[kernel] r10243 - in dists/trunk/linux-2.6/debian/patches: bugfix/all series

Maximilian Attems maks at alioth.debian.org
Tue Jan 29 09:43:56 UTC 2008


Author: maks
Date: Tue Jan 29 09:43:52 2008
New Revision: 10243

Log:
update to patch-2.6.24-git5

no further conflicts
arm merge happend (some patches can probably be killed now)
sh arch merge


Added:
   dists/trunk/linux-2.6/debian/patches/bugfix/all/patch-2.6.24-git5
      - copied, changed from r10239, /dists/trunk/linux-2.6/debian/patches/bugfix/all/patch-2.6.24-git4
Removed:
   dists/trunk/linux-2.6/debian/patches/bugfix/all/patch-2.6.24-git4
Modified:
   dists/trunk/linux-2.6/debian/patches/series/1~experimental.1

Copied: dists/trunk/linux-2.6/debian/patches/bugfix/all/patch-2.6.24-git5 (from r10239, /dists/trunk/linux-2.6/debian/patches/bugfix/all/patch-2.6.24-git4)
==============================================================================
--- /dists/trunk/linux-2.6/debian/patches/bugfix/all/patch-2.6.24-git4	(original)
+++ dists/trunk/linux-2.6/debian/patches/bugfix/all/patch-2.6.24-git5	Tue Jan 29 09:43:52 2008
@@ -814,6 +814,18 @@
  	"Reader Batch" list than in the "Reader Pipe" list.
  
  o	"Free-Block Circulation": Shows the number of torture structures
+diff --git a/Documentation/cpu-freq/user-guide.txt b/Documentation/cpu-freq/user-guide.txt
+index 555c8cf..af3b925 100644
+--- a/Documentation/cpu-freq/user-guide.txt
++++ b/Documentation/cpu-freq/user-guide.txt
+@@ -45,6 +45,7 @@ The following ARM processors are supported by cpufreq:
+ ARM Integrator
+ ARM-SA1100
+ ARM-SA1110
++Intel PXA
+ 
+ 
+ 1.2 x86
 diff --git a/Documentation/cpu-hotplug.txt b/Documentation/cpu-hotplug.txt
 index a741f65..ba0aacd 100644
 --- a/Documentation/cpu-hotplug.txt
@@ -1928,6 +1940,18 @@
  
 +For a more complete example of using ksets and kobjects properly, see the
 +sample/kobject/kset-example.c code.
+diff --git a/Documentation/kprobes.txt b/Documentation/kprobes.txt
+index cb12ae1..53a6389 100644
+--- a/Documentation/kprobes.txt
++++ b/Documentation/kprobes.txt
+@@ -141,6 +141,7 @@ architectures:
+ - ppc64
+ - ia64 (Does not support probes on instruction slot1.)
+ - sparc64 (Return probes not yet implemented.)
++- arm
+ 
+ 3. Configuring Kprobes
+ 
 diff --git a/Documentation/m68k/kernel-options.txt b/Documentation/m68k/kernel-options.txt
 index 248589e..c93bed6 100644
 --- a/Documentation/m68k/kernel-options.txt
@@ -5361,1898 +5385,2156 @@
  M:	linux390 at de.ibm.com
  L:	linux-s390 at vger.kernel.org
  W:	http://www.ibm.com/developerworks/linux/linux390/
-diff --git a/arch/arm/kernel/time.c b/arch/arm/kernel/time.c
-index 1533d3e..e59b5b8 100644
---- a/arch/arm/kernel/time.c
-+++ b/arch/arm/kernel/time.c
-@@ -79,17 +79,6 @@ static unsigned long dummy_gettimeoffset(void)
- }
- #endif
- 
--/*
-- * An implementation of printk_clock() independent from
-- * sched_clock().  This avoids non-bootable kernels when
-- * printk_clock is enabled.
-- */
--unsigned long long printk_clock(void)
--{
--	return (unsigned long long)(jiffies - INITIAL_JIFFIES) *
--			(1000000000 / HZ);
--}
--
- static unsigned long next_rtc_update;
- 
- /*
-@@ -195,7 +184,7 @@ static int leds_shutdown(struct sys_device *dev)
- }
- 
- static struct sysdev_class leds_sysclass = {
--	set_kset_name("leds"),
-+	.name		= "leds",
- 	.shutdown	= leds_shutdown,
- 	.suspend	= leds_suspend,
- 	.resume		= leds_resume,
-@@ -369,7 +358,7 @@ static int timer_resume(struct sys_device *dev)
- #endif
- 
- static struct sysdev_class timer_sysclass = {
--	set_kset_name("timer"),
-+	.name		= "timer",
- 	.suspend	= timer_suspend,
- 	.resume		= timer_resume,
- };
-diff --git a/arch/arm/mach-integrator/integrator_ap.c b/arch/arm/mach-integrator/integrator_ap.c
-index 7228075..df37e93 100644
---- a/arch/arm/mach-integrator/integrator_ap.c
-+++ b/arch/arm/mach-integrator/integrator_ap.c
-@@ -214,7 +214,7 @@ static int irq_resume(struct sys_device *dev)
- #endif
- 
- static struct sysdev_class irq_class = {
--	set_kset_name("irq"),
-+	.name		= "irq",
- 	.suspend	= irq_suspend,
- 	.resume		= irq_resume,
- };
-diff --git a/arch/arm/mach-ixp4xx/avila-setup.c b/arch/arm/mach-ixp4xx/avila-setup.c
-index d59b8dc..e38f45f 100644
---- a/arch/arm/mach-ixp4xx/avila-setup.c
-+++ b/arch/arm/mach-ixp4xx/avila-setup.c
-@@ -18,6 +18,7 @@
- #include <linux/tty.h>
- #include <linux/serial_8250.h>
- #include <linux/slab.h>
-+#include <linux/i2c-gpio.h>
- 
- #include <asm/types.h>
- #include <asm/setup.h>
-@@ -47,18 +48,17 @@ static struct platform_device avila_flash = {
- 	.resource	= &avila_flash_resource,
- };
- 
--static struct ixp4xx_i2c_pins avila_i2c_gpio_pins = {
-+static struct i2c_gpio_platform_data avila_i2c_gpio_data = {
- 	.sda_pin	= AVILA_SDA_PIN,
- 	.scl_pin	= AVILA_SCL_PIN,
- };
- 
--static struct platform_device avila_i2c_controller = {
--	.name		= "IXP4XX-I2C",
-+static struct platform_device avila_i2c_gpio = {
-+	.name		= "i2c-gpio",
- 	.id		= 0,
--	.dev		= {
--		.platform_data = &avila_i2c_gpio_pins,
-+	.dev	 = {
-+		.platform_data	= &avila_i2c_gpio_data,
- 	},
--	.num_resources	= 0
- };
- 
- static struct resource avila_uart_resources[] = {
-@@ -133,7 +133,7 @@ static struct platform_device avila_pata = {
- };
- 
- static struct platform_device *avila_devices[] __initdata = {
--	&avila_i2c_controller,
-+	&avila_i2c_gpio,
- 	&avila_flash,
- 	&avila_uart
- };
-diff --git a/arch/arm/mach-ixp4xx/dsmg600-setup.c b/arch/arm/mach-ixp4xx/dsmg600-setup.c
-index 1e75e10..c473d40 100644
---- a/arch/arm/mach-ixp4xx/dsmg600-setup.c
-+++ b/arch/arm/mach-ixp4xx/dsmg600-setup.c
-@@ -14,6 +14,7 @@
- #include <linux/kernel.h>
- #include <linux/serial.h>
- #include <linux/serial_8250.h>
-+#include <linux/i2c-gpio.h>
- 
- #include <asm/mach-types.h>
- #include <asm/mach/arch.h>
-@@ -37,15 +38,17 @@ static struct platform_device dsmg600_flash = {
- 	.resource		= &dsmg600_flash_resource,
- };
- 
--static struct ixp4xx_i2c_pins dsmg600_i2c_gpio_pins = {
-+static struct i2c_gpio_platform_data dsmg600_i2c_gpio_data = {
- 	.sda_pin		= DSMG600_SDA_PIN,
- 	.scl_pin		= DSMG600_SCL_PIN,
- };
- 
--static struct platform_device dsmg600_i2c_controller = {
--	.name			= "IXP4XX-I2C",
-+static struct platform_device dsmg600_i2c_gpio = {
-+	.name			= "i2c-gpio",
- 	.id			= 0,
--	.dev.platform_data	= &dsmg600_i2c_gpio_pins,
-+	.dev	 = {
-+		.platform_data	= &dsmg600_i2c_gpio_data,
-+	},
- };
- 
- #ifdef CONFIG_LEDS_CLASS
-@@ -116,7 +119,7 @@ static struct platform_device dsmg600_uart = {
- };
- 
- static struct platform_device *dsmg600_devices[] __initdata = {
--	&dsmg600_i2c_controller,
-+	&dsmg600_i2c_gpio,
- 	&dsmg600_flash,
- };
- 
-diff --git a/arch/arm/mach-ixp4xx/ixdp425-setup.c b/arch/arm/mach-ixp4xx/ixdp425-setup.c
-index d5008d8..e89070d 100644
---- a/arch/arm/mach-ixp4xx/ixdp425-setup.c
-+++ b/arch/arm/mach-ixp4xx/ixdp425-setup.c
-@@ -15,6 +15,7 @@
- #include <linux/tty.h>
- #include <linux/serial_8250.h>
- #include <linux/slab.h>
-+#include <linux/i2c-gpio.h>
- #include <linux/io.h>
- #include <linux/mtd/mtd.h>
- #include <linux/mtd/nand.h>
-@@ -120,18 +121,17 @@ static struct platform_device ixdp425_flash_nand = {
- };
- #endif	/* CONFIG_MTD_NAND_PLATFORM */
- 
--static struct ixp4xx_i2c_pins ixdp425_i2c_gpio_pins = {
-+static struct i2c_gpio_platform_data ixdp425_i2c_gpio_data = {
- 	.sda_pin	= IXDP425_SDA_PIN,
- 	.scl_pin	= IXDP425_SCL_PIN,
- };
- 
--static struct platform_device ixdp425_i2c_controller = {
--	.name		= "IXP4XX-I2C",
-+static struct platform_device ixdp425_i2c_gpio = {
-+	.name		= "i2c-gpio",
- 	.id		= 0,
--	.dev		= {
--		.platform_data = &ixdp425_i2c_gpio_pins,
-+	.dev	 = {
-+		.platform_data	= &ixdp425_i2c_gpio_data,
- 	},
--	.num_resources	= 0
- };
- 
- static struct resource ixdp425_uart_resources[] = {
-@@ -178,7 +178,7 @@ static struct platform_device ixdp425_uart = {
- };
- 
- static struct platform_device *ixdp425_devices[] __initdata = {
--	&ixdp425_i2c_controller,
-+	&ixdp425_i2c_gpio,
- 	&ixdp425_flash,
- #if defined(CONFIG_MTD_NAND_PLATFORM) || \
-     defined(CONFIG_MTD_NAND_PLATFORM_MODULE)
-diff --git a/arch/arm/mach-ixp4xx/nas100d-setup.c b/arch/arm/mach-ixp4xx/nas100d-setup.c
-index 78a1741..54d884f 100644
---- a/arch/arm/mach-ixp4xx/nas100d-setup.c
-+++ b/arch/arm/mach-ixp4xx/nas100d-setup.c
-@@ -16,6 +16,7 @@
- #include <linux/serial.h>
- #include <linux/serial_8250.h>
- #include <linux/leds.h>
-+#include <linux/i2c-gpio.h>
- 
- #include <asm/mach-types.h>
- #include <asm/mach/arch.h>
-@@ -68,16 +69,17 @@ static struct platform_device nas100d_leds = {
- };
- #endif
- 
--static struct ixp4xx_i2c_pins nas100d_i2c_gpio_pins = {
-+static struct i2c_gpio_platform_data nas100d_i2c_gpio_data = {
- 	.sda_pin		= NAS100D_SDA_PIN,
- 	.scl_pin		= NAS100D_SCL_PIN,
- };
- 
--static struct platform_device nas100d_i2c_controller = {
--	.name			= "IXP4XX-I2C",
-+static struct platform_device nas100d_i2c_gpio = {
-+	.name			= "i2c-gpio",
- 	.id			= 0,
--	.dev.platform_data	= &nas100d_i2c_gpio_pins,
--	.num_resources		= 0,
-+	.dev	 = {
-+		.platform_data	= &nas100d_i2c_gpio_data,
-+	},
- };
- 
- static struct resource nas100d_uart_resources[] = {
-@@ -124,7 +126,7 @@ static struct platform_device nas100d_uart = {
- };
- 
- static struct platform_device *nas100d_devices[] __initdata = {
--	&nas100d_i2c_controller,
-+	&nas100d_i2c_gpio,
- 	&nas100d_flash,
- #ifdef CONFIG_LEDS_IXP4XX
- 	&nas100d_leds,
-diff --git a/arch/arm/mach-ixp4xx/nslu2-setup.c b/arch/arm/mach-ixp4xx/nslu2-setup.c
-index 9bf8ccb..77277d2 100644
---- a/arch/arm/mach-ixp4xx/nslu2-setup.c
-+++ b/arch/arm/mach-ixp4xx/nslu2-setup.c
-@@ -18,6 +18,7 @@
- #include <linux/serial.h>
- #include <linux/serial_8250.h>
- #include <linux/leds.h>
-+#include <linux/i2c-gpio.h>
- 
- #include <asm/mach-types.h>
- #include <asm/mach/arch.h>
-@@ -41,7 +42,7 @@ static struct platform_device nslu2_flash = {
- 	.resource		= &nslu2_flash_resource,
- };
- 
--static struct ixp4xx_i2c_pins nslu2_i2c_gpio_pins = {
-+static struct i2c_gpio_platform_data nslu2_i2c_gpio_data = {
- 	.sda_pin		= NSLU2_SDA_PIN,
- 	.scl_pin		= NSLU2_SCL_PIN,
- };
-@@ -82,11 +83,12 @@ static struct platform_device nslu2_leds = {
- };
- #endif
- 
--static struct platform_device nslu2_i2c_controller = {
--	.name			= "IXP4XX-I2C",
-+static struct platform_device nslu2_i2c_gpio = {
-+	.name			= "i2c-gpio",
- 	.id			= 0,
--	.dev.platform_data	= &nslu2_i2c_gpio_pins,
--	.num_resources		= 0,
-+	.dev	 = {
-+		.platform_data	= &nslu2_i2c_gpio_data,
-+	},
- };
- 
- static struct platform_device nslu2_beeper = {
-@@ -139,7 +141,7 @@ static struct platform_device nslu2_uart = {
- };
- 
- static struct platform_device *nslu2_devices[] __initdata = {
--	&nslu2_i2c_controller,
-+	&nslu2_i2c_gpio,
- 	&nslu2_flash,
- 	&nslu2_beeper,
- #ifdef CONFIG_LEDS_IXP4XX
-diff --git a/arch/arm/mach-omap1/board-h2.c b/arch/arm/mach-omap1/board-h2.c
-index 1306812..9393824 100644
---- a/arch/arm/mach-omap1/board-h2.c
-+++ b/arch/arm/mach-omap1/board-h2.c
-@@ -27,6 +27,7 @@
- #include <linux/mtd/nand.h>
- #include <linux/mtd/partitions.h>
- #include <linux/input.h>
-+#include <linux/i2c/tps65010.h>
- 
- #include <asm/hardware.h>
- #include <asm/gpio.h>
-@@ -36,7 +37,6 @@
- #include <asm/mach/flash.h>
- #include <asm/mach/map.h>
- 
--#include <asm/arch/tps65010.h>
- #include <asm/arch/mux.h>
- #include <asm/arch/tc.h>
- #include <asm/arch/irda.h>
-diff --git a/arch/arm/mach-omap1/board-h3.c b/arch/arm/mach-omap1/board-h3.c
-index 4f84ae2..978cdab 100644
---- a/arch/arm/mach-omap1/board-h3.c
-+++ b/arch/arm/mach-omap1/board-h3.c
-@@ -26,6 +26,7 @@
- #include <linux/mtd/nand.h>
- #include <linux/mtd/partitions.h>
- #include <linux/input.h>
-+#include <linux/i2c/tps65010.h>
- 
- #include <asm/setup.h>
- #include <asm/page.h>
-@@ -37,7 +38,6 @@
- #include <asm/mach/flash.h>
- #include <asm/mach/map.h>
+diff --git a/Makefile b/Makefile
+index 189d8ef..2185467 100644
+--- a/Makefile
++++ b/Makefile
+@@ -169,7 +169,7 @@ SUBARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \
+ 				  -e s/arm.*/arm/ -e s/sa110/arm/ \
+ 				  -e s/s390x/s390/ -e s/parisc64/parisc/ \
+ 				  -e s/ppc.*/powerpc/ -e s/mips.*/mips/ \
+-				  -e s/sh[234].*/sh/ )
++				  -e s/sh.*/sh/ )
+ 
+ # Cross compiling and selecting different set of gcc/bin-utils
+ # ---------------------------------------------------------------------------
+diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
+index a04f507..de211ac 100644
+--- a/arch/arm/Kconfig
++++ b/arch/arm/Kconfig
+@@ -180,8 +180,8 @@ config ARCH_AT91
+ 	bool "Atmel AT91"
+ 	select GENERIC_GPIO
+ 	help
+-	  This enables support for systems based on the Atmel AT91RM9200
+-	  and AT91SAM9xxx processors.
++	  This enables support for systems based on the Atmel AT91RM9200,
++	  AT91SAM9 and AT91CAP9 processors.
+ 
+ config ARCH_CLPS7500
+ 	bool "Cirrus CL-PS7500FE"
+@@ -217,6 +217,7 @@ config ARCH_EP93XX
+ 	bool "EP93xx-based"
+ 	select ARM_AMBA
+ 	select ARM_VIC
++	select GENERIC_GPIO
+ 	help
+ 	  This enables support for the Cirrus EP93xx series of CPUs.
  
--#include <asm/arch/tps65010.h>
- #include <asm/arch/gpioexpander.h>
- #include <asm/arch/irqs.h>
- #include <asm/arch/mux.h>
-diff --git a/arch/arm/mach-omap1/board-osk.c b/arch/arm/mach-omap1/board-osk.c
-index 5db182d..5b575e6 100644
---- a/arch/arm/mach-omap1/board-osk.c
-+++ b/arch/arm/mach-omap1/board-osk.c
-@@ -37,6 +37,8 @@
- #include <linux/mtd/mtd.h>
- #include <linux/mtd/partitions.h>
+@@ -333,6 +334,16 @@ config ARCH_MXC
+ 	help
+ 	  Support for Freescale MXC/iMX-based family of processors
  
-+#include <linux/i2c/tps65010.h>
++config ARCH_ORION
++	bool "Marvell Orion"
++	depends on MMU
++	select PCI
++	select GENERIC_GPIO
++	select GENERIC_TIME
++	select GENERIC_CLOCKEVENTS
++	help
++	  Support for Marvell Orion System on Chip family.
 +
- #include <asm/hardware.h>
- #include <asm/gpio.h>
- 
-@@ -46,7 +48,6 @@
- #include <asm/mach/flash.h>
- 
- #include <asm/arch/usb.h>
--#include <asm/arch/tps65010.h>
- #include <asm/arch/mux.h>
- #include <asm/arch/tc.h>
- #include <asm/arch/common.h>
-diff --git a/arch/arm/mach-omap1/leds-osk.c b/arch/arm/mach-omap1/leds-osk.c
-index 86de303..6939d5e 100644
---- a/arch/arm/mach-omap1/leds-osk.c
-+++ b/arch/arm/mach-omap1/leds-osk.c
-@@ -5,13 +5,13 @@
-  */
- #include <linux/init.h>
- #include <linux/workqueue.h>
-+#include <linux/i2c/tps65010.h>
- 
- #include <asm/hardware.h>
- #include <asm/leds.h>
- #include <asm/system.h>
- 
- #include <asm/arch/gpio.h>
--#include <asm/arch/tps65010.h>
- 
- #include "leds.h"
- 
-diff --git a/arch/arm/mach-omap1/pm.c b/arch/arm/mach-omap1/pm.c
-index 3bf01e2..d9805e3 100644
---- a/arch/arm/mach-omap1/pm.c
-+++ b/arch/arm/mach-omap1/pm.c
-@@ -69,14 +69,14 @@ static unsigned int mpui1610_sleep_save[MPUI1610_SLEEP_SAVE_SIZE];
- 
- static unsigned short enable_dyn_sleep = 1;
- 
--static ssize_t omap_pm_sleep_while_idle_show(struct kset *kset, char *buf)
-+static ssize_t idle_show(struct kobject *kobj, struct kobj_attribute *attr,
-+			 char *buf)
- {
- 	return sprintf(buf, "%hu\n", enable_dyn_sleep);
- }
- 
--static ssize_t omap_pm_sleep_while_idle_store(struct kset *kset,
--					      const char * buf,
--					      size_t n)
-+static ssize_t idle_store(struct kobject *kobj, struct kobj_attribute *attr,
-+			  const char * buf, size_t n)
- {
- 	unsigned short value;
- 	if (sscanf(buf, "%hu", &value) != 1 ||
-@@ -88,16 +88,9 @@ static ssize_t omap_pm_sleep_while_idle_store(struct kset *kset,
- 	return n;
- }
- 
--static struct subsys_attribute sleep_while_idle_attr = {
--	.attr   = {
--		.name = __stringify(sleep_while_idle),
--		.mode = 0644,
--	},
--	.show   = omap_pm_sleep_while_idle_show,
--	.store  = omap_pm_sleep_while_idle_store,
--};
-+static struct kobj_attribute sleep_while_idle_attr =
-+	__ATTR(sleep_while_idle, 0644, idle_show, idle_store);
- 
--extern struct kset power_subsys;
- static void (*omap_sram_idle)(void) = NULL;
- static void (*omap_sram_suspend)(unsigned long r0, unsigned long r1) = NULL;
- 
-@@ -726,9 +719,9 @@ static int __init omap_pm_init(void)
- 	omap_pm_init_proc();
- #endif
- 
--	error = subsys_create_file(&power_subsys, &sleep_while_idle_attr);
-+	error = sysfs_create_file(power_kobj, &sleep_while_idle_attr);
- 	if (error)
--		printk(KERN_ERR "subsys_create_file failed: %d\n", error);
-+		printk(KERN_ERR "sysfs_create_file failed: %d\n", error);
- 
- 	if (cpu_is_omap16xx()) {
- 		/* configure LOW_PWR pin */
-diff --git a/arch/arm/mach-pxa/akita-ioexp.c b/arch/arm/mach-pxa/akita-ioexp.c
-index 12d2fe0..254892a 100644
---- a/arch/arm/mach-pxa/akita-ioexp.c
-+++ b/arch/arm/mach-pxa/akita-ioexp.c
-@@ -29,7 +29,7 @@
- #define MAX7310_TIMEOUT  0x04
- 
- /* Addresses to scan */
--static unsigned short normal_i2c[] = { 0x18, I2C_CLIENT_END };
-+static const unsigned short normal_i2c[] = { 0x18, I2C_CLIENT_END };
- 
- /* I2C Magic */
- I2C_CLIENT_INSMOD;
-diff --git a/arch/arm/mach-pxa/cm-x270.c b/arch/arm/mach-pxa/cm-x270.c
-index 177664c..a163492 100644
---- a/arch/arm/mach-pxa/cm-x270.c
-+++ b/arch/arm/mach-pxa/cm-x270.c
-@@ -566,7 +566,7 @@ static int cmx270_resume(struct sys_device *dev)
- }
- 
- static struct sysdev_class cmx270_pm_sysclass = {
--	set_kset_name("pm"),
-+	.name = "pm",
- 	.resume = cmx270_resume,
- 	.suspend = cmx270_suspend,
- };
-diff --git a/arch/arm/mach-pxa/lpd270.c b/arch/arm/mach-pxa/lpd270.c
-index 2611644..78ebad0 100644
---- a/arch/arm/mach-pxa/lpd270.c
-+++ b/arch/arm/mach-pxa/lpd270.c
-@@ -122,7 +122,7 @@ static int lpd270_irq_resume(struct sys_device *dev)
- }
- 
- static struct sysdev_class lpd270_irq_sysclass = {
--	set_kset_name("cpld_irq"),
-+	.name = "cpld_irq",
- 	.resume = lpd270_irq_resume,
- };
- 
-diff --git a/arch/arm/mach-pxa/lubbock.c b/arch/arm/mach-pxa/lubbock.c
-index 011a1a7..1d3112d 100644
---- a/arch/arm/mach-pxa/lubbock.c
-+++ b/arch/arm/mach-pxa/lubbock.c
-@@ -126,7 +126,7 @@ static int lubbock_irq_resume(struct sys_device *dev)
- }
- 
- static struct sysdev_class lubbock_irq_sysclass = {
--	set_kset_name("cpld_irq"),
-+	.name = "cpld_irq",
- 	.resume = lubbock_irq_resume,
- };
- 
-diff --git a/arch/arm/mach-pxa/mainstone.c b/arch/arm/mach-pxa/mainstone.c
-index a4bc348..41d8c6c 100644
---- a/arch/arm/mach-pxa/mainstone.c
-+++ b/arch/arm/mach-pxa/mainstone.c
-@@ -120,7 +120,7 @@ static int mainstone_irq_resume(struct sys_device *dev)
- }
- 
- static struct sysdev_class mainstone_irq_sysclass = {
--	set_kset_name("cpld_irq"),
-+	.name = "cpld_irq",
- 	.resume = mainstone_irq_resume,
- };
+ config ARCH_PNX4008
+ 	bool "Philips Nexperia PNX4008 Mobile"
+ 	help
+@@ -345,6 +356,7 @@ config ARCH_PXA
+ 	select GENERIC_GPIO
+ 	select GENERIC_TIME
+ 	select GENERIC_CLOCKEVENTS
++	select TICK_ONESHOT
+ 	help
+ 	  Support for Intel/Marvell's PXA2xx/PXA3xx processor line.
  
-diff --git a/arch/arm/mach-pxa/pxa27x.c b/arch/arm/mach-pxa/pxa27x.c
-index 8e126e6..57efebd 100644
---- a/arch/arm/mach-pxa/pxa27x.c
-+++ b/arch/arm/mach-pxa/pxa27x.c
-@@ -24,6 +24,7 @@
- #include <asm/arch/ohci.h>
- #include <asm/arch/pm.h>
- #include <asm/arch/dma.h>
-+#include <asm/arch/i2c.h>
+@@ -366,6 +378,7 @@ config ARCH_SA1100
+ 	select ARCH_DISCONTIGMEM_ENABLE
+ 	select ARCH_MTD_XIP
+ 	select GENERIC_GPIO
++	select GENERIC_TIME
+ 	help
+ 	  Support for StrongARM 11x0 based boards.
  
- #include "generic.h"
- #include "devices.h"
-@@ -423,6 +424,11 @@ struct platform_device pxa27x_device_i2c_power = {
- 	.num_resources	= ARRAY_SIZE(i2c_power_resources),
- };
+@@ -409,6 +422,17 @@ config ARCH_OMAP
+ 	help
+ 	  Support for TI's OMAP platform (OMAP1 and OMAP2).
  
-+void __init pxa_set_i2c_power_info(struct i2c_pxa_platform_data *info)
-+{
-+	pxa27x_device_i2c_power.dev.platform_data = info;
-+}
++config ARCH_MSM7X00A
++	bool "Qualcomm MSM7X00A"
++	select GENERIC_TIME
++	select GENERIC_CLOCKEVENTS
++	help
++	  Support for Qualcomm MSM7X00A based systems.  This runs on the ARM11
++	  apps processor of the MSM7X00A and depends on a shared memory
++	  interface to the ARM9 modem processor which runs the baseband stack
++	  and controls some vital subsystems (clock and power control, etc).
++	  <http://www.cdmatech.com/products/msm7200_chipset_solution.jsp>
 +
- static struct platform_device *devices[] __initdata = {
- 	&pxa_device_mci,
- 	&pxa_device_udc,
-diff --git a/arch/arm/mach-s3c2410/s3c2410.c b/arch/arm/mach-s3c2410/s3c2410.c
-index e580303..0e79919 100644
---- a/arch/arm/mach-s3c2410/s3c2410.c
-+++ b/arch/arm/mach-s3c2410/s3c2410.c
-@@ -100,7 +100,7 @@ void __init s3c2410_init_clocks(int xtal)
- }
- 
- struct sysdev_class s3c2410_sysclass = {
--	set_kset_name("s3c2410-core"),
-+	.name = "s3c2410-core",
- };
- 
- static struct sys_device s3c2410_sysdev = {
-diff --git a/arch/arm/mach-s3c2412/s3c2412.c b/arch/arm/mach-s3c2412/s3c2412.c
-index 4f92a15..265cd3f 100644
---- a/arch/arm/mach-s3c2412/s3c2412.c
-+++ b/arch/arm/mach-s3c2412/s3c2412.c
-@@ -196,7 +196,7 @@ void __init s3c2412_init_clocks(int xtal)
- */
- 
- struct sysdev_class s3c2412_sysclass = {
--	set_kset_name("s3c2412-core"),
-+	.name = "s3c2412-core",
- };
- 
- static int __init s3c2412_core_init(void)
-diff --git a/arch/arm/mach-s3c2440/mach-osiris.c b/arch/arm/mach-s3c2440/mach-osiris.c
-index c326983..78af766 100644
---- a/arch/arm/mach-s3c2440/mach-osiris.c
-+++ b/arch/arm/mach-s3c2440/mach-osiris.c
-@@ -312,7 +312,7 @@ static int osiris_pm_resume(struct sys_device *sd)
- #endif
- 
- static struct sysdev_class osiris_pm_sysclass = {
--	set_kset_name("mach-osiris"),
-+	.name		= "mach-osiris",
- 	.suspend	= osiris_pm_suspend,
- 	.resume		= osiris_pm_resume,
- };
-diff --git a/arch/arm/mach-s3c2443/s3c2443.c b/arch/arm/mach-s3c2443/s3c2443.c
-index 8d81171..9ce4905 100644
---- a/arch/arm/mach-s3c2443/s3c2443.c
-+++ b/arch/arm/mach-s3c2443/s3c2443.c
-@@ -43,7 +43,7 @@ static struct map_desc s3c2443_iodesc[] __initdata = {
- };
- 
- struct sysdev_class s3c2443_sysclass = {
--	set_kset_name("s3c2443-core"),
-+	.name = "s3c2443-core",
- };
- 
- static struct sys_device s3c2443_sysdev = {
-diff --git a/arch/arm/mach-sa1100/irq.c b/arch/arm/mach-sa1100/irq.c
-index edf3347..3dc17d7 100644
---- a/arch/arm/mach-sa1100/irq.c
-+++ b/arch/arm/mach-sa1100/irq.c
-@@ -283,7 +283,7 @@ static int sa1100irq_resume(struct sys_device *dev)
- }
- 
- static struct sysdev_class sa1100irq_sysclass = {
--	set_kset_name("sa11x0-irq"),
-+	.name		= "sa11x0-irq",
- 	.suspend	= sa1100irq_suspend,
- 	.resume		= sa1100irq_resume,
- };
-diff --git a/arch/arm/oprofile/common.c b/arch/arm/oprofile/common.c
-index a9de727..0a5cf3a 100644
---- a/arch/arm/oprofile/common.c
-+++ b/arch/arm/oprofile/common.c
-@@ -96,7 +96,7 @@ static int op_arm_resume(struct sys_device *dev)
- }
- 
- static struct sysdev_class oprofile_sysclass = {
--	set_kset_name("oprofile"),
-+	.name		= "oprofile",
- 	.resume		= op_arm_resume,
- 	.suspend	= op_arm_suspend,
- };
-diff --git a/arch/arm/plat-omap/gpio.c b/arch/arm/plat-omap/gpio.c
-index 6097753..b2a87b8 100644
---- a/arch/arm/plat-omap/gpio.c
-+++ b/arch/arm/plat-omap/gpio.c
-@@ -1455,7 +1455,7 @@ static int omap_gpio_resume(struct sys_device *dev)
- }
- 
- static struct sysdev_class omap_gpio_sysclass = {
--	set_kset_name("gpio"),
-+	.name		= "gpio",
- 	.suspend	= omap_gpio_suspend,
- 	.resume		= omap_gpio_resume,
- };
-diff --git a/arch/arm/plat-s3c24xx/dma.c b/arch/arm/plat-s3c24xx/dma.c
-index 29696e4..aae1b9c 100644
---- a/arch/arm/plat-s3c24xx/dma.c
-+++ b/arch/arm/plat-s3c24xx/dma.c
-@@ -1265,7 +1265,7 @@ static int s3c2410_dma_resume(struct sys_device *dev)
- #endif /* CONFIG_PM */
- 
- struct sysdev_class dma_sysclass = {
--	set_kset_name("s3c24xx-dma"),
-+	.name		= "s3c24xx-dma",
- 	.suspend	= s3c2410_dma_suspend,
- 	.resume		= s3c2410_dma_resume,
- };
-diff --git a/arch/arm/plat-s3c24xx/s3c244x.c b/arch/arm/plat-s3c24xx/s3c244x.c
-index 3444b13..f197bb3 100644
---- a/arch/arm/plat-s3c24xx/s3c244x.c
-+++ b/arch/arm/plat-s3c24xx/s3c244x.c
-@@ -151,13 +151,13 @@ static int s3c244x_resume(struct sys_device *dev)
- /* Since the S3C2442 and S3C2440 share  items, put both sysclasses here */
+ endchoice
  
- struct sysdev_class s3c2440_sysclass = {
--	set_kset_name("s3c2440-core"),
-+	.name		= "s3c2440-core",
- 	.suspend	= s3c244x_suspend,
- 	.resume		= s3c244x_resume
- };
+ source "arch/arm/mach-clps711x/Kconfig"
+@@ -441,6 +465,8 @@ source "arch/arm/mach-omap1/Kconfig"
  
- struct sysdev_class s3c2442_sysclass = {
--	set_kset_name("s3c2442-core"),
-+	.name		= "s3c2442-core",
- 	.suspend	= s3c244x_suspend,
- 	.resume		= s3c244x_resume
- };
-diff --git a/arch/avr32/Kconfig b/arch/avr32/Kconfig
-index b77abce..e34e2c9 100644
---- a/arch/avr32/Kconfig
-+++ b/arch/avr32/Kconfig
-@@ -54,6 +54,9 @@ config ARCH_HAS_ILOG2_U32
- config ARCH_HAS_ILOG2_U64
- 	def_bool n
+ source "arch/arm/mach-omap2/Kconfig"
  
-+config ARCH_SUPPORTS_OPROFILE
-+	def_bool y
++source "arch/arm/mach-orion/Kconfig"
 +
- config GENERIC_HWEIGHT
- 	def_bool y
+ source "arch/arm/plat-s3c24xx/Kconfig"
+ source "arch/arm/plat-s3c/Kconfig"
  
-@@ -81,19 +84,23 @@ config PLATFORM_AT32AP
- 	select MMU
- 	select PERFORMANCE_COUNTERS
+@@ -477,6 +503,8 @@ source "arch/arm/mach-davinci/Kconfig"
  
--choice
--	prompt "AVR32 CPU type"
--	default CPU_AT32AP7000
-+#
-+# CPU types
-+#
+ source "arch/arm/mach-ks8695/Kconfig"
  
--config CPU_AT32AP7000
--	bool "AT32AP7000"
-+# AP7000 derivatives
-+config CPU_AT32AP700X
-+	bool
- 	select PLATFORM_AT32AP
--endchoice
--
--#
--# CPU Daughterboards for ATSTK1000
--config BOARD_ATSTK1002
-+config CPU_AT32AP7000
-+	bool
-+	select CPU_AT32AP700X
-+config CPU_AT32AP7001
-+	bool
-+	select CPU_AT32AP700X
-+config CPU_AT32AP7002
++source "arch/arm/mach-msm/Kconfig"
++
+ # Definitions to make life easier
+ config ARCH_ACORN
  	bool
-+	select CPU_AT32AP700X
+@@ -657,6 +685,7 @@ config HZ
+ 	default 128 if ARCH_L7200
+ 	default 200 if ARCH_EBSA110 || ARCH_S3C2410
+ 	default OMAP_32K_TIMER_HZ if ARCH_OMAP && OMAP_32K_TIMER
++	default AT91_TIMER_HZ if ARCH_AT91
+ 	default 100
+ 
+ config AEABI
+@@ -716,7 +745,7 @@ config LEDS
+ 		   ARCH_OMAP || ARCH_P720T || ARCH_PXA_IDP || \
+ 		   ARCH_SA1100 || ARCH_SHARK || ARCH_VERSATILE || \
+ 		   ARCH_AT91 || MACH_TRIZEPS4 || ARCH_DAVINCI || \
+-		   ARCH_KS8695
++		   ARCH_KS8695 || MACH_RD88F5182
+ 	help
+ 	  If you say Y here, the LEDs on your machine will be used
+ 	  to provide useful information about your current system status.
+@@ -867,7 +896,7 @@ config KEXEC
  
- choice
- 	prompt "AVR32 board type"
-@@ -101,10 +108,10 @@ choice
+ endmenu
  
- config BOARD_ATSTK1000
- 	bool "ATSTK1000 evaluation board"
--	select BOARD_ATSTK1002 if CPU_AT32AP7000
+-if (ARCH_SA1100 || ARCH_INTEGRATOR || ARCH_OMAP || ARCH_IMX )
++if (ARCH_SA1100 || ARCH_INTEGRATOR || ARCH_OMAP || ARCH_IMX || ARCH_PXA)
  
- config BOARD_ATNGW100
- 	bool "ATNGW100 Network Gateway"
-+	select CPU_AT32AP7000
- endchoice
+ menu "CPU Frequency scaling"
  
- if BOARD_ATSTK1000
-@@ -123,15 +130,15 @@ source "arch/avr32/mach-at32ap/Kconfig"
+@@ -903,6 +932,12 @@ config CPU_FREQ_IMX
  
- config LOAD_ADDRESS
- 	hex
--	default 0x10000000 if LOADER_U_BOOT=y && CPU_AT32AP7000=y
-+	default 0x10000000 if LOADER_U_BOOT=y && CPU_AT32AP700X=y
+ 	  If in doubt, say N.
  
- config ENTRY_ADDRESS
- 	hex
--	default 0x90000000 if LOADER_U_BOOT=y && CPU_AT32AP7000=y
-+	default 0x90000000 if LOADER_U_BOOT=y && CPU_AT32AP700X=y
++config CPU_FREQ_PXA
++	bool
++	depends on CPU_FREQ && ARCH_PXA && PXA25x
++	default y
++	select CPU_FREQ_DEFAULT_GOV_USERSPACE
++
+ endmenu
  
- config PHYS_OFFSET
- 	hex
--	default 0x10000000 if CPU_AT32AP7000=y
-+	default 0x10000000 if CPU_AT32AP700X=y
+ endif
+@@ -951,7 +986,7 @@ config FPE_FASTFPE
  
- source "kernel/Kconfig.preempt"
+ config VFP
+ 	bool "VFP-format floating point maths"
+-	depends on CPU_V6 || CPU_ARM926T
++	depends on CPU_V6 || CPU_ARM926T || CPU_V7 || CPU_FEROCEON
+ 	help
+ 	  Say Y to include VFP support code in the kernel. This is needed
+ 	  if your hardware includes a VFP unit.
+@@ -961,6 +996,18 @@ config VFP
  
-@@ -163,6 +170,16 @@ config OWNERSHIP_TRACE
- 	  enabling Nexus-compliant debuggers to keep track of the PID of the
- 	  currently executing task.
+ 	  Say N if your target does not have VFP hardware.
  
-+config NMI_DEBUGGING
-+	bool "NMI Debugging"
-+	default n
++config VFPv3
++	bool
++	depends on VFP
++	default y if CPU_V7
++
++config NEON
++	bool "Advanced SIMD (NEON) Extension support"
++	depends on VFPv3 && CPU_V7
 +	help
-+	  Say Y here and pass the nmi_debug command-line parameter to
-+	  the kernel to turn on NMI debugging. Depending on the value
-+	  of the nmi_debug option, various pieces of information will
-+	  be dumped to the console when a Non-Maskable Interrupt
-+	  happens.
++	  Say Y to include support code for NEON, the ARMv7 Advanced SIMD
++	  Extension.
 +
- # FPU emulation goes here
+ endmenu
  
- source "kernel/Kconfig.hz"
-@@ -219,6 +236,8 @@ source "drivers/Kconfig"
+ menu "Userspace binary formats"
+diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug
+index 18101f5..192ee01 100644
+--- a/arch/arm/Kconfig.debug
++++ b/arch/arm/Kconfig.debug
+@@ -43,6 +43,12 @@ config DEBUG_ERRORS
+ 	  you are concerned with the code size or don't want to see these
+ 	  messages.
+ 
++config DEBUG_STACK_USAGE
++	bool "Enable stack utilization instrumentation"
++	depends on DEBUG_KERNEL
++	help
++	  Enables the display of the minimum amount of free stack which each
++	  task has ever had available in the sysrq-T output.
  
- source "fs/Kconfig"
+ # These options are only for real kernel hackers who want to get their hands dirty.
+ config DEBUG_LL
+diff --git a/arch/arm/Kconfig.instrumentation b/arch/arm/Kconfig.instrumentation
+index 63b8c6d..453ad8e 100644
+--- a/arch/arm/Kconfig.instrumentation
++++ b/arch/arm/Kconfig.instrumentation
+@@ -43,6 +43,16 @@ config OPROFILE_MPCORE
+ config OPROFILE_ARM11_CORE
+ 	bool
  
-+source "kernel/Kconfig.instrumentation"
++config KPROBES
++	bool "Kprobes"
++	depends on KALLSYMS && MODULES && !UML && !XIP_KERNEL
++	help
++	  Kprobes allows you to trap at almost any kernel address and
++	  execute a callback function.  register_kprobe() establishes
++	  a probepoint and specifies the callback.  Kprobes is useful
++	  for kernel debugging, non-intrusive instrumentation and testing.
++	  If in doubt, say "N".
 +
- source "arch/avr32/Kconfig.debug"
- 
- source "security/Kconfig"
-diff --git a/arch/avr32/Kconfig.debug b/arch/avr32/Kconfig.debug
-index 64ace00..2283933 100644
---- a/arch/avr32/Kconfig.debug
-+++ b/arch/avr32/Kconfig.debug
-@@ -6,14 +6,4 @@ config TRACE_IRQFLAGS_SUPPORT
- 
- source "lib/Kconfig.debug"
+ config MARKERS
+ 	bool "Activate markers"
+ 	help
+diff --git a/arch/arm/Makefile b/arch/arm/Makefile
+index 35e56c9..7b8ff66 100644
+--- a/arch/arm/Makefile
++++ b/arch/arm/Makefile
+@@ -139,6 +139,8 @@ endif
+  machine-$(CONFIG_ARCH_KS8695)     := ks8695
+   incdir-$(CONFIG_ARCH_MXC)	   := mxc
+  machine-$(CONFIG_ARCH_MX3)	   := mx3
++ machine-$(CONFIG_ARCH_ORION)	   := orion
++ machine-$(CONFIG_ARCH_MSM7X00A)   := msm
+ 
+ ifeq ($(CONFIG_ARCH_EBSA110),y)
+ # This is what happens if you forget the IOCS16 line.
+diff --git a/arch/arm/boot/compressed/Makefile b/arch/arm/boot/compressed/Makefile
+index 5fde99f..de9d9ee 100644
+--- a/arch/arm/boot/compressed/Makefile
++++ b/arch/arm/boot/compressed/Makefile
+@@ -44,10 +44,6 @@ ifeq ($(CONFIG_PXA_SHARPSL),y)
+ OBJS		+= head-sharpsl.o
+ endif
  
--config KPROBES
--	bool "Kprobes"
--	depends on DEBUG_KERNEL
--	help
--	  Kprobes allows you to trap at almost any kernel address and
--          execute a callback function.  register_kprobe() establishes
--          a probepoint and specifies the callback.  Kprobes is useful
--          for kernel debugging, non-intrusive instrumentation and testing.
--          If in doubt, say "N".
+-ifeq ($(CONFIG_ARCH_AT91RM9200),y)
+-OBJS		+= head-at91rm9200.o
+-endif
 -
- endmenu
-diff --git a/arch/avr32/Makefile b/arch/avr32/Makefile
-index 8791864..17a3529 100644
---- a/arch/avr32/Makefile
-+++ b/arch/avr32/Makefile
-@@ -16,7 +16,7 @@ KBUILD_AFLAGS	+= -mrelax -mno-pic
- CFLAGS_MODULE	+= -mno-relax
- LDFLAGS_vmlinux	+= --relax
- 
--cpuflags-$(CONFIG_CPU_AT32AP7000)	+= -mcpu=ap7000
-+cpuflags-$(CONFIG_PLATFORM_AT32AP)	+= -march=ap
- 
- KBUILD_CFLAGS	+= $(cpuflags-y)
- KBUILD_AFLAGS	+= $(cpuflags-y)
-@@ -31,6 +31,7 @@ core-$(CONFIG_BOARD_ATNGW100)		+= arch/avr32/boards/atngw100/
- core-$(CONFIG_LOADER_U_BOOT)		+= arch/avr32/boot/u-boot/
- core-y					+= arch/avr32/kernel/
- core-y					+= arch/avr32/mm/
-+drivers-$(CONFIG_OPROFILE)		+= arch/avr32/oprofile/
- libs-y					+= arch/avr32/lib/
- 
- archincdir-$(CONFIG_PLATFORM_AT32AP)	:= arch-at32ap
-diff --git a/arch/avr32/boards/atngw100/setup.c b/arch/avr32/boards/atngw100/setup.c
-index 52987c8..a398be2 100644
---- a/arch/avr32/boards/atngw100/setup.c
-+++ b/arch/avr32/boards/atngw100/setup.c
-@@ -20,7 +20,7 @@
- #include <asm/io.h>
- #include <asm/setup.h>
- 
--#include <asm/arch/at32ap7000.h>
-+#include <asm/arch/at32ap700x.h>
- #include <asm/arch/board.h>
- #include <asm/arch/init.h>
- #include <asm/arch/portmux.h>
-diff --git a/arch/avr32/boards/atstk1000/Kconfig b/arch/avr32/boards/atstk1000/Kconfig
-index 718578f..af90b00 100644
---- a/arch/avr32/boards/atstk1000/Kconfig
-+++ b/arch/avr32/boards/atstk1000/Kconfig
-@@ -1,34 +1,53 @@
- # STK1000 customization
- 
--if BOARD_ATSTK1002
-+if BOARD_ATSTK1000
+ ifeq ($(CONFIG_CPU_BIG_ENDIAN),y)
+ ifeq ($(CONFIG_CPU_CP15),y)
+ OBJS		+= big-endian.o
+diff --git a/arch/arm/boot/compressed/head-at91rm9200.S b/arch/arm/boot/compressed/head-at91rm9200.S
+deleted file mode 100644
+index 11782cc..0000000
+--- a/arch/arm/boot/compressed/head-at91rm9200.S
++++ /dev/null
+@@ -1,81 +0,0 @@
+-/*
+- * linux/arch/arm/boot/compressed/head-at91rm9200.S
+- *
+- *  Copyright (C) 2003 SAN People
+- *
+- * This program is free software; you can redistribute it and/or modify
+- * it under the terms of the 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/mach-types.h>
+-
+-		.section	".start", "ax"
+-
+-		@ Atmel AT91RM9200-DK : 262
+-		mov	r3,	#(MACH_TYPE_AT91RM9200DK & 0xff)
+-		orr	r3, r3, #(MACH_TYPE_AT91RM9200DK & 0xff00)
+-		cmp	r7, r3
+-		beq	99f
+-
+-		@ Cogent CSB337 : 399
+-		mov	r3,	#(MACH_TYPE_CSB337 & 0xff)
+-		orr	r3, r3, #(MACH_TYPE_CSB337 & 0xff00)
+-		cmp	r7, r3
+-		beq	99f
+-
+-		@ Cogent CSB637 : 648
+-		mov	r3,	#(MACH_TYPE_CSB637 & 0xff)
+-		orr	r3, r3,	#(MACH_TYPE_CSB637 & 0xff00)
+-		cmp	r7, r3
+-		beq	99f
+-
+-		@ Atmel AT91RM9200-EK : 705
+-		mov	r3,	#(MACH_TYPE_AT91RM9200EK & 0xff)
+-		orr	r3, r3, #(MACH_TYPE_AT91RM9200EK & 0xff00)
+-		cmp	r7, r3
+-		beq	99f
+-
+-		@ Conitec Carmeva : 769
+-		mov	r3,	#(MACH_TYPE_CARMEVA & 0xff)
+-		orr	r3, r3, #(MACH_TYPE_CARMEVA & 0xff00)
+-		cmp	r7, r3
+-		beq	99f
+-
+-		@ KwikByte KB920x : 612
+-		mov	r3,	#(MACH_TYPE_KB9200 & 0xff)
+-		orr	r3, r3, #(MACH_TYPE_KB9200 & 0xff00)
+-		cmp	r7, r3
+-		beq	99f
+-
+-		@ Embest ATEB9200 : 923
+-		mov	r3,	#(MACH_TYPE_ATEB9200 & 0xff)
+-		orr	r3, r3,	#(MACH_TYPE_ATEB9200 & 0xff00)
+-		cmp	r7, r3
+-		beq	99f
+-
+-		@ Sperry-Sun KAFA : 662
+-		mov	r3,	#(MACH_TYPE_KAFA & 0xff)
+-		orr	r3, r3,	#(MACH_TYPE_KAFA & 0xff00)
+-		cmp	r7, r3
+-		beq	99f
+-
+-		@ picotux 200 : 963
+-		mov	r3,	#(MACH_TYPE_PICOTUX2XX & 0xff)
+-		orr	r3, r3, #(MACH_TYPE_PICOTUX2XX & 0xff00)
+-		cmp	r7, r3
+-		beq	99f
+-
+-		@ Ajeco 1ARM : 1075
+-		mov	r3,	#(MACH_TYPE_ONEARM & 0xff)
+-		orr	r3, r3, #(MACH_TYPE_ONEARM & 0xff00)
+-		cmp	r7, r3
+-		beq	99f
+-
+-		@ Unknown board, use the AT91RM9200DK board
+-		@ mov	r7, #MACH_TYPE_AT91RM9200
+-		mov	r7,	#(MACH_TYPE_AT91RM9200DK & 0xff)
+-		orr	r7, r7, #(MACH_TYPE_AT91RM9200DK & 0xff00)
+-
+-99:
+diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S
+index 5cac46a..3c2c8f2 100644
+--- a/arch/arm/boot/compressed/head.S
++++ b/arch/arm/boot/compressed/head.S
+@@ -623,6 +623,12 @@ proc_types:
+ 		b	__armv4_mmu_cache_off
+ 		b	__armv4_mmu_cache_flush
+ 
++		.word	0x56055310		@ Feroceon
++		.word	0xfffffff0
++		b	__armv4_mmu_cache_on
++		b	__armv4_mmu_cache_off
++		b	__armv5tej_mmu_cache_flush
++
+ 		@ These match on the architecture ID
+ 
+ 		.word	0x00020000		@ ARMv4T
+@@ -641,7 +647,7 @@ proc_types:
+ 		.word	0x000f0000
+ 		b	__armv4_mmu_cache_on
+ 		b	__armv4_mmu_cache_off
+-		b	__armv4_mmu_cache_flush
++		b	__armv5tej_mmu_cache_flush
+ 
+ 		.word	0x0007b000		@ ARMv6
+ 		.word	0x000ff000
+@@ -821,6 +827,13 @@ iflush:
+ 		mcr	p15, 0, r10, c7, c10, 4	@ drain WB
+ 		mov	pc, lr
+ 
++__armv5tej_mmu_cache_flush:
++1:		mrc	p15, 0, r15, c7, c14, 3	@ test,clean,invalidate D cache
++		bne	1b
++		mcr	p15, 0, r0, c7, c5, 0	@ flush I cache
++		mcr	p15, 0, r0, c7, c10, 4	@ drain WB
++		mov	pc, lr
++
+ __armv4_mmu_cache_flush:
+ 		mov	r2, #64*1024		@ default: 32K dcache size (*2)
+ 		mov	r11, #32		@ default: 32 byte line size
+diff --git a/arch/arm/common/rtctime.c b/arch/arm/common/rtctime.c
+index bf1075e..f53bca4 100644
+--- a/arch/arm/common/rtctime.c
++++ b/arch/arm/common/rtctime.c
+@@ -20,7 +20,6 @@
+ #include <linux/capability.h>
+ #include <linux/device.h>
+ #include <linux/mutex.h>
+-#include <linux/rtc.h>
  
--config BOARD_ATSTK1002_CUSTOM
--	bool "Non-default STK-1002 jumper settings"
-+choice
-+	prompt "ATSTK1000 CPU daughterboard type"
-+	default BOARD_ATSTK1002
+ #include <asm/rtc.h>
+ #include <asm/semaphore.h>
+diff --git a/arch/arm/configs/at91cap9adk_defconfig b/arch/arm/configs/at91cap9adk_defconfig
+new file mode 100644
+index 0000000..e32e736
+--- /dev/null
++++ b/arch/arm/configs/at91cap9adk_defconfig
+@@ -0,0 +1,1143 @@
++#
++# Automatically generated make config: don't edit
++# Linux kernel version: 2.6.24-rc8
++# Wed Jan 23 22:55:57 2008
++#
++CONFIG_ARM=y
++CONFIG_SYS_SUPPORTS_APM_EMULATION=y
++CONFIG_GENERIC_GPIO=y
++# CONFIG_GENERIC_TIME is not set
++# CONFIG_GENERIC_CLOCKEVENTS is not set
++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_ZONE_DMA=y
++CONFIG_VECTORS_BASE=0xffff0000
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
 +
-+config BOARD_ATSTK1002
-+	bool "ATSTK1002"
-+	select CPU_AT32AP7000
++#
++# 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 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_USER_NS is not set
++# CONFIG_PID_NS is not set
++# CONFIG_AUDIT is not set
++# CONFIG_IKCONFIG is not set
++CONFIG_LOG_BUF_SHIFT=14
++# CONFIG_CGROUPS is not set
++CONFIG_FAIR_GROUP_SCHED=y
++CONFIG_FAIR_USER_SCHED=y
++# CONFIG_FAIR_CGROUP_SCHED is not set
++CONFIG_SYSFS_DEPRECATED=y
++# CONFIG_RELAY 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_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_BASE_FULL=y
++CONFIG_FUTEX=y
++CONFIG_ANON_INODES=y
++CONFIG_EPOLL=y
++CONFIG_SIGNALFD=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_SLABINFO=y
++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
 +
-+config BOARD_ATSTK1003
-+	bool "ATSTK1003"
-+	select CPU_AT32AP7001
++#
++# 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 BOARD_ATSTK1004
-+	bool "ATSTK1004"
-+	select CPU_AT32AP7002
++#
++# 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_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_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
 +
-+endchoice
++#
++# Boot options
++#
 +
++#
++# Power management
++#
 +
-+config BOARD_ATSTK100X_CUSTOM
-+	bool "Non-default STK1002/STK1003/STK1004 jumper settings"
- 	help
- 	  You will normally leave the jumpers on the CPU card at their
- 	  default settings.  If you need to use certain peripherals,
- 	  you will need to change some of those jumpers.
- 
--if BOARD_ATSTK1002_CUSTOM
-+if BOARD_ATSTK100X_CUSTOM
- 
--config BOARD_ATSTK1002_SW1_CUSTOM
-+config BOARD_ATSTK100X_SW1_CUSTOM
- 	bool "SW1: use SSC1 (not SPI0)"
- 	help
- 	  This also prevents using the external DAC as an audio interface,
- 	  and means you can't initialize the on-board QVGA display.
- 
--config BOARD_ATSTK1002_SW2_CUSTOM
-+config BOARD_ATSTK100X_SW2_CUSTOM
- 	bool "SW2: use IRDA or TIMER0 (not UART-A, MMC/SD, and PS2-A)"
- 	help
- 	  If you change this you'll want an updated boot loader putting
- 	  the console on UART-C not UART-A.
- 
--config BOARD_ATSTK1002_SW3_CUSTOM
-+config BOARD_ATSTK100X_SW3_CUSTOM
- 	bool "SW3: use TIMER1 (not SSC0 and GCLK)"
- 	help
- 	  This also prevents using the external DAC as an audio interface.
- 
--config BOARD_ATSTK1002_SW4_CUSTOM
-+config BOARD_ATSTK100X_SW4_CUSTOM
- 	bool "SW4: use ISI/Camera (not GPIOs, SPI1, and PS2-B)"
- 	help
- 	  To use the camera interface you'll need a custom card (on the
-@@ -36,27 +55,29 @@ config BOARD_ATSTK1002_SW4_CUSTOM
- 
- config BOARD_ATSTK1002_SW5_CUSTOM
- 	bool "SW5: use MACB1 (not LCDC)"
-+	depends on BOARD_ATSTK1002
- 
- config BOARD_ATSTK1002_SW6_CUSTOM
- 	bool "SW6: more GPIOs (not MACB0)"
-+	depends on BOARD_ATSTK1002
- 
- endif	# custom
- 
--config BOARD_ATSTK1002_SPI1
-+config BOARD_ATSTK100X_SPI1
- 	bool "Configure SPI1 controller"
--	depends on !BOARD_ATSTK1002_SW4_CUSTOM
-+	depends on !BOARD_ATSTK100X_SW4_CUSTOM
- 	help
- 	  All the signals for the second SPI controller are available on
- 	  GPIO lines and accessed through the J1 jumper block.  Say "y"
- 	  here to configure that SPI controller.
- 
--config BOARD_ATSTK1002_J2_LED
-+config BOARD_ATSTK1000_J2_LED
- 	bool
--	default BOARD_ATSTK1002_J2_LED8 || BOARD_ATSTK1002_J2_RGB
-+	default BOARD_ATSTK1000_J2_LED8 || BOARD_ATSTK1000_J2_RGB
- 
- choice
- 	prompt "LEDs connected to J2:"
--	depends on LEDS_GPIO && !BOARD_ATSTK1002_SW4_CUSTOM
-+	depends on LEDS_GPIO && !BOARD_ATSTK100X_SW4_CUSTOM
- 	optional
- 	help
- 	  Select this if you have jumpered the J2 jumper block to the
-@@ -64,16 +85,21 @@ choice
- 	  IDC cable.  A default "heartbeat" trigger is provided, but
- 	  you can of course override this.
- 
--config BOARD_ATSTK1002_J2_LED8
-+config BOARD_ATSTK1000_J2_LED8
- 	bool "LED0..LED7"
- 	help
- 	  Select this if J2 is jumpered to LED0..LED7 amber leds.
- 
--config BOARD_ATSTK1002_J2_RGB
-+config BOARD_ATSTK1000_J2_RGB
- 	bool "RGB leds"
- 	help
- 	  Select this if J2 is jumpered to the RGB leds.
- 
- endchoice
- 
--endif	# stk 1002
-+config BOARD_ATSTK1000_EXTDAC
-+	bool
-+	depends on !BOARD_ATSTK100X_SW1_CUSTOM && !BOARD_ATSTK100X_SW3_CUSTOM
-+	default y
++#
++# Atmel AT91 System-on-Chip
++#
++# CONFIG_ARCH_AT91RM9200 is not set
++# CONFIG_ARCH_AT91SAM9260 is not set
++# CONFIG_ARCH_AT91SAM9261 is not set
++# CONFIG_ARCH_AT91SAM9263 is not set
++# CONFIG_ARCH_AT91SAM9RL is not set
++CONFIG_ARCH_AT91CAP9=y
++# CONFIG_ARCH_AT91X40 is not set
++CONFIG_AT91_PMC_UNIT=y
 +
-+endif	# stk 1000
-diff --git a/arch/avr32/boards/atstk1000/Makefile b/arch/avr32/boards/atstk1000/Makefile
-index 8e09922..beead86 100644
---- a/arch/avr32/boards/atstk1000/Makefile
-+++ b/arch/avr32/boards/atstk1000/Makefile
-@@ -1,2 +1,4 @@
- obj-y				+= setup.o flash.o
- obj-$(CONFIG_BOARD_ATSTK1002)	+= atstk1002.o
-+obj-$(CONFIG_BOARD_ATSTK1003)	+= atstk1003.o
-+obj-$(CONFIG_BOARD_ATSTK1004)	+= atstk1004.o
-diff --git a/arch/avr32/boards/atstk1000/atstk1000.h b/arch/avr32/boards/atstk1000/atstk1000.h
-index 9a49ed0..9392d32 100644
---- a/arch/avr32/boards/atstk1000/atstk1000.h
-+++ b/arch/avr32/boards/atstk1000/atstk1000.h
-@@ -12,4 +12,6 @@
- 
- extern struct atmel_lcdfb_info atstk1000_lcdc_data;
- 
-+void atstk1000_setup_j2_leds(void);
++#
++# AT91CAP9 Board Type
++#
++CONFIG_MACH_AT91CAP9ADK=y
 +
- #endif /* __ARCH_AVR32_BOARDS_ATSTK1000_ATSTK1000_H */
-diff --git a/arch/avr32/boards/atstk1000/atstk1002.c b/arch/avr32/boards/atstk1000/atstk1002.c
-index 5be0d13..000eb42 100644
---- a/arch/avr32/boards/atstk1000/atstk1002.c
-+++ b/arch/avr32/boards/atstk1000/atstk1002.c
-@@ -11,7 +11,6 @@
- #include <linux/etherdevice.h>
- #include <linux/init.h>
- #include <linux/kernel.h>
--#include <linux/leds.h>
- #include <linux/platform_device.h>
- #include <linux/string.h>
- #include <linux/types.h>
-@@ -22,7 +21,7 @@
- 
- #include <asm/io.h>
- #include <asm/setup.h>
--#include <asm/arch/at32ap7000.h>
-+#include <asm/arch/at32ap700x.h>
- #include <asm/arch/board.h>
- #include <asm/arch/init.h>
- #include <asm/arch/portmux.h>
-@@ -49,18 +48,16 @@ static struct eth_platform_data __initdata eth_data[2] = {
- 	},
- };
- 
--#ifndef CONFIG_BOARD_ATSTK1002_SW1_CUSTOM
--#ifndef CONFIG_BOARD_ATSTK1002_SW3_CUSTOM
-+#ifdef CONFIG_BOARD_ATSTK1000_EXTDAC
- static struct at73c213_board_info at73c213_data = {
- 	.ssc_id		= 0,
- 	.shortname	= "AVR32 STK1000 external DAC",
- };
- #endif
--#endif
- 
--#ifndef CONFIG_BOARD_ATSTK1002_SW1_CUSTOM
-+#ifndef CONFIG_BOARD_ATSTK100X_SW1_CUSTOM
- static struct spi_board_info spi0_board_info[] __initdata = {
--#ifndef CONFIG_BOARD_ATSTK1002_SW3_CUSTOM
-+#ifdef CONFIG_BOARD_ATSTK1000_EXTDAC
- 	{
- 		/* AT73C213 */
- 		.modalias	= "at73c213",
-@@ -80,7 +77,7 @@ static struct spi_board_info spi0_board_info[] __initdata = {
- };
- #endif
- 
--#ifdef CONFIG_BOARD_ATSTK1002_SPI1
-+#ifdef CONFIG_BOARD_ATSTK100X_SPI1
- static struct spi_board_info spi1_board_info[] __initdata = { {
- 	/* patch in custom entries here */
- } };
-@@ -141,68 +138,8 @@ static void __init set_hw_addr(struct platform_device *pdev)
- 	clk_put(pclk);
- }
- 
--#ifdef CONFIG_BOARD_ATSTK1002_J2_LED
--
--static struct gpio_led stk_j2_led[] = {
--#ifdef CONFIG_BOARD_ATSTK1002_J2_LED8
--#define LEDSTRING "J2 jumpered to LED8"
--	{ .name = "led0:amber", .gpio = GPIO_PIN_PB( 8), },
--	{ .name = "led1:amber", .gpio = GPIO_PIN_PB( 9), },
--	{ .name = "led2:amber", .gpio = GPIO_PIN_PB(10), },
--	{ .name = "led3:amber", .gpio = GPIO_PIN_PB(13), },
--	{ .name = "led4:amber", .gpio = GPIO_PIN_PB(14), },
--	{ .name = "led5:amber", .gpio = GPIO_PIN_PB(15), },
--	{ .name = "led6:amber", .gpio = GPIO_PIN_PB(16), },
--	{ .name = "led7:amber", .gpio = GPIO_PIN_PB(30),
--			.default_trigger = "heartbeat", },
--#else	/* RGB */
--#define LEDSTRING "J2 jumpered to RGB LEDs"
--	{ .name = "r1:red",     .gpio = GPIO_PIN_PB( 8), },
--	{ .name = "g1:green",   .gpio = GPIO_PIN_PB(10), },
--	{ .name = "b1:blue",    .gpio = GPIO_PIN_PB(14), },
--
--	{ .name = "r2:red",     .gpio = GPIO_PIN_PB( 9),
--			.default_trigger = "heartbeat", },
--	{ .name = "g2:green",   .gpio = GPIO_PIN_PB(13), },
--	{ .name = "b2:blue",    .gpio = GPIO_PIN_PB(15),
--			.default_trigger = "heartbeat", },
--	/* PB16, PB30 unused */
--#endif
--};
--
--static struct gpio_led_platform_data stk_j2_led_data = {
--	.num_leds	= ARRAY_SIZE(stk_j2_led),
--	.leds		= stk_j2_led,
--};
--
--static struct platform_device stk_j2_led_dev = {
--	.name		= "leds-gpio",
--	.id		= 2,	/* gpio block J2 */
--	.dev		= {
--		.platform_data	= &stk_j2_led_data,
--	},
--};
--
--static void setup_j2_leds(void)
--{
--	unsigned	i;
--
--	for (i = 0; i < ARRAY_SIZE(stk_j2_led); i++)
--		at32_select_gpio(stk_j2_led[i].gpio, AT32_GPIOF_OUTPUT);
--
--	printk("STK1002: " LEDSTRING "\n");
--	platform_device_register(&stk_j2_led_dev);
--}
--
--#else
--static void setup_j2_leds(void)
--{
--}
--#endif
--
--#ifndef CONFIG_BOARD_ATSTK1002_SW1_CUSTOM
--#ifndef CONFIG_BOARD_ATSTK1002_SW3_CUSTOM
--static void __init at73c213_set_clk(struct at73c213_board_info *info)
-+#ifdef CONFIG_BOARD_ATSTK1000_EXTDAC
-+static void __init atstk1002_setup_extdac(void)
- {
- 	struct clk *gclk;
- 	struct clk *pll;
-@@ -220,7 +157,7 @@ static void __init at73c213_set_clk(struct at73c213_board_info *info)
- 	}
- 
- 	at32_select_periph(GPIO_PIN_PA(30), GPIO_PERIPH_A, 0);
--	info->dac_clk = gclk;
-+	at73c213_data.dac_clk = gclk;
- 
- err_set_clk:
- 	clk_put(pll);
-@@ -229,12 +166,16 @@ err_pll:
- err_gclk:
- 	return;
- }
--#endif
--#endif
-+#else
-+static void __init atstk1002_setup_extdac(void)
-+{
++#
++# AT91 Board Options
++#
++CONFIG_MTD_AT91_DATAFLASH_CARD=y
++# CONFIG_MTD_NAND_AT91_BUSWIDTH_16 is not set
 +
-+}
-+#endif /* CONFIG_BOARD_ATSTK1000_EXTDAC */
- 
- void __init setup_board(void)
- {
--#ifdef	CONFIG_BOARD_ATSTK1002_SW2_CUSTOM
-+#ifdef	CONFIG_BOARD_ATSTK100X_SW2_CUSTOM
- 	at32_map_usart(0, 1);	/* USART 0/B: /dev/ttyS1, IRDA */
- #else
- 	at32_map_usart(1, 0);	/* USART 1/A: /dev/ttyS0, DB9 */
-@@ -271,7 +212,7 @@ static int __init atstk1002_init(void)
- 
- 	at32_add_system_devices();
- 
--#ifdef	CONFIG_BOARD_ATSTK1002_SW2_CUSTOM
-+#ifdef	CONFIG_BOARD_ATSTK100X_SW2_CUSTOM
- 	at32_add_device_usart(1);
- #else
- 	at32_add_device_usart(0);
-@@ -281,10 +222,10 @@ static int __init atstk1002_init(void)
- #ifndef CONFIG_BOARD_ATSTK1002_SW6_CUSTOM
- 	set_hw_addr(at32_add_device_eth(0, &eth_data[0]));
- #endif
--#ifndef CONFIG_BOARD_ATSTK1002_SW1_CUSTOM
-+#ifndef CONFIG_BOARD_ATSTK100X_SW1_CUSTOM
- 	at32_add_device_spi(0, spi0_board_info, ARRAY_SIZE(spi0_board_info));
- #endif
--#ifdef CONFIG_BOARD_ATSTK1002_SPI1
-+#ifdef CONFIG_BOARD_ATSTK100X_SPI1
- 	at32_add_device_spi(1, spi1_board_info, ARRAY_SIZE(spi1_board_info));
- #endif
- #ifdef CONFIG_BOARD_ATSTK1002_SW5_CUSTOM
-@@ -294,17 +235,12 @@ static int __init atstk1002_init(void)
- 			     fbmem_start, fbmem_size);
- #endif
- 	at32_add_device_usba(0, NULL);
--#ifndef CONFIG_BOARD_ATSTK1002_SW3_CUSTOM
-+#ifndef CONFIG_BOARD_ATSTK100X_SW3_CUSTOM
- 	at32_add_device_ssc(0, ATMEL_SSC_TX);
- #endif
- 
--	setup_j2_leds();
--
--#ifndef CONFIG_BOARD_ATSTK1002_SW3_CUSTOM
--#ifndef CONFIG_BOARD_ATSTK1002_SW1_CUSTOM
--	at73c213_set_clk(&at73c213_data);
--#endif
--#endif
-+	atstk1000_setup_j2_leds();
-+	atstk1002_setup_extdac();
- 
- 	return 0;
- }
-diff --git a/arch/avr32/boards/atstk1000/atstk1003.c b/arch/avr32/boards/atstk1000/atstk1003.c
-new file mode 100644
-index 0000000..a0b223d
---- /dev/null
-+++ b/arch/avr32/boards/atstk1000/atstk1003.c
-@@ -0,0 +1,162 @@
-+/*
-+ * ATSTK1003 daughterboard-specific init code
-+ *
-+ * 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 version 2 as
-+ * published by the Free Software Foundation.
-+ */
-+#include <linux/clk.h>
-+#include <linux/err.h>
-+#include <linux/init.h>
-+#include <linux/kernel.h>
-+#include <linux/platform_device.h>
-+#include <linux/string.h>
-+#include <linux/types.h>
++#
++# AT91 Feature Selections
++#
++CONFIG_AT91_PROGRAMMABLE_CLOCKS=y
++CONFIG_AT91_TIMER_HZ=100
 +
-+#include <linux/spi/at73c213.h>
-+#include <linux/spi/spi.h>
++#
++# Processor Type
++#
++CONFIG_CPU_32=y
++CONFIG_CPU_ARM926T=y
++CONFIG_CPU_32v5=y
++CONFIG_CPU_ABRT_EV5TJ=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
 +
-+#include <asm/setup.h>
++#
++# Processor Features
++#
++# CONFIG_ARM_THUMB is not set
++# 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
 +
-+#include <asm/arch/at32ap700x.h>
-+#include <asm/arch/board.h>
-+#include <asm/arch/init.h>
-+#include <asm/arch/portmux.h>
++#
++# Bus support
++#
++# CONFIG_PCI_SYSCALL is not set
++# CONFIG_ARCH_SUPPORTS_MSI is not set
++# CONFIG_PCCARD is not set
 +
-+#include "atstk1000.h"
++#
++# Kernel Features
++#
++# CONFIG_TICK_ONESHOT is not set
++# CONFIG_PREEMPT is not set
++# CONFIG_NO_IDLE_HZ 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_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=y
++CONFIG_LEDS_TIMER=y
++CONFIG_LEDS_CPU=y
++CONFIG_ALIGNMENT_TRAP=y
 +
-+#ifdef CONFIG_BOARD_ATSTK1000_EXTDAC
-+static struct at73c213_board_info at73c213_data = {
-+	.ssc_id		= 0,
-+	.shortname	= "AVR32 STK1000 external DAC",
-+};
-+#endif
++#
++# Boot options
++#
++CONFIG_ZBOOT_ROM_TEXT=0x0
++CONFIG_ZBOOT_ROM_BSS=0x0
++CONFIG_CMDLINE="console=ttyS0,115200 root=/dev/ram0 rw"
++# CONFIG_XIP_KERNEL is not set
++# CONFIG_KEXEC is not set
 +
-+#ifndef CONFIG_BOARD_ATSTK100X_SW1_CUSTOM
-+static struct spi_board_info spi0_board_info[] __initdata = {
-+#ifdef CONFIG_BOARD_ATSTK1000_EXTDAC
-+	{
-+		/* AT73C213 */
-+		.modalias	= "at73c213",
-+		.max_speed_hz	= 200000,
-+		.chip_select	= 0,
-+		.mode		= SPI_MODE_1,
-+		.platform_data	= &at73c213_data,
-+	},
-+#endif
-+	/*
-+	 * We can control the LTV350QV LCD panel, but it isn't much
-+	 * point since we don't have an LCD controller...
-+	 */
-+};
-+#endif
++#
++# Floating point emulation
++#
 +
-+#ifdef CONFIG_BOARD_ATSTK100X_SPI1
-+static struct spi_board_info spi1_board_info[] __initdata = { {
-+	/* patch in custom entries here */
-+} };
-+#endif
++#
++# 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
 +
-+#ifdef CONFIG_BOARD_ATSTK1000_EXTDAC
-+static void __init atstk1003_setup_extdac(void)
-+{
-+	struct clk *gclk;
-+	struct clk *pll;
++#
++# Userspace binary formats
++#
++CONFIG_BINFMT_ELF=y
++# CONFIG_BINFMT_AOUT is not set
++# CONFIG_BINFMT_MISC is not set
 +
-+	gclk = clk_get(NULL, "gclk0");
-+	if (IS_ERR(gclk))
-+		goto err_gclk;
-+	pll = clk_get(NULL, "pll0");
-+	if (IS_ERR(pll))
-+		goto err_pll;
++#
++# Power management options
++#
++# CONFIG_PM is not set
++CONFIG_SUSPEND_UP_POSSIBLE=y
 +
-+	if (clk_set_parent(gclk, pll)) {
-+		pr_debug("STK1000: failed to set pll0 as parent for DAC clock\n");
-+		goto err_set_clk;
-+	}
++#
++# Networking
++#
++CONFIG_NET=y
 +
-+	at32_select_periph(GPIO_PIN_PA(30), GPIO_PERIPH_A, 0);
-+	at73c213_data.dac_clk = gclk;
++#
++# 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=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_INET6_XFRM_TUNNEL is not set
++# CONFIG_INET6_TUNNEL 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
 +
-+err_set_clk:
-+	clk_put(pll);
-+err_pll:
-+	clk_put(gclk);
-+err_gclk:
-+	return;
-+}
-+#else
-+static void __init atstk1003_setup_extdac(void)
-+{
++#
++# Network testing
++#
++# CONFIG_NET_PKTGEN is not set
++# CONFIG_HAMRADIO is not set
++# CONFIG_IRDA is not set
++# CONFIG_BT is not set
++# CONFIG_AF_RXRPC is not set
 +
-+}
-+#endif /* CONFIG_BOARD_ATSTK1000_EXTDAC */
++#
++# 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
 +
-+void __init setup_board(void)
-+{
-+#ifdef	CONFIG_BOARD_ATSTK100X_SW2_CUSTOM
-+	at32_map_usart(0, 1);	/* USART 0/B: /dev/ttyS1, IRDA */
-+#else
-+	at32_map_usart(1, 0);	/* USART 1/A: /dev/ttyS0, DB9 */
-+#endif
-+	/* USART 2/unused: expansion connector */
-+	at32_map_usart(3, 2);	/* USART 3/C: /dev/ttyS2, DB9 */
++#
++# Device Drivers
++#
 +
-+	at32_setup_serial_console(0);
-+}
++#
++# Generic Driver Options
++#
++CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
++CONFIG_STANDALONE=y
++CONFIG_PREVENT_FIRMWARE_BUILD=y
++# CONFIG_FW_LOADER is not set
++# 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
 +
-+static int __init atstk1003_init(void)
-+{
-+	/*
-+	 * ATSTK1000 uses 32-bit SDRAM interface. Reserve the
-+	 * SDRAM-specific pins so that nobody messes with them.
-+	 */
-+	at32_reserve_pin(GPIO_PIN_PE(0));	/* DATA[16]	*/
-+	at32_reserve_pin(GPIO_PIN_PE(1));	/* DATA[17]	*/
-+	at32_reserve_pin(GPIO_PIN_PE(2));	/* DATA[18]	*/
-+	at32_reserve_pin(GPIO_PIN_PE(3));	/* DATA[19]	*/
-+	at32_reserve_pin(GPIO_PIN_PE(4));	/* DATA[20]	*/
-+	at32_reserve_pin(GPIO_PIN_PE(5));	/* DATA[21]	*/
-+	at32_reserve_pin(GPIO_PIN_PE(6));	/* DATA[22]	*/
-+	at32_reserve_pin(GPIO_PIN_PE(7));	/* DATA[23]	*/
-+	at32_reserve_pin(GPIO_PIN_PE(8));	/* DATA[24]	*/
-+	at32_reserve_pin(GPIO_PIN_PE(9));	/* DATA[25]	*/
-+	at32_reserve_pin(GPIO_PIN_PE(10));	/* DATA[26]	*/
-+	at32_reserve_pin(GPIO_PIN_PE(11));	/* DATA[27]	*/
-+	at32_reserve_pin(GPIO_PIN_PE(12));	/* DATA[28]	*/
-+	at32_reserve_pin(GPIO_PIN_PE(13));	/* DATA[29]	*/
-+	at32_reserve_pin(GPIO_PIN_PE(14));	/* DATA[30]	*/
-+	at32_reserve_pin(GPIO_PIN_PE(15));	/* DATA[31]	*/
-+	at32_reserve_pin(GPIO_PIN_PE(26));	/* SDCS		*/
++#
++# 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
 +
-+	at32_add_system_devices();
++#
++# RAM/ROM/Flash chip drivers
++#
++CONFIG_MTD_CFI=y
++CONFIG_MTD_JEDECPROBE=y
++CONFIG_MTD_GEN_PROBE=y
++# 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=y
++# 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
 +
-+#ifdef	CONFIG_BOARD_ATSTK100X_SW2_CUSTOM
-+	at32_add_device_usart(1);
-+#else
-+	at32_add_device_usart(0);
-+#endif
-+	at32_add_device_usart(2);
++#
++# 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=0x0
++CONFIG_MTD_PHYSMAP_BANKWIDTH=0
++# CONFIG_MTD_ARM_INTEGRATOR is not set
++# CONFIG_MTD_IMPA7 is not set
++# CONFIG_MTD_PLATRAM is not set
 +
-+#ifndef CONFIG_BOARD_ATSTK100X_SW1_CUSTOM
-+	at32_add_device_spi(0, spi0_board_info, ARRAY_SIZE(spi0_board_info));
-+#endif
-+#ifdef CONFIG_BOARD_ATSTK100X_SPI1
-+	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);
-+#endif
-+	at32_add_device_usba(0, NULL);
-+#ifndef CONFIG_BOARD_ATSTK100X_SW3_CUSTOM
-+	at32_add_device_ssc(0, ATMEL_SSC_TX);
-+#endif
++#
++# 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
 +
-+	atstk1000_setup_j2_leds();
-+	atstk1003_setup_extdac();
++#
++# 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_AT91=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
 +
-+	return 0;
-+}
-+postcore_initcall(atstk1003_init);
-diff --git a/arch/avr32/boards/atstk1000/atstk1004.c b/arch/avr32/boards/atstk1000/atstk1004.c
-new file mode 100644
-index 0000000..5a77030
---- /dev/null
-+++ b/arch/avr32/boards/atstk1000/atstk1004.c
-@@ -0,0 +1,147 @@
-+/*
-+ * ATSTK1003 daughterboard-specific init code
-+ *
-+ * 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 version 2 as
-+ * published by the Free Software Foundation.
-+ */
-+#include <linux/clk.h>
-+#include <linux/err.h>
-+#include <linux/init.h>
-+#include <linux/kernel.h>
-+#include <linux/platform_device.h>
-+#include <linux/string.h>
-+#include <linux/types.h>
++#
++# 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=8192
++CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
++# CONFIG_CDROM_PKTCDVD is not set
++# CONFIG_ATA_OVER_ETH is not set
++CONFIG_MISC_DEVICES=y
++# CONFIG_EEPROM_93CX6 is not set
++CONFIG_ATMEL_SSC=y
 +
-+#include <linux/spi/at73c213.h>
-+#include <linux/spi/spi.h>
++#
++# 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
 +
-+#include <video/atmel_lcdc.h>
++#
++# 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
 +
-+#include <asm/setup.h>
++#
++# 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
 +
-+#include <asm/arch/at32ap700x.h>
-+#include <asm/arch/board.h>
-+#include <asm/arch/init.h>
-+#include <asm/arch/portmux.h>
++#
++# 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_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
 +
-+#include "atstk1000.h"
++#
++# 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_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_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
 +
-+#ifdef CONFIG_BOARD_ATSTK1000_EXTDAC
-+static struct at73c213_board_info at73c213_data = {
-+	.ssc_id		= 0,
-+	.shortname	= "AVR32 STK1000 external DAC",
-+};
-+#endif
++#
++# Wireless LAN
++#
++# CONFIG_WLAN_PRE80211 is not set
++# CONFIG_WLAN_80211 is not set
 +
-+#ifndef CONFIG_BOARD_ATSTK100X_SW1_CUSTOM
-+static struct spi_board_info spi0_board_info[] __initdata = {
-+#ifdef CONFIG_BOARD_ATSTK1000_EXTDAC
-+	{
-+		/* AT73C213 */
-+		.modalias	= "at73c213",
-+		.max_speed_hz	= 200000,
-+		.chip_select	= 0,
-+		.mode		= SPI_MODE_1,
-+		.platform_data	= &at73c213_data,
-+	},
-+#endif
-+	{
-+		/* QVGA display */
-+		.modalias	= "ltv350qv",
-+		.max_speed_hz	= 16000000,
-+		.chip_select	= 1,
-+		.mode		= SPI_MODE_3,
-+	},
-+};
-+#endif
++#
++# 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_SHAPER 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
 +
-+#ifdef CONFIG_BOARD_ATSTK100X_SPI1
-+static struct spi_board_info spi1_board_info[] __initdata = { {
-+	/* patch in custom entries here */
-+} };
-+#endif
++#
++# Input device support
++#
++CONFIG_INPUT=y
++# CONFIG_INPUT_FF_MEMLESS is not set
++# CONFIG_INPUT_POLLDEV is not set
 +
-+#ifdef CONFIG_BOARD_ATSTK1000_EXTDAC
-+static void __init atstk1004_setup_extdac(void)
-+{
-+	struct clk *gclk;
-+	struct clk *pll;
++#
++# 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
 +
-+	gclk = clk_get(NULL, "gclk0");
-+	if (IS_ERR(gclk))
-+		goto err_gclk;
-+	pll = clk_get(NULL, "pll0");
-+	if (IS_ERR(pll))
-+		goto err_pll;
++#
++# 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_ADS7846=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 is not set
++# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set
++# CONFIG_INPUT_MISC is not set
 +
-+	if (clk_set_parent(gclk, pll)) {
-+		pr_debug("STK1000: failed to set pll0 as parent for DAC clock\n");
-+		goto err_set_clk;
-+	}
++#
++# Hardware I/O ports
++#
++# CONFIG_SERIO is not set
++# CONFIG_GAMEPORT is not set
 +
-+	at32_select_periph(GPIO_PIN_PA(30), GPIO_PERIPH_A, 0);
-+	at73c213_data.dac_clk = gclk;
++#
++# Character devices
++#
++CONFIG_VT=y
++CONFIG_VT_CONSOLE=y
++CONFIG_HW_CONSOLE=y
++# CONFIG_VT_HW_CONSOLE_BINDING is not set
++# CONFIG_SERIAL_NONSTANDARD is not set
 +
-+err_set_clk:
-+	clk_put(pll);
-+err_pll:
-+	clk_put(gclk);
-+err_gclk:
-+	return;
-+}
-+#else
-+static void __init atstk1004_setup_extdac(void)
-+{
++#
++# Serial drivers
++#
++# CONFIG_SERIAL_8250 is not set
 +
-+}
-+#endif /* CONFIG_BOARD_ATSTK1000_EXTDAC */
++#
++# Non-8250 serial port support
++#
++CONFIG_SERIAL_ATMEL=y
++CONFIG_SERIAL_ATMEL_CONSOLE=y
++# CONFIG_SERIAL_ATMEL_TTYAT is not set
++CONFIG_SERIAL_CORE=y
++CONFIG_SERIAL_CORE_CONSOLE=y
++CONFIG_UNIX98_PTYS=y
++CONFIG_LEGACY_PTYS=y
++CONFIG_LEGACY_PTY_COUNT=256
++# CONFIG_IPMI_HANDLER is not set
++CONFIG_HW_RANDOM=y
++# 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
 +
-+void __init setup_board(void)
-+{
-+#ifdef	CONFIG_BOARD_ATSTK100X_SW2_CUSTOM
-+	at32_map_usart(0, 1);	/* USART 0/B: /dev/ttyS1, IRDA */
-+#else
-+	at32_map_usart(1, 0);	/* USART 1/A: /dev/ttyS0, DB9 */
-+#endif
-+	/* USART 2/unused: expansion connector */
-+	at32_map_usart(3, 2);	/* USART 3/C: /dev/ttyS2, DB9 */
++#
++# I2C Algorithms
++#
++# CONFIG_I2C_ALGOBIT is not set
++# CONFIG_I2C_ALGOPCF is not set
++# CONFIG_I2C_ALGOPCA is not set
 +
-+	at32_setup_serial_console(0);
-+}
++#
++# I2C Hardware Bus support
++#
++# 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
 +
-+static int __init atstk1004_init(void)
-+{
-+	at32_add_system_devices();
++#
++# Miscellaneous I2C Chip support
++#
++# CONFIG_SENSORS_DS1337 is not set
++# CONFIG_SENSORS_DS1374 is not set
++# CONFIG_DS1682 is not set
++# CONFIG_SENSORS_EEPROM is not set
++# CONFIG_SENSORS_PCF8574 is not set
++# CONFIG_SENSORS_PCA9539 is not set
++# CONFIG_SENSORS_PCF8591 is not set
++# CONFIG_SENSORS_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
 +
-+#ifdef	CONFIG_BOARD_ATSTK100X_SW2_CUSTOM
-+	at32_add_device_usart(1);
-+#else
-+	at32_add_device_usart(0);
-+#endif
-+	at32_add_device_usart(2);
++#
++# SPI support
++#
++CONFIG_SPI=y
++# CONFIG_SPI_DEBUG is not set
++CONFIG_SPI_MASTER=y
 +
-+#ifndef CONFIG_BOARD_ATSTK100X_SW1_CUSTOM
-+	at32_add_device_spi(0, spi0_board_info, ARRAY_SIZE(spi0_board_info));
-+#endif
-+#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);
-+#endif
-+	at32_add_device_lcdc(0, &atstk1000_lcdc_data,
-+			     fbmem_start, fbmem_size);
-+	at32_add_device_usba(0, NULL);
-+#ifndef CONFIG_BOARD_ATSTK100X_SW3_CUSTOM
-+	at32_add_device_ssc(0, ATMEL_SSC_TX);
-+#endif
++#
++# SPI Master Controller Drivers
++#
++CONFIG_SPI_ATMEL=y
++# CONFIG_SPI_BITBANG is not set
 +
-+	atstk1000_setup_j2_leds();
-+	atstk1004_setup_extdac();
++#
++# 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 is not set
++CONFIG_WATCHDOG=y
++CONFIG_WATCHDOG_NOWAYOUT=y
 +
-+	return 0;
-+}
-+postcore_initcall(atstk1004_init);
-diff --git a/arch/avr32/boards/atstk1000/setup.c b/arch/avr32/boards/atstk1000/setup.c
-index c9af409..8bedf93 100644
---- a/arch/avr32/boards/atstk1000/setup.c
-+++ b/arch/avr32/boards/atstk1000/setup.c
-@@ -10,13 +10,17 @@
- #include <linux/bootmem.h>
- #include <linux/fb.h>
- #include <linux/init.h>
-+#include <linux/platform_device.h>
- #include <linux/types.h>
- #include <linux/linkage.h>
- 
- #include <video/atmel_lcdc.h>
- 
- #include <asm/setup.h>
++#
++# Watchdog Device Drivers
++#
++# CONFIG_SOFT_WATCHDOG is not set
 +
-+#include <asm/arch/at32ap700x.h>
- #include <asm/arch/board.h>
-+#include <asm/arch/portmux.h>
- 
- #include "atstk1000.h"
- 
-@@ -61,3 +65,63 @@ struct atmel_lcdfb_info __initdata atstk1000_lcdc_data = {
- 	.default_monspecs	= &atstk1000_default_monspecs,
- 	.guard_time		= 2,
- };
++#
++# USB-based Watchdog Cards
++#
++# CONFIG_USBPCWATCHDOG is not set
 +
-+#ifdef CONFIG_BOARD_ATSTK1000_J2_LED
-+#include <linux/leds.h>
++#
++# Sonics Silicon Backplane
++#
++CONFIG_SSB_POSSIBLE=y
++# CONFIG_SSB is not set
 +
-+static struct gpio_led stk1000_j2_led[] = {
-+#ifdef CONFIG_BOARD_ATSTK1000_J2_LED8
-+#define LEDSTRING "J2 jumpered to LED8"
-+	{ .name = "led0:amber", .gpio = GPIO_PIN_PB( 8), },
-+	{ .name = "led1:amber", .gpio = GPIO_PIN_PB( 9), },
-+	{ .name = "led2:amber", .gpio = GPIO_PIN_PB(10), },
-+	{ .name = "led3:amber", .gpio = GPIO_PIN_PB(13), },
-+	{ .name = "led4:amber", .gpio = GPIO_PIN_PB(14), },
-+	{ .name = "led5:amber", .gpio = GPIO_PIN_PB(15), },
-+	{ .name = "led6:amber", .gpio = GPIO_PIN_PB(16), },
-+	{ .name = "led7:amber", .gpio = GPIO_PIN_PB(30),
-+			.default_trigger = "heartbeat", },
-+#else	/* RGB */
-+#define LEDSTRING "J2 jumpered to RGB LEDs"
-+	{ .name = "r1:red",     .gpio = GPIO_PIN_PB( 8), },
-+	{ .name = "g1:green",   .gpio = GPIO_PIN_PB(10), },
-+	{ .name = "b1:blue",    .gpio = GPIO_PIN_PB(14), },
++#
++# Multifunction device drivers
++#
++# CONFIG_MFD_SM501 is not set
 +
-+	{ .name = "r2:red",     .gpio = GPIO_PIN_PB( 9),
-+			.default_trigger = "heartbeat", },
-+	{ .name = "g2:green",   .gpio = GPIO_PIN_PB(13), },
-+	{ .name = "b2:blue",    .gpio = GPIO_PIN_PB(15),
-+			.default_trigger = "heartbeat", },
-+	/* PB16, PB30 unused */
-+#endif
-+};
++#
++# Multimedia devices
++#
++# CONFIG_VIDEO_DEV is not set
++# CONFIG_DVB_CORE is not set
++# CONFIG_DAB is not set
 +
-+static struct gpio_led_platform_data stk1000_j2_led_data = {
-+	.num_leds	= ARRAY_SIZE(stk1000_j2_led),
-+	.leds		= stk1000_j2_led,
-+};
++#
++# 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_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
 +
-+static struct platform_device stk1000_j2_led_dev = {
-+	.name		= "leds-gpio",
-+	.id		= 2,	/* gpio block J2 */
-+	.dev		= {
-+		.platform_data	= &stk1000_j2_led_data,
-+	},
-+};
++#
++# Frame buffer hardware drivers
++#
++# CONFIG_FB_S1D13XXX is not set
++CONFIG_FB_ATMEL=y
++# CONFIG_FB_VIRTUAL is not set
++# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
 +
-+void __init atstk1000_setup_j2_leds(void)
-+{
-+	unsigned	i;
++#
++# Display device support
++#
++# CONFIG_DISPLAY_SUPPORT is not set
 +
-+	for (i = 0; i < ARRAY_SIZE(stk1000_j2_led); i++)
-+		at32_select_gpio(stk1000_j2_led[i].gpio, AT32_GPIOF_OUTPUT);
++#
++# Console display driver support
++#
++# CONFIG_VGA_CONSOLE is not set
++CONFIG_DUMMY_CONSOLE=y
++# CONFIG_FRAMEBUFFER_CONSOLE is not set
++CONFIG_LOGO=y
++# CONFIG_LOGO_LINUX_MONO is not set
++CONFIG_LOGO_LINUX_VGA16=y
++# CONFIG_LOGO_LINUX_CLUT224 is not set
 +
-+	printk("STK1000: " LEDSTRING "\n");
-+	platform_device_register(&stk1000_j2_led_dev);
-+}
-+#else /* CONFIG_BOARD_ATSTK1000_J2_LED */
-+void __init atstk1000_setup_j2_leds(void)
-+{
++#
++# Sound
++#
++# CONFIG_SOUND is not set
++CONFIG_HID_SUPPORT=y
++CONFIG_HID=y
++CONFIG_HID_DEBUG=y
++# CONFIG_HIDRAW is not set
 +
-+}
-+#endif /* CONFIG_BOARD_ATSTK1000_J2_LED */
-diff --git a/arch/avr32/configs/atngw100_defconfig b/arch/avr32/configs/atngw100_defconfig
-index b799a68..0604607 100644
---- a/arch/avr32/configs/atngw100_defconfig
-+++ b/arch/avr32/configs/atngw100_defconfig
-@@ -1,46 +1,51 @@
- #
- # Automatically generated make config: don't edit
--# Linux kernel version: 2.6.22-rc5
--# Sat Jun 23 15:40:05 2007
-+# Linux kernel version: 2.6.24-rc7
-+# Wed Jan  9 23:20:41 2008
- #
- CONFIG_AVR32=y
- CONFIG_GENERIC_GPIO=y
- 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_GENERIC_TIME=y
-+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
- # CONFIG_ARCH_HAS_ILOG2_U32 is not set
- # CONFIG_ARCH_HAS_ILOG2_U64 is not set
-+CONFIG_ARCH_SUPPORTS_OPROFILE=y
- CONFIG_GENERIC_HWEIGHT=y
- CONFIG_GENERIC_CALIBRATE_DELAY=y
- CONFIG_GENERIC_BUG=y
- CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
- 
- #
--# Code maturity level options
-+# General setup
- #
- CONFIG_EXPERIMENTAL=y
- CONFIG_BROKEN_ON_SMP=y
- CONFIG_INIT_ENV_ARG_LIMIT=32
--
--#
--# General setup
--#
- CONFIG_LOCALVERSION=""
- # CONFIG_LOCALVERSION_AUTO is not set
- CONFIG_SWAP=y
- CONFIG_SYSVIPC=y
--# CONFIG_IPC_NS is not set
- CONFIG_SYSVIPC_SYSCTL=y
- CONFIG_POSIX_MQUEUE=y
- CONFIG_BSD_PROCESS_ACCT=y
- CONFIG_BSD_PROCESS_ACCT_V3=y
- # CONFIG_TASKSTATS is not set
--# CONFIG_UTS_NS is not set
-+# CONFIG_USER_NS is not set
-+# CONFIG_PID_NS is not set
- # CONFIG_AUDIT is not set
- # CONFIG_IKCONFIG is not set
- CONFIG_LOG_BUF_SHIFT=14
++#
++# 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
++
++#
++# 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_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_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_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
++#
++
++#
++# USB Serial Converter support
++#
++# CONFIG_USB_SERIAL is not set
++
++#
++# USB Miscellaneous drivers
++#
++# CONFIG_USB_EMI62 is not set
++# CONFIG_USB_EMI26 is not set
++# CONFIG_USB_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
++
++#
++# USB DSL modem support
++#
++
++#
++# USB Gadget Support
++#
++# CONFIG_USB_GADGET is not set
++CONFIG_MMC=y
++# CONFIG_MMC_DEBUG is not set
++# 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
++
++#
++# MMC/SD Host Controller Drivers
++#
++CONFIG_MMC_AT91=y
++# CONFIG_MMC_SPI is not set
++# CONFIG_NEW_LEDS is not set
++CONFIG_RTC_LIB=y
++# CONFIG_RTC_CLASS 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_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_GFS2_FS is not set
++# CONFIG_OCFS2_FS is not set
++# CONFIG_MINIX_FS is not set
++# CONFIG_ROMFS_FS is not set
++CONFIG_INOTIFY=y
++CONFIG_INOTIFY_USER=y
++# CONFIG_QUOTA is not set
++CONFIG_DNOTIFY=y
++# CONFIG_AUTOFS_FS is not set
++# CONFIG_AUTOFS4_FS is not set
++# CONFIG_FUSE_FS is not set
++
++#
++# CD-ROM/DVD Filesystems
++#
++# CONFIG_ISO9660_FS is not set
++# CONFIG_UDF_FS is not set
++
++#
++# DOS/FAT/NT Filesystems
++#
++CONFIG_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_HPFS_FS is not set
++# CONFIG_QNX4FS_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 is not set
++# CONFIG_NFS_V4 is not set
++# CONFIG_NFS_DIRECTIO is not set
++# CONFIG_NFSD is not set
++CONFIG_ROOT_NFS=y
++CONFIG_LOCKD=y
++CONFIG_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 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
++CONFIG_INSTRUMENTATION=y
++# CONFIG_PROFILING is not set
++# CONFIG_MARKERS is not set
++
++#
++# Kernel hacking
++#
++# CONFIG_PRINTK_TIME is not set
++CONFIG_ENABLE_WARN_DEPRECATED=y
++CONFIG_ENABLE_MUST_CHECK=y
++# 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=y
++CONFIG_SCHED_DEBUG=y
++# CONFIG_SCHEDSTATS is not set
++# CONFIG_TIMER_STATS 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 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_LIST is not set
++# CONFIG_DEBUG_SG is not set
++CONFIG_FRAME_POINTER=y
++CONFIG_FORCED_INLINING=y
++# CONFIG_BOOT_PRINTK_DELAY is not set
++# CONFIG_RCU_TORTURE_TEST is not set
++# CONFIG_FAULT_INJECTION is not set
++# CONFIG_SAMPLES is not set
++CONFIG_DEBUG_USER=y
++# CONFIG_DEBUG_ERRORS 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 is not set
++
++#
++# Library routines
++#
++CONFIG_BITREVERSE=y
++# CONFIG_CRC_CCITT is not set
++# 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/colibri_defconfig b/arch/arm/configs/colibri_defconfig
+new file mode 100644
+index 0000000..c3e3418
+--- /dev/null
++++ b/arch/arm/configs/colibri_defconfig
+@@ -0,0 +1,1481 @@
++#
++# Automatically generated make config: don't edit
++# Linux kernel version: 2.6.24-rc3
++# Mon Dec  3 13:36:09 2007
++#
++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_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_LOCK_KERNEL=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=y
++CONFIG_BSD_PROCESS_ACCT=y
++CONFIG_BSD_PROCESS_ACCT_V3=y
++# CONFIG_TASKSTATS is not set
++# CONFIG_USER_NS is not set
++# CONFIG_PID_NS 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_FAIR_GROUP_SCHED=y
 +CONFIG_FAIR_USER_SCHED=y
 +# CONFIG_FAIR_CGROUP_SCHED is not set
- CONFIG_SYSFS_DEPRECATED=y
- # CONFIG_RELAY is not set
- CONFIG_BLK_DEV_INITRD=y
-@@ -61,35 +66,28 @@ 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 is not set
-+CONFIG_SLUB_DEBUG=y
- # CONFIG_SLAB is not set
- CONFIG_SLUB=y
- # CONFIG_SLOB is not set
-+CONFIG_SLABINFO=y
- CONFIG_RT_MUTEXES=y
- # CONFIG_TINY_SHMEM is not set
- CONFIG_BASE_SMALL=1
--
--#
--# Loadable module support
--#
- CONFIG_MODULES=y
- CONFIG_MODULE_UNLOAD=y
- CONFIG_MODULE_FORCE_UNLOAD=y
- # CONFIG_MODVERSIONS is not set
- # CONFIG_MODULE_SRCVERSION_ALL is not set
- CONFIG_KMOD=y
--
--#
--# Block layer
--#
- CONFIG_BLOCK=y
- # CONFIG_LBD is not set
- # CONFIG_BLK_DEV_IO_TRACE is not set
- # CONFIG_LSF is not set
++CONFIG_SYSFS_DEPRECATED=y
++# CONFIG_RELAY 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=y
++CONFIG_HOTPLUG=y
++CONFIG_PRINTK=y
++CONFIG_BUG=y
++CONFIG_ELF_CORE=y
++CONFIG_BASE_FULL=y
++CONFIG_FUTEX=y
++CONFIG_ANON_INODES=y
++CONFIG_EPOLL=y
++CONFIG_SIGNALFD=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_RT_MUTEXES=y
++# CONFIG_TINY_SHMEM is not set
++CONFIG_BASE_SMALL=0
++CONFIG_MODULES=y
++CONFIG_MODULE_UNLOAD=y
++CONFIG_MODULE_FORCE_UNLOAD=y
++CONFIG_MODVERSIONS=y
++CONFIG_MODULE_SRCVERSION_ALL=y
++CONFIG_KMOD=y
++CONFIG_BLOCK=y
++CONFIG_LBD=y
++# CONFIG_BLK_DEV_IO_TRACE is not set
++CONFIG_LSF=y
 +# CONFIG_BLK_DEV_BSG is not set
- 
- #
- # IO Schedulers
-@@ -111,6 +109,7 @@ CONFIG_SUBARCH_AVR32B=y
- CONFIG_MMU=y
- CONFIG_PERFORMANCE_COUNTERS=y
- CONFIG_PLATFORM_AT32AP=y
-+CONFIG_CPU_AT32AP700X=y
- CONFIG_CPU_AT32AP7000=y
- # CONFIG_BOARD_ATSTK1000 is not set
- CONFIG_BOARD_ATNGW100=y
-@@ -119,9 +118,9 @@ CONFIG_LOADER_U_BOOT=y
- #
- # Atmel AVR32 AP options
- #
--# CONFIG_AP7000_32_BIT_SMC is not set
--CONFIG_AP7000_16_BIT_SMC=y
--# CONFIG_AP7000_8_BIT_SMC is not set
-+# CONFIG_AP700X_32_BIT_SMC is not set
-+CONFIG_AP700X_16_BIT_SMC=y
-+# CONFIG_AP700X_8_BIT_SMC is not set
- CONFIG_LOAD_ADDRESS=0x10000000
- CONFIG_ENTRY_ADDRESS=0x90000000
- CONFIG_PHYS_OFFSET=0x10000000
-@@ -141,9 +140,11 @@ CONFIG_FLATMEM_MANUAL=y
- CONFIG_FLATMEM=y
- CONFIG_FLAT_NODE_MEM_MAP=y
- # CONFIG_SPARSEMEM_STATIC is not set
++
++#
++# IO Schedulers
++#
++CONFIG_IOSCHED_NOOP=y
++CONFIG_IOSCHED_AS=y
++CONFIG_IOSCHED_DEADLINE=y
++CONFIG_IOSCHED_CFQ=y
++CONFIG_DEFAULT_AS=y
++# CONFIG_DEFAULT_DEADLINE is not set
++# CONFIG_DEFAULT_CFQ is not set
++# CONFIG_DEFAULT_NOOP is not set
++CONFIG_DEFAULT_IOSCHED="anticipatory"
++
++#
++# 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_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
++
++#
++# Intel PXA2xx/PXA3xx Implementations
++#
++# 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_MACH_TRIZEPS4 is not set
++# CONFIG_MACH_EM_X270 is not set
++CONFIG_MACH_COLIBRI=y
++# CONFIG_MACH_ZYLONITE is not set
++# CONFIG_MACH_ARMCORE is not set
++CONFIG_PXA27x=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_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 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_SPLIT_PTLOCK_CPUS=4
- # CONFIG_RESOURCES_64BIT is not set
- CONFIG_ZONE_DMA_FLAG=0
++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_OWNERSHIP_TRACE is not set
- # CONFIG_HZ_100 is not set
- CONFIG_HZ_250=y
-@@ -153,13 +154,31 @@ CONFIG_HZ=250
- CONFIG_CMDLINE=""
- 
- #
--# Bus options
++CONFIG_ALIGNMENT_TRAP=y
++
++#
++# Boot options
++#
++CONFIG_ZBOOT_ROM_TEXT=0
++CONFIG_ZBOOT_ROM_BSS=0
++CONFIG_CMDLINE=""
++# 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
++
++#
++# Userspace binary formats
++#
++CONFIG_BINFMT_ELF=y
++# CONFIG_BINFMT_AOUT is not set
++# CONFIG_BINFMT_MISC is not set
++
++#
 +# Power management options
- #
--# CONFIG_ARCH_SUPPORTS_MSI is not set
- 
- #
--# PCCARD (PCMCIA/CardBus) support
-+# CPU Frequency scaling
- #
-+CONFIG_CPU_FREQ=y
-+CONFIG_CPU_FREQ_TABLE=y
-+# CONFIG_CPU_FREQ_DEBUG is not set
-+# CONFIG_CPU_FREQ_STAT is not set
-+CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
-+# 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=y
-+# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
-+CONFIG_CPU_FREQ_AT32AP=y
++#
++CONFIG_PM=y
++# CONFIG_PM_LEGACY is not set
++# CONFIG_PM_DEBUG is not set
++CONFIG_PM_SLEEP=y
++CONFIG_SUSPEND_UP_POSSIBLE=y
++CONFIG_SUSPEND=y
++# CONFIG_APM_EMULATION is not set
 +
 +#
-+# Bus options
++# Networking
 +#
-+# CONFIG_ARCH_SUPPORTS_MSI is not set
- # CONFIG_PCCARD is not set
- 
- #
-@@ -213,6 +232,7 @@ CONFIG_INET_TUNNEL=y
- CONFIG_INET_XFRM_MODE_TRANSPORT=y
- CONFIG_INET_XFRM_MODE_TUNNEL=y
- CONFIG_INET_XFRM_MODE_BEET=y
++CONFIG_NET=y
++
++#
++# Networking options
++#
++CONFIG_PACKET=y
++CONFIG_PACKET_MMAP=y
++CONFIG_UNIX=y
++CONFIG_XFRM=y
++CONFIG_XFRM_USER=m
++# CONFIG_XFRM_SUB_POLICY is not set
++# CONFIG_XFRM_MIGRATE is not set
++CONFIG_NET_KEY=y
++# CONFIG_NET_KEY_MIGRATE 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 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=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
-@@ -240,6 +260,7 @@ CONFIG_IPV6_SIT=y
- # CONFIG_NETWORK_SECMARK is not set
- CONFIG_NETFILTER=y
- # CONFIG_NETFILTER_DEBUG is not set
-+CONFIG_BRIDGE_NETFILTER=y
- 
- #
- # Core Netfilter Configuration
-@@ -252,6 +273,7 @@ CONFIG_NF_CONNTRACK_MARK=y
- # CONFIG_NF_CONNTRACK_EVENTS is not set
- CONFIG_NF_CT_PROTO_GRE=m
- # CONFIG_NF_CT_PROTO_SCTP is not set
-+# CONFIG_NF_CT_PROTO_UDPLITE is not set
- CONFIG_NF_CONNTRACK_AMANDA=m
- CONFIG_NF_CONNTRACK_FTP=m
- CONFIG_NF_CONNTRACK_H323=m
-@@ -269,9 +291,11 @@ CONFIG_NETFILTER_XT_TARGET_MARK=m
- CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
- CONFIG_NETFILTER_XT_TARGET_NFLOG=m
- # CONFIG_NETFILTER_XT_TARGET_NOTRACK is not set
-+# CONFIG_NETFILTER_XT_TARGET_TRACE is not set
- CONFIG_NETFILTER_XT_TARGET_TCPMSS=m
- CONFIG_NETFILTER_XT_MATCH_COMMENT=m
- CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m
-+# CONFIG_NETFILTER_XT_MATCH_CONNLIMIT is not set
- CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
- CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
- # CONFIG_NETFILTER_XT_MATCH_DCCP is not set
-@@ -284,6 +308,7 @@ CONFIG_NETFILTER_XT_MATCH_MAC=m
- CONFIG_NETFILTER_XT_MATCH_MARK=m
- CONFIG_NETFILTER_XT_MATCH_POLICY=m
- CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m
-+# CONFIG_NETFILTER_XT_MATCH_PHYSDEV is not set
- CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
- CONFIG_NETFILTER_XT_MATCH_QUOTA=m
- CONFIG_NETFILTER_XT_MATCH_REALM=m
-@@ -292,6 +317,8 @@ CONFIG_NETFILTER_XT_MATCH_STATE=m
- CONFIG_NETFILTER_XT_MATCH_STATISTIC=m
- CONFIG_NETFILTER_XT_MATCH_STRING=m
- CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
-+# CONFIG_NETFILTER_XT_MATCH_TIME is not set
-+# CONFIG_NETFILTER_XT_MATCH_U32 is not set
- CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
- 
- #
-@@ -359,13 +386,19 @@ CONFIG_IP6_NF_TARGET_REJECT=m
- CONFIG_IP6_NF_MANGLE=m
- CONFIG_IP6_NF_TARGET_HL=m
- CONFIG_IP6_NF_RAW=m
++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_INET6_XFRM_TUNNEL is not set
++# CONFIG_INET6_TUNNEL is not set
++# CONFIG_NETLABEL is not set
++# CONFIG_NETWORK_SECMARK is not set
++CONFIG_NETFILTER=y
++# CONFIG_NETFILTER_DEBUG is not set
 +
 +#
-+# Bridge: Netfilter Configuration
++# Core Netfilter Configuration
 +#
-+# CONFIG_BRIDGE_NF_EBTABLES 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_BRIDGE=m
- CONFIG_VLAN_8021Q=m
- # CONFIG_DECNET is not set
-+CONFIG_LLC=m
- # CONFIG_LLC2 is not set
- # CONFIG_IPX is not set
- # CONFIG_ATALK is not set
-@@ -373,10 +406,6 @@ CONFIG_VLAN_8021Q=m
- # CONFIG_LAPB is not set
- # CONFIG_ECONET is not set
- # CONFIG_WAN_ROUTER is not set
--
--#
--# QoS and/or fair queueing
--#
- # CONFIG_NET_SCHED is not set
- CONFIG_NET_CLS_ROUTE=y
- 
-@@ -384,6 +413,7 @@ CONFIG_NET_CLS_ROUTE=y
- # Network testing
- #
- # CONFIG_NET_PKTGEN is not set
-+# CONFIG_NET_TCPPROBE is not set
- # CONFIG_HAMRADIO is not set
- # CONFIG_IRDA is not set
- # CONFIG_BT is not set
-@@ -397,6 +427,7 @@ CONFIG_NET_CLS_ROUTE=y
- # CONFIG_MAC80211 is not set
- # CONFIG_IEEE80211 is not set
- # CONFIG_RFKILL is not set
++# CONFIG_NETFILTER_NETLINK is not set
++# CONFIG_NF_CONNTRACK_ENABLED is not set
++# CONFIG_NF_CONNTRACK is not set
++# CONFIG_NETFILTER_XTABLES is not set
++
++#
++# IP: Netfilter Configuration
++#
++CONFIG_IP_NF_QUEUE=m
++# CONFIG_IP_NF_IPTABLES is not set
++# CONFIG_IP_NF_ARPTABLES 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=m
++# 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_IRDA=m
++
++#
++# IrDA protocols
++#
++CONFIG_IRLAN=m
++CONFIG_IRCOMM=m
++CONFIG_IRDA_ULTRA=y
++
++#
++# IrDA options
++#
++CONFIG_IRDA_CACHE_LAST_LSAP=y
++CONFIG_IRDA_FAST_RR=y
++# CONFIG_IRDA_DEBUG is not set
++
++#
++# Infrared-port device drivers
++#
++
++#
++# SIR device drivers
++#
++CONFIG_IRTTY_SIR=m
++
++#
++# Dongle support
++#
++# CONFIG_DONGLE is not set
++# CONFIG_KINGSUN_DONGLE is not set
++# CONFIG_KSDAZZLE_DONGLE is not set
++# CONFIG_KS959_DONGLE is not set
++
++#
++# Old SIR device drivers
++#
++# CONFIG_IRPORT_SIR is not set
++
++#
++# Old Serial dongle support
++#
++
++#
++# FIR device drivers
++#
++# CONFIG_USB_IRDA is not set
++# CONFIG_SIGMATEL_FIR is not set
++# CONFIG_PXA_FICP is not set
++# CONFIG_MCS_FIR 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 is not set
++# 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_HCIVHCI is not set
++# CONFIG_AF_RXRPC is not set
++
++#
++# Wireless
++#
++CONFIG_CFG80211=y
++CONFIG_NL80211=y
++CONFIG_WIRELESS_EXT=y
++# CONFIG_MAC80211 is not set
++CONFIG_IEEE80211=y
++# CONFIG_IEEE80211_DEBUG is not set
++CONFIG_IEEE80211_CRYPT_WEP=y
++CONFIG_IEEE80211_CRYPT_CCMP=m
++CONFIG_IEEE80211_CRYPT_TKIP=m
++CONFIG_IEEE80211_SOFTMAC=m
++# CONFIG_IEEE80211_SOFTMAC_DEBUG is not set
++# CONFIG_RFKILL is not set
 +# CONFIG_NET_9P is not set
- 
- #
- # Device Drivers
-@@ -405,16 +436,13 @@ CONFIG_NET_CLS_ROUTE=y
- #
- # Generic Driver Options
- #
++
++#
++# Device Drivers
++#
++
++#
++# Generic Driver Options
++#
 +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
- CONFIG_STANDALONE=y
- # CONFIG_PREVENT_FIRMWARE_BUILD is not set
- # CONFIG_FW_LOADER is not set
- # CONFIG_DEBUG_DRIVER is not set
- # CONFIG_DEBUG_DEVRES is not set
- # CONFIG_SYS_HYPERVISOR is not set
--
--#
--# Connector - unified userspace <-> kernelspace linker
--#
- # CONFIG_CONNECTOR is not set
- CONFIG_MTD=y
- # CONFIG_MTD_DEBUG is not set
-@@ -434,6 +462,7 @@ CONFIG_MTD_BLOCK=y
- # CONFIG_INFTL is not set
- # CONFIG_RFD_FTL is not set
- # CONFIG_SSFDC is not set
++CONFIG_STANDALONE=y
++CONFIG_PREVENT_FIRMWARE_BUILD=y
++CONFIG_FW_LOADER=y
++# CONFIG_DEBUG_DRIVER is not set
++# CONFIG_DEBUG_DEVRES is not set
++# CONFIG_SYS_HYPERVISOR is not set
++CONFIG_CONNECTOR=y
++CONFIG_PROC_EVENTS=y
++CONFIG_MTD=y
++# CONFIG_MTD_DEBUG is not set
++CONFIG_MTD_CONCAT=y
++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=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
-@@ -493,20 +522,8 @@ CONFIG_MTD_DATAFLASH=y
- # UBI - Unsorted block images
- #
- # CONFIG_MTD_UBI is not set
--
--#
--# Parallel port support
--#
- # CONFIG_PARPORT is not set
--
--#
--# Plug and Play support
--#
--# CONFIG_PNPACPI is not set
--
--#
--# Block devices
--#
++
++#
++# 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 is not set
++# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
++CONFIG_MTD_CFI_LE_BYTE_SWAP=y
++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_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 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=y
++CONFIG_MTD_PHYSMAP=y
++CONFIG_MTD_PHYSMAP_START=0x0
++CONFIG_MTD_PHYSMAP_LEN=0x0
++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
++
++#
++# 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=y
++
++#
++# 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=y
++CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADVANCED=y
++CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS=0x4000000
++CONFIG_MTD_NAND_DISKONCHIP_PROBE_HIGH=y
++CONFIG_MTD_NAND_DISKONCHIP_BBTWRITE=y
++# CONFIG_MTD_NAND_SHARPSL 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=y
++# CONFIG_MTD_ONENAND_VERIFY_WRITE is not set
++# CONFIG_MTD_ONENAND_GENERIC is not set
++# CONFIG_MTD_ONENAND_OTP is not set
++# CONFIG_MTD_ONENAND_2X_PROGRAM is not set
++# CONFIG_MTD_ONENAND_SIM 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=m
- # CONFIG_BLK_DEV_CRYPTOLOOP is not set
-@@ -517,11 +534,7 @@ CONFIG_BLK_DEV_RAM_SIZE=4096
- CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
- # CONFIG_CDROM_PKTCDVD is not set
- # CONFIG_ATA_OVER_ETH is not set
--
--#
--# Misc devices
--#
--# CONFIG_BLINK is not set
-+# CONFIG_MISC_DEVICES is not set
- # CONFIG_IDE is not set
- 
- #
-@@ -529,30 +542,42 @@ CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
- #
- # CONFIG_RAID_ATTRS is not set
- # CONFIG_SCSI is not set
++# CONFIG_BLK_DEV_COW_COMMON is not set
++CONFIG_BLK_DEV_LOOP=y
++CONFIG_BLK_DEV_CRYPTOLOOP=m
++CONFIG_BLK_DEV_NBD=y
++# CONFIG_BLK_DEV_UB is not set
++CONFIG_BLK_DEV_RAM=y
++CONFIG_BLK_DEV_RAM_COUNT=8
++CONFIG_BLK_DEV_RAM_SIZE=4096
++CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
++# CONFIG_CDROM_PKTCDVD is not set
++# CONFIG_ATA_OVER_ETH is not set
++CONFIG_MISC_DEVICES=y
++# CONFIG_EEPROM_93CX6 is not set
++CONFIG_IDE=y
++CONFIG_IDE_MAX_HWIFS=4
++CONFIG_BLK_DEV_IDE=y
++
++#
++# Please see Documentation/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=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_IDE_GENERIC=y
++# CONFIG_BLK_DEV_PLATFORM is not set
++# CONFIG_IDE_ARM is not set
++# CONFIG_BLK_DEV_IDEDMA is not set
++CONFIG_IDE_ARCH_OBSOLETE_INIT=y
++# CONFIG_BLK_DEV_HD 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
--
--#
--# Multi-device support (RAID and LVM)
--#
- # CONFIG_MD is not set
--
--#
--# Network device support
--#
- CONFIG_NETDEVICES=y
++# 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_DUMMY is not set
++# CONFIG_BONDING is not set
 +# CONFIG_MACVLAN is not set
- # CONFIG_EQUALIZER is not set
- CONFIG_TUN=m
--# CONFIG_PHYLIB is not set
--
--#
--# Ethernet (10 or 100Mbit)
--#
++# CONFIG_EQUALIZER is not set
++# CONFIG_TUN is not set
 +# CONFIG_VETH is not set
 +CONFIG_PHYLIB=y
 +
@@ -7270,80 +7552,167 @@
 +# CONFIG_ICPLUS_PHY is not set
 +# CONFIG_FIXED_PHY is not set
 +# CONFIG_MDIO_BITBANG is not set
- CONFIG_NET_ETHERNET=y
--CONFIG_MII=y
-+# CONFIG_MII is not set
- CONFIG_MACB=y
++CONFIG_NET_ETHERNET=y
++CONFIG_MII=y
++# CONFIG_AX88796 is not set
++# CONFIG_SMC91X is not set
++CONFIG_DM9000=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
- 
-@@ -571,21 +596,14 @@ CONFIG_PPP_DEFLATE=m
- CONFIG_PPP_BSDCOMP=m
- CONFIG_PPP_MPPE=m
- CONFIG_PPPOE=m
-+# CONFIG_PPPOL2TP is not set
- # CONFIG_SLIP is not set
- CONFIG_SLHC=m
- # CONFIG_SHAPER is not set
- # CONFIG_NETCONSOLE is not set
- # CONFIG_NETPOLL is not set
- # CONFIG_NET_POLL_CONTROLLER is not set
--
--#
--# ISDN subsystem
--#
- # CONFIG_ISDN is not set
--
--#
--# Telephony Support
--#
- # CONFIG_PHONE is not set
- 
- #
-@@ -620,23 +638,50 @@ CONFIG_SERIAL_CORE=y
- CONFIG_SERIAL_CORE_CONSOLE=y
- CONFIG_UNIX98_PTYS=y
- # CONFIG_LEGACY_PTYS is not set
--
--#
--# IPMI
--#
- # CONFIG_IPMI_HANDLER is not set
--# CONFIG_WATCHDOG is not set
- # CONFIG_HW_RANDOM is not set
- # CONFIG_RTC is not set
- # CONFIG_GEN_RTC is not set
- # CONFIG_R3964 is not set
- # CONFIG_RAW_DRIVER 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 is not set
++# CONFIG_USB_ZD1201 is not set
++CONFIG_HOSTAP=y
++CONFIG_HOSTAP_FIRMWARE=y
++CONFIG_HOSTAP_FIRMWARE_NVRAM=y
++# CONFIG_ZD1211RW 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_SHAPER 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=640
++CONFIG_INPUT_MOUSEDEV_SCREEN_Y=480
++# 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=m
++# 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 is not set
++# CONFIG_KEYBOARD_GPIO is not set
++CONFIG_INPUT_MOUSE=y
++# CONFIG_MOUSE_PS2 is not set
++CONFIG_MOUSE_SERIAL=m
++# CONFIG_MOUSE_APPLETOUCH is not set
++# CONFIG_MOUSE_VSXXXAA is not set
++# CONFIG_MOUSE_GPIO 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=y
++# CONFIG_TOUCHSCREEN_USB_COMPOSITE 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=m
++
++#
++# Hardware I/O ports
++#
++CONFIG_SERIO=y
++CONFIG_SERIO_SERPORT=y
++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_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=y
++CONFIG_LEGACY_PTY_COUNT=256
++# CONFIG_IPMI_HANDLER is not set
++CONFIG_HW_RANDOM=y
++# CONFIG_NVRAM is not set
++# CONFIG_R3964 is not set
++# CONFIG_RAW_DRIVER is not set
 +# CONFIG_TCG_TPM is not set
-+CONFIG_I2C=m
++CONFIG_I2C=y
 +CONFIG_I2C_BOARDINFO=y
-+CONFIG_I2C_CHARDEV=m
- 
- #
--# TPM devices
++CONFIG_I2C_CHARDEV=y
++
++#
 +# I2C Algorithms
- #
--# CONFIG_TCG_TPM is not set
--# CONFIG_I2C is not set
-+CONFIG_I2C_ALGOBIT=m
++#
++# CONFIG_I2C_ALGOBIT is not set
 +# CONFIG_I2C_ALGOPCF is not set
 +# CONFIG_I2C_ALGOPCA is not set
 +
 +#
 +# I2C Hardware Bus support
 +#
-+CONFIG_I2C_GPIO=m
++# CONFIG_I2C_GPIO is not set
++# CONFIG_I2C_PXA 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
 +
 +#
 +# Miscellaneous I2C Chip support
@@ -7361,84 +7730,311 @@
 +# CONFIG_I2C_DEBUG_ALGO is not set
 +# CONFIG_I2C_DEBUG_BUS is not set
 +# CONFIG_I2C_DEBUG_CHIP is not set
- 
- #
- # SPI support
-@@ -655,13 +700,25 @@ CONFIG_SPI_ATMEL=y
- # SPI Protocol Masters
- #
- # CONFIG_SPI_AT25 is not set
--# CONFIG_SPI_SPIDEV is not set
-+CONFIG_SPI_SPIDEV=m
-+# CONFIG_SPI_TLE62X0 is not set
++
++#
++# SPI support
++#
++# CONFIG_SPI is not set
++# CONFIG_SPI_MASTER is not set
 +# CONFIG_W1 is not set
 +# CONFIG_POWER_SUPPLY is not set
-+# CONFIG_HWMON 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_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_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_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
- 
- #
--# Dallas's 1-wire bus
++
++#
 +# Watchdog Device Drivers
- #
--# CONFIG_W1 is not set
--# CONFIG_HWMON is not set
++#
 +# CONFIG_SOFT_WATCHDOG is not set
-+CONFIG_AT32AP700X_WDT=y
++# CONFIG_SA1100_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
-@@ -678,23 +735,21 @@ CONFIG_SPI_ATMEL=y
- #
- # 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
--# CONFIG_VGASTATE is not set
--# CONFIG_FB is not set
- 
- #
- # Sound
- #
- # CONFIG_SOUND is not set
--
--#
--# USB support
--#
++
++#
++# Multifunction device drivers
++#
++# CONFIG_MFD_SM501 is not set
++
++#
++# Multimedia devices
++#
++# CONFIG_VIDEO_DEV is not set
++# CONFIG_DVB_CORE is not set
++CONFIG_DAB=y
++# CONFIG_USB_DABUSB is not set
++
++#
++# Graphics support
++#
++# CONFIG_VGASTATE is not set
++# CONFIG_VIDEO_OUTPUT_CONTROL is not set
++CONFIG_FB=y
++CONFIG_FIRMWARE_EDID=y
++# 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_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_UVESA is not set
++# CONFIG_FB_S1D13XXX is not set
++CONFIG_FB_PXA=y
++# CONFIG_FB_PXA_PARAMETERS is not set
++# CONFIG_FB_MBX is not set
++# CONFIG_FB_VIRTUAL is not set
++CONFIG_BACKLIGHT_LCD_SUPPORT=y
++CONFIG_LCD_CLASS_DEVICE=y
++CONFIG_BACKLIGHT_CLASS_DEVICE=y
++# CONFIG_BACKLIGHT_CORGI 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=y
++CONFIG_FONTS=y
++CONFIG_FONT_8x8=y
++CONFIG_FONT_8x16=y
++# 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=y
++CONFIG_LOGO_LINUX_MONO=y
++CONFIG_LOGO_LINUX_VGA16=y
++CONFIG_LOGO_LINUX_CLUT224=y
++
++#
++# Sound
++#
++# CONFIG_SOUND is not set
++CONFIG_AC97_BUS=y
++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 is not set
- # CONFIG_USB_ARCH_HAS_OHCI is not set
- # CONFIG_USB_ARCH_HAS_EHCI is not set
-@@ -706,12 +761,47 @@ CONFIG_SPI_ATMEL=y
- #
- # USB Gadget Support
- #
--# CONFIG_USB_GADGET is not set
--# CONFIG_MMC is not set
--
--#
--# LED devices
--#
-+CONFIG_USB_GADGET=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
++
++#
++# 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_PERSIST is not set
++# CONFIG_USB_OTG is not set
++
++#
++# USB Host Controller Drivers
++#
++# CONFIG_USB_ISP116X_HCD is not set
++# CONFIG_USB_OHCI_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_LIBUSUAL is not set
++
++#
++# USB Imaging devices
++#
++# CONFIG_USB_MDC800 is not set
++# CONFIG_USB_MON is not set
++
++#
++# USB port drivers
++#
++
++#
++# USB Serial Converter support
++#
++CONFIG_USB_SERIAL=m
++# CONFIG_USB_SERIAL_GENERIC is not set
++# CONFIG_USB_SERIAL_AIRCABLE is not set
++# CONFIG_USB_SERIAL_AIRPRIME 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_KEYSPAN_PDA is not set
++# CONFIG_USB_SERIAL_KEYSPAN is not set
++# CONFIG_USB_SERIAL_KLSI is not set
++# CONFIG_USB_SERIAL_KOBIL_SCT is not set
++# CONFIG_USB_SERIAL_MCT_U232 is not set
++# CONFIG_USB_SERIAL_MOS7720 is not set
++# CONFIG_USB_SERIAL_MOS7840 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_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_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
++
++#
++# USB DSL modem support
++#
++
++#
++# USB Gadget Support
++#
++CONFIG_USB_GADGET=m
 +# CONFIG_USB_GADGET_DEBUG is not set
 +# CONFIG_USB_GADGET_DEBUG_FILES is not set
++# CONFIG_USB_GADGET_DEBUG_FS is not set
 +CONFIG_USB_GADGET_SELECTED=y
 +# CONFIG_USB_GADGET_AMD5536UDC is not set
-+CONFIG_USB_GADGET_ATMEL_USBA=y
-+CONFIG_USB_ATMEL_USBA=y
++# 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_PXA2XX is not set
@@ -7448,67 +8044,61 @@
 +# 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_DUMMY_HCD=y
++CONFIG_USB_DUMMY_HCD=m
 +CONFIG_USB_GADGET_DUALSPEED=y
-+CONFIG_USB_ZERO=m
-+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_ZERO is not set
++# CONFIG_USB_ETH is not set
++# CONFIG_USB_GADGETFS is not set
++# CONFIG_USB_FILE_STORAGE is not set
++# CONFIG_USB_G_SERIAL is not set
 +# CONFIG_USB_MIDI_GADGET is not set
-+CONFIG_MMC=m
++CONFIG_MMC=y
 +# CONFIG_MMC_DEBUG is not set
 +# CONFIG_MMC_UNSAFE_RESUME is not set
 +
 +#
 +# MMC/SD Card Drivers
 +#
-+CONFIG_MMC_BLOCK=m
++CONFIG_MMC_BLOCK=y
 +CONFIG_MMC_BLOCK_BOUNCE=y
 +# CONFIG_SDIO_UART is not set
 +
 +#
 +# MMC/SD Host Controller Drivers
 +#
-+CONFIG_MMC_SPI=m
- CONFIG_NEW_LEDS=y
- CONFIG_LEDS_CLASS=y
- 
-@@ -726,53 +816,71 @@ CONFIG_LEDS_GPIO=y
- CONFIG_LEDS_TRIGGERS=y
- CONFIG_LEDS_TRIGGER_TIMER=y
- CONFIG_LEDS_TRIGGER_HEARTBEAT=y
--
--
--#
--# LED drivers
--#
++# CONFIG_MMC_PXA is not set
++CONFIG_NEW_LEDS=y
++# CONFIG_LEDS_CLASS is not set
++
++#
++# LED drivers
++#
++
++#
++# LED Triggers
++#
++CONFIG_LEDS_TRIGGERS=y
++CONFIG_LEDS_TRIGGER_TIMER=y
++# CONFIG_LEDS_TRIGGER_IDE_DISK is not set
++CONFIG_LEDS_TRIGGER_HEARTBEAT=y
 +CONFIG_RTC_LIB=y
 +CONFIG_RTC_CLASS=y
-+CONFIG_RTC_HCTOSYS=y
-+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
++# CONFIG_RTC_HCTOSYS is not set
 +# CONFIG_RTC_DEBUG is not set
- 
- #
--# LED Triggers
--#
--
--#
--# InfiniBand support
++
++#
 +# 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
- 
- #
--# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
++
++#
 +# I2C RTC drivers
- #
++#
 +# CONFIG_RTC_DRV_DS1307 is not set
 +# CONFIG_RTC_DRV_DS1374 is not set
 +# CONFIG_RTC_DRV_DS1672 is not set
@@ -7517,676 +8107,897 @@
 +# 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_PCF8583=m
 +# CONFIG_RTC_DRV_M41T80 is not set
- 
- #
--# Real Time Clock
++
++#
 +# SPI RTC drivers
- #
--# CONFIG_RTC_CLASS is not set
-+# CONFIG_RTC_DRV_RS5C348 is not set
-+# CONFIG_RTC_DRV_MAX6902 is not set
- 
- #
--# DMA Engine support
++#
++
++#
 +# Platform RTC drivers
- #
--# CONFIG_DMA_ENGINE is not set
++#
++# CONFIG_RTC_DRV_CMOS is not set
 +# CONFIG_RTC_DRV_DS1553 is not set
 +# CONFIG_RTC_DRV_STK17TA8 is not set
 +# CONFIG_RTC_DRV_DS1742 is not set
 +# CONFIG_RTC_DRV_M48T86 is not set
 +# CONFIG_RTC_DRV_M48T59 is not set
 +# CONFIG_RTC_DRV_V3020 is not set
- 
- #
--# DMA Clients
++
++#
 +# on-CPU RTC drivers
- #
-+CONFIG_RTC_DRV_AT32AP700X=y
- 
- #
--# DMA Devices
-+# Userspace I/O
- #
-+# CONFIG_UIO is not set
- 
- #
- # File systems
- #
--CONFIG_EXT2_FS=y
-+CONFIG_EXT2_FS=m
- # CONFIG_EXT2_FS_XATTR is not set
- # CONFIG_EXT2_FS_XIP is not set
--CONFIG_EXT3_FS=y
-+CONFIG_EXT3_FS=m
- # CONFIG_EXT3_FS_XATTR is not set
- # CONFIG_EXT4DEV_FS is not set
--CONFIG_JBD=y
--# CONFIG_JBD_DEBUG 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
-@@ -781,7 +889,8 @@ CONFIG_JBD=y
- # CONFIG_OCFS2_FS is not set
- # CONFIG_MINIX_FS is not set
- # CONFIG_ROMFS_FS is not set
--# CONFIG_INOTIFY is not set
++#
++# CONFIG_RTC_DRV_SA1100 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=y
++# CONFIG_XFS_FS is not set
++# CONFIG_GFS2_FS is not set
++# CONFIG_OCFS2_FS is not set
++# CONFIG_MINIX_FS is not set
++# CONFIG_ROMFS_FS is not set
 +CONFIG_INOTIFY=y
 +CONFIG_INOTIFY_USER=y
- # CONFIG_QUOTA is not set
- # CONFIG_DNOTIFY is not set
- # CONFIG_AUTOFS_FS is not set
-@@ -814,8 +923,7 @@ CONFIG_SYSFS=y
- CONFIG_TMPFS=y
- # CONFIG_TMPFS_POSIX_ACL is not set
- # CONFIG_HUGETLB_PAGE is not set
--CONFIG_RAMFS=y
--CONFIG_CONFIGFS_FS=y
-+CONFIG_CONFIGFS_FS=m
- 
- #
- # Miscellaneous filesystems
-@@ -830,10 +938,12 @@ CONFIG_CONFIGFS_FS=y
- 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_QUOTA is not set
++CONFIG_DNOTIFY=y
++# CONFIG_AUTOFS_FS is not set
++CONFIG_AUTOFS4_FS=y
++# 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-15"
++# 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=y
++
++#
++# Miscellaneous filesystems
++#
++# CONFIG_ADFS_FS is not set
++# CONFIG_AFFS_FS is not set
++# CONFIG_ECRYPT_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=1
++CONFIG_JFFS2_FS_WRITEBUFFER=y
++CONFIG_JFFS2_FS_WBUF_VERIFY=y
++# 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
-@@ -842,19 +952,21 @@ CONFIG_JFFS2_RTIME=y
- # CONFIG_QNX4FS_FS is not set
- # CONFIG_SYSV_FS is not set
- # CONFIG_UFS_FS is not set
--
--#
--# Network File Systems
--#
++CONFIG_JFFS2_RTIME=y
++# CONFIG_JFFS2_RUBIN is not set
++# CONFIG_CRAMFS is not set
++# CONFIG_VXFS_FS is not set
++# CONFIG_HPFS_FS is not set
++# CONFIG_QNX4FS_FS is not set
++# CONFIG_SYSV_FS is not set
++# CONFIG_UFS_FS is not set
 +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_NFS_DIRECTIO is not set
--# CONFIG_NFSD is not set
-+CONFIG_NFSD=m
++CONFIG_NFS_FS=y
++CONFIG_NFS_V3=y
++# CONFIG_NFS_V3_ACL is not set
++CONFIG_NFS_V4=y
++# CONFIG_NFS_DIRECTIO is not set
++CONFIG_NFSD=y
 +CONFIG_NFSD_V3=y
 +# CONFIG_NFSD_V3_ACL is not set
-+# CONFIG_NFSD_V4 is not set
++CONFIG_NFSD_V4=y
 +CONFIG_NFSD_TCP=y
- CONFIG_ROOT_NFS=y
- CONFIG_LOCKD=y
- CONFIG_LOCKD_V4=y
-+CONFIG_EXPORTFS=m
- CONFIG_NFS_COMMON=y
- CONFIG_SUNRPC=y
- # CONFIG_SUNRPC_BIND34 is not set
-@@ -871,23 +983,18 @@ CONFIG_CIFS=m
- # CONFIG_NCP_FS is not set
- # CONFIG_CODA_FS is not set
- # CONFIG_AFS_FS is not set
--# CONFIG_9P_FS is not set
- 
- #
- # Partition Types
- #
- # CONFIG_PARTITION_ADVANCED is not set
- CONFIG_MSDOS_PARTITION=y
--
--#
--# Native Language Support
--#
--CONFIG_NLS=y
-+CONFIG_NLS=m
- CONFIG_NLS_DEFAULT="iso8859-1"
--# CONFIG_NLS_CODEPAGE_437 is not set
-+CONFIG_NLS_CODEPAGE_437=m
- # CONFIG_NLS_CODEPAGE_737 is not set
- # CONFIG_NLS_CODEPAGE_775 is not set
--CONFIG_NLS_CODEPAGE_850=y
-+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
-@@ -908,7 +1015,7 @@ CONFIG_NLS_CODEPAGE_850=y
- # 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_ROOT_NFS=y
++CONFIG_LOCKD=y
++CONFIG_LOCKD_V4=y
++CONFIG_EXPORTFS=y
++CONFIG_NFS_COMMON=y
++CONFIG_SUNRPC=y
++CONFIG_SUNRPC_GSS=y
++# CONFIG_SUNRPC_BIND34 is not set
++CONFIG_RPCSEC_GSS_KRB5=y
++# CONFIG_RPCSEC_GSS_SPKM3 is not set
++# CONFIG_SMB_FS is not set
++# CONFIG_CIFS is not set
++# CONFIG_NCP_FS is not set
++# CONFIG_CODA_FS is not set
++# CONFIG_AFS_FS is not set
++
++#
++# Partition Types
++#
++# CONFIG_PARTITION_ADVANCED is not set
++CONFIG_MSDOS_PARTITION=y
++CONFIG_NLS=y
++CONFIG_NLS_DEFAULT="iso8859-15"
++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=y
 +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
-@@ -921,18 +1028,19 @@ CONFIG_NLS_ISO8859_1=y
- # 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
--
--#
--# Distributed Lock Manager
--#
++# 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
++# CONFIG_DLM is not set
 +CONFIG_INSTRUMENTATION=y
-+CONFIG_PROFILING=y
-+CONFIG_OPROFILE=m
-+CONFIG_KPROBES=y
++# CONFIG_PROFILING is not set
 +# CONFIG_MARKERS is not set
- 
- #
- # Kernel hacking
- #
--CONFIG_TRACE_IRQFLAGS_SUPPORT=y
- # CONFIG_PRINTK_TIME is not set
++
++#
++# Kernel hacking
++#
++CONFIG_PRINTK_TIME=y
 +CONFIG_ENABLE_WARN_DEPRECATED=y
- CONFIG_ENABLE_MUST_CHECK=y
- CONFIG_MAGIC_SYSRQ=y
- # CONFIG_UNUSED_SYMBOLS is not set
-@@ -941,12 +1049,17 @@ CONFIG_MAGIC_SYSRQ=y
- CONFIG_DEBUG_KERNEL=y
- # CONFIG_DEBUG_SHIRQ is not set
- CONFIG_DETECT_SOFTLOCKUP=y
++CONFIG_ENABLE_MUST_CHECK=y
++CONFIG_MAGIC_SYSRQ=y
++# 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=y
 +CONFIG_SCHED_DEBUG=y
- # CONFIG_SCHEDSTATS is not set
- # CONFIG_TIMER_STATS is not set
-+# CONFIG_SLUB_DEBUG_ON 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_SCHEDSTATS is not set
++# CONFIG_TIMER_STATS 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
-@@ -954,21 +1067,21 @@ CONFIG_DEBUG_BUGVERBOSE=y
- # CONFIG_DEBUG_INFO is not set
- # CONFIG_DEBUG_VM is not set
- # CONFIG_DEBUG_LIST 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_LIST is not set
 +# CONFIG_DEBUG_SG is not set
- CONFIG_FRAME_POINTER=y
- # CONFIG_FORCED_INLINING is not set
++CONFIG_FRAME_POINTER=y
++CONFIG_FORCED_INLINING=y
 +# CONFIG_BOOT_PRINTK_DELAY is not set
- # CONFIG_RCU_TORTURE_TEST is not set
-+# CONFIG_LKDTM is not set
- # CONFIG_FAULT_INJECTION is not set
--# CONFIG_KPROBES is not set
++# CONFIG_RCU_TORTURE_TEST is not set
++# CONFIG_FAULT_INJECTION is not set
 +# CONFIG_SAMPLES is not set
- 
- #
- # Security options
- #
- # CONFIG_KEYS is not set
- # CONFIG_SECURITY is not set
--
--#
--# Cryptographic options
--#
++CONFIG_DEBUG_USER=y
++CONFIG_DEBUG_ERRORS=y
++CONFIG_DEBUG_LL=y
++# CONFIG_DEBUG_ICEDCC is not set
++
++#
++# Security options
++#
++CONFIG_KEYS=y
++CONFIG_KEYS_DEBUG_PROC_KEYS=y
++CONFIG_SECURITY=y
++# CONFIG_SECURITY_NETWORK is not set
++CONFIG_SECURITY_CAPABILITIES=y
 +# CONFIG_SECURITY_FILE_CAPABILITIES is not set
- CONFIG_CRYPTO=y
- CONFIG_CRYPTO_ALGAPI=y
- CONFIG_CRYPTO_BLKCIPHER=y
-@@ -989,6 +1102,7 @@ CONFIG_CRYPTO_ECB=m
- CONFIG_CRYPTO_CBC=y
- CONFIG_CRYPTO_PCBC=m
- # CONFIG_CRYPTO_LRW is not set
++# CONFIG_SECURITY_ROOTPLUG is not set
++CONFIG_CRYPTO=y
++CONFIG_CRYPTO_ALGAPI=y
++CONFIG_CRYPTO_BLKCIPHER=y
++CONFIG_CRYPTO_MANAGER=y
++# CONFIG_CRYPTO_HMAC is not set
++# CONFIG_CRYPTO_XCBC is not set
++# CONFIG_CRYPTO_NULL is not set
++# CONFIG_CRYPTO_MD4 is not set
++CONFIG_CRYPTO_MD5=y
++CONFIG_CRYPTO_SHA1=m
++CONFIG_CRYPTO_SHA256=m
++CONFIG_CRYPTO_SHA512=m
++# CONFIG_CRYPTO_WP512 is not set
++# CONFIG_CRYPTO_TGR192 is not set
++# CONFIG_CRYPTO_GF128MUL is not set
++CONFIG_CRYPTO_ECB=y
++CONFIG_CRYPTO_CBC=y
++CONFIG_CRYPTO_PCBC=m
++# CONFIG_CRYPTO_LRW is not set
 +# CONFIG_CRYPTO_XTS is not set
- # CONFIG_CRYPTO_CRYPTD is not set
- CONFIG_CRYPTO_DES=y
- # CONFIG_CRYPTO_FCRYPT is not set
-@@ -1002,15 +1116,14 @@ CONFIG_CRYPTO_DES=y
- CONFIG_CRYPTO_ARC4=m
- # CONFIG_CRYPTO_KHAZAD is not set
- # CONFIG_CRYPTO_ANUBIS is not set
++# CONFIG_CRYPTO_CRYPTD is not set
++CONFIG_CRYPTO_DES=y
++# CONFIG_CRYPTO_FCRYPT is not set
++# CONFIG_CRYPTO_BLOWFISH is not set
++# CONFIG_CRYPTO_TWOFISH is not set
++# CONFIG_CRYPTO_SERPENT is not set
++CONFIG_CRYPTO_AES=m
++# CONFIG_CRYPTO_CAST5 is not set
++# CONFIG_CRYPTO_CAST6 is not set
++# CONFIG_CRYPTO_TEA is not set
++CONFIG_CRYPTO_ARC4=y
++# CONFIG_CRYPTO_KHAZAD is not set
++# CONFIG_CRYPTO_ANUBIS is not set
 +# CONFIG_CRYPTO_SEED is not set
- CONFIG_CRYPTO_DEFLATE=y
- # CONFIG_CRYPTO_MICHAEL_MIC is not set
- # CONFIG_CRYPTO_CRC32C is not set
- # CONFIG_CRYPTO_CAMELLIA is not set
- # CONFIG_CRYPTO_TEST is not set
--
--#
--# Hardware crypto devices
--#
++CONFIG_CRYPTO_DEFLATE=m
++CONFIG_CRYPTO_MICHAEL_MIC=m
++CONFIG_CRYPTO_CRC32C=y
++# CONFIG_CRYPTO_CAMELLIA is not set
++# CONFIG_CRYPTO_TEST is not set
 +# CONFIG_CRYPTO_AUTHENC is not set
 +CONFIG_CRYPTO_HW=y
++
++#
++# Library routines
++#
++CONFIG_BITREVERSE=y
++CONFIG_CRC_CCITT=y
++CONFIG_CRC16=y
++# CONFIG_CRC_ITU_T is not set
++CONFIG_CRC32=y
++# CONFIG_CRC7 is not set
++CONFIG_LIBCRC32C=y
++CONFIG_ZLIB_INFLATE=y
++CONFIG_ZLIB_DEFLATE=y
++CONFIG_REED_SOLOMON=y
++CONFIG_REED_SOLOMON_DEC16=y
++CONFIG_PLIST=y
++CONFIG_HAS_IOMEM=y
++CONFIG_HAS_IOPORT=y
++CONFIG_HAS_DMA=y
+diff --git a/arch/arm/configs/collie_defconfig b/arch/arm/configs/collie_defconfig
+index 970c8c7..4264e27 100644
+--- a/arch/arm/configs/collie_defconfig
++++ b/arch/arm/configs/collie_defconfig
+@@ -367,7 +367,6 @@ 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_OBSOLETE_CHIPS=y
+ CONFIG_MTD_SHARP=y
+ # CONFIG_MTD_XIP is not set
  
- #
- # Library routines
-@@ -1018,8 +1131,9 @@ CONFIG_CRYPTO_DEFLATE=y
- CONFIG_BITREVERSE=y
- CONFIG_CRC_CCITT=m
- # CONFIG_CRC16 is not set
--# CONFIG_CRC_ITU_T is not set
-+CONFIG_CRC_ITU_T=m
- CONFIG_CRC32=y
-+CONFIG_CRC7=m
- # CONFIG_LIBCRC32C is not set
- CONFIG_ZLIB_INFLATE=y
- CONFIG_ZLIB_DEFLATE=y
-diff --git a/arch/avr32/configs/atstk1002_defconfig b/arch/avr32/configs/atstk1002_defconfig
-index 3b977fd..2fb2ede 100644
---- a/arch/avr32/configs/atstk1002_defconfig
-+++ b/arch/avr32/configs/atstk1002_defconfig
-@@ -1,48 +1,48 @@
- #
- # Automatically generated make config: don't edit
--# Linux kernel version: 2.6.22-rc5
--# Sat Jun 23 15:32:08 2007
-+# Linux kernel version: 2.6.24-rc7
-+# Wed Jan  9 23:07:43 2008
- #
- CONFIG_AVR32=y
- CONFIG_GENERIC_GPIO=y
- CONFIG_GENERIC_HARDIRQS=y
-+CONFIG_STACKTRACE_SUPPORT=y
-+CONFIG_LOCKDEP_SUPPORT=y
+diff --git a/arch/arm/configs/eseries_pxa_defconfig b/arch/arm/configs/eseries_pxa_defconfig
+new file mode 100644
+index 0000000..ed487b9
+--- /dev/null
++++ b/arch/arm/configs/eseries_pxa_defconfig
+@@ -0,0 +1,1499 @@
++#
++# Automatically generated make config: don't edit
++# Linux kernel version: 2.6.21-hh17
++# Fri Nov  9 20:23:03 2007
++#
++CONFIG_ARM=y
++CONFIG_SYS_SUPPORTS_APM_EMULATION=y
++CONFIG_GENERIC_GPIO=y
++CONFIG_GENERIC_TIME=y
++CONFIG_MMU=y
++# CONFIG_NO_IOPORT is not set
++CONFIG_GENERIC_HARDIRQS=y
 +CONFIG_TRACE_IRQFLAGS_SUPPORT=y
- CONFIG_HARDIRQS_SW_RESEND=y
- CONFIG_GENERIC_IRQ_PROBE=y
- CONFIG_RWSEM_GENERIC_SPINLOCK=y
- CONFIG_GENERIC_TIME=y
-+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
- # CONFIG_ARCH_HAS_ILOG2_U32 is not set
- # CONFIG_ARCH_HAS_ILOG2_U64 is not set
-+CONFIG_ARCH_SUPPORTS_OPROFILE=y
- CONFIG_GENERIC_HWEIGHT=y
- CONFIG_GENERIC_CALIBRATE_DELAY=y
- CONFIG_GENERIC_BUG=y
- CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
- 
- #
--# Code maturity level options
++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_ZONE_DMA=y
++CONFIG_ARCH_MTD_XIP=y
++CONFIG_VECTORS_BASE=0xffff0000
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
++
++#
++# Code maturity level options
++#
++CONFIG_EXPERIMENTAL=y
++CONFIG_BROKEN_ON_SMP=y
++CONFIG_INIT_ENV_ARG_LIMIT=32
++
++#
 +# General setup
- #
- CONFIG_EXPERIMENTAL=y
- CONFIG_BROKEN_ON_SMP=y
- CONFIG_INIT_ENV_ARG_LIMIT=32
--
--#
--# General setup
--#
- CONFIG_LOCALVERSION=""
- # CONFIG_LOCALVERSION_AUTO is not set
- CONFIG_SWAP=y
- CONFIG_SYSVIPC=y
--# CONFIG_IPC_NS is not set
- CONFIG_SYSVIPC_SYSCTL=y
- CONFIG_POSIX_MQUEUE=y
--CONFIG_BSD_PROCESS_ACCT=y
--CONFIG_BSD_PROCESS_ACCT_V3=y
--CONFIG_TASKSTATS=y
--CONFIG_TASK_DELAY_ACCT=y
--# CONFIG_TASK_XACCT is not set
--# CONFIG_UTS_NS is not set
--CONFIG_AUDIT=y
++#
++CONFIG_LOCALVERSION=""
++CONFIG_LOCALVERSION_AUTO=y
++CONFIG_SWAP=y
++CONFIG_SYSVIPC=y
++# CONFIG_IPC_NS is not set
++CONFIG_SYSVIPC_SYSCTL=y
++# CONFIG_POSIX_MQUEUE is not set
 +# CONFIG_BSD_PROCESS_ACCT is not set
 +# CONFIG_TASKSTATS is not set
-+# CONFIG_USER_NS is not set
-+# CONFIG_PID_NS is not set
++# CONFIG_UTS_NS is not set
 +# CONFIG_AUDIT is not set
- # CONFIG_IKCONFIG is not set
- CONFIG_LOG_BUF_SHIFT=14
-+# CONFIG_CGROUPS is not set
-+# CONFIG_FAIR_GROUP_SCHED is not set
- CONFIG_SYSFS_DEPRECATED=y
- CONFIG_RELAY=y
- CONFIG_BLK_DEV_INITRD=y
-@@ -63,35 +63,28 @@ 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 is not set
-+CONFIG_SLUB_DEBUG=y
- # CONFIG_SLAB is not set
- CONFIG_SLUB=y
- # CONFIG_SLOB is not set
-+CONFIG_SLABINFO=y
- CONFIG_RT_MUTEXES=y
- # CONFIG_TINY_SHMEM is not set
- CONFIG_BASE_SMALL=1
--
--#
--# Loadable module support
--#
- CONFIG_MODULES=y
- CONFIG_MODULE_UNLOAD=y
- # CONFIG_MODULE_FORCE_UNLOAD is not set
- # CONFIG_MODVERSIONS is not set
- # CONFIG_MODULE_SRCVERSION_ALL is not set
- # CONFIG_KMOD is not set
--
--#
--# Block layer
--#
- CONFIG_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
-@@ -99,12 +92,12 @@ CONFIG_BLOCK=y
- CONFIG_IOSCHED_NOOP=y
- # CONFIG_IOSCHED_AS is not set
- # CONFIG_IOSCHED_DEADLINE is not set
--# CONFIG_IOSCHED_CFQ is not set
++# CONFIG_IKCONFIG is not set
++CONFIG_SYSFS_DEPRECATED=y
++# CONFIG_RELAY 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_KALLSYMS is not set
++CONFIG_HOTPLUG=y
++CONFIG_PRINTK=y
++CONFIG_BUG=y
++CONFIG_ELF_CORE=y
++CONFIG_BASE_FULL=y
++CONFIG_FUTEX=y
++CONFIG_EPOLL=y
++CONFIG_SHMEM=y
++CONFIG_SLAB=y
++CONFIG_VM_EVENT_COUNTERS=y
++CONFIG_RT_MUTEXES=y
++# CONFIG_TINY_SHMEM is not set
++CONFIG_BASE_SMALL=0
++# CONFIG_SLOB is not set
++
++#
++# Loadable module support
++#
++CONFIG_MODULES=y
++CONFIG_MODULE_UNLOAD=y
++CONFIG_MODULE_FORCE_UNLOAD=y
++# CONFIG_MODVERSIONS is not set
++# CONFIG_MODULE_SRCVERSION_ALL is not set
++CONFIG_KMOD=y
++
++#
++# Block layer
++#
++CONFIG_BLOCK=y
++# CONFIG_LBD is not set
++# CONFIG_BLK_DEV_IO_TRACE is not set
++# CONFIG_LSF is not set
++
++#
++# IO Schedulers
++#
++CONFIG_IOSCHED_NOOP=y
++CONFIG_IOSCHED_AS=y
++CONFIG_IOSCHED_DEADLINE=y
 +CONFIG_IOSCHED_CFQ=y
- # CONFIG_DEFAULT_AS is not set
- # CONFIG_DEFAULT_DEADLINE is not set
--# CONFIG_DEFAULT_CFQ is not set
--CONFIG_DEFAULT_NOOP=y
--CONFIG_DEFAULT_IOSCHED="noop"
-+CONFIG_DEFAULT_CFQ=y
++CONFIG_DEFAULT_AS=y
++# CONFIG_DEFAULT_DEADLINE is not set
++# CONFIG_DEFAULT_CFQ is not set
 +# CONFIG_DEFAULT_NOOP is not set
-+CONFIG_DEFAULT_IOSCHED="cfq"
- 
- #
- # System Type and features
-@@ -113,18 +106,27 @@ CONFIG_SUBARCH_AVR32B=y
- CONFIG_MMU=y
- CONFIG_PERFORMANCE_COUNTERS=y
- CONFIG_PLATFORM_AT32AP=y
-+CONFIG_CPU_AT32AP700X=y
- CONFIG_CPU_AT32AP7000=y
--CONFIG_BOARD_ATSTK1002=y
- CONFIG_BOARD_ATSTK1000=y
- # CONFIG_BOARD_ATNGW100 is not set
-+CONFIG_BOARD_ATSTK1002=y
-+# CONFIG_BOARD_ATSTK1003 is not set
-+# CONFIG_BOARD_ATSTK1004 is not set
-+# CONFIG_BOARD_ATSTK100X_CUSTOM is not set
-+# CONFIG_BOARD_ATSTK100X_SPI1 is not set
-+# CONFIG_BOARD_ATSTK1000_J2_LED is not set
-+# CONFIG_BOARD_ATSTK1000_J2_LED8 is not set
-+# CONFIG_BOARD_ATSTK1000_J2_RGB is not set
-+CONFIG_BOARD_ATSTK1000_EXTDAC=y
- CONFIG_LOADER_U_BOOT=y
- 
- #
- # Atmel AVR32 AP options
- #
--# CONFIG_AP7000_32_BIT_SMC is not set
--CONFIG_AP7000_16_BIT_SMC=y
--# CONFIG_AP7000_8_BIT_SMC is not set
-+# CONFIG_AP700X_32_BIT_SMC is not set
-+CONFIG_AP700X_16_BIT_SMC=y
-+# CONFIG_AP700X_8_BIT_SMC is not set
- CONFIG_LOAD_ADDRESS=0x10000000
- CONFIG_ENTRY_ADDRESS=0x90000000
- CONFIG_PHYS_OFFSET=0x10000000
-@@ -144,9 +146,11 @@ CONFIG_FLATMEM_MANUAL=y
- CONFIG_FLATMEM=y
- CONFIG_FLAT_NODE_MEM_MAP=y
- # CONFIG_SPARSEMEM_STATIC is not set
-+# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
- CONFIG_SPLIT_PTLOCK_CPUS=4
- # CONFIG_RESOURCES_64BIT is not set
- CONFIG_ZONE_DMA_FLAG=0
-+CONFIG_VIRT_TO_BUS=y
- # CONFIG_OWNERSHIP_TRACE is not set
- # CONFIG_HZ_100 is not set
- CONFIG_HZ_250=y
-@@ -156,13 +160,31 @@ CONFIG_HZ=250
- CONFIG_CMDLINE=""
- 
- #
--# Bus options
-+# Power management options
- #
--# CONFIG_ARCH_SUPPORTS_MSI is not set
- 
- #
--# PCCARD (PCMCIA/CardBus) support
++CONFIG_DEFAULT_IOSCHED="anticipatory"
++
++#
++# 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_IOP32X is not set
++# CONFIG_ARCH_IOP33X is not set
++# CONFIG_ARCH_IOP13XX is not set
++# CONFIG_ARCH_IXP4XX is not set
++# CONFIG_ARCH_IXP2000 is not set
++# CONFIG_ARCH_IXP23XX is not set
++# CONFIG_ARCH_L7200 is not set
++# CONFIG_ARCH_NS9XXX 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_OMAP is not set
++# CONFIG_BOARD_IRQ_MAP_SMALL is not set
++CONFIG_BOARD_IRQ_MAP_BIG=y
++CONFIG_DMABOUNCE=y
++
++#
++# Intel PXA2xx Implementations
++#
++# 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_TOSHIBA_TMIO_OHCI=y
++CONFIG_ARCH_ESERIES=y
++CONFIG_MACH_E330=y
++CONFIG_MACH_E740=y
++CONFIG_MACH_E750=y
++CONFIG_MACH_E400=y
++CONFIG_MACH_E800=y
++CONFIG_E330_LCD=y
++CONFIG_E740_LCD=y
++CONFIG_E750_LCD=y
++CONFIG_E400_LCD=y
++CONFIG_E800_LCD=y
++CONFIG_ESERIES_UDC=y
++CONFIG_E330_TC6387XB=y
++CONFIG_E740_T7L66XB=y
++CONFIG_E400_T7L66XB=y
++CONFIG_E750_E800_TC6393XB=y
++CONFIG_E740_PCMCIA=m
++CONFIG_E750_PCMCIA=m
++CONFIG_E800_PCMCIA=m
++# CONFIG_MACH_A620 is not set
++# CONFIG_MACH_A716 is not set
++# CONFIG_MACH_A730 is not set
++# CONFIG_ARCH_H1900 is not set
++# CONFIG_ARCH_H2200 is not set
++# CONFIG_MACH_H3900 is not set
++# CONFIG_MACH_H4000 is not set
++# CONFIG_MACH_H4700 is not set
++# CONFIG_MACH_HX2750 is not set
++# CONFIG_ARCH_H5400 is not set
++# CONFIG_MACH_HIMALAYA is not set
++# CONFIG_MACH_HTCUNIVERSAL is not set
++# CONFIG_MACH_HTCALPINE is not set
++# CONFIG_MACH_MAGICIAN is not set
++# CONFIG_MACH_HTCAPACHE is not set
++# CONFIG_MACH_BLUEANGEL is not set
++
++#
++# HTC_HW6X00
++#
++# CONFIG_MACH_HTCBEETLES is not set
++# CONFIG_MACH_HW6900 is not set
++# CONFIG_MACH_HTCATHENA is not set
++# CONFIG_ARCH_AXIMX3 is not set
++# CONFIG_ARCH_AXIMX5 is not set
++# CONFIG_MACH_X50 is not set
++# CONFIG_ARCH_ROVERP1 is not set
++# CONFIG_ARCH_ROVERP5P is not set
++# CONFIG_MACH_XSCALE_PALMLD is not set
++# CONFIG_MACH_T3XSCALE is not set
++# CONFIG_MACH_RECON is not set
++# CONFIG_MACH_GHI270HG is not set
++# CONFIG_MACH_GHI270 is not set
++# CONFIG_MACH_LOOXC550 is not set
++# CONFIG_PXA_SHARPSL is not set
++# CONFIG_MACH_TRIZEPS4 is not set
++CONFIG_PXA25x=y
++
++#
++# Linux As Bootloader
++#
++# CONFIG_LAB is not set
++
++#
++# Processor Type
++#
++CONFIG_CPU_32=y
++CONFIG_CPU_XSCALE=y
++CONFIG_CPU_32v5=y
++CONFIG_CPU_ABRT_EV5T=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 is not set
++# CONFIG_CPU_DCACHE_DISABLE is not set
++# CONFIG_OUTER_CACHE is not set
++CONFIG_IWMMXT=y
++CONFIG_XSCALE_PMU=y
++
++#
++# Bus support
++#
++
++#
++# PCCARD (PCMCIA/CardBus) support
++#
++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_PCMCIA_PXA2XX=m
++
++#
++# Kernel Features
++#
++# CONFIG_PREEMPT is not set
++# CONFIG_NO_IDLE_HZ 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_SPLIT_PTLOCK_CPUS=4096
++# CONFIG_RESOURCES_64BIT is not set
++CONFIG_ZONE_DMA_FLAG=1
++CONFIG_ALIGNMENT_TRAP=y
++
++#
++# Boot options
++#
++CONFIG_ZBOOT_ROM_TEXT=0x0
++CONFIG_ZBOOT_ROM_BSS=0x0
++CONFIG_CMDLINE=""
++# CONFIG_XIP_KERNEL is not set
++CONFIG_KEXEC=y
++# CONFIG_TXTOFFSET_DELTA 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 is not set
-+CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
-+# 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=y
-+# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
-+CONFIG_CPU_FREQ_AT32AP=y
++# CONFIG_CPU_FREQ is not set
 +
- #
-+# Bus options
 +#
-+# CONFIG_ARCH_SUPPORTS_MSI is not set
- # CONFIG_PCCARD is not set
- 
- #
-@@ -182,7 +204,12 @@ CONFIG_NET=y
- CONFIG_PACKET=y
- CONFIG_PACKET_MMAP=y
- CONFIG_UNIX=y
--# CONFIG_NET_KEY 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=y
++
++#
++# Power management options
++#
++CONFIG_PM=y
++CONFIG_PM_LEGACY=y
++# CONFIG_PM_DEBUG is not set
++# CONFIG_DPM_DEBUG is not set
++# CONFIG_PM_SYSFS_DEPRECATED is not set
++# CONFIG_APM_EMULATION is not set
++
++#
++# Networking
++#
++CONFIG_NET=y
++
++#
++# Networking options
++#
++# CONFIG_NETDEBUG is not set
++# CONFIG_PACKET is not set
++CONFIG_UNIX=y
 +CONFIG_XFRM=y
-+CONFIG_XFRM_USER=m
++# CONFIG_XFRM_USER is not set
 +# CONFIG_XFRM_SUB_POLICY is not set
 +# CONFIG_XFRM_MIGRATE is not set
-+CONFIG_NET_KEY=m
-+# CONFIG_NET_KEY_MIGRATE is not set
- CONFIG_INET=y
- # CONFIG_IP_MULTICAST is not set
- # CONFIG_IP_ADVANCED_ROUTER is not set
-@@ -191,36 +218,52 @@ 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_NET_IPIP=m
-+CONFIG_NET_IPGRE=m
- # 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_AH=m
-+CONFIG_INET_ESP=m
- # 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_TUNNEL=m
-+CONFIG_INET_XFRM_MODE_TRANSPORT=m
-+CONFIG_INET_XFRM_MODE_TUNNEL=m
-+CONFIG_INET_XFRM_MODE_BEET=m
-+# 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_INET6_XFRM_TUNNEL is not set
--# CONFIG_INET6_TUNNEL is not set
-+CONFIG_IPV6=m
-+# CONFIG_IPV6_PRIVACY is not set
-+# CONFIG_IPV6_ROUTER_PREF is not set
-+# CONFIG_IPV6_OPTIMISTIC_DAD is not set
-+CONFIG_INET6_AH=m
-+CONFIG_INET6_ESP=m
-+CONFIG_INET6_IPCOMP=m
-+# CONFIG_IPV6_MIP6 is not set
-+CONFIG_INET6_XFRM_TUNNEL=m
-+CONFIG_INET6_TUNNEL=m
-+CONFIG_INET6_XFRM_MODE_TRANSPORT=m
-+CONFIG_INET6_XFRM_MODE_TUNNEL=m
-+CONFIG_INET6_XFRM_MODE_BEET=m
-+# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
-+CONFIG_IPV6_SIT=m
-+CONFIG_IPV6_TUNNEL=m
-+# CONFIG_IPV6_MULTIPLE_TABLES 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_BRIDGE=m
- # CONFIG_VLAN_8021Q is not set
- # CONFIG_DECNET is not set
-+CONFIG_LLC=m
- # CONFIG_LLC2 is not set
- # CONFIG_IPX is not set
- # CONFIG_ATALK is not set
-@@ -228,16 +271,13 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
- # CONFIG_LAPB is not set
- # CONFIG_ECONET is not set
- # CONFIG_WAN_ROUTER is not set
--
--#
--# QoS and/or fair queueing
--#
- # CONFIG_NET_SCHED is not set
- 
- #
- # Network testing
- #
- # CONFIG_NET_PKTGEN is not set
-+# CONFIG_NET_TCPPROBE is not set
- # CONFIG_HAMRADIO is not set
- # CONFIG_IRDA is not set
- # CONFIG_BT is not set
-@@ -251,6 +291,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
- # CONFIG_MAC80211 is not set
- # CONFIG_IEEE80211 is not set
- # CONFIG_RFKILL is not set
-+# CONFIG_NET_9P is not set
- 
- #
- # Device Drivers
-@@ -259,16 +300,13 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
- #
- # Generic Driver Options
- #
-+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
- CONFIG_STANDALONE=y
- # CONFIG_PREVENT_FIRMWARE_BUILD is not set
- # CONFIG_FW_LOADER is not set
- # CONFIG_DEBUG_DRIVER is not set
- # CONFIG_DEBUG_DEVRES is not set
- # CONFIG_SYS_HYPERVISOR is not set
--
--#
--# Connector - unified userspace <-> kernelspace linker
--#
- # CONFIG_CONNECTOR is not set
- CONFIG_MTD=y
- # CONFIG_MTD_DEBUG is not set
-@@ -288,6 +326,7 @@ CONFIG_MTD_BLOCK=y
- # 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
-@@ -327,6 +366,8 @@ CONFIG_MTD_PHYSMAP_BANKWIDTH=2
- #
- # Self-contained MTD device drivers
- #
-+CONFIG_MTD_DATAFLASH=m
-+CONFIG_MTD_M25P80=m
- # CONFIG_MTD_SLRAM is not set
- # CONFIG_MTD_PHRAM is not set
- # CONFIG_MTD_MTDRAM is not set
-@@ -345,20 +386,8 @@ CONFIG_MTD_PHYSMAP_BANKWIDTH=2
- # UBI - Unsorted block images
- #
- # CONFIG_MTD_UBI is not set
--
--#
--# Parallel port support
--#
- # CONFIG_PARPORT is not set
--
--#
--# Plug and Play support
--#
--# CONFIG_PNPACPI is not set
--
--#
--# Block devices
--#
-+CONFIG_BLK_DEV=y
- # CONFIG_BLK_DEV_COW_COMMON is not set
- CONFIG_BLK_DEV_LOOP=m
- # CONFIG_BLK_DEV_CRYPTOLOOP is not set
-@@ -369,42 +398,87 @@ CONFIG_BLK_DEV_RAM_SIZE=4096
- CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
- # CONFIG_CDROM_PKTCDVD is not set
- # CONFIG_ATA_OVER_ETH is not set
--
--#
--# Misc devices
--#
--# CONFIG_BLINK is not set
-+CONFIG_MISC_DEVICES=y
-+# CONFIG_EEPROM_93CX6 is not set
-+CONFIG_ATMEL_SSC=m
- # CONFIG_IDE is not set
- 
- #
- # SCSI device support
- #
- # CONFIG_RAID_ATTRS is not set
--# CONFIG_SCSI 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 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=y
++CONFIG_INET_XFRM_MODE_TUNNEL=y
++CONFIG_INET_XFRM_MODE_BEET=y
++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_INET6_XFRM_TUNNEL is not set
++# CONFIG_INET6_TUNNEL is not set
++# CONFIG_NETWORK_SECMARK is not set
++# CONFIG_NETFILTER is not set
++
++#
++# DCCP Configuration (EXPERIMENTAL)
++#
++# CONFIG_IP_DCCP is not set
++
++#
++# SCTP Configuration (EXPERIMENTAL)
++#
++# CONFIG_IP_SCTP is not set
++
++#
++# TIPC Configuration (EXPERIMENTAL)
++#
++# CONFIG_TIPC is not set
++# CONFIG_ATM is not set
++# CONFIG_BRIDGE is not set
++# CONFIG_VLAN_8021Q is not set
++# CONFIG_DECNET is not set
++# CONFIG_LLC2 is not set
++# CONFIG_IPX is not set
++# CONFIG_ATALK is not set
++# CONFIG_X25 is not set
++# CONFIG_LAPB is not set
++# CONFIG_ECONET is not set
++# CONFIG_WAN_ROUTER is not set
++
++#
++# QoS and/or fair queueing
++#
++# CONFIG_NET_SCHED is not set
++
++#
++# Network testing
++#
++# CONFIG_NET_PKTGEN is not set
++# CONFIG_HAMRADIO is not set
++# CONFIG_IRDA is not set
++# CONFIG_BT is not set
++CONFIG_IEEE80211=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_IEEE80211_SOFTMAC is not set
++CONFIG_WIRELESS_EXT=y
++
++#
++# Device Drivers
++#
++
++#
++# Generic Driver Options
++#
++# CONFIG_STANDALONE is not set
++CONFIG_PREVENT_FIRMWARE_BUILD=y
++CONFIG_FW_LOADER=y
++# CONFIG_SYS_HYPERVISOR is not set
++
++#
++# Connector - unified userspace <-> kernelspace linker
++#
++# CONFIG_CONNECTOR is not set
++
++#
++# Memory Technology Devices (MTD)
++#
++CONFIG_MTD=m
++# 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_AFS_PARTS is not set
++
++#
++# User Modules And Translation Layers
++#
++CONFIG_MTD_CHAR=m
++CONFIG_MTD_BLKDEVS=m
++CONFIG_MTD_BLOCK=m
++# CONFIG_MTD_BLOCK_RO is not set
++# 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
++
++#
++# 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
++# CONFIG_MTD_OBSOLETE_CHIPS 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
++
++#
++# NAND Flash Device Drivers
++#
++CONFIG_MTD_NAND=m
++CONFIG_MTD_NAND_VERIFY_WRITE=y
++# CONFIG_MTD_NAND_ECC_SMC is not set
++# CONFIG_MTD_NAND_H1900 is not set
++CONFIG_MTD_NAND_IDS=m
++# CONFIG_MTD_NAND_DISKONCHIP is not set
++# CONFIG_MTD_NAND_SHARPSL is not set
++# CONFIG_MTD_NAND_NANDSIM is not set
++
++#
++# OneNAND Flash Device Drivers
++#
++# CONFIG_MTD_ONENAND is not set
++
++#
++# Parallel port support
++#
++# CONFIG_PARPORT is not set
++
++#
++# Plug and Play support
++#
++# CONFIG_PNPACPI is not set
++
++#
++# Block devices
++#
++# 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=y
++CONFIG_BLK_DEV_RAM_COUNT=16
++CONFIG_BLK_DEV_RAM_SIZE=6144
++CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
++# CONFIG_CDROM_PKTCDVD is not set
++# CONFIG_ATA_OVER_ETH is not set
++
++#
++# ATA/ATAPI/MFM/RLL support
++#
++CONFIG_IDE=m
++CONFIG_IDE_MAX_HWIFS=4
++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 is not set
++# CONFIG_BLK_DEV_IDETAPE is not set
++# CONFIG_BLK_DEV_IDEFLOPPY is not set
++# CONFIG_BLK_DEV_IDESCSI is not set
++# CONFIG_IDE_TASK_IOCTL is not set
++
++#
++# IDE chipset support/bugfixes
++#
++# CONFIG_IDE_GENERIC is not set
++# CONFIG_IDE_ARM is not set
++# CONFIG_BLK_DEV_IDEDMA is not set
++# CONFIG_BLK_DEV_HD 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_ATA is not set
++# CONFIG_SCSI_NETLINK is not set
 +# CONFIG_SCSI_PROC_FS is not set
- 
- #
--# Multi-device support (RAID and LVM)
++
++#
 +# SCSI support type (disk, tape, CD-ROM)
- #
--# CONFIG_MD is not set
-+CONFIG_BLK_DEV_SD=m
++#
++# CONFIG_BLK_DEV_SD is not set
 +# CONFIG_CHR_DEV_ST is not set
 +# CONFIG_CHR_DEV_OSST is not set
-+CONFIG_BLK_DEV_SR=m
-+# CONFIG_BLK_DEV_SR_VENDOR is not set
++# CONFIG_BLK_DEV_SR is not set
 +# CONFIG_CHR_DEV_SG is not set
 +# CONFIG_CHR_DEV_SCH is not set
- 
- #
--# Network device support
++
++#
 +# 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
@@ -8194,235 +9005,334 @@
 +# CONFIG_SCSI_SPI_ATTRS is not set
 +# CONFIG_SCSI_FC_ATTRS is not set
 +# CONFIG_SCSI_ISCSI_ATTRS is not set
++# CONFIG_SCSI_SAS_ATTRS is not set
 +# CONFIG_SCSI_SAS_LIBSAS is not set
-+# CONFIG_SCSI_SRP_ATTRS is not set
-+# CONFIG_SCSI_LOWLEVEL is not set
-+CONFIG_ATA=m
-+# CONFIG_ATA_NONSTANDARD is not set
-+CONFIG_PATA_AT32=m
-+# CONFIG_PATA_PLATFORM is not set
++
++#
++# SCSI low-level drivers
++#
++# CONFIG_ISCSI_TCP is not set
++# CONFIG_SCSI_DEBUG is not set
++
++#
++# PCMCIA SCSI adapter support
++#
++# CONFIG_PCMCIA_AHA152X is not set
++# CONFIG_PCMCIA_FDOMAIN is not set
++# CONFIG_PCMCIA_NINJA_SCSI is not set
++# CONFIG_PCMCIA_QLOGIC is not set
++# CONFIG_PCMCIA_SYM53C500 is not set
++
++#
++# Serial ATA (prod) and Parallel ATA (experimental) drivers
++#
++# CONFIG_ATA is not set
++
++#
++# Multi-device support (RAID and LVM)
++#
 +# CONFIG_MD is not set
- CONFIG_NETDEVICES=y
--CONFIG_DUMMY=y
-+# CONFIG_NETDEVICES_MULTIQUEUE is not set
++
++#
++# Fusion MPT device support
++#
++# CONFIG_FUSION is not set
++
++#
++# IEEE 1394 (FireWire) support
++#
++
++#
++# I2O device support
++#
++
++#
++# Network device support
++#
++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=m
--# CONFIG_PHYLIB is not set
--
--#
--# Ethernet (10 or 100Mbit)
--#
-+# CONFIG_VETH is not set
-+CONFIG_PHYLIB=y
++# CONFIG_BONDING is not set
++# CONFIG_EQUALIZER is not set
++# CONFIG_TUN is not set
 +
 +#
-+# MII PHY device drivers
++# PHY device support
++#
++
++#
++# Ethernet (10 or 100Mbit)
++#
++# CONFIG_NET_ETHERNET is not set
++
++#
++# Ethernet (1000 Mbit)
++#
++
++#
++# Ethernet (10000 Mbit)
++#
++
++#
++# Token Ring devices
++#
++
++#
++# Wireless LAN (non-hamradio)
++#
++CONFIG_NET_RADIO=y
++# CONFIG_NET_WIRELESS_RTNETLINK is not set
++
++#
++# Obsolete Wireless cards support (pre-802.11)
++#
++# CONFIG_STRIP is not set
++# CONFIG_PCMCIA_WAVELAN is not set
++# 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 is not set
++# CONFIG_ATMEL is not set
++
++#
++# Wireless 802.11b Pcmcia/Cardbus cards support
++#
++# CONFIG_AIRO_CS is not set
++# CONFIG_PCMCIA_WL3501 is not set
++# CONFIG_USB_ZD1201 is not set
++CONFIG_HOSTAP=m
++# CONFIG_HOSTAP_FIRMWARE is not set
++# CONFIG_HOSTAP_CS is not set
++# CONFIG_ACX is not set
++CONFIG_NET_WIRELESS=y
++
++#
++# PCMCIA network device support
++#
++# CONFIG_NET_PCMCIA is not set
++
++#
++# Wan interfaces
++#
++# CONFIG_WAN is not set
++# CONFIG_PPP is not set
++# CONFIG_SLIP is not set
++# CONFIG_SHAPER is not set
++# CONFIG_NETCONSOLE is not set
++# CONFIG_NETPOLL is not set
++# CONFIG_NET_POLL_CONTROLLER is not set
++
++#
++# ISDN subsystem
 +#
-+# CONFIG_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_FIXED_PHY is not set
-+# CONFIG_MDIO_BITBANG is not set
- CONFIG_NET_ETHERNET=y
--CONFIG_MII=y
-+# CONFIG_MII is not set
- CONFIG_MACB=y
-+# 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
- 
-@@ -423,27 +497,54 @@ 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_SHAPER 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
- 
- #
--# ISDN subsystem
++
++#
 +# Input device support
- #
--# CONFIG_ISDN is not set
-+CONFIG_INPUT=m
++#
++CONFIG_INPUT=y
 +# CONFIG_INPUT_FF_MEMLESS is not set
-+CONFIG_INPUT_POLLDEV=m
- 
- #
--# Telephony Support
++
++#
 +# Userland interfaces
- #
--# CONFIG_PHONE is not set
-+CONFIG_INPUT_MOUSEDEV=m
-+CONFIG_INPUT_MOUSEDEV_PSAUX=y
-+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
-+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
++#
++# CONFIG_INPUT_MOUSEDEV is not set
 +# CONFIG_INPUT_JOYDEV is not set
++CONFIG_INPUT_TSDEV=m
++CONFIG_INPUT_TSDEV_SCREEN_X=240
++CONFIG_INPUT_TSDEV_SCREEN_Y=320
 +CONFIG_INPUT_EVDEV=m
 +# CONFIG_INPUT_EVBUG is not set
- 
- #
--# Input device support
++# CONFIG_INPUT_LED_TRIGGER is not set
++
++#
 +# Input Device Drivers
- #
--# CONFIG_INPUT 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=m
-+CONFIG_INPUT_MOUSE=y
-+# CONFIG_MOUSE_PS2 is not set
-+# CONFIG_MOUSE_SERIAL is not set
-+# CONFIG_MOUSE_VSXXXAA is not set
-+CONFIG_MOUSE_GPIO=m
++#
++# 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_TOUCHSCREEN=y
++# 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_WM97XX=m
++CONFIG_TOUCHSCREEN_WM9705=y
++CONFIG_TOUCHSCREEN_WM9712=y
++CONFIG_TOUCHSCREEN_WM9713=y
++# 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_INPUT_MISC is not set
- 
- #
- # Hardware I/O ports
-@@ -472,35 +573,87 @@ CONFIG_SERIAL_CORE=y
- CONFIG_SERIAL_CORE_CONSOLE=y
- CONFIG_UNIX98_PTYS=y
- # CONFIG_LEGACY_PTYS is not set
--
--#
--# IPMI
--#
- # CONFIG_IPMI_HANDLER is not set
--# CONFIG_WATCHDOG is not set
- # CONFIG_HW_RANDOM is not set
- # CONFIG_RTC is not set
- # CONFIG_GEN_RTC is not set
- # CONFIG_R3964 is not set
- # CONFIG_RAW_DRIVER is not set
++
++#
++# Hardware I/O ports
++#
++# CONFIG_SERIO 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_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_RS232_SERIAL is not set
++CONFIG_UNIX98_PTYS=y
++# CONFIG_LEGACY_PTYS is not set
++
++#
++# IPMI
++#
++# CONFIG_IPMI_HANDLER is not set
++
++#
++# Watchdog Cards
++#
++# CONFIG_WATCHDOG is not set
++CONFIG_HW_RANDOM=m
++# CONFIG_NVRAM is not set
++# CONFIG_SA1100_RTC is not set
++# CONFIG_DTLK is not set
++# CONFIG_R3964 is not set
++# CONFIG_TIHTC 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_RAW_DRIVER is not set
++
++#
++# TPM devices
++#
 +# CONFIG_TCG_TPM is not set
-+CONFIG_I2C=m
-+CONFIG_I2C_BOARDINFO=y
-+CONFIG_I2C_CHARDEV=m
- 
- #
--# TPM devices
-+# I2C Algorithms
- #
--# CONFIG_TCG_TPM is not set
--# CONFIG_I2C is not set
-+CONFIG_I2C_ALGOBIT=m
-+# CONFIG_I2C_ALGOPCF is not set
-+# CONFIG_I2C_ALGOPCA is not set
 +
 +#
-+# I2C Hardware Bus support
++# I2C support
 +#
-+CONFIG_I2C_GPIO=m
-+# 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 is not set
 +
 +#
-+# Miscellaneous I2C Chip support
++# SPI support
 +#
-+# CONFIG_SENSORS_DS1337 is not set
-+# CONFIG_SENSORS_DS1374 is not set
-+# CONFIG_DS1682 is not set
-+# CONFIG_SENSORS_EEPROM is not set
-+# CONFIG_SENSORS_PCF8574 is not set
-+# CONFIG_SENSORS_PCA9539 is not set
-+# CONFIG_SENSORS_PCF8591 is not set
-+# CONFIG_SENSORS_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
- 
- #
- # SPI support
- #
--# CONFIG_SPI is not set
--# CONFIG_SPI_MASTER is not set
-+CONFIG_SPI=y
-+# CONFIG_SPI_DEBUG is not set
-+CONFIG_SPI_MASTER=y
++# CONFIG_SPI is not set
++# CONFIG_SPI_MASTER is not set
 +
 +#
-+# SPI Master Controller Drivers
++# Dallas's 1-wire bus
 +#
-+CONFIG_SPI_ATMEL=y
-+# CONFIG_SPI_BITBANG is not set
- 
- #
--# Dallas's 1-wire bus
-+# SPI Protocol Masters
- #
-+# CONFIG_SPI_AT25 is not set
-+CONFIG_SPI_SPIDEV=m
-+# CONFIG_SPI_TLE62X0 is not set
- # CONFIG_W1 is not set
++# CONFIG_W1 is not set
++
++#
++# Hardware Monitoring support
++#
++# CONFIG_HWMON is not set
++# CONFIG_HWMON_VID is not set
 +# CONFIG_POWER_SUPPLY is not set
- # CONFIG_HWMON is not set
-+CONFIG_WATCHDOG=y
-+# CONFIG_WATCHDOG_NOWAYOUT is not set
 +
 +#
-+# Watchdog Device Drivers
++# L3 serial bus support
 +#
-+# CONFIG_SOFT_WATCHDOG is not set
-+CONFIG_AT32AP700X_WDT=y
++# CONFIG_L3 is not set
 +
 +#
-+# Sonics Silicon Backplane
++# Misc devices
 +#
-+CONFIG_SSB_POSSIBLE=y
-+# CONFIG_SSB is not set
- 
- #
- # Multifunction device drivers
-@@ -517,23 +670,94 @@ CONFIG_UNIX98_PTYS=y
- #
- # Graphics support
- #
--# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
-+# CONFIG_VGASTATE is not set
-+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
++
++#
++# Multimedia Capabilities Port drivers
++#
++# CONFIG_ADC is not set
++
++#
++# Compaq/iPAQ Drivers
++#
++
++#
++# Compaq/HP iPAQ Drivers
++#
++# CONFIG_IPAQ_SLEEVE is not set
++# CONFIG_SLEEVE_DEBUG is not set
++
++#
++# Multifunction device drivers
++#
++# CONFIG_MFD_SM501 is not set
++# CONFIG_HTC_ASIC2 is not set
++# CONFIG_HTC_ASIC3 is not set
++# CONFIG_HTC_PASIC3 is not set
++# CONFIG_HTC_EGPIO is not set
++# CONFIG_HTC_BBKEYS is not set
++# CONFIG_HTC_ASIC3_DS1WM is not set
++# CONFIG_SOC_SAMCOP is not set
++# CONFIG_SOC_HAMCOP is not set
++# CONFIG_SOC_MQ11XX is not set
++CONFIG_SOC_T7L66XB=y
++# CONFIG_SOC_TC6387XB is not set
++CONFIG_SOC_TC6393XB=y
++# CONFIG_SOC_TSC2101 is not set
++# CONFIG_SOC_TSC2200 is not set
++
++#
++# LED devices
++#
++# CONFIG_NEW_LEDS is not set
++
++#
++# LED drivers
++#
++
++#
++# LED Triggers
++#
++# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set
++
++#
++# Multimedia devices
++#
++# CONFIG_VIDEO_DEV is not set
++
++#
++# Digital Video Broadcasting Devices
++#
++# CONFIG_DVB is not set
++# CONFIG_USB_DABUSB is not set
++
++#
++# Graphics support
++#
++CONFIG_BACKLIGHT_LCD_SUPPORT=y
++CONFIG_BACKLIGHT_CLASS_DEVICE=y
++CONFIG_LCD_CLASS_DEVICE=y
++CONFIG_BACKLIGHT_CORGI=y
 +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_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
@@ -8432,27 +9342,46 @@
 +#
 +# Frame buffer hardware drivers
 +#
++# CONFIG_FB_IMAGEON is not set
 +# CONFIG_FB_S1D13XXX is not set
-+CONFIG_FB_ATMEL=y
++CONFIG_FB_PXA=y
++# CONFIG_FB_PXA_PARAMETERS is not set
++# CONFIG_FB_MBX is not set
++CONFIG_FB_W100=y
 +# CONFIG_FB_VIRTUAL is not set
-+CONFIG_BACKLIGHT_LCD_SUPPORT=y
-+CONFIG_LCD_CLASS_DEVICE=y
-+CONFIG_LCD_LTV350QV=y
-+# CONFIG_BACKLIGHT_CLASS_DEVICE is not set
- 
- #
- # Display device support
- #
- # CONFIG_DISPLAY_SUPPORT is not set
--# CONFIG_VGASTATE is not set
--# CONFIG_FB is not set
-+# CONFIG_LOGO is not set
- 
- #
- # Sound
- #
--# CONFIG_SOUND is not set
-+CONFIG_SOUND=m
++# CONFIG_FB_VSFB is not set
++
++#
++# Console display driver support
++#
++# CONFIG_VGA_CONSOLE is not set
++CONFIG_DUMMY_CONSOLE=y
++CONFIG_FRAMEBUFFER_CONSOLE=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 is not set
++# CONFIG_FONT_7x14 is not set
++# CONFIG_FONT_PEARL_8x8 is not set
++CONFIG_FONT_ACORN_8x8=y
++# 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
++
++#
++# Logo configuration
++#
++CONFIG_LOGO=y
++# CONFIG_LOGO_LINUX_MONO is not set
++# CONFIG_LOGO_LINUX_VGA16 is not set
++CONFIG_LOGO_LINUX_CLUT224=y
++
++#
++# Sound
++#
++CONFIG_SOUND=y
 +
 +#
 +# Advanced Linux Sound Architecture
@@ -8465,14 +9394,13 @@
 +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 is not set
-+# CONFIG_SND_VERBOSE_PROCFS is not set
-+# CONFIG_SND_VERBOSE_PRINTK is not set
++CONFIG_SND_DYNAMIC_MINORS=y
++CONFIG_SND_SUPPORT_OLD_API=y
++CONFIG_SND_VERBOSE_PROCFS=y
++CONFIG_SND_VERBOSE_PRINTK=y
 +# CONFIG_SND_DEBUG is not set
- 
- #
--# USB support
++
++#
 +# Generic devices
 +#
 +# CONFIG_SND_DUMMY is not set
@@ -8480,107 +9408,1462 @@
 +# CONFIG_SND_SERIAL_U16550 is not set
 +# CONFIG_SND_MPU401 is not set
 +
- #
-+# SPI devices
 +#
-+CONFIG_SND_AT73C213=m
-+CONFIG_SND_AT73C213_TARGET_BITRATE=48000
++# ALSA ARM devices
++#
++# CONFIG_SND_PXA2XX_AC97 is not set
++# CONFIG_SND_RECON is not set
 +
 +#
-+# System on Chip audio support
++# USB devices
 +#
-+# CONFIG_SND_SOC is not set
++# CONFIG_SND_USB_AUDIO is not set
 +
 +#
-+# SoC Audio support for SuperH
++# PCMCIA devices
++#
++# CONFIG_SND_VXPOCKET is not set
++# CONFIG_SND_PDAUDIOCF is not set
++
++#
++# SoC audio support
++#
++CONFIG_SND_SOC_AC97_BUS=y
++CONFIG_SND_SOC=m
++
++#
++# SoC Platforms
++#
++
++#
++# SoC Audio for the Atmel AT91
++#
++
++#
++# SoC Audio for the Intel PXA2xx
++#
++CONFIG_SND_PXA2XX_SOC=m
++CONFIG_SND_PXA2XX_SOC_AC97=m
++CONFIG_SND_PXA2XX_SOC_E740_WM9705=m
++CONFIG_SND_PXA2XX_SOC_E750_WM9705=m
++CONFIG_SND_PXA2XX_SOC_E800_WM9712=m
++# CONFIG_SND_PXA2XX_SOC_MAGICIAN is not set
++# CONFIG_SND_PXA2XX_SOC_BLUEANGEL is not set
++# CONFIG_SND_PXA2XX_SOC_H5000 is not set
++
++#
++# SoC Audio for the Freescale i.MX
 +#
 +
 +#
++# SoC Audio for the Samsung S3C24XX
++#
++# CONFIG_SND_SOC_AC97_CODEC is not set
++# CONFIG_SND_SOC_WM8711 is not set
++# CONFIG_SND_SOC_WM8510 is not set
++# CONFIG_SND_SOC_WM8731 is not set
++# CONFIG_SND_SOC_WM8750 is not set
++# CONFIG_SND_SOC_WM8753 is not set
++# CONFIG_SND_SOC_WM8772 is not set
++# CONFIG_SND_SOC_WM8971 is not set
++# CONFIG_SND_SOC_WM8956 is not set
++# CONFIG_SND_SOC_WM8960 is not set
++# CONFIG_SND_SOC_WM8976 is not set
++# CONFIG_SND_SOC_WM8974 is not set
++# CONFIG_SND_SOC_WM8980 is not set
++CONFIG_SND_SOC_WM9705=m
++# CONFIG_SND_SOC_WM9713 is not set
++CONFIG_SND_SOC_WM9712=m
++# CONFIG_SND_SOC_UDA1380 is not set
++# CONFIG_SND_SOC_AK4535 is not set
++
++#
 +# Open Sound System
 +#
 +# CONFIG_SOUND_PRIME is not set
-+# CONFIG_HID_SUPPORT is not set
-+CONFIG_USB_SUPPORT=y
- # CONFIG_USB_ARCH_HAS_HCD is not set
- # CONFIG_USB_ARCH_HAS_OHCI is not set
- # CONFIG_USB_ARCH_HAS_EHCI is not set
-@@ -545,47 +769,116 @@ CONFIG_UNIX98_PTYS=y
- #
- # USB Gadget Support
- #
--# CONFIG_USB_GADGET is not set
--# CONFIG_MMC is not set
--
--#
--# LED devices
--#
--# CONFIG_NEW_LEDS is not set
++CONFIG_AC97_BUS=m
++
++#
++# HID Devices
++#
++CONFIG_HID=y
++# CONFIG_HID_DEBUG is not set
++
++#
++# USB support
++#
++CONFIG_USB_ARCH_HAS_HCD=y
++CONFIG_USB_ARCH_HAS_OHCI=y
++# CONFIG_USB_ARCH_HAS_EHCI is not set
++CONFIG_USB=m
++CONFIG_USB_DEBUG=y
++
++#
++# Miscellaneous USB options
++#
++CONFIG_USB_DEVICEFS=y
++CONFIG_USB_DYNAMIC_MINORS=y
++# CONFIG_USB_SUSPEND is not set
++# CONFIG_USB_OTG is not set
++
++#
++# USB Host Controller Drivers
++#
++# CONFIG_USB_ISP116X_HCD is not set
++# CONFIG_USB_OHCI_HCD is not set
++# CONFIG_USB_SL811_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=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_KARMA is not set
++# CONFIG_USB_LIBUSUAL 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_AIPTEK is not set
++# CONFIG_USB_WACOM is not set
++# CONFIG_USB_ACECAD is not set
++# CONFIG_USB_KBTAB is not set
++# CONFIG_USB_POWERMATE is not set
++# CONFIG_USB_TOUCHSCREEN is not set
++# CONFIG_USB_YEALINK is not set
++# CONFIG_USB_XPAD is not set
++# CONFIG_USB_ATI_REMOTE is not set
++# CONFIG_USB_ATI_REMOTE2 is not set
++# CONFIG_USB_KEYSPAN_REMOTE is not set
++# CONFIG_USB_APPLETOUCH is not set
++# CONFIG_USB_GTCO is not set
++
++#
++# USB Imaging devices
++#
++# CONFIG_USB_MDC800 is not set
++# CONFIG_USB_MICROTEK 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_MII is not set
++# CONFIG_USB_USBNET is not set
++# CONFIG_USB_MON is not set
++
++#
++# USB port drivers
++#
++
++#
++# USB Serial Converter support
++#
++# CONFIG_USB_SERIAL is not set
++
++#
++# USB Miscellaneous drivers
++#
++# CONFIG_USB_EMI62 is not set
++# CONFIG_USB_EMI26 is not set
++# CONFIG_USB_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
++
++#
++# USB DSL modem support
++#
++
++#
++# USB Gadget Support
++#
 +CONFIG_USB_GADGET=y
-+# CONFIG_USB_GADGET_DEBUG is not set
 +# CONFIG_USB_GADGET_DEBUG_FILES is not set
-+# CONFIG_USB_GADGET_DEBUG_FS is not set
 +CONFIG_USB_GADGET_SELECTED=y
-+# CONFIG_USB_GADGET_AMD5536UDC is not set
-+CONFIG_USB_GADGET_ATMEL_USBA=y
-+CONFIG_USB_ATMEL_USBA=y
-+# CONFIG_USB_GADGET_FSL_USB2 is not set
 +# CONFIG_USB_GADGET_NET2280 is not set
-+# CONFIG_USB_GADGET_PXA2XX is not set
-+# CONFIG_USB_GADGET_M66592 is not set
++CONFIG_USB_GADGET_PXA2XX=y
++CONFIG_USB_PXA2XX=y
++# CONFIG_USB_PXA2XX_SMALL is not set
++# CONFIG_USB_GADGET_PXA27X is not set
 +# CONFIG_USB_GADGET_GOKU is not set
++# CONFIG_USB_GADGET_MQ11XX 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_OMAP is not set
 +# CONFIG_USB_GADGET_AT91 is not set
 +# CONFIG_USB_GADGET_DUMMY_HCD is not set
-+CONFIG_USB_GADGET_DUALSPEED=y
-+CONFIG_USB_ZERO=m
-+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_GADGET_DUALSPEED is not set
++# CONFIG_USB_ZERO is not set
++CONFIG_USB_ETH=y
++# CONFIG_USB_ETH_RNDIS is not set
++# CONFIG_USB_GADGETFS is not set
++# CONFIG_USB_FILE_STORAGE is not set
++# CONFIG_USB_G_SERIAL is not set
 +# CONFIG_USB_MIDI_GADGET is not set
-+CONFIG_MMC=m
++# CONFIG_USB_G_CHAR is not set
++# CONFIG_USB_PXA2XX_GPIO is not set
++
++#
++# MMC/SD Card support
++#
++CONFIG_MMC=y
 +# CONFIG_MMC_DEBUG is not set
-+# CONFIG_MMC_UNSAFE_RESUME is not set
++CONFIG_MMC_BLOCK=y
++# CONFIG_MMC_PXA is not set
++CONFIG_MMC_TMIO=y
++# CONFIG_MMC_SAMCOP is not set
 +
 +#
-+# MMC/SD Card Drivers
++# Real Time Clock
 +#
-+CONFIG_MMC_BLOCK=m
-+CONFIG_MMC_BLOCK_BOUNCE=y
-+# CONFIG_SDIO_UART is not set
++CONFIG_RTC_LIB=y
++# CONFIG_RTC_CLASS is not set
 +
 +#
-+# MMC/SD Host Controller Drivers
++# File systems
 +#
-+CONFIG_MMC_SPI=m
-+CONFIG_NEW_LEDS=y
-+CONFIG_LEDS_CLASS=m
- 
++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_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_GFS2_FS is not set
++# CONFIG_OCFS2_FS is not set
++# CONFIG_MINIX_FS is not set
++# CONFIG_ROMFS_FS is not set
++CONFIG_INOTIFY=y
++CONFIG_INOTIFY_USER=y
++# CONFIG_QUOTA is not set
++CONFIG_DNOTIFY=y
++# CONFIG_AUTOFS_FS is not set
++# CONFIG_AUTOFS4_FS is not set
++# CONFIG_FUSE_FS is not set
++
++#
++# CD-ROM/DVD Filesystems
++#
++# CONFIG_ISO9660_FS is not set
++# CONFIG_UDF_FS is not set
++
++#
++# DOS/FAT/NT Filesystems
++#
++CONFIG_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_RAMFS=y
++# CONFIG_CONFIGFS_FS is not set
++
++#
++# Miscellaneous filesystems
++#
++# CONFIG_ADFS_FS is not set
++# CONFIG_AFFS_FS is not set
++# CONFIG_HFS_FS is not set
++# CONFIG_HFSPLUS_FS is not set
++# CONFIG_BEFS_FS is not set
++# CONFIG_BFS_FS is not set
++# CONFIG_EFS_FS is not set
++CONFIG_JFFS2_FS=m
++CONFIG_JFFS2_FS_DEBUG=0
++CONFIG_JFFS2_FS_WRITEBUFFER=y
++# 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_RTIME=y
++# CONFIG_JFFS2_RUBIN is not set
++# CONFIG_CRAMFS is not set
++# CONFIG_VXFS_FS is not set
++# CONFIG_HPFS_FS is not set
++# CONFIG_QNX4FS_FS is not set
++# CONFIG_SYSV_FS is not set
++# CONFIG_UFS_FS is not set
++
++#
++# Network File Systems
++#
++CONFIG_NFS_FS=y
++CONFIG_NFS_V3=y
++# CONFIG_NFS_V3_ACL is not set
++# CONFIG_NFS_V4 is not set
++# CONFIG_NFS_DIRECTIO is not set
++# 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
++# CONFIG_9P_FS is not set
++
++#
++# Partition Types
++#
++CONFIG_PARTITION_ADVANCED=y
++# CONFIG_ACORN_PARTITION is not set
++# CONFIG_OSF_PARTITION is not set
++# CONFIG_AMIGA_PARTITION is not set
++# CONFIG_ATARI_PARTITION is not set
++# CONFIG_MAC_PARTITION is not set
++CONFIG_MSDOS_PARTITION=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
++
++#
++# Native Language Support
++#
++CONFIG_NLS=y
++CONFIG_NLS_DEFAULT="iso8859-1"
++CONFIG_NLS_CODEPAGE_437=y
++# CONFIG_NLS_CODEPAGE_737 is not set
++# CONFIG_NLS_CODEPAGE_775 is not set
++# CONFIG_NLS_CODEPAGE_850 is not set
++# CONFIG_NLS_CODEPAGE_852 is not set
++# CONFIG_NLS_CODEPAGE_855 is not set
++# CONFIG_NLS_CODEPAGE_857 is not set
++# CONFIG_NLS_CODEPAGE_860 is not set
++# CONFIG_NLS_CODEPAGE_861 is not set
++# CONFIG_NLS_CODEPAGE_862 is not set
++# CONFIG_NLS_CODEPAGE_863 is not set
++# CONFIG_NLS_CODEPAGE_864 is not set
++# CONFIG_NLS_CODEPAGE_865 is not set
++# CONFIG_NLS_CODEPAGE_866 is not set
++# CONFIG_NLS_CODEPAGE_869 is not set
++# CONFIG_NLS_CODEPAGE_936 is not set
++# CONFIG_NLS_CODEPAGE_950 is not set
++# CONFIG_NLS_CODEPAGE_932 is not set
++# CONFIG_NLS_CODEPAGE_949 is not set
++# CONFIG_NLS_CODEPAGE_874 is not set
++# CONFIG_NLS_ISO8859_8 is not set
++# CONFIG_NLS_CODEPAGE_1250 is not set
++# CONFIG_NLS_CODEPAGE_1251 is not set
++# CONFIG_NLS_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
++
++#
++# Distributed Lock Manager
++#
++# CONFIG_DLM is not set
++
++#
++# Profiling support
++#
++# CONFIG_PROFILING is not set
++
++#
++# Kernel hacking
++#
++# CONFIG_PRINTK_TIME is not set
++CONFIG_ENABLE_MUST_CHECK=y
++# 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_LOG_BUF_SHIFT=14
++# CONFIG_DEBUG_BUGVERBOSE is not set
++CONFIG_FRAME_POINTER=y
++# CONFIG_DEBUG_USER is not set
++
++#
++# Security options
++#
++# CONFIG_KEYS is not set
++# CONFIG_SECURITY is not set
++
++#
++# Cryptographic options
++#
++CONFIG_CRYPTO=y
++CONFIG_CRYPTO_ALGAPI=m
++CONFIG_CRYPTO_BLKCIPHER=m
++CONFIG_CRYPTO_MANAGER=m
++# CONFIG_CRYPTO_HMAC is not set
++# CONFIG_CRYPTO_XCBC is not set
++# CONFIG_CRYPTO_NULL is not set
++# CONFIG_CRYPTO_MD4 is not set
++# CONFIG_CRYPTO_MD5 is not set
++# CONFIG_CRYPTO_SHA1 is not set
++# CONFIG_CRYPTO_SHA256 is not set
++# CONFIG_CRYPTO_SHA512 is not set
++# CONFIG_CRYPTO_WP512 is not set
++# CONFIG_CRYPTO_TGR192 is not set
++# CONFIG_CRYPTO_GF128MUL is not set
++CONFIG_CRYPTO_ECB=m
++CONFIG_CRYPTO_CBC=m
++CONFIG_CRYPTO_PCBC=m
++# CONFIG_CRYPTO_LRW is not set
++# CONFIG_CRYPTO_DES is not set
++# CONFIG_CRYPTO_FCRYPT is not set
++# CONFIG_CRYPTO_BLOWFISH is not set
++# CONFIG_CRYPTO_TWOFISH is not set
++# CONFIG_CRYPTO_SERPENT is not set
++# CONFIG_CRYPTO_AES is not set
++# CONFIG_CRYPTO_CAST5 is not set
++# CONFIG_CRYPTO_CAST6 is not set
++# CONFIG_CRYPTO_TEA is not set
++CONFIG_CRYPTO_ARC4=m
++# CONFIG_CRYPTO_KHAZAD is not set
++# CONFIG_CRYPTO_ANUBIS is not set
++# CONFIG_CRYPTO_DEFLATE is not set
++# CONFIG_CRYPTO_MICHAEL_MIC is not set
++# CONFIG_CRYPTO_CRC32C is not set
++# CONFIG_CRYPTO_CAMELLIA is not set
++# CONFIG_CRYPTO_TEST is not set
++
++#
++# Hardware crypto devices
++#
++
++#
++# Library routines
++#
++CONFIG_BITREVERSE=y
++# CONFIG_CRC_CCITT is not set
++# CONFIG_CRC16 is not set
++CONFIG_CRC32=y
++# CONFIG_LIBCRC32C is not set
++CONFIG_ZLIB_INFLATE=m
++CONFIG_ZLIB_DEFLATE=m
++CONFIG_PLIST=y
++CONFIG_HAS_IOMEM=y
++CONFIG_HAS_IOPORT=y
+diff --git a/arch/arm/configs/iop13xx_defconfig b/arch/arm/configs/iop13xx_defconfig
+index add03c9..988b4d1 100644
+--- a/arch/arm/configs/iop13xx_defconfig
++++ b/arch/arm/configs/iop13xx_defconfig
+@@ -1,7 +1,7 @@
  #
- # LED drivers
+ # Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.22
+-# Thu Jul 19 15:57:52 2007
++# Linux kernel version: 2.6.24-rc5
++# Wed Dec 12 16:11:03 2007
  #
-+CONFIG_LEDS_GPIO=m
+ CONFIG_ARM=y
+ CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+@@ -26,15 +26,11 @@ CONFIG_VECTORS_BASE=0xffff0000
+ CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
  
  #
- # LED Triggers
- #
-+CONFIG_LEDS_TRIGGERS=y
-+CONFIG_LEDS_TRIGGER_TIMER=m
-+CONFIG_LEDS_TRIGGER_HEARTBEAT=m
-+CONFIG_RTC_LIB=y
-+CONFIG_RTC_CLASS=y
-+CONFIG_RTC_HCTOSYS=y
-+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
-+# CONFIG_RTC_DEBUG is not set
- 
+-# Code maturity level options
++# General setup
  #
--# InfiniBand support
+ CONFIG_EXPERIMENTAL=y
+ CONFIG_BROKEN_ON_SMP=y
+ CONFIG_INIT_ENV_ARG_LIMIT=32
+-
+-#
+-# General setup
+-#
+ CONFIG_LOCALVERSION=""
+ # CONFIG_LOCALVERSION_AUTO is not set
+ CONFIG_SWAP=y
+@@ -45,10 +41,15 @@ CONFIG_BSD_PROCESS_ACCT=y
+ # CONFIG_BSD_PROCESS_ACCT_V3 is not set
+ # CONFIG_TASKSTATS is not set
+ # CONFIG_USER_NS is not set
++# CONFIG_PID_NS 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_FAIR_GROUP_SCHED=y
++CONFIG_FAIR_USER_SCHED=y
++# CONFIG_FAIR_CGROUP_SCHED is not set
+ CONFIG_SYSFS_DEPRECATED=y
+ # CONFIG_RELAY is not set
+ CONFIG_BLK_DEV_INITRD=y
+@@ -69,7 +70,6 @@ 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
+@@ -130,6 +130,7 @@ CONFIG_ARCH_IOP13XX=y
+ # 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_PNX4008 is not set
+ # CONFIG_ARCH_PXA is not set
+ # CONFIG_ARCH_RPC is not set
+@@ -151,9 +152,12 @@ CONFIG_MACH_IQ81340SC=y
+ CONFIG_MACH_IQ81340MC=y
+ 
+ #
+-# IOP13XX IMU Support
++# Boot options
++#
++
++#
++# Power management
+ #
+-# CONFIG_IOP_IMU is not set
+ CONFIG_PLAT_IOP=y
+ 
+ #
+@@ -185,10 +189,7 @@ CONFIG_PCI=y
+ CONFIG_PCI_SYSCALL=y
+ CONFIG_ARCH_SUPPORTS_MSI=y
+ # CONFIG_PCI_MSI is not set
+-
+-#
+-# PCCARD (PCMCIA/CardBus) support
+-#
++CONFIG_PCI_LEGACY=y
+ # CONFIG_PCCARD is not set
+ 
+ #
+@@ -207,6 +208,7 @@ CONFIG_FLATMEM_MANUAL=y
+ CONFIG_FLATMEM=y
+ CONFIG_FLAT_NODE_MEM_MAP=y
+ # CONFIG_SPARSEMEM_STATIC is not set
++# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
+ CONFIG_SPLIT_PTLOCK_CPUS=4096
+ # CONFIG_RESOURCES_64BIT is not set
+ CONFIG_ZONE_DMA_FLAG=1
+@@ -246,6 +248,7 @@ CONFIG_BINFMT_AOUT=y
+ # Power management options
+ #
+ # CONFIG_PM is not set
++CONFIG_SUSPEND_UP_POSSIBLE=y
+ 
+ #
+ # Networking
+@@ -285,6 +288,7 @@ CONFIG_IP_PNP_BOOTP=y
+ 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
+@@ -324,10 +328,6 @@ CONFIG_IPV6=y
+ # CONFIG_LAPB is not set
+ # CONFIG_ECONET is not set
+ # CONFIG_WAN_ROUTER is not set
+-
+-#
+-# QoS and/or fair queueing
+-#
+ # CONFIG_NET_SCHED is not set
+ 
+ #
+@@ -356,6 +356,7 @@ CONFIG_IPV6=y
+ #
+ # Generic Driver Options
+ #
++CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+ CONFIG_STANDALONE=y
+ CONFIG_PREVENT_FIRMWARE_BUILD=y
+ # CONFIG_FW_LOADER is not set
+@@ -383,6 +384,7 @@ CONFIG_MTD_BLOCK=y
+ # 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
+@@ -423,6 +425,7 @@ CONFIG_MTD_PHYSMAP_START=0xfa000000
+ CONFIG_MTD_PHYSMAP_LEN=0x0
+ CONFIG_MTD_PHYSMAP_BANKWIDTH=2
+ # CONFIG_MTD_ARM_INTEGRATOR is not set
++# CONFIG_MTD_INTEL_VR_NOR is not set
+ # CONFIG_MTD_PLATRAM is not set
+ 
+ #
+@@ -463,6 +466,11 @@ CONFIG_BLK_DEV_RAM_SIZE=8192
+ CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+ # CONFIG_CDROM_PKTCDVD is not set
+ # CONFIG_ATA_OVER_ETH is not set
++CONFIG_MISC_DEVICES=y
++# CONFIG_PHANTOM is not set
++# CONFIG_EEPROM_93CX6 is not set
++# CONFIG_SGI_IOC4 is not set
++# CONFIG_TIFM_CORE is not set
+ 
+ #
+ # SCSI device support
+@@ -499,12 +507,9 @@ CONFIG_SCSI_WAIT_SCAN=m
+ # CONFIG_SCSI_SPI_ATTRS is not set
+ # CONFIG_SCSI_FC_ATTRS is not set
+ CONFIG_SCSI_ISCSI_ATTRS=y
+-CONFIG_SCSI_SAS_ATTRS=y
+ # CONFIG_SCSI_SAS_LIBSAS is not set
+-
+-#
+-# SCSI low-level drivers
+-#
++# 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
+@@ -515,6 +520,7 @@ CONFIG_SCSI_SAS_ATTRS=y
+ # 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
+@@ -555,14 +561,8 @@ CONFIG_BLK_DEV_DM=y
+ # CONFIG_DM_ZERO is not set
+ # CONFIG_DM_MULTIPATH is not set
+ # CONFIG_DM_DELAY is not set
+-
+-#
+-# Fusion MPT device support
+-#
++# CONFIG_DM_UEVENT is not set
+ # CONFIG_FUSION is not set
+-# CONFIG_FUSION_SPI is not set
+-# CONFIG_FUSION_FC is not set
+-# CONFIG_FUSION_SAS is not set
+ 
+ #
+ # IEEE 1394 (FireWire) support
+@@ -577,6 +577,8 @@ CONFIG_NETDEVICES=y
+ # CONFIG_MACVLAN is not set
+ # CONFIG_EQUALIZER is not set
+ # CONFIG_TUN is not set
++# CONFIG_VETH is not set
++# CONFIG_IP1000 is not set
+ # CONFIG_ARCNET is not set
+ # CONFIG_NET_ETHERNET is not set
+ CONFIG_NETDEV_1000=y
+@@ -585,6 +587,7 @@ CONFIG_NETDEV_1000=y
+ CONFIG_E1000=y
+ CONFIG_E1000_NAPI=y
+ # CONFIG_E1000_DISABLE_PACKET_SPLIT is not set
++# CONFIG_E1000E is not set
+ # CONFIG_NS83820 is not set
+ # CONFIG_HAMACHI is not set
+ # CONFIG_YELLOWFIN is not set
+@@ -592,6 +595,7 @@ CONFIG_E1000_NAPI=y
+ # CONFIG_SIS190 is not set
+ # CONFIG_SKGE is not set
+ # CONFIG_SKY2 is not set
++# CONFIG_SK98LIN is not set
+ # CONFIG_VIA_VELOCITY is not set
+ # CONFIG_TIGON3 is not set
+ # CONFIG_BNX2 is not set
+@@ -600,11 +604,14 @@ CONFIG_E1000_NAPI=y
+ CONFIG_NETDEV_10000=y
+ # CONFIG_CHELSIO_T1 is not set
+ # CONFIG_CHELSIO_T3 is not set
++# CONFIG_IXGBE is not set
+ # CONFIG_IXGB is not set
+ # CONFIG_S2IO is not set
+ # CONFIG_MYRI10GE is not set
+ # CONFIG_NETXEN_NIC is not set
++# CONFIG_NIU is not set
+ # CONFIG_MLX4_CORE is not set
++# CONFIG_TEHUTI is not set
+ # CONFIG_TR is not set
+ 
+ #
+@@ -639,7 +646,6 @@ CONFIG_INPUT_MOUSEDEV=y
+ CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+ # CONFIG_INPUT_JOYDEV is not set
+-# CONFIG_INPUT_TSDEV is not set
+ # CONFIG_INPUT_EVDEV is not set
+ # CONFIG_INPUT_EVBUG is not set
+ 
+@@ -688,12 +694,10 @@ CONFIG_UNIX98_PTYS=y
+ CONFIG_LEGACY_PTYS=y
+ CONFIG_LEGACY_PTY_COUNT=256
+ # CONFIG_IPMI_HANDLER is not set
+-# CONFIG_WATCHDOG is not set
+ CONFIG_HW_RANDOM=y
+ # CONFIG_NVRAM is not set
+ # CONFIG_R3964 is not set
+ # CONFIG_APPLICOM is not set
+-# CONFIG_DRM is not set
+ # CONFIG_RAW_DRIVER is not set
+ # CONFIG_TCG_TPM is not set
+ CONFIG_DEVPORT=y
+@@ -758,9 +762,9 @@ CONFIG_I2C_IOP3XX=y
+ # CONFIG_SPI is not set
+ # CONFIG_SPI_MASTER 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_ABITUGURU is not set
+ # CONFIG_SENSORS_AD7418 is not set
+ # CONFIG_SENSORS_ADM1021 is not set
+ # CONFIG_SENSORS_ADM1025 is not set
+@@ -768,12 +772,13 @@ CONFIG_HWMON=y
+ # CONFIG_SENSORS_ADM1029 is not set
+ # CONFIG_SENSORS_ADM1031 is not set
+ # CONFIG_SENSORS_ADM9240 is not set
+-# CONFIG_SENSORS_ASB100 is not set
++# CONFIG_SENSORS_ADT7470 is not set
+ # CONFIG_SENSORS_ATXP1 is not set
+ # CONFIG_SENSORS_DS1621 is not set
++# CONFIG_SENSORS_I5K_AMB is not set
+ # CONFIG_SENSORS_F71805F is not set
+-# CONFIG_SENSORS_FSCHER is not set
+-# CONFIG_SENSORS_FSCPOS 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
+@@ -787,14 +792,17 @@ CONFIG_HWMON=y
+ # 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_SIS5595 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_THMC50 is not set
+ # CONFIG_SENSORS_VIA686A is not set
+ # CONFIG_SENSORS_VT1211 is not set
+ # CONFIG_SENSORS_VT8231 is not set
+@@ -806,29 +814,18 @@ CONFIG_HWMON=y
+ # CONFIG_SENSORS_W83627HF is not set
+ # CONFIG_SENSORS_W83627EHF is not set
+ # CONFIG_HWMON_DEBUG_CHIP is not set
+-CONFIG_MISC_DEVICES=y
+-# CONFIG_PHANTOM is not set
+-# CONFIG_EEPROM_93CX6 is not set
+-# CONFIG_SGI_IOC4 is not set
+-# CONFIG_TIFM_CORE is not set
+-
+-#
+-# Multifunction device drivers
+-#
+-# CONFIG_MFD_SM501 is not set
+-
+-#
+-# LED devices
+-#
+-# CONFIG_NEW_LEDS is not set
++# CONFIG_WATCHDOG is not set
+ 
+ #
+-# LED drivers
++# Sonics Silicon Backplane
+ #
++CONFIG_SSB_POSSIBLE=y
++# CONFIG_SSB is not set
+ 
+ #
+-# LED Triggers
++# Multifunction device drivers
+ #
++# CONFIG_MFD_SM501 is not set
+ 
+ #
+ # Multimedia devices
+@@ -840,14 +837,16 @@ CONFIG_DAB=y
+ #
+ # Graphics support
+ #
++# CONFIG_DRM is not set
++# 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
+-# CONFIG_VGASTATE is not set
+-# CONFIG_FB is not set
+ 
+ #
+ # Console display driver support
+@@ -862,6 +861,7 @@ CONFIG_DUMMY_CONSOLE=y
+ CONFIG_HID_SUPPORT=y
+ CONFIG_HID=y
+ # CONFIG_HID_DEBUG is not set
++# CONFIG_HIDRAW is not set
+ CONFIG_USB_SUPPORT=y
+ CONFIG_USB_ARCH_HAS_HCD=y
+ CONFIG_USB_ARCH_HAS_OHCI=y
+@@ -877,16 +877,15 @@ CONFIG_USB_ARCH_HAS_EHCI=y
+ #
+ # CONFIG_USB_GADGET is not set
+ # CONFIG_MMC is not set
+-
+-#
+-# Real Time Clock
+-#
++# CONFIG_NEW_LEDS is not set
+ CONFIG_RTC_LIB=y
+ # CONFIG_RTC_CLASS is not set
++CONFIG_DMADEVICES=y
+ 
+ #
+-# DMA Engine support
++# DMA Devices
+ #
++CONFIG_INTEL_IOP_ADMA=y
+ CONFIG_DMA_ENGINE=y
+ 
+ #
+@@ -895,12 +894,6 @@ CONFIG_DMA_ENGINE=y
+ # CONFIG_NET_DMA is not set
+ 
+ #
+-# DMA Devices
+-#
+-# CONFIG_INTEL_IOATDMA is not set
+-CONFIG_INTEL_IOP_ADMA=y
+-
+-#
+ # File systems
+ #
+ CONFIG_EXT2_FS=y
+@@ -912,7 +905,6 @@ CONFIG_EXT3_FS_XATTR=y
+ # CONFIG_EXT3_FS_SECURITY is not set
+ # CONFIG_EXT4DEV_FS is not set
+ CONFIG_JBD=y
+-# CONFIG_JBD_DEBUG is not set
+ CONFIG_FS_MBCACHE=y
+ # CONFIG_REISERFS_FS is not set
+ # CONFIG_JFS_FS is not set
+@@ -952,7 +944,6 @@ CONFIG_SYSFS=y
+ CONFIG_TMPFS=y
+ # CONFIG_TMPFS_POSIX_ACL is not set
+ # CONFIG_HUGETLB_PAGE is not set
+-CONFIG_RAMFS=y
+ # CONFIG_CONFIGFS_FS is not set
+ 
+ #
+@@ -969,10 +960,12 @@ CONFIG_ECRYPT_FS=y
+ 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
+@@ -981,10 +974,7 @@ CONFIG_CRAMFS=y
+ # CONFIG_QNX4FS_FS is not set
+ # CONFIG_SYSV_FS is not set
+ # CONFIG_UFS_FS is not set
+-
+-#
+-# Network File Systems
+-#
++CONFIG_NETWORK_FILESYSTEMS=y
+ CONFIG_NFS_FS=y
+ CONFIG_NFS_V3=y
+ # CONFIG_NFS_V3_ACL is not set
+@@ -1037,10 +1027,6 @@ CONFIG_MSDOS_PARTITION=y
+ # CONFIG_KARMA_PARTITION is not set
+ # CONFIG_EFI_PARTITION is not set
+ # CONFIG_SYSV68_PARTITION is not set
+-
+-#
+-# Native Language Support
+-#
+ CONFIG_NLS=y
+ CONFIG_NLS_DEFAULT="iso8859-1"
+ # CONFIG_NLS_CODEPAGE_437 is not set
+@@ -1081,21 +1067,16 @@ CONFIG_NLS_DEFAULT="iso8859-1"
+ # CONFIG_NLS_KOI8_R is not set
+ # CONFIG_NLS_KOI8_U is not set
+ # CONFIG_NLS_UTF8 is not set
+-
+-#
+-# Distributed Lock Manager
+-#
+ # CONFIG_DLM is not set
+-
+-#
+-# Profiling support
+-#
++CONFIG_INSTRUMENTATION=y
+ # CONFIG_PROFILING is not set
++# CONFIG_MARKERS is not set
+ 
+ #
+ # Kernel hacking
+ #
+ # CONFIG_PRINTK_TIME is not set
++CONFIG_ENABLE_WARN_DEPRECATED=y
+ CONFIG_ENABLE_MUST_CHECK=y
+ # CONFIG_MAGIC_SYSRQ is not set
+ # CONFIG_UNUSED_SYMBOLS is not set
+@@ -1104,6 +1085,7 @@ CONFIG_ENABLE_MUST_CHECK=y
+ # CONFIG_DEBUG_KERNEL is not set
+ CONFIG_DEBUG_BUGVERBOSE=y
+ CONFIG_FRAME_POINTER=y
++# CONFIG_SAMPLES is not set
+ CONFIG_DEBUG_USER=y
+ 
+ #
+@@ -1112,6 +1094,7 @@ CONFIG_DEBUG_USER=y
+ CONFIG_KEYS=y
+ CONFIG_KEYS_DEBUG_PROC_KEYS=y
+ # CONFIG_SECURITY is not set
++# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+ CONFIG_XOR_BLOCKS=y
+ CONFIG_ASYNC_CORE=y
+ CONFIG_ASYNC_MEMCPY=y
+@@ -1136,6 +1119,7 @@ CONFIG_CRYPTO_ECB=y
+ CONFIG_CRYPTO_CBC=y
+ CONFIG_CRYPTO_PCBC=m
+ CONFIG_CRYPTO_LRW=y
++# CONFIG_CRYPTO_XTS is not set
+ # CONFIG_CRYPTO_CRYPTD is not set
+ CONFIG_CRYPTO_DES=y
+ # CONFIG_CRYPTO_FCRYPT is not set
+@@ -1150,11 +1134,13 @@ CONFIG_CRYPTO_TEA=y
+ CONFIG_CRYPTO_ARC4=y
+ CONFIG_CRYPTO_KHAZAD=y
+ CONFIG_CRYPTO_ANUBIS=y
++# CONFIG_CRYPTO_SEED is not set
+ CONFIG_CRYPTO_DEFLATE=y
+ CONFIG_CRYPTO_MICHAEL_MIC=y
+ CONFIG_CRYPTO_CRC32C=y
+ # CONFIG_CRYPTO_CAMELLIA is not set
+ # CONFIG_CRYPTO_TEST is not set
++# CONFIG_CRYPTO_AUTHENC is not set
+ CONFIG_CRYPTO_HW=y
+ 
+ #
+diff --git a/arch/arm/configs/iop32x_defconfig b/arch/arm/configs/iop32x_defconfig
+index 027aef2..83f40d4 100644
+--- a/arch/arm/configs/iop32x_defconfig
++++ b/arch/arm/configs/iop32x_defconfig
+@@ -1,7 +1,7 @@
+ #
+ # Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.22
+-# Thu Jul 19 16:00:36 2007
++# Linux kernel version: 2.6.24-rc5
++# Wed Dec 12 15:49:08 2007
+ #
+ CONFIG_ARM=y
+ CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+@@ -26,15 +26,11 @@ CONFIG_VECTORS_BASE=0xffff0000
+ CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+ 
+ #
+-# Code maturity level options
++# General setup
+ #
+ CONFIG_EXPERIMENTAL=y
+ CONFIG_BROKEN_ON_SMP=y
+ CONFIG_INIT_ENV_ARG_LIMIT=32
+-
+-#
+-# General setup
+-#
+ CONFIG_LOCALVERSION=""
+ CONFIG_LOCALVERSION_AUTO=y
+ CONFIG_SWAP=y
+@@ -45,9 +41,14 @@ CONFIG_BSD_PROCESS_ACCT=y
+ # CONFIG_BSD_PROCESS_ACCT_V3 is not set
+ # CONFIG_TASKSTATS is not set
+ # CONFIG_USER_NS is not set
++# CONFIG_PID_NS is not set
+ # CONFIG_AUDIT is not set
+ # CONFIG_IKCONFIG is not set
+ CONFIG_LOG_BUF_SHIFT=14
++# CONFIG_CGROUPS is not set
++CONFIG_FAIR_GROUP_SCHED=y
++CONFIG_FAIR_USER_SCHED=y
++# CONFIG_FAIR_CGROUP_SCHED is not set
+ CONFIG_SYSFS_DEPRECATED=y
+ # CONFIG_RELAY is not set
+ CONFIG_BLK_DEV_INITRD=y
+@@ -69,7 +70,6 @@ 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
+@@ -130,6 +130,7 @@ CONFIG_ARCH_IOP32X=y
+ # 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_PNX4008 is not set
+ # CONFIG_ARCH_PXA is not set
+ # CONFIG_ARCH_RPC is not set
+@@ -153,6 +154,15 @@ CONFIG_ARCH_IQ80321=y
+ CONFIG_ARCH_IQ31244=y
+ CONFIG_MACH_N2100=y
+ CONFIG_IOP3XX_ATU=y
++# CONFIG_MACH_EM7210 is not set
++
++#
++# Boot options
++#
++
++#
++# Power management
++#
+ CONFIG_PLAT_IOP=y
+ 
+ #
+@@ -182,11 +192,8 @@ CONFIG_XSCALE_PMU=y
+ CONFIG_PCI=y
+ CONFIG_PCI_SYSCALL=y
+ # CONFIG_ARCH_SUPPORTS_MSI is not set
++CONFIG_PCI_LEGACY=y
+ # CONFIG_PCI_DEBUG is not set
+-
+-#
+-# PCCARD (PCMCIA/CardBus) support
+-#
+ # CONFIG_PCCARD is not set
+ 
+ #
+@@ -205,6 +212,7 @@ CONFIG_FLATMEM_MANUAL=y
+ CONFIG_FLATMEM=y
+ CONFIG_FLAT_NODE_MEM_MAP=y
+ # CONFIG_SPARSEMEM_STATIC is not set
++# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
+ CONFIG_SPLIT_PTLOCK_CPUS=4096
+ # CONFIG_RESOURCES_64BIT is not set
+ CONFIG_ZONE_DMA_FLAG=1
+@@ -244,6 +252,7 @@ CONFIG_BINFMT_AOUT=y
+ # Power management options
+ #
+ # CONFIG_PM is not set
++CONFIG_SUSPEND_UP_POSSIBLE=y
+ 
+ #
+ # Networking
+@@ -282,6 +291,7 @@ CONFIG_IP_PNP_BOOTP=y
+ 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
+@@ -321,10 +331,6 @@ CONFIG_IPV6=y
+ # CONFIG_LAPB is not set
+ # CONFIG_ECONET is not set
+ # CONFIG_WAN_ROUTER is not set
+-
+-#
+-# QoS and/or fair queueing
+-#
+ # CONFIG_NET_SCHED is not set
+ 
+ #
+@@ -353,6 +359,7 @@ CONFIG_IPV6=y
+ #
+ # Generic Driver Options
+ #
++CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+ CONFIG_STANDALONE=y
+ CONFIG_PREVENT_FIRMWARE_BUILD=y
+ # CONFIG_FW_LOADER is not set
+@@ -382,6 +389,7 @@ CONFIG_MTD_BLOCK=y
+ # 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
+@@ -417,6 +425,7 @@ CONFIG_MTD_PHYSMAP_START=0x0
+ CONFIG_MTD_PHYSMAP_LEN=0x0
+ CONFIG_MTD_PHYSMAP_BANKWIDTH=1
+ # CONFIG_MTD_ARM_INTEGRATOR is not set
++# CONFIG_MTD_INTEL_VR_NOR is not set
+ # CONFIG_MTD_PLATRAM is not set
+ 
+ #
+@@ -459,6 +468,11 @@ CONFIG_BLK_DEV_RAM_SIZE=8192
+ CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+ # CONFIG_CDROM_PKTCDVD is not set
+ # CONFIG_ATA_OVER_ETH is not set
++CONFIG_MISC_DEVICES=y
++# CONFIG_PHANTOM is not set
++# CONFIG_EEPROM_93CX6 is not set
++# CONFIG_SGI_IOC4 is not set
++# CONFIG_TIFM_CORE is not set
+ # CONFIG_IDE is not set
+ 
+ #
+@@ -496,12 +510,9 @@ CONFIG_SCSI_WAIT_SCAN=m
+ # CONFIG_SCSI_SPI_ATTRS is not set
+ # CONFIG_SCSI_FC_ATTRS is not set
+ # CONFIG_SCSI_ISCSI_ATTRS is not set
+-# CONFIG_SCSI_SAS_ATTRS is not set
+ # CONFIG_SCSI_SAS_LIBSAS is not set
+-
+-#
+-# SCSI low-level drivers
+-#
++# 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
+@@ -512,6 +523,7 @@ CONFIG_SCSI_WAIT_SCAN=m
+ # 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
+@@ -576,6 +588,7 @@ CONFIG_SATA_VITESSE=y
+ # CONFIG_PATA_OLDPIIX is not set
+ # CONFIG_PATA_NETCELL 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_PDC_OLD is not set
+@@ -606,14 +619,8 @@ CONFIG_BLK_DEV_DM=y
+ # CONFIG_DM_ZERO is not set
+ # CONFIG_DM_MULTIPATH is not set
+ # CONFIG_DM_DELAY is not set
+-
+-#
+-# Fusion MPT device support
+-#
++# CONFIG_DM_UEVENT is not set
+ # CONFIG_FUSION is not set
+-# CONFIG_FUSION_SPI is not set
+-# CONFIG_FUSION_FC is not set
+-# CONFIG_FUSION_SAS is not set
+ 
+ #
+ # IEEE 1394 (FireWire) support
+@@ -628,6 +635,8 @@ CONFIG_NETDEVICES=y
+ # CONFIG_MACVLAN is not set
+ # CONFIG_EQUALIZER is not set
+ # CONFIG_TUN is not set
++# CONFIG_VETH is not set
++# CONFIG_IP1000 is not set
+ # CONFIG_ARCNET is not set
+ # CONFIG_PHYLIB is not set
+ CONFIG_NET_ETHERNET=y
+@@ -641,13 +650,16 @@ CONFIG_MII=y
+ # CONFIG_DM9000 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_DGRS is not set
+ # CONFIG_EEPRO100 is not set
+ CONFIG_E100=y
+ # CONFIG_FEALNX is not set
+@@ -667,6 +679,7 @@ CONFIG_NETDEV_1000=y
+ CONFIG_E1000=y
+ CONFIG_E1000_NAPI=y
+ # CONFIG_E1000_DISABLE_PACKET_SPLIT is not set
++# CONFIG_E1000E is not set
+ # CONFIG_NS83820 is not set
+ # CONFIG_HAMACHI is not set
+ # CONFIG_YELLOWFIN is not set
+@@ -675,6 +688,7 @@ CONFIG_R8169=y
+ # CONFIG_SIS190 is not set
+ # CONFIG_SKGE is not set
+ # CONFIG_SKY2 is not set
++# CONFIG_SK98LIN is not set
+ # CONFIG_VIA_VELOCITY is not set
+ # CONFIG_TIGON3 is not set
+ # CONFIG_BNX2 is not set
+@@ -683,11 +697,14 @@ CONFIG_R8169=y
+ CONFIG_NETDEV_10000=y
+ # CONFIG_CHELSIO_T1 is not set
+ # CONFIG_CHELSIO_T3 is not set
++# CONFIG_IXGBE is not set
+ # CONFIG_IXGB is not set
+ # CONFIG_S2IO is not set
+ # CONFIG_MYRI10GE is not set
+ # CONFIG_NETXEN_NIC is not set
++# CONFIG_NIU is not set
+ # CONFIG_MLX4_CORE is not set
++# CONFIG_TEHUTI is not set
+ # CONFIG_TR is not set
+ 
+ #
+@@ -703,7 +720,6 @@ CONFIG_NETDEV_10000=y
+ # CONFIG_USB_KAWETH is not set
+ # CONFIG_USB_PEGASUS is not set
+ # CONFIG_USB_RTL8150 is not set
+-# CONFIG_USB_USBNET_MII is not set
+ # CONFIG_USB_USBNET is not set
+ # CONFIG_WAN is not set
+ # CONFIG_FDDI is not set
+@@ -732,7 +748,6 @@ CONFIG_INPUT_MOUSEDEV=y
+ CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+ # CONFIG_INPUT_JOYDEV is not set
+-# CONFIG_INPUT_TSDEV is not set
+ # CONFIG_INPUT_EVDEV is not set
+ # CONFIG_INPUT_EVBUG is not set
+ 
+@@ -781,12 +796,10 @@ CONFIG_UNIX98_PTYS=y
+ CONFIG_LEGACY_PTYS=y
+ CONFIG_LEGACY_PTY_COUNT=256
+ # CONFIG_IPMI_HANDLER is not set
+-# CONFIG_WATCHDOG is not set
+ CONFIG_HW_RANDOM=y
+ # CONFIG_NVRAM is not set
+ # CONFIG_R3964 is not set
+ # CONFIG_APPLICOM is not set
+-# CONFIG_DRM is not set
+ # CONFIG_RAW_DRIVER is not set
+ # CONFIG_TCG_TPM is not set
+ CONFIG_DEVPORT=y
+@@ -852,9 +865,9 @@ CONFIG_I2C_IOP3XX=y
+ # CONFIG_SPI is not set
+ # CONFIG_SPI_MASTER 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_ABITUGURU is not set
+ # CONFIG_SENSORS_AD7418 is not set
+ # CONFIG_SENSORS_ADM1021 is not set
+ # CONFIG_SENSORS_ADM1025 is not set
+@@ -862,12 +875,13 @@ CONFIG_HWMON=y
+ # CONFIG_SENSORS_ADM1029 is not set
+ # CONFIG_SENSORS_ADM1031 is not set
+ # CONFIG_SENSORS_ADM9240 is not set
+-# CONFIG_SENSORS_ASB100 is not set
++# CONFIG_SENSORS_ADT7470 is not set
+ # CONFIG_SENSORS_ATXP1 is not set
+ # CONFIG_SENSORS_DS1621 is not set
++# CONFIG_SENSORS_I5K_AMB is not set
+ # CONFIG_SENSORS_F71805F is not set
+-# CONFIG_SENSORS_FSCHER is not set
+-# CONFIG_SENSORS_FSCPOS 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
+@@ -881,14 +895,17 @@ CONFIG_HWMON=y
+ # 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_SIS5595 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_THMC50 is not set
+ # CONFIG_SENSORS_VIA686A is not set
+ # CONFIG_SENSORS_VT1211 is not set
+ # CONFIG_SENSORS_VT8231 is not set
+@@ -900,29 +917,18 @@ CONFIG_HWMON=y
+ # CONFIG_SENSORS_W83627HF is not set
+ # CONFIG_SENSORS_W83627EHF is not set
+ # CONFIG_HWMON_DEBUG_CHIP is not set
+-CONFIG_MISC_DEVICES=y
+-# CONFIG_PHANTOM is not set
+-# CONFIG_EEPROM_93CX6 is not set
+-# CONFIG_SGI_IOC4 is not set
+-# CONFIG_TIFM_CORE is not set
+-
+-#
+-# Multifunction device drivers
+-#
+-# CONFIG_MFD_SM501 is not set
+-
+-#
+-# LED devices
+-#
+-# CONFIG_NEW_LEDS is not set
++# CONFIG_WATCHDOG is not set
+ 
+ #
+-# LED drivers
++# Sonics Silicon Backplane
+ #
++CONFIG_SSB_POSSIBLE=y
++# CONFIG_SSB is not set
+ 
+ #
+-# LED Triggers
++# Multifunction device drivers
+ #
++# CONFIG_MFD_SM501 is not set
+ 
+ #
+ # Multimedia devices
+@@ -935,14 +941,16 @@ CONFIG_DAB=y
+ #
+ # Graphics support
+ #
++# CONFIG_DRM is not set
++# 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
+-# CONFIG_VGASTATE is not set
+-# CONFIG_FB is not set
+ 
+ #
+ # Console display driver support
+@@ -957,6 +965,7 @@ CONFIG_DUMMY_CONSOLE=y
+ CONFIG_HID_SUPPORT=y
+ CONFIG_HID=y
+ # CONFIG_HID_DEBUG is not set
++# CONFIG_HIDRAW is not set
+ 
+ #
+ # USB Input Devices
+@@ -1013,6 +1022,7 @@ 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
+@@ -1070,28 +1080,66 @@ CONFIG_USB_MON=y
+ #
+ # CONFIG_USB_GADGET 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
+ 
+ #
+-# Real Time Clock
 +# RTC interfaces
  #
+-CONFIG_RTC_LIB=y
+-# CONFIG_RTC_CLASS is not set
 +CONFIG_RTC_INTF_SYSFS=y
 +CONFIG_RTC_INTF_PROC=y
 +CONFIG_RTC_INTF_DEV=y
@@ -8588,14 +10871,15 @@
 +# CONFIG_RTC_DRV_TEST is not set
  
  #
--# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
+-# DMA Engine support
 +# I2C RTC drivers
  #
+-CONFIG_DMA_ENGINE=y
 +# 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_RS5C372=y
 +# CONFIG_RTC_DRV_ISL1208 is not set
 +# CONFIG_RTC_DRV_X1205 is not set
 +# CONFIG_RTC_DRV_PCF8563 is not set
@@ -8603,77 +10887,62 @@
 +# CONFIG_RTC_DRV_M41T80 is not set
  
  #
--# Real Time Clock
+-# DMA Clients
 +# SPI RTC drivers
  #
--# CONFIG_RTC_CLASS is not set
-+# CONFIG_RTC_DRV_RS5C348 is not set
-+# CONFIG_RTC_DRV_MAX6902 is not set
- 
- #
--# DMA Engine support
+-CONFIG_NET_DMA=y
++
++#
 +# Platform RTC drivers
- #
--# CONFIG_DMA_ENGINE is not set
++#
++# CONFIG_RTC_DRV_CMOS is not set
 +# CONFIG_RTC_DRV_DS1553 is not set
 +# CONFIG_RTC_DRV_STK17TA8 is not set
 +# CONFIG_RTC_DRV_DS1742 is not set
 +# CONFIG_RTC_DRV_M48T86 is not set
 +# CONFIG_RTC_DRV_M48T59 is not set
 +# CONFIG_RTC_DRV_V3020 is not set
- 
- #
--# DMA Clients
++
++#
 +# on-CPU RTC drivers
- #
-+CONFIG_RTC_DRV_AT32AP700X=y
++#
++CONFIG_DMADEVICES=y
  
  #
--# DMA Devices
-+# Userspace I/O
+ # DMA Devices
  #
-+# CONFIG_UIO is not set
+-# CONFIG_INTEL_IOATDMA is not set
+ CONFIG_INTEL_IOP_ADMA=y
++CONFIG_DMA_ENGINE=y
++
++#
++# DMA Clients
++#
++CONFIG_NET_DMA=y
  
  #
  # File systems
-@@ -593,8 +886,11 @@ CONFIG_UNIX98_PTYS=y
- CONFIG_EXT2_FS=m
- # CONFIG_EXT2_FS_XATTR is not set
- # CONFIG_EXT2_FS_XIP is not set
--# CONFIG_EXT3_FS is not set
-+CONFIG_EXT3_FS=m
-+# CONFIG_EXT3_FS_XATTR is not set
+@@ -1105,7 +1153,6 @@ CONFIG_EXT3_FS_XATTR=y
+ # CONFIG_EXT3_FS_SECURITY is not set
  # CONFIG_EXT4DEV_FS is not set
-+CONFIG_JBD=m
-+# CONFIG_JBD_DEBUG is not set
+ CONFIG_JBD=y
+-# CONFIG_JBD_DEBUG is not set
+ CONFIG_FS_MBCACHE=y
  # CONFIG_REISERFS_FS is not set
  # CONFIG_JFS_FS is not set
- # CONFIG_FS_POSIX_ACL is not set
-@@ -609,7 +905,7 @@ CONFIG_INOTIFY_USER=y
- # CONFIG_DNOTIFY is not set
- # CONFIG_AUTOFS_FS is not set
- # CONFIG_AUTOFS4_FS is not set
--# CONFIG_FUSE_FS is not set
-+CONFIG_FUSE_FS=m
- 
- #
- # CD-ROM/DVD Filesystems
-@@ -637,8 +933,7 @@ CONFIG_SYSFS=y
+@@ -1145,7 +1192,6 @@ CONFIG_SYSFS=y
  CONFIG_TMPFS=y
  # CONFIG_TMPFS_POSIX_ACL is not set
  # CONFIG_HUGETLB_PAGE is not set
 -CONFIG_RAMFS=y
--CONFIG_CONFIGFS_FS=m
-+# CONFIG_CONFIGFS_FS is not set
+ # CONFIG_CONFIGFS_FS is not set
  
  #
- # Miscellaneous filesystems
-@@ -652,11 +947,12 @@ CONFIG_CONFIGFS_FS=m
- # CONFIG_EFS_FS is not set
+@@ -1162,10 +1208,12 @@ CONFIG_ECRYPT_FS=y
  CONFIG_JFFS2_FS=y
  CONFIG_JFFS2_FS_DEBUG=0
--CONFIG_JFFS2_FS_WRITEBUFFER=y
-+# CONFIG_JFFS2_FS_WRITEBUFFER is not set
+ 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
@@ -8681,8 +10950,8 @@
 +# CONFIG_JFFS2_LZO is not set
  CONFIG_JFFS2_RTIME=y
  # CONFIG_JFFS2_RUBIN is not set
- # CONFIG_CRAMFS is not set
-@@ -665,10 +961,7 @@ CONFIG_JFFS2_RTIME=y
+ CONFIG_CRAMFS=y
+@@ -1174,10 +1222,7 @@ CONFIG_CRAMFS=y
  # CONFIG_QNX4FS_FS is not set
  # CONFIG_SYSV_FS is not set
  # CONFIG_UFS_FS is not set
@@ -8694,162 +10963,582 @@
  CONFIG_NFS_FS=y
  CONFIG_NFS_V3=y
  # CONFIG_NFS_V3_ACL is not set
-@@ -688,17 +981,12 @@ CONFIG_SUNRPC=y
- # CONFIG_NCP_FS is not set
- # CONFIG_CODA_FS is not set
- # CONFIG_AFS_FS is not set
--# CONFIG_9P_FS is not set
- 
- #
- # Partition Types
- #
- # CONFIG_PARTITION_ADVANCED is not set
- CONFIG_MSDOS_PARTITION=y
+@@ -1224,26 +1269,17 @@ CONFIG_MSDOS_PARTITION=y
+ # CONFIG_KARMA_PARTITION is not set
+ # CONFIG_EFI_PARTITION is not set
+ # CONFIG_SYSV68_PARTITION is not set
 -
 -#
 -# Native Language Support
 -#
- CONFIG_NLS=m
- CONFIG_NLS_DEFAULT="iso8859-1"
- CONFIG_NLS_CODEPAGE_437=m
-@@ -739,17 +1027,18 @@ CONFIG_NLS_ISO8859_1=m
- # CONFIG_NLS_KOI8_R is not set
- # CONFIG_NLS_KOI8_U is not set
- CONFIG_NLS_UTF8=m
+ # CONFIG_NLS is not set
 -
 -#
 -# Distributed Lock Manager
 -#
  # CONFIG_DLM is not set
+-
+-#
+-# Profiling support
+-#
 +CONFIG_INSTRUMENTATION=y
-+CONFIG_PROFILING=y
-+CONFIG_OPROFILE=m
-+CONFIG_KPROBES=y
+ # CONFIG_PROFILING is not set
 +# CONFIG_MARKERS is not set
  
  #
  # Kernel hacking
  #
--CONFIG_TRACE_IRQFLAGS_SUPPORT=y
  # CONFIG_PRINTK_TIME is not set
 +CONFIG_ENABLE_WARN_DEPRECATED=y
  CONFIG_ENABLE_MUST_CHECK=y
  CONFIG_MAGIC_SYSRQ=y
  # CONFIG_UNUSED_SYMBOLS is not set
-@@ -758,12 +1047,17 @@ CONFIG_DEBUG_FS=y
- CONFIG_DEBUG_KERNEL=y
- # CONFIG_DEBUG_SHIRQ is not set
- CONFIG_DETECT_SOFTLOCKUP=y
-+CONFIG_SCHED_DEBUG=y
- # CONFIG_SCHEDSTATS is not set
- # CONFIG_TIMER_STATS is not set
-+# CONFIG_SLUB_DEBUG_ON 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
-@@ -771,22 +1065,63 @@ CONFIG_DEBUG_BUGVERBOSE=y
+@@ -1270,10 +1306,13 @@ CONFIG_DEBUG_BUGVERBOSE=y
  # CONFIG_DEBUG_INFO is not set
  # CONFIG_DEBUG_VM is not set
  # CONFIG_DEBUG_LIST is not set
 +# CONFIG_DEBUG_SG is not set
  CONFIG_FRAME_POINTER=y
- CONFIG_FORCED_INLINING=y
+ # CONFIG_FORCED_INLINING is not set
 +# CONFIG_BOOT_PRINTK_DELAY is not set
  # CONFIG_RCU_TORTURE_TEST is not set
-+# CONFIG_LKDTM is not set
  # CONFIG_FAULT_INJECTION is not set
--# CONFIG_KPROBES is not set
 +# CONFIG_SAMPLES is not set
+ CONFIG_DEBUG_USER=y
+ # CONFIG_DEBUG_ERRORS is not set
+ CONFIG_DEBUG_LL=y
+@@ -1285,6 +1324,7 @@ CONFIG_DEBUG_LL=y
+ CONFIG_KEYS=y
+ CONFIG_KEYS_DEBUG_PROC_KEYS=y
+ # CONFIG_SECURITY is not set
++# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+ CONFIG_XOR_BLOCKS=y
+ CONFIG_ASYNC_CORE=y
+ CONFIG_ASYNC_MEMCPY=y
+@@ -1309,6 +1349,7 @@ CONFIG_CRYPTO_ECB=y
+ CONFIG_CRYPTO_CBC=y
+ CONFIG_CRYPTO_PCBC=m
+ CONFIG_CRYPTO_LRW=y
++# CONFIG_CRYPTO_XTS is not set
+ # CONFIG_CRYPTO_CRYPTD is not set
+ CONFIG_CRYPTO_DES=y
+ # CONFIG_CRYPTO_FCRYPT is not set
+@@ -1323,11 +1364,13 @@ CONFIG_CRYPTO_TEA=y
+ CONFIG_CRYPTO_ARC4=y
+ CONFIG_CRYPTO_KHAZAD=y
+ CONFIG_CRYPTO_ANUBIS=y
++# CONFIG_CRYPTO_SEED is not set
+ CONFIG_CRYPTO_DEFLATE=y
+ CONFIG_CRYPTO_MICHAEL_MIC=y
+ CONFIG_CRYPTO_CRC32C=y
+ # CONFIG_CRYPTO_CAMELLIA is not set
+ # CONFIG_CRYPTO_TEST is not set
++# CONFIG_CRYPTO_AUTHENC is not set
+ CONFIG_CRYPTO_HW=y
  
  #
- # Security options
+diff --git a/arch/arm/configs/iop33x_defconfig b/arch/arm/configs/iop33x_defconfig
+index 721ee64..917afb5 100644
+--- a/arch/arm/configs/iop33x_defconfig
++++ b/arch/arm/configs/iop33x_defconfig
+@@ -1,7 +1,7 @@
  #
- # CONFIG_KEYS is not set
- # CONFIG_SECURITY is not set
+ # Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.22
+-# Thu Jul 19 16:05:59 2007
++# Linux kernel version: 2.6.24-rc5
++# Wed Dec 12 16:11:27 2007
+ #
+ CONFIG_ARM=y
+ CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+@@ -26,15 +26,11 @@ CONFIG_VECTORS_BASE=0xffff0000
+ CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+ 
+ #
+-# Code maturity level options
++# General setup
+ #
+ CONFIG_EXPERIMENTAL=y
+ CONFIG_BROKEN_ON_SMP=y
+ CONFIG_INIT_ENV_ARG_LIMIT=32
 -
 -#
--# Cryptographic options
+-# General setup
 -#
--# CONFIG_CRYPTO is not set
-+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
-+CONFIG_CRYPTO=y
-+CONFIG_CRYPTO_ALGAPI=m
-+CONFIG_CRYPTO_BLKCIPHER=m
-+CONFIG_CRYPTO_HASH=m
-+CONFIG_CRYPTO_MANAGER=m
-+CONFIG_CRYPTO_HMAC=m
-+# CONFIG_CRYPTO_XCBC is not set
-+# CONFIG_CRYPTO_NULL is not set
-+# CONFIG_CRYPTO_MD4 is not set
-+CONFIG_CRYPTO_MD5=m
-+CONFIG_CRYPTO_SHA1=m
-+# CONFIG_CRYPTO_SHA256 is not set
-+# CONFIG_CRYPTO_SHA512 is not set
-+# CONFIG_CRYPTO_WP512 is not set
-+# CONFIG_CRYPTO_TGR192 is not set
-+# CONFIG_CRYPTO_GF128MUL is not set
-+# CONFIG_CRYPTO_ECB is not set
-+CONFIG_CRYPTO_CBC=m
-+# CONFIG_CRYPTO_PCBC is not set
-+# CONFIG_CRYPTO_LRW is not set
-+# CONFIG_CRYPTO_XTS is not set
-+# CONFIG_CRYPTO_CRYPTD is not set
-+CONFIG_CRYPTO_DES=m
-+# CONFIG_CRYPTO_FCRYPT is not set
-+# CONFIG_CRYPTO_BLOWFISH is not set
-+# CONFIG_CRYPTO_TWOFISH is not set
-+# CONFIG_CRYPTO_SERPENT is not set
-+# CONFIG_CRYPTO_AES is not set
-+# CONFIG_CRYPTO_CAST5 is not set
-+# CONFIG_CRYPTO_CAST6 is not set
-+# CONFIG_CRYPTO_TEA is not set
-+# CONFIG_CRYPTO_ARC4 is not set
-+# CONFIG_CRYPTO_KHAZAD is not set
-+# CONFIG_CRYPTO_ANUBIS is not set
-+# CONFIG_CRYPTO_SEED is not set
-+CONFIG_CRYPTO_DEFLATE=m
-+# CONFIG_CRYPTO_MICHAEL_MIC is not set
-+# CONFIG_CRYPTO_CRC32C is not set
-+# CONFIG_CRYPTO_CAMELLIA is not set
-+# CONFIG_CRYPTO_TEST is not set
-+# CONFIG_CRYPTO_AUTHENC is not set
-+# CONFIG_CRYPTO_HW is not set
+ CONFIG_LOCALVERSION=""
+ CONFIG_LOCALVERSION_AUTO=y
+ CONFIG_SWAP=y
+@@ -45,9 +41,14 @@ CONFIG_BSD_PROCESS_ACCT=y
+ # CONFIG_BSD_PROCESS_ACCT_V3 is not set
+ # CONFIG_TASKSTATS is not set
+ # CONFIG_USER_NS is not set
++# CONFIG_PID_NS is not set
+ # CONFIG_AUDIT is not set
+ # CONFIG_IKCONFIG is not set
+ CONFIG_LOG_BUF_SHIFT=14
++# CONFIG_CGROUPS is not set
++CONFIG_FAIR_GROUP_SCHED=y
++CONFIG_FAIR_USER_SCHED=y
++# CONFIG_FAIR_CGROUP_SCHED is not set
+ CONFIG_SYSFS_DEPRECATED=y
+ # CONFIG_RELAY is not set
+ CONFIG_BLK_DEV_INITRD=y
+@@ -69,7 +70,6 @@ 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
+@@ -130,6 +130,7 @@ CONFIG_ARCH_IOP33X=y
+ # 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_PNX4008 is not set
+ # CONFIG_ARCH_PXA is not set
+ # CONFIG_ARCH_RPC is not set
+@@ -150,6 +151,14 @@ CONFIG_IOP3XX_ATU=y
+ #
+ CONFIG_ARCH_IQ80331=y
+ CONFIG_MACH_IQ80332=y
++
++#
++# Boot options
++#
++
++#
++# Power management
++#
+ CONFIG_PLAT_IOP=y
  
  #
- # Library routines
-@@ -794,10 +1129,10 @@ CONFIG_FORCED_INLINING=y
- CONFIG_BITREVERSE=y
- CONFIG_CRC_CCITT=m
- # CONFIG_CRC16 is not set
--# CONFIG_CRC_ITU_T is not set
-+CONFIG_CRC_ITU_T=m
- CONFIG_CRC32=y
-+CONFIG_CRC7=m
- # CONFIG_LIBCRC32C is not set
--CONFIG_AUDIT_GENERIC=y
- CONFIG_ZLIB_INFLATE=y
- CONFIG_ZLIB_DEFLATE=y
- CONFIG_PLIST=y
-diff --git a/arch/avr32/configs/atstk1003_defconfig b/arch/avr32/configs/atstk1003_defconfig
+@@ -179,11 +188,8 @@ CONFIG_XSCALE_PMU=y
+ CONFIG_PCI=y
+ CONFIG_PCI_SYSCALL=y
+ # CONFIG_ARCH_SUPPORTS_MSI is not set
++CONFIG_PCI_LEGACY=y
+ # CONFIG_PCI_DEBUG is not set
+-
+-#
+-# PCCARD (PCMCIA/CardBus) support
+-#
+ # CONFIG_PCCARD is not set
+ 
+ #
+@@ -202,6 +208,7 @@ CONFIG_FLATMEM_MANUAL=y
+ CONFIG_FLATMEM=y
+ CONFIG_FLAT_NODE_MEM_MAP=y
+ # CONFIG_SPARSEMEM_STATIC is not set
++# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
+ CONFIG_SPLIT_PTLOCK_CPUS=4096
+ # CONFIG_RESOURCES_64BIT is not set
+ CONFIG_ZONE_DMA_FLAG=1
+@@ -241,6 +248,7 @@ CONFIG_BINFMT_AOUT=y
+ # Power management options
+ #
+ # CONFIG_PM is not set
++CONFIG_SUSPEND_UP_POSSIBLE=y
+ 
+ #
+ # Networking
+@@ -279,6 +287,7 @@ CONFIG_IP_PNP_BOOTP=y
+ 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
+@@ -318,10 +327,6 @@ CONFIG_IPV6=y
+ # CONFIG_LAPB is not set
+ # CONFIG_ECONET is not set
+ # CONFIG_WAN_ROUTER is not set
+-
+-#
+-# QoS and/or fair queueing
+-#
+ # CONFIG_NET_SCHED is not set
+ 
+ #
+@@ -350,6 +355,7 @@ CONFIG_IPV6=y
+ #
+ # Generic Driver Options
+ #
++CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+ CONFIG_STANDALONE=y
+ CONFIG_PREVENT_FIRMWARE_BUILD=y
+ # CONFIG_FW_LOADER is not set
+@@ -379,6 +385,7 @@ CONFIG_MTD_BLOCK=y
+ # 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
+@@ -419,6 +426,7 @@ CONFIG_MTD_PHYSMAP_START=0x0
+ CONFIG_MTD_PHYSMAP_LEN=0x0
+ CONFIG_MTD_PHYSMAP_BANKWIDTH=1
+ # CONFIG_MTD_ARM_INTEGRATOR is not set
++# CONFIG_MTD_INTEL_VR_NOR is not set
+ # CONFIG_MTD_PLATRAM is not set
+ 
+ #
+@@ -459,6 +467,11 @@ CONFIG_BLK_DEV_RAM_SIZE=8192
+ CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+ # CONFIG_CDROM_PKTCDVD is not set
+ # CONFIG_ATA_OVER_ETH is not set
++CONFIG_MISC_DEVICES=y
++# CONFIG_PHANTOM is not set
++# CONFIG_EEPROM_93CX6 is not set
++# CONFIG_SGI_IOC4 is not set
++# CONFIG_TIFM_CORE is not set
+ # CONFIG_IDE is not set
+ 
+ #
+@@ -496,12 +509,9 @@ CONFIG_SCSI_WAIT_SCAN=m
+ # CONFIG_SCSI_SPI_ATTRS is not set
+ # CONFIG_SCSI_FC_ATTRS is not set
+ # CONFIG_SCSI_ISCSI_ATTRS is not set
+-# CONFIG_SCSI_SAS_ATTRS is not set
+ # CONFIG_SCSI_SAS_LIBSAS is not set
+-
+-#
+-# SCSI low-level drivers
+-#
++# 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
+@@ -512,6 +522,7 @@ CONFIG_SCSI_WAIT_SCAN=m
+ # 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
+@@ -552,14 +563,8 @@ CONFIG_BLK_DEV_DM=y
+ # CONFIG_DM_ZERO is not set
+ # CONFIG_DM_MULTIPATH is not set
+ # CONFIG_DM_DELAY is not set
+-
+-#
+-# Fusion MPT device support
+-#
++# CONFIG_DM_UEVENT is not set
+ # CONFIG_FUSION is not set
+-# CONFIG_FUSION_SPI is not set
+-# CONFIG_FUSION_FC is not set
+-# CONFIG_FUSION_SAS is not set
+ 
+ #
+ # IEEE 1394 (FireWire) support
+@@ -574,6 +579,8 @@ CONFIG_NETDEVICES=y
+ # CONFIG_MACVLAN is not set
+ # CONFIG_EQUALIZER is not set
+ # CONFIG_TUN is not set
++# CONFIG_VETH is not set
++# CONFIG_IP1000 is not set
+ # CONFIG_ARCNET is not set
+ # CONFIG_NET_ETHERNET is not set
+ CONFIG_NETDEV_1000=y
+@@ -582,6 +589,7 @@ CONFIG_NETDEV_1000=y
+ CONFIG_E1000=y
+ CONFIG_E1000_NAPI=y
+ # CONFIG_E1000_DISABLE_PACKET_SPLIT is not set
++# CONFIG_E1000E is not set
+ # CONFIG_NS83820 is not set
+ # CONFIG_HAMACHI is not set
+ # CONFIG_YELLOWFIN is not set
+@@ -589,6 +597,7 @@ CONFIG_E1000_NAPI=y
+ # CONFIG_SIS190 is not set
+ # CONFIG_SKGE is not set
+ # CONFIG_SKY2 is not set
++# CONFIG_SK98LIN is not set
+ # CONFIG_VIA_VELOCITY is not set
+ # CONFIG_TIGON3 is not set
+ # CONFIG_BNX2 is not set
+@@ -597,11 +606,14 @@ CONFIG_E1000_NAPI=y
+ CONFIG_NETDEV_10000=y
+ # CONFIG_CHELSIO_T1 is not set
+ # CONFIG_CHELSIO_T3 is not set
++# CONFIG_IXGBE is not set
+ # CONFIG_IXGB is not set
+ # CONFIG_S2IO is not set
+ # CONFIG_MYRI10GE is not set
+ # CONFIG_NETXEN_NIC is not set
++# CONFIG_NIU is not set
+ # CONFIG_MLX4_CORE is not set
++# CONFIG_TEHUTI is not set
+ # CONFIG_TR is not set
+ 
+ #
+@@ -636,7 +648,6 @@ CONFIG_INPUT_MOUSEDEV=y
+ CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+ # CONFIG_INPUT_JOYDEV is not set
+-# CONFIG_INPUT_TSDEV is not set
+ # CONFIG_INPUT_EVDEV is not set
+ # CONFIG_INPUT_EVBUG is not set
+ 
+@@ -685,12 +696,10 @@ CONFIG_UNIX98_PTYS=y
+ CONFIG_LEGACY_PTYS=y
+ CONFIG_LEGACY_PTY_COUNT=256
+ # CONFIG_IPMI_HANDLER is not set
+-# CONFIG_WATCHDOG is not set
+ CONFIG_HW_RANDOM=y
+ # CONFIG_NVRAM is not set
+ # CONFIG_R3964 is not set
+ # CONFIG_APPLICOM is not set
+-# CONFIG_DRM is not set
+ # CONFIG_RAW_DRIVER is not set
+ # CONFIG_TCG_TPM is not set
+ CONFIG_DEVPORT=y
+@@ -755,9 +764,9 @@ CONFIG_I2C_IOP3XX=y
+ # CONFIG_SPI is not set
+ # CONFIG_SPI_MASTER 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_ABITUGURU is not set
+ # CONFIG_SENSORS_AD7418 is not set
+ # CONFIG_SENSORS_ADM1021 is not set
+ # CONFIG_SENSORS_ADM1025 is not set
+@@ -765,12 +774,13 @@ CONFIG_HWMON=y
+ # CONFIG_SENSORS_ADM1029 is not set
+ # CONFIG_SENSORS_ADM1031 is not set
+ # CONFIG_SENSORS_ADM9240 is not set
+-# CONFIG_SENSORS_ASB100 is not set
++# CONFIG_SENSORS_ADT7470 is not set
+ # CONFIG_SENSORS_ATXP1 is not set
+ # CONFIG_SENSORS_DS1621 is not set
++# CONFIG_SENSORS_I5K_AMB is not set
+ # CONFIG_SENSORS_F71805F is not set
+-# CONFIG_SENSORS_FSCHER is not set
+-# CONFIG_SENSORS_FSCPOS 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
+@@ -784,14 +794,17 @@ CONFIG_HWMON=y
+ # 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_SIS5595 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_THMC50 is not set
+ # CONFIG_SENSORS_VIA686A is not set
+ # CONFIG_SENSORS_VT1211 is not set
+ # CONFIG_SENSORS_VT8231 is not set
+@@ -803,29 +816,18 @@ CONFIG_HWMON=y
+ # CONFIG_SENSORS_W83627HF is not set
+ # CONFIG_SENSORS_W83627EHF is not set
+ # CONFIG_HWMON_DEBUG_CHIP is not set
+-CONFIG_MISC_DEVICES=y
+-# CONFIG_PHANTOM is not set
+-# CONFIG_EEPROM_93CX6 is not set
+-# CONFIG_SGI_IOC4 is not set
+-# CONFIG_TIFM_CORE is not set
+-
+-#
+-# Multifunction device drivers
+-#
+-# CONFIG_MFD_SM501 is not set
+-
+-#
+-# LED devices
+-#
+-# CONFIG_NEW_LEDS is not set
++# CONFIG_WATCHDOG is not set
+ 
+ #
+-# LED drivers
++# Sonics Silicon Backplane
+ #
++CONFIG_SSB_POSSIBLE=y
++# CONFIG_SSB is not set
+ 
+ #
+-# LED Triggers
++# Multifunction device drivers
+ #
++# CONFIG_MFD_SM501 is not set
+ 
+ #
+ # Multimedia devices
+@@ -837,14 +839,16 @@ CONFIG_DAB=y
+ #
+ # Graphics support
+ #
++# CONFIG_DRM is not set
++# 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
+-# CONFIG_VGASTATE is not set
+-# CONFIG_FB is not set
+ 
+ #
+ # Console display driver support
+@@ -859,6 +863,7 @@ CONFIG_DUMMY_CONSOLE=y
+ CONFIG_HID_SUPPORT=y
+ CONFIG_HID=y
+ # CONFIG_HID_DEBUG is not set
++# CONFIG_HIDRAW is not set
+ CONFIG_USB_SUPPORT=y
+ CONFIG_USB_ARCH_HAS_HCD=y
+ CONFIG_USB_ARCH_HAS_OHCI=y
+@@ -874,16 +879,15 @@ CONFIG_USB_ARCH_HAS_EHCI=y
+ #
+ # CONFIG_USB_GADGET is not set
+ # CONFIG_MMC is not set
+-
+-#
+-# Real Time Clock
+-#
++# CONFIG_NEW_LEDS is not set
+ CONFIG_RTC_LIB=y
+ # CONFIG_RTC_CLASS is not set
++CONFIG_DMADEVICES=y
+ 
+ #
+-# DMA Engine support
++# DMA Devices
+ #
++CONFIG_INTEL_IOP_ADMA=y
+ CONFIG_DMA_ENGINE=y
+ 
+ #
+@@ -892,12 +896,6 @@ CONFIG_DMA_ENGINE=y
+ CONFIG_NET_DMA=y
+ 
+ #
+-# DMA Devices
+-#
+-# CONFIG_INTEL_IOATDMA is not set
+-CONFIG_INTEL_IOP_ADMA=y
+-
+-#
+ # File systems
+ #
+ CONFIG_EXT2_FS=y
+@@ -909,7 +907,6 @@ CONFIG_EXT3_FS_XATTR=y
+ # CONFIG_EXT3_FS_SECURITY is not set
+ # CONFIG_EXT4DEV_FS is not set
+ CONFIG_JBD=y
+-# CONFIG_JBD_DEBUG is not set
+ CONFIG_FS_MBCACHE=y
+ # CONFIG_REISERFS_FS is not set
+ # CONFIG_JFS_FS is not set
+@@ -949,7 +946,6 @@ CONFIG_SYSFS=y
+ CONFIG_TMPFS=y
+ # CONFIG_TMPFS_POSIX_ACL is not set
+ # CONFIG_HUGETLB_PAGE is not set
+-CONFIG_RAMFS=y
+ # CONFIG_CONFIGFS_FS is not set
+ 
+ #
+@@ -969,10 +965,7 @@ CONFIG_CRAMFS=y
+ # CONFIG_QNX4FS_FS is not set
+ # CONFIG_SYSV_FS is not set
+ # CONFIG_UFS_FS is not set
+-
+-#
+-# Network File Systems
+-#
++CONFIG_NETWORK_FILESYSTEMS=y
+ CONFIG_NFS_FS=y
+ CONFIG_NFS_V3=y
+ # CONFIG_NFS_V3_ACL is not set
+@@ -1019,26 +1012,17 @@ CONFIG_MSDOS_PARTITION=y
+ # CONFIG_KARMA_PARTITION is not set
+ # CONFIG_EFI_PARTITION is not set
+ # CONFIG_SYSV68_PARTITION is not set
+-
+-#
+-# Native Language Support
+-#
+ # CONFIG_NLS is not set
+-
+-#
+-# Distributed Lock Manager
+-#
+ # CONFIG_DLM is not set
+-
+-#
+-# Profiling support
+-#
++CONFIG_INSTRUMENTATION=y
+ # CONFIG_PROFILING is not set
++# CONFIG_MARKERS is not set
+ 
+ #
+ # Kernel hacking
+ #
+ # CONFIG_PRINTK_TIME is not set
++CONFIG_ENABLE_WARN_DEPRECATED=y
+ CONFIG_ENABLE_MUST_CHECK=y
+ CONFIG_MAGIC_SYSRQ=y
+ # CONFIG_UNUSED_SYMBOLS is not set
+@@ -1065,10 +1049,13 @@ CONFIG_DEBUG_BUGVERBOSE=y
+ # CONFIG_DEBUG_INFO is not set
+ # CONFIG_DEBUG_VM is not set
+ # CONFIG_DEBUG_LIST is not set
++# CONFIG_DEBUG_SG is not set
+ CONFIG_FRAME_POINTER=y
+ # CONFIG_FORCED_INLINING is not set
++# CONFIG_BOOT_PRINTK_DELAY is not set
+ # CONFIG_RCU_TORTURE_TEST is not set
+ # CONFIG_FAULT_INJECTION is not set
++# CONFIG_SAMPLES is not set
+ CONFIG_DEBUG_USER=y
+ # CONFIG_DEBUG_ERRORS is not set
+ CONFIG_DEBUG_LL=y
+@@ -1079,6 +1066,7 @@ CONFIG_DEBUG_LL=y
+ #
+ # CONFIG_KEYS is not set
+ # CONFIG_SECURITY is not set
++# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+ CONFIG_XOR_BLOCKS=y
+ CONFIG_ASYNC_CORE=y
+ CONFIG_ASYNC_MEMCPY=y
+diff --git a/arch/arm/configs/littleton_defconfig b/arch/arm/configs/littleton_defconfig
 new file mode 100644
-index 0000000..45e23e0
+index 0000000..1db4969
 --- /dev/null
-+++ b/arch/avr32/configs/atstk1003_defconfig
-@@ -0,0 +1,1015 @@
++++ b/arch/arm/configs/littleton_defconfig
+@@ -0,0 +1,783 @@
 +#
 +# Automatically generated make config: don't edit
-+# Linux kernel version: 2.6.24-rc7
-+# Wed Jan  9 22:54:34 2008
++# Linux kernel version: 2.6.24-rc5
++# Fri Dec 21 11:06:19 2007
 +#
-+CONFIG_AVR32=y
++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
@@ -8857,14 +11546,13 @@
 +CONFIG_HARDIRQS_SW_RESEND=y
 +CONFIG_GENERIC_IRQ_PROBE=y
 +CONFIG_RWSEM_GENERIC_SPINLOCK=y
-+CONFIG_GENERIC_TIME=y
-+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
 +# CONFIG_ARCH_HAS_ILOG2_U32 is not set
 +# CONFIG_ARCH_HAS_ILOG2_U64 is not set
-+CONFIG_ARCH_SUPPORTS_OPROFILE=y
 +CONFIG_GENERIC_HWEIGHT=y
 +CONFIG_GENERIC_CALIBRATE_DELAY=y
-+CONFIG_GENERIC_BUG=y
++CONFIG_ZONE_DMA=y
++CONFIG_ARCH_MTD_XIP=y
++CONFIG_VECTORS_BASE=0xffff0000
 +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
 +
 +#
@@ -8872,21 +11560,19 @@
 +#
 +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_LOCALVERSION_AUTO=y
 +CONFIG_SWAP=y
 +CONFIG_SYSVIPC=y
 +CONFIG_SYSVIPC_SYSCTL=y
-+CONFIG_POSIX_MQUEUE=y
-+CONFIG_BSD_PROCESS_ACCT=y
-+CONFIG_BSD_PROCESS_ACCT_V3=y
-+CONFIG_TASKSTATS=y
-+CONFIG_TASK_DELAY_ACCT=y
-+# CONFIG_TASK_XACCT is not set
++# CONFIG_POSIX_MQUEUE is not set
++# CONFIG_BSD_PROCESS_ACCT is not set
++# CONFIG_TASKSTATS is not set
 +# CONFIG_USER_NS is not set
 +# CONFIG_PID_NS is not set
-+CONFIG_AUDIT=y
++# CONFIG_AUDIT is not set
 +# CONFIG_IKCONFIG is not set
 +CONFIG_LOG_BUF_SHIFT=14
 +# CONFIG_CGROUPS is not set
@@ -8894,13 +11580,14 @@
 +CONFIG_FAIR_USER_SCHED=y
 +# CONFIG_FAIR_CGROUP_SCHED is not set
 +CONFIG_SYSFS_DEPRECATED=y
-+CONFIG_RELAY=y
++# CONFIG_RELAY is not set
 +CONFIG_BLK_DEV_INITRD=y
 +CONFIG_INITRAMFS_SOURCE=""
 +CONFIG_CC_OPTIMIZE_FOR_SIZE=y
 +CONFIG_SYSCTL=y
-+CONFIG_EMBEDDED=y
-+# CONFIG_SYSCTL_SYSCALL is not set
++# 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
@@ -8908,7 +11595,7 @@
 +CONFIG_PRINTK=y
 +CONFIG_BUG=y
 +CONFIG_ELF_CORE=y
-+# CONFIG_BASE_FULL is not set
++CONFIG_BASE_FULL=y
 +CONFIG_FUTEX=y
 +CONFIG_ANON_INODES=y
 +CONFIG_EPOLL=y
@@ -8916,17 +11603,15 @@
 +CONFIG_EVENTFD=y
 +CONFIG_SHMEM=y
 +CONFIG_VM_EVENT_COUNTERS=y
-+# CONFIG_SLUB_DEBUG is not set
-+# CONFIG_SLAB is not set
-+CONFIG_SLUB=y
++CONFIG_SLAB=y
++# CONFIG_SLUB is not set
 +# CONFIG_SLOB is not set
-+CONFIG_SLABINFO=y
 +CONFIG_RT_MUTEXES=y
 +# CONFIG_TINY_SHMEM is not set
-+CONFIG_BASE_SMALL=1
++CONFIG_BASE_SMALL=0
 +CONFIG_MODULES=y
 +CONFIG_MODULE_UNLOAD=y
-+# CONFIG_MODULE_FORCE_UNLOAD is not set
++CONFIG_MODULE_FORCE_UNLOAD=y
 +# CONFIG_MODVERSIONS is not set
 +# CONFIG_MODULE_SRCVERSION_ALL is not set
 +# CONFIG_KMOD is not set
@@ -8940,8 +11625,8 @@
 +# IO Schedulers
 +#
 +CONFIG_IOSCHED_NOOP=y
-+# CONFIG_IOSCHED_AS is not set
-+# CONFIG_IOSCHED_DEADLINE is not set
++CONFIG_IOSCHED_AS=y
++CONFIG_IOSCHED_DEADLINE=y
 +CONFIG_IOSCHED_CFQ=y
 +# CONFIG_DEFAULT_AS is not set
 +# CONFIG_DEFAULT_DEADLINE is not set
@@ -8950,45 +11635,114 @@
 +CONFIG_DEFAULT_IOSCHED="cfq"
 +
 +#
-+# System Type and features
++# System Type
 +#
-+CONFIG_SUBARCH_AVR32B=y
-+CONFIG_MMU=y
-+CONFIG_PERFORMANCE_COUNTERS=y
-+CONFIG_PLATFORM_AT32AP=y
-+CONFIG_CPU_AT32AP700X=y
-+CONFIG_CPU_AT32AP7001=y
-+CONFIG_BOARD_ATSTK1000=y
-+# CONFIG_BOARD_ATNGW100 is not set
-+# CONFIG_BOARD_ATSTK1002 is not set
-+CONFIG_BOARD_ATSTK1003=y
-+# CONFIG_BOARD_ATSTK1004 is not set
-+# CONFIG_BOARD_ATSTK100X_CUSTOM is not set
-+# CONFIG_BOARD_ATSTK100X_SPI1 is not set
-+# CONFIG_BOARD_ATSTK1000_J2_LED is not set
-+# CONFIG_BOARD_ATSTK1000_J2_LED8 is not set
-+# CONFIG_BOARD_ATSTK1000_J2_RGB is not set
-+CONFIG_BOARD_ATSTK1000_EXTDAC=y
-+CONFIG_LOADER_U_BOOT=y
++# 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_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
 +
 +#
-+# Atmel AVR32 AP options
++# Intel PXA2xx/PXA3xx Implementations
 +#
-+# CONFIG_AP700X_32_BIT_SMC is not set
-+CONFIG_AP700X_16_BIT_SMC=y
-+# CONFIG_AP700X_8_BIT_SMC is not set
-+CONFIG_LOAD_ADDRESS=0x10000000
-+CONFIG_ENTRY_ADDRESS=0x90000000
-+CONFIG_PHYS_OFFSET=0x10000000
-+CONFIG_PREEMPT_NONE=y
-+# CONFIG_PREEMPT_VOLUNTARY is not set
-+# CONFIG_PREEMPT is not set
-+# CONFIG_HAVE_ARCH_BOOTMEM_NODE is not set
-+# CONFIG_ARCH_HAVE_MEMORY_PRESENT is not set
-+# CONFIG_NEED_NODE_MEMMAP_SIZE is not set
-+CONFIG_ARCH_FLATMEM_ENABLE=y
++
++#
++# Supported PXA3xx Processor Variants
++#
++CONFIG_CPU_PXA300=y
++CONFIG_CPU_PXA310=y
++# CONFIG_CPU_PXA320 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_MACH_TRIZEPS4 is not set
++# CONFIG_MACH_EM_X270 is not set
++# CONFIG_MACH_ZYLONITE is not set
++CONFIG_MACH_LITTLETON=y
++# CONFIG_MACH_ARMCORE is not set
++CONFIG_PXA3xx=y
++CONFIG_PXA_SSP=y
++
++#
++# 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_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 is not set
++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 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_ARCH_SPARSEMEM_ENABLE is not set
 +CONFIG_SELECT_MEMORY_MODEL=y
 +CONFIG_FLATMEM_MANUAL=y
 +# CONFIG_DISCONTIGMEM_MANUAL is not set
@@ -8997,53 +11751,52 @@
 +CONFIG_FLAT_NODE_MEM_MAP=y
 +# CONFIG_SPARSEMEM_STATIC is not set
 +# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
-+CONFIG_SPLIT_PTLOCK_CPUS=4
++CONFIG_SPLIT_PTLOCK_CPUS=4096
 +# CONFIG_RESOURCES_64BIT is not set
-+CONFIG_ZONE_DMA_FLAG=0
++CONFIG_ZONE_DMA_FLAG=1
++CONFIG_BOUNCE=y
 +CONFIG_VIRT_TO_BUS=y
-+# CONFIG_OWNERSHIP_TRACE is not set
-+# 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_CMDLINE=""
++CONFIG_ALIGNMENT_TRAP=y
 +
 +#
-+# Power management options
++# Boot options
 +#
++CONFIG_ZBOOT_ROM_TEXT=0x0
++CONFIG_ZBOOT_ROM_BSS=0x0
++CONFIG_CMDLINE="root=/dev/nfs rootfstype=nfs nfsroot=192.168.1.100:/nfsroot/ ip=192.168.1.101:192.168.1.100::255.255.255.0::eth0:on console=ttyS2,38400 mem=64M"
++# 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 is not set
-+CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
-+# 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=y
-+# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
-+CONFIG_CPU_FREQ_AT32AP=y
++# CONFIG_CPU_FREQ is not set
 +
 +#
-+# Bus options
++# Floating point emulation
 +#
-+# CONFIG_ARCH_SUPPORTS_MSI is not set
-+# CONFIG_PCCARD is not set
 +
 +#
-+# Executable file formats
++# 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 is not set
++CONFIG_SUSPEND_UP_POSSIBLE=y
++
++#
 +# Networking
 +#
 +CONFIG_NET=y
@@ -9052,14 +11805,21 @@
 +# Networking options
 +#
 +CONFIG_PACKET=y
-+CONFIG_PACKET_MMAP=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_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 is not set
++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
@@ -9069,11 +11829,12 @@
 +# 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_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_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"
@@ -9103,7 +11864,6 @@
 +# Network testing
 +#
 +# CONFIG_NET_PKTGEN is not set
-+# CONFIG_NET_TCPPROBE is not set
 +# CONFIG_HAMRADIO is not set
 +# CONFIG_IRDA is not set
 +# CONFIG_BT is not set
@@ -9127,153 +11887,27 @@
 +# Generic Driver Options
 +#
 +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
-+CONFIG_STANDALONE=y
++# CONFIG_STANDALONE is not set
 +# CONFIG_PREVENT_FIRMWARE_BUILD is not set
-+# CONFIG_FW_LOADER is not set
++CONFIG_FW_LOADER=y
 +# 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
-+
-+#
-+# 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
++# CONFIG_MTD is not set
++# CONFIG_PARPORT is not set
++# CONFIG_BLK_DEV is not set
++# CONFIG_MISC_DEVICES is not set
++# CONFIG_IDE is not set
 +
 +#
-+# RAM/ROM/Flash chip drivers
-+#
-+CONFIG_MTD_CFI=y
-+# CONFIG_MTD_JEDECPROBE is not set
-+CONFIG_MTD_GEN_PROBE=y
-+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
-+CONFIG_MTD_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=y
-+# 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
-+
-+#
-+# Mapping drivers for chip access
-+#
-+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
-+CONFIG_MTD_PHYSMAP=y
-+CONFIG_MTD_PHYSMAP_START=0x8000000
-+CONFIG_MTD_PHYSMAP_LEN=0x0
-+CONFIG_MTD_PHYSMAP_BANKWIDTH=2
-+# CONFIG_MTD_PLATRAM is not set
-+
-+#
-+# Self-contained MTD device drivers
-+#
-+CONFIG_MTD_DATAFLASH=m
-+CONFIG_MTD_M25P80=m
-+# 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_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=m
-+CONFIG_BLK_DEV_RAM_COUNT=16
-+CONFIG_BLK_DEV_RAM_SIZE=4096
-+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
-+# CONFIG_CDROM_PKTCDVD is not set
-+# CONFIG_ATA_OVER_ETH is not set
-+CONFIG_MISC_DEVICES=y
-+# CONFIG_EEPROM_93CX6 is not set
-+CONFIG_ATMEL_SSC=m
-+# CONFIG_IDE is not set
-+
-+#
-+# SCSI device support
++# SCSI device support
 +#
 +# CONFIG_RAID_ATTRS is not set
-+CONFIG_SCSI=m
-+CONFIG_SCSI_DMA=y
-+# CONFIG_SCSI_TGT is not set
++# CONFIG_SCSI is not set
++# CONFIG_SCSI_DMA 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=m
-+# CONFIG_BLK_DEV_SR_VENDOR 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_ATA=m
-+# CONFIG_ATA_NONSTANDARD is not set
-+CONFIG_PATA_AT32=m
-+# CONFIG_PATA_PLATFORM is not set
++# CONFIG_ATA is not set
 +# CONFIG_MD is not set
 +CONFIG_NETDEVICES=y
 +# CONFIG_NETDEVICES_MULTIQUEUE is not set
@@ -9283,7 +11917,18 @@
 +# CONFIG_EQUALIZER is not set
 +# CONFIG_TUN is not set
 +# CONFIG_VETH is not set
-+# CONFIG_NET_ETHERNET is not set
++# CONFIG_PHYLIB is not set
++CONFIG_NET_ETHERNET=y
++CONFIG_MII=y
++# CONFIG_AX88796 is not set
++CONFIG_SMC91X=y
++# CONFIG_DM9000 is not set
++# 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
 +
@@ -9293,37 +11938,26 @@
 +# CONFIG_WLAN_PRE80211 is not set
 +# CONFIG_WLAN_80211 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_PPP is not set
 +# CONFIG_SLIP is not set
-+CONFIG_SLHC=m
 +# CONFIG_SHAPER 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=m
++CONFIG_INPUT=y
 +# CONFIG_INPUT_FF_MEMLESS is not set
-+CONFIG_INPUT_POLLDEV=m
++# CONFIG_INPUT_POLLDEV is not set
 +
 +#
 +# Userland interfaces
 +#
-+CONFIG_INPUT_MOUSEDEV=m
-+CONFIG_INPUT_MOUSEDEV_PSAUX=y
++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
@@ -9333,19 +11967,8 @@
 +#
 +# 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_GPIO=m
-+CONFIG_INPUT_MOUSE=y
-+# CONFIG_MOUSE_PS2 is not set
-+# CONFIG_MOUSE_SERIAL is not set
-+# CONFIG_MOUSE_VSXXXAA is not set
-+CONFIG_MOUSE_GPIO=m
++# 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
@@ -9360,7 +11983,10 @@
 +#
 +# Character devices
 +#
-+# CONFIG_VT is not set
++CONFIG_VT=y
++CONFIG_VT_CONSOLE=y
++CONFIG_HW_CONSOLE=y
++# CONFIG_VT_HW_CONSOLE_BINDING is not set
 +# CONFIG_SERIAL_NONSTANDARD is not set
 +
 +#
@@ -9371,88 +11997,29 @@
 +#
 +# Non-8250 serial port support
 +#
-+CONFIG_SERIAL_ATMEL=y
-+CONFIG_SERIAL_ATMEL_CONSOLE=y
-+# CONFIG_SERIAL_ATMEL_TTYAT is not set
++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_RTC is not set
-+# CONFIG_GEN_RTC 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=m
-+CONFIG_I2C_BOARDINFO=y
-+CONFIG_I2C_CHARDEV=m
-+
-+#
-+# I2C Algorithms
-+#
-+CONFIG_I2C_ALGOBIT=m
-+# CONFIG_I2C_ALGOPCF is not set
-+# CONFIG_I2C_ALGOPCA is not set
-+
-+#
-+# I2C Hardware Bus support
-+#
-+CONFIG_I2C_GPIO=m
-+# 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
-+
-+#
-+# Miscellaneous I2C Chip support
-+#
-+# CONFIG_SENSORS_DS1337 is not set
-+# CONFIG_SENSORS_DS1374 is not set
-+# CONFIG_DS1682 is not set
-+# CONFIG_SENSORS_EEPROM is not set
-+# CONFIG_SENSORS_PCF8574 is not set
-+# CONFIG_SENSORS_PCA9539 is not set
-+# CONFIG_SENSORS_PCF8591 is not set
-+# CONFIG_SENSORS_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_I2C is not set
 +
 +#
 +# SPI support
 +#
-+CONFIG_SPI=y
-+# CONFIG_SPI_DEBUG is not set
-+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=m
-+# CONFIG_SPI_TLE62X0 is not set
++# CONFIG_SPI is not set
++# CONFIG_SPI_MASTER 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 is not set
-+
-+#
-+# Watchdog Device Drivers
-+#
-+# CONFIG_SOFT_WATCHDOG is not set
-+CONFIG_AT32AP700X_WDT=y
++# CONFIG_WATCHDOG is not set
 +
 +#
 +# Sonics Silicon Backplane
@@ -9477,213 +12044,94 @@
 +#
 +# 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
-+
-+#
-+# 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
++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_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
 +
 +#
-+# SPI devices
++# Frame buffer hardware drivers
 +#
-+CONFIG_SND_AT73C213=m
-+CONFIG_SND_AT73C213_TARGET_BITRATE=48000
++# CONFIG_FB_S1D13XXX is not set
++CONFIG_FB_PXA=y
++# CONFIG_FB_PXA_PARAMETERS is not set
++# CONFIG_FB_MBX is not set
++# CONFIG_FB_VIRTUAL is not set
++# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
 +
 +#
-+# System on Chip audio support
++# Display device support
 +#
-+# CONFIG_SND_SOC is not set
++# CONFIG_DISPLAY_SUPPORT is not set
 +
 +#
-+# SoC Audio support for SuperH
++# 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 is not set
++CONFIG_FONT_8x16=y
++# 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=y
++CONFIG_LOGO_LINUX_MONO=y
++CONFIG_LOGO_LINUX_VGA16=y
++CONFIG_LOGO_LINUX_CLUT224=y
 +
 +#
-+# Open Sound System
++# Sound
 +#
-+# CONFIG_SOUND_PRIME is not set
++# CONFIG_SOUND is not set
 +# CONFIG_HID_SUPPORT is not set
-+CONFIG_USB_SUPPORT=y
-+# CONFIG_USB_ARCH_HAS_HCD is not set
-+# CONFIG_USB_ARCH_HAS_OHCI is not set
-+# CONFIG_USB_ARCH_HAS_EHCI is not set
-+
-+#
-+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
-+#
-+
-+#
-+# USB Gadget Support
-+#
-+CONFIG_USB_GADGET=y
-+# CONFIG_USB_GADGET_DEBUG is not set
-+# CONFIG_USB_GADGET_DEBUG_FILES is not set
-+CONFIG_USB_GADGET_DEBUG_FS=y
-+CONFIG_USB_GADGET_SELECTED=y
-+# CONFIG_USB_GADGET_AMD5536UDC is not set
-+CONFIG_USB_GADGET_ATMEL_USBA=y
-+CONFIG_USB_ATMEL_USBA=y
-+# CONFIG_USB_GADGET_FSL_USB2 is not set
-+# CONFIG_USB_GADGET_NET2280 is not set
-+# CONFIG_USB_GADGET_PXA2XX is not set
-+# CONFIG_USB_GADGET_M66592 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=y
-+CONFIG_USB_ZERO=m
-+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_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 is not set
-+# CONFIG_SDIO_UART is not set
-+
-+#
-+# MMC/SD Host Controller Drivers
-+#
-+CONFIG_MMC_SPI=m
-+CONFIG_NEW_LEDS=y
-+CONFIG_LEDS_CLASS=y
-+
-+#
-+# LED drivers
-+#
-+CONFIG_LEDS_GPIO=y
-+
-+#
-+# LED Triggers
-+#
-+CONFIG_LEDS_TRIGGERS=y
-+CONFIG_LEDS_TRIGGER_TIMER=y
-+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
++# 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
-+
-+#
-+# 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
-+
-+#
-+# SPI RTC drivers
-+#
-+# CONFIG_RTC_DRV_RS5C348 is not set
-+# CONFIG_RTC_DRV_MAX6902 is not set
-+
-+#
-+# Platform RTC drivers
-+#
-+# CONFIG_RTC_DRV_DS1553 is not set
-+# CONFIG_RTC_DRV_STK17TA8 is not set
-+# CONFIG_RTC_DRV_DS1742 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_AT32AP700X=y
-+
-+#
-+# Userspace I/O
-+#
-+CONFIG_UIO=m
++# CONFIG_RTC_CLASS 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_EXT2_FS is not set
++# CONFIG_EXT3_FS is not set
 +# CONFIG_EXT4DEV_FS is not set
-+CONFIG_JBD=m
-+# CONFIG_JBD_DEBUG is not set
 +# CONFIG_REISERFS_FS is not set
 +# CONFIG_JFS_FS is not set
-+# CONFIG_FS_POSIX_ACL is not set
++CONFIG_FS_POSIX_ACL=y
 +# CONFIG_XFS_FS is not set
 +# CONFIG_GFS2_FS is not set
 +# CONFIG_OCFS2_FS is not set
 +# CONFIG_MINIX_FS is not set
 +# CONFIG_ROMFS_FS is not set
-+CONFIG_INOTIFY=y
-+CONFIG_INOTIFY_USER=y
++# CONFIG_INOTIFY is not set
 +# CONFIG_QUOTA is not set
 +# CONFIG_DNOTIFY is not set
 +# CONFIG_AUTOFS_FS is not set
 +# CONFIG_AUTOFS4_FS is not set
-+CONFIG_FUSE_FS=m
++# CONFIG_FUSE_FS is not set
 +
 +#
 +# CD-ROM/DVD Filesystems
@@ -9694,24 +12142,19 @@
 +#
 +# 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_MSDOS_FS is not set
++# CONFIG_VFAT_FS is not set
 +# CONFIG_NTFS_FS is not set
 +
 +#
 +# Pseudo filesystems
 +#
 +CONFIG_PROC_FS=y
-+CONFIG_PROC_KCORE=y
 +CONFIG_PROC_SYSCTL=y
 +CONFIG_SYSFS=y
-+CONFIG_TMPFS=y
-+# CONFIG_TMPFS_POSIX_ACL is not set
++# CONFIG_TMPFS is not set
 +# CONFIG_HUGETLB_PAGE is not set
-+CONFIG_CONFIGFS_FS=m
++# CONFIG_CONFIGFS_FS is not set
 +
 +#
 +# Miscellaneous filesystems
@@ -9723,86 +12166,53 @@
 +# 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_HPFS_FS is not set
 +# CONFIG_QNX4FS_FS is not set
 +# CONFIG_SYSV_FS is not set
 +# CONFIG_UFS_FS is not set
-+# CONFIG_NETWORK_FILESYSTEMS 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_NFS_DIRECTIO=y
++# CONFIG_NFSD is not set
++CONFIG_ROOT_NFS=y
++CONFIG_LOCKD=y
++CONFIG_LOCKD_V4=y
++CONFIG_NFS_ACL_SUPPORT=y
++CONFIG_NFS_COMMON=y
++CONFIG_SUNRPC=y
++CONFIG_SUNRPC_GSS=y
++# CONFIG_SUNRPC_BIND34 is not set
++CONFIG_RPCSEC_GSS_KRB5=y
++# CONFIG_RPCSEC_GSS_SPKM3 is not set
++# CONFIG_SMB_FS is not set
++# CONFIG_CIFS is not set
++# CONFIG_NCP_FS is not set
++# CONFIG_CODA_FS is not set
++# CONFIG_AFS_FS is not set
 +
 +#
 +# Partition Types
 +#
 +# CONFIG_PARTITION_ADVANCED is not set
 +CONFIG_MSDOS_PARTITION=y
-+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_NLS is not set
 +# CONFIG_DLM is not set
-+CONFIG_INSTRUMENTATION=y
-+CONFIG_PROFILING=y
-+CONFIG_OPROFILE=m
-+CONFIG_KPROBES=y
-+# CONFIG_MARKERS is not set
++# CONFIG_INSTRUMENTATION is not set
 +
 +#
 +# Kernel hacking
 +#
-+# CONFIG_PRINTK_TIME is not set
++CONFIG_PRINTK_TIME=y
 +CONFIG_ENABLE_WARN_DEPRECATED=y
 +CONFIG_ENABLE_MUST_CHECK=y
 +CONFIG_MAGIC_SYSRQ=y
 +# CONFIG_UNUSED_SYMBOLS is not set
-+CONFIG_DEBUG_FS=y
++# CONFIG_DEBUG_FS is not set
 +# CONFIG_HEADERS_CHECK is not set
 +CONFIG_DEBUG_KERNEL=y
 +# CONFIG_DEBUG_SHIRQ is not set
@@ -9810,6 +12220,8 @@
 +CONFIG_SCHED_DEBUG=y
 +# CONFIG_SCHEDSTATS is not set
 +# CONFIG_TIMER_STATS is not set
++# CONFIG_DEBUG_SLAB is not set
++# CONFIG_DEBUG_PREEMPT is not set
 +# CONFIG_DEBUG_RT_MUTEXES is not set
 +# CONFIG_RT_MUTEX_TESTER is not set
 +# CONFIG_DEBUG_SPINLOCK is not set
@@ -9821,7 +12233,7 @@
 +# 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_INFO=y
 +# CONFIG_DEBUG_VM is not set
 +# CONFIG_DEBUG_LIST is not set
 +# CONFIG_DEBUG_SG is not set
@@ -9829,9 +12241,12 @@
 +CONFIG_FORCED_INLINING=y
 +# CONFIG_BOOT_PRINTK_DELAY is not set
 +# CONFIG_RCU_TORTURE_TEST is not set
-+# CONFIG_LKDTM is not set
 +# CONFIG_FAULT_INJECTION is not set
 +# CONFIG_SAMPLES is not set
++CONFIG_DEBUG_USER=y
++CONFIG_DEBUG_ERRORS=y
++CONFIG_DEBUG_LL=y
++# CONFIG_DEBUG_ICEDCC is not set
 +
 +#
 +# Security options
@@ -9839,53 +12254,94 @@
 +# CONFIG_KEYS is not set
 +# CONFIG_SECURITY is not set
 +# CONFIG_SECURITY_FILE_CAPABILITIES is not set
-+# CONFIG_CRYPTO is not set
++CONFIG_CRYPTO=y
++CONFIG_CRYPTO_ALGAPI=y
++CONFIG_CRYPTO_BLKCIPHER=y
++CONFIG_CRYPTO_MANAGER=y
++# CONFIG_CRYPTO_HMAC is not set
++# CONFIG_CRYPTO_XCBC is not set
++# CONFIG_CRYPTO_NULL is not set
++# CONFIG_CRYPTO_MD4 is not set
++CONFIG_CRYPTO_MD5=y
++# CONFIG_CRYPTO_SHA1 is not set
++# CONFIG_CRYPTO_SHA256 is not set
++# CONFIG_CRYPTO_SHA512 is not set
++# CONFIG_CRYPTO_WP512 is not set
++# CONFIG_CRYPTO_TGR192 is not set
++# CONFIG_CRYPTO_GF128MUL is not set
++# CONFIG_CRYPTO_ECB is not set
++CONFIG_CRYPTO_CBC=y
++# CONFIG_CRYPTO_PCBC is not set
++# CONFIG_CRYPTO_LRW is not set
++# CONFIG_CRYPTO_XTS is not set
++# CONFIG_CRYPTO_CRYPTD is not set
++CONFIG_CRYPTO_DES=y
++# CONFIG_CRYPTO_FCRYPT is not set
++# CONFIG_CRYPTO_BLOWFISH is not set
++# CONFIG_CRYPTO_TWOFISH is not set
++# CONFIG_CRYPTO_SERPENT is not set
++# CONFIG_CRYPTO_AES is not set
++# CONFIG_CRYPTO_CAST5 is not set
++# CONFIG_CRYPTO_CAST6 is not set
++# CONFIG_CRYPTO_TEA is not set
++# CONFIG_CRYPTO_ARC4 is not set
++# CONFIG_CRYPTO_KHAZAD is not set
++# CONFIG_CRYPTO_ANUBIS is not set
++# CONFIG_CRYPTO_SEED is not set
++# CONFIG_CRYPTO_DEFLATE is not set
++# CONFIG_CRYPTO_MICHAEL_MIC is not set
++# CONFIG_CRYPTO_CRC32C is not set
++# CONFIG_CRYPTO_CAMELLIA is not set
++# CONFIG_CRYPTO_TEST is not set
++# CONFIG_CRYPTO_AUTHENC is not set
++CONFIG_CRYPTO_HW=y
 +
 +#
 +# Library routines
 +#
 +CONFIG_BITREVERSE=y
-+CONFIG_CRC_CCITT=m
++CONFIG_CRC_CCITT=y
 +# CONFIG_CRC16 is not set
-+CONFIG_CRC_ITU_T=m
++# CONFIG_CRC_ITU_T is not set
 +CONFIG_CRC32=y
-+CONFIG_CRC7=m
++# CONFIG_CRC7 is not set
 +# CONFIG_LIBCRC32C is not set
-+CONFIG_AUDIT_GENERIC=y
-+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/avr32/configs/atstk1004_defconfig b/arch/avr32/configs/atstk1004_defconfig
+diff --git a/arch/arm/configs/msm_defconfig b/arch/arm/configs/msm_defconfig
 new file mode 100644
-index 0000000..634c527
+index 0000000..ae4c5e6
 --- /dev/null
-+++ b/arch/avr32/configs/atstk1004_defconfig
-@@ -0,0 +1,621 @@
++++ b/arch/arm/configs/msm_defconfig
+@@ -0,0 +1,895 @@
 +#
 +# Automatically generated make config: don't edit
-+# Linux kernel version: 2.6.24-rc7
-+# Wed Jan  9 23:04:20 2008
++# Linux kernel version: 2.6.23
++# Wed Nov  7 01:36:45 2007
 +#
-+CONFIG_AVR32=y
-+CONFIG_GENERIC_GPIO=y
++CONFIG_ARM=y
++CONFIG_SYS_SUPPORTS_APM_EMULATION=y
++# CONFIG_GENERIC_GPIO is not set
++CONFIG_GENERIC_TIME=y
++CONFIG_GENERIC_CLOCKEVENTS=y
++CONFIG_MMU=y
++# CONFIG_NO_IOPORT is not set
 +CONFIG_GENERIC_HARDIRQS=y
++CONFIG_GENERIC_GPIOS=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_GENERIC_TIME=y
-+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
 +# CONFIG_ARCH_HAS_ILOG2_U32 is not set
 +# CONFIG_ARCH_HAS_ILOG2_U64 is not set
-+CONFIG_ARCH_SUPPORTS_OPROFILE=y
 +CONFIG_GENERIC_HWEIGHT=y
 +CONFIG_GENERIC_CALIBRATE_DELAY=y
-+CONFIG_GENERIC_BUG=y
++CONFIG_ZONE_DMA=y
++CONFIG_VECTORS_BASE=0xffff0000
 +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
 +
 +#
@@ -9893,86 +12349,174 @@
 +#
 +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_LOCALVERSION_AUTO=y
++CONFIG_SWAP=y
 +# CONFIG_SYSVIPC is not set
 +# CONFIG_POSIX_MQUEUE is not set
 +# CONFIG_BSD_PROCESS_ACCT is not set
 +# CONFIG_TASKSTATS is not set
 +# CONFIG_USER_NS is not set
-+# CONFIG_PID_NS is not set
 +# CONFIG_AUDIT is not set
-+# CONFIG_IKCONFIG is not set
-+CONFIG_LOG_BUF_SHIFT=14
-+# CONFIG_CGROUPS is not set
-+# CONFIG_FAIR_GROUP_SCHED is not set
++CONFIG_IKCONFIG=y
++CONFIG_IKCONFIG_PROC=y
++CONFIG_LOG_BUF_SHIFT=17
 +CONFIG_SYSFS_DEPRECATED=y
 +# CONFIG_RELAY is not set
-+# CONFIG_BLK_DEV_INITRD is not set
++CONFIG_BLK_DEV_INITRD=y
++CONFIG_INITRAMFS_SOURCE=""
 +CONFIG_CC_OPTIMIZE_FOR_SIZE=y
 +CONFIG_SYSCTL=y
-+CONFIG_EMBEDDED=y
-+# CONFIG_SYSCTL_SYSCALL is not set
++CONFIG_PANIC_TIMEOUT=0
++# 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_BASE_FULL is not set
-+# CONFIG_FUTEX is not set
-+# CONFIG_EPOLL is not set
-+# CONFIG_SIGNALFD is not set
-+# CONFIG_EVENTFD is not set
++CONFIG_BASE_FULL=y
++CONFIG_FUTEX=y
++CONFIG_ANON_INODES=y
++CONFIG_EPOLL=y
++CONFIG_SIGNALFD=y
++CONFIG_EVENTFD=y
 +CONFIG_SHMEM=y
 +CONFIG_VM_EVENT_COUNTERS=y
-+# CONFIG_SLAB is not set
++CONFIG_SLAB=y
 +# CONFIG_SLUB is not set
-+CONFIG_SLOB=y
++# CONFIG_SLOB is not set
++CONFIG_RT_MUTEXES=y
 +# CONFIG_TINY_SHMEM is not set
-+CONFIG_BASE_SMALL=1
++CONFIG_BASE_SMALL=0
 +# CONFIG_MODULES is not set
-+# CONFIG_BLOCK is not set
++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
 +
 +#
-+# System Type and features
++# IO Schedulers
 +#
-+CONFIG_SUBARCH_AVR32B=y
-+CONFIG_MMU=y
-+CONFIG_PERFORMANCE_COUNTERS=y
-+CONFIG_PLATFORM_AT32AP=y
-+CONFIG_CPU_AT32AP700X=y
-+CONFIG_CPU_AT32AP7002=y
-+CONFIG_BOARD_ATSTK1000=y
-+# CONFIG_BOARD_ATNGW100 is not set
-+# CONFIG_BOARD_ATSTK1002 is not set
-+# CONFIG_BOARD_ATSTK1003 is not set
-+CONFIG_BOARD_ATSTK1004=y
-+# CONFIG_BOARD_ATSTK100X_CUSTOM is not set
-+# CONFIG_BOARD_ATSTK100X_SPI1 is not set
-+# CONFIG_BOARD_ATSTK1000_J2_LED is not set
-+CONFIG_BOARD_ATSTK1000_EXTDAC=y
-+CONFIG_LOADER_U_BOOT=y
++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"
 +
 +#
-+# Atmel AVR32 AP options
++# System Type
 +#
-+# CONFIG_AP700X_32_BIT_SMC is not set
-+CONFIG_AP700X_16_BIT_SMC=y
-+# CONFIG_AP700X_8_BIT_SMC is not set
-+CONFIG_LOAD_ADDRESS=0x10000000
-+CONFIG_ENTRY_ADDRESS=0x90000000
-+CONFIG_PHYS_OFFSET=0x10000000
-+CONFIG_PREEMPT_NONE=y
-+# CONFIG_PREEMPT_VOLUNTARY is not set
-+# CONFIG_PREEMPT is not set
-+# CONFIG_HAVE_ARCH_BOOTMEM_NODE is not set
-+# CONFIG_ARCH_HAVE_MEMORY_PRESENT is not set
-+# CONFIG_NEED_NODE_MEMMAP_SIZE is not set
-+CONFIG_ARCH_FLATMEM_ENABLE=y
++# CONFIG_ARCH_AAEC2000 is not set
++# CONFIG_ARCH_GOLDFISH 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_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=y
++
++#
++# Boot options
++#
++
++#
++# Power management
++#
++
++#
++# MSM7200 Board Type
++#
++CONFIG_MACH_HALIBUT=y
++CONFIG_SERIAL_MSM=y
++CONFIG_SERIAL_MSM_CONSOLE=y
++# CONFIG_SERIAL_MSM_NOINIT is not set
++CONFIG_MSM_SMD=y
++
++#
++# Processor Type
++#
++CONFIG_CPU_32=y
++CONFIG_CPU_V6=y
++# CONFIG_CPU_32v6K is not set
++CONFIG_CPU_32v6=y
++CONFIG_CPU_ABRT_EV6=y
++CONFIG_CPU_CACHE_V6=y
++CONFIG_CPU_CACHE_VIPT=y
++CONFIG_CPU_COPY_V6=y
++CONFIG_CPU_TLB_V6=y
++CONFIG_CPU_HAS_ASID=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_BPREDICT_DISABLE is not set
++# CONFIG_OUTER_CACHE is not set
++
++#
++# Bus support
++#
++# CONFIG_PCI_SYSCALL is not set
++# CONFIG_ARCH_SUPPORTS_MSI is not set
++
++#
++# PCCARD (PCMCIA/CardBus) support
++#
++# CONFIG_PCCARD is not set
++
++#
++# Kernel Features
++#
++CONFIG_TICK_ONESHOT=y
++CONFIG_NO_HZ=y
++CONFIG_HIGH_RES_TIMERS=y
++CONFIG_PREEMPT=y
++CONFIG_HZ=100
++CONFIG_AEABI=y
++# CONFIG_OABI_COMPAT is not set
 +# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
-+# CONFIG_ARCH_SPARSEMEM_ENABLE is not set
 +CONFIG_SELECT_MEMORY_MODEL=y
 +CONFIG_FLATMEM_MANUAL=y
 +# CONFIG_DISCONTIGMEM_MANUAL is not set
@@ -9980,54 +12524,45 @@
 +CONFIG_FLATMEM=y
 +CONFIG_FLAT_NODE_MEM_MAP=y
 +# CONFIG_SPARSEMEM_STATIC is not set
-+# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
 +CONFIG_SPLIT_PTLOCK_CPUS=4
-+# CONFIG_RESOURCES_64BIT is not set
-+CONFIG_ZONE_DMA_FLAG=0
++CONFIG_RESOURCES_64BIT=y
++CONFIG_ZONE_DMA_FLAG=1
++CONFIG_BOUNCE=y
 +CONFIG_VIRT_TO_BUS=y
-+# CONFIG_OWNERSHIP_TRACE is not set
-+# 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_CMDLINE=""
++CONFIG_ALIGNMENT_TRAP=y
 +
 +#
-+# Power management options
++# Boot options
 +#
++CONFIG_ZBOOT_ROM_TEXT=0x0
++CONFIG_ZBOOT_ROM_BSS=0x0
++CONFIG_CMDLINE="mem=64M console=ttyMSM,115200n8"
++# CONFIG_XIP_KERNEL is not set
++# CONFIG_KEXEC is not set
 +
 +#
-+# CPU Frequency scaling
++# Floating point emulation
 +#
-+CONFIG_CPU_FREQ=y
-+CONFIG_CPU_FREQ_TABLE=y
-+# CONFIG_CPU_FREQ_DEBUG is not set
-+# CONFIG_CPU_FREQ_STAT is not set
-+CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
-+# 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=y
-+# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
-+CONFIG_CPU_FREQ_AT32AP=y
 +
 +#
-+# Bus options
++# At least one emulation must be selected
 +#
-+# CONFIG_ARCH_SUPPORTS_MSI is not set
-+# CONFIG_PCCARD is not set
++# CONFIG_VFP is not set
 +
 +#
-+# Executable file formats
++# 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_SUSPEND_UP_POSSIBLE=y
++
++#
 +# Networking
 +#
 +CONFIG_NET=y
@@ -10035,8 +12570,7 @@
 +#
 +# Networking options
 +#
-+CONFIG_PACKET=y
-+CONFIG_PACKET_MMAP=y
++# CONFIG_PACKET is not set
 +CONFIG_UNIX=y
 +# CONFIG_NET_KEY is not set
 +CONFIG_INET=y
@@ -10056,7 +12590,6 @@
 +# 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
@@ -10081,6 +12614,10 @@
 +# CONFIG_LAPB is not set
 +# CONFIG_ECONET is not set
 +# CONFIG_WAN_ROUTER is not set
++
++#
++# QoS and/or fair queueing
++#
 +# CONFIG_NET_SCHED is not set
 +
 +#
@@ -10109,10 +12646,11 @@
 +#
 +# Generic Driver Options
 +#
-+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 +CONFIG_STANDALONE=y
-+# CONFIG_PREVENT_FIRMWARE_BUILD is not set
-+# CONFIG_FW_LOADER is not set
++CONFIG_PREVENT_FIRMWARE_BUILD=y
++CONFIG_FW_LOADER=y
++# 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
@@ -10121,20 +12659,25 @@
 +CONFIG_MTD_PARTITIONS=y
 +# CONFIG_MTD_REDBOOT_PARTS is not set
 +CONFIG_MTD_CMDLINE_PARTS=y
++# CONFIG_MTD_AFS_PARTS is not set
 +
 +#
 +# User Modules And Translation Layers
 +#
 +CONFIG_MTD_CHAR=y
-+# CONFIG_MTD_OOPS is not set
++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
 +
 +#
 +# RAM/ROM/Flash chip drivers
 +#
-+CONFIG_MTD_CFI=y
++# CONFIG_MTD_CFI is not set
 +# CONFIG_MTD_JEDECPROBE is not set
-+CONFIG_MTD_GEN_PROBE=y
-+# 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
@@ -10145,10 +12688,6 @@
 +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=y
-+# 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
@@ -10157,20 +12696,16 @@
 +# Mapping drivers for chip access
 +#
 +# CONFIG_MTD_COMPLEX_MAPPINGS is not set
-+CONFIG_MTD_PHYSMAP=y
-+CONFIG_MTD_PHYSMAP_START=0x8000000
-+CONFIG_MTD_PHYSMAP_LEN=0x0
-+CONFIG_MTD_PHYSMAP_BANKWIDTH=2
 +# 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
++CONFIG_MTD_MSM_NAND=y
 +
 +#
 +# Disk-On-Chip Device Drivers
@@ -10178,6 +12713,7 @@
 +# CONFIG_MTD_DOC2000 is not set
 +# CONFIG_MTD_DOC2001 is not set
 +# CONFIG_MTD_DOC2001PLUS is not set
++# CONFIG_MTD_GOLDFISH_NAND is not set
 +# CONFIG_MTD_NAND is not set
 +# CONFIG_MTD_ONENAND is not set
 +
@@ -10186,21 +12722,118 @@
 +#
 +# CONFIG_MTD_UBI is not set
 +# CONFIG_PARPORT is not set
-+# CONFIG_MISC_DEVICES 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_RAM is not set
++# CONFIG_CDROM_PKTCDVD is not set
++# CONFIG_ATA_OVER_ETH 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_NETDEVICES is not set
++# CONFIG_ATA is not set
++# CONFIG_MD is not set
++CONFIG_NETDEVICES=y
++# CONFIG_NETDEVICES_MULTIQUEUE 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
++# CONFIG_PHYLIB is not set
++CONFIG_NET_ETHERNET=y
++CONFIG_MII=y
++# CONFIG_AX88796 is not set
++CONFIG_SMC91X=y
++# CONFIG_DM9000 is not set
++CONFIG_NETDEV_1000=y
++CONFIG_NETDEV_10000=y
++
++#
++# Wireless LAN
++#
++# CONFIG_WLAN_PRE80211 is not set
++# CONFIG_WLAN_80211 is not set
++# CONFIG_WAN is not set
++CONFIG_PPP=y
++# CONFIG_PPP_MULTILINK is not set
++# CONFIG_PPP_FILTER is not set
++CONFIG_PPP_ASYNC=y
++# CONFIG_PPP_SYNC_TTY is not set
++CONFIG_PPP_DEFLATE=y
++CONFIG_PPP_BSDCOMP=y
++# CONFIG_PPP_MPPE is not set
++# CONFIG_PPPOE is not set
++# CONFIG_PPPOL2TP is not set
++# CONFIG_SLIP is not set
++CONFIG_SLHC=y
++# CONFIG_SHAPER is not set
++# CONFIG_NETCONSOLE is not set
++CONFIG_MSM_RMNET=y
++# 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 is not set
++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_TSDEV 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_GOLDFISH_EVENTS 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_SYNAPTICS_I2C_MEP is not set
++CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI=y
++# 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_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_INPUT_GPIO=y
 +
 +#
 +# Hardware I/O ports
@@ -10211,7 +12844,10 @@
 +#
 +# Character devices
 +#
-+# CONFIG_VT is not set
++CONFIG_VT=y
++CONFIG_VT_CONSOLE=y
++CONFIG_HW_CONSOLE=y
++CONFIG_VT_HW_CONSOLE_BINDING=y
 +# CONFIG_SERIAL_NONSTANDARD is not set
 +
 +#
@@ -10222,81 +12858,101 @@
 +#
 +# Non-8250 serial port support
 +#
-+CONFIG_SERIAL_ATMEL=y
-+CONFIG_SERIAL_ATMEL_CONSOLE=y
-+# CONFIG_SERIAL_ATMEL_TTYAT is not set
 +CONFIG_SERIAL_CORE=y
 +CONFIG_SERIAL_CORE_CONSOLE=y
 +CONFIG_UNIX98_PTYS=y
 +# CONFIG_LEGACY_PTYS is not set
 +# CONFIG_IPMI_HANDLER is not set
++# CONFIG_WATCHDOG is not set
 +# CONFIG_HW_RANDOM is not set
-+# CONFIG_RTC is not set
-+# CONFIG_GEN_RTC 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 is not set
-+
-+#
-+# SPI support
-+#
-+CONFIG_SPI=y
-+CONFIG_SPI_MASTER=y
++CONFIG_DCC_TTY=y
++# CONFIG_GOLDFISH_TTY is not set
++CONFIG_BINDER=y
++CONFIG_I2C=y
++CONFIG_I2C_BOARDINFO=y
++# CONFIG_I2C_CHARDEV is not set
 +
 +#
-+# SPI Master Controller Drivers
++# I2C Algorithms
 +#
-+CONFIG_SPI_ATMEL=y
-+# CONFIG_SPI_BITBANG is not set
++# CONFIG_I2C_ALGOBIT is not set
++# CONFIG_I2C_ALGOPCF is not set
++# CONFIG_I2C_ALGOPCA is not set
 +
 +#
-+# SPI Protocol Masters
++# I2C Hardware Bus support
 +#
-+# 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 is not set
-+CONFIG_WATCHDOG=y
-+# CONFIG_WATCHDOG_NOWAYOUT is not set
++CONFIG_I2C_MSM=y
++# 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
 +
 +#
-+# Watchdog Device Drivers
++# Miscellaneous I2C Chip support
 +#
-+# CONFIG_SOFT_WATCHDOG is not set
-+CONFIG_AT32AP700X_WDT=y
++# CONFIG_SENSORS_DS1337 is not set
++# CONFIG_SENSORS_DS1374 is not set
++# CONFIG_DS1682 is not set
++# CONFIG_SENSORS_EEPROM is not set
++# CONFIG_SENSORS_PCF8574 is not set
++# CONFIG_SENSORS_PCA9539 is not set
++CONFIG_SENSORS_PCA9633=y
++# CONFIG_SENSORS_PCF8591 is not set
++# CONFIG_SENSORS_MAX6875 is not set
++CONFIG_SENSORS_AKM8976=y
++# 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
 +
 +#
-+# Sonics Silicon Backplane
++# SPI support
 +#
-+CONFIG_SSB_POSSIBLE=y
-+# CONFIG_SSB is not set
++# CONFIG_SPI is not set
++# CONFIG_SPI_MASTER is not set
++# CONFIG_W1 is not set
++# CONFIG_HWMON is not set
++CONFIG_MISC_DEVICES=y
++# CONFIG_EEPROM_93CX6 is not set
++CONFIG_LOW_MEMORY_KILLER=y
 +
 +#
 +# Multifunction device drivers
 +#
 +# CONFIG_MFD_SM501 is not set
++CONFIG_NEW_LEDS=y
++CONFIG_LEDS_CLASS=y
 +
 +#
 +# Multimedia devices
 +#
 +# CONFIG_VIDEO_DEV is not set
 +# CONFIG_DVB_CORE is not set
-+# CONFIG_DAB is not set
++CONFIG_DAB=y
 +
 +#
 +# Graphics support
 +#
++# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
++
++#
++# Display device support
++#
++# CONFIG_DISPLAY_SUPPORT is not set
 +# CONFIG_VGASTATE is not set
-+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
++CONFIG_VIDEO_OUTPUT_CONTROL=y
 +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
@@ -10305,34 +12961,42 @@
 +# 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
++CONFIG_FB_MODE_HELPERS=y
++CONFIG_FB_TILEBLITTING=y
 +
 +#
 +# Frame buffer hardware drivers
 +#
 +# CONFIG_FB_S1D13XXX is not set
-+CONFIG_FB_ATMEL=y
++CONFIG_FB_MSM=y
++# CONFIG_FB_GOLDFISH is not set
 +# CONFIG_FB_VIRTUAL is not set
-+CONFIG_BACKLIGHT_LCD_SUPPORT=y
-+CONFIG_LCD_CLASS_DEVICE=y
-+CONFIG_LCD_LTV350QV=y
-+# CONFIG_BACKLIGHT_CLASS_DEVICE is not set
 +
 +#
-+# Display device support
++# Console display driver support
 +#
-+# CONFIG_DISPLAY_SUPPORT is not set
++# 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 is not set
 +
 +#
 +# Sound
 +#
 +# CONFIG_SOUND is not set
++CONFIG_HID_SUPPORT=y
++CONFIG_HID=y
++# CONFIG_HID_DEBUG is not set
 +CONFIG_USB_SUPPORT=y
-+# CONFIG_USB_ARCH_HAS_HCD is not set
++CONFIG_USB_ARCH_HAS_HCD=y
 +# CONFIG_USB_ARCH_HAS_OHCI is not set
 +# CONFIG_USB_ARCH_HAS_EHCI is not set
++# CONFIG_USB is not set
 +
 +#
 +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
@@ -10341,140 +13005,201 @@
 +#
 +# USB Gadget Support
 +#
-+CONFIG_USB_GADGET=y
-+# 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=y
-+CONFIG_USB_ATMEL_USBA=y
-+# CONFIG_USB_GADGET_FSL_USB2 is not set
-+# CONFIG_USB_GADGET_NET2280 is not set
-+# CONFIG_USB_GADGET_PXA2XX is not set
-+# CONFIG_USB_GADGET_M66592 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=y
-+# CONFIG_USB_ZERO is not set
-+CONFIG_USB_ETH=y
-+# CONFIG_USB_ETH_RNDIS is not set
-+# CONFIG_USB_GADGETFS is not set
-+# CONFIG_USB_FILE_STORAGE is not set
-+# CONFIG_USB_G_SERIAL is not set
-+# CONFIG_USB_MIDI_GADGET 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
++# CONFIG_USB_GADGET is not set
 +
 +#
-+# RTC interfaces
++# USB Function Support
 +#
-+CONFIG_RTC_INTF_SYSFS=y
-+# CONFIG_RTC_INTF_PROC is not set
-+CONFIG_RTC_INTF_DEV=y
-+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
-+# CONFIG_RTC_DRV_TEST is not set
++CONFIG_USB_FUNCTION=y
++CONFIG_USB_FUNCTION_MSM_HSUSB=y
++# CONFIG_USB_FUNCTION_NULL is not set
++# CONFIG_USB_FUNCTION_ZERO is not set
++# CONFIG_USB_FUNCTION_LOOPBACK is not set
++CONFIG_USB_FUNCTION_ADB=y
++# CONFIG_MMC is not set
++CONFIG_RTC_LIB=y
++# CONFIG_RTC_CLASS is not set
 +
 +#
-+# SPI RTC drivers
++# DMA Engine support
 +#
-+# CONFIG_RTC_DRV_RS5C348 is not set
-+# CONFIG_RTC_DRV_MAX6902 is not set
++# CONFIG_DMA_ENGINE is not set
 +
 +#
-+# Platform RTC drivers
++# DMA Clients
 +#
-+# CONFIG_RTC_DRV_DS1553 is not set
-+# CONFIG_RTC_DRV_STK17TA8 is not set
-+# CONFIG_RTC_DRV_DS1742 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
++# DMA Devices
 +#
-+CONFIG_RTC_DRV_AT32AP700X=y
 +
 +#
-+# Userspace I/O
++# Android
 +#
-+# CONFIG_UIO is not set
++# CONFIG_ANDROID_GADGET is not set
++# CONFIG_ANDROID_RAM_CONSOLE is not set
++CONFIG_ANDROID_LOGGER=y
++CONFIG_ANDROID_VIBRATOR=y
 +
 +#
 +# File systems
 +#
-+# CONFIG_INOTIFY is not set
++# 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_GFS2_FS is not set
++# CONFIG_OCFS2_FS is not set
++# CONFIG_MINIX_FS is not set
++# CONFIG_ROMFS_FS is not set
++CONFIG_INOTIFY=y
++CONFIG_INOTIFY_USER=y
 +# CONFIG_QUOTA is not set
-+# CONFIG_DNOTIFY is not set
++CONFIG_DNOTIFY=y
 +# CONFIG_AUTOFS_FS is not set
 +# CONFIG_AUTOFS4_FS is not set
 +# CONFIG_FUSE_FS is not set
 +
 +#
++# CD-ROM/DVD Filesystems
++#
++# CONFIG_ISO9660_FS is not set
++# CONFIG_UDF_FS is not set
++
++#
++# DOS/FAT/NT Filesystems
++#
++# CONFIG_MSDOS_FS is not set
++# CONFIG_VFAT_FS is not set
++# CONFIG_NTFS_FS is not set
++
++#
 +# Pseudo filesystems
 +#
 +CONFIG_PROC_FS=y
-+CONFIG_PROC_KCORE=y
 +CONFIG_PROC_SYSCTL=y
 +CONFIG_SYSFS=y
 +CONFIG_TMPFS=y
 +# CONFIG_TMPFS_POSIX_ACL is not set
 +# CONFIG_HUGETLB_PAGE is not set
++CONFIG_RAMFS=y
 +# CONFIG_CONFIGFS_FS is not set
 +
 +#
 +# Miscellaneous filesystems
 +#
-+CONFIG_JFFS2_FS=y
-+CONFIG_JFFS2_FS_DEBUG=0
-+# CONFIG_JFFS2_FS_WRITEBUFFER 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_NETWORK_FILESYSTEMS is not set
++# 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=y
++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_CHECKPOINT_RESERVED_BLOCKS=10
++# 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 is not set
++# CONFIG_CRAMFS is not set
++# CONFIG_VXFS_FS is not set
++# CONFIG_HPFS_FS is not set
++# CONFIG_QNX4FS_FS is not set
++# CONFIG_SYSV_FS is not set
++# CONFIG_UFS_FS is not set
++
++#
++# Network File Systems
++#
++# CONFIG_NFS_FS is not set
++# CONFIG_NFSD is not set
++# CONFIG_SMB_FS is not set
++# CONFIG_CIFS is not set
++# CONFIG_NCP_FS is not set
++# CONFIG_CODA_FS is not set
++# CONFIG_AFS_FS is not set
++
++#
++# Partition Types
++#
++# CONFIG_PARTITION_ADVANCED is not set
++CONFIG_MSDOS_PARTITION=y
++
++#
++# Native Language Support
++#
 +# CONFIG_NLS is not set
++
++#
++# Distributed Lock Manager
++#
 +# CONFIG_DLM is not set
-+# CONFIG_INSTRUMENTATION is not set
++
++#
++# Profiling support
++#
++# CONFIG_PROFILING is not set
 +
 +#
 +# Kernel hacking
 +#
 +# CONFIG_PRINTK_TIME is not set
-+CONFIG_ENABLE_WARN_DEPRECATED=y
 +CONFIG_ENABLE_MUST_CHECK=y
 +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 is not set
-+# CONFIG_DEBUG_BUGVERBOSE is not set
-+# CONFIG_SAMPLES is not set
++CONFIG_DEBUG_KERNEL=y
++# CONFIG_DEBUG_SHIRQ is not set
++CONFIG_DETECT_SOFTLOCKUP=y
++CONFIG_SCHED_DEBUG=y
++CONFIG_SCHEDSTATS=y
++# CONFIG_TIMER_STATS 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=y
++# CONFIG_DEBUG_LOCK_ALLOC is not set
++# CONFIG_PROVE_LOCKING is not set
++# CONFIG_LOCK_STAT is not set
++CONFIG_DEBUG_SPINLOCK_SLEEP=y
++# 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_LIST is not set
++CONFIG_FRAME_POINTER=y
++# CONFIG_FORCED_INLINING is not set
++# CONFIG_FAULT_INJECTION is not set
++# CONFIG_DEBUG_USER is not set
++# CONFIG_DEBUG_ERRORS 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_CRC_CCITT is not set
++CONFIG_CRC_CCITT=y
 +# CONFIG_CRC16 is not set
 +# CONFIG_CRC_ITU_T is not set
 +CONFIG_CRC32=y
@@ -10482,6551 +13207,9492 @@
 +# 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/avr32/kernel/Makefile b/arch/avr32/kernel/Makefile
-index 2d6d48f..e4b6d12 100644
---- a/arch/avr32/kernel/Makefile
-+++ b/arch/avr32/kernel/Makefile
-@@ -6,9 +6,10 @@ extra-y				:= head.o vmlinux.lds
- 
- obj-$(CONFIG_SUBARCH_AVR32B)	+= entry-avr32b.o
- obj-y				+= syscall_table.o syscall-stubs.o irq.o
--obj-y				+= setup.o traps.o semaphore.o ptrace.o
-+obj-y				+= setup.o traps.o semaphore.o ocd.o ptrace.o
- obj-y				+= signal.o sys_avr32.o process.o time.o
- obj-y				+= init_task.o switch_to.o cpu.o
- obj-$(CONFIG_MODULES)		+= module.o avr32_ksyms.o
- obj-$(CONFIG_KPROBES)		+= kprobes.o
- obj-$(CONFIG_STACKTRACE)	+= stacktrace.o
-+obj-$(CONFIG_NMI_DEBUGGING)	+= nmi_debug.o
-diff --git a/arch/avr32/kernel/cpu.c b/arch/avr32/kernel/cpu.c
-index 2714cf6..b8409ca 100644
---- a/arch/avr32/kernel/cpu.c
-+++ b/arch/avr32/kernel/cpu.c
-@@ -13,6 +13,7 @@
- #include <linux/percpu.h>
- #include <linux/param.h>
- #include <linux/errno.h>
-+#include <linux/clk.h>
- 
- #include <asm/setup.h>
- #include <asm/sysreg.h>
-@@ -187,9 +188,20 @@ static int __init topology_init(void)
- 
- subsys_initcall(topology_init);
- 
-+struct chip_id_map {
-+	u16	mid;
-+	u16	pn;
-+	const char *name;
-+};
-+
-+static const struct chip_id_map chip_names[] = {
-+	{ .mid = 0x1f, .pn = 0x1e82, .name = "AT32AP700x" },
-+};
-+#define NR_CHIP_NAMES ARRAY_SIZE(chip_names)
-+
- static const char *cpu_names[] = {
- 	"Morgan",
--	"AP7000",
-+	"AP7",
- };
- #define NR_CPU_NAMES ARRAY_SIZE(cpu_names)
- 
-@@ -206,12 +218,32 @@ static const char *mmu_types[] = {
- 	"MPU"
- };
- 
-+static const char *cpu_feature_flags[] = {
-+	"rmw", "dsp", "simd", "ocd", "perfctr", "java", "fpu",
-+};
+diff --git a/arch/arm/configs/orion_defconfig b/arch/arm/configs/orion_defconfig
+new file mode 100644
+index 0000000..17a55de
+--- /dev/null
++++ b/arch/arm/configs/orion_defconfig
+@@ -0,0 +1,1384 @@
++#
++# Automatically generated make config: don't edit
++# Linux kernel version: 2.6.24-rc3
++# Wed Nov 28 15:13:57 2007
++#
++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_ZONE_DMA=y
++CONFIG_VECTORS_BASE=0xffff0000
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
 +
-+static const char *get_chip_name(struct avr32_cpuinfo *cpu)
-+{
-+	unsigned int i;
-+	unsigned int mid = avr32_get_manufacturer_id(cpu);
-+	unsigned int pn = avr32_get_product_number(cpu);
++#
++# 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=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_TASKSTATS is not set
++# CONFIG_USER_NS is not set
++# CONFIG_PID_NS is not set
++# CONFIG_AUDIT is not set
++# CONFIG_IKCONFIG is not set
++CONFIG_LOG_BUF_SHIFT=14
++# CONFIG_CGROUPS is not set
++CONFIG_FAIR_GROUP_SCHED=y
++CONFIG_FAIR_USER_SCHED=y
++# CONFIG_FAIR_CGROUP_SCHED is not set
++CONFIG_SYSFS_DEPRECATED=y
++# CONFIG_RELAY 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_EXTRA_PASS is not set
++CONFIG_HOTPLUG=y
++CONFIG_PRINTK=y
++CONFIG_BUG=y
++CONFIG_ELF_CORE=y
++CONFIG_BASE_FULL=y
++CONFIG_FUTEX=y
++CONFIG_ANON_INODES=y
++CONFIG_EPOLL=y
++CONFIG_SIGNALFD=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_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 is not set
++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
 +
-+	for (i = 0; i < NR_CHIP_NAMES; i++) {
-+		if (chip_names[i].mid == mid && chip_names[i].pn == pn)
-+			return chip_names[i].name;
-+	}
++#
++# 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"
 +
-+	return "(unknown)";
-+}
++#
++# 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_ORION=y
++# 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
 +
- void __init setup_processor(void)
- {
- 	unsigned long config0, config1;
- 	unsigned long features;
- 	unsigned cpu_id, cpu_rev, arch_id, arch_rev, mmu_type;
-+	unsigned device_id;
- 	unsigned tmp;
-+	unsigned i;
- 
- 	config0 = sysreg_read(CONFIG0);
- 	config1 = sysreg_read(CONFIG1);
-@@ -221,11 +253,14 @@ void __init setup_processor(void)
- 	arch_rev = SYSREG_BFEXT(AR, config0);
- 	mmu_type = SYSREG_BFEXT(MMUT, config0);
- 
-+	device_id = ocd_read(DID);
++#
++# Orion Implementations
++#
++CONFIG_MACH_DB88F5281=y
++CONFIG_MACH_RD88F5182=y
++CONFIG_MACH_KUROBOX_PRO=y
++CONFIG_MACH_DNS323=y
++CONFIG_MACH_TS209=y
 +
- 	boot_cpu_data.arch_type = arch_id;
- 	boot_cpu_data.cpu_type = cpu_id;
- 	boot_cpu_data.arch_revision = arch_rev;
- 	boot_cpu_data.cpu_revision = cpu_rev;
- 	boot_cpu_data.tlb_config = mmu_type;
-+	boot_cpu_data.device_id = device_id;
- 
- 	tmp = SYSREG_BFEXT(ILSZ, config1);
- 	if (tmp) {
-@@ -247,41 +282,34 @@ void __init setup_processor(void)
- 		return;
- 	}
- 
--	printk ("CPU: %s [%02x] revision %d (%s revision %d)\n",
-+	printk ("CPU: %s chip revision %c\n", get_chip_name(&boot_cpu_data),
-+			avr32_get_chip_revision(&boot_cpu_data) + 'A');
-+	printk ("CPU: %s [%02x] core revision %d (%s arch revision %d)\n",
- 		cpu_names[cpu_id], cpu_id, cpu_rev,
- 		arch_names[arch_id], arch_rev);
- 	printk ("CPU: MMU configuration: %s\n", mmu_types[mmu_type]);
- 
- 	printk ("CPU: features:");
- 	features = 0;
--	if (config0 & SYSREG_BIT(CONFIG0_R)) {
-+	if (config0 & SYSREG_BIT(CONFIG0_R))
- 		features |= AVR32_FEATURE_RMW;
--		printk(" rmw");
--	}
--	if (config0 & SYSREG_BIT(CONFIG0_D)) {
-+	if (config0 & SYSREG_BIT(CONFIG0_D))
- 		features |= AVR32_FEATURE_DSP;
--		printk(" dsp");
--	}
--	if (config0 & SYSREG_BIT(CONFIG0_S)) {
-+	if (config0 & SYSREG_BIT(CONFIG0_S))
- 		features |= AVR32_FEATURE_SIMD;
--		printk(" simd");
--	}
--	if (config0 & SYSREG_BIT(CONFIG0_O)) {
-+	if (config0 & SYSREG_BIT(CONFIG0_O))
- 		features |= AVR32_FEATURE_OCD;
--		printk(" ocd");
--	}
--	if (config0 & SYSREG_BIT(CONFIG0_P)) {
-+	if (config0 & SYSREG_BIT(CONFIG0_P))
- 		features |= AVR32_FEATURE_PCTR;
--		printk(" perfctr");
--	}
--	if (config0 & SYSREG_BIT(CONFIG0_J)) {
-+	if (config0 & SYSREG_BIT(CONFIG0_J))
- 		features |= AVR32_FEATURE_JAVA;
--		printk(" java");
--	}
--	if (config0 & SYSREG_BIT(CONFIG0_F)) {
-+	if (config0 & SYSREG_BIT(CONFIG0_F))
- 		features |= AVR32_FEATURE_FPU;
--		printk(" fpu");
--	}
++#
++# Boot options
++#
 +
-+	for (i = 0; i < ARRAY_SIZE(cpu_feature_flags); i++)
-+		if (features & (1 << i))
-+			printk(" %s", cpu_feature_flags[i]);
++#
++# Power management
++#
 +
- 	printk("\n");
- 	boot_cpu_data.features = features;
- }
-@@ -291,6 +319,8 @@ static int c_show(struct seq_file *m, void *v)
- {
- 	unsigned int icache_size, dcache_size;
- 	unsigned int cpu = smp_processor_id();
-+	unsigned int freq;
-+	unsigned int i;
- 
- 	icache_size = boot_cpu_data.icache.ways *
- 		boot_cpu_data.icache.sets *
-@@ -301,15 +331,21 @@ static int c_show(struct seq_file *m, void *v)
- 
- 	seq_printf(m, "processor\t: %d\n", cpu);
- 
-+	seq_printf(m, "chip type\t: %s revision %c\n",
-+			get_chip_name(&boot_cpu_data),
-+			avr32_get_chip_revision(&boot_cpu_data) + 'A');
- 	if (boot_cpu_data.arch_type < NR_ARCH_NAMES)
--		seq_printf(m, "cpu family\t: %s revision %d\n",
-+		seq_printf(m, "cpu arch\t: %s revision %d\n",
- 			   arch_names[boot_cpu_data.arch_type],
- 			   boot_cpu_data.arch_revision);
- 	if (boot_cpu_data.cpu_type < NR_CPU_NAMES)
--		seq_printf(m, "cpu type\t: %s revision %d\n",
-+		seq_printf(m, "cpu core\t: %s revision %d\n",
- 			   cpu_names[boot_cpu_data.cpu_type],
- 			   boot_cpu_data.cpu_revision);
- 
-+	freq = (clk_get_rate(boot_cpu_data.clk) + 500) / 1000;
-+	seq_printf(m, "cpu MHz\t\t: %u.%03u\n", freq / 1000, freq % 1000);
++#
++# Processor Type
++#
++CONFIG_CPU_32=y
++CONFIG_CPU_FEROCEON=y
++CONFIG_CPU_FEROCEON_OLD_ID=y
++CONFIG_CPU_32v5=y
++CONFIG_CPU_ABRT_EV5T=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
 +
- 	seq_printf(m, "i-cache\t\t: %dK (%u ways x %u sets x %u)\n",
- 		   icache_size >> 10,
- 		   boot_cpu_data.icache.ways,
-@@ -320,7 +356,13 @@ static int c_show(struct seq_file *m, void *v)
- 		   boot_cpu_data.dcache.ways,
- 		   boot_cpu_data.dcache.sets,
- 		   boot_cpu_data.dcache.linesz);
--	seq_printf(m, "bogomips\t: %lu.%02lu\n",
++#
++# 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_OUTER_CACHE is not set
 +
-+	seq_printf(m, "features\t:");
-+	for (i = 0; i < ARRAY_SIZE(cpu_feature_flags); i++)
-+		if (boot_cpu_data.features & (1 << i))
-+			seq_printf(m, " %s", cpu_feature_flags[i]);
++#
++# Bus support
++#
++CONFIG_PCI=y
++CONFIG_PCI_SYSCALL=y
++# CONFIG_ARCH_SUPPORTS_MSI is not set
++CONFIG_PCI_LEGACY=y
++# CONFIG_PCCARD is not set
 +
-+	seq_printf(m, "\nbogomips\t: %lu.%02lu\n",
- 		   boot_cpu_data.loops_per_jiffy / (500000/HZ),
- 		   (boot_cpu_data.loops_per_jiffy / (5000/HZ)) % 100);
- 
-@@ -343,7 +385,7 @@ static void c_stop(struct seq_file *m, void *v)
- 
- }
- 
--struct seq_operations cpuinfo_op = {
-+const struct seq_operations cpuinfo_op = {
- 	.start	= c_start,
- 	.next	= c_next,
- 	.stop	= c_stop,
-diff --git a/arch/avr32/kernel/irq.c b/arch/avr32/kernel/irq.c
-index 61f2de2..a8e767d 100644
---- a/arch/avr32/kernel/irq.c
-+++ b/arch/avr32/kernel/irq.c
-@@ -25,6 +25,17 @@ void ack_bad_irq(unsigned int irq)
- 	printk("unexpected IRQ %u\n", irq);
- }
- 
-+/* May be overridden by platform code */
-+int __weak nmi_enable(void)
-+{
-+	return -ENOSYS;
-+}
++#
++# Kernel Features
++#
++CONFIG_TICK_ONESHOT=y
++CONFIG_NO_HZ=y
++CONFIG_HIGH_RES_TIMERS=y
++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_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=y
++CONFIG_LEDS_CPU=y
++CONFIG_ALIGNMENT_TRAP=y
 +
-+void __weak nmi_disable(void)
-+{
++#
++# Boot options
++#
++CONFIG_ZBOOT_ROM_TEXT=0x0
++CONFIG_ZBOOT_ROM_BSS=0x0
++CONFIG_CMDLINE=""
++# CONFIG_XIP_KERNEL is not set
++# CONFIG_KEXEC is not set
 +
-+}
++#
++# Floating point emulation
++#
 +
- #ifdef CONFIG_PROC_FS
- int show_interrupts(struct seq_file *p, void *v)
- {
-diff --git a/arch/avr32/kernel/kprobes.c b/arch/avr32/kernel/kprobes.c
-index 799ba89..f820e9f 100644
---- a/arch/avr32/kernel/kprobes.c
-+++ b/arch/avr32/kernel/kprobes.c
-@@ -48,6 +48,7 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p)
- void __kprobes arch_arm_kprobe(struct kprobe *p)
- {
- 	pr_debug("arming kprobe at %p\n", p->addr);
-+	ocd_enable(NULL);
- 	*p->addr = BREAKPOINT_INSTRUCTION;
- 	flush_icache_range((unsigned long)p->addr,
- 			   (unsigned long)p->addr + sizeof(kprobe_opcode_t));
-@@ -56,6 +57,7 @@ void __kprobes arch_arm_kprobe(struct kprobe *p)
- void __kprobes arch_disarm_kprobe(struct kprobe *p)
- {
- 	pr_debug("disarming kprobe at %p\n", p->addr);
-+	ocd_disable(NULL);
- 	*p->addr = p->opcode;
- 	flush_icache_range((unsigned long)p->addr,
- 			   (unsigned long)p->addr + sizeof(kprobe_opcode_t));
-@@ -260,9 +262,6 @@ int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
- 
- int __init arch_init_kprobes(void)
- {
--	printk("KPROBES: Enabling monitor mode (MM|DBE)...\n");
--	ocd_write(DC, (1 << OCD_DC_MM_BIT) | (1 << OCD_DC_DBE_BIT));
--
- 	/* TODO: Register kretprobe trampoline */
- 	return 0;
- }
-diff --git a/arch/avr32/kernel/nmi_debug.c b/arch/avr32/kernel/nmi_debug.c
-new file mode 100644
-index 0000000..3414b85
---- /dev/null
-+++ b/arch/avr32/kernel/nmi_debug.c
-@@ -0,0 +1,82 @@
-+/*
-+ * 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 version 2 as
-+ * published by the Free Software Foundation.
-+ */
-+#include <linux/delay.h>
-+#include <linux/kdebug.h>
-+#include <linux/notifier.h>
-+#include <linux/sched.h>
++#
++# 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=y
 +
-+#include <asm/irq.h>
++#
++# Userspace binary formats
++#
++CONFIG_BINFMT_ELF=y
++# CONFIG_BINFMT_AOUT is not set
++# CONFIG_BINFMT_MISC is not set
 +
-+enum nmi_action {
-+	NMI_SHOW_STATE	= 1 << 0,
-+	NMI_SHOW_REGS	= 1 << 1,
-+	NMI_DIE		= 1 << 2,
-+	NMI_DEBOUNCE	= 1 << 3,
-+};
++#
++# Power management options
++#
++# CONFIG_PM is not set
++CONFIG_SUSPEND_UP_POSSIBLE=y
 +
-+static unsigned long nmi_actions;
++#
++# Networking
++#
++CONFIG_NET=y
 +
-+static int nmi_debug_notify(struct notifier_block *self,
-+		unsigned long val, void *data)
-+{
-+	struct die_args *args = data;
++#
++# 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_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=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_INET6_XFRM_TUNNEL is not set
++# CONFIG_INET6_TUNNEL 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
 +
-+	if (likely(val != DIE_NMI))
-+		return NOTIFY_DONE;
++#
++# Network testing
++#
++CONFIG_NET_PKTGEN=m
++# CONFIG_HAMRADIO is not set
++# CONFIG_IRDA is not set
++# CONFIG_BT is not set
++# CONFIG_AF_RXRPC is not set
 +
-+	if (nmi_actions & NMI_SHOW_STATE)
-+		show_state();
-+	if (nmi_actions & NMI_SHOW_REGS)
-+		show_regs(args->regs);
-+	if (nmi_actions & NMI_DEBOUNCE)
-+		mdelay(10);
-+	if (nmi_actions & NMI_DIE)
-+		return NOTIFY_BAD;
++#
++# 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
 +
-+	return NOTIFY_OK;
-+}
++#
++# Device Drivers
++#
 +
-+static struct notifier_block nmi_debug_nb = {
-+	.notifier_call = nmi_debug_notify,
-+};
++#
++# Generic Driver Options
++#
++CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
++CONFIG_STANDALONE=y
++CONFIG_PREVENT_FIRMWARE_BUILD=y
++CONFIG_FW_LOADER=y
++# 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
 +
-+static int __init nmi_debug_setup(char *str)
-+{
-+	char *p, *sep;
++#
++# User Modules And Translation Layers
++#
++CONFIG_MTD_CHAR=y
++CONFIG_MTD_BLKDEVS=y
++CONFIG_MTD_BLOCK=y
++CONFIG_FTL=y
++CONFIG_NFTL=y
++# CONFIG_NFTL_RW 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
 +
-+	register_die_notifier(&nmi_debug_nb);
-+	if (nmi_enable()) {
-+		printk(KERN_WARNING "Unable to enable NMI.\n");
-+		return 0;
-+	}
++#
++# 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=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=y
++# 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
 +
-+	if (*str != '=')
-+		return 0;
++#
++# 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=0x0
++CONFIG_MTD_PHYSMAP_BANKWIDTH=0
++# CONFIG_MTD_ARM_INTEGRATOR is not set
++# CONFIG_MTD_IMPA7 is not set
++# CONFIG_MTD_INTEL_VR_NOR is not set
++# CONFIG_MTD_PLATRAM is not set
 +
-+	for (p = str + 1; *p; p = sep + 1) {
-+		sep = strchr(p, ',');
-+		if (sep)
-+			*sep = 0;
-+		if (strcmp(p, "state") == 0)
-+			nmi_actions |= NMI_SHOW_STATE;
-+		else if (strcmp(p, "regs") == 0)
-+			nmi_actions |= NMI_SHOW_REGS;
-+		else if (strcmp(p, "debounce") == 0)
-+			nmi_actions |= NMI_DEBOUNCE;
-+		else if (strcmp(p, "die") == 0)
-+			nmi_actions |= NMI_DIE;
-+		else
-+			printk(KERN_WARNING "NMI: Unrecognized action `%s'\n",
-+				p);
-+		if (!sep)
-+			break;
-+	}
++#
++# 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
 +
-+	return 0;
-+}
-+__setup("nmi_debug", nmi_debug_setup);
-diff --git a/arch/avr32/kernel/ocd.c b/arch/avr32/kernel/ocd.c
-new file mode 100644
-index 0000000..c4f0232
---- /dev/null
-+++ b/arch/avr32/kernel/ocd.c
-@@ -0,0 +1,163 @@
-+/*
-+ * 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 version 2 as
-+ * published by the Free Software Foundation.
-+ */
-+#include <linux/init.h>
-+#include <linux/sched.h>
-+#include <linux/spinlock.h>
++#
++# 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=y
++# 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_CAFE 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_NAND_ORION=y
++# CONFIG_MTD_ONENAND is not set
 +
-+#include <asm/ocd.h>
++#
++# 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 is not set
++# CONFIG_CDROM_PKTCDVD is not set
++# CONFIG_ATA_OVER_ETH is not set
++CONFIG_MISC_DEVICES=y
++# CONFIG_PHANTOM is not set
++# CONFIG_EEPROM_93CX6 is not set
++# CONFIG_SGI_IOC4 is not set
++# CONFIG_TIFM_CORE is not set
 +
-+static long ocd_count;
-+static spinlock_t ocd_lock;
++#
++# 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
 +
-+/**
-+ * ocd_enable - enable on-chip debugging
-+ * @child: task to be debugged
-+ *
-+ * If @child is non-NULL, ocd_enable() first checks if debugging has
-+ * already been enabled for @child, and if it has, does nothing.
-+ *
-+ * If @child is NULL (e.g. when debugging the kernel), or debugging
-+ * has not already been enabled for it, ocd_enable() increments the
-+ * reference count and enables the debugging hardware.
-+ */
-+void ocd_enable(struct task_struct *child)
-+{
-+	u32 dc;
++#
++# 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=y
++# CONFIG_BLK_DEV_SR_VENDOR is not set
++CONFIG_CHR_DEV_SG=y
++# CONFIG_CHR_DEV_SCH is not set
 +
-+	if (child)
-+		pr_debug("ocd_enable: child=%s [%u]\n",
-+				child->comm, child->pid);
-+	else
-+		pr_debug("ocd_enable (no child)\n");
++#
++# 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
 +
-+	if (!child || !test_and_set_tsk_thread_flag(child, TIF_DEBUG)) {
-+		spin_lock(&ocd_lock);
-+		ocd_count++;
-+		dc = ocd_read(DC);
-+		dc |= (1 << OCD_DC_MM_BIT) | (1 << OCD_DC_DBE_BIT);
-+		ocd_write(DC, dc);
-+		spin_unlock(&ocd_lock);
-+	}
-+}
++#
++# 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_STEX is not set
++CONFIG_SCSI_MVSATA=y
 +
-+/**
-+ * ocd_disable - disable on-chip debugging
-+ * @child: task that was being debugged, but isn't anymore
-+ *
-+ * If @child is non-NULL, ocd_disable() checks if debugging is enabled
-+ * for @child, and if it isn't, does nothing.
-+ *
-+ * If @child is NULL (e.g. when debugging the kernel), or debugging is
-+ * enabled, ocd_disable() decrements the reference count, and if it
-+ * reaches zero, disables the debugging hardware.
-+ */
-+void ocd_disable(struct task_struct *child)
-+{
-+	u32 dc;
++#
++# Sata options
++#
++# CONFIG_MV_SATA_SUPPORT_ATAPI is not set
++# CONFIG_MV_SATA_ENABLE_1MB_IOS is not set
++CONFIG_SATA_NO_DEBUG=y
++# CONFIG_SATA_DEBUG_ON_ERROR is not set
++# CONFIG_SATA_FULL_DEBUG 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_ATA=m
++# CONFIG_ATA_NONSTANDARD is not set
++# CONFIG_SATA_AHCI is not set
++# 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_SIL24 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_NS87410 is not set
++# CONFIG_PATA_NS87415 is not set
++# CONFIG_PATA_OPTI is not set
++# CONFIG_PATA_OPTIDMA is not set
++# 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
 +
-+	if (!child)
-+		pr_debug("ocd_disable (no child)\n");
-+	else if (test_tsk_thread_flag(child, TIF_DEBUG))
-+		pr_debug("ocd_disable: child=%s [%u]\n",
-+				child->comm, child->pid);
++#
++# 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_IP1000 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 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=y
++# CONFIG_FEALNX is not set
++# CONFIG_NATSEMI is not set
++# CONFIG_NE2K_PCI is not set
++# CONFIG_8139CP is not set
++# CONFIG_8139TOO is not set
++# CONFIG_SIS900 is not set
++# CONFIG_EPIC100 is not set
++# CONFIG_SUNDANCE is not set
++# CONFIG_TLAN is not set
++# CONFIG_VIA_RHINE is not set
++# CONFIG_SC92031 is not set
++CONFIG_NETDEV_1000=y
++# CONFIG_ACENIC is not set
++# CONFIG_DL2K is not set
++CONFIG_E1000=y
++CONFIG_E1000_NAPI=y
++# CONFIG_E1000_DISABLE_PACKET_SPLIT is not set
++# CONFIG_E1000E is not set
++# CONFIG_NS83820 is not set
++# CONFIG_HAMACHI is not set
++# CONFIG_YELLOWFIN is not set
++# CONFIG_R8169 is not set
++# CONFIG_SIS190 is not set
++CONFIG_SKGE=y
++CONFIG_SKY2=y
++# CONFIG_SK98LIN is not set
++# CONFIG_VIA_VELOCITY is not set
++CONFIG_TIGON3=y
++# CONFIG_BNX2 is not set
++CONFIG_MV643XX_ETH=y
++# CONFIG_QLA3XXX is not set
++# CONFIG_ATL1 is not set
++CONFIG_NETDEV_10000=y
++# CONFIG_CHELSIO_T1 is not set
++# CONFIG_CHELSIO_T3 is not set
++# CONFIG_IXGBE is not set
++# CONFIG_IXGB is not set
++# CONFIG_S2IO is not set
++# CONFIG_MYRI10GE is not set
++# CONFIG_NETXEN_NIC is not set
++# CONFIG_NIU is not set
++# CONFIG_MLX4_CORE is not set
++# CONFIG_TEHUTI is not set
++# CONFIG_TR is not set
 +
-+	if (!child || test_and_clear_tsk_thread_flag(child, TIF_DEBUG)) {
-+		spin_lock(&ocd_lock);
-+		ocd_count--;
++#
++# Wireless LAN
++#
++# CONFIG_WLAN_PRE80211 is not set
++# CONFIG_WLAN_80211 is not set
 +
-+		WARN_ON(ocd_count < 0);
++#
++# 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_FDDI is not set
++# CONFIG_HIPPI is not set
++# CONFIG_PPP is not set
++# CONFIG_SLIP is not set
++# CONFIG_NET_FC is not set
++# CONFIG_SHAPER is not set
++# CONFIG_NETCONSOLE is not set
++# CONFIG_NETPOLL is not set
++# CONFIG_NET_POLL_CONTROLLER is not set
++# CONFIG_ISDN is not set
 +
-+		if (ocd_count <= 0) {
-+			dc = ocd_read(DC);
-+			dc &= ~((1 << OCD_DC_MM_BIT) | (1 << OCD_DC_DBE_BIT));
-+			ocd_write(DC, dc);
-+		}
-+		spin_unlock(&ocd_lock);
-+	}
-+}
++#
++# Input device support
++#
++CONFIG_INPUT=y
++# CONFIG_INPUT_FF_MEMLESS is not set
++# CONFIG_INPUT_POLLDEV is not set
 +
-+#ifdef CONFIG_DEBUG_FS
-+#include <linux/debugfs.h>
-+#include <linux/module.h>
++#
++# 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 is not set
++# CONFIG_INPUT_EVBUG is not set
 +
-+static struct dentry *ocd_debugfs_root;
-+static struct dentry *ocd_debugfs_DC;
-+static struct dentry *ocd_debugfs_DS;
-+static struct dentry *ocd_debugfs_count;
++#
++# 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
 +
-+static u64 ocd_DC_get(void *data)
-+{
-+	return ocd_read(DC);
-+}
-+static void ocd_DC_set(void *data, u64 val)
-+{
-+	ocd_write(DC, val);
-+}
-+DEFINE_SIMPLE_ATTRIBUTE(fops_DC, ocd_DC_get, ocd_DC_set, "0x%08llx\n");
++#
++# Hardware I/O ports
++#
++# CONFIG_SERIO is not set
++# CONFIG_GAMEPORT is not set
 +
-+static u64 ocd_DS_get(void *data)
-+{
-+	return ocd_read(DS);
-+}
-+DEFINE_SIMPLE_ATTRIBUTE(fops_DS, ocd_DS_get, NULL, "0x%08llx\n");
++#
++# Character devices
++#
++CONFIG_VT=y
++CONFIG_VT_CONSOLE=y
++CONFIG_HW_CONSOLE=y
++# CONFIG_VT_HW_CONSOLE_BINDING is not set
++# CONFIG_SERIAL_NONSTANDARD is not set
 +
-+static u64 ocd_count_get(void *data)
-+{
-+	return ocd_count;
-+}
-+DEFINE_SIMPLE_ATTRIBUTE(fops_count, ocd_count_get, NULL, "%lld\n");
++#
++# Serial drivers
++#
++CONFIG_SERIAL_8250=y
++CONFIG_SERIAL_8250_CONSOLE=y
++CONFIG_SERIAL_8250_PCI=y
++CONFIG_SERIAL_8250_NR_UARTS=4
++CONFIG_SERIAL_8250_RUNTIME_UARTS=2
++# CONFIG_SERIAL_8250_EXTENDED is not set
 +
-+static void ocd_debugfs_init(void)
-+{
-+	struct dentry *root;
++#
++# Non-8250 serial port support
++#
++CONFIG_SERIAL_CORE=y
++CONFIG_SERIAL_CORE_CONSOLE=y
++# CONFIG_SERIAL_JSM is not set
++CONFIG_UNIX98_PTYS=y
++CONFIG_LEGACY_PTYS=y
++CONFIG_LEGACY_PTY_COUNT=16
++# CONFIG_IPMI_HANDLER is not set
++CONFIG_HW_RANDOM=m
++# CONFIG_NVRAM is not set
++# CONFIG_R3964 is not set
++# CONFIG_APPLICOM 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
 +
-+	root = debugfs_create_dir("ocd", NULL);
-+	if (IS_ERR(root) || !root)
-+		goto err_root;
-+	ocd_debugfs_root = root;
++#
++# I2C Algorithms
++#
++# CONFIG_I2C_ALGOBIT is not set
++# CONFIG_I2C_ALGOPCF is not set
++# CONFIG_I2C_ALGOPCA is not set
 +
-+	ocd_debugfs_DC = debugfs_create_file("DC", S_IRUSR | S_IWUSR,
-+				root, NULL, &fops_DC);
-+	if (!ocd_debugfs_DC)
-+		goto err_DC;
++#
++# 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_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_MV64XXX=y
 +
-+	ocd_debugfs_DS = debugfs_create_file("DS", S_IRUSR, root,
-+				NULL, &fops_DS);
-+	if (!ocd_debugfs_DS)
-+		goto err_DS;
++#
++# Miscellaneous I2C Chip support
++#
++# CONFIG_SENSORS_DS1337 is not set
++# CONFIG_SENSORS_DS1374 is not set
++# CONFIG_DS1682 is not set
++# CONFIG_SENSORS_EEPROM is not set
++# CONFIG_SENSORS_PCF8574 is not set
++# CONFIG_SENSORS_PCA9539 is not set
++# CONFIG_SENSORS_PCF8591 is not set
++# CONFIG_SENSORS_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
 +
-+	ocd_debugfs_count = debugfs_create_file("count", S_IRUSR, root,
-+				NULL, &fops_count);
-+	if (!ocd_debugfs_count)
-+		goto err_count;
++#
++# SPI support
++#
++# CONFIG_SPI is not set
++# CONFIG_SPI_MASTER 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_ATXP1 is not set
++# CONFIG_SENSORS_DS1621 is not set
++# CONFIG_SENSORS_I5K_AMB 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_SIS5595 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_THMC50 is not set
++# CONFIG_SENSORS_VIA686A is not set
++# CONFIG_SENSORS_VT1211 is not set
++# CONFIG_SENSORS_VT8231 is not set
++# CONFIG_SENSORS_W83781D is not set
++# CONFIG_SENSORS_W83791D is not set
++# CONFIG_SENSORS_W83792D is not set
++# CONFIG_SENSORS_W83793 is not set
++# CONFIG_SENSORS_W83L785TS is not set
++# CONFIG_SENSORS_W83627HF is not set
++# CONFIG_SENSORS_W83627EHF is not set
++# CONFIG_HWMON_DEBUG_CHIP is not set
++# CONFIG_WATCHDOG is not set
 +
-+	return;
++#
++# Sonics Silicon Backplane
++#
++CONFIG_SSB_POSSIBLE=y
++# CONFIG_SSB is not set
 +
-+err_count:
-+	debugfs_remove(ocd_debugfs_DS);
-+err_DS:
-+	debugfs_remove(ocd_debugfs_DC);
-+err_DC:
-+	debugfs_remove(ocd_debugfs_root);
-+err_root:
-+	printk(KERN_WARNING "OCD: Failed to create debugfs entries\n");
-+}
-+#else
-+static inline void ocd_debugfs_init(void)
-+{
++#
++# Multifunction device drivers
++#
++# CONFIG_MFD_SM501 is not set
 +
-+}
-+#endif
++#
++# Multimedia devices
++#
++# CONFIG_VIDEO_DEV is not set
++# CONFIG_DVB_CORE is not set
++CONFIG_DAB=y
++# CONFIG_USB_DABUSB is not set
 +
-+static int __init ocd_init(void)
-+{
-+	spin_lock_init(&ocd_lock);
-+	ocd_debugfs_init();
-+	return 0;
-+}
-+arch_initcall(ocd_init);
-diff --git a/arch/avr32/kernel/process.c b/arch/avr32/kernel/process.c
-index 9d6dac8..eaaa69b 100644
---- a/arch/avr32/kernel/process.c
-+++ b/arch/avr32/kernel/process.c
-@@ -103,7 +103,7 @@ EXPORT_SYMBOL(kernel_thread);
-  */
- void exit_thread(void)
- {
--	/* nothing to do */
-+	ocd_disable(current);
- }
- 
- void flush_thread(void)
-@@ -345,6 +345,9 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
- 	p->thread.cpu_context.ksp = (unsigned long)childregs;
- 	p->thread.cpu_context.pc = (unsigned long)ret_from_fork;
- 
-+	if ((clone_flags & CLONE_PTRACE) && test_thread_flag(TIF_DEBUG))
-+		ocd_enable(p);
++#
++# Graphics support
++#
++# CONFIG_DRM is not set
++# CONFIG_VGASTATE is not set
++# CONFIG_VIDEO_OUTPUT_CONTROL is not set
++# CONFIG_FB is not set
++# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
 +
- 	return 0;
- }
- 
-diff --git a/arch/avr32/kernel/ptrace.c b/arch/avr32/kernel/ptrace.c
-index 002369e..1fed38f 100644
---- a/arch/avr32/kernel/ptrace.c
-+++ b/arch/avr32/kernel/ptrace.c
-@@ -58,6 +58,7 @@ void ptrace_disable(struct task_struct *child)
- {
- 	clear_tsk_thread_flag(child, TIF_SINGLE_STEP);
- 	clear_tsk_thread_flag(child, TIF_BREAKPOINT);
-+	ocd_disable(child);
- }
- 
- /*
-@@ -144,10 +145,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
- {
- 	int ret;
- 
--	pr_debug("ptrace: Enabling monitor mode...\n");
--	ocd_write(DC, ocd_read(DC) | (1 << OCD_DC_MM_BIT)
--			| (1 << OCD_DC_DBE_BIT));
--
- 	switch (request) {
- 	/* Read the word at location addr in the child process */
- 	case PTRACE_PEEKTEXT:
-diff --git a/arch/avr32/kernel/signal.c b/arch/avr32/kernel/signal.c
-index 0ec1485..5616a00 100644
---- a/arch/avr32/kernel/signal.c
-+++ b/arch/avr32/kernel/signal.c
-@@ -270,19 +270,12 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset, int syscall)
- 	if (!user_mode(regs))
- 		return 0;
- 
--	if (try_to_freeze()) {
--		signr = 0;
--		if (!signal_pending(current))
--			goto no_signal;
--	}
--
- 	if (test_thread_flag(TIF_RESTORE_SIGMASK))
- 		oldset = &current->saved_sigmask;
- 	else if (!oldset)
- 		oldset = &current->blocked;
- 
- 	signr = get_signal_to_deliver(&info, &ka, regs, NULL);
--no_signal:
- 	if (syscall) {
- 		switch (regs->r12) {
- 		case -ERESTART_RESTARTBLOCK:
-diff --git a/arch/avr32/kernel/time.c b/arch/avr32/kernel/time.c
-index 7014a35..36a46c3 100644
---- a/arch/avr32/kernel/time.c
-+++ b/arch/avr32/kernel/time.c
-@@ -214,7 +214,7 @@ void __init time_init(void)
- }
- 
- static struct sysdev_class timer_class = {
--	set_kset_name("timer"),
-+	.name = "timer",
- };
- 
- static struct sys_device timer_device = {
-diff --git a/arch/avr32/kernel/traps.c b/arch/avr32/kernel/traps.c
-index 870c075..cf6f686 100644
---- a/arch/avr32/kernel/traps.c
-+++ b/arch/avr32/kernel/traps.c
-@@ -9,6 +9,7 @@
- #include <linux/bug.h>
- #include <linux/init.h>
- #include <linux/kallsyms.h>
-+#include <linux/kdebug.h>
- #include <linux/module.h>
- #include <linux/notifier.h>
- #include <linux/sched.h>
-@@ -107,9 +108,23 @@ void _exception(long signr, struct pt_regs *regs, int code,
- 
- asmlinkage void do_nmi(unsigned long ecr, struct pt_regs *regs)
- {
--	printk(KERN_ALERT "Got Non-Maskable Interrupt, dumping regs\n");
--	show_regs_log_lvl(regs, KERN_ALERT);
--	show_stack_log_lvl(current, regs->sp, regs, KERN_ALERT);
-+	int ret;
++#
++# Display device support
++#
++# CONFIG_DISPLAY_SUPPORT is not set
 +
-+	nmi_enter();
++#
++# Console display driver support
++#
++# CONFIG_VGA_CONSOLE is not set
++CONFIG_DUMMY_CONSOLE=y
 +
-+	ret = notify_die(DIE_NMI, "NMI", regs, 0, ecr, SIGINT);
-+	switch (ret) {
-+	case NOTIFY_OK:
-+	case NOTIFY_STOP:
-+		return;
-+	case NOTIFY_BAD:
-+		die("Fatal Non-Maskable Interrupt", regs, SIGINT);
-+	default:
-+		break;
-+	}
++#
++# Sound
++#
++# CONFIG_SOUND is not set
++CONFIG_HID_SUPPORT=y
++CONFIG_HID=y
++# CONFIG_HID_DEBUG is not set
++# CONFIG_HIDRAW is not set
 +
-+	printk(KERN_ALERT "Got NMI, but nobody cared. Disabling...\n");
-+	nmi_disable();
- }
- 
- asmlinkage void do_critical_exception(unsigned long ecr, struct pt_regs *regs)
-diff --git a/arch/avr32/mach-at32ap/Kconfig b/arch/avr32/mach-at32ap/Kconfig
-index eb30783..a7bbcc8 100644
---- a/arch/avr32/mach-at32ap/Kconfig
-+++ b/arch/avr32/mach-at32ap/Kconfig
-@@ -3,9 +3,9 @@ if PLATFORM_AT32AP
- menu "Atmel AVR32 AP options"
- 
- choice
--	prompt "AT32AP7000 static memory bus width"
--	depends on CPU_AT32AP7000
--	default AP7000_16_BIT_SMC
-+	prompt "AT32AP700x static memory bus width"
-+	depends on CPU_AT32AP700X
-+	default AP700X_16_BIT_SMC
- 	help
- 	  Define the width of the AP7000 external static memory interface.
- 	  This is used to determine how to mangle the address and/or data
-@@ -15,13 +15,13 @@ choice
- 	  width for all chip selects, excluding the flash (which is using
- 	  raw access and is thus not affected by any of this.)
- 
--config AP7000_32_BIT_SMC
-+config AP700X_32_BIT_SMC
- 	bool "32 bit"
- 
--config AP7000_16_BIT_SMC
-+config AP700X_16_BIT_SMC
- 	bool "16 bit"
- 
--config AP7000_8_BIT_SMC
-+config AP700X_8_BIT_SMC
- 	bool "8 bit"
- 
- endchoice
-diff --git a/arch/avr32/mach-at32ap/Makefile b/arch/avr32/mach-at32ap/Makefile
-index a8b4450..5e9f821 100644
---- a/arch/avr32/mach-at32ap/Makefile
-+++ b/arch/avr32/mach-at32ap/Makefile
-@@ -1,4 +1,4 @@
- obj-y				+= at32ap.o clock.o intc.o extint.o pio.o hsmc.o
--obj-$(CONFIG_CPU_AT32AP7000)	+= at32ap7000.o
--obj-$(CONFIG_CPU_AT32AP7000)	+= time-tc.o
-+obj-$(CONFIG_CPU_AT32AP700X)	+= at32ap700x.o
-+obj-$(CONFIG_CPU_AT32AP700X)	+= time-tc.o
- obj-$(CONFIG_CPU_FREQ_AT32AP)	+= cpufreq.o
-diff --git a/arch/avr32/mach-at32ap/at32ap7000.c b/arch/avr32/mach-at32ap/at32ap7000.c
-deleted file mode 100644
-index 7c4388f..0000000
---- a/arch/avr32/mach-at32ap/at32ap7000.c
-+++ /dev/null
-@@ -1,1730 +0,0 @@
--/*
-- * Copyright (C) 2005-2006 Atmel 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/clk.h>
--#include <linux/fb.h>
--#include <linux/init.h>
--#include <linux/platform_device.h>
--#include <linux/dma-mapping.h>
--#include <linux/spi/spi.h>
--
--#include <asm/io.h>
--
--#include <asm/arch/at32ap7000.h>
--#include <asm/arch/board.h>
--#include <asm/arch/portmux.h>
--
--#include <video/atmel_lcdc.h>
--
--#include "clock.h"
--#include "hmatrix.h"
--#include "pio.h"
--#include "pm.h"
--
--
--#define PBMEM(base)					\
--	{						\
--		.start		= base,			\
--		.end		= base + 0x3ff,		\
--		.flags		= IORESOURCE_MEM,	\
--	}
--#define IRQ(num)					\
--	{						\
--		.start		= num,			\
--		.end		= num,			\
--		.flags		= IORESOURCE_IRQ,	\
--	}
--#define NAMED_IRQ(num, _name)				\
--	{						\
--		.start		= num,			\
--		.end		= num,			\
--		.name		= _name,		\
--		.flags		= IORESOURCE_IRQ,	\
--	}
--
--/* REVISIT these assume *every* device supports DMA, but several
-- * don't ... tc, smc, pio, rtc, watchdog, pwm, ps2, and more.
-- */
--#define DEFINE_DEV(_name, _id)					\
--static u64 _name##_id##_dma_mask = DMA_32BIT_MASK;		\
--static struct platform_device _name##_id##_device = {		\
--	.name		= #_name,				\
--	.id		= _id,					\
--	.dev		= {					\
--		.dma_mask = &_name##_id##_dma_mask,		\
--		.coherent_dma_mask = DMA_32BIT_MASK,		\
--	},							\
--	.resource	= _name##_id##_resource,		\
--	.num_resources	= ARRAY_SIZE(_name##_id##_resource),	\
--}
--#define DEFINE_DEV_DATA(_name, _id)				\
--static u64 _name##_id##_dma_mask = DMA_32BIT_MASK;		\
--static struct platform_device _name##_id##_device = {		\
--	.name		= #_name,				\
--	.id		= _id,					\
--	.dev		= {					\
--		.dma_mask = &_name##_id##_dma_mask,		\
--		.platform_data	= &_name##_id##_data,		\
--		.coherent_dma_mask = DMA_32BIT_MASK,		\
--	},							\
--	.resource	= _name##_id##_resource,		\
--	.num_resources	= ARRAY_SIZE(_name##_id##_resource),	\
--}
--
--#define select_peripheral(pin, periph, flags)			\
--	at32_select_periph(GPIO_PIN_##pin, GPIO_##periph, flags)
--
--#define DEV_CLK(_name, devname, bus, _index)			\
--static struct clk devname##_##_name = {				\
--	.name		= #_name,				\
--	.dev		= &devname##_device.dev,		\
--	.parent		= &bus##_clk,				\
--	.mode		= bus##_clk_mode,			\
--	.get_rate	= bus##_clk_get_rate,			\
--	.index		= _index,				\
--}
--
--static DEFINE_SPINLOCK(pm_lock);
--
--unsigned long at32ap7000_osc_rates[3] = {
--	[0] = 32768,
--	/* FIXME: these are ATSTK1002-specific */
--	[1] = 20000000,
--	[2] = 12000000,
--};
--
--static unsigned long osc_get_rate(struct clk *clk)
--{
--	return at32ap7000_osc_rates[clk->index];
--}
--
--static unsigned long pll_get_rate(struct clk *clk, unsigned long control)
--{
--	unsigned long div, mul, rate;
--
--	if (!(control & PM_BIT(PLLEN)))
--		return 0;
--
--	div = PM_BFEXT(PLLDIV, control) + 1;
--	mul = PM_BFEXT(PLLMUL, control) + 1;
--
--	rate = clk->parent->get_rate(clk->parent);
--	rate = (rate + div / 2) / div;
--	rate *= mul;
--
--	return rate;
--}
--
--static unsigned long pll0_get_rate(struct clk *clk)
--{
--	u32 control;
--
--	control = pm_readl(PLL0);
--
--	return pll_get_rate(clk, control);
--}
--
--static unsigned long pll1_get_rate(struct clk *clk)
--{
--	u32 control;
--
--	control = pm_readl(PLL1);
--
--	return pll_get_rate(clk, control);
--}
--
--/*
-- * The AT32AP7000 has five primary clock sources: One 32kHz
-- * oscillator, two crystal oscillators and two PLLs.
-- */
--static struct clk osc32k = {
--	.name		= "osc32k",
--	.get_rate	= osc_get_rate,
--	.users		= 1,
--	.index		= 0,
--};
--static struct clk osc0 = {
--	.name		= "osc0",
--	.get_rate	= osc_get_rate,
--	.users		= 1,
--	.index		= 1,
--};
--static struct clk osc1 = {
--	.name		= "osc1",
--	.get_rate	= osc_get_rate,
--	.index		= 2,
--};
--static struct clk pll0 = {
--	.name		= "pll0",
--	.get_rate	= pll0_get_rate,
--	.parent		= &osc0,
--};
--static struct clk pll1 = {
--	.name		= "pll1",
--	.get_rate	= pll1_get_rate,
--	.parent		= &osc0,
--};
--
--/*
-- * The main clock can be either osc0 or pll0.  The boot loader may
-- * have chosen one for us, so we don't really know which one until we
-- * have a look at the SM.
-- */
--static struct clk *main_clock;
--
--/*
-- * Synchronous clocks are generated from the main clock. The clocks
-- * must satisfy the constraint
-- *   fCPU >= fHSB >= fPB
-- * i.e. each clock must not be faster than its parent.
-- */
--static unsigned long bus_clk_get_rate(struct clk *clk, unsigned int shift)
--{
--	return main_clock->get_rate(main_clock) >> shift;
--};
--
--static void cpu_clk_mode(struct clk *clk, int enabled)
--{
--	unsigned long flags;
--	u32 mask;
--
--	spin_lock_irqsave(&pm_lock, flags);
--	mask = pm_readl(CPU_MASK);
--	if (enabled)
--		mask |= 1 << clk->index;
--	else
--		mask &= ~(1 << clk->index);
--	pm_writel(CPU_MASK, mask);
--	spin_unlock_irqrestore(&pm_lock, flags);
--}
--
--static unsigned long cpu_clk_get_rate(struct clk *clk)
--{
--	unsigned long cksel, shift = 0;
--
--	cksel = pm_readl(CKSEL);
--	if (cksel & PM_BIT(CPUDIV))
--		shift = PM_BFEXT(CPUSEL, cksel) + 1;
--
--	return bus_clk_get_rate(clk, shift);
--}
--
--static long cpu_clk_set_rate(struct clk *clk, unsigned long rate, int apply)
--{
--	u32 control;
--	unsigned long parent_rate, child_div, actual_rate, div;
--
--	parent_rate = clk->parent->get_rate(clk->parent);
--	control = pm_readl(CKSEL);
--
--	if (control & PM_BIT(HSBDIV))
--		child_div = 1 << (PM_BFEXT(HSBSEL, control) + 1);
--	else
--		child_div = 1;
--
--	if (rate > 3 * (parent_rate / 4) || child_div == 1) {
--		actual_rate = parent_rate;
--		control &= ~PM_BIT(CPUDIV);
--	} else {
--		unsigned int cpusel;
--		div = (parent_rate + rate / 2) / rate;
--		if (div > child_div)
--			div = child_div;
--		cpusel = (div > 1) ? (fls(div) - 2) : 0;
--		control = PM_BIT(CPUDIV) | PM_BFINS(CPUSEL, cpusel, control);
--		actual_rate = parent_rate / (1 << (cpusel + 1));
--	}
--
--	pr_debug("clk %s: new rate %lu (actual rate %lu)\n",
--			clk->name, rate, actual_rate);
--
--	if (apply)
--		pm_writel(CKSEL, control);
--
--	return actual_rate;
--}
--
--static void hsb_clk_mode(struct clk *clk, int enabled)
--{
--	unsigned long flags;
--	u32 mask;
--
--	spin_lock_irqsave(&pm_lock, flags);
--	mask = pm_readl(HSB_MASK);
--	if (enabled)
--		mask |= 1 << clk->index;
--	else
--		mask &= ~(1 << clk->index);
--	pm_writel(HSB_MASK, mask);
--	spin_unlock_irqrestore(&pm_lock, flags);
--}
--
--static unsigned long hsb_clk_get_rate(struct clk *clk)
--{
--	unsigned long cksel, shift = 0;
--
--	cksel = pm_readl(CKSEL);
--	if (cksel & PM_BIT(HSBDIV))
--		shift = PM_BFEXT(HSBSEL, cksel) + 1;
--
--	return bus_clk_get_rate(clk, shift);
--}
--
--static void pba_clk_mode(struct clk *clk, int enabled)
--{
--	unsigned long flags;
--	u32 mask;
--
--	spin_lock_irqsave(&pm_lock, flags);
--	mask = pm_readl(PBA_MASK);
--	if (enabled)
--		mask |= 1 << clk->index;
--	else
--		mask &= ~(1 << clk->index);
--	pm_writel(PBA_MASK, mask);
--	spin_unlock_irqrestore(&pm_lock, flags);
--}
--
--static unsigned long pba_clk_get_rate(struct clk *clk)
--{
--	unsigned long cksel, shift = 0;
--
--	cksel = pm_readl(CKSEL);
--	if (cksel & PM_BIT(PBADIV))
--		shift = PM_BFEXT(PBASEL, cksel) + 1;
--
--	return bus_clk_get_rate(clk, shift);
--}
--
--static void pbb_clk_mode(struct clk *clk, int enabled)
--{
--	unsigned long flags;
--	u32 mask;
--
--	spin_lock_irqsave(&pm_lock, flags);
--	mask = pm_readl(PBB_MASK);
--	if (enabled)
--		mask |= 1 << clk->index;
--	else
--		mask &= ~(1 << clk->index);
--	pm_writel(PBB_MASK, mask);
--	spin_unlock_irqrestore(&pm_lock, flags);
--}
--
--static unsigned long pbb_clk_get_rate(struct clk *clk)
--{
--	unsigned long cksel, shift = 0;
--
--	cksel = pm_readl(CKSEL);
--	if (cksel & PM_BIT(PBBDIV))
--		shift = PM_BFEXT(PBBSEL, cksel) + 1;
--
--	return bus_clk_get_rate(clk, shift);
--}
--
--static struct clk cpu_clk = {
--	.name		= "cpu",
--	.get_rate	= cpu_clk_get_rate,
--	.set_rate	= cpu_clk_set_rate,
--	.users		= 1,
--};
--static struct clk hsb_clk = {
--	.name		= "hsb",
--	.parent		= &cpu_clk,
--	.get_rate	= hsb_clk_get_rate,
--};
--static struct clk pba_clk = {
--	.name		= "pba",
--	.parent		= &hsb_clk,
--	.mode		= hsb_clk_mode,
--	.get_rate	= pba_clk_get_rate,
--	.index		= 1,
--};
--static struct clk pbb_clk = {
--	.name		= "pbb",
--	.parent		= &hsb_clk,
--	.mode		= hsb_clk_mode,
--	.get_rate	= pbb_clk_get_rate,
--	.users		= 1,
--	.index		= 2,
--};
--
--/* --------------------------------------------------------------------
-- *  Generic Clock operations
-- * -------------------------------------------------------------------- */
--
--static void genclk_mode(struct clk *clk, int enabled)
--{
--	u32 control;
--
--	control = pm_readl(GCCTRL(clk->index));
--	if (enabled)
--		control |= PM_BIT(CEN);
--	else
--		control &= ~PM_BIT(CEN);
--	pm_writel(GCCTRL(clk->index), control);
--}
--
--static unsigned long genclk_get_rate(struct clk *clk)
--{
--	u32 control;
--	unsigned long div = 1;
--
--	control = pm_readl(GCCTRL(clk->index));
--	if (control & PM_BIT(DIVEN))
--		div = 2 * (PM_BFEXT(DIV, control) + 1);
--
--	return clk->parent->get_rate(clk->parent) / div;
--}
--
--static long genclk_set_rate(struct clk *clk, unsigned long rate, int apply)
--{
--	u32 control;
--	unsigned long parent_rate, actual_rate, div;
--
--	parent_rate = clk->parent->get_rate(clk->parent);
--	control = pm_readl(GCCTRL(clk->index));
--
--	if (rate > 3 * parent_rate / 4) {
--		actual_rate = parent_rate;
--		control &= ~PM_BIT(DIVEN);
--	} else {
--		div = (parent_rate + rate) / (2 * rate) - 1;
--		control = PM_BFINS(DIV, div, control) | PM_BIT(DIVEN);
--		actual_rate = parent_rate / (2 * (div + 1));
--	}
--
--	dev_dbg(clk->dev, "clk %s: new rate %lu (actual rate %lu)\n",
--		clk->name, rate, actual_rate);
--
--	if (apply)
--		pm_writel(GCCTRL(clk->index), control);
--
--	return actual_rate;
--}
--
--int genclk_set_parent(struct clk *clk, struct clk *parent)
--{
--	u32 control;
--
--	dev_dbg(clk->dev, "clk %s: new parent %s (was %s)\n",
--		clk->name, parent->name, clk->parent->name);
--
--	control = pm_readl(GCCTRL(clk->index));
--
--	if (parent == &osc1 || parent == &pll1)
--		control |= PM_BIT(OSCSEL);
--	else if (parent == &osc0 || parent == &pll0)
--		control &= ~PM_BIT(OSCSEL);
--	else
--		return -EINVAL;
--
--	if (parent == &pll0 || parent == &pll1)
--		control |= PM_BIT(PLLSEL);
--	else
--		control &= ~PM_BIT(PLLSEL);
--
--	pm_writel(GCCTRL(clk->index), control);
--	clk->parent = parent;
--
--	return 0;
--}
--
--static void __init genclk_init_parent(struct clk *clk)
--{
--	u32 control;
--	struct clk *parent;
--
--	BUG_ON(clk->index > 7);
--
--	control = pm_readl(GCCTRL(clk->index));
--	if (control & PM_BIT(OSCSEL))
--		parent = (control & PM_BIT(PLLSEL)) ? &pll1 : &osc1;
--	else
--		parent = (control & PM_BIT(PLLSEL)) ? &pll0 : &osc0;
--
--	clk->parent = parent;
--}
--
--/* --------------------------------------------------------------------
-- *  System peripherals
-- * -------------------------------------------------------------------- */
--static struct resource at32_pm0_resource[] = {
--	{
--		.start	= 0xfff00000,
--		.end	= 0xfff0007f,
--		.flags	= IORESOURCE_MEM,
--	},
--	IRQ(20),
--};
--
--static struct resource at32ap700x_rtc0_resource[] = {
--	{
--		.start	= 0xfff00080,
--		.end	= 0xfff000af,
--		.flags	= IORESOURCE_MEM,
--	},
--	IRQ(21),
--};
--
--static struct resource at32_wdt0_resource[] = {
--	{
--		.start	= 0xfff000b0,
--		.end	= 0xfff000cf,
--		.flags	= IORESOURCE_MEM,
--	},
--};
--
--static struct resource at32_eic0_resource[] = {
--	{
--		.start	= 0xfff00100,
--		.end	= 0xfff0013f,
--		.flags	= IORESOURCE_MEM,
--	},
--	IRQ(19),
--};
--
--DEFINE_DEV(at32_pm, 0);
--DEFINE_DEV(at32ap700x_rtc, 0);
--DEFINE_DEV(at32_wdt, 0);
--DEFINE_DEV(at32_eic, 0);
--
--/*
-- * Peripheral clock for PM, RTC, WDT and EIC. PM will ensure that this
-- * is always running.
-- */
--static struct clk at32_pm_pclk = {
--	.name		= "pclk",
--	.dev		= &at32_pm0_device.dev,
--	.parent		= &pbb_clk,
--	.mode		= pbb_clk_mode,
--	.get_rate	= pbb_clk_get_rate,
--	.users		= 1,
--	.index		= 0,
--};
--
--static struct resource intc0_resource[] = {
--	PBMEM(0xfff00400),
--};
--struct platform_device at32_intc0_device = {
--	.name		= "intc",
--	.id		= 0,
--	.resource	= intc0_resource,
--	.num_resources	= ARRAY_SIZE(intc0_resource),
--};
--DEV_CLK(pclk, at32_intc0, pbb, 1);
--
--static struct clk ebi_clk = {
--	.name		= "ebi",
--	.parent		= &hsb_clk,
--	.mode		= hsb_clk_mode,
--	.get_rate	= hsb_clk_get_rate,
--	.users		= 1,
--};
--static struct clk hramc_clk = {
--	.name		= "hramc",
--	.parent		= &hsb_clk,
--	.mode		= hsb_clk_mode,
--	.get_rate	= hsb_clk_get_rate,
--	.users		= 1,
--	.index		= 3,
--};
--
--static struct resource smc0_resource[] = {
--	PBMEM(0xfff03400),
--};
--DEFINE_DEV(smc, 0);
--DEV_CLK(pclk, smc0, pbb, 13);
--DEV_CLK(mck, smc0, hsb, 0);
--
--static struct platform_device pdc_device = {
--	.name		= "pdc",
--	.id		= 0,
--};
--DEV_CLK(hclk, pdc, hsb, 4);
--DEV_CLK(pclk, pdc, pba, 16);
--
--static struct clk pico_clk = {
--	.name		= "pico",
--	.parent		= &cpu_clk,
--	.mode		= cpu_clk_mode,
--	.get_rate	= cpu_clk_get_rate,
--	.users		= 1,
--};
--
--static struct resource dmaca0_resource[] = {
--	{
--		.start	= 0xff200000,
--		.end	= 0xff20ffff,
--		.flags	= IORESOURCE_MEM,
--	},
--	IRQ(2),
--};
--DEFINE_DEV(dmaca, 0);
--DEV_CLK(hclk, dmaca0, hsb, 10);
--
--/* --------------------------------------------------------------------
-- * HMATRIX
-- * -------------------------------------------------------------------- */
--
--static struct clk hmatrix_clk = {
--	.name		= "hmatrix_clk",
--	.parent		= &pbb_clk,
--	.mode		= pbb_clk_mode,
--	.get_rate	= pbb_clk_get_rate,
--	.index		= 2,
--	.users		= 1,
--};
--#define HMATRIX_BASE	((void __iomem *)0xfff00800)
--
--#define hmatrix_readl(reg)					\
--	__raw_readl((HMATRIX_BASE) + HMATRIX_##reg)
--#define hmatrix_writel(reg,value)				\
--	__raw_writel((value), (HMATRIX_BASE) + HMATRIX_##reg)
--
--/*
-- * Set bits in the HMATRIX Special Function Register (SFR) used by the
-- * External Bus Interface (EBI). This can be used to enable special
-- * features like CompactFlash support, NAND Flash support, etc. on
-- * certain chipselects.
-- */
--static inline void set_ebi_sfr_bits(u32 mask)
--{
--	u32 sfr;
--
--	clk_enable(&hmatrix_clk);
--	sfr = hmatrix_readl(SFR4);
--	sfr |= mask;
--	hmatrix_writel(SFR4, sfr);
--	clk_disable(&hmatrix_clk);
--}
--
--/* --------------------------------------------------------------------
-- *  System Timer/Counter (TC)
-- * -------------------------------------------------------------------- */
--static struct resource at32_systc0_resource[] = {
--	PBMEM(0xfff00c00),
--	IRQ(22),
--};
--struct platform_device at32_systc0_device = {
--	.name		= "systc",
--	.id		= 0,
--	.resource	= at32_systc0_resource,
--	.num_resources	= ARRAY_SIZE(at32_systc0_resource),
--};
--DEV_CLK(pclk, at32_systc0, pbb, 3);
--
--/* --------------------------------------------------------------------
-- *  PIO
-- * -------------------------------------------------------------------- */
--
--static struct resource pio0_resource[] = {
--	PBMEM(0xffe02800),
--	IRQ(13),
--};
--DEFINE_DEV(pio, 0);
--DEV_CLK(mck, pio0, pba, 10);
--
--static struct resource pio1_resource[] = {
--	PBMEM(0xffe02c00),
--	IRQ(14),
--};
--DEFINE_DEV(pio, 1);
--DEV_CLK(mck, pio1, pba, 11);
--
--static struct resource pio2_resource[] = {
--	PBMEM(0xffe03000),
--	IRQ(15),
--};
--DEFINE_DEV(pio, 2);
--DEV_CLK(mck, pio2, pba, 12);
--
--static struct resource pio3_resource[] = {
--	PBMEM(0xffe03400),
--	IRQ(16),
--};
--DEFINE_DEV(pio, 3);
--DEV_CLK(mck, pio3, pba, 13);
--
--static struct resource pio4_resource[] = {
--	PBMEM(0xffe03800),
--	IRQ(17),
--};
--DEFINE_DEV(pio, 4);
--DEV_CLK(mck, pio4, pba, 14);
--
--void __init at32_add_system_devices(void)
--{
--	platform_device_register(&at32_pm0_device);
--	platform_device_register(&at32_intc0_device);
--	platform_device_register(&at32ap700x_rtc0_device);
--	platform_device_register(&at32_wdt0_device);
--	platform_device_register(&at32_eic0_device);
--	platform_device_register(&smc0_device);
--	platform_device_register(&pdc_device);
--	platform_device_register(&dmaca0_device);
--
--	platform_device_register(&at32_systc0_device);
--
--	platform_device_register(&pio0_device);
--	platform_device_register(&pio1_device);
--	platform_device_register(&pio2_device);
--	platform_device_register(&pio3_device);
--	platform_device_register(&pio4_device);
--}
--
--/* --------------------------------------------------------------------
-- *  USART
-- * -------------------------------------------------------------------- */
--
--static struct atmel_uart_data atmel_usart0_data = {
--	.use_dma_tx	= 1,
--	.use_dma_rx	= 1,
--};
--static struct resource atmel_usart0_resource[] = {
--	PBMEM(0xffe00c00),
--	IRQ(6),
--};
--DEFINE_DEV_DATA(atmel_usart, 0);
--DEV_CLK(usart, atmel_usart0, pba, 3);
--
--static struct atmel_uart_data atmel_usart1_data = {
--	.use_dma_tx	= 1,
--	.use_dma_rx	= 1,
--};
--static struct resource atmel_usart1_resource[] = {
--	PBMEM(0xffe01000),
--	IRQ(7),
--};
--DEFINE_DEV_DATA(atmel_usart, 1);
--DEV_CLK(usart, atmel_usart1, pba, 4);
--
--static struct atmel_uart_data atmel_usart2_data = {
--	.use_dma_tx	= 1,
--	.use_dma_rx	= 1,
--};
--static struct resource atmel_usart2_resource[] = {
--	PBMEM(0xffe01400),
--	IRQ(8),
--};
--DEFINE_DEV_DATA(atmel_usart, 2);
--DEV_CLK(usart, atmel_usart2, pba, 5);
--
--static struct atmel_uart_data atmel_usart3_data = {
--	.use_dma_tx	= 1,
--	.use_dma_rx	= 1,
--};
--static struct resource atmel_usart3_resource[] = {
--	PBMEM(0xffe01800),
--	IRQ(9),
--};
--DEFINE_DEV_DATA(atmel_usart, 3);
--DEV_CLK(usart, atmel_usart3, pba, 6);
--
--static inline void configure_usart0_pins(void)
--{
--	select_peripheral(PA(8),  PERIPH_B, 0);	/* RXD	*/
--	select_peripheral(PA(9),  PERIPH_B, 0);	/* TXD	*/
--}
--
--static inline void configure_usart1_pins(void)
--{
--	select_peripheral(PA(17), PERIPH_A, 0);	/* RXD	*/
--	select_peripheral(PA(18), PERIPH_A, 0);	/* TXD	*/
--}
--
--static inline void configure_usart2_pins(void)
--{
--	select_peripheral(PB(26), PERIPH_B, 0);	/* RXD	*/
--	select_peripheral(PB(27), PERIPH_B, 0);	/* TXD	*/
--}
--
--static inline void configure_usart3_pins(void)
--{
--	select_peripheral(PB(18), PERIPH_B, 0);	/* RXD	*/
--	select_peripheral(PB(17), PERIPH_B, 0);	/* TXD	*/
--}
--
--static struct platform_device *__initdata at32_usarts[4];
--
--void __init at32_map_usart(unsigned int hw_id, unsigned int line)
--{
--	struct platform_device *pdev;
--
--	switch (hw_id) {
--	case 0:
--		pdev = &atmel_usart0_device;
--		configure_usart0_pins();
--		break;
--	case 1:
--		pdev = &atmel_usart1_device;
--		configure_usart1_pins();
--		break;
--	case 2:
--		pdev = &atmel_usart2_device;
--		configure_usart2_pins();
--		break;
--	case 3:
--		pdev = &atmel_usart3_device;
--		configure_usart3_pins();
--		break;
--	default:
--		return;
--	}
--
--	if (PXSEG(pdev->resource[0].start) == P4SEG) {
--		/* Addresses in the P4 segment are permanently mapped 1:1 */
--		struct atmel_uart_data *data = pdev->dev.platform_data;
--		data->regs = (void __iomem *)pdev->resource[0].start;
--	}
--
--	pdev->id = line;
--	at32_usarts[line] = pdev;
--}
--
--struct platform_device *__init at32_add_device_usart(unsigned int id)
--{
--	platform_device_register(at32_usarts[id]);
--	return at32_usarts[id];
--}
--
--struct platform_device *atmel_default_console_device;
--
--void __init at32_setup_serial_console(unsigned int usart_id)
--{
--	atmel_default_console_device = at32_usarts[usart_id];
--}
--
--/* --------------------------------------------------------------------
-- *  Ethernet
-- * -------------------------------------------------------------------- */
--
--static struct eth_platform_data macb0_data;
--static struct resource macb0_resource[] = {
--	PBMEM(0xfff01800),
--	IRQ(25),
--};
--DEFINE_DEV_DATA(macb, 0);
--DEV_CLK(hclk, macb0, hsb, 8);
--DEV_CLK(pclk, macb0, pbb, 6);
--
--static struct eth_platform_data macb1_data;
--static struct resource macb1_resource[] = {
--	PBMEM(0xfff01c00),
--	IRQ(26),
--};
--DEFINE_DEV_DATA(macb, 1);
--DEV_CLK(hclk, macb1, hsb, 9);
--DEV_CLK(pclk, macb1, pbb, 7);
--
--struct platform_device *__init
--at32_add_device_eth(unsigned int id, struct eth_platform_data *data)
--{
--	struct platform_device *pdev;
--
--	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	*/
--
--		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	*/
--		}
--		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	*/
--
--		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	*/
--		}
--		break;
--
--	default:
--		return NULL;
--	}
--
--	memcpy(pdev->dev.platform_data, data, sizeof(struct eth_platform_data));
--	platform_device_register(pdev);
--
--	return pdev;
--}
--
--/* --------------------------------------------------------------------
-- *  SPI
-- * -------------------------------------------------------------------- */
--static struct resource atmel_spi0_resource[] = {
--	PBMEM(0xffe00000),
--	IRQ(3),
--};
--DEFINE_DEV(atmel_spi, 0);
--DEV_CLK(spi_clk, atmel_spi0, pba, 0);
--
--static struct resource atmel_spi1_resource[] = {
--	PBMEM(0xffe00400),
--	IRQ(4),
--};
--DEFINE_DEV(atmel_spi, 1);
--DEV_CLK(spi_clk, atmel_spi1, pba, 1);
--
--static void __init
--at32_spi_setup_slaves(unsigned int bus_num, struct spi_board_info *b,
--		      unsigned int n, const u8 *pins)
--{
--	unsigned int pin, mode;
--
--	for (; n; n--, b++) {
--		b->bus_num = bus_num;
--		if (b->chip_select >= 4)
--			continue;
--		pin = (unsigned)b->controller_data;
--		if (!pin) {
--			pin = pins[b->chip_select];
--			b->controller_data = (void *)pin;
--		}
--		mode = AT32_GPIOF_OUTPUT;
--		if (!(b->mode & SPI_CS_HIGH))
--			mode |= AT32_GPIOF_HIGH;
--		at32_select_gpio(pin, mode);
--	}
--}
--
--struct platform_device *__init
--at32_add_device_spi(unsigned int id, struct spi_board_info *b, unsigned int n)
--{
--	/*
--	 * Manage the chipselects as GPIOs, normally using the same pins
--	 * the SPI controller expects; but boards can use other pins.
--	 */
--	static u8 __initdata spi0_pins[] =
--		{ GPIO_PIN_PA(3), GPIO_PIN_PA(4),
--		  GPIO_PIN_PA(5), GPIO_PIN_PA(20), };
--	static u8 __initdata spi1_pins[] =
--		{ GPIO_PIN_PB(2), GPIO_PIN_PB(3),
--		  GPIO_PIN_PB(4), GPIO_PIN_PA(27), };
--	struct platform_device *pdev;
--
--	switch (id) {
--	case 0:
--		pdev = &atmel_spi0_device;
--		select_peripheral(PA(0),  PERIPH_A, 0);	/* MISO	 */
--		select_peripheral(PA(1),  PERIPH_A, 0);	/* MOSI	 */
--		select_peripheral(PA(2),  PERIPH_A, 0);	/* SCK	 */
--		at32_spi_setup_slaves(0, b, n, spi0_pins);
--		break;
--
--	case 1:
--		pdev = &atmel_spi1_device;
--		select_peripheral(PB(0),  PERIPH_B, 0);	/* MISO  */
--		select_peripheral(PB(1),  PERIPH_B, 0);	/* MOSI  */
--		select_peripheral(PB(5),  PERIPH_B, 0);	/* SCK   */
--		at32_spi_setup_slaves(1, b, n, spi1_pins);
--		break;
--
--	default:
--		return NULL;
--	}
--
--	spi_register_board_info(b, n);
--	platform_device_register(pdev);
--	return pdev;
--}
--
--/* --------------------------------------------------------------------
-- *  TWI
-- * -------------------------------------------------------------------- */
--static struct resource atmel_twi0_resource[] __initdata = {
--	PBMEM(0xffe00800),
--	IRQ(5),
--};
--static struct clk atmel_twi0_pclk = {
--	.name		= "twi_pclk",
--	.parent		= &pba_clk,
--	.mode		= pba_clk_mode,
--	.get_rate	= pba_clk_get_rate,
--	.index		= 2,
--};
--
--struct platform_device *__init at32_add_device_twi(unsigned int id)
--{
--	struct platform_device *pdev;
--
--	if (id != 0)
--		return NULL;
--
--	pdev = platform_device_alloc("atmel_twi", id);
--	if (!pdev)
--		return NULL;
--
--	if (platform_device_add_resources(pdev, atmel_twi0_resource,
--				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	*/
--
--	atmel_twi0_pclk.dev = &pdev->dev;
--
--	platform_device_add(pdev);
--	return pdev;
--
--err_add_resources:
--	platform_device_put(pdev);
--	return NULL;
--}
--
--/* --------------------------------------------------------------------
-- * MMC
-- * -------------------------------------------------------------------- */
--static struct resource atmel_mci0_resource[] __initdata = {
--	PBMEM(0xfff02400),
--	IRQ(28),
--};
--static struct clk atmel_mci0_pclk = {
--	.name		= "mci_clk",
--	.parent		= &pbb_clk,
--	.mode		= pbb_clk_mode,
--	.get_rate	= pbb_clk_get_rate,
--	.index		= 9,
--};
--
--struct platform_device *__init at32_add_device_mci(unsigned int id)
--{
--	struct platform_device *pdev;
--
--	if (id != 0)
--		return NULL;
--
--	pdev = platform_device_alloc("atmel_mci", id);
--	if (!pdev)
--		return NULL;
--
--	if (platform_device_add_resources(pdev, atmel_mci0_resource,
--				ARRAY_SIZE(atmel_mci0_resource)))
--		goto err_add_resources;
--
--	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 */
--
--	atmel_mci0_pclk.dev = &pdev->dev;
--
--	platform_device_add(pdev);
--	return pdev;
--
--err_add_resources:
--	platform_device_put(pdev);
--	return NULL;
--}
--
--/* --------------------------------------------------------------------
-- *  LCDC
-- * -------------------------------------------------------------------- */
--static struct atmel_lcdfb_info atmel_lcdfb0_data;
--static struct resource atmel_lcdfb0_resource[] = {
--	{
--		.start		= 0xff000000,
--		.end		= 0xff000fff,
--		.flags		= IORESOURCE_MEM,
--	},
--	IRQ(1),
--	{
--		/* Placeholder for pre-allocated fb memory */
--		.start		= 0x00000000,
--		.end		= 0x00000000,
--		.flags		= 0,
--	},
--};
--DEFINE_DEV_DATA(atmel_lcdfb, 0);
--DEV_CLK(hck1, atmel_lcdfb0, hsb, 7);
--static struct clk atmel_lcdfb0_pixclk = {
--	.name		= "lcdc_clk",
--	.dev		= &atmel_lcdfb0_device.dev,
--	.mode		= genclk_mode,
--	.get_rate	= genclk_get_rate,
--	.set_rate	= genclk_set_rate,
--	.set_parent	= genclk_set_parent,
--	.index		= 7,
--};
--
--struct platform_device *__init
--at32_add_device_lcdc(unsigned int id, struct atmel_lcdfb_info *data,
--		     unsigned long fbmem_start, unsigned long fbmem_len)
--{
--	struct platform_device *pdev;
--	struct atmel_lcdfb_info *info;
--	struct fb_monspecs *monspecs;
--	struct fb_videomode *modedb;
--	unsigned int modedb_size;
--
--	/*
--	 * Do a deep copy of the fb data, monspecs and modedb. Make
--	 * sure all allocations are done before setting up the
--	 * portmux.
--	 */
--	monspecs = kmemdup(data->default_monspecs,
--			   sizeof(struct fb_monspecs), GFP_KERNEL);
--	if (!monspecs)
--		return NULL;
--
--	modedb_size = sizeof(struct fb_videomode) * monspecs->modedb_len;
--	modedb = kmemdup(monspecs->modedb, modedb_size, GFP_KERNEL);
--	if (!modedb)
--		goto err_dup_modedb;
--	monspecs->modedb = modedb;
--
--	switch (id) {
--	case 0:
--		pdev = &atmel_lcdfb0_device;
--		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 */
--
--		clk_set_parent(&atmel_lcdfb0_pixclk, &pll0);
--		clk_set_rate(&atmel_lcdfb0_pixclk, clk_get_rate(&pll0));
--		break;
--
--	default:
--		goto err_invalid_id;
--	}
--
--	if (fbmem_len) {
--		pdev->resource[2].start = fbmem_start;
--		pdev->resource[2].end = fbmem_start + fbmem_len - 1;
--		pdev->resource[2].flags = IORESOURCE_MEM;
--	}
--
--	info = pdev->dev.platform_data;
--	memcpy(info, data, sizeof(struct atmel_lcdfb_info));
--	info->default_monspecs = monspecs;
--
--	platform_device_register(pdev);
--	return pdev;
--
--err_invalid_id:
--	kfree(modedb);
--err_dup_modedb:
--	kfree(monspecs);
--	return NULL;
--}
--
--/* --------------------------------------------------------------------
-- *  SSC
-- * -------------------------------------------------------------------- */
--static struct resource ssc0_resource[] = {
--	PBMEM(0xffe01c00),
--	IRQ(10),
--};
--DEFINE_DEV(ssc, 0);
--DEV_CLK(pclk, ssc0, pba, 7);
--
--static struct resource ssc1_resource[] = {
--	PBMEM(0xffe02000),
--	IRQ(11),
--};
--DEFINE_DEV(ssc, 1);
--DEV_CLK(pclk, ssc1, pba, 8);
--
--static struct resource ssc2_resource[] = {
--	PBMEM(0xffe02400),
--	IRQ(12),
--};
--DEFINE_DEV(ssc, 2);
--DEV_CLK(pclk, ssc2, pba, 9);
--
--struct platform_device *__init
--at32_add_device_ssc(unsigned int id, unsigned int flags)
--{
--	struct platform_device *pdev;
--
--	switch (id) {
--	case 0:
--		pdev = &ssc0_device;
--		if (flags & ATMEL_SSC_RF)
--			select_peripheral(PA(21), PERIPH_A, 0);	/* RF */
--		if (flags & ATMEL_SSC_RK)
--			select_peripheral(PA(22), PERIPH_A, 0);	/* RK */
--		if (flags & ATMEL_SSC_TK)
--			select_peripheral(PA(23), PERIPH_A, 0);	/* TK */
--		if (flags & ATMEL_SSC_TF)
--			select_peripheral(PA(24), PERIPH_A, 0);	/* TF */
--		if (flags & ATMEL_SSC_TD)
--			select_peripheral(PA(25), PERIPH_A, 0);	/* TD */
--		if (flags & ATMEL_SSC_RD)
--			select_peripheral(PA(26), PERIPH_A, 0);	/* RD */
--		break;
--	case 1:
--		pdev = &ssc1_device;
--		if (flags & ATMEL_SSC_RF)
--			select_peripheral(PA(0), PERIPH_B, 0);	/* RF */
--		if (flags & ATMEL_SSC_RK)
--			select_peripheral(PA(1), PERIPH_B, 0);	/* RK */
--		if (flags & ATMEL_SSC_TK)
--			select_peripheral(PA(2), PERIPH_B, 0);	/* TK */
--		if (flags & ATMEL_SSC_TF)
--			select_peripheral(PA(3), PERIPH_B, 0);	/* TF */
--		if (flags & ATMEL_SSC_TD)
--			select_peripheral(PA(4), PERIPH_B, 0);	/* TD */
--		if (flags & ATMEL_SSC_RD)
--			select_peripheral(PA(5), PERIPH_B, 0);	/* RD */
--		break;
--	case 2:
--		pdev = &ssc2_device;
--		if (flags & ATMEL_SSC_TD)
--			select_peripheral(PB(13), PERIPH_A, 0);	/* TD */
--		if (flags & ATMEL_SSC_RD)
--			select_peripheral(PB(14), PERIPH_A, 0);	/* RD */
--		if (flags & ATMEL_SSC_TK)
--			select_peripheral(PB(15), PERIPH_A, 0);	/* TK */
--		if (flags & ATMEL_SSC_TF)
--			select_peripheral(PB(16), PERIPH_A, 0);	/* TF */
--		if (flags & ATMEL_SSC_RF)
--			select_peripheral(PB(17), PERIPH_A, 0);	/* RF */
--		if (flags & ATMEL_SSC_RK)
--			select_peripheral(PB(18), PERIPH_A, 0);	/* RK */
--		break;
--	default:
--		return NULL;
--	}
--
--	platform_device_register(pdev);
--	return pdev;
--}
--
--/* --------------------------------------------------------------------
-- *  USB Device Controller
-- * -------------------------------------------------------------------- */
--static struct resource usba0_resource[] __initdata = {
--	{
--		.start		= 0xff300000,
--		.end		= 0xff3fffff,
--		.flags		= IORESOURCE_MEM,
--	}, {
--		.start		= 0xfff03000,
--		.end		= 0xfff033ff,
--		.flags		= IORESOURCE_MEM,
--	},
--	IRQ(31),
--};
--static struct clk usba0_pclk = {
--	.name		= "pclk",
--	.parent		= &pbb_clk,
--	.mode		= pbb_clk_mode,
--	.get_rate	= pbb_clk_get_rate,
--	.index		= 12,
--};
--static struct clk usba0_hclk = {
--	.name		= "hclk",
--	.parent		= &hsb_clk,
--	.mode		= hsb_clk_mode,
--	.get_rate	= hsb_clk_get_rate,
--	.index		= 6,
--};
--
--struct platform_device *__init
--at32_add_device_usba(unsigned int id, struct usba_platform_data *data)
--{
--	struct platform_device *pdev;
--
--	if (id != 0)
--		return NULL;
--
--	pdev = platform_device_alloc("atmel_usba_udc", 0);
--	if (!pdev)
--		return NULL;
--
--	if (platform_device_add_resources(pdev, usba0_resource,
--					  ARRAY_SIZE(usba0_resource)))
--		goto out_free_pdev;
--
--	if (data) {
--		if (platform_device_add_data(pdev, data, sizeof(*data)))
--			goto out_free_pdev;
--
--		if (data->vbus_pin != GPIO_PIN_NONE)
--			at32_select_gpio(data->vbus_pin, 0);
--	}
--
--	usba0_pclk.dev = &pdev->dev;
--	usba0_hclk.dev = &pdev->dev;
--
--	platform_device_add(pdev);
--
--	return pdev;
--
--out_free_pdev:
--	platform_device_put(pdev);
--	return NULL;
--}
--
--/* --------------------------------------------------------------------
-- * IDE / CompactFlash
-- * -------------------------------------------------------------------- */
--static struct resource at32_smc_cs4_resource[] __initdata = {
--	{
--		.start	= 0x04000000,
--		.end	= 0x07ffffff,
--		.flags	= IORESOURCE_MEM,
--	},
--	IRQ(~0UL), /* Magic IRQ will be overridden */
--};
--static struct resource at32_smc_cs5_resource[] __initdata = {
--	{
--		.start	= 0x20000000,
--		.end	= 0x23ffffff,
--		.flags	= IORESOURCE_MEM,
--	},
--	IRQ(~0UL), /* Magic IRQ will be overridden */
--};
--
--static int __init at32_init_ide_or_cf(struct platform_device *pdev,
--		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),
--	};
--	static bool common_pins_initialized __initdata = false;
--	unsigned int extint_pin;
--	int ret;
--
--	if (extint >= ARRAY_SIZE(extint_pin_map))
--		return -EINVAL;
--	extint_pin = extint_pin_map[extint];
--
--	switch (cs) {
--	case 4:
--		ret = platform_device_add_resources(pdev,
--				at32_smc_cs4_resource,
--				ARRAY_SIZE(at32_smc_cs4_resource));
--		if (ret)
--			return ret;
--
--		select_peripheral(PE(21), PERIPH_A, 0); /* NCS4   -> OE_N  */
--		set_ebi_sfr_bits(HMATRIX_BIT(CS4A));
--		break;
--	case 5:
--		ret = platform_device_add_resources(pdev,
--				at32_smc_cs5_resource,
--				ARRAY_SIZE(at32_smc_cs5_resource));
--		if (ret)
--			return ret;
--
--		select_peripheral(PE(22), PERIPH_A, 0); /* NCS5   -> OE_N  */
--		set_ebi_sfr_bits(HMATRIX_BIT(CS5A));
--		break;
--	default:
--		return -EINVAL;
--	}
--
--	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 */
--		common_pins_initialized = true;
--	}
--
--	at32_select_periph(extint_pin, GPIO_PERIPH_A, AT32_GPIOF_DEGLITCH);
--
--	pdev->resource[1].start = EIM_IRQ_BASE + extint;
--	pdev->resource[1].end = pdev->resource[1].start;
--
--	return 0;
--}
--
--struct platform_device *__init
--at32_add_device_ide(unsigned int id, unsigned int extint,
--		    struct ide_platform_data *data)
--{
--	struct platform_device *pdev;
--
--	pdev = platform_device_alloc("at32_ide", id);
--	if (!pdev)
--		goto fail;
--
--	if (platform_device_add_data(pdev, data,
--				sizeof(struct ide_platform_data)))
--		goto fail;
--
--	if (at32_init_ide_or_cf(pdev, data->cs, extint))
--		goto fail;
--
--	platform_device_add(pdev);
--	return pdev;
--
--fail:
--	platform_device_put(pdev);
--	return NULL;
--}
--
--struct platform_device *__init
--at32_add_device_cf(unsigned int id, unsigned int extint,
--		    struct cf_platform_data *data)
--{
--	struct platform_device *pdev;
--
--	pdev = platform_device_alloc("at32_cf", id);
--	if (!pdev)
--		goto fail;
--
--	if (platform_device_add_data(pdev, data,
--				sizeof(struct cf_platform_data)))
--		goto fail;
--
--	if (at32_init_ide_or_cf(pdev, data->cs, extint))
--		goto fail;
--
--	if (data->detect_pin != GPIO_PIN_NONE)
--		at32_select_gpio(data->detect_pin, AT32_GPIOF_DEGLITCH);
--	if (data->reset_pin != GPIO_PIN_NONE)
--		at32_select_gpio(data->reset_pin, 0);
--	if (data->vcc_pin != GPIO_PIN_NONE)
--		at32_select_gpio(data->vcc_pin, 0);
--	/* READY is used as extint, so we can't select it as gpio */
--
--	platform_device_add(pdev);
--	return pdev;
--
--fail:
--	platform_device_put(pdev);
--	return NULL;
--}
--
--/* --------------------------------------------------------------------
-- * AC97C
-- * -------------------------------------------------------------------- */
--static struct resource atmel_ac97c0_resource[] __initdata = {
--	PBMEM(0xfff02800),
--	IRQ(29),
--};
--static struct clk atmel_ac97c0_pclk = {
--	.name		= "pclk",
--	.parent		= &pbb_clk,
--	.mode		= pbb_clk_mode,
--	.get_rate	= pbb_clk_get_rate,
--	.index		= 10,
--};
--
--struct platform_device *__init at32_add_device_ac97c(unsigned int id)
--{
--	struct platform_device *pdev;
--
--	if (id != 0)
--		return NULL;
--
--	pdev = platform_device_alloc("atmel_ac97c", id);
--	if (!pdev)
--		return NULL;
--
--	if (platform_device_add_resources(pdev, atmel_ac97c0_resource,
--				ARRAY_SIZE(atmel_ac97c0_resource)))
--		goto err_add_resources;
--
--	select_peripheral(PB(20), PERIPH_B, 0);	/* SYNC	*/
--	select_peripheral(PB(21), PERIPH_B, 0);	/* SDO	*/
--	select_peripheral(PB(22), PERIPH_B, 0);	/* SDI	*/
--	select_peripheral(PB(23), PERIPH_B, 0);	/* SCLK	*/
--
--	atmel_ac97c0_pclk.dev = &pdev->dev;
--
--	platform_device_add(pdev);
--	return pdev;
--
--err_add_resources:
--	platform_device_put(pdev);
--	return NULL;
--}
--
--/* --------------------------------------------------------------------
-- * ABDAC
-- * -------------------------------------------------------------------- */
--static struct resource abdac0_resource[] __initdata = {
--	PBMEM(0xfff02000),
--	IRQ(27),
--};
--static struct clk abdac0_pclk = {
--	.name		= "pclk",
--	.parent		= &pbb_clk,
--	.mode		= pbb_clk_mode,
--	.get_rate	= pbb_clk_get_rate,
--	.index		= 8,
--};
--static struct clk abdac0_sample_clk = {
--	.name		= "sample_clk",
--	.mode		= genclk_mode,
--	.get_rate	= genclk_get_rate,
--	.set_rate	= genclk_set_rate,
--	.set_parent	= genclk_set_parent,
--	.index		= 6,
--};
--
--struct platform_device *__init at32_add_device_abdac(unsigned int id)
--{
--	struct platform_device *pdev;
--
--	if (id != 0)
--		return NULL;
--
--	pdev = platform_device_alloc("abdac", id);
--	if (!pdev)
--		return NULL;
--
--	if (platform_device_add_resources(pdev, abdac0_resource,
--				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	*/
--
--	abdac0_pclk.dev = &pdev->dev;
--	abdac0_sample_clk.dev = &pdev->dev;
--
--	platform_device_add(pdev);
--	return pdev;
--
--err_add_resources:
--	platform_device_put(pdev);
--	return NULL;
--}
--
--/* --------------------------------------------------------------------
-- *  GCLK
-- * -------------------------------------------------------------------- */
--static struct clk gclk0 = {
--	.name		= "gclk0",
--	.mode		= genclk_mode,
--	.get_rate	= genclk_get_rate,
--	.set_rate	= genclk_set_rate,
--	.set_parent	= genclk_set_parent,
--	.index		= 0,
--};
--static struct clk gclk1 = {
--	.name		= "gclk1",
--	.mode		= genclk_mode,
--	.get_rate	= genclk_get_rate,
--	.set_rate	= genclk_set_rate,
--	.set_parent	= genclk_set_parent,
--	.index		= 1,
--};
--static struct clk gclk2 = {
--	.name		= "gclk2",
--	.mode		= genclk_mode,
--	.get_rate	= genclk_get_rate,
--	.set_rate	= genclk_set_rate,
--	.set_parent	= genclk_set_parent,
--	.index		= 2,
--};
--static struct clk gclk3 = {
--	.name		= "gclk3",
--	.mode		= genclk_mode,
--	.get_rate	= genclk_get_rate,
--	.set_rate	= genclk_set_rate,
--	.set_parent	= genclk_set_parent,
--	.index		= 3,
--};
--static struct clk gclk4 = {
--	.name		= "gclk4",
--	.mode		= genclk_mode,
--	.get_rate	= genclk_get_rate,
--	.set_rate	= genclk_set_rate,
--	.set_parent	= genclk_set_parent,
--	.index		= 4,
--};
--
--struct clk *at32_clock_list[] = {
--	&osc32k,
--	&osc0,
--	&osc1,
--	&pll0,
--	&pll1,
--	&cpu_clk,
--	&hsb_clk,
--	&pba_clk,
--	&pbb_clk,
--	&at32_pm_pclk,
--	&at32_intc0_pclk,
--	&hmatrix_clk,
--	&ebi_clk,
--	&hramc_clk,
--	&smc0_pclk,
--	&smc0_mck,
--	&pdc_hclk,
--	&pdc_pclk,
--	&dmaca0_hclk,
--	&pico_clk,
--	&pio0_mck,
--	&pio1_mck,
--	&pio2_mck,
--	&pio3_mck,
--	&pio4_mck,
--	&at32_systc0_pclk,
--	&atmel_usart0_usart,
--	&atmel_usart1_usart,
--	&atmel_usart2_usart,
--	&atmel_usart3_usart,
--	&macb0_hclk,
--	&macb0_pclk,
--	&macb1_hclk,
--	&macb1_pclk,
--	&atmel_spi0_spi_clk,
--	&atmel_spi1_spi_clk,
--	&atmel_twi0_pclk,
--	&atmel_mci0_pclk,
--	&atmel_lcdfb0_hck1,
--	&atmel_lcdfb0_pixclk,
--	&ssc0_pclk,
--	&ssc1_pclk,
--	&ssc2_pclk,
--	&usba0_hclk,
--	&usba0_pclk,
--	&atmel_ac97c0_pclk,
--	&abdac0_pclk,
--	&abdac0_sample_clk,
--	&gclk0,
--	&gclk1,
--	&gclk2,
--	&gclk3,
--	&gclk4,
--};
--unsigned int at32_nr_clocks = ARRAY_SIZE(at32_clock_list);
--
--void __init at32_portmux_init(void)
--{
--	at32_init_pio(&pio0_device);
--	at32_init_pio(&pio1_device);
--	at32_init_pio(&pio2_device);
--	at32_init_pio(&pio3_device);
--	at32_init_pio(&pio4_device);
--}
--
--void __init at32_clock_init(void)
--{
--	u32 cpu_mask = 0, hsb_mask = 0, pba_mask = 0, pbb_mask = 0;
--	int i;
--
--	if (pm_readl(MCCTRL) & PM_BIT(PLLSEL)) {
--		main_clock = &pll0;
--		cpu_clk.parent = &pll0;
--	} else {
--		main_clock = &osc0;
--		cpu_clk.parent = &osc0;
--	}
--
--	if (pm_readl(PLL0) & PM_BIT(PLLOSC))
--		pll0.parent = &osc1;
--	if (pm_readl(PLL1) & PM_BIT(PLLOSC))
--		pll1.parent = &osc1;
--
--	genclk_init_parent(&gclk0);
--	genclk_init_parent(&gclk1);
--	genclk_init_parent(&gclk2);
--	genclk_init_parent(&gclk3);
--	genclk_init_parent(&gclk4);
--	genclk_init_parent(&atmel_lcdfb0_pixclk);
--	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...
--	 */
--	for (i = 0; i < ARRAY_SIZE(at32_clock_list); i++) {
--		struct clk *clk = at32_clock_list[i];
--
--		if (clk->users == 0)
--			continue;
--
--		if (clk->mode == &cpu_clk_mode)
--			cpu_mask |= 1 << clk->index;
--		else if (clk->mode == &hsb_clk_mode)
--			hsb_mask |= 1 << clk->index;
--		else if (clk->mode == &pba_clk_mode)
--			pba_mask |= 1 << clk->index;
--		else if (clk->mode == &pbb_clk_mode)
--			pbb_mask |= 1 << clk->index;
--	}
--
--	pm_writel(CPU_MASK, cpu_mask);
--	pm_writel(HSB_MASK, hsb_mask);
--	pm_writel(PBA_MASK, pba_mask);
--	pm_writel(PBB_MASK, pbb_mask);
--}
-diff --git a/arch/avr32/mach-at32ap/at32ap700x.c b/arch/avr32/mach-at32ap/at32ap700x.c
-new file mode 100644
-index 0000000..14e61f0
---- /dev/null
-+++ b/arch/avr32/mach-at32ap/at32ap700x.c
-@@ -0,0 +1,1743 @@
-+/*
-+ * Copyright (C) 2005-2006 Atmel 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/clk.h>
-+#include <linux/fb.h>
-+#include <linux/init.h>
-+#include <linux/platform_device.h>
-+#include <linux/dma-mapping.h>
-+#include <linux/spi/spi.h>
-+
-+#include <asm/io.h>
-+#include <asm/irq.h>
++#
++# 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
 +
-+#include <asm/arch/at32ap700x.h>
-+#include <asm/arch/board.h>
-+#include <asm/arch/portmux.h>
++#
++# 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
 +
-+#include <video/atmel_lcdc.h>
++#
++# USB Host Controller Drivers
++#
++CONFIG_USB_EHCI_HCD=y
++CONFIG_USB_EHCI_SPLIT_ISO=y
++CONFIG_USB_EHCI_ROOT_HUB_TT=y
++CONFIG_USB_EHCI_TT_NEWSCHED=y
++# 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=y
++CONFIG_USB_SL811_HCD=y
++# CONFIG_USB_R8A66597_HCD is not set
 +
-+#include "clock.h"
-+#include "hmatrix.h"
-+#include "pio.h"
-+#include "pm.h"
++#
++# USB Device Class drivers
++#
++# CONFIG_USB_ACM is not set
++CONFIG_USB_PRINTER=y
 +
++#
++# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
++#
 +
-+#define PBMEM(base)					\
-+	{						\
-+		.start		= base,			\
-+		.end		= base + 0x3ff,		\
-+		.flags		= IORESOURCE_MEM,	\
-+	}
-+#define IRQ(num)					\
-+	{						\
-+		.start		= num,			\
-+		.end		= num,			\
-+		.flags		= IORESOURCE_IRQ,	\
-+	}
-+#define NAMED_IRQ(num, _name)				\
-+	{						\
-+		.start		= num,			\
-+		.end		= num,			\
-+		.name		= _name,		\
-+		.flags		= IORESOURCE_IRQ,	\
-+	}
++#
++# 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=y
++CONFIG_USB_STORAGE_FREECOM=y
++# CONFIG_USB_STORAGE_ISD200 is not set
++CONFIG_USB_STORAGE_DPCM=y
++# CONFIG_USB_STORAGE_USBAT is not set
++CONFIG_USB_STORAGE_SDDR09=y
++CONFIG_USB_STORAGE_SDDR55=y
++CONFIG_USB_STORAGE_JUMPSHOT=y
++# CONFIG_USB_STORAGE_ALAUDA is not set
++# CONFIG_USB_STORAGE_KARMA is not set
++# CONFIG_USB_LIBUSUAL is not set
 +
-+/* REVISIT these assume *every* device supports DMA, but several
-+ * don't ... tc, smc, pio, rtc, watchdog, pwm, ps2, and more.
-+ */
-+#define DEFINE_DEV(_name, _id)					\
-+static u64 _name##_id##_dma_mask = DMA_32BIT_MASK;		\
-+static struct platform_device _name##_id##_device = {		\
-+	.name		= #_name,				\
-+	.id		= _id,					\
-+	.dev		= {					\
-+		.dma_mask = &_name##_id##_dma_mask,		\
-+		.coherent_dma_mask = DMA_32BIT_MASK,		\
-+	},							\
-+	.resource	= _name##_id##_resource,		\
-+	.num_resources	= ARRAY_SIZE(_name##_id##_resource),	\
-+}
-+#define DEFINE_DEV_DATA(_name, _id)				\
-+static u64 _name##_id##_dma_mask = DMA_32BIT_MASK;		\
-+static struct platform_device _name##_id##_device = {		\
-+	.name		= #_name,				\
-+	.id		= _id,					\
-+	.dev		= {					\
-+		.dma_mask = &_name##_id##_dma_mask,		\
-+		.platform_data	= &_name##_id##_data,		\
-+		.coherent_dma_mask = DMA_32BIT_MASK,		\
-+	},							\
-+	.resource	= _name##_id##_resource,		\
-+	.num_resources	= ARRAY_SIZE(_name##_id##_resource),	\
-+}
++#
++# USB Imaging devices
++#
++# CONFIG_USB_MDC800 is not set
++# CONFIG_USB_MICROTEK is not set
++# CONFIG_USB_MON is not set
 +
-+#define select_peripheral(pin, periph, flags)			\
-+	at32_select_periph(GPIO_PIN_##pin, GPIO_##periph, flags)
++#
++# USB port drivers
++#
 +
-+#define DEV_CLK(_name, devname, bus, _index)			\
-+static struct clk devname##_##_name = {				\
-+	.name		= #_name,				\
-+	.dev		= &devname##_device.dev,		\
-+	.parent		= &bus##_clk,				\
-+	.mode		= bus##_clk_mode,			\
-+	.get_rate	= bus##_clk_get_rate,			\
-+	.index		= _index,				\
-+}
++#
++# USB Serial Converter support
++#
++# CONFIG_USB_SERIAL is not set
 +
-+static DEFINE_SPINLOCK(pm_lock);
++#
++# 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_TEST is not set
 +
-+unsigned long at32ap7000_osc_rates[3] = {
-+	[0] = 32768,
-+	/* FIXME: these are ATSTK1002-specific */
-+	[1] = 20000000,
-+	[2] = 12000000,
-+};
++#
++# USB DSL modem support
++#
 +
-+static unsigned long osc_get_rate(struct clk *clk)
-+{
-+	return at32ap7000_osc_rates[clk->index];
-+}
++#
++# USB Gadget Support
++#
++# CONFIG_USB_GADGET is not set
++# CONFIG_MMC is not set
++CONFIG_NEW_LEDS=y
++CONFIG_LEDS_CLASS=y
 +
-+static unsigned long pll_get_rate(struct clk *clk, unsigned long control)
-+{
-+	unsigned long div, mul, rate;
++#
++# LED drivers
++#
++# CONFIG_LEDS_GPIO is not set
 +
-+	if (!(control & PM_BIT(PLLEN)))
-+		return 0;
++#
++# LED Triggers
++#
++CONFIG_LEDS_TRIGGERS=y
++CONFIG_LEDS_TRIGGER_TIMER=y
++CONFIG_LEDS_TRIGGER_HEARTBEAT=y
++CONFIG_RTC_LIB=y
++CONFIG_RTC_CLASS=y
++CONFIG_RTC_HCTOSYS=y
++CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
++# CONFIG_RTC_DEBUG is not set
 +
-+	div = PM_BFEXT(PLLDIV, control) + 1;
-+	mul = PM_BFEXT(PLLMUL, control) + 1;
++#
++# 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
 +
-+	rate = clk->parent->get_rate(clk->parent);
-+	rate = (rate + div / 2) / div;
-+	rate *= mul;
++#
++# I2C RTC drivers
++#
++CONFIG_RTC_DRV_DS1307=y
++# 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=y
++# 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=y
++# CONFIG_RTC_DRV_M41T80_WDT is not set
 +
-+	return rate;
-+}
++#
++# SPI RTC drivers
++#
 +
-+static unsigned long pll0_get_rate(struct clk *clk)
-+{
-+	u32 control;
++#
++# Platform RTC drivers
++#
++# CONFIG_RTC_DRV_CMOS is not set
++# CONFIG_RTC_DRV_DS1553 is not set
++# CONFIG_RTC_DRV_STK17TA8 is not set
++# CONFIG_RTC_DRV_DS1742 is not set
++# CONFIG_RTC_DRV_M48T86 is not set
++# CONFIG_RTC_DRV_M48T59 is not set
++# CONFIG_RTC_DRV_V3020 is not set
 +
-+	control = pm_readl(PLL0);
++#
++# on-CPU RTC drivers
++#
 +
-+	return pll_get_rate(clk, control);
-+}
++#
++# 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_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_GFS2_FS is not set
++# CONFIG_OCFS2_FS is not set
++# CONFIG_MINIX_FS is not set
++# CONFIG_ROMFS_FS is not set
++CONFIG_INOTIFY=y
++CONFIG_INOTIFY_USER=y
++# CONFIG_QUOTA is not set
++CONFIG_DNOTIFY=y
++# CONFIG_AUTOFS_FS is not set
++# CONFIG_AUTOFS4_FS is not set
++# CONFIG_FUSE_FS is not set
 +
-+static unsigned long pll1_get_rate(struct clk *clk)
-+{
-+	u32 control;
++#
++# CD-ROM/DVD Filesystems
++#
++CONFIG_ISO9660_FS=y
++# CONFIG_JOLIET is not set
++# CONFIG_ZISOFS is not set
++CONFIG_UDF_FS=m
++CONFIG_UDF_NLS=y
 +
-+	control = pm_readl(PLL1);
++#
++# DOS/FAT/NT Filesystems
++#
++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
 +
-+	return pll_get_rate(clk, control);
-+}
++#
++# 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
 +
-+/*
-+ * The AT32AP7000 has five primary clock sources: One 32kHz
-+ * oscillator, two crystal oscillators and two PLLs.
-+ */
-+static struct clk osc32k = {
-+	.name		= "osc32k",
-+	.get_rate	= osc_get_rate,
-+	.users		= 1,
-+	.index		= 0,
-+};
-+static struct clk osc0 = {
-+	.name		= "osc0",
-+	.get_rate	= osc_get_rate,
-+	.users		= 1,
-+	.index		= 1,
-+};
-+static struct clk osc1 = {
-+	.name		= "osc1",
-+	.get_rate	= osc_get_rate,
-+	.index		= 2,
-+};
-+static struct clk pll0 = {
-+	.name		= "pll0",
-+	.get_rate	= pll0_get_rate,
-+	.parent		= &osc0,
-+};
-+static struct clk pll1 = {
-+	.name		= "pll1",
-+	.get_rate	= pll1_get_rate,
-+	.parent		= &osc0,
-+};
++#
++# 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_HPFS_FS is not set
++# CONFIG_QNX4FS_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_NFS_DIRECTIO is not set
++# CONFIG_NFSD is not set
++CONFIG_ROOT_NFS=y
++CONFIG_LOCKD=y
++CONFIG_LOCKD_V4=y
++CONFIG_NFS_COMMON=y
++CONFIG_SUNRPC=y
++# CONFIG_SUNRPC_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 is not set
++# CONFIG_NCP_FS is not set
++# CONFIG_CODA_FS is not set
++# CONFIG_AFS_FS is not set
 +
-+/*
-+ * The main clock can be either osc0 or pll0.  The boot loader may
-+ * have chosen one for us, so we don't really know which one until we
-+ * have a look at the SM.
-+ */
-+static struct clk *main_clock;
++#
++# 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=y
++CONFIG_MINIX_SUBPARTITION=y
++CONFIG_SOLARIS_X86_PARTITION=y
++CONFIG_UNIXWARE_DISKLABEL=y
++CONFIG_LDM_PARTITION=y
++CONFIG_LDM_DEBUG=y
++# CONFIG_SGI_PARTITION is not set
++# CONFIG_ULTRIX_PARTITION is not set
++CONFIG_SUN_PARTITION=y
++# CONFIG_KARMA_PARTITION is not set
++# CONFIG_EFI_PARTITION is not set
++# CONFIG_SYSV68_PARTITION is not set
++CONFIG_NLS=y
++CONFIG_NLS_DEFAULT="iso8859-1"
++CONFIG_NLS_CODEPAGE_437=y
++# CONFIG_NLS_CODEPAGE_737 is not set
++# CONFIG_NLS_CODEPAGE_775 is not set
++CONFIG_NLS_CODEPAGE_850=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=y
++# 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
++CONFIG_INSTRUMENTATION=y
++# CONFIG_PROFILING is not set
++# CONFIG_MARKERS is not set
 +
-+/*
-+ * Synchronous clocks are generated from the main clock. The clocks
-+ * must satisfy the constraint
-+ *   fCPU >= fHSB >= fPB
-+ * i.e. each clock must not be faster than its parent.
-+ */
-+static unsigned long bus_clk_get_rate(struct clk *clk, unsigned int shift)
-+{
-+	return main_clock->get_rate(main_clock) >> shift;
-+};
++#
++# Kernel hacking
++#
++# CONFIG_PRINTK_TIME is not set
++CONFIG_ENABLE_WARN_DEPRECATED=y
++CONFIG_ENABLE_MUST_CHECK=y
++# 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 is not set
++CONFIG_FRAME_POINTER=y
++# CONFIG_SAMPLES is not set
++CONFIG_DEBUG_USER=y
 +
-+static void cpu_clk_mode(struct clk *clk, int enabled)
-+{
-+	unsigned long flags;
-+	u32 mask;
++#
++# Security options
++#
++# CONFIG_KEYS is not set
++# CONFIG_SECURITY is not set
++# CONFIG_SECURITY_FILE_CAPABILITIES is not set
++CONFIG_CRYPTO=y
++CONFIG_CRYPTO_ALGAPI=m
++CONFIG_CRYPTO_BLKCIPHER=m
++CONFIG_CRYPTO_MANAGER=m
++# CONFIG_CRYPTO_HMAC is not set
++# CONFIG_CRYPTO_XCBC is not set
++# CONFIG_CRYPTO_NULL is not set
++# CONFIG_CRYPTO_MD4 is not set
++# CONFIG_CRYPTO_MD5 is not set
++# CONFIG_CRYPTO_SHA1 is not set
++# CONFIG_CRYPTO_SHA256 is not set
++# CONFIG_CRYPTO_SHA512 is not set
++# CONFIG_CRYPTO_WP512 is not set
++# CONFIG_CRYPTO_TGR192 is not set
++# CONFIG_CRYPTO_GF128MUL is not set
++CONFIG_CRYPTO_ECB=m
++CONFIG_CRYPTO_CBC=m
++CONFIG_CRYPTO_PCBC=m
++# CONFIG_CRYPTO_LRW is not set
++# CONFIG_CRYPTO_XTS is not set
++# CONFIG_CRYPTO_CRYPTD is not set
++# CONFIG_CRYPTO_DES is not set
++# CONFIG_CRYPTO_FCRYPT is not set
++# CONFIG_CRYPTO_BLOWFISH is not set
++# CONFIG_CRYPTO_TWOFISH is not set
++# CONFIG_CRYPTO_SERPENT is not set
++# CONFIG_CRYPTO_AES is not set
++# CONFIG_CRYPTO_CAST5 is not set
++# CONFIG_CRYPTO_CAST6 is not set
++# CONFIG_CRYPTO_TEA is not set
++# CONFIG_CRYPTO_ARC4 is not set
++# CONFIG_CRYPTO_KHAZAD is not set
++# CONFIG_CRYPTO_ANUBIS is not set
++# CONFIG_CRYPTO_SEED is not set
++# CONFIG_CRYPTO_DEFLATE is not set
++# CONFIG_CRYPTO_MICHAEL_MIC is not set
++# CONFIG_CRYPTO_CRC32C is not set
++# CONFIG_CRYPTO_CAMELLIA is not set
++# CONFIG_CRYPTO_TEST is not set
++# CONFIG_CRYPTO_AUTHENC is not set
++CONFIG_CRYPTO_HW=y
 +
-+	spin_lock_irqsave(&pm_lock, flags);
-+	mask = pm_readl(CPU_MASK);
-+	if (enabled)
-+		mask |= 1 << clk->index;
-+	else
-+		mask &= ~(1 << clk->index);
-+	pm_writel(CPU_MASK, mask);
-+	spin_unlock_irqrestore(&pm_lock, flags);
-+}
++#
++# Library routines
++#
++CONFIG_BITREVERSE=y
++CONFIG_CRC_CCITT=y
++CONFIG_CRC16=y
++# CONFIG_CRC_ITU_T is not set
++CONFIG_CRC32=y
++# CONFIG_CRC7 is not set
++CONFIG_LIBCRC32C=y
++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/pcm027_defconfig b/arch/arm/configs/pcm027_defconfig
+new file mode 100644
+index 0000000..17b9b24
+--- /dev/null
++++ b/arch/arm/configs/pcm027_defconfig
+@@ -0,0 +1,1096 @@
++#
++# Automatically generated make config: don't edit
++# Linux kernel version: 2.6.24-rc6
++# Fri Dec 21 10:52:09 2007
++#
++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_ZONE_DMA=y
++CONFIG_ARCH_MTD_XIP=y
++CONFIG_VECTORS_BASE=0xffff0000
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
 +
-+static unsigned long cpu_clk_get_rate(struct clk *clk)
-+{
-+	unsigned long cksel, shift = 0;
++#
++# 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=y
++# CONFIG_SWAP is not set
++CONFIG_SYSVIPC=y
++CONFIG_SYSVIPC_SYSCTL=y
++CONFIG_POSIX_MQUEUE=y
++CONFIG_BSD_PROCESS_ACCT=y
++# CONFIG_BSD_PROCESS_ACCT_V3 is not set
++# CONFIG_TASKSTATS is not set
++# CONFIG_USER_NS is not set
++# CONFIG_PID_NS 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_FAIR_GROUP_SCHED=y
++CONFIG_FAIR_USER_SCHED=y
++# CONFIG_FAIR_CGROUP_SCHED is not set
++CONFIG_SYSFS_DEPRECATED=y
++# CONFIG_RELAY is not set
++# CONFIG_BLK_DEV_INITRD is not set
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
++CONFIG_SYSCTL=y
++CONFIG_EMBEDDED=y
++CONFIG_UID16=y
++CONFIG_SYSCTL_SYSCALL=y
++# CONFIG_KALLSYMS is not set
++CONFIG_HOTPLUG=y
++CONFIG_PRINTK=y
++CONFIG_BUG=y
++CONFIG_ELF_CORE=y
++CONFIG_BASE_FULL=y
++CONFIG_FUTEX=y
++CONFIG_ANON_INODES=y
++CONFIG_EPOLL=y
++CONFIG_SIGNALFD=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_RT_MUTEXES=y
++# CONFIG_TINY_SHMEM is not set
++CONFIG_BASE_SMALL=0
++CONFIG_MODULES=y
++CONFIG_MODULE_UNLOAD=y
++CONFIG_MODULE_FORCE_UNLOAD=y
++# CONFIG_MODVERSIONS is not set
++# CONFIG_MODULE_SRCVERSION_ALL is not set
++# CONFIG_KMOD is not set
++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
 +
-+	cksel = pm_readl(CKSEL);
-+	if (cksel & PM_BIT(CPUDIV))
-+		shift = PM_BFEXT(CPUSEL, cksel) + 1;
++#
++# 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"
 +
-+	return bus_clk_get_rate(clk, shift);
-+}
++#
++# 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_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
 +
-+static long cpu_clk_set_rate(struct clk *clk, unsigned long rate, int apply)
-+{
-+	u32 control;
-+	unsigned long parent_rate, child_div, actual_rate, div;
++#
++# Intel PXA2xx/PXA3xx Implementations
++#
++# 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_MACH_TRIZEPS4 is not set
++# CONFIG_MACH_EM_X270 is not set
++# CONFIG_MACH_ZYLONITE is not set
++# CONFIG_MACH_ARMCORE is not set
++CONFIG_MACH_PCM027=y
++CONFIG_MACH_PCM990_BASEBOARD=y
++CONFIG_PXA27x=y
 +
-+	parent_rate = clk->parent->get_rate(clk->parent);
-+	control = pm_readl(CKSEL);
++#
++# Boot options
++#
 +
-+	if (control & PM_BIT(HSBDIV))
-+		child_div = 1 << (PM_BFEXT(HSBSEL, control) + 1);
-+	else
-+		child_div = 1;
++#
++# Power management
++#
 +
-+	if (rate > 3 * (parent_rate / 4) || child_div == 1) {
-+		actual_rate = parent_rate;
-+		control &= ~PM_BIT(CPUDIV);
-+	} else {
-+		unsigned int cpusel;
-+		div = (parent_rate + rate / 2) / rate;
-+		if (div > child_div)
-+			div = child_div;
-+		cpusel = (div > 1) ? (fls(div) - 2) : 0;
-+		control = PM_BIT(CPUDIV) | PM_BFINS(CPUSEL, cpusel, control);
-+		actual_rate = parent_rate / (1 << (cpusel + 1));
-+	}
++#
++# Processor Type
++#
++CONFIG_CPU_32=y
++CONFIG_CPU_XSCALE=y
++CONFIG_CPU_32v5=y
++CONFIG_CPU_ABRT_EV5T=y
++CONFIG_CPU_CACHE_VIVT=y
++CONFIG_CPU_TLB_V4WBI=y
++CONFIG_CPU_CP15=y
++CONFIG_CPU_CP15_MMU=y
 +
-+	pr_debug("clk %s: new rate %lu (actual rate %lu)\n",
-+			clk->name, rate, actual_rate);
++#
++# 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
 +
-+	if (apply)
-+		pm_writel(CKSEL, control);
++#
++# Bus support
++#
++# CONFIG_PCI_SYSCALL is not set
++# CONFIG_ARCH_SUPPORTS_MSI is not set
++# CONFIG_PCCARD is not set
 +
-+	return actual_rate;
-+}
++#
++# Kernel Features
++#
++CONFIG_TICK_ONESHOT=y
++CONFIG_NO_HZ=y
++CONFIG_HIGH_RES_TIMERS=y
++CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
++CONFIG_PREEMPT=y
++CONFIG_HZ=100
++CONFIG_AEABI=y
++# CONFIG_OABI_COMPAT is not set
++# 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_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
 +
-+static void hsb_clk_mode(struct clk *clk, int enabled)
-+{
-+	unsigned long flags;
-+	u32 mask;
++#
++# Boot options
++#
++CONFIG_ZBOOT_ROM_TEXT=0x0
++CONFIG_ZBOOT_ROM_BSS=0x0
++CONFIG_CMDLINE=""
++# CONFIG_XIP_KERNEL is not set
++# CONFIG_KEXEC is not set
 +
-+	spin_lock_irqsave(&pm_lock, flags);
-+	mask = pm_readl(HSB_MASK);
-+	if (enabled)
-+		mask |= 1 << clk->index;
-+	else
-+		mask &= ~(1 << clk->index);
-+	pm_writel(HSB_MASK, mask);
-+	spin_unlock_irqrestore(&pm_lock, flags);
-+}
++#
++# Floating point emulation
++#
 +
-+static unsigned long hsb_clk_get_rate(struct clk *clk)
-+{
-+	unsigned long cksel, shift = 0;
++#
++# At least one emulation must be selected
++#
 +
-+	cksel = pm_readl(CKSEL);
-+	if (cksel & PM_BIT(HSBDIV))
-+		shift = PM_BFEXT(HSBSEL, cksel) + 1;
++#
++# Userspace binary formats
++#
++CONFIG_BINFMT_ELF=y
++# CONFIG_BINFMT_AOUT is not set
++# CONFIG_BINFMT_MISC is not set
 +
-+	return bus_clk_get_rate(clk, shift);
-+}
++#
++# Power management options
++#
++# CONFIG_PM is not set
++CONFIG_SUSPEND_UP_POSSIBLE=y
 +
-+static void pba_clk_mode(struct clk *clk, int enabled)
-+{
-+	unsigned long flags;
-+	u32 mask;
++#
++# Networking
++#
++CONFIG_NET=y
 +
-+	spin_lock_irqsave(&pm_lock, flags);
-+	mask = pm_readl(PBA_MASK);
-+	if (enabled)
-+		mask |= 1 << clk->index;
-+	else
-+		mask &= ~(1 << clk->index);
-+	pm_writel(PBA_MASK, mask);
-+	spin_unlock_irqrestore(&pm_lock, flags);
-+}
++#
++# Networking options
++#
++CONFIG_PACKET=y
++CONFIG_PACKET_MMAP=y
++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 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 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_INET6_XFRM_TUNNEL is not set
++# CONFIG_INET6_TUNNEL 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
 +
-+static unsigned long pba_clk_get_rate(struct clk *clk)
-+{
-+	unsigned long cksel, shift = 0;
++#
++# Network testing
++#
++# CONFIG_NET_PKTGEN is not set
++# CONFIG_HAMRADIO is not set
++# CONFIG_IRDA is not set
++# CONFIG_BT is not set
++# CONFIG_AF_RXRPC is not set
 +
-+	cksel = pm_readl(CKSEL);
-+	if (cksel & PM_BIT(PBADIV))
-+		shift = PM_BFEXT(PBASEL, cksel) + 1;
++#
++# 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
 +
-+	return bus_clk_get_rate(clk, shift);
-+}
++#
++# Device Drivers
++#
 +
-+static void pbb_clk_mode(struct clk *clk, int enabled)
-+{
-+	unsigned long flags;
-+	u32 mask;
++#
++# Generic Driver Options
++#
++CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
++CONFIG_STANDALONE=y
++CONFIG_PREVENT_FIRMWARE_BUILD=y
++CONFIG_FW_LOADER=y
++# 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
 +
-+	spin_lock_irqsave(&pm_lock, flags);
-+	mask = pm_readl(PBB_MASK);
-+	if (enabled)
-+		mask |= 1 << clk->index;
-+	else
-+		mask &= ~(1 << clk->index);
-+	pm_writel(PBB_MASK, mask);
-+	spin_unlock_irqrestore(&pm_lock, flags);
-+}
++#
++# 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
 +
-+static unsigned long pbb_clk_get_rate(struct clk *clk)
-+{
-+	unsigned long cksel, shift = 0;
++#
++# RAM/ROM/Flash chip drivers
++#
++CONFIG_MTD_CFI=y
++# CONFIG_MTD_JEDECPROBE is not set
++CONFIG_MTD_GEN_PROBE=y
++# CONFIG_MTD_CFI_ADV_OPTIONS is not set
++CONFIG_MTD_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
 +
-+	cksel = pm_readl(CKSEL);
-+	if (cksel & PM_BIT(PBBDIV))
-+		shift = PM_BFEXT(PBBSEL, cksel) + 1;
++#
++# Mapping drivers for chip access
++#
++# CONFIG_MTD_COMPLEX_MAPPINGS is not set
++CONFIG_MTD_PHYSMAP=y
++CONFIG_MTD_PHYSMAP_START=0x00000000
++CONFIG_MTD_PHYSMAP_LEN=0x0
++CONFIG_MTD_PHYSMAP_BANKWIDTH=0
++# CONFIG_MTD_PXA2XX is not set
++# CONFIG_MTD_ARM_INTEGRATOR is not set
++# CONFIG_MTD_SHARP_SL is not set
++# CONFIG_MTD_PLATRAM is not set
 +
-+	return bus_clk_get_rate(clk, shift);
-+}
++#
++# 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
 +
-+static struct clk cpu_clk = {
-+	.name		= "cpu",
-+	.get_rate	= cpu_clk_get_rate,
-+	.set_rate	= cpu_clk_set_rate,
-+	.users		= 1,
-+};
-+static struct clk hsb_clk = {
-+	.name		= "hsb",
-+	.parent		= &cpu_clk,
-+	.get_rate	= hsb_clk_get_rate,
-+};
-+static struct clk pba_clk = {
-+	.name		= "pba",
-+	.parent		= &hsb_clk,
-+	.mode		= hsb_clk_mode,
-+	.get_rate	= pba_clk_get_rate,
-+	.index		= 1,
-+};
-+static struct clk pbb_clk = {
-+	.name		= "pbb",
-+	.parent		= &hsb_clk,
-+	.mode		= hsb_clk_mode,
-+	.get_rate	= pbb_clk_get_rate,
-+	.users		= 1,
-+	.index		= 2,
-+};
++#
++# 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
 +
-+/* --------------------------------------------------------------------
-+ *  Generic Clock operations
-+ * -------------------------------------------------------------------- */
++#
++# UBI - Unsorted block images
++#
++# CONFIG_MTD_UBI is not set
++# CONFIG_PARPORT is not set
++# CONFIG_BLK_DEV is not set
++# CONFIG_MISC_DEVICES is not set
++# CONFIG_IDE is not set
 +
-+static void genclk_mode(struct clk *clk, int enabled)
-+{
-+	u32 control;
++#
++# 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
 +
-+	control = pm_readl(GCCTRL(clk->index));
-+	if (enabled)
-+		control |= PM_BIT(CEN);
-+	else
-+		control &= ~PM_BIT(CEN);
-+	pm_writel(GCCTRL(clk->index), control);
-+}
++#
++# 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
 +
-+static unsigned long genclk_get_rate(struct clk *clk)
-+{
-+	u32 control;
-+	unsigned long div = 1;
++#
++# 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
 +
-+	control = pm_readl(GCCTRL(clk->index));
-+	if (control & PM_BIT(DIVEN))
-+		div = 2 * (PM_BFEXT(DIV, control) + 1);
++#
++# 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 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 is not set
++CONFIG_NET_ETHERNET=y
++CONFIG_MII=y
++# CONFIG_AX88796 is not set
++CONFIG_SMC91X=y
++# CONFIG_DM9000 is not set
++# 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
 +
-+	return clk->parent->get_rate(clk->parent) / div;
-+}
++#
++# Wireless LAN
++#
++# CONFIG_WLAN_PRE80211 is not set
++# CONFIG_WLAN_80211 is not set
 +
-+static long genclk_set_rate(struct clk *clk, unsigned long rate, int apply)
-+{
-+	u32 control;
-+	unsigned long parent_rate, actual_rate, div;
++#
++# 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_SHAPER 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
 +
-+	parent_rate = clk->parent->get_rate(clk->parent);
-+	control = pm_readl(GCCTRL(clk->index));
++#
++# Input device support
++#
++CONFIG_INPUT=y
++# CONFIG_INPUT_FF_MEMLESS is not set
++# CONFIG_INPUT_POLLDEV is not set
 +
-+	if (rate > 3 * parent_rate / 4) {
-+		actual_rate = parent_rate;
-+		control &= ~PM_BIT(DIVEN);
-+	} else {
-+		div = (parent_rate + rate) / (2 * rate) - 1;
-+		control = PM_BFINS(DIV, div, control) | PM_BIT(DIVEN);
-+		actual_rate = parent_rate / (2 * (div + 1));
-+	}
++#
++# 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
 +
-+	dev_dbg(clk->dev, "clk %s: new rate %lu (actual rate %lu)\n",
-+		clk->name, rate, actual_rate);
++#
++# 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
 +
-+	if (apply)
-+		pm_writel(GCCTRL(clk->index), control);
++#
++# Hardware I/O ports
++#
++# CONFIG_SERIO is not set
++# CONFIG_GAMEPORT is not set
 +
-+	return actual_rate;
-+}
++#
++# Character devices
++#
++CONFIG_VT=y
++CONFIG_VT_CONSOLE=y
++CONFIG_HW_CONSOLE=y
++# CONFIG_VT_HW_CONSOLE_BINDING is not set
++# CONFIG_SERIAL_NONSTANDARD is not set
 +
-+int genclk_set_parent(struct clk *clk, struct clk *parent)
-+{
-+	u32 control;
++#
++# Serial drivers
++#
++# CONFIG_SERIAL_8250 is not set
 +
-+	dev_dbg(clk->dev, "clk %s: new parent %s (was %s)\n",
-+		clk->name, parent->name, clk->parent->name);
++#
++# 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=y
 +
-+	control = pm_readl(GCCTRL(clk->index));
++#
++# I2C Algorithms
++#
++# CONFIG_I2C_ALGOBIT is not set
++# CONFIG_I2C_ALGOPCF is not set
++# CONFIG_I2C_ALGOPCA is not set
 +
-+	if (parent == &osc1 || parent == &pll1)
-+		control |= PM_BIT(OSCSEL);
-+	else if (parent == &osc0 || parent == &pll0)
-+		control &= ~PM_BIT(OSCSEL);
-+	else
-+		return -EINVAL;
++#
++# I2C Hardware Bus support
++#
++# CONFIG_I2C_GPIO is not set
++CONFIG_I2C_PXA=y
++# CONFIG_I2C_PXA_SLAVE 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
 +
-+	if (parent == &pll0 || parent == &pll1)
-+		control |= PM_BIT(PLLSEL);
-+	else
-+		control &= ~PM_BIT(PLLSEL);
++#
++# Miscellaneous I2C Chip support
++#
++# CONFIG_SENSORS_DS1337 is not set
++# CONFIG_SENSORS_DS1374 is not set
++# CONFIG_DS1682 is not set
++CONFIG_SENSORS_EEPROM=y
++# CONFIG_SENSORS_PCF8574 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
 +
-+	pm_writel(GCCTRL(clk->index), control);
-+	clk->parent = parent;
++#
++# SPI support
++#
++# CONFIG_SPI is not set
++# CONFIG_SPI_MASTER is not set
++# CONFIG_W1 is not set
++# CONFIG_POWER_SUPPLY is not set
++# CONFIG_HWMON is not set
++# CONFIG_WATCHDOG is not set
 +
-+	return 0;
-+}
++#
++# Sonics Silicon Backplane
++#
++CONFIG_SSB_POSSIBLE=y
++# CONFIG_SSB is not set
 +
-+static void __init genclk_init_parent(struct clk *clk)
-+{
-+	u32 control;
-+	struct clk *parent;
++#
++# Multifunction device drivers
++#
++# CONFIG_MFD_SM501 is not set
 +
-+	BUG_ON(clk->index > 7);
++#
++# Multimedia devices
++#
++# CONFIG_VIDEO_DEV is not set
++# CONFIG_DVB_CORE is not set
++# CONFIG_DAB is not set
 +
-+	control = pm_readl(GCCTRL(clk->index));
-+	if (control & PM_BIT(OSCSEL))
-+		parent = (control & PM_BIT(PLLSEL)) ? &pll1 : &osc1;
-+	else
-+		parent = (control & PM_BIT(PLLSEL)) ? &pll0 : &osc0;
++#
++# 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
 +
-+	clk->parent = parent;
-+}
++#
++# Display device support
++#
++# CONFIG_DISPLAY_SUPPORT is not set
 +
-+/* --------------------------------------------------------------------
-+ *  System peripherals
-+ * -------------------------------------------------------------------- */
-+static struct resource at32_pm0_resource[] = {
-+	{
-+		.start	= 0xfff00000,
-+		.end	= 0xfff0007f,
-+		.flags	= IORESOURCE_MEM,
-+	},
-+	IRQ(20),
-+};
++#
++# Console display driver support
++#
++# CONFIG_VGA_CONSOLE is not set
++CONFIG_DUMMY_CONSOLE=y
 +
-+static struct resource at32ap700x_rtc0_resource[] = {
-+	{
-+		.start	= 0xfff00080,
-+		.end	= 0xfff000af,
-+		.flags	= IORESOURCE_MEM,
-+	},
-+	IRQ(21),
-+};
++#
++# Sound
++#
++CONFIG_SOUND=y
 +
-+static struct resource at32_wdt0_resource[] = {
-+	{
-+		.start	= 0xfff000b0,
-+		.end	= 0xfff000cf,
-+		.flags	= IORESOURCE_MEM,
-+	},
-+};
++#
++# Advanced Linux Sound Architecture
++#
++CONFIG_SND=y
++CONFIG_SND_TIMER=y
++CONFIG_SND_PCM=y
++# CONFIG_SND_SEQUENCER is not set
++CONFIG_SND_OSSEMUL=y
++CONFIG_SND_MIXER_OSS=y
++CONFIG_SND_PCM_OSS=y
++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
 +
-+static struct resource at32_eic0_resource[] = {
-+	{
-+		.start	= 0xfff00100,
-+		.end	= 0xfff0013f,
-+		.flags	= IORESOURCE_MEM,
-+	},
-+	IRQ(19),
-+};
++#
++# Generic devices
++#
++CONFIG_SND_AC97_CODEC=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
 +
-+DEFINE_DEV(at32_pm, 0);
-+DEFINE_DEV(at32ap700x_rtc, 0);
-+DEFINE_DEV(at32_wdt, 0);
-+DEFINE_DEV(at32_eic, 0);
++#
++# ALSA ARM devices
++#
++CONFIG_SND_PXA2XX_PCM=y
++CONFIG_SND_PXA2XX_AC97=y
 +
-+/*
-+ * Peripheral clock for PM, RTC, WDT and EIC. PM will ensure that this
-+ * is always running.
-+ */
-+static struct clk at32_pm_pclk = {
-+	.name		= "pclk",
-+	.dev		= &at32_pm0_device.dev,
-+	.parent		= &pbb_clk,
-+	.mode		= pbb_clk_mode,
-+	.get_rate	= pbb_clk_get_rate,
-+	.users		= 1,
-+	.index		= 0,
-+};
++#
++# USB devices
++#
++# CONFIG_SND_USB_AUDIO is not set
++# CONFIG_SND_USB_CAIAQ is not set
 +
-+static struct resource intc0_resource[] = {
-+	PBMEM(0xfff00400),
-+};
-+struct platform_device at32_intc0_device = {
-+	.name		= "intc",
-+	.id		= 0,
-+	.resource	= intc0_resource,
-+	.num_resources	= ARRAY_SIZE(intc0_resource),
-+};
-+DEV_CLK(pclk, at32_intc0, pbb, 1);
++#
++# System on Chip audio support
++#
++# CONFIG_SND_SOC is not set
 +
-+static struct clk ebi_clk = {
-+	.name		= "ebi",
-+	.parent		= &hsb_clk,
-+	.mode		= hsb_clk_mode,
-+	.get_rate	= hsb_clk_get_rate,
-+	.users		= 1,
-+};
-+static struct clk hramc_clk = {
-+	.name		= "hramc",
-+	.parent		= &hsb_clk,
-+	.mode		= hsb_clk_mode,
-+	.get_rate	= hsb_clk_get_rate,
-+	.users		= 1,
-+	.index		= 3,
-+};
++#
++# SoC Audio support for SuperH
++#
 +
-+static struct resource smc0_resource[] = {
-+	PBMEM(0xfff03400),
-+};
-+DEFINE_DEV(smc, 0);
-+DEV_CLK(pclk, smc0, pbb, 13);
-+DEV_CLK(mck, smc0, hsb, 0);
++#
++# Open Sound System
++#
++# CONFIG_SOUND_PRIME is not set
++CONFIG_AC97_BUS=y
++# CONFIG_HID_SUPPORT 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
 +
-+static struct platform_device pdc_device = {
-+	.name		= "pdc",
-+	.id		= 0,
-+};
-+DEV_CLK(hclk, pdc, hsb, 4);
-+DEV_CLK(pclk, pdc, pba, 16);
++#
++# 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
 +
-+static struct clk pico_clk = {
-+	.name		= "pico",
-+	.parent		= &cpu_clk,
-+	.mode		= cpu_clk_mode,
-+	.get_rate	= cpu_clk_get_rate,
-+	.users		= 1,
-+};
++#
++# USB Host Controller Drivers
++#
++# 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_SL811_HCD is not set
++# CONFIG_USB_R8A66597_HCD is not set
 +
-+static struct resource dmaca0_resource[] = {
-+	{
-+		.start	= 0xff200000,
-+		.end	= 0xff20ffff,
-+		.flags	= IORESOURCE_MEM,
-+	},
-+	IRQ(2),
-+};
-+DEFINE_DEV(dmaca, 0);
-+DEV_CLK(hclk, dmaca0, hsb, 10);
++#
++# USB Device Class drivers
++#
++# CONFIG_USB_ACM is not set
++# CONFIG_USB_PRINTER is not set
 +
-+/* --------------------------------------------------------------------
-+ * HMATRIX
-+ * -------------------------------------------------------------------- */
++#
++# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
++#
 +
-+static struct clk hmatrix_clk = {
-+	.name		= "hmatrix_clk",
-+	.parent		= &pbb_clk,
-+	.mode		= pbb_clk_mode,
-+	.get_rate	= pbb_clk_get_rate,
-+	.index		= 2,
-+	.users		= 1,
-+};
-+#define HMATRIX_BASE	((void __iomem *)0xfff00800)
++#
++# 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_KARMA is not set
++# CONFIG_USB_LIBUSUAL is not set
 +
-+#define hmatrix_readl(reg)					\
-+	__raw_readl((HMATRIX_BASE) + HMATRIX_##reg)
-+#define hmatrix_writel(reg,value)				\
-+	__raw_writel((value), (HMATRIX_BASE) + HMATRIX_##reg)
++#
++# USB Imaging devices
++#
++# CONFIG_USB_MDC800 is not set
++# CONFIG_USB_MICROTEK is not set
++# CONFIG_USB_MON is not set
 +
-+/*
-+ * Set bits in the HMATRIX Special Function Register (SFR) used by the
-+ * External Bus Interface (EBI). This can be used to enable special
-+ * features like CompactFlash support, NAND Flash support, etc. on
-+ * certain chipselects.
-+ */
-+static inline void set_ebi_sfr_bits(u32 mask)
-+{
-+	u32 sfr;
++#
++# USB port drivers
++#
 +
-+	clk_enable(&hmatrix_clk);
-+	sfr = hmatrix_readl(SFR4);
-+	sfr |= mask;
-+	hmatrix_writel(SFR4, sfr);
-+	clk_disable(&hmatrix_clk);
-+}
++#
++# USB Serial Converter support
++#
++# CONFIG_USB_SERIAL is not set
 +
-+/* --------------------------------------------------------------------
-+ *  System Timer/Counter (TC)
-+ * -------------------------------------------------------------------- */
-+static struct resource at32_systc0_resource[] = {
-+	PBMEM(0xfff00c00),
-+	IRQ(22),
-+};
-+struct platform_device at32_systc0_device = {
-+	.name		= "systc",
-+	.id		= 0,
-+	.resource	= at32_systc0_resource,
-+	.num_resources	= ARRAY_SIZE(at32_systc0_resource),
-+};
-+DEV_CLK(pclk, at32_systc0, pbb, 3);
++#
++# 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
 +
-+/* --------------------------------------------------------------------
-+ *  PIO
-+ * -------------------------------------------------------------------- */
++#
++# USB DSL modem support
++#
 +
-+static struct resource pio0_resource[] = {
-+	PBMEM(0xffe02800),
-+	IRQ(13),
-+};
-+DEFINE_DEV(pio, 0);
-+DEV_CLK(mck, pio0, pba, 10);
++#
++# USB Gadget Support
++#
++# CONFIG_USB_GADGET is not set
++CONFIG_MMC=y
++# CONFIG_MMC_DEBUG is not set
++# CONFIG_MMC_UNSAFE_RESUME is not set
 +
-+static struct resource pio1_resource[] = {
-+	PBMEM(0xffe02c00),
-+	IRQ(14),
-+};
-+DEFINE_DEV(pio, 1);
-+DEV_CLK(mck, pio1, pba, 11);
++#
++# MMC/SD Card Drivers
++#
++CONFIG_MMC_BLOCK=y
++CONFIG_MMC_BLOCK_BOUNCE=y
++# CONFIG_SDIO_UART is not set
 +
-+static struct resource pio2_resource[] = {
-+	PBMEM(0xffe03000),
-+	IRQ(15),
-+};
-+DEFINE_DEV(pio, 2);
-+DEV_CLK(mck, pio2, pba, 12);
++#
++# MMC/SD Host Controller Drivers
++#
++CONFIG_MMC_PXA=y
++# 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
 +
-+static struct resource pio3_resource[] = {
-+	PBMEM(0xffe03400),
-+	IRQ(16),
-+};
-+DEFINE_DEV(pio, 3);
-+DEV_CLK(mck, pio3, pba, 13);
++#
++# 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
 +
-+static struct resource pio4_resource[] = {
-+	PBMEM(0xffe03800),
-+	IRQ(17),
-+};
-+DEFINE_DEV(pio, 4);
-+DEV_CLK(mck, pio4, pba, 14);
++#
++# 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=m
++# CONFIG_RTC_DRV_PCF8583 is not set
++# CONFIG_RTC_DRV_M41T80 is not set
 +
-+void __init at32_add_system_devices(void)
-+{
-+	platform_device_register(&at32_pm0_device);
-+	platform_device_register(&at32_intc0_device);
-+	platform_device_register(&at32ap700x_rtc0_device);
-+	platform_device_register(&at32_wdt0_device);
-+	platform_device_register(&at32_eic0_device);
-+	platform_device_register(&smc0_device);
-+	platform_device_register(&pdc_device);
-+	platform_device_register(&dmaca0_device);
++#
++# SPI RTC drivers
++#
 +
-+	platform_device_register(&at32_systc0_device);
++#
++# Platform RTC drivers
++#
++# CONFIG_RTC_DRV_CMOS is not set
++# CONFIG_RTC_DRV_DS1553 is not set
++# CONFIG_RTC_DRV_STK17TA8 is not set
++# CONFIG_RTC_DRV_DS1742 is not set
++# CONFIG_RTC_DRV_M48T86 is not set
++# CONFIG_RTC_DRV_M48T59 is not set
++# CONFIG_RTC_DRV_V3020 is not set
 +
-+	platform_device_register(&pio0_device);
-+	platform_device_register(&pio1_device);
-+	platform_device_register(&pio2_device);
-+	platform_device_register(&pio3_device);
-+	platform_device_register(&pio4_device);
-+}
++#
++# on-CPU RTC drivers
++#
++CONFIG_RTC_DRV_SA1100=m
 +
-+/* --------------------------------------------------------------------
-+ *  USART
-+ * -------------------------------------------------------------------- */
++#
++# 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=y
++# CONFIG_EXT3_FS_POSIX_ACL is not set
++# CONFIG_EXT3_FS_SECURITY is not set
++# CONFIG_EXT4DEV_FS is not set
++CONFIG_JBD=m
++CONFIG_FS_MBCACHE=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_GFS2_FS is not set
++# CONFIG_OCFS2_FS is not set
++# CONFIG_MINIX_FS is not set
++# CONFIG_ROMFS_FS is not set
++# CONFIG_INOTIFY is not set
++# CONFIG_QUOTA is not set
++# CONFIG_DNOTIFY is not set
++# CONFIG_AUTOFS_FS is not set
++# CONFIG_AUTOFS4_FS is not set
++# CONFIG_FUSE_FS is not set
 +
-+static struct atmel_uart_data atmel_usart0_data = {
-+	.use_dma_tx	= 1,
-+	.use_dma_rx	= 1,
-+};
-+static struct resource atmel_usart0_resource[] = {
-+	PBMEM(0xffe00c00),
-+	IRQ(6),
-+};
-+DEFINE_DEV_DATA(atmel_usart, 0);
-+DEV_CLK(usart, atmel_usart0, pba, 3);
++#
++# CD-ROM/DVD Filesystems
++#
++# CONFIG_ISO9660_FS is not set
++# CONFIG_UDF_FS is not set
 +
-+static struct atmel_uart_data atmel_usart1_data = {
-+	.use_dma_tx	= 1,
-+	.use_dma_rx	= 1,
-+};
-+static struct resource atmel_usart1_resource[] = {
-+	PBMEM(0xffe01000),
-+	IRQ(7),
-+};
-+DEFINE_DEV_DATA(atmel_usart, 1);
-+DEV_CLK(usart, atmel_usart1, pba, 4);
++#
++# DOS/FAT/NT Filesystems
++#
++CONFIG_FAT_FS=m
++# CONFIG_MSDOS_FS is not set
++CONFIG_VFAT_FS=m
++CONFIG_FAT_DEFAULT_CODEPAGE=850
++CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-15"
++# CONFIG_NTFS_FS is not set
 +
-+static struct atmel_uart_data atmel_usart2_data = {
-+	.use_dma_tx	= 1,
-+	.use_dma_rx	= 1,
-+};
-+static struct resource atmel_usart2_resource[] = {
-+	PBMEM(0xffe01400),
-+	IRQ(8),
-+};
-+DEFINE_DEV_DATA(atmel_usart, 2);
-+DEV_CLK(usart, atmel_usart2, pba, 5);
++#
++# 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
 +
-+static struct atmel_uart_data atmel_usart3_data = {
-+	.use_dma_tx	= 1,
-+	.use_dma_rx	= 1,
-+};
-+static struct resource atmel_usart3_resource[] = {
-+	PBMEM(0xffe01800),
-+	IRQ(9),
++#
++# 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_HPFS_FS is not set
++# CONFIG_QNX4FS_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_NFS_DIRECTIO=y
++# 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 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=y
++CONFIG_NLS_DEFAULT="iso8859-15"
++# 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=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 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=y
++# 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
++# CONFIG_INSTRUMENTATION is not set
++
++#
++# Kernel hacking
++#
++# CONFIG_PRINTK_TIME is not set
++CONFIG_ENABLE_WARN_DEPRECATED=y
++CONFIG_ENABLE_MUST_CHECK=y
++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 is not set
++# CONFIG_DEBUG_BUGVERBOSE is not set
++CONFIG_FRAME_POINTER=y
++# CONFIG_SAMPLES is not set
++# CONFIG_DEBUG_USER 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_CRC_CCITT is not set
++# 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/kernel/Makefile b/arch/arm/kernel/Makefile
+index 593b565..faa7619 100644
+--- a/arch/arm/kernel/Makefile
++++ b/arch/arm/kernel/Makefile
+@@ -19,6 +19,7 @@ obj-$(CONFIG_ISA_DMA)		+= dma-isa.o
+ obj-$(CONFIG_PCI)		+= bios32.o isa.o
+ obj-$(CONFIG_SMP)		+= smp.o
+ obj-$(CONFIG_KEXEC)		+= machine_kexec.o relocate_kernel.o
++obj-$(CONFIG_KPROBES)		+= kprobes.o kprobes-decode.o
+ obj-$(CONFIG_OABI_COMPAT)	+= sys_oabi-compat.o
+ 
+ obj-$(CONFIG_CRUNCH)		+= crunch.o crunch-bits.o
+diff --git a/arch/arm/kernel/dma-isa.c b/arch/arm/kernel/dma-isa.c
+index 0a3e9ad..2f080a3 100644
+--- a/arch/arm/kernel/dma-isa.c
++++ b/arch/arm/kernel/dma-isa.c
+@@ -216,7 +216,7 @@ void __init isa_init_dma(dma_t *dma)
+ 
+ 		request_dma(DMA_ISA_CASCADE, "cascade");
+ 
+-		for (i = 0; i < sizeof(dma_resources) / sizeof(dma_resources[0]); i++)
++		for (i = 0; i < ARRAY_SIZE(dma_resources); i++)
+ 			request_resource(&ioport_resource, dma_resources + i);
+ 	}
+ }
+diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
+index 29dec08..a46d5b4 100644
+--- a/arch/arm/kernel/entry-armv.S
++++ b/arch/arm/kernel/entry-armv.S
+@@ -11,8 +11,8 @@
+  *
+  *  Low-level vector interface routines
+  *
+- *  Note:  there is a StrongARM bug in the STMIA rn, {regs}^ instruction that causes
+- *  it to save wrong values...  Be aware!
++ *  Note:  there is a StrongARM bug in the STMIA rn, {regs}^ instruction
++ *  that causes it to save wrong values...  Be aware!
+  */
+ 
+ #include <asm/memory.h>
+@@ -58,6 +58,12 @@
+ 
+ 	.endm
+ 
++#ifdef CONFIG_KPROBES
++	.section	.kprobes.text,"ax",%progbits
++#else
++	.text
++#endif
++
+ /*
+  * Invalid mode handlers
+  */
+@@ -112,8 +118,8 @@ common_invalid:
+ #define SPFIX(code...)
+ #endif
+ 
+-	.macro	svc_entry
+-	sub	sp, sp, #S_FRAME_SIZE
++	.macro	svc_entry, stack_hole=0
++	sub	sp, sp, #(S_FRAME_SIZE + \stack_hole)
+  SPFIX(	tst	sp, #4		)
+  SPFIX(	bicne	sp, sp, #4	)
+ 	stmib	sp, {r1 - r12}
+@@ -121,7 +127,7 @@ common_invalid:
+ 	ldmia	r0, {r1 - r3}
+ 	add	r5, sp, #S_SP		@ here for interlock avoidance
+ 	mov	r4, #-1			@  ""  ""      ""       ""
+-	add	r0, sp, #S_FRAME_SIZE   @  ""  ""      ""       ""
++	add	r0, sp, #(S_FRAME_SIZE + \stack_hole)
+  SPFIX(	addne	r0, r0, #4	)
+ 	str	r1, [sp]		@ save the "real" r0 copied
+ 					@ from the exception stack
+@@ -242,7 +248,14 @@ svc_preempt:
+ 
+ 	.align	5
+ __und_svc:
++#ifdef CONFIG_KPROBES
++	@ If a kprobe is about to simulate a "stmdb sp..." instruction,
++	@ it obviously needs free stack space which then will belong to
++	@ the saved context.
++	svc_entry 64
++#else
+ 	svc_entry
++#endif
+ 
+ 	@
+ 	@ call emulation code, which returns using r9 if it has emulated
+@@ -480,6 +493,13 @@ __und_usr:
+  * co-processor instructions.  However, we have to watch out
+  * for the ARM6/ARM7 SWI bug.
+  *
++ * NEON is a special case that has to be handled here. Not all
++ * NEON instructions are co-processor instructions, so we have
++ * to make a special case of checking for them. Plus, there's
++ * five groups of them, so we have a table of mask/opcode pairs
++ * to check against, and if any match then we branch off into the
++ * NEON handler code.
++ *
+  * Emulators may wish to make use of the following registers:
+  *  r0  = instruction opcode.
+  *  r2  = PC+4
+@@ -488,6 +508,23 @@ __und_usr:
+  *  lr  = unrecognised instruction return address
+  */
+ call_fpe:
++#ifdef CONFIG_NEON
++	adr	r6, .LCneon_opcodes
++2:
++	ldr	r7, [r6], #4			@ mask value
++	cmp	r7, #0				@ end mask?
++	beq	1f
++	and	r8, r0, r7
++	ldr	r7, [r6], #4			@ opcode bits matching in mask
++	cmp	r8, r7				@ NEON instruction?
++	bne	2b
++	get_thread_info r10
++	mov	r7, #1
++	strb	r7, [r10, #TI_USED_CP + 10]	@ mark CP#10 as used
++	strb	r7, [r10, #TI_USED_CP + 11]	@ mark CP#11 as used
++	b	do_vfp				@ let VFP handler handle this
++1:
++#endif
+ 	tst	r0, #0x08000000			@ only CDP/CPRT/LDC/STC have bit 27
+ #if defined(CONFIG_CPU_ARM610) || defined(CONFIG_CPU_ARM710)
+ 	and	r8, r0, #0x0f000000		@ mask out op-code bits
+@@ -537,6 +574,20 @@ call_fpe:
+ 	mov	pc, lr				@ CP#14 (Debug)
+ 	mov	pc, lr				@ CP#15 (Control)
+ 
++#ifdef CONFIG_NEON
++	.align	6
++
++.LCneon_opcodes:
++	.word	0xfe000000			@ mask
++	.word	0xf2000000			@ opcode
++
++	.word	0xff100000			@ mask
++	.word	0xf4000000			@ opcode
++
++	.word	0x00000000			@ mask
++	.word	0x00000000			@ opcode
++#endif
++
+ do_fpe:
+ 	enable_irq
+ 	ldr	r4, .LCfp
+@@ -555,7 +606,7 @@ do_fpe:
+ 	.data
+ ENTRY(fp_enter)
+ 	.word	no_fp
+-	.text
++	.previous
+ 
+ no_fp:	mov	pc, lr
+ 
+diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S
+index 33e6cc2..6c90c50 100644
+--- a/arch/arm/kernel/entry-common.S
++++ b/arch/arm/kernel/entry-common.S
+@@ -72,7 +72,7 @@ no_work_pending:
+ 	ldr	r1, [sp, #S_PSR]		@ get calling cpsr
+ 	ldr	lr, [sp, #S_PC]!		@ get pc
+ 	msr	spsr_cxsf, r1			@ save in spsr_svc
+-	ldmdb	sp, {r0 - lr}^			@ get calling r1 - lr
++	ldmdb	sp, {r0 - lr}^			@ get calling r0 - lr
+ 	mov	r0, r0
+ 	add	sp, sp, #S_FRAME_SIZE - S_PC
+ 	movs	pc, lr				@ return & move spsr_svc into cpsr
+diff --git a/arch/arm/kernel/kprobes-decode.c b/arch/arm/kernel/kprobes-decode.c
+new file mode 100644
+index 0000000..d51bc8b
+--- /dev/null
++++ b/arch/arm/kernel/kprobes-decode.c
+@@ -0,0 +1,1529 @@
++/*
++ * arch/arm/kernel/kprobes-decode.c
++ *
++ * Copyright (C) 2006, 2007 Motorola 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.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++ * General Public License for more details.
++ */
++
++/*
++ * We do not have hardware single-stepping on ARM, This
++ * effort is further complicated by the ARM not having a
++ * "next PC" register.  Instructions that change the PC
++ * can't be safely single-stepped in a MP environment, so
++ * we have a lot of work to do:
++ *
++ * In the prepare phase:
++ *   *) If it is an instruction that does anything
++ *      with the CPU mode, we reject it for a kprobe.
++ *      (This is out of laziness rather than need.  The
++ *      instructions could be simulated.)
++ *
++ *   *) Otherwise, decode the instruction rewriting its
++ *      registers to take fixed, ordered registers and
++ *      setting a handler for it to run the instruction.
++ *
++ * In the execution phase by an instruction's handler:
++ *
++ *   *) If the PC is written to by the instruction, the
++ *      instruction must be fully simulated in software.
++ *      If it is a conditional instruction, the handler
++ *      will use insn[0] to copy its condition code to
++ *	set r0 to 1 and insn[1] to "mov pc, lr" to return.
++ *
++ *   *) Otherwise, a modified form of the instruction is
++ *      directly executed.  Its handler calls the
++ *      instruction in insn[0].  In insn[1] is a
++ *      "mov pc, lr" to return.
++ *
++ *      Before calling, load up the reordered registers
++ *      from the original instruction's registers.  If one
++ *      of the original input registers is the PC, compute
++ *      and adjust the appropriate input register.
++ *
++ *	After call completes, copy the output registers to
++ *      the original instruction's original registers.
++ *
++ * We don't use a real breakpoint instruction since that
++ * would have us in the kernel go from SVC mode to SVC
++ * mode losing the link register.  Instead we use an
++ * undefined instruction.  To simplify processing, the
++ * undefined instruction used for kprobes must be reserved
++ * exclusively for kprobes use.
++ *
++ * TODO: ifdef out some instruction decoding based on architecture.
++ */
++
++#include <linux/kernel.h>
++#include <linux/kprobes.h>
++
++#define sign_extend(x, signbit) ((x) | (0 - ((x) & (1 << (signbit)))))
++
++#define branch_displacement(insn) sign_extend(((insn) & 0xffffff) << 2, 25)
++
++#define PSR_fs	(PSR_f|PSR_s)
++
++#define KPROBE_RETURN_INSTRUCTION	0xe1a0f00e	/* mov pc, lr */
++#define SET_R0_TRUE_INSTRUCTION		0xe3a00001	/* mov	r0, #1 */
++
++#define	truecc_insn(insn)	(((insn) & 0xf0000000) | \
++				 (SET_R0_TRUE_INSTRUCTION & 0x0fffffff))
++
++typedef long (insn_0arg_fn_t)(void);
++typedef long (insn_1arg_fn_t)(long);
++typedef long (insn_2arg_fn_t)(long, long);
++typedef long (insn_3arg_fn_t)(long, long, long);
++typedef long (insn_4arg_fn_t)(long, long, long, long);
++typedef long long (insn_llret_0arg_fn_t)(void);
++typedef long long (insn_llret_3arg_fn_t)(long, long, long);
++typedef long long (insn_llret_4arg_fn_t)(long, long, long, long);
++
++union reg_pair {
++	long long	dr;
++#ifdef __LITTLE_ENDIAN
++	struct { long	r0, r1; };
++#else
++	struct { long	r1, r0; };
++#endif
 +};
-+DEFINE_DEV_DATA(atmel_usart, 3);
-+DEV_CLK(usart, atmel_usart3, pba, 6);
 +
-+static inline void configure_usart0_pins(void)
++/*
++ * For STR and STM instructions, an ARM core may choose to use either
++ * a +8 or a +12 displacement from the current instruction's address.
++ * Whichever value is chosen for a given core, it must be the same for
++ * both instructions and may not change.  This function measures it.
++ */
++
++static int str_pc_offset;
++
++static void __init find_str_pc_offset(void)
 +{
-+	select_peripheral(PA(8),  PERIPH_B, 0);	/* RXD	*/
-+	select_peripheral(PA(9),  PERIPH_B, 0);	/* TXD	*/
++	int addr, scratch, ret;
++
++	__asm__ (
++		"sub	%[ret], pc, #4		\n\t"
++		"str	pc, %[addr]		\n\t"
++		"ldr	%[scr], %[addr]		\n\t"
++		"sub	%[ret], %[scr], %[ret]	\n\t"
++		: [ret] "=r" (ret), [scr] "=r" (scratch), [addr] "+m" (addr));
++
++	str_pc_offset = ret;
 +}
 +
-+static inline void configure_usart1_pins(void)
++/*
++ * The insnslot_?arg_r[w]flags() functions below are to keep the
++ * msr -> *fn -> mrs instruction sequences indivisible so that
++ * the state of the CPSR flags aren't inadvertently modified
++ * just before or just after the call.
++ */
++
++static inline long __kprobes
++insnslot_0arg_rflags(long cpsr, insn_0arg_fn_t *fn)
 +{
-+	select_peripheral(PA(17), PERIPH_A, 0);	/* RXD	*/
-+	select_peripheral(PA(18), PERIPH_A, 0);	/* TXD	*/
++	register long ret asm("r0");
++
++	__asm__ __volatile__ (
++		"msr	cpsr_fs, %[cpsr]	\n\t"
++		"mov	lr, pc			\n\t"
++		"mov	pc, %[fn]		\n\t"
++		: "=r" (ret)
++		: [cpsr] "r" (cpsr), [fn] "r" (fn)
++		: "lr", "cc"
++	);
++	return ret;
 +}
 +
-+static inline void configure_usart2_pins(void)
++static inline long long __kprobes
++insnslot_llret_0arg_rflags(long cpsr, insn_llret_0arg_fn_t *fn)
 +{
-+	select_peripheral(PB(26), PERIPH_B, 0);	/* RXD	*/
-+	select_peripheral(PB(27), PERIPH_B, 0);	/* TXD	*/
++	register long ret0 asm("r0");
++	register long ret1 asm("r1");
++	union reg_pair fnr;
++
++	__asm__ __volatile__ (
++		"msr	cpsr_fs, %[cpsr]	\n\t"
++		"mov	lr, pc			\n\t"
++		"mov	pc, %[fn]		\n\t"
++		: "=r" (ret0), "=r" (ret1)
++		: [cpsr] "r" (cpsr), [fn] "r" (fn)
++		: "lr", "cc"
++	);
++	fnr.r0 = ret0;
++	fnr.r1 = ret1;
++	return fnr.dr;
++}
++
++static inline long __kprobes
++insnslot_1arg_rflags(long r0, long cpsr, insn_1arg_fn_t *fn)
++{
++	register long rr0 asm("r0") = r0;
++	register long ret asm("r0");
++
++	__asm__ __volatile__ (
++		"msr	cpsr_fs, %[cpsr]	\n\t"
++		"mov	lr, pc			\n\t"
++		"mov	pc, %[fn]		\n\t"
++		: "=r" (ret)
++		: "0" (rr0), [cpsr] "r" (cpsr), [fn] "r" (fn)
++		: "lr", "cc"
++	);
++	return ret;
 +}
 +
-+static inline void configure_usart3_pins(void)
++static inline long __kprobes
++insnslot_2arg_rflags(long r0, long r1, long cpsr, insn_2arg_fn_t *fn)
 +{
-+	select_peripheral(PB(18), PERIPH_B, 0);	/* RXD	*/
-+	select_peripheral(PB(17), PERIPH_B, 0);	/* TXD	*/
++	register long rr0 asm("r0") = r0;
++	register long rr1 asm("r1") = r1;
++	register long ret asm("r0");
++
++	__asm__ __volatile__ (
++		"msr	cpsr_fs, %[cpsr]	\n\t"
++		"mov	lr, pc			\n\t"
++		"mov	pc, %[fn]		\n\t"
++		: "=r" (ret)
++		: "0" (rr0), "r" (rr1),
++		  [cpsr] "r" (cpsr), [fn] "r" (fn)
++		: "lr", "cc"
++	);
++	return ret;
 +}
 +
-+static struct platform_device *__initdata at32_usarts[4];
-+
-+void __init at32_map_usart(unsigned int hw_id, unsigned int line)
++static inline long __kprobes
++insnslot_3arg_rflags(long r0, long r1, long r2, long cpsr, insn_3arg_fn_t *fn)
 +{
-+	struct platform_device *pdev;
-+
-+	switch (hw_id) {
-+	case 0:
-+		pdev = &atmel_usart0_device;
-+		configure_usart0_pins();
-+		break;
-+	case 1:
-+		pdev = &atmel_usart1_device;
-+		configure_usart1_pins();
-+		break;
-+	case 2:
-+		pdev = &atmel_usart2_device;
-+		configure_usart2_pins();
-+		break;
-+	case 3:
-+		pdev = &atmel_usart3_device;
-+		configure_usart3_pins();
-+		break;
-+	default:
-+		return;
-+	}
++	register long rr0 asm("r0") = r0;
++	register long rr1 asm("r1") = r1;
++	register long rr2 asm("r2") = r2;
++	register long ret asm("r0");
++
++	__asm__ __volatile__ (
++		"msr	cpsr_fs, %[cpsr]	\n\t"
++		"mov	lr, pc			\n\t"
++		"mov	pc, %[fn]		\n\t"
++		: "=r" (ret)
++		: "0" (rr0), "r" (rr1), "r" (rr2),
++		  [cpsr] "r" (cpsr), [fn] "r" (fn)
++		: "lr", "cc"
++	);
++	return ret;
++}
 +
-+	if (PXSEG(pdev->resource[0].start) == P4SEG) {
-+		/* Addresses in the P4 segment are permanently mapped 1:1 */
-+		struct atmel_uart_data *data = pdev->dev.platform_data;
-+		data->regs = (void __iomem *)pdev->resource[0].start;
-+	}
++static inline long long __kprobes
++insnslot_llret_3arg_rflags(long r0, long r1, long r2, long cpsr,
++			   insn_llret_3arg_fn_t *fn)
++{
++	register long rr0 asm("r0") = r0;
++	register long rr1 asm("r1") = r1;
++	register long rr2 asm("r2") = r2;
++	register long ret0 asm("r0");
++	register long ret1 asm("r1");
++	union reg_pair fnr;
++
++	__asm__ __volatile__ (
++		"msr	cpsr_fs, %[cpsr]	\n\t"
++		"mov	lr, pc			\n\t"
++		"mov	pc, %[fn]		\n\t"
++		: "=r" (ret0), "=r" (ret1)
++		: "0" (rr0), "r" (rr1), "r" (rr2),
++		  [cpsr] "r" (cpsr), [fn] "r" (fn)
++		: "lr", "cc"
++	);
++	fnr.r0 = ret0;
++	fnr.r1 = ret1;
++	return fnr.dr;
++}
++
++static inline long __kprobes
++insnslot_4arg_rflags(long r0, long r1, long r2, long r3, long cpsr,
++		     insn_4arg_fn_t *fn)
++{
++	register long rr0 asm("r0") = r0;
++	register long rr1 asm("r1") = r1;
++	register long rr2 asm("r2") = r2;
++	register long rr3 asm("r3") = r3;
++	register long ret asm("r0");
++
++	__asm__ __volatile__ (
++		"msr	cpsr_fs, %[cpsr]	\n\t"
++		"mov	lr, pc			\n\t"
++		"mov	pc, %[fn]		\n\t"
++		: "=r" (ret)
++		: "0" (rr0), "r" (rr1), "r" (rr2), "r" (rr3),
++		  [cpsr] "r" (cpsr), [fn] "r" (fn)
++		: "lr", "cc"
++	);
++	return ret;
++}
 +
-+	pdev->id = line;
-+	at32_usarts[line] = pdev;
++static inline long __kprobes
++insnslot_1arg_rwflags(long r0, long *cpsr, insn_1arg_fn_t *fn)
++{
++	register long rr0 asm("r0") = r0;
++	register long ret asm("r0");
++	long oldcpsr = *cpsr;
++	long newcpsr;
++
++	__asm__ __volatile__ (
++		"msr	cpsr_fs, %[oldcpsr]	\n\t"
++		"mov	lr, pc			\n\t"
++		"mov	pc, %[fn]		\n\t"
++		"mrs	%[newcpsr], cpsr	\n\t"
++		: "=r" (ret), [newcpsr] "=r" (newcpsr)
++		: "0" (rr0), [oldcpsr] "r" (oldcpsr), [fn] "r" (fn)
++		: "lr", "cc"
++	);
++	*cpsr = (oldcpsr & ~PSR_fs) | (newcpsr & PSR_fs);
++	return ret;
 +}
 +
-+struct platform_device *__init at32_add_device_usart(unsigned int id)
++static inline long __kprobes
++insnslot_2arg_rwflags(long r0, long r1, long *cpsr, insn_2arg_fn_t *fn)
 +{
-+	platform_device_register(at32_usarts[id]);
-+	return at32_usarts[id];
++	register long rr0 asm("r0") = r0;
++	register long rr1 asm("r1") = r1;
++	register long ret asm("r0");
++	long oldcpsr = *cpsr;
++	long newcpsr;
++
++	__asm__ __volatile__ (
++		"msr	cpsr_fs, %[oldcpsr]	\n\t"
++		"mov	lr, pc			\n\t"
++		"mov	pc, %[fn]		\n\t"
++		"mrs	%[newcpsr], cpsr	\n\t"
++		: "=r" (ret), [newcpsr] "=r" (newcpsr)
++		: "0" (rr0), "r" (rr1), [oldcpsr] "r" (oldcpsr), [fn] "r" (fn)
++		: "lr", "cc"
++	);
++	*cpsr = (oldcpsr & ~PSR_fs) | (newcpsr & PSR_fs);
++	return ret;
 +}
 +
-+struct platform_device *atmel_default_console_device;
++static inline long __kprobes
++insnslot_3arg_rwflags(long r0, long r1, long r2, long *cpsr,
++		      insn_3arg_fn_t *fn)
++{
++	register long rr0 asm("r0") = r0;
++	register long rr1 asm("r1") = r1;
++	register long rr2 asm("r2") = r2;
++	register long ret asm("r0");
++	long oldcpsr = *cpsr;
++	long newcpsr;
++
++	__asm__ __volatile__ (
++		"msr	cpsr_fs, %[oldcpsr]	\n\t"
++		"mov	lr, pc			\n\t"
++		"mov	pc, %[fn]		\n\t"
++		"mrs	%[newcpsr], cpsr	\n\t"
++		: "=r" (ret), [newcpsr] "=r" (newcpsr)
++		: "0" (rr0), "r" (rr1), "r" (rr2),
++		  [oldcpsr] "r" (oldcpsr), [fn] "r" (fn)
++		: "lr", "cc"
++	);
++	*cpsr = (oldcpsr & ~PSR_fs) | (newcpsr & PSR_fs);
++	return ret;
++}
 +
-+void __init at32_setup_serial_console(unsigned int usart_id)
-+{
-+	atmel_default_console_device = at32_usarts[usart_id];
++static inline long __kprobes
++insnslot_4arg_rwflags(long r0, long r1, long r2, long r3, long *cpsr,
++		      insn_4arg_fn_t *fn)
++{
++	register long rr0 asm("r0") = r0;
++	register long rr1 asm("r1") = r1;
++	register long rr2 asm("r2") = r2;
++	register long rr3 asm("r3") = r3;
++	register long ret asm("r0");
++	long oldcpsr = *cpsr;
++	long newcpsr;
++
++	__asm__ __volatile__ (
++		"msr	cpsr_fs, %[oldcpsr]	\n\t"
++		"mov	lr, pc			\n\t"
++		"mov	pc, %[fn]		\n\t"
++		"mrs	%[newcpsr], cpsr	\n\t"
++		: "=r" (ret), [newcpsr] "=r" (newcpsr)
++		: "0" (rr0), "r" (rr1), "r" (rr2), "r" (rr3),
++		  [oldcpsr] "r" (oldcpsr), [fn] "r" (fn)
++		: "lr", "cc"
++	);
++	*cpsr = (oldcpsr & ~PSR_fs) | (newcpsr & PSR_fs);
++	return ret;
 +}
 +
-+/* --------------------------------------------------------------------
-+ *  Ethernet
-+ * -------------------------------------------------------------------- */
++static inline long long __kprobes
++insnslot_llret_4arg_rwflags(long r0, long r1, long r2, long r3, long *cpsr,
++			    insn_llret_4arg_fn_t *fn)
++{
++	register long rr0 asm("r0") = r0;
++	register long rr1 asm("r1") = r1;
++	register long rr2 asm("r2") = r2;
++	register long rr3 asm("r3") = r3;
++	register long ret0 asm("r0");
++	register long ret1 asm("r1");
++	long oldcpsr = *cpsr;
++	long newcpsr;
++	union reg_pair fnr;
++
++	__asm__ __volatile__ (
++		"msr	cpsr_fs, %[oldcpsr]	\n\t"
++		"mov	lr, pc			\n\t"
++		"mov	pc, %[fn]		\n\t"
++		"mrs	%[newcpsr], cpsr	\n\t"
++		: "=r" (ret0), "=r" (ret1), [newcpsr] "=r" (newcpsr)
++		: "0" (rr0), "r" (rr1), "r" (rr2), "r" (rr3),
++		  [oldcpsr] "r" (oldcpsr), [fn] "r" (fn)
++		: "lr", "cc"
++	);
++	*cpsr = (oldcpsr & ~PSR_fs) | (newcpsr & PSR_fs);
++	fnr.r0 = ret0;
++	fnr.r1 = ret1;
++	return fnr.dr;
++}
 +
-+#ifdef CONFIG_CPU_AT32AP7000
-+static struct eth_platform_data macb0_data;
-+static struct resource macb0_resource[] = {
-+	PBMEM(0xfff01800),
-+	IRQ(25),
-+};
-+DEFINE_DEV_DATA(macb, 0);
-+DEV_CLK(hclk, macb0, hsb, 8);
-+DEV_CLK(pclk, macb0, pbb, 6);
++/*
++ * To avoid the complications of mimicing single-stepping on a
++ * processor without a Next-PC or a single-step mode, and to
++ * avoid having to deal with the side-effects of boosting, we
++ * simulate or emulate (almost) all ARM instructions.
++ *
++ * "Simulation" is where the instruction's behavior is duplicated in
++ * C code.  "Emulation" is where the original instruction is rewritten
++ * and executed, often by altering its registers.
++ *
++ * By having all behavior of the kprobe'd instruction completed before
++ * returning from the kprobe_handler(), all locks (scheduler and
++ * interrupt) can safely be released.  There is no need for secondary
++ * breakpoints, no race with MP or preemptable kernels, nor having to
++ * clean up resources counts at a later time impacting overall system
++ * performance.  By rewriting the instruction, only the minimum registers
++ * need to be loaded and saved back optimizing performance.
++ *
++ * Calling the insnslot_*_rwflags version of a function doesn't hurt
++ * anything even when the CPSR flags aren't updated by the
++ * instruction.  It's just a little slower in return for saving
++ * a little space by not having a duplicate function that doesn't
++ * update the flags.  (The same optimization can be said for
++ * instructions that do or don't perform register writeback)
++ * Also, instructions can either read the flags, only write the
++ * flags, or read and write the flags.  To save combinations
++ * rather than for sheer performance, flag functions just assume
++ * read and write of flags.
++ */
++
++static void __kprobes simulate_bbl(struct kprobe *p, struct pt_regs *regs)
++{
++	insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0];
++	kprobe_opcode_t insn = p->opcode;
++	long iaddr = (long)p->addr;
++	int disp  = branch_displacement(insn);
 +
-+static struct eth_platform_data macb1_data;
-+static struct resource macb1_resource[] = {
-+	PBMEM(0xfff01c00),
-+	IRQ(26),
-+};
-+DEFINE_DEV_DATA(macb, 1);
-+DEV_CLK(hclk, macb1, hsb, 9);
-+DEV_CLK(pclk, macb1, pbb, 7);
++	if (!insnslot_1arg_rflags(0, regs->ARM_cpsr, i_fn))
++		return;
 +
-+struct platform_device *__init
-+at32_add_device_eth(unsigned int id, struct eth_platform_data *data)
++	if (insn & (1 << 24))
++		regs->ARM_lr = iaddr + 4;
++
++	regs->ARM_pc = iaddr + 8 + disp;
++}
++
++static void __kprobes simulate_blx1(struct kprobe *p, struct pt_regs *regs)
 +{
-+	struct platform_device *pdev;
++	kprobe_opcode_t insn = p->opcode;
++	long iaddr = (long)p->addr;
++	int disp = branch_displacement(insn);
 +
-+	switch (id) {
-+	case 0:
-+		pdev = &macb0_device;
++	regs->ARM_lr = iaddr + 4;
++	regs->ARM_pc = iaddr + 8 + disp + ((insn >> 23) & 0x2);
++	regs->ARM_cpsr |= PSR_T_BIT;
++}
 +
-+		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	*/
++static void __kprobes simulate_blx2bx(struct kprobe *p, struct pt_regs *regs)
++{
++	insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0];
++	kprobe_opcode_t insn = p->opcode;
++	int rm = insn & 0xf;
++	long rmv = regs->uregs[rm];
 +
-+		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	*/
-+		}
-+		break;
++	if (!insnslot_1arg_rflags(0, regs->ARM_cpsr, i_fn))
++		return;
 +
-+	case 1:
-+		pdev = &macb1_device;
++	if (insn & (1 << 5))
++		regs->ARM_lr = (long)p->addr + 4;
 +
-+		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	*/
++	regs->ARM_pc = rmv & ~0x1;
++	regs->ARM_cpsr &= ~PSR_T_BIT;
++	if (rmv & 0x1)
++		regs->ARM_cpsr |= PSR_T_BIT;
++}
++
++static void __kprobes simulate_ldm1stm1(struct kprobe *p, struct pt_regs *regs)
++{
++	insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0];
++	kprobe_opcode_t insn = p->opcode;
++	int rn = (insn >> 16) & 0xf;
++	int lbit = insn & (1 << 20);
++	int wbit = insn & (1 << 21);
++	int ubit = insn & (1 << 23);
++	int pbit = insn & (1 << 24);
++	long *addr = (long *)regs->uregs[rn];
++	int reg_bit_vector;
++	int reg_count;
 +
-+		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	*/
-+		}
-+		break;
++	if (!insnslot_1arg_rflags(0, regs->ARM_cpsr, i_fn))
++		return;
 +
-+	default:
-+		return NULL;
++	reg_count = 0;
++	reg_bit_vector = insn & 0xffff;
++	while (reg_bit_vector) {
++		reg_bit_vector &= (reg_bit_vector - 1);
++		++reg_count;
++	}
++
++	if (!ubit)
++		addr -= reg_count;
++	addr += (!pbit ^ !ubit);
++
++	reg_bit_vector = insn & 0xffff;
++	while (reg_bit_vector) {
++		int reg = __ffs(reg_bit_vector);
++		reg_bit_vector &= (reg_bit_vector - 1);
++		if (lbit)
++			regs->uregs[reg] = *addr++;
++		else
++			*addr++ = regs->uregs[reg];
 +	}
 +
-+	memcpy(pdev->dev.platform_data, data, sizeof(struct eth_platform_data));
-+	platform_device_register(pdev);
++	if (wbit) {
++		if (!ubit)
++			addr -= reg_count;
++		addr -= (!pbit ^ !ubit);
++		regs->uregs[rn] = (long)addr;
++	}
++}
 +
-+	return pdev;
++static void __kprobes simulate_stm1_pc(struct kprobe *p, struct pt_regs *regs)
++{
++	insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0];
++
++	if (!insnslot_1arg_rflags(0, regs->ARM_cpsr, i_fn))
++		return;
++
++	regs->ARM_pc = (long)p->addr + str_pc_offset;
++	simulate_ldm1stm1(p, regs);
++	regs->ARM_pc = (long)p->addr + 4;
++}
++
++static void __kprobes simulate_mov_ipsp(struct kprobe *p, struct pt_regs *regs)
++{
++	regs->uregs[12] = regs->uregs[13];
++}
++
++static void __kprobes emulate_ldcstc(struct kprobe *p, struct pt_regs *regs)
++{
++	insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0];
++	kprobe_opcode_t insn = p->opcode;
++	int rn = (insn >> 16) & 0xf;
++	long rnv = regs->uregs[rn];
++
++	/* Save Rn in case of writeback. */
++	regs->uregs[rn] = insnslot_1arg_rflags(rnv, regs->ARM_cpsr, i_fn);
++}
++
++static void __kprobes emulate_ldrd(struct kprobe *p, struct pt_regs *regs)
++{
++	insn_2arg_fn_t *i_fn = (insn_2arg_fn_t *)&p->ainsn.insn[0];
++	kprobe_opcode_t insn = p->opcode;
++	int rd = (insn >> 12) & 0xf;
++	int rn = (insn >> 16) & 0xf;
++	int rm = insn & 0xf;  /* rm may be invalid, don't care. */
++
++	/* Not following the C calling convention here, so need asm(). */
++	__asm__ __volatile__ (
++		"ldr	r0, %[rn]	\n\t"
++		"ldr	r1, %[rm]	\n\t"
++		"msr	cpsr_fs, %[cpsr]\n\t"
++		"mov	lr, pc		\n\t"
++		"mov	pc, %[i_fn]	\n\t"
++		"str	r0, %[rn]	\n\t"	/* in case of writeback */
++		"str	r2, %[rd0]	\n\t"
++		"str	r3, %[rd1]	\n\t"
++		: [rn]  "+m" (regs->uregs[rn]),
++		  [rd0] "=m" (regs->uregs[rd]),
++		  [rd1] "=m" (regs->uregs[rd+1])
++		: [rm]   "m" (regs->uregs[rm]),
++		  [cpsr] "r" (regs->ARM_cpsr),
++		  [i_fn] "r" (i_fn)
++		: "r0", "r1", "r2", "r3", "lr", "cc"
++	);
 +}
++
++static void __kprobes emulate_strd(struct kprobe *p, struct pt_regs *regs)
++{
++	insn_4arg_fn_t *i_fn = (insn_4arg_fn_t *)&p->ainsn.insn[0];
++	kprobe_opcode_t insn = p->opcode;
++	int rd = (insn >> 12) & 0xf;
++	int rn = (insn >> 16) & 0xf;
++	int rm  = insn & 0xf;
++	long rnv = regs->uregs[rn];
++	long rmv = regs->uregs[rm];  /* rm/rmv may be invalid, don't care. */
++
++	regs->uregs[rn] = insnslot_4arg_rflags(rnv, rmv, regs->uregs[rd],
++					       regs->uregs[rd+1],
++					       regs->ARM_cpsr, i_fn);
++}
++
++static void __kprobes emulate_ldr(struct kprobe *p, struct pt_regs *regs)
++{
++	insn_llret_3arg_fn_t *i_fn = (insn_llret_3arg_fn_t *)&p->ainsn.insn[0];
++	kprobe_opcode_t insn = p->opcode;
++	union reg_pair fnr;
++	int rd = (insn >> 12) & 0xf;
++	int rn = (insn >> 16) & 0xf;
++	int rm = insn & 0xf;
++	long rdv;
++	long rnv  = regs->uregs[rn];
++	long rmv  = regs->uregs[rm]; /* rm/rmv may be invalid, don't care. */
++	long cpsr = regs->ARM_cpsr;
++
++	fnr.dr = insnslot_llret_3arg_rflags(rnv, 0, rmv, cpsr, i_fn);
++	regs->uregs[rn] = fnr.r0;  /* Save Rn in case of writeback. */
++	rdv = fnr.r1;
++
++	if (rd == 15) {
++#if __LINUX_ARM_ARCH__ >= 5
++		cpsr &= ~PSR_T_BIT;
++		if (rdv & 0x1)
++			cpsr |= PSR_T_BIT;
++		regs->ARM_cpsr = cpsr;
++		rdv &= ~0x1;
++#else
++		rdv &= ~0x2;
 +#endif
++	}
++	regs->uregs[rd] = rdv;
++}
 +
-+/* --------------------------------------------------------------------
-+ *  SPI
-+ * -------------------------------------------------------------------- */
-+static struct resource atmel_spi0_resource[] = {
-+	PBMEM(0xffe00000),
-+	IRQ(3),
-+};
-+DEFINE_DEV(atmel_spi, 0);
-+DEV_CLK(spi_clk, atmel_spi0, pba, 0);
++static void __kprobes emulate_str(struct kprobe *p, struct pt_regs *regs)
++{
++	insn_3arg_fn_t *i_fn = (insn_3arg_fn_t *)&p->ainsn.insn[0];
++	kprobe_opcode_t insn = p->opcode;
++	long iaddr = (long)p->addr;
++	int rd = (insn >> 12) & 0xf;
++	int rn = (insn >> 16) & 0xf;
++	int rm = insn & 0xf;
++	long rdv = (rd == 15) ? iaddr + str_pc_offset : regs->uregs[rd];
++	long rnv = (rn == 15) ? iaddr +  8 : regs->uregs[rn];
++	long rmv = regs->uregs[rm];  /* rm/rmv may be invalid, don't care. */
 +
-+static struct resource atmel_spi1_resource[] = {
-+	PBMEM(0xffe00400),
-+	IRQ(4),
-+};
-+DEFINE_DEV(atmel_spi, 1);
-+DEV_CLK(spi_clk, atmel_spi1, pba, 1);
++	/* Save Rn in case of writeback. */
++	regs->uregs[rn] =
++		insnslot_3arg_rflags(rnv, rdv, rmv, regs->ARM_cpsr, i_fn);
++}
 +
-+static void __init
-+at32_spi_setup_slaves(unsigned int bus_num, struct spi_board_info *b,
-+		      unsigned int n, const u8 *pins)
++static void __kprobes emulate_mrrc(struct kprobe *p, struct pt_regs *regs)
 +{
-+	unsigned int pin, mode;
++	insn_llret_0arg_fn_t *i_fn = (insn_llret_0arg_fn_t *)&p->ainsn.insn[0];
++	kprobe_opcode_t insn = p->opcode;
++	union reg_pair fnr;
++	int rd = (insn >> 12) & 0xf;
++	int rn = (insn >> 16) & 0xf;
 +
-+	for (; n; n--, b++) {
-+		b->bus_num = bus_num;
-+		if (b->chip_select >= 4)
-+			continue;
-+		pin = (unsigned)b->controller_data;
-+		if (!pin) {
-+			pin = pins[b->chip_select];
-+			b->controller_data = (void *)pin;
-+		}
-+		mode = AT32_GPIOF_OUTPUT;
-+		if (!(b->mode & SPI_CS_HIGH))
-+			mode |= AT32_GPIOF_HIGH;
-+		at32_select_gpio(pin, mode);
-+	}
++	fnr.dr = insnslot_llret_0arg_rflags(regs->ARM_cpsr, i_fn);
++	regs->uregs[rn] = fnr.r0;
++	regs->uregs[rd] = fnr.r1;
 +}
 +
-+struct platform_device *__init
-+at32_add_device_spi(unsigned int id, struct spi_board_info *b, unsigned int n)
++static void __kprobes emulate_mcrr(struct kprobe *p, struct pt_regs *regs)
 +{
-+	/*
-+	 * Manage the chipselects as GPIOs, normally using the same pins
-+	 * the SPI controller expects; but boards can use other pins.
-+	 */
-+	static u8 __initdata spi0_pins[] =
-+		{ GPIO_PIN_PA(3), GPIO_PIN_PA(4),
-+		  GPIO_PIN_PA(5), GPIO_PIN_PA(20), };
-+	static u8 __initdata spi1_pins[] =
-+		{ GPIO_PIN_PB(2), GPIO_PIN_PB(3),
-+		  GPIO_PIN_PB(4), GPIO_PIN_PA(27), };
-+	struct platform_device *pdev;
++	insn_2arg_fn_t *i_fn = (insn_2arg_fn_t *)&p->ainsn.insn[0];
++	kprobe_opcode_t insn = p->opcode;
++	int rd = (insn >> 12) & 0xf;
++	int rn = (insn >> 16) & 0xf;
++	long rnv = regs->uregs[rn];
++	long rdv = regs->uregs[rd];
 +
-+	switch (id) {
-+	case 0:
-+		pdev = &atmel_spi0_device;
-+		select_peripheral(PA(0),  PERIPH_A, 0);	/* MISO	 */
-+		select_peripheral(PA(1),  PERIPH_A, 0);	/* MOSI	 */
-+		select_peripheral(PA(2),  PERIPH_A, 0);	/* SCK	 */
-+		at32_spi_setup_slaves(0, b, n, spi0_pins);
-+		break;
++	insnslot_2arg_rflags(rnv, rdv, regs->ARM_cpsr, i_fn);
++}
 +
-+	case 1:
-+		pdev = &atmel_spi1_device;
-+		select_peripheral(PB(0),  PERIPH_B, 0);	/* MISO  */
-+		select_peripheral(PB(1),  PERIPH_B, 0);	/* MOSI  */
-+		select_peripheral(PB(5),  PERIPH_B, 0);	/* SCK   */
-+		at32_spi_setup_slaves(1, b, n, spi1_pins);
-+		break;
++static void __kprobes emulate_sat(struct kprobe *p, struct pt_regs *regs)
++{
++	insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0];
++	kprobe_opcode_t insn = p->opcode;
++	int rd = (insn >> 12) & 0xf;
++	int rm = insn & 0xf;
++	long rmv = regs->uregs[rm];
 +
-+	default:
-+		return NULL;
-+	}
++	/* Writes Q flag */
++	regs->uregs[rd] = insnslot_1arg_rwflags(rmv, &regs->ARM_cpsr, i_fn);
++}
 +
-+	spi_register_board_info(b, n);
-+	platform_device_register(pdev);
-+	return pdev;
++static void __kprobes emulate_sel(struct kprobe *p, struct pt_regs *regs)
++{
++	insn_2arg_fn_t *i_fn = (insn_2arg_fn_t *)&p->ainsn.insn[0];
++	kprobe_opcode_t insn = p->opcode;
++	int rd = (insn >> 12) & 0xf;
++	int rn = (insn >> 16) & 0xf;
++	int rm = insn & 0xf;
++	long rnv = regs->uregs[rn];
++	long rmv = regs->uregs[rm];
++
++	/* Reads GE bits */
++	regs->uregs[rd] = insnslot_2arg_rflags(rnv, rmv, regs->ARM_cpsr, i_fn);
 +}
 +
-+/* --------------------------------------------------------------------
-+ *  TWI
-+ * -------------------------------------------------------------------- */
-+static struct resource atmel_twi0_resource[] __initdata = {
-+	PBMEM(0xffe00800),
-+	IRQ(5),
-+};
-+static struct clk atmel_twi0_pclk = {
-+	.name		= "twi_pclk",
-+	.parent		= &pba_clk,
-+	.mode		= pba_clk_mode,
-+	.get_rate	= pba_clk_get_rate,
-+	.index		= 2,
-+};
++static void __kprobes emulate_none(struct kprobe *p, struct pt_regs *regs)
++{
++	insn_0arg_fn_t *i_fn = (insn_0arg_fn_t *)&p->ainsn.insn[0];
 +
-+struct platform_device *__init at32_add_device_twi(unsigned int id)
++	insnslot_0arg_rflags(regs->ARM_cpsr, i_fn);
++}
++
++static void __kprobes emulate_rd12(struct kprobe *p, struct pt_regs *regs)
 +{
-+	struct platform_device *pdev;
++	insn_0arg_fn_t *i_fn = (insn_0arg_fn_t *)&p->ainsn.insn[0];
++	kprobe_opcode_t insn = p->opcode;
++	int rd = (insn >> 12) & 0xf;
 +
-+	if (id != 0)
-+		return NULL;
++	regs->uregs[rd] = insnslot_0arg_rflags(regs->ARM_cpsr, i_fn);
++}
 +
-+	pdev = platform_device_alloc("atmel_twi", id);
-+	if (!pdev)
-+		return NULL;
++static void __kprobes emulate_ird12(struct kprobe *p, struct pt_regs *regs)
++{
++	insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0];
++	kprobe_opcode_t insn = p->opcode;
++	int ird = (insn >> 12) & 0xf;
 +
-+	if (platform_device_add_resources(pdev, atmel_twi0_resource,
-+				ARRAY_SIZE(atmel_twi0_resource)))
-+		goto err_add_resources;
++	insnslot_1arg_rflags(regs->uregs[ird], regs->ARM_cpsr, i_fn);
++}
 +
-+	select_peripheral(PA(6),  PERIPH_A, 0);	/* SDA	*/
-+	select_peripheral(PA(7),  PERIPH_A, 0);	/* SDL	*/
++static void __kprobes emulate_rn16(struct kprobe *p, struct pt_regs *regs)
++{
++	insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0];
++	kprobe_opcode_t insn = p->opcode;
++	int rn = (insn >> 16) & 0xf;
++	long rnv = regs->uregs[rn];
 +
-+	atmel_twi0_pclk.dev = &pdev->dev;
++	insnslot_1arg_rflags(rnv, regs->ARM_cpsr, i_fn);
++}
 +
-+	platform_device_add(pdev);
-+	return pdev;
++static void __kprobes emulate_rd12rm0(struct kprobe *p, struct pt_regs *regs)
++{
++	insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0];
++	kprobe_opcode_t insn = p->opcode;
++	int rd = (insn >> 12) & 0xf;
++	int rm = insn & 0xf;
++	long rmv = regs->uregs[rm];
 +
-+err_add_resources:
-+	platform_device_put(pdev);
-+	return NULL;
++	regs->uregs[rd] = insnslot_1arg_rflags(rmv, regs->ARM_cpsr, i_fn);
 +}
 +
-+/* --------------------------------------------------------------------
-+ * MMC
-+ * -------------------------------------------------------------------- */
-+static struct resource atmel_mci0_resource[] __initdata = {
-+	PBMEM(0xfff02400),
-+	IRQ(28),
-+};
-+static struct clk atmel_mci0_pclk = {
-+	.name		= "mci_clk",
-+	.parent		= &pbb_clk,
-+	.mode		= pbb_clk_mode,
-+	.get_rate	= pbb_clk_get_rate,
-+	.index		= 9,
-+};
++static void __kprobes
++emulate_rd12rn16rm0_rwflags(struct kprobe *p, struct pt_regs *regs)
++{
++	insn_2arg_fn_t *i_fn = (insn_2arg_fn_t *)&p->ainsn.insn[0];
++	kprobe_opcode_t insn = p->opcode;
++	int rd = (insn >> 12) & 0xf;
++	int rn = (insn >> 16) & 0xf;
++	int rm = insn & 0xf;
++	long rnv = regs->uregs[rn];
++	long rmv = regs->uregs[rm];
 +
-+struct platform_device *__init at32_add_device_mci(unsigned int id)
++	regs->uregs[rd] =
++		insnslot_2arg_rwflags(rnv, rmv, &regs->ARM_cpsr, i_fn);
++}
++
++static void __kprobes
++emulate_rd16rn12rs8rm0_rwflags(struct kprobe *p, struct pt_regs *regs)
 +{
-+	struct platform_device *pdev;
++	insn_3arg_fn_t *i_fn = (insn_3arg_fn_t *)&p->ainsn.insn[0];
++	kprobe_opcode_t insn = p->opcode;
++	int rd = (insn >> 16) & 0xf;
++	int rn = (insn >> 12) & 0xf;
++	int rs = (insn >> 8) & 0xf;
++	int rm = insn & 0xf;
++	long rnv = regs->uregs[rn];
++	long rsv = regs->uregs[rs];
++	long rmv = regs->uregs[rm];
 +
-+	if (id != 0)
-+		return NULL;
++	regs->uregs[rd] =
++		insnslot_3arg_rwflags(rnv, rsv, rmv, &regs->ARM_cpsr, i_fn);
++}
 +
-+	pdev = platform_device_alloc("atmel_mci", id);
-+	if (!pdev)
-+		return NULL;
++static void __kprobes
++emulate_rd16rs8rm0_rwflags(struct kprobe *p, struct pt_regs *regs)
++{
++	insn_2arg_fn_t *i_fn = (insn_2arg_fn_t *)&p->ainsn.insn[0];
++	kprobe_opcode_t insn = p->opcode;
++	int rd = (insn >> 16) & 0xf;
++	int rs = (insn >> 8) & 0xf;
++	int rm = insn & 0xf;
++	long rsv = regs->uregs[rs];
++	long rmv = regs->uregs[rm];
 +
-+	if (platform_device_add_resources(pdev, atmel_mci0_resource,
-+				ARRAY_SIZE(atmel_mci0_resource)))
-+		goto err_add_resources;
++	regs->uregs[rd] =
++		insnslot_2arg_rwflags(rsv, rmv, &regs->ARM_cpsr, i_fn);
++}
 +
-+	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 */
++static void __kprobes
++emulate_rdhi16rdlo12rs8rm0_rwflags(struct kprobe *p, struct pt_regs *regs)
++{
++	insn_llret_4arg_fn_t *i_fn = (insn_llret_4arg_fn_t *)&p->ainsn.insn[0];
++	kprobe_opcode_t insn = p->opcode;
++	union reg_pair fnr;
++	int rdhi = (insn >> 16) & 0xf;
++	int rdlo = (insn >> 12) & 0xf;
++	int rs   = (insn >> 8) & 0xf;
++	int rm   = insn & 0xf;
++	long rsv = regs->uregs[rs];
++	long rmv = regs->uregs[rm];
 +
-+	atmel_mci0_pclk.dev = &pdev->dev;
++	fnr.dr = insnslot_llret_4arg_rwflags(regs->uregs[rdhi],
++					     regs->uregs[rdlo], rsv, rmv,
++					     &regs->ARM_cpsr, i_fn);
++	regs->uregs[rdhi] = fnr.r0;
++	regs->uregs[rdlo] = fnr.r1;
++}
 +
-+	platform_device_add(pdev);
-+	return pdev;
++static void __kprobes
++emulate_alu_imm_rflags(struct kprobe *p, struct pt_regs *regs)
++{
++	insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0];
++	kprobe_opcode_t insn = p->opcode;
++	int rd = (insn >> 12) & 0xf;
++	int rn = (insn >> 16) & 0xf;
++	long rnv = (rn == 15) ? (long)p->addr + 8 : regs->uregs[rn];
 +
-+err_add_resources:
-+	platform_device_put(pdev);
-+	return NULL;
++	regs->uregs[rd] = insnslot_1arg_rflags(rnv, regs->ARM_cpsr, i_fn);
 +}
 +
-+/* --------------------------------------------------------------------
-+ *  LCDC
-+ * -------------------------------------------------------------------- */
-+#if defined(CONFIG_CPU_AT32AP7000) || defined(CONFIG_CPU_AT32AP7002)
-+static struct atmel_lcdfb_info atmel_lcdfb0_data;
-+static struct resource atmel_lcdfb0_resource[] = {
-+	{
-+		.start		= 0xff000000,
-+		.end		= 0xff000fff,
-+		.flags		= IORESOURCE_MEM,
-+	},
-+	IRQ(1),
-+	{
-+		/* Placeholder for pre-allocated fb memory */
-+		.start		= 0x00000000,
-+		.end		= 0x00000000,
-+		.flags		= 0,
-+	},
-+};
-+DEFINE_DEV_DATA(atmel_lcdfb, 0);
-+DEV_CLK(hck1, atmel_lcdfb0, hsb, 7);
-+static struct clk atmel_lcdfb0_pixclk = {
-+	.name		= "lcdc_clk",
-+	.dev		= &atmel_lcdfb0_device.dev,
-+	.mode		= genclk_mode,
-+	.get_rate	= genclk_get_rate,
-+	.set_rate	= genclk_set_rate,
-+	.set_parent	= genclk_set_parent,
-+	.index		= 7,
-+};
++static void __kprobes
++emulate_alu_imm_rwflags(struct kprobe *p, struct pt_regs *regs)
++{
++	insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0];
++	kprobe_opcode_t insn = p->opcode;
++	int rd = (insn >> 12) & 0xf;
++	int rn = (insn >> 16) & 0xf;
++	long rnv = (rn == 15) ? (long)p->addr + 8 : regs->uregs[rn];
 +
-+struct platform_device *__init
-+at32_add_device_lcdc(unsigned int id, struct atmel_lcdfb_info *data,
-+		     unsigned long fbmem_start, unsigned long fbmem_len)
++	regs->uregs[rd] = insnslot_1arg_rwflags(rnv, &regs->ARM_cpsr, i_fn);
++}
++
++static void __kprobes
++emulate_alu_rflags(struct kprobe *p, struct pt_regs *regs)
 +{
-+	struct platform_device *pdev;
-+	struct atmel_lcdfb_info *info;
-+	struct fb_monspecs *monspecs;
-+	struct fb_videomode *modedb;
-+	unsigned int modedb_size;
++	insn_3arg_fn_t *i_fn = (insn_3arg_fn_t *)&p->ainsn.insn[0];
++	kprobe_opcode_t insn = p->opcode;
++	long ppc = (long)p->addr + 8;
++	int rd = (insn >> 12) & 0xf;
++	int rn = (insn >> 16) & 0xf;	/* rn/rnv/rs/rsv may be */
++	int rs = (insn >> 8) & 0xf;	/* invalid, don't care. */
++	int rm = insn & 0xf;
++	long rnv = (rn == 15) ? ppc : regs->uregs[rn];
++	long rmv = (rm == 15) ? ppc : regs->uregs[rm];
++	long rsv = regs->uregs[rs];
 +
-+	/*
-+	 * Do a deep copy of the fb data, monspecs and modedb. Make
-+	 * sure all allocations are done before setting up the
-+	 * portmux.
-+	 */
-+	monspecs = kmemdup(data->default_monspecs,
-+			   sizeof(struct fb_monspecs), GFP_KERNEL);
-+	if (!monspecs)
-+		return NULL;
++	regs->uregs[rd] =
++		insnslot_3arg_rflags(rnv, rmv, rsv, regs->ARM_cpsr, i_fn);
++}
 +
-+	modedb_size = sizeof(struct fb_videomode) * monspecs->modedb_len;
-+	modedb = kmemdup(monspecs->modedb, modedb_size, GFP_KERNEL);
-+	if (!modedb)
-+		goto err_dup_modedb;
-+	monspecs->modedb = modedb;
++static void __kprobes
++emulate_alu_rwflags(struct kprobe *p, struct pt_regs *regs)
++{
++	insn_3arg_fn_t *i_fn = (insn_3arg_fn_t *)&p->ainsn.insn[0];
++	kprobe_opcode_t insn = p->opcode;
++	long ppc = (long)p->addr + 8;
++	int rd = (insn >> 12) & 0xf;
++	int rn = (insn >> 16) & 0xf;	/* rn/rnv/rs/rsv may be */
++	int rs = (insn >> 8) & 0xf;	/* invalid, don't care. */
++	int rm = insn & 0xf;
++	long rnv = (rn == 15) ? ppc : regs->uregs[rn];
++	long rmv = (rm == 15) ? ppc : regs->uregs[rm];
++	long rsv = regs->uregs[rs];
 +
-+	switch (id) {
-+	case 0:
-+		pdev = &atmel_lcdfb0_device;
-+		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 */
++	regs->uregs[rd] =
++		insnslot_3arg_rwflags(rnv, rmv, rsv, &regs->ARM_cpsr, i_fn);
++}
 +
-+		clk_set_parent(&atmel_lcdfb0_pixclk, &pll0);
-+		clk_set_rate(&atmel_lcdfb0_pixclk, clk_get_rate(&pll0));
-+		break;
++static enum kprobe_insn __kprobes
++prep_emulate_ldr_str(kprobe_opcode_t insn, struct arch_specific_insn *asi)
++{
++	int ibit = (insn & (1 << 26)) ? 25 : 22;
 +
-+	default:
-+		goto err_invalid_id;
++	insn &= 0xfff00fff;
++	insn |= 0x00001000;	/* Rn = r0, Rd = r1 */
++	if (insn & (1 << ibit)) {
++		insn &= ~0xf;
++		insn |= 2;	/* Rm = r2 */
 +	}
++	asi->insn[0] = insn;
++	asi->insn_handler = (insn & (1 << 20)) ? emulate_ldr : emulate_str;
++	return INSN_GOOD;
++}
 +
-+	if (fbmem_len) {
-+		pdev->resource[2].start = fbmem_start;
-+		pdev->resource[2].end = fbmem_start + fbmem_len - 1;
-+		pdev->resource[2].flags = IORESOURCE_MEM;
-+	}
++static enum kprobe_insn __kprobes
++prep_emulate_rd12rm0(kprobe_opcode_t insn, struct arch_specific_insn *asi)
++{
++	insn &= 0xffff0ff0;	/* Rd = r0, Rm = r0 */
++	asi->insn[0] = insn;
++	asi->insn_handler = emulate_rd12rm0;
++	return INSN_GOOD;
++}
 +
-+	info = pdev->dev.platform_data;
-+	memcpy(info, data, sizeof(struct atmel_lcdfb_info));
-+	info->default_monspecs = monspecs;
++static enum kprobe_insn __kprobes
++prep_emulate_rd12(kprobe_opcode_t insn, struct arch_specific_insn *asi)
++{
++	insn &= 0xffff0fff;	/* Rd = r0 */
++	asi->insn[0] = insn;
++	asi->insn_handler = emulate_rd12;
++	return INSN_GOOD;
++}
 +
-+	platform_device_register(pdev);
-+	return pdev;
++static enum kprobe_insn __kprobes
++prep_emulate_rd12rn16rm0_wflags(kprobe_opcode_t insn,
++				struct arch_specific_insn *asi)
++{
++	insn &= 0xfff00ff0;	/* Rd = r0, Rn = r0 */
++	insn |= 0x00000001;	/* Rm = r1 */
++	asi->insn[0] = insn;
++	asi->insn_handler = emulate_rd12rn16rm0_rwflags;
++	return INSN_GOOD;
++}
 +
-+err_invalid_id:
-+	kfree(modedb);
-+err_dup_modedb:
-+	kfree(monspecs);
-+	return NULL;
++static enum kprobe_insn __kprobes
++prep_emulate_rd16rs8rm0_wflags(kprobe_opcode_t insn,
++			       struct arch_specific_insn *asi)
++{
++	insn &= 0xfff0f0f0;	/* Rd = r0, Rs = r0 */
++	insn |= 0x00000001;	/* Rm = r1          */
++	asi->insn[0] = insn;
++	asi->insn_handler = emulate_rd16rs8rm0_rwflags;
++	return INSN_GOOD;
 +}
-+#endif
 +
-+/* --------------------------------------------------------------------
-+ *  SSC
-+ * -------------------------------------------------------------------- */
-+static struct resource ssc0_resource[] = {
-+	PBMEM(0xffe01c00),
-+	IRQ(10),
-+};
-+DEFINE_DEV(ssc, 0);
-+DEV_CLK(pclk, ssc0, pba, 7);
++static enum kprobe_insn __kprobes
++prep_emulate_rd16rn12rs8rm0_wflags(kprobe_opcode_t insn,
++				   struct arch_specific_insn *asi)
++{
++	insn &= 0xfff000f0;	/* Rd = r0, Rn = r0 */
++	insn |= 0x00000102;	/* Rs = r1, Rm = r2 */
++	asi->insn[0] = insn;
++	asi->insn_handler = emulate_rd16rn12rs8rm0_rwflags;
++	return INSN_GOOD;
++}
 +
-+static struct resource ssc1_resource[] = {
-+	PBMEM(0xffe02000),
-+	IRQ(11),
-+};
-+DEFINE_DEV(ssc, 1);
-+DEV_CLK(pclk, ssc1, pba, 8);
++static enum kprobe_insn __kprobes
++prep_emulate_rdhi16rdlo12rs8rm0_wflags(kprobe_opcode_t insn,
++				       struct arch_specific_insn *asi)
++{
++	insn &= 0xfff000f0;	/* RdHi = r0, RdLo = r1 */
++	insn |= 0x00001203;	/* Rs = r2, Rm = r3 */
++	asi->insn[0] = insn;
++	asi->insn_handler = emulate_rdhi16rdlo12rs8rm0_rwflags;
++	return INSN_GOOD;
++}
 +
-+static struct resource ssc2_resource[] = {
-+	PBMEM(0xffe02400),
-+	IRQ(12),
-+};
-+DEFINE_DEV(ssc, 2);
-+DEV_CLK(pclk, ssc2, pba, 9);
++/*
++ * For the instruction masking and comparisons in all the "space_*"
++ * functions below, Do _not_ rearrange the order of tests unless
++ * you're very, very sure of what you are doing.  For the sake of
++ * efficiency, the masks for some tests sometimes assume other test
++ * have been done prior to them so the number of patterns to test
++ * for an instruction set can be as broad as possible to reduce the
++ * number of tests needed.
++ */
 +
-+struct platform_device *__init
-+at32_add_device_ssc(unsigned int id, unsigned int flags)
++static enum kprobe_insn __kprobes
++space_1111(kprobe_opcode_t insn, struct arch_specific_insn *asi)
 +{
-+	struct platform_device *pdev;
++	/* CPS mmod == 1 : 1111 0001 0000 xx10 xxxx xxxx xx0x xxxx */
++	/* RFE           : 1111 100x x0x1 xxxx xxxx 1010 xxxx xxxx */
++	/* SRS           : 1111 100x x1x0 1101 xxxx 0101 xxxx xxxx */
++	if ((insn & 0xfff30020) == 0xf1020000 ||
++	    (insn & 0xfe500f00) == 0xf8100a00 ||
++	    (insn & 0xfe5f0f00) == 0xf84d0500)
++		return INSN_REJECTED;
 +
-+	switch (id) {
-+	case 0:
-+		pdev = &ssc0_device;
-+		if (flags & ATMEL_SSC_RF)
-+			select_peripheral(PA(21), PERIPH_A, 0);	/* RF */
-+		if (flags & ATMEL_SSC_RK)
-+			select_peripheral(PA(22), PERIPH_A, 0);	/* RK */
-+		if (flags & ATMEL_SSC_TK)
-+			select_peripheral(PA(23), PERIPH_A, 0);	/* TK */
-+		if (flags & ATMEL_SSC_TF)
-+			select_peripheral(PA(24), PERIPH_A, 0);	/* TF */
-+		if (flags & ATMEL_SSC_TD)
-+			select_peripheral(PA(25), PERIPH_A, 0);	/* TD */
-+		if (flags & ATMEL_SSC_RD)
-+			select_peripheral(PA(26), PERIPH_A, 0);	/* RD */
-+		break;
-+	case 1:
-+		pdev = &ssc1_device;
-+		if (flags & ATMEL_SSC_RF)
-+			select_peripheral(PA(0), PERIPH_B, 0);	/* RF */
-+		if (flags & ATMEL_SSC_RK)
-+			select_peripheral(PA(1), PERIPH_B, 0);	/* RK */
-+		if (flags & ATMEL_SSC_TK)
-+			select_peripheral(PA(2), PERIPH_B, 0);	/* TK */
-+		if (flags & ATMEL_SSC_TF)
-+			select_peripheral(PA(3), PERIPH_B, 0);	/* TF */
-+		if (flags & ATMEL_SSC_TD)
-+			select_peripheral(PA(4), PERIPH_B, 0);	/* TD */
-+		if (flags & ATMEL_SSC_RD)
-+			select_peripheral(PA(5), PERIPH_B, 0);	/* RD */
-+		break;
-+	case 2:
-+		pdev = &ssc2_device;
-+		if (flags & ATMEL_SSC_TD)
-+			select_peripheral(PB(13), PERIPH_A, 0);	/* TD */
-+		if (flags & ATMEL_SSC_RD)
-+			select_peripheral(PB(14), PERIPH_A, 0);	/* RD */
-+		if (flags & ATMEL_SSC_TK)
-+			select_peripheral(PB(15), PERIPH_A, 0);	/* TK */
-+		if (flags & ATMEL_SSC_TF)
-+			select_peripheral(PB(16), PERIPH_A, 0);	/* TF */
-+		if (flags & ATMEL_SSC_RF)
-+			select_peripheral(PB(17), PERIPH_A, 0);	/* RF */
-+		if (flags & ATMEL_SSC_RK)
-+			select_peripheral(PB(18), PERIPH_A, 0);	/* RK */
-+		break;
-+	default:
-+		return NULL;
++	/* PLD : 1111 01x1 x101 xxxx xxxx xxxx xxxx xxxx : */
++	if ((insn & 0xfd700000) == 0xf4500000) {
++		insn &= 0xfff0ffff;	/* Rn = r0 */
++		asi->insn[0] = insn;
++		asi->insn_handler = emulate_rn16;
++		return INSN_GOOD;
 +	}
 +
-+	platform_device_register(pdev);
-+	return pdev;
-+}
++	/* BLX(1) : 1111 101x xxxx xxxx xxxx xxxx xxxx xxxx : */
++	if ((insn & 0xfe000000) == 0xfa000000) {
++		asi->insn_handler = simulate_blx1;
++		return INSN_GOOD_NO_SLOT;
++	}
 +
-+/* --------------------------------------------------------------------
-+ *  USB Device Controller
-+ * -------------------------------------------------------------------- */
-+static struct resource usba0_resource[] __initdata = {
-+	{
-+		.start		= 0xff300000,
-+		.end		= 0xff3fffff,
-+		.flags		= IORESOURCE_MEM,
-+	}, {
-+		.start		= 0xfff03000,
-+		.end		= 0xfff033ff,
-+		.flags		= IORESOURCE_MEM,
-+	},
-+	IRQ(31),
-+};
-+static struct clk usba0_pclk = {
-+	.name		= "pclk",
-+	.parent		= &pbb_clk,
-+	.mode		= pbb_clk_mode,
-+	.get_rate	= pbb_clk_get_rate,
-+	.index		= 12,
-+};
-+static struct clk usba0_hclk = {
-+	.name		= "hclk",
-+	.parent		= &hsb_clk,
-+	.mode		= hsb_clk_mode,
-+	.get_rate	= hsb_clk_get_rate,
-+	.index		= 6,
-+};
++	/* SETEND : 1111 0001 0000 0001 xxxx xxxx 0000 xxxx */
++	/* CDP2   : 1111 1110 xxxx xxxx xxxx xxxx xxx0 xxxx */
++	if ((insn & 0xffff00f0) == 0xf1010000 ||
++	    (insn & 0xff000010) == 0xfe000000) {
++		asi->insn[0] = insn;
++		asi->insn_handler = emulate_none;
++		return INSN_GOOD;
++	}
 +
-+struct platform_device *__init
-+at32_add_device_usba(unsigned int id, struct usba_platform_data *data)
++	/* MCRR2 : 1111 1100 0100 xxxx xxxx xxxx xxxx xxxx : (Rd != Rn) */
++	/* MRRC2 : 1111 1100 0101 xxxx xxxx xxxx xxxx xxxx : (Rd != Rn) */
++	if ((insn & 0xffe00000) == 0xfc400000) {
++		insn &= 0xfff00fff;	/* Rn = r0 */
++		insn |= 0x00001000;	/* Rd = r1 */
++		asi->insn[0] = insn;
++		asi->insn_handler =
++			(insn & (1 << 20)) ? emulate_mrrc : emulate_mcrr;
++		return INSN_GOOD;
++	}
++
++	/* LDC2 : 1111 110x xxx1 xxxx xxxx xxxx xxxx xxxx */
++	/* STC2 : 1111 110x xxx0 xxxx xxxx xxxx xxxx xxxx */
++	if ((insn & 0xfe000000) == 0xfc000000) {
++		insn &= 0xfff0ffff;      /* Rn = r0 */
++		asi->insn[0] = insn;
++		asi->insn_handler = emulate_ldcstc;
++		return INSN_GOOD;
++	}
++
++	/* MCR2 : 1111 1110 xxx0 xxxx xxxx xxxx xxx1 xxxx */
++	/* MRC2 : 1111 1110 xxx1 xxxx xxxx xxxx xxx1 xxxx */
++	insn &= 0xffff0fff;	/* Rd = r0 */
++	asi->insn[0]      = insn;
++	asi->insn_handler = (insn & (1 << 20)) ? emulate_rd12 : emulate_ird12;
++	return INSN_GOOD;
++}
++
++static enum kprobe_insn __kprobes
++space_cccc_000x(kprobe_opcode_t insn, struct arch_specific_insn *asi)
 +{
-+	struct platform_device *pdev;
++	/* cccc 0001 0xx0 xxxx xxxx xxxx xxxx xxx0 xxxx */
++	if ((insn & 0x0f900010) == 0x01000000) {
 +
-+	if (id != 0)
-+		return NULL;
++		/* BXJ  : cccc 0001 0010 xxxx xxxx xxxx 0010 xxxx */
++		/* MSR  : cccc 0001 0x10 xxxx xxxx xxxx 0000 xxxx */
++		if ((insn & 0x0ff000f0) == 0x01200020 ||
++		    (insn & 0x0fb000f0) == 0x01200000)
++			return INSN_REJECTED;
 +
-+	pdev = platform_device_alloc("atmel_usba_udc", 0);
-+	if (!pdev)
-+		return NULL;
++		/* MRS : cccc 0001 0x00 xxxx xxxx xxxx 0000 xxxx */
++		if ((insn & 0x0fb00010) == 0x01000000)
++			return prep_emulate_rd12(insn, asi);
 +
-+	if (platform_device_add_resources(pdev, usba0_resource,
-+					  ARRAY_SIZE(usba0_resource)))
-+		goto out_free_pdev;
++		/* SMLALxy : cccc 0001 0100 xxxx xxxx xxxx 1xx0 xxxx */
++		if ((insn & 0x0ff00090) == 0x01400080)
++			return prep_emulate_rdhi16rdlo12rs8rm0_wflags(insn, asi);
 +
-+	if (data) {
-+		if (platform_device_add_data(pdev, data, sizeof(*data)))
-+			goto out_free_pdev;
++		/* SMULWy : cccc 0001 0010 xxxx xxxx xxxx 1x10 xxxx */
++		/* SMULxy : cccc 0001 0110 xxxx xxxx xxxx 1xx0 xxxx */
++		if ((insn & 0x0ff000b0) == 0x012000a0 ||
++		    (insn & 0x0ff00090) == 0x01600080)
++			return prep_emulate_rd16rs8rm0_wflags(insn, asi);
++
++		/* SMLAxy : cccc 0001 0000 xxxx xxxx xxxx 1xx0 xxxx : Q */
++		/* SMLAWy : cccc 0001 0010 xxxx xxxx xxxx 0x00 xxxx : Q */
++		return prep_emulate_rd16rn12rs8rm0_wflags(insn, asi);
 +
-+		if (data->vbus_pin != GPIO_PIN_NONE)
-+			at32_select_gpio(data->vbus_pin, 0);
 +	}
 +
-+	usba0_pclk.dev = &pdev->dev;
-+	usba0_hclk.dev = &pdev->dev;
++	/* cccc 0001 0xx0 xxxx xxxx xxxx xxxx 0xx1 xxxx */
++	else if ((insn & 0x0f900090) == 0x01000010) {
 +
-+	platform_device_add(pdev);
++		/* BKPT : 1110 0001 0010 xxxx xxxx xxxx 0111 xxxx */
++		if ((insn & 0xfff000f0) == 0xe1200070)
++			return INSN_REJECTED;
 +
-+	return pdev;
++		/* BLX(2) : cccc 0001 0010 xxxx xxxx xxxx 0011 xxxx */
++		/* BX     : cccc 0001 0010 xxxx xxxx xxxx 0001 xxxx */
++		if ((insn & 0x0ff000d0) == 0x01200010) {
++			asi->insn[0] = truecc_insn(insn);
++			asi->insn_handler = simulate_blx2bx;
++			return INSN_GOOD;
++		}
 +
-+out_free_pdev:
-+	platform_device_put(pdev);
-+	return NULL;
-+}
++		/* CLZ : cccc 0001 0110 xxxx xxxx xxxx 0001 xxxx */
++		if ((insn & 0x0ff000f0) == 0x01600010)
++			return prep_emulate_rd12rm0(insn, asi);
 +
-+/* --------------------------------------------------------------------
-+ * IDE / CompactFlash
-+ * -------------------------------------------------------------------- */
-+#if defined(CONFIG_CPU_AT32AP7000) || defined(CONFIG_CPU_AT32AP7001)
-+static struct resource at32_smc_cs4_resource[] __initdata = {
-+	{
-+		.start	= 0x04000000,
-+		.end	= 0x07ffffff,
-+		.flags	= IORESOURCE_MEM,
-+	},
-+	IRQ(~0UL), /* Magic IRQ will be overridden */
-+};
-+static struct resource at32_smc_cs5_resource[] __initdata = {
-+	{
-+		.start	= 0x20000000,
-+		.end	= 0x23ffffff,
-+		.flags	= IORESOURCE_MEM,
-+	},
-+	IRQ(~0UL), /* Magic IRQ will be overridden */
-+};
++		/* QADD    : cccc 0001 0000 xxxx xxxx xxxx 0101 xxxx :Q */
++		/* QSUB    : cccc 0001 0010 xxxx xxxx xxxx 0101 xxxx :Q */
++		/* QDADD   : cccc 0001 0100 xxxx xxxx xxxx 0101 xxxx :Q */
++		/* QDSUB   : cccc 0001 0110 xxxx xxxx xxxx 0101 xxxx :Q */
++		return prep_emulate_rd12rn16rm0_wflags(insn, asi);
++	}
 +
-+static int __init at32_init_ide_or_cf(struct platform_device *pdev,
-+		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),
-+	};
-+	static bool common_pins_initialized __initdata = false;
-+	unsigned int extint_pin;
-+	int ret;
++	/* cccc 0000 xxxx xxxx xxxx xxxx xxxx 1001 xxxx */
++	else if ((insn & 0x0f000090) == 0x00000090) {
 +
-+	if (extint >= ARRAY_SIZE(extint_pin_map))
-+		return -EINVAL;
-+	extint_pin = extint_pin_map[extint];
++		/* MUL    : cccc 0000 0000 xxxx xxxx xxxx 1001 xxxx :   */
++		/* MULS   : cccc 0000 0001 xxxx xxxx xxxx 1001 xxxx :cc */
++		/* MLA    : cccc 0000 0010 xxxx xxxx xxxx 1001 xxxx :   */
++		/* MLAS   : cccc 0000 0011 xxxx xxxx xxxx 1001 xxxx :cc */
++		/* UMAAL  : cccc 0000 0100 xxxx xxxx xxxx 1001 xxxx :   */
++		/* UMULL  : cccc 0000 1000 xxxx xxxx xxxx 1001 xxxx :   */
++		/* UMULLS : cccc 0000 1001 xxxx xxxx xxxx 1001 xxxx :cc */
++		/* UMLAL  : cccc 0000 1010 xxxx xxxx xxxx 1001 xxxx :   */
++		/* UMLALS : cccc 0000 1011 xxxx xxxx xxxx 1001 xxxx :cc */
++		/* SMULL  : cccc 0000 1100 xxxx xxxx xxxx 1001 xxxx :   */
++		/* SMULLS : cccc 0000 1101 xxxx xxxx xxxx 1001 xxxx :cc */
++		/* SMLAL  : cccc 0000 1110 xxxx xxxx xxxx 1001 xxxx :   */
++		/* SMLALS : cccc 0000 1111 xxxx xxxx xxxx 1001 xxxx :cc */
++		if ((insn & 0x0fe000f0) == 0x00000090) {
++		       return prep_emulate_rd16rs8rm0_wflags(insn, asi);
++		} else if  ((insn & 0x0fe000f0) == 0x00200090) {
++		       return prep_emulate_rd16rn12rs8rm0_wflags(insn, asi);
++		} else {
++		       return prep_emulate_rdhi16rdlo12rs8rm0_wflags(insn, asi);
++		}
++	}
 +
-+	switch (cs) {
-+	case 4:
-+		ret = platform_device_add_resources(pdev,
-+				at32_smc_cs4_resource,
-+				ARRAY_SIZE(at32_smc_cs4_resource));
-+		if (ret)
-+			return ret;
++	/* cccc 000x xxxx xxxx xxxx xxxx xxxx 1xx1 xxxx */
++	else if ((insn & 0x0e000090) == 0x00000090) {
 +
-+		select_peripheral(PE(21), PERIPH_A, 0); /* NCS4   -> OE_N  */
-+		set_ebi_sfr_bits(HMATRIX_BIT(CS4A));
-+		break;
-+	case 5:
-+		ret = platform_device_add_resources(pdev,
-+				at32_smc_cs5_resource,
-+				ARRAY_SIZE(at32_smc_cs5_resource));
-+		if (ret)
-+			return ret;
++		/* SWP   : cccc 0001 0000 xxxx xxxx xxxx 1001 xxxx */
++		/* SWPB  : cccc 0001 0100 xxxx xxxx xxxx 1001 xxxx */
++		/* LDRD  : cccc 000x xxx0 xxxx xxxx xxxx 1101 xxxx */
++		/* STRD  : cccc 000x xxx0 xxxx xxxx xxxx 1111 xxxx */
++		/* STREX : cccc 0001 1000 xxxx xxxx xxxx 1001 xxxx */
++		/* LDREX : cccc 0001 1001 xxxx xxxx xxxx 1001 xxxx */
++		/* LDRH  : cccc 000x xxx1 xxxx xxxx xxxx 1011 xxxx */
++		/* STRH  : cccc 000x xxx0 xxxx xxxx xxxx 1011 xxxx */
++		/* LDRSB : cccc 000x xxx1 xxxx xxxx xxxx 1101 xxxx */
++		/* LDRSH : cccc 000x xxx1 xxxx xxxx xxxx 1111 xxxx */
++		if ((insn & 0x0fb000f0) == 0x01000090) {
++			/* SWP/SWPB */
++			return prep_emulate_rd12rn16rm0_wflags(insn, asi);
++		} else if ((insn & 0x0e1000d0) == 0x00000d0) {
++			/* STRD/LDRD */
++			insn &= 0xfff00fff;
++			insn |= 0x00002000;	/* Rn = r0, Rd = r2 */
++			if (insn & (1 << 22)) {
++				/* I bit */
++				insn &= ~0xf;
++				insn |= 1;	/* Rm = r1 */
++			}
++			asi->insn[0] = insn;
++			asi->insn_handler =
++				(insn & (1 << 5)) ? emulate_strd : emulate_ldrd;
++			return INSN_GOOD;
++		}
 +
-+		select_peripheral(PE(22), PERIPH_A, 0); /* NCS5   -> OE_N  */
-+		set_ebi_sfr_bits(HMATRIX_BIT(CS5A));
-+		break;
-+	default:
-+		return -EINVAL;
++		return prep_emulate_ldr_str(insn, asi);
 +	}
 +
-+	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 */
-+		common_pins_initialized = true;
-+	}
++	/* cccc 000x xxxx xxxx xxxx xxxx xxxx xxxx xxxx */
 +
-+	at32_select_periph(extint_pin, GPIO_PERIPH_A, AT32_GPIOF_DEGLITCH);
++	/*
++	 * ALU op with S bit and Rd == 15 :
++	 * 	cccc 000x xxx1 xxxx 1111 xxxx xxxx xxxx
++	 */
++	if ((insn & 0x0e10f000) == 0x0010f000)
++		return INSN_REJECTED;
 +
-+	pdev->resource[1].start = EIM_IRQ_BASE + extint;
-+	pdev->resource[1].end = pdev->resource[1].start;
++	/*
++	 * "mov ip, sp" is the most common kprobe'd instruction by far.
++	 * Check and optimize for it explicitly.
++	 */
++	if (insn == 0xe1a0c00d) {
++		asi->insn_handler = simulate_mov_ipsp;
++		return INSN_GOOD_NO_SLOT;
++	}
 +
-+	return 0;
++	/*
++	 * Data processing: Immediate-shift / Register-shift
++	 * ALU op : cccc 000x xxxx xxxx xxxx xxxx xxxx xxxx
++	 * CPY    : cccc 0001 1010 xxxx xxxx 0000 0000 xxxx
++	 * MOV    : cccc 0001 101x xxxx xxxx xxxx xxxx xxxx
++	 * *S (bit 20) updates condition codes
++	 * ADC/SBC/RSC reads the C flag
++	 */
++	insn &= 0xfff00ff0;	/* Rn = r0, Rd = r0 */
++	insn |= 0x00000001;	/* Rm = r1 */
++	if (insn & 0x010) {
++		insn &= 0xfffff0ff;     /* register shift */
++		insn |= 0x00000200;     /* Rs = r2 */
++	}
++	asi->insn[0] = insn;
++	asi->insn_handler = (insn & (1 << 20)) ?  /* S-bit */
++				emulate_alu_rwflags : emulate_alu_rflags;
++	return INSN_GOOD;
 +}
 +
-+struct platform_device *__init
-+at32_add_device_ide(unsigned int id, unsigned int extint,
-+		    struct ide_platform_data *data)
++static enum kprobe_insn __kprobes
++space_cccc_001x(kprobe_opcode_t insn, struct arch_specific_insn *asi)
 +{
-+	struct platform_device *pdev;
++	/*
++	 * MSR   : cccc 0011 0x10 xxxx xxxx xxxx xxxx xxxx
++	 * Undef : cccc 0011 0x00 xxxx xxxx xxxx xxxx xxxx
++	 * ALU op with S bit and Rd == 15 :
++	 *	   cccc 001x xxx1 xxxx 1111 xxxx xxxx xxxx
++	 */
++	if ((insn & 0x0f900000) == 0x03200000 ||	/* MSR & Undef */
++	    (insn & 0x0e10f000) == 0x0210f000)		/* ALU s-bit, R15  */
++		return INSN_REJECTED;
 +
-+	pdev = platform_device_alloc("at32_ide", id);
-+	if (!pdev)
-+		goto fail;
++	/*
++	 * Data processing: 32-bit Immediate
++	 * ALU op : cccc 001x xxxx xxxx xxxx xxxx xxxx xxxx
++	 * MOV    : cccc 0011 101x xxxx xxxx xxxx xxxx xxxx
++	 * *S (bit 20) updates condition codes
++	 * ADC/SBC/RSC reads the C flag
++	 */
++	insn &= 0xfff00ff0;	/* Rn = r0, Rd = r0 */
++	asi->insn[0] = insn;
++	asi->insn_handler = (insn & (1 << 20)) ?  /* S-bit */
++			emulate_alu_imm_rwflags : emulate_alu_imm_rflags;
++	return INSN_GOOD;
++}
++
++static enum kprobe_insn __kprobes
++space_cccc_0110__1(kprobe_opcode_t insn, struct arch_specific_insn *asi)
++{
++	/* SEL : cccc 0110 1000 xxxx xxxx xxxx 1011 xxxx GE: !!! */
++	if ((insn & 0x0ff000f0) == 0x068000b0) {
++		insn &= 0xfff00ff0;	/* Rd = r0, Rn = r0 */
++		insn |= 0x00000001;	/* Rm = r1 */
++		asi->insn[0] = insn;
++		asi->insn_handler = emulate_sel;
++		return INSN_GOOD;
++	}
++
++	/* SSAT   : cccc 0110 101x xxxx xxxx xxxx xx01 xxxx :Q */
++	/* USAT   : cccc 0110 111x xxxx xxxx xxxx xx01 xxxx :Q */
++	/* SSAT16 : cccc 0110 1010 xxxx xxxx xxxx 0011 xxxx :Q */
++	/* USAT16 : cccc 0110 1110 xxxx xxxx xxxx 0011 xxxx :Q */
++	if ((insn & 0x0fa00030) == 0x06a00010 ||
++	    (insn & 0x0fb000f0) == 0x06a00030) {
++		insn &= 0xffff0ff0;	/* Rd = r0, Rm = r0 */
++		asi->insn[0] = insn;
++		asi->insn_handler = emulate_sat;
++		return INSN_GOOD;
++	}
++
++	/* REV    : cccc 0110 1011 xxxx xxxx xxxx 0011 xxxx */
++	/* REV16  : cccc 0110 1011 xxxx xxxx xxxx 1011 xxxx */
++	/* REVSH  : cccc 0110 1111 xxxx xxxx xxxx 1011 xxxx */
++	if ((insn & 0x0ff00070) == 0x06b00030 ||
++	    (insn & 0x0ff000f0) == 0x06f000b0)
++		return prep_emulate_rd12rm0(insn, asi);
++
++	/* SADD16    : cccc 0110 0001 xxxx xxxx xxxx 0001 xxxx :GE */
++	/* SADDSUBX  : cccc 0110 0001 xxxx xxxx xxxx 0011 xxxx :GE */
++	/* SSUBADDX  : cccc 0110 0001 xxxx xxxx xxxx 0101 xxxx :GE */
++	/* SSUB16    : cccc 0110 0001 xxxx xxxx xxxx 0111 xxxx :GE */
++	/* SADD8     : cccc 0110 0001 xxxx xxxx xxxx 1001 xxxx :GE */
++	/* SSUB8     : cccc 0110 0001 xxxx xxxx xxxx 1111 xxxx :GE */
++	/* QADD16    : cccc 0110 0010 xxxx xxxx xxxx 0001 xxxx :   */
++	/* QADDSUBX  : cccc 0110 0010 xxxx xxxx xxxx 0011 xxxx :   */
++	/* QSUBADDX  : cccc 0110 0010 xxxx xxxx xxxx 0101 xxxx :   */
++	/* QSUB16    : cccc 0110 0010 xxxx xxxx xxxx 0111 xxxx :   */
++	/* QADD8     : cccc 0110 0010 xxxx xxxx xxxx 1001 xxxx :   */
++	/* QSUB8     : cccc 0110 0010 xxxx xxxx xxxx 1111 xxxx :   */
++	/* SHADD16   : cccc 0110 0011 xxxx xxxx xxxx 0001 xxxx :   */
++	/* SHADDSUBX : cccc 0110 0011 xxxx xxxx xxxx 0011 xxxx :   */
++	/* SHSUBADDX : cccc 0110 0011 xxxx xxxx xxxx 0101 xxxx :   */
++	/* SHSUB16   : cccc 0110 0011 xxxx xxxx xxxx 0111 xxxx :   */
++	/* SHADD8    : cccc 0110 0011 xxxx xxxx xxxx 1001 xxxx :   */
++	/* SHSUB8    : cccc 0110 0011 xxxx xxxx xxxx 1111 xxxx :   */
++	/* UADD16    : cccc 0110 0101 xxxx xxxx xxxx 0001 xxxx :GE */
++	/* UADDSUBX  : cccc 0110 0101 xxxx xxxx xxxx 0011 xxxx :GE */
++	/* USUBADDX  : cccc 0110 0101 xxxx xxxx xxxx 0101 xxxx :GE */
++	/* USUB16    : cccc 0110 0101 xxxx xxxx xxxx 0111 xxxx :GE */
++	/* UADD8     : cccc 0110 0101 xxxx xxxx xxxx 1001 xxxx :GE */
++	/* USUB8     : cccc 0110 0101 xxxx xxxx xxxx 1111 xxxx :GE */
++	/* UQADD16   : cccc 0110 0110 xxxx xxxx xxxx 0001 xxxx :   */
++	/* UQADDSUBX : cccc 0110 0110 xxxx xxxx xxxx 0011 xxxx :   */
++	/* UQSUBADDX : cccc 0110 0110 xxxx xxxx xxxx 0101 xxxx :   */
++	/* UQSUB16   : cccc 0110 0110 xxxx xxxx xxxx 0111 xxxx :   */
++	/* UQADD8    : cccc 0110 0110 xxxx xxxx xxxx 1001 xxxx :   */
++	/* UQSUB8    : cccc 0110 0110 xxxx xxxx xxxx 1111 xxxx :   */
++	/* UHADD16   : cccc 0110 0111 xxxx xxxx xxxx 0001 xxxx :   */
++	/* UHADDSUBX : cccc 0110 0111 xxxx xxxx xxxx 0011 xxxx :   */
++	/* UHSUBADDX : cccc 0110 0111 xxxx xxxx xxxx 0101 xxxx :   */
++	/* UHSUB16   : cccc 0110 0111 xxxx xxxx xxxx 0111 xxxx :   */
++	/* UHADD8    : cccc 0110 0111 xxxx xxxx xxxx 1001 xxxx :   */
++	/* UHSUB8    : cccc 0110 0111 xxxx xxxx xxxx 1111 xxxx :   */
++	/* PKHBT     : cccc 0110 1000 xxxx xxxx xxxx x001 xxxx :   */
++	/* PKHTB     : cccc 0110 1000 xxxx xxxx xxxx x101 xxxx :   */
++	/* SXTAB16   : cccc 0110 1000 xxxx xxxx xxxx 0111 xxxx :   */
++	/* SXTB      : cccc 0110 1010 xxxx xxxx xxxx 0111 xxxx :   */
++	/* SXTAB     : cccc 0110 1010 xxxx xxxx xxxx 0111 xxxx :   */
++	/* SXTAH     : cccc 0110 1011 xxxx xxxx xxxx 0111 xxxx :   */
++	/* UXTAB16   : cccc 0110 1100 xxxx xxxx xxxx 0111 xxxx :   */
++	/* UXTAB     : cccc 0110 1110 xxxx xxxx xxxx 0111 xxxx :   */
++	/* UXTAH     : cccc 0110 1111 xxxx xxxx xxxx 0111 xxxx :   */
++	return prep_emulate_rd12rn16rm0_wflags(insn, asi);
++}
++
++static enum kprobe_insn __kprobes
++space_cccc_0111__1(kprobe_opcode_t insn, struct arch_specific_insn *asi)
++{
++	/* Undef : cccc 0111 1111 xxxx xxxx xxxx 1111 xxxx */
++	if ((insn & 0x0ff000f0) == 0x03f000f0)
++		return INSN_REJECTED;
++
++	/* USADA8 : cccc 0111 1000 xxxx xxxx xxxx 0001 xxxx */
++	/* USAD8  : cccc 0111 1000 xxxx 1111 xxxx 0001 xxxx */
++	if ((insn & 0x0ff000f0) == 0x07800010)
++		 return prep_emulate_rd16rn12rs8rm0_wflags(insn, asi);
++
++	/* SMLALD : cccc 0111 0100 xxxx xxxx xxxx 00x1 xxxx */
++	/* SMLSLD : cccc 0111 0100 xxxx xxxx xxxx 01x1 xxxx */
++	if ((insn & 0x0ff00090) == 0x07400010)
++		return prep_emulate_rdhi16rdlo12rs8rm0_wflags(insn, asi);
++
++	/* SMLAD  : cccc 0111 0000 xxxx xxxx xxxx 00x1 xxxx :Q */
++	/* SMLSD  : cccc 0111 0000 xxxx xxxx xxxx 01x1 xxxx :Q */
++	/* SMMLA  : cccc 0111 0101 xxxx xxxx xxxx 00x1 xxxx :  */
++	/* SMMLS  : cccc 0111 0101 xxxx xxxx xxxx 11x1 xxxx :  */
++	if ((insn & 0x0ff00090) == 0x07000010 ||
++	    (insn & 0x0ff000d0) == 0x07500010 ||
++	    (insn & 0x0ff000d0) == 0x075000d0)
++		return prep_emulate_rd16rn12rs8rm0_wflags(insn, asi);
++
++	/* SMUSD  : cccc 0111 0000 xxxx xxxx xxxx 01x1 xxxx :  */
++	/* SMUAD  : cccc 0111 0000 xxxx 1111 xxxx 00x1 xxxx :Q */
++	/* SMMUL  : cccc 0111 0101 xxxx 1111 xxxx 00x1 xxxx :  */
++	return prep_emulate_rd16rs8rm0_wflags(insn, asi);
++}
++
++static enum kprobe_insn __kprobes
++space_cccc_01xx(kprobe_opcode_t insn, struct arch_specific_insn *asi)
++{
++	/* LDR   : cccc 01xx x0x1 xxxx xxxx xxxx xxxx xxxx */
++	/* LDRB  : cccc 01xx x1x1 xxxx xxxx xxxx xxxx xxxx */
++	/* LDRBT : cccc 01x0 x111 xxxx xxxx xxxx xxxx xxxx */
++	/* LDRT  : cccc 01x0 x011 xxxx xxxx xxxx xxxx xxxx */
++	/* STR   : cccc 01xx x0x0 xxxx xxxx xxxx xxxx xxxx */
++	/* STRB  : cccc 01xx x1x0 xxxx xxxx xxxx xxxx xxxx */
++	/* STRBT : cccc 01x0 x110 xxxx xxxx xxxx xxxx xxxx */
++	/* STRT  : cccc 01x0 x010 xxxx xxxx xxxx xxxx xxxx */
++	return prep_emulate_ldr_str(insn, asi);
++}
++
++static enum kprobe_insn __kprobes
++space_cccc_100x(kprobe_opcode_t insn, struct arch_specific_insn *asi)
++{
++	/* LDM(2) : cccc 100x x101 xxxx 0xxx xxxx xxxx xxxx */
++	/* LDM(3) : cccc 100x x1x1 xxxx 1xxx xxxx xxxx xxxx */
++	if ((insn & 0x0e708000) == 0x85000000 ||
++	    (insn & 0x0e508000) == 0x85010000)
++		return INSN_REJECTED;
++
++	/* LDM(1) : cccc 100x x0x1 xxxx xxxx xxxx xxxx xxxx */
++	/* STM(1) : cccc 100x x0x0 xxxx xxxx xxxx xxxx xxxx */
++	asi->insn[0] = truecc_insn(insn);
++	asi->insn_handler = ((insn & 0x108000) == 0x008000) ? /* STM & R15 */
++				simulate_stm1_pc : simulate_ldm1stm1;
++	return INSN_GOOD;
++}
++
++static enum kprobe_insn __kprobes
++space_cccc_101x(kprobe_opcode_t insn, struct arch_specific_insn *asi)
++{
++	/* B  : cccc 1010 xxxx xxxx xxxx xxxx xxxx xxxx */
++	/* BL : cccc 1011 xxxx xxxx xxxx xxxx xxxx xxxx */
++	asi->insn[0] = truecc_insn(insn);
++	asi->insn_handler = simulate_bbl;
++	return INSN_GOOD;
++}
++
++static enum kprobe_insn __kprobes
++space_cccc_1100_010x(kprobe_opcode_t insn, struct arch_specific_insn *asi)
++{
++	/* MCRR : cccc 1100 0100 xxxx xxxx xxxx xxxx xxxx : (Rd!=Rn) */
++	/* MRRC : cccc 1100 0101 xxxx xxxx xxxx xxxx xxxx : (Rd!=Rn) */
++	insn &= 0xfff00fff;
++	insn |= 0x00001000;	/* Rn = r0, Rd = r1 */
++	asi->insn[0] = insn;
++	asi->insn_handler = (insn & (1 << 20)) ? emulate_mrrc : emulate_mcrr;
++	return INSN_GOOD;
++}
++
++static enum kprobe_insn __kprobes
++space_cccc_110x(kprobe_opcode_t insn, struct arch_specific_insn *asi)
++{
++	/* LDC : cccc 110x xxx1 xxxx xxxx xxxx xxxx xxxx */
++	/* STC : cccc 110x xxx0 xxxx xxxx xxxx xxxx xxxx */
++	insn &= 0xfff0ffff;	/* Rn = r0 */
++	asi->insn[0] = insn;
++	asi->insn_handler = emulate_ldcstc;
++	return INSN_GOOD;
++}
++
++static enum kprobe_insn __kprobes
++space_cccc_111x(kprobe_opcode_t insn, struct arch_specific_insn *asi)
++{
++	/* BKPT : 1110 0001 0010 xxxx xxxx xxxx 0111 xxxx */
++	/* SWI  : cccc 1111 xxxx xxxx xxxx xxxx xxxx xxxx */
++	if ((insn & 0xfff000f0) == 0xe1200070 ||
++	    (insn & 0x0f000000) == 0x0f000000)
++		return INSN_REJECTED;
++
++	/* CDP : cccc 1110 xxxx xxxx xxxx xxxx xxx0 xxxx */
++	if ((insn & 0x0f000010) == 0x0e000000) {
++		asi->insn[0] = insn;
++		asi->insn_handler = emulate_none;
++		return INSN_GOOD;
++	}
++
++	/* MCR : cccc 1110 xxx0 xxxx xxxx xxxx xxx1 xxxx */
++	/* MRC : cccc 1110 xxx1 xxxx xxxx xxxx xxx1 xxxx */
++	insn &= 0xffff0fff;	/* Rd = r0 */
++	asi->insn[0] = insn;
++	asi->insn_handler = (insn & (1 << 20)) ? emulate_rd12 : emulate_ird12;
++	return INSN_GOOD;
++}
++
++/* Return:
++ *   INSN_REJECTED     If instruction is one not allowed to kprobe,
++ *   INSN_GOOD         If instruction is supported and uses instruction slot,
++ *   INSN_GOOD_NO_SLOT If instruction is supported but doesn't use its slot.
++ *
++ * For instructions we don't want to kprobe (INSN_REJECTED return result):
++ *   These are generally ones that modify the processor state making
++ *   them "hard" to simulate such as switches processor modes or
++ *   make accesses in alternate modes.  Any of these could be simulated
++ *   if the work was put into it, but low return considering they
++ *   should also be very rare.
++ */
++enum kprobe_insn __kprobes
++arm_kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi)
++{
++	asi->insn[1] = KPROBE_RETURN_INSTRUCTION;
++
++	if ((insn & 0xf0000000) == 0xf0000000) {
++
++		return space_1111(insn, asi);
++
++	} else if ((insn & 0x0e000000) == 0x00000000) {
++
++		return space_cccc_000x(insn, asi);
++
++	} else if ((insn & 0x0e000000) == 0x02000000) {
++
++		return space_cccc_001x(insn, asi);
++
++	} else if ((insn & 0x0f000010) == 0x06000010) {
++
++		return space_cccc_0110__1(insn, asi);
++
++	} else if ((insn & 0x0f000010) == 0x07000010) {
++
++		return space_cccc_0111__1(insn, asi);
++
++	} else if ((insn & 0x0c000000) == 0x04000000) {
++
++		return space_cccc_01xx(insn, asi);
++
++	} else if ((insn & 0x0e000000) == 0x08000000) {
++
++		return space_cccc_100x(insn, asi);
++
++	} else if ((insn & 0x0e000000) == 0x0a000000) {
++
++		return space_cccc_101x(insn, asi);
++
++	} else if ((insn & 0x0fe00000) == 0x0c400000) {
++
++		return space_cccc_1100_010x(insn, asi);
++
++	} else if ((insn & 0x0e000000) == 0x0c400000) {
++
++		return space_cccc_110x(insn, asi);
++
++	}
++
++	return space_cccc_111x(insn, asi);
++}
++
++void __init arm_kprobe_decode_init(void)
++{
++	find_str_pc_offset();
++}
++
++
++/*
++ * All ARM instructions listed below.
++ *
++ * Instructions and their general purpose registers are given.
++ * If a particular register may not use R15, it is prefixed with a "!".
++ * If marked with a "*" means the value returned by reading R15
++ * is implementation defined.
++ *
++ * ADC/ADD/AND/BIC/CMN/CMP/EOR/MOV/MVN/ORR/RSB/RSC/SBC/SUB/TEQ
++ *     TST: Rd, Rn, Rm, !Rs
++ * BX: Rm
++ * BLX(2): !Rm
++ * BX: Rm (R15 legal, but discouraged)
++ * BXJ: !Rm,
++ * CLZ: !Rd, !Rm
++ * CPY: Rd, Rm
++ * LDC/2,STC/2 immediate offset & unindex: Rn
++ * LDC/2,STC/2 immediate pre/post-indexed: !Rn
++ * LDM(1/3): !Rn, register_list
++ * LDM(2): !Rn, !register_list
++ * LDR,STR,PLD immediate offset: Rd, Rn
++ * LDR,STR,PLD register offset: Rd, Rn, !Rm
++ * LDR,STR,PLD scaled register offset: Rd, !Rn, !Rm
++ * LDR,STR immediate pre/post-indexed: Rd, !Rn
++ * LDR,STR register pre/post-indexed: Rd, !Rn, !Rm
++ * LDR,STR scaled register pre/post-indexed: Rd, !Rn, !Rm
++ * LDRB,STRB immediate offset: !Rd, Rn
++ * LDRB,STRB register offset: !Rd, Rn, !Rm
++ * LDRB,STRB scaled register offset: !Rd, !Rn, !Rm
++ * LDRB,STRB immediate pre/post-indexed: !Rd, !Rn
++ * LDRB,STRB register pre/post-indexed: !Rd, !Rn, !Rm
++ * LDRB,STRB scaled register pre/post-indexed: !Rd, !Rn, !Rm
++ * LDRT,LDRBT,STRBT immediate pre/post-indexed: !Rd, !Rn
++ * LDRT,LDRBT,STRBT register pre/post-indexed: !Rd, !Rn, !Rm
++ * LDRT,LDRBT,STRBT scaled register pre/post-indexed: !Rd, !Rn, !Rm
++ * LDRH/SH/SB/D,STRH/SH/SB/D immediate offset: !Rd, Rn
++ * LDRH/SH/SB/D,STRH/SH/SB/D register offset: !Rd, Rn, !Rm
++ * LDRH/SH/SB/D,STRH/SH/SB/D immediate pre/post-indexed: !Rd, !Rn
++ * LDRH/SH/SB/D,STRH/SH/SB/D register pre/post-indexed: !Rd, !Rn, !Rm
++ * LDREX: !Rd, !Rn
++ * MCR/2: !Rd
++ * MCRR/2,MRRC/2: !Rd, !Rn
++ * MLA: !Rd, !Rn, !Rm, !Rs
++ * MOV: Rd
++ * MRC/2: !Rd (if Rd==15, only changes cond codes, not the register)
++ * MRS,MSR: !Rd
++ * MUL: !Rd, !Rm, !Rs
++ * PKH{BT,TB}: !Rd, !Rn, !Rm
++ * QDADD,[U]QADD/16/8/SUBX: !Rd, !Rm, !Rn
++ * QDSUB,[U]QSUB/16/8/ADDX: !Rd, !Rm, !Rn
++ * REV/16/SH: !Rd, !Rm
++ * RFE: !Rn
++ * {S,U}[H]ADD{16,8,SUBX},{S,U}[H]SUB{16,8,ADDX}: !Rd, !Rn, !Rm
++ * SEL: !Rd, !Rn, !Rm
++ * SMLA<x><y>,SMLA{D,W<y>},SMLSD,SMML{A,S}: !Rd, !Rn, !Rm, !Rs
++ * SMLAL<x><y>,SMLA{D,LD},SMLSLD,SMMULL,SMULW<y>: !RdHi, !RdLo, !Rm, !Rs
++ * SMMUL,SMUAD,SMUL<x><y>,SMUSD: !Rd, !Rm, !Rs
++ * SSAT/16: !Rd, !Rm
++ * STM(1/2): !Rn, register_list* (R15 in reg list not recommended)
++ * STRT immediate pre/post-indexed: Rd*, !Rn
++ * STRT register pre/post-indexed: Rd*, !Rn, !Rm
++ * STRT scaled register pre/post-indexed: Rd*, !Rn, !Rm
++ * STREX: !Rd, !Rn, !Rm
++ * SWP/B: !Rd, !Rn, !Rm
++ * {S,U}XTA{B,B16,H}: !Rd, !Rn, !Rm
++ * {S,U}XT{B,B16,H}: !Rd, !Rm
++ * UM{AA,LA,UL}L: !RdHi, !RdLo, !Rm, !Rs
++ * USA{D8,A8,T,T16}: !Rd, !Rm, !Rs
++ *
++ * May transfer control by writing R15 (possible mode changes or alternate
++ * mode accesses marked by "*"):
++ * ALU op (* with s-bit), B, BL, BKPT, BLX(1/2), BX, BXJ, CPS*, CPY,
++ * LDM(1), LDM(2/3)*, LDR, MOV, RFE*, SWI*
++ *
++ * Instructions that do not take general registers, nor transfer control:
++ * CDP/2, SETEND, SRS*
++ */
+diff --git a/arch/arm/kernel/kprobes.c b/arch/arm/kernel/kprobes.c
+new file mode 100644
+index 0000000..a22a98c
+--- /dev/null
++++ b/arch/arm/kernel/kprobes.c
+@@ -0,0 +1,447 @@
++/*
++ * arch/arm/kernel/kprobes.c
++ *
++ * Kprobes on ARM
++ *
++ * Abhishek Sagar <sagar.abhishek at gmail.com>
++ * Copyright (C) 2006, 2007 Motorola Inc.
++ *
++ * Nicolas Pitre <nico at marvell.com>
++ * Copyright (C) 2007 Marvell 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.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++ * General Public License for more details.
++ */
 +
-+	if (platform_device_add_data(pdev, data,
-+				sizeof(struct ide_platform_data)))
-+		goto fail;
++#include <linux/kernel.h>
++#include <linux/kprobes.h>
++#include <linux/module.h>
++#include <linux/stringify.h>
++#include <asm/traps.h>
++#include <asm/cacheflush.h>
 +
-+	if (at32_init_ide_or_cf(pdev, data->cs, extint))
-+		goto fail;
++#define MIN_STACK_SIZE(addr) 				\
++	min((unsigned long)MAX_STACK_SIZE,		\
++	    (unsigned long)current_thread_info() + THREAD_START_SP - (addr))
 +
-+	platform_device_add(pdev);
-+	return pdev;
++#define flush_insns(addr, cnt) 				\
++	flush_icache_range((unsigned long)(addr),	\
++			   (unsigned long)(addr) +	\
++			   sizeof(kprobe_opcode_t) * (cnt))
 +
-+fail:
-+	platform_device_put(pdev);
-+	return NULL;
-+}
++/* Used as a marker in ARM_pc to note when we're in a jprobe. */
++#define JPROBE_MAGIC_ADDR		0xffffffff
 +
-+struct platform_device *__init
-+at32_add_device_cf(unsigned int id, unsigned int extint,
-+		    struct cf_platform_data *data)
++DEFINE_PER_CPU(struct kprobe *, current_kprobe) = NULL;
++DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk);
++
++
++int __kprobes arch_prepare_kprobe(struct kprobe *p)
 +{
-+	struct platform_device *pdev;
++	kprobe_opcode_t insn;
++	kprobe_opcode_t tmp_insn[MAX_INSN_SIZE];
++	unsigned long addr = (unsigned long)p->addr;
++	int is;
 +
-+	pdev = platform_device_alloc("at32_cf", id);
-+	if (!pdev)
-+		goto fail;
++	if (addr & 0x3 || in_exception_text(addr))
++		return -EINVAL;
 +
-+	if (platform_device_add_data(pdev, data,
-+				sizeof(struct cf_platform_data)))
-+		goto fail;
++	insn = *p->addr;
++	p->opcode = insn;
++	p->ainsn.insn = tmp_insn;
 +
-+	if (at32_init_ide_or_cf(pdev, data->cs, extint))
-+		goto fail;
++	switch (arm_kprobe_decode_insn(insn, &p->ainsn)) {
++	case INSN_REJECTED:	/* not supported */
++		return -EINVAL;
 +
-+	if (data->detect_pin != GPIO_PIN_NONE)
-+		at32_select_gpio(data->detect_pin, AT32_GPIOF_DEGLITCH);
-+	if (data->reset_pin != GPIO_PIN_NONE)
-+		at32_select_gpio(data->reset_pin, 0);
-+	if (data->vcc_pin != GPIO_PIN_NONE)
-+		at32_select_gpio(data->vcc_pin, 0);
-+	/* READY is used as extint, so we can't select it as gpio */
++	case INSN_GOOD:		/* instruction uses slot */
++		p->ainsn.insn = get_insn_slot();
++		if (!p->ainsn.insn)
++			return -ENOMEM;
++		for (is = 0; is < MAX_INSN_SIZE; ++is)
++			p->ainsn.insn[is] = tmp_insn[is];
++		flush_insns(&p->ainsn.insn, MAX_INSN_SIZE);
++		break;
 +
-+	platform_device_add(pdev);
-+	return pdev;
++	case INSN_GOOD_NO_SLOT:	/* instruction doesn't need insn slot */
++		p->ainsn.insn = NULL;
++		break;
++	}
 +
-+fail:
-+	platform_device_put(pdev);
-+	return NULL;
++	return 0;
 +}
-+#endif
 +
-+/* --------------------------------------------------------------------
-+ * AC97C
-+ * -------------------------------------------------------------------- */
-+static struct resource atmel_ac97c0_resource[] __initdata = {
-+	PBMEM(0xfff02800),
-+	IRQ(29),
-+};
-+static struct clk atmel_ac97c0_pclk = {
-+	.name		= "pclk",
-+	.parent		= &pbb_clk,
-+	.mode		= pbb_clk_mode,
-+	.get_rate	= pbb_clk_get_rate,
-+	.index		= 10,
-+};
++void __kprobes arch_arm_kprobe(struct kprobe *p)
++{
++	*p->addr = KPROBE_BREAKPOINT_INSTRUCTION;
++	flush_insns(p->addr, 1);
++}
 +
-+struct platform_device *__init at32_add_device_ac97c(unsigned int id)
++void __kprobes arch_disarm_kprobe(struct kprobe *p)
 +{
-+	struct platform_device *pdev;
++	*p->addr = p->opcode;
++	flush_insns(p->addr, 1);
++}
 +
-+	if (id != 0)
-+		return NULL;
++void __kprobes arch_remove_kprobe(struct kprobe *p)
++{
++	if (p->ainsn.insn) {
++		mutex_lock(&kprobe_mutex);
++		free_insn_slot(p->ainsn.insn, 0);
++		mutex_unlock(&kprobe_mutex);
++		p->ainsn.insn = NULL;
++	}
++}
 +
-+	pdev = platform_device_alloc("atmel_ac97c", id);
-+	if (!pdev)
-+		return NULL;
++static void __kprobes save_previous_kprobe(struct kprobe_ctlblk *kcb)
++{
++	kcb->prev_kprobe.kp = kprobe_running();
++	kcb->prev_kprobe.status = kcb->kprobe_status;
++}
 +
-+	if (platform_device_add_resources(pdev, atmel_ac97c0_resource,
-+				ARRAY_SIZE(atmel_ac97c0_resource)))
-+		goto err_add_resources;
++static void __kprobes restore_previous_kprobe(struct kprobe_ctlblk *kcb)
++{
++	__get_cpu_var(current_kprobe) = kcb->prev_kprobe.kp;
++	kcb->kprobe_status = kcb->prev_kprobe.status;
++}
 +
-+	select_peripheral(PB(20), PERIPH_B, 0);	/* SYNC	*/
-+	select_peripheral(PB(21), PERIPH_B, 0);	/* SDO	*/
-+	select_peripheral(PB(22), PERIPH_B, 0);	/* SDI	*/
-+	select_peripheral(PB(23), PERIPH_B, 0);	/* SCLK	*/
++static void __kprobes set_current_kprobe(struct kprobe *p)
++{
++	__get_cpu_var(current_kprobe) = p;
++}
 +
-+	atmel_ac97c0_pclk.dev = &pdev->dev;
++static void __kprobes singlestep(struct kprobe *p, struct pt_regs *regs,
++				 struct kprobe_ctlblk *kcb)
++{
++	regs->ARM_pc += 4;
++	p->ainsn.insn_handler(p, regs);
++}
 +
-+	platform_device_add(pdev);
-+	return pdev;
++/*
++ * Called with IRQs disabled. IRQs must remain disabled from that point
++ * all the way until processing this kprobe is complete.  The current
++ * kprobes implementation cannot process more than one nested level of
++ * kprobe, and that level is reserved for user kprobe handlers, so we can't
++ * risk encountering a new kprobe in an interrupt handler.
++ */
++void __kprobes kprobe_handler(struct pt_regs *regs)
++{
++	struct kprobe *p, *cur;
++	struct kprobe_ctlblk *kcb;
++	kprobe_opcode_t	*addr = (kprobe_opcode_t *)regs->ARM_pc;
 +
-+err_add_resources:
-+	platform_device_put(pdev);
-+	return NULL;
++	kcb = get_kprobe_ctlblk();
++	cur = kprobe_running();
++	p = get_kprobe(addr);
++
++	if (p) {
++		if (cur) {
++			/* Kprobe is pending, so we're recursing. */
++			switch (kcb->kprobe_status) {
++			case KPROBE_HIT_ACTIVE:
++			case KPROBE_HIT_SSDONE:
++				/* A pre- or post-handler probe got us here. */
++				kprobes_inc_nmissed_count(p);
++				save_previous_kprobe(kcb);
++				set_current_kprobe(p);
++				kcb->kprobe_status = KPROBE_REENTER;
++				singlestep(p, regs, kcb);
++				restore_previous_kprobe(kcb);
++				break;
++			default:
++				/* impossible cases */
++				BUG();
++			}
++		} else {
++			set_current_kprobe(p);
++			kcb->kprobe_status = KPROBE_HIT_ACTIVE;
++
++			/*
++			 * If we have no pre-handler or it returned 0, we
++			 * continue with normal processing.  If we have a
++			 * pre-handler and it returned non-zero, it prepped
++			 * for calling the break_handler below on re-entry,
++			 * so get out doing nothing more here.
++			 */
++			if (!p->pre_handler || !p->pre_handler(p, regs)) {
++				kcb->kprobe_status = KPROBE_HIT_SS;
++				singlestep(p, regs, kcb);
++				if (p->post_handler) {
++					kcb->kprobe_status = KPROBE_HIT_SSDONE;
++					p->post_handler(p, regs, 0);
++				}
++				reset_current_kprobe();
++			}
++		}
++	} else if (cur) {
++		/* We probably hit a jprobe.  Call its break handler. */
++		if (cur->break_handler && cur->break_handler(cur, regs)) {
++			kcb->kprobe_status = KPROBE_HIT_SS;
++			singlestep(cur, regs, kcb);
++			if (cur->post_handler) {
++				kcb->kprobe_status = KPROBE_HIT_SSDONE;
++				cur->post_handler(cur, regs, 0);
++			}
++		}
++		reset_current_kprobe();
++	} else {
++		/*
++		 * The probe was removed and a race is in progress.
++		 * There is nothing we can do about it.  Let's restart
++		 * the instruction.  By the time we can restart, the
++		 * real instruction will be there.
++		 */
++	}
 +}
 +
-+/* --------------------------------------------------------------------
-+ * ABDAC
-+ * -------------------------------------------------------------------- */
-+static struct resource abdac0_resource[] __initdata = {
-+	PBMEM(0xfff02000),
-+	IRQ(27),
-+};
-+static struct clk abdac0_pclk = {
-+	.name		= "pclk",
-+	.parent		= &pbb_clk,
-+	.mode		= pbb_clk_mode,
-+	.get_rate	= pbb_clk_get_rate,
-+	.index		= 8,
-+};
-+static struct clk abdac0_sample_clk = {
-+	.name		= "sample_clk",
-+	.mode		= genclk_mode,
-+	.get_rate	= genclk_get_rate,
-+	.set_rate	= genclk_set_rate,
-+	.set_parent	= genclk_set_parent,
-+	.index		= 6,
-+};
++int kprobe_trap_handler(struct pt_regs *regs, unsigned int instr)
++{
++	kprobe_handler(regs);
++	return 0;
++}
 +
-+struct platform_device *__init at32_add_device_abdac(unsigned int id)
++int __kprobes kprobe_fault_handler(struct pt_regs *regs, unsigned int fsr)
 +{
-+	struct platform_device *pdev;
++	struct kprobe *cur = kprobe_running();
++	struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
 +
-+	if (id != 0)
-+		return NULL;
++	switch (kcb->kprobe_status) {
++	case KPROBE_HIT_SS:
++	case KPROBE_REENTER:
++		/*
++		 * We are here because the instruction being single
++		 * stepped caused a page fault. We reset the current
++		 * kprobe and the PC to point back to the probe address
++		 * and allow the page fault handler to continue as a
++		 * normal page fault.
++		 */
++		regs->ARM_pc = (long)cur->addr;
++		if (kcb->kprobe_status == KPROBE_REENTER) {
++			restore_previous_kprobe(kcb);
++		} else {
++			reset_current_kprobe();
++		}
++		break;
 +
-+	pdev = platform_device_alloc("abdac", id);
-+	if (!pdev)
-+		return NULL;
++	case KPROBE_HIT_ACTIVE:
++	case KPROBE_HIT_SSDONE:
++		/*
++		 * We increment the nmissed count for accounting,
++		 * we can also use npre/npostfault count for accounting
++		 * these specific fault cases.
++		 */
++		kprobes_inc_nmissed_count(cur);
 +
-+	if (platform_device_add_resources(pdev, abdac0_resource,
-+				ARRAY_SIZE(abdac0_resource)))
-+		goto err_add_resources;
++		/*
++		 * We come here because instructions in the pre/post
++		 * handler caused the page_fault, this could happen
++		 * if handler tries to access user space by
++		 * copy_from_user(), get_user() etc. Let the
++		 * user-specified handler try to fix it.
++		 */
++		if (cur->fault_handler && cur->fault_handler(cur, regs, fsr))
++			return 1;
++		break;
 +
-+	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	*/
++	default:
++		break;
++	}
 +
-+	abdac0_pclk.dev = &pdev->dev;
-+	abdac0_sample_clk.dev = &pdev->dev;
++	return 0;
++}
 +
-+	platform_device_add(pdev);
-+	return pdev;
++int __kprobes kprobe_exceptions_notify(struct notifier_block *self,
++				       unsigned long val, void *data)
++{
++	/*
++	 * notify_die() is currently never called on ARM,
++	 * so this callback is currently empty.
++	 */
++	return NOTIFY_DONE;
++}
 +
-+err_add_resources:
-+	platform_device_put(pdev);
-+	return NULL;
++/*
++ * When a retprobed function returns, trampoline_handler() is called,
++ * calling the kretprobe's handler. We construct a struct pt_regs to
++ * give a view of registers r0-r11 to the user return-handler.  This is
++ * not a complete pt_regs structure, but that should be plenty sufficient
++ * for kretprobe handlers which should normally be interested in r0 only
++ * anyway.
++ */
++static void __attribute__((naked)) __kprobes kretprobe_trampoline(void)
++{
++	__asm__ __volatile__ (
++		"stmdb	sp!, {r0 - r11}		\n\t"
++		"mov	r0, sp			\n\t"
++		"bl	trampoline_handler	\n\t"
++		"mov	lr, r0			\n\t"
++		"ldmia	sp!, {r0 - r11}		\n\t"
++		"mov	pc, lr			\n\t"
++		: : : "memory");
 +}
 +
-+/* --------------------------------------------------------------------
-+ *  GCLK
-+ * -------------------------------------------------------------------- */
-+static struct clk gclk0 = {
-+	.name		= "gclk0",
-+	.mode		= genclk_mode,
-+	.get_rate	= genclk_get_rate,
-+	.set_rate	= genclk_set_rate,
-+	.set_parent	= genclk_set_parent,
-+	.index		= 0,
-+};
-+static struct clk gclk1 = {
-+	.name		= "gclk1",
-+	.mode		= genclk_mode,
-+	.get_rate	= genclk_get_rate,
-+	.set_rate	= genclk_set_rate,
-+	.set_parent	= genclk_set_parent,
-+	.index		= 1,
-+};
-+static struct clk gclk2 = {
-+	.name		= "gclk2",
-+	.mode		= genclk_mode,
-+	.get_rate	= genclk_get_rate,
-+	.set_rate	= genclk_set_rate,
-+	.set_parent	= genclk_set_parent,
-+	.index		= 2,
-+};
-+static struct clk gclk3 = {
-+	.name		= "gclk3",
-+	.mode		= genclk_mode,
-+	.get_rate	= genclk_get_rate,
-+	.set_rate	= genclk_set_rate,
-+	.set_parent	= genclk_set_parent,
-+	.index		= 3,
-+};
-+static struct clk gclk4 = {
-+	.name		= "gclk4",
-+	.mode		= genclk_mode,
-+	.get_rate	= genclk_get_rate,
-+	.set_rate	= genclk_set_rate,
-+	.set_parent	= genclk_set_parent,
-+	.index		= 4,
-+};
++/* Called from kretprobe_trampoline */
++static __used __kprobes void *trampoline_handler(struct pt_regs *regs)
++{
++	struct kretprobe_instance *ri = NULL;
++	struct hlist_head *head, empty_rp;
++	struct hlist_node *node, *tmp;
++	unsigned long flags, orig_ret_address = 0;
++	unsigned long trampoline_address = (unsigned long)&kretprobe_trampoline;
 +
-+struct clk *at32_clock_list[] = {
-+	&osc32k,
-+	&osc0,
-+	&osc1,
-+	&pll0,
-+	&pll1,
-+	&cpu_clk,
-+	&hsb_clk,
-+	&pba_clk,
-+	&pbb_clk,
-+	&at32_pm_pclk,
-+	&at32_intc0_pclk,
-+	&hmatrix_clk,
-+	&ebi_clk,
-+	&hramc_clk,
-+	&smc0_pclk,
-+	&smc0_mck,
-+	&pdc_hclk,
-+	&pdc_pclk,
-+	&dmaca0_hclk,
-+	&pico_clk,
-+	&pio0_mck,
-+	&pio1_mck,
-+	&pio2_mck,
-+	&pio3_mck,
-+	&pio4_mck,
-+	&at32_systc0_pclk,
-+	&atmel_usart0_usart,
-+	&atmel_usart1_usart,
-+	&atmel_usart2_usart,
-+	&atmel_usart3_usart,
-+#if defined(CONFIG_CPU_AT32AP7000)
-+	&macb0_hclk,
-+	&macb0_pclk,
-+	&macb1_hclk,
-+	&macb1_pclk,
-+#endif
-+	&atmel_spi0_spi_clk,
-+	&atmel_spi1_spi_clk,
-+	&atmel_twi0_pclk,
-+	&atmel_mci0_pclk,
-+#if defined(CONFIG_CPU_AT32AP7000) || defined(CONFIG_CPU_AT32AP7002)
-+	&atmel_lcdfb0_hck1,
-+	&atmel_lcdfb0_pixclk,
-+#endif
-+	&ssc0_pclk,
-+	&ssc1_pclk,
-+	&ssc2_pclk,
-+	&usba0_hclk,
-+	&usba0_pclk,
-+	&atmel_ac97c0_pclk,
-+	&abdac0_pclk,
-+	&abdac0_sample_clk,
-+	&gclk0,
-+	&gclk1,
-+	&gclk2,
-+	&gclk3,
-+	&gclk4,
-+};
-+unsigned int at32_nr_clocks = ARRAY_SIZE(at32_clock_list);
++	INIT_HLIST_HEAD(&empty_rp);
++	spin_lock_irqsave(&kretprobe_lock, flags);
++	head = kretprobe_inst_table_head(current);
 +
-+void __init at32_portmux_init(void)
-+{
-+	at32_init_pio(&pio0_device);
-+	at32_init_pio(&pio1_device);
-+	at32_init_pio(&pio2_device);
-+	at32_init_pio(&pio3_device);
-+	at32_init_pio(&pio4_device);
++	/*
++	 * It is possible to have multiple instances associated with a given
++	 * task either because multiple functions in the call path have
++	 * a return probe installed on them, and/or more than one return
++	 * probe was registered for a target function.
++	 *
++	 * We can handle this because:
++	 *     - instances are always inserted at the head of the list
++	 *     - when multiple return probes are registered for the same
++	 *       function, the first instance's ret_addr will point to the
++	 *       real return address, and all the rest will point to
++	 *       kretprobe_trampoline
++	 */
++	hlist_for_each_entry_safe(ri, node, tmp, head, hlist) {
++		if (ri->task != current)
++			/* another task is sharing our hash bucket */
++			continue;
++
++		if (ri->rp && ri->rp->handler) {
++			__get_cpu_var(current_kprobe) = &ri->rp->kp;
++			get_kprobe_ctlblk()->kprobe_status = KPROBE_HIT_ACTIVE;
++			ri->rp->handler(ri, regs);
++			__get_cpu_var(current_kprobe) = NULL;
++		}
++
++		orig_ret_address = (unsigned long)ri->ret_addr;
++		recycle_rp_inst(ri, &empty_rp);
++
++		if (orig_ret_address != trampoline_address)
++			/*
++			 * This is the real return address. Any other
++			 * instances associated with this task are for
++			 * other calls deeper on the call stack
++			 */
++			break;
++	}
++
++	kretprobe_assert(ri, orig_ret_address, trampoline_address);
++	spin_unlock_irqrestore(&kretprobe_lock, flags);
++
++	hlist_for_each_entry_safe(ri, node, tmp, &empty_rp, hlist) {
++		hlist_del(&ri->hlist);
++		kfree(ri);
++	}
++
++	return (void *)orig_ret_address;
 +}
 +
-+void __init at32_clock_init(void)
++/* Called with kretprobe_lock held. */
++void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri,
++				      struct pt_regs *regs)
 +{
-+	u32 cpu_mask = 0, hsb_mask = 0, pba_mask = 0, pbb_mask = 0;
-+	int i;
++	ri->ret_addr = (kprobe_opcode_t *)regs->ARM_lr;
 +
-+	if (pm_readl(MCCTRL) & PM_BIT(PLLSEL)) {
-+		main_clock = &pll0;
-+		cpu_clk.parent = &pll0;
-+	} else {
-+		main_clock = &osc0;
-+		cpu_clk.parent = &osc0;
-+	}
++	/* Replace the return addr with trampoline addr. */
++	regs->ARM_lr = (unsigned long)&kretprobe_trampoline;
++}
 +
-+	if (pm_readl(PLL0) & PM_BIT(PLLOSC))
-+		pll0.parent = &osc1;
-+	if (pm_readl(PLL1) & PM_BIT(PLLOSC))
-+		pll1.parent = &osc1;
++int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
++{
++	struct jprobe *jp = container_of(p, struct jprobe, kp);
++	struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
++	long sp_addr = regs->ARM_sp;
 +
-+	genclk_init_parent(&gclk0);
-+	genclk_init_parent(&gclk1);
-+	genclk_init_parent(&gclk2);
-+	genclk_init_parent(&gclk3);
-+	genclk_init_parent(&gclk4);
-+#if defined(CONFIG_CPU_AT32AP7000) || defined(CONFIG_CPU_AT32AP7002)
-+	genclk_init_parent(&atmel_lcdfb0_pixclk);
-+#endif
-+	genclk_init_parent(&abdac0_sample_clk);
++	kcb->jprobe_saved_regs = *regs;
++	memcpy(kcb->jprobes_stack, (void *)sp_addr, MIN_STACK_SIZE(sp_addr));
++	regs->ARM_pc = (long)jp->entry;
++	regs->ARM_cpsr |= PSR_I_BIT;
++	preempt_disable();
++	return 1;
++}
 +
-+	/*
-+	 * 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];
++void __kprobes jprobe_return(void)
++{
++	struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
 +
-+		if (clk->users == 0)
-+			continue;
++	__asm__ __volatile__ (
++		/*
++		 * Setup an empty pt_regs. Fill SP and PC fields as
++		 * they're needed by longjmp_break_handler.
++		 */
++		"sub    sp, %0, %1		\n\t"
++		"ldr    r0, ="__stringify(JPROBE_MAGIC_ADDR)"\n\t"
++		"str    %0, [sp, %2]		\n\t"
++		"str    r0, [sp, %3]		\n\t"
++		"mov    r0, sp			\n\t"
++		"bl     kprobe_handler		\n\t"
 +
-+		if (clk->mode == &cpu_clk_mode)
-+			cpu_mask |= 1 << clk->index;
-+		else if (clk->mode == &hsb_clk_mode)
-+			hsb_mask |= 1 << clk->index;
-+		else if (clk->mode == &pba_clk_mode)
-+			pba_mask |= 1 << clk->index;
-+		else if (clk->mode == &pbb_clk_mode)
-+			pbb_mask |= 1 << clk->index;
++		/*
++		 * Return to the context saved by setjmp_pre_handler
++		 * and restored by longjmp_break_handler.
++		 */
++		"ldr	r0, [sp, %4]		\n\t"
++		"msr	cpsr_cxsf, r0		\n\t"
++		"ldmia	sp, {r0 - pc}		\n\t"
++		:
++		: "r" (kcb->jprobe_saved_regs.ARM_sp),
++		  "I" (sizeof(struct pt_regs)),
++		  "J" (offsetof(struct pt_regs, ARM_sp)),
++		  "J" (offsetof(struct pt_regs, ARM_pc)),
++		  "J" (offsetof(struct pt_regs, ARM_cpsr))
++		: "memory", "cc");
++}
++
++int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
++{
++	struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
++	long stack_addr = kcb->jprobe_saved_regs.ARM_sp;
++	long orig_sp = regs->ARM_sp;
++	struct jprobe *jp = container_of(p, struct jprobe, kp);
++
++	if (regs->ARM_pc == JPROBE_MAGIC_ADDR) {
++		if (orig_sp != stack_addr) {
++			struct pt_regs *saved_regs =
++				(struct pt_regs *)kcb->jprobe_saved_regs.ARM_sp;
++			printk("current sp %lx does not match saved sp %lx\n",
++			       orig_sp, stack_addr);
++			printk("Saved registers for jprobe %p\n", jp);
++			show_regs(saved_regs);
++			printk("Current registers\n");
++			show_regs(regs);
++			BUG();
++		}
++		*regs = kcb->jprobe_saved_regs;
++		memcpy((void *)stack_addr, kcb->jprobes_stack,
++		       MIN_STACK_SIZE(stack_addr));
++		preempt_enable_no_resched();
++		return 1;
 +	}
++	return 0;
++}
 +
-+	pm_writel(CPU_MASK, cpu_mask);
-+	pm_writel(HSB_MASK, hsb_mask);
-+	pm_writel(PBA_MASK, pba_mask);
-+	pm_writel(PBB_MASK, pbb_mask);
++static struct undef_hook kprobes_break_hook = {
++	.instr_mask	= 0xffffffff,
++	.instr_val	= KPROBE_BREAKPOINT_INSTRUCTION,
++	.cpsr_mask	= MODE_MASK,
++	.cpsr_val	= SVC_MODE,
++	.fn		= kprobe_trap_handler,
++};
++
++int __init arch_init_kprobes()
++{
++	arm_kprobe_decode_init();
++	register_undef_hook(&kprobes_break_hook);
++	return 0;
 +}
-diff --git a/arch/avr32/mach-at32ap/extint.c b/arch/avr32/mach-at32ap/extint.c
-index f5bfd4c..c36a6d5 100644
---- a/arch/avr32/mach-at32ap/extint.c
-+++ b/arch/avr32/mach-at32ap/extint.c
-@@ -26,16 +26,10 @@
- #define EIC_MODE				0x0014
- #define EIC_EDGE				0x0018
- #define EIC_LEVEL				0x001c
--#define EIC_TEST				0x0020
- #define EIC_NMIC				0x0024
+diff --git a/arch/arm/kernel/time.c b/arch/arm/kernel/time.c
+index 1533d3e..b5867ec 100644
+--- a/arch/arm/kernel/time.c
++++ b/arch/arm/kernel/time.c
+@@ -79,17 +79,6 @@ static unsigned long dummy_gettimeoffset(void)
+ }
+ #endif
  
--/* Bitfields in TEST */
--#define EIC_TESTEN_OFFSET			31
--#define EIC_TESTEN_SIZE				1
+-/*
+- * An implementation of printk_clock() independent from
+- * sched_clock().  This avoids non-bootable kernels when
+- * printk_clock is enabled.
+- */
+-unsigned long long printk_clock(void)
+-{
+-	return (unsigned long long)(jiffies - INITIAL_JIFFIES) *
+-			(1000000000 / HZ);
+-}
 -
- /* Bitfields in NMIC */
--#define EIC_EN_OFFSET				0
--#define EIC_EN_SIZE				1
-+#define EIC_NMIC_ENABLE				(1 << 0)
+ static unsigned long next_rtc_update;
  
- /* Bit manipulation macros */
- #define EIC_BIT(name)					\
-@@ -63,6 +57,9 @@ struct eic {
- 	unsigned int first_irq;
+ /*
+@@ -195,7 +184,7 @@ static int leds_shutdown(struct sys_device *dev)
+ }
+ 
+ static struct sysdev_class leds_sysclass = {
+-	set_kset_name("leds"),
++	.name		= "leds",
+ 	.shutdown	= leds_shutdown,
+ 	.suspend	= leds_suspend,
+ 	.resume		= leds_resume,
+@@ -336,7 +325,9 @@ void timer_tick(void)
+ 	profile_tick(CPU_PROFILING);
+ 	do_leds();
+ 	do_set_rtc();
++	write_seqlock(&xtime_lock);
+ 	do_timer(1);
++	write_sequnlock(&xtime_lock);
+ #ifndef CONFIG_SMP
+ 	update_process_times(user_mode(get_irq_regs()));
+ #endif
+@@ -369,7 +360,7 @@ static int timer_resume(struct sys_device *dev)
+ #endif
+ 
+ static struct sysdev_class timer_sysclass = {
+-	set_kset_name("timer"),
++	.name		= "timer",
+ 	.suspend	= timer_suspend,
+ 	.resume		= timer_resume,
  };
+diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
+index c34db4e..5595fdd 100644
+--- a/arch/arm/kernel/traps.c
++++ b/arch/arm/kernel/traps.c
+@@ -19,6 +19,7 @@
+ #include <linux/kallsyms.h>
+ #include <linux/delay.h>
+ #include <linux/init.h>
++#include <linux/kprobes.h>
  
-+static struct eic *nmi_eic;
-+static bool nmi_enabled;
-+
- static void eic_ack_irq(unsigned int irq)
- {
- 	struct eic *eic = get_irq_chip_data(irq);
-@@ -133,8 +130,11 @@ static int eic_set_irq_type(unsigned int irq, unsigned int flow_type)
- 		eic_writel(eic, EDGE, edge);
- 		eic_writel(eic, LEVEL, level);
+ #include <asm/atomic.h>
+ #include <asm/cacheflush.h>
+@@ -46,15 +47,6 @@ __setup("user_debug=", user_debug_setup);
  
--		if (flow_type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH))
-+		if (flow_type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) {
- 			flow_type |= IRQ_LEVEL;
-+			__set_irq_handler_unlocked(irq, handle_level_irq);
-+		} else
-+			__set_irq_handler_unlocked(irq, handle_edge_irq);
- 		desc->status &= ~(IRQ_TYPE_SENSE_MASK | IRQ_LEVEL);
- 		desc->status |= flow_type;
- 	}
-@@ -154,9 +154,8 @@ static struct irq_chip eic_chip = {
- static void demux_eic_irq(unsigned int irq, struct irq_desc *desc)
+ static void dump_mem(const char *str, unsigned long bottom, unsigned long top);
+ 
+-static inline int in_exception_text(unsigned long ptr)
+-{
+-	extern char __exception_text_start[];
+-	extern char __exception_text_end[];
+-
+-	return ptr >= (unsigned long)&__exception_text_start &&
+-	       ptr < (unsigned long)&__exception_text_end;
+-}
+-
+ void dump_backtrace_entry(unsigned long where, unsigned long from, unsigned long frame)
  {
- 	struct eic *eic = desc->handler_data;
--	struct irq_desc *ext_desc;
- 	unsigned long status, pending;
--	unsigned int i, ext_irq;
-+	unsigned int i;
+ #ifdef CONFIG_KALLSYMS
+@@ -322,6 +314,17 @@ asmlinkage void __exception do_undefinstr(struct pt_regs *regs)
+ 		get_user(instr, (u32 __user *)pc);
+ 	}
  
- 	status = eic_readl(eic, ISR);
- 	pending = status & eic_readl(eic, IMR);
-@@ -165,15 +164,28 @@ static void demux_eic_irq(unsigned int irq, struct irq_desc *desc)
- 		i = fls(pending) - 1;
- 		pending &= ~(1 << i);
++#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
++
+ 	spin_lock_irqsave(&undef_lock, flags);
+ 	list_for_each_entry(hook, &undef_hook, node) {
+ 		if ((instr & hook->instr_mask) == hook->instr_val &&
+diff --git a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S
+index 5ff5406..30f732c 100644
+--- a/arch/arm/kernel/vmlinux.lds.S
++++ b/arch/arm/kernel/vmlinux.lds.S
+@@ -94,6 +94,7 @@ SECTIONS
+ 			TEXT_TEXT
+ 			SCHED_TEXT
+ 			LOCK_TEXT
++			KPROBES_TEXT
+ #ifdef CONFIG_MMU
+ 			*(.fixup)
+ #endif
+diff --git a/arch/arm/mach-aaec2000/core.c b/arch/arm/mach-aaec2000/core.c
+index 0446ef2..b016be2 100644
+--- a/arch/arm/mach-aaec2000/core.c
++++ b/arch/arm/mach-aaec2000/core.c
+@@ -130,13 +130,9 @@ static irqreturn_t
+ aaec2000_timer_interrupt(int irq, void *dev_id)
+ {
+ 	/* TODO: Check timer accuracy */
+-	write_seqlock(&xtime_lock);
+-
+ 	timer_tick();
+ 	TIMER1_CLEAR = 1;
  
--		ext_irq = i + eic->first_irq;
--		ext_desc = irq_desc + ext_irq;
--		if (ext_desc->status & IRQ_LEVEL)
--			handle_level_irq(ext_irq, ext_desc);
--		else
--			handle_edge_irq(ext_irq, ext_desc);
-+		generic_handle_irq(i + eic->first_irq);
- 	}
+-	write_sequnlock(&xtime_lock);
+-
+ 	return IRQ_HANDLED;
  }
  
-+int nmi_enable(void)
-+{
-+	nmi_enabled = true;
+diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig
+index 05a9f8a..5b0422c 100644
+--- a/arch/arm/mach-at91/Kconfig
++++ b/arch/arm/mach-at91/Kconfig
+@@ -22,6 +22,9 @@ config ARCH_AT91SAM9263
+ config ARCH_AT91SAM9RL
+ 	bool "AT91SAM9RL"
+ 
++config ARCH_AT91CAP9
++	bool "AT91CAP9"
 +
-+	if (nmi_eic)
-+		eic_writel(nmi_eic, NMIC, EIC_NMIC_ENABLE);
+ config ARCH_AT91X40
+ 	bool "AT91x40"
+ 
+@@ -178,6 +181,21 @@ endif
+ 
+ # ----------------------------------------------------------
+ 
++if ARCH_AT91CAP9
 +
-+	return 0;
-+}
++comment "AT91CAP9 Board Type"
 +
-+void nmi_disable(void)
-+{
-+	if (nmi_eic)
-+		eic_writel(nmi_eic, NMIC, 0);
++config MACH_AT91CAP9ADK
++	bool "Atmel AT91CAP9A-DK Evaluation Kit"
++	depends on ARCH_AT91CAP9
++	help
++	  Select this if you are using Atmel's AT91CAP9A-DK Evaluation Kit.
++	  <http://www.atmel.com/dyn/products/tools_card.asp?tool_id=4138>
 +
-+	nmi_enabled = false;
-+}
++endif
 +
- static int __init eic_probe(struct platform_device *pdev)
- {
- 	struct eic *eic;
-@@ -214,14 +226,13 @@ static int __init eic_probe(struct platform_device *pdev)
- 	pattern = eic_readl(eic, MODE);
- 	nr_irqs = fls(pattern);
- 
--	/* Trigger on falling edge unless overridden by driver */
--	eic_writel(eic, MODE, 0UL);
-+	/* Trigger on low level unless overridden by driver */
- 	eic_writel(eic, EDGE, 0UL);
-+	eic_writel(eic, LEVEL, 0UL);
- 
- 	eic->chip = &eic_chip;
- 
- 	for (i = 0; i < nr_irqs; i++) {
--		/* NOTE the handler we set here is ignored by the demux */
- 		set_irq_chip_and_handler(eic->first_irq + i, &eic_chip,
- 					 handle_level_irq);
- 		set_irq_chip_data(eic->first_irq + i, eic);
-@@ -230,6 +241,16 @@ static int __init eic_probe(struct platform_device *pdev)
- 	set_irq_chained_handler(int_irq, demux_eic_irq);
- 	set_irq_data(int_irq, eic);
- 
-+	if (pdev->id == 0) {
-+		nmi_eic = eic;
-+		if (nmi_enabled)
-+			/*
-+			 * Someone tried to enable NMI before we were
-+			 * ready. Do it now.
-+			 */
-+			nmi_enable();
-+	}
++# ----------------------------------------------------------
 +
- 	dev_info(&pdev->dev,
- 		 "External Interrupt Controller at 0x%p, IRQ %u\n",
- 		 eic->regs, int_irq);
-diff --git a/arch/avr32/mm/dma-coherent.c b/arch/avr32/mm/dma-coherent.c
-index 177fea8..6d8c794 100644
---- a/arch/avr32/mm/dma-coherent.c
-+++ b/arch/avr32/mm/dma-coherent.c
-@@ -41,6 +41,13 @@ static struct page *__dma_alloc(struct device *dev, size_t size,
- 	struct page *page, *free, *end;
- 	int order;
+ if ARCH_AT91X40
  
-+	/* Following is a work-around (a.k.a. hack) to prevent pages
-+	 * with __GFP_COMP being passed to split_page() which cannot
-+	 * handle them.  The real problem is that this flag probably
-+	 * should be 0 on AVR32 as it is not supported on this
-+	 * platform--see CONFIG_HUGETLB_PAGE. */
-+	gfp &= ~(__GFP_COMP);
-+
- 	size = PAGE_ALIGN(size);
- 	order = get_order(size);
+ comment "AT91X40 Board Type"
+@@ -198,13 +216,13 @@ comment "AT91 Board Options"
  
-diff --git a/arch/avr32/mm/tlb.c b/arch/avr32/mm/tlb.c
-index 5667201..b835257 100644
---- a/arch/avr32/mm/tlb.c
-+++ b/arch/avr32/mm/tlb.c
-@@ -348,7 +348,7 @@ static int tlb_show(struct seq_file *tlb, void *v)
- 	return 0;
- }
+ config MTD_AT91_DATAFLASH_CARD
+ 	bool "Enable DataFlash Card support"
+-	depends on (ARCH_AT91RM9200DK || MACH_AT91RM9200EK || MACH_AT91SAM9260EK || MACH_AT91SAM9261EK || MACH_AT91SAM9263EK)
++	depends on (ARCH_AT91RM9200DK || MACH_AT91RM9200EK || MACH_AT91SAM9260EK || MACH_AT91SAM9261EK || MACH_AT91SAM9263EK || MACH_AT91CAP9ADK)
+ 	help
+ 	  Enable support for the DataFlash card.
  
--static struct seq_operations tlb_ops = {
-+static const struct seq_operations tlb_ops = {
- 	.start		= tlb_start,
- 	.next		= tlb_next,
- 	.stop		= tlb_stop,
-diff --git a/arch/avr32/oprofile/Makefile b/arch/avr32/oprofile/Makefile
-new file mode 100644
-index 0000000..1fe81c3
---- /dev/null
-+++ b/arch/avr32/oprofile/Makefile
-@@ -0,0 +1,8 @@
-+obj-$(CONFIG_OPROFILE) += oprofile.o
+ config MTD_NAND_AT91_BUSWIDTH_16
+ 	bool "Enable 16-bit data bus interface to NAND flash"
+-	depends on (MACH_AT91SAM9260EK || MACH_AT91SAM9261EK || MACH_AT91SAM9263EK)
++	depends on (MACH_AT91SAM9260EK || MACH_AT91SAM9261EK || MACH_AT91SAM9263EK || MACH_AT91CAP9ADK)
+ 	help
+ 	  On AT91SAM926x boards both types of NAND flash can be present
+ 	  (8 and 16 bit data bus width).
+@@ -219,6 +237,22 @@ config AT91_PROGRAMMABLE_CLOCKS
+ 	  Select this if you need to program one or more of the PCK0..PCK3
+ 	  programmable clock outputs.
+ 
++config AT91_TIMER_HZ
++       int "Kernel HZ (jiffies per second)"
++       range 32 1024
++       depends on ARCH_AT91
++       default "128" if ARCH_AT91RM9200
++       default "100"
++       help
++	  On AT91rm9200 chips where you're using a system clock derived
++	  from the 32768 Hz hardware clock, this tick rate should divide
++	  it exactly: use a power-of-two value, such as 128 or 256, to
++	  reduce timing errors caused by rounding.
++
++	  On AT91sam926x chips, or otherwise when using a higher precision
++	  system clock (of at least several MHz), rounding is less of a
++	  problem so it can be safer to use a decimal values like 100.
 +
-+oprofile-y		:= $(addprefix ../../../drivers/oprofile/,	\
-+				oprof.o cpu_buffer.o buffer_sync.o	\
-+				event_buffer.o oprofile_files.o		\
-+				oprofilefs.o oprofile_stats.o		\
-+				timer_int.o)
-+oprofile-y		+= op_model_avr32.o
-diff --git a/arch/avr32/oprofile/op_model_avr32.c b/arch/avr32/oprofile/op_model_avr32.c
+ endmenu
+ 
+ endif
+diff --git a/arch/arm/mach-at91/Makefile b/arch/arm/mach-at91/Makefile
+index a21f08c..bf5f293 100644
+--- a/arch/arm/mach-at91/Makefile
++++ b/arch/arm/mach-at91/Makefile
+@@ -8,7 +8,6 @@ obj-n		:=
+ obj-		:=
+ 
+ obj-$(CONFIG_AT91_PMC_UNIT)	+= clock.o
+-obj-$(CONFIG_PM)		+= pm.o
+ 
+ # CPU-specific support
+ obj-$(CONFIG_ARCH_AT91RM9200)	+= at91rm9200.o at91rm9200_time.o at91rm9200_devices.o
+@@ -16,6 +15,7 @@ obj-$(CONFIG_ARCH_AT91SAM9260)	+= at91sam9260.o at91sam926x_time.o at91sam9260_d
+ obj-$(CONFIG_ARCH_AT91SAM9261)	+= at91sam9261.o at91sam926x_time.o at91sam9261_devices.o
+ obj-$(CONFIG_ARCH_AT91SAM9263)	+= at91sam9263.o at91sam926x_time.o at91sam9263_devices.o
+ obj-$(CONFIG_ARCH_AT91SAM9RL)	+= at91sam9rl.o at91sam926x_time.o at91sam9rl_devices.o
++obj-$(CONFIG_ARCH_AT91CAP9)	+= at91cap9.o at91sam926x_time.o at91cap9_devices.o
+ obj-$(CONFIG_ARCH_AT91X40)	+= at91x40.o at91x40_time.o
+ 
+ # AT91RM9200 board-specific support
+@@ -29,7 +29,6 @@ obj-$(CONFIG_MACH_KB9200)	+= board-kb9202.o
+ obj-$(CONFIG_MACH_ATEB9200)	+= board-eb9200.o
+ obj-$(CONFIG_MACH_KAFA)		+= board-kafa.o
+ obj-$(CONFIG_MACH_PICOTUX2XX)	+= board-picotux200.o
+-obj-$(CONFIG_MACH_AT91EB01)	+= board-eb01.o
+ 
+ # AT91SAM9260 board-specific support
+ obj-$(CONFIG_MACH_AT91SAM9260EK) += board-sam9260ek.o
+@@ -43,19 +42,17 @@ obj-$(CONFIG_MACH_AT91SAM9263EK) += board-sam9263ek.o
+ # AT91SAM9RL board-specific support
+ obj-$(CONFIG_MACH_AT91SAM9RLEK)	+= board-sam9rlek.o
+ 
+-# LEDs support
+-led-$(CONFIG_ARCH_AT91RM9200DK)	+= leds.o
+-led-$(CONFIG_MACH_AT91RM9200EK)	+= leds.o
+-led-$(CONFIG_MACH_AT91SAM9261EK)+= leds.o
+-led-$(CONFIG_MACH_CSB337)	+= leds.o
+-led-$(CONFIG_MACH_CSB637)	+= leds.o
+-led-$(CONFIG_MACH_KB9200)	+= leds.o
+-led-$(CONFIG_MACH_KAFA)		+= leds.o
+-obj-$(CONFIG_LEDS) += $(led-y)
++# AT91CAP9 board-specific support
++obj-$(CONFIG_MACH_AT91CAP9ADK)	+= board-cap9adk.o
+ 
+-# VGA support
+-#obj-$(CONFIG_FB_S1D13XXX)	+= ics1523.o
++# AT91X40 board-specific support
++obj-$(CONFIG_MACH_AT91EB01)	+= board-eb01.o
+ 
++# Drivers
++obj-y				+= leds.o
++
++# Power Management
++obj-$(CONFIG_PM)		+= pm.o
+ 
+ ifeq ($(CONFIG_PM_DEBUG),y)
+ CFLAGS_pm.o += -DDEBUG
+diff --git a/arch/arm/mach-at91/Makefile.boot b/arch/arm/mach-at91/Makefile.boot
+index e667dcc..071a250 100644
+--- a/arch/arm/mach-at91/Makefile.boot
++++ b/arch/arm/mach-at91/Makefile.boot
+@@ -3,7 +3,12 @@
+ #   PARAMS_PHYS must be within 4MB of ZRELADDR
+ #   INITRD_PHYS must be in RAM
+ 
++ifeq ($(CONFIG_ARCH_AT91CAP9),y)
++   zreladdr-y	:= 0x70008000
++params_phys-y	:= 0x70000100
++initrd_phys-y	:= 0x70410000
++else
+    zreladdr-y	:= 0x20008000
+ params_phys-y	:= 0x20000100
+ initrd_phys-y	:= 0x20410000
+-
++endif
+diff --git a/arch/arm/mach-at91/at91cap9.c b/arch/arm/mach-at91/at91cap9.c
 new file mode 100644
-index 0000000..e2f876b
+index 0000000..48d27d8
 --- /dev/null
-+++ b/arch/avr32/oprofile/op_model_avr32.c
-@@ -0,0 +1,235 @@
++++ b/arch/arm/mach-at91/at91cap9.c
+@@ -0,0 +1,365 @@
 +/*
-+ * AVR32 Performance Counter Driver
++ * arch/arm/mach-at91/at91cap9.c
 + *
-+ * Copyright (C) 2005-2007 Atmel Corporation
++ *  Copyright (C) 2007 Stelian Pop <stelian.pop at leadtechdesign.com>
++ *  Copyright (C) 2007 Lead Tech Design <www.leadtechdesign.com>
++ *  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 version 2 as
-+ * published by the Free Software Foundation.
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
 + *
-+ * Author: Ronny Pedersen
 + */
-+#include <linux/errno.h>
-+#include <linux/interrupt.h>
-+#include <linux/irq.h>
-+#include <linux/oprofile.h>
-+#include <linux/sched.h>
-+#include <linux/types.h>
 +
-+#include <asm/intc.h>
-+#include <asm/sysreg.h>
-+#include <asm/system.h>
++#include <linux/module.h>
 +
-+#define AVR32_PERFCTR_IRQ_GROUP	0
-+#define AVR32_PERFCTR_IRQ_LINE	1
++#include <asm/mach/arch.h>
++#include <asm/mach/map.h>
++#include <asm/arch/at91cap9.h>
++#include <asm/arch/at91_pmc.h>
++#include <asm/arch/at91_rstc.h>
 +
-+enum { PCCNT, PCNT0, PCNT1, NR_counter };
++#include "generic.h"
++#include "clock.h"
 +
-+struct avr32_perf_counter {
-+	unsigned long	enabled;
-+	unsigned long	event;
-+	unsigned long	count;
-+	unsigned long	unit_mask;
-+	unsigned long	kernel;
-+	unsigned long	user;
++static struct map_desc at91cap9_io_desc[] __initdata = {
++	{
++		.virtual	= AT91_VA_BASE_SYS,
++		.pfn		= __phys_to_pfn(AT91_BASE_SYS),
++		.length		= SZ_16K,
++		.type		= MT_DEVICE,
++	}, {
++		.virtual	= AT91_IO_VIRT_BASE - AT91CAP9_SRAM_SIZE,
++		.pfn		= __phys_to_pfn(AT91CAP9_SRAM_BASE),
++		.length		= AT91CAP9_SRAM_SIZE,
++		.type		= MT_DEVICE,
++	},
++};
 +
-+	u32		ie_mask;
-+	u32		flag_mask;
++/* --------------------------------------------------------------------
++ *  Clocks
++ * -------------------------------------------------------------------- */
++
++/*
++ * The peripheral clocks.
++ */
++static struct clk pioABCD_clk = {
++	.name		= "pioABCD_clk",
++	.pmc_mask	= 1 << AT91CAP9_ID_PIOABCD,
++	.type		= CLK_TYPE_PERIPHERAL,
++};
++static struct clk mpb0_clk = {
++	.name		= "mpb0_clk",
++	.pmc_mask	= 1 << AT91CAP9_ID_MPB0,
++	.type		= CLK_TYPE_PERIPHERAL,
++};
++static struct clk mpb1_clk = {
++	.name		= "mpb1_clk",
++	.pmc_mask	= 1 << AT91CAP9_ID_MPB1,
++	.type		= CLK_TYPE_PERIPHERAL,
++};
++static struct clk mpb2_clk = {
++	.name		= "mpb2_clk",
++	.pmc_mask	= 1 << AT91CAP9_ID_MPB2,
++	.type		= CLK_TYPE_PERIPHERAL,
++};
++static struct clk mpb3_clk = {
++	.name		= "mpb3_clk",
++	.pmc_mask	= 1 << AT91CAP9_ID_MPB3,
++	.type		= CLK_TYPE_PERIPHERAL,
++};
++static struct clk mpb4_clk = {
++	.name		= "mpb4_clk",
++	.pmc_mask	= 1 << AT91CAP9_ID_MPB4,
++	.type		= CLK_TYPE_PERIPHERAL,
++};
++static struct clk usart0_clk = {
++	.name		= "usart0_clk",
++	.pmc_mask	= 1 << AT91CAP9_ID_US0,
++	.type		= CLK_TYPE_PERIPHERAL,
++};
++static struct clk usart1_clk = {
++	.name		= "usart1_clk",
++	.pmc_mask	= 1 << AT91CAP9_ID_US1,
++	.type		= CLK_TYPE_PERIPHERAL,
++};
++static struct clk usart2_clk = {
++	.name		= "usart2_clk",
++	.pmc_mask	= 1 << AT91CAP9_ID_US2,
++	.type		= CLK_TYPE_PERIPHERAL,
++};
++static struct clk mmc0_clk = {
++	.name		= "mci0_clk",
++	.pmc_mask	= 1 << AT91CAP9_ID_MCI0,
++	.type		= CLK_TYPE_PERIPHERAL,
++};
++static struct clk mmc1_clk = {
++	.name		= "mci1_clk",
++	.pmc_mask	= 1 << AT91CAP9_ID_MCI1,
++	.type		= CLK_TYPE_PERIPHERAL,
++};
++static struct clk can_clk = {
++	.name		= "can_clk",
++	.pmc_mask	= 1 << AT91CAP9_ID_CAN,
++	.type		= CLK_TYPE_PERIPHERAL,
++};
++static struct clk twi_clk = {
++	.name		= "twi_clk",
++	.pmc_mask	= 1 << AT91CAP9_ID_TWI,
++	.type		= CLK_TYPE_PERIPHERAL,
++};
++static struct clk spi0_clk = {
++	.name		= "spi0_clk",
++	.pmc_mask	= 1 << AT91CAP9_ID_SPI0,
++	.type		= CLK_TYPE_PERIPHERAL,
++};
++static struct clk spi1_clk = {
++	.name		= "spi1_clk",
++	.pmc_mask	= 1 << AT91CAP9_ID_SPI1,
++	.type		= CLK_TYPE_PERIPHERAL,
++};
++static struct clk ssc0_clk = {
++	.name		= "ssc0_clk",
++	.pmc_mask	= 1 << AT91CAP9_ID_SSC0,
++	.type		= CLK_TYPE_PERIPHERAL,
++};
++static struct clk ssc1_clk = {
++	.name		= "ssc1_clk",
++	.pmc_mask	= 1 << AT91CAP9_ID_SSC1,
++	.type		= CLK_TYPE_PERIPHERAL,
++};
++static struct clk ac97_clk = {
++	.name		= "ac97_clk",
++	.pmc_mask	= 1 << AT91CAP9_ID_AC97C,
++	.type		= CLK_TYPE_PERIPHERAL,
++};
++static struct clk tcb_clk = {
++	.name		= "tcb_clk",
++	.pmc_mask	= 1 << AT91CAP9_ID_TCB,
++	.type		= CLK_TYPE_PERIPHERAL,
++};
++static struct clk pwmc_clk = {
++	.name		= "pwmc_clk",
++	.pmc_mask	= 1 << AT91CAP9_ID_PWMC,
++	.type		= CLK_TYPE_PERIPHERAL,
++};
++static struct clk macb_clk = {
++	.name		= "macb_clk",
++	.pmc_mask	= 1 << AT91CAP9_ID_EMAC,
++	.type		= CLK_TYPE_PERIPHERAL,
++};
++static struct clk aestdes_clk = {
++	.name		= "aestdes_clk",
++	.pmc_mask	= 1 << AT91CAP9_ID_AESTDES,
++	.type		= CLK_TYPE_PERIPHERAL,
++};
++static struct clk adc_clk = {
++	.name		= "adc_clk",
++	.pmc_mask	= 1 << AT91CAP9_ID_ADC,
++	.type		= CLK_TYPE_PERIPHERAL,
++};
++static struct clk isi_clk = {
++	.name		= "isi_clk",
++	.pmc_mask	= 1 << AT91CAP9_ID_ISI,
++	.type		= CLK_TYPE_PERIPHERAL,
++};
++static struct clk lcdc_clk = {
++	.name		= "lcdc_clk",
++	.pmc_mask	= 1 << AT91CAP9_ID_LCDC,
++	.type		= CLK_TYPE_PERIPHERAL,
++};
++static struct clk dma_clk = {
++	.name		= "dma_clk",
++	.pmc_mask	= 1 << AT91CAP9_ID_DMA,
++	.type		= CLK_TYPE_PERIPHERAL,
++};
++static struct clk udphs_clk = {
++	.name		= "udphs_clk",
++	.pmc_mask	= 1 << AT91CAP9_ID_UDPHS,
++	.type		= CLK_TYPE_PERIPHERAL,
++};
++static struct clk ohci_clk = {
++	.name		= "ohci_clk",
++	.pmc_mask	= 1 << AT91CAP9_ID_UHP,
++	.type		= CLK_TYPE_PERIPHERAL,
++};
++
++static struct clk *periph_clocks[] __initdata = {
++	&pioABCD_clk,
++	&mpb0_clk,
++	&mpb1_clk,
++	&mpb2_clk,
++	&mpb3_clk,
++	&mpb4_clk,
++	&usart0_clk,
++	&usart1_clk,
++	&usart2_clk,
++	&mmc0_clk,
++	&mmc1_clk,
++	&can_clk,
++	&twi_clk,
++	&spi0_clk,
++	&spi1_clk,
++	&ssc0_clk,
++	&ssc1_clk,
++	&ac97_clk,
++	&tcb_clk,
++	&pwmc_clk,
++	&macb_clk,
++	&aestdes_clk,
++	&adc_clk,
++	&isi_clk,
++	&lcdc_clk,
++	&dma_clk,
++	&udphs_clk,
++	&ohci_clk,
++	// irq0 .. irq1
 +};
 +
-+static struct avr32_perf_counter counter[NR_counter] = {
++/*
++ * The four programmable clocks.
++ * You must configure pin multiplexing to bring these signals out.
++ */
++static struct clk pck0 = {
++	.name		= "pck0",
++	.pmc_mask	= AT91_PMC_PCK0,
++	.type		= CLK_TYPE_PROGRAMMABLE,
++	.id		= 0,
++};
++static struct clk pck1 = {
++	.name		= "pck1",
++	.pmc_mask	= AT91_PMC_PCK1,
++	.type		= CLK_TYPE_PROGRAMMABLE,
++	.id		= 1,
++};
++static struct clk pck2 = {
++	.name		= "pck2",
++	.pmc_mask	= AT91_PMC_PCK2,
++	.type		= CLK_TYPE_PROGRAMMABLE,
++	.id		= 2,
++};
++static struct clk pck3 = {
++	.name		= "pck3",
++	.pmc_mask	= AT91_PMC_PCK3,
++	.type		= CLK_TYPE_PROGRAMMABLE,
++	.id		= 3,
++};
++
++static void __init at91cap9_register_clocks(void)
++{
++	int i;
++
++	for (i = 0; i < ARRAY_SIZE(periph_clocks); i++)
++		clk_register(periph_clocks[i]);
++
++	clk_register(&pck0);
++	clk_register(&pck1);
++	clk_register(&pck2);
++	clk_register(&pck3);
++}
++
++/* --------------------------------------------------------------------
++ *  GPIO
++ * -------------------------------------------------------------------- */
++
++static struct at91_gpio_bank at91cap9_gpio[] = {
 +	{
-+		.ie_mask	= SYSREG_BIT(IEC),
-+		.flag_mask	= SYSREG_BIT(FC),
++		.id		= AT91CAP9_ID_PIOABCD,
++		.offset		= AT91_PIOA,
++		.clock		= &pioABCD_clk,
 +	}, {
-+		.ie_mask	= SYSREG_BIT(IE0),
-+		.flag_mask	= SYSREG_BIT(F0),
++		.id		= AT91CAP9_ID_PIOABCD,
++		.offset		= AT91_PIOB,
++		.clock		= &pioABCD_clk,
 +	}, {
-+		.ie_mask	= SYSREG_BIT(IE1),
-+		.flag_mask	= SYSREG_BIT(F1),
-+	},
++		.id		= AT91CAP9_ID_PIOABCD,
++		.offset		= AT91_PIOC,
++		.clock		= &pioABCD_clk,
++	}, {
++		.id		= AT91CAP9_ID_PIOABCD,
++		.offset		= AT91_PIOD,
++		.clock		= &pioABCD_clk,
++	}
 +};
 +
-+static void avr32_perf_counter_reset(void)
++static void at91cap9_reset(void)
 +{
-+	/* Reset all counter and disable/clear all interrupts */
-+	sysreg_write(PCCR, (SYSREG_BIT(PCCR_R)
-+				| SYSREG_BIT(PCCR_C)
-+				| SYSREG_BIT(FC)
-+				| SYSREG_BIT(F0)
-+				| SYSREG_BIT(F1)));
++	at91_sys_write(AT91_RSTC_CR, AT91_RSTC_KEY | AT91_RSTC_PROCRST | AT91_RSTC_PERRST);
 +}
 +
-+static irqreturn_t avr32_perf_counter_interrupt(int irq, void *dev_id)
++/* --------------------------------------------------------------------
++ *  AT91CAP9 processor initialization
++ * -------------------------------------------------------------------- */
++
++void __init at91cap9_initialize(unsigned long main_clock)
 +{
-+	struct avr32_perf_counter *ctr = dev_id;
-+	struct pt_regs *regs;
-+	u32 pccr;
++	/* Map peripherals */
++	iotable_init(at91cap9_io_desc, ARRAY_SIZE(at91cap9_io_desc));
 +
-+	if (likely(!(intc_get_pending(AVR32_PERFCTR_IRQ_GROUP)
-+					& (1 << AVR32_PERFCTR_IRQ_LINE))))
-+		return IRQ_NONE;
++	at91_arch_reset = at91cap9_reset;
++	at91_extern_irq = (1 << AT91CAP9_ID_IRQ0) | (1 << AT91CAP9_ID_IRQ1);
 +
-+	regs = get_irq_regs();
-+	pccr = sysreg_read(PCCR);
++	/* Init clock subsystem */
++	at91_clock_init(main_clock);
 +
-+	/* Clear the interrupt flags we're about to handle */
-+	sysreg_write(PCCR, pccr);
++	/* Register the processor-specific clocks */
++	at91cap9_register_clocks();
 +
-+	/* PCCNT */
-+	if (ctr->enabled && (pccr & ctr->flag_mask)) {
-+		sysreg_write(PCCNT, -ctr->count);
-+		oprofile_add_sample(regs, PCCNT);
-+	}
-+	ctr++;
-+	/* PCNT0 */
-+	if (ctr->enabled && (pccr & ctr->flag_mask)) {
-+		sysreg_write(PCNT0, -ctr->count);
-+		oprofile_add_sample(regs, PCNT0);
-+	}
-+	ctr++;
-+	/* PCNT1 */
-+	if (ctr->enabled && (pccr & ctr->flag_mask)) {
-+		sysreg_write(PCNT1, -ctr->count);
-+		oprofile_add_sample(regs, PCNT1);
-+	}
++	/* Register GPIO subsystem */
++	at91_gpio_init(at91cap9_gpio, 4);
++}
 +
-+	return IRQ_HANDLED;
++/* --------------------------------------------------------------------
++ *  Interrupt initialization
++ * -------------------------------------------------------------------- */
++
++/*
++ * The default interrupt priority levels (0 = lowest, 7 = highest).
++ */
++static unsigned int at91cap9_default_irq_priority[NR_AIC_IRQS] __initdata = {
++	7,	/* Advanced Interrupt Controller (FIQ) */
++	7,	/* System Peripherals */
++	1,	/* Parallel IO Controller A, B, C and D */
++	0,	/* MP Block Peripheral 0 */
++	0,	/* MP Block Peripheral 1 */
++	0,	/* MP Block Peripheral 2 */
++	0,	/* MP Block Peripheral 3 */
++	0,	/* MP Block Peripheral 4 */
++	5,	/* USART 0 */
++	5,	/* USART 1 */
++	5,	/* USART 2 */
++	0,	/* Multimedia Card Interface 0 */
++	0,	/* Multimedia Card Interface 1 */
++	3,	/* CAN */
++	6,	/* Two-Wire Interface */
++	5,	/* Serial Peripheral Interface 0 */
++	5,	/* Serial Peripheral Interface 1 */
++	4,	/* Serial Synchronous Controller 0 */
++	4,	/* Serial Synchronous Controller 1 */
++	5,	/* AC97 Controller */
++	0,	/* Timer Counter 0, 1 and 2 */
++	0,	/* Pulse Width Modulation Controller */
++	3,	/* Ethernet */
++	0,	/* Advanced Encryption Standard, Triple DES*/
++	0,	/* Analog-to-Digital Converter */
++	0,	/* Image Sensor Interface */
++	3,	/* LCD Controller */
++	0,	/* DMA Controller */
++	2,	/* USB Device Port */
++	2,	/* USB Host port */
++	0,	/* Advanced Interrupt Controller (IRQ0) */
++	0,	/* Advanced Interrupt Controller (IRQ1) */
++};
++
++void __init at91cap9_init_interrupts(unsigned int priority[NR_AIC_IRQS])
++{
++	if (!priority)
++		priority = at91cap9_default_irq_priority;
++
++	/* Initialize the AIC interrupt controller */
++	at91_aic_init(priority);
++
++	/* Enable GPIO interrupts */
++	at91_gpio_irq_setup();
 +}
+diff --git a/arch/arm/mach-at91/at91cap9_devices.c b/arch/arm/mach-at91/at91cap9_devices.c
+new file mode 100644
+index 0000000..c50fad9
+--- /dev/null
++++ b/arch/arm/mach-at91/at91cap9_devices.c
+@@ -0,0 +1,1066 @@
++/*
++ * arch/arm/mach-at91/at91cap9_devices.c
++ *
++ *  Copyright (C) 2007 Stelian Pop <stelian.pop at leadtechdesign.com>
++ *  Copyright (C) 2007 Lead Tech Design <www.leadtechdesign.com>
++ *  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 option) any later version.
++ *
++ */
++#include <asm/mach/arch.h>
++#include <asm/mach/map.h>
 +
-+static int avr32_perf_counter_create_files(struct super_block *sb,
-+		struct dentry *root)
-+{
-+	struct dentry *dir;
-+	unsigned int i;
-+	char filename[4];
++#include <linux/dma-mapping.h>
++#include <linux/platform_device.h>
++#include <linux/mtd/physmap.h>
 +
-+	for (i = 0; i < NR_counter; i++) {
-+		snprintf(filename, sizeof(filename), "%u", i);
-+		dir = oprofilefs_mkdir(sb, root, filename);
++#include <video/atmel_lcdc.h>
 +
-+		oprofilefs_create_ulong(sb, dir, "enabled",
-+				&counter[i].enabled);
-+		oprofilefs_create_ulong(sb, dir, "event",
-+				&counter[i].event);
-+		oprofilefs_create_ulong(sb, dir, "count",
-+				&counter[i].count);
++#include <asm/arch/board.h>
++#include <asm/arch/gpio.h>
++#include <asm/arch/at91cap9.h>
++#include <asm/arch/at91sam926x_mc.h>
++#include <asm/arch/at91cap9_matrix.h>
 +
-+		/* Dummy entries */
-+		oprofilefs_create_ulong(sb, dir, "kernel",
-+				&counter[i].kernel);
-+		oprofilefs_create_ulong(sb, dir, "user",
-+				&counter[i].user);
-+		oprofilefs_create_ulong(sb, dir, "unit_mask",
-+				&counter[i].unit_mask);
-+	}
++#include "generic.h"
 +
-+	return 0;
-+}
 +
-+static int avr32_perf_counter_setup(void)
++/* --------------------------------------------------------------------
++ *  USB Host
++ * -------------------------------------------------------------------- */
++
++#if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
++static u64 ohci_dmamask = DMA_BIT_MASK(32);
++static struct at91_usbh_data usbh_data;
++
++static struct resource usbh_resources[] = {
++	[0] = {
++		.start	= AT91CAP9_UHP_BASE,
++		.end	= AT91CAP9_UHP_BASE + SZ_1M - 1,
++		.flags	= IORESOURCE_MEM,
++	},
++	[1] = {
++		.start	= AT91CAP9_ID_UHP,
++		.end	= AT91CAP9_ID_UHP,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device at91_usbh_device = {
++	.name		= "at91_ohci",
++	.id		= -1,
++	.dev		= {
++				.dma_mask		= &ohci_dmamask,
++				.coherent_dma_mask	= DMA_BIT_MASK(32),
++				.platform_data		= &usbh_data,
++	},
++	.resource	= usbh_resources,
++	.num_resources	= ARRAY_SIZE(usbh_resources),
++};
++
++void __init at91_add_device_usbh(struct at91_usbh_data *data)
 +{
-+	struct avr32_perf_counter *ctr;
-+	u32 pccr;
-+	int ret;
 +	int i;
 +
-+	pr_debug("avr32_perf_counter_setup\n");
++	if (!data)
++		return;
 +
-+	if (sysreg_read(PCCR) & SYSREG_BIT(PCCR_E)) {
-+		printk(KERN_ERR
-+			"oprofile: setup: perf counter already enabled\n");
-+		return -EBUSY;
++	/* Enable VBus control for UHP ports */
++	for (i = 0; i < data->ports; i++) {
++		if (data->vbus_pin[i])
++			at91_set_gpio_output(data->vbus_pin[i], 0);
 +	}
 +
-+	ret = request_irq(AVR32_PERFCTR_IRQ_GROUP,
-+			avr32_perf_counter_interrupt, IRQF_SHARED,
-+			"oprofile", counter);
-+	if (ret)
-+		return ret;
++	usbh_data = *data;
++	platform_device_register(&at91_usbh_device);
++}
++#else
++void __init at91_add_device_usbh(struct at91_usbh_data *data) {}
++#endif
 +
-+	avr32_perf_counter_reset();
 +
-+	pccr = 0;
-+	for (i = PCCNT; i < NR_counter; i++) {
-+		ctr = &counter[i];
-+		if (!ctr->enabled)
-+			continue;
++/* --------------------------------------------------------------------
++ *  Ethernet
++ * -------------------------------------------------------------------- */
 +
-+		pr_debug("enabling counter %d...\n", i);
++#if defined(CONFIG_MACB) || defined(CONFIG_MACB_MODULE)
++static u64 eth_dmamask = DMA_BIT_MASK(32);
++static struct at91_eth_data eth_data;
 +
-+		pccr |= ctr->ie_mask;
++static struct resource eth_resources[] = {
++	[0] = {
++		.start	= AT91CAP9_BASE_EMAC,
++		.end	= AT91CAP9_BASE_EMAC + SZ_16K - 1,
++		.flags	= IORESOURCE_MEM,
++	},
++	[1] = {
++		.start	= AT91CAP9_ID_EMAC,
++		.end	= AT91CAP9_ID_EMAC,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
 +
-+		switch (i) {
-+		case PCCNT:
-+			/* PCCNT always counts cycles, so no events */
-+			sysreg_write(PCCNT, -ctr->count);
-+			break;
-+		case PCNT0:
-+			pccr |= SYSREG_BF(CONF0, ctr->event);
-+			sysreg_write(PCNT0, -ctr->count);
-+			break;
-+		case PCNT1:
-+			pccr |= SYSREG_BF(CONF1, ctr->event);
-+			sysreg_write(PCNT1, -ctr->count);
-+			break;
-+		}
-+	}
++static struct platform_device at91cap9_eth_device = {
++	.name		= "macb",
++	.id		= -1,
++	.dev		= {
++				.dma_mask		= &eth_dmamask,
++				.coherent_dma_mask	= DMA_BIT_MASK(32),
++				.platform_data		= &eth_data,
++	},
++	.resource	= eth_resources,
++	.num_resources	= ARRAY_SIZE(eth_resources),
++};
 +
-+	pr_debug("oprofile: writing 0x%x to PCCR...\n", pccr);
++void __init at91_add_device_eth(struct at91_eth_data *data)
++{
++	if (!data)
++		return;
 +
-+	sysreg_write(PCCR, pccr);
++	if (data->phy_irq_pin) {
++		at91_set_gpio_input(data->phy_irq_pin, 0);
++		at91_set_deglitch(data->phy_irq_pin, 1);
++	}
++
++	/* Pins used for MII and RMII */
++	at91_set_A_periph(AT91_PIN_PB21, 0);	/* ETXCK_EREFCK */
++	at91_set_A_periph(AT91_PIN_PB22, 0);	/* ERXDV */
++	at91_set_A_periph(AT91_PIN_PB25, 0);	/* ERX0 */
++	at91_set_A_periph(AT91_PIN_PB26, 0);	/* ERX1 */
++	at91_set_A_periph(AT91_PIN_PB27, 0);	/* ERXER */
++	at91_set_A_periph(AT91_PIN_PB28, 0);	/* ETXEN */
++	at91_set_A_periph(AT91_PIN_PB23, 0);	/* ETX0 */
++	at91_set_A_periph(AT91_PIN_PB24, 0);	/* ETX1 */
++	at91_set_A_periph(AT91_PIN_PB30, 0);	/* EMDIO */
++	at91_set_A_periph(AT91_PIN_PB29, 0);	/* EMDC */
++
++	if (!data->is_rmii) {
++		at91_set_B_periph(AT91_PIN_PC25, 0);	/* ECRS */
++		at91_set_B_periph(AT91_PIN_PC26, 0);	/* ECOL */
++		at91_set_B_periph(AT91_PIN_PC22, 0);	/* ERX2 */
++		at91_set_B_periph(AT91_PIN_PC23, 0);	/* ERX3 */
++		at91_set_B_periph(AT91_PIN_PC27, 0);	/* ERXCK */
++		at91_set_B_periph(AT91_PIN_PC20, 0);	/* ETX2 */
++		at91_set_B_periph(AT91_PIN_PC21, 0);	/* ETX3 */
++		at91_set_B_periph(AT91_PIN_PC24, 0);	/* ETXER */
++	}
 +
-+	return 0;
++	eth_data = *data;
++	platform_device_register(&at91cap9_eth_device);
 +}
++#else
++void __init at91_add_device_eth(struct at91_eth_data *data) {}
++#endif
 +
-+static void avr32_perf_counter_shutdown(void)
-+{
-+	pr_debug("avr32_perf_counter_shutdown\n");
 +
-+	avr32_perf_counter_reset();
-+	free_irq(AVR32_PERFCTR_IRQ_GROUP, counter);
-+}
++/* --------------------------------------------------------------------
++ *  MMC / SD
++ * -------------------------------------------------------------------- */
 +
-+static int avr32_perf_counter_start(void)
-+{
-+	pr_debug("avr32_perf_counter_start\n");
++#if defined(CONFIG_MMC_AT91) || defined(CONFIG_MMC_AT91_MODULE)
++static u64 mmc_dmamask = DMA_BIT_MASK(32);
++static struct at91_mmc_data mmc0_data, mmc1_data;
 +
-+	sysreg_write(PCCR, sysreg_read(PCCR) | SYSREG_BIT(PCCR_E));
++static struct resource mmc0_resources[] = {
++	[0] = {
++		.start	= AT91CAP9_BASE_MCI0,
++		.end	= AT91CAP9_BASE_MCI0 + SZ_16K - 1,
++		.flags	= IORESOURCE_MEM,
++	},
++	[1] = {
++		.start	= AT91CAP9_ID_MCI0,
++		.end	= AT91CAP9_ID_MCI0,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
 +
-+	return 0;
-+}
++static struct platform_device at91cap9_mmc0_device = {
++	.name		= "at91_mci",
++	.id		= 0,
++	.dev		= {
++				.dma_mask		= &mmc_dmamask,
++				.coherent_dma_mask	= DMA_BIT_MASK(32),
++				.platform_data		= &mmc0_data,
++	},
++	.resource	= mmc0_resources,
++	.num_resources	= ARRAY_SIZE(mmc0_resources),
++};
 +
-+static void avr32_perf_counter_stop(void)
++static struct resource mmc1_resources[] = {
++	[0] = {
++		.start	= AT91CAP9_BASE_MCI1,
++		.end	= AT91CAP9_BASE_MCI1 + SZ_16K - 1,
++		.flags	= IORESOURCE_MEM,
++	},
++	[1] = {
++		.start	= AT91CAP9_ID_MCI1,
++		.end	= AT91CAP9_ID_MCI1,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device at91cap9_mmc1_device = {
++	.name		= "at91_mci",
++	.id		= 1,
++	.dev		= {
++				.dma_mask		= &mmc_dmamask,
++				.coherent_dma_mask	= DMA_BIT_MASK(32),
++				.platform_data		= &mmc1_data,
++	},
++	.resource	= mmc1_resources,
++	.num_resources	= ARRAY_SIZE(mmc1_resources),
++};
++
++void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data)
 +{
-+	pr_debug("avr32_perf_counter_stop\n");
++	if (!data)
++		return;
 +
-+	sysreg_write(PCCR, sysreg_read(PCCR) & ~SYSREG_BIT(PCCR_E));
++	/* input/irq */
++	if (data->det_pin) {
++		at91_set_gpio_input(data->det_pin, 1);
++		at91_set_deglitch(data->det_pin, 1);
++	}
++	if (data->wp_pin)
++		at91_set_gpio_input(data->wp_pin, 1);
++	if (data->vcc_pin)
++		at91_set_gpio_output(data->vcc_pin, 0);
++
++	if (mmc_id == 0) {		/* MCI0 */
++		/* CLK */
++		at91_set_A_periph(AT91_PIN_PA2, 0);
++
++		/* CMD */
++		at91_set_A_periph(AT91_PIN_PA1, 1);
++
++		/* DAT0, maybe DAT1..DAT3 */
++		at91_set_A_periph(AT91_PIN_PA0, 1);
++		if (data->wire4) {
++			at91_set_A_periph(AT91_PIN_PA3, 1);
++			at91_set_A_periph(AT91_PIN_PA4, 1);
++			at91_set_A_periph(AT91_PIN_PA5, 1);
++		}
++
++		mmc0_data = *data;
++		at91_clock_associate("mci0_clk", &at91cap9_mmc1_device.dev, "mci_clk");
++		platform_device_register(&at91cap9_mmc0_device);
++	} else {			/* MCI1 */
++		/* CLK */
++		at91_set_A_periph(AT91_PIN_PA16, 0);
++
++		/* CMD */
++		at91_set_A_periph(AT91_PIN_PA17, 1);
++
++		/* DAT0, maybe DAT1..DAT3 */
++		at91_set_A_periph(AT91_PIN_PA18, 1);
++		if (data->wire4) {
++			at91_set_A_periph(AT91_PIN_PA19, 1);
++			at91_set_A_periph(AT91_PIN_PA20, 1);
++			at91_set_A_periph(AT91_PIN_PA21, 1);
++		}
++
++		mmc1_data = *data;
++		at91_clock_associate("mci1_clk", &at91cap9_mmc1_device.dev, "mci_clk");
++		platform_device_register(&at91cap9_mmc1_device);
++	}
 +}
++#else
++void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data) {}
++#endif
 +
-+static struct oprofile_operations avr32_perf_counter_ops __initdata = {
-+	.create_files	= avr32_perf_counter_create_files,
-+	.setup		= avr32_perf_counter_setup,
-+	.shutdown	= avr32_perf_counter_shutdown,
-+	.start		= avr32_perf_counter_start,
-+	.stop		= avr32_perf_counter_stop,
-+	.cpu_type	= "avr32",
++
++/* --------------------------------------------------------------------
++ *  NAND / SmartMedia
++ * -------------------------------------------------------------------- */
++
++#if defined(CONFIG_MTD_NAND_AT91) || defined(CONFIG_MTD_NAND_AT91_MODULE)
++static struct at91_nand_data nand_data;
++
++#define NAND_BASE	AT91_CHIPSELECT_3
++
++static struct resource nand_resources[] = {
++	{
++		.start	= NAND_BASE,
++		.end	= NAND_BASE + SZ_256M - 1,
++		.flags	= IORESOURCE_MEM,
++	}
 +};
 +
-+int __init oprofile_arch_init(struct oprofile_operations *ops)
++static struct platform_device at91cap9_nand_device = {
++	.name		= "at91_nand",
++	.id		= -1,
++	.dev		= {
++				.platform_data	= &nand_data,
++	},
++	.resource	= nand_resources,
++	.num_resources	= ARRAY_SIZE(nand_resources),
++};
++
++void __init at91_add_device_nand(struct at91_nand_data *data)
 +{
-+	if (!(current_cpu_data.features & AVR32_FEATURE_PCTR))
-+		return -ENODEV;
++	unsigned long csa, mode;
 +
-+	memcpy(ops, &avr32_perf_counter_ops,
-+			sizeof(struct oprofile_operations));
++	if (!data)
++		return;
 +
-+	printk(KERN_INFO "oprofile: using AVR32 performance monitoring.\n");
++	csa = at91_sys_read(AT91_MATRIX_EBICSA);
++	at91_sys_write(AT91_MATRIX_EBICSA, csa | AT91_MATRIX_EBI_CS3A_SMC_SMARTMEDIA | AT91_MATRIX_EBI_VDDIOMSEL_3_3V);
 +
-+	return 0;
++	/* set the bus interface characteristics */
++	at91_sys_write(AT91_SMC_SETUP(3), AT91_SMC_NWESETUP_(2) | AT91_SMC_NCS_WRSETUP_(1)
++			| AT91_SMC_NRDSETUP_(2) | AT91_SMC_NCS_RDSETUP_(1));
++
++	at91_sys_write(AT91_SMC_PULSE(3), AT91_SMC_NWEPULSE_(4) | AT91_SMC_NCS_WRPULSE_(6)
++			| AT91_SMC_NRDPULSE_(4) | AT91_SMC_NCS_RDPULSE_(6));
++
++	at91_sys_write(AT91_SMC_CYCLE(3), AT91_SMC_NWECYCLE_(8) | AT91_SMC_NRDCYCLE_(8));
++
++	if (data->bus_width_16)
++		mode = AT91_SMC_DBW_16;
++	else
++		mode = AT91_SMC_DBW_8;
++	at91_sys_write(AT91_SMC_MODE(3), mode | AT91_SMC_READMODE | AT91_SMC_WRITEMODE | AT91_SMC_EXNWMODE_DISABLE | AT91_SMC_TDF_(1));
++
++	/* enable pin */
++	if (data->enable_pin)
++		at91_set_gpio_output(data->enable_pin, 1);
++
++	/* ready/busy pin */
++	if (data->rdy_pin)
++		at91_set_gpio_input(data->rdy_pin, 1);
++
++	/* card detect pin */
++	if (data->det_pin)
++		at91_set_gpio_input(data->det_pin, 1);
++
++	nand_data = *data;
++	platform_device_register(&at91cap9_nand_device);
 +}
++#else
++void __init at91_add_device_nand(struct at91_nand_data *data) {}
++#endif
 +
-+void oprofile_arch_exit(void)
++/* --------------------------------------------------------------------
++ *  TWI (i2c)
++ * -------------------------------------------------------------------- */
++
++/*
++ * Prefer the GPIO code since the TWI controller isn't robust
++ * (gets overruns and underruns under load) and can only issue
++ * repeated STARTs in one scenario (the driver doesn't yet handle them).
++ */
++#if defined(CONFIG_I2C_GPIO) || defined(CONFIG_I2C_GPIO_MODULE)
++
++static struct i2c_gpio_platform_data pdata = {
++	.sda_pin		= AT91_PIN_PB4,
++	.sda_is_open_drain	= 1,
++	.scl_pin		= AT91_PIN_PB5,
++	.scl_is_open_drain	= 1,
++	.udelay			= 2,		/* ~100 kHz */
++};
++
++static struct platform_device at91cap9_twi_device = {
++	.name			= "i2c-gpio",
++	.id			= -1,
++	.dev.platform_data	= &pdata,
++};
++
++void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices)
 +{
++	at91_set_GPIO_periph(AT91_PIN_PB4, 1);		/* TWD (SDA) */
++	at91_set_multi_drive(AT91_PIN_PB4, 1);
 +
-+}
-diff --git a/arch/blackfin/Kconfig b/arch/blackfin/Kconfig
-index 25232ba..fc7ca86 100644
---- a/arch/blackfin/Kconfig
-+++ b/arch/blackfin/Kconfig
-@@ -85,11 +85,26 @@ config BF522
- 	help
- 	  BF522 Processor Support.
- 
-+config BF523
-+	bool "BF523"
-+	help
-+	  BF523 Processor Support.
++	at91_set_GPIO_periph(AT91_PIN_PB5, 1);		/* TWCK (SCL) */
++	at91_set_multi_drive(AT91_PIN_PB5, 1);
 +
-+config BF524
-+	bool "BF524"
-+	help
-+	  BF524 Processor Support.
++	i2c_register_board_info(0, devices, nr_devices);
++	platform_device_register(&at91cap9_twi_device);
++}
 +
- config BF525
- 	bool "BF525"
- 	help
- 	  BF525 Processor Support.
- 
-+config BF526
-+	bool "BF526"
-+	help
-+	  BF526 Processor Support.
++#elif defined(CONFIG_I2C_AT91) || defined(CONFIG_I2C_AT91_MODULE)
 +
- config BF527
- 	bool "BF527"
- 	help
-@@ -198,7 +213,7 @@ endchoice
++static struct resource twi_resources[] = {
++	[0] = {
++		.start	= AT91CAP9_BASE_TWI,
++		.end	= AT91CAP9_BASE_TWI + SZ_16K - 1,
++		.flags	= IORESOURCE_MEM,
++	},
++	[1] = {
++		.start	= AT91CAP9_ID_TWI,
++		.end	= AT91CAP9_ID_TWI,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device at91cap9_twi_device = {
++	.name		= "at91_i2c",
++	.id		= -1,
++	.resource	= twi_resources,
++	.num_resources	= ARRAY_SIZE(twi_resources),
++};
++
++void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices)
++{
++	/* pins used for TWI interface */
++	at91_set_B_periph(AT91_PIN_PB4, 0);		/* TWD */
++	at91_set_multi_drive(AT91_PIN_PB4, 1);
++
++	at91_set_B_periph(AT91_PIN_PB5, 0);		/* TWCK */
++	at91_set_multi_drive(AT91_PIN_PB5, 1);
++
++	i2c_register_board_info(0, devices, nr_devices);
++	platform_device_register(&at91cap9_twi_device);
++}
++#else
++void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices) {}
++#endif
++
++/* --------------------------------------------------------------------
++ *  SPI
++ * -------------------------------------------------------------------- */
++
++#if defined(CONFIG_SPI_ATMEL) || defined(CONFIG_SPI_ATMEL_MODULE)
++static u64 spi_dmamask = DMA_BIT_MASK(32);
++
++static struct resource spi0_resources[] = {
++	[0] = {
++		.start	= AT91CAP9_BASE_SPI0,
++		.end	= AT91CAP9_BASE_SPI0 + SZ_16K - 1,
++		.flags	= IORESOURCE_MEM,
++	},
++	[1] = {
++		.start	= AT91CAP9_ID_SPI0,
++		.end	= AT91CAP9_ID_SPI0,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device at91cap9_spi0_device = {
++	.name		= "atmel_spi",
++	.id		= 0,
++	.dev		= {
++				.dma_mask		= &spi_dmamask,
++				.coherent_dma_mask	= DMA_BIT_MASK(32),
++	},
++	.resource	= spi0_resources,
++	.num_resources	= ARRAY_SIZE(spi0_resources),
++};
++
++static const unsigned spi0_standard_cs[4] = { AT91_PIN_PA5, AT91_PIN_PA3, AT91_PIN_PD0, AT91_PIN_PD1 };
++
++static struct resource spi1_resources[] = {
++	[0] = {
++		.start	= AT91CAP9_BASE_SPI1,
++		.end	= AT91CAP9_BASE_SPI1 + SZ_16K - 1,
++		.flags	= IORESOURCE_MEM,
++	},
++	[1] = {
++		.start	= AT91CAP9_ID_SPI1,
++		.end	= AT91CAP9_ID_SPI1,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device at91cap9_spi1_device = {
++	.name		= "atmel_spi",
++	.id		= 1,
++	.dev		= {
++				.dma_mask		= &spi_dmamask,
++				.coherent_dma_mask	= DMA_BIT_MASK(32),
++	},
++	.resource	= spi1_resources,
++	.num_resources	= ARRAY_SIZE(spi1_resources),
++};
++
++static const unsigned spi1_standard_cs[4] = { AT91_PIN_PB15, AT91_PIN_PB16, AT91_PIN_PB17, AT91_PIN_PB18 };
++
++void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices)
++{
++	int i;
++	unsigned long cs_pin;
++	short enable_spi0 = 0;
++	short enable_spi1 = 0;
++
++	/* Choose SPI chip-selects */
++	for (i = 0; i < nr_devices; i++) {
++		if (devices[i].controller_data)
++			cs_pin = (unsigned long) devices[i].controller_data;
++		else if (devices[i].bus_num == 0)
++			cs_pin = spi0_standard_cs[devices[i].chip_select];
++		else
++			cs_pin = spi1_standard_cs[devices[i].chip_select];
++
++		if (devices[i].bus_num == 0)
++			enable_spi0 = 1;
++		else
++			enable_spi1 = 1;
++
++		/* enable chip-select pin */
++		at91_set_gpio_output(cs_pin, 1);
++
++		/* pass chip-select pin to driver */
++		devices[i].controller_data = (void *) cs_pin;
++	}
++
++	spi_register_board_info(devices, nr_devices);
++
++	/* Configure SPI bus(es) */
++	if (enable_spi0) {
++		at91_set_B_periph(AT91_PIN_PA0, 0);	/* SPI0_MISO */
++		at91_set_B_periph(AT91_PIN_PA1, 0);	/* SPI0_MOSI */
++		at91_set_B_periph(AT91_PIN_PA2, 0);	/* SPI0_SPCK */
++
++		at91_clock_associate("spi0_clk", &at91cap9_spi0_device.dev, "spi_clk");
++		platform_device_register(&at91cap9_spi0_device);
++	}
++	if (enable_spi1) {
++		at91_set_A_periph(AT91_PIN_PB12, 0);	/* SPI1_MISO */
++		at91_set_A_periph(AT91_PIN_PB13, 0);	/* SPI1_MOSI */
++		at91_set_A_periph(AT91_PIN_PB14, 0);	/* SPI1_SPCK */
++
++		at91_clock_associate("spi1_clk", &at91cap9_spi1_device.dev, "spi_clk");
++		platform_device_register(&at91cap9_spi1_device);
++	}
++}
++#else
++void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices) {}
++#endif
++
++
++/* --------------------------------------------------------------------
++ *  RTT
++ * -------------------------------------------------------------------- */
++
++static struct platform_device at91cap9_rtt_device = {
++	.name		= "at91_rtt",
++	.id		= -1,
++	.num_resources	= 0,
++};
++
++static void __init at91_add_device_rtt(void)
++{
++	platform_device_register(&at91cap9_rtt_device);
++}
++
++
++/* --------------------------------------------------------------------
++ *  Watchdog
++ * -------------------------------------------------------------------- */
++
++#if defined(CONFIG_AT91SAM9_WATCHDOG) || defined(CONFIG_AT91SAM9_WATCHDOG_MODULE)
++static struct platform_device at91cap9_wdt_device = {
++	.name		= "at91_wdt",
++	.id		= -1,
++	.num_resources	= 0,
++};
++
++static void __init at91_add_device_watchdog(void)
++{
++	platform_device_register(&at91cap9_wdt_device);
++}
++#else
++static void __init at91_add_device_watchdog(void) {}
++#endif
++
++
++/* --------------------------------------------------------------------
++ *  AC97
++ * -------------------------------------------------------------------- */
++
++#if defined(CONFIG_SND_AT91_AC97) || defined(CONFIG_SND_AT91_AC97_MODULE)
++static u64 ac97_dmamask = DMA_BIT_MASK(32);
++static struct atmel_ac97_data ac97_data;
++
++static struct resource ac97_resources[] = {
++	[0] = {
++		.start	= AT91CAP9_BASE_AC97C,
++		.end	= AT91CAP9_BASE_AC97C + SZ_16K - 1,
++		.flags	= IORESOURCE_MEM,
++	},
++	[1] = {
++		.start	= AT91CAP9_ID_AC97C,
++		.end	= AT91CAP9_ID_AC97C,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device at91cap9_ac97_device = {
++	.name		= "ac97c",
++	.id		= 1,
++	.dev		= {
++				.dma_mask		= &ac97_dmamask,
++				.coherent_dma_mask	= DMA_BIT_MASK(32),
++				.platform_data		= &ac97_data,
++	},
++	.resource	= ac97_resources,
++	.num_resources	= ARRAY_SIZE(ac97_resources),
++};
++
++void __init at91_add_device_ac97(struct atmel_ac97_data *data)
++{
++	if (!data)
++		return;
++
++	at91_set_A_periph(AT91_PIN_PA6, 0);	/* AC97FS */
++	at91_set_A_periph(AT91_PIN_PA7, 0);	/* AC97CK */
++	at91_set_A_periph(AT91_PIN_PA8, 0);	/* AC97TX */
++	at91_set_A_periph(AT91_PIN_PA9, 0);	/* AC97RX */
++
++	/* reset */
++	if (data->reset_pin)
++		at91_set_gpio_output(data->reset_pin, 0);
++
++	ac97_data = *data;
++	platform_device_register(&at91cap9_ac97_device);
++}
++#else
++void __init at91_add_device_ac97(struct atmel_ac97_data *data) {}
++#endif
++
++
++/* --------------------------------------------------------------------
++ *  LCD Controller
++ * -------------------------------------------------------------------- */
++
++#if defined(CONFIG_FB_ATMEL) || defined(CONFIG_FB_ATMEL_MODULE)
++static u64 lcdc_dmamask = DMA_BIT_MASK(32);
++static struct atmel_lcdfb_info lcdc_data;
++
++static struct resource lcdc_resources[] = {
++	[0] = {
++		.start	= AT91CAP9_LCDC_BASE,
++		.end	= AT91CAP9_LCDC_BASE + SZ_4K - 1,
++		.flags	= IORESOURCE_MEM,
++	},
++	[1] = {
++		.start	= AT91CAP9_ID_LCDC,
++		.end	= AT91CAP9_ID_LCDC,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device at91_lcdc_device = {
++	.name		= "atmel_lcdfb",
++	.id		= 0,
++	.dev		= {
++				.dma_mask		= &lcdc_dmamask,
++				.coherent_dma_mask	= DMA_BIT_MASK(32),
++				.platform_data		= &lcdc_data,
++	},
++	.resource	= lcdc_resources,
++	.num_resources	= ARRAY_SIZE(lcdc_resources),
++};
++
++void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data)
++{
++	if (!data)
++		return;
++
++	at91_set_A_periph(AT91_PIN_PC1, 0);	/* LCDHSYNC */
++	at91_set_A_periph(AT91_PIN_PC2, 0);	/* LCDDOTCK */
++	at91_set_A_periph(AT91_PIN_PC3, 0);	/* LCDDEN */
++	at91_set_B_periph(AT91_PIN_PB9, 0);	/* LCDCC */
++	at91_set_A_periph(AT91_PIN_PC6, 0);	/* LCDD2 */
++	at91_set_A_periph(AT91_PIN_PC7, 0);	/* LCDD3 */
++	at91_set_A_periph(AT91_PIN_PC8, 0);	/* LCDD4 */
++	at91_set_A_periph(AT91_PIN_PC9, 0);	/* LCDD5 */
++	at91_set_A_periph(AT91_PIN_PC10, 0);	/* LCDD6 */
++	at91_set_A_periph(AT91_PIN_PC11, 0);	/* LCDD7 */
++	at91_set_A_periph(AT91_PIN_PC14, 0);	/* LCDD10 */
++	at91_set_A_periph(AT91_PIN_PC15, 0);	/* LCDD11 */
++	at91_set_A_periph(AT91_PIN_PC16, 0);	/* LCDD12 */
++	at91_set_A_periph(AT91_PIN_PC17, 0);	/* LCDD13 */
++	at91_set_A_periph(AT91_PIN_PC18, 0);	/* LCDD14 */
++	at91_set_A_periph(AT91_PIN_PC19, 0);	/* LCDD15 */
++	at91_set_A_periph(AT91_PIN_PC22, 0);	/* LCDD18 */
++	at91_set_A_periph(AT91_PIN_PC23, 0);	/* LCDD19 */
++	at91_set_A_periph(AT91_PIN_PC24, 0);	/* LCDD20 */
++	at91_set_A_periph(AT91_PIN_PC25, 0);	/* LCDD21 */
++	at91_set_A_periph(AT91_PIN_PC26, 0);	/* LCDD22 */
++	at91_set_A_periph(AT91_PIN_PC27, 0);	/* LCDD23 */
++
++	lcdc_data = *data;
++	platform_device_register(&at91_lcdc_device);
++}
++#else
++void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data) {}
++#endif
++
++
++/* --------------------------------------------------------------------
++ *  SSC -- Synchronous Serial Controller
++ * -------------------------------------------------------------------- */
++
++#if defined(CONFIG_ATMEL_SSC) || defined(CONFIG_ATMEL_SSC_MODULE)
++static u64 ssc0_dmamask = DMA_BIT_MASK(32);
++
++static struct resource ssc0_resources[] = {
++	[0] = {
++		.start	= AT91CAP9_BASE_SSC0,
++		.end	= AT91CAP9_BASE_SSC0 + SZ_16K - 1,
++		.flags	= IORESOURCE_MEM,
++	},
++	[1] = {
++		.start	= AT91CAP9_ID_SSC0,
++		.end	= AT91CAP9_ID_SSC0,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device at91cap9_ssc0_device = {
++	.name	= "ssc",
++	.id	= 0,
++	.dev	= {
++		.dma_mask		= &ssc0_dmamask,
++		.coherent_dma_mask	= DMA_BIT_MASK(32),
++	},
++	.resource	= ssc0_resources,
++	.num_resources	= ARRAY_SIZE(ssc0_resources),
++};
++
++static inline void configure_ssc0_pins(unsigned pins)
++{
++	if (pins & ATMEL_SSC_TF)
++		at91_set_A_periph(AT91_PIN_PB0, 1);
++	if (pins & ATMEL_SSC_TK)
++		at91_set_A_periph(AT91_PIN_PB1, 1);
++	if (pins & ATMEL_SSC_TD)
++		at91_set_A_periph(AT91_PIN_PB2, 1);
++	if (pins & ATMEL_SSC_RD)
++		at91_set_A_periph(AT91_PIN_PB3, 1);
++	if (pins & ATMEL_SSC_RK)
++		at91_set_A_periph(AT91_PIN_PB4, 1);
++	if (pins & ATMEL_SSC_RF)
++		at91_set_A_periph(AT91_PIN_PB5, 1);
++}
++
++static u64 ssc1_dmamask = DMA_BIT_MASK(32);
++
++static struct resource ssc1_resources[] = {
++	[0] = {
++		.start	= AT91CAP9_BASE_SSC1,
++		.end	= AT91CAP9_BASE_SSC1 + SZ_16K - 1,
++		.flags	= IORESOURCE_MEM,
++	},
++	[1] = {
++		.start	= AT91CAP9_ID_SSC1,
++		.end	= AT91CAP9_ID_SSC1,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device at91cap9_ssc1_device = {
++	.name	= "ssc",
++	.id	= 1,
++	.dev	= {
++		.dma_mask		= &ssc1_dmamask,
++		.coherent_dma_mask	= DMA_BIT_MASK(32),
++	},
++	.resource	= ssc1_resources,
++	.num_resources	= ARRAY_SIZE(ssc1_resources),
++};
++
++static inline void configure_ssc1_pins(unsigned pins)
++{
++	if (pins & ATMEL_SSC_TF)
++		at91_set_A_periph(AT91_PIN_PB6, 1);
++	if (pins & ATMEL_SSC_TK)
++		at91_set_A_periph(AT91_PIN_PB7, 1);
++	if (pins & ATMEL_SSC_TD)
++		at91_set_A_periph(AT91_PIN_PB8, 1);
++	if (pins & ATMEL_SSC_RD)
++		at91_set_A_periph(AT91_PIN_PB9, 1);
++	if (pins & ATMEL_SSC_RK)
++		at91_set_A_periph(AT91_PIN_PB10, 1);
++	if (pins & ATMEL_SSC_RF)
++		at91_set_A_periph(AT91_PIN_PB11, 1);
++}
++
++/*
++ * SSC controllers are accessed through library code, instead of any
++ * kind of all-singing/all-dancing driver.  For example one could be
++ * used by a particular I2S audio codec's driver, while another one
++ * on the same system might be used by a custom data capture driver.
++ */
++void __init at91_add_device_ssc(unsigned id, unsigned pins)
++{
++	struct platform_device *pdev;
++
++	/*
++	 * NOTE: caller is responsible for passing information matching
++	 * "pins" to whatever will be using each particular controller.
++	 */
++	switch (id) {
++	case AT91CAP9_ID_SSC0:
++		pdev = &at91cap9_ssc0_device;
++		configure_ssc0_pins(pins);
++		at91_clock_associate("ssc0_clk", &pdev->dev, "ssc");
++		break;
++	case AT91CAP9_ID_SSC1:
++		pdev = &at91cap9_ssc1_device;
++		configure_ssc1_pins(pins);
++		at91_clock_associate("ssc1_clk", &pdev->dev, "ssc");
++		break;
++	default:
++		return;
++	}
++
++	platform_device_register(pdev);
++}
++
++#else
++void __init at91_add_device_ssc(unsigned id, unsigned pins) {}
++#endif
++
++
++/* --------------------------------------------------------------------
++ *  UART
++ * -------------------------------------------------------------------- */
++
++#if defined(CONFIG_SERIAL_ATMEL)
++static struct resource dbgu_resources[] = {
++	[0] = {
++		.start	= AT91_VA_BASE_SYS + AT91_DBGU,
++		.end	= AT91_VA_BASE_SYS + AT91_DBGU + SZ_512 - 1,
++		.flags	= IORESOURCE_MEM,
++	},
++	[1] = {
++		.start	= AT91_ID_SYS,
++		.end	= AT91_ID_SYS,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct atmel_uart_data dbgu_data = {
++	.use_dma_tx	= 0,
++	.use_dma_rx	= 0,		/* DBGU not capable of receive DMA */
++	.regs		= (void __iomem *)(AT91_VA_BASE_SYS + AT91_DBGU),
++};
++
++static u64 dbgu_dmamask = DMA_BIT_MASK(32);
++
++static struct platform_device at91cap9_dbgu_device = {
++	.name		= "atmel_usart",
++	.id		= 0,
++	.dev		= {
++				.dma_mask		= &dbgu_dmamask,
++				.coherent_dma_mask	= DMA_BIT_MASK(32),
++				.platform_data		= &dbgu_data,
++	},
++	.resource	= dbgu_resources,
++	.num_resources	= ARRAY_SIZE(dbgu_resources),
++};
++
++static inline void configure_dbgu_pins(void)
++{
++	at91_set_A_periph(AT91_PIN_PC30, 0);		/* DRXD */
++	at91_set_A_periph(AT91_PIN_PC31, 1);		/* DTXD */
++}
++
++static struct resource uart0_resources[] = {
++	[0] = {
++		.start	= AT91CAP9_BASE_US0,
++		.end	= AT91CAP9_BASE_US0 + SZ_16K - 1,
++		.flags	= IORESOURCE_MEM,
++	},
++	[1] = {
++		.start	= AT91CAP9_ID_US0,
++		.end	= AT91CAP9_ID_US0,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct atmel_uart_data uart0_data = {
++	.use_dma_tx	= 1,
++	.use_dma_rx	= 1,
++};
++
++static u64 uart0_dmamask = DMA_BIT_MASK(32);
++
++static struct platform_device at91cap9_uart0_device = {
++	.name		= "atmel_usart",
++	.id		= 1,
++	.dev		= {
++				.dma_mask		= &uart0_dmamask,
++				.coherent_dma_mask	= DMA_BIT_MASK(32),
++				.platform_data		= &uart0_data,
++	},
++	.resource	= uart0_resources,
++	.num_resources	= ARRAY_SIZE(uart0_resources),
++};
++
++static inline void configure_usart0_pins(unsigned pins)
++{
++	at91_set_A_periph(AT91_PIN_PA22, 1);		/* TXD0 */
++	at91_set_A_periph(AT91_PIN_PA23, 0);		/* RXD0 */
++
++	if (pins & ATMEL_UART_RTS)
++		at91_set_A_periph(AT91_PIN_PA24, 0);	/* RTS0 */
++	if (pins & ATMEL_UART_CTS)
++		at91_set_A_periph(AT91_PIN_PA25, 0);	/* CTS0 */
++}
++
++static struct resource uart1_resources[] = {
++	[0] = {
++		.start	= AT91CAP9_BASE_US1,
++		.end	= AT91CAP9_BASE_US1 + SZ_16K - 1,
++		.flags	= IORESOURCE_MEM,
++	},
++	[1] = {
++		.start	= AT91CAP9_ID_US1,
++		.end	= AT91CAP9_ID_US1,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct atmel_uart_data uart1_data = {
++	.use_dma_tx	= 1,
++	.use_dma_rx	= 1,
++};
++
++static u64 uart1_dmamask = DMA_BIT_MASK(32);
++
++static struct platform_device at91cap9_uart1_device = {
++	.name		= "atmel_usart",
++	.id		= 2,
++	.dev		= {
++				.dma_mask		= &uart1_dmamask,
++				.coherent_dma_mask	= DMA_BIT_MASK(32),
++				.platform_data		= &uart1_data,
++	},
++	.resource	= uart1_resources,
++	.num_resources	= ARRAY_SIZE(uart1_resources),
++};
++
++static inline void configure_usart1_pins(unsigned pins)
++{
++	at91_set_A_periph(AT91_PIN_PD0, 1);		/* TXD1 */
++	at91_set_A_periph(AT91_PIN_PD1, 0);		/* RXD1 */
++
++	if (pins & ATMEL_UART_RTS)
++		at91_set_B_periph(AT91_PIN_PD7, 0);	/* RTS1 */
++	if (pins & ATMEL_UART_CTS)
++		at91_set_B_periph(AT91_PIN_PD8, 0);	/* CTS1 */
++}
++
++static struct resource uart2_resources[] = {
++	[0] = {
++		.start	= AT91CAP9_BASE_US2,
++		.end	= AT91CAP9_BASE_US2 + SZ_16K - 1,
++		.flags	= IORESOURCE_MEM,
++	},
++	[1] = {
++		.start	= AT91CAP9_ID_US2,
++		.end	= AT91CAP9_ID_US2,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct atmel_uart_data uart2_data = {
++	.use_dma_tx	= 1,
++	.use_dma_rx	= 1,
++};
++
++static u64 uart2_dmamask = DMA_BIT_MASK(32);
++
++static struct platform_device at91cap9_uart2_device = {
++	.name		= "atmel_usart",
++	.id		= 3,
++	.dev		= {
++				.dma_mask		= &uart2_dmamask,
++				.coherent_dma_mask	= DMA_BIT_MASK(32),
++				.platform_data		= &uart2_data,
++	},
++	.resource	= uart2_resources,
++	.num_resources	= ARRAY_SIZE(uart2_resources),
++};
++
++static inline void configure_usart2_pins(unsigned pins)
++{
++	at91_set_A_periph(AT91_PIN_PD2, 1);		/* TXD2 */
++	at91_set_A_periph(AT91_PIN_PD3, 0);		/* RXD2 */
++
++	if (pins & ATMEL_UART_RTS)
++		at91_set_B_periph(AT91_PIN_PD5, 0);	/* RTS2 */
++	if (pins & ATMEL_UART_CTS)
++		at91_set_B_periph(AT91_PIN_PD6, 0);	/* CTS2 */
++}
++
++static struct platform_device *at91_uarts[ATMEL_MAX_UART];	/* the UARTs to use */
++struct platform_device *atmel_default_console_device;	/* the serial console device */
++
++void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins)
++{
++	struct platform_device *pdev;
++
++	switch (id) {
++		case 0:		/* DBGU */
++			pdev = &at91cap9_dbgu_device;
++			configure_dbgu_pins();
++			at91_clock_associate("mck", &pdev->dev, "usart");
++			break;
++		case AT91CAP9_ID_US0:
++			pdev = &at91cap9_uart0_device;
++			configure_usart0_pins(pins);
++			at91_clock_associate("usart0_clk", &pdev->dev, "usart");
++			break;
++		case AT91CAP9_ID_US1:
++			pdev = &at91cap9_uart1_device;
++			configure_usart1_pins(pins);
++			at91_clock_associate("usart1_clk", &pdev->dev, "usart");
++			break;
++		case AT91CAP9_ID_US2:
++			pdev = &at91cap9_uart2_device;
++			configure_usart2_pins(pins);
++			at91_clock_associate("usart2_clk", &pdev->dev, "usart");
++			break;
++		default:
++			return;
++	}
++	pdev->id = portnr;		/* update to mapped ID */
++
++	if (portnr < ATMEL_MAX_UART)
++		at91_uarts[portnr] = pdev;
++}
++
++void __init at91_set_serial_console(unsigned portnr)
++{
++	if (portnr < ATMEL_MAX_UART)
++		atmel_default_console_device = at91_uarts[portnr];
++	if (!atmel_default_console_device)
++		printk(KERN_INFO "AT91: No default serial console defined.\n");
++}
++
++void __init at91_add_device_serial(void)
++{
++	int i;
++
++	for (i = 0; i < ATMEL_MAX_UART; i++) {
++		if (at91_uarts[i])
++			platform_device_register(at91_uarts[i]);
++	}
++}
++#else
++void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins) {}
++void __init at91_set_serial_console(unsigned portnr) {}
++void __init at91_add_device_serial(void) {}
++#endif
++
++
++/* -------------------------------------------------------------------- */
++/*
++ * These devices are always present and don't need any board-specific
++ * setup.
++ */
++static int __init at91_add_standard_devices(void)
++{
++	at91_add_device_rtt();
++	at91_add_device_watchdog();
++	return 0;
++}
++
++arch_initcall(at91_add_standard_devices);
+diff --git a/arch/arm/mach-at91/at91rm9200.c b/arch/arm/mach-at91/at91rm9200.c
+index 2cad2bf..d688c1d 100644
+--- a/arch/arm/mach-at91/at91rm9200.c
++++ b/arch/arm/mach-at91/at91rm9200.c
+@@ -301,28 +301,28 @@ void __init at91rm9200_initialize(unsigned long main_clock, unsigned short banks
+ static unsigned int at91rm9200_default_irq_priority[NR_AIC_IRQS] __initdata = {
+ 	7,	/* Advanced Interrupt Controller (FIQ) */
+ 	7,	/* System Peripherals */
+-	0,	/* Parallel IO Controller A */
+-	0,	/* Parallel IO Controller B */
+-	0,	/* Parallel IO Controller C */
+-	0,	/* Parallel IO Controller D */
+-	6,	/* USART 0 */
+-	6,	/* USART 1 */
+-	6,	/* USART 2 */
+-	6,	/* USART 3 */
++	1,	/* Parallel IO Controller A */
++	1,	/* Parallel IO Controller B */
++	1,	/* Parallel IO Controller C */
++	1,	/* Parallel IO Controller D */
++	5,	/* USART 0 */
++	5,	/* USART 1 */
++	5,	/* USART 2 */
++	5,	/* USART 3 */
+ 	0,	/* Multimedia Card Interface */
+-	4,	/* USB Device Port */
+-	0,	/* Two-Wire Interface */
+-	6,	/* Serial Peripheral Interface */
+-	5,	/* Serial Synchronous Controller 0 */
+-	5,	/* Serial Synchronous Controller 1 */
+-	5,	/* Serial Synchronous Controller 2 */
++	2,	/* USB Device Port */
++	6,	/* Two-Wire Interface */
++	5,	/* Serial Peripheral Interface */
++	4,	/* Serial Synchronous Controller 0 */
++	4,	/* Serial Synchronous Controller 1 */
++	4,	/* Serial Synchronous Controller 2 */
+ 	0,	/* Timer Counter 0 */
+ 	0,	/* Timer Counter 1 */
+ 	0,	/* Timer Counter 2 */
+ 	0,	/* Timer Counter 3 */
+ 	0,	/* Timer Counter 4 */
+ 	0,	/* Timer Counter 5 */
+-	3,	/* USB Host port */
++	2,	/* USB Host port */
+ 	3,	/* Ethernet MAC */
+ 	0,	/* Advanced Interrupt Controller (IRQ0) */
+ 	0,	/* Advanced Interrupt Controller (IRQ1) */
+diff --git a/arch/arm/mach-at91/at91rm9200_devices.c b/arch/arm/mach-at91/at91rm9200_devices.c
+index 9296833..ef6aeb8 100644
+--- a/arch/arm/mach-at91/at91rm9200_devices.c
++++ b/arch/arm/mach-at91/at91rm9200_devices.c
+@@ -13,6 +13,7 @@
+ #include <asm/mach/arch.h>
+ #include <asm/mach/map.h>
  
- config BF52x
- 	bool
--	depends on (BF522 || BF525 || BF527)
-+	depends on (BF522 || BF523 || BF524 || BF525 || BF526 || BF527)
- 	default y
++#include <linux/dma-mapping.h>
+ #include <linux/platform_device.h>
+ #include <linux/i2c-gpio.h>
  
- config BF53x
-@@ -253,11 +268,6 @@ config MEM_MT48LC32M16A2TG_75
- 	depends on (BFIN527_EZKIT)
- 	default y
+@@ -29,7 +30,7 @@
+  * -------------------------------------------------------------------- */
  
--config BFIN_SHARED_FLASH_ENET
--	bool
--	depends on (BFIN533_STAMP)
--	default y
--
- source "arch/blackfin/mach-bf527/Kconfig"
- source "arch/blackfin/mach-bf533/Kconfig"
- source "arch/blackfin/mach-bf561/Kconfig"
-@@ -317,7 +327,7 @@ config VCO_MULT
- 	range 1 64
- 	default "22" if BFIN533_EZKIT
- 	default "45" if BFIN533_STAMP
--	default "20" if (BFIN537_STAMP || BFIN527_EZKIT)
-+	default "20" if (BFIN537_STAMP || BFIN527_EZKIT || BFIN548_EZKIT)
- 	default "22" if BFIN533_BLUETECHNIX_CM
- 	default "20" if BFIN537_BLUETECHNIX_CM
- 	default "20" if BFIN561_BLUETECHNIX_CM
-@@ -354,7 +364,7 @@ config SCLK_DIV
- 	range 1 15
- 	default 5 if BFIN533_EZKIT
- 	default 5 if BFIN533_STAMP
--	default 4 if (BFIN537_STAMP || BFIN527_EZKIT)
-+	default 4 if (BFIN537_STAMP || BFIN527_EZKIT || BFIN548_EZKIT)
- 	default 5 if BFIN533_BLUETECHNIX_CM
- 	default 4 if BFIN537_BLUETECHNIX_CM
- 	default 4 if BFIN561_BLUETECHNIX_CM
-@@ -371,7 +381,10 @@ config SCLK_DIV
- config MAX_VCO_HZ
- 	int
- 	default 600000000 if BF522
-+	default 400000000 if BF523
-+	default 400000000 if BF524
- 	default 600000000 if BF525
-+	default 400000000 if BF526
- 	default 600000000 if BF527
- 	default 400000000 if BF531
- 	default 400000000 if BF532
-@@ -383,6 +396,8 @@ config MAX_VCO_HZ
- 	default 533333333 if BF539
- 	default 600000000 if BF542
- 	default 533333333 if BF544
-+	default 600000000 if BF547
-+	default 600000000 if BF548
- 	default 533333333 if BF549
- 	default 600000000 if BF561
+ #if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
+-static u64 ohci_dmamask = 0xffffffffUL;
++static u64 ohci_dmamask = DMA_BIT_MASK(32);
+ static struct at91_usbh_data usbh_data;
+ 
+ static struct resource usbh_resources[] = {
+@@ -50,7 +51,7 @@ static struct platform_device at91rm9200_usbh_device = {
+ 	.id		= -1,
+ 	.dev		= {
+ 				.dma_mask		= &ohci_dmamask,
+-				.coherent_dma_mask	= 0xffffffff,
++				.coherent_dma_mask	= DMA_BIT_MASK(32),
+ 				.platform_data		= &usbh_data,
+ 	},
+ 	.resource	= usbh_resources,
+@@ -125,7 +126,7 @@ void __init at91_add_device_udc(struct at91_udc_data *data) {}
+  * -------------------------------------------------------------------- */
+ 
+ #if defined(CONFIG_ARM_AT91_ETHER) || defined(CONFIG_ARM_AT91_ETHER_MODULE)
+-static u64 eth_dmamask = 0xffffffffUL;
++static u64 eth_dmamask = DMA_BIT_MASK(32);
+ static struct at91_eth_data eth_data;
+ 
+ static struct resource eth_resources[] = {
+@@ -146,7 +147,7 @@ static struct platform_device at91rm9200_eth_device = {
+ 	.id		= -1,
+ 	.dev		= {
+ 				.dma_mask		= &eth_dmamask,
+-				.coherent_dma_mask	= 0xffffffff,
++				.coherent_dma_mask	= DMA_BIT_MASK(32),
+ 				.platform_data		= &eth_data,
+ 	},
+ 	.resource	= eth_resources,
+@@ -285,7 +286,7 @@ void __init at91_add_device_cf(struct at91_cf_data *data) {}
+  * -------------------------------------------------------------------- */
+ 
+ #if defined(CONFIG_MMC_AT91) || defined(CONFIG_MMC_AT91_MODULE)
+-static u64 mmc_dmamask = 0xffffffffUL;
++static u64 mmc_dmamask = DMA_BIT_MASK(32);
+ static struct at91_mmc_data mmc_data;
+ 
+ static struct resource mmc_resources[] = {
+@@ -306,7 +307,7 @@ static struct platform_device at91rm9200_mmc_device = {
+ 	.id		= -1,
+ 	.dev		= {
+ 				.dma_mask		= &mmc_dmamask,
+-				.coherent_dma_mask	= 0xffffffff,
++				.coherent_dma_mask	= DMA_BIT_MASK(32),
+ 				.platform_data		= &mmc_data,
+ 	},
+ 	.resource	= mmc_resources,
+@@ -375,7 +376,7 @@ static struct at91_nand_data nand_data;
+ static struct resource nand_resources[] = {
+ 	{
+ 		.start	= NAND_BASE,
+-		.end	= NAND_BASE + SZ_8M - 1,
++		.end	= NAND_BASE + SZ_256M - 1,
+ 		.flags	= IORESOURCE_MEM,
+ 	}
+ };
+@@ -513,7 +514,7 @@ void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices)
+  * -------------------------------------------------------------------- */
  
-@@ -409,6 +424,7 @@ config MEM_SIZE
- 	default  32 if BFIN533_EZKIT
- 	default  64 if BFIN527_EZKIT
- 	default  64 if BFIN537_STAMP
-+	default  64 if BFIN548_EZKIT
- 	default  64 if BFIN561_EZKIT
- 	default 128 if BFIN533_STAMP
- 	default  64 if PNAV10
-@@ -416,6 +432,7 @@ config MEM_SIZE
+ #if defined(CONFIG_SPI_ATMEL) || defined(CONFIG_SPI_ATMEL_MODULE)
+-static u64 spi_dmamask = 0xffffffffUL;
++static u64 spi_dmamask = DMA_BIT_MASK(32);
  
- config MEM_ADD_WIDTH
- 	int "SDRAM Memory Address Width"
-+	depends on (!BF54x)
- 	default  9 if BFIN533_EZKIT
- 	default  9 if BFIN561_EZKIT
- 	default  9 if H8606_HVSISTEMAS
-@@ -424,6 +441,19 @@ config MEM_ADD_WIDTH
- 	default 11 if BFIN533_STAMP
- 	default 10 if PNAV10
+ static struct resource spi_resources[] = {
+ 	[0] = {
+@@ -533,7 +534,7 @@ static struct platform_device at91rm9200_spi_device = {
+ 	.id		= 0,
+ 	.dev		= {
+ 				.dma_mask		= &spi_dmamask,
+-				.coherent_dma_mask	= 0xffffffff,
++				.coherent_dma_mask	= DMA_BIT_MASK(32),
+ 	},
+ 	.resource	= spi_resources,
+ 	.num_resources	= ARRAY_SIZE(spi_resources),
+@@ -557,8 +558,11 @@ void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices)
+ 		else
+ 			cs_pin = spi_standard_cs[devices[i].chip_select];
  
+-		/* enable chip-select pin */
+-		at91_set_gpio_output(cs_pin, 1);
++		if (devices[i].chip_select == 0)	/* for CS0 errata */
++			at91_set_A_periph(cs_pin, 0);
++		else
++			at91_set_gpio_output(cs_pin, 1);
 +
-+choice
-+	prompt "DDR SDRAM Chip Type"
-+	depends on BFIN548_EZKIT
-+	default MEM_MT46V32M16_5B
+ 
+ 		/* pass chip-select pin to driver */
+ 		devices[i].controller_data = (void *) cs_pin;
+@@ -613,24 +617,175 @@ static void __init at91_add_device_watchdog(void) {}
+ 
+ 
+ /* --------------------------------------------------------------------
+- *  LEDs
++ *  SSC -- Synchronous Serial Controller
+  * -------------------------------------------------------------------- */
+ 
+-#if defined(CONFIG_LEDS)
+-u8 at91_leds_cpu;
+-u8 at91_leds_timer;
++#if defined(CONFIG_ATMEL_SSC) || defined(CONFIG_ATMEL_SSC_MODULE)
++static u64 ssc0_dmamask = DMA_BIT_MASK(32);
 +
-+config MEM_MT46V32M16_6T
-+        bool "MT46V32M16_6T"
++static struct resource ssc0_resources[] = {
++	[0] = {
++		.start	= AT91RM9200_BASE_SSC0,
++		.end	= AT91RM9200_BASE_SSC0 + SZ_16K - 1,
++		.flags	= IORESOURCE_MEM,
++	},
++	[1] = {
++		.start	= AT91RM9200_ID_SSC0,
++		.end	= AT91RM9200_ID_SSC0,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
 +
-+config MEM_MT46V32M16_5B
-+        bool "MT46V32M16_5B"
-+endchoice
++static struct platform_device at91rm9200_ssc0_device = {
++	.name	= "ssc",
++	.id	= 0,
++	.dev	= {
++		.dma_mask		= &ssc0_dmamask,
++		.coherent_dma_mask	= DMA_BIT_MASK(32),
++	},
++	.resource	= ssc0_resources,
++	.num_resources	= ARRAY_SIZE(ssc0_resources),
++};
 +
- config ENET_FLASH_PIN
- 	int "PF port/pin used for flash and ethernet sharing"
- 	depends on (BFIN533_STAMP)
-@@ -448,40 +478,6 @@ config BOOT_LOAD
- 	  memory region is used to capture NULL pointer references as well
- 	  as some core kernel functions.
++static inline void configure_ssc0_pins(unsigned pins)
++{
++	if (pins & ATMEL_SSC_TF)
++		at91_set_A_periph(AT91_PIN_PB0, 1);
++	if (pins & ATMEL_SSC_TK)
++		at91_set_A_periph(AT91_PIN_PB1, 1);
++	if (pins & ATMEL_SSC_TD)
++		at91_set_A_periph(AT91_PIN_PB2, 1);
++	if (pins & ATMEL_SSC_RD)
++		at91_set_A_periph(AT91_PIN_PB3, 1);
++	if (pins & ATMEL_SSC_RK)
++		at91_set_A_periph(AT91_PIN_PB4, 1);
++	if (pins & ATMEL_SSC_RF)
++		at91_set_A_periph(AT91_PIN_PB5, 1);
++}
++
++static u64 ssc1_dmamask = DMA_BIT_MASK(32);
++
++static struct resource ssc1_resources[] = {
++	[0] = {
++		.start	= AT91RM9200_BASE_SSC1,
++		.end	= AT91RM9200_BASE_SSC1 + SZ_16K - 1,
++		.flags	= IORESOURCE_MEM,
++	},
++	[1] = {
++		.start	= AT91RM9200_ID_SSC1,
++		.end	= AT91RM9200_ID_SSC1,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device at91rm9200_ssc1_device = {
++	.name	= "ssc",
++	.id	= 1,
++	.dev	= {
++		.dma_mask		= &ssc1_dmamask,
++		.coherent_dma_mask	= DMA_BIT_MASK(32),
++	},
++	.resource	= ssc1_resources,
++	.num_resources	= ARRAY_SIZE(ssc1_resources),
++};
++
++static inline void configure_ssc1_pins(unsigned pins)
++{
++	if (pins & ATMEL_SSC_TF)
++		at91_set_A_periph(AT91_PIN_PB6, 1);
++	if (pins & ATMEL_SSC_TK)
++		at91_set_A_periph(AT91_PIN_PB7, 1);
++	if (pins & ATMEL_SSC_TD)
++		at91_set_A_periph(AT91_PIN_PB8, 1);
++	if (pins & ATMEL_SSC_RD)
++		at91_set_A_periph(AT91_PIN_PB9, 1);
++	if (pins & ATMEL_SSC_RK)
++		at91_set_A_periph(AT91_PIN_PB10, 1);
++	if (pins & ATMEL_SSC_RF)
++		at91_set_A_periph(AT91_PIN_PB11, 1);
++}
++
++static u64 ssc2_dmamask = DMA_BIT_MASK(32);
++
++static struct resource ssc2_resources[] = {
++	[0] = {
++		.start	= AT91RM9200_BASE_SSC2,
++		.end	= AT91RM9200_BASE_SSC2 + SZ_16K - 1,
++		.flags	= IORESOURCE_MEM,
++	},
++	[1] = {
++		.start	= AT91RM9200_ID_SSC2,
++		.end	= AT91RM9200_ID_SSC2,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device at91rm9200_ssc2_device = {
++	.name	= "ssc",
++	.id	= 2,
++	.dev	= {
++		.dma_mask		= &ssc2_dmamask,
++		.coherent_dma_mask	= DMA_BIT_MASK(32),
++	},
++	.resource	= ssc2_resources,
++	.num_resources	= ARRAY_SIZE(ssc2_resources),
++};
++
++static inline void configure_ssc2_pins(unsigned pins)
++{
++	if (pins & ATMEL_SSC_TF)
++		at91_set_A_periph(AT91_PIN_PB12, 1);
++	if (pins & ATMEL_SSC_TK)
++		at91_set_A_periph(AT91_PIN_PB13, 1);
++	if (pins & ATMEL_SSC_TD)
++		at91_set_A_periph(AT91_PIN_PB14, 1);
++	if (pins & ATMEL_SSC_RD)
++		at91_set_A_periph(AT91_PIN_PB15, 1);
++	if (pins & ATMEL_SSC_RK)
++		at91_set_A_periph(AT91_PIN_PB16, 1);
++	if (pins & ATMEL_SSC_RF)
++		at91_set_A_periph(AT91_PIN_PB17, 1);
++}
+ 
+-void __init at91_init_leds(u8 cpu_led, u8 timer_led)
++/*
++ * SSC controllers are accessed through library code, instead of any
++ * kind of all-singing/all-dancing driver.  For example one could be
++ * used by a particular I2S audio codec's driver, while another one
++ * on the same system might be used by a custom data capture driver.
++ */
++void __init at91_add_device_ssc(unsigned id, unsigned pins)
+ {
+-	/* Enable GPIO to access the LEDs */
+-	at91_set_gpio_output(cpu_led, 1);
+-	at91_set_gpio_output(timer_led, 1);
++	struct platform_device *pdev;
  
--comment "LED Status Indicators"
--	depends on (BFIN533_STAMP || BFIN533_BLUETECHNIX_CM)
--
--config BFIN_ALIVE_LED
--	bool "Enable Board Alive"
--	depends on (BFIN533_STAMP || BFIN533_BLUETECHNIX_CM)
--	default n
--	help
--	  Blink the LEDs you select when the kernel is running.  Helps detect
--	  a hung kernel.
--
--config BFIN_ALIVE_LED_NUM
--	int "LED"
--	depends on BFIN_ALIVE_LED
--	range 1 3 if BFIN533_STAMP
--	default "3" if BFIN533_STAMP
--	help
--	  Select the LED (marked on the board) for you to blink.
--
--config BFIN_IDLE_LED
--	bool "Enable System Load/Idle LED"
--	depends on (BFIN533_STAMP || BFIN533_BLUETECHNIX_CM)
--	default n
--	help
--	  Blinks the LED you select when to determine kernel load.
--
--config BFIN_IDLE_LED_NUM
--	int "LED"
--	depends on BFIN_IDLE_LED
--	range 1 3 if BFIN533_STAMP
--	default "2" if BFIN533_STAMP
--	help
--	  Select the LED (marked on the board) for you to blink.
--
- choice
- 	prompt "Blackfin Exception Scratch Register"
- 	default BFIN_SCRATCH_REG_RETN
-@@ -528,41 +524,6 @@ config BFIN_SCRATCH_REG_CYCLES
+-	at91_leds_cpu	= cpu_led;
+-	at91_leds_timer	= timer_led;
++	/*
++	 * NOTE: caller is responsible for passing information matching
++	 * "pins" to whatever will be using each particular controller.
++	 */
++	switch (id) {
++	case AT91RM9200_ID_SSC0:
++		pdev = &at91rm9200_ssc0_device;
++		configure_ssc0_pins(pins);
++		at91_clock_associate("ssc0_clk", &pdev->dev, "ssc");
++		break;
++	case AT91RM9200_ID_SSC1:
++		pdev = &at91rm9200_ssc1_device;
++		configure_ssc1_pins(pins);
++		at91_clock_associate("ssc1_clk", &pdev->dev, "ssc");
++		break;
++	case AT91RM9200_ID_SSC2:
++		pdev = &at91rm9200_ssc2_device;
++		configure_ssc2_pins(pins);
++		at91_clock_associate("ssc2_clk", &pdev->dev, "ssc");
++		break;
++	default:
++		return;
++	}
++
++	platform_device_register(pdev);
+ }
++
+ #else
+-void __init at91_init_leds(u8 cpu_led, u8 timer_led) {}
++void __init at91_add_device_ssc(unsigned id, unsigned pins) {}
+ #endif
  
- endchoice
  
--#
--# Sorry - but you need to put the hex address here -
--#
--
--# Flag Data register
--config BFIN_ALIVE_LED_PORT
--	hex
--	default 0xFFC00700 if (BFIN533_STAMP)
--
--# Peripheral Flag Direction Register
--config BFIN_ALIVE_LED_DPORT
--	hex
--	default 0xFFC00730 if (BFIN533_STAMP)
--
--config BFIN_ALIVE_LED_PIN
--	hex
--	default 0x04 if (BFIN533_STAMP && BFIN_ALIVE_LED_NUM = 1)
--	default 0x08 if (BFIN533_STAMP && BFIN_ALIVE_LED_NUM = 2)
--	default 0x10 if (BFIN533_STAMP && BFIN_ALIVE_LED_NUM = 3)
--
--config BFIN_IDLE_LED_PORT
--	hex
--	default 0xFFC00700 if (BFIN533_STAMP)
--
--# Peripheral Flag Direction Register
--config BFIN_IDLE_LED_DPORT
--	hex
--	default 0xFFC00730 if (BFIN533_STAMP)
--
--config BFIN_IDLE_LED_PIN
--	hex
--	default 0x04 if (BFIN533_STAMP && BFIN_IDLE_LED_NUM = 1)
--	default 0x08 if (BFIN533_STAMP && BFIN_IDLE_LED_NUM = 2)
--	default 0x10 if (BFIN533_STAMP && BFIN_IDLE_LED_NUM = 3)
--
- endmenu
+@@ -658,12 +813,15 @@ static struct atmel_uart_data dbgu_data = {
+ 	.regs		= (void __iomem *)(AT91_VA_BASE_SYS + AT91_DBGU),
+ };
  
++static u64 dbgu_dmamask = DMA_BIT_MASK(32);
++
+ static struct platform_device at91rm9200_dbgu_device = {
+ 	.name		= "atmel_usart",
+ 	.id		= 0,
+ 	.dev		= {
+-				.platform_data	= &dbgu_data,
+-				.coherent_dma_mask = 0xffffffff,
++				.dma_mask		= &dbgu_dmamask,
++				.coherent_dma_mask	= DMA_BIT_MASK(32),
++				.platform_data		= &dbgu_data,
+ 	},
+ 	.resource	= dbgu_resources,
+ 	.num_resources	= ARRAY_SIZE(dbgu_resources),
+@@ -693,28 +851,35 @@ static struct atmel_uart_data uart0_data = {
+ 	.use_dma_rx	= 1,
+ };
+ 
++static u64 uart0_dmamask = DMA_BIT_MASK(32);
++
+ static struct platform_device at91rm9200_uart0_device = {
+ 	.name		= "atmel_usart",
+ 	.id		= 1,
+ 	.dev		= {
+-				.platform_data	= &uart0_data,
+-				.coherent_dma_mask = 0xffffffff,
++				.dma_mask		= &uart0_dmamask,
++				.coherent_dma_mask	= DMA_BIT_MASK(32),
++				.platform_data		= &uart0_data,
+ 	},
+ 	.resource	= uart0_resources,
+ 	.num_resources	= ARRAY_SIZE(uart0_resources),
+ };
  
-@@ -799,6 +760,15 @@ config L1_MAX_PIECE
- 	  Set the max memory pieces for the L1 SRAM allocation algorithm.
- 	  Min value is 16. Max value is 1024.
+-static inline void configure_usart0_pins(void)
++static inline void configure_usart0_pins(unsigned pins)
+ {
+ 	at91_set_A_periph(AT91_PIN_PA17, 1);		/* TXD0 */
+ 	at91_set_A_periph(AT91_PIN_PA18, 0);		/* RXD0 */
+-	at91_set_A_periph(AT91_PIN_PA20, 0);		/* CTS0 */
  
+-	/*
+-	 * AT91RM9200 Errata #39 - RTS0 is not internally connected to PA21.
+-	 *  We need to drive the pin manually.  Default is off (RTS is active low).
+-	 */
+-	at91_set_gpio_output(AT91_PIN_PA21, 1);
++	if (pins & ATMEL_UART_CTS)
++		at91_set_A_periph(AT91_PIN_PA20, 0);	/* CTS0 */
 +
-+config MPU
-+	bool "Enable the memory protection unit (EXPERIMENTAL)"
-+	default n
-+	help
-+	  Use the processor's MPU to protect applications from accessing
-+	  memory they do not own.  This comes at a performance penalty
-+	  and is recommended only for debugging.
-+
- comment "Asynchonous Memory Configuration"
++	if (pins & ATMEL_UART_RTS) {
++		/*
++		 * AT91RM9200 Errata #39 - RTS0 is not internally connected to PA21.
++		 *  We need to drive the pin manually.  Default is off (RTS is active low).
++		 */
++		at91_set_gpio_output(AT91_PIN_PA21, 1);
++	}
+ }
  
- menu "EBIU_AMGCTL Global Control"
-@@ -808,7 +778,6 @@ config C_AMCKEN
+ static struct resource uart1_resources[] = {
+@@ -735,27 +900,37 @@ static struct atmel_uart_data uart1_data = {
+ 	.use_dma_rx	= 1,
+ };
  
- config C_CDPRIO
- 	bool "DMA has priority over core for ext. accesses"
--	depends on !BF54x
- 	default n
++static u64 uart1_dmamask = DMA_BIT_MASK(32);
++
+ static struct platform_device at91rm9200_uart1_device = {
+ 	.name		= "atmel_usart",
+ 	.id		= 2,
+ 	.dev		= {
+-				.platform_data	= &uart1_data,
+-				.coherent_dma_mask = 0xffffffff,
++				.dma_mask		= &uart1_dmamask,
++				.coherent_dma_mask	= DMA_BIT_MASK(32),
++				.platform_data		= &uart1_data,
+ 	},
+ 	.resource	= uart1_resources,
+ 	.num_resources	= ARRAY_SIZE(uart1_resources),
+ };
  
- config C_B0PEN
-@@ -949,8 +918,10 @@ endchoice
- config PM_WAKEUP_SIC_IWR
- 	hex "Wakeup Events (SIC_IWR)"
- 	depends on PM_WAKEUP_GPIO_BY_SIC_IWR
--	default 0x80000000 if (BF537 || BF536 || BF534)
--	default 0x100000 if (BF533 || BF532 || BF531)
-+	default 0x8 if (BF537 || BF536 || BF534)
-+	default 0x80 if (BF533 || BF532 || BF531)
-+	default 0x80 if (BF54x)
-+	default 0x80 if (BF52x)
+-static inline void configure_usart1_pins(void)
++static inline void configure_usart1_pins(unsigned pins)
+ {
+-	at91_set_A_periph(AT91_PIN_PB18, 0);		/* RI1 */
+-	at91_set_A_periph(AT91_PIN_PB19, 0);		/* DTR1 */
+ 	at91_set_A_periph(AT91_PIN_PB20, 1);		/* TXD1 */
+ 	at91_set_A_periph(AT91_PIN_PB21, 0);		/* RXD1 */
+-	at91_set_A_periph(AT91_PIN_PB23, 0);		/* DCD1 */
+-	at91_set_A_periph(AT91_PIN_PB24, 0);		/* CTS1 */
+-	at91_set_A_periph(AT91_PIN_PB25, 0);		/* DSR1 */
+-	at91_set_A_periph(AT91_PIN_PB26, 0);		/* RTS1 */
++
++	if (pins & ATMEL_UART_RI)
++		at91_set_A_periph(AT91_PIN_PB18, 0);	/* RI1 */
++	if (pins & ATMEL_UART_DTR)
++		at91_set_A_periph(AT91_PIN_PB19, 0);	/* DTR1 */
++	if (pins & ATMEL_UART_DCD)
++		at91_set_A_periph(AT91_PIN_PB23, 0);	/* DCD1 */
++	if (pins & ATMEL_UART_CTS)
++		at91_set_A_periph(AT91_PIN_PB24, 0);	/* CTS1 */
++	if (pins & ATMEL_UART_DSR)
++		at91_set_A_periph(AT91_PIN_PB25, 0);	/* DSR1 */
++	if (pins & ATMEL_UART_RTS)
++		at91_set_A_periph(AT91_PIN_PB26, 0);	/* RTS1 */
+ }
+ 
+ static struct resource uart2_resources[] = {
+@@ -776,21 +951,29 @@ static struct atmel_uart_data uart2_data = {
+ 	.use_dma_rx	= 1,
+ };
+ 
++static u64 uart2_dmamask = DMA_BIT_MASK(32);
++
+ static struct platform_device at91rm9200_uart2_device = {
+ 	.name		= "atmel_usart",
+ 	.id		= 3,
+ 	.dev		= {
+-				.platform_data	= &uart2_data,
+-				.coherent_dma_mask = 0xffffffff,
++				.dma_mask		= &uart2_dmamask,
++				.coherent_dma_mask	= DMA_BIT_MASK(32),
++				.platform_data		= &uart2_data,
+ 	},
+ 	.resource	= uart2_resources,
+ 	.num_resources	= ARRAY_SIZE(uart2_resources),
+ };
  
- config PM_WAKEUP_GPIO_NUMBER
- 	int "Wakeup GPIO number"
-diff --git a/arch/blackfin/Makefile b/arch/blackfin/Makefile
-index c47e000..0edc402 100644
---- a/arch/blackfin/Makefile
-+++ b/arch/blackfin/Makefile
-@@ -21,7 +21,10 @@ KBUILD_DEFCONFIG := BF537-STAMP_defconfig
+-static inline void configure_usart2_pins(void)
++static inline void configure_usart2_pins(unsigned pins)
+ {
+ 	at91_set_A_periph(AT91_PIN_PA22, 0);		/* RXD2 */
+ 	at91_set_A_periph(AT91_PIN_PA23, 1);		/* TXD2 */
++
++	if (pins & ATMEL_UART_CTS)
++		at91_set_B_periph(AT91_PIN_PA30, 0);	/* CTS2 */
++	if (pins & ATMEL_UART_RTS)
++		at91_set_B_periph(AT91_PIN_PA31, 0);	/* RTS2 */
+ }
  
- # setup the machine name and the machine dependent settings
- machine-$(CONFIG_BF522) := bf527
-+machine-$(CONFIG_BF523) := bf527
-+machine-$(CONFIG_BF524) := bf527
- machine-$(CONFIG_BF525) := bf527
-+machine-$(CONFIG_BF526) := bf527
- machine-$(CONFIG_BF527) := bf527
- machine-$(CONFIG_BF531) := bf533
- machine-$(CONFIG_BF532) := bf533
-@@ -39,7 +42,10 @@ MACHINE := $(machine-y)
- export MACHINE
+ static struct resource uart3_resources[] = {
+@@ -811,27 +994,35 @@ static struct atmel_uart_data uart3_data = {
+ 	.use_dma_rx	= 1,
+ };
  
- cpu-$(CONFIG_BF522) := bf522
-+cpu-$(CONFIG_BF523) := bf523
-+cpu-$(CONFIG_BF524) := bf524
- cpu-$(CONFIG_BF525) := bf525
-+cpu-$(CONFIG_BF526) := bf526
- cpu-$(CONFIG_BF527) := bf527
- cpu-$(CONFIG_BF531) := bf531
- cpu-$(CONFIG_BF532) := bf532
-@@ -76,6 +82,12 @@ core-y   += arch/$(ARCH)/mach-$(MACHINE)/
- core-y   += arch/$(ARCH)/mach-$(MACHINE)/boards/
- endif
++static u64 uart3_dmamask = DMA_BIT_MASK(32);
++
+ static struct platform_device at91rm9200_uart3_device = {
+ 	.name		= "atmel_usart",
+ 	.id		= 4,
+ 	.dev		= {
+-				.platform_data	= &uart3_data,
+-				.coherent_dma_mask = 0xffffffff,
++				.dma_mask		= &uart3_dmamask,
++				.coherent_dma_mask	= DMA_BIT_MASK(32),
++				.platform_data		= &uart3_data,
+ 	},
+ 	.resource	= uart3_resources,
+ 	.num_resources	= ARRAY_SIZE(uart3_resources),
+ };
  
-+ifeq ($(CONFIG_MPU),y)
-+core-y	+= arch/$(ARCH)/kernel/cplb-mpu/
-+else
-+core-y	+= arch/$(ARCH)/kernel/cplb-nompu/
-+endif
+-static inline void configure_usart3_pins(void)
++static inline void configure_usart3_pins(unsigned pins)
+ {
+ 	at91_set_B_periph(AT91_PIN_PA5, 1);		/* TXD3 */
+ 	at91_set_B_periph(AT91_PIN_PA6, 0);		/* RXD3 */
 +
- libs-y   += arch/$(ARCH)/lib/
++	if (pins & ATMEL_UART_CTS)
++		at91_set_B_periph(AT91_PIN_PB1, 0);	/* CTS3 */
++	if (pins & ATMEL_UART_RTS)
++		at91_set_B_periph(AT91_PIN_PB0, 0);	/* RTS3 */
+ }
  
- drivers-$(CONFIG_OPROFILE) += arch/$(ARCH)/oprofile/
-diff --git a/arch/blackfin/configs/BF527-EZKIT_defconfig b/arch/blackfin/configs/BF527-EZKIT_defconfig
-index fa6eb4e..d59ee15 100644
---- a/arch/blackfin/configs/BF527-EZKIT_defconfig
-+++ b/arch/blackfin/configs/BF527-EZKIT_defconfig
-@@ -1,6 +1,7 @@
- #
- # Automatically generated make config: don't edit
--# Linux kernel version: 2.6.22.12
-+# Linux kernel version: 2.6.22.14
-+# Thu Nov 29 17:32:47 2007
- #
- # CONFIG_MMU is not set
- # CONFIG_FPU is not set
-@@ -153,8 +154,8 @@ CONFIG_BFIN527_EZKIT=y
- CONFIG_BF527_SPORT0_PORTG=y
- CONFIG_BF527_SPORT0_TSCLK_PG10=y
- # CONFIG_BF527_SPORT0_TSCLK_PG14 is not set
--# CONFIG_BF527_UART1_PORTF is not set
--CONFIG_BF527_UART1_PORTG=y
-+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
+-struct platform_device *at91_uarts[ATMEL_MAX_UART];	/* the UARTs to use */
++static struct platform_device *at91_uarts[ATMEL_MAX_UART];	/* the UARTs to use */
+ struct platform_device *atmel_default_console_device;	/* the serial console device */
  
-@@ -232,7 +233,7 @@ CONFIG_CLKIN_HZ=25000000
- # CONFIG_BFIN_KERNEL_CLOCK is not set
- CONFIG_MAX_VCO_HZ=600000000
- CONFIG_MIN_VCO_HZ=50000000
--CONFIG_MAX_SCLK_HZ=133000000
-+CONFIG_MAX_SCLK_HZ=133333333
- CONFIG_MIN_SCLK_HZ=27000000
+-void __init at91_init_serial(struct at91_uart_config *config)
++void __init __deprecated at91_init_serial(struct at91_uart_config *config)
+ {
+ 	int i;
  
- #
-@@ -626,8 +627,8 @@ CONFIG_BFIN_MAC_RMII=y
- # CONFIG_SMSC911X is not set
- # CONFIG_DM9000 is not set
- CONFIG_NETDEV_1000=y
--CONFIG_NETDEV_10000=y
- # CONFIG_AX88180 is not set
-+CONFIG_NETDEV_10000=y
+@@ -839,22 +1030,22 @@ void __init at91_init_serial(struct at91_uart_config *config)
+ 	for (i = 0; i < config->nr_tty; i++) {
+ 		switch (config->tty_map[i]) {
+ 			case 0:
+-				configure_usart0_pins();
++				configure_usart0_pins(ATMEL_UART_CTS | ATMEL_UART_RTS);
+ 				at91_uarts[i] = &at91rm9200_uart0_device;
+ 				at91_clock_associate("usart0_clk", &at91rm9200_uart0_device.dev, "usart");
+ 				break;
+ 			case 1:
+-				configure_usart1_pins();
++				configure_usart1_pins(ATMEL_UART_CTS | ATMEL_UART_RTS | ATMEL_UART_DSR | ATMEL_UART_DTR | ATMEL_UART_DCD | ATMEL_UART_RI);
+ 				at91_uarts[i] = &at91rm9200_uart1_device;
+ 				at91_clock_associate("usart1_clk", &at91rm9200_uart1_device.dev, "usart");
+ 				break;
+ 			case 2:
+-				configure_usart2_pins();
++				configure_usart2_pins(0);
+ 				at91_uarts[i] = &at91rm9200_uart2_device;
+ 				at91_clock_associate("usart2_clk", &at91rm9200_uart2_device.dev, "usart");
+ 				break;
+ 			case 3:
+-				configure_usart3_pins();
++				configure_usart3_pins(0);
+ 				at91_uarts[i] = &at91rm9200_uart3_device;
+ 				at91_clock_associate("usart3_clk", &at91rm9200_uart3_device.dev, "usart");
+ 				break;
+@@ -876,6 +1067,53 @@ void __init at91_init_serial(struct at91_uart_config *config)
+ 		printk(KERN_INFO "AT91: No default serial console defined.\n");
+ }
  
- #
- # Wireless LAN
-@@ -1183,7 +1184,7 @@ CONFIG_NLS_DEFAULT="iso8859-1"
- #
- # CONFIG_PRINTK_TIME is not set
- CONFIG_ENABLE_MUST_CHECK=y
--CONFIG_MAGIC_SYSRQ=y
-+# CONFIG_MAGIC_SYSRQ is not set
- # CONFIG_UNUSED_SYMBOLS is not set
- CONFIG_DEBUG_FS=y
- # CONFIG_HEADERS_CHECK is not set
-@@ -1208,7 +1209,7 @@ CONFIG_ACCESS_CHECK=y
- # CONFIG_KEYS is not set
- CONFIG_SECURITY=y
- # CONFIG_SECURITY_NETWORK is not set
--CONFIG_SECURITY_CAPABILITIES=y
-+CONFIG_SECURITY_CAPABILITIES=m
++void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins)
++{
++	struct platform_device *pdev;
++
++	switch (id) {
++		case 0:		/* DBGU */
++			pdev = &at91rm9200_dbgu_device;
++			configure_dbgu_pins();
++			at91_clock_associate("mck", &pdev->dev, "usart");
++			break;
++		case AT91RM9200_ID_US0:
++			pdev = &at91rm9200_uart0_device;
++			configure_usart0_pins(pins);
++			at91_clock_associate("usart0_clk", &pdev->dev, "usart");
++			break;
++		case AT91RM9200_ID_US1:
++			pdev = &at91rm9200_uart1_device;
++			configure_usart1_pins(pins);
++			at91_clock_associate("usart1_clk", &pdev->dev, "usart");
++			break;
++		case AT91RM9200_ID_US2:
++			pdev = &at91rm9200_uart2_device;
++			configure_usart2_pins(pins);
++			at91_clock_associate("usart2_clk", &pdev->dev, "usart");
++			break;
++		case AT91RM9200_ID_US3:
++			pdev = &at91rm9200_uart3_device;
++			configure_usart3_pins(pins);
++			at91_clock_associate("usart3_clk", &pdev->dev, "usart");
++			break;
++		default:
++			return;
++	}
++	pdev->id = portnr;		/* update to mapped ID */
++
++	if (portnr < ATMEL_MAX_UART)
++		at91_uarts[portnr] = pdev;
++}
++
++void __init at91_set_serial_console(unsigned portnr)
++{
++	if (portnr < ATMEL_MAX_UART)
++		atmel_default_console_device = at91_uarts[portnr];
++	if (!atmel_default_console_device)
++		printk(KERN_INFO "AT91: No default serial console defined.\n");
++}
++
+ void __init at91_add_device_serial(void)
+ {
+ 	int i;
+@@ -886,7 +1124,9 @@ void __init at91_add_device_serial(void)
+ 	}
+ }
+ #else
+-void __init at91_init_serial(struct at91_uart_config *config) {}
++void __init __deprecated at91_init_serial(struct at91_uart_config *config) {}
++void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins) {}
++void __init at91_set_serial_console(unsigned portnr) {}
+ void __init at91_add_device_serial(void) {}
+ #endif
  
- #
- # Cryptographic options
-@@ -1219,7 +1220,7 @@ CONFIG_SECURITY_CAPABILITIES=y
- # Library routines
- #
- CONFIG_BITREVERSE=y
--# CONFIG_CRC_CCITT is not set
-+CONFIG_CRC_CCITT=m
- # CONFIG_CRC16 is not set
- # CONFIG_CRC_ITU_T is not set
- CONFIG_CRC32=y
-diff --git a/arch/blackfin/configs/BF533-EZKIT_defconfig b/arch/blackfin/configs/BF533-EZKIT_defconfig
-index 4fdb493..811711f 100644
---- a/arch/blackfin/configs/BF533-EZKIT_defconfig
-+++ b/arch/blackfin/configs/BF533-EZKIT_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.16
- #
- # CONFIG_MMU is not set
- # CONFIG_FPU is not set
-@@ -115,7 +115,10 @@ CONFIG_PREEMPT_VOLUNTARY=y
- # 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 is not set
- # CONFIG_BF527 is not set
- # CONFIG_BF531 is not set
- # CONFIG_BF532 is not set
-@@ -194,7 +197,7 @@ CONFIG_CLKIN_HZ=27000000
- # CONFIG_BFIN_KERNEL_CLOCK is not set
- CONFIG_MAX_VCO_HZ=750000000
- CONFIG_MIN_VCO_HZ=50000000
--CONFIG_MAX_SCLK_HZ=133000000
-+CONFIG_MAX_SCLK_HZ=133333333
- CONFIG_MIN_SCLK_HZ=27000000
+diff --git a/arch/arm/mach-at91/at91sam9260.c b/arch/arm/mach-at91/at91sam9260.c
+index e47381e..18d0661 100644
+--- a/arch/arm/mach-at91/at91sam9260.c
++++ b/arch/arm/mach-at91/at91sam9260.c
+@@ -327,30 +327,30 @@ void __init at91sam9260_initialize(unsigned long main_clock)
+ static unsigned int at91sam9260_default_irq_priority[NR_AIC_IRQS] __initdata = {
+ 	7,	/* Advanced Interrupt Controller */
+ 	7,	/* System Peripherals */
+-	0,	/* Parallel IO Controller A */
+-	0,	/* Parallel IO Controller B */
+-	0,	/* Parallel IO Controller C */
++	1,	/* Parallel IO Controller A */
++	1,	/* Parallel IO Controller B */
++	1,	/* Parallel IO Controller C */
+ 	0,	/* Analog-to-Digital Converter */
+-	6,	/* USART 0 */
+-	6,	/* USART 1 */
+-	6,	/* USART 2 */
++	5,	/* USART 0 */
++	5,	/* USART 1 */
++	5,	/* USART 2 */
+ 	0,	/* Multimedia Card Interface */
+-	4,	/* USB Device Port */
+-	0,	/* Two-Wire Interface */
+-	6,	/* Serial Peripheral Interface 0 */
+-	6,	/* Serial Peripheral Interface 1 */
++	2,	/* USB Device Port */
++	6,	/* Two-Wire Interface */
++	5,	/* Serial Peripheral Interface 0 */
++	5,	/* Serial Peripheral Interface 1 */
+ 	5,	/* Serial Synchronous Controller */
+ 	0,
+ 	0,
+ 	0,	/* Timer Counter 0 */
+ 	0,	/* Timer Counter 1 */
+ 	0,	/* Timer Counter 2 */
+-	3,	/* USB Host port */
++	2,	/* USB Host port */
+ 	3,	/* Ethernet */
+ 	0,	/* Image Sensor Interface */
+-	6,	/* USART 3 */
+-	6,	/* USART 4 */
+-	6,	/* USART 5 */
++	5,	/* USART 3 */
++	5,	/* USART 4 */
++	5,	/* USART 5 */
+ 	0,	/* Timer Counter 3 */
+ 	0,	/* Timer Counter 4 */
+ 	0,	/* Timer Counter 5 */
+diff --git a/arch/arm/mach-at91/at91sam9260_devices.c b/arch/arm/mach-at91/at91sam9260_devices.c
+index 3091bf4..105f840 100644
+--- a/arch/arm/mach-at91/at91sam9260_devices.c
++++ b/arch/arm/mach-at91/at91sam9260_devices.c
+@@ -12,6 +12,7 @@
+ #include <asm/mach/arch.h>
+ #include <asm/mach/map.h>
  
- #
-@@ -267,6 +270,7 @@ CONFIG_BFIN_DCACHE=y
- # CONFIG_BFIN_WB is not set
- CONFIG_BFIN_WT=y
- CONFIG_L1_MAX_PIECE=16
-+# CONFIG_MPU is not set
++#include <linux/dma-mapping.h>
+ #include <linux/platform_device.h>
+ #include <linux/i2c-gpio.h>
  
- #
- # Asynchonous Memory Configuration
-@@ -321,7 +325,7 @@ CONFIG_PM=y
- CONFIG_PM_WAKEUP_GPIO_BY_SIC_IWR=y
- # CONFIG_PM_WAKEUP_BY_GPIO is not set
- # CONFIG_PM_WAKEUP_GPIO_API is not set
--CONFIG_PM_WAKEUP_SIC_IWR=0x100000
-+CONFIG_PM_WAKEUP_SIC_IWR=0x80
+@@ -29,7 +30,7 @@
+  * -------------------------------------------------------------------- */
  
- #
- # CPU Frequency scaling
-@@ -510,7 +514,6 @@ CONFIG_MTD_CFI_I2=y
- # CONFIG_MTD_CFI_INTELEXT is not set
- # CONFIG_MTD_CFI_AMDSTD is not set
- # CONFIG_MTD_CFI_STAA is not set
--CONFIG_MTD_MW320D=m
- CONFIG_MTD_RAM=y
- CONFIG_MTD_ROM=m
- # CONFIG_MTD_ABSENT is not set
-@@ -520,9 +523,6 @@ CONFIG_MTD_ROM=m
- #
- CONFIG_MTD_COMPLEX_MAPPINGS=y
- # CONFIG_MTD_PHYSMAP is not set
--CONFIG_MTD_BF5xx=m
--CONFIG_BFIN_FLASH_SIZE=0x400000
--CONFIG_EBIU_FLASH_BASE=0x20000000
- # CONFIG_MTD_UCLINUX is not set
- # CONFIG_MTD_PLATRAM is not set
+ #if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
+-static u64 ohci_dmamask = 0xffffffffUL;
++static u64 ohci_dmamask = DMA_BIT_MASK(32);
+ static struct at91_usbh_data usbh_data;
+ 
+ static struct resource usbh_resources[] = {
+@@ -50,7 +51,7 @@ static struct platform_device at91_usbh_device = {
+ 	.id		= -1,
+ 	.dev		= {
+ 				.dma_mask		= &ohci_dmamask,
+-				.coherent_dma_mask	= 0xffffffff,
++				.coherent_dma_mask	= DMA_BIT_MASK(32),
+ 				.platform_data		= &usbh_data,
+ 	},
+ 	.resource	= usbh_resources,
+@@ -125,7 +126,7 @@ void __init at91_add_device_udc(struct at91_udc_data *data) {}
+  * -------------------------------------------------------------------- */
+ 
+ #if defined(CONFIG_MACB) || defined(CONFIG_MACB_MODULE)
+-static u64 eth_dmamask = 0xffffffffUL;
++static u64 eth_dmamask = DMA_BIT_MASK(32);
+ static struct at91_eth_data eth_data;
+ 
+ static struct resource eth_resources[] = {
+@@ -146,7 +147,7 @@ static struct platform_device at91sam9260_eth_device = {
+ 	.id		= -1,
+ 	.dev		= {
+ 				.dma_mask		= &eth_dmamask,
+-				.coherent_dma_mask	= 0xffffffff,
++				.coherent_dma_mask	= DMA_BIT_MASK(32),
+ 				.platform_data		= &eth_data,
+ 	},
+ 	.resource	= eth_resources,
+@@ -199,7 +200,7 @@ void __init at91_add_device_eth(struct at91_eth_data *data) {}
+  * -------------------------------------------------------------------- */
+ 
+ #if defined(CONFIG_MMC_AT91) || defined(CONFIG_MMC_AT91_MODULE)
+-static u64 mmc_dmamask = 0xffffffffUL;
++static u64 mmc_dmamask = DMA_BIT_MASK(32);
+ static struct at91_mmc_data mmc_data;
+ 
+ static struct resource mmc_resources[] = {
+@@ -220,7 +221,7 @@ static struct platform_device at91sam9260_mmc_device = {
+ 	.id		= -1,
+ 	.dev		= {
+ 				.dma_mask		= &mmc_dmamask,
+-				.coherent_dma_mask	= 0xffffffff,
++				.coherent_dma_mask	= DMA_BIT_MASK(32),
+ 				.platform_data		= &mmc_data,
+ 	},
+ 	.resource	= mmc_resources,
+@@ -289,7 +290,7 @@ static struct at91_nand_data nand_data;
+ static struct resource nand_resources[] = {
+ 	{
+ 		.start	= NAND_BASE,
+-		.end	= NAND_BASE + SZ_8M - 1,
++		.end	= NAND_BASE + SZ_256M - 1,
+ 		.flags	= IORESOURCE_MEM,
+ 	}
+ };
+@@ -312,7 +313,7 @@ void __init at91_add_device_nand(struct at91_nand_data *data)
+ 		return;
  
-@@ -610,8 +610,8 @@ CONFIG_SMC91X=y
- # CONFIG_SMSC911X is not set
- # CONFIG_DM9000 is not set
- CONFIG_NETDEV_1000=y
--CONFIG_NETDEV_10000=y
- # CONFIG_AX88180 is not set
-+CONFIG_NETDEV_10000=y
+ 	csa = at91_sys_read(AT91_MATRIX_EBICSA);
+-	at91_sys_write(AT91_MATRIX_EBICSA, csa | AT91_MATRIX_CS3A_SMC);
++	at91_sys_write(AT91_MATRIX_EBICSA, csa | AT91_MATRIX_CS3A_SMC_SMARTMEDIA);
+ 
+ 	/* set the bus interface characteristics */
+ 	at91_sys_write(AT91_SMC_SETUP(3), AT91_SMC_NWESETUP_(0) | AT91_SMC_NCS_WRSETUP_(0)
+@@ -431,7 +432,7 @@ void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices)
+  * -------------------------------------------------------------------- */
+ 
+ #if defined(CONFIG_SPI_ATMEL) || defined(CONFIG_SPI_ATMEL_MODULE)
+-static u64 spi_dmamask = 0xffffffffUL;
++static u64 spi_dmamask = DMA_BIT_MASK(32);
  
- #
- # Wireless LAN
-@@ -680,7 +680,6 @@ CONFIG_INPUT_EVDEV=m
- CONFIG_BFIN_SPORT=y
- # CONFIG_BFIN_TIMER_LATENCY is not set
- # CONFIG_AD5304 is not set
--# CONFIG_BF5xx_FBDMA is not set
- # CONFIG_VT is not set
- # CONFIG_SERIAL_NONSTANDARD is not set
+ static struct resource spi0_resources[] = {
+ 	[0] = {
+@@ -451,7 +452,7 @@ static struct platform_device at91sam9260_spi0_device = {
+ 	.id		= 0,
+ 	.dev		= {
+ 				.dma_mask		= &spi_dmamask,
+-				.coherent_dma_mask	= 0xffffffff,
++				.coherent_dma_mask	= DMA_BIT_MASK(32),
+ 	},
+ 	.resource	= spi0_resources,
+ 	.num_resources	= ARRAY_SIZE(spi0_resources),
+@@ -477,7 +478,7 @@ static struct platform_device at91sam9260_spi1_device = {
+ 	.id		= 1,
+ 	.dev		= {
+ 				.dma_mask		= &spi_dmamask,
+-				.coherent_dma_mask	= 0xffffffff,
++				.coherent_dma_mask	= DMA_BIT_MASK(32),
+ 	},
+ 	.resource	= spi1_resources,
+ 	.num_resources	= ARRAY_SIZE(spi1_resources),
+@@ -539,24 +540,126 @@ void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices)
  
-diff --git a/arch/blackfin/configs/BF533-STAMP_defconfig b/arch/blackfin/configs/BF533-STAMP_defconfig
-index b04e8e5..9b7123c 100644
---- a/arch/blackfin/configs/BF533-STAMP_defconfig
-+++ b/arch/blackfin/configs/BF533-STAMP_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.16
- #
- # CONFIG_MMU is not set
- # CONFIG_FPU is not set
-@@ -115,7 +115,10 @@ CONFIG_PREEMPT_VOLUNTARY=y
- # 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 is not set
- # CONFIG_BF527 is not set
- # CONFIG_BF531 is not set
- # CONFIG_BF532 is not set
-@@ -140,7 +143,6 @@ CONFIG_BF_REV_0_3=y
- CONFIG_BF53x=y
- CONFIG_BFIN_SINGLE_CORE=y
- CONFIG_MEM_MT48LC64M4A2FB_7E=y
--CONFIG_BFIN_SHARED_FLASH_ENET=y
- # CONFIG_BFIN533_EZKIT is not set
- CONFIG_BFIN533_STAMP=y
- # CONFIG_BFIN533_BLUETECHNIX_CM is not set
-@@ -195,7 +197,7 @@ CONFIG_CLKIN_HZ=11059200
- # CONFIG_BFIN_KERNEL_CLOCK is not set
- CONFIG_MAX_VCO_HZ=750000000
- CONFIG_MIN_VCO_HZ=50000000
--CONFIG_MAX_SCLK_HZ=133000000
-+CONFIG_MAX_SCLK_HZ=133333333
- CONFIG_MIN_SCLK_HZ=27000000
  
- #
-@@ -215,18 +217,10 @@ CONFIG_MEM_ADD_WIDTH=11
- CONFIG_ENET_FLASH_PIN=0
- CONFIG_BOOT_LOAD=0x1000
+ /* --------------------------------------------------------------------
+- *  LEDs
++ *  RTT
+  * -------------------------------------------------------------------- */
+ 
+-#if defined(CONFIG_LEDS)
+-u8 at91_leds_cpu;
+-u8 at91_leds_timer;
++static struct resource rtt_resources[] = {
++	{
++		.start	= AT91_BASE_SYS + AT91_RTT,
++		.end	= AT91_BASE_SYS + AT91_RTT + SZ_16 - 1,
++		.flags	= IORESOURCE_MEM,
++	}
++};
  
--#
--# LED Status Indicators
--#
--# CONFIG_BFIN_ALIVE_LED is not set
--# CONFIG_BFIN_IDLE_LED is not set
+-void __init at91_init_leds(u8 cpu_led, u8 timer_led)
++static struct platform_device at91sam9260_rtt_device = {
++	.name		= "at91_rtt",
++	.id		= -1,
++	.resource	= rtt_resources,
++	.num_resources	= ARRAY_SIZE(rtt_resources),
++};
++
++static void __init at91_add_device_rtt(void)
+ {
+-	/* Enable GPIO to access the LEDs */
+-	at91_set_gpio_output(cpu_led, 1);
+-	at91_set_gpio_output(timer_led, 1);
++	platform_device_register(&at91sam9260_rtt_device);
++}
 +
- CONFIG_BFIN_SCRATCH_REG_RETN=y
- # CONFIG_BFIN_SCRATCH_REG_RETE is not set
- # CONFIG_BFIN_SCRATCH_REG_CYCLES is not set
--CONFIG_BFIN_ALIVE_LED_PORT=0xFFC00700
--CONFIG_BFIN_ALIVE_LED_DPORT=0xFFC00730
--CONFIG_BFIN_IDLE_LED_PORT=0xFFC00700
--CONFIG_BFIN_IDLE_LED_DPORT=0xFFC00730
  
- #
- # Blackfin Kernel Optimizations
-@@ -279,6 +273,7 @@ CONFIG_BFIN_DCACHE=y
- # CONFIG_BFIN_WB is not set
- CONFIG_BFIN_WT=y
- CONFIG_L1_MAX_PIECE=16
-+# CONFIG_MPU is not set
+-	at91_leds_cpu	= cpu_led;
+-	at91_leds_timer	= timer_led;
++/* --------------------------------------------------------------------
++ *  Watchdog
++ * -------------------------------------------------------------------- */
++
++#if defined(CONFIG_AT91SAM9_WATCHDOG) || defined(CONFIG_AT91SAM9_WATCHDOG_MODULE)
++static struct platform_device at91sam9260_wdt_device = {
++	.name		= "at91_wdt",
++	.id		= -1,
++	.num_resources	= 0,
++};
++
++static void __init at91_add_device_watchdog(void)
++{
++	platform_device_register(&at91sam9260_wdt_device);
+ }
+ #else
+-void __init at91_init_leds(u8 cpu_led, u8 timer_led) {}
++static void __init at91_add_device_watchdog(void) {}
++#endif
++
++
++/* --------------------------------------------------------------------
++ *  SSC -- Synchronous Serial Controller
++ * -------------------------------------------------------------------- */
++
++#if defined(CONFIG_ATMEL_SSC) || defined(CONFIG_ATMEL_SSC_MODULE)
++static u64 ssc_dmamask = DMA_BIT_MASK(32);
++
++static struct resource ssc_resources[] = {
++	[0] = {
++		.start	= AT91SAM9260_BASE_SSC,
++		.end	= AT91SAM9260_BASE_SSC + SZ_16K - 1,
++		.flags	= IORESOURCE_MEM,
++	},
++	[1] = {
++		.start	= AT91SAM9260_ID_SSC,
++		.end	= AT91SAM9260_ID_SSC,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device at91sam9260_ssc_device = {
++	.name	= "ssc",
++	.id	= 0,
++	.dev	= {
++		.dma_mask		= &ssc_dmamask,
++		.coherent_dma_mask	= DMA_BIT_MASK(32),
++	},
++	.resource	= ssc_resources,
++	.num_resources	= ARRAY_SIZE(ssc_resources),
++};
++
++static inline void configure_ssc_pins(unsigned pins)
++{
++	if (pins & ATMEL_SSC_TF)
++		at91_set_A_periph(AT91_PIN_PB17, 1);
++	if (pins & ATMEL_SSC_TK)
++		at91_set_A_periph(AT91_PIN_PB16, 1);
++	if (pins & ATMEL_SSC_TD)
++		at91_set_A_periph(AT91_PIN_PB18, 1);
++	if (pins & ATMEL_SSC_RD)
++		at91_set_A_periph(AT91_PIN_PB19, 1);
++	if (pins & ATMEL_SSC_RK)
++		at91_set_A_periph(AT91_PIN_PB20, 1);
++	if (pins & ATMEL_SSC_RF)
++		at91_set_A_periph(AT91_PIN_PB21, 1);
++}
++
++/*
++ * SSC controllers are accessed through library code, instead of any
++ * kind of all-singing/all-dancing driver.  For example one could be
++ * used by a particular I2S audio codec's driver, while another one
++ * on the same system might be used by a custom data capture driver.
++ */
++void __init at91_add_device_ssc(unsigned id, unsigned pins)
++{
++	struct platform_device *pdev;
++
++	/*
++	 * NOTE: caller is responsible for passing information matching
++	 * "pins" to whatever will be using each particular controller.
++	 */
++	switch (id) {
++	case AT91SAM9260_ID_SSC:
++		pdev = &at91sam9260_ssc_device;
++		configure_ssc_pins(pins);
++		at91_clock_associate("ssc_clk", &pdev->dev, "pclk");
++		break;
++	default:
++		return;
++	}
++
++	platform_device_register(pdev);
++}
++
++#else
++void __init at91_add_device_ssc(unsigned id, unsigned pins) {}
+ #endif
  
- #
- # Asynchonous Memory Configuration
-@@ -333,7 +328,7 @@ CONFIG_PM=y
- CONFIG_PM_WAKEUP_GPIO_BY_SIC_IWR=y
- # CONFIG_PM_WAKEUP_BY_GPIO is not set
- # CONFIG_PM_WAKEUP_GPIO_API is not set
--CONFIG_PM_WAKEUP_SIC_IWR=0x100000
-+CONFIG_PM_WAKEUP_SIC_IWR=0x80
  
- #
- # CPU Frequency scaling
-@@ -522,7 +517,6 @@ CONFIG_MTD_CFI_I2=y
- # CONFIG_MTD_CFI_INTELEXT is not set
- # CONFIG_MTD_CFI_AMDSTD is not set
- # CONFIG_MTD_CFI_STAA is not set
--CONFIG_MTD_MW320D=m
- CONFIG_MTD_RAM=y
- CONFIG_MTD_ROM=m
- # CONFIG_MTD_ABSENT is not set
-@@ -532,17 +526,6 @@ CONFIG_MTD_ROM=m
- #
- CONFIG_MTD_COMPLEX_MAPPINGS=y
- # CONFIG_MTD_PHYSMAP is not set
--CONFIG_MTD_BF5xx=m
--CONFIG_BFIN_FLASH_SIZE=0x400000
--CONFIG_EBIU_FLASH_BASE=0x20000000
--
--#
--# FLASH_EBIU_AMBCTL Control
--#
--CONFIG_BFIN_FLASH_BANK_0=0x7BB0
--CONFIG_BFIN_FLASH_BANK_1=0x7BB0
--CONFIG_BFIN_FLASH_BANK_2=0x7BB0
--CONFIG_BFIN_FLASH_BANK_3=0x7BB0
- # CONFIG_MTD_UCLINUX is not set
- # CONFIG_MTD_PLATRAM is not set
+@@ -583,12 +686,15 @@ static struct atmel_uart_data dbgu_data = {
+ 	.regs		= (void __iomem *)(AT91_VA_BASE_SYS + AT91_DBGU),
+ };
  
-@@ -630,8 +613,8 @@ CONFIG_SMC91X=y
- # CONFIG_SMSC911X is not set
- # CONFIG_DM9000 is not set
- CONFIG_NETDEV_1000=y
--CONFIG_NETDEV_10000=y
- # CONFIG_AX88180 is not set
-+CONFIG_NETDEV_10000=y
++static u64 dbgu_dmamask = DMA_BIT_MASK(32);
++
+ static struct platform_device at91sam9260_dbgu_device = {
+ 	.name		= "atmel_usart",
+ 	.id		= 0,
+ 	.dev		= {
+-				.platform_data	= &dbgu_data,
+-				.coherent_dma_mask = 0xffffffff,
++				.dma_mask		= &dbgu_dmamask,
++				.coherent_dma_mask	= DMA_BIT_MASK(32),
++				.platform_data		= &dbgu_data,
+ 	},
+ 	.resource	= dbgu_resources,
+ 	.num_resources	= ARRAY_SIZE(dbgu_resources),
+@@ -618,27 +724,37 @@ static struct atmel_uart_data uart0_data = {
+ 	.use_dma_rx	= 1,
+ };
+ 
++static u64 uart0_dmamask = DMA_BIT_MASK(32);
++
+ static struct platform_device at91sam9260_uart0_device = {
+ 	.name		= "atmel_usart",
+ 	.id		= 1,
+ 	.dev		= {
+-				.platform_data	= &uart0_data,
+-				.coherent_dma_mask = 0xffffffff,
++				.dma_mask		= &uart0_dmamask,
++				.coherent_dma_mask	= DMA_BIT_MASK(32),
++				.platform_data		= &uart0_data,
+ 	},
+ 	.resource	= uart0_resources,
+ 	.num_resources	= ARRAY_SIZE(uart0_resources),
+ };
  
- #
- # Wireless LAN
-@@ -687,7 +670,6 @@ CONFIG_INPUT_MISC=y
- # 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_TWI_KEYPAD=m
- CONFIG_BFIN_TWIKEYPAD_IRQ_PFX=39
+-static inline void configure_usart0_pins(void)
++static inline void configure_usart0_pins(unsigned pins)
+ {
+ 	at91_set_A_periph(AT91_PIN_PB4, 1);		/* TXD0 */
+ 	at91_set_A_periph(AT91_PIN_PB5, 0);		/* RXD0 */
+-	at91_set_A_periph(AT91_PIN_PB26, 0);		/* RTS0 */
+-	at91_set_A_periph(AT91_PIN_PB27, 0);		/* CTS0 */
+-	at91_set_A_periph(AT91_PIN_PB24, 0);		/* DTR0 */
+-	at91_set_A_periph(AT91_PIN_PB22, 0);		/* DSR0 */
+-	at91_set_A_periph(AT91_PIN_PB23, 0);		/* DCD0 */
+-	at91_set_A_periph(AT91_PIN_PB25, 0);		/* RI0 */
++
++	if (pins & ATMEL_UART_RTS)
++		at91_set_A_periph(AT91_PIN_PB26, 0);	/* RTS0 */
++	if (pins & ATMEL_UART_CTS)
++		at91_set_A_periph(AT91_PIN_PB27, 0);	/* CTS0 */
++	if (pins & ATMEL_UART_DTR)
++		at91_set_A_periph(AT91_PIN_PB24, 0);	/* DTR0 */
++	if (pins & ATMEL_UART_DSR)
++		at91_set_A_periph(AT91_PIN_PB22, 0);	/* DSR0 */
++	if (pins & ATMEL_UART_DCD)
++		at91_set_A_periph(AT91_PIN_PB23, 0);	/* DCD0 */
++	if (pins & ATMEL_UART_RI)
++		at91_set_A_periph(AT91_PIN_PB25, 0);	/* RI0 */
+ }
+ 
+ static struct resource uart1_resources[] = {
+@@ -659,23 +775,29 @@ static struct atmel_uart_data uart1_data = {
+ 	.use_dma_rx	= 1,
+ };
+ 
++static u64 uart1_dmamask = DMA_BIT_MASK(32);
++
+ static struct platform_device at91sam9260_uart1_device = {
+ 	.name		= "atmel_usart",
+ 	.id		= 2,
+ 	.dev		= {
+-				.platform_data	= &uart1_data,
+-				.coherent_dma_mask = 0xffffffff,
++				.dma_mask		= &uart1_dmamask,
++				.coherent_dma_mask	= DMA_BIT_MASK(32),
++				.platform_data		= &uart1_data,
+ 	},
+ 	.resource	= uart1_resources,
+ 	.num_resources	= ARRAY_SIZE(uart1_resources),
+ };
  
-@@ -711,8 +693,6 @@ CONFIG_BFIN_SPORT=y
- CONFIG_TWI_LCD=m
- CONFIG_TWI_LCD_SLAVE_ADDR=34
- # CONFIG_AD5304 is not set
--# CONFIG_BF5xx_TEA5764 is not set
--# CONFIG_BF5xx_FBDMA is not set
- # CONFIG_VT is not set
- # CONFIG_SERIAL_NONSTANDARD is not set
+-static inline void configure_usart1_pins(void)
++static inline void configure_usart1_pins(unsigned pins)
+ {
+ 	at91_set_A_periph(AT91_PIN_PB6, 1);		/* TXD1 */
+ 	at91_set_A_periph(AT91_PIN_PB7, 0);		/* RXD1 */
+-	at91_set_A_periph(AT91_PIN_PB28, 0);		/* RTS1 */
+-	at91_set_A_periph(AT91_PIN_PB29, 0);		/* CTS1 */
++
++	if (pins & ATMEL_UART_RTS)
++		at91_set_A_periph(AT91_PIN_PB28, 0);	/* RTS1 */
++	if (pins & ATMEL_UART_CTS)
++		at91_set_A_periph(AT91_PIN_PB29, 0);	/* CTS1 */
+ }
+ 
+ static struct resource uart2_resources[] = {
+@@ -696,21 +818,29 @@ static struct atmel_uart_data uart2_data = {
+ 	.use_dma_rx	= 1,
+ };
+ 
++static u64 uart2_dmamask = DMA_BIT_MASK(32);
++
+ static struct platform_device at91sam9260_uart2_device = {
+ 	.name		= "atmel_usart",
+ 	.id		= 3,
+ 	.dev		= {
+-				.platform_data	= &uart2_data,
+-				.coherent_dma_mask = 0xffffffff,
++				.dma_mask		= &uart2_dmamask,
++				.coherent_dma_mask	= DMA_BIT_MASK(32),
++				.platform_data		= &uart2_data,
+ 	},
+ 	.resource	= uart2_resources,
+ 	.num_resources	= ARRAY_SIZE(uart2_resources),
+ };
  
-@@ -778,7 +758,6 @@ CONFIG_I2C_ALGOBIT=m
- #
- # I2C Hardware Bus support
- #
--# CONFIG_I2C_BLACKFIN_GPIO is not set
- # CONFIG_I2C_GPIO is not set
- # CONFIG_I2C_OCORES is not set
- # CONFIG_I2C_PARPORT_LIGHT is not set
-diff --git a/arch/blackfin/configs/BF537-STAMP_defconfig b/arch/blackfin/configs/BF537-STAMP_defconfig
-index f812b66..b37ccc6 100644
---- a/arch/blackfin/configs/BF537-STAMP_defconfig
-+++ b/arch/blackfin/configs/BF537-STAMP_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.16
- #
- # CONFIG_MMU is not set
- # CONFIG_FPU is not set
-@@ -115,7 +115,10 @@ CONFIG_PREEMPT_VOLUNTARY=y
- # 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 is not set
- # CONFIG_BF527 is not set
- # CONFIG_BF531 is not set
- # CONFIG_BF532 is not set
-@@ -170,6 +173,7 @@ CONFIG_IRQ_WATCH=13
- CONFIG_BFIN537_STAMP=y
- # CONFIG_BFIN537_BLUETECHNIX_CM is not set
- # CONFIG_PNAV10 is not set
-+# CONFIG_CAMSIG_MINOTAUR is not set
- # CONFIG_GENERIC_BF537_BOARD is not set
+-static inline void configure_usart2_pins(void)
++static inline void configure_usart2_pins(unsigned pins)
+ {
+ 	at91_set_A_periph(AT91_PIN_PB8, 1);		/* TXD2 */
+ 	at91_set_A_periph(AT91_PIN_PB9, 0);		/* RXD2 */
++
++	if (pins & ATMEL_UART_RTS)
++		at91_set_A_periph(AT91_PIN_PA4, 0);	/* RTS2 */
++	if (pins & ATMEL_UART_CTS)
++		at91_set_A_periph(AT91_PIN_PA5, 0);	/* CTS2 */
+ }
  
- #
-@@ -201,7 +205,7 @@ CONFIG_CLKIN_HZ=25000000
- # CONFIG_BFIN_KERNEL_CLOCK is not set
- CONFIG_MAX_VCO_HZ=600000000
- CONFIG_MIN_VCO_HZ=50000000
--CONFIG_MAX_SCLK_HZ=133000000
-+CONFIG_MAX_SCLK_HZ=133333333
- CONFIG_MIN_SCLK_HZ=27000000
+ static struct resource uart3_resources[] = {
+@@ -731,21 +861,29 @@ static struct atmel_uart_data uart3_data = {
+ 	.use_dma_rx	= 1,
+ };
  
- #
-@@ -274,6 +278,7 @@ CONFIG_BFIN_DCACHE=y
- # CONFIG_BFIN_WB is not set
- CONFIG_BFIN_WT=y
- CONFIG_L1_MAX_PIECE=16
-+# CONFIG_MPU is not set
++static u64 uart3_dmamask = DMA_BIT_MASK(32);
++
+ static struct platform_device at91sam9260_uart3_device = {
+ 	.name		= "atmel_usart",
+ 	.id		= 4,
+ 	.dev		= {
+-				.platform_data	= &uart3_data,
+-				.coherent_dma_mask = 0xffffffff,
++				.dma_mask		= &uart3_dmamask,
++				.coherent_dma_mask	= DMA_BIT_MASK(32),
++				.platform_data		= &uart3_data,
+ 	},
+ 	.resource	= uart3_resources,
+ 	.num_resources	= ARRAY_SIZE(uart3_resources),
+ };
  
- #
- # Asynchonous Memory Configuration
-@@ -328,7 +333,7 @@ CONFIG_PM=y
- CONFIG_PM_WAKEUP_GPIO_BY_SIC_IWR=y
- # CONFIG_PM_WAKEUP_BY_GPIO is not set
- # CONFIG_PM_WAKEUP_GPIO_API is not set
--CONFIG_PM_WAKEUP_SIC_IWR=0x80000000
-+CONFIG_PM_WAKEUP_SIC_IWR=0x8
+-static inline void configure_usart3_pins(void)
++static inline void configure_usart3_pins(unsigned pins)
+ {
+ 	at91_set_A_periph(AT91_PIN_PB10, 1);		/* TXD3 */
+ 	at91_set_A_periph(AT91_PIN_PB11, 0);		/* RXD3 */
++
++	if (pins & ATMEL_UART_RTS)
++		at91_set_B_periph(AT91_PIN_PC8, 0);	/* RTS3 */
++	if (pins & ATMEL_UART_CTS)
++		at91_set_B_periph(AT91_PIN_PC10, 0);	/* CTS3 */
+ }
  
- #
- # CPU Frequency scaling
-@@ -483,7 +488,7 @@ CONFIG_MTD=y
- # 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_CMDLINE_PARTS=y
+ static struct resource uart4_resources[] = {
+@@ -766,12 +904,15 @@ static struct atmel_uart_data uart4_data = {
+ 	.use_dma_rx	= 1,
+ };
  
- #
- # User Modules And Translation Layers
-@@ -500,8 +505,8 @@ CONFIG_MTD_BLOCK=y
- #
- # RAM/ROM/Flash chip drivers
- #
--# CONFIG_MTD_CFI is not set
--CONFIG_MTD_JEDECPROBE=m
-+CONFIG_MTD_CFI=m
-+# CONFIG_MTD_JEDECPROBE is not set
- CONFIG_MTD_GEN_PROBE=m
- # CONFIG_MTD_CFI_ADV_OPTIONS is not set
- CONFIG_MTD_MAP_BANK_WIDTH_1=y
-@@ -515,9 +520,9 @@ 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_AMDSTD=m
- # CONFIG_MTD_CFI_STAA is not set
--CONFIG_MTD_MW320D=m
-+CONFIG_MTD_CFI_UTIL=m
- CONFIG_MTD_RAM=y
- CONFIG_MTD_ROM=m
- # CONFIG_MTD_ABSENT is not set
-@@ -525,11 +530,11 @@ CONFIG_MTD_ROM=m
- #
- # Mapping drivers for chip access
- #
--CONFIG_MTD_COMPLEX_MAPPINGS=y
--# CONFIG_MTD_PHYSMAP is not set
--CONFIG_MTD_BF5xx=m
--CONFIG_BFIN_FLASH_SIZE=0x400000
--CONFIG_EBIU_FLASH_BASE=0x20000000
-+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
-+CONFIG_MTD_PHYSMAP=m
-+CONFIG_MTD_PHYSMAP_START=0x20000000
-+CONFIG_MTD_PHYSMAP_LEN=0x0
-+CONFIG_MTD_PHYSMAP_BANKWIDTH=2
- # CONFIG_MTD_UCLINUX is not set
- # CONFIG_MTD_PLATRAM is not set
++static u64 uart4_dmamask = DMA_BIT_MASK(32);
++
+ static struct platform_device at91sam9260_uart4_device = {
+ 	.name		= "atmel_usart",
+ 	.id		= 5,
+ 	.dev		= {
+-				.platform_data	= &uart4_data,
+-				.coherent_dma_mask = 0xffffffff,
++				.dma_mask		= &uart4_dmamask,
++				.coherent_dma_mask	= DMA_BIT_MASK(32),
++				.platform_data		= &uart4_data,
+ 	},
+ 	.resource	= uart4_resources,
+ 	.num_resources	= ARRAY_SIZE(uart4_resources),
+@@ -801,12 +942,15 @@ static struct atmel_uart_data uart5_data = {
+ 	.use_dma_rx	= 1,
+ };
+ 
++static u64 uart5_dmamask = DMA_BIT_MASK(32);
++
+ static struct platform_device at91sam9260_uart5_device = {
+ 	.name		= "atmel_usart",
+ 	.id		= 6,
+ 	.dev		= {
+-				.platform_data	= &uart5_data,
+-				.coherent_dma_mask = 0xffffffff,
++				.dma_mask		= &uart5_dmamask,
++				.coherent_dma_mask	= DMA_BIT_MASK(32),
++				.platform_data		= &uart5_data,
+ 	},
+ 	.resource	= uart5_resources,
+ 	.num_resources	= ARRAY_SIZE(uart5_resources),
+@@ -818,10 +962,10 @@ static inline void configure_usart5_pins(void)
+ 	at91_set_A_periph(AT91_PIN_PB13, 0);		/* RXD5 */
+ }
  
-@@ -647,8 +652,8 @@ CONFIG_BFIN_RX_DESC_NUM=20
- # CONFIG_SMSC911X is not set
- # CONFIG_DM9000 is not set
- CONFIG_NETDEV_1000=y
--CONFIG_NETDEV_10000=y
- # CONFIG_AX88180 is not set
-+CONFIG_NETDEV_10000=y
+-struct platform_device *at91_uarts[ATMEL_MAX_UART];	/* the UARTs to use */
++static struct platform_device *at91_uarts[ATMEL_MAX_UART];	/* the UARTs to use */
+ struct platform_device *atmel_default_console_device;	/* the serial console device */
  
- #
- # Wireless LAN
-@@ -704,7 +709,6 @@ CONFIG_INPUT_MISC=y
- # 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_TWI_KEYPAD=m
- CONFIG_BFIN_TWIKEYPAD_IRQ_PFX=72
+-void __init at91_init_serial(struct at91_uart_config *config)
++void __init __deprecated at91_init_serial(struct at91_uart_config *config)
+ {
+ 	int i;
  
-@@ -728,8 +732,6 @@ CONFIG_BFIN_SPORT=y
- CONFIG_TWI_LCD=m
- CONFIG_TWI_LCD_SLAVE_ADDR=34
- # CONFIG_AD5304 is not set
--# CONFIG_BF5xx_TEA5764 is not set
--# CONFIG_BF5xx_FBDMA is not set
- # CONFIG_VT is not set
- # CONFIG_SERIAL_NONSTANDARD is not set
+@@ -829,22 +973,22 @@ void __init at91_init_serial(struct at91_uart_config *config)
+ 	for (i = 0; i < config->nr_tty; i++) {
+ 		switch (config->tty_map[i]) {
+ 			case 0:
+-				configure_usart0_pins();
++				configure_usart0_pins(ATMEL_UART_CTS | ATMEL_UART_RTS | ATMEL_UART_DSR | ATMEL_UART_DTR | ATMEL_UART_DCD | ATMEL_UART_RI);
+ 				at91_uarts[i] = &at91sam9260_uart0_device;
+ 				at91_clock_associate("usart0_clk", &at91sam9260_uart0_device.dev, "usart");
+ 				break;
+ 			case 1:
+-				configure_usart1_pins();
++				configure_usart1_pins(ATMEL_UART_CTS | ATMEL_UART_RTS);
+ 				at91_uarts[i] = &at91sam9260_uart1_device;
+ 				at91_clock_associate("usart1_clk", &at91sam9260_uart1_device.dev, "usart");
+ 				break;
+ 			case 2:
+-				configure_usart2_pins();
++				configure_usart2_pins(0);
+ 				at91_uarts[i] = &at91sam9260_uart2_device;
+ 				at91_clock_associate("usart2_clk", &at91sam9260_uart2_device.dev, "usart");
+ 				break;
+ 			case 3:
+-				configure_usart3_pins();
++				configure_usart3_pins(0);
+ 				at91_uarts[i] = &at91sam9260_uart3_device;
+ 				at91_clock_associate("usart3_clk", &at91sam9260_uart3_device.dev, "usart");
+ 				break;
+@@ -876,6 +1020,63 @@ void __init at91_init_serial(struct at91_uart_config *config)
+ 		printk(KERN_INFO "AT91: No default serial console defined.\n");
+ }
  
-@@ -802,7 +804,6 @@ CONFIG_I2C_CHARDEV=m
- #
- # I2C Hardware Bus support
- #
--# CONFIG_I2C_BLACKFIN_GPIO is not set
- CONFIG_I2C_BLACKFIN_TWI=m
- CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ=50
- # CONFIG_I2C_GPIO is not set
-@@ -957,6 +958,7 @@ CONFIG_LQ035_SLAVE_ADDR=0x58
- # CONFIG_FB_BFIN_LANDSCAPE is not set
- # CONFIG_FB_BFIN_BGR is not set
- # CONFIG_FB_BFIN_T350MCQB is not set
-+# CONFIG_FB_HITACHI_TX09 is not set
- # CONFIG_FB_S1D13XXX is not set
- # CONFIG_FB_VIRTUAL is not set
- # CONFIG_LOGO is not set
-@@ -1008,12 +1010,22 @@ CONFIG_SND_BFIN_AD73311_SE=4
- #
- # System on Chip audio support
- #
--# CONFIG_SND_SOC is not set
-+CONFIG_SND_SOC_AC97_BUS=y
-+CONFIG_SND_SOC=m
-+CONFIG_SND_BF5XX_SOC=m
-+CONFIG_SND_BF5XX_SOC_AC97=m
-+# CONFIG_SND_BF5XX_SOC_WM8750 is not set
-+# CONFIG_SND_BF5XX_SOC_WM8731 is not set
-+CONFIG_SND_BF5XX_SOC_BF5xx=m
-+CONFIG_SND_BF5XX_SPORT_NUM=0
-+# CONFIG_SND_BF5XX_HAVE_COLD_RESET is not set
-+CONFIG_SND_SOC_AD1980=m
++void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins)
++{
++	struct platform_device *pdev;
++
++	switch (id) {
++		case 0:		/* DBGU */
++			pdev = &at91sam9260_dbgu_device;
++			configure_dbgu_pins();
++			at91_clock_associate("mck", &pdev->dev, "usart");
++			break;
++		case AT91SAM9260_ID_US0:
++			pdev = &at91sam9260_uart0_device;
++			configure_usart0_pins(pins);
++			at91_clock_associate("usart0_clk", &pdev->dev, "usart");
++			break;
++		case AT91SAM9260_ID_US1:
++			pdev = &at91sam9260_uart1_device;
++			configure_usart1_pins(pins);
++			at91_clock_associate("usart1_clk", &pdev->dev, "usart");
++			break;
++		case AT91SAM9260_ID_US2:
++			pdev = &at91sam9260_uart2_device;
++			configure_usart2_pins(pins);
++			at91_clock_associate("usart2_clk", &pdev->dev, "usart");
++			break;
++		case AT91SAM9260_ID_US3:
++			pdev = &at91sam9260_uart3_device;
++			configure_usart3_pins(pins);
++			at91_clock_associate("usart3_clk", &pdev->dev, "usart");
++			break;
++		case AT91SAM9260_ID_US4:
++			pdev = &at91sam9260_uart4_device;
++			configure_usart4_pins();
++			at91_clock_associate("usart4_clk", &pdev->dev, "usart");
++			break;
++		case AT91SAM9260_ID_US5:
++			pdev = &at91sam9260_uart5_device;
++			configure_usart5_pins();
++			at91_clock_associate("usart5_clk", &pdev->dev, "usart");
++			break;
++		default:
++			return;
++	}
++	pdev->id = portnr;		/* update to mapped ID */
++
++	if (portnr < ATMEL_MAX_UART)
++		at91_uarts[portnr] = pdev;
++}
++
++void __init at91_set_serial_console(unsigned portnr)
++{
++	if (portnr < ATMEL_MAX_UART)
++		atmel_default_console_device = at91_uarts[portnr];
++	if (!atmel_default_console_device)
++		printk(KERN_INFO "AT91: No default serial console defined.\n");
++}
++
+ void __init at91_add_device_serial(void)
+ {
+ 	int i;
+@@ -886,7 +1087,9 @@ void __init at91_add_device_serial(void)
+ 	}
+ }
+ #else
+-void __init at91_init_serial(struct at91_uart_config *config) {}
++void __init __deprecated at91_init_serial(struct at91_uart_config *config) {}
++void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins) {}
++void __init at91_set_serial_console(unsigned portnr) {}
+ void __init at91_add_device_serial(void) {}
+ #endif
  
- #
- # Open Sound System
- #
- # CONFIG_SOUND_PRIME is not set
-+CONFIG_AC97_BUS=m
+@@ -898,6 +1101,8 @@ void __init at91_add_device_serial(void) {}
+  */
+ static int __init at91_add_standard_devices(void)
+ {
++	at91_add_device_rtt();
++	at91_add_device_watchdog();
+ 	return 0;
+ }
  
- #
- # HID Devices
-diff --git a/arch/blackfin/configs/BF548-EZKIT_defconfig b/arch/blackfin/configs/BF548-EZKIT_defconfig
-index 48367cc..fd70216 100644
---- a/arch/blackfin/configs/BF548-EZKIT_defconfig
-+++ b/arch/blackfin/configs/BF548-EZKIT_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.16
- #
- # CONFIG_MMU is not set
- # CONFIG_FPU is not set
-@@ -115,7 +115,10 @@ CONFIG_PREEMPT_VOLUNTARY=y
- # 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 is not set
- # CONFIG_BF527 is not set
- # CONFIG_BF531 is not set
- # CONFIG_BF532 is not set
-@@ -126,8 +129,8 @@ CONFIG_PREEMPT_VOLUNTARY=y
- # CONFIG_BF542 is not set
- # CONFIG_BF544 is not set
- # CONFIG_BF547 is not set
--# CONFIG_BF548 is not set
--CONFIG_BF549=y
-+CONFIG_BF548=y
-+# CONFIG_BF549 is not set
- # CONFIG_BF561 is not set
- CONFIG_BF_REV_0_0=y
- # CONFIG_BF_REV_0_1 is not set
-@@ -265,9 +268,9 @@ CONFIG_PINT3_ASSIGN=0x02020303
- #
- CONFIG_CLKIN_HZ=25000000
- # CONFIG_BFIN_KERNEL_CLOCK is not set
--CONFIG_MAX_VCO_HZ=533000000
-+CONFIG_MAX_VCO_HZ=600000000
- CONFIG_MIN_VCO_HZ=50000000
--CONFIG_MAX_SCLK_HZ=133000000
-+CONFIG_MAX_SCLK_HZ=133333333
- CONFIG_MIN_SCLK_HZ=27000000
+diff --git a/arch/arm/mach-at91/at91sam9261.c b/arch/arm/mach-at91/at91sam9261.c
+index dfe8c39..90b87e1 100644
+--- a/arch/arm/mach-at91/at91sam9261.c
++++ b/arch/arm/mach-at91/at91sam9261.c
+@@ -279,25 +279,25 @@ void __init at91sam9261_initialize(unsigned long main_clock)
+ static unsigned int at91sam9261_default_irq_priority[NR_AIC_IRQS] __initdata = {
+ 	7,	/* Advanced Interrupt Controller */
+ 	7,	/* System Peripherals */
+-	0,	/* Parallel IO Controller A */
+-	0,	/* Parallel IO Controller B */
+-	0,	/* Parallel IO Controller C */
++	1,	/* Parallel IO Controller A */
++	1,	/* Parallel IO Controller B */
++	1,	/* Parallel IO Controller C */
+ 	0,
+-	6,	/* USART 0 */
+-	6,	/* USART 1 */
+-	6,	/* USART 2 */
++	5,	/* USART 0 */
++	5,	/* USART 1 */
++	5,	/* USART 2 */
+ 	0,	/* Multimedia Card Interface */
+-	4,	/* USB Device Port */
+-	0,	/* Two-Wire Interface */
+-	6,	/* Serial Peripheral Interface 0 */
+-	6,	/* Serial Peripheral Interface 1 */
+-	5,	/* Serial Synchronous Controller 0 */
+-	5,	/* Serial Synchronous Controller 1 */
+-	5,	/* Serial Synchronous Controller 2 */
++	2,	/* USB Device Port */
++	6,	/* Two-Wire Interface */
++	5,	/* Serial Peripheral Interface 0 */
++	5,	/* Serial Peripheral Interface 1 */
++	4,	/* Serial Synchronous Controller 0 */
++	4,	/* Serial Synchronous Controller 1 */
++	4,	/* Serial Synchronous Controller 2 */
+ 	0,	/* Timer Counter 0 */
+ 	0,	/* Timer Counter 1 */
+ 	0,	/* Timer Counter 2 */
+-	3,	/* USB Host port */
++	2,	/* USB Host port */
+ 	3,	/* LCD Controller */
+ 	0,
+ 	0,
+diff --git a/arch/arm/mach-at91/at91sam9261_devices.c b/arch/arm/mach-at91/at91sam9261_devices.c
+index 64979a9..2456412 100644
+--- a/arch/arm/mach-at91/at91sam9261_devices.c
++++ b/arch/arm/mach-at91/at91sam9261_devices.c
+@@ -13,6 +13,7 @@
+ #include <asm/mach/arch.h>
+ #include <asm/mach/map.h>
  
- #
-@@ -283,7 +286,8 @@ CONFIG_HZ=250
- # Memory Setup
- #
- CONFIG_MEM_SIZE=64
--CONFIG_MEM_ADD_WIDTH=10
-+# CONFIG_MEM_MT46V32M16_6T is not set
-+CONFIG_MEM_MT46V32M16_5B=y
- CONFIG_BOOT_LOAD=0x1000
- CONFIG_BFIN_SCRATCH_REG_RETN=y
- # CONFIG_BFIN_SCRATCH_REG_RETE is not set
-@@ -340,6 +344,7 @@ CONFIG_BFIN_DCACHE=y
- # CONFIG_BFIN_WB is not set
- CONFIG_BFIN_WT=y
- CONFIG_L1_MAX_PIECE=16
-+# CONFIG_MPU is not set
++#include <linux/dma-mapping.h>
+ #include <linux/platform_device.h>
+ #include <linux/i2c-gpio.h>
  
- #
- # Asynchonous Memory Configuration
-@@ -349,6 +354,7 @@ CONFIG_L1_MAX_PIECE=16
- # EBIU_AMGCTL Global Control
- #
- CONFIG_C_AMCKEN=y
-+# CONFIG_C_CDPRIO is not set
- # CONFIG_C_AMBEN is not set
- # CONFIG_C_AMBEN_B0 is not set
- # CONFIG_C_AMBEN_B0_B1 is not set
-@@ -362,9 +368,9 @@ CONFIG_BANK_0=0x7BB0
- CONFIG_BANK_1=0x5554
- CONFIG_BANK_2=0x7BB0
- CONFIG_BANK_3=0x99B3
--CONFIG_EBUI_MBSCTLVAL=0x0
--CONFIG_EBUI_MODEVAL=0x1
--CONFIG_EBUI_FCTLVAL=0x6
-+CONFIG_EBIU_MBSCTLVAL=0x0
-+CONFIG_EBIU_MODEVAL=0x1
-+CONFIG_EBIU_FCTLVAL=0x6
+@@ -33,7 +34,7 @@
+  * -------------------------------------------------------------------- */
  
- #
- # Bus options (PCI, PCMCIA, EISA, MCA, ISA)
-@@ -537,7 +543,6 @@ CONFIG_MTD_CFI_I2=y
- CONFIG_MTD_CFI_INTELEXT=y
- # CONFIG_MTD_CFI_AMDSTD is not set
- # CONFIG_MTD_CFI_STAA is not set
--# CONFIG_MTD_MW320D is not set
- CONFIG_MTD_CFI_UTIL=y
- CONFIG_MTD_RAM=y
- # CONFIG_MTD_ROM is not set
-@@ -549,9 +554,8 @@ CONFIG_MTD_RAM=y
- CONFIG_MTD_COMPLEX_MAPPINGS=y
- CONFIG_MTD_PHYSMAP=y
- CONFIG_MTD_PHYSMAP_START=0x20000000
--CONFIG_MTD_PHYSMAP_LEN=0x400000
-+CONFIG_MTD_PHYSMAP_LEN=0
- CONFIG_MTD_PHYSMAP_BANKWIDTH=2
--# CONFIG_MTD_BF5xx is not set
- # CONFIG_MTD_UCLINUX is not set
- # CONFIG_MTD_PLATRAM is not set
+ #if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
+-static u64 ohci_dmamask = 0xffffffffUL;
++static u64 ohci_dmamask = DMA_BIT_MASK(32);
+ static struct at91_usbh_data usbh_data;
+ 
+ static struct resource usbh_resources[] = {
+@@ -54,7 +55,7 @@ static struct platform_device at91sam9261_usbh_device = {
+ 	.id		= -1,
+ 	.dev		= {
+ 				.dma_mask		= &ohci_dmamask,
+-				.coherent_dma_mask	= 0xffffffff,
++				.coherent_dma_mask	= DMA_BIT_MASK(32),
+ 				.platform_data		= &usbh_data,
+ 	},
+ 	.resource	= usbh_resources,
+@@ -106,8 +107,6 @@ static struct platform_device at91sam9261_udc_device = {
  
-@@ -690,8 +694,8 @@ CONFIG_MII=y
- CONFIG_SMSC911X=y
- # CONFIG_DM9000 is not set
- CONFIG_NETDEV_1000=y
--CONFIG_NETDEV_10000=y
- # CONFIG_AX88180 is not set
-+CONFIG_NETDEV_10000=y
+ void __init at91_add_device_udc(struct at91_udc_data *data)
+ {
+-	unsigned long x;
+-
+ 	if (!data)
+ 		return;
  
- #
- # Wireless LAN
-@@ -719,7 +723,7 @@ CONFIG_NETDEV_10000=y
- #
- # Input device support
- #
--CONFIG_INPUT=m
-+CONFIG_INPUT=y
- # CONFIG_INPUT_FF_MEMLESS is not set
- # CONFIG_INPUT_POLLDEV is not set
+@@ -116,9 +115,7 @@ void __init at91_add_device_udc(struct at91_udc_data *data)
+ 		at91_set_deglitch(data->vbus_pin, 1);
+ 	}
  
-@@ -745,7 +749,8 @@ CONFIG_INPUT_KEYBOARD=y
- # CONFIG_KEYBOARD_NEWTON is not set
- # CONFIG_KEYBOARD_STOWAWAY is not set
- # CONFIG_KEYBOARD_GPIO is not set
--CONFIG_KEYBOARD_BFIN=m
-+CONFIG_KEYBOARD_BFIN=y
-+# CONFIG_KEYBOARD_OPENCORES is not set
- # CONFIG_INPUT_MOUSE is not set
- # CONFIG_INPUT_JOYSTICK is not set
- # CONFIG_INPUT_TABLET is not set
-@@ -768,7 +773,6 @@ CONFIG_INPUT_MISC=y
- # 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_TWI_KEYPAD is not set
+-	/* Pullup pin is handled internally */
+-	x = at91_sys_read(AT91_MATRIX_USBPUCR);
+-	at91_sys_write(AT91_MATRIX_USBPUCR, x | AT91_MATRIX_USBPUCR_PUON);
++	/* Pullup pin is handled internally by USB device peripheral */
+ 
+ 	udc_data = *data;
+ 	platform_device_register(&at91sam9261_udc_device);
+@@ -132,7 +129,7 @@ void __init at91_add_device_udc(struct at91_udc_data *data) {}
+  * -------------------------------------------------------------------- */
+ 
+ #if defined(CONFIG_MMC_AT91) || defined(CONFIG_MMC_AT91_MODULE)
+-static u64 mmc_dmamask = 0xffffffffUL;
++static u64 mmc_dmamask = DMA_BIT_MASK(32);
+ static struct at91_mmc_data mmc_data;
+ 
+ static struct resource mmc_resources[] = {
+@@ -153,7 +150,7 @@ static struct platform_device at91sam9261_mmc_device = {
+ 	.id		= -1,
+ 	.dev		= {
+ 				.dma_mask		= &mmc_dmamask,
+-				.coherent_dma_mask	= 0xffffffff,
++				.coherent_dma_mask	= DMA_BIT_MASK(32),
+ 				.platform_data		= &mmc_data,
+ 	},
+ 	.resource	= mmc_resources,
+@@ -232,7 +229,7 @@ void __init at91_add_device_nand(struct at91_nand_data *data)
+ 		return;
  
- #
-@@ -786,13 +790,16 @@ CONFIG_INPUT_MISC=y
- # CONFIG_BF5xx_PPIFCD is not set
- # CONFIG_BFIN_SIMPLE_TIMER is not set
- # CONFIG_BF5xx_PPI is not set
-+CONFIG_BFIN_OTP=y
-+# CONFIG_BFIN_OTP_WRITE_ENABLE is not set
- # CONFIG_BFIN_SPORT is not set
- # CONFIG_BFIN_TIMER_LATENCY is not set
- # CONFIG_TWI_LCD is not set
- # CONFIG_AD5304 is not set
--# CONFIG_BF5xx_TEA5764 is not set
--# CONFIG_BF5xx_FBDMA is not set
--# CONFIG_VT is not set
-+CONFIG_VT=y
-+CONFIG_VT_CONSOLE=y
-+CONFIG_HW_CONSOLE=y
-+# CONFIG_VT_HW_CONSOLE_BINDING is not set
- # CONFIG_SERIAL_NONSTANDARD is not set
+ 	csa = at91_sys_read(AT91_MATRIX_EBICSA);
+-	at91_sys_write(AT91_MATRIX_EBICSA, csa | AT91_MATRIX_CS3A_SMC);
++	at91_sys_write(AT91_MATRIX_EBICSA, csa | AT91_MATRIX_CS3A_SMC_SMARTMEDIA);
+ 
+ 	/* set the bus interface characteristics */
+ 	at91_sys_write(AT91_SMC_SETUP(3), AT91_SMC_NWESETUP_(0) | AT91_SMC_NCS_WRSETUP_(0)
+@@ -354,7 +351,7 @@ void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices)
+  * -------------------------------------------------------------------- */
+ 
+ #if defined(CONFIG_SPI_ATMEL) || defined(CONFIG_SPI_ATMEL_MODULE)
+-static u64 spi_dmamask = 0xffffffffUL;
++static u64 spi_dmamask = DMA_BIT_MASK(32);
  
- #
-@@ -858,7 +865,6 @@ CONFIG_I2C_CHARDEV=y
- #
- # I2C Hardware Bus support
- #
--# CONFIG_I2C_BLACKFIN_GPIO is not set
- CONFIG_I2C_BLACKFIN_TWI=y
- CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ=50
- # CONFIG_I2C_GPIO is not set
-@@ -976,12 +982,12 @@ CONFIG_DAB=y
- #
- # CONFIG_DISPLAY_SUPPORT is not set
- # CONFIG_VGASTATE is not set
--CONFIG_FB=m
-+CONFIG_FB=y
- CONFIG_FIRMWARE_EDID=y
- # CONFIG_FB_DDC is not set
--CONFIG_FB_CFB_FILLRECT=m
--CONFIG_FB_CFB_COPYAREA=m
--CONFIG_FB_CFB_IMAGEBLIT=m
-+CONFIG_FB_CFB_FILLRECT=y
-+CONFIG_FB_CFB_COPYAREA=y
-+CONFIG_FB_CFB_IMAGEBLIT=y
- # CONFIG_FB_SYS_FILLRECT is not set
- # CONFIG_FB_SYS_COPYAREA is not set
- # CONFIG_FB_SYS_IMAGEBLIT is not set
-@@ -998,11 +1004,34 @@ CONFIG_FB_DEFERRED_IO=y
- #
- # CONFIG_FB_BFIN_7171 is not set
- # CONFIG_FB_BFIN_7393 is not set
--CONFIG_FB_BF54X_LQ043=m
-+CONFIG_FB_BF54X_LQ043=y
- # CONFIG_FB_BFIN_T350MCQB is not set
- # CONFIG_FB_S1D13XXX is not set
- # CONFIG_FB_VIRTUAL is not set
--# CONFIG_LOGO is not set
-+
-+#
-+# Console display driver support
-+#
-+CONFIG_DUMMY_CONSOLE=y
-+CONFIG_FRAMEBUFFER_CONSOLE=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 is not set
-+# CONFIG_LOGO_LINUX_VGA16 is not set
-+# CONFIG_LOGO_LINUX_CLUT224 is not set
-+# CONFIG_LOGO_BLACKFIN_VGA16 is not set
-+CONFIG_LOGO_BLACKFIN_CLUT224=y
+ static struct resource spi0_resources[] = {
+ 	[0] = {
+@@ -374,7 +371,7 @@ static struct platform_device at91sam9261_spi0_device = {
+ 	.id		= 0,
+ 	.dev		= {
+ 				.dma_mask		= &spi_dmamask,
+-				.coherent_dma_mask	= 0xffffffff,
++				.coherent_dma_mask	= DMA_BIT_MASK(32),
+ 	},
+ 	.resource	= spi0_resources,
+ 	.num_resources	= ARRAY_SIZE(spi0_resources),
+@@ -400,7 +397,7 @@ static struct platform_device at91sam9261_spi1_device = {
+ 	.id		= 1,
+ 	.dev		= {
+ 				.dma_mask		= &spi_dmamask,
+-				.coherent_dma_mask	= 0xffffffff,
++				.coherent_dma_mask	= DMA_BIT_MASK(32),
+ 	},
+ 	.resource	= spi1_resources,
+ 	.num_resources	= ARRAY_SIZE(spi1_resources),
+@@ -466,7 +463,7 @@ void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices)
+  * -------------------------------------------------------------------- */
+ 
+ #if defined(CONFIG_FB_ATMEL) || defined(CONFIG_FB_ATMEL_MODULE)
+-static u64 lcdc_dmamask = 0xffffffffUL;
++static u64 lcdc_dmamask = DMA_BIT_MASK(32);
+ static struct atmel_lcdfb_info lcdc_data;
  
- #
- # Sound
-@@ -1051,7 +1080,8 @@ CONFIG_SND_BF5XX_SOC_BF548_EZKIT=y
- # CONFIG_SND_BF5XX_SOC_WM8750 is not set
- # CONFIG_SND_BF5XX_SOC_WM8731 is not set
- CONFIG_SND_BF5XX_SPORT_NUM=0
--# CONFIG_SND_BF5XX_HAVE_COLD_RESET is not set
-+CONFIG_SND_BF5XX_HAVE_COLD_RESET=y
-+CONFIG_SND_BF5XX_RESET_GPIO_NUM=19
- CONFIG_SND_SOC_AD1980=y
+ static struct resource lcdc_resources[] = {
+@@ -494,7 +491,7 @@ static struct platform_device at91_lcdc_device = {
+ 	.id		= 0,
+ 	.dev		= {
+ 				.dma_mask		= &lcdc_dmamask,
+-				.coherent_dma_mask	= 0xffffffff,
++				.coherent_dma_mask	= DMA_BIT_MASK(32),
+ 				.platform_data		= &lcdc_data,
+ 	},
+ 	.resource	= lcdc_resources,
+@@ -507,6 +504,17 @@ void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data)
+ 		return;
+ 	}
  
- #
-@@ -1403,7 +1433,7 @@ CONFIG_NLS_UTF8=m
- #
- # CONFIG_PRINTK_TIME is not set
- CONFIG_ENABLE_MUST_CHECK=y
--CONFIG_MAGIC_SYSRQ=y
-+# CONFIG_MAGIC_SYSRQ is not set
- # CONFIG_UNUSED_SYMBOLS is not set
- CONFIG_DEBUG_FS=y
- # CONFIG_HEADERS_CHECK is not set
-@@ -1428,7 +1458,7 @@ CONFIG_ACCESS_CHECK=y
- # CONFIG_KEYS is not set
- CONFIG_SECURITY=y
- # CONFIG_SECURITY_NETWORK is not set
--CONFIG_SECURITY_CAPABILITIES=y
-+CONFIG_SECURITY_CAPABILITIES=m
++#if defined(CONFIG_FB_ATMEL_STN)
++	at91_set_A_periph(AT91_PIN_PB0, 0);     /* LCDVSYNC */
++	at91_set_A_periph(AT91_PIN_PB1, 0);     /* LCDHSYNC */
++	at91_set_A_periph(AT91_PIN_PB2, 0);     /* LCDDOTCK */
++	at91_set_A_periph(AT91_PIN_PB3, 0);     /* LCDDEN */
++	at91_set_A_periph(AT91_PIN_PB4, 0);     /* LCDCC */
++	at91_set_A_periph(AT91_PIN_PB5, 0);     /* LCDD0 */
++	at91_set_A_periph(AT91_PIN_PB6, 0);     /* LCDD1 */
++	at91_set_A_periph(AT91_PIN_PB7, 0);     /* LCDD2 */
++	at91_set_A_periph(AT91_PIN_PB8, 0);     /* LCDD3 */
++#else
+ 	at91_set_A_periph(AT91_PIN_PB1, 0);	/* LCDHSYNC */
+ 	at91_set_A_periph(AT91_PIN_PB2, 0);	/* LCDDOTCK */
+ 	at91_set_A_periph(AT91_PIN_PB3, 0);	/* LCDDEN */
+@@ -529,6 +537,7 @@ void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data)
+ 	at91_set_B_periph(AT91_PIN_PB26, 0);	/* LCDD21 */
+ 	at91_set_B_periph(AT91_PIN_PB27, 0);	/* LCDD22 */
+ 	at91_set_B_periph(AT91_PIN_PB28, 0);	/* LCDD23 */
++#endif
  
- #
- # Cryptographic options
-@@ -1439,7 +1469,7 @@ CONFIG_SECURITY_CAPABILITIES=y
- # Library routines
- #
- CONFIG_BITREVERSE=y
--# CONFIG_CRC_CCITT is not set
-+CONFIG_CRC_CCITT=m
- # CONFIG_CRC16 is not set
- # CONFIG_CRC_ITU_T is not set
- CONFIG_CRC32=y
-diff --git a/arch/blackfin/configs/BF561-EZKIT_defconfig b/arch/blackfin/configs/BF561-EZKIT_defconfig
-index e9f100b..8546994 100644
---- a/arch/blackfin/configs/BF561-EZKIT_defconfig
-+++ b/arch/blackfin/configs/BF561-EZKIT_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.16
- #
- # CONFIG_MMU is not set
- # CONFIG_FPU is not set
-@@ -115,7 +115,10 @@ CONFIG_PREEMPT_VOLUNTARY=y
- # 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 is not set
- # CONFIG_BF527 is not set
- # CONFIG_BF531 is not set
- # CONFIG_BF532 is not set
-@@ -238,7 +241,7 @@ CONFIG_CLKIN_HZ=30000000
- # CONFIG_BFIN_KERNEL_CLOCK is not set
- CONFIG_MAX_VCO_HZ=600000000
- CONFIG_MIN_VCO_HZ=50000000
--CONFIG_MAX_SCLK_HZ=133000000
-+CONFIG_MAX_SCLK_HZ=133333333
- CONFIG_MIN_SCLK_HZ=27000000
+ 	lcdc_data = *data;
+ 	platform_device_register(&at91_lcdc_device);
+@@ -539,24 +548,220 @@ void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data) {}
  
- #
-@@ -311,6 +314,7 @@ CONFIG_BFIN_DCACHE=y
- # CONFIG_BFIN_WB is not set
- CONFIG_BFIN_WT=y
- CONFIG_L1_MAX_PIECE=16
-+# CONFIG_MPU is not set
  
- #
- # Asynchonous Memory Configuration
-@@ -512,7 +516,7 @@ CONFIG_MTD=y
- # 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_CMDLINE_PARTS=y
+ /* --------------------------------------------------------------------
+- *  LEDs
++ *  RTT
++ * -------------------------------------------------------------------- */
++
++static struct resource rtt_resources[] = {
++	{
++		.start	= AT91_BASE_SYS + AT91_RTT,
++		.end	= AT91_BASE_SYS + AT91_RTT + SZ_16 - 1,
++		.flags	= IORESOURCE_MEM,
++	}
++};
++
++static struct platform_device at91sam9261_rtt_device = {
++	.name		= "at91_rtt",
++	.id		= -1,
++	.resource	= rtt_resources,
++	.num_resources	= ARRAY_SIZE(rtt_resources),
++};
++
++static void __init at91_add_device_rtt(void)
++{
++	platform_device_register(&at91sam9261_rtt_device);
++}
++
++
++/* --------------------------------------------------------------------
++ *  Watchdog
++ * -------------------------------------------------------------------- */
++
++#if defined(CONFIG_AT91SAM9_WATCHDOG) || defined(CONFIG_AT91SAM9_WATCHDOG_MODULE)
++static struct platform_device at91sam9261_wdt_device = {
++	.name		= "at91_wdt",
++	.id		= -1,
++	.num_resources	= 0,
++};
++
++static void __init at91_add_device_watchdog(void)
++{
++	platform_device_register(&at91sam9261_wdt_device);
++}
++#else
++static void __init at91_add_device_watchdog(void) {}
++#endif
++
++
++/* --------------------------------------------------------------------
++ *  SSC -- Synchronous Serial Controller
+  * -------------------------------------------------------------------- */
  
- #
- # User Modules And Translation Layers
-@@ -529,8 +533,8 @@ CONFIG_MTD_BLOCK=y
- #
- # RAM/ROM/Flash chip drivers
- #
--# CONFIG_MTD_CFI is not set
--CONFIG_MTD_JEDECPROBE=m
-+CONFIG_MTD_CFI=m
-+# CONFIG_MTD_JEDECPROBE is not set
- CONFIG_MTD_GEN_PROBE=m
- # CONFIG_MTD_CFI_ADV_OPTIONS is not set
- CONFIG_MTD_MAP_BANK_WIDTH_1=y
-@@ -544,9 +548,9 @@ 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_AMDSTD=m
- # CONFIG_MTD_CFI_STAA is not set
--CONFIG_MTD_MW320D=m
-+CONFIG_MTD_CFI_UTIL=m
- CONFIG_MTD_RAM=y
- CONFIG_MTD_ROM=m
- # CONFIG_MTD_ABSENT is not set
-@@ -554,12 +558,11 @@ CONFIG_MTD_ROM=m
- #
- # Mapping drivers for chip access
- #
--CONFIG_MTD_COMPLEX_MAPPINGS=y
--# CONFIG_MTD_PHYSMAP is not set
--# CONFIG_MTD_EZKIT561 is not set
--CONFIG_MTD_BF5xx=m
--CONFIG_BFIN_FLASH_SIZE=0x0400000
--CONFIG_EBIU_FLASH_BASE=0x20000000
-+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
-+CONFIG_MTD_PHYSMAP=m
-+CONFIG_MTD_PHYSMAP_START=0x20000000
-+CONFIG_MTD_PHYSMAP_LEN=0x0
-+CONFIG_MTD_PHYSMAP_BANKWIDTH=2
- # CONFIG_MTD_UCLINUX is not set
- # CONFIG_MTD_PLATRAM is not set
+-#if defined(CONFIG_LEDS)
+-u8 at91_leds_cpu;
+-u8 at91_leds_timer;
++#if defined(CONFIG_ATMEL_SSC) || defined(CONFIG_ATMEL_SSC_MODULE)
++static u64 ssc0_dmamask = DMA_BIT_MASK(32);
++
++static struct resource ssc0_resources[] = {
++	[0] = {
++		.start	= AT91SAM9261_BASE_SSC0,
++		.end	= AT91SAM9261_BASE_SSC0 + SZ_16K - 1,
++		.flags	= IORESOURCE_MEM,
++	},
++	[1] = {
++		.start	= AT91SAM9261_ID_SSC0,
++		.end	= AT91SAM9261_ID_SSC0,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device at91sam9261_ssc0_device = {
++	.name	= "ssc",
++	.id	= 0,
++	.dev	= {
++		.dma_mask		= &ssc0_dmamask,
++		.coherent_dma_mask	= DMA_BIT_MASK(32),
++	},
++	.resource	= ssc0_resources,
++	.num_resources	= ARRAY_SIZE(ssc0_resources),
++};
++
++static inline void configure_ssc0_pins(unsigned pins)
++{
++	if (pins & ATMEL_SSC_TF)
++		at91_set_A_periph(AT91_PIN_PB21, 1);
++	if (pins & ATMEL_SSC_TK)
++		at91_set_A_periph(AT91_PIN_PB22, 1);
++	if (pins & ATMEL_SSC_TD)
++		at91_set_A_periph(AT91_PIN_PB23, 1);
++	if (pins & ATMEL_SSC_RD)
++		at91_set_A_periph(AT91_PIN_PB24, 1);
++	if (pins & ATMEL_SSC_RK)
++		at91_set_A_periph(AT91_PIN_PB25, 1);
++	if (pins & ATMEL_SSC_RF)
++		at91_set_A_periph(AT91_PIN_PB26, 1);
++}
++
++static u64 ssc1_dmamask = DMA_BIT_MASK(32);
++
++static struct resource ssc1_resources[] = {
++	[0] = {
++		.start	= AT91SAM9261_BASE_SSC1,
++		.end	= AT91SAM9261_BASE_SSC1 + SZ_16K - 1,
++		.flags	= IORESOURCE_MEM,
++	},
++	[1] = {
++		.start	= AT91SAM9261_ID_SSC1,
++		.end	= AT91SAM9261_ID_SSC1,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device at91sam9261_ssc1_device = {
++	.name	= "ssc",
++	.id	= 1,
++	.dev	= {
++		.dma_mask		= &ssc1_dmamask,
++		.coherent_dma_mask	= DMA_BIT_MASK(32),
++	},
++	.resource	= ssc1_resources,
++	.num_resources	= ARRAY_SIZE(ssc1_resources),
++};
++
++static inline void configure_ssc1_pins(unsigned pins)
++{
++	if (pins & ATMEL_SSC_TF)
++		at91_set_B_periph(AT91_PIN_PA17, 1);
++	if (pins & ATMEL_SSC_TK)
++		at91_set_B_periph(AT91_PIN_PA18, 1);
++	if (pins & ATMEL_SSC_TD)
++		at91_set_B_periph(AT91_PIN_PA19, 1);
++	if (pins & ATMEL_SSC_RD)
++		at91_set_B_periph(AT91_PIN_PA20, 1);
++	if (pins & ATMEL_SSC_RK)
++		at91_set_B_periph(AT91_PIN_PA21, 1);
++	if (pins & ATMEL_SSC_RF)
++		at91_set_B_periph(AT91_PIN_PA22, 1);
++}
++
++static u64 ssc2_dmamask = DMA_BIT_MASK(32);
++
++static struct resource ssc2_resources[] = {
++	[0] = {
++		.start	= AT91SAM9261_BASE_SSC2,
++		.end	= AT91SAM9261_BASE_SSC2 + SZ_16K - 1,
++		.flags	= IORESOURCE_MEM,
++	},
++	[1] = {
++		.start	= AT91SAM9261_ID_SSC2,
++		.end	= AT91SAM9261_ID_SSC2,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device at91sam9261_ssc2_device = {
++	.name	= "ssc",
++	.id	= 2,
++	.dev	= {
++		.dma_mask		= &ssc2_dmamask,
++		.coherent_dma_mask	= DMA_BIT_MASK(32),
++	},
++	.resource	= ssc2_resources,
++	.num_resources	= ARRAY_SIZE(ssc2_resources),
++};
++
++static inline void configure_ssc2_pins(unsigned pins)
++{
++	if (pins & ATMEL_SSC_TF)
++		at91_set_B_periph(AT91_PIN_PC25, 1);
++	if (pins & ATMEL_SSC_TK)
++		at91_set_B_periph(AT91_PIN_PC26, 1);
++	if (pins & ATMEL_SSC_TD)
++		at91_set_B_periph(AT91_PIN_PC27, 1);
++	if (pins & ATMEL_SSC_RD)
++		at91_set_B_periph(AT91_PIN_PC28, 1);
++	if (pins & ATMEL_SSC_RK)
++		at91_set_B_periph(AT91_PIN_PC29, 1);
++	if (pins & ATMEL_SSC_RF)
++		at91_set_B_periph(AT91_PIN_PC30, 1);
++}
+ 
+-void __init at91_init_leds(u8 cpu_led, u8 timer_led)
++/*
++ * SSC controllers are accessed through library code, instead of any
++ * kind of all-singing/all-dancing driver.  For example one could be
++ * used by a particular I2S audio codec's driver, while another one
++ * on the same system might be used by a custom data capture driver.
++ */
++void __init at91_add_device_ssc(unsigned id, unsigned pins)
+ {
+-	/* Enable GPIO to access the LEDs */
+-	at91_set_gpio_output(cpu_led, 1);
+-	at91_set_gpio_output(timer_led, 1);
++	struct platform_device *pdev;
++
++	/*
++	 * NOTE: caller is responsible for passing information matching
++	 * "pins" to whatever will be using each particular controller.
++	 */
++	switch (id) {
++	case AT91SAM9261_ID_SSC0:
++		pdev = &at91sam9261_ssc0_device;
++		configure_ssc0_pins(pins);
++		at91_clock_associate("ssc0_clk", &pdev->dev, "pclk");
++		break;
++	case AT91SAM9261_ID_SSC1:
++		pdev = &at91sam9261_ssc1_device;
++		configure_ssc1_pins(pins);
++		at91_clock_associate("ssc1_clk", &pdev->dev, "pclk");
++		break;
++	case AT91SAM9261_ID_SSC2:
++		pdev = &at91sam9261_ssc2_device;
++		configure_ssc2_pins(pins);
++		at91_clock_associate("ssc2_clk", &pdev->dev, "pclk");
++		break;
++	default:
++		return;
++	}
  
-@@ -647,8 +650,8 @@ CONFIG_SMC91X=y
- # CONFIG_SMSC911X is not set
- # CONFIG_DM9000 is not set
- CONFIG_NETDEV_1000=y
--CONFIG_NETDEV_10000=y
- # CONFIG_AX88180 is not set
-+CONFIG_NETDEV_10000=y
+-	at91_leds_cpu	= cpu_led;
+-	at91_leds_timer	= timer_led;
++	platform_device_register(pdev);
+ }
++
+ #else
+-void __init at91_init_leds(u8 cpu_led, u8 timer_led) {}
++void __init at91_add_device_ssc(unsigned id, unsigned pins) {}
+ #endif
  
- #
- # Wireless LAN
-@@ -717,7 +720,6 @@ CONFIG_INPUT_EVDEV=m
- # CONFIG_BFIN_SPORT is not set
- # CONFIG_BFIN_TIMER_LATENCY is not set
- # CONFIG_AD5304 is not set
--# CONFIG_BF5xx_FBDMA is not set
- # CONFIG_VT is not set
- # CONFIG_SERIAL_NONSTANDARD is not set
  
-diff --git a/arch/blackfin/kernel/Makefile b/arch/blackfin/kernel/Makefile
-index 8a4cfb2..318b9b6 100644
---- a/arch/blackfin/kernel/Makefile
-+++ b/arch/blackfin/kernel/Makefile
-@@ -7,7 +7,7 @@ extra-y := init_task.o vmlinux.lds
- obj-y := \
- 	entry.o process.o bfin_ksyms.o ptrace.o setup.o signal.o \
- 	sys_bfin.o time.o traps.o irqchip.o dma-mapping.o flat.o \
--	fixed_code.o cplbinit.o cacheinit.o reboot.o bfin_gpio.o
-+	fixed_code.o reboot.o bfin_gpio.o
+@@ -584,12 +789,15 @@ static struct atmel_uart_data dbgu_data = {
+ 	.regs		= (void __iomem *)(AT91_VA_BASE_SYS + AT91_DBGU),
+ };
  
- obj-$(CONFIG_BFIN_GPTIMERS)          += gptimers.o
- obj-$(CONFIG_MODULES)                += module.o
-diff --git a/arch/blackfin/kernel/bfin_dma_5xx.c b/arch/blackfin/kernel/bfin_dma_5xx.c
-index b544460..fa9debe 100644
---- a/arch/blackfin/kernel/bfin_dma_5xx.c
-+++ b/arch/blackfin/kernel/bfin_dma_5xx.c
-@@ -339,13 +339,13 @@ EXPORT_SYMBOL(set_dma_config);
++static u64 dbgu_dmamask = DMA_BIT_MASK(32);
++
+ static struct platform_device at91sam9261_dbgu_device = {
+ 	.name		= "atmel_usart",
+ 	.id		= 0,
+ 	.dev		= {
+-				.platform_data	= &dbgu_data,
+-				.coherent_dma_mask = 0xffffffff,
++				.dma_mask		= &dbgu_dmamask,
++				.coherent_dma_mask	= DMA_BIT_MASK(32),
++				.platform_data		= &dbgu_data,
+ 	},
+ 	.resource	= dbgu_resources,
+ 	.num_resources	= ARRAY_SIZE(dbgu_resources),
+@@ -619,23 +827,29 @@ static struct atmel_uart_data uart0_data = {
+ 	.use_dma_rx	= 1,
+ };
+ 
++static u64 uart0_dmamask = DMA_BIT_MASK(32);
++
+ static struct platform_device at91sam9261_uart0_device = {
+ 	.name		= "atmel_usart",
+ 	.id		= 1,
+ 	.dev		= {
+-				.platform_data	= &uart0_data,
+-				.coherent_dma_mask = 0xffffffff,
++				.dma_mask		= &uart0_dmamask,
++				.coherent_dma_mask	= DMA_BIT_MASK(32),
++				.platform_data		= &uart0_data,
+ 	},
+ 	.resource	= uart0_resources,
+ 	.num_resources	= ARRAY_SIZE(uart0_resources),
+ };
  
- unsigned short
- set_bfin_dma_config(char direction, char flow_mode,
--		    char intr_mode, char dma_mode, char width)
-+		    char intr_mode, char dma_mode, char width, char syncmode)
+-static inline void configure_usart0_pins(void)
++static inline void configure_usart0_pins(unsigned pins)
  {
- 	unsigned short config;
- 
- 	config =
- 	    ((direction << 1) | (width << 2) | (dma_mode << 4) |
--	     (intr_mode << 6) | (flow_mode << 12) | RESTART);
-+	     (intr_mode << 6) | (flow_mode << 12) | (syncmode << 5));
- 	return config;
- }
- EXPORT_SYMBOL(set_bfin_dma_config);
-diff --git a/arch/blackfin/kernel/bfin_gpio.c b/arch/blackfin/kernel/bfin_gpio.c
-index ce85d4b..6bbe0a2 100644
---- a/arch/blackfin/kernel/bfin_gpio.c
-+++ b/arch/blackfin/kernel/bfin_gpio.c
-@@ -7,7 +7,7 @@
-  * Description:  GPIO Abstraction Layer
-  *
-  * Modified:
-- *               Copyright 2007 Analog Devices Inc.
-+ *               Copyright 2008 Analog Devices Inc.
-  *
-  * Bugs:         Enter bugs at http://blackfin.uclinux.org/
-  *
-@@ -83,6 +83,7 @@
- #include <linux/delay.h>
- #include <linux/module.h>
- #include <linux/err.h>
-+#include <linux/proc_fs.h>
- #include <asm/blackfin.h>
- #include <asm/gpio.h>
- #include <asm/portmux.h>
-@@ -136,7 +137,6 @@ static unsigned short *port_fer[gpio_bank(MAX_BLACKFIN_GPIOS)] = {
- 	(unsigned short *) PORTG_FER,
- 	(unsigned short *) PORTH_FER,
+ 	at91_set_A_periph(AT91_PIN_PC8, 1);		/* TXD0 */
+ 	at91_set_A_periph(AT91_PIN_PC9, 0);		/* RXD0 */
+-	at91_set_A_periph(AT91_PIN_PC10, 0);		/* RTS0 */
+-	at91_set_A_periph(AT91_PIN_PC11, 0);		/* CTS0 */
++
++	if (pins & ATMEL_UART_RTS)
++		at91_set_A_periph(AT91_PIN_PC10, 0);	/* RTS0 */
++	if (pins & ATMEL_UART_CTS)
++		at91_set_A_periph(AT91_PIN_PC11, 0);	/* CTS0 */
+ }
+ 
+ static struct resource uart1_resources[] = {
+@@ -656,21 +870,29 @@ static struct atmel_uart_data uart1_data = {
+ 	.use_dma_rx	= 1,
+ };
+ 
++static u64 uart1_dmamask = DMA_BIT_MASK(32);
++
+ static struct platform_device at91sam9261_uart1_device = {
+ 	.name		= "atmel_usart",
+ 	.id		= 2,
+ 	.dev		= {
+-				.platform_data	= &uart1_data,
+-				.coherent_dma_mask = 0xffffffff,
++				.dma_mask		= &uart1_dmamask,
++				.coherent_dma_mask	= DMA_BIT_MASK(32),
++				.platform_data		= &uart1_data,
+ 	},
+ 	.resource	= uart1_resources,
+ 	.num_resources	= ARRAY_SIZE(uart1_resources),
  };
--
- #endif
- 
- #ifdef BF527_FAMILY
-@@ -178,15 +178,13 @@ static struct gpio_port_t *gpio_array[gpio_bank(MAX_BLACKFIN_GPIOS)] = {
- #endif
- 
- static unsigned short reserved_gpio_map[gpio_bank(MAX_BLACKFIN_GPIOS)];
--static unsigned short reserved_peri_map[gpio_bank(MAX_BLACKFIN_GPIOS + 16)];
-+static unsigned short reserved_peri_map[gpio_bank(MAX_RESOURCES)];
  
--#define MAX_RESOURCES 		256
- #define RESOURCE_LABEL_SIZE 	16
+-static inline void configure_usart1_pins(void)
++static inline void configure_usart1_pins(unsigned pins)
+ {
+ 	at91_set_A_periph(AT91_PIN_PC12, 1);		/* TXD1 */
+ 	at91_set_A_periph(AT91_PIN_PC13, 0);		/* RXD1 */
++
++	if (pins & ATMEL_UART_RTS)
++		at91_set_B_periph(AT91_PIN_PA12, 0);	/* RTS1 */
++	if (pins & ATMEL_UART_CTS)
++		at91_set_B_periph(AT91_PIN_PA13, 0);	/* CTS1 */
+ }
  
--struct str_ident {
-+static struct str_ident {
- 	char name[RESOURCE_LABEL_SIZE];
--} *str_ident;
--
-+} str_ident[MAX_RESOURCES];
+ static struct resource uart2_resources[] = {
+@@ -691,27 +913,35 @@ static struct atmel_uart_data uart2_data = {
+ 	.use_dma_rx	= 1,
+ };
  
- #ifdef CONFIG_PM
- static unsigned short wakeup_map[gpio_bank(MAX_BLACKFIN_GPIOS)];
-@@ -212,7 +210,7 @@ static unsigned int sic_iwr_irqs[gpio_bank(MAX_BLACKFIN_GPIOS)] = {IRQ_PROG0_INT
- #endif /* CONFIG_PM */
++static u64 uart2_dmamask = DMA_BIT_MASK(32);
++
+ static struct platform_device at91sam9261_uart2_device = {
+ 	.name		= "atmel_usart",
+ 	.id		= 3,
+ 	.dev		= {
+-				.platform_data	= &uart2_data,
+-				.coherent_dma_mask = 0xffffffff,
++				.dma_mask		= &uart2_dmamask,
++				.coherent_dma_mask	= DMA_BIT_MASK(32),
++				.platform_data		= &uart2_data,
+ 	},
+ 	.resource	= uart2_resources,
+ 	.num_resources	= ARRAY_SIZE(uart2_resources),
+ };
  
- #if defined(BF548_FAMILY)
--inline int check_gpio(unsigned short gpio)
-+inline int check_gpio(unsigned gpio)
- {
- 	if (gpio == GPIO_PB15 || gpio == GPIO_PC14 || gpio == GPIO_PC15
- 	    || gpio == GPIO_PH14 || gpio == GPIO_PH15
-@@ -222,7 +220,7 @@ inline int check_gpio(unsigned short gpio)
- 	return 0;
- }
- #else
--inline int check_gpio(unsigned short gpio)
-+inline int check_gpio(unsigned gpio)
+-static inline void configure_usart2_pins(void)
++static inline void configure_usart2_pins(unsigned pins)
  {
- 	if (gpio >= MAX_BLACKFIN_GPIOS)
- 		return -EINVAL;
-@@ -230,9 +228,13 @@ inline int check_gpio(unsigned short gpio)
+ 	at91_set_A_periph(AT91_PIN_PC15, 0);		/* RXD2 */
+ 	at91_set_A_periph(AT91_PIN_PC14, 1);		/* TXD2 */
++
++	if (pins & ATMEL_UART_RTS)
++		at91_set_B_periph(AT91_PIN_PA15, 0);	/* RTS2*/
++	if (pins & ATMEL_UART_CTS)
++		at91_set_B_periph(AT91_PIN_PA16, 0);	/* CTS2 */
  }
- #endif
  
--static void set_label(unsigned short ident, const char *label)
-+void gpio_error(unsigned gpio)
+-struct platform_device *at91_uarts[ATMEL_MAX_UART];	/* the UARTs to use */
++static struct platform_device *at91_uarts[ATMEL_MAX_UART];	/* the UARTs to use */
+ struct platform_device *atmel_default_console_device;	/* the serial console device */
+ 
+-void __init at91_init_serial(struct at91_uart_config *config)
++void __init __deprecated at91_init_serial(struct at91_uart_config *config)
  {
-+	printk(KERN_ERR "bfin-gpio: GPIO %d wasn't requested!\n", gpio);
-+}
+ 	int i;
  
-+static void set_label(unsigned short ident, const char *label)
-+{
- 	if (label && str_ident) {
- 		strncpy(str_ident[ident].name, label,
- 			 RESOURCE_LABEL_SIZE);
-@@ -250,6 +252,11 @@ static char *get_label(unsigned short ident)
+@@ -719,17 +949,17 @@ void __init at91_init_serial(struct at91_uart_config *config)
+ 	for (i = 0; i < config->nr_tty; i++) {
+ 		switch (config->tty_map[i]) {
+ 			case 0:
+-				configure_usart0_pins();
++				configure_usart0_pins(ATMEL_UART_CTS | ATMEL_UART_RTS);
+ 				at91_uarts[i] = &at91sam9261_uart0_device;
+ 				at91_clock_associate("usart0_clk", &at91sam9261_uart0_device.dev, "usart");
+ 				break;
+ 			case 1:
+-				configure_usart1_pins();
++				configure_usart1_pins(0);
+ 				at91_uarts[i] = &at91sam9261_uart1_device;
+ 				at91_clock_associate("usart1_clk", &at91sam9261_uart1_device.dev, "usart");
+ 				break;
+ 			case 2:
+-				configure_usart2_pins();
++				configure_usart2_pins(0);
+ 				at91_uarts[i] = &at91sam9261_uart2_device;
+ 				at91_clock_associate("usart2_clk", &at91sam9261_uart2_device.dev, "usart");
+ 				break;
+@@ -751,6 +981,48 @@ void __init at91_init_serial(struct at91_uart_config *config)
+ 		printk(KERN_INFO "AT91: No default serial console defined.\n");
+ }
  
- static int cmp_label(unsigned short ident, const char *label)
- {
-+	if (label == NULL) {
-+		dump_stack();
-+		printk(KERN_ERR "Please provide none-null label\n");
++void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins)
++{
++	struct platform_device *pdev;
++
++	switch (id) {
++		case 0:		/* DBGU */
++			pdev = &at91sam9261_dbgu_device;
++			configure_dbgu_pins();
++			at91_clock_associate("mck", &pdev->dev, "usart");
++			break;
++		case AT91SAM9261_ID_US0:
++			pdev = &at91sam9261_uart0_device;
++			configure_usart0_pins(pins);
++			at91_clock_associate("usart0_clk", &pdev->dev, "usart");
++			break;
++		case AT91SAM9261_ID_US1:
++			pdev = &at91sam9261_uart1_device;
++			configure_usart1_pins(pins);
++			at91_clock_associate("usart1_clk", &pdev->dev, "usart");
++			break;
++		case AT91SAM9261_ID_US2:
++			pdev = &at91sam9261_uart2_device;
++			configure_usart2_pins(pins);
++			at91_clock_associate("usart2_clk", &pdev->dev, "usart");
++			break;
++		default:
++			return;
 +	}
++	pdev->id = portnr;		/* update to mapped ID */
 +
- 	if (label && str_ident)
- 		return strncmp(str_ident[ident].name,
- 				 label, strlen(label));
-@@ -258,7 +265,7 @@ static int cmp_label(unsigned short ident, const char *label)
- }
- 
- #if defined(BF527_FAMILY) || defined(BF537_FAMILY)
--static void port_setup(unsigned short gpio, unsigned short usage)
-+static void port_setup(unsigned gpio, unsigned short usage)
++	if (portnr < ATMEL_MAX_UART)
++		at91_uarts[portnr] = pdev;
++}
++
++void __init at91_set_serial_console(unsigned portnr)
++{
++	if (portnr < ATMEL_MAX_UART)
++		atmel_default_console_device = at91_uarts[portnr];
++	if (!atmel_default_console_device)
++		printk(KERN_INFO "AT91: No default serial console defined.\n");
++}
++
+ void __init at91_add_device_serial(void)
  {
- 	if (!check_gpio(gpio)) {
- 		if (usage == GPIO_USAGE)
-@@ -269,7 +276,7 @@ static void port_setup(unsigned short gpio, unsigned short usage)
+ 	int i;
+@@ -761,7 +1033,9 @@ void __init at91_add_device_serial(void)
  	}
  }
- #elif defined(BF548_FAMILY)
--static void port_setup(unsigned short gpio, unsigned short usage)
-+static void port_setup(unsigned gpio, unsigned short usage)
- {
- 	if (usage == GPIO_USAGE)
- 		gpio_array[gpio_bank(gpio)]->port_fer &= ~gpio_bit(gpio);
-@@ -390,7 +397,7 @@ inline void portmux_setup(unsigned short portno, unsigned short function)
+ #else
+-void __init at91_init_serial(struct at91_uart_config *config) {}
++void __init __deprecated at91_init_serial(struct at91_uart_config *config) {}
++void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins) {}
++void __init at91_set_serial_console(unsigned portnr) {}
+ void __init at91_add_device_serial(void) {}
  #endif
  
- #ifndef BF548_FAMILY
--static void default_gpio(unsigned short gpio)
-+static void default_gpio(unsigned gpio)
+@@ -774,6 +1048,8 @@ void __init at91_add_device_serial(void) {}
+  */
+ static int __init at91_add_standard_devices(void)
  {
- 	unsigned short bank, bitmask;
- 	unsigned long flags;
-@@ -410,7 +417,6 @@ static void default_gpio(unsigned short gpio)
- 	gpio_bankb[bank]->edge &= ~bitmask;
- 	AWA_DUMMY_READ(edge);
- 	local_irq_restore(flags);
--
++	at91_add_device_rtt();
++	at91_add_device_watchdog();
+ 	return 0;
  }
- #else
- # define default_gpio(...)  do { } while (0)
-@@ -418,12 +424,6 @@ static void default_gpio(unsigned short gpio)
- 
- static int __init bfin_gpio_init(void)
- {
--	str_ident = kcalloc(MAX_RESOURCES,
--				 sizeof(struct str_ident), GFP_KERNEL);
--	if (str_ident == NULL)
--		return -ENOMEM;
--
--	memset(str_ident, 0, MAX_RESOURCES * sizeof(struct str_ident));
- 
- 	printk(KERN_INFO "Blackfin GPIO Controller\n");
  
-@@ -454,10 +454,9 @@ arch_initcall(bfin_gpio_init);
- /* Set a specific bit */
+diff --git a/arch/arm/mach-at91/at91sam9263.c b/arch/arm/mach-at91/at91sam9263.c
+index 00e27b1..a53ba0f 100644
+--- a/arch/arm/mach-at91/at91sam9263.c
++++ b/arch/arm/mach-at91/at91sam9263.c
+@@ -304,34 +304,34 @@ void __init at91sam9263_initialize(unsigned long main_clock)
+ static unsigned int at91sam9263_default_irq_priority[NR_AIC_IRQS] __initdata = {
+ 	7,	/* Advanced Interrupt Controller (FIQ) */
+ 	7,	/* System Peripherals */
+-	0,	/* Parallel IO Controller A */
+-	0,	/* Parallel IO Controller B */
+-	0,	/* Parallel IO Controller C, D and E */
++	1,	/* Parallel IO Controller A */
++	1,	/* Parallel IO Controller B */
++	1,	/* Parallel IO Controller C, D and E */
+ 	0,
+ 	0,
+-	6,	/* USART 0 */
+-	6,	/* USART 1 */
+-	6,	/* USART 2 */
++	5,	/* USART 0 */
++	5,	/* USART 1 */
++	5,	/* USART 2 */
+ 	0,	/* Multimedia Card Interface 0 */
+ 	0,	/* Multimedia Card Interface 1 */
+-	4,	/* CAN */
+-	0,	/* Two-Wire Interface */
+-	6,	/* Serial Peripheral Interface 0 */
+-	6,	/* Serial Peripheral Interface 1 */
+-	5,	/* Serial Synchronous Controller 0 */
+-	5,	/* Serial Synchronous Controller 1 */
+-	6,	/* AC97 Controller */
++	3,	/* CAN */
++	6,	/* Two-Wire Interface */
++	5,	/* Serial Peripheral Interface 0 */
++	5,	/* Serial Peripheral Interface 1 */
++	4,	/* Serial Synchronous Controller 0 */
++	4,	/* Serial Synchronous Controller 1 */
++	5,	/* AC97 Controller */
+ 	0,	/* Timer Counter 0, 1 and 2 */
+ 	0,	/* Pulse Width Modulation Controller */
+ 	3,	/* Ethernet */
+ 	0,
+ 	0,	/* 2D Graphic Engine */
+-	3,	/* USB Device Port */
++	2,	/* USB Device Port */
+ 	0,	/* Image Sensor Interface */
+ 	3,	/* LDC Controller */
+ 	0,	/* DMA Controller */
+ 	0,
+-	3,	/* USB Host port */
++	2,	/* USB Host port */
+ 	0,	/* Advanced Interrupt Controller (IRQ0) */
+ 	0,	/* Advanced Interrupt Controller (IRQ1) */
+ };
+diff --git a/arch/arm/mach-at91/at91sam9263_devices.c b/arch/arm/mach-at91/at91sam9263_devices.c
+index ac329a9..0b12e1a 100644
+--- a/arch/arm/mach-at91/at91sam9263_devices.c
++++ b/arch/arm/mach-at91/at91sam9263_devices.c
+@@ -12,6 +12,7 @@
+ #include <asm/mach/arch.h>
+ #include <asm/mach/map.h>
  
- #define SET_GPIO(name) \
--void set_gpio_ ## name(unsigned short gpio, unsigned short arg) \
-+void set_gpio_ ## name(unsigned gpio, unsigned short arg) \
- { \
- 	unsigned long flags; \
--	BUG_ON(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio))); \
- 	local_irq_save(flags); \
- 	if (arg) \
- 		gpio_bankb[gpio_bank(gpio)]->name |= gpio_bit(gpio); \
-@@ -477,10 +476,9 @@ SET_GPIO(both)
++#include <linux/dma-mapping.h>
+ #include <linux/platform_device.h>
+ #include <linux/i2c-gpio.h>
  
- #if ANOMALY_05000311 || ANOMALY_05000323
- #define SET_GPIO_SC(name) \
--void set_gpio_ ## name(unsigned short gpio, unsigned short arg) \
-+void set_gpio_ ## name(unsigned gpio, unsigned short arg) \
- { \
- 	unsigned long flags; \
--	BUG_ON(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio))); \
- 	local_irq_save(flags); \
- 	if (arg) \
- 		gpio_bankb[gpio_bank(gpio)]->name ## _set = gpio_bit(gpio); \
-@@ -492,9 +490,8 @@ void set_gpio_ ## name(unsigned short gpio, unsigned short arg) \
- EXPORT_SYMBOL(set_gpio_ ## name);
- #else
- #define SET_GPIO_SC(name) \
--void set_gpio_ ## name(unsigned short gpio, unsigned short arg) \
-+void set_gpio_ ## name(unsigned gpio, unsigned short arg) \
- { \
--	BUG_ON(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio))); \
- 	if (arg) \
- 		gpio_bankb[gpio_bank(gpio)]->name ## _set = gpio_bit(gpio); \
- 	else \
-@@ -508,19 +505,17 @@ SET_GPIO_SC(maskb)
- SET_GPIO_SC(data)
+@@ -32,7 +33,7 @@
+  * -------------------------------------------------------------------- */
  
- #if ANOMALY_05000311 || ANOMALY_05000323
--void set_gpio_toggle(unsigned short gpio)
-+void set_gpio_toggle(unsigned gpio)
- {
- 	unsigned long flags;
--	BUG_ON(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio)));
- 	local_irq_save(flags);
- 	gpio_bankb[gpio_bank(gpio)]->toggle = gpio_bit(gpio);
- 	AWA_DUMMY_READ(toggle);
- 	local_irq_restore(flags);
- }
- #else
--void set_gpio_toggle(unsigned short gpio)
-+void set_gpio_toggle(unsigned gpio)
- {
--	BUG_ON(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio)));
- 	gpio_bankb[gpio_bank(gpio)]->toggle = gpio_bit(gpio);
- }
- #endif
-@@ -531,7 +526,7 @@ EXPORT_SYMBOL(set_gpio_toggle);
+ #if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
+-static u64 ohci_dmamask = 0xffffffffUL;
++static u64 ohci_dmamask = DMA_BIT_MASK(32);
+ static struct at91_usbh_data usbh_data;
+ 
+ static struct resource usbh_resources[] = {
+@@ -53,7 +54,7 @@ static struct platform_device at91_usbh_device = {
+ 	.id		= -1,
+ 	.dev		= {
+ 				.dma_mask		= &ohci_dmamask,
+-				.coherent_dma_mask	= 0xffffffff,
++				.coherent_dma_mask	= DMA_BIT_MASK(32),
+ 				.platform_data		= &usbh_data,
+ 	},
+ 	.resource	= usbh_resources,
+@@ -136,7 +137,7 @@ void __init at91_add_device_udc(struct at91_udc_data *data) {}
+  * -------------------------------------------------------------------- */
+ 
+ #if defined(CONFIG_MACB) || defined(CONFIG_MACB_MODULE)
+-static u64 eth_dmamask = 0xffffffffUL;
++static u64 eth_dmamask = DMA_BIT_MASK(32);
+ static struct at91_eth_data eth_data;
+ 
+ static struct resource eth_resources[] = {
+@@ -157,7 +158,7 @@ static struct platform_device at91sam9263_eth_device = {
+ 	.id		= -1,
+ 	.dev		= {
+ 				.dma_mask		= &eth_dmamask,
+-				.coherent_dma_mask	= 0xffffffff,
++				.coherent_dma_mask	= DMA_BIT_MASK(32),
+ 				.platform_data		= &eth_data,
+ 	},
+ 	.resource	= eth_resources,
+@@ -210,7 +211,7 @@ void __init at91_add_device_eth(struct at91_eth_data *data) {}
+  * -------------------------------------------------------------------- */
+ 
+ #if defined(CONFIG_MMC_AT91) || defined(CONFIG_MMC_AT91_MODULE)
+-static u64 mmc_dmamask = 0xffffffffUL;
++static u64 mmc_dmamask = DMA_BIT_MASK(32);
+ static struct at91_mmc_data mmc0_data, mmc1_data;
  
- #if ANOMALY_05000311 || ANOMALY_05000323
- #define SET_GPIO_P(name) \
--void set_gpiop_ ## name(unsigned short gpio, unsigned short arg) \
-+void set_gpiop_ ## name(unsigned gpio, unsigned short arg) \
- { \
- 	unsigned long flags; \
- 	local_irq_save(flags); \
-@@ -542,7 +537,7 @@ void set_gpiop_ ## name(unsigned short gpio, unsigned short arg) \
- EXPORT_SYMBOL(set_gpiop_ ## name);
- #else
- #define SET_GPIO_P(name) \
--void set_gpiop_ ## name(unsigned short gpio, unsigned short arg) \
-+void set_gpiop_ ## name(unsigned gpio, unsigned short arg) \
- { \
- 	gpio_bankb[gpio_bank(gpio)]->name = arg; \
- } \
-@@ -558,11 +553,10 @@ SET_GPIO_P(both)
- SET_GPIO_P(maska)
- SET_GPIO_P(maskb)
+ static struct resource mmc0_resources[] = {
+@@ -231,7 +232,7 @@ static struct platform_device at91sam9263_mmc0_device = {
+ 	.id		= 0,
+ 	.dev		= {
+ 				.dma_mask		= &mmc_dmamask,
+-				.coherent_dma_mask	= 0xffffffff,
++				.coherent_dma_mask	= DMA_BIT_MASK(32),
+ 				.platform_data		= &mmc0_data,
+ 	},
+ 	.resource	= mmc0_resources,
+@@ -256,7 +257,7 @@ static struct platform_device at91sam9263_mmc1_device = {
+ 	.id		= 1,
+ 	.dev		= {
+ 				.dma_mask		= &mmc_dmamask,
+-				.coherent_dma_mask	= 0xffffffff,
++				.coherent_dma_mask	= DMA_BIT_MASK(32),
+ 				.platform_data		= &mmc1_data,
+ 	},
+ 	.resource	= mmc1_resources,
+@@ -382,7 +383,7 @@ void __init at91_add_device_nand(struct at91_nand_data *data)
+ 		return;
  
--
- /* Get a specific bit */
- #if ANOMALY_05000311 || ANOMALY_05000323
- #define GET_GPIO(name) \
--unsigned short get_gpio_ ## name(unsigned short gpio) \
-+unsigned short get_gpio_ ## name(unsigned gpio) \
- { \
- 	unsigned long flags; \
- 	unsigned short ret; \
-@@ -575,7 +569,7 @@ unsigned short get_gpio_ ## name(unsigned short gpio) \
- EXPORT_SYMBOL(get_gpio_ ## name);
- #else
- #define GET_GPIO(name) \
--unsigned short get_gpio_ ## name(unsigned short gpio) \
-+unsigned short get_gpio_ ## name(unsigned gpio) \
- { \
- 	return (0x01 & (gpio_bankb[gpio_bank(gpio)]->name >> gpio_sub_n(gpio))); \
- } \
-@@ -595,7 +589,7 @@ GET_GPIO(maskb)
+ 	csa = at91_sys_read(AT91_MATRIX_EBI0CSA);
+-	at91_sys_write(AT91_MATRIX_EBI0CSA, csa | AT91_MATRIX_EBI0_CS3A_SMC);
++	at91_sys_write(AT91_MATRIX_EBI0CSA, csa | AT91_MATRIX_EBI0_CS3A_SMC_SMARTMEDIA);
+ 
+ 	/* set the bus interface characteristics */
+ 	at91_sys_write(AT91_SMC_SETUP(3), AT91_SMC_NWESETUP_(0) | AT91_SMC_NCS_WRSETUP_(0)
+@@ -500,7 +501,7 @@ void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices)
+  * -------------------------------------------------------------------- */
+ 
+ #if defined(CONFIG_SPI_ATMEL) || defined(CONFIG_SPI_ATMEL_MODULE)
+-static u64 spi_dmamask = 0xffffffffUL;
++static u64 spi_dmamask = DMA_BIT_MASK(32);
  
- #if ANOMALY_05000311 || ANOMALY_05000323
- #define GET_GPIO_P(name) \
--unsigned short get_gpiop_ ## name(unsigned short gpio) \
-+unsigned short get_gpiop_ ## name(unsigned gpio) \
- { \
- 	unsigned long flags; \
- 	unsigned short ret; \
-@@ -608,7 +602,7 @@ unsigned short get_gpiop_ ## name(unsigned short gpio) \
- EXPORT_SYMBOL(get_gpiop_ ## name);
- #else
- #define GET_GPIO_P(name) \
--unsigned short get_gpiop_ ## name(unsigned short gpio) \
-+unsigned short get_gpiop_ ## name(unsigned gpio) \
- { \
- 	return (gpio_bankb[gpio_bank(gpio)]->name);\
- } \
-@@ -645,7 +639,7 @@ GET_GPIO_P(maskb)
- *************************************************************
- * MODIFICATION HISTORY :
- **************************************************************/
--int gpio_pm_wakeup_request(unsigned short gpio, unsigned char type)
-+int gpio_pm_wakeup_request(unsigned gpio, unsigned char type)
- {
- 	unsigned long flags;
+ static struct resource spi0_resources[] = {
+ 	[0] = {
+@@ -520,7 +521,7 @@ static struct platform_device at91sam9263_spi0_device = {
+ 	.id		= 0,
+ 	.dev		= {
+ 				.dma_mask		= &spi_dmamask,
+-				.coherent_dma_mask	= 0xffffffff,
++				.coherent_dma_mask	= DMA_BIT_MASK(32),
+ 	},
+ 	.resource	= spi0_resources,
+ 	.num_resources	= ARRAY_SIZE(spi0_resources),
+@@ -546,7 +547,7 @@ static struct platform_device at91sam9263_spi1_device = {
+ 	.id		= 1,
+ 	.dev		= {
+ 				.dma_mask		= &spi_dmamask,
+-				.coherent_dma_mask	= 0xffffffff,
++				.coherent_dma_mask	= DMA_BIT_MASK(32),
+ 	},
+ 	.resource	= spi1_resources,
+ 	.num_resources	= ARRAY_SIZE(spi1_resources),
+@@ -612,7 +613,7 @@ void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices)
+  * -------------------------------------------------------------------- */
+ 
+ #if defined(CONFIG_SND_AT91_AC97) || defined(CONFIG_SND_AT91_AC97_MODULE)
+-static u64 ac97_dmamask = 0xffffffffUL;
++static u64 ac97_dmamask = DMA_BIT_MASK(32);
+ static struct atmel_ac97_data ac97_data;
+ 
+ static struct resource ac97_resources[] = {
+@@ -633,7 +634,7 @@ static struct platform_device at91sam9263_ac97_device = {
+ 	.id		= 1,
+ 	.dev		= {
+ 				.dma_mask		= &ac97_dmamask,
+-				.coherent_dma_mask	= 0xffffffff,
++				.coherent_dma_mask	= DMA_BIT_MASK(32),
+ 				.platform_data		= &ac97_data,
+ 	},
+ 	.resource	= ac97_resources,
+@@ -667,7 +668,7 @@ void __init at91_add_device_ac97(struct atmel_ac97_data *data) {}
+  * -------------------------------------------------------------------- */
+ 
+ #if defined(CONFIG_FB_ATMEL) || defined(CONFIG_FB_ATMEL_MODULE)
+-static u64 lcdc_dmamask = 0xffffffffUL;
++static u64 lcdc_dmamask = DMA_BIT_MASK(32);
+ static struct atmel_lcdfb_info lcdc_data;
  
-@@ -653,7 +647,6 @@ int gpio_pm_wakeup_request(unsigned short gpio, unsigned char type)
- 		return -EINVAL;
+ static struct resource lcdc_resources[] = {
+@@ -688,7 +689,7 @@ static struct platform_device at91_lcdc_device = {
+ 	.id		= 0,
+ 	.dev		= {
+ 				.dma_mask		= &lcdc_dmamask,
+-				.coherent_dma_mask	= 0xffffffff,
++				.coherent_dma_mask	= DMA_BIT_MASK(32),
+ 				.platform_data		= &lcdc_data,
+ 	},
+ 	.resource	= lcdc_resources,
+@@ -732,24 +733,242 @@ void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data) {}
  
- 	local_irq_save(flags);
--
- 	wakeup_map[gpio_bank(gpio)] |= gpio_bit(gpio);
- 	wakeup_flags_map[gpio] = type;
- 	local_irq_restore(flags);
-@@ -662,7 +655,7 @@ int gpio_pm_wakeup_request(unsigned short gpio, unsigned char type)
- }
- EXPORT_SYMBOL(gpio_pm_wakeup_request);
  
--void gpio_pm_wakeup_free(unsigned short gpio)
-+void gpio_pm_wakeup_free(unsigned gpio)
- {
- 	unsigned long flags;
+ /* --------------------------------------------------------------------
+- *  LEDs
++ *  Image Sensor Interface
+  * -------------------------------------------------------------------- */
+ 
+-#if defined(CONFIG_LEDS)
+-u8 at91_leds_cpu;
+-u8 at91_leds_timer;
++#if defined(CONFIG_VIDEO_AT91_ISI) || defined(CONFIG_VIDEO_AT91_ISI_MODULE)
  
-@@ -677,7 +670,7 @@ void gpio_pm_wakeup_free(unsigned short gpio)
- }
- EXPORT_SYMBOL(gpio_pm_wakeup_free);
- 
--static int bfin_gpio_wakeup_type(unsigned short gpio, unsigned char type)
-+static int bfin_gpio_wakeup_type(unsigned gpio, unsigned char type)
- {
- 	port_setup(gpio, GPIO_USAGE);
- 	set_gpio_dir(gpio, 0);
-@@ -784,6 +777,14 @@ void gpio_pm_restore(void)
- }
- 
- #endif
-+#else /* BF548_FAMILY */
+-void __init at91_init_leds(u8 cpu_led, u8 timer_led)
++struct resource isi_resources[] = {
++	[0] = {
++		.start	= AT91SAM9263_BASE_ISI,
++		.end	= AT91SAM9263_BASE_ISI + SZ_16K - 1,
++		.flags	= IORESOURCE_MEM,
++	},
++	[1] = {
++		.start	= AT91SAM9263_ID_ISI,
++		.end	= AT91SAM9263_ID_ISI,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
 +
-+unsigned short get_gpio_dir(unsigned gpio)
++static struct platform_device at91sam9263_isi_device = {
++	.name		= "at91_isi",
++	.id		= -1,
++	.resource	= isi_resources,
++	.num_resources	= ARRAY_SIZE(isi_resources),
++};
++
++void __init at91_add_device_isi(void)
 +{
-+	return (0x01 & (gpio_array[gpio_bank(gpio)]->port_dir_clear >> gpio_sub_n(gpio)));
++	at91_set_A_periph(AT91_PIN_PE0, 0);	/* ISI_D0 */
++	at91_set_A_periph(AT91_PIN_PE1, 0);	/* ISI_D1 */
++	at91_set_A_periph(AT91_PIN_PE2, 0);	/* ISI_D2 */
++	at91_set_A_periph(AT91_PIN_PE3, 0);	/* ISI_D3 */
++	at91_set_A_periph(AT91_PIN_PE4, 0);	/* ISI_D4 */
++	at91_set_A_periph(AT91_PIN_PE5, 0);	/* ISI_D5 */
++	at91_set_A_periph(AT91_PIN_PE6, 0);	/* ISI_D6 */
++	at91_set_A_periph(AT91_PIN_PE7, 0);	/* ISI_D7 */
++	at91_set_A_periph(AT91_PIN_PE8, 0);	/* ISI_PCK */
++	at91_set_A_periph(AT91_PIN_PE9, 0);	/* ISI_HSYNC */
++	at91_set_A_periph(AT91_PIN_PE10, 0);	/* ISI_VSYNC */
++	at91_set_B_periph(AT91_PIN_PE11, 0);	/* ISI_MCK (PCK3) */
++	at91_set_B_periph(AT91_PIN_PE12, 0);	/* ISI_PD8 */
++	at91_set_B_periph(AT91_PIN_PE13, 0);	/* ISI_PD9 */
++	at91_set_B_periph(AT91_PIN_PE14, 0);	/* ISI_PD10 */
++	at91_set_B_periph(AT91_PIN_PE15, 0);	/* ISI_PD11 */
 +}
-+EXPORT_SYMBOL(get_gpio_dir);
++#else
++void __init at91_add_device_isi(void) {}
++#endif
 +
- #endif /* BF548_FAMILY */
- 
- /***********************************************************
-@@ -1028,7 +1029,7 @@ EXPORT_SYMBOL(peripheral_free_list);
- * MODIFICATION HISTORY :
- **************************************************************/
- 
--int gpio_request(unsigned short gpio, const char *label)
-+int gpio_request(unsigned gpio, const char *label)
++
++/* --------------------------------------------------------------------
++ *  RTT
++ * -------------------------------------------------------------------- */
++
++static struct resource rtt0_resources[] = {
++	{
++		.start	= AT91_BASE_SYS + AT91_RTT0,
++		.end	= AT91_BASE_SYS + AT91_RTT0 + SZ_16 - 1,
++		.flags	= IORESOURCE_MEM,
++	}
++};
++
++static struct platform_device at91sam9263_rtt0_device = {
++	.name		= "at91_rtt",
++	.id		= 0,
++	.resource	= rtt0_resources,
++	.num_resources	= ARRAY_SIZE(rtt0_resources),
++};
++
++static struct resource rtt1_resources[] = {
++	{
++		.start	= AT91_BASE_SYS + AT91_RTT1,
++		.end	= AT91_BASE_SYS + AT91_RTT1 + SZ_16 - 1,
++		.flags	= IORESOURCE_MEM,
++	}
++};
++
++static struct platform_device at91sam9263_rtt1_device = {
++	.name		= "at91_rtt",
++	.id		= 1,
++	.resource	= rtt1_resources,
++	.num_resources	= ARRAY_SIZE(rtt1_resources),
++};
++
++static void __init at91_add_device_rtt(void)
++{
++	platform_device_register(&at91sam9263_rtt0_device);
++	platform_device_register(&at91sam9263_rtt1_device);
++}
++
++
++/* --------------------------------------------------------------------
++ *  Watchdog
++ * -------------------------------------------------------------------- */
++
++#if defined(CONFIG_AT91SAM9_WATCHDOG) || defined(CONFIG_AT91SAM9_WATCHDOG_MODULE)
++static struct platform_device at91sam9263_wdt_device = {
++	.name		= "at91_wdt",
++	.id		= -1,
++	.num_resources	= 0,
++};
++
++static void __init at91_add_device_watchdog(void)
++{
++	platform_device_register(&at91sam9263_wdt_device);
++}
++#else
++static void __init at91_add_device_watchdog(void) {}
++#endif
++
++
++/* --------------------------------------------------------------------
++ *  SSC -- Synchronous Serial Controller
++ * -------------------------------------------------------------------- */
++
++#if defined(CONFIG_ATMEL_SSC) || defined(CONFIG_ATMEL_SSC_MODULE)
++static u64 ssc0_dmamask = DMA_BIT_MASK(32);
++
++static struct resource ssc0_resources[] = {
++	[0] = {
++		.start	= AT91SAM9263_BASE_SSC0,
++		.end	= AT91SAM9263_BASE_SSC0 + SZ_16K - 1,
++		.flags	= IORESOURCE_MEM,
++	},
++	[1] = {
++		.start	= AT91SAM9263_ID_SSC0,
++		.end	= AT91SAM9263_ID_SSC0,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device at91sam9263_ssc0_device = {
++	.name	= "ssc",
++	.id	= 0,
++	.dev	= {
++		.dma_mask		= &ssc0_dmamask,
++		.coherent_dma_mask	= DMA_BIT_MASK(32),
++	},
++	.resource	= ssc0_resources,
++	.num_resources	= ARRAY_SIZE(ssc0_resources),
++};
++
++static inline void configure_ssc0_pins(unsigned pins)
++{
++	if (pins & ATMEL_SSC_TF)
++		at91_set_B_periph(AT91_PIN_PB0, 1);
++	if (pins & ATMEL_SSC_TK)
++		at91_set_B_periph(AT91_PIN_PB1, 1);
++	if (pins & ATMEL_SSC_TD)
++		at91_set_B_periph(AT91_PIN_PB2, 1);
++	if (pins & ATMEL_SSC_RD)
++		at91_set_B_periph(AT91_PIN_PB3, 1);
++	if (pins & ATMEL_SSC_RK)
++		at91_set_B_periph(AT91_PIN_PB4, 1);
++	if (pins & ATMEL_SSC_RF)
++		at91_set_B_periph(AT91_PIN_PB5, 1);
++}
++
++static u64 ssc1_dmamask = DMA_BIT_MASK(32);
++
++static struct resource ssc1_resources[] = {
++	[0] = {
++		.start	= AT91SAM9263_BASE_SSC1,
++		.end	= AT91SAM9263_BASE_SSC1 + SZ_16K - 1,
++		.flags	= IORESOURCE_MEM,
++	},
++	[1] = {
++		.start	= AT91SAM9263_ID_SSC1,
++		.end	= AT91SAM9263_ID_SSC1,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device at91sam9263_ssc1_device = {
++	.name	= "ssc",
++	.id	= 1,
++	.dev	= {
++		.dma_mask		= &ssc1_dmamask,
++		.coherent_dma_mask	= DMA_BIT_MASK(32),
++	},
++	.resource	= ssc1_resources,
++	.num_resources	= ARRAY_SIZE(ssc1_resources),
++};
++
++static inline void configure_ssc1_pins(unsigned pins)
++{
++	if (pins & ATMEL_SSC_TF)
++		at91_set_A_periph(AT91_PIN_PB6, 1);
++	if (pins & ATMEL_SSC_TK)
++		at91_set_A_periph(AT91_PIN_PB7, 1);
++	if (pins & ATMEL_SSC_TD)
++		at91_set_A_periph(AT91_PIN_PB8, 1);
++	if (pins & ATMEL_SSC_RD)
++		at91_set_A_periph(AT91_PIN_PB9, 1);
++	if (pins & ATMEL_SSC_RK)
++		at91_set_A_periph(AT91_PIN_PB10, 1);
++	if (pins & ATMEL_SSC_RF)
++		at91_set_A_periph(AT91_PIN_PB11, 1);
++}
++
++/*
++ * Return the device node so that board init code can use it as the
++ * parent for the device node reflecting how it's used on this board.
++ *
++ * SSC controllers are accessed through library code, instead of any
++ * kind of all-singing/all-dancing driver.  For example one could be
++ * used by a particular I2S audio codec's driver, while another one
++ * on the same system might be used by a custom data capture driver.
++ */
++void __init at91_add_device_ssc(unsigned id, unsigned pins)
  {
- 	unsigned long flags;
+-	/* Enable GPIO to access the LEDs */
+-	at91_set_gpio_output(cpu_led, 1);
+-	at91_set_gpio_output(timer_led, 1);
++	struct platform_device *pdev;
++
++	/*
++	 * NOTE: caller is responsible for passing information matching
++	 * "pins" to whatever will be using each particular controller.
++	 */
++	switch (id) {
++	case AT91SAM9263_ID_SSC0:
++		pdev = &at91sam9263_ssc0_device;
++		configure_ssc0_pins(pins);
++		at91_clock_associate("ssc0_clk", &pdev->dev, "pclk");
++		break;
++	case AT91SAM9263_ID_SSC1:
++		pdev = &at91sam9263_ssc1_device;
++		configure_ssc1_pins(pins);
++		at91_clock_associate("ssc1_clk", &pdev->dev, "pclk");
++		break;
++	default:
++		return;
++	}
  
-@@ -1075,7 +1076,7 @@ int gpio_request(unsigned short gpio, const char *label)
+-	at91_leds_cpu	= cpu_led;
+-	at91_leds_timer	= timer_led;
++	platform_device_register(pdev);
  }
- EXPORT_SYMBOL(gpio_request);
- 
--void gpio_free(unsigned short gpio)
-+void gpio_free(unsigned gpio)
- {
- 	unsigned long flags;
++
+ #else
+-void __init at91_init_leds(u8 cpu_led, u8 timer_led) {}
++void __init at91_add_device_ssc(unsigned id, unsigned pins) {}
+ #endif
  
-@@ -1085,7 +1086,7 @@ void gpio_free(unsigned short gpio)
- 	local_irq_save(flags);
  
- 	if (unlikely(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio)))) {
--		printk(KERN_ERR "bfin-gpio: GPIO %d wasn't reserved!\n", gpio);
-+		gpio_error(gpio);
- 		dump_stack();
- 		local_irq_restore(flags);
- 		return;
-@@ -1101,44 +1102,55 @@ void gpio_free(unsigned short gpio)
- }
- EXPORT_SYMBOL(gpio_free);
+@@ -778,12 +997,15 @@ static struct atmel_uart_data dbgu_data = {
+ 	.regs		= (void __iomem *)(AT91_VA_BASE_SYS + AT91_DBGU),
+ };
  
++static u64 dbgu_dmamask = DMA_BIT_MASK(32);
 +
- #ifdef BF548_FAMILY
--void gpio_direction_input(unsigned short gpio)
-+int gpio_direction_input(unsigned gpio)
+ static struct platform_device at91sam9263_dbgu_device = {
+ 	.name		= "atmel_usart",
+ 	.id		= 0,
+ 	.dev		= {
+-				.platform_data	= &dbgu_data,
+-				.coherent_dma_mask = 0xffffffff,
++				.dma_mask		= &dbgu_dmamask,
++				.coherent_dma_mask	= DMA_BIT_MASK(32),
++				.platform_data		= &dbgu_data,
+ 	},
+ 	.resource	= dbgu_resources,
+ 	.num_resources	= ARRAY_SIZE(dbgu_resources),
+@@ -813,23 +1035,29 @@ static struct atmel_uart_data uart0_data = {
+ 	.use_dma_rx	= 1,
+ };
+ 
++static u64 uart0_dmamask = DMA_BIT_MASK(32);
++
+ static struct platform_device at91sam9263_uart0_device = {
+ 	.name		= "atmel_usart",
+ 	.id		= 1,
+ 	.dev		= {
+-				.platform_data	= &uart0_data,
+-				.coherent_dma_mask = 0xffffffff,
++				.dma_mask		= &uart0_dmamask,
++				.coherent_dma_mask	= DMA_BIT_MASK(32),
++				.platform_data		= &uart0_data,
+ 	},
+ 	.resource	= uart0_resources,
+ 	.num_resources	= ARRAY_SIZE(uart0_resources),
+ };
+ 
+-static inline void configure_usart0_pins(void)
++static inline void configure_usart0_pins(unsigned pins)
  {
- 	unsigned long flags;
+ 	at91_set_A_periph(AT91_PIN_PA26, 1);		/* TXD0 */
+ 	at91_set_A_periph(AT91_PIN_PA27, 0);		/* RXD0 */
+-	at91_set_A_periph(AT91_PIN_PA28, 0);		/* RTS0 */
+-	at91_set_A_periph(AT91_PIN_PA29, 0);		/* CTS0 */
++
++	if (pins & ATMEL_UART_RTS)
++		at91_set_A_periph(AT91_PIN_PA28, 0);	/* RTS0 */
++	if (pins & ATMEL_UART_CTS)
++		at91_set_A_periph(AT91_PIN_PA29, 0);	/* CTS0 */
+ }
+ 
+ static struct resource uart1_resources[] = {
+@@ -850,23 +1078,29 @@ static struct atmel_uart_data uart1_data = {
+ 	.use_dma_rx	= 1,
+ };
+ 
++static u64 uart1_dmamask = DMA_BIT_MASK(32);
++
+ static struct platform_device at91sam9263_uart1_device = {
+ 	.name		= "atmel_usart",
+ 	.id		= 2,
+ 	.dev		= {
+-				.platform_data	= &uart1_data,
+-				.coherent_dma_mask = 0xffffffff,
++				.dma_mask		= &uart1_dmamask,
++				.coherent_dma_mask	= DMA_BIT_MASK(32),
++				.platform_data		= &uart1_data,
+ 	},
+ 	.resource	= uart1_resources,
+ 	.num_resources	= ARRAY_SIZE(uart1_resources),
+ };
  
--	BUG_ON(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio)));
-+	if (!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio))) {
-+		gpio_error(gpio);
-+		return -EINVAL;
-+	}
+-static inline void configure_usart1_pins(void)
++static inline void configure_usart1_pins(unsigned pins)
+ {
+ 	at91_set_A_periph(AT91_PIN_PD0, 1);		/* TXD1 */
+ 	at91_set_A_periph(AT91_PIN_PD1, 0);		/* RXD1 */
+-	at91_set_B_periph(AT91_PIN_PD7, 0);		/* RTS1 */
+-	at91_set_B_periph(AT91_PIN_PD8, 0);		/* CTS1 */
++
++	if (pins & ATMEL_UART_RTS)
++		at91_set_B_periph(AT91_PIN_PD7, 0);	/* RTS1 */
++	if (pins & ATMEL_UART_CTS)
++		at91_set_B_periph(AT91_PIN_PD8, 0);	/* CTS1 */
+ }
+ 
+ static struct resource uart2_resources[] = {
+@@ -887,29 +1121,35 @@ static struct atmel_uart_data uart2_data = {
+ 	.use_dma_rx	= 1,
+ };
+ 
++static u64 uart2_dmamask = DMA_BIT_MASK(32);
++
+ static struct platform_device at91sam9263_uart2_device = {
+ 	.name		= "atmel_usart",
+ 	.id		= 3,
+ 	.dev		= {
+-				.platform_data	= &uart2_data,
+-				.coherent_dma_mask = 0xffffffff,
++				.dma_mask		= &uart2_dmamask,
++				.coherent_dma_mask	= DMA_BIT_MASK(32),
++				.platform_data		= &uart2_data,
+ 	},
+ 	.resource	= uart2_resources,
+ 	.num_resources	= ARRAY_SIZE(uart2_resources),
+ };
  
- 	local_irq_save(flags);
- 	gpio_array[gpio_bank(gpio)]->port_dir_clear = gpio_bit(gpio);
- 	gpio_array[gpio_bank(gpio)]->port_inen |= gpio_bit(gpio);
- 	local_irq_restore(flags);
+-static inline void configure_usart2_pins(void)
++static inline void configure_usart2_pins(unsigned pins)
+ {
+ 	at91_set_A_periph(AT91_PIN_PD2, 1);		/* TXD2 */
+ 	at91_set_A_periph(AT91_PIN_PD3, 0);		/* RXD2 */
+-	at91_set_B_periph(AT91_PIN_PD5, 0);		/* RTS2 */
+-	at91_set_B_periph(AT91_PIN_PD6, 0);		/* CTS2 */
 +
-+	return 0;
++	if (pins & ATMEL_UART_RTS)
++		at91_set_B_periph(AT91_PIN_PD5, 0);	/* RTS2 */
++	if (pins & ATMEL_UART_CTS)
++		at91_set_B_periph(AT91_PIN_PD6, 0);	/* CTS2 */
  }
- EXPORT_SYMBOL(gpio_direction_input);
  
--void gpio_direction_output(unsigned short gpio)
-+int gpio_direction_output(unsigned gpio, int value)
- {
- 	unsigned long flags;
+-struct platform_device *at91_uarts[ATMEL_MAX_UART];	/* the UARTs to use */
++static struct platform_device *at91_uarts[ATMEL_MAX_UART];	/* the UARTs to use */
+ struct platform_device *atmel_default_console_device;	/* the serial console device */
  
--	BUG_ON(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio)));
-+	if (!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio))) {
-+		gpio_error(gpio);
-+		return -EINVAL;
-+	}
+-void __init at91_init_serial(struct at91_uart_config *config)
++void __init __deprecated at91_init_serial(struct at91_uart_config *config)
+ {
+ 	int i;
  
- 	local_irq_save(flags);
- 	gpio_array[gpio_bank(gpio)]->port_inen &= ~gpio_bit(gpio);
-+	gpio_set_value(gpio, value);
- 	gpio_array[gpio_bank(gpio)]->port_dir_set = gpio_bit(gpio);
- 	local_irq_restore(flags);
-+
-+	return 0;
+@@ -917,17 +1157,17 @@ void __init at91_init_serial(struct at91_uart_config *config)
+ 	for (i = 0; i < config->nr_tty; i++) {
+ 		switch (config->tty_map[i]) {
+ 			case 0:
+-				configure_usart0_pins();
++				configure_usart0_pins(ATMEL_UART_CTS | ATMEL_UART_RTS);
+ 				at91_uarts[i] = &at91sam9263_uart0_device;
+ 				at91_clock_associate("usart0_clk", &at91sam9263_uart0_device.dev, "usart");
+ 				break;
+ 			case 1:
+-				configure_usart1_pins();
++				configure_usart1_pins(ATMEL_UART_CTS | ATMEL_UART_RTS);
+ 				at91_uarts[i] = &at91sam9263_uart1_device;
+ 				at91_clock_associate("usart1_clk", &at91sam9263_uart1_device.dev, "usart");
+ 				break;
+ 			case 2:
+-				configure_usart2_pins();
++				configure_usart2_pins(ATMEL_UART_CTS | ATMEL_UART_RTS);
+ 				at91_uarts[i] = &at91sam9263_uart2_device;
+ 				at91_clock_associate("usart2_clk", &at91sam9263_uart2_device.dev, "usart");
+ 				break;
+@@ -949,6 +1189,48 @@ void __init at91_init_serial(struct at91_uart_config *config)
+ 		printk(KERN_INFO "AT91: No default serial console defined.\n");
  }
- EXPORT_SYMBOL(gpio_direction_output);
  
--void gpio_set_value(unsigned short gpio, unsigned short arg)
-+void gpio_set_value(unsigned gpio, int arg)
++void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins)
++{
++	struct platform_device *pdev;
++
++	switch (id) {
++		case 0:		/* DBGU */
++			pdev = &at91sam9263_dbgu_device;
++			configure_dbgu_pins();
++			at91_clock_associate("mck", &pdev->dev, "usart");
++			break;
++		case AT91SAM9263_ID_US0:
++			pdev = &at91sam9263_uart0_device;
++			configure_usart0_pins(pins);
++			at91_clock_associate("usart0_clk", &pdev->dev, "usart");
++			break;
++		case AT91SAM9263_ID_US1:
++			pdev = &at91sam9263_uart1_device;
++			configure_usart1_pins(pins);
++			at91_clock_associate("usart1_clk", &pdev->dev, "usart");
++			break;
++		case AT91SAM9263_ID_US2:
++			pdev = &at91sam9263_uart2_device;
++			configure_usart2_pins(pins);
++			at91_clock_associate("usart2_clk", &pdev->dev, "usart");
++			break;
++		default:
++			return;
++	}
++	pdev->id = portnr;		/* update to mapped ID */
++
++	if (portnr < ATMEL_MAX_UART)
++		at91_uarts[portnr] = pdev;
++}
++
++void __init at91_set_serial_console(unsigned portnr)
++{
++	if (portnr < ATMEL_MAX_UART)
++		atmel_default_console_device = at91_uarts[portnr];
++	if (!atmel_default_console_device)
++		printk(KERN_INFO "AT91: No default serial console defined.\n");
++}
++
+ void __init at91_add_device_serial(void)
  {
- 	if (arg)
- 		gpio_array[gpio_bank(gpio)]->port_set = gpio_bit(gpio);
- 	else
- 		gpio_array[gpio_bank(gpio)]->port_clear = gpio_bit(gpio);
--
+ 	int i;
+@@ -960,6 +1242,8 @@ void __init at91_add_device_serial(void)
  }
- EXPORT_SYMBOL(gpio_set_value);
+ #else
+ void __init at91_init_serial(struct at91_uart_config *config) {}
++void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins) {}
++void __init at91_set_serial_console(unsigned portnr) {}
+ void __init at91_add_device_serial(void) {}
+ #endif
  
--unsigned short gpio_get_value(unsigned short gpio)
-+int gpio_get_value(unsigned gpio)
+@@ -971,6 +1255,8 @@ void __init at91_add_device_serial(void) {}
+  */
+ static int __init at91_add_standard_devices(void)
  {
- 	return (1 & (gpio_array[gpio_bank(gpio)]->port_data >> gpio_sub_n(gpio)));
++	at91_add_device_rtt();
++	at91_add_device_watchdog();
+ 	return 0;
  }
-@@ -1146,31 +1158,47 @@ EXPORT_SYMBOL(gpio_get_value);
  
- #else
- 
--void gpio_direction_input(unsigned short gpio)
-+int gpio_direction_input(unsigned gpio)
- {
- 	unsigned long flags;
+diff --git a/arch/arm/mach-at91/at91sam9rl_devices.c b/arch/arm/mach-at91/at91sam9rl_devices.c
+index 2bd60a3..f43b5c3 100644
+--- a/arch/arm/mach-at91/at91sam9rl_devices.c
++++ b/arch/arm/mach-at91/at91sam9rl_devices.c
+@@ -9,6 +9,7 @@
+ #include <asm/mach/arch.h>
+ #include <asm/mach/map.h>
  
--	BUG_ON(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio)));
-+	if (!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio))) {
-+		gpio_error(gpio);
-+		return -EINVAL;
-+	}
++#include <linux/dma-mapping.h>
+ #include <linux/platform_device.h>
+ #include <linux/i2c-gpio.h>
  
- 	local_irq_save(flags);
- 	gpio_bankb[gpio_bank(gpio)]->dir &= ~gpio_bit(gpio);
- 	gpio_bankb[gpio_bank(gpio)]->inen |= gpio_bit(gpio);
- 	AWA_DUMMY_READ(inen);
- 	local_irq_restore(flags);
-+
-+	return 0;
- }
- EXPORT_SYMBOL(gpio_direction_input);
+@@ -29,7 +30,7 @@
+  * -------------------------------------------------------------------- */
  
--void gpio_direction_output(unsigned short gpio)
-+int gpio_direction_output(unsigned gpio, int value)
- {
- 	unsigned long flags;
+ #if defined(CONFIG_MMC_AT91) || defined(CONFIG_MMC_AT91_MODULE)
+-static u64 mmc_dmamask = 0xffffffffUL;
++static u64 mmc_dmamask = DMA_BIT_MASK(32);
+ static struct at91_mmc_data mmc_data;
+ 
+ static struct resource mmc_resources[] = {
+@@ -50,7 +51,7 @@ static struct platform_device at91sam9rl_mmc_device = {
+ 	.id		= -1,
+ 	.dev		= {
+ 				.dma_mask		= &mmc_dmamask,
+-				.coherent_dma_mask	= 0xffffffff,
++				.coherent_dma_mask	= DMA_BIT_MASK(32),
+ 				.platform_data		= &mmc_data,
+ 	},
+ 	.resource	= mmc_resources,
+@@ -247,7 +248,7 @@ void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices)
+  * -------------------------------------------------------------------- */
+ 
+ #if defined(CONFIG_SPI_ATMEL) || defined(CONFIG_SPI_ATMEL_MODULE)
+-static u64 spi_dmamask = 0xffffffffUL;
++static u64 spi_dmamask = DMA_BIT_MASK(32);
  
--	BUG_ON(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio)));
-+	if (!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio))) {
-+		gpio_error(gpio);
-+		return -EINVAL;
-+	}
+ static struct resource spi_resources[] = {
+ 	[0] = {
+@@ -267,7 +268,7 @@ static struct platform_device at91sam9rl_spi_device = {
+ 	.id		= 0,
+ 	.dev		= {
+ 				.dma_mask		= &spi_dmamask,
+-				.coherent_dma_mask	= 0xffffffff,
++				.coherent_dma_mask	= DMA_BIT_MASK(32),
+ 	},
+ 	.resource	= spi_resources,
+ 	.num_resources	= ARRAY_SIZE(spi_resources),
+@@ -312,7 +313,7 @@ void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices)
+  * -------------------------------------------------------------------- */
+ 
+ #if defined(CONFIG_FB_ATMEL) || defined(CONFIG_FB_ATMEL_MODULE)
+-static u64 lcdc_dmamask = 0xffffffffUL;
++static u64 lcdc_dmamask = DMA_BIT_MASK(32);
+ static struct atmel_lcdfb_info lcdc_data;
  
- 	local_irq_save(flags);
- 	gpio_bankb[gpio_bank(gpio)]->inen &= ~gpio_bit(gpio);
-+
-+	if (value)
-+		gpio_bankb[gpio_bank(gpio)]->data_set = gpio_bit(gpio);
-+	else
-+		gpio_bankb[gpio_bank(gpio)]->data_clear = gpio_bit(gpio);
-+
- 	gpio_bankb[gpio_bank(gpio)]->dir |= gpio_bit(gpio);
- 	AWA_DUMMY_READ(dir);
- 	local_irq_restore(flags);
-+
-+	return 0;
- }
- EXPORT_SYMBOL(gpio_direction_output);
+ static struct resource lcdc_resources[] = {
+@@ -340,7 +341,7 @@ static struct platform_device at91_lcdc_device = {
+ 	.id		= 0,
+ 	.dev		= {
+ 				.dma_mask		= &lcdc_dmamask,
+-				.coherent_dma_mask	= 0xffffffff,
++				.coherent_dma_mask	= DMA_BIT_MASK(32),
+ 				.platform_data		= &lcdc_data,
+ 	},
+ 	.resource	= lcdc_resources,
+@@ -384,24 +385,196 @@ void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data) {}
  
-@@ -1190,7 +1218,40 @@ void bfin_gpio_reset_spi0_ssel1(void)
  
- 	port_setup(gpio, GPIO_USAGE);
- 	gpio_bankb[gpio_bank(gpio)]->data_set = gpio_bit(gpio);
-+	AWA_DUMMY_READ(data_set);
- 	udelay(1);
- }
+ /* --------------------------------------------------------------------
+- *  LEDs
++ *  RTC
+  * -------------------------------------------------------------------- */
+ 
+-#if defined(CONFIG_LEDS)
+-u8 at91_leds_cpu;
+-u8 at91_leds_timer;
++#if defined(CONFIG_RTC_DRV_AT91RM9200) || defined(CONFIG_RTC_DRV_AT91RM9200_MODULE)
++static struct platform_device at91sam9rl_rtc_device = {
++	.name		= "at91_rtc",
++	.id		= -1,
++	.num_resources	= 0,
++};
  
- #endif /*BF548_FAMILY */
+-void __init at91_init_leds(u8 cpu_led, u8 timer_led)
++static void __init at91_add_device_rtc(void)
+ {
+-	/* Enable GPIO to access the LEDs */
+-	at91_set_gpio_output(cpu_led, 1);
+-	at91_set_gpio_output(timer_led, 1);
++	platform_device_register(&at91sam9rl_rtc_device);
++}
++#else
++static void __init at91_add_device_rtc(void) {}
++#endif
 +
-+#if defined(CONFIG_PROC_FS)
-+static int gpio_proc_read(char *buf, char **start, off_t offset,
-+			  int len, int *unused_i, void *unused_v)
-+{
-+	int c, outlen = 0;
 +
-+	for (c = 0; c < MAX_RESOURCES; c++) {
-+		if (!check_gpio(c) && (reserved_gpio_map[gpio_bank(c)] & gpio_bit(c)))
-+			len = sprintf(buf, "GPIO_%d: %s \t\tGPIO %s\n", c,
-+				 get_label(c), get_gpio_dir(c) ? "OUTPUT" : "INPUT");
-+		else if (reserved_peri_map[gpio_bank(c)] & gpio_bit(c))
-+			len = sprintf(buf, "GPIO_%d: %s \t\tPeripheral\n", c, get_label(c));
-+		else
-+			continue;
-+		buf += len;
-+		outlen += len;
++/* --------------------------------------------------------------------
++ *  RTT
++ * -------------------------------------------------------------------- */
++
++static struct resource rtt_resources[] = {
++	{
++		.start	= AT91_BASE_SYS + AT91_RTT,
++		.end	= AT91_BASE_SYS + AT91_RTT + SZ_16 - 1,
++		.flags	= IORESOURCE_MEM,
 +	}
-+	return outlen;
-+}
++};
 +
-+static __init int gpio_register_proc(void)
++static struct platform_device at91sam9rl_rtt_device = {
++	.name		= "at91_rtt",
++	.id		= -1,
++	.resource	= rtt_resources,
++	.num_resources	= ARRAY_SIZE(rtt_resources),
++};
+ 
+-	at91_leds_cpu	= cpu_led;
+-	at91_leds_timer	= timer_led;
++static void __init at91_add_device_rtt(void)
 +{
-+	struct proc_dir_entry *proc_gpio;
-+
-+	proc_gpio = create_proc_entry("gpio", S_IRUGO, NULL);
-+	if (proc_gpio)
-+		proc_gpio->read_proc = gpio_proc_read;
-+	return proc_gpio != NULL;
++	platform_device_register(&at91sam9rl_rtt_device);
 +}
-+__initcall(gpio_register_proc);
-+#endif
-diff --git a/arch/blackfin/kernel/cacheinit.c b/arch/blackfin/kernel/cacheinit.c
-deleted file mode 100644
-index 62cbba7..0000000
---- a/arch/blackfin/kernel/cacheinit.c
-+++ /dev/null
-@@ -1,67 +0,0 @@
--/*
-- *               Copyright 2004-2007 Analog Devices 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, see the file COPYING, or write
-- * to the Free Software Foundation, Inc.,
-- * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
-- */
--
--#include <linux/cpu.h>
--
--#include <asm/cacheflush.h>
--#include <asm/blackfin.h>
--#include <asm/cplb.h>
--#include <asm/cplbinit.h>
--
--#if defined(CONFIG_BFIN_ICACHE)
--void bfin_icache_init(void)
--{
--	unsigned long *table = icplb_table;
--	unsigned long ctrl;
--	int i;
--
--	for (i = 0; i < MAX_CPLBS; i++) {
--		unsigned long addr = *table++;
--		unsigned long data = *table++;
--		if (addr == (unsigned long)-1)
--			break;
--		bfin_write32(ICPLB_ADDR0 + i * 4, addr);
--		bfin_write32(ICPLB_DATA0 + i * 4, data);
--	}
--	ctrl = bfin_read_IMEM_CONTROL();
--	ctrl |= IMC | ENICPLB;
--	bfin_write_IMEM_CONTROL(ctrl);
--}
--#endif
--
--#if defined(CONFIG_BFIN_DCACHE)
--void bfin_dcache_init(void)
--{
--	unsigned long *table = dcplb_table;
--	unsigned long ctrl;
--	int i;
--
--	for (i = 0; i < MAX_CPLBS; i++) {
--		unsigned long addr = *table++;
--		unsigned long data = *table++;
--		if (addr == (unsigned long)-1)
--			break;
--		bfin_write32(DCPLB_ADDR0 + i * 4, addr);
--		bfin_write32(DCPLB_DATA0 + i * 4, data);
--	}
--	ctrl = bfin_read_DMEM_CONTROL();
--	ctrl |= DMEM_CNTR;
--	bfin_write_DMEM_CONTROL(ctrl);
--}
--#endif
-diff --git a/arch/blackfin/kernel/cplb-mpu/Makefile b/arch/blackfin/kernel/cplb-mpu/Makefile
-new file mode 100644
-index 0000000..286b693
---- /dev/null
-+++ b/arch/blackfin/kernel/cplb-mpu/Makefile
-@@ -0,0 +1,8 @@
-+#
-+# arch/blackfin/kernel/cplb-nompu/Makefile
-+#
-+
-+obj-y := cplbinit.o cacheinit.o cplbmgr.o
-+
-+obj-$(CONFIG_CPLB_INFO) += cplbinfo.o
 +
-diff --git a/arch/blackfin/kernel/cplb-mpu/cacheinit.c b/arch/blackfin/kernel/cplb-mpu/cacheinit.c
-new file mode 100644
-index 0000000..9eecfa4
---- /dev/null
-+++ b/arch/blackfin/kernel/cplb-mpu/cacheinit.c
-@@ -0,0 +1,62 @@
-+/*
-+ *               Copyright 2004-2007 Analog Devices 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, see the file COPYING, or write
-+ * to the Free Software Foundation, Inc.,
-+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
-+ */
 +
-+#include <linux/cpu.h>
++/* --------------------------------------------------------------------
++ *  Watchdog
++ * -------------------------------------------------------------------- */
 +
-+#include <asm/cacheflush.h>
-+#include <asm/blackfin.h>
-+#include <asm/cplb.h>
-+#include <asm/cplbinit.h>
++#if defined(CONFIG_AT91SAM9_WATCHDOG) || defined(CONFIG_AT91SAM9_WATCHDOG_MODULE)
++static struct platform_device at91sam9rl_wdt_device = {
++	.name		= "at91_wdt",
++	.id		= -1,
++	.num_resources	= 0,
++};
 +
-+#if defined(CONFIG_BFIN_ICACHE)
-+void bfin_icache_init(void)
++static void __init at91_add_device_watchdog(void)
 +{
-+	unsigned long ctrl;
-+	int i;
-+
-+	SSYNC();
-+	for (i = 0; i < MAX_CPLBS; i++) {
-+		bfin_write32(ICPLB_ADDR0 + i * 4, icplb_tbl[i].addr);
-+		bfin_write32(ICPLB_DATA0 + i * 4, icplb_tbl[i].data);
-+	}
-+	ctrl = bfin_read_IMEM_CONTROL();
-+	ctrl |= IMC | ENICPLB;
-+	bfin_write_IMEM_CONTROL(ctrl);
-+	SSYNC();
-+}
++	platform_device_register(&at91sam9rl_wdt_device);
+ }
+ #else
+-void __init at91_init_leds(u8 cpu_led, u8 timer_led) {}
++static void __init at91_add_device_watchdog(void) {}
 +#endif
 +
-+#if defined(CONFIG_BFIN_DCACHE)
-+void bfin_dcache_init(void)
-+{
-+	unsigned long ctrl;
-+	int i;
 +
-+	SSYNC();
-+	for (i = 0; i < MAX_CPLBS; i++) {
-+		bfin_write32(DCPLB_ADDR0 + i * 4, dcplb_tbl[i].addr);
-+		bfin_write32(DCPLB_DATA0 + i * 4, dcplb_tbl[i].data);
-+	}
++/* --------------------------------------------------------------------
++ *  SSC -- Synchronous Serial Controller
++ * -------------------------------------------------------------------- */
 +
-+	ctrl = bfin_read_DMEM_CONTROL();
-+	ctrl |= DMEM_CNTR;
-+	bfin_write_DMEM_CONTROL(ctrl);
-+	SSYNC();
-+}
-+#endif
-diff --git a/arch/blackfin/kernel/cplb-mpu/cplbinfo.c b/arch/blackfin/kernel/cplb-mpu/cplbinfo.c
-new file mode 100644
-index 0000000..bd07229
---- /dev/null
-+++ b/arch/blackfin/kernel/cplb-mpu/cplbinfo.c
-@@ -0,0 +1,144 @@
-+/*
-+ * File:         arch/blackfin/mach-common/cplbinfo.c
-+ * Based on:
-+ * Author:       Sonic Zhang <sonic.zhang at analog.com>
-+ *
-+ * Created:      Jan. 2005
-+ * Description:  Display CPLB status
-+ *
-+ * Modified:
-+ *               Copyright 2004-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
-+ */
++#if defined(CONFIG_ATMEL_SSC) || defined(CONFIG_ATMEL_SSC_MODULE)
++static u64 ssc0_dmamask = DMA_BIT_MASK(32);
 +
-+#include <linux/module.h>
-+#include <linux/kernel.h>
-+#include <linux/init.h>
-+#include <linux/proc_fs.h>
-+#include <linux/uaccess.h>
++static struct resource ssc0_resources[] = {
++	[0] = {
++		.start	= AT91SAM9RL_BASE_SSC0,
++		.end	= AT91SAM9RL_BASE_SSC0 + SZ_16K - 1,
++		.flags	= IORESOURCE_MEM,
++	},
++	[1] = {
++		.start	= AT91SAM9RL_ID_SSC0,
++		.end	= AT91SAM9RL_ID_SSC0,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
 +
-+#include <asm/current.h>
-+#include <asm/system.h>
-+#include <asm/cplb.h>
-+#include <asm/cplbinit.h>
-+#include <asm/blackfin.h>
++static struct platform_device at91sam9rl_ssc0_device = {
++	.name	= "ssc",
++	.id	= 0,
++	.dev	= {
++		.dma_mask		= &ssc0_dmamask,
++		.coherent_dma_mask	= DMA_BIT_MASK(32),
++	},
++	.resource	= ssc0_resources,
++	.num_resources	= ARRAY_SIZE(ssc0_resources),
++};
 +
-+#define CPLB_I 1
-+#define CPLB_D 2
++static inline void configure_ssc0_pins(unsigned pins)
++{
++	if (pins & ATMEL_SSC_TF)
++		at91_set_A_periph(AT91_PIN_PC0, 1);
++	if (pins & ATMEL_SSC_TK)
++		at91_set_A_periph(AT91_PIN_PC1, 1);
++	if (pins & ATMEL_SSC_TD)
++		at91_set_A_periph(AT91_PIN_PA15, 1);
++	if (pins & ATMEL_SSC_RD)
++		at91_set_A_periph(AT91_PIN_PA16, 1);
++	if (pins & ATMEL_SSC_RK)
++		at91_set_B_periph(AT91_PIN_PA10, 1);
++	if (pins & ATMEL_SSC_RF)
++		at91_set_B_periph(AT91_PIN_PA22, 1);
++}
 +
-+#define SYNC_SYS    SSYNC()
-+#define SYNC_CORE   CSYNC()
++static u64 ssc1_dmamask = DMA_BIT_MASK(32);
 +
-+#define CPLB_BIT_PAGESIZE 0x30000
++static struct resource ssc1_resources[] = {
++	[0] = {
++		.start	= AT91SAM9RL_BASE_SSC1,
++		.end	= AT91SAM9RL_BASE_SSC1 + SZ_16K - 1,
++		.flags	= IORESOURCE_MEM,
++	},
++	[1] = {
++		.start	= AT91SAM9RL_ID_SSC1,
++		.end	= AT91SAM9RL_ID_SSC1,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
 +
-+static char page_size_string_table[][4] = { "1K", "4K", "1M", "4M" };
++static struct platform_device at91sam9rl_ssc1_device = {
++	.name	= "ssc",
++	.id	= 1,
++	.dev	= {
++		.dma_mask		= &ssc1_dmamask,
++		.coherent_dma_mask	= DMA_BIT_MASK(32),
++	},
++	.resource	= ssc1_resources,
++	.num_resources	= ARRAY_SIZE(ssc1_resources),
++};
 +
-+static char *cplb_print_entry(char *buf, struct cplb_entry *tbl, int switched)
++static inline void configure_ssc1_pins(unsigned pins)
 +{
-+	int i;
-+	buf += sprintf(buf, "Index\tAddress\t\tData\tSize\tU/RD\tU/WR\tS/WR\tSwitch\n");
-+	for (i = 0; i < MAX_CPLBS; i++) {
-+		unsigned long data = tbl[i].data;
-+		unsigned long addr = tbl[i].addr;
-+		if (!(data & CPLB_VALID))
-+			continue;
-+
-+		buf +=
-+		    sprintf(buf,
-+			    "%d\t0x%08lx\t%06lx\t%s\t%c\t%c\t%c\t%c\n",
-+			    i, addr, data,
-+			    page_size_string_table[(data & 0x30000) >> 16],
-+			    (data & CPLB_USER_RD) ? 'Y' : 'N',
-+			    (data & CPLB_USER_WR) ? 'Y' : 'N',
-+			    (data & CPLB_SUPV_WR) ? 'Y' : 'N',
-+			    i < switched ? 'N' : 'Y');
-+	}
-+	buf += sprintf(buf, "\n");
-+
-+	return buf;
++	if (pins & ATMEL_SSC_TF)
++		at91_set_B_periph(AT91_PIN_PA29, 1);
++	if (pins & ATMEL_SSC_TK)
++		at91_set_B_periph(AT91_PIN_PA30, 1);
++	if (pins & ATMEL_SSC_TD)
++		at91_set_B_periph(AT91_PIN_PA13, 1);
++	if (pins & ATMEL_SSC_RD)
++		at91_set_B_periph(AT91_PIN_PA14, 1);
++	if (pins & ATMEL_SSC_RK)
++		at91_set_B_periph(AT91_PIN_PA9, 1);
++	if (pins & ATMEL_SSC_RF)
++		at91_set_B_periph(AT91_PIN_PA8, 1);
 +}
 +
-+int cplbinfo_proc_output(char *buf)
++/*
++ * Return the device node so that board init code can use it as the
++ * parent for the device node reflecting how it's used on this board.
++ *
++ * SSC controllers are accessed through library code, instead of any
++ * kind of all-singing/all-dancing driver.  For example one could be
++ * used by a particular I2S audio codec's driver, while another one
++ * on the same system might be used by a custom data capture driver.
++ */
++void __init at91_add_device_ssc(unsigned id, unsigned pins)
 +{
-+	char *p;
++	struct platform_device *pdev;
 +
-+	p = buf;
++	/*
++	 * NOTE: caller is responsible for passing information matching
++	 * "pins" to whatever will be using each particular controller.
++	 */
++	switch (id) {
++	case AT91SAM9RL_ID_SSC0:
++		pdev = &at91sam9rl_ssc0_device;
++		configure_ssc0_pins(pins);
++		at91_clock_associate("ssc0_clk", &pdev->dev, "pclk");
++		break;
++	case AT91SAM9RL_ID_SSC1:
++		pdev = &at91sam9rl_ssc1_device;
++		configure_ssc1_pins(pins);
++		at91_clock_associate("ssc1_clk", &pdev->dev, "pclk");
++		break;
++	default:
++		return;
++	}
 +
-+	p += sprintf(p, "------------------ CPLB Information ------------------\n\n");
++	platform_device_register(pdev);
++}
 +
-+	if (bfin_read_IMEM_CONTROL() & ENICPLB) {
-+		p += sprintf(p, "Instruction CPLB entry:\n");
-+		p = cplb_print_entry(p, icplb_tbl, first_switched_icplb);
-+	} else
-+		p += sprintf(p, "Instruction CPLB is disabled.\n\n");
++#else
++void __init at91_add_device_ssc(unsigned id, unsigned pins) {}
+ #endif
+ 
+ 
+@@ -429,12 +602,15 @@ static struct atmel_uart_data dbgu_data = {
+ 	.regs		= (void __iomem *)(AT91_VA_BASE_SYS + AT91_DBGU),
+ };
+ 
++static u64 dbgu_dmamask = DMA_BIT_MASK(32);
 +
-+	if (1 || bfin_read_DMEM_CONTROL() & ENDCPLB) {
-+		p += sprintf(p, "Data CPLB entry:\n");
-+		p = cplb_print_entry(p, dcplb_tbl, first_switched_dcplb);
-+	} else
-+		p += sprintf(p, "Data CPLB is disabled.\n");
+ static struct platform_device at91sam9rl_dbgu_device = {
+ 	.name		= "atmel_usart",
+ 	.id		= 0,
+ 	.dev		= {
+-				.platform_data	= &dbgu_data,
+-				.coherent_dma_mask = 0xffffffff,
++				.dma_mask		= &dbgu_dmamask,
++				.coherent_dma_mask	= DMA_BIT_MASK(32),
++				.platform_data		= &dbgu_data,
+ 	},
+ 	.resource	= dbgu_resources,
+ 	.num_resources	= ARRAY_SIZE(dbgu_resources),
+@@ -464,23 +640,37 @@ static struct atmel_uart_data uart0_data = {
+ 	.use_dma_rx	= 1,
+ };
+ 
++static u64 uart0_dmamask = DMA_BIT_MASK(32);
++
+ static struct platform_device at91sam9rl_uart0_device = {
+ 	.name		= "atmel_usart",
+ 	.id		= 1,
+ 	.dev		= {
+-				.platform_data	= &uart0_data,
+-				.coherent_dma_mask = 0xffffffff,
++				.dma_mask		= &uart0_dmamask,
++				.coherent_dma_mask	= DMA_BIT_MASK(32),
++				.platform_data		= &uart0_data,
+ 	},
+ 	.resource	= uart0_resources,
+ 	.num_resources	= ARRAY_SIZE(uart0_resources),
+ };
+ 
+-static inline void configure_usart0_pins(void)
++static inline void configure_usart0_pins(unsigned pins)
+ {
+ 	at91_set_A_periph(AT91_PIN_PA6, 1);		/* TXD0 */
+ 	at91_set_A_periph(AT91_PIN_PA7, 0);		/* RXD0 */
+-	at91_set_A_periph(AT91_PIN_PA9, 0);		/* RTS0 */
+-	at91_set_A_periph(AT91_PIN_PA10, 0);		/* CTS0 */
++
++	if (pins & ATMEL_UART_RTS)
++		at91_set_A_periph(AT91_PIN_PA9, 0);	/* RTS0 */
++	if (pins & ATMEL_UART_CTS)
++		at91_set_A_periph(AT91_PIN_PA10, 0);	/* CTS0 */
++	if (pins & ATMEL_UART_DSR)
++		at91_set_A_periph(AT91_PIN_PD14, 0);	/* DSR0 */
++	if (pins & ATMEL_UART_DTR)
++		at91_set_A_periph(AT91_PIN_PD15, 0);	/* DTR0 */
++	if (pins & ATMEL_UART_DCD)
++		at91_set_A_periph(AT91_PIN_PD16, 0);	/* DCD0 */
++	if (pins & ATMEL_UART_RI)
++		at91_set_A_periph(AT91_PIN_PD17, 0);	/* RI0 */
+ }
+ 
+ static struct resource uart1_resources[] = {
+@@ -501,21 +691,29 @@ static struct atmel_uart_data uart1_data = {
+ 	.use_dma_rx	= 1,
+ };
+ 
++static u64 uart1_dmamask = DMA_BIT_MASK(32);
++
+ static struct platform_device at91sam9rl_uart1_device = {
+ 	.name		= "atmel_usart",
+ 	.id		= 2,
+ 	.dev		= {
+-				.platform_data	= &uart1_data,
+-				.coherent_dma_mask = 0xffffffff,
++				.dma_mask		= &uart1_dmamask,
++				.coherent_dma_mask	= DMA_BIT_MASK(32),
++				.platform_data		= &uart1_data,
+ 	},
+ 	.resource	= uart1_resources,
+ 	.num_resources	= ARRAY_SIZE(uart1_resources),
+ };
+ 
+-static inline void configure_usart1_pins(void)
++static inline void configure_usart1_pins(unsigned pins)
+ {
+ 	at91_set_A_periph(AT91_PIN_PA11, 1);		/* TXD1 */
+ 	at91_set_A_periph(AT91_PIN_PA12, 0);		/* RXD1 */
 +
-+	p += sprintf(p, "ICPLB miss: %d\nICPLB supervisor miss: %d\n",
-+		     nr_icplb_miss, nr_icplb_supv_miss);
-+	p += sprintf(p, "DCPLB miss: %d\nDCPLB protection fault:%d\n",
-+		     nr_dcplb_miss, nr_dcplb_prot);
-+	p += sprintf(p, "CPLB flushes: %d\n",
-+		     nr_cplb_flush);
++	if (pins & ATMEL_UART_RTS)
++		at91_set_B_periph(AT91_PIN_PA18, 0);	/* RTS1 */
++	if (pins & ATMEL_UART_CTS)
++		at91_set_B_periph(AT91_PIN_PA19, 0);	/* CTS1 */
+ }
+ 
+ static struct resource uart2_resources[] = {
+@@ -536,21 +734,29 @@ static struct atmel_uart_data uart2_data = {
+ 	.use_dma_rx	= 1,
+ };
+ 
++static u64 uart2_dmamask = DMA_BIT_MASK(32);
 +
-+	return p - buf;
-+}
+ static struct platform_device at91sam9rl_uart2_device = {
+ 	.name		= "atmel_usart",
+ 	.id		= 3,
+ 	.dev		= {
+-				.platform_data	= &uart2_data,
+-				.coherent_dma_mask = 0xffffffff,
++				.dma_mask		= &uart2_dmamask,
++				.coherent_dma_mask	= DMA_BIT_MASK(32),
++				.platform_data		= &uart2_data,
+ 	},
+ 	.resource	= uart2_resources,
+ 	.num_resources	= ARRAY_SIZE(uart2_resources),
+ };
+ 
+-static inline void configure_usart2_pins(void)
++static inline void configure_usart2_pins(unsigned pins)
+ {
+ 	at91_set_A_periph(AT91_PIN_PA13, 1);		/* TXD2 */
+ 	at91_set_A_periph(AT91_PIN_PA14, 0);		/* RXD2 */
 +
-+static int cplbinfo_read_proc(char *page, char **start, off_t off,
-+			      int count, int *eof, void *data)
-+{
-+	int len;
++	if (pins & ATMEL_UART_RTS)
++		at91_set_A_periph(AT91_PIN_PA29, 0);	/* RTS2 */
++	if (pins & ATMEL_UART_CTS)
++		at91_set_A_periph(AT91_PIN_PA30, 0);	/* CTS2 */
+ }
+ 
+ static struct resource uart3_resources[] = {
+@@ -571,27 +777,35 @@ static struct atmel_uart_data uart3_data = {
+ 	.use_dma_rx	= 1,
+ };
+ 
++static u64 uart3_dmamask = DMA_BIT_MASK(32);
 +
-+	len = cplbinfo_proc_output(page);
-+	if (len <= off + count)
-+		*eof = 1;
-+	*start = page + off;
-+	len -= off;
-+	if (len > count)
-+		len = count;
-+	if (len < 0)
-+		len = 0;
-+	return len;
-+}
+ static struct platform_device at91sam9rl_uart3_device = {
+ 	.name		= "atmel_usart",
+ 	.id		= 4,
+ 	.dev		= {
+-				.platform_data	= &uart3_data,
+-				.coherent_dma_mask = 0xffffffff,
++				.dma_mask		= &uart3_dmamask,
++				.coherent_dma_mask	= DMA_BIT_MASK(32),
++				.platform_data		= &uart3_data,
+ 	},
+ 	.resource	= uart3_resources,
+ 	.num_resources	= ARRAY_SIZE(uart3_resources),
+ };
+ 
+-static inline void configure_usart3_pins(void)
++static inline void configure_usart3_pins(unsigned pins)
+ {
+ 	at91_set_A_periph(AT91_PIN_PB0, 1);		/* TXD3 */
+ 	at91_set_A_periph(AT91_PIN_PB1, 0);		/* RXD3 */
 +
-+static int __init cplbinfo_init(void)
++	if (pins & ATMEL_UART_RTS)
++		at91_set_B_periph(AT91_PIN_PD4, 0);	/* RTS3 */
++	if (pins & ATMEL_UART_CTS)
++		at91_set_B_periph(AT91_PIN_PD3, 0);	/* CTS3 */
+ }
+ 
+-struct platform_device *at91_uarts[ATMEL_MAX_UART];	/* the UARTs to use */
++static struct platform_device *at91_uarts[ATMEL_MAX_UART];	/* the UARTs to use */
+ struct platform_device *atmel_default_console_device;	/* the serial console device */
+ 
+-void __init at91_init_serial(struct at91_uart_config *config)
++void __init __deprecated at91_init_serial(struct at91_uart_config *config)
+ {
+ 	int i;
+ 
+@@ -599,22 +813,22 @@ void __init at91_init_serial(struct at91_uart_config *config)
+ 	for (i = 0; i < config->nr_tty; i++) {
+ 		switch (config->tty_map[i]) {
+ 			case 0:
+-				configure_usart0_pins();
++				configure_usart0_pins(ATMEL_UART_CTS | ATMEL_UART_RTS);
+ 				at91_uarts[i] = &at91sam9rl_uart0_device;
+ 				at91_clock_associate("usart0_clk", &at91sam9rl_uart0_device.dev, "usart");
+ 				break;
+ 			case 1:
+-				configure_usart1_pins();
++				configure_usart1_pins(0);
+ 				at91_uarts[i] = &at91sam9rl_uart1_device;
+ 				at91_clock_associate("usart1_clk", &at91sam9rl_uart1_device.dev, "usart");
+ 				break;
+ 			case 2:
+-				configure_usart2_pins();
++				configure_usart2_pins(0);
+ 				at91_uarts[i] = &at91sam9rl_uart2_device;
+ 				at91_clock_associate("usart2_clk", &at91sam9rl_uart2_device.dev, "usart");
+ 				break;
+ 			case 3:
+-				configure_usart3_pins();
++				configure_usart3_pins(0);
+ 				at91_uarts[i] = &at91sam9rl_uart3_device;
+ 				at91_clock_associate("usart3_clk", &at91sam9rl_uart3_device.dev, "usart");
+ 				break;
+@@ -636,6 +850,53 @@ void __init at91_init_serial(struct at91_uart_config *config)
+ 		printk(KERN_INFO "AT91: No default serial console defined.\n");
+ }
+ 
++void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins)
 +{
-+	struct proc_dir_entry *entry;
-+
-+	entry = create_proc_entry("cplbinfo", 0, NULL);
-+	if (!entry)
-+		return -ENOMEM;
++	struct platform_device *pdev;
 +
-+	entry->read_proc = cplbinfo_read_proc;
-+	entry->data = NULL;
++	switch (id) {
++		case 0:		/* DBGU */
++			pdev = &at91sam9rl_dbgu_device;
++			configure_dbgu_pins();
++			at91_clock_associate("mck", &pdev->dev, "usart");
++			break;
++		case AT91SAM9RL_ID_US0:
++			pdev = &at91sam9rl_uart0_device;
++			configure_usart0_pins(pins);
++			at91_clock_associate("usart0_clk", &pdev->dev, "usart");
++			break;
++		case AT91SAM9RL_ID_US1:
++			pdev = &at91sam9rl_uart1_device;
++			configure_usart1_pins(pins);
++			at91_clock_associate("usart1_clk", &pdev->dev, "usart");
++			break;
++		case AT91SAM9RL_ID_US2:
++			pdev = &at91sam9rl_uart2_device;
++			configure_usart2_pins(pins);
++			at91_clock_associate("usart2_clk", &pdev->dev, "usart");
++			break;
++		case AT91SAM9RL_ID_US3:
++			pdev = &at91sam9rl_uart3_device;
++			configure_usart3_pins(pins);
++			at91_clock_associate("usart3_clk", &pdev->dev, "usart");
++			break;
++		default:
++			return;
++	}
++	pdev->id = portnr;		/* update to mapped ID */
 +
-+	return 0;
++	if (portnr < ATMEL_MAX_UART)
++		at91_uarts[portnr] = pdev;
 +}
 +
-+static void __exit cplbinfo_exit(void)
++void __init at91_set_serial_console(unsigned portnr)
 +{
-+	remove_proc_entry("cplbinfo", NULL);
++	if (portnr < ATMEL_MAX_UART)
++		atmel_default_console_device = at91_uarts[portnr];
++	if (!atmel_default_console_device)
++		printk(KERN_INFO "AT91: No default serial console defined.\n");
 +}
 +
-+module_init(cplbinfo_init);
-+module_exit(cplbinfo_exit);
-diff --git a/arch/blackfin/kernel/cplb-mpu/cplbinit.c b/arch/blackfin/kernel/cplb-mpu/cplbinit.c
+ void __init at91_add_device_serial(void)
+ {
+ 	int i;
+@@ -646,7 +907,9 @@ void __init at91_add_device_serial(void)
+ 	}
+ }
+ #else
+-void __init at91_init_serial(struct at91_uart_config *config) {}
++void __init __deprecated at91_init_serial(struct at91_uart_config *config) {}
++void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins) {}
++void __init at91_set_serial_console(unsigned portnr) {}
+ void __init at91_add_device_serial(void) {}
+ #endif
+ 
+@@ -659,6 +922,9 @@ void __init at91_add_device_serial(void) {}
+  */
+ static int __init at91_add_standard_devices(void)
+ {
++	at91_add_device_rtc();
++	at91_add_device_rtt();
++	at91_add_device_watchdog();
+ 	return 0;
+ }
+ 
+diff --git a/arch/arm/mach-at91/board-cap9adk.c b/arch/arm/mach-at91/board-cap9adk.c
 new file mode 100644
-index 0000000..e2e2b50
+index 0000000..1854371
 --- /dev/null
-+++ b/arch/blackfin/kernel/cplb-mpu/cplbinit.c
-@@ -0,0 +1,91 @@
++++ b/arch/arm/mach-at91/board-cap9adk.c
+@@ -0,0 +1,359 @@
 +/*
-+ * Blackfin CPLB initialization
-+ *
-+ *               Copyright 2004-2007 Analog Devices Inc.
++ * linux/arch/arm/mach-at91/board-cap9adk.c
 + *
-+ * Bugs:         Enter bugs at http://blackfin.uclinux.org/
++ *  Copyright (C) 2007 Stelian Pop <stelian.pop at leadtechdesign.com>
++ *  Copyright (C) 2007 Lead Tech Design <www.leadtechdesign.com>
++ *  Copyright (C) 2005 SAN People
++ *  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
@@ -17039,666 +22705,2118 @@
 + * GNU 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
++ * 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/spi/ads7846.h>
++#include <linux/fb.h>
++#include <linux/mtd/physmap.h>
 +
-+#include <asm/blackfin.h>
-+#include <asm/cplb.h>
-+#include <asm/cplbinit.h>
++#include <video/atmel_lcdc.h>
 +
-+struct cplb_entry icplb_tbl[MAX_CPLBS];
-+struct cplb_entry dcplb_tbl[MAX_CPLBS];
++#include <asm/hardware.h>
++#include <asm/setup.h>
++#include <asm/mach-types.h>
++#include <asm/irq.h>
 +
-+int first_switched_icplb, first_switched_dcplb;
-+int first_mask_dcplb;
++#include <asm/mach/arch.h>
++#include <asm/mach/map.h>
++#include <asm/mach/irq.h>
 +
-+void __init generate_cpl_tables(void)
++#include <asm/arch/board.h>
++#include <asm/arch/gpio.h>
++#include <asm/arch/at91cap9_matrix.h>
++#include <asm/arch/at91sam926x_mc.h>
++
++#include "generic.h"
++
++
++static void __init cap9adk_map_io(void)
 +{
-+	int i_d, i_i;
-+	unsigned long addr;
-+	unsigned long d_data, i_data;
-+	unsigned long d_cache = 0, i_cache = 0;
++	/* Initialize processor: 12 MHz crystal */
++	at91cap9_initialize(12000000);
 +
-+#ifdef CONFIG_BFIN_ICACHE
-+	i_cache = CPLB_L1_CHBL | ANOMALY_05000158_WORKAROUND;
-+#endif
++	/* Setup the LEDs: USER1 and USER2 LED for cpu/timer... */
++	at91_init_leds(AT91_PIN_PA10, AT91_PIN_PA11);
++	/* ... POWER LED always on */
++	at91_set_gpio_output(AT91_PIN_PC29, 1);
 +
-+#ifdef CONFIG_BFIN_DCACHE
-+	d_cache = CPLB_L1_CHBL;
-+#ifdef CONFIG_BLKFIN_WT
-+	d_cache |= CPLB_L1_AOW | CPLB_WT;
-+#endif
-+#endif
-+	i_d = i_i = 0;
++	/* Setup the serial ports and console */
++	at91_register_uart(0, 0, 0);		/* DBGU = ttyS0 */
++	at91_set_serial_console(0);
++}
 +
-+	/* Set up the zero page.  */
-+	dcplb_tbl[i_d].addr = 0;
-+	dcplb_tbl[i_d++].data = SDRAM_OOPS | PAGE_SIZE_1KB;
++static void __init cap9adk_init_irq(void)
++{
++	at91cap9_init_interrupts(NULL);
++}
 +
-+#if 0
-+	icplb_tbl[i_i].addr = 0;
-+	icplb_tbl[i_i++].data = i_cache | CPLB_USER_RD | PAGE_SIZE_4KB;
-+#endif
 +
-+	/* Cover kernel memory with 4M pages.  */
-+	addr = 0;
-+	d_data = d_cache | CPLB_SUPV_WR | CPLB_VALID | PAGE_SIZE_4MB | CPLB_DIRTY;
-+	i_data = i_cache | CPLB_VALID | CPLB_PORTPRIO | PAGE_SIZE_4MB;
++/*
++ * USB Host port
++ */
++static struct at91_usbh_data __initdata cap9adk_usbh_data = {
++	.ports		= 2,
++};
 +
-+	for (; addr < memory_start; addr += 4 * 1024 * 1024) {
-+		dcplb_tbl[i_d].addr = addr;
-+		dcplb_tbl[i_d++].data = d_data;
-+		icplb_tbl[i_i].addr = addr;
-+		icplb_tbl[i_i++].data = i_data | (addr == 0 ? CPLB_USER_RD : 0);
-+	}
 +
-+	/* Cover L1 memory.  One 4M area for code and data each is enough.  */
-+#if L1_DATA_A_LENGTH > 0 || L1_DATA_B_LENGTH > 0
-+	dcplb_tbl[i_d].addr = L1_DATA_A_START;
-+	dcplb_tbl[i_d++].data = L1_DMEMORY | PAGE_SIZE_4MB;
-+#endif
-+	icplb_tbl[i_i].addr = L1_CODE_START;
-+	icplb_tbl[i_i++].data = L1_IMEMORY | PAGE_SIZE_4MB;
++/*
++ * ADS7846 Touchscreen
++ */
++#if defined(CONFIG_TOUCHSCREEN_ADS7846) || defined(CONFIG_TOUCHSCREEN_ADS7846_MODULE)
++static int ads7843_pendown_state(void)
++{
++	return !at91_get_gpio_value(AT91_PIN_PC4);	/* Touchscreen PENIRQ */
++}
 +
-+	first_mask_dcplb = i_d;
-+	first_switched_dcplb = i_d + (1 << page_mask_order);
-+	first_switched_icplb = i_i;
++static struct ads7846_platform_data ads_info = {
++	.model			= 7843,
++	.x_min			= 150,
++	.x_max			= 3830,
++	.y_min			= 190,
++	.y_max			= 3830,
++	.vref_delay_usecs	= 100,
++	.x_plate_ohms		= 450,
++	.y_plate_ohms		= 250,
++	.pressure_max		= 15000,
++	.debounce_max		= 1,
++	.debounce_rep		= 0,
++	.debounce_tol		= (~0),
++	.get_pendown_state	= ads7843_pendown_state,
++};
 +
-+	while (i_d < MAX_CPLBS)
-+		dcplb_tbl[i_d++].data = 0;
-+	while (i_i < MAX_CPLBS)
-+		icplb_tbl[i_i++].data = 0;
++static void __init cap9adk_add_device_ts(void)
++{
++	at91_set_gpio_input(AT91_PIN_PC4, 1);	/* Touchscreen PENIRQ */
++	at91_set_gpio_input(AT91_PIN_PC5, 1);	/* Touchscreen BUSY */
 +}
-diff --git a/arch/blackfin/kernel/cplb-mpu/cplbmgr.c b/arch/blackfin/kernel/cplb-mpu/cplbmgr.c
-new file mode 100644
-index 0000000..c426a22
---- /dev/null
-+++ b/arch/blackfin/kernel/cplb-mpu/cplbmgr.c
-@@ -0,0 +1,338 @@
++#else
++static void __init cap9adk_add_device_ts(void) {}
++#endif
++
++
 +/*
-+ *               Blackfin CPLB exception handling.
-+ *               Copyright 2004-2007 Analog Devices 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, see the file COPYING, or write
-+ * to the Free Software Foundation, Inc.,
-+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ * SPI devices.
 + */
-+#include <linux/module.h>
-+#include <linux/mm.h>
++static struct spi_board_info cap9adk_spi_devices[] = {
++#if defined(CONFIG_MTD_AT91_DATAFLASH_CARD)
++	{	/* DataFlash card */
++		.modalias	= "mtd_dataflash",
++		.chip_select	= 0,
++		.max_speed_hz	= 15 * 1000 * 1000,
++		.bus_num	= 0,
++	},
++#endif
++#if defined(CONFIG_TOUCHSCREEN_ADS7846) || defined(CONFIG_TOUCHSCREEN_ADS7846_MODULE)
++	{
++		.modalias	= "ads7846",
++		.chip_select	= 3,		/* can be 2 or 3, depending on J2 jumper */
++		.max_speed_hz	= 125000 * 26,	/* (max sample rate @ 3V) * (cmd + data + overhead) */
++		.bus_num	= 0,
++		.platform_data	= &ads_info,
++		.irq		= AT91_PIN_PC4,
++	},
++#endif
++};
 +
-+#include <asm/blackfin.h>
-+#include <asm/cplbinit.h>
-+#include <asm/mmu_context.h>
 +
-+#ifdef CONFIG_BFIN_ICACHE
++/*
++ * MCI (SD/MMC)
++ */
++static struct at91_mmc_data __initdata cap9adk_mmc_data = {
++	.wire4		= 1,
++//	.det_pin	= ... not connected
++//	.wp_pin		= ... not connected
++//	.vcc_pin	= ... not connected
++};
 +
-+#define FAULT_RW	(1 << 16)
-+#define FAULT_USERSUPV	(1 << 17)
 +
-+int page_mask_nelts;
-+int page_mask_order;
-+unsigned long *current_rwx_mask;
++/*
++ * MACB Ethernet device
++ */
++static struct at91_eth_data __initdata cap9adk_macb_data = {
++	.is_rmii	= 1,
++};
 +
-+int nr_dcplb_miss, nr_icplb_miss, nr_icplb_supv_miss, nr_dcplb_prot;
-+int nr_cplb_flush;
 +
-+static inline void disable_dcplb(void)
-+{
-+	unsigned long ctrl;
-+	SSYNC();
-+	ctrl = bfin_read_DMEM_CONTROL();
-+	ctrl &= ~ENDCPLB;
-+	bfin_write_DMEM_CONTROL(ctrl);
-+	SSYNC();
-+}
++/*
++ * NAND flash
++ */
++static struct mtd_partition __initdata cap9adk_nand_partitions[] = {
++	{
++		.name	= "NAND partition",
++		.offset	= 0,
++		.size	= MTDPART_SIZ_FULL,
++	},
++};
 +
-+static inline void enable_dcplb(void)
++static struct mtd_partition * __init nand_partitions(int size, int *num_partitions)
 +{
-+	unsigned long ctrl;
-+	SSYNC();
-+	ctrl = bfin_read_DMEM_CONTROL();
-+	ctrl |= ENDCPLB;
-+	bfin_write_DMEM_CONTROL(ctrl);
-+	SSYNC();
++	*num_partitions = ARRAY_SIZE(cap9adk_nand_partitions);
++	return cap9adk_nand_partitions;
 +}
 +
-+static inline void disable_icplb(void)
-+{
-+	unsigned long ctrl;
-+	SSYNC();
-+	ctrl = bfin_read_IMEM_CONTROL();
-+	ctrl &= ~ENICPLB;
-+	bfin_write_IMEM_CONTROL(ctrl);
-+	SSYNC();
-+}
++static struct at91_nand_data __initdata cap9adk_nand_data = {
++	.ale		= 21,
++	.cle		= 22,
++//	.det_pin	= ... not connected
++//	.rdy_pin	= ... not connected
++	.enable_pin	= AT91_PIN_PD15,
++	.partition_info	= nand_partitions,
++#if defined(CONFIG_MTD_NAND_AT91_BUSWIDTH_16)
++	.bus_width_16	= 1,
++#else
++	.bus_width_16	= 0,
++#endif
++};
 +
-+static inline void enable_icplb(void)
-+{
-+	unsigned long ctrl;
-+	SSYNC();
-+	ctrl = bfin_read_IMEM_CONTROL();
-+	ctrl |= ENICPLB;
-+	bfin_write_IMEM_CONTROL(ctrl);
-+	SSYNC();
-+}
 +
 +/*
-+ * Given the contents of the status register, return the index of the
-+ * CPLB that caused the fault.
++ * NOR flash
 + */
-+static inline int faulting_cplb_index(int status)
++static struct mtd_partition cap9adk_nor_partitions[] = {
++	{
++		.name		= "NOR partition",
++		.offset		= 0,
++		.size		= MTDPART_SIZ_FULL,
++	},
++};
++
++static struct physmap_flash_data cap9adk_nor_data = {
++	.width		= 2,
++	.parts		= cap9adk_nor_partitions,
++	.nr_parts	= ARRAY_SIZE(cap9adk_nor_partitions),
++};
++
++#define NOR_BASE	AT91_CHIPSELECT_0
++#define NOR_SIZE	0x800000
++
++static struct resource nor_flash_resources[] = {
++	{
++		.start	= NOR_BASE,
++		.end	= NOR_BASE + NOR_SIZE - 1,
++		.flags	= IORESOURCE_MEM,
++	}
++};
++
++static struct platform_device cap9adk_nor_flash = {
++	.name		= "physmap-flash",
++	.id		= 0,
++	.dev		= {
++				.platform_data	= &cap9adk_nor_data,
++	},
++	.resource	= nor_flash_resources,
++	.num_resources	= ARRAY_SIZE(nor_flash_resources),
++};
++
++static __init void cap9adk_add_device_nor(void)
 +{
-+	int signbits = __builtin_bfin_norm_fr1x32(status & 0xFFFF);
-+	return 30 - signbits;
++	unsigned long csa;
++
++	csa = at91_sys_read(AT91_MATRIX_EBICSA);
++	at91_sys_write(AT91_MATRIX_EBICSA, csa | AT91_MATRIX_EBI_VDDIOMSEL_3_3V);
++
++	/* set the bus interface characteristics */
++	at91_sys_write(AT91_SMC_SETUP(0), AT91_SMC_NWESETUP_(4) | AT91_SMC_NCS_WRSETUP_(2)
++			| AT91_SMC_NRDSETUP_(4) | AT91_SMC_NCS_RDSETUP_(2));
++
++	at91_sys_write(AT91_SMC_PULSE(0), AT91_SMC_NWEPULSE_(8) | AT91_SMC_NCS_WRPULSE_(10)
++			| AT91_SMC_NRDPULSE_(8) | AT91_SMC_NCS_RDPULSE_(10));
++
++	at91_sys_write(AT91_SMC_CYCLE(0), AT91_SMC_NWECYCLE_(16) | AT91_SMC_NRDCYCLE_(16));
++
++	at91_sys_write(AT91_SMC_MODE(0), AT91_SMC_READMODE | AT91_SMC_WRITEMODE
++			| AT91_SMC_EXNWMODE_DISABLE | AT91_SMC_BAT_WRITE
++			| AT91_SMC_DBW_16 | AT91_SMC_TDF_(1));
++
++	platform_device_register(&cap9adk_nor_flash);
 +}
 +
++
 +/*
-+ * Given the contents of the status register and the DCPLB_DATA contents,
-+ * return true if a write access should be permitted.
++ * LCD Controller
 + */
-+static inline int write_permitted(int status, unsigned long data)
++#if defined(CONFIG_FB_ATMEL) || defined(CONFIG_FB_ATMEL_MODULE)
++static struct fb_videomode at91_tft_vga_modes[] = {
++	{
++	        .name           = "TX09D50VM1CCA @ 60",
++		.refresh	= 60,
++		.xres		= 240,		.yres		= 320,
++		.pixclock	= KHZ2PICOS(4965),
++
++		.left_margin	= 1,		.right_margin	= 33,
++		.upper_margin	= 1,		.lower_margin	= 0,
++		.hsync_len	= 5,		.vsync_len	= 1,
++
++		.sync		= FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
++		.vmode		= FB_VMODE_NONINTERLACED,
++	},
++};
++
++static struct fb_monspecs at91fb_default_monspecs = {
++	.manufacturer	= "HIT",
++	.monitor        = "TX09D70VM1CCA",
++
++	.modedb		= at91_tft_vga_modes,
++	.modedb_len	= ARRAY_SIZE(at91_tft_vga_modes),
++	.hfmin		= 15000,
++	.hfmax		= 64000,
++	.vfmin		= 50,
++	.vfmax		= 150,
++};
++
++#define AT91CAP9_DEFAULT_LCDCON2 	(ATMEL_LCDC_MEMOR_LITTLE \
++					| ATMEL_LCDC_DISTYPE_TFT    \
++					| ATMEL_LCDC_CLKMOD_ALWAYSACTIVE)
++
++static void at91_lcdc_power_control(int on)
 +{
-+	if (status & FAULT_USERSUPV)
-+		return !!(data & CPLB_SUPV_WR);
++	if (on)
++		at91_set_gpio_value(AT91_PIN_PC0, 0);	/* power up */
 +	else
-+		return !!(data & CPLB_USER_WR);
++		at91_set_gpio_value(AT91_PIN_PC0, 1);	/* power down */
 +}
 +
-+/* Counters to implement round-robin replacement.  */
-+static int icplb_rr_index, dcplb_rr_index;
++/* Driver datas */
++static struct atmel_lcdfb_info __initdata cap9adk_lcdc_data = {
++	.default_bpp			= 16,
++	.default_dmacon			= ATMEL_LCDC_DMAEN,
++	.default_lcdcon2		= AT91CAP9_DEFAULT_LCDCON2,
++	.default_monspecs		= &at91fb_default_monspecs,
++	.atmel_lcdfb_power_control	= at91_lcdc_power_control,
++	.guard_time			= 1,
++};
++
++#else
++static struct atmel_lcdfb_info __initdata cap9adk_lcdc_data;
++#endif
++
 +
 +/*
-+ * Find an ICPLB entry to be evicted and return its index.
++ * AC97
 + */
-+static int evict_one_icplb(void)
++static struct atmel_ac97_data cap9adk_ac97_data = {
++//	.reset_pin	= ... not connected
++};
++
++
++static void __init cap9adk_board_init(void)
 +{
-+	int i;
-+	for (i = first_switched_icplb; i < MAX_CPLBS; i++)
-+		if ((icplb_tbl[i].data & CPLB_VALID) == 0)
-+			return i;
-+	i = first_switched_icplb + icplb_rr_index;
-+	if (i >= MAX_CPLBS) {
-+		i -= MAX_CPLBS - first_switched_icplb;
-+		icplb_rr_index -= MAX_CPLBS - first_switched_icplb;
++	/* Serial */
++	at91_add_device_serial();
++	/* USB Host */
++	set_irq_type(AT91CAP9_ID_UHP, IRQT_HIGH);
++	at91_add_device_usbh(&cap9adk_usbh_data);
++	/* SPI */
++	at91_add_device_spi(cap9adk_spi_devices, ARRAY_SIZE(cap9adk_spi_devices));
++	/* Touchscreen */
++	cap9adk_add_device_ts();
++	/* MMC */
++	at91_add_device_mmc(1, &cap9adk_mmc_data);
++	/* Ethernet */
++	at91_add_device_eth(&cap9adk_macb_data);
++	/* NAND */
++	at91_add_device_nand(&cap9adk_nand_data);
++	/* NOR Flash */
++	cap9adk_add_device_nor();
++	/* I2C */
++	at91_add_device_i2c(NULL, 0);
++	/* LCD Controller */
++	set_irq_type(AT91CAP9_ID_LCDC, IRQT_HIGH);
++	at91_add_device_lcdc(&cap9adk_lcdc_data);
++	/* AC97 */
++	at91_add_device_ac97(&cap9adk_ac97_data);
++}
++
++MACHINE_START(AT91CAP9ADK, "Atmel AT91CAP9A-DK")
++	/* Maintainer: Stelian Pop <stelian.pop at leadtechdesign.com> */
++	.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		= cap9adk_map_io,
++	.init_irq	= cap9adk_init_irq,
++	.init_machine	= cap9adk_board_init,
++MACHINE_END
+diff --git a/arch/arm/mach-at91/board-csb337.c b/arch/arm/mach-at91/board-csb337.c
+index d0aa20c..0e2a11f 100644
+--- a/arch/arm/mach-at91/board-csb337.c
++++ b/arch/arm/mach-at91/board-csb337.c
+@@ -25,6 +25,8 @@
+ #include <linux/platform_device.h>
+ #include <linux/spi/spi.h>
+ #include <linux/mtd/physmap.h>
++#include <linux/input.h>
++#include <linux/gpio_keys.h>
+ 
+ #include <asm/hardware.h>
+ #include <asm/setup.h>
+@@ -156,6 +158,85 @@ static struct platform_device csb_flash = {
+ 	.num_resources	= ARRAY_SIZE(csb_flash_resources),
+ };
+ 
++/*
++ * GPIO Buttons (on CSB300)
++ */
++#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
++static struct gpio_keys_button csb300_buttons[] = {
++	{
++		.gpio		= AT91_PIN_PB29,
++		.code		= BTN_0,
++		.desc		= "sw0",
++		.active_low	= 1,
++		.wakeup		= 1,
++	},
++	{
++		.gpio		= AT91_PIN_PB28,
++		.code		= BTN_1,
++		.desc		= "sw1",
++		.active_low	= 1,
++		.wakeup		= 1,
++	},
++	{
++		.gpio		= AT91_PIN_PA21,
++		.code		= BTN_2,
++		.desc		= "sw2",
++		.active_low	= 1,
++		.wakeup		= 1,
 +	}
-+	icplb_rr_index++;
-+	return i;
-+}
++};
 +
-+static int evict_one_dcplb(void)
-+{
-+	int i;
-+	for (i = first_switched_dcplb; i < MAX_CPLBS; i++)
-+		if ((dcplb_tbl[i].data & CPLB_VALID) == 0)
-+			return i;
-+	i = first_switched_dcplb + dcplb_rr_index;
-+	if (i >= MAX_CPLBS) {
-+		i -= MAX_CPLBS - first_switched_dcplb;
-+		dcplb_rr_index -= MAX_CPLBS - first_switched_dcplb;
++static struct gpio_keys_platform_data csb300_button_data = {
++	.buttons	= csb300_buttons,
++	.nbuttons	= ARRAY_SIZE(csb300_buttons),
++};
++
++static struct platform_device csb300_button_device = {
++	.name		= "gpio-keys",
++	.id		= -1,
++	.num_resources	= 0,
++	.dev		= {
++		.platform_data	= &csb300_button_data,
 +	}
-+	dcplb_rr_index++;
-+	return i;
-+}
++};
 +
-+static noinline int dcplb_miss(void)
++static void __init csb300_add_device_buttons(void)
 +{
-+	unsigned long addr = bfin_read_DCPLB_FAULT_ADDR();
-+	int status = bfin_read_DCPLB_STATUS();
-+	unsigned long *mask;
-+	int idx;
-+	unsigned long d_data;
-+
-+	nr_dcplb_miss++;
-+	if (addr >= _ramend)
-+		return CPLB_PROT_VIOL;
++	at91_set_gpio_input(AT91_PIN_PB29, 0);	/* sw0 */
++	at91_set_deglitch(AT91_PIN_PB29, 1);
++	at91_set_gpio_input(AT91_PIN_PB28, 0);	/* sw1 */
++	at91_set_deglitch(AT91_PIN_PB28, 1);
++	at91_set_gpio_input(AT91_PIN_PA21, 0);	/* sw2 */
++	at91_set_deglitch(AT91_PIN_PA21, 1);
 +
-+	d_data = CPLB_SUPV_WR | CPLB_VALID | CPLB_DIRTY | PAGE_SIZE_4KB;
-+#ifdef CONFIG_BFIN_DCACHE
-+	d_data |= CPLB_L1_CHBL | ANOMALY_05000158_WORKAROUND;
-+#ifdef CONFIG_BLKFIN_WT
-+	d_data |= CPLB_L1_AOW | CPLB_WT;
-+#endif
++	platform_device_register(&csb300_button_device);
++}
++#else
++static void __init csb300_add_device_buttons(void) {}
 +#endif
-+	mask = current_rwx_mask;
-+	if (mask) {
-+		int page = addr >> PAGE_SHIFT;
-+		int offs = page >> 5;
-+		int bit = 1 << (page & 31);
 +
-+		if (mask[offs] & bit)
-+			d_data |= CPLB_USER_RD;
++static struct gpio_led csb_leds[] = {
++	{	/* "led0", yellow */
++		.name			= "led0",
++		.gpio			= AT91_PIN_PB2,
++		.active_low		= 1,
++		.default_trigger	= "heartbeat",
++	},
++	{	/* "led1", green */
++		.name			= "led1",
++		.gpio			= AT91_PIN_PB1,
++		.active_low		= 1,
++		.default_trigger	= "mmc0",
++	},
++	{	/* "led2", yellow */
++		.name			= "led2",
++		.gpio			= AT91_PIN_PB0,
++		.active_low		= 1,
++		.default_trigger	= "ide-disk",
++	},
++};
 +
-+		mask += page_mask_nelts;
-+		if (mask[offs] & bit)
-+			d_data |= CPLB_USER_WR;
++
+ static void __init csb337_board_init(void)
+ {
+ 	/* Serial */
+@@ -177,6 +258,10 @@ static void __init csb337_board_init(void)
+ 	at91_add_device_mmc(0, &csb337_mmc_data);
+ 	/* NOR flash */
+ 	platform_device_register(&csb_flash);
++	/* LEDs */
++	at91_gpio_leds(csb_leds, ARRAY_SIZE(csb_leds));
++	/* Switches on CSB300 */
++	csb300_add_device_buttons();
+ }
+ 
+ MACHINE_START(CSB337, "Cogent CSB337")
+diff --git a/arch/arm/mach-at91/board-dk.c b/arch/arm/mach-at91/board-dk.c
+index 40c9e43..0a897ef 100644
+--- a/arch/arm/mach-at91/board-dk.c
++++ b/arch/arm/mach-at91/board-dk.c
+@@ -183,6 +183,14 @@ static struct platform_device dk_flash = {
+ 	.num_resources	= 1,
+ };
+ 
++static struct gpio_led dk_leds[] = {
++	{
++		.name			= "led0",
++		.gpio			= AT91_PIN_PB2,
++		.active_low		= 1,
++		.default_trigger	= "heartbeat",
++	}
++};
+ 
+ static void __init dk_board_init(void)
+ {
+@@ -213,6 +221,8 @@ static void __init dk_board_init(void)
+ 	at91_add_device_nand(&dk_nand_data);
+ 	/* NOR Flash */
+ 	platform_device_register(&dk_flash);
++	/* LEDs */
++	at91_gpio_leds(dk_leds, ARRAY_SIZE(dk_leds));
+ 	/* VGA */
+ //	dk_add_device_video();
+ }
+diff --git a/arch/arm/mach-at91/board-ek.c b/arch/arm/mach-at91/board-ek.c
+index 53a5ef9..0574e50 100644
+--- a/arch/arm/mach-at91/board-ek.c
++++ b/arch/arm/mach-at91/board-ek.c
+@@ -141,6 +141,25 @@ static struct platform_device ek_flash = {
+ 	.num_resources	= 1,
+ };
+ 
++static struct gpio_led ek_leds[] = {
++	{	/* "user led 1", DS2 */
++		.name			= "green",
++		.gpio			= AT91_PIN_PB0,
++		.active_low		= 1,
++		.default_trigger	= "mmc0",
++	},
++	{	/* "user led 2", DS4 */
++		.name			= "yellow",
++		.gpio			= AT91_PIN_PB1,
++		.active_low		= 1,
++		.default_trigger	= "heartbeat",
++	},
++	{	/* "user led 3", DS6 */
++		.name			= "red",
++		.gpio			= AT91_PIN_PB2,
++		.active_low		= 1,
 +	}
++};
+ 
+ static void __init ek_board_init(void)
+ {
+@@ -167,6 +186,8 @@ static void __init ek_board_init(void)
+ #endif
+ 	/* NOR Flash */
+ 	platform_device_register(&ek_flash);
++	/* LEDs */
++	at91_gpio_leds(ek_leds, ARRAY_SIZE(ek_leds));
+ 	/* VGA */
+ //	ek_add_device_video();
+ }
+diff --git a/arch/arm/mach-at91/board-sam9261ek.c b/arch/arm/mach-at91/board-sam9261ek.c
+index 550ae59..aa29ea5 100644
+--- a/arch/arm/mach-at91/board-sam9261ek.c
++++ b/arch/arm/mach-at91/board-sam9261ek.c
+@@ -280,6 +280,68 @@ static struct spi_board_info ek_spi_devices[] = {
+  * LCD Controller
+  */
+ #if defined(CONFIG_FB_ATMEL) || defined(CONFIG_FB_ATMEL_MODULE)
++
++#if defined(CONFIG_FB_ATMEL_STN)
++
++/* STN */
++static struct fb_videomode at91_stn_modes[] = {
++        {
++		.name           = "SP06Q002 @ 75",
++		.refresh        = 75,
++		.xres           = 320,          .yres           = 240,
++		.pixclock       = KHZ2PICOS(1440),
++
++		.left_margin    = 1,            .right_margin   = 1,
++		.upper_margin   = 0,            .lower_margin   = 0,
++		.hsync_len      = 1,            .vsync_len      = 1,
++
++		.sync		= FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
++		.vmode          = FB_VMODE_NONINTERLACED,
++        },
++};
++
++static struct fb_monspecs at91fb_default_stn_monspecs = {
++        .manufacturer   = "HIT",
++        .monitor        = "SP06Q002",
++
++        .modedb         = at91_stn_modes,
++        .modedb_len     = ARRAY_SIZE(at91_stn_modes),
++        .hfmin          = 15000,
++        .hfmax          = 64000,
++        .vfmin          = 50,
++        .vfmax          = 150,
++};
++
++#define AT91SAM9261_DEFAULT_STN_LCDCON2	(ATMEL_LCDC_MEMOR_LITTLE \
++					| ATMEL_LCDC_DISTYPE_STNMONO \
++					| ATMEL_LCDC_CLKMOD_ALWAYSACTIVE \
++					| ATMEL_LCDC_IFWIDTH_4 \
++					| ATMEL_LCDC_SCANMOD_SINGLE)
++
++static void at91_lcdc_stn_power_control(int on)
++{
++	/* backlight */
++	if (on) {	/* power up */
++		at91_set_gpio_value(AT91_PIN_PC14, 0);
++		at91_set_gpio_value(AT91_PIN_PC15, 0);
++	} else {	/* power down */
++		at91_set_gpio_value(AT91_PIN_PC14, 1);
++		at91_set_gpio_value(AT91_PIN_PC15, 1);
++	}
++}
++
++static struct atmel_lcdfb_info __initdata ek_lcdc_data = {
++	.default_bpp			= 1,
++	.default_dmacon			= ATMEL_LCDC_DMAEN,
++	.default_lcdcon2		= AT91SAM9261_DEFAULT_STN_LCDCON2,
++	.default_monspecs		= &at91fb_default_stn_monspecs,
++	.atmel_lcdfb_power_control	= at91_lcdc_stn_power_control,
++	.guard_time			= 1,
++};
 +
-+	idx = evict_one_dcplb();
++#else
 +
-+	addr &= PAGE_MASK;
-+	dcplb_tbl[idx].addr = addr;
-+	dcplb_tbl[idx].data = d_data;
++/* TFT */
+ static struct fb_videomode at91_tft_vga_modes[] = {
+ 	{
+ 	        .name           = "TX09D50VM1CCA @ 60",
+@@ -296,7 +358,7 @@ static struct fb_videomode at91_tft_vga_modes[] = {
+ 	},
+ };
+ 
+-static struct fb_monspecs at91fb_default_monspecs = {
++static struct fb_monspecs at91fb_default_tft_monspecs = {
+ 	.manufacturer	= "HIT",
+ 	.monitor        = "TX09D50VM1CCA",
+ 
+@@ -308,11 +370,11 @@ static struct fb_monspecs at91fb_default_monspecs = {
+ 	.vfmax		= 150,
+ };
+ 
+-#define AT91SAM9261_DEFAULT_LCDCON2 	(ATMEL_LCDC_MEMOR_LITTLE \
++#define AT91SAM9261_DEFAULT_TFT_LCDCON2	(ATMEL_LCDC_MEMOR_LITTLE \
+ 					| ATMEL_LCDC_DISTYPE_TFT    \
+ 					| ATMEL_LCDC_CLKMOD_ALWAYSACTIVE)
+ 
+-static void at91_lcdc_power_control(int on)
++static void at91_lcdc_tft_power_control(int on)
+ {
+ 	if (on)
+ 		at91_set_gpio_value(AT91_PIN_PA12, 0);	/* power up */
+@@ -320,15 +382,15 @@ static void at91_lcdc_power_control(int on)
+ 		at91_set_gpio_value(AT91_PIN_PA12, 1);	/* power down */
+ }
+ 
+-/* Driver datas */
+ static struct atmel_lcdfb_info __initdata ek_lcdc_data = {
+ 	.default_bpp			= 16,
+ 	.default_dmacon			= ATMEL_LCDC_DMAEN,
+-	.default_lcdcon2		= AT91SAM9261_DEFAULT_LCDCON2,
+-	.default_monspecs		= &at91fb_default_monspecs,
+-	.atmel_lcdfb_power_control	= at91_lcdc_power_control,
++	.default_lcdcon2		= AT91SAM9261_DEFAULT_TFT_LCDCON2,
++	.default_monspecs		= &at91fb_default_tft_monspecs,
++	.atmel_lcdfb_power_control	= at91_lcdc_tft_power_control,
+ 	.guard_time			= 1,
+ };
++#endif
+ 
+ #else
+ static struct atmel_lcdfb_info __initdata ek_lcdc_data;
+@@ -342,25 +404,25 @@ static struct atmel_lcdfb_info __initdata ek_lcdc_data;
+ static struct gpio_keys_button ek_buttons[] = {
+ 	{
+ 		.gpio		= AT91_PIN_PA27,
+-		.keycode	= BTN_0,
++		.code		= BTN_0,
+ 		.desc		= "Button 0",
+ 		.active_low	= 1,
+ 	},
+ 	{
+ 		.gpio		= AT91_PIN_PA26,
+-		.keycode	= BTN_1,
++		.code		= BTN_1,
+ 		.desc		= "Button 1",
+ 		.active_low	= 1,
+ 	},
+ 	{
+ 		.gpio		= AT91_PIN_PA25,
+-		.keycode	= BTN_2,
++		.code		= BTN_2,
+ 		.desc		= "Button 2",
+ 		.active_low	= 1,
+ 	},
+ 	{
+ 		.gpio		= AT91_PIN_PA24,
+-		.keycode	= BTN_3,
++		.code		= BTN_3,
+ 		.desc		= "Button 3",
+ 		.active_low	= 1,
+ 	}
+diff --git a/arch/arm/mach-at91/board-sam9263ek.c b/arch/arm/mach-at91/board-sam9263ek.c
+index ab9dcc0..f09347a 100644
+--- a/arch/arm/mach-at91/board-sam9263ek.c
++++ b/arch/arm/mach-at91/board-sam9263ek.c
+@@ -27,6 +27,8 @@
+ #include <linux/spi/spi.h>
+ #include <linux/spi/ads7846.h>
+ #include <linux/fb.h>
++#include <linux/gpio_keys.h>
++#include <linux/input.h>
+ 
+ #include <video/atmel_lcdc.h>
+ 
+@@ -163,6 +165,7 @@ static struct at91_mmc_data __initdata ek_mmc_data = {
+  * MACB Ethernet device
+  */
+ static struct at91_eth_data __initdata ek_macb_data = {
++	.phy_irq_pin	= AT91_PIN_PE31,
+ 	.is_rmii	= 1,
+ };
+ 
+@@ -264,6 +267,55 @@ static struct atmel_lcdfb_info __initdata ek_lcdc_data;
+ 
+ 
+ /*
++ * GPIO Buttons
++ */
++#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
++static struct gpio_keys_button ek_buttons[] = {
++	{	/* BP1, "leftclic" */
++		.code		= BTN_LEFT,
++		.gpio		= AT91_PIN_PC5,
++		.active_low	= 1,
++		.desc		= "left_click",
++		.wakeup		= 1,
++	},
++	{	/* BP2, "rightclic" */
++		.code		= BTN_RIGHT,
++		.gpio		= AT91_PIN_PC4,
++		.active_low	= 1,
++		.desc		= "right_click",
++		.wakeup		= 1,
++	},
++};
 +
-+	disable_dcplb();
-+	bfin_write32(DCPLB_DATA0 + idx * 4, d_data);
-+	bfin_write32(DCPLB_ADDR0 + idx * 4, addr);
-+	enable_dcplb();
++static struct gpio_keys_platform_data ek_button_data = {
++	.buttons	= ek_buttons,
++	.nbuttons	= ARRAY_SIZE(ek_buttons),
++};
 +
-+	return 0;
-+}
++static struct platform_device ek_button_device = {
++	.name		= "gpio-keys",
++	.id		= -1,
++	.num_resources	= 0,
++	.dev		= {
++		.platform_data	= &ek_button_data,
++	}
++};
 +
-+static noinline int icplb_miss(void)
++static void __init ek_add_device_buttons(void)
 +{
-+	unsigned long addr = bfin_read_ICPLB_FAULT_ADDR();
-+	int status = bfin_read_ICPLB_STATUS();
-+	int idx;
-+	unsigned long i_data;
-+
-+	nr_icplb_miss++;
-+	if (status & FAULT_USERSUPV)
-+		nr_icplb_supv_miss++;
-+
-+	if (addr >= _ramend)
-+		return CPLB_PROT_VIOL;
++	at91_set_GPIO_periph(AT91_PIN_PC5, 0);	/* left button */
++	at91_set_deglitch(AT91_PIN_PC5, 1);
++	at91_set_GPIO_periph(AT91_PIN_PC4, 0);	/* right button */
++	at91_set_deglitch(AT91_PIN_PC4, 1);
 +
-+	/*
-+	 * First, try to find a CPLB that matches this address.  If we
-+	 * find one, then the fact that we're in the miss handler means
-+	 * that the instruction crosses a page boundary.
-+	 */
-+	for (idx = first_switched_icplb; idx < MAX_CPLBS; idx++) {
-+		if (icplb_tbl[idx].data & CPLB_VALID) {
-+			unsigned long this_addr = icplb_tbl[idx].addr;
-+			if (this_addr <= addr && this_addr + PAGE_SIZE > addr) {
-+				addr += PAGE_SIZE;
-+				break;
-+			}
-+		}
-+	}
-+
-+	i_data = CPLB_VALID | CPLB_PORTPRIO | PAGE_SIZE_4KB;
-+#ifdef CONFIG_BFIN_ICACHE
-+	i_data |= CPLB_L1_CHBL | ANOMALY_05000158_WORKAROUND;
++	platform_device_register(&ek_button_device);
++}
++#else
++static void __init ek_add_device_buttons(void) {}
 +#endif
 +
-+	/*
-+	 * Two cases to distinguish - a supervisor access must necessarily
-+	 * be for a module page; we grant it unconditionally (could do better
-+	 * here in the future).  Otherwise, check the x bitmap of the current
-+	 * process.
-+	 */
-+	if (!(status & FAULT_USERSUPV)) {
-+		unsigned long *mask = current_rwx_mask;
 +
-+		if (mask) {
-+			int page = addr >> PAGE_SHIFT;
-+			int offs = page >> 5;
-+			int bit = 1 << (page & 31);
++/*
+  * AC97
+  */
+ static struct atmel_ac97_data ek_ac97_data = {
+@@ -271,6 +323,30 @@ static struct atmel_ac97_data ek_ac97_data = {
+ };
+ 
+ 
++/*
++ * 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 */
++		.name			= "ds2",
++		.gpio			= AT91_PIN_PC29,
++		.active_low		= 1,
++		.default_trigger	= "nand-disk",
++	},
++	{	/* "power" led, yellow, pwm0 */
++		.name			= "ds3",
++		.gpio			= AT91_PIN_PB7,
++		.default_trigger	= "heartbeat",
++	},
++};
 +
-+			mask += 2 * page_mask_nelts;
-+			if (mask[offs] & bit)
-+				i_data |= CPLB_USER_RD;
-+		}
-+	}
 +
-+	idx = evict_one_icplb();
-+	addr &= PAGE_MASK;
-+	icplb_tbl[idx].addr = addr;
-+	icplb_tbl[idx].data = i_data;
+ static void __init ek_board_init(void)
+ {
+ 	/* Serial */
+@@ -294,8 +370,12 @@ static void __init ek_board_init(void)
+ 	at91_add_device_i2c(NULL, 0);
+ 	/* LCD Controller */
+ 	at91_add_device_lcdc(&ek_lcdc_data);
++	/* Push Buttons */
++	ek_add_device_buttons();
+ 	/* AC97 */
+ 	at91_add_device_ac97(&ek_ac97_data);
++	/* LEDs */
++	at91_gpio_leds(ek_leds, ARRAY_SIZE(ek_leds));
+ }
+ 
+ MACHINE_START(AT91SAM9263EK, "Atmel AT91SAM9263-EK")
+diff --git a/arch/arm/mach-at91/clock.c b/arch/arm/mach-at91/clock.c
+index 57c3b64..ec76eea 100644
+--- a/arch/arm/mach-at91/clock.c
++++ b/arch/arm/mach-at91/clock.c
+@@ -574,6 +574,8 @@ int __init at91_clock_init(unsigned long main_clock)
+ 	} else if (cpu_is_at91sam9260() || cpu_is_at91sam9261() || cpu_is_at91sam9263()) {
+ 		uhpck.pmc_mask = AT91SAM926x_PMC_UHP;
+ 		udpck.pmc_mask = AT91SAM926x_PMC_UDP;
++	} else if (cpu_is_at91cap9()) {
++		uhpck.pmc_mask = AT91CAP9_PMC_UHP;
+ 	}
+ 	at91_sys_write(AT91_CKGR_PLLBR, 0);
+ 
+diff --git a/arch/arm/mach-at91/generic.h b/arch/arm/mach-at91/generic.h
+index 77d4c0a..b5daf7f 100644
+--- a/arch/arm/mach-at91/generic.h
++++ b/arch/arm/mach-at91/generic.h
+@@ -15,6 +15,7 @@ extern void __init at91sam9261_initialize(unsigned long main_clock);
+ extern void __init at91sam9263_initialize(unsigned long main_clock);
+ extern void __init at91sam9rl_initialize(unsigned long main_clock);
+ extern void __init at91x40_initialize(unsigned long main_clock);
++extern void __init at91cap9_initialize(unsigned long main_clock);
+ 
+  /* Interrupts */
+ extern void __init at91rm9200_init_interrupts(unsigned int priority[]);
+@@ -23,6 +24,7 @@ extern void __init at91sam9261_init_interrupts(unsigned int priority[]);
+ extern void __init at91sam9263_init_interrupts(unsigned int priority[]);
+ extern void __init at91sam9rl_init_interrupts(unsigned int priority[]);
+ extern void __init at91x40_init_interrupts(unsigned int priority[]);
++extern void __init at91cap9_init_interrupts(unsigned int priority[]);
+ extern void __init at91_aic_init(unsigned int priority[]);
+ 
+  /* Timer */
+diff --git a/arch/arm/mach-at91/gpio.c b/arch/arm/mach-at91/gpio.c
+index aa2d365..6aeddd6 100644
+--- a/arch/arm/mach-at91/gpio.c
++++ b/arch/arm/mach-at91/gpio.c
+@@ -13,6 +13,8 @@
+ #include <linux/errno.h>
+ #include <linux/interrupt.h>
+ #include <linux/irq.h>
++#include <linux/debugfs.h>
++#include <linux/seq_file.h>
+ #include <linux/kernel.h>
+ #include <linux/list.h>
+ #include <linux/module.h>
+@@ -414,6 +416,66 @@ static void gpio_irq_handler(unsigned irq, struct irq_desc *desc)
+ 
+ /*--------------------------------------------------------------------------*/
+ 
++#ifdef CONFIG_DEBUG_FS
 +
-+	disable_icplb();
-+	bfin_write32(ICPLB_DATA0 + idx * 4, i_data);
-+	bfin_write32(ICPLB_ADDR0 + idx * 4, addr);
-+	enable_icplb();
++static int at91_gpio_show(struct seq_file *s, void *unused)
++{
++	int bank, j;
 +
-+	return 0;
-+}
++	/* print heading */
++	seq_printf(s, "Pin\t");
++	for (bank = 0; bank < gpio_banks; bank++) {
++		seq_printf(s, "PIO%c\t", 'A' + bank);
++	};
++	seq_printf(s, "\n\n");
 +
-+static noinline int dcplb_protection_fault(void)
-+{
-+	unsigned long addr = bfin_read_DCPLB_FAULT_ADDR();
-+	int status = bfin_read_DCPLB_STATUS();
++	/* print pin status */
++	for (j = 0; j < 32; j++) {
++		seq_printf(s, "%i:\t", j);
++
++		for (bank = 0; bank < gpio_banks; bank++) {
++			unsigned	pin  = PIN_BASE + (32 * bank) + j;
++			void __iomem	*pio = pin_to_controller(pin);
++			unsigned	mask = pin_to_mask(pin);
 +
-+	nr_dcplb_prot++;
++			if (__raw_readl(pio + PIO_PSR) & mask)
++				seq_printf(s, "GPIO:%s", __raw_readl(pio + PIO_PDSR) & mask ? "1" : "0");
++			else
++				seq_printf(s, "%s", __raw_readl(pio + PIO_ABSR) & mask ? "B" : "A");
 +
-+	if (status & FAULT_RW) {
-+		int idx = faulting_cplb_index(status);
-+		unsigned long data = dcplb_tbl[idx].data;
-+		if (!(data & CPLB_WT) && !(data & CPLB_DIRTY) &&
-+		    write_permitted(status, data)) {
-+			data |= CPLB_DIRTY;
-+			dcplb_tbl[idx].data = data;
-+			bfin_write32(DCPLB_DATA0 + idx * 4, data);
-+			return 0;
++			seq_printf(s, "\t");
 +		}
++
++		seq_printf(s, "\n");
 +	}
-+	return CPLB_PROT_VIOL;
++
++	return 0;
 +}
 +
-+int cplb_hdr(int seqstat, struct pt_regs *regs)
++static int at91_gpio_open(struct inode *inode, struct file *file)
 +{
-+	int cause = seqstat & 0x3f;
-+	switch (cause) {
-+	case 0x23:
-+		return dcplb_protection_fault();
-+	case 0x2C:
-+		return icplb_miss();
-+	case 0x26:
-+		return dcplb_miss();
-+	default:
-+	    return 1;
-+		panic_cplb_error(seqstat, regs);
-+	}
++	return single_open(file, at91_gpio_show, NULL);
 +}
 +
-+void flush_switched_cplbs(void)
++static const struct file_operations at91_gpio_operations = {
++	.open		= at91_gpio_open,
++	.read		= seq_read,
++	.llseek		= seq_lseek,
++	.release	= single_release,
++};
++
++static int __init at91_gpio_debugfs_init(void)
 +{
-+	int i;
++	/* /sys/kernel/debug/at91_gpio */
++	(void) debugfs_create_file("at91_gpio", S_IFREG | S_IRUGO, NULL, NULL, &at91_gpio_operations);
++	return 0;
++}
++postcore_initcall(at91_gpio_debugfs_init);
 +
-+	nr_cplb_flush++;
++#endif
 +
-+	disable_icplb();
-+	for (i = first_switched_icplb; i < MAX_CPLBS; i++) {
-+		icplb_tbl[i].data = 0;
-+		bfin_write32(ICPLB_DATA0 + i * 4, 0);
-+	}
-+	enable_icplb();
++/*--------------------------------------------------------------------------*/
 +
-+	disable_dcplb();
-+	for (i = first_mask_dcplb; i < MAX_CPLBS; i++) {
-+		dcplb_tbl[i].data = 0;
-+		bfin_write32(DCPLB_DATA0 + i * 4, 0);
-+	}
-+	enable_dcplb();
-+}
+ /*
+  * Called from the processor-specific init to enable GPIO interrupt support.
+  */
+diff --git a/arch/arm/mach-at91/leds.c b/arch/arm/mach-at91/leds.c
+index 0d51449..9cdcda5 100644
+--- a/arch/arm/mach-at91/leds.c
++++ b/arch/arm/mach-at91/leds.c
+@@ -14,11 +14,62 @@
+ #include <linux/init.h>
+ 
+ #include <asm/mach-types.h>
+-#include <asm/leds.h>
+ #include <asm/arch/board.h>
+ #include <asm/arch/gpio.h>
+ 
+ 
++/* ------------------------------------------------------------------------- */
 +
-+void set_mask_dcplbs(unsigned long *masks)
++#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 = {
++	.name			= "leds-gpio",
++	.id			= -1,
++	.dev.platform_data	= &led_data,
++};
++
++void __init at91_gpio_leds(struct gpio_led *leds, int nr)
 +{
 +	int i;
-+	unsigned long addr = (unsigned long)masks;
-+	unsigned long d_data;
-+	current_rwx_mask = masks;
 +
-+	if (!masks)
++	if (!nr)
 +		return;
 +
-+	d_data = CPLB_SUPV_WR | CPLB_VALID | CPLB_DIRTY | PAGE_SIZE_4KB;
-+#ifdef CONFIG_BFIN_DCACHE
-+	d_data |= CPLB_L1_CHBL;
-+#ifdef CONFIG_BLKFIN_WT
-+	d_data |= CPLB_L1_AOW | CPLB_WT;
-+#endif
-+#endif
++	for (i = 0; i < nr; i++)
++		at91_set_gpio_output(leds[i].gpio, leds[i].active_low);
 +
-+	disable_dcplb();
-+	for (i = first_mask_dcplb; i < first_switched_dcplb; i++) {
-+		dcplb_tbl[i].addr = addr;
-+		dcplb_tbl[i].data = d_data;
-+		bfin_write32(DCPLB_DATA0 + i * 4, d_data);
-+		bfin_write32(DCPLB_ADDR0 + i * 4, addr);
-+		addr += PAGE_SIZE;
-+	}
-+	enable_dcplb();
++	led_data.leds = leds;
++	led_data.num_leds = nr;
++	platform_device_register(&at91_leds);
 +}
 +
++#else
++void __init at91_gpio_leds(struct gpio_led *leds, int nr) {}
 +#endif
-diff --git a/arch/blackfin/kernel/cplb-nompu/Makefile b/arch/blackfin/kernel/cplb-nompu/Makefile
-new file mode 100644
-index 0000000..d36ea9b
---- /dev/null
-+++ b/arch/blackfin/kernel/cplb-nompu/Makefile
-@@ -0,0 +1,8 @@
-+#
-+# arch/blackfin/kernel/cplb-nompu/Makefile
-+#
 +
-+obj-y := cplbinit.o cacheinit.o cplbhdlr.o cplbmgr.o
 +
-+obj-$(CONFIG_CPLB_INFO) += cplbinfo.o
++/* ------------------------------------------------------------------------- */
++
++#if defined(CONFIG_LEDS)
++
++#include <asm/leds.h>
 +
-diff --git a/arch/blackfin/kernel/cplb-nompu/cacheinit.c b/arch/blackfin/kernel/cplb-nompu/cacheinit.c
-new file mode 100644
-index 0000000..8a18399
---- /dev/null
-+++ b/arch/blackfin/kernel/cplb-nompu/cacheinit.c
-@@ -0,0 +1,69 @@
 +/*
-+ *               Copyright 2004-2007 Analog Devices 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, see the file COPYING, or write
-+ * to the Free Software Foundation, Inc.,
-+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ * Old ARM-specific LED framework; not fully functional when generic time is
++ * in use.
 + */
 +
-+#include <linux/cpu.h>
++static u8 at91_leds_cpu;
++static u8 at91_leds_timer;
 +
-+#include <asm/cacheflush.h>
-+#include <asm/blackfin.h>
-+#include <asm/cplb.h>
-+#include <asm/cplbinit.h>
+ static inline void at91_led_on(unsigned int led)
+ {
+ 	at91_set_gpio_value(led, 0);
+@@ -93,3 +144,18 @@ static int __init leds_init(void)
+ }
+ 
+ __initcall(leds_init);
 +
-+#if defined(CONFIG_BFIN_ICACHE)
-+void bfin_icache_init(void)
++
++void __init at91_init_leds(u8 cpu_led, u8 timer_led)
 +{
-+	unsigned long *table = icplb_table;
-+	unsigned long ctrl;
-+	int i;
++	/* Enable GPIO to access the LEDs */
++	at91_set_gpio_output(cpu_led, 1);
++	at91_set_gpio_output(timer_led, 1);
 +
-+	for (i = 0; i < MAX_CPLBS; i++) {
-+		unsigned long addr = *table++;
-+		unsigned long data = *table++;
-+		if (addr == (unsigned long)-1)
-+			break;
-+		bfin_write32(ICPLB_ADDR0 + i * 4, addr);
-+		bfin_write32(ICPLB_DATA0 + i * 4, data);
-+	}
-+	ctrl = bfin_read_IMEM_CONTROL();
-+	ctrl |= IMC | ENICPLB;
-+	bfin_write_IMEM_CONTROL(ctrl);
-+	SSYNC();
++	at91_leds_cpu	= cpu_led;
++	at91_leds_timer	= timer_led;
 +}
++
++#else
++void __init at91_init_leds(u8 cpu_led, u8 timer_led) {}
 +#endif
+diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c
+index 98cb614..4b120cc 100644
+--- a/arch/arm/mach-at91/pm.c
++++ b/arch/arm/mach-at91/pm.c
+@@ -80,6 +80,11 @@ static int at91_pm_verify_clocks(void)
+ 			pr_debug("AT91: PM - Suspend-to-RAM with USB still active\n");
+ 			return 0;
+ 		}
++	} else if (cpu_is_at91cap9()) {
++		if ((scsr & AT91CAP9_PMC_UHP) != 0) {
++			pr_debug("AT91: PM - Suspend-to-RAM with USB still active\n");
++			return 0;
++		}
+ 	}
+ 
+ #ifdef CONFIG_AT91_PROGRAMMABLE_CLOCKS
+diff --git a/arch/arm/mach-clps711x/time.c b/arch/arm/mach-clps711x/time.c
+index f428af7..e5dc33f 100644
+--- a/arch/arm/mach-clps711x/time.c
++++ b/arch/arm/mach-clps711x/time.c
+@@ -50,9 +50,7 @@ static unsigned long clps711x_gettimeoffset(void)
+ static irqreturn_t
+ p720t_timer_interrupt(int irq, void *dev_id)
+ {
+-	write_seqlock(&xtime_lock);
+ 	timer_tick();
+-	write_sequnlock(&xtime_lock);
+ 	return IRQ_HANDLED;
+ }
+ 
+diff --git a/arch/arm/mach-clps7500/core.c b/arch/arm/mach-clps7500/core.c
+index 986205e..2ac6367 100644
+--- a/arch/arm/mach-clps7500/core.c
++++ b/arch/arm/mach-clps7500/core.c
+@@ -298,8 +298,6 @@ extern unsigned long ioc_timer_gettimeoffset(void);
+ static irqreturn_t
+ clps7500_timer_interrupt(int irq, void *dev_id)
+ {
+-	write_seqlock(&xtime_lock);
+-
+ 	timer_tick();
+ 
+ 	/* Why not using do_leds interface?? */
+@@ -313,8 +311,6 @@ clps7500_timer_interrupt(int irq, void *dev_id)
+ 		}
+ 	}
+ 
+-	write_sequnlock(&xtime_lock);
+-
+ 	return IRQ_HANDLED;
+ }
+ 
+diff --git a/arch/arm/mach-ebsa110/core.c b/arch/arm/mach-ebsa110/core.c
+index 8c1b569..7710e14 100644
+--- a/arch/arm/mach-ebsa110/core.c
++++ b/arch/arm/mach-ebsa110/core.c
+@@ -178,8 +178,6 @@ ebsa110_timer_interrupt(int irq, void *dev_id)
+ {
+ 	u32 count;
+ 
+-	write_seqlock(&xtime_lock);
+-
+ 	/* latch and read timer 1 */
+ 	__raw_writeb(0x40, PIT_CTRL);
+ 	count = __raw_readb(PIT_T1);
+@@ -192,8 +190,6 @@ ebsa110_timer_interrupt(int irq, void *dev_id)
+ 
+ 	timer_tick();
+ 
+-	write_sequnlock(&xtime_lock);
+-
+ 	return IRQ_HANDLED;
+ }
+ 
+diff --git a/arch/arm/mach-ep93xx/core.c b/arch/arm/mach-ep93xx/core.c
+index 70b2c78..91f6a07 100644
+--- a/arch/arm/mach-ep93xx/core.c
++++ b/arch/arm/mach-ep93xx/core.c
+@@ -3,6 +3,7 @@
+  * Core routines for Cirrus EP93xx chips.
+  *
+  * Copyright (C) 2006 Lennert Buytenhek <buytenh at wantstofly.org>
++ * Copyright (C) 2007 Herbert Valerio Riedel <hvr at gnu.org>
+  *
+  * Thanks go to Michael Burian and Ray Lehtiniemi for their key
+  * role in the ep93xx linux community.
+@@ -21,7 +22,6 @@
+ #include <linux/serial.h>
+ #include <linux/tty.h>
+ #include <linux/bitops.h>
+-#include <linux/serial.h>
+ #include <linux/serial_8250.h>
+ #include <linux/serial_core.h>
+ #include <linux/device.h>
+@@ -99,8 +99,6 @@ static unsigned int last_jiffy_time;
+ 
+ static int ep93xx_timer_interrupt(int irq, void *dev_id)
+ {
+-	write_seqlock(&xtime_lock);
+-
+ 	__raw_writel(1, EP93XX_TIMER1_CLEAR);
+ 	while ((signed long)
+ 		(__raw_readl(EP93XX_TIMER4_VALUE_LOW) - last_jiffy_time)
+@@ -109,8 +107,6 @@ static int ep93xx_timer_interrupt(int irq, void *dev_id)
+ 		timer_tick();
+ 	}
+ 
+-	write_sequnlock(&xtime_lock);
+-
+ 	return IRQ_HANDLED;
+ }
+ 
+@@ -157,38 +153,41 @@ static unsigned char gpio_int_enabled[3];
+ static unsigned char gpio_int_type1[3];
+ static unsigned char gpio_int_type2[3];
+ 
+-static void update_gpio_int_params(int abf)
++/* Port ordering is: A B F */
++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 void update_gpio_int_params(unsigned port)
+ {
+-	if (abf == 0) {
+-		__raw_writeb(0, EP93XX_GPIO_A_INT_ENABLE);
+-		__raw_writeb(gpio_int_type2[0], EP93XX_GPIO_A_INT_TYPE2);
+-		__raw_writeb(gpio_int_type1[0], EP93XX_GPIO_A_INT_TYPE1);
+-		__raw_writeb(gpio_int_unmasked[0] & gpio_int_enabled[0], EP93XX_GPIO_A_INT_ENABLE);
+-	} else if (abf == 1) {
+-		__raw_writeb(0, EP93XX_GPIO_B_INT_ENABLE);
+-		__raw_writeb(gpio_int_type2[1], EP93XX_GPIO_B_INT_TYPE2);
+-		__raw_writeb(gpio_int_type1[1], EP93XX_GPIO_B_INT_TYPE1);
+-		__raw_writeb(gpio_int_unmasked[1] & gpio_int_enabled[1], EP93XX_GPIO_B_INT_ENABLE);
+-	} else if (abf == 2) {
+-		__raw_writeb(0, EP93XX_GPIO_F_INT_ENABLE);
+-		__raw_writeb(gpio_int_type2[2], EP93XX_GPIO_F_INT_TYPE2);
+-		__raw_writeb(gpio_int_type1[2], EP93XX_GPIO_F_INT_TYPE1);
+-		__raw_writeb(gpio_int_unmasked[2] & gpio_int_enabled[2], EP93XX_GPIO_F_INT_ENABLE);
+-	} else {
+-		BUG();
+-	}
+-}
++	BUG_ON(port > 2);
+ 
++	__raw_writeb(0, EP93XX_GPIO_REG(int_en_register_offset[port]));
+ 
+-static unsigned char data_register_offset[8] = {
+-	0x00, 0x04, 0x08, 0x0c, 0x20, 0x30, 0x38, 0x40,
++	__raw_writeb(gpio_int_type2[port],
++		EP93XX_GPIO_REG(int_type2_register_offset[port]));
 +
-+#if defined(CONFIG_BFIN_DCACHE)
-+void bfin_dcache_init(void)
++	__raw_writeb(gpio_int_type1[port],
++		EP93XX_GPIO_REG(int_type1_register_offset[port]));
++
++	__raw_writeb(gpio_int_unmasked[port] & gpio_int_enabled[port],
++		EP93XX_GPIO_REG(int_en_register_offset[port]));
++}
++
++/* Port ordering is: A B F D E C G H */
++static const u8 data_register_offset[8] = {
++	0x00, 0x04, 0x30, 0x0c, 0x20, 0x08, 0x38, 0x40,
+ };
+ 
+-static unsigned char data_direction_register_offset[8] = {
+-	0x10, 0x14, 0x18, 0x1c, 0x24, 0x34, 0x3c, 0x44,
++static const u8 data_direction_register_offset[8] = {
++	0x10, 0x14, 0x34, 0x1c, 0x24, 0x18, 0x3c, 0x44,
+ };
+ 
+-void gpio_line_config(int line, int direction)
++#define GPIO_IN		0
++#define GPIO_OUT	1
++
++static void ep93xx_gpio_set_direction(unsigned line, int direction)
+ {
+ 	unsigned int data_direction_register;
+ 	unsigned long flags;
+@@ -199,14 +198,10 @@ void gpio_line_config(int line, int direction)
+ 
+ 	local_irq_save(flags);
+ 	if (direction == GPIO_OUT) {
+-		if (line >= 0 && line < 16) {
+-			/* Port A/B.  */
++		if (line >= 0 && line <= EP93XX_GPIO_LINE_MAX_IRQ) {
++			/* Port A/B/F */
+ 			gpio_int_unmasked[line >> 3] &= ~(1 << (line & 7));
+ 			update_gpio_int_params(line >> 3);
+-		} else if (line >= 40 && line < 48) {
+-			/* Port F.  */
+-			gpio_int_unmasked[2] &= ~(1 << (line & 7));
+-			update_gpio_int_params(2);
+ 		}
+ 
+ 		v = __raw_readb(data_direction_register);
+@@ -219,39 +214,58 @@ void gpio_line_config(int line, int direction)
+ 	}
+ 	local_irq_restore(flags);
+ }
+-EXPORT_SYMBOL(gpio_line_config);
+ 
+-int gpio_line_get(int line)
++int gpio_direction_input(unsigned gpio)
 +{
-+	unsigned long *table = dcplb_table;
-+	unsigned long ctrl;
-+	int i;
++	if (gpio > EP93XX_GPIO_LINE_MAX)
++		return -EINVAL;
 +
-+	for (i = 0; i < MAX_CPLBS; i++) {
-+		unsigned long addr = *table++;
-+		unsigned long data = *table++;
-+		if (addr == (unsigned long)-1)
-+			break;
-+		bfin_write32(DCPLB_ADDR0 + i * 4, addr);
-+		bfin_write32(DCPLB_DATA0 + i * 4, data);
-+	}
-+	ctrl = bfin_read_DMEM_CONTROL();
-+	ctrl |= DMEM_CNTR;
-+	bfin_write_DMEM_CONTROL(ctrl);
-+	SSYNC();
++	ep93xx_gpio_set_direction(gpio, GPIO_IN);
++
++	return 0;
 +}
-+#endif
-diff --git a/arch/blackfin/kernel/cplb-nompu/cplbhdlr.S b/arch/blackfin/kernel/cplb-nompu/cplbhdlr.S
-new file mode 100644
-index 0000000..2788532
---- /dev/null
-+++ b/arch/blackfin/kernel/cplb-nompu/cplbhdlr.S
-@@ -0,0 +1,130 @@
-+/*
-+ * File:         arch/blackfin/mach-common/cplbhdlr.S
-+ * Based on:
-+ * Author:       LG Soft India
-+ *
-+ * Created:      ?
-+ * Description:  CPLB exception handler
-+ *
-+ * Modified:
-+ *               Copyright 2004-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
-+ */
++EXPORT_SYMBOL(gpio_direction_input);
 +
-+#include <linux/linkage.h>
-+#include <asm/cplb.h>
-+#include <asm/entry.h>
++int gpio_direction_output(unsigned gpio, int value)
++{
++	if (gpio > EP93XX_GPIO_LINE_MAX)
++		return -EINVAL;
 +
-+#ifdef CONFIG_EXCPT_IRQ_SYSC_L1
-+.section .l1.text
-+#else
-+.text
-+#endif
++	gpio_set_value(gpio, value);
++	ep93xx_gpio_set_direction(gpio, GPIO_OUT);
 +
-+.type _cplb_mgr, STT_FUNC;
-+.type _panic_cplb_error, STT_FUNC;
++	return 0;
++}
++EXPORT_SYMBOL(gpio_direction_output);
 +
-+.align 2
++int gpio_get_value(unsigned gpio)
+ {
+ 	unsigned int data_register;
+ 
+-	data_register = EP93XX_GPIO_REG(data_register_offset[line >> 3]);
++	data_register = EP93XX_GPIO_REG(data_register_offset[gpio >> 3]);
+ 
+-	return !!(__raw_readb(data_register) & (1 << (line & 7)));
++	return !!(__raw_readb(data_register) & (1 << (gpio & 7)));
+ }
+-EXPORT_SYMBOL(gpio_line_get);
++EXPORT_SYMBOL(gpio_get_value);
+ 
+-void gpio_line_set(int line, int value)
++void gpio_set_value(unsigned gpio, int value)
+ {
+ 	unsigned int data_register;
+ 	unsigned long flags;
+ 	unsigned char v;
+ 
+-	data_register = EP93XX_GPIO_REG(data_register_offset[line >> 3]);
++	data_register = EP93XX_GPIO_REG(data_register_offset[gpio >> 3]);
+ 
+ 	local_irq_save(flags);
+-	if (value == EP93XX_GPIO_HIGH) {
+-		v = __raw_readb(data_register);
+-		v |= 1 << (line & 7);
+-		__raw_writeb(v, data_register);
+-	} else if (value == EP93XX_GPIO_LOW) {
+-		v = __raw_readb(data_register);
+-		v &= ~(1 << (line & 7));
+-		__raw_writeb(v, data_register);
+-	}
++	v = __raw_readb(data_register);
++	if (value)
++		v |= 1 << (gpio & 7);
++	else
++		v &= ~(1 << (gpio & 7));
++	__raw_writeb(v, data_register);
+ 	local_irq_restore(flags);
+ }
+-EXPORT_SYMBOL(gpio_line_set);
++EXPORT_SYMBOL(gpio_set_value);
+ 
+ 
+ /*************************************************************************
+@@ -265,47 +279,67 @@ static void ep93xx_gpio_ab_irq_handler(unsigned int irq, struct irq_desc *desc)
+ 	status = __raw_readb(EP93XX_GPIO_A_INT_STATUS);
+ 	for (i = 0; i < 8; i++) {
+ 		if (status & (1 << i)) {
+-			desc = irq_desc + IRQ_EP93XX_GPIO(0) + i;
+-			desc_handle_irq(IRQ_EP93XX_GPIO(0) + i, desc);
++			int gpio_irq = gpio_to_irq(EP93XX_GPIO_LINE_A(0)) + i;
++			desc = irq_desc + gpio_irq;
++			desc_handle_irq(gpio_irq, desc);
+ 		}
+ 	}
+ 
+ 	status = __raw_readb(EP93XX_GPIO_B_INT_STATUS);
+ 	for (i = 0; i < 8; i++) {
+ 		if (status & (1 << i)) {
+-			desc = irq_desc + IRQ_EP93XX_GPIO(8) + i;
+-			desc_handle_irq(IRQ_EP93XX_GPIO(8) + i, desc);
++			int gpio_irq = gpio_to_irq(EP93XX_GPIO_LINE_B(0)) + i;
++			desc = irq_desc + gpio_irq;
++			desc_handle_irq(gpio_irq, desc);
+ 		}
+ 	}
+ }
+ 
+ static void ep93xx_gpio_f_irq_handler(unsigned int irq, struct irq_desc *desc)
+ {
+-	int gpio_irq = IRQ_EP93XX_GPIO(16) + (((irq + 1) & 7) ^ 4);
++	/*
++	 * map discontiguous hw irq range to continous sw irq range:
++	 *
++	 *  IRQ_EP93XX_GPIO{0..7}MUX -> gpio_to_irq(EP93XX_GPIO_LINE_F({0..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);
+ }
+ 
++static void ep93xx_gpio_irq_ack(unsigned int irq)
++{
++	int line = irq_to_gpio(irq);
++	int port = line >> 3;
++	int port_mask = 1 << (line & 7);
 +
-+ENTRY(__cplb_hdr)
-+	R2 = SEQSTAT;
++	if ((irq_desc[irq].status & IRQ_TYPE_SENSE_MASK) == IRQT_BOTHEDGE) {
++		gpio_int_type2[port] ^= port_mask; /* switch edge direction */
++		update_gpio_int_params(port);
++	}
 +
-+	/* Mask the contents of SEQSTAT and leave only EXCAUSE in R2 */
-+	R2 <<= 26;
-+	R2 >>= 26;
++	__raw_writeb(port_mask, EP93XX_GPIO_REG(eoi_register_offset[port]));
++}
 +
-+	R1 = 0x23; /* Data access CPLB protection violation */
-+	CC = R2 == R1;
-+	IF !CC JUMP .Lnot_data_write;
-+	R0 = 2;		/* is a write to data space*/
-+	JUMP .Lis_icplb_miss;
+ static void ep93xx_gpio_irq_mask_ack(unsigned int irq)
+ {
+-	int line = irq - IRQ_EP93XX_GPIO(0);
++	int line = irq_to_gpio(irq);
+ 	int port = line >> 3;
++	int port_mask = 1 << (line & 7);
+ 
+-	gpio_int_unmasked[port] &= ~(1 << (line & 7));
++	if ((irq_desc[irq].status & IRQ_TYPE_SENSE_MASK) == IRQT_BOTHEDGE)
++		gpio_int_type2[port] ^= port_mask; /* switch edge direction */
 +
-+.Lnot_data_write:
-+	R1 = 0x2C; /* CPLB miss on an instruction fetch */
-+	CC = R2 == R1;
-+	R0 = 0;		/* is_data_miss == False*/
-+	IF CC JUMP .Lis_icplb_miss;
++	gpio_int_unmasked[port] &= ~port_mask;
+ 	update_gpio_int_params(port);
+ 
+-	if (port == 0) {
+-		__raw_writel(1 << (line & 7), EP93XX_GPIO_A_INT_ACK);
+-	} else if (port == 1) {
+-		__raw_writel(1 << (line & 7), EP93XX_GPIO_B_INT_ACK);
+-	} else if (port == 2) {
+-		__raw_writel(1 << (line & 7), EP93XX_GPIO_F_INT_ACK);
+-	}
++	__raw_writeb(port_mask, EP93XX_GPIO_REG(eoi_register_offset[port]));
+ }
+ 
+ static void ep93xx_gpio_irq_mask(unsigned int irq)
+ {
+-	int line = irq - IRQ_EP93XX_GPIO(0);
++	int line = irq_to_gpio(irq);
+ 	int port = line >> 3;
+ 
+ 	gpio_int_unmasked[port] &= ~(1 << (line & 7));
+@@ -314,7 +348,7 @@ static void ep93xx_gpio_irq_mask(unsigned int irq)
+ 
+ static void ep93xx_gpio_irq_unmask(unsigned int irq)
+ {
+-	int line = irq - IRQ_EP93XX_GPIO(0);
++	int line = irq_to_gpio(irq);
+ 	int port = line >> 3;
+ 
+ 	gpio_int_unmasked[port] |= 1 << (line & 7);
+@@ -329,38 +363,54 @@ static void ep93xx_gpio_irq_unmask(unsigned int irq)
+  */
+ static int ep93xx_gpio_irq_type(unsigned int irq, unsigned int type)
+ {
+-	int port;
+-	int line;
+-
+-	line = irq - IRQ_EP93XX_GPIO(0);
+-	if (line >= 0 && line < 16) {
+-		gpio_line_config(line, GPIO_IN);
+-	} else {
+-		gpio_line_config(EP93XX_GPIO_LINE_F(line-16), GPIO_IN);
++	struct irq_desc *desc = irq_desc + irq;
++	const int gpio = irq_to_gpio(irq);
++	const int port = gpio >> 3;
++	const int port_mask = 1 << (gpio & 7);
 +
-+	R1 = 0x26;
-+	CC = R2 == R1;
-+	IF !CC JUMP .Lunknown;
++	ep93xx_gpio_set_direction(gpio, GPIO_IN);
 +
-+	R0 = 1;		/* is_data_miss == True*/
++	switch (type) {
++	case IRQT_RISING:
++		gpio_int_type1[port] |= port_mask;
++		gpio_int_type2[port] |= port_mask;
++		desc->handle_irq = handle_edge_irq;
++		break;
++	case IRQT_FALLING:
++		gpio_int_type1[port] |= port_mask;
++		gpio_int_type2[port] &= ~port_mask;
++		desc->handle_irq = handle_edge_irq;
++		break;
++	case IRQT_HIGH:
++		gpio_int_type1[port] &= ~port_mask;
++		gpio_int_type2[port] |= port_mask;
++		desc->handle_irq = handle_level_irq;
++		break;
++	case IRQT_LOW:
++		gpio_int_type1[port] &= ~port_mask;
++		gpio_int_type2[port] &= ~port_mask;
++		desc->handle_irq = handle_level_irq;
++		break;
++	case IRQT_BOTHEDGE:
++		gpio_int_type1[port] |= port_mask;
++		/* set initial polarity based on current input level */
++		if (gpio_get_value(gpio))
++			gpio_int_type2[port] &= ~port_mask; /* falling */
++		else
++			gpio_int_type2[port] |= port_mask; /* rising */
++		desc->handle_irq = handle_edge_irq;
++		break;
++	default:
++		pr_err("ep93xx: failed to set irq type %d for gpio %d\n",
++		       type, gpio);
++		return -EINVAL;
+ 	}
+ 
+-	port = line >> 3;
+-	line &= 7;
+-
+-	if (type & IRQT_RISING) {
+-		gpio_int_enabled[port] |= 1 << line;
+-		gpio_int_type1[port] |= 1 << line;
+-		gpio_int_type2[port] |= 1 << line;
+-	} else if (type & IRQT_FALLING) {
+-		gpio_int_enabled[port] |= 1 << line;
+-		gpio_int_type1[port] |= 1 << line;
+-		gpio_int_type2[port] &= ~(1 << line);
+-	} else if (type & IRQT_HIGH) {
+-		gpio_int_enabled[port] |= 1 << line;
+-		gpio_int_type1[port] &= ~(1 << line);
+-		gpio_int_type2[port] |= 1 << line;
+-	} else if (type & IRQT_LOW) {
+-		gpio_int_enabled[port] |= 1 << line;
+-		gpio_int_type1[port] &= ~(1 << line);
+-		gpio_int_type2[port] &= ~(1 << line);
+-	} else {
+-		gpio_int_enabled[port] &= ~(1 << line);
+-	}
++	gpio_int_enabled[port] |= port_mask;
 +
-+.Lis_icplb_miss:
++	desc->status &= ~IRQ_TYPE_SENSE_MASK;
++	desc->status |= type & IRQ_TYPE_SENSE_MASK;
 +
-+#if defined(CONFIG_BFIN_ICACHE) || defined(CONFIG_BFIN_DCACHE)
-+# if defined(CONFIG_BFIN_ICACHE) && !defined(CONFIG_BFIN_DCACHE)
-+	R1 = CPLB_ENABLE_ICACHE;
-+# endif
-+# if !defined(CONFIG_BFIN_ICACHE) && defined(CONFIG_BFIN_DCACHE)
-+	R1 = CPLB_ENABLE_DCACHE;
-+# endif
-+# if defined(CONFIG_BFIN_ICACHE) && defined(CONFIG_BFIN_DCACHE)
-+	R1 = CPLB_ENABLE_DCACHE | CPLB_ENABLE_ICACHE;
-+# endif
-+#else
-+	R1 = 0;
-+#endif
+ 	update_gpio_int_params(port);
+ 
+ 	return 0;
+@@ -368,7 +418,8 @@ static int ep93xx_gpio_irq_type(unsigned int irq, unsigned int type)
+ 
+ static struct irq_chip ep93xx_gpio_irq_chip = {
+ 	.name		= "GPIO",
+-	.ack		= ep93xx_gpio_irq_mask_ack,
++	.ack		= ep93xx_gpio_irq_ack,
++	.mask_ack	= ep93xx_gpio_irq_mask_ack,
+ 	.mask		= ep93xx_gpio_irq_mask,
+ 	.unmask		= ep93xx_gpio_irq_unmask,
+ 	.set_type	= ep93xx_gpio_irq_type,
+@@ -377,15 +428,16 @@ static struct irq_chip ep93xx_gpio_irq_chip = {
+ 
+ void __init ep93xx_init_irq(void)
+ {
+-	int irq;
++	int gpio_irq;
+ 
+ 	vic_init((void *)EP93XX_VIC1_BASE, 0, EP93XX_VIC1_VALID_IRQ_MASK);
+ 	vic_init((void *)EP93XX_VIC2_BASE, 32, EP93XX_VIC2_VALID_IRQ_MASK);
+ 
+-	for (irq = IRQ_EP93XX_GPIO(0); irq <= IRQ_EP93XX_GPIO(23); irq++) {
+-		set_irq_chip(irq, &ep93xx_gpio_irq_chip);
+-		set_irq_handler(irq, handle_level_irq);
+-		set_irq_flags(irq, IRQF_VALID);
++	for (gpio_irq = gpio_to_irq(0);
++	     gpio_irq <= gpio_to_irq(EP93XX_GPIO_LINE_MAX_IRQ); ++gpio_irq) {
++		set_irq_chip(gpio_irq, &ep93xx_gpio_irq_chip);
++		set_irq_handler(gpio_irq, handle_level_irq);
++		set_irq_flags(gpio_irq, IRQF_VALID);
+ 	}
+ 
+ 	set_irq_chained_handler(IRQ_EP93XX_GPIO_AB, ep93xx_gpio_ab_irq_handler);
+diff --git a/arch/arm/mach-footbridge/dc21285-timer.c b/arch/arm/mach-footbridge/dc21285-timer.c
+index 3a63941..b2a2118 100644
+--- a/arch/arm/mach-footbridge/dc21285-timer.c
++++ b/arch/arm/mach-footbridge/dc21285-timer.c
+@@ -30,14 +30,10 @@ static unsigned long timer1_gettimeoffset (void)
+ static irqreturn_t
+ timer1_interrupt(int irq, void *dev_id)
+ {
+-	write_seqlock(&xtime_lock);
+-
+ 	*CSR_TIMER1_CLR = 0;
+ 
+ 	timer_tick();
+ 
+-	write_sequnlock(&xtime_lock);
+-
+ 	return IRQ_HANDLED;
+ }
+ 
+diff --git a/arch/arm/mach-footbridge/isa-timer.c b/arch/arm/mach-footbridge/isa-timer.c
+index d08d641..a764e01 100644
+--- a/arch/arm/mach-footbridge/isa-timer.c
++++ b/arch/arm/mach-footbridge/isa-timer.c
+@@ -64,9 +64,7 @@ static unsigned long isa_gettimeoffset(void)
+ static irqreturn_t
+ isa_timer_interrupt(int irq, void *dev_id)
+ {
+-	write_seqlock(&xtime_lock);
+ 	timer_tick();
+-	write_sequnlock(&xtime_lock);
+ 	return IRQ_HANDLED;
+ }
+ 
+diff --git a/arch/arm/mach-h720x/cpu-h7201.c b/arch/arm/mach-h720x/cpu-h7201.c
+index 9107b8e..c2a431f 100644
+--- a/arch/arm/mach-h720x/cpu-h7201.c
++++ b/arch/arm/mach-h720x/cpu-h7201.c
+@@ -29,13 +29,9 @@
+ static irqreturn_t
+ h7201_timer_interrupt(int irq, void *dev_id)
+ {
+-	write_seqlock(&xtime_lock);
+-
+ 	CPU_REG (TIMER_VIRT, TIMER_TOPSTAT);
+ 	timer_tick();
+ 
+-	write_sequnlock(&xtime_lock);
+-
+ 	return IRQ_HANDLED;
+ }
+ 
+diff --git a/arch/arm/mach-h720x/cpu-h7202.c b/arch/arm/mach-h720x/cpu-h7202.c
+index 0a1a25f..c627fa1 100644
+--- a/arch/arm/mach-h720x/cpu-h7202.c
++++ b/arch/arm/mach-h720x/cpu-h7202.c
+@@ -113,9 +113,7 @@ h7202_timerx_demux_handler(unsigned int irq_unused, struct irq_desc *desc)
+ 	mask = CPU_REG (TIMER_VIRT, TIMER_TOPSTAT);
+ 
+ 	if ( mask & TSTAT_T0INT ) {
+-		write_seqlock(&xtime_lock);
+ 		timer_tick();
+-		write_sequnlock(&xtime_lock);
+ 		if( mask == TSTAT_T0INT )
+ 			return;
+ 	}
+diff --git a/arch/arm/mach-integrator/core.c b/arch/arm/mach-integrator/core.c
+index e9c82de..7fbbc17 100644
+--- a/arch/arm/mach-integrator/core.c
++++ b/arch/arm/mach-integrator/core.c
+@@ -250,8 +250,6 @@ unsigned long integrator_gettimeoffset(void)
+ static irqreturn_t
+ integrator_timer_interrupt(int irq, void *dev_id)
+ {
+-	write_seqlock(&xtime_lock);
+-
+ 	/*
+ 	 * clear the interrupt
+ 	 */
+@@ -259,8 +257,6 @@ integrator_timer_interrupt(int irq, void *dev_id)
+ 
+ 	timer_tick();
+ 
+-	write_sequnlock(&xtime_lock);
+-
+ 	return IRQ_HANDLED;
+ }
+ 
+diff --git a/arch/arm/mach-integrator/integrator_ap.c b/arch/arm/mach-integrator/integrator_ap.c
+index 7228075..df37e93 100644
+--- a/arch/arm/mach-integrator/integrator_ap.c
++++ b/arch/arm/mach-integrator/integrator_ap.c
+@@ -214,7 +214,7 @@ static int irq_resume(struct sys_device *dev)
+ #endif
+ 
+ static struct sysdev_class irq_class = {
+-	set_kset_name("irq"),
++	.name		= "irq",
+ 	.suspend	= irq_suspend,
+ 	.resume		= irq_resume,
+ };
+diff --git a/arch/arm/mach-integrator/pci_v3.c b/arch/arm/mach-integrator/pci_v3.c
+index d4d8134..d55fa4e 100644
+--- a/arch/arm/mach-integrator/pci_v3.c
++++ b/arch/arm/mach-integrator/pci_v3.c
+@@ -440,7 +440,7 @@ v3_pci_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
+ 	return 1;
+ }
+ 
+-static irqreturn_t v3_irq(int irq, void *devid)
++static irqreturn_t v3_irq(int dummy, void *devid)
+ {
+ #ifdef CONFIG_DEBUG_LL
+ 	struct pt_regs *regs = get_irq_regs();
+@@ -448,8 +448,10 @@ static irqreturn_t v3_irq(int irq, void *devid)
+ 	unsigned long instr = *(unsigned long *)pc;
+ 	char buf[128];
+ 
+-	sprintf(buf, "V3 int %d: pc=0x%08lx [%08lx] LBFADDR=%08x LBFCODE=%02x ISTAT=%02x\n", irq,
+-		pc, instr, __raw_readl(SC_LBFADDR), __raw_readl(SC_LBFCODE) & 255,
++	sprintf(buf, "V3 int %d: pc=0x%08lx [%08lx] LBFADDR=%08x LBFCODE=%02x "
++		"ISTAT=%02x\n", IRQ_AP_V3INT, pc, instr,
++		__raw_readl(SC_LBFADDR),
++		__raw_readl(SC_LBFCODE) & 255,
+ 		v3_readb(V3_LB_ISTAT));
+ 	printascii(buf);
+ #endif
+diff --git a/arch/arm/mach-iop32x/glantank.c b/arch/arm/mach-iop32x/glantank.c
+index 2b086ab..74c65ce 100644
+--- a/arch/arm/mach-iop32x/glantank.c
++++ b/arch/arm/mach-iop32x/glantank.c
+@@ -3,7 +3,7 @@
+  *
+  * Board support code for the GLAN Tank.
+  *
+- * Copyright (C) 2006 Martin Michlmayr <tbm at cyrius.com>
++ * Copyright (C) 2006, 2007 Martin Michlmayr <tbm at cyrius.com>
+  * Copyright (C) 2006 Lennert Buytenhek <buytenh at wantstofly.org>
+  *
+  * This program is free software; you can redistribute it and/or modify it
+@@ -21,6 +21,7 @@
+ #include <linux/serial_core.h>
+ #include <linux/serial_8250.h>
+ #include <linux/mtd/physmap.h>
++#include <linux/i2c.h>
+ #include <linux/platform_device.h>
+ #include <asm/hardware.h>
+ #include <asm/io.h>
+@@ -118,7 +119,7 @@ subsys_initcall(glantank_pci_init);
+  * GLAN Tank machine initialization.
+  */
+ static struct physmap_flash_data glantank_flash_data = {
+-	.width		= 1,
++	.width		= 2,
+ };
+ 
+ static struct resource glantank_flash_resource = {
+@@ -166,6 +167,13 @@ static struct platform_device glantank_serial_device = {
+ 	.resource	= &glantank_uart_resource,
+ };
+ 
++static struct i2c_board_info __initdata glantank_i2c_devices[] = {
++	{
++		I2C_BOARD_INFO("rtc-rs5c372", 0x32),
++		.type = "rs5c372a",
++	},
++};
 +
-+	[--SP] = RETS;
-+	CALL _cplb_mgr;
-+	RETS = [SP++];
-+	CC = R0 == 0;
-+	IF !CC JUMP .Lnot_replaced;
-+	RTS;
+ static void glantank_power_off(void)
+ {
+ 	__raw_writeb(0x01, 0xfe8d0004);
+@@ -183,6 +191,9 @@ static void __init glantank_init_machine(void)
+ 	platform_device_register(&iop3xx_dma_0_channel);
+ 	platform_device_register(&iop3xx_dma_1_channel);
+ 
++	i2c_register_board_info(0, glantank_i2c_devices,
++		ARRAY_SIZE(glantank_i2c_devices));
 +
-+/*
-+ * Diagnostic exception handlers
-+ */
-+.Lunknown:
-+	R0 = CPLB_UNKNOWN_ERR;
-+	JUMP .Lcplb_error;
+ 	pm_power_off = glantank_power_off;
+ }
+ 
+diff --git a/arch/arm/mach-ixp2000/core.c b/arch/arm/mach-ixp2000/core.c
+index cb6ad21..81cdc82 100644
+--- a/arch/arm/mach-ixp2000/core.c
++++ b/arch/arm/mach-ixp2000/core.c
+@@ -206,8 +206,6 @@ unsigned long ixp2000_gettimeoffset (void)
+ 
+ static int ixp2000_timer_interrupt(int irq, void *dev_id)
+ {
+-	write_seqlock(&xtime_lock);
+-
+ 	/* clear timer 1 */
+ 	ixp2000_reg_wrb(IXP2000_T1_CLR, 1);
+ 
+@@ -217,8 +215,6 @@ static int ixp2000_timer_interrupt(int irq, void *dev_id)
+ 		next_jiffy_time -= ticks_per_jiffy;
+ 	}
+ 
+-	write_sequnlock(&xtime_lock);
+-
+ 	return IRQ_HANDLED;
+ }
+ 
+diff --git a/arch/arm/mach-ixp23xx/core.c b/arch/arm/mach-ixp23xx/core.c
+index 16356ff..5fea5a1 100644
+--- a/arch/arm/mach-ixp23xx/core.c
++++ b/arch/arm/mach-ixp23xx/core.c
+@@ -22,7 +22,6 @@
+ #include <linux/serial.h>
+ #include <linux/tty.h>
+ #include <linux/bitops.h>
+-#include <linux/serial.h>
+ #include <linux/serial_8250.h>
+ #include <linux/serial_core.h>
+ #include <linux/device.h>
+diff --git a/arch/arm/mach-ixp23xx/espresso.c b/arch/arm/mach-ixp23xx/espresso.c
+index 7a85ced..d3a779a 100644
+--- a/arch/arm/mach-ixp23xx/espresso.c
++++ b/arch/arm/mach-ixp23xx/espresso.c
+@@ -19,7 +19,6 @@
+ #include <linux/tty.h>
+ #include <linux/bitops.h>
+ #include <linux/ioport.h>
+-#include <linux/serial.h>
+ #include <linux/serial_8250.h>
+ #include <linux/serial_core.h>
+ #include <linux/device.h>
+@@ -40,7 +39,6 @@
+ #include <asm/mach/map.h>
+ #include <asm/mach/irq.h>
+ #include <asm/mach/arch.h>
+-#include <asm/mach/irq.h>
+ #include <asm/mach/pci.h>
+ 
+ static int __init espresso_pci_init(void)
+diff --git a/arch/arm/mach-ixp23xx/ixdp2351.c b/arch/arm/mach-ixp23xx/ixdp2351.c
+index c41a6b5..5c5d4d6 100644
+--- a/arch/arm/mach-ixp23xx/ixdp2351.c
++++ b/arch/arm/mach-ixp23xx/ixdp2351.c
+@@ -24,7 +24,6 @@
+ #include <linux/tty.h>
+ #include <linux/bitops.h>
+ #include <linux/ioport.h>
+-#include <linux/serial.h>
+ #include <linux/serial_8250.h>
+ #include <linux/serial_core.h>
+ #include <linux/device.h>
+@@ -44,7 +43,6 @@
+ #include <asm/mach/map.h>
+ #include <asm/mach/irq.h>
+ #include <asm/mach/arch.h>
+-#include <asm/mach/irq.h>
+ #include <asm/mach/pci.h>
+ 
+ /*
+diff --git a/arch/arm/mach-ixp23xx/roadrunner.c b/arch/arm/mach-ixp23xx/roadrunner.c
+index e356449..f0f70ba 100644
+--- a/arch/arm/mach-ixp23xx/roadrunner.c
++++ b/arch/arm/mach-ixp23xx/roadrunner.c
+@@ -23,7 +23,6 @@
+ #include <linux/tty.h>
+ #include <linux/bitops.h>
+ #include <linux/ioport.h>
+-#include <linux/serial.h>
+ #include <linux/serial_8250.h>
+ #include <linux/serial_core.h>
+ #include <linux/device.h>
+@@ -44,7 +43,6 @@
+ #include <asm/mach/map.h>
+ #include <asm/mach/irq.h>
+ #include <asm/mach/arch.h>
+-#include <asm/mach/irq.h>
+ #include <asm/mach/pci.h>
+ 
+ /*
+diff --git a/arch/arm/mach-ixp4xx/avila-setup.c b/arch/arm/mach-ixp4xx/avila-setup.c
+index d59b8dc..e38f45f 100644
+--- a/arch/arm/mach-ixp4xx/avila-setup.c
++++ b/arch/arm/mach-ixp4xx/avila-setup.c
+@@ -18,6 +18,7 @@
+ #include <linux/tty.h>
+ #include <linux/serial_8250.h>
+ #include <linux/slab.h>
++#include <linux/i2c-gpio.h>
+ 
+ #include <asm/types.h>
+ #include <asm/setup.h>
+@@ -47,18 +48,17 @@ static struct platform_device avila_flash = {
+ 	.resource	= &avila_flash_resource,
+ };
+ 
+-static struct ixp4xx_i2c_pins avila_i2c_gpio_pins = {
++static struct i2c_gpio_platform_data avila_i2c_gpio_data = {
+ 	.sda_pin	= AVILA_SDA_PIN,
+ 	.scl_pin	= AVILA_SCL_PIN,
+ };
+ 
+-static struct platform_device avila_i2c_controller = {
+-	.name		= "IXP4XX-I2C",
++static struct platform_device avila_i2c_gpio = {
++	.name		= "i2c-gpio",
+ 	.id		= 0,
+-	.dev		= {
+-		.platform_data = &avila_i2c_gpio_pins,
++	.dev	 = {
++		.platform_data	= &avila_i2c_gpio_data,
+ 	},
+-	.num_resources	= 0
+ };
+ 
+ static struct resource avila_uart_resources[] = {
+@@ -133,7 +133,7 @@ static struct platform_device avila_pata = {
+ };
+ 
+ static struct platform_device *avila_devices[] __initdata = {
+-	&avila_i2c_controller,
++	&avila_i2c_gpio,
+ 	&avila_flash,
+ 	&avila_uart
+ };
+diff --git a/arch/arm/mach-ixp4xx/dsmg600-setup.c b/arch/arm/mach-ixp4xx/dsmg600-setup.c
+index 1e75e10..c473d40 100644
+--- a/arch/arm/mach-ixp4xx/dsmg600-setup.c
++++ b/arch/arm/mach-ixp4xx/dsmg600-setup.c
+@@ -14,6 +14,7 @@
+ #include <linux/kernel.h>
+ #include <linux/serial.h>
+ #include <linux/serial_8250.h>
++#include <linux/i2c-gpio.h>
+ 
+ #include <asm/mach-types.h>
+ #include <asm/mach/arch.h>
+@@ -37,15 +38,17 @@ static struct platform_device dsmg600_flash = {
+ 	.resource		= &dsmg600_flash_resource,
+ };
+ 
+-static struct ixp4xx_i2c_pins dsmg600_i2c_gpio_pins = {
++static struct i2c_gpio_platform_data dsmg600_i2c_gpio_data = {
+ 	.sda_pin		= DSMG600_SDA_PIN,
+ 	.scl_pin		= DSMG600_SCL_PIN,
+ };
+ 
+-static struct platform_device dsmg600_i2c_controller = {
+-	.name			= "IXP4XX-I2C",
++static struct platform_device dsmg600_i2c_gpio = {
++	.name			= "i2c-gpio",
+ 	.id			= 0,
+-	.dev.platform_data	= &dsmg600_i2c_gpio_pins,
++	.dev	 = {
++		.platform_data	= &dsmg600_i2c_gpio_data,
++	},
+ };
+ 
+ #ifdef CONFIG_LEDS_CLASS
+@@ -116,7 +119,7 @@ static struct platform_device dsmg600_uart = {
+ };
+ 
+ static struct platform_device *dsmg600_devices[] __initdata = {
+-	&dsmg600_i2c_controller,
++	&dsmg600_i2c_gpio,
+ 	&dsmg600_flash,
+ };
+ 
+diff --git a/arch/arm/mach-ixp4xx/ixdp425-setup.c b/arch/arm/mach-ixp4xx/ixdp425-setup.c
+index d5008d8..e89070d 100644
+--- a/arch/arm/mach-ixp4xx/ixdp425-setup.c
++++ b/arch/arm/mach-ixp4xx/ixdp425-setup.c
+@@ -15,6 +15,7 @@
+ #include <linux/tty.h>
+ #include <linux/serial_8250.h>
+ #include <linux/slab.h>
++#include <linux/i2c-gpio.h>
+ #include <linux/io.h>
+ #include <linux/mtd/mtd.h>
+ #include <linux/mtd/nand.h>
+@@ -120,18 +121,17 @@ static struct platform_device ixdp425_flash_nand = {
+ };
+ #endif	/* CONFIG_MTD_NAND_PLATFORM */
+ 
+-static struct ixp4xx_i2c_pins ixdp425_i2c_gpio_pins = {
++static struct i2c_gpio_platform_data ixdp425_i2c_gpio_data = {
+ 	.sda_pin	= IXDP425_SDA_PIN,
+ 	.scl_pin	= IXDP425_SCL_PIN,
+ };
+ 
+-static struct platform_device ixdp425_i2c_controller = {
+-	.name		= "IXP4XX-I2C",
++static struct platform_device ixdp425_i2c_gpio = {
++	.name		= "i2c-gpio",
+ 	.id		= 0,
+-	.dev		= {
+-		.platform_data = &ixdp425_i2c_gpio_pins,
++	.dev	 = {
++		.platform_data	= &ixdp425_i2c_gpio_data,
+ 	},
+-	.num_resources	= 0
+ };
+ 
+ static struct resource ixdp425_uart_resources[] = {
+@@ -178,7 +178,7 @@ static struct platform_device ixdp425_uart = {
+ };
+ 
+ static struct platform_device *ixdp425_devices[] __initdata = {
+-	&ixdp425_i2c_controller,
++	&ixdp425_i2c_gpio,
+ 	&ixdp425_flash,
+ #if defined(CONFIG_MTD_NAND_PLATFORM) || \
+     defined(CONFIG_MTD_NAND_PLATFORM_MODULE)
+diff --git a/arch/arm/mach-ixp4xx/nas100d-setup.c b/arch/arm/mach-ixp4xx/nas100d-setup.c
+index 78a1741..54d884f 100644
+--- a/arch/arm/mach-ixp4xx/nas100d-setup.c
++++ b/arch/arm/mach-ixp4xx/nas100d-setup.c
+@@ -16,6 +16,7 @@
+ #include <linux/serial.h>
+ #include <linux/serial_8250.h>
+ #include <linux/leds.h>
++#include <linux/i2c-gpio.h>
+ 
+ #include <asm/mach-types.h>
+ #include <asm/mach/arch.h>
+@@ -68,16 +69,17 @@ static struct platform_device nas100d_leds = {
+ };
+ #endif
+ 
+-static struct ixp4xx_i2c_pins nas100d_i2c_gpio_pins = {
++static struct i2c_gpio_platform_data nas100d_i2c_gpio_data = {
+ 	.sda_pin		= NAS100D_SDA_PIN,
+ 	.scl_pin		= NAS100D_SCL_PIN,
+ };
+ 
+-static struct platform_device nas100d_i2c_controller = {
+-	.name			= "IXP4XX-I2C",
++static struct platform_device nas100d_i2c_gpio = {
++	.name			= "i2c-gpio",
+ 	.id			= 0,
+-	.dev.platform_data	= &nas100d_i2c_gpio_pins,
+-	.num_resources		= 0,
++	.dev	 = {
++		.platform_data	= &nas100d_i2c_gpio_data,
++	},
+ };
+ 
+ static struct resource nas100d_uart_resources[] = {
+@@ -124,7 +126,7 @@ static struct platform_device nas100d_uart = {
+ };
+ 
+ static struct platform_device *nas100d_devices[] __initdata = {
+-	&nas100d_i2c_controller,
++	&nas100d_i2c_gpio,
+ 	&nas100d_flash,
+ #ifdef CONFIG_LEDS_IXP4XX
+ 	&nas100d_leds,
+diff --git a/arch/arm/mach-ixp4xx/nslu2-power.c b/arch/arm/mach-ixp4xx/nslu2-power.c
+index acd71e9..6f10dc2 100644
+--- a/arch/arm/mach-ixp4xx/nslu2-power.c
++++ b/arch/arm/mach-ixp4xx/nslu2-power.c
+@@ -21,7 +21,6 @@
+ #include <linux/reboot.h>
+ #include <linux/irq.h>
+ #include <linux/interrupt.h>
+-#include <linux/reboot.h>
+ 
+ #include <asm/mach-types.h>
+ 
+diff --git a/arch/arm/mach-ixp4xx/nslu2-setup.c b/arch/arm/mach-ixp4xx/nslu2-setup.c
+index 9bf8ccb..77277d2 100644
+--- a/arch/arm/mach-ixp4xx/nslu2-setup.c
++++ b/arch/arm/mach-ixp4xx/nslu2-setup.c
+@@ -18,6 +18,7 @@
+ #include <linux/serial.h>
+ #include <linux/serial_8250.h>
+ #include <linux/leds.h>
++#include <linux/i2c-gpio.h>
+ 
+ #include <asm/mach-types.h>
+ #include <asm/mach/arch.h>
+@@ -41,7 +42,7 @@ static struct platform_device nslu2_flash = {
+ 	.resource		= &nslu2_flash_resource,
+ };
+ 
+-static struct ixp4xx_i2c_pins nslu2_i2c_gpio_pins = {
++static struct i2c_gpio_platform_data nslu2_i2c_gpio_data = {
+ 	.sda_pin		= NSLU2_SDA_PIN,
+ 	.scl_pin		= NSLU2_SCL_PIN,
+ };
+@@ -82,11 +83,12 @@ static struct platform_device nslu2_leds = {
+ };
+ #endif
+ 
+-static struct platform_device nslu2_i2c_controller = {
+-	.name			= "IXP4XX-I2C",
++static struct platform_device nslu2_i2c_gpio = {
++	.name			= "i2c-gpio",
+ 	.id			= 0,
+-	.dev.platform_data	= &nslu2_i2c_gpio_pins,
+-	.num_resources		= 0,
++	.dev	 = {
++		.platform_data	= &nslu2_i2c_gpio_data,
++	},
+ };
+ 
+ static struct platform_device nslu2_beeper = {
+@@ -139,7 +141,7 @@ static struct platform_device nslu2_uart = {
+ };
+ 
+ static struct platform_device *nslu2_devices[] __initdata = {
+-	&nslu2_i2c_controller,
++	&nslu2_i2c_gpio,
+ 	&nslu2_flash,
+ 	&nslu2_beeper,
+ #ifdef CONFIG_LEDS_IXP4XX
+diff --git a/arch/arm/mach-ks8695/Makefile b/arch/arm/mach-ks8695/Makefile
+index 2a07a28..730a3af 100644
+--- a/arch/arm/mach-ks8695/Makefile
++++ b/arch/arm/mach-ks8695/Makefile
+@@ -9,7 +9,7 @@ obj-n				:=
+ obj-				:=
+ 
+ # PCI support is optional
+-#obj-$(CONFIG_PCI)		+= pci.o
++obj-$(CONFIG_PCI)		+= pci.o
+ 
+ # Board-specific support
+ obj-$(CONFIG_MACH_KS8695)	+= board-micrel.o
+diff --git a/arch/arm/mach-ks8695/board-micrel.c b/arch/arm/mach-ks8695/board-micrel.c
+index 2feeef8..05ac2bd 100644
+--- a/arch/arm/mach-ks8695/board-micrel.c
++++ b/arch/arm/mach-ks8695/board-micrel.c
+@@ -40,7 +40,7 @@ static void __init micrel_init(void)
+ 	printk(KERN_INFO "Micrel KS8695 Development Board initializing\n");
+ 
+ #ifdef CONFIG_PCI
+-//	ks8695_init_pci(&micrel_pci);
++	ks8695_init_pci(&micrel_pci);
+ #endif
+ 
+ 	/* Add devices */
+diff --git a/arch/arm/mach-ks8695/gpio.c b/arch/arm/mach-ks8695/gpio.c
+index b1aa3cb..5e46191 100644
+--- a/arch/arm/mach-ks8695/gpio.c
++++ b/arch/arm/mach-ks8695/gpio.c
+@@ -20,6 +20,8 @@
+ #include <linux/kernel.h>
+ #include <linux/mm.h>
+ #include <linux/init.h>
++#include <linux/debugfs.h>
++#include <linux/seq_file.h>
+ #include <linux/module.h>
+ 
+ #include <asm/io.h>
+@@ -216,3 +218,84 @@ int irq_to_gpio(unsigned int irq)
+ 	return (irq - KS8695_IRQ_EXTERN0);
+ }
+ EXPORT_SYMBOL(irq_to_gpio);
 +
-+.Lnot_replaced:
-+	CC = R0 == CPLB_NO_UNLOCKED;
-+	IF !CC JUMP .Lnext_check;
-+	R0 = CPLB_NO_UNLOCKED;
-+	JUMP .Lcplb_error;
 +
-+.Lnext_check:
-+	CC = R0 == CPLB_NO_ADDR_MATCH;
-+	IF !CC JUMP .Lnext_check2;
-+	R0 = CPLB_NO_ADDR_MATCH;
-+	JUMP .Lcplb_error;
++/* .... Debug interface ..................................................... */
 +
-+.Lnext_check2:
-+	CC = R0 == CPLB_PROT_VIOL;
-+	IF !CC JUMP .Lstrange_return_from_cplb_mgr;
-+	R0 = CPLB_PROT_VIOL;
-+	JUMP .Lcplb_error;
++#ifdef CONFIG_DEBUG_FS
 +
-+.Lstrange_return_from_cplb_mgr:
-+	IDLE;
-+	CSYNC;
-+	JUMP .Lstrange_return_from_cplb_mgr;
++static int ks8695_gpio_show(struct seq_file *s, void *unused)
++{
++	unsigned int enable[] = { IOPC_IOEINT0EN, IOPC_IOEINT1EN, IOPC_IOEINT2EN, IOPC_IOEINT3EN, IOPC_IOTIM0EN, IOPC_IOTIM1EN };
++	unsigned int intmask[] = { IOPC_IOEINT0TM, IOPC_IOEINT1TM, IOPC_IOEINT2TM, IOPC_IOEINT3TM };
++	unsigned long mode, ctrl, data;
++	int i;
 +
-+.Lcplb_error:
-+	R1 = sp;
-+	SP += -12;
-+	call _panic_cplb_error;
-+	SP += 12;
-+	JUMP _handle_bad_cplb;
++	mode = __raw_readl(KS8695_GPIO_VA + KS8695_IOPM);
++	ctrl = __raw_readl(KS8695_GPIO_VA + KS8695_IOPC);
++	data = __raw_readl(KS8695_GPIO_VA + KS8695_IOPD);
++
++	seq_printf(s, "Pin\tI/O\tFunction\tState\n\n");
++
++	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");
++
++		if (i <= KS8695_GPIO_3) {
++			if (ctrl & enable[i]) {
++				seq_printf(s, "EXT%i ", i);
++
++				switch ((ctrl & intmask[i]) >> (4 * i)) {
++					case IOPC_TM_LOW:
++						seq_printf(s, "(Low)");		break;
++					case IOPC_TM_HIGH:
++						seq_printf(s, "(High)");	break;
++					case IOPC_TM_RISING:
++						seq_printf(s, "(Rising)");	break;
++					case IOPC_TM_FALLING:
++						seq_printf(s, "(Falling)");	break;
++					case IOPC_TM_EDGE:
++						seq_printf(s, "(Edges)");	break;
++				}
++			}
++			else
++				seq_printf(s, "GPIO\t");
++		}
++		else if (i <= KS8695_GPIO_5) {
++			if (ctrl & enable[i])
++				seq_printf(s, "TOUT%i\t", i - KS8695_GPIO_4);
++			else
++				seq_printf(s, "GPIO\t");
++		}
++		else
++			seq_printf(s, "GPIO\t");
 +
-+ENDPROC(__cplb_hdr)
-diff --git a/arch/blackfin/kernel/cplb-nompu/cplbinfo.c b/arch/blackfin/kernel/cplb-nompu/cplbinfo.c
++		seq_printf(s, "\t");
++
++		seq_printf(s, "%i\n", (data & IOPD_(i)) ? 1 : 0);
++	}
++	return 0;
++}
++
++static int ks8695_gpio_open(struct inode *inode, struct file *file)
++{
++	return single_open(file, ks8695_gpio_show, NULL);
++}
++
++static const struct file_operations ks8695_gpio_operations = {
++	.open		= ks8695_gpio_open,
++	.read		= seq_read,
++	.llseek		= seq_lseek,
++	.release	= single_release,
++};
++
++static int __init ks8695_gpio_debugfs_init(void)
++{
++	/* /sys/kernel/debug/ks8695_gpio */
++	(void) debugfs_create_file("ks8695_gpio", S_IFREG | S_IRUGO, NULL, NULL, &ks8695_gpio_operations);
++	return 0;
++}
++postcore_initcall(ks8695_gpio_debugfs_init);
++
++#endif
+diff --git a/arch/arm/mach-ks8695/pci.c b/arch/arm/mach-ks8695/pci.c
 new file mode 100644
-index 0000000..a4f0b42
+index 0000000..3f4e033
 --- /dev/null
-+++ b/arch/blackfin/kernel/cplb-nompu/cplbinfo.c
-@@ -0,0 +1,208 @@
++++ b/arch/arm/mach-ks8695/pci.c
+@@ -0,0 +1,326 @@
 +/*
-+ * File:         arch/blackfin/mach-common/cplbinfo.c
-+ * Based on:
-+ * Author:       Sonic Zhang <sonic.zhang at analog.com>
-+ *
-+ * Created:      Jan. 2005
-+ * Description:  Display CPLB status
-+ *
-+ * Modified:
-+ *               Copyright 2004-2006 Analog Devices Inc.
++ * arch/arm/mach-ks8695/pci.c
 + *
-+ * Bugs:         Enter bugs at http://blackfin.uclinux.org/
++ *  Copyright (C) 2003, Micrel Semiconductors
++ *  Copyright (C) 2006, Greg Ungerer <gerg at snapgear.com>
++ *  Copyright (C) 2006, Ben Dooks
++ *  Copyright (C) 2007, Andrew Victor
 + *
 + * This program is free software; you can redistribute it and/or modify
 + * it under the terms of the GNU General Public License as published by
@@ -17711,9680 +24829,92435 @@
 + * GNU 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
++ * 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/kernel.h>
++#include <linux/pci.h>
++#include <linux/mm.h>
 +#include <linux/init.h>
-+#include <linux/proc_fs.h>
-+#include <linux/uaccess.h>
++#include <linux/irq.h>
++#include <linux/delay.h>
 +
-+#include <asm/current.h>
-+#include <asm/system.h>
-+#include <asm/cplb.h>
-+#include <asm/blackfin.h>
++#include <asm/io.h>
++#include <asm/signal.h>
++#include <asm/mach/pci.h>
++#include <asm/hardware.h>
 +
-+#define CPLB_I 1
-+#define CPLB_D 2
++#include <asm/arch/devices.h>
++#include <asm/arch/regs-pci.h>
 +
-+#define SYNC_SYS    SSYNC()
-+#define SYNC_CORE   CSYNC()
 +
-+#define CPLB_BIT_PAGESIZE 0x30000
++static int pci_dbg;
++static int pci_cfg_dbg;
 +
-+static int page_size_table[4] = {
-+	0x00000400,		/* 1K */
-+	0x00001000,		/* 4K */
-+	0x00100000,		/* 1M */
-+	0x00400000		/* 4M */
-+};
 +
-+static char page_size_string_table[][4] = { "1K", "4K", "1M", "4M" };
-+
-+static int cplb_find_entry(unsigned long *cplb_addr,
-+			   unsigned long *cplb_data, unsigned long addr,
-+			   unsigned long data)
++static void ks8695_pci_setupconfig(unsigned int bus_nr, unsigned int devfn, unsigned int where)
 +{
-+	int ii;
++	unsigned long pbca;
 +
-+	for (ii = 0; ii < 16; ii++)
-+		if (addr >= cplb_addr[ii] && addr < cplb_addr[ii] +
-+		    page_size_table[(cplb_data[ii] & CPLB_BIT_PAGESIZE) >> 16]
-+			&& (cplb_data[ii] == data))
-+			return ii;
++	pbca = PBCA_ENABLE | (where & ~3);
++	pbca |= PCI_SLOT(devfn) << 11 ;
++	pbca |= PCI_FUNC(devfn) << 8;
++	pbca |= bus_nr << 16;
 +
-+	return -1;
++	if (bus_nr == 0) {
++		/* use Type-0 transaction */
++		__raw_writel(pbca, KS8695_PCI_VA + KS8695_PBCA);
++	} else {
++		/* use Type-1 transaction */
++		__raw_writel(pbca | PBCA_TYPE1, KS8695_PCI_VA + KS8695_PBCA);
++	}
 +}
 +
-+static char *cplb_print_entry(char *buf, int type)
++
++/*
++ * The KS8695 datasheet prohibits anything other than 32bit accesses
++ * to the IO registers, so all our configuration must be done with
++ * 32bit operations, and the correct bit masking and shifting.
++ */
++
++static int ks8695_pci_readconfig(struct pci_bus *bus,
++			unsigned int devfn, int where, int size, u32 *value)
 +{
-+	unsigned long *p_addr = dpdt_table;
-+	unsigned long *p_data = dpdt_table + 1;
-+	unsigned long *p_icount = dpdt_swapcount_table;
-+	unsigned long *p_ocount = dpdt_swapcount_table + 1;
-+	unsigned long *cplb_addr = (unsigned long *)DCPLB_ADDR0;
-+	unsigned long *cplb_data = (unsigned long *)DCPLB_DATA0;
-+	int entry = 0, used_cplb = 0;
++	ks8695_pci_setupconfig(bus->number, devfn, where);
 +
-+	if (type == CPLB_I) {
-+		buf += sprintf(buf, "Instruction CPLB entry:\n");
-+		p_addr = ipdt_table;
-+		p_data = ipdt_table + 1;
-+		p_icount = ipdt_swapcount_table;
-+		p_ocount = ipdt_swapcount_table + 1;
-+		cplb_addr = (unsigned long *)ICPLB_ADDR0;
-+		cplb_data = (unsigned long *)ICPLB_DATA0;
-+	} else
-+		buf += sprintf(buf, "Data CPLB entry:\n");
++	*value = __raw_readl(KS8695_PCI_VA +  KS8695_PBCD);
 +
-+	buf += sprintf(buf, "Address\t\tData\tSize\tValid\tLocked\tSwapin\tiCount\toCount\n");
++	switch (size) {
++		case 4:
++			break;
++		case 2:
++			*value = *value >> ((where & 2) * 8);
++			*value &= 0xffff;
++			break;
++		case 1:
++			*value = *value >> ((where & 3) * 8);
++			*value &= 0xff;
++			break;
++	}
 +
-+	while (*p_addr != 0xffffffff) {
-+		entry = cplb_find_entry(cplb_addr, cplb_data, *p_addr, *p_data);
-+		if (entry >= 0)
-+			used_cplb |= 1 << entry;
++	if (pci_cfg_dbg) {
++		printk("read: %d,%08x,%02x,%d: %08x (%08x)\n",
++			bus->number, devfn, where, size, *value,
++			__raw_readl(KS8695_PCI_VA +  KS8695_PBCD));
++	}
 +
-+		buf +=
-+		    sprintf(buf,
-+			    "0x%08lx\t0x%05lx\t%s\t%c\t%c\t%2d\t%ld\t%ld\n",
-+			    *p_addr, *p_data,
-+			    page_size_string_table[(*p_data & 0x30000) >> 16],
-+			    (*p_data & CPLB_VALID) ? 'Y' : 'N',
-+			    (*p_data & CPLB_LOCK) ? 'Y' : 'N', entry, *p_icount,
-+			    *p_ocount);
++	return PCIBIOS_SUCCESSFUL;
++}
 +
-+		p_addr += 2;
-+		p_data += 2;
-+		p_icount += 2;
-+		p_ocount += 2;
++static int ks8695_pci_writeconfig(struct pci_bus *bus,
++			unsigned int devfn, int where, int size, u32 value)
++{
++	unsigned long tmp;
++
++	if (pci_cfg_dbg) {
++		printk("write: %d,%08x,%02x,%d: %08x\n",
++			bus->number, devfn, where, size, value);
 +	}
 +
-+	if (used_cplb != 0xffff) {
-+		buf += sprintf(buf, "Unused/mismatched CPLBs:\n");
++	ks8695_pci_setupconfig(bus->number, devfn, where);
 +
-+		for (entry = 0; entry < 16; entry++)
-+			if (0 == ((1 << entry) & used_cplb)) {
-+				int flags = cplb_data[entry];
-+				buf +=
-+				    sprintf(buf,
-+					    "%2d: 0x%08lx\t0x%05x\t%s\t%c\t%c\n",
-+					    entry, cplb_addr[entry], flags,
-+					    page_size_string_table[(flags &
-+								    0x30000) >>
-+								   16],
-+					    (flags & CPLB_VALID) ? 'Y' : 'N',
-+					    (flags & CPLB_LOCK) ? 'Y' : 'N');
-+			}
++	switch (size) {
++		case 4:
++			__raw_writel(value, KS8695_PCI_VA +  KS8695_PBCD);
++			break;
++		case 2:
++			tmp = __raw_readl(KS8695_PCI_VA +  KS8695_PBCD);
++			tmp &= ~(0xffff << ((where & 2) * 8));
++			tmp |= value << ((where & 2) * 8);
++
++			__raw_writel(tmp, KS8695_PCI_VA +  KS8695_PBCD);
++			break;
++		case 1:
++			tmp = __raw_readl(KS8695_PCI_VA +  KS8695_PBCD);
++			tmp &= ~(0xff << ((where & 3) * 8));
++			tmp |= value << ((where & 3) * 8);
++
++			__raw_writel(tmp, KS8695_PCI_VA +  KS8695_PBCD);
++			break;
 +	}
 +
-+	buf += sprintf(buf, "\n");
++	return PCIBIOS_SUCCESSFUL;
++}
 +
-+	return buf;
++static void ks8695_local_writeconfig(int where, u32 value)
++{
++	ks8695_pci_setupconfig(0, 0, where);
++	__raw_writel(value, KS8695_PCI_VA + KS8695_PBCD);
 +}
 +
-+static int cplbinfo_proc_output(char *buf)
++static struct pci_ops ks8695_pci_ops = {
++	.read	= ks8695_pci_readconfig,
++	.write	= ks8695_pci_writeconfig,
++};
++
++static struct pci_bus *ks8695_pci_scan_bus(int nr, struct pci_sys_data *sys)
 +{
-+	char *p;
++	return pci_scan_bus(sys->busnr, &ks8695_pci_ops, sys);
++}
 +
-+	p = buf;
++static struct resource pci_mem = {
++	.name	= "PCI Memory space",
++	.start	= KS8695_PCIMEM_PA,
++	.end	= KS8695_PCIMEM_PA + (KS8695_PCIMEM_SIZE - 1),
++	.flags	= IORESOURCE_MEM,
++};
 +
-+	p += sprintf(p, "------------------ CPLB Information ------------------\n\n");
++static struct resource pci_io = {
++	.name	= "PCI IO space",
++	.start	= KS8695_PCIIO_PA,
++	.end	= KS8695_PCIIO_PA + (KS8695_PCIIO_SIZE - 1),
++	.flags	= IORESOURCE_IO,
++};
 +
-+	if (bfin_read_IMEM_CONTROL() & ENICPLB)
-+		p = cplb_print_entry(p, CPLB_I);
-+	else
-+		p += sprintf(p, "Instruction CPLB is disabled.\n\n");
++static int __init ks8695_pci_setup(int nr, struct pci_sys_data *sys)
++{
++	if (nr > 0)
++		return 0;
 +
-+	if (bfin_read_DMEM_CONTROL() & ENDCPLB)
-+		p = cplb_print_entry(p, CPLB_D);
-+	else
-+		p += sprintf(p, "Data CPLB is disabled.\n");
++	request_resource(&iomem_resource, &pci_mem);
++	request_resource(&ioport_resource, &pci_io);
 +
-+	return p - buf;
++	sys->resource[0] = &pci_io;
++	sys->resource[1] = &pci_mem;
++	sys->resource[2] = NULL;
++
++	/* Assign and enable processor bridge */
++	ks8695_local_writeconfig(PCI_BASE_ADDRESS_0, KS8695_PCIMEM_PA);
++
++	/* Enable bus-master & Memory Space access */
++	ks8695_local_writeconfig(PCI_COMMAND, PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY);
++
++	/* Set cache-line size & latency. */
++	ks8695_local_writeconfig(PCI_CACHE_LINE_SIZE, (32 << 8) | (L1_CACHE_BYTES / sizeof(u32)));
++
++	/* Reserve PCI memory space for PCI-AHB resources */
++	if (!request_mem_region(KS8695_PCIMEM_PA, SZ_64M, "PCI-AHB Bridge")) {
++		printk(KERN_ERR "Cannot allocate PCI-AHB Bridge memory.\n");
++		return -EBUSY;
++	}
++
++	return 1;
 +}
 +
-+static int cplbinfo_read_proc(char *page, char **start, off_t off,
-+			      int count, int *eof, void *data)
++static inline unsigned int size_mask(unsigned long size)
 +{
-+	int len;
-+
-+	len = cplbinfo_proc_output(page);
-+	if (len <= off + count)
-+		*eof = 1;
-+	*start = page + off;
-+	len -= off;
-+	if (len > count)
-+		len = count;
-+	if (len < 0)
-+		len = 0;
-+	return len;
++	return (~size) + 1;
 +}
 +
-+static int cplbinfo_write_proc(struct file *file, const char __user *buffer,
-+			       unsigned long count, void *data)
++static int ks8695_pci_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
 +{
-+	printk(KERN_INFO "Reset the CPLB swap in/out counts.\n");
-+	memset(ipdt_swapcount_table, 0, MAX_SWITCH_I_CPLBS * sizeof(unsigned long));
-+	memset(dpdt_swapcount_table, 0, MAX_SWITCH_D_CPLBS * sizeof(unsigned long));
++	unsigned long pc = instruction_pointer(regs);
++	unsigned long instr = *(unsigned long *)pc;
++	unsigned long cmdstat;
 +
-+	return count;
++	cmdstat = __raw_readl(KS8695_PCI_VA + KS8695_CRCFCS);
++
++	printk(KERN_ERR "PCI abort: address = 0x%08lx fsr = 0x%03x PC = 0x%08lx LR = 0x%08lx [%s%s%s%s%s]\n",
++		addr, fsr, regs->ARM_pc, regs->ARM_lr,
++		cmdstat & (PCI_STATUS_SIG_TARGET_ABORT << 16) ? "GenTarget" : " ",
++		cmdstat & (PCI_STATUS_REC_TARGET_ABORT << 16) ? "RecvTarget" : " ",
++		cmdstat & (PCI_STATUS_REC_MASTER_ABORT << 16) ? "MasterAbort" : " ",
++		cmdstat & (PCI_STATUS_SIG_SYSTEM_ERROR << 16) ? "SysError" : " ",
++		cmdstat & (PCI_STATUS_DETECTED_PARITY << 16)  ? "Parity" : " "
++	);
++
++	__raw_writel(cmdstat, KS8695_PCI_VA + KS8695_CRCFCS);
++
++	/*
++	 * If the instruction being executed was a read,
++	 * make it look like it read all-ones.
++	 */
++	if ((instr & 0x0c100000) == 0x04100000) {
++		int reg = (instr >> 12) & 15;
++		unsigned long val;
++
++		if (instr & 0x00400000)
++			val = 255;
++		else
++			val = -1;
++
++		regs->uregs[reg] = val;
++		regs->ARM_pc += 4;
++		return 0;
++	}
++
++	if ((instr & 0x0e100090) == 0x00100090) {
++		int reg = (instr >> 12) & 15;
++
++		regs->uregs[reg] = -1;
++		regs->ARM_pc += 4;
++		return 0;
++	}
++
++	return 1;
 +}
 +
-+static int __init cplbinfo_init(void)
++static void __init ks8695_pci_preinit(void)
 +{
-+	struct proc_dir_entry *entry;
++	/* stage 1 initialization, subid, subdevice = 0x0001 */
++	__raw_writel(0x00010001, KS8695_PCI_VA + KS8695_CRCSID);
 +
-+	entry = create_proc_entry("cplbinfo", 0, NULL);
-+	if (!entry)
-+		return -ENOMEM;
++	/* stage 2 initialization */
++	/* prefetch limits with 16 words, retry enable */
++	__raw_writel(0x40000000, KS8695_PCI_VA + KS8695_PBCS);
 +
-+	entry->read_proc = cplbinfo_read_proc;
-+	entry->write_proc = cplbinfo_write_proc;
-+	entry->data = NULL;
++	/* configure memory mapping */
++	__raw_writel(KS8695_PCIMEM_PA, KS8695_PCI_VA + KS8695_PMBA);
++	__raw_writel(size_mask(KS8695_PCIMEM_SIZE), KS8695_PCI_VA + KS8695_PMBAM);
++	__raw_writel(KS8695_PCIMEM_PA, KS8695_PCI_VA + KS8695_PMBAT);
++	__raw_writel(0, KS8695_PCI_VA + KS8695_PMBAC);
 +
-+	return 0;
++	/* configure IO mapping */
++	__raw_writel(KS8695_PCIIO_PA, KS8695_PCI_VA + KS8695_PIOBA);
++	__raw_writel(size_mask(KS8695_PCIIO_SIZE), KS8695_PCI_VA + KS8695_PIOBAM);
++	__raw_writel(KS8695_PCIIO_PA, KS8695_PCI_VA + KS8695_PIOBAT);
++	__raw_writel(0, KS8695_PCI_VA + KS8695_PIOBAC);
++
++	/* hook in fault handlers */
++	hook_fault_code(8, ks8695_pci_fault, SIGBUS, "external abort on non-linefetch");
++	hook_fault_code(10, ks8695_pci_fault, SIGBUS, "external abort on non-linefetch");
 +}
 +
-+static void __exit cplbinfo_exit(void)
++static void ks8695_show_pciregs(void)
 +{
-+	remove_proc_entry("cplbinfo", NULL);
++	if (!pci_dbg)
++		return;
++
++	printk(KERN_INFO "PCI: CRCFID = %08x\n", __raw_readl(KS8695_PCI_VA + KS8695_CRCFID));
++	printk(KERN_INFO "PCI: CRCFCS = %08x\n", __raw_readl(KS8695_PCI_VA + KS8695_CRCFCS));
++	printk(KERN_INFO "PCI: CRCFRV = %08x\n", __raw_readl(KS8695_PCI_VA + KS8695_CRCFRV));
++	printk(KERN_INFO "PCI: CRCFLT = %08x\n", __raw_readl(KS8695_PCI_VA + KS8695_CRCFLT));
++	printk(KERN_INFO "PCI: CRCBMA = %08x\n", __raw_readl(KS8695_PCI_VA + KS8695_CRCBMA));
++	printk(KERN_INFO "PCI: CRCSID = %08x\n", __raw_readl(KS8695_PCI_VA + KS8695_CRCSID));
++	printk(KERN_INFO "PCI: CRCFIT = %08x\n", __raw_readl(KS8695_PCI_VA + KS8695_CRCFIT));
++
++	printk(KERN_INFO "PCI: PBM    = %08x\n", __raw_readl(KS8695_PCI_VA + KS8695_PBM));
++	printk(KERN_INFO "PCI: PBCS   = %08x\n", __raw_readl(KS8695_PCI_VA + KS8695_PBCS));
++
++	printk(KERN_INFO "PCI: PMBA   = %08x\n", __raw_readl(KS8695_PCI_VA + KS8695_PMBA));
++	printk(KERN_INFO "PCI: PMBAC  = %08x\n", __raw_readl(KS8695_PCI_VA + KS8695_PMBAC));
++	printk(KERN_INFO "PCI: PMBAM  = %08x\n", __raw_readl(KS8695_PCI_VA + KS8695_PMBAM));
++	printk(KERN_INFO "PCI: PMBAT  = %08x\n", __raw_readl(KS8695_PCI_VA + KS8695_PMBAT));
++
++	printk(KERN_INFO "PCI: PIOBA  = %08x\n", __raw_readl(KS8695_PCI_VA + KS8695_PIOBA));
++	printk(KERN_INFO "PCI: PIOBAC = %08x\n", __raw_readl(KS8695_PCI_VA + KS8695_PIOBAC));
++	printk(KERN_INFO "PCI: PIOBAM = %08x\n", __raw_readl(KS8695_PCI_VA + KS8695_PIOBAM));
++	printk(KERN_INFO "PCI: PIOBAT = %08x\n", __raw_readl(KS8695_PCI_VA + KS8695_PIOBAT));
 +}
 +
-+module_init(cplbinfo_init);
-+module_exit(cplbinfo_exit);
-diff --git a/arch/blackfin/kernel/cplb-nompu/cplbinit.c b/arch/blackfin/kernel/cplb-nompu/cplbinit.c
++
++static struct hw_pci ks8695_pci __initdata = {
++	.nr_controllers	= 1,
++	.preinit	= ks8695_pci_preinit,
++	.setup		= ks8695_pci_setup,
++	.scan		= ks8695_pci_scan_bus,
++	.postinit	= NULL,
++	.swizzle	= pci_std_swizzle,
++	.map_irq	= NULL,
++};
++
++void __init ks8695_init_pci(struct ks8695_pci_cfg *cfg)
++{
++	if (__raw_readl(KS8695_PCI_VA + KS8695_CRCFRV) & CFRV_GUEST) {
++		printk("PCI: KS8695 in guest mode, not initialising\n");
++		return;
++	}
++
++	printk(KERN_INFO "PCI: Initialising\n");
++	ks8695_show_pciregs();
++
++	/* set Mode */
++	__raw_writel(cfg->mode << 29, KS8695_PCI_VA + KS8695_PBM);
++
++	ks8695_pci.map_irq = cfg->map_irq;	/* board-specific map_irq method */
++
++	pci_common_init(&ks8695_pci);
++}
+diff --git a/arch/arm/mach-ks8695/time.c b/arch/arm/mach-ks8695/time.c
+index d2c86e4..02f766b 100644
+--- a/arch/arm/mach-ks8695/time.c
++++ b/arch/arm/mach-ks8695/time.c
+@@ -70,10 +70,7 @@ static unsigned long ks8695_gettimeoffset (void)
+  */
+ static irqreturn_t ks8695_timer_interrupt(int irq, void *dev_id)
+ {
+-	write_seqlock(&xtime_lock);
+ 	timer_tick();
+-	write_sequnlock(&xtime_lock);
+-
+ 	return IRQ_HANDLED;
+ }
+ 
+diff --git a/arch/arm/mach-lh7a40x/time.c b/arch/arm/mach-lh7a40x/time.c
+index c25316d..e50e60b 100644
+--- a/arch/arm/mach-lh7a40x/time.c
++++ b/arch/arm/mach-lh7a40x/time.c
+@@ -41,13 +41,9 @@
+ static irqreturn_t
+ lh7a40x_timer_interrupt(int irq, void *dev_id)
+ {
+-	write_seqlock(&xtime_lock);
+-
+ 	TIMER_EOI = 0;
+ 	timer_tick();
+ 
+-	write_sequnlock(&xtime_lock);
+-
+ 	return IRQ_HANDLED;
+ }
+ 
+diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
 new file mode 100644
-index 0000000..6320bc4
+index 0000000..3553bab
 --- /dev/null
-+++ b/arch/blackfin/kernel/cplb-nompu/cplbinit.c
-@@ -0,0 +1,437 @@
-+/*
-+ * Blackfin CPLB initialization
-+ *
-+ *               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.
++++ b/arch/arm/mach-msm/Kconfig
+@@ -0,0 +1,18 @@
++if ARCH_MSM7X00A
++
++comment "MSM7X00A Board Type"
++	depends on ARCH_MSM7X00A
++
++config MACH_HALIBUT
++	depends on ARCH_MSM7X00A
++	default y
++	bool "Halibut Board (QCT SURF7200A)"
++	help
++	  Support for the Qualcomm SURF7200A eval board.
++
++config MSM7X00A_IDLE
++	depends on ARCH_MSM7X00A
++	default y
++	bool "Idle Support for MSM7X00A"
++
++endif
+diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
+new file mode 100644
+index 0000000..d12f236
+--- /dev/null
++++ b/arch/arm/mach-msm/Makefile
+@@ -0,0 +1,7 @@
++obj-y += io.o idle.o irq.o timer.o dma.o
++
++# Common code for board init
++obj-y += common.o
++
++obj-$(CONFIG_MACH_HALIBUT) += board-halibut.o
++
+diff --git a/arch/arm/mach-msm/Makefile.boot b/arch/arm/mach-msm/Makefile.boot
+new file mode 100644
+index 0000000..24dfbf8
+--- /dev/null
++++ b/arch/arm/mach-msm/Makefile.boot
+@@ -0,0 +1,3 @@
++  zreladdr-y		:= 0x10008000
++params_phys-y		:= 0x10000100
++initrd_phys-y		:= 0x10800000
+diff --git a/arch/arm/mach-msm/board-halibut.c b/arch/arm/mach-msm/board-halibut.c
+new file mode 100644
+index 0000000..86dfb2b
+--- /dev/null
++++ b/arch/arm/mach-msm/board-halibut.c
+@@ -0,0 +1,114 @@
++/* linux/arch/arm/mach-msm/board-halibut.c
++ *
++ * Copyright (C) 2007 Google, Inc.
++ * Author: Brian Swetland <swetland at google.com>
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
 + *
 + * This program is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 + * GNU 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 <asm/blackfin.h>
-+#include <asm/cplb.h>
-+#include <asm/cplbinit.h>
 +
-+u_long icplb_table[MAX_CPLBS + 1];
-+u_long dcplb_table[MAX_CPLBS + 1];
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/platform_device.h>
++#include <linux/input.h>
 +
-+#ifdef CONFIG_CPLB_SWITCH_TAB_L1
-+# define PDT_ATTR __attribute__((l1_data))
-+#else
-+# define PDT_ATTR
-+#endif
++#include <asm/hardware.h>
++#include <asm/mach-types.h>
++#include <asm/mach/arch.h>
++#include <asm/mach/map.h>
++#include <asm/mach/flash.h>
 +
-+u_long ipdt_table[MAX_SWITCH_I_CPLBS + 1] PDT_ATTR;
-+u_long dpdt_table[MAX_SWITCH_D_CPLBS + 1] PDT_ATTR;
++#include <asm/arch/board.h>
++#include <asm/arch/msm_iomap.h>
 +
-+#ifdef CONFIG_CPLB_INFO
-+u_long ipdt_swapcount_table[MAX_SWITCH_I_CPLBS] PDT_ATTR;
-+u_long dpdt_swapcount_table[MAX_SWITCH_D_CPLBS] PDT_ATTR;
-+#endif
++#include <asm/io.h>
++#include <asm/delay.h>
 +
-+struct s_cplb {
-+	struct cplb_tab init_i;
-+	struct cplb_tab init_d;
-+	struct cplb_tab switch_i;
-+	struct cplb_tab switch_d;
-+};
++#include <linux/mtd/nand.h>
++#include <linux/mtd/partitions.h>
 +
-+#if defined(CONFIG_BFIN_DCACHE) || defined(CONFIG_BFIN_ICACHE)
-+static struct cplb_desc cplb_data[] = {
-+	{
-+		.start = 0,
-+		.end = SIZE_1K,
-+		.psize = SIZE_1K,
-+		.attr = INITIAL_T | SWITCH_T | I_CPLB | D_CPLB,
-+		.i_conf = SDRAM_OOPS,
-+		.d_conf = SDRAM_OOPS,
-+#if defined(CONFIG_DEBUG_HUNT_FOR_ZERO)
-+		.valid = 1,
-+#else
-+		.valid = 0,
-+#endif
-+		.name = "Zero Pointer Guard Page",
-+	},
-+	{
-+		.start = L1_CODE_START,
-+		.end = L1_CODE_START + L1_CODE_LENGTH,
-+		.psize = SIZE_4M,
-+		.attr = INITIAL_T | SWITCH_T | I_CPLB,
-+		.i_conf = L1_IMEMORY,
-+		.d_conf = 0,
-+		.valid = 1,
-+		.name = "L1 I-Memory",
-+	},
-+	{
-+		.start = L1_DATA_A_START,
-+		.end = L1_DATA_B_START + L1_DATA_B_LENGTH,
-+		.psize = SIZE_4M,
-+		.attr = INITIAL_T | SWITCH_T | D_CPLB,
-+		.i_conf = 0,
-+		.d_conf = L1_DMEMORY,
-+#if ((L1_DATA_A_LENGTH > 0) || (L1_DATA_B_LENGTH > 0))
-+		.valid = 1,
-+#else
-+		.valid = 0,
-+#endif
-+		.name = "L1 D-Memory",
-+	},
-+	{
-+		.start = 0,
-+		.end = 0,  /* dynamic */
-+		.psize = 0,
-+		.attr = INITIAL_T | SWITCH_T | I_CPLB | D_CPLB,
-+		.i_conf = SDRAM_IGENERIC,
-+		.d_conf = SDRAM_DGENERIC,
-+		.valid = 1,
-+		.name = "Kernel Memory",
-+	},
-+	{
-+		.start = 0, /* dynamic */
-+		.end = 0, /* dynamic */
-+		.psize = 0,
-+		.attr = INITIAL_T | SWITCH_T | D_CPLB,
-+		.i_conf = SDRAM_IGENERIC,
-+		.d_conf = SDRAM_DNON_CHBL,
-+		.valid = 1,
-+		.name = "uClinux MTD Memory",
-+	},
-+	{
-+		.start = 0, /* dynamic */
-+		.end = 0,   /* dynamic */
-+		.psize = SIZE_1M,
-+		.attr = INITIAL_T | SWITCH_T | D_CPLB,
-+		.d_conf = SDRAM_DNON_CHBL,
-+		.valid = 1,
-+		.name = "Uncached DMA Zone",
-+	},
-+	{
-+		.start = 0, /* dynamic */
-+		.end = 0, /* dynamic */
-+		.psize = 0,
-+		.attr = SWITCH_T | D_CPLB,
-+		.i_conf = 0, /* dynamic */
-+		.d_conf = 0, /* dynamic */
-+		.valid = 1,
-+		.name = "Reserved Memory",
-+	},
-+	{
-+		.start = ASYNC_BANK0_BASE,
-+		.end = ASYNC_BANK3_BASE + ASYNC_BANK3_SIZE,
-+		.psize = 0,
-+		.attr = SWITCH_T | D_CPLB,
-+		.d_conf = SDRAM_EBIU,
-+		.valid = 1,
-+		.name = "Asynchronous Memory Banks",
-+	},
-+	{
-+#ifdef L2_START
-+		.start = L2_START,
-+		.end = L2_START + L2_LENGTH,
-+		.psize = SIZE_1M,
-+		.attr = SWITCH_T | I_CPLB | D_CPLB,
-+		.i_conf = L2_MEMORY,
-+		.d_conf = L2_MEMORY,
-+		.valid = 1,
-+#else
-+		.valid = 0,
-+#endif
-+		.name = "L2 Memory",
++static struct resource smc91x_resources[] = {
++	[0] = {
++		.start	= 0x9C004300,
++		.end	= 0x9C004400,
++		.flags	= IORESOURCE_MEM,
 +	},
-+	{
-+		.start = BOOT_ROM_START,
-+		.end = BOOT_ROM_START + BOOT_ROM_LENGTH,
-+		.psize = SIZE_1M,
-+		.attr = SWITCH_T | I_CPLB | D_CPLB,
-+		.i_conf = SDRAM_IGENERIC,
-+		.d_conf = SDRAM_DGENERIC,
-+		.valid = 1,
-+		.name = "On-Chip BootROM",
++	[1] = {
++		.start	= MSM_GPIO_TO_INT(49),
++		.end	= MSM_GPIO_TO_INT(49),
++		.flags	= IORESOURCE_IRQ,
 +	},
 +};
 +
-+static u16 __init lock_kernel_check(u32 start, u32 end)
-+{
-+	if ((end   <= (u32) _end && end   >= (u32)_stext) ||
-+	    (start <= (u32) _end && start >= (u32)_stext))
-+		return IN_KERNEL;
-+	return 0;
-+}
++static struct platform_device smc91x_device = {
++	.name		= "smc91x",
++	.id		= 0,
++	.num_resources	= ARRAY_SIZE(smc91x_resources),
++	.resource	= smc91x_resources,
++};
 +
-+static unsigned short __init
-+fill_cplbtab(struct cplb_tab *table,
-+	     unsigned long start, unsigned long end,
-+	     unsigned long block_size, unsigned long cplb_data)
++static void mddi0_panel_power(int on)
 +{
-+	int i;
-+
-+	switch (block_size) {
-+	case SIZE_4M:
-+		i = 3;
-+		break;
-+	case SIZE_1M:
-+		i = 2;
-+		break;
-+	case SIZE_4K:
-+		i = 1;
-+		break;
-+	case SIZE_1K:
-+	default:
-+		i = 0;
-+		break;
-+	}
++}
 +
-+	cplb_data = (cplb_data & ~(3 << 16)) | (i << 16);
++static struct msm_mddi_platform_data msm_mddi0_pdata = {
++	.panel_power	= mddi0_panel_power,
++	.has_vsync_irq	= 0,
++};
 +
-+	while ((start < end) && (table->pos < table->size)) {
++static struct platform_device msm_mddi0_device = {
++	.name	= "msm_mddi",
++	.id	= 0,
++	.dev	= {
++		.platform_data = &msm_mddi0_pdata
++	},
++};
 +
-+		table->tab[table->pos++] = start;
++static struct platform_device msm_serial0_device = {
++	.name	= "msm_serial",
++	.id	= 0,
++};
 +
-+		if (lock_kernel_check(start, start + block_size) == IN_KERNEL)
-+			table->tab[table->pos++] =
-+			    cplb_data | CPLB_LOCK | CPLB_DIRTY;
-+		else
-+			table->tab[table->pos++] = cplb_data;
++static struct platform_device *devices[] __initdata = {
++	&msm_serial0_device,
++	&msm_mddi0_device,
++	&smc91x_device,
++};
 +
-+		start += block_size;
-+	}
-+	return 0;
-+}
++extern struct sys_timer msm_timer;
 +
-+static unsigned short __init
-+close_cplbtab(struct cplb_tab *table)
++static void __init halibut_init_irq(void)
 +{
-+
-+	while (table->pos < table->size) {
-+
-+		table->tab[table->pos++] = 0;
-+		table->tab[table->pos++] = 0; /* !CPLB_VALID */
-+	}
-+	return 0;
++	msm_init_irq();
 +}
 +
-+/* helper function */
-+static void __fill_code_cplbtab(struct cplb_tab *t, int i, u32 a_start, u32 a_end)
++static void __init halibut_init(void)
 +{
-+	if (cplb_data[i].psize) {
-+		fill_cplbtab(t,
-+				cplb_data[i].start,
-+				cplb_data[i].end,
-+				cplb_data[i].psize,
-+				cplb_data[i].i_conf);
-+	} else {
-+#if defined(CONFIG_BFIN_ICACHE)
-+		if (ANOMALY_05000263 && i == SDRAM_KERN) {
-+			fill_cplbtab(t,
-+					cplb_data[i].start,
-+					cplb_data[i].end,
-+					SIZE_4M,
-+					cplb_data[i].i_conf);
-+		} else
-+#endif
-+		{
-+			fill_cplbtab(t,
-+					cplb_data[i].start,
-+					a_start,
-+					SIZE_1M,
-+					cplb_data[i].i_conf);
-+			fill_cplbtab(t,
-+					a_start,
-+					a_end,
-+					SIZE_4M,
-+					cplb_data[i].i_conf);
-+			fill_cplbtab(t, a_end,
-+					cplb_data[i].end,
-+					SIZE_1M,
-+					cplb_data[i].i_conf);
-+		}
-+	}
++	platform_add_devices(devices, ARRAY_SIZE(devices));
++	msm_add_devices();
 +}
 +
-+static void __fill_data_cplbtab(struct cplb_tab *t, int i, u32 a_start, u32 a_end)
++static void __init halibut_map_io(void)
 +{
-+	if (cplb_data[i].psize) {
-+		fill_cplbtab(t,
-+				cplb_data[i].start,
-+				cplb_data[i].end,
-+				cplb_data[i].psize,
-+				cplb_data[i].d_conf);
-+	} else {
-+		fill_cplbtab(t,
-+				cplb_data[i].start,
-+				a_start, SIZE_1M,
-+				cplb_data[i].d_conf);
-+		fill_cplbtab(t, a_start,
-+				a_end, SIZE_4M,
-+				cplb_data[i].d_conf);
-+		fill_cplbtab(t, a_end,
-+				cplb_data[i].end,
-+				SIZE_1M,
-+				cplb_data[i].d_conf);
-+	}
++	msm_map_common_io();
 +}
 +
-+void __init generate_cpl_tables(void)
-+{
++MACHINE_START(HALIBUT, "Halibut Board (QCT SURF7200A)")
 +
-+	u16 i, j, process;
-+	u32 a_start, a_end, as, ae, as_1m;
++/* UART for LL DEBUG */
++	.phys_io	= MSM_UART1_PHYS,
++	.io_pg_offst	= ((MSM_UART1_BASE) >> 18) & 0xfffc,
 +
-+	struct cplb_tab *t_i = NULL;
-+	struct cplb_tab *t_d = NULL;
-+	struct s_cplb cplb;
++	.boot_params	= 0x10000100,
++	.map_io		= halibut_map_io,
++	.init_irq	= halibut_init_irq,
++	.init_machine	= halibut_init,
++	.timer		= &msm_timer,
++MACHINE_END
+diff --git a/arch/arm/mach-msm/common.c b/arch/arm/mach-msm/common.c
+new file mode 100644
+index 0000000..3f5d336
+--- /dev/null
++++ b/arch/arm/mach-msm/common.c
+@@ -0,0 +1,116 @@
++/* linux/arch/arm/mach-msm/common.c
++ *
++ * Common setup code for MSM7K Boards
++ *
++ * Copyright (C) 2007 Google, Inc.
++ * Author: Brian Swetland <swetland at google.com>
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ */
 +
-+	cplb.init_i.size = MAX_CPLBS;
-+	cplb.init_d.size = MAX_CPLBS;
-+	cplb.switch_i.size = MAX_SWITCH_I_CPLBS;
-+	cplb.switch_d.size = MAX_SWITCH_D_CPLBS;
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/platform_device.h>
 +
-+	cplb.init_i.pos = 0;
-+	cplb.init_d.pos = 0;
-+	cplb.switch_i.pos = 0;
-+	cplb.switch_d.pos = 0;
++#include <asm/mach/flash.h>
++#include <asm/io.h>
 +
-+	cplb.init_i.tab = icplb_table;
-+	cplb.init_d.tab = dcplb_table;
-+	cplb.switch_i.tab = ipdt_table;
-+	cplb.switch_d.tab = dpdt_table;
++#include <asm/setup.h>
 +
-+	cplb_data[SDRAM_KERN].end = memory_end;
++#include <linux/mtd/nand.h>
++#include <linux/mtd/partitions.h>
 +
-+#ifdef CONFIG_MTD_UCLINUX
-+	cplb_data[SDRAM_RAM_MTD].start = memory_mtd_start;
-+	cplb_data[SDRAM_RAM_MTD].end = memory_mtd_start + mtd_size;
-+	cplb_data[SDRAM_RAM_MTD].valid = mtd_size > 0;
-+# if defined(CONFIG_ROMFS_FS)
-+	cplb_data[SDRAM_RAM_MTD].attr |= I_CPLB;
++#include <asm/arch/msm_iomap.h>
 +
-+	/*
-+	 * The ROMFS_FS size is often not multiple of 1MB.
-+	 * This can cause multiple CPLB sets covering the same memory area.
-+	 * This will then cause multiple CPLB hit exceptions.
-+	 * Workaround: We ensure a contiguous memory area by extending the kernel
-+	 * memory section over the mtd section.
-+	 * For ROMFS_FS memory must be covered with ICPLBs anyways.
-+	 * So there is no difference between kernel and mtd memory setup.
-+	 */
++#include <asm/arch/board.h>
 +
-+	cplb_data[SDRAM_KERN].end = memory_mtd_start + mtd_size;;
-+	cplb_data[SDRAM_RAM_MTD].valid = 0;
++struct flash_platform_data msm_nand_data = {
++	.parts		= 0,
++	.nr_parts	= 0,
++};
 +
-+# endif
-+#else
-+	cplb_data[SDRAM_RAM_MTD].valid = 0;
-+#endif
++static struct resource msm_nand_resources[] = {
++	[0] = {
++		.start	= 7,
++		.end	= 7,
++		.flags	= IORESOURCE_DMA,
++	},
++};
 +
-+	cplb_data[SDRAM_DMAZ].start = _ramend - DMA_UNCACHED_REGION;
-+	cplb_data[SDRAM_DMAZ].end = _ramend;
++static struct platform_device msm_nand_device = {
++	.name		= "msm_nand",
++	.id		= -1,
++	.num_resources	= ARRAY_SIZE(msm_nand_resources),
++	.resource	= msm_nand_resources,
++	.dev		= {
++		.platform_data	= &msm_nand_data,
++	},
++};
 +
-+	cplb_data[RES_MEM].start = _ramend;
-+	cplb_data[RES_MEM].end = physical_mem_end;
++static struct platform_device msm_smd_device = {
++	.name	= "msm_smd",
++	.id	= -1,
++};
 +
-+	if (reserved_mem_dcache_on)
-+		cplb_data[RES_MEM].d_conf = SDRAM_DGENERIC;
-+	else
-+		cplb_data[RES_MEM].d_conf = SDRAM_DNON_CHBL;
++static struct resource msm_i2c_resources[] = {
++	{
++		.start	= MSM_I2C_BASE,
++		.end	= MSM_I2C_BASE + MSM_I2C_SIZE - 1,
++		.flags	= IORESOURCE_MEM,
++	},
++	{
++		.start	= INT_PWB_I2C,
++		.end	= INT_PWB_I2C,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
 +
-+	if (reserved_mem_icache_on)
-+		cplb_data[RES_MEM].i_conf = SDRAM_IGENERIC;
-+	else
-+		cplb_data[RES_MEM].i_conf = SDRAM_INON_CHBL;
++static struct platform_device msm_i2c_device = {
++	.name		= "msm_i2c",
++	.id		= 0,
++	.num_resources	= ARRAY_SIZE(msm_i2c_resources),
++	.resource	= msm_i2c_resources,
++};
 +
-+	for (i = ZERO_P; i < ARRAY_SIZE(cplb_data); ++i) {
-+		if (!cplb_data[i].valid)
-+			continue;
++static struct resource usb_resources[] = {
++	{
++		.start	= MSM_HSUSB_PHYS,
++		.end	= MSM_HSUSB_PHYS + MSM_HSUSB_SIZE,
++		.flags	= IORESOURCE_MEM,
++	},
++	{
++		.start	= INT_USB_HS,
++		.end	= INT_USB_HS,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
 +
-+		as_1m = cplb_data[i].start % SIZE_1M;
++static struct platform_device msm_hsusb_device = {
++	.name		= "msm_hsusb",
++	.id		= -1,
++	.num_resources	= ARRAY_SIZE(usb_resources),
++	.resource	= usb_resources,
++	.dev		= {
++		.coherent_dma_mask	= 0xffffffff,
++	},
++};
 +
-+		/* We need to make sure all sections are properly 1M aligned
-+		 * However between Kernel Memory and the Kernel mtd section, depending on the
-+		 * rootfs size, there can be overlapping memory areas.
-+		 */
++static struct platform_device *devices[] __initdata = {
++	&msm_nand_device,
++	&msm_smd_device,
++	&msm_i2c_device,
++	&msm_hsusb_device,
++};
 +
-+		if (as_1m && i != L1I_MEM && i != L1D_MEM) {
-+#ifdef CONFIG_MTD_UCLINUX
-+			if (i == SDRAM_RAM_MTD) {
-+				if ((cplb_data[SDRAM_KERN].end + 1) > cplb_data[SDRAM_RAM_MTD].start)
-+					cplb_data[SDRAM_RAM_MTD].start = (cplb_data[i].start & (-2*SIZE_1M)) + SIZE_1M;
-+				else
-+					cplb_data[SDRAM_RAM_MTD].start = (cplb_data[i].start & (-2*SIZE_1M));
-+			} else
-+#endif
-+				printk(KERN_WARNING "Unaligned Start of %s at 0x%X\n",
-+				       cplb_data[i].name, cplb_data[i].start);
++void __init msm_add_devices(void)
++{
++	platform_add_devices(devices, ARRAY_SIZE(devices));
++}
+diff --git a/arch/arm/mach-msm/dma.c b/arch/arm/mach-msm/dma.c
+new file mode 100644
+index 0000000..8b0f339
+--- /dev/null
++++ b/arch/arm/mach-msm/dma.c
+@@ -0,0 +1,214 @@
++/* linux/arch/arm/mach-msm/dma.c
++ *
++ * Copyright (C) 2007 Google, Inc.
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ */
++
++#include <asm/io.h>
++#include <linux/interrupt.h>
++#include <asm/arch/dma.h>
++
++#define MSM_DMOV_CHANNEL_COUNT 16
++
++enum {
++	MSM_DMOV_PRINT_ERRORS = 1,
++	MSM_DMOV_PRINT_IO = 2,
++	MSM_DMOV_PRINT_FLOW = 4
++};
++
++static DEFINE_SPINLOCK(msm_dmov_lock);
++static struct msm_dmov_cmd active_command;
++static struct list_head ready_commands[MSM_DMOV_CHANNEL_COUNT];
++static struct list_head active_commands[MSM_DMOV_CHANNEL_COUNT];
++unsigned int msm_dmov_print_mask = MSM_DMOV_PRINT_ERRORS;
++
++#define MSM_DMOV_DPRINTF(mask, format, args...) \
++	do { \
++		if ((mask) & msm_dmov_print_mask) \
++			printk(KERN_ERR format, args); \
++	} while (0)
++#define PRINT_ERROR(format, args...) \
++	MSM_DMOV_DPRINTF(MSM_DMOV_PRINT_ERRORS, format, args);
++#define PRINT_IO(format, args...) \
++	MSM_DMOV_DPRINTF(MSM_DMOV_PRINT_IO, format, args);
++#define PRINT_FLOW(format, args...) \
++	MSM_DMOV_DPRINTF(MSM_DMOV_PRINT_FLOW, format, args);
++
++void msm_dmov_enqueue_cmd(unsigned id, struct msm_dmov_cmd *cmd)
++{
++	unsigned long irq_flags;
++	unsigned int status;
++
++	spin_lock_irqsave(&msm_dmov_lock, irq_flags);
++	status = readl(DMOV_STATUS(id));
++	if (list_empty(&ready_commands[id]) &&
++		(status & DMOV_STATUS_CMD_PTR_RDY)) {
++#if 0
++		if (list_empty(&active_commands[id])) {
++			PRINT_FLOW("msm_dmov_enqueue_cmd(%d), enable interrupt\n", id);
++			writel(DMOV_CONFIG_IRQ_EN, DMOV_CONFIG(id));
 +		}
++#endif
++		PRINT_IO("msm_dmov_enqueue_cmd(%d), start command, status %x\n", id, status);
++		list_add_tail(&cmd->list, &active_commands[id]);
++		writel(cmd->cmdptr, DMOV_CMD_PTR(id));
++	} else {
++		if (list_empty(&active_commands[id]))
++			PRINT_ERROR("msm_dmov_enqueue_cmd(%d), error datamover stalled, status %x\n", id, status);
 +
-+		as = cplb_data[i].start % SIZE_4M;
-+		ae = cplb_data[i].end % SIZE_4M;
++		PRINT_IO("msm_dmov_enqueue_cmd(%d), enqueue command, status %x\n", id, status);
++		list_add_tail(&cmd->list, &ready_commands[id]);
++	}
++	spin_unlock_irqrestore(&msm_dmov_lock, irq_flags);
++}
 +
-+		if (as)
-+			a_start = cplb_data[i].start + (SIZE_4M - (as));
-+		else
-+			a_start = cplb_data[i].start;
++struct msm_dmov_exec_cmdptr_cmd {
++	struct msm_dmov_cmd dmov_cmd;
++	struct completion complete;
++	unsigned id;
++	unsigned int result;
++	unsigned int flush[6];
++};
 +
-+		a_end = cplb_data[i].end - ae;
++static void dmov_exec_cmdptr_complete_func(struct msm_dmov_cmd *_cmd, unsigned int result)
++{
++	struct msm_dmov_exec_cmdptr_cmd *cmd = container_of(_cmd, struct msm_dmov_exec_cmdptr_cmd, dmov_cmd);
++	cmd->result = result;
++	if (result != 0x80000002) {
++		cmd->flush[0] = readl(DMOV_FLUSH0(cmd->id));
++		cmd->flush[1] = readl(DMOV_FLUSH1(cmd->id));
++		cmd->flush[2] = readl(DMOV_FLUSH2(cmd->id));
++		cmd->flush[3] = readl(DMOV_FLUSH3(cmd->id));
++		cmd->flush[4] = readl(DMOV_FLUSH4(cmd->id));
++		cmd->flush[5] = readl(DMOV_FLUSH5(cmd->id));
++	}
++	complete(&cmd->complete);
++}
 +
-+		for (j = INITIAL_T; j <= SWITCH_T; j++) {
++int msm_dmov_exec_cmd(unsigned id, unsigned int cmdptr)
++{
++	struct msm_dmov_exec_cmdptr_cmd cmd;
 +
-+			switch (j) {
-+			case INITIAL_T:
-+				if (cplb_data[i].attr & INITIAL_T) {
-+					t_i = &cplb.init_i;
-+					t_d = &cplb.init_d;
-+					process = 1;
-+				} else
-+					process = 0;
-+				break;
-+			case SWITCH_T:
-+				if (cplb_data[i].attr & SWITCH_T) {
-+					t_i = &cplb.switch_i;
-+					t_d = &cplb.switch_d;
-+					process = 1;
-+				} else
-+					process = 0;
-+				break;
-+			default:
-+					process = 0;
-+				break;
-+			}
++	PRINT_FLOW("dmov_exec_cmdptr(%d, %x)\n", id, cmdptr);
 +
-+			if (!process)
-+				continue;
-+			if (cplb_data[i].attr & I_CPLB)
-+				__fill_code_cplbtab(t_i, i, a_start, a_end);
++	cmd.dmov_cmd.cmdptr = cmdptr;
++	cmd.dmov_cmd.complete_func = dmov_exec_cmdptr_complete_func;
++	cmd.id = id;
++	init_completion(&cmd.complete);
 +
-+			if (cplb_data[i].attr & D_CPLB)
-+				__fill_data_cplbtab(t_d, i, a_start, a_end);
-+		}
++	msm_dmov_enqueue_cmd(id, &cmd.dmov_cmd);
++	wait_for_completion(&cmd.complete);
++
++	if (cmd.result != 0x80000002) {
++		PRINT_ERROR("dmov_exec_cmdptr(%d): ERROR, result: %x\n", id, cmd.result);
++		PRINT_ERROR("dmov_exec_cmdptr(%d):  flush: %x %x %x %x\n",
++			id, cmd.flush[0], cmd.flush[1], cmd.flush[2], cmd.flush[3]);
++		return -EIO;
 +	}
++	PRINT_FLOW("dmov_exec_cmdptr(%d, %x) done\n", id, cmdptr);
++	return 0;
++}
 +
-+/* close tables */
 +
-+	close_cplbtab(&cplb.init_i);
-+	close_cplbtab(&cplb.init_d);
++static irqreturn_t msm_datamover_irq_handler(int irq, void *dev_id)
++{
++	unsigned int int_status, mask, id;
++	unsigned long irq_flags;
++	unsigned int ch_status;
++	unsigned int ch_result;
++	struct msm_dmov_cmd *cmd;
 +
-+	cplb.init_i.tab[cplb.init_i.pos] = -1;
-+	cplb.init_d.tab[cplb.init_d.pos] = -1;
-+	cplb.switch_i.tab[cplb.switch_i.pos] = -1;
-+	cplb.switch_d.tab[cplb.switch_d.pos] = -1;
++	spin_lock_irqsave(&msm_dmov_lock, irq_flags);
 +
++	int_status = readl(DMOV_ISR); /* read and clear interrupt */
++	PRINT_FLOW("msm_datamover_irq_handler: DMOV_ISR %x\n", int_status);
++
++	while (int_status) {
++		mask = int_status & -int_status;
++		id = fls(mask) - 1;
++		PRINT_FLOW("msm_datamover_irq_handler %08x %08x id %d\n", int_status, mask, id);
++		int_status &= ~mask;
++		ch_status = readl(DMOV_STATUS(id));
++		if (!(ch_status & DMOV_STATUS_RSLT_VALID)) {
++			PRINT_FLOW("msm_datamover_irq_handler id %d, result not valid %x\n", id, ch_status);
++			continue;
++		}
++		do {
++			ch_result = readl(DMOV_RSLT(id));
++			if (list_empty(&active_commands[id])) {
++				PRINT_ERROR("msm_datamover_irq_handler id %d, got result "
++					"with no active command, status %x, result %x\n",
++					id, ch_status, ch_result);
++				cmd = NULL;
++			} else
++				cmd = list_entry(active_commands[id].next, typeof(*cmd), list);
++			PRINT_FLOW("msm_datamover_irq_handler id %d, status %x, result %x\n", id, ch_status, ch_result);
++			if (ch_result & DMOV_RSLT_DONE) {
++				PRINT_FLOW("msm_datamover_irq_handler id %d, status %x\n",
++					id, ch_status);
++				PRINT_IO("msm_datamover_irq_handler id %d, got result "
++					"for %p, result %x\n", id, cmd, ch_result);
++				if (cmd) {
++					list_del(&cmd->list);
++					cmd->complete_func(cmd, ch_result);
++				}
++			}
++			if (ch_result & DMOV_RSLT_FLUSH) {
++				unsigned int flush0 = readl(DMOV_FLUSH0(id));
++				PRINT_FLOW("msm_datamover_irq_handler id %d, status %x\n", id, ch_status);
++				PRINT_FLOW("msm_datamover_irq_handler id %d, flush, result %x, flush0 %x\n", id, ch_result, flush0);
++				if (cmd) {
++					list_del(&cmd->list);
++					cmd->complete_func(cmd, ch_result);
++				}
++			}
++			if (ch_result & DMOV_RSLT_ERROR) {
++				unsigned int flush0 = readl(DMOV_FLUSH0(id));
++				PRINT_ERROR("msm_datamover_irq_handler id %d, status %x\n", id, ch_status);
++				PRINT_ERROR("msm_datamover_irq_handler id %d, error, result %x, flush0 %x\n", id, ch_result, flush0);
++				if (cmd) {
++					list_del(&cmd->list);
++					cmd->complete_func(cmd, ch_result);
++				}
++				/* this does not seem to work, once we get an error */
++				/* the datamover will no longer accept commands */
++				writel(0, DMOV_FLUSH0(id));
++			}
++			ch_status = readl(DMOV_STATUS(id));
++			PRINT_FLOW("msm_datamover_irq_handler id %d, status %x\n", id, ch_status);
++			if ((ch_status & DMOV_STATUS_CMD_PTR_RDY) && !list_empty(&ready_commands[id])) {
++				cmd = list_entry(ready_commands[id].next, typeof(*cmd), list);
++				list_del(&cmd->list);
++				list_add_tail(&cmd->list, &active_commands[id]);
++				PRINT_FLOW("msm_datamover_irq_handler id %d, start command\n", id);
++				writel(cmd->cmdptr, DMOV_CMD_PTR(id));
++			}
++		} while (ch_status & DMOV_STATUS_RSLT_VALID);
++		PRINT_FLOW("msm_datamover_irq_handler id %d, status %x\n", id, ch_status);
++	}
++	spin_unlock_irqrestore(&msm_dmov_lock, irq_flags);
++	return IRQ_HANDLED;
 +}
 +
-+#endif
++static int __init msm_init_datamover(void)
++{
++	int i;
++	for (i = 0; i < MSM_DMOV_CHANNEL_COUNT; i++) {
++		INIT_LIST_HEAD(&ready_commands[i]);
++		INIT_LIST_HEAD(&active_commands[i]);
++		writel(DMOV_CONFIG_IRQ_EN | DMOV_CONFIG_FORCE_TOP_PTR_RSLT | DMOV_CONFIG_FORCE_FLUSH_RSLT, DMOV_CONFIG(i));
++	}
++	return request_irq(INT_ADM_AARM, msm_datamover_irq_handler, 0, "msmdatamover", NULL);
++}
 +
-diff --git a/arch/blackfin/kernel/cplb-nompu/cplbmgr.S b/arch/blackfin/kernel/cplb-nompu/cplbmgr.S
++arch_initcall(msm_init_datamover);
++
+diff --git a/arch/arm/mach-msm/idle.S b/arch/arm/mach-msm/idle.S
 new file mode 100644
-index 0000000..f5cf3ac
+index 0000000..2b1cb7f
 --- /dev/null
-+++ b/arch/blackfin/kernel/cplb-nompu/cplbmgr.S
-@@ -0,0 +1,646 @@
-+/*
-+ * File:         arch/blackfin/mach-common/cplbmgtr.S
-+ * Based on:
-+ * Author:       LG Soft India
-+ *
-+ * Created:      ?
-+ * Description:  CPLB replacement routine for CPLB mismatch
++++ b/arch/arm/mach-msm/idle.S
+@@ -0,0 +1,36 @@
++/* linux/include/asm-arm/arch-msm/idle.S
 + *
-+ * Modified:
-+ *               Copyright 2004-2006 Analog Devices Inc.
++ * Idle processing for MSM7K - work around bugs with SWFI.
 + *
-+ * Bugs:         Enter bugs at http://blackfin.uclinux.org/
++ * Copyright (c) 2007 QUALCOMM Incorporated.
++ * Copyright (C) 2007 Google, 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 licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
 + *
 + * This program is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 + * GNU 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
-+ */
-+
-+/* Usage: int _cplb_mgr(is_data_miss,int enable_cache)
-+ * is_data_miss==2 => Mark as Dirty, write to the clean data page
-+ * is_data_miss==1 => Replace a data CPLB.
-+ * is_data_miss==0 => Replace an instruction CPLB.
-+ *
-+ * Returns:
-+ * CPLB_RELOADED	=> Successfully updated CPLB table.
-+ * CPLB_NO_UNLOCKED	=> All CPLBs are locked, so cannot be evicted.
-+ *			   This indicates that the CPLBs in the configuration
-+ *			   tablei are badly configured, as this should never
-+ *			   occur.
-+ * CPLB_NO_ADDR_MATCH	=> The address being accessed, that triggered the
-+ *			   exception, is not covered by any of the CPLBs in
-+ *			   the configuration table. The application is
-+ *			   presumably misbehaving.
-+ * CPLB_PROT_VIOL	=> The address being accessed, that triggered the
-+ *			   exception, was not a first-write to a clean Write
-+ *			   Back Data page, and so presumably is a genuine
-+ *			   violation of the page's protection attributes.
-+ *			   The application is misbehaving.
-+ */
-+
++ */ 
++		
 +#include <linux/linkage.h>
-+#include <asm/blackfin.h>
-+#include <asm/cplb.h>
++#include <asm/assembler.h>
 +
-+#ifdef CONFIG_EXCPT_IRQ_SYSC_L1
-+.section .l1.text
-+#else
-+.text
++ENTRY(arch_idle)
++#ifdef CONFIG_MSM7X00A_IDLE
++	mrc     p15, 0, r1, c1, c0, 0    /* read current CR    */
++	bic     r0, r1, #(1 << 2)        /* clear dcache bit   */
++	bic     r0, r0, #(1 << 12)       /* clear icache bit   */
++	mcr     p15, 0, r0, c1, c0, 0    /* disable d/i cache  */
++
++	mov     r0, #0                   /* prepare wfi value  */
++	mcr     p15, 0, r0, c7, c10, 0   /* flush the cache    */
++	mcr     p15, 0, r0, c7, c10, 4   /* memory barrier     */
++	mcr     p15, 0, r0, c7, c0, 4    /* wait for interrupt */
++
++	mcr     p15, 0, r1, c1, c0, 0    /* restore d/i cache  */
 +#endif
++	mov     pc, lr
+diff --git a/arch/arm/mach-msm/io.c b/arch/arm/mach-msm/io.c
+new file mode 100644
+index 0000000..c39edb9
+--- /dev/null
++++ b/arch/arm/mach-msm/io.c
+@@ -0,0 +1,85 @@
++/* arch/arm/mach-msm/io.c
++ *
++ * MSM7K io support
++ *
++ * Copyright (C) 2007 Google, Inc.
++ * Author: Brian Swetland <swetland at google.com>
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ */
 +
-+.align 2;
-+ENTRY(_cplb_mgr)
++#include <linux/kernel.h>
++#include <linux/init.h>
 +
-+	[--SP]=( R7:4,P5:3 );
++#include <asm/hardware.h>
++#include <asm/io.h>
++#include <asm/page.h>
++#include <asm/arch/msm_iomap.h>
++#include <asm/mach/map.h>
 +
-+	CC = R0 == 2;
-+	IF CC JUMP .Ldcplb_write;
++#include <asm/arch/board.h>
 +
-+	CC = R0 == 0;
-+	IF !CC JUMP .Ldcplb_miss_compare;
++#define MSM_DEVICE(name) { \
++		.virtual = MSM_##name##_BASE, \
++		.pfn = __phys_to_pfn(MSM_##name##_PHYS), \
++		.length = MSM_##name##_SIZE, \
++		.type = MT_DEVICE_NONSHARED, \
++	 }
 +
-+	/* ICPLB Miss Exception. We need to choose one of the
-+	* currently-installed CPLBs, and replace it with one
-+	* from the configuration table.
-+	*/
++static struct map_desc msm_io_desc[] __initdata = {
++	MSM_DEVICE(VIC),
++	MSM_DEVICE(CSR),
++	MSM_DEVICE(GPT),
++	MSM_DEVICE(DMOV),
++	MSM_DEVICE(UART1),
++	MSM_DEVICE(UART2),
++	MSM_DEVICE(UART3),
++	MSM_DEVICE(I2C),
++	MSM_DEVICE(GPIO1),
++	MSM_DEVICE(GPIO2),
++	MSM_DEVICE(HSUSB),
++	MSM_DEVICE(CLK_CTL),
++	MSM_DEVICE(PMDH),
++	MSM_DEVICE(EMDH),
++	MSM_DEVICE(MDP),
++	{
++		.virtual =  MSM_SHARED_RAM_BASE,
++		.pfn =      __phys_to_pfn(MSM_SHARED_RAM_PHYS),
++		.length =   MSM_SHARED_RAM_SIZE,
++		.type =     MT_DEVICE,
++	},
++};
 +
-+	/* A multi-word instruction can cross a page boundary. This means the
-+	 * first part of the instruction can be in a valid page, but the
-+	 * second part is not, and hence generates the instruction miss.
-+	 * However, the fault address is for the start of the instruction,
-+	 * not the part that's in the bad page. Therefore, we have to check
-+	 * whether the fault address applies to a page that is already present
-+	 * in the table.
++void __init msm_map_common_io(void)
++{
++	/* Make sure the peripheral register window is closed, since
++	 * we will use PTE flags (TEX[1]=1,B=0,C=1) to determine which
++	 * pages are peripheral interface or not.
 +	 */
++	asm("mcr p15, 0, %0, c15, c2, 4" : : "r" (0));
 +
-+	P4.L = LO(ICPLB_FAULT_ADDR);
-+	P4.H = HI(ICPLB_FAULT_ADDR);
++	iotable_init(msm_io_desc, ARRAY_SIZE(msm_io_desc));
++}
 +
-+	P1 = 16;
-+	P5.L = _page_size_table;
-+	P5.H = _page_size_table;
++void __iomem *
++__msm_ioremap(unsigned long phys_addr, size_t size, unsigned int mtype)
++{
++	if (mtype == MT_DEVICE) {
++		/* The peripherals in the 88000000 - D0000000 range
++		 * are only accessable by type MT_DEVICE_NONSHARED.
++		 * Adjust mtype as necessary to make this "just work."
++		 */
++		if ((phys_addr >= 0x88000000) && (phys_addr < 0xD0000000))
++			mtype = MT_DEVICE_NONSHARED;
++	}
 +
-+	P0.L = LO(ICPLB_DATA0);
-+	P0.H = HI(ICPLB_DATA0);
-+	R4 = [P4];		/* Get faulting address*/
-+	R6 = 64;		/* Advance past the fault address, which*/
-+	R6 = R6 + R4;		/* we'll use if we find a match*/
-+	R3 = ((16 << 8) | 2);	/* Extract mask, two bits at posn 16 */
++	return __arm_ioremap(phys_addr, size, mtype);
++}
+diff --git a/arch/arm/mach-msm/irq.c b/arch/arm/mach-msm/irq.c
+new file mode 100644
+index 0000000..2415804
+--- /dev/null
++++ b/arch/arm/mach-msm/irq.c
+@@ -0,0 +1,154 @@
++/* linux/arch/arm/mach-msm/irq.c
++ *
++ * Copyright (C) 2007 Google, Inc.
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ */
 +
-+	R5 = 0;
-+.Lisearch:
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/sched.h>
++#include <linux/interrupt.h>
++#include <linux/ptrace.h>
++#include <linux/timer.h>
 +
-+	R1 = [P0-0x100];	/* Address for this CPLB */
++#include <linux/irq.h>
++#include <asm/hardware.h>
 +
-+	R0 = [P0++];		/* Info for this CPLB*/
-+	CC = BITTST(R0,0);	/* Is the CPLB valid?*/
-+	IF !CC JUMP .Lnomatch;	/* Skip it, if not.*/
-+	CC = R4 < R1(IU);	/* If fault address less than page start*/
-+	IF CC JUMP .Lnomatch;	/* then skip this one.*/
-+	R2 = EXTRACT(R0,R3.L) (Z);	/* Get page size*/
-+	P1 = R2;
-+	P1 = P5 + (P1<<2);	/* index into page-size table*/
-+	R2 = [P1];		/* Get the page size*/
-+	R1 = R1 + R2;		/* and add to page start, to get page end*/
-+	CC = R4 < R1(IU);	/* and see whether fault addr is in page.*/
-+	IF !CC R4 = R6;		/* If so, advance the address and finish loop.*/
-+	IF !CC JUMP .Lisearch_done;
-+.Lnomatch:
-+	/* Go around again*/
-+	R5 += 1;
-+	CC = BITTST(R5, 4);	/* i.e CC = R5 >= 16*/
-+	IF !CC JUMP .Lisearch;
++#include <asm/io.h>
 +
-+.Lisearch_done:
-+	I0 = R4;		/* Fault address we'll search for*/
++#include <asm/arch/msm_iomap.h>
 +
-+	/* set up pointers */
-+	P0.L = LO(ICPLB_DATA0);
-+	P0.H = HI(ICPLB_DATA0);
++#define VIC_REG(off) (MSM_VIC_BASE + (off))
 +
-+	/* The replacement procedure for ICPLBs */
++#define VIC_INT_SELECT0     VIC_REG(0x0000)  /* 1: FIQ, 0: IRQ */
++#define VIC_INT_SELECT1     VIC_REG(0x0004)  /* 1: FIQ, 0: IRQ */
++#define VIC_INT_EN0         VIC_REG(0x0010)
++#define VIC_INT_EN1         VIC_REG(0x0014)
++#define VIC_INT_ENCLEAR0    VIC_REG(0x0020)
++#define VIC_INT_ENCLEAR1    VIC_REG(0x0024)
++#define VIC_INT_ENSET0      VIC_REG(0x0030)
++#define VIC_INT_ENSET1      VIC_REG(0x0034)
++#define VIC_INT_TYPE0       VIC_REG(0x0040)  /* 1: EDGE, 0: LEVEL  */
++#define VIC_INT_TYPE1       VIC_REG(0x0044)  /* 1: EDGE, 0: LEVEL  */
++#define VIC_INT_POLARITY0   VIC_REG(0x0050)  /* 1: NEG, 0: POS */
++#define VIC_INT_POLARITY1   VIC_REG(0x0054)  /* 1: NEG, 0: POS */
++#define VIC_NO_PEND_VAL     VIC_REG(0x0060)
++#define VIC_INT_MASTEREN    VIC_REG(0x0064)  /* 1: IRQ, 2: FIQ     */
++#define VIC_PROTECTION      VIC_REG(0x006C)  /* 1: ENABLE          */
++#define VIC_CONFIG          VIC_REG(0x0068)  /* 1: USE ARM1136 VIC */
++#define VIC_IRQ_STATUS0     VIC_REG(0x0080)
++#define VIC_IRQ_STATUS1     VIC_REG(0x0084)
++#define VIC_FIQ_STATUS0     VIC_REG(0x0090)
++#define VIC_FIQ_STATUS1     VIC_REG(0x0094)
++#define VIC_RAW_STATUS0     VIC_REG(0x00A0)
++#define VIC_RAW_STATUS1     VIC_REG(0x00A4)
++#define VIC_INT_CLEAR0      VIC_REG(0x00B0)
++#define VIC_INT_CLEAR1      VIC_REG(0x00B4)
++#define VIC_SOFTINT0        VIC_REG(0x00C0)
++#define VIC_SOFTINT1        VIC_REG(0x00C4)
++#define VIC_IRQ_VEC_RD      VIC_REG(0x00D0)  /* pending int # */
++#define VIC_IRQ_VEC_PEND_RD VIC_REG(0x00D4)  /* pending vector addr */
++#define VIC_IRQ_VEC_WR      VIC_REG(0x00D8)
++#define VIC_IRQ_IN_SERVICE  VIC_REG(0x00E0)
++#define VIC_IRQ_IN_STACK    VIC_REG(0x00E4)
++#define VIC_TEST_BUS_SEL    VIC_REG(0x00E8)
++
++#define VIC_VECTPRIORITY(n) VIC_REG(0x0200+((n) * 4))
++#define VIC_VECTADDR(n)     VIC_REG(0x0400+((n) * 4))
++
++static void msm_irq_ack(unsigned int irq)
++{
++	unsigned reg = VIC_INT_CLEAR0 + ((irq & 32) ? 4 : 0);
++	irq = 1 << (irq & 31);
++	writel(irq, reg);
++}
++
++static void msm_irq_mask(unsigned int irq)
++{
++	unsigned reg = VIC_INT_ENCLEAR0 + ((irq & 32) ? 4 : 0);
++	writel(1 << (irq & 31), reg);
++}
 +
-+	P4.L = LO(IMEM_CONTROL);
-+	P4.H = HI(IMEM_CONTROL);
++static void msm_irq_unmask(unsigned int irq)
++{
++	unsigned reg = VIC_INT_ENSET0 + ((irq & 32) ? 4 : 0);
++	writel(1 << (irq & 31), reg);
++}
 +
-+	/* Turn off CPLBs while we work, necessary according to HRM before
-+	 * modifying CPLB descriptors
-+	 */
-+	R5 = [P4];		/* Control Register*/
-+	BITCLR(R5,ENICPLB_P);
-+	CLI R1;
-+	SSYNC;		/* SSYNC required before writing to IMEM_CONTROL. */
-+	.align 8;
-+	[P4] = R5;
-+	SSYNC;
-+	STI R1;
++static int msm_irq_set_wake(unsigned int irq, unsigned int on)
++{
++	return -EINVAL;
++}
 +
-+	R1 = -1;		/* end point comparison */
-+	R3 = 16;		/* counter */
++static int msm_irq_set_type(unsigned int irq, unsigned int flow_type)
++{
++	unsigned treg = VIC_INT_TYPE0 + ((irq & 32) ? 4 : 0);
++	unsigned preg = VIC_INT_POLARITY0 + ((irq & 32) ? 4 : 0);
++	int b = 1 << (irq & 31);
 +
-+	/* Search through CPLBs for first non-locked entry */
-+	/* Overwrite it by moving everyone else up by 1 */
-+.Licheck_lock:
-+	R0 = [P0++];
-+	R3 = R3 + R1;
-+	CC = R3 == R1;
-+	IF CC JUMP .Lall_locked;
-+	CC = BITTST(R0, 0);		/* an invalid entry is good */
-+	IF !CC JUMP .Lifound_victim;
-+	CC = BITTST(R0,1);		/* but a locked entry isn't */
-+	IF CC JUMP .Licheck_lock;
++	if (flow_type & (IRQF_TRIGGER_FALLING | IRQF_TRIGGER_LOW))
++		writel(readl(preg) | b, preg);
++	if (flow_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_HIGH))
++		writel(readl(preg) & (~b), preg);
 +
-+.Lifound_victim:
-+#ifdef CONFIG_CPLB_INFO
-+	R7 = [P0 - 0x104];
-+	P2.L = _ipdt_table;
-+	P2.H = _ipdt_table;
-+	P3.L = _ipdt_swapcount_table;
-+	P3.H = _ipdt_swapcount_table;
-+	P3 += -4;
-+.Licount:
-+	R2 = [P2];	/* address from config table */
-+	P2 += 8;
-+	P3 += 8;
-+	CC = R2==-1;
-+	IF CC JUMP .Licount_done;
-+	CC = R7==R2;
-+	IF !CC JUMP .Licount;
-+	R7 = [P3];
-+	R7 += 1;
-+	[P3] = R7;
-+	CSYNC;
-+.Licount_done:
-+#endif
-+	LC0=R3;
-+	LSETUP(.Lis_move,.Lie_move) LC0;
-+.Lis_move:
-+	R0 = [P0];
-+	[P0 - 4] = R0;
-+	R0 = [P0 - 0x100];
-+	[P0-0x104] = R0;
-+.Lie_move:
-+	P0+=4;
++	if (flow_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) {
++		writel(readl(treg) | b, treg);
++		set_irq_handler(irq, handle_edge_irq);
++	}
++	if (flow_type & (IRQF_TRIGGER_HIGH | IRQF_TRIGGER_LOW)) {
++		writel(readl(treg) & (~b), treg);
++		set_irq_handler(irq, handle_level_irq);
++	}
++	return 0;
++}
 +
-+	/* Clear ICPLB_DATA15, in case we don't find a replacement
-+	 * otherwise, we would have a duplicate entry, and will crash
-+	 */
-+	R0 = 0;
-+	[P0 - 4] = R0;
++static struct irq_chip msm_irq_chip = {
++	.name      = "msm",
++	.ack       = msm_irq_ack,
++	.mask      = msm_irq_mask,
++	.unmask    = msm_irq_unmask,
++	.set_wake  = msm_irq_set_wake,
++	.set_type  = msm_irq_set_type,
++};
 +
-+	/* We've made space in the ICPLB table, so that ICPLB15
-+	 * is now free to be overwritten. Next, we have to determine
-+	 * which CPLB we need to install, from the configuration
-+	 * table. This is a matter of getting the start-of-page
-+	 * addresses and page-lengths from the config table, and
-+	 * determining whether the fault address falls within that
-+	 * range.
-+ 	 */
++void __init msm_init_irq(void)
++{
++	unsigned n;
 +
-+	P2.L = _ipdt_table;
-+	P2.H = _ipdt_table;
-+#ifdef	CONFIG_CPLB_INFO
-+	P3.L = _ipdt_swapcount_table;
-+	P3.H = _ipdt_swapcount_table;
-+	P3 += -8;
-+#endif
-+	P0.L = _page_size_table;
-+	P0.H = _page_size_table;
++	/* select level interrupts */
++	writel(0, VIC_INT_TYPE0);
++	writel(0, VIC_INT_TYPE1);
 +
-+	/* Retrieve our fault address (which may have been advanced
-+	 * because the faulting instruction crossed a page boundary).
-+	 */
++	/* select highlevel interrupts */
++	writel(0, VIC_INT_POLARITY0);
++	writel(0, VIC_INT_POLARITY1);
 +
-+	R0 = I0;
++	/* select IRQ for all INTs */
++	writel(0, VIC_INT_SELECT0);
++	writel(0, VIC_INT_SELECT1);
 +
-+	/* An extraction pattern, to get the page-size bits from
-+	 * the CPLB data entry. Bits 16-17, so two bits at posn 16.
-+	 */
++	/* disable all INTs */
++	writel(0, VIC_INT_EN0);
++	writel(0, VIC_INT_EN1);
 +
-+	R1 = ((16<<8)|2);
-+.Linext:	R4 = [P2++];	/* address from config table */
-+	R2 = [P2++];	/* data from config table */
-+#ifdef	CONFIG_CPLB_INFO
-+	P3 += 8;
-+#endif
++	/* don't use 1136 vic */
++	writel(0, VIC_CONFIG);
 +
-+	CC = R4 == -1;	/* End of config table*/
-+	IF CC JUMP .Lno_page_in_table;
++	/* enable interrupt controller */
++	writel(1, VIC_INT_MASTEREN);
 +
-+	/* See if failed address > start address */
-+	CC = R4 <= R0(IU);
-+	IF !CC JUMP .Linext;
++	for (n = 0; n < NR_MSM_IRQS; n++) {
++		set_irq_chip(n, &msm_irq_chip);
++		set_irq_handler(n, handle_level_irq);
++		set_irq_flags(n, IRQF_VALID);
++	}
++}
+diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c
+new file mode 100644
+index 0000000..bd4732d
+--- /dev/null
++++ b/arch/arm/mach-msm/timer.c
+@@ -0,0 +1,205 @@
++/* linux/arch/arm/mach-msm/timer.c
++ *
++ * Copyright (C) 2007 Google, Inc.
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ */
 +
-+	/* extract page size (17:16)*/
-+	R3 = EXTRACT(R2, R1.L) (Z);
++#include <linux/init.h>
++#include <linux/time.h>
++#include <linux/interrupt.h>
++#include <linux/irq.h>
++#include <linux/clk.h>
++#include <linux/clockchips.h>
++#include <linux/delay.h>
 +
-+	/* add page size to addr to get range */
++#include <asm/mach/time.h>
++#include <asm/arch/msm_iomap.h>
 +
-+	P5 = R3;
-+	P5 = P0 + (P5 << 2);	/* scaled, for int access*/
-+	R3 = [P5];
-+	R3 = R3 + R4;
++#include <asm/io.h>
 +
-+	/* See if failed address < (start address + page size) */
-+	CC = R0 < R3(IU);
-+	IF !CC JUMP .Linext;
++#define MSM_DGT_BASE (MSM_GPT_BASE + 0x10)
++#define MSM_DGT_SHIFT (5)
 +
-+	/* We've found a CPLB in the config table that covers
-+	 * the faulting address, so install this CPLB into the
-+	 * last entry of the table.
-+	 */
++#define TIMER_MATCH_VAL         0x0000
++#define TIMER_COUNT_VAL         0x0004
++#define TIMER_ENABLE            0x0008
++#define TIMER_ENABLE_CLR_ON_MATCH_EN    2
++#define TIMER_ENABLE_EN                 1
++#define TIMER_CLEAR             0x000C
++
++#define CSR_PROTECTION          0x0020
++#define CSR_PROTECTION_EN               1
++
++#define GPT_HZ 32768
++#define DGT_HZ 19200000 /* 19.2 MHz or 600 KHz after shift */
++
++struct msm_clock {
++	struct clock_event_device   clockevent;
++	struct clocksource          clocksource;
++	struct irqaction            irq;
++	uint32_t                    regbase;
++	uint32_t                    freq;
++	uint32_t                    shift;
++};
 +
-+	P1.L = LO(ICPLB_DATA15);		/* ICPLB_DATA15 */
-+	P1.H = HI(ICPLB_DATA15);
-+	[P1] = R2;
-+	[P1-0x100] = R4;
-+#ifdef	CONFIG_CPLB_INFO
-+	R3 = [P3];
-+	R3 += 1;
-+	[P3] = R3;
-+#endif
++static irqreturn_t msm_timer_interrupt(int irq, void *dev_id)
++{
++	struct clock_event_device *evt = dev_id;
++	evt->event_handler(evt);
++	return IRQ_HANDLED;
++}
 +
-+	/* P4 points to IMEM_CONTROL, and R5 contains its old
-+	 * value, after we disabled ICPLBS. Re-enable them.
-+	 */
++static cycle_t msm_gpt_read(void)
++{
++	return readl(MSM_GPT_BASE + TIMER_COUNT_VAL);
++}
 +
-+	BITSET(R5,ENICPLB_P);
-+	CLI R2;
-+	SSYNC;		/* SSYNC required before writing to IMEM_CONTROL. */
-+	.align 8;
-+	[P4] = R5;
-+	SSYNC;
-+	STI R2;
++static cycle_t msm_dgt_read(void)
++{
++	return readl(MSM_DGT_BASE + TIMER_COUNT_VAL) >> MSM_DGT_SHIFT;
++}
 +
-+	( R7:4,P5:3 ) = [SP++];
-+	R0 = CPLB_RELOADED;
-+	RTS;
++static int msm_timer_set_next_event(unsigned long cycles,
++				    struct clock_event_device *evt)
++{
++	struct msm_clock *clock = container_of(evt, struct msm_clock, clockevent);
++	uint32_t now = readl(clock->regbase + TIMER_COUNT_VAL);
++	uint32_t alarm = now + (cycles << clock->shift);
++	int late;
 +
-+/* FAILED CASES*/
-+.Lno_page_in_table:
-+	R0 = CPLB_NO_ADDR_MATCH;
-+	JUMP .Lfail_ret;
++	writel(alarm, clock->regbase + TIMER_MATCH_VAL);
++	now = readl(clock->regbase + TIMER_COUNT_VAL);
++	late = now - alarm;
++	if (late >= (-2 << clock->shift) && late < DGT_HZ*5) {
++		printk(KERN_NOTICE "msm_timer_set_next_event(%lu) clock %s, "
++		       "alarm already expired, now %x, alarm %x, late %d\n",
++		       cycles, clock->clockevent.name, now, alarm, late);
++		return -ETIME;
++	}
++	return 0;
++}
 +
-+.Lall_locked:
-+	R0 = CPLB_NO_UNLOCKED;
-+	JUMP .Lfail_ret;
++static void msm_timer_set_mode(enum clock_event_mode mode,
++			      struct clock_event_device *evt)
++{
++	struct msm_clock *clock = container_of(evt, struct msm_clock, clockevent);
++	switch (mode) {
++	case CLOCK_EVT_MODE_RESUME:
++	case CLOCK_EVT_MODE_PERIODIC:
++		break;
++	case CLOCK_EVT_MODE_ONESHOT:
++		writel(TIMER_ENABLE_EN, clock->regbase + TIMER_ENABLE);
++		break;
++	case CLOCK_EVT_MODE_UNUSED:
++	case CLOCK_EVT_MODE_SHUTDOWN:
++		writel(0, clock->regbase + TIMER_ENABLE);
++		break;
++	}
++}
 +
-+.Lprot_violation:
-+	R0 = CPLB_PROT_VIOL;
++static struct msm_clock msm_clocks[] = {
++	{
++		.clockevent = {
++			.name           = "gp_timer",
++			.features       = CLOCK_EVT_FEAT_ONESHOT,
++			.shift          = 32,
++			.rating         = 200,
++			.set_next_event = msm_timer_set_next_event,
++			.set_mode       = msm_timer_set_mode,
++		},
++		.clocksource = {
++			.name           = "gp_timer",
++			.rating         = 200,
++			.read           = msm_gpt_read,
++			.mask           = CLOCKSOURCE_MASK(32),
++			.shift          = 24,
++			.flags          = CLOCK_SOURCE_IS_CONTINUOUS,
++		},
++		.irq = {
++			.name    = "gp_timer",
++			.flags   = IRQF_DISABLED | IRQF_TIMER | IRQF_TRIGGER_RISING,
++			.handler = msm_timer_interrupt,
++			.dev_id  = &msm_clocks[0].clockevent,
++			.irq     = INT_GP_TIMER_EXP
++		},
++		.regbase = MSM_GPT_BASE,
++		.freq = GPT_HZ
++	},
++	{
++		.clockevent = {
++			.name           = "dg_timer",
++			.features       = CLOCK_EVT_FEAT_ONESHOT,
++			.shift          = 32 + MSM_DGT_SHIFT,
++			.rating         = 300,
++			.set_next_event = msm_timer_set_next_event,
++			.set_mode       = msm_timer_set_mode,
++		},
++		.clocksource = {
++			.name           = "dg_timer",
++			.rating         = 300,
++			.read           = msm_dgt_read,
++			.mask           = CLOCKSOURCE_MASK((32 - MSM_DGT_SHIFT)),
++			.shift          = 24 - MSM_DGT_SHIFT,
++			.flags          = CLOCK_SOURCE_IS_CONTINUOUS,
++		},
++		.irq = {
++			.name    = "dg_timer",
++			.flags   = IRQF_DISABLED | IRQF_TIMER | IRQF_TRIGGER_RISING,
++			.handler = msm_timer_interrupt,
++			.dev_id  = &msm_clocks[1].clockevent,
++			.irq     = INT_DEBUG_TIMER_EXP
++		},
++		.regbase = MSM_DGT_BASE,
++		.freq = DGT_HZ >> MSM_DGT_SHIFT,
++		.shift = MSM_DGT_SHIFT
++	}
++};
 +
-+.Lfail_ret:
-+	/* Make sure we turn protection/cache back on, even in the failing case */
-+	BITSET(R5,ENICPLB_P);
-+	CLI R2;
-+	SSYNC;          /* SSYNC required before writing to IMEM_CONTROL. */
-+	.align 8;
-+	[P4] = R5;
-+	SSYNC;
-+	STI R2;
++static void __init msm_timer_init(void)
++{
++	int i;
++	int res;
 +
-+	( R7:4,P5:3 ) = [SP++];
-+	RTS;
++	for (i = 0; i < ARRAY_SIZE(msm_clocks); i++) {
++		struct msm_clock *clock = &msm_clocks[i];
++		struct clock_event_device *ce = &clock->clockevent;
++		struct clocksource *cs = &clock->clocksource;
++		writel(0, clock->regbase + TIMER_ENABLE);
++		writel(0, clock->regbase + TIMER_CLEAR);
++		writel(~0, clock->regbase + TIMER_MATCH_VAL);
++
++		ce->mult = div_sc(clock->freq, NSEC_PER_SEC, ce->shift);
++		/* allow at least 10 seconds to notice that the timer wrapped */
++		ce->max_delta_ns =
++			clockevent_delta2ns(0xf0000000 >> clock->shift, ce);
++		/* 4 gets rounded down to 3 */
++		ce->min_delta_ns = clockevent_delta2ns(4, ce);
++		ce->cpumask = cpumask_of_cpu(0);
++
++		cs->mult = clocksource_hz2mult(clock->freq, cs->shift);
++		res = clocksource_register(cs);
++		if (res)
++			printk(KERN_ERR "msm_timer_init: clocksource_register "
++			       "failed for %s\n", cs->name);
++
++		res = setup_irq(clock->irq.irq, &clock->irq);
++		if (res)
++			printk(KERN_ERR "msm_timer_init: setup_irq "
++			       "failed for %s\n", cs->name);
++
++		clockevents_register_device(ce);
++	}
++}
 +
-+.Ldcplb_write:
++struct sys_timer msm_timer = {
++	.init = msm_timer_init
++};
+diff --git a/arch/arm/mach-mx3/time.c b/arch/arm/mach-mx3/time.c
+index e81fb5c..fb565c9 100644
+--- a/arch/arm/mach-mx3/time.c
++++ b/arch/arm/mach-mx3/time.c
+@@ -45,8 +45,6 @@ static irqreturn_t mxc_timer_interrupt(int irq, void *dev_id)
+ {
+ 	unsigned int next_match;
+ 
+-	write_seqlock(&xtime_lock);
+-
+ 	if (__raw_readl(MXC_GPT_GPTSR) & GPTSR_OF1) {
+ 		do {
+ 			timer_tick();
+@@ -57,8 +55,6 @@ static irqreturn_t mxc_timer_interrupt(int irq, void *dev_id)
+ 				       __raw_readl(MXC_GPT_GPTCNT)) <= 0);
+ 	}
+ 
+-	write_sequnlock(&xtime_lock);
+-
+ 	return IRQ_HANDLED;
+ }
+ 
+diff --git a/arch/arm/mach-netx/time.c b/arch/arm/mach-netx/time.c
+index 4762e20..ea07b54 100644
+--- a/arch/arm/mach-netx/time.c
++++ b/arch/arm/mach-netx/time.c
+@@ -33,12 +33,8 @@
+ static irqreturn_t
+ netx_timer_interrupt(int irq, void *dev_id)
+ {
+-	write_seqlock(&xtime_lock);
+-
+ 	timer_tick();
+ 
+-	write_sequnlock(&xtime_lock);
+-
+ 	/* acknowledge interrupt */
+ 	writel(COUNTER_BIT(0), NETX_GPIO_IRQ);
+ 
+diff --git a/arch/arm/mach-omap1/board-fsample.c b/arch/arm/mach-omap1/board-fsample.c
+index d5f6ea1..f550b19 100644
+--- a/arch/arm/mach-omap1/board-fsample.c
++++ b/arch/arm/mach-omap1/board-fsample.c
+@@ -76,7 +76,7 @@ static struct resource smc91x_resources[] = {
+ 	[1] = {
+ 		.start	= INT_730_MPU_EXT_NIRQ,
+ 		.end	= 0,
+-		.flags	= IORESOURCE_IRQ,
++		.flags	= IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE,
+ 	},
+ };
+ 
+diff --git a/arch/arm/mach-omap1/board-h2.c b/arch/arm/mach-omap1/board-h2.c
+index 1306812..bfa04fa 100644
+--- a/arch/arm/mach-omap1/board-h2.c
++++ b/arch/arm/mach-omap1/board-h2.c
+@@ -27,6 +27,7 @@
+ #include <linux/mtd/nand.h>
+ #include <linux/mtd/partitions.h>
+ #include <linux/input.h>
++#include <linux/i2c/tps65010.h>
+ 
+ #include <asm/hardware.h>
+ #include <asm/gpio.h>
+@@ -36,7 +37,6 @@
+ #include <asm/mach/flash.h>
+ #include <asm/mach/map.h>
+ 
+-#include <asm/arch/tps65010.h>
+ #include <asm/arch/mux.h>
+ #include <asm/arch/tc.h>
+ #include <asm/arch/irda.h>
+@@ -209,7 +209,7 @@ static struct resource h2_smc91x_resources[] = {
+ 	[1] = {
+ 		.start	= OMAP_GPIO_IRQ(0),
+ 		.end	= OMAP_GPIO_IRQ(0),
+-		.flags	= IORESOURCE_IRQ,
++		.flags	= IORESOURCE_IRQ | IORESOURCE_IRQ_LOWEDGE,
+ 	},
+ };
+ 
+diff --git a/arch/arm/mach-omap1/board-h3.c b/arch/arm/mach-omap1/board-h3.c
+index 4f84ae2..0565198 100644
+--- a/arch/arm/mach-omap1/board-h3.c
++++ b/arch/arm/mach-omap1/board-h3.c
+@@ -26,6 +26,7 @@
+ #include <linux/mtd/nand.h>
+ #include <linux/mtd/partitions.h>
+ #include <linux/input.h>
++#include <linux/i2c/tps65010.h>
+ 
+ #include <asm/setup.h>
+ #include <asm/page.h>
+@@ -37,7 +38,6 @@
+ #include <asm/mach/flash.h>
+ #include <asm/mach/map.h>
+ 
+-#include <asm/arch/tps65010.h>
+ #include <asm/arch/gpioexpander.h>
+ #include <asm/arch/irqs.h>
+ #include <asm/arch/mux.h>
+@@ -208,7 +208,7 @@ static struct resource smc91x_resources[] = {
+ 	[1] = {
+ 		.start	= OMAP_GPIO_IRQ(40),
+ 		.end	= OMAP_GPIO_IRQ(40),
+-		.flags	= IORESOURCE_IRQ,
++		.flags	= IORESOURCE_IRQ | IORESOURCE_IRQ_LOWEDGE,
+ 	},
+ };
+ 
+diff --git a/arch/arm/mach-omap1/board-innovator.c b/arch/arm/mach-omap1/board-innovator.c
+index 7e63a41..7d2d8af 100644
+--- a/arch/arm/mach-omap1/board-innovator.c
++++ b/arch/arm/mach-omap1/board-innovator.c
+@@ -202,7 +202,7 @@ static struct resource innovator1510_smc91x_resources[] = {
+ 	[1] = {
+ 		.start	= OMAP1510_INT_ETHER,
+ 		.end	= OMAP1510_INT_ETHER,
+-		.flags	= IORESOURCE_IRQ,
++		.flags	= IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE,
+ 	},
+ };
+ 
+@@ -269,7 +269,7 @@ static struct resource innovator1610_smc91x_resources[] = {
+ 	[1] = {
+ 		.start	= OMAP_GPIO_IRQ(0),
+ 		.end	= OMAP_GPIO_IRQ(0),
+-		.flags	= IORESOURCE_IRQ,
++		.flags	= IORESOURCE_IRQ | IORESOURCE_IRQ_LOWEDGE,
+ 	},
+ };
+ 
+diff --git a/arch/arm/mach-omap1/board-nokia770.c b/arch/arm/mach-omap1/board-nokia770.c
+index 182a98a..e2c8ffd 100644
+--- a/arch/arm/mach-omap1/board-nokia770.c
++++ b/arch/arm/mach-omap1/board-nokia770.c
+@@ -32,7 +32,6 @@
+ #include <asm/arch/common.h>
+ #include <asm/arch/dsp_common.h>
+ #include <asm/arch/aic23.h>
+-#include <asm/arch/gpio.h>
+ #include <asm/arch/omapfb.h>
+ #include <asm/arch/lcd_mipid.h>
+ 
+diff --git a/arch/arm/mach-omap1/board-osk.c b/arch/arm/mach-omap1/board-osk.c
+index 5db182d..8433344 100644
+--- a/arch/arm/mach-omap1/board-osk.c
++++ b/arch/arm/mach-omap1/board-osk.c
+@@ -31,12 +31,13 @@
+ #include <linux/platform_device.h>
+ #include <linux/interrupt.h>
+ #include <linux/irq.h>
+-#include <linux/interrupt.h>
+ #include <linux/i2c.h>
+ 
+ #include <linux/mtd/mtd.h>
+ #include <linux/mtd/partitions.h>
+ 
++#include <linux/i2c/tps65010.h>
 +
-+	/* if a DCPLB is marked as write-back (CPLB_WT==0), and
-+	 * it is clean (CPLB_DIRTY==0), then a write to the
-+	 * CPLB's page triggers a protection violation. We have to
-+	 * mark the CPLB as dirty, to indicate that there are
-+	 * pending writes associated with the CPLB.
-+	 */
+ #include <asm/hardware.h>
+ #include <asm/gpio.h>
+ 
+@@ -46,7 +47,6 @@
+ #include <asm/mach/flash.h>
+ 
+ #include <asm/arch/usb.h>
+-#include <asm/arch/tps65010.h>
+ #include <asm/arch/mux.h>
+ #include <asm/arch/tc.h>
+ #include <asm/arch/common.h>
+@@ -111,7 +111,7 @@ static struct resource osk5912_smc91x_resources[] = {
+ 	[1] = {
+ 		.start	= OMAP_GPIO_IRQ(0),
+ 		.end	= OMAP_GPIO_IRQ(0),
+-		.flags	= IORESOURCE_IRQ,
++		.flags	= IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE,
+ 	},
+ };
+ 
+diff --git a/arch/arm/mach-omap1/board-palmtt.c b/arch/arm/mach-omap1/board-palmtt.c
+index e47010f..ed7094a 100644
+--- a/arch/arm/mach-omap1/board-palmtt.c
++++ b/arch/arm/mach-omap1/board-palmtt.c
+@@ -42,7 +42,6 @@
+ #include <asm/arch/common.h>
+ #include <asm/arch/omap-alsa.h>
+ 
+-#include <linux/input.h>
+ #include <linux/spi/spi.h>
+ #include <linux/spi/ads7846.h>
+ 
+diff --git a/arch/arm/mach-omap1/board-palmz71.c b/arch/arm/mach-omap1/board-palmz71.c
+index c275d51..a9a0f66 100644
+--- a/arch/arm/mach-omap1/board-palmz71.c
++++ b/arch/arm/mach-omap1/board-palmz71.c
+@@ -44,7 +44,6 @@
+ #include <asm/arch/common.h>
+ #include <asm/arch/omap-alsa.h>
+ 
+-#include <linux/input.h>
+ #include <linux/spi/spi.h>
+ #include <linux/spi/ads7846.h>
+ 
+diff --git a/arch/arm/mach-omap1/board-perseus2.c b/arch/arm/mach-omap1/board-perseus2.c
+index e44437e..534dcfb 100644
+--- a/arch/arm/mach-omap1/board-perseus2.c
++++ b/arch/arm/mach-omap1/board-perseus2.c
+@@ -75,7 +75,7 @@ static struct resource smc91x_resources[] = {
+ 	[1] = {
+ 		.start	= INT_730_MPU_EXT_NIRQ,
+ 		.end	= 0,
+-		.flags	= IORESOURCE_IRQ,
++		.flags	= IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE,
+ 	},
+ };
+ 
+diff --git a/arch/arm/mach-omap1/board-voiceblue.c b/arch/arm/mach-omap1/board-voiceblue.c
+index 214dd19..c82a1cd 100644
+--- a/arch/arm/mach-omap1/board-voiceblue.c
++++ b/arch/arm/mach-omap1/board-voiceblue.c
+@@ -117,7 +117,7 @@ static struct resource voiceblue_smc91x_resources[] = {
+ 	[1] = {
+ 		.start	= OMAP_GPIO_IRQ(8),
+ 		.end	= OMAP_GPIO_IRQ(8),
+-		.flags	= IORESOURCE_IRQ,
++		.flags	= IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE,
+ 	},
+ };
+ 
+diff --git a/arch/arm/mach-omap1/leds-osk.c b/arch/arm/mach-omap1/leds-osk.c
+index 86de303..6939d5e 100644
+--- a/arch/arm/mach-omap1/leds-osk.c
++++ b/arch/arm/mach-omap1/leds-osk.c
+@@ -5,13 +5,13 @@
+  */
+ #include <linux/init.h>
+ #include <linux/workqueue.h>
++#include <linux/i2c/tps65010.h>
+ 
+ #include <asm/hardware.h>
+ #include <asm/leds.h>
+ #include <asm/system.h>
+ 
+ #include <asm/arch/gpio.h>
+-#include <asm/arch/tps65010.h>
+ 
+ #include "leds.h"
+ 
+diff --git a/arch/arm/mach-omap1/pm.c b/arch/arm/mach-omap1/pm.c
+index 3bf01e2..06b7e54 100644
+--- a/arch/arm/mach-omap1/pm.c
++++ b/arch/arm/mach-omap1/pm.c
+@@ -69,14 +69,14 @@ static unsigned int mpui1610_sleep_save[MPUI1610_SLEEP_SAVE_SIZE];
+ 
+ static unsigned short enable_dyn_sleep = 1;
+ 
+-static ssize_t omap_pm_sleep_while_idle_show(struct kset *kset, char *buf)
++static ssize_t idle_show(struct kobject *kobj, struct kobj_attribute *attr,
++			 char *buf)
+ {
+ 	return sprintf(buf, "%hu\n", enable_dyn_sleep);
+ }
+ 
+-static ssize_t omap_pm_sleep_while_idle_store(struct kset *kset,
+-					      const char * buf,
+-					      size_t n)
++static ssize_t idle_store(struct kobject *kobj, struct kobj_attribute *attr,
++			  const char * buf, size_t n)
+ {
+ 	unsigned short value;
+ 	if (sscanf(buf, "%hu", &value) != 1 ||
+@@ -88,16 +88,9 @@ static ssize_t omap_pm_sleep_while_idle_store(struct kset *kset,
+ 	return n;
+ }
+ 
+-static struct subsys_attribute sleep_while_idle_attr = {
+-	.attr   = {
+-		.name = __stringify(sleep_while_idle),
+-		.mode = 0644,
+-	},
+-	.show   = omap_pm_sleep_while_idle_show,
+-	.store  = omap_pm_sleep_while_idle_store,
+-};
++static struct kobj_attribute sleep_while_idle_attr =
++	__ATTR(sleep_while_idle, 0644, idle_show, idle_store);
+ 
+-extern struct kset power_subsys;
+ static void (*omap_sram_idle)(void) = NULL;
+ static void (*omap_sram_suspend)(unsigned long r0, unsigned long r1) = NULL;
+ 
+@@ -646,7 +639,7 @@ static void omap_pm_finish(void)
+ }
+ 
+ 
+-static irqreturn_t  omap_wakeup_interrupt(int irq, void *dev)
++static irqreturn_t omap_wakeup_interrupt(int irq, void *dev)
+ {
+ 	return IRQ_HANDLED;
+ }
+@@ -726,9 +719,9 @@ static int __init omap_pm_init(void)
+ 	omap_pm_init_proc();
+ #endif
+ 
+-	error = subsys_create_file(&power_subsys, &sleep_while_idle_attr);
++	error = sysfs_create_file(power_kobj, &sleep_while_idle_attr);
+ 	if (error)
+-		printk(KERN_ERR "subsys_create_file failed: %d\n", error);
++		printk(KERN_ERR "sysfs_create_file failed: %d\n", error);
+ 
+ 	if (cpu_is_omap16xx()) {
+ 		/* configure LOW_PWR pin */
+diff --git a/arch/arm/mach-omap2/board-2430sdp.c b/arch/arm/mach-omap2/board-2430sdp.c
+index 7e76fbf..64235de 100644
+--- a/arch/arm/mach-omap2/board-2430sdp.c
++++ b/arch/arm/mach-omap2/board-2430sdp.c
+@@ -104,7 +104,7 @@ static struct resource sdp2430_smc91x_resources[] = {
+ 	[1] = {
+ 		.start	= OMAP_GPIO_IRQ(OMAP24XX_ETHR_GPIO_IRQ),
+ 		.end	= OMAP_GPIO_IRQ(OMAP24XX_ETHR_GPIO_IRQ),
+-		.flags	= IORESOURCE_IRQ,
++		.flags	= IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE,
+ 	},
+ };
+ 
+diff --git a/arch/arm/mach-omap2/board-apollon.c b/arch/arm/mach-omap2/board-apollon.c
+index 3bb49c1..7846551 100644
+--- a/arch/arm/mach-omap2/board-apollon.c
++++ b/arch/arm/mach-omap2/board-apollon.c
+@@ -26,7 +26,6 @@
+ #include <linux/interrupt.h>
+ #include <linux/delay.h>
+ #include <linux/leds.h>
+-#include <linux/irq.h>
+ 
+ #include <asm/hardware.h>
+ #include <asm/mach-types.h>
+@@ -127,7 +126,7 @@ static struct resource apollon_smc91x_resources[] = {
+ 	[1] = {
+ 		.start	= OMAP_GPIO_IRQ(APOLLON_ETHR_GPIO_IRQ),
+ 		.end	= OMAP_GPIO_IRQ(APOLLON_ETHR_GPIO_IRQ),
+-		.flags	= IORESOURCE_IRQ,
++		.flags	= IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE,
+ 	},
+ };
+ 
+diff --git a/arch/arm/mach-omap2/timer-gp.c b/arch/arm/mach-omap2/timer-gp.c
+index 8d322c2..3234dee 100644
+--- a/arch/arm/mach-omap2/timer-gp.c
++++ b/arch/arm/mach-omap2/timer-gp.c
+@@ -40,13 +40,9 @@ static inline void omap2_gp_timer_start(unsigned long load_val)
+ 
+ static irqreturn_t omap2_gp_timer_interrupt(int irq, void *dev_id)
+ {
+-	write_seqlock(&xtime_lock);
+-
+ 	omap_dm_timer_write_status(gptimer, OMAP_TIMER_INT_OVERFLOW);
+ 	timer_tick();
+ 
+-	write_sequnlock(&xtime_lock);
+-
+ 	return IRQ_HANDLED;
+ }
+ 
+diff --git a/arch/arm/mach-orion/Kconfig b/arch/arm/mach-orion/Kconfig
+new file mode 100644
+index 0000000..1dcbb6a
+--- /dev/null
++++ b/arch/arm/mach-orion/Kconfig
+@@ -0,0 +1,41 @@
++if ARCH_ORION
++
++menu "Orion Implementations"
++
++config MACH_DB88F5281
++	bool "Marvell Orion-2 Development Board"
++	select I2C_BOARDINFO
++	help
++	  Say 'Y' here if you want your kernel to support the
++	  Marvell Orion-2 (88F5281) Development Board
 +
-+	P4.L = LO(DCPLB_STATUS);
-+	P4.H = HI(DCPLB_STATUS);
-+	P3.L = LO(DCPLB_DATA0);
-+	P3.H = HI(DCPLB_DATA0);
-+	R5 = [P4];
++config MACH_RD88F5182
++	bool "Marvell Orion-NAS Reference Design"
++	select I2C_BOARDINFO
++	help
++	  Say 'Y' here if you want your kernel to support the
++	  Marvell Orion-NAS (88F5182) RD2
 +
-+	/* A protection violation can be caused by more than just writes
-+	 * to a clean WB page, so we have to ensure that:
-+	 * - It's a write
-+	 * - to a clean WB page
-+	 * - and is allowed in the mode the access occurred.
-+	 */
++config MACH_KUROBOX_PRO
++	bool "KuroBox Pro"
++	select I2C_BOARDINFO
++	help
++	  Say 'Y' here if you want your kernel to support the
++	  KuroBox Pro platform.
 +
-+	CC = BITTST(R5, 16);	/* ensure it was a write*/
-+	IF !CC JUMP .Lprot_violation;
++config MACH_DNS323
++	bool "D-Link DNS-323"
++	select I2C_BOARDINFO
++	help
++	  Say 'Y' here if you want your kernel to support the
++	  D-Link DNS-323 platform.
 +
-+	/* to check the rest, we have to retrieve the DCPLB.*/
++config MACH_TS209
++	bool "QNAP TS-109/TS-209"
++	help
++	  Say 'Y' here if you want your kernel to support the
++	  QNAP TS-109/TS-209 platform.
 +
-+	/* The low half of DCPLB_STATUS is a bit mask*/
++endmenu
 +
-+	R2 = R5.L (Z);	/* indicating which CPLB triggered the event.*/
-+	R3 = 30;	/* so we can use this to determine the offset*/
-+	R2.L = SIGNBITS R2;
-+	R2 = R2.L (Z);	/* into the DCPLB table.*/
-+	R3 = R3 - R2;
-+	P4 = R3;
-+	P3 = P3 + (P4<<2);
-+	R3 = [P3];	/* Retrieve the CPLB*/
++endif
+diff --git a/arch/arm/mach-orion/Makefile b/arch/arm/mach-orion/Makefile
+new file mode 100644
+index 0000000..f91d937
+--- /dev/null
++++ b/arch/arm/mach-orion/Makefile
+@@ -0,0 +1,6 @@
++obj-y				+= common.o addr-map.o pci.o gpio.o irq.o time.o
++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_DNS323)	+= dns323-setup.o
++obj-$(CONFIG_MACH_TS209)	+= ts209-setup.o
+diff --git a/arch/arm/mach-orion/Makefile.boot b/arch/arm/mach-orion/Makefile.boot
+new file mode 100644
+index 0000000..67039c3
+--- /dev/null
++++ b/arch/arm/mach-orion/Makefile.boot
+@@ -0,0 +1,3 @@
++   zreladdr-y	:= 0x00008000
++params_phys-y	:= 0x00000100
++initrd_phys-y	:= 0x00800000
+diff --git a/arch/arm/mach-orion/addr-map.c b/arch/arm/mach-orion/addr-map.c
+new file mode 100644
+index 0000000..488da38
+--- /dev/null
++++ b/arch/arm/mach-orion/addr-map.c
+@@ -0,0 +1,484 @@
++/*
++ * arch/arm/mach-orion/addr-map.c
++ *
++ * Address map functions for Marvell Orion System On Chip
++ *
++ * Maintainer: Tzachi Perelstein <tzachi at marvell.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.
++ */
 +
-+	/* Now we can check whether it's a clean WB page*/
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <asm/hardware.h>
++#include "common.h"
 +
-+	CC = BITTST(R3, 14);	/* 0==WB, 1==WT*/
-+	IF CC JUMP .Lprot_violation;
-+	CC = BITTST(R3, 7);	/* 0 == clean, 1 == dirty*/
-+	IF CC JUMP .Lprot_violation;
++/*
++ * The Orion has fully programable address map. There's a separate address
++ * map for each of the device _master_ interfaces, e.g. CPU, PCI, PCIE, USB,
++ * Gigabit Ethernet, DMA/XOR engines, etc. Each interface has its own
++ * address decode windows that allow it to access any of the Orion resources.
++ *
++ * CPU address decoding --
++ * Linux assumes that it is the boot loader that already setup the access to
++ * DDR and internal registers.
++ * Setup access to PCI and PCI-E IO/MEM space is issued by core.c.
++ * Setup access to various devices located on the device bus interface (e.g.
++ * flashes, RTC, etc) should be issued by machine-setup.c according to
++ * specific board population (by using orion_setup_cpu_win()).
++ *
++ * Non-CPU Masters address decoding --
++ * Unlike the CPU, we setup the access from Orion's master interfaces to DDR
++ * banks only (the typical use case).
++ * Setup access for each master to DDR is issued by common.c.
++ *
++ * Note: although orion_setbits() and orion_clrbits() are not atomic
++ * no locking is necessary here since code in this file is only called
++ * at boot time when there is no concurrency issues.
++ */
 +
-+	/* Check whether the write is allowed in the mode that was active.*/
++/*
++ * Generic Address Decode Windows bit settings
++ */
++#define TARGET_DDR		0
++#define TARGET_PCI		3
++#define TARGET_PCIE		4
++#define TARGET_DEV_BUS		1
++#define ATTR_DDR_CS(n)		(((n) ==0) ? 0xe :	\
++				((n) == 1) ? 0xd :	\
++				((n) == 2) ? 0xb :	\
++				((n) == 3) ? 0x7 : 0xf)
++#define ATTR_PCIE_MEM		0x59
++#define ATTR_PCIE_IO		0x51
++#define ATTR_PCI_MEM		0x59
++#define ATTR_PCI_IO		0x51
++#define ATTR_DEV_CS0		0x1e
++#define ATTR_DEV_CS1		0x1d
++#define ATTR_DEV_CS2		0x1b
++#define ATTR_DEV_BOOT		0xf
++#define WIN_EN			1
 +
-+	R2 = 1<<3;		/* checking write in user mode*/
-+	CC = BITTST(R5, 17);	/* 0==was user, 1==was super*/
-+	R5 = CC;
-+	R2 <<= R5;		/* if was super, check write in super mode*/
-+	R2 = R3 & R2;
-+	CC = R2 == 0;
-+	IF CC JUMP .Lprot_violation;
++/*
++ * Helpers to get DDR banks info
++ */
++#define DDR_BASE_CS(n)		ORION_DDR_REG(0x1500 + ((n) * 8))
++#define DDR_SIZE_CS(n)		ORION_DDR_REG(0x1504 + ((n) * 8))
++#define DDR_MAX_CS		4
++#define DDR_REG_TO_SIZE(reg)	(((reg) | 0xffffff) + 1)
++#define DDR_REG_TO_BASE(reg)	((reg) & 0xff000000)
++#define DDR_BANK_EN		1
 +
-+	/* It's a genuine write-to-clean-page.*/
++/*
++ * CPU Address Decode Windows registers
++ */
++#define CPU_WIN_CTRL(n)		ORION_BRIDGE_REG(0x000 | ((n) << 4))
++#define CPU_WIN_BASE(n)		ORION_BRIDGE_REG(0x004 | ((n) << 4))
++#define CPU_WIN_REMAP_LO(n)	ORION_BRIDGE_REG(0x008 | ((n) << 4))
++#define CPU_WIN_REMAP_HI(n)	ORION_BRIDGE_REG(0x00c | ((n) << 4))
++#define CPU_MAX_WIN		8
 +
-+	BITSET(R3, 7);		/* mark as dirty*/
-+	[P3] = R3;		/* and write back.*/
-+	NOP;
-+	CSYNC;
-+	( R7:4,P5:3 ) = [SP++];
-+	R0 = CPLB_RELOADED;
-+	RTS;
++/*
++ * Use this CPU address decode windows allocation
++ */
++#define CPU_WIN_PCIE_IO		0
++#define CPU_WIN_PCI_IO		1
++#define CPU_WIN_PCIE_MEM	2
++#define CPU_WIN_PCI_MEM		3
++#define CPU_WIN_DEV_BOOT	4
++#define CPU_WIN_DEV_CS0		5
++#define CPU_WIN_DEV_CS1		6
++#define CPU_WIN_DEV_CS2		7
 +
-+.Ldcplb_miss_compare:
++/*
++ * PCIE Address Decode Windows registers
++ */
++#define PCIE_BAR_CTRL(n)	ORION_PCIE_REG(0x1804 + ((n - 1) * 4))
++#define PCIE_BAR_LO(n)		ORION_PCIE_REG(0x0010 + ((n) * 8))
++#define PCIE_BAR_HI(n)		ORION_PCIE_REG(0x0014 + ((n) * 8))
++#define PCIE_WIN_CTRL(n)	ORION_PCIE_REG(0x1820 + ((n) << 4))
++#define PCIE_WIN_BASE(n)	ORION_PCIE_REG(0x1824 + ((n) << 4))
++#define PCIE_WIN_REMAP(n)	ORION_PCIE_REG(0x182c + ((n) << 4))
++#define PCIE_DEFWIN_CTRL	ORION_PCIE_REG(0x18b0)
++#define PCIE_EXPROM_WIN_CTRL	ORION_PCIE_REG(0x18c0)
++#define PCIE_EXPROM_WIN_REMP	ORION_PCIE_REG(0x18c4)
++#define PCIE_MAX_BARS		3
++#define PCIE_MAX_WINS		5
 +
-+	/* Data CPLB Miss event. We need to choose a CPLB to
-+	 * evict, and then locate a new CPLB to install from the
-+	 * config table, that covers the faulting address.
-+	 */
++/*
++ * Use PCIE BAR '1' for all DDR banks
++ */
++#define PCIE_DRAM_BAR		1
 +
-+	P1.L = LO(DCPLB_DATA15);
-+	P1.H = HI(DCPLB_DATA15);
++/*
++ * PCI Address Decode Windows registers
++ */
++#define PCI_BAR_SIZE_DDR_CS(n)	(((n) == 0) ? ORION_PCI_REG(0xc08) : \
++				((n) == 1) ? ORION_PCI_REG(0xd08) :  \
++				((n) == 2) ? ORION_PCI_REG(0xc0c) :  \
++				((n) == 3) ? ORION_PCI_REG(0xd0c) : 0)
++#define PCI_BAR_REMAP_DDR_CS(n)	(((n) ==0) ? ORION_PCI_REG(0xc48) : \
++				((n) == 1) ? ORION_PCI_REG(0xd48) :  \
++				((n) == 2) ? ORION_PCI_REG(0xc4c) :  \
++				((n) == 3) ? ORION_PCI_REG(0xd4c) : 0)
++#define PCI_BAR_ENABLE		ORION_PCI_REG(0xc3c)
++#define PCI_CTRL_BASE_LO(n)	ORION_PCI_REG(0x1e00 | ((n) << 4))
++#define PCI_CTRL_BASE_HI(n)	ORION_PCI_REG(0x1e04 | ((n) << 4))
++#define PCI_CTRL_SIZE(n)	ORION_PCI_REG(0x1e08 | ((n) << 4))
++#define PCI_ADDR_DECODE_CTRL	ORION_PCI_REG(0xd3c)
 +
-+	P4.L = LO(DCPLB_FAULT_ADDR);
-+	P4.H = HI(DCPLB_FAULT_ADDR);
-+	R4 = [P4];
-+	I0 = R4;
++/*
++ * PCI configuration heleprs for BAR settings
++ */
++#define PCI_CONF_FUNC_BAR_CS(n)		((n) >> 1)
++#define PCI_CONF_REG_BAR_LO_CS(n)	(((n) & 1) ? 0x18 : 0x10)
++#define PCI_CONF_REG_BAR_HI_CS(n)	(((n) & 1) ? 0x1c : 0x14)
 +
-+	/* The replacement procedure for DCPLBs*/
++/*
++ * Gigabit Ethernet Address Decode Windows registers
++ */
++#define ETH_WIN_BASE(win)	ORION_ETH_REG(0x200 + ((win) * 8))
++#define ETH_WIN_SIZE(win)	ORION_ETH_REG(0x204 + ((win) * 8))
++#define ETH_WIN_REMAP(win)	ORION_ETH_REG(0x280 + ((win) * 4))
++#define ETH_WIN_EN		ORION_ETH_REG(0x290)
++#define ETH_WIN_PROT		ORION_ETH_REG(0x294)
++#define ETH_MAX_WIN		6
++#define ETH_MAX_REMAP_WIN	4
 +
-+	R6 = R1;	/* Save for later*/
++/*
++ * USB Address Decode Windows registers
++ */
++#define USB_WIN_CTRL(i, w)	((i == 0) ? ORION_USB0_REG(0x320 + ((w) << 4)) \
++					: ORION_USB1_REG(0x320 + ((w) << 4)))
++#define USB_WIN_BASE(i, w)	((i == 0) ? ORION_USB0_REG(0x324 + ((w) << 4)) \
++					: ORION_USB1_REG(0x324 + ((w) << 4)))
++#define USB_MAX_WIN		4
 +
-+	/* Turn off CPLBs while we work.*/
-+	P4.L = LO(DMEM_CONTROL);
-+	P4.H = HI(DMEM_CONTROL);
-+	R5 = [P4];
-+	BITCLR(R5,ENDCPLB_P);
-+	CLI R0;
-+	SSYNC;		/* SSYNC required before writing to DMEM_CONTROL. */
-+	.align 8;
-+	[P4] = R5;
-+	SSYNC;
-+	STI R0;
++/*
++ * SATA Address Decode Windows registers
++ */
++#define SATA_WIN_CTRL(win)	ORION_SATA_REG(0x30 + ((win) * 0x10))
++#define SATA_WIN_BASE(win)	ORION_SATA_REG(0x34 + ((win) * 0x10))
++#define SATA_MAX_WIN		4
 +
-+	/* Start looking for a CPLB to evict. Our order of preference
-+	 * is: invalid CPLBs, clean CPLBs, dirty CPLBs. Locked CPLBs
-+	 * are no good.
++static int __init orion_cpu_win_can_remap(u32 win)
++{
++	u32 dev, rev;
++
++	orion_pcie_id(&dev, &rev);
++	if ((dev == MV88F5281_DEV_ID && win < 4)
++	    || (dev == MV88F5182_DEV_ID && win < 2)
++	    || (dev == MV88F5181_DEV_ID && win < 2))
++		return 1;
++
++	return 0;
++}
++
++void __init orion_setup_cpu_win(enum orion_target target, u32 base, u32 size, int remap)
++{
++	u32 win, attr, ctrl;
++
++	switch (target) {
++	case ORION_PCIE_IO:
++		target = TARGET_PCIE;
++		attr = ATTR_PCIE_IO;
++		win = CPU_WIN_PCIE_IO;
++		break;
++	case ORION_PCI_IO:
++		target = TARGET_PCI;
++		attr = ATTR_PCI_IO;
++		win = CPU_WIN_PCI_IO;
++		break;
++	case ORION_PCIE_MEM:
++		target = TARGET_PCIE;
++		attr = ATTR_PCIE_MEM;
++		win = CPU_WIN_PCIE_MEM;
++		break;
++	case ORION_PCI_MEM:
++		target = TARGET_PCI;
++		attr = ATTR_PCI_MEM;
++		win = CPU_WIN_PCI_MEM;
++		break;
++	case ORION_DEV_BOOT:
++		target = TARGET_DEV_BUS;
++		attr = ATTR_DEV_BOOT;
++		win = CPU_WIN_DEV_BOOT;
++		break;
++	case ORION_DEV0:
++		target = TARGET_DEV_BUS;
++		attr = ATTR_DEV_CS0;
++		win = CPU_WIN_DEV_CS0;
++		break;
++	case ORION_DEV1:
++		target = TARGET_DEV_BUS;
++		attr = ATTR_DEV_CS1;
++		win = CPU_WIN_DEV_CS1;
++		break;
++	case ORION_DEV2:
++		target = TARGET_DEV_BUS;
++		attr = ATTR_DEV_CS2;
++		win = CPU_WIN_DEV_CS2;
++		break;
++	case ORION_DDR:
++	case ORION_REGS:
++		/*
++		 * Must be mapped by bootloader.
++		 */
++	default:
++		target = attr = win = -1;
++		BUG();
++	}
++
++	base &= 0xffff0000;
++	ctrl = (((size - 1) & 0xffff0000) | (attr << 8) |
++		(target << 4) | WIN_EN);
++
++	orion_write(CPU_WIN_BASE(win), base);
++	orion_write(CPU_WIN_CTRL(win), ctrl);
++
++	if (orion_cpu_win_can_remap(win)) {
++		if (remap >= 0) {
++			orion_write(CPU_WIN_REMAP_LO(win), remap & 0xffff0000);
++			orion_write(CPU_WIN_REMAP_HI(win), 0);
++		} else {
++			orion_write(CPU_WIN_REMAP_LO(win), base);
++			orion_write(CPU_WIN_REMAP_HI(win), 0);
++		}
++	}
++}
++
++void __init orion_setup_cpu_wins(void)
++{
++	int i;
++
++	/*
++	 * First, disable and clear windows
 +	 */
++	for (i = 0; i < CPU_MAX_WIN; i++) {
++		orion_write(CPU_WIN_BASE(i), 0);
++		orion_write(CPU_WIN_CTRL(i), 0);
++		if (orion_cpu_win_can_remap(i)) {
++			orion_write(CPU_WIN_REMAP_LO(i), 0);
++			orion_write(CPU_WIN_REMAP_HI(i), 0);
++		}
++	}
 +
-+	I1.L = LO(DCPLB_DATA0);
-+	I1.H = HI(DCPLB_DATA0);
-+	P1 = 2;
-+	P2 = 16;
-+	I2.L = _dcplb_preference;
-+	I2.H = _dcplb_preference;
-+	LSETUP(.Lsdsearch1, .Ledsearch1) LC0 = P1;
-+.Lsdsearch1:
-+	R0 = [I2++];		/* Get the bits we're interested in*/
-+	P0 = I1;		/* Go back to start of table*/
-+	LSETUP (.Lsdsearch2, .Ledsearch2) LC1 = P2;
-+.Lsdsearch2:
-+	R1 = [P0++];		/* Fetch each installed CPLB in turn*/
-+	R2 = R1 & R0;		/* and test for interesting bits.*/
-+	CC = R2 == 0;		/* If none are set, it'll do.*/
-+	IF !CC JUMP .Lskip_stack_check;
++	/*
++	 * Setup windows for PCI+PCIE IO+MAM space
++	 */
++	orion_setup_cpu_win(ORION_PCIE_IO, ORION_PCIE_IO_BASE,
++				ORION_PCIE_IO_SIZE, ORION_PCIE_IO_REMAP);
++	orion_setup_cpu_win(ORION_PCI_IO, ORION_PCI_IO_BASE,
++				ORION_PCI_IO_SIZE, ORION_PCI_IO_REMAP);
++	orion_setup_cpu_win(ORION_PCIE_MEM, ORION_PCIE_MEM_BASE,
++				ORION_PCIE_MEM_SIZE, -1);
++	orion_setup_cpu_win(ORION_PCI_MEM, ORION_PCI_MEM_BASE,
++				ORION_PCI_MEM_SIZE, -1);
++}
 +
-+	R2 = [P0 - 0x104]; 	/* R2 - PageStart */
-+	P3.L = _page_size_table; /* retrieve end address */
-+	P3.H = _page_size_table; /* retrieve end address */
-+	R3 = 0x1002;		/* 16th - position, 2 bits -length */
-+#if ANOMALY_05000209
-+	nop;			/* Anomaly 05000209 */
-+#endif
-+	R7 = EXTRACT(R1,R3.l);
-+	R7 = R7 << 2;		/* Page size index offset */
-+	P5 = R7;
-+	P3 = P3 + P5;
-+	R7 = [P3];		/* page size in bytes */
++/*
++ * Setup PCIE BARs and Address Decode Wins:
++ * BAR[0,2] -> disabled, BAR[1] -> covers all DRAM banks
++ * WIN[0-3] -> DRAM bank[0-3]
++ */
++void __init orion_setup_pcie_wins(void)
++{
++	u32 base, size, i;
 +
-+	R7 = R2 + R7;		/* R7 - PageEnd */
-+	R4 = SP; 		/* Test SP is in range */
++	/*
++	 * First, disable and clear BARs and windows
++	 */
++	for (i = 1; i < PCIE_MAX_BARS; i++) {
++		orion_write(PCIE_BAR_CTRL(i), 0);
++		orion_write(PCIE_BAR_LO(i), 0);
++		orion_write(PCIE_BAR_HI(i), 0);
++	}
 +
-+	CC = R7 < R4;		/* if PageEnd < SP */
-+	IF CC JUMP .Ldfound_victim;
-+	R3 = 0x284;		/* stack length from start of trap till
-+				 * the point.
-+				 * 20 stack locations for future modifications
-+				 */
-+	R4 = R4 + R3;
-+	CC = R4 < R2;		/* if SP + stacklen < PageStart */
-+	IF CC JUMP .Ldfound_victim;
-+.Lskip_stack_check:
++	for (i = 0; i < PCIE_MAX_WINS; i++) {
++		orion_write(PCIE_WIN_CTRL(i), 0);
++		orion_write(PCIE_WIN_BASE(i), 0);
++		orion_write(PCIE_WIN_REMAP(i), 0);
++	}
 +
-+.Ledsearch2: NOP;
-+.Ledsearch1: NOP;
++	/*
++	 * Setup windows for DDR banks. Count total DDR size on the fly.
++	 */
++	base = DDR_REG_TO_BASE(orion_read(DDR_BASE_CS(0)));
++	size = 0;
++	for (i = 0; i < DDR_MAX_CS; i++) {
++		u32 bank_base, bank_size;
++		bank_size = orion_read(DDR_SIZE_CS(i));
++		bank_base = orion_read(DDR_BASE_CS(i));
++		if (bank_size & DDR_BANK_EN) {
++			bank_size = DDR_REG_TO_SIZE(bank_size);
++			bank_base = DDR_REG_TO_BASE(bank_base);
++			orion_write(PCIE_WIN_BASE(i), bank_base & 0xffff0000);
++			orion_write(PCIE_WIN_REMAP(i), 0);
++			orion_write(PCIE_WIN_CTRL(i),
++					((bank_size-1) & 0xffff0000) |
++					(ATTR_DDR_CS(i) << 8) |
++					(TARGET_DDR << 4) |
++					(PCIE_DRAM_BAR << 1) | WIN_EN);
++			size += bank_size;
++		}
++	}
 +
-+	/* If we got here, we didn't find a DCPLB we considered
-+	 * replacable, which means all of them were locked.
++	/*
++	 * Setup BAR[1] to all DRAM banks
 +	 */
++	orion_write(PCIE_BAR_LO(PCIE_DRAM_BAR), base & 0xffff0000);
++	orion_write(PCIE_BAR_HI(PCIE_DRAM_BAR), 0);
++	orion_write(PCIE_BAR_CTRL(PCIE_DRAM_BAR),
++				((size - 1) & 0xffff0000) | WIN_EN);
++}
 +
-+	JUMP .Lall_locked;
-+.Ldfound_victim:
++void __init orion_setup_pci_wins(void)
++{
++	u32 base, size, i;
 +
-+#ifdef CONFIG_CPLB_INFO
-+	R7 = [P0 - 0x104];
-+	P2.L = _dpdt_table;
-+	P2.H = _dpdt_table;
-+	P3.L = _dpdt_swapcount_table;
-+	P3.H = _dpdt_swapcount_table;
-+	P3 += -4;
-+.Ldicount:
-+	R2 = [P2];
-+	P2 += 8;
-+	P3 += 8;
-+	CC = R2==-1;
-+	IF CC JUMP .Ldicount_done;
-+	CC = R7==R2;
-+	IF !CC JUMP .Ldicount;
-+	R7 = [P3];
-+	R7 += 1;
-+	[P3] = R7;
-+.Ldicount_done:
-+#endif
++	/*
++	 * First, disable windows
++	 */
++	orion_write(PCI_BAR_ENABLE, 0xffffffff);
 +
-+	/* Clean down the hardware loops*/
-+	R2 = 0;
-+	LC1 = R2;
-+	LC0 = R2;
++	/*
++	 * Setup windows for DDR banks.
++	 */
++	for (i = 0; i < DDR_MAX_CS; i++) {
++		base = orion_read(DDR_BASE_CS(i));
++		size = orion_read(DDR_SIZE_CS(i));
++		if (size & DDR_BANK_EN) {
++			u32 bus, dev, func, reg, val;
++			size = DDR_REG_TO_SIZE(size);
++			base = DDR_REG_TO_BASE(base);
++			bus = orion_pci_local_bus_nr();
++			dev = orion_pci_local_dev_nr();
++			func = PCI_CONF_FUNC_BAR_CS(i);
++			reg = PCI_CONF_REG_BAR_LO_CS(i);
++			orion_pci_hw_rd_conf(bus, dev, func, reg, 4, &val);
++			orion_pci_hw_wr_conf(bus, dev, func, reg, 4,
++					(base & 0xfffff000) | (val & 0xfff));
++			reg = PCI_CONF_REG_BAR_HI_CS(i);
++			orion_pci_hw_wr_conf(bus, dev, func, reg, 4, 0);
++			orion_write(PCI_BAR_SIZE_DDR_CS(i),
++					(size - 1) & 0xfffff000);
++			orion_write(PCI_BAR_REMAP_DDR_CS(i),
++					base & 0xfffff000);
++			orion_clrbits(PCI_BAR_ENABLE, (1 << i));
++		}
++	}
 +
-+	/* There's a suitable victim in [P0-4] (because we've
-+	 * advanced already).
++	/*
++	 * Disable automatic update of address remaping when writing to BARs
 +	 */
++	orion_setbits(PCI_ADDR_DECODE_CTRL, 1);
++}
 +
-+.LDdoverwrite:
++void __init orion_setup_usb_wins(void)
++{
++	int i;
++	u32 usb_if, dev, rev;
++	u32 max_usb_if = 1;
 +
-+	/* [P0-4] is a suitable victim CPLB, so we want to
-+	 * overwrite it by moving all the following CPLBs
-+	 * one space closer to the start.
++	orion_pcie_id(&dev, &rev);
++	if (dev == MV88F5182_DEV_ID)
++		max_usb_if = 2;
++
++	for (usb_if = 0; usb_if < max_usb_if; usb_if++) {
++		/*
++		 * First, disable and clear windows
++		 */
++		for (i = 0; i < USB_MAX_WIN; i++) {
++			orion_write(USB_WIN_BASE(usb_if, i), 0);
++			orion_write(USB_WIN_CTRL(usb_if, i), 0);
++		}
++
++		/*
++		 * Setup windows for DDR banks.
++		 */
++		for (i = 0; i < DDR_MAX_CS; i++) {
++			u32 base, size;
++			size = orion_read(DDR_SIZE_CS(i));
++			base = orion_read(DDR_BASE_CS(i));
++			if (size & DDR_BANK_EN) {
++				base = DDR_REG_TO_BASE(base);
++				size = DDR_REG_TO_SIZE(size);
++				orion_write(USB_WIN_CTRL(usb_if, i),
++						((size-1) & 0xffff0000) |
++						(ATTR_DDR_CS(i) << 8) |
++						(TARGET_DDR << 4) | WIN_EN);
++				orion_write(USB_WIN_BASE(usb_if, i),
++						base & 0xffff0000);
++			}
++		}
++	}
++}
++
++void __init orion_setup_eth_wins(void)
++{
++	int i;
++
++	/*
++	 * First, disable and clear windows
 +	 */
++	for (i = 0; i < ETH_MAX_WIN; i++) {
++		orion_write(ETH_WIN_BASE(i), 0);
++		orion_write(ETH_WIN_SIZE(i), 0);
++		orion_setbits(ETH_WIN_EN, 1 << i);
++		orion_clrbits(ETH_WIN_PROT, 0x3 << (i * 2));
++		if (i < ETH_MAX_REMAP_WIN)
++			orion_write(ETH_WIN_REMAP(i), 0);
++	}
 +
-+	R1.L = LO(DCPLB_DATA16);		/* DCPLB_DATA15 + 4 */
-+	R1.H = HI(DCPLB_DATA16);
-+	R0 = P0;
++	/*
++	 * Setup windows for DDR banks.
++	 */
++	for (i = 0; i < DDR_MAX_CS; i++) {
++		u32 base, size;
++		size = orion_read(DDR_SIZE_CS(i));
++		base = orion_read(DDR_BASE_CS(i));
++		if (size & DDR_BANK_EN) {
++			base = DDR_REG_TO_BASE(base);
++			size = DDR_REG_TO_SIZE(size);
++			orion_write(ETH_WIN_SIZE(i), (size-1) & 0xffff0000);
++			orion_write(ETH_WIN_BASE(i), (base & 0xffff0000) |
++					(ATTR_DDR_CS(i) << 8) |
++					TARGET_DDR);
++			orion_clrbits(ETH_WIN_EN, 1 << i);
++			orion_setbits(ETH_WIN_PROT, 0x3 << (i * 2));
++		}
++	}
++}
 +
-+	/* If the victim happens to be in DCPLB15,
-+	 * we don't need to move anything.
++void __init orion_setup_sata_wins(void)
++{
++	int i;
++
++	/*
++	 * First, disable and clear windows
 +	 */
++	for (i = 0; i < SATA_MAX_WIN; i++) {
++		orion_write(SATA_WIN_BASE(i), 0);
++		orion_write(SATA_WIN_CTRL(i), 0);
++	}
 +
-+	CC = R1 == R0;
-+	IF CC JUMP .Lde_moved;
-+	R1 = R1 - R0;
-+	R1 >>= 2;
-+	P1 = R1;
-+	LSETUP(.Lds_move, .Lde_move) LC0=P1;
-+.Lds_move:
-+	R0 = [P0++];	/* move data */
-+	[P0 - 8] = R0;
-+	R0 = [P0-0x104]	/* move address */
-+.Lde_move:
-+	 [P0-0x108] = R0;
++	/*
++	 * Setup windows for DDR banks.
++	 */
++	for (i = 0; i < DDR_MAX_CS; i++) {
++		u32 base, size;
++		size = orion_read(DDR_SIZE_CS(i));
++		base = orion_read(DDR_BASE_CS(i));
++		if (size & DDR_BANK_EN) {
++			base = DDR_REG_TO_BASE(base);
++			size = DDR_REG_TO_SIZE(size);
++			orion_write(SATA_WIN_CTRL(i),
++					((size-1) & 0xffff0000) |
++					(ATTR_DDR_CS(i) << 8) |
++					(TARGET_DDR << 4) | WIN_EN);
++			orion_write(SATA_WIN_BASE(i),
++					base & 0xffff0000);
++		}
++	}
++}
+diff --git a/arch/arm/mach-orion/common.c b/arch/arm/mach-orion/common.c
+new file mode 100644
+index 0000000..5e20b6b
+--- /dev/null
++++ b/arch/arm/mach-orion/common.c
+@@ -0,0 +1,315 @@
++/*
++ * arch/arm/mach-orion/common.c
++ *
++ * Core functions for Marvell Orion System On Chip
++ *
++ * Maintainer: Tzachi Perelstein <tzachi at marvell.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.
++ */
 +
-+.Lde_moved:
-+	NOP;
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/platform_device.h>
++#include <linux/serial_8250.h>
++#include <linux/mv643xx_eth.h>
++#include <linux/mv643xx_i2c.h>
++#include <asm/page.h>
++#include <asm/timex.h>
++#include <asm/mach/map.h>
++#include <asm/arch/orion.h>
++#include "common.h"
++
++/*****************************************************************************
++ * I/O Address Mapping
++ ****************************************************************************/
++static struct map_desc orion_io_desc[] __initdata = {
++	{
++		.virtual	= ORION_REGS_BASE,
++		.pfn		= __phys_to_pfn(ORION_REGS_BASE),
++		.length		= ORION_REGS_SIZE,
++		.type		= MT_DEVICE
++	},
++	{
++		.virtual	= ORION_PCIE_IO_BASE,
++		.pfn		= __phys_to_pfn(ORION_PCIE_IO_BASE),
++		.length		= ORION_PCIE_IO_SIZE,
++		.type		= MT_DEVICE
++	},
++	{
++		.virtual	= ORION_PCI_IO_BASE,
++		.pfn		= __phys_to_pfn(ORION_PCI_IO_BASE),
++		.length		= ORION_PCI_IO_SIZE,
++		.type		= MT_DEVICE
++	},
++	{
++		.virtual	= ORION_PCIE_WA_BASE,
++		.pfn		= __phys_to_pfn(ORION_PCIE_WA_BASE),
++		.length		= ORION_PCIE_WA_SIZE,
++		.type		= MT_DEVICE
++	},
++};
 +
-+	/* Clear DCPLB_DATA15, in case we don't find a replacement
-+	 * otherwise, we would have a duplicate entry, and will crash
++void __init orion_map_io(void)
++{
++	iotable_init(orion_io_desc, ARRAY_SIZE(orion_io_desc));
++}
++
++/*****************************************************************************
++ * UART
++ ****************************************************************************/
++
++static struct resource orion_uart_resources[] = {
++	{
++		.start		= UART0_BASE,
++		.end		= UART0_BASE + 0xff,
++		.flags		= IORESOURCE_MEM,
++	},
++	{
++		.start		= IRQ_ORION_UART0,
++		.end		= IRQ_ORION_UART0,
++		.flags		= IORESOURCE_IRQ,
++	},
++	{
++		.start		= UART1_BASE,
++		.end		= UART1_BASE + 0xff,
++		.flags		= IORESOURCE_MEM,
++	},
++	{
++		.start		= IRQ_ORION_UART1,
++		.end		= IRQ_ORION_UART1,
++		.flags		= IORESOURCE_IRQ,
++	},
++};
++
++static struct plat_serial8250_port orion_uart_data[] = {
++	{
++		.mapbase	= UART0_BASE,
++		.membase	= (char *)UART0_BASE,
++		.irq		= IRQ_ORION_UART0,
++		.flags		= UPF_SKIP_TEST | UPF_BOOT_AUTOCONF,
++		.iotype		= UPIO_MEM,
++		.regshift	= 2,
++		.uartclk	= ORION_TCLK,
++	},
++	{
++		.mapbase	= UART1_BASE,
++		.membase	= (char *)UART1_BASE,
++		.irq		= IRQ_ORION_UART1,
++		.flags		= UPF_SKIP_TEST | UPF_BOOT_AUTOCONF,
++		.iotype		= UPIO_MEM,
++		.regshift	= 2,
++		.uartclk	= ORION_TCLK,
++	},
++	{ },
++};
++
++static struct platform_device orion_uart = {
++	.name			= "serial8250",
++	.id			= PLAT8250_DEV_PLATFORM,
++	.dev			= {
++		.platform_data	= orion_uart_data,
++	},
++	.resource		= orion_uart_resources,
++	.num_resources		= ARRAY_SIZE(orion_uart_resources),
++};
++
++/*******************************************************************************
++ * USB Controller - 2 interfaces
++ ******************************************************************************/
++
++static struct resource orion_ehci0_resources[] = {
++	{
++		.start	= ORION_USB0_REG_BASE,
++		.end	= ORION_USB0_REG_BASE + SZ_4K,
++		.flags	= IORESOURCE_MEM,
++	},
++	{
++		.start	= IRQ_ORION_USB0_CTRL,
++		.end	= IRQ_ORION_USB0_CTRL,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct resource orion_ehci1_resources[] = {
++	{
++		.start	= ORION_USB1_REG_BASE,
++		.end	= ORION_USB1_REG_BASE + SZ_4K,
++		.flags	= IORESOURCE_MEM,
++	},
++	{
++		.start	= IRQ_ORION_USB1_CTRL,
++		.end	= IRQ_ORION_USB1_CTRL,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static u64 ehci_dmamask = 0xffffffffUL;
++
++static struct platform_device orion_ehci0 = {
++	.name		= "orion-ehci",
++	.id		= 0,
++	.dev		= {
++		.dma_mask		= &ehci_dmamask,
++		.coherent_dma_mask	= 0xffffffff,
++	},
++	.resource	= orion_ehci0_resources,
++	.num_resources	= ARRAY_SIZE(orion_ehci0_resources),
++};
++
++static struct platform_device orion_ehci1 = {
++	.name		= "orion-ehci",
++	.id		= 1,
++	.dev		= {
++		.dma_mask		= &ehci_dmamask,
++		.coherent_dma_mask	= 0xffffffff,
++	},
++	.resource	= orion_ehci1_resources,
++	.num_resources	= ARRAY_SIZE(orion_ehci1_resources),
++};
++
++/*****************************************************************************
++ * Gigabit Ethernet port
++ * (The Orion and Discovery (MV643xx) families use the same Ethernet driver)
++ ****************************************************************************/
++
++static struct resource orion_eth_shared_resources[] = {
++	{
++		.start	= ORION_ETH_REG_BASE,
++		.end	= ORION_ETH_REG_BASE + 0xffff,
++		.flags	= IORESOURCE_MEM,
++	},
++};
++
++static struct platform_device orion_eth_shared = {
++	.name		= MV643XX_ETH_SHARED_NAME,
++	.id		= 0,
++	.num_resources	= 1,
++	.resource	= orion_eth_shared_resources,
++};
++
++static struct resource orion_eth_resources[] = {
++	{
++		.name	= "eth irq",
++		.start	= IRQ_ORION_ETH_SUM,
++		.end	= IRQ_ORION_ETH_SUM,
++		.flags	= IORESOURCE_IRQ,
++	}
++};
++
++static struct platform_device orion_eth = {
++	.name		= MV643XX_ETH_NAME,
++	.id		= 0,
++	.num_resources	= 1,
++	.resource	= orion_eth_resources,
++};
++
++void __init orion_eth_init(struct mv643xx_eth_platform_data *eth_data)
++{
++	orion_eth.dev.platform_data = eth_data;
++	platform_device_register(&orion_eth_shared);
++	platform_device_register(&orion_eth);
++}
++
++/*****************************************************************************
++ * I2C controller
++ * (The Orion and Discovery (MV643xx) families share the same I2C controller)
++ ****************************************************************************/
++
++static struct mv64xxx_i2c_pdata orion_i2c_pdata = {
++	.freq_m		= 8, /* assumes 166 MHz TCLK */
++	.freq_n		= 3,
++	.timeout	= 1000, /* Default timeout of 1 second */
++};
++
++static struct resource orion_i2c_resources[] = {
++	{
++		.name   = "i2c base",
++		.start  = I2C_BASE,
++		.end    = I2C_BASE + 0x20 -1,
++		.flags  = IORESOURCE_MEM,
++	},
++	{
++		.name   = "i2c irq",
++		.start  = IRQ_ORION_I2C,
++		.end    = IRQ_ORION_I2C,
++		.flags  = IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device orion_i2c = {
++	.name		= MV64XXX_I2C_CTLR_NAME,
++	.id		= 0,
++	.num_resources	= ARRAY_SIZE(orion_i2c_resources),
++	.resource	= orion_i2c_resources,
++	.dev		= {
++		.platform_data = &orion_i2c_pdata,
++	},
++};
++
++/*****************************************************************************
++ * General
++ ****************************************************************************/
++
++/*
++ * Identify device ID and rev from PCIE configuration header space '0'.
++ */
++static void orion_id(u32 *dev, u32 *rev, char **dev_name)
++{
++	orion_pcie_id(dev, rev);
++
++	if (*dev == MV88F5281_DEV_ID) {
++		if (*rev == MV88F5281_REV_D2) {
++			*dev_name = "MV88F5281-D2";
++		} else if (*rev == MV88F5281_REV_D1) {
++			*dev_name = "MV88F5281-D1";
++		} else {
++			*dev_name = "MV88F5281-Rev-Unsupported";
++		}
++	} else if (*dev == MV88F5182_DEV_ID) {
++		if (*rev == MV88F5182_REV_A2) {
++			*dev_name = "MV88F5182-A2";
++		} else {
++			*dev_name = "MV88F5182-Rev-Unsupported";
++		}
++	} else if (*dev == MV88F5181_DEV_ID) {
++		if (*rev == MV88F5181_REV_B1) {
++			*dev_name = "MV88F5181-Rev-B1";
++		} else {
++			*dev_name = "MV88F5181-Rev-Unsupported";
++		}
++	} else {
++		*dev_name = "Device-Unknown";
++	}
++}
++
++void __init orion_init(void)
++{
++	char *dev_name;
++	u32 dev, rev;
++
++	orion_id(&dev, &rev, &dev_name);
++	printk(KERN_INFO "Orion ID: %s. TCLK=%d.\n", dev_name, ORION_TCLK);
++
++	/*
++	 * Setup Orion address map
 +	 */
-+	R0 = 0;
-+	[P0 - 0x4] = R0;
++	orion_setup_cpu_wins();
++	orion_setup_usb_wins();
++	orion_setup_eth_wins();
++	orion_setup_pci_wins();
++	orion_setup_pcie_wins();
++	if (dev == MV88F5182_DEV_ID)
++		orion_setup_sata_wins();
 +
-+	/* We've now made space in DCPLB15 for the new CPLB to be
-+	 * installed. The next stage is to locate a CPLB in the
-+	 * config table that covers the faulting address.
++	/*
++	 * REgister devices
 +	 */
++	platform_device_register(&orion_uart);
++	platform_device_register(&orion_ehci0);
++	if (dev == MV88F5182_DEV_ID)
++		platform_device_register(&orion_ehci1);
++	platform_device_register(&orion_i2c);
++}
+diff --git a/arch/arm/mach-orion/common.h b/arch/arm/mach-orion/common.h
+new file mode 100644
+index 0000000..06c10c0
+--- /dev/null
++++ b/arch/arm/mach-orion/common.h
+@@ -0,0 +1,78 @@
++#ifndef __ARCH_ORION_COMMON_H__
++#define __ARCH_ORION_COMMON_H__
 +
-+	R0 = I0;		/* Our faulting address */
++/*
++ * Basic Orion init functions used early by machine-setup.
++ */
 +
-+	P2.L = _dpdt_table;
-+	P2.H = _dpdt_table;
-+#ifdef	CONFIG_CPLB_INFO
-+	P3.L = _dpdt_swapcount_table;
-+	P3.H = _dpdt_swapcount_table;
-+	P3 += -8;
-+#endif
++void __init orion_map_io(void);
++void __init orion_init_irq(void);
++void __init orion_init(void);
 +
-+	P1.L = _page_size_table;
-+	P1.H = _page_size_table;
++/*
++ * Enumerations and functions for Orion windows mapping. Used by Orion core
++ * functions to map its interfaces and by the machine-setup to map its on-
++ * board devices. Details in /mach-orion/addr-map.c
++ */
 +
-+	/* An extraction pattern, to retrieve bits 17:16.*/
++enum orion_target {
++	ORION_DEV_BOOT = 0,
++	ORION_DEV0,
++	ORION_DEV1,
++	ORION_DEV2,
++	ORION_PCIE_MEM,
++	ORION_PCIE_IO,
++	ORION_PCI_MEM,
++	ORION_PCI_IO,
++	ORION_DDR,
++	ORION_REGS,
++	ORION_MAX_TARGETS
++};
 +
-+	R1 = (16<<8)|2;
-+.Ldnext:	R4 = [P2++];	/* address */
-+	R2 = [P2++];	/* data */
-+#ifdef	CONFIG_CPLB_INFO
-+	P3 += 8;
-+#endif
++void orion_setup_cpu_win(enum orion_target target, u32 base, u32 size, int remap);
++void orion_setup_cpu_wins(void);
++void orion_setup_eth_wins(void);
++void orion_setup_usb_wins(void);
++void orion_setup_pci_wins(void);
++void orion_setup_pcie_wins(void);
++void orion_setup_sata_wins(void);
 +
-+	CC = R4 == -1;
-+	IF CC JUMP .Lno_page_in_table;
++/*
++ * Shared code used internally by other Orion core functions.
++ * (/mach-orion/pci.c)
++ */
 +
-+	/* See if failed address > start address */
-+	CC = R4 <= R0(IU);
-+	IF !CC JUMP .Ldnext;
++struct pci_sys_data;
++struct pci_bus;
 +
-+	/* extract page size (17:16)*/
-+	R3 = EXTRACT(R2, R1.L) (Z);
++void orion_pcie_id(u32 *dev, u32 *rev);
++u32 orion_pcie_local_bus_nr(void);
++u32 orion_pci_local_bus_nr(void);
++u32 orion_pci_local_dev_nr(void);
++int orion_pci_sys_setup(int nr, struct pci_sys_data *sys);
++struct pci_bus *orion_pci_sys_scan_bus(int nr, struct pci_sys_data *sys);
++int orion_pci_hw_rd_conf(u32 bus, u32 dev, u32 func, u32 where, u32 size, u32 *val);
++int orion_pci_hw_wr_conf(u32 bus, u32 dev, u32 func, u32 where, u32 size, u32 val);
 +
-+	/* add page size to addr to get range */
++/*
++ * Valid GPIO pins according to MPP setup, used by machine-setup.
++ * (/mach-orion/gpio.c).
++ */
 +
-+	P5 = R3;
-+	P5 = P1 + (P5 << 2);
-+	R3 = [P5];
-+	R3 = R3 + R4;
++void __init orion_gpio_set_valid_pins(u32 pins);
++void gpio_display(void);	/* debug */
 +
-+	/* See if failed address < (start address + page size) */
-+	CC = R0 < R3(IU);
-+	IF !CC JUMP .Ldnext;
++/*
++ * Orion system timer (clocksource + clockevnt, /mach-orion/time.c)
++ */
++extern struct sys_timer orion_timer;
 +
-+	/* We've found the CPLB that should be installed, so
-+	 * write it into CPLB15, masking off any caching bits
-+	 * if necessary.
++/*
++ * Pull in Orion Ethernet platform_data, used by machine-setup
++ */
++
++struct mv643xx_eth_platform_data;
++
++void __init orion_eth_init(struct mv643xx_eth_platform_data *eth_data);
++
++#endif /* __ARCH_ORION_COMMON_H__ */
+diff --git a/arch/arm/mach-orion/db88f5281-setup.c b/arch/arm/mach-orion/db88f5281-setup.c
+new file mode 100644
+index 0000000..cb2a95c
+--- /dev/null
++++ b/arch/arm/mach-orion/db88f5281-setup.c
+@@ -0,0 +1,364 @@
++/*
++ * arch/arm/mach-orion/db88f5281-setup.c
++ *
++ * Marvell Orion-2 Development Board Setup
++ *
++ * Maintainer: Tzachi Perelstein <tzachi at marvell.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/platform_device.h>
++#include <linux/pci.h>
++#include <linux/irq.h>
++#include <linux/mtd/physmap.h>
++#include <linux/mtd/nand.h>
++#include <linux/timer.h>
++#include <linux/mv643xx_eth.h>
++#include <linux/i2c.h>
++#include <asm/mach-types.h>
++#include <asm/gpio.h>
++#include <asm/mach/arch.h>
++#include <asm/mach/pci.h>
++#include <asm/arch/orion.h>
++#include <asm/arch/platform.h>
++#include "common.h"
++
++/*****************************************************************************
++ * DB-88F5281 on board devices
++ ****************************************************************************/
++
++/*
++ * 512K NOR flash Device bus boot chip select
++ */
++
++#define DB88F5281_NOR_BOOT_BASE		0xf4000000
++#define DB88F5281_NOR_BOOT_SIZE		SZ_512K
++
++/*
++ * 7-Segment on Device bus chip select 0
++ */
++
++#define DB88F5281_7SEG_BASE		0xfa000000
++#define DB88F5281_7SEG_SIZE		SZ_1K
++
++/*
++ * 32M NOR flash on Device bus chip select 1
++ */
++
++#define DB88F5281_NOR_BASE		0xfc000000
++#define DB88F5281_NOR_SIZE		SZ_32M
++
++/*
++ * 32M NAND flash on Device bus chip select 2
++ */
++
++#define DB88F5281_NAND_BASE		0xfa800000
++#define DB88F5281_NAND_SIZE		SZ_1K
++
++/*
++ * PCI
++ */
++
++#define DB88F5281_PCI_SLOT0_OFFS		7
++#define DB88F5281_PCI_SLOT0_IRQ_PIN		12
++#define DB88F5281_PCI_SLOT1_SLOT2_IRQ_PIN	13
++
++/*****************************************************************************
++ * 512M NOR Flash on Device bus Boot CS
++ ****************************************************************************/
++
++static struct physmap_flash_data db88f5281_boot_flash_data = {
++	.width		= 1,	/* 8 bit bus width */
++};
++
++static struct resource db88f5281_boot_flash_resource = {
++	.flags		= IORESOURCE_MEM,
++	.start		= DB88F5281_NOR_BOOT_BASE,
++	.end		= DB88F5281_NOR_BOOT_BASE + DB88F5281_NOR_BOOT_SIZE - 1,
++};
++
++static struct platform_device db88f5281_boot_flash = {
++	.name		= "physmap-flash",
++	.id		= 0,
++	.dev		= {
++		.platform_data = &db88f5281_boot_flash_data,
++	},
++	.num_resources	= 1,
++	.resource	= &db88f5281_boot_flash_resource,
++};
++
++/*****************************************************************************
++ * 32M NOR Flash on Device bus CS1
++ ****************************************************************************/
++
++static struct physmap_flash_data db88f5281_nor_flash_data = {
++	.width		= 4,	/* 32 bit bus width */
++};
++
++static struct resource db88f5281_nor_flash_resource = {
++	.flags		= IORESOURCE_MEM,
++	.start		= DB88F5281_NOR_BASE,
++	.end		= DB88F5281_NOR_BASE + DB88F5281_NOR_SIZE - 1,
++};
++
++static struct platform_device db88f5281_nor_flash = {
++	.name		= "physmap-flash",
++	.id		= 1,
++	.dev		= {
++		.platform_data = &db88f5281_nor_flash_data,
++	},
++	.num_resources	= 1,
++	.resource	= &db88f5281_nor_flash_resource,
++};
++
++/*****************************************************************************
++ * 32M NAND Flash on Device bus CS2
++ ****************************************************************************/
++
++static struct mtd_partition db88f5281_nand_parts[] = {
++	{
++		.name = "kernel",
++		.offset = 0,
++		.size = SZ_2M,
++	},
++	{
++		.name = "root",
++		.offset = SZ_2M,
++		.size = (SZ_16M - SZ_2M),
++	},
++	{
++		.name = "user",
++		.offset = SZ_16M,
++		.size = SZ_8M,
++	},
++	{
++		.name = "recovery",
++		.offset = (SZ_16M + SZ_8M),
++		.size = SZ_8M,
++	},
++};
++
++static struct resource db88f5281_nand_resource = {
++	.flags		= IORESOURCE_MEM,
++	.start		= DB88F5281_NAND_BASE,
++	.end		= DB88F5281_NAND_BASE + DB88F5281_NAND_SIZE - 1,
++};
++
++static struct orion_nand_data db88f5281_nand_data = {
++	.parts		= db88f5281_nand_parts,
++	.nr_parts	= ARRAY_SIZE(db88f5281_nand_parts),
++	.cle		= 0,
++	.ale		= 1,
++	.width		= 8,
++};
++
++static struct platform_device db88f5281_nand_flash = {
++	.name		= "orion_nand",
++	.id		= -1,
++	.dev		= {
++		.platform_data	= &db88f5281_nand_data,
++	},
++	.resource	= &db88f5281_nand_resource,
++	.num_resources	= 1,
++};
++
++/*****************************************************************************
++ * 7-Segment on Device bus CS0
++ * Dummy counter every 2 sec
++ ****************************************************************************/
++
++static void __iomem *db88f5281_7seg;
++static struct timer_list db88f5281_timer;
++
++static void db88f5281_7seg_event(unsigned long data)
++{
++	static int count = 0;
++	writel(0, db88f5281_7seg + (count << 4));
++	count = (count + 1) & 7;
++	mod_timer(&db88f5281_timer, jiffies + 2 * HZ);
++}
++
++static int __init db88f5281_7seg_init(void)
++{
++	if (machine_is_db88f5281()) {
++		db88f5281_7seg = ioremap(DB88F5281_7SEG_BASE,
++					DB88F5281_7SEG_SIZE);
++		if (!db88f5281_7seg) {
++			printk(KERN_ERR "Failed to ioremap db88f5281_7seg\n");
++			return -EIO;
++		}
++		setup_timer(&db88f5281_timer, db88f5281_7seg_event, 0);
++		mod_timer(&db88f5281_timer, jiffies + 2 * HZ);
++	}
++
++	return 0;
++}
++
++__initcall(db88f5281_7seg_init);
++
++/*****************************************************************************
++ * PCI
++ ****************************************************************************/
++
++void __init db88f5281_pci_preinit(void)
++{
++	int pin;
++
++	/*
++	 * Configure PCI GPIO IRQ pins
 +	 */
++	pin = DB88F5281_PCI_SLOT0_IRQ_PIN;
++	if (gpio_request(pin, "PCI Int1") == 0) {
++		if (gpio_direction_input(pin) == 0) {
++			set_irq_type(gpio_to_irq(pin), IRQT_LOW);
++		} else {
++			printk(KERN_ERR "db88f5281_pci_preinit faield to "
++					"set_irq_type pin %d\n", pin);
++			gpio_free(pin);
++		}
++	} else {
++		printk(KERN_ERR "db88f5281_pci_preinit failed to gpio_request %d\n", pin);
++	}
 +
-+	P1.L = LO(DCPLB_DATA15);
-+	P1.H = HI(DCPLB_DATA15);
++	pin = DB88F5281_PCI_SLOT1_SLOT2_IRQ_PIN;
++	if (gpio_request(pin, "PCI Int2") == 0) {
++		if (gpio_direction_input(pin) == 0) {
++			set_irq_type(gpio_to_irq(pin), IRQT_LOW);
++		} else {
++			printk(KERN_ERR "db88f5281_pci_preinit faield "
++					"to set_irq_type pin %d\n", pin);
++			gpio_free(pin);
++		}
++	} else {
++		printk(KERN_ERR "db88f5281_pci_preinit failed to gpio_request %d\n", pin);
++	}
++}
 +
-+	/* If the DCPLB has cache bits set, but caching hasn't
-+	 * been enabled, then we want to mask off the cache-in-L1
-+	 * bit before installing. Moreover, if caching is off, we
-+	 * also want to ensure that the DCPLB has WT mode set, rather
-+	 * than WB, since WB pages still trigger first-write exceptions
-+	 * even when not caching is off, and the page isn't marked as
-+	 * cachable. Finally, we could mark the page as clean, not dirty,
-+	 * but we choose to leave that decision to the user; if the user
-+	 * chooses to have a CPLB pre-defined as dirty, then they always
-+	 * pay the cost of flushing during eviction, but don't pay the
-+	 * cost of first-write exceptions to mark the page as dirty.
++static int __init db88f5281_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
++{
++	/*
++	 * PCIE IRQ is connected internally (not GPIO)
 +	 */
++	if (dev->bus->number == orion_pcie_local_bus_nr())
++		return IRQ_ORION_PCIE0_INT;
 +
-+#ifdef CONFIG_BFIN_WT
-+	BITSET(R6, 14);		/* Set WT*/
-+#endif
++	/*
++	 * PCI IRQs are connected via GPIOs
++	 */
++	switch (slot - DB88F5281_PCI_SLOT0_OFFS) {
++	case 0:
++		return gpio_to_irq(DB88F5281_PCI_SLOT0_IRQ_PIN);
++	case 1:
++	case 2:
++		return gpio_to_irq(DB88F5281_PCI_SLOT1_SLOT2_IRQ_PIN);
++	default:
++		return -1;
++	}
++}
 +
-+	[P1] = R2;
-+	[P1-0x100] = R4;
-+#ifdef	CONFIG_CPLB_INFO
-+	R3 = [P3];
-+	R3 += 1;
-+	[P3] = R3;
-+#endif
++static struct hw_pci db88f5281_pci __initdata = {
++	.nr_controllers	= 2,
++	.preinit	= db88f5281_pci_preinit,
++	.swizzle	= pci_std_swizzle,
++	.setup		= orion_pci_sys_setup,
++	.scan		= orion_pci_sys_scan_bus,
++	.map_irq	= db88f5281_pci_map_irq,
++};
 +
-+	/* We've installed the CPLB, so re-enable CPLBs. P4
-+	 * points to DMEM_CONTROL, and R5 is the value we
-+	 * last wrote to it, when we were disabling CPLBs.
++static int __init db88f5281_pci_init(void)
++{
++	if (machine_is_db88f5281())
++		pci_common_init(&db88f5281_pci);
++
++	return 0;
++}
++
++subsys_initcall(db88f5281_pci_init);
++
++/*****************************************************************************
++ * Ethernet
++ ****************************************************************************/
++static struct mv643xx_eth_platform_data db88f5281_eth_data = {
++	.phy_addr	= 8,
++	.force_phy_addr = 1,
++};
++
++/*****************************************************************************
++ * RTC DS1339 on I2C bus
++ ****************************************************************************/
++static struct i2c_board_info __initdata db88f5281_i2c_rtc = {
++	.driver_name	= "rtc-ds1307",
++	.type		= "ds1339",
++	.addr		= 0x68,
++};
++
++/*****************************************************************************
++ * General Setup
++ ****************************************************************************/
++
++static struct platform_device *db88f5281_devs[] __initdata = {
++	&db88f5281_boot_flash,
++	&db88f5281_nor_flash,
++	&db88f5281_nand_flash,
++};
++
++static void __init db88f5281_init(void)
++{
++	/*
++	 * Basic Orion setup. Need to be called early.
 +	 */
++	orion_init();
 +
-+	BITSET(R5,ENDCPLB_P);
-+	CLI R2;
-+	.align 8;
-+	[P4] = R5;
-+	SSYNC;
-+	STI R2;
++	/*
++	 * Setup the CPU address decode windows for our on-board devices
++	 */
++	orion_setup_cpu_win(ORION_DEV_BOOT, DB88F5281_NOR_BOOT_BASE,
++				DB88F5281_NOR_BOOT_SIZE, -1);
++	orion_setup_cpu_win(ORION_DEV0,	DB88F5281_7SEG_BASE,
++				DB88F5281_7SEG_SIZE, -1);
++	orion_setup_cpu_win(ORION_DEV1, DB88F5281_NOR_BASE,
++				DB88F5281_NOR_SIZE, -1);
++	orion_setup_cpu_win(ORION_DEV2,	DB88F5281_NAND_BASE,
++				DB88F5281_NAND_SIZE, -1);
 +
-+	( R7:4,P5:3 ) = [SP++];
-+	R0 = CPLB_RELOADED;
-+	RTS;
-+ENDPROC(_cplb_mgr)
++	/*
++	 * Setup Multiplexing Pins:
++	 * MPP0: GPIO (USB Over Current)	MPP1: GPIO (USB Vbat input)
++	 * MPP2: PCI_REQn[2]			MPP3: PCI_GNTn[2]
++	 * MPP4: PCI_REQn[3]			MPP5: PCI_GNTn[3]
++	 * MPP6: GPIO (JP0, CON17.2)		MPP7: GPIO (JP1, CON17.1)
++	 * MPP8: GPIO (JP2, CON11.2)		MPP9: GPIO (JP3, CON11.3)
++	 * MPP10: GPIO (RTC int)		MPP11: GPIO (Baud Rate Generator)
++	 * MPP12: GPIO (PCI int 1)		MPP13: GPIO (PCI int 2)
++	 * MPP14: NAND_REn[2]			MPP15: NAND_WEn[2]
++	 * MPP16: UART1_RX			MPP17: UART1_TX
++	 * MPP18: UART1_CTS			MPP19: UART1_RTS
++	 * MPP-DEV: DEV_D[16:31]
++	 */
++	orion_write(MPP_0_7_CTRL, 0x00222203);
++	orion_write(MPP_8_15_CTRL, 0x44000000);
++	orion_write(MPP_16_19_CTRL, 0);
++	orion_write(MPP_DEV_CTRL, 0);
++
++	orion_gpio_set_valid_pins(0x00003fc3);
++
++	platform_add_devices(db88f5281_devs, ARRAY_SIZE(db88f5281_devs));
++	i2c_register_board_info(0, &db88f5281_i2c_rtc, 1);
++	orion_eth_init(&db88f5281_eth_data);
++}
++
++MACHINE_START(DB88F5281, "Marvell Orion-2 Development Board")
++	/* Maintainer: Tzachi Perelstein <tzachi at marvell.com> */
++	.phys_io	= ORION_REGS_BASE,
++	.io_pg_offst	= ((ORION_REGS_BASE) >> 18) & 0xfffc,
++	.boot_params	= 0x00000100,
++	.init_machine	= db88f5281_init,
++	.map_io		= orion_map_io,
++	.init_irq	= orion_init_irq,
++	.timer		= &orion_timer,
++MACHINE_END
+diff --git a/arch/arm/mach-orion/dns323-setup.c b/arch/arm/mach-orion/dns323-setup.c
+new file mode 100644
+index 0000000..c8a806f
+--- /dev/null
++++ b/arch/arm/mach-orion/dns323-setup.c
+@@ -0,0 +1,322 @@
++/*
++ * arch/arm/mach-orion/dns323-setup.c
++ *
++ * Copyright (C) 2007 Herbert Valerio Riedel <hvr at gnu.org>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License as
++ * published by the Free Software Foundation; either version 2 of the
++ * License, or (at your option) any later version.
++ *
++ */
 +
-+.data
-+.align 4;
-+_page_size_table:
-+.byte4	0x00000400;	/* 1K */
-+.byte4	0x00001000;	/* 4K */
-+.byte4	0x00100000;	/* 1M */
-+.byte4	0x00400000;	/* 4M */
++#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 <asm/mach-types.h>
++#include <asm/gpio.h>
++#include <asm/mach/arch.h>
++#include <asm/mach/pci.h>
++#include <asm/arch/orion.h>
++#include <asm/arch/platform.h>
++#include "common.h"
++
++#define DNS323_GPIO_LED_RIGHT_AMBER	1
++#define DNS323_GPIO_LED_LEFT_AMBER	2
++#define DNS323_GPIO_LED_POWER		5
++#define DNS323_GPIO_OVERTEMP		6
++#define DNS323_GPIO_RTC			7
++#define DNS323_GPIO_POWER_OFF		8
++#define DNS323_GPIO_KEY_POWER		9
++#define DNS323_GPIO_KEY_RESET		10
++
++/****************************************************************************
++ * PCI setup
++ */
++
++static int __init dns323_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
++{
++	/* PCI-E */
++	if (dev->bus->number == orion_pcie_local_bus_nr())
++		return IRQ_ORION_PCIE0_INT;
 +
-+.align 4;
-+_dcplb_preference:
-+.byte4	0x00000001;	/* valid bit */
-+.byte4	0x00000002;	/* lock bit */
-diff --git a/arch/blackfin/kernel/cplbinit.c b/arch/blackfin/kernel/cplbinit.c
++	pr_err("%s: requested mapping for unknown bus\n", __func__);
++
++	return -1;
++}
++
++static struct hw_pci dns323_pci __initdata = {
++	.nr_controllers = 1,
++	.swizzle	= pci_std_swizzle,
++	.setup		= orion_pci_sys_setup,
++	.scan		= orion_pci_sys_scan_bus,
++	.map_irq	= dns323_pci_map_irq,
++};
++
++static int __init dns323_pci_init(void)
++{
++	if (machine_is_dns323())
++		pci_common_init(&dns323_pci);
++
++	return 0;
++}
++
++subsys_initcall(dns323_pci_init);
++
++/****************************************************************************
++ * Ethernet
++ */
++
++static struct mv643xx_eth_platform_data dns323_eth_data = {
++	.phy_addr = 8,
++	.force_phy_addr = 1,
++};
++
++/****************************************************************************
++ * 8MiB NOR flash (Spansion S29GL064M90TFIR4)
++ *
++ * Layout as used by D-Link:
++ *  0x00000000-0x00010000 : "MTD1"
++ *  0x00010000-0x00020000 : "MTD2"
++ *  0x00020000-0x001a0000 : "Linux Kernel"
++ *  0x001a0000-0x007d0000 : "File System"
++ *  0x007d0000-0x00800000 : "u-boot"
++ */
++
++#define DNS323_NOR_BOOT_BASE 0xf4000000
++#define DNS323_NOR_BOOT_SIZE SZ_8M
++
++static struct mtd_partition dns323_partitions[] = {
++	{
++		.name	= "MTD1",
++		.size	= 0x00010000,
++		.offset	= 0,
++	}, {
++		.name	= "MTD2",
++		.size	= 0x00010000,
++		.offset = 0x00010000,
++	}, {
++		.name	= "Linux Kernel",
++		.size	= 0x00180000,
++		.offset	= 0x00020000,
++	}, {
++		.name	= "File System",
++		.size	= 0x00630000,
++		.offset	= 0x001A0000,
++	}, {
++		.name	= "u-boot",
++		.size	= 0x00030000,
++		.offset	= 0x007d0000,
++	}
++};
++
++static struct physmap_flash_data dns323_nor_flash_data = {
++	.width		= 1,
++	.parts		= dns323_partitions,
++	.nr_parts	= ARRAY_SIZE(dns323_partitions)
++};
++
++static struct resource dns323_nor_flash_resource = {
++	.flags		= IORESOURCE_MEM,
++	.start		= DNS323_NOR_BOOT_BASE,
++	.end		= DNS323_NOR_BOOT_BASE + DNS323_NOR_BOOT_SIZE - 1,
++};
++
++static struct platform_device dns323_nor_flash = {
++	.name		= "physmap-flash",
++	.id		= 0,
++	.dev		= { .platform_data = &dns323_nor_flash_data, },
++	.resource	= &dns323_nor_flash_resource,
++	.num_resources	= 1,
++};
++
++/****************************************************************************
++ * GPIO LEDs (simple - doesn't use hardware blinking support)
++ */
++
++static struct gpio_led dns323_leds[] = {
++	{
++		.name = "power:blue",
++		.gpio = DNS323_GPIO_LED_POWER,
++		.active_low = 1,
++	}, {
++		.name = "right:amber",
++		.gpio = DNS323_GPIO_LED_RIGHT_AMBER,
++		.active_low = 1,
++	}, {
++		.name = "left:amber",
++		.gpio = DNS323_GPIO_LED_LEFT_AMBER,
++		.active_low = 1,
++	},
++};
++
++static struct gpio_led_platform_data dns323_led_data = {
++	.num_leds	= ARRAY_SIZE(dns323_leds),
++	.leds		= dns323_leds,
++};
++
++static struct platform_device dns323_gpio_leds = {
++	.name		= "leds-gpio",
++	.id		= -1,
++	.dev		= { .platform_data = &dns323_led_data, },
++};
++
++/****************************************************************************
++ * GPIO Attached Keys
++ */
++
++static struct gpio_keys_button dns323_buttons[] = {
++	{
++		.code		= KEY_RESTART,
++		.gpio		= DNS323_GPIO_KEY_RESET,
++		.desc		= "Reset Button",
++		.active_low	= 1,
++	},
++	{
++		.code		= KEY_POWER,
++		.gpio		= DNS323_GPIO_KEY_POWER,
++		.desc		= "Power Button",
++		.active_low	= 1,
++	}
++};
++
++static struct gpio_keys_platform_data dns323_button_data = {
++	.buttons	= dns323_buttons,
++	.nbuttons       = ARRAY_SIZE(dns323_buttons),
++};
++
++static struct platform_device dns323_button_device = {
++	.name		= "gpio-keys",
++	.id		= -1,
++	.num_resources	= 0,
++	.dev		= { .platform_data  = &dns323_button_data, },
++};
++
++/****************************************************************************
++ * General Setup
++ */
++
++static struct platform_device *dns323_plat_devices[] __initdata = {
++	&dns323_nor_flash,
++	&dns323_gpio_leds,
++	&dns323_button_device,
++};
++
++/*
++ * On the DNS-323 the following devices are attached via I2C:
++ *
++ *  i2c addr | chip        | description
++ *  0x3e     | GMT G760Af  | fan speed PWM controller
++ *  0x48     | GMT G751-2f | temp. sensor and therm. watchdog (LM75 compatible)
++ *  0x68     | ST M41T80   | RTC w/ alarm
++ */
++static struct i2c_board_info __initdata dns323_i2c_devices[] = {
++	{
++		I2C_BOARD_INFO("g760a", 0x3e),
++		.type = "g760a",
++	},
++#if 0
++	/* this entry requires the new-style driver model lm75 driver,
++	 * for the meantime "insmod lm75.ko force_lm75=0,0x48" is needed */
++	{
++		I2C_BOARD_INFO("lm75", 0x48),
++		.type = "g751",
++	},
++#endif
++	{
++		I2C_BOARD_INFO("rtc-m41t80", 0x68),
++		.type = "m41t80",
++	}
++};
++
++/* DNS-323 specific power off method */
++static void dns323_power_off(void)
++{
++	pr_info("%s: triggering power-off...\n", __func__);
++	gpio_set_value(DNS323_GPIO_POWER_OFF, 1);
++}
++
++static void __init dns323_init(void)
++{
++	/* Setup basic Orion functions. Need to be called early. */
++	orion_init();
++
++	/* setup flash mapping
++	 * CS3 holds a 8 MB Spansion S29GL064M90TFIR4
++	 */
++	orion_setup_cpu_win(ORION_DEV_BOOT, DNS323_NOR_BOOT_BASE,
++			    DNS323_NOR_BOOT_SIZE, -1);
++
++	/* DNS-323 has a Marvell 88X7042 SATA controller attached via PCIE
++	 *
++	 * Open a special address decode windows for the PCIE WA.
++	 */
++	orion_write(ORION_REGS_BASE | 0x20074, ORION_PCIE_WA_BASE);
++	orion_write(ORION_REGS_BASE | 0x20070,
++		    (0x7941 | (((ORION_PCIE_WA_SIZE >> 16) - 1)) << 16));
++
++	/* set MPP to 0 as D-Link's 2.6.12.6 kernel did */
++	orion_write(MPP_0_7_CTRL, 0);
++	orion_write(MPP_8_15_CTRL, 0);
++	orion_write(MPP_16_19_CTRL, 0);
++	orion_write(MPP_DEV_CTRL, 0);
++
++	/* Define used GPIO pins
++
++	  GPIO Map:
++
++	  |  0 |     | PEX_RST_OUT (not controlled by GPIO)
++	  |  1 | Out | right amber LED (= sata ch0 LED)  (low-active)
++	  |  2 | Out | left  amber LED (= sata ch1 LED)  (low-active)
++	  |  3 | Out | //unknown//
++	  |  4 | Out | power button LED (low-active, together with pin #5)
++	  |  5 | Out | power button LED (low-active, together with pin #4)
++	  |  6 | In  | GMT G751-2f overtemp. shutdown signal (low-active)
++	  |  7 | In  | M41T80 nIRQ/OUT/SQW signal
++	  |  8 | Out | triggers power off (high-active)
++	  |  9 | In  | power button switch (low-active)
++	  | 10 | In  | reset button switch (low-active)
++	  | 11 | Out | //unknown//
++	  | 12 | Out | //unknown//
++	  | 13 | Out | //unknown//
++	  | 14 | Out | //unknown//
++	  | 15 | Out | //unknown//
++	*/
++	orion_gpio_set_valid_pins(0x07f6);
++
++	/* register dns323 specific power-off method */
++	if ((gpio_request(DNS323_GPIO_POWER_OFF, "POWEROFF") != 0)
++	    || (gpio_direction_output(DNS323_GPIO_POWER_OFF, 0) != 0))
++		pr_err("DNS323: failed to setup power-off GPIO\n");
++
++	pm_power_off = dns323_power_off;
++
++	/* register flash and other platform devices */
++	platform_add_devices(dns323_plat_devices,
++			     ARRAY_SIZE(dns323_plat_devices));
++
++	i2c_register_board_info(0, dns323_i2c_devices,
++				ARRAY_SIZE(dns323_i2c_devices));
++
++	orion_eth_init(&dns323_eth_data);
++}
++
++/* Warning: D-Link uses a wrong mach-type (=526) in their bootloader */
++MACHINE_START(DNS323, "D-Link DNS-323")
++	/* Maintainer: Herbert Valerio Riedel <hvr at gnu.org> */
++	.phys_io	= ORION_REGS_BASE,
++	.io_pg_offst	= ((ORION_REGS_BASE) >> 18) & 0xFFFC,
++	.boot_params	= 0x00000100,
++	.init_machine	= dns323_init,
++	.map_io		= orion_map_io,
++	.init_irq	= orion_init_irq,
++	.timer		= &orion_timer,
++MACHINE_END
+diff --git a/arch/arm/mach-orion/gpio.c b/arch/arm/mach-orion/gpio.c
+new file mode 100644
+index 0000000..d5f00c8
+--- /dev/null
++++ b/arch/arm/mach-orion/gpio.c
+@@ -0,0 +1,225 @@
++/*
++ * arch/arm/mach-orion/gpio.c
++ *
++ * GPIO functions for Marvell Orion System On Chip
++ *
++ * Maintainer: Tzachi Perelstein <tzachi at marvell.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/module.h>
++#include <linux/spinlock.h>
++#include <linux/bitops.h>
++#include <asm/gpio.h>
++#include <asm/arch/orion.h>
++#include "common.h"
++
++static DEFINE_SPINLOCK(gpio_lock);
++static unsigned long gpio_valid[BITS_TO_LONGS(GPIO_MAX)];
++static const char *gpio_label[GPIO_MAX];  /* non null for allocated GPIOs */
++
++void __init orion_gpio_set_valid_pins(u32 pins)
++{
++	gpio_valid[0] = pins;
++}
++
++/*
++ * GENERIC_GPIO primitives
++ */
++int gpio_direction_input(unsigned pin)
++{
++	unsigned long flags;
++
++	if (pin >= GPIO_MAX || !test_bit(pin, gpio_valid)) {
++		pr_debug("%s: invalid GPIO %d\n", __FUNCTION__, pin);
++		return -EINVAL;
++	}
++
++	spin_lock_irqsave(&gpio_lock, flags);
++
++	/*
++	 * Some callers might have not used the gpio_request(),
++	 * so flag this pin as requested now.
++	 */
++	if (!gpio_label[pin])
++		gpio_label[pin] = "?";
++
++	orion_setbits(GPIO_IO_CONF, 1 << pin);
++
++	spin_unlock_irqrestore(&gpio_lock, flags);
++	return 0;
++}
++EXPORT_SYMBOL(gpio_direction_input);
++
++int gpio_direction_output(unsigned pin, int value)
++{
++	unsigned long flags;
++	int mask;
++
++	if (pin >= GPIO_MAX || !test_bit(pin, gpio_valid)) {
++		pr_debug("%s: invalid GPIO %d\n", __FUNCTION__, pin);
++		return -EINVAL;
++	}
++
++	spin_lock_irqsave(&gpio_lock, flags);
++
++	/*
++	 * Some callers might have not used the gpio_request(),
++	 * so flag this pin as requested now.
++	 */
++	if (!gpio_label[pin])
++		gpio_label[pin] = "?";
++
++	mask = 1 << pin;
++	orion_clrbits(GPIO_BLINK_EN, mask);
++	if (value)
++		orion_setbits(GPIO_OUT, mask);
++	else
++		orion_clrbits(GPIO_OUT, mask);
++	orion_clrbits(GPIO_IO_CONF, mask);
++
++	spin_unlock_irqrestore(&gpio_lock, flags);
++	return 0;
++}
++EXPORT_SYMBOL(gpio_direction_output);
++
++int gpio_get_value(unsigned pin)
++{
++	int val, mask = 1 << pin;
++
++	if (orion_read(GPIO_IO_CONF) & mask)
++		val = orion_read(GPIO_DATA_IN) ^ orion_read(GPIO_IN_POL);
++	else
++		val = orion_read(GPIO_OUT);
++
++	return val & mask;
++}
++EXPORT_SYMBOL(gpio_get_value);
++
++void gpio_set_value(unsigned pin, int value)
++{
++	unsigned long flags;
++	int mask = 1 << pin;
++
++	spin_lock_irqsave(&gpio_lock, flags);
++
++	orion_clrbits(GPIO_BLINK_EN, mask);
++	if (value)
++		orion_setbits(GPIO_OUT, mask);
++	else
++		orion_clrbits(GPIO_OUT, mask);
++
++	spin_unlock_irqrestore(&gpio_lock, flags);
++}
++EXPORT_SYMBOL(gpio_set_value);
++
++void orion_gpio_set_blink(unsigned pin, int blink)
++{
++	unsigned long flags;
++	int mask = 1 << pin;
++
++	spin_lock_irqsave(&gpio_lock, flags);
++
++	orion_clrbits(GPIO_OUT, mask);
++	if (blink)
++		orion_setbits(GPIO_BLINK_EN, mask);
++	else
++		orion_clrbits(GPIO_BLINK_EN, mask);
++
++	spin_unlock_irqrestore(&gpio_lock, flags);
++}
++EXPORT_SYMBOL(orion_gpio_set_blink);
++
++int gpio_request(unsigned pin, const char *label)
++{
++	int ret = 0;
++	unsigned long flags;
++
++	if (pin >= GPIO_MAX || !test_bit(pin, gpio_valid)) {
++		pr_debug("%s: invalid GPIO %d\n", __FUNCTION__, pin);
++		return -EINVAL;
++	}
++
++	spin_lock_irqsave(&gpio_lock, flags);
++
++	if (gpio_label[pin]) {
++		pr_debug("%s: GPIO %d already used as %s\n",
++			 __FUNCTION__, pin, gpio_label[pin]);
++		ret = -EBUSY;
++	} else
++		gpio_label[pin] = label ? label : "?";
++
++	spin_unlock_irqrestore(&gpio_lock, flags);
++	return ret;
++}
++EXPORT_SYMBOL(gpio_request);
++
++void gpio_free(unsigned pin)
++{
++	if (pin >= GPIO_MAX || !test_bit(pin, gpio_valid)) {
++		pr_debug("%s: invalid GPIO %d\n", __FUNCTION__, pin);
++		return;
++	}
++
++	if (!gpio_label[pin])
++		pr_warning("%s: GPIO %d already freed\n", __FUNCTION__, pin);
++	else
++		gpio_label[pin] = NULL;
++}
++EXPORT_SYMBOL(gpio_free);
++
++/* Debug helper */
++void gpio_display(void)
++{
++	int i;
++
++	for (i = 0; i < GPIO_MAX; i++) {
++		printk(KERN_DEBUG "Pin-%d: ", i);
++
++		if (!test_bit(i, gpio_valid)) {
++			printk("non-GPIO\n");
++		} else if (!gpio_label[i]) {
++			printk("GPIO, free\n");
++		} else {
++			printk("GPIO, used by %s, ", gpio_label[i]);
++			if (orion_read(GPIO_IO_CONF) & (1 << i)) {
++				printk("input, active %s, level %s, edge %s\n",
++				((orion_read(GPIO_IN_POL) >> i) & 1) ? "low" : "high",
++				((orion_read(GPIO_LEVEL_MASK) >> i) & 1) ? "enabled" : "masked",
++				((orion_read(GPIO_EDGE_MASK) >> i) & 1) ? "enabled" : "masked");
++			} else {
++				printk("output, val=%d\n", (orion_read(GPIO_OUT) >> i) & 1);
++			}
++		}
++	}
++
++	printk(KERN_DEBUG "MPP_0_7_CTRL (0x%08x) = 0x%08x\n",
++				MPP_0_7_CTRL, orion_read(MPP_0_7_CTRL));
++	printk(KERN_DEBUG "MPP_8_15_CTRL (0x%08x) = 0x%08x\n",
++				MPP_8_15_CTRL, orion_read(MPP_8_15_CTRL));
++	printk(KERN_DEBUG "MPP_16_19_CTRL (0x%08x) = 0x%08x\n",
++				MPP_16_19_CTRL, orion_read(MPP_16_19_CTRL));
++	printk(KERN_DEBUG "MPP_DEV_CTRL (0x%08x) = 0x%08x\n",
++				MPP_DEV_CTRL, orion_read(MPP_DEV_CTRL));
++	printk(KERN_DEBUG "GPIO_OUT (0x%08x) = 0x%08x\n",
++				GPIO_OUT, orion_read(GPIO_OUT));
++	printk(KERN_DEBUG "GPIO_IO_CONF (0x%08x) = 0x%08x\n",
++				GPIO_IO_CONF, orion_read(GPIO_IO_CONF));
++	printk(KERN_DEBUG "GPIO_BLINK_EN (0x%08x) = 0x%08x\n",
++				GPIO_BLINK_EN, orion_read(GPIO_BLINK_EN));
++	printk(KERN_DEBUG "GPIO_IN_POL (0x%08x) = 0x%08x\n",
++				GPIO_IN_POL, orion_read(GPIO_IN_POL));
++	printk(KERN_DEBUG "GPIO_DATA_IN (0x%08x) = 0x%08x\n",
++				GPIO_DATA_IN, orion_read(GPIO_DATA_IN));
++	printk(KERN_DEBUG "GPIO_LEVEL_MASK (0x%08x) = 0x%08x\n",
++				GPIO_LEVEL_MASK, orion_read(GPIO_LEVEL_MASK));
++	printk(KERN_DEBUG "GPIO_EDGE_CAUSE (0x%08x) = 0x%08x\n",
++				GPIO_EDGE_CAUSE, orion_read(GPIO_EDGE_CAUSE));
++	printk(KERN_DEBUG "GPIO_EDGE_MASK (0x%08x) = 0x%08x\n",
++				GPIO_EDGE_MASK, orion_read(GPIO_EDGE_MASK));
++}
+diff --git a/arch/arm/mach-orion/irq.c b/arch/arm/mach-orion/irq.c
+new file mode 100644
+index 0000000..df7e12a
+--- /dev/null
++++ b/arch/arm/mach-orion/irq.c
+@@ -0,0 +1,241 @@
++/*
++ * arch/arm/mach-orion/irq.c
++ *
++ * Core IRQ functions for Marvell Orion System On Chip
++ *
++ * Maintainer: Tzachi Perelstein <tzachi at marvell.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/irq.h>
++#include <asm/gpio.h>
++#include <asm/arch/orion.h>
++#include "common.h"
++
++/*****************************************************************************
++ * Orion GPIO IRQ
++ *
++ * GPIO_IN_POL register controlls whether GPIO_DATA_IN will hold the same
++ * value of the line or the opposite value.
++ *
++ * Level IRQ handlers: DATA_IN is used directly as cause register.
++ *                     Interrupt are masked by LEVEL_MASK registers.
++ * Edge IRQ handlers:  Change in DATA_IN are latched in EDGE_CAUSE.
++ *                     Interrupt are masked by EDGE_MASK registers.
++ * Both-edge handlers: Similar to regular Edge handlers, but also swaps
++ *                     the polarity to catch the next line transaction.
++ *                     This is a race condition that might not perfectly
++ *                     work on some use cases.
++ *
++ * Every eight GPIO lines are grouped (OR'ed) before going up to main
++ * cause register.
++ *
++ *                    EDGE  cause    mask
++ *        data-in   /--------| |-----| |----\
++ *     -----| |-----                         ---- to main cause reg
++ *           X      \----------------| |----/
++ *        polarity    LEVEL          mask
++ *
++ ****************************************************************************/
++static void orion_gpio_irq_ack(u32 irq)
++{
++	int pin = irq_to_gpio(irq);
++	if (irq_desc[irq].status & IRQ_LEVEL)
++		/*
++		 * Mask bit for level interrupt
++		 */
++		orion_clrbits(GPIO_LEVEL_MASK, 1 << pin);
++	else
++		/*
++		 * Clear casue bit for egde interrupt
++		 */
++		orion_clrbits(GPIO_EDGE_CAUSE, 1 << pin);
++}
++
++static void orion_gpio_irq_mask(u32 irq)
++{
++	int pin = irq_to_gpio(irq);
++	if (irq_desc[irq].status & IRQ_LEVEL)
++		orion_clrbits(GPIO_LEVEL_MASK, 1 << pin);
++	else
++		orion_clrbits(GPIO_EDGE_MASK, 1 << pin);
++}
++
++static void orion_gpio_irq_unmask(u32 irq)
++{
++	int pin = irq_to_gpio(irq);
++	if (irq_desc[irq].status & IRQ_LEVEL)
++		orion_setbits(GPIO_LEVEL_MASK, 1 << pin);
++	else
++		orion_setbits(GPIO_EDGE_MASK, 1 << pin);
++}
++
++static int orion_gpio_set_irq_type(u32 irq, u32 type)
++{
++	int pin = irq_to_gpio(irq);
++	struct irq_desc *desc;
++
++	if ((orion_read(GPIO_IO_CONF) & (1 << pin)) == 0) {
++		printk(KERN_ERR "orion_gpio_set_irq_type failed "
++				"(irq %d, pin %d).\n", irq, pin);
++		return -EINVAL;
++	}
++
++	desc = irq_desc + irq;
++
++	switch (type) {
++	case IRQT_HIGH:
++		desc->handle_irq = handle_level_irq;
++		desc->status |= IRQ_LEVEL;
++		orion_clrbits(GPIO_IN_POL, (1 << pin));
++		break;
++	case IRQT_LOW:
++		desc->handle_irq = handle_level_irq;
++		desc->status |= IRQ_LEVEL;
++		orion_setbits(GPIO_IN_POL, (1 << pin));
++		break;
++	case IRQT_RISING:
++		desc->handle_irq = handle_edge_irq;
++		desc->status &= ~IRQ_LEVEL;
++		orion_clrbits(GPIO_IN_POL, (1 << pin));
++		break;
++	case IRQT_FALLING:
++		desc->handle_irq = handle_edge_irq;
++		desc->status &= ~IRQ_LEVEL;
++		orion_setbits(GPIO_IN_POL, (1 << pin));
++		break;
++	case IRQT_BOTHEDGE:
++		desc->handle_irq = handle_edge_irq;
++		desc->status &= ~IRQ_LEVEL;
++		/*
++		 * set initial polarity based on current input level
++		 */
++		if ((orion_read(GPIO_IN_POL) ^ orion_read(GPIO_DATA_IN))
++		    & (1 << pin))
++			orion_setbits(GPIO_IN_POL, (1 << pin)); /* falling */
++		else
++			orion_clrbits(GPIO_IN_POL, (1 << pin)); /* rising */
++
++		break;
++	default:
++		printk(KERN_ERR "failed to set irq=%d (type=%d)\n", irq, type);
++		return -EINVAL;
++	}
++
++	desc->status &= ~IRQ_TYPE_SENSE_MASK;
++	desc->status |= type & IRQ_TYPE_SENSE_MASK;
++
++	return 0;
++}
++
++static struct irq_chip orion_gpio_irq_chip = {
++	.name		= "Orion-IRQ-GPIO",
++	.ack		= orion_gpio_irq_ack,
++	.mask		= orion_gpio_irq_mask,
++	.unmask		= orion_gpio_irq_unmask,
++	.set_type	= orion_gpio_set_irq_type,
++};
++
++static void orion_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
++{
++	u32 cause, offs, pin;
++
++	BUG_ON(irq < IRQ_ORION_GPIO_0_7 || irq > IRQ_ORION_GPIO_24_31);
++	offs = (irq - IRQ_ORION_GPIO_0_7) * 8;
++	cause = (orion_read(GPIO_DATA_IN) & orion_read(GPIO_LEVEL_MASK)) |
++		(orion_read(GPIO_EDGE_CAUSE) & orion_read(GPIO_EDGE_MASK));
++
++	for (pin = offs; pin < offs + 8; pin++) {
++		if (cause & (1 << pin)) {
++			irq = gpio_to_irq(pin);
++			desc = irq_desc + irq;
++			if ((desc->status & IRQ_TYPE_SENSE_MASK) == IRQT_BOTHEDGE) {
++				/* Swap polarity (race with GPIO line) */
++				u32 polarity = orion_read(GPIO_IN_POL);
++				polarity ^= 1 << pin;
++				orion_write(GPIO_IN_POL, polarity);
++			}
++			desc_handle_irq(irq, desc);
++		}
++	}
++}
++
++static void __init orion_init_gpio_irq(void)
++{
++	int i;
++	struct irq_desc *desc;
++
++	/*
++	 * Mask and clear GPIO IRQ interrupts
++	 */
++	orion_write(GPIO_LEVEL_MASK, 0x0);
++	orion_write(GPIO_EDGE_MASK, 0x0);
++	orion_write(GPIO_EDGE_CAUSE, 0x0);
++
++	/*
++	 * Register chained level handlers for GPIO IRQs by default.
++	 * User can use set_type() if he wants to use edge types handlers.
++	 */
++	for (i = IRQ_ORION_GPIO_START; i < NR_IRQS; i++) {
++		set_irq_chip(i, &orion_gpio_irq_chip);
++		set_irq_handler(i, handle_level_irq);
++		desc = irq_desc + i;
++		desc->status |= IRQ_LEVEL;
++		set_irq_flags(i, IRQF_VALID);
++	}
++	set_irq_chained_handler(IRQ_ORION_GPIO_0_7, orion_gpio_irq_handler);
++	set_irq_chained_handler(IRQ_ORION_GPIO_8_15, orion_gpio_irq_handler);
++	set_irq_chained_handler(IRQ_ORION_GPIO_16_23, orion_gpio_irq_handler);
++	set_irq_chained_handler(IRQ_ORION_GPIO_24_31, orion_gpio_irq_handler);
++}
++
++/*****************************************************************************
++ * Orion Main IRQ
++ ****************************************************************************/
++static void orion_main_irq_mask(u32 irq)
++{
++	orion_clrbits(MAIN_IRQ_MASK, 1 << irq);
++}
++
++static void orion_main_irq_unmask(u32 irq)
++{
++	orion_setbits(MAIN_IRQ_MASK, 1 << irq);
++}
++
++static struct irq_chip orion_main_irq_chip = {
++	.name		= "Orion-IRQ-Main",
++	.ack		= orion_main_irq_mask,
++	.mask		= orion_main_irq_mask,
++	.unmask		= orion_main_irq_unmask,
++};
++
++static void __init orion_init_main_irq(void)
++{
++	int i;
++
++	/*
++	 * Mask and clear Main IRQ interrupts
++	 */
++	orion_write(MAIN_IRQ_MASK, 0x0);
++	orion_write(MAIN_IRQ_CAUSE, 0x0);
++
++	/*
++	 * Register level handler for Main IRQs
++	 */
++	for (i = 0; i < IRQ_ORION_GPIO_START; i++) {
++		set_irq_chip(i, &orion_main_irq_chip);
++		set_irq_handler(i, handle_level_irq);
++		set_irq_flags(i, IRQF_VALID);
++	}
++}
++
++void __init orion_init_irq(void)
++{
++	orion_init_main_irq();
++	orion_init_gpio_irq();
++}
+diff --git a/arch/arm/mach-orion/kurobox_pro-setup.c b/arch/arm/mach-orion/kurobox_pro-setup.c
+new file mode 100644
+index 0000000..2d812ed
+--- /dev/null
++++ b/arch/arm/mach-orion/kurobox_pro-setup.c
+@@ -0,0 +1,234 @@
++/*
++ * arch/arm/mach-orion/kurobox_pro-setup.c
++ *
++ * Maintainer: Ronen Shitrit <rshitrit at marvell.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/platform_device.h>
++#include <linux/pci.h>
++#include <linux/irq.h>
++#include <linux/mtd/physmap.h>
++#include <linux/mtd/nand.h>
++#include <linux/mv643xx_eth.h>
++#include <linux/i2c.h>
++#include <asm/mach-types.h>
++#include <asm/gpio.h>
++#include <asm/mach/arch.h>
++#include <asm/mach/pci.h>
++#include <asm/arch/orion.h>
++#include <asm/arch/platform.h>
++#include "common.h"
++
++/*****************************************************************************
++ * KUROBOX-PRO Info
++ ****************************************************************************/
++
++/*
++ * 256K NOR flash Device bus boot chip select
++ */
++
++#define KUROBOX_PRO_NOR_BOOT_BASE	0xf4000000
++#define KUROBOX_PRO_NOR_BOOT_SIZE	SZ_256K
++
++/*
++ * 256M NAND flash on Device bus chip select 1
++ */
++
++#define KUROBOX_PRO_NAND_BASE		0xfc000000
++#define KUROBOX_PRO_NAND_SIZE		SZ_2M
++
++/*****************************************************************************
++ * 256MB NAND Flash on Device bus CS0
++ ****************************************************************************/
++
++static struct mtd_partition kurobox_pro_nand_parts[] = {
++	{
++		.name	= "uImage",
++		.offset	= 0,
++		.size	= SZ_4M,
++	},
++	{
++		.name	= "rootfs",
++		.offset	= SZ_4M,
++		.size	= SZ_64M,
++	},
++	{
++		.name	= "extra",
++		.offset	= SZ_4M + SZ_64M,
++		.size	= SZ_256M - (SZ_4M + SZ_64M),
++	},
++};
++
++static struct resource kurobox_pro_nand_resource = {
++	.flags		= IORESOURCE_MEM,
++	.start		= KUROBOX_PRO_NAND_BASE,
++	.end		= KUROBOX_PRO_NAND_BASE + KUROBOX_PRO_NAND_SIZE - 1,
++};
++
++static struct orion_nand_data kurobox_pro_nand_data = {
++	.parts		= kurobox_pro_nand_parts,
++	.nr_parts	= ARRAY_SIZE(kurobox_pro_nand_parts),
++	.cle		= 0,
++	.ale		= 1,
++	.width		= 8,
++};
++
++static struct platform_device kurobox_pro_nand_flash = {
++	.name		= "orion_nand",
++	.id		= -1,
++	.dev		= {
++		.platform_data	= &kurobox_pro_nand_data,
++	},
++	.resource	= &kurobox_pro_nand_resource,
++	.num_resources	= 1,
++};
++
++/*****************************************************************************
++ * 256KB NOR Flash on BOOT Device
++ ****************************************************************************/
++
++static struct physmap_flash_data kurobox_pro_nor_flash_data = {
++	.width		= 1,
++};
++
++static struct resource kurobox_pro_nor_flash_resource = {
++	.flags			= IORESOURCE_MEM,
++	.start			= KUROBOX_PRO_NOR_BOOT_BASE,
++	.end			= KUROBOX_PRO_NOR_BOOT_BASE + KUROBOX_PRO_NOR_BOOT_SIZE - 1,
++};
++
++static struct platform_device kurobox_pro_nor_flash = {
++	.name			= "physmap-flash",
++	.id			= 0,
++	.dev		= {
++		.platform_data	= &kurobox_pro_nor_flash_data,
++	},
++	.num_resources		= 1,
++	.resource		= &kurobox_pro_nor_flash_resource,
++};
++
++/*****************************************************************************
++ * PCI
++ ****************************************************************************/
++
++static int __init kurobox_pro_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
++{
++	/*
++	 * PCI isn't used on the Kuro
++	 */
++	if (dev->bus->number == orion_pcie_local_bus_nr())
++		return IRQ_ORION_PCIE0_INT;
++	else
++		printk(KERN_ERR "kurobox_pro_pci_map_irq failed, unknown bus\n");
++
++	return -1;
++}
++
++static struct hw_pci kurobox_pro_pci __initdata = {
++	.nr_controllers	= 1,
++	.swizzle	= pci_std_swizzle,
++	.setup		= orion_pci_sys_setup,
++	.scan		= orion_pci_sys_scan_bus,
++	.map_irq	= kurobox_pro_pci_map_irq,
++};
++
++static int __init kurobox_pro_pci_init(void)
++{
++	if (machine_is_kurobox_pro())
++		pci_common_init(&kurobox_pro_pci);
++
++	return 0;
++}
++
++subsys_initcall(kurobox_pro_pci_init);
++
++/*****************************************************************************
++ * Ethernet
++ ****************************************************************************/
++
++static struct mv643xx_eth_platform_data kurobox_pro_eth_data = {
++	.phy_addr	= 8,
++	.force_phy_addr = 1,
++};
++
++/*****************************************************************************
++ * RTC 5C372a on I2C bus
++ ****************************************************************************/
++static struct i2c_board_info __initdata kurobox_pro_i2c_rtc = {
++       .driver_name    = "rtc-rs5c372",
++       .type           = "rs5c372a",
++       .addr           = 0x32,
++};
++
++/*****************************************************************************
++ * General Setup
++ ****************************************************************************/
++
++static struct platform_device *kurobox_pro_devices[] __initdata = {
++	&kurobox_pro_nor_flash,
++	&kurobox_pro_nand_flash,
++};
++
++static void __init kurobox_pro_init(void)
++{
++	/*
++	 * Setup basic Orion functions. Need to be called early.
++	 */
++	orion_init();
++
++	/*
++	 * Setup the CPU address decode windows for our devices
++	 */
++	orion_setup_cpu_win(ORION_DEV_BOOT, KUROBOX_PRO_NOR_BOOT_BASE,
++				KUROBOX_PRO_NOR_BOOT_SIZE, -1);
++	orion_setup_cpu_win(ORION_DEV0,	KUROBOX_PRO_NAND_BASE,
++				KUROBOX_PRO_NAND_SIZE, -1);
++	/*
++	 * Open a special address decode windows for the PCIE WA.
++	 */
++	orion_write(ORION_REGS_BASE | 0x20074, ORION_PCIE_WA_BASE);
++	orion_write(ORION_REGS_BASE | 0x20070, (0x7941 |
++		(((ORION_PCIE_WA_SIZE >> 16) - 1)) << 16));
++
++	/*
++	 * Setup Multiplexing Pins --
++	 * MPP[0-1] Not used
++	 * MPP[2] GPIO Micon
++	 * MPP[3] GPIO RTC
++	 * MPP[4-5] Not used
++	 * MPP[6] Nand Flash REn
++	 * MPP[7] Nand Flash WEn
++	 * MPP[8-11] Not used
++	 * MPP[12] SATA 0 presence Indication
++	 * MPP[13] SATA 1 presence Indication
++	 * MPP[14] SATA 0 active Indication
++	 * MPP[15] SATA 1 active indication
++	 * MPP[16-19] Not used
++	 */
++	orion_write(MPP_0_7_CTRL, 0x44220003);
++	orion_write(MPP_8_15_CTRL, 0x55550000);
++	orion_write(MPP_16_19_CTRL, 0x0);
++
++	orion_gpio_set_valid_pins(0x0000000c);
++
++	platform_add_devices(kurobox_pro_devices, ARRAY_SIZE(kurobox_pro_devices));
++	i2c_register_board_info(0, &kurobox_pro_i2c_rtc, 1);
++	orion_eth_init(&kurobox_pro_eth_data);
++}
++
++MACHINE_START(KUROBOX_PRO, "Buffalo/Revogear Kurobox Pro")
++	/* Maintainer: Ronen Shitrit <rshitrit at marvell.com> */
++	.phys_io	= ORION_REGS_BASE,
++	.io_pg_offst	= ((ORION_REGS_BASE) >> 18) & 0xFFFC,
++	.boot_params	= 0x00000100,
++	.init_machine	= kurobox_pro_init,
++	.map_io		= orion_map_io,
++	.init_irq	= orion_init_irq,
++	.timer		= &orion_timer,
++MACHINE_END
+diff --git a/arch/arm/mach-orion/pci.c b/arch/arm/mach-orion/pci.c
+new file mode 100644
+index 0000000..0498d7c
+--- /dev/null
++++ b/arch/arm/mach-orion/pci.c
+@@ -0,0 +1,557 @@
++/*
++ * arch/arm/mach-orion/pci.c
++ *
++ * PCI and PCIE functions for Marvell Orion System On Chip
++ *
++ * Maintainer: Tzachi Perelstein <tzachi at marvell.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/pci.h>
++#include <asm/mach/pci.h>
++#include "common.h"
++
++/*****************************************************************************
++ * Orion has one PCIE controller and one PCI controller.
++ *
++ * Note1: The local PCIE bus number is '0'. The local PCI bus number
++ * follows the scanned PCIE bridged busses, if any.
++ *
++ * Note2: It is possible for PCI/PCIE agents to access many subsystem's
++ * space, by configuring BARs and Address Decode Windows, e.g. flashes on
++ * device bus, Orion registers, etc. However this code only enable the
++ * access to DDR banks.
++ ****************************************************************************/
++
++
++/*****************************************************************************
++ * PCIE controller
++ ****************************************************************************/
++#define PCIE_CTRL		ORION_PCIE_REG(0x1a00)
++#define PCIE_STAT		ORION_PCIE_REG(0x1a04)
++#define PCIE_DEV_ID		ORION_PCIE_REG(0x0000)
++#define PCIE_CMD_STAT		ORION_PCIE_REG(0x0004)
++#define PCIE_DEV_REV		ORION_PCIE_REG(0x0008)
++#define PCIE_MASK		ORION_PCIE_REG(0x1910)
++#define PCIE_CONF_ADDR		ORION_PCIE_REG(0x18f8)
++#define PCIE_CONF_DATA		ORION_PCIE_REG(0x18fc)
++
++/*
++ * PCIE_STAT bits
++ */
++#define PCIE_STAT_LINK_DOWN		1
++#define PCIE_STAT_BUS_OFFS		8
++#define PCIE_STAT_BUS_MASK		(0xff << PCIE_STAT_BUS_OFFS)
++#define PCIE_STAT_DEV_OFFS		20
++#define PCIE_STAT_DEV_MASK		(0x1f << PCIE_STAT_DEV_OFFS)
++
++/*
++ * PCIE_CONF_ADDR bits
++ */
++#define PCIE_CONF_REG(r)		((((r) & 0xf00) << 24) | ((r) & 0xfc))
++#define PCIE_CONF_FUNC(f)		(((f) & 0x3) << 8)
++#define PCIE_CONF_DEV(d)		(((d) & 0x1f) << 11)
++#define PCIE_CONF_BUS(b)		(((b) & 0xff) << 16)
++#define PCIE_CONF_ADDR_EN		(1 << 31)
++
++/*
++ * PCIE config cycles are done by programming the PCIE_CONF_ADDR register
++ * and then reading the PCIE_CONF_DATA register. Need to make sure these
++ * transactions are atomic.
++ */
++static DEFINE_SPINLOCK(orion_pcie_lock);
++
++void orion_pcie_id(u32 *dev, u32 *rev)
++{
++	*dev = orion_read(PCIE_DEV_ID) >> 16;
++	*rev = orion_read(PCIE_DEV_REV) & 0xff;
++}
++
++u32 orion_pcie_local_bus_nr(void)
++{
++	u32 stat = orion_read(PCIE_STAT);
++	return((stat & PCIE_STAT_BUS_MASK) >> PCIE_STAT_BUS_OFFS);
++}
++
++static u32 orion_pcie_local_dev_nr(void)
++{
++	u32 stat = orion_read(PCIE_STAT);
++	return((stat & PCIE_STAT_DEV_MASK) >> PCIE_STAT_DEV_OFFS);
++}
++
++static u32 orion_pcie_no_link(void)
++{
++	u32 stat = orion_read(PCIE_STAT);
++	return(stat & PCIE_STAT_LINK_DOWN);
++}
++
++static void orion_pcie_set_bus_nr(int nr)
++{
++	orion_clrbits(PCIE_STAT, PCIE_STAT_BUS_MASK);
++	orion_setbits(PCIE_STAT, nr << PCIE_STAT_BUS_OFFS);
++}
++
++static void orion_pcie_master_slave_enable(void)
++{
++	orion_setbits(PCIE_CMD_STAT, PCI_COMMAND_MASTER |
++					  PCI_COMMAND_IO |
++					  PCI_COMMAND_MEMORY);
++}
++
++static void orion_pcie_enable_interrupts(void)
++{
++	/*
++	 * Enable interrupts lines
++	 * INTA[24] INTB[25] INTC[26] INTD[27]
++	 */
++	orion_setbits(PCIE_MASK, 0xf<<24);
++}
++
++static int orion_pcie_valid_config(u32 bus, u32 dev)
++{
++	/*
++	 * Don't go out when trying to access --
++	 * 1. our own device
++	 * 2. where there's no device connected (no link)
++	 * 3. nonexisting devices on local bus
++	 */
++
++	if ((orion_pcie_local_bus_nr() == bus) &&
++	   (orion_pcie_local_dev_nr() == dev))
++		return 0;
++
++	if (orion_pcie_no_link())
++		return 0;
++
++	if (bus == orion_pcie_local_bus_nr())
++		if (((orion_pcie_local_dev_nr() == 0) && (dev != 1)) ||
++		   ((orion_pcie_local_dev_nr() != 0) && (dev != 0)))
++		return 0;
++
++	return 1;
++}
++
++static int orion_pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where,
++						int size, u32 *val)
++{
++	unsigned long flags;
++	unsigned int dev, rev, pcie_addr;
++
++	if (orion_pcie_valid_config(bus->number, PCI_SLOT(devfn)) == 0) {
++		*val = 0xffffffff;
++		return PCIBIOS_DEVICE_NOT_FOUND;
++	}
++
++	spin_lock_irqsave(&orion_pcie_lock, flags);
++
++	orion_write(PCIE_CONF_ADDR, PCIE_CONF_BUS(bus->number) |
++			PCIE_CONF_DEV(PCI_SLOT(devfn)) |
++			PCIE_CONF_FUNC(PCI_FUNC(devfn)) |
++			PCIE_CONF_REG(where) | PCIE_CONF_ADDR_EN);
++
++	orion_pcie_id(&dev, &rev);
++	if (dev == MV88F5181_DEV_ID || dev == MV88F5182_DEV_ID) {
++		/* extended register space */
++		pcie_addr = ORION_PCIE_WA_BASE;
++		pcie_addr |= PCIE_CONF_BUS(bus->number) |
++			PCIE_CONF_DEV(PCI_SLOT(devfn)) |
++			PCIE_CONF_FUNC(PCI_FUNC(devfn)) |
++			PCIE_CONF_REG(where);
++		*val = orion_read(pcie_addr);
++	} else
++		*val = orion_read(PCIE_CONF_DATA);
++
++	if (size == 1)
++		*val = (*val >> (8*(where & 0x3))) & 0xff;
++	else if (size == 2)
++		*val = (*val >> (8*(where & 0x3))) & 0xffff;
++
++	spin_unlock_irqrestore(&orion_pcie_lock, flags);
++
++	return PCIBIOS_SUCCESSFUL;
++}
++
++
++static int orion_pcie_wr_conf(struct pci_bus *bus, u32 devfn, int where,
++						int size, u32 val)
++{
++	unsigned long flags;
++	int ret;
++
++	if (orion_pcie_valid_config(bus->number, PCI_SLOT(devfn)) == 0)
++		return PCIBIOS_DEVICE_NOT_FOUND;
++
++	spin_lock_irqsave(&orion_pcie_lock, flags);
++
++	ret = PCIBIOS_SUCCESSFUL;
++
++	orion_write(PCIE_CONF_ADDR, PCIE_CONF_BUS(bus->number) |
++			PCIE_CONF_DEV(PCI_SLOT(devfn)) |
++			PCIE_CONF_FUNC(PCI_FUNC(devfn)) |
++			PCIE_CONF_REG(where) | PCIE_CONF_ADDR_EN);
++
++	if (size == 4) {
++		__raw_writel(val, PCIE_CONF_DATA);
++	} else if (size == 2) {
++		__raw_writew(val, PCIE_CONF_DATA + (where & 0x3));
++	} else if (size == 1) {
++		__raw_writeb(val, PCIE_CONF_DATA + (where & 0x3));
++	} else {
++		ret = PCIBIOS_BAD_REGISTER_NUMBER;
++	}
++
++	spin_unlock_irqrestore(&orion_pcie_lock, flags);
++
++	return ret;
++}
++
++struct pci_ops orion_pcie_ops = {
++	.read = orion_pcie_rd_conf,
++	.write = orion_pcie_wr_conf,
++};
++
++
++static int orion_pcie_setup(struct pci_sys_data *sys)
++{
++	struct resource *res;
++
++	/*
++	 * Master + Slave enable
++	 */
++	orion_pcie_master_slave_enable();
++
++	/*
++	 * Enable interrupts lines A-D
++	 */
++	orion_pcie_enable_interrupts();
++
++	/*
++	 * Request resource
++	 */
++	res = kzalloc(sizeof(struct resource) * 2, GFP_KERNEL);
++	if (!res)
++		panic("orion_pci_setup unable to alloc resources");
++
++	/*
++	 * IORESOURCE_IO
++	 */
++	res[0].name = "PCI-EX I/O Space";
++	res[0].flags = IORESOURCE_IO;
++	res[0].start = ORION_PCIE_IO_REMAP;
++	res[0].end = res[0].start + ORION_PCIE_IO_SIZE - 1;
++	if (request_resource(&ioport_resource, &res[0]))
++		panic("Request PCIE IO resource failed\n");
++	sys->resource[0] = &res[0];
++
++	/*
++	 * IORESOURCE_MEM
++	 */
++	res[1].name = "PCI-EX Memory Space";
++	res[1].flags = IORESOURCE_MEM;
++	res[1].start = ORION_PCIE_MEM_BASE;
++	res[1].end = res[1].start + ORION_PCIE_MEM_SIZE - 1;
++	if (request_resource(&iomem_resource, &res[1]))
++		panic("Request PCIE Memory resource failed\n");
++	sys->resource[1] = &res[1];
++
++	sys->resource[2] = NULL;
++	sys->io_offset = 0;
++
++	return 1;
++}
++
++/*****************************************************************************
++ * PCI controller
++ ****************************************************************************/
++#define PCI_MODE		ORION_PCI_REG(0xd00)
++#define PCI_CMD			ORION_PCI_REG(0xc00)
++#define PCI_P2P_CONF		ORION_PCI_REG(0x1d14)
++#define PCI_CONF_ADDR		ORION_PCI_REG(0xc78)
++#define PCI_CONF_DATA		ORION_PCI_REG(0xc7c)
++
++/*
++ * PCI_MODE bits
++ */
++#define PCI_MODE_64BIT			(1 << 2)
++#define PCI_MODE_PCIX			((1 << 4) | (1 << 5))
++
++/*
++ * PCI_CMD bits
++ */
++#define PCI_CMD_HOST_REORDER		(1 << 29)
++
++/*
++ * PCI_P2P_CONF bits
++ */
++#define PCI_P2P_BUS_OFFS		16
++#define PCI_P2P_BUS_MASK		(0xff << PCI_P2P_BUS_OFFS)
++#define PCI_P2P_DEV_OFFS		24
++#define PCI_P2P_DEV_MASK		(0x1f << PCI_P2P_DEV_OFFS)
++
++/*
++ * PCI_CONF_ADDR bits
++ */
++#define PCI_CONF_REG(reg)		((reg) & 0xfc)
++#define PCI_CONF_FUNC(func)		(((func) & 0x3) << 8)
++#define PCI_CONF_DEV(dev)		(((dev) & 0x1f) << 11)
++#define PCI_CONF_BUS(bus)		(((bus) & 0xff) << 16)
++#define PCI_CONF_ADDR_EN		(1 << 31)
++
++/*
++ * Internal configuration space
++ */
++#define PCI_CONF_FUNC_STAT_CMD		0
++#define PCI_CONF_REG_STAT_CMD		4
++#define PCIX_STAT			0x64
++#define PCIX_STAT_BUS_OFFS		8
++#define PCIX_STAT_BUS_MASK		(0xff << PCIX_STAT_BUS_OFFS)
++
++/*
++ * PCI config cycles are done by programming the PCI_CONF_ADDR register
++ * and then reading the PCI_CONF_DATA register. Need to make sure these
++ * transactions are atomic.
++ */
++static DEFINE_SPINLOCK(orion_pci_lock);
++
++u32 orion_pci_local_bus_nr(void)
++{
++	u32 conf = orion_read(PCI_P2P_CONF);
++	return((conf & PCI_P2P_BUS_MASK) >> PCI_P2P_BUS_OFFS);
++}
++
++u32 orion_pci_local_dev_nr(void)
++{
++	u32 conf = orion_read(PCI_P2P_CONF);
++	return((conf & PCI_P2P_DEV_MASK) >> PCI_P2P_DEV_OFFS);
++}
++
++int orion_pci_hw_rd_conf(u32 bus, u32 dev, u32 func,
++					u32 where, u32 size, u32 *val)
++{
++	unsigned long flags;
++	spin_lock_irqsave(&orion_pci_lock, flags);
++
++	orion_write(PCI_CONF_ADDR, PCI_CONF_BUS(bus) |
++			PCI_CONF_DEV(dev) | PCI_CONF_REG(where) |
++			PCI_CONF_FUNC(func) | PCI_CONF_ADDR_EN);
++
++	*val = orion_read(PCI_CONF_DATA);
++
++	if (size == 1)
++		*val = (*val >> (8*(where & 0x3))) & 0xff;
++	else if (size == 2)
++		*val = (*val >> (8*(where & 0x3))) & 0xffff;
++
++	spin_unlock_irqrestore(&orion_pci_lock, flags);
++
++	return PCIBIOS_SUCCESSFUL;
++}
++
++int orion_pci_hw_wr_conf(u32 bus, u32 dev, u32 func,
++					u32 where, u32 size, u32 val)
++{
++	unsigned long flags;
++	int ret = PCIBIOS_SUCCESSFUL;
++
++	spin_lock_irqsave(&orion_pci_lock, flags);
++
++	orion_write(PCI_CONF_ADDR, PCI_CONF_BUS(bus) |
++			PCI_CONF_DEV(dev) | PCI_CONF_REG(where) |
++			PCI_CONF_FUNC(func) | PCI_CONF_ADDR_EN);
++
++	if (size == 4) {
++		__raw_writel(val, PCI_CONF_DATA);
++	} else if (size == 2) {
++		__raw_writew(val, PCI_CONF_DATA + (where & 0x3));
++	} else if (size == 1) {
++		__raw_writeb(val, PCI_CONF_DATA + (where & 0x3));
++	} else {
++		ret = PCIBIOS_BAD_REGISTER_NUMBER;
++	}
++
++	spin_unlock_irqrestore(&orion_pci_lock, flags);
++
++	return ret;
++}
++
++static int orion_pci_rd_conf(struct pci_bus *bus, u32 devfn,
++				int where, int size, u32 *val)
++{
++	/*
++	 * Don't go out for local device
++	 */
++	if ((orion_pci_local_bus_nr() == bus->number) &&
++	   (orion_pci_local_dev_nr() == PCI_SLOT(devfn))) {
++		*val = 0xffffffff;
++		return PCIBIOS_DEVICE_NOT_FOUND;
++	}
++
++	return orion_pci_hw_rd_conf(bus->number, PCI_SLOT(devfn),
++					PCI_FUNC(devfn), where, size, val);
++}
++
++static int orion_pci_wr_conf(struct pci_bus *bus, u32 devfn,
++				int where, int size, u32 val)
++{
++	/*
++	 * Don't go out for local device
++	 */
++	if ((orion_pci_local_bus_nr() == bus->number) &&
++	   (orion_pci_local_dev_nr() == PCI_SLOT(devfn)))
++		return PCIBIOS_DEVICE_NOT_FOUND;
++
++	return orion_pci_hw_wr_conf(bus->number, PCI_SLOT(devfn),
++					PCI_FUNC(devfn), where, size, val);
++}
++
++struct pci_ops orion_pci_ops = {
++	.read = orion_pci_rd_conf,
++	.write = orion_pci_wr_conf,
++};
++
++static void orion_pci_set_bus_nr(int nr)
++{
++	u32 p2p = orion_read(PCI_P2P_CONF);
++
++	if (orion_read(PCI_MODE) & PCI_MODE_PCIX) {
++		/*
++		 * PCI-X mode
++		 */
++		u32 pcix_status, bus, dev;
++		bus = (p2p & PCI_P2P_BUS_MASK) >> PCI_P2P_BUS_OFFS;
++		dev = (p2p & PCI_P2P_DEV_MASK) >> PCI_P2P_DEV_OFFS;
++		orion_pci_hw_rd_conf(bus, dev, 0, PCIX_STAT, 4, &pcix_status);
++		pcix_status &= ~PCIX_STAT_BUS_MASK;
++		pcix_status |= (nr << PCIX_STAT_BUS_OFFS);
++		orion_pci_hw_wr_conf(bus, dev, 0, PCIX_STAT, 4, pcix_status);
++	} else {
++		/*
++		 * PCI Conventional mode
++		 */
++		p2p &= ~PCI_P2P_BUS_MASK;
++		p2p |= (nr << PCI_P2P_BUS_OFFS);
++		orion_write(PCI_P2P_CONF, p2p);
++	}
++}
++
++static void orion_pci_master_slave_enable(void)
++{
++	u32 bus_nr, dev_nr, func, reg, val;
++
++	bus_nr = orion_pci_local_bus_nr();
++	dev_nr = orion_pci_local_dev_nr();
++	func = PCI_CONF_FUNC_STAT_CMD;
++	reg = PCI_CONF_REG_STAT_CMD;
++	orion_pci_hw_rd_conf(bus_nr, dev_nr, func, reg, 4, &val);
++	val |= (PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
++	orion_pci_hw_wr_conf(bus_nr, dev_nr, func, reg, 4, val | 0x7);
++}
++
++static int orion_pci_setup(struct pci_sys_data *sys)
++{
++	struct resource *res;
++
++	/*
++	 * Master + Slave enable
++	 */
++	orion_pci_master_slave_enable();
++
++	/*
++	 * Force ordering
++	 */
++	orion_setbits(PCI_CMD, PCI_CMD_HOST_REORDER);
++
++	/*
++	 * Request resources
++	 */
++	res = kzalloc(sizeof(struct resource) * 2, GFP_KERNEL);
++	if (!res)
++		panic("orion_pci_setup unable to alloc resources");
++
++	/*
++	 * IORESOURCE_IO
++	 */
++	res[0].name = "PCI I/O Space";
++	res[0].flags = IORESOURCE_IO;
++	res[0].start = ORION_PCI_IO_REMAP;
++	res[0].end = res[0].start + ORION_PCI_IO_SIZE - 1;
++	if (request_resource(&ioport_resource, &res[0]))
++		panic("Request PCI IO resource failed\n");
++	sys->resource[0] = &res[0];
++
++	/*
++	 * IORESOURCE_MEM
++	 */
++	res[1].name = "PCI Memory Space";
++	res[1].flags = IORESOURCE_MEM;
++	res[1].start = ORION_PCI_MEM_BASE;
++	res[1].end = res[1].start + ORION_PCI_MEM_SIZE - 1;
++	if (request_resource(&iomem_resource, &res[1]))
++		panic("Request PCI Memory resource failed\n");
++	sys->resource[1] = &res[1];
++
++	sys->resource[2] = NULL;
++	sys->io_offset = 0;
++
++	return 1;
++}
++
++
++/*****************************************************************************
++ * General PCIE + PCI
++ ****************************************************************************/
++int orion_pci_sys_setup(int nr, struct pci_sys_data *sys)
++{
++	int ret = 0;
++
++	if (nr == 0) {
++		/*
++		 * PCIE setup
++		 */
++		orion_pcie_set_bus_nr(0);
++		ret = orion_pcie_setup(sys);
++	} else if (nr == 1) {
++		/*
++		 * PCI setup
++		 */
++		ret = orion_pci_setup(sys);
++	}
++
++	return ret;
++}
++
++struct pci_bus *orion_pci_sys_scan_bus(int nr, struct pci_sys_data *sys)
++{
++	struct pci_ops *ops;
++	struct pci_bus *bus;
++
++
++	if (nr == 0) {
++		u32 pci_bus;
++		/*
++		 * PCIE scan
++		 */
++		ops = &orion_pcie_ops;
++		bus = pci_scan_bus(sys->busnr, ops, sys);
++		/*
++		 * Set local PCI bus number to follow PCIE bridges (if any)
++		 */
++		pci_bus	= bus->number + bus->subordinate - bus->secondary + 1;
++		orion_pci_set_bus_nr(pci_bus);
++	} else if (nr == 1) {
++		/*
++		 * PCI scan
++		 */
++		ops = &orion_pci_ops;
++		bus = pci_scan_bus(sys->busnr, ops, sys);
++	} else {
++		BUG();
++		bus = NULL;
++	}
++
++	return bus;
++}
+diff --git a/arch/arm/mach-orion/rd88f5182-setup.c b/arch/arm/mach-orion/rd88f5182-setup.c
+new file mode 100644
+index 0000000..026d743
+--- /dev/null
++++ b/arch/arm/mach-orion/rd88f5182-setup.c
+@@ -0,0 +1,306 @@
++/*
++ * arch/arm/mach-orion/rd88f5182-setup.c
++ *
++ * Marvell Orion-NAS Reference Design Setup
++ *
++ * Maintainer: Ronen Shitrit <rshitrit at marvell.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/platform_device.h>
++#include <linux/pci.h>
++#include <linux/irq.h>
++#include <linux/mtd/physmap.h>
++#include <linux/mv643xx_eth.h>
++#include <linux/i2c.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 <asm/arch/orion.h>
++#include <asm/arch/platform.h>
++#include "common.h"
++
++/*****************************************************************************
++ * RD-88F5182 Info
++ ****************************************************************************/
++
++/*
++ * 512K NOR flash Device bus boot chip select
++ */
++
++#define RD88F5182_NOR_BOOT_BASE		0xf4000000
++#define RD88F5182_NOR_BOOT_SIZE		SZ_512K
++
++/*
++ * 16M NOR flash on Device bus chip select 1
++ */
++
++#define RD88F5182_NOR_BASE		0xfc000000
++#define RD88F5182_NOR_SIZE		SZ_16M
++
++/*
++ * PCI
++ */
++
++#define RD88F5182_PCI_SLOT0_OFFS	7
++#define RD88F5182_PCI_SLOT0_IRQ_A_PIN	7
++#define RD88F5182_PCI_SLOT0_IRQ_B_PIN	6
++
++/*
++ * GPIO Debug LED
++ */
++
++#define RD88F5182_GPIO_DBG_LED		0
++
++/*****************************************************************************
++ * 16M NOR Flash on Device bus CS1
++ ****************************************************************************/
++
++static struct physmap_flash_data rd88f5182_nor_flash_data = {
++	.width		= 1,
++};
++
++static struct resource rd88f5182_nor_flash_resource = {
++	.flags			= IORESOURCE_MEM,
++	.start			= RD88F5182_NOR_BASE,
++	.end			= RD88F5182_NOR_BASE + RD88F5182_NOR_SIZE - 1,
++};
++
++static struct platform_device rd88f5182_nor_flash = {
++	.name			= "physmap-flash",
++	.id			= 0,
++	.dev		= {
++		.platform_data	= &rd88f5182_nor_flash_data,
++	},
++	.num_resources		= 1,
++	.resource		= &rd88f5182_nor_flash_resource,
++};
++
++#ifdef CONFIG_LEDS
++
++/*****************************************************************************
++ * Use GPIO debug led as CPU active indication
++ ****************************************************************************/
++
++static void rd88f5182_dbgled_event(led_event_t evt)
++{
++	int val;
++
++	if (evt == led_idle_end)
++		val = 1;
++	else if (evt == led_idle_start)
++		val = 0;
++	else
++		return;
++
++	gpio_set_value(RD88F5182_GPIO_DBG_LED, val);
++}
++
++static int __init rd88f5182_dbgled_init(void)
++{
++	int pin;
++
++	if (machine_is_rd88f5182()) {
++		pin = RD88F5182_GPIO_DBG_LED;
++
++		if (gpio_request(pin, "DBGLED") == 0) {
++			if (gpio_direction_output(pin, 0) != 0) {
++				printk(KERN_ERR "rd88f5182_dbgled_init failed "
++						"to set output pin %d\n", pin);
++				gpio_free(pin);
++				return 0;
++			}
++		} else {
++			printk(KERN_ERR "rd88f5182_dbgled_init failed "
++					"to request gpio %d\n", pin);
++			return 0;
++		}
++
++		leds_event = rd88f5182_dbgled_event;
++	}
++	return 0;
++}
++
++__initcall(rd88f5182_dbgled_init);
++
++#endif
++
++/*****************************************************************************
++ * PCI
++ ****************************************************************************/
++
++void __init rd88f5182_pci_preinit(void)
++{
++	int pin;
++
++	/*
++	 * Configure PCI GPIO IRQ pins
++	 */
++	pin = RD88F5182_PCI_SLOT0_IRQ_A_PIN;
++	if (gpio_request(pin, "PCI IntA") == 0) {
++		if (gpio_direction_input(pin) == 0) {
++			set_irq_type(gpio_to_irq(pin), IRQT_LOW);
++		} else {
++			printk(KERN_ERR "rd88f5182_pci_preinit faield to "
++					"set_irq_type pin %d\n", pin);
++			gpio_free(pin);
++		}
++	} else {
++		printk(KERN_ERR "rd88f5182_pci_preinit failed to request gpio %d\n", pin);
++	}
++
++	pin = RD88F5182_PCI_SLOT0_IRQ_B_PIN;
++	if (gpio_request(pin, "PCI IntB") == 0) {
++		if (gpio_direction_input(pin) == 0) {
++			set_irq_type(gpio_to_irq(pin), IRQT_LOW);
++		} else {
++			printk(KERN_ERR "rd88f5182_pci_preinit faield to "
++					"set_irq_type pin %d\n", pin);
++			gpio_free(pin);
++		}
++	} else {
++		printk(KERN_ERR "rd88f5182_pci_preinit failed to gpio_request %d\n", pin);
++	}
++}
++
++static int __init rd88f5182_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
++{
++	/*
++	 * PCI-E isn't used on the RD2
++	 */
++	if (dev->bus->number == orion_pcie_local_bus_nr())
++		return IRQ_ORION_PCIE0_INT;
++
++	/*
++	 * PCI IRQs are connected via GPIOs
++	 */
++	switch (slot - RD88F5182_PCI_SLOT0_OFFS) {
++	case 0:
++		if (pin == 1)
++			return gpio_to_irq(RD88F5182_PCI_SLOT0_IRQ_A_PIN);
++		else
++			return gpio_to_irq(RD88F5182_PCI_SLOT0_IRQ_B_PIN);
++	default:
++		return -1;
++	}
++}
++
++static struct hw_pci rd88f5182_pci __initdata = {
++	.nr_controllers	= 2,
++	.preinit	= rd88f5182_pci_preinit,
++	.swizzle	= pci_std_swizzle,
++	.setup		= orion_pci_sys_setup,
++	.scan		= orion_pci_sys_scan_bus,
++	.map_irq	= rd88f5182_pci_map_irq,
++};
++
++static int __init rd88f5182_pci_init(void)
++{
++	if (machine_is_rd88f5182())
++		pci_common_init(&rd88f5182_pci);
++
++	return 0;
++}
++
++subsys_initcall(rd88f5182_pci_init);
++
++/*****************************************************************************
++ * Ethernet
++ ****************************************************************************/
++
++static struct mv643xx_eth_platform_data rd88f5182_eth_data = {
++	.phy_addr	= 8,
++	.force_phy_addr = 1,
++};
++
++/*****************************************************************************
++ * RTC DS1338 on I2C bus
++ ****************************************************************************/
++static struct i2c_board_info __initdata rd88f5182_i2c_rtc = {
++	.driver_name	= "rtc-ds1307",
++	.type		= "ds1338",
++	.addr		= 0x68,
++};
++
++/*****************************************************************************
++ * General Setup
++ ****************************************************************************/
++
++static struct platform_device *rd88f5182_devices[] __initdata = {
++	&rd88f5182_nor_flash,
++};
++
++static void __init rd88f5182_init(void)
++{
++	/*
++	 * Setup basic Orion functions. Need to be called early.
++	 */
++	orion_init();
++
++	/*
++	 * Setup the CPU address decode windows for our devices
++	 */
++	orion_setup_cpu_win(ORION_DEV_BOOT, RD88F5182_NOR_BOOT_BASE,
++				RD88F5182_NOR_BOOT_SIZE, -1);
++	orion_setup_cpu_win(ORION_DEV1, RD88F5182_NOR_BASE,
++				RD88F5182_NOR_SIZE, -1);
++
++	/*
++	 * Open a special address decode windows for the PCIE WA.
++	 */
++	orion_write(ORION_REGS_BASE | 0x20074, ORION_PCIE_WA_BASE);
++	orion_write(ORION_REGS_BASE | 0x20070, (0x7941 |
++		(((ORION_PCIE_WA_SIZE >> 16) - 1)) << 16));
++
++	/*
++	 * Setup Multiplexing Pins --
++	 * MPP[0] Debug Led (GPIO - Out)
++	 * MPP[1] Debug Led (GPIO - Out)
++	 * MPP[2] N/A
++	 * MPP[3] RTC_Int (GPIO - In)
++	 * MPP[4] GPIO
++	 * MPP[5] GPIO
++	 * MPP[6] PCI_intA (GPIO - In)
++	 * MPP[7] PCI_intB (GPIO - In)
++	 * MPP[8-11] N/A
++	 * MPP[12] SATA 0 presence Indication
++	 * MPP[13] SATA 1 presence Indication
++	 * MPP[14] SATA 0 active Indication
++	 * MPP[15] SATA 1 active indication
++	 * MPP[16-19] Not used
++	 * MPP[20] PCI Clock to MV88F5182
++	 * MPP[21] PCI Clock to mini PCI CON11
++	 * MPP[22] USB 0 over current indication
++	 * MPP[23] USB 1 over current indication
++	 * MPP[24] USB 1 over current enable
++	 * MPP[25] USB 0 over current enable
++	 */
++
++	orion_write(MPP_0_7_CTRL, 0x00000003);
++	orion_write(MPP_8_15_CTRL, 0x55550000);
++	orion_write(MPP_16_19_CTRL, 0x5555);
++
++	orion_gpio_set_valid_pins(0x000000fb);
++
++	platform_add_devices(rd88f5182_devices, ARRAY_SIZE(rd88f5182_devices));
++	i2c_register_board_info(0, &rd88f5182_i2c_rtc, 1);
++	orion_eth_init(&rd88f5182_eth_data);
++}
++
++MACHINE_START(RD88F5182, "Marvell Orion-NAS Reference Design")
++	/* Maintainer: Ronen Shitrit <rshitrit at marvell.com> */
++	.phys_io	= ORION_REGS_BASE,
++	.io_pg_offst	= ((ORION_REGS_BASE) >> 18) & 0xFFFC,
++	.boot_params	= 0x00000100,
++	.init_machine	= rd88f5182_init,
++	.map_io		= orion_map_io,
++	.init_irq	= orion_init_irq,
++	.timer		= &orion_timer,
++MACHINE_END
+diff --git a/arch/arm/mach-orion/time.c b/arch/arm/mach-orion/time.c
+new file mode 100644
+index 0000000..bd4262d
+--- /dev/null
++++ b/arch/arm/mach-orion/time.c
+@@ -0,0 +1,181 @@
++/*
++ * arch/arm/mach-orion/time.c
++ *
++ * Core time functions for Marvell Orion System On Chip
++ *
++ * Maintainer: Tzachi Perelstein <tzachi at marvell.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/clockchips.h>
++#include <linux/interrupt.h>
++#include <linux/irq.h>
++#include <asm/mach/time.h>
++#include <asm/arch/orion.h>
++#include "common.h"
++
++/*
++ * Timer0: clock_event_device, Tick.
++ * Timer1: clocksource, Free running.
++ * WatchDog: Not used.
++ *
++ * Timers are counting down.
++ */
++#define CLOCKEVENT	0
++#define CLOCKSOURCE	1
++
++/*
++ * Timers bits
++ */
++#define BRIDGE_INT_TIMER(x)	(1 << ((x) + 1))
++#define TIMER_EN(x)		(1 << ((x) * 2))
++#define TIMER_RELOAD_EN(x)	(1 << (((x) * 2) + 1))
++#define BRIDGE_INT_TIMER_WD	(1 << 3)
++#define TIMER_WD_EN		(1 << 4)
++#define TIMER_WD_RELOAD_EN	(1 << 5)
++
++static cycle_t orion_clksrc_read(void)
++{
++	return (0xffffffff - orion_read(TIMER_VAL(CLOCKSOURCE)));
++}
++
++static struct clocksource orion_clksrc = {
++	.name		= "orion_clocksource",
++	.shift		= 20,
++	.rating		= 300,
++	.read		= orion_clksrc_read,
++	.mask		= CLOCKSOURCE_MASK(32),
++	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
++};
++
++static int
++orion_clkevt_next_event(unsigned long delta, struct clock_event_device *dev)
++{
++	unsigned long flags;
++
++	if (delta == 0)
++		return -ETIME;
++
++	local_irq_save(flags);
++
++	/*
++	 * Clear and enable timer interrupt bit
++	 */
++	orion_write(BRIDGE_CAUSE, ~BRIDGE_INT_TIMER(CLOCKEVENT));
++	orion_setbits(BRIDGE_MASK, BRIDGE_INT_TIMER(CLOCKEVENT));
++
++	/*
++	 * Setup new timer value
++	 */
++	orion_write(TIMER_VAL(CLOCKEVENT), delta);
++
++	/*
++	 * Disable auto reload and kickoff the timer
++	 */
++	orion_clrbits(TIMER_CTRL, TIMER_RELOAD_EN(CLOCKEVENT));
++	orion_setbits(TIMER_CTRL, TIMER_EN(CLOCKEVENT));
++
++	local_irq_restore(flags);
++
++	return 0;
++}
++
++static void
++orion_clkevt_mode(enum clock_event_mode mode, struct clock_event_device *dev)
++{
++	unsigned long flags;
++
++	local_irq_save(flags);
++
++	if (mode == CLOCK_EVT_MODE_PERIODIC) {
++		/*
++		 * Setup latch cycles in timer and enable reload interrupt.
++		 */
++		orion_write(TIMER_VAL_RELOAD(CLOCKEVENT), LATCH);
++		orion_write(TIMER_VAL(CLOCKEVENT), LATCH);
++		orion_setbits(BRIDGE_MASK, BRIDGE_INT_TIMER(CLOCKEVENT));
++		orion_setbits(TIMER_CTRL, TIMER_RELOAD_EN(CLOCKEVENT) |
++					  TIMER_EN(CLOCKEVENT));
++	} else {
++		/*
++		 * Disable timer and interrupt
++		 */
++		orion_clrbits(BRIDGE_MASK, BRIDGE_INT_TIMER(CLOCKEVENT));
++		orion_write(BRIDGE_CAUSE, ~BRIDGE_INT_TIMER(CLOCKEVENT));
++		orion_clrbits(TIMER_CTRL, TIMER_RELOAD_EN(CLOCKEVENT) |
++					  TIMER_EN(CLOCKEVENT));
++	}
++
++	local_irq_restore(flags);
++}
++
++static struct clock_event_device orion_clkevt = {
++	.name		= "orion_tick",
++	.features	= CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
++	.shift		= 32,
++	.rating		= 300,
++	.cpumask	= CPU_MASK_CPU0,
++	.set_next_event	= orion_clkevt_next_event,
++	.set_mode	= orion_clkevt_mode,
++};
++
++static irqreturn_t orion_timer_interrupt(int irq, void *dev_id)
++{
++	/*
++	 * Clear cause bit and do event
++	 */
++	orion_write(BRIDGE_CAUSE, ~BRIDGE_INT_TIMER(CLOCKEVENT));
++	orion_clkevt.event_handler(&orion_clkevt);
++	return IRQ_HANDLED;
++}
++
++static struct irqaction orion_timer_irq = {
++	.name		= "orion_tick",
++	.flags		= IRQF_DISABLED | IRQF_TIMER,
++	.handler	= orion_timer_interrupt
++};
++
++static void orion_timer_init(void)
++{
++	/*
++	 * Setup clocksource free running timer (no interrupt on reload)
++	 */
++	orion_write(TIMER_VAL(CLOCKSOURCE), 0xffffffff);
++	orion_write(TIMER_VAL_RELOAD(CLOCKSOURCE), 0xffffffff);
++	orion_clrbits(BRIDGE_MASK, BRIDGE_INT_TIMER(CLOCKSOURCE));
++	orion_setbits(TIMER_CTRL, TIMER_RELOAD_EN(CLOCKSOURCE) |
++				  TIMER_EN(CLOCKSOURCE));
++
++	/*
++	 * Register clocksource
++	 */
++	orion_clksrc.mult =
++		clocksource_hz2mult(CLOCK_TICK_RATE, orion_clksrc.shift);
++
++	clocksource_register(&orion_clksrc);
++
++	/*
++	 * Connect and enable tick handler
++	 */
++	setup_irq(IRQ_ORION_BRIDGE, &orion_timer_irq);
++
++	/*
++	 * Register clockevent
++	 */
++	orion_clkevt.mult =
++		div_sc(CLOCK_TICK_RATE, NSEC_PER_SEC, orion_clkevt.shift);
++	orion_clkevt.max_delta_ns =
++		clockevent_delta2ns(0xfffffffe, &orion_clkevt);
++	orion_clkevt.min_delta_ns =
++		clockevent_delta2ns(1, &orion_clkevt);
++
++	clockevents_register_device(&orion_clkevt);
++}
++
++struct sys_timer orion_timer = {
++	.init = orion_timer_init,
++};
+diff --git a/arch/arm/mach-orion/ts209-setup.c b/arch/arm/mach-orion/ts209-setup.c
+new file mode 100644
+index 0000000..e3e930e
+--- /dev/null
++++ b/arch/arm/mach-orion/ts209-setup.c
+@@ -0,0 +1,335 @@
++/*
++ * QNAP TS-109/TS-209 Board Setup
++ *
++ * Maintainer: Byron Bradley <byron.bbradley at 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/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/mtd/nand.h>
++#include <linux/mv643xx_eth.h>
++#include <linux/gpio_keys.h>
++#include <linux/input.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 <asm/arch/orion.h>
++#include <asm/arch/platform.h>
++#include "common.h"
++
++#define QNAP_TS209_NOR_BOOT_BASE 0xf4000000
++#define QNAP_TS209_NOR_BOOT_SIZE SZ_8M
++
++/****************************************************************************
++ * 8MiB NOR flash. The struct mtd_partition is not in the same order as the
++ *     partitions on the device because we want to keep compatability with
++ *     existing QNAP firmware.
++ *
++ * Layout as used by QNAP:
++ *  [2] 0x00000000-0x00200000 : "Kernel"
++ *  [3] 0x00200000-0x00600000 : "RootFS1"
++ *  [4] 0x00600000-0x00700000 : "RootFS2"
++ *  [6] 0x00700000-0x00760000 : "NAS Config" (read-only)
++ *  [5] 0x00760000-0x00780000 : "U-Boot Config"
++ *  [1] 0x00780000-0x00800000 : "U-Boot" (read-only)
++ ***************************************************************************/
++static struct mtd_partition qnap_ts209_partitions[] = {
++	{
++		.name       = "U-Boot",
++		.size       = 0x00080000,
++		.offset     = 0x00780000,
++		.mask_flags = MTD_WRITEABLE,
++	}, {
++		.name   = "Kernel",
++		.size   = 0x00200000,
++		.offset = 0,
++	}, {
++		.name   = "RootFS1",
++		.size   = 0x00400000,
++		.offset = 0x00200000,
++	}, {
++		.name   = "RootFS2",
++		.size   = 0x00100000,
++		.offset = 0x00600000,
++	}, {
++		.name   = "U-Boot Config",
++		.size   = 0x00020000,
++		.offset = 0x00760000,
++	}, {
++		.name       = "NAS Config",
++		.size       = 0x00060000,
++		.offset     = 0x00700000,
++		.mask_flags = MTD_WRITEABLE,
++	}
++};
++
++static struct physmap_flash_data qnap_ts209_nor_flash_data = {
++	.width    = 1,
++	.parts    = qnap_ts209_partitions,
++	.nr_parts = ARRAY_SIZE(qnap_ts209_partitions)
++};
++
++static struct resource qnap_ts209_nor_flash_resource = {
++	.flags = IORESOURCE_MEM,
++	.start = QNAP_TS209_NOR_BOOT_BASE,
++	.end   = QNAP_TS209_NOR_BOOT_BASE + QNAP_TS209_NOR_BOOT_SIZE - 1,
++};
++
++static struct platform_device qnap_ts209_nor_flash = {
++	.name          = "physmap-flash",
++	.id            = 0,
++	.dev           = { .platform_data = &qnap_ts209_nor_flash_data, },
++	.resource      = &qnap_ts209_nor_flash_resource,
++	.num_resources = 1,
++};
++
++/*****************************************************************************
++ * PCI
++ ****************************************************************************/
++
++#define QNAP_TS209_PCI_SLOT0_OFFS	7
++#define QNAP_TS209_PCI_SLOT0_IRQ_PIN	6
++#define QNAP_TS209_PCI_SLOT1_IRQ_PIN	7
++
++void __init qnap_ts209_pci_preinit(void)
++{
++	int pin;
++
++	/*
++	 * Configure PCI GPIO IRQ pins
++	 */
++	pin = QNAP_TS209_PCI_SLOT0_IRQ_PIN;
++	if (gpio_request(pin, "PCI Int1") == 0) {
++		if (gpio_direction_input(pin) == 0) {
++			set_irq_type(gpio_to_irq(pin), IRQT_LOW);
++		} else {
++			printk(KERN_ERR "qnap_ts209_pci_preinit failed to "
++					"set_irq_type pin %d\n", pin);
++			gpio_free(pin);
++		}
++	} else {
++		printk(KERN_ERR "qnap_ts209_pci_preinit failed to gpio_request "
++				"%d\n", pin);
++	}
++
++	pin = QNAP_TS209_PCI_SLOT1_IRQ_PIN;
++	if (gpio_request(pin, "PCI Int2") == 0) {
++		if (gpio_direction_input(pin) == 0) {
++			set_irq_type(gpio_to_irq(pin), IRQT_LOW);
++		} else {
++			printk(KERN_ERR "qnap_ts209_pci_preinit failed "
++					"to set_irq_type pin %d\n", pin);
++			gpio_free(pin);
++		}
++	} else {
++		printk(KERN_ERR "qnap_ts209_pci_preinit failed to gpio_request "
++				"%d\n", pin);
++	}
++}
++
++static int __init qnap_ts209_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
++{
++	/*
++	 * PCIE IRQ is connected internally (not GPIO)
++	 */
++	if (dev->bus->number == orion_pcie_local_bus_nr())
++		return IRQ_ORION_PCIE0_INT;
++
++	/*
++	 * PCI IRQs are connected via GPIOs
++	 */
++	switch (slot - QNAP_TS209_PCI_SLOT0_OFFS) {
++	case 0:
++		return gpio_to_irq(QNAP_TS209_PCI_SLOT0_IRQ_PIN);
++	case 1:
++		return gpio_to_irq(QNAP_TS209_PCI_SLOT1_IRQ_PIN);
++	default:
++		return -1;
++	}
++}
++
++static struct hw_pci qnap_ts209_pci __initdata = {
++	.nr_controllers = 2,
++	.preinit        = qnap_ts209_pci_preinit,
++	.swizzle        = pci_std_swizzle,
++	.setup          = orion_pci_sys_setup,
++	.scan           = orion_pci_sys_scan_bus,
++	.map_irq        = qnap_ts209_pci_map_irq,
++};
++
++static int __init qnap_ts209_pci_init(void)
++{
++	if (machine_is_ts_x09())
++		pci_common_init(&qnap_ts209_pci);
++
++	return 0;
++}
++
++subsys_initcall(qnap_ts209_pci_init);
++
++/*****************************************************************************
++ * Ethernet
++ ****************************************************************************/
++
++static struct mv643xx_eth_platform_data qnap_ts209_eth_data = {
++	.phy_addr       = 8,
++	.force_phy_addr = 1,
++};
++
++/*****************************************************************************
++ * RTC S35390A on I2C bus
++ ****************************************************************************/
++static struct i2c_board_info __initdata qnap_ts209_i2c_rtc = {
++       .driver_name = "rtc-s35390a",
++       .addr        = 0x30,
++};
++
++/****************************************************************************
++ * GPIO Attached Keys
++ *     Power button is attached to the PIC microcontroller
++ ****************************************************************************/
++
++#define QNAP_TS209_GPIO_KEY_MEDIA	1
++#define QNAP_TS209_GPIO_KEY_RESET	2
++
++static struct gpio_keys_button qnap_ts209_buttons[] = {
++	{
++		.code		= KEY_RESTART,
++		.gpio		= QNAP_TS209_GPIO_KEY_MEDIA,
++		.desc		= "USB Copy Button",
++		.active_low	= 1,
++	},
++	{
++		.code		= KEY_POWER,
++		.gpio		= QNAP_TS209_GPIO_KEY_RESET,
++		.desc		= "Reset Button",
++		.active_low	= 1,
++	}
++};
++
++static struct gpio_keys_platform_data qnap_ts209_button_data = {
++	.buttons	= qnap_ts209_buttons,
++	.nbuttons       = ARRAY_SIZE(qnap_ts209_buttons),
++};
++
++static struct platform_device qnap_ts209_button_device = {
++	.name		= "gpio-keys",
++	.id		= -1,
++	.num_resources	= 0,
++	.dev		= { .platform_data  = &qnap_ts209_button_data, },
++};
++
++/*****************************************************************************
++ * General Setup
++ ****************************************************************************/
++
++static struct platform_device *qnap_ts209_devices[] __initdata = {
++	&qnap_ts209_nor_flash,
++	&qnap_ts209_button_device,
++};
++
++/*
++ * QNAP TS-[12]09 specific power off method via UART1-attached PIC
++ */
++
++#define UART1_REG(x)  (UART1_BASE + ((UART_##x) << 2))
++
++static void qnap_ts209_power_off(void)
++{
++	/* 19200 baud divisor */
++	const unsigned divisor = ((ORION_TCLK + (8 * 19200)) / (16 * 19200));
++
++	pr_info("%s: triggering power-off...\n", __func__);
++
++	/* hijack uart1 and reset into sane state (19200,8n1) */
++	orion_write(UART1_REG(LCR), 0x83);
++	orion_write(UART1_REG(DLL), divisor & 0xff);
++	orion_write(UART1_REG(DLM), (divisor >> 8) & 0xff);
++	orion_write(UART1_REG(LCR), 0x03);
++	orion_write(UART1_REG(IER), 0x00);
++	orion_write(UART1_REG(FCR), 0x00);
++	orion_write(UART1_REG(MCR), 0x00);
++
++	/* send the power-off command 'A' to PIC */
++	orion_write(UART1_REG(TX), 'A');
++}
++
++static void __init qnap_ts209_init(void)
++{
++	/*
++	 * Setup basic Orion functions. Need to be called early.
++	 */
++	orion_init();
++
++	/*
++	 * Setup flash mapping
++	 */
++	orion_setup_cpu_win(ORION_DEV_BOOT, QNAP_TS209_NOR_BOOT_BASE,
++			    QNAP_TS209_NOR_BOOT_SIZE, -1);
++
++	/*
++	 * Open a special address decode windows for the PCIE WA.
++	 */
++	orion_write(ORION_REGS_BASE | 0x20074, ORION_PCIE_WA_BASE);
++	orion_write(ORION_REGS_BASE | 0x20070, (0x7941 |
++		(((ORION_PCIE_WA_SIZE >> 16) - 1)) << 16));
++
++	/*
++	 * Setup Multiplexing Pins --
++	 * MPP[0] Reserved
++	 * MPP[1] USB copy button (0 active)
++	 * MPP[2] Load defaults button (0 active)
++	 * MPP[3] GPIO RTC
++	 * MPP[4-5] Reserved
++	 * MPP[6] PCI Int A
++	 * MPP[7] PCI Int B
++	 * MPP[8-11] Reserved
++	 * MPP[12] SATA 0 presence
++	 * MPP[13] SATA 1 presence
++	 * MPP[14] SATA 0 active
++	 * MPP[15] SATA 1 active
++	 * MPP[16] UART1 RXD
++	 * MPP[17] UART1 TXD
++	 * MPP[18] SW_RST (0 active)
++	 * MPP[19] Reserved
++	 * MPP[20] PCI clock 0
++	 * MPP[21] PCI clock 1
++	 * MPP[22] USB 0 over current
++	 * MPP[23-25] Reserved
++	 */
++	orion_write(MPP_0_7_CTRL, 0x3);
++	orion_write(MPP_8_15_CTRL, 0x55550000);
++	orion_write(MPP_16_19_CTRL, 0x5500);
++	orion_gpio_set_valid_pins(0x3cc0fff);
++
++	/* register ts209 specific power-off method */
++	pm_power_off = qnap_ts209_power_off;
++
++	platform_add_devices(qnap_ts209_devices,
++				ARRAY_SIZE(qnap_ts209_devices));
++	i2c_register_board_info(0, &qnap_ts209_i2c_rtc, 1);
++	orion_eth_init(&qnap_ts209_eth_data);
++}
++
++MACHINE_START(TS209, "QNAP TS-109/TS-209")
++	/* Maintainer:  Byron Bradley <byron.bbradley at gmail.com> */
++	.phys_io	= ORION_REGS_BASE,
++	.io_pg_offst	= ((ORION_REGS_BASE) >> 18) & 0xFFFC,
++	.boot_params	= 0x00000100,
++	.init_machine	= qnap_ts209_init,
++	.map_io		= orion_map_io,
++	.init_irq	= orion_init_irq,
++	.timer		= &orion_timer,
++MACHINE_END
+diff --git a/arch/arm/mach-pnx4008/time.c b/arch/arm/mach-pnx4008/time.c
+index 67e05f0..6d4ca8f 100644
+--- a/arch/arm/mach-pnx4008/time.c
++++ b/arch/arm/mach-pnx4008/time.c
+@@ -51,8 +51,6 @@ static irqreturn_t pnx4008_timer_interrupt(int irq, void *dev_id)
+ {
+ 	if (__raw_readl(HSTIM_INT) & MATCH0_INT) {
+ 
+-		write_seqlock(&xtime_lock);
+-
+ 		do {
+ 			timer_tick();
+ 
+@@ -73,8 +71,6 @@ static irqreturn_t pnx4008_timer_interrupt(int irq, void *dev_id)
+ 		} while ((signed)
+ 			 (__raw_readl(HSTIM_MATCH0) -
+ 			  __raw_readl(HSTIM_COUNTER)) < 0);
+-
+-		write_sequnlock(&xtime_lock);
+ 	}
+ 
+ 	return IRQ_HANDLED;
+diff --git a/arch/arm/mach-pxa/Kconfig b/arch/arm/mach-pxa/Kconfig
+index 656d496..0908bea 100644
+--- a/arch/arm/mach-pxa/Kconfig
++++ b/arch/arm/mach-pxa/Kconfig
+@@ -51,6 +51,50 @@ config PXA_SHARPSL
+ 	  SL-C3000 (Spitz), SL-C3100 (Borzoi) or SL-C6000x (Tosa)
+ 	  handheld computer.
+ 
++config ARCH_PXA_ESERIES
++	bool "PXA based Toshiba e-series PDAs"
++	select PXA25x
++
++config MACH_E330
++	bool "Toshiba e330"
++	default y
++	depends on ARCH_PXA_ESERIES
++	help
++	  Say Y here if you intend to run this kernel on a Toshiba
++	  e330 family PDA.
++
++config MACH_E740
++	bool "Toshiba e740"
++	default y
++	depends on ARCH_PXA_ESERIES
++	help
++	  Say Y here if you intend to run this kernel on a Toshiba
++	  e740 family PDA.
++
++config MACH_E750
++	bool "Toshiba e750"
++	default y
++	depends on ARCH_PXA_ESERIES
++	help
++	  Say Y here if you intend to run this kernel on a Toshiba
++	  e750 family PDA.
++
++config MACH_E400
++	bool "Toshiba e400"
++	default y
++	depends on ARCH_PXA_ESERIES
++	help
++	  Say Y here if you intend to run this kernel on a Toshiba
++	  e400 family PDA.
++
++config MACH_E800
++	bool "Toshiba e800"
++	default y
++	depends on ARCH_PXA_ESERIES
++	help
++	  Say Y here if you intend to run this kernel on a Toshiba
++	  e800 family PDA.
++
+ config MACH_TRIZEPS4
+ 	bool "Keith und Koep Trizeps4 DIMM-Module"
+ 	select PXA27x
+@@ -59,15 +103,44 @@ config MACH_EM_X270
+ 	bool "CompuLab EM-x270 platform"
+ 	select PXA27x
+ 
++config MACH_COLIBRI
++	bool "Toradex Colibri PX27x"
++	select PXA27x
++
+ config MACH_ZYLONITE
+ 	bool "PXA3xx Development Platform"
+ 	select PXA3xx
+ 
++config MACH_LITTLETON
++	bool "PXA3xx Form Factor Platform (aka Littleton)"
++	select PXA3xx
++	select PXA_SSP
++
+ config MACH_ARMCORE
+ 	bool "CompuLab CM-X270 modules"
+ 	select PXA27x
+ 	select IWMMXT
+ 
++config MACH_MAGICIAN
++	bool "Enable HTC Magician Support"
++	depends on ARCH_PXA
++	select PXA27x
++	select IWMMXT
++
++config MACH_PCM027
++	bool "Phytec phyCORE-PXA270 CPU module (PCM-027)"
++	select PXA27x
++	select IWMMXT
++
++endchoice
++
++choice
++	prompt "Used baseboard"
++	depends on MACH_PCM027
++
++config MACH_PCM990_BASEBOARD
++	bool "PHYTEC PCM-990 development board"
++
+ endchoice
+ 
+ if PXA_SHARPSL
+diff --git a/arch/arm/mach-pxa/Makefile b/arch/arm/mach-pxa/Makefile
+index 4263527..b5c916c 100644
+--- a/arch/arm/mach-pxa/Makefile
++++ b/arch/arm/mach-pxa/Makefile
+@@ -3,7 +3,7 @@
+ #
+ 
+ # Common support (must be linked before board specific support)
+-obj-y				+= clock.o generic.o irq.o dma.o time.o
++obj-y				+= clock.o devices.o generic.o irq.o dma.o time.o
+ obj-$(CONFIG_PXA25x)		+= pxa25x.o
+ obj-$(CONFIG_PXA27x)		+= pxa27x.o
+ obj-$(CONFIG_PXA3xx)		+= pxa3xx.o mfp.o
+@@ -16,18 +16,24 @@ obj-$(CONFIG_MACH_LOGICPD_PXA270) += lpd270.o
+ obj-$(CONFIG_MACH_MAINSTONE)	+= mainstone.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_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
+ 
+ ifeq ($(CONFIG_MACH_ZYLONITE),y)
+   obj-y				+= zylonite.o
+   obj-$(CONFIG_CPU_PXA300)	+= zylonite_pxa300.o
+   obj-$(CONFIG_CPU_PXA320)	+= zylonite_pxa320.o
+ endif
++obj-$(CONFIG_MACH_LITTLETON)	+= littleton.o
+ 
+ obj-$(CONFIG_MACH_ARMCORE)      += cm-x270.o
+ 
+@@ -41,13 +47,10 @@ led-$(CONFIG_MACH_TRIZEPS4)	+= leds-trizeps4.o
+ obj-$(CONFIG_LEDS)		+= $(led-y)
+ 
+ # Misc features
+-obj-$(CONFIG_PM)		+= pm.o sleep.o
++obj-$(CONFIG_PM)		+= pm.o sleep.o standby.o
++obj-$(CONFIG_CPU_FREQ)		+= cpu-pxa.o
+ obj-$(CONFIG_PXA_SSP)		+= ssp.o
+ 
+-ifeq ($(CONFIG_PXA27x),y)
+-obj-$(CONFIG_PM)		+= standby.o
+-endif
+-
+ ifeq ($(CONFIG_PCI),y)
+ obj-$(CONFIG_MACH_ARMCORE) += cm-x270-pci.o
+ endif
+diff --git a/arch/arm/mach-pxa/akita-ioexp.c b/arch/arm/mach-pxa/akita-ioexp.c
+index 12d2fe0..254892a 100644
+--- a/arch/arm/mach-pxa/akita-ioexp.c
++++ b/arch/arm/mach-pxa/akita-ioexp.c
+@@ -29,7 +29,7 @@
+ #define MAX7310_TIMEOUT  0x04
+ 
+ /* Addresses to scan */
+-static unsigned short normal_i2c[] = { 0x18, I2C_CLIENT_END };
++static const unsigned short normal_i2c[] = { 0x18, I2C_CLIENT_END };
+ 
+ /* I2C Magic */
+ I2C_CLIENT_INSMOD;
+diff --git a/arch/arm/mach-pxa/cm-x270.c b/arch/arm/mach-pxa/cm-x270.c
+index 177664c..28cfd71 100644
+--- a/arch/arm/mach-pxa/cm-x270.c
++++ b/arch/arm/mach-pxa/cm-x270.c
+@@ -487,18 +487,15 @@ static int cmx270_mci_init(struct device *dev,
+ 
+ 	/* card detect IRQ on GPIO 83 */
+ 	pxa_gpio_mode(IRQ_TO_GPIO(CMX270_MMC_IRQ));
+-	set_irq_type(CMX270_MMC_IRQ, IRQT_FALLING);
+ 
+ 	err = request_irq(CMX270_MMC_IRQ, cmx270_detect_int,
+ 			  IRQF_DISABLED | IRQF_TRIGGER_FALLING,
+ 			  "MMC card detect", data);
+-	if (err) {
++	if (err)
+ 		printk(KERN_ERR "cmx270_mci_init: MMC/SD: can't"
+ 		       " request MMC card detect IRQ\n");
+-		return -1;
+-	}
+ 
+-	return 0;
++	return err;
+ }
+ 
+ static void cmx270_mci_setpower(struct device *dev, unsigned int vdd)
+@@ -566,7 +563,7 @@ static int cmx270_resume(struct sys_device *dev)
+ }
+ 
+ static struct sysdev_class cmx270_pm_sysclass = {
+-	set_kset_name("pm"),
++	.name = "pm",
+ 	.resume = cmx270_resume,
+ 	.suspend = cmx270_suspend,
+ };
+diff --git a/arch/arm/mach-pxa/colibri.c b/arch/arm/mach-pxa/colibri.c
+new file mode 100644
+index 0000000..6db54e3
+--- /dev/null
++++ b/arch/arm/mach-pxa/colibri.c
+@@ -0,0 +1,134 @@
++/*
++ *  linux/arch/arm/mach-pxa/colibri.c
++ *
++ *  Support for Toradex PXA27x based Colibri module
++ *  Daniel Mack <daniel at caiaq.de>
++ *
++ *  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/platform_device.h>
++#include <linux/sysdev.h>
++#include <linux/interrupt.h>
++#include <linux/bitops.h>
++#include <linux/ioport.h>
++#include <linux/delay.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/partitions.h>
++#include <linux/mtd/physmap.h>
++#include <asm/mach-types.h>
++#include <asm/hardware.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 <asm/mach/flash.h>
++#include <asm/arch/pxa-regs.h>
++#include <asm/arch/colibri.h>
++
++#include "generic.h"
++#include "devices.h"
++
++/*
++ * Flash
++ */
++static struct mtd_partition colibri_partitions[] = {
++	{
++		.name =		"Bootloader",
++		.offset =	0x00000000,
++		.size =		0x00040000,
++		.mask_flags =	MTD_WRITEABLE  /* force read-only */
++	}, {
++		.name =		"Kernel",
++		.offset =	0x00040000,
++		.size =		0x00400000,
++		.mask_flags =	0
++	}, {
++		.name =		"Rootfs",
++		.offset =	0x00440000,
++		.size =		MTDPART_SIZ_FULL,
++		.mask_flags =	0
++	}
++};
++
++static struct physmap_flash_data colibri_flash_data[] = {
++	{
++		.width		= 4,			/* bankwidth in bytes */
++		.parts		= colibri_partitions,
++		.nr_parts	= ARRAY_SIZE(colibri_partitions)
++	}
++};
++
++static struct resource flash_resource = {
++	.start	= PXA_CS0_PHYS,
++	.end	= PXA_CS0_PHYS + SZ_32M - 1,
++	.flags	= IORESOURCE_MEM,
++};
++
++static struct platform_device flash_device = {
++	.name	= "physmap-flash",
++	.id	= 0,
++	.dev 	= {
++		.platform_data = colibri_flash_data,
++	},
++	.resource = &flash_resource,
++	.num_resources = 1,
++};
++
++/*
++ * DM9000 Ethernet
++ */
++static struct resource dm9000_resources[] = {
++	[0] = {
++		.start	= COLIBRI_ETH_PHYS,
++		.end	= COLIBRI_ETH_PHYS + 3,
++		.flags	= IORESOURCE_MEM,
++	},
++	[1] = {
++		.start	= COLIBRI_ETH_PHYS + 4,
++		.end	= COLIBRI_ETH_PHYS + 4 + 500,
++		.flags	= IORESOURCE_MEM,
++	},
++	[2] = {
++		.start	= COLIBRI_ETH_IRQ,
++		.end	= COLIBRI_ETH_IRQ,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device dm9000_device = {
++	.name		= "dm9000",
++	.id		= -1,
++	.num_resources	= ARRAY_SIZE(dm9000_resources),
++	.resource	= dm9000_resources,
++};
++
++static struct platform_device *colibri_devices[] __initdata = {
++	&flash_device,
++	&dm9000_device,
++};
++
++static void __init colibri_init(void)
++{
++	/* DM9000 LAN */
++	pxa_gpio_mode(GPIO78_nCS_2_MD);
++	pxa_gpio_mode(GPIO_DM9000 | GPIO_IN);
++	set_irq_type(COLIBRI_ETH_IRQ, IRQT_FALLING);
++
++	platform_add_devices(colibri_devices, ARRAY_SIZE(colibri_devices));
++}
++
++MACHINE_START(COLIBRI, "Toradex Colibri PXA27x")
++	.phys_io	= 0x40000000,
++	.io_pg_offst	= (io_p2v(0x40000000) >> 18) & 0xfffc,
++	.boot_params	= COLIBRI_SDRAM_BASE + 0x100,
++	.init_machine	= colibri_init,
++	.map_io		= pxa_map_io,
++	.init_irq	= pxa27x_init_irq,
++	.timer		= &pxa_timer,
++MACHINE_END
+diff --git a/arch/arm/mach-pxa/corgi.c b/arch/arm/mach-pxa/corgi.c
+index 2363cc6..9292576 100644
+--- a/arch/arm/mach-pxa/corgi.c
++++ b/arch/arm/mach-pxa/corgi.c
+@@ -21,6 +21,7 @@
+ #include <linux/mmc/host.h>
+ #include <linux/pm.h>
+ #include <linux/backlight.h>
++#include <video/w100fb.h>
+ 
+ #include <asm/setup.h>
+ #include <asm/memory.h>
+@@ -141,6 +142,136 @@ struct corgissp_machinfo corgi_ssp_machinfo = {
+ 
+ 
+ /*
++ * 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,
++	.ext_timing_cntl   = 0x10002a4a,
++	.io_cntl           = 0x7ff87012,
++	.size              = 0x1fffff,
++};
++
++static struct w100_gen_regs corgi_fb_regs = {
++	.lcd_format    = 0x00000003,
++	.lcdd_cntl1    = 0x01CC0000,
++	.lcdd_cntl2    = 0x0003FFFF,
++	.genlcd_cntl1  = 0x00FFFF0D,
++	.genlcd_cntl2  = 0x003F3003,
++	.genlcd_cntl3  = 0x000102aa,
++};
++
++static struct w100_gpio_regs corgi_fb_gpio = {
++	.init_data1   = 0x000000bf,
++	.init_data2   = 0x00000000,
++	.gpio_dir1    = 0x00000000,
++	.gpio_oe1     = 0x03c0feff,
++	.gpio_dir2    = 0x00000000,
++	.gpio_oe2     = 0x00000000,
++};
++
++static struct w100_mode corgi_fb_modes[] = {
++{
++	.xres            = 480,
++	.yres            = 640,
++	.left_margin     = 0x56,
++	.right_margin    = 0x55,
++	.upper_margin    = 0x03,
++	.lower_margin    = 0x00,
++	.crtc_ss         = 0x82360056,
++	.crtc_ls         = 0xA0280000,
++	.crtc_gs         = 0x80280028,
++	.crtc_vpos_gs    = 0x02830002,
++	.crtc_rev        = 0x00400008,
++	.crtc_dclk       = 0xA0000000,
++	.crtc_gclk       = 0x8015010F,
++	.crtc_goe        = 0x80100110,
++	.crtc_ps1_active = 0x41060010,
++	.pll_freq        = 75,
++	.fast_pll_freq   = 100,
++	.sysclk_src      = CLK_SRC_PLL,
++	.sysclk_divider  = 0,
++	.pixclk_src      = CLK_SRC_PLL,
++	.pixclk_divider  = 2,
++	.pixclk_divider_rotated = 6,
++},{
++	.xres            = 240,
++	.yres            = 320,
++	.left_margin     = 0x27,
++	.right_margin    = 0x2e,
++	.upper_margin    = 0x01,
++	.lower_margin    = 0x00,
++	.crtc_ss         = 0x81170027,
++	.crtc_ls         = 0xA0140000,
++	.crtc_gs         = 0xC0140014,
++	.crtc_vpos_gs    = 0x00010141,
++	.crtc_rev        = 0x00400008,
++	.crtc_dclk       = 0xA0000000,
++	.crtc_gclk       = 0x8015010F,
++	.crtc_goe        = 0x80100110,
++	.crtc_ps1_active = 0x41060010,
++	.pll_freq        = 0,
++	.fast_pll_freq   = 0,
++	.sysclk_src      = CLK_SRC_XTAL,
++	.sysclk_divider  = 0,
++	.pixclk_src      = CLK_SRC_XTAL,
++	.pixclk_divider  = 1,
++	.pixclk_divider_rotated = 1,
++},
++
++};
++
++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,
++	.modelist   = &corgi_fb_modes[0],
++	.num_modes  = 2,
++	.gpio       = &corgi_fb_gpio,
++	.xtal_freq  = 12500000,
++	.xtal_dbl   = 0,
++};
++
++static struct resource corgi_fb_resources[] = {
++	[0] = {
++		.start   = 0x08000000,
++		.end     = 0x08ffffff,
++		.flags   = IORESOURCE_MEM,
++	},
++};
++
++static struct platform_device corgifb_device = {
++	.name           = "w100fb",
++	.id             = -1,
++	.num_resources	= ARRAY_SIZE(corgi_fb_resources),
++	.resource	= corgi_fb_resources,
++	.dev            = {
++		.platform_data = &corgi_fb_info,
++		.parent = &corgissp_device.dev,
++	},
++
++};
++
++
++/*
+  * Corgi Backlight Device
+  */
+ static void corgi_bl_kick_battery(void)
+@@ -154,6 +285,21 @@ static void corgi_bl_kick_battery(void)
+ 	}
+ }
+ 
++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,
+@@ -190,9 +336,40 @@ static struct platform_device corgiled_device = {
+ 	.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,
+@@ -202,9 +379,9 @@ static struct resource corgits_resources[] = {
+ };
+ 
+ static struct corgits_machinfo  corgi_ts_machinfo = {
+-	.get_hsync_len   = corgi_get_hsync_len,
+-	.put_hsync       = corgi_put_hsync,
+-	.wait_hsync      = corgi_wait_hsync,
++	.get_hsync_invperiod = corgi_get_hsync_invperiod,
++	.put_hsync           = corgi_put_hsync,
++	.wait_hsync          = corgi_wait_hsync,
+ };
+ 
+ static struct platform_device corgits_device = {
+@@ -242,12 +419,10 @@ static int corgi_mci_init(struct device *dev, irq_handler_t corgi_detect_int, vo
+ 	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) {
++	if (err)
+ 		printk(KERN_ERR "corgi_mci_init: MMC/SD: can't request MMC card detect IRQ\n");
+-		return -1;
+-	}
+ 
+-	return 0;
++	return err;
+ }
+ 
+ static void corgi_mci_setpower(struct device *dev, unsigned int vdd)
+diff --git a/arch/arm/mach-pxa/corgi_lcd.c b/arch/arm/mach-pxa/corgi_lcd.c
+index 365b943..9328df3 100644
+--- a/arch/arm/mach-pxa/corgi_lcd.c
++++ b/arch/arm/mach-pxa/corgi_lcd.c
+@@ -173,7 +173,7 @@ static void lcdtg_set_phadadj(int mode)
+ 
+ static int lcd_inited;
+ 
+-static void lcdtg_hw_init(int mode)
++void corgi_lcdtg_hw_init(int mode)
+ {
+ 	if (!lcd_inited) {
+ 		int comadj;
+@@ -254,7 +254,7 @@ static void lcdtg_hw_init(int mode)
+ 	}
+ }
+ 
+-static void lcdtg_suspend(void)
++void corgi_lcdtg_suspend(void)
+ {
+ 	/* 60Hz x 2 frame = 16.7msec x 2 = 33.4 msec */
+ 	mdelay(34);
+@@ -288,298 +288,3 @@ static void lcdtg_suspend(void)
+ 	lcd_inited = 0;
+ }
+ 
+-
+-/*
+- * Corgi w100 Frame Buffer Device
+- */
+-#ifdef CONFIG_PXA_SHARP_C7xx
+-
+-#include <video/w100fb.h>
+-
+-static void w100_lcdtg_suspend(struct w100fb_par *par)
+-{
+-	lcdtg_suspend();
+-}
+-
+-static void w100_lcdtg_init(struct w100fb_par *par)
+-{
+-	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,
+-	.ext_timing_cntl   = 0x10002a4a,
+-	.io_cntl           = 0x7ff87012,
+-	.size              = 0x1fffff,
+-};
+-
+-static struct w100_gen_regs corgi_fb_regs = {
+-	.lcd_format    = 0x00000003,
+-	.lcdd_cntl1    = 0x01CC0000,
+-	.lcdd_cntl2    = 0x0003FFFF,
+-	.genlcd_cntl1  = 0x00FFFF0D,
+-	.genlcd_cntl2  = 0x003F3003,
+-	.genlcd_cntl3  = 0x000102aa,
+-};
+-
+-static struct w100_gpio_regs corgi_fb_gpio = {
+-	.init_data1   = 0x000000bf,
+-	.init_data2   = 0x00000000,
+-	.gpio_dir1    = 0x00000000,
+-	.gpio_oe1     = 0x03c0feff,
+-	.gpio_dir2    = 0x00000000,
+-	.gpio_oe2     = 0x00000000,
+-};
+-
+-static struct w100_mode corgi_fb_modes[] = {
+-{
+-	.xres            = 480,
+-	.yres            = 640,
+-	.left_margin     = 0x56,
+-	.right_margin    = 0x55,
+-	.upper_margin    = 0x03,
+-	.lower_margin    = 0x00,
+-	.crtc_ss         = 0x82360056,
+-	.crtc_ls         = 0xA0280000,
+-	.crtc_gs         = 0x80280028,
+-	.crtc_vpos_gs    = 0x02830002,
+-	.crtc_rev        = 0x00400008,
+-	.crtc_dclk       = 0xA0000000,
+-	.crtc_gclk       = 0x8015010F,
+-	.crtc_goe        = 0x80100110,
+-	.crtc_ps1_active = 0x41060010,
+-	.pll_freq        = 75,
+-	.fast_pll_freq   = 100,
+-	.sysclk_src      = CLK_SRC_PLL,
+-	.sysclk_divider  = 0,
+-	.pixclk_src      = CLK_SRC_PLL,
+-	.pixclk_divider  = 2,
+-	.pixclk_divider_rotated = 6,
+-},{
+-	.xres            = 240,
+-	.yres            = 320,
+-	.left_margin     = 0x27,
+-	.right_margin    = 0x2e,
+-	.upper_margin    = 0x01,
+-	.lower_margin    = 0x00,
+-	.crtc_ss         = 0x81170027,
+-	.crtc_ls         = 0xA0140000,
+-	.crtc_gs         = 0xC0140014,
+-	.crtc_vpos_gs    = 0x00010141,
+-	.crtc_rev        = 0x00400008,
+-	.crtc_dclk       = 0xA0000000,
+-	.crtc_gclk       = 0x8015010F,
+-	.crtc_goe        = 0x80100110,
+-	.crtc_ps1_active = 0x41060010,
+-	.pll_freq        = 0,
+-	.fast_pll_freq   = 0,
+-	.sysclk_src      = CLK_SRC_XTAL,
+-	.sysclk_divider  = 0,
+-	.pixclk_src      = CLK_SRC_XTAL,
+-	.pixclk_divider  = 1,
+-	.pixclk_divider_rotated = 1,
+-},
+-
+-};
+-
+-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,
+-	.modelist   = &corgi_fb_modes[0],
+-	.num_modes  = 2,
+-	.gpio       = &corgi_fb_gpio,
+-	.xtal_freq  = 12500000,
+-	.xtal_dbl   = 0,
+-};
+-
+-static struct resource corgi_fb_resources[] = {
+-	[0] = {
+-		.start   = 0x08000000,
+-		.end     = 0x08ffffff,
+-		.flags   = IORESOURCE_MEM,
+-	},
+-};
+-
+-struct platform_device corgifb_device = {
+-	.name           = "w100fb",
+-	.id             = -1,
+-	.num_resources	= ARRAY_SIZE(corgi_fb_resources),
+-	.resource	= corgi_fb_resources,
+-	.dev            = {
+- 		.platform_data = &corgi_fb_info,
+- 		.parent = &corgissp_device.dev,
+-	},
+-
+-};
+-#endif
+-
+-
+-/*
+- * Spitz PXA Frame Buffer Device
+- */
+-#ifdef CONFIG_PXA_SHARP_Cxx00
+-
+-#include <asm/arch/pxafb.h>
+-
+-void spitz_lcd_power(int on, struct fb_var_screeninfo *var)
+-{
+-	if (on)
+-		lcdtg_hw_init(var->xres);
+-	else
+-		lcdtg_suspend();
+-}
+-
+-#endif
+-
+-
+-/*
+- * Corgi/Spitz Touchscreen to LCD interface
+- */
+-static unsigned long (*get_hsync_time)(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);
+-}
+-
+-#ifdef CONFIG_PXA_SHARP_C7xx
+-unsigned long corgi_get_hsync_len(void)
+-{
+-	if (!get_hsync_time)
+-		get_hsync_time = symbol_get(w100fb_get_hsynclen);
+-	if (!get_hsync_time)
+-		return 0;
+-
+-	return get_hsync_time(&corgifb_device.dev);
+-}
+-
+-void corgi_put_hsync(void)
+-{
+-	if (get_hsync_time)
+-		symbol_put(w100fb_get_hsynclen);
+-	get_hsync_time = NULL;
+-}
+-
+-void corgi_wait_hsync(void)
+-{
+-	sharpsl_wait_sync(CORGI_GPIO_HSYNC);
+-}
+-#endif
+-
+-#ifdef CONFIG_PXA_SHARP_Cxx00
+-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);
+-}
+-
+-unsigned long spitz_get_hsync_len(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_time)
+-		get_hsync_time = symbol_get(pxafb_get_hsync_time);
+-	if (!get_hsync_time)
+-#endif
+-		return 0;
+-
+-	return pxafb_get_hsync_time(spitz_pxafb_dev);
+-}
+-
+-void spitz_put_hsync(void)
+-{
+-	put_device(spitz_pxafb_dev);
+-	if (get_hsync_time)
+-		symbol_put(pxafb_get_hsync_time);
+-	spitz_pxafb_dev = NULL;
+-	get_hsync_time = NULL;
+-}
+-
+-void spitz_wait_hsync(void)
+-{
+-	sharpsl_wait_sync(SPITZ_GPIO_HSYNC);
+-}
+-#endif
+-
+-/*
+- * Corgi/Spitz Backlight Power
+- */
+-#ifdef CONFIG_PXA_SHARP_C7xx
+-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);
+-}
+-#endif
+-
+-
+-#if defined(CONFIG_MACH_SPITZ) || defined(CONFIG_MACH_BORZOI)
+-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);
+-}
+-#endif
+-
+-#ifdef CONFIG_MACH_AKITA
+-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);
+-}
+-#endif
+diff --git a/arch/arm/mach-pxa/corgi_ssp.c b/arch/arm/mach-pxa/corgi_ssp.c
+index 40dea3d..efba65e 100644
+--- a/arch/arm/mach-pxa/corgi_ssp.c
++++ b/arch/arm/mach-pxa/corgi_ssp.c
+@@ -21,6 +21,7 @@
+ 
+ #include <asm/arch/ssp.h>
+ #include <asm/arch/pxa-regs.h>
++#include <asm/arch/regs-ssp.h>
+ #include "sharpsl.h"
+ 
+ static DEFINE_SPINLOCK(corgi_ssp_lock);
+diff --git a/arch/arm/mach-pxa/cpu-pxa.c b/arch/arm/mach-pxa/cpu-pxa.c
+new file mode 100644
+index 0000000..cbc583b
+--- /dev/null
++++ b/arch/arm/mach-pxa/cpu-pxa.c
+@@ -0,0 +1,294 @@
++/*
++ *  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 <asm/hardware.h>
++#include <asm/arch/pxa-regs.h>
++#include <asm/arch/pxa2xx-regs.h>
++
++#ifdef DEBUG
++static unsigned int freq_debug;
++MODULE_PARM(freq_debug, "i");
++MODULE_PARM_DESC(freq_debug, "Set the debug messages to on=1/off=0");
++#else
++#define freq_debug  0
++#endif
++
++typedef struct {
++	unsigned int khz;
++	unsigned int membus;
++	unsigned int cccr;
++	unsigned int div2;
++} 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 MDREFR_DRI(x)       (((x) * SDRAM_TREF) / (SDRAM_ROWS * 32))
++
++#define CCLKCFG_TURBO       0x1
++#define CCLKCFG_FCS         0x2
++#define PXA25x_MIN_FREQ     99500
++#define PXA25x_MAX_FREQ     398100
++#define MDREFR_DB2_MASK     (MDREFR_K2DB2 | MDREFR_K1DB2)
++#define MDREFR_DRI_MASK     0xFFF
++
++
++/* Use the run mode frequencies for the CPUFREQ_POLICY_PERFORMANCE policy */
++static pxa_freqs_t pxa255_run_freqs[] =
++{
++    /* CPU   MEMBUS  CCCR  DIV2*/
++    { 99500,  99500, 0x121, 1}, /* run= 99, turbo= 99, PXbus=50,  SDRAM=50 */
++    {132700, 132700, 0x123, 1}, /* run=133, turbo=133, PXbus=66,  SDRAM=66 */
++    {199100,  99500, 0x141, 0}, /* run=199, turbo=199, PXbus=99,  SDRAM=99 */
++    {265400, 132700, 0x143, 1}, /* run=265, turbo=265, PXbus=133, SDRAM=66 */
++    {331800, 165900, 0x145, 1}, /* run=331, turbo=331, PXbus=166, SDRAM=83 */
++    {398100,  99500, 0x161, 0}, /* run=398, turbo=398, PXbus=196, SDRAM=99 */
++    {0,}
++};
++#define NUM_RUN_FREQS ARRAY_SIZE(pxa255_run_freqs)
++
++static struct cpufreq_frequency_table pxa255_run_freq_table[NUM_RUN_FREQS+1];
++
++/* Use the turbo mode frequencies for the CPUFREQ_POLICY_POWERSAVE policy */
++static pxa_freqs_t pxa255_turbo_freqs[] =
++{
++    /* CPU   MEMBUS  CCCR  DIV2*/
++    { 99500, 99500,  0x121, 1}, /* run=99,  turbo= 99, PXbus=50, SDRAM=50 */
++    {199100, 99500,  0x221, 0}, /* run=99,  turbo=199, PXbus=50, SDRAM=99 */
++    {298500, 99500,  0x321, 0}, /* run=99,  turbo=287, PXbus=50, SDRAM=99 */
++    {298600, 99500,  0x1c1, 0}, /* run=199, turbo=287, PXbus=99, SDRAM=99 */
++    {398100, 99500,  0x241, 0}, /* run=199, turbo=398, PXbus=99, SDRAM=99 */
++    {0,}
++};
++#define NUM_TURBO_FREQS ARRAY_SIZE(pxa255_turbo_freqs)
++
++static struct cpufreq_frequency_table pxa255_turbo_freq_table[NUM_TURBO_FREQS+1];
++
++extern unsigned get_clk_frequency_khz(int info);
++
++/* find a valid frequency point */
++static int pxa_verify_policy(struct cpufreq_policy *policy)
++{
++	struct cpufreq_frequency_table *pxa_freqs_table;
++	int ret;
++
++	if (policy->policy == CPUFREQ_POLICY_PERFORMANCE) {
++		pxa_freqs_table = pxa255_run_freq_table;
++	} else if (policy->policy == CPUFREQ_POLICY_POWERSAVE) {
++		pxa_freqs_table = pxa255_turbo_freq_table;
++	} else {
++		printk("CPU PXA: Unknown policy found. "
++		       "Using CPUFREQ_POLICY_PERFORMANCE\n");
++		pxa_freqs_table = pxa255_run_freq_table;
++	}
++
++	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 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;
++	int idx;
++	unsigned long flags;
++	unsigned int unused, preset_mdrefr, postset_mdrefr;
++	void *ramstart = phys_to_virt(0xa0000000);
++
++	/* Get the current policy */
++	if (policy->policy == CPUFREQ_POLICY_PERFORMANCE) {
++		pxa_freq_settings = pxa255_run_freqs;
++		pxa_freqs_table   = pxa255_run_freq_table;
++	} else if (policy->policy == CPUFREQ_POLICY_POWERSAVE) {
++		pxa_freq_settings = pxa255_turbo_freqs;
++		pxa_freqs_table   = pxa255_turbo_freq_table;
++	} else {
++		printk("CPU PXA: Unknown policy found. "
++		       "Using CPUFREQ_POLICY_PERFORMANCE\n");
++		pxa_freq_settings = pxa255_run_freqs;
++		pxa_freqs_table   = pxa255_run_freq_table;
++	}
++
++	/* Lookup the next frequency */
++	if (cpufreq_frequency_table_target(policy, pxa_freqs_table,
++	                                   target_freq, relation, &idx)) {
++		return -EINVAL;
++	}
++
++	freqs.old = policy->cur;
++	freqs.new = pxa_freq_settings[idx].khz;
++	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) ?
++		       (pxa_freq_settings[idx].membus / 2000) :
++		       (pxa_freq_settings[idx].membus / 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(pxa_freq_settings[idx].membus)) {
++		preset_mdrefr = (preset_mdrefr & ~MDREFR_DRI_MASK) |
++		                MDREFR_DRI(pxa_freq_settings[idx].membus);
++	}
++	postset_mdrefr = (postset_mdrefr & ~MDREFR_DRI_MASK) |
++		            MDREFR_DRI(pxa_freq_settings[idx].membus);
++
++	/* 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 */
++	CCCR = pxa_freq_settings[idx].cccr;
++
++	asm volatile("							\n\
++		ldr	r4, [%1]		/* load MDREFR */	\n\
++		b	2f						\n\
++		.align	5 						\n\
++1:									\n\
++		str	%4, [%1]		/* preset the MDREFR */	\n\
++		mcr	p14, 0, %2, c6, c0, 0	/* set CCLKCFG[FCS] */	\n\
++		str	%5, [%1]		/* postset the MDREFR */ \n\
++									\n\
++		b	3f						\n\
++2:		b	1b						\n\
++3:		nop							\n\
++	  "
++	  : "=&r" (unused)
++	  : "r" (&MDREFR), "r" (CCLKCFG_TURBO|CCLKCFG_FCS), "r" (ramstart),
++	    "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 int pxa_cpufreq_init(struct cpufreq_policy *policy)
++{
++	int i;
++
++	/* set default policy and cpuinfo */
++	policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
++	policy->policy = CPUFREQ_POLICY_PERFORMANCE;
++	policy->cpuinfo.max_freq = PXA25x_MAX_FREQ;
++	policy->cpuinfo.min_freq = PXA25x_MIN_FREQ;
++	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 the run cpufreq_frequency_table struct */
++	for (i = 0; i < NUM_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 the turbo cpufreq_frequency_table struct */
++	for (i = 0; i < NUM_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;
++
++	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,
++	.name	= "PXA25x",
++};
++
++static int __init pxa_cpu_init(void)
++{
++	int ret = -ENODEV;
++	if (cpu_is_pxa25x())
++		ret = cpufreq_register_driver(&pxa_cpufreq_driver);
++	return ret;
++}
++
++static void __exit pxa_cpu_exit(void)
++{
++	if (cpu_is_pxa25x())
++		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/devices.c b/arch/arm/mach-pxa/devices.c
+new file mode 100644
+index 0000000..50ff453
+--- /dev/null
++++ b/arch/arm/mach-pxa/devices.c
+@@ -0,0 +1,662 @@
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/platform_device.h>
++#include <linux/dma-mapping.h>
++
++#include <asm/arch/gpio.h>
++#include <asm/arch/udc.h>
++#include <asm/arch/pxafb.h>
++#include <asm/arch/mmc.h>
++#include <asm/arch/irda.h>
++#include <asm/arch/i2c.h>
++
++#include "devices.h"
++
++void __init pxa_register_device(struct platform_device *dev, void *data)
++{
++	int ret;
++
++	dev->dev.platform_data = data;
++
++	ret = platform_device_register(dev);
++	if (ret)
++		dev_err(&dev->dev, "unable to register device: %d\n", ret);
++}
++
++static struct resource pxamci_resources[] = {
++	[0] = {
++		.start	= 0x41100000,
++		.end	= 0x41100fff,
++		.flags	= IORESOURCE_MEM,
++	},
++	[1] = {
++		.start	= IRQ_MMC,
++		.end	= IRQ_MMC,
++		.flags	= IORESOURCE_IRQ,
++	},
++	[2] = {
++		.start	= 21,
++		.end	= 21,
++		.flags	= IORESOURCE_DMA,
++	},
++	[3] = {
++		.start	= 22,
++		.end	= 22,
++		.flags	= IORESOURCE_DMA,
++	},
++};
++
++static u64 pxamci_dmamask = 0xffffffffUL;
++
++struct platform_device pxa_device_mci = {
++	.name		= "pxa2xx-mci",
++	.id		= 0,
++	.dev		= {
++		.dma_mask = &pxamci_dmamask,
++		.coherent_dma_mask = 0xffffffff,
++	},
++	.num_resources	= ARRAY_SIZE(pxamci_resources),
++	.resource	= pxamci_resources,
++};
++
++void __init pxa_set_mci_info(struct pxamci_platform_data *info)
++{
++	pxa_register_device(&pxa_device_mci, info);
++}
++
++
++static struct pxa2xx_udc_mach_info pxa_udc_info;
++
++void __init pxa_set_udc_info(struct pxa2xx_udc_mach_info *info)
++{
++	memcpy(&pxa_udc_info, info, sizeof *info);
++}
++
++static struct resource pxa2xx_udc_resources[] = {
++	[0] = {
++		.start	= 0x40600000,
++		.end	= 0x4060ffff,
++		.flags	= IORESOURCE_MEM,
++	},
++	[1] = {
++		.start	= IRQ_USB,
++		.end	= IRQ_USB,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static u64 udc_dma_mask = ~(u32)0;
++
++struct platform_device pxa_device_udc = {
++	.name		= "pxa2xx-udc",
++	.id		= -1,
++	.resource	= pxa2xx_udc_resources,
++	.num_resources	= ARRAY_SIZE(pxa2xx_udc_resources),
++	.dev		=  {
++		.platform_data	= &pxa_udc_info,
++		.dma_mask	= &udc_dma_mask,
++	}
++};
++
++static struct resource pxafb_resources[] = {
++	[0] = {
++		.start	= 0x44000000,
++		.end	= 0x4400ffff,
++		.flags	= IORESOURCE_MEM,
++	},
++	[1] = {
++		.start	= IRQ_LCD,
++		.end	= IRQ_LCD,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static u64 fb_dma_mask = ~(u64)0;
++
++struct platform_device pxa_device_fb = {
++	.name		= "pxa2xx-fb",
++	.id		= -1,
++	.dev		= {
++		.dma_mask	= &fb_dma_mask,
++		.coherent_dma_mask = 0xffffffff,
++	},
++	.num_resources	= ARRAY_SIZE(pxafb_resources),
++	.resource	= pxafb_resources,
++};
++
++void __init set_pxa_fb_info(struct pxafb_mach_info *info)
++{
++	pxa_register_device(&pxa_device_fb, info);
++}
++
++void __init set_pxa_fb_parent(struct device *parent_dev)
++{
++	pxa_device_fb.dev.parent = parent_dev;
++}
++
++static struct resource pxa_resource_ffuart[] = {
++	{
++		.start	= __PREG(FFUART),
++		.end	= __PREG(FFUART) + 35,
++		.flags	= IORESOURCE_MEM,
++	}, {
++		.start	= IRQ_FFUART,
++		.end	= IRQ_FFUART,
++		.flags	= IORESOURCE_IRQ,
++	}
++};
++
++struct platform_device pxa_device_ffuart= {
++	.name		= "pxa2xx-uart",
++	.id		= 0,
++	.resource	= pxa_resource_ffuart,
++	.num_resources	= ARRAY_SIZE(pxa_resource_ffuart),
++};
++
++static struct resource pxa_resource_btuart[] = {
++	{
++		.start	= __PREG(BTUART),
++		.end	= __PREG(BTUART) + 35,
++		.flags	= IORESOURCE_MEM,
++	}, {
++		.start	= IRQ_BTUART,
++		.end	= IRQ_BTUART,
++		.flags	= IORESOURCE_IRQ,
++	}
++};
++
++struct platform_device pxa_device_btuart = {
++	.name		= "pxa2xx-uart",
++	.id		= 1,
++	.resource	= pxa_resource_btuart,
++	.num_resources	= ARRAY_SIZE(pxa_resource_btuart),
++};
++
++static struct resource pxa_resource_stuart[] = {
++	{
++		.start	= __PREG(STUART),
++		.end	= __PREG(STUART) + 35,
++		.flags	= IORESOURCE_MEM,
++	}, {
++		.start	= IRQ_STUART,
++		.end	= IRQ_STUART,
++		.flags	= IORESOURCE_IRQ,
++	}
++};
++
++struct platform_device pxa_device_stuart = {
++	.name		= "pxa2xx-uart",
++	.id		= 2,
++	.resource	= pxa_resource_stuart,
++	.num_resources	= ARRAY_SIZE(pxa_resource_stuart),
++};
++
++static struct resource pxa_resource_hwuart[] = {
++	{
++		.start	= __PREG(HWUART),
++		.end	= __PREG(HWUART) + 47,
++		.flags	= IORESOURCE_MEM,
++	}, {
++		.start	= IRQ_HWUART,
++		.end	= IRQ_HWUART,
++		.flags	= IORESOURCE_IRQ,
++	}
++};
++
++struct platform_device pxa_device_hwuart = {
++	.name		= "pxa2xx-uart",
++	.id		= 3,
++	.resource	= pxa_resource_hwuart,
++	.num_resources	= ARRAY_SIZE(pxa_resource_hwuart),
++};
++
++static struct resource pxai2c_resources[] = {
++	{
++		.start	= 0x40301680,
++		.end	= 0x403016a3,
++		.flags	= IORESOURCE_MEM,
++	}, {
++		.start	= IRQ_I2C,
++		.end	= IRQ_I2C,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++struct platform_device pxa_device_i2c = {
++	.name		= "pxa2xx-i2c",
++	.id		= 0,
++	.resource	= pxai2c_resources,
++	.num_resources	= ARRAY_SIZE(pxai2c_resources),
++};
++
++void __init pxa_set_i2c_info(struct i2c_pxa_platform_data *info)
++{
++	pxa_register_device(&pxa_device_i2c, info);
++}
++
++static struct resource pxai2s_resources[] = {
++	{
++		.start	= 0x40400000,
++		.end	= 0x40400083,
++		.flags	= IORESOURCE_MEM,
++	}, {
++		.start	= IRQ_I2S,
++		.end	= IRQ_I2S,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++struct platform_device pxa_device_i2s = {
++	.name		= "pxa2xx-i2s",
++	.id		= -1,
++	.resource	= pxai2s_resources,
++	.num_resources	= ARRAY_SIZE(pxai2s_resources),
++};
++
++static u64 pxaficp_dmamask = ~(u32)0;
++
++struct platform_device pxa_device_ficp = {
++	.name		= "pxa2xx-ir",
++	.id		= -1,
++	.dev		= {
++		.dma_mask = &pxaficp_dmamask,
++		.coherent_dma_mask = 0xffffffff,
++	},
++};
++
++void __init pxa_set_ficp_info(struct pxaficp_platform_data *info)
++{
++	pxa_register_device(&pxa_device_ficp, info);
++}
++
++struct platform_device pxa_device_rtc = {
++	.name		= "sa1100-rtc",
++	.id		= -1,
++};
++
++#ifdef CONFIG_PXA25x
++
++static u64 pxa25x_ssp_dma_mask = DMA_BIT_MASK(32);
++
++static struct resource pxa25x_resource_ssp[] = {
++	[0] = {
++		.start	= 0x41000000,
++		.end	= 0x4100001f,
++		.flags	= IORESOURCE_MEM,
++	},
++	[1] = {
++		.start	= IRQ_SSP,
++		.end	= IRQ_SSP,
++		.flags	= IORESOURCE_IRQ,
++	},
++	[2] = {
++		/* DRCMR for RX */
++		.start	= 13,
++		.end	= 13,
++		.flags	= IORESOURCE_DMA,
++	},
++	[3] = {
++		/* DRCMR for TX */
++		.start	= 14,
++		.end	= 14,
++		.flags	= IORESOURCE_DMA,
++	},
++};
++
++struct platform_device pxa25x_device_ssp = {
++	.name		= "pxa25x-ssp",
++	.id		= 0,
++	.dev		= {
++		.dma_mask = &pxa25x_ssp_dma_mask,
++		.coherent_dma_mask = DMA_BIT_MASK(32),
++	},
++	.resource	= pxa25x_resource_ssp,
++	.num_resources	= ARRAY_SIZE(pxa25x_resource_ssp),
++};
++
++static u64 pxa25x_nssp_dma_mask = DMA_BIT_MASK(32);
++
++static struct resource pxa25x_resource_nssp[] = {
++	[0] = {
++		.start	= 0x41400000,
++		.end	= 0x4140002f,
++		.flags	= IORESOURCE_MEM,
++	},
++	[1] = {
++		.start	= IRQ_NSSP,
++		.end	= IRQ_NSSP,
++		.flags	= IORESOURCE_IRQ,
++	},
++	[2] = {
++		/* DRCMR for RX */
++		.start	= 15,
++		.end	= 15,
++		.flags	= IORESOURCE_DMA,
++	},
++	[3] = {
++		/* DRCMR for TX */
++		.start	= 16,
++		.end	= 16,
++		.flags	= IORESOURCE_DMA,
++	},
++};
++
++struct platform_device pxa25x_device_nssp = {
++	.name		= "pxa25x-nssp",
++	.id		= 1,
++	.dev		= {
++		.dma_mask = &pxa25x_nssp_dma_mask,
++		.coherent_dma_mask = DMA_BIT_MASK(32),
++	},
++	.resource	= pxa25x_resource_nssp,
++	.num_resources	= ARRAY_SIZE(pxa25x_resource_nssp),
++};
++
++static u64 pxa25x_assp_dma_mask = DMA_BIT_MASK(32);
++
++static struct resource pxa25x_resource_assp[] = {
++	[0] = {
++		.start	= 0x41500000,
++		.end	= 0x4150002f,
++		.flags	= IORESOURCE_MEM,
++	},
++	[1] = {
++		.start	= IRQ_ASSP,
++		.end	= IRQ_ASSP,
++		.flags	= IORESOURCE_IRQ,
++	},
++	[2] = {
++		/* DRCMR for RX */
++		.start	= 23,
++		.end	= 23,
++		.flags	= IORESOURCE_DMA,
++	},
++	[3] = {
++		/* DRCMR for TX */
++		.start	= 24,
++		.end	= 24,
++		.flags	= IORESOURCE_DMA,
++	},
++};
++
++struct platform_device pxa25x_device_assp = {
++	/* ASSP is basically equivalent to NSSP */
++	.name		= "pxa25x-nssp",
++	.id		= 2,
++	.dev		= {
++		.dma_mask = &pxa25x_assp_dma_mask,
++		.coherent_dma_mask = DMA_BIT_MASK(32),
++	},
++	.resource	= pxa25x_resource_assp,
++	.num_resources	= ARRAY_SIZE(pxa25x_resource_assp),
++};
++#endif /* CONFIG_PXA25x */
++
++#if defined(CONFIG_PXA27x) || defined(CONFIG_PXA3xx)
++
++static u64 pxa27x_ohci_dma_mask = DMA_BIT_MASK(32);
++
++static struct resource pxa27x_resource_ohci[] = {
++	[0] = {
++		.start  = 0x4C000000,
++		.end    = 0x4C00ff6f,
++		.flags  = IORESOURCE_MEM,
++	},
++	[1] = {
++		.start  = IRQ_USBH1,
++		.end    = IRQ_USBH1,
++		.flags  = IORESOURCE_IRQ,
++	},
++};
++
++struct platform_device pxa27x_device_ohci = {
++	.name		= "pxa27x-ohci",
++	.id		= -1,
++	.dev		= {
++		.dma_mask = &pxa27x_ohci_dma_mask,
++		.coherent_dma_mask = DMA_BIT_MASK(32),
++	},
++	.num_resources  = ARRAY_SIZE(pxa27x_resource_ohci),
++	.resource       = pxa27x_resource_ohci,
++};
++
++void __init pxa_set_ohci_info(struct pxaohci_platform_data *info)
++{
++	pxa_register_device(&pxa27x_device_ohci, info);
++}
++
++static u64 pxa27x_ssp1_dma_mask = DMA_BIT_MASK(32);
++
++static struct resource pxa27x_resource_ssp1[] = {
++	[0] = {
++		.start	= 0x41000000,
++		.end	= 0x4100003f,
++		.flags	= IORESOURCE_MEM,
++	},
++	[1] = {
++		.start	= IRQ_SSP,
++		.end	= IRQ_SSP,
++		.flags	= IORESOURCE_IRQ,
++	},
++	[2] = {
++		/* DRCMR for RX */
++		.start	= 13,
++		.end	= 13,
++		.flags	= IORESOURCE_DMA,
++	},
++	[3] = {
++		/* DRCMR for TX */
++		.start	= 14,
++		.end	= 14,
++		.flags	= IORESOURCE_DMA,
++	},
++};
++
++struct platform_device pxa27x_device_ssp1 = {
++	.name		= "pxa27x-ssp",
++	.id		= 0,
++	.dev		= {
++		.dma_mask = &pxa27x_ssp1_dma_mask,
++		.coherent_dma_mask = DMA_BIT_MASK(32),
++	},
++	.resource	= pxa27x_resource_ssp1,
++	.num_resources	= ARRAY_SIZE(pxa27x_resource_ssp1),
++};
++
++static u64 pxa27x_ssp2_dma_mask = DMA_BIT_MASK(32);
++
++static struct resource pxa27x_resource_ssp2[] = {
++	[0] = {
++		.start	= 0x41700000,
++		.end	= 0x4170003f,
++		.flags	= IORESOURCE_MEM,
++	},
++	[1] = {
++		.start	= IRQ_SSP2,
++		.end	= IRQ_SSP2,
++		.flags	= IORESOURCE_IRQ,
++	},
++	[2] = {
++		/* DRCMR for RX */
++		.start	= 15,
++		.end	= 15,
++		.flags	= IORESOURCE_DMA,
++	},
++	[3] = {
++		/* DRCMR for TX */
++		.start	= 16,
++		.end	= 16,
++		.flags	= IORESOURCE_DMA,
++	},
++};
++
++struct platform_device pxa27x_device_ssp2 = {
++	.name		= "pxa27x-ssp",
++	.id		= 1,
++	.dev		= {
++		.dma_mask = &pxa27x_ssp2_dma_mask,
++		.coherent_dma_mask = DMA_BIT_MASK(32),
++	},
++	.resource	= pxa27x_resource_ssp2,
++	.num_resources	= ARRAY_SIZE(pxa27x_resource_ssp2),
++};
++
++static u64 pxa27x_ssp3_dma_mask = DMA_BIT_MASK(32);
++
++static struct resource pxa27x_resource_ssp3[] = {
++	[0] = {
++		.start	= 0x41900000,
++		.end	= 0x4190003f,
++		.flags	= IORESOURCE_MEM,
++	},
++	[1] = {
++		.start	= IRQ_SSP3,
++		.end	= IRQ_SSP3,
++		.flags	= IORESOURCE_IRQ,
++	},
++	[2] = {
++		/* DRCMR for RX */
++		.start	= 66,
++		.end	= 66,
++		.flags	= IORESOURCE_DMA,
++	},
++	[3] = {
++		/* DRCMR for TX */
++		.start	= 67,
++		.end	= 67,
++		.flags	= IORESOURCE_DMA,
++	},
++};
++
++struct platform_device pxa27x_device_ssp3 = {
++	.name		= "pxa27x-ssp",
++	.id		= 2,
++	.dev		= {
++		.dma_mask = &pxa27x_ssp3_dma_mask,
++		.coherent_dma_mask = DMA_BIT_MASK(32),
++	},
++	.resource	= pxa27x_resource_ssp3,
++	.num_resources	= ARRAY_SIZE(pxa27x_resource_ssp3),
++};
++#endif /* CONFIG_PXA27x || CONFIG_PXA3xx */
++
++#ifdef CONFIG_PXA3xx
++static u64 pxa3xx_ssp4_dma_mask = DMA_BIT_MASK(32);
++
++static struct resource pxa3xx_resource_ssp4[] = {
++	[0] = {
++		.start	= 0x41a00000,
++		.end	= 0x41a0003f,
++		.flags	= IORESOURCE_MEM,
++	},
++	[1] = {
++		.start	= IRQ_SSP4,
++		.end	= IRQ_SSP4,
++		.flags	= IORESOURCE_IRQ,
++	},
++	[2] = {
++		/* DRCMR for RX */
++		.start	= 2,
++		.end	= 2,
++		.flags	= IORESOURCE_DMA,
++	},
++	[3] = {
++		/* DRCMR for TX */
++		.start	= 3,
++		.end	= 3,
++		.flags	= IORESOURCE_DMA,
++	},
++};
++
++struct platform_device pxa3xx_device_ssp4 = {
++	/* PXA3xx SSP is basically equivalent to PXA27x */
++	.name		= "pxa27x-ssp",
++	.id		= 3,
++	.dev		= {
++		.dma_mask = &pxa3xx_ssp4_dma_mask,
++		.coherent_dma_mask = DMA_BIT_MASK(32),
++	},
++	.resource	= pxa3xx_resource_ssp4,
++	.num_resources	= ARRAY_SIZE(pxa3xx_resource_ssp4),
++};
++
++static struct resource pxa3xx_resources_mci2[] = {
++	[0] = {
++		.start	= 0x42000000,
++		.end	= 0x42000fff,
++		.flags	= IORESOURCE_MEM,
++	},
++	[1] = {
++		.start	= IRQ_MMC2,
++		.end	= IRQ_MMC2,
++		.flags	= IORESOURCE_IRQ,
++	},
++	[2] = {
++		.start	= 93,
++		.end	= 93,
++		.flags	= IORESOURCE_DMA,
++	},
++	[3] = {
++		.start	= 94,
++		.end	= 94,
++		.flags	= IORESOURCE_DMA,
++	},
++};
++
++struct platform_device pxa3xx_device_mci2 = {
++	.name		= "pxa2xx-mci",
++	.id		= 1,
++	.dev		= {
++		.dma_mask = &pxamci_dmamask,
++		.coherent_dma_mask =	0xffffffff,
++	},
++	.num_resources	= ARRAY_SIZE(pxa3xx_resources_mci2),
++	.resource	= pxa3xx_resources_mci2,
++};
++
++void __init pxa3xx_set_mci2_info(struct pxamci_platform_data *info)
++{
++	pxa_register_device(&pxa3xx_device_mci2, info);
++}
++
++static struct resource pxa3xx_resources_mci3[] = {
++	[0] = {
++		.start	= 0x42500000,
++		.end	= 0x42500fff,
++		.flags	= IORESOURCE_MEM,
++	},
++	[1] = {
++		.start	= IRQ_MMC3,
++		.end	= IRQ_MMC3,
++		.flags	= IORESOURCE_IRQ,
++	},
++	[2] = {
++		.start	= 100,
++		.end	= 100,
++		.flags	= IORESOURCE_DMA,
++	},
++	[3] = {
++		.start	= 101,
++		.end	= 101,
++		.flags	= IORESOURCE_DMA,
++	},
++};
++
++struct platform_device pxa3xx_device_mci3 = {
++	.name		= "pxa2xx-mci",
++	.id		= 2,
++	.dev		= {
++		.dma_mask = &pxamci_dmamask,
++		.coherent_dma_mask = 0xffffffff,
++	},
++	.num_resources	= ARRAY_SIZE(pxa3xx_resources_mci3),
++	.resource	= pxa3xx_resources_mci3,
++};
++
++void __init pxa3xx_set_mci3_info(struct pxamci_platform_data *info)
++{
++	pxa_register_device(&pxa3xx_device_mci3, info);
++}
++
++#endif /* CONFIG_PXA3xx */
+diff --git a/arch/arm/mach-pxa/devices.h b/arch/arm/mach-pxa/devices.h
+index 94c8d5c..96c7c89 100644
+--- a/arch/arm/mach-pxa/devices.h
++++ b/arch/arm/mach-pxa/devices.h
+@@ -1,4 +1,6 @@
+ extern struct platform_device pxa_device_mci;
++extern struct platform_device pxa3xx_device_mci2;
++extern struct platform_device pxa3xx_device_mci3;
+ extern struct platform_device pxa_device_udc;
+ extern struct platform_device pxa_device_fb;
+ extern struct platform_device pxa_device_ffuart;
+@@ -12,3 +14,13 @@ extern struct platform_device pxa_device_rtc;
+ 
+ extern struct platform_device pxa27x_device_i2c_power;
+ extern struct platform_device pxa27x_device_ohci;
++
++extern struct platform_device pxa25x_device_ssp;
++extern struct platform_device pxa25x_device_nssp;
++extern struct platform_device pxa25x_device_assp;
++extern struct platform_device pxa27x_device_ssp1;
++extern struct platform_device pxa27x_device_ssp2;
++extern struct platform_device pxa27x_device_ssp3;
++extern struct platform_device pxa3xx_device_ssp4;
++
++void __init pxa_register_device(struct platform_device *dev, void *data);
+diff --git a/arch/arm/mach-pxa/eseries.c b/arch/arm/mach-pxa/eseries.c
+new file mode 100644
+index 0000000..ee0ae93
+--- /dev/null
++++ b/arch/arm/mach-pxa/eseries.c
+@@ -0,0 +1,101 @@
++/*
++ * Hardware definitions for the Toshiba eseries PDAs
++ *
++ * Copyright (c) 2003 Ian Molton <spyro at 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/init.h>
++
++#include <asm/setup.h>
++#include <asm/mach/arch.h>
++#include <asm/arch/hardware.h>
++#include <asm/mach-types.h>
++
++#include <generic.h>
++
++/* Only e800 has 128MB RAM */
++static void __init eseries_fixup(struct machine_desc *desc,
++                      struct tag *tags, char **cmdline, struct meminfo *mi)
++{
++	mi->nr_banks=1;
++	mi->bank[0].start = 0xa0000000;
++	mi->bank[0].node = 0;
++	if (machine_is_e800())
++		mi->bank[0].size = (128*1024*1024);
++	else
++		mi->bank[0].size = (64*1024*1024);
++}
++
++/* e-series machine definitions */
++
++#ifdef CONFIG_MACH_E330
++MACHINE_START(E330, "Toshiba e330")
++        /* Maintainer: Ian Molton (spyro at 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 at 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_E750
++MACHINE_START(E750, "Toshiba e750")
++        /* Maintainer: Ian Molton (spyro at 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 at 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_E800
++MACHINE_START(E800, "Toshiba e800")
++        /* Maintainer: Ian Molton (spyro at 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
++
+diff --git a/arch/arm/mach-pxa/generic.c b/arch/arm/mach-pxa/generic.c
+index 1c34946..698aeec 100644
+--- a/arch/arm/mach-pxa/generic.c
++++ b/arch/arm/mach-pxa/generic.c
+@@ -20,7 +20,6 @@
+ #include <linux/kernel.h>
+ #include <linux/init.h>
+ #include <linux/delay.h>
+-#include <linux/platform_device.h>
+ #include <linux/ioport.h>
+ #include <linux/pm.h>
+ #include <linux/string.h>
+@@ -33,13 +32,7 @@
+ 
+ #include <asm/arch/pxa-regs.h>
+ #include <asm/arch/gpio.h>
+-#include <asm/arch/udc.h>
+-#include <asm/arch/pxafb.h>
+-#include <asm/arch/mmc.h>
+-#include <asm/arch/irda.h>
+-#include <asm/arch/i2c.h>
+ 
+-#include "devices.h"
+ #include "generic.h"
+ 
+ /*
+@@ -203,7 +196,7 @@ static struct map_desc standard_io_desc[] __initdata = {
+ 	}, {	/* Mem Ctl */
+ 		.virtual	=  0xf6000000,
+ 		.pfn		= __phys_to_pfn(0x48000000),
+-		.length		= 0x00100000,
++		.length		= 0x00200000,
+ 		.type		= MT_DEVICE
+ 	}, {	/* USB host */
+ 		.virtual	=  0xf8000000,
+@@ -233,245 +226,3 @@ void __init pxa_map_io(void)
+ 	iotable_init(standard_io_desc, ARRAY_SIZE(standard_io_desc));
+ 	get_clk_frequency_khz(1);
+ }
+-
+-
+-static struct resource pxamci_resources[] = {
+-	[0] = {
+-		.start	= 0x41100000,
+-		.end	= 0x41100fff,
+-		.flags	= IORESOURCE_MEM,
+-	},
+-	[1] = {
+-		.start	= IRQ_MMC,
+-		.end	= IRQ_MMC,
+-		.flags	= IORESOURCE_IRQ,
+-	},
+-};
+-
+-static u64 pxamci_dmamask = 0xffffffffUL;
+-
+-struct platform_device pxa_device_mci = {
+-	.name		= "pxa2xx-mci",
+-	.id		= -1,
+-	.dev		= {
+-		.dma_mask = &pxamci_dmamask,
+-		.coherent_dma_mask = 0xffffffff,
+-	},
+-	.num_resources	= ARRAY_SIZE(pxamci_resources),
+-	.resource	= pxamci_resources,
+-};
+-
+-void __init pxa_set_mci_info(struct pxamci_platform_data *info)
+-{
+-	pxa_device_mci.dev.platform_data = info;
+-}
+-
+-
+-static struct pxa2xx_udc_mach_info pxa_udc_info;
+-
+-void __init pxa_set_udc_info(struct pxa2xx_udc_mach_info *info)
+-{
+-	memcpy(&pxa_udc_info, info, sizeof *info);
+-}
+-
+-static struct resource pxa2xx_udc_resources[] = {
+-	[0] = {
+-		.start	= 0x40600000,
+-		.end	= 0x4060ffff,
+-		.flags	= IORESOURCE_MEM,
+-	},
+-	[1] = {
+-		.start	= IRQ_USB,
+-		.end	= IRQ_USB,
+-		.flags	= IORESOURCE_IRQ,
+-	},
+-};
+-
+-static u64 udc_dma_mask = ~(u32)0;
+-
+-struct platform_device pxa_device_udc = {
+-	.name		= "pxa2xx-udc",
+-	.id		= -1,
+-	.resource	= pxa2xx_udc_resources,
+-	.num_resources	= ARRAY_SIZE(pxa2xx_udc_resources),
+-	.dev		=  {
+-		.platform_data	= &pxa_udc_info,
+-		.dma_mask	= &udc_dma_mask,
+-	}
+-};
+-
+-static struct resource pxafb_resources[] = {
+-	[0] = {
+-		.start	= 0x44000000,
+-		.end	= 0x4400ffff,
+-		.flags	= IORESOURCE_MEM,
+-	},
+-	[1] = {
+-		.start	= IRQ_LCD,
+-		.end	= IRQ_LCD,
+-		.flags	= IORESOURCE_IRQ,
+-	},
+-};
+-
+-static u64 fb_dma_mask = ~(u64)0;
+-
+-struct platform_device pxa_device_fb = {
+-	.name		= "pxa2xx-fb",
+-	.id		= -1,
+-	.dev		= {
+-		.dma_mask	= &fb_dma_mask,
+-		.coherent_dma_mask = 0xffffffff,
+-	},
+-	.num_resources	= ARRAY_SIZE(pxafb_resources),
+-	.resource	= pxafb_resources,
+-};
+-
+-void __init set_pxa_fb_info(struct pxafb_mach_info *info)
+-{
+-	pxa_device_fb.dev.platform_data = info;
+-}
+-
+-void __init set_pxa_fb_parent(struct device *parent_dev)
+-{
+-	pxa_device_fb.dev.parent = parent_dev;
+-}
+-
+-static struct resource pxa_resource_ffuart[] = {
+-	{
+-		.start	= __PREG(FFUART),
+-		.end	= __PREG(FFUART) + 35,
+-		.flags	= IORESOURCE_MEM,
+-	}, {
+-		.start	= IRQ_FFUART,
+-		.end	= IRQ_FFUART,
+-		.flags	= IORESOURCE_IRQ,
+-	}
+-};
+-
+-struct platform_device pxa_device_ffuart= {
+-	.name		= "pxa2xx-uart",
+-	.id		= 0,
+-	.resource	= pxa_resource_ffuart,
+-	.num_resources	= ARRAY_SIZE(pxa_resource_ffuart),
+-};
+-
+-static struct resource pxa_resource_btuart[] = {
+-	{
+-		.start	= __PREG(BTUART),
+-		.end	= __PREG(BTUART) + 35,
+-		.flags	= IORESOURCE_MEM,
+-	}, {
+-		.start	= IRQ_BTUART,
+-		.end	= IRQ_BTUART,
+-		.flags	= IORESOURCE_IRQ,
+-	}
+-};
+-
+-struct platform_device pxa_device_btuart = {
+-	.name		= "pxa2xx-uart",
+-	.id		= 1,
+-	.resource	= pxa_resource_btuart,
+-	.num_resources	= ARRAY_SIZE(pxa_resource_btuart),
+-};
+-
+-static struct resource pxa_resource_stuart[] = {
+-	{
+-		.start	= __PREG(STUART),
+-		.end	= __PREG(STUART) + 35,
+-		.flags	= IORESOURCE_MEM,
+-	}, {
+-		.start	= IRQ_STUART,
+-		.end	= IRQ_STUART,
+-		.flags	= IORESOURCE_IRQ,
+-	}
+-};
+-
+-struct platform_device pxa_device_stuart = {
+-	.name		= "pxa2xx-uart",
+-	.id		= 2,
+-	.resource	= pxa_resource_stuart,
+-	.num_resources	= ARRAY_SIZE(pxa_resource_stuart),
+-};
+-
+-static struct resource pxa_resource_hwuart[] = {
+-	{
+-		.start	= __PREG(HWUART),
+-		.end	= __PREG(HWUART) + 47,
+-		.flags	= IORESOURCE_MEM,
+-	}, {
+-		.start	= IRQ_HWUART,
+-		.end	= IRQ_HWUART,
+-		.flags	= IORESOURCE_IRQ,
+-	}
+-};
+-
+-struct platform_device pxa_device_hwuart = {
+-	.name		= "pxa2xx-uart",
+-	.id		= 3,
+-	.resource	= pxa_resource_hwuart,
+-	.num_resources	= ARRAY_SIZE(pxa_resource_hwuart),
+-};
+-
+-static struct resource pxai2c_resources[] = {
+-	{
+-		.start	= 0x40301680,
+-		.end	= 0x403016a3,
+-		.flags	= IORESOURCE_MEM,
+-	}, {
+-		.start	= IRQ_I2C,
+-		.end	= IRQ_I2C,
+-		.flags	= IORESOURCE_IRQ,
+-	},
+-};
+-
+-struct platform_device pxa_device_i2c = {
+-	.name		= "pxa2xx-i2c",
+-	.id		= 0,
+-	.resource	= pxai2c_resources,
+-	.num_resources	= ARRAY_SIZE(pxai2c_resources),
+-};
+-
+-void __init pxa_set_i2c_info(struct i2c_pxa_platform_data *info)
+-{
+-	pxa_device_i2c.dev.platform_data = info;
+-}
+-
+-static struct resource pxai2s_resources[] = {
+-	{
+-		.start	= 0x40400000,
+-		.end	= 0x40400083,
+-		.flags	= IORESOURCE_MEM,
+-	}, {
+-		.start	= IRQ_I2S,
+-		.end	= IRQ_I2S,
+-		.flags	= IORESOURCE_IRQ,
+-	},
+-};
+-
+-struct platform_device pxa_device_i2s = {
+-	.name		= "pxa2xx-i2s",
+-	.id		= -1,
+-	.resource	= pxai2s_resources,
+-	.num_resources	= ARRAY_SIZE(pxai2s_resources),
+-};
+-
+-static u64 pxaficp_dmamask = ~(u32)0;
+-
+-struct platform_device pxa_device_ficp = {
+-	.name		= "pxa2xx-ir",
+-	.id		= -1,
+-	.dev		= {
+-		.dma_mask = &pxaficp_dmamask,
+-		.coherent_dma_mask = 0xffffffff,
+-	},
+-};
+-
+-void __init pxa_set_ficp_info(struct pxaficp_platform_data *info)
+-{
+-	pxa_device_ficp.dev.platform_data = info;
+-}
+-
+-struct platform_device pxa_device_rtc = {
+-	.name		= "sa1100-rtc",
+-	.id		= -1,
+-};
+diff --git a/arch/arm/mach-pxa/idp.c b/arch/arm/mach-pxa/idp.c
+index 465108d..0a94344 100644
+--- a/arch/arm/mach-pxa/idp.c
++++ b/arch/arm/mach-pxa/idp.c
+@@ -54,7 +54,7 @@ static struct resource smc91x_resources[] = {
+ 	[1] = {
+ 		.start	= IRQ_GPIO(4),
+ 		.end	= IRQ_GPIO(4),
+-		.flags	= IORESOURCE_IRQ,
++		.flags	= IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE,
+ 	}
+ };
+ 
+diff --git a/arch/arm/mach-pxa/littleton.c b/arch/arm/mach-pxa/littleton.c
+new file mode 100644
+index 0000000..0a4b54c
+--- /dev/null
++++ b/arch/arm/mach-pxa/littleton.c
+@@ -0,0 +1,325 @@
++/*
++ *  linux/arch/arm/mach-pxa/littleton.c
++ *
++ *  Support for the Marvell Littleton Development Platform.
++ *
++ *  Author:	Jason Chagas (largely modified code)
++ *  Created:	Nov 20, 2006
++ *  Copyright:	(C) Copyright 2006 Marvell International Ltd.
++ *
++ *  2007-11-22  modified to align with latest kernel
++ *              eric miao <eric.miao at 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/init.h>
++#include <linux/interrupt.h>
++#include <linux/delay.h>
++#include <linux/platform_device.h>
++#include <linux/clk.h>
++
++#include <asm/types.h>
++#include <asm/setup.h>
++#include <asm/memory.h>
++#include <asm/mach-types.h>
++#include <asm/hardware.h>
++#include <asm/irq.h>
++
++#include <asm/mach/arch.h>
++#include <asm/mach/map.h>
++#include <asm/mach/irq.h>
++
++#include <asm/arch/pxa-regs.h>
++#include <asm/arch/mfp-pxa300.h>
++#include <asm/arch/gpio.h>
++#include <asm/arch/pxafb.h>
++#include <asm/arch/ssp.h>
++#include <asm/arch/littleton.h>
++
++#include "generic.h"
++
++#define ARRAY_AND_SIZE(x)	(x), ARRAY_SIZE(x)
++
++/* Littleton MFP configurations */
++static mfp_cfg_t littleton_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,
++	GPIO70_LCD_LDD_16,
++	GPIO71_LCD_LDD_17,
++	GPIO72_LCD_FCLK,
++	GPIO73_LCD_LCLK,
++	GPIO74_LCD_PCLK,
++	GPIO75_LCD_BIAS,
++
++	/* SSP2 */
++	GPIO25_SSP2_SCLK,
++	GPIO17_SSP2_FRM,
++	GPIO27_SSP2_TXD,
++
++	/* Debug Ethernet */
++	GPIO90_GPIO,
++};
++
++static struct resource smc91x_resources[] = {
++	[0] = {
++		.start	= (LITTLETON_ETH_PHYS + 0x300),
++		.end	= (LITTLETON_ETH_PHYS + 0xfffff),
++		.flags	= IORESOURCE_MEM,
++	},
++	[1] = {
++		.start	= IRQ_GPIO(mfp_to_gpio(MFP_PIN_GPIO90)),
++		.end	= IRQ_GPIO(mfp_to_gpio(MFP_PIN_GPIO90)),
++		.flags	= IORESOURCE_IRQ | IRQF_TRIGGER_FALLING,
++	}
++};
++
++static struct platform_device smc91x_device = {
++	.name		= "smc91x",
++	.id		= 0,
++	.num_resources	= ARRAY_SIZE(smc91x_resources),
++	.resource	= smc91x_resources,
++};
++
++#if defined(CONFIG_FB_PXA) || defined(CONFIG_FB_PXA_MODULES)
++/* 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 */
++		.pixclock	= 38250,
++		.xres		= 480,
++		.yres		= 640,
++		.bpp		= 16,
++		.hsync_len	= 8,
++		.left_margin	= 8,
++		.right_margin	= 24,
++		.vsync_len	= 2,
++		.upper_margin	= 2,
++		.lower_margin	= 4,
++		.sync		= 0,
++	},
++	[1] = {
++		/* QVGA */
++		.pixclock	= 153000,
++		.xres		= 240,
++		.yres		= 320,
++		.bpp		= 16,
++		.hsync_len	= 8,
++		.left_margin	= 8,
++		.right_margin	= 88,
++		.vsync_len	= 2,
++		.upper_margin	= 2,
++		.lower_margin	= 2,
++		.sync		= 0,
++	},
++};
++
++static struct pxafb_mach_info littleton_lcd_info = {
++	.modes			= tpo_tdo24mtea1_modes,
++	.num_modes		= 2,
++	.lccr0			= LCCR0_Act,
++	.lccr3			= LCCR3_HSP | LCCR3_VSP,
++	.pxafb_lcd_power	= littleton_lcd_power,
++};
++
++static void littleton_init_lcd(void)
++{
++	set_pxa_fb_info(&littleton_lcd_info);
++}
++#else
++static inline void littleton_init_lcd(void) {};
++#endif /* CONFIG_FB_PXA || CONFIG_FB_PXA_MODULES */
++
++static void __init littleton_init(void)
++{
++	/* initialize MFP configurations */
++	pxa3xx_mfp_config(ARRAY_AND_SIZE(littleton_mfp_cfg));
++
++	/*
++	 * Note: we depend bootloader set the correct
++	 * value to MSC register for SMC91x.
++	 */
++	platform_device_register(&smc91x_device);
++
++	littleton_init_lcd();
++}
++
++MACHINE_START(LITTLETON, "Marvell Form Factor Development Platform (aka Littleton)")
++	.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	= littleton_init,
++MACHINE_END
+diff --git a/arch/arm/mach-pxa/lpd270.c b/arch/arm/mach-pxa/lpd270.c
+index 2611644..afa62ff 100644
+--- a/arch/arm/mach-pxa/lpd270.c
++++ b/arch/arm/mach-pxa/lpd270.c
+@@ -38,6 +38,7 @@
+ #include <asm/mach/flash.h>
+ 
+ #include <asm/arch/pxa-regs.h>
++#include <asm/arch/pxa2xx-regs.h>
+ #include <asm/arch/lpd270.h>
+ #include <asm/arch/audio.h>
+ #include <asm/arch/pxafb.h>
+@@ -122,7 +123,7 @@ static int lpd270_irq_resume(struct sys_device *dev)
+ }
+ 
+ static struct sysdev_class lpd270_irq_sysclass = {
+-	set_kset_name("cpld_irq"),
++	.name = "cpld_irq",
+ 	.resume = lpd270_irq_resume,
+ };
+ 
+diff --git a/arch/arm/mach-pxa/lubbock.c b/arch/arm/mach-pxa/lubbock.c
+index 011a1a7..e7ae4bb 100644
+--- a/arch/arm/mach-pxa/lubbock.c
++++ b/arch/arm/mach-pxa/lubbock.c
+@@ -41,6 +41,7 @@
+ #include <asm/hardware/sa1111.h>
+ 
+ #include <asm/arch/pxa-regs.h>
++#include <asm/arch/pxa2xx-regs.h>
+ #include <asm/arch/lubbock.h>
+ #include <asm/arch/udc.h>
+ #include <asm/arch/irda.h>
+@@ -126,7 +127,7 @@ static int lubbock_irq_resume(struct sys_device *dev)
+ }
+ 
+ static struct sysdev_class lubbock_irq_sysclass = {
+-	set_kset_name("cpld_irq"),
++	.name = "cpld_irq",
+ 	.resume = lubbock_irq_resume,
+ };
+ 
+@@ -136,9 +137,13 @@ static struct sys_device lubbock_irq_device = {
+ 
+ static int __init lubbock_irq_device_init(void)
+ {
+-	int ret = sysdev_class_register(&lubbock_irq_sysclass);
+-	if (ret == 0)
+-		ret = sysdev_register(&lubbock_irq_device);
++	int ret = -ENODEV;
++
++	if (machine_is_lubbock()) {
++		ret = sysdev_class_register(&lubbock_irq_sysclass);
++		if (ret == 0)
++			ret = sysdev_register(&lubbock_irq_device);
++	}
+ 	return ret;
+ }
+ 
+@@ -191,7 +196,7 @@ static struct resource smc91x_resources[] = {
+ 	[1] = {
+ 		.start	= LUBBOCK_ETH_IRQ,
+ 		.end	= LUBBOCK_ETH_IRQ,
+-		.flags	= IORESOURCE_IRQ,
++		.flags	= IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE,
+ 	},
+ 	[2] = {
+ 		.name	= "smc91x-attrib",
+@@ -206,30 +211,13 @@ static struct resource smc91x_resources[] = {
+  * (to J5) and poking board registers (as done below).  Else it's only useful
+  * for the temperature sensors.
+  */
+-static struct resource pxa_ssp_resources[] = {
+-	[0] = {
+-		.start	= __PREG(SSCR0_P(1)),
+-		.end	= __PREG(SSCR0_P(1)) + 0x14,
+-		.flags	= IORESOURCE_MEM,
+-	},
+-	[1] = {
+-		.start	= IRQ_SSP,
+-		.end	= IRQ_SSP,
+-		.flags	= IORESOURCE_IRQ,
+-	},
+-};
+-
+ static struct pxa2xx_spi_master pxa_ssp_master_info = {
+-	.ssp_type	= PXA25x_SSP,
+-	.clock_enable	= CKEN_SSP,
+ 	.num_chipselect	= 0,
+ };
+ 
+ static struct platform_device pxa_ssp = {
+ 	.name		= "pxa2xx-spi",
+ 	.id		= 1,
+-	.resource	= pxa_ssp_resources,
+-	.num_resources	= ARRAY_SIZE(pxa_ssp_resources),
+ 	.dev = {
+ 		.platform_data	= &pxa_ssp_master_info,
+ 	},
+diff --git a/arch/arm/mach-pxa/magician.c b/arch/arm/mach-pxa/magician.c
+new file mode 100644
+index 0000000..d98ef7a
+--- /dev/null
++++ b/arch/arm/mach-pxa/magician.c
+@@ -0,0 +1,218 @@
++/*
++ * Support for HTC Magician PDA phones:
++ * i-mate JAM, O2 Xda mini, Orange SPV M500, Qtek s100, Qtek s110
++ * and T-Mobile MDA Compact.
++ *
++ * Copyright (c) 2006-2007 Philipp Zabel
++ *
++ * Based on hx4700.c, spitz.c and others.
++ *
++ * 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/gpio_keys.h>
++#include <linux/input.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/map.h>
++#include <linux/mtd/physmap.h>
++
++#include <asm/gpio.h>
++#include <asm/hardware.h>
++#include <asm/mach-types.h>
++#include <asm/mach/arch.h>
++#include <asm/arch/magician.h>
++#include <asm/arch/pxa-regs.h>
++#include <asm/arch/pxafb.h>
++#include <asm/arch/irda.h>
++#include <asm/arch/ohci.h>
++
++#include "generic.h"
++
++/*
++ * IRDA
++ */
++
++static void magician_irda_transceiver_mode(struct device *dev, int mode)
++{
++	gpio_set_value(GPIO83_MAGICIAN_nIR_EN, mode & IR_OFF);
++}
++
++static struct pxaficp_platform_data magician_ficp_info = {
++	.transceiver_cap  = IR_SIRMODE | IR_OFF,
++	.transceiver_mode = magician_irda_transceiver_mode,
++};
++
++/*
++ * GPIO Keys
++ */
++
++static struct gpio_keys_button magician_button_table[] = {
++	{KEY_POWER,      GPIO0_MAGICIAN_KEY_POWER,      0, "Power button"},
++	{KEY_ESC,        GPIO37_MAGICIAN_KEY_HANGUP,    0, "Hangup button"},
++	{KEY_F10,        GPIO38_MAGICIAN_KEY_CONTACTS,  0, "Contacts button"},
++	{KEY_CALENDAR,   GPIO90_MAGICIAN_KEY_CALENDAR,  0, "Calendar button"},
++	{KEY_CAMERA,     GPIO91_MAGICIAN_KEY_CAMERA,    0, "Camera button"},
++	{KEY_UP,         GPIO93_MAGICIAN_KEY_UP,        0, "Up button"},
++	{KEY_DOWN,       GPIO94_MAGICIAN_KEY_DOWN,      0, "Down button"},
++	{KEY_LEFT,       GPIO95_MAGICIAN_KEY_LEFT,      0, "Left button"},
++	{KEY_RIGHT,      GPIO96_MAGICIAN_KEY_RIGHT,     0, "Right button"},
++	{KEY_KPENTER,    GPIO97_MAGICIAN_KEY_ENTER,     0, "Action button"},
++	{KEY_RECORD,     GPIO98_MAGICIAN_KEY_RECORD,    0, "Record button"},
++	{KEY_VOLUMEUP,   GPIO100_MAGICIAN_KEY_VOL_UP,   0, "Volume up"},
++	{KEY_VOLUMEDOWN, GPIO101_MAGICIAN_KEY_VOL_DOWN, 0, "Volume down"},
++	{KEY_PHONE,      GPIO102_MAGICIAN_KEY_PHONE,    0, "Phone button"},
++	{KEY_PLAY,       GPIO99_MAGICIAN_HEADPHONE_IN,  0, "Headset button"},
++};
++
++static struct gpio_keys_platform_data gpio_keys_data = {
++	.buttons  = magician_button_table,
++	.nbuttons = ARRAY_SIZE(magician_button_table),
++};
++
++static struct platform_device gpio_keys = {
++	.name = "gpio-keys",
++	.dev  = {
++		.platform_data = &gpio_keys_data,
++	},
++	.id   = -1,
++};
++
++/*
++ * LCD - Toppoly TD028STEB1
++ */
++
++static struct pxafb_mode_info toppoly_modes[] = {
++	{
++		.pixclock     = 96153,
++		.bpp          = 16,
++		.xres         = 240,
++		.yres         = 320,
++		.hsync_len    = 11,
++		.vsync_len    = 3,
++		.left_margin  = 19,
++		.upper_margin = 2,
++		.right_margin = 10,
++		.lower_margin = 2,
++		.sync         = 0,
++	},
++};
++
++static struct pxafb_mach_info toppoly_info = {
++	.modes       = toppoly_modes,
++	.num_modes   = 1,
++	.fixed_modes = 1,
++	.lccr0       = LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
++	.lccr3       = LCCR3_PixRsEdg,
++};
++
++/*
++ * Backlight
++ */
++
++static void magician_set_bl_intensity(int intensity)
++{
++	if (intensity) {
++		PWM_CTRL0 = 1;
++		PWM_PERVAL0 = 0xc8;
++		PWM_PWDUTY0 = intensity;
++		pxa_set_cken(CKEN_PWM0, 1);
++	} else {
++		pxa_set_cken(CKEN_PWM0, 0);
++	}
++}
++
++static struct generic_bl_info backlight_info = {
++	.default_intensity = 0x64,
++	.limit_mask        = 0x0b,
++	.max_intensity     = 0xc7,
++	.set_bl_intensity  = magician_set_bl_intensity,
++};
++
++static struct platform_device backlight = {
++	.name = "corgi-bl",
++	.dev  = {
++		.platform_data = &backlight_info,
++	},
++	.id   = -1,
++};
++
++
++/*
++ * 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,
++};
++
++
++/*
++ * StrataFlash
++ */
++
++#define PXA_CS_SIZE		0x04000000
++
++static struct resource strataflash_resource = {
++	.start = PXA_CS0_PHYS,
++	.end   = PXA_CS0_PHYS + PXA_CS_SIZE - 1,
++	.flags = IORESOURCE_MEM,
++};
++
++static struct physmap_flash_data strataflash_data = {
++	.width = 4,
++};
++
++static struct platform_device strataflash = {
++	.name          = "physmap-flash",
++	.id            = -1,
++	.num_resources = 1,
++	.resource      = &strataflash_resource,
++	.dev = {
++		.platform_data = &strataflash_data,
++	},
++};
++
++/*
++ * Platform devices
++ */
++
++static struct platform_device *devices[] __initdata = {
++	&gpio_keys,
++	&backlight,
++	&strataflash,
++};
++
++static void __init magician_init(void)
++{
++	platform_add_devices(devices, ARRAY_SIZE(devices));
++	pxa_set_ohci_info(&magician_ohci_info);
++	pxa_set_ficp_info(&magician_ficp_info);
++	set_pxa_fb_info(&toppoly_info);
++}
++
++
++MACHINE_START(MAGICIAN, "HTC Magician")
++	.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 = magician_init,
++	.timer = &pxa_timer,
++MACHINE_END
+diff --git a/arch/arm/mach-pxa/mainstone.c b/arch/arm/mach-pxa/mainstone.c
+index a4bc348..345c3de 100644
+--- a/arch/arm/mach-pxa/mainstone.c
++++ b/arch/arm/mach-pxa/mainstone.c
+@@ -23,6 +23,7 @@
+ #include <linux/ioport.h>
+ #include <linux/mtd/mtd.h>
+ #include <linux/mtd/partitions.h>
++#include <linux/backlight.h>
+ 
+ #include <asm/types.h>
+ #include <asm/setup.h>
+@@ -38,6 +39,7 @@
+ #include <asm/mach/flash.h>
+ 
+ #include <asm/arch/pxa-regs.h>
++#include <asm/arch/pxa2xx-regs.h>
+ #include <asm/arch/mainstone.h>
+ #include <asm/arch/audio.h>
+ #include <asm/arch/pxafb.h>
+@@ -120,7 +122,7 @@ static int mainstone_irq_resume(struct sys_device *dev)
+ }
+ 
+ static struct sysdev_class mainstone_irq_sysclass = {
+-	set_kset_name("cpld_irq"),
++	.name = "cpld_irq",
+ 	.resume = mainstone_irq_resume,
+ };
+ 
+@@ -130,9 +132,13 @@ static struct sys_device mainstone_irq_device = {
+ 
+ static int __init mainstone_irq_device_init(void)
+ {
+-	int ret = sysdev_class_register(&mainstone_irq_sysclass);
+-	if (ret == 0)
+-		ret = sysdev_register(&mainstone_irq_device);
++	int ret = -ENODEV;
++
++	if (machine_is_mainstone()) {
++		ret = sysdev_class_register(&mainstone_irq_sysclass);
++		if (ret == 0)
++			ret = sysdev_register(&mainstone_irq_device);
++	}
+ 	return ret;
+ }
+ 
+@@ -150,7 +156,7 @@ static struct resource smc91x_resources[] = {
+ 	[1] = {
+ 		.start	= MAINSTONE_IRQ(3),
+ 		.end	= MAINSTONE_IRQ(3),
+-		.flags	= IORESOURCE_IRQ,
++		.flags	= IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE,
+ 	}
+ };
+ 
+@@ -263,21 +269,60 @@ static struct platform_device mst_flash_device[2] = {
+ 	},
+ };
+ 
+-static void mainstone_backlight_power(int on)
++#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
++static int mainstone_backlight_update_status(struct backlight_device *bl)
+ {
+-	if (on) {
++	int brightness = bl->props.brightness;
++
++	if (bl->props.power != FB_BLANK_UNBLANK ||
++	    bl->props.fb_blank != FB_BLANK_UNBLANK)
++		brightness = 0;
++
++	if (brightness != 0) {
+ 		pxa_gpio_mode(GPIO16_PWM0_MD);
+ 		pxa_set_cken(CKEN_PWM0, 1);
+-		PWM_CTRL0 = 0;
+-		PWM_PWDUTY0 = 0x3ff;
+-		PWM_PERVAL0 = 0x3ff;
+-	} else {
+-		PWM_CTRL0 = 0;
+-		PWM_PWDUTY0 = 0x0;
+-		PWM_PERVAL0 = 0x3FF;
++	}
++	PWM_CTRL0 = 0;
++	PWM_PWDUTY0 = brightness;
++	PWM_PERVAL0 = bl->props.max_brightness;
++	if (brightness == 0)
+ 		pxa_set_cken(CKEN_PWM0, 0);
++	return 0; /* pointless return value */
++}
++
++static int mainstone_backlight_get_brightness(struct backlight_device *bl)
++{
++	return PWM_PWDUTY0;
++}
++
++static /*const*/ struct backlight_ops mainstone_backlight_ops = {
++	.update_status	= mainstone_backlight_update_status,
++	.get_brightness	= mainstone_backlight_get_brightness,
++};
++
++static void __init mainstone_backlight_register(void)
++{
++	struct backlight_device *bl;
++
++	bl = backlight_device_register("mainstone-bl", &pxa_device_fb.dev,
++				       NULL, &mainstone_backlight_ops);
++	if (IS_ERR(bl)) {
++		printk(KERN_ERR "mainstone: unable to register backlight: %ld\n",
++		       PTR_ERR(bl));
++		return;
+ 	}
++
++	/*
++	 * broken design - register-then-setup interfaces are
++	 * utterly broken by definition.
++	 */
++	bl->props.max_brightness = 1023;
++	bl->props.brightness = 1023;
++	backlight_update_status(bl);
+ }
++#else
++#define mainstone_backlight_register()	do { } while (0)
++#endif
+ 
+ static struct pxafb_mode_info toshiba_ltm04c380k_mode = {
+ 	.pixclock		= 50000,
+@@ -311,7 +356,6 @@ static struct pxafb_mach_info mainstone_pxafb_info = {
+ 	.num_modes      	= 1,
+ 	.lccr0			= LCCR0_Act,
+ 	.lccr3			= LCCR3_PCP,
+-	.pxafb_backlight_power	= mainstone_backlight_power,
+ };
+ 
+ static int mainstone_mci_init(struct device *dev, irq_handler_t mstone_detect_int, void *data)
+@@ -335,12 +379,10 @@ static int mainstone_mci_init(struct device *dev, irq_handler_t mstone_detect_in
+ 
+ 	err = request_irq(MAINSTONE_MMC_IRQ, mstone_detect_int, IRQF_DISABLED,
+ 			     "MMC card detect", data);
+-	if (err) {
++	if (err)
+ 		printk(KERN_ERR "mainstone_mci_init: MMC/SD: can't request MMC card detect IRQ\n");
+-		return -1;
+-	}
+ 
+-	return 0;
++	return err;
+ }
+ 
+ static void mainstone_mci_setpower(struct device *dev, unsigned int vdd)
+@@ -473,6 +515,7 @@ static void __init mainstone_init(void)
+ 		mainstone_pxafb_info.modes = &toshiba_ltm035a776c_mode;
+ 
+ 	set_pxa_fb_info(&mainstone_pxafb_info);
++	mainstone_backlight_register();
+ 
+ 	pxa_set_mci_info(&mainstone_mci_platform_data);
+ 	pxa_set_ficp_info(&mainstone_ficp_platform_data);
+diff --git a/arch/arm/mach-pxa/mfp.c b/arch/arm/mach-pxa/mfp.c
+index 436f965..ec1b2d8 100644
+--- a/arch/arm/mach-pxa/mfp.c
++++ b/arch/arm/mach-pxa/mfp.c
+@@ -17,9 +17,11 @@
+ #include <linux/kernel.h>
+ #include <linux/init.h>
+ #include <linux/io.h>
++#include <linux/sysdev.h>
+ 
+ #include <asm/hardware.h>
+ #include <asm/arch/mfp.h>
++#include <asm/arch/mfp-pxa3xx.h>
+ 
+ /* mfp_spin_lock is used to ensure that MFP register configuration
+  * (most likely a read-modify-write operation) is atomic, and that
+@@ -28,43 +30,110 @@
+ static DEFINE_SPINLOCK(mfp_spin_lock);
+ 
+ static void __iomem *mfpr_mmio_base = (void __iomem *)&__REG(MFPR_BASE);
++
++struct pxa3xx_mfp_pin {
++	unsigned long	config;		/* -1 for not configured */
++	unsigned long	mfpr_off;	/* MFPRxx Register offset */
++	unsigned long	mfpr_run;	/* Run-Mode Register Value */
++	unsigned long	mfpr_lpm;	/* Low Power Mode Register Value */
++};
++
+ static struct pxa3xx_mfp_pin mfp_table[MFP_PIN_MAX];
+ 
++/* mapping of MFP_LPM_* definitions to MFPR_LPM_* register bits */
++const static unsigned long mfpr_lpm[] = {
++	MFPR_LPM_INPUT,
++	MFPR_LPM_DRIVE_LOW,
++	MFPR_LPM_DRIVE_HIGH,
++	MFPR_LPM_PULL_LOW,
++	MFPR_LPM_PULL_HIGH,
++	MFPR_LPM_FLOAT,
++};
++
++/* mapping of MFP_PULL_* definitions to MFPR_PULL_* register bits */
++const static unsigned long mfpr_pull[] = {
++	MFPR_PULL_NONE,
++	MFPR_PULL_LOW,
++	MFPR_PULL_HIGH,
++	MFPR_PULL_BOTH,
++};
++
++/* mapping of MFP_LPM_EDGE_* definitions to MFPR_EDGE_* register bits */
++const static unsigned long mfpr_edge[] = {
++	MFPR_EDGE_NONE,
++	MFPR_EDGE_RISE,
++	MFPR_EDGE_FALL,
++	MFPR_EDGE_BOTH,
++};
++
+ #define mfpr_readl(off)			\
+ 	__raw_readl(mfpr_mmio_base + (off))
+ 
+ #define mfpr_writel(off, val)		\
+ 	__raw_writel(val, mfpr_mmio_base + (off))
+ 
++#define mfp_configured(p)	((p)->config != -1)
++
+ /*
+  * perform a read-back of any MFPR register to make sure the
+  * previous writings are finished
+  */
+ #define mfpr_sync()	(void)__raw_readl(mfpr_mmio_base + 0)
+ 
+-static inline void __mfp_config(int pin, unsigned long val)
++static inline void __mfp_config_run(struct pxa3xx_mfp_pin *p)
+ {
+-	unsigned long off = mfp_table[pin].mfpr_off;
++	if (mfp_configured(p))
++		mfpr_writel(p->mfpr_off, p->mfpr_run);
++}
+ 
+-	mfp_table[pin].mfpr_val = val;
+-	mfpr_writel(off, val);
++static inline void __mfp_config_lpm(struct pxa3xx_mfp_pin *p)
++{
++	if (mfp_configured(p)) {
++		unsigned long mfpr_clr = (p->mfpr_run & ~MFPR_EDGE_BOTH) | MFPR_EDGE_CLEAR;
++		if (mfpr_clr != p->mfpr_run)
++			mfpr_writel(p->mfpr_off, mfpr_clr);
++		if (p->mfpr_lpm != mfpr_clr)
++			mfpr_writel(p->mfpr_off, p->mfpr_lpm);
++	}
+ }
+ 
+-void pxa3xx_mfp_config(mfp_cfg_t *mfp_cfgs, int num)
++void pxa3xx_mfp_config(unsigned long *mfp_cfgs, int num)
+ {
+-	int i, pin;
+-	unsigned long val, flags;
+-	mfp_cfg_t *mfp_cfg = mfp_cfgs;
++	unsigned long flags;
++	int i;
+ 
+ 	spin_lock_irqsave(&mfp_spin_lock, flags);
+ 
+-	for (i = 0; i < num; i++, mfp_cfg++) {
+-		pin = MFP_CFG_PIN(*mfp_cfg);
+-		val = MFP_CFG_VAL(*mfp_cfg);
++	for (i = 0; i < num; i++, mfp_cfgs++) {
++		unsigned long tmp, c = *mfp_cfgs;
++		struct pxa3xx_mfp_pin *p;
++		int pin, af, drv, lpm, edge, pull;
+ 
++		pin = MFP_PIN(c);
+ 		BUG_ON(pin >= MFP_PIN_MAX);
+-
+-		__mfp_config(pin, val);
++		p = &mfp_table[pin];
++
++		af  = MFP_AF(c);
++		drv = MFP_DS(c);
++		lpm = MFP_LPM_STATE(c);
++		edge = MFP_LPM_EDGE(c);
++		pull = MFP_PULL(c);
++
++		/* run-mode pull settings will conflict with MFPR bits of
++		 * low power mode state,  calculate mfpr_run and mfpr_lpm
++		 * individually if pull != MFP_PULL_NONE
++		 */
++		tmp = MFPR_AF_SEL(af) | MFPR_DRIVE(drv);
++
++		if (likely(pull == MFP_PULL_NONE)) {
++			p->mfpr_run = tmp | mfpr_lpm[lpm] | mfpr_edge[edge];
++			p->mfpr_lpm = p->mfpr_run;
++		} else {
++			p->mfpr_lpm = tmp | mfpr_lpm[lpm] | mfpr_edge[edge];
++			p->mfpr_run = tmp | mfpr_pull[pull];
++		}
++
++		p->config = c; __mfp_config_run(p);
+ 	}
+ 
+ 	mfpr_sync();
+@@ -96,140 +165,82 @@ void pxa3xx_mfp_write(int mfp, unsigned long val)
+ 	spin_unlock_irqrestore(&mfp_spin_lock, flags);
+ }
+ 
+-void pxa3xx_mfp_set_afds(int mfp, int af, int ds)
+-{
+-	uint32_t mfpr_off, mfpr_val;
+-	unsigned long flags;
+-
+-	BUG_ON(mfp >= MFP_PIN_MAX);
+-
+-	spin_lock_irqsave(&mfp_spin_lock, flags);
+-	mfpr_off = mfp_table[mfp].mfpr_off;
+-
+-	mfpr_val = mfpr_readl(mfpr_off);
+-	mfpr_val &= ~(MFPR_AF_MASK | MFPR_DRV_MASK);
+-	mfpr_val |= (((af & 0x7) << MFPR_ALT_OFFSET) |
+-		     ((ds & 0x7) << MFPR_DRV_OFFSET));
+-
+-	mfpr_writel(mfpr_off, mfpr_val);
+-	mfpr_sync();
+-
+-	spin_unlock_irqrestore(&mfp_spin_lock, flags);
+-}
+-
+-void pxa3xx_mfp_set_rdh(int mfp, int rdh)
++void __init pxa3xx_mfp_init_addr(struct pxa3xx_mfp_addr_map *map)
+ {
+-	uint32_t mfpr_off, mfpr_val;
+-	unsigned long flags;
+-
+-	BUG_ON(mfp >= MFP_PIN_MAX);
++	struct pxa3xx_mfp_addr_map *p;
++	unsigned long offset, flags;
++	int i;
+ 
+ 	spin_lock_irqsave(&mfp_spin_lock, flags);
+ 
+-	mfpr_off = mfp_table[mfp].mfpr_off;
+-
+-	mfpr_val = mfpr_readl(mfpr_off);
+-	mfpr_val &= ~MFPR_RDH_MASK;
+-
+-	if (likely(rdh))
+-		mfpr_val |= (1u << MFPR_SS_OFFSET);
++	for (p = map; p->start != MFP_PIN_INVALID; p++) {
++		offset = p->offset;
++		i = p->start;
+ 
+-	mfpr_writel(mfpr_off, mfpr_val);
+-	mfpr_sync();
++		do {
++			mfp_table[i].mfpr_off = offset;
++			mfp_table[i].mfpr_run = 0;
++			mfp_table[i].mfpr_lpm = 0;
++			offset += 4; i++;
++		} while ((i <= p->end) && (p->end != -1));
++	}
+ 
+ 	spin_unlock_irqrestore(&mfp_spin_lock, flags);
+ }
+ 
+-void pxa3xx_mfp_set_lpm(int mfp, int lpm)
++void __init pxa3xx_init_mfp(void)
+ {
+-	uint32_t mfpr_off, mfpr_val;
+-	unsigned long flags;
+-
+-	BUG_ON(mfp >= MFP_PIN_MAX);
+-
+-	spin_lock_irqsave(&mfp_spin_lock, flags);
+-
+-	mfpr_off = mfp_table[mfp].mfpr_off;
+-	mfpr_val = mfpr_readl(mfpr_off);
+-	mfpr_val &= ~MFPR_LPM_MASK;
+-
+-	if (lpm & 0x1) mfpr_val |= 1u << MFPR_SON_OFFSET;
+-	if (lpm & 0x2) mfpr_val |= 1u << MFPR_SD_OFFSET;
+-	if (lpm & 0x4) mfpr_val |= 1u << MFPR_PU_OFFSET;
+-	if (lpm & 0x8) mfpr_val |= 1u << MFPR_PD_OFFSET;
+-	if (lpm &0x10) mfpr_val |= 1u << MFPR_PS_OFFSET;
+-
+-	mfpr_writel(mfpr_off, mfpr_val);
+-	mfpr_sync();
++	int i;
+ 
+-	spin_unlock_irqrestore(&mfp_spin_lock, flags);
++	for (i = 0; i < ARRAY_SIZE(mfp_table); i++)
++		mfp_table[i].config = -1;
+ }
+ 
+-void pxa3xx_mfp_set_pull(int mfp, int pull)
++#ifdef CONFIG_PM
++/*
++ * Configure the MFPs appropriately for suspend/resume.
++ * FIXME: this should probably depend on which system state we're
++ * entering - for instance, we might not want to place MFP pins in
++ * a pull-down mode if they're an active low chip select, and we're
++ * just entering standby.
++ */
++static int pxa3xx_mfp_suspend(struct sys_device *d, pm_message_t state)
+ {
+-	uint32_t mfpr_off, mfpr_val;
+-	unsigned long flags;
+-
+-	BUG_ON(mfp >= MFP_PIN_MAX);
+-
+-	spin_lock_irqsave(&mfp_spin_lock, flags);
++	int pin;
+ 
+-	mfpr_off = mfp_table[mfp].mfpr_off;
+-	mfpr_val = mfpr_readl(mfpr_off);
+-	mfpr_val &= ~MFPR_PULL_MASK;
+-	mfpr_val |= ((pull & 0x7u) << MFPR_PD_OFFSET);
+-
+-	mfpr_writel(mfpr_off, mfpr_val);
+-	mfpr_sync();
+-
+-	spin_unlock_irqrestore(&mfp_spin_lock, flags);
++	for (pin = 0; pin < ARRAY_SIZE(mfp_table); pin++) {
++		struct pxa3xx_mfp_pin *p = &mfp_table[pin];
++		__mfp_config_lpm(p);
++	}
++	return 0;
+ }
+ 
+-void pxa3xx_mfp_set_edge(int mfp, int edge)
++static int pxa3xx_mfp_resume(struct sys_device *d)
+ {
+-	uint32_t mfpr_off, mfpr_val;
+-	unsigned long flags;
+-
+-	BUG_ON(mfp >= MFP_PIN_MAX);
+-
+-	spin_lock_irqsave(&mfp_spin_lock, flags);
+-
+-	mfpr_off = mfp_table[mfp].mfpr_off;
+-	mfpr_val = mfpr_readl(mfpr_off);
+-
+-	mfpr_val &= ~MFPR_EDGE_MASK;
+-	mfpr_val |= (edge & 0x3u) << MFPR_ERE_OFFSET;
+-	mfpr_val |= (!edge & 0x1) << MFPR_EC_OFFSET;
++	int pin;
+ 
+-	mfpr_writel(mfpr_off, mfpr_val);
+-	mfpr_sync();
+-
+-	spin_unlock_irqrestore(&mfp_spin_lock, flags);
++	for (pin = 0; pin < ARRAY_SIZE(mfp_table); pin++) {
++		struct pxa3xx_mfp_pin *p = &mfp_table[pin];
++		__mfp_config_run(p);
++	}
++	return 0;
+ }
+ 
+-void __init pxa3xx_mfp_init_addr(struct pxa3xx_mfp_addr_map *map)
+-{
+-	struct pxa3xx_mfp_addr_map *p;
+-	unsigned long offset, flags;
+-	int i;
+-
+-	spin_lock_irqsave(&mfp_spin_lock, flags);
+-
+-	for (p = map; p->start != MFP_PIN_INVALID; p++) {
+-		offset = p->offset;
+-		i = p->start;
+-
+-		do {
+-			mfp_table[i].mfpr_off = offset;
+-			mfp_table[i].mfpr_val = 0;
+-			offset += 4; i++;
+-		} while ((i <= p->end) && (p->end != -1));
+-	}
++static struct sysdev_class mfp_sysclass = {
++	set_kset_name("mfp"),
++	.suspend	= pxa3xx_mfp_suspend,
++	.resume 	= pxa3xx_mfp_resume,
++};
+ 
+-	spin_unlock_irqrestore(&mfp_spin_lock, flags);
+-}
++static struct sys_device mfp_device = {
++	.id		= 0,
++	.cls		= &mfp_sysclass,
++};
+ 
+-void __init pxa3xx_init_mfp(void)
++static int __init mfp_init_devicefs(void)
+ {
+-	memset(mfp_table, 0, sizeof(mfp_table));
++	sysdev_class_register(&mfp_sysclass);
++	return sysdev_register(&mfp_device);
+ }
++device_initcall(mfp_init_devicefs);
++#endif
+diff --git a/arch/arm/mach-pxa/pcm027.c b/arch/arm/mach-pxa/pcm027.c
+new file mode 100644
+index 0000000..540c3bb
+--- /dev/null
++++ b/arch/arm/mach-pxa/pcm027.c
+@@ -0,0 +1,216 @@
++/*
++ *  linux/arch/arm/mach-pxa/pcm027.c
++ *  Support for the Phytec phyCORE-PXA270 CPU card (aka PCM-027).
++ *
++ *  Refer
++ *   http://www.phytec.com/products/sbc/ARM-XScale/phyCORE-XScale-PXA270.html
++ *  for additional hardware info
++ *
++ *  Author:	Juergen Kilb
++ *  Created:	April 05, 2005
++ *  Copyright:	Phytec Messtechnik GmbH
++ *  e-Mail:	armlinux at phytec.de
++ *
++ *  based on Intel Mainstone Board
++ *
++ *  Copyright 2007 Juergen Beisert @ Pengutronix (j.beisert at pengutronix.de)
++ *
++ *  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/irq.h>
++#include <linux/platform_device.h>
++#include <linux/mtd/physmap.h>
++#include <linux/spi/spi.h>
++#include <linux/leds.h>
++#include <asm/mach-types.h>
++#include <asm/mach/arch.h>
++#include <asm/arch/hardware.h>
++#include <asm/arch/pxa-regs.h>
++#include <asm/arch/pxa2xx_spi.h>
++#include <asm/arch/pcm027.h>
++#include "generic.h"
++
++/*
++ * ABSTRACT:
++ *
++ * The PXA270 processor comes with a bunch of hardware on its silicon.
++ * Not all of this hardware can be used at the same time and not all
++ * is routed to module's connectors. Also it depends on the baseboard, what
++ * kind of hardware can be used in which way.
++ * -> So this file supports the main devices on the CPU card only!
++ * Refer pcm990-baseboard.c how to extend this features to get a full
++ * blown system with many common interfaces.
++ *
++ * The PCM-027 supports the following interfaces through its connectors and
++ * will be used in pcm990-baseboard.c:
++ *
++ * - LCD support
++ * - MMC support
++ * - IDE/CF card
++ * - FFUART
++ * - BTUART
++ * - IRUART
++ * - AC97
++ * - SSP
++ * - SSP3
++ *
++ * Claimed GPIOs:
++ * GPIO0 -> IRQ input from RTC
++ * GPIO2 -> SYS_ENA*)
++ * GPIO3 -> PWR_SCL
++ * GPIO4 -> PWR_SDA
++ * GPIO5 -> PowerCap0*)
++ * GPIO6 -> PowerCap1*)
++ * GPIO7 -> PowerCap2*)
++ * GPIO8 -> PowerCap3*)
++ * GPIO15 -> /CS1
++ * GPIO20 -> /CS2
++ * GPIO21 -> /CS3
++ * GPIO33 -> /CS5 network controller select
++ * GPIO52 -> IRQ from network controller
++ * GPIO78 -> /CS2
++ * GPIO80 -> /CS4
++ * GPIO90 -> LED0
++ * GPIO91 -> LED1
++ * GPIO114 -> IRQ from CAN controller
++ * GPIO117 -> SCL
++ * GPIO118 -> SDA
++ *
++ * *) CPU internal use only
++ */
++
++/*
++ * SMC91x network controller specific stuff
++ */
++static struct resource smc91x_resources[] = {
++	[0] = {
++		.start	= PCM027_ETH_PHYS + 0x300,
++		.end	= PCM027_ETH_PHYS + PCM027_ETH_SIZE,
++		.flags	= IORESOURCE_MEM,
++	},
++	[1] = {
++		.start	= PCM027_ETH_IRQ,
++		.end	= PCM027_ETH_IRQ,
++		/* note: smc91x's driver doesn't use the trigger bits yet */
++		.flags	= IORESOURCE_IRQ | PCM027_ETH_IRQ_EDGE,
++	}
++};
++
++static struct platform_device smc91x_device = {
++	.name		= "smc91x",
++	.id		= 0,
++	.num_resources	= ARRAY_SIZE(smc91x_resources),
++	.resource	= smc91x_resources,
++};
++
++static struct physmap_flash_data pcm027_flash_data = {
++	.width  = 4,
++};
++
++static struct resource pcm027_flash_resource = {
++	.start          = PCM027_FLASH_PHYS,
++	.end            = PCM027_FLASH_PHYS + PCM027_FLASH_SIZE - 1 ,
++	.flags          = IORESOURCE_MEM,
++};
++
++static struct platform_device pcm027_flash = {
++	.name           = "physmap-flash",
++	.id             = 0,
++	.dev            = {
++		.platform_data  = &pcm027_flash_data,
++	},
++	.resource       = &pcm027_flash_resource,
++	.num_resources  = 1,
++};
++
++#ifdef CONFIG_LEDS_GPIO
++
++static struct gpio_led pcm027_led[] = {
++	{
++		.name = "led0:red",	/* FIXME */
++		.gpio = PCM027_LED_CPU
++	},
++	{
++		.name = "led1:green",	/* FIXME */
++		.gpio = PCM027_LED_HEARD_BEAT
++	},
++};
++
++static struct gpio_led_platform_data pcm027_led_data = {
++	.num_leds	= ARRAY_SIZE(pcm027_led),
++	.leds		= pcm027_led
++};
++
++static struct platform_device pcm027_led_dev = {
++	.name		= "leds-gpio",
++	.id		= 0,
++	.dev		= {
++		.platform_data	= &pcm027_led_data,
++	},
++};
++
++#endif /* CONFIG_LEDS_GPIO */
++
++/*
++ * declare the available device resources on this board
++ */
++static struct platform_device *devices[] __initdata = {
++	&smc91x_device,
++	&pcm027_flash,
++#ifdef CONFIG_LEDS_GPIO
++	&pcm027_led_dev
++#endif
++};
++
++/*
++ * pcm027_init - breath some life into the board
++ */
++static void __init pcm027_init(void)
++{
++	/* system bus arbiter setting
++	 * - Core_Park
++	 * - LCD_wt:DMA_wt:CORE_Wt = 2:3:4
++	 */
++	ARB_CNTRL = ARB_CORE_PARK | 0x234;
++
++	platform_add_devices(devices, ARRAY_SIZE(devices));
++
++	/* 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 */
++
++	/* at last call the baseboard to initialize itself */
++#ifdef CONFIG_MACH_PCM990_BASEBOARD
++	pcm990_baseboard_init();
++#endif
++}
++
++static void __init pcm027_map_io(void)
++{
++	pxa_map_io();
++
++	/* initialize sleep mode regs (wake-up sources, etc) */
++	PGSR0 = 0x01308000;
++	PGSR1 = 0x00CF0002;
++	PGSR2 = 0x0E294000;
++	PGSR3 = 0x0000C000;
++	PWER  = 0x40000000 | PWER_GPIO0 | PWER_GPIO1;
++	PRER  = 0x00000000;
++	PFER  = 0x00000003;
++}
++
++MACHINE_START(PCM027, "Phytec Messtechnik GmbH phyCORE-PXA270")
++	/* Maintainer: Pengutronix */
++	.boot_params	= 0xa0000100,
++	.phys_io	= 0x40000000,
++	.io_pg_offst	= (io_p2v(0x40000000) >> 18) & 0xfffc,
++	.map_io		= pcm027_map_io,
++	.init_irq	= pxa27x_init_irq,
++	.timer		= &pxa_timer,
++	.init_machine	= pcm027_init,
++MACHINE_END
+diff --git a/arch/arm/mach-pxa/pcm990-baseboard.c b/arch/arm/mach-pxa/pcm990-baseboard.c
+new file mode 100644
+index 0000000..3dda16a
+--- /dev/null
++++ b/arch/arm/mach-pxa/pcm990-baseboard.c
+@@ -0,0 +1,330 @@
++/*
++ *  arch/arm/mach-pxa/pcm990-baseboard.c
++ *  Support for the Phytec phyCORE-PXA270 Development Platform (PCM-990).
++ *
++ *  Refer
++ *   http://www.phytec.com/products/rdk/ARM-XScale/phyCORE-XScale-PXA270.html
++ *  for additional hardware info
++ *
++ *  Author:	Juergen Kilb
++ *  Created:	April 05, 2005
++ *  Copyright:	Phytec Messtechnik GmbH
++ *  e-Mail:	armlinux at phytec.de
++ *
++ *  based on Intel Mainstone Board
++ *
++ *  Copyright 2007 Juergen Beisert @ Pengutronix (j.beisert at pengutronix.de)
++ *
++ *  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/irq.h>
++#include <linux/platform_device.h>
++#include <linux/ide.h>
++#include <asm/mach/map.h>
++#include <asm/arch/pxa-regs.h>
++#include <asm/arch/mmc.h>
++#include <asm/arch/ohci.h>
++#include <asm/arch/pcm990_baseboard.h>
++
++/*
++ * The PCM-990 development baseboard uses PCM-027's hardeware in the
++ * following way:
++ *
++ * - LCD support is in use
++ *  - GPIO16 is output for back light on/off with PWM
++ *  - GPIO58 ... GPIO73 are outputs for display data
++ *  - GPIO74 is output output for LCDFCLK
++ *  - GPIO75 is output for LCDLCLK
++ *  - GPIO76 is output for LCDPCLK
++ *  - GPIO77 is output for LCDBIAS
++ * - MMC support is in use
++ *  - GPIO32 is output for MMCCLK
++ *  - GPIO92 is MMDAT0
++ *  - GPIO109 is MMDAT1
++ *  - GPIO110 is MMCS0
++ *  - GPIO111 is MMCS1
++ *  - GPIO112 is MMCMD
++ * - IDE/CF card is in use
++ *  - GPIO48 is output /POE
++ *  - GPIO49 is output /PWE
++ *  - GPIO50 is output /PIOR
++ *  - GPIO51 is output /PIOW
++ *  - GPIO54 is output /PCE2
++ *  - GPIO55 is output /PREG
++ *  - GPIO56 is input /PWAIT
++ *  - GPIO57 is output /PIOS16
++ *  - GPIO79 is output PSKTSEL
++ *  - GPIO85 is output /PCE1
++ * - FFUART is in use
++ *  - GPIO34 is input FFRXD
++ *  - GPIO35 is input FFCTS
++ *  - GPIO36 is input FFDCD
++ *  - GPIO37 is input FFDSR
++ *  - GPIO38 is input FFRI
++ *  - GPIO39 is output FFTXD
++ *  - GPIO40 is output FFDTR
++ *  - GPIO41 is output FFRTS
++ * - BTUART is in use
++ *  - GPIO42 is input BTRXD
++ *  - GPIO43 is output BTTXD
++ *  - GPIO44 is input BTCTS
++ *  - GPIO45 is output BTRTS
++ * - IRUART is in use
++ *  - GPIO46 is input STDRXD
++ *  - GPIO47 is output STDTXD
++ * - AC97 is in use*)
++ *  - GPIO28 is input AC97CLK
++ *  - GPIO29 is input AC97DatIn
++ *  - GPIO30 is output AC97DatO
++ *  - GPIO31 is output AC97SYNC
++ *  - GPIO113 is output AC97_RESET
++ * - SSP is in use
++ *  - GPIO23 is output SSPSCLK
++ *  - GPIO24 is output chip select to Max7301
++ *  - GPIO25 is output SSPTXD
++ *  - GPIO26 is input SSPRXD
++ *  - GPIO27 is input for Max7301 IRQ
++ *  - GPIO53 is input SSPSYSCLK
++ * - SSP3 is in use
++ *  - GPIO81 is output SSPTXD3
++ *  - GPIO82 is input SSPRXD3
++ *  - GPIO83 is output SSPSFRM
++ *  - GPIO84 is output SSPCLK3
++ *
++ * Otherwise claimed GPIOs:
++ * GPIO1 -> IRQ from user switch
++ * GPIO9 -> IRQ from power management
++ * GPIO10 -> IRQ from WML9712 AC97 controller
++ * GPIO11 -> IRQ from IDE controller
++ * GPIO12 -> IRQ from CF controller
++ * GPIO13 -> IRQ from CF controller
++ * GPIO14 -> GPIO free
++ * GPIO15 -> /CS1 selects baseboard's Control CPLD (U7, 16 bit wide data path)
++ * GPIO19 -> GPIO free
++ * GPIO20 -> /SDCS2
++ * GPIO21 -> /CS3 PC card socket select
++ * GPIO33 -> /CS5  network controller select
++ * GPIO78 -> /CS2  (16 bit wide data path)
++ * GPIO80 -> /CS4  (16 bit wide data path)
++ * GPIO86 -> GPIO free
++ * GPIO87 -> GPIO free
++ * GPIO90 -> LED0 on CPU module
++ * GPIO91 -> LED1 on CPI module
++ * GPIO117 -> SCL
++ * GPIO118 -> SDA
++ */
++
++static unsigned long pcm990_irq_enabled;
++
++static void pcm990_mask_ack_irq(unsigned int irq)
++{
++	int pcm990_irq = (irq - PCM027_IRQ(0));
++	PCM990_INTMSKENA = (pcm990_irq_enabled &= ~(1 << pcm990_irq));
++}
++
++static void pcm990_unmask_irq(unsigned int irq)
++{
++	int pcm990_irq = (irq - PCM027_IRQ(0));
++	/* the irq can be acknowledged only if deasserted, so it's done here */
++	PCM990_INTSETCLR |= 1 << pcm990_irq;
++	PCM990_INTMSKENA  = (pcm990_irq_enabled |= (1 << pcm990_irq));
++}
++
++static struct irq_chip pcm990_irq_chip = {
++	.mask_ack	= pcm990_mask_ack_irq,
++	.unmask		= pcm990_unmask_irq,
++};
++
++static void pcm990_irq_handler(unsigned int irq, struct irq_desc *desc)
++{
++	unsigned long pending = (~PCM990_INTSETCLR) & pcm990_irq_enabled;
++
++	do {
++		GEDR(PCM990_CTRL_INT_IRQ_GPIO) =
++					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);
++		}
++		pending = (~PCM990_INTSETCLR) & pcm990_irq_enabled;
++	} while (pending);
++}
++
++static void __init pcm990_init_irq(void)
++{
++	int irq;
++
++	/* setup extra PCM990 irqs */
++	for (irq = PCM027_IRQ(0); irq <= PCM027_IRQ(3); irq++) {
++		set_irq_chip(irq, &pcm990_irq_chip);
++		set_irq_handler(irq, handle_level_irq);
++		set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
++	}
++
++	PCM990_INTMSKENA = 0x00;	/* disable all Interrupts */
++	PCM990_INTSETCLR = 0xFF;
++
++	set_irq_chained_handler(PCM990_CTRL_INT_IRQ, pcm990_irq_handler);
++	set_irq_type(PCM990_CTRL_INT_IRQ, PCM990_CTRL_INT_IRQ_EDGE);
++}
++
++static int pcm990_mci_init(struct device *dev, irq_handler_t mci_detect_int,
++			void *data)
++{
++	int err;
++
++	/*
++	 * enable 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);
++
++	err = request_irq(PCM027_MMCDET_IRQ, mci_detect_int, IRQF_DISABLED,
++			     "MMC card detect", data);
++	if (err)
++		printk(KERN_ERR "pcm990_mci_init: MMC/SD: can't request MMC "
++				"card detect IRQ\n");
++
++	return err;
++}
++
++static void pcm990_mci_setpower(struct device *dev, unsigned int vdd)
++{
++	struct pxamci_platform_data *p_d = dev->platform_data;
++
++	if ((1 << vdd) & p_d->ocr_mask)
++		__PCM990_CTRL_REG(PCM990_CTRL_PHYS + PCM990_CTRL_REG5) =
++						PCM990_CTRL_MMC2PWR;
++	else
++		__PCM990_CTRL_REG(PCM990_CTRL_PHYS + PCM990_CTRL_REG5) =
++						~PCM990_CTRL_MMC2PWR;
++}
++
++static void pcm990_mci_exit(struct device *dev, void *data)
++{
++	free_irq(PCM027_MMCDET_IRQ, data);
++}
++
++#define MSECS_PER_JIFFY (1000/HZ)
++
++static struct pxamci_platform_data pcm990_mci_platform_data = {
++	.detect_delay	= 250 / MSECS_PER_JIFFY,
++	.ocr_mask	= MMC_VDD_32_33 | MMC_VDD_33_34,
++	.init 		= pcm990_mci_init,
++	.setpower 	= pcm990_mci_setpower,
++	.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)
++{
++	pxa_gpio_mode(PCM990_USB_OVERCURRENT);
++	pxa_gpio_mode(PCM990_USB_PWR_EN);
++	/*
++	 * 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,
++};
++
++/*
++ * AC97 support
++ * Note: The connected AC97 mixer also reports interrupts at PCM990_AC97_IRQ
++ */
++static struct resource pxa27x_ac97_resources[] = {
++	[0] = {
++		.start  = 0x40500000,
++		.end	= 0x40500000 + 0xfff,
++		.flags  = IORESOURCE_MEM,
++	},
++	[1] = {
++		.start  = IRQ_AC97,
++		.end    = IRQ_AC97,
++		.flags  = IORESOURCE_IRQ,
++	},
++};
++
++static u64 pxa_ac97_dmamask = 0xffffffffUL;
++
++static struct platform_device pxa27x_device_ac97 = {
++	.name           = "pxa2xx-ac97",
++	.id             = -1,
++	.dev            = {
++		.dma_mask = &pxa_ac97_dmamask,
++		.coherent_dma_mask = 0xffffffff,
++	},
++	.num_resources  = ARRAY_SIZE(pxa27x_ac97_resources),
++	.resource       = pxa27x_ac97_resources,
++};
++
++/*
++ * enable generic access to the base board control CPLDs U6 and U7
++ */
++static struct map_desc pcm990_io_desc[] __initdata = {
++	{
++		.virtual	= PCM990_CTRL_BASE,
++		.pfn		= __phys_to_pfn(PCM990_CTRL_PHYS),
++		.length		= PCM990_CTRL_SIZE,
++		.type		= MT_DEVICE	/* CPLD */
++	}, {
++		.virtual	= PCM990_CF_PLD_BASE,
++		.pfn		= __phys_to_pfn(PCM990_CF_PLD_PHYS),
++		.length		= PCM990_CF_PLD_SIZE,
++		.type		= MT_DEVICE	/* CPLD */
++	}
++};
++
++/*
++ * system init for baseboard usage. Will be called by pcm027 init.
++ *
++ * Add platform devices present on this baseboard and init
++ * them from CPU side as far as required to use them later on
++ */
++void __init pcm990_baseboard_init(void)
++{
++	/* register CPLD access */
++	iotable_init(pcm990_io_desc, ARRAY_SIZE(pcm990_io_desc));
++
++	/* register CPLD's IRQ controller */
++	pcm990_init_irq();
++
++	platform_device_register(&pxa27x_device_ac97);
++
++	/* MMC */
++	pxa_set_mci_info(&pcm990_mci_platform_data);
++
++	/* USB host */
++	pxa_set_ohci_info(&pcm990_ohci_platform_data);
++
++	printk(KERN_INFO"PCM-990 Evaluation baseboard initialized\n");
++}
+diff --git a/arch/arm/mach-pxa/pm.c b/arch/arm/mach-pxa/pm.c
+index a941c71..039194c 100644
+--- a/arch/arm/mach-pxa/pm.c
++++ b/arch/arm/mach-pxa/pm.c
+@@ -38,34 +38,37 @@ int pxa_pm_enter(suspend_state_t state)
+ 		iwmmxt_task_disable(NULL);
+ #endif
+ 
+-	pxa_cpu_pm_fns->save(sleep_save);
++	/* skip registers saving for standby */
++	if (state != PM_SUSPEND_STANDBY) {
++		pxa_cpu_pm_fns->save(sleep_save);
++		/* before sleeping, calculate and save a checksum */
++		for (i = 0; i < pxa_cpu_pm_fns->save_size - 1; i++)
++			sleep_save_checksum += sleep_save[i];
++	}
+ 
+ 	/* Clear sleep reset status */
+ 	RCSR = RCSR_SMR;
+ 
+-	/* before sleeping, calculate and save a checksum */
+-	for (i = 0; i < pxa_cpu_pm_fns->save_size - 1; i++)
+-		sleep_save_checksum += sleep_save[i];
+-
+ 	/* *** go zzz *** */
+ 	pxa_cpu_pm_fns->enter(state);
+ 	cpu_init();
+ 
+-	/* after sleeping, validate the checksum */
+-	for (i = 0; i < pxa_cpu_pm_fns->save_size - 1; i++)
+-		checksum += sleep_save[i];
++	if (state != PM_SUSPEND_STANDBY) {
++		/* after sleeping, validate the checksum */
++		for (i = 0; i < pxa_cpu_pm_fns->save_size - 1; i++)
++			checksum += sleep_save[i];
+ 
+-	/* if invalid, display message and wait for a hardware reset */
+-	if (checksum != sleep_save_checksum) {
++		/* if invalid, display message and wait for a hardware reset */
++		if (checksum != sleep_save_checksum) {
+ #ifdef CONFIG_ARCH_LUBBOCK
+-		LUB_HEXLED = 0xbadbadc5;
++			LUB_HEXLED = 0xbadbadc5;
+ #endif
+-		while (1)
+-			pxa_cpu_pm_fns->enter(state);
++			while (1)
++				pxa_cpu_pm_fns->enter(state);
++		}
++		pxa_cpu_pm_fns->restore(sleep_save);
+ 	}
+ 
+-	pxa_cpu_pm_fns->restore(sleep_save);
+-
+ 	pr_debug("*** made it back from resume\n");
+ 
+ 	return 0;
+diff --git a/arch/arm/mach-pxa/poodle.c b/arch/arm/mach-pxa/poodle.c
+index 655668d..dd54496 100644
+--- a/arch/arm/mach-pxa/poodle.c
++++ b/arch/arm/mach-pxa/poodle.c
+@@ -215,12 +215,10 @@ static int poodle_mci_init(struct device *dev, irq_handler_t poodle_detect_int,
+ 	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) {
++	if (err)
+ 		printk(KERN_ERR "poodle_mci_init: MMC/SD: can't request MMC card detect IRQ\n");
+-		return -1;
+-	}
+ 
+-	return 0;
++	return err;
+ }
+ 
+ static void poodle_mci_setpower(struct device *dev, unsigned int vdd)
+diff --git a/arch/arm/mach-pxa/pxa25x.c b/arch/arm/mach-pxa/pxa25x.c
+index 9732d5d..ddd05bf 100644
+--- a/arch/arm/mach-pxa/pxa25x.c
++++ b/arch/arm/mach-pxa/pxa25x.c
+@@ -111,21 +111,27 @@ static const struct clkops clk_pxa25x_lcd_ops = {
+  * 95.842MHz -> MMC 19.169MHz, I2C 31.949MHz, FICP 47.923MHz, USB 47.923MHz
+  * 147.456MHz -> UART 14.7456MHz, AC97 12.288MHz, I2S 5.672MHz (allegedly)
+  */
++static struct clk pxa25x_hwuart_clk =
++	INIT_CKEN("UARTCLK", HWUART, 14745600, 1, &pxa_device_hwuart.dev)
++;
++
+ static struct clk pxa25x_clks[] = {
+ 	INIT_CK("LCDCLK", LCD, &clk_pxa25x_lcd_ops, &pxa_device_fb.dev),
+ 	INIT_CKEN("UARTCLK", FFUART, 14745600, 1, &pxa_device_ffuart.dev),
+ 	INIT_CKEN("UARTCLK", BTUART, 14745600, 1, &pxa_device_btuart.dev),
+-	INIT_CKEN("UARTCLK", BTUART, 14745600, 1, &pxa_device_btuart.dev),
+ 	INIT_CKEN("UARTCLK", STUART, 14745600, 1, NULL),
+ 	INIT_CKEN("UDCCLK", USB, 47923000, 5, &pxa_device_udc.dev),
+ 	INIT_CKEN("MMCCLK", MMC, 19169000, 0, &pxa_device_mci.dev),
+ 	INIT_CKEN("I2CCLK", I2C, 31949000, 0, &pxa_device_i2c.dev),
++
++	INIT_CKEN("SSPCLK",  SSP, 3686400, 0, &pxa25x_device_ssp.dev),
++	INIT_CKEN("SSPCLK", NSSP, 3686400, 0, &pxa25x_device_nssp.dev),
++	INIT_CKEN("SSPCLK", ASSP, 3686400, 0, &pxa25x_device_assp.dev),
++
+ 	/*
+ 	INIT_CKEN("PWMCLK",  PWM0, 3686400,  0, NULL),
+ 	INIT_CKEN("PWMCLK",  PWM0, 3686400,  0, NULL),
+-	INIT_CKEN("SSPCLK",  SSP,  3686400,  0, NULL),
+ 	INIT_CKEN("I2SCLK",  I2S,  14745600, 0, NULL),
+-	INIT_CKEN("NSSPCLK", NSSP, 3686400,  0, NULL),
+ 	*/
+ 	INIT_CKEN("FICPCLK", FICP, 47923000, 0, NULL),
+ };
+@@ -213,8 +219,6 @@ static void pxa25x_cpu_pm_restore(unsigned long *sleep_save)
+ 
+ static void pxa25x_cpu_pm_enter(suspend_state_t state)
+ {
+-	CKEN = 0;
+-
+ 	switch (state) {
+ 	case PM_SUSPEND_MEM:
+ 		/* set resume return address */
+@@ -236,6 +240,8 @@ static void __init pxa25x_init_pm(void)
+ {
+ 	pxa_cpu_pm_fns = &pxa25x_cpu_pm_fns;
+ }
++#else
++static inline void pxa25x_init_pm(void) {}
+ #endif
+ 
+ /* PXA25x: supports wakeup from GPIO0..GPIO15 and RTC alarm
+@@ -287,30 +293,33 @@ void __init pxa25x_init_irq(void)
+ }
+ 
+ static struct platform_device *pxa25x_devices[] __initdata = {
+-	&pxa_device_mci,
+ 	&pxa_device_udc,
+-	&pxa_device_fb,
+ 	&pxa_device_ffuart,
+ 	&pxa_device_btuart,
+ 	&pxa_device_stuart,
+-	&pxa_device_i2c,
+ 	&pxa_device_i2s,
+-	&pxa_device_ficp,
+ 	&pxa_device_rtc,
++	&pxa25x_device_ssp,
++	&pxa25x_device_nssp,
++	&pxa25x_device_assp,
+ };
+ 
+ static int __init pxa25x_init(void)
+ {
+ 	int ret = 0;
+ 
++	/* Only add HWUART for PXA255/26x; PXA210/250/27x do not have it. */
++	if (cpu_is_pxa25x())
++		clks_register(&pxa25x_hwuart_clk, 1);
++
+ 	if (cpu_is_pxa21x() || cpu_is_pxa25x()) {
+ 		clks_register(pxa25x_clks, ARRAY_SIZE(pxa25x_clks));
+ 
+ 		if ((ret = pxa_init_dma(16)))
+ 			return ret;
+-#ifdef CONFIG_PM
++
+ 		pxa25x_init_pm();
+-#endif
++
+ 		ret = platform_add_devices(pxa25x_devices,
+ 					   ARRAY_SIZE(pxa25x_devices));
+ 	}
+diff --git a/arch/arm/mach-pxa/pxa27x.c b/arch/arm/mach-pxa/pxa27x.c
+index 8e126e6..96cf274 100644
+--- a/arch/arm/mach-pxa/pxa27x.c
++++ b/arch/arm/mach-pxa/pxa27x.c
+@@ -21,9 +21,11 @@
+ #include <asm/irq.h>
+ #include <asm/arch/irqs.h>
+ #include <asm/arch/pxa-regs.h>
++#include <asm/arch/pxa2xx-regs.h>
+ #include <asm/arch/ohci.h>
+ #include <asm/arch/pm.h>
+ #include <asm/arch/dma.h>
++#include <asm/arch/i2c.h>
+ 
+ #include "generic.h"
+ #include "devices.h"
+@@ -150,11 +152,12 @@ static struct clk pxa27x_clks[] = {
+ 	INIT_CKEN("I2CCLK", PWRI2C, 13000000, 0, &pxa27x_device_i2c_power.dev),
+ 	INIT_CKEN("KBDCLK", KEYPAD, 32768, 0, NULL),
+ 
++	INIT_CKEN("SSPCLK", SSP1, 13000000, 0, &pxa27x_device_ssp1.dev),
++	INIT_CKEN("SSPCLK", SSP2, 13000000, 0, &pxa27x_device_ssp2.dev),
++	INIT_CKEN("SSPCLK", SSP3, 13000000, 0, &pxa27x_device_ssp3.dev),
++
+ 	/*
+ 	INIT_CKEN("PWMCLK",  PWM0, 13000000, 0, NULL),
+-	INIT_CKEN("SSPCLK",  SSP1, 13000000, 0, NULL),
+-	INIT_CKEN("SSPCLK",  SSP2, 13000000, 0, NULL),
+-	INIT_CKEN("SSPCLK",  SSP3, 13000000, 0, NULL),
+ 	INIT_CKEN("MSLCLK",  MSL,  48000000, 0, NULL),
+ 	INIT_CKEN("USIMCLK", USIM, 48000000, 0, NULL),
+ 	INIT_CKEN("MSTKCLK", MEMSTK, 19500000, 0, NULL),
+@@ -263,12 +266,6 @@ void pxa27x_cpu_pm_enter(suspend_state_t state)
+ {
+ 	extern void pxa_cpu_standby(void);
+ 
+-	if (state == PM_SUSPEND_STANDBY)
+-		CKEN = (1 << CKEN_MEMC) | (1 << CKEN_OSTIMER) |
+-			(1 << CKEN_LCD) | (1 << CKEN_PWM0);
+-	else
+-		CKEN = (1 << CKEN_MEMC) | (1 << CKEN_OSTIMER);
+-
+ 	/* ensure voltage-change sequencer not initiated, which hangs */
+ 	PCFR &= ~PCFR_FVC;
+ 
+@@ -304,6 +301,8 @@ static void __init pxa27x_init_pm(void)
+ {
+ 	pxa_cpu_pm_fns = &pxa27x_cpu_pm_fns;
+ }
++#else
++static inline void pxa27x_init_pm(void) {}
+ #endif
+ 
+ /* PXA27x:  Various gpios can issue wakeup events.  This logic only
+@@ -373,37 +372,6 @@ void __init pxa27x_init_irq(void)
+  * device registration specific to PXA27x.
+  */
+ 
+-static u64 pxa27x_dmamask = 0xffffffffUL;
+-
+-static struct resource pxa27x_ohci_resources[] = {
+-	[0] = {
+-		.start  = 0x4C000000,
+-		.end    = 0x4C00ff6f,
+-		.flags  = IORESOURCE_MEM,
+-	},
+-	[1] = {
+-		.start  = IRQ_USBH1,
+-		.end    = IRQ_USBH1,
+-		.flags  = IORESOURCE_IRQ,
+-	},
+-};
+-
+-struct platform_device pxa27x_device_ohci = {
+-	.name		= "pxa27x-ohci",
+-	.id		= -1,
+-	.dev		= {
+-		.dma_mask = &pxa27x_dmamask,
+-		.coherent_dma_mask = 0xffffffff,
+-	},
+-	.num_resources  = ARRAY_SIZE(pxa27x_ohci_resources),
+-	.resource       = pxa27x_ohci_resources,
+-};
+-
+-void __init pxa_set_ohci_info(struct pxaohci_platform_data *info)
+-{
+-	pxa27x_device_ohci.dev.platform_data = info;
+-}
+-
+ static struct resource i2c_power_resources[] = {
+ 	{
+ 		.start	= 0x40f00180,
+@@ -423,19 +391,22 @@ struct platform_device pxa27x_device_i2c_power = {
+ 	.num_resources	= ARRAY_SIZE(i2c_power_resources),
+ };
+ 
++void __init pxa_set_i2c_power_info(struct i2c_pxa_platform_data *info)
++{
++	pxa27x_device_i2c_power.dev.platform_data = info;
++}
++
+ static struct platform_device *devices[] __initdata = {
+-	&pxa_device_mci,
+ 	&pxa_device_udc,
+-	&pxa_device_fb,
+ 	&pxa_device_ffuart,
+ 	&pxa_device_btuart,
+ 	&pxa_device_stuart,
+-	&pxa_device_i2c,
+ 	&pxa_device_i2s,
+-	&pxa_device_ficp,
+ 	&pxa_device_rtc,
+ 	&pxa27x_device_i2c_power,
+-	&pxa27x_device_ohci,
++	&pxa27x_device_ssp1,
++	&pxa27x_device_ssp2,
++	&pxa27x_device_ssp3,
+ };
+ 
+ static int __init pxa27x_init(void)
+@@ -446,9 +417,9 @@ static int __init pxa27x_init(void)
+ 
+ 		if ((ret = pxa_init_dma(32)))
+ 			return ret;
+-#ifdef CONFIG_PM
++
+ 		pxa27x_init_pm();
+-#endif
++
+ 		ret = platform_add_devices(devices, ARRAY_SIZE(devices));
+ 	}
+ 	return ret;
+diff --git a/arch/arm/mach-pxa/pxa3xx.c b/arch/arm/mach-pxa/pxa3xx.c
+index 61d9c9d..5cbf057 100644
+--- a/arch/arm/mach-pxa/pxa3xx.c
++++ b/arch/arm/mach-pxa/pxa3xx.c
+@@ -19,6 +19,7 @@
+ #include <linux/pm.h>
+ #include <linux/platform_device.h>
+ #include <linux/irq.h>
++#include <linux/io.h>
+ 
+ #include <asm/hardware.h>
+ #include <asm/arch/pxa3xx-regs.h>
+@@ -86,7 +87,7 @@ unsigned int pxa3xx_get_clk_frequency_khz(int info)
+ 			HSS / 1000000, (HSS % 1000000) / 10000);
+ 	}
+ 
+-	return CLK;
++	return CLK / 1000;
+ }
+ 
+ /*
+@@ -189,8 +190,237 @@ static struct clk pxa3xx_clks[] = {
+ 
+ 	PXA3xx_CKEN("I2CCLK", I2C,  32842000, 0, &pxa_device_i2c.dev),
+ 	PXA3xx_CKEN("UDCCLK", UDC,  48000000, 5, &pxa_device_udc.dev),
++	PXA3xx_CKEN("USBCLK", USBH, 48000000, 0, &pxa27x_device_ohci.dev),
++
++	PXA3xx_CKEN("SSPCLK", SSP1, 13000000, 0, &pxa27x_device_ssp1.dev),
++	PXA3xx_CKEN("SSPCLK", SSP2, 13000000, 0, &pxa27x_device_ssp2.dev),
++	PXA3xx_CKEN("SSPCLK", SSP3, 13000000, 0, &pxa27x_device_ssp3.dev),
++	PXA3xx_CKEN("SSPCLK", SSP4, 13000000, 0, &pxa3xx_device_ssp4.dev),
++
++	PXA3xx_CKEN("MMCCLK", MMC1, 19500000, 0, &pxa_device_mci.dev),
++	PXA3xx_CKEN("MMCCLK", MMC2, 19500000, 0, &pxa3xx_device_mci2.dev),
++	PXA3xx_CKEN("MMCCLK", MMC3, 19500000, 0, &pxa3xx_device_mci3.dev),
++};
++
++#ifdef CONFIG_PM
++#define SLEEP_SAVE_SIZE	4
++
++#define ISRAM_START	0x5c000000
++#define ISRAM_SIZE	SZ_256K
++
++static void __iomem *sram;
++static unsigned long wakeup_src;
++
++static void pxa3xx_cpu_pm_save(unsigned long *sleep_save)
++{
++	pr_debug("PM: CKENA=%08x CKENB=%08x\n", CKENA, CKENB);
++
++	if (CKENA & (1 << CKEN_USBH)) {
++		printk(KERN_ERR "PM: USB host clock not stopped?\n");
++		CKENA &= ~(1 << CKEN_USBH);
++	}
++//	CKENA |= 1 << (CKEN_ISC & 31);
++
++	/*
++	 * Low power modes require the HSIO2 clock to be enabled.
++	 */
++	CKENB |= 1 << (CKEN_HSIO2 & 31);
++}
++
++static void pxa3xx_cpu_pm_restore(unsigned long *sleep_save)
++{
++	CKENB &= ~(1 << (CKEN_HSIO2 & 31));
++}
++
++/*
++ * Enter a standby mode (S0D1C2 or S0D2C2).  Upon wakeup, the dynamic
++ * memory controller has to be reinitialised, so we place some code
++ * in the SRAM to perform this function.
++ *
++ * We disable FIQs across the standby - otherwise, we might receive a
++ * FIQ while the SDRAM is unavailable.
++ */
++static void pxa3xx_cpu_standby(unsigned int pwrmode)
++{
++	extern const char pm_enter_standby_start[], pm_enter_standby_end[];
++	void (*fn)(unsigned int) = (void __force *)(sram + 0x8000);
++
++	memcpy_toio(sram + 0x8000, pm_enter_standby_start,
++		    pm_enter_standby_end - pm_enter_standby_start);
++
++	AD2D0SR = ~0;
++	AD2D1SR = ~0;
++	AD2D0ER = wakeup_src;
++	AD2D1ER = 0;
++	ASCR = ASCR;
++	ARSR = ARSR;
++
++	local_fiq_disable();
++	fn(pwrmode);
++	local_fiq_enable();
++
++	AD2D0ER = 0;
++	AD2D1ER = 0;
++
++	printk("PM: AD2D0SR=%08x ASCR=%08x\n", AD2D0SR, ASCR);
++}
++
++static void pxa3xx_cpu_pm_enter(suspend_state_t state)
++{
++	/*
++	 * Don't sleep if no wakeup sources are defined
++	 */
++	if (wakeup_src == 0)
++		return;
++
++	switch (state) {
++	case PM_SUSPEND_STANDBY:
++		pxa3xx_cpu_standby(PXA3xx_PM_S0D2C2);
++		break;
++
++	case PM_SUSPEND_MEM:
++		break;
++	}
++}
++
++static int pxa3xx_cpu_pm_valid(suspend_state_t state)
++{
++	return state == PM_SUSPEND_MEM || state == PM_SUSPEND_STANDBY;
++}
++
++static struct pxa_cpu_pm_fns pxa3xx_cpu_pm_fns = {
++	.save_size	= SLEEP_SAVE_SIZE,
++	.save		= pxa3xx_cpu_pm_save,
++	.restore	= pxa3xx_cpu_pm_restore,
++	.valid		= pxa3xx_cpu_pm_valid,
++	.enter		= pxa3xx_cpu_pm_enter,
+ };
+ 
++static void __init pxa3xx_init_pm(void)
++{
++	sram = ioremap(ISRAM_START, ISRAM_SIZE);
++	if (!sram) {
++		printk(KERN_ERR "Unable to map ISRAM: disabling standby/suspend\n");
++		return;
++	}
++
++	/*
++	 * Since we copy wakeup code into the SRAM, we need to ensure
++	 * that it is preserved over the low power modes.  Note: bit 8
++	 * is undocumented in the developer manual, but must be set.
++	 */
++	AD1R |= ADXR_L2 | ADXR_R0;
++	AD2R |= ADXR_L2 | ADXR_R0;
++	AD3R |= ADXR_L2 | ADXR_R0;
++
++	/*
++	 * Clear the resume enable registers.
++	 */
++	AD1D0ER = 0;
++	AD2D0ER = 0;
++	AD2D1ER = 0;
++	AD3ER = 0;
++
++	pxa_cpu_pm_fns = &pxa3xx_cpu_pm_fns;
++}
++
++static int pxa3xx_set_wake(unsigned int irq, unsigned int on)
++{
++	unsigned long flags, mask = 0;
++
++	switch (irq) {
++	case IRQ_SSP3:
++		mask = ADXER_MFP_WSSP3;
++		break;
++	case IRQ_MSL:
++		mask = ADXER_WMSL0;
++		break;
++	case IRQ_USBH2:
++	case IRQ_USBH1:
++		mask = ADXER_WUSBH;
++		break;
++	case IRQ_KEYPAD:
++		mask = ADXER_WKP;
++		break;
++	case IRQ_AC97:
++		mask = ADXER_MFP_WAC97;
++		break;
++	case IRQ_USIM:
++		mask = ADXER_WUSIM0;
++		break;
++	case IRQ_SSP2:
++		mask = ADXER_MFP_WSSP2;
++		break;
++	case IRQ_I2C:
++		mask = ADXER_MFP_WI2C;
++		break;
++	case IRQ_STUART:
++		mask = ADXER_MFP_WUART3;
++		break;
++	case IRQ_BTUART:
++		mask = ADXER_MFP_WUART2;
++		break;
++	case IRQ_FFUART:
++		mask = ADXER_MFP_WUART1;
++		break;
++	case IRQ_MMC:
++		mask = ADXER_MFP_WMMC1;
++		break;
++	case IRQ_SSP:
++		mask = ADXER_MFP_WSSP1;
++		break;
++	case IRQ_RTCAlrm:
++		mask = ADXER_WRTC;
++		break;
++	case IRQ_SSP4:
++		mask = ADXER_MFP_WSSP4;
++		break;
++	case IRQ_TSI:
++		mask = ADXER_WTSI;
++		break;
++	case IRQ_USIM2:
++		mask = ADXER_WUSIM1;
++		break;
++	case IRQ_MMC2:
++		mask = ADXER_MFP_WMMC2;
++		break;
++	case IRQ_NAND:
++		mask = ADXER_MFP_WFLASH;
++		break;
++	case IRQ_USB2:
++		mask = ADXER_WUSB2;
++		break;
++	case IRQ_WAKEUP0:
++		mask = ADXER_WEXTWAKE0;
++		break;
++	case IRQ_WAKEUP1:
++		mask = ADXER_WEXTWAKE1;
++		break;
++	case IRQ_MMC3:
++		mask = ADXER_MFP_GEN12;
++		break;
++	}
++
++	local_irq_save(flags);
++	if (on)
++		wakeup_src |= mask;
++	else
++		wakeup_src &= ~mask;
++	local_irq_restore(flags);
++
++	return 0;
++}
++
++static void pxa3xx_init_irq_pm(void)
++{
++	pxa_init_irq_set_wake(pxa3xx_set_wake);
++}
++
++#else
++static inline void pxa3xx_init_pm(void) {}
++static inline void pxa3xx_init_irq_pm(void) {}
++#endif
++
+ void __init pxa3xx_init_irq(void)
+ {
+ 	/* enable CP6 access */
+@@ -202,6 +432,7 @@ void __init pxa3xx_init_irq(void)
+ 	pxa_init_irq_low();
+ 	pxa_init_irq_high();
+ 	pxa_init_irq_gpio(128);
++	pxa3xx_init_irq_pm();
+ }
+ 
+ /*
+@@ -209,16 +440,16 @@ void __init pxa3xx_init_irq(void)
+  */
+ 
+ static struct platform_device *devices[] __initdata = {
+-	&pxa_device_mci,
+ 	&pxa_device_udc,
+-	&pxa_device_fb,
+ 	&pxa_device_ffuart,
+ 	&pxa_device_btuart,
+ 	&pxa_device_stuart,
+-	&pxa_device_i2c,
+ 	&pxa_device_i2s,
+-	&pxa_device_ficp,
+ 	&pxa_device_rtc,
++	&pxa27x_device_ssp1,
++	&pxa27x_device_ssp2,
++	&pxa27x_device_ssp3,
++	&pxa3xx_device_ssp4,
+ };
+ 
+ static int __init pxa3xx_init(void)
+@@ -231,6 +462,8 @@ static int __init pxa3xx_init(void)
+ 		if ((ret = pxa_init_dma(32)))
+ 			return ret;
+ 
++		pxa3xx_init_pm();
++
+ 		return platform_add_devices(devices, ARRAY_SIZE(devices));
+ 	}
+ 	return 0;
+diff --git a/arch/arm/mach-pxa/sharpsl.h b/arch/arm/mach-pxa/sharpsl.h
+index da4769c..047909a 100644
+--- a/arch/arm/mach-pxa/sharpsl.h
++++ b/arch/arm/mach-pxa/sharpsl.h
+@@ -26,28 +26,15 @@ void corgi_ssp_set_machinfo(struct corgissp_machinfo *machinfo);
+ 
+ 
+ /*
+- * SharpSL Backlight
++ * SharpSL/Corgi LCD Driver
+  */
+-void corgi_bl_set_intensity(int intensity);
+-void spitz_bl_set_intensity(int intensity);
+-void akita_bl_set_intensity(int intensity);
+-
+-
+-/*
+- * SharpSL Touchscreen Driver
+- */
+-unsigned long corgi_get_hsync_len(void);
+-unsigned long spitz_get_hsync_len(void);
+-void corgi_put_hsync(void);
+-void spitz_put_hsync(void);
+-void corgi_wait_hsync(void);
+-void spitz_wait_hsync(void);
++void corgi_lcdtg_suspend(void);
++void corgi_lcdtg_hw_init(int mode);
+ 
+ 
+ /*
+  * SharpSL Battery/PM Driver
+  */
+-
+ #define READ_GPIO_BIT(x)    (GPLR(x) & GPIO_bit(x))
+ 
+ /* MAX1111 Channel Definitions */
+diff --git a/arch/arm/mach-pxa/sleep.S b/arch/arm/mach-pxa/sleep.S
+index d044772..14bb4a9 100644
+--- a/arch/arm/mach-pxa/sleep.S
++++ b/arch/arm/mach-pxa/sleep.S
+@@ -16,6 +16,7 @@
+ #include <asm/hardware.h>
+ 
+ #include <asm/arch/pxa-regs.h>
++#include <asm/arch/pxa2xx-regs.h>
+ 
+ #define MDREFR_KDIV	0x200a4000	// all banks
+ #define CCCR_SLEEP	0x00000107	// L=7 2N=2 A=0 PPDIS=0 CPDIS=0
+@@ -49,6 +50,7 @@ pxa_cpu_save_sp:
+ 	str	r0, [r1]
+ 	ldr	pc, [sp], #4
+ 
++#ifdef CONFIG_PXA27x
+ /*
+  * pxa27x_cpu_suspend()
+  *
+@@ -104,9 +106,11 @@ ENTRY(pxa27x_cpu_suspend)
+ 
+ 	@ align execution to a cache line
+ 	b	pxa_cpu_do_suspend
++#endif
+ 
++#ifdef CONFIG_PXA25x
+ /*
+- * pxa27x_cpu_suspend()
++ * pxa25x_cpu_suspend()
+  *
+  * Forces CPU into sleep state.
+  *
+@@ -169,6 +173,7 @@ ENTRY(pxa25x_cpu_suspend)
+ 	mcr	p14, 0, r0, c6, c0, 0
+ 	orr	r0, r0, #2			@ initiate change bit
+ 	b	pxa_cpu_do_suspend
++#endif
+ 
+ 	.ltorg
+ 	.align	5
+@@ -208,7 +213,7 @@ pxa_cpu_do_suspend:
+ 20:	b	20b				@ loop waiting for sleep
+ 
+ /*
+- * cpu_pxa_resume()
++ * pxa_cpu_resume()
+  *
+  * entry point from bootloader into kernel during resume
+  *
+diff --git a/arch/arm/mach-pxa/spitz.c b/arch/arm/mach-pxa/spitz.c
+index 2d78199..5078ede 100644
+--- a/arch/arm/mach-pxa/spitz.c
++++ b/arch/arm/mach-pxa/spitz.c
+@@ -271,6 +271,55 @@ static struct platform_device spitzled_device = {
+ /*
+  * 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,
+@@ -280,9 +329,9 @@ static struct resource spitzts_resources[] = {
+ };
+ 
+ static struct corgits_machinfo  spitz_ts_machinfo = {
+-	.get_hsync_len   = spitz_get_hsync_len,
+-	.put_hsync       = spitz_put_hsync,
+-	.wait_hsync      = spitz_wait_hsync,
++	.get_hsync_invperiod = spitz_get_hsync_invperiod,
++	.put_hsync           = spitz_put_hsync,
++	.wait_hsync          = spitz_wait_hsync,
+ };
+ 
+ static struct platform_device spitzts_device = {
+@@ -325,12 +374,10 @@ static int spitz_mci_init(struct device *dev, irq_handler_t spitz_detect_int, vo
+ 	err = request_irq(SPITZ_IRQ_GPIO_nSD_DETECT, spitz_detect_int,
+ 			  IRQF_DISABLED | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+ 			  "MMC card detect", data);
+-	if (err) {
++	if (err)
+ 		printk(KERN_ERR "spitz_mci_init: MMC/SD: can't request MMC card detect IRQ\n");
+-		return -1;
+-	}
+ 
+-	return 0;
++	return err;
+ }
+ 
+ static void spitz_mci_setpower(struct device *dev, unsigned int vdd)
+@@ -423,6 +470,14 @@ static struct pxaficp_platform_data spitz_ficp_platform_data = {
+  * 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,
+@@ -520,6 +575,27 @@ static void __init common_init(void)
+ 	set_pxa_fb_info(&spitz_pxafb_info);
+ }
+ 
++#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;
+@@ -530,6 +606,7 @@ static void __init spitz_init(void)
+ 
+ 	platform_device_register(&spitzscoop2_device);
+ }
++#endif
+ 
+ #ifdef CONFIG_MACH_AKITA
+ /*
+@@ -542,6 +619,26 @@ struct platform_device akitaioexp_device = {
+ 
+ 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 void __init akita_init(void)
+ {
+ 	spitz_ficp_platform_data.transceiver_mode = akita_irda_transceiver_mode;
+@@ -558,7 +655,6 @@ static void __init akita_init(void)
+ }
+ #endif
+ 
+-
+ static void __init fixup_spitz(struct machine_desc *desc,
+ 		struct tag *tags, char **cmdline, struct meminfo *mi)
+ {
+diff --git a/arch/arm/mach-pxa/ssp.c b/arch/arm/mach-pxa/ssp.c
+index 422afee..00af7f2 100644
+--- a/arch/arm/mach-pxa/ssp.c
++++ b/arch/arm/mach-pxa/ssp.c
+@@ -32,45 +32,27 @@
+ #include <linux/ioport.h>
+ #include <linux/init.h>
+ #include <linux/mutex.h>
++#include <linux/clk.h>
++#include <linux/err.h>
++#include <linux/platform_device.h>
++
+ #include <asm/io.h>
+ #include <asm/irq.h>
+ #include <asm/hardware.h>
+ #include <asm/arch/ssp.h>
+ #include <asm/arch/pxa-regs.h>
+-
+-#define PXA_SSP_PORTS 	3
++#include <asm/arch/regs-ssp.h>
+ 
+ #define TIMEOUT 100000
+ 
+-struct ssp_info_ {
+-	int irq;
+-	u32 clock;
+-};
+-
+-/*
+- * SSP port clock and IRQ settings
+- */
+-static const struct ssp_info_ ssp_info[PXA_SSP_PORTS] = {
+-#if defined (CONFIG_PXA27x)
+-	{IRQ_SSP,	CKEN_SSP1},
+-	{IRQ_SSP2,	CKEN_SSP2},
+-	{IRQ_SSP3,	CKEN_SSP3},
+-#else
+-	{IRQ_SSP,	CKEN_SSP},
+-	{IRQ_NSSP,	CKEN_NSSP},
+-	{IRQ_ASSP,	CKEN_ASSP},
+-#endif
+-};
+-
+-static DEFINE_MUTEX(mutex);
+-static int use_count[PXA_SSP_PORTS] = {0, 0, 0};
+-
+ static irqreturn_t ssp_interrupt(int irq, void *dev_id)
+ {
+-	struct ssp_dev *dev = (struct ssp_dev*) dev_id;
+-	unsigned int status = SSSR_P(dev->port);
++	struct ssp_dev *dev = dev_id;
++	struct ssp_device *ssp = dev->ssp;
++	unsigned int status;
+ 
+-	SSSR_P(dev->port) = status; /* clear status bits */
++	status = __raw_readl(ssp->mmio_base + SSSR);
++	__raw_writel(status, ssp->mmio_base + SSSR);
+ 
+ 	if (status & SSSR_ROR)
+ 		printk(KERN_WARNING "SSP(%d): receiver overrun\n", dev->port);
+@@ -99,15 +81,16 @@ static irqreturn_t ssp_interrupt(int irq, void *dev_id)
+  */
+ int ssp_write_word(struct ssp_dev *dev, u32 data)
+ {
++	struct ssp_device *ssp = dev->ssp;
+ 	int timeout = TIMEOUT;
+ 
+-	while (!(SSSR_P(dev->port) & SSSR_TNF)) {
++	while (!(__raw_readl(ssp->mmio_base + SSSR) & SSSR_TNF)) {
+ 	        if (!--timeout)
+ 	        	return -ETIMEDOUT;
+ 		cpu_relax();
+ 	}
+ 
+-	SSDR_P(dev->port) = data;
++	__raw_writel(data, ssp->mmio_base + SSDR);
+ 
+ 	return 0;
+ }
+@@ -129,15 +112,16 @@ int ssp_write_word(struct ssp_dev *dev, u32 data)
+  */
+ int ssp_read_word(struct ssp_dev *dev, u32 *data)
+ {
++	struct ssp_device *ssp = dev->ssp;
+ 	int timeout = TIMEOUT;
+ 
+-	while (!(SSSR_P(dev->port) & SSSR_RNE)) {
++	while (!(__raw_readl(ssp->mmio_base + SSSR) & SSSR_RNE)) {
+ 	        if (!--timeout)
+ 	        	return -ETIMEDOUT;
+ 		cpu_relax();
+ 	}
+ 
+-	*data = SSDR_P(dev->port);
++	*data = __raw_readl(ssp->mmio_base + SSDR);
+ 	return 0;
+ }
+ 
+@@ -151,17 +135,28 @@ int ssp_read_word(struct ssp_dev *dev, u32 *data)
+  */
+ int ssp_flush(struct ssp_dev *dev)
+ {
++	struct ssp_device *ssp = dev->ssp;
+ 	int timeout = TIMEOUT * 2;
+ 
++	/* ensure TX FIFO is empty instead of not full */
++	if (cpu_is_pxa3xx()) {
++		while (__raw_readl(ssp->mmio_base + SSSR) & 0xf00) {
++			if (!--timeout)
++				return -ETIMEDOUT;
++			cpu_relax();
++		}
++		timeout = TIMEOUT * 2;
++	}
++
+ 	do {
+-		while (SSSR_P(dev->port) & SSSR_RNE) {
++		while (__raw_readl(ssp->mmio_base + SSSR) & SSSR_RNE) {
+ 		        if (!--timeout)
+ 		        	return -ETIMEDOUT;
+-			(void) SSDR_P(dev->port);
++			(void)__raw_readl(ssp->mmio_base + SSDR);
+ 		}
+ 	        if (!--timeout)
+ 	        	return -ETIMEDOUT;
+-	} while (SSSR_P(dev->port) & SSSR_BSY);
++	} while (__raw_readl(ssp->mmio_base + SSSR) & SSSR_BSY);
+ 
+ 	return 0;
+ }
+@@ -173,7 +168,12 @@ int ssp_flush(struct ssp_dev *dev)
+  */
+ void ssp_enable(struct ssp_dev *dev)
+ {
+-	SSCR0_P(dev->port) |= SSCR0_SSE;
++	struct ssp_device *ssp = dev->ssp;
++	uint32_t sscr0;
++
++	sscr0 = __raw_readl(ssp->mmio_base + SSCR0);
++	sscr0 |= SSCR0_SSE;
++	__raw_writel(sscr0, ssp->mmio_base + SSCR0);
+ }
+ 
+ /**
+@@ -183,7 +183,12 @@ void ssp_enable(struct ssp_dev *dev)
+  */
+ void ssp_disable(struct ssp_dev *dev)
+ {
+-	SSCR0_P(dev->port) &= ~SSCR0_SSE;
++	struct ssp_device *ssp = dev->ssp;
++	uint32_t sscr0;
++
++	sscr0 = __raw_readl(ssp->mmio_base + SSCR0);
++	sscr0 &= ~SSCR0_SSE;
++	__raw_writel(sscr0, ssp->mmio_base + SSCR0);
+ }
+ 
+ /**
+@@ -192,14 +197,16 @@ void ssp_disable(struct ssp_dev *dev)
+  *
+  * Save the configured SSP state for suspend.
+  */
+-void ssp_save_state(struct ssp_dev *dev, struct ssp_state *ssp)
++void ssp_save_state(struct ssp_dev *dev, struct ssp_state *state)
+ {
+-	ssp->cr0 = SSCR0_P(dev->port);
+-	ssp->cr1 = SSCR1_P(dev->port);
+-	ssp->to = SSTO_P(dev->port);
+-	ssp->psp = SSPSP_P(dev->port);
++	struct ssp_device *ssp = dev->ssp;
++
++	state->cr0 = __raw_readl(ssp->mmio_base + SSCR0);
++	state->cr1 = __raw_readl(ssp->mmio_base + SSCR1);
++	state->to  = __raw_readl(ssp->mmio_base + SSTO);
++	state->psp = __raw_readl(ssp->mmio_base + SSPSP);
+ 
+-	SSCR0_P(dev->port) &= ~SSCR0_SSE;
++	ssp_disable(dev);
+ }
+ 
+ /**
+@@ -208,16 +215,18 @@ void ssp_save_state(struct ssp_dev *dev, struct ssp_state *ssp)
+  *
+  * Restore the SSP configuration saved previously by ssp_save_state.
+  */
+-void ssp_restore_state(struct ssp_dev *dev, struct ssp_state *ssp)
++void ssp_restore_state(struct ssp_dev *dev, struct ssp_state *state)
+ {
+-	SSSR_P(dev->port) = SSSR_ROR | SSSR_TUR | SSSR_BCE;
++	struct ssp_device *ssp = dev->ssp;
++	uint32_t sssr = SSSR_ROR | SSSR_TUR | SSSR_BCE;
+ 
+-	SSCR0_P(dev->port) = ssp->cr0 & ~SSCR0_SSE;
+-	SSCR1_P(dev->port) = ssp->cr1;
+-	SSTO_P(dev->port) = ssp->to;
+-	SSPSP_P(dev->port) = ssp->psp;
++	__raw_writel(sssr, ssp->mmio_base + SSSR);
+ 
+-	SSCR0_P(dev->port) = ssp->cr0;
++	__raw_writel(state->cr0 & ~SSCR0_SSE, ssp->mmio_base + SSCR0);
++	__raw_writel(state->cr1, ssp->mmio_base + SSCR1);
++	__raw_writel(state->to,  ssp->mmio_base + SSTO);
++	__raw_writel(state->psp, ssp->mmio_base + SSPSP);
++	__raw_writel(state->cr0, ssp->mmio_base + SSCR0);
+ }
+ 
+ /**
+@@ -231,15 +240,17 @@ void ssp_restore_state(struct ssp_dev *dev, struct ssp_state *ssp)
+  */
+ int ssp_config(struct ssp_dev *dev, u32 mode, u32 flags, u32 psp_flags, u32 speed)
+ {
++	struct ssp_device *ssp = dev->ssp;
++
+ 	dev->mode = mode;
+ 	dev->flags = flags;
+ 	dev->psp_flags = psp_flags;
+ 	dev->speed = speed;
+ 
+ 	/* set up port type, speed, port settings */
+-	SSCR0_P(dev->port) = (dev->speed | dev->mode);
+-	SSCR1_P(dev->port) = dev->flags;
+-	SSPSP_P(dev->port) = dev->psp_flags;
++	__raw_writel((dev->speed | dev->mode), ssp->mmio_base + SSCR0);
++	__raw_writel(dev->flags, ssp->mmio_base + SSCR1);
++	__raw_writel(dev->psp_flags, ssp->mmio_base + SSPSP);
+ 
+ 	return 0;
+ }
+@@ -256,44 +267,32 @@ int ssp_config(struct ssp_dev *dev, u32 mode, u32 flags, u32 psp_flags, u32 spee
+  */
+ int ssp_init(struct ssp_dev *dev, u32 port, u32 init_flags)
+ {
++	struct ssp_device *ssp;
+ 	int ret;
+ 
+-	if (port > PXA_SSP_PORTS || port == 0)
++	ssp = ssp_request(port, "SSP");
++	if (ssp == NULL)
+ 		return -ENODEV;
+ 
+-	mutex_lock(&mutex);
+-	if (use_count[port - 1]) {
+-		mutex_unlock(&mutex);
+-		return -EBUSY;
+-	}
+-	use_count[port - 1]++;
+-
+-	if (!request_mem_region(__PREG(SSCR0_P(port)), 0x2c, "SSP")) {
+-		use_count[port - 1]--;
+-		mutex_unlock(&mutex);
+-		return -EBUSY;
+-	}
++	dev->ssp = ssp;
+ 	dev->port = port;
+ 
+ 	/* do we need to get irq */
+ 	if (!(init_flags & SSP_NO_IRQ)) {
+-		ret = request_irq(ssp_info[port-1].irq, ssp_interrupt,
++		ret = request_irq(ssp->irq, ssp_interrupt,
+ 				0, "SSP", dev);
+ 	    	if (ret)
+ 			goto out_region;
+-	    	dev->irq = ssp_info[port-1].irq;
++		dev->irq = ssp->irq;
+ 	} else
+ 		dev->irq = 0;
+ 
+ 	/* turn on SSP port clock */
+-	pxa_set_cken(ssp_info[port-1].clock, 1);
+-	mutex_unlock(&mutex);
++	clk_enable(ssp->clk);
+ 	return 0;
+ 
+ out_region:
+-	release_mem_region(__PREG(SSCR0_P(port)), 0x2c);
+-	use_count[port - 1]--;
+-	mutex_unlock(&mutex);
++	ssp_free(ssp);
+ 	return ret;
+ }
+ 
+@@ -304,23 +303,240 @@ out_region:
+  */
+ void ssp_exit(struct ssp_dev *dev)
+ {
+-	mutex_lock(&mutex);
+-	SSCR0_P(dev->port) &= ~SSCR0_SSE;
++	struct ssp_device *ssp = dev->ssp;
++
++	ssp_disable(dev);
++	free_irq(dev->irq, dev);
++	clk_disable(ssp->clk);
++	ssp_free(ssp);
++}
++
++static DEFINE_MUTEX(ssp_lock);
++static LIST_HEAD(ssp_list);
++
++struct ssp_device *ssp_request(int port, const char *label)
++{
++	struct ssp_device *ssp = NULL;
++
++	mutex_lock(&ssp_lock);
++
++	list_for_each_entry(ssp, &ssp_list, node) {
++		if (ssp->port_id == port && ssp->use_count == 0) {
++			ssp->use_count++;
++			ssp->label = label;
++			break;
++		}
++	}
++
++	mutex_unlock(&ssp_lock);
++
++	if (ssp->port_id != port)
++		return NULL;
++
++	return ssp;
++}
++EXPORT_SYMBOL(ssp_request);
++
++void ssp_free(struct ssp_device *ssp)
++{
++	mutex_lock(&ssp_lock);
++	if (ssp->use_count) {
++		ssp->use_count--;
++		ssp->label = NULL;
++	} else
++		dev_err(&ssp->pdev->dev, "device already free\n");
++	mutex_unlock(&ssp_lock);
++}
++EXPORT_SYMBOL(ssp_free);
++
++static int __devinit ssp_probe(struct platform_device *pdev, int type)
++{
++	struct resource *res;
++	struct ssp_device *ssp;
++	int ret = 0;
++
++	ssp = kzalloc(sizeof(struct ssp_device), GFP_KERNEL);
++	if (ssp == NULL) {
++		dev_err(&pdev->dev, "failed to allocate memory");
++		return -ENOMEM;
++	}
++
++	ssp->clk = clk_get(&pdev->dev, "SSPCLK");
++	if (IS_ERR(ssp->clk)) {
++		ret = PTR_ERR(ssp->clk);
++		goto err_free;
++	}
++
++	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	if (res == NULL) {
++		dev_err(&pdev->dev, "no memory resource defined\n");
++		ret = -ENODEV;
++		goto err_free_clk;
++	}
++
++	res = request_mem_region(res->start, res->end - res->start + 1,
++			pdev->name);
++	if (res == NULL) {
++		dev_err(&pdev->dev, "failed to request memory resource\n");
++		ret = -EBUSY;
++		goto err_free_clk;
++	}
++
++	ssp->phys_base = res->start;
++
++	ssp->mmio_base = ioremap(res->start, res->end - res->start + 1);
++	if (ssp->mmio_base == NULL) {
++		dev_err(&pdev->dev, "failed to ioremap() registers\n");
++		ret = -ENODEV;
++		goto err_free_mem;
++	}
++
++	ssp->irq = platform_get_irq(pdev, 0);
++	if (ssp->irq < 0) {
++		dev_err(&pdev->dev, "no IRQ resource defined\n");
++		ret = -ENODEV;
++		goto err_free_io;
++	}
++
++	res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
++	if (res == NULL) {
++		dev_err(&pdev->dev, "no SSP RX DRCMR defined\n");
++		ret = -ENODEV;
++		goto err_free_io;
++	}
++	ssp->drcmr_rx = res->start;
++
++	res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
++	if (res == NULL) {
++		dev_err(&pdev->dev, "no SSP TX DRCMR defined\n");
++		ret = -ENODEV;
++		goto err_free_io;
++	}
++	ssp->drcmr_tx = res->start;
++
++	/* PXA2xx/3xx SSP ports starts from 1 and the internal pdev->id
++	 * starts from 0, do a translation here
++	 */
++	ssp->port_id = pdev->id + 1;
++	ssp->use_count = 0;
++	ssp->type = type;
++
++	mutex_lock(&ssp_lock);
++	list_add(&ssp->node, &ssp_list);
++	mutex_unlock(&ssp_lock);
++
++	platform_set_drvdata(pdev, ssp);
++	return 0;
++
++err_free_io:
++	iounmap(ssp->mmio_base);
++err_free_mem:
++	release_mem_region(res->start, res->end - res->start + 1);
++err_free_clk:
++	clk_put(ssp->clk);
++err_free:
++	kfree(ssp);
++	return ret;
++}
++
++static int __devexit ssp_remove(struct platform_device *pdev)
++{
++	struct resource *res;
++	struct ssp_device *ssp;
++
++	ssp = platform_get_drvdata(pdev);
++	if (ssp == NULL)
++		return -ENODEV;
++
++	iounmap(ssp->mmio_base);
++
++	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	release_mem_region(res->start, res->end - res->start + 1);
++
++	clk_put(ssp->clk);
+ 
+-    	if (dev->port > PXA_SSP_PORTS || dev->port == 0) {
+-		printk(KERN_WARNING "SSP: tried to close invalid port\n");
+-		mutex_unlock(&mutex);
+-		return;
++	mutex_lock(&ssp_lock);
++	list_del(&ssp->node);
++	mutex_unlock(&ssp_lock);
++
++	kfree(ssp);
++	return 0;
++}
++
++static int __devinit pxa25x_ssp_probe(struct platform_device *pdev)
++{
++	return ssp_probe(pdev, PXA25x_SSP);
++}
++
++static int __devinit pxa25x_nssp_probe(struct platform_device *pdev)
++{
++	return ssp_probe(pdev, PXA25x_NSSP);
++}
++
++static int __devinit pxa27x_ssp_probe(struct platform_device *pdev)
++{
++	return ssp_probe(pdev, PXA27x_SSP);
++}
++
++static struct platform_driver pxa25x_ssp_driver = {
++	.driver		= {
++		.name	= "pxa25x-ssp",
++	},
++	.probe		= pxa25x_ssp_probe,
++	.remove		= __devexit_p(ssp_remove),
++};
++
++static struct platform_driver pxa25x_nssp_driver = {
++	.driver		= {
++		.name	= "pxa25x-nssp",
++	},
++	.probe		= pxa25x_nssp_probe,
++	.remove		= __devexit_p(ssp_remove),
++};
++
++static struct platform_driver pxa27x_ssp_driver = {
++	.driver		= {
++		.name	= "pxa27x-ssp",
++	},
++	.probe		= pxa27x_ssp_probe,
++	.remove		= __devexit_p(ssp_remove),
++};
++
++static int __init pxa_ssp_init(void)
++{
++	int ret = 0;
++
++	ret = platform_driver_register(&pxa25x_ssp_driver);
++	if (ret) {
++		printk(KERN_ERR "failed to register pxa25x_ssp_driver");
++		return ret;
++	}
++
++	ret = platform_driver_register(&pxa25x_nssp_driver);
++	if (ret) {
++		printk(KERN_ERR "failed to register pxa25x_nssp_driver");
++		return ret;
++	}
++
++	ret = platform_driver_register(&pxa27x_ssp_driver);
++	if (ret) {
++		printk(KERN_ERR "failed to register pxa27x_ssp_driver");
++		return ret;
+ 	}
+ 
+-	pxa_set_cken(ssp_info[dev->port-1].clock, 0);
+-	if (dev->irq)
+-		free_irq(dev->irq, dev);
+-	release_mem_region(__PREG(SSCR0_P(dev->port)), 0x2c);
+-	use_count[dev->port - 1]--;
+-	mutex_unlock(&mutex);
++	return ret;
++}
++
++static void __exit pxa_ssp_exit(void)
++{
++	platform_driver_unregister(&pxa25x_ssp_driver);
++	platform_driver_unregister(&pxa25x_nssp_driver);
++	platform_driver_unregister(&pxa27x_ssp_driver);
+ }
+ 
++arch_initcall(pxa_ssp_init);
++module_exit(pxa_ssp_exit);
++
+ EXPORT_SYMBOL(ssp_write_word);
+ EXPORT_SYMBOL(ssp_read_word);
+ EXPORT_SYMBOL(ssp_flush);
+diff --git a/arch/arm/mach-pxa/standby.S b/arch/arm/mach-pxa/standby.S
+index d774430..167412e 100644
+--- a/arch/arm/mach-pxa/standby.S
++++ b/arch/arm/mach-pxa/standby.S
+@@ -17,6 +17,7 @@
+ 
+ 		.text
+ 
++#ifdef CONFIG_PXA27x
+ ENTRY(pxa_cpu_standby)
+ 	ldr	r0, =PSSR
+ 	mov	r1, #(PSSR_PH | PSSR_STS)
+@@ -29,3 +30,85 @@ ENTRY(pxa_cpu_standby)
+ 1:	mcr	p14, 0, r2, c7, c0, 0	@ put the system into Standby
+ 	str	r1, [r0]		@ make sure PSSR_PH/STS are clear
+ 	mov	pc, lr
++
++#endif
++
++#ifdef CONFIG_PXA3xx
++
++#define MDCNFG		0x0000
++#define MDCNFG_DMCEN	(1 << 30)
++#define DDR_HCAL	0x0060
++#define DDR_HCAL_HCRNG	0x1f
++#define DDR_HCAL_HCPROG	(1 << 28)
++#define DDR_HCAL_HCEN	(1 << 31)
++#define DMCIER		0x0070
++#define DMCIER_EDLP	(1 << 29)
++#define DMCISR		0x0078
++#define RCOMP		0x0100
++#define RCOMP_SWEVAL	(1 << 31)
++
++ENTRY(pm_enter_standby_start)
++	mov	r1, #0xf6000000		@ DMEMC_REG_BASE (MDCNFG)
++	add	r1, r1, #0x00100000
++
++	/*
++	 * Preload the TLB entry for accessing the dynamic memory
++	 * controller registers.  Note that page table lookups will
++	 * fail until the dynamic memory controller has been
++	 * reinitialised - and that includes MMU page table walks.
++	 * This also means that only the dynamic memory controller
++	 * can be reliably accessed in the code following standby.
++	 */
++	ldr	r2, [r1]		@ Dummy read MDCNFG
++
++	mcr	p14, 0, r0, c7, c0, 0
++	.rept	8
++	nop
++	.endr
++
++	ldr	r0, [r1, #DDR_HCAL]	@ Clear (and wait for) HCEN
++	bic	r0, r0, #DDR_HCAL_HCEN
++	str	r0, [r1, #DDR_HCAL]
++1:	ldr	r0, [r1, #DDR_HCAL]
++	tst	r0, #DDR_HCAL_HCEN
++	bne	1b
++
++	ldr	r0, [r1, #RCOMP]	@ Initiate RCOMP
++	orr	r0, r0, #RCOMP_SWEVAL
++	str	r0, [r1, #RCOMP]
++
++	mov	r0, #~0			@ Clear interrupts
++	str	r0, [r1, #DMCISR]
++
++	ldr	r0, [r1, #DMCIER]	@ set DMIER[EDLP]
++	orr	r0, r0, #DMCIER_EDLP
++	str	r0, [r1, #DMCIER]
++
++	ldr	r0, [r1, #DDR_HCAL]	@ clear HCRNG, set HCPROG, HCEN
++	bic	r0, r0, #DDR_HCAL_HCRNG
++	orr	r0, r0, #DDR_HCAL_HCEN | DDR_HCAL_HCPROG
++	str	r0, [r1, #DDR_HCAL]
++
++1:	ldr	r0, [r1, #DMCISR]
++	tst	r0, #DMCIER_EDLP
++	beq	1b
++
++	ldr	r0, [r1, #MDCNFG]	@ set MDCNFG[DMCEN]
++	orr	r0, r0, #MDCNFG_DMCEN
++	str	r0, [r1, #MDCNFG]
++1:	ldr	r0, [r1, #MDCNFG]
++	tst	r0, #MDCNFG_DMCEN
++	beq	1b
++
++	ldr	r0, [r1, #DDR_HCAL]	@ set DDR_HCAL[HCRNG]
++	orr	r0, r0, #2 @ HCRNG
++	str	r0, [r1, #DDR_HCAL]
++
++	ldr	r0, [r1, #DMCIER]	@ Clear the interrupt
++	bic	r0, r0, #0x20000000
++	str	r0, [r1, #DMCIER]
++
++	mov	pc, lr
++ENTRY(pm_enter_standby_end)
++
++#endif
+diff --git a/arch/arm/mach-pxa/time.c b/arch/arm/mach-pxa/time.c
+index fbfa192..7b7c017 100644
+--- a/arch/arm/mach-pxa/time.c
++++ b/arch/arm/mach-pxa/time.c
+@@ -59,55 +59,17 @@ unsigned long long sched_clock(void)
+ }
+ 
+ 
++#define MIN_OSCR_DELTA 16
++
+ static irqreturn_t
+ pxa_ost0_interrupt(int irq, void *dev_id)
+ {
+-	int next_match;
+ 	struct clock_event_device *c = dev_id;
+ 
+-	if (c->mode == CLOCK_EVT_MODE_ONESHOT) {
+-		/* Disarm the compare/match, signal the event. */
+-		OIER &= ~OIER_E0;
+-		OSSR = OSSR_M0;
+-		c->event_handler(c);
+-	} else if (c->mode == CLOCK_EVT_MODE_PERIODIC) {
+-		/* Call the event handler as many times as necessary
+-		 * to recover missed events, if any (if we update
+-		 * OSMR0 and OSCR0 is still ahead of us, we've missed
+-		 * the event).  As we're dealing with that, re-arm the
+-		 * compare/match for the next event.
+-		 *
+-		 * HACK ALERT:
+-		 *
+-		 * There's a latency between the instruction that
+-		 * writes to OSMR0 and the actual commit to the
+-		 * physical hardware, because the CPU doesn't (have
+-		 * to) run at bus speed, there's a write buffer
+-		 * between the CPU and the bus, etc. etc.  So if the
+-		 * target OSCR0 is "very close", to the OSMR0 load
+-		 * value, the update to OSMR0 might not get to the
+-		 * hardware in time and we'll miss that interrupt.
+-		 *
+-		 * To be safe, if the new OSMR0 is "very close" to the
+-		 * target OSCR0 value, we call the event_handler as
+-		 * though the event actually happened.  According to
+-		 * Nico's comment in the previous version of this
+-		 * code, experience has shown that 6 OSCR ticks is
+-		 * "very close" but he went with 8.  We will use 16,
+-		 * based on the results of testing on PXA270.
+-		 *
+-		 * To be doubly sure, we also tell clkevt via
+-		 * clockevents_register_device() not to ask for
+-		 * anything that might put us "very close".
+-	 */
+-#define MIN_OSCR_DELTA 16
+-		do {
+-			OSSR = OSSR_M0;
+-			next_match = (OSMR0 += LATCH);
+-			c->event_handler(c);
+-		} while (((signed long)(next_match - OSCR) <= MIN_OSCR_DELTA)
+-			 && (c->mode == CLOCK_EVT_MODE_PERIODIC));
+-	}
++	/* Disarm the compare/match, signal the event. */
++	OIER &= ~OIER_E0;
++	OSSR = OSSR_M0;
++	c->event_handler(c);
+ 
+ 	return IRQ_HANDLED;
+ }
+@@ -133,14 +95,6 @@ pxa_osmr0_set_mode(enum clock_event_mode mode, struct clock_event_device *dev)
+ 	unsigned long irqflags;
+ 
+ 	switch (mode) {
+-	case CLOCK_EVT_MODE_PERIODIC:
+-		raw_local_irq_save(irqflags);
+-		OSSR = OSSR_M0;
+-		OIER |= OIER_E0;
+-		OSMR0 = OSCR + LATCH;
+-		raw_local_irq_restore(irqflags);
+-		break;
+-
+ 	case CLOCK_EVT_MODE_ONESHOT:
+ 		raw_local_irq_save(irqflags);
+ 		OIER &= ~OIER_E0;
+@@ -158,13 +112,14 @@ pxa_osmr0_set_mode(enum clock_event_mode mode, struct clock_event_device *dev)
+ 		break;
+ 
+ 	case CLOCK_EVT_MODE_RESUME:
++	case CLOCK_EVT_MODE_PERIODIC:
+ 		break;
+ 	}
+ }
+ 
+ static struct clock_event_device ckevt_pxa_osmr0 = {
+ 	.name		= "osmr0",
+-	.features	= CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
++	.features	= CLOCK_EVT_FEAT_ONESHOT,
+ 	.shift		= 32,
+ 	.rating		= 200,
+ 	.cpumask	= CPU_MASK_CPU0,
+@@ -214,7 +169,7 @@ static void __init pxa_timer_init(void)
+ 	ckevt_pxa_osmr0.max_delta_ns =
+ 		clockevent_delta2ns(0x7fffffff, &ckevt_pxa_osmr0);
+ 	ckevt_pxa_osmr0.min_delta_ns =
+-		clockevent_delta2ns(MIN_OSCR_DELTA, &ckevt_pxa_osmr0) + 1;
++		clockevent_delta2ns(MIN_OSCR_DELTA * 2, &ckevt_pxa_osmr0) + 1;
+ 
+ 	cksrc_pxa_oscr0.mult =
+ 		clocksource_hz2mult(clock_tick_rate, cksrc_pxa_oscr0.shift);
+@@ -226,7 +181,7 @@ static void __init pxa_timer_init(void)
+ }
+ 
+ #ifdef CONFIG_PM
+-static unsigned long osmr[4], oier;
++static unsigned long osmr[4], oier, oscr;
+ 
+ static void pxa_timer_suspend(void)
+ {
+@@ -235,23 +190,26 @@ static void pxa_timer_suspend(void)
+ 	osmr[2] = OSMR2;
+ 	osmr[3] = OSMR3;
+ 	oier = OIER;
++	oscr = OSCR;
+ }
+ 
+ static void pxa_timer_resume(void)
+ {
++	/*
++	 * Ensure that we have at least MIN_OSCR_DELTA between match
++	 * register 0 and the OSCR, to guarantee that we will receive
++	 * the one-shot timer interrupt.  We adjust OSMR0 in preference
++	 * to OSCR to guarantee that OSCR is monotonically incrementing.
++	 */
++	if (osmr[0] - oscr < MIN_OSCR_DELTA)
++		osmr[0] += MIN_OSCR_DELTA;
++
+ 	OSMR0 = osmr[0];
+ 	OSMR1 = osmr[1];
+ 	OSMR2 = osmr[2];
+ 	OSMR3 = osmr[3];
+ 	OIER = oier;
+-
+-	/*
+-	 * OSCR0 is the system timer, which has to increase
+-	 * monotonically until it rolls over in hardware.  The value
+-	 * (OSMR0 - LATCH) is OSCR0 at the most recent system tick,
+-	 * which is a handy value to restore to OSCR0.
+-	 */
+-	OSCR = OSMR0 - LATCH;
++	OSCR = oscr;
+ }
+ #else
+ #define pxa_timer_suspend NULL
+diff --git a/arch/arm/mach-pxa/tosa.c b/arch/arm/mach-pxa/tosa.c
+index 240fd04..1919756 100644
+--- a/arch/arm/mach-pxa/tosa.c
++++ b/arch/arm/mach-pxa/tosa.c
+@@ -184,16 +184,13 @@ static int tosa_mci_init(struct device *dev, irq_handler_t tosa_detect_int, void
+ 
+ 	tosa_mci_platform_data.detect_delay = msecs_to_jiffies(250);
+ 
+-	err = request_irq(TOSA_IRQ_GPIO_nSD_DETECT, tosa_detect_int, IRQF_DISABLED,
++	err = request_irq(TOSA_IRQ_GPIO_nSD_DETECT, tosa_detect_int,
++			  IRQF_DISABLED | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+ 				"MMC/SD card detect", data);
+-	if (err) {
++	if (err)
+ 		printk(KERN_ERR "tosa_mci_init: MMC/SD: can't request MMC card detect IRQ\n");
+-		return -1;
+-	}
+-
+-	set_irq_type(TOSA_IRQ_GPIO_nSD_DETECT, IRQT_BOTHEDGE);
+ 
+-	return 0;
++	return err;
+ }
+ 
+ static void tosa_mci_setpower(struct device *dev, unsigned int vdd)
+diff --git a/arch/arm/mach-pxa/trizeps4.c b/arch/arm/mach-pxa/trizeps4.c
+index e4ba43b..853fc94 100644
+--- a/arch/arm/mach-pxa/trizeps4.c
++++ b/arch/arm/mach-pxa/trizeps4.c
+@@ -296,11 +296,10 @@ static int trizeps4_mci_init(struct device *dev, irq_handler_t mci_detect_int, v
+ 	err = request_irq(TRIZEPS4_MMC_IRQ, mci_detect_int,
+ 			  IRQF_DISABLED | IRQF_TRIGGER_RISING,
+ 			  "MMC card detect", data);
+-	if (err) {
++	if (err)
+ 		printk(KERN_ERR "trizeps4_mci_init: MMC/SD: can't request MMC card detect IRQ\n");
+-		return -1;
+-	}
+-	return 0;
++
++	return err;
+ }
+ 
+ static void trizeps4_mci_exit(struct device *dev, void *data)
+diff --git a/arch/arm/mach-pxa/zylonite.c b/arch/arm/mach-pxa/zylonite.c
+index 743a87b..7731d50 100644
+--- a/arch/arm/mach-pxa/zylonite.c
++++ b/arch/arm/mach-pxa/zylonite.c
+@@ -25,9 +25,13 @@
+ #include <asm/arch/gpio.h>
+ #include <asm/arch/pxafb.h>
+ #include <asm/arch/zylonite.h>
++#include <asm/arch/mmc.h>
+ 
+ #include "generic.h"
+ 
++#define MAX_SLOTS	3
++struct platform_mmc_slot zylonite_mmc_slot[MAX_SLOTS];
++
+ int gpio_backlight;
+ int gpio_eth_irq;
+ 
+@@ -43,7 +47,7 @@ static struct resource smc91x_resources[] = {
+ 	[1] = {
+ 		.start	= -1,	/* for run-time assignment */
+ 		.end	= -1,
+-		.flags	= IORESOURCE_IRQ,
++		.flags	= IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE,
+ 	}
+ };
+ 
+@@ -156,6 +160,95 @@ static void __init zylonite_init_lcd(void)
+ static inline void zylonite_init_lcd(void) {}
+ #endif
+ 
++#if defined(CONFIG_MMC)
++static int zylonite_mci_ro(struct device *dev)
++{
++	struct platform_device *pdev = to_platform_device(dev);
++
++	return gpio_get_value(zylonite_mmc_slot[pdev->id].gpio_wp);
++}
++
++static int zylonite_mci_init(struct device *dev,
++			     irq_handler_t zylonite_detect_int,
++			     void *data)
++{
++	struct platform_device *pdev = to_platform_device(dev);
++	int err, cd_irq, gpio_cd, gpio_wp;
++
++	cd_irq = gpio_to_irq(zylonite_mmc_slot[pdev->id].gpio_cd);
++	gpio_cd = zylonite_mmc_slot[pdev->id].gpio_cd;
++	gpio_wp = zylonite_mmc_slot[pdev->id].gpio_wp;
++
++	/*
++	 * setup GPIO for Zylonite MMC controller
++	 */
++	err = gpio_request(gpio_cd, "mmc card detect");
++	if (err)
++		goto err_request_cd;
++	gpio_direction_input(gpio_cd);
++
++	err = gpio_request(gpio_wp, "mmc write protect");
++	if (err)
++		goto err_request_wp;
++	gpio_direction_input(gpio_wp);
++
++	err = request_irq(cd_irq, zylonite_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(gpio_wp);
++err_request_wp:
++	gpio_free(gpio_cd);
++err_request_cd:
++	return err;
++}
++
++static void zylonite_mci_exit(struct device *dev, void *data)
++{
++	struct platform_device *pdev = to_platform_device(dev);
++	int cd_irq, gpio_cd, gpio_wp;
++
++	cd_irq = gpio_to_irq(zylonite_mmc_slot[pdev->id].gpio_cd);
++	gpio_cd = zylonite_mmc_slot[pdev->id].gpio_cd;
++	gpio_wp = zylonite_mmc_slot[pdev->id].gpio_wp;
++
++	free_irq(cd_irq, data);
++	gpio_free(gpio_cd);
++	gpio_free(gpio_wp);
++}
++
++static struct pxamci_platform_data zylonite_mci_platform_data = {
++	.detect_delay	= 20,
++	.ocr_mask	= MMC_VDD_32_33|MMC_VDD_33_34,
++	.init 		= zylonite_mci_init,
++	.exit		= zylonite_mci_exit,
++	.get_ro		= zylonite_mci_ro,
++};
++
++static struct pxamci_platform_data zylonite_mci2_platform_data = {
++	.detect_delay	= 20,
++	.ocr_mask	= MMC_VDD_32_33|MMC_VDD_33_34,
++};
++
++static void __init zylonite_init_mmc(void)
++{
++	pxa_set_mci_info(&zylonite_mci_platform_data);
++	pxa3xx_set_mci2_info(&zylonite_mci2_platform_data);
++	if (cpu_is_pxa310())
++		pxa3xx_set_mci3_info(&zylonite_mci_platform_data);
++}
++#else
++static inline void zylonite_init_mmc(void) {}
++#endif
++
+ static void __init zylonite_init(void)
+ {
+ 	/* board-processor specific initialization */
+@@ -171,6 +264,7 @@ static void __init zylonite_init(void)
+ 	platform_device_register(&smc91x_device);
+ 
+ 	zylonite_init_lcd();
++	zylonite_init_mmc();
+ }
+ 
+ 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 1832bc3..6ac04c0 100644
+--- a/arch/arm/mach-pxa/zylonite_pxa300.c
++++ b/arch/arm/mach-pxa/zylonite_pxa300.c
+@@ -53,13 +53,13 @@ static mfp_cfg_t common_mfp_cfg[] __initdata = {
+ 
+ 	/* BTUART */
+ 	GPIO111_UART2_RTS,
+-	GPIO112_UART2_RXD,
++	GPIO112_UART2_RXD | MFP_LPM_EDGE_FALL,
+ 	GPIO113_UART2_TXD,
+-	GPIO114_UART2_CTS,
++	GPIO114_UART2_CTS | MFP_LPM_EDGE_BOTH,
+ 
+ 	/* STUART */
+ 	GPIO109_UART3_TXD,
+-	GPIO110_UART3_RXD,
++	GPIO110_UART3_RXD | MFP_LPM_EDGE_FALL,
+ 
+ 	/* AC97 */
+ 	GPIO23_AC97_nACRESET,
+@@ -70,16 +70,16 @@ static mfp_cfg_t common_mfp_cfg[] __initdata = {
+ 	GPIO28_AC97_SYNC,
+ 
+ 	/* Keypad */
+-	GPIO107_KP_DKIN_0,
+-	GPIO108_KP_DKIN_1,
+-	GPIO115_KP_MKIN_0,
+-	GPIO116_KP_MKIN_1,
+-	GPIO117_KP_MKIN_2,
+-	GPIO118_KP_MKIN_3,
+-	GPIO119_KP_MKIN_4,
+-	GPIO120_KP_MKIN_5,
+-	GPIO2_2_KP_MKIN_6,
+-	GPIO3_2_KP_MKIN_7,
++	GPIO107_KP_DKIN_0 | MFP_LPM_EDGE_BOTH,
++	GPIO108_KP_DKIN_1 | MFP_LPM_EDGE_BOTH,
++	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,
+@@ -88,16 +88,33 @@ static mfp_cfg_t common_mfp_cfg[] __initdata = {
+ 	GPIO4_2_KP_MKOUT_5,
+ 	GPIO5_2_KP_MKOUT_6,
+ 	GPIO6_2_KP_MKOUT_7,
++
++	/* 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 */
++	GPIO15_GPIO,	/* CMD1 default as GPIO 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,
+ };
+ 
+ static mfp_cfg_t pxa300_mfp_cfg[] __initdata = {
+ 	/* FFUART */
+-	GPIO30_UART1_RXD,
++	GPIO30_UART1_RXD | MFP_LPM_EDGE_FALL,
+ 	GPIO31_UART1_TXD,
+ 	GPIO32_UART1_CTS,
+ 	GPIO37_UART1_RTS,
+ 	GPIO33_UART1_DCD,
+-	GPIO34_UART1_DSR,
++	GPIO34_UART1_DSR | MFP_LPM_EDGE_FALL,
+ 	GPIO35_UART1_RI,
+ 	GPIO36_UART1_DTR,
+ 
+@@ -108,7 +125,7 @@ static mfp_cfg_t pxa300_mfp_cfg[] __initdata = {
+ 
+ static mfp_cfg_t pxa310_mfp_cfg[] __initdata = {
+ 	/* FFUART */
+-	GPIO99_UART1_RXD,
++	GPIO99_UART1_RXD | MFP_LPM_EDGE_FALL,
+ 	GPIO100_UART1_TXD,
+ 	GPIO101_UART1_CTS,
+ 	GPIO106_UART1_RTS,
+@@ -116,6 +133,14 @@ static mfp_cfg_t pxa310_mfp_cfg[] __initdata = {
+ 	/* Ethernet */
+ 	GPIO2_nCS3,
+ 	GPIO102_GPIO,
++
++	/* MMC3 */
++	GPIO7_2_MMC3_DAT0,
++	GPIO8_2_MMC3_DAT1 | MFP_LPM_EDGE_BOTH,
++	GPIO9_2_MMC3_DAT2,
++	GPIO10_2_MMC3_DAT3,
++	GPIO103_MMC3_CLK,
++	GPIO105_MMC3_CMD,
+ };
+ 
+ #define NUM_LCD_DETECT_PINS	7
+@@ -174,6 +199,10 @@ void __init zylonite_pxa300_init(void)
+ 
+ 		/* GPIO pin assignment */
+ 		gpio_backlight = mfp_to_gpio(MFP_PIN_GPIO20);
++
++		/* MMC card detect & write protect for controller 0 */
++		zylonite_mmc_slot[0].gpio_cd  = EXT_GPIO(0);
++		zylonite_mmc_slot[0].gpio_wp  = EXT_GPIO(2);
+ 	}
+ 
+ 	if (cpu_is_pxa300()) {
+@@ -184,5 +213,9 @@ void __init zylonite_pxa300_init(void)
+ 	if (cpu_is_pxa310()) {
+ 		pxa3xx_mfp_config(ARRAY_AND_SIZE(pxa310_mfp_cfg));
+ 		gpio_eth_irq = mfp_to_gpio(MFP_PIN_GPIO102);
++
++		/* MMC card detect & write protect for controller 2 */
++		zylonite_mmc_slot[2].gpio_cd = EXT_GPIO(30);
++		zylonite_mmc_slot[2].gpio_wp = EXT_GPIO(31);
+ 	}
+ }
+diff --git a/arch/arm/mach-pxa/zylonite_pxa320.c b/arch/arm/mach-pxa/zylonite_pxa320.c
+index 94c7158..dfa7999 100644
+--- a/arch/arm/mach-pxa/zylonite_pxa320.c
++++ b/arch/arm/mach-pxa/zylonite_pxa320.c
+@@ -51,11 +51,11 @@ static mfp_cfg_t mfp_cfg[] __initdata = {
+ 	GPIO17_2_LCD_BIAS,
+ 
+ 	/* FFUART */
+-	GPIO41_UART1_RXD,
++	GPIO41_UART1_RXD | MFP_LPM_EDGE_FALL,
+ 	GPIO42_UART1_TXD,
+ 	GPIO43_UART1_CTS,
+ 	GPIO44_UART1_DCD,
+-	GPIO45_UART1_DSR,
++	GPIO45_UART1_DSR | MFP_LPM_EDGE_FALL,
+ 	GPIO46_UART1_RI,
+ 	GPIO47_UART1_DTR,
+ 	GPIO48_UART1_RTS,
+@@ -73,16 +73,16 @@ static mfp_cfg_t mfp_cfg[] __initdata = {
+ 	GPIO33_I2C_SDA,
+ 
+ 	/* Keypad */
+-	GPIO105_KP_DKIN_0,
+-	GPIO106_KP_DKIN_1,
+-	GPIO113_KP_MKIN_0,
+-	GPIO114_KP_MKIN_1,
+-	GPIO115_KP_MKIN_2,
+-	GPIO116_KP_MKIN_3,
+-	GPIO117_KP_MKIN_4,
+-	GPIO118_KP_MKIN_5,
+-	GPIO119_KP_MKIN_6,
+-	GPIO120_KP_MKIN_7,
++	GPIO105_KP_DKIN_0 | MFP_LPM_EDGE_BOTH,
++	GPIO106_KP_DKIN_1 | MFP_LPM_EDGE_BOTH,
++	GPIO113_KP_MKIN_0 | MFP_LPM_EDGE_BOTH,
++	GPIO114_KP_MKIN_1 | MFP_LPM_EDGE_BOTH,
++	GPIO115_KP_MKIN_2 | MFP_LPM_EDGE_BOTH,
++	GPIO116_KP_MKIN_3 | MFP_LPM_EDGE_BOTH,
++	GPIO117_KP_MKIN_4 | MFP_LPM_EDGE_BOTH,
++	GPIO118_KP_MKIN_5 | MFP_LPM_EDGE_BOTH,
++	GPIO119_KP_MKIN_6 | MFP_LPM_EDGE_BOTH,
++	GPIO120_KP_MKIN_7 | MFP_LPM_EDGE_BOTH,
+ 	GPIO121_KP_MKOUT_0,
+ 	GPIO122_KP_MKOUT_1,
+ 	GPIO123_KP_MKOUT_2,
+@@ -95,6 +95,23 @@ static mfp_cfg_t mfp_cfg[] __initdata = {
+ 	/* Ethernet */
+ 	GPIO4_nCS3,
+ 	GPIO90_GPIO,
++
++	/* MMC1 */
++	GPIO18_MMC1_DAT0,
++	GPIO19_MMC1_DAT1 | MFP_LPM_EDGE_BOTH,
++	GPIO20_MMC1_DAT2,
++	GPIO21_MMC1_DAT3,
++	GPIO22_MMC1_CLK,
++	GPIO23_MMC1_CMD,/* CMD0 for slot 0 */
++	GPIO31_GPIO,	/* CMD1 default as GPIO for slot 0 */
++
++	/* MMC2 */
++	GPIO24_MMC2_DAT0,
++	GPIO25_MMC2_DAT1 | MFP_LPM_EDGE_BOTH,
++	GPIO26_MMC2_DAT2,
++	GPIO27_MMC2_DAT3,
++	GPIO28_MMC2_CLK,
++	GPIO29_MMC2_CMD,
+ };
+ 
+ #define NUM_LCD_DETECT_PINS	7
+@@ -169,5 +186,9 @@ void __init zylonite_pxa320_init(void)
+ 		/* GPIO pin assignment */
+ 		gpio_backlight	= mfp_to_gpio(MFP_PIN_GPIO14);
+ 		gpio_eth_irq	= mfp_to_gpio(MFP_PIN_GPIO9);
++
++		/* MMC card detect & write protect for controller 0 */
++		zylonite_mmc_slot[0].gpio_cd  = mfp_to_gpio(MFP_PIN_GPIO1);
++		zylonite_mmc_slot[0].gpio_wp  = mfp_to_gpio(MFP_PIN_GPIO5);
+ 	}
+ }
+diff --git a/arch/arm/mach-realview/core.c b/arch/arm/mach-realview/core.c
+index c7f1b44..61d7021 100644
+--- a/arch/arm/mach-realview/core.c
++++ b/arch/arm/mach-realview/core.c
+@@ -530,8 +530,6 @@ static unsigned long realview_gettimeoffset(void)
+  */
+ static irqreturn_t realview_timer_interrupt(int irq, void *dev_id)
+ {
+-	write_seqlock(&xtime_lock);
+-
+ 	// ...clear the interrupt
+ 	writel(1, TIMER0_VA_BASE + TIMER_INTCLR);
+ 
+@@ -542,8 +540,6 @@ static irqreturn_t realview_timer_interrupt(int irq, void *dev_id)
+ 	update_process_times(user_mode(get_irq_regs()));
+ #endif
+ 
+-	write_sequnlock(&xtime_lock);
+-
+ 	return IRQ_HANDLED;
+ }
+ 
+diff --git a/arch/arm/mach-s3c2410/mach-bast.c b/arch/arm/mach-s3c2410/mach-bast.c
+index 587864f..6617547 100644
+--- a/arch/arm/mach-s3c2410/mach-bast.c
++++ b/arch/arm/mach-s3c2410/mach-bast.c
+@@ -530,7 +530,7 @@ static struct s3c2410fb_mach_info __initdata bast_fb_info = {
+ 
+ 	.displays = bast_lcd_info,
+ 	.num_displays = ARRAY_SIZE(bast_lcd_info),
+-	.default_display = 4,
++	.default_display = 1,
+ };
+ 
+ /* Standard BAST devices */
+@@ -540,7 +540,6 @@ static struct platform_device *bast_devices[] __initdata = {
+ 	&s3c_device_lcd,
+ 	&s3c_device_wdt,
+ 	&s3c_device_i2c,
+-	&s3c_device_iis,
+  	&s3c_device_rtc,
+ 	&s3c_device_nand,
+ 	&bast_device_nor,
+diff --git a/arch/arm/mach-s3c2410/mach-vr1000.c b/arch/arm/mach-s3c2410/mach-vr1000.c
+index 9f43f3f..3aade7b 100644
+--- a/arch/arm/mach-s3c2410/mach-vr1000.c
++++ b/arch/arm/mach-s3c2410/mach-vr1000.c
+@@ -365,7 +365,6 @@ static struct platform_device *vr1000_devices[] __initdata = {
+ 	&s3c_device_lcd,
+ 	&s3c_device_wdt,
+ 	&s3c_device_i2c,
+-	&s3c_device_iis,
+ 	&s3c_device_adc,
+ 	&serial_device,
+ 	&vr1000_nor,
+diff --git a/arch/arm/mach-s3c2410/s3c2410.c b/arch/arm/mach-s3c2410/s3c2410.c
+index e580303..0e79919 100644
+--- a/arch/arm/mach-s3c2410/s3c2410.c
++++ b/arch/arm/mach-s3c2410/s3c2410.c
+@@ -100,7 +100,7 @@ void __init s3c2410_init_clocks(int xtal)
+ }
+ 
+ struct sysdev_class s3c2410_sysclass = {
+-	set_kset_name("s3c2410-core"),
++	.name = "s3c2410-core",
+ };
+ 
+ static struct sys_device s3c2410_sysdev = {
+diff --git a/arch/arm/mach-s3c2410/usb-simtec.c b/arch/arm/mach-s3c2410/usb-simtec.c
+index bcd562a..6aec86a 100644
+--- a/arch/arm/mach-s3c2410/usb-simtec.c
++++ b/arch/arm/mach-s3c2410/usb-simtec.c
+@@ -60,7 +60,7 @@ usb_simtec_powercontrol(int port, int to)
+ static irqreturn_t
+ usb_simtec_ocirq(int irq, void *pw)
+ {
+-	struct s3c2410_hcd_info *info = (struct s3c2410_hcd_info *)pw;
++	struct s3c2410_hcd_info *info = pw;
+ 
+ 	if (s3c2410_gpio_getpin(S3C2410_GPG10) == 0) {
+ 		pr_debug("usb_simtec: over-current irq (oc detected)\n");
+diff --git a/arch/arm/mach-s3c2412/Kconfig b/arch/arm/mach-s3c2412/Kconfig
+index 8e8fe48..0b43431 100644
+--- a/arch/arm/mach-s3c2412/Kconfig
++++ b/arch/arm/mach-s3c2412/Kconfig
+@@ -10,6 +10,7 @@ config CPU_S3C2412
+ 	select CPU_LLSERIAL_S3C2440
+ 	select S3C2412_PM if PM
+ 	select S3C2412_DMA if S3C2410_DMA
++	select S3C2410_GPIO
+ 	help
+ 	  Support for the S3C2412 and S3C2413 SoCs from the S3C24XX line
+ 
+diff --git a/arch/arm/mach-s3c2412/Makefile b/arch/arm/mach-s3c2412/Makefile
+index f8e0116..267f334 100644
+--- a/arch/arm/mach-s3c2412/Makefile
++++ b/arch/arm/mach-s3c2412/Makefile
+@@ -12,8 +12,9 @@ obj-				:=
+ obj-$(CONFIG_CPU_S3C2412)	+= s3c2412.o
+ obj-$(CONFIG_CPU_S3C2412)	+= irq.o
+ obj-$(CONFIG_CPU_S3C2412)	+= clock.o
++obj-$(CONFIG_CPU_S3C2412)	+= gpio.o
+ obj-$(CONFIG_S3C2412_DMA)	+= dma.o
+-obj-$(CONFIG_S3C2412_PM)	+= pm.o
++obj-$(CONFIG_S3C2412_PM)	+= pm.o sleep.o
+ 
+ # Machine support
+ 
+diff --git a/arch/arm/mach-s3c2412/clock.c b/arch/arm/mach-s3c2412/clock.c
+index 4589936..2697a65 100644
+--- a/arch/arm/mach-s3c2412/clock.c
++++ b/arch/arm/mach-s3c2412/clock.c
+@@ -217,7 +217,7 @@ static int s3c2412_setparent_msysclk(struct clk *clk, struct clk *parent)
+ 
+ 	if (parent == &clk_mdivclk)
+ 		clksrc &= ~S3C2412_CLKSRC_MSYSCLK_MPLL;
+-	else if (parent == &clk_upll)
++	else if (parent == &clk_mpll)
+ 		clksrc |= S3C2412_CLKSRC_MSYSCLK_MPLL;
+ 	else
+ 		return -EINVAL;
+@@ -234,6 +234,45 @@ static struct clk clk_msysclk = {
+ 	.set_parent	= s3c2412_setparent_msysclk,
+ };
+ 
++static int s3c2412_setparent_armclk(struct clk *clk, struct clk *parent)
++{
++	unsigned long flags;
++	unsigned long clkdiv;
++	unsigned long dvs;
++
++	/* Note, we current equate fclk andf msysclk for S3C2412 */
++
++	if (parent == &clk_msysclk || parent == &clk_f)
++		dvs = 0;
++	else if (parent == &clk_h)
++		dvs = S3C2412_CLKDIVN_DVSEN;
++	else
++		return -EINVAL;
++
++	clk->parent = parent;
++
++	/* update this under irq lockdown, clkdivn is not protected
++	 * by the clock system. */
++
++	local_irq_save(flags);
++
++	clkdiv  = __raw_readl(S3C2410_CLKDIVN);
++	clkdiv &= ~S3C2412_CLKDIVN_DVSEN;
++	clkdiv |= dvs;
++	__raw_writel(clkdiv, S3C2410_CLKDIVN);
++
++	local_irq_restore(flags);
++
++	return 0;
++}
++
++static struct clk clk_armclk = {
++	.name		= "armclk",
++	.id		= -1,
++	.parent		= &clk_msysclk,
++	.set_parent	= s3c2412_setparent_armclk,
++};
++
+ /* these next clocks have an divider immediately after them,
+  * so we can register them with their divider and leave out the
+  * intermediate clock stage
+@@ -630,11 +669,13 @@ static struct clk *clks[] __initdata = {
+ 	&clk_erefclk,
+ 	&clk_urefclk,
+ 	&clk_mrefclk,
++	&clk_armclk,
+ };
+ 
+ int __init s3c2412_baseclk_add(void)
+ {
+ 	unsigned long clkcon  = __raw_readl(S3C2410_CLKCON);
++	unsigned int dvs;
+ 	struct clk *clkp;
+ 	int ret;
+ 	int ptr;
+@@ -643,6 +684,8 @@ int __init s3c2412_baseclk_add(void)
+ 	clk_usb_bus.parent = &clk_usbsrc;
+ 	clk_usb_bus.rate = 0x0;
+ 
++	clk_f.parent = &clk_msysclk;
++
+ 	s3c2412_clk_initparents();
+ 
+ 	for (ptr = 0; ptr < ARRAY_SIZE(clks); ptr++) {
+@@ -655,6 +698,15 @@ int __init s3c2412_baseclk_add(void)
+ 		}
+ 	}
+ 
++	/* set the dvs state according to what we got at boot time */
++
++	dvs = __raw_readl(S3C2410_CLKDIVN) & S3C2412_CLKDIVN_DVSEN;
++
++	if (dvs)
++		clk_armclk.parent = &clk_h;
++
++	printk(KERN_INFO "S3C2412: DVS is %s\n", dvs ? "on" : "off");
++
+ 	/* ensure usb bus clock is within correct rate of 48MHz */
+ 
+ 	if (clk_get_rate(&clk_usb_bus) != (48 * 1000 * 1000)) {
+diff --git a/arch/arm/mach-s3c2412/dma.c b/arch/arm/mach-s3c2412/dma.c
+index 53c1d5b..1dd8649 100644
+--- a/arch/arm/mach-s3c2412/dma.c
++++ b/arch/arm/mach-s3c2412/dma.c
+@@ -30,6 +30,7 @@
+ #include <asm/arch/regs-mem.h>
+ #include <asm/arch/regs-lcd.h>
+ #include <asm/arch/regs-sdi.h>
++#include <asm/plat-s3c24xx/regs-s3c2412-iis.h>
+ #include <asm/plat-s3c24xx/regs-iis.h>
+ #include <asm/plat-s3c24xx/regs-spi.h>
+ 
+@@ -39,106 +40,141 @@ static struct s3c24xx_dma_map __initdata s3c2412_dma_mappings[] = {
+ 	[DMACH_XD0] = {
+ 		.name		= "xdreq0",
+ 		.channels	= MAP(S3C2412_DMAREQSEL_XDREQ0),
++		.channels_rx	= MAP(S3C2412_DMAREQSEL_XDREQ0),
+ 	},
+ 	[DMACH_XD1] = {
+ 		.name		= "xdreq1",
+ 		.channels	= MAP(S3C2412_DMAREQSEL_XDREQ1),
++		.channels_rx	= MAP(S3C2412_DMAREQSEL_XDREQ1),
+ 	},
+ 	[DMACH_SDI] = {
+ 		.name		= "sdi",
+ 		.channels	= MAP(S3C2412_DMAREQSEL_SDI),
+-		.hw_addr.to	= S3C2410_PA_IIS + S3C2410_IISFIFO,
+-		.hw_addr.from	= S3C2410_PA_IIS + S3C2410_IISFIFO,
++		.channels_rx	= MAP(S3C2412_DMAREQSEL_SDI),
++		.hw_addr.to	= S3C2410_PA_SDI + S3C2410_SDIDATA,
++		.hw_addr.from	= S3C2410_PA_SDI + S3C2410_SDIDATA,
+ 	},
+ 	[DMACH_SPI0] = {
+ 		.name		= "spi0",
+ 		.channels	= MAP(S3C2412_DMAREQSEL_SPI0TX),
++		.channels_rx	= MAP(S3C2412_DMAREQSEL_SPI0RX),
+ 		.hw_addr.to	= S3C2410_PA_SPI + S3C2410_SPTDAT,
+ 		.hw_addr.from	= S3C2410_PA_SPI + S3C2410_SPRDAT,
+ 	},
+ 	[DMACH_SPI1] = {
+ 		.name		= "spi1",
+ 		.channels	= MAP(S3C2412_DMAREQSEL_SPI1TX),
++		.channels_rx	= MAP(S3C2412_DMAREQSEL_SPI1RX),
+ 		.hw_addr.to	= S3C2410_PA_SPI + S3C2412_SPI1 + S3C2410_SPTDAT,
+ 		.hw_addr.from	= S3C2410_PA_SPI + S3C2412_SPI1  + S3C2410_SPRDAT,
+ 	},
+ 	[DMACH_UART0] = {
+ 		.name		= "uart0",
+ 		.channels	= MAP(S3C2412_DMAREQSEL_UART0_0),
++		.channels_rx	= MAP(S3C2412_DMAREQSEL_UART0_0),
+ 		.hw_addr.to	= S3C2410_PA_UART0 + S3C2410_UTXH,
+ 		.hw_addr.from	= S3C2410_PA_UART0 + S3C2410_URXH,
+ 	},
+ 	[DMACH_UART1] = {
+ 		.name		= "uart1",
+ 		.channels	= MAP(S3C2412_DMAREQSEL_UART1_0),
++		.channels_rx	= MAP(S3C2412_DMAREQSEL_UART1_0),
+ 		.hw_addr.to	= S3C2410_PA_UART1 + S3C2410_UTXH,
+ 		.hw_addr.from	= S3C2410_PA_UART1 + S3C2410_URXH,
+ 	},
+       	[DMACH_UART2] = {
+ 		.name		= "uart2",
+ 		.channels	= MAP(S3C2412_DMAREQSEL_UART2_0),
++		.channels_rx	= MAP(S3C2412_DMAREQSEL_UART2_0),
+ 		.hw_addr.to	= S3C2410_PA_UART2 + S3C2410_UTXH,
+ 		.hw_addr.from	= S3C2410_PA_UART2 + S3C2410_URXH,
+ 	},
+ 	[DMACH_UART0_SRC2] = {
+ 		.name		= "uart0",
+ 		.channels	= MAP(S3C2412_DMAREQSEL_UART0_1),
++		.channels_rx	= MAP(S3C2412_DMAREQSEL_UART0_1),
+ 		.hw_addr.to	= S3C2410_PA_UART0 + S3C2410_UTXH,
+ 		.hw_addr.from	= S3C2410_PA_UART0 + S3C2410_URXH,
+ 	},
+ 	[DMACH_UART1_SRC2] = {
+ 		.name		= "uart1",
+ 		.channels	= MAP(S3C2412_DMAREQSEL_UART1_1),
++		.channels_rx	= MAP(S3C2412_DMAREQSEL_UART1_1),
+ 		.hw_addr.to	= S3C2410_PA_UART1 + S3C2410_UTXH,
+ 		.hw_addr.from	= S3C2410_PA_UART1 + S3C2410_URXH,
+ 	},
+       	[DMACH_UART2_SRC2] = {
+ 		.name		= "uart2",
+ 		.channels	= MAP(S3C2412_DMAREQSEL_UART2_1),
++		.channels_rx	= MAP(S3C2412_DMAREQSEL_UART2_1),
+ 		.hw_addr.to	= S3C2410_PA_UART2 + S3C2410_UTXH,
+ 		.hw_addr.from	= S3C2410_PA_UART2 + S3C2410_URXH,
+ 	},
+ 	[DMACH_TIMER] = {
+ 		.name		= "timer",
+ 		.channels	= MAP(S3C2412_DMAREQSEL_TIMER),
++		.channels_rx	= MAP(S3C2412_DMAREQSEL_TIMER),
+ 	},
+ 	[DMACH_I2S_IN] = {
+ 		.name		= "i2s-sdi",
+ 		.channels	= MAP(S3C2412_DMAREQSEL_I2SRX),
+-		.hw_addr.from	= S3C2410_PA_IIS + S3C2410_IISFIFO,
++		.channels_rx	= MAP(S3C2412_DMAREQSEL_I2SRX),
++		.hw_addr.from	= S3C2410_PA_IIS + S3C2412_IISRXD,
+ 	},
+ 	[DMACH_I2S_OUT] = {
+ 		.name		= "i2s-sdo",
+ 		.channels	= MAP(S3C2412_DMAREQSEL_I2STX),
+-		.hw_addr.to	= S3C2410_PA_IIS + S3C2410_IISFIFO,
++		.channels_rx	= MAP(S3C2412_DMAREQSEL_I2STX),
++		.hw_addr.to	= S3C2410_PA_IIS + S3C2412_IISTXD,
+ 	},
+ 	[DMACH_USB_EP1] = {
+ 		.name		= "usb-ep1",
+ 		.channels	= MAP(S3C2412_DMAREQSEL_USBEP1),
++		.channels_rx	= MAP(S3C2412_DMAREQSEL_USBEP1),
+ 	},
+ 	[DMACH_USB_EP2] = {
+ 		.name		= "usb-ep2",
+ 		.channels	= MAP(S3C2412_DMAREQSEL_USBEP2),
++		.channels_rx	= MAP(S3C2412_DMAREQSEL_USBEP2),
+ 	},
+ 	[DMACH_USB_EP3] = {
+ 		.name		= "usb-ep3",
+ 		.channels	= MAP(S3C2412_DMAREQSEL_USBEP3),
++		.channels_rx	= MAP(S3C2412_DMAREQSEL_USBEP3),
+ 	},
+ 	[DMACH_USB_EP4] = {
+ 		.name		= "usb-ep4",
+ 		.channels	= MAP(S3C2412_DMAREQSEL_USBEP4),
++		.channels_rx	= MAP(S3C2412_DMAREQSEL_USBEP4),
+ 	},
+ };
+ 
++static void s3c2412_dma_direction(struct s3c2410_dma_chan *chan,
++				  struct s3c24xx_dma_map *map,
++				  enum s3c2410_dmasrc dir)
++{
++	unsigned long chsel;
++
++	if (dir == S3C2410_DMASRC_HW)
++		chsel = map->channels_rx[0];
++	else
++		chsel = map->channels[0];
++
++	chsel &= ~DMA_CH_VALID;
++	chsel |= S3C2412_DMAREQSEL_HW;
++
++	writel(chsel, chan->regs + S3C2412_DMA_DMAREQSEL);
++}
++
+ static void s3c2412_dma_select(struct s3c2410_dma_chan *chan,
+ 			       struct s3c24xx_dma_map *map)
+ {
+-	writel(map->channels[0] | S3C2412_DMAREQSEL_HW,
+-	       chan->regs + S3C2412_DMA_DMAREQSEL);
++	s3c2412_dma_direction(chan, map, chan->source);
+ }
+ 
+ static struct s3c24xx_dma_selection __initdata s3c2412_dma_sel = {
+ 	.select		= s3c2412_dma_select,
++	.direction	= s3c2412_dma_direction,
+ 	.dcon_mask	= 0,
+ 	.map		= s3c2412_dma_mappings,
+ 	.map_size	= ARRAY_SIZE(s3c2412_dma_mappings),
+diff --git a/arch/arm/mach-s3c2412/gpio.c b/arch/arm/mach-s3c2412/gpio.c
+new file mode 100644
+index 0000000..8e55c3a
+--- /dev/null
++++ b/arch/arm/mach-s3c2412/gpio.c
+@@ -0,0 +1,60 @@
++/* linux/arch/arm/mach-s3c2412/gpio.c
++ *
++ * Copyright (c) 2007 Simtec Electronics
++ *	Ben Dooks <ben at simtec.co.uk>
++ *
++ * http://armlinux.simtec.co.uk/.
++ *
++ * S3C2412/S3C2413 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 version 2 as
++ * published by the Free Software Foundation.
++*/
++
++#include <linux/kernel.h>
++#include <linux/types.h>
++#include <linux/module.h>
++#include <linux/interrupt.h>
++
++#include <asm/mach/arch.h>
++#include <asm/mach/map.h>
++
++#include <asm/arch/regs-gpio.h>
++
++#include <asm/hardware.h>
++
++int s3c2412_gpio_set_sleepcfg(unsigned int pin, unsigned int state)
++{
++	void __iomem *base = S3C24XX_GPIO_BASE(pin);
++	unsigned long offs = S3C2410_GPIO_OFFSET(pin);
++	unsigned long flags;
++	unsigned long slpcon;
++
++	offs *= 2;
++
++	if (pin < S3C2410_GPIO_BANKB)
++		return -EINVAL;
++
++	if (pin >= S3C2410_GPIO_BANKF &&
++	    pin <= S3C2410_GPIO_BANKG)
++		return -EINVAL;
++
++	if (pin > (S3C2410_GPIO_BANKH + 32))
++		return -EINVAL;
++
++	local_irq_save(flags);
++
++	slpcon = __raw_readl(base + 0x0C);
++
++	slpcon &= ~(3 << offs);
++	slpcon |= state << offs;
++
++	__raw_writel(slpcon, base + 0x0C);
++
++	local_irq_restore(flags);
++
++	return 0;
++}
++
++EXPORT_SYMBOL(s3c2412_gpio_set_sleepcfg);
+diff --git a/arch/arm/mach-s3c2412/irq.c b/arch/arm/mach-s3c2412/irq.c
+index e9d0c76..cc1917b 100644
+--- a/arch/arm/mach-s3c2412/irq.c
++++ b/arch/arm/mach-s3c2412/irq.c
+@@ -33,6 +33,7 @@
+ 
+ #include <asm/arch/regs-irq.h>
+ #include <asm/arch/regs-gpio.h>
++#include <asm/arch/regs-power.h>
+ 
+ #include <asm/plat-s3c24xx/cpu.h>
+ #include <asm/plat-s3c24xx/irq.h>
+@@ -153,6 +154,22 @@ static struct irq_chip s3c2412_irq_cfsdi = {
+ 	.unmask		= s3c2412_irq_cfsdi_unmask,
+ };
+ 
++static int s3c2412_irq_rtc_wake(unsigned int irqno, unsigned int state)
++{
++	unsigned long pwrcfg;
++
++	pwrcfg = __raw_readl(S3C2412_PWRCFG);
++	if (state)
++		pwrcfg &= ~S3C2412_PWRCFG_RTC_MASKIRQ;
++	else
++		pwrcfg |= S3C2412_PWRCFG_RTC_MASKIRQ;
++	__raw_writel(pwrcfg, S3C2412_PWRCFG);
++
++	return s3c_irq_chip.set_wake(irqno, state);
++}
++
++static struct irq_chip s3c2412_irq_rtc_chip;
++
+ static int s3c2412_irq_add(struct sys_device *sysdev)
+ {
+ 	unsigned int irqno;
+@@ -173,6 +190,13 @@ static int s3c2412_irq_add(struct sys_device *sysdev)
+ 		set_irq_flags(irqno, IRQF_VALID);
+ 	}
+ 
++	/* change RTC IRQ's set wake method */
++
++	s3c2412_irq_rtc_chip = s3c_irq_chip;
++	s3c2412_irq_rtc_chip.set_wake = s3c2412_irq_rtc_wake;
++
++	set_irq_chip(IRQ_RTC, &s3c2412_irq_rtc_chip);
++
+ 	return 0;
+ }
+ 
+diff --git a/arch/arm/mach-s3c2412/pm.c b/arch/arm/mach-s3c2412/pm.c
+index 8988dac..d4ffb2d 100644
+--- a/arch/arm/mach-s3c2412/pm.c
++++ b/arch/arm/mach-s3c2412/pm.c
+@@ -33,6 +33,8 @@
+ 
+ #include <asm/plat-s3c24xx/s3c2412.h>
+ 
++extern void s3c2412_sleep_enter(void);
++
+ static void s3c2412_cpu_suspend(void)
+ {
+ 	unsigned long tmp;
+@@ -43,20 +45,7 @@ static void s3c2412_cpu_suspend(void)
+ 	tmp |= S3C2412_PWRCFG_STANDBYWFI_SLEEP;
+ 	__raw_writel(tmp, S3C2412_PWRCFG);
+ 
+-	/* issue the standby signal into the pm unit. Note, we
+-	 * issue a write-buffer drain just in case */
+-
+-	tmp = 0;
+-
+-	asm("b 1f\n\t"
+-	    ".align 5\n\t"
+-	    "1:\n\t"
+-	    "mcr p15, 0, %0, c7, c10, 4\n\t"
+-	    "mcr p15, 0, %0, c7, c0, 4" :: "r" (tmp));
+-
+-	/* we should never get past here */
+-
+-	panic("sleep resumed to originator?");
++	s3c2412_sleep_enter();
+ }
+ 
+ static void s3c2412_pm_prepare(void)
+@@ -88,7 +77,6 @@ static struct sleep_save s3c2412_sleep[] = {
+ 	SAVE_ITEM(S3C2412_GPBSLPCON),
+ 	SAVE_ITEM(S3C2412_GPCSLPCON),
+ 	SAVE_ITEM(S3C2412_GPDSLPCON),
+-	SAVE_ITEM(S3C2412_GPESLPCON),
+ 	SAVE_ITEM(S3C2412_GPFSLPCON),
+ 	SAVE_ITEM(S3C2412_GPGSLPCON),
+ 	SAVE_ITEM(S3C2412_GPHSLPCON),
+diff --git a/arch/arm/mach-s3c2412/s3c2412.c b/arch/arm/mach-s3c2412/s3c2412.c
+index 4f92a15..abf1599 100644
+--- a/arch/arm/mach-s3c2412/s3c2412.c
++++ b/arch/arm/mach-s3c2412/s3c2412.c
+@@ -168,6 +168,8 @@ void __init s3c2412_init_clocks(int xtal)
+ 
+ 	fclk = s3c2410_get_pll(__raw_readl(S3C2410_MPLLCON), xtal*2);
+ 
++	clk_mpll.rate = fclk;
++
+ 	tmp = __raw_readl(S3C2410_CLKDIVN);
+ 
+ 	/* work out clock scalings */
+@@ -196,7 +198,7 @@ void __init s3c2412_init_clocks(int xtal)
+ */
+ 
+ struct sysdev_class s3c2412_sysclass = {
+-	set_kset_name("s3c2412-core"),
++	.name = "s3c2412-core",
+ };
+ 
+ static int __init s3c2412_core_init(void)
+diff --git a/arch/arm/mach-s3c2412/sleep.S b/arch/arm/mach-s3c2412/sleep.S
+new file mode 100644
+index 0000000..db32cac
+--- /dev/null
++++ b/arch/arm/mach-s3c2412/sleep.S
+@@ -0,0 +1,68 @@
++/* linux/arch/arm/mach-s3c2412/sleep.S
++ *
++ * Copyright (c) 2007 Simtec Electronics
++ *	Ben Dooks <ben at simtec.co.uk>
++ *
++ * S3C2412 Power Manager low-level sleep support
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You 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/linkage.h>
++#include <asm/assembler.h>
++#include <asm/hardware.h>
++#include <asm/arch/map.h>
++
++#include <asm/arch/regs-irq.h>
++
++	.text
++
++	.global	s3c2412_sleep_enter
++
++s3c2412_sleep_enter:
++	mov	r0, #0			/* argument for coprocessors */
++	ldr	r1, =S3C2410_INTPND
++	ldr	r2, =S3C2410_SRCPND
++	ldr	r3, =S3C2410_EINTPEND
++
++	teq	r0, r0
++	bl	s3c2412_sleep_enter1
++	teq	pc, r0
++	bl	s3c2412_sleep_enter1
++
++	.align	5
++
++	/* this is called twice, first with the Z flag to ensure that the
++	 * instructions have been loaded into the cache, and the second
++	 * time to try and suspend the system.
++	*/
++s3c2412_sleep_enter1:
++	mcr	p15, 0, r0, c7, c10, 4
++	mcrne	p15, 0, r0, c7, c0, 4
++
++	/* if we return from here, it is because an interrupt was
++	 * active when we tried to shutdown. Try and ack the IRQ and
++	 * retry, as simply returning causes the system to lock.
++	*/
++
++	ldrne	r9, [ r1 ]
++	strne	r9, [ r1 ]
++	ldrne	r9, [ r2 ]
++	strne	r9, [ r2 ]
++	ldrne	r9, [ r3 ]
++	strne	r9, [ r3 ]
++	bne	s3c2412_sleep_enter1
++
++	mov	pc, r14
+diff --git a/arch/arm/mach-s3c2440/clock.c b/arch/arm/mach-s3c2440/clock.c
+index 79e2ea4..184d804 100644
+--- a/arch/arm/mach-s3c2440/clock.c
++++ b/arch/arm/mach-s3c2440/clock.c
+@@ -111,14 +111,9 @@ static struct clk s3c2440_clk_ac97 = {
+ 
+ static int s3c2440_clk_add(struct sys_device *sysdev)
+ {
+-	unsigned long camdivn = __raw_readl(S3C2440_CAMDIVN);
+-	unsigned long clkdivn;
++	struct clk *clock_upll;
+ 	struct clk *clock_h;
+ 	struct clk *clock_p;
+-	struct clk *clock_upll;
+-
+-	printk("S3C2440: Clock Support, DVS %s\n",
+-	       (camdivn & S3C2440_CAMDIVN_DVSEN) ? "on" : "off");
+ 
+ 	clock_p = clk_get(NULL, "pclk");
+ 	clock_h = clk_get(NULL, "hclk");
+@@ -129,21 +124,6 @@ static int s3c2440_clk_add(struct sys_device *sysdev)
+ 		return -EINVAL;
+ 	}
+ 
+-	/* check rate of UPLL, and if it is near 96MHz, then change
+-	 * to using half the UPLL rate for the system */
+-
+-	if (clk_get_rate(clock_upll) > (94 * MHZ)) {
+-		clk_usb_bus.rate = clk_get_rate(clock_upll) / 2;
+-
+-		mutex_lock(&clocks_mutex);
+-
+-		clkdivn = __raw_readl(S3C2410_CLKDIVN);
+-		clkdivn |= S3C2440_CLKDIVN_UCLK;
+-		__raw_writel(clkdivn, S3C2410_CLKDIVN);
+-
+-		mutex_unlock(&clocks_mutex);
+-	}
+-
+ 	s3c2440_clk_cam.parent = clock_h;
+ 	s3c2440_clk_ac97.parent = clock_p;
+ 	s3c2440_clk_cam_upll.parent = clock_upll;
+diff --git a/arch/arm/mach-s3c2440/mach-osiris.c b/arch/arm/mach-s3c2440/mach-osiris.c
+index c326983..78af766 100644
+--- a/arch/arm/mach-s3c2440/mach-osiris.c
++++ b/arch/arm/mach-s3c2440/mach-osiris.c
+@@ -312,7 +312,7 @@ static int osiris_pm_resume(struct sys_device *sd)
+ #endif
+ 
+ static struct sysdev_class osiris_pm_sysclass = {
+-	set_kset_name("mach-osiris"),
++	.name		= "mach-osiris",
+ 	.suspend	= osiris_pm_suspend,
+ 	.resume		= osiris_pm_resume,
+ };
+diff --git a/arch/arm/mach-s3c2442/clock.c b/arch/arm/mach-s3c2442/clock.c
+index 5b9e830..2d030d4 100644
+--- a/arch/arm/mach-s3c2442/clock.c
++++ b/arch/arm/mach-s3c2442/clock.c
+@@ -115,14 +115,9 @@ static struct clk s3c2442_clk_cam_upll = {
+ 
+ static int s3c2442_clk_add(struct sys_device *sysdev)
+ {
+-	unsigned long camdivn = __raw_readl(S3C2440_CAMDIVN);
+-	unsigned long clkdivn;
++	struct clk *clock_upll;
+ 	struct clk *clock_h;
+ 	struct clk *clock_p;
+-	struct clk *clock_upll;
+-
+-	printk("S3C2442: Clock Support, DVS %s\n",
+-	       (camdivn & S3C2440_CAMDIVN_DVSEN) ? "on" : "off");
+ 
+ 	clock_p = clk_get(NULL, "pclk");
+ 	clock_h = clk_get(NULL, "hclk");
+@@ -133,21 +128,6 @@ static int s3c2442_clk_add(struct sys_device *sysdev)
+ 		return -EINVAL;
+ 	}
+ 
+-	/* check rate of UPLL, and if it is near 96MHz, then change
+-	 * to using half the UPLL rate for the system */
+-
+-	if (clk_get_rate(clock_upll) > (94 * MHZ)) {
+-		clk_usb_bus.rate = clk_get_rate(clock_upll) / 2;
+-
+-		mutex_lock(&clocks_mutex);
+-
+-		clkdivn = __raw_readl(S3C2410_CLKDIVN);
+-		clkdivn |= S3C2440_CLKDIVN_UCLK;
+-		__raw_writel(clkdivn, S3C2410_CLKDIVN);
+-
+-		mutex_unlock(&clocks_mutex);
+-	}
+-
+ 	s3c2442_clk_cam.parent = clock_h;
+ 	s3c2442_clk_cam_upll.parent = clock_upll;
+ 
+diff --git a/arch/arm/mach-s3c2443/s3c2443.c b/arch/arm/mach-s3c2443/s3c2443.c
+index 8d81171..9ce4905 100644
+--- a/arch/arm/mach-s3c2443/s3c2443.c
++++ b/arch/arm/mach-s3c2443/s3c2443.c
+@@ -43,7 +43,7 @@ static struct map_desc s3c2443_iodesc[] __initdata = {
+ };
+ 
+ struct sysdev_class s3c2443_sysclass = {
+-	set_kset_name("s3c2443-core"),
++	.name = "s3c2443-core",
+ };
+ 
+ static struct sys_device s3c2443_sysdev = {
+diff --git a/arch/arm/mach-sa1100/irq.c b/arch/arm/mach-sa1100/irq.c
+index edf3347..3dc17d7 100644
+--- a/arch/arm/mach-sa1100/irq.c
++++ b/arch/arm/mach-sa1100/irq.c
+@@ -283,7 +283,7 @@ static int sa1100irq_resume(struct sys_device *dev)
+ }
+ 
+ static struct sysdev_class sa1100irq_sysclass = {
+-	set_kset_name("sa11x0-irq"),
++	.name		= "sa11x0-irq",
+ 	.suspend	= sa1100irq_suspend,
+ 	.resume		= sa1100irq_resume,
+ };
+diff --git a/arch/arm/mach-sa1100/ssp.c b/arch/arm/mach-sa1100/ssp.c
+index 59703c6..06206ce 100644
+--- a/arch/arm/mach-sa1100/ssp.c
++++ b/arch/arm/mach-sa1100/ssp.c
+@@ -29,9 +29,8 @@ static irqreturn_t ssp_interrupt(int irq, void *dev_id)
+ {
+ 	unsigned int status = Ser4SSSR;
+ 
+-	if (status & SSSR_ROR) {
++	if (status & SSSR_ROR)
+ 		printk(KERN_WARNING "SSP: receiver overrun\n");
+-	}
+ 
+ 	Ser4SSSR = SSSR_ROR;
+ 
+diff --git a/arch/arm/mach-sa1100/time.c b/arch/arm/mach-sa1100/time.c
+index fdf7b01..c267736 100644
+--- a/arch/arm/mach-sa1100/time.c
++++ b/arch/arm/mach-sa1100/time.c
+@@ -14,6 +14,7 @@
+ #include <linux/irq.h>
+ #include <linux/timex.h>
+ #include <linux/signal.h>
++#include <linux/clocksource.h>
+ 
+ #include <asm/mach/time.h>
+ #include <asm/hardware.h>
+@@ -35,23 +36,6 @@ static int sa1100_set_rtc(void)
+ 	return 0;
+ }
+ 
+-/* IRQs are disabled before entering here from do_gettimeofday() */
+-static unsigned long sa1100_gettimeoffset (void)
+-{
+-	unsigned long ticks_to_match, elapsed, usec;
+-
+-	/* Get ticks before next timer match */
+-	ticks_to_match = OSMR0 - OSCR;
+-
+-	/* We need elapsed ticks since last match */
+-	elapsed = LATCH - ticks_to_match;
+-
+-	/* Now convert them to usec */
+-	usec = (unsigned long)(elapsed * (tick_nsec / 1000))/LATCH;
+-
+-	return usec;
+-}
+-
+ #ifdef CONFIG_NO_IDLE_HZ
+ static unsigned long initial_match;
+ static int match_posponed;
+@@ -62,8 +46,6 @@ sa1100_timer_interrupt(int irq, void *dev_id)
+ {
+ 	unsigned int next_match;
+ 
+-	write_seqlock(&xtime_lock);
+-
+ #ifdef CONFIG_NO_IDLE_HZ
+ 	if (match_posponed) {
+ 		match_posponed = 0;
+@@ -85,8 +67,6 @@ sa1100_timer_interrupt(int irq, void *dev_id)
+ 		next_match = (OSMR0 += LATCH);
+ 	} while ((signed long)(next_match - OSCR) <= 0);
+ 
+-	write_sequnlock(&xtime_lock);
+-
+ 	return IRQ_HANDLED;
+ }
+ 
+@@ -96,6 +76,20 @@ static struct irqaction sa1100_timer_irq = {
+ 	.handler	= sa1100_timer_interrupt,
+ };
+ 
++static cycle_t sa1100_read_oscr(void)
++{
++	return OSCR;
++}
++
++static struct clocksource cksrc_sa1100_oscr = {
++	.name		= "oscr",
++	.rating		= 200,
++	.read		= sa1100_read_oscr,
++	.mask		= CLOCKSOURCE_MASK(32),
++	.shift		= 20,
++	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
++};
++
+ static void __init sa1100_timer_init(void)
+ {
+ 	unsigned long flags;
+@@ -109,6 +103,11 @@ static void __init sa1100_timer_init(void)
+ 	OIER = OIER_E0;		/* enable match on timer 0 to cause interrupts */
+ 	OSMR0 = OSCR + LATCH;	/* set initial match */
+ 	local_irq_restore(flags);
++
++	cksrc_sa1100_oscr.mult =
++		clocksource_hz2mult(CLOCK_TICK_RATE, cksrc_sa1100_oscr.shift);
++
++	clocksource_register(&cksrc_sa1100_oscr);
+ }
+ 
+ #ifdef CONFIG_NO_IDLE_HZ
+@@ -182,7 +181,6 @@ struct sys_timer sa1100_timer = {
+ 	.init		= sa1100_timer_init,
+ 	.suspend	= sa1100_timer_suspend,
+ 	.resume		= sa1100_timer_resume,
+-	.offset		= sa1100_gettimeoffset,
+ #ifdef CONFIG_NO_IDLE_HZ
+ 	.dyn_tick	= &sa1100_dyn_tick,
+ #endif
+diff --git a/arch/arm/mach-shark/core.c b/arch/arm/mach-shark/core.c
+index a0545db..09d9f33 100644
+--- a/arch/arm/mach-shark/core.c
++++ b/arch/arm/mach-shark/core.c
+@@ -82,9 +82,7 @@ static void __init shark_map_io(void)
+ static irqreturn_t
+ shark_timer_interrupt(int irq, void *dev_id)
+ {
+-	write_seqlock(&xtime_lock);
+ 	timer_tick();
+-	write_sequnlock(&xtime_lock);
+ 	return IRQ_HANDLED;
+ }
+ 
+diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig
+index 7868f4d..76348f0 100644
+--- a/arch/arm/mm/Kconfig
++++ b/arch/arm/mm/Kconfig
+@@ -171,8 +171,8 @@ config CPU_ARM925T
+ # ARM926T
+ config CPU_ARM926T
+ 	bool "Support ARM926T processor"
+-	depends on ARCH_INTEGRATOR || ARCH_VERSATILE_PB || MACH_VERSATILE_AB || ARCH_OMAP730 || ARCH_OMAP16XX || MACH_REALVIEW_EB || ARCH_PNX4008 || ARCH_NETX || CPU_S3C2412 || ARCH_AT91SAM9260 || ARCH_AT91SAM9261 || ARCH_AT91SAM9263 || ARCH_AT91SAM9RL || ARCH_NS9XXX || ARCH_DAVINCI
+-	default y if ARCH_VERSATILE_PB || MACH_VERSATILE_AB || ARCH_OMAP730 || ARCH_OMAP16XX || ARCH_PNX4008 || ARCH_NETX || CPU_S3C2412 || ARCH_AT91SAM9260 || ARCH_AT91SAM9261 || ARCH_AT91SAM9263 || ARCH_AT91SAM9RL || ARCH_NS9XXX || ARCH_DAVINCI
++	depends on ARCH_INTEGRATOR || ARCH_VERSATILE_PB || MACH_VERSATILE_AB || ARCH_OMAP730 || ARCH_OMAP16XX || MACH_REALVIEW_EB || ARCH_PNX4008 || ARCH_NETX || CPU_S3C2412 || ARCH_AT91SAM9260 || ARCH_AT91SAM9261 || ARCH_AT91SAM9263 || ARCH_AT91SAM9RL || ARCH_AT91CAP9 || ARCH_NS9XXX || ARCH_DAVINCI
++	default y if ARCH_VERSATILE_PB || MACH_VERSATILE_AB || ARCH_OMAP730 || ARCH_OMAP16XX || ARCH_PNX4008 || ARCH_NETX || CPU_S3C2412 || ARCH_AT91SAM9260 || ARCH_AT91SAM9261 || ARCH_AT91SAM9263 || ARCH_AT91SAM9RL || ARCH_AT91CAP9 || ARCH_NS9XXX || ARCH_DAVINCI
+ 	select CPU_32v5
+ 	select CPU_ABRT_EV5TJ
+ 	select CPU_CACHE_VIVT
+@@ -342,11 +342,33 @@ config CPU_XSC3
+ 	select CPU_TLB_V4WBI if MMU
+ 	select IO_36
+ 
++# Feroceon
++config CPU_FEROCEON
++	bool
++	depends on ARCH_ORION
++	default y
++	select CPU_32v5
++	select CPU_ABRT_EV5T
++	select CPU_CACHE_VIVT
++	select CPU_CP15_MMU
++	select CPU_COPY_V4WB if MMU
++	select CPU_TLB_V4WBI if MMU
++
++config CPU_FEROCEON_OLD_ID
++	bool "Accept early Feroceon cores with an ARM926 ID"
++	depends on CPU_FEROCEON && !CPU_ARM926T
++	default y
++	help
++	  This enables the usage of some old Feroceon cores
++	  for which the CPU ID is equal to the ARM926 ID.
++	  Relevant for Feroceon-1850 and early Feroceon-2850.
++
+ # ARMv6
+ config CPU_V6
+ 	bool "Support ARM V6 processor"
+-	depends on ARCH_INTEGRATOR || MACH_REALVIEW_EB || ARCH_OMAP2 || ARCH_MX3
++	depends on ARCH_INTEGRATOR || MACH_REALVIEW_EB || ARCH_OMAP2 || ARCH_MX3 || ARCH_MSM7X00A
+ 	default y if ARCH_MX3
++	default y if ARCH_MSM7X00A
+ 	select CPU_32v6
+ 	select CPU_ABRT_EV6
+ 	select CPU_CACHE_V6
+@@ -538,7 +560,7 @@ comment "Processor Features"
+ 
+ config ARM_THUMB
+ 	bool "Support Thumb user binaries"
+-	depends on CPU_ARM720T || CPU_ARM740T || CPU_ARM920T || CPU_ARM922T || CPU_ARM925T || CPU_ARM926T || CPU_ARM940T || CPU_ARM946E || CPU_ARM1020 || CPU_ARM1020E || CPU_ARM1022 || CPU_ARM1026 || CPU_XSCALE || CPU_XSC3 || CPU_V6 || CPU_V7
++	depends on CPU_ARM720T || CPU_ARM740T || CPU_ARM920T || CPU_ARM922T || CPU_ARM925T || CPU_ARM926T || CPU_ARM940T || CPU_ARM946E || CPU_ARM1020 || CPU_ARM1020E || CPU_ARM1022 || CPU_ARM1026 || CPU_XSCALE || CPU_XSC3 || CPU_V6 || CPU_V7 || CPU_FEROCEON
+ 	default y
+ 	help
+ 	  Say Y if you want to include kernel support for running user space
+@@ -600,7 +622,7 @@ config CPU_DCACHE_SIZE
+ 
+ config CPU_DCACHE_WRITETHROUGH
+ 	bool "Force write through D-cache"
+-	depends on (CPU_ARM740T || CPU_ARM920T || CPU_ARM922T || CPU_ARM925T || CPU_ARM926T || CPU_ARM940T || CPU_ARM946E || CPU_ARM1020) && !CPU_DCACHE_DISABLE
++	depends on (CPU_ARM740T || CPU_ARM920T || CPU_ARM922T || CPU_ARM925T || CPU_ARM926T || CPU_ARM940T || CPU_ARM946E || CPU_ARM1020 || CPU_FEROCEON) && !CPU_DCACHE_DISABLE
+ 	default y if CPU_ARM925T
+ 	help
+ 	  Say Y here to use the data cache in writethrough mode. Unless you
+diff --git a/arch/arm/mm/Makefile b/arch/arm/mm/Makefile
+index 7627027..44536a0 100644
+--- a/arch/arm/mm/Makefile
++++ b/arch/arm/mm/Makefile
+@@ -68,6 +68,7 @@ obj-$(CONFIG_CPU_SA110)		+= proc-sa110.o
+ obj-$(CONFIG_CPU_SA1100)	+= proc-sa1100.o
+ obj-$(CONFIG_CPU_XSCALE)	+= proc-xscale.o
+ obj-$(CONFIG_CPU_XSC3)		+= proc-xsc3.o
++obj-$(CONFIG_CPU_FEROCEON)	+= proc-feroceon.o
+ obj-$(CONFIG_CPU_V6)		+= proc-v6.o
+ obj-$(CONFIG_CPU_V7)		+= proc-v7.o
+ 
+diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c
+index a8a7dab..28ad7ab 100644
+--- a/arch/arm/mm/fault.c
++++ b/arch/arm/mm/fault.c
+@@ -12,6 +12,7 @@
+ #include <linux/signal.h>
+ #include <linux/mm.h>
+ #include <linux/init.h>
++#include <linux/kprobes.h>
+ 
+ #include <asm/system.h>
+ #include <asm/pgtable.h>
+@@ -20,6 +21,29 @@
+ 
+ #include "fault.h"
+ 
++
++#ifdef CONFIG_KPROBES
++static inline int notify_page_fault(struct pt_regs *regs, unsigned int fsr)
++{
++	int ret = 0;
++
++	if (!user_mode(regs)) {
++		/* kprobe_running() needs smp_processor_id() */
++		preempt_disable();
++		if (kprobe_running() && kprobe_fault_handler(regs, fsr))
++			ret = 1;
++		preempt_enable();
++	}
++
++	return ret;
++}
++#else
++static inline int notify_page_fault(struct pt_regs *regs, unsigned int fsr)
++{
++	return 0;
++}
++#endif
++
+ /*
+  * This is useful to dump out the page tables associated with
+  * 'addr' in mm 'mm'.
+@@ -215,13 +239,16 @@ out:
+ 	return fault;
+ }
+ 
+-static int
++static int __kprobes
+ do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
+ {
+ 	struct task_struct *tsk;
+ 	struct mm_struct *mm;
+ 	int fault, sig, code;
+ 
++	if (notify_page_fault(regs, fsr))
++		return 0;
++
+ 	tsk = current;
+ 	mm  = tsk->mm;
+ 
+@@ -311,7 +338,7 @@ no_context:
+  * interrupt or a critical region, and should only copy the information
+  * from the master page table, nothing more.
+  */
+-static int
++static int __kprobes
+ do_translation_fault(unsigned long addr, unsigned int fsr,
+ 		     struct pt_regs *regs)
+ {
+diff --git a/arch/arm/mm/proc-feroceon.S b/arch/arm/mm/proc-feroceon.S
+new file mode 100644
+index 0000000..fa0dc7e
+--- /dev/null
++++ b/arch/arm/mm/proc-feroceon.S
+@@ -0,0 +1,506 @@
++/*
++ *  linux/arch/arm/mm/proc-feroceon.S: MMU functions for Feroceon
++ *
++ *  Heavily based on proc-arm926.S
++ *  Maintainer: Assaf Hoffman <hoffman at marvell.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/linkage.h>
++#include <linux/init.h>
++#include <asm/assembler.h>
++#include <asm/elf.h>
++#include <asm/pgtable-hwdef.h>
++#include <asm/pgtable.h>
++#include <asm/page.h>
++#include <asm/ptrace.h>
++#include "proc-macros.S"
++
++/*
++ * This is the maximum size of an area which will be invalidated
++ * using the single invalidate entry instructions.  Anything larger
++ * than this, and we go for the whole cache.
++ *
++ * This value should be chosen such that we choose the cheapest
++ * alternative.
++ */
++#define CACHE_DLIMIT	16384
++
++/*
++ * the cache line size of the I and D cache
++ */
++#define CACHE_DLINESIZE	32
++
++	.text
++/*
++ * cpu_feroceon_proc_init()
++ */
++ENTRY(cpu_feroceon_proc_init)
++	mov	pc, lr
++
++/*
++ * cpu_feroceon_proc_fin()
++ */
++ENTRY(cpu_feroceon_proc_fin)
++	stmfd	sp!, {lr}
++	mov	ip, #PSR_F_BIT | PSR_I_BIT | SVC_MODE
++	msr	cpsr_c, ip
++	bl	feroceon_flush_kern_cache_all
++	mrc	p15, 0, r0, c1, c0, 0		@ ctrl register
++	bic	r0, r0, #0x1000			@ ...i............
++	bic	r0, r0, #0x000e			@ ............wca.
++	mcr	p15, 0, r0, c1, c0, 0		@ disable caches
++	ldmfd	sp!, {pc}
++
++/*
++ * cpu_feroceon_reset(loc)
++ *
++ * Perform a soft reset of the system.  Put the CPU into the
++ * same state as it would be if it had been reset, and branch
++ * to what would be the reset vector.
++ *
++ * loc: location to jump to for soft reset
++ */
++	.align	5
++ENTRY(cpu_feroceon_reset)
++	mov	ip, #0
++	mcr	p15, 0, ip, c7, c7, 0		@ invalidate I,D caches
++	mcr	p15, 0, ip, c7, c10, 4		@ drain WB
++#ifdef CONFIG_MMU
++	mcr	p15, 0, ip, c8, c7, 0		@ invalidate I & D TLBs
++#endif
++	mrc	p15, 0, ip, c1, c0, 0		@ ctrl register
++	bic	ip, ip, #0x000f			@ ............wcam
++	bic	ip, ip, #0x1100			@ ...i...s........
++	mcr	p15, 0, ip, c1, c0, 0		@ ctrl register
++	mov	pc, r0
++
++/*
++ * cpu_feroceon_do_idle()
++ *
++ * Called with IRQs disabled
++ */
++	.align	10
++ENTRY(cpu_feroceon_do_idle)
++	mov	r0, #0
++	mcr	p15, 0, r0, c7, c10, 4		@ Drain write buffer
++	mcr	p15, 0, r0, c7, c0, 4		@ Wait for interrupt
++	mov	pc, lr
++
++/*
++ *	flush_user_cache_all()
++ *
++ *	Clean and invalidate all cache entries in a particular
++ *	address space.
++ */
++ENTRY(feroceon_flush_user_cache_all)
++	/* FALLTHROUGH */
++
++/*
++ *	flush_kern_cache_all()
++ *
++ *	Clean and invalidate the entire cache.
++ */
++ENTRY(feroceon_flush_kern_cache_all)
++	mov	r2, #VM_EXEC
++	mov	ip, #0
++__flush_whole_cache:
++#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
++	mcr	p15, 0, ip, c7, c6, 0		@ invalidate D cache
++#else
++1:	mrc	p15, 0, r15, c7, c14, 3 	@ test,clean,invalidate
++	bne	1b
++#endif
++	tst	r2, #VM_EXEC
++	mcrne	p15, 0, ip, c7, c5, 0		@ invalidate I cache
++	mcrne	p15, 0, ip, c7, c10, 4		@ drain WB
++	mov	pc, lr
++
++/*
++ *	flush_user_cache_range(start, end, flags)
++ *
++ *	Clean and invalidate a range of cache entries in the
++ *	specified address range.
++ *
++ *	- start	- start address (inclusive)
++ *	- end	- end address (exclusive)
++ *	- flags	- vm_flags describing address space
++ */
++ENTRY(feroceon_flush_user_cache_range)
++	mov	ip, #0
++	sub	r3, r1, r0			@ calculate total size
++	cmp	r3, #CACHE_DLIMIT
++	bgt	__flush_whole_cache
++1:	tst	r2, #VM_EXEC
++#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
++	mcr	p15, 0, r0, c7, c6, 1		@ invalidate D entry
++	mcrne	p15, 0, r0, c7, c5, 1		@ invalidate I entry
++	add	r0, r0, #CACHE_DLINESIZE
++	mcr	p15, 0, r0, c7, c6, 1		@ invalidate D entry
++	mcrne	p15, 0, r0, c7, c5, 1		@ invalidate I entry
++	add	r0, r0, #CACHE_DLINESIZE
++#else
++	mcr	p15, 0, r0, c7, c14, 1		@ clean and invalidate D entry
++	mcrne	p15, 0, r0, c7, c5, 1		@ invalidate I entry
++	add	r0, r0, #CACHE_DLINESIZE
++	mcr	p15, 0, r0, c7, c14, 1		@ clean and invalidate D entry
++	mcrne	p15, 0, r0, c7, c5, 1		@ invalidate I entry
++	add	r0, r0, #CACHE_DLINESIZE
++#endif
++	cmp	r0, r1
++	blo	1b
++	tst	r2, #VM_EXEC
++	mcrne	p15, 0, ip, c7, c10, 4		@ drain WB
++	mov	pc, lr
++
++/*
++ *	coherent_kern_range(start, end)
++ *
++ *	Ensure coherency between the Icache and the Dcache in the
++ *	region described by start, end.  If you have non-snooping
++ *	Harvard caches, you need to implement this function.
++ *
++ *	- start	- virtual start address
++ *	- end	- virtual end address
++ */
++ENTRY(feroceon_coherent_kern_range)
++	/* FALLTHROUGH */
++
++/*
++ *	coherent_user_range(start, end)
++ *
++ *	Ensure coherency between the Icache and the Dcache in the
++ *	region described by start, end.  If you have non-snooping
++ *	Harvard caches, you need to implement this function.
++ *
++ *	- start	- virtual start address
++ *	- end	- virtual end address
++ */
++ENTRY(feroceon_coherent_user_range)
++	bic	r0, r0, #CACHE_DLINESIZE - 1
++1:	mcr	p15, 0, r0, c7, c10, 1		@ clean D entry
++	mcr	p15, 0, r0, c7, c5, 1		@ invalidate I entry
++	add	r0, r0, #CACHE_DLINESIZE
++	cmp	r0, r1
++	blo	1b
++	mcr	p15, 0, r0, c7, c10, 4		@ drain WB
++	mov	pc, lr
++
++/*
++ *	flush_kern_dcache_page(void *page)
++ *
++ *	Ensure no D cache aliasing occurs, either with itself or
++ *	the I cache
++ *
++ *	- addr	- page aligned address
++ */
++ENTRY(feroceon_flush_kern_dcache_page)
++	add	r1, r0, #PAGE_SZ
++1:	mcr	p15, 0, r0, c7, c14, 1		@ clean+invalidate D entry
++	add	r0, r0, #CACHE_DLINESIZE
++	cmp	r0, r1
++	blo	1b
++	mov	r0, #0
++	mcr	p15, 0, r0, c7, c5, 0		@ invalidate I cache
++	mcr	p15, 0, r0, c7, c10, 4		@ drain WB
++	mov	pc, lr
++
++/*
++ *	dma_inv_range(start, end)
++ *
++ *	Invalidate (discard) the specified virtual address range.
++ *	May not write back any entries.  If 'start' or 'end'
++ *	are not cache line aligned, those lines must be written
++ *	back.
++ *
++ *	- start	- virtual start address
++ *	- end	- virtual end address
++ *
++ * (same as v4wb)
++ */
++ENTRY(feroceon_dma_inv_range)
++#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
++	tst	r0, #CACHE_DLINESIZE - 1
++	mcrne	p15, 0, r0, c7, c10, 1		@ clean D entry
++	tst	r1, #CACHE_DLINESIZE - 1
++	mcrne	p15, 0, r1, c7, c10, 1		@ clean D entry
++#endif
++	bic	r0, r0, #CACHE_DLINESIZE - 1
++1:	mcr	p15, 0, r0, c7, c6, 1		@ invalidate D entry
++	add	r0, r0, #CACHE_DLINESIZE
++	cmp	r0, r1
++	blo	1b
++	mcr	p15, 0, r0, c7, c10, 4		@ drain WB
++	mov	pc, lr
++
++/*
++ *	dma_clean_range(start, end)
++ *
++ *	Clean the specified virtual address range.
++ *
++ *	- start	- virtual start address
++ *	- end	- virtual end address
++ *
++ * (same as v4wb)
++ */
++ENTRY(feroceon_dma_clean_range)
++#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
++	bic	r0, r0, #CACHE_DLINESIZE - 1
++1:	mcr	p15, 0, r0, c7, c10, 1		@ clean D entry
++	add	r0, r0, #CACHE_DLINESIZE
++	cmp	r0, r1
++	blo	1b
++#endif
++	mcr	p15, 0, r0, c7, c10, 4		@ drain WB
++	mov	pc, lr
++
++/*
++ *	dma_flush_range(start, end)
++ *
++ *	Clean and invalidate the specified virtual address range.
++ *
++ *	- start	- virtual start address
++ *	- end	- virtual end address
++ */
++ENTRY(feroceon_dma_flush_range)
++	bic	r0, r0, #CACHE_DLINESIZE - 1
++1:
++#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
++	mcr	p15, 0, r0, c7, c14, 1		@ clean+invalidate D entry
++#else
++	mcr	p15, 0, r0, c7, c10, 1		@ clean D entry
++#endif
++	add	r0, r0, #CACHE_DLINESIZE
++	cmp	r0, r1
++	blo	1b
++	mcr	p15, 0, r0, c7, c10, 4		@ drain WB
++	mov	pc, lr
++
++ENTRY(feroceon_cache_fns)
++	.long	feroceon_flush_kern_cache_all
++	.long	feroceon_flush_user_cache_all
++	.long	feroceon_flush_user_cache_range
++	.long	feroceon_coherent_kern_range
++	.long	feroceon_coherent_user_range
++	.long	feroceon_flush_kern_dcache_page
++	.long	feroceon_dma_inv_range
++	.long	feroceon_dma_clean_range
++	.long	feroceon_dma_flush_range
++
++ENTRY(cpu_feroceon_dcache_clean_area)
++#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
++1:	mcr	p15, 0, r0, c7, c10, 1		@ clean D entry
++	add	r0, r0, #CACHE_DLINESIZE
++	subs	r1, r1, #CACHE_DLINESIZE
++	bhi	1b
++#endif
++	mcr	p15, 0, r0, c7, c10, 4		@ drain WB
++	mov	pc, lr
++
++/* =============================== PageTable ============================== */
++
++/*
++ * cpu_feroceon_switch_mm(pgd)
++ *
++ * Set the translation base pointer to be as described by pgd.
++ *
++ * pgd: new page tables
++ */
++	.align	5
++ENTRY(cpu_feroceon_switch_mm)
++#ifdef CONFIG_MMU
++	mov	ip, #0
++#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
++	mcr	p15, 0, ip, c7, c6, 0		@ invalidate D cache
++#else
++@ && 'Clean & Invalidate whole DCache'
++1:	mrc	p15, 0, r15, c7, c14, 3 	@ test,clean,invalidate
++	bne	1b
++#endif
++	mcr	p15, 0, ip, c7, c5, 0		@ invalidate I cache
++	mcr	p15, 0, ip, c7, c10, 4		@ drain WB
++	mcr	p15, 0, r0, c2, c0, 0		@ load page table pointer
++	mcr	p15, 0, ip, c8, c7, 0		@ invalidate I & D TLBs
++#endif
++	mov	pc, lr
++
++/*
++ * cpu_feroceon_set_pte_ext(ptep, pte, ext)
++ *
++ * Set a PTE and flush it out
++ */
++	.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
++
++#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
++	mov	r0, r0
++#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
++	mcr	p15, 0, r0, c7, c10, 1		@ clean D entry
++#endif
++	mcr	p15, 0, r0, c7, c10, 4		@ drain WB
++#endif
++	mov	pc, lr
++
++	__INIT
++
++	.type	__feroceon_setup, #function
++__feroceon_setup:
++	mov	r0, #0
++	mcr	p15, 0, r0, c7, c7		@ invalidate I,D caches on v4
++	mcr	p15, 0, r0, c7, c10, 4		@ drain write buffer on v4
++#ifdef CONFIG_MMU
++	mcr	p15, 0, r0, c8, c7		@ invalidate I,D TLBs on v4
++#endif
++
++
++#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
++	mov	r0, #4				@ disable write-back on caches explicitly
++	mcr	p15, 7, r0, c15, c0, 0
++#endif
++
++	adr	r5, feroceon_crval
++	ldmia	r5, {r5, r6}
++	mrc	p15, 0, r0, c1, c0		@ get control register v4
++	bic	r0, r0, r5
++	orr	r0, r0, r6
++#ifdef CONFIG_CPU_CACHE_ROUND_ROBIN
++	orr	r0, r0, #0x4000			@ .1.. .... .... ....
++#endif
++	mov	pc, lr
++	.size	__feroceon_setup, . - __feroceon_setup
++
++	/*
++	 *  R
++	 * .RVI ZFRS BLDP WCAM
++	 * .011 0001 ..11 0101
++	 *
++	 */
++	.type	feroceon_crval, #object
++feroceon_crval:
++	crval	clear=0x00007f3f, mmuset=0x00003135, ucset=0x00001134
++
++	__INITDATA
++
++/*
++ * Purpose : Function pointers used to access above functions - all calls
++ *	     come through these
++ */
++	.type	feroceon_processor_functions, #object
++feroceon_processor_functions:
++	.word	v5t_early_abort
++	.word	cpu_feroceon_proc_init
++	.word	cpu_feroceon_proc_fin
++	.word	cpu_feroceon_reset
++	.word	cpu_feroceon_do_idle
++	.word	cpu_feroceon_dcache_clean_area
++	.word	cpu_feroceon_switch_mm
++	.word	cpu_feroceon_set_pte_ext
++	.size	feroceon_processor_functions, . - feroceon_processor_functions
++
++	.section ".rodata"
++
++	.type	cpu_arch_name, #object
++cpu_arch_name:
++	.asciz	"armv5te"
++	.size	cpu_arch_name, . - cpu_arch_name
++
++	.type	cpu_elf_name, #object
++cpu_elf_name:
++	.asciz	"v5"
++	.size	cpu_elf_name, . - cpu_elf_name
++
++	.type	cpu_feroceon_name, #object
++cpu_feroceon_name:
++	.asciz	"Feroceon"
++	.size	cpu_feroceon_name, . - cpu_feroceon_name
++
++	.align
++
++	.section ".proc.info.init", #alloc, #execinstr
++
++#ifdef CONFIG_CPU_FEROCEON_OLD_ID
++	.type	__feroceon_old_id_proc_info,#object
++__feroceon_old_id_proc_info:
++	.long	0x41069260
++	.long	0xfffffff0
++	.long   PMD_TYPE_SECT | \
++		PMD_SECT_BUFFERABLE | \
++		PMD_SECT_CACHEABLE | \
++		PMD_BIT4 | \
++		PMD_SECT_AP_WRITE | \
++		PMD_SECT_AP_READ
++	.long   PMD_TYPE_SECT | \
++		PMD_BIT4 | \
++		PMD_SECT_AP_WRITE | \
++		PMD_SECT_AP_READ
++	b	__feroceon_setup
++	.long	cpu_arch_name
++	.long	cpu_elf_name
++	.long	HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP
++	.long	cpu_feroceon_name
++	.long	feroceon_processor_functions
++	.long	v4wbi_tlb_fns
++	.long	v4wb_user_fns
++	.long	feroceon_cache_fns
++	.size	__feroceon_old_id_proc_info, . - __feroceon_old_id_proc_info
++#endif
++
++	.type	__feroceon_proc_info,#object
++__feroceon_proc_info:
++	.long	0x56055310
++	.long	0xfffffff0
++	.long   PMD_TYPE_SECT | \
++		PMD_SECT_BUFFERABLE | \
++		PMD_SECT_CACHEABLE | \
++		PMD_BIT4 | \
++		PMD_SECT_AP_WRITE | \
++		PMD_SECT_AP_READ
++	.long   PMD_TYPE_SECT | \
++		PMD_BIT4 | \
++		PMD_SECT_AP_WRITE | \
++		PMD_SECT_AP_READ
++	b	__feroceon_setup
++	.long	cpu_arch_name
++	.long	cpu_elf_name
++	.long	HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP
++	.long	cpu_feroceon_name
++	.long	feroceon_processor_functions
++	.long	v4wbi_tlb_fns
++	.long	v4wb_user_fns
++	.long	feroceon_cache_fns
++	.size	__feroceon_proc_info, . - __feroceon_proc_info
+diff --git a/arch/arm/oprofile/common.c b/arch/arm/oprofile/common.c
+index a9de727..0a5cf3a 100644
+--- a/arch/arm/oprofile/common.c
++++ b/arch/arm/oprofile/common.c
+@@ -96,7 +96,7 @@ static int op_arm_resume(struct sys_device *dev)
+ }
+ 
+ static struct sysdev_class oprofile_sysclass = {
+-	set_kset_name("oprofile"),
++	.name		= "oprofile",
+ 	.resume		= op_arm_resume,
+ 	.suspend	= op_arm_suspend,
+ };
+diff --git a/arch/arm/plat-omap/debug-devices.c b/arch/arm/plat-omap/debug-devices.c
+index 83a5f8b..f455233 100644
+--- a/arch/arm/plat-omap/debug-devices.c
++++ b/arch/arm/plat-omap/debug-devices.c
+@@ -29,7 +29,7 @@ static struct resource smc91x_resources[] = {
+ 		.flags  = IORESOURCE_MEM,
+ 	},
+ 	[1] = {
+-		.flags  = IORESOURCE_IRQ,
++		.flags  = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWEDGE,
+ 	},
+ };
+ 
+diff --git a/arch/arm/plat-omap/gpio.c b/arch/arm/plat-omap/gpio.c
+index 6097753..b2a87b8 100644
+--- a/arch/arm/plat-omap/gpio.c
++++ b/arch/arm/plat-omap/gpio.c
+@@ -1455,7 +1455,7 @@ static int omap_gpio_resume(struct sys_device *dev)
+ }
+ 
+ static struct sysdev_class omap_gpio_sysclass = {
+-	set_kset_name("gpio"),
++	.name		= "gpio",
+ 	.suspend	= omap_gpio_suspend,
+ 	.resume		= omap_gpio_resume,
+ };
+diff --git a/arch/arm/plat-omap/mailbox.c b/arch/arm/plat-omap/mailbox.c
+index 0360b1f..1945ddf 100644
+--- a/arch/arm/plat-omap/mailbox.c
++++ b/arch/arm/plat-omap/mailbox.c
+@@ -116,8 +116,8 @@ static void mbox_tx_work(struct work_struct *work)
+ 		}
+ 
+ 		spin_lock(q->queue_lock);
+-		blkdev_dequeue_request(rq);
+-		end_that_request_last(rq, 0);
++		if (__blk_end_request(rq, 0, 0))
++			BUG();
+ 		spin_unlock(q->queue_lock);
+ 	}
+ }
+@@ -149,10 +149,8 @@ static void mbox_rx_work(struct work_struct *work)
+ 
+ 		msg = (mbox_msg_t) rq->data;
+ 
+-		spin_lock_irqsave(q->queue_lock, flags);
+-		blkdev_dequeue_request(rq);
+-		end_that_request_last(rq, 0);
+-		spin_unlock_irqrestore(q->queue_lock, flags);
++		if (blk_end_request(rq, 0, 0))
++			BUG();
+ 
+ 		mbox->rxq->callback((void *)msg);
+ 	}
+@@ -212,7 +210,7 @@ static void __mbox_rx_interrupt(struct omap_mbox *mbox)
+ 
+ static irqreturn_t mbox_interrupt(int irq, void *p)
+ {
+-	struct omap_mbox *mbox = (struct omap_mbox *)p;
++	struct omap_mbox *mbox = p;
+ 
+ 	if (is_mbox_irq(mbox, IRQ_TX))
+ 		__mbox_tx_interrupt(mbox);
+@@ -263,10 +261,8 @@ omap_mbox_read(struct device *dev, struct device_attribute *attr, char *buf)
+ 
+ 		*p = (mbox_msg_t) rq->data;
+ 
+-		spin_lock_irqsave(q->queue_lock, flags);
+-		blkdev_dequeue_request(rq);
+-		end_that_request_last(rq, 0);
+-		spin_unlock_irqrestore(q->queue_lock, flags);
++		if (blk_end_request(rq, 0, 0))
++			BUG();
+ 
+ 		if (unlikely(mbox_seq_test(mbox, *p))) {
+ 			pr_info("mbox: Illegal seq bit!(%08x) ignored\n", *p);
+diff --git a/arch/arm/plat-omap/mcbsp.c b/arch/arm/plat-omap/mcbsp.c
+index f7b9ccd..2af5bd5 100644
+--- a/arch/arm/plat-omap/mcbsp.c
++++ b/arch/arm/plat-omap/mcbsp.c
+@@ -98,9 +98,10 @@ static void omap_mcbsp_dump_reg(u8 id)
+ 
+ static irqreturn_t omap_mcbsp_tx_irq_handler(int irq, void *dev_id)
+ {
+-	struct omap_mcbsp * mcbsp_tx = (struct omap_mcbsp *)(dev_id);
++	struct omap_mcbsp *mcbsp_tx = dev_id;
+ 
+-	DBG("TX IRQ callback : 0x%x\n", OMAP_MCBSP_READ(mcbsp_tx->io_base, SPCR2));
++	DBG("TX IRQ callback : 0x%x\n",
++	    OMAP_MCBSP_READ(mcbsp_tx->io_base, SPCR2));
+ 
+ 	complete(&mcbsp_tx->tx_irq_completion);
+ 	return IRQ_HANDLED;
+@@ -108,9 +109,10 @@ static irqreturn_t omap_mcbsp_tx_irq_handler(int irq, void *dev_id)
+ 
+ static irqreturn_t omap_mcbsp_rx_irq_handler(int irq, void *dev_id)
+ {
+-	struct omap_mcbsp * mcbsp_rx = (struct omap_mcbsp *)(dev_id);
++	struct omap_mcbsp *mcbsp_rx = dev_id;
+ 
+-	DBG("RX IRQ callback : 0x%x\n", OMAP_MCBSP_READ(mcbsp_rx->io_base, SPCR2));
++	DBG("RX IRQ callback : 0x%x\n",
++	    OMAP_MCBSP_READ(mcbsp_rx->io_base, SPCR2));
+ 
+ 	complete(&mcbsp_rx->rx_irq_completion);
+ 	return IRQ_HANDLED;
+@@ -118,9 +120,10 @@ static irqreturn_t omap_mcbsp_rx_irq_handler(int irq, void *dev_id)
+ 
+ static void omap_mcbsp_tx_dma_callback(int lch, u16 ch_status, void *data)
+ {
+-	struct omap_mcbsp * mcbsp_dma_tx = (struct omap_mcbsp *)(data);
++	struct omap_mcbsp *mcbsp_dma_tx = data;
+ 
+-	DBG("TX DMA callback : 0x%x\n", OMAP_MCBSP_READ(mcbsp_dma_tx->io_base, SPCR2));
++	DBG("TX DMA callback : 0x%x\n",
++	    OMAP_MCBSP_READ(mcbsp_dma_tx->io_base, SPCR2));
+ 
+ 	/* We can free the channels */
+ 	omap_free_dma(mcbsp_dma_tx->dma_tx_lch);
+@@ -131,9 +134,10 @@ static void omap_mcbsp_tx_dma_callback(int lch, u16 ch_status, void *data)
+ 
+ static void omap_mcbsp_rx_dma_callback(int lch, u16 ch_status, void *data)
+ {
+-	struct omap_mcbsp * mcbsp_dma_rx = (struct omap_mcbsp *)(data);
++	struct omap_mcbsp *mcbsp_dma_rx = data;
+ 
+-	DBG("RX DMA callback : 0x%x\n", OMAP_MCBSP_READ(mcbsp_dma_rx->io_base, SPCR2));
++	DBG("RX DMA callback : 0x%x\n",
++	    OMAP_MCBSP_READ(mcbsp_dma_rx->io_base, SPCR2));
+ 
+ 	/* We can free the channels */
+ 	omap_free_dma(mcbsp_dma_rx->dma_rx_lch);
+diff --git a/arch/arm/plat-s3c24xx/Makefile b/arch/arm/plat-s3c24xx/Makefile
+index 8e5ccaa..131d202 100644
+--- a/arch/arm/plat-s3c24xx/Makefile
++++ b/arch/arm/plat-s3c24xx/Makefile
+@@ -23,6 +23,7 @@ obj-y				+= clock.o
+ 
+ obj-$(CONFIG_CPU_S3C244X)	+= s3c244x.o
+ obj-$(CONFIG_CPU_S3C244X)	+= s3c244x-irq.o
++obj-$(CONFIG_CPU_S3C244X)	+= s3c244x-clock.o
+ obj-$(CONFIG_PM_SIMTEC)		+= pm-simtec.o
+ obj-$(CONFIG_PM)		+= pm.o
+ obj-$(CONFIG_PM)		+= sleep.o
+diff --git a/arch/arm/plat-s3c24xx/clock.c b/arch/arm/plat-s3c24xx/clock.c
+index 79cda0f..99a4474 100644
+--- a/arch/arm/plat-s3c24xx/clock.c
++++ b/arch/arm/plat-s3c24xx/clock.c
+@@ -172,6 +172,15 @@ int clk_set_rate(struct clk *clk, unsigned long rate)
+ 	if (IS_ERR(clk))
+ 		return -EINVAL;
+ 
++	/* We do not default just do a clk->rate = rate as
++	 * the clock may have been made this way by choice.
++	 */
++
++	WARN_ON(clk->set_rate == NULL);
++
++	if (clk->set_rate == NULL)
++		return -EINVAL;
++
+ 	mutex_lock(&clocks_mutex);
+ 	ret = (clk->set_rate)(clk, rate);
+ 	mutex_unlock(&clocks_mutex);
+@@ -213,6 +222,12 @@ EXPORT_SYMBOL(clk_set_parent);
+ 
+ /* base clocks */
+ 
++static int clk_default_setrate(struct clk *clk, unsigned long rate)
++{
++	clk->rate = rate;
++	return 0;
++}
++
+ struct clk clk_xtal = {
+ 	.name		= "xtal",
+ 	.id		= -1,
+@@ -224,6 +239,7 @@ struct clk clk_xtal = {
+ struct clk clk_mpll = {
+ 	.name		= "mpll",
+ 	.id		= -1,
++	.set_rate	= clk_default_setrate,
+ };
+ 
+ struct clk clk_upll = {
+@@ -239,6 +255,7 @@ struct clk clk_f = {
+ 	.rate		= 0,
+ 	.parent		= &clk_mpll,
+ 	.ctrlbit	= 0,
++	.set_rate	= clk_default_setrate,
+ };
+ 
+ struct clk clk_h = {
+@@ -247,6 +264,7 @@ struct clk clk_h = {
+ 	.rate		= 0,
+ 	.parent		= NULL,
+ 	.ctrlbit	= 0,
++	.set_rate	= clk_default_setrate,
+ };
+ 
+ struct clk clk_p = {
+@@ -255,6 +273,7 @@ struct clk clk_p = {
+ 	.rate		= 0,
+ 	.parent		= NULL,
+ 	.ctrlbit	= 0,
++	.set_rate	= clk_default_setrate,
+ };
+ 
+ struct clk clk_usb_bus = {
+diff --git a/arch/arm/plat-s3c24xx/dma.c b/arch/arm/plat-s3c24xx/dma.c
+index 29696e4..ac9ff16 100644
+--- a/arch/arm/plat-s3c24xx/dma.c
++++ b/arch/arm/plat-s3c24xx/dma.c
+@@ -525,7 +525,8 @@ int s3c2410_dma_enqueue(unsigned int channel, void *id,
+ 		}
+ 	} else if (chan->state == S3C2410_DMA_IDLE) {
+ 		if (chan->flags & S3C2410_DMAF_AUTOSTART) {
+-			s3c2410_dma_ctrl(chan->number, S3C2410_DMAOP_START);
++			s3c2410_dma_ctrl(chan->number | DMACH_LOW_LEVEL,
++					 S3C2410_DMAOP_START);
+ 		}
+ 	}
+ 
+@@ -787,7 +788,7 @@ int s3c2410_dma_request(unsigned int channel,
+ 
+ 	pr_debug("%s: channel initialised, %p\n", __FUNCTION__, chan);
+ 
+-	return 0;
++	return chan->number | DMACH_LOW_LEVEL;
+ }
+ 
+ EXPORT_SYMBOL(s3c2410_dma_request);
+@@ -1173,6 +1174,7 @@ int s3c2410_dma_devconfig(int channel,
+ 
+ 	chan->source = source;
+ 	chan->dev_addr = devaddr;
++	chan->hw_cfg = hwcfg;
+ 
+ 	switch (source) {
+ 	case S3C2410_DMASRC_HW:
+@@ -1184,7 +1186,7 @@ int s3c2410_dma_devconfig(int channel,
+ 		dma_wrreg(chan, S3C2410_DMA_DIDSTC, (0<<1) | (0<<0));
+ 
+ 		chan->addr_reg = dma_regaddr(chan, S3C2410_DMA_DIDST);
+-		return 0;
++		break;
+ 
+ 	case S3C2410_DMASRC_MEM:
+ 		/* source is memory */
+@@ -1195,11 +1197,19 @@ int s3c2410_dma_devconfig(int channel,
+ 		dma_wrreg(chan, S3C2410_DMA_DIDSTC, hwcfg & 3);
+ 
+ 		chan->addr_reg = dma_regaddr(chan, S3C2410_DMA_DISRC);
+-		return 0;
++		break;
++
++	default:
++		printk(KERN_ERR "dma%d: invalid source type (%d)\n",
++		       channel, source);
++
++		return -EINVAL;
+ 	}
+ 
+-	printk(KERN_ERR "dma%d: invalid source type (%d)\n", channel, source);
+-	return -EINVAL;
++	if (dma_sel.direction != NULL)
++		(dma_sel.direction)(chan, chan->map, source);
++
++	return 0;
+ }
+ 
+ EXPORT_SYMBOL(s3c2410_dma_devconfig);
+@@ -1227,6 +1237,10 @@ int s3c2410_dma_getposition(dmach_t channel, dma_addr_t *src, dma_addr_t *dst)
+ 
+ EXPORT_SYMBOL(s3c2410_dma_getposition);
+ 
++static struct s3c2410_dma_chan *to_dma_chan(struct sys_device *dev)
++{
++	return container_of(dev, struct s3c2410_dma_chan, dev);
++}
+ 
+ /* system device class */
+ 
+@@ -1234,7 +1248,7 @@ EXPORT_SYMBOL(s3c2410_dma_getposition);
+ 
+ static int s3c2410_dma_suspend(struct sys_device *dev, pm_message_t state)
+ {
+-	struct s3c2410_dma_chan *cp = container_of(dev, struct s3c2410_dma_chan, dev);
++	struct s3c2410_dma_chan *cp = to_dma_chan(dev);
+ 
+ 	printk(KERN_DEBUG "suspending dma channel %d\n", cp->number);
+ 
+@@ -1256,6 +1270,24 @@ static int s3c2410_dma_suspend(struct sys_device *dev, pm_message_t state)
+ 
+ static int s3c2410_dma_resume(struct sys_device *dev)
+ {
++	struct s3c2410_dma_chan *cp = to_dma_chan(dev);
++	unsigned int no = cp->number | DMACH_LOW_LEVEL;
++
++	/* restore channel's hardware configuration */
++
++	if (!cp->in_use)
++		return 0;
++
++	printk(KERN_INFO "dma%d: restoring configuration\n", cp->number);
++
++	s3c2410_dma_config(no, cp->xfer_unit, cp->dcon);
++	s3c2410_dma_devconfig(no, cp->source, cp->hw_cfg, cp->dev_addr);
++
++	/* re-select the dma source for this channel */
++
++	if (cp->map != NULL)
++		dma_sel.select(cp, cp->map);
++
+ 	return 0;
+ }
+ 
+@@ -1265,7 +1297,7 @@ static int s3c2410_dma_resume(struct sys_device *dev)
+ #endif /* CONFIG_PM */
+ 
+ struct sysdev_class dma_sysclass = {
+-	set_kset_name("s3c24xx-dma"),
++	.name		= "s3c24xx-dma",
+ 	.suspend	= s3c2410_dma_suspend,
+ 	.resume		= s3c2410_dma_resume,
+ };
+@@ -1445,6 +1477,7 @@ static struct s3c2410_dma_chan *s3c2410_dma_map_channel(int channel)
+ 
+  found:
+ 	dmach = &s3c2410_chans[ch];
++	dmach->map = ch_map;
+ 	dma_chan_map[channel] = dmach;
+ 
+ 	/* select the channel */
+diff --git a/arch/arm/plat-s3c24xx/gpio.c b/arch/arm/plat-s3c24xx/gpio.c
+index ec3a09c..ee99dcc 100644
+--- a/arch/arm/plat-s3c24xx/gpio.c
++++ b/arch/arm/plat-s3c24xx/gpio.c
+@@ -122,6 +122,19 @@ void s3c2410_gpio_pullup(unsigned int pin, unsigned int to)
+ 
+ EXPORT_SYMBOL(s3c2410_gpio_pullup);
+ 
++int s3c2410_gpio_getpull(unsigned int pin)
++{
++	void __iomem *base = S3C24XX_GPIO_BASE(pin);
++	unsigned long offs = S3C2410_GPIO_OFFSET(pin);
++
++	if (pin < S3C2410_GPIO_BANKB)
++		return -EINVAL;
++
++	return (__raw_readl(base + 0x08) & (1L << offs)) ? 1 : 0;
++}
++
++EXPORT_SYMBOL(s3c2410_gpio_getpull);
++
+ void s3c2410_gpio_setpin(unsigned int pin, unsigned int to)
+ {
+ 	void __iomem *base = S3C24XX_GPIO_BASE(pin);
+@@ -186,3 +199,19 @@ int s3c2410_gpio_getirq(unsigned int pin)
+ }
+ 
+ EXPORT_SYMBOL(s3c2410_gpio_getirq);
++
++int s3c2410_gpio_irq2pin(unsigned int irq)
++{
++	if (irq >= IRQ_EINT0 && irq <= IRQ_EINT3)
++		return S3C2410_GPF0 + (irq - IRQ_EINT0);
++
++	if (irq >= IRQ_EINT4 && irq <= IRQ_EINT7)
++		return S3C2410_GPF4 + (irq - IRQ_EINT4);
++
++	if (irq >= IRQ_EINT8 && irq <= IRQ_EINT23)
++		return S3C2410_GPG0 + (irq - IRQ_EINT8);
++
++	return -EINVAL;
++}
++
++EXPORT_SYMBOL(s3c2410_gpio_irq2pin);
+diff --git a/arch/arm/plat-s3c24xx/irq.c b/arch/arm/plat-s3c24xx/irq.c
+index 8fbc884..d486f51 100644
+--- a/arch/arm/plat-s3c24xx/irq.c
++++ b/arch/arm/plat-s3c24xx/irq.c
+@@ -187,7 +187,7 @@ struct irq_chip s3c_irq_level_chip = {
+ 	.set_wake	= s3c_irq_wake
+ };
+ 
+-static struct irq_chip s3c_irq_chip = {
++struct irq_chip s3c_irq_chip = {
+ 	.name		= "s3c",
+ 	.ack		= s3c_irq_ack,
+ 	.mask		= s3c_irq_mask,
+diff --git a/arch/arm/plat-s3c24xx/pm.c b/arch/arm/plat-s3c24xx/pm.c
+index 4fdb311..bf5581a 100644
+--- a/arch/arm/plat-s3c24xx/pm.c
++++ b/arch/arm/plat-s3c24xx/pm.c
+@@ -83,38 +83,39 @@ static struct sleep_save core_save[] = {
+ 	SAVE_ITEM(S3C2410_REFRESH),
+ };
+ 
+-static struct sleep_save gpio_save[] = {
+-	SAVE_ITEM(S3C2410_GPACON),
+-	SAVE_ITEM(S3C2410_GPADAT),
+-
+-	SAVE_ITEM(S3C2410_GPBCON),
+-	SAVE_ITEM(S3C2410_GPBDAT),
+-	SAVE_ITEM(S3C2410_GPBUP),
+-
+-	SAVE_ITEM(S3C2410_GPCCON),
+-	SAVE_ITEM(S3C2410_GPCDAT),
+-	SAVE_ITEM(S3C2410_GPCUP),
+-
+-	SAVE_ITEM(S3C2410_GPDCON),
+-	SAVE_ITEM(S3C2410_GPDDAT),
+-	SAVE_ITEM(S3C2410_GPDUP),
+-
+-	SAVE_ITEM(S3C2410_GPECON),
+-	SAVE_ITEM(S3C2410_GPEDAT),
+-	SAVE_ITEM(S3C2410_GPEUP),
+-
+-	SAVE_ITEM(S3C2410_GPFCON),
+-	SAVE_ITEM(S3C2410_GPFDAT),
+-	SAVE_ITEM(S3C2410_GPFUP),
+-
+-	SAVE_ITEM(S3C2410_GPGCON),
+-	SAVE_ITEM(S3C2410_GPGDAT),
+-	SAVE_ITEM(S3C2410_GPGUP),
+-
+-	SAVE_ITEM(S3C2410_GPHCON),
+-	SAVE_ITEM(S3C2410_GPHDAT),
+-	SAVE_ITEM(S3C2410_GPHUP),
++static struct gpio_sleep {
++	void __iomem	*base;
++	unsigned int	 gpcon;
++	unsigned int	 gpdat;
++	unsigned int	 gpup;
++} gpio_save[] = {
++	[0] = {
++		.base	= S3C2410_GPACON,
++	},
++	[1] = {
++		.base	= S3C2410_GPBCON,
++	},
++	[2] = {
++		.base	= S3C2410_GPCCON,
++	},
++	[3] = {
++		.base	= S3C2410_GPDCON,
++	},
++	[4] = {
++		.base	= S3C2410_GPECON,
++	},
++	[5] = {
++		.base	= S3C2410_GPFCON,
++	},
++	[6] = {
++		.base	= S3C2410_GPGCON,
++	},
++	[7] = {
++		.base	= S3C2410_GPHCON,
++	},
++};
+ 
++static struct sleep_save misc_save[] = {
+ 	SAVE_ITEM(S3C2410_DCLKCON),
+ };
+ 
+@@ -486,6 +487,184 @@ static void s3c2410_pm_configure_extint(void)
+ 	}
+ }
+ 
++/* offsets for CON/DAT/UP registers */
++
++#define OFFS_CON	(S3C2410_GPACON - S3C2410_GPACON)
++#define OFFS_DAT	(S3C2410_GPADAT - S3C2410_GPACON)
++#define OFFS_UP		(S3C2410_GPBUP  - S3C2410_GPBCON)
++
++/* s3c2410_pm_save_gpios()
++ *
++ * Save the state of the GPIOs
++ */
++
++static void s3c2410_pm_save_gpios(void)
++{
++	struct gpio_sleep *gps = gpio_save;
++	unsigned int gpio;
++
++	for (gpio = 0; gpio < ARRAY_SIZE(gpio_save); gpio++, gps++) {
++		void __iomem *base = gps->base;
++
++		gps->gpcon = __raw_readl(base + OFFS_CON);
++		gps->gpdat = __raw_readl(base + OFFS_DAT);
++
++		if (gpio > 0)
++			gps->gpup = __raw_readl(base + OFFS_UP);
++
++	}
++}
++
++/* Test whether the given masked+shifted bits of an GPIO configuration
++ * are one of the SFN (special function) modes. */
++
++static inline int is_sfn(unsigned long con)
++{
++	return (con == 2 || con == 3);
++}
++
++/* Test if the given masked+shifted GPIO configuration is an input */
++
++static inline int is_in(unsigned long con)
++{
++	return con == 0;
++}
++
++/* Test if the given masked+shifted GPIO configuration is an output */
++
++static inline int is_out(unsigned long con)
++{
++	return con == 1;
++}
++
++/* s3c2410_pm_restore_gpio()
++ *
++ * Restore one of the GPIO banks that was saved during suspend. This is
++ * not as simple as once thought, due to the possibility of glitches
++ * from the order that the CON and DAT registers are set in.
++ *
++ * The three states the pin can be are {IN,OUT,SFN} which gives us 9
++ * combinations of changes to check. Three of these, if the pin stays
++ * in the same configuration can be discounted. This leaves us with
++ * the following:
++ *
++ * { IN => OUT }  Change DAT first
++ * { IN => SFN }  Change CON first
++ * { OUT => SFN } Change CON first, so new data will not glitch
++ * { OUT => IN }  Change CON first, so new data will not glitch
++ * { SFN => IN }  Change CON first
++ * { SFN => OUT } Change DAT first, so new data will not glitch [1]
++ *
++ * We do not currently deal with the UP registers as these control
++ * weak resistors, so a small delay in change should not need to bring
++ * these into the calculations.
++ *
++ * [1] this assumes that writing to a pin DAT whilst in SFN will set the
++ *     state for when it is next output.
++ */
++
++static void s3c2410_pm_restore_gpio(int index, struct gpio_sleep *gps)
++{
++	void __iomem *base = gps->base;
++	unsigned long gps_gpcon = gps->gpcon;
++	unsigned long gps_gpdat = gps->gpdat;
++	unsigned long old_gpcon;
++	unsigned long old_gpdat;
++	unsigned long old_gpup = 0x0;
++	unsigned long gpcon;
++	int nr;
++
++	old_gpcon = __raw_readl(base + OFFS_CON);
++	old_gpdat = __raw_readl(base + OFFS_DAT);
++
++	if (base == S3C2410_GPACON) {
++		/* GPACON only has one bit per control / data and no PULLUPs.
++		 * GPACON[x] = 0 => Output, 1 => SFN */
++
++		/* first set all SFN bits to SFN */
++
++		gpcon = old_gpcon | gps->gpcon;
++		__raw_writel(gpcon, base + OFFS_CON);
++
++		/* now set all the other bits */
++
++		__raw_writel(gps_gpdat, base + OFFS_DAT);
++		__raw_writel(gps_gpcon, base + OFFS_CON);
++	} else {
++		unsigned long old, new, mask;
++		unsigned long change_mask = 0x0;
++
++		old_gpup = __raw_readl(base + OFFS_UP);
++
++		/* Create a change_mask of all the items that need to have
++		 * their CON value changed before their DAT value, so that
++		 * we minimise the work between the two settings.
++		 */
++
++		for (nr = 0, mask = 0x03; nr < 32; nr += 2, mask <<= 2) {
++			old = (old_gpcon & mask) >> nr;
++			new = (gps_gpcon & mask) >> nr;
++
++			/* If there is no change, then skip */
++
++			if (old == new)
++				continue;
++
++			/* If both are special function, then skip */
++
++			if (is_sfn(old) && is_sfn(new))
++				continue;
++
++			/* Change is IN => OUT, do not change now */
++
++			if (is_in(old) && is_out(new))
++				continue;
++
++			/* Change is SFN => OUT, do not change now */
++
++			if (is_sfn(old) && is_out(new))
++				continue;
++
++			/* We should now be at the case of IN=>SFN,
++			 * OUT=>SFN, OUT=>IN, SFN=>IN. */
++
++			change_mask |= mask;
++		}
++
++		/* Write the new CON settings */
++
++		gpcon = old_gpcon & ~change_mask;
++		gpcon |= gps_gpcon & change_mask;
++
++		__raw_writel(gpcon, base + OFFS_CON);
++
++		/* Now change any items that require DAT,CON */
++
++		__raw_writel(gps_gpdat, base + OFFS_DAT);
++		__raw_writel(gps_gpcon, base + OFFS_CON);
++		__raw_writel(gps->gpup, base + OFFS_UP);
++	}
++
++	DBG("GPIO[%d] CON %08lx => %08lx, DAT %08lx => %08lx\n",
++	    index, old_gpcon, gps_gpcon, old_gpdat, gps_gpdat);
++}
++
++
++/** s3c2410_pm_restore_gpios()
++ *
++ * Restore the state of the GPIOs
++ */
++
++static void s3c2410_pm_restore_gpios(void)
++{
++	struct gpio_sleep *gps = gpio_save;
++	int gpio;
++
++	for (gpio = 0; gpio < ARRAY_SIZE(gpio_save); gpio++, gps++) {
++		s3c2410_pm_restore_gpio(gpio, gps);
++	}
++}
++
+ void (*pm_cpu_prep)(void);
+ void (*pm_cpu_sleep)(void);
+ 
+@@ -535,7 +714,8 @@ static int s3c2410_pm_enter(suspend_state_t state)
+ 
+ 	/* save all necessary core registers not covered by the drivers */
+ 
+-	s3c2410_pm_do_save(gpio_save, ARRAY_SIZE(gpio_save));
++	s3c2410_pm_save_gpios();
++	s3c2410_pm_do_save(misc_save, ARRAY_SIZE(misc_save));
+ 	s3c2410_pm_do_save(core_save, ARRAY_SIZE(core_save));
+ 	s3c2410_pm_do_save(uart_save, ARRAY_SIZE(uart_save));
+ 
+@@ -585,8 +765,9 @@ static int s3c2410_pm_enter(suspend_state_t state)
+ 	/* restore the system state */
+ 
+ 	s3c2410_pm_do_restore_core(core_save, ARRAY_SIZE(core_save));
+-	s3c2410_pm_do_restore(gpio_save, ARRAY_SIZE(gpio_save));
++	s3c2410_pm_do_restore(misc_save, ARRAY_SIZE(misc_save));
+ 	s3c2410_pm_do_restore(uart_save, ARRAY_SIZE(uart_save));
++	s3c2410_pm_restore_gpios();
+ 
+ 	s3c2410_pm_debug_init();
+ 
+diff --git a/arch/arm/plat-s3c24xx/s3c244x-clock.c b/arch/arm/plat-s3c24xx/s3c244x-clock.c
+new file mode 100644
+index 0000000..faf3e0f
+--- /dev/null
++++ b/arch/arm/plat-s3c24xx/s3c244x-clock.c
+@@ -0,0 +1,137 @@
++/* linux/arch/arm/plat-s3c24xx/s3c24xx-clock.c
++ *
++ * Copyright (c) 2004-2005,2008 Simtec Electronics
++ *	http://armlinux.simtec.co.uk/
++ *	Ben Dooks <ben at simtec.co.uk>
++ *
++ * S3C2440/S3C2442 Common clock support
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You 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/module.h>
++#include <linux/kernel.h>
++#include <linux/list.h>
++#include <linux/errno.h>
++#include <linux/err.h>
++#include <linux/device.h>
++#include <linux/sysdev.h>
++#include <linux/interrupt.h>
++#include <linux/ioport.h>
++#include <linux/mutex.h>
++#include <linux/clk.h>
++
++#include <asm/hardware.h>
++#include <asm/atomic.h>
++#include <asm/irq.h>
++#include <asm/io.h>
++
++#include <asm/arch/regs-clock.h>
++
++#include <asm/plat-s3c24xx/clock.h>
++#include <asm/plat-s3c24xx/cpu.h>
++
++static int s3c2440_setparent_armclk(struct clk *clk, struct clk *parent)
++{
++	unsigned long camdivn;
++	unsigned long dvs;
++
++	if (parent == &clk_f)
++		dvs = 0;
++	else if (parent == &clk_h)
++		dvs = S3C2440_CAMDIVN_DVSEN;
++	else
++		return -EINVAL;
++
++	clk->parent = parent;
++
++	camdivn  = __raw_readl(S3C2440_CAMDIVN);
++	camdivn &= ~S3C2440_CAMDIVN_DVSEN;
++	camdivn |= dvs;
++	__raw_writel(camdivn, S3C2440_CAMDIVN);
++
++	return 0;
++}
++
++static struct clk clk_arm = {
++	.name		= "armclk",
++	.id		= -1,
++	.set_parent	= s3c2440_setparent_armclk,
++};
++
++static int s3c244x_clk_add(struct sys_device *sysdev)
++{
++	unsigned long camdivn = __raw_readl(S3C2440_CAMDIVN);
++	unsigned long clkdivn;
++	struct clk *clock_upll;
++	int ret;
++
++	printk("S3C244X: Clock Support, DVS %s\n",
++	       (camdivn & S3C2440_CAMDIVN_DVSEN) ? "on" : "off");
++
++	clk_arm.parent = (camdivn & S3C2440_CAMDIVN_DVSEN) ? &clk_h : &clk_f;
++
++	ret = s3c24xx_register_clock(&clk_arm);
++	if (ret < 0) {
++		printk(KERN_ERR "S3C24XX: Failed to add armclk (%d)\n", ret);
++		return ret;
++	}
++
++	clock_upll = clk_get(NULL, "upll");
++	if (IS_ERR(clock_upll)) {
++		printk(KERN_ERR "S3C244X: Failed to get upll clock\n");
++		return -ENOENT;
++	}
++
++	/* check rate of UPLL, and if it is near 96MHz, then change
++	 * to using half the UPLL rate for the system */
++
++	if (clk_get_rate(clock_upll) > (94 * MHZ)) {
++		clk_usb_bus.rate = clk_get_rate(clock_upll) / 2;
++
++		mutex_lock(&clocks_mutex);
++
++		clkdivn = __raw_readl(S3C2410_CLKDIVN);
++		clkdivn |= S3C2440_CLKDIVN_UCLK;
++		__raw_writel(clkdivn, S3C2410_CLKDIVN);
++
++		mutex_unlock(&clocks_mutex);
++	}
++
++	return 0;
++}
++
++static struct sysdev_driver s3c2440_clk_driver = {
++	.add		= s3c244x_clk_add,
++};
++
++static int s3c2440_clk_init(void)
++{
++	return sysdev_driver_register(&s3c2440_sysclass, &s3c2440_clk_driver);
++}
++
++arch_initcall(s3c2440_clk_init);
++
++static struct sysdev_driver s3c2442_clk_driver = {
++	.add		= s3c244x_clk_add,
++};
++
++static int s3c2442_clk_init(void)
++{
++	return sysdev_driver_register(&s3c2442_sysclass, &s3c2442_clk_driver);
++}
++
++arch_initcall(s3c2442_clk_init);
+diff --git a/arch/arm/plat-s3c24xx/s3c244x.c b/arch/arm/plat-s3c24xx/s3c244x.c
+index 3444b13..f197bb3 100644
+--- a/arch/arm/plat-s3c24xx/s3c244x.c
++++ b/arch/arm/plat-s3c24xx/s3c244x.c
+@@ -151,13 +151,13 @@ static int s3c244x_resume(struct sys_device *dev)
+ /* Since the S3C2442 and S3C2440 share  items, put both sysclasses here */
+ 
+ struct sysdev_class s3c2440_sysclass = {
+-	set_kset_name("s3c2440-core"),
++	.name		= "s3c2440-core",
+ 	.suspend	= s3c244x_suspend,
+ 	.resume		= s3c244x_resume
+ };
+ 
+ struct sysdev_class s3c2442_sysclass = {
+-	set_kset_name("s3c2442-core"),
++	.name		= "s3c2442-core",
+ 	.suspend	= s3c244x_suspend,
+ 	.resume		= s3c244x_resume
+ };
+diff --git a/arch/arm/tools/mach-types b/arch/arm/tools/mach-types
+index 0a9a5e7..7ed58c0 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: Fri May 11 19:53:41 2007
++# Last update: Sat Jan 26 14:45:34 2008
+ #
+ # machine_is_xxx	CONFIG_xxxx		MACH_TYPE_xxx		number
+ #
+@@ -266,7 +266,7 @@ stork_egg		ARCH_STORK_EGG		STORK_EGG		248
+ wismo			SA1100_WISMO		WISMO			249
+ ezlinx			ARCH_EZLINX		EZLINX			250
+ at91rm9200		ARCH_AT91RM9200		AT91RM9200		251
+-orion			ARCH_ORION		ORION			252
++adtech_orion		ARCH_ADTECH_ORION	ADTECH_ORION		252
+ neptune			ARCH_NEPTUNE		NEPTUNE			253
+ hackkit			SA1100_HACKKIT		HACKKIT			254
+ pxa_wins30		ARCH_PXA_WINS30		PXA_WINS30		255
+@@ -661,7 +661,6 @@ a9200ec			MACH_A9200EC		A9200EC			645
+ pnx0105			MACH_PNX0105		PNX0105			646
+ adcpoecpu		MACH_ADCPOECPU		ADCPOECPU		647
+ csb637			MACH_CSB637		CSB637			648
+-ml69q6203		MACH_ML69Q6203		ML69Q6203		649
+ mb9200			MACH_MB9200		MB9200			650
+ kulun			MACH_KULUN		KULUN			651
+ snapper			MACH_SNAPPER		SNAPPER			652
+@@ -953,7 +952,6 @@ fred_jack		MACH_FRED_JACK		FRED_JACK		939
+ ttg_color1		MACH_TTG_COLOR1		TTG_COLOR1		940
+ nxeb500hmi		MACH_NXEB500HMI		NXEB500HMI		941
+ netdcu8			MACH_NETDCU8		NETDCU8			942
+-ml675050_cpu_boa	MACH_ML675050_CPU_BOA	ML675050_CPU_BOA	943
+ ng_fvx538		MACH_NG_FVX538		NG_FVX538		944
+ ng_fvs338		MACH_NG_FVS338		NG_FVS338		945
+ pnx4103			MACH_PNX4103		PNX4103			946
+@@ -1148,7 +1146,7 @@ aidx270			MACH_AIDX270		AIDX270			1134
+ rema			MACH_REMA		REMA			1135
+ bps1000			MACH_BPS1000		BPS1000			1136
+ hw90350			MACH_HW90350		HW90350			1137
+-omap_sdp3430		MACH_OMAP_SDP3430	OMAP_SDP3430		1138
++omap_3430sdp		MACH_OMAP_3430SDP	OMAP_3430SDP		1138
+ bluetouch		MACH_BLUETOUCH		BLUETOUCH		1139
+ vstms			MACH_VSTMS		VSTMS			1140
+ xsbase270		MACH_XSBASE270		XSBASE270		1141
+@@ -1214,7 +1212,7 @@ osstbox			MACH_OSSTBOX		OSSTBOX			1203
+ kbat9261		MACH_KBAT9261		KBAT9261		1204
+ ct1100			MACH_CT1100		CT1100			1205
+ akcppxa			MACH_AKCPPXA		AKCPPXA			1206
+-zevio_1020		MACH_ZEVIO_1020		ZEVIO_1020		1207
++ochaya1020		MACH_OCHAYA1020		OCHAYA1020		1207
+ hitrack			MACH_HITRACK		HITRACK			1208
+ syme1			MACH_SYME1		SYME1			1209
+ syhl1			MACH_SYHL1		SYHL1			1210
+@@ -1299,7 +1297,7 @@ xp179			MACH_XP179		XP179			1290
+ h4300			MACH_H4300		H4300			1291
+ goramo_mlr		MACH_GORAMO_MLR		GORAMO_MLR		1292
+ mxc30020evb		MACH_MXC30020EVB	MXC30020EVB		1293
+-adsbitsymx		MACH_ADSBITSIMX		ADSBITSIMX		1294
++adsbitsyg5		MACH_ADSBITSYG5		ADSBITSYG5		1294
+ adsportalplus		MACH_ADSPORTALPLUS	ADSPORTALPLUS		1295
+ mmsp2plus		MACH_MMSP2PLUS		MMSP2PLUS		1296
+ em_x270			MACH_EM_X270		EM_X270			1297
+@@ -1367,3 +1365,249 @@ db88f5281		MACH_DB88F5281		DB88F5281		1358
+ csb726			MACH_CSB726		CSB726			1359
+ tik27			MACH_TIK27		TIK27			1360
+ mx_uc7420		MACH_MX_UC7420		MX_UC7420		1361
++rirm3			MACH_RIRM3		RIRM3			1362
++pelco_odyssey		MACH_PELCO_ODYSSEY	PELCO_ODYSSEY		1363
++adx_abox		MACH_ADX_ABOX		ADX_ABOX		1365
++adx_tpid		MACH_ADX_TPID		ADX_TPID		1366
++minicheck		MACH_MINICHECK		MINICHECK		1367
++idam			MACH_IDAM		IDAM			1368
++mario_mx		MACH_MARIO_MX		MARIO_MX		1369
++vi1888			MACH_VI1888		VI1888			1370
++zr4230			MACH_ZR4230		ZR4230			1371
++t1_ix_blue		MACH_T1_IX_BLUE		T1_IX_BLUE		1372
++syhq2			MACH_SYHQ2		SYHQ2			1373
++computime_r3		MACH_COMPUTIME_R3	COMPUTIME_R3		1374
++oratis			MACH_ORATIS		ORATIS			1375
++mikko			MACH_MIKKO		MIKKO			1376
++holon			MACH_HOLON		HOLON			1377
++olip8			MACH_OLIP8		OLIP8			1378
++ghi270hg		MACH_GHI270HG		GHI270HG		1379
++davinci_dm6467_evm	MACH_DAVINCI_DM6467_EVM	DAVINCI_DM6467_EVM	1380
++davinci_dm355_evm	MACH_DAVINCI_DM350_EVM	DAVINCI_DM350_EVM	1381
++blackriver		MACH_BLACKRIVER		BLACKRIVER		1383
++sandgate_wp		MACH_SANDGATEWP		SANDGATEWP		1384
++cdotbwsg		MACH_CDOTBWSG		CDOTBWSG		1385
++quark963		MACH_QUARK963		QUARK963		1386
++csb735			MACH_CSB735		CSB735			1387
++littleton		MACH_LITTLETON		LITTLETON		1388
++mio_p550		MACH_MIO_P550		MIO_P550		1389
++motion2440		MACH_MOTION2440		MOTION2440		1390
++imm500			MACH_IMM500		IMM500			1391
++homematic		MACH_HOMEMATIC		HOMEMATIC		1392
++ermine			MACH_ERMINE		ERMINE			1393
++kb9202b			MACH_KB9202B		KB9202B			1394
++hs1xx			MACH_HS1XX		HS1XX			1395
++studentmate2440		MACH_STUDENTMATE2440	STUDENTMATE2440		1396
++arvoo_l1_z1		MACH_ARVOO_L1_Z1	ARVOO_L1_Z1		1397
++dep2410k		MACH_DEP2410K		DEP2410K		1398
++xxsvideo		MACH_XXSVIDEO		XXSVIDEO		1399
++im4004			MACH_IM4004		IM4004			1400
++ochaya1050		MACH_OCHAYA1050		OCHAYA1050		1401
++lep9261			MACH_LEP9261		LEP9261			1402
++svenmeb			MACH_SVENMEB		SVENMEB			1403
++fortunet2ne		MACH_FORTUNET2NE	FORTUNET2NE		1404
++nxhx			MACH_NXHX		NXHX			1406
++realview_pb11mp		MACH_REALVIEW_PB11MP	REALVIEW_PB11MP		1407
++ids500			MACH_IDS500		IDS500			1408
++ors_n725		MACH_ORS_N725		ORS_N725		1409
++hsdarm			MACH_HSDARM		HSDARM			1410
++sha_pon003		MACH_SHA_PON003		SHA_PON003		1411
++sha_pon004		MACH_SHA_PON004		SHA_PON004		1412
++sha_pon007		MACH_SHA_PON007		SHA_PON007		1413
++sha_pon011		MACH_SHA_PON011		SHA_PON011		1414
++h6042			MACH_H6042		H6042			1415
++h6043			MACH_H6043		H6043			1416
++looxc550		MACH_LOOXC550		LOOXC550		1417
++cnty_titan		MACH_CNTY_TITAN		CNTY_TITAN		1418
++app3xx			MACH_APP3XX		APP3XX			1419
++sideoatsgrama		MACH_SIDEOATSGRAMA	SIDEOATSGRAMA		1420
++xscale_palmt700p	MACH_XSCALE_PALMT700P	XSCALE_PALMT700P	1421
++xscale_palmt700w	MACH_XSCALE_PALMT700W	XSCALE_PALMT700W	1422
++xscale_palmt750		MACH_XSCALE_PALMT750	XSCALE_PALMT750		1423
++xscale_palmt755p	MACH_XSCALE_PALMT755P	XSCALE_PALMT755P	1424
++ezreganut9200		MACH_EZREGANUT9200	EZREGANUT9200		1425
++sarge			MACH_SARGE		SARGE			1426
++a696			MACH_A696		A696			1427
++turtle1916		MACH_TURTLE		TURTLE			1428
++mx27_3ds		MACH_MX27_3DS		MX27_3DS		1430
++bishop			MACH_BISHOP		BISHOP			1431
++pxx			MACH_PXX		PXX			1432
++redwood			MACH_REDWOOD		REDWOOD			1433
++omap_2430dlp		MACH_OMAP_2430DLP	OMAP_2430DLP		1436
++omap_2430osk		MACH_OMAP_2430OSK	OMAP_2430OSK		1437
++sardine			MACH_SARDINE		SARDINE			1438
++halibut			MACH_HALIBUT		HALIBUT			1439
++trout			MACH_TROUT		TROUT			1440
++goldfish		MACH_GOLDFISH		GOLDFISH		1441
++gesbc2440		MACH_GESBC2440		GESBC2440		1442
++nomad			MACH_NOMAD		NOMAD			1443
++rosalind		MACH_ROSALIND		ROSALIND		1444
++cc9p9215		MACH_CC9P9215		CC9P9215		1445
++cc9p9210		MACH_CC9P9210		CC9P9210		1446
++cc9p9215js		MACH_CC9P9215JS		CC9P9215JS		1447
++cc9p9210js		MACH_CC9P9210JS		CC9P9210JS		1448
++nasffe			MACH_NASFFE		NASFFE			1449
++tn2x0bd			MACH_TN2X0BD		TN2X0BD			1450
++gwmpxa			MACH_GWMPXA		GWMPXA			1451
++exyplus			MACH_EXYPLUS		EXYPLUS			1452
++jadoo21			MACH_JADOO21		JADOO21			1453
++looxn560		MACH_LOOXN560		LOOXN560		1454
++bonsai			MACH_BONSAI		BONSAI			1455
++adsmilgato		MACH_ADSMILGATO		ADSMILGATO		1456
++gba			MACH_GBA		GBA			1457
++h6044			MACH_H6044		H6044			1458
++app			MACH_APP		APP			1459
++tct_hammer		MACH_TCT_HAMMER		TCT_HAMMER		1460
++herald			MACH_HERMES		HERMES			1461
++artemis			MACH_ARTEMIS		ARTEMIS			1462
++htctitan		MACH_HTCTITAN		HTCTITAN		1463
++qranium			MACH_QRANIUM		QRANIUM			1464
++adx_wsc2		MACH_ADX_WSC2		ADX_WSC2		1465
++adx_medinet		MACH_ADX_MEDINET	ADX_MEDINET		1466
++bboard			MACH_BBOARD		BBOARD			1467
++cambria			MACH_CAMBRIA		CAMBRIA			1468
++mt7xxx			MACH_MT7XXX		MT7XXX			1469
++matrix512		MACH_MATRIX512		MATRIX512		1470
++matrix522		MACH_MATRIX522		MATRIX522		1471
++ipac5010		MACH_IPAC5010		IPAC5010		1472
++sakura			MACH_SAKURA		SAKURA			1473
++grocx			MACH_GROCX		GROCX			1474
++pm9263			MACH_PM9263		PM9263			1475
++sim_one			MACH_SIM_ONE		SIM_ONE			1476
++acq132			MACH_ACQ132		ACQ132			1477
++datr			MACH_DATR		DATR			1478
++actux1			MACH_ACTUX1		ACTUX1			1479
++actux2			MACH_ACTUX2		ACTUX2			1480
++actux3			MACH_ACTUX3		ACTUX3			1481
++flexit			MACH_FLEXIT		FLEXIT			1482
++bh2x0bd			MACH_BH2X0BD		BH2X0BD			1483
++atb2002			MACH_ATB2002		ATB2002			1484
++xenon			MACH_XENON		XENON			1485
++fm607			MACH_FM607		FM607			1486
++matrix514		MACH_MATRIX514		MATRIX514		1487
++matrix524		MACH_MATRIX524		MATRIX524		1488
++inpod			MACH_INPOD		INPOD			1489
++jive			MACH_JIVE		JIVE			1490
++tll_mx21		MACH_TLL_MX21		TLL_MX21		1491
++sbc2800			MACH_SBC2800		SBC2800			1492
++cc7ucamry		MACH_CC7UCAMRY		CC7UCAMRY		1493
++ubisys_p9_sc15		MACH_UBISYS_P9_SC15	UBISYS_P9_SC15		1494
++ubisys_p9_ssc2d10	MACH_UBISYS_P9_SSC2D10	UBISYS_P9_SSC2D10	1495
++ubisys_p9_rcu3		MACH_UBISYS_P9_RCU3	UBISYS_P9_RCU3		1496
++aml_m8000		MACH_AML_M8000		AML_M8000		1497
++snapper_270		MACH_SNAPPER_270	SNAPPER_270		1498
++omap_bbx		MACH_OMAP_BBX		OMAP_BBX		1499
++ucn2410			MACH_UCN2410		UCN2410			1500
++sam9_l9260		MACH_SAM9_L9260		SAM9_L9260		1501
++eti_c2			MACH_ETI_C2		ETI_C2			1502
++avalanche		MACH_AVALANCHE		AVALANCHE		1503
++realview_pb1176		MACH_REALVIEW_PB1176	REALVIEW_PB1176		1504
++dp1500			MACH_DP1500		DP1500			1505
++apple_iphone		MACH_APPLE_IPHONE	APPLE_IPHONE		1506
++yl9200			MACH_YL9200		YL9200			1507
++rd88f5182		MACH_RD88F5182		RD88F5182		1508
++kurobox_pro		MACH_KUROBOX_PRO	KUROBOX_PRO		1509
++se_poet			MACH_SE_POET		SE_POET			1510
++mx31_3ds		MACH_MX31_3DS		MX31_3DS		1511
++r270			MACH_R270		R270			1512
++armour21		MACH_ARMOUR21		ARMOUR21		1513
++dt2			MACH_DT2		DT2			1514
++vt4			MACH_VT4		VT4			1515
++tyco320			MACH_TYCO320		TYCO320			1516
++adma			MACH_ADMA		ADMA			1517
++wp188			MACH_WP188		WP188			1518
++corsica			MACH_CORSICA		CORSICA			1519
++bigeye			MACH_BIGEYE		BIGEYE			1520
++tll5000			MACH_TLL5000		TLL5000			1522
++hni270			MACH_HNI_X270		HNI_X270		1523
++qong			MACH_QONG		QONG			1524
++tcompact		MACH_TCOMPACT		TCOMPACT		1525
++puma5			MACH_PUMA5		PUMA5			1526
++elara			MACH_ELARA		ELARA			1527
++ellington		MACH_ELLINGTON		ELLINGTON		1528
++xda_atom		MACH_XDA_ATOM		XDA_ATOM		1529
++energizer2		MACH_ENERGIZER2		ENERGIZER2		1530
++odin			MACH_ODIN		ODIN			1531
++actux4			MACH_ACTUX4		ACTUX4			1532
++esl_omap		MACH_ESL_OMAP		ESL_OMAP		1533
++omap2evm		MACH_OMAP2EVM		OMAP2EVM		1534
++omap3evm		MACH_OMAP3EVM		OMAP3EVM		1535
++adx_pcu57		MACH_ADX_PCU57		ADX_PCU57		1536
++monaco			MACH_MONACO		MONACO			1537
++levante			MACH_LEVANTE		LEVANTE			1538
++tmxipx425		MACH_TMXIPX425		TMXIPX425		1539
++leep			MACH_LEEP		LEEP			1540
++raad			MACH_RAAD		RAAD			1541
++dns323			MACH_DNS323		DNS323			1542
++ap1000			MACH_AP1000		AP1000			1543
++a9sam6432		MACH_A9SAM6432		A9SAM6432		1544
++shiny			MACH_SHINY		SHINY			1545
++omap3_beagle		MACH_OMAP3_BEAGLE	OMAP3_BEAGLE		1546
++csr_bdb2		MACH_CSR_BDB2		CSR_BDB2		1547
++nokia_n810		MACH_NOKIA_N810		NOKIA_N810		1548
++c270			MACH_C270		C270			1549
++sentry			MACH_SENTRY		SENTRY			1550
++pcm038			MACH_PCM038		PCM038			1551
++anc300			MACH_ANC300		ANC300			1552
++htckaiser		MACH_HTCKAISER		HTCKAISER		1553
++sbat100			MACH_SBAT100		SBAT100			1554
++modunorm		MACH_MODUNORM		MODUNORM		1555
++pelos_twarm		MACH_PELOS_TWARM	PELOS_TWARM		1556
++flank			MACH_FLANK		FLANK			1557
++sirloin			MACH_SIRLOIN		SIRLOIN			1558
++brisket			MACH_BRISKET		BRISKET			1559
++chuck			MACH_CHUCK		CHUCK			1560
++otter			MACH_OTTER		OTTER			1561
++davinci_ldk		MACH_DAVINCI_LDK	DAVINCI_LDK		1562
++phreedom		MACH_PHREEDOM		PHREEDOM		1563
++sg310			MACH_SG310		SG310			1564
++ts_x09			MACH_TS209		TS209			1565
++at91cap9adk		MACH_AT91CAP9ADK	AT91CAP9ADK		1566
++tion9315		MACH_TION9315		TION9315		1567
++mast			MACH_MAST		MAST			1568
++pfw			MACH_PFW		PFW			1569
++yl_p2440		MACH_YL_P2440		YL_P2440		1570
++zsbc32			MACH_ZSBC32		ZSBC32			1571
++omap_pace2		MACH_OMAP_PACE2		OMAP_PACE2		1572
++imx_pace2		MACH_IMX_PACE2		IMX_PACE2		1573
++mx31moboard		MACH_MX31MOBOARD	MX31MOBOARD		1574
++mx37_3ds		MACH_MX37_3DS		MX37_3DS		1575
++rcc			MACH_RCC		RCC			1576
++dmp			MACH_ARM9		ARM9			1577
++vision_ep9307		MACH_VISION_EP9307	VISION_EP9307		1578
++scly1000		MACH_SCLY1000		SCLY1000		1579
++fontel_ep		MACH_FONTEL_EP		FONTEL_EP		1580
++voiceblue3g		MACH_VOICEBLUE3G	VOICEBLUE3G		1581
++tt9200			MACH_TT9200		TT9200			1582
++digi2410		MACH_DIGI2410		DIGI2410		1583
++terastation_pro2	MACH_TERASTATION_PRO2	TERASTATION_PRO2	1584
++linkstation_pro		MACH_LINKSTATION_PRO	LINKSTATION_PRO		1585
++motorola_a780		MACH_MOTOROLA_A780	MOTOROLA_A780		1587
++motorola_e6		MACH_MOTOROLA_E6	MOTOROLA_E6		1588
++motorola_e2		MACH_MOTOROLA_E2	MOTOROLA_E2		1589
++motorola_e680		MACH_MOTOROLA_E680	MOTOROLA_E680		1590
++ur2410			MACH_UR2410		UR2410			1591
++tas9261			MACH_TAS9261		TAS9261			1592
++davinci_hermes_hd	MACH_HERMES_HD		HERMES_HD		1593
++davinci_perseo_hd	MACH_PERSEO_HD		PERSEO_HD		1594
++stargazer2		MACH_STARGAZER2		STARGAZER2		1595
++e350			MACH_E350		E350			1596
++wpcm450			MACH_WPCM450		WPCM450			1597
++cartesio		MACH_CARTESIO		CARTESIO		1598
++toybox			MACH_TOYBOX		TOYBOX			1599
++tx27			MACH_TX27		TX27			1600
++ts409			MACH_TS409		TS409			1601
++p300			MACH_P300		P300			1602
++xdacomet		MACH_XDACOMET		XDACOMET		1603
++dexflex2		MACH_DEXFLEX2		DEXFLEX2		1604
++ow			MACH_OW			OW			1605
++armebs3			MACH_ARMEBS3		ARMEBS3			1606
++u3			MACH_U3			U3			1607
++smdk2450		MACH_SMDK2450		SMDK2450		1608
++rsi_ews			MACH_RSI_EWS		RSI_EWS			1609
++tnb			MACH_TNB		TNB			1610
++toepath			MACH_TOEPATH		TOEPATH			1611
++kb9263			MACH_KB9263		KB9263			1612
++mt7108			MACH_MT7108		MT7108			1613
++smtr2440		MACH_SMTR2440		SMTR2440		1614
++manao			MACH_MANAO		MANAO			1615
+diff --git a/arch/arm/vfp/vfp.h b/arch/arm/vfp/vfp.h
+index 791d023..c85860b 100644
+--- a/arch/arm/vfp/vfp.h
++++ b/arch/arm/vfp/vfp.h
+@@ -265,7 +265,11 @@ struct vfp_double {
+  * which returns (double)0.0.  This is useful for the compare with
+  * zero instructions.
+  */
++#ifdef CONFIG_VFPv3
++#define VFP_REG_ZERO	32
++#else
+ #define VFP_REG_ZERO	16
++#endif
+ extern u64 vfp_get_double(unsigned int reg);
+ extern void vfp_put_double(u64 val, unsigned int reg);
+ 
+diff --git a/arch/arm/vfp/vfphw.S b/arch/arm/vfp/vfphw.S
+index 0ac022f..353f9e5 100644
+--- a/arch/arm/vfp/vfphw.S
++++ b/arch/arm/vfp/vfphw.S
+@@ -99,12 +99,12 @@ vfp_support_entry:
+ 	DBGSTR1	"save old state %p", r4
+ 	cmp	r4, #0
+ 	beq	no_old_VFP_process
++	VFPFSTMIA r4, r5		@ save the working registers
+ 	VFPFMRX	r5, FPSCR		@ current status
+-	VFPFMRX	r6, FPINST		@ FPINST (always there, rev0 onwards)
+-	tst	r1, #FPEXC_FPV2		@ is there an FPINST2 to read?
+-	VFPFMRX	r8, FPINST2, NE		@ FPINST2 if needed - avoids reading
+-					@ nonexistant reg on rev0
+-	VFPFSTMIA r4 			@ save the working registers
++	tst	r1, #FPEXC_EX		@ is there additional state to save?
++	VFPFMRX	r6, FPINST, NE		@ FPINST (only if FPEXC.EX is set)
++	tstne	r1, #FPEXC_FP2V		@ is there an FPINST2 to read?
++	VFPFMRX	r8, FPINST2, NE		@ FPINST2 if needed (and present)
+ 	stmia	r4, {r1, r5, r6, r8}	@ save FPEXC, FPSCR, FPINST, FPINST2
+ 					@ and point r4 at the word at the
+ 					@ start of the register dump
+@@ -114,13 +114,13 @@ no_old_VFP_process:
+ 	DBGSTR1	"load state %p", r10
+ 	str	r10, [r3, r11, lsl #2]	@ update the last_VFP_context pointer
+ 					@ Load the saved state back into the VFP
+-	VFPFLDMIA r10	 		@ reload the working registers while
++	VFPFLDMIA r10, r5		@ reload the working registers while
+ 					@ FPEXC is in a safe state
+ 	ldmia	r10, {r1, r5, r6, r8}	@ load FPEXC, FPSCR, FPINST, FPINST2
+-	tst	r1, #FPEXC_FPV2		@ is there an FPINST2 to write?
+-	VFPFMXR	FPINST2, r8, NE		@ FPINST2 if needed - avoids writing
+-					@ nonexistant reg on rev0
+-	VFPFMXR	FPINST, r6
++	tst	r1, #FPEXC_EX		@ is there additional state to restore?
++	VFPFMXR	FPINST, r6, NE		@ restore FPINST (only if FPEXC.EX is set)
++	tstne	r1, #FPEXC_FP2V		@ is there an FPINST2 to write?
++	VFPFMXR	FPINST2, r8, NE		@ FPINST2 if needed (and present)
+ 	VFPFMXR	FPSCR, r5		@ restore status
+ 
+ check_for_exception:
+@@ -136,10 +136,14 @@ check_for_exception:
+ 
+ 
+ look_for_VFP_exceptions:
+-	tst	r1, #FPEXC_EX
++	@ Check for synchronous or asynchronous exception
++	tst	r1, #FPEXC_EX | FPEXC_DEX
+ 	bne	process_exception
++	@ On some implementations of the VFP subarch 1, setting FPSCR.IXE
++	@ causes all the CDP instructions to be bounced synchronously without
++	@ setting the FPEXC.EX bit
+ 	VFPFMRX	r5, FPSCR
+-	tst	r5, #FPSCR_IXE		@ IXE doesn't set FPEXC_EX !
++	tst	r5, #FPSCR_IXE
+ 	bne	process_exception
+ 
+ 	@ Fall into hand on to next handler - appropriate coproc instr
+@@ -150,10 +154,6 @@ look_for_VFP_exceptions:
+ 
+ process_exception:
+ 	DBGSTR	"bounce"
+-	sub	r2, r2, #4
+-	str	r2, [sp, #S_PC]		@ retry the instruction on exit from
+-					@ the imprecise exception handling in
+-					@ the support code
+ 	mov	r2, sp			@ nothing stacked - regdump is at TOS
+ 	mov	lr, r9			@ setup for a return to the user code.
+ 
+@@ -161,7 +161,7 @@ process_exception:
+ 	@   r0 holds the trigger instruction
+ 	@   r1 holds the FPEXC value
+ 	@   r2 pointer to register dump
+-	b	VFP9_bounce		@ we have handled this - the support
++	b	VFP_bounce		@ we have handled this - the support
+ 					@ code will raise an exception if
+ 					@ required. If not, the user code will
+ 					@ retry the faulted instruction
+@@ -174,12 +174,12 @@ vfp_save_state:
+ 	@ r0 - save location
+ 	@ r1 - FPEXC
+ 	DBGSTR1	"save VFP state %p", r0
++	VFPFSTMIA r0, r2		@ save the working registers
+ 	VFPFMRX	r2, FPSCR		@ current status
+-	VFPFMRX	r3, FPINST		@ FPINST (always there, rev0 onwards)
+-	tst	r1, #FPEXC_FPV2		@ is there an FPINST2 to read?
+-	VFPFMRX	r12, FPINST2, NE	@ FPINST2 if needed - avoids reading
+-					@ nonexistant reg on rev0
+-	VFPFSTMIA r0 			@ save the working registers
++	tst	r1, #FPEXC_EX		@ is there additional state to save?
++	VFPFMRX	r3, FPINST, NE		@ FPINST (only if FPEXC.EX is set)
++	tstne	r1, #FPEXC_FP2V		@ is there an FPINST2 to read?
++	VFPFMRX	r12, FPINST2, NE	@ FPINST2 if needed (and present)
+ 	stmia	r0, {r1, r2, r3, r12}	@ save FPEXC, FPSCR, FPINST, FPINST2
+ 	mov	pc, lr
+ #endif
+@@ -217,8 +217,15 @@ vfp_get_double:
+ 	fmrrd	r0, r1, d\dr
+ 	mov	pc, lr
+ 	.endr
++#ifdef CONFIG_VFPv3
++	@ d16 - d31 registers
++	.irp	dr,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
++	mrrc	p11, 3, r0, r1, c\dr	@ fmrrd	r0, r1, d\dr
++	mov	pc, lr
++	.endr
++#endif
+ 
+-	@ virtual register 16 for compare with zero
++	@ virtual register 16 (or 32 if VFPv3) for compare with zero
+ 	mov	r0, #0
+ 	mov	r1, #0
+ 	mov	pc, lr
+@@ -231,3 +238,10 @@ vfp_put_double:
+ 	fmdrr	d\dr, r0, r1
+ 	mov	pc, lr
+ 	.endr
++#ifdef CONFIG_VFPv3
++	@ d16 - d31 registers
++	.irp	dr,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
++	mcrr	p11, 3, r1, r2, c\dr	@ fmdrr	r1, r2, d\dr
++	mov	pc, lr
++	.endr
++#endif
+diff --git a/arch/arm/vfp/vfpinstr.h b/arch/arm/vfp/vfpinstr.h
+index 7f343a4..15b95b5 100644
+--- a/arch/arm/vfp/vfpinstr.h
++++ b/arch/arm/vfp/vfpinstr.h
+@@ -52,11 +52,11 @@
+ #define FEXT_TO_IDX(inst)	((inst & 0x000f0000) >> 15 | (inst & (1 << 7)) >> 7)
+ 
+ #define vfp_get_sd(inst)	((inst & 0x0000f000) >> 11 | (inst & (1 << 22)) >> 22)
+-#define vfp_get_dd(inst)	((inst & 0x0000f000) >> 12)
++#define vfp_get_dd(inst)	((inst & 0x0000f000) >> 12 | (inst & (1 << 22)) >> 18)
+ #define vfp_get_sm(inst)	((inst & 0x0000000f) << 1 | (inst & (1 << 5)) >> 5)
+-#define vfp_get_dm(inst)	((inst & 0x0000000f))
++#define vfp_get_dm(inst)	((inst & 0x0000000f) | (inst & (1 << 5)) >> 1)
+ #define vfp_get_sn(inst)	((inst & 0x000f0000) >> 15 | (inst & (1 << 7)) >> 7)
+-#define vfp_get_dn(inst)	((inst & 0x000f0000) >> 16)
++#define vfp_get_dn(inst)	((inst & 0x000f0000) >> 16 | (inst & (1 << 7)) >> 3)
+ 
+ #define vfp_single(inst)	(((inst) & 0x0000f00) == 0xa00)
+ 
+diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c
+index b4e210d..32455c6 100644
+--- a/arch/arm/vfp/vfpmodule.c
++++ b/arch/arm/vfp/vfpmodule.c
+@@ -125,13 +125,13 @@ void vfp_raise_sigfpe(unsigned int sicode, struct pt_regs *regs)
+ 	send_sig_info(SIGFPE, &info, current);
+ }
+ 
+-static void vfp_panic(char *reason)
++static void vfp_panic(char *reason, u32 inst)
+ {
+ 	int i;
+ 
+ 	printk(KERN_ERR "VFP: Error: %s\n", reason);
+ 	printk(KERN_ERR "VFP: EXC 0x%08x SCR 0x%08x INST 0x%08x\n",
+-		fmrx(FPEXC), fmrx(FPSCR), fmrx(FPINST));
++		fmrx(FPEXC), fmrx(FPSCR), inst);
+ 	for (i = 0; i < 32; i += 2)
+ 		printk(KERN_ERR "VFP: s%2u: 0x%08x s%2u: 0x%08x\n",
+ 		       i, vfp_get_float(i), i+1, vfp_get_float(i+1));
+@@ -147,19 +147,16 @@ static void vfp_raise_exceptions(u32 exceptions, u32 inst, u32 fpscr, struct pt_
+ 	pr_debug("VFP: raising exceptions %08x\n", exceptions);
+ 
+ 	if (exceptions == VFP_EXCEPTION_ERROR) {
+-		vfp_panic("unhandled bounce");
++		vfp_panic("unhandled bounce", inst);
+ 		vfp_raise_sigfpe(0, regs);
+ 		return;
+ 	}
+ 
+ 	/*
+-	 * If any of the status flags are set, update the FPSCR.
++	 * Update the FPSCR with the additional exception flags.
+ 	 * Comparison instructions always return at least one of
+ 	 * these flags set.
+ 	 */
+-	if (exceptions & (FPSCR_N|FPSCR_Z|FPSCR_C|FPSCR_V))
+-		fpscr &= ~(FPSCR_N|FPSCR_Z|FPSCR_C|FPSCR_V);
+-
+ 	fpscr |= exceptions;
+ 
+ 	fmxr(FPSCR, fpscr);
+@@ -220,35 +217,64 @@ static u32 vfp_emulate_instruction(u32 inst, u32 fpscr, struct pt_regs *regs)
+ /*
+  * Package up a bounce condition.
+  */
+-void VFP9_bounce(u32 trigger, u32 fpexc, struct pt_regs *regs)
++void VFP_bounce(u32 trigger, u32 fpexc, struct pt_regs *regs)
+ {
+-	u32 fpscr, orig_fpscr, exceptions, inst;
++	u32 fpscr, orig_fpscr, fpsid, exceptions;
+ 
+ 	pr_debug("VFP: bounce: trigger %08x fpexc %08x\n", trigger, fpexc);
+ 
+ 	/*
+-	 * Enable access to the VFP so we can handle the bounce.
++	 * At this point, FPEXC can have the following configuration:
++	 *
++	 *  EX DEX IXE
++	 *  0   1   x   - synchronous exception
++	 *  1   x   0   - asynchronous exception
++	 *  1   x   1   - sychronous on VFP subarch 1 and asynchronous on later
++	 *  0   0   1   - synchronous on VFP9 (non-standard subarch 1
++	 *                implementation), undefined otherwise
++	 *
++	 * Clear various bits and enable access to the VFP so we can
++	 * handle the bounce.
+ 	 */
+-	fmxr(FPEXC, fpexc & ~(FPEXC_EX|FPEXC_FPV2|FPEXC_INV|FPEXC_UFC|FPEXC_OFC|FPEXC_IOC));
++	fmxr(FPEXC, fpexc & ~(FPEXC_EX|FPEXC_DEX|FPEXC_FP2V|FPEXC_VV|FPEXC_TRAP_MASK));
+ 
++	fpsid = fmrx(FPSID);
+ 	orig_fpscr = fpscr = fmrx(FPSCR);
+ 
+ 	/*
+-	 * If we are running with inexact exceptions enabled, we need to
+-	 * emulate the trigger instruction.  Note that as we're emulating
+-	 * the trigger instruction, we need to increment PC.
++	 * Check for the special VFP subarch 1 and FPSCR.IXE bit case
+ 	 */
+-	if (fpscr & FPSCR_IXE) {
+-		regs->ARM_pc += 4;
++	if ((fpsid & FPSID_ARCH_MASK) == (1 << FPSID_ARCH_BIT)
++	    && (fpscr & FPSCR_IXE)) {
++		/*
++		 * Synchronous exception, emulate the trigger instruction
++		 */
+ 		goto emulate;
+ 	}
+ 
+-	barrier();
++	if (fpexc & FPEXC_EX) {
++		/*
++		 * Asynchronous exception. The instruction is read from FPINST
++		 * and the interrupted instruction has to be restarted.
++		 */
++		trigger = fmrx(FPINST);
++		regs->ARM_pc -= 4;
++	} else if (!(fpexc & FPEXC_DEX)) {
++		/*
++		 * Illegal combination of bits. It can be caused by an
++		 * unallocated VFP instruction but with FPSCR.IXE set and not
++		 * on VFP subarch 1.
++		 */
++		 vfp_raise_exceptions(VFP_EXCEPTION_ERROR, trigger, fpscr, regs);
++		 return;
++	}
+ 
+ 	/*
+-	 * Modify fpscr to indicate the number of iterations remaining
++	 * Modify fpscr to indicate the number of iterations remaining.
++	 * If FPEXC.EX is 0, FPEXC.DEX is 1 and the FPEXC.VV bit indicates
++	 * whether FPEXC.VECITR or FPSCR.LEN is used.
+ 	 */
+-	if (fpexc & FPEXC_EX) {
++	if (fpexc & (FPEXC_EX | FPEXC_VV)) {
+ 		u32 len;
+ 
+ 		len = fpexc + (1 << FPEXC_LENGTH_BIT);
+@@ -262,15 +288,15 @@ void VFP9_bounce(u32 trigger, u32 fpexc, struct pt_regs *regs)
+ 	 * FPEXC bounce reason, but this appears to be unreliable.
+ 	 * Emulate the bounced instruction instead.
+ 	 */
+-	inst = fmrx(FPINST);
+-	exceptions = vfp_emulate_instruction(inst, fpscr, regs);
++	exceptions = vfp_emulate_instruction(trigger, fpscr, regs);
+ 	if (exceptions)
+-		vfp_raise_exceptions(exceptions, inst, orig_fpscr, regs);
++		vfp_raise_exceptions(exceptions, trigger, orig_fpscr, regs);
+ 
+ 	/*
+-	 * If there isn't a second FP instruction, exit now.
++	 * If there isn't a second FP instruction, exit now. Note that
++	 * the FPEXC.FP2V bit is valid only if FPEXC.EX is 1.
+ 	 */
+-	if (!(fpexc & FPEXC_FPV2))
++	if (fpexc ^ (FPEXC_EX | FPEXC_FP2V))
+ 		return;
+ 
+ 	/*
+@@ -279,10 +305,9 @@ void VFP9_bounce(u32 trigger, u32 fpexc, struct pt_regs *regs)
+ 	 */
+ 	barrier();
+ 	trigger = fmrx(FPINST2);
+-	orig_fpscr = fpscr = fmrx(FPSCR);
+ 
+  emulate:
+-	exceptions = vfp_emulate_instruction(trigger, fpscr, regs);
++	exceptions = vfp_emulate_instruction(trigger, orig_fpscr, regs);
+ 	if (exceptions)
+ 		vfp_raise_exceptions(exceptions, trigger, orig_fpscr, regs);
+ }
+@@ -306,16 +331,9 @@ static int __init vfp_init(void)
+ {
+ 	unsigned int vfpsid;
+ 	unsigned int cpu_arch = cpu_architecture();
+-	u32 access = 0;
+ 
+-	if (cpu_arch >= CPU_ARCH_ARMv6) {
+-		access = get_copro_access();
+-
+-		/*
+-		 * Enable full access to VFP (cp10 and cp11)
+-		 */
+-		set_copro_access(access | CPACC_FULL(10) | CPACC_FULL(11));
+-	}
++	if (cpu_arch >= CPU_ARCH_ARMv6)
++		vfp_enable(NULL);
+ 
+ 	/*
+ 	 * First check that there is a VFP that we can use.
+@@ -329,15 +347,9 @@ static int __init vfp_init(void)
+ 	vfp_vector = vfp_null_entry;
+ 
+ 	printk(KERN_INFO "VFP support v0.3: ");
+-	if (VFP_arch) {
++	if (VFP_arch)
+ 		printk("not present\n");
+-
+-		/*
+-		 * Restore the copro access register.
+-		 */
+-		if (cpu_arch >= CPU_ARCH_ARMv6)
+-			set_copro_access(access);
+-	} else if (vfpsid & FPSID_NODOUBLE) {
++	else if (vfpsid & FPSID_NODOUBLE) {
+ 		printk("no double precision support\n");
+ 	} else {
+ 		smp_call_function(vfp_enable, NULL, 1, 1);
+diff --git a/arch/avr32/Kconfig b/arch/avr32/Kconfig
+index b77abce..e34e2c9 100644
+--- a/arch/avr32/Kconfig
++++ b/arch/avr32/Kconfig
+@@ -54,6 +54,9 @@ config ARCH_HAS_ILOG2_U32
+ config ARCH_HAS_ILOG2_U64
+ 	def_bool n
+ 
++config ARCH_SUPPORTS_OPROFILE
++	def_bool y
++
+ config GENERIC_HWEIGHT
+ 	def_bool y
+ 
+@@ -81,19 +84,23 @@ config PLATFORM_AT32AP
+ 	select MMU
+ 	select PERFORMANCE_COUNTERS
+ 
+-choice
+-	prompt "AVR32 CPU type"
+-	default CPU_AT32AP7000
++#
++# CPU types
++#
+ 
+-config CPU_AT32AP7000
+-	bool "AT32AP7000"
++# AP7000 derivatives
++config CPU_AT32AP700X
++	bool
+ 	select PLATFORM_AT32AP
+-endchoice
+-
+-#
+-# CPU Daughterboards for ATSTK1000
+-config BOARD_ATSTK1002
++config CPU_AT32AP7000
++	bool
++	select CPU_AT32AP700X
++config CPU_AT32AP7001
++	bool
++	select CPU_AT32AP700X
++config CPU_AT32AP7002
+ 	bool
++	select CPU_AT32AP700X
+ 
+ choice
+ 	prompt "AVR32 board type"
+@@ -101,10 +108,10 @@ choice
+ 
+ config BOARD_ATSTK1000
+ 	bool "ATSTK1000 evaluation board"
+-	select BOARD_ATSTK1002 if CPU_AT32AP7000
+ 
+ config BOARD_ATNGW100
+ 	bool "ATNGW100 Network Gateway"
++	select CPU_AT32AP7000
+ endchoice
+ 
+ if BOARD_ATSTK1000
+@@ -123,15 +130,15 @@ source "arch/avr32/mach-at32ap/Kconfig"
+ 
+ config LOAD_ADDRESS
+ 	hex
+-	default 0x10000000 if LOADER_U_BOOT=y && CPU_AT32AP7000=y
++	default 0x10000000 if LOADER_U_BOOT=y && CPU_AT32AP700X=y
+ 
+ config ENTRY_ADDRESS
+ 	hex
+-	default 0x90000000 if LOADER_U_BOOT=y && CPU_AT32AP7000=y
++	default 0x90000000 if LOADER_U_BOOT=y && CPU_AT32AP700X=y
+ 
+ config PHYS_OFFSET
+ 	hex
+-	default 0x10000000 if CPU_AT32AP7000=y
++	default 0x10000000 if CPU_AT32AP700X=y
+ 
+ source "kernel/Kconfig.preempt"
+ 
+@@ -163,6 +170,16 @@ config OWNERSHIP_TRACE
+ 	  enabling Nexus-compliant debuggers to keep track of the PID of the
+ 	  currently executing task.
+ 
++config NMI_DEBUGGING
++	bool "NMI Debugging"
++	default n
++	help
++	  Say Y here and pass the nmi_debug command-line parameter to
++	  the kernel to turn on NMI debugging. Depending on the value
++	  of the nmi_debug option, various pieces of information will
++	  be dumped to the console when a Non-Maskable Interrupt
++	  happens.
++
+ # FPU emulation goes here
+ 
+ source "kernel/Kconfig.hz"
+@@ -219,6 +236,8 @@ source "drivers/Kconfig"
+ 
+ source "fs/Kconfig"
+ 
++source "kernel/Kconfig.instrumentation"
++
+ source "arch/avr32/Kconfig.debug"
+ 
+ source "security/Kconfig"
+diff --git a/arch/avr32/Kconfig.debug b/arch/avr32/Kconfig.debug
+index 64ace00..2283933 100644
+--- a/arch/avr32/Kconfig.debug
++++ b/arch/avr32/Kconfig.debug
+@@ -6,14 +6,4 @@ config TRACE_IRQFLAGS_SUPPORT
+ 
+ source "lib/Kconfig.debug"
+ 
+-config KPROBES
+-	bool "Kprobes"
+-	depends on DEBUG_KERNEL
+-	help
+-	  Kprobes allows you to trap at almost any kernel address and
+-          execute a callback function.  register_kprobe() establishes
+-          a probepoint and specifies the callback.  Kprobes is useful
+-          for kernel debugging, non-intrusive instrumentation and testing.
+-          If in doubt, say "N".
+-
+ endmenu
+diff --git a/arch/avr32/Makefile b/arch/avr32/Makefile
+index 8791864..17a3529 100644
+--- a/arch/avr32/Makefile
++++ b/arch/avr32/Makefile
+@@ -16,7 +16,7 @@ KBUILD_AFLAGS	+= -mrelax -mno-pic
+ CFLAGS_MODULE	+= -mno-relax
+ LDFLAGS_vmlinux	+= --relax
+ 
+-cpuflags-$(CONFIG_CPU_AT32AP7000)	+= -mcpu=ap7000
++cpuflags-$(CONFIG_PLATFORM_AT32AP)	+= -march=ap
+ 
+ KBUILD_CFLAGS	+= $(cpuflags-y)
+ KBUILD_AFLAGS	+= $(cpuflags-y)
+@@ -31,6 +31,7 @@ core-$(CONFIG_BOARD_ATNGW100)		+= arch/avr32/boards/atngw100/
+ core-$(CONFIG_LOADER_U_BOOT)		+= arch/avr32/boot/u-boot/
+ core-y					+= arch/avr32/kernel/
+ core-y					+= arch/avr32/mm/
++drivers-$(CONFIG_OPROFILE)		+= arch/avr32/oprofile/
+ libs-y					+= arch/avr32/lib/
+ 
+ archincdir-$(CONFIG_PLATFORM_AT32AP)	:= arch-at32ap
+diff --git a/arch/avr32/boards/atngw100/setup.c b/arch/avr32/boards/atngw100/setup.c
+index 52987c8..a398be2 100644
+--- a/arch/avr32/boards/atngw100/setup.c
++++ b/arch/avr32/boards/atngw100/setup.c
+@@ -20,7 +20,7 @@
+ #include <asm/io.h>
+ #include <asm/setup.h>
+ 
+-#include <asm/arch/at32ap7000.h>
++#include <asm/arch/at32ap700x.h>
+ #include <asm/arch/board.h>
+ #include <asm/arch/init.h>
+ #include <asm/arch/portmux.h>
+diff --git a/arch/avr32/boards/atstk1000/Kconfig b/arch/avr32/boards/atstk1000/Kconfig
+index 718578f..af90b00 100644
+--- a/arch/avr32/boards/atstk1000/Kconfig
++++ b/arch/avr32/boards/atstk1000/Kconfig
+@@ -1,34 +1,53 @@
+ # STK1000 customization
+ 
+-if BOARD_ATSTK1002
++if BOARD_ATSTK1000
+ 
+-config BOARD_ATSTK1002_CUSTOM
+-	bool "Non-default STK-1002 jumper settings"
++choice
++	prompt "ATSTK1000 CPU daughterboard type"
++	default BOARD_ATSTK1002
++
++config BOARD_ATSTK1002
++	bool "ATSTK1002"
++	select CPU_AT32AP7000
++
++config BOARD_ATSTK1003
++	bool "ATSTK1003"
++	select CPU_AT32AP7001
++
++config BOARD_ATSTK1004
++	bool "ATSTK1004"
++	select CPU_AT32AP7002
++
++endchoice
++
++
++config BOARD_ATSTK100X_CUSTOM
++	bool "Non-default STK1002/STK1003/STK1004 jumper settings"
+ 	help
+ 	  You will normally leave the jumpers on the CPU card at their
+ 	  default settings.  If you need to use certain peripherals,
+ 	  you will need to change some of those jumpers.
+ 
+-if BOARD_ATSTK1002_CUSTOM
++if BOARD_ATSTK100X_CUSTOM
+ 
+-config BOARD_ATSTK1002_SW1_CUSTOM
++config BOARD_ATSTK100X_SW1_CUSTOM
+ 	bool "SW1: use SSC1 (not SPI0)"
+ 	help
+ 	  This also prevents using the external DAC as an audio interface,
+ 	  and means you can't initialize the on-board QVGA display.
+ 
+-config BOARD_ATSTK1002_SW2_CUSTOM
++config BOARD_ATSTK100X_SW2_CUSTOM
+ 	bool "SW2: use IRDA or TIMER0 (not UART-A, MMC/SD, and PS2-A)"
+ 	help
+ 	  If you change this you'll want an updated boot loader putting
+ 	  the console on UART-C not UART-A.
+ 
+-config BOARD_ATSTK1002_SW3_CUSTOM
++config BOARD_ATSTK100X_SW3_CUSTOM
+ 	bool "SW3: use TIMER1 (not SSC0 and GCLK)"
+ 	help
+ 	  This also prevents using the external DAC as an audio interface.
+ 
+-config BOARD_ATSTK1002_SW4_CUSTOM
++config BOARD_ATSTK100X_SW4_CUSTOM
+ 	bool "SW4: use ISI/Camera (not GPIOs, SPI1, and PS2-B)"
+ 	help
+ 	  To use the camera interface you'll need a custom card (on the
+@@ -36,27 +55,29 @@ config BOARD_ATSTK1002_SW4_CUSTOM
+ 
+ config BOARD_ATSTK1002_SW5_CUSTOM
+ 	bool "SW5: use MACB1 (not LCDC)"
++	depends on BOARD_ATSTK1002
+ 
+ config BOARD_ATSTK1002_SW6_CUSTOM
+ 	bool "SW6: more GPIOs (not MACB0)"
++	depends on BOARD_ATSTK1002
+ 
+ endif	# custom
+ 
+-config BOARD_ATSTK1002_SPI1
++config BOARD_ATSTK100X_SPI1
+ 	bool "Configure SPI1 controller"
+-	depends on !BOARD_ATSTK1002_SW4_CUSTOM
++	depends on !BOARD_ATSTK100X_SW4_CUSTOM
+ 	help
+ 	  All the signals for the second SPI controller are available on
+ 	  GPIO lines and accessed through the J1 jumper block.  Say "y"
+ 	  here to configure that SPI controller.
+ 
+-config BOARD_ATSTK1002_J2_LED
++config BOARD_ATSTK1000_J2_LED
+ 	bool
+-	default BOARD_ATSTK1002_J2_LED8 || BOARD_ATSTK1002_J2_RGB
++	default BOARD_ATSTK1000_J2_LED8 || BOARD_ATSTK1000_J2_RGB
+ 
+ choice
+ 	prompt "LEDs connected to J2:"
+-	depends on LEDS_GPIO && !BOARD_ATSTK1002_SW4_CUSTOM
++	depends on LEDS_GPIO && !BOARD_ATSTK100X_SW4_CUSTOM
+ 	optional
+ 	help
+ 	  Select this if you have jumpered the J2 jumper block to the
+@@ -64,16 +85,21 @@ choice
+ 	  IDC cable.  A default "heartbeat" trigger is provided, but
+ 	  you can of course override this.
+ 
+-config BOARD_ATSTK1002_J2_LED8
++config BOARD_ATSTK1000_J2_LED8
+ 	bool "LED0..LED7"
+ 	help
+ 	  Select this if J2 is jumpered to LED0..LED7 amber leds.
+ 
+-config BOARD_ATSTK1002_J2_RGB
++config BOARD_ATSTK1000_J2_RGB
+ 	bool "RGB leds"
+ 	help
+ 	  Select this if J2 is jumpered to the RGB leds.
+ 
+ endchoice
+ 
+-endif	# stk 1002
++config BOARD_ATSTK1000_EXTDAC
++	bool
++	depends on !BOARD_ATSTK100X_SW1_CUSTOM && !BOARD_ATSTK100X_SW3_CUSTOM
++	default y
++
++endif	# stk 1000
+diff --git a/arch/avr32/boards/atstk1000/Makefile b/arch/avr32/boards/atstk1000/Makefile
+index 8e09922..beead86 100644
+--- a/arch/avr32/boards/atstk1000/Makefile
++++ b/arch/avr32/boards/atstk1000/Makefile
+@@ -1,2 +1,4 @@
+ obj-y				+= setup.o flash.o
+ obj-$(CONFIG_BOARD_ATSTK1002)	+= atstk1002.o
++obj-$(CONFIG_BOARD_ATSTK1003)	+= atstk1003.o
++obj-$(CONFIG_BOARD_ATSTK1004)	+= atstk1004.o
+diff --git a/arch/avr32/boards/atstk1000/atstk1000.h b/arch/avr32/boards/atstk1000/atstk1000.h
+index 9a49ed0..9392d32 100644
+--- a/arch/avr32/boards/atstk1000/atstk1000.h
++++ b/arch/avr32/boards/atstk1000/atstk1000.h
+@@ -12,4 +12,6 @@
+ 
+ extern struct atmel_lcdfb_info atstk1000_lcdc_data;
+ 
++void atstk1000_setup_j2_leds(void);
++
+ #endif /* __ARCH_AVR32_BOARDS_ATSTK1000_ATSTK1000_H */
+diff --git a/arch/avr32/boards/atstk1000/atstk1002.c b/arch/avr32/boards/atstk1000/atstk1002.c
+index 5be0d13..000eb42 100644
+--- a/arch/avr32/boards/atstk1000/atstk1002.c
++++ b/arch/avr32/boards/atstk1000/atstk1002.c
+@@ -11,7 +11,6 @@
+ #include <linux/etherdevice.h>
+ #include <linux/init.h>
+ #include <linux/kernel.h>
+-#include <linux/leds.h>
+ #include <linux/platform_device.h>
+ #include <linux/string.h>
+ #include <linux/types.h>
+@@ -22,7 +21,7 @@
+ 
+ #include <asm/io.h>
+ #include <asm/setup.h>
+-#include <asm/arch/at32ap7000.h>
++#include <asm/arch/at32ap700x.h>
+ #include <asm/arch/board.h>
+ #include <asm/arch/init.h>
+ #include <asm/arch/portmux.h>
+@@ -49,18 +48,16 @@ static struct eth_platform_data __initdata eth_data[2] = {
+ 	},
+ };
+ 
+-#ifndef CONFIG_BOARD_ATSTK1002_SW1_CUSTOM
+-#ifndef CONFIG_BOARD_ATSTK1002_SW3_CUSTOM
++#ifdef CONFIG_BOARD_ATSTK1000_EXTDAC
+ static struct at73c213_board_info at73c213_data = {
+ 	.ssc_id		= 0,
+ 	.shortname	= "AVR32 STK1000 external DAC",
+ };
+ #endif
+-#endif
+ 
+-#ifndef CONFIG_BOARD_ATSTK1002_SW1_CUSTOM
++#ifndef CONFIG_BOARD_ATSTK100X_SW1_CUSTOM
+ static struct spi_board_info spi0_board_info[] __initdata = {
+-#ifndef CONFIG_BOARD_ATSTK1002_SW3_CUSTOM
++#ifdef CONFIG_BOARD_ATSTK1000_EXTDAC
+ 	{
+ 		/* AT73C213 */
+ 		.modalias	= "at73c213",
+@@ -80,7 +77,7 @@ static struct spi_board_info spi0_board_info[] __initdata = {
+ };
+ #endif
+ 
+-#ifdef CONFIG_BOARD_ATSTK1002_SPI1
++#ifdef CONFIG_BOARD_ATSTK100X_SPI1
+ static struct spi_board_info spi1_board_info[] __initdata = { {
+ 	/* patch in custom entries here */
+ } };
+@@ -141,68 +138,8 @@ static void __init set_hw_addr(struct platform_device *pdev)
+ 	clk_put(pclk);
+ }
+ 
+-#ifdef CONFIG_BOARD_ATSTK1002_J2_LED
+-
+-static struct gpio_led stk_j2_led[] = {
+-#ifdef CONFIG_BOARD_ATSTK1002_J2_LED8
+-#define LEDSTRING "J2 jumpered to LED8"
+-	{ .name = "led0:amber", .gpio = GPIO_PIN_PB( 8), },
+-	{ .name = "led1:amber", .gpio = GPIO_PIN_PB( 9), },
+-	{ .name = "led2:amber", .gpio = GPIO_PIN_PB(10), },
+-	{ .name = "led3:amber", .gpio = GPIO_PIN_PB(13), },
+-	{ .name = "led4:amber", .gpio = GPIO_PIN_PB(14), },
+-	{ .name = "led5:amber", .gpio = GPIO_PIN_PB(15), },
+-	{ .name = "led6:amber", .gpio = GPIO_PIN_PB(16), },
+-	{ .name = "led7:amber", .gpio = GPIO_PIN_PB(30),
+-			.default_trigger = "heartbeat", },
+-#else	/* RGB */
+-#define LEDSTRING "J2 jumpered to RGB LEDs"
+-	{ .name = "r1:red",     .gpio = GPIO_PIN_PB( 8), },
+-	{ .name = "g1:green",   .gpio = GPIO_PIN_PB(10), },
+-	{ .name = "b1:blue",    .gpio = GPIO_PIN_PB(14), },
+-
+-	{ .name = "r2:red",     .gpio = GPIO_PIN_PB( 9),
+-			.default_trigger = "heartbeat", },
+-	{ .name = "g2:green",   .gpio = GPIO_PIN_PB(13), },
+-	{ .name = "b2:blue",    .gpio = GPIO_PIN_PB(15),
+-			.default_trigger = "heartbeat", },
+-	/* PB16, PB30 unused */
+-#endif
+-};
+-
+-static struct gpio_led_platform_data stk_j2_led_data = {
+-	.num_leds	= ARRAY_SIZE(stk_j2_led),
+-	.leds		= stk_j2_led,
+-};
+-
+-static struct platform_device stk_j2_led_dev = {
+-	.name		= "leds-gpio",
+-	.id		= 2,	/* gpio block J2 */
+-	.dev		= {
+-		.platform_data	= &stk_j2_led_data,
+-	},
+-};
+-
+-static void setup_j2_leds(void)
+-{
+-	unsigned	i;
+-
+-	for (i = 0; i < ARRAY_SIZE(stk_j2_led); i++)
+-		at32_select_gpio(stk_j2_led[i].gpio, AT32_GPIOF_OUTPUT);
+-
+-	printk("STK1002: " LEDSTRING "\n");
+-	platform_device_register(&stk_j2_led_dev);
+-}
+-
+-#else
+-static void setup_j2_leds(void)
+-{
+-}
+-#endif
+-
+-#ifndef CONFIG_BOARD_ATSTK1002_SW1_CUSTOM
+-#ifndef CONFIG_BOARD_ATSTK1002_SW3_CUSTOM
+-static void __init at73c213_set_clk(struct at73c213_board_info *info)
++#ifdef CONFIG_BOARD_ATSTK1000_EXTDAC
++static void __init atstk1002_setup_extdac(void)
+ {
+ 	struct clk *gclk;
+ 	struct clk *pll;
+@@ -220,7 +157,7 @@ static void __init at73c213_set_clk(struct at73c213_board_info *info)
+ 	}
+ 
+ 	at32_select_periph(GPIO_PIN_PA(30), GPIO_PERIPH_A, 0);
+-	info->dac_clk = gclk;
++	at73c213_data.dac_clk = gclk;
+ 
+ err_set_clk:
+ 	clk_put(pll);
+@@ -229,12 +166,16 @@ err_pll:
+ err_gclk:
+ 	return;
+ }
+-#endif
+-#endif
++#else
++static void __init atstk1002_setup_extdac(void)
++{
++
++}
++#endif /* CONFIG_BOARD_ATSTK1000_EXTDAC */
+ 
+ void __init setup_board(void)
+ {
+-#ifdef	CONFIG_BOARD_ATSTK1002_SW2_CUSTOM
++#ifdef	CONFIG_BOARD_ATSTK100X_SW2_CUSTOM
+ 	at32_map_usart(0, 1);	/* USART 0/B: /dev/ttyS1, IRDA */
+ #else
+ 	at32_map_usart(1, 0);	/* USART 1/A: /dev/ttyS0, DB9 */
+@@ -271,7 +212,7 @@ static int __init atstk1002_init(void)
+ 
+ 	at32_add_system_devices();
+ 
+-#ifdef	CONFIG_BOARD_ATSTK1002_SW2_CUSTOM
++#ifdef	CONFIG_BOARD_ATSTK100X_SW2_CUSTOM
+ 	at32_add_device_usart(1);
+ #else
+ 	at32_add_device_usart(0);
+@@ -281,10 +222,10 @@ static int __init atstk1002_init(void)
+ #ifndef CONFIG_BOARD_ATSTK1002_SW6_CUSTOM
+ 	set_hw_addr(at32_add_device_eth(0, &eth_data[0]));
+ #endif
+-#ifndef CONFIG_BOARD_ATSTK1002_SW1_CUSTOM
++#ifndef CONFIG_BOARD_ATSTK100X_SW1_CUSTOM
+ 	at32_add_device_spi(0, spi0_board_info, ARRAY_SIZE(spi0_board_info));
+ #endif
+-#ifdef CONFIG_BOARD_ATSTK1002_SPI1
++#ifdef CONFIG_BOARD_ATSTK100X_SPI1
+ 	at32_add_device_spi(1, spi1_board_info, ARRAY_SIZE(spi1_board_info));
+ #endif
+ #ifdef CONFIG_BOARD_ATSTK1002_SW5_CUSTOM
+@@ -294,17 +235,12 @@ static int __init atstk1002_init(void)
+ 			     fbmem_start, fbmem_size);
+ #endif
+ 	at32_add_device_usba(0, NULL);
+-#ifndef CONFIG_BOARD_ATSTK1002_SW3_CUSTOM
++#ifndef CONFIG_BOARD_ATSTK100X_SW3_CUSTOM
+ 	at32_add_device_ssc(0, ATMEL_SSC_TX);
+ #endif
+ 
+-	setup_j2_leds();
+-
+-#ifndef CONFIG_BOARD_ATSTK1002_SW3_CUSTOM
+-#ifndef CONFIG_BOARD_ATSTK1002_SW1_CUSTOM
+-	at73c213_set_clk(&at73c213_data);
+-#endif
+-#endif
++	atstk1000_setup_j2_leds();
++	atstk1002_setup_extdac();
+ 
+ 	return 0;
+ }
+diff --git a/arch/avr32/boards/atstk1000/atstk1003.c b/arch/avr32/boards/atstk1000/atstk1003.c
+new file mode 100644
+index 0000000..a0b223d
+--- /dev/null
++++ b/arch/avr32/boards/atstk1000/atstk1003.c
+@@ -0,0 +1,162 @@
++/*
++ * ATSTK1003 daughterboard-specific init code
++ *
++ * 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 version 2 as
++ * published by the Free Software Foundation.
++ */
++#include <linux/clk.h>
++#include <linux/err.h>
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/platform_device.h>
++#include <linux/string.h>
++#include <linux/types.h>
++
++#include <linux/spi/at73c213.h>
++#include <linux/spi/spi.h>
++
++#include <asm/setup.h>
++
++#include <asm/arch/at32ap700x.h>
++#include <asm/arch/board.h>
++#include <asm/arch/init.h>
++#include <asm/arch/portmux.h>
++
++#include "atstk1000.h"
++
++#ifdef CONFIG_BOARD_ATSTK1000_EXTDAC
++static struct at73c213_board_info at73c213_data = {
++	.ssc_id		= 0,
++	.shortname	= "AVR32 STK1000 external DAC",
++};
++#endif
++
++#ifndef CONFIG_BOARD_ATSTK100X_SW1_CUSTOM
++static struct spi_board_info spi0_board_info[] __initdata = {
++#ifdef CONFIG_BOARD_ATSTK1000_EXTDAC
++	{
++		/* AT73C213 */
++		.modalias	= "at73c213",
++		.max_speed_hz	= 200000,
++		.chip_select	= 0,
++		.mode		= SPI_MODE_1,
++		.platform_data	= &at73c213_data,
++	},
++#endif
++	/*
++	 * We can control the LTV350QV LCD panel, but it isn't much
++	 * point since we don't have an LCD controller...
++	 */
++};
++#endif
++
++#ifdef CONFIG_BOARD_ATSTK100X_SPI1
++static struct spi_board_info spi1_board_info[] __initdata = { {
++	/* patch in custom entries here */
++} };
++#endif
++
++#ifdef CONFIG_BOARD_ATSTK1000_EXTDAC
++static void __init atstk1003_setup_extdac(void)
++{
++	struct clk *gclk;
++	struct clk *pll;
++
++	gclk = clk_get(NULL, "gclk0");
++	if (IS_ERR(gclk))
++		goto err_gclk;
++	pll = clk_get(NULL, "pll0");
++	if (IS_ERR(pll))
++		goto err_pll;
++
++	if (clk_set_parent(gclk, pll)) {
++		pr_debug("STK1000: failed to set pll0 as parent for DAC clock\n");
++		goto err_set_clk;
++	}
++
++	at32_select_periph(GPIO_PIN_PA(30), GPIO_PERIPH_A, 0);
++	at73c213_data.dac_clk = gclk;
++
++err_set_clk:
++	clk_put(pll);
++err_pll:
++	clk_put(gclk);
++err_gclk:
++	return;
++}
++#else
++static void __init atstk1003_setup_extdac(void)
++{
++
++}
++#endif /* CONFIG_BOARD_ATSTK1000_EXTDAC */
++
++void __init setup_board(void)
++{
++#ifdef	CONFIG_BOARD_ATSTK100X_SW2_CUSTOM
++	at32_map_usart(0, 1);	/* USART 0/B: /dev/ttyS1, IRDA */
++#else
++	at32_map_usart(1, 0);	/* USART 1/A: /dev/ttyS0, DB9 */
++#endif
++	/* USART 2/unused: expansion connector */
++	at32_map_usart(3, 2);	/* USART 3/C: /dev/ttyS2, DB9 */
++
++	at32_setup_serial_console(0);
++}
++
++static int __init atstk1003_init(void)
++{
++	/*
++	 * ATSTK1000 uses 32-bit SDRAM interface. Reserve the
++	 * SDRAM-specific pins so that nobody messes with them.
++	 */
++	at32_reserve_pin(GPIO_PIN_PE(0));	/* DATA[16]	*/
++	at32_reserve_pin(GPIO_PIN_PE(1));	/* DATA[17]	*/
++	at32_reserve_pin(GPIO_PIN_PE(2));	/* DATA[18]	*/
++	at32_reserve_pin(GPIO_PIN_PE(3));	/* DATA[19]	*/
++	at32_reserve_pin(GPIO_PIN_PE(4));	/* DATA[20]	*/
++	at32_reserve_pin(GPIO_PIN_PE(5));	/* DATA[21]	*/
++	at32_reserve_pin(GPIO_PIN_PE(6));	/* DATA[22]	*/
++	at32_reserve_pin(GPIO_PIN_PE(7));	/* DATA[23]	*/
++	at32_reserve_pin(GPIO_PIN_PE(8));	/* DATA[24]	*/
++	at32_reserve_pin(GPIO_PIN_PE(9));	/* DATA[25]	*/
++	at32_reserve_pin(GPIO_PIN_PE(10));	/* DATA[26]	*/
++	at32_reserve_pin(GPIO_PIN_PE(11));	/* DATA[27]	*/
++	at32_reserve_pin(GPIO_PIN_PE(12));	/* DATA[28]	*/
++	at32_reserve_pin(GPIO_PIN_PE(13));	/* DATA[29]	*/
++	at32_reserve_pin(GPIO_PIN_PE(14));	/* DATA[30]	*/
++	at32_reserve_pin(GPIO_PIN_PE(15));	/* DATA[31]	*/
++	at32_reserve_pin(GPIO_PIN_PE(26));	/* SDCS		*/
++
++	at32_add_system_devices();
++
++#ifdef	CONFIG_BOARD_ATSTK100X_SW2_CUSTOM
++	at32_add_device_usart(1);
++#else
++	at32_add_device_usart(0);
++#endif
++	at32_add_device_usart(2);
++
++#ifndef CONFIG_BOARD_ATSTK100X_SW1_CUSTOM
++	at32_add_device_spi(0, spi0_board_info, ARRAY_SIZE(spi0_board_info));
++#endif
++#ifdef CONFIG_BOARD_ATSTK100X_SPI1
++	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);
++#endif
++	at32_add_device_usba(0, NULL);
++#ifndef CONFIG_BOARD_ATSTK100X_SW3_CUSTOM
++	at32_add_device_ssc(0, ATMEL_SSC_TX);
++#endif
++
++	atstk1000_setup_j2_leds();
++	atstk1003_setup_extdac();
++
++	return 0;
++}
++postcore_initcall(atstk1003_init);
+diff --git a/arch/avr32/boards/atstk1000/atstk1004.c b/arch/avr32/boards/atstk1000/atstk1004.c
+new file mode 100644
+index 0000000..5a77030
+--- /dev/null
++++ b/arch/avr32/boards/atstk1000/atstk1004.c
+@@ -0,0 +1,147 @@
++/*
++ * ATSTK1003 daughterboard-specific init code
++ *
++ * 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 version 2 as
++ * published by the Free Software Foundation.
++ */
++#include <linux/clk.h>
++#include <linux/err.h>
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/platform_device.h>
++#include <linux/string.h>
++#include <linux/types.h>
++
++#include <linux/spi/at73c213.h>
++#include <linux/spi/spi.h>
++
++#include <video/atmel_lcdc.h>
++
++#include <asm/setup.h>
++
++#include <asm/arch/at32ap700x.h>
++#include <asm/arch/board.h>
++#include <asm/arch/init.h>
++#include <asm/arch/portmux.h>
++
++#include "atstk1000.h"
++
++#ifdef CONFIG_BOARD_ATSTK1000_EXTDAC
++static struct at73c213_board_info at73c213_data = {
++	.ssc_id		= 0,
++	.shortname	= "AVR32 STK1000 external DAC",
++};
++#endif
++
++#ifndef CONFIG_BOARD_ATSTK100X_SW1_CUSTOM
++static struct spi_board_info spi0_board_info[] __initdata = {
++#ifdef CONFIG_BOARD_ATSTK1000_EXTDAC
++	{
++		/* AT73C213 */
++		.modalias	= "at73c213",
++		.max_speed_hz	= 200000,
++		.chip_select	= 0,
++		.mode		= SPI_MODE_1,
++		.platform_data	= &at73c213_data,
++	},
++#endif
++	{
++		/* QVGA display */
++		.modalias	= "ltv350qv",
++		.max_speed_hz	= 16000000,
++		.chip_select	= 1,
++		.mode		= SPI_MODE_3,
++	},
++};
++#endif
++
++#ifdef CONFIG_BOARD_ATSTK100X_SPI1
++static struct spi_board_info spi1_board_info[] __initdata = { {
++	/* patch in custom entries here */
++} };
++#endif
++
++#ifdef CONFIG_BOARD_ATSTK1000_EXTDAC
++static void __init atstk1004_setup_extdac(void)
++{
++	struct clk *gclk;
++	struct clk *pll;
++
++	gclk = clk_get(NULL, "gclk0");
++	if (IS_ERR(gclk))
++		goto err_gclk;
++	pll = clk_get(NULL, "pll0");
++	if (IS_ERR(pll))
++		goto err_pll;
++
++	if (clk_set_parent(gclk, pll)) {
++		pr_debug("STK1000: failed to set pll0 as parent for DAC clock\n");
++		goto err_set_clk;
++	}
++
++	at32_select_periph(GPIO_PIN_PA(30), GPIO_PERIPH_A, 0);
++	at73c213_data.dac_clk = gclk;
++
++err_set_clk:
++	clk_put(pll);
++err_pll:
++	clk_put(gclk);
++err_gclk:
++	return;
++}
++#else
++static void __init atstk1004_setup_extdac(void)
++{
++
++}
++#endif /* CONFIG_BOARD_ATSTK1000_EXTDAC */
++
++void __init setup_board(void)
++{
++#ifdef	CONFIG_BOARD_ATSTK100X_SW2_CUSTOM
++	at32_map_usart(0, 1);	/* USART 0/B: /dev/ttyS1, IRDA */
++#else
++	at32_map_usart(1, 0);	/* USART 1/A: /dev/ttyS0, DB9 */
++#endif
++	/* USART 2/unused: expansion connector */
++	at32_map_usart(3, 2);	/* USART 3/C: /dev/ttyS2, DB9 */
++
++	at32_setup_serial_console(0);
++}
++
++static int __init atstk1004_init(void)
++{
++	at32_add_system_devices();
++
++#ifdef	CONFIG_BOARD_ATSTK100X_SW2_CUSTOM
++	at32_add_device_usart(1);
++#else
++	at32_add_device_usart(0);
++#endif
++	at32_add_device_usart(2);
++
++#ifndef CONFIG_BOARD_ATSTK100X_SW1_CUSTOM
++	at32_add_device_spi(0, spi0_board_info, ARRAY_SIZE(spi0_board_info));
++#endif
++#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);
++#endif
++	at32_add_device_lcdc(0, &atstk1000_lcdc_data,
++			     fbmem_start, fbmem_size);
++	at32_add_device_usba(0, NULL);
++#ifndef CONFIG_BOARD_ATSTK100X_SW3_CUSTOM
++	at32_add_device_ssc(0, ATMEL_SSC_TX);
++#endif
++
++	atstk1000_setup_j2_leds();
++	atstk1004_setup_extdac();
++
++	return 0;
++}
++postcore_initcall(atstk1004_init);
+diff --git a/arch/avr32/boards/atstk1000/setup.c b/arch/avr32/boards/atstk1000/setup.c
+index c9af409..8bedf93 100644
+--- a/arch/avr32/boards/atstk1000/setup.c
++++ b/arch/avr32/boards/atstk1000/setup.c
+@@ -10,13 +10,17 @@
+ #include <linux/bootmem.h>
+ #include <linux/fb.h>
+ #include <linux/init.h>
++#include <linux/platform_device.h>
+ #include <linux/types.h>
+ #include <linux/linkage.h>
+ 
+ #include <video/atmel_lcdc.h>
+ 
+ #include <asm/setup.h>
++
++#include <asm/arch/at32ap700x.h>
+ #include <asm/arch/board.h>
++#include <asm/arch/portmux.h>
+ 
+ #include "atstk1000.h"
+ 
+@@ -61,3 +65,63 @@ struct atmel_lcdfb_info __initdata atstk1000_lcdc_data = {
+ 	.default_monspecs	= &atstk1000_default_monspecs,
+ 	.guard_time		= 2,
+ };
++
++#ifdef CONFIG_BOARD_ATSTK1000_J2_LED
++#include <linux/leds.h>
++
++static struct gpio_led stk1000_j2_led[] = {
++#ifdef CONFIG_BOARD_ATSTK1000_J2_LED8
++#define LEDSTRING "J2 jumpered to LED8"
++	{ .name = "led0:amber", .gpio = GPIO_PIN_PB( 8), },
++	{ .name = "led1:amber", .gpio = GPIO_PIN_PB( 9), },
++	{ .name = "led2:amber", .gpio = GPIO_PIN_PB(10), },
++	{ .name = "led3:amber", .gpio = GPIO_PIN_PB(13), },
++	{ .name = "led4:amber", .gpio = GPIO_PIN_PB(14), },
++	{ .name = "led5:amber", .gpio = GPIO_PIN_PB(15), },
++	{ .name = "led6:amber", .gpio = GPIO_PIN_PB(16), },
++	{ .name = "led7:amber", .gpio = GPIO_PIN_PB(30),
++			.default_trigger = "heartbeat", },
++#else	/* RGB */
++#define LEDSTRING "J2 jumpered to RGB LEDs"
++	{ .name = "r1:red",     .gpio = GPIO_PIN_PB( 8), },
++	{ .name = "g1:green",   .gpio = GPIO_PIN_PB(10), },
++	{ .name = "b1:blue",    .gpio = GPIO_PIN_PB(14), },
++
++	{ .name = "r2:red",     .gpio = GPIO_PIN_PB( 9),
++			.default_trigger = "heartbeat", },
++	{ .name = "g2:green",   .gpio = GPIO_PIN_PB(13), },
++	{ .name = "b2:blue",    .gpio = GPIO_PIN_PB(15),
++			.default_trigger = "heartbeat", },
++	/* PB16, PB30 unused */
++#endif
++};
++
++static struct gpio_led_platform_data stk1000_j2_led_data = {
++	.num_leds	= ARRAY_SIZE(stk1000_j2_led),
++	.leds		= stk1000_j2_led,
++};
++
++static struct platform_device stk1000_j2_led_dev = {
++	.name		= "leds-gpio",
++	.id		= 2,	/* gpio block J2 */
++	.dev		= {
++		.platform_data	= &stk1000_j2_led_data,
++	},
++};
++
++void __init atstk1000_setup_j2_leds(void)
++{
++	unsigned	i;
++
++	for (i = 0; i < ARRAY_SIZE(stk1000_j2_led); i++)
++		at32_select_gpio(stk1000_j2_led[i].gpio, AT32_GPIOF_OUTPUT);
++
++	printk("STK1000: " LEDSTRING "\n");
++	platform_device_register(&stk1000_j2_led_dev);
++}
++#else /* CONFIG_BOARD_ATSTK1000_J2_LED */
++void __init atstk1000_setup_j2_leds(void)
++{
++
++}
++#endif /* CONFIG_BOARD_ATSTK1000_J2_LED */
+diff --git a/arch/avr32/configs/atngw100_defconfig b/arch/avr32/configs/atngw100_defconfig
+index b799a68..0604607 100644
+--- a/arch/avr32/configs/atngw100_defconfig
++++ b/arch/avr32/configs/atngw100_defconfig
+@@ -1,46 +1,51 @@
+ #
+ # Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.22-rc5
+-# Sat Jun 23 15:40:05 2007
++# Linux kernel version: 2.6.24-rc7
++# Wed Jan  9 23:20:41 2008
+ #
+ CONFIG_AVR32=y
+ CONFIG_GENERIC_GPIO=y
+ 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_GENERIC_TIME=y
++# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+ # CONFIG_ARCH_HAS_ILOG2_U32 is not set
+ # CONFIG_ARCH_HAS_ILOG2_U64 is not set
++CONFIG_ARCH_SUPPORTS_OPROFILE=y
+ CONFIG_GENERIC_HWEIGHT=y
+ CONFIG_GENERIC_CALIBRATE_DELAY=y
+ CONFIG_GENERIC_BUG=y
+ CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+ 
+ #
+-# Code maturity level options
++# General setup
+ #
+ CONFIG_EXPERIMENTAL=y
+ CONFIG_BROKEN_ON_SMP=y
+ CONFIG_INIT_ENV_ARG_LIMIT=32
+-
+-#
+-# General setup
+-#
+ CONFIG_LOCALVERSION=""
+ # CONFIG_LOCALVERSION_AUTO is not set
+ CONFIG_SWAP=y
+ CONFIG_SYSVIPC=y
+-# CONFIG_IPC_NS is not set
+ CONFIG_SYSVIPC_SYSCTL=y
+ CONFIG_POSIX_MQUEUE=y
+ CONFIG_BSD_PROCESS_ACCT=y
+ CONFIG_BSD_PROCESS_ACCT_V3=y
+ # CONFIG_TASKSTATS is not set
+-# CONFIG_UTS_NS is not set
++# CONFIG_USER_NS is not set
++# CONFIG_PID_NS is not set
+ # CONFIG_AUDIT is not set
+ # CONFIG_IKCONFIG is not set
+ CONFIG_LOG_BUF_SHIFT=14
++# CONFIG_CGROUPS is not set
++CONFIG_FAIR_GROUP_SCHED=y
++CONFIG_FAIR_USER_SCHED=y
++# CONFIG_FAIR_CGROUP_SCHED is not set
+ CONFIG_SYSFS_DEPRECATED=y
+ # CONFIG_RELAY is not set
+ CONFIG_BLK_DEV_INITRD=y
+@@ -61,35 +66,28 @@ 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 is not set
++CONFIG_SLUB_DEBUG=y
+ # CONFIG_SLAB is not set
+ CONFIG_SLUB=y
+ # CONFIG_SLOB is not set
++CONFIG_SLABINFO=y
+ CONFIG_RT_MUTEXES=y
+ # CONFIG_TINY_SHMEM is not set
+ CONFIG_BASE_SMALL=1
+-
+-#
+-# Loadable module support
+-#
+ CONFIG_MODULES=y
+ CONFIG_MODULE_UNLOAD=y
+ CONFIG_MODULE_FORCE_UNLOAD=y
+ # CONFIG_MODVERSIONS is not set
+ # CONFIG_MODULE_SRCVERSION_ALL is not set
+ CONFIG_KMOD=y
+-
+-#
+-# Block layer
+-#
+ 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
+@@ -111,6 +109,7 @@ CONFIG_SUBARCH_AVR32B=y
+ CONFIG_MMU=y
+ CONFIG_PERFORMANCE_COUNTERS=y
+ CONFIG_PLATFORM_AT32AP=y
++CONFIG_CPU_AT32AP700X=y
+ CONFIG_CPU_AT32AP7000=y
+ # CONFIG_BOARD_ATSTK1000 is not set
+ CONFIG_BOARD_ATNGW100=y
+@@ -119,9 +118,9 @@ CONFIG_LOADER_U_BOOT=y
+ #
+ # Atmel AVR32 AP options
+ #
+-# CONFIG_AP7000_32_BIT_SMC is not set
+-CONFIG_AP7000_16_BIT_SMC=y
+-# CONFIG_AP7000_8_BIT_SMC is not set
++# CONFIG_AP700X_32_BIT_SMC is not set
++CONFIG_AP700X_16_BIT_SMC=y
++# CONFIG_AP700X_8_BIT_SMC is not set
+ CONFIG_LOAD_ADDRESS=0x10000000
+ CONFIG_ENTRY_ADDRESS=0x90000000
+ CONFIG_PHYS_OFFSET=0x10000000
+@@ -141,9 +140,11 @@ CONFIG_FLATMEM_MANUAL=y
+ CONFIG_FLATMEM=y
+ CONFIG_FLAT_NODE_MEM_MAP=y
+ # CONFIG_SPARSEMEM_STATIC is not set
++# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
+ CONFIG_SPLIT_PTLOCK_CPUS=4
+ # CONFIG_RESOURCES_64BIT is not set
+ CONFIG_ZONE_DMA_FLAG=0
++CONFIG_VIRT_TO_BUS=y
+ # CONFIG_OWNERSHIP_TRACE is not set
+ # CONFIG_HZ_100 is not set
+ CONFIG_HZ_250=y
+@@ -153,13 +154,31 @@ CONFIG_HZ=250
+ CONFIG_CMDLINE=""
+ 
+ #
+-# Bus options
++# Power management options
+ #
+-# CONFIG_ARCH_SUPPORTS_MSI is not set
+ 
+ #
+-# PCCARD (PCMCIA/CardBus) support
++# CPU Frequency scaling
+ #
++CONFIG_CPU_FREQ=y
++CONFIG_CPU_FREQ_TABLE=y
++# CONFIG_CPU_FREQ_DEBUG is not set
++# CONFIG_CPU_FREQ_STAT is not set
++CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
++# 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=y
++# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
++CONFIG_CPU_FREQ_AT32AP=y
++
++#
++# Bus options
++#
++# CONFIG_ARCH_SUPPORTS_MSI is not set
+ # CONFIG_PCCARD is not set
+ 
+ #
+@@ -213,6 +232,7 @@ CONFIG_INET_TUNNEL=y
+ 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
+@@ -240,6 +260,7 @@ CONFIG_IPV6_SIT=y
+ # CONFIG_NETWORK_SECMARK is not set
+ CONFIG_NETFILTER=y
+ # CONFIG_NETFILTER_DEBUG is not set
++CONFIG_BRIDGE_NETFILTER=y
+ 
+ #
+ # Core Netfilter Configuration
+@@ -252,6 +273,7 @@ CONFIG_NF_CONNTRACK_MARK=y
+ # CONFIG_NF_CONNTRACK_EVENTS is not set
+ CONFIG_NF_CT_PROTO_GRE=m
+ # CONFIG_NF_CT_PROTO_SCTP is not set
++# CONFIG_NF_CT_PROTO_UDPLITE is not set
+ CONFIG_NF_CONNTRACK_AMANDA=m
+ CONFIG_NF_CONNTRACK_FTP=m
+ CONFIG_NF_CONNTRACK_H323=m
+@@ -269,9 +291,11 @@ CONFIG_NETFILTER_XT_TARGET_MARK=m
+ CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
+ CONFIG_NETFILTER_XT_TARGET_NFLOG=m
+ # CONFIG_NETFILTER_XT_TARGET_NOTRACK is not set
++# CONFIG_NETFILTER_XT_TARGET_TRACE is not set
+ CONFIG_NETFILTER_XT_TARGET_TCPMSS=m
+ CONFIG_NETFILTER_XT_MATCH_COMMENT=m
+ CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m
++# CONFIG_NETFILTER_XT_MATCH_CONNLIMIT is not set
+ CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
+ CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
+ # CONFIG_NETFILTER_XT_MATCH_DCCP is not set
+@@ -284,6 +308,7 @@ CONFIG_NETFILTER_XT_MATCH_MAC=m
+ CONFIG_NETFILTER_XT_MATCH_MARK=m
+ CONFIG_NETFILTER_XT_MATCH_POLICY=m
+ CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m
++# CONFIG_NETFILTER_XT_MATCH_PHYSDEV is not set
+ CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
+ CONFIG_NETFILTER_XT_MATCH_QUOTA=m
+ CONFIG_NETFILTER_XT_MATCH_REALM=m
+@@ -292,6 +317,8 @@ CONFIG_NETFILTER_XT_MATCH_STATE=m
+ CONFIG_NETFILTER_XT_MATCH_STATISTIC=m
+ CONFIG_NETFILTER_XT_MATCH_STRING=m
+ CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
++# CONFIG_NETFILTER_XT_MATCH_TIME is not set
++# CONFIG_NETFILTER_XT_MATCH_U32 is not set
+ CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
+ 
+ #
+@@ -359,13 +386,19 @@ CONFIG_IP6_NF_TARGET_REJECT=m
+ CONFIG_IP6_NF_MANGLE=m
+ CONFIG_IP6_NF_TARGET_HL=m
+ CONFIG_IP6_NF_RAW=m
++
++#
++# Bridge: Netfilter Configuration
++#
++# CONFIG_BRIDGE_NF_EBTABLES 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_BRIDGE=m
+ CONFIG_VLAN_8021Q=m
+ # CONFIG_DECNET is not set
++CONFIG_LLC=m
+ # CONFIG_LLC2 is not set
+ # CONFIG_IPX is not set
+ # CONFIG_ATALK is not set
+@@ -373,10 +406,6 @@ CONFIG_VLAN_8021Q=m
+ # CONFIG_LAPB is not set
+ # CONFIG_ECONET is not set
+ # CONFIG_WAN_ROUTER is not set
+-
+-#
+-# QoS and/or fair queueing
+-#
+ # CONFIG_NET_SCHED is not set
+ CONFIG_NET_CLS_ROUTE=y
+ 
+@@ -384,6 +413,7 @@ CONFIG_NET_CLS_ROUTE=y
+ # Network testing
+ #
+ # CONFIG_NET_PKTGEN is not set
++# CONFIG_NET_TCPPROBE is not set
+ # CONFIG_HAMRADIO is not set
+ # CONFIG_IRDA is not set
+ # CONFIG_BT is not set
+@@ -397,6 +427,7 @@ CONFIG_NET_CLS_ROUTE=y
+ # CONFIG_MAC80211 is not set
+ # CONFIG_IEEE80211 is not set
+ # CONFIG_RFKILL is not set
++# CONFIG_NET_9P is not set
+ 
+ #
+ # Device Drivers
+@@ -405,16 +436,13 @@ CONFIG_NET_CLS_ROUTE=y
+ #
+ # Generic Driver Options
+ #
++CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+ CONFIG_STANDALONE=y
+ # CONFIG_PREVENT_FIRMWARE_BUILD is not set
+ # CONFIG_FW_LOADER is not set
+ # CONFIG_DEBUG_DRIVER is not set
+ # CONFIG_DEBUG_DEVRES is not set
+ # CONFIG_SYS_HYPERVISOR is not set
+-
+-#
+-# Connector - unified userspace <-> kernelspace linker
+-#
+ # CONFIG_CONNECTOR is not set
+ CONFIG_MTD=y
+ # CONFIG_MTD_DEBUG is not set
+@@ -434,6 +462,7 @@ CONFIG_MTD_BLOCK=y
+ # 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
+@@ -493,20 +522,8 @@ CONFIG_MTD_DATAFLASH=y
+ # UBI - Unsorted block images
+ #
+ # CONFIG_MTD_UBI is not set
+-
+-#
+-# Parallel port support
+-#
+ # CONFIG_PARPORT is not set
+-
+-#
+-# Plug and Play support
+-#
+-# CONFIG_PNPACPI is not set
+-
+-#
+-# Block devices
+-#
++CONFIG_BLK_DEV=y
+ # CONFIG_BLK_DEV_COW_COMMON is not set
+ CONFIG_BLK_DEV_LOOP=m
+ # CONFIG_BLK_DEV_CRYPTOLOOP is not set
+@@ -517,11 +534,7 @@ CONFIG_BLK_DEV_RAM_SIZE=4096
+ CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+ # CONFIG_CDROM_PKTCDVD is not set
+ # CONFIG_ATA_OVER_ETH is not set
+-
+-#
+-# Misc devices
+-#
+-# CONFIG_BLINK is not set
++# CONFIG_MISC_DEVICES is not set
+ # CONFIG_IDE is not set
+ 
+ #
+@@ -529,30 +542,42 @@ CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+ #
+ # 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
+-
+-#
+-# Multi-device support (RAID and LVM)
+-#
+ # CONFIG_MD is not set
+-
+-#
+-# Network device support
+-#
+ 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=m
+-# CONFIG_PHYLIB is not set
+-
+-#
+-# Ethernet (10 or 100Mbit)
+-#
++# 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_FIXED_PHY is not set
++# CONFIG_MDIO_BITBANG is not set
+ CONFIG_NET_ETHERNET=y
+-CONFIG_MII=y
++# CONFIG_MII is not set
+ CONFIG_MACB=y
++# 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
+ 
+@@ -571,21 +596,14 @@ CONFIG_PPP_DEFLATE=m
+ CONFIG_PPP_BSDCOMP=m
+ CONFIG_PPP_MPPE=m
+ CONFIG_PPPOE=m
++# CONFIG_PPPOL2TP is not set
+ # CONFIG_SLIP is not set
+ CONFIG_SLHC=m
+ # CONFIG_SHAPER is not set
+ # CONFIG_NETCONSOLE is not set
+ # CONFIG_NETPOLL is not set
+ # CONFIG_NET_POLL_CONTROLLER is not set
+-
+-#
+-# ISDN subsystem
+-#
+ # CONFIG_ISDN is not set
+-
+-#
+-# Telephony Support
+-#
+ # CONFIG_PHONE is not set
+ 
+ #
+@@ -620,23 +638,50 @@ CONFIG_SERIAL_CORE=y
+ CONFIG_SERIAL_CORE_CONSOLE=y
+ CONFIG_UNIX98_PTYS=y
+ # CONFIG_LEGACY_PTYS is not set
+-
+-#
+-# IPMI
+-#
+ # CONFIG_IPMI_HANDLER is not set
+-# CONFIG_WATCHDOG is not set
+ # CONFIG_HW_RANDOM is not set
+ # CONFIG_RTC is not set
+ # CONFIG_GEN_RTC is not set
+ # CONFIG_R3964 is not set
+ # CONFIG_RAW_DRIVER is not set
++# CONFIG_TCG_TPM is not set
++CONFIG_I2C=m
++CONFIG_I2C_BOARDINFO=y
++CONFIG_I2C_CHARDEV=m
+ 
+ #
+-# TPM devices
++# I2C Algorithms
+ #
+-# CONFIG_TCG_TPM is not set
+-# CONFIG_I2C is not set
++CONFIG_I2C_ALGOBIT=m
++# CONFIG_I2C_ALGOPCF is not set
++# CONFIG_I2C_ALGOPCA is not set
++
++#
++# I2C Hardware Bus support
++#
++CONFIG_I2C_GPIO=m
++# 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
++
++#
++# Miscellaneous I2C Chip support
++#
++# CONFIG_SENSORS_DS1337 is not set
++# CONFIG_SENSORS_DS1374 is not set
++# CONFIG_DS1682 is not set
++# CONFIG_SENSORS_EEPROM is not set
++# CONFIG_SENSORS_PCF8574 is not set
++# CONFIG_SENSORS_PCA9539 is not set
++# CONFIG_SENSORS_PCF8591 is not set
++# CONFIG_SENSORS_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
+ 
+ #
+ # SPI support
+@@ -655,13 +700,25 @@ CONFIG_SPI_ATMEL=y
+ # SPI Protocol Masters
+ #
+ # CONFIG_SPI_AT25 is not set
+-# CONFIG_SPI_SPIDEV is not set
++CONFIG_SPI_SPIDEV=m
++# 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 is not set
+ 
+ #
+-# Dallas's 1-wire bus
++# Watchdog Device Drivers
+ #
+-# CONFIG_W1 is not set
+-# CONFIG_HWMON is not set
++# CONFIG_SOFT_WATCHDOG is not set
++CONFIG_AT32AP700X_WDT=y
++
++#
++# Sonics Silicon Backplane
++#
++CONFIG_SSB_POSSIBLE=y
++# CONFIG_SSB is not set
+ 
+ #
+ # Multifunction device drivers
+@@ -678,23 +735,21 @@ CONFIG_SPI_ATMEL=y
+ #
+ # 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
+-# CONFIG_VGASTATE is not set
+-# CONFIG_FB is not set
+ 
+ #
+ # Sound
+ #
+ # CONFIG_SOUND is not set
+-
+-#
+-# USB support
+-#
++CONFIG_USB_SUPPORT=y
+ # CONFIG_USB_ARCH_HAS_HCD is not set
+ # CONFIG_USB_ARCH_HAS_OHCI is not set
+ # CONFIG_USB_ARCH_HAS_EHCI is not set
+@@ -706,12 +761,47 @@ CONFIG_SPI_ATMEL=y
+ #
+ # USB Gadget Support
+ #
+-# CONFIG_USB_GADGET is not set
+-# CONFIG_MMC is not set
+-
+-#
+-# LED devices
+-#
++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=y
++CONFIG_USB_ATMEL_USBA=y
++# CONFIG_USB_GADGET_FSL_USB2 is not set
++# CONFIG_USB_GADGET_NET2280 is not set
++# CONFIG_USB_GADGET_PXA2XX is not set
++# CONFIG_USB_GADGET_M66592 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=y
++CONFIG_USB_ZERO=m
++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_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_SPI=m
+ CONFIG_NEW_LEDS=y
+ CONFIG_LEDS_CLASS=y
+ 
+@@ -726,53 +816,71 @@ CONFIG_LEDS_GPIO=y
+ CONFIG_LEDS_TRIGGERS=y
+ CONFIG_LEDS_TRIGGER_TIMER=y
+ CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+-
+-
+-#
+-# LED drivers
+-#
++CONFIG_RTC_LIB=y
++CONFIG_RTC_CLASS=y
++CONFIG_RTC_HCTOSYS=y
++CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
++# CONFIG_RTC_DEBUG is not set
+ 
+ #
+-# LED Triggers
+-#
+-
+-#
+-# InfiniBand support
++# 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
+ 
+ #
+-# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
++# 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
+ 
+ #
+-# Real Time Clock
++# SPI RTC drivers
+ #
+-# CONFIG_RTC_CLASS is not set
++# CONFIG_RTC_DRV_RS5C348 is not set
++# CONFIG_RTC_DRV_MAX6902 is not set
+ 
+ #
+-# DMA Engine support
++# Platform RTC drivers
+ #
+-# CONFIG_DMA_ENGINE is not set
++# CONFIG_RTC_DRV_DS1553 is not set
++# CONFIG_RTC_DRV_STK17TA8 is not set
++# CONFIG_RTC_DRV_DS1742 is not set
++# CONFIG_RTC_DRV_M48T86 is not set
++# CONFIG_RTC_DRV_M48T59 is not set
++# CONFIG_RTC_DRV_V3020 is not set
+ 
+ #
+-# DMA Clients
++# on-CPU RTC drivers
+ #
++CONFIG_RTC_DRV_AT32AP700X=y
+ 
+ #
+-# DMA Devices
++# Userspace I/O
+ #
++# CONFIG_UIO is not set
+ 
+ #
+ # File systems
+ #
+-CONFIG_EXT2_FS=y
++CONFIG_EXT2_FS=m
+ # CONFIG_EXT2_FS_XATTR is not set
+ # CONFIG_EXT2_FS_XIP is not set
+-CONFIG_EXT3_FS=y
++CONFIG_EXT3_FS=m
+ # CONFIG_EXT3_FS_XATTR is not set
+ # CONFIG_EXT4DEV_FS is not set
+-CONFIG_JBD=y
+-# CONFIG_JBD_DEBUG 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
+@@ -781,7 +889,8 @@ CONFIG_JBD=y
+ # CONFIG_OCFS2_FS is not set
+ # CONFIG_MINIX_FS is not set
+ # CONFIG_ROMFS_FS is not set
+-# CONFIG_INOTIFY is not set
++CONFIG_INOTIFY=y
++CONFIG_INOTIFY_USER=y
+ # CONFIG_QUOTA is not set
+ # CONFIG_DNOTIFY is not set
+ # CONFIG_AUTOFS_FS is not set
+@@ -814,8 +923,7 @@ CONFIG_SYSFS=y
+ CONFIG_TMPFS=y
+ # CONFIG_TMPFS_POSIX_ACL is not set
+ # CONFIG_HUGETLB_PAGE is not set
+-CONFIG_RAMFS=y
+-CONFIG_CONFIGFS_FS=y
++CONFIG_CONFIGFS_FS=m
+ 
+ #
+ # Miscellaneous filesystems
+@@ -830,10 +938,12 @@ CONFIG_CONFIGFS_FS=y
+ 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
+@@ -842,19 +952,21 @@ CONFIG_JFFS2_RTIME=y
+ # CONFIG_QNX4FS_FS is not set
+ # CONFIG_SYSV_FS is not set
+ # CONFIG_UFS_FS is not set
+-
+-#
+-# Network File Systems
+-#
++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_NFS_DIRECTIO is not set
+-# CONFIG_NFSD is not set
++CONFIG_NFSD=m
++CONFIG_NFSD_V3=y
++# CONFIG_NFSD_V3_ACL is not set
++# CONFIG_NFSD_V4 is not set
++CONFIG_NFSD_TCP=y
+ CONFIG_ROOT_NFS=y
+ CONFIG_LOCKD=y
+ CONFIG_LOCKD_V4=y
++CONFIG_EXPORTFS=m
+ CONFIG_NFS_COMMON=y
+ CONFIG_SUNRPC=y
+ # CONFIG_SUNRPC_BIND34 is not set
+@@ -871,23 +983,18 @@ CONFIG_CIFS=m
+ # CONFIG_NCP_FS is not set
+ # CONFIG_CODA_FS is not set
+ # CONFIG_AFS_FS is not set
+-# CONFIG_9P_FS is not set
+ 
+ #
+ # Partition Types
+ #
+ # CONFIG_PARTITION_ADVANCED is not set
+ CONFIG_MSDOS_PARTITION=y
+-
+-#
+-# Native Language Support
+-#
+-CONFIG_NLS=y
++CONFIG_NLS=m
+ CONFIG_NLS_DEFAULT="iso8859-1"
+-# CONFIG_NLS_CODEPAGE_437 is not set
++CONFIG_NLS_CODEPAGE_437=m
+ # CONFIG_NLS_CODEPAGE_737 is not set
+ # CONFIG_NLS_CODEPAGE_775 is not set
+-CONFIG_NLS_CODEPAGE_850=y
++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
+@@ -908,7 +1015,7 @@ CONFIG_NLS_CODEPAGE_850=y
+ # 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_1=m
+ # CONFIG_NLS_ISO8859_2 is not set
+ # CONFIG_NLS_ISO8859_3 is not set
+ # CONFIG_NLS_ISO8859_4 is not set
+@@ -921,18 +1028,19 @@ CONFIG_NLS_ISO8859_1=y
+ # 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
+-
+-#
+-# Distributed Lock Manager
+-#
++CONFIG_NLS_UTF8=m
+ # CONFIG_DLM is not set
++CONFIG_INSTRUMENTATION=y
++CONFIG_PROFILING=y
++CONFIG_OPROFILE=m
++CONFIG_KPROBES=y
++# CONFIG_MARKERS is not set
+ 
+ #
+ # Kernel hacking
+ #
+-CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+ # CONFIG_PRINTK_TIME is not set
++CONFIG_ENABLE_WARN_DEPRECATED=y
+ CONFIG_ENABLE_MUST_CHECK=y
+ CONFIG_MAGIC_SYSRQ=y
+ # CONFIG_UNUSED_SYMBOLS is not set
+@@ -941,12 +1049,17 @@ CONFIG_MAGIC_SYSRQ=y
+ CONFIG_DEBUG_KERNEL=y
+ # CONFIG_DEBUG_SHIRQ is not set
+ CONFIG_DETECT_SOFTLOCKUP=y
++CONFIG_SCHED_DEBUG=y
+ # CONFIG_SCHEDSTATS is not set
+ # CONFIG_TIMER_STATS is not set
++# CONFIG_SLUB_DEBUG_ON 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
+@@ -954,21 +1067,21 @@ CONFIG_DEBUG_BUGVERBOSE=y
+ # CONFIG_DEBUG_INFO is not set
+ # CONFIG_DEBUG_VM is not set
+ # CONFIG_DEBUG_LIST is not set
++# CONFIG_DEBUG_SG is not set
+ CONFIG_FRAME_POINTER=y
+ # CONFIG_FORCED_INLINING is not set
++# CONFIG_BOOT_PRINTK_DELAY is not set
+ # CONFIG_RCU_TORTURE_TEST is not set
++# CONFIG_LKDTM is not set
+ # CONFIG_FAULT_INJECTION is not set
+-# CONFIG_KPROBES is not set
++# CONFIG_SAMPLES is not set
+ 
+ #
+ # Security options
+ #
+ # CONFIG_KEYS is not set
+ # CONFIG_SECURITY is not set
+-
+-#
+-# Cryptographic options
+-#
++# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+ CONFIG_CRYPTO=y
+ CONFIG_CRYPTO_ALGAPI=y
+ CONFIG_CRYPTO_BLKCIPHER=y
+@@ -989,6 +1102,7 @@ CONFIG_CRYPTO_ECB=m
+ CONFIG_CRYPTO_CBC=y
+ CONFIG_CRYPTO_PCBC=m
+ # CONFIG_CRYPTO_LRW is not set
++# CONFIG_CRYPTO_XTS is not set
+ # CONFIG_CRYPTO_CRYPTD is not set
+ CONFIG_CRYPTO_DES=y
+ # CONFIG_CRYPTO_FCRYPT is not set
+@@ -1002,15 +1116,14 @@ CONFIG_CRYPTO_DES=y
+ CONFIG_CRYPTO_ARC4=m
+ # CONFIG_CRYPTO_KHAZAD is not set
+ # CONFIG_CRYPTO_ANUBIS is not set
++# CONFIG_CRYPTO_SEED is not set
+ CONFIG_CRYPTO_DEFLATE=y
+ # CONFIG_CRYPTO_MICHAEL_MIC is not set
+ # CONFIG_CRYPTO_CRC32C is not set
+ # CONFIG_CRYPTO_CAMELLIA is not set
+ # CONFIG_CRYPTO_TEST is not set
+-
+-#
+-# Hardware crypto devices
+-#
++# CONFIG_CRYPTO_AUTHENC is not set
++CONFIG_CRYPTO_HW=y
+ 
+ #
+ # Library routines
+@@ -1018,8 +1131,9 @@ CONFIG_CRYPTO_DEFLATE=y
+ CONFIG_BITREVERSE=y
+ CONFIG_CRC_CCITT=m
+ # CONFIG_CRC16 is not set
+-# CONFIG_CRC_ITU_T is not set
++CONFIG_CRC_ITU_T=m
+ CONFIG_CRC32=y
++CONFIG_CRC7=m
+ # CONFIG_LIBCRC32C is not set
+ CONFIG_ZLIB_INFLATE=y
+ CONFIG_ZLIB_DEFLATE=y
+diff --git a/arch/avr32/configs/atstk1002_defconfig b/arch/avr32/configs/atstk1002_defconfig
+index 3b977fd..2fb2ede 100644
+--- a/arch/avr32/configs/atstk1002_defconfig
++++ b/arch/avr32/configs/atstk1002_defconfig
+@@ -1,48 +1,48 @@
+ #
+ # Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.22-rc5
+-# Sat Jun 23 15:32:08 2007
++# Linux kernel version: 2.6.24-rc7
++# Wed Jan  9 23:07:43 2008
+ #
+ CONFIG_AVR32=y
+ CONFIG_GENERIC_GPIO=y
+ 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_GENERIC_TIME=y
++# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+ # CONFIG_ARCH_HAS_ILOG2_U32 is not set
+ # CONFIG_ARCH_HAS_ILOG2_U64 is not set
++CONFIG_ARCH_SUPPORTS_OPROFILE=y
+ CONFIG_GENERIC_HWEIGHT=y
+ CONFIG_GENERIC_CALIBRATE_DELAY=y
+ CONFIG_GENERIC_BUG=y
+ CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+ 
+ #
+-# Code maturity level options
++# General setup
+ #
+ CONFIG_EXPERIMENTAL=y
+ CONFIG_BROKEN_ON_SMP=y
+ CONFIG_INIT_ENV_ARG_LIMIT=32
+-
+-#
+-# General setup
+-#
+ CONFIG_LOCALVERSION=""
+ # CONFIG_LOCALVERSION_AUTO is not set
+ CONFIG_SWAP=y
+ CONFIG_SYSVIPC=y
+-# CONFIG_IPC_NS is not set
+ CONFIG_SYSVIPC_SYSCTL=y
+ CONFIG_POSIX_MQUEUE=y
+-CONFIG_BSD_PROCESS_ACCT=y
+-CONFIG_BSD_PROCESS_ACCT_V3=y
+-CONFIG_TASKSTATS=y
+-CONFIG_TASK_DELAY_ACCT=y
+-# CONFIG_TASK_XACCT is not set
+-# CONFIG_UTS_NS is not set
+-CONFIG_AUDIT=y
++# CONFIG_BSD_PROCESS_ACCT is not set
++# CONFIG_TASKSTATS is not set
++# CONFIG_USER_NS is not set
++# CONFIG_PID_NS is not set
++# CONFIG_AUDIT is not set
+ # CONFIG_IKCONFIG is not set
+ CONFIG_LOG_BUF_SHIFT=14
++# CONFIG_CGROUPS is not set
++# CONFIG_FAIR_GROUP_SCHED is not set
+ CONFIG_SYSFS_DEPRECATED=y
+ CONFIG_RELAY=y
+ CONFIG_BLK_DEV_INITRD=y
+@@ -63,35 +63,28 @@ 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 is not set
++CONFIG_SLUB_DEBUG=y
+ # CONFIG_SLAB is not set
+ CONFIG_SLUB=y
+ # CONFIG_SLOB is not set
++CONFIG_SLABINFO=y
+ CONFIG_RT_MUTEXES=y
+ # CONFIG_TINY_SHMEM is not set
+ CONFIG_BASE_SMALL=1
+-
+-#
+-# Loadable module support
+-#
+ CONFIG_MODULES=y
+ CONFIG_MODULE_UNLOAD=y
+ # CONFIG_MODULE_FORCE_UNLOAD is not set
+ # CONFIG_MODVERSIONS is not set
+ # CONFIG_MODULE_SRCVERSION_ALL is not set
+ # CONFIG_KMOD is not set
+-
+-#
+-# Block layer
+-#
+ CONFIG_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
+@@ -99,12 +92,12 @@ CONFIG_BLOCK=y
+ CONFIG_IOSCHED_NOOP=y
+ # CONFIG_IOSCHED_AS is not set
+ # CONFIG_IOSCHED_DEADLINE is not set
+-# CONFIG_IOSCHED_CFQ is not set
++CONFIG_IOSCHED_CFQ=y
+ # 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_DEFAULT_CFQ=y
++# CONFIG_DEFAULT_NOOP is not set
++CONFIG_DEFAULT_IOSCHED="cfq"
+ 
+ #
+ # System Type and features
+@@ -113,18 +106,27 @@ CONFIG_SUBARCH_AVR32B=y
+ CONFIG_MMU=y
+ CONFIG_PERFORMANCE_COUNTERS=y
+ CONFIG_PLATFORM_AT32AP=y
++CONFIG_CPU_AT32AP700X=y
+ CONFIG_CPU_AT32AP7000=y
+-CONFIG_BOARD_ATSTK1002=y
+ CONFIG_BOARD_ATSTK1000=y
+ # CONFIG_BOARD_ATNGW100 is not set
++CONFIG_BOARD_ATSTK1002=y
++# CONFIG_BOARD_ATSTK1003 is not set
++# CONFIG_BOARD_ATSTK1004 is not set
++# CONFIG_BOARD_ATSTK100X_CUSTOM is not set
++# CONFIG_BOARD_ATSTK100X_SPI1 is not set
++# CONFIG_BOARD_ATSTK1000_J2_LED is not set
++# CONFIG_BOARD_ATSTK1000_J2_LED8 is not set
++# CONFIG_BOARD_ATSTK1000_J2_RGB is not set
++CONFIG_BOARD_ATSTK1000_EXTDAC=y
+ CONFIG_LOADER_U_BOOT=y
+ 
+ #
+ # Atmel AVR32 AP options
+ #
+-# CONFIG_AP7000_32_BIT_SMC is not set
+-CONFIG_AP7000_16_BIT_SMC=y
+-# CONFIG_AP7000_8_BIT_SMC is not set
++# CONFIG_AP700X_32_BIT_SMC is not set
++CONFIG_AP700X_16_BIT_SMC=y
++# CONFIG_AP700X_8_BIT_SMC is not set
+ CONFIG_LOAD_ADDRESS=0x10000000
+ CONFIG_ENTRY_ADDRESS=0x90000000
+ CONFIG_PHYS_OFFSET=0x10000000
+@@ -144,9 +146,11 @@ CONFIG_FLATMEM_MANUAL=y
+ CONFIG_FLATMEM=y
+ CONFIG_FLAT_NODE_MEM_MAP=y
+ # CONFIG_SPARSEMEM_STATIC is not set
++# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
+ CONFIG_SPLIT_PTLOCK_CPUS=4
+ # CONFIG_RESOURCES_64BIT is not set
+ CONFIG_ZONE_DMA_FLAG=0
++CONFIG_VIRT_TO_BUS=y
+ # CONFIG_OWNERSHIP_TRACE is not set
+ # CONFIG_HZ_100 is not set
+ CONFIG_HZ_250=y
+@@ -156,13 +160,31 @@ CONFIG_HZ=250
+ CONFIG_CMDLINE=""
+ 
+ #
+-# Bus options
++# Power management options
+ #
+-# CONFIG_ARCH_SUPPORTS_MSI is not set
+ 
+ #
+-# PCCARD (PCMCIA/CardBus) support
++# CPU Frequency scaling
++#
++CONFIG_CPU_FREQ=y
++CONFIG_CPU_FREQ_TABLE=y
++# CONFIG_CPU_FREQ_DEBUG is not set
++# CONFIG_CPU_FREQ_STAT is not set
++CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
++# 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=y
++# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
++CONFIG_CPU_FREQ_AT32AP=y
++
+ #
++# Bus options
++#
++# CONFIG_ARCH_SUPPORTS_MSI is not set
+ # CONFIG_PCCARD is not set
+ 
+ #
+@@ -182,7 +204,12 @@ CONFIG_NET=y
+ CONFIG_PACKET=y
+ CONFIG_PACKET_MMAP=y
+ CONFIG_UNIX=y
+-# CONFIG_NET_KEY is not set
++CONFIG_XFRM=y
++CONFIG_XFRM_USER=m
++# CONFIG_XFRM_SUB_POLICY is not set
++# CONFIG_XFRM_MIGRATE is not set
++CONFIG_NET_KEY=m
++# CONFIG_NET_KEY_MIGRATE is not set
+ CONFIG_INET=y
+ # CONFIG_IP_MULTICAST is not set
+ # CONFIG_IP_ADVANCED_ROUTER is not set
+@@ -191,36 +218,52 @@ 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_NET_IPIP=m
++CONFIG_NET_IPGRE=m
+ # 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_AH=m
++CONFIG_INET_ESP=m
+ # 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_TUNNEL=m
++CONFIG_INET_XFRM_MODE_TRANSPORT=m
++CONFIG_INET_XFRM_MODE_TUNNEL=m
++CONFIG_INET_XFRM_MODE_BEET=m
++# 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_INET6_XFRM_TUNNEL is not set
+-# CONFIG_INET6_TUNNEL is not set
++CONFIG_IPV6=m
++# CONFIG_IPV6_PRIVACY is not set
++# CONFIG_IPV6_ROUTER_PREF is not set
++# CONFIG_IPV6_OPTIMISTIC_DAD is not set
++CONFIG_INET6_AH=m
++CONFIG_INET6_ESP=m
++CONFIG_INET6_IPCOMP=m
++# CONFIG_IPV6_MIP6 is not set
++CONFIG_INET6_XFRM_TUNNEL=m
++CONFIG_INET6_TUNNEL=m
++CONFIG_INET6_XFRM_MODE_TRANSPORT=m
++CONFIG_INET6_XFRM_MODE_TUNNEL=m
++CONFIG_INET6_XFRM_MODE_BEET=m
++# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
++CONFIG_IPV6_SIT=m
++CONFIG_IPV6_TUNNEL=m
++# CONFIG_IPV6_MULTIPLE_TABLES 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_BRIDGE=m
+ # CONFIG_VLAN_8021Q is not set
+ # CONFIG_DECNET is not set
++CONFIG_LLC=m
+ # CONFIG_LLC2 is not set
+ # CONFIG_IPX is not set
+ # CONFIG_ATALK is not set
+@@ -228,16 +271,13 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
+ # CONFIG_LAPB is not set
+ # CONFIG_ECONET is not set
+ # CONFIG_WAN_ROUTER is not set
+-
+-#
+-# QoS and/or fair queueing
+-#
+ # CONFIG_NET_SCHED is not set
+ 
+ #
+ # Network testing
+ #
+ # CONFIG_NET_PKTGEN is not set
++# CONFIG_NET_TCPPROBE is not set
+ # CONFIG_HAMRADIO is not set
+ # CONFIG_IRDA is not set
+ # CONFIG_BT is not set
+@@ -251,6 +291,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
+ # CONFIG_MAC80211 is not set
+ # CONFIG_IEEE80211 is not set
+ # CONFIG_RFKILL is not set
++# CONFIG_NET_9P is not set
+ 
+ #
+ # Device Drivers
+@@ -259,16 +300,13 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
+ #
+ # Generic Driver Options
+ #
++CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+ CONFIG_STANDALONE=y
+ # CONFIG_PREVENT_FIRMWARE_BUILD is not set
+ # CONFIG_FW_LOADER is not set
+ # CONFIG_DEBUG_DRIVER is not set
+ # CONFIG_DEBUG_DEVRES is not set
+ # CONFIG_SYS_HYPERVISOR is not set
+-
+-#
+-# Connector - unified userspace <-> kernelspace linker
+-#
+ # CONFIG_CONNECTOR is not set
+ CONFIG_MTD=y
+ # CONFIG_MTD_DEBUG is not set
+@@ -288,6 +326,7 @@ CONFIG_MTD_BLOCK=y
+ # 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
+@@ -327,6 +366,8 @@ CONFIG_MTD_PHYSMAP_BANKWIDTH=2
+ #
+ # Self-contained MTD device drivers
+ #
++CONFIG_MTD_DATAFLASH=m
++CONFIG_MTD_M25P80=m
+ # CONFIG_MTD_SLRAM is not set
+ # CONFIG_MTD_PHRAM is not set
+ # CONFIG_MTD_MTDRAM is not set
+@@ -345,20 +386,8 @@ CONFIG_MTD_PHYSMAP_BANKWIDTH=2
+ # UBI - Unsorted block images
+ #
+ # CONFIG_MTD_UBI is not set
+-
+-#
+-# Parallel port support
+-#
+ # CONFIG_PARPORT is not set
+-
+-#
+-# Plug and Play support
+-#
+-# CONFIG_PNPACPI is not set
+-
+-#
+-# Block devices
+-#
++CONFIG_BLK_DEV=y
+ # CONFIG_BLK_DEV_COW_COMMON is not set
+ CONFIG_BLK_DEV_LOOP=m
+ # CONFIG_BLK_DEV_CRYPTOLOOP is not set
+@@ -369,42 +398,87 @@ CONFIG_BLK_DEV_RAM_SIZE=4096
+ CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+ # CONFIG_CDROM_PKTCDVD is not set
+ # CONFIG_ATA_OVER_ETH is not set
+-
+-#
+-# Misc devices
+-#
+-# CONFIG_BLINK is not set
++CONFIG_MISC_DEVICES=y
++# CONFIG_EEPROM_93CX6 is not set
++CONFIG_ATMEL_SSC=m
+ # CONFIG_IDE is not set
+ 
+ #
+ # SCSI device support
+ #
+ # CONFIG_RAID_ATTRS is not set
+-# CONFIG_SCSI is not set
++CONFIG_SCSI=m
++CONFIG_SCSI_DMA=y
++# CONFIG_SCSI_TGT is not set
+ # CONFIG_SCSI_NETLINK is not set
+-# CONFIG_ATA is not set
++# CONFIG_SCSI_PROC_FS is not set
+ 
+ #
+-# Multi-device support (RAID and LVM)
++# SCSI support type (disk, tape, CD-ROM)
+ #
+-# CONFIG_MD is not set
++CONFIG_BLK_DEV_SD=m
++# CONFIG_CHR_DEV_ST is not set
++# CONFIG_CHR_DEV_OSST is not set
++CONFIG_BLK_DEV_SR=m
++# CONFIG_BLK_DEV_SR_VENDOR is not set
++# CONFIG_CHR_DEV_SG is not set
++# CONFIG_CHR_DEV_SCH is not set
+ 
+ #
+-# Network device support
++# 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 is not set
++CONFIG_ATA=m
++# CONFIG_ATA_NONSTANDARD is not set
++CONFIG_PATA_AT32=m
++# CONFIG_PATA_PLATFORM is not set
++# CONFIG_MD is not set
+ CONFIG_NETDEVICES=y
+-CONFIG_DUMMY=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=m
+-# CONFIG_PHYLIB is not set
+-
+-#
+-# Ethernet (10 or 100Mbit)
+-#
++# 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_FIXED_PHY is not set
++# CONFIG_MDIO_BITBANG is not set
+ CONFIG_NET_ETHERNET=y
+-CONFIG_MII=y
++# CONFIG_MII is not set
+ CONFIG_MACB=y
++# 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
+ 
+@@ -423,27 +497,54 @@ 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_SHAPER 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
+ 
+ #
+-# ISDN subsystem
++# Input device support
+ #
+-# CONFIG_ISDN is not set
++CONFIG_INPUT=m
++# CONFIG_INPUT_FF_MEMLESS is not set
++CONFIG_INPUT_POLLDEV=m
+ 
+ #
+-# Telephony Support
++# Userland interfaces
+ #
+-# CONFIG_PHONE is not set
++CONFIG_INPUT_MOUSEDEV=m
++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=m
++# CONFIG_INPUT_EVBUG is not set
+ 
+ #
+-# Input device support
++# Input Device Drivers
+ #
+-# CONFIG_INPUT 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=m
++CONFIG_INPUT_MOUSE=y
++# CONFIG_MOUSE_PS2 is not set
++# CONFIG_MOUSE_SERIAL is not set
++# CONFIG_MOUSE_VSXXXAA is not set
++CONFIG_MOUSE_GPIO=m
++# 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
+@@ -472,35 +573,87 @@ CONFIG_SERIAL_CORE=y
+ CONFIG_SERIAL_CORE_CONSOLE=y
+ CONFIG_UNIX98_PTYS=y
+ # CONFIG_LEGACY_PTYS is not set
+-
+-#
+-# IPMI
+-#
+ # CONFIG_IPMI_HANDLER is not set
+-# CONFIG_WATCHDOG is not set
+ # CONFIG_HW_RANDOM is not set
+ # CONFIG_RTC is not set
+ # CONFIG_GEN_RTC is not set
+ # CONFIG_R3964 is not set
+ # CONFIG_RAW_DRIVER is not set
++# CONFIG_TCG_TPM is not set
++CONFIG_I2C=m
++CONFIG_I2C_BOARDINFO=y
++CONFIG_I2C_CHARDEV=m
+ 
+ #
+-# TPM devices
++# I2C Algorithms
+ #
+-# CONFIG_TCG_TPM is not set
+-# CONFIG_I2C is not set
++CONFIG_I2C_ALGOBIT=m
++# CONFIG_I2C_ALGOPCF is not set
++# CONFIG_I2C_ALGOPCA is not set
++
++#
++# I2C Hardware Bus support
++#
++CONFIG_I2C_GPIO=m
++# 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
++
++#
++# Miscellaneous I2C Chip support
++#
++# CONFIG_SENSORS_DS1337 is not set
++# CONFIG_SENSORS_DS1374 is not set
++# CONFIG_DS1682 is not set
++# CONFIG_SENSORS_EEPROM is not set
++# CONFIG_SENSORS_PCF8574 is not set
++# CONFIG_SENSORS_PCA9539 is not set
++# CONFIG_SENSORS_PCF8591 is not set
++# CONFIG_SENSORS_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
+ 
+ #
+ # SPI support
+ #
+-# CONFIG_SPI is not set
+-# CONFIG_SPI_MASTER is not set
++CONFIG_SPI=y
++# CONFIG_SPI_DEBUG is not set
++CONFIG_SPI_MASTER=y
++
++#
++# SPI Master Controller Drivers
++#
++CONFIG_SPI_ATMEL=y
++# CONFIG_SPI_BITBANG is not set
+ 
+ #
+-# Dallas's 1-wire bus
++# SPI Protocol Masters
+ #
++# CONFIG_SPI_AT25 is not set
++CONFIG_SPI_SPIDEV=m
++# 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 is not set
++
++#
++# Watchdog Device Drivers
++#
++# CONFIG_SOFT_WATCHDOG is not set
++CONFIG_AT32AP700X_WDT=y
++
++#
++# Sonics Silicon Backplane
++#
++CONFIG_SSB_POSSIBLE=y
++# CONFIG_SSB is not set
+ 
+ #
+ # Multifunction device drivers
+@@ -517,23 +670,94 @@ CONFIG_UNIX98_PTYS=y
+ #
+ # Graphics support
+ #
+-# CONFIG_BACKLIGHT_LCD_SUPPORT 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_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_S1D13XXX is not set
++CONFIG_FB_ATMEL=y
++# CONFIG_FB_VIRTUAL is not set
++CONFIG_BACKLIGHT_LCD_SUPPORT=y
++CONFIG_LCD_CLASS_DEVICE=y
++CONFIG_LCD_LTV350QV=y
++# CONFIG_BACKLIGHT_CLASS_DEVICE is not set
+ 
+ #
+ # Display device support
+ #
+ # CONFIG_DISPLAY_SUPPORT is not set
+-# CONFIG_VGASTATE is not set
+-# CONFIG_FB is not set
++# CONFIG_LOGO is not set
+ 
+ #
+ # Sound
+ #
+-# CONFIG_SOUND is not set
++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 is not set
++# CONFIG_SND_VERBOSE_PROCFS is not set
++# CONFIG_SND_VERBOSE_PRINTK is not set
++# CONFIG_SND_DEBUG is not set
+ 
+ #
+-# USB support
++# 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
++#
++CONFIG_SND_AT73C213=m
++CONFIG_SND_AT73C213_TARGET_BITRATE=48000
++
++#
++# System on Chip audio support
++#
++# CONFIG_SND_SOC is not set
++
++#
++# SoC Audio support for SuperH
++#
++
++#
++# Open Sound System
++#
++# CONFIG_SOUND_PRIME is not set
++# CONFIG_HID_SUPPORT is not set
++CONFIG_USB_SUPPORT=y
+ # CONFIG_USB_ARCH_HAS_HCD is not set
+ # CONFIG_USB_ARCH_HAS_OHCI is not set
+ # CONFIG_USB_ARCH_HAS_EHCI is not set
+@@ -545,47 +769,116 @@ CONFIG_UNIX98_PTYS=y
+ #
+ # USB Gadget Support
+ #
+-# CONFIG_USB_GADGET is not set
+-# CONFIG_MMC is not set
+-
+-#
+-# LED devices
+-#
+-# CONFIG_NEW_LEDS 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_DEBUG_FS is not set
++CONFIG_USB_GADGET_SELECTED=y
++# CONFIG_USB_GADGET_AMD5536UDC is not set
++CONFIG_USB_GADGET_ATMEL_USBA=y
++CONFIG_USB_ATMEL_USBA=y
++# CONFIG_USB_GADGET_FSL_USB2 is not set
++# CONFIG_USB_GADGET_NET2280 is not set
++# CONFIG_USB_GADGET_PXA2XX is not set
++# CONFIG_USB_GADGET_M66592 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=y
++CONFIG_USB_ZERO=m
++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_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_SPI=m
++CONFIG_NEW_LEDS=y
++CONFIG_LEDS_CLASS=m
+ 
+ #
+ # LED drivers
+ #
++CONFIG_LEDS_GPIO=m
+ 
+ #
+ # LED Triggers
+ #
++CONFIG_LEDS_TRIGGERS=y
++CONFIG_LEDS_TRIGGER_TIMER=m
++CONFIG_LEDS_TRIGGER_HEARTBEAT=m
++CONFIG_RTC_LIB=y
++CONFIG_RTC_CLASS=y
++CONFIG_RTC_HCTOSYS=y
++CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
++# CONFIG_RTC_DEBUG is not set
+ 
+ #
+-# InfiniBand support
++# 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
+ 
+ #
+-# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
++# 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
+ 
+ #
+-# Real Time Clock
++# SPI RTC drivers
+ #
+-# CONFIG_RTC_CLASS is not set
++# CONFIG_RTC_DRV_RS5C348 is not set
++# CONFIG_RTC_DRV_MAX6902 is not set
+ 
+ #
+-# DMA Engine support
++# Platform RTC drivers
+ #
+-# CONFIG_DMA_ENGINE is not set
++# CONFIG_RTC_DRV_DS1553 is not set
++# CONFIG_RTC_DRV_STK17TA8 is not set
++# CONFIG_RTC_DRV_DS1742 is not set
++# CONFIG_RTC_DRV_M48T86 is not set
++# CONFIG_RTC_DRV_M48T59 is not set
++# CONFIG_RTC_DRV_V3020 is not set
+ 
+ #
+-# DMA Clients
++# on-CPU RTC drivers
+ #
++CONFIG_RTC_DRV_AT32AP700X=y
+ 
+ #
+-# DMA Devices
++# Userspace I/O
+ #
++# CONFIG_UIO is not set
+ 
+ #
+ # File systems
+@@ -593,8 +886,11 @@ CONFIG_UNIX98_PTYS=y
+ CONFIG_EXT2_FS=m
+ # CONFIG_EXT2_FS_XATTR is not set
+ # CONFIG_EXT2_FS_XIP is not set
+-# CONFIG_EXT3_FS is not set
++CONFIG_EXT3_FS=m
++# CONFIG_EXT3_FS_XATTR is not set
+ # CONFIG_EXT4DEV_FS is not set
++CONFIG_JBD=m
++# CONFIG_JBD_DEBUG is not set
+ # CONFIG_REISERFS_FS is not set
+ # CONFIG_JFS_FS is not set
+ # CONFIG_FS_POSIX_ACL is not set
+@@ -609,7 +905,7 @@ CONFIG_INOTIFY_USER=y
+ # CONFIG_DNOTIFY is not set
+ # CONFIG_AUTOFS_FS is not set
+ # CONFIG_AUTOFS4_FS is not set
+-# CONFIG_FUSE_FS is not set
++CONFIG_FUSE_FS=m
+ 
+ #
+ # CD-ROM/DVD Filesystems
+@@ -637,8 +933,7 @@ CONFIG_SYSFS=y
+ CONFIG_TMPFS=y
+ # CONFIG_TMPFS_POSIX_ACL is not set
+ # CONFIG_HUGETLB_PAGE is not set
+-CONFIG_RAMFS=y
+-CONFIG_CONFIGFS_FS=m
++# CONFIG_CONFIGFS_FS is not set
+ 
+ #
+ # Miscellaneous filesystems
+@@ -652,11 +947,12 @@ CONFIG_CONFIGFS_FS=m
+ # CONFIG_EFS_FS is not set
+ CONFIG_JFFS2_FS=y
+ CONFIG_JFFS2_FS_DEBUG=0
+-CONFIG_JFFS2_FS_WRITEBUFFER=y
++# CONFIG_JFFS2_FS_WRITEBUFFER 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
+@@ -665,10 +961,7 @@ CONFIG_JFFS2_RTIME=y
+ # CONFIG_QNX4FS_FS is not set
+ # CONFIG_SYSV_FS is not set
+ # CONFIG_UFS_FS is not set
+-
+-#
+-# Network File Systems
+-#
++CONFIG_NETWORK_FILESYSTEMS=y
+ CONFIG_NFS_FS=y
+ CONFIG_NFS_V3=y
+ # CONFIG_NFS_V3_ACL is not set
+@@ -688,17 +981,12 @@ CONFIG_SUNRPC=y
+ # CONFIG_NCP_FS is not set
+ # CONFIG_CODA_FS is not set
+ # CONFIG_AFS_FS is not set
+-# CONFIG_9P_FS is not set
+ 
+ #
+ # Partition Types
+ #
+ # CONFIG_PARTITION_ADVANCED is not set
+ CONFIG_MSDOS_PARTITION=y
+-
+-#
+-# Native Language Support
+-#
+ CONFIG_NLS=m
+ CONFIG_NLS_DEFAULT="iso8859-1"
+ CONFIG_NLS_CODEPAGE_437=m
+@@ -739,17 +1027,18 @@ CONFIG_NLS_ISO8859_1=m
+ # CONFIG_NLS_KOI8_R is not set
+ # CONFIG_NLS_KOI8_U is not set
+ CONFIG_NLS_UTF8=m
+-
+-#
+-# Distributed Lock Manager
+-#
+ # CONFIG_DLM is not set
++CONFIG_INSTRUMENTATION=y
++CONFIG_PROFILING=y
++CONFIG_OPROFILE=m
++CONFIG_KPROBES=y
++# CONFIG_MARKERS is not set
+ 
+ #
+ # Kernel hacking
+ #
+-CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+ # CONFIG_PRINTK_TIME is not set
++CONFIG_ENABLE_WARN_DEPRECATED=y
+ CONFIG_ENABLE_MUST_CHECK=y
+ CONFIG_MAGIC_SYSRQ=y
+ # CONFIG_UNUSED_SYMBOLS is not set
+@@ -758,12 +1047,17 @@ CONFIG_DEBUG_FS=y
+ CONFIG_DEBUG_KERNEL=y
+ # CONFIG_DEBUG_SHIRQ is not set
+ CONFIG_DETECT_SOFTLOCKUP=y
++CONFIG_SCHED_DEBUG=y
+ # CONFIG_SCHEDSTATS is not set
+ # CONFIG_TIMER_STATS is not set
++# CONFIG_SLUB_DEBUG_ON 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
+@@ -771,22 +1065,63 @@ CONFIG_DEBUG_BUGVERBOSE=y
+ # CONFIG_DEBUG_INFO is not set
+ # CONFIG_DEBUG_VM is not set
+ # CONFIG_DEBUG_LIST is not set
++# CONFIG_DEBUG_SG is not set
+ CONFIG_FRAME_POINTER=y
+ CONFIG_FORCED_INLINING=y
++# CONFIG_BOOT_PRINTK_DELAY is not set
+ # CONFIG_RCU_TORTURE_TEST is not set
++# CONFIG_LKDTM is not set
+ # CONFIG_FAULT_INJECTION is not set
+-# CONFIG_KPROBES is not set
++# CONFIG_SAMPLES is not set
+ 
+ #
+ # Security options
+ #
+ # CONFIG_KEYS is not set
+ # CONFIG_SECURITY is not set
+-
+-#
+-# Cryptographic options
+-#
+-# CONFIG_CRYPTO is not set
++# CONFIG_SECURITY_FILE_CAPABILITIES is not set
++CONFIG_CRYPTO=y
++CONFIG_CRYPTO_ALGAPI=m
++CONFIG_CRYPTO_BLKCIPHER=m
++CONFIG_CRYPTO_HASH=m
++CONFIG_CRYPTO_MANAGER=m
++CONFIG_CRYPTO_HMAC=m
++# CONFIG_CRYPTO_XCBC is not set
++# CONFIG_CRYPTO_NULL is not set
++# CONFIG_CRYPTO_MD4 is not set
++CONFIG_CRYPTO_MD5=m
++CONFIG_CRYPTO_SHA1=m
++# CONFIG_CRYPTO_SHA256 is not set
++# CONFIG_CRYPTO_SHA512 is not set
++# CONFIG_CRYPTO_WP512 is not set
++# CONFIG_CRYPTO_TGR192 is not set
++# CONFIG_CRYPTO_GF128MUL is not set
++# CONFIG_CRYPTO_ECB is not set
++CONFIG_CRYPTO_CBC=m
++# CONFIG_CRYPTO_PCBC is not set
++# CONFIG_CRYPTO_LRW is not set
++# CONFIG_CRYPTO_XTS is not set
++# CONFIG_CRYPTO_CRYPTD is not set
++CONFIG_CRYPTO_DES=m
++# CONFIG_CRYPTO_FCRYPT is not set
++# CONFIG_CRYPTO_BLOWFISH is not set
++# CONFIG_CRYPTO_TWOFISH is not set
++# CONFIG_CRYPTO_SERPENT is not set
++# CONFIG_CRYPTO_AES is not set
++# CONFIG_CRYPTO_CAST5 is not set
++# CONFIG_CRYPTO_CAST6 is not set
++# CONFIG_CRYPTO_TEA is not set
++# CONFIG_CRYPTO_ARC4 is not set
++# CONFIG_CRYPTO_KHAZAD is not set
++# CONFIG_CRYPTO_ANUBIS is not set
++# CONFIG_CRYPTO_SEED is not set
++CONFIG_CRYPTO_DEFLATE=m
++# CONFIG_CRYPTO_MICHAEL_MIC is not set
++# CONFIG_CRYPTO_CRC32C is not set
++# CONFIG_CRYPTO_CAMELLIA is not set
++# CONFIG_CRYPTO_TEST is not set
++# CONFIG_CRYPTO_AUTHENC is not set
++# CONFIG_CRYPTO_HW is not set
+ 
+ #
+ # Library routines
+@@ -794,10 +1129,10 @@ CONFIG_FORCED_INLINING=y
+ CONFIG_BITREVERSE=y
+ CONFIG_CRC_CCITT=m
+ # CONFIG_CRC16 is not set
+-# CONFIG_CRC_ITU_T is not set
++CONFIG_CRC_ITU_T=m
+ CONFIG_CRC32=y
++CONFIG_CRC7=m
+ # CONFIG_LIBCRC32C is not set
+-CONFIG_AUDIT_GENERIC=y
+ CONFIG_ZLIB_INFLATE=y
+ CONFIG_ZLIB_DEFLATE=y
+ CONFIG_PLIST=y
+diff --git a/arch/avr32/configs/atstk1003_defconfig b/arch/avr32/configs/atstk1003_defconfig
+new file mode 100644
+index 0000000..45e23e0
+--- /dev/null
++++ b/arch/avr32/configs/atstk1003_defconfig
+@@ -0,0 +1,1015 @@
++#
++# Automatically generated make config: don't edit
++# Linux kernel version: 2.6.24-rc7
++# Wed Jan  9 22:54:34 2008
++#
++CONFIG_AVR32=y
++CONFIG_GENERIC_GPIO=y
++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_GENERIC_TIME=y
++# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
++# CONFIG_ARCH_HAS_ILOG2_U32 is not set
++# CONFIG_ARCH_HAS_ILOG2_U64 is not set
++CONFIG_ARCH_SUPPORTS_OPROFILE=y
++CONFIG_GENERIC_HWEIGHT=y
++CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_GENERIC_BUG=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 is not set
++CONFIG_SWAP=y
++CONFIG_SYSVIPC=y
++CONFIG_SYSVIPC_SYSCTL=y
++CONFIG_POSIX_MQUEUE=y
++CONFIG_BSD_PROCESS_ACCT=y
++CONFIG_BSD_PROCESS_ACCT_V3=y
++CONFIG_TASKSTATS=y
++CONFIG_TASK_DELAY_ACCT=y
++# CONFIG_TASK_XACCT is not set
++# CONFIG_USER_NS is not set
++# CONFIG_PID_NS is not set
++CONFIG_AUDIT=y
++# CONFIG_IKCONFIG is not set
++CONFIG_LOG_BUF_SHIFT=14
++# CONFIG_CGROUPS is not set
++CONFIG_FAIR_GROUP_SCHED=y
++CONFIG_FAIR_USER_SCHED=y
++# CONFIG_FAIR_CGROUP_SCHED is not set
++CONFIG_SYSFS_DEPRECATED=y
++CONFIG_RELAY=y
++CONFIG_BLK_DEV_INITRD=y
++CONFIG_INITRAMFS_SOURCE=""
++CONFIG_CC_OPTIMIZE_FOR_SIZE=y
++CONFIG_SYSCTL=y
++CONFIG_EMBEDDED=y
++# CONFIG_SYSCTL_SYSCALL is not set
++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_BASE_FULL is not set
++CONFIG_FUTEX=y
++CONFIG_ANON_INODES=y
++CONFIG_EPOLL=y
++CONFIG_SIGNALFD=y
++CONFIG_EVENTFD=y
++CONFIG_SHMEM=y
++CONFIG_VM_EVENT_COUNTERS=y
++# CONFIG_SLUB_DEBUG is not set
++# CONFIG_SLAB is not set
++CONFIG_SLUB=y
++# CONFIG_SLOB is not set
++CONFIG_SLABINFO=y
++CONFIG_RT_MUTEXES=y
++# CONFIG_TINY_SHMEM is not set
++CONFIG_BASE_SMALL=1
++CONFIG_MODULES=y
++CONFIG_MODULE_UNLOAD=y
++# CONFIG_MODULE_FORCE_UNLOAD is not set
++# CONFIG_MODVERSIONS is not set
++# CONFIG_MODULE_SRCVERSION_ALL is not set
++# CONFIG_KMOD is not set
++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=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"
++
++#
++# System Type and features
++#
++CONFIG_SUBARCH_AVR32B=y
++CONFIG_MMU=y
++CONFIG_PERFORMANCE_COUNTERS=y
++CONFIG_PLATFORM_AT32AP=y
++CONFIG_CPU_AT32AP700X=y
++CONFIG_CPU_AT32AP7001=y
++CONFIG_BOARD_ATSTK1000=y
++# CONFIG_BOARD_ATNGW100 is not set
++# CONFIG_BOARD_ATSTK1002 is not set
++CONFIG_BOARD_ATSTK1003=y
++# CONFIG_BOARD_ATSTK1004 is not set
++# CONFIG_BOARD_ATSTK100X_CUSTOM is not set
++# CONFIG_BOARD_ATSTK100X_SPI1 is not set
++# CONFIG_BOARD_ATSTK1000_J2_LED is not set
++# CONFIG_BOARD_ATSTK1000_J2_LED8 is not set
++# CONFIG_BOARD_ATSTK1000_J2_RGB is not set
++CONFIG_BOARD_ATSTK1000_EXTDAC=y
++CONFIG_LOADER_U_BOOT=y
++
++#
++# Atmel AVR32 AP options
++#
++# CONFIG_AP700X_32_BIT_SMC is not set
++CONFIG_AP700X_16_BIT_SMC=y
++# CONFIG_AP700X_8_BIT_SMC is not set
++CONFIG_LOAD_ADDRESS=0x10000000
++CONFIG_ENTRY_ADDRESS=0x90000000
++CONFIG_PHYS_OFFSET=0x10000000
++CONFIG_PREEMPT_NONE=y
++# CONFIG_PREEMPT_VOLUNTARY is not set
++# CONFIG_PREEMPT is not set
++# CONFIG_HAVE_ARCH_BOOTMEM_NODE is not set
++# CONFIG_ARCH_HAVE_MEMORY_PRESENT is not set
++# CONFIG_NEED_NODE_MEMMAP_SIZE is not set
++CONFIG_ARCH_FLATMEM_ENABLE=y
++# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
++# CONFIG_ARCH_SPARSEMEM_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_SPLIT_PTLOCK_CPUS=4
++# CONFIG_RESOURCES_64BIT is not set
++CONFIG_ZONE_DMA_FLAG=0
++CONFIG_VIRT_TO_BUS=y
++# CONFIG_OWNERSHIP_TRACE is not set
++# 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_CMDLINE=""
++
++#
++# Power management options
++#
++
++#
++# CPU Frequency scaling
++#
++CONFIG_CPU_FREQ=y
++CONFIG_CPU_FREQ_TABLE=y
++# CONFIG_CPU_FREQ_DEBUG is not set
++# CONFIG_CPU_FREQ_STAT is not set
++CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
++# 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=y
++# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
++CONFIG_CPU_FREQ_AT32AP=y
++
++#
++# Bus options
++#
++# CONFIG_ARCH_SUPPORTS_MSI is not set
++# CONFIG_PCCARD is not set
++
++#
++# Executable file formats
++#
++CONFIG_BINFMT_ELF=y
++# CONFIG_BINFMT_MISC is not set
++
++#
++# Networking
++#
++CONFIG_NET=y
++
++#
++# Networking options
++#
++CONFIG_PACKET=y
++CONFIG_PACKET_MMAP=y
++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 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 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_INET6_XFRM_TUNNEL is not set
++# CONFIG_INET6_TUNNEL 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_NET_TCPPROBE is not set
++# CONFIG_HAMRADIO 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 is not set
++# CONFIG_FW_LOADER is not set
++# 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
++
++#
++# 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 is not set
++CONFIG_MTD_GEN_PROBE=y
++# 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=y
++# 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
++
++#
++# Mapping drivers for chip access
++#
++# CONFIG_MTD_COMPLEX_MAPPINGS is not set
++CONFIG_MTD_PHYSMAP=y
++CONFIG_MTD_PHYSMAP_START=0x8000000
++CONFIG_MTD_PHYSMAP_LEN=0x0
++CONFIG_MTD_PHYSMAP_BANKWIDTH=2
++# CONFIG_MTD_PLATRAM is not set
++
++#
++# Self-contained MTD device drivers
++#
++CONFIG_MTD_DATAFLASH=m
++CONFIG_MTD_M25P80=m
++# 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_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=m
++CONFIG_BLK_DEV_RAM_COUNT=16
++CONFIG_BLK_DEV_RAM_SIZE=4096
++CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
++# CONFIG_CDROM_PKTCDVD is not set
++# CONFIG_ATA_OVER_ETH is not set
++CONFIG_MISC_DEVICES=y
++# CONFIG_EEPROM_93CX6 is not set
++CONFIG_ATMEL_SSC=m
++# 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=m
++# CONFIG_BLK_DEV_SR_VENDOR 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_ATA=m
++# CONFIG_ATA_NONSTANDARD is not set
++CONFIG_PATA_AT32=m
++# CONFIG_PATA_PLATFORM 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_NET_ETHERNET 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_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_SHAPER 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=m
++# CONFIG_INPUT_FF_MEMLESS is not set
++CONFIG_INPUT_POLLDEV=m
++
++#
++# Userland interfaces
++#
++CONFIG_INPUT_MOUSEDEV=m
++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 is not set
++# 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_GPIO=m
++CONFIG_INPUT_MOUSE=y
++# CONFIG_MOUSE_PS2 is not set
++# CONFIG_MOUSE_SERIAL is not set
++# CONFIG_MOUSE_VSXXXAA is not set
++CONFIG_MOUSE_GPIO=m
++# 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 is not set
++# 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_TTYAT is not set
++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_RTC is not set
++# CONFIG_GEN_RTC is not set
++# CONFIG_R3964 is not set
++# CONFIG_RAW_DRIVER is not set
++# CONFIG_TCG_TPM is not set
++CONFIG_I2C=m
++CONFIG_I2C_BOARDINFO=y
++CONFIG_I2C_CHARDEV=m
++
++#
++# I2C Algorithms
++#
++CONFIG_I2C_ALGOBIT=m
++# CONFIG_I2C_ALGOPCF is not set
++# CONFIG_I2C_ALGOPCA is not set
++
++#
++# I2C Hardware Bus support
++#
++CONFIG_I2C_GPIO=m
++# 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
++
++#
++# Miscellaneous I2C Chip support
++#
++# CONFIG_SENSORS_DS1337 is not set
++# CONFIG_SENSORS_DS1374 is not set
++# CONFIG_DS1682 is not set
++# CONFIG_SENSORS_EEPROM is not set
++# CONFIG_SENSORS_PCF8574 is not set
++# CONFIG_SENSORS_PCA9539 is not set
++# CONFIG_SENSORS_PCF8591 is not set
++# CONFIG_SENSORS_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
++
++#
++# SPI support
++#
++CONFIG_SPI=y
++# CONFIG_SPI_DEBUG is not set
++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=m
++# 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 is not set
++
++#
++# Watchdog Device Drivers
++#
++# CONFIG_SOFT_WATCHDOG is not set
++CONFIG_AT32AP700X_WDT=y
++
++#
++# Sonics Silicon Backplane
++#
++CONFIG_SSB_POSSIBLE=y
++# CONFIG_SSB is not set
++
++#
++# Multifunction device drivers
++#
++# CONFIG_MFD_SM501 is not set
++
++#
++# Multimedia devices
++#
++# CONFIG_VIDEO_DEV is not set
++# CONFIG_DVB_CORE is not set
++# 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
++
++#
++# 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
++#
++CONFIG_SND_AT73C213=m
++CONFIG_SND_AT73C213_TARGET_BITRATE=48000
++
++#
++# System on Chip audio support
++#
++# CONFIG_SND_SOC is not set
++
++#
++# SoC Audio support for SuperH
++#
++
++#
++# Open Sound System
++#
++# CONFIG_SOUND_PRIME is not set
++# CONFIG_HID_SUPPORT is not set
++CONFIG_USB_SUPPORT=y
++# CONFIG_USB_ARCH_HAS_HCD is not set
++# CONFIG_USB_ARCH_HAS_OHCI is not set
++# CONFIG_USB_ARCH_HAS_EHCI is not set
++
++#
++# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
++#
++
++#
++# USB Gadget Support
++#
++CONFIG_USB_GADGET=y
++# CONFIG_USB_GADGET_DEBUG is not set
++# CONFIG_USB_GADGET_DEBUG_FILES is not set
++CONFIG_USB_GADGET_DEBUG_FS=y
++CONFIG_USB_GADGET_SELECTED=y
++# CONFIG_USB_GADGET_AMD5536UDC is not set
++CONFIG_USB_GADGET_ATMEL_USBA=y
++CONFIG_USB_ATMEL_USBA=y
++# CONFIG_USB_GADGET_FSL_USB2 is not set
++# CONFIG_USB_GADGET_NET2280 is not set
++# CONFIG_USB_GADGET_PXA2XX is not set
++# CONFIG_USB_GADGET_M66592 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=y
++CONFIG_USB_ZERO=m
++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_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 is not set
++# CONFIG_SDIO_UART is not set
++
++#
++# MMC/SD Host Controller Drivers
++#
++CONFIG_MMC_SPI=m
++CONFIG_NEW_LEDS=y
++CONFIG_LEDS_CLASS=y
++
++#
++# LED drivers
++#
++CONFIG_LEDS_GPIO=y
++
++#
++# LED Triggers
++#
++CONFIG_LEDS_TRIGGERS=y
++CONFIG_LEDS_TRIGGER_TIMER=y
++CONFIG_LEDS_TRIGGER_HEARTBEAT=y
++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
++
++#
++# SPI RTC drivers
++#
++# CONFIG_RTC_DRV_RS5C348 is not set
++# CONFIG_RTC_DRV_MAX6902 is not set
++
++#
++# Platform RTC drivers
++#
++# CONFIG_RTC_DRV_DS1553 is not set
++# CONFIG_RTC_DRV_STK17TA8 is not set
++# CONFIG_RTC_DRV_DS1742 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_AT32AP700X=y
++
++#
++# Userspace I/O
++#
++CONFIG_UIO=m
++
++#
++# 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_JBD_DEBUG 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_GFS2_FS is not set
++# CONFIG_OCFS2_FS is not set
++# CONFIG_MINIX_FS is not set
++# CONFIG_ROMFS_FS is not set
++CONFIG_INOTIFY=y
++CONFIG_INOTIFY_USER=y
++# CONFIG_QUOTA is not set
++# CONFIG_DNOTIFY is not set
++# CONFIG_AUTOFS_FS is not set
++# CONFIG_AUTOFS4_FS is not set
++CONFIG_FUSE_FS=m
++
++#
++# 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_KCORE=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=m
++
++#
++# 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_HPFS_FS is not set
++# CONFIG_QNX4FS_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=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
++CONFIG_INSTRUMENTATION=y
++CONFIG_PROFILING=y
++CONFIG_OPROFILE=m
++CONFIG_KPROBES=y
++# CONFIG_MARKERS is not set
++
++#
++# Kernel hacking
++#
++# CONFIG_PRINTK_TIME is not set
++CONFIG_ENABLE_WARN_DEPRECATED=y
++CONFIG_ENABLE_MUST_CHECK=y
++CONFIG_MAGIC_SYSRQ=y
++# 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=y
++CONFIG_SCHED_DEBUG=y
++# CONFIG_SCHEDSTATS is not set
++# CONFIG_TIMER_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_LIST is not set
++# CONFIG_DEBUG_SG is not set
++CONFIG_FRAME_POINTER=y
++CONFIG_FORCED_INLINING=y
++# CONFIG_BOOT_PRINTK_DELAY is not set
++# CONFIG_RCU_TORTURE_TEST is not set
++# CONFIG_LKDTM is not set
++# CONFIG_FAULT_INJECTION is not set
++# CONFIG_SAMPLES 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_CRC_CCITT=m
++# CONFIG_CRC16 is not set
++CONFIG_CRC_ITU_T=m
++CONFIG_CRC32=y
++CONFIG_CRC7=m
++# CONFIG_LIBCRC32C is not set
++CONFIG_AUDIT_GENERIC=y
++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/avr32/configs/atstk1004_defconfig b/arch/avr32/configs/atstk1004_defconfig
+new file mode 100644
+index 0000000..634c527
+--- /dev/null
++++ b/arch/avr32/configs/atstk1004_defconfig
+@@ -0,0 +1,621 @@
++#
++# Automatically generated make config: don't edit
++# Linux kernel version: 2.6.24-rc7
++# Wed Jan  9 23:04:20 2008
++#
++CONFIG_AVR32=y
++CONFIG_GENERIC_GPIO=y
++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_GENERIC_TIME=y
++# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
++# CONFIG_ARCH_HAS_ILOG2_U32 is not set
++# CONFIG_ARCH_HAS_ILOG2_U64 is not set
++CONFIG_ARCH_SUPPORTS_OPROFILE=y
++CONFIG_GENERIC_HWEIGHT=y
++CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_GENERIC_BUG=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 is not set
++# CONFIG_SYSVIPC is not set
++# CONFIG_POSIX_MQUEUE is not set
++# CONFIG_BSD_PROCESS_ACCT is not set
++# CONFIG_TASKSTATS is not set
++# CONFIG_USER_NS is not set
++# CONFIG_PID_NS is not set
++# CONFIG_AUDIT is not set
++# CONFIG_IKCONFIG is not set
++CONFIG_LOG_BUF_SHIFT=14
++# CONFIG_CGROUPS is not set
++# CONFIG_FAIR_GROUP_SCHED is not set
++CONFIG_SYSFS_DEPRECATED=y
++# CONFIG_RELAY is not set
++# CONFIG_BLK_DEV_INITRD is not set
++CONFIG_CC_OPTIMIZE_FOR_SIZE=y
++CONFIG_SYSCTL=y
++CONFIG_EMBEDDED=y
++# CONFIG_SYSCTL_SYSCALL is not set
++CONFIG_KALLSYMS=y
++# CONFIG_KALLSYMS_EXTRA_PASS is not set
++CONFIG_HOTPLUG=y
++CONFIG_PRINTK=y
++CONFIG_BUG=y
++CONFIG_ELF_CORE=y
++# CONFIG_BASE_FULL is not set
++# CONFIG_FUTEX is not set
++# CONFIG_EPOLL is not set
++# CONFIG_SIGNALFD is not set
++# CONFIG_EVENTFD is not set
++CONFIG_SHMEM=y
++CONFIG_VM_EVENT_COUNTERS=y
++# CONFIG_SLAB is not set
++# CONFIG_SLUB is not set
++CONFIG_SLOB=y
++# CONFIG_TINY_SHMEM is not set
++CONFIG_BASE_SMALL=1
++# CONFIG_MODULES is not set
++# CONFIG_BLOCK is not set
++
++#
++# System Type and features
++#
++CONFIG_SUBARCH_AVR32B=y
++CONFIG_MMU=y
++CONFIG_PERFORMANCE_COUNTERS=y
++CONFIG_PLATFORM_AT32AP=y
++CONFIG_CPU_AT32AP700X=y
++CONFIG_CPU_AT32AP7002=y
++CONFIG_BOARD_ATSTK1000=y
++# CONFIG_BOARD_ATNGW100 is not set
++# CONFIG_BOARD_ATSTK1002 is not set
++# CONFIG_BOARD_ATSTK1003 is not set
++CONFIG_BOARD_ATSTK1004=y
++# CONFIG_BOARD_ATSTK100X_CUSTOM is not set
++# CONFIG_BOARD_ATSTK100X_SPI1 is not set
++# CONFIG_BOARD_ATSTK1000_J2_LED is not set
++CONFIG_BOARD_ATSTK1000_EXTDAC=y
++CONFIG_LOADER_U_BOOT=y
++
++#
++# Atmel AVR32 AP options
++#
++# CONFIG_AP700X_32_BIT_SMC is not set
++CONFIG_AP700X_16_BIT_SMC=y
++# CONFIG_AP700X_8_BIT_SMC is not set
++CONFIG_LOAD_ADDRESS=0x10000000
++CONFIG_ENTRY_ADDRESS=0x90000000
++CONFIG_PHYS_OFFSET=0x10000000
++CONFIG_PREEMPT_NONE=y
++# CONFIG_PREEMPT_VOLUNTARY is not set
++# CONFIG_PREEMPT is not set
++# CONFIG_HAVE_ARCH_BOOTMEM_NODE is not set
++# CONFIG_ARCH_HAVE_MEMORY_PRESENT is not set
++# CONFIG_NEED_NODE_MEMMAP_SIZE is not set
++CONFIG_ARCH_FLATMEM_ENABLE=y
++# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
++# CONFIG_ARCH_SPARSEMEM_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_SPLIT_PTLOCK_CPUS=4
++# CONFIG_RESOURCES_64BIT is not set
++CONFIG_ZONE_DMA_FLAG=0
++CONFIG_VIRT_TO_BUS=y
++# CONFIG_OWNERSHIP_TRACE is not set
++# 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_CMDLINE=""
++
++#
++# Power management options
++#
++
++#
++# CPU Frequency scaling
++#
++CONFIG_CPU_FREQ=y
++CONFIG_CPU_FREQ_TABLE=y
++# CONFIG_CPU_FREQ_DEBUG is not set
++# CONFIG_CPU_FREQ_STAT is not set
++CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
++# 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=y
++# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
++CONFIG_CPU_FREQ_AT32AP=y
++
++#
++# Bus options
++#
++# CONFIG_ARCH_SUPPORTS_MSI is not set
++# CONFIG_PCCARD is not set
++
++#
++# Executable file formats
++#
++CONFIG_BINFMT_ELF=y
++# CONFIG_BINFMT_MISC is not set
++
++#
++# Networking
++#
++CONFIG_NET=y
++
++#
++# Networking options
++#
++CONFIG_PACKET=y
++CONFIG_PACKET_MMAP=y
++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 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 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_INET6_XFRM_TUNNEL is not set
++# CONFIG_INET6_TUNNEL 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_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 is not set
++# 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=y
++
++#
++# User Modules And Translation Layers
++#
++CONFIG_MTD_CHAR=y
++# CONFIG_MTD_OOPS is not set
++
++#
++# RAM/ROM/Flash chip drivers
++#
++CONFIG_MTD_CFI=y
++# CONFIG_MTD_JEDECPROBE is not set
++CONFIG_MTD_GEN_PROBE=y
++# CONFIG_MTD_CFI_ADV_OPTIONS is not set
++CONFIG_MTD_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=y
++# 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
++
++#
++# Mapping drivers for chip access
++#
++# CONFIG_MTD_COMPLEX_MAPPINGS is not set
++CONFIG_MTD_PHYSMAP=y
++CONFIG_MTD_PHYSMAP_START=0x8000000
++CONFIG_MTD_PHYSMAP_LEN=0x0
++CONFIG_MTD_PHYSMAP_BANKWIDTH=2
++# 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
++
++#
++# 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_MISC_DEVICES is not set
++
++#
++# SCSI device support
++#
++# CONFIG_SCSI_DMA is not set
++# CONFIG_SCSI_NETLINK is not set
++# CONFIG_NETDEVICES is not set
++# CONFIG_ISDN is not set
++# CONFIG_PHONE is not set
++
++#
++# Input device support
++#
++# CONFIG_INPUT is not set
++
++#
++# Hardware I/O ports
++#
++# CONFIG_SERIO is not set
++# CONFIG_GAMEPORT is not set
++
++#
++# Character devices
++#
++# CONFIG_VT is not set
++# CONFIG_SERIAL_NONSTANDARD is not set
++
++#
++# Serial drivers
++#
++# CONFIG_SERIAL_8250 is not set
++
++#
++# Non-8250 serial port support
++#
++CONFIG_SERIAL_ATMEL=y
++CONFIG_SERIAL_ATMEL_CONSOLE=y
++# CONFIG_SERIAL_ATMEL_TTYAT is not set
++CONFIG_SERIAL_CORE=y
++CONFIG_SERIAL_CORE_CONSOLE=y
++CONFIG_UNIX98_PTYS=y
++# CONFIG_LEGACY_PTYS is not set
++# CONFIG_IPMI_HANDLER is not set
++# CONFIG_HW_RANDOM is not set
++# CONFIG_RTC is not set
++# CONFIG_GEN_RTC is not set
++# CONFIG_R3964 is not set
++# CONFIG_TCG_TPM is not set
++# CONFIG_I2C is not set
++
++#
++# SPI support
++#
++CONFIG_SPI=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 is not set
++# 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 is not set
++
++#
++# Watchdog Device Drivers
++#
++# CONFIG_SOFT_WATCHDOG is not set
++CONFIG_AT32AP700X_WDT=y
++
++#
++# Sonics Silicon Backplane
++#
++CONFIG_SSB_POSSIBLE=y
++# CONFIG_SSB is not set
++
++#
++# Multifunction device drivers
++#
++# CONFIG_MFD_SM501 is not set
++
++#
++# Multimedia devices
++#
++# CONFIG_VIDEO_DEV is not set
++# CONFIG_DVB_CORE is not set
++# 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_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_S1D13XXX is not set
++CONFIG_FB_ATMEL=y
++# CONFIG_FB_VIRTUAL is not set
++CONFIG_BACKLIGHT_LCD_SUPPORT=y
++CONFIG_LCD_CLASS_DEVICE=y
++CONFIG_LCD_LTV350QV=y
++# CONFIG_BACKLIGHT_CLASS_DEVICE is not set
++
++#
++# Display device support
++#
++# CONFIG_DISPLAY_SUPPORT is not set
++# CONFIG_LOGO is not set
++
++#
++# Sound
++#
++# CONFIG_SOUND is not set
++CONFIG_USB_SUPPORT=y
++# CONFIG_USB_ARCH_HAS_HCD is not set
++# CONFIG_USB_ARCH_HAS_OHCI is not set
++# CONFIG_USB_ARCH_HAS_EHCI is not set
++
++#
++# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
++#
++
++#
++# USB Gadget Support
++#
++CONFIG_USB_GADGET=y
++# 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=y
++CONFIG_USB_ATMEL_USBA=y
++# CONFIG_USB_GADGET_FSL_USB2 is not set
++# CONFIG_USB_GADGET_NET2280 is not set
++# CONFIG_USB_GADGET_PXA2XX is not set
++# CONFIG_USB_GADGET_M66592 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=y
++# CONFIG_USB_ZERO is not set
++CONFIG_USB_ETH=y
++# CONFIG_USB_ETH_RNDIS is not set
++# CONFIG_USB_GADGETFS is not set
++# CONFIG_USB_FILE_STORAGE is not set
++# CONFIG_USB_G_SERIAL is not set
++# CONFIG_USB_MIDI_GADGET 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 is not set
++CONFIG_RTC_INTF_DEV=y
++# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
++# CONFIG_RTC_DRV_TEST is not set
++
++#
++# SPI RTC drivers
++#
++# CONFIG_RTC_DRV_RS5C348 is not set
++# CONFIG_RTC_DRV_MAX6902 is not set
++
++#
++# Platform RTC drivers
++#
++# CONFIG_RTC_DRV_DS1553 is not set
++# CONFIG_RTC_DRV_STK17TA8 is not set
++# CONFIG_RTC_DRV_DS1742 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_AT32AP700X=y
++
++#
++# Userspace I/O
++#
++# CONFIG_UIO is not set
++
++#
++# File systems
++#
++# CONFIG_INOTIFY is not set
++# CONFIG_QUOTA is not set
++# CONFIG_DNOTIFY is not set
++# CONFIG_AUTOFS_FS is not set
++# CONFIG_AUTOFS4_FS is not set
++# CONFIG_FUSE_FS is not set
++
++#
++# Pseudo filesystems
++#
++CONFIG_PROC_FS=y
++CONFIG_PROC_KCORE=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_JFFS2_FS=y
++CONFIG_JFFS2_FS_DEBUG=0
++# CONFIG_JFFS2_FS_WRITEBUFFER 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_NETWORK_FILESYSTEMS is not set
++# CONFIG_NLS is not set
++# CONFIG_DLM is not set
++# CONFIG_INSTRUMENTATION is not set
++
++#
++# Kernel hacking
++#
++# CONFIG_PRINTK_TIME is not set
++CONFIG_ENABLE_WARN_DEPRECATED=y
++CONFIG_ENABLE_MUST_CHECK=y
++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 is not set
++# CONFIG_DEBUG_BUGVERBOSE is not set
++# CONFIG_SAMPLES 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_CRC_CCITT is not set
++# 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_HAS_IOMEM=y
++CONFIG_HAS_IOPORT=y
++CONFIG_HAS_DMA=y
+diff --git a/arch/avr32/kernel/Makefile b/arch/avr32/kernel/Makefile
+index 2d6d48f..e4b6d12 100644
+--- a/arch/avr32/kernel/Makefile
++++ b/arch/avr32/kernel/Makefile
+@@ -6,9 +6,10 @@ extra-y				:= head.o vmlinux.lds
+ 
+ obj-$(CONFIG_SUBARCH_AVR32B)	+= entry-avr32b.o
+ obj-y				+= syscall_table.o syscall-stubs.o irq.o
+-obj-y				+= setup.o traps.o semaphore.o ptrace.o
++obj-y				+= setup.o traps.o semaphore.o ocd.o ptrace.o
+ obj-y				+= signal.o sys_avr32.o process.o time.o
+ obj-y				+= init_task.o switch_to.o cpu.o
+ obj-$(CONFIG_MODULES)		+= module.o avr32_ksyms.o
+ obj-$(CONFIG_KPROBES)		+= kprobes.o
+ obj-$(CONFIG_STACKTRACE)	+= stacktrace.o
++obj-$(CONFIG_NMI_DEBUGGING)	+= nmi_debug.o
+diff --git a/arch/avr32/kernel/cpu.c b/arch/avr32/kernel/cpu.c
+index 2714cf6..b8409ca 100644
+--- a/arch/avr32/kernel/cpu.c
++++ b/arch/avr32/kernel/cpu.c
+@@ -13,6 +13,7 @@
+ #include <linux/percpu.h>
+ #include <linux/param.h>
+ #include <linux/errno.h>
++#include <linux/clk.h>
+ 
+ #include <asm/setup.h>
+ #include <asm/sysreg.h>
+@@ -187,9 +188,20 @@ static int __init topology_init(void)
+ 
+ subsys_initcall(topology_init);
+ 
++struct chip_id_map {
++	u16	mid;
++	u16	pn;
++	const char *name;
++};
++
++static const struct chip_id_map chip_names[] = {
++	{ .mid = 0x1f, .pn = 0x1e82, .name = "AT32AP700x" },
++};
++#define NR_CHIP_NAMES ARRAY_SIZE(chip_names)
++
+ static const char *cpu_names[] = {
+ 	"Morgan",
+-	"AP7000",
++	"AP7",
+ };
+ #define NR_CPU_NAMES ARRAY_SIZE(cpu_names)
+ 
+@@ -206,12 +218,32 @@ static const char *mmu_types[] = {
+ 	"MPU"
+ };
+ 
++static const char *cpu_feature_flags[] = {
++	"rmw", "dsp", "simd", "ocd", "perfctr", "java", "fpu",
++};
++
++static const char *get_chip_name(struct avr32_cpuinfo *cpu)
++{
++	unsigned int i;
++	unsigned int mid = avr32_get_manufacturer_id(cpu);
++	unsigned int pn = avr32_get_product_number(cpu);
++
++	for (i = 0; i < NR_CHIP_NAMES; i++) {
++		if (chip_names[i].mid == mid && chip_names[i].pn == pn)
++			return chip_names[i].name;
++	}
++
++	return "(unknown)";
++}
++
+ void __init setup_processor(void)
+ {
+ 	unsigned long config0, config1;
+ 	unsigned long features;
+ 	unsigned cpu_id, cpu_rev, arch_id, arch_rev, mmu_type;
++	unsigned device_id;
+ 	unsigned tmp;
++	unsigned i;
+ 
+ 	config0 = sysreg_read(CONFIG0);
+ 	config1 = sysreg_read(CONFIG1);
+@@ -221,11 +253,14 @@ void __init setup_processor(void)
+ 	arch_rev = SYSREG_BFEXT(AR, config0);
+ 	mmu_type = SYSREG_BFEXT(MMUT, config0);
+ 
++	device_id = ocd_read(DID);
++
+ 	boot_cpu_data.arch_type = arch_id;
+ 	boot_cpu_data.cpu_type = cpu_id;
+ 	boot_cpu_data.arch_revision = arch_rev;
+ 	boot_cpu_data.cpu_revision = cpu_rev;
+ 	boot_cpu_data.tlb_config = mmu_type;
++	boot_cpu_data.device_id = device_id;
+ 
+ 	tmp = SYSREG_BFEXT(ILSZ, config1);
+ 	if (tmp) {
+@@ -247,41 +282,34 @@ void __init setup_processor(void)
+ 		return;
+ 	}
+ 
+-	printk ("CPU: %s [%02x] revision %d (%s revision %d)\n",
++	printk ("CPU: %s chip revision %c\n", get_chip_name(&boot_cpu_data),
++			avr32_get_chip_revision(&boot_cpu_data) + 'A');
++	printk ("CPU: %s [%02x] core revision %d (%s arch revision %d)\n",
+ 		cpu_names[cpu_id], cpu_id, cpu_rev,
+ 		arch_names[arch_id], arch_rev);
+ 	printk ("CPU: MMU configuration: %s\n", mmu_types[mmu_type]);
+ 
+ 	printk ("CPU: features:");
+ 	features = 0;
+-	if (config0 & SYSREG_BIT(CONFIG0_R)) {
++	if (config0 & SYSREG_BIT(CONFIG0_R))
+ 		features |= AVR32_FEATURE_RMW;
+-		printk(" rmw");
+-	}
+-	if (config0 & SYSREG_BIT(CONFIG0_D)) {
++	if (config0 & SYSREG_BIT(CONFIG0_D))
+ 		features |= AVR32_FEATURE_DSP;
+-		printk(" dsp");
+-	}
+-	if (config0 & SYSREG_BIT(CONFIG0_S)) {
++	if (config0 & SYSREG_BIT(CONFIG0_S))
+ 		features |= AVR32_FEATURE_SIMD;
+-		printk(" simd");
+-	}
+-	if (config0 & SYSREG_BIT(CONFIG0_O)) {
++	if (config0 & SYSREG_BIT(CONFIG0_O))
+ 		features |= AVR32_FEATURE_OCD;
+-		printk(" ocd");
+-	}
+-	if (config0 & SYSREG_BIT(CONFIG0_P)) {
++	if (config0 & SYSREG_BIT(CONFIG0_P))
+ 		features |= AVR32_FEATURE_PCTR;
+-		printk(" perfctr");
+-	}
+-	if (config0 & SYSREG_BIT(CONFIG0_J)) {
++	if (config0 & SYSREG_BIT(CONFIG0_J))
+ 		features |= AVR32_FEATURE_JAVA;
+-		printk(" java");
+-	}
+-	if (config0 & SYSREG_BIT(CONFIG0_F)) {
++	if (config0 & SYSREG_BIT(CONFIG0_F))
+ 		features |= AVR32_FEATURE_FPU;
+-		printk(" fpu");
+-	}
++
++	for (i = 0; i < ARRAY_SIZE(cpu_feature_flags); i++)
++		if (features & (1 << i))
++			printk(" %s", cpu_feature_flags[i]);
++
+ 	printk("\n");
+ 	boot_cpu_data.features = features;
+ }
+@@ -291,6 +319,8 @@ static int c_show(struct seq_file *m, void *v)
+ {
+ 	unsigned int icache_size, dcache_size;
+ 	unsigned int cpu = smp_processor_id();
++	unsigned int freq;
++	unsigned int i;
+ 
+ 	icache_size = boot_cpu_data.icache.ways *
+ 		boot_cpu_data.icache.sets *
+@@ -301,15 +331,21 @@ static int c_show(struct seq_file *m, void *v)
+ 
+ 	seq_printf(m, "processor\t: %d\n", cpu);
+ 
++	seq_printf(m, "chip type\t: %s revision %c\n",
++			get_chip_name(&boot_cpu_data),
++			avr32_get_chip_revision(&boot_cpu_data) + 'A');
+ 	if (boot_cpu_data.arch_type < NR_ARCH_NAMES)
+-		seq_printf(m, "cpu family\t: %s revision %d\n",
++		seq_printf(m, "cpu arch\t: %s revision %d\n",
+ 			   arch_names[boot_cpu_data.arch_type],
+ 			   boot_cpu_data.arch_revision);
+ 	if (boot_cpu_data.cpu_type < NR_CPU_NAMES)
+-		seq_printf(m, "cpu type\t: %s revision %d\n",
++		seq_printf(m, "cpu core\t: %s revision %d\n",
+ 			   cpu_names[boot_cpu_data.cpu_type],
+ 			   boot_cpu_data.cpu_revision);
+ 
++	freq = (clk_get_rate(boot_cpu_data.clk) + 500) / 1000;
++	seq_printf(m, "cpu MHz\t\t: %u.%03u\n", freq / 1000, freq % 1000);
++
+ 	seq_printf(m, "i-cache\t\t: %dK (%u ways x %u sets x %u)\n",
+ 		   icache_size >> 10,
+ 		   boot_cpu_data.icache.ways,
+@@ -320,7 +356,13 @@ static int c_show(struct seq_file *m, void *v)
+ 		   boot_cpu_data.dcache.ways,
+ 		   boot_cpu_data.dcache.sets,
+ 		   boot_cpu_data.dcache.linesz);
+-	seq_printf(m, "bogomips\t: %lu.%02lu\n",
++
++	seq_printf(m, "features\t:");
++	for (i = 0; i < ARRAY_SIZE(cpu_feature_flags); i++)
++		if (boot_cpu_data.features & (1 << i))
++			seq_printf(m, " %s", cpu_feature_flags[i]);
++
++	seq_printf(m, "\nbogomips\t: %lu.%02lu\n",
+ 		   boot_cpu_data.loops_per_jiffy / (500000/HZ),
+ 		   (boot_cpu_data.loops_per_jiffy / (5000/HZ)) % 100);
+ 
+@@ -343,7 +385,7 @@ static void c_stop(struct seq_file *m, void *v)
+ 
+ }
+ 
+-struct seq_operations cpuinfo_op = {
++const struct seq_operations cpuinfo_op = {
+ 	.start	= c_start,
+ 	.next	= c_next,
+ 	.stop	= c_stop,
+diff --git a/arch/avr32/kernel/irq.c b/arch/avr32/kernel/irq.c
+index 61f2de2..a8e767d 100644
+--- a/arch/avr32/kernel/irq.c
++++ b/arch/avr32/kernel/irq.c
+@@ -25,6 +25,17 @@ void ack_bad_irq(unsigned int irq)
+ 	printk("unexpected IRQ %u\n", irq);
+ }
+ 
++/* May be overridden by platform code */
++int __weak nmi_enable(void)
++{
++	return -ENOSYS;
++}
++
++void __weak nmi_disable(void)
++{
++
++}
++
+ #ifdef CONFIG_PROC_FS
+ int show_interrupts(struct seq_file *p, void *v)
+ {
+diff --git a/arch/avr32/kernel/kprobes.c b/arch/avr32/kernel/kprobes.c
+index 799ba89..f820e9f 100644
+--- a/arch/avr32/kernel/kprobes.c
++++ b/arch/avr32/kernel/kprobes.c
+@@ -48,6 +48,7 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p)
+ void __kprobes arch_arm_kprobe(struct kprobe *p)
+ {
+ 	pr_debug("arming kprobe at %p\n", p->addr);
++	ocd_enable(NULL);
+ 	*p->addr = BREAKPOINT_INSTRUCTION;
+ 	flush_icache_range((unsigned long)p->addr,
+ 			   (unsigned long)p->addr + sizeof(kprobe_opcode_t));
+@@ -56,6 +57,7 @@ void __kprobes arch_arm_kprobe(struct kprobe *p)
+ void __kprobes arch_disarm_kprobe(struct kprobe *p)
+ {
+ 	pr_debug("disarming kprobe at %p\n", p->addr);
++	ocd_disable(NULL);
+ 	*p->addr = p->opcode;
+ 	flush_icache_range((unsigned long)p->addr,
+ 			   (unsigned long)p->addr + sizeof(kprobe_opcode_t));
+@@ -260,9 +262,6 @@ int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
+ 
+ int __init arch_init_kprobes(void)
+ {
+-	printk("KPROBES: Enabling monitor mode (MM|DBE)...\n");
+-	ocd_write(DC, (1 << OCD_DC_MM_BIT) | (1 << OCD_DC_DBE_BIT));
+-
+ 	/* TODO: Register kretprobe trampoline */
+ 	return 0;
+ }
+diff --git a/arch/avr32/kernel/nmi_debug.c b/arch/avr32/kernel/nmi_debug.c
+new file mode 100644
+index 0000000..3414b85
+--- /dev/null
++++ b/arch/avr32/kernel/nmi_debug.c
+@@ -0,0 +1,82 @@
++/*
++ * 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 version 2 as
++ * published by the Free Software Foundation.
++ */
++#include <linux/delay.h>
++#include <linux/kdebug.h>
++#include <linux/notifier.h>
++#include <linux/sched.h>
++
++#include <asm/irq.h>
++
++enum nmi_action {
++	NMI_SHOW_STATE	= 1 << 0,
++	NMI_SHOW_REGS	= 1 << 1,
++	NMI_DIE		= 1 << 2,
++	NMI_DEBOUNCE	= 1 << 3,
++};
++
++static unsigned long nmi_actions;
++
++static int nmi_debug_notify(struct notifier_block *self,
++		unsigned long val, void *data)
++{
++	struct die_args *args = data;
++
++	if (likely(val != DIE_NMI))
++		return NOTIFY_DONE;
++
++	if (nmi_actions & NMI_SHOW_STATE)
++		show_state();
++	if (nmi_actions & NMI_SHOW_REGS)
++		show_regs(args->regs);
++	if (nmi_actions & NMI_DEBOUNCE)
++		mdelay(10);
++	if (nmi_actions & NMI_DIE)
++		return NOTIFY_BAD;
++
++	return NOTIFY_OK;
++}
++
++static struct notifier_block nmi_debug_nb = {
++	.notifier_call = nmi_debug_notify,
++};
++
++static int __init nmi_debug_setup(char *str)
++{
++	char *p, *sep;
++
++	register_die_notifier(&nmi_debug_nb);
++	if (nmi_enable()) {
++		printk(KERN_WARNING "Unable to enable NMI.\n");
++		return 0;
++	}
++
++	if (*str != '=')
++		return 0;
++
++	for (p = str + 1; *p; p = sep + 1) {
++		sep = strchr(p, ',');
++		if (sep)
++			*sep = 0;
++		if (strcmp(p, "state") == 0)
++			nmi_actions |= NMI_SHOW_STATE;
++		else if (strcmp(p, "regs") == 0)
++			nmi_actions |= NMI_SHOW_REGS;
++		else if (strcmp(p, "debounce") == 0)
++			nmi_actions |= NMI_DEBOUNCE;
++		else if (strcmp(p, "die") == 0)
++			nmi_actions |= NMI_DIE;
++		else
++			printk(KERN_WARNING "NMI: Unrecognized action `%s'\n",
++				p);
++		if (!sep)
++			break;
++	}
++
++	return 0;
++}
++__setup("nmi_debug", nmi_debug_setup);
+diff --git a/arch/avr32/kernel/ocd.c b/arch/avr32/kernel/ocd.c
+new file mode 100644
+index 0000000..c4f0232
+--- /dev/null
++++ b/arch/avr32/kernel/ocd.c
+@@ -0,0 +1,163 @@
++/*
++ * 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 version 2 as
++ * published by the Free Software Foundation.
++ */
++#include <linux/init.h>
++#include <linux/sched.h>
++#include <linux/spinlock.h>
++
++#include <asm/ocd.h>
++
++static long ocd_count;
++static spinlock_t ocd_lock;
++
++/**
++ * ocd_enable - enable on-chip debugging
++ * @child: task to be debugged
++ *
++ * If @child is non-NULL, ocd_enable() first checks if debugging has
++ * already been enabled for @child, and if it has, does nothing.
++ *
++ * If @child is NULL (e.g. when debugging the kernel), or debugging
++ * has not already been enabled for it, ocd_enable() increments the
++ * reference count and enables the debugging hardware.
++ */
++void ocd_enable(struct task_struct *child)
++{
++	u32 dc;
++
++	if (child)
++		pr_debug("ocd_enable: child=%s [%u]\n",
++				child->comm, child->pid);
++	else
++		pr_debug("ocd_enable (no child)\n");
++
++	if (!child || !test_and_set_tsk_thread_flag(child, TIF_DEBUG)) {
++		spin_lock(&ocd_lock);
++		ocd_count++;
++		dc = ocd_read(DC);
++		dc |= (1 << OCD_DC_MM_BIT) | (1 << OCD_DC_DBE_BIT);
++		ocd_write(DC, dc);
++		spin_unlock(&ocd_lock);
++	}
++}
++
++/**
++ * ocd_disable - disable on-chip debugging
++ * @child: task that was being debugged, but isn't anymore
++ *
++ * If @child is non-NULL, ocd_disable() checks if debugging is enabled
++ * for @child, and if it isn't, does nothing.
++ *
++ * If @child is NULL (e.g. when debugging the kernel), or debugging is
++ * enabled, ocd_disable() decrements the reference count, and if it
++ * reaches zero, disables the debugging hardware.
++ */
++void ocd_disable(struct task_struct *child)
++{
++	u32 dc;
++
++	if (!child)
++		pr_debug("ocd_disable (no child)\n");
++	else if (test_tsk_thread_flag(child, TIF_DEBUG))
++		pr_debug("ocd_disable: child=%s [%u]\n",
++				child->comm, child->pid);
++
++	if (!child || test_and_clear_tsk_thread_flag(child, TIF_DEBUG)) {
++		spin_lock(&ocd_lock);
++		ocd_count--;
++
++		WARN_ON(ocd_count < 0);
++
++		if (ocd_count <= 0) {
++			dc = ocd_read(DC);
++			dc &= ~((1 << OCD_DC_MM_BIT) | (1 << OCD_DC_DBE_BIT));
++			ocd_write(DC, dc);
++		}
++		spin_unlock(&ocd_lock);
++	}
++}
++
++#ifdef CONFIG_DEBUG_FS
++#include <linux/debugfs.h>
++#include <linux/module.h>
++
++static struct dentry *ocd_debugfs_root;
++static struct dentry *ocd_debugfs_DC;
++static struct dentry *ocd_debugfs_DS;
++static struct dentry *ocd_debugfs_count;
++
++static u64 ocd_DC_get(void *data)
++{
++	return ocd_read(DC);
++}
++static void ocd_DC_set(void *data, u64 val)
++{
++	ocd_write(DC, val);
++}
++DEFINE_SIMPLE_ATTRIBUTE(fops_DC, ocd_DC_get, ocd_DC_set, "0x%08llx\n");
++
++static u64 ocd_DS_get(void *data)
++{
++	return ocd_read(DS);
++}
++DEFINE_SIMPLE_ATTRIBUTE(fops_DS, ocd_DS_get, NULL, "0x%08llx\n");
++
++static u64 ocd_count_get(void *data)
++{
++	return ocd_count;
++}
++DEFINE_SIMPLE_ATTRIBUTE(fops_count, ocd_count_get, NULL, "%lld\n");
++
++static void ocd_debugfs_init(void)
++{
++	struct dentry *root;
++
++	root = debugfs_create_dir("ocd", NULL);
++	if (IS_ERR(root) || !root)
++		goto err_root;
++	ocd_debugfs_root = root;
++
++	ocd_debugfs_DC = debugfs_create_file("DC", S_IRUSR | S_IWUSR,
++				root, NULL, &fops_DC);
++	if (!ocd_debugfs_DC)
++		goto err_DC;
++
++	ocd_debugfs_DS = debugfs_create_file("DS", S_IRUSR, root,
++				NULL, &fops_DS);
++	if (!ocd_debugfs_DS)
++		goto err_DS;
++
++	ocd_debugfs_count = debugfs_create_file("count", S_IRUSR, root,
++				NULL, &fops_count);
++	if (!ocd_debugfs_count)
++		goto err_count;
++
++	return;
++
++err_count:
++	debugfs_remove(ocd_debugfs_DS);
++err_DS:
++	debugfs_remove(ocd_debugfs_DC);
++err_DC:
++	debugfs_remove(ocd_debugfs_root);
++err_root:
++	printk(KERN_WARNING "OCD: Failed to create debugfs entries\n");
++}
++#else
++static inline void ocd_debugfs_init(void)
++{
++
++}
++#endif
++
++static int __init ocd_init(void)
++{
++	spin_lock_init(&ocd_lock);
++	ocd_debugfs_init();
++	return 0;
++}
++arch_initcall(ocd_init);
+diff --git a/arch/avr32/kernel/process.c b/arch/avr32/kernel/process.c
+index 9d6dac8..eaaa69b 100644
+--- a/arch/avr32/kernel/process.c
++++ b/arch/avr32/kernel/process.c
+@@ -103,7 +103,7 @@ EXPORT_SYMBOL(kernel_thread);
+  */
+ void exit_thread(void)
+ {
+-	/* nothing to do */
++	ocd_disable(current);
+ }
+ 
+ void flush_thread(void)
+@@ -345,6 +345,9 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
+ 	p->thread.cpu_context.ksp = (unsigned long)childregs;
+ 	p->thread.cpu_context.pc = (unsigned long)ret_from_fork;
+ 
++	if ((clone_flags & CLONE_PTRACE) && test_thread_flag(TIF_DEBUG))
++		ocd_enable(p);
++
+ 	return 0;
+ }
+ 
+diff --git a/arch/avr32/kernel/ptrace.c b/arch/avr32/kernel/ptrace.c
+index 002369e..1fed38f 100644
+--- a/arch/avr32/kernel/ptrace.c
++++ b/arch/avr32/kernel/ptrace.c
+@@ -58,6 +58,7 @@ void ptrace_disable(struct task_struct *child)
+ {
+ 	clear_tsk_thread_flag(child, TIF_SINGLE_STEP);
+ 	clear_tsk_thread_flag(child, TIF_BREAKPOINT);
++	ocd_disable(child);
+ }
+ 
+ /*
+@@ -144,10 +145,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
+ {
+ 	int ret;
+ 
+-	pr_debug("ptrace: Enabling monitor mode...\n");
+-	ocd_write(DC, ocd_read(DC) | (1 << OCD_DC_MM_BIT)
+-			| (1 << OCD_DC_DBE_BIT));
+-
+ 	switch (request) {
+ 	/* Read the word at location addr in the child process */
+ 	case PTRACE_PEEKTEXT:
+diff --git a/arch/avr32/kernel/signal.c b/arch/avr32/kernel/signal.c
+index 0ec1485..5616a00 100644
+--- a/arch/avr32/kernel/signal.c
++++ b/arch/avr32/kernel/signal.c
+@@ -270,19 +270,12 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset, int syscall)
+ 	if (!user_mode(regs))
+ 		return 0;
+ 
+-	if (try_to_freeze()) {
+-		signr = 0;
+-		if (!signal_pending(current))
+-			goto no_signal;
+-	}
+-
+ 	if (test_thread_flag(TIF_RESTORE_SIGMASK))
+ 		oldset = &current->saved_sigmask;
+ 	else if (!oldset)
+ 		oldset = &current->blocked;
+ 
+ 	signr = get_signal_to_deliver(&info, &ka, regs, NULL);
+-no_signal:
+ 	if (syscall) {
+ 		switch (regs->r12) {
+ 		case -ERESTART_RESTARTBLOCK:
+diff --git a/arch/avr32/kernel/time.c b/arch/avr32/kernel/time.c
+index 7014a35..36a46c3 100644
+--- a/arch/avr32/kernel/time.c
++++ b/arch/avr32/kernel/time.c
+@@ -214,7 +214,7 @@ void __init time_init(void)
+ }
+ 
+ static struct sysdev_class timer_class = {
+-	set_kset_name("timer"),
++	.name = "timer",
+ };
+ 
+ static struct sys_device timer_device = {
+diff --git a/arch/avr32/kernel/traps.c b/arch/avr32/kernel/traps.c
+index 870c075..cf6f686 100644
+--- a/arch/avr32/kernel/traps.c
++++ b/arch/avr32/kernel/traps.c
+@@ -9,6 +9,7 @@
+ #include <linux/bug.h>
+ #include <linux/init.h>
+ #include <linux/kallsyms.h>
++#include <linux/kdebug.h>
+ #include <linux/module.h>
+ #include <linux/notifier.h>
+ #include <linux/sched.h>
+@@ -107,9 +108,23 @@ void _exception(long signr, struct pt_regs *regs, int code,
+ 
+ asmlinkage void do_nmi(unsigned long ecr, struct pt_regs *regs)
+ {
+-	printk(KERN_ALERT "Got Non-Maskable Interrupt, dumping regs\n");
+-	show_regs_log_lvl(regs, KERN_ALERT);
+-	show_stack_log_lvl(current, regs->sp, regs, KERN_ALERT);
++	int ret;
++
++	nmi_enter();
++
++	ret = notify_die(DIE_NMI, "NMI", regs, 0, ecr, SIGINT);
++	switch (ret) {
++	case NOTIFY_OK:
++	case NOTIFY_STOP:
++		return;
++	case NOTIFY_BAD:
++		die("Fatal Non-Maskable Interrupt", regs, SIGINT);
++	default:
++		break;
++	}
++
++	printk(KERN_ALERT "Got NMI, but nobody cared. Disabling...\n");
++	nmi_disable();
+ }
+ 
+ asmlinkage void do_critical_exception(unsigned long ecr, struct pt_regs *regs)
+diff --git a/arch/avr32/mach-at32ap/Kconfig b/arch/avr32/mach-at32ap/Kconfig
+index eb30783..a7bbcc8 100644
+--- a/arch/avr32/mach-at32ap/Kconfig
++++ b/arch/avr32/mach-at32ap/Kconfig
+@@ -3,9 +3,9 @@ if PLATFORM_AT32AP
+ menu "Atmel AVR32 AP options"
+ 
+ choice
+-	prompt "AT32AP7000 static memory bus width"
+-	depends on CPU_AT32AP7000
+-	default AP7000_16_BIT_SMC
++	prompt "AT32AP700x static memory bus width"
++	depends on CPU_AT32AP700X
++	default AP700X_16_BIT_SMC
+ 	help
+ 	  Define the width of the AP7000 external static memory interface.
+ 	  This is used to determine how to mangle the address and/or data
+@@ -15,13 +15,13 @@ choice
+ 	  width for all chip selects, excluding the flash (which is using
+ 	  raw access and is thus not affected by any of this.)
+ 
+-config AP7000_32_BIT_SMC
++config AP700X_32_BIT_SMC
+ 	bool "32 bit"
+ 
+-config AP7000_16_BIT_SMC
++config AP700X_16_BIT_SMC
+ 	bool "16 bit"
+ 
+-config AP7000_8_BIT_SMC
++config AP700X_8_BIT_SMC
+ 	bool "8 bit"
+ 
+ endchoice
+diff --git a/arch/avr32/mach-at32ap/Makefile b/arch/avr32/mach-at32ap/Makefile
+index a8b4450..5e9f821 100644
+--- a/arch/avr32/mach-at32ap/Makefile
++++ b/arch/avr32/mach-at32ap/Makefile
+@@ -1,4 +1,4 @@
+ obj-y				+= at32ap.o clock.o intc.o extint.o pio.o hsmc.o
+-obj-$(CONFIG_CPU_AT32AP7000)	+= at32ap7000.o
+-obj-$(CONFIG_CPU_AT32AP7000)	+= time-tc.o
++obj-$(CONFIG_CPU_AT32AP700X)	+= at32ap700x.o
++obj-$(CONFIG_CPU_AT32AP700X)	+= time-tc.o
+ obj-$(CONFIG_CPU_FREQ_AT32AP)	+= cpufreq.o
+diff --git a/arch/avr32/mach-at32ap/at32ap7000.c b/arch/avr32/mach-at32ap/at32ap7000.c
+deleted file mode 100644
+index 7c4388f..0000000
+--- a/arch/avr32/mach-at32ap/at32ap7000.c
++++ /dev/null
+@@ -1,1730 +0,0 @@
+-/*
+- * Copyright (C) 2005-2006 Atmel 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/clk.h>
+-#include <linux/fb.h>
+-#include <linux/init.h>
+-#include <linux/platform_device.h>
+-#include <linux/dma-mapping.h>
+-#include <linux/spi/spi.h>
+-
+-#include <asm/io.h>
+-
+-#include <asm/arch/at32ap7000.h>
+-#include <asm/arch/board.h>
+-#include <asm/arch/portmux.h>
+-
+-#include <video/atmel_lcdc.h>
+-
+-#include "clock.h"
+-#include "hmatrix.h"
+-#include "pio.h"
+-#include "pm.h"
+-
+-
+-#define PBMEM(base)					\
+-	{						\
+-		.start		= base,			\
+-		.end		= base + 0x3ff,		\
+-		.flags		= IORESOURCE_MEM,	\
+-	}
+-#define IRQ(num)					\
+-	{						\
+-		.start		= num,			\
+-		.end		= num,			\
+-		.flags		= IORESOURCE_IRQ,	\
+-	}
+-#define NAMED_IRQ(num, _name)				\
+-	{						\
+-		.start		= num,			\
+-		.end		= num,			\
+-		.name		= _name,		\
+-		.flags		= IORESOURCE_IRQ,	\
+-	}
+-
+-/* REVISIT these assume *every* device supports DMA, but several
+- * don't ... tc, smc, pio, rtc, watchdog, pwm, ps2, and more.
+- */
+-#define DEFINE_DEV(_name, _id)					\
+-static u64 _name##_id##_dma_mask = DMA_32BIT_MASK;		\
+-static struct platform_device _name##_id##_device = {		\
+-	.name		= #_name,				\
+-	.id		= _id,					\
+-	.dev		= {					\
+-		.dma_mask = &_name##_id##_dma_mask,		\
+-		.coherent_dma_mask = DMA_32BIT_MASK,		\
+-	},							\
+-	.resource	= _name##_id##_resource,		\
+-	.num_resources	= ARRAY_SIZE(_name##_id##_resource),	\
+-}
+-#define DEFINE_DEV_DATA(_name, _id)				\
+-static u64 _name##_id##_dma_mask = DMA_32BIT_MASK;		\
+-static struct platform_device _name##_id##_device = {		\
+-	.name		= #_name,				\
+-	.id		= _id,					\
+-	.dev		= {					\
+-		.dma_mask = &_name##_id##_dma_mask,		\
+-		.platform_data	= &_name##_id##_data,		\
+-		.coherent_dma_mask = DMA_32BIT_MASK,		\
+-	},							\
+-	.resource	= _name##_id##_resource,		\
+-	.num_resources	= ARRAY_SIZE(_name##_id##_resource),	\
+-}
+-
+-#define select_peripheral(pin, periph, flags)			\
+-	at32_select_periph(GPIO_PIN_##pin, GPIO_##periph, flags)
+-
+-#define DEV_CLK(_name, devname, bus, _index)			\
+-static struct clk devname##_##_name = {				\
+-	.name		= #_name,				\
+-	.dev		= &devname##_device.dev,		\
+-	.parent		= &bus##_clk,				\
+-	.mode		= bus##_clk_mode,			\
+-	.get_rate	= bus##_clk_get_rate,			\
+-	.index		= _index,				\
+-}
+-
+-static DEFINE_SPINLOCK(pm_lock);
+-
+-unsigned long at32ap7000_osc_rates[3] = {
+-	[0] = 32768,
+-	/* FIXME: these are ATSTK1002-specific */
+-	[1] = 20000000,
+-	[2] = 12000000,
+-};
+-
+-static unsigned long osc_get_rate(struct clk *clk)
+-{
+-	return at32ap7000_osc_rates[clk->index];
+-}
+-
+-static unsigned long pll_get_rate(struct clk *clk, unsigned long control)
+-{
+-	unsigned long div, mul, rate;
+-
+-	if (!(control & PM_BIT(PLLEN)))
+-		return 0;
+-
+-	div = PM_BFEXT(PLLDIV, control) + 1;
+-	mul = PM_BFEXT(PLLMUL, control) + 1;
+-
+-	rate = clk->parent->get_rate(clk->parent);
+-	rate = (rate + div / 2) / div;
+-	rate *= mul;
+-
+-	return rate;
+-}
+-
+-static unsigned long pll0_get_rate(struct clk *clk)
+-{
+-	u32 control;
+-
+-	control = pm_readl(PLL0);
+-
+-	return pll_get_rate(clk, control);
+-}
+-
+-static unsigned long pll1_get_rate(struct clk *clk)
+-{
+-	u32 control;
+-
+-	control = pm_readl(PLL1);
+-
+-	return pll_get_rate(clk, control);
+-}
+-
+-/*
+- * The AT32AP7000 has five primary clock sources: One 32kHz
+- * oscillator, two crystal oscillators and two PLLs.
+- */
+-static struct clk osc32k = {
+-	.name		= "osc32k",
+-	.get_rate	= osc_get_rate,
+-	.users		= 1,
+-	.index		= 0,
+-};
+-static struct clk osc0 = {
+-	.name		= "osc0",
+-	.get_rate	= osc_get_rate,
+-	.users		= 1,
+-	.index		= 1,
+-};
+-static struct clk osc1 = {
+-	.name		= "osc1",
+-	.get_rate	= osc_get_rate,
+-	.index		= 2,
+-};
+-static struct clk pll0 = {
+-	.name		= "pll0",
+-	.get_rate	= pll0_get_rate,
+-	.parent		= &osc0,
+-};
+-static struct clk pll1 = {
+-	.name		= "pll1",
+-	.get_rate	= pll1_get_rate,
+-	.parent		= &osc0,
+-};
+-
+-/*
+- * The main clock can be either osc0 or pll0.  The boot loader may
+- * have chosen one for us, so we don't really know which one until we
+- * have a look at the SM.
+- */
+-static struct clk *main_clock;
+-
+-/*
+- * Synchronous clocks are generated from the main clock. The clocks
+- * must satisfy the constraint
+- *   fCPU >= fHSB >= fPB
+- * i.e. each clock must not be faster than its parent.
+- */
+-static unsigned long bus_clk_get_rate(struct clk *clk, unsigned int shift)
+-{
+-	return main_clock->get_rate(main_clock) >> shift;
+-};
+-
+-static void cpu_clk_mode(struct clk *clk, int enabled)
+-{
+-	unsigned long flags;
+-	u32 mask;
+-
+-	spin_lock_irqsave(&pm_lock, flags);
+-	mask = pm_readl(CPU_MASK);
+-	if (enabled)
+-		mask |= 1 << clk->index;
+-	else
+-		mask &= ~(1 << clk->index);
+-	pm_writel(CPU_MASK, mask);
+-	spin_unlock_irqrestore(&pm_lock, flags);
+-}
+-
+-static unsigned long cpu_clk_get_rate(struct clk *clk)
+-{
+-	unsigned long cksel, shift = 0;
+-
+-	cksel = pm_readl(CKSEL);
+-	if (cksel & PM_BIT(CPUDIV))
+-		shift = PM_BFEXT(CPUSEL, cksel) + 1;
+-
+-	return bus_clk_get_rate(clk, shift);
+-}
+-
+-static long cpu_clk_set_rate(struct clk *clk, unsigned long rate, int apply)
+-{
+-	u32 control;
+-	unsigned long parent_rate, child_div, actual_rate, div;
+-
+-	parent_rate = clk->parent->get_rate(clk->parent);
+-	control = pm_readl(CKSEL);
+-
+-	if (control & PM_BIT(HSBDIV))
+-		child_div = 1 << (PM_BFEXT(HSBSEL, control) + 1);
+-	else
+-		child_div = 1;
+-
+-	if (rate > 3 * (parent_rate / 4) || child_div == 1) {
+-		actual_rate = parent_rate;
+-		control &= ~PM_BIT(CPUDIV);
+-	} else {
+-		unsigned int cpusel;
+-		div = (parent_rate + rate / 2) / rate;
+-		if (div > child_div)
+-			div = child_div;
+-		cpusel = (div > 1) ? (fls(div) - 2) : 0;
+-		control = PM_BIT(CPUDIV) | PM_BFINS(CPUSEL, cpusel, control);
+-		actual_rate = parent_rate / (1 << (cpusel + 1));
+-	}
+-
+-	pr_debug("clk %s: new rate %lu (actual rate %lu)\n",
+-			clk->name, rate, actual_rate);
+-
+-	if (apply)
+-		pm_writel(CKSEL, control);
+-
+-	return actual_rate;
+-}
+-
+-static void hsb_clk_mode(struct clk *clk, int enabled)
+-{
+-	unsigned long flags;
+-	u32 mask;
+-
+-	spin_lock_irqsave(&pm_lock, flags);
+-	mask = pm_readl(HSB_MASK);
+-	if (enabled)
+-		mask |= 1 << clk->index;
+-	else
+-		mask &= ~(1 << clk->index);
+-	pm_writel(HSB_MASK, mask);
+-	spin_unlock_irqrestore(&pm_lock, flags);
+-}
+-
+-static unsigned long hsb_clk_get_rate(struct clk *clk)
+-{
+-	unsigned long cksel, shift = 0;
+-
+-	cksel = pm_readl(CKSEL);
+-	if (cksel & PM_BIT(HSBDIV))
+-		shift = PM_BFEXT(HSBSEL, cksel) + 1;
+-
+-	return bus_clk_get_rate(clk, shift);
+-}
+-
+-static void pba_clk_mode(struct clk *clk, int enabled)
+-{
+-	unsigned long flags;
+-	u32 mask;
+-
+-	spin_lock_irqsave(&pm_lock, flags);
+-	mask = pm_readl(PBA_MASK);
+-	if (enabled)
+-		mask |= 1 << clk->index;
+-	else
+-		mask &= ~(1 << clk->index);
+-	pm_writel(PBA_MASK, mask);
+-	spin_unlock_irqrestore(&pm_lock, flags);
+-}
+-
+-static unsigned long pba_clk_get_rate(struct clk *clk)
+-{
+-	unsigned long cksel, shift = 0;
+-
+-	cksel = pm_readl(CKSEL);
+-	if (cksel & PM_BIT(PBADIV))
+-		shift = PM_BFEXT(PBASEL, cksel) + 1;
+-
+-	return bus_clk_get_rate(clk, shift);
+-}
+-
+-static void pbb_clk_mode(struct clk *clk, int enabled)
+-{
+-	unsigned long flags;
+-	u32 mask;
+-
+-	spin_lock_irqsave(&pm_lock, flags);
+-	mask = pm_readl(PBB_MASK);
+-	if (enabled)
+-		mask |= 1 << clk->index;
+-	else
+-		mask &= ~(1 << clk->index);
+-	pm_writel(PBB_MASK, mask);
+-	spin_unlock_irqrestore(&pm_lock, flags);
+-}
+-
+-static unsigned long pbb_clk_get_rate(struct clk *clk)
+-{
+-	unsigned long cksel, shift = 0;
+-
+-	cksel = pm_readl(CKSEL);
+-	if (cksel & PM_BIT(PBBDIV))
+-		shift = PM_BFEXT(PBBSEL, cksel) + 1;
+-
+-	return bus_clk_get_rate(clk, shift);
+-}
+-
+-static struct clk cpu_clk = {
+-	.name		= "cpu",
+-	.get_rate	= cpu_clk_get_rate,
+-	.set_rate	= cpu_clk_set_rate,
+-	.users		= 1,
+-};
+-static struct clk hsb_clk = {
+-	.name		= "hsb",
+-	.parent		= &cpu_clk,
+-	.get_rate	= hsb_clk_get_rate,
+-};
+-static struct clk pba_clk = {
+-	.name		= "pba",
+-	.parent		= &hsb_clk,
+-	.mode		= hsb_clk_mode,
+-	.get_rate	= pba_clk_get_rate,
+-	.index		= 1,
+-};
+-static struct clk pbb_clk = {
+-	.name		= "pbb",
+-	.parent		= &hsb_clk,
+-	.mode		= hsb_clk_mode,
+-	.get_rate	= pbb_clk_get_rate,
+-	.users		= 1,
+-	.index		= 2,
+-};
+-
+-/* --------------------------------------------------------------------
+- *  Generic Clock operations
+- * -------------------------------------------------------------------- */
+-
+-static void genclk_mode(struct clk *clk, int enabled)
+-{
+-	u32 control;
+-
+-	control = pm_readl(GCCTRL(clk->index));
+-	if (enabled)
+-		control |= PM_BIT(CEN);
+-	else
+-		control &= ~PM_BIT(CEN);
+-	pm_writel(GCCTRL(clk->index), control);
+-}
+-
+-static unsigned long genclk_get_rate(struct clk *clk)
+-{
+-	u32 control;
+-	unsigned long div = 1;
+-
+-	control = pm_readl(GCCTRL(clk->index));
+-	if (control & PM_BIT(DIVEN))
+-		div = 2 * (PM_BFEXT(DIV, control) + 1);
+-
+-	return clk->parent->get_rate(clk->parent) / div;
+-}
+-
+-static long genclk_set_rate(struct clk *clk, unsigned long rate, int apply)
+-{
+-	u32 control;
+-	unsigned long parent_rate, actual_rate, div;
+-
+-	parent_rate = clk->parent->get_rate(clk->parent);
+-	control = pm_readl(GCCTRL(clk->index));
+-
+-	if (rate > 3 * parent_rate / 4) {
+-		actual_rate = parent_rate;
+-		control &= ~PM_BIT(DIVEN);
+-	} else {
+-		div = (parent_rate + rate) / (2 * rate) - 1;
+-		control = PM_BFINS(DIV, div, control) | PM_BIT(DIVEN);
+-		actual_rate = parent_rate / (2 * (div + 1));
+-	}
+-
+-	dev_dbg(clk->dev, "clk %s: new rate %lu (actual rate %lu)\n",
+-		clk->name, rate, actual_rate);
+-
+-	if (apply)
+-		pm_writel(GCCTRL(clk->index), control);
+-
+-	return actual_rate;
+-}
+-
+-int genclk_set_parent(struct clk *clk, struct clk *parent)
+-{
+-	u32 control;
+-
+-	dev_dbg(clk->dev, "clk %s: new parent %s (was %s)\n",
+-		clk->name, parent->name, clk->parent->name);
+-
+-	control = pm_readl(GCCTRL(clk->index));
+-
+-	if (parent == &osc1 || parent == &pll1)
+-		control |= PM_BIT(OSCSEL);
+-	else if (parent == &osc0 || parent == &pll0)
+-		control &= ~PM_BIT(OSCSEL);
+-	else
+-		return -EINVAL;
+-
+-	if (parent == &pll0 || parent == &pll1)
+-		control |= PM_BIT(PLLSEL);
+-	else
+-		control &= ~PM_BIT(PLLSEL);
+-
+-	pm_writel(GCCTRL(clk->index), control);
+-	clk->parent = parent;
+-
+-	return 0;
+-}
+-
+-static void __init genclk_init_parent(struct clk *clk)
+-{
+-	u32 control;
+-	struct clk *parent;
+-
+-	BUG_ON(clk->index > 7);
+-
+-	control = pm_readl(GCCTRL(clk->index));
+-	if (control & PM_BIT(OSCSEL))
+-		parent = (control & PM_BIT(PLLSEL)) ? &pll1 : &osc1;
+-	else
+-		parent = (control & PM_BIT(PLLSEL)) ? &pll0 : &osc0;
+-
+-	clk->parent = parent;
+-}
+-
+-/* --------------------------------------------------------------------
+- *  System peripherals
+- * -------------------------------------------------------------------- */
+-static struct resource at32_pm0_resource[] = {
+-	{
+-		.start	= 0xfff00000,
+-		.end	= 0xfff0007f,
+-		.flags	= IORESOURCE_MEM,
+-	},
+-	IRQ(20),
+-};
+-
+-static struct resource at32ap700x_rtc0_resource[] = {
+-	{
+-		.start	= 0xfff00080,
+-		.end	= 0xfff000af,
+-		.flags	= IORESOURCE_MEM,
+-	},
+-	IRQ(21),
+-};
+-
+-static struct resource at32_wdt0_resource[] = {
+-	{
+-		.start	= 0xfff000b0,
+-		.end	= 0xfff000cf,
+-		.flags	= IORESOURCE_MEM,
+-	},
+-};
+-
+-static struct resource at32_eic0_resource[] = {
+-	{
+-		.start	= 0xfff00100,
+-		.end	= 0xfff0013f,
+-		.flags	= IORESOURCE_MEM,
+-	},
+-	IRQ(19),
+-};
+-
+-DEFINE_DEV(at32_pm, 0);
+-DEFINE_DEV(at32ap700x_rtc, 0);
+-DEFINE_DEV(at32_wdt, 0);
+-DEFINE_DEV(at32_eic, 0);
+-
+-/*
+- * Peripheral clock for PM, RTC, WDT and EIC. PM will ensure that this
+- * is always running.
+- */
+-static struct clk at32_pm_pclk = {
+-	.name		= "pclk",
+-	.dev		= &at32_pm0_device.dev,
+-	.parent		= &pbb_clk,
+-	.mode		= pbb_clk_mode,
+-	.get_rate	= pbb_clk_get_rate,
+-	.users		= 1,
+-	.index		= 0,
+-};
+-
+-static struct resource intc0_resource[] = {
+-	PBMEM(0xfff00400),
+-};
+-struct platform_device at32_intc0_device = {
+-	.name		= "intc",
+-	.id		= 0,
+-	.resource	= intc0_resource,
+-	.num_resources	= ARRAY_SIZE(intc0_resource),
+-};
+-DEV_CLK(pclk, at32_intc0, pbb, 1);
+-
+-static struct clk ebi_clk = {
+-	.name		= "ebi",
+-	.parent		= &hsb_clk,
+-	.mode		= hsb_clk_mode,
+-	.get_rate	= hsb_clk_get_rate,
+-	.users		= 1,
+-};
+-static struct clk hramc_clk = {
+-	.name		= "hramc",
+-	.parent		= &hsb_clk,
+-	.mode		= hsb_clk_mode,
+-	.get_rate	= hsb_clk_get_rate,
+-	.users		= 1,
+-	.index		= 3,
+-};
+-
+-static struct resource smc0_resource[] = {
+-	PBMEM(0xfff03400),
+-};
+-DEFINE_DEV(smc, 0);
+-DEV_CLK(pclk, smc0, pbb, 13);
+-DEV_CLK(mck, smc0, hsb, 0);
+-
+-static struct platform_device pdc_device = {
+-	.name		= "pdc",
+-	.id		= 0,
+-};
+-DEV_CLK(hclk, pdc, hsb, 4);
+-DEV_CLK(pclk, pdc, pba, 16);
+-
+-static struct clk pico_clk = {
+-	.name		= "pico",
+-	.parent		= &cpu_clk,
+-	.mode		= cpu_clk_mode,
+-	.get_rate	= cpu_clk_get_rate,
+-	.users		= 1,
+-};
+-
+-static struct resource dmaca0_resource[] = {
+-	{
+-		.start	= 0xff200000,
+-		.end	= 0xff20ffff,
+-		.flags	= IORESOURCE_MEM,
+-	},
+-	IRQ(2),
+-};
+-DEFINE_DEV(dmaca, 0);
+-DEV_CLK(hclk, dmaca0, hsb, 10);
+-
+-/* --------------------------------------------------------------------
+- * HMATRIX
+- * -------------------------------------------------------------------- */
+-
+-static struct clk hmatrix_clk = {
+-	.name		= "hmatrix_clk",
+-	.parent		= &pbb_clk,
+-	.mode		= pbb_clk_mode,
+-	.get_rate	= pbb_clk_get_rate,
+-	.index		= 2,
+-	.users		= 1,
+-};
+-#define HMATRIX_BASE	((void __iomem *)0xfff00800)
+-
+-#define hmatrix_readl(reg)					\
+-	__raw_readl((HMATRIX_BASE) + HMATRIX_##reg)
+-#define hmatrix_writel(reg,value)				\
+-	__raw_writel((value), (HMATRIX_BASE) + HMATRIX_##reg)
+-
+-/*
+- * Set bits in the HMATRIX Special Function Register (SFR) used by the
+- * External Bus Interface (EBI). This can be used to enable special
+- * features like CompactFlash support, NAND Flash support, etc. on
+- * certain chipselects.
+- */
+-static inline void set_ebi_sfr_bits(u32 mask)
+-{
+-	u32 sfr;
+-
+-	clk_enable(&hmatrix_clk);
+-	sfr = hmatrix_readl(SFR4);
+-	sfr |= mask;
+-	hmatrix_writel(SFR4, sfr);
+-	clk_disable(&hmatrix_clk);
+-}
+-
+-/* --------------------------------------------------------------------
+- *  System Timer/Counter (TC)
+- * -------------------------------------------------------------------- */
+-static struct resource at32_systc0_resource[] = {
+-	PBMEM(0xfff00c00),
+-	IRQ(22),
+-};
+-struct platform_device at32_systc0_device = {
+-	.name		= "systc",
+-	.id		= 0,
+-	.resource	= at32_systc0_resource,
+-	.num_resources	= ARRAY_SIZE(at32_systc0_resource),
+-};
+-DEV_CLK(pclk, at32_systc0, pbb, 3);
+-
+-/* --------------------------------------------------------------------
+- *  PIO
+- * -------------------------------------------------------------------- */
+-
+-static struct resource pio0_resource[] = {
+-	PBMEM(0xffe02800),
+-	IRQ(13),
+-};
+-DEFINE_DEV(pio, 0);
+-DEV_CLK(mck, pio0, pba, 10);
+-
+-static struct resource pio1_resource[] = {
+-	PBMEM(0xffe02c00),
+-	IRQ(14),
+-};
+-DEFINE_DEV(pio, 1);
+-DEV_CLK(mck, pio1, pba, 11);
+-
+-static struct resource pio2_resource[] = {
+-	PBMEM(0xffe03000),
+-	IRQ(15),
+-};
+-DEFINE_DEV(pio, 2);
+-DEV_CLK(mck, pio2, pba, 12);
+-
+-static struct resource pio3_resource[] = {
+-	PBMEM(0xffe03400),
+-	IRQ(16),
+-};
+-DEFINE_DEV(pio, 3);
+-DEV_CLK(mck, pio3, pba, 13);
+-
+-static struct resource pio4_resource[] = {
+-	PBMEM(0xffe03800),
+-	IRQ(17),
+-};
+-DEFINE_DEV(pio, 4);
+-DEV_CLK(mck, pio4, pba, 14);
+-
+-void __init at32_add_system_devices(void)
+-{
+-	platform_device_register(&at32_pm0_device);
+-	platform_device_register(&at32_intc0_device);
+-	platform_device_register(&at32ap700x_rtc0_device);
+-	platform_device_register(&at32_wdt0_device);
+-	platform_device_register(&at32_eic0_device);
+-	platform_device_register(&smc0_device);
+-	platform_device_register(&pdc_device);
+-	platform_device_register(&dmaca0_device);
+-
+-	platform_device_register(&at32_systc0_device);
+-
+-	platform_device_register(&pio0_device);
+-	platform_device_register(&pio1_device);
+-	platform_device_register(&pio2_device);
+-	platform_device_register(&pio3_device);
+-	platform_device_register(&pio4_device);
+-}
+-
+-/* --------------------------------------------------------------------
+- *  USART
+- * -------------------------------------------------------------------- */
+-
+-static struct atmel_uart_data atmel_usart0_data = {
+-	.use_dma_tx	= 1,
+-	.use_dma_rx	= 1,
+-};
+-static struct resource atmel_usart0_resource[] = {
+-	PBMEM(0xffe00c00),
+-	IRQ(6),
+-};
+-DEFINE_DEV_DATA(atmel_usart, 0);
+-DEV_CLK(usart, atmel_usart0, pba, 3);
+-
+-static struct atmel_uart_data atmel_usart1_data = {
+-	.use_dma_tx	= 1,
+-	.use_dma_rx	= 1,
+-};
+-static struct resource atmel_usart1_resource[] = {
+-	PBMEM(0xffe01000),
+-	IRQ(7),
+-};
+-DEFINE_DEV_DATA(atmel_usart, 1);
+-DEV_CLK(usart, atmel_usart1, pba, 4);
+-
+-static struct atmel_uart_data atmel_usart2_data = {
+-	.use_dma_tx	= 1,
+-	.use_dma_rx	= 1,
+-};
+-static struct resource atmel_usart2_resource[] = {
+-	PBMEM(0xffe01400),
+-	IRQ(8),
+-};
+-DEFINE_DEV_DATA(atmel_usart, 2);
+-DEV_CLK(usart, atmel_usart2, pba, 5);
+-
+-static struct atmel_uart_data atmel_usart3_data = {
+-	.use_dma_tx	= 1,
+-	.use_dma_rx	= 1,
+-};
+-static struct resource atmel_usart3_resource[] = {
+-	PBMEM(0xffe01800),
+-	IRQ(9),
+-};
+-DEFINE_DEV_DATA(atmel_usart, 3);
+-DEV_CLK(usart, atmel_usart3, pba, 6);
+-
+-static inline void configure_usart0_pins(void)
+-{
+-	select_peripheral(PA(8),  PERIPH_B, 0);	/* RXD	*/
+-	select_peripheral(PA(9),  PERIPH_B, 0);	/* TXD	*/
+-}
+-
+-static inline void configure_usart1_pins(void)
+-{
+-	select_peripheral(PA(17), PERIPH_A, 0);	/* RXD	*/
+-	select_peripheral(PA(18), PERIPH_A, 0);	/* TXD	*/
+-}
+-
+-static inline void configure_usart2_pins(void)
+-{
+-	select_peripheral(PB(26), PERIPH_B, 0);	/* RXD	*/
+-	select_peripheral(PB(27), PERIPH_B, 0);	/* TXD	*/
+-}
+-
+-static inline void configure_usart3_pins(void)
+-{
+-	select_peripheral(PB(18), PERIPH_B, 0);	/* RXD	*/
+-	select_peripheral(PB(17), PERIPH_B, 0);	/* TXD	*/
+-}
+-
+-static struct platform_device *__initdata at32_usarts[4];
+-
+-void __init at32_map_usart(unsigned int hw_id, unsigned int line)
+-{
+-	struct platform_device *pdev;
+-
+-	switch (hw_id) {
+-	case 0:
+-		pdev = &atmel_usart0_device;
+-		configure_usart0_pins();
+-		break;
+-	case 1:
+-		pdev = &atmel_usart1_device;
+-		configure_usart1_pins();
+-		break;
+-	case 2:
+-		pdev = &atmel_usart2_device;
+-		configure_usart2_pins();
+-		break;
+-	case 3:
+-		pdev = &atmel_usart3_device;
+-		configure_usart3_pins();
+-		break;
+-	default:
+-		return;
+-	}
+-
+-	if (PXSEG(pdev->resource[0].start) == P4SEG) {
+-		/* Addresses in the P4 segment are permanently mapped 1:1 */
+-		struct atmel_uart_data *data = pdev->dev.platform_data;
+-		data->regs = (void __iomem *)pdev->resource[0].start;
+-	}
+-
+-	pdev->id = line;
+-	at32_usarts[line] = pdev;
+-}
+-
+-struct platform_device *__init at32_add_device_usart(unsigned int id)
+-{
+-	platform_device_register(at32_usarts[id]);
+-	return at32_usarts[id];
+-}
+-
+-struct platform_device *atmel_default_console_device;
+-
+-void __init at32_setup_serial_console(unsigned int usart_id)
+-{
+-	atmel_default_console_device = at32_usarts[usart_id];
+-}
+-
+-/* --------------------------------------------------------------------
+- *  Ethernet
+- * -------------------------------------------------------------------- */
+-
+-static struct eth_platform_data macb0_data;
+-static struct resource macb0_resource[] = {
+-	PBMEM(0xfff01800),
+-	IRQ(25),
+-};
+-DEFINE_DEV_DATA(macb, 0);
+-DEV_CLK(hclk, macb0, hsb, 8);
+-DEV_CLK(pclk, macb0, pbb, 6);
+-
+-static struct eth_platform_data macb1_data;
+-static struct resource macb1_resource[] = {
+-	PBMEM(0xfff01c00),
+-	IRQ(26),
+-};
+-DEFINE_DEV_DATA(macb, 1);
+-DEV_CLK(hclk, macb1, hsb, 9);
+-DEV_CLK(pclk, macb1, pbb, 7);
+-
+-struct platform_device *__init
+-at32_add_device_eth(unsigned int id, struct eth_platform_data *data)
+-{
+-	struct platform_device *pdev;
+-
+-	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	*/
+-
+-		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	*/
+-		}
+-		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	*/
+-
+-		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	*/
+-		}
+-		break;
+-
+-	default:
+-		return NULL;
+-	}
+-
+-	memcpy(pdev->dev.platform_data, data, sizeof(struct eth_platform_data));
+-	platform_device_register(pdev);
+-
+-	return pdev;
+-}
+-
+-/* --------------------------------------------------------------------
+- *  SPI
+- * -------------------------------------------------------------------- */
+-static struct resource atmel_spi0_resource[] = {
+-	PBMEM(0xffe00000),
+-	IRQ(3),
+-};
+-DEFINE_DEV(atmel_spi, 0);
+-DEV_CLK(spi_clk, atmel_spi0, pba, 0);
+-
+-static struct resource atmel_spi1_resource[] = {
+-	PBMEM(0xffe00400),
+-	IRQ(4),
+-};
+-DEFINE_DEV(atmel_spi, 1);
+-DEV_CLK(spi_clk, atmel_spi1, pba, 1);
+-
+-static void __init
+-at32_spi_setup_slaves(unsigned int bus_num, struct spi_board_info *b,
+-		      unsigned int n, const u8 *pins)
+-{
+-	unsigned int pin, mode;
+-
+-	for (; n; n--, b++) {
+-		b->bus_num = bus_num;
+-		if (b->chip_select >= 4)
+-			continue;
+-		pin = (unsigned)b->controller_data;
+-		if (!pin) {
+-			pin = pins[b->chip_select];
+-			b->controller_data = (void *)pin;
+-		}
+-		mode = AT32_GPIOF_OUTPUT;
+-		if (!(b->mode & SPI_CS_HIGH))
+-			mode |= AT32_GPIOF_HIGH;
+-		at32_select_gpio(pin, mode);
+-	}
+-}
+-
+-struct platform_device *__init
+-at32_add_device_spi(unsigned int id, struct spi_board_info *b, unsigned int n)
+-{
+-	/*
+-	 * Manage the chipselects as GPIOs, normally using the same pins
+-	 * the SPI controller expects; but boards can use other pins.
+-	 */
+-	static u8 __initdata spi0_pins[] =
+-		{ GPIO_PIN_PA(3), GPIO_PIN_PA(4),
+-		  GPIO_PIN_PA(5), GPIO_PIN_PA(20), };
+-	static u8 __initdata spi1_pins[] =
+-		{ GPIO_PIN_PB(2), GPIO_PIN_PB(3),
+-		  GPIO_PIN_PB(4), GPIO_PIN_PA(27), };
+-	struct platform_device *pdev;
+-
+-	switch (id) {
+-	case 0:
+-		pdev = &atmel_spi0_device;
+-		select_peripheral(PA(0),  PERIPH_A, 0);	/* MISO	 */
+-		select_peripheral(PA(1),  PERIPH_A, 0);	/* MOSI	 */
+-		select_peripheral(PA(2),  PERIPH_A, 0);	/* SCK	 */
+-		at32_spi_setup_slaves(0, b, n, spi0_pins);
+-		break;
+-
+-	case 1:
+-		pdev = &atmel_spi1_device;
+-		select_peripheral(PB(0),  PERIPH_B, 0);	/* MISO  */
+-		select_peripheral(PB(1),  PERIPH_B, 0);	/* MOSI  */
+-		select_peripheral(PB(5),  PERIPH_B, 0);	/* SCK   */
+-		at32_spi_setup_slaves(1, b, n, spi1_pins);
+-		break;
+-
+-	default:
+-		return NULL;
+-	}
+-
+-	spi_register_board_info(b, n);
+-	platform_device_register(pdev);
+-	return pdev;
+-}
+-
+-/* --------------------------------------------------------------------
+- *  TWI
+- * -------------------------------------------------------------------- */
+-static struct resource atmel_twi0_resource[] __initdata = {
+-	PBMEM(0xffe00800),
+-	IRQ(5),
+-};
+-static struct clk atmel_twi0_pclk = {
+-	.name		= "twi_pclk",
+-	.parent		= &pba_clk,
+-	.mode		= pba_clk_mode,
+-	.get_rate	= pba_clk_get_rate,
+-	.index		= 2,
+-};
+-
+-struct platform_device *__init at32_add_device_twi(unsigned int id)
+-{
+-	struct platform_device *pdev;
+-
+-	if (id != 0)
+-		return NULL;
+-
+-	pdev = platform_device_alloc("atmel_twi", id);
+-	if (!pdev)
+-		return NULL;
+-
+-	if (platform_device_add_resources(pdev, atmel_twi0_resource,
+-				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	*/
+-
+-	atmel_twi0_pclk.dev = &pdev->dev;
+-
+-	platform_device_add(pdev);
+-	return pdev;
+-
+-err_add_resources:
+-	platform_device_put(pdev);
+-	return NULL;
+-}
+-
+-/* --------------------------------------------------------------------
+- * MMC
+- * -------------------------------------------------------------------- */
+-static struct resource atmel_mci0_resource[] __initdata = {
+-	PBMEM(0xfff02400),
+-	IRQ(28),
+-};
+-static struct clk atmel_mci0_pclk = {
+-	.name		= "mci_clk",
+-	.parent		= &pbb_clk,
+-	.mode		= pbb_clk_mode,
+-	.get_rate	= pbb_clk_get_rate,
+-	.index		= 9,
+-};
+-
+-struct platform_device *__init at32_add_device_mci(unsigned int id)
+-{
+-	struct platform_device *pdev;
+-
+-	if (id != 0)
+-		return NULL;
+-
+-	pdev = platform_device_alloc("atmel_mci", id);
+-	if (!pdev)
+-		return NULL;
+-
+-	if (platform_device_add_resources(pdev, atmel_mci0_resource,
+-				ARRAY_SIZE(atmel_mci0_resource)))
+-		goto err_add_resources;
+-
+-	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 */
+-
+-	atmel_mci0_pclk.dev = &pdev->dev;
+-
+-	platform_device_add(pdev);
+-	return pdev;
+-
+-err_add_resources:
+-	platform_device_put(pdev);
+-	return NULL;
+-}
+-
+-/* --------------------------------------------------------------------
+- *  LCDC
+- * -------------------------------------------------------------------- */
+-static struct atmel_lcdfb_info atmel_lcdfb0_data;
+-static struct resource atmel_lcdfb0_resource[] = {
+-	{
+-		.start		= 0xff000000,
+-		.end		= 0xff000fff,
+-		.flags		= IORESOURCE_MEM,
+-	},
+-	IRQ(1),
+-	{
+-		/* Placeholder for pre-allocated fb memory */
+-		.start		= 0x00000000,
+-		.end		= 0x00000000,
+-		.flags		= 0,
+-	},
+-};
+-DEFINE_DEV_DATA(atmel_lcdfb, 0);
+-DEV_CLK(hck1, atmel_lcdfb0, hsb, 7);
+-static struct clk atmel_lcdfb0_pixclk = {
+-	.name		= "lcdc_clk",
+-	.dev		= &atmel_lcdfb0_device.dev,
+-	.mode		= genclk_mode,
+-	.get_rate	= genclk_get_rate,
+-	.set_rate	= genclk_set_rate,
+-	.set_parent	= genclk_set_parent,
+-	.index		= 7,
+-};
+-
+-struct platform_device *__init
+-at32_add_device_lcdc(unsigned int id, struct atmel_lcdfb_info *data,
+-		     unsigned long fbmem_start, unsigned long fbmem_len)
+-{
+-	struct platform_device *pdev;
+-	struct atmel_lcdfb_info *info;
+-	struct fb_monspecs *monspecs;
+-	struct fb_videomode *modedb;
+-	unsigned int modedb_size;
+-
+-	/*
+-	 * Do a deep copy of the fb data, monspecs and modedb. Make
+-	 * sure all allocations are done before setting up the
+-	 * portmux.
+-	 */
+-	monspecs = kmemdup(data->default_monspecs,
+-			   sizeof(struct fb_monspecs), GFP_KERNEL);
+-	if (!monspecs)
+-		return NULL;
+-
+-	modedb_size = sizeof(struct fb_videomode) * monspecs->modedb_len;
+-	modedb = kmemdup(monspecs->modedb, modedb_size, GFP_KERNEL);
+-	if (!modedb)
+-		goto err_dup_modedb;
+-	monspecs->modedb = modedb;
+-
+-	switch (id) {
+-	case 0:
+-		pdev = &atmel_lcdfb0_device;
+-		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 */
+-
+-		clk_set_parent(&atmel_lcdfb0_pixclk, &pll0);
+-		clk_set_rate(&atmel_lcdfb0_pixclk, clk_get_rate(&pll0));
+-		break;
+-
+-	default:
+-		goto err_invalid_id;
+-	}
+-
+-	if (fbmem_len) {
+-		pdev->resource[2].start = fbmem_start;
+-		pdev->resource[2].end = fbmem_start + fbmem_len - 1;
+-		pdev->resource[2].flags = IORESOURCE_MEM;
+-	}
+-
+-	info = pdev->dev.platform_data;
+-	memcpy(info, data, sizeof(struct atmel_lcdfb_info));
+-	info->default_monspecs = monspecs;
+-
+-	platform_device_register(pdev);
+-	return pdev;
+-
+-err_invalid_id:
+-	kfree(modedb);
+-err_dup_modedb:
+-	kfree(monspecs);
+-	return NULL;
+-}
+-
+-/* --------------------------------------------------------------------
+- *  SSC
+- * -------------------------------------------------------------------- */
+-static struct resource ssc0_resource[] = {
+-	PBMEM(0xffe01c00),
+-	IRQ(10),
+-};
+-DEFINE_DEV(ssc, 0);
+-DEV_CLK(pclk, ssc0, pba, 7);
+-
+-static struct resource ssc1_resource[] = {
+-	PBMEM(0xffe02000),
+-	IRQ(11),
+-};
+-DEFINE_DEV(ssc, 1);
+-DEV_CLK(pclk, ssc1, pba, 8);
+-
+-static struct resource ssc2_resource[] = {
+-	PBMEM(0xffe02400),
+-	IRQ(12),
+-};
+-DEFINE_DEV(ssc, 2);
+-DEV_CLK(pclk, ssc2, pba, 9);
+-
+-struct platform_device *__init
+-at32_add_device_ssc(unsigned int id, unsigned int flags)
+-{
+-	struct platform_device *pdev;
+-
+-	switch (id) {
+-	case 0:
+-		pdev = &ssc0_device;
+-		if (flags & ATMEL_SSC_RF)
+-			select_peripheral(PA(21), PERIPH_A, 0);	/* RF */
+-		if (flags & ATMEL_SSC_RK)
+-			select_peripheral(PA(22), PERIPH_A, 0);	/* RK */
+-		if (flags & ATMEL_SSC_TK)
+-			select_peripheral(PA(23), PERIPH_A, 0);	/* TK */
+-		if (flags & ATMEL_SSC_TF)
+-			select_peripheral(PA(24), PERIPH_A, 0);	/* TF */
+-		if (flags & ATMEL_SSC_TD)
+-			select_peripheral(PA(25), PERIPH_A, 0);	/* TD */
+-		if (flags & ATMEL_SSC_RD)
+-			select_peripheral(PA(26), PERIPH_A, 0);	/* RD */
+-		break;
+-	case 1:
+-		pdev = &ssc1_device;
+-		if (flags & ATMEL_SSC_RF)
+-			select_peripheral(PA(0), PERIPH_B, 0);	/* RF */
+-		if (flags & ATMEL_SSC_RK)
+-			select_peripheral(PA(1), PERIPH_B, 0);	/* RK */
+-		if (flags & ATMEL_SSC_TK)
+-			select_peripheral(PA(2), PERIPH_B, 0);	/* TK */
+-		if (flags & ATMEL_SSC_TF)
+-			select_peripheral(PA(3), PERIPH_B, 0);	/* TF */
+-		if (flags & ATMEL_SSC_TD)
+-			select_peripheral(PA(4), PERIPH_B, 0);	/* TD */
+-		if (flags & ATMEL_SSC_RD)
+-			select_peripheral(PA(5), PERIPH_B, 0);	/* RD */
+-		break;
+-	case 2:
+-		pdev = &ssc2_device;
+-		if (flags & ATMEL_SSC_TD)
+-			select_peripheral(PB(13), PERIPH_A, 0);	/* TD */
+-		if (flags & ATMEL_SSC_RD)
+-			select_peripheral(PB(14), PERIPH_A, 0);	/* RD */
+-		if (flags & ATMEL_SSC_TK)
+-			select_peripheral(PB(15), PERIPH_A, 0);	/* TK */
+-		if (flags & ATMEL_SSC_TF)
+-			select_peripheral(PB(16), PERIPH_A, 0);	/* TF */
+-		if (flags & ATMEL_SSC_RF)
+-			select_peripheral(PB(17), PERIPH_A, 0);	/* RF */
+-		if (flags & ATMEL_SSC_RK)
+-			select_peripheral(PB(18), PERIPH_A, 0);	/* RK */
+-		break;
+-	default:
+-		return NULL;
+-	}
+-
+-	platform_device_register(pdev);
+-	return pdev;
+-}
+-
+-/* --------------------------------------------------------------------
+- *  USB Device Controller
+- * -------------------------------------------------------------------- */
+-static struct resource usba0_resource[] __initdata = {
+-	{
+-		.start		= 0xff300000,
+-		.end		= 0xff3fffff,
+-		.flags		= IORESOURCE_MEM,
+-	}, {
+-		.start		= 0xfff03000,
+-		.end		= 0xfff033ff,
+-		.flags		= IORESOURCE_MEM,
+-	},
+-	IRQ(31),
+-};
+-static struct clk usba0_pclk = {
+-	.name		= "pclk",
+-	.parent		= &pbb_clk,
+-	.mode		= pbb_clk_mode,
+-	.get_rate	= pbb_clk_get_rate,
+-	.index		= 12,
+-};
+-static struct clk usba0_hclk = {
+-	.name		= "hclk",
+-	.parent		= &hsb_clk,
+-	.mode		= hsb_clk_mode,
+-	.get_rate	= hsb_clk_get_rate,
+-	.index		= 6,
+-};
+-
+-struct platform_device *__init
+-at32_add_device_usba(unsigned int id, struct usba_platform_data *data)
+-{
+-	struct platform_device *pdev;
+-
+-	if (id != 0)
+-		return NULL;
+-
+-	pdev = platform_device_alloc("atmel_usba_udc", 0);
+-	if (!pdev)
+-		return NULL;
+-
+-	if (platform_device_add_resources(pdev, usba0_resource,
+-					  ARRAY_SIZE(usba0_resource)))
+-		goto out_free_pdev;
+-
+-	if (data) {
+-		if (platform_device_add_data(pdev, data, sizeof(*data)))
+-			goto out_free_pdev;
+-
+-		if (data->vbus_pin != GPIO_PIN_NONE)
+-			at32_select_gpio(data->vbus_pin, 0);
+-	}
+-
+-	usba0_pclk.dev = &pdev->dev;
+-	usba0_hclk.dev = &pdev->dev;
+-
+-	platform_device_add(pdev);
+-
+-	return pdev;
+-
+-out_free_pdev:
+-	platform_device_put(pdev);
+-	return NULL;
+-}
+-
+-/* --------------------------------------------------------------------
+- * IDE / CompactFlash
+- * -------------------------------------------------------------------- */
+-static struct resource at32_smc_cs4_resource[] __initdata = {
+-	{
+-		.start	= 0x04000000,
+-		.end	= 0x07ffffff,
+-		.flags	= IORESOURCE_MEM,
+-	},
+-	IRQ(~0UL), /* Magic IRQ will be overridden */
+-};
+-static struct resource at32_smc_cs5_resource[] __initdata = {
+-	{
+-		.start	= 0x20000000,
+-		.end	= 0x23ffffff,
+-		.flags	= IORESOURCE_MEM,
+-	},
+-	IRQ(~0UL), /* Magic IRQ will be overridden */
+-};
+-
+-static int __init at32_init_ide_or_cf(struct platform_device *pdev,
+-		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),
+-	};
+-	static bool common_pins_initialized __initdata = false;
+-	unsigned int extint_pin;
+-	int ret;
+-
+-	if (extint >= ARRAY_SIZE(extint_pin_map))
+-		return -EINVAL;
+-	extint_pin = extint_pin_map[extint];
+-
+-	switch (cs) {
+-	case 4:
+-		ret = platform_device_add_resources(pdev,
+-				at32_smc_cs4_resource,
+-				ARRAY_SIZE(at32_smc_cs4_resource));
+-		if (ret)
+-			return ret;
+-
+-		select_peripheral(PE(21), PERIPH_A, 0); /* NCS4   -> OE_N  */
+-		set_ebi_sfr_bits(HMATRIX_BIT(CS4A));
+-		break;
+-	case 5:
+-		ret = platform_device_add_resources(pdev,
+-				at32_smc_cs5_resource,
+-				ARRAY_SIZE(at32_smc_cs5_resource));
+-		if (ret)
+-			return ret;
+-
+-		select_peripheral(PE(22), PERIPH_A, 0); /* NCS5   -> OE_N  */
+-		set_ebi_sfr_bits(HMATRIX_BIT(CS5A));
+-		break;
+-	default:
+-		return -EINVAL;
+-	}
+-
+-	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 */
+-		common_pins_initialized = true;
+-	}
+-
+-	at32_select_periph(extint_pin, GPIO_PERIPH_A, AT32_GPIOF_DEGLITCH);
+-
+-	pdev->resource[1].start = EIM_IRQ_BASE + extint;
+-	pdev->resource[1].end = pdev->resource[1].start;
+-
+-	return 0;
+-}
+-
+-struct platform_device *__init
+-at32_add_device_ide(unsigned int id, unsigned int extint,
+-		    struct ide_platform_data *data)
+-{
+-	struct platform_device *pdev;
+-
+-	pdev = platform_device_alloc("at32_ide", id);
+-	if (!pdev)
+-		goto fail;
+-
+-	if (platform_device_add_data(pdev, data,
+-				sizeof(struct ide_platform_data)))
+-		goto fail;
+-
+-	if (at32_init_ide_or_cf(pdev, data->cs, extint))
+-		goto fail;
+-
+-	platform_device_add(pdev);
+-	return pdev;
+-
+-fail:
+-	platform_device_put(pdev);
+-	return NULL;
+-}
+-
+-struct platform_device *__init
+-at32_add_device_cf(unsigned int id, unsigned int extint,
+-		    struct cf_platform_data *data)
+-{
+-	struct platform_device *pdev;
+-
+-	pdev = platform_device_alloc("at32_cf", id);
+-	if (!pdev)
+-		goto fail;
+-
+-	if (platform_device_add_data(pdev, data,
+-				sizeof(struct cf_platform_data)))
+-		goto fail;
+-
+-	if (at32_init_ide_or_cf(pdev, data->cs, extint))
+-		goto fail;
+-
+-	if (data->detect_pin != GPIO_PIN_NONE)
+-		at32_select_gpio(data->detect_pin, AT32_GPIOF_DEGLITCH);
+-	if (data->reset_pin != GPIO_PIN_NONE)
+-		at32_select_gpio(data->reset_pin, 0);
+-	if (data->vcc_pin != GPIO_PIN_NONE)
+-		at32_select_gpio(data->vcc_pin, 0);
+-	/* READY is used as extint, so we can't select it as gpio */
+-
+-	platform_device_add(pdev);
+-	return pdev;
+-
+-fail:
+-	platform_device_put(pdev);
+-	return NULL;
+-}
+-
+-/* --------------------------------------------------------------------
+- * AC97C
+- * -------------------------------------------------------------------- */
+-static struct resource atmel_ac97c0_resource[] __initdata = {
+-	PBMEM(0xfff02800),
+-	IRQ(29),
+-};
+-static struct clk atmel_ac97c0_pclk = {
+-	.name		= "pclk",
+-	.parent		= &pbb_clk,
+-	.mode		= pbb_clk_mode,
+-	.get_rate	= pbb_clk_get_rate,
+-	.index		= 10,
+-};
+-
+-struct platform_device *__init at32_add_device_ac97c(unsigned int id)
+-{
+-	struct platform_device *pdev;
+-
+-	if (id != 0)
+-		return NULL;
+-
+-	pdev = platform_device_alloc("atmel_ac97c", id);
+-	if (!pdev)
+-		return NULL;
+-
+-	if (platform_device_add_resources(pdev, atmel_ac97c0_resource,
+-				ARRAY_SIZE(atmel_ac97c0_resource)))
+-		goto err_add_resources;
+-
+-	select_peripheral(PB(20), PERIPH_B, 0);	/* SYNC	*/
+-	select_peripheral(PB(21), PERIPH_B, 0);	/* SDO	*/
+-	select_peripheral(PB(22), PERIPH_B, 0);	/* SDI	*/
+-	select_peripheral(PB(23), PERIPH_B, 0);	/* SCLK	*/
+-
+-	atmel_ac97c0_pclk.dev = &pdev->dev;
+-
+-	platform_device_add(pdev);
+-	return pdev;
+-
+-err_add_resources:
+-	platform_device_put(pdev);
+-	return NULL;
+-}
+-
+-/* --------------------------------------------------------------------
+- * ABDAC
+- * -------------------------------------------------------------------- */
+-static struct resource abdac0_resource[] __initdata = {
+-	PBMEM(0xfff02000),
+-	IRQ(27),
+-};
+-static struct clk abdac0_pclk = {
+-	.name		= "pclk",
+-	.parent		= &pbb_clk,
+-	.mode		= pbb_clk_mode,
+-	.get_rate	= pbb_clk_get_rate,
+-	.index		= 8,
+-};
+-static struct clk abdac0_sample_clk = {
+-	.name		= "sample_clk",
+-	.mode		= genclk_mode,
+-	.get_rate	= genclk_get_rate,
+-	.set_rate	= genclk_set_rate,
+-	.set_parent	= genclk_set_parent,
+-	.index		= 6,
+-};
+-
+-struct platform_device *__init at32_add_device_abdac(unsigned int id)
+-{
+-	struct platform_device *pdev;
+-
+-	if (id != 0)
+-		return NULL;
+-
+-	pdev = platform_device_alloc("abdac", id);
+-	if (!pdev)
+-		return NULL;
+-
+-	if (platform_device_add_resources(pdev, abdac0_resource,
+-				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	*/
+-
+-	abdac0_pclk.dev = &pdev->dev;
+-	abdac0_sample_clk.dev = &pdev->dev;
+-
+-	platform_device_add(pdev);
+-	return pdev;
+-
+-err_add_resources:
+-	platform_device_put(pdev);
+-	return NULL;
+-}
+-
+-/* --------------------------------------------------------------------
+- *  GCLK
+- * -------------------------------------------------------------------- */
+-static struct clk gclk0 = {
+-	.name		= "gclk0",
+-	.mode		= genclk_mode,
+-	.get_rate	= genclk_get_rate,
+-	.set_rate	= genclk_set_rate,
+-	.set_parent	= genclk_set_parent,
+-	.index		= 0,
+-};
+-static struct clk gclk1 = {
+-	.name		= "gclk1",
+-	.mode		= genclk_mode,
+-	.get_rate	= genclk_get_rate,
+-	.set_rate	= genclk_set_rate,
+-	.set_parent	= genclk_set_parent,
+-	.index		= 1,
+-};
+-static struct clk gclk2 = {
+-	.name		= "gclk2",
+-	.mode		= genclk_mode,
+-	.get_rate	= genclk_get_rate,
+-	.set_rate	= genclk_set_rate,
+-	.set_parent	= genclk_set_parent,
+-	.index		= 2,
+-};
+-static struct clk gclk3 = {
+-	.name		= "gclk3",
+-	.mode		= genclk_mode,
+-	.get_rate	= genclk_get_rate,
+-	.set_rate	= genclk_set_rate,
+-	.set_parent	= genclk_set_parent,
+-	.index		= 3,
+-};
+-static struct clk gclk4 = {
+-	.name		= "gclk4",
+-	.mode		= genclk_mode,
+-	.get_rate	= genclk_get_rate,
+-	.set_rate	= genclk_set_rate,
+-	.set_parent	= genclk_set_parent,
+-	.index		= 4,
+-};
+-
+-struct clk *at32_clock_list[] = {
+-	&osc32k,
+-	&osc0,
+-	&osc1,
+-	&pll0,
+-	&pll1,
+-	&cpu_clk,
+-	&hsb_clk,
+-	&pba_clk,
+-	&pbb_clk,
+-	&at32_pm_pclk,
+-	&at32_intc0_pclk,
+-	&hmatrix_clk,
+-	&ebi_clk,
+-	&hramc_clk,
+-	&smc0_pclk,
+-	&smc0_mck,
+-	&pdc_hclk,
+-	&pdc_pclk,
+-	&dmaca0_hclk,
+-	&pico_clk,
+-	&pio0_mck,
+-	&pio1_mck,
+-	&pio2_mck,
+-	&pio3_mck,
+-	&pio4_mck,
+-	&at32_systc0_pclk,
+-	&atmel_usart0_usart,
+-	&atmel_usart1_usart,
+-	&atmel_usart2_usart,
+-	&atmel_usart3_usart,
+-	&macb0_hclk,
+-	&macb0_pclk,
+-	&macb1_hclk,
+-	&macb1_pclk,
+-	&atmel_spi0_spi_clk,
+-	&atmel_spi1_spi_clk,
+-	&atmel_twi0_pclk,
+-	&atmel_mci0_pclk,
+-	&atmel_lcdfb0_hck1,
+-	&atmel_lcdfb0_pixclk,
+-	&ssc0_pclk,
+-	&ssc1_pclk,
+-	&ssc2_pclk,
+-	&usba0_hclk,
+-	&usba0_pclk,
+-	&atmel_ac97c0_pclk,
+-	&abdac0_pclk,
+-	&abdac0_sample_clk,
+-	&gclk0,
+-	&gclk1,
+-	&gclk2,
+-	&gclk3,
+-	&gclk4,
+-};
+-unsigned int at32_nr_clocks = ARRAY_SIZE(at32_clock_list);
+-
+-void __init at32_portmux_init(void)
+-{
+-	at32_init_pio(&pio0_device);
+-	at32_init_pio(&pio1_device);
+-	at32_init_pio(&pio2_device);
+-	at32_init_pio(&pio3_device);
+-	at32_init_pio(&pio4_device);
+-}
+-
+-void __init at32_clock_init(void)
+-{
+-	u32 cpu_mask = 0, hsb_mask = 0, pba_mask = 0, pbb_mask = 0;
+-	int i;
+-
+-	if (pm_readl(MCCTRL) & PM_BIT(PLLSEL)) {
+-		main_clock = &pll0;
+-		cpu_clk.parent = &pll0;
+-	} else {
+-		main_clock = &osc0;
+-		cpu_clk.parent = &osc0;
+-	}
+-
+-	if (pm_readl(PLL0) & PM_BIT(PLLOSC))
+-		pll0.parent = &osc1;
+-	if (pm_readl(PLL1) & PM_BIT(PLLOSC))
+-		pll1.parent = &osc1;
+-
+-	genclk_init_parent(&gclk0);
+-	genclk_init_parent(&gclk1);
+-	genclk_init_parent(&gclk2);
+-	genclk_init_parent(&gclk3);
+-	genclk_init_parent(&gclk4);
+-	genclk_init_parent(&atmel_lcdfb0_pixclk);
+-	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...
+-	 */
+-	for (i = 0; i < ARRAY_SIZE(at32_clock_list); i++) {
+-		struct clk *clk = at32_clock_list[i];
+-
+-		if (clk->users == 0)
+-			continue;
+-
+-		if (clk->mode == &cpu_clk_mode)
+-			cpu_mask |= 1 << clk->index;
+-		else if (clk->mode == &hsb_clk_mode)
+-			hsb_mask |= 1 << clk->index;
+-		else if (clk->mode == &pba_clk_mode)
+-			pba_mask |= 1 << clk->index;
+-		else if (clk->mode == &pbb_clk_mode)
+-			pbb_mask |= 1 << clk->index;
+-	}
+-
+-	pm_writel(CPU_MASK, cpu_mask);
+-	pm_writel(HSB_MASK, hsb_mask);
+-	pm_writel(PBA_MASK, pba_mask);
+-	pm_writel(PBB_MASK, pbb_mask);
+-}
+diff --git a/arch/avr32/mach-at32ap/at32ap700x.c b/arch/avr32/mach-at32ap/at32ap700x.c
+new file mode 100644
+index 0000000..14e61f0
+--- /dev/null
++++ b/arch/avr32/mach-at32ap/at32ap700x.c
+@@ -0,0 +1,1743 @@
++/*
++ * Copyright (C) 2005-2006 Atmel 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/clk.h>
++#include <linux/fb.h>
++#include <linux/init.h>
++#include <linux/platform_device.h>
++#include <linux/dma-mapping.h>
++#include <linux/spi/spi.h>
++
++#include <asm/io.h>
++#include <asm/irq.h>
++
++#include <asm/arch/at32ap700x.h>
++#include <asm/arch/board.h>
++#include <asm/arch/portmux.h>
++
++#include <video/atmel_lcdc.h>
++
++#include "clock.h"
++#include "hmatrix.h"
++#include "pio.h"
++#include "pm.h"
++
++
++#define PBMEM(base)					\
++	{						\
++		.start		= base,			\
++		.end		= base + 0x3ff,		\
++		.flags		= IORESOURCE_MEM,	\
++	}
++#define IRQ(num)					\
++	{						\
++		.start		= num,			\
++		.end		= num,			\
++		.flags		= IORESOURCE_IRQ,	\
++	}
++#define NAMED_IRQ(num, _name)				\
++	{						\
++		.start		= num,			\
++		.end		= num,			\
++		.name		= _name,		\
++		.flags		= IORESOURCE_IRQ,	\
++	}
++
++/* REVISIT these assume *every* device supports DMA, but several
++ * don't ... tc, smc, pio, rtc, watchdog, pwm, ps2, and more.
++ */
++#define DEFINE_DEV(_name, _id)					\
++static u64 _name##_id##_dma_mask = DMA_32BIT_MASK;		\
++static struct platform_device _name##_id##_device = {		\
++	.name		= #_name,				\
++	.id		= _id,					\
++	.dev		= {					\
++		.dma_mask = &_name##_id##_dma_mask,		\
++		.coherent_dma_mask = DMA_32BIT_MASK,		\
++	},							\
++	.resource	= _name##_id##_resource,		\
++	.num_resources	= ARRAY_SIZE(_name##_id##_resource),	\
++}
++#define DEFINE_DEV_DATA(_name, _id)				\
++static u64 _name##_id##_dma_mask = DMA_32BIT_MASK;		\
++static struct platform_device _name##_id##_device = {		\
++	.name		= #_name,				\
++	.id		= _id,					\
++	.dev		= {					\
++		.dma_mask = &_name##_id##_dma_mask,		\
++		.platform_data	= &_name##_id##_data,		\
++		.coherent_dma_mask = DMA_32BIT_MASK,		\
++	},							\
++	.resource	= _name##_id##_resource,		\
++	.num_resources	= ARRAY_SIZE(_name##_id##_resource),	\
++}
++
++#define select_peripheral(pin, periph, flags)			\
++	at32_select_periph(GPIO_PIN_##pin, GPIO_##periph, flags)
++
++#define DEV_CLK(_name, devname, bus, _index)			\
++static struct clk devname##_##_name = {				\
++	.name		= #_name,				\
++	.dev		= &devname##_device.dev,		\
++	.parent		= &bus##_clk,				\
++	.mode		= bus##_clk_mode,			\
++	.get_rate	= bus##_clk_get_rate,			\
++	.index		= _index,				\
++}
++
++static DEFINE_SPINLOCK(pm_lock);
++
++unsigned long at32ap7000_osc_rates[3] = {
++	[0] = 32768,
++	/* FIXME: these are ATSTK1002-specific */
++	[1] = 20000000,
++	[2] = 12000000,
++};
++
++static unsigned long osc_get_rate(struct clk *clk)
++{
++	return at32ap7000_osc_rates[clk->index];
++}
++
++static unsigned long pll_get_rate(struct clk *clk, unsigned long control)
++{
++	unsigned long div, mul, rate;
++
++	if (!(control & PM_BIT(PLLEN)))
++		return 0;
++
++	div = PM_BFEXT(PLLDIV, control) + 1;
++	mul = PM_BFEXT(PLLMUL, control) + 1;
++
++	rate = clk->parent->get_rate(clk->parent);
++	rate = (rate + div / 2) / div;
++	rate *= mul;
++
++	return rate;
++}
++
++static unsigned long pll0_get_rate(struct clk *clk)
++{
++	u32 control;
++
++	control = pm_readl(PLL0);
++
++	return pll_get_rate(clk, control);
++}
++
++static unsigned long pll1_get_rate(struct clk *clk)
++{
++	u32 control;
++
++	control = pm_readl(PLL1);
++
++	return pll_get_rate(clk, control);
++}
++
++/*
++ * The AT32AP7000 has five primary clock sources: One 32kHz
++ * oscillator, two crystal oscillators and two PLLs.
++ */
++static struct clk osc32k = {
++	.name		= "osc32k",
++	.get_rate	= osc_get_rate,
++	.users		= 1,
++	.index		= 0,
++};
++static struct clk osc0 = {
++	.name		= "osc0",
++	.get_rate	= osc_get_rate,
++	.users		= 1,
++	.index		= 1,
++};
++static struct clk osc1 = {
++	.name		= "osc1",
++	.get_rate	= osc_get_rate,
++	.index		= 2,
++};
++static struct clk pll0 = {
++	.name		= "pll0",
++	.get_rate	= pll0_get_rate,
++	.parent		= &osc0,
++};
++static struct clk pll1 = {
++	.name		= "pll1",
++	.get_rate	= pll1_get_rate,
++	.parent		= &osc0,
++};
++
++/*
++ * The main clock can be either osc0 or pll0.  The boot loader may
++ * have chosen one for us, so we don't really know which one until we
++ * have a look at the SM.
++ */
++static struct clk *main_clock;
++
++/*
++ * Synchronous clocks are generated from the main clock. The clocks
++ * must satisfy the constraint
++ *   fCPU >= fHSB >= fPB
++ * i.e. each clock must not be faster than its parent.
++ */
++static unsigned long bus_clk_get_rate(struct clk *clk, unsigned int shift)
++{
++	return main_clock->get_rate(main_clock) >> shift;
++};
++
++static void cpu_clk_mode(struct clk *clk, int enabled)
++{
++	unsigned long flags;
++	u32 mask;
++
++	spin_lock_irqsave(&pm_lock, flags);
++	mask = pm_readl(CPU_MASK);
++	if (enabled)
++		mask |= 1 << clk->index;
++	else
++		mask &= ~(1 << clk->index);
++	pm_writel(CPU_MASK, mask);
++	spin_unlock_irqrestore(&pm_lock, flags);
++}
++
++static unsigned long cpu_clk_get_rate(struct clk *clk)
++{
++	unsigned long cksel, shift = 0;
++
++	cksel = pm_readl(CKSEL);
++	if (cksel & PM_BIT(CPUDIV))
++		shift = PM_BFEXT(CPUSEL, cksel) + 1;
++
++	return bus_clk_get_rate(clk, shift);
++}
++
++static long cpu_clk_set_rate(struct clk *clk, unsigned long rate, int apply)
++{
++	u32 control;
++	unsigned long parent_rate, child_div, actual_rate, div;
++
++	parent_rate = clk->parent->get_rate(clk->parent);
++	control = pm_readl(CKSEL);
++
++	if (control & PM_BIT(HSBDIV))
++		child_div = 1 << (PM_BFEXT(HSBSEL, control) + 1);
++	else
++		child_div = 1;
++
++	if (rate > 3 * (parent_rate / 4) || child_div == 1) {
++		actual_rate = parent_rate;
++		control &= ~PM_BIT(CPUDIV);
++	} else {
++		unsigned int cpusel;
++		div = (parent_rate + rate / 2) / rate;
++		if (div > child_div)
++			div = child_div;
++		cpusel = (div > 1) ? (fls(div) - 2) : 0;
++		control = PM_BIT(CPUDIV) | PM_BFINS(CPUSEL, cpusel, control);
++		actual_rate = parent_rate / (1 << (cpusel + 1));
++	}
++
++	pr_debug("clk %s: new rate %lu (actual rate %lu)\n",
++			clk->name, rate, actual_rate);
++
++	if (apply)
++		pm_writel(CKSEL, control);
++
++	return actual_rate;
++}
++
++static void hsb_clk_mode(struct clk *clk, int enabled)
++{
++	unsigned long flags;
++	u32 mask;
++
++	spin_lock_irqsave(&pm_lock, flags);
++	mask = pm_readl(HSB_MASK);
++	if (enabled)
++		mask |= 1 << clk->index;
++	else
++		mask &= ~(1 << clk->index);
++	pm_writel(HSB_MASK, mask);
++	spin_unlock_irqrestore(&pm_lock, flags);
++}
++
++static unsigned long hsb_clk_get_rate(struct clk *clk)
++{
++	unsigned long cksel, shift = 0;
++
++	cksel = pm_readl(CKSEL);
++	if (cksel & PM_BIT(HSBDIV))
++		shift = PM_BFEXT(HSBSEL, cksel) + 1;
++
++	return bus_clk_get_rate(clk, shift);
++}
++
++static void pba_clk_mode(struct clk *clk, int enabled)
++{
++	unsigned long flags;
++	u32 mask;
++
++	spin_lock_irqsave(&pm_lock, flags);
++	mask = pm_readl(PBA_MASK);
++	if (enabled)
++		mask |= 1 << clk->index;
++	else
++		mask &= ~(1 << clk->index);
++	pm_writel(PBA_MASK, mask);
++	spin_unlock_irqrestore(&pm_lock, flags);
++}
++
++static unsigned long pba_clk_get_rate(struct clk *clk)
++{
++	unsigned long cksel, shift = 0;
++
++	cksel = pm_readl(CKSEL);
++	if (cksel & PM_BIT(PBADIV))
++		shift = PM_BFEXT(PBASEL, cksel) + 1;
++
++	return bus_clk_get_rate(clk, shift);
++}
++
++static void pbb_clk_mode(struct clk *clk, int enabled)
++{
++	unsigned long flags;
++	u32 mask;
++
++	spin_lock_irqsave(&pm_lock, flags);
++	mask = pm_readl(PBB_MASK);
++	if (enabled)
++		mask |= 1 << clk->index;
++	else
++		mask &= ~(1 << clk->index);
++	pm_writel(PBB_MASK, mask);
++	spin_unlock_irqrestore(&pm_lock, flags);
++}
++
++static unsigned long pbb_clk_get_rate(struct clk *clk)
++{
++	unsigned long cksel, shift = 0;
++
++	cksel = pm_readl(CKSEL);
++	if (cksel & PM_BIT(PBBDIV))
++		shift = PM_BFEXT(PBBSEL, cksel) + 1;
++
++	return bus_clk_get_rate(clk, shift);
++}
++
++static struct clk cpu_clk = {
++	.name		= "cpu",
++	.get_rate	= cpu_clk_get_rate,
++	.set_rate	= cpu_clk_set_rate,
++	.users		= 1,
++};
++static struct clk hsb_clk = {
++	.name		= "hsb",
++	.parent		= &cpu_clk,
++	.get_rate	= hsb_clk_get_rate,
++};
++static struct clk pba_clk = {
++	.name		= "pba",
++	.parent		= &hsb_clk,
++	.mode		= hsb_clk_mode,
++	.get_rate	= pba_clk_get_rate,
++	.index		= 1,
++};
++static struct clk pbb_clk = {
++	.name		= "pbb",
++	.parent		= &hsb_clk,
++	.mode		= hsb_clk_mode,
++	.get_rate	= pbb_clk_get_rate,
++	.users		= 1,
++	.index		= 2,
++};
++
++/* --------------------------------------------------------------------
++ *  Generic Clock operations
++ * -------------------------------------------------------------------- */
++
++static void genclk_mode(struct clk *clk, int enabled)
++{
++	u32 control;
++
++	control = pm_readl(GCCTRL(clk->index));
++	if (enabled)
++		control |= PM_BIT(CEN);
++	else
++		control &= ~PM_BIT(CEN);
++	pm_writel(GCCTRL(clk->index), control);
++}
++
++static unsigned long genclk_get_rate(struct clk *clk)
++{
++	u32 control;
++	unsigned long div = 1;
++
++	control = pm_readl(GCCTRL(clk->index));
++	if (control & PM_BIT(DIVEN))
++		div = 2 * (PM_BFEXT(DIV, control) + 1);
++
++	return clk->parent->get_rate(clk->parent) / div;
++}
++
++static long genclk_set_rate(struct clk *clk, unsigned long rate, int apply)
++{
++	u32 control;
++	unsigned long parent_rate, actual_rate, div;
++
++	parent_rate = clk->parent->get_rate(clk->parent);
++	control = pm_readl(GCCTRL(clk->index));
++
++	if (rate > 3 * parent_rate / 4) {
++		actual_rate = parent_rate;
++		control &= ~PM_BIT(DIVEN);
++	} else {
++		div = (parent_rate + rate) / (2 * rate) - 1;
++		control = PM_BFINS(DIV, div, control) | PM_BIT(DIVEN);
++		actual_rate = parent_rate / (2 * (div + 1));
++	}
++
++	dev_dbg(clk->dev, "clk %s: new rate %lu (actual rate %lu)\n",
++		clk->name, rate, actual_rate);
++
++	if (apply)
++		pm_writel(GCCTRL(clk->index), control);
++
++	return actual_rate;
++}
++
++int genclk_set_parent(struct clk *clk, struct clk *parent)
++{
++	u32 control;
++
++	dev_dbg(clk->dev, "clk %s: new parent %s (was %s)\n",
++		clk->name, parent->name, clk->parent->name);
++
++	control = pm_readl(GCCTRL(clk->index));
++
++	if (parent == &osc1 || parent == &pll1)
++		control |= PM_BIT(OSCSEL);
++	else if (parent == &osc0 || parent == &pll0)
++		control &= ~PM_BIT(OSCSEL);
++	else
++		return -EINVAL;
++
++	if (parent == &pll0 || parent == &pll1)
++		control |= PM_BIT(PLLSEL);
++	else
++		control &= ~PM_BIT(PLLSEL);
++
++	pm_writel(GCCTRL(clk->index), control);
++	clk->parent = parent;
++
++	return 0;
++}
++
++static void __init genclk_init_parent(struct clk *clk)
++{
++	u32 control;
++	struct clk *parent;
++
++	BUG_ON(clk->index > 7);
++
++	control = pm_readl(GCCTRL(clk->index));
++	if (control & PM_BIT(OSCSEL))
++		parent = (control & PM_BIT(PLLSEL)) ? &pll1 : &osc1;
++	else
++		parent = (control & PM_BIT(PLLSEL)) ? &pll0 : &osc0;
++
++	clk->parent = parent;
++}
++
++/* --------------------------------------------------------------------
++ *  System peripherals
++ * -------------------------------------------------------------------- */
++static struct resource at32_pm0_resource[] = {
++	{
++		.start	= 0xfff00000,
++		.end	= 0xfff0007f,
++		.flags	= IORESOURCE_MEM,
++	},
++	IRQ(20),
++};
++
++static struct resource at32ap700x_rtc0_resource[] = {
++	{
++		.start	= 0xfff00080,
++		.end	= 0xfff000af,
++		.flags	= IORESOURCE_MEM,
++	},
++	IRQ(21),
++};
++
++static struct resource at32_wdt0_resource[] = {
++	{
++		.start	= 0xfff000b0,
++		.end	= 0xfff000cf,
++		.flags	= IORESOURCE_MEM,
++	},
++};
++
++static struct resource at32_eic0_resource[] = {
++	{
++		.start	= 0xfff00100,
++		.end	= 0xfff0013f,
++		.flags	= IORESOURCE_MEM,
++	},
++	IRQ(19),
++};
++
++DEFINE_DEV(at32_pm, 0);
++DEFINE_DEV(at32ap700x_rtc, 0);
++DEFINE_DEV(at32_wdt, 0);
++DEFINE_DEV(at32_eic, 0);
++
++/*
++ * Peripheral clock for PM, RTC, WDT and EIC. PM will ensure that this
++ * is always running.
++ */
++static struct clk at32_pm_pclk = {
++	.name		= "pclk",
++	.dev		= &at32_pm0_device.dev,
++	.parent		= &pbb_clk,
++	.mode		= pbb_clk_mode,
++	.get_rate	= pbb_clk_get_rate,
++	.users		= 1,
++	.index		= 0,
++};
++
++static struct resource intc0_resource[] = {
++	PBMEM(0xfff00400),
++};
++struct platform_device at32_intc0_device = {
++	.name		= "intc",
++	.id		= 0,
++	.resource	= intc0_resource,
++	.num_resources	= ARRAY_SIZE(intc0_resource),
++};
++DEV_CLK(pclk, at32_intc0, pbb, 1);
++
++static struct clk ebi_clk = {
++	.name		= "ebi",
++	.parent		= &hsb_clk,
++	.mode		= hsb_clk_mode,
++	.get_rate	= hsb_clk_get_rate,
++	.users		= 1,
++};
++static struct clk hramc_clk = {
++	.name		= "hramc",
++	.parent		= &hsb_clk,
++	.mode		= hsb_clk_mode,
++	.get_rate	= hsb_clk_get_rate,
++	.users		= 1,
++	.index		= 3,
++};
++
++static struct resource smc0_resource[] = {
++	PBMEM(0xfff03400),
++};
++DEFINE_DEV(smc, 0);
++DEV_CLK(pclk, smc0, pbb, 13);
++DEV_CLK(mck, smc0, hsb, 0);
++
++static struct platform_device pdc_device = {
++	.name		= "pdc",
++	.id		= 0,
++};
++DEV_CLK(hclk, pdc, hsb, 4);
++DEV_CLK(pclk, pdc, pba, 16);
++
++static struct clk pico_clk = {
++	.name		= "pico",
++	.parent		= &cpu_clk,
++	.mode		= cpu_clk_mode,
++	.get_rate	= cpu_clk_get_rate,
++	.users		= 1,
++};
++
++static struct resource dmaca0_resource[] = {
++	{
++		.start	= 0xff200000,
++		.end	= 0xff20ffff,
++		.flags	= IORESOURCE_MEM,
++	},
++	IRQ(2),
++};
++DEFINE_DEV(dmaca, 0);
++DEV_CLK(hclk, dmaca0, hsb, 10);
++
++/* --------------------------------------------------------------------
++ * HMATRIX
++ * -------------------------------------------------------------------- */
++
++static struct clk hmatrix_clk = {
++	.name		= "hmatrix_clk",
++	.parent		= &pbb_clk,
++	.mode		= pbb_clk_mode,
++	.get_rate	= pbb_clk_get_rate,
++	.index		= 2,
++	.users		= 1,
++};
++#define HMATRIX_BASE	((void __iomem *)0xfff00800)
++
++#define hmatrix_readl(reg)					\
++	__raw_readl((HMATRIX_BASE) + HMATRIX_##reg)
++#define hmatrix_writel(reg,value)				\
++	__raw_writel((value), (HMATRIX_BASE) + HMATRIX_##reg)
++
++/*
++ * Set bits in the HMATRIX Special Function Register (SFR) used by the
++ * External Bus Interface (EBI). This can be used to enable special
++ * features like CompactFlash support, NAND Flash support, etc. on
++ * certain chipselects.
++ */
++static inline void set_ebi_sfr_bits(u32 mask)
++{
++	u32 sfr;
++
++	clk_enable(&hmatrix_clk);
++	sfr = hmatrix_readl(SFR4);
++	sfr |= mask;
++	hmatrix_writel(SFR4, sfr);
++	clk_disable(&hmatrix_clk);
++}
++
++/* --------------------------------------------------------------------
++ *  System Timer/Counter (TC)
++ * -------------------------------------------------------------------- */
++static struct resource at32_systc0_resource[] = {
++	PBMEM(0xfff00c00),
++	IRQ(22),
++};
++struct platform_device at32_systc0_device = {
++	.name		= "systc",
++	.id		= 0,
++	.resource	= at32_systc0_resource,
++	.num_resources	= ARRAY_SIZE(at32_systc0_resource),
++};
++DEV_CLK(pclk, at32_systc0, pbb, 3);
++
++/* --------------------------------------------------------------------
++ *  PIO
++ * -------------------------------------------------------------------- */
++
++static struct resource pio0_resource[] = {
++	PBMEM(0xffe02800),
++	IRQ(13),
++};
++DEFINE_DEV(pio, 0);
++DEV_CLK(mck, pio0, pba, 10);
++
++static struct resource pio1_resource[] = {
++	PBMEM(0xffe02c00),
++	IRQ(14),
++};
++DEFINE_DEV(pio, 1);
++DEV_CLK(mck, pio1, pba, 11);
++
++static struct resource pio2_resource[] = {
++	PBMEM(0xffe03000),
++	IRQ(15),
++};
++DEFINE_DEV(pio, 2);
++DEV_CLK(mck, pio2, pba, 12);
++
++static struct resource pio3_resource[] = {
++	PBMEM(0xffe03400),
++	IRQ(16),
++};
++DEFINE_DEV(pio, 3);
++DEV_CLK(mck, pio3, pba, 13);
++
++static struct resource pio4_resource[] = {
++	PBMEM(0xffe03800),
++	IRQ(17),
++};
++DEFINE_DEV(pio, 4);
++DEV_CLK(mck, pio4, pba, 14);
++
++void __init at32_add_system_devices(void)
++{
++	platform_device_register(&at32_pm0_device);
++	platform_device_register(&at32_intc0_device);
++	platform_device_register(&at32ap700x_rtc0_device);
++	platform_device_register(&at32_wdt0_device);
++	platform_device_register(&at32_eic0_device);
++	platform_device_register(&smc0_device);
++	platform_device_register(&pdc_device);
++	platform_device_register(&dmaca0_device);
++
++	platform_device_register(&at32_systc0_device);
++
++	platform_device_register(&pio0_device);
++	platform_device_register(&pio1_device);
++	platform_device_register(&pio2_device);
++	platform_device_register(&pio3_device);
++	platform_device_register(&pio4_device);
++}
++
++/* --------------------------------------------------------------------
++ *  USART
++ * -------------------------------------------------------------------- */
++
++static struct atmel_uart_data atmel_usart0_data = {
++	.use_dma_tx	= 1,
++	.use_dma_rx	= 1,
++};
++static struct resource atmel_usart0_resource[] = {
++	PBMEM(0xffe00c00),
++	IRQ(6),
++};
++DEFINE_DEV_DATA(atmel_usart, 0);
++DEV_CLK(usart, atmel_usart0, pba, 3);
++
++static struct atmel_uart_data atmel_usart1_data = {
++	.use_dma_tx	= 1,
++	.use_dma_rx	= 1,
++};
++static struct resource atmel_usart1_resource[] = {
++	PBMEM(0xffe01000),
++	IRQ(7),
++};
++DEFINE_DEV_DATA(atmel_usart, 1);
++DEV_CLK(usart, atmel_usart1, pba, 4);
++
++static struct atmel_uart_data atmel_usart2_data = {
++	.use_dma_tx	= 1,
++	.use_dma_rx	= 1,
++};
++static struct resource atmel_usart2_resource[] = {
++	PBMEM(0xffe01400),
++	IRQ(8),
++};
++DEFINE_DEV_DATA(atmel_usart, 2);
++DEV_CLK(usart, atmel_usart2, pba, 5);
++
++static struct atmel_uart_data atmel_usart3_data = {
++	.use_dma_tx	= 1,
++	.use_dma_rx	= 1,
++};
++static struct resource atmel_usart3_resource[] = {
++	PBMEM(0xffe01800),
++	IRQ(9),
++};
++DEFINE_DEV_DATA(atmel_usart, 3);
++DEV_CLK(usart, atmel_usart3, pba, 6);
++
++static inline void configure_usart0_pins(void)
++{
++	select_peripheral(PA(8),  PERIPH_B, 0);	/* RXD	*/
++	select_peripheral(PA(9),  PERIPH_B, 0);	/* TXD	*/
++}
++
++static inline void configure_usart1_pins(void)
++{
++	select_peripheral(PA(17), PERIPH_A, 0);	/* RXD	*/
++	select_peripheral(PA(18), PERIPH_A, 0);	/* TXD	*/
++}
++
++static inline void configure_usart2_pins(void)
++{
++	select_peripheral(PB(26), PERIPH_B, 0);	/* RXD	*/
++	select_peripheral(PB(27), PERIPH_B, 0);	/* TXD	*/
++}
++
++static inline void configure_usart3_pins(void)
++{
++	select_peripheral(PB(18), PERIPH_B, 0);	/* RXD	*/
++	select_peripheral(PB(17), PERIPH_B, 0);	/* TXD	*/
++}
++
++static struct platform_device *__initdata at32_usarts[4];
++
++void __init at32_map_usart(unsigned int hw_id, unsigned int line)
++{
++	struct platform_device *pdev;
++
++	switch (hw_id) {
++	case 0:
++		pdev = &atmel_usart0_device;
++		configure_usart0_pins();
++		break;
++	case 1:
++		pdev = &atmel_usart1_device;
++		configure_usart1_pins();
++		break;
++	case 2:
++		pdev = &atmel_usart2_device;
++		configure_usart2_pins();
++		break;
++	case 3:
++		pdev = &atmel_usart3_device;
++		configure_usart3_pins();
++		break;
++	default:
++		return;
++	}
++
++	if (PXSEG(pdev->resource[0].start) == P4SEG) {
++		/* Addresses in the P4 segment are permanently mapped 1:1 */
++		struct atmel_uart_data *data = pdev->dev.platform_data;
++		data->regs = (void __iomem *)pdev->resource[0].start;
++	}
++
++	pdev->id = line;
++	at32_usarts[line] = pdev;
++}
++
++struct platform_device *__init at32_add_device_usart(unsigned int id)
++{
++	platform_device_register(at32_usarts[id]);
++	return at32_usarts[id];
++}
++
++struct platform_device *atmel_default_console_device;
++
++void __init at32_setup_serial_console(unsigned int usart_id)
++{
++	atmel_default_console_device = at32_usarts[usart_id];
++}
++
++/* --------------------------------------------------------------------
++ *  Ethernet
++ * -------------------------------------------------------------------- */
++
++#ifdef CONFIG_CPU_AT32AP7000
++static struct eth_platform_data macb0_data;
++static struct resource macb0_resource[] = {
++	PBMEM(0xfff01800),
++	IRQ(25),
++};
++DEFINE_DEV_DATA(macb, 0);
++DEV_CLK(hclk, macb0, hsb, 8);
++DEV_CLK(pclk, macb0, pbb, 6);
++
++static struct eth_platform_data macb1_data;
++static struct resource macb1_resource[] = {
++	PBMEM(0xfff01c00),
++	IRQ(26),
++};
++DEFINE_DEV_DATA(macb, 1);
++DEV_CLK(hclk, macb1, hsb, 9);
++DEV_CLK(pclk, macb1, pbb, 7);
++
++struct platform_device *__init
++at32_add_device_eth(unsigned int id, struct eth_platform_data *data)
++{
++	struct platform_device *pdev;
++
++	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	*/
++
++		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	*/
++		}
++		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	*/
++
++		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	*/
++		}
++		break;
++
++	default:
++		return NULL;
++	}
++
++	memcpy(pdev->dev.platform_data, data, sizeof(struct eth_platform_data));
++	platform_device_register(pdev);
++
++	return pdev;
++}
++#endif
++
++/* --------------------------------------------------------------------
++ *  SPI
++ * -------------------------------------------------------------------- */
++static struct resource atmel_spi0_resource[] = {
++	PBMEM(0xffe00000),
++	IRQ(3),
++};
++DEFINE_DEV(atmel_spi, 0);
++DEV_CLK(spi_clk, atmel_spi0, pba, 0);
++
++static struct resource atmel_spi1_resource[] = {
++	PBMEM(0xffe00400),
++	IRQ(4),
++};
++DEFINE_DEV(atmel_spi, 1);
++DEV_CLK(spi_clk, atmel_spi1, pba, 1);
++
++static void __init
++at32_spi_setup_slaves(unsigned int bus_num, struct spi_board_info *b,
++		      unsigned int n, const u8 *pins)
++{
++	unsigned int pin, mode;
++
++	for (; n; n--, b++) {
++		b->bus_num = bus_num;
++		if (b->chip_select >= 4)
++			continue;
++		pin = (unsigned)b->controller_data;
++		if (!pin) {
++			pin = pins[b->chip_select];
++			b->controller_data = (void *)pin;
++		}
++		mode = AT32_GPIOF_OUTPUT;
++		if (!(b->mode & SPI_CS_HIGH))
++			mode |= AT32_GPIOF_HIGH;
++		at32_select_gpio(pin, mode);
++	}
++}
++
++struct platform_device *__init
++at32_add_device_spi(unsigned int id, struct spi_board_info *b, unsigned int n)
++{
++	/*
++	 * Manage the chipselects as GPIOs, normally using the same pins
++	 * the SPI controller expects; but boards can use other pins.
++	 */
++	static u8 __initdata spi0_pins[] =
++		{ GPIO_PIN_PA(3), GPIO_PIN_PA(4),
++		  GPIO_PIN_PA(5), GPIO_PIN_PA(20), };
++	static u8 __initdata spi1_pins[] =
++		{ GPIO_PIN_PB(2), GPIO_PIN_PB(3),
++		  GPIO_PIN_PB(4), GPIO_PIN_PA(27), };
++	struct platform_device *pdev;
++
++	switch (id) {
++	case 0:
++		pdev = &atmel_spi0_device;
++		select_peripheral(PA(0),  PERIPH_A, 0);	/* MISO	 */
++		select_peripheral(PA(1),  PERIPH_A, 0);	/* MOSI	 */
++		select_peripheral(PA(2),  PERIPH_A, 0);	/* SCK	 */
++		at32_spi_setup_slaves(0, b, n, spi0_pins);
++		break;
++
++	case 1:
++		pdev = &atmel_spi1_device;
++		select_peripheral(PB(0),  PERIPH_B, 0);	/* MISO  */
++		select_peripheral(PB(1),  PERIPH_B, 0);	/* MOSI  */
++		select_peripheral(PB(5),  PERIPH_B, 0);	/* SCK   */
++		at32_spi_setup_slaves(1, b, n, spi1_pins);
++		break;
++
++	default:
++		return NULL;
++	}
++
++	spi_register_board_info(b, n);
++	platform_device_register(pdev);
++	return pdev;
++}
++
++/* --------------------------------------------------------------------
++ *  TWI
++ * -------------------------------------------------------------------- */
++static struct resource atmel_twi0_resource[] __initdata = {
++	PBMEM(0xffe00800),
++	IRQ(5),
++};
++static struct clk atmel_twi0_pclk = {
++	.name		= "twi_pclk",
++	.parent		= &pba_clk,
++	.mode		= pba_clk_mode,
++	.get_rate	= pba_clk_get_rate,
++	.index		= 2,
++};
++
++struct platform_device *__init at32_add_device_twi(unsigned int id)
++{
++	struct platform_device *pdev;
++
++	if (id != 0)
++		return NULL;
++
++	pdev = platform_device_alloc("atmel_twi", id);
++	if (!pdev)
++		return NULL;
++
++	if (platform_device_add_resources(pdev, atmel_twi0_resource,
++				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	*/
++
++	atmel_twi0_pclk.dev = &pdev->dev;
++
++	platform_device_add(pdev);
++	return pdev;
++
++err_add_resources:
++	platform_device_put(pdev);
++	return NULL;
++}
++
++/* --------------------------------------------------------------------
++ * MMC
++ * -------------------------------------------------------------------- */
++static struct resource atmel_mci0_resource[] __initdata = {
++	PBMEM(0xfff02400),
++	IRQ(28),
++};
++static struct clk atmel_mci0_pclk = {
++	.name		= "mci_clk",
++	.parent		= &pbb_clk,
++	.mode		= pbb_clk_mode,
++	.get_rate	= pbb_clk_get_rate,
++	.index		= 9,
++};
++
++struct platform_device *__init at32_add_device_mci(unsigned int id)
++{
++	struct platform_device *pdev;
++
++	if (id != 0)
++		return NULL;
++
++	pdev = platform_device_alloc("atmel_mci", id);
++	if (!pdev)
++		return NULL;
++
++	if (platform_device_add_resources(pdev, atmel_mci0_resource,
++				ARRAY_SIZE(atmel_mci0_resource)))
++		goto err_add_resources;
++
++	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 */
++
++	atmel_mci0_pclk.dev = &pdev->dev;
++
++	platform_device_add(pdev);
++	return pdev;
++
++err_add_resources:
++	platform_device_put(pdev);
++	return NULL;
++}
++
++/* --------------------------------------------------------------------
++ *  LCDC
++ * -------------------------------------------------------------------- */
++#if defined(CONFIG_CPU_AT32AP7000) || defined(CONFIG_CPU_AT32AP7002)
++static struct atmel_lcdfb_info atmel_lcdfb0_data;
++static struct resource atmel_lcdfb0_resource[] = {
++	{
++		.start		= 0xff000000,
++		.end		= 0xff000fff,
++		.flags		= IORESOURCE_MEM,
++	},
++	IRQ(1),
++	{
++		/* Placeholder for pre-allocated fb memory */
++		.start		= 0x00000000,
++		.end		= 0x00000000,
++		.flags		= 0,
++	},
++};
++DEFINE_DEV_DATA(atmel_lcdfb, 0);
++DEV_CLK(hck1, atmel_lcdfb0, hsb, 7);
++static struct clk atmel_lcdfb0_pixclk = {
++	.name		= "lcdc_clk",
++	.dev		= &atmel_lcdfb0_device.dev,
++	.mode		= genclk_mode,
++	.get_rate	= genclk_get_rate,
++	.set_rate	= genclk_set_rate,
++	.set_parent	= genclk_set_parent,
++	.index		= 7,
++};
++
++struct platform_device *__init
++at32_add_device_lcdc(unsigned int id, struct atmel_lcdfb_info *data,
++		     unsigned long fbmem_start, unsigned long fbmem_len)
++{
++	struct platform_device *pdev;
++	struct atmel_lcdfb_info *info;
++	struct fb_monspecs *monspecs;
++	struct fb_videomode *modedb;
++	unsigned int modedb_size;
++
++	/*
++	 * Do a deep copy of the fb data, monspecs and modedb. Make
++	 * sure all allocations are done before setting up the
++	 * portmux.
++	 */
++	monspecs = kmemdup(data->default_monspecs,
++			   sizeof(struct fb_monspecs), GFP_KERNEL);
++	if (!monspecs)
++		return NULL;
++
++	modedb_size = sizeof(struct fb_videomode) * monspecs->modedb_len;
++	modedb = kmemdup(monspecs->modedb, modedb_size, GFP_KERNEL);
++	if (!modedb)
++		goto err_dup_modedb;
++	monspecs->modedb = modedb;
++
++	switch (id) {
++	case 0:
++		pdev = &atmel_lcdfb0_device;
++		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 */
++
++		clk_set_parent(&atmel_lcdfb0_pixclk, &pll0);
++		clk_set_rate(&atmel_lcdfb0_pixclk, clk_get_rate(&pll0));
++		break;
++
++	default:
++		goto err_invalid_id;
++	}
++
++	if (fbmem_len) {
++		pdev->resource[2].start = fbmem_start;
++		pdev->resource[2].end = fbmem_start + fbmem_len - 1;
++		pdev->resource[2].flags = IORESOURCE_MEM;
++	}
++
++	info = pdev->dev.platform_data;
++	memcpy(info, data, sizeof(struct atmel_lcdfb_info));
++	info->default_monspecs = monspecs;
++
++	platform_device_register(pdev);
++	return pdev;
++
++err_invalid_id:
++	kfree(modedb);
++err_dup_modedb:
++	kfree(monspecs);
++	return NULL;
++}
++#endif
++
++/* --------------------------------------------------------------------
++ *  SSC
++ * -------------------------------------------------------------------- */
++static struct resource ssc0_resource[] = {
++	PBMEM(0xffe01c00),
++	IRQ(10),
++};
++DEFINE_DEV(ssc, 0);
++DEV_CLK(pclk, ssc0, pba, 7);
++
++static struct resource ssc1_resource[] = {
++	PBMEM(0xffe02000),
++	IRQ(11),
++};
++DEFINE_DEV(ssc, 1);
++DEV_CLK(pclk, ssc1, pba, 8);
++
++static struct resource ssc2_resource[] = {
++	PBMEM(0xffe02400),
++	IRQ(12),
++};
++DEFINE_DEV(ssc, 2);
++DEV_CLK(pclk, ssc2, pba, 9);
++
++struct platform_device *__init
++at32_add_device_ssc(unsigned int id, unsigned int flags)
++{
++	struct platform_device *pdev;
++
++	switch (id) {
++	case 0:
++		pdev = &ssc0_device;
++		if (flags & ATMEL_SSC_RF)
++			select_peripheral(PA(21), PERIPH_A, 0);	/* RF */
++		if (flags & ATMEL_SSC_RK)
++			select_peripheral(PA(22), PERIPH_A, 0);	/* RK */
++		if (flags & ATMEL_SSC_TK)
++			select_peripheral(PA(23), PERIPH_A, 0);	/* TK */
++		if (flags & ATMEL_SSC_TF)
++			select_peripheral(PA(24), PERIPH_A, 0);	/* TF */
++		if (flags & ATMEL_SSC_TD)
++			select_peripheral(PA(25), PERIPH_A, 0);	/* TD */
++		if (flags & ATMEL_SSC_RD)
++			select_peripheral(PA(26), PERIPH_A, 0);	/* RD */
++		break;
++	case 1:
++		pdev = &ssc1_device;
++		if (flags & ATMEL_SSC_RF)
++			select_peripheral(PA(0), PERIPH_B, 0);	/* RF */
++		if (flags & ATMEL_SSC_RK)
++			select_peripheral(PA(1), PERIPH_B, 0);	/* RK */
++		if (flags & ATMEL_SSC_TK)
++			select_peripheral(PA(2), PERIPH_B, 0);	/* TK */
++		if (flags & ATMEL_SSC_TF)
++			select_peripheral(PA(3), PERIPH_B, 0);	/* TF */
++		if (flags & ATMEL_SSC_TD)
++			select_peripheral(PA(4), PERIPH_B, 0);	/* TD */
++		if (flags & ATMEL_SSC_RD)
++			select_peripheral(PA(5), PERIPH_B, 0);	/* RD */
++		break;
++	case 2:
++		pdev = &ssc2_device;
++		if (flags & ATMEL_SSC_TD)
++			select_peripheral(PB(13), PERIPH_A, 0);	/* TD */
++		if (flags & ATMEL_SSC_RD)
++			select_peripheral(PB(14), PERIPH_A, 0);	/* RD */
++		if (flags & ATMEL_SSC_TK)
++			select_peripheral(PB(15), PERIPH_A, 0);	/* TK */
++		if (flags & ATMEL_SSC_TF)
++			select_peripheral(PB(16), PERIPH_A, 0);	/* TF */
++		if (flags & ATMEL_SSC_RF)
++			select_peripheral(PB(17), PERIPH_A, 0);	/* RF */
++		if (flags & ATMEL_SSC_RK)
++			select_peripheral(PB(18), PERIPH_A, 0);	/* RK */
++		break;
++	default:
++		return NULL;
++	}
++
++	platform_device_register(pdev);
++	return pdev;
++}
++
++/* --------------------------------------------------------------------
++ *  USB Device Controller
++ * -------------------------------------------------------------------- */
++static struct resource usba0_resource[] __initdata = {
++	{
++		.start		= 0xff300000,
++		.end		= 0xff3fffff,
++		.flags		= IORESOURCE_MEM,
++	}, {
++		.start		= 0xfff03000,
++		.end		= 0xfff033ff,
++		.flags		= IORESOURCE_MEM,
++	},
++	IRQ(31),
++};
++static struct clk usba0_pclk = {
++	.name		= "pclk",
++	.parent		= &pbb_clk,
++	.mode		= pbb_clk_mode,
++	.get_rate	= pbb_clk_get_rate,
++	.index		= 12,
++};
++static struct clk usba0_hclk = {
++	.name		= "hclk",
++	.parent		= &hsb_clk,
++	.mode		= hsb_clk_mode,
++	.get_rate	= hsb_clk_get_rate,
++	.index		= 6,
++};
++
++struct platform_device *__init
++at32_add_device_usba(unsigned int id, struct usba_platform_data *data)
++{
++	struct platform_device *pdev;
++
++	if (id != 0)
++		return NULL;
++
++	pdev = platform_device_alloc("atmel_usba_udc", 0);
++	if (!pdev)
++		return NULL;
++
++	if (platform_device_add_resources(pdev, usba0_resource,
++					  ARRAY_SIZE(usba0_resource)))
++		goto out_free_pdev;
++
++	if (data) {
++		if (platform_device_add_data(pdev, data, sizeof(*data)))
++			goto out_free_pdev;
++
++		if (data->vbus_pin != GPIO_PIN_NONE)
++			at32_select_gpio(data->vbus_pin, 0);
++	}
++
++	usba0_pclk.dev = &pdev->dev;
++	usba0_hclk.dev = &pdev->dev;
++
++	platform_device_add(pdev);
++
++	return pdev;
++
++out_free_pdev:
++	platform_device_put(pdev);
++	return NULL;
++}
++
++/* --------------------------------------------------------------------
++ * IDE / CompactFlash
++ * -------------------------------------------------------------------- */
++#if defined(CONFIG_CPU_AT32AP7000) || defined(CONFIG_CPU_AT32AP7001)
++static struct resource at32_smc_cs4_resource[] __initdata = {
++	{
++		.start	= 0x04000000,
++		.end	= 0x07ffffff,
++		.flags	= IORESOURCE_MEM,
++	},
++	IRQ(~0UL), /* Magic IRQ will be overridden */
++};
++static struct resource at32_smc_cs5_resource[] __initdata = {
++	{
++		.start	= 0x20000000,
++		.end	= 0x23ffffff,
++		.flags	= IORESOURCE_MEM,
++	},
++	IRQ(~0UL), /* Magic IRQ will be overridden */
++};
++
++static int __init at32_init_ide_or_cf(struct platform_device *pdev,
++		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),
++	};
++	static bool common_pins_initialized __initdata = false;
++	unsigned int extint_pin;
++	int ret;
++
++	if (extint >= ARRAY_SIZE(extint_pin_map))
++		return -EINVAL;
++	extint_pin = extint_pin_map[extint];
++
++	switch (cs) {
++	case 4:
++		ret = platform_device_add_resources(pdev,
++				at32_smc_cs4_resource,
++				ARRAY_SIZE(at32_smc_cs4_resource));
++		if (ret)
++			return ret;
++
++		select_peripheral(PE(21), PERIPH_A, 0); /* NCS4   -> OE_N  */
++		set_ebi_sfr_bits(HMATRIX_BIT(CS4A));
++		break;
++	case 5:
++		ret = platform_device_add_resources(pdev,
++				at32_smc_cs5_resource,
++				ARRAY_SIZE(at32_smc_cs5_resource));
++		if (ret)
++			return ret;
++
++		select_peripheral(PE(22), PERIPH_A, 0); /* NCS5   -> OE_N  */
++		set_ebi_sfr_bits(HMATRIX_BIT(CS5A));
++		break;
++	default:
++		return -EINVAL;
++	}
++
++	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 */
++		common_pins_initialized = true;
++	}
++
++	at32_select_periph(extint_pin, GPIO_PERIPH_A, AT32_GPIOF_DEGLITCH);
++
++	pdev->resource[1].start = EIM_IRQ_BASE + extint;
++	pdev->resource[1].end = pdev->resource[1].start;
++
++	return 0;
++}
++
++struct platform_device *__init
++at32_add_device_ide(unsigned int id, unsigned int extint,
++		    struct ide_platform_data *data)
++{
++	struct platform_device *pdev;
++
++	pdev = platform_device_alloc("at32_ide", id);
++	if (!pdev)
++		goto fail;
++
++	if (platform_device_add_data(pdev, data,
++				sizeof(struct ide_platform_data)))
++		goto fail;
++
++	if (at32_init_ide_or_cf(pdev, data->cs, extint))
++		goto fail;
++
++	platform_device_add(pdev);
++	return pdev;
++
++fail:
++	platform_device_put(pdev);
++	return NULL;
++}
++
++struct platform_device *__init
++at32_add_device_cf(unsigned int id, unsigned int extint,
++		    struct cf_platform_data *data)
++{
++	struct platform_device *pdev;
++
++	pdev = platform_device_alloc("at32_cf", id);
++	if (!pdev)
++		goto fail;
++
++	if (platform_device_add_data(pdev, data,
++				sizeof(struct cf_platform_data)))
++		goto fail;
++
++	if (at32_init_ide_or_cf(pdev, data->cs, extint))
++		goto fail;
++
++	if (data->detect_pin != GPIO_PIN_NONE)
++		at32_select_gpio(data->detect_pin, AT32_GPIOF_DEGLITCH);
++	if (data->reset_pin != GPIO_PIN_NONE)
++		at32_select_gpio(data->reset_pin, 0);
++	if (data->vcc_pin != GPIO_PIN_NONE)
++		at32_select_gpio(data->vcc_pin, 0);
++	/* READY is used as extint, so we can't select it as gpio */
++
++	platform_device_add(pdev);
++	return pdev;
++
++fail:
++	platform_device_put(pdev);
++	return NULL;
++}
++#endif
++
++/* --------------------------------------------------------------------
++ * AC97C
++ * -------------------------------------------------------------------- */
++static struct resource atmel_ac97c0_resource[] __initdata = {
++	PBMEM(0xfff02800),
++	IRQ(29),
++};
++static struct clk atmel_ac97c0_pclk = {
++	.name		= "pclk",
++	.parent		= &pbb_clk,
++	.mode		= pbb_clk_mode,
++	.get_rate	= pbb_clk_get_rate,
++	.index		= 10,
++};
++
++struct platform_device *__init at32_add_device_ac97c(unsigned int id)
++{
++	struct platform_device *pdev;
++
++	if (id != 0)
++		return NULL;
++
++	pdev = platform_device_alloc("atmel_ac97c", id);
++	if (!pdev)
++		return NULL;
++
++	if (platform_device_add_resources(pdev, atmel_ac97c0_resource,
++				ARRAY_SIZE(atmel_ac97c0_resource)))
++		goto err_add_resources;
++
++	select_peripheral(PB(20), PERIPH_B, 0);	/* SYNC	*/
++	select_peripheral(PB(21), PERIPH_B, 0);	/* SDO	*/
++	select_peripheral(PB(22), PERIPH_B, 0);	/* SDI	*/
++	select_peripheral(PB(23), PERIPH_B, 0);	/* SCLK	*/
++
++	atmel_ac97c0_pclk.dev = &pdev->dev;
++
++	platform_device_add(pdev);
++	return pdev;
++
++err_add_resources:
++	platform_device_put(pdev);
++	return NULL;
++}
++
++/* --------------------------------------------------------------------
++ * ABDAC
++ * -------------------------------------------------------------------- */
++static struct resource abdac0_resource[] __initdata = {
++	PBMEM(0xfff02000),
++	IRQ(27),
++};
++static struct clk abdac0_pclk = {
++	.name		= "pclk",
++	.parent		= &pbb_clk,
++	.mode		= pbb_clk_mode,
++	.get_rate	= pbb_clk_get_rate,
++	.index		= 8,
++};
++static struct clk abdac0_sample_clk = {
++	.name		= "sample_clk",
++	.mode		= genclk_mode,
++	.get_rate	= genclk_get_rate,
++	.set_rate	= genclk_set_rate,
++	.set_parent	= genclk_set_parent,
++	.index		= 6,
++};
++
++struct platform_device *__init at32_add_device_abdac(unsigned int id)
++{
++	struct platform_device *pdev;
++
++	if (id != 0)
++		return NULL;
++
++	pdev = platform_device_alloc("abdac", id);
++	if (!pdev)
++		return NULL;
++
++	if (platform_device_add_resources(pdev, abdac0_resource,
++				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	*/
++
++	abdac0_pclk.dev = &pdev->dev;
++	abdac0_sample_clk.dev = &pdev->dev;
++
++	platform_device_add(pdev);
++	return pdev;
++
++err_add_resources:
++	platform_device_put(pdev);
++	return NULL;
++}
++
++/* --------------------------------------------------------------------
++ *  GCLK
++ * -------------------------------------------------------------------- */
++static struct clk gclk0 = {
++	.name		= "gclk0",
++	.mode		= genclk_mode,
++	.get_rate	= genclk_get_rate,
++	.set_rate	= genclk_set_rate,
++	.set_parent	= genclk_set_parent,
++	.index		= 0,
++};
++static struct clk gclk1 = {
++	.name		= "gclk1",
++	.mode		= genclk_mode,
++	.get_rate	= genclk_get_rate,
++	.set_rate	= genclk_set_rate,
++	.set_parent	= genclk_set_parent,
++	.index		= 1,
++};
++static struct clk gclk2 = {
++	.name		= "gclk2",
++	.mode		= genclk_mode,
++	.get_rate	= genclk_get_rate,
++	.set_rate	= genclk_set_rate,
++	.set_parent	= genclk_set_parent,
++	.index		= 2,
++};
++static struct clk gclk3 = {
++	.name		= "gclk3",
++	.mode		= genclk_mode,
++	.get_rate	= genclk_get_rate,
++	.set_rate	= genclk_set_rate,
++	.set_parent	= genclk_set_parent,
++	.index		= 3,
++};
++static struct clk gclk4 = {
++	.name		= "gclk4",
++	.mode		= genclk_mode,
++	.get_rate	= genclk_get_rate,
++	.set_rate	= genclk_set_rate,
++	.set_parent	= genclk_set_parent,
++	.index		= 4,
++};
++
++struct clk *at32_clock_list[] = {
++	&osc32k,
++	&osc0,
++	&osc1,
++	&pll0,
++	&pll1,
++	&cpu_clk,
++	&hsb_clk,
++	&pba_clk,
++	&pbb_clk,
++	&at32_pm_pclk,
++	&at32_intc0_pclk,
++	&hmatrix_clk,
++	&ebi_clk,
++	&hramc_clk,
++	&smc0_pclk,
++	&smc0_mck,
++	&pdc_hclk,
++	&pdc_pclk,
++	&dmaca0_hclk,
++	&pico_clk,
++	&pio0_mck,
++	&pio1_mck,
++	&pio2_mck,
++	&pio3_mck,
++	&pio4_mck,
++	&at32_systc0_pclk,
++	&atmel_usart0_usart,
++	&atmel_usart1_usart,
++	&atmel_usart2_usart,
++	&atmel_usart3_usart,
++#if defined(CONFIG_CPU_AT32AP7000)
++	&macb0_hclk,
++	&macb0_pclk,
++	&macb1_hclk,
++	&macb1_pclk,
++#endif
++	&atmel_spi0_spi_clk,
++	&atmel_spi1_spi_clk,
++	&atmel_twi0_pclk,
++	&atmel_mci0_pclk,
++#if defined(CONFIG_CPU_AT32AP7000) || defined(CONFIG_CPU_AT32AP7002)
++	&atmel_lcdfb0_hck1,
++	&atmel_lcdfb0_pixclk,
++#endif
++	&ssc0_pclk,
++	&ssc1_pclk,
++	&ssc2_pclk,
++	&usba0_hclk,
++	&usba0_pclk,
++	&atmel_ac97c0_pclk,
++	&abdac0_pclk,
++	&abdac0_sample_clk,
++	&gclk0,
++	&gclk1,
++	&gclk2,
++	&gclk3,
++	&gclk4,
++};
++unsigned int at32_nr_clocks = ARRAY_SIZE(at32_clock_list);
++
++void __init at32_portmux_init(void)
++{
++	at32_init_pio(&pio0_device);
++	at32_init_pio(&pio1_device);
++	at32_init_pio(&pio2_device);
++	at32_init_pio(&pio3_device);
++	at32_init_pio(&pio4_device);
++}
++
++void __init at32_clock_init(void)
++{
++	u32 cpu_mask = 0, hsb_mask = 0, pba_mask = 0, pbb_mask = 0;
++	int i;
++
++	if (pm_readl(MCCTRL) & PM_BIT(PLLSEL)) {
++		main_clock = &pll0;
++		cpu_clk.parent = &pll0;
++	} else {
++		main_clock = &osc0;
++		cpu_clk.parent = &osc0;
++	}
++
++	if (pm_readl(PLL0) & PM_BIT(PLLOSC))
++		pll0.parent = &osc1;
++	if (pm_readl(PLL1) & PM_BIT(PLLOSC))
++		pll1.parent = &osc1;
++
++	genclk_init_parent(&gclk0);
++	genclk_init_parent(&gclk1);
++	genclk_init_parent(&gclk2);
++	genclk_init_parent(&gclk3);
++	genclk_init_parent(&gclk4);
++#if defined(CONFIG_CPU_AT32AP7000) || defined(CONFIG_CPU_AT32AP7002)
++	genclk_init_parent(&atmel_lcdfb0_pixclk);
++#endif
++	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...
++	 */
++	for (i = 0; i < ARRAY_SIZE(at32_clock_list); i++) {
++		struct clk *clk = at32_clock_list[i];
++
++		if (clk->users == 0)
++			continue;
++
++		if (clk->mode == &cpu_clk_mode)
++			cpu_mask |= 1 << clk->index;
++		else if (clk->mode == &hsb_clk_mode)
++			hsb_mask |= 1 << clk->index;
++		else if (clk->mode == &pba_clk_mode)
++			pba_mask |= 1 << clk->index;
++		else if (clk->mode == &pbb_clk_mode)
++			pbb_mask |= 1 << clk->index;
++	}
++
++	pm_writel(CPU_MASK, cpu_mask);
++	pm_writel(HSB_MASK, hsb_mask);
++	pm_writel(PBA_MASK, pba_mask);
++	pm_writel(PBB_MASK, pbb_mask);
++}
+diff --git a/arch/avr32/mach-at32ap/extint.c b/arch/avr32/mach-at32ap/extint.c
+index f5bfd4c..c36a6d5 100644
+--- a/arch/avr32/mach-at32ap/extint.c
++++ b/arch/avr32/mach-at32ap/extint.c
+@@ -26,16 +26,10 @@
+ #define EIC_MODE				0x0014
+ #define EIC_EDGE				0x0018
+ #define EIC_LEVEL				0x001c
+-#define EIC_TEST				0x0020
+ #define EIC_NMIC				0x0024
+ 
+-/* Bitfields in TEST */
+-#define EIC_TESTEN_OFFSET			31
+-#define EIC_TESTEN_SIZE				1
+-
+ /* Bitfields in NMIC */
+-#define EIC_EN_OFFSET				0
+-#define EIC_EN_SIZE				1
++#define EIC_NMIC_ENABLE				(1 << 0)
+ 
+ /* Bit manipulation macros */
+ #define EIC_BIT(name)					\
+@@ -63,6 +57,9 @@ struct eic {
+ 	unsigned int first_irq;
+ };
+ 
++static struct eic *nmi_eic;
++static bool nmi_enabled;
++
+ static void eic_ack_irq(unsigned int irq)
+ {
+ 	struct eic *eic = get_irq_chip_data(irq);
+@@ -133,8 +130,11 @@ static int eic_set_irq_type(unsigned int irq, unsigned int flow_type)
+ 		eic_writel(eic, EDGE, edge);
+ 		eic_writel(eic, LEVEL, level);
+ 
+-		if (flow_type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH))
++		if (flow_type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) {
+ 			flow_type |= IRQ_LEVEL;
++			__set_irq_handler_unlocked(irq, handle_level_irq);
++		} else
++			__set_irq_handler_unlocked(irq, handle_edge_irq);
+ 		desc->status &= ~(IRQ_TYPE_SENSE_MASK | IRQ_LEVEL);
+ 		desc->status |= flow_type;
+ 	}
+@@ -154,9 +154,8 @@ static struct irq_chip eic_chip = {
+ static void demux_eic_irq(unsigned int irq, struct irq_desc *desc)
+ {
+ 	struct eic *eic = desc->handler_data;
+-	struct irq_desc *ext_desc;
+ 	unsigned long status, pending;
+-	unsigned int i, ext_irq;
++	unsigned int i;
+ 
+ 	status = eic_readl(eic, ISR);
+ 	pending = status & eic_readl(eic, IMR);
+@@ -165,15 +164,28 @@ static void demux_eic_irq(unsigned int irq, struct irq_desc *desc)
+ 		i = fls(pending) - 1;
+ 		pending &= ~(1 << i);
+ 
+-		ext_irq = i + eic->first_irq;
+-		ext_desc = irq_desc + ext_irq;
+-		if (ext_desc->status & IRQ_LEVEL)
+-			handle_level_irq(ext_irq, ext_desc);
+-		else
+-			handle_edge_irq(ext_irq, ext_desc);
++		generic_handle_irq(i + eic->first_irq);
+ 	}
+ }
+ 
++int nmi_enable(void)
++{
++	nmi_enabled = true;
++
++	if (nmi_eic)
++		eic_writel(nmi_eic, NMIC, EIC_NMIC_ENABLE);
++
++	return 0;
++}
++
++void nmi_disable(void)
++{
++	if (nmi_eic)
++		eic_writel(nmi_eic, NMIC, 0);
++
++	nmi_enabled = false;
++}
++
+ static int __init eic_probe(struct platform_device *pdev)
+ {
+ 	struct eic *eic;
+@@ -214,14 +226,13 @@ static int __init eic_probe(struct platform_device *pdev)
+ 	pattern = eic_readl(eic, MODE);
+ 	nr_irqs = fls(pattern);
+ 
+-	/* Trigger on falling edge unless overridden by driver */
+-	eic_writel(eic, MODE, 0UL);
++	/* Trigger on low level unless overridden by driver */
+ 	eic_writel(eic, EDGE, 0UL);
++	eic_writel(eic, LEVEL, 0UL);
+ 
+ 	eic->chip = &eic_chip;
+ 
+ 	for (i = 0; i < nr_irqs; i++) {
+-		/* NOTE the handler we set here is ignored by the demux */
+ 		set_irq_chip_and_handler(eic->first_irq + i, &eic_chip,
+ 					 handle_level_irq);
+ 		set_irq_chip_data(eic->first_irq + i, eic);
+@@ -230,6 +241,16 @@ static int __init eic_probe(struct platform_device *pdev)
+ 	set_irq_chained_handler(int_irq, demux_eic_irq);
+ 	set_irq_data(int_irq, eic);
+ 
++	if (pdev->id == 0) {
++		nmi_eic = eic;
++		if (nmi_enabled)
++			/*
++			 * Someone tried to enable NMI before we were
++			 * ready. Do it now.
++			 */
++			nmi_enable();
++	}
++
+ 	dev_info(&pdev->dev,
+ 		 "External Interrupt Controller at 0x%p, IRQ %u\n",
+ 		 eic->regs, int_irq);
+diff --git a/arch/avr32/mm/dma-coherent.c b/arch/avr32/mm/dma-coherent.c
+index 177fea8..6d8c794 100644
+--- a/arch/avr32/mm/dma-coherent.c
++++ b/arch/avr32/mm/dma-coherent.c
+@@ -41,6 +41,13 @@ static struct page *__dma_alloc(struct device *dev, size_t size,
+ 	struct page *page, *free, *end;
+ 	int order;
+ 
++	/* Following is a work-around (a.k.a. hack) to prevent pages
++	 * with __GFP_COMP being passed to split_page() which cannot
++	 * handle them.  The real problem is that this flag probably
++	 * should be 0 on AVR32 as it is not supported on this
++	 * platform--see CONFIG_HUGETLB_PAGE. */
++	gfp &= ~(__GFP_COMP);
++
+ 	size = PAGE_ALIGN(size);
+ 	order = get_order(size);
+ 
+diff --git a/arch/avr32/mm/tlb.c b/arch/avr32/mm/tlb.c
+index 5667201..b835257 100644
+--- a/arch/avr32/mm/tlb.c
++++ b/arch/avr32/mm/tlb.c
+@@ -348,7 +348,7 @@ static int tlb_show(struct seq_file *tlb, void *v)
+ 	return 0;
+ }
+ 
+-static struct seq_operations tlb_ops = {
++static const struct seq_operations tlb_ops = {
+ 	.start		= tlb_start,
+ 	.next		= tlb_next,
+ 	.stop		= tlb_stop,
+diff --git a/arch/avr32/oprofile/Makefile b/arch/avr32/oprofile/Makefile
+new file mode 100644
+index 0000000..1fe81c3
+--- /dev/null
++++ b/arch/avr32/oprofile/Makefile
+@@ -0,0 +1,8 @@
++obj-$(CONFIG_OPROFILE) += oprofile.o
++
++oprofile-y		:= $(addprefix ../../../drivers/oprofile/,	\
++				oprof.o cpu_buffer.o buffer_sync.o	\
++				event_buffer.o oprofile_files.o		\
++				oprofilefs.o oprofile_stats.o		\
++				timer_int.o)
++oprofile-y		+= op_model_avr32.o
+diff --git a/arch/avr32/oprofile/op_model_avr32.c b/arch/avr32/oprofile/op_model_avr32.c
+new file mode 100644
+index 0000000..e2f876b
+--- /dev/null
++++ b/arch/avr32/oprofile/op_model_avr32.c
+@@ -0,0 +1,235 @@
++/*
++ * AVR32 Performance Counter Driver
++ *
++ * Copyright (C) 2005-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 version 2 as
++ * published by the Free Software Foundation.
++ *
++ * Author: Ronny Pedersen
++ */
++#include <linux/errno.h>
++#include <linux/interrupt.h>
++#include <linux/irq.h>
++#include <linux/oprofile.h>
++#include <linux/sched.h>
++#include <linux/types.h>
++
++#include <asm/intc.h>
++#include <asm/sysreg.h>
++#include <asm/system.h>
++
++#define AVR32_PERFCTR_IRQ_GROUP	0
++#define AVR32_PERFCTR_IRQ_LINE	1
++
++enum { PCCNT, PCNT0, PCNT1, NR_counter };
++
++struct avr32_perf_counter {
++	unsigned long	enabled;
++	unsigned long	event;
++	unsigned long	count;
++	unsigned long	unit_mask;
++	unsigned long	kernel;
++	unsigned long	user;
++
++	u32		ie_mask;
++	u32		flag_mask;
++};
++
++static struct avr32_perf_counter counter[NR_counter] = {
++	{
++		.ie_mask	= SYSREG_BIT(IEC),
++		.flag_mask	= SYSREG_BIT(FC),
++	}, {
++		.ie_mask	= SYSREG_BIT(IE0),
++		.flag_mask	= SYSREG_BIT(F0),
++	}, {
++		.ie_mask	= SYSREG_BIT(IE1),
++		.flag_mask	= SYSREG_BIT(F1),
++	},
++};
++
++static void avr32_perf_counter_reset(void)
++{
++	/* Reset all counter and disable/clear all interrupts */
++	sysreg_write(PCCR, (SYSREG_BIT(PCCR_R)
++				| SYSREG_BIT(PCCR_C)
++				| SYSREG_BIT(FC)
++				| SYSREG_BIT(F0)
++				| SYSREG_BIT(F1)));
++}
++
++static irqreturn_t avr32_perf_counter_interrupt(int irq, void *dev_id)
++{
++	struct avr32_perf_counter *ctr = dev_id;
++	struct pt_regs *regs;
++	u32 pccr;
++
++	if (likely(!(intc_get_pending(AVR32_PERFCTR_IRQ_GROUP)
++					& (1 << AVR32_PERFCTR_IRQ_LINE))))
++		return IRQ_NONE;
++
++	regs = get_irq_regs();
++	pccr = sysreg_read(PCCR);
++
++	/* Clear the interrupt flags we're about to handle */
++	sysreg_write(PCCR, pccr);
++
++	/* PCCNT */
++	if (ctr->enabled && (pccr & ctr->flag_mask)) {
++		sysreg_write(PCCNT, -ctr->count);
++		oprofile_add_sample(regs, PCCNT);
++	}
++	ctr++;
++	/* PCNT0 */
++	if (ctr->enabled && (pccr & ctr->flag_mask)) {
++		sysreg_write(PCNT0, -ctr->count);
++		oprofile_add_sample(regs, PCNT0);
++	}
++	ctr++;
++	/* PCNT1 */
++	if (ctr->enabled && (pccr & ctr->flag_mask)) {
++		sysreg_write(PCNT1, -ctr->count);
++		oprofile_add_sample(regs, PCNT1);
++	}
++
++	return IRQ_HANDLED;
++}
++
++static int avr32_perf_counter_create_files(struct super_block *sb,
++		struct dentry *root)
++{
++	struct dentry *dir;
++	unsigned int i;
++	char filename[4];
++
++	for (i = 0; i < NR_counter; i++) {
++		snprintf(filename, sizeof(filename), "%u", i);
++		dir = oprofilefs_mkdir(sb, root, filename);
++
++		oprofilefs_create_ulong(sb, dir, "enabled",
++				&counter[i].enabled);
++		oprofilefs_create_ulong(sb, dir, "event",
++				&counter[i].event);
++		oprofilefs_create_ulong(sb, dir, "count",
++				&counter[i].count);
++
++		/* Dummy entries */
++		oprofilefs_create_ulong(sb, dir, "kernel",
++				&counter[i].kernel);
++		oprofilefs_create_ulong(sb, dir, "user",
++				&counter[i].user);
++		oprofilefs_create_ulong(sb, dir, "unit_mask",
++				&counter[i].unit_mask);
++	}
++
++	return 0;
++}
++
++static int avr32_perf_counter_setup(void)
++{
++	struct avr32_perf_counter *ctr;
++	u32 pccr;
++	int ret;
++	int i;
++
++	pr_debug("avr32_perf_counter_setup\n");
++
++	if (sysreg_read(PCCR) & SYSREG_BIT(PCCR_E)) {
++		printk(KERN_ERR
++			"oprofile: setup: perf counter already enabled\n");
++		return -EBUSY;
++	}
++
++	ret = request_irq(AVR32_PERFCTR_IRQ_GROUP,
++			avr32_perf_counter_interrupt, IRQF_SHARED,
++			"oprofile", counter);
++	if (ret)
++		return ret;
++
++	avr32_perf_counter_reset();
++
++	pccr = 0;
++	for (i = PCCNT; i < NR_counter; i++) {
++		ctr = &counter[i];
++		if (!ctr->enabled)
++			continue;
++
++		pr_debug("enabling counter %d...\n", i);
++
++		pccr |= ctr->ie_mask;
++
++		switch (i) {
++		case PCCNT:
++			/* PCCNT always counts cycles, so no events */
++			sysreg_write(PCCNT, -ctr->count);
++			break;
++		case PCNT0:
++			pccr |= SYSREG_BF(CONF0, ctr->event);
++			sysreg_write(PCNT0, -ctr->count);
++			break;
++		case PCNT1:
++			pccr |= SYSREG_BF(CONF1, ctr->event);
++			sysreg_write(PCNT1, -ctr->count);
++			break;
++		}
++	}
++
++	pr_debug("oprofile: writing 0x%x to PCCR...\n", pccr);
++
++	sysreg_write(PCCR, pccr);
++
++	return 0;
++}
++
++static void avr32_perf_counter_shutdown(void)
++{
++	pr_debug("avr32_perf_counter_shutdown\n");
++
++	avr32_perf_counter_reset();
++	free_irq(AVR32_PERFCTR_IRQ_GROUP, counter);
++}
++
++static int avr32_perf_counter_start(void)
++{
++	pr_debug("avr32_perf_counter_start\n");
++
++	sysreg_write(PCCR, sysreg_read(PCCR) | SYSREG_BIT(PCCR_E));
++
++	return 0;
++}
++
++static void avr32_perf_counter_stop(void)
++{
++	pr_debug("avr32_perf_counter_stop\n");
++
++	sysreg_write(PCCR, sysreg_read(PCCR) & ~SYSREG_BIT(PCCR_E));
++}
++
++static struct oprofile_operations avr32_perf_counter_ops __initdata = {
++	.create_files	= avr32_perf_counter_create_files,
++	.setup		= avr32_perf_counter_setup,
++	.shutdown	= avr32_perf_counter_shutdown,
++	.start		= avr32_perf_counter_start,
++	.stop		= avr32_perf_counter_stop,
++	.cpu_type	= "avr32",
++};
++
++int __init oprofile_arch_init(struct oprofile_operations *ops)
++{
++	if (!(current_cpu_data.features & AVR32_FEATURE_PCTR))
++		return -ENODEV;
++
++	memcpy(ops, &avr32_perf_counter_ops,
++			sizeof(struct oprofile_operations));
++
++	printk(KERN_INFO "oprofile: using AVR32 performance monitoring.\n");
++
++	return 0;
++}
++
++void oprofile_arch_exit(void)
++{
++
++}
+diff --git a/arch/blackfin/Kconfig b/arch/blackfin/Kconfig
+index 25232ba..fc7ca86 100644
+--- a/arch/blackfin/Kconfig
++++ b/arch/blackfin/Kconfig
+@@ -85,11 +85,26 @@ config BF522
+ 	help
+ 	  BF522 Processor Support.
+ 
++config BF523
++	bool "BF523"
++	help
++	  BF523 Processor Support.
++
++config BF524
++	bool "BF524"
++	help
++	  BF524 Processor Support.
++
+ config BF525
+ 	bool "BF525"
+ 	help
+ 	  BF525 Processor Support.
+ 
++config BF526
++	bool "BF526"
++	help
++	  BF526 Processor Support.
++
+ config BF527
+ 	bool "BF527"
+ 	help
+@@ -198,7 +213,7 @@ endchoice
+ 
+ config BF52x
+ 	bool
+-	depends on (BF522 || BF525 || BF527)
++	depends on (BF522 || BF523 || BF524 || BF525 || BF526 || BF527)
+ 	default y
+ 
+ config BF53x
+@@ -253,11 +268,6 @@ config MEM_MT48LC32M16A2TG_75
+ 	depends on (BFIN527_EZKIT)
+ 	default y
+ 
+-config BFIN_SHARED_FLASH_ENET
+-	bool
+-	depends on (BFIN533_STAMP)
+-	default y
+-
+ source "arch/blackfin/mach-bf527/Kconfig"
+ source "arch/blackfin/mach-bf533/Kconfig"
+ source "arch/blackfin/mach-bf561/Kconfig"
+@@ -317,7 +327,7 @@ config VCO_MULT
+ 	range 1 64
+ 	default "22" if BFIN533_EZKIT
+ 	default "45" if BFIN533_STAMP
+-	default "20" if (BFIN537_STAMP || BFIN527_EZKIT)
++	default "20" if (BFIN537_STAMP || BFIN527_EZKIT || BFIN548_EZKIT)
+ 	default "22" if BFIN533_BLUETECHNIX_CM
+ 	default "20" if BFIN537_BLUETECHNIX_CM
+ 	default "20" if BFIN561_BLUETECHNIX_CM
+@@ -354,7 +364,7 @@ config SCLK_DIV
+ 	range 1 15
+ 	default 5 if BFIN533_EZKIT
+ 	default 5 if BFIN533_STAMP
+-	default 4 if (BFIN537_STAMP || BFIN527_EZKIT)
++	default 4 if (BFIN537_STAMP || BFIN527_EZKIT || BFIN548_EZKIT)
+ 	default 5 if BFIN533_BLUETECHNIX_CM
+ 	default 4 if BFIN537_BLUETECHNIX_CM
+ 	default 4 if BFIN561_BLUETECHNIX_CM
+@@ -371,7 +381,10 @@ config SCLK_DIV
+ config MAX_VCO_HZ
+ 	int
+ 	default 600000000 if BF522
++	default 400000000 if BF523
++	default 400000000 if BF524
+ 	default 600000000 if BF525
++	default 400000000 if BF526
+ 	default 600000000 if BF527
+ 	default 400000000 if BF531
+ 	default 400000000 if BF532
+@@ -383,6 +396,8 @@ config MAX_VCO_HZ
+ 	default 533333333 if BF539
+ 	default 600000000 if BF542
+ 	default 533333333 if BF544
++	default 600000000 if BF547
++	default 600000000 if BF548
+ 	default 533333333 if BF549
+ 	default 600000000 if BF561
+ 
+@@ -409,6 +424,7 @@ config MEM_SIZE
+ 	default  32 if BFIN533_EZKIT
+ 	default  64 if BFIN527_EZKIT
+ 	default  64 if BFIN537_STAMP
++	default  64 if BFIN548_EZKIT
+ 	default  64 if BFIN561_EZKIT
+ 	default 128 if BFIN533_STAMP
+ 	default  64 if PNAV10
+@@ -416,6 +432,7 @@ config MEM_SIZE
+ 
+ config MEM_ADD_WIDTH
+ 	int "SDRAM Memory Address Width"
++	depends on (!BF54x)
+ 	default  9 if BFIN533_EZKIT
+ 	default  9 if BFIN561_EZKIT
+ 	default  9 if H8606_HVSISTEMAS
+@@ -424,6 +441,19 @@ config MEM_ADD_WIDTH
+ 	default 11 if BFIN533_STAMP
+ 	default 10 if PNAV10
+ 
++
++choice
++	prompt "DDR SDRAM Chip Type"
++	depends on BFIN548_EZKIT
++	default MEM_MT46V32M16_5B
++
++config MEM_MT46V32M16_6T
++        bool "MT46V32M16_6T"
++
++config MEM_MT46V32M16_5B
++        bool "MT46V32M16_5B"
++endchoice
++
+ config ENET_FLASH_PIN
+ 	int "PF port/pin used for flash and ethernet sharing"
+ 	depends on (BFIN533_STAMP)
+@@ -448,40 +478,6 @@ config BOOT_LOAD
+ 	  memory region is used to capture NULL pointer references as well
+ 	  as some core kernel functions.
+ 
+-comment "LED Status Indicators"
+-	depends on (BFIN533_STAMP || BFIN533_BLUETECHNIX_CM)
+-
+-config BFIN_ALIVE_LED
+-	bool "Enable Board Alive"
+-	depends on (BFIN533_STAMP || BFIN533_BLUETECHNIX_CM)
+-	default n
+-	help
+-	  Blink the LEDs you select when the kernel is running.  Helps detect
+-	  a hung kernel.
+-
+-config BFIN_ALIVE_LED_NUM
+-	int "LED"
+-	depends on BFIN_ALIVE_LED
+-	range 1 3 if BFIN533_STAMP
+-	default "3" if BFIN533_STAMP
+-	help
+-	  Select the LED (marked on the board) for you to blink.
+-
+-config BFIN_IDLE_LED
+-	bool "Enable System Load/Idle LED"
+-	depends on (BFIN533_STAMP || BFIN533_BLUETECHNIX_CM)
+-	default n
+-	help
+-	  Blinks the LED you select when to determine kernel load.
+-
+-config BFIN_IDLE_LED_NUM
+-	int "LED"
+-	depends on BFIN_IDLE_LED
+-	range 1 3 if BFIN533_STAMP
+-	default "2" if BFIN533_STAMP
+-	help
+-	  Select the LED (marked on the board) for you to blink.
+-
+ choice
+ 	prompt "Blackfin Exception Scratch Register"
+ 	default BFIN_SCRATCH_REG_RETN
+@@ -528,41 +524,6 @@ config BFIN_SCRATCH_REG_CYCLES
+ 
+ endchoice
+ 
+-#
+-# Sorry - but you need to put the hex address here -
+-#
+-
+-# Flag Data register
+-config BFIN_ALIVE_LED_PORT
+-	hex
+-	default 0xFFC00700 if (BFIN533_STAMP)
+-
+-# Peripheral Flag Direction Register
+-config BFIN_ALIVE_LED_DPORT
+-	hex
+-	default 0xFFC00730 if (BFIN533_STAMP)
+-
+-config BFIN_ALIVE_LED_PIN
+-	hex
+-	default 0x04 if (BFIN533_STAMP && BFIN_ALIVE_LED_NUM = 1)
+-	default 0x08 if (BFIN533_STAMP && BFIN_ALIVE_LED_NUM = 2)
+-	default 0x10 if (BFIN533_STAMP && BFIN_ALIVE_LED_NUM = 3)
+-
+-config BFIN_IDLE_LED_PORT
+-	hex
+-	default 0xFFC00700 if (BFIN533_STAMP)
+-
+-# Peripheral Flag Direction Register
+-config BFIN_IDLE_LED_DPORT
+-	hex
+-	default 0xFFC00730 if (BFIN533_STAMP)
+-
+-config BFIN_IDLE_LED_PIN
+-	hex
+-	default 0x04 if (BFIN533_STAMP && BFIN_IDLE_LED_NUM = 1)
+-	default 0x08 if (BFIN533_STAMP && BFIN_IDLE_LED_NUM = 2)
+-	default 0x10 if (BFIN533_STAMP && BFIN_IDLE_LED_NUM = 3)
+-
+ endmenu
+ 
+ 
+@@ -799,6 +760,15 @@ config L1_MAX_PIECE
+ 	  Set the max memory pieces for the L1 SRAM allocation algorithm.
+ 	  Min value is 16. Max value is 1024.
+ 
++
++config MPU
++	bool "Enable the memory protection unit (EXPERIMENTAL)"
++	default n
++	help
++	  Use the processor's MPU to protect applications from accessing
++	  memory they do not own.  This comes at a performance penalty
++	  and is recommended only for debugging.
++
+ comment "Asynchonous Memory Configuration"
+ 
+ menu "EBIU_AMGCTL Global Control"
+@@ -808,7 +778,6 @@ config C_AMCKEN
+ 
+ config C_CDPRIO
+ 	bool "DMA has priority over core for ext. accesses"
+-	depends on !BF54x
+ 	default n
+ 
+ config C_B0PEN
+@@ -949,8 +918,10 @@ endchoice
+ config PM_WAKEUP_SIC_IWR
+ 	hex "Wakeup Events (SIC_IWR)"
+ 	depends on PM_WAKEUP_GPIO_BY_SIC_IWR
+-	default 0x80000000 if (BF537 || BF536 || BF534)
+-	default 0x100000 if (BF533 || BF532 || BF531)
++	default 0x8 if (BF537 || BF536 || BF534)
++	default 0x80 if (BF533 || BF532 || BF531)
++	default 0x80 if (BF54x)
++	default 0x80 if (BF52x)
+ 
+ config PM_WAKEUP_GPIO_NUMBER
+ 	int "Wakeup GPIO number"
+diff --git a/arch/blackfin/Makefile b/arch/blackfin/Makefile
+index c47e000..0edc402 100644
+--- a/arch/blackfin/Makefile
++++ b/arch/blackfin/Makefile
+@@ -21,7 +21,10 @@ KBUILD_DEFCONFIG := BF537-STAMP_defconfig
+ 
+ # setup the machine name and the machine dependent settings
+ machine-$(CONFIG_BF522) := bf527
++machine-$(CONFIG_BF523) := bf527
++machine-$(CONFIG_BF524) := bf527
+ machine-$(CONFIG_BF525) := bf527
++machine-$(CONFIG_BF526) := bf527
+ machine-$(CONFIG_BF527) := bf527
+ machine-$(CONFIG_BF531) := bf533
+ machine-$(CONFIG_BF532) := bf533
+@@ -39,7 +42,10 @@ MACHINE := $(machine-y)
+ export MACHINE
+ 
+ cpu-$(CONFIG_BF522) := bf522
++cpu-$(CONFIG_BF523) := bf523
++cpu-$(CONFIG_BF524) := bf524
+ cpu-$(CONFIG_BF525) := bf525
++cpu-$(CONFIG_BF526) := bf526
+ cpu-$(CONFIG_BF527) := bf527
+ cpu-$(CONFIG_BF531) := bf531
+ cpu-$(CONFIG_BF532) := bf532
+@@ -76,6 +82,12 @@ core-y   += arch/$(ARCH)/mach-$(MACHINE)/
+ core-y   += arch/$(ARCH)/mach-$(MACHINE)/boards/
+ endif
+ 
++ifeq ($(CONFIG_MPU),y)
++core-y	+= arch/$(ARCH)/kernel/cplb-mpu/
++else
++core-y	+= arch/$(ARCH)/kernel/cplb-nompu/
++endif
++
+ libs-y   += arch/$(ARCH)/lib/
+ 
+ drivers-$(CONFIG_OPROFILE) += arch/$(ARCH)/oprofile/
+diff --git a/arch/blackfin/configs/BF527-EZKIT_defconfig b/arch/blackfin/configs/BF527-EZKIT_defconfig
+index fa6eb4e..d59ee15 100644
+--- a/arch/blackfin/configs/BF527-EZKIT_defconfig
++++ b/arch/blackfin/configs/BF527-EZKIT_defconfig
+@@ -1,6 +1,7 @@
+ #
+ # Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.22.12
++# Linux kernel version: 2.6.22.14
++# Thu Nov 29 17:32:47 2007
+ #
+ # CONFIG_MMU is not set
+ # CONFIG_FPU is not set
+@@ -153,8 +154,8 @@ CONFIG_BFIN527_EZKIT=y
+ CONFIG_BF527_SPORT0_PORTG=y
+ CONFIG_BF527_SPORT0_TSCLK_PG10=y
+ # CONFIG_BF527_SPORT0_TSCLK_PG14 is not set
+-# CONFIG_BF527_UART1_PORTF is not set
+-CONFIG_BF527_UART1_PORTG=y
++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
+ 
+@@ -232,7 +233,7 @@ CONFIG_CLKIN_HZ=25000000
+ # CONFIG_BFIN_KERNEL_CLOCK is not set
+ CONFIG_MAX_VCO_HZ=600000000
+ CONFIG_MIN_VCO_HZ=50000000
+-CONFIG_MAX_SCLK_HZ=133000000
++CONFIG_MAX_SCLK_HZ=133333333
+ CONFIG_MIN_SCLK_HZ=27000000
+ 
+ #
+@@ -626,8 +627,8 @@ CONFIG_BFIN_MAC_RMII=y
+ # CONFIG_SMSC911X is not set
+ # CONFIG_DM9000 is not set
+ CONFIG_NETDEV_1000=y
+-CONFIG_NETDEV_10000=y
+ # CONFIG_AX88180 is not set
++CONFIG_NETDEV_10000=y
+ 
+ #
+ # Wireless LAN
+@@ -1183,7 +1184,7 @@ CONFIG_NLS_DEFAULT="iso8859-1"
+ #
+ # CONFIG_PRINTK_TIME is not set
+ CONFIG_ENABLE_MUST_CHECK=y
+-CONFIG_MAGIC_SYSRQ=y
++# CONFIG_MAGIC_SYSRQ is not set
+ # CONFIG_UNUSED_SYMBOLS is not set
+ CONFIG_DEBUG_FS=y
+ # CONFIG_HEADERS_CHECK is not set
+@@ -1208,7 +1209,7 @@ CONFIG_ACCESS_CHECK=y
+ # CONFIG_KEYS is not set
+ CONFIG_SECURITY=y
+ # CONFIG_SECURITY_NETWORK is not set
+-CONFIG_SECURITY_CAPABILITIES=y
++CONFIG_SECURITY_CAPABILITIES=m
+ 
+ #
+ # Cryptographic options
+@@ -1219,7 +1220,7 @@ CONFIG_SECURITY_CAPABILITIES=y
+ # Library routines
+ #
+ CONFIG_BITREVERSE=y
+-# CONFIG_CRC_CCITT is not set
++CONFIG_CRC_CCITT=m
+ # CONFIG_CRC16 is not set
+ # CONFIG_CRC_ITU_T is not set
+ CONFIG_CRC32=y
+diff --git a/arch/blackfin/configs/BF533-EZKIT_defconfig b/arch/blackfin/configs/BF533-EZKIT_defconfig
+index 4fdb493..811711f 100644
+--- a/arch/blackfin/configs/BF533-EZKIT_defconfig
++++ b/arch/blackfin/configs/BF533-EZKIT_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.16
+ #
+ # CONFIG_MMU is not set
+ # CONFIG_FPU is not set
+@@ -115,7 +115,10 @@ CONFIG_PREEMPT_VOLUNTARY=y
+ # 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 is not set
+ # CONFIG_BF527 is not set
+ # CONFIG_BF531 is not set
+ # CONFIG_BF532 is not set
+@@ -194,7 +197,7 @@ CONFIG_CLKIN_HZ=27000000
+ # CONFIG_BFIN_KERNEL_CLOCK is not set
+ CONFIG_MAX_VCO_HZ=750000000
+ CONFIG_MIN_VCO_HZ=50000000
+-CONFIG_MAX_SCLK_HZ=133000000
++CONFIG_MAX_SCLK_HZ=133333333
+ CONFIG_MIN_SCLK_HZ=27000000
+ 
+ #
+@@ -267,6 +270,7 @@ CONFIG_BFIN_DCACHE=y
+ # CONFIG_BFIN_WB is not set
+ CONFIG_BFIN_WT=y
+ CONFIG_L1_MAX_PIECE=16
++# CONFIG_MPU is not set
+ 
+ #
+ # Asynchonous Memory Configuration
+@@ -321,7 +325,7 @@ CONFIG_PM=y
+ CONFIG_PM_WAKEUP_GPIO_BY_SIC_IWR=y
+ # CONFIG_PM_WAKEUP_BY_GPIO is not set
+ # CONFIG_PM_WAKEUP_GPIO_API is not set
+-CONFIG_PM_WAKEUP_SIC_IWR=0x100000
++CONFIG_PM_WAKEUP_SIC_IWR=0x80
+ 
+ #
+ # CPU Frequency scaling
+@@ -510,7 +514,6 @@ CONFIG_MTD_CFI_I2=y
+ # CONFIG_MTD_CFI_INTELEXT is not set
+ # CONFIG_MTD_CFI_AMDSTD is not set
+ # CONFIG_MTD_CFI_STAA is not set
+-CONFIG_MTD_MW320D=m
+ CONFIG_MTD_RAM=y
+ CONFIG_MTD_ROM=m
+ # CONFIG_MTD_ABSENT is not set
+@@ -520,9 +523,6 @@ CONFIG_MTD_ROM=m
+ #
+ CONFIG_MTD_COMPLEX_MAPPINGS=y
+ # CONFIG_MTD_PHYSMAP is not set
+-CONFIG_MTD_BF5xx=m
+-CONFIG_BFIN_FLASH_SIZE=0x400000
+-CONFIG_EBIU_FLASH_BASE=0x20000000
+ # CONFIG_MTD_UCLINUX is not set
+ # CONFIG_MTD_PLATRAM is not set
+ 
+@@ -610,8 +610,8 @@ CONFIG_SMC91X=y
+ # CONFIG_SMSC911X is not set
+ # CONFIG_DM9000 is not set
+ CONFIG_NETDEV_1000=y
+-CONFIG_NETDEV_10000=y
+ # CONFIG_AX88180 is not set
++CONFIG_NETDEV_10000=y
+ 
+ #
+ # Wireless LAN
+@@ -680,7 +680,6 @@ CONFIG_INPUT_EVDEV=m
+ CONFIG_BFIN_SPORT=y
+ # CONFIG_BFIN_TIMER_LATENCY is not set
+ # CONFIG_AD5304 is not set
+-# CONFIG_BF5xx_FBDMA is not set
+ # CONFIG_VT is not set
+ # CONFIG_SERIAL_NONSTANDARD is not set
+ 
+diff --git a/arch/blackfin/configs/BF533-STAMP_defconfig b/arch/blackfin/configs/BF533-STAMP_defconfig
+index b04e8e5..9b7123c 100644
+--- a/arch/blackfin/configs/BF533-STAMP_defconfig
++++ b/arch/blackfin/configs/BF533-STAMP_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.16
+ #
+ # CONFIG_MMU is not set
+ # CONFIG_FPU is not set
+@@ -115,7 +115,10 @@ CONFIG_PREEMPT_VOLUNTARY=y
+ # 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 is not set
+ # CONFIG_BF527 is not set
+ # CONFIG_BF531 is not set
+ # CONFIG_BF532 is not set
+@@ -140,7 +143,6 @@ CONFIG_BF_REV_0_3=y
+ CONFIG_BF53x=y
+ CONFIG_BFIN_SINGLE_CORE=y
+ CONFIG_MEM_MT48LC64M4A2FB_7E=y
+-CONFIG_BFIN_SHARED_FLASH_ENET=y
+ # CONFIG_BFIN533_EZKIT is not set
+ CONFIG_BFIN533_STAMP=y
+ # CONFIG_BFIN533_BLUETECHNIX_CM is not set
+@@ -195,7 +197,7 @@ CONFIG_CLKIN_HZ=11059200
+ # CONFIG_BFIN_KERNEL_CLOCK is not set
+ CONFIG_MAX_VCO_HZ=750000000
+ CONFIG_MIN_VCO_HZ=50000000
+-CONFIG_MAX_SCLK_HZ=133000000
++CONFIG_MAX_SCLK_HZ=133333333
+ CONFIG_MIN_SCLK_HZ=27000000
+ 
+ #
+@@ -215,18 +217,10 @@ CONFIG_MEM_ADD_WIDTH=11
+ CONFIG_ENET_FLASH_PIN=0
+ CONFIG_BOOT_LOAD=0x1000
+ 
+-#
+-# LED Status Indicators
+-#
+-# CONFIG_BFIN_ALIVE_LED is not set
+-# CONFIG_BFIN_IDLE_LED is not set
++
+ CONFIG_BFIN_SCRATCH_REG_RETN=y
+ # CONFIG_BFIN_SCRATCH_REG_RETE is not set
+ # CONFIG_BFIN_SCRATCH_REG_CYCLES is not set
+-CONFIG_BFIN_ALIVE_LED_PORT=0xFFC00700
+-CONFIG_BFIN_ALIVE_LED_DPORT=0xFFC00730
+-CONFIG_BFIN_IDLE_LED_PORT=0xFFC00700
+-CONFIG_BFIN_IDLE_LED_DPORT=0xFFC00730
+ 
+ #
+ # Blackfin Kernel Optimizations
+@@ -279,6 +273,7 @@ CONFIG_BFIN_DCACHE=y
+ # CONFIG_BFIN_WB is not set
+ CONFIG_BFIN_WT=y
+ CONFIG_L1_MAX_PIECE=16
++# CONFIG_MPU is not set
+ 
+ #
+ # Asynchonous Memory Configuration
+@@ -333,7 +328,7 @@ CONFIG_PM=y
+ CONFIG_PM_WAKEUP_GPIO_BY_SIC_IWR=y
+ # CONFIG_PM_WAKEUP_BY_GPIO is not set
+ # CONFIG_PM_WAKEUP_GPIO_API is not set
+-CONFIG_PM_WAKEUP_SIC_IWR=0x100000
++CONFIG_PM_WAKEUP_SIC_IWR=0x80
+ 
+ #
+ # CPU Frequency scaling
+@@ -522,7 +517,6 @@ CONFIG_MTD_CFI_I2=y
+ # CONFIG_MTD_CFI_INTELEXT is not set
+ # CONFIG_MTD_CFI_AMDSTD is not set
+ # CONFIG_MTD_CFI_STAA is not set
+-CONFIG_MTD_MW320D=m
+ CONFIG_MTD_RAM=y
+ CONFIG_MTD_ROM=m
+ # CONFIG_MTD_ABSENT is not set
+@@ -532,17 +526,6 @@ CONFIG_MTD_ROM=m
+ #
+ CONFIG_MTD_COMPLEX_MAPPINGS=y
+ # CONFIG_MTD_PHYSMAP is not set
+-CONFIG_MTD_BF5xx=m
+-CONFIG_BFIN_FLASH_SIZE=0x400000
+-CONFIG_EBIU_FLASH_BASE=0x20000000
+-
+-#
+-# FLASH_EBIU_AMBCTL Control
+-#
+-CONFIG_BFIN_FLASH_BANK_0=0x7BB0
+-CONFIG_BFIN_FLASH_BANK_1=0x7BB0
+-CONFIG_BFIN_FLASH_BANK_2=0x7BB0
+-CONFIG_BFIN_FLASH_BANK_3=0x7BB0
+ # CONFIG_MTD_UCLINUX is not set
+ # CONFIG_MTD_PLATRAM is not set
+ 
+@@ -630,8 +613,8 @@ CONFIG_SMC91X=y
+ # CONFIG_SMSC911X is not set
+ # CONFIG_DM9000 is not set
+ CONFIG_NETDEV_1000=y
+-CONFIG_NETDEV_10000=y
+ # CONFIG_AX88180 is not set
++CONFIG_NETDEV_10000=y
+ 
+ #
+ # Wireless LAN
+@@ -687,7 +670,6 @@ CONFIG_INPUT_MISC=y
+ # 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_TWI_KEYPAD=m
+ CONFIG_BFIN_TWIKEYPAD_IRQ_PFX=39
+ 
+@@ -711,8 +693,6 @@ CONFIG_BFIN_SPORT=y
+ CONFIG_TWI_LCD=m
+ CONFIG_TWI_LCD_SLAVE_ADDR=34
+ # CONFIG_AD5304 is not set
+-# CONFIG_BF5xx_TEA5764 is not set
+-# CONFIG_BF5xx_FBDMA is not set
+ # CONFIG_VT is not set
+ # CONFIG_SERIAL_NONSTANDARD is not set
+ 
+@@ -778,7 +758,6 @@ CONFIG_I2C_ALGOBIT=m
+ #
+ # I2C Hardware Bus support
+ #
+-# CONFIG_I2C_BLACKFIN_GPIO is not set
+ # CONFIG_I2C_GPIO is not set
+ # CONFIG_I2C_OCORES is not set
+ # CONFIG_I2C_PARPORT_LIGHT is not set
+diff --git a/arch/blackfin/configs/BF537-STAMP_defconfig b/arch/blackfin/configs/BF537-STAMP_defconfig
+index f812b66..b37ccc6 100644
+--- a/arch/blackfin/configs/BF537-STAMP_defconfig
++++ b/arch/blackfin/configs/BF537-STAMP_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.16
+ #
+ # CONFIG_MMU is not set
+ # CONFIG_FPU is not set
+@@ -115,7 +115,10 @@ CONFIG_PREEMPT_VOLUNTARY=y
+ # 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 is not set
+ # CONFIG_BF527 is not set
+ # CONFIG_BF531 is not set
+ # CONFIG_BF532 is not set
+@@ -170,6 +173,7 @@ CONFIG_IRQ_WATCH=13
+ CONFIG_BFIN537_STAMP=y
+ # CONFIG_BFIN537_BLUETECHNIX_CM is not set
+ # CONFIG_PNAV10 is not set
++# CONFIG_CAMSIG_MINOTAUR is not set
+ # CONFIG_GENERIC_BF537_BOARD is not set
+ 
+ #
+@@ -201,7 +205,7 @@ CONFIG_CLKIN_HZ=25000000
+ # CONFIG_BFIN_KERNEL_CLOCK is not set
+ CONFIG_MAX_VCO_HZ=600000000
+ CONFIG_MIN_VCO_HZ=50000000
+-CONFIG_MAX_SCLK_HZ=133000000
++CONFIG_MAX_SCLK_HZ=133333333
+ CONFIG_MIN_SCLK_HZ=27000000
+ 
+ #
+@@ -274,6 +278,7 @@ CONFIG_BFIN_DCACHE=y
+ # CONFIG_BFIN_WB is not set
+ CONFIG_BFIN_WT=y
+ CONFIG_L1_MAX_PIECE=16
++# CONFIG_MPU is not set
+ 
+ #
+ # Asynchonous Memory Configuration
+@@ -328,7 +333,7 @@ CONFIG_PM=y
+ CONFIG_PM_WAKEUP_GPIO_BY_SIC_IWR=y
+ # CONFIG_PM_WAKEUP_BY_GPIO is not set
+ # CONFIG_PM_WAKEUP_GPIO_API is not set
+-CONFIG_PM_WAKEUP_SIC_IWR=0x80000000
++CONFIG_PM_WAKEUP_SIC_IWR=0x8
+ 
+ #
+ # CPU Frequency scaling
+@@ -483,7 +488,7 @@ CONFIG_MTD=y
+ # 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_CMDLINE_PARTS=y
+ 
+ #
+ # User Modules And Translation Layers
+@@ -500,8 +505,8 @@ CONFIG_MTD_BLOCK=y
+ #
+ # RAM/ROM/Flash chip drivers
+ #
+-# CONFIG_MTD_CFI is not set
+-CONFIG_MTD_JEDECPROBE=m
++CONFIG_MTD_CFI=m
++# CONFIG_MTD_JEDECPROBE is not set
+ CONFIG_MTD_GEN_PROBE=m
+ # CONFIG_MTD_CFI_ADV_OPTIONS is not set
+ CONFIG_MTD_MAP_BANK_WIDTH_1=y
+@@ -515,9 +520,9 @@ 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_AMDSTD=m
+ # CONFIG_MTD_CFI_STAA is not set
+-CONFIG_MTD_MW320D=m
++CONFIG_MTD_CFI_UTIL=m
+ CONFIG_MTD_RAM=y
+ CONFIG_MTD_ROM=m
+ # CONFIG_MTD_ABSENT is not set
+@@ -525,11 +530,11 @@ CONFIG_MTD_ROM=m
+ #
+ # Mapping drivers for chip access
+ #
+-CONFIG_MTD_COMPLEX_MAPPINGS=y
+-# CONFIG_MTD_PHYSMAP is not set
+-CONFIG_MTD_BF5xx=m
+-CONFIG_BFIN_FLASH_SIZE=0x400000
+-CONFIG_EBIU_FLASH_BASE=0x20000000
++# CONFIG_MTD_COMPLEX_MAPPINGS is not set
++CONFIG_MTD_PHYSMAP=m
++CONFIG_MTD_PHYSMAP_START=0x20000000
++CONFIG_MTD_PHYSMAP_LEN=0x0
++CONFIG_MTD_PHYSMAP_BANKWIDTH=2
+ # CONFIG_MTD_UCLINUX is not set
+ # CONFIG_MTD_PLATRAM is not set
+ 
+@@ -647,8 +652,8 @@ CONFIG_BFIN_RX_DESC_NUM=20
+ # CONFIG_SMSC911X is not set
+ # CONFIG_DM9000 is not set
+ CONFIG_NETDEV_1000=y
+-CONFIG_NETDEV_10000=y
+ # CONFIG_AX88180 is not set
++CONFIG_NETDEV_10000=y
+ 
+ #
+ # Wireless LAN
+@@ -704,7 +709,6 @@ CONFIG_INPUT_MISC=y
+ # 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_TWI_KEYPAD=m
+ CONFIG_BFIN_TWIKEYPAD_IRQ_PFX=72
+ 
+@@ -728,8 +732,6 @@ CONFIG_BFIN_SPORT=y
+ CONFIG_TWI_LCD=m
+ CONFIG_TWI_LCD_SLAVE_ADDR=34
+ # CONFIG_AD5304 is not set
+-# CONFIG_BF5xx_TEA5764 is not set
+-# CONFIG_BF5xx_FBDMA is not set
+ # CONFIG_VT is not set
+ # CONFIG_SERIAL_NONSTANDARD is not set
+ 
+@@ -802,7 +804,6 @@ CONFIG_I2C_CHARDEV=m
+ #
+ # I2C Hardware Bus support
+ #
+-# CONFIG_I2C_BLACKFIN_GPIO is not set
+ CONFIG_I2C_BLACKFIN_TWI=m
+ CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ=50
+ # CONFIG_I2C_GPIO is not set
+@@ -957,6 +958,7 @@ CONFIG_LQ035_SLAVE_ADDR=0x58
+ # CONFIG_FB_BFIN_LANDSCAPE is not set
+ # CONFIG_FB_BFIN_BGR is not set
+ # CONFIG_FB_BFIN_T350MCQB is not set
++# CONFIG_FB_HITACHI_TX09 is not set
+ # CONFIG_FB_S1D13XXX is not set
+ # CONFIG_FB_VIRTUAL is not set
+ # CONFIG_LOGO is not set
+@@ -1008,12 +1010,22 @@ CONFIG_SND_BFIN_AD73311_SE=4
+ #
+ # System on Chip audio support
+ #
+-# CONFIG_SND_SOC is not set
++CONFIG_SND_SOC_AC97_BUS=y
++CONFIG_SND_SOC=m
++CONFIG_SND_BF5XX_SOC=m
++CONFIG_SND_BF5XX_SOC_AC97=m
++# CONFIG_SND_BF5XX_SOC_WM8750 is not set
++# CONFIG_SND_BF5XX_SOC_WM8731 is not set
++CONFIG_SND_BF5XX_SOC_BF5xx=m
++CONFIG_SND_BF5XX_SPORT_NUM=0
++# CONFIG_SND_BF5XX_HAVE_COLD_RESET is not set
++CONFIG_SND_SOC_AD1980=m
+ 
+ #
+ # Open Sound System
+ #
+ # CONFIG_SOUND_PRIME is not set
++CONFIG_AC97_BUS=m
+ 
+ #
+ # HID Devices
+diff --git a/arch/blackfin/configs/BF548-EZKIT_defconfig b/arch/blackfin/configs/BF548-EZKIT_defconfig
+index 48367cc..fd70216 100644
+--- a/arch/blackfin/configs/BF548-EZKIT_defconfig
++++ b/arch/blackfin/configs/BF548-EZKIT_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.16
+ #
+ # CONFIG_MMU is not set
+ # CONFIG_FPU is not set
+@@ -115,7 +115,10 @@ CONFIG_PREEMPT_VOLUNTARY=y
+ # 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 is not set
+ # CONFIG_BF527 is not set
+ # CONFIG_BF531 is not set
+ # CONFIG_BF532 is not set
+@@ -126,8 +129,8 @@ CONFIG_PREEMPT_VOLUNTARY=y
+ # CONFIG_BF542 is not set
+ # CONFIG_BF544 is not set
+ # CONFIG_BF547 is not set
+-# CONFIG_BF548 is not set
+-CONFIG_BF549=y
++CONFIG_BF548=y
++# CONFIG_BF549 is not set
+ # CONFIG_BF561 is not set
+ CONFIG_BF_REV_0_0=y
+ # CONFIG_BF_REV_0_1 is not set
+@@ -265,9 +268,9 @@ CONFIG_PINT3_ASSIGN=0x02020303
+ #
+ CONFIG_CLKIN_HZ=25000000
+ # CONFIG_BFIN_KERNEL_CLOCK is not set
+-CONFIG_MAX_VCO_HZ=533000000
++CONFIG_MAX_VCO_HZ=600000000
+ CONFIG_MIN_VCO_HZ=50000000
+-CONFIG_MAX_SCLK_HZ=133000000
++CONFIG_MAX_SCLK_HZ=133333333
+ CONFIG_MIN_SCLK_HZ=27000000
+ 
+ #
+@@ -283,7 +286,8 @@ CONFIG_HZ=250
+ # Memory Setup
+ #
+ CONFIG_MEM_SIZE=64
+-CONFIG_MEM_ADD_WIDTH=10
++# CONFIG_MEM_MT46V32M16_6T is not set
++CONFIG_MEM_MT46V32M16_5B=y
+ CONFIG_BOOT_LOAD=0x1000
+ CONFIG_BFIN_SCRATCH_REG_RETN=y
+ # CONFIG_BFIN_SCRATCH_REG_RETE is not set
+@@ -340,6 +344,7 @@ CONFIG_BFIN_DCACHE=y
+ # CONFIG_BFIN_WB is not set
+ CONFIG_BFIN_WT=y
+ CONFIG_L1_MAX_PIECE=16
++# CONFIG_MPU is not set
+ 
+ #
+ # Asynchonous Memory Configuration
+@@ -349,6 +354,7 @@ CONFIG_L1_MAX_PIECE=16
+ # EBIU_AMGCTL Global Control
+ #
+ CONFIG_C_AMCKEN=y
++# CONFIG_C_CDPRIO is not set
+ # CONFIG_C_AMBEN is not set
+ # CONFIG_C_AMBEN_B0 is not set
+ # CONFIG_C_AMBEN_B0_B1 is not set
+@@ -362,9 +368,9 @@ CONFIG_BANK_0=0x7BB0
+ CONFIG_BANK_1=0x5554
+ CONFIG_BANK_2=0x7BB0
+ CONFIG_BANK_3=0x99B3
+-CONFIG_EBUI_MBSCTLVAL=0x0
+-CONFIG_EBUI_MODEVAL=0x1
+-CONFIG_EBUI_FCTLVAL=0x6
++CONFIG_EBIU_MBSCTLVAL=0x0
++CONFIG_EBIU_MODEVAL=0x1
++CONFIG_EBIU_FCTLVAL=0x6
+ 
+ #
+ # Bus options (PCI, PCMCIA, EISA, MCA, ISA)
+@@ -537,7 +543,6 @@ CONFIG_MTD_CFI_I2=y
+ CONFIG_MTD_CFI_INTELEXT=y
+ # CONFIG_MTD_CFI_AMDSTD is not set
+ # CONFIG_MTD_CFI_STAA is not set
+-# CONFIG_MTD_MW320D is not set
+ CONFIG_MTD_CFI_UTIL=y
+ CONFIG_MTD_RAM=y
+ # CONFIG_MTD_ROM is not set
+@@ -549,9 +554,8 @@ CONFIG_MTD_RAM=y
+ CONFIG_MTD_COMPLEX_MAPPINGS=y
+ CONFIG_MTD_PHYSMAP=y
+ CONFIG_MTD_PHYSMAP_START=0x20000000
+-CONFIG_MTD_PHYSMAP_LEN=0x400000
++CONFIG_MTD_PHYSMAP_LEN=0
+ CONFIG_MTD_PHYSMAP_BANKWIDTH=2
+-# CONFIG_MTD_BF5xx is not set
+ # CONFIG_MTD_UCLINUX is not set
+ # CONFIG_MTD_PLATRAM is not set
+ 
+@@ -690,8 +694,8 @@ CONFIG_MII=y
+ CONFIG_SMSC911X=y
+ # CONFIG_DM9000 is not set
+ CONFIG_NETDEV_1000=y
+-CONFIG_NETDEV_10000=y
+ # CONFIG_AX88180 is not set
++CONFIG_NETDEV_10000=y
+ 
+ #
+ # Wireless LAN
+@@ -719,7 +723,7 @@ CONFIG_NETDEV_10000=y
+ #
+ # Input device support
+ #
+-CONFIG_INPUT=m
++CONFIG_INPUT=y
+ # CONFIG_INPUT_FF_MEMLESS is not set
+ # CONFIG_INPUT_POLLDEV is not set
+ 
+@@ -745,7 +749,8 @@ CONFIG_INPUT_KEYBOARD=y
+ # CONFIG_KEYBOARD_NEWTON is not set
+ # CONFIG_KEYBOARD_STOWAWAY is not set
+ # CONFIG_KEYBOARD_GPIO is not set
+-CONFIG_KEYBOARD_BFIN=m
++CONFIG_KEYBOARD_BFIN=y
++# CONFIG_KEYBOARD_OPENCORES is not set
+ # CONFIG_INPUT_MOUSE is not set
+ # CONFIG_INPUT_JOYSTICK is not set
+ # CONFIG_INPUT_TABLET is not set
+@@ -768,7 +773,6 @@ CONFIG_INPUT_MISC=y
+ # 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_TWI_KEYPAD is not set
+ 
+ #
+@@ -786,13 +790,16 @@ CONFIG_INPUT_MISC=y
+ # CONFIG_BF5xx_PPIFCD is not set
+ # CONFIG_BFIN_SIMPLE_TIMER is not set
+ # CONFIG_BF5xx_PPI is not set
++CONFIG_BFIN_OTP=y
++# CONFIG_BFIN_OTP_WRITE_ENABLE is not set
+ # CONFIG_BFIN_SPORT is not set
+ # CONFIG_BFIN_TIMER_LATENCY is not set
+ # CONFIG_TWI_LCD is not set
+ # CONFIG_AD5304 is not set
+-# CONFIG_BF5xx_TEA5764 is not set
+-# CONFIG_BF5xx_FBDMA is not set
+-# CONFIG_VT is not set
++CONFIG_VT=y
++CONFIG_VT_CONSOLE=y
++CONFIG_HW_CONSOLE=y
++# CONFIG_VT_HW_CONSOLE_BINDING is not set
+ # CONFIG_SERIAL_NONSTANDARD is not set
+ 
+ #
+@@ -858,7 +865,6 @@ CONFIG_I2C_CHARDEV=y
+ #
+ # I2C Hardware Bus support
+ #
+-# CONFIG_I2C_BLACKFIN_GPIO is not set
+ CONFIG_I2C_BLACKFIN_TWI=y
+ CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ=50
+ # CONFIG_I2C_GPIO is not set
+@@ -976,12 +982,12 @@ CONFIG_DAB=y
+ #
+ # CONFIG_DISPLAY_SUPPORT is not set
+ # CONFIG_VGASTATE is not set
+-CONFIG_FB=m
++CONFIG_FB=y
+ CONFIG_FIRMWARE_EDID=y
+ # CONFIG_FB_DDC is not set
+-CONFIG_FB_CFB_FILLRECT=m
+-CONFIG_FB_CFB_COPYAREA=m
+-CONFIG_FB_CFB_IMAGEBLIT=m
++CONFIG_FB_CFB_FILLRECT=y
++CONFIG_FB_CFB_COPYAREA=y
++CONFIG_FB_CFB_IMAGEBLIT=y
+ # CONFIG_FB_SYS_FILLRECT is not set
+ # CONFIG_FB_SYS_COPYAREA is not set
+ # CONFIG_FB_SYS_IMAGEBLIT is not set
+@@ -998,11 +1004,34 @@ CONFIG_FB_DEFERRED_IO=y
+ #
+ # CONFIG_FB_BFIN_7171 is not set
+ # CONFIG_FB_BFIN_7393 is not set
+-CONFIG_FB_BF54X_LQ043=m
++CONFIG_FB_BF54X_LQ043=y
+ # CONFIG_FB_BFIN_T350MCQB is not set
+ # CONFIG_FB_S1D13XXX is not set
+ # CONFIG_FB_VIRTUAL is not set
+-# CONFIG_LOGO is not set
++
++#
++# Console display driver support
++#
++CONFIG_DUMMY_CONSOLE=y
++CONFIG_FRAMEBUFFER_CONSOLE=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 is not set
++# CONFIG_LOGO_LINUX_VGA16 is not set
++# CONFIG_LOGO_LINUX_CLUT224 is not set
++# CONFIG_LOGO_BLACKFIN_VGA16 is not set
++CONFIG_LOGO_BLACKFIN_CLUT224=y
+ 
+ #
+ # Sound
+@@ -1051,7 +1080,8 @@ CONFIG_SND_BF5XX_SOC_BF548_EZKIT=y
+ # CONFIG_SND_BF5XX_SOC_WM8750 is not set
+ # CONFIG_SND_BF5XX_SOC_WM8731 is not set
+ CONFIG_SND_BF5XX_SPORT_NUM=0
+-# CONFIG_SND_BF5XX_HAVE_COLD_RESET is not set
++CONFIG_SND_BF5XX_HAVE_COLD_RESET=y
++CONFIG_SND_BF5XX_RESET_GPIO_NUM=19
+ CONFIG_SND_SOC_AD1980=y
+ 
+ #
+@@ -1403,7 +1433,7 @@ CONFIG_NLS_UTF8=m
+ #
+ # CONFIG_PRINTK_TIME is not set
+ CONFIG_ENABLE_MUST_CHECK=y
+-CONFIG_MAGIC_SYSRQ=y
++# CONFIG_MAGIC_SYSRQ is not set
+ # CONFIG_UNUSED_SYMBOLS is not set
+ CONFIG_DEBUG_FS=y
+ # CONFIG_HEADERS_CHECK is not set
+@@ -1428,7 +1458,7 @@ CONFIG_ACCESS_CHECK=y
+ # CONFIG_KEYS is not set
+ CONFIG_SECURITY=y
+ # CONFIG_SECURITY_NETWORK is not set
+-CONFIG_SECURITY_CAPABILITIES=y
++CONFIG_SECURITY_CAPABILITIES=m
+ 
+ #
+ # Cryptographic options
+@@ -1439,7 +1469,7 @@ CONFIG_SECURITY_CAPABILITIES=y
+ # Library routines
+ #
+ CONFIG_BITREVERSE=y
+-# CONFIG_CRC_CCITT is not set
++CONFIG_CRC_CCITT=m
+ # CONFIG_CRC16 is not set
+ # CONFIG_CRC_ITU_T is not set
+ CONFIG_CRC32=y
+diff --git a/arch/blackfin/configs/BF561-EZKIT_defconfig b/arch/blackfin/configs/BF561-EZKIT_defconfig
+index e9f100b..8546994 100644
+--- a/arch/blackfin/configs/BF561-EZKIT_defconfig
++++ b/arch/blackfin/configs/BF561-EZKIT_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.16
+ #
+ # CONFIG_MMU is not set
+ # CONFIG_FPU is not set
+@@ -115,7 +115,10 @@ CONFIG_PREEMPT_VOLUNTARY=y
+ # 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 is not set
+ # CONFIG_BF527 is not set
+ # CONFIG_BF531 is not set
+ # CONFIG_BF532 is not set
+@@ -238,7 +241,7 @@ CONFIG_CLKIN_HZ=30000000
+ # CONFIG_BFIN_KERNEL_CLOCK is not set
+ CONFIG_MAX_VCO_HZ=600000000
+ CONFIG_MIN_VCO_HZ=50000000
+-CONFIG_MAX_SCLK_HZ=133000000
++CONFIG_MAX_SCLK_HZ=133333333
+ CONFIG_MIN_SCLK_HZ=27000000
+ 
+ #
+@@ -311,6 +314,7 @@ CONFIG_BFIN_DCACHE=y
+ # CONFIG_BFIN_WB is not set
+ CONFIG_BFIN_WT=y
+ CONFIG_L1_MAX_PIECE=16
++# CONFIG_MPU is not set
+ 
+ #
+ # Asynchonous Memory Configuration
+@@ -512,7 +516,7 @@ CONFIG_MTD=y
+ # 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_CMDLINE_PARTS=y
+ 
+ #
+ # User Modules And Translation Layers
+@@ -529,8 +533,8 @@ CONFIG_MTD_BLOCK=y
+ #
+ # RAM/ROM/Flash chip drivers
+ #
+-# CONFIG_MTD_CFI is not set
+-CONFIG_MTD_JEDECPROBE=m
++CONFIG_MTD_CFI=m
++# CONFIG_MTD_JEDECPROBE is not set
+ CONFIG_MTD_GEN_PROBE=m
+ # CONFIG_MTD_CFI_ADV_OPTIONS is not set
+ CONFIG_MTD_MAP_BANK_WIDTH_1=y
+@@ -544,9 +548,9 @@ 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_AMDSTD=m
+ # CONFIG_MTD_CFI_STAA is not set
+-CONFIG_MTD_MW320D=m
++CONFIG_MTD_CFI_UTIL=m
+ CONFIG_MTD_RAM=y
+ CONFIG_MTD_ROM=m
+ # CONFIG_MTD_ABSENT is not set
+@@ -554,12 +558,11 @@ CONFIG_MTD_ROM=m
+ #
+ # Mapping drivers for chip access
+ #
+-CONFIG_MTD_COMPLEX_MAPPINGS=y
+-# CONFIG_MTD_PHYSMAP is not set
+-# CONFIG_MTD_EZKIT561 is not set
+-CONFIG_MTD_BF5xx=m
+-CONFIG_BFIN_FLASH_SIZE=0x0400000
+-CONFIG_EBIU_FLASH_BASE=0x20000000
++# CONFIG_MTD_COMPLEX_MAPPINGS is not set
++CONFIG_MTD_PHYSMAP=m
++CONFIG_MTD_PHYSMAP_START=0x20000000
++CONFIG_MTD_PHYSMAP_LEN=0x0
++CONFIG_MTD_PHYSMAP_BANKWIDTH=2
+ # CONFIG_MTD_UCLINUX is not set
+ # CONFIG_MTD_PLATRAM is not set
+ 
+@@ -647,8 +650,8 @@ CONFIG_SMC91X=y
+ # CONFIG_SMSC911X is not set
+ # CONFIG_DM9000 is not set
+ CONFIG_NETDEV_1000=y
+-CONFIG_NETDEV_10000=y
+ # CONFIG_AX88180 is not set
++CONFIG_NETDEV_10000=y
+ 
+ #
+ # Wireless LAN
+@@ -717,7 +720,6 @@ CONFIG_INPUT_EVDEV=m
+ # CONFIG_BFIN_SPORT is not set
+ # CONFIG_BFIN_TIMER_LATENCY is not set
+ # CONFIG_AD5304 is not set
+-# CONFIG_BF5xx_FBDMA is not set
+ # CONFIG_VT is not set
+ # CONFIG_SERIAL_NONSTANDARD is not set
+ 
+diff --git a/arch/blackfin/kernel/Makefile b/arch/blackfin/kernel/Makefile
+index 8a4cfb2..318b9b6 100644
+--- a/arch/blackfin/kernel/Makefile
++++ b/arch/blackfin/kernel/Makefile
+@@ -7,7 +7,7 @@ extra-y := init_task.o vmlinux.lds
+ obj-y := \
+ 	entry.o process.o bfin_ksyms.o ptrace.o setup.o signal.o \
+ 	sys_bfin.o time.o traps.o irqchip.o dma-mapping.o flat.o \
+-	fixed_code.o cplbinit.o cacheinit.o reboot.o bfin_gpio.o
++	fixed_code.o reboot.o bfin_gpio.o
+ 
+ obj-$(CONFIG_BFIN_GPTIMERS)          += gptimers.o
+ obj-$(CONFIG_MODULES)                += module.o
+diff --git a/arch/blackfin/kernel/bfin_dma_5xx.c b/arch/blackfin/kernel/bfin_dma_5xx.c
+index b544460..fa9debe 100644
+--- a/arch/blackfin/kernel/bfin_dma_5xx.c
++++ b/arch/blackfin/kernel/bfin_dma_5xx.c
+@@ -339,13 +339,13 @@ EXPORT_SYMBOL(set_dma_config);
+ 
+ unsigned short
+ set_bfin_dma_config(char direction, char flow_mode,
+-		    char intr_mode, char dma_mode, char width)
++		    char intr_mode, char dma_mode, char width, char syncmode)
+ {
+ 	unsigned short config;
+ 
+ 	config =
+ 	    ((direction << 1) | (width << 2) | (dma_mode << 4) |
+-	     (intr_mode << 6) | (flow_mode << 12) | RESTART);
++	     (intr_mode << 6) | (flow_mode << 12) | (syncmode << 5));
+ 	return config;
+ }
+ EXPORT_SYMBOL(set_bfin_dma_config);
+diff --git a/arch/blackfin/kernel/bfin_gpio.c b/arch/blackfin/kernel/bfin_gpio.c
+index ce85d4b..6bbe0a2 100644
+--- a/arch/blackfin/kernel/bfin_gpio.c
++++ b/arch/blackfin/kernel/bfin_gpio.c
+@@ -7,7 +7,7 @@
+  * Description:  GPIO Abstraction Layer
+  *
+  * Modified:
+- *               Copyright 2007 Analog Devices Inc.
++ *               Copyright 2008 Analog Devices Inc.
+  *
+  * Bugs:         Enter bugs at http://blackfin.uclinux.org/
+  *
+@@ -83,6 +83,7 @@
+ #include <linux/delay.h>
+ #include <linux/module.h>
+ #include <linux/err.h>
++#include <linux/proc_fs.h>
+ #include <asm/blackfin.h>
+ #include <asm/gpio.h>
+ #include <asm/portmux.h>
+@@ -136,7 +137,6 @@ static unsigned short *port_fer[gpio_bank(MAX_BLACKFIN_GPIOS)] = {
+ 	(unsigned short *) PORTG_FER,
+ 	(unsigned short *) PORTH_FER,
+ };
+-
+ #endif
+ 
+ #ifdef BF527_FAMILY
+@@ -178,15 +178,13 @@ static struct gpio_port_t *gpio_array[gpio_bank(MAX_BLACKFIN_GPIOS)] = {
+ #endif
+ 
+ static unsigned short reserved_gpio_map[gpio_bank(MAX_BLACKFIN_GPIOS)];
+-static unsigned short reserved_peri_map[gpio_bank(MAX_BLACKFIN_GPIOS + 16)];
++static unsigned short reserved_peri_map[gpio_bank(MAX_RESOURCES)];
+ 
+-#define MAX_RESOURCES 		256
+ #define RESOURCE_LABEL_SIZE 	16
+ 
+-struct str_ident {
++static struct str_ident {
+ 	char name[RESOURCE_LABEL_SIZE];
+-} *str_ident;
+-
++} str_ident[MAX_RESOURCES];
+ 
+ #ifdef CONFIG_PM
+ static unsigned short wakeup_map[gpio_bank(MAX_BLACKFIN_GPIOS)];
+@@ -212,7 +210,7 @@ static unsigned int sic_iwr_irqs[gpio_bank(MAX_BLACKFIN_GPIOS)] = {IRQ_PROG0_INT
+ #endif /* CONFIG_PM */
+ 
+ #if defined(BF548_FAMILY)
+-inline int check_gpio(unsigned short gpio)
++inline int check_gpio(unsigned gpio)
+ {
+ 	if (gpio == GPIO_PB15 || gpio == GPIO_PC14 || gpio == GPIO_PC15
+ 	    || gpio == GPIO_PH14 || gpio == GPIO_PH15
+@@ -222,7 +220,7 @@ inline int check_gpio(unsigned short gpio)
+ 	return 0;
+ }
+ #else
+-inline int check_gpio(unsigned short gpio)
++inline int check_gpio(unsigned gpio)
+ {
+ 	if (gpio >= MAX_BLACKFIN_GPIOS)
+ 		return -EINVAL;
+@@ -230,9 +228,13 @@ inline int check_gpio(unsigned short gpio)
+ }
+ #endif
+ 
+-static void set_label(unsigned short ident, const char *label)
++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) {
+ 		strncpy(str_ident[ident].name, label,
+ 			 RESOURCE_LABEL_SIZE);
+@@ -250,6 +252,11 @@ static char *get_label(unsigned short ident)
+ 
+ static int cmp_label(unsigned short ident, const char *label)
+ {
++	if (label == NULL) {
++		dump_stack();
++		printk(KERN_ERR "Please provide none-null label\n");
++	}
++
+ 	if (label && str_ident)
+ 		return strncmp(str_ident[ident].name,
+ 				 label, strlen(label));
+@@ -258,7 +265,7 @@ static int cmp_label(unsigned short ident, const char *label)
+ }
+ 
+ #if defined(BF527_FAMILY) || defined(BF537_FAMILY)
+-static void port_setup(unsigned short gpio, unsigned short usage)
++static void port_setup(unsigned gpio, unsigned short usage)
+ {
+ 	if (!check_gpio(gpio)) {
+ 		if (usage == GPIO_USAGE)
+@@ -269,7 +276,7 @@ static void port_setup(unsigned short gpio, unsigned short usage)
+ 	}
+ }
+ #elif defined(BF548_FAMILY)
+-static void port_setup(unsigned short gpio, unsigned short usage)
++static void port_setup(unsigned gpio, unsigned short usage)
+ {
+ 	if (usage == GPIO_USAGE)
+ 		gpio_array[gpio_bank(gpio)]->port_fer &= ~gpio_bit(gpio);
+@@ -390,7 +397,7 @@ inline void portmux_setup(unsigned short portno, unsigned short function)
+ #endif
+ 
+ #ifndef BF548_FAMILY
+-static void default_gpio(unsigned short gpio)
++static void default_gpio(unsigned gpio)
+ {
+ 	unsigned short bank, bitmask;
+ 	unsigned long flags;
+@@ -410,7 +417,6 @@ static void default_gpio(unsigned short gpio)
+ 	gpio_bankb[bank]->edge &= ~bitmask;
+ 	AWA_DUMMY_READ(edge);
+ 	local_irq_restore(flags);
+-
+ }
+ #else
+ # define default_gpio(...)  do { } while (0)
+@@ -418,12 +424,6 @@ static void default_gpio(unsigned short gpio)
+ 
+ static int __init bfin_gpio_init(void)
+ {
+-	str_ident = kcalloc(MAX_RESOURCES,
+-				 sizeof(struct str_ident), GFP_KERNEL);
+-	if (str_ident == NULL)
+-		return -ENOMEM;
+-
+-	memset(str_ident, 0, MAX_RESOURCES * sizeof(struct str_ident));
+ 
+ 	printk(KERN_INFO "Blackfin GPIO Controller\n");
+ 
+@@ -454,10 +454,9 @@ arch_initcall(bfin_gpio_init);
+ /* Set a specific bit */
+ 
+ #define SET_GPIO(name) \
+-void set_gpio_ ## name(unsigned short gpio, unsigned short arg) \
++void set_gpio_ ## name(unsigned gpio, unsigned short arg) \
+ { \
+ 	unsigned long flags; \
+-	BUG_ON(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio))); \
+ 	local_irq_save(flags); \
+ 	if (arg) \
+ 		gpio_bankb[gpio_bank(gpio)]->name |= gpio_bit(gpio); \
+@@ -477,10 +476,9 @@ SET_GPIO(both)
+ 
+ #if ANOMALY_05000311 || ANOMALY_05000323
+ #define SET_GPIO_SC(name) \
+-void set_gpio_ ## name(unsigned short gpio, unsigned short arg) \
++void set_gpio_ ## name(unsigned gpio, unsigned short arg) \
+ { \
+ 	unsigned long flags; \
+-	BUG_ON(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio))); \
+ 	local_irq_save(flags); \
+ 	if (arg) \
+ 		gpio_bankb[gpio_bank(gpio)]->name ## _set = gpio_bit(gpio); \
+@@ -492,9 +490,8 @@ void set_gpio_ ## name(unsigned short gpio, unsigned short arg) \
+ EXPORT_SYMBOL(set_gpio_ ## name);
+ #else
+ #define SET_GPIO_SC(name) \
+-void set_gpio_ ## name(unsigned short gpio, unsigned short arg) \
++void set_gpio_ ## name(unsigned gpio, unsigned short arg) \
+ { \
+-	BUG_ON(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio))); \
+ 	if (arg) \
+ 		gpio_bankb[gpio_bank(gpio)]->name ## _set = gpio_bit(gpio); \
+ 	else \
+@@ -508,19 +505,17 @@ SET_GPIO_SC(maskb)
+ SET_GPIO_SC(data)
+ 
+ #if ANOMALY_05000311 || ANOMALY_05000323
+-void set_gpio_toggle(unsigned short gpio)
++void set_gpio_toggle(unsigned gpio)
+ {
+ 	unsigned long flags;
+-	BUG_ON(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio)));
+ 	local_irq_save(flags);
+ 	gpio_bankb[gpio_bank(gpio)]->toggle = gpio_bit(gpio);
+ 	AWA_DUMMY_READ(toggle);
+ 	local_irq_restore(flags);
+ }
+ #else
+-void set_gpio_toggle(unsigned short gpio)
++void set_gpio_toggle(unsigned gpio)
+ {
+-	BUG_ON(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio)));
+ 	gpio_bankb[gpio_bank(gpio)]->toggle = gpio_bit(gpio);
+ }
+ #endif
+@@ -531,7 +526,7 @@ EXPORT_SYMBOL(set_gpio_toggle);
+ 
+ #if ANOMALY_05000311 || ANOMALY_05000323
+ #define SET_GPIO_P(name) \
+-void set_gpiop_ ## name(unsigned short gpio, unsigned short arg) \
++void set_gpiop_ ## name(unsigned gpio, unsigned short arg) \
+ { \
+ 	unsigned long flags; \
+ 	local_irq_save(flags); \
+@@ -542,7 +537,7 @@ void set_gpiop_ ## name(unsigned short gpio, unsigned short arg) \
+ EXPORT_SYMBOL(set_gpiop_ ## name);
+ #else
+ #define SET_GPIO_P(name) \
+-void set_gpiop_ ## name(unsigned short gpio, unsigned short arg) \
++void set_gpiop_ ## name(unsigned gpio, unsigned short arg) \
+ { \
+ 	gpio_bankb[gpio_bank(gpio)]->name = arg; \
+ } \
+@@ -558,11 +553,10 @@ SET_GPIO_P(both)
+ SET_GPIO_P(maska)
+ SET_GPIO_P(maskb)
+ 
+-
+ /* Get a specific bit */
+ #if ANOMALY_05000311 || ANOMALY_05000323
+ #define GET_GPIO(name) \
+-unsigned short get_gpio_ ## name(unsigned short gpio) \
++unsigned short get_gpio_ ## name(unsigned gpio) \
+ { \
+ 	unsigned long flags; \
+ 	unsigned short ret; \
+@@ -575,7 +569,7 @@ unsigned short get_gpio_ ## name(unsigned short gpio) \
+ EXPORT_SYMBOL(get_gpio_ ## name);
+ #else
+ #define GET_GPIO(name) \
+-unsigned short get_gpio_ ## name(unsigned short gpio) \
++unsigned short get_gpio_ ## name(unsigned gpio) \
+ { \
+ 	return (0x01 & (gpio_bankb[gpio_bank(gpio)]->name >> gpio_sub_n(gpio))); \
+ } \
+@@ -595,7 +589,7 @@ GET_GPIO(maskb)
+ 
+ #if ANOMALY_05000311 || ANOMALY_05000323
+ #define GET_GPIO_P(name) \
+-unsigned short get_gpiop_ ## name(unsigned short gpio) \
++unsigned short get_gpiop_ ## name(unsigned gpio) \
+ { \
+ 	unsigned long flags; \
+ 	unsigned short ret; \
+@@ -608,7 +602,7 @@ unsigned short get_gpiop_ ## name(unsigned short gpio) \
+ EXPORT_SYMBOL(get_gpiop_ ## name);
+ #else
+ #define GET_GPIO_P(name) \
+-unsigned short get_gpiop_ ## name(unsigned short gpio) \
++unsigned short get_gpiop_ ## name(unsigned gpio) \
+ { \
+ 	return (gpio_bankb[gpio_bank(gpio)]->name);\
+ } \
+@@ -645,7 +639,7 @@ GET_GPIO_P(maskb)
+ *************************************************************
+ * MODIFICATION HISTORY :
+ **************************************************************/
+-int gpio_pm_wakeup_request(unsigned short gpio, unsigned char type)
++int gpio_pm_wakeup_request(unsigned gpio, unsigned char type)
+ {
+ 	unsigned long flags;
+ 
+@@ -653,7 +647,6 @@ int gpio_pm_wakeup_request(unsigned short gpio, unsigned char type)
+ 		return -EINVAL;
+ 
+ 	local_irq_save(flags);
+-
+ 	wakeup_map[gpio_bank(gpio)] |= gpio_bit(gpio);
+ 	wakeup_flags_map[gpio] = type;
+ 	local_irq_restore(flags);
+@@ -662,7 +655,7 @@ int gpio_pm_wakeup_request(unsigned short gpio, unsigned char type)
+ }
+ EXPORT_SYMBOL(gpio_pm_wakeup_request);
+ 
+-void gpio_pm_wakeup_free(unsigned short gpio)
++void gpio_pm_wakeup_free(unsigned gpio)
+ {
+ 	unsigned long flags;
+ 
+@@ -677,7 +670,7 @@ void gpio_pm_wakeup_free(unsigned short gpio)
+ }
+ EXPORT_SYMBOL(gpio_pm_wakeup_free);
+ 
+-static int bfin_gpio_wakeup_type(unsigned short gpio, unsigned char type)
++static int bfin_gpio_wakeup_type(unsigned gpio, unsigned char type)
+ {
+ 	port_setup(gpio, GPIO_USAGE);
+ 	set_gpio_dir(gpio, 0);
+@@ -784,6 +777,14 @@ void gpio_pm_restore(void)
+ }
+ 
+ #endif
++#else /* BF548_FAMILY */
++
++unsigned short get_gpio_dir(unsigned gpio)
++{
++	return (0x01 & (gpio_array[gpio_bank(gpio)]->port_dir_clear >> gpio_sub_n(gpio)));
++}
++EXPORT_SYMBOL(get_gpio_dir);
++
+ #endif /* BF548_FAMILY */
+ 
+ /***********************************************************
+@@ -1028,7 +1029,7 @@ EXPORT_SYMBOL(peripheral_free_list);
+ * MODIFICATION HISTORY :
+ **************************************************************/
+ 
+-int gpio_request(unsigned short gpio, const char *label)
++int gpio_request(unsigned gpio, const char *label)
+ {
+ 	unsigned long flags;
+ 
+@@ -1075,7 +1076,7 @@ int gpio_request(unsigned short gpio, const char *label)
+ }
+ EXPORT_SYMBOL(gpio_request);
+ 
+-void gpio_free(unsigned short gpio)
++void gpio_free(unsigned gpio)
+ {
+ 	unsigned long flags;
+ 
+@@ -1085,7 +1086,7 @@ void gpio_free(unsigned short gpio)
+ 	local_irq_save(flags);
+ 
+ 	if (unlikely(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio)))) {
+-		printk(KERN_ERR "bfin-gpio: GPIO %d wasn't reserved!\n", gpio);
++		gpio_error(gpio);
+ 		dump_stack();
+ 		local_irq_restore(flags);
+ 		return;
+@@ -1101,44 +1102,55 @@ void gpio_free(unsigned short gpio)
+ }
+ EXPORT_SYMBOL(gpio_free);
+ 
++
+ #ifdef BF548_FAMILY
+-void gpio_direction_input(unsigned short gpio)
++int gpio_direction_input(unsigned gpio)
+ {
+ 	unsigned long flags;
+ 
+-	BUG_ON(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio)));
++	if (!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio))) {
++		gpio_error(gpio);
++		return -EINVAL;
++	}
+ 
+ 	local_irq_save(flags);
+ 	gpio_array[gpio_bank(gpio)]->port_dir_clear = gpio_bit(gpio);
+ 	gpio_array[gpio_bank(gpio)]->port_inen |= gpio_bit(gpio);
+ 	local_irq_restore(flags);
++
++	return 0;
+ }
+ EXPORT_SYMBOL(gpio_direction_input);
+ 
+-void gpio_direction_output(unsigned short gpio)
++int gpio_direction_output(unsigned gpio, int value)
+ {
+ 	unsigned long flags;
+ 
+-	BUG_ON(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio)));
++	if (!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio))) {
++		gpio_error(gpio);
++		return -EINVAL;
++	}
+ 
+ 	local_irq_save(flags);
+ 	gpio_array[gpio_bank(gpio)]->port_inen &= ~gpio_bit(gpio);
++	gpio_set_value(gpio, value);
+ 	gpio_array[gpio_bank(gpio)]->port_dir_set = gpio_bit(gpio);
+ 	local_irq_restore(flags);
++
++	return 0;
+ }
+ EXPORT_SYMBOL(gpio_direction_output);
+ 
+-void gpio_set_value(unsigned short gpio, unsigned short arg)
++void gpio_set_value(unsigned gpio, int arg)
+ {
+ 	if (arg)
+ 		gpio_array[gpio_bank(gpio)]->port_set = gpio_bit(gpio);
+ 	else
+ 		gpio_array[gpio_bank(gpio)]->port_clear = gpio_bit(gpio);
+-
+ }
+ EXPORT_SYMBOL(gpio_set_value);
+ 
+-unsigned short gpio_get_value(unsigned short gpio)
++int gpio_get_value(unsigned gpio)
+ {
+ 	return (1 & (gpio_array[gpio_bank(gpio)]->port_data >> gpio_sub_n(gpio)));
+ }
+@@ -1146,31 +1158,47 @@ EXPORT_SYMBOL(gpio_get_value);
+ 
+ #else
+ 
+-void gpio_direction_input(unsigned short gpio)
++int gpio_direction_input(unsigned gpio)
+ {
+ 	unsigned long flags;
+ 
+-	BUG_ON(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio)));
++	if (!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio))) {
++		gpio_error(gpio);
++		return -EINVAL;
++	}
+ 
+ 	local_irq_save(flags);
+ 	gpio_bankb[gpio_bank(gpio)]->dir &= ~gpio_bit(gpio);
+ 	gpio_bankb[gpio_bank(gpio)]->inen |= gpio_bit(gpio);
+ 	AWA_DUMMY_READ(inen);
+ 	local_irq_restore(flags);
++
++	return 0;
+ }
+ EXPORT_SYMBOL(gpio_direction_input);
+ 
+-void gpio_direction_output(unsigned short gpio)
++int gpio_direction_output(unsigned gpio, int value)
+ {
+ 	unsigned long flags;
+ 
+-	BUG_ON(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio)));
++	if (!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio))) {
++		gpio_error(gpio);
++		return -EINVAL;
++	}
+ 
+ 	local_irq_save(flags);
+ 	gpio_bankb[gpio_bank(gpio)]->inen &= ~gpio_bit(gpio);
++
++	if (value)
++		gpio_bankb[gpio_bank(gpio)]->data_set = gpio_bit(gpio);
++	else
++		gpio_bankb[gpio_bank(gpio)]->data_clear = gpio_bit(gpio);
++
+ 	gpio_bankb[gpio_bank(gpio)]->dir |= gpio_bit(gpio);
+ 	AWA_DUMMY_READ(dir);
+ 	local_irq_restore(flags);
++
++	return 0;
+ }
+ EXPORT_SYMBOL(gpio_direction_output);
+ 
+@@ -1190,7 +1218,40 @@ void bfin_gpio_reset_spi0_ssel1(void)
+ 
+ 	port_setup(gpio, GPIO_USAGE);
+ 	gpio_bankb[gpio_bank(gpio)]->data_set = gpio_bit(gpio);
++	AWA_DUMMY_READ(data_set);
+ 	udelay(1);
+ }
+ 
+ #endif /*BF548_FAMILY */
++
++#if defined(CONFIG_PROC_FS)
++static int gpio_proc_read(char *buf, char **start, off_t offset,
++			  int len, int *unused_i, void *unused_v)
++{
++	int c, outlen = 0;
++
++	for (c = 0; c < MAX_RESOURCES; c++) {
++		if (!check_gpio(c) && (reserved_gpio_map[gpio_bank(c)] & gpio_bit(c)))
++			len = sprintf(buf, "GPIO_%d: %s \t\tGPIO %s\n", c,
++				 get_label(c), get_gpio_dir(c) ? "OUTPUT" : "INPUT");
++		else if (reserved_peri_map[gpio_bank(c)] & gpio_bit(c))
++			len = sprintf(buf, "GPIO_%d: %s \t\tPeripheral\n", c, get_label(c));
++		else
++			continue;
++		buf += len;
++		outlen += len;
++	}
++	return outlen;
++}
++
++static __init int gpio_register_proc(void)
++{
++	struct proc_dir_entry *proc_gpio;
++
++	proc_gpio = create_proc_entry("gpio", S_IRUGO, NULL);
++	if (proc_gpio)
++		proc_gpio->read_proc = gpio_proc_read;
++	return proc_gpio != NULL;
++}
++__initcall(gpio_register_proc);
++#endif
+diff --git a/arch/blackfin/kernel/cacheinit.c b/arch/blackfin/kernel/cacheinit.c
+deleted file mode 100644
+index 62cbba7..0000000
+--- a/arch/blackfin/kernel/cacheinit.c
++++ /dev/null
+@@ -1,67 +0,0 @@
+-/*
+- *               Copyright 2004-2007 Analog Devices 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, see the file COPYING, or write
+- * to the Free Software Foundation, Inc.,
+- * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+- */
+-
+-#include <linux/cpu.h>
+-
+-#include <asm/cacheflush.h>
+-#include <asm/blackfin.h>
+-#include <asm/cplb.h>
+-#include <asm/cplbinit.h>
+-
+-#if defined(CONFIG_BFIN_ICACHE)
+-void bfin_icache_init(void)
+-{
+-	unsigned long *table = icplb_table;
+-	unsigned long ctrl;
+-	int i;
+-
+-	for (i = 0; i < MAX_CPLBS; i++) {
+-		unsigned long addr = *table++;
+-		unsigned long data = *table++;
+-		if (addr == (unsigned long)-1)
+-			break;
+-		bfin_write32(ICPLB_ADDR0 + i * 4, addr);
+-		bfin_write32(ICPLB_DATA0 + i * 4, data);
+-	}
+-	ctrl = bfin_read_IMEM_CONTROL();
+-	ctrl |= IMC | ENICPLB;
+-	bfin_write_IMEM_CONTROL(ctrl);
+-}
+-#endif
+-
+-#if defined(CONFIG_BFIN_DCACHE)
+-void bfin_dcache_init(void)
+-{
+-	unsigned long *table = dcplb_table;
+-	unsigned long ctrl;
+-	int i;
+-
+-	for (i = 0; i < MAX_CPLBS; i++) {
+-		unsigned long addr = *table++;
+-		unsigned long data = *table++;
+-		if (addr == (unsigned long)-1)
+-			break;
+-		bfin_write32(DCPLB_ADDR0 + i * 4, addr);
+-		bfin_write32(DCPLB_DATA0 + i * 4, data);
+-	}
+-	ctrl = bfin_read_DMEM_CONTROL();
+-	ctrl |= DMEM_CNTR;
+-	bfin_write_DMEM_CONTROL(ctrl);
+-}
+-#endif
+diff --git a/arch/blackfin/kernel/cplb-mpu/Makefile b/arch/blackfin/kernel/cplb-mpu/Makefile
+new file mode 100644
+index 0000000..286b693
+--- /dev/null
++++ b/arch/blackfin/kernel/cplb-mpu/Makefile
+@@ -0,0 +1,8 @@
++#
++# arch/blackfin/kernel/cplb-nompu/Makefile
++#
++
++obj-y := cplbinit.o cacheinit.o cplbmgr.o
++
++obj-$(CONFIG_CPLB_INFO) += cplbinfo.o
++
+diff --git a/arch/blackfin/kernel/cplb-mpu/cacheinit.c b/arch/blackfin/kernel/cplb-mpu/cacheinit.c
+new file mode 100644
+index 0000000..9eecfa4
+--- /dev/null
++++ b/arch/blackfin/kernel/cplb-mpu/cacheinit.c
+@@ -0,0 +1,62 @@
++/*
++ *               Copyright 2004-2007 Analog Devices 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, see the file COPYING, or write
++ * to the Free Software Foundation, Inc.,
++ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ */
++
++#include <linux/cpu.h>
++
++#include <asm/cacheflush.h>
++#include <asm/blackfin.h>
++#include <asm/cplb.h>
++#include <asm/cplbinit.h>
++
++#if defined(CONFIG_BFIN_ICACHE)
++void bfin_icache_init(void)
++{
++	unsigned long ctrl;
++	int i;
++
++	SSYNC();
++	for (i = 0; i < MAX_CPLBS; i++) {
++		bfin_write32(ICPLB_ADDR0 + i * 4, icplb_tbl[i].addr);
++		bfin_write32(ICPLB_DATA0 + i * 4, icplb_tbl[i].data);
++	}
++	ctrl = bfin_read_IMEM_CONTROL();
++	ctrl |= IMC | ENICPLB;
++	bfin_write_IMEM_CONTROL(ctrl);
++	SSYNC();
++}
++#endif
++
++#if defined(CONFIG_BFIN_DCACHE)
++void bfin_dcache_init(void)
++{
++	unsigned long ctrl;
++	int i;
++
++	SSYNC();
++	for (i = 0; i < MAX_CPLBS; i++) {
++		bfin_write32(DCPLB_ADDR0 + i * 4, dcplb_tbl[i].addr);
++		bfin_write32(DCPLB_DATA0 + i * 4, dcplb_tbl[i].data);
++	}
++
++	ctrl = bfin_read_DMEM_CONTROL();
++	ctrl |= DMEM_CNTR;
++	bfin_write_DMEM_CONTROL(ctrl);
++	SSYNC();
++}
++#endif
+diff --git a/arch/blackfin/kernel/cplb-mpu/cplbinfo.c b/arch/blackfin/kernel/cplb-mpu/cplbinfo.c
+new file mode 100644
+index 0000000..bd07229
+--- /dev/null
++++ b/arch/blackfin/kernel/cplb-mpu/cplbinfo.c
+@@ -0,0 +1,144 @@
++/*
++ * File:         arch/blackfin/mach-common/cplbinfo.c
++ * Based on:
++ * Author:       Sonic Zhang <sonic.zhang at analog.com>
++ *
++ * Created:      Jan. 2005
++ * Description:  Display CPLB status
++ *
++ * Modified:
++ *               Copyright 2004-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
++ */
++
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/proc_fs.h>
++#include <linux/uaccess.h>
++
++#include <asm/current.h>
++#include <asm/system.h>
++#include <asm/cplb.h>
++#include <asm/cplbinit.h>
++#include <asm/blackfin.h>
++
++#define CPLB_I 1
++#define CPLB_D 2
++
++#define SYNC_SYS    SSYNC()
++#define SYNC_CORE   CSYNC()
++
++#define CPLB_BIT_PAGESIZE 0x30000
++
++static char page_size_string_table[][4] = { "1K", "4K", "1M", "4M" };
++
++static char *cplb_print_entry(char *buf, struct cplb_entry *tbl, int switched)
++{
++	int i;
++	buf += sprintf(buf, "Index\tAddress\t\tData\tSize\tU/RD\tU/WR\tS/WR\tSwitch\n");
++	for (i = 0; i < MAX_CPLBS; i++) {
++		unsigned long data = tbl[i].data;
++		unsigned long addr = tbl[i].addr;
++		if (!(data & CPLB_VALID))
++			continue;
++
++		buf +=
++		    sprintf(buf,
++			    "%d\t0x%08lx\t%06lx\t%s\t%c\t%c\t%c\t%c\n",
++			    i, addr, data,
++			    page_size_string_table[(data & 0x30000) >> 16],
++			    (data & CPLB_USER_RD) ? 'Y' : 'N',
++			    (data & CPLB_USER_WR) ? 'Y' : 'N',
++			    (data & CPLB_SUPV_WR) ? 'Y' : 'N',
++			    i < switched ? 'N' : 'Y');
++	}
++	buf += sprintf(buf, "\n");
++
++	return buf;
++}
++
++int cplbinfo_proc_output(char *buf)
++{
++	char *p;
++
++	p = buf;
++
++	p += sprintf(p, "------------------ CPLB Information ------------------\n\n");
++
++	if (bfin_read_IMEM_CONTROL() & ENICPLB) {
++		p += sprintf(p, "Instruction CPLB entry:\n");
++		p = cplb_print_entry(p, icplb_tbl, first_switched_icplb);
++	} else
++		p += sprintf(p, "Instruction CPLB is disabled.\n\n");
++
++	if (1 || bfin_read_DMEM_CONTROL() & ENDCPLB) {
++		p += sprintf(p, "Data CPLB entry:\n");
++		p = cplb_print_entry(p, dcplb_tbl, first_switched_dcplb);
++	} else
++		p += sprintf(p, "Data CPLB is disabled.\n");
++
++	p += sprintf(p, "ICPLB miss: %d\nICPLB supervisor miss: %d\n",
++		     nr_icplb_miss, nr_icplb_supv_miss);
++	p += sprintf(p, "DCPLB miss: %d\nDCPLB protection fault:%d\n",
++		     nr_dcplb_miss, nr_dcplb_prot);
++	p += sprintf(p, "CPLB flushes: %d\n",
++		     nr_cplb_flush);
++
++	return p - buf;
++}
++
++static int cplbinfo_read_proc(char *page, char **start, off_t off,
++			      int count, int *eof, void *data)
++{
++	int len;
++
++	len = cplbinfo_proc_output(page);
++	if (len <= off + count)
++		*eof = 1;
++	*start = page + off;
++	len -= off;
++	if (len > count)
++		len = count;
++	if (len < 0)
++		len = 0;
++	return len;
++}
++
++static int __init cplbinfo_init(void)
++{
++	struct proc_dir_entry *entry;
++
++	entry = create_proc_entry("cplbinfo", 0, NULL);
++	if (!entry)
++		return -ENOMEM;
++
++	entry->read_proc = cplbinfo_read_proc;
++	entry->data = NULL;
++
++	return 0;
++}
++
++static void __exit cplbinfo_exit(void)
++{
++	remove_proc_entry("cplbinfo", NULL);
++}
++
++module_init(cplbinfo_init);
++module_exit(cplbinfo_exit);
+diff --git a/arch/blackfin/kernel/cplb-mpu/cplbinit.c b/arch/blackfin/kernel/cplb-mpu/cplbinit.c
+new file mode 100644
+index 0000000..e2e2b50
+--- /dev/null
++++ b/arch/blackfin/kernel/cplb-mpu/cplbinit.c
+@@ -0,0 +1,91 @@
++/*
++ * Blackfin CPLB initialization
++ *
++ *               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 <asm/blackfin.h>
++#include <asm/cplb.h>
++#include <asm/cplbinit.h>
++
++struct cplb_entry icplb_tbl[MAX_CPLBS];
++struct cplb_entry dcplb_tbl[MAX_CPLBS];
++
++int first_switched_icplb, first_switched_dcplb;
++int first_mask_dcplb;
++
++void __init generate_cpl_tables(void)
++{
++	int i_d, i_i;
++	unsigned long addr;
++	unsigned long d_data, i_data;
++	unsigned long d_cache = 0, i_cache = 0;
++
++#ifdef CONFIG_BFIN_ICACHE
++	i_cache = CPLB_L1_CHBL | ANOMALY_05000158_WORKAROUND;
++#endif
++
++#ifdef CONFIG_BFIN_DCACHE
++	d_cache = CPLB_L1_CHBL;
++#ifdef CONFIG_BLKFIN_WT
++	d_cache |= CPLB_L1_AOW | CPLB_WT;
++#endif
++#endif
++	i_d = i_i = 0;
++
++	/* Set up the zero page.  */
++	dcplb_tbl[i_d].addr = 0;
++	dcplb_tbl[i_d++].data = SDRAM_OOPS | PAGE_SIZE_1KB;
++
++#if 0
++	icplb_tbl[i_i].addr = 0;
++	icplb_tbl[i_i++].data = i_cache | CPLB_USER_RD | PAGE_SIZE_4KB;
++#endif
++
++	/* Cover kernel memory with 4M pages.  */
++	addr = 0;
++	d_data = d_cache | CPLB_SUPV_WR | CPLB_VALID | PAGE_SIZE_4MB | CPLB_DIRTY;
++	i_data = i_cache | CPLB_VALID | CPLB_PORTPRIO | PAGE_SIZE_4MB;
++
++	for (; addr < memory_start; addr += 4 * 1024 * 1024) {
++		dcplb_tbl[i_d].addr = addr;
++		dcplb_tbl[i_d++].data = d_data;
++		icplb_tbl[i_i].addr = addr;
++		icplb_tbl[i_i++].data = i_data | (addr == 0 ? CPLB_USER_RD : 0);
++	}
++
++	/* Cover L1 memory.  One 4M area for code and data each is enough.  */
++#if L1_DATA_A_LENGTH > 0 || L1_DATA_B_LENGTH > 0
++	dcplb_tbl[i_d].addr = L1_DATA_A_START;
++	dcplb_tbl[i_d++].data = L1_DMEMORY | PAGE_SIZE_4MB;
++#endif
++	icplb_tbl[i_i].addr = L1_CODE_START;
++	icplb_tbl[i_i++].data = L1_IMEMORY | PAGE_SIZE_4MB;
++
++	first_mask_dcplb = i_d;
++	first_switched_dcplb = i_d + (1 << page_mask_order);
++	first_switched_icplb = i_i;
++
++	while (i_d < MAX_CPLBS)
++		dcplb_tbl[i_d++].data = 0;
++	while (i_i < MAX_CPLBS)
++		icplb_tbl[i_i++].data = 0;
++}
+diff --git a/arch/blackfin/kernel/cplb-mpu/cplbmgr.c b/arch/blackfin/kernel/cplb-mpu/cplbmgr.c
+new file mode 100644
+index 0000000..c426a22
+--- /dev/null
++++ b/arch/blackfin/kernel/cplb-mpu/cplbmgr.c
+@@ -0,0 +1,338 @@
++/*
++ *               Blackfin CPLB exception handling.
++ *               Copyright 2004-2007 Analog Devices 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, 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/mm.h>
++
++#include <asm/blackfin.h>
++#include <asm/cplbinit.h>
++#include <asm/mmu_context.h>
++
++#ifdef CONFIG_BFIN_ICACHE
++
++#define FAULT_RW	(1 << 16)
++#define FAULT_USERSUPV	(1 << 17)
++
++int page_mask_nelts;
++int page_mask_order;
++unsigned long *current_rwx_mask;
++
++int nr_dcplb_miss, nr_icplb_miss, nr_icplb_supv_miss, nr_dcplb_prot;
++int nr_cplb_flush;
++
++static inline void disable_dcplb(void)
++{
++	unsigned long ctrl;
++	SSYNC();
++	ctrl = bfin_read_DMEM_CONTROL();
++	ctrl &= ~ENDCPLB;
++	bfin_write_DMEM_CONTROL(ctrl);
++	SSYNC();
++}
++
++static inline void enable_dcplb(void)
++{
++	unsigned long ctrl;
++	SSYNC();
++	ctrl = bfin_read_DMEM_CONTROL();
++	ctrl |= ENDCPLB;
++	bfin_write_DMEM_CONTROL(ctrl);
++	SSYNC();
++}
++
++static inline void disable_icplb(void)
++{
++	unsigned long ctrl;
++	SSYNC();
++	ctrl = bfin_read_IMEM_CONTROL();
++	ctrl &= ~ENICPLB;
++	bfin_write_IMEM_CONTROL(ctrl);
++	SSYNC();
++}
++
++static inline void enable_icplb(void)
++{
++	unsigned long ctrl;
++	SSYNC();
++	ctrl = bfin_read_IMEM_CONTROL();
++	ctrl |= ENICPLB;
++	bfin_write_IMEM_CONTROL(ctrl);
++	SSYNC();
++}
++
++/*
++ * Given the contents of the status register, return the index of the
++ * CPLB that caused the fault.
++ */
++static inline int faulting_cplb_index(int status)
++{
++	int signbits = __builtin_bfin_norm_fr1x32(status & 0xFFFF);
++	return 30 - signbits;
++}
++
++/*
++ * Given the contents of the status register and the DCPLB_DATA contents,
++ * return true if a write access should be permitted.
++ */
++static inline int write_permitted(int status, unsigned long data)
++{
++	if (status & FAULT_USERSUPV)
++		return !!(data & CPLB_SUPV_WR);
++	else
++		return !!(data & CPLB_USER_WR);
++}
++
++/* Counters to implement round-robin replacement.  */
++static int icplb_rr_index, dcplb_rr_index;
++
++/*
++ * Find an ICPLB entry to be evicted and return its index.
++ */
++static int evict_one_icplb(void)
++{
++	int i;
++	for (i = first_switched_icplb; i < MAX_CPLBS; i++)
++		if ((icplb_tbl[i].data & CPLB_VALID) == 0)
++			return i;
++	i = first_switched_icplb + icplb_rr_index;
++	if (i >= MAX_CPLBS) {
++		i -= MAX_CPLBS - first_switched_icplb;
++		icplb_rr_index -= MAX_CPLBS - first_switched_icplb;
++	}
++	icplb_rr_index++;
++	return i;
++}
++
++static int evict_one_dcplb(void)
++{
++	int i;
++	for (i = first_switched_dcplb; i < MAX_CPLBS; i++)
++		if ((dcplb_tbl[i].data & CPLB_VALID) == 0)
++			return i;
++	i = first_switched_dcplb + dcplb_rr_index;
++	if (i >= MAX_CPLBS) {
++		i -= MAX_CPLBS - first_switched_dcplb;
++		dcplb_rr_index -= MAX_CPLBS - first_switched_dcplb;
++	}
++	dcplb_rr_index++;
++	return i;
++}
++
++static noinline int dcplb_miss(void)
++{
++	unsigned long addr = bfin_read_DCPLB_FAULT_ADDR();
++	int status = bfin_read_DCPLB_STATUS();
++	unsigned long *mask;
++	int idx;
++	unsigned long d_data;
++
++	nr_dcplb_miss++;
++	if (addr >= _ramend)
++		return CPLB_PROT_VIOL;
++
++	d_data = CPLB_SUPV_WR | CPLB_VALID | CPLB_DIRTY | PAGE_SIZE_4KB;
++#ifdef CONFIG_BFIN_DCACHE
++	d_data |= CPLB_L1_CHBL | ANOMALY_05000158_WORKAROUND;
++#ifdef CONFIG_BLKFIN_WT
++	d_data |= CPLB_L1_AOW | CPLB_WT;
++#endif
++#endif
++	mask = current_rwx_mask;
++	if (mask) {
++		int page = addr >> PAGE_SHIFT;
++		int offs = page >> 5;
++		int bit = 1 << (page & 31);
++
++		if (mask[offs] & bit)
++			d_data |= CPLB_USER_RD;
++
++		mask += page_mask_nelts;
++		if (mask[offs] & bit)
++			d_data |= CPLB_USER_WR;
++	}
++
++	idx = evict_one_dcplb();
++
++	addr &= PAGE_MASK;
++	dcplb_tbl[idx].addr = addr;
++	dcplb_tbl[idx].data = d_data;
++
++	disable_dcplb();
++	bfin_write32(DCPLB_DATA0 + idx * 4, d_data);
++	bfin_write32(DCPLB_ADDR0 + idx * 4, addr);
++	enable_dcplb();
++
++	return 0;
++}
++
++static noinline int icplb_miss(void)
++{
++	unsigned long addr = bfin_read_ICPLB_FAULT_ADDR();
++	int status = bfin_read_ICPLB_STATUS();
++	int idx;
++	unsigned long i_data;
++
++	nr_icplb_miss++;
++	if (status & FAULT_USERSUPV)
++		nr_icplb_supv_miss++;
++
++	if (addr >= _ramend)
++		return CPLB_PROT_VIOL;
++
++	/*
++	 * First, try to find a CPLB that matches this address.  If we
++	 * find one, then the fact that we're in the miss handler means
++	 * that the instruction crosses a page boundary.
++	 */
++	for (idx = first_switched_icplb; idx < MAX_CPLBS; idx++) {
++		if (icplb_tbl[idx].data & CPLB_VALID) {
++			unsigned long this_addr = icplb_tbl[idx].addr;
++			if (this_addr <= addr && this_addr + PAGE_SIZE > addr) {
++				addr += PAGE_SIZE;
++				break;
++			}
++		}
++	}
++
++	i_data = CPLB_VALID | CPLB_PORTPRIO | PAGE_SIZE_4KB;
++#ifdef CONFIG_BFIN_ICACHE
++	i_data |= CPLB_L1_CHBL | ANOMALY_05000158_WORKAROUND;
++#endif
++
++	/*
++	 * Two cases to distinguish - a supervisor access must necessarily
++	 * be for a module page; we grant it unconditionally (could do better
++	 * here in the future).  Otherwise, check the x bitmap of the current
++	 * process.
++	 */
++	if (!(status & FAULT_USERSUPV)) {
++		unsigned long *mask = current_rwx_mask;
++
++		if (mask) {
++			int page = addr >> PAGE_SHIFT;
++			int offs = page >> 5;
++			int bit = 1 << (page & 31);
++
++			mask += 2 * page_mask_nelts;
++			if (mask[offs] & bit)
++				i_data |= CPLB_USER_RD;
++		}
++	}
++
++	idx = evict_one_icplb();
++	addr &= PAGE_MASK;
++	icplb_tbl[idx].addr = addr;
++	icplb_tbl[idx].data = i_data;
++
++	disable_icplb();
++	bfin_write32(ICPLB_DATA0 + idx * 4, i_data);
++	bfin_write32(ICPLB_ADDR0 + idx * 4, addr);
++	enable_icplb();
++
++	return 0;
++}
++
++static noinline int dcplb_protection_fault(void)
++{
++	unsigned long addr = bfin_read_DCPLB_FAULT_ADDR();
++	int status = bfin_read_DCPLB_STATUS();
++
++	nr_dcplb_prot++;
++
++	if (status & FAULT_RW) {
++		int idx = faulting_cplb_index(status);
++		unsigned long data = dcplb_tbl[idx].data;
++		if (!(data & CPLB_WT) && !(data & CPLB_DIRTY) &&
++		    write_permitted(status, data)) {
++			data |= CPLB_DIRTY;
++			dcplb_tbl[idx].data = data;
++			bfin_write32(DCPLB_DATA0 + idx * 4, data);
++			return 0;
++		}
++	}
++	return CPLB_PROT_VIOL;
++}
++
++int cplb_hdr(int seqstat, struct pt_regs *regs)
++{
++	int cause = seqstat & 0x3f;
++	switch (cause) {
++	case 0x23:
++		return dcplb_protection_fault();
++	case 0x2C:
++		return icplb_miss();
++	case 0x26:
++		return dcplb_miss();
++	default:
++	    return 1;
++		panic_cplb_error(seqstat, regs);
++	}
++}
++
++void flush_switched_cplbs(void)
++{
++	int i;
++
++	nr_cplb_flush++;
++
++	disable_icplb();
++	for (i = first_switched_icplb; i < MAX_CPLBS; i++) {
++		icplb_tbl[i].data = 0;
++		bfin_write32(ICPLB_DATA0 + i * 4, 0);
++	}
++	enable_icplb();
++
++	disable_dcplb();
++	for (i = first_mask_dcplb; i < MAX_CPLBS; i++) {
++		dcplb_tbl[i].data = 0;
++		bfin_write32(DCPLB_DATA0 + i * 4, 0);
++	}
++	enable_dcplb();
++}
++
++void set_mask_dcplbs(unsigned long *masks)
++{
++	int i;
++	unsigned long addr = (unsigned long)masks;
++	unsigned long d_data;
++	current_rwx_mask = masks;
++
++	if (!masks)
++		return;
++
++	d_data = CPLB_SUPV_WR | CPLB_VALID | CPLB_DIRTY | PAGE_SIZE_4KB;
++#ifdef CONFIG_BFIN_DCACHE
++	d_data |= CPLB_L1_CHBL;
++#ifdef CONFIG_BLKFIN_WT
++	d_data |= CPLB_L1_AOW | CPLB_WT;
++#endif
++#endif
++
++	disable_dcplb();
++	for (i = first_mask_dcplb; i < first_switched_dcplb; i++) {
++		dcplb_tbl[i].addr = addr;
++		dcplb_tbl[i].data = d_data;
++		bfin_write32(DCPLB_DATA0 + i * 4, d_data);
++		bfin_write32(DCPLB_ADDR0 + i * 4, addr);
++		addr += PAGE_SIZE;
++	}
++	enable_dcplb();
++}
++
++#endif
+diff --git a/arch/blackfin/kernel/cplb-nompu/Makefile b/arch/blackfin/kernel/cplb-nompu/Makefile
+new file mode 100644
+index 0000000..d36ea9b
+--- /dev/null
++++ b/arch/blackfin/kernel/cplb-nompu/Makefile
+@@ -0,0 +1,8 @@
++#
++# arch/blackfin/kernel/cplb-nompu/Makefile
++#
++
++obj-y := cplbinit.o cacheinit.o cplbhdlr.o cplbmgr.o
++
++obj-$(CONFIG_CPLB_INFO) += cplbinfo.o
++
+diff --git a/arch/blackfin/kernel/cplb-nompu/cacheinit.c b/arch/blackfin/kernel/cplb-nompu/cacheinit.c
+new file mode 100644
+index 0000000..8a18399
+--- /dev/null
++++ b/arch/blackfin/kernel/cplb-nompu/cacheinit.c
+@@ -0,0 +1,69 @@
++/*
++ *               Copyright 2004-2007 Analog Devices 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, see the file COPYING, or write
++ * to the Free Software Foundation, Inc.,
++ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ */
++
++#include <linux/cpu.h>
++
++#include <asm/cacheflush.h>
++#include <asm/blackfin.h>
++#include <asm/cplb.h>
++#include <asm/cplbinit.h>
++
++#if defined(CONFIG_BFIN_ICACHE)
++void bfin_icache_init(void)
++{
++	unsigned long *table = icplb_table;
++	unsigned long ctrl;
++	int i;
++
++	for (i = 0; i < MAX_CPLBS; i++) {
++		unsigned long addr = *table++;
++		unsigned long data = *table++;
++		if (addr == (unsigned long)-1)
++			break;
++		bfin_write32(ICPLB_ADDR0 + i * 4, addr);
++		bfin_write32(ICPLB_DATA0 + i * 4, data);
++	}
++	ctrl = bfin_read_IMEM_CONTROL();
++	ctrl |= IMC | ENICPLB;
++	bfin_write_IMEM_CONTROL(ctrl);
++	SSYNC();
++}
++#endif
++
++#if defined(CONFIG_BFIN_DCACHE)
++void bfin_dcache_init(void)
++{
++	unsigned long *table = dcplb_table;
++	unsigned long ctrl;
++	int i;
++
++	for (i = 0; i < MAX_CPLBS; i++) {
++		unsigned long addr = *table++;
++		unsigned long data = *table++;
++		if (addr == (unsigned long)-1)
++			break;
++		bfin_write32(DCPLB_ADDR0 + i * 4, addr);
++		bfin_write32(DCPLB_DATA0 + i * 4, data);
++	}
++	ctrl = bfin_read_DMEM_CONTROL();
++	ctrl |= DMEM_CNTR;
++	bfin_write_DMEM_CONTROL(ctrl);
++	SSYNC();
++}
++#endif
+diff --git a/arch/blackfin/kernel/cplb-nompu/cplbhdlr.S b/arch/blackfin/kernel/cplb-nompu/cplbhdlr.S
+new file mode 100644
+index 0000000..2788532
+--- /dev/null
++++ b/arch/blackfin/kernel/cplb-nompu/cplbhdlr.S
+@@ -0,0 +1,130 @@
++/*
++ * File:         arch/blackfin/mach-common/cplbhdlr.S
++ * Based on:
++ * Author:       LG Soft India
++ *
++ * Created:      ?
++ * Description:  CPLB exception handler
++ *
++ * Modified:
++ *               Copyright 2004-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
++ */
++
++#include <linux/linkage.h>
++#include <asm/cplb.h>
++#include <asm/entry.h>
++
++#ifdef CONFIG_EXCPT_IRQ_SYSC_L1
++.section .l1.text
++#else
++.text
++#endif
++
++.type _cplb_mgr, STT_FUNC;
++.type _panic_cplb_error, STT_FUNC;
++
++.align 2
++
++ENTRY(__cplb_hdr)
++	R2 = SEQSTAT;
++
++	/* Mask the contents of SEQSTAT and leave only EXCAUSE in R2 */
++	R2 <<= 26;
++	R2 >>= 26;
++
++	R1 = 0x23; /* Data access CPLB protection violation */
++	CC = R2 == R1;
++	IF !CC JUMP .Lnot_data_write;
++	R0 = 2;		/* is a write to data space*/
++	JUMP .Lis_icplb_miss;
++
++.Lnot_data_write:
++	R1 = 0x2C; /* CPLB miss on an instruction fetch */
++	CC = R2 == R1;
++	R0 = 0;		/* is_data_miss == False*/
++	IF CC JUMP .Lis_icplb_miss;
++
++	R1 = 0x26;
++	CC = R2 == R1;
++	IF !CC JUMP .Lunknown;
++
++	R0 = 1;		/* is_data_miss == True*/
++
++.Lis_icplb_miss:
++
++#if defined(CONFIG_BFIN_ICACHE) || defined(CONFIG_BFIN_DCACHE)
++# if defined(CONFIG_BFIN_ICACHE) && !defined(CONFIG_BFIN_DCACHE)
++	R1 = CPLB_ENABLE_ICACHE;
++# endif
++# if !defined(CONFIG_BFIN_ICACHE) && defined(CONFIG_BFIN_DCACHE)
++	R1 = CPLB_ENABLE_DCACHE;
++# endif
++# if defined(CONFIG_BFIN_ICACHE) && defined(CONFIG_BFIN_DCACHE)
++	R1 = CPLB_ENABLE_DCACHE | CPLB_ENABLE_ICACHE;
++# endif
++#else
++	R1 = 0;
++#endif
++
++	[--SP] = RETS;
++	CALL _cplb_mgr;
++	RETS = [SP++];
++	CC = R0 == 0;
++	IF !CC JUMP .Lnot_replaced;
++	RTS;
++
++/*
++ * Diagnostic exception handlers
++ */
++.Lunknown:
++	R0 = CPLB_UNKNOWN_ERR;
++	JUMP .Lcplb_error;
++
++.Lnot_replaced:
++	CC = R0 == CPLB_NO_UNLOCKED;
++	IF !CC JUMP .Lnext_check;
++	R0 = CPLB_NO_UNLOCKED;
++	JUMP .Lcplb_error;
++
++.Lnext_check:
++	CC = R0 == CPLB_NO_ADDR_MATCH;
++	IF !CC JUMP .Lnext_check2;
++	R0 = CPLB_NO_ADDR_MATCH;
++	JUMP .Lcplb_error;
++
++.Lnext_check2:
++	CC = R0 == CPLB_PROT_VIOL;
++	IF !CC JUMP .Lstrange_return_from_cplb_mgr;
++	R0 = CPLB_PROT_VIOL;
++	JUMP .Lcplb_error;
++
++.Lstrange_return_from_cplb_mgr:
++	IDLE;
++	CSYNC;
++	JUMP .Lstrange_return_from_cplb_mgr;
++
++.Lcplb_error:
++	R1 = sp;
++	SP += -12;
++	call _panic_cplb_error;
++	SP += 12;
++	JUMP _handle_bad_cplb;
++
++ENDPROC(__cplb_hdr)
+diff --git a/arch/blackfin/kernel/cplb-nompu/cplbinfo.c b/arch/blackfin/kernel/cplb-nompu/cplbinfo.c
+new file mode 100644
+index 0000000..a4f0b42
+--- /dev/null
++++ b/arch/blackfin/kernel/cplb-nompu/cplbinfo.c
+@@ -0,0 +1,208 @@
++/*
++ * File:         arch/blackfin/mach-common/cplbinfo.c
++ * Based on:
++ * Author:       Sonic Zhang <sonic.zhang at analog.com>
++ *
++ * Created:      Jan. 2005
++ * Description:  Display CPLB status
++ *
++ * Modified:
++ *               Copyright 2004-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
++ */
++
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/proc_fs.h>
++#include <linux/uaccess.h>
++
++#include <asm/current.h>
++#include <asm/system.h>
++#include <asm/cplb.h>
++#include <asm/blackfin.h>
++
++#define CPLB_I 1
++#define CPLB_D 2
++
++#define SYNC_SYS    SSYNC()
++#define SYNC_CORE   CSYNC()
++
++#define CPLB_BIT_PAGESIZE 0x30000
++
++static int page_size_table[4] = {
++	0x00000400,		/* 1K */
++	0x00001000,		/* 4K */
++	0x00100000,		/* 1M */
++	0x00400000		/* 4M */
++};
++
++static char page_size_string_table[][4] = { "1K", "4K", "1M", "4M" };
++
++static int cplb_find_entry(unsigned long *cplb_addr,
++			   unsigned long *cplb_data, unsigned long addr,
++			   unsigned long data)
++{
++	int ii;
++
++	for (ii = 0; ii < 16; ii++)
++		if (addr >= cplb_addr[ii] && addr < cplb_addr[ii] +
++		    page_size_table[(cplb_data[ii] & CPLB_BIT_PAGESIZE) >> 16]
++			&& (cplb_data[ii] == data))
++			return ii;
++
++	return -1;
++}
++
++static char *cplb_print_entry(char *buf, int type)
++{
++	unsigned long *p_addr = dpdt_table;
++	unsigned long *p_data = dpdt_table + 1;
++	unsigned long *p_icount = dpdt_swapcount_table;
++	unsigned long *p_ocount = dpdt_swapcount_table + 1;
++	unsigned long *cplb_addr = (unsigned long *)DCPLB_ADDR0;
++	unsigned long *cplb_data = (unsigned long *)DCPLB_DATA0;
++	int entry = 0, used_cplb = 0;
++
++	if (type == CPLB_I) {
++		buf += sprintf(buf, "Instruction CPLB entry:\n");
++		p_addr = ipdt_table;
++		p_data = ipdt_table + 1;
++		p_icount = ipdt_swapcount_table;
++		p_ocount = ipdt_swapcount_table + 1;
++		cplb_addr = (unsigned long *)ICPLB_ADDR0;
++		cplb_data = (unsigned long *)ICPLB_DATA0;
++	} else
++		buf += sprintf(buf, "Data CPLB entry:\n");
++
++	buf += sprintf(buf, "Address\t\tData\tSize\tValid\tLocked\tSwapin\tiCount\toCount\n");
++
++	while (*p_addr != 0xffffffff) {
++		entry = cplb_find_entry(cplb_addr, cplb_data, *p_addr, *p_data);
++		if (entry >= 0)
++			used_cplb |= 1 << entry;
++
++		buf +=
++		    sprintf(buf,
++			    "0x%08lx\t0x%05lx\t%s\t%c\t%c\t%2d\t%ld\t%ld\n",
++			    *p_addr, *p_data,
++			    page_size_string_table[(*p_data & 0x30000) >> 16],
++			    (*p_data & CPLB_VALID) ? 'Y' : 'N',
++			    (*p_data & CPLB_LOCK) ? 'Y' : 'N', entry, *p_icount,
++			    *p_ocount);
++
++		p_addr += 2;
++		p_data += 2;
++		p_icount += 2;
++		p_ocount += 2;
++	}
++
++	if (used_cplb != 0xffff) {
++		buf += sprintf(buf, "Unused/mismatched CPLBs:\n");
++
++		for (entry = 0; entry < 16; entry++)
++			if (0 == ((1 << entry) & used_cplb)) {
++				int flags = cplb_data[entry];
++				buf +=
++				    sprintf(buf,
++					    "%2d: 0x%08lx\t0x%05x\t%s\t%c\t%c\n",
++					    entry, cplb_addr[entry], flags,
++					    page_size_string_table[(flags &
++								    0x30000) >>
++								   16],
++					    (flags & CPLB_VALID) ? 'Y' : 'N',
++					    (flags & CPLB_LOCK) ? 'Y' : 'N');
++			}
++	}
++
++	buf += sprintf(buf, "\n");
++
++	return buf;
++}
++
++static int cplbinfo_proc_output(char *buf)
++{
++	char *p;
++
++	p = buf;
++
++	p += sprintf(p, "------------------ CPLB Information ------------------\n\n");
++
++	if (bfin_read_IMEM_CONTROL() & ENICPLB)
++		p = cplb_print_entry(p, CPLB_I);
++	else
++		p += sprintf(p, "Instruction CPLB is disabled.\n\n");
++
++	if (bfin_read_DMEM_CONTROL() & ENDCPLB)
++		p = cplb_print_entry(p, CPLB_D);
++	else
++		p += sprintf(p, "Data CPLB is disabled.\n");
++
++	return p - buf;
++}
++
++static int cplbinfo_read_proc(char *page, char **start, off_t off,
++			      int count, int *eof, void *data)
++{
++	int len;
++
++	len = cplbinfo_proc_output(page);
++	if (len <= off + count)
++		*eof = 1;
++	*start = page + off;
++	len -= off;
++	if (len > count)
++		len = count;
++	if (len < 0)
++		len = 0;
++	return len;
++}
++
++static int cplbinfo_write_proc(struct file *file, const char __user *buffer,
++			       unsigned long count, void *data)
++{
++	printk(KERN_INFO "Reset the CPLB swap in/out counts.\n");
++	memset(ipdt_swapcount_table, 0, MAX_SWITCH_I_CPLBS * sizeof(unsigned long));
++	memset(dpdt_swapcount_table, 0, MAX_SWITCH_D_CPLBS * sizeof(unsigned long));
++
++	return count;
++}
++
++static int __init cplbinfo_init(void)
++{
++	struct proc_dir_entry *entry;
++
++	entry = create_proc_entry("cplbinfo", 0, NULL);
++	if (!entry)
++		return -ENOMEM;
++
++	entry->read_proc = cplbinfo_read_proc;
++	entry->write_proc = cplbinfo_write_proc;
++	entry->data = NULL;
++
++	return 0;
++}
++
++static void __exit cplbinfo_exit(void)
++{
++	remove_proc_entry("cplbinfo", NULL);
++}
++
++module_init(cplbinfo_init);
++module_exit(cplbinfo_exit);
+diff --git a/arch/blackfin/kernel/cplb-nompu/cplbinit.c b/arch/blackfin/kernel/cplb-nompu/cplbinit.c
+new file mode 100644
+index 0000000..6320bc4
+--- /dev/null
++++ b/arch/blackfin/kernel/cplb-nompu/cplbinit.c
+@@ -0,0 +1,437 @@
++/*
++ * Blackfin CPLB initialization
++ *
++ *               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 <asm/blackfin.h>
++#include <asm/cplb.h>
++#include <asm/cplbinit.h>
++
++u_long icplb_table[MAX_CPLBS + 1];
++u_long dcplb_table[MAX_CPLBS + 1];
++
++#ifdef CONFIG_CPLB_SWITCH_TAB_L1
++# define PDT_ATTR __attribute__((l1_data))
++#else
++# define PDT_ATTR
++#endif
++
++u_long ipdt_table[MAX_SWITCH_I_CPLBS + 1] PDT_ATTR;
++u_long dpdt_table[MAX_SWITCH_D_CPLBS + 1] PDT_ATTR;
++
++#ifdef CONFIG_CPLB_INFO
++u_long ipdt_swapcount_table[MAX_SWITCH_I_CPLBS] PDT_ATTR;
++u_long dpdt_swapcount_table[MAX_SWITCH_D_CPLBS] PDT_ATTR;
++#endif
++
++struct s_cplb {
++	struct cplb_tab init_i;
++	struct cplb_tab init_d;
++	struct cplb_tab switch_i;
++	struct cplb_tab switch_d;
++};
++
++#if defined(CONFIG_BFIN_DCACHE) || defined(CONFIG_BFIN_ICACHE)
++static struct cplb_desc cplb_data[] = {
++	{
++		.start = 0,
++		.end = SIZE_1K,
++		.psize = SIZE_1K,
++		.attr = INITIAL_T | SWITCH_T | I_CPLB | D_CPLB,
++		.i_conf = SDRAM_OOPS,
++		.d_conf = SDRAM_OOPS,
++#if defined(CONFIG_DEBUG_HUNT_FOR_ZERO)
++		.valid = 1,
++#else
++		.valid = 0,
++#endif
++		.name = "Zero Pointer Guard Page",
++	},
++	{
++		.start = L1_CODE_START,
++		.end = L1_CODE_START + L1_CODE_LENGTH,
++		.psize = SIZE_4M,
++		.attr = INITIAL_T | SWITCH_T | I_CPLB,
++		.i_conf = L1_IMEMORY,
++		.d_conf = 0,
++		.valid = 1,
++		.name = "L1 I-Memory",
++	},
++	{
++		.start = L1_DATA_A_START,
++		.end = L1_DATA_B_START + L1_DATA_B_LENGTH,
++		.psize = SIZE_4M,
++		.attr = INITIAL_T | SWITCH_T | D_CPLB,
++		.i_conf = 0,
++		.d_conf = L1_DMEMORY,
++#if ((L1_DATA_A_LENGTH > 0) || (L1_DATA_B_LENGTH > 0))
++		.valid = 1,
++#else
++		.valid = 0,
++#endif
++		.name = "L1 D-Memory",
++	},
++	{
++		.start = 0,
++		.end = 0,  /* dynamic */
++		.psize = 0,
++		.attr = INITIAL_T | SWITCH_T | I_CPLB | D_CPLB,
++		.i_conf = SDRAM_IGENERIC,
++		.d_conf = SDRAM_DGENERIC,
++		.valid = 1,
++		.name = "Kernel Memory",
++	},
++	{
++		.start = 0, /* dynamic */
++		.end = 0, /* dynamic */
++		.psize = 0,
++		.attr = INITIAL_T | SWITCH_T | D_CPLB,
++		.i_conf = SDRAM_IGENERIC,
++		.d_conf = SDRAM_DNON_CHBL,
++		.valid = 1,
++		.name = "uClinux MTD Memory",
++	},
++	{
++		.start = 0, /* dynamic */
++		.end = 0,   /* dynamic */
++		.psize = SIZE_1M,
++		.attr = INITIAL_T | SWITCH_T | D_CPLB,
++		.d_conf = SDRAM_DNON_CHBL,
++		.valid = 1,
++		.name = "Uncached DMA Zone",
++	},
++	{
++		.start = 0, /* dynamic */
++		.end = 0, /* dynamic */
++		.psize = 0,
++		.attr = SWITCH_T | D_CPLB,
++		.i_conf = 0, /* dynamic */
++		.d_conf = 0, /* dynamic */
++		.valid = 1,
++		.name = "Reserved Memory",
++	},
++	{
++		.start = ASYNC_BANK0_BASE,
++		.end = ASYNC_BANK3_BASE + ASYNC_BANK3_SIZE,
++		.psize = 0,
++		.attr = SWITCH_T | D_CPLB,
++		.d_conf = SDRAM_EBIU,
++		.valid = 1,
++		.name = "Asynchronous Memory Banks",
++	},
++	{
++#ifdef L2_START
++		.start = L2_START,
++		.end = L2_START + L2_LENGTH,
++		.psize = SIZE_1M,
++		.attr = SWITCH_T | I_CPLB | D_CPLB,
++		.i_conf = L2_MEMORY,
++		.d_conf = L2_MEMORY,
++		.valid = 1,
++#else
++		.valid = 0,
++#endif
++		.name = "L2 Memory",
++	},
++	{
++		.start = BOOT_ROM_START,
++		.end = BOOT_ROM_START + BOOT_ROM_LENGTH,
++		.psize = SIZE_1M,
++		.attr = SWITCH_T | I_CPLB | D_CPLB,
++		.i_conf = SDRAM_IGENERIC,
++		.d_conf = SDRAM_DGENERIC,
++		.valid = 1,
++		.name = "On-Chip BootROM",
++	},
++};
++
++static u16 __init lock_kernel_check(u32 start, u32 end)
++{
++	if ((end   <= (u32) _end && end   >= (u32)_stext) ||
++	    (start <= (u32) _end && start >= (u32)_stext))
++		return IN_KERNEL;
++	return 0;
++}
++
++static unsigned short __init
++fill_cplbtab(struct cplb_tab *table,
++	     unsigned long start, unsigned long end,
++	     unsigned long block_size, unsigned long cplb_data)
++{
++	int i;
++
++	switch (block_size) {
++	case SIZE_4M:
++		i = 3;
++		break;
++	case SIZE_1M:
++		i = 2;
++		break;
++	case SIZE_4K:
++		i = 1;
++		break;
++	case SIZE_1K:
++	default:
++		i = 0;
++		break;
++	}
++
++	cplb_data = (cplb_data & ~(3 << 16)) | (i << 16);
++
++	while ((start < end) && (table->pos < table->size)) {
++
++		table->tab[table->pos++] = start;
++
++		if (lock_kernel_check(start, start + block_size) == IN_KERNEL)
++			table->tab[table->pos++] =
++			    cplb_data | CPLB_LOCK | CPLB_DIRTY;
++		else
++			table->tab[table->pos++] = cplb_data;
++
++		start += block_size;
++	}
++	return 0;
++}
++
++static unsigned short __init
++close_cplbtab(struct cplb_tab *table)
++{
++
++	while (table->pos < table->size) {
++
++		table->tab[table->pos++] = 0;
++		table->tab[table->pos++] = 0; /* !CPLB_VALID */
++	}
++	return 0;
++}
++
++/* helper function */
++static void __fill_code_cplbtab(struct cplb_tab *t, int i, u32 a_start, u32 a_end)
++{
++	if (cplb_data[i].psize) {
++		fill_cplbtab(t,
++				cplb_data[i].start,
++				cplb_data[i].end,
++				cplb_data[i].psize,
++				cplb_data[i].i_conf);
++	} else {
++#if defined(CONFIG_BFIN_ICACHE)
++		if (ANOMALY_05000263 && i == SDRAM_KERN) {
++			fill_cplbtab(t,
++					cplb_data[i].start,
++					cplb_data[i].end,
++					SIZE_4M,
++					cplb_data[i].i_conf);
++		} else
++#endif
++		{
++			fill_cplbtab(t,
++					cplb_data[i].start,
++					a_start,
++					SIZE_1M,
++					cplb_data[i].i_conf);
++			fill_cplbtab(t,
++					a_start,
++					a_end,
++					SIZE_4M,
++					cplb_data[i].i_conf);
++			fill_cplbtab(t, a_end,
++					cplb_data[i].end,
++					SIZE_1M,
++					cplb_data[i].i_conf);
++		}
++	}
++}
++
++static void __fill_data_cplbtab(struct cplb_tab *t, int i, u32 a_start, u32 a_end)
++{
++	if (cplb_data[i].psize) {
++		fill_cplbtab(t,
++				cplb_data[i].start,
++				cplb_data[i].end,
++				cplb_data[i].psize,
++				cplb_data[i].d_conf);
++	} else {
++		fill_cplbtab(t,
++				cplb_data[i].start,
++				a_start, SIZE_1M,
++				cplb_data[i].d_conf);
++		fill_cplbtab(t, a_start,
++				a_end, SIZE_4M,
++				cplb_data[i].d_conf);
++		fill_cplbtab(t, a_end,
++				cplb_data[i].end,
++				SIZE_1M,
++				cplb_data[i].d_conf);
++	}
++}
++
++void __init generate_cpl_tables(void)
++{
++
++	u16 i, j, process;
++	u32 a_start, a_end, as, ae, as_1m;
++
++	struct cplb_tab *t_i = NULL;
++	struct cplb_tab *t_d = NULL;
++	struct s_cplb cplb;
++
++	cplb.init_i.size = MAX_CPLBS;
++	cplb.init_d.size = MAX_CPLBS;
++	cplb.switch_i.size = MAX_SWITCH_I_CPLBS;
++	cplb.switch_d.size = MAX_SWITCH_D_CPLBS;
++
++	cplb.init_i.pos = 0;
++	cplb.init_d.pos = 0;
++	cplb.switch_i.pos = 0;
++	cplb.switch_d.pos = 0;
++
++	cplb.init_i.tab = icplb_table;
++	cplb.init_d.tab = dcplb_table;
++	cplb.switch_i.tab = ipdt_table;
++	cplb.switch_d.tab = dpdt_table;
++
++	cplb_data[SDRAM_KERN].end = memory_end;
++
++#ifdef CONFIG_MTD_UCLINUX
++	cplb_data[SDRAM_RAM_MTD].start = memory_mtd_start;
++	cplb_data[SDRAM_RAM_MTD].end = memory_mtd_start + mtd_size;
++	cplb_data[SDRAM_RAM_MTD].valid = mtd_size > 0;
++# if defined(CONFIG_ROMFS_FS)
++	cplb_data[SDRAM_RAM_MTD].attr |= I_CPLB;
++
++	/*
++	 * The ROMFS_FS size is often not multiple of 1MB.
++	 * This can cause multiple CPLB sets covering the same memory area.
++	 * This will then cause multiple CPLB hit exceptions.
++	 * Workaround: We ensure a contiguous memory area by extending the kernel
++	 * memory section over the mtd section.
++	 * For ROMFS_FS memory must be covered with ICPLBs anyways.
++	 * So there is no difference between kernel and mtd memory setup.
++	 */
++
++	cplb_data[SDRAM_KERN].end = memory_mtd_start + mtd_size;;
++	cplb_data[SDRAM_RAM_MTD].valid = 0;
++
++# endif
++#else
++	cplb_data[SDRAM_RAM_MTD].valid = 0;
++#endif
++
++	cplb_data[SDRAM_DMAZ].start = _ramend - DMA_UNCACHED_REGION;
++	cplb_data[SDRAM_DMAZ].end = _ramend;
++
++	cplb_data[RES_MEM].start = _ramend;
++	cplb_data[RES_MEM].end = physical_mem_end;
++
++	if (reserved_mem_dcache_on)
++		cplb_data[RES_MEM].d_conf = SDRAM_DGENERIC;
++	else
++		cplb_data[RES_MEM].d_conf = SDRAM_DNON_CHBL;
++
++	if (reserved_mem_icache_on)
++		cplb_data[RES_MEM].i_conf = SDRAM_IGENERIC;
++	else
++		cplb_data[RES_MEM].i_conf = SDRAM_INON_CHBL;
++
++	for (i = ZERO_P; i < ARRAY_SIZE(cplb_data); ++i) {
++		if (!cplb_data[i].valid)
++			continue;
++
++		as_1m = cplb_data[i].start % SIZE_1M;
++
++		/* We need to make sure all sections are properly 1M aligned
++		 * However between Kernel Memory and the Kernel mtd section, depending on the
++		 * rootfs size, there can be overlapping memory areas.
++		 */
++
++		if (as_1m && i != L1I_MEM && i != L1D_MEM) {
++#ifdef CONFIG_MTD_UCLINUX
++			if (i == SDRAM_RAM_MTD) {
++				if ((cplb_data[SDRAM_KERN].end + 1) > cplb_data[SDRAM_RAM_MTD].start)
++					cplb_data[SDRAM_RAM_MTD].start = (cplb_data[i].start & (-2*SIZE_1M)) + SIZE_1M;
++				else
++					cplb_data[SDRAM_RAM_MTD].start = (cplb_data[i].start & (-2*SIZE_1M));
++			} else
++#endif
++				printk(KERN_WARNING "Unaligned Start of %s at 0x%X\n",
++				       cplb_data[i].name, cplb_data[i].start);
++		}
++
++		as = cplb_data[i].start % SIZE_4M;
++		ae = cplb_data[i].end % SIZE_4M;
++
++		if (as)
++			a_start = cplb_data[i].start + (SIZE_4M - (as));
++		else
++			a_start = cplb_data[i].start;
++
++		a_end = cplb_data[i].end - ae;
++
++		for (j = INITIAL_T; j <= SWITCH_T; j++) {
++
++			switch (j) {
++			case INITIAL_T:
++				if (cplb_data[i].attr & INITIAL_T) {
++					t_i = &cplb.init_i;
++					t_d = &cplb.init_d;
++					process = 1;
++				} else
++					process = 0;
++				break;
++			case SWITCH_T:
++				if (cplb_data[i].attr & SWITCH_T) {
++					t_i = &cplb.switch_i;
++					t_d = &cplb.switch_d;
++					process = 1;
++				} else
++					process = 0;
++				break;
++			default:
++					process = 0;
++				break;
++			}
++
++			if (!process)
++				continue;
++			if (cplb_data[i].attr & I_CPLB)
++				__fill_code_cplbtab(t_i, i, a_start, a_end);
++
++			if (cplb_data[i].attr & D_CPLB)
++				__fill_data_cplbtab(t_d, i, a_start, a_end);
++		}
++	}
++
++/* close tables */
++
++	close_cplbtab(&cplb.init_i);
++	close_cplbtab(&cplb.init_d);
++
++	cplb.init_i.tab[cplb.init_i.pos] = -1;
++	cplb.init_d.tab[cplb.init_d.pos] = -1;
++	cplb.switch_i.tab[cplb.switch_i.pos] = -1;
++	cplb.switch_d.tab[cplb.switch_d.pos] = -1;
++
++}
++
++#endif
++
+diff --git a/arch/blackfin/kernel/cplb-nompu/cplbmgr.S b/arch/blackfin/kernel/cplb-nompu/cplbmgr.S
+new file mode 100644
+index 0000000..f5cf3ac
+--- /dev/null
++++ b/arch/blackfin/kernel/cplb-nompu/cplbmgr.S
+@@ -0,0 +1,646 @@
++/*
++ * File:         arch/blackfin/mach-common/cplbmgtr.S
++ * Based on:
++ * Author:       LG Soft India
++ *
++ * Created:      ?
++ * Description:  CPLB replacement routine for CPLB mismatch
++ *
++ * Modified:
++ *               Copyright 2004-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
++ */
++
++/* Usage: int _cplb_mgr(is_data_miss,int enable_cache)
++ * is_data_miss==2 => Mark as Dirty, write to the clean data page
++ * is_data_miss==1 => Replace a data CPLB.
++ * is_data_miss==0 => Replace an instruction CPLB.
++ *
++ * Returns:
++ * CPLB_RELOADED	=> Successfully updated CPLB table.
++ * CPLB_NO_UNLOCKED	=> All CPLBs are locked, so cannot be evicted.
++ *			   This indicates that the CPLBs in the configuration
++ *			   tablei are badly configured, as this should never
++ *			   occur.
++ * CPLB_NO_ADDR_MATCH	=> The address being accessed, that triggered the
++ *			   exception, is not covered by any of the CPLBs in
++ *			   the configuration table. The application is
++ *			   presumably misbehaving.
++ * CPLB_PROT_VIOL	=> The address being accessed, that triggered the
++ *			   exception, was not a first-write to a clean Write
++ *			   Back Data page, and so presumably is a genuine
++ *			   violation of the page's protection attributes.
++ *			   The application is misbehaving.
++ */
++
++#include <linux/linkage.h>
++#include <asm/blackfin.h>
++#include <asm/cplb.h>
++
++#ifdef CONFIG_EXCPT_IRQ_SYSC_L1
++.section .l1.text
++#else
++.text
++#endif
++
++.align 2;
++ENTRY(_cplb_mgr)
++
++	[--SP]=( R7:4,P5:3 );
++
++	CC = R0 == 2;
++	IF CC JUMP .Ldcplb_write;
++
++	CC = R0 == 0;
++	IF !CC JUMP .Ldcplb_miss_compare;
++
++	/* ICPLB Miss Exception. We need to choose one of the
++	* currently-installed CPLBs, and replace it with one
++	* from the configuration table.
++	*/
++
++	/* A multi-word instruction can cross a page boundary. This means the
++	 * first part of the instruction can be in a valid page, but the
++	 * second part is not, and hence generates the instruction miss.
++	 * However, the fault address is for the start of the instruction,
++	 * not the part that's in the bad page. Therefore, we have to check
++	 * whether the fault address applies to a page that is already present
++	 * in the table.
++	 */
++
++	P4.L = LO(ICPLB_FAULT_ADDR);
++	P4.H = HI(ICPLB_FAULT_ADDR);
++
++	P1 = 16;
++	P5.L = _page_size_table;
++	P5.H = _page_size_table;
++
++	P0.L = LO(ICPLB_DATA0);
++	P0.H = HI(ICPLB_DATA0);
++	R4 = [P4];		/* Get faulting address*/
++	R6 = 64;		/* Advance past the fault address, which*/
++	R6 = R6 + R4;		/* we'll use if we find a match*/
++	R3 = ((16 << 8) | 2);	/* Extract mask, two bits at posn 16 */
++
++	R5 = 0;
++.Lisearch:
++
++	R1 = [P0-0x100];	/* Address for this CPLB */
++
++	R0 = [P0++];		/* Info for this CPLB*/
++	CC = BITTST(R0,0);	/* Is the CPLB valid?*/
++	IF !CC JUMP .Lnomatch;	/* Skip it, if not.*/
++	CC = R4 < R1(IU);	/* If fault address less than page start*/
++	IF CC JUMP .Lnomatch;	/* then skip this one.*/
++	R2 = EXTRACT(R0,R3.L) (Z);	/* Get page size*/
++	P1 = R2;
++	P1 = P5 + (P1<<2);	/* index into page-size table*/
++	R2 = [P1];		/* Get the page size*/
++	R1 = R1 + R2;		/* and add to page start, to get page end*/
++	CC = R4 < R1(IU);	/* and see whether fault addr is in page.*/
++	IF !CC R4 = R6;		/* If so, advance the address and finish loop.*/
++	IF !CC JUMP .Lisearch_done;
++.Lnomatch:
++	/* Go around again*/
++	R5 += 1;
++	CC = BITTST(R5, 4);	/* i.e CC = R5 >= 16*/
++	IF !CC JUMP .Lisearch;
++
++.Lisearch_done:
++	I0 = R4;		/* Fault address we'll search for*/
++
++	/* set up pointers */
++	P0.L = LO(ICPLB_DATA0);
++	P0.H = HI(ICPLB_DATA0);
++
++	/* The replacement procedure for ICPLBs */
++
++	P4.L = LO(IMEM_CONTROL);
++	P4.H = HI(IMEM_CONTROL);
++
++	/* Turn off CPLBs while we work, necessary according to HRM before
++	 * modifying CPLB descriptors
++	 */
++	R5 = [P4];		/* Control Register*/
++	BITCLR(R5,ENICPLB_P);
++	CLI R1;
++	SSYNC;		/* SSYNC required before writing to IMEM_CONTROL. */
++	.align 8;
++	[P4] = R5;
++	SSYNC;
++	STI R1;
++
++	R1 = -1;		/* end point comparison */
++	R3 = 16;		/* counter */
++
++	/* Search through CPLBs for first non-locked entry */
++	/* Overwrite it by moving everyone else up by 1 */
++.Licheck_lock:
++	R0 = [P0++];
++	R3 = R3 + R1;
++	CC = R3 == R1;
++	IF CC JUMP .Lall_locked;
++	CC = BITTST(R0, 0);		/* an invalid entry is good */
++	IF !CC JUMP .Lifound_victim;
++	CC = BITTST(R0,1);		/* but a locked entry isn't */
++	IF CC JUMP .Licheck_lock;
++
++.Lifound_victim:
++#ifdef CONFIG_CPLB_INFO
++	R7 = [P0 - 0x104];
++	P2.L = _ipdt_table;
++	P2.H = _ipdt_table;
++	P3.L = _ipdt_swapcount_table;
++	P3.H = _ipdt_swapcount_table;
++	P3 += -4;
++.Licount:
++	R2 = [P2];	/* address from config table */
++	P2 += 8;
++	P3 += 8;
++	CC = R2==-1;
++	IF CC JUMP .Licount_done;
++	CC = R7==R2;
++	IF !CC JUMP .Licount;
++	R7 = [P3];
++	R7 += 1;
++	[P3] = R7;
++	CSYNC;
++.Licount_done:
++#endif
++	LC0=R3;
++	LSETUP(.Lis_move,.Lie_move) LC0;
++.Lis_move:
++	R0 = [P0];
++	[P0 - 4] = R0;
++	R0 = [P0 - 0x100];
++	[P0-0x104] = R0;
++.Lie_move:
++	P0+=4;
++
++	/* Clear ICPLB_DATA15, in case we don't find a replacement
++	 * otherwise, we would have a duplicate entry, and will crash
++	 */
++	R0 = 0;
++	[P0 - 4] = R0;
++
++	/* We've made space in the ICPLB table, so that ICPLB15
++	 * is now free to be overwritten. Next, we have to determine
++	 * which CPLB we need to install, from the configuration
++	 * table. This is a matter of getting the start-of-page
++	 * addresses and page-lengths from the config table, and
++	 * determining whether the fault address falls within that
++	 * range.
++ 	 */
++
++	P2.L = _ipdt_table;
++	P2.H = _ipdt_table;
++#ifdef	CONFIG_CPLB_INFO
++	P3.L = _ipdt_swapcount_table;
++	P3.H = _ipdt_swapcount_table;
++	P3 += -8;
++#endif
++	P0.L = _page_size_table;
++	P0.H = _page_size_table;
++
++	/* Retrieve our fault address (which may have been advanced
++	 * because the faulting instruction crossed a page boundary).
++	 */
++
++	R0 = I0;
++
++	/* An extraction pattern, to get the page-size bits from
++	 * the CPLB data entry. Bits 16-17, so two bits at posn 16.
++	 */
++
++	R1 = ((16<<8)|2);
++.Linext:	R4 = [P2++];	/* address from config table */
++	R2 = [P2++];	/* data from config table */
++#ifdef	CONFIG_CPLB_INFO
++	P3 += 8;
++#endif
++
++	CC = R4 == -1;	/* End of config table*/
++	IF CC JUMP .Lno_page_in_table;
++
++	/* See if failed address > start address */
++	CC = R4 <= R0(IU);
++	IF !CC JUMP .Linext;
++
++	/* extract page size (17:16)*/
++	R3 = EXTRACT(R2, R1.L) (Z);
++
++	/* add page size to addr to get range */
++
++	P5 = R3;
++	P5 = P0 + (P5 << 2);	/* scaled, for int access*/
++	R3 = [P5];
++	R3 = R3 + R4;
++
++	/* See if failed address < (start address + page size) */
++	CC = R0 < R3(IU);
++	IF !CC JUMP .Linext;
++
++	/* We've found a CPLB in the config table that covers
++	 * the faulting address, so install this CPLB into the
++	 * last entry of the table.
++	 */
++
++	P1.L = LO(ICPLB_DATA15);		/* ICPLB_DATA15 */
++	P1.H = HI(ICPLB_DATA15);
++	[P1] = R2;
++	[P1-0x100] = R4;
++#ifdef	CONFIG_CPLB_INFO
++	R3 = [P3];
++	R3 += 1;
++	[P3] = R3;
++#endif
++
++	/* P4 points to IMEM_CONTROL, and R5 contains its old
++	 * value, after we disabled ICPLBS. Re-enable them.
++	 */
++
++	BITSET(R5,ENICPLB_P);
++	CLI R2;
++	SSYNC;		/* SSYNC required before writing to IMEM_CONTROL. */
++	.align 8;
++	[P4] = R5;
++	SSYNC;
++	STI R2;
++
++	( R7:4,P5:3 ) = [SP++];
++	R0 = CPLB_RELOADED;
++	RTS;
++
++/* FAILED CASES*/
++.Lno_page_in_table:
++	R0 = CPLB_NO_ADDR_MATCH;
++	JUMP .Lfail_ret;
++
++.Lall_locked:
++	R0 = CPLB_NO_UNLOCKED;
++	JUMP .Lfail_ret;
++
++.Lprot_violation:
++	R0 = CPLB_PROT_VIOL;
++
++.Lfail_ret:
++	/* Make sure we turn protection/cache back on, even in the failing case */
++	BITSET(R5,ENICPLB_P);
++	CLI R2;
++	SSYNC;          /* SSYNC required before writing to IMEM_CONTROL. */
++	.align 8;
++	[P4] = R5;
++	SSYNC;
++	STI R2;
++
++	( R7:4,P5:3 ) = [SP++];
++	RTS;
++
++.Ldcplb_write:
++
++	/* if a DCPLB is marked as write-back (CPLB_WT==0), and
++	 * it is clean (CPLB_DIRTY==0), then a write to the
++	 * CPLB's page triggers a protection violation. We have to
++	 * mark the CPLB as dirty, to indicate that there are
++	 * pending writes associated with the CPLB.
++	 */
++
++	P4.L = LO(DCPLB_STATUS);
++	P4.H = HI(DCPLB_STATUS);
++	P3.L = LO(DCPLB_DATA0);
++	P3.H = HI(DCPLB_DATA0);
++	R5 = [P4];
++
++	/* A protection violation can be caused by more than just writes
++	 * to a clean WB page, so we have to ensure that:
++	 * - It's a write
++	 * - to a clean WB page
++	 * - and is allowed in the mode the access occurred.
++	 */
++
++	CC = BITTST(R5, 16);	/* ensure it was a write*/
++	IF !CC JUMP .Lprot_violation;
++
++	/* to check the rest, we have to retrieve the DCPLB.*/
++
++	/* The low half of DCPLB_STATUS is a bit mask*/
++
++	R2 = R5.L (Z);	/* indicating which CPLB triggered the event.*/
++	R3 = 30;	/* so we can use this to determine the offset*/
++	R2.L = SIGNBITS R2;
++	R2 = R2.L (Z);	/* into the DCPLB table.*/
++	R3 = R3 - R2;
++	P4 = R3;
++	P3 = P3 + (P4<<2);
++	R3 = [P3];	/* Retrieve the CPLB*/
++
++	/* Now we can check whether it's a clean WB page*/
++
++	CC = BITTST(R3, 14);	/* 0==WB, 1==WT*/
++	IF CC JUMP .Lprot_violation;
++	CC = BITTST(R3, 7);	/* 0 == clean, 1 == dirty*/
++	IF CC JUMP .Lprot_violation;
++
++	/* Check whether the write is allowed in the mode that was active.*/
++
++	R2 = 1<<3;		/* checking write in user mode*/
++	CC = BITTST(R5, 17);	/* 0==was user, 1==was super*/
++	R5 = CC;
++	R2 <<= R5;		/* if was super, check write in super mode*/
++	R2 = R3 & R2;
++	CC = R2 == 0;
++	IF CC JUMP .Lprot_violation;
++
++	/* It's a genuine write-to-clean-page.*/
++
++	BITSET(R3, 7);		/* mark as dirty*/
++	[P3] = R3;		/* and write back.*/
++	NOP;
++	CSYNC;
++	( R7:4,P5:3 ) = [SP++];
++	R0 = CPLB_RELOADED;
++	RTS;
++
++.Ldcplb_miss_compare:
++
++	/* Data CPLB Miss event. We need to choose a CPLB to
++	 * evict, and then locate a new CPLB to install from the
++	 * config table, that covers the faulting address.
++	 */
++
++	P1.L = LO(DCPLB_DATA15);
++	P1.H = HI(DCPLB_DATA15);
++
++	P4.L = LO(DCPLB_FAULT_ADDR);
++	P4.H = HI(DCPLB_FAULT_ADDR);
++	R4 = [P4];
++	I0 = R4;
++
++	/* The replacement procedure for DCPLBs*/
++
++	R6 = R1;	/* Save for later*/
++
++	/* Turn off CPLBs while we work.*/
++	P4.L = LO(DMEM_CONTROL);
++	P4.H = HI(DMEM_CONTROL);
++	R5 = [P4];
++	BITCLR(R5,ENDCPLB_P);
++	CLI R0;
++	SSYNC;		/* SSYNC required before writing to DMEM_CONTROL. */
++	.align 8;
++	[P4] = R5;
++	SSYNC;
++	STI R0;
++
++	/* Start looking for a CPLB to evict. Our order of preference
++	 * is: invalid CPLBs, clean CPLBs, dirty CPLBs. Locked CPLBs
++	 * are no good.
++	 */
++
++	I1.L = LO(DCPLB_DATA0);
++	I1.H = HI(DCPLB_DATA0);
++	P1 = 2;
++	P2 = 16;
++	I2.L = _dcplb_preference;
++	I2.H = _dcplb_preference;
++	LSETUP(.Lsdsearch1, .Ledsearch1) LC0 = P1;
++.Lsdsearch1:
++	R0 = [I2++];		/* Get the bits we're interested in*/
++	P0 = I1;		/* Go back to start of table*/
++	LSETUP (.Lsdsearch2, .Ledsearch2) LC1 = P2;
++.Lsdsearch2:
++	R1 = [P0++];		/* Fetch each installed CPLB in turn*/
++	R2 = R1 & R0;		/* and test for interesting bits.*/
++	CC = R2 == 0;		/* If none are set, it'll do.*/
++	IF !CC JUMP .Lskip_stack_check;
++
++	R2 = [P0 - 0x104]; 	/* R2 - PageStart */
++	P3.L = _page_size_table; /* retrieve end address */
++	P3.H = _page_size_table; /* retrieve end address */
++	R3 = 0x1002;		/* 16th - position, 2 bits -length */
++#if ANOMALY_05000209
++	nop;			/* Anomaly 05000209 */
++#endif
++	R7 = EXTRACT(R1,R3.l);
++	R7 = R7 << 2;		/* Page size index offset */
++	P5 = R7;
++	P3 = P3 + P5;
++	R7 = [P3];		/* page size in bytes */
++
++	R7 = R2 + R7;		/* R7 - PageEnd */
++	R4 = SP; 		/* Test SP is in range */
++
++	CC = R7 < R4;		/* if PageEnd < SP */
++	IF CC JUMP .Ldfound_victim;
++	R3 = 0x284;		/* stack length from start of trap till
++				 * the point.
++				 * 20 stack locations for future modifications
++				 */
++	R4 = R4 + R3;
++	CC = R4 < R2;		/* if SP + stacklen < PageStart */
++	IF CC JUMP .Ldfound_victim;
++.Lskip_stack_check:
++
++.Ledsearch2: NOP;
++.Ledsearch1: NOP;
++
++	/* If we got here, we didn't find a DCPLB we considered
++	 * replacable, which means all of them were locked.
++	 */
++
++	JUMP .Lall_locked;
++.Ldfound_victim:
++
++#ifdef CONFIG_CPLB_INFO
++	R7 = [P0 - 0x104];
++	P2.L = _dpdt_table;
++	P2.H = _dpdt_table;
++	P3.L = _dpdt_swapcount_table;
++	P3.H = _dpdt_swapcount_table;
++	P3 += -4;
++.Ldicount:
++	R2 = [P2];
++	P2 += 8;
++	P3 += 8;
++	CC = R2==-1;
++	IF CC JUMP .Ldicount_done;
++	CC = R7==R2;
++	IF !CC JUMP .Ldicount;
++	R7 = [P3];
++	R7 += 1;
++	[P3] = R7;
++.Ldicount_done:
++#endif
++
++	/* Clean down the hardware loops*/
++	R2 = 0;
++	LC1 = R2;
++	LC0 = R2;
++
++	/* There's a suitable victim in [P0-4] (because we've
++	 * advanced already).
++	 */
++
++.LDdoverwrite:
++
++	/* [P0-4] is a suitable victim CPLB, so we want to
++	 * overwrite it by moving all the following CPLBs
++	 * one space closer to the start.
++	 */
++
++	R1.L = LO(DCPLB_DATA16);		/* DCPLB_DATA15 + 4 */
++	R1.H = HI(DCPLB_DATA16);
++	R0 = P0;
++
++	/* If the victim happens to be in DCPLB15,
++	 * we don't need to move anything.
++	 */
++
++	CC = R1 == R0;
++	IF CC JUMP .Lde_moved;
++	R1 = R1 - R0;
++	R1 >>= 2;
++	P1 = R1;
++	LSETUP(.Lds_move, .Lde_move) LC0=P1;
++.Lds_move:
++	R0 = [P0++];	/* move data */
++	[P0 - 8] = R0;
++	R0 = [P0-0x104]	/* move address */
++.Lde_move:
++	 [P0-0x108] = R0;
++
++.Lde_moved:
++	NOP;
++
++	/* Clear DCPLB_DATA15, in case we don't find a replacement
++	 * otherwise, we would have a duplicate entry, and will crash
++	 */
++	R0 = 0;
++	[P0 - 0x4] = R0;
++
++	/* We've now made space in DCPLB15 for the new CPLB to be
++	 * installed. The next stage is to locate a CPLB in the
++	 * config table that covers the faulting address.
++	 */
++
++	R0 = I0;		/* Our faulting address */
++
++	P2.L = _dpdt_table;
++	P2.H = _dpdt_table;
++#ifdef	CONFIG_CPLB_INFO
++	P3.L = _dpdt_swapcount_table;
++	P3.H = _dpdt_swapcount_table;
++	P3 += -8;
++#endif
++
++	P1.L = _page_size_table;
++	P1.H = _page_size_table;
++
++	/* An extraction pattern, to retrieve bits 17:16.*/
++
++	R1 = (16<<8)|2;
++.Ldnext:	R4 = [P2++];	/* address */
++	R2 = [P2++];	/* data */
++#ifdef	CONFIG_CPLB_INFO
++	P3 += 8;
++#endif
++
++	CC = R4 == -1;
++	IF CC JUMP .Lno_page_in_table;
++
++	/* See if failed address > start address */
++	CC = R4 <= R0(IU);
++	IF !CC JUMP .Ldnext;
++
++	/* extract page size (17:16)*/
++	R3 = EXTRACT(R2, R1.L) (Z);
++
++	/* add page size to addr to get range */
++
++	P5 = R3;
++	P5 = P1 + (P5 << 2);
++	R3 = [P5];
++	R3 = R3 + R4;
++
++	/* See if failed address < (start address + page size) */
++	CC = R0 < R3(IU);
++	IF !CC JUMP .Ldnext;
++
++	/* We've found the CPLB that should be installed, so
++	 * write it into CPLB15, masking off any caching bits
++	 * if necessary.
++	 */
++
++	P1.L = LO(DCPLB_DATA15);
++	P1.H = HI(DCPLB_DATA15);
++
++	/* If the DCPLB has cache bits set, but caching hasn't
++	 * been enabled, then we want to mask off the cache-in-L1
++	 * bit before installing. Moreover, if caching is off, we
++	 * also want to ensure that the DCPLB has WT mode set, rather
++	 * than WB, since WB pages still trigger first-write exceptions
++	 * even when not caching is off, and the page isn't marked as
++	 * cachable. Finally, we could mark the page as clean, not dirty,
++	 * but we choose to leave that decision to the user; if the user
++	 * chooses to have a CPLB pre-defined as dirty, then they always
++	 * pay the cost of flushing during eviction, but don't pay the
++	 * cost of first-write exceptions to mark the page as dirty.
++	 */
++
++#ifdef CONFIG_BFIN_WT
++	BITSET(R6, 14);		/* Set WT*/
++#endif
++
++	[P1] = R2;
++	[P1-0x100] = R4;
++#ifdef	CONFIG_CPLB_INFO
++	R3 = [P3];
++	R3 += 1;
++	[P3] = R3;
++#endif
++
++	/* We've installed the CPLB, so re-enable CPLBs. P4
++	 * points to DMEM_CONTROL, and R5 is the value we
++	 * last wrote to it, when we were disabling CPLBs.
++	 */
++
++	BITSET(R5,ENDCPLB_P);
++	CLI R2;
++	.align 8;
++	[P4] = R5;
++	SSYNC;
++	STI R2;
++
++	( R7:4,P5:3 ) = [SP++];
++	R0 = CPLB_RELOADED;
++	RTS;
++ENDPROC(_cplb_mgr)
++
++.data
++.align 4;
++_page_size_table:
++.byte4	0x00000400;	/* 1K */
++.byte4	0x00001000;	/* 4K */
++.byte4	0x00100000;	/* 1M */
++.byte4	0x00400000;	/* 4M */
++
++.align 4;
++_dcplb_preference:
++.byte4	0x00000001;	/* valid bit */
++.byte4	0x00000002;	/* lock bit */
+diff --git a/arch/blackfin/kernel/cplbinit.c b/arch/blackfin/kernel/cplbinit.c
+deleted file mode 100644
+index 6320bc4..0000000
+--- a/arch/blackfin/kernel/cplbinit.c
++++ /dev/null
+@@ -1,437 +0,0 @@
+-/*
+- * Blackfin CPLB initialization
+- *
+- *               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 <asm/blackfin.h>
+-#include <asm/cplb.h>
+-#include <asm/cplbinit.h>
+-
+-u_long icplb_table[MAX_CPLBS + 1];
+-u_long dcplb_table[MAX_CPLBS + 1];
+-
+-#ifdef CONFIG_CPLB_SWITCH_TAB_L1
+-# define PDT_ATTR __attribute__((l1_data))
+-#else
+-# define PDT_ATTR
+-#endif
+-
+-u_long ipdt_table[MAX_SWITCH_I_CPLBS + 1] PDT_ATTR;
+-u_long dpdt_table[MAX_SWITCH_D_CPLBS + 1] PDT_ATTR;
+-
+-#ifdef CONFIG_CPLB_INFO
+-u_long ipdt_swapcount_table[MAX_SWITCH_I_CPLBS] PDT_ATTR;
+-u_long dpdt_swapcount_table[MAX_SWITCH_D_CPLBS] PDT_ATTR;
+-#endif
+-
+-struct s_cplb {
+-	struct cplb_tab init_i;
+-	struct cplb_tab init_d;
+-	struct cplb_tab switch_i;
+-	struct cplb_tab switch_d;
+-};
+-
+-#if defined(CONFIG_BFIN_DCACHE) || defined(CONFIG_BFIN_ICACHE)
+-static struct cplb_desc cplb_data[] = {
+-	{
+-		.start = 0,
+-		.end = SIZE_1K,
+-		.psize = SIZE_1K,
+-		.attr = INITIAL_T | SWITCH_T | I_CPLB | D_CPLB,
+-		.i_conf = SDRAM_OOPS,
+-		.d_conf = SDRAM_OOPS,
+-#if defined(CONFIG_DEBUG_HUNT_FOR_ZERO)
+-		.valid = 1,
+-#else
+-		.valid = 0,
+-#endif
+-		.name = "Zero Pointer Guard Page",
+-	},
+-	{
+-		.start = L1_CODE_START,
+-		.end = L1_CODE_START + L1_CODE_LENGTH,
+-		.psize = SIZE_4M,
+-		.attr = INITIAL_T | SWITCH_T | I_CPLB,
+-		.i_conf = L1_IMEMORY,
+-		.d_conf = 0,
+-		.valid = 1,
+-		.name = "L1 I-Memory",
+-	},
+-	{
+-		.start = L1_DATA_A_START,
+-		.end = L1_DATA_B_START + L1_DATA_B_LENGTH,
+-		.psize = SIZE_4M,
+-		.attr = INITIAL_T | SWITCH_T | D_CPLB,
+-		.i_conf = 0,
+-		.d_conf = L1_DMEMORY,
+-#if ((L1_DATA_A_LENGTH > 0) || (L1_DATA_B_LENGTH > 0))
+-		.valid = 1,
+-#else
+-		.valid = 0,
+-#endif
+-		.name = "L1 D-Memory",
+-	},
+-	{
+-		.start = 0,
+-		.end = 0,  /* dynamic */
+-		.psize = 0,
+-		.attr = INITIAL_T | SWITCH_T | I_CPLB | D_CPLB,
+-		.i_conf = SDRAM_IGENERIC,
+-		.d_conf = SDRAM_DGENERIC,
+-		.valid = 1,
+-		.name = "Kernel Memory",
+-	},
+-	{
+-		.start = 0, /* dynamic */
+-		.end = 0, /* dynamic */
+-		.psize = 0,
+-		.attr = INITIAL_T | SWITCH_T | D_CPLB,
+-		.i_conf = SDRAM_IGENERIC,
+-		.d_conf = SDRAM_DNON_CHBL,
+-		.valid = 1,
+-		.name = "uClinux MTD Memory",
+-	},
+-	{
+-		.start = 0, /* dynamic */
+-		.end = 0,   /* dynamic */
+-		.psize = SIZE_1M,
+-		.attr = INITIAL_T | SWITCH_T | D_CPLB,
+-		.d_conf = SDRAM_DNON_CHBL,
+-		.valid = 1,
+-		.name = "Uncached DMA Zone",
+-	},
+-	{
+-		.start = 0, /* dynamic */
+-		.end = 0, /* dynamic */
+-		.psize = 0,
+-		.attr = SWITCH_T | D_CPLB,
+-		.i_conf = 0, /* dynamic */
+-		.d_conf = 0, /* dynamic */
+-		.valid = 1,
+-		.name = "Reserved Memory",
+-	},
+-	{
+-		.start = ASYNC_BANK0_BASE,
+-		.end = ASYNC_BANK3_BASE + ASYNC_BANK3_SIZE,
+-		.psize = 0,
+-		.attr = SWITCH_T | D_CPLB,
+-		.d_conf = SDRAM_EBIU,
+-		.valid = 1,
+-		.name = "Asynchronous Memory Banks",
+-	},
+-	{
+-#ifdef L2_START
+-		.start = L2_START,
+-		.end = L2_START + L2_LENGTH,
+-		.psize = SIZE_1M,
+-		.attr = SWITCH_T | I_CPLB | D_CPLB,
+-		.i_conf = L2_MEMORY,
+-		.d_conf = L2_MEMORY,
+-		.valid = 1,
+-#else
+-		.valid = 0,
+-#endif
+-		.name = "L2 Memory",
+-	},
+-	{
+-		.start = BOOT_ROM_START,
+-		.end = BOOT_ROM_START + BOOT_ROM_LENGTH,
+-		.psize = SIZE_1M,
+-		.attr = SWITCH_T | I_CPLB | D_CPLB,
+-		.i_conf = SDRAM_IGENERIC,
+-		.d_conf = SDRAM_DGENERIC,
+-		.valid = 1,
+-		.name = "On-Chip BootROM",
+-	},
+-};
+-
+-static u16 __init lock_kernel_check(u32 start, u32 end)
+-{
+-	if ((end   <= (u32) _end && end   >= (u32)_stext) ||
+-	    (start <= (u32) _end && start >= (u32)_stext))
+-		return IN_KERNEL;
+-	return 0;
+-}
+-
+-static unsigned short __init
+-fill_cplbtab(struct cplb_tab *table,
+-	     unsigned long start, unsigned long end,
+-	     unsigned long block_size, unsigned long cplb_data)
+-{
+-	int i;
+-
+-	switch (block_size) {
+-	case SIZE_4M:
+-		i = 3;
+-		break;
+-	case SIZE_1M:
+-		i = 2;
+-		break;
+-	case SIZE_4K:
+-		i = 1;
+-		break;
+-	case SIZE_1K:
+-	default:
+-		i = 0;
+-		break;
+-	}
+-
+-	cplb_data = (cplb_data & ~(3 << 16)) | (i << 16);
+-
+-	while ((start < end) && (table->pos < table->size)) {
+-
+-		table->tab[table->pos++] = start;
+-
+-		if (lock_kernel_check(start, start + block_size) == IN_KERNEL)
+-			table->tab[table->pos++] =
+-			    cplb_data | CPLB_LOCK | CPLB_DIRTY;
+-		else
+-			table->tab[table->pos++] = cplb_data;
+-
+-		start += block_size;
+-	}
+-	return 0;
+-}
+-
+-static unsigned short __init
+-close_cplbtab(struct cplb_tab *table)
+-{
+-
+-	while (table->pos < table->size) {
+-
+-		table->tab[table->pos++] = 0;
+-		table->tab[table->pos++] = 0; /* !CPLB_VALID */
+-	}
+-	return 0;
+-}
+-
+-/* helper function */
+-static void __fill_code_cplbtab(struct cplb_tab *t, int i, u32 a_start, u32 a_end)
+-{
+-	if (cplb_data[i].psize) {
+-		fill_cplbtab(t,
+-				cplb_data[i].start,
+-				cplb_data[i].end,
+-				cplb_data[i].psize,
+-				cplb_data[i].i_conf);
+-	} else {
+-#if defined(CONFIG_BFIN_ICACHE)
+-		if (ANOMALY_05000263 && i == SDRAM_KERN) {
+-			fill_cplbtab(t,
+-					cplb_data[i].start,
+-					cplb_data[i].end,
+-					SIZE_4M,
+-					cplb_data[i].i_conf);
+-		} else
+-#endif
+-		{
+-			fill_cplbtab(t,
+-					cplb_data[i].start,
+-					a_start,
+-					SIZE_1M,
+-					cplb_data[i].i_conf);
+-			fill_cplbtab(t,
+-					a_start,
+-					a_end,
+-					SIZE_4M,
+-					cplb_data[i].i_conf);
+-			fill_cplbtab(t, a_end,
+-					cplb_data[i].end,
+-					SIZE_1M,
+-					cplb_data[i].i_conf);
+-		}
+-	}
+-}
+-
+-static void __fill_data_cplbtab(struct cplb_tab *t, int i, u32 a_start, u32 a_end)
+-{
+-	if (cplb_data[i].psize) {
+-		fill_cplbtab(t,
+-				cplb_data[i].start,
+-				cplb_data[i].end,
+-				cplb_data[i].psize,
+-				cplb_data[i].d_conf);
+-	} else {
+-		fill_cplbtab(t,
+-				cplb_data[i].start,
+-				a_start, SIZE_1M,
+-				cplb_data[i].d_conf);
+-		fill_cplbtab(t, a_start,
+-				a_end, SIZE_4M,
+-				cplb_data[i].d_conf);
+-		fill_cplbtab(t, a_end,
+-				cplb_data[i].end,
+-				SIZE_1M,
+-				cplb_data[i].d_conf);
+-	}
+-}
+-
+-void __init generate_cpl_tables(void)
+-{
+-
+-	u16 i, j, process;
+-	u32 a_start, a_end, as, ae, as_1m;
+-
+-	struct cplb_tab *t_i = NULL;
+-	struct cplb_tab *t_d = NULL;
+-	struct s_cplb cplb;
+-
+-	cplb.init_i.size = MAX_CPLBS;
+-	cplb.init_d.size = MAX_CPLBS;
+-	cplb.switch_i.size = MAX_SWITCH_I_CPLBS;
+-	cplb.switch_d.size = MAX_SWITCH_D_CPLBS;
+-
+-	cplb.init_i.pos = 0;
+-	cplb.init_d.pos = 0;
+-	cplb.switch_i.pos = 0;
+-	cplb.switch_d.pos = 0;
+-
+-	cplb.init_i.tab = icplb_table;
+-	cplb.init_d.tab = dcplb_table;
+-	cplb.switch_i.tab = ipdt_table;
+-	cplb.switch_d.tab = dpdt_table;
+-
+-	cplb_data[SDRAM_KERN].end = memory_end;
+-
+-#ifdef CONFIG_MTD_UCLINUX
+-	cplb_data[SDRAM_RAM_MTD].start = memory_mtd_start;
+-	cplb_data[SDRAM_RAM_MTD].end = memory_mtd_start + mtd_size;
+-	cplb_data[SDRAM_RAM_MTD].valid = mtd_size > 0;
+-# if defined(CONFIG_ROMFS_FS)
+-	cplb_data[SDRAM_RAM_MTD].attr |= I_CPLB;
+-
+-	/*
+-	 * The ROMFS_FS size is often not multiple of 1MB.
+-	 * This can cause multiple CPLB sets covering the same memory area.
+-	 * This will then cause multiple CPLB hit exceptions.
+-	 * Workaround: We ensure a contiguous memory area by extending the kernel
+-	 * memory section over the mtd section.
+-	 * For ROMFS_FS memory must be covered with ICPLBs anyways.
+-	 * So there is no difference between kernel and mtd memory setup.
+-	 */
+-
+-	cplb_data[SDRAM_KERN].end = memory_mtd_start + mtd_size;;
+-	cplb_data[SDRAM_RAM_MTD].valid = 0;
+-
+-# endif
+-#else
+-	cplb_data[SDRAM_RAM_MTD].valid = 0;
+-#endif
+-
+-	cplb_data[SDRAM_DMAZ].start = _ramend - DMA_UNCACHED_REGION;
+-	cplb_data[SDRAM_DMAZ].end = _ramend;
+-
+-	cplb_data[RES_MEM].start = _ramend;
+-	cplb_data[RES_MEM].end = physical_mem_end;
+-
+-	if (reserved_mem_dcache_on)
+-		cplb_data[RES_MEM].d_conf = SDRAM_DGENERIC;
+-	else
+-		cplb_data[RES_MEM].d_conf = SDRAM_DNON_CHBL;
+-
+-	if (reserved_mem_icache_on)
+-		cplb_data[RES_MEM].i_conf = SDRAM_IGENERIC;
+-	else
+-		cplb_data[RES_MEM].i_conf = SDRAM_INON_CHBL;
+-
+-	for (i = ZERO_P; i < ARRAY_SIZE(cplb_data); ++i) {
+-		if (!cplb_data[i].valid)
+-			continue;
+-
+-		as_1m = cplb_data[i].start % SIZE_1M;
+-
+-		/* We need to make sure all sections are properly 1M aligned
+-		 * However between Kernel Memory and the Kernel mtd section, depending on the
+-		 * rootfs size, there can be overlapping memory areas.
+-		 */
+-
+-		if (as_1m && i != L1I_MEM && i != L1D_MEM) {
+-#ifdef CONFIG_MTD_UCLINUX
+-			if (i == SDRAM_RAM_MTD) {
+-				if ((cplb_data[SDRAM_KERN].end + 1) > cplb_data[SDRAM_RAM_MTD].start)
+-					cplb_data[SDRAM_RAM_MTD].start = (cplb_data[i].start & (-2*SIZE_1M)) + SIZE_1M;
+-				else
+-					cplb_data[SDRAM_RAM_MTD].start = (cplb_data[i].start & (-2*SIZE_1M));
+-			} else
+-#endif
+-				printk(KERN_WARNING "Unaligned Start of %s at 0x%X\n",
+-				       cplb_data[i].name, cplb_data[i].start);
+-		}
+-
+-		as = cplb_data[i].start % SIZE_4M;
+-		ae = cplb_data[i].end % SIZE_4M;
+-
+-		if (as)
+-			a_start = cplb_data[i].start + (SIZE_4M - (as));
+-		else
+-			a_start = cplb_data[i].start;
+-
+-		a_end = cplb_data[i].end - ae;
+-
+-		for (j = INITIAL_T; j <= SWITCH_T; j++) {
+-
+-			switch (j) {
+-			case INITIAL_T:
+-				if (cplb_data[i].attr & INITIAL_T) {
+-					t_i = &cplb.init_i;
+-					t_d = &cplb.init_d;
+-					process = 1;
+-				} else
+-					process = 0;
+-				break;
+-			case SWITCH_T:
+-				if (cplb_data[i].attr & SWITCH_T) {
+-					t_i = &cplb.switch_i;
+-					t_d = &cplb.switch_d;
+-					process = 1;
+-				} else
+-					process = 0;
+-				break;
+-			default:
+-					process = 0;
+-				break;
+-			}
+-
+-			if (!process)
+-				continue;
+-			if (cplb_data[i].attr & I_CPLB)
+-				__fill_code_cplbtab(t_i, i, a_start, a_end);
+-
+-			if (cplb_data[i].attr & D_CPLB)
+-				__fill_data_cplbtab(t_d, i, a_start, a_end);
+-		}
+-	}
+-
+-/* close tables */
+-
+-	close_cplbtab(&cplb.init_i);
+-	close_cplbtab(&cplb.init_d);
+-
+-	cplb.init_i.tab[cplb.init_i.pos] = -1;
+-	cplb.init_d.tab[cplb.init_d.pos] = -1;
+-	cplb.switch_i.tab[cplb.switch_i.pos] = -1;
+-	cplb.switch_d.tab[cplb.switch_d.pos] = -1;
+-
+-}
+-
+-#endif
+-
+diff --git a/arch/blackfin/kernel/early_printk.c b/arch/blackfin/kernel/early_printk.c
+index 724f4a5..60f67f9 100644
+--- a/arch/blackfin/kernel/early_printk.c
++++ b/arch/blackfin/kernel/early_printk.c
+@@ -187,7 +187,7 @@ asmlinkage void __init init_early_exception_vectors(void)
+ 	bfin_write_EVT15(early_trap);
+ 	CSYNC();
+ 
+-	/* Set all the return from interupt, exception, NMI to a known place
++	/* Set all the return from interrupt, exception, NMI to a known place
+ 	 * so if we do a RETI, RETX or RETN by mistake - we go somewhere known
+ 	 * Note - don't change RETS - we are in a subroutine, or
+ 	 * RETE - since it might screw up if emulator is attached
+@@ -205,7 +205,7 @@ asmlinkage void __init early_trap_c(struct pt_regs *fp, void *retaddr)
+ 	if (likely(early_console == NULL))
+ 		setup_early_printk(DEFAULT_EARLY_PORT);
+ 
+-	dump_bfin_mem((void *)fp->retx);
++	dump_bfin_mem(fp);
+ 	show_regs(fp);
+ 	dump_bfin_trace_buffer();
+ 
+diff --git a/arch/blackfin/kernel/process.c b/arch/blackfin/kernel/process.c
+index 5bf1512..023dc80 100644
+--- a/arch/blackfin/kernel/process.c
++++ b/arch/blackfin/kernel/process.c
+@@ -39,9 +39,6 @@
+ #include <asm/blackfin.h>
+ #include <asm/fixed_code.h>
+ 
+-#define	LED_ON	0
+-#define	LED_OFF	1
+-
+ asmlinkage void ret_from_fork(void);
+ 
+ /* Points to the SDRAM backup memory for the stack that is currently in
+@@ -70,32 +67,6 @@ void (*pm_power_off)(void) = NULL;
+ EXPORT_SYMBOL(pm_power_off);
+ 
+ /*
+- * We are using a different LED from the one used to indicate timer interrupt.
+- */
+-#if defined(CONFIG_BFIN_IDLE_LED)
+-static inline void leds_switch(int flag)
+-{
+-	unsigned short tmp = 0;
+-
+-	tmp = bfin_read_CONFIG_BFIN_IDLE_LED_PORT();
+-	SSYNC();
+-
+-	if (flag == LED_ON)
+-		tmp &= ~CONFIG_BFIN_IDLE_LED_PIN;	/* light on */
+-	else
+-		tmp |= CONFIG_BFIN_IDLE_LED_PIN;	/* light off */
+-
+-	bfin_write_CONFIG_BFIN_IDLE_LED_PORT(tmp);
+-	SSYNC();
+-
+-}
+-#else
+-static inline void leds_switch(int flag)
+-{
+-}
+-#endif
+-
+-/*
+  * The idle loop on BFIN
+  */
+ #ifdef CONFIG_IDLE_L1
+@@ -106,12 +77,10 @@ void cpu_idle(void)__attribute__((l1_text));
+ void default_idle(void)
+ {
+ 	while (!need_resched()) {
+-		leds_switch(LED_OFF);
+ 		local_irq_disable();
+ 		if (likely(!need_resched()))
+ 			idle_with_irq_disabled();
+ 		local_irq_enable();
+-		leds_switch(LED_ON);
+ 	}
+ }
+ 
+@@ -327,6 +296,7 @@ void finish_atomic_sections (struct pt_regs *regs)
+ }
+ 
+ #if defined(CONFIG_ACCESS_CHECK)
++/* Return 1 if access to memory range is OK, 0 otherwise */
+ int _access_ok(unsigned long addr, unsigned long size)
+ {
+ 	if (size == 0)
+diff --git a/arch/blackfin/kernel/reboot.c b/arch/blackfin/kernel/reboot.c
+index ae28aac..483f93d 100644
+--- a/arch/blackfin/kernel/reboot.c
++++ b/arch/blackfin/kernel/reboot.c
+@@ -19,6 +19,11 @@
+ #define SYSCR_VAL 	0x10
+ #endif
+ 
++/*
++ * Delay min 5 SCLK cycles using worst case CCLK/SCLK ratio (15)
++ */
++#define SWRST_DELAY	(5 * 15)
++
+ /* A system soft reset makes external memory unusable
+  * so force this function into L1.
+  */
+@@ -34,7 +39,13 @@ void bfin_reset(void)
+ 	while (1) {
+ 		/* initiate system soft reset with magic 0x7 */
+ 		bfin_write_SWRST(0x7);
+-		asm("ssync;");
++
++		/* Wait for System reset to actually reset, needs to be 5 SCLKs, */
++		/* Assume CCLK / SCLK ratio is worst case (15), and use 5*15     */
++
++		asm("LSETUP(.Lfoo,.Lfoo) LC0 = %0\n .Lfoo: NOP;\n"
++		 : : "a" (SWRST_DELAY) : "LC0", "LT0", "LB0");
++
+ 		/* clear system soft reset */
+ 		bfin_write_SWRST(0);
+ 		asm("ssync;");
+diff --git a/arch/blackfin/kernel/setup.c b/arch/blackfin/kernel/setup.c
+index d282201..462cae8 100644
+--- a/arch/blackfin/kernel/setup.c
++++ b/arch/blackfin/kernel/setup.c
+@@ -238,7 +238,13 @@ void __init setup_arch(char **cmdline_p)
+ 	memory_end = _ramend - DMA_UNCACHED_REGION;
+ 
+ 	_ramstart = (unsigned long)__bss_stop;
++	_rambase = (unsigned long)_stext;
++#ifdef CONFIG_MPU
++	/* Round up to multiple of 4MB.  */
++	memory_start = (_ramstart + 0x3fffff) & ~0x3fffff;
++#else
+ 	memory_start = PAGE_ALIGN(_ramstart);
++#endif
+ 
+ #if defined(CONFIG_MTD_UCLINUX)
+ 	/* generic memory mapped MTD driver */
+@@ -307,6 +313,11 @@ void __init setup_arch(char **cmdline_p)
+ 	printk(KERN_NOTICE "Warning: limiting memory to %liMB due to hardware anomaly 05000263\n", memory_end >> 20);
+ #endif				/* ANOMALY_05000263 */
+ 
++#ifdef CONFIG_MPU
++	page_mask_nelts = ((_ramend >> PAGE_SHIFT) + 31) / 32;
++	page_mask_order = get_order(3 * page_mask_nelts * sizeof(long));
++#endif
++
+ #if !defined(CONFIG_MTD_UCLINUX)
+ 	memory_end -= SIZE_4K; /*In case there is no valid CPLB behind memory_end make sure we don't get to close*/
+ #endif
+@@ -315,8 +326,6 @@ void __init setup_arch(char **cmdline_p)
+ 	init_mm.end_data = (unsigned long)_edata;
+ 	init_mm.brk = (unsigned long)0;
+ 
+-	init_leds();
+-
+ 	_bfin_swrst = bfin_read_SWRST();
+ 
+ 	if (_bfin_swrst & RESET_DOUBLE)
+diff --git a/arch/blackfin/kernel/time.c b/arch/blackfin/kernel/time.c
+index beef057..5bd64e3 100644
+--- a/arch/blackfin/kernel/time.c
++++ b/arch/blackfin/kernel/time.c
+@@ -42,75 +42,6 @@
+ static void time_sched_init(irqreturn_t(*timer_routine)
+ 			(int, void *));
+ static unsigned long gettimeoffset(void);
+-static inline void do_leds(void);
+-
+-#if (defined(CONFIG_BFIN_ALIVE_LED) || defined(CONFIG_BFIN_IDLE_LED))
+-void __init init_leds(void)
+-{
+-	unsigned int tmp = 0;
+-
+-#if defined(CONFIG_BFIN_ALIVE_LED)
+-	/* config pins as output. */
+-	tmp = bfin_read_CONFIG_BFIN_ALIVE_LED_DPORT();
+-	SSYNC();
+-	bfin_write_CONFIG_BFIN_ALIVE_LED_DPORT(tmp | CONFIG_BFIN_ALIVE_LED_PIN);
+-	SSYNC();
+-
+-	/*      First set led be off */
+-	tmp = bfin_read_CONFIG_BFIN_ALIVE_LED_PORT();
+-	SSYNC();
+-	bfin_write_CONFIG_BFIN_ALIVE_LED_PORT(tmp | CONFIG_BFIN_ALIVE_LED_PIN);	/* light off */
+-	SSYNC();
+-#endif
+-
+-#if defined(CONFIG_BFIN_IDLE_LED)
+-	/* config pins as output. */
+-	tmp = bfin_read_CONFIG_BFIN_IDLE_LED_DPORT();
+-	SSYNC();
+-	bfin_write_CONFIG_BFIN_IDLE_LED_DPORT(tmp | CONFIG_BFIN_IDLE_LED_PIN);
+-	SSYNC();
+-
+-	/*      First set led be off */
+-	tmp = bfin_read_CONFIG_BFIN_IDLE_LED_PORT();
+-	SSYNC();
+-	bfin_write_CONFIG_BFIN_IDLE_LED_PORT(tmp | CONFIG_BFIN_IDLE_LED_PIN);	/* light off */
+-	SSYNC();
+-#endif
+-}
+-#else
+-void __init init_leds(void)
+-{
+-}
+-#endif
+-
+-#if defined(CONFIG_BFIN_ALIVE_LED)
+-static inline void do_leds(void)
+-{
+-	static unsigned int count = 50;
+-	static int flag;
+-	unsigned short tmp = 0;
+-
+-	if (--count == 0) {
+-		count = 50;
+-		flag = ~flag;
+-	}
+-	tmp = bfin_read_CONFIG_BFIN_ALIVE_LED_PORT();
+-	SSYNC();
+-
+-	if (flag)
+-		tmp &= ~CONFIG_BFIN_ALIVE_LED_PIN;	/* light on */
+-	else
+-		tmp |= CONFIG_BFIN_ALIVE_LED_PIN;	/* light off */
+-
+-	bfin_write_CONFIG_BFIN_ALIVE_LED_PORT(tmp);
+-	SSYNC();
+-
+-}
+-#else
+-static inline void do_leds(void)
+-{
+-}
+-#endif
+ 
+ static struct irqaction bfin_timer_irq = {
+ 	.name = "BFIN Timer Tick",
+@@ -205,7 +136,6 @@ irqreturn_t timer_interrupt(int irq, void *dummy)
+ 	write_seqlock(&xtime_lock);
+ 
+ 	do_timer(1);
+-	do_leds();
+ 
+ #ifndef CONFIG_SMP
+ 	update_process_times(user_mode(get_irq_regs()));
+diff --git a/arch/blackfin/kernel/traps.c b/arch/blackfin/kernel/traps.c
+index 21a55ef..66b5f3e 100644
+--- a/arch/blackfin/kernel/traps.c
++++ b/arch/blackfin/kernel/traps.c
+@@ -36,8 +36,10 @@
+ #include <asm/cacheflush.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>
+@@ -170,7 +172,7 @@ asmlinkage void double_fault_c(struct pt_regs *fp)
+ 	oops_in_progress = 1;
+ 	printk(KERN_EMERG "\n" KERN_EMERG "Double Fault\n");
+ 	dump_bfin_process(fp);
+-	dump_bfin_mem((void *)fp->retx);
++	dump_bfin_mem(fp);
+ 	show_regs(fp);
+ 	panic("Double Fault - unrecoverable event\n");
+ 
+@@ -195,9 +197,13 @@ asmlinkage void trap_c(struct pt_regs *fp)
+ 	 * we will kernel panic, so the system reboots.
+ 	 * If KGDB is enabled, don't set this for kernel breakpoints
+ 	*/
+-	if ((bfin_read_IPEND() & 0xFFC0)
++
++	/* TODO: check to see if we are in some sort of deferred HWERR
++	 * that we should be able to recover from, not kernel panic
++	 */
++	if ((bfin_read_IPEND() & 0xFFC0) && (trapnr != VEC_STEP)
+ #ifdef CONFIG_KGDB
+-		&& trapnr != VEC_EXCPT02
++		&& (trapnr != VEC_EXCPT02)
+ #endif
+ 	){
+ 		console_verbose();
+@@ -433,6 +439,36 @@ asmlinkage void trap_c(struct pt_regs *fp)
+ 	/* 0x3D - Reserved, Caught by default */
+ 	/* 0x3E - Reserved, Caught by default */
+ 	/* 0x3F - Reserved, Caught by default */
++	case VEC_HWERR:
++		info.si_code = BUS_ADRALN;
++		sig = SIGBUS;
++		switch (fp->seqstat & SEQSTAT_HWERRCAUSE) {
++		/* System MMR Error */
++		case (SEQSTAT_HWERRCAUSE_SYSTEM_MMR):
++			info.si_code = BUS_ADRALN;
++			sig = SIGBUS;
++			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));
++			break;
++		/* Performance Monitor Overflow */
++		case (SEQSTAT_HWERRCAUSE_PERF_FLOW):
++			printk(KERN_NOTICE HWC_x12(KERN_NOTICE));
++			break;
++		/* RAISE 5 instruction */
++		case (SEQSTAT_HWERRCAUSE_RAISE_5):
++			printk(KERN_NOTICE HWC_x18(KERN_NOTICE));
++			break;
++		default:        /* Reserved */
++			printk(KERN_NOTICE HWC_default(KERN_NOTICE));
++			break;
++		}
++		CHK_DEBUGGER_TRAP();
++		break;
+ 	default:
+ 		info.si_code = TRAP_ILLTRAP;
+ 		sig = SIGTRAP;
+@@ -447,7 +483,7 @@ asmlinkage void trap_c(struct pt_regs *fp)
+ 	if (sig != SIGTRAP) {
+ 		unsigned long stack;
+ 		dump_bfin_process(fp);
+-		dump_bfin_mem((void *)fp->retx);
++		dump_bfin_mem(fp);
+ 		show_regs(fp);
+ 
+ 		/* Print out the trace buffer if it makes sense */
+@@ -461,6 +497,7 @@ asmlinkage void trap_c(struct pt_regs *fp)
+ 			dump_bfin_trace_buffer();
+ 		show_stack(current, &stack);
+ 		if (oops_in_progress) {
++			print_modules();
+ #ifndef CONFIG_ACCESS_CHECK
+ 			printk(KERN_EMERG "Please turn on "
+ 			       "CONFIG_ACCESS_CHECK\n");
+@@ -474,13 +511,6 @@ asmlinkage void trap_c(struct pt_regs *fp)
+ 	info.si_addr = (void *)fp->pc;
+ 	force_sig_info(sig, &info, current);
+ 
+-	/* Ensure that bad return addresses don't end up in an infinite
+-	 * loop, due to speculative loads/reads. This needs to be done after
+-	 * the signal has been sent.
+-	 */
+-	if (trapnr == VEC_CPLB_I_M && sig != SIGTRAP)
+-		fp->pc = SAFE_USER_INSTRUCTION;
+-
+ 	trace_buffer_restore(j);
+ 	return;
+ }
+@@ -616,8 +646,10 @@ void dump_bfin_process(struct pt_regs *fp)
+ 	if (oops_in_progress)
+ 		printk(KERN_EMERG "Kernel OOPS in progress\n");
+ 
+-	if (context & 0x0020)
+-		printk(KERN_NOTICE "Deferred excecption or HW Error context\n");
++	if (context & 0x0020 && (fp->seqstat & SEQSTAT_EXCAUSE) == VEC_HWERR)
++		printk(KERN_NOTICE "HW Error context\n");
++	else if (context & 0x0020)
++		printk(KERN_NOTICE "Defered Exception context\n");
+ 	else if (context & 0x3FC0)
+ 		printk(KERN_NOTICE "Interrupt context\n");
+ 	else if (context & 0x4000)
+@@ -645,59 +677,124 @@ void dump_bfin_process(struct pt_regs *fp)
+ 		     "No Valid process in current context\n");
+ }
+ 
+-void dump_bfin_mem(void *retaddr)
++void dump_bfin_mem(struct pt_regs *fp)
+ {
++	unsigned short *addr, *erraddr, val = 0, err = 0;
++	char sti = 0, buf[6];
+ 
+-	if (retaddr >= (void *)FIXED_CODE_START  && retaddr < (void *)physical_mem_end
+-#if L1_CODE_LENGTH != 0
+-	    /* FIXME: Copy the code out of L1 Instruction SRAM through dma
+-	       memcpy.  */
+-	    && !(retaddr >= (void *)L1_CODE_START
+-	         && retaddr < (void *)(L1_CODE_START + L1_CODE_LENGTH))
+-#endif
+-	) {
+-		int i = ((unsigned int)retaddr & 0xFFFFFFF0) - 32;
+-		unsigned short x = 0;
+-		printk(KERN_NOTICE "return address: [0x%p]; contents of:", retaddr);
+-		for (; i < ((unsigned int)retaddr & 0xFFFFFFF0) + 32; i += 2) {
+-			if (!(i & 0xF))
+-				printk("\n" KERN_NOTICE "0x%08x: ", i);
+-
+-			if (get_user(x, (unsigned short *)i))
+-				break;
++	if (unlikely((fp->seqstat & SEQSTAT_EXCAUSE) == VEC_HWERR))
++		erraddr = (void *)fp->pc;
++	else
++		erraddr = (void *)fp->retx;
++
++	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);
++
++		if (get_user(val, addr)) {
++			if (addr >= (unsigned short *)L1_CODE_START &&
++			    addr < (unsigned short *)(L1_CODE_START + L1_CODE_LENGTH)) {
++				dma_memcpy(&val, addr, sizeof(val));
++				sprintf(buf, "%04x", val);
++			} else if (addr >= (unsigned short *)FIXED_CODE_START &&
++				addr <= (unsigned short *)memory_start) {
++				val = bfin_read16(addr);
++				sprintf(buf, "%04x", val);
++			} else {
++				val = 0;
++				sprintf(buf, "????");
++			}
++		} else
++			sprintf(buf, "%04x", val);
++
++		if (addr == erraddr) {
++			printk("[%s]", buf);
++			err = val;
++		} else
++			printk(" %s ", buf);
++
++		/* Do any previous instructions turn on interrupts? */
++		if (addr <= erraddr &&				/* in the past */
++		    ((val >= 0x0040 && val <= 0x0047) ||	/* STI instruction */
++		      val == 0x017b))				/* [SP++] = RETI */
++			sti = 1;
++	}
++
++	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");
+ #ifndef CONFIG_DEBUG_HWERR
+-			/* If one of the last few instructions was a STI
+-			 * it is likely that the error occured awhile ago
+-			 * and we just noticed. This only happens in kernel
+-			 * context, which should mean an oops is happening
+-			 */
+-			if (oops_in_progress && x >= 0x0040 && x <= 0x0047 && i <= 0)
+-				panic("\n\nWARNING : You should reconfigure"
+-					" the kernel to turn on\n"
+-					" 'Hardware error interrupt"
+-					" debugging'\n"
+-					" The rest of this error"
+-					" is meanless\n");
+-#endif
+-			if (i == (unsigned int)retaddr)
+-				printk("[%04x]", x);
+-			else
+-				printk(" %04x ", x);
++		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
++		/* If we are handling only one peripheral interrupt
++		 * and current mm and pid are valid, and the last error
++		 * was in that user space process's text area
++		 * print it out - because that is where the problem exists
++		 */
++		if ((!(((fp)->ipend & ~0x30) & (((fp)->ipend & ~0x30) - 1))) &&
++		     (current->pid && current->mm)) {
++			/* 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");
++				show_regs(fp + 1);
++				printk(KERN_NOTICE "-------------------------------------------\n");
++			}
+ 		}
+-		printk("\n");
+-	} else
+-		printk("\n" KERN_NOTICE
+-			"Cannot look at the [PC] <%p> for it is"
+-			" in unreadable memory - sorry\n", retaddr);
++#endif
++	}
+ }
+ 
+ void show_regs(struct pt_regs *fp)
+ {
+ 	char buf [150];
++	struct irqaction *action;
++	unsigned int i;
++	unsigned long flags;
+ 
+-	printk(KERN_NOTICE "\n" KERN_NOTICE "SEQUENCER STATUS:\n");
++	printk(KERN_NOTICE "\n" KERN_NOTICE "SEQUENCER STATUS:\t\t%s\n", print_tainted());
+ 	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",
++		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);
++		}
++	}
++
++	/* if no interrupts are going off, don't print this out */
++	if (fp->ipend & ~0x3F) {
++		for (i = 0; i < (NR_IRQS - 1); i++) {
++			spin_lock_irqsave(&irq_desc[i].lock, flags);
++			action = irq_desc[i].action;
++			if (!action)
++				goto unlock;
++
++			decode_address(buf, (unsigned int)action->handler);
++			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);
++			}
++			printk("\n");
++unlock:
++			spin_unlock_irqrestore(&irq_desc[i].lock, flags);
++		}
++	}
+ 
+ 	decode_address(buf, fp->rete);
+ 	printk(KERN_NOTICE " RETE: %s\n", buf);
+@@ -708,9 +805,10 @@ void show_regs(struct pt_regs *fp)
+ 	decode_address(buf, fp->rets);
+ 	printk(KERN_NOTICE " RETS: %s\n", buf);
+ 	decode_address(buf, fp->pc);
+-	printk(KERN_NOTICE " PC: %s\n", buf);
++	printk(KERN_NOTICE " PC  : %s\n", buf);
+ 
+-	if ((long)fp->seqstat & SEQSTAT_EXCAUSE) {
++	if (((long)fp->seqstat &  SEQSTAT_EXCAUSE) &&
++	    (((long)fp->seqstat & SEQSTAT_EXCAUSE) != VEC_HWERR)) {
+ 		decode_address(buf, bfin_read_DCPLB_FAULT_ADDR());
+ 		printk(KERN_NOTICE "DCPLB_FAULT_ADDR: %s\n", buf);
+ 		decode_address(buf, bfin_read_ICPLB_FAULT_ADDR());
+@@ -824,7 +922,7 @@ void panic_cplb_error(int cplb_panic, struct pt_regs *fp)
+ 	printk(KERN_EMERG "DCPLB_FAULT_ADDR=%p\n", (void *)bfin_read_DCPLB_FAULT_ADDR());
+ 	printk(KERN_EMERG "ICPLB_FAULT_ADDR=%p\n", (void *)bfin_read_ICPLB_FAULT_ADDR());
+ 	dump_bfin_process(fp);
+-	dump_bfin_mem((void *)fp->retx);
++	dump_bfin_mem(fp);
+ 	show_regs(fp);
+ 	dump_stack();
+ 	panic("Unrecoverable event\n");
+diff --git a/arch/blackfin/lib/memcpy.S b/arch/blackfin/lib/memcpy.S
+index 2e63364..e654a18 100644
+--- a/arch/blackfin/lib/memcpy.S
++++ b/arch/blackfin/lib/memcpy.S
+@@ -70,8 +70,8 @@ ENTRY(_memcpy)
+ 	/* Check for aligned data.*/
+ 
+ 	R3 = R1 | R0;
+-	R0 = 0x3;
+-	R3 = R3 & R0;
++	R1 = 0x3;
++	R3 = R3 & R1;
+ 	CC = R3;	/* low bits set on either address? */
+ 	IF CC JUMP .Lnot_aligned;
+ 
+@@ -83,7 +83,6 @@ ENTRY(_memcpy)
+ 	/* less than eight bytes... */
+ 	P2 = R2;
+ 	LSETUP(.Lthree_start, .Lthree_end) LC0=P2;
+-	R0 = R1;	/* setup src address for return */
+ .Lthree_start:
+ 	R3 = B[P1++] (X);
+ .Lthree_end:
+@@ -95,7 +94,6 @@ ENTRY(_memcpy)
+ 	/* There's at least eight bytes to copy. */
+ 	P2 += -1;	/* because we unroll one iteration */
+ 	LSETUP(.Lword_loops, .Lword_loope) LC0=P2;
+-	R0 = R1;
+ 	I1 = P1;
+ 	R3 = [I1++];
+ #if ANOMALY_05000202
+@@ -120,7 +118,6 @@ ENTRY(_memcpy)
+ .Lnot_aligned:
+ 	/* From here, we're copying byte-by-byte. */
+ 	LSETUP (.Lbyte_start, .Lbyte_end) LC0=P2;
+-	R0 = R1;	/* Save src address for return */
+ .Lbyte_start:
+ 	R1 = B[P1++] (X);
+ .Lbyte_end:
+@@ -135,7 +132,6 @@ ENTRY(_memcpy)
+ 	 * Don't bother to work out alignment for
+ 	 * the reverse case.
+ 	 */
+-	R0 = R1;	/* save src for later. */
+ 	P0 = P0 + P2;
+ 	P0 += -1;
+ 	P1 = P1 + P2;
+diff --git a/arch/blackfin/mach-bf527/Kconfig b/arch/blackfin/mach-bf527/Kconfig
+index 5c73683..3cde4be 100644
+--- a/arch/blackfin/mach-bf527/Kconfig
++++ b/arch/blackfin/mach-bf527/Kconfig
+@@ -43,7 +43,7 @@ endchoice
+ 
+ choice
+ 	prompt "UART1"
+-	default BF527_UART1_PORTG
++	default BF527_UART1_PORTF
+ 	help
+ 	  Select PORT used for UART1. See Hardware Reference Manual
+ 
+diff --git a/arch/blackfin/mach-bf527/boards/ezkit.c b/arch/blackfin/mach-bf527/boards/ezkit.c
+index 003e2ac..f8c411a 100644
+--- a/arch/blackfin/mach-bf527/boards/ezkit.c
++++ b/arch/blackfin/mach-bf527/boards/ezkit.c
+@@ -8,7 +8,7 @@
+  *
+  * Modified:
+  *               Copyright 2005 National ICT Australia (NICTA)
+- *               Copyright 2004-2007 Analog Devices Inc.
++ *               Copyright 2004-2008 Analog Devices Inc.
+  *
+  * Bugs:         Enter bugs at http://blackfin.uclinux.org/
+  *
+@@ -41,6 +41,7 @@
+ #include <linux/irq.h>
+ #include <linux/interrupt.h>
+ #include <linux/usb/sl811.h>
++#include <linux/usb/musb.h>
+ #include <asm/cplb.h>
+ #include <asm/dma.h>
+ #include <asm/bfin5xx_spi.h>
+@@ -105,6 +106,69 @@ void __exit bfin_isp1761_exit(void)
+ arch_initcall(bfin_isp1761_init);
+ #endif
+ 
++#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_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
++	.multipoint	= 0,
++};
++
++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_FB_BFIN_T350MCQB) || defined(CONFIG_FB_BFIN_T350MCQB_MODULE)
++
++static struct resource bf52x_t350mcqb_resources[] = {
++	{
++		.start = IRQ_PPI_ERROR,
++		.end = IRQ_PPI_ERROR,
++		.flags = IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device bf52x_t350mcqb_device = {
++	.name		= "bfin-t350mcqb",
++	.id		= -1,
++	.num_resources 	= ARRAY_SIZE(bf52x_t350mcqb_resources),
++	.resource 	= bf52x_t350mcqb_resources,
++};
++#endif
++
+ #if defined(CONFIG_MTD_NAND_BF5XX) || defined(CONFIG_MTD_NAND_BF5XX_MODULE)
+ static struct mtd_partition partition_info[] = {
+ 	{
+@@ -253,12 +317,7 @@ static struct resource sl811_hcd_resources[] = {
+ void sl811_port_power(struct device *dev, int is_on)
+ {
+ 	gpio_request(CONFIG_USB_SL811_BFIN_GPIO_VBUS, "usb:SL811_VBUS");
+-	gpio_direction_output(CONFIG_USB_SL811_BFIN_GPIO_VBUS);
+-
+-	if (is_on)
+-		gpio_set_value(CONFIG_USB_SL811_BFIN_GPIO_VBUS, 1);
+-	else
+-		gpio_set_value(CONFIG_USB_SL811_BFIN_GPIO_VBUS, 0);
++	gpio_direction_output(CONFIG_USB_SL811_BFIN_GPIO_VBUS, is_on);
+ }
+ #endif
+ 
+@@ -718,6 +777,28 @@ static struct platform_device bfin_pata_device = {
+ };
+ #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 platform_device *stamp_devices[] __initdata = {
+ #if defined(CONFIG_MTD_NAND_BF5XX) || defined(CONFIG_MTD_NAND_BF5XX_MODULE)
+ 	&bf5xx_nand_device,
+@@ -739,6 +820,10 @@ static struct platform_device *stamp_devices[] __initdata = {
+ 	&isp1362_hcd_device,
+ #endif
+ 
++#if defined(CONFIG_USB_MUSB_HDRC) || defined(CONFIG_USB_MUSB_HDRC_MODULE)
++	&musb_device,
++#endif
++
+ #if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
+ 	&smc91x_device,
+ #endif
+@@ -763,6 +848,10 @@ static struct platform_device *stamp_devices[] __initdata = {
+ 	&bfin_fb_device,
+ #endif
+ 
++#if defined(CONFIG_FB_BFIN_T350MCQB) || defined(CONFIG_FB_BFIN_T350MCQB_MODULE)
++	&bf52x_t350mcqb_device,
++#endif
++
+ #if defined(CONFIG_FB_BFIN_7393) || defined(CONFIG_FB_BFIN_7393_MODULE)
+ 	&bfin_fb_adv7393_device,
+ #endif
+@@ -783,6 +872,10 @@ static struct platform_device *stamp_devices[] __initdata = {
+ #if defined(CONFIG_PATA_PLATFORM) || defined(CONFIG_PATA_PLATFORM_MODULE)
+ 	&bfin_pata_device,
+ #endif
++
++#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
++	&bfin_device_gpiokeys,
++#endif
+ };
+ 
+ static int __init stamp_init(void)
+diff --git a/arch/blackfin/mach-bf533/boards/H8606.c b/arch/blackfin/mach-bf533/boards/H8606.c
+index 6bcf404..a72c7a6 100644
+--- a/arch/blackfin/mach-bf533/boards/H8606.c
++++ b/arch/blackfin/mach-bf533/boards/H8606.c
+@@ -40,6 +40,7 @@
+ #endif
+ #include <linux/pata_platform.h>
+ #include <linux/irq.h>
++
+ #include <asm/dma.h>
+ #include <asm/bfin5xx_spi.h>
+ #include <asm/reboot.h>
+@@ -303,7 +304,77 @@ static struct platform_device bfin_uart_device = {
+ };
+ #endif
+ 
+-static struct platform_device *stamp_devices[] __initdata = {
++#if defined(CONFIG_SERIAL_8250) || defined(CONFIG_SERIAL_8250_MODULE)
++
++#include <linux/serial_8250.h>
++#include <linux/serial.h>
++
++/*
++ * Configuration for two 16550 UARTS in FPGA at addresses 0x20200000 and 0x202000010.
++ * running at half system clock, both with interrupt output or-ed to PF8. Change to
++ * suit different FPGA configuration, or to suit real 16550 UARTS connected to the bus
++ */
++
++static struct plat_serial8250_port serial8250_platform_data [] = {
++	{
++		.membase = 0x20200000,
++		.mapbase = 0x20200000,
++		.irq = IRQ_PF8,
++		.flags = UPF_BOOT_AUTOCONF | UART_CONFIG_TYPE,
++		.iotype = UPIO_MEM,
++		.regshift = 1,
++		.uartclk = 66666667,
++	}, {
++		.membase = 0x20200010,
++		.mapbase = 0x20200010,
++		.irq = IRQ_PF8,
++		.flags = UPF_BOOT_AUTOCONF | UART_CONFIG_TYPE,
++		.iotype = UPIO_MEM,
++		.regshift = 1,
++		.uartclk = 66666667,
++	}, {
++	}
++};
++
++static struct platform_device serial8250_device = {
++	.id		= PLAT8250_DEV_PLATFORM,
++	.name		= "serial8250",
++	.dev		= {
++		.platform_data = serial8250_platform_data,
++	},
++};
++
++#endif
++
++#if defined(CONFIG_KEYBOARD_OPENCORES) || defined(CONFIG_KEYBOARD_OPENCORES_MODULE)
++
++/*
++ * Configuration for one OpenCores keyboard controller in FPGA at address 0x20200030,
++ * interrupt output wired to PF9. Change to suit different FPGA configuration
++ */
++
++static struct resource opencores_kbd_resources[] = {
++	[0] = {
++		.start	= 0x20200030,
++		.end	= 0x20300030 + 2,
++		.flags	= IORESOURCE_MEM,
++	},
++	[1] = {
++		.start	= IRQ_PF9,
++		.end	= IRQ_PF9,
++		.flags	= IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE,
++	},
++};
++
++static struct platform_device opencores_kbd_device = {
++	.id		= -1,
++	.name		= "opencores-kbd",
++	.resource	= opencores_kbd_resources,
++	.num_resources	= ARRAY_SIZE(opencores_kbd_resources),
++};
++#endif
++
++static struct platform_device *h8606_devices[] __initdata = {
+ #if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE)
+ 	&rtc_device,
+ #endif
+@@ -327,13 +398,21 @@ static struct platform_device *stamp_devices[] __initdata = {
+ #if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
+ 	&bfin_uart_device,
+ #endif
++
++#if defined(CONFIG_SERIAL_8250) || defined(CONFIG_SERIAL_8250_MODULE)
++	&serial8250_device,
++#endif
++
++#if defined(CONFIG_KEYBOARD_OPENCORES) || defined(CONFIG_KEYBOARD_OPENCORES_MODULE)
++	&opencores_kbd_device,
++#endif
+ };
+ 
+ static int __init H8606_init(void)
+ {
+ 	printk(KERN_INFO "HV Sistemas H8606 board support by http://www.hvsistemas.com\n");
+ 	printk(KERN_INFO "%s(): registering device resources\n", __FUNCTION__);
+-	platform_add_devices(stamp_devices, ARRAY_SIZE(stamp_devices));
++	platform_add_devices(h8606_devices, ARRAY_SIZE(h8606_devices));
+ #if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+ 	spi_register_board_info(bfin_spi_board_info, ARRAY_SIZE(bfin_spi_board_info));
+ #endif
+diff --git a/arch/blackfin/mach-bf533/boards/ezkit.c b/arch/blackfin/mach-bf533/boards/ezkit.c
+index be85203..c37dd45 100644
+--- a/arch/blackfin/mach-bf533/boards/ezkit.c
++++ b/arch/blackfin/mach-bf533/boards/ezkit.c
+@@ -256,6 +256,50 @@ static struct platform_device bfin_pata_device = {
+ };
+ #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_PF7, 1, "gpio-keys: BTN0"},
++	{BTN_1, GPIO_PF8, 1, "gpio-keys: BTN1"},
++	{BTN_2, GPIO_PF9, 1, "gpio-keys: BTN2"},
++	{BTN_3, GPIO_PF10, 1, "gpio-keys: BTN3"},
++};
++
++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
++
++#if defined(CONFIG_I2C_GPIO) || defined(CONFIG_I2C_GPIO_MODULE)
++#include <linux/i2c-gpio.h>
++
++static struct i2c_gpio_platform_data i2c_gpio_data = {
++	.sda_pin		= 1,
++	.scl_pin		= 0,
++	.sda_is_open_drain	= 0,
++	.scl_is_open_drain	= 0,
++	.udelay			= 40,
++};
++
++static struct platform_device i2c_gpio_device = {
++	.name		= "i2c-gpio",
++	.id		= 0,
++	.dev		= {
++		.platform_data	= &i2c_gpio_data,
++	},
++};
++#endif
++
+ static struct platform_device *ezkit_devices[] __initdata = {
+ #if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
+ 	&smc91x_device,
+@@ -280,6 +324,14 @@ static struct platform_device *ezkit_devices[] __initdata = {
+ #if defined(CONFIG_PATA_PLATFORM) || defined(CONFIG_PATA_PLATFORM_MODULE)
+ 	&bfin_pata_device,
+ #endif
++
++#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
++	&bfin_device_gpiokeys,
++#endif
++
++#if defined(CONFIG_I2C_GPIO) || defined(CONFIG_I2C_GPIO_MODULE)
++	&i2c_gpio_device,
++#endif
+ };
+ 
+ static int __init ezkit_init(void)
+diff --git a/arch/blackfin/mach-bf533/boards/stamp.c b/arch/blackfin/mach-bf533/boards/stamp.c
+index 8fde8d8..ac52b04 100644
+--- a/arch/blackfin/mach-bf533/boards/stamp.c
++++ b/arch/blackfin/mach-bf533/boards/stamp.c
+@@ -32,6 +32,7 @@
+ #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>
+ #if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE)
+@@ -108,6 +109,50 @@ static struct platform_device net2272_bfin_device = {
+ };
+ #endif
+ 
++static struct mtd_partition stamp_partitions[] = {
++	{
++		.name   = "Bootloader",
++		.size   = 0x20000,
++		.offset = 0,
++	}, {
++		.name   = "Kernel",
++		.size   = 0xE0000,
++		.offset = MTDPART_OFS_APPEND,
++	}, {
++		.name   = "RootFS",
++		.size   = MTDPART_SIZ_FULL,
++		.offset = MTDPART_OFS_APPEND,
++	}
++};
++
++static struct physmap_flash_data stamp_flash_data = {
++	.width    = 2,
++	.parts    = stamp_partitions,
++	.nr_parts = ARRAY_SIZE(stamp_partitions),
++};
++
++static struct resource stamp_flash_resource[] = {
++	{
++		.name  = "cfi_probe",
++		.start = 0x20000000,
++		.end   = 0x203fffff,
++		.flags = IORESOURCE_MEM,
++	}, {
++		.start = CONFIG_ENET_FLASH_PIN,
++		.flags = IORESOURCE_IRQ,
++	}
++};
++
++static struct platform_device stamp_flash_device = {
++	.name          = "BF5xx-Flash",
++	.id            = 0,
++	.dev = {
++		.platform_data = &stamp_flash_data,
++	},
++	.num_resources = ARRAY_SIZE(stamp_flash_resource),
++	.resource      = stamp_flash_resource,
++};
++
+ #if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+ /* all SPI peripherals info goes here */
+ 
+@@ -373,6 +418,49 @@ static struct platform_device bfin_pata_device = {
+ };
+ #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_PF5, 1, "gpio-keys: BTN0"},
++	{BTN_1, GPIO_PF6, 1, "gpio-keys: BTN1"},
++	{BTN_2, GPIO_PF8, 1, "gpio-keys: BTN2"},
++};
++
++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
++
++#if defined(CONFIG_I2C_GPIO) || defined(CONFIG_I2C_GPIO_MODULE)
++#include <linux/i2c-gpio.h>
++
++static struct i2c_gpio_platform_data i2c_gpio_data = {
++	.sda_pin		= 2,
++	.scl_pin		= 3,
++	.sda_is_open_drain	= 0,
++	.scl_is_open_drain	= 0,
++	.udelay			= 40,
++};
++
++static struct platform_device i2c_gpio_device = {
++	.name		= "i2c-gpio",
++	.id		= 0,
++	.dev		= {
++		.platform_data	= &i2c_gpio_data,
++	},
++};
++#endif
++
+ static struct platform_device *stamp_devices[] __initdata = {
+ #if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE)
+ 	&rtc_device,
+@@ -406,6 +494,15 @@ static struct platform_device *stamp_devices[] __initdata = {
+ #if defined(CONFIG_PATA_PLATFORM) || defined(CONFIG_PATA_PLATFORM_MODULE)
+ 	&bfin_pata_device,
+ #endif
++
++#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
++	&bfin_device_gpiokeys,
++#endif
++
++#if defined(CONFIG_I2C_GPIO) || defined(CONFIG_I2C_GPIO_MODULE)
++	&i2c_gpio_device,
++#endif
++	&stamp_flash_device,
+ };
+ 
+ static int __init stamp_init(void)
+@@ -418,12 +515,10 @@ static int __init stamp_init(void)
+ 		return ret;
+ 
+ #if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
+-# if defined(CONFIG_BFIN_SHARED_FLASH_ENET)
+ 	/* setup BF533_STAMP CPLD to route AMS3 to Ethernet MAC */
+ 	bfin_write_FIO_DIR(bfin_read_FIO_DIR() | (1 << CONFIG_ENET_FLASH_PIN));
+ 	bfin_write_FIO_FLAG_S(1 << CONFIG_ENET_FLASH_PIN);
+ 	SSYNC();
+-# endif
+ #endif
+ 
+ #if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+@@ -440,10 +535,8 @@ arch_initcall(stamp_init);
+ 
+ void native_machine_restart(char *cmd)
+ {
+-#if defined(CONFIG_BFIN_SHARED_FLASH_ENET)
+-# define BIT_TO_SET (1 << CONFIG_ENET_FLASH_PIN)
++#define BIT_TO_SET (1 << CONFIG_ENET_FLASH_PIN)
+ 	bfin_write_FIO_INEN(~BIT_TO_SET);
+ 	bfin_write_FIO_DIR(BIT_TO_SET);
+ 	bfin_write_FIO_FLAG_C(BIT_TO_SET);
+-#endif
+ }
+diff --git a/arch/blackfin/mach-bf537/boards/Kconfig b/arch/blackfin/mach-bf537/boards/Kconfig
+index 96a1519..7e789db 100644
+--- a/arch/blackfin/mach-bf537/boards/Kconfig
++++ b/arch/blackfin/mach-bf537/boards/Kconfig
+@@ -21,6 +21,12 @@ config PNAV10
+ 	help
+ 	  PNAV board support.
+ 
++config CAMSIG_MINOTAUR
++	bool "Cambridge Signal Processing LTD Minotaur"
++	depends on (BF537)
++	help
++	  Board supply package for CSP Minotaur
++
+ config GENERIC_BF537_BOARD
+ 	bool "Generic"
+ 	help
+diff --git a/arch/blackfin/mach-bf537/boards/Makefile b/arch/blackfin/mach-bf537/boards/Makefile
+index 94a8517..87e450f 100644
+--- a/arch/blackfin/mach-bf537/boards/Makefile
++++ b/arch/blackfin/mach-bf537/boards/Makefile
+@@ -6,3 +6,4 @@ obj-$(CONFIG_GENERIC_BF537_BOARD)      += generic_board.o
+ obj-$(CONFIG_BFIN537_STAMP)            += stamp.o led.o
+ obj-$(CONFIG_BFIN537_BLUETECHNIX_CM)   += cm_bf537.o
+ obj-$(CONFIG_PNAV10)                   += pnav10.o
++obj-$(CONFIG_CAMSIG_MINOTAUR)          += minotaur.o
+diff --git a/arch/blackfin/mach-bf537/boards/cm_bf537.c b/arch/blackfin/mach-bf537/boards/cm_bf537.c
+index c0fb06d..8703b67 100644
+--- a/arch/blackfin/mach-bf537/boards/cm_bf537.c
++++ b/arch/blackfin/mach-bf537/boards/cm_bf537.c
+@@ -29,6 +29,7 @@
+  */
+ 
+ #include <linux/device.h>
++#include <linux/etherdevice.h>
+ #include <linux/platform_device.h>
+ #include <linux/mtd/mtd.h>
+ #include <linux/mtd/partitions.h>
+@@ -216,6 +217,12 @@ static struct platform_device rtc_device = {
+ };
+ #endif
+ 
++#if defined(CONFIG_FB_HITACHI_TX09) || defined(CONFIG_FB_HITACHI_TX09_MODULE)
++static struct platform_device hitachi_fb_device = {
++	.name = "hitachi-tx09",
++};
++#endif
++
+ #if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
+ static struct resource smc91x_resources[] = {
+ 	{
+@@ -374,6 +381,10 @@ static struct platform_device bfin_pata_device = {
+ #endif
+ 
+ static struct platform_device *cm_bf537_devices[] __initdata = {
++#if defined(CONFIG_FB_HITACHI_TX09) || defined(CONFIG_FB_HITACHI_TX09_MODULE)
++	&hitachi_fb_device,
++#endif
++
+ #if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE)
+ 	&rtc_device,
+ #endif
+diff --git a/arch/blackfin/mach-bf537/boards/generic_board.c b/arch/blackfin/mach-bf537/boards/generic_board.c
+index 09f4bfb..3e52f3f 100644
+--- a/arch/blackfin/mach-bf537/boards/generic_board.c
++++ b/arch/blackfin/mach-bf537/boards/generic_board.c
+@@ -8,7 +8,7 @@
+  *
+  * Modified:
+  *               Copyright 2005 National ICT Australia (NICTA)
+- *               Copyright 2004-2007 Analog Devices Inc.
++ *               Copyright 2004-2008 Analog Devices Inc.
+  *
+  * Bugs:         Enter bugs at http://blackfin.uclinux.org/
+  *
+@@ -29,6 +29,7 @@
+  */
+ 
+ #include <linux/device.h>
++#include <linux/etherdevice.h>
+ #include <linux/platform_device.h>
+ #include <linux/mtd/mtd.h>
+ #include <linux/mtd/partitions.h>
+@@ -204,12 +205,8 @@ static struct resource sl811_hcd_resources[] = {
+ void sl811_port_power(struct device *dev, int is_on)
+ {
+ 	gpio_request(CONFIG_USB_SL811_BFIN_GPIO_VBUS, "usb:SL811_VBUS");
+-	gpio_direction_output(CONFIG_USB_SL811_BFIN_GPIO_VBUS);
++	gpio_direction_output(CONFIG_USB_SL811_BFIN_GPIO_VBUS, is_on);
+ 
+-	if (is_on)
+-		gpio_set_value(CONFIG_USB_SL811_BFIN_GPIO_VBUS, 1);
+-	else
+-		gpio_set_value(CONFIG_USB_SL811_BFIN_GPIO_VBUS, 0);
+ }
+ #endif
+ 
+@@ -733,9 +730,11 @@ void native_machine_restart(char *cmd)
+ 		bfin_gpio_reset_spi0_ssel1();
+ }
+ 
++#if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
+ void bfin_get_ether_addr(char *addr)
+ {
+ 	random_ether_addr(addr);
+ 	printk(KERN_WARNING "%s:%s: Setting Ethernet MAC to a random one\n", __FILE__, __func__);
+ }
+ EXPORT_SYMBOL(bfin_get_ether_addr);
++#endif
+diff --git a/arch/blackfin/mach-bf537/boards/minotaur.c b/arch/blackfin/mach-bf537/boards/minotaur.c
+new file mode 100644
+index 0000000..b8bbba8
+--- /dev/null
++++ b/arch/blackfin/mach-bf537/boards/minotaur.c
+@@ -0,0 +1,317 @@
++/*
++ */
++
++#include <linux/device.h>
++#include <linux/platform_device.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/partitions.h>
++#include <linux/spi/spi.h>
++#include <linux/spi/flash.h>
++#if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE)
++#include <linux/usb_isp1362.h>
++#endif
++#include <linux/pata_platform.h>
++#include <linux/irq.h>
++#include <linux/interrupt.h>
++#include <linux/usb_sl811.h>
++#include <asm/dma.h>
++#include <asm/bfin5xx_spi.h>
++#include <asm/reboot.h>
++#include <linux/spi/ad7877.h>
++
++/*
++ * Name the Board for the /proc/cpuinfo
++ */
++char *bfin_board_name = "CamSig Minotaur BF537";
++
++#if defined(CONFIG_BFIN_CFPCMCIA) || defined(CONFIG_BFIN_CFPCMCIA_MODULE)
++static struct resource bfin_pcmcia_cf_resources[] = {
++	{
++		.start = 0x20310000, /* IO PORT */
++		.end = 0x20312000,
++		.flags = IORESOURCE_MEM,
++	}, {
++		.start = 0x20311000, /* Attribute Memory */
++		.end = 0x20311FFF,
++		.flags = IORESOURCE_MEM,
++	}, {
++		.start = IRQ_PF4,
++		.end = IRQ_PF4,
++		.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL,
++	}, {
++		.start = IRQ_PF6, /* Card Detect PF6 */
++		.end = IRQ_PF6,
++		.flags = IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device bfin_pcmcia_cf_device = {
++	.name = "bfin_cf_pcmcia",
++	.id = -1,
++	.num_resources = ARRAY_SIZE(bfin_pcmcia_cf_resources),
++	.resource = bfin_pcmcia_cf_resources,
++};
++#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_USB_NET2272) || defined(CONFIG_USB_NET2272_MODULE)
++static struct resource net2272_bfin_resources[] = {
++	{
++		.start = 0x20300000,
++		.end = 0x20300000 + 0x100,
++		.flags = IORESOURCE_MEM,
++	}, {
++		.start = IRQ_PF7,
++		.end = IRQ_PF7,
++		.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
++	},
++};
++
++static struct platform_device net2272_bfin_device = {
++	.name = "net2272",
++	.id = -1,
++	.num_resources = ARRAY_SIZE(net2272_bfin_resources),
++	.resource = net2272_bfin_resources,
++};
++#endif
++
++#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
++/* all SPI peripherals info goes here */
++
++#if defined(CONFIG_MTD_M25P80) \
++	|| defined(CONFIG_MTD_M25P80_MODULE)
++
++/* Partition sizes */
++#define FLASH_SIZE       0x00400000
++#define PSIZE_UBOOT      0x00030000
++#define PSIZE_INITRAMFS  0x00240000
++
++static struct mtd_partition bfin_spi_flash_partitions[] = {
++	{
++		.name       = "uboot",
++		.size       = PSIZE_UBOOT,
++		.offset     = 0x000000,
++		.mask_flags = MTD_CAP_ROM
++	}, {
++		.name       = "initramfs",
++		.size       = PSIZE_INITRAMFS,
++		.offset     = PSIZE_UBOOT
++	}, {
++		.name       = "opt",
++		.size       = FLASH_SIZE - (PSIZE_UBOOT + PSIZE_INITRAMFS),
++		.offset     = PSIZE_UBOOT + PSIZE_INITRAMFS,
++	}
++};
++
++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 = "m25p64",
++};
++
++/* 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_MMC) || defined(CONFIG_SPI_MMC_MODULE)
++static struct bfin5xx_spi_chip spi_mmc_chip_info = {
++	.enable_dma = 1,
++	.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_MMC) || defined(CONFIG_SPI_MMC_MODULE)
++	{
++		.modalias = "spi_mmc_dummy",
++		.max_speed_hz = 5000000,     /* 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 = 5000000,     /* 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
++};
++
++/* 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 */
++};
++
++/* 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[] = {
++	{
++		.start = 0xFFC00400,
++		.end = 0xFFC004FF,
++		.flags = IORESOURCE_MEM,
++	}, {
++		.start = 0xFFC02000,
++		.end = 0xFFC020FF,
++		.flags = IORESOURCE_MEM,
++	},
++};
++
++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_I2C_BLACKFIN_TWI) || defined(CONFIG_I2C_BLACKFIN_TWI_MODULE)
++static struct resource bfin_twi0_resource[] = {
++	[0] = {
++		.start = TWI0_REGBASE,
++		.end   = TWI0_REGBASE + 0xFF,
++		.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
++
++#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
++
++static struct platform_device *minotaur_devices[] __initdata = {
++#if defined(CONFIG_BFIN_CFPCMCIA) || defined(CONFIG_BFIN_CFPCMCIA_MODULE)
++	&bfin_pcmcia_cf_device,
++#endif
++
++#if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE)
++	&rtc_device,
++#endif
++
++#if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
++	&bfin_mac_device,
++#endif
++
++#if defined(CONFIG_USB_NET2272) || defined(CONFIG_USB_NET2272_MODULE)
++	&net2272_bfin_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_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
++
++};
++
++static int __init minotaur_init(void)
++{
++	printk(KERN_INFO "%s(): registering device resources\n", __FUNCTION__);
++	platform_add_devices(minotaur_devices, ARRAY_SIZE(minotaur_devices));
++#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
++	spi_register_board_info(bfin_spi_board_info,
++				ARRAY_SIZE(bfin_spi_board_info));
++#endif
++
++	return 0;
++}
++
++arch_initcall(minotaur_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();
++}
+diff --git a/arch/blackfin/mach-bf537/boards/pnav10.c b/arch/blackfin/mach-bf537/boards/pnav10.c
+index fd5f4a6..509a8a2 100644
+--- a/arch/blackfin/mach-bf537/boards/pnav10.c
++++ b/arch/blackfin/mach-bf537/boards/pnav10.c
+@@ -8,7 +8,7 @@
+  *
+  * Modified:
+  *               Copyright 2005 National ICT Australia (NICTA)
+- *               Copyright 2004-2006 Analog Devices Inc.
++ *               Copyright 2004-2008 Analog Devices Inc.
+  *
+  * Bugs:         Enter bugs at http://blackfin.uclinux.org/
+  *
+@@ -29,6 +29,7 @@
+  */
+ 
+ #include <linux/device.h>
++#include <linux/etherdevice.h>
+ #include <linux/platform_device.h>
+ #include <linux/mtd/mtd.h>
+ #include <linux/mtd/partitions.h>
+@@ -133,12 +134,8 @@ static struct resource sl811_hcd_resources[] = {
+ void sl811_port_power(struct device *dev, int is_on)
+ {
+ 	gpio_request(CONFIG_USB_SL811_BFIN_GPIO_VBUS, "usb:SL811_VBUS");
+-	gpio_direction_output(CONFIG_USB_SL811_BFIN_GPIO_VBUS);
++	gpio_direction_output(CONFIG_USB_SL811_BFIN_GPIO_VBUS, is_on);
+ 
+-	if (is_on)
+-		gpio_set_value(CONFIG_USB_SL811_BFIN_GPIO_VBUS, 1);
+-	else
+-		gpio_set_value(CONFIG_USB_SL811_BFIN_GPIO_VBUS, 0);
+ }
+ #endif
+ 
+diff --git a/arch/blackfin/mach-bf537/boards/stamp.c b/arch/blackfin/mach-bf537/boards/stamp.c
+index 07b0dc2..7725415 100644
+--- a/arch/blackfin/mach-bf537/boards/stamp.c
++++ b/arch/blackfin/mach-bf537/boards/stamp.c
+@@ -32,6 +32,7 @@
+ #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>
+ #if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE)
+@@ -103,6 +104,30 @@ void __exit bfin_isp1761_exit(void)
+ arch_initcall(bfin_isp1761_init);
+ #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_PF2, 1, "gpio-keys: BTN0"},
++	{BTN_1, GPIO_PF3, 1, "gpio-keys: BTN1"},
++	{BTN_2, GPIO_PF4, 1, "gpio-keys: BTN2"},
++	{BTN_3, GPIO_PF5, 1, "gpio-keys: BTN3"},
++};
++
++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
++
+ #if defined(CONFIG_BFIN_CFPCMCIA) || defined(CONFIG_BFIN_CFPCMCIA_MODULE)
+ static struct resource bfin_pcmcia_cf_resources[] = {
+ 	{
+@@ -226,12 +251,7 @@ static struct resource sl811_hcd_resources[] = {
+ void sl811_port_power(struct device *dev, int is_on)
+ {
+ 	gpio_request(CONFIG_USB_SL811_BFIN_GPIO_VBUS, "usb:SL811_VBUS");
+-	gpio_direction_output(CONFIG_USB_SL811_BFIN_GPIO_VBUS);
+-
+-	if (is_on)
+-		gpio_set_value(CONFIG_USB_SL811_BFIN_GPIO_VBUS, 1);
+-	else
+-		gpio_set_value(CONFIG_USB_SL811_BFIN_GPIO_VBUS, 0);
++	gpio_direction_output(CONFIG_USB_SL811_BFIN_GPIO_VBUS, is_on);
+ }
+ #endif
+ 
+@@ -320,6 +340,49 @@ static struct platform_device net2272_bfin_device = {
+ };
+ #endif
+ 
++static struct mtd_partition stamp_partitions[] = {
++	{
++		.name       = "Bootloader",
++		.size       = 0x20000,
++		.offset     = 0,
++	}, {
++		.name       = "Kernel",
++		.size       = 0xE0000,
++		.offset     = MTDPART_OFS_APPEND,
++	}, {
++		.name       = "RootFS",
++		.size       = 0x400000 - 0x20000 - 0xE0000 - 0x10000,
++		.offset     = MTDPART_OFS_APPEND,
++	}, {
++		.name       = "MAC Address",
++		.size       = MTDPART_SIZ_FULL,
++		.offset     = 0x3F0000,
++		.mask_flags = MTD_WRITEABLE,
++	}
++};
++
++static struct physmap_flash_data stamp_flash_data = {
++	.width      = 2,
++	.parts      = stamp_partitions,
++	.nr_parts   = ARRAY_SIZE(stamp_partitions),
++};
++
++static struct resource stamp_flash_resource = {
++	.start = 0x20000000,
++	.end   = 0x203fffff,
++	.flags = IORESOURCE_MEM,
++};
++
++static struct platform_device stamp_flash_device = {
++	.name          = "physmap-flash",
++	.id            = 0,
++	.dev = {
++		.platform_data = &stamp_flash_data,
++	},
++	.num_resources = 1,
++	.resource      = &stamp_flash_resource,
++};
++
+ #if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+ /* all SPI peripherals info goes here */
+ 
+@@ -738,6 +801,11 @@ static struct platform_device *stamp_devices[] __initdata = {
+ #if defined(CONFIG_PATA_PLATFORM) || defined(CONFIG_PATA_PLATFORM_MODULE)
+ 	&bfin_pata_device,
+ #endif
++
++#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
++	&bfin_device_gpiokeys,
++#endif
++	&stamp_flash_device,
+ };
+ 
+ static int __init stamp_init(void)
+diff --git a/arch/blackfin/mach-bf548/Kconfig b/arch/blackfin/mach-bf548/Kconfig
+index d8bd3b4..1bfcd8f 100644
+--- a/arch/blackfin/mach-bf548/Kconfig
++++ b/arch/blackfin/mach-bf548/Kconfig
+@@ -7,7 +7,7 @@ menu "BF548 Specific Configuration"
+ config DEB_DMA_URGENT
+ 	bool "DMA has priority over core for ext. accesses"
+ 	depends on BF54x
+-	default n
++	default y
+ 	help
+ 	  Treat any DEB1, DEB2 and DEB3 request as Urgent
+ 
+diff --git a/arch/blackfin/mach-bf548/boards/ezkit.c b/arch/blackfin/mach-bf548/boards/ezkit.c
+index d37d665..14860f0 100644
+--- a/arch/blackfin/mach-bf548/boards/ezkit.c
++++ b/arch/blackfin/mach-bf548/boards/ezkit.c
+@@ -32,6 +32,7 @@
+ #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/irq.h>
+@@ -206,23 +207,6 @@ static struct platform_device smsc911x_device = {
+ };
+ #endif
+ 
+-#if defined(CONFIG_USB_BF54x_HCD) || defined(CONFIG_USB_BF54x_HCD_MODULE)
+-static struct resource bf54x_hcd_resources[] = {
+-	{
+-		.start = 0xFFC03C00,
+-		.end = 0xFFC040FF,
+-		.flags = IORESOURCE_MEM,
+-	},
+-};
+-
+-static struct platform_device bf54x_hcd = {
+-	.name = "bf54x-hcd",
+-	.id = 0,
+-	.num_resources = ARRAY_SIZE(bf54x_hcd_resources),
+-	.resource = bf54x_hcd_resources,
+-};
+-#endif
+-
+ #if defined(CONFIG_USB_MUSB_HDRC) || defined(CONFIG_USB_MUSB_HDRC_MODULE)
+ static struct resource musb_resources[] = {
+ 	[0] = {
+@@ -243,14 +227,14 @@ static struct resource musb_resources[] = {
+ };
+ 
+ static struct musb_hdrc_platform_data musb_plat = {
+-#ifdef CONFIG_USB_MUSB_OTG
++#if defined(CONFIG_USB_MUSB_OTG)
+ 	.mode		= MUSB_OTG,
+-#elif CONFIG_USB_MUSB_HDRC_HCD
++#elif defined(CONFIG_USB_MUSB_HDRC_HCD)
+ 	.mode		= MUSB_HOST,
+-#elif CONFIG_USB_GADGET_MUSB_HDRC
++#elif defined(CONFIG_USB_GADGET_MUSB_HDRC)
+ 	.mode		= MUSB_PERIPHERAL,
+ #endif
+-	.multipoint	= 1,
++	.multipoint	= 0,
+ };
+ 
+ static u64 musb_dmamask = ~(u32)0;
+@@ -344,6 +328,44 @@ static struct platform_device bf54x_sdh_device = {
+ };
+ #endif
+ 
++static struct mtd_partition ezkit_partitions[] = {
++	{
++		.name       = "Bootloader",
++		.size       = 0x20000,
++		.offset     = 0,
++	}, {
++		.name       = "Kernel",
++		.size       = 0xE0000,
++		.offset     = MTDPART_OFS_APPEND,
++	}, {
++		.name       = "RootFS",
++		.size       = MTDPART_SIZ_FULL,
++		.offset     = MTDPART_OFS_APPEND,
++	}
++};
++
++static struct physmap_flash_data ezkit_flash_data = {
++	.width      = 2,
++	.parts      = ezkit_partitions,
++	.nr_parts   = ARRAY_SIZE(ezkit_partitions),
++};
++
++static struct resource ezkit_flash_resource = {
++	.start = 0x20000000,
++	.end   = 0x20ffffff,
++	.flags = IORESOURCE_MEM,
++};
++
++static struct platform_device ezkit_flash_device = {
++	.name          = "physmap-flash",
++	.id            = 0,
++	.dev = {
++		.platform_data = &ezkit_flash_data,
++	},
++	.num_resources = 1,
++	.resource      = &ezkit_flash_resource,
++};
++
+ #if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+ /* all SPI peripherals info goes here */
+ #if defined(CONFIG_MTD_M25P80) \
+@@ -531,6 +553,29 @@ static struct platform_device i2c_bfin_twi1_device = {
+ #endif
+ #endif
+ 
++#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
++#include <linux/gpio_keys.h>
++
++static struct gpio_keys_button bfin_gpio_keys_table[] = {
++	{BTN_0, GPIO_PB8, 1, "gpio-keys: BTN0"},
++	{BTN_1, GPIO_PB9, 1, "gpio-keys: BTN1"},
++	{BTN_2, GPIO_PB10, 1, "gpio-keys: BTN2"},
++	{BTN_3, GPIO_PB11, 1, "gpio-keys: BTN3"},
++};
++
++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 platform_device *ezkit_devices[] __initdata = {
+ #if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE)
+ 	&rtc_device,
+@@ -548,10 +593,6 @@ static struct platform_device *ezkit_devices[] __initdata = {
+ 	&smsc911x_device,
+ #endif
+ 
+-#if defined(CONFIG_USB_BF54x_HCD) || defined(CONFIG_USB_BF54x_HCD_MODULE)
+-	&bf54x_hcd,
+-#endif
+-
+ #if defined(CONFIG_USB_MUSB_HDRC) || defined(CONFIG_USB_MUSB_HDRC_MODULE)
+ 	&musb_device,
+ #endif
+@@ -583,6 +624,11 @@ static struct platform_device *ezkit_devices[] __initdata = {
+ 	&i2c_bfin_twi1_device,
+ #endif
+ #endif
++
++#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
++	&bfin_device_gpiokeys,
++#endif
++	&ezkit_flash_device,
+ };
+ 
+ static int __init stamp_init(void)
+diff --git a/arch/blackfin/mach-bf548/head.S b/arch/blackfin/mach-bf548/head.S
+index 74b34c7..74fe258 100644
+--- a/arch/blackfin/mach-bf548/head.S
++++ b/arch/blackfin/mach-bf548/head.S
+@@ -298,8 +298,8 @@ ENTRY(_start_dma_code)
+ 	w[p0] = r0.l;
+ 	ssync;
+ 
+-	p0.h = hi(SIC_IWR);
+-	p0.l = lo(SIC_IWR);
++	p0.h = hi(SIC_IWR0);
++	p0.l = lo(SIC_IWR0);
+ 	r0.l = 0x1;
+ 	r0.h = 0x0;
+ 	[p0] = r0;
+@@ -324,12 +324,25 @@ ENTRY(_start_dma_code)
+ 	w[p0] = r0.l;
+ 	ssync;
+ 
++#if defined(CONFIG_BF54x)
++	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)
++.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,                  */
+@@ -361,6 +374,39 @@ ENTRY(_start_dma_code)
+ 	w[p0] = r0.l;
+ 	ssync;
+ 
++#if defined(CONFIG_BF54x)
++	P2.H = hi(EBIU_RSTCTL);
++	P2.L = lo(EBIU_RSTCTL);
++	R0 = [P2];
++	CC = BITTST(R0, 0);
++	if CC jump .Lskipddrrst;
++	BITSET (R0, 0);
++.Lskipddrrst:
++	BITCLR (R0, 3);
++	[P2] = R0;
++	SSYNC;
++
++	p0.l = lo(EBIU_DDRCTL0);
++	p0.h = hi(EBIU_DDRCTL0);
++	r0.l = lo(mem_DDRCTL0);
++	r0.h = hi(mem_DDRCTL0);
++	[p0] = r0;
++	ssync;
++
++	p0.l = lo(EBIU_DDRCTL1);
++	p0.h = hi(EBIU_DDRCTL1);
++	r0.l = lo(mem_DDRCTL1);
++	r0.h = hi(mem_DDRCTL1);
++	[p0] = r0;
++	ssync;
++
++	p0.l = lo(EBIU_DDRCTL2);
++	p0.h = hi(EBIU_DDRCTL2);
++	r0.l = lo(mem_DDRCTL2);
++	r0.h = hi(mem_DDRCTL2);
++	[p0] = r0;
++	ssync;
++#else
+ 	p0.l = lo(EBIU_SDRRC);
+ 	p0.h = hi(EBIU_SDRRC);
+ 	r0 = mem_SDRRC;
+@@ -394,9 +440,10 @@ ENTRY(_start_dma_code)
+ 	R1 = R1 | R0;
+ 	[P2] = R1;
+ 	SSYNC;
++#endif
+ 
+-	p0.h = hi(SIC_IWR);
+-	p0.l = lo(SIC_IWR);
++	p0.h = hi(SIC_IWR0);
++	p0.l = lo(SIC_IWR0);
+ 	r0.l = lo(IWR_ENABLE_ALL);
+ 	r0.h = hi(IWR_ENABLE_ALL);
+ 	[p0] = r0;
+diff --git a/arch/blackfin/mach-bf548/ints-priority.c b/arch/blackfin/mach-bf548/ints-priority.c
+index cb0ebac..2665653 100644
+--- a/arch/blackfin/mach-bf548/ints-priority.c
++++ b/arch/blackfin/mach-bf548/ints-priority.c
+@@ -4,7 +4,7 @@
+  * Author:       Michael Hennerich
+  *
+  * Created:
+- * Description:  Set up the interupt priorities
++ * Description:  Set up the interrupt priorities
+  *
+  * Modified:
+  *               Copyright 2004-2006 Analog Devices Inc.
+@@ -58,7 +58,7 @@ void program_IAR(void)
+ 			    ((CONFIG_IRQ_PINT1 - 7) << IRQ_PINT1_POS) |
+ 			    ((CONFIG_IRQ_MDMAS0 - 7) << IRQ_MDMAS0_POS) |
+ 			    ((CONFIG_IRQ_MDMAS1 - 7) << IRQ_MDMAS1_POS) |
+-			    ((CONFIG_IRQ_WATCHDOG - 7) << IRQ_WATCHDOG_POS));
++			    ((CONFIG_IRQ_WATCHDOG - 7) << IRQ_WATCH_POS));
+ 
+ 	bfin_write_SIC_IAR3(((CONFIG_IRQ_DMAC1_ERR - 7) << IRQ_DMAC1_ERR_POS) |
+ 			    ((CONFIG_IRQ_SPORT2_ERR - 7) << IRQ_SPORT2_ERR_POS) |
+diff --git a/arch/blackfin/mach-bf561/boards/cm_bf561.c b/arch/blackfin/mach-bf561/boards/cm_bf561.c
+index c19cd29..3a79a90 100644
+--- a/arch/blackfin/mach-bf561/boards/cm_bf561.c
++++ b/arch/blackfin/mach-bf561/boards/cm_bf561.c
+@@ -198,6 +198,13 @@ static struct platform_device bfin_spi0_device = {
+ #endif  /* spi master and devices */
+ 
+ 
++#if defined(CONFIG_FB_HITACHI_TX09) || defined(CONFIG_FB_HITACHI_TX09_MODULE)
++static struct platform_device hitachi_fb_device = {
++	.name = "hitachi-tx09",
++};
++#endif
++
++
+ #if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
+ 
+ static struct resource smc91x_resources[] = {
+@@ -315,6 +322,10 @@ static struct platform_device bfin_pata_device = {
+ 
+ static struct platform_device *cm_bf561_devices[] __initdata = {
+ 
++#if defined(CONFIG_FB_HITACHI_TX09) || defined(CONFIG_FB_HITACHI_TX09_MODULE)
++	&hitachi_fb_device,
++#endif
++
+ #if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
+ 	&bfin_uart_device,
+ #endif
+diff --git a/arch/blackfin/mach-bf561/boards/ezkit.c b/arch/blackfin/mach-bf561/boards/ezkit.c
+index 4ff8f6e..7601c3b 100644
+--- a/arch/blackfin/mach-bf561/boards/ezkit.c
++++ b/arch/blackfin/mach-bf561/boards/ezkit.c
+@@ -29,6 +29,9 @@
+ 
+ #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/irq.h>
+ #include <linux/interrupt.h>
+@@ -155,6 +158,44 @@ static struct platform_device bfin_uart_device = {
+ };
+ #endif
+ 
++static struct mtd_partition ezkit_partitions[] = {
++	{
++		.name       = "Bootloader",
++		.size       = 0x20000,
++		.offset     = 0,
++	}, {
++		.name       = "Kernel",
++		.size       = 0xE0000,
++		.offset     = MTDPART_OFS_APPEND,
++	}, {
++		.name       = "RootFS",
++		.size       = MTDPART_SIZ_FULL,
++		.offset     = MTDPART_OFS_APPEND,
++	}
++};
++
++static struct physmap_flash_data ezkit_flash_data = {
++	.width      = 2,
++	.parts      = ezkit_partitions,
++	.nr_parts   = ARRAY_SIZE(ezkit_partitions),
++};
++
++static struct resource ezkit_flash_resource = {
++	.start = 0x20000000,
++	.end   = 0x207fffff,
++	.flags = IORESOURCE_MEM,
++};
++
++static struct platform_device ezkit_flash_device = {
++	.name          = "physmap-flash",
++	.id            = 0,
++	.dev = {
++		.platform_data = &ezkit_flash_data,
++	},
++	.num_resources = 1,
++	.resource      = &ezkit_flash_resource,
++};
++
+ #ifdef CONFIG_SPI_BFIN
+ #if defined(CONFIG_SND_BLACKFIN_AD1836) \
+ 	|| defined(CONFIG_SND_BLACKFIN_AD1836_MODULE)
+@@ -246,6 +287,50 @@ static struct platform_device bfin_pata_device = {
+ };
+ #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_PF5, 1, "gpio-keys: BTN0"},
++	{BTN_1, GPIO_PF6, 1, "gpio-keys: BTN1"},
++	{BTN_2, GPIO_PF7, 1, "gpio-keys: BTN2"},
++	{BTN_3, GPIO_PF8, 1, "gpio-keys: BTN3"},
++};
++
++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
++
++#if defined(CONFIG_I2C_GPIO) || defined(CONFIG_I2C_GPIO_MODULE)
++#include <linux/i2c-gpio.h>
++
++static struct i2c_gpio_platform_data i2c_gpio_data = {
++	.sda_pin		= 1,
++	.scl_pin		= 0,
++	.sda_is_open_drain	= 0,
++	.scl_is_open_drain	= 0,
++	.udelay			= 40,
++};
++
++static struct platform_device i2c_gpio_device = {
++	.name		= "i2c-gpio",
++	.id		= 0,
++	.dev		= {
++		.platform_data	= &i2c_gpio_data,
++	},
++};
++#endif
++
+ static struct platform_device *ezkit_devices[] __initdata = {
+ #if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
+ 	&smc91x_device,
+@@ -258,12 +343,23 @@ static struct platform_device *ezkit_devices[] __initdata = {
+ #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_PATA_PLATFORM) || defined(CONFIG_PATA_PLATFORM_MODULE)
+ 	&bfin_pata_device,
+ #endif
++
++#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
++	&bfin_device_gpiokeys,
++#endif
++
++#if defined(CONFIG_I2C_GPIO) || defined(CONFIG_I2C_GPIO_MODULE)
++	&i2c_gpio_device,
++#endif
++	&ezkit_flash_device,
+ };
+ 
+ static int __init ezkit_init(void)
+diff --git a/arch/blackfin/mach-bf561/coreb.c b/arch/blackfin/mach-bf561/coreb.c
+index 5d1d21b..1b44e9e 100644
+--- a/arch/blackfin/mach-bf561/coreb.c
++++ b/arch/blackfin/mach-bf561/coreb.c
+@@ -33,7 +33,9 @@
+ #include <linux/ioport.h>
+ #include <linux/module.h>
+ #include <linux/uaccess.h>
++#include <linux/fs.h>
+ #include <asm/dma.h>
++#include <asm/cacheflush.h>
+ 
+ #define MODULE_VER		"v0.1"
+ 
+@@ -90,11 +92,12 @@ static ssize_t coreb_write(struct file *file, const char *buf, size_t count,
+ 
+ 		coreb_dma_done = 0;
+ 
++		flush_dcache_range((unsigned long)buf, (unsigned long)(buf+len));
+ 		/* Source Channel */
+ 		set_dma_start_addr(CH_MEM_STREAM2_SRC, (unsigned long)buf);
+ 		set_dma_x_count(CH_MEM_STREAM2_SRC, len);
+ 		set_dma_x_modify(CH_MEM_STREAM2_SRC, sizeof(char));
+-		set_dma_config(CH_MEM_STREAM2_SRC, RESTART);
++		set_dma_config(CH_MEM_STREAM2_SRC, 0);
+ 		/* Destination Channel */
+ 		set_dma_start_addr(CH_MEM_STREAM2_DEST, coreb_base + p);
+ 		set_dma_x_count(CH_MEM_STREAM2_DEST, len);
+@@ -135,11 +138,12 @@ static ssize_t coreb_read(struct file *file, char *buf, size_t count,
+ 
+ 		coreb_dma_done = 0;
+ 
++		invalidate_dcache_range((unsigned long)buf, (unsigned long)(buf+len));
+ 		/* Source Channel */
+ 		set_dma_start_addr(CH_MEM_STREAM2_SRC, coreb_base + p);
+ 		set_dma_x_count(CH_MEM_STREAM2_SRC, len);
+ 		set_dma_x_modify(CH_MEM_STREAM2_SRC, sizeof(char));
+-		set_dma_config(CH_MEM_STREAM2_SRC, RESTART);
++		set_dma_config(CH_MEM_STREAM2_SRC, 0);
+ 		/* Destination Channel */
+ 		set_dma_start_addr(CH_MEM_STREAM2_DEST, (unsigned long)buf);
+ 		set_dma_x_count(CH_MEM_STREAM2_DEST, len);
+@@ -266,7 +270,7 @@ static int coreb_ioctl(struct inode *inode, struct file *file,
+ 		coreb_status |= COREB_IS_RUNNING;
+ 		bfin_write_SICA_SYSCR(bfin_read_SICA_SYSCR() & ~0x0020);
+ 		SSYNC();
+-		spin_lock_irq(&coreb_lock);
++		spin_unlock_irq(&coreb_lock);
+ 		break;
+ #if defined(CONFIG_BF561_COREB_RESET)
+ 	case CMD_COREB_STOP:
+@@ -275,7 +279,7 @@ static int coreb_ioctl(struct inode *inode, struct file *file,
+ 		bfin_write_SICA_SYSCR(bfin_read_SICA_SYSCR() | 0x0020);
+ 		bfin_write_SICB_SYSCR(bfin_read_SICB_SYSCR() | 0x0080);
+ 		coreb_status &= ~COREB_IS_RUNNING;
+-		spin_lock_irq(&coreb_lock);
++		spin_unlock_irq(&coreb_lock);
+ 		break;
+ 	case CMD_COREB_RESET:
+ 		printk(KERN_INFO "Resetting Core B\n");
+diff --git a/arch/blackfin/mach-common/Makefile b/arch/blackfin/mach-common/Makefile
+index 4d7733d..8636d42 100644
+--- a/arch/blackfin/mach-common/Makefile
++++ b/arch/blackfin/mach-common/Makefile
+@@ -3,10 +3,9 @@
+ #
+ 
+ obj-y := \
+-	cache.o cacheinit.o cplbhdlr.o cplbmgr.o entry.o \
++	cache.o cacheinit.o entry.o \
+ 	interrupt.o lock.o irqpanic.o arch_checks.o
+ 
+-obj-$(CONFIG_CPLB_INFO)          += cplbinfo.o
+ obj-$(CONFIG_BFIN_SINGLE_CORE)   += ints-priority-sc.o
+ obj-$(CONFIG_BFIN_DUAL_CORE)     += ints-priority-dc.o
+ obj-$(CONFIG_PM)                 += pm.o dpmc.o
+diff --git a/arch/blackfin/mach-common/cplbhdlr.S b/arch/blackfin/mach-common/cplbhdlr.S
+deleted file mode 100644
+index 2788532..0000000
+--- a/arch/blackfin/mach-common/cplbhdlr.S
++++ /dev/null
+@@ -1,130 +0,0 @@
+-/*
+- * File:         arch/blackfin/mach-common/cplbhdlr.S
+- * Based on:
+- * Author:       LG Soft India
+- *
+- * Created:      ?
+- * Description:  CPLB exception handler
+- *
+- * Modified:
+- *               Copyright 2004-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
+- */
+-
+-#include <linux/linkage.h>
+-#include <asm/cplb.h>
+-#include <asm/entry.h>
+-
+-#ifdef CONFIG_EXCPT_IRQ_SYSC_L1
+-.section .l1.text
+-#else
+-.text
+-#endif
+-
+-.type _cplb_mgr, STT_FUNC;
+-.type _panic_cplb_error, STT_FUNC;
+-
+-.align 2
+-
+-ENTRY(__cplb_hdr)
+-	R2 = SEQSTAT;
+-
+-	/* Mask the contents of SEQSTAT and leave only EXCAUSE in R2 */
+-	R2 <<= 26;
+-	R2 >>= 26;
+-
+-	R1 = 0x23; /* Data access CPLB protection violation */
+-	CC = R2 == R1;
+-	IF !CC JUMP .Lnot_data_write;
+-	R0 = 2;		/* is a write to data space*/
+-	JUMP .Lis_icplb_miss;
+-
+-.Lnot_data_write:
+-	R1 = 0x2C; /* CPLB miss on an instruction fetch */
+-	CC = R2 == R1;
+-	R0 = 0;		/* is_data_miss == False*/
+-	IF CC JUMP .Lis_icplb_miss;
+-
+-	R1 = 0x26;
+-	CC = R2 == R1;
+-	IF !CC JUMP .Lunknown;
+-
+-	R0 = 1;		/* is_data_miss == True*/
+-
+-.Lis_icplb_miss:
+-
+-#if defined(CONFIG_BFIN_ICACHE) || defined(CONFIG_BFIN_DCACHE)
+-# if defined(CONFIG_BFIN_ICACHE) && !defined(CONFIG_BFIN_DCACHE)
+-	R1 = CPLB_ENABLE_ICACHE;
+-# endif
+-# if !defined(CONFIG_BFIN_ICACHE) && defined(CONFIG_BFIN_DCACHE)
+-	R1 = CPLB_ENABLE_DCACHE;
+-# endif
+-# if defined(CONFIG_BFIN_ICACHE) && defined(CONFIG_BFIN_DCACHE)
+-	R1 = CPLB_ENABLE_DCACHE | CPLB_ENABLE_ICACHE;
+-# endif
+-#else
+-	R1 = 0;
+-#endif
+-
+-	[--SP] = RETS;
+-	CALL _cplb_mgr;
+-	RETS = [SP++];
+-	CC = R0 == 0;
+-	IF !CC JUMP .Lnot_replaced;
+-	RTS;
+-
+-/*
+- * Diagnostic exception handlers
+- */
+-.Lunknown:
+-	R0 = CPLB_UNKNOWN_ERR;
+-	JUMP .Lcplb_error;
+-
+-.Lnot_replaced:
+-	CC = R0 == CPLB_NO_UNLOCKED;
+-	IF !CC JUMP .Lnext_check;
+-	R0 = CPLB_NO_UNLOCKED;
+-	JUMP .Lcplb_error;
+-
+-.Lnext_check:
+-	CC = R0 == CPLB_NO_ADDR_MATCH;
+-	IF !CC JUMP .Lnext_check2;
+-	R0 = CPLB_NO_ADDR_MATCH;
+-	JUMP .Lcplb_error;
+-
+-.Lnext_check2:
+-	CC = R0 == CPLB_PROT_VIOL;
+-	IF !CC JUMP .Lstrange_return_from_cplb_mgr;
+-	R0 = CPLB_PROT_VIOL;
+-	JUMP .Lcplb_error;
+-
+-.Lstrange_return_from_cplb_mgr:
+-	IDLE;
+-	CSYNC;
+-	JUMP .Lstrange_return_from_cplb_mgr;
+-
+-.Lcplb_error:
+-	R1 = sp;
+-	SP += -12;
+-	call _panic_cplb_error;
+-	SP += 12;
+-	JUMP _handle_bad_cplb;
+-
+-ENDPROC(__cplb_hdr)
+diff --git a/arch/blackfin/mach-common/cplbinfo.c b/arch/blackfin/mach-common/cplbinfo.c
+deleted file mode 100644
+index a4f0b42..0000000
+--- a/arch/blackfin/mach-common/cplbinfo.c
++++ /dev/null
+@@ -1,208 +0,0 @@
+-/*
+- * File:         arch/blackfin/mach-common/cplbinfo.c
+- * Based on:
+- * Author:       Sonic Zhang <sonic.zhang at analog.com>
+- *
+- * Created:      Jan. 2005
+- * Description:  Display CPLB status
+- *
+- * Modified:
+- *               Copyright 2004-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
+- */
+-
+-#include <linux/module.h>
+-#include <linux/kernel.h>
+-#include <linux/init.h>
+-#include <linux/proc_fs.h>
+-#include <linux/uaccess.h>
+-
+-#include <asm/current.h>
+-#include <asm/system.h>
+-#include <asm/cplb.h>
+-#include <asm/blackfin.h>
+-
+-#define CPLB_I 1
+-#define CPLB_D 2
+-
+-#define SYNC_SYS    SSYNC()
+-#define SYNC_CORE   CSYNC()
+-
+-#define CPLB_BIT_PAGESIZE 0x30000
+-
+-static int page_size_table[4] = {
+-	0x00000400,		/* 1K */
+-	0x00001000,		/* 4K */
+-	0x00100000,		/* 1M */
+-	0x00400000		/* 4M */
+-};
+-
+-static char page_size_string_table[][4] = { "1K", "4K", "1M", "4M" };
+-
+-static int cplb_find_entry(unsigned long *cplb_addr,
+-			   unsigned long *cplb_data, unsigned long addr,
+-			   unsigned long data)
+-{
+-	int ii;
+-
+-	for (ii = 0; ii < 16; ii++)
+-		if (addr >= cplb_addr[ii] && addr < cplb_addr[ii] +
+-		    page_size_table[(cplb_data[ii] & CPLB_BIT_PAGESIZE) >> 16]
+-			&& (cplb_data[ii] == data))
+-			return ii;
+-
+-	return -1;
+-}
+-
+-static char *cplb_print_entry(char *buf, int type)
+-{
+-	unsigned long *p_addr = dpdt_table;
+-	unsigned long *p_data = dpdt_table + 1;
+-	unsigned long *p_icount = dpdt_swapcount_table;
+-	unsigned long *p_ocount = dpdt_swapcount_table + 1;
+-	unsigned long *cplb_addr = (unsigned long *)DCPLB_ADDR0;
+-	unsigned long *cplb_data = (unsigned long *)DCPLB_DATA0;
+-	int entry = 0, used_cplb = 0;
+-
+-	if (type == CPLB_I) {
+-		buf += sprintf(buf, "Instruction CPLB entry:\n");
+-		p_addr = ipdt_table;
+-		p_data = ipdt_table + 1;
+-		p_icount = ipdt_swapcount_table;
+-		p_ocount = ipdt_swapcount_table + 1;
+-		cplb_addr = (unsigned long *)ICPLB_ADDR0;
+-		cplb_data = (unsigned long *)ICPLB_DATA0;
+-	} else
+-		buf += sprintf(buf, "Data CPLB entry:\n");
+-
+-	buf += sprintf(buf, "Address\t\tData\tSize\tValid\tLocked\tSwapin\tiCount\toCount\n");
+-
+-	while (*p_addr != 0xffffffff) {
+-		entry = cplb_find_entry(cplb_addr, cplb_data, *p_addr, *p_data);
+-		if (entry >= 0)
+-			used_cplb |= 1 << entry;
+-
+-		buf +=
+-		    sprintf(buf,
+-			    "0x%08lx\t0x%05lx\t%s\t%c\t%c\t%2d\t%ld\t%ld\n",
+-			    *p_addr, *p_data,
+-			    page_size_string_table[(*p_data & 0x30000) >> 16],
+-			    (*p_data & CPLB_VALID) ? 'Y' : 'N',
+-			    (*p_data & CPLB_LOCK) ? 'Y' : 'N', entry, *p_icount,
+-			    *p_ocount);
+-
+-		p_addr += 2;
+-		p_data += 2;
+-		p_icount += 2;
+-		p_ocount += 2;
+-	}
+-
+-	if (used_cplb != 0xffff) {
+-		buf += sprintf(buf, "Unused/mismatched CPLBs:\n");
+-
+-		for (entry = 0; entry < 16; entry++)
+-			if (0 == ((1 << entry) & used_cplb)) {
+-				int flags = cplb_data[entry];
+-				buf +=
+-				    sprintf(buf,
+-					    "%2d: 0x%08lx\t0x%05x\t%s\t%c\t%c\n",
+-					    entry, cplb_addr[entry], flags,
+-					    page_size_string_table[(flags &
+-								    0x30000) >>
+-								   16],
+-					    (flags & CPLB_VALID) ? 'Y' : 'N',
+-					    (flags & CPLB_LOCK) ? 'Y' : 'N');
+-			}
+-	}
+-
+-	buf += sprintf(buf, "\n");
+-
+-	return buf;
+-}
+-
+-static int cplbinfo_proc_output(char *buf)
+-{
+-	char *p;
+-
+-	p = buf;
+-
+-	p += sprintf(p, "------------------ CPLB Information ------------------\n\n");
+-
+-	if (bfin_read_IMEM_CONTROL() & ENICPLB)
+-		p = cplb_print_entry(p, CPLB_I);
+-	else
+-		p += sprintf(p, "Instruction CPLB is disabled.\n\n");
+-
+-	if (bfin_read_DMEM_CONTROL() & ENDCPLB)
+-		p = cplb_print_entry(p, CPLB_D);
+-	else
+-		p += sprintf(p, "Data CPLB is disabled.\n");
+-
+-	return p - buf;
+-}
+-
+-static int cplbinfo_read_proc(char *page, char **start, off_t off,
+-			      int count, int *eof, void *data)
+-{
+-	int len;
+-
+-	len = cplbinfo_proc_output(page);
+-	if (len <= off + count)
+-		*eof = 1;
+-	*start = page + off;
+-	len -= off;
+-	if (len > count)
+-		len = count;
+-	if (len < 0)
+-		len = 0;
+-	return len;
+-}
+-
+-static int cplbinfo_write_proc(struct file *file, const char __user *buffer,
+-			       unsigned long count, void *data)
+-{
+-	printk(KERN_INFO "Reset the CPLB swap in/out counts.\n");
+-	memset(ipdt_swapcount_table, 0, MAX_SWITCH_I_CPLBS * sizeof(unsigned long));
+-	memset(dpdt_swapcount_table, 0, MAX_SWITCH_D_CPLBS * sizeof(unsigned long));
+-
+-	return count;
+-}
+-
+-static int __init cplbinfo_init(void)
+-{
+-	struct proc_dir_entry *entry;
+-
+-	entry = create_proc_entry("cplbinfo", 0, NULL);
+-	if (!entry)
+-		return -ENOMEM;
+-
+-	entry->read_proc = cplbinfo_read_proc;
+-	entry->write_proc = cplbinfo_write_proc;
+-	entry->data = NULL;
+-
+-	return 0;
+-}
+-
+-static void __exit cplbinfo_exit(void)
+-{
+-	remove_proc_entry("cplbinfo", NULL);
+-}
+-
+-module_init(cplbinfo_init);
+-module_exit(cplbinfo_exit);
+diff --git a/arch/blackfin/mach-common/cplbmgr.S b/arch/blackfin/mach-common/cplbmgr.S
+deleted file mode 100644
+index 6f909cb..0000000
+--- a/arch/blackfin/mach-common/cplbmgr.S
++++ /dev/null
+@@ -1,619 +0,0 @@
+-/*
+- * File:         arch/blackfin/mach-common/cplbmgtr.S
+- * Based on:
+- * Author:       LG Soft India
+- *
+- * Created:      ?
+- * Description:  CPLB replacement routine for CPLB mismatch
+- *
+- * Modified:
+- *               Copyright 2004-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
+- */
+-
+-/* Usage: int _cplb_mgr(is_data_miss,int enable_cache)
+- * is_data_miss==2 => Mark as Dirty, write to the clean data page
+- * is_data_miss==1 => Replace a data CPLB.
+- * is_data_miss==0 => Replace an instruction CPLB.
+- *
+- * Returns:
+- * CPLB_RELOADED	=> Successfully updated CPLB table.
+- * CPLB_NO_UNLOCKED	=> All CPLBs are locked, so cannot be evicted.
+- *			   This indicates that the CPLBs in the configuration
+- *			   tablei are badly configured, as this should never
+- *			   occur.
+- * CPLB_NO_ADDR_MATCH	=> The address being accessed, that triggered the
+- *			   exception, is not covered by any of the CPLBs in
+- *			   the configuration table. The application is
+- *			   presumably misbehaving.
+- * CPLB_PROT_VIOL	=> The address being accessed, that triggered the
+- *			   exception, was not a first-write to a clean Write
+- *			   Back Data page, and so presumably is a genuine
+- *			   violation of the page's protection attributes.
+- *			   The application is misbehaving.
+- */
+-
+-#include <linux/linkage.h>
+-#include <asm/blackfin.h>
+-#include <asm/cplb.h>
+-
+-#ifdef CONFIG_EXCPT_IRQ_SYSC_L1
+-.section .l1.text
+-#else
+-.text
+-#endif
+-
+-.align 2;
+-ENTRY(_cplb_mgr)
+-
+-	[--SP]=( R7:4,P5:3 );
+-
+-	CC = R0 == 2;
+-	IF CC JUMP .Ldcplb_write;
+-
+-	CC = R0 == 0;
+-	IF !CC JUMP .Ldcplb_miss_compare;
+-
+-	/* ICPLB Miss Exception. We need to choose one of the
+-	* currently-installed CPLBs, and replace it with one
+-	* from the configuration table.
+-	*/
+-
+-	P4.L = LO(ICPLB_FAULT_ADDR);
+-	P4.H = HI(ICPLB_FAULT_ADDR);
+-
+-	P1 = 16;
+-	P5.L = _page_size_table;
+-	P5.H = _page_size_table;
+-
+-	P0.L = LO(ICPLB_DATA0);
+-	P0.H = HI(ICPLB_DATA0);
+-	R4 = [P4];		/* Get faulting address*/
+-	R6 = 64;		/* Advance past the fault address, which*/
+-	R6 = R6 + R4;		/* we'll use if we find a match*/
+-	R3 = ((16 << 8) | 2);	/* Extract mask, bits 16 and 17.*/
+-
+-	R5 = 0;
+-.Lisearch:
+-
+-	R1 = [P0-0x100];	/* Address for this CPLB */
+-
+-	R0 = [P0++];		/* Info for this CPLB*/
+-	CC = BITTST(R0,0);	/* Is the CPLB valid?*/
+-	IF !CC JUMP .Lnomatch;	/* Skip it, if not.*/
+-	CC = R4 < R1(IU);	/* If fault address less than page start*/
+-	IF CC JUMP .Lnomatch;	/* then skip this one.*/
+-	R2 = EXTRACT(R0,R3.L) (Z);	/* Get page size*/
+-	P1 = R2;
+-	P1 = P5 + (P1<<2);	/* index into page-size table*/
+-	R2 = [P1];		/* Get the page size*/
+-	R1 = R1 + R2;		/* and add to page start, to get page end*/
+-	CC = R4 < R1(IU);	/* and see whether fault addr is in page.*/
+-	IF !CC R4 = R6;		/* If so, advance the address and finish loop.*/
+-	IF !CC JUMP .Lisearch_done;
+-.Lnomatch:
+-	/* Go around again*/
+-	R5 += 1;
+-	CC = BITTST(R5, 4);	/* i.e CC = R5 >= 16*/
+-	IF !CC JUMP .Lisearch;
+-
+-.Lisearch_done:
+-	I0 = R4;		/* Fault address we'll search for*/
+-
+-	/* set up pointers */
+-	P0.L = LO(ICPLB_DATA0);
+-	P0.H = HI(ICPLB_DATA0);
+-
+-	/* The replacement procedure for ICPLBs */
+-
+-	P4.L = LO(IMEM_CONTROL);
+-	P4.H = HI(IMEM_CONTROL);
+-
+-	/* disable cplbs */
+-	R5 = [P4];		/* Control Register*/
+-	BITCLR(R5,ENICPLB_P);
+-	CLI R1;
+-	SSYNC;		/* SSYNC required before writing to IMEM_CONTROL. */
+-	.align 8;
+-	[P4] = R5;
+-	SSYNC;
+-	STI R1;
+-
+-	R1 = -1;		/* end point comparison */
+-	R3 = 16;		/* counter */
+-
+-	/* Search through CPLBs for first non-locked entry */
+-	/* Overwrite it by moving everyone else up by 1 */
+-.Licheck_lock:
+-	R0 = [P0++];
+-	R3 = R3 + R1;
+-	CC = R3 == R1;
+-	IF CC JUMP .Lall_locked;
+-	CC = BITTST(R0, 0);		/* an invalid entry is good */
+-	IF !CC JUMP .Lifound_victim;
+-	CC = BITTST(R0,1);		/* but a locked entry isn't */
+-	IF CC JUMP .Licheck_lock;
+-
+-.Lifound_victim:
+-#ifdef CONFIG_CPLB_INFO
+-	R7 = [P0 - 0x104];
+-	P2.L = _ipdt_table;
+-	P2.H = _ipdt_table;
+-	P3.L = _ipdt_swapcount_table;
+-	P3.H = _ipdt_swapcount_table;
+-	P3 += -4;
+-.Licount:
+-	R2 = [P2];	/* address from config table */
+-	P2 += 8;
+-	P3 += 8;
+-	CC = R2==-1;
+-	IF CC JUMP .Licount_done;
+-	CC = R7==R2;
+-	IF !CC JUMP .Licount;
+-	R7 = [P3];
+-	R7 += 1;
+-	[P3] = R7;
+-	CSYNC;
+-.Licount_done:
+-#endif
+-	LC0=R3;
+-	LSETUP(.Lis_move,.Lie_move) LC0;
+-.Lis_move:
+-	R0 = [P0];
+-	[P0 - 4] = R0;
+-	R0 = [P0 - 0x100];
+-	[P0-0x104] = R0;
+-.Lie_move:P0+=4;
+-
+-	/* We've made space in the ICPLB table, so that ICPLB15
+-	 * is now free to be overwritten. Next, we have to determine
+-	 * which CPLB we need to install, from the configuration
+-	 * table. This is a matter of getting the start-of-page
+-	 * addresses and page-lengths from the config table, and
+-	 * determining whether the fault address falls within that
+-	 * range.
+- 	 */
+-
+-	P2.L = _ipdt_table;
+-	P2.H = _ipdt_table;
+-#ifdef	CONFIG_CPLB_INFO
+-	P3.L = _ipdt_swapcount_table;
+-	P3.H = _ipdt_swapcount_table;
+-	P3 += -8;
+-#endif
+-	P0.L = _page_size_table;
+-	P0.H = _page_size_table;
+-
+-	/* Retrieve our fault address (which may have been advanced
+-	 * because the faulting instruction crossed a page boundary).
+-	 */
+-
+-	R0 = I0;
+-
+-	/* An extraction pattern, to get the page-size bits from
+-	 * the CPLB data entry. Bits 16-17, so two bits at posn 16.
+-	 */
+-
+-	R1 = ((16<<8)|2);
+-.Linext:	R4 = [P2++];	/* address from config table */
+-	R2 = [P2++];	/* data from config table */
+-#ifdef	CONFIG_CPLB_INFO
+-	P3 += 8;
+-#endif
+-
+-	CC = R4 == -1;	/* End of config table*/
+-	IF CC JUMP .Lno_page_in_table;
+-
+-	/* See if failed address > start address */
+-	CC = R4 <= R0(IU);
+-	IF !CC JUMP .Linext;
+-
+-	/* extract page size (17:16)*/
+-	R3 = EXTRACT(R2, R1.L) (Z);
+-
+-	/* add page size to addr to get range */
+-
+-	P5 = R3;
+-	P5 = P0 + (P5 << 2);	/* scaled, for int access*/
+-	R3 = [P5];
+-	R3 = R3 + R4;
+-
+-	/* See if failed address < (start address + page size) */
+-	CC = R0 < R3(IU);
+-	IF !CC JUMP .Linext;
+-
+-	/* We've found a CPLB in the config table that covers
+-	 * the faulting address, so install this CPLB into the
+-	 * last entry of the table.
+-	 */
+-
+-	P1.L = LO(ICPLB_DATA15);		/* ICPLB_DATA15 */
+-	P1.H = HI(ICPLB_DATA15);
+-	[P1] = R2;
+-	[P1-0x100] = R4;
+-#ifdef	CONFIG_CPLB_INFO
+-	R3 = [P3];
+-	R3 += 1;
+-	[P3] = R3;
+-#endif
+-
+-	/* P4 points to IMEM_CONTROL, and R5 contains its old
+-	 * value, after we disabled ICPLBS. Re-enable them.
+-	 */
+-
+-	BITSET(R5,ENICPLB_P);
+-	CLI R2;
+-	SSYNC;		/* SSYNC required before writing to IMEM_CONTROL. */
+-	.align 8;
+-	[P4] = R5;
+-	SSYNC;
+-	STI R2;
+-
+-	( R7:4,P5:3 ) = [SP++];
+-	R0 = CPLB_RELOADED;
+-	RTS;
+-
+-/* FAILED CASES*/
+-.Lno_page_in_table:
+-	R0 = CPLB_NO_ADDR_MATCH;
+-	JUMP .Lfail_ret;
+-
+-.Lall_locked:
+-	R0 = CPLB_NO_UNLOCKED;
+-	JUMP .Lfail_ret;
+-
+-.Lprot_violation:
+-	R0 = CPLB_PROT_VIOL;
+-
+-.Lfail_ret:
+-	/* Make sure we turn protection/cache back on, even in the failing case */
+-	BITSET(R5,ENICPLB_P);
+-	CLI R2;
+-	SSYNC;          /* SSYNC required before writing to IMEM_CONTROL. */
+-	.align 8;
+-	[P4] = R5;
+-	SSYNC;
+-	STI R2;
+-
+-	( R7:4,P5:3 ) = [SP++];
+-	RTS;
+-
+-.Ldcplb_write:
+-
+-	/* if a DCPLB is marked as write-back (CPLB_WT==0), and
+-	 * it is clean (CPLB_DIRTY==0), then a write to the
+-	 * CPLB's page triggers a protection violation. We have to
+-	 * mark the CPLB as dirty, to indicate that there are
+-	 * pending writes associated with the CPLB.
+-	 */
+-
+-	P4.L = LO(DCPLB_STATUS);
+-	P4.H = HI(DCPLB_STATUS);
+-	P3.L = LO(DCPLB_DATA0);
+-	P3.H = HI(DCPLB_DATA0);
+-	R5 = [P4];
+-
+-	/* A protection violation can be caused by more than just writes
+-	 * to a clean WB page, so we have to ensure that:
+-	 * - It's a write
+-	 * - to a clean WB page
+-	 * - and is allowed in the mode the access occurred.
+-	 */
+-
+-	CC = BITTST(R5, 16);	/* ensure it was a write*/
+-	IF !CC JUMP .Lprot_violation;
+-
+-	/* to check the rest, we have to retrieve the DCPLB.*/
+-
+-	/* The low half of DCPLB_STATUS is a bit mask*/
+-
+-	R2 = R5.L (Z);	/* indicating which CPLB triggered the event.*/
+-	R3 = 30;	/* so we can use this to determine the offset*/
+-	R2.L = SIGNBITS R2;
+-	R2 = R2.L (Z);	/* into the DCPLB table.*/
+-	R3 = R3 - R2;
+-	P4 = R3;
+-	P3 = P3 + (P4<<2);
+-	R3 = [P3];	/* Retrieve the CPLB*/
+-
+-	/* Now we can check whether it's a clean WB page*/
+-
+-	CC = BITTST(R3, 14);	/* 0==WB, 1==WT*/
+-	IF CC JUMP .Lprot_violation;
+-	CC = BITTST(R3, 7);	/* 0 == clean, 1 == dirty*/
+-	IF CC JUMP .Lprot_violation;
+-
+-	/* Check whether the write is allowed in the mode that was active.*/
+-
+-	R2 = 1<<3;		/* checking write in user mode*/
+-	CC = BITTST(R5, 17);	/* 0==was user, 1==was super*/
+-	R5 = CC;
+-	R2 <<= R5;		/* if was super, check write in super mode*/
+-	R2 = R3 & R2;
+-	CC = R2 == 0;
+-	IF CC JUMP .Lprot_violation;
+-
+-	/* It's a genuine write-to-clean-page.*/
+-
+-	BITSET(R3, 7);		/* mark as dirty*/
+-	[P3] = R3;		/* and write back.*/
+-	NOP;
+-	CSYNC;
+-	( R7:4,P5:3 ) = [SP++];
+-	R0 = CPLB_RELOADED;
+-	RTS;
+-
+-.Ldcplb_miss_compare:
+-
+-	/* Data CPLB Miss event. We need to choose a CPLB to
+-	 * evict, and then locate a new CPLB to install from the
+-	 * config table, that covers the faulting address.
+-	 */
+-
+-	P1.L = LO(DCPLB_DATA15);
+-	P1.H = HI(DCPLB_DATA15);
+-
+-	P4.L = LO(DCPLB_FAULT_ADDR);
+-	P4.H = HI(DCPLB_FAULT_ADDR);
+-	R4 = [P4];
+-	I0 = R4;
+-
+-	/* The replacement procedure for DCPLBs*/
+-
+-	R6 = R1;	/* Save for later*/
+-
+-	/* Turn off CPLBs while we work.*/
+-	P4.L = LO(DMEM_CONTROL);
+-	P4.H = HI(DMEM_CONTROL);
+-	R5 = [P4];
+-	BITCLR(R5,ENDCPLB_P);
+-	CLI R0;
+-	SSYNC;		/* SSYNC required before writing to DMEM_CONTROL. */
+-	.align 8;
+-	[P4] = R5;
+-	SSYNC;
+-	STI R0;
+-
+-	/* Start looking for a CPLB to evict. Our order of preference
+-	 * is: invalid CPLBs, clean CPLBs, dirty CPLBs. Locked CPLBs
+-	 * are no good.
+-	 */
+-
+-	I1.L = LO(DCPLB_DATA0);
+-	I1.H = HI(DCPLB_DATA0);
+-	P1 = 2;
+-	P2 = 16;
+-	I2.L = _dcplb_preference;
+-	I2.H = _dcplb_preference;
+-	LSETUP(.Lsdsearch1, .Ledsearch1) LC0 = P1;
+-.Lsdsearch1:
+-	R0 = [I2++];		/* Get the bits we're interested in*/
+-	P0 = I1;		/* Go back to start of table*/
+-	LSETUP (.Lsdsearch2, .Ledsearch2) LC1 = P2;
+-.Lsdsearch2:
+-	R1 = [P0++];		/* Fetch each installed CPLB in turn*/
+-	R2 = R1 & R0;		/* and test for interesting bits.*/
+-	CC = R2 == 0;		/* If none are set, it'll do.*/
+-	IF !CC JUMP .Lskip_stack_check;
+-
+-	R2 = [P0 - 0x104]; 	/* R2 - PageStart */
+-	P3.L = _page_size_table; /* retrieve end address */
+-	P3.H = _page_size_table; /* retrieve end address */
+-	R3 = 0x1002;		/* 16th - position, 2 bits -length */
+-#if ANOMALY_05000209
+-	nop;			/* Anomaly 05000209 */
+-#endif
+-	R7 = EXTRACT(R1,R3.l);
+-	R7 = R7 << 2;		/* Page size index offset */
+-	P5 = R7;
+-	P3 = P3 + P5;
+-	R7 = [P3];		/* page size in bytes */
+-
+-	R7 = R2 + R7;		/* R7 - PageEnd */
+-	R4 = SP; 		/* Test SP is in range */
+-
+-	CC = R7 < R4;		/* if PageEnd < SP */
+-	IF CC JUMP .Ldfound_victim;
+-	R3 = 0x284;		/* stack length from start of trap till
+-				 * the point.
+-				 * 20 stack locations for future modifications
+-				 */
+-	R4 = R4 + R3;
+-	CC = R4 < R2;		/* if SP + stacklen < PageStart */
+-	IF CC JUMP .Ldfound_victim;
+-.Lskip_stack_check:
+-
+-.Ledsearch2: NOP;
+-.Ledsearch1: NOP;
+-
+-	/* If we got here, we didn't find a DCPLB we considered
+-	 * replacable, which means all of them were locked.
+-	 */
+-
+-	JUMP .Lall_locked;
+-.Ldfound_victim:
+-
+-#ifdef CONFIG_CPLB_INFO
+-	R7 = [P0 - 0x104];
+-	P2.L = _dpdt_table;
+-	P2.H = _dpdt_table;
+-	P3.L = _dpdt_swapcount_table;
+-	P3.H = _dpdt_swapcount_table;
+-	P3 += -4;
+-.Ldicount:
+-	R2 = [P2];
+-	P2 += 8;
+-	P3 += 8;
+-	CC = R2==-1;
+-	IF CC JUMP .Ldicount_done;
+-	CC = R7==R2;
+-	IF !CC JUMP .Ldicount;
+-	R7 = [P3];
+-	R7 += 1;
+-	[P3] = R7;
+-.Ldicount_done:
+-#endif
+-
+-	/* Clean down the hardware loops*/
+-	R2 = 0;
+-	LC1 = R2;
+-	LC0 = R2;
+-
+-	/* There's a suitable victim in [P0-4] (because we've
+-	 * advanced already).
+-	 */
+-
+-.LDdoverwrite:
+-
+-	/* [P0-4] is a suitable victim CPLB, so we want to
+-	 * overwrite it by moving all the following CPLBs
+-	 * one space closer to the start.
+-	 */
+-
+-	R1.L = LO(DCPLB_DATA16);		/* DCPLB_DATA15 + 4 */
+-	R1.H = HI(DCPLB_DATA16);
+-	R0 = P0;
+-
+-	/* If the victim happens to be in DCPLB15,
+-	 * we don't need to move anything.
+-	 */
+-
+-	CC = R1 == R0;
+-	IF CC JUMP .Lde_moved;
+-	R1 = R1 - R0;
+-	R1 >>= 2;
+-	P1 = R1;
+-	LSETUP(.Lds_move, .Lde_move) LC0=P1;
+-.Lds_move:
+-	R0 = [P0++];	/* move data */
+-	[P0 - 8] = R0;
+-	R0 = [P0-0x104]	/* move address */
+-.Lde_move: [P0-0x108] = R0;
+-
+-	/* We've now made space in DCPLB15 for the new CPLB to be
+-	 * installed. The next stage is to locate a CPLB in the
+-	 * config table that covers the faulting address.
+-	 */
+-
+-.Lde_moved:NOP;
+-	R0 = I0;		/* Our faulting address */
+-
+-	P2.L = _dpdt_table;
+-	P2.H = _dpdt_table;
+-#ifdef	CONFIG_CPLB_INFO
+-	P3.L = _dpdt_swapcount_table;
+-	P3.H = _dpdt_swapcount_table;
+-	P3 += -8;
+-#endif
+-
+-	P1.L = _page_size_table;
+-	P1.H = _page_size_table;
+-
+-	/* An extraction pattern, to retrieve bits 17:16.*/
+-
+-	R1 = (16<<8)|2;
+-.Ldnext:	R4 = [P2++];	/* address */
+-	R2 = [P2++];	/* data */
+-#ifdef	CONFIG_CPLB_INFO
+-	P3 += 8;
+-#endif
+-
+-	CC = R4 == -1;
+-	IF CC JUMP .Lno_page_in_table;
+-
+-	/* See if failed address > start address */
+-	CC = R4 <= R0(IU);
+-	IF !CC JUMP .Ldnext;
+-
+-	/* extract page size (17:16)*/
+-	R3 = EXTRACT(R2, R1.L) (Z);
+-
+-	/* add page size to addr to get range */
+-
+-	P5 = R3;
+-	P5 = P1 + (P5 << 2);
+-	R3 = [P5];
+-	R3 = R3 + R4;
+-
+-	/* See if failed address < (start address + page size) */
+-	CC = R0 < R3(IU);
+-	IF !CC JUMP .Ldnext;
+-
+-	/* We've found the CPLB that should be installed, so
+-	 * write it into CPLB15, masking off any caching bits
+-	 * if necessary.
+-	 */
+-
+-	P1.L = LO(DCPLB_DATA15);
+-	P1.H = HI(DCPLB_DATA15);
+-
+-	/* If the DCPLB has cache bits set, but caching hasn't
+-	 * been enabled, then we want to mask off the cache-in-L1
+-	 * bit before installing. Moreover, if caching is off, we
+-	 * also want to ensure that the DCPLB has WT mode set, rather
+-	 * than WB, since WB pages still trigger first-write exceptions
+-	 * even when not caching is off, and the page isn't marked as
+-	 * cachable. Finally, we could mark the page as clean, not dirty,
+-	 * but we choose to leave that decision to the user; if the user
+-	 * chooses to have a CPLB pre-defined as dirty, then they always
+-	 * pay the cost of flushing during eviction, but don't pay the
+-	 * cost of first-write exceptions to mark the page as dirty.
+-	 */
+-
+-#ifdef CONFIG_BFIN_WT
+-	BITSET(R6, 14);		/* Set WT*/
+-#endif
+-
+-	[P1] = R2;
+-	[P1-0x100] = R4;
+-#ifdef	CONFIG_CPLB_INFO
+-	R3 = [P3];
+-	R3 += 1;
+-	[P3] = R3;
+-#endif
+-
+-	/* We've installed the CPLB, so re-enable CPLBs. P4
+-	 * points to DMEM_CONTROL, and R5 is the value we
+-	 * last wrote to it, when we were disabling CPLBs.
+-	 */
+-
+-	BITSET(R5,ENDCPLB_P);
+-	CLI R2;
+-	.align 8;
+-	[P4] = R5;
+-	SSYNC;
+-	STI R2;
+-
+-	( R7:4,P5:3 ) = [SP++];
+-	R0 = CPLB_RELOADED;
+-	RTS;
+-ENDPROC(_cplb_mgr)
+-
+-.data
+-.align 4;
+-_page_size_table:
+-.byte4	0x00000400;	/* 1K */
+-.byte4	0x00001000;	/* 4K */
+-.byte4	0x00100000;	/* 1M */
+-.byte4	0x00400000;	/* 4M */
+-
+-.align 4;
+-_dcplb_preference:
+-.byte4	0x00000001;	/* valid bit */
+-.byte4	0x00000002;	/* lock bit */
+diff --git a/arch/blackfin/mach-common/dpmc.S b/arch/blackfin/mach-common/dpmc.S
+index 39fbc28..b82c096 100644
+--- a/arch/blackfin/mach-common/dpmc.S
++++ b/arch/blackfin/mach-common/dpmc.S
+@@ -38,6 +38,9 @@ ENTRY(_unmask_wdog_wakeup_evt)
+ #if defined(CONFIG_BF561)
+ 	P0.H = hi(SICA_IWR1);
+ 	P0.L = lo(SICA_IWR1);
++#elif defined(CONFIG_BF54x) || defined(CONFIG_BF52x)
++	P0.h = HI(SIC_IWR0);
++	P0.l = LO(SIC_IWR0);
+ #else
+ 	P0.h = HI(SIC_IWR);
+ 	P0.l = LO(SIC_IWR);
+@@ -172,7 +175,7 @@ ENTRY(_sleep_mode)
+ 	call _set_sic_iwr;
+ 
+ 	R0 = 0xFFFF (Z);
+-	call _set_rtc_istat
++	call _set_rtc_istat;
+ 
+ 	P0.H = hi(PLL_CTL);
+ 	P0.L = lo(PLL_CTL);
+@@ -210,7 +213,7 @@ ENTRY(_hibernate_mode)
+ 	call _set_sic_iwr;
+ 
+ 	R0 = 0xFFFF (Z);
+-	call _set_rtc_istat
++	call _set_rtc_istat;
+ 
+ 	P0.H = hi(VR_CTL);
+ 	P0.L = lo(VR_CTL);
+@@ -236,7 +239,7 @@ ENTRY(_deep_sleep)
+ 
+ 	call _set_sic_iwr;
+ 
+-	call _set_sdram_srfs;
++	call _set_dram_srfs;
+ 
+ 	/* Clear all the interrupts,bits sticky */
+ 	R0 = 0xFFFF (Z);
+@@ -253,7 +256,7 @@ ENTRY(_deep_sleep)
+ 	SSYNC;
+ 	IDLE;
+ 
+-	call _unset_sdram_srfs;
++	call _unset_dram_srfs;
+ 
+ 	call _test_pll_locked;
+ 
+@@ -285,23 +288,22 @@ ENTRY(_sleep_deeper)
+ 	P3 = R0;
+ 	R0 = IWR_ENABLE(0);
+ 	call _set_sic_iwr;
+-	call _set_sdram_srfs;
++	call _set_dram_srfs;	/* Set SDRAM Self Refresh */
+ 
+ 	/* Clear all the interrupts,bits sticky */
+ 	R0 = 0xFFFF (Z);
+-	call _set_rtc_istat
+-
++	call _set_rtc_istat;
+ 	P0.H = hi(PLL_DIV);
+ 	P0.L = lo(PLL_DIV);
+ 	R6 = W[P0](z);
+ 	R0.L = 0xF;
+-	W[P0] = R0.l;
++	W[P0] = R0.l;		/* Set Max VCO to SCLK divider */
+ 
+ 	P0.H = hi(PLL_CTL);
+ 	P0.L = lo(PLL_CTL);
+ 	R5 = W[P0](z);
+ 	R0.L = (CONFIG_MIN_VCO_HZ/CONFIG_CLKIN_HZ) << 9;
+-	W[P0] = R0.l;
++	W[P0] = R0.l;		/* Set Min CLKIN to VCO multiplier */
+ 
+ 	SSYNC;
+ 	IDLE;
+@@ -317,29 +319,28 @@ ENTRY(_sleep_deeper)
+ 	R1 = R1|R2;
+ 
+ 	R2 = DEPOSIT(R7, R1);
+-	W[P0] = R2;
++	W[P0] = R2;		/* Set Min Core Voltage */
+ 
+ 	SSYNC;
+ 	IDLE;
+ 
+ 	call _test_pll_locked;
+ 
++	R0 = P3;
++	call _set_sic_iwr;	/* Set Awake from IDLE */
++
+ 	P0.H = hi(PLL_CTL);
+ 	P0.L = lo(PLL_CTL);
+ 	R0 = W[P0](z);
+ 	BITSET (R0, 3);
+-	W[P0] = R0.L;
+-
+-	R0 = P3;
+-	call _set_sic_iwr;
+-
++	W[P0] = R0.L;		/* Turn CCLK OFF */
+ 	SSYNC;
+ 	IDLE;
+ 
+ 	call _test_pll_locked;
+ 
+ 	R0 = IWR_ENABLE(0);
+-	call _set_sic_iwr;
++	call _set_sic_iwr;	/* Set Awake from IDLE PLL */
+ 
+ 	P0.H = hi(VR_CTL);
+ 	P0.L = lo(VR_CTL);
+@@ -352,15 +353,15 @@ ENTRY(_sleep_deeper)
+ 
+ 	P0.H = hi(PLL_DIV);
+ 	P0.L = lo(PLL_DIV);
+-	W[P0]= R6;
++	W[P0]= R6;		/* Restore CCLK and SCLK divider */
+ 
+ 	P0.H = hi(PLL_CTL);
+ 	P0.L = lo(PLL_CTL);
+-	w[p0] = R5;
++	w[p0] = R5;		/* Restore VCO multiplier */
+ 	IDLE;
+ 	call _test_pll_locked;
+ 
+-	call _unset_sdram_srfs;
++	call _unset_dram_srfs;	/* SDRAM Self Refresh Off */
+ 
+ 	STI R4;
+ 
+@@ -368,25 +369,47 @@ ENTRY(_sleep_deeper)
+ 	( R7:0, P5:0 ) = [SP++];
+ 	RTS;
+ 
+-ENTRY(_set_sdram_srfs)
+-	/*  set the sdram to self refresh mode */
++ENTRY(_set_dram_srfs)
++	/*  set the dram to self refresh mode */
++#if defined(CONFIG_BF54x)
++	P0.H = hi(EBIU_RSTCTL);
++	P0.L = lo(EBIU_RSTCTL);
++	R2 = [P0];
++	R3.H = hi(SRREQ);
++	R3.L = lo(SRREQ);
++#else
+ 	P0.H = hi(EBIU_SDGCTL);
+ 	P0.L = lo(EBIU_SDGCTL);
+ 	R2 = [P0];
+ 	R3.H = hi(SRFS);
+ 	R3.L = lo(SRFS);
++#endif
+ 	R2 = R2|R3;
+ 	[P0] = R2;
+ 	ssync;
++#if defined(CONFIG_BF54x)
++.LSRR_MODE:
++	R2 = [P0];
++	CC = BITTST(R2, 4);
++	if !CC JUMP .LSRR_MODE;
++#endif
+ 	RTS;
+ 
+-ENTRY(_unset_sdram_srfs)
+-	/*  set the sdram out of self refresh mode */
++ENTRY(_unset_dram_srfs)
++	/*  set the dram out of self refresh mode */
++#if defined(CONFIG_BF54x)
++	P0.H = hi(EBIU_RSTCTL);
++	P0.L = lo(EBIU_RSTCTL);
++	R2 = [P0];
++	R3.H = hi(SRREQ);
++	R3.L = lo(SRREQ);
++#else
+ 	P0.H = hi(EBIU_SDGCTL);
+ 	P0.L = lo(EBIU_SDGCTL);
+ 	R2 = [P0];
+ 	R3.H = hi(SRFS);
+ 	R3.L = lo(SRFS);
++#endif
+ 	R3 = ~R3;
+ 	R2 = R2&R3;
+ 	[P0] = R2;
+@@ -394,8 +417,13 @@ ENTRY(_unset_sdram_srfs)
+ 	RTS;
+ 
+ ENTRY(_set_sic_iwr)
++#if defined(CONFIG_BF54x) || defined(CONFIG_BF52x)
++	P0.H = hi(SIC_IWR0);
++	P0.L = lo(SIC_IWR0);
++#else
+ 	P0.H = hi(SIC_IWR);
+ 	P0.L = lo(SIC_IWR);
++#endif
+ 	[P0] = R0;
+ 	SSYNC;
+ 	RTS;
+diff --git a/arch/blackfin/mach-common/entry.S b/arch/blackfin/mach-common/entry.S
+index dc9d3ee..56ff51b 100644
+--- a/arch/blackfin/mach-common/entry.S
++++ b/arch/blackfin/mach-common/entry.S
+@@ -95,6 +95,9 @@ ENTRY(_ex_workaround_261)
+ 	R6 = 0x26;	/* Data CPLB Miss */
+ 	cc = R6 == R7;
+ 	if cc jump _ex_dcplb_miss (BP);
++	R6 = 0x23;	/* Data CPLB Miss */
++	cc = R6 == R7;
++	if cc jump _ex_dcplb_viol (BP);
+ 	/* Handle 0x23 Data CPLB Protection Violation
+ 	 * and Data CPLB Multiple Hits - Linux Trap Zero
+ 	 */
+@@ -102,17 +105,33 @@ ENTRY(_ex_workaround_261)
+ ENDPROC(_ex_workaround_261)
+ 
+ #else
++#ifdef CONFIG_MPU
++#define _ex_dviol _ex_dcplb_viol
++#else
+ #define _ex_dviol _ex_trap_c
++#endif
+ #define _ex_dmiss _ex_dcplb_miss
+ #define _ex_dmult _ex_trap_c
+ #endif
+ 
++
++ENTRY(_ex_dcplb_viol)
+ ENTRY(_ex_dcplb_miss)
+ ENTRY(_ex_icplb_miss)
+ 	(R7:6,P5:4) = [sp++];
+ 	ASTAT = [sp++];
+ 	SAVE_ALL_SYS
++#ifdef CONFIG_MPU
++	R0 = SEQSTAT;
++	R1 = SP;
++	sp += -12;
++	call _cplb_hdr;
++	sp += 12;
++	CC = R0 == 0;
++	IF !CC JUMP _handle_bad_cplb;
++#else
+ 	call __cplb_hdr;
++#endif
+ 	DEBUG_START_HWTRACE(p5, r7)
+ 	RESTORE_ALL_SYS
+ 	SP = EX_SCRATCH_REG;
+@@ -329,7 +348,7 @@ ENTRY(_exception_to_level5)
+ 	R7 = R7 + R6;
+ 	P5 = R7;
+ 	R1 = [P5];
+-	[SP + 8] = r1;
++	[SP + PT_SEQSTAT] = r1;
+ 
+ 	r0 = sp; 	/* stack frame pt_regs pointer argument ==> r0 */
+ 	SP += -12;
+@@ -633,9 +652,7 @@ ENTRY(_ret_from_exception)
+ 	[sp + PT_IPEND] = r0;
+ 
+ 1:
+-	r1 = 0x37(Z);
+-	r2 = ~r1;
+-	r2.h = 0;
++	r2 = LO(~0x37) (Z);
+ 	r0 = r2 & r0;
+ 	cc = r0 == 0;
+ 	if !cc jump 4f;	/* if not return to user mode, get out */
+@@ -1364,6 +1381,7 @@ ENTRY(_sys_call_table)
+ 	.long _sys_set_robust_list
+ 	.long _sys_get_robust_list	/* 355 */
+ 	.long _sys_fallocate
++	.long _sys_semtimedop
+ 	.rept NR_syscalls-(.-_sys_call_table)/4
+ 	.long _sys_ni_syscall
+ 	.endr
+diff --git a/arch/blackfin/mach-common/interrupt.S b/arch/blackfin/mach-common/interrupt.S
+index 4de3764..7f752c8 100644
+--- a/arch/blackfin/mach-common/interrupt.S
++++ b/arch/blackfin/mach-common/interrupt.S
+@@ -34,9 +34,13 @@
+ #include <asm/entry.h>
+ #include <asm/asm-offsets.h>
+ #include <asm/trace.h>
++#include <asm/traps.h>
++#include <asm/thread_info.h>
+ 
+ #include <asm/mach-common/context.S>
+ 
++.extern _ret_from_exception
++
+ #ifdef CONFIG_I_ENTRY_L1
+ .section .l1.text
+ #else
+@@ -117,8 +121,8 @@ __common_int_entry:
+ 
+ #if ANOMALY_05000283 || ANOMALY_05000315
+ 	cc = r7 == r7;
+-	p5.h = 0xffc0;
+-	p5.l = 0x0014;
++	p5.h = HI(CHIPID);
++	p5.l = LO(CHIPID);
+ 	if cc jump 1f;
+ 	r7.l = W[p5];
+ 1:
+@@ -134,26 +138,22 @@ __common_int_entry:
+ 
+ /* interrupt routine for ivhw - 5 */
+ ENTRY(_evt_ivhw)
+-	SAVE_CONTEXT
++	SAVE_ALL_SYS
+ #ifdef CONFIG_FRAME_POINTER
+ 	fp = 0;
+ #endif
++
+ #if ANOMALY_05000283
+ 	cc = r7 == r7;
+-	p5.h = 0xffc0;
+-	p5.l = 0x0014;
++	p5.h = HI(CHIPID);
++	p5.l = LO(CHIPID);
+ 	if cc jump 1f;
+ 	r7.l = W[p5];
+ 1:
+ #endif
+ 
+-	trace_buffer_stop(p0, r0);
+-
+-	r0 = IRQ_HWERR;
+-	r1 = sp;
+-
+ #ifdef CONFIG_HARDWARE_PM
+-	r7 = SEQSTAT;
++	r7 = [sp + PT_SEQSTAT];
+ 	r7 = r7 >>> 0xe;
+ 	r6 = 0x1F;
+ 	r7 = r7 & r6;
+@@ -161,11 +161,29 @@ ENTRY(_evt_ivhw)
+ 	cc = r7 == r5;
+ 	if cc jump .Lcall_do_ovf; /* deal with performance counter overflow */
+ #endif
+-
++	# We are going to dump something out, so make sure we print IPEND properly
++	p2.l = lo(IPEND);
++	p2.h = hi(IPEND);
++	r0 = [p2];
++	[sp + PT_IPEND] = r0;
++
++	/* set the EXCAUSE to HWERR for trap_c */
++	r0 = [sp + PT_SEQSTAT];
++	R1.L = LO(VEC_HWERR);
++	R1.H = HI(VEC_HWERR);
++	R0 = R0 | R1;
++	[sp + PT_SEQSTAT] = R0;
++
++	r0 = sp;        /* stack frame pt_regs pointer argument ==> r0 */
+ 	SP += -12;
+-	call _irq_panic;
++	call _trap_c;
+ 	SP += 12;
++
++	call _ret_from_exception;
++.Lcommon_restore_all_sys:
++	RESTORE_ALL_SYS
+ 	rti;
++
+ #ifdef CONFIG_HARDWARE_PM
+ .Lcall_do_ovf:
+ 
+@@ -173,9 +191,11 @@ ENTRY(_evt_ivhw)
+ 	call _pm_overflow;
+ 	SP += 12;
+ 
+-	jump .Lcommon_restore_context;
++	jump .Lcommon_restore_all_sys;
+ #endif
+ 
++ENDPROC(_evt_ivhw)
++
+ /* Interrupt routine for evt2 (NMI).
+  * We don't actually use this, so just return.
+  * For inner circle type details, please see:
+diff --git a/arch/blackfin/mach-common/ints-priority-dc.c b/arch/blackfin/mach-common/ints-priority-dc.c
+index 4882f0e..8d18d6b 100644
+--- a/arch/blackfin/mach-common/ints-priority-dc.c
++++ b/arch/blackfin/mach-common/ints-priority-dc.c
+@@ -222,11 +222,12 @@ static void bf561_gpio_unmask_irq(unsigned int irq)
+ static unsigned int bf561_gpio_irq_startup(unsigned int irq)
+ {
+ 	unsigned int ret;
++	char buf[8];
+ 	u16 gpionr = irq - IRQ_PF0;
+ 
+ 	if (!(gpio_enabled[gpio_bank(gpionr)] & gpio_bit(gpionr))) {
+-
+-		ret = gpio_request(gpionr, "IRQ");
++		snprintf(buf, sizeof buf, "IRQ %d", irq);
++		ret = gpio_request(gpionr, buf);
+ 		if (ret)
+ 			return ret;
+ 
+@@ -250,6 +251,7 @@ static int bf561_gpio_irq_type(unsigned int irq, unsigned int type)
+ {
+ 
+ 	unsigned int ret;
++	char buf[8];
+ 	u16 gpionr = irq - IRQ_PF0;
+ 
+ 
+@@ -265,8 +267,8 @@ static int bf561_gpio_irq_type(unsigned int irq, unsigned int type)
+ 			    IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) {
+ 
+ 		if (!(gpio_enabled[gpio_bank(gpionr)] & gpio_bit(gpionr))) {
+-
+-			ret = gpio_request(gpionr, "IRQ");
++			snprintf(buf, sizeof buf, "IRQ %d", irq);
++			ret = gpio_request(gpionr, buf);
+ 			if (ret)
+ 				return ret;
+ 
+diff --git a/arch/blackfin/mach-common/ints-priority-sc.c b/arch/blackfin/mach-common/ints-priority-sc.c
+index 147f073..dec42ac 100644
+--- a/arch/blackfin/mach-common/ints-priority-sc.c
++++ b/arch/blackfin/mach-common/ints-priority-sc.c
+@@ -313,6 +313,7 @@ static void bfin_demux_error_irq(unsigned int int_err_irq,
+ static unsigned short gpio_enabled[gpio_bank(MAX_BLACKFIN_GPIOS)];
+ static unsigned short gpio_edge_triggered[gpio_bank(MAX_BLACKFIN_GPIOS)];
+ 
++
+ static void bfin_gpio_ack_irq(unsigned int irq)
+ {
+ 	u16 gpionr = irq - IRQ_PF0;
+@@ -352,9 +353,11 @@ static unsigned int bfin_gpio_irq_startup(unsigned int irq)
+ {
+ 	unsigned int ret;
+ 	u16 gpionr = irq - IRQ_PF0;
++	char buf[8];
+ 
+ 	if (!(gpio_enabled[gpio_bank(gpionr)] & gpio_bit(gpionr))) {
+-		ret = gpio_request(gpionr, "IRQ");
++		snprintf(buf, sizeof buf, "IRQ %d", irq);
++		ret = gpio_request(gpionr, buf);
+ 		if (ret)
+ 			return ret;
+ 	}
+@@ -376,6 +379,7 @@ static int bfin_gpio_irq_type(unsigned int irq, unsigned int type)
+ {
+ 
+ 	unsigned int ret;
++	char buf[8];
+ 	u16 gpionr = irq - IRQ_PF0;
+ 
+ 	if (type == IRQ_TYPE_PROBE) {
+@@ -388,7 +392,8 @@ static int bfin_gpio_irq_type(unsigned int irq, unsigned int type)
+ 	if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING |
+ 		    IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) {
+ 		if (!(gpio_enabled[gpio_bank(gpionr)] & gpio_bit(gpionr))) {
+-			ret = gpio_request(gpionr, "IRQ");
++			snprintf(buf, sizeof buf, "IRQ %d", irq);
++			ret = gpio_request(gpionr, buf);
+ 			if (ret)
+ 				return ret;
+ 		}
+@@ -478,6 +483,10 @@ static void bfin_demux_gpio_irq(unsigned int intb_irq,
+ static unsigned char irq2pint_lut[NR_PINTS];
+ static unsigned char pint2irq_lut[NR_PINT_SYS_IRQS * NR_PINT_BITS];
+ 
++static unsigned int gpio_both_edge_triggered[NR_PINT_SYS_IRQS];
++static unsigned short gpio_enabled[gpio_bank(MAX_BLACKFIN_GPIOS)];
++
++
+ struct pin_int_t {
+ 	unsigned int mask_set;
+ 	unsigned int mask_clear;
+@@ -544,13 +553,20 @@ void init_pint_lut(void)
+ 
+ }
+ 
+-static unsigned short gpio_enabled[gpio_bank(MAX_BLACKFIN_GPIOS)];
+-
+ static void bfin_gpio_ack_irq(unsigned int irq)
+ {
+ 	u8 pint_val = irq2pint_lut[irq - SYS_IRQS];
++	u32 pintbit = PINT_BIT(pint_val);
++	u8 bank = PINT_2_BANK(pint_val);
++
++	if (unlikely(gpio_both_edge_triggered[bank] & pintbit)) {
++		if (pint[bank]->invert_set & pintbit)
++			pint[bank]->invert_clear = pintbit;
++		else
++			pint[bank]->invert_set = pintbit;
++	}
++	pint[bank]->request = pintbit;
+ 
+-	pint[PINT_2_BANK(pint_val)]->request = PINT_BIT(pint_val);
+ 	SSYNC();
+ }
+ 
+@@ -560,6 +576,13 @@ static void bfin_gpio_mask_ack_irq(unsigned int irq)
+ 	u32 pintbit = PINT_BIT(pint_val);
+ 	u8 bank = PINT_2_BANK(pint_val);
+ 
++	if (unlikely(gpio_both_edge_triggered[bank] & pintbit)) {
++		if (pint[bank]->invert_set & pintbit)
++			pint[bank]->invert_clear = pintbit;
++		else
++			pint[bank]->invert_set = pintbit;
++	}
++
+ 	pint[bank]->request = pintbit;
+ 	pint[bank]->mask_clear = pintbit;
+ 	SSYNC();
+@@ -587,7 +610,8 @@ static void bfin_gpio_unmask_irq(unsigned int irq)
+ static unsigned int bfin_gpio_irq_startup(unsigned int irq)
+ {
+ 	unsigned int ret;
+-	u16 gpionr = irq - IRQ_PA0;
++	char buf[8];
++	u16 gpionr = irq_to_gpio(irq);
+ 	u8 pint_val = irq2pint_lut[irq - SYS_IRQS];
+ 
+ 	if (pint_val == IRQ_NOT_AVAIL) {
+@@ -598,7 +622,8 @@ static unsigned int bfin_gpio_irq_startup(unsigned int irq)
+ 	}
+ 
+ 	if (!(gpio_enabled[gpio_bank(gpionr)] & gpio_bit(gpionr))) {
+-		ret = gpio_request(gpionr, "IRQ");
++		snprintf(buf, sizeof buf, "IRQ %d", irq);
++		ret = gpio_request(gpionr, buf);
+ 		if (ret)
+ 			return ret;
+ 	}
+@@ -611,16 +636,19 @@ static unsigned int bfin_gpio_irq_startup(unsigned int irq)
+ 
+ static void bfin_gpio_irq_shutdown(unsigned int irq)
+ {
++	u16 gpionr = irq_to_gpio(irq);
++
+ 	bfin_gpio_mask_irq(irq);
+-	gpio_free(irq - IRQ_PA0);
+-	gpio_enabled[gpio_bank(irq - IRQ_PA0)] &= ~gpio_bit(irq - IRQ_PA0);
++	gpio_free(gpionr);
++	gpio_enabled[gpio_bank(gpionr)] &= ~gpio_bit(gpionr);
+ }
+ 
+ static int bfin_gpio_irq_type(unsigned int irq, unsigned int type)
+ {
+ 
+ 	unsigned int ret;
+-	u16 gpionr = irq - IRQ_PA0;
++	char buf[8];
++	u16 gpionr = irq_to_gpio(irq);
+ 	u8 pint_val = irq2pint_lut[irq - SYS_IRQS];
+ 	u32 pintbit = PINT_BIT(pint_val);
+ 	u8 bank = PINT_2_BANK(pint_val);
+@@ -638,7 +666,8 @@ static int bfin_gpio_irq_type(unsigned int irq, unsigned int type)
+ 	if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING |
+ 		    IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) {
+ 		if (!(gpio_enabled[gpio_bank(gpionr)] & gpio_bit(gpionr))) {
+-			ret = gpio_request(gpionr, "IRQ");
++			snprintf(buf, sizeof buf, "IRQ %d", irq);
++			ret = gpio_request(gpionr, buf);
+ 			if (ret)
+ 				return ret;
+ 		}
+@@ -651,28 +680,33 @@ static int bfin_gpio_irq_type(unsigned int irq, unsigned int type)
+ 
+ 	gpio_direction_input(gpionr);
+ 
+-	if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) {
+-		pint[bank]->edge_set = pintbit;
+-	} else {
+-		pint[bank]->edge_clear = pintbit;
+-	}
+-
+ 	if ((type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_LEVEL_LOW)))
+ 		pint[bank]->invert_set = pintbit;	/* low or falling edge denoted by one */
+ 	else
+-		pint[bank]->invert_set = pintbit;	/* high or rising edge denoted by zero */
++		pint[bank]->invert_clear = pintbit;	/* high or rising edge denoted by zero */
+ 
+-	if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))
+-		pint[bank]->invert_set = pintbit;
+-	else
+-		pint[bank]->invert_set = pintbit;
++	if ((type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))
++	    == (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) {
+ 
+-	SSYNC();
++		gpio_both_edge_triggered[bank] |= pintbit;
+ 
+-	if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))
++		if (gpio_get_value(gpionr))
++			pint[bank]->invert_set = pintbit;
++		else
++			pint[bank]->invert_clear = pintbit;
++	} else {
++		gpio_both_edge_triggered[bank] &= ~pintbit;
++	}
++
++	if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) {
++		pint[bank]->edge_set = pintbit;
+ 		set_irq_handler(irq, handle_edge_irq);
+-	else
++	} else {
++		pint[bank]->edge_clear = pintbit;
+ 		set_irq_handler(irq, handle_level_irq);
++	}
++
++	SSYNC();
+ 
+ 	return 0;
+ }
+diff --git a/arch/blackfin/mach-common/irqpanic.c b/arch/blackfin/mach-common/irqpanic.c
+index b22959b..606ded9 100644
+--- a/arch/blackfin/mach-common/irqpanic.c
++++ b/arch/blackfin/mach-common/irqpanic.c
+@@ -46,9 +46,6 @@ void irq_panic(int reason, struct pt_regs *regs) __attribute__ ((l1_text));
+  */
+ asmlinkage void irq_panic(int reason, struct pt_regs *regs)
+ {
+-	int sig = 0;
+-	siginfo_t info;
+-
+ #ifdef CONFIG_DEBUG_ICACHE_CHECK
+ 	unsigned int cmd, tag, ca, cache_hi, cache_lo, *pa;
+ 	unsigned short i, j, die;
+@@ -136,53 +133,6 @@ asmlinkage void irq_panic(int reason, struct pt_regs *regs)
+ 	}
+ #endif
+ 
+-	printk(KERN_EMERG "\n");
+-	printk(KERN_EMERG "Exception: IRQ 0x%x entered\n", reason);
+-	printk(KERN_EMERG " code=[0x%08lx],   stack frame=0x%08lx,  "
+-	    " bad PC=0x%08lx\n",
+-	    (unsigned long)regs->seqstat,
+-	    (unsigned long)regs,
+-	    (unsigned long)regs->pc);
+-	if (reason == 0x5) {
+-		printk(KERN_EMERG "----------- HARDWARE ERROR -----------\n");
+-
+-		/* There is only need to check for Hardware Errors, since other
+-		 * EXCEPTIONS are handled in TRAPS.c (MH)
+-		 */
+-		switch (regs->seqstat & SEQSTAT_HWERRCAUSE) {
+-		case (SEQSTAT_HWERRCAUSE_SYSTEM_MMR):	/* System MMR Error */
+-			info.si_code = BUS_ADRALN;
+-			sig = SIGBUS;
+-			printk(KERN_EMERG HWC_x2(KERN_EMERG));
+-			break;
+-		case (SEQSTAT_HWERRCAUSE_EXTERN_ADDR):	/* External Memory Addressing Error */
+-			info.si_code = BUS_ADRERR;
+-			sig = SIGBUS;
+-			printk(KERN_EMERG HWC_x3(KERN_EMERG));
+-			break;
+-		case (SEQSTAT_HWERRCAUSE_PERF_FLOW):	/* Performance Monitor Overflow */
+-			printk(KERN_EMERG HWC_x12(KERN_EMERG));
+-			break;
+-		case (SEQSTAT_HWERRCAUSE_RAISE_5):	/* RAISE 5 instruction */
+-			printk(KERN_EMERG HWC_x18(KERN_EMERG));
+-			break;
+-		default:	/* Reserved */
+-			printk(KERN_EMERG HWC_default(KERN_EMERG));
+-			break;
+-		}
+-	}
+-
+-	regs->ipend = bfin_read_IPEND();
+-	dump_bfin_process(regs);
+-	dump_bfin_mem((void *)regs->pc);
+-	show_regs(regs);
+-	if (0 == (info.si_signo = sig) || 0 == user_mode(regs))	/* in kernelspace */
+-		panic("Unhandled IRQ or exceptions!\n");
+-	else {			/* in userspace */
+-		info.si_errno = 0;
+-		info.si_addr = (void *)regs->pc;
+-		force_sig_info(sig, &info, current);
+-	}
+ }
+ 
+ #ifdef CONFIG_HARDWARE_PM
+diff --git a/arch/blackfin/mach-common/pm.c b/arch/blackfin/mach-common/pm.c
+index dac51fb..81930f7 100644
+--- a/arch/blackfin/mach-common/pm.c
++++ b/arch/blackfin/mach-common/pm.c
+@@ -77,7 +77,15 @@ void bfin_pm_suspend_standby_enter(void)
+ 
+ 		gpio_pm_restore();
+ 
++#if defined(CONFIG_BF54x) || defined(CONFIG_BF52x)
++		bfin_write_SIC_IWR0(IWR_ENABLE_ALL);
++		bfin_write_SIC_IWR1(IWR_ENABLE_ALL);
++# ifdef CONFIG_BF54x
++		bfin_write_SIC_IWR2(IWR_ENABLE_ALL);
++# endif
++#else
+ 		bfin_write_SIC_IWR(IWR_ENABLE_ALL);
++#endif
+ 
+ 		local_irq_restore(flags);
+ 	}
+@@ -85,7 +93,15 @@ void bfin_pm_suspend_standby_enter(void)
+ 
+ #if defined(CONFIG_PM_WAKEUP_GPIO_BY_SIC_IWR)
+ 	sleep_deeper(CONFIG_PM_WAKEUP_SIC_IWR);
++# if defined(CONFIG_BF54x) || defined(CONFIG_BF52x)
++	bfin_write_SIC_IWR0(IWR_ENABLE_ALL);
++	bfin_write_SIC_IWR1(IWR_ENABLE_ALL);
++#  ifdef CONFIG_BF54x
++	bfin_write_SIC_IWR2(IWR_ENABLE_ALL);
++#  endif
++# else
+ 	bfin_write_SIC_IWR(IWR_ENABLE_ALL);
++# endif
+ #endif				/* CONFIG_PM_WAKEUP_GPIO_BY_SIC_IWR */
+ }
+ 
+diff --git a/arch/blackfin/mm/init.c b/arch/blackfin/mm/init.c
+index e97ea8f..eb1a12a 100644
+--- a/arch/blackfin/mm/init.c
++++ b/arch/blackfin/mm/init.c
+@@ -128,8 +128,8 @@ void __init paging_init(void)
+ void __init mem_init(void)
+ {
+ 	unsigned int codek = 0, datak = 0, initk = 0;
++	unsigned int reservedpages = 0, freepages = 0;
+ 	unsigned long tmp;
+-	unsigned int len = _ramend - _rambase;
+ 	unsigned long start_mem = memory_start;
+ 	unsigned long end_mem = memory_end;
+ 
+@@ -138,19 +138,36 @@ void __init mem_init(void)
+ 
+ 	start_mem = PAGE_ALIGN(start_mem);
+ 	max_mapnr = num_physpages = MAP_NR(high_memory);
+-	printk(KERN_INFO "Physical pages: %lx\n", num_physpages);
++	printk(KERN_INFO "Kernel managed physical pages: %lu\n",
++		num_physpages);
+ 
+ 	/* This will put all memory onto the freelists. */
+ 	totalram_pages = free_all_bootmem();
+ 
++	reservedpages = 0;
++	for (tmp = 0; tmp < max_mapnr; tmp++)
++		if (PageReserved(pfn_to_page(tmp)))
++			reservedpages++;
++	freepages =  max_mapnr - reservedpages;
++
++	/* do not count in kernel image between _rambase and _ramstart */
++	reservedpages -= (_ramstart - _rambase) >> PAGE_SHIFT;
++#if (defined(CONFIG_BFIN_ICACHE) && ANOMALY_05000263)
++	reservedpages += (_ramend - memory_end - DMA_UNCACHED_REGION) >>
++				PAGE_SHIFT;
++#endif
++
+ 	codek = (_etext - _stext) >> 10;
+-	datak = (__bss_stop - __bss_start) >> 10;
+ 	initk = (__init_end - __init_begin) >> 10;
++	datak = ((_ramstart - _rambase) >> 10) - codek - initk;
+ 
+-	tmp = nr_free_pages() << PAGE_SHIFT;
+ 	printk(KERN_INFO
+-	     "Memory available: %luk/%uk RAM, (%uk init code, %uk kernel code, %uk data, %uk dma)\n",
+-	     tmp >> 10, len >> 10, initk, codek, datak, DMA_UNCACHED_REGION >> 10);
++	     "Memory available: %luk/%luk RAM, "
++		"(%uk init code, %uk kernel code, "
++		"%uk data, %uk dma, %uk reserved)\n",
++		(unsigned long) freepages << (PAGE_SHIFT-10), _ramend >> 10,
++		initk, codek, datak, DMA_UNCACHED_REGION >> 10,
++		(reservedpages << (PAGE_SHIFT-10)));
+ 
+ 	/* Initialize the blackfin L1 Memory. */
+ 	l1sram_init();
+@@ -184,13 +201,15 @@ static __init void free_init_pages(const char *what, unsigned long begin, unsign
+ #ifdef CONFIG_BLK_DEV_INITRD
+ void __init free_initrd_mem(unsigned long start, unsigned long end)
+ {
++#ifndef CONFIG_MPU
+ 	free_init_pages("initrd memory", start, end);
++#endif
+ }
+ #endif
+ 
+ void __init free_initmem(void)
+ {
+-#ifdef CONFIG_RAMKERNEL
++#if defined CONFIG_RAMKERNEL && !defined CONFIG_MPU
+ 	free_init_pages("unused kernel memory",
+ 			(unsigned long)(&__init_begin),
+ 			(unsigned long)(&__init_end));
+diff --git a/arch/cris/arch-v32/drivers/iop_fw_load.c b/arch/cris/arch-v32/drivers/iop_fw_load.c
+index 11f9895..f4bdc1d 100644
+--- a/arch/cris/arch-v32/drivers/iop_fw_load.c
++++ b/arch/cris/arch-v32/drivers/iop_fw_load.c
+@@ -20,6 +20,9 @@
+ 
+ #define IOP_TIMEOUT 100
+ 
++#error "This driver is broken with regard to its driver core usage."
++#error "Please contact <greg at kroah.com> for details on how to fix it properly."
++
+ static struct device iop_spu_device[2] = {
+ 	{ .bus_id =     "iop-spu0", },
+ 	{ .bus_id =     "iop-spu1", },
+@@ -192,6 +195,13 @@ int iop_start_mpu(unsigned int start_addr)
+ 
+ static int __init iop_fw_load_init(void)
+ {
++#if 0
++	/*
++	 * static struct devices can not be added directly to sysfs by ignoring
++	 * the driver model infrastructure.  To fix this properly, please use
++	 * the platform_bus to register these devices to be able to properly
++	 * use the firmware infrastructure.
++	 */
+ 	device_initialize(&iop_spu_device[0]);
+ 	kobject_set_name(&iop_spu_device[0].kobj, "iop-spu0");
+ 	kobject_add(&iop_spu_device[0].kobj);
+@@ -201,6 +211,7 @@ static int __init iop_fw_load_init(void)
+ 	device_initialize(&iop_mpu_device);
+ 	kobject_set_name(&iop_mpu_device.kobj, "iop-mpu");
+ 	kobject_add(&iop_mpu_device.kobj);
++#endif
+ 	return 0;
+ }
+ 
+diff --git a/arch/ia64/kernel/setup.c b/arch/ia64/kernel/setup.c
+index 4ac2b1f..86028c6 100644
+--- a/arch/ia64/kernel/setup.c
++++ b/arch/ia64/kernel/setup.c
+@@ -71,8 +71,6 @@ unsigned long __per_cpu_offset[NR_CPUS];
+ EXPORT_SYMBOL(__per_cpu_offset);
+ #endif
+ 
+-extern void ia64_setup_printk_clock(void);
+-
+ DEFINE_PER_CPU(struct cpuinfo_ia64, cpu_info);
+ DEFINE_PER_CPU(unsigned long, local_per_cpu_offset);
+ unsigned long ia64_cycles_per_usec;
+@@ -507,8 +505,6 @@ setup_arch (char **cmdline_p)
+ 	/* process SAL system table: */
+ 	ia64_sal_init(__va(efi.sal_systab));
+ 
+-	ia64_setup_printk_clock();
+-
+ #ifdef CONFIG_SMP
+ 	cpu_physical_id(0) = hard_smp_processor_id();
+ #endif
+diff --git a/arch/ia64/kernel/time.c b/arch/ia64/kernel/time.c
+index 2bb8421..3ab0427 100644
+--- a/arch/ia64/kernel/time.c
++++ b/arch/ia64/kernel/time.c
+@@ -344,33 +344,6 @@ udelay (unsigned long usecs)
+ }
+ EXPORT_SYMBOL(udelay);
+ 
+-static unsigned long long ia64_itc_printk_clock(void)
+-{
+-	if (ia64_get_kr(IA64_KR_PER_CPU_DATA))
+-		return sched_clock();
+-	return 0;
+-}
+-
+-static unsigned long long ia64_default_printk_clock(void)
+-{
+-	return (unsigned long long)(jiffies_64 - INITIAL_JIFFIES) *
+-		(1000000000/HZ);
+-}
+-
+-unsigned long long (*ia64_printk_clock)(void) = &ia64_default_printk_clock;
+-
+-unsigned long long printk_clock(void)
+-{
+-	return ia64_printk_clock();
+-}
+-
+-void __init
+-ia64_setup_printk_clock(void)
+-{
+-	if (!(sal_platform_features & IA64_SAL_PLATFORM_FEATURE_ITC_DRIFT))
+-		ia64_printk_clock = ia64_itc_printk_clock;
+-}
+-
+ /* IA64 doesn't cache the timezone */
+ void update_vsyscall_tz(void)
+ {
+diff --git a/arch/ia64/kernel/topology.c b/arch/ia64/kernel/topology.c
+index 14261fe..a2484fc 100644
+--- a/arch/ia64/kernel/topology.c
++++ b/arch/ia64/kernel/topology.c
+@@ -354,27 +354,27 @@ static int __cpuinit cache_add_dev(struct sys_device * sys_dev)
+ 	if (unlikely(retval < 0))
+ 		return retval;
+ 
+-	all_cpu_cache_info[cpu].kobj.parent = &sys_dev->kobj;
+-	kobject_set_name(&all_cpu_cache_info[cpu].kobj, "%s", "cache");
+-	all_cpu_cache_info[cpu].kobj.ktype = &cache_ktype_percpu_entry;
+-	retval = kobject_register(&all_cpu_cache_info[cpu].kobj);
++	retval = kobject_init_and_add(&all_cpu_cache_info[cpu].kobj,
++				      &cache_ktype_percpu_entry, &sys_dev->kobj,
++				      "%s", "cache");
+ 
+ 	for (i = 0; i < all_cpu_cache_info[cpu].num_cache_leaves; i++) {
+ 		this_object = LEAF_KOBJECT_PTR(cpu,i);
+-		this_object->kobj.parent = &all_cpu_cache_info[cpu].kobj;
+-		kobject_set_name(&(this_object->kobj), "index%1lu", i);
+-		this_object->kobj.ktype = &cache_ktype;
+-		retval = kobject_register(&(this_object->kobj));
++		retval = kobject_init_and_add(&(this_object->kobj),
++					      &cache_ktype,
++					      &all_cpu_cache_info[cpu].kobj,
++					      "index%1lu", i);
+ 		if (unlikely(retval)) {
+ 			for (j = 0; j < i; j++) {
+-				kobject_unregister(
+-					&(LEAF_KOBJECT_PTR(cpu,j)->kobj));
++				kobject_put(&(LEAF_KOBJECT_PTR(cpu,j)->kobj));
+ 			}
+-			kobject_unregister(&all_cpu_cache_info[cpu].kobj);
++			kobject_put(&all_cpu_cache_info[cpu].kobj);
+ 			cpu_cache_sysfs_exit(cpu);
+ 			break;
+ 		}
++		kobject_uevent(&(this_object->kobj), KOBJ_ADD);
+ 	}
++	kobject_uevent(&all_cpu_cache_info[cpu].kobj, KOBJ_ADD);
+ 	return retval;
+ }
+ 
+@@ -385,10 +385,10 @@ static int __cpuinit cache_remove_dev(struct sys_device * sys_dev)
+ 	unsigned long i;
+ 
+ 	for (i = 0; i < all_cpu_cache_info[cpu].num_cache_leaves; i++)
+-		kobject_unregister(&(LEAF_KOBJECT_PTR(cpu,i)->kobj));
++		kobject_put(&(LEAF_KOBJECT_PTR(cpu,i)->kobj));
+ 
+ 	if (all_cpu_cache_info[cpu].kobj.parent) {
+-		kobject_unregister(&all_cpu_cache_info[cpu].kobj);
++		kobject_put(&all_cpu_cache_info[cpu].kobj);
+ 		memset(&all_cpu_cache_info[cpu].kobj,
+ 			0,
+ 			sizeof(struct kobject));
+diff --git a/arch/ia64/sn/kernel/setup.c b/arch/ia64/sn/kernel/setup.c
+index 1f38a3a..bb1d249 100644
+--- a/arch/ia64/sn/kernel/setup.c
++++ b/arch/ia64/sn/kernel/setup.c
+@@ -64,7 +64,6 @@ extern void sn_timer_init(void);
+ extern unsigned long last_time_offset;
+ extern void (*ia64_mark_idle) (int);
+ extern void snidle(int);
+-extern unsigned long long (*ia64_printk_clock)(void);
+ 
+ unsigned long sn_rtc_cycles_per_second;
+ EXPORT_SYMBOL(sn_rtc_cycles_per_second);
+@@ -360,14 +359,6 @@ sn_scan_pcdp(void)
+ 
+ static unsigned long sn2_rtc_initial;
+ 
+-static unsigned long long ia64_sn2_printk_clock(void)
+-{
+-	unsigned long rtc_now = rtc_time();
+-
+-	return (rtc_now - sn2_rtc_initial) *
+-		(1000000000 / sn_rtc_cycles_per_second);
+-}
+-
+ /**
+  * sn_setup - SN platform setup routine
+  * @cmdline_p: kernel command line
+@@ -468,8 +459,6 @@ void __init sn_setup(char **cmdline_p)
+ 
+ 	platform_intr_list[ACPI_INTERRUPT_CPEI] = IA64_CPE_VECTOR;
+ 
+-	ia64_printk_clock = ia64_sn2_printk_clock;
+-
+ 	printk("SGI SAL version %x.%02x\n", version >> 8, version & 0x00FF);
+ 
+ 	/*
+diff --git a/arch/mips/au1000/common/platform.c b/arch/mips/au1000/common/platform.c
+index d51e18f..841904c 100644
+--- a/arch/mips/au1000/common/platform.c
++++ b/arch/mips/au1000/common/platform.c
+@@ -270,6 +270,24 @@ static struct platform_device smc91x_device = {
+ 
+ #endif
+ 
++/* All Alchemy demoboards with I2C have this #define in their headers */
++#ifdef SMBUS_PSC_BASE
++static struct resource pbdb_smbus_resources[] = {
++	{
++		.start	= SMBUS_PSC_BASE,
++		.end	= SMBUS_PSC_BASE + 0x24 - 1,
++		.flags	= IORESOURCE_MEM,
++	},
++};
++
++static struct platform_device pbdb_smbus_device = {
++	.name		= "au1xpsc_smbus",
++	.id		= 0,	/* bus number */
++	.num_resources	= ARRAY_SIZE(pbdb_smbus_resources),
++	.resource	= pbdb_smbus_resources,
++};
++#endif
++
+ static struct platform_device *au1xxx_platform_devices[] __initdata = {
+ 	&au1xxx_usb_ohci_device,
+ 	&au1x00_pcmcia_device,
+@@ -287,6 +305,9 @@ static struct platform_device *au1xxx_platform_devices[] __initdata = {
+ #ifdef CONFIG_MIPS_DB1200
+ 	&smc91x_device,
+ #endif
++#ifdef SMBUS_PSC_BASE
++	&pbdb_smbus_device,
++#endif
+ };
+ 
+ int __init au1xxx_platform_init(void)
+diff --git a/arch/mips/kernel/i8259.c b/arch/mips/kernel/i8259.c
+index 4710135..197d797 100644
+--- a/arch/mips/kernel/i8259.c
++++ b/arch/mips/kernel/i8259.c
+@@ -238,7 +238,7 @@ static int i8259A_shutdown(struct sys_device *dev)
+ }
+ 
+ static struct sysdev_class i8259_sysdev_class = {
+-	set_kset_name("i8259"),
++	.name = "i8259",
+ 	.resume = i8259A_resume,
+ 	.shutdown = i8259A_shutdown,
+ };
+diff --git a/arch/mips/kernel/mips-mt-fpaff.c b/arch/mips/kernel/mips-mt-fpaff.c
+index 892665b..bb4f00c 100644
+--- a/arch/mips/kernel/mips-mt-fpaff.c
++++ b/arch/mips/kernel/mips-mt-fpaff.c
+@@ -58,13 +58,13 @@ asmlinkage long mipsmt_sys_sched_setaffinity(pid_t pid, unsigned int len,
+ 	if (copy_from_user(&new_mask, user_mask_ptr, sizeof(new_mask)))
+ 		return -EFAULT;
+ 
+-	lock_cpu_hotplug();
++	get_online_cpus();
+ 	read_lock(&tasklist_lock);
+ 
+ 	p = find_process_by_pid(pid);
+ 	if (!p) {
+ 		read_unlock(&tasklist_lock);
+-		unlock_cpu_hotplug();
++		put_online_cpus();
+ 		return -ESRCH;
+ 	}
+ 
+@@ -106,7 +106,7 @@ asmlinkage long mipsmt_sys_sched_setaffinity(pid_t pid, unsigned int len,
+ 
+ out_unlock:
+ 	put_task_struct(p);
+-	unlock_cpu_hotplug();
++	put_online_cpus();
+ 	return retval;
+ }
+ 
+@@ -125,7 +125,7 @@ asmlinkage long mipsmt_sys_sched_getaffinity(pid_t pid, unsigned int len,
+ 	if (len < real_len)
+ 		return -EINVAL;
+ 
+-	lock_cpu_hotplug();
++	get_online_cpus();
+ 	read_lock(&tasklist_lock);
+ 
+ 	retval = -ESRCH;
+@@ -140,7 +140,7 @@ asmlinkage long mipsmt_sys_sched_getaffinity(pid_t pid, unsigned int len,
+ 
+ out_unlock:
+ 	read_unlock(&tasklist_lock);
+-	unlock_cpu_hotplug();
++	put_online_cpus();
+ 	if (retval)
+ 		return retval;
+ 	if (copy_to_user(user_mask_ptr, &mask, real_len))
+diff --git a/arch/powerpc/platforms/cell/spu_base.c b/arch/powerpc/platforms/cell/spu_base.c
+index c83c3e3..a088622 100644
+--- a/arch/powerpc/platforms/cell/spu_base.c
++++ b/arch/powerpc/platforms/cell/spu_base.c
+@@ -459,7 +459,7 @@ static int spu_shutdown(struct sys_device *sysdev)
+ }
+ 
+ static struct sysdev_class spu_sysdev_class = {
+-	set_kset_name("spu"),
++	.name = "spu",
+ 	.shutdown = spu_shutdown,
+ };
+ 
+diff --git a/arch/powerpc/platforms/powermac/pic.c b/arch/powerpc/platforms/powermac/pic.c
+index 999f5e1..84c0d4e 100644
+--- a/arch/powerpc/platforms/powermac/pic.c
++++ b/arch/powerpc/platforms/powermac/pic.c
+@@ -663,7 +663,7 @@ static int pmacpic_resume(struct sys_device *sysdev)
+ #endif /* CONFIG_PM && CONFIG_PPC32 */
+ 
+ static struct sysdev_class pmacpic_sysclass = {
+-	set_kset_name("pmac_pic"),
++	.name = "pmac_pic",
+ };
+ 
+ static struct sys_device device_pmacpic = {
+diff --git a/arch/powerpc/platforms/pseries/hotplug-cpu.c b/arch/powerpc/platforms/pseries/hotplug-cpu.c
+index 412e6b4..c4ad54e 100644
+--- a/arch/powerpc/platforms/pseries/hotplug-cpu.c
++++ b/arch/powerpc/platforms/pseries/hotplug-cpu.c
+@@ -153,7 +153,7 @@ static int pseries_add_processor(struct device_node *np)
+ 	for (i = 0; i < nthreads; i++)
+ 		cpu_set(i, tmp);
+ 
+-	lock_cpu_hotplug();
++	cpu_maps_update_begin();
+ 
+ 	BUG_ON(!cpus_subset(cpu_present_map, cpu_possible_map));
+ 
+@@ -190,7 +190,7 @@ static int pseries_add_processor(struct device_node *np)
+ 	}
+ 	err = 0;
+ out_unlock:
+-	unlock_cpu_hotplug();
++	cpu_maps_update_done();
+ 	return err;
+ }
+ 
+@@ -211,7 +211,7 @@ static void pseries_remove_processor(struct device_node *np)
+ 
+ 	nthreads = len / sizeof(u32);
+ 
+-	lock_cpu_hotplug();
++	cpu_maps_update_begin();
+ 	for (i = 0; i < nthreads; i++) {
+ 		for_each_present_cpu(cpu) {
+ 			if (get_hard_smp_processor_id(cpu) != intserv[i])
+@@ -225,7 +225,7 @@ static void pseries_remove_processor(struct device_node *np)
+ 			printk(KERN_WARNING "Could not find cpu to remove "
+ 			       "with physical id 0x%x\n", intserv[i]);
+ 	}
+-	unlock_cpu_hotplug();
++	cpu_maps_update_done();
+ }
+ 
+ static int pseries_smp_notifier(struct notifier_block *nb,
+diff --git a/arch/powerpc/platforms/pseries/power.c b/arch/powerpc/platforms/pseries/power.c
+index 73e6902..e95fc15 100644
+--- a/arch/powerpc/platforms/pseries/power.c
++++ b/arch/powerpc/platforms/pseries/power.c
+@@ -28,13 +28,15 @@
+ 
+ unsigned long rtas_poweron_auto; /* default and normal state is 0 */
+ 
+-static ssize_t auto_poweron_show(struct kset *kset, char *buf)
++static ssize_t auto_poweron_show(struct kobject *kobj,
++				 struct kobj_attribute *attr, char *buf)
+ {
+         return sprintf(buf, "%lu\n", rtas_poweron_auto);
+ }
+ 
+-static ssize_t
+-auto_poweron_store(struct kset *kset, const char *buf, size_t n)
++static ssize_t auto_poweron_store(struct kobject *kobj,
++				  struct kobj_attribute *attr,
++				  const char *buf, size_t n)
+ {
+ 	int ret;
+ 	unsigned long ups_restart;
+@@ -47,17 +49,11 @@ auto_poweron_store(struct kset *kset, const char *buf, size_t n)
+ 	return -EINVAL;
+ }
+ 
+-static struct subsys_attribute auto_poweron_attr = {
+-        .attr   = {
+-                .name = __stringify(auto_poweron),
+-                .mode = 0644,
+-        },
+-        .show   = auto_poweron_show,
+-        .store  = auto_poweron_store,
+-};
++static struct kobj_attribute auto_poweron_attr =
++	__ATTR(auto_poweron, 0644, auto_poweron_show, auto_poweron_store);
+ 
+ #ifndef CONFIG_PM
+-decl_subsys(power,NULL,NULL);
++struct kobject *power_kobj;
+ 
+ static struct attribute *g[] = {
+         &auto_poweron_attr.attr,
+@@ -70,18 +66,16 @@ static struct attribute_group attr_group = {
+ 
+ static int __init pm_init(void)
+ {
+-        int error = subsystem_register(&power_subsys);
+-        if (!error)
+-                error = sysfs_create_group(&power_subsys.kobj, &attr_group);
+-        return error;
++	power_kobj = kobject_create_and_add("power", NULL);
++	if (!power_kobj)
++		return -ENOMEM;
++	return sysfs_create_group(power_kobj, &attr_group);
+ }
+ core_initcall(pm_init);
+ #else
+-extern struct kset power_subsys;
+-
+ static int __init apo_pm_init(void)
+ {
+-	return (subsys_create_file(&power_subsys, &auto_poweron_attr));
++	return (sysfs_create_file(power_kobj, &auto_poweron_attr));
+ }
+ __initcall(apo_pm_init);
+ #endif
+diff --git a/arch/powerpc/platforms/pseries/rtasd.c b/arch/powerpc/platforms/pseries/rtasd.c
+index 73401c8..e3078ce 100644
+--- a/arch/powerpc/platforms/pseries/rtasd.c
++++ b/arch/powerpc/platforms/pseries/rtasd.c
+@@ -382,7 +382,7 @@ static void do_event_scan_all_cpus(long delay)
+ {
+ 	int cpu;
+ 
+-	lock_cpu_hotplug();
++	get_online_cpus();
+ 	cpu = first_cpu(cpu_online_map);
+ 	for (;;) {
+ 		set_cpus_allowed(current, cpumask_of_cpu(cpu));
+@@ -390,15 +390,15 @@ static void do_event_scan_all_cpus(long delay)
+ 		set_cpus_allowed(current, CPU_MASK_ALL);
+ 
+ 		/* Drop hotplug lock, and sleep for the specified delay */
+-		unlock_cpu_hotplug();
++		put_online_cpus();
+ 		msleep_interruptible(delay);
+-		lock_cpu_hotplug();
++		get_online_cpus();
+ 
+ 		cpu = next_cpu(cpu, cpu_online_map);
+ 		if (cpu == NR_CPUS)
+ 			break;
+ 	}
+-	unlock_cpu_hotplug();
++	put_online_cpus();
+ }
+ 
+ static int rtasd(void *unused)
+diff --git a/arch/powerpc/sysdev/ipic.c b/arch/powerpc/sysdev/ipic.c
+index 05a56e5..e898ff4 100644
+--- a/arch/powerpc/sysdev/ipic.c
++++ b/arch/powerpc/sysdev/ipic.c
+@@ -725,7 +725,7 @@ unsigned int ipic_get_irq(void)
+ }
+ 
+ static struct sysdev_class ipic_sysclass = {
+-	set_kset_name("ipic"),
++	.name = "ipic",
+ };
+ 
+ static struct sys_device device_ipic = {
+diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c
+index e479388..212a94f 100644
+--- a/arch/powerpc/sysdev/mpic.c
++++ b/arch/powerpc/sysdev/mpic.c
+@@ -1584,7 +1584,7 @@ static struct sysdev_class mpic_sysclass = {
+ 	.resume = mpic_resume,
+ 	.suspend = mpic_suspend,
+ #endif
+-	set_kset_name("mpic"),
++	.name = "mpic",
+ };
+ 
+ static int mpic_init_sys(void)
+diff --git a/arch/powerpc/sysdev/mv64x60_dev.c b/arch/powerpc/sysdev/mv64x60_dev.c
+index 548a320..4316f5a 100644
+--- a/arch/powerpc/sysdev/mv64x60_dev.c
++++ b/arch/powerpc/sysdev/mv64x60_dev.c
+@@ -361,12 +361,6 @@ static int __init mv64x60_i2c_device_setup(struct device_node *np, int id)
+ 	else
+ 		pdata.timeout = 1000;	/* 1 second */
+ 
+-	prop = of_get_property(np, "retries", NULL);
+-	if (prop)
+-		pdata.retries = *prop;
+-	else
+-		pdata.retries = 1;
+-
+ 	pdev = platform_device_alloc(MV64XXX_I2C_CTLR_NAME, id);
+ 	if (!pdev)
+ 		return -ENOMEM;
+diff --git a/arch/powerpc/sysdev/qe_lib/qe_ic.c b/arch/powerpc/sysdev/qe_lib/qe_ic.c
+index e1c0fd6..f59444d 100644
+--- a/arch/powerpc/sysdev/qe_lib/qe_ic.c
++++ b/arch/powerpc/sysdev/qe_lib/qe_ic.c
+@@ -483,7 +483,7 @@ int qe_ic_set_high_priority(unsigned int virq, unsigned int priority, int high)
+ }
+ 
+ static struct sysdev_class qe_ic_sysclass = {
+-	set_kset_name("qe_ic"),
++	.name = "qe_ic",
+ };
+ 
+ static struct sys_device device_qe_ic = {
+diff --git a/arch/ppc/platforms/83xx/mpc834x_sys.c b/arch/ppc/platforms/83xx/mpc834x_sys.c
+index b84f8df..cb0a749 100644
+--- a/arch/ppc/platforms/83xx/mpc834x_sys.c
++++ b/arch/ppc/platforms/83xx/mpc834x_sys.c
+@@ -224,26 +224,6 @@ mpc834x_sys_init_IRQ(void)
+ 	ipic_set_default_priority();
+ }
+ 
+-#if defined(CONFIG_I2C_MPC) && defined(CONFIG_SENSORS_DS1374)
+-extern ulong	ds1374_get_rtc_time(void);
+-extern int	ds1374_set_rtc_time(ulong);
+-
+-static int __init
+-mpc834x_rtc_hookup(void)
+-{
+-	struct timespec	tv;
+-
+-	ppc_md.get_rtc_time = ds1374_get_rtc_time;
+-	ppc_md.set_rtc_time = ds1374_set_rtc_time;
+-
+-	tv.tv_nsec = 0;
+-	tv.tv_sec = (ppc_md.get_rtc_time)();
+-	do_settimeofday(&tv);
+-
+-	return 0;
+-}
+-late_initcall(mpc834x_rtc_hookup);
+-#endif
+ static __inline__ void
+ mpc834x_sys_set_bat(void)
+ {
+diff --git a/arch/ppc/platforms/85xx/tqm85xx.c b/arch/ppc/platforms/85xx/tqm85xx.c
+index 4ee2bd1..27ce389 100644
+--- a/arch/ppc/platforms/85xx/tqm85xx.c
++++ b/arch/ppc/platforms/85xx/tqm85xx.c
+@@ -258,27 +258,6 @@ int tqm85xx_show_cpuinfo(struct seq_file *m)
+ 	return 0;
+ }
+ 
+-#if defined(CONFIG_I2C) && defined(CONFIG_SENSORS_DS1337)
+-extern ulong ds1337_get_rtc_time(void);
+-extern int ds1337_set_rtc_time(unsigned long nowtime);
+-
+-static int __init
+-tqm85xx_rtc_hookup(void)
+-{
+-	struct timespec	tv;
+-
+-        ppc_md.set_rtc_time = ds1337_set_rtc_time;
+-        ppc_md.get_rtc_time = ds1337_get_rtc_time;
+-
+-	tv.tv_nsec = 0;
+-	tv.tv_sec = (ppc_md.get_rtc_time)();
+-	do_settimeofday(&tv);
+-
+-	return 0;
+-}
+-late_initcall(tqm85xx_rtc_hookup);
+-#endif
+-
+ #ifdef CONFIG_PCI
+ /*
+  * interrupt routing
+diff --git a/arch/ppc/platforms/katana.c b/arch/ppc/platforms/katana.c
+index 52f63e6..fe6e88c 100644
+--- a/arch/ppc/platforms/katana.c
++++ b/arch/ppc/platforms/katana.c
+@@ -838,27 +838,6 @@ katana_find_end_of_memory(void)
+ 	return bdp->bi_memsize;
+ }
+ 
+-#if defined(CONFIG_I2C_MV64XXX) && defined(CONFIG_SENSORS_M41T00)
+-extern ulong	m41t00_get_rtc_time(void);
+-extern int	m41t00_set_rtc_time(ulong);
+-
+-static int __init
+-katana_rtc_hookup(void)
+-{
+-	struct timespec	tv;
+-
+-	ppc_md.get_rtc_time = m41t00_get_rtc_time;
+-	ppc_md.set_rtc_time = m41t00_set_rtc_time;
+-
+-	tv.tv_nsec = 0;
+-	tv.tv_sec = (ppc_md.get_rtc_time)();
+-	do_settimeofday(&tv);
+-
+-	return 0;
+-}
+-late_initcall(katana_rtc_hookup);
+-#endif
+-
+ #if defined(CONFIG_SERIAL_TEXT_DEBUG) && defined(CONFIG_SERIAL_MPSC_CONSOLE)
+ static void __init
+ katana_map_io(void)
+diff --git a/arch/ppc/syslib/ipic.c b/arch/ppc/syslib/ipic.c
+index 9192777..4f163e2 100644
+--- a/arch/ppc/syslib/ipic.c
++++ b/arch/ppc/syslib/ipic.c
+@@ -614,7 +614,7 @@ int ipic_get_irq(void)
+ }
+ 
+ static struct sysdev_class ipic_sysclass = {
+-	set_kset_name("ipic"),
++	.name = "ipic",
+ };
+ 
+ static struct sys_device device_ipic = {
+diff --git a/arch/ppc/syslib/mv64x60.c b/arch/ppc/syslib/mv64x60.c
+index 2744b8a..90fe904 100644
+--- a/arch/ppc/syslib/mv64x60.c
++++ b/arch/ppc/syslib/mv64x60.c
+@@ -411,7 +411,6 @@ static struct mv64xxx_i2c_pdata mv64xxx_i2c_pdata = {
+ 	.freq_m			= 8,
+ 	.freq_n			= 3,
+ 	.timeout		= 1000, /* Default timeout of 1 second */
+-	.retries		= 1,
+ };
+ 
+ static struct resource mv64xxx_i2c_resources[] = {
+diff --git a/arch/ppc/syslib/open_pic.c b/arch/ppc/syslib/open_pic.c
+index 18ec947..da36522 100644
+--- a/arch/ppc/syslib/open_pic.c
++++ b/arch/ppc/syslib/open_pic.c
+@@ -1043,7 +1043,7 @@ int openpic_resume(struct sys_device *sysdev)
+ #endif /* CONFIG_PM */
+ 
+ static struct sysdev_class openpic_sysclass = {
+-	set_kset_name("openpic"),
++	.name = "openpic",
+ };
+ 
+ static struct sys_device device_openpic = {
+diff --git a/arch/ppc/syslib/open_pic2.c b/arch/ppc/syslib/open_pic2.c
+index d585207..449075a 100644
+--- a/arch/ppc/syslib/open_pic2.c
++++ b/arch/ppc/syslib/open_pic2.c
+@@ -666,7 +666,7 @@ int openpic2_resume(struct sys_device *sysdev)
+ 
+ /* HACK ALERT */
+ static struct sysdev_class openpic2_sysclass = {
+-	set_kset_name("openpic2"),
++	.name = "openpic2",
+ };
+ 
+ static struct sys_device device_openpic2 = {
+diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig
+index 1330061..6ef54d2 100644
+--- a/arch/s390/Kconfig
++++ b/arch/s390/Kconfig
+@@ -276,9 +276,6 @@ source "kernel/Kconfig.preempt"
+ 
+ source "mm/Kconfig"
+ 
+-config HOLES_IN_ZONE
+-	def_bool y
+-
+ comment "I/O subsystem configuration"
+ 
+ config MACHCHK_WARNING
+diff --git a/arch/s390/crypto/Kconfig b/arch/s390/crypto/Kconfig
+deleted file mode 100644
+index d1defbb..0000000
+--- a/arch/s390/crypto/Kconfig
++++ /dev/null
+@@ -1,60 +0,0 @@
+-config CRYPTO_SHA1_S390
+-	tristate "SHA1 digest algorithm"
+-	depends on S390
+-	select CRYPTO_ALGAPI
+-	help
+-	  This is the s390 hardware accelerated implementation of the
+-	  SHA-1 secure hash standard (FIPS 180-1/DFIPS 180-2).
+-
+-config CRYPTO_SHA256_S390
+-	tristate "SHA256 digest algorithm"
+-	depends on S390
+-	select CRYPTO_ALGAPI
+-	help
+-	  This is the s390 hardware accelerated implementation of the
+-	  SHA256 secure hash standard (DFIPS 180-2).
+-
+-	  This version of SHA implements a 256 bit hash with 128 bits of
+-	  security against collision attacks.
+-
+-config CRYPTO_DES_S390
+-	tristate "DES and Triple DES cipher algorithms"
+-	depends on S390
+-	select CRYPTO_ALGAPI
+-	select CRYPTO_BLKCIPHER
+-	help
+-	  This us the s390 hardware accelerated implementation of the
+-	  DES cipher algorithm (FIPS 46-2), and Triple DES EDE (FIPS 46-3).
+-
+-config CRYPTO_AES_S390
+-	tristate "AES cipher algorithms"
+-	depends on S390
+-	select CRYPTO_ALGAPI
+-	select CRYPTO_BLKCIPHER
+-	help
+-	  This is the s390 hardware accelerated implementation of the
+-	  AES cipher algorithms (FIPS-197). AES uses the Rijndael
+-	  algorithm.
+-
+-	  Rijndael appears to be consistently a very good performer in
+-	  both hardware and software across a wide range of computing
+-	  environments regardless of its use in feedback or non-feedback
+-	  modes. Its key setup time is excellent, and its key agility is
+-	  good. Rijndael's very low memory requirements make it very well
+-	  suited for restricted-space environments, in which it also
+-	  demonstrates excellent performance. Rijndael's operations are
+-	  among the easiest to defend against power and timing attacks.
+-
+-	  On s390 the System z9-109 currently only supports the key size
+-	  of 128 bit.
+-
+-config S390_PRNG
+-	tristate "Pseudo random number generator device driver"
+-	depends on S390
+-	default "m"
+-	help
+-	  Select this option if you want to use the s390 pseudo random number
+-	  generator. The PRNG is part of the cryptographic processor functions
+-	  and uses triple-DES to generate secure random numbers like the
+-	  ANSI X9.17 standard. The PRNG is usable via the char device
+-	  /dev/prandom.
+diff --git a/arch/s390/crypto/aes_s390.c b/arch/s390/crypto/aes_s390.c
+index 5126696..a3f67f8 100644
+--- a/arch/s390/crypto/aes_s390.c
++++ b/arch/s390/crypto/aes_s390.c
+@@ -6,6 +6,7 @@
+  * s390 Version:
+  *   Copyright IBM Corp. 2005,2007
+  *   Author(s): Jan Glauber (jang at de.ibm.com)
++ *		Sebastian Siewior (sebastian at breakpoint.cc> SW-Fallback
+  *
+  * Derived from "crypto/aes_generic.c"
+  *
+@@ -16,17 +17,13 @@
+  *
+  */
+ 
++#include <crypto/aes.h>
+ #include <crypto/algapi.h>
++#include <linux/err.h>
+ #include <linux/module.h>
+ #include <linux/init.h>
+ #include "crypt_s390.h"
+ 
+-#define AES_MIN_KEY_SIZE	16
+-#define AES_MAX_KEY_SIZE	32
+-
+-/* data block size for all key lengths */
+-#define AES_BLOCK_SIZE		16
+-
+ #define AES_KEYLEN_128		1
+ #define AES_KEYLEN_192		2
+ #define AES_KEYLEN_256		4
+@@ -39,45 +36,89 @@ struct s390_aes_ctx {
+ 	long enc;
+ 	long dec;
+ 	int key_len;
++	union {
++		struct crypto_blkcipher *blk;
++		struct crypto_cipher *cip;
++	} fallback;
+ };
+ 
+-static int aes_set_key(struct crypto_tfm *tfm, const u8 *in_key,
+-		       unsigned int key_len)
++/*
++ * Check if the key_len is supported by the HW.
++ * Returns 0 if it is, a positive number if it is not and software fallback is
++ * required or a negative number in case the key size is not valid
++ */
++static int need_fallback(unsigned int key_len)
+ {
+-	struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm);
+-	u32 *flags = &tfm->crt_flags;
+-
+ 	switch (key_len) {
+ 	case 16:
+ 		if (!(keylen_flag & AES_KEYLEN_128))
+-			goto fail;
++			return 1;
+ 		break;
+ 	case 24:
+ 		if (!(keylen_flag & AES_KEYLEN_192))
+-			goto fail;
+-
++			return 1;
+ 		break;
+ 	case 32:
+ 		if (!(keylen_flag & AES_KEYLEN_256))
+-			goto fail;
++			return 1;
+ 		break;
+ 	default:
+-		goto fail;
++		return -1;
+ 		break;
+ 	}
++	return 0;
++}
++
++static int setkey_fallback_cip(struct crypto_tfm *tfm, const u8 *in_key,
++		unsigned int key_len)
++{
++	struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm);
++	int ret;
++
++	sctx->fallback.blk->base.crt_flags &= ~CRYPTO_TFM_REQ_MASK;
++	sctx->fallback.blk->base.crt_flags |= (tfm->crt_flags &
++			CRYPTO_TFM_REQ_MASK);
++
++	ret = crypto_cipher_setkey(sctx->fallback.cip, in_key, key_len);
++	if (ret) {
++		tfm->crt_flags &= ~CRYPTO_TFM_RES_MASK;
++		tfm->crt_flags |= (sctx->fallback.blk->base.crt_flags &
++				CRYPTO_TFM_RES_MASK);
++	}
++	return ret;
++}
++
++static int aes_set_key(struct crypto_tfm *tfm, const u8 *in_key,
++		       unsigned int key_len)
++{
++	struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm);
++	u32 *flags = &tfm->crt_flags;
++	int ret;
++
++	ret = need_fallback(key_len);
++	if (ret < 0) {
++		*flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
++		return -EINVAL;
++	}
+ 
+ 	sctx->key_len = key_len;
+-	memcpy(sctx->key, in_key, key_len);
+-	return 0;
+-fail:
+-	*flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
+-	return -EINVAL;
++	if (!ret) {
++		memcpy(sctx->key, in_key, key_len);
++		return 0;
++	}
++
++	return setkey_fallback_cip(tfm, in_key, key_len);
+ }
+ 
+ static void aes_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
+ {
+ 	const struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm);
+ 
++	if (unlikely(need_fallback(sctx->key_len))) {
++		crypto_cipher_encrypt_one(sctx->fallback.cip, out, in);
++		return;
++	}
++
+ 	switch (sctx->key_len) {
+ 	case 16:
+ 		crypt_s390_km(KM_AES_128_ENCRYPT, &sctx->key, out, in,
+@@ -98,6 +139,11 @@ static void aes_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
+ {
+ 	const struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm);
+ 
++	if (unlikely(need_fallback(sctx->key_len))) {
++		crypto_cipher_decrypt_one(sctx->fallback.cip, out, in);
++		return;
++	}
++
+ 	switch (sctx->key_len) {
+ 	case 16:
+ 		crypt_s390_km(KM_AES_128_DECRYPT, &sctx->key, out, in,
+@@ -114,6 +160,29 @@ static void aes_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
+ 	}
+ }
+ 
++static int fallback_init_cip(struct crypto_tfm *tfm)
++{
++	const char *name = tfm->__crt_alg->cra_name;
++	struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm);
++
++	sctx->fallback.cip = crypto_alloc_cipher(name, 0,
++			CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK);
++
++	if (IS_ERR(sctx->fallback.cip)) {
++		printk(KERN_ERR "Error allocating fallback algo %s\n", name);
++		return PTR_ERR(sctx->fallback.blk);
++	}
++
++	return 0;
++}
++
++static void fallback_exit_cip(struct crypto_tfm *tfm)
++{
++	struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm);
++
++	crypto_free_cipher(sctx->fallback.cip);
++	sctx->fallback.cip = NULL;
++}
+ 
+ static struct crypto_alg aes_alg = {
+ 	.cra_name		=	"aes",
+@@ -125,6 +194,8 @@ static struct crypto_alg aes_alg = {
+ 	.cra_ctxsize		=	sizeof(struct s390_aes_ctx),
+ 	.cra_module		=	THIS_MODULE,
+ 	.cra_list		=	LIST_HEAD_INIT(aes_alg.cra_list),
++	.cra_init               =       fallback_init_cip,
++	.cra_exit               =       fallback_exit_cip,
+ 	.cra_u			=	{
+ 		.cipher = {
+ 			.cia_min_keysize	=	AES_MIN_KEY_SIZE,
+@@ -136,10 +207,70 @@ static struct crypto_alg aes_alg = {
+ 	}
+ };
+ 
++static int setkey_fallback_blk(struct crypto_tfm *tfm, const u8 *key,
++		unsigned int len)
++{
++	struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm);
++	unsigned int ret;
++
++	sctx->fallback.blk->base.crt_flags &= ~CRYPTO_TFM_REQ_MASK;
++	sctx->fallback.blk->base.crt_flags |= (tfm->crt_flags &
++			CRYPTO_TFM_REQ_MASK);
++
++	ret = crypto_blkcipher_setkey(sctx->fallback.blk, key, len);
++	if (ret) {
++		tfm->crt_flags &= ~CRYPTO_TFM_RES_MASK;
++		tfm->crt_flags |= (sctx->fallback.blk->base.crt_flags &
++				CRYPTO_TFM_RES_MASK);
++	}
++	return ret;
++}
++
++static int fallback_blk_dec(struct blkcipher_desc *desc,
++		struct scatterlist *dst, struct scatterlist *src,
++		unsigned int nbytes)
++{
++	unsigned int ret;
++	struct crypto_blkcipher *tfm;
++	struct s390_aes_ctx *sctx = crypto_blkcipher_ctx(desc->tfm);
++
++	tfm = desc->tfm;
++	desc->tfm = sctx->fallback.blk;
++
++	ret = crypto_blkcipher_decrypt_iv(desc, dst, src, nbytes);
++
++	desc->tfm = tfm;
++	return ret;
++}
++
++static int fallback_blk_enc(struct blkcipher_desc *desc,
++		struct scatterlist *dst, struct scatterlist *src,
++		unsigned int nbytes)
++{
++	unsigned int ret;
++	struct crypto_blkcipher *tfm;
++	struct s390_aes_ctx *sctx = crypto_blkcipher_ctx(desc->tfm);
++
++	tfm = desc->tfm;
++	desc->tfm = sctx->fallback.blk;
++
++	ret = crypto_blkcipher_encrypt_iv(desc, dst, src, nbytes);
++
++	desc->tfm = tfm;
++	return ret;
++}
++
+ static int ecb_aes_set_key(struct crypto_tfm *tfm, const u8 *in_key,
+ 			   unsigned int key_len)
+ {
+ 	struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm);
++	int ret;
++
++	ret = need_fallback(key_len);
++	if (ret > 0) {
++		sctx->key_len = key_len;
++		return setkey_fallback_blk(tfm, in_key, key_len);
++	}
+ 
+ 	switch (key_len) {
+ 	case 16:
+@@ -188,6 +319,9 @@ static int ecb_aes_encrypt(struct blkcipher_desc *desc,
+ 	struct s390_aes_ctx *sctx = crypto_blkcipher_ctx(desc->tfm);
+ 	struct blkcipher_walk walk;
+ 
++	if (unlikely(need_fallback(sctx->key_len)))
++		return fallback_blk_enc(desc, dst, src, nbytes);
++
+ 	blkcipher_walk_init(&walk, dst, src, nbytes);
+ 	return ecb_aes_crypt(desc, sctx->enc, sctx->key, &walk);
+ }
+@@ -199,10 +333,37 @@ static int ecb_aes_decrypt(struct blkcipher_desc *desc,
+ 	struct s390_aes_ctx *sctx = crypto_blkcipher_ctx(desc->tfm);
+ 	struct blkcipher_walk walk;
+ 
++	if (unlikely(need_fallback(sctx->key_len)))
++		return fallback_blk_dec(desc, dst, src, nbytes);
++
+ 	blkcipher_walk_init(&walk, dst, src, nbytes);
+ 	return ecb_aes_crypt(desc, sctx->dec, sctx->key, &walk);
+ }
+ 
++static int fallback_init_blk(struct crypto_tfm *tfm)
++{
++	const char *name = tfm->__crt_alg->cra_name;
++	struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm);
++
++	sctx->fallback.blk = crypto_alloc_blkcipher(name, 0,
++			CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK);
++
++	if (IS_ERR(sctx->fallback.blk)) {
++		printk(KERN_ERR "Error allocating fallback algo %s\n", name);
++		return PTR_ERR(sctx->fallback.blk);
++	}
++
++	return 0;
++}
++
++static void fallback_exit_blk(struct crypto_tfm *tfm)
++{
++	struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm);
++
++	crypto_free_blkcipher(sctx->fallback.blk);
++	sctx->fallback.blk = NULL;
++}
++
+ static struct crypto_alg ecb_aes_alg = {
+ 	.cra_name		=	"ecb(aes)",
+ 	.cra_driver_name	=	"ecb-aes-s390",
+@@ -214,6 +375,8 @@ static struct crypto_alg ecb_aes_alg = {
+ 	.cra_type		=	&crypto_blkcipher_type,
+ 	.cra_module		=	THIS_MODULE,
+ 	.cra_list		=	LIST_HEAD_INIT(ecb_aes_alg.cra_list),
++	.cra_init		=	fallback_init_blk,
++	.cra_exit		=	fallback_exit_blk,
+ 	.cra_u			=	{
+ 		.blkcipher = {
+ 			.min_keysize		=	AES_MIN_KEY_SIZE,
+@@ -229,6 +392,13 @@ static int cbc_aes_set_key(struct crypto_tfm *tfm, const u8 *in_key,
+ 			   unsigned int key_len)
+ {
+ 	struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm);
++	int ret;
++
++	ret = need_fallback(key_len);
++	if (ret > 0) {
++		sctx->key_len = key_len;
++		return setkey_fallback_blk(tfm, in_key, key_len);
++	}
+ 
+ 	switch (key_len) {
+ 	case 16:
+@@ -283,6 +453,9 @@ static int cbc_aes_encrypt(struct blkcipher_desc *desc,
+ 	struct s390_aes_ctx *sctx = crypto_blkcipher_ctx(desc->tfm);
+ 	struct blkcipher_walk walk;
+ 
++	if (unlikely(need_fallback(sctx->key_len)))
++		return fallback_blk_enc(desc, dst, src, nbytes);
++
+ 	blkcipher_walk_init(&walk, dst, src, nbytes);
+ 	return cbc_aes_crypt(desc, sctx->enc, sctx->iv, &walk);
+ }
+@@ -294,6 +467,9 @@ static int cbc_aes_decrypt(struct blkcipher_desc *desc,
+ 	struct s390_aes_ctx *sctx = crypto_blkcipher_ctx(desc->tfm);
+ 	struct blkcipher_walk walk;
+ 
++	if (unlikely(need_fallback(sctx->key_len)))
++		return fallback_blk_dec(desc, dst, src, nbytes);
++
+ 	blkcipher_walk_init(&walk, dst, src, nbytes);
+ 	return cbc_aes_crypt(desc, sctx->dec, sctx->iv, &walk);
+ }
+@@ -309,6 +485,8 @@ static struct crypto_alg cbc_aes_alg = {
+ 	.cra_type		=	&crypto_blkcipher_type,
+ 	.cra_module		=	THIS_MODULE,
+ 	.cra_list		=	LIST_HEAD_INIT(cbc_aes_alg.cra_list),
++	.cra_init		=	fallback_init_blk,
++	.cra_exit		=	fallback_exit_blk,
+ 	.cra_u			=	{
+ 		.blkcipher = {
+ 			.min_keysize		=	AES_MIN_KEY_SIZE,
+@@ -336,14 +514,10 @@ static int __init aes_init(void)
+ 		return -EOPNOTSUPP;
+ 
+ 	/* z9 109 and z9 BC/EC only support 128 bit key length */
+-	if (keylen_flag == AES_KEYLEN_128) {
+-		aes_alg.cra_u.cipher.cia_max_keysize = AES_MIN_KEY_SIZE;
+-		ecb_aes_alg.cra_u.blkcipher.max_keysize = AES_MIN_KEY_SIZE;
+-		cbc_aes_alg.cra_u.blkcipher.max_keysize = AES_MIN_KEY_SIZE;
++	if (keylen_flag == AES_KEYLEN_128)
+ 		printk(KERN_INFO
+-		       "aes_s390: hardware acceleration only available for"
++		       "aes_s390: hardware acceleration only available for "
+ 		       "128 bit keys\n");
+-	}
+ 
+ 	ret = crypto_register_alg(&aes_alg);
+ 	if (ret)
+@@ -382,4 +556,3 @@ MODULE_ALIAS("aes");
+ 
+ MODULE_DESCRIPTION("Rijndael (AES) Cipher Algorithm");
+ MODULE_LICENSE("GPL");
+-
+diff --git a/arch/s390/crypto/prng.c b/arch/s390/crypto/prng.c
+index 8eb3a1a..0cfefdd 100644
+--- a/arch/s390/crypto/prng.c
++++ b/arch/s390/crypto/prng.c
+@@ -90,7 +90,7 @@ static ssize_t prng_read(struct file *file, char __user *ubuf, size_t nbytes,
+ 	int ret = 0;
+ 	int tmp;
+ 
+-	/* nbytes can be arbitrary long, we spilt it into chunks */
++	/* nbytes can be arbitrary length, we split it into chunks */
+ 	while (nbytes) {
+ 		/* same as in extract_entropy_user in random.c */
+ 		if (need_resched()) {
+@@ -146,7 +146,7 @@ static ssize_t prng_read(struct file *file, char __user *ubuf, size_t nbytes,
+ 	return ret;
+ }
+ 
+-static struct file_operations prng_fops = {
++static const struct file_operations prng_fops = {
+ 	.owner		= THIS_MODULE,
+ 	.open		= &prng_open,
+ 	.release	= NULL,
+diff --git a/arch/s390/hypfs/inode.c b/arch/s390/hypfs/inode.c
+index 5245717..4b010ff 100644
+--- a/arch/s390/hypfs/inode.c
++++ b/arch/s390/hypfs/inode.c
+@@ -490,7 +490,7 @@ static struct super_operations hypfs_s_ops = {
+ 	.show_options	= hypfs_show_options,
+ };
+ 
+-static decl_subsys(s390, NULL, NULL);
++static struct kobject *s390_kobj;
+ 
+ static int __init hypfs_init(void)
+ {
+@@ -506,17 +506,18 @@ static int __init hypfs_init(void)
+ 			goto fail_diag;
+ 		}
+ 	}
+-	kobj_set_kset_s(&s390_subsys, hypervisor_subsys);
+-	rc = subsystem_register(&s390_subsys);
+-	if (rc)
++	s390_kobj = kobject_create_and_add("s390", hypervisor_kobj);
++	if (!s390_kobj) {
++		rc = -ENOMEM;;
+ 		goto fail_sysfs;
++	}
+ 	rc = register_filesystem(&hypfs_type);
+ 	if (rc)
+ 		goto fail_filesystem;
+ 	return 0;
+ 
+ fail_filesystem:
+-	subsystem_unregister(&s390_subsys);
++	kobject_put(s390_kobj);
+ fail_sysfs:
+ 	if (!MACHINE_IS_VM)
+ 		hypfs_diag_exit();
+@@ -530,7 +531,7 @@ static void __exit hypfs_exit(void)
+ 	if (!MACHINE_IS_VM)
+ 		hypfs_diag_exit();
+ 	unregister_filesystem(&hypfs_type);
+-	subsystem_unregister(&s390_subsys);
++	kobject_put(s390_kobj);
+ }
+ 
+ module_init(hypfs_init)
+diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile
+index 56cb710..b3b650a 100644
+--- a/arch/s390/kernel/Makefile
++++ b/arch/s390/kernel/Makefile
+@@ -31,7 +31,3 @@ S390_KEXEC_OBJS := machine_kexec.o crash.o
+ S390_KEXEC_OBJS += $(if $(CONFIG_64BIT),relocate_kernel64.o,relocate_kernel.o)
+ obj-$(CONFIG_KEXEC) += $(S390_KEXEC_OBJS)
+ 
+-#
+-# This is just to get the dependencies...
+-#
+-binfmt_elf32.o:	$(TOPDIR)/fs/binfmt_elf.c
+diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c
+index 1b3af7d..9f7b73b 100644
+--- a/arch/s390/kernel/early.c
++++ b/arch/s390/kernel/early.c
+@@ -276,7 +276,7 @@ void __init startup_init(void)
+ 	create_kernel_nss();
+ 	sort_main_extable();
+ 	setup_lowcore_early();
+-	sclp_readinfo_early();
++	sclp_read_info_early();
+ 	sclp_facilities_detect();
+ 	memsize = sclp_memory_detect();
+ #ifndef CONFIG_64BIT
+diff --git a/arch/s390/kernel/head64.S b/arch/s390/kernel/head64.S
+index a87b197..79dccd2 100644
+--- a/arch/s390/kernel/head64.S
++++ b/arch/s390/kernel/head64.S
+@@ -157,7 +157,7 @@ startup_continue:
+ 	.long	0xb2b10000		# store facility list
+ 	tm	0xc8,0x08		# check bit for clearing-by-ASCE
+ 	bno	0f-.LPG1(%r13)
+-	lhi	%r1,2094
++	lhi	%r1,2048
+ 	lhi	%r2,0
+ 	.long	0xb98e2001
+ 	oi	7(%r12),0x80		# set IDTE flag
+diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c
+index ce0856d..db28cca 100644
+--- a/arch/s390/kernel/ipl.c
++++ b/arch/s390/kernel/ipl.c
+@@ -2,7 +2,7 @@
+  *  arch/s390/kernel/ipl.c
+  *    ipl/reipl/dump support for Linux on s390.
+  *
+- *    Copyright (C) IBM Corp. 2005,2006
++ *    Copyright IBM Corp. 2005,2007
+  *    Author(s): Michael Holzheu <holzheu at de.ibm.com>
+  *		 Heiko Carstens <heiko.carstens at de.ibm.com>
+  *		 Volker Sameske <sameske at de.ibm.com>
+@@ -31,6 +31,43 @@
+ #define IPL_FCP_DUMP_STR	"fcp_dump"
+ #define IPL_NSS_STR		"nss"
+ 
++#define DUMP_CCW_STR		"ccw"
++#define DUMP_FCP_STR		"fcp"
++#define DUMP_NONE_STR		"none"
++
++/*
++ * Four shutdown trigger types are supported:
++ * - panic
++ * - halt
++ * - power off
++ * - reipl
++ */
++#define ON_PANIC_STR		"on_panic"
++#define ON_HALT_STR		"on_halt"
++#define ON_POFF_STR		"on_poff"
++#define ON_REIPL_STR		"on_reboot"
++
++struct shutdown_action;
++struct shutdown_trigger {
++	char *name;
++	struct shutdown_action *action;
++};
++
++/*
++ * Five shutdown action types are supported:
++ */
++#define SHUTDOWN_ACTION_IPL_STR		"ipl"
++#define SHUTDOWN_ACTION_REIPL_STR	"reipl"
++#define SHUTDOWN_ACTION_DUMP_STR	"dump"
++#define SHUTDOWN_ACTION_VMCMD_STR	"vmcmd"
++#define SHUTDOWN_ACTION_STOP_STR	"stop"
++
++struct shutdown_action {
++	char *name;
++	void (*fn) (struct shutdown_trigger *trigger);
++	int (*init) (void);
++};
++
+ static char *ipl_type_str(enum ipl_type type)
+ {
+ 	switch (type) {
+@@ -54,10 +91,6 @@ enum dump_type {
+ 	DUMP_TYPE_FCP	= 4,
+ };
+ 
+-#define DUMP_NONE_STR	 "none"
+-#define DUMP_CCW_STR	 "ccw"
+-#define DUMP_FCP_STR	 "fcp"
+-
+ static char *dump_type_str(enum dump_type type)
+ {
+ 	switch (type) {
+@@ -99,30 +132,6 @@ enum dump_method {
+ 	DUMP_METHOD_FCP_DIAG,
+ };
+ 
+-enum shutdown_action {
+-	SHUTDOWN_REIPL,
+-	SHUTDOWN_DUMP,
+-	SHUTDOWN_STOP,
+-};
+-
+-#define SHUTDOWN_REIPL_STR "reipl"
+-#define SHUTDOWN_DUMP_STR  "dump"
+-#define SHUTDOWN_STOP_STR  "stop"
+-
+-static char *shutdown_action_str(enum shutdown_action action)
+-{
+-	switch (action) {
+-	case SHUTDOWN_REIPL:
+-		return SHUTDOWN_REIPL_STR;
+-	case SHUTDOWN_DUMP:
+-		return SHUTDOWN_DUMP_STR;
+-	case SHUTDOWN_STOP:
+-		return SHUTDOWN_STOP_STR;
+-	default:
+-		return NULL;
+-	}
+-}
+-
+ static int diag308_set_works = 0;
+ 
+ static int reipl_capabilities = IPL_TYPE_UNKNOWN;
+@@ -140,8 +149,6 @@ static enum dump_method dump_method = DUMP_METHOD_NONE;
+ static struct ipl_parameter_block *dump_block_fcp;
+ static struct ipl_parameter_block *dump_block_ccw;
+ 
+-static enum shutdown_action on_panic_action = SHUTDOWN_STOP;
+-
+ static struct sclp_ipl_info sclp_ipl_info;
+ 
+ int diag308(unsigned long subcode, void *addr)
+@@ -162,22 +169,25 @@ EXPORT_SYMBOL_GPL(diag308);
+ /* SYSFS */
+ 
+ #define DEFINE_IPL_ATTR_RO(_prefix, _name, _format, _value)		\
+-static ssize_t sys_##_prefix##_##_name##_show(struct kset *kset,	\
++static ssize_t sys_##_prefix##_##_name##_show(struct kobject *kobj,	\
++		struct kobj_attribute *attr,				\
+ 		char *page)						\
+ {									\
+ 	return sprintf(page, _format, _value);				\
+ }									\
+-static struct subsys_attribute sys_##_prefix##_##_name##_attr =		\
++static struct kobj_attribute sys_##_prefix##_##_name##_attr =		\
+ 	__ATTR(_name, S_IRUGO, sys_##_prefix##_##_name##_show, NULL);
+ 
+ #define DEFINE_IPL_ATTR_RW(_prefix, _name, _fmt_out, _fmt_in, _value)	\
+-static ssize_t sys_##_prefix##_##_name##_show(struct kset *kset,	\
++static ssize_t sys_##_prefix##_##_name##_show(struct kobject *kobj,	\
++		struct kobj_attribute *attr,				\
+ 		char *page)						\
+ {									\
+ 	return sprintf(page, _fmt_out,					\
+ 			(unsigned long long) _value);			\
+ }									\
+-static ssize_t sys_##_prefix##_##_name##_store(struct kset *kset,	\
++static ssize_t sys_##_prefix##_##_name##_store(struct kobject *kobj,	\
++		struct kobj_attribute *attr,				\
+ 		const char *buf, size_t len)				\
+ {									\
+ 	unsigned long long value;					\
+@@ -186,25 +196,27 @@ static ssize_t sys_##_prefix##_##_name##_store(struct kset *kset,	\
+ 	_value = value;							\
+ 	return len;							\
+ }									\
+-static struct subsys_attribute sys_##_prefix##_##_name##_attr =		\
++static struct kobj_attribute sys_##_prefix##_##_name##_attr =		\
+ 	__ATTR(_name,(S_IRUGO | S_IWUSR),				\
+ 			sys_##_prefix##_##_name##_show,			\
+ 			sys_##_prefix##_##_name##_store);
+ 
+ #define DEFINE_IPL_ATTR_STR_RW(_prefix, _name, _fmt_out, _fmt_in, _value)\
+-static ssize_t sys_##_prefix##_##_name##_show(struct kset *kset,	\
++static ssize_t sys_##_prefix##_##_name##_show(struct kobject *kobj,	\
++		struct kobj_attribute *attr,				\
+ 		char *page)						\
+ {									\
+ 	return sprintf(page, _fmt_out, _value);				\
+ }									\
+-static ssize_t sys_##_prefix##_##_name##_store(struct kset *kset,	\
++static ssize_t sys_##_prefix##_##_name##_store(struct kobject *kobj,	\
++		struct kobj_attribute *attr,				\
+ 		const char *buf, size_t len)				\
+ {									\
+-	if (sscanf(buf, _fmt_in, _value) != 1)				\
+-		return -EINVAL;						\
++	strncpy(_value, buf, sizeof(_value) - 1);			\
++	strstrip(_value);						\
+ 	return len;							\
+ }									\
+-static struct subsys_attribute sys_##_prefix##_##_name##_attr =		\
++static struct kobj_attribute sys_##_prefix##_##_name##_attr =		\
+ 	__ATTR(_name,(S_IRUGO | S_IWUSR),				\
+ 			sys_##_prefix##_##_name##_show,			\
+ 			sys_##_prefix##_##_name##_store);
+@@ -240,44 +252,19 @@ static __init enum ipl_type get_ipl_type(void)
+ 	return IPL_TYPE_FCP;
+ }
+ 
+-void __init setup_ipl_info(void)
+-{
+-	ipl_info.type = get_ipl_type();
+-	switch (ipl_info.type) {
+-	case IPL_TYPE_CCW:
+-		ipl_info.data.ccw.dev_id.devno = ipl_devno;
+-		ipl_info.data.ccw.dev_id.ssid = 0;
+-		break;
+-	case IPL_TYPE_FCP:
+-	case IPL_TYPE_FCP_DUMP:
+-		ipl_info.data.fcp.dev_id.devno =
+-			IPL_PARMBLOCK_START->ipl_info.fcp.devno;
+-		ipl_info.data.fcp.dev_id.ssid = 0;
+-		ipl_info.data.fcp.wwpn = IPL_PARMBLOCK_START->ipl_info.fcp.wwpn;
+-		ipl_info.data.fcp.lun = IPL_PARMBLOCK_START->ipl_info.fcp.lun;
+-		break;
+-	case IPL_TYPE_NSS:
+-		strncpy(ipl_info.data.nss.name, kernel_nss_name,
+-			sizeof(ipl_info.data.nss.name));
+-		break;
+-	case IPL_TYPE_UNKNOWN:
+-	default:
+-		/* We have no info to copy */
+-		break;
+-	}
+-}
+-
+ struct ipl_info ipl_info;
+ EXPORT_SYMBOL_GPL(ipl_info);
+ 
+-static ssize_t ipl_type_show(struct kset *kset, char *page)
++static ssize_t ipl_type_show(struct kobject *kobj, struct kobj_attribute *attr,
++			     char *page)
+ {
+ 	return sprintf(page, "%s\n", ipl_type_str(ipl_info.type));
+ }
+ 
+-static struct subsys_attribute sys_ipl_type_attr = __ATTR_RO(ipl_type);
++static struct kobj_attribute sys_ipl_type_attr = __ATTR_RO(ipl_type);
+ 
+-static ssize_t sys_ipl_device_show(struct kset *kset, char *page)
++static ssize_t sys_ipl_device_show(struct kobject *kobj,
++				   struct kobj_attribute *attr, char *page)
+ {
+ 	struct ipl_parameter_block *ipl = IPL_PARMBLOCK_START;
+ 
+@@ -292,7 +279,7 @@ static ssize_t sys_ipl_device_show(struct kset *kset, char *page)
+ 	}
+ }
+ 
+-static struct subsys_attribute sys_ipl_device_attr =
++static struct kobj_attribute sys_ipl_device_attr =
+ 	__ATTR(device, S_IRUGO, sys_ipl_device_show, NULL);
+ 
+ static ssize_t ipl_parameter_read(struct kobject *kobj, struct bin_attribute *attr,
+@@ -367,7 +354,8 @@ static struct attribute_group ipl_fcp_attr_group = {
+ 
+ /* CCW ipl device attributes */
+ 
+-static ssize_t ipl_ccw_loadparm_show(struct kset *kset, char *page)
++static ssize_t ipl_ccw_loadparm_show(struct kobject *kobj,
++				     struct kobj_attribute *attr, char *page)
+ {
+ 	char loadparm[LOADPARM_LEN + 1] = {};
+ 
+@@ -379,7 +367,7 @@ static ssize_t ipl_ccw_loadparm_show(struct kset *kset, char *page)
+ 	return sprintf(page, "%s\n", loadparm);
+ }
+ 
+-static struct subsys_attribute sys_ipl_ccw_loadparm_attr =
++static struct kobj_attribute sys_ipl_ccw_loadparm_attr =
+ 	__ATTR(loadparm, 0444, ipl_ccw_loadparm_show, NULL);
+ 
+ static struct attribute *ipl_ccw_attrs[] = {
+@@ -418,10 +406,76 @@ static struct attribute_group ipl_unknown_attr_group = {
+ 	.attrs = ipl_unknown_attrs,
+ };
+ 
+-static decl_subsys(ipl, NULL, NULL);
++static struct kset *ipl_kset;
++
++static int __init ipl_register_fcp_files(void)
++{
++	int rc;
++
++	rc = sysfs_create_group(&ipl_kset->kobj, &ipl_fcp_attr_group);
++	if (rc)
++		goto out;
++	rc = sysfs_create_bin_file(&ipl_kset->kobj, &ipl_parameter_attr);
++	if (rc)
++		goto out_ipl_parm;
++	rc = sysfs_create_bin_file(&ipl_kset->kobj, &ipl_scp_data_attr);
++	if (!rc)
++		goto out;
++
++	sysfs_remove_bin_file(&ipl_kset->kobj, &ipl_parameter_attr);
++
++out_ipl_parm:
++	sysfs_remove_group(&ipl_kset->kobj, &ipl_fcp_attr_group);
++out:
++	return rc;
++}
++
++static void ipl_run(struct shutdown_trigger *trigger)
++{
++	diag308(DIAG308_IPL, NULL);
++	if (MACHINE_IS_VM)
++		__cpcmd("IPL", NULL, 0, NULL);
++	else if (ipl_info.type == IPL_TYPE_CCW)
++		reipl_ccw_dev(&ipl_info.data.ccw.dev_id);
++}
++
++static int ipl_init(void)
++{
++	int rc;
++
++	ipl_kset = kset_create_and_add("ipl", NULL, firmware_kobj);
++	if (!ipl_kset) {
++		rc = -ENOMEM;
++		goto out;
++	}
++	switch (ipl_info.type) {
++	case IPL_TYPE_CCW:
++		rc = sysfs_create_group(&ipl_kset->kobj, &ipl_ccw_attr_group);
++		break;
++	case IPL_TYPE_FCP:
++	case IPL_TYPE_FCP_DUMP:
++		rc = ipl_register_fcp_files();
++		break;
++	case IPL_TYPE_NSS:
++		rc = sysfs_create_group(&ipl_kset->kobj, &ipl_nss_attr_group);
++		break;
++	default:
++		rc = sysfs_create_group(&ipl_kset->kobj,
++					&ipl_unknown_attr_group);
++		break;
++	}
++out:
++	if (rc)
++		panic("ipl_init failed: rc = %i\n", rc);
++
++	return 0;
++}
++
++static struct shutdown_action ipl_action = {SHUTDOWN_ACTION_IPL_STR, ipl_run,
++					    ipl_init};
+ 
+ /*
+- * reipl section
++ * reipl shutdown action: Reboot Linux on shutdown.
+  */
+ 
+ /* FCP reipl device attributes */
+@@ -465,7 +519,8 @@ static void reipl_get_ascii_loadparm(char *loadparm)
+ 	strstrip(loadparm);
+ }
+ 
+-static ssize_t reipl_ccw_loadparm_show(struct kset *kset, char *page)
++static ssize_t reipl_ccw_loadparm_show(struct kobject *kobj,
++				       struct kobj_attribute *attr, char *page)
+ {
+ 	char buf[LOADPARM_LEN + 1];
+ 
+@@ -473,7 +528,8 @@ static ssize_t reipl_ccw_loadparm_show(struct kset *kset, char *page)
+ 	return sprintf(page, "%s\n", buf);
+ }
+ 
+-static ssize_t reipl_ccw_loadparm_store(struct kset *kset,
++static ssize_t reipl_ccw_loadparm_store(struct kobject *kobj,
++					struct kobj_attribute *attr,
+ 					const char *buf, size_t len)
+ {
+ 	int i, lp_len;
+@@ -500,7 +556,7 @@ static ssize_t reipl_ccw_loadparm_store(struct kset *kset,
+ 	return len;
+ }
+ 
+-static struct subsys_attribute sys_reipl_ccw_loadparm_attr =
++static struct kobj_attribute sys_reipl_ccw_loadparm_attr =
+ 	__ATTR(loadparm, 0644, reipl_ccw_loadparm_show,
+ 	       reipl_ccw_loadparm_store);
+ 
+@@ -539,7 +595,9 @@ static int reipl_set_type(enum ipl_type type)
+ 
+ 	switch(type) {
+ 	case IPL_TYPE_CCW:
+-		if (MACHINE_IS_VM)
++		if (diag308_set_works)
++			reipl_method = REIPL_METHOD_CCW_DIAG;
++		else if (MACHINE_IS_VM)
+ 			reipl_method = REIPL_METHOD_CCW_VM;
+ 		else
+ 			reipl_method = REIPL_METHOD_CCW_CIO;
+@@ -568,13 +626,15 @@ static int reipl_set_type(enum ipl_type type)
+ 	return 0;
+ }
+ 
+-static ssize_t reipl_type_show(struct kset *kset, char *page)
++static ssize_t reipl_type_show(struct kobject *kobj,
++			       struct kobj_attribute *attr, char *page)
+ {
+ 	return sprintf(page, "%s\n", ipl_type_str(reipl_type));
+ }
+ 
+-static ssize_t reipl_type_store(struct kset *kset, const char *buf,
+-				size_t len)
++static ssize_t reipl_type_store(struct kobject *kobj,
++				struct kobj_attribute *attr,
++				const char *buf, size_t len)
+ {
+ 	int rc = -EINVAL;
+ 
+@@ -587,140 +647,12 @@ static ssize_t reipl_type_store(struct kset *kset, const char *buf,
+ 	return (rc != 0) ? rc : len;
+ }
+ 
+-static struct subsys_attribute reipl_type_attr =
+-		__ATTR(reipl_type, 0644, reipl_type_show, reipl_type_store);
+-
+-static decl_subsys(reipl, NULL, NULL);
+-
+-/*
+- * dump section
+- */
+-
+-/* FCP dump device attributes */
+-
+-DEFINE_IPL_ATTR_RW(dump_fcp, wwpn, "0x%016llx\n", "%016llx\n",
+-		   dump_block_fcp->ipl_info.fcp.wwpn);
+-DEFINE_IPL_ATTR_RW(dump_fcp, lun, "0x%016llx\n", "%016llx\n",
+-		   dump_block_fcp->ipl_info.fcp.lun);
+-DEFINE_IPL_ATTR_RW(dump_fcp, bootprog, "%lld\n", "%lld\n",
+-		   dump_block_fcp->ipl_info.fcp.bootprog);
+-DEFINE_IPL_ATTR_RW(dump_fcp, br_lba, "%lld\n", "%lld\n",
+-		   dump_block_fcp->ipl_info.fcp.br_lba);
+-DEFINE_IPL_ATTR_RW(dump_fcp, device, "0.0.%04llx\n", "0.0.%llx\n",
+-		   dump_block_fcp->ipl_info.fcp.devno);
+-
+-static struct attribute *dump_fcp_attrs[] = {
+-	&sys_dump_fcp_device_attr.attr,
+-	&sys_dump_fcp_wwpn_attr.attr,
+-	&sys_dump_fcp_lun_attr.attr,
+-	&sys_dump_fcp_bootprog_attr.attr,
+-	&sys_dump_fcp_br_lba_attr.attr,
+-	NULL,
+-};
+-
+-static struct attribute_group dump_fcp_attr_group = {
+-	.name  = IPL_FCP_STR,
+-	.attrs = dump_fcp_attrs,
+-};
+-
+-/* CCW dump device attributes */
+-
+-DEFINE_IPL_ATTR_RW(dump_ccw, device, "0.0.%04llx\n", "0.0.%llx\n",
+-		   dump_block_ccw->ipl_info.ccw.devno);
+-
+-static struct attribute *dump_ccw_attrs[] = {
+-	&sys_dump_ccw_device_attr.attr,
+-	NULL,
+-};
+-
+-static struct attribute_group dump_ccw_attr_group = {
+-	.name  = IPL_CCW_STR,
+-	.attrs = dump_ccw_attrs,
+-};
+-
+-/* dump type */
+-
+-static int dump_set_type(enum dump_type type)
+-{
+-	if (!(dump_capabilities & type))
+-		return -EINVAL;
+-	switch(type) {
+-	case DUMP_TYPE_CCW:
+-		if (MACHINE_IS_VM)
+-			dump_method = DUMP_METHOD_CCW_VM;
+-		else if (diag308_set_works)
+-			dump_method = DUMP_METHOD_CCW_DIAG;
+-		else
+-			dump_method = DUMP_METHOD_CCW_CIO;
+-		break;
+-	case DUMP_TYPE_FCP:
+-		dump_method = DUMP_METHOD_FCP_DIAG;
+-		break;
+-	default:
+-		dump_method = DUMP_METHOD_NONE;
+-	}
+-	dump_type = type;
+-	return 0;
+-}
+-
+-static ssize_t dump_type_show(struct kset *kset, char *page)
+-{
+-	return sprintf(page, "%s\n", dump_type_str(dump_type));
+-}
+-
+-static ssize_t dump_type_store(struct kset *kset, const char *buf,
+-			       size_t len)
+-{
+-	int rc = -EINVAL;
+-
+-	if (strncmp(buf, DUMP_NONE_STR, strlen(DUMP_NONE_STR)) == 0)
+-		rc = dump_set_type(DUMP_TYPE_NONE);
+-	else if (strncmp(buf, DUMP_CCW_STR, strlen(DUMP_CCW_STR)) == 0)
+-		rc = dump_set_type(DUMP_TYPE_CCW);
+-	else if (strncmp(buf, DUMP_FCP_STR, strlen(DUMP_FCP_STR)) == 0)
+-		rc = dump_set_type(DUMP_TYPE_FCP);
+-	return (rc != 0) ? rc : len;
+-}
+-
+-static struct subsys_attribute dump_type_attr =
+-		__ATTR(dump_type, 0644, dump_type_show, dump_type_store);
+-
+-static decl_subsys(dump, NULL, NULL);
+-
+-/*
+- * Shutdown actions section
+- */
+-
+-static decl_subsys(shutdown_actions, NULL, NULL);
+-
+-/* on panic */
+-
+-static ssize_t on_panic_show(struct kset *kset, char *page)
+-{
+-	return sprintf(page, "%s\n", shutdown_action_str(on_panic_action));
+-}
+-
+-static ssize_t on_panic_store(struct kset *kset, const char *buf,
+-			      size_t len)
+-{
+-	if (strncmp(buf, SHUTDOWN_REIPL_STR, strlen(SHUTDOWN_REIPL_STR)) == 0)
+-		on_panic_action = SHUTDOWN_REIPL;
+-	else if (strncmp(buf, SHUTDOWN_DUMP_STR,
+-			 strlen(SHUTDOWN_DUMP_STR)) == 0)
+-		on_panic_action = SHUTDOWN_DUMP;
+-	else if (strncmp(buf, SHUTDOWN_STOP_STR,
+-			 strlen(SHUTDOWN_STOP_STR)) == 0)
+-		on_panic_action = SHUTDOWN_STOP;
+-	else
+-		return -EINVAL;
+-
+-	return len;
+-}
++static struct kobj_attribute reipl_type_attr =
++	__ATTR(reipl_type, 0644, reipl_type_show, reipl_type_store);
+ 
+-static struct subsys_attribute on_panic_attr =
+-		__ATTR(on_panic, 0644, on_panic_show, on_panic_store);
++static struct kset *reipl_kset;
+ 
+-void do_reipl(void)
++void reipl_run(struct shutdown_trigger *trigger)
+ {
+ 	struct ccw_dev_id devid;
+ 	static char buf[100];
+@@ -729,8 +661,6 @@ void do_reipl(void)
+ 	switch (reipl_method) {
+ 	case REIPL_METHOD_CCW_CIO:
+ 		devid.devno = reipl_block_ccw->ipl_info.ccw.devno;
+-		if (ipl_info.type == IPL_TYPE_CCW && devid.devno == ipl_devno)
+-			diag308(DIAG308_IPL, NULL);
+ 		devid.ssid  = 0;
+ 		reipl_ccw_dev(&devid);
+ 		break;
+@@ -771,98 +701,6 @@ void do_reipl(void)
+ 	default:
+ 		break;
+ 	}
+-	signal_processor(smp_processor_id(), sigp_stop_and_store_status);
+-}
+-
+-static void do_dump(void)
+-{
+-	struct ccw_dev_id devid;
+-	static char buf[100];
+-
+-	switch (dump_method) {
+-	case DUMP_METHOD_CCW_CIO:
+-		smp_send_stop();
+-		devid.devno = dump_block_ccw->ipl_info.ccw.devno;
+-		devid.ssid  = 0;
+-		reipl_ccw_dev(&devid);
+-		break;
+-	case DUMP_METHOD_CCW_VM:
+-		smp_send_stop();
+-		sprintf(buf, "STORE STATUS");
+-		__cpcmd(buf, NULL, 0, NULL);
+-		sprintf(buf, "IPL %X", dump_block_ccw->ipl_info.ccw.devno);
+-		__cpcmd(buf, NULL, 0, NULL);
+-		break;
+-	case DUMP_METHOD_CCW_DIAG:
+-		diag308(DIAG308_SET, dump_block_ccw);
+-		diag308(DIAG308_DUMP, NULL);
+-		break;
+-	case DUMP_METHOD_FCP_DIAG:
+-		diag308(DIAG308_SET, dump_block_fcp);
+-		diag308(DIAG308_DUMP, NULL);
+-		break;
+-	case DUMP_METHOD_NONE:
+-	default:
+-		return;
+-	}
+-	printk(KERN_EMERG "Dump failed!\n");
+-}
+-
+-/* init functions */
+-
+-static int __init ipl_register_fcp_files(void)
+-{
+-	int rc;
+-
+-	rc = sysfs_create_group(&ipl_subsys.kobj,
+-				&ipl_fcp_attr_group);
+-	if (rc)
+-		goto out;
+-	rc = sysfs_create_bin_file(&ipl_subsys.kobj,
+-				   &ipl_parameter_attr);
+-	if (rc)
+-		goto out_ipl_parm;
+-	rc = sysfs_create_bin_file(&ipl_subsys.kobj,
+-				   &ipl_scp_data_attr);
+-	if (!rc)
+-		goto out;
+-
+-	sysfs_remove_bin_file(&ipl_subsys.kobj, &ipl_parameter_attr);
+-
+-out_ipl_parm:
+-	sysfs_remove_group(&ipl_subsys.kobj, &ipl_fcp_attr_group);
+-out:
+-	return rc;
+-}
+-
+-static int __init ipl_init(void)
+-{
+-	int rc;
+-
+-	rc = firmware_register(&ipl_subsys);
+-	if (rc)
+-		return rc;
+-	switch (ipl_info.type) {
+-	case IPL_TYPE_CCW:
+-		rc = sysfs_create_group(&ipl_subsys.kobj,
+-					&ipl_ccw_attr_group);
+-		break;
+-	case IPL_TYPE_FCP:
+-	case IPL_TYPE_FCP_DUMP:
+-		rc = ipl_register_fcp_files();
+-		break;
+-	case IPL_TYPE_NSS:
+-		rc = sysfs_create_group(&ipl_subsys.kobj,
+-					&ipl_nss_attr_group);
+-		break;
+-	default:
+-		rc = sysfs_create_group(&ipl_subsys.kobj,
+-					&ipl_unknown_attr_group);
+-		break;
+-	}
+-	if (rc)
+-		firmware_unregister(&ipl_subsys);
+-	return rc;
+ }
+ 
+ static void __init reipl_probe(void)
+@@ -883,7 +721,7 @@ static int __init reipl_nss_init(void)
+ 
+ 	if (!MACHINE_IS_VM)
+ 		return 0;
+-	rc = sysfs_create_group(&reipl_subsys.kobj, &reipl_nss_attr_group);
++	rc = sysfs_create_group(&reipl_kset->kobj, &reipl_nss_attr_group);
+ 	if (rc)
+ 		return rc;
+ 	strncpy(reipl_nss_name, kernel_nss_name, NSS_NAME_SIZE + 1);
+@@ -898,7 +736,7 @@ static int __init reipl_ccw_init(void)
+ 	reipl_block_ccw = (void *) get_zeroed_page(GFP_KERNEL);
+ 	if (!reipl_block_ccw)
+ 		return -ENOMEM;
+-	rc = sysfs_create_group(&reipl_subsys.kobj, &reipl_ccw_attr_group);
++	rc = sysfs_create_group(&reipl_kset->kobj, &reipl_ccw_attr_group);
+ 	if (rc) {
+ 		free_page((unsigned long)reipl_block_ccw);
+ 		return rc;
+@@ -907,6 +745,7 @@ static int __init reipl_ccw_init(void)
+ 	reipl_block_ccw->hdr.version = IPL_PARM_BLOCK_VERSION;
+ 	reipl_block_ccw->hdr.blk0_len = IPL_PARM_BLK0_CCW_LEN;
+ 	reipl_block_ccw->hdr.pbt = DIAG308_IPL_TYPE_CCW;
++	reipl_block_ccw->hdr.flags = DIAG308_FLAGS_LP_VALID;
+ 	/* check if read scp info worked and set loadparm */
+ 	if (sclp_ipl_info.is_valid)
+ 		memcpy(reipl_block_ccw->ipl_info.ccw.load_param,
+@@ -915,8 +754,7 @@ static int __init reipl_ccw_init(void)
+ 		/* read scp info failed: set empty loadparm (EBCDIC blanks) */
+ 		memset(reipl_block_ccw->ipl_info.ccw.load_param, 0x40,
+ 		       LOADPARM_LEN);
+-	/* FIXME: check for diag308_set_works when enabling diag ccw reipl */
+-	if (!MACHINE_IS_VM)
++	if (!MACHINE_IS_VM && !diag308_set_works)
+ 		sys_reipl_ccw_loadparm_attr.attr.mode = S_IRUGO;
+ 	if (ipl_info.type == IPL_TYPE_CCW)
+ 		reipl_block_ccw->ipl_info.ccw.devno = ipl_devno;
+@@ -936,7 +774,7 @@ static int __init reipl_fcp_init(void)
+ 	reipl_block_fcp = (void *) get_zeroed_page(GFP_KERNEL);
+ 	if (!reipl_block_fcp)
+ 		return -ENOMEM;
+-	rc = sysfs_create_group(&reipl_subsys.kobj, &reipl_fcp_attr_group);
++	rc = sysfs_create_group(&reipl_kset->kobj, &reipl_fcp_attr_group);
+ 	if (rc) {
+ 		free_page((unsigned long)reipl_block_fcp);
+ 		return rc;
+@@ -954,16 +792,16 @@ static int __init reipl_fcp_init(void)
+ 	return 0;
+ }
+ 
+-static int __init reipl_init(void)
++static int reipl_init(void)
+ {
+ 	int rc;
+ 
+-	rc = firmware_register(&reipl_subsys);
+-	if (rc)
+-		return rc;
+-	rc = subsys_create_file(&reipl_subsys, &reipl_type_attr);
++	reipl_kset = kset_create_and_add("reipl", NULL, firmware_kobj);
++	if (!reipl_kset)
++		return -ENOMEM;
++	rc = sysfs_create_file(&reipl_kset->kobj, &reipl_type_attr.attr);
+ 	if (rc) {
+-		firmware_unregister(&reipl_subsys);
++		kset_unregister(reipl_kset);
+ 		return rc;
+ 	}
+ 	rc = reipl_ccw_init();
+@@ -981,6 +819,140 @@ static int __init reipl_init(void)
+ 	return 0;
+ }
+ 
++static struct shutdown_action reipl_action = {SHUTDOWN_ACTION_REIPL_STR,
++					      reipl_run, reipl_init};
++
++/*
++ * dump shutdown action: Dump Linux on shutdown.
++ */
++
++/* FCP dump device attributes */
++
++DEFINE_IPL_ATTR_RW(dump_fcp, wwpn, "0x%016llx\n", "%016llx\n",
++		   dump_block_fcp->ipl_info.fcp.wwpn);
++DEFINE_IPL_ATTR_RW(dump_fcp, lun, "0x%016llx\n", "%016llx\n",
++		   dump_block_fcp->ipl_info.fcp.lun);
++DEFINE_IPL_ATTR_RW(dump_fcp, bootprog, "%lld\n", "%lld\n",
++		   dump_block_fcp->ipl_info.fcp.bootprog);
++DEFINE_IPL_ATTR_RW(dump_fcp, br_lba, "%lld\n", "%lld\n",
++		   dump_block_fcp->ipl_info.fcp.br_lba);
++DEFINE_IPL_ATTR_RW(dump_fcp, device, "0.0.%04llx\n", "0.0.%llx\n",
++		   dump_block_fcp->ipl_info.fcp.devno);
++
++static struct attribute *dump_fcp_attrs[] = {
++	&sys_dump_fcp_device_attr.attr,
++	&sys_dump_fcp_wwpn_attr.attr,
++	&sys_dump_fcp_lun_attr.attr,
++	&sys_dump_fcp_bootprog_attr.attr,
++	&sys_dump_fcp_br_lba_attr.attr,
++	NULL,
++};
++
++static struct attribute_group dump_fcp_attr_group = {
++	.name  = IPL_FCP_STR,
++	.attrs = dump_fcp_attrs,
++};
++
++/* CCW dump device attributes */
++
++DEFINE_IPL_ATTR_RW(dump_ccw, device, "0.0.%04llx\n", "0.0.%llx\n",
++		   dump_block_ccw->ipl_info.ccw.devno);
++
++static struct attribute *dump_ccw_attrs[] = {
++	&sys_dump_ccw_device_attr.attr,
++	NULL,
++};
++
++static struct attribute_group dump_ccw_attr_group = {
++	.name  = IPL_CCW_STR,
++	.attrs = dump_ccw_attrs,
++};
++
++/* dump type */
++
++static int dump_set_type(enum dump_type type)
++{
++	if (!(dump_capabilities & type))
++		return -EINVAL;
++	switch (type) {
++	case DUMP_TYPE_CCW:
++		if (diag308_set_works)
++			dump_method = DUMP_METHOD_CCW_DIAG;
++		else if (MACHINE_IS_VM)
++			dump_method = DUMP_METHOD_CCW_VM;
++		else
++			dump_method = DUMP_METHOD_CCW_CIO;
++		break;
++	case DUMP_TYPE_FCP:
++		dump_method = DUMP_METHOD_FCP_DIAG;
++		break;
++	default:
++		dump_method = DUMP_METHOD_NONE;
++	}
++	dump_type = type;
++	return 0;
++}
++
++static ssize_t dump_type_show(struct kobject *kobj,
++			      struct kobj_attribute *attr, char *page)
++{
++	return sprintf(page, "%s\n", dump_type_str(dump_type));
++}
++
++static ssize_t dump_type_store(struct kobject *kobj,
++			       struct kobj_attribute *attr,
++			       const char *buf, size_t len)
++{
++	int rc = -EINVAL;
++
++	if (strncmp(buf, DUMP_NONE_STR, strlen(DUMP_NONE_STR)) == 0)
++		rc = dump_set_type(DUMP_TYPE_NONE);
++	else if (strncmp(buf, DUMP_CCW_STR, strlen(DUMP_CCW_STR)) == 0)
++		rc = dump_set_type(DUMP_TYPE_CCW);
++	else if (strncmp(buf, DUMP_FCP_STR, strlen(DUMP_FCP_STR)) == 0)
++		rc = dump_set_type(DUMP_TYPE_FCP);
++	return (rc != 0) ? rc : len;
++}
++
++static struct kobj_attribute dump_type_attr =
++	__ATTR(dump_type, 0644, dump_type_show, dump_type_store);
++
++static struct kset *dump_kset;
++
++static void dump_run(struct shutdown_trigger *trigger)
++{
++	struct ccw_dev_id devid;
++	static char buf[100];
++
++	switch (dump_method) {
++	case DUMP_METHOD_CCW_CIO:
++		smp_send_stop();
++		devid.devno = dump_block_ccw->ipl_info.ccw.devno;
++		devid.ssid  = 0;
++		reipl_ccw_dev(&devid);
++		break;
++	case DUMP_METHOD_CCW_VM:
++		smp_send_stop();
++		sprintf(buf, "STORE STATUS");
++		__cpcmd(buf, NULL, 0, NULL);
++		sprintf(buf, "IPL %X", dump_block_ccw->ipl_info.ccw.devno);
++		__cpcmd(buf, NULL, 0, NULL);
++		break;
++	case DUMP_METHOD_CCW_DIAG:
++		diag308(DIAG308_SET, dump_block_ccw);
++		diag308(DIAG308_DUMP, NULL);
++		break;
++	case DUMP_METHOD_FCP_DIAG:
++		diag308(DIAG308_SET, dump_block_fcp);
++		diag308(DIAG308_DUMP, NULL);
++		break;
++	case DUMP_METHOD_NONE:
++	default:
++		return;
++	}
++	printk(KERN_EMERG "Dump failed!\n");
++}
++
+ static int __init dump_ccw_init(void)
+ {
+ 	int rc;
+@@ -988,7 +960,7 @@ static int __init dump_ccw_init(void)
+ 	dump_block_ccw = (void *) get_zeroed_page(GFP_KERNEL);
+ 	if (!dump_block_ccw)
+ 		return -ENOMEM;
+-	rc = sysfs_create_group(&dump_subsys.kobj, &dump_ccw_attr_group);
++	rc = sysfs_create_group(&dump_kset->kobj, &dump_ccw_attr_group);
+ 	if (rc) {
+ 		free_page((unsigned long)dump_block_ccw);
+ 		return rc;
+@@ -1012,7 +984,7 @@ static int __init dump_fcp_init(void)
+ 	dump_block_fcp = (void *) get_zeroed_page(GFP_KERNEL);
+ 	if (!dump_block_fcp)
+ 		return -ENOMEM;
+-	rc = sysfs_create_group(&dump_subsys.kobj, &dump_fcp_attr_group);
++	rc = sysfs_create_group(&dump_kset->kobj, &dump_fcp_attr_group);
+ 	if (rc) {
+ 		free_page((unsigned long)dump_block_fcp);
+ 		return rc;
+@@ -1026,33 +998,16 @@ static int __init dump_fcp_init(void)
+ 	return 0;
+ }
+ 
+-#define SHUTDOWN_ON_PANIC_PRIO 0
+-
+-static int shutdown_on_panic_notify(struct notifier_block *self,
+-				    unsigned long event, void *data)
+-{
+-	if (on_panic_action == SHUTDOWN_DUMP)
+-		do_dump();
+-	else if (on_panic_action == SHUTDOWN_REIPL)
+-		do_reipl();
+-	return NOTIFY_OK;
+-}
+-
+-static struct notifier_block shutdown_on_panic_nb = {
+-	.notifier_call = shutdown_on_panic_notify,
+-	.priority = SHUTDOWN_ON_PANIC_PRIO
+-};
+-
+-static int __init dump_init(void)
++static int dump_init(void)
+ {
+ 	int rc;
+ 
+-	rc = firmware_register(&dump_subsys);
+-	if (rc)
+-		return rc;
+-	rc = subsys_create_file(&dump_subsys, &dump_type_attr);
++	dump_kset = kset_create_and_add("dump", NULL, firmware_kobj);
++	if (!dump_kset)
++		return -ENOMEM;
++	rc = sysfs_create_file(&dump_kset->kobj, &dump_type_attr.attr);
+ 	if (rc) {
+-		firmware_unregister(&dump_subsys);
++		kset_unregister(dump_kset);
+ 		return rc;
+ 	}
+ 	rc = dump_ccw_init();
+@@ -1065,46 +1020,381 @@ static int __init dump_init(void)
+ 	return 0;
+ }
+ 
+-static int __init shutdown_actions_init(void)
++static struct shutdown_action dump_action = {SHUTDOWN_ACTION_DUMP_STR,
++					     dump_run, dump_init};
++
++/*
++ * vmcmd shutdown action: Trigger vm command on shutdown.
++ */
++
++static char vmcmd_on_reboot[128];
++static char vmcmd_on_panic[128];
++static char vmcmd_on_halt[128];
++static char vmcmd_on_poff[128];
++
++DEFINE_IPL_ATTR_STR_RW(vmcmd, on_reboot, "%s\n", "%s\n", vmcmd_on_reboot);
++DEFINE_IPL_ATTR_STR_RW(vmcmd, on_panic, "%s\n", "%s\n", vmcmd_on_panic);
++DEFINE_IPL_ATTR_STR_RW(vmcmd, on_halt, "%s\n", "%s\n", vmcmd_on_halt);
++DEFINE_IPL_ATTR_STR_RW(vmcmd, on_poff, "%s\n", "%s\n", vmcmd_on_poff);
++
++static struct attribute *vmcmd_attrs[] = {
++	&sys_vmcmd_on_reboot_attr.attr,
++	&sys_vmcmd_on_panic_attr.attr,
++	&sys_vmcmd_on_halt_attr.attr,
++	&sys_vmcmd_on_poff_attr.attr,
++	NULL,
++};
++
++static struct attribute_group vmcmd_attr_group = {
++	.attrs = vmcmd_attrs,
++};
++
++static struct kset *vmcmd_kset;
++
++static void vmcmd_run(struct shutdown_trigger *trigger)
++{
++	char *cmd, *next_cmd;
++
++	if (strcmp(trigger->name, ON_REIPL_STR) == 0)
++		cmd = vmcmd_on_reboot;
++	else if (strcmp(trigger->name, ON_PANIC_STR) == 0)
++		cmd = vmcmd_on_panic;
++	else if (strcmp(trigger->name, ON_HALT_STR) == 0)
++		cmd = vmcmd_on_halt;
++	else if (strcmp(trigger->name, ON_POFF_STR) == 0)
++		cmd = vmcmd_on_poff;
++	else
++		return;
++
++	if (strlen(cmd) == 0)
++		return;
++	do {
++		next_cmd = strchr(cmd, '\n');
++		if (next_cmd) {
++			next_cmd[0] = 0;
++			next_cmd += 1;
++		}
++		__cpcmd(cmd, NULL, 0, NULL);
++		cmd = next_cmd;
++	} while (cmd != NULL);
++}
++
++static int vmcmd_init(void)
+ {
+-	int rc;
++	if (!MACHINE_IS_VM)
++		return -ENOTSUPP;
++	vmcmd_kset = kset_create_and_add("vmcmd", NULL, firmware_kobj);
++	if (!vmcmd_kset)
++		return -ENOMEM;
++	return sysfs_create_group(&vmcmd_kset->kobj, &vmcmd_attr_group);
++}
+ 
+-	rc = firmware_register(&shutdown_actions_subsys);
+-	if (rc)
+-		return rc;
+-	rc = subsys_create_file(&shutdown_actions_subsys, &on_panic_attr);
+-	if (rc) {
+-		firmware_unregister(&shutdown_actions_subsys);
+-		return rc;
++static struct shutdown_action vmcmd_action = {SHUTDOWN_ACTION_VMCMD_STR,
++					      vmcmd_run, vmcmd_init};
++
++/*
++ * stop shutdown action: Stop Linux on shutdown.
++ */
++
++static void stop_run(struct shutdown_trigger *trigger)
++{
++	if (strcmp(trigger->name, ON_PANIC_STR) == 0)
++		disabled_wait((unsigned long) __builtin_return_address(0));
++	else {
++		signal_processor(smp_processor_id(), sigp_stop);
++		for (;;);
+ 	}
+-	atomic_notifier_chain_register(&panic_notifier_list,
+-				       &shutdown_on_panic_nb);
+-	return 0;
+ }
+ 
+-static int __init s390_ipl_init(void)
++static struct shutdown_action stop_action = {SHUTDOWN_ACTION_STOP_STR,
++					     stop_run, NULL};
++
++/* action list */
++
++static struct shutdown_action *shutdown_actions_list[] = {
++	&ipl_action, &reipl_action, &dump_action, &vmcmd_action, &stop_action};
++#define SHUTDOWN_ACTIONS_COUNT (sizeof(shutdown_actions_list) / sizeof(void *))
++
++/*
++ * Trigger section
++ */
++
++static struct kset *shutdown_actions_kset;
++
++static int set_trigger(const char *buf, struct shutdown_trigger *trigger,
++		       size_t len)
+ {
+-	int rc;
++	int i;
++	for (i = 0; i < SHUTDOWN_ACTIONS_COUNT; i++) {
++		if (!shutdown_actions_list[i])
++			continue;
++		if (strncmp(buf, shutdown_actions_list[i]->name,
++			    strlen(shutdown_actions_list[i]->name)) == 0) {
++			trigger->action = shutdown_actions_list[i];
++			return len;
++		}
++	}
++	return -EINVAL;
++}
+ 
+-	sclp_get_ipl_info(&sclp_ipl_info);
++/* on reipl */
++
++static struct shutdown_trigger on_reboot_trigger = {ON_REIPL_STR,
++						    &reipl_action};
++
++static ssize_t on_reboot_show(struct kobject *kobj,
++			      struct kobj_attribute *attr, char *page)
++{
++	return sprintf(page, "%s\n", on_reboot_trigger.action->name);
++}
++
++static ssize_t on_reboot_store(struct kobject *kobj,
++			       struct kobj_attribute *attr,
++			       const char *buf, size_t len)
++{
++	return set_trigger(buf, &on_reboot_trigger, len);
++}
++
++static struct kobj_attribute on_reboot_attr =
++	__ATTR(on_reboot, 0644, on_reboot_show, on_reboot_store);
++
++static void do_machine_restart(char *__unused)
++{
++	smp_send_stop();
++	on_reboot_trigger.action->fn(&on_reboot_trigger);
++	reipl_run(NULL);
++}
++void (*_machine_restart)(char *command) = do_machine_restart;
++
++/* on panic */
++
++static struct shutdown_trigger on_panic_trigger = {ON_PANIC_STR, &stop_action};
++
++static ssize_t on_panic_show(struct kobject *kobj,
++			     struct kobj_attribute *attr, char *page)
++{
++	return sprintf(page, "%s\n", on_panic_trigger.action->name);
++}
++
++static ssize_t on_panic_store(struct kobject *kobj,
++			      struct kobj_attribute *attr,
++			      const char *buf, size_t len)
++{
++	return set_trigger(buf, &on_panic_trigger, len);
++}
++
++static struct kobj_attribute on_panic_attr =
++	__ATTR(on_panic, 0644, on_panic_show, on_panic_store);
++
++static void do_panic(void)
++{
++	on_panic_trigger.action->fn(&on_panic_trigger);
++	stop_run(&on_panic_trigger);
++}
++
++/* on halt */
++
++static struct shutdown_trigger on_halt_trigger = {ON_HALT_STR, &stop_action};
++
++static ssize_t on_halt_show(struct kobject *kobj,
++			    struct kobj_attribute *attr, char *page)
++{
++	return sprintf(page, "%s\n", on_halt_trigger.action->name);
++}
++
++static ssize_t on_halt_store(struct kobject *kobj,
++			     struct kobj_attribute *attr,
++			     const char *buf, size_t len)
++{
++	return set_trigger(buf, &on_halt_trigger, len);
++}
++
++static struct kobj_attribute on_halt_attr =
++	__ATTR(on_halt, 0644, on_halt_show, on_halt_store);
++
++
++static void do_machine_halt(void)
++{
++	smp_send_stop();
++	on_halt_trigger.action->fn(&on_halt_trigger);
++	stop_run(&on_halt_trigger);
++}
++void (*_machine_halt)(void) = do_machine_halt;
++
++/* on power off */
++
++static struct shutdown_trigger on_poff_trigger = {ON_POFF_STR, &stop_action};
++
++static ssize_t on_poff_show(struct kobject *kobj,
++			    struct kobj_attribute *attr, char *page)
++{
++	return sprintf(page, "%s\n", on_poff_trigger.action->name);
++}
++
++static ssize_t on_poff_store(struct kobject *kobj,
++			     struct kobj_attribute *attr,
++			     const char *buf, size_t len)
++{
++	return set_trigger(buf, &on_poff_trigger, len);
++}
++
++static struct kobj_attribute on_poff_attr =
++	__ATTR(on_poff, 0644, on_poff_show, on_poff_store);
++
++
++static void do_machine_power_off(void)
++{
++	smp_send_stop();
++	on_poff_trigger.action->fn(&on_poff_trigger);
++	stop_run(&on_poff_trigger);
++}
++void (*_machine_power_off)(void) = do_machine_power_off;
++
++static void __init shutdown_triggers_init(void)
++{
++	shutdown_actions_kset = kset_create_and_add("shutdown_actions", NULL,
++						    firmware_kobj);
++	if (!shutdown_actions_kset)
++		goto fail;
++	if (sysfs_create_file(&shutdown_actions_kset->kobj,
++			      &on_reboot_attr.attr))
++		goto fail;
++	if (sysfs_create_file(&shutdown_actions_kset->kobj,
++			      &on_panic_attr.attr))
++		goto fail;
++	if (sysfs_create_file(&shutdown_actions_kset->kobj,
++			      &on_halt_attr.attr))
++		goto fail;
++	if (sysfs_create_file(&shutdown_actions_kset->kobj,
++			      &on_poff_attr.attr))
++		goto fail;
++
++	return;
++fail:
++	panic("shutdown_triggers_init failed\n");
++}
++
++static void __init shutdown_actions_init(void)
++{
++	int i;
++
++	for (i = 0; i < SHUTDOWN_ACTIONS_COUNT; i++) {
++		if (!shutdown_actions_list[i]->init)
++			continue;
++		if (shutdown_actions_list[i]->init())
++			shutdown_actions_list[i] = NULL;
++	}
++}
++
++static int __init s390_ipl_init(void)
++{
+ 	reipl_probe();
+-	rc = ipl_init();
+-	if (rc)
+-		return rc;
+-	rc = reipl_init();
+-	if (rc)
+-		return rc;
+-	rc = dump_init();
+-	if (rc)
+-		return rc;
+-	rc = shutdown_actions_init();
+-	if (rc)
+-		return rc;
++	sclp_get_ipl_info(&sclp_ipl_info);
++	shutdown_actions_init();
++	shutdown_triggers_init();
+ 	return 0;
+ }
+ 
+ __initcall(s390_ipl_init);
+ 
++static void __init strncpy_skip_quote(char *dst, char *src, int n)
++{
++	int sx, dx;
++
++	dx = 0;
++	for (sx = 0; src[sx] != 0; sx++) {
++		if (src[sx] == '"')
++			continue;
++		dst[dx++] = src[sx];
++		if (dx >= n)
++			break;
++	}
++}
++
++static int __init vmcmd_on_reboot_setup(char *str)
++{
++	if (!MACHINE_IS_VM)
++		return 1;
++	strncpy_skip_quote(vmcmd_on_reboot, str, 127);
++	vmcmd_on_reboot[127] = 0;
++	on_reboot_trigger.action = &vmcmd_action;
++	return 1;
++}
++__setup("vmreboot=", vmcmd_on_reboot_setup);
++
++static int __init vmcmd_on_panic_setup(char *str)
++{
++	if (!MACHINE_IS_VM)
++		return 1;
++	strncpy_skip_quote(vmcmd_on_panic, str, 127);
++	vmcmd_on_panic[127] = 0;
++	on_panic_trigger.action = &vmcmd_action;
++	return 1;
++}
++__setup("vmpanic=", vmcmd_on_panic_setup);
++
++static int __init vmcmd_on_halt_setup(char *str)
++{
++	if (!MACHINE_IS_VM)
++		return 1;
++	strncpy_skip_quote(vmcmd_on_halt, str, 127);
++	vmcmd_on_halt[127] = 0;
++	on_halt_trigger.action = &vmcmd_action;
++	return 1;
++}
++__setup("vmhalt=", vmcmd_on_halt_setup);
++
++static int __init vmcmd_on_poff_setup(char *str)
++{
++	if (!MACHINE_IS_VM)
++		return 1;
++	strncpy_skip_quote(vmcmd_on_poff, str, 127);
++	vmcmd_on_poff[127] = 0;
++	on_poff_trigger.action = &vmcmd_action;
++	return 1;
++}
++__setup("vmpoff=", vmcmd_on_poff_setup);
++
++static int on_panic_notify(struct notifier_block *self,
++			   unsigned long event, void *data)
++{
++	do_panic();
++	return NOTIFY_OK;
++}
++
++static struct notifier_block on_panic_nb = {
++	.notifier_call = on_panic_notify,
++	.priority = 0,
++};
++
++void __init setup_ipl(void)
++{
++	ipl_info.type = get_ipl_type();
++	switch (ipl_info.type) {
++	case IPL_TYPE_CCW:
++		ipl_info.data.ccw.dev_id.devno = ipl_devno;
++		ipl_info.data.ccw.dev_id.ssid = 0;
++		break;
++	case IPL_TYPE_FCP:
++	case IPL_TYPE_FCP_DUMP:
++		ipl_info.data.fcp.dev_id.devno =
++			IPL_PARMBLOCK_START->ipl_info.fcp.devno;
++		ipl_info.data.fcp.dev_id.ssid = 0;
++		ipl_info.data.fcp.wwpn = IPL_PARMBLOCK_START->ipl_info.fcp.wwpn;
++		ipl_info.data.fcp.lun = IPL_PARMBLOCK_START->ipl_info.fcp.lun;
++		break;
++	case IPL_TYPE_NSS:
++		strncpy(ipl_info.data.nss.name, kernel_nss_name,
++			sizeof(ipl_info.data.nss.name));
++		break;
++	case IPL_TYPE_UNKNOWN:
++	default:
++		/* We have no info to copy */
++		break;
++	}
++	atomic_notifier_chain_register(&panic_notifier_list, &on_panic_nb);
++}
++
+ void __init ipl_save_parameters(void)
+ {
+ 	struct cio_iplinfo iplinfo;
+@@ -1185,3 +1475,4 @@ void s390_reset_system(void)
+ 
+ 	do_reset_calls();
+ }
++
+diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c
+index 29f7884..0e7aca0 100644
+--- a/arch/s390/kernel/process.c
++++ b/arch/s390/kernel/process.c
+@@ -36,7 +36,7 @@
+ #include <linux/init.h>
+ #include <linux/module.h>
+ #include <linux/notifier.h>
+-
++#include <linux/utsname.h>
+ #include <asm/uaccess.h>
+ #include <asm/pgtable.h>
+ #include <asm/system.h>
+@@ -182,13 +182,15 @@ void cpu_idle(void)
+ 
+ void show_regs(struct pt_regs *regs)
+ {
+-	struct task_struct *tsk = current;
+-
+-        printk("CPU:    %d    %s\n", task_thread_info(tsk)->cpu, print_tainted());
+-        printk("Process %s (pid: %d, task: %p, ksp: %p)\n",
+-	       current->comm, task_pid_nr(current), (void *) tsk,
+-	       (void *) tsk->thread.ksp);
+-
++	print_modules();
++	printk("CPU: %d %s %s %.*s\n",
++	       task_thread_info(current)->cpu, print_tainted(),
++	       init_utsname()->release,
++	       (int)strcspn(init_utsname()->version, " "),
++	       init_utsname()->version);
++	printk("Process %s (pid: %d, task: %p, ksp: %p)\n",
++	       current->comm, current->pid, current,
++	       (void *) current->thread.ksp);
+ 	show_registers(regs);
+ 	/* Show stack backtrace if pt_regs is from kernel mode */
+ 	if (!(regs->psw.mask & PSW_MASK_PSTATE))
+diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c
+index 1d81bf9..6e036ba 100644
+--- a/arch/s390/kernel/ptrace.c
++++ b/arch/s390/kernel/ptrace.c
+@@ -86,13 +86,13 @@ FixPerRegisters(struct task_struct *task)
+ 		per_info->control_regs.bits.storage_alt_space_ctl = 0;
+ }
+ 
+-static void set_single_step(struct task_struct *task)
++void user_enable_single_step(struct task_struct *task)
+ {
+ 	task->thread.per_info.single_step = 1;
+ 	FixPerRegisters(task);
+ }
+ 
+-static void clear_single_step(struct task_struct *task)
++void user_disable_single_step(struct task_struct *task)
+ {
+ 	task->thread.per_info.single_step = 0;
+ 	FixPerRegisters(task);
+@@ -107,7 +107,7 @@ void
+ ptrace_disable(struct task_struct *child)
+ {
+ 	/* make sure the single step bit is not set. */
+-	clear_single_step(child);
++	user_disable_single_step(child);
+ }
+ 
+ #ifndef CONFIG_64BIT
+@@ -651,7 +651,7 @@ do_ptrace(struct task_struct *child, long request, long addr, long data)
+ 			clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+ 		child->exit_code = data;
+ 		/* make sure the single step bit is not set. */
+-		clear_single_step(child);
++		user_disable_single_step(child);
+ 		wake_up_process(child);
+ 		return 0;
+ 
+@@ -665,7 +665,7 @@ do_ptrace(struct task_struct *child, long request, long addr, long data)
+ 			return 0;
+ 		child->exit_code = SIGKILL;
+ 		/* make sure the single step bit is not set. */
+-		clear_single_step(child);
++		user_disable_single_step(child);
+ 		wake_up_process(child);
+ 		return 0;
+ 
+@@ -675,10 +675,7 @@ do_ptrace(struct task_struct *child, long request, long addr, long data)
+ 			return -EIO;
+ 		clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+ 		child->exit_code = data;
+-		if (data)
+-			set_tsk_thread_flag(child, TIF_SINGLE_STEP);
+-		else
+-			set_single_step(child);
++		user_enable_single_step(child);
+ 		/* give it a chance to run. */
+ 		wake_up_process(child);
+ 		return 0;
+diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c
+index 577aa7d..766c783 100644
+--- a/arch/s390/kernel/setup.c
++++ b/arch/s390/kernel/setup.c
+@@ -126,75 +126,6 @@ void __cpuinit cpu_init(void)
+ }
+ 
+ /*
+- * VM halt and poweroff setup routines
+- */
+-char vmhalt_cmd[128] = "";
+-char vmpoff_cmd[128] = "";
+-static char vmpanic_cmd[128] = "";
+-
+-static void strncpy_skip_quote(char *dst, char *src, int n)
+-{
+-        int sx, dx;
+-
+-        dx = 0;
+-        for (sx = 0; src[sx] != 0; sx++) {
+-                if (src[sx] == '"') continue;
+-                dst[dx++] = src[sx];
+-                if (dx >= n) break;
+-        }
+-}
+-
+-static int __init vmhalt_setup(char *str)
+-{
+-        strncpy_skip_quote(vmhalt_cmd, str, 127);
+-        vmhalt_cmd[127] = 0;
+-        return 1;
+-}
+-
+-__setup("vmhalt=", vmhalt_setup);
+-
+-static int __init vmpoff_setup(char *str)
+-{
+-        strncpy_skip_quote(vmpoff_cmd, str, 127);
+-        vmpoff_cmd[127] = 0;
+-        return 1;
+-}
+-
+-__setup("vmpoff=", vmpoff_setup);
+-
+-static int vmpanic_notify(struct notifier_block *self, unsigned long event,
+-			  void *data)
+-{
+-	if (MACHINE_IS_VM && strlen(vmpanic_cmd) > 0)
+-		cpcmd(vmpanic_cmd, NULL, 0, NULL);
+-
+-	return NOTIFY_OK;
+-}
+-
+-#define PANIC_PRI_VMPANIC	0
+-
+-static struct notifier_block vmpanic_nb = {
+-	.notifier_call = vmpanic_notify,
+-	.priority = PANIC_PRI_VMPANIC
+-};
+-
+-static int __init vmpanic_setup(char *str)
+-{
+-	static int register_done __initdata = 0;
+-
+-	strncpy_skip_quote(vmpanic_cmd, str, 127);
+-	vmpanic_cmd[127] = 0;
+-	if (!register_done) {
+-		register_done = 1;
+-		atomic_notifier_chain_register(&panic_notifier_list,
+-					       &vmpanic_nb);
+-	}
+-	return 1;
+-}
+-
+-__setup("vmpanic=", vmpanic_setup);
+-
+-/*
+  * condev= and conmode= setup parameter.
+  */
+ 
+@@ -308,38 +239,6 @@ static void __init setup_zfcpdump(unsigned int console_devno)
+ static inline void setup_zfcpdump(unsigned int console_devno) {}
+ #endif /* CONFIG_ZFCPDUMP */
+ 
+-#ifdef CONFIG_SMP
+-void (*_machine_restart)(char *command) = machine_restart_smp;
+-void (*_machine_halt)(void) = machine_halt_smp;
+-void (*_machine_power_off)(void) = machine_power_off_smp;
+-#else
+-/*
+- * Reboot, halt and power_off routines for non SMP.
+- */
+-static void do_machine_restart_nonsmp(char * __unused)
+-{
+-	do_reipl();
+-}
+-
+-static void do_machine_halt_nonsmp(void)
+-{
+-        if (MACHINE_IS_VM && strlen(vmhalt_cmd) > 0)
+-		__cpcmd(vmhalt_cmd, NULL, 0, NULL);
+-        signal_processor(smp_processor_id(), sigp_stop_and_store_status);
+-}
+-
+-static void do_machine_power_off_nonsmp(void)
+-{
+-        if (MACHINE_IS_VM && strlen(vmpoff_cmd) > 0)
+-		__cpcmd(vmpoff_cmd, NULL, 0, NULL);
+-        signal_processor(smp_processor_id(), sigp_stop_and_store_status);
+-}
+-
+-void (*_machine_restart)(char *command) = do_machine_restart_nonsmp;
+-void (*_machine_halt)(void) = do_machine_halt_nonsmp;
+-void (*_machine_power_off)(void) = do_machine_power_off_nonsmp;
+-#endif
+-
+  /*
+  * Reboot, halt and power_off stubs. They just call _machine_restart,
+  * _machine_halt or _machine_power_off. 
+@@ -559,7 +458,9 @@ setup_resources(void)
+ 	data_resource.start = (unsigned long) &_etext;
+ 	data_resource.end = (unsigned long) &_edata - 1;
+ 
+-	for (i = 0; i < MEMORY_CHUNKS && memory_chunk[i].size > 0; i++) {
++	for (i = 0; i < MEMORY_CHUNKS; i++) {
++		if (!memory_chunk[i].size)
++			continue;
+ 		res = alloc_bootmem_low(sizeof(struct resource));
+ 		res->flags = IORESOURCE_BUSY | IORESOURCE_MEM;
+ 		switch (memory_chunk[i].type) {
+@@ -617,7 +518,7 @@ EXPORT_SYMBOL_GPL(real_memory_size);
+ static void __init setup_memory_end(void)
+ {
+ 	unsigned long memory_size;
+-	unsigned long max_mem, max_phys;
++	unsigned long max_mem;
+ 	int i;
+ 
+ #if defined(CONFIG_ZFCPDUMP) || defined(CONFIG_ZFCPDUMP_MODULE)
+@@ -625,10 +526,31 @@ static void __init setup_memory_end(void)
+ 		memory_end = ZFCPDUMP_HSA_SIZE;
+ #endif
+ 	memory_size = 0;
+-	max_phys = VMALLOC_END_INIT - VMALLOC_MIN_SIZE;
+ 	memory_end &= PAGE_MASK;
+ 
+-	max_mem = memory_end ? min(max_phys, memory_end) : max_phys;
++	max_mem = memory_end ? min(VMALLOC_START, memory_end) : VMALLOC_START;
++	memory_end = min(max_mem, memory_end);
++
++	/*
++	 * Make sure all chunks are MAX_ORDER aligned so we don't need the
++	 * extra checks that HOLES_IN_ZONE would require.
++	 */
++	for (i = 0; i < MEMORY_CHUNKS; i++) {
++		unsigned long start, end;
++		struct mem_chunk *chunk;
++		unsigned long align;
++
++		chunk = &memory_chunk[i];
++		align = 1UL << (MAX_ORDER + PAGE_SHIFT - 1);
++		start = (chunk->addr + align - 1) & ~(align - 1);
++		end = (chunk->addr + chunk->size) & ~(align - 1);
++		if (start >= end)
++			memset(chunk, 0, sizeof(*chunk));
++		else {
++			chunk->addr = start;
++			chunk->size = end - start;
++		}
++	}
+ 
+ 	for (i = 0; i < MEMORY_CHUNKS; i++) {
+ 		struct mem_chunk *chunk = &memory_chunk[i];
+@@ -890,7 +812,7 @@ setup_arch(char **cmdline_p)
+ 
+ 	parse_early_param();
+ 
+-	setup_ipl_info();
++	setup_ipl();
+ 	setup_memory_end();
+ 	setup_addressing_mode();
+ 	setup_memory();
+@@ -899,7 +821,6 @@ setup_arch(char **cmdline_p)
+ 
+         cpu_init();
+         __cpu_logical_map[0] = S390_lowcore.cpu_data.cpu_addr;
+-	smp_setup_cpu_possible_map();
+ 
+ 	/*
+ 	 * Setup capabilities (ELF_HWCAP & ELF_PLATFORM).
+@@ -920,7 +841,7 @@ setup_arch(char **cmdline_p)
+ 
+ void __cpuinit print_cpu_info(struct cpuinfo_S390 *cpuinfo)
+ {
+-   printk("cpu %d "
++   printk(KERN_INFO "cpu %d "
+ #ifdef CONFIG_SMP
+            "phys_idx=%d "
+ #endif
+@@ -996,7 +917,7 @@ static void *c_next(struct seq_file *m, void *v, loff_t *pos)
+ static void c_stop(struct seq_file *m, void *v)
+ {
+ }
+-struct seq_operations cpuinfo_op = {
++const struct seq_operations cpuinfo_op = {
+ 	.start	= c_start,
+ 	.next	= c_next,
+ 	.stop	= c_stop,
+diff --git a/arch/s390/kernel/signal.c b/arch/s390/kernel/signal.c
+index d264671..4449bf3 100644
+--- a/arch/s390/kernel/signal.c
++++ b/arch/s390/kernel/signal.c
+@@ -471,6 +471,7 @@ void do_signal(struct pt_regs *regs)
+ 
+ 	if (signr > 0) {
+ 		/* Whee!  Actually deliver the signal.  */
++		int ret;
+ #ifdef CONFIG_COMPAT
+ 		if (test_thread_flag(TIF_31BIT)) {
+ 			extern int handle_signal32(unsigned long sig,
+@@ -478,15 +479,12 @@ void do_signal(struct pt_regs *regs)
+ 						   siginfo_t *info,
+ 						   sigset_t *oldset,
+ 						   struct pt_regs *regs);
+-			if (handle_signal32(
+-				    signr, &ka, &info, oldset, regs) == 0) {
+-				if (test_thread_flag(TIF_RESTORE_SIGMASK))
+-					clear_thread_flag(TIF_RESTORE_SIGMASK);
+-			}
+-			return;
++			ret = handle_signal32(signr, &ka, &info, oldset, regs);
+ 	        }
++		else
+ #endif
+-		if (handle_signal(signr, &ka, &info, oldset, regs) == 0) {
++			ret = handle_signal(signr, &ka, &info, oldset, regs);
++		if (!ret) {
+ 			/*
+ 			 * A signal was successfully delivered; the saved
+ 			 * sigmask will have been stored in the signal frame,
+@@ -495,6 +493,14 @@ void do_signal(struct pt_regs *regs)
+ 			 */
+ 			if (test_thread_flag(TIF_RESTORE_SIGMASK))
+ 				clear_thread_flag(TIF_RESTORE_SIGMASK);
++
++			/*
++			 * If we would have taken a single-step trap
++			 * for a normal instruction, act like we took
++			 * one for the handler setup.
++			 */
++			if (current->thread.per_info.single_step)
++				set_thread_flag(TIF_SINGLE_STEP);
+ 		}
+ 		return;
+ 	}
+diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c
+index 264ea90..aa37fa1 100644
+--- a/arch/s390/kernel/smp.c
++++ b/arch/s390/kernel/smp.c
+@@ -42,6 +42,7 @@
+ #include <asm/tlbflush.h>
+ #include <asm/timer.h>
+ #include <asm/lowcore.h>
++#include <asm/sclp.h>
+ #include <asm/cpu.h>
+ 
+ /*
+@@ -53,11 +54,27 @@ EXPORT_SYMBOL(lowcore_ptr);
+ cpumask_t cpu_online_map = CPU_MASK_NONE;
+ EXPORT_SYMBOL(cpu_online_map);
+ 
+-cpumask_t cpu_possible_map = CPU_MASK_NONE;
++cpumask_t cpu_possible_map = CPU_MASK_ALL;
+ EXPORT_SYMBOL(cpu_possible_map);
+ 
+ static struct task_struct *current_set[NR_CPUS];
+ 
++static u8 smp_cpu_type;
++static int smp_use_sigp_detection;
++
++enum s390_cpu_state {
++	CPU_STATE_STANDBY,
++	CPU_STATE_CONFIGURED,
++};
++
++#ifdef CONFIG_HOTPLUG_CPU
++static DEFINE_MUTEX(smp_cpu_state_mutex);
++#endif
++static int smp_cpu_state[NR_CPUS];
++
++static DEFINE_PER_CPU(struct cpu, cpu_devices);
++DEFINE_PER_CPU(struct s390_idle_data, s390_idle);
++
+ static void smp_ext_bitcall(int, ec_bit_sig);
+ 
+ /*
+@@ -193,6 +210,33 @@ int smp_call_function_single(int cpu, void (*func) (void *info), void *info,
+ }
+ EXPORT_SYMBOL(smp_call_function_single);
+ 
++/**
++ * smp_call_function_mask(): Run a function on a set of other CPUs.
++ * @mask: The set of cpus to run on.  Must not include the current cpu.
++ * @func: The function to run. This must be fast and non-blocking.
++ * @info: An arbitrary pointer to pass to the function.
++ * @wait: If true, wait (atomically) until function has completed on other CPUs.
++ *
++ * Returns 0 on success, else a negative status code.
++ *
++ * If @wait is true, then returns once @func has returned; otherwise
++ * it returns just before the target cpu calls @func.
++ *
++ * You must not call this function with disabled interrupts or from a
++ * hardware interrupt handler or from a bottom half handler.
++ */
++int
++smp_call_function_mask(cpumask_t mask,
++			void (*func)(void *), void *info,
++			int wait)
++{
++	preempt_disable();
++	__smp_call_function_map(func, info, 0, wait, mask);
++	preempt_enable();
++	return 0;
++}
++EXPORT_SYMBOL(smp_call_function_mask);
++
+ void smp_send_stop(void)
+ {
+ 	int cpu, rc;
+@@ -217,33 +261,6 @@ void smp_send_stop(void)
+ }
+ 
+ /*
+- * Reboot, halt and power_off routines for SMP.
+- */
+-void machine_restart_smp(char *__unused)
+-{
+-	smp_send_stop();
+-	do_reipl();
+-}
+-
+-void machine_halt_smp(void)
+-{
+-	smp_send_stop();
+-	if (MACHINE_IS_VM && strlen(vmhalt_cmd) > 0)
+-		__cpcmd(vmhalt_cmd, NULL, 0, NULL);
+-	signal_processor(smp_processor_id(), sigp_stop_and_store_status);
+-	for (;;);
+-}
+-
+-void machine_power_off_smp(void)
+-{
+-	smp_send_stop();
+-	if (MACHINE_IS_VM && strlen(vmpoff_cmd) > 0)
+-		__cpcmd(vmpoff_cmd, NULL, 0, NULL);
+-	signal_processor(smp_processor_id(), sigp_stop_and_store_status);
+-	for (;;);
+-}
+-
+-/*
+  * This is the main routine where commands issued by other
+  * cpus are handled.
+  */
+@@ -355,6 +372,13 @@ void smp_ctl_clear_bit(int cr, int bit)
+ }
+ EXPORT_SYMBOL(smp_ctl_clear_bit);
+ 
++/*
++ * In early ipl state a temp. logically cpu number is needed, so the sigp
++ * functions can be used to sense other cpus. Since NR_CPUS is >= 2 on
++ * CONFIG_SMP and the ipl cpu is logical cpu 0, it must be 1.
++ */
++#define CPU_INIT_NO	1
++
+ #if defined(CONFIG_ZFCPDUMP) || defined(CONFIG_ZFCPDUMP_MODULE)
+ 
+ /*
+@@ -375,9 +399,10 @@ static void __init smp_get_save_area(unsigned int cpu, unsigned int phy_cpu)
+ 		       "kernel was compiled with NR_CPUS=%i\n", cpu, NR_CPUS);
+ 		return;
+ 	}
+-	zfcpdump_save_areas[cpu] = alloc_bootmem(sizeof(union save_area));
+-	__cpu_logical_map[1] = (__u16) phy_cpu;
+-	while (signal_processor(1, sigp_stop_and_store_status) == sigp_busy)
++	zfcpdump_save_areas[cpu] = kmalloc(sizeof(union save_area), GFP_KERNEL);
++	__cpu_logical_map[CPU_INIT_NO] = (__u16) phy_cpu;
++	while (signal_processor(CPU_INIT_NO, sigp_stop_and_store_status) ==
++	       sigp_busy)
+ 		cpu_relax();
+ 	memcpy(zfcpdump_save_areas[cpu],
+ 	       (void *)(unsigned long) store_prefix() + SAVE_AREA_BASE,
+@@ -397,32 +422,155 @@ static inline void smp_get_save_area(unsigned int cpu, unsigned int phy_cpu) { }
+ 
+ #endif /* CONFIG_ZFCPDUMP || CONFIG_ZFCPDUMP_MODULE */
+ 
+-/*
+- * Lets check how many CPUs we have.
+- */
+-static unsigned int __init smp_count_cpus(void)
++static int cpu_stopped(int cpu)
+ {
+-	unsigned int cpu, num_cpus;
+-	__u16 boot_cpu_addr;
++	__u32 status;
+ 
+-	/*
+-	 * cpu 0 is the boot cpu. See smp_prepare_boot_cpu.
+-	 */
++	/* Check for stopped state */
++	if (signal_processor_ps(&status, 0, cpu, sigp_sense) ==
++	    sigp_status_stored) {
++		if (status & 0x40)
++			return 1;
++	}
++	return 0;
++}
++
++static int cpu_known(int cpu_id)
++{
++	int cpu;
++
++	for_each_present_cpu(cpu) {
++		if (__cpu_logical_map[cpu] == cpu_id)
++			return 1;
++	}
++	return 0;
++}
++
++static int smp_rescan_cpus_sigp(cpumask_t avail)
++{
++	int cpu_id, logical_cpu;
++
++	logical_cpu = first_cpu(avail);
++	if (logical_cpu == NR_CPUS)
++		return 0;
++	for (cpu_id = 0; cpu_id <= 65535; cpu_id++) {
++		if (cpu_known(cpu_id))
++			continue;
++		__cpu_logical_map[logical_cpu] = cpu_id;
++		if (!cpu_stopped(logical_cpu))
++			continue;
++		cpu_set(logical_cpu, cpu_present_map);
++		smp_cpu_state[logical_cpu] = CPU_STATE_CONFIGURED;
++		logical_cpu = next_cpu(logical_cpu, avail);
++		if (logical_cpu == NR_CPUS)
++			break;
++	}
++	return 0;
++}
++
++static int smp_rescan_cpus_sclp(cpumask_t avail)
++{
++	struct sclp_cpu_info *info;
++	int cpu_id, logical_cpu, cpu;
++	int rc;
++
++	logical_cpu = first_cpu(avail);
++	if (logical_cpu == NR_CPUS)
++		return 0;
++	info = kmalloc(sizeof(*info), GFP_KERNEL);
++	if (!info)
++		return -ENOMEM;
++	rc = sclp_get_cpu_info(info);
++	if (rc)
++		goto out;
++	for (cpu = 0; cpu < info->combined; cpu++) {
++		if (info->has_cpu_type && info->cpu[cpu].type != smp_cpu_type)
++			continue;
++		cpu_id = info->cpu[cpu].address;
++		if (cpu_known(cpu_id))
++			continue;
++		__cpu_logical_map[logical_cpu] = cpu_id;
++		cpu_set(logical_cpu, cpu_present_map);
++		if (cpu >= info->configured)
++			smp_cpu_state[logical_cpu] = CPU_STATE_STANDBY;
++		else
++			smp_cpu_state[logical_cpu] = CPU_STATE_CONFIGURED;
++		logical_cpu = next_cpu(logical_cpu, avail);
++		if (logical_cpu == NR_CPUS)
++			break;
++	}
++out:
++	kfree(info);
++	return rc;
++}
++
++static int smp_rescan_cpus(void)
++{
++	cpumask_t avail;
++
++	cpus_xor(avail, cpu_possible_map, cpu_present_map);
++	if (smp_use_sigp_detection)
++		return smp_rescan_cpus_sigp(avail);
++	else
++		return smp_rescan_cpus_sclp(avail);
++}
++
++static void __init smp_detect_cpus(void)
++{
++	unsigned int cpu, c_cpus, s_cpus;
++	struct sclp_cpu_info *info;
++	u16 boot_cpu_addr, cpu_addr;
++
++	c_cpus = 1;
++	s_cpus = 0;
+ 	boot_cpu_addr = S390_lowcore.cpu_data.cpu_addr;
+-	current_thread_info()->cpu = 0;
+-	num_cpus = 1;
+-	for (cpu = 0; cpu <= 65535; cpu++) {
+-		if ((__u16) cpu == boot_cpu_addr)
++	info = kmalloc(sizeof(*info), GFP_KERNEL);
++	if (!info)
++		panic("smp_detect_cpus failed to allocate memory\n");
++	/* Use sigp detection algorithm if sclp doesn't work. */
++	if (sclp_get_cpu_info(info)) {
++		smp_use_sigp_detection = 1;
++		for (cpu = 0; cpu <= 65535; cpu++) {
++			if (cpu == boot_cpu_addr)
++				continue;
++			__cpu_logical_map[CPU_INIT_NO] = cpu;
++			if (!cpu_stopped(CPU_INIT_NO))
++				continue;
++			smp_get_save_area(c_cpus, cpu);
++			c_cpus++;
++		}
++		goto out;
++	}
++
++	if (info->has_cpu_type) {
++		for (cpu = 0; cpu < info->combined; cpu++) {
++			if (info->cpu[cpu].address == boot_cpu_addr) {
++				smp_cpu_type = info->cpu[cpu].type;
++				break;
++			}
++		}
++	}
++
++	for (cpu = 0; cpu < info->combined; cpu++) {
++		if (info->has_cpu_type && info->cpu[cpu].type != smp_cpu_type)
++			continue;
++		cpu_addr = info->cpu[cpu].address;
++		if (cpu_addr == boot_cpu_addr)
+ 			continue;
+-		__cpu_logical_map[1] = (__u16) cpu;
+-		if (signal_processor(1, sigp_sense) == sigp_not_operational)
++		__cpu_logical_map[CPU_INIT_NO] = cpu_addr;
++		if (!cpu_stopped(CPU_INIT_NO)) {
++			s_cpus++;
+ 			continue;
+-		smp_get_save_area(num_cpus, cpu);
+-		num_cpus++;
++		}
++		smp_get_save_area(c_cpus, cpu_addr);
++		c_cpus++;
+ 	}
+-	printk("Detected %d CPU's\n", (int) num_cpus);
+-	printk("Boot cpu address %2X\n", boot_cpu_addr);
+-	return num_cpus;
++out:
++	kfree(info);
++	printk(KERN_INFO "CPUs: %d configured, %d standby\n", c_cpus, s_cpus);
++	get_online_cpus();
++	smp_rescan_cpus();
++	put_online_cpus();
+ }
+ 
+ /*
+@@ -453,8 +601,6 @@ int __cpuinit start_secondary(void *cpuvoid)
+ 	return 0;
+ }
+ 
+-DEFINE_PER_CPU(struct s390_idle_data, s390_idle);
+-
+ static void __init smp_create_idle(unsigned int cpu)
+ {
+ 	struct task_struct *p;
+@@ -470,37 +616,82 @@ static void __init smp_create_idle(unsigned int cpu)
+ 	spin_lock_init(&(&per_cpu(s390_idle, cpu))->lock);
+ }
+ 
+-static int cpu_stopped(int cpu)
++static int __cpuinit smp_alloc_lowcore(int cpu)
+ {
+-	__u32 status;
++	unsigned long async_stack, panic_stack;
++	struct _lowcore *lowcore;
++	int lc_order;
++
++	lc_order = sizeof(long) == 8 ? 1 : 0;
++	lowcore = (void *) __get_free_pages(GFP_KERNEL | GFP_DMA, lc_order);
++	if (!lowcore)
++		return -ENOMEM;
++	async_stack = __get_free_pages(GFP_KERNEL, ASYNC_ORDER);
++	if (!async_stack)
++		goto out_async_stack;
++	panic_stack = __get_free_page(GFP_KERNEL);
++	if (!panic_stack)
++		goto out_panic_stack;
++
++	*lowcore = S390_lowcore;
++	lowcore->async_stack = async_stack + ASYNC_SIZE;
++	lowcore->panic_stack = panic_stack + PAGE_SIZE;
+ 
+-	/* Check for stopped state */
+-	if (signal_processor_ps(&status, 0, cpu, sigp_sense) ==
+-	    sigp_status_stored) {
+-		if (status & 0x40)
+-			return 1;
++#ifndef CONFIG_64BIT
++	if (MACHINE_HAS_IEEE) {
++		unsigned long save_area;
++
++		save_area = get_zeroed_page(GFP_KERNEL);
++		if (!save_area)
++			goto out_save_area;
++		lowcore->extended_save_area_addr = (u32) save_area;
+ 	}
++#endif
++	lowcore_ptr[cpu] = lowcore;
+ 	return 0;
++
++#ifndef CONFIG_64BIT
++out_save_area:
++	free_page(panic_stack);
++#endif
++out_panic_stack:
++	free_pages(async_stack, ASYNC_ORDER);
++out_async_stack:
++	free_pages((unsigned long) lowcore, lc_order);
++	return -ENOMEM;
+ }
+ 
+-/* Upping and downing of CPUs */
++#ifdef CONFIG_HOTPLUG_CPU
++static void smp_free_lowcore(int cpu)
++{
++	struct _lowcore *lowcore;
++	int lc_order;
++
++	lc_order = sizeof(long) == 8 ? 1 : 0;
++	lowcore = lowcore_ptr[cpu];
++#ifndef CONFIG_64BIT
++	if (MACHINE_HAS_IEEE)
++		free_page((unsigned long) lowcore->extended_save_area_addr);
++#endif
++	free_page(lowcore->panic_stack - PAGE_SIZE);
++	free_pages(lowcore->async_stack - ASYNC_SIZE, ASYNC_ORDER);
++	free_pages((unsigned long) lowcore, lc_order);
++	lowcore_ptr[cpu] = NULL;
++}
++#endif /* CONFIG_HOTPLUG_CPU */
+ 
+-int __cpu_up(unsigned int cpu)
++/* Upping and downing of CPUs */
++int __cpuinit __cpu_up(unsigned int cpu)
+ {
+ 	struct task_struct *idle;
+ 	struct _lowcore *cpu_lowcore;
+ 	struct stack_frame *sf;
+ 	sigp_ccode ccode;
+-	int curr_cpu;
+ 
+-	for (curr_cpu = 0; curr_cpu <= 65535; curr_cpu++) {
+-		__cpu_logical_map[cpu] = (__u16) curr_cpu;
+-		if (cpu_stopped(cpu))
+-			break;
+-	}
+-
+-	if (!cpu_stopped(cpu))
+-		return -ENODEV;
++	if (smp_cpu_state[cpu] != CPU_STATE_CONFIGURED)
++		return -EIO;
++	if (smp_alloc_lowcore(cpu))
++		return -ENOMEM;
+ 
+ 	ccode = signal_processor_p((__u32)(unsigned long)(lowcore_ptr[cpu]),
+ 				   cpu, sigp_set_prefix);
+@@ -515,6 +706,7 @@ int __cpu_up(unsigned int cpu)
+ 	cpu_lowcore = lowcore_ptr[cpu];
+ 	cpu_lowcore->kernel_stack = (unsigned long)
+ 		task_stack_page(idle) + THREAD_SIZE;
++	cpu_lowcore->thread_info = (unsigned long) task_thread_info(idle);
+ 	sf = (struct stack_frame *) (cpu_lowcore->kernel_stack
+ 				     - sizeof(struct pt_regs)
+ 				     - sizeof(struct stack_frame));
+@@ -528,6 +720,8 @@ int __cpu_up(unsigned int cpu)
+ 	cpu_lowcore->percpu_offset = __per_cpu_offset[cpu];
+ 	cpu_lowcore->current_task = (unsigned long) idle;
+ 	cpu_lowcore->cpu_data.cpu_nr = cpu;
++	cpu_lowcore->softirq_pending = 0;
++	cpu_lowcore->ext_call_fast = 0;
+ 	eieio();
+ 
+ 	while (signal_processor(cpu, sigp_restart) == sigp_busy)
+@@ -538,44 +732,20 @@ int __cpu_up(unsigned int cpu)
+ 	return 0;
+ }
+ 
+-static unsigned int __initdata additional_cpus;
+-static unsigned int __initdata possible_cpus;
+-
+-void __init smp_setup_cpu_possible_map(void)
++static int __init setup_possible_cpus(char *s)
+ {
+-	unsigned int phy_cpus, pos_cpus, cpu;
+-
+-	phy_cpus = smp_count_cpus();
+-	pos_cpus = min(phy_cpus + additional_cpus, (unsigned int) NR_CPUS);
+-
+-	if (possible_cpus)
+-		pos_cpus = min(possible_cpus, (unsigned int) NR_CPUS);
++	int pcpus, cpu;
+ 
+-	for (cpu = 0; cpu < pos_cpus; cpu++)
++	pcpus = simple_strtoul(s, NULL, 0);
++	cpu_possible_map = cpumask_of_cpu(0);
++	for (cpu = 1; cpu < pcpus && cpu < NR_CPUS; cpu++)
+ 		cpu_set(cpu, cpu_possible_map);
+-
+-	phy_cpus = min(phy_cpus, pos_cpus);
+-
+-	for (cpu = 0; cpu < phy_cpus; cpu++)
+-		cpu_set(cpu, cpu_present_map);
+-}
+-
+-#ifdef CONFIG_HOTPLUG_CPU
+-
+-static int __init setup_additional_cpus(char *s)
+-{
+-	additional_cpus = simple_strtoul(s, NULL, 0);
+-	return 0;
+-}
+-early_param("additional_cpus", setup_additional_cpus);
+-
+-static int __init setup_possible_cpus(char *s)
+-{
+-	possible_cpus = simple_strtoul(s, NULL, 0);
+ 	return 0;
+ }
+ early_param("possible_cpus", setup_possible_cpus);
+ 
++#ifdef CONFIG_HOTPLUG_CPU
++
+ int __cpu_disable(void)
+ {
+ 	struct ec_creg_mask_parms cr_parms;
+@@ -612,7 +782,8 @@ void __cpu_die(unsigned int cpu)
+ 	/* Wait until target cpu is down */
+ 	while (!smp_cpu_not_running(cpu))
+ 		cpu_relax();
+-	printk("Processor %d spun down\n", cpu);
++	smp_free_lowcore(cpu);
++	printk(KERN_INFO "Processor %d spun down\n", cpu);
+ }
+ 
+ void cpu_die(void)
+@@ -625,49 +796,19 @@ void cpu_die(void)
+ 
+ #endif /* CONFIG_HOTPLUG_CPU */
+ 
+-/*
+- *	Cycle through the processors and setup structures.
+- */
+-
+ void __init smp_prepare_cpus(unsigned int max_cpus)
+ {
+-	unsigned long stack;
+ 	unsigned int cpu;
+-	int i;
++
++	smp_detect_cpus();
+ 
+ 	/* request the 0x1201 emergency signal external interrupt */
+ 	if (register_external_interrupt(0x1201, do_ext_call_interrupt) != 0)
+ 		panic("Couldn't request external interrupt 0x1201");
+ 	memset(lowcore_ptr, 0, sizeof(lowcore_ptr));
+-	/*
+-	 *  Initialize prefix pages and stacks for all possible cpus
+-	 */
+ 	print_cpu_info(&S390_lowcore.cpu_data);
++	smp_alloc_lowcore(smp_processor_id());
+ 
+-	for_each_possible_cpu(i) {
+-		lowcore_ptr[i] = (struct _lowcore *)
+-			__get_free_pages(GFP_KERNEL | GFP_DMA,
+-					 sizeof(void*) == 8 ? 1 : 0);
+-		stack = __get_free_pages(GFP_KERNEL, ASYNC_ORDER);
+-		if (!lowcore_ptr[i] || !stack)
+-			panic("smp_boot_cpus failed to allocate memory\n");
+-
+-		*(lowcore_ptr[i]) = S390_lowcore;
+-		lowcore_ptr[i]->async_stack = stack + ASYNC_SIZE;
+-		stack = __get_free_pages(GFP_KERNEL, 0);
+-		if (!stack)
+-			panic("smp_boot_cpus failed to allocate memory\n");
+-		lowcore_ptr[i]->panic_stack = stack + PAGE_SIZE;
+-#ifndef CONFIG_64BIT
+-		if (MACHINE_HAS_IEEE) {
+-			lowcore_ptr[i]->extended_save_area_addr =
+-				(__u32) __get_free_pages(GFP_KERNEL, 0);
+-			if (!lowcore_ptr[i]->extended_save_area_addr)
+-				panic("smp_boot_cpus failed to "
+-				      "allocate memory\n");
+-		}
+-#endif
+-	}
+ #ifndef CONFIG_64BIT
+ 	if (MACHINE_HAS_IEEE)
+ 		ctl_set_bit(14, 29); /* enable extended save area */
+@@ -683,15 +824,17 @@ void __init smp_prepare_boot_cpu(void)
+ {
+ 	BUG_ON(smp_processor_id() != 0);
+ 
++	current_thread_info()->cpu = 0;
++	cpu_set(0, cpu_present_map);
+ 	cpu_set(0, cpu_online_map);
+ 	S390_lowcore.percpu_offset = __per_cpu_offset[0];
+ 	current_set[0] = current;
++	smp_cpu_state[0] = CPU_STATE_CONFIGURED;
+ 	spin_lock_init(&(&__get_cpu_var(s390_idle))->lock);
+ }
+ 
+ void __init smp_cpus_done(unsigned int max_cpus)
+ {
+-	cpu_present_map = cpu_possible_map;
+ }
+ 
+ /*
+@@ -705,7 +848,79 @@ int setup_profiling_timer(unsigned int multiplier)
+ 	return 0;
+ }
+ 
+-static DEFINE_PER_CPU(struct cpu, cpu_devices);
++#ifdef CONFIG_HOTPLUG_CPU
++static ssize_t cpu_configure_show(struct sys_device *dev, char *buf)
++{
++	ssize_t count;
++
++	mutex_lock(&smp_cpu_state_mutex);
++	count = sprintf(buf, "%d\n", smp_cpu_state[dev->id]);
++	mutex_unlock(&smp_cpu_state_mutex);
++	return count;
++}
++
++static ssize_t cpu_configure_store(struct sys_device *dev, const char *buf,
++				   size_t count)
++{
++	int cpu = dev->id;
++	int val, rc;
++	char delim;
++
++	if (sscanf(buf, "%d %c", &val, &delim) != 1)
++		return -EINVAL;
++	if (val != 0 && val != 1)
++		return -EINVAL;
++
++	mutex_lock(&smp_cpu_state_mutex);
++	get_online_cpus();
++	rc = -EBUSY;
++	if (cpu_online(cpu))
++		goto out;
++	rc = 0;
++	switch (val) {
++	case 0:
++		if (smp_cpu_state[cpu] == CPU_STATE_CONFIGURED) {
++			rc = sclp_cpu_deconfigure(__cpu_logical_map[cpu]);
++			if (!rc)
++				smp_cpu_state[cpu] = CPU_STATE_STANDBY;
++		}
++		break;
++	case 1:
++		if (smp_cpu_state[cpu] == CPU_STATE_STANDBY) {
++			rc = sclp_cpu_configure(__cpu_logical_map[cpu]);
++			if (!rc)
++				smp_cpu_state[cpu] = CPU_STATE_CONFIGURED;
++		}
++		break;
++	default:
++		break;
++	}
++out:
++	put_online_cpus();
++	mutex_unlock(&smp_cpu_state_mutex);
++	return rc ? rc : count;
++}
++static SYSDEV_ATTR(configure, 0644, cpu_configure_show, cpu_configure_store);
++#endif /* CONFIG_HOTPLUG_CPU */
++
++static ssize_t show_cpu_address(struct sys_device *dev, char *buf)
++{
++	return sprintf(buf, "%d\n", __cpu_logical_map[dev->id]);
++}
++static SYSDEV_ATTR(address, 0444, show_cpu_address, NULL);
++
++
++static struct attribute *cpu_common_attrs[] = {
++#ifdef CONFIG_HOTPLUG_CPU
++	&attr_configure.attr,
++#endif
++	&attr_address.attr,
++	NULL,
++};
++
++static struct attribute_group cpu_common_attr_group = {
++	.attrs = cpu_common_attrs,
++};
+ 
+ static ssize_t show_capability(struct sys_device *dev, char *buf)
+ {
+@@ -750,15 +965,15 @@ static ssize_t show_idle_time(struct sys_device *dev, char *buf)
+ }
+ static SYSDEV_ATTR(idle_time_us, 0444, show_idle_time, NULL);
+ 
+-static struct attribute *cpu_attrs[] = {
++static struct attribute *cpu_online_attrs[] = {
+ 	&attr_capability.attr,
+ 	&attr_idle_count.attr,
+ 	&attr_idle_time_us.attr,
+ 	NULL,
+ };
+ 
+-static struct attribute_group cpu_attr_group = {
+-	.attrs = cpu_attrs,
++static struct attribute_group cpu_online_attr_group = {
++	.attrs = cpu_online_attrs,
+ };
+ 
+ static int __cpuinit smp_cpu_notify(struct notifier_block *self,
+@@ -778,12 +993,12 @@ static int __cpuinit smp_cpu_notify(struct notifier_block *self,
+ 		idle->idle_time = 0;
+ 		idle->idle_count = 0;
+ 		spin_unlock_irq(&idle->lock);
+-		if (sysfs_create_group(&s->kobj, &cpu_attr_group))
++		if (sysfs_create_group(&s->kobj, &cpu_online_attr_group))
+ 			return NOTIFY_BAD;
+ 		break;
+ 	case CPU_DEAD:
+ 	case CPU_DEAD_FROZEN:
+-		sysfs_remove_group(&s->kobj, &cpu_attr_group);
++		sysfs_remove_group(&s->kobj, &cpu_online_attr_group);
+ 		break;
+ 	}
+ 	return NOTIFY_OK;
+@@ -793,6 +1008,62 @@ static struct notifier_block __cpuinitdata smp_cpu_nb = {
+ 	.notifier_call = smp_cpu_notify,
+ };
+ 
++static int smp_add_present_cpu(int cpu)
++{
++	struct cpu *c = &per_cpu(cpu_devices, cpu);
++	struct sys_device *s = &c->sysdev;
++	int rc;
++
++	c->hotpluggable = 1;
++	rc = register_cpu(c, cpu);
++	if (rc)
++		goto out;
++	rc = sysfs_create_group(&s->kobj, &cpu_common_attr_group);
++	if (rc)
++		goto out_cpu;
++	if (!cpu_online(cpu))
++		goto out;
++	rc = sysfs_create_group(&s->kobj, &cpu_online_attr_group);
++	if (!rc)
++		return 0;
++	sysfs_remove_group(&s->kobj, &cpu_common_attr_group);
++out_cpu:
++#ifdef CONFIG_HOTPLUG_CPU
++	unregister_cpu(c);
++#endif
++out:
++	return rc;
++}
++
++#ifdef CONFIG_HOTPLUG_CPU
++static ssize_t rescan_store(struct sys_device *dev, const char *buf,
++			    size_t count)
++{
++	cpumask_t newcpus;
++	int cpu;
++	int rc;
++
++	mutex_lock(&smp_cpu_state_mutex);
++	get_online_cpus();
++	newcpus = cpu_present_map;
++	rc = smp_rescan_cpus();
++	if (rc)
++		goto out;
++	cpus_andnot(newcpus, cpu_present_map, newcpus);
++	for_each_cpu_mask(cpu, newcpus) {
++		rc = smp_add_present_cpu(cpu);
++		if (rc)
++			cpu_clear(cpu, cpu_present_map);
++	}
++	rc = 0;
++out:
++	put_online_cpus();
++	mutex_unlock(&smp_cpu_state_mutex);
++	return rc ? rc : count;
++}
++static SYSDEV_ATTR(rescan, 0200, NULL, rescan_store);
++#endif /* CONFIG_HOTPLUG_CPU */
++
+ static int __init topology_init(void)
+ {
+ 	int cpu;
+@@ -800,16 +1071,14 @@ static int __init topology_init(void)
+ 
+ 	register_cpu_notifier(&smp_cpu_nb);
+ 
+-	for_each_possible_cpu(cpu) {
+-		struct cpu *c = &per_cpu(cpu_devices, cpu);
+-		struct sys_device *s = &c->sysdev;
+-
+-		c->hotpluggable = 1;
+-		register_cpu(c, cpu);
+-		if (!cpu_online(cpu))
+-			continue;
+-		s = &c->sysdev;
+-		rc = sysfs_create_group(&s->kobj, &cpu_attr_group);
++#ifdef CONFIG_HOTPLUG_CPU
++	rc = sysfs_create_file(&cpu_sysdev_class.kset.kobj,
++			       &attr_rescan.attr);
++	if (rc)
++		return rc;
++#endif
++	for_each_present_cpu(cpu) {
++		rc = smp_add_present_cpu(cpu);
+ 		if (rc)
+ 			return rc;
+ 	}
+diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c
+index 22b800c..3bbac12 100644
+--- a/arch/s390/kernel/time.c
++++ b/arch/s390/kernel/time.c
+@@ -1145,7 +1145,7 @@ static void etr_work_fn(struct work_struct *work)
+  * Sysfs interface functions
+  */
+ static struct sysdev_class etr_sysclass = {
+-	set_kset_name("etr")
++	.name	= "etr",
+ };
+ 
+ static struct sys_device etr_port0_dev = {
+diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c
+index 8ed16a8..52b8342 100644
+--- a/arch/s390/kernel/traps.c
++++ b/arch/s390/kernel/traps.c
+@@ -31,6 +31,7 @@
+ #include <linux/reboot.h>
+ #include <linux/kprobes.h>
+ #include <linux/bug.h>
++#include <linux/utsname.h>
+ #include <asm/system.h>
+ #include <asm/uaccess.h>
+ #include <asm/io.h>
+@@ -168,9 +169,16 @@ void show_stack(struct task_struct *task, unsigned long *sp)
+  */
+ void dump_stack(void)
+ {
++	printk("CPU: %d %s %s %.*s\n",
++	       task_thread_info(current)->cpu, print_tainted(),
++	       init_utsname()->release,
++	       (int)strcspn(init_utsname()->version, " "),
++	       init_utsname()->version);
++	printk("Process %s (pid: %d, task: %p, ksp: %p)\n",
++	       current->comm, current->pid, current,
++	       (void *) current->thread.ksp);
+ 	show_stack(NULL, NULL);
+ }
+-
+ EXPORT_SYMBOL(dump_stack);
+ 
+ static inline int mask_bits(struct pt_regs *regs, unsigned long bits)
+@@ -258,8 +266,14 @@ void die(const char * str, struct pt_regs * regs, long err)
+ 	console_verbose();
+ 	spin_lock_irq(&die_lock);
+ 	bust_spinlocks(1);
+-	printk("%s: %04lx [#%d]\n", str, err & 0xffff, ++die_counter);
+-	print_modules();
++	printk("%s: %04lx [#%d] ", str, err & 0xffff, ++die_counter);
++#ifdef CONFIG_PREEMPT
++	printk("PREEMPT ");
++#endif
++#ifdef CONFIG_SMP
++	printk("SMP");
++#endif
++	printk("\n");
+ 	notify_die(DIE_OOPS, str, regs, err, current->thread.trap_no, SIGSEGV);
+ 	show_regs(regs);
+ 	bust_spinlocks(0);
+diff --git a/arch/s390/kernel/vmlinux.lds.S b/arch/s390/kernel/vmlinux.lds.S
+index 849120e..9361591 100644
+--- a/arch/s390/kernel/vmlinux.lds.S
++++ b/arch/s390/kernel/vmlinux.lds.S
+@@ -17,6 +17,12 @@ ENTRY(_start)
+ jiffies = jiffies_64;
+ #endif
+ 
++PHDRS {
++	text PT_LOAD FLAGS(5);	/* R_E */
++	data PT_LOAD FLAGS(7);	/* RWE */
++	note PT_NOTE FLAGS(0);	/* ___ */
++}
++
+ SECTIONS
+ {
+ 	. = 0x00000000;
+@@ -33,6 +39,9 @@ SECTIONS
+ 
+ 	_etext = .;		/* End of text section */
+ 
++	NOTES :text :note
++	BUG_TABLE :text
++
+ 	RODATA
+ 
+ #ifdef CONFIG_SHARED_KERNEL
+@@ -49,9 +58,6 @@ SECTIONS
+ 		__stop___ex_table = .;
+ 	}
+ 
+-	NOTES
+-	BUG_TABLE
+-
+ 	.data : {		/* Data */
+ 		DATA_DATA
+ 		CONSTRUCTORS
+diff --git a/arch/s390/lib/spinlock.c b/arch/s390/lib/spinlock.c
+index 8d76403..e41f400 100644
+--- a/arch/s390/lib/spinlock.c
++++ b/arch/s390/lib/spinlock.c
+@@ -39,7 +39,7 @@ static inline void _raw_yield_cpu(int cpu)
+ 		_raw_yield();
+ }
+ 
+-void _raw_spin_lock_wait(raw_spinlock_t *lp, unsigned int pc)
++void _raw_spin_lock_wait(raw_spinlock_t *lp)
+ {
+ 	int count = spin_retry;
+ 	unsigned int cpu = ~smp_processor_id();
+@@ -53,15 +53,36 @@ void _raw_spin_lock_wait(raw_spinlock_t *lp, unsigned int pc)
+ 		}
+ 		if (__raw_spin_is_locked(lp))
+ 			continue;
+-		if (_raw_compare_and_swap(&lp->owner_cpu, 0, cpu) == 0) {
+-			lp->owner_pc = pc;
++		if (_raw_compare_and_swap(&lp->owner_cpu, 0, cpu) == 0)
+ 			return;
+-		}
+ 	}
+ }
+ EXPORT_SYMBOL(_raw_spin_lock_wait);
+ 
+-int _raw_spin_trylock_retry(raw_spinlock_t *lp, unsigned int pc)
++void _raw_spin_lock_wait_flags(raw_spinlock_t *lp, unsigned long flags)
++{
++	int count = spin_retry;
++	unsigned int cpu = ~smp_processor_id();
++
++	local_irq_restore(flags);
++	while (1) {
++		if (count-- <= 0) {
++			unsigned int owner = lp->owner_cpu;
++			if (owner != 0)
++				_raw_yield_cpu(~owner);
++			count = spin_retry;
++		}
++		if (__raw_spin_is_locked(lp))
++			continue;
++		local_irq_disable();
++		if (_raw_compare_and_swap(&lp->owner_cpu, 0, cpu) == 0)
++			return;
++		local_irq_restore(flags);
++	}
++}
++EXPORT_SYMBOL(_raw_spin_lock_wait_flags);
++
++int _raw_spin_trylock_retry(raw_spinlock_t *lp)
+ {
+ 	unsigned int cpu = ~smp_processor_id();
+ 	int count;
+@@ -69,10 +90,8 @@ int _raw_spin_trylock_retry(raw_spinlock_t *lp, unsigned int pc)
+ 	for (count = spin_retry; count > 0; count--) {
+ 		if (__raw_spin_is_locked(lp))
+ 			continue;
+-		if (_raw_compare_and_swap(&lp->owner_cpu, 0, cpu) == 0) {
+-			lp->owner_pc = pc;
++		if (_raw_compare_and_swap(&lp->owner_cpu, 0, cpu) == 0)
+ 			return 1;
+-		}
+ 	}
+ 	return 0;
+ }
+diff --git a/arch/s390/mm/extmem.c b/arch/s390/mm/extmem.c
+index 394980b..880b0eb 100644
+--- a/arch/s390/mm/extmem.c
++++ b/arch/s390/mm/extmem.c
+@@ -83,7 +83,7 @@ struct dcss_segment {
+ };
+ 
+ static DEFINE_MUTEX(dcss_lock);
+-static struct list_head dcss_list = LIST_HEAD_INIT(dcss_list);
++static LIST_HEAD(dcss_list);
+ static char *segtype_string[] = { "SW", "EW", "SR", "ER", "SN", "EN", "SC",
+ 					"EW/EN-MIXED" };
+ 
+diff --git a/arch/s390/mm/vmem.c b/arch/s390/mm/vmem.c
+index fb9c5a8..79d13a1 100644
+--- a/arch/s390/mm/vmem.c
++++ b/arch/s390/mm/vmem.c
+@@ -15,10 +15,6 @@
+ #include <asm/setup.h>
+ #include <asm/tlbflush.h>
+ 
+-unsigned long vmalloc_end;
+-EXPORT_SYMBOL(vmalloc_end);
+-
+-static struct page *vmem_map;
+ static DEFINE_MUTEX(vmem_mutex);
+ 
+ struct memory_segment {
+@@ -188,8 +184,8 @@ static int vmem_add_mem_map(unsigned long start, unsigned long size)
+ 	pte_t  pte;
+ 	int ret = -ENOMEM;
+ 
+-	map_start = vmem_map + PFN_DOWN(start);
+-	map_end	= vmem_map + PFN_DOWN(start + size);
++	map_start = VMEM_MAP + PFN_DOWN(start);
++	map_end	= VMEM_MAP + PFN_DOWN(start + size);
+ 
+ 	start_addr = (unsigned long) map_start & PAGE_MASK;
+ 	end_addr = PFN_ALIGN((unsigned long) map_end);
+@@ -240,10 +236,10 @@ static int vmem_add_mem(unsigned long start, unsigned long size)
+ {
+ 	int ret;
+ 
+-	ret = vmem_add_range(start, size);
++	ret = vmem_add_mem_map(start, size);
+ 	if (ret)
+ 		return ret;
+-	return vmem_add_mem_map(start, size);
++	return vmem_add_range(start, size);
+ }
+ 
+ /*
+@@ -254,7 +250,7 @@ static int insert_memory_segment(struct memory_segment *seg)
+ {
+ 	struct memory_segment *tmp;
+ 
+-	if (PFN_DOWN(seg->start + seg->size) > max_pfn ||
++	if (seg->start + seg->size >= VMALLOC_START ||
+ 	    seg->start + seg->size < seg->start)
+ 		return -ERANGE;
+ 
+@@ -357,17 +353,15 @@ out:
+ 
+ /*
+  * map whole physical memory to virtual memory (identity mapping)
++ * we reserve enough space in the vmalloc area for vmemmap to hotplug
++ * additional memory segments.
+  */
+ void __init vmem_map_init(void)
+ {
+-	unsigned long map_size;
+ 	int i;
+ 
+-	map_size = ALIGN(max_low_pfn, MAX_ORDER_NR_PAGES) * sizeof(struct page);
+-	vmalloc_end = PFN_ALIGN(VMALLOC_END_INIT) - PFN_ALIGN(map_size);
+-	vmem_map = (struct page *) vmalloc_end;
+-	NODE_DATA(0)->node_mem_map = vmem_map;
+-
++	BUILD_BUG_ON((unsigned long)VMEM_MAP + VMEM_MAP_SIZE > VMEM_MAP_MAX);
++	NODE_DATA(0)->node_mem_map = VMEM_MAP;
+ 	for (i = 0; i < MEMORY_CHUNKS && memory_chunk[i].size > 0; i++)
+ 		vmem_add_mem(memory_chunk[i].addr, memory_chunk[i].size);
+ }
+@@ -382,7 +376,7 @@ static int __init vmem_convert_memory_chunk(void)
+ 	int i;
+ 
+ 	mutex_lock(&vmem_mutex);
+-	for (i = 0; i < MEMORY_CHUNKS && memory_chunk[i].size > 0; i++) {
++	for (i = 0; i < MEMORY_CHUNKS; i++) {
+ 		if (!memory_chunk[i].size)
+ 			continue;
+ 		seg = kzalloc(sizeof(*seg), GFP_KERNEL);
+diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig
+index 496d635..1cd9c8f 100644
+--- a/arch/sh/Kconfig
++++ b/arch/sh/Kconfig
+@@ -6,8 +6,7 @@
+ mainmenu "Linux/SuperH Kernel Configuration"
+ 
+ config SUPERH
+-	bool
+-	default y
++	def_bool y
+ 	select EMBEDDED
+ 	help
+ 	  The SuperH is a RISC processor targeted for use in embedded systems
+@@ -15,36 +14,36 @@ config SUPERH
+ 	  gaming console.  The SuperH port has a home page at
+ 	  <http://www.linux-sh.org/>.
+ 
++config SUPERH32
++	def_bool !SUPERH64
++
++config SUPERH64
++	def_bool y if CPU_SH5
++
+ config RWSEM_GENERIC_SPINLOCK
+-	bool
+-	default y
++	def_bool y
+ 
+ config RWSEM_XCHGADD_ALGORITHM
+ 	bool
+ 
+ config GENERIC_BUG
+ 	def_bool y
+-	depends on BUG
++	depends on BUG && SUPERH32
+ 
+ config GENERIC_FIND_NEXT_BIT
+-	bool
+-	default y
++	def_bool y
+ 
+ config GENERIC_HWEIGHT
+-	bool
+-	default y
++	def_bool y
+ 
+ config GENERIC_HARDIRQS
+-	bool
+-	default y
++	def_bool y
+ 
+ config GENERIC_IRQ_PROBE
+-	bool
+-	default y
++	def_bool y
+ 
+ config GENERIC_CALIBRATE_DELAY
+-	bool
+-	default y
++	def_bool y
+ 
+ config GENERIC_IOMAP
+ 	bool
+@@ -75,20 +74,16 @@ config ARCH_MAY_HAVE_PC_FDC
+ 	bool
+ 
+ config STACKTRACE_SUPPORT
+-	bool
+-	default y
++	def_bool y
+ 
+ config LOCKDEP_SUPPORT
+-	bool
+-	default y
++	def_bool y
+ 
+ config ARCH_HAS_ILOG2_U32
+-	bool
+-	default n
++	def_bool n
+ 
+ config ARCH_HAS_ILOG2_U64
+-	bool
+-	default n
++	def_bool n
+ 
+ config ARCH_NO_VIRT_TO_BUS
+ 	def_bool y
+@@ -97,110 +92,234 @@ source "init/Kconfig"
+ 
+ menu "System type"
+ 
+-source "arch/sh/mm/Kconfig"
++#
++# Processor families
++#
++config CPU_SH2
++	bool
+ 
+-menu "Processor features"
++config CPU_SH2A
++	bool
++	select CPU_SH2
++
++config CPU_SH3
++	bool
++	select CPU_HAS_INTEVT
++	select CPU_HAS_SR_RB
++
++config CPU_SH4
++	bool
++	select CPU_HAS_INTEVT
++	select CPU_HAS_SR_RB
++	select CPU_HAS_PTEA if !CPU_SH4A || CPU_SHX2
++	select CPU_HAS_FPU if !CPU_SH4AL_DSP
++
++config CPU_SH4A
++	bool
++	select CPU_SH4
++
++config CPU_SH4AL_DSP
++	bool
++	select CPU_SH4A
++	select CPU_HAS_DSP
++
++config CPU_SH5
++	bool
++	select CPU_HAS_FPU
++
++config CPU_SHX2
++	bool
++
++config CPU_SHX3
++	bool
+ 
+ choice
+-	prompt "Endianess selection" 
+-	default CPU_LITTLE_ENDIAN
+-	help
+-	  Some SuperH machines can be configured for either little or big
+-	  endian byte order. These modes require different kernels.
++	prompt "Processor sub-type selection"
+ 
+-config CPU_LITTLE_ENDIAN
+-	bool "Little Endian"
++#
++# Processor subtypes
++#
+ 
+-config CPU_BIG_ENDIAN
+-	bool "Big Endian"
++# SH-2 Processor Support
+ 
+-endchoice
++config CPU_SUBTYPE_SH7619
++	bool "Support SH7619 processor"
++	select CPU_SH2
++
++# SH-2A Processor Support
++
++config CPU_SUBTYPE_SH7203
++	bool "Support SH7203 processor"
++	select CPU_SH2A
++	select CPU_HAS_FPU
++
++config CPU_SUBTYPE_SH7206
++	bool "Support SH7206 processor"
++	select CPU_SH2A
+ 
+-config SH_FPU
+-	bool "FPU support"
+-	depends on CPU_HAS_FPU
+-	default y
++config CPU_SUBTYPE_SH7263
++	bool "Support SH7263 processor"
++	select CPU_SH2A
++	select CPU_HAS_FPU
++
++# SH-3 Processor Support
++
++config CPU_SUBTYPE_SH7705
++	bool "Support SH7705 processor"
++	select CPU_SH3
++
++config CPU_SUBTYPE_SH7706
++	bool "Support SH7706 processor"
++	select CPU_SH3
+ 	help
+-	  Selecting this option will enable support for SH processors that
+-	  have FPU units (ie, SH77xx).
++	  Select SH7706 if you have a 133 Mhz SH-3 HD6417706 CPU.
+ 
+-	  This option must be set in order to enable the FPU.
++config CPU_SUBTYPE_SH7707
++	bool "Support SH7707 processor"
++	select CPU_SH3
++	help
++	  Select SH7707 if you have a  60 Mhz SH-3 HD6417707 CPU.
+ 
+-config SH_FPU_EMU
+-	bool "FPU emulation support"
+-	depends on !SH_FPU && EXPERIMENTAL
+-	default n
++config CPU_SUBTYPE_SH7708
++	bool "Support SH7708 processor"
++	select CPU_SH3
+ 	help
+-	  Selecting this option will enable support for software FPU emulation.
+-	  Most SH-3 users will want to say Y here, whereas most SH-4 users will
+-	  want to say N.
++	  Select SH7708 if you have a  60 Mhz SH-3 HD6417708S or
++	  if you have a 100 Mhz SH-3 HD6417708R CPU.
+ 
+-config SH_DSP
+-	bool "DSP support"
+-	depends on CPU_HAS_DSP
+-	default y
++config CPU_SUBTYPE_SH7709
++	bool "Support SH7709 processor"
++	select CPU_SH3
+ 	help
+-	  Selecting this option will enable support for SH processors that
+-	  have DSP units (ie, SH2-DSP, SH3-DSP, and SH4AL-DSP).
++	  Select SH7709 if you have a  80 Mhz SH-3 HD6417709 CPU.
+ 
+-	  This option must be set in order to enable the DSP.
++config CPU_SUBTYPE_SH7710
++	bool "Support SH7710 processor"
++	select CPU_SH3
++	select CPU_HAS_DSP
++	help
++	  Select SH7710 if you have a SH3-DSP SH7710 CPU.
+ 
+-config SH_ADC
+-	bool "ADC support"
+-	depends on CPU_SH3
+-	default y
++config CPU_SUBTYPE_SH7712
++	bool "Support SH7712 processor"
++	select CPU_SH3
++	select CPU_HAS_DSP
+ 	help
+-	  Selecting this option will allow the Linux kernel to use SH3 on-chip
+-	  ADC module.
++	  Select SH7712 if you have a SH3-DSP SH7712 CPU.
+ 
+-	  If unsure, say N.
++config CPU_SUBTYPE_SH7720
++	bool "Support SH7720 processor"
++	select CPU_SH3
++	select CPU_HAS_DSP
++	help
++	  Select SH7720 if you have a SH3-DSP SH7720 CPU.
+ 
+-config SH_STORE_QUEUES
+-	bool "Support for Store Queues"
+-	depends on CPU_SH4
++config CPU_SUBTYPE_SH7721
++	bool "Support SH7721 processor"
++	select CPU_SH3
++	select CPU_HAS_DSP
+ 	help
+-	  Selecting this option will enable an in-kernel API for manipulating
+-	  the store queues integrated in the SH-4 processors.
++	  Select SH7721 if you have a SH3-DSP SH7721 CPU.
+ 
+-config SPECULATIVE_EXECUTION
+-	bool "Speculative subroutine return"
+-	depends on CPU_SUBTYPE_SH7780 && EXPERIMENTAL
++# SH-4 Processor Support
++
++config CPU_SUBTYPE_SH7750
++	bool "Support SH7750 processor"
++	select CPU_SH4
+ 	help
+-	  This enables support for a speculative instruction fetch for
+-	  subroutine return. There are various pitfalls associated with
+-	  this, as outlined in the SH7780 hardware manual.
++	  Select SH7750 if you have a 200 Mhz SH-4 HD6417750 CPU.
+ 
+-	  If unsure, say N.
++config CPU_SUBTYPE_SH7091
++	bool "Support SH7091 processor"
++	select CPU_SH4
++	help
++	  Select SH7091 if you have an SH-4 based Sega device (such as
++	  the Dreamcast, Naomi, and Naomi 2).
+ 
+-config CPU_HAS_INTEVT
+-	bool
++config CPU_SUBTYPE_SH7750R
++	bool "Support SH7750R processor"
++	select CPU_SH4
+ 
+-config CPU_HAS_MASKREG_IRQ
+-	bool
++config CPU_SUBTYPE_SH7750S
++	bool "Support SH7750S processor"
++	select CPU_SH4
+ 
+-config CPU_HAS_IPR_IRQ
+-	bool
++config CPU_SUBTYPE_SH7751
++	bool "Support SH7751 processor"
++	select CPU_SH4
++	help
++	  Select SH7751 if you have a 166 Mhz SH-4 HD6417751 CPU,
++	  or if you have a HD6417751R CPU.
+ 
+-config CPU_HAS_SR_RB
+-	bool
++config CPU_SUBTYPE_SH7751R
++	bool "Support SH7751R processor"
++	select CPU_SH4
++
++config CPU_SUBTYPE_SH7760
++	bool "Support SH7760 processor"
++	select CPU_SH4
++
++config CPU_SUBTYPE_SH4_202
++	bool "Support SH4-202 processor"
++	select CPU_SH4
++
++# SH-4A Processor Support
++
++config CPU_SUBTYPE_SH7763
++	bool "Support SH7763 processor"
++	select CPU_SH4A
+ 	help
+-	  This will enable the use of SR.RB register bank usage. Processors
+-	  that are lacking this bit must have another method in place for
+-	  accomplishing what is taken care of by the banked registers.
++	  Select SH7763 if you have a SH4A SH7763(R5S77631) CPU.
+ 
+-	  See <file:Documentation/sh/register-banks.txt> for further
+-	  information on SR.RB and register banking in the kernel in general.
++config CPU_SUBTYPE_SH7770
++	bool "Support SH7770 processor"
++	select CPU_SH4A
+ 
+-config CPU_HAS_PTEA
+-	bool
++config CPU_SUBTYPE_SH7780
++	bool "Support SH7780 processor"
++	select CPU_SH4A
+ 
+-config CPU_HAS_DSP
+-	bool
++config CPU_SUBTYPE_SH7785
++	bool "Support SH7785 processor"
++	select CPU_SH4A
++	select CPU_SHX2
++	select ARCH_SPARSEMEM_ENABLE
++	select SYS_SUPPORTS_NUMA
+ 
+-config CPU_HAS_FPU
+-	bool
++config CPU_SUBTYPE_SHX3
++	bool "Support SH-X3 processor"
++	select CPU_SH4A
++	select CPU_SHX3
++	select ARCH_SPARSEMEM_ENABLE
++	select SYS_SUPPORTS_NUMA
++	select SYS_SUPPORTS_SMP
+ 
+-endmenu
++# SH4AL-DSP Processor Support
++
++config CPU_SUBTYPE_SH7343
++	bool "Support SH7343 processor"
++	select CPU_SH4AL_DSP
++
++config CPU_SUBTYPE_SH7722
++	bool "Support SH7722 processor"
++	select CPU_SH4AL_DSP
++	select CPU_SHX2
++	select ARCH_SPARSEMEM_ENABLE
++	select SYS_SUPPORTS_NUMA
++
++# SH-5 Processor Support
++
++config CPU_SUBTYPE_SH5_101
++	bool "Support SH5-101 processor"
++	select CPU_SH5
++
++config CPU_SUBTYPE_SH5_103
++	bool "Support SH5-103 processor"
++
++endchoice
++
++source "arch/sh/mm/Kconfig"
++source "arch/sh/Kconfig.cpu"
+ 
+ menu "Board support"
+ 
+@@ -321,13 +440,6 @@ config SH_SECUREEDGE5410
+ 	  This includes both the OEM SecureEdge products as well as the
+ 	  SME product line.
+ 
+-config SH_HS7751RVOIP
+-	bool "HS7751RVOIP"
+-	depends on CPU_SUBTYPE_SH7751R
+-	help
+-	  Select HS7751RVOIP if configuring for a Renesas Technology
+-	  Sales VoIP board.
+-
+ config SH_7710VOIPGW
+ 	bool "SH7710-VOIP-GW"
+ 	depends on CPU_SUBTYPE_SH7710
+@@ -343,6 +455,14 @@ config SH_RTS7751R2D
+ 	  Select RTS7751R2D if configuring for a Renesas Technology
+ 	  Sales SH-Graphics board.
+ 
++config SH_SDK7780
++	bool "SDK7780R3"
++	depends on CPU_SUBTYPE_SH7780
++	select SYS_SUPPORTS_PCI
++	help
++	  Select SDK7780 if configuring for a Renesas SH7780 SDK7780R3
++	  evaluation board.
++
+ config SH_HIGHLANDER
+ 	bool "Highlander"
+ 	depends on CPU_SUBTYPE_SH7780 || CPU_SUBTYPE_SH7785
+@@ -399,41 +519,47 @@ config SH_MAGIC_PANEL_R2
+ 	help
+ 	  Select Magic Panel R2 if configuring for Magic Panel R2.
+ 
++config SH_CAYMAN
++	bool "Hitachi Cayman"
++	depends on CPU_SUBTYPE_SH5_101 || CPU_SUBTYPE_SH5_103
++	select SYS_SUPPORTS_PCI
++
+ endmenu
+ 
+-source "arch/sh/boards/renesas/hs7751rvoip/Kconfig"
+ source "arch/sh/boards/renesas/rts7751r2d/Kconfig"
+ source "arch/sh/boards/renesas/r7780rp/Kconfig"
++source "arch/sh/boards/renesas/sdk7780/Kconfig"
+ source "arch/sh/boards/magicpanelr2/Kconfig"
+ 
+ menu "Timer and clock configuration"
+ 
+ config SH_TMU
+-	bool "TMU timer support"
++	def_bool y
++	prompt "TMU timer support"
+ 	depends on CPU_SH3 || CPU_SH4
+ 	select GENERIC_TIME
+ 	select GENERIC_CLOCKEVENTS
+-	default y
+ 	help
+ 	  This enables the use of the TMU as the system timer.
+ 
+ config SH_CMT
+-	bool "CMT timer support"
++	def_bool y
++	prompt "CMT timer support"
+ 	depends on CPU_SH2
+-	default y
+ 	help
+ 	  This enables the use of the CMT as the system timer.
+ 
+ config SH_MTU2
+-	bool "MTU2 timer support"
++	def_bool n
++	prompt "MTU2 timer support"
+ 	depends on CPU_SH2A
+-	default n
+ 	help
+ 	  This enables the use of the MTU2 as the system timer.
+ 
+ config SH_TIMER_IRQ
+ 	int
+-	default "28" if CPU_SUBTYPE_SH7780 || CPU_SUBTYPE_SH7785
++	default "28" if CPU_SUBTYPE_SH7780 || CPU_SUBTYPE_SH7785 || \
++			CPU_SUBTYPE_SH7763
+ 	default "86" if CPU_SUBTYPE_SH7619
+ 	default "140" if CPU_SUBTYPE_SH7206
+ 	default "16"
+@@ -445,7 +571,8 @@ config SH_PCLK_FREQ
+ 	default "32000000" if CPU_SUBTYPE_SH7722
+ 	default "33333333" if CPU_SUBTYPE_SH7770 || \
+ 			      CPU_SUBTYPE_SH7760 || CPU_SUBTYPE_SH7705 || \
+-			      CPU_SUBTYPE_SH7206
++			      CPU_SUBTYPE_SH7203 || CPU_SUBTYPE_SH7206 || \
++			      CPU_SUBTYPE_SH7263
+ 	default "60000000" if CPU_SUBTYPE_SH7751 || CPU_SUBTYPE_SH7751R
+ 	default "66000000" if CPU_SUBTYPE_SH4_202
+ 	default "50000000"
+@@ -456,7 +583,7 @@ config SH_PCLK_FREQ
+ 
+ config SH_CLK_MD
+ 	int "CPU Mode Pin Setting"
+-	depends on CPU_SUBTYPE_SH7619 || CPU_SUBTYPE_SH7206
++	depends on CPU_SH2
+ 	default 6 if CPU_SUBTYPE_SH7206
+ 	default 5 if CPU_SUBTYPE_SH7619
+ 	default 0
+@@ -490,9 +617,8 @@ source "arch/sh/drivers/Kconfig"
+ endmenu
+ 
+ config ISA_DMA_API
+-	bool
++	def_bool y
+ 	depends on SH_MPC1211
+-	default y
+ 
+ menu "Kernel features"
+ 
+@@ -570,7 +696,7 @@ source "kernel/Kconfig.preempt"
+ 
+ config GUSA
+ 	def_bool y
+-	depends on !SMP
++	depends on !SMP && SUPERH32
+ 	help
+ 	  This enables support for gUSA (general UserSpace Atomicity).
+ 	  This is the default implementation for both UP and non-ll/sc
+@@ -582,6 +708,16 @@ config GUSA
+ 	  This should only be disabled for special cases where alternate
+ 	  atomicity implementations exist.
+ 
++config GUSA_RB
++	bool "Implement atomic operations by roll-back (gRB) (EXPERIMENTAL)"
++	depends on GUSA && CPU_SH3 || (CPU_SH4 && !CPU_SH4A)
++	help
++	  Enabling this option will allow the kernel to implement some
++	  atomic operations using a software implemention of load-locked/
++	  store-conditional (LLSC). On machines which do not have hardware
++	  LLSC, this should be more efficient than the other alternative of
++	  disabling insterrupts around the atomic sequence.
++
+ endmenu
+ 
+ menu "Boot options"
+diff --git a/arch/sh/Kconfig.cpu b/arch/sh/Kconfig.cpu
+new file mode 100644
+index 0000000..d850184
+--- /dev/null
++++ b/arch/sh/Kconfig.cpu
+@@ -0,0 +1,115 @@
++menu "Processor features"
++
++choice
++	prompt "Endianess selection" 
++	default CPU_LITTLE_ENDIAN
++	help
++	  Some SuperH machines can be configured for either little or big
++	  endian byte order. These modes require different kernels.
++
++config CPU_LITTLE_ENDIAN
++	bool "Little Endian"
++
++config CPU_BIG_ENDIAN
++	bool "Big Endian"
++
++endchoice
++
++config SH_FPU
++	def_bool y
++	prompt "FPU support"
++	depends on CPU_HAS_FPU
++	help
++	  Selecting this option will enable support for SH processors that
++	  have FPU units (ie, SH77xx).
++
++	  This option must be set in order to enable the FPU.
++
++config SH64_FPU_DENORM_FLUSH
++	bool "Flush floating point denorms to zero"
++	depends on SH_FPU && SUPERH64
++
++config SH_FPU_EMU
++	def_bool n
++	prompt "FPU emulation support"
++	depends on !SH_FPU && EXPERIMENTAL
++	help
++	  Selecting this option will enable support for software FPU emulation.
++	  Most SH-3 users will want to say Y here, whereas most SH-4 users will
++	  want to say N.
++
++config SH_DSP
++	def_bool y
++	prompt "DSP support"
++	depends on CPU_HAS_DSP
++	help
++	  Selecting this option will enable support for SH processors that
++	  have DSP units (ie, SH2-DSP, SH3-DSP, and SH4AL-DSP).
++
++	  This option must be set in order to enable the DSP.
++
++config SH_ADC
++	def_bool y
++	prompt "ADC support"
++	depends on CPU_SH3
++	help
++	  Selecting this option will allow the Linux kernel to use SH3 on-chip
++	  ADC module.
++
++	  If unsure, say N.
++
++config SH_STORE_QUEUES
++	bool "Support for Store Queues"
++	depends on CPU_SH4
++	help
++	  Selecting this option will enable an in-kernel API for manipulating
++	  the store queues integrated in the SH-4 processors.
++
++config SPECULATIVE_EXECUTION
++	bool "Speculative subroutine return"
++	depends on CPU_SUBTYPE_SH7780 && EXPERIMENTAL
++	help
++	  This enables support for a speculative instruction fetch for
++	  subroutine return. There are various pitfalls associated with
++	  this, as outlined in the SH7780 hardware manual.
++
++	  If unsure, say N.
++
++config SH64_USER_MISALIGNED_FIXUP
++	def_bool y
++	prompt "Fixup misaligned loads/stores occurring in user mode"
++	depends on SUPERH64
++
++config SH64_ID2815_WORKAROUND
++	bool "Include workaround for SH5-101 cut2 silicon defect ID2815"
++	depends on CPU_SUBTYPE_SH5_101
++
++config CPU_HAS_INTEVT
++	bool
++
++config CPU_HAS_MASKREG_IRQ
++	bool
++
++config CPU_HAS_IPR_IRQ
++	bool
++
++config CPU_HAS_SR_RB
++	bool
++	help
++	  This will enable the use of SR.RB register bank usage. Processors
++	  that are lacking this bit must have another method in place for
++	  accomplishing what is taken care of by the banked registers.
++
++	  See <file:Documentation/sh/register-banks.txt> for further
++	  information on SR.RB and register banking in the kernel in general.
++
++config CPU_HAS_PTEA
++	bool
++
++config CPU_HAS_DSP
++	bool
++
++config CPU_HAS_FPU
++	bool
++
++endmenu
+diff --git a/arch/sh/Kconfig.debug b/arch/sh/Kconfig.debug
+index 722da68..f7c7161 100644
+--- a/arch/sh/Kconfig.debug
++++ b/arch/sh/Kconfig.debug
+@@ -1,8 +1,7 @@
+ menu "Kernel hacking"
+ 
+ config TRACE_IRQFLAGS_SUPPORT
+-	bool
+-	default y
++	def_bool y
+ 
+ source "lib/Kconfig.debug"
+ 
+@@ -30,12 +29,13 @@ config EARLY_SCIF_CONSOLE
+ config EARLY_SCIF_CONSOLE_PORT
+ 	hex
+ 	depends on EARLY_SCIF_CONSOLE
+-	default "0xffe00000" if CPU_SUBTYPE_SH7780
++ 	default "0xffe00000" if CPU_SUBTYPE_SH7780 || CPU_SUBTYPE_SH7763
+ 	default "0xffea0000" if CPU_SUBTYPE_SH7785
+-	default "0xfffe9800" if CPU_SUBTYPE_SH7206
++	default "0xfffe8000" if CPU_SUBTYPE_SH7203
++	default "0xfffe9800" if CPU_SUBTYPE_SH7206 || CPU_SUBTYPE_SH7263
+ 	default "0xf8420000" if CPU_SUBTYPE_SH7619
+ 	default "0xa4400000" if CPU_SUBTYPE_SH7712 || CPU_SUBTYPE_SH7705
+-	default "0xa4430000" if CPU_SUBTYPE_SH7720
++	default "0xa4430000" if CPU_SUBTYPE_SH7720 || CPU_SUBTYPE_SH7721
+ 	default "0xffc30000" if CPU_SUBTYPE_SHX3
+ 	default "0xffe80000" if CPU_SH4
+ 	default "0x00000000"
+@@ -62,7 +62,7 @@ config DEBUG_BOOTMEM
+ 
+ config DEBUG_STACKOVERFLOW
+ 	bool "Check for stack overflows"
+-	depends on DEBUG_KERNEL
++	depends on DEBUG_KERNEL && SUPERH32
+ 	help
+ 	  This option will cause messages to be printed if free stack space
+ 	  drops below a certain limit.
+@@ -88,7 +88,7 @@ config 4KSTACKS
+ 
+ config IRQSTACKS
+ 	bool "Use separate kernel stacks when processing interrupts"
+-	depends on DEBUG_KERNEL
++	depends on DEBUG_KERNEL && SUPERH32
+ 	help
+ 	  If you say Y here the kernel will use separate kernel stacks
+ 	  for handling hard and soft interrupts.  This can help avoid
+@@ -119,19 +119,19 @@ config COMPILE_OPTIONS
+ 	depends on MORE_COMPILE_OPTIONS
+ 
+ config KGDB_NMI
+-	bool "Enter KGDB on NMI"
+-	default n
++	def_bool n
++	prompt "Enter KGDB on NMI"
+ 
+ config SH_KGDB_CONSOLE
+-	bool "Console messages through GDB"
++	def_bool n
++	prompt "Console messages through GDB"
+ 	depends on !SERIAL_SH_SCI_CONSOLE && SERIAL_SH_SCI=y
+ 	select SERIAL_CORE_CONSOLE
+-	default n
+ 
+ config KGDB_SYSRQ
+-	bool "Allow SysRq 'G' to enter KGDB"
++	def_bool y
++	prompt "Allow SysRq 'G' to enter KGDB"
+ 	depends on MAGIC_SYSRQ
+-	default y
+ 
+ comment "Serial port setup"
+ 
+@@ -174,4 +174,29 @@ endchoice
+ 
+ endmenu
+ 
++if SUPERH64
++
++config SH64_PROC_ASIDS
++	bool "Debug: report ASIDs through /proc/asids"
++	depends on PROC_FS
++
++config SH64_SR_WATCH
++	bool "Debug: set SR.WATCH to enable hardware watchpoints and trace"
++
++config POOR_MANS_STRACE
++	bool "Debug: enable rudimentary strace facility"
++	help
++	  This option allows system calls to be traced to the console.  It also
++	  aids in detecting kernel stack underflow.  It is useful for debugging
++	  early-userland problems (e.g. init incurring fatal exceptions.)
++
++config SH_ALPHANUMERIC
++	bool "Enable debug outputs to on-board alphanumeric display"
++	depends on SH_CAYMAN
++
++config SH_NO_BSS_INIT
++	bool "Avoid zeroing BSS (to speed-up startup on suitable platforms)"
++
++endif
++
+ endmenu
+diff --git a/arch/sh/Makefile b/arch/sh/Makefile
+index e189fae..17fc361 100644
+--- a/arch/sh/Makefile
++++ b/arch/sh/Makefile
+@@ -1,17 +1,13 @@
+-# $Id: Makefile,v 1.35 2004/04/15 03:39:20 sugioka Exp $
+ #
+-# This file is subject to the terms and conditions of the GNU General Public
+-# License.  See the file "COPYING" in the main directory of this archive
+-# for more details.
++# arch/sh/Makefile
+ #
+ # Copyright (C) 1999  Kaz Kojima
+ # Copyright (C) 2002, 2003, 2004  Paul Mundt
+ # Copyright (C) 2002  M. R. Brown
+ #
+-# This file is included by the global makefile so that you can add your own
+-# architecture-specific flags and dependencies. Remember to do have actions
+-# for "archclean" and "archdep" for cleaning up and making dependencies for
+-# this architecture
++# 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.
+ #
+ isa-y					:= any
+ isa-$(CONFIG_SH_DSP)			:= sh
+@@ -21,13 +17,9 @@ isa-$(CONFIG_CPU_SH3)			:= sh3
+ isa-$(CONFIG_CPU_SH4)			:= sh4
+ isa-$(CONFIG_CPU_SH4A)			:= sh4a
+ isa-$(CONFIG_CPU_SH4AL_DSP)		:= sh4al
+-
++isa-$(CONFIG_CPU_SH5)			:= shmedia
+ isa-$(CONFIG_SH_DSP)			:= $(isa-y)-dsp
+ 
+-ifndef CONFIG_MMU
+-isa-y			:= $(isa-y)-nommu
+-endif
+-
+ ifndef CONFIG_SH_DSP
+ ifndef CONFIG_SH_FPU
+ isa-y			:= $(isa-y)-nofpu
+@@ -44,6 +36,7 @@ cflags-$(CONFIG_CPU_SH4)		:= $(call cc-option,-m4,) \
+ 	$(call cc-option,-mno-implicit-fp,-m4-nofpu)
+ cflags-$(CONFIG_CPU_SH4A)		+= $(call cc-option,-m4a,) \
+ 					   $(call cc-option,-m4a-nofpu,)
++cflags-$(CONFIG_CPU_SH5)		:= $(call cc-option,-m5-32media-nofpu,)
+ 
+ cflags-$(CONFIG_CPU_BIG_ENDIAN)		+= -mb
+ cflags-$(CONFIG_CPU_LITTLE_ENDIAN)	+= -ml
+@@ -66,22 +59,27 @@ cflags-y	+= $(isaflags-y) -ffreestanding
+ cflags-$(CONFIG_MORE_COMPILE_OPTIONS)	+= \
+ 	$(shell echo $(CONFIG_COMPILE_OPTIONS) | sed -e 's/"//g')
+ 
+-OBJCOPYFLAGS	:= -O binary -R .note -R .note.gnu.build-id -R .comment -R .stab -R .stabstr -S
++OBJCOPYFLAGS	:= -O binary -R .note -R .note.gnu.build-id -R .comment \
++		   -R .stab -R .stabstr -S
+ 
+-#
+-# arch/sh/defconfig doesn't reflect any real hardware, and as such should
+-# never be used by anyone. Use a board-specific defconfig that has a
+-# reasonable chance of being current instead.
+-#
+-KBUILD_DEFCONFIG := r7780rp_defconfig
++# Give the various platforms the opportunity to set default image types
++defaultimage-$(CONFIG_SUPERH32)	:= zImage
+ 
+-KBUILD_IMAGE	:= arch/sh/boot/zImage
++# Set some sensible Kbuild defaults
++KBUILD_DEFCONFIG	:= r7780mp_defconfig
++KBUILD_IMAGE		:= $(defaultimage-y)
+ 
+ #
+ # Choosing incompatible machines durings configuration will result in
+ # error messages during linking.
+ #
+-LDFLAGS_vmlinux     += -e _stext
++ifdef CONFIG_SUPERH32
++LDFLAGS_vmlinux	+= -e _stext
++else
++LDFLAGS_vmlinux	+= --defsym phys_stext=_stext-$(CONFIG_PAGE_OFFSET) \
++		   --defsym phys_stext_shmedia=phys_stext+1 \
++		   -e phys_stext_shmedia
++endif
+ 
+ ifdef CONFIG_CPU_LITTLE_ENDIAN
+ LDFLAGS_vmlinux		+= --defsym 'jiffies=jiffies_64'
+@@ -94,7 +92,9 @@ endif
+ KBUILD_CFLAGS		+= -pipe $(cflags-y)
+ KBUILD_AFLAGS		+= $(cflags-y)
+ 
+-head-y := arch/sh/kernel/head.o arch/sh/kernel/init_task.o
++head-y			:= arch/sh/kernel/init_task.o
++head-$(CONFIG_SUPERH32)	+= arch/sh/kernel/head_32.o
++head-$(CONFIG_SUPERH64)	+= arch/sh/kernel/head_64.o
+ 
+ LIBGCC := $(shell $(CC) $(KBUILD_CFLAGS) -print-libgcc-file-name)
+ 
+@@ -112,11 +112,11 @@ machdir-$(CONFIG_SH_DREAMCAST)			+= dreamcast
+ machdir-$(CONFIG_SH_MPC1211)			+= mpc1211
+ machdir-$(CONFIG_SH_SH03)			+= sh03
+ machdir-$(CONFIG_SH_SECUREEDGE5410)		+= snapgear
+-machdir-$(CONFIG_SH_HS7751RVOIP)		+= renesas/hs7751rvoip
+ machdir-$(CONFIG_SH_RTS7751R2D)			+= renesas/rts7751r2d
+ machdir-$(CONFIG_SH_7751_SYSTEMH)		+= renesas/systemh
+ machdir-$(CONFIG_SH_EDOSK7705)			+= renesas/edosk7705
+ machdir-$(CONFIG_SH_HIGHLANDER)			+= renesas/r7780rp
++machdir-$(CONFIG_SH_SDK7780)			+= renesas/sdk7780
+ machdir-$(CONFIG_SH_7710VOIPGW)			+= renesas/sh7710voipgw
+ machdir-$(CONFIG_SH_X3PROTO)			+= renesas/x3proto
+ machdir-$(CONFIG_SH_SH4202_MICRODEV)		+= superh/microdev
+@@ -127,6 +127,7 @@ machdir-$(CONFIG_SH_7206_SOLUTION_ENGINE)	+= se/7206
+ machdir-$(CONFIG_SH_7619_SOLUTION_ENGINE)	+= se/7619
+ machdir-$(CONFIG_SH_LBOX_RE2)			+= lboxre2
+ machdir-$(CONFIG_SH_MAGIC_PANEL_R2)		+= magicpanelr2
++machdir-$(CONFIG_SH_CAYMAN)			+= cayman
+ 
+ incdir-y	:= $(notdir $(machdir-y))
+ 
+@@ -137,22 +138,22 @@ endif
+ 
+ # Companion chips
+ core-$(CONFIG_HD6446X_SERIES)	+= arch/sh/cchips/hd6446x/
+-core-$(CONFIG_MFD_SM501)	+= arch/sh/cchips/voyagergx/
+ 
+ cpuincdir-$(CONFIG_CPU_SH2)	:= cpu-sh2
+ cpuincdir-$(CONFIG_CPU_SH2A)	:= cpu-sh2a
+ cpuincdir-$(CONFIG_CPU_SH3)	:= cpu-sh3
+ cpuincdir-$(CONFIG_CPU_SH4)	:= cpu-sh4
++cpuincdir-$(CONFIG_CPU_SH5)	:= cpu-sh5
+ 
+-libs-y				:= arch/sh/lib/	$(libs-y) $(LIBGCC)
++libs-$(CONFIG_SUPERH32)		:= arch/sh/lib/	$(libs-y)
++libs-$(CONFIG_SUPERH64)		:= arch/sh/lib64/ $(libs-y)
++libs-y				+= $(LIBGCC)
+ 
+ drivers-y			+= arch/sh/drivers/
+ drivers-$(CONFIG_OPROFILE)	+= arch/sh/oprofile/
+ 
+ boot := arch/sh/boot
+ 
+-CPPFLAGS_vmlinux.lds := -traditional
+-
+ incdir-prefix	:= $(srctree)/include/asm-sh/
+ 
+ #	Update machine arch and proc symlinks if something which affects
+@@ -196,29 +197,61 @@ include/asm-sh/.mach: $(wildcard include/config/sh/*.h) \
+ 	done
+ 	@touch $@
+ 
+-archprepare: include/asm-sh/.cpu include/asm-sh/.mach maketools
+-
+ PHONY += maketools FORCE
++
+ maketools:  include/linux/version.h FORCE
+ 	$(Q)$(MAKE) $(build)=arch/sh/tools include/asm-sh/machtypes.h
+ 
+-all: zImage
++all: $(KBUILD_IMAGE)
+ 
+ zImage uImage uImage.srec vmlinux.srec: vmlinux
+ 	$(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
+ 
+ compressed: zImage
+ 
++archprepare: include/asm-sh/.cpu include/asm-sh/.mach maketools \
++	     arch/sh/lib64/syscalltab.h
++
+ archclean:
+ 	$(Q)$(MAKE) $(clean)=$(boot)
+ 
+-CLEAN_FILES += include/asm-sh/machtypes.h \
+-	       include/asm-sh/cpu include/asm-sh/.cpu \
+-	       include/asm-sh/mach include/asm-sh/.mach
+-
+ define archhelp
+ 	@echo '* zImage 	           - Compressed kernel image'
+ 	@echo '  vmlinux.srec	           - Create an ELF S-record'
+ 	@echo '  uImage  	           - Create a bootable image for U-Boot'
+ 	@echo '  uImage.srec  	           - Create an S-record for U-Boot'
+ endef
++
++define filechk_gen-syscalltab
++       (set -e; \
++	echo "/*"; \
++	echo " * DO NOT MODIFY."; \
++	echo " *"; \
++	echo " * This file was generated by arch/sh/Makefile"; \
++	echo " * Any changes will be reverted at build time."; \
++	echo " */"; \
++	echo ""; \
++	echo "#ifndef __SYSCALLTAB_H"; \
++	echo "#define __SYSCALLTAB_H"; \
++	echo ""; \
++	echo "#include <linux/kernel.h>"; \
++	echo ""; \
++	echo "struct syscall_info {"; \
++	echo "	const char *name;"; \
++	echo "} syscall_info_table[] = {"; \
++	sed -e '/^.*\.long /!d;s//	{ "/;s/\(\([^/]*\)\/\)\{1\}.*/\2/; \
++		s/[ \t]*$$//g;s/$$/" },/;s/\("\)sys_/\1/g'; \
++	echo "};"; \
++	echo ""; \
++	echo "#define NUM_SYSCALL_INFO_ENTRIES ARRAY_SIZE(syscall_info_table)";\
++	echo ""; \
++	echo "#endif /* __SYSCALLTAB_H */" )
++endef
++
++arch/sh/lib64/syscalltab.h: arch/sh/kernel/syscalls_64.S
++	$(call filechk,gen-syscalltab)
++
++CLEAN_FILES += arch/sh/lib64/syscalltab.h \
++	       include/asm-sh/machtypes.h \
++	       include/asm-sh/cpu include/asm-sh/.cpu \
++	       include/asm-sh/mach include/asm-sh/.mach
+diff --git a/arch/sh/boards/cayman/Makefile b/arch/sh/boards/cayman/Makefile
+new file mode 100644
+index 0000000..489a8f8
+--- /dev/null
++++ b/arch/sh/boards/cayman/Makefile
+@@ -0,0 +1,5 @@
++#
++# Makefile for the Hitachi Cayman specific parts of the kernel
++#
++obj-y := setup.o irq.o
++obj-$(CONFIG_HEARTBEAT)	+= led.o
+diff --git a/arch/sh/boards/cayman/irq.c b/arch/sh/boards/cayman/irq.c
+new file mode 100644
+index 0000000..30ec7be
+--- /dev/null
++++ b/arch/sh/boards/cayman/irq.c
+@@ -0,0 +1,197 @@
++/*
++ * arch/sh/mach-cayman/irq.c - SH-5 Cayman Interrupt Support
++ *
++ * This file handles the board specific parts of the Cayman interrupt system
++ *
++ * Copyright (C) 2002 Stuart Menefy
++ *
++ * 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/io.h>
++#include <linux/irq.h>
++#include <linux/interrupt.h>
++#include <linux/signal.h>
++#include <asm/cpu/irq.h>
++#include <asm/page.h>
++
++/* Setup for the SMSC FDC37C935 / LAN91C100FD */
++#define SMSC_IRQ         IRQ_IRL1
++
++/* Setup for PCI Bus 2, which transmits interrupts via the EPLD */
++#define PCI2_IRQ         IRQ_IRL3
++
++unsigned long epld_virt;
++
++#define EPLD_BASE        0x04002000
++#define EPLD_STATUS_BASE (epld_virt + 0x10)
++#define EPLD_MASK_BASE   (epld_virt + 0x20)
++
++/* Note the SMSC SuperIO chip and SMSC LAN chip interrupts are all muxed onto
++   the same SH-5 interrupt */
++
++static irqreturn_t cayman_interrupt_smsc(int irq, void *dev_id)
++{
++        printk(KERN_INFO "CAYMAN: spurious SMSC interrupt\n");
++	return IRQ_NONE;
++}
++
++static irqreturn_t cayman_interrupt_pci2(int irq, void *dev_id)
++{
++        printk(KERN_INFO "CAYMAN: spurious PCI interrupt, IRQ %d\n", irq);
++	return IRQ_NONE;
++}
++
++static struct irqaction cayman_action_smsc = {
++	.name		= "Cayman SMSC Mux",
++	.handler	= cayman_interrupt_smsc,
++	.flags		= IRQF_DISABLED,
++};
++
++static struct irqaction cayman_action_pci2 = {
++	.name		= "Cayman PCI2 Mux",
++	.handler	= cayman_interrupt_pci2,
++	.flags		= IRQF_DISABLED,
++};
++
++static void enable_cayman_irq(unsigned int irq)
++{
++	unsigned long flags;
++	unsigned long mask;
++	unsigned int reg;
++	unsigned char bit;
++
++	irq -= START_EXT_IRQS;
++	reg = EPLD_MASK_BASE + ((irq / 8) << 2);
++	bit = 1<<(irq % 8);
++	local_irq_save(flags);
++	mask = ctrl_inl(reg);
++	mask |= bit;
++	ctrl_outl(mask, reg);
++	local_irq_restore(flags);
++}
++
++void disable_cayman_irq(unsigned int irq)
++{
++	unsigned long flags;
++	unsigned long mask;
++	unsigned int reg;
++	unsigned char bit;
++
++	irq -= START_EXT_IRQS;
++	reg = EPLD_MASK_BASE + ((irq / 8) << 2);
++	bit = 1<<(irq % 8);
++	local_irq_save(flags);
++	mask = ctrl_inl(reg);
++	mask &= ~bit;
++	ctrl_outl(mask, reg);
++	local_irq_restore(flags);
++}
++
++static void ack_cayman_irq(unsigned int irq)
++{
++	disable_cayman_irq(irq);
++}
++
++static void end_cayman_irq(unsigned int irq)
++{
++	if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
++		enable_cayman_irq(irq);
++}
++
++static unsigned int startup_cayman_irq(unsigned int irq)
++{
++	enable_cayman_irq(irq);
++	return 0; /* never anything pending */
++}
++
++static void shutdown_cayman_irq(unsigned int irq)
++{
++	disable_cayman_irq(irq);
++}
++
++struct hw_interrupt_type cayman_irq_type = {
++	.typename	= "Cayman-IRQ",
++	.startup	= startup_cayman_irq,
++	.shutdown	= shutdown_cayman_irq,
++	.enable		= enable_cayman_irq,
++	.disable	= disable_cayman_irq,
++	.ack		= ack_cayman_irq,
++	.end		= end_cayman_irq,
++};
++
++int cayman_irq_demux(int evt)
++{
++	int irq = intc_evt_to_irq[evt];
++
++	if (irq == SMSC_IRQ) {
++		unsigned long status;
++		int i;
++
++		status = ctrl_inl(EPLD_STATUS_BASE) &
++			 ctrl_inl(EPLD_MASK_BASE) & 0xff;
++		if (status == 0) {
++			irq = -1;
++		} else {
++			for (i=0; i<8; i++) {
++				if (status & (1<<i))
++					break;
++			}
++			irq = START_EXT_IRQS + i;
++		}
++	}
++
++	if (irq == PCI2_IRQ) {
++		unsigned long status;
++		int i;
++
++		status = ctrl_inl(EPLD_STATUS_BASE + 3 * sizeof(u32)) &
++			 ctrl_inl(EPLD_MASK_BASE + 3 * sizeof(u32)) & 0xff;
++		if (status == 0) {
++			irq = -1;
++		} else {
++			for (i=0; i<8; i++) {
++				if (status & (1<<i))
++					break;
++			}
++			irq = START_EXT_IRQS + (3 * 8) + i;
++		}
++	}
++
++	return irq;
++}
++
++#if defined(CONFIG_PROC_FS) && defined(CONFIG_SYSCTL)
++int cayman_irq_describe(char* p, int irq)
++{
++	if (irq < NR_INTC_IRQS) {
++		return intc_irq_describe(p, irq);
++	} else if (irq < NR_INTC_IRQS + 8) {
++		return sprintf(p, "(SMSC %d)", irq - NR_INTC_IRQS);
++	} else if ((irq >= NR_INTC_IRQS + 24) && (irq < NR_INTC_IRQS + 32)) {
++		return sprintf(p, "(PCI2 %d)", irq - (NR_INTC_IRQS + 24));
++	}
++
++	return 0;
++}
++#endif
++
++void init_cayman_irq(void)
++{
++	int i;
++
++	epld_virt = onchip_remap(EPLD_BASE, 1024, "EPLD");
++	if (!epld_virt) {
++		printk(KERN_ERR "Cayman IRQ: Unable to remap EPLD\n");
++		return;
++	}
++
++	for (i=0; i<NR_EXT_IRQS; i++) {
++		irq_desc[START_EXT_IRQS + i].chip = &cayman_irq_type;
++	}
++
++	/* Setup the SMSC interrupt */
++	setup_irq(SMSC_IRQ, &cayman_action_smsc);
++	setup_irq(PCI2_IRQ, &cayman_action_pci2);
++}
+diff --git a/arch/sh/boards/cayman/led.c b/arch/sh/boards/cayman/led.c
+new file mode 100644
+index 0000000..a808eac
+--- /dev/null
++++ b/arch/sh/boards/cayman/led.c
+@@ -0,0 +1,51 @@
++/*
++ * arch/sh/boards/cayman/led.c
++ *
++ * Copyright (C) 2002 Stuart Menefy <stuart.menefy at st.com>
++ *
++ * May be copied or modified under the terms of the GNU General Public
++ * License.  See linux/COPYING for more information.
++ *
++ * Flash the LEDs
++ */
++#include <asm/io.h>
++
++/*
++** It is supposed these functions to be used for a low level
++** debugging (via Cayman LEDs), hence to be available as soon
++** as possible.
++** Unfortunately Cayman LEDs relies on Cayman EPLD to be mapped
++** (this happen when IRQ are initialized... quite late).
++** These triky dependencies should be removed. Temporary, it
++** may be enough to NOP until EPLD is mapped.
++*/
++
++extern unsigned long epld_virt;
++
++#define LED_ADDR      (epld_virt + 0x008)
++#define HDSP2534_ADDR (epld_virt + 0x100)
++
++void mach_led(int position, int value)
++{
++	if (!epld_virt)
++		return;
++
++	if (value)
++		ctrl_outl(0, LED_ADDR);
++	else
++		ctrl_outl(1, LED_ADDR);
++
++}
++
++void mach_alphanum(int position, unsigned char value)
++{
++	if (!epld_virt)
++		return;
++
++	ctrl_outb(value, HDSP2534_ADDR + 0xe0 + (position << 2));
++}
++
++void mach_alphanum_brightness(int setting)
++{
++	ctrl_outb(setting & 7, HDSP2534_ADDR + 0xc0);
++}
+diff --git a/arch/sh/boards/cayman/setup.c b/arch/sh/boards/cayman/setup.c
+new file mode 100644
+index 0000000..8c9fa47
+--- /dev/null
++++ b/arch/sh/boards/cayman/setup.c
+@@ -0,0 +1,187 @@
++/*
++ * arch/sh/mach-cayman/setup.c
++ *
++ * SH5 Cayman support
++ *
++ * Copyright (C) 2002  David J. Mckay & Benedict Gaster
++ * Copyright (C) 2003 - 2007  Paul Mundt
++ *
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License.  See the file "COPYING" in the main directory of this archive
++ * for more details.
++ */
++#include <linux/init.h>
++#include <linux/io.h>
++#include <linux/kernel.h>
++#include <asm/cpu/irq.h>
++
++/*
++ * Platform Dependent Interrupt Priorities.
++ */
++
++/* Using defaults defined in irq.h */
++#define	RES NO_PRIORITY		/* Disabled */
++#define IR0 IRL0_PRIORITY	/* IRLs */
++#define IR1 IRL1_PRIORITY
++#define IR2 IRL2_PRIORITY
++#define IR3 IRL3_PRIORITY
++#define PCA INTA_PRIORITY	/* PCI Ints */
++#define PCB INTB_PRIORITY
++#define PCC INTC_PRIORITY
++#define PCD INTD_PRIORITY
++#define SER TOP_PRIORITY
++#define ERR TOP_PRIORITY
++#define PW0 TOP_PRIORITY
++#define PW1 TOP_PRIORITY
++#define PW2 TOP_PRIORITY
++#define PW3 TOP_PRIORITY
++#define DM0 NO_PRIORITY		/* DMA Ints */
++#define DM1 NO_PRIORITY
++#define DM2 NO_PRIORITY
++#define DM3 NO_PRIORITY
++#define DAE NO_PRIORITY
++#define TU0 TIMER_PRIORITY	/* TMU Ints */
++#define TU1 NO_PRIORITY
++#define TU2 NO_PRIORITY
++#define TI2 NO_PRIORITY
++#define ATI NO_PRIORITY		/* RTC Ints */
++#define PRI NO_PRIORITY
++#define CUI RTC_PRIORITY
++#define ERI SCIF_PRIORITY	/* SCIF Ints */
++#define RXI SCIF_PRIORITY
++#define BRI SCIF_PRIORITY
++#define TXI SCIF_PRIORITY
++#define ITI TOP_PRIORITY	/* WDT Ints */
++
++/* Setup for the SMSC FDC37C935 */
++#define SMSC_SUPERIO_BASE	0x04000000
++#define SMSC_CONFIG_PORT_ADDR	0x3f0
++#define SMSC_INDEX_PORT_ADDR	SMSC_CONFIG_PORT_ADDR
++#define SMSC_DATA_PORT_ADDR	0x3f1
++
++#define SMSC_ENTER_CONFIG_KEY	0x55
++#define SMSC_EXIT_CONFIG_KEY	0xaa
++
++#define SMCS_LOGICAL_DEV_INDEX	0x07
++#define SMSC_DEVICE_ID_INDEX	0x20
++#define SMSC_DEVICE_REV_INDEX	0x21
++#define SMSC_ACTIVATE_INDEX	0x30
++#define SMSC_PRIMARY_BASE_INDEX  0x60
++#define SMSC_SECONDARY_BASE_INDEX 0x62
++#define SMSC_PRIMARY_INT_INDEX	0x70
++#define SMSC_SECONDARY_INT_INDEX 0x72
++
++#define SMSC_IDE1_DEVICE	1
++#define SMSC_KEYBOARD_DEVICE	7
++#define SMSC_CONFIG_REGISTERS	8
++
++#define SMSC_SUPERIO_READ_INDEXED(index) ({ \
++	outb((index), SMSC_INDEX_PORT_ADDR); \
++	inb(SMSC_DATA_PORT_ADDR); })
++#define SMSC_SUPERIO_WRITE_INDEXED(val, index) ({ \
++	outb((index), SMSC_INDEX_PORT_ADDR); \
++	outb((val),   SMSC_DATA_PORT_ADDR); })
++
++#define IDE1_PRIMARY_BASE	0x01f0
++#define IDE1_SECONDARY_BASE	0x03f6
++
++unsigned long smsc_superio_virt;
++
++int platform_int_priority[NR_INTC_IRQS] = {
++	IR0, IR1, IR2, IR3, PCA, PCB, PCC, PCD,	/* IRQ  0- 7 */
++	RES, RES, RES, RES, SER, ERR, PW3, PW2,	/* IRQ  8-15 */
++	PW1, PW0, DM0, DM1, DM2, DM3, DAE, RES,	/* IRQ 16-23 */
++	RES, RES, RES, RES, RES, RES, RES, RES,	/* IRQ 24-31 */
++	TU0, TU1, TU2, TI2, ATI, PRI, CUI, ERI,	/* IRQ 32-39 */
++	RXI, BRI, TXI, RES, RES, RES, RES, RES,	/* IRQ 40-47 */
++	RES, RES, RES, RES, RES, RES, RES, RES,	/* IRQ 48-55 */
++	RES, RES, RES, RES, RES, RES, RES, ITI,	/* IRQ 56-63 */
++};
++
++static int __init smsc_superio_setup(void)
++{
++	unsigned char devid, devrev;
++
++	smsc_superio_virt = onchip_remap(SMSC_SUPERIO_BASE, 1024, "SMSC SuperIO");
++	if (!smsc_superio_virt) {
++		panic("Unable to remap SMSC SuperIO\n");
++	}
++
++	/* Initially the chip is in run state */
++	/* Put it into configuration state */
++	outb(SMSC_ENTER_CONFIG_KEY, SMSC_CONFIG_PORT_ADDR);
++	outb(SMSC_ENTER_CONFIG_KEY, SMSC_CONFIG_PORT_ADDR);
++
++	/* Read device ID info */
++	devid = SMSC_SUPERIO_READ_INDEXED(SMSC_DEVICE_ID_INDEX);
++	devrev = SMSC_SUPERIO_READ_INDEXED(SMSC_DEVICE_REV_INDEX);
++	printk("SMSC SuperIO devid %02x rev %02x\n", devid, devrev);
++
++	/* Select the keyboard device */
++	SMSC_SUPERIO_WRITE_INDEXED(SMSC_KEYBOARD_DEVICE, SMCS_LOGICAL_DEV_INDEX);
++
++	/* enable it */
++	SMSC_SUPERIO_WRITE_INDEXED(1, SMSC_ACTIVATE_INDEX);
++
++	/* Select the interrupts */
++	/* On a PC keyboard is IRQ1, mouse is IRQ12 */
++	SMSC_SUPERIO_WRITE_INDEXED(1, SMSC_PRIMARY_INT_INDEX);
++	SMSC_SUPERIO_WRITE_INDEXED(12, SMSC_SECONDARY_INT_INDEX);
++
++#ifdef CONFIG_IDE
++	/*
++	 * Only IDE1 exists on the Cayman
++	 */
++
++	/* Power it on */
++	SMSC_SUPERIO_WRITE_INDEXED(1 << SMSC_IDE1_DEVICE, 0x22);
++
++	SMSC_SUPERIO_WRITE_INDEXED(SMSC_IDE1_DEVICE, SMCS_LOGICAL_DEV_INDEX);
++	SMSC_SUPERIO_WRITE_INDEXED(1, SMSC_ACTIVATE_INDEX);
++
++	SMSC_SUPERIO_WRITE_INDEXED(IDE1_PRIMARY_BASE >> 8,
++				   SMSC_PRIMARY_BASE_INDEX + 0);
++	SMSC_SUPERIO_WRITE_INDEXED(IDE1_PRIMARY_BASE & 0xff,
++				   SMSC_PRIMARY_BASE_INDEX + 1);
++
++	SMSC_SUPERIO_WRITE_INDEXED(IDE1_SECONDARY_BASE >> 8,
++				   SMSC_SECONDARY_BASE_INDEX + 0);
++	SMSC_SUPERIO_WRITE_INDEXED(IDE1_SECONDARY_BASE & 0xff,
++				   SMSC_SECONDARY_BASE_INDEX + 1);
++
++	SMSC_SUPERIO_WRITE_INDEXED(14, SMSC_PRIMARY_INT_INDEX);
++
++	SMSC_SUPERIO_WRITE_INDEXED(SMSC_CONFIG_REGISTERS,
++				   SMCS_LOGICAL_DEV_INDEX);
++
++	SMSC_SUPERIO_WRITE_INDEXED(0x00, 0xc2); /* GP42 = nIDE1_OE */
++	SMSC_SUPERIO_WRITE_INDEXED(0x01, 0xc5); /* GP45 = IDE1_IRQ */
++	SMSC_SUPERIO_WRITE_INDEXED(0x00, 0xc6); /* GP46 = nIOROP */
++	SMSC_SUPERIO_WRITE_INDEXED(0x00, 0xc7); /* GP47 = nIOWOP */
++#endif
++
++	/* Exit the configuration state */
++	outb(SMSC_EXIT_CONFIG_KEY, SMSC_CONFIG_PORT_ADDR);
++
++	return 0;
++}
++__initcall(smsc_superio_setup);
++
++static void __iomem *cayman_ioport_map(unsigned long port, unsigned int len)
++{
++	if (port < 0x400) {
++		extern unsigned long smsc_superio_virt;
++		return (void __iomem *)((port << 2) | smsc_superio_virt);
++	}
++
++	return (void __iomem *)port;
++}
++
++extern void init_cayman_irq(void);
++
++static struct sh_machine_vector mv_cayman __initmv = {
++	.mv_name		= "Hitachi Cayman",
++	.mv_nr_irqs		= 64,
++	.mv_ioport_map		= cayman_ioport_map,
++	.mv_init_irq		= init_cayman_irq,
++};
+diff --git a/arch/sh/boards/dreamcast/irq.c b/arch/sh/boards/dreamcast/irq.c
+index 5bf01f8..9d0673a 100644
+--- a/arch/sh/boards/dreamcast/irq.c
++++ b/arch/sh/boards/dreamcast/irq.c
+@@ -136,7 +136,7 @@ int systemasic_irq_demux(int irq)
+         emr = EMR_BASE + (level << 4) + (level << 2);
+         esr = ESR_BASE + (level << 2);
+ 
+-        /* Mask the ESR to filter any spurious, unwanted interrtupts */
++        /* Mask the ESR to filter any spurious, unwanted interrupts */
+         status = inl(esr);
+         status &= inl(emr);
+ 
+diff --git a/arch/sh/boards/dreamcast/setup.c b/arch/sh/boards/dreamcast/setup.c
+index 8799df6..2581c8c 100644
+--- a/arch/sh/boards/dreamcast/setup.c
++++ b/arch/sh/boards/dreamcast/setup.c
+@@ -33,9 +33,6 @@ extern void aica_time_init(void);
+ extern int gapspci_init(void);
+ extern int systemasic_irq_demux(int);
+ 
+-void *dreamcast_consistent_alloc(struct device *, size_t, dma_addr_t *, gfp_t);
+-int dreamcast_consistent_free(struct device *, size_t, void *, dma_addr_t);
+-
+ static void __init dreamcast_setup(char **cmdline_p)
+ {
+ 	int i;
+@@ -64,9 +61,4 @@ static struct sh_machine_vector mv_dreamcast __initmv = {
+ 	.mv_name		= "Sega Dreamcast",
+ 	.mv_setup		= dreamcast_setup,
+ 	.mv_irq_demux		= systemasic_irq_demux,
+-
+-#ifdef CONFIG_PCI
+-	.mv_consistent_alloc	= dreamcast_consistent_alloc,
+-	.mv_consistent_free	= dreamcast_consistent_free,
+-#endif
+ };
+diff --git a/arch/sh/boards/landisk/gio.c b/arch/sh/boards/landisk/gio.c
+index a37643d..1702508 100644
+--- a/arch/sh/boards/landisk/gio.c
++++ b/arch/sh/boards/landisk/gio.c
+@@ -121,7 +121,7 @@ static int gio_ioctl(struct inode *inode, struct file *filp,
+ 	return 0;
+ }
+ 
+-static struct file_operations gio_fops = {
++static const struct file_operations gio_fops = {
+ 	.owner = THIS_MODULE,
+ 	.open = gio_open,	/* open */
+ 	.release = gio_close,	/* release */
+diff --git a/arch/sh/boards/renesas/hs7751rvoip/Kconfig b/arch/sh/boards/renesas/hs7751rvoip/Kconfig
+deleted file mode 100644
+index 1743be4..0000000
+--- a/arch/sh/boards/renesas/hs7751rvoip/Kconfig
++++ /dev/null
+@@ -1,12 +0,0 @@
+-if SH_HS7751RVOIP
+-
+-menu "HS7751RVoIP options"
+-
+-config HS7751RVOIP_CODEC
+-	bool "Support VoIP Codec section"
+-	help
+-	  Selecting this option will support CODEC section.
+-
+-endmenu
+-
+-endif
+diff --git a/arch/sh/boards/renesas/hs7751rvoip/Makefile b/arch/sh/boards/renesas/hs7751rvoip/Makefile
+deleted file mode 100644
+index e626377..0000000
+--- a/arch/sh/boards/renesas/hs7751rvoip/Makefile
++++ /dev/null
+@@ -1,8 +0,0 @@
+-#
+-# Makefile for the HS7751RVoIP specific parts of the kernel
+-#
+-
+-obj-y	 := setup.o io.o irq.o
+-
+-obj-$(CONFIG_PCI) += pci.o
+-
+diff --git a/arch/sh/boards/renesas/hs7751rvoip/io.c b/arch/sh/boards/renesas/hs7751rvoip/io.c
+deleted file mode 100644
+index bb9aa0d..0000000
+--- a/arch/sh/boards/renesas/hs7751rvoip/io.c
++++ /dev/null
+@@ -1,283 +0,0 @@
+-/*
+- * linux/arch/sh/boards/renesas/hs7751rvoip/io.c
+- *
+- * Copyright (C) 2001  Ian da Silva, Jeremy Siegel
+- * Based largely on io_se.c.
+- *
+- * I/O routine for Renesas Technology sales HS7751RVoIP
+- *
+- * Initial version only to support LAN access; some
+- * placeholder code from io_hs7751rvoip.c left in with the
+- * expectation of later SuperIO and PCMCIA access.
+- */
+-#include <linux/kernel.h>
+-#include <linux/types.h>
+-#include <linux/module.h>
+-#include <linux/pci.h>
+-#include <asm/io.h>
+-#include <asm/hs7751rvoip.h>
+-#include <asm/addrspace.h>
+-
+-extern void *area6_io8_base;	/* Area 6 8bit I/O Base address */
+-extern void *area5_io16_base;	/* Area 5 16bit I/O Base address */
+-
+-/*
+- * The 7751R HS7751RVoIP uses the built-in PCI controller (PCIC)
+- * of the 7751R processor, and has a SuperIO accessible via the PCI.
+- * The board also includes a PCMCIA controller on its memory bus,
+- * like the other Solution Engine boards.
+- */
+-
+-#define CODEC_IO_BASE	0x1000
+-#define CODEC_IOMAP(a)	((unsigned long)area6_io8_base + ((a) - CODEC_IO_BASE))
+-
+-static inline unsigned long port2adr(unsigned int port)
+-{
+-	if ((0x1f0 <= port && port < 0x1f8) || port == 0x3f6)
+-		if (port == 0x3f6)
+-			return ((unsigned long)area5_io16_base + 0x0c);
+-		else
+-			return ((unsigned long)area5_io16_base + 0x800 +
+-				((port-0x1f0) << 1));
+-	else
+-		maybebadio((unsigned long)port);
+-	return port;
+-}
+-
+-/* The 7751R HS7751RVoIP seems to have everything hooked */
+-/* up pretty normally (nothing on high-bytes only...) so this */
+-/* shouldn't be needed */
+-static inline int shifted_port(unsigned long port)
+-{
+-	/* For IDE registers, value is not shifted */
+-	if ((0x1f0 <= port && port < 0x1f8) || port == 0x3f6)
+-		return 0;
+-	else
+-		return 1;
+-}
+-
+-#if defined(CONFIG_HS7751RVOIP_CODEC)
+-#define codec_port(port)	\
+-	((CODEC_IO_BASE <= (port)) && ((port) < (CODEC_IO_BASE + 0x20)))
+-#else
+-#define codec_port(port)	(0)
+-#endif
+-
+-/*
+- * General outline: remap really low stuff [eventually] to SuperIO,
+- * stuff in PCI IO space (at or above window at pci.h:PCIBIOS_MIN_IO)
+- * is mapped through the PCI IO window.  Stuff with high bits (PXSEG)
+- * should be way beyond the window, and is used  w/o translation for
+- * compatibility.
+- */
+-unsigned char hs7751rvoip_inb(unsigned long port)
+-{
+-	if (PXSEG(port))
+-		return ctrl_inb(port);
+-	else if (codec_port(port))
+-		return ctrl_inb(CODEC_IOMAP(port));
+-	else if (is_pci_ioaddr(port) || shifted_port(port))
+-		return ctrl_inb(pci_ioaddr(port));
+-	else
+-		return ctrl_inw(port2adr(port)) & 0xff;
+-}
+-
+-unsigned char hs7751rvoip_inb_p(unsigned long port)
+-{
+-	unsigned char v;
+-
+-        if (PXSEG(port))
+-		v = ctrl_inb(port);
+-	else if (codec_port(port))
+-		v = ctrl_inb(CODEC_IOMAP(port));
+-	else if (is_pci_ioaddr(port) || shifted_port(port))
+-		v = ctrl_inb(pci_ioaddr(port));
+-	else
+-		v = ctrl_inw(port2adr(port)) & 0xff;
+-	ctrl_delay();
+-	return v;
+-}
+-
+-unsigned short hs7751rvoip_inw(unsigned long port)
+-{
+-        if (PXSEG(port))
+-		return ctrl_inw(port);
+-	else if (is_pci_ioaddr(port) || shifted_port(port))
+-		return ctrl_inw(pci_ioaddr(port));
+-	else
+-		maybebadio(port);
+-	return 0;
+-}
+-
+-unsigned int hs7751rvoip_inl(unsigned long port)
+-{
+-        if (PXSEG(port))
+-		return ctrl_inl(port);
+-	else if (is_pci_ioaddr(port) || shifted_port(port))
+-		return ctrl_inl(pci_ioaddr(port));
+-	else
+-		maybebadio(port);
+-	return 0;
+-}
+-
+-void hs7751rvoip_outb(unsigned char value, unsigned long port)
+-{
+-
+-        if (PXSEG(port))
+-		ctrl_outb(value, port);
+-	else if (codec_port(port))
+-		ctrl_outb(value, CODEC_IOMAP(port));
+-	else if (is_pci_ioaddr(port) || shifted_port(port))
+-		ctrl_outb(value, pci_ioaddr(port));
+-	else
+-		ctrl_outb(value, port2adr(port));
+-}
+-
+-void hs7751rvoip_outb_p(unsigned char value, unsigned long port)
+-{
+-        if (PXSEG(port))
+-		ctrl_outb(value, port);
+-	else if (codec_port(port))
+-		ctrl_outb(value, CODEC_IOMAP(port));
+-	else if (is_pci_ioaddr(port) || shifted_port(port))
+-		ctrl_outb(value, pci_ioaddr(port));
+-	else
+-		ctrl_outw(value, port2adr(port));
+-
+-	ctrl_delay();
+-}
+-
+-void hs7751rvoip_outw(unsigned short value, unsigned long port)
+-{
+-        if (PXSEG(port))
+-		ctrl_outw(value, port);
+-	else if (is_pci_ioaddr(port) || shifted_port(port))
+-		ctrl_outw(value, pci_ioaddr(port));
+-	else
+-		maybebadio(port);
+-}
+-
+-void hs7751rvoip_outl(unsigned int value, unsigned long port)
+-{
+-        if (PXSEG(port))
+-		ctrl_outl(value, port);
+-	else if (is_pci_ioaddr(port) || shifted_port(port))
+-		ctrl_outl(value, pci_ioaddr(port));
+-	else
+-		maybebadio(port);
+-}
+-
+-void hs7751rvoip_insb(unsigned long port, void *addr, unsigned long count)
+-{
+-	u8 *buf = addr;
+-
+-	if (PXSEG(port))
+-		while (count--)
+-			*buf++ = ctrl_inb(port);
+-	else if (codec_port(port))
+-		while (count--)
+-			*buf++ = ctrl_inb(CODEC_IOMAP(port));
+-	else if (is_pci_ioaddr(port) || shifted_port(port)) {
+-		volatile u8 *bp = (volatile u8 *)pci_ioaddr(port);
+-
+-		while (count--)
+-			*buf++ = *bp;
+-	} else {
+-		volatile u16 *p = (volatile u16 *)port2adr(port);
+-
+-		while (count--)
+-			*buf++ = *p & 0xff;
+-	}
+-}
+-
+-void hs7751rvoip_insw(unsigned long port, void *addr, unsigned long count)
+-{
+-	volatile u16 *p;
+-	u16 *buf = addr;
+-
+-	if (PXSEG(port))
+-		p = (volatile u16 *)port;
+-	else if (is_pci_ioaddr(port) || shifted_port(port))
+-		p = (volatile u16 *)pci_ioaddr(port);
+-	else
+-		p = (volatile u16 *)port2adr(port);
+-	while (count--)
+-		*buf++ = *p;
+-}
+-
+-void hs7751rvoip_insl(unsigned long port, void *addr, unsigned long count)
+-{
+-
+-	if (is_pci_ioaddr(port) || shifted_port(port)) {
+-		volatile u32 *p = (volatile u32 *)pci_ioaddr(port);
+-		u32 *buf = addr;
+-
+-		while (count--)
+-			*buf++ = *p;
+-	} else
+-		maybebadio(port);
+-}
+-
+-void hs7751rvoip_outsb(unsigned long port, const void *addr, unsigned long count)
+-{
+-	const u8 *buf = addr;
+-
+-	if (PXSEG(port))
+-		while (count--)
+-			ctrl_outb(*buf++, port);
+-	else if (codec_port(port))
+-		while (count--)
+-			ctrl_outb(*buf++, CODEC_IOMAP(port));
+-	else if (is_pci_ioaddr(port) || shifted_port(port)) {
+-		volatile u8 *bp = (volatile u8 *)pci_ioaddr(port);
+-
+-		while (count--)
+-			*bp = *buf++;
+-	} else {
+-		volatile u16 *p = (volatile u16 *)port2adr(port);
+-
+-		while (count--)
+-			*p = *buf++;
+-	}
+-}
+-
+-void hs7751rvoip_outsw(unsigned long port, const void *addr, unsigned long count)
+-{
+-	volatile u16 *p;
+-	const u16 *buf = addr;
+-
+-	if (PXSEG(port))
+-		p = (volatile u16 *)port;
+-	else if (is_pci_ioaddr(port) || shifted_port(port))
+-		p = (volatile u16 *)pci_ioaddr(port);
+-	else
+-		p = (volatile u16 *)port2adr(port);
+-
+-	while (count--)
+-		*p = *buf++;
+-}
+-
+-void hs7751rvoip_outsl(unsigned long port, const void *addr, unsigned long count)
+-{
+-	const u32 *buf = addr;
+-
+-	if (is_pci_ioaddr(port) || shifted_port(port)) {
+-		volatile u32 *p = (volatile u32 *)pci_ioaddr(port);
+-
+-		while (count--)
+-			*p = *buf++;
+-	} else
+-		maybebadio(port);
+-}
+-
+-void __iomem *hs7751rvoip_ioport_map(unsigned long port, unsigned int size)
+-{
+-        if (PXSEG(port))
+-                return (void __iomem *)port;
+-	else if (unlikely(codec_port(port) && (size == 1)))
+-		return (void __iomem *)CODEC_IOMAP(port);
+-        else if (is_pci_ioaddr(port))
+-                return (void __iomem *)pci_ioaddr(port);
+-
+-        return (void __iomem *)port2adr(port);
+-}
+diff --git a/arch/sh/boards/renesas/hs7751rvoip/irq.c b/arch/sh/boards/renesas/hs7751rvoip/irq.c
+deleted file mode 100644
+index e55c668..0000000
+--- a/arch/sh/boards/renesas/hs7751rvoip/irq.c
++++ /dev/null
+@@ -1,116 +0,0 @@
+-/*
+- * linux/arch/sh/boards/renesas/hs7751rvoip/irq.c
+- *
+- * Copyright (C) 2000  Kazumoto Kojima
+- *
+- * Renesas Technology Sales HS7751RVoIP Support.
+- *
+- * Modified for HS7751RVoIP by
+- * Atom Create Engineering Co., Ltd. 2002.
+- * Lineo uSolutions, Inc. 2003.
+- */
+-
+-#include <linux/init.h>
+-#include <linux/irq.h>
+-#include <linux/interrupt.h>
+-#include <asm/io.h>
+-#include <asm/irq.h>
+-#include <asm/hs7751rvoip.h>
+-
+-static int mask_pos[] = {8, 9, 10, 11, 12, 13, 0, 1, 2, 3, 4, 5, 6, 7};
+-
+-static void enable_hs7751rvoip_irq(unsigned int irq);
+-static void disable_hs7751rvoip_irq(unsigned int irq);
+-
+-/* shutdown is same as "disable" */
+-#define shutdown_hs7751rvoip_irq disable_hs7751rvoip_irq
+-
+-static void ack_hs7751rvoip_irq(unsigned int irq);
+-static void end_hs7751rvoip_irq(unsigned int irq);
+-
+-static unsigned int startup_hs7751rvoip_irq(unsigned int irq)
+-{
+-	enable_hs7751rvoip_irq(irq);
+-	return 0; /* never anything pending */
+-}
+-
+-static void disable_hs7751rvoip_irq(unsigned int irq)
+-{
+-	unsigned short val;
+-	unsigned short mask = 0xffff ^ (0x0001 << mask_pos[irq]);
+-
+-	/* Set the priority in IPR to 0 */
+-	val = ctrl_inw(IRLCNTR3);
+-	val &= mask;
+-	ctrl_outw(val, IRLCNTR3);
+-}
+-
+-static void enable_hs7751rvoip_irq(unsigned int irq)
+-{
+-	unsigned short val;
+-	unsigned short value = (0x0001 << mask_pos[irq]);
+-
+-	/* Set priority in IPR back to original value */
+-	val = ctrl_inw(IRLCNTR3);
+-	val |= value;
+-	ctrl_outw(val, IRLCNTR3);
+-}
+-
+-static void ack_hs7751rvoip_irq(unsigned int irq)
+-{
+-	disable_hs7751rvoip_irq(irq);
+-}
+-
+-static void end_hs7751rvoip_irq(unsigned int irq)
+-{
+-	if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
+-		enable_hs7751rvoip_irq(irq);
+-}
+-
+-static struct hw_interrupt_type hs7751rvoip_irq_type = {
+-	.typename =  "HS7751RVoIP IRQ",
+-	.startup = startup_hs7751rvoip_irq,
+-	.shutdown = shutdown_hs7751rvoip_irq,
+-	.enable = enable_hs7751rvoip_irq,
+-	.disable = disable_hs7751rvoip_irq,
+-	.ack = ack_hs7751rvoip_irq,
+-	.end = end_hs7751rvoip_irq,
+-};
+-
+-static void make_hs7751rvoip_irq(unsigned int irq)
+-{
+-	disable_irq_nosync(irq);
+-	irq_desc[irq].chip = &hs7751rvoip_irq_type;
+-	disable_hs7751rvoip_irq(irq);
+-}
+-
+-/*
+- * Initialize IRQ setting
+- */
+-void __init init_hs7751rvoip_IRQ(void)
+-{
+-	int i;
+-
+-	/* IRL0=ON HOOK1
+-	 * IRL1=OFF HOOK1
+-	 * IRL2=ON HOOK2
+-	 * IRL3=OFF HOOK2
+-	 * IRL4=Ringing Detection
+-	 * IRL5=CODEC
+-	 * IRL6=Ethernet
+-	 * IRL7=Ethernet Hub
+-	 * IRL8=USB Communication
+-	 * IRL9=USB Connection
+-	 * IRL10=USB DMA
+-	 * IRL11=CF Card
+-	 * IRL12=PCMCIA
+-	 * IRL13=PCI Slot
+-	 */
+-	ctrl_outw(0x9876, IRLCNTR1);
+-	ctrl_outw(0xdcba, IRLCNTR2);
+-	ctrl_outw(0x0050, IRLCNTR4);
+-	ctrl_outw(0x4321, IRLCNTR5);
+-
+-	for (i=0; i<14; i++)
+-		make_hs7751rvoip_irq(i);
+-}
+diff --git a/arch/sh/boards/renesas/hs7751rvoip/pci.c b/arch/sh/boards/renesas/hs7751rvoip/pci.c
+deleted file mode 100644
+index 1c0ddee..0000000
+--- a/arch/sh/boards/renesas/hs7751rvoip/pci.c
++++ /dev/null
+@@ -1,149 +0,0 @@
+-/*
+- * linux/arch/sh/boards/renesas/hs7751rvoip/pci.c
+- *
+- * Author:  Ian DaSilva (idasilva at mvista.com)
+- *
+- * Highly leveraged from pci-bigsur.c, written by Dustin McIntire.
+- *
+- * May be copied or modified under the terms of the GNU General Public
+- * License.  See linux/COPYING for more information.
+- *
+- * PCI initialization for the Renesas SH7751R HS7751RVoIP board
+- */
+-
+-#include <linux/kernel.h>
+-#include <linux/types.h>
+-#include <linux/init.h>
+-#include <linux/delay.h>
+-#include <linux/pci.h>
+-#include <linux/module.h>
+-
+-#include <asm/io.h>
+-#include "../../../drivers/pci/pci-sh7751.h"
+-#include <asm/hs7751rvoip/hs7751rvoip.h>
+-
+-#define PCIMCR_MRSET_OFF	0xBFFFFFFF
+-#define PCIMCR_RFSH_OFF		0xFFFFFFFB
+-
+-/*
+- * Only long word accesses of the PCIC's internal local registers and the
+- * configuration registers from the CPU is supported.
+- */
+-#define PCIC_WRITE(x,v) writel((v), PCI_REG(x))
+-#define PCIC_READ(x) readl(PCI_REG(x))
+-
+-/*
+- * Description:  This function sets up and initializes the pcic, sets
+- * up the BARS, maps the DRAM into the address space etc, etc.
+- */
+-int __init pcibios_init_platform(void)
+-{
+-	unsigned long bcr1, wcr1, wcr2, wcr3, mcr;
+-	unsigned short bcr2, bcr3;
+-
+-	/*
+-	 * Initialize the slave bus controller on the pcic.  The values used
+-	 * here should not be hardcoded, but they should be taken from the bsc
+-	 * on the processor, to make this function as generic as possible.
+-	 * (i.e. Another sbc may usr different SDRAM timing settings -- in order
+-	 * for the pcic to work, its settings need to be exactly the same.)
+-	 */
+-	bcr1 = (*(volatile unsigned long *)(SH7751_BCR1));
+-	bcr2 = (*(volatile unsigned short *)(SH7751_BCR2));
+-	bcr3 = (*(volatile unsigned short *)(SH7751_BCR3));
+-	wcr1 = (*(volatile unsigned long *)(SH7751_WCR1));
+-	wcr2 = (*(volatile unsigned long *)(SH7751_WCR2));
+-	wcr3 = (*(volatile unsigned long *)(SH7751_WCR3));
+-	mcr = (*(volatile unsigned long *)(SH7751_MCR));
+-
+-	bcr1 = bcr1 | 0x00080000;  /* Enable Bit 19, BREQEN */
+-	(*(volatile unsigned long *)(SH7751_BCR1)) = bcr1;
+-
+-	bcr1 = bcr1 | 0x40080000;  /* Enable Bit 19 BREQEN, set PCIC to slave */
+-	PCIC_WRITE(SH7751_PCIBCR1, bcr1);	/* PCIC BCR1 */
+-	PCIC_WRITE(SH7751_PCIBCR2, bcr2);	/* PCIC BCR2 */
+-	PCIC_WRITE(SH7751_PCIBCR3, bcr3);	/* PCIC BCR3 */
+-	PCIC_WRITE(SH7751_PCIWCR1, wcr1);	/* PCIC WCR1 */
+-	PCIC_WRITE(SH7751_PCIWCR2, wcr2);	/* PCIC WCR2 */
+-	PCIC_WRITE(SH7751_PCIWCR3, wcr3);	/* PCIC WCR3 */
+-	mcr = (mcr & PCIMCR_MRSET_OFF) & PCIMCR_RFSH_OFF;
+-	PCIC_WRITE(SH7751_PCIMCR, mcr);		/* PCIC MCR */
+-
+-	/* Enable all interrupts, so we know what to fix */
+-	PCIC_WRITE(SH7751_PCIINTM, 0x0000c3ff);
+-	PCIC_WRITE(SH7751_PCIAINTM, 0x0000380f);
+-
+-	/* Set up standard PCI config registers */
+-	PCIC_WRITE(SH7751_PCICONF1, 0xFB900047); /* Bus Master, Mem & I/O access */
+-	PCIC_WRITE(SH7751_PCICONF2, 0x00000000); /* PCI Class code & Revision ID */
+-	PCIC_WRITE(SH7751_PCICONF4, 0xab000001); /* PCI I/O address (local regs) */
+-	PCIC_WRITE(SH7751_PCICONF5, 0x0c000000); /* PCI MEM address (local RAM)  */
+-	PCIC_WRITE(SH7751_PCICONF6, 0xd0000000); /* PCI MEM address (unused) */
+-	PCIC_WRITE(SH7751_PCICONF11, 0x35051054); /* PCI Subsystem ID & Vendor ID */
+-	PCIC_WRITE(SH7751_PCILSR0, 0x03f00000);	/* MEM (full 64M exposed) */
+-	PCIC_WRITE(SH7751_PCILSR1, 0x00000000); /* MEM (unused) */
+-	PCIC_WRITE(SH7751_PCILAR0, 0x0c000000); /* MEM (direct map from PCI) */
+-	PCIC_WRITE(SH7751_PCILAR1, 0x00000000); /* MEM (unused) */
+-
+-	/* Now turn it on... */
+-	PCIC_WRITE(SH7751_PCICR, 0xa5000001);
+-
+-	/*
+-	 * Set PCIMBR and PCIIOBR here, assuming a single window
+-	 * (16M MEM, 256K IO) is enough.  If a larger space is
+-	 * needed, the readx/writex and inx/outx functions will
+-	 * have to do more (e.g. setting registers for each call).
+-	 */
+-
+-	/*
+-	 * Set the MBR so PCI address is one-to-one with window,
+-	 * meaning all calls go straight through... use ifdef to
+-	 * catch erroneous assumption.
+-	 */
+-	BUG_ON(PCIBIOS_MIN_MEM != SH7751_PCI_MEMORY_BASE);
+-
+-	PCIC_WRITE(SH7751_PCIMBR, PCIBIOS_MIN_MEM);
+-
+-	/* Set IOBR for window containing area specified in pci.h */
+-	PCIC_WRITE(SH7751_PCIIOBR, (PCIBIOS_MIN_IO & SH7751_PCIIOBR_MASK));
+-
+-	/* All done, may as well say so... */
+-	printk("SH7751R PCI: Finished initialization of the PCI controller\n");
+-
+-	return 1;
+-}
+-
+-int __init pcibios_map_platform_irq(u8 slot, u8 pin)
+-{
+-        switch (slot) {
+-	case 0: return IRQ_PCISLOT;	/* PCI Extend slot */
+-	case 1: return IRQ_PCMCIA;	/* PCI Cardbus Bridge */
+-	case 2: return IRQ_PCIETH;	/* Realtek Ethernet controller */
+-	case 3: return IRQ_PCIHUB;	/* Realtek Ethernet Hub controller */
+-	default:
+-		printk("PCI: Bad IRQ mapping request for slot %d\n", slot);
+-		return -1;
+-	}
+-}
+-
+-static struct resource sh7751_io_resource = {
+-	.name	= "SH7751_IO",
+-	.start	= 0x4000,
+-	.end	= 0x4000 + SH7751_PCI_IO_SIZE - 1,
+-	.flags	= IORESOURCE_IO
+-};
+-
+-static struct resource sh7751_mem_resource = {
+-	.name	= "SH7751_mem",
+-	.start	= SH7751_PCI_MEMORY_BASE,
+-	.end	= SH7751_PCI_MEMORY_BASE + SH7751_PCI_MEM_SIZE - 1,
+-	.flags	= IORESOURCE_MEM
+-};
+-
+-extern struct pci_ops sh7751_pci_ops;
+-
+-struct pci_channel board_pci_channels[] = {
+-	{ &sh7751_pci_ops, &sh7751_io_resource, &sh7751_mem_resource, 0, 0xff },
+-	{ NULL, NULL, NULL, 0, 0 },
+-};
+-EXPORT_SYMBOL(board_pci_channels);
+diff --git a/arch/sh/boards/renesas/hs7751rvoip/setup.c b/arch/sh/boards/renesas/hs7751rvoip/setup.c
+deleted file mode 100644
+index c056259..0000000
+--- a/arch/sh/boards/renesas/hs7751rvoip/setup.c
++++ /dev/null
+@@ -1,105 +0,0 @@
+-/*
+- * Renesas Technology Sales HS7751RVoIP Support.
+- *
+- * Copyright (C) 2000  Kazumoto Kojima
+- *
+- * Modified for HS7751RVoIP by
+- * Atom Create Engineering Co., Ltd. 2002.
+- * Lineo uSolutions, Inc. 2003.
+- */
+-#include <linux/init.h>
+-#include <linux/irq.h>
+-#include <linux/mm.h>
+-#include <linux/pm.h>
+-#include <asm/hs7751rvoip.h>
+-#include <asm/io.h>
+-#include <asm/machvec.h>
+-
+-static void hs7751rvoip_power_off(void)
+-{
+-	ctrl_outw(ctrl_inw(PA_OUTPORTR) & 0xffdf, PA_OUTPORTR);
+-}
+-
+-void *area5_io8_base;
+-void *area6_io8_base;
+-void *area5_io16_base;
+-void *area6_io16_base;
+-
+-static int __init hs7751rvoip_cf_init(void)
+-{
+-	pgprot_t prot;
+-	unsigned long paddrbase;
+-
+-	/* open I/O area window */
+-	paddrbase = virt_to_phys((void *)(PA_AREA5_IO+0x00000800));
+-	prot = PAGE_KERNEL_PCC(1, _PAGE_PCC_COM16);
+-	area5_io16_base = p3_ioremap(paddrbase, PAGE_SIZE, prot.pgprot);
+-	if (!area5_io16_base) {
+-		printk("allocate_cf_area : can't open CF I/O window!\n");
+-		return -ENOMEM;
+-	}
+-
+-	/* XXX : do we need attribute and common-memory area also? */
+-
+-	paddrbase = virt_to_phys((void *)PA_AREA6_IO);
+-#if defined(CONFIG_HS7751RVOIP_CODEC)
+-	prot = PAGE_KERNEL_PCC(0, _PAGE_PCC_COM8);
+-#else
+-	prot = PAGE_KERNEL_PCC(0, _PAGE_PCC_IO8);
+-#endif
+-	area6_io8_base = p3_ioremap(paddrbase, PAGE_SIZE, prot.pgprot);
+-	if (!area6_io8_base) {
+-		printk("allocate_cf_area : can't open CODEC I/O 8bit window!\n");
+-		return -ENOMEM;
+-	}
+-	prot = PAGE_KERNEL_PCC(0, _PAGE_PCC_IO16);
+-	area6_io16_base = p3_ioremap(paddrbase, PAGE_SIZE, prot.pgprot);
+-	if (!area6_io16_base) {
+-		printk("allocate_cf_area : can't open CODEC I/O 16bit window!\n");
+-		return -ENOMEM;
+-	}
+-
+-	return 0;
+-}
+-device_initcall(hs7751rvoip_cf_init);
+-
+-/*
+- * Initialize the board
+- */
+-static void __init hs7751rvoip_setup(char **cmdline_p)
+-{
+-	ctrl_outb(0xf0, PA_OUTPORTR);
+-	pm_power_off = hs7751rvoip_power_off;
+-
+-	printk(KERN_INFO "Renesas Technology Sales HS7751RVoIP-2 support.\n");
+-}
+-
+-static struct sh_machine_vector mv_hs7751rvoip __initmv = {
+-	.mv_name		= "HS7751RVoIP",
+-	.mv_setup		= hs7751rvoip_setup,
+-	.mv_nr_irqs		= 72,
+-
+-	.mv_inb			= hs7751rvoip_inb,
+-	.mv_inw			= hs7751rvoip_inw,
+-	.mv_inl			= hs7751rvoip_inl,
+-	.mv_outb		= hs7751rvoip_outb,
+-	.mv_outw		= hs7751rvoip_outw,
+-	.mv_outl		= hs7751rvoip_outl,
+-
+-	.mv_inb_p		= hs7751rvoip_inb_p,
+-	.mv_inw_p		= hs7751rvoip_inw,
+-	.mv_inl_p		= hs7751rvoip_inl,
+-	.mv_outb_p		= hs7751rvoip_outb_p,
+-	.mv_outw_p		= hs7751rvoip_outw,
+-	.mv_outl_p		= hs7751rvoip_outl,
+-
+-	.mv_insb		= hs7751rvoip_insb,
+-	.mv_insw		= hs7751rvoip_insw,
+-	.mv_insl		= hs7751rvoip_insl,
+-	.mv_outsb		= hs7751rvoip_outsb,
+-	.mv_outsw		= hs7751rvoip_outsw,
+-	.mv_outsl		= hs7751rvoip_outsl,
+-
+-	.mv_init_irq		= init_hs7751rvoip_IRQ,
+-	.mv_ioport_map		= hs7751rvoip_ioport_map,
+-};
+diff --git a/arch/sh/boards/renesas/r7780rp/Makefile b/arch/sh/boards/renesas/r7780rp/Makefile
+index dd26182..20a1008 100644
+--- a/arch/sh/boards/renesas/r7780rp/Makefile
++++ b/arch/sh/boards/renesas/r7780rp/Makefile
+@@ -3,7 +3,7 @@
+ #
+ irqinit-$(CONFIG_SH_R7780MP)	:= irq-r7780mp.o
+ irqinit-$(CONFIG_SH_R7785RP)	:= irq-r7785rp.o
+-irqinit-$(CONFIG_SH_R7780RP)	:= irq-r7780rp.o irq.o
++irqinit-$(CONFIG_SH_R7780RP)	:= irq-r7780rp.o
+ obj-y				:= setup.o $(irqinit-y)
+ 
+ ifneq ($(CONFIG_SH_R7785RP),y)
+diff --git a/arch/sh/boards/renesas/r7780rp/irq-r7780mp.c b/arch/sh/boards/renesas/r7780rp/irq-r7780mp.c
+index 59b47fe..1f8f073 100644
+--- a/arch/sh/boards/renesas/r7780rp/irq-r7780mp.c
++++ b/arch/sh/boards/renesas/r7780rp/irq-r7780mp.c
+@@ -47,7 +47,7 @@ static unsigned char irl2irq[HL_NR_IRL] __initdata = {
+ };
+ 
+ static DECLARE_INTC_DESC(intc_desc, "r7780mp", vectors,
+-			 NULL, NULL, mask_registers, NULL, NULL);
++			 NULL, mask_registers, NULL, NULL);
+ 
+ unsigned char * __init highlander_init_irq_r7780mp(void)
+ {
+diff --git a/arch/sh/boards/renesas/r7780rp/irq-r7780rp.c b/arch/sh/boards/renesas/r7780rp/irq-r7780rp.c
+index fa4a534..bd34048 100644
+--- a/arch/sh/boards/renesas/r7780rp/irq-r7780rp.c
++++ b/arch/sh/boards/renesas/r7780rp/irq-r7780rp.c
+@@ -3,21 +3,65 @@
+  *
+  * Copyright (C) 2002  Atom Create Engineering Co., Ltd.
+  * Copyright (C) 2006  Paul Mundt
++ * Copyright (C) 2008  Magnus Damm
+  *
+  * 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/irq.h>
+ #include <linux/io.h>
+ #include <asm/r7780rp.h>
+ 
++enum {
++	UNUSED = 0,
++
++	/* board specific interrupt sources */
++
++	AX88796,          /* Ethernet controller */
++	PSW,              /* Push Switch */
++	CF,               /* Compact Flash */
++
++	PCI_A,
++	PCI_B,
++	PCI_C,
++	PCI_D,
++};
++
++static struct intc_vect vectors[] __initdata = {
++	INTC_IRQ(PCI_A, 65), /* dirty: overwrite cpu vectors for pci */
++	INTC_IRQ(PCI_B, 66),
++	INTC_IRQ(PCI_C, 67),
++	INTC_IRQ(PCI_D, 68),
++	INTC_IRQ(CF, IRQ_CF),
++	INTC_IRQ(PSW, IRQ_PSW),
++	INTC_IRQ(AX88796, IRQ_AX88796),
++};
++
++static struct intc_mask_reg mask_registers[] __initdata = {
++	{ 0xa5000000, 0, 16, /* IRLMSK */
++	  { PCI_A, PCI_B, PCI_C, PCI_D, CF, 0, 0, 0,
++	    0, 0, 0, 0, 0, 0, PSW, AX88796 } },
++};
++
++static unsigned char irl2irq[HL_NR_IRL] __initdata = {
++	65, 66, 67, 68,
++	IRQ_CF, 0, 0, 0,
++	0, 0, 0, 0,
++	IRQ_AX88796, IRQ_PSW
++};
++
++static DECLARE_INTC_DESC(intc_desc, "r7780rp", vectors,
++			 NULL, mask_registers, NULL, NULL);
++
+ unsigned char * __init highlander_init_irq_r7780rp(void)
+ {
+-	int i;
+-
+-	for (i = 0; i < 15; i++)
+-		make_r7780rp_irq(i);
++	if (ctrl_inw(0xa5000600)) {
++		printk(KERN_INFO "Using r7780rp interrupt controller.\n");
++		register_intc_controller(&intc_desc);
++		return irl2irq;
++	}
+ 
+ 	return NULL;
+ }
+diff --git a/arch/sh/boards/renesas/r7780rp/irq-r7785rp.c b/arch/sh/boards/renesas/r7780rp/irq-r7785rp.c
+index b2c6a84..bf7ec10 100644
+--- a/arch/sh/boards/renesas/r7780rp/irq-r7785rp.c
++++ b/arch/sh/boards/renesas/r7780rp/irq-r7785rp.c
+@@ -2,7 +2,7 @@
+  * Renesas Solutions Highlander R7785RP Support.
+  *
+  * Copyright (C) 2002  Atom Create Engineering Co., Ltd.
+- * Copyright (C) 2006  Paul Mundt
++ * Copyright (C) 2006 - 2008  Paul Mundt
+  * Copyright (C) 2007  Magnus Damm
+  *
+  * This file is subject to the terms and conditions of the GNU General Public
+@@ -17,31 +17,52 @@
+ enum {
+ 	UNUSED = 0,
+ 
+-	/* board specific interrupt sources */
+-	AX88796,          /* Ethernet controller */
+-	CF,               /* Compact Flash */
++	/* FPGA specific interrupt sources */
++	CF,		/* Compact Flash */
++	SMBUS,		/* SMBUS */
++	TP,		/* Touch panel */
++	RTC,		/* RTC Alarm */
++	TH_ALERT,	/* Temperature sensor */
++	AX88796,	/* Ethernet controller */
++
++	/* external bus connector */
++	EXT0, EXT1, EXT2, EXT3, EXT4, EXT5, EXT6, EXT7,
+ };
+ 
+ static struct intc_vect vectors[] __initdata = {
+ 	INTC_IRQ(CF, IRQ_CF),
++	INTC_IRQ(SMBUS, IRQ_SMBUS),
++	INTC_IRQ(TP, IRQ_TP),
++	INTC_IRQ(RTC, IRQ_RTC),
++	INTC_IRQ(TH_ALERT, IRQ_TH_ALERT),
++
++	INTC_IRQ(EXT0, IRQ_EXT0), INTC_IRQ(EXT1, IRQ_EXT1),
++	INTC_IRQ(EXT2, IRQ_EXT2), INTC_IRQ(EXT3, IRQ_EXT3),
++
++	INTC_IRQ(EXT4, IRQ_EXT4), INTC_IRQ(EXT5, IRQ_EXT5),
++	INTC_IRQ(EXT6, IRQ_EXT6), INTC_IRQ(EXT7, IRQ_EXT7),
++
+ 	INTC_IRQ(AX88796, IRQ_AX88796),
+ };
+ 
+ static struct intc_mask_reg mask_registers[] __initdata = {
+ 	{ 0xa4000010, 0, 16, /* IRLMCR1 */
+-	  { 0, 0, 0, 0, CF, AX88796, 0, 0,
+-	    0, 0, 0, 0, 0, 0, 0, 0 } },
++	  { 0, 0, 0, 0, CF, AX88796, SMBUS, TP,
++	    RTC, 0, TH_ALERT, 0, 0, 0, 0, 0 } },
++	{ 0xa4000012, 0, 16, /* IRLMCR2 */
++	  { 0, 0, 0, 0, 0, 0, 0, 0,
++	    EXT7, EXT6, EXT5, EXT4, EXT3, EXT2, EXT1, EXT0 } },
+ };
+ 
+ static unsigned char irl2irq[HL_NR_IRL] __initdata = {
+-	0, IRQ_CF, 0, 0,
+-	0, 0, 0, 0,
+-	0, 0, IRQ_AX88796, 0,
+-	0, 0, 0,
++	0, IRQ_CF, IRQ_EXT4, IRQ_EXT5,
++	IRQ_EXT6, IRQ_EXT7, IRQ_SMBUS, IRQ_TP,
++	IRQ_RTC, IRQ_TH_ALERT, IRQ_AX88796, IRQ_EXT0,
++	IRQ_EXT1, IRQ_EXT2, IRQ_EXT3,
+ };
+ 
+ static DECLARE_INTC_DESC(intc_desc, "r7785rp", vectors,
+-			 NULL, NULL, mask_registers, NULL, NULL);
++			 NULL, mask_registers, NULL, NULL);
+ 
+ unsigned char * __init highlander_init_irq_r7785rp(void)
+ {
+@@ -58,7 +79,7 @@ unsigned char * __init highlander_init_irq_r7785rp(void)
+ 	ctrl_outw(0x7060, PA_IRLPRC);	/* FPGA IRLC */
+ 	ctrl_outw(0x0000, PA_IRLPRD);	/* FPGA IRLD */
+ 	ctrl_outw(0x4321, PA_IRLPRE);	/* FPGA IRLE */
+-	ctrl_outw(0x0000, PA_IRLPRF);	/* FPGA IRLF */
++	ctrl_outw(0xdcba, PA_IRLPRF);	/* FPGA IRLF */
+ 
+ 	register_intc_controller(&intc_desc);
+ 	return irl2irq;
+diff --git a/arch/sh/boards/renesas/r7780rp/irq.c b/arch/sh/boards/renesas/r7780rp/irq.c
+deleted file mode 100644
+index e0b8eb5..0000000
+--- a/arch/sh/boards/renesas/r7780rp/irq.c
++++ /dev/null
+@@ -1,51 +0,0 @@
+-/*
+- * Renesas Solutions Highlander R7780RP-1 Support.
+- *
+- * Copyright (C) 2002  Atom Create Engineering Co., Ltd.
+- * Copyright (C) 2006  Paul Mundt
+- *
+- * This file is subject to the terms and conditions of the GNU General Public
+- * License.  See the file "COPYING" in the main directory of this archive
+- * for more details.
+- */
+-#include <linux/init.h>
+-#include <linux/irq.h>
+-#include <linux/interrupt.h>
+-#include <linux/io.h>
+-#include <asm/r7780rp.h>
+-
+-#ifdef CONFIG_SH_R7780RP
+-static int mask_pos[] = {15, 14, 13, 12, 11, 10, 9, 8, 7, 5, 6, 4, 0, 1, 2, 0};
+-#elif defined(CONFIG_SH_R7780MP)
+-static int mask_pos[] = {12, 11, 9, 14, 15, 8, 13, 6, 5, 4, 3, 2, 0, 0, 1, 0};
+-#elif defined(CONFIG_SH_R7785RP)
+-static int mask_pos[] = {2, 11, 2, 2, 2, 2, 9, 8, 7, 5, 10, 2, 2, 2, 2, 2};
+-#endif
+-
+-static void enable_r7780rp_irq(unsigned int irq)
+-{
+-	/* Set priority in IPR back to original value */
+-	ctrl_outw(ctrl_inw(IRLCNTR1) | (1 << mask_pos[irq]), IRLCNTR1);
+-}
+-
+-static void disable_r7780rp_irq(unsigned int irq)
+-{
+-	/* Set the priority in IPR to 0 */
+-	ctrl_outw(ctrl_inw(IRLCNTR1) & (0xffff ^ (1 << mask_pos[irq])),
+-		  IRLCNTR1);
+-}
+-
+-static struct irq_chip r7780rp_irq_chip __read_mostly = {
+-	.name		= "R7780RP",
+-	.mask		= disable_r7780rp_irq,
+-	.unmask		= enable_r7780rp_irq,
+-	.mask_ack	= disable_r7780rp_irq,
+-};
+-
+-void make_r7780rp_irq(unsigned int irq)
+-{
+-	disable_irq_nosync(irq);
+-	set_irq_chip_and_handler_name(irq, &r7780rp_irq_chip,
+-				      handle_level_irq, "level");
+-	enable_r7780rp_irq(irq);
+-}
+diff --git a/arch/sh/boards/renesas/r7780rp/setup.c b/arch/sh/boards/renesas/r7780rp/setup.c
+index 0fdc0bc..a43b477 100644
+--- a/arch/sh/boards/renesas/r7780rp/setup.c
++++ b/arch/sh/boards/renesas/r7780rp/setup.c
+@@ -179,9 +179,11 @@ static struct platform_device ax88796_device = {
+ static struct platform_device *r7780rp_devices[] __initdata = {
+ 	&r8a66597_usb_host_device,
+ 	&m66592_usb_peripheral_device,
+-	&cf_ide_device,
+ 	&heartbeat_device,
++#ifndef CONFIG_SH_R7780RP
++	&cf_ide_device,
+ 	&ax88796_device,
++#endif
+ };
+ 
+ static int __init r7780rp_devices_setup(void)
+@@ -316,9 +318,9 @@ void __init highlander_init_irq(void)
+ 			break;
+ #endif
+ #ifdef CONFIG_SH_R7780RP
+-		highlander_init_irq_r7780rp();
+-		ucp = irl2irq;
+-		break;
++		ucp = highlander_init_irq_r7780rp();
++		if (ucp)
++			break;
+ #endif
+ 	} while (0);
+ 
+diff --git a/arch/sh/boards/renesas/rts7751r2d/irq.c b/arch/sh/boards/renesas/rts7751r2d/irq.c
+index 7cc2813..8e49f6e 100644
+--- a/arch/sh/boards/renesas/rts7751r2d/irq.c
++++ b/arch/sh/boards/renesas/rts7751r2d/irq.c
+@@ -13,7 +13,6 @@
+ #include <linux/irq.h>
+ #include <linux/interrupt.h>
+ #include <linux/io.h>
+-#include <asm/voyagergx.h>
+ #include <asm/rts7751r2d.h>
+ 
+ #define R2D_NR_IRL 13
+@@ -71,7 +70,7 @@ static unsigned char irl2irq_r2d_1[R2D_NR_IRL] __initdata = {
+ };
+ 
+ static DECLARE_INTC_DESC(intc_desc_r2d_1, "r2d-1", vectors_r2d_1,
+-			 NULL, NULL, mask_registers_r2d_1, NULL, NULL);
++			 NULL, mask_registers_r2d_1, NULL, NULL);
+ 
+ #endif /* CONFIG_RTS7751R2D_1 */
+ 
+@@ -109,7 +108,7 @@ static unsigned char irl2irq_r2d_plus[R2D_NR_IRL] __initdata = {
+ };
+ 
+ static DECLARE_INTC_DESC(intc_desc_r2d_plus, "r2d-plus", vectors_r2d_plus,
+-			 NULL, NULL, mask_registers_r2d_plus, NULL, NULL);
++			 NULL, mask_registers_r2d_plus, NULL, NULL);
+ 
+ #endif /* CONFIG_RTS7751R2D_PLUS */
+ 
+@@ -153,7 +152,4 @@ void __init init_rts7751r2d_IRQ(void)
+ 	}
+ 
+ 	register_intc_controller(d);
+-#ifdef CONFIG_MFD_SM501
+-	setup_voyagergx_irq();
+-#endif
+ }
+diff --git a/arch/sh/boards/renesas/rts7751r2d/setup.c b/arch/sh/boards/renesas/rts7751r2d/setup.c
+index 8125d20..3452b07 100644
+--- a/arch/sh/boards/renesas/rts7751r2d/setup.c
++++ b/arch/sh/boards/renesas/rts7751r2d/setup.c
+@@ -13,34 +13,15 @@
+ #include <linux/pata_platform.h>
+ #include <linux/serial_8250.h>
+ #include <linux/sm501.h>
++#include <linux/sm501-regs.h>
+ #include <linux/pm.h>
++#include <linux/fb.h>
++#include <linux/spi/spi.h>
++#include <linux/spi/spi_bitbang.h>
+ #include <asm/machvec.h>
+ #include <asm/rts7751r2d.h>
+-#include <asm/voyagergx.h>
+ #include <asm/io.h>
+-
+-static void __init voyagergx_serial_init(void)
+-{
+-	unsigned long val;
+-
+-	/*
+-	 * GPIO Control
+-	 */
+-	val = readl((void __iomem *)GPIO_MUX_HIGH);
+-	val |= 0x00001fe0;
+-	writel(val, (void __iomem *)GPIO_MUX_HIGH);
+-
+-	/*
+-	 * Power Mode Gate
+-	 */
+-	val = readl((void __iomem *)POWER_MODE0_GATE);
+-	val |= (POWER_MODE0_GATE_U0 | POWER_MODE0_GATE_U1);
+-	writel(val, (void __iomem *)POWER_MODE0_GATE);
+-
+-	val = readl((void __iomem *)POWER_MODE1_GATE);
+-	val |= (POWER_MODE1_GATE_U0 | POWER_MODE1_GATE_U1);
+-	writel(val, (void __iomem *)POWER_MODE1_GATE);
+-}
++#include <asm/spi.h>
+ 
+ static struct resource cf_ide_resources[] = {
+ 	[0] = {
+@@ -75,6 +56,43 @@ static struct platform_device cf_ide_device  = {
+ 	},
+ };
+ 
++static struct spi_board_info spi_bus[] = {
++	{
++		.modalias	= "rtc-r9701",
++		.max_speed_hz	= 1000000,
++		.mode		= SPI_MODE_3,
++	},
++};
++
++static void r2d_chip_select(struct sh_spi_info *spi, int cs, int state)
++{
++	BUG_ON(cs != 0);  /* Single Epson RTC-9701JE attached on CS0 */
++	ctrl_outw(state == BITBANG_CS_ACTIVE, PA_RTCCE);
++}
++
++static struct sh_spi_info spi_info = {
++	.num_chipselect = 1,
++	.chip_select = r2d_chip_select,
++};
++
++static struct resource spi_sh_sci_resources[] = {
++	{
++		.start	= 0xffe00000,
++		.end	= 0xffe0001f,
++		.flags	= IORESOURCE_MEM,
++	},
++};
++
++static struct platform_device spi_sh_sci_device  = {
++	.name		= "spi_sh_sci",
++	.id		= -1,
++	.num_resources	= ARRAY_SIZE(spi_sh_sci_resources),
++	.resource	= spi_sh_sci_resources,
++	.dev	= {
++		.platform_data	= &spi_info,
++	},
++};
++
+ static struct resource heartbeat_resources[] = {
+ 	[0] = {
+ 		.start	= PA_OUTPORT,
+@@ -93,11 +111,11 @@ static struct platform_device heartbeat_device = {
+ #ifdef CONFIG_MFD_SM501
+ static struct plat_serial8250_port uart_platform_data[] = {
+ 	{
+-		.membase	= (void __iomem *)VOYAGER_UART_BASE,
+-		.mapbase	= VOYAGER_UART_BASE,
++		.membase	= (void __iomem *)0xb3e30000,
++		.mapbase	= 0xb3e30000,
+ 		.iotype		= UPIO_MEM,
+-		.irq		= IRQ_SM501_U0,
+-		.flags		= UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
++		.irq		= IRQ_VOYAGER,
++		.flags		= UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ,
+ 		.regshift	= 2,
+ 		.uartclk	= (9600 * 16),
+ 	},
+@@ -124,14 +142,67 @@ static struct resource sm501_resources[] = {
+ 		.flags	= IORESOURCE_MEM,
+ 	},
+ 	[2]	= {
+-		.start	= IRQ_SM501_CV,
++		.start	= IRQ_VOYAGER,
+ 		.flags	= IORESOURCE_IRQ,
+ 	},
+ };
+ 
++static struct fb_videomode sm501_default_mode = {
++	.pixclock	= 35714,
++	.xres		= 640,
++	.yres		= 480,
++	.left_margin	= 105,
++	.right_margin	= 50,
++	.upper_margin	= 35,
++	.lower_margin	= 0,
++	.hsync_len	= 96,
++	.vsync_len	= 2,
++	.sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
++};
++
++static struct sm501_platdata_fbsub sm501_pdata_fbsub_pnl = {
++	.def_bpp	= 16,
++	.def_mode	= &sm501_default_mode,
++	.flags		= SM501FB_FLAG_USE_INIT_MODE |
++			  SM501FB_FLAG_USE_HWCURSOR |
++			  SM501FB_FLAG_USE_HWACCEL |
++			  SM501FB_FLAG_DISABLE_AT_EXIT,
++};
++
++static struct sm501_platdata_fbsub sm501_pdata_fbsub_crt = {
++	.flags		= (SM501FB_FLAG_USE_INIT_MODE |
++			   SM501FB_FLAG_USE_HWCURSOR |
++			   SM501FB_FLAG_USE_HWACCEL |
++			   SM501FB_FLAG_DISABLE_AT_EXIT),
++
++};
++
++static struct sm501_platdata_fb sm501_fb_pdata = {
++	.fb_route	= SM501_FB_OWN,
++	.fb_crt		= &sm501_pdata_fbsub_crt,
++	.fb_pnl		= &sm501_pdata_fbsub_pnl,
++	.flags		= SM501_FBPD_SWAP_FB_ENDIAN,
++};
++
++static struct sm501_initdata sm501_initdata = {
++	.gpio_high	= {
++		.set	= 0x00001fe0,
++		.mask	= 0x0,
++	},
++	.devices	= SM501_USE_USB_HOST,
++};
++
++static struct sm501_platdata sm501_platform_data = {
++	.init		= &sm501_initdata,
++	.fb		= &sm501_fb_pdata,
++};
++
+ static struct platform_device sm501_device = {
+ 	.name		= "sm501",
+ 	.id		= -1,
++	.dev		= {
++		.platform_data	= &sm501_platform_data,
++	},
+ 	.num_resources	= ARRAY_SIZE(sm501_resources),
+ 	.resource	= sm501_resources,
+ };
+@@ -145,10 +216,12 @@ static struct platform_device *rts7751r2d_devices[] __initdata = {
+ #endif
+ 	&cf_ide_device,
+ 	&heartbeat_device,
++	&spi_sh_sci_device,
+ };
+ 
+ static int __init rts7751r2d_devices_setup(void)
+ {
++	spi_register_board_info(spi_bus, ARRAY_SIZE(spi_bus));
+ 	return platform_add_devices(rts7751r2d_devices,
+ 				    ARRAY_SIZE(rts7751r2d_devices));
+ }
+@@ -192,6 +265,7 @@ u8 rts7751r2d_readb(void __iomem *addr)
+  */
+ static void __init rts7751r2d_setup(char **cmdline_p)
+ {
++	void __iomem *sm501_reg;
+ 	u16 ver = ctrl_inw(PA_VERREG);
+ 
+ 	printk(KERN_INFO "Renesas Technology Sales RTS7751R2D support.\n");
+@@ -202,7 +276,30 @@ static void __init rts7751r2d_setup(char **cmdline_p)
+ 	ctrl_outw(0x0000, PA_OUTPORT);
+ 	pm_power_off = rts7751r2d_power_off;
+ 
+-	voyagergx_serial_init();
++	/* sm501 dram configuration:
++	 * ColSizeX = 11 - External Memory Column Size: 256 words.
++	 * APX = 1 - External Memory Active to Pre-Charge Delay: 7 clocks.
++	 * RstX = 1 - External Memory Reset: Normal.
++	 * Rfsh = 1 - Local Memory Refresh to Command Delay: 12 clocks.
++	 * BwC =  1 - Local Memory Block Write Cycle Time: 2 clocks.
++	 * BwP =  1 - Local Memory Block Write to Pre-Charge Delay: 1 clock.
++	 * AP = 1 - Internal Memory Active to Pre-Charge Delay: 7 clocks.
++	 * Rst = 1 - Internal Memory Reset: Normal.
++	 * RA = 1 - Internal Memory Remain in Active State: Do not remain.
++	 */
++
++	sm501_reg = (void __iomem *)0xb3e00000 + SM501_DRAM_CONTROL;
++	writel(readl(sm501_reg) | 0x00f107c0, sm501_reg);
++
++	/*
++	 * Power Mode Gate - Enable UART0
++	 */
++
++	sm501_reg = (void __iomem *)0xb3e00000 + SM501_POWER_MODE_0_GATE;
++	writel(readl(sm501_reg) | (1 << SM501_GATE_UART0), sm501_reg);
++
++	sm501_reg = (void __iomem *)0xb3e00000 + SM501_POWER_MODE_1_GATE;
++	writel(readl(sm501_reg) | (1 << SM501_GATE_UART0), sm501_reg);
+ }
+ 
+ /*
+@@ -215,8 +312,4 @@ static struct sh_machine_vector mv_rts7751r2d __initmv = {
+ 	.mv_irq_demux		= rts7751r2d_irq_demux,
+ 	.mv_writeb		= rts7751r2d_writeb,
+ 	.mv_readb		= rts7751r2d_readb,
+-#if defined(CONFIG_MFD_SM501) && defined(CONFIG_USB_OHCI_HCD)
+-	.mv_consistent_alloc	= voyagergx_consistent_alloc,
+-	.mv_consistent_free	= voyagergx_consistent_free,
+-#endif
+ };
+diff --git a/arch/sh/boards/renesas/sdk7780/Kconfig b/arch/sh/boards/renesas/sdk7780/Kconfig
+new file mode 100644
+index 0000000..e4f5b69
+--- /dev/null
++++ b/arch/sh/boards/renesas/sdk7780/Kconfig
+@@ -0,0 +1,23 @@
++if SH_SDK7780
++
++choice
++	prompt "SDK7780 options"
++	default SH_SDK7780_BASE
++
++config SH_SDK7780_STANDALONE
++	bool "SDK7780 board support"
++	depends on CPU_SUBTYPE_SH7780
++	help
++	  Selecting this option will enable support for the
++	  standalone version of the SDK7780. If in doubt, say Y.
++
++config SH_SDK7780_BASE
++	bool "SDK7780 with base-board support"
++	depends on CPU_SUBTYPE_SH7780
++	help
++	  Selecting this option will enable support for the expansion
++	  baseboard devices. If in doubt, say Y.
++
++endchoice
++
++endif
+diff --git a/arch/sh/boards/renesas/sdk7780/Makefile b/arch/sh/boards/renesas/sdk7780/Makefile
+new file mode 100644
+index 0000000..3d8f0be
+--- /dev/null
++++ b/arch/sh/boards/renesas/sdk7780/Makefile
+@@ -0,0 +1,5 @@
++#
++# Makefile for the SDK7780 specific parts of the kernel
++#
++obj-y	 := setup.o irq.o
++
+diff --git a/arch/sh/boards/renesas/sdk7780/irq.c b/arch/sh/boards/renesas/sdk7780/irq.c
+new file mode 100644
+index 0000000..87cdc57
+--- /dev/null
++++ b/arch/sh/boards/renesas/sdk7780/irq.c
+@@ -0,0 +1,46 @@
++/*
++ * linux/arch/sh/boards/renesas/sdk7780/irq.c
++ *
++ * Renesas Technology Europe SDK7780 Support.
++ *
++ * Copyright (C) 2008  Nicholas Beck <nbeck at mpc-data.co.uk>
++ *
++ * 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/irq.h>
++#include <linux/io.h>
++#include <asm/sdk7780.h>
++
++enum {
++	UNUSED = 0,
++	/* board specific interrupt sources */
++	SMC91C111,	/* Ethernet controller */
++};
++
++static struct intc_vect fpga_vectors[] __initdata = {
++	INTC_IRQ(SMC91C111, IRQ_ETHERNET),
++};
++
++static struct intc_mask_reg fpga_mask_registers[] __initdata = {
++	{ 0, FPGA_IRQ0MR, 16,
++	  { 0, 0, 0, 0, 0, 0, 0, 0,
++	    0, 0, 0, SMC91C111, 0, 0, 0, 0 } },
++};
++
++static DECLARE_INTC_DESC(fpga_intc_desc, "sdk7780-irq", fpga_vectors,
++			 NULL, fpga_mask_registers, NULL, NULL);
++
++void __init init_sdk7780_IRQ(void)
++{
++	printk(KERN_INFO "Using SDK7780 interrupt controller.\n");
++
++	ctrl_outw(0xFFFF, FPGA_IRQ0MR);
++	/* Setup IRL 0-3 */
++	ctrl_outw(0x0003, FPGA_IMSR);
++	plat_irq_setup_pins(IRQ_MODE_IRL3210);
++
++	register_intc_controller(&fpga_intc_desc);
++}
+diff --git a/arch/sh/boards/renesas/sdk7780/setup.c b/arch/sh/boards/renesas/sdk7780/setup.c
+new file mode 100644
+index 0000000..5df32f2
+--- /dev/null
++++ b/arch/sh/boards/renesas/sdk7780/setup.c
+@@ -0,0 +1,109 @@
++/*
++ * arch/sh/boards/renesas/sdk7780/setup.c
++ *
++ * Renesas Solutions SH7780 SDK Support
++ * Copyright (C) 2008 Nicholas Beck <nbeck at mpc-data.co.uk>
++ *
++ * 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/types.h>
++#include <linux/platform_device.h>
++#include <linux/pata_platform.h>
++#include <asm/machvec.h>
++#include <asm/sdk7780.h>
++#include <asm/heartbeat.h>
++#include <asm/io.h>
++#include <asm/addrspace.h>
++
++#define GPIO_PECR        0xFFEA0008
++
++//* Heartbeat */
++static struct heartbeat_data heartbeat_data = {
++	.regsize = 16,
++};
++
++static struct resource heartbeat_resources[] = {
++	[0] = {
++		.start  = PA_LED,
++		.end    = PA_LED,
++		.flags  = IORESOURCE_MEM,
++	},
++};
++
++static struct platform_device heartbeat_device = {
++	.name           = "heartbeat",
++	.id             = -1,
++	.dev = {
++		.platform_data = &heartbeat_data,
++	},
++	.num_resources  = ARRAY_SIZE(heartbeat_resources),
++	.resource       = heartbeat_resources,
++};
++
++/* SMC91x */
++static struct resource smc91x_eth_resources[] = {
++	[0] = {
++		.name   = "smc91x-regs" ,
++		.start  = PA_LAN + 0x300,
++		.end    = PA_LAN + 0x300 + 0x10 ,
++		.flags  = IORESOURCE_MEM,
++	},
++	[1] = {
++		.start  = IRQ_ETHERNET,
++		.end    = IRQ_ETHERNET,
++		.flags  = IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device smc91x_eth_device = {
++	.name           = "smc91x",
++	.id             = 0,
++	.dev = {
++		.dma_mask               = NULL,         /* don't use dma */
++		.coherent_dma_mask      = 0xffffffff,
++	},
++	.num_resources  = ARRAY_SIZE(smc91x_eth_resources),
++	.resource       = smc91x_eth_resources,
++};
++
++static struct platform_device *sdk7780_devices[] __initdata = {
++	&heartbeat_device,
++	&smc91x_eth_device,
++};
++
++static int __init sdk7780_devices_setup(void)
++{
++	return platform_add_devices(sdk7780_devices,
++		ARRAY_SIZE(sdk7780_devices));
++}
++device_initcall(sdk7780_devices_setup);
++
++static void __init sdk7780_setup(char **cmdline_p)
++{
++	u16 ver = ctrl_inw(FPGA_FPVERR);
++	u16 dateStamp = ctrl_inw(FPGA_FPDATER);
++
++	printk(KERN_INFO "Renesas Technology Europe SDK7780 support.\n");
++	printk(KERN_INFO "Board version: %d (revision %d), "
++			 "FPGA version: %d (revision %d), datestamp : %d\n",
++			 (ver >> 12) & 0xf, (ver >> 8) & 0xf,
++			 (ver >>  4) & 0xf, ver & 0xf,
++			 dateStamp);
++
++	/* Setup pin mux'ing for PCIC */
++	ctrl_outw(0x0000, GPIO_PECR);
++}
++
++/*
++ * The Machine Vector
++ */
++static struct sh_machine_vector mv_se7780 __initmv = {
++	.mv_name        = "Renesas SDK7780-R3" ,
++	.mv_setup		= sdk7780_setup,
++	.mv_nr_irqs		= 111,
++	.mv_init_irq	= init_sdk7780_IRQ,
++};
++
+diff --git a/arch/sh/boot/Makefile b/arch/sh/boot/Makefile
+index 1b0f5be..59f552c 100644
+--- a/arch/sh/boot/Makefile
++++ b/arch/sh/boot/Makefile
+@@ -35,17 +35,28 @@ $(obj)/compressed/vmlinux: FORCE
+ KERNEL_LOAD	:= $(shell /bin/bash -c 'printf "0x%8x" \
+ 		     $$[$(CONFIG_PAGE_OFFSET)  + \
+ 			$(CONFIG_MEMORY_START) + \
++			$(CONFIG_ZERO_PAGE_OFFSET)]')
++
++KERNEL_ENTRY	:= $(shell /bin/bash -c 'printf "0x%8x" \
++		     $$[$(CONFIG_PAGE_OFFSET)  + \
++			$(CONFIG_MEMORY_START) + \
+ 			$(CONFIG_ZERO_PAGE_OFFSET)+0x1000]')
+ 
+ quiet_cmd_uimage = UIMAGE  $@
+       cmd_uimage = $(CONFIG_SHELL) $(MKIMAGE) -A sh -O linux -T kernel \
+-		   -C none -a $(KERNEL_LOAD) -e $(KERNEL_LOAD) \
++		   -C none -a $(KERNEL_LOAD) -e $(KERNEL_ENTRY) \
+ 		   -n 'Linux-$(KERNELRELEASE)' -d $< $@
+ 
+-$(obj)/uImage: $(obj)/zImage FORCE
++$(obj)/uImage: $(obj)/vmlinux.bin.gz FORCE
+ 	$(call if_changed,uimage)
+ 	@echo '  Image $@ is ready'
+ 
++$(obj)/vmlinux.bin: vmlinux FORCE
++	$(call if_changed,objcopy)
++
++$(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin FORCE
++	$(call if_changed,gzip)
++
+ OBJCOPYFLAGS_vmlinux.srec := -I binary -O srec
+ $(obj)/vmlinux.srec: $(obj)/compressed/vmlinux
+ 	$(call if_changed,objcopy)
+@@ -54,4 +65,5 @@ OBJCOPYFLAGS_uImage.srec := -I binary -O srec
+ $(obj)/uImage.srec: $(obj)/uImage
+ 	$(call if_changed,objcopy)
+ 
+-clean-files	+= uImage uImage.srec vmlinux.srec
++clean-files	+= uImage uImage.srec vmlinux.srec \
++		   vmlinux.bin vmlinux.bin.gz
+diff --git a/arch/sh/boot/compressed/Makefile b/arch/sh/boot/compressed/Makefile
+index 906a13f..efb01dc 100644
+--- a/arch/sh/boot/compressed/Makefile
++++ b/arch/sh/boot/compressed/Makefile
+@@ -1,43 +1,5 @@
+-#
+-# linux/arch/sh/boot/compressed/Makefile
+-#
+-# create a compressed vmlinux image from the original vmlinux
+-#
+-
+-targets		:= vmlinux vmlinux.bin vmlinux.bin.gz head.o misc.o piggy.o
+-EXTRA_AFLAGS	:= -traditional
+-
+-OBJECTS = $(obj)/head.o $(obj)/misc.o
+-
+-ifdef CONFIG_SH_STANDARD_BIOS
+-OBJECTS += $(obj)/../../kernel/sh_bios.o
++ifeq ($(CONFIG_SUPERH32),y)
++include ${srctree}/arch/sh/boot/compressed/Makefile_32
++else
++include ${srctree}/arch/sh/boot/compressed/Makefile_64
+ endif
+-
+-#
+-# IMAGE_OFFSET is the load offset of the compression loader
+-#
+-IMAGE_OFFSET	:= $(shell /bin/bash -c 'printf "0x%08x" \
+-		     $$[$(CONFIG_PAGE_OFFSET)  + \
+-			$(CONFIG_MEMORY_START) + \
+-			$(CONFIG_BOOT_LINK_OFFSET)]')
+-
+-LIBGCC	:= $(shell $(CC) $(KBUILD_CFLAGS) -print-libgcc-file-name)
+-
+-LDFLAGS_vmlinux := -Ttext $(IMAGE_OFFSET) -e startup -T $(obj)/../../kernel/vmlinux.lds
+-
+-
+-$(obj)/vmlinux: $(OBJECTS) $(obj)/piggy.o $(LIBGCC) FORCE
+-	$(call if_changed,ld)
+-	@:
+-
+-$(obj)/vmlinux.bin: vmlinux FORCE
+-	$(call if_changed,objcopy)
+-
+-$(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin FORCE
+-	$(call if_changed,gzip)
+-
+-LDFLAGS_piggy.o := -r --format binary --oformat elf32-sh-linux -T
+-OBJCOPYFLAGS += -R .empty_zero_page
+-
+-$(obj)/piggy.o: $(obj)/vmlinux.scr $(obj)/vmlinux.bin.gz FORCE
+-	$(call if_changed,ld)
+diff --git a/arch/sh/boot/compressed/Makefile_32 b/arch/sh/boot/compressed/Makefile_32
+new file mode 100644
+index 0000000..6ac8d4a
+--- /dev/null
++++ b/arch/sh/boot/compressed/Makefile_32
+@@ -0,0 +1,43 @@
++#
++# linux/arch/sh/boot/compressed/Makefile
++#
++# create a compressed vmlinux image from the original vmlinux
++#
++
++targets		:= vmlinux vmlinux.bin vmlinux.bin.gz \
++		   head_32.o misc_32.o piggy.o
++EXTRA_AFLAGS	:= -traditional
++
++OBJECTS = $(obj)/head_32.o $(obj)/misc_32.o
++
++ifdef CONFIG_SH_STANDARD_BIOS
++OBJECTS += $(obj)/../../kernel/sh_bios.o
++endif
++
++#
++# IMAGE_OFFSET is the load offset of the compression loader
++#
++IMAGE_OFFSET	:= $(shell /bin/bash -c 'printf "0x%08x" \
++		     $$[$(CONFIG_PAGE_OFFSET)  + \
++			$(CONFIG_MEMORY_START) + \
++			$(CONFIG_BOOT_LINK_OFFSET)]')
++
++LIBGCC	:= $(shell $(CC) $(KBUILD_CFLAGS) -print-libgcc-file-name)
++
++LDFLAGS_vmlinux := -Ttext $(IMAGE_OFFSET) -e startup -T $(obj)/../../kernel/vmlinux.lds
++
++$(obj)/vmlinux: $(OBJECTS) $(obj)/piggy.o $(LIBGCC) FORCE
++	$(call if_changed,ld)
++	@:
++
++$(obj)/vmlinux.bin: vmlinux FORCE
++	$(call if_changed,objcopy)
++
++$(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin FORCE
++	$(call if_changed,gzip)
++
++LDFLAGS_piggy.o := -r --format binary --oformat elf32-sh-linux -T
++OBJCOPYFLAGS += -R .empty_zero_page
++
++$(obj)/piggy.o: $(obj)/vmlinux.scr $(obj)/vmlinux.bin.gz FORCE
++	$(call if_changed,ld)
+diff --git a/arch/sh/boot/compressed/Makefile_64 b/arch/sh/boot/compressed/Makefile_64
+new file mode 100644
+index 0000000..4334f2b
+--- /dev/null
++++ b/arch/sh/boot/compressed/Makefile_64
+@@ -0,0 +1,45 @@
++#
++# arch/sh/boot/compressed/Makefile_64
++#
++# create a compressed vmlinux image from the original vmlinux
++#
++# Copyright (C) 2002 Stuart Menefy
++# Copyright (C) 2004 Paul Mundt
++#
++# This file is subject to the terms and conditions of the GNU General Public
++# License.  See the file "COPYING" in the main directory of this archive
++# for more details.
++#
++
++targets		:= vmlinux vmlinux.bin vmlinux.bin.gz \
++		   head_64.o misc_64.o cache.o piggy.o
++EXTRA_AFLAGS	:= -traditional
++
++OBJECTS		:= $(obj)/vmlinux_64.lds $(obj)/head_64.o $(obj)/misc_64.o \
++		   $(obj)/cache.o
++
++#
++# ZIMAGE_OFFSET is the load offset of the compression loader
++# (4M for the kernel plus 64K for this loader)
++#
++ZIMAGE_OFFSET	:= $(shell /bin/bash -c 'printf "0x%08x" \
++		     $$[$(CONFIG_PAGE_OFFSET)+0x400000+0x10000]')
++
++LDFLAGS_vmlinux := -Ttext $(ZIMAGE_OFFSET) -e startup \
++		    -T $(obj)/../../kernel/vmlinux.lds
++
++$(obj)/vmlinux: $(OBJECTS) $(obj)/piggy.o FORCE
++	$(call if_changed,ld)
++	@:
++
++$(obj)/vmlinux.bin: vmlinux FORCE
++	$(call if_changed,objcopy)
++
++$(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin FORCE
++	$(call if_changed,gzip)
++
++LDFLAGS_piggy.o := -r --format binary --oformat elf32-sh64-linux -T
++OBJCOPYFLAGS += -R .empty_zero_page
++
++$(obj)/piggy.o: $(obj)/vmlinux.scr $(obj)/vmlinux.bin.gz FORCE
++	$(call if_changed,ld)
+diff --git a/arch/sh/boot/compressed/cache.c b/arch/sh/boot/compressed/cache.c
+new file mode 100644
+index 0000000..e27fc74
+--- /dev/null
++++ b/arch/sh/boot/compressed/cache.c
+@@ -0,0 +1,12 @@
++int cache_control(unsigned int command)
++{
++	volatile unsigned int *p = (volatile unsigned int *) 0x80000000;
++	int i;
++
++	for (i = 0; i < (32 * 1024); i += 32) {
++		(void)*p;
++		p += (32 / sizeof (int));
++	}
++
++	return 0;
++}
+diff --git a/arch/sh/boot/compressed/head.S b/arch/sh/boot/compressed/head.S
+deleted file mode 100644
+index a8399b0..0000000
+--- a/arch/sh/boot/compressed/head.S
++++ /dev/null
+@@ -1,120 +0,0 @@
+-/*
+- *  linux/arch/sh/boot/compressed/head.S
+- *
+- *  Copyright (C) 1999 Stuart Menefy
+- *  Copyright (C) 2003 SUGIOKA Toshinobu
+- */
+-
+-.text
+-
+-#include <linux/linkage.h>
+-#include <asm/page.h>
+-
+-	.global	startup
+-startup:
+-	/* Load initial status register */
+-	mov.l   init_sr, r1
+-	ldc     r1, sr
+-
+-	/* Move myself to proper location if necessary */
+-	mova	1f, r0
+-	mov.l	1f, r2
+-	cmp/eq	r2, r0
+-	bt	clear_bss
+-	sub	r0, r2
+-	mov.l	bss_start_addr, r0
+-	mov	#0xe0, r1
+-	and	r1, r0			! align cache line
+-	mov.l	text_start_addr, r3
+-	mov	r0, r1
+-	sub	r2, r1
+-3:
+-	mov.l	@r1, r4
+-	mov.l	@(4,r1), r5
+-	mov.l	@(8,r1), r6
+-	mov.l	@(12,r1), r7
+-	mov.l	@(16,r1), r8
+-	mov.l	@(20,r1), r9
+-	mov.l	@(24,r1), r10
+-	mov.l	@(28,r1), r11
+-	mov.l	r4, @r0
+-	mov.l	r5, @(4,r0)
+-	mov.l	r6, @(8,r0)
+-	mov.l	r7, @(12,r0)
+-	mov.l	r8, @(16,r0)
+-	mov.l	r9, @(20,r0)
+-	mov.l	r10, @(24,r0)
+-	mov.l	r11, @(28,r0)
+-#ifdef CONFIG_CPU_SH4
+-	ocbwb	@r0
+-#endif
+-	cmp/hi	r3, r0
+-	add	#-32, r0
+-	bt/s	3b
+-	 add	#-32, r1
+-	mov.l	2f, r0
+-	jmp	@r0
+-	 nop
+-
+-	.align 2
+-1:	.long	1b
+-2:	.long	clear_bss
+-text_start_addr:
+-	.long	startup
+-
+-	/* Clear BSS */
+-clear_bss:
+-	mov.l	end_addr, r1
+-	mov.l	bss_start_addr, r2
+-	mov	#0, r0
+-l1:
+-	mov.l	r0, @-r1
+-	cmp/eq	r1,r2
+-	bf	l1
+-
+-	/* Set the initial pointer. */
+-	mov.l	init_stack_addr, r0
+-	mov.l	@r0, r15
+-
+-	/* Decompress the kernel */
+-	mov.l	decompress_kernel_addr, r0
+-	jsr	@r0
+-	nop
+-
+-	/* Jump to the start of the decompressed kernel */
+-	mov.l	kernel_start_addr, r0
+-	jmp	@r0
+-	nop
+-	
+-	.align	2
+-bss_start_addr:
+-	.long	__bss_start
+-end_addr:
+-	.long	_end
+-init_sr:
+-	.long	0x400000F0	/* Privileged mode, Bank=0, Block=0, IMASK=0xF */
+-init_stack_addr:
+-	.long	stack_start
+-decompress_kernel_addr:
+-	.long	decompress_kernel
+-kernel_start_addr:
+-	.long	_text+PAGE_SIZE
+-
+-	.align	9
+-fake_headers_as_bzImage:
+-	.word	0
+-	.ascii	"HdrS"		! header signature
+-	.word	0x0202		! header version number (>= 0x0105)
+-				! or else old loadlin-1.5 will fail)
+-	.word	0		! default_switch
+-	.word	0		! SETUPSEG
+-	.word	0x1000
+-	.word	0		! pointing to kernel version string
+-	.byte	0		! = 0, old one (LILO, Loadlin,
+-				! 0xTV: T=0 for LILO
+-				!       V = version
+-	.byte	1		! Load flags bzImage=1
+-	.word	0x8000		! size to move, when setup is not
+-	.long	0x100000	! 0x100000 = default for big kernel
+-	.long	0		! address of loaded ramdisk image
+-	.long	0		# its size in bytes
+diff --git a/arch/sh/boot/compressed/head_32.S b/arch/sh/boot/compressed/head_32.S
+new file mode 100644
+index 0000000..a8399b0
+--- /dev/null
++++ b/arch/sh/boot/compressed/head_32.S
+@@ -0,0 +1,120 @@
++/*
++ *  linux/arch/sh/boot/compressed/head.S
++ *
++ *  Copyright (C) 1999 Stuart Menefy
++ *  Copyright (C) 2003 SUGIOKA Toshinobu
++ */
++
++.text
++
++#include <linux/linkage.h>
++#include <asm/page.h>
++
++	.global	startup
++startup:
++	/* Load initial status register */
++	mov.l   init_sr, r1
++	ldc     r1, sr
++
++	/* Move myself to proper location if necessary */
++	mova	1f, r0
++	mov.l	1f, r2
++	cmp/eq	r2, r0
++	bt	clear_bss
++	sub	r0, r2
++	mov.l	bss_start_addr, r0
++	mov	#0xe0, r1
++	and	r1, r0			! align cache line
++	mov.l	text_start_addr, r3
++	mov	r0, r1
++	sub	r2, r1
++3:
++	mov.l	@r1, r4
++	mov.l	@(4,r1), r5
++	mov.l	@(8,r1), r6
++	mov.l	@(12,r1), r7
++	mov.l	@(16,r1), r8
++	mov.l	@(20,r1), r9
++	mov.l	@(24,r1), r10
++	mov.l	@(28,r1), r11
++	mov.l	r4, @r0
++	mov.l	r5, @(4,r0)
++	mov.l	r6, @(8,r0)
++	mov.l	r7, @(12,r0)
++	mov.l	r8, @(16,r0)
++	mov.l	r9, @(20,r0)
++	mov.l	r10, @(24,r0)
++	mov.l	r11, @(28,r0)
++#ifdef CONFIG_CPU_SH4
++	ocbwb	@r0
++#endif
++	cmp/hi	r3, r0
++	add	#-32, r0
++	bt/s	3b
++	 add	#-32, r1
++	mov.l	2f, r0
++	jmp	@r0
++	 nop
++
++	.align 2
++1:	.long	1b
++2:	.long	clear_bss
++text_start_addr:
++	.long	startup
++
++	/* Clear BSS */
++clear_bss:
++	mov.l	end_addr, r1
++	mov.l	bss_start_addr, r2
++	mov	#0, r0
++l1:
++	mov.l	r0, @-r1
++	cmp/eq	r1,r2
++	bf	l1
++
++	/* Set the initial pointer. */
++	mov.l	init_stack_addr, r0
++	mov.l	@r0, r15
++
++	/* Decompress the kernel */
++	mov.l	decompress_kernel_addr, r0
++	jsr	@r0
++	nop
++
++	/* Jump to the start of the decompressed kernel */
++	mov.l	kernel_start_addr, r0
++	jmp	@r0
++	nop
++	
++	.align	2
++bss_start_addr:
++	.long	__bss_start
++end_addr:
++	.long	_end
++init_sr:
++	.long	0x400000F0	/* Privileged mode, Bank=0, Block=0, IMASK=0xF */
++init_stack_addr:
++	.long	stack_start
++decompress_kernel_addr:
++	.long	decompress_kernel
++kernel_start_addr:
++	.long	_text+PAGE_SIZE
++
++	.align	9
++fake_headers_as_bzImage:
++	.word	0
++	.ascii	"HdrS"		! header signature
++	.word	0x0202		! header version number (>= 0x0105)
++				! or else old loadlin-1.5 will fail)
++	.word	0		! default_switch
++	.word	0		! SETUPSEG
++	.word	0x1000
++	.word	0		! pointing to kernel version string
++	.byte	0		! = 0, old one (LILO, Loadlin,
++				! 0xTV: T=0 for LILO
++				!       V = version
++	.byte	1		! Load flags bzImage=1
++	.word	0x8000		! size to move, when setup is not
++	.long	0x100000	! 0x100000 = default for big kernel
++	.long	0		! address of loaded ramdisk image
++	.long	0		# its size in bytes
+diff --git a/arch/sh/boot/compressed/head_64.S b/arch/sh/boot/compressed/head_64.S
+new file mode 100644
+index 0000000..1d4ecbf
+--- /dev/null
++++ b/arch/sh/boot/compressed/head_64.S
+@@ -0,0 +1,163 @@
++/*
++ * 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.
++ *
++ * arch/shmedia/boot/compressed/head.S
++ *
++ * Copied from
++ *   arch/shmedia/kernel/head.S
++ * which carried the copyright:
++ *   Copyright (C) 2000, 2001  Paolo Alberelli
++ *
++ * Modification for compressed loader:
++ *   Copyright (C) 2002 Stuart Menefy (stuart.menefy at st.com)
++ */
++#include <linux/linkage.h>
++#include <asm/cache.h>
++#include <asm/cpu/mmu_context.h>
++#include <asm/cpu/registers.h>
++
++/*
++ * Fixed TLB entries to identity map the beginning of RAM
++ */
++#define MMUIR_TEXT_H	0x0000000000000003 | CONFIG_MEMORY_START
++			/* Enabled, Shared, ASID 0, Eff. Add. 0xA0000000 */
++#define MMUIR_TEXT_L	0x000000000000009a | CONFIG_MEMORY_START
++			/* 512 Mb, Cacheable (Write-back), execute, Not User, Ph. Add. */
++
++#define MMUDR_CACHED_H	0x0000000000000003 | CONFIG_MEMORY_START
++			/* Enabled, Shared, ASID 0, Eff. Add. 0xA0000000 */
++#define MMUDR_CACHED_L	0x000000000000015a | CONFIG_MEMORY_START
++			/* 512 Mb, Cacheable (Write-back), read/write, Not User, Ph. Add. */
++
++#define	ICCR0_INIT_VAL	ICCR0_ON | ICCR0_ICI		/* ICE + ICI */
++#define	ICCR1_INIT_VAL	ICCR1_NOLOCK			/* No locking */
++
++#if 1
++#define	OCCR0_INIT_VAL	OCCR0_ON | OCCR0_OCI | OCCR0_WB	/* OCE + OCI + WB */
++#else
++#define	OCCR0_INIT_VAL	OCCR0_OFF
++#endif
++#define	OCCR1_INIT_VAL	OCCR1_NOLOCK			/* No locking */
++
++	.text
++
++	.global	startup
++startup:
++	/*
++	 * Prevent speculative fetch on device memory due to
++	 * uninitialized target registers.
++	 * This must be executed before the first branch.
++	 */
++	ptabs/u	r63, tr0
++	ptabs/u	r63, tr1
++	ptabs/u	r63, tr2
++	ptabs/u	r63, tr3
++	ptabs/u	r63, tr4
++	ptabs/u	r63, tr5
++	ptabs/u	r63, tr6
++	ptabs/u	r63, tr7
++	synci
++
++	/*
++	 * Set initial TLB entries for cached and uncached regions.
++	 * Note: PTA/BLINK is PIC code, PTABS/BLINK isn't !
++	 */
++	/* Clear ITLBs */
++	pta	1f, tr1
++	movi	ITLB_FIXED, r21
++	movi	ITLB_LAST_VAR_UNRESTRICTED+TLB_STEP, r22
++1:	putcfg	r21, 0, r63		/* Clear MMUIR[n].PTEH.V */
++	addi	r21, TLB_STEP, r21
++        bne	r21, r22, tr1
++
++	/* Clear DTLBs */
++	pta	1f, tr1
++	movi	DTLB_FIXED, r21
++	movi	DTLB_LAST_VAR_UNRESTRICTED+TLB_STEP, r22
++1:	putcfg	r21, 0, r63		/* Clear MMUDR[n].PTEH.V */
++	addi	r21, TLB_STEP, r21
++        bne	r21, r22, tr1
++
++	/* Map one big (512Mb) page for ITLB */
++	movi	ITLB_FIXED, r21
++	movi	MMUIR_TEXT_L, r22	/* PTEL first */
++	putcfg	r21, 1, r22		/* Set MMUIR[0].PTEL */
++	movi	MMUIR_TEXT_H, r22	/* PTEH last */
++	putcfg	r21, 0, r22		/* Set MMUIR[0].PTEH */
++
++	/* Map one big CACHED (512Mb) page for DTLB */
++	movi	DTLB_FIXED, r21
++	movi	MMUDR_CACHED_L, r22	/* PTEL first */
++	putcfg	r21, 1, r22		/* Set MMUDR[0].PTEL */
++	movi	MMUDR_CACHED_H, r22	/* PTEH last */
++	putcfg	r21, 0, r22		/* Set MMUDR[0].PTEH */
++
++	/* ICache */
++	movi	ICCR_BASE, r21
++	movi	ICCR0_INIT_VAL, r22
++	movi	ICCR1_INIT_VAL, r23
++	putcfg	r21, ICCR_REG0, r22
++	putcfg	r21, ICCR_REG1, r23
++	synci
++
++	/* OCache */
++	movi	OCCR_BASE, r21
++	movi	OCCR0_INIT_VAL, r22
++	movi	OCCR1_INIT_VAL, r23
++	putcfg	r21, OCCR_REG0, r22
++	putcfg	r21, OCCR_REG1, r23
++	synco
++
++	/*
++	 * Enable the MMU.
++	 * From here-on code can be non-PIC.
++	 */
++	movi	SR_HARMLESS | SR_ENABLE_MMU, r22
++	putcon	r22, SSR
++	movi	1f, r22
++	putcon	r22, SPC
++	synco
++	rte				/* And now go into the hyperspace ... */
++1:					/* ... that's the next instruction ! */
++
++	/* Set initial stack pointer */
++	movi	datalabel stack_start, r0
++	ld.l	r0, 0, r15
++
++	/*
++	 * Clear bss
++	 */
++	pt	1f, tr1
++	movi	datalabel __bss_start, r22
++	movi	datalabel _end, r23
++1:	st.l	r22, 0, r63
++	addi	r22, 4, r22
++	bne	r22, r23, tr1
++
++	/*
++	 * Decompress the kernel.
++	 */
++	pt	decompress_kernel, tr0
++	blink	tr0, r18
++
++	/*
++	 * Disable the MMU.
++	 */
++	movi	SR_HARMLESS, r22
++	putcon	r22, SSR
++	movi	1f, r22
++	putcon	r22, SPC
++	synco
++	rte				/* And now go into the hyperspace ... */
++1:					/* ... that's the next instruction ! */
++
++	/* Jump into the decompressed kernel */
++	movi	datalabel (CONFIG_MEMORY_START + 0x2000)+1, r19
++	ptabs	r19, tr0
++	blink	tr0, r18
++
++	/* Shouldn't return here, but just in case, loop forever */
++	pt	1f, tr0
++1:	blink	tr0, r63
+diff --git a/arch/sh/boot/compressed/misc.c b/arch/sh/boot/compressed/misc.c
+deleted file mode 100644
+index df65e30..0000000
+--- a/arch/sh/boot/compressed/misc.c
++++ /dev/null
+@@ -1,241 +0,0 @@
+-/*
+- * arch/sh/boot/compressed/misc.c
+- *
+- * This is a collection of several routines from gzip-1.0.3
+- * adapted for Linux.
+- *
+- * malloc by Hannu Savolainen 1993 and Matthias Urlichs 1994
+- *
+- * Adapted for SH by Stuart Menefy, Aug 1999
+- *
+- * Modified to use standard LinuxSH BIOS by Greg Banks 7Jul2000
+- */
+-
+-#include <asm/uaccess.h>
+-#include <asm/addrspace.h>
+-#include <asm/page.h>
+-#ifdef CONFIG_SH_STANDARD_BIOS
+-#include <asm/sh_bios.h>
+-#endif
+-
+-/*
+- * gzip declarations
+- */
+-
+-#define OF(args)  args
+-#define STATIC static
+-
+-#undef memset
+-#undef memcpy
+-#define memzero(s, n)     memset ((s), 0, (n))
+-
+-typedef unsigned char  uch;
+-typedef unsigned short ush;
+-typedef unsigned long  ulg;
+-
+-#define WSIZE 0x8000		/* Window size must be at least 32k, */
+-				/* and a power of two */
+-
+-static uch *inbuf;	     /* input buffer */
+-static uch window[WSIZE];    /* Sliding window buffer */
+-
+-static unsigned insize = 0;  /* valid bytes in inbuf */
+-static unsigned inptr = 0;   /* index of next byte to be processed in inbuf */
+-static unsigned outcnt = 0;  /* bytes in output buffer */
+-
+-/* gzip flag byte */
+-#define ASCII_FLAG   0x01 /* bit 0 set: file probably ASCII text */
+-#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */
+-#define EXTRA_FIELD  0x04 /* bit 2 set: extra field present */
+-#define ORIG_NAME    0x08 /* bit 3 set: original file name present */
+-#define COMMENT      0x10 /* bit 4 set: file comment present */
+-#define ENCRYPTED    0x20 /* bit 5 set: file is encrypted */
+-#define RESERVED     0xC0 /* bit 6,7:   reserved */
+-
+-#define get_byte()  (inptr < insize ? inbuf[inptr++] : fill_inbuf())
+-
+-/* Diagnostic functions */
+-#ifdef DEBUG
+-#  define Assert(cond,msg) {if(!(cond)) error(msg);}
+-#  define Trace(x) fprintf x
+-#  define Tracev(x) {if (verbose) fprintf x ;}
+-#  define Tracevv(x) {if (verbose>1) fprintf x ;}
+-#  define Tracec(c,x) {if (verbose && (c)) fprintf x ;}
+-#  define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;}
+-#else
+-#  define Assert(cond,msg)
+-#  define Trace(x)
+-#  define Tracev(x)
+-#  define Tracevv(x)
+-#  define Tracec(c,x)
+-#  define Tracecv(c,x)
+-#endif
+-
+-static int  fill_inbuf(void);
+-static void flush_window(void);
+-static void error(char *m);
+-static void gzip_mark(void **);
+-static void gzip_release(void **);
+-
+-extern char input_data[];
+-extern int input_len;
+-
+-static long bytes_out = 0;
+-static uch *output_data;
+-static unsigned long output_ptr = 0;
+-
+-static void *malloc(int size);
+-static void free(void *where);
+-static void error(char *m);
+-static void gzip_mark(void **);
+-static void gzip_release(void **);
+-
+-int puts(const char *);
+-
+-extern int _text;		/* Defined in vmlinux.lds.S */
+-extern int _end;
+-static unsigned long free_mem_ptr;
+-static unsigned long free_mem_end_ptr;
+-
+-#define HEAP_SIZE             0x10000
+-
+-#include "../../../../lib/inflate.c"
+-
+-static void *malloc(int size)
+-{
+-	void *p;
+-
+-	if (size <0) error("Malloc error");
+-	if (free_mem_ptr == 0) error("Memory error");
+-
+-	free_mem_ptr = (free_mem_ptr + 3) & ~3;	/* Align */
+-
+-	p = (void *)free_mem_ptr;
+-	free_mem_ptr += size;
+-
+-	if (free_mem_ptr >= free_mem_end_ptr)
+-		error("Out of memory");
+-
+-	return p;
+-}
+-
+-static void free(void *where)
+-{	/* Don't care */
+-}
+-
+-static void gzip_mark(void **ptr)
+-{
+-	*ptr = (void *) free_mem_ptr;
+-}
+-
+-static void gzip_release(void **ptr)
+-{
+-	free_mem_ptr = (long) *ptr;
+-}
+-
+-#ifdef CONFIG_SH_STANDARD_BIOS
+-size_t strlen(const char *s)
+-{
+-	int i = 0;
+-
+-	while (*s++)
+-		i++;
+-	return i;
+-}
+-
+-int puts(const char *s)
+-{
+-	int len = strlen(s);
+-	sh_bios_console_write(s, len);
+-	return len;
+-}
+-#else
+-int puts(const char *s)
+-{
+-	/* This should be updated to use the sh-sci routines */
+-	return 0;
+-}
+-#endif
+-
+-void* memset(void* s, int c, size_t n)
+-{
+-	int i;
+-	char *ss = (char*)s;
+-
+-	for (i=0;i<n;i++) ss[i] = c;
+-	return s;
+-}
+-
+-void* memcpy(void* __dest, __const void* __src,
+-			    size_t __n)
+-{
+-	int i;
+-	char *d = (char *)__dest, *s = (char *)__src;
+-
+-	for (i=0;i<__n;i++) d[i] = s[i];
+-	return __dest;
+-}
+-
+-/* ===========================================================================
+- * Fill the input buffer. This is called only when the buffer is empty
+- * and at least one byte is really needed.
+- */
+-static int fill_inbuf(void)
+-{
+-	if (insize != 0) {
+-		error("ran out of input data");
+-	}
+-
+-	inbuf = input_data;
+-	insize = input_len;
+-	inptr = 1;
+-	return inbuf[0];
+-}
+-
+-/* ===========================================================================
+- * Write the output window window[0..outcnt-1] and update crc and bytes_out.
+- * (Used for the decompressed data only.)
+- */
+-static void flush_window(void)
+-{
+-    ulg c = crc;         /* temporary variable */
+-    unsigned n;
+-    uch *in, *out, ch;
+-
+-    in = window;
+-    out = &output_data[output_ptr];
+-    for (n = 0; n < outcnt; n++) {
+-	    ch = *out++ = *in++;
+-	    c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8);
+-    }
+-    crc = c;
+-    bytes_out += (ulg)outcnt;
+-    output_ptr += (ulg)outcnt;
+-    outcnt = 0;
+-}
+-
+-static void error(char *x)
+-{
+-	puts("\n\n");
+-	puts(x);
+-	puts("\n\n -- System halted");
+-
+-	while(1);	/* Halt */
+-}
+-
+-#define STACK_SIZE (4096)
+-long user_stack [STACK_SIZE];
+-long* stack_start = &user_stack[STACK_SIZE];
+-
+-void decompress_kernel(void)
+-{
+-	output_data = 0;
+-	output_ptr = P2SEGADDR((unsigned long)&_text+PAGE_SIZE);
+-	free_mem_ptr = (unsigned long)&_end;
+-	free_mem_end_ptr = free_mem_ptr + HEAP_SIZE;
+-
+-	makecrc();
+-	puts("Uncompressing Linux... ");
+-	gunzip();
+-	puts("Ok, booting the kernel.\n");
+-}
+diff --git a/arch/sh/boot/compressed/misc_32.c b/arch/sh/boot/compressed/misc_32.c
+new file mode 100644
+index 0000000..adcea31
+--- /dev/null
++++ b/arch/sh/boot/compressed/misc_32.c
+@@ -0,0 +1,244 @@
++/*
++ * arch/sh/boot/compressed/misc.c
++ *
++ * This is a collection of several routines from gzip-1.0.3
++ * adapted for Linux.
++ *
++ * malloc by Hannu Savolainen 1993 and Matthias Urlichs 1994
++ *
++ * Adapted for SH by Stuart Menefy, Aug 1999
++ *
++ * Modified to use standard LinuxSH BIOS by Greg Banks 7Jul2000
++ */
++
++#include <asm/uaccess.h>
++#include <asm/addrspace.h>
++#include <asm/page.h>
++#ifdef CONFIG_SH_STANDARD_BIOS
++#include <asm/sh_bios.h>
++#endif
++
++/*
++ * gzip declarations
++ */
++
++#define OF(args)  args
++#define STATIC static
++
++#undef memset
++#undef memcpy
++#define memzero(s, n)     memset ((s), 0, (n))
++
++typedef unsigned char  uch;
++typedef unsigned short ush;
++typedef unsigned long  ulg;
++
++#define WSIZE 0x8000		/* Window size must be at least 32k, */
++				/* and a power of two */
++
++static uch *inbuf;	     /* input buffer */
++static uch window[WSIZE];    /* Sliding window buffer */
++
++static unsigned insize = 0;  /* valid bytes in inbuf */
++static unsigned inptr = 0;   /* index of next byte to be processed in inbuf */
++static unsigned outcnt = 0;  /* bytes in output buffer */
++
++/* gzip flag byte */
++#define ASCII_FLAG   0x01 /* bit 0 set: file probably ASCII text */
++#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */
++#define EXTRA_FIELD  0x04 /* bit 2 set: extra field present */
++#define ORIG_NAME    0x08 /* bit 3 set: original file name present */
++#define COMMENT      0x10 /* bit 4 set: file comment present */
++#define ENCRYPTED    0x20 /* bit 5 set: file is encrypted */
++#define RESERVED     0xC0 /* bit 6,7:   reserved */
++
++#define get_byte()  (inptr < insize ? inbuf[inptr++] : fill_inbuf())
++
++/* Diagnostic functions */
++#ifdef DEBUG
++#  define Assert(cond,msg) {if(!(cond)) error(msg);}
++#  define Trace(x) fprintf x
++#  define Tracev(x) {if (verbose) fprintf x ;}
++#  define Tracevv(x) {if (verbose>1) fprintf x ;}
++#  define Tracec(c,x) {if (verbose && (c)) fprintf x ;}
++#  define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;}
++#else
++#  define Assert(cond,msg)
++#  define Trace(x)
++#  define Tracev(x)
++#  define Tracevv(x)
++#  define Tracec(c,x)
++#  define Tracecv(c,x)
++#endif
++
++static int  fill_inbuf(void);
++static void flush_window(void);
++static void error(char *m);
++static void gzip_mark(void **);
++static void gzip_release(void **);
++
++extern char input_data[];
++extern int input_len;
++
++static long bytes_out = 0;
++static uch *output_data;
++static unsigned long output_ptr = 0;
++
++static void *malloc(int size);
++static void free(void *where);
++static void error(char *m);
++static void gzip_mark(void **);
++static void gzip_release(void **);
++
++int puts(const char *);
++
++extern int _text;		/* Defined in vmlinux.lds.S */
++extern int _end;
++static unsigned long free_mem_ptr;
++static unsigned long free_mem_end_ptr;
++
++#define HEAP_SIZE             0x10000
++
++#include "../../../../lib/inflate.c"
++
++static void *malloc(int size)
++{
++	void *p;
++
++	if (size <0) error("Malloc error");
++	if (free_mem_ptr == 0) error("Memory error");
++
++	free_mem_ptr = (free_mem_ptr + 3) & ~3;	/* Align */
++
++	p = (void *)free_mem_ptr;
++	free_mem_ptr += size;
++
++	if (free_mem_ptr >= free_mem_end_ptr)
++		error("Out of memory");
++
++	return p;
++}
++
++static void free(void *where)
++{	/* Don't care */
++}
++
++static void gzip_mark(void **ptr)
++{
++	*ptr = (void *) free_mem_ptr;
++}
++
++static void gzip_release(void **ptr)
++{
++	free_mem_ptr = (long) *ptr;
++}
++
++#ifdef CONFIG_SH_STANDARD_BIOS
++size_t strlen(const char *s)
++{
++	int i = 0;
++
++	while (*s++)
++		i++;
++	return i;
++}
++
++int puts(const char *s)
++{
++	int len = strlen(s);
++	sh_bios_console_write(s, len);
++	return len;
++}
++#else
++int puts(const char *s)
++{
++	/* This should be updated to use the sh-sci routines */
++	return 0;
++}
++#endif
++
++void* memset(void* s, int c, size_t n)
++{
++	int i;
++	char *ss = (char*)s;
++
++	for (i=0;i<n;i++) ss[i] = c;
++	return s;
++}
++
++void* memcpy(void* __dest, __const void* __src,
++			    size_t __n)
++{
++	int i;
++	char *d = (char *)__dest, *s = (char *)__src;
++
++	for (i=0;i<__n;i++) d[i] = s[i];
++	return __dest;
++}
++
++/* ===========================================================================
++ * Fill the input buffer. This is called only when the buffer is empty
++ * and at least one byte is really needed.
++ */
++static int fill_inbuf(void)
++{
++	if (insize != 0) {
++		error("ran out of input data");
++	}
++
++	inbuf = input_data;
++	insize = input_len;
++	inptr = 1;
++	return inbuf[0];
++}
++
++/* ===========================================================================
++ * Write the output window window[0..outcnt-1] and update crc and bytes_out.
++ * (Used for the decompressed data only.)
++ */
++static void flush_window(void)
++{
++    ulg c = crc;         /* temporary variable */
++    unsigned n;
++    uch *in, *out, ch;
++
++    in = window;
++    out = &output_data[output_ptr];
++    for (n = 0; n < outcnt; n++) {
++	    ch = *out++ = *in++;
++	    c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8);
++    }
++    crc = c;
++    bytes_out += (ulg)outcnt;
++    output_ptr += (ulg)outcnt;
++    outcnt = 0;
++}
++
++static void error(char *x)
++{
++	puts("\n\n");
++	puts(x);
++	puts("\n\n -- System halted");
++
++	while(1);	/* Halt */
++}
++
++#define STACK_SIZE (4096)
++long user_stack [STACK_SIZE];
++long* stack_start = &user_stack[STACK_SIZE];
++
++void decompress_kernel(void)
++{
++	output_data = 0;
++	output_ptr = PHYSADDR((unsigned long)&_text+PAGE_SIZE);
++#ifdef CONFIG_29BIT
++	output_ptr |= P2SEG;
++#endif
++	free_mem_ptr = (unsigned long)&_end;
++	free_mem_end_ptr = free_mem_ptr + HEAP_SIZE;
++
++	makecrc();
++	puts("Uncompressing Linux... ");
++	gunzip();
++	puts("Ok, booting the kernel.\n");
++}
+diff --git a/arch/sh/boot/compressed/misc_64.c b/arch/sh/boot/compressed/misc_64.c
+new file mode 100644
+index 0000000..a006ef8
+--- /dev/null
++++ b/arch/sh/boot/compressed/misc_64.c
+@@ -0,0 +1,250 @@
++/*
++ * arch/sh/boot/compressed/misc_64.c
++ *
++ * This is a collection of several routines from gzip-1.0.3
++ * adapted for Linux.
++ *
++ * malloc by Hannu Savolainen 1993 and Matthias Urlichs 1994
++ *
++ * Adapted for SHmedia from sh by Stuart Menefy, May 2002
++ */
++
++#include <asm/uaccess.h>
++
++/* cache.c */
++#define CACHE_ENABLE      0
++#define CACHE_DISABLE     1
++int cache_control(unsigned int command);
++
++/*
++ * gzip declarations
++ */
++
++#define OF(args)  args
++#define STATIC static
++
++#undef memset
++#undef memcpy
++#define memzero(s, n)     memset ((s), 0, (n))
++
++typedef unsigned char uch;
++typedef unsigned short ush;
++typedef unsigned long ulg;
++
++#define WSIZE 0x8000		/* Window size must be at least 32k, */
++				/* and a power of two */
++
++static uch *inbuf;		/* input buffer */
++static uch window[WSIZE];	/* Sliding window buffer */
++
++static unsigned insize = 0;	/* valid bytes in inbuf */
++static unsigned inptr = 0;	/* index of next byte to be processed in inbuf */
++static unsigned outcnt = 0;	/* bytes in output buffer */
++
++/* gzip flag byte */
++#define ASCII_FLAG   0x01	/* bit 0 set: file probably ASCII text */
++#define CONTINUATION 0x02	/* bit 1 set: continuation of multi-part gzip file */
++#define EXTRA_FIELD  0x04	/* bit 2 set: extra field present */
++#define ORIG_NAME    0x08	/* bit 3 set: original file name present */
++#define COMMENT      0x10	/* bit 4 set: file comment present */
++#define ENCRYPTED    0x20	/* bit 5 set: file is encrypted */
++#define RESERVED     0xC0	/* bit 6,7:   reserved */
++
++#define get_byte()  (inptr < insize ? inbuf[inptr++] : fill_inbuf())
++
++/* Diagnostic functions */
++#ifdef DEBUG
++#  define Assert(cond,msg) {if(!(cond)) error(msg);}
++#  define Trace(x) fprintf x
++#  define Tracev(x) {if (verbose) fprintf x ;}
++#  define Tracevv(x) {if (verbose>1) fprintf x ;}
++#  define Tracec(c,x) {if (verbose && (c)) fprintf x ;}
++#  define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;}
++#else
++#  define Assert(cond,msg)
++#  define Trace(x)
++#  define Tracev(x)
++#  define Tracevv(x)
++#  define Tracec(c,x)
++#  define Tracecv(c,x)
++#endif
++
++static int fill_inbuf(void);
++static void flush_window(void);
++static void error(char *m);
++static void gzip_mark(void **);
++static void gzip_release(void **);
++
++extern char input_data[];
++extern int input_len;
++
++static long bytes_out = 0;
++static uch *output_data;
++static unsigned long output_ptr = 0;
++
++static void *malloc(int size);
++static void free(void *where);
++static void error(char *m);
++static void gzip_mark(void **);
++static void gzip_release(void **);
++
++static void puts(const char *);
++
++extern int _text;		/* Defined in vmlinux.lds.S */
++extern int _end;
++static unsigned long free_mem_ptr;
++static unsigned long free_mem_end_ptr;
++
++#define HEAP_SIZE             0x10000
++
++#include "../../../../lib/inflate.c"
++
++static void *malloc(int size)
++{
++	void *p;
++
++	if (size < 0)
++		error("Malloc error\n");
++	if (free_mem_ptr == 0)
++		error("Memory error\n");
++
++	free_mem_ptr = (free_mem_ptr + 3) & ~3;	/* Align */
++
++	p = (void *) free_mem_ptr;
++	free_mem_ptr += size;
++
++	if (free_mem_ptr >= free_mem_end_ptr)
++		error("\nOut of memory\n");
++
++	return p;
++}
++
++static void free(void *where)
++{				/* Don't care */
++}
++
++static void gzip_mark(void **ptr)
++{
++	*ptr = (void *) free_mem_ptr;
++}
++
++static void gzip_release(void **ptr)
++{
++	free_mem_ptr = (long) *ptr;
++}
++
++void puts(const char *s)
++{
++}
++
++void *memset(void *s, int c, size_t n)
++{
++	int i;
++	char *ss = (char *) s;
++
++	for (i = 0; i < n; i++)
++		ss[i] = c;
++	return s;
++}
++
++void *memcpy(void *__dest, __const void *__src, size_t __n)
++{
++	int i;
++	char *d = (char *) __dest, *s = (char *) __src;
++
++	for (i = 0; i < __n; i++)
++		d[i] = s[i];
++	return __dest;
++}
++
++/* ===========================================================================
++ * Fill the input buffer. This is called only when the buffer is empty
++ * and at least one byte is really needed.
++ */
++static int fill_inbuf(void)
++{
++	if (insize != 0) {
++		error("ran out of input data\n");
++	}
++
++	inbuf = input_data;
++	insize = input_len;
++	inptr = 1;
++	return inbuf[0];
++}
++
++/* ===========================================================================
++ * Write the output window window[0..outcnt-1] and update crc and bytes_out.
++ * (Used for the decompressed data only.)
++ */
++static void flush_window(void)
++{
++	ulg c = crc;		/* temporary variable */
++	unsigned n;
++	uch *in, *out, ch;
++
++	in = window;
++	out = &output_data[output_ptr];
++	for (n = 0; n < outcnt; n++) {
++		ch = *out++ = *in++;
++		c = crc_32_tab[((int) c ^ ch) & 0xff] ^ (c >> 8);
++	}
++	crc = c;
++	bytes_out += (ulg) outcnt;
++	output_ptr += (ulg) outcnt;
++	outcnt = 0;
++	puts(".");
++}
++
++static void error(char *x)
++{
++	puts("\n\n");
++	puts(x);
++	puts("\n\n -- System halted");
++
++	while (1) ;		/* Halt */
++}
++
++#define STACK_SIZE (4096)
++long __attribute__ ((aligned(8))) user_stack[STACK_SIZE];
++long *stack_start = &user_stack[STACK_SIZE];
++
++void decompress_kernel(void)
++{
++	output_data = (uch *) (CONFIG_MEMORY_START + 0x2000);
++	free_mem_ptr = (unsigned long) &_end;
++	free_mem_end_ptr = free_mem_ptr + HEAP_SIZE;
++
++	makecrc();
++	puts("Uncompressing Linux... ");
++	cache_control(CACHE_ENABLE);
++	gunzip();
++	puts("\n");
++
++#if 0
++	/* When booting from ROM may want to do something like this if the
++	 * boot loader doesn't.
++	 */
++
++	/* Set up the parameters and command line */
++	{
++		volatile unsigned int *parambase =
++		    (int *) (CONFIG_MEMORY_START + 0x1000);
++
++		parambase[0] = 0x1;	/* MOUNT_ROOT_RDONLY */
++		parambase[1] = 0x0;	/* RAMDISK_FLAGS */
++		parambase[2] = 0x0200;	/* ORIG_ROOT_DEV */
++		parambase[3] = 0x0;	/* LOADER_TYPE */
++		parambase[4] = 0x0;	/* INITRD_START */
++		parambase[5] = 0x0;	/* INITRD_SIZE */
++		parambase[6] = 0;
++
++		strcpy((char *) ((int) parambase + 0x100),
++		       "console=ttySC0,38400");
++	}
++#endif
++
++	puts("Ok, booting the kernel.\n");
++
++	cache_control(CACHE_DISABLE);
++}
+diff --git a/arch/sh/boot/compressed/vmlinux_64.lds b/arch/sh/boot/compressed/vmlinux_64.lds
+new file mode 100644
+index 0000000..59c2ef4
+--- /dev/null
++++ b/arch/sh/boot/compressed/vmlinux_64.lds
+@@ -0,0 +1,64 @@
++/*
++ * ld script to make compressed SuperH/shmedia Linux kernel+decompression
++ *		bootstrap
++ * Modified by Stuart Menefy from arch/sh/vmlinux.lds.S written by Niibe Yutaka
++ */
++
++
++#ifdef CONFIG_LITTLE_ENDIAN
++/* OUTPUT_FORMAT("elf32-sh64l-linux", "elf32-sh64l-linux", "elf32-sh64l-linux") */
++#define NOP 0x6ff0fff0
++#else
++/* OUTPUT_FORMAT("elf32-sh64", "elf32-sh64", "elf32-sh64") */
++#define NOP 0xf0fff06f
++#endif
++
++OUTPUT_FORMAT("elf32-sh64-linux")
++OUTPUT_ARCH(sh)
++ENTRY(_start)
++
++#define ALIGNED_GAP(section, align) (((ADDR(section)+SIZEOF(section)+(align)-1) & ~((align)-1))-ADDR(section))
++#define FOLLOWING(section, align) AT (LOADADDR(section) + ALIGNED_GAP(section,align))
++
++SECTIONS
++{
++  _text = .;			/* Text and read-only data */
++
++  .text : {
++	*(.text)
++	*(.text64)
++	*(.text..SHmedia32)
++	*(.fixup)
++	*(.gnu.warning)
++	} = NOP
++  . = ALIGN(4);
++  .rodata : { *(.rodata) }
++
++  /* There is no 'real' reason for eight byte alignment, four would work
++   * as well, but gdb downloads much (*4) faster with this.
++   */
++  . = ALIGN(8);
++  .image : { *(.image) }
++  . = ALIGN(4);
++  _etext = .;			/* End of text section */
++
++  .data :			/* Data */
++	FOLLOWING(.image, 4)
++	{
++	_data = .;
++	*(.data)
++	}
++  _data_image = LOADADDR(.data);/* Address of data section in ROM */
++
++  _edata = .;			/* End of data section */
++
++  .stack : { stack = .;  _stack = .; }
++
++  . = ALIGN(4);
++  __bss_start = .;		/* BSS */
++  .bss : {
++	*(.bss)
++	}
++  . = ALIGN(4);
++  _end = . ;
++}
+diff --git a/arch/sh/cchips/voyagergx/Makefile b/arch/sh/cchips/voyagergx/Makefile
+deleted file mode 100644
+index f73963c..0000000
+--- a/arch/sh/cchips/voyagergx/Makefile
++++ /dev/null
+@@ -1,9 +0,0 @@
+-#
+-# Makefile for VoyagerGX
+-#
+-
+-obj-y	:= irq.o setup.o
+-
+-obj-$(CONFIG_USB_OHCI_HCD)	+= consistent.o
+-
+-EXTRA_CFLAGS += -Werror
+diff --git a/arch/sh/cchips/voyagergx/consistent.c b/arch/sh/cchips/voyagergx/consistent.c
+deleted file mode 100644
+index 07e8b9c..0000000
+--- a/arch/sh/cchips/voyagergx/consistent.c
++++ /dev/null
+@@ -1,121 +0,0 @@
+-/*
+- * arch/sh/cchips/voyagergx/consistent.c
+- *
+- * Copyright (C) 2004  Paul Mundt
+- *
+- * This file is subject to the terms and conditions of the GNU General Public
+- * License.  See the file "COPYING" in the main directory of this archive
+- * for more details.
+- */
+-#include <linux/mm.h>
+-#include <linux/dma-mapping.h>
+-#include <linux/slab.h>
+-#include <linux/list.h>
+-#include <linux/types.h>
+-#include <linux/module.h>
+-#include <linux/device.h>
+-#include <asm/io.h>
+-
+-
+-struct voya_alloc_entry {
+-	struct list_head list;
+-	unsigned long ofs;
+-	unsigned long len;
+-};
+-
+-static DEFINE_SPINLOCK(voya_list_lock);
+-static LIST_HEAD(voya_alloc_list);
+-
+-#define OHCI_SRAM_START	0xb0000000
+-#define OHCI_HCCA_SIZE	0x100
+-#define OHCI_SRAM_SIZE	0x10000
+-
+-#define VOYAGER_OHCI_NAME	"voyager-ohci"
+-
+-void *voyagergx_consistent_alloc(struct device *dev, size_t size,
+-				 dma_addr_t *handle, gfp_t flag)
+-{
+-	struct list_head *list = &voya_alloc_list;
+-	struct voya_alloc_entry *entry;
+-	unsigned long start, end;
+-	unsigned long flags;
+-
+-	/*
+-	 * The SM501 contains an integrated 8051 with its own SRAM.
+-	 * Devices within the cchip can all hook into the 8051 SRAM.
+-	 * We presently use this for the OHCI.
+-	 *
+-	 * Everything else goes through consistent_alloc().
+-	 */
+-	if (!dev || strcmp(dev->driver->name, VOYAGER_OHCI_NAME))
+-		return NULL;
+-
+-	start = OHCI_SRAM_START + OHCI_HCCA_SIZE;
+-
+-	entry = kmalloc(sizeof(struct voya_alloc_entry), GFP_ATOMIC);
+-	if (!entry)
+-		return ERR_PTR(-ENOMEM);
+-
+-	entry->len = (size + 15) & ~15;
+-
+-	/*
+-	 * The basis for this allocator is dwmw2's malloc.. the
+-	 * Matrox allocator :-)
+-	 */
+-	spin_lock_irqsave(&voya_list_lock, flags);
+-	list_for_each(list, &voya_alloc_list) {
+-		struct voya_alloc_entry *p;
+-
+-		p = list_entry(list, struct voya_alloc_entry, list);
+-
+-		if (p->ofs - start >= size)
+-			goto out;
+-
+-		start = p->ofs + p->len;
+-	}
+-
+-	end  = start + (OHCI_SRAM_SIZE  - OHCI_HCCA_SIZE);
+-	list = &voya_alloc_list;
+-
+-	if (end - start >= size) {
+-out:
+-		entry->ofs = start;
+-		list_add_tail(&entry->list, list);
+-		spin_unlock_irqrestore(&voya_list_lock, flags);
+-
+-		*handle = start;
+-		return (void *)start;
+-	}
+-
+-	kfree(entry);
+-	spin_unlock_irqrestore(&voya_list_lock, flags);
+-
+-	return ERR_PTR(-EINVAL);
+-}
+-
+-int voyagergx_consistent_free(struct device *dev, size_t size,
+-			      void *vaddr, dma_addr_t handle)
+-{
+-	struct voya_alloc_entry *entry;
+-	unsigned long flags;
+-
+-	if (!dev || strcmp(dev->driver->name, VOYAGER_OHCI_NAME))
+-		return -EINVAL;
+-
+-	spin_lock_irqsave(&voya_list_lock, flags);
+-	list_for_each_entry(entry, &voya_alloc_list, list) {
+-		if (entry->ofs != handle)
+-			continue;
+-
+-		list_del(&entry->list);
+-		kfree(entry);
+-
+-		break;
+-	}
+-	spin_unlock_irqrestore(&voya_list_lock, flags);
+-
+-	return 0;
+-}
+-
+-EXPORT_SYMBOL(voyagergx_consistent_alloc);
+-EXPORT_SYMBOL(voyagergx_consistent_free);
+diff --git a/arch/sh/cchips/voyagergx/irq.c b/arch/sh/cchips/voyagergx/irq.c
+deleted file mode 100644
+index ade3038..0000000
+--- a/arch/sh/cchips/voyagergx/irq.c
++++ /dev/null
+@@ -1,101 +0,0 @@
+-/* -------------------------------------------------------------------- */
+-/* setup_voyagergx.c:                                                     */
+-/* -------------------------------------------------------------------- */
+-/*  This program is free software; you can redistribute it and/or modify
+-    it under the terms of the GNU General Public License as published by
+-    the Free Software Foundation; either version 2 of the License, or
+-    (at your option) any later version.
+-
+-    This program is distributed in the hope that it will be useful,
+-    but WITHOUT ANY WARRANTY; without even the implied warranty of
+-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+-    GNU General Public License for more details.
+-
+-    You should have received a copy of the GNU General Public License
+-    along with this program; if not, write to the Free Software
+-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+-
+-    Copyright 2003 (c) Lineo uSolutions,Inc.
+-*/
+-#include <linux/interrupt.h>
+-#include <linux/init.h>
+-#include <linux/io.h>
+-#include <asm/voyagergx.h>
+-#include <asm/rts7751r2d.h>
+-
+-enum {
+-	UNUSED = 0,
+-
+-	/* voyager specific interrupt sources */
+-	UP, G54, G53, G52, G51, G50, G49, G48,
+-	I2C, PW, DMA, PCI, I2S, AC, US,
+-	U1, U0, CV, MC, S1, S0,
+-	UH, TWOD, ZD, PV, CI,
+-};
+-
+-static struct intc_vect vectors[] __initdata = {
+-	INTC_IRQ(UP, IRQ_SM501_UP), INTC_IRQ(G54, IRQ_SM501_G54),
+-	INTC_IRQ(G53, IRQ_SM501_G53), INTC_IRQ(G52, IRQ_SM501_G52),
+-	INTC_IRQ(G51, IRQ_SM501_G51), INTC_IRQ(G50, IRQ_SM501_G50),
+-	INTC_IRQ(G49, IRQ_SM501_G49), INTC_IRQ(G48, IRQ_SM501_G48),
+-	INTC_IRQ(I2C, IRQ_SM501_I2C), INTC_IRQ(PW, IRQ_SM501_PW),
+-	INTC_IRQ(DMA, IRQ_SM501_DMA), INTC_IRQ(PCI, IRQ_SM501_PCI),
+-	INTC_IRQ(I2S, IRQ_SM501_I2S), INTC_IRQ(AC, IRQ_SM501_AC),
+-	INTC_IRQ(US, IRQ_SM501_US), INTC_IRQ(U1, IRQ_SM501_U1),
+-	INTC_IRQ(U0, IRQ_SM501_U0), INTC_IRQ(CV, IRQ_SM501_CV),
+-	INTC_IRQ(MC, IRQ_SM501_MC), INTC_IRQ(S1, IRQ_SM501_S1),
+-	INTC_IRQ(S0, IRQ_SM501_S0), INTC_IRQ(UH, IRQ_SM501_UH),
+-	INTC_IRQ(TWOD, IRQ_SM501_2D), INTC_IRQ(ZD, IRQ_SM501_ZD),
+-	INTC_IRQ(PV, IRQ_SM501_PV), INTC_IRQ(CI, IRQ_SM501_CI),
+-};
+-
+-static struct intc_mask_reg mask_registers[] __initdata = {
+-	{ VOYAGER_INT_MASK, 0, 32, /* "Interrupt Mask", MMIO_base + 0x30 */
+-	  { UP, G54, G53, G52, G51, G50, G49, G48,
+-	    I2C, PW, 0, DMA, PCI, I2S, AC, US,
+-	    0, 0, U1, U0, CV, MC, S1, S0,
+-	    0, UH, 0, 0, TWOD, ZD, PV, CI } },
+-};
+-
+-static DECLARE_INTC_DESC(intc_desc, "voyagergx", vectors,
+-			 NULL, NULL, mask_registers, NULL, NULL);
+-
+-static unsigned int voyagergx_stat2irq[32] = {
+-	IRQ_SM501_CI, IRQ_SM501_PV, IRQ_SM501_ZD, IRQ_SM501_2D,
+-	0, 0, IRQ_SM501_UH, 0,
+-	IRQ_SM501_S0, IRQ_SM501_S1, IRQ_SM501_MC, IRQ_SM501_CV,
+-	IRQ_SM501_U0, IRQ_SM501_U1, 0, 0,
+-	IRQ_SM501_US, IRQ_SM501_AC, IRQ_SM501_I2S, IRQ_SM501_PCI,
+-	IRQ_SM501_DMA, 0, IRQ_SM501_PW, IRQ_SM501_I2C,
+-	IRQ_SM501_G48, IRQ_SM501_G49, IRQ_SM501_G50, IRQ_SM501_G51,
+-	IRQ_SM501_G52, IRQ_SM501_G53, IRQ_SM501_G54, IRQ_SM501_UP
+-};
+-
+-static void voyagergx_irq_demux(unsigned int irq, struct irq_desc *desc)
+-{
+-	unsigned long intv = ctrl_inl(INT_STATUS);
+-	struct irq_desc *ext_desc;
+-	unsigned int ext_irq;
+-	unsigned int k = 0;
+-
+-	while (intv) {
+-		ext_irq = voyagergx_stat2irq[k];
+-		if (ext_irq && (intv & 1)) {
+-			ext_desc = irq_desc + ext_irq;
+-			handle_level_irq(ext_irq, ext_desc);
+-		}
+-		intv >>= 1;
+-		k++;
+-	}
+-}
+-
+-void __init setup_voyagergx_irq(void)
+-{
+-	printk(KERN_INFO "VoyagerGX on irq %d (mapped into %d to %d)\n",
+-	       IRQ_VOYAGER,
+-	       VOYAGER_IRQ_BASE,
+-	       VOYAGER_IRQ_BASE + VOYAGER_IRQ_NUM - 1);
+-
+-	register_intc_controller(&intc_desc);
+-	set_irq_chained_handler(IRQ_VOYAGER, voyagergx_irq_demux);
+-}
+diff --git a/arch/sh/cchips/voyagergx/setup.c b/arch/sh/cchips/voyagergx/setup.c
+deleted file mode 100644
+index 33f0302..0000000
+--- a/arch/sh/cchips/voyagergx/setup.c
++++ /dev/null
+@@ -1,37 +0,0 @@
+-/*
+- * arch/sh/cchips/voyagergx/setup.c
+- *
+- * Setup routines for VoyagerGX cchip.
+- *
+- * Copyright (C) 2003 Lineo uSolutions, Inc.
+- *
+- * This program is free software; you can redistribute it and/or modify it
+- * under the terms of the GNU General Public License as published by the
+- * Free Software Foundation; either version 2 of the License, or (at your
+- * option) any later version.
+- */
+-#include <linux/init.h>
+-#include <linux/module.h>
+-#include <asm/io.h>
+-#include <asm/voyagergx.h>
+-
+-static int __init setup_voyagergx(void)
+-{
+-	unsigned long val;
+-
+-	val = readl((void __iomem *)DRAM_CTRL);
+-	val |= (DRAM_CTRL_CPU_COLUMN_SIZE_256	|
+-		DRAM_CTRL_CPU_ACTIVE_PRECHARGE	|
+-		DRAM_CTRL_CPU_RESET		|
+-		DRAM_CTRL_REFRESH_COMMAND	|
+-		DRAM_CTRL_BLOCK_WRITE_TIME	|
+-		DRAM_CTRL_BLOCK_WRITE_PRECHARGE	|
+-		DRAM_CTRL_ACTIVE_PRECHARGE	|
+-		DRAM_CTRL_RESET			|
+-		DRAM_CTRL_REMAIN_ACTIVE);
+-	writel(val, (void __iomem *)DRAM_CTRL);
+-
+-	return 0;
+-}
+-
+-module_init(setup_voyagergx);
+diff --git a/arch/sh/configs/cayman_defconfig b/arch/sh/configs/cayman_defconfig
+new file mode 100644
+index 0000000..a05b278
+--- /dev/null
++++ b/arch/sh/configs/cayman_defconfig
+@@ -0,0 +1,1166 @@
++#
++# Automatically generated make config: don't edit
++# Linux kernel version: 2.6.24-rc3
++# Fri Nov 23 14:15:55 2007
++#
++CONFIG_SUPERH=y
++# CONFIG_SUPERH32 is not set
++CONFIG_SUPERH64=y
++CONFIG_RWSEM_GENERIC_SPINLOCK=y
++CONFIG_GENERIC_FIND_NEXT_BIT=y
++CONFIG_GENERIC_HWEIGHT=y
++CONFIG_GENERIC_HARDIRQS=y
++CONFIG_GENERIC_IRQ_PROBE=y
++CONFIG_GENERIC_CALIBRATE_DELAY=y
++# CONFIG_GENERIC_TIME is not set
++# CONFIG_GENERIC_CLOCKEVENTS is not set
++CONFIG_SYS_SUPPORTS_PCI=y
++CONFIG_STACKTRACE_SUPPORT=y
++CONFIG_LOCKDEP_SUPPORT=y
++# CONFIG_ARCH_HAS_ILOG2_U32 is not set
++# CONFIG_ARCH_HAS_ILOG2_U64 is not set
++CONFIG_ARCH_NO_VIRT_TO_BUS=y
++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=y
++CONFIG_SWAP=y
++# CONFIG_SYSVIPC is not set
++CONFIG_POSIX_MQUEUE=y
++# CONFIG_BSD_PROCESS_ACCT is not set
++# CONFIG_TASKSTATS is not set
++# CONFIG_USER_NS is not set
++# CONFIG_PID_NS is not set
++# CONFIG_AUDIT is not set
++# CONFIG_IKCONFIG is not set
++CONFIG_LOG_BUF_SHIFT=14
++# CONFIG_CGROUPS is not set
++CONFIG_FAIR_GROUP_SCHED=y
++CONFIG_FAIR_USER_SCHED=y
++# CONFIG_FAIR_CGROUP_SCHED is not set
++CONFIG_SYSFS_DEPRECATED=y
++# CONFIG_RELAY is not set
++# CONFIG_BLK_DEV_INITRD is not set
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
++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_BASE_FULL=y
++CONFIG_FUTEX=y
++CONFIG_ANON_INODES=y
++CONFIG_EPOLL=y
++CONFIG_SIGNALFD=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_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"
++
++#
++# System type
++#
++CONFIG_CPU_SH5=y
++# CONFIG_CPU_SUBTYPE_SH7619 is not set
++# CONFIG_CPU_SUBTYPE_SH7206 is not set
++# CONFIG_CPU_SUBTYPE_SH7705 is not set
++# CONFIG_CPU_SUBTYPE_SH7706 is not set
++# CONFIG_CPU_SUBTYPE_SH7707 is not set
++# CONFIG_CPU_SUBTYPE_SH7708 is not set
++# CONFIG_CPU_SUBTYPE_SH7709 is not set
++# CONFIG_CPU_SUBTYPE_SH7710 is not set
++# CONFIG_CPU_SUBTYPE_SH7712 is not set
++# CONFIG_CPU_SUBTYPE_SH7720 is not set
++# CONFIG_CPU_SUBTYPE_SH7750 is not set
++# CONFIG_CPU_SUBTYPE_SH7091 is not set
++# CONFIG_CPU_SUBTYPE_SH7750R is not set
++# CONFIG_CPU_SUBTYPE_SH7750S is not set
++# CONFIG_CPU_SUBTYPE_SH7751 is not set
++# CONFIG_CPU_SUBTYPE_SH7751R is not set
++# CONFIG_CPU_SUBTYPE_SH7760 is not set
++# CONFIG_CPU_SUBTYPE_SH4_202 is not set
++# CONFIG_CPU_SUBTYPE_SH7770 is not set
++# CONFIG_CPU_SUBTYPE_SH7780 is not set
++# CONFIG_CPU_SUBTYPE_SH7785 is not set
++# CONFIG_CPU_SUBTYPE_SHX3 is not set
++# CONFIG_CPU_SUBTYPE_SH7343 is not set
++# CONFIG_CPU_SUBTYPE_SH7722 is not set
++CONFIG_CPU_SUBTYPE_SH5_101=y
++# CONFIG_CPU_SUBTYPE_SH5_103 is not set
++
++#
++# Memory management options
++#
++CONFIG_QUICKLIST=y
++CONFIG_MMU=y
++CONFIG_PAGE_OFFSET=0x20000000
++CONFIG_MEMORY_START=0x80000000
++CONFIG_MEMORY_SIZE=0x00400000
++CONFIG_32BIT=y
++CONFIG_ARCH_FLATMEM_ENABLE=y
++CONFIG_ARCH_SPARSEMEM_ENABLE=y
++CONFIG_ARCH_SPARSEMEM_DEFAULT=y
++CONFIG_MAX_ACTIVE_REGIONS=1
++CONFIG_ARCH_POPULATES_NODE_MAP=y
++CONFIG_ARCH_SELECT_MEMORY_MODEL=y
++CONFIG_PAGE_SIZE_4KB=y
++# CONFIG_PAGE_SIZE_8KB is not set
++# CONFIG_PAGE_SIZE_64KB is not set
++CONFIG_HUGETLB_PAGE_SIZE_64K=y
++# CONFIG_HUGETLB_PAGE_SIZE_256K is not set
++# CONFIG_HUGETLB_PAGE_SIZE_1MB is not set
++# CONFIG_HUGETLB_PAGE_SIZE_4MB is not set
++# CONFIG_HUGETLB_PAGE_SIZE_64MB is not set
++# CONFIG_HUGETLB_PAGE_SIZE_512MB 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=y
++# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
++CONFIG_SPLIT_PTLOCK_CPUS=4
++CONFIG_RESOURCES_64BIT=y
++CONFIG_ZONE_DMA_FLAG=0
++CONFIG_NR_QUICK=2
++
++#
++# Cache configuration
++#
++# CONFIG_SH_DIRECT_MAPPED is not set
++# CONFIG_CACHE_WRITEBACK is not set
++# CONFIG_CACHE_WRITETHROUGH is not set
++CONFIG_CACHE_OFF=y
++
++#
++# Processor features
++#
++CONFIG_CPU_LITTLE_ENDIAN=y
++# CONFIG_CPU_BIG_ENDIAN is not set
++CONFIG_SH_FPU=y
++# CONFIG_SH64_FPU_DENORM_FLUSH is not set
++CONFIG_SH64_USER_MISALIGNED_FIXUP=y
++CONFIG_SH64_ID2815_WORKAROUND=y
++CONFIG_CPU_HAS_FPU=y
++
++#
++# Board support
++#
++CONFIG_SH_CAYMAN=y
++
++#
++# Timer and clock configuration
++#
++CONFIG_SH_TIMER_IRQ=16
++CONFIG_SH_PCLK_FREQ=50000000
++# CONFIG_TICK_ONESHOT is not set
++
++#
++# CPU Frequency scaling
++#
++# CONFIG_CPU_FREQ is not set
++
++#
++# DMA support
++#
++
++#
++# Companion Chips
++#
++
++#
++# Additional SuperH Device Drivers
++#
++CONFIG_HEARTBEAT=y
++# CONFIG_PUSH_SWITCH is not set
++
++#
++# Kernel features
++#
++# 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_KEXEC is not set
++# CONFIG_CRASH_DUMP is not set
++# CONFIG_PREEMPT_NONE is not set
++# CONFIG_PREEMPT_VOLUNTARY is not set
++CONFIG_PREEMPT=y
++CONFIG_PREEMPT_BKL=y
++CONFIG_GUSA=y
++
++#
++# Boot options
++#
++CONFIG_ZERO_PAGE_OFFSET=0x00001000
++CONFIG_BOOT_LINK_OFFSET=0x00800000
++# CONFIG_CMDLINE_BOOL is not set
++
++#
++# Bus options
++#
++CONFIG_PCI=y
++CONFIG_SH_PCIDMA_NONCOHERENT=y
++CONFIG_PCI_AUTO=y
++CONFIG_PCI_AUTO_UPDATE_RESOURCES=y
++# CONFIG_ARCH_SUPPORTS_MSI is not set
++CONFIG_PCI_LEGACY=y
++# CONFIG_PCI_DEBUG is not set
++# CONFIG_PCCARD is not set
++# CONFIG_HOTPLUG_PCI is not set
++
++#
++# Executable file formats
++#
++CONFIG_BINFMT_ELF=y
++# CONFIG_BINFMT_MISC 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_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 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=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_INET6_XFRM_TUNNEL is not set
++# CONFIG_INET6_TUNNEL 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_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_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_BLK_DEV=y
++# CONFIG_BLK_CPQ_CISS_DA is not set
++# CONFIG_BLK_DEV_DAC960 is not set
++# CONFIG_BLK_DEV_UMEM is not set
++# CONFIG_BLK_DEV_COW_COMMON is not set
++CONFIG_BLK_DEV_LOOP=y
++# CONFIG_BLK_DEV_CRYPTOLOOP is not set
++# CONFIG_BLK_DEV_NBD is not set
++# CONFIG_BLK_DEV_SX8 is not set
++CONFIG_BLK_DEV_RAM=y
++CONFIG_BLK_DEV_RAM_COUNT=16
++CONFIG_BLK_DEV_RAM_SIZE=4096
++CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
++# CONFIG_CDROM_PKTCDVD is not set
++# CONFIG_ATA_OVER_ETH is not set
++CONFIG_MISC_DEVICES=y
++# CONFIG_PHANTOM is not set
++# CONFIG_EEPROM_93CX6 is not set
++# CONFIG_SGI_IOC4 is not set
++# CONFIG_TIFM_CORE is not set
++# 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=y
++# 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_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_STEX is not set
++# CONFIG_SCSI_SYM53C8XX_2 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_ATA 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_IP1000 is not set
++# CONFIG_ARCNET is not set
++# CONFIG_PHYLIB is not set
++CONFIG_NET_ETHERNET=y
++# CONFIG_MII is not set
++# CONFIG_AX88796 is not set
++# CONFIG_STNIC 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_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 is not set
++# CONFIG_B44 is not set
++CONFIG_NETDEV_1000=y
++# CONFIG_ACENIC is not set
++# CONFIG_DL2K is not set
++# CONFIG_E1000 is not set
++# CONFIG_E1000E is not set
++# CONFIG_NS83820 is not set
++# CONFIG_HAMACHI is not set
++# CONFIG_YELLOWFIN is not set
++# CONFIG_R8169 is not set
++# CONFIG_SIS190 is not set
++# CONFIG_SKGE is not set
++# CONFIG_SKY2 is not set
++# CONFIG_SK98LIN is not set
++# CONFIG_VIA_VELOCITY is not set
++# CONFIG_TIGON3 is not set
++# CONFIG_BNX2 is not set
++# CONFIG_QLA3XXX is not set
++# CONFIG_ATL1 is not set
++CONFIG_NETDEV_10000=y
++# CONFIG_CHELSIO_T1 is not set
++# CONFIG_CHELSIO_T3 is not set
++# CONFIG_IXGBE is not set
++# CONFIG_IXGB is not set
++# CONFIG_S2IO is not set
++# CONFIG_MYRI10GE is not set
++# CONFIG_NETXEN_NIC is not set
++# CONFIG_NIU is not set
++# CONFIG_MLX4_CORE is not set
++# CONFIG_TEHUTI is not set
++# CONFIG_TR is not set
++
++#
++# Wireless LAN
++#
++# CONFIG_WLAN_PRE80211 is not set
++# CONFIG_WLAN_80211 is not set
++# CONFIG_WAN is not set
++# CONFIG_FDDI is not set
++# CONFIG_HIPPI is not set
++# CONFIG_PPP is not set
++# CONFIG_SLIP is not set
++# CONFIG_NET_FC is not set
++# CONFIG_SHAPER is not set
++# CONFIG_NETCONSOLE is not set
++# CONFIG_NETPOLL is not set
++# CONFIG_NET_POLL_CONTROLLER is not set
++# 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=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_VT_CONSOLE=y
++CONFIG_HW_CONSOLE=y
++# CONFIG_VT_HW_CONSOLE_BINDING is not set
++# CONFIG_SERIAL_NONSTANDARD is not set
++
++#
++# Serial drivers
++#
++# CONFIG_SERIAL_8250 is not set
++
++#
++# Non-8250 serial port support
++#
++# CONFIG_SERIAL_SH_SCI is not set
++# CONFIG_SERIAL_JSM 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=y
++# CONFIG_R3964 is not set
++# CONFIG_APPLICOM is not set
++# CONFIG_RAW_DRIVER is not set
++# CONFIG_TCG_TPM is not set
++CONFIG_DEVPORT=y
++CONFIG_I2C=m
++CONFIG_I2C_BOARDINFO=y
++# CONFIG_I2C_CHARDEV is not set
++
++#
++# I2C Algorithms
++#
++# CONFIG_I2C_ALGOBIT is not set
++# CONFIG_I2C_ALGOPCF is not set
++# CONFIG_I2C_ALGOPCA is not set
++
++#
++# I2C Hardware Bus support
++#
++# CONFIG_I2C_ALI1535 is not set
++# CONFIG_I2C_ALI1563 is not set
++# CONFIG_I2C_ALI15X3 is not set
++# CONFIG_I2C_AMD756 is not set
++# CONFIG_I2C_AMD8111 is not set
++# CONFIG_I2C_I801 is not set
++# CONFIG_I2C_I810 is not set
++# CONFIG_I2C_PIIX4 is not set
++# CONFIG_I2C_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_VIA is not set
++# CONFIG_I2C_VIAPRO is not set
++# CONFIG_I2C_VOODOO3 is not set
++
++#
++# Miscellaneous I2C Chip support
++#
++# CONFIG_SENSORS_DS1337 is not set
++# CONFIG_SENSORS_DS1374 is not set
++# CONFIG_DS1682 is not set
++# CONFIG_SENSORS_EEPROM is not set
++# CONFIG_SENSORS_PCF8574 is not set
++# CONFIG_SENSORS_PCA9539 is not set
++# CONFIG_SENSORS_PCF8591 is not set
++# CONFIG_SENSORS_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
++
++#
++# SPI support
++#
++# CONFIG_SPI is not set
++# CONFIG_SPI_MASTER 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_ATXP1 is not set
++# CONFIG_SENSORS_DS1621 is not set
++# CONFIG_SENSORS_I5K_AMB 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_SIS5595 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_THMC50 is not set
++# CONFIG_SENSORS_VIA686A is not set
++# CONFIG_SENSORS_VT1211 is not set
++# CONFIG_SENSORS_VT8231 is not set
++# CONFIG_SENSORS_W83781D is not set
++# CONFIG_SENSORS_W83791D is not set
++# CONFIG_SENSORS_W83792D is not set
++# CONFIG_SENSORS_W83793 is not set
++# CONFIG_SENSORS_W83L785TS is not set
++# CONFIG_SENSORS_W83627HF is not set
++# CONFIG_SENSORS_W83627EHF is not set
++# CONFIG_HWMON_DEBUG_CHIP is not set
++CONFIG_WATCHDOG=y
++# CONFIG_WATCHDOG_NOWAYOUT is not set
++
++#
++# Watchdog Device Drivers
++#
++# CONFIG_SOFT_WATCHDOG is not set
++
++#
++# PCI-based Watchdog Cards
++#
++# CONFIG_PCIPCWATCHDOG is not set
++# CONFIG_WDTPCI is not set
++
++#
++# Sonics Silicon Backplane
++#
++CONFIG_SSB_POSSIBLE=y
++# CONFIG_SSB is not set
++
++#
++# Multifunction device drivers
++#
++# CONFIG_MFD_SM501 is not set
++
++#
++# Multimedia devices
++#
++CONFIG_VIDEO_DEV=m
++# CONFIG_VIDEO_V4L1 is not set
++# CONFIG_VIDEO_V4L1_COMPAT is not set
++CONFIG_VIDEO_V4L2=y
++CONFIG_VIDEO_CAPTURE_DRIVERS=y
++# CONFIG_VIDEO_ADV_DEBUG is not set
++CONFIG_VIDEO_HELPER_CHIPS_AUTO=y
++# CONFIG_VIDEO_VIVI is not set
++# CONFIG_VIDEO_SAA5246A is not set
++# CONFIG_VIDEO_SAA5249 is not set
++# CONFIG_VIDEO_SAA7134 is not set
++# CONFIG_VIDEO_HEXIUM_ORION is not set
++# CONFIG_VIDEO_HEXIUM_GEMINI is not set
++# CONFIG_VIDEO_CX88 is not set
++# CONFIG_VIDEO_CX23885 is not set
++# CONFIG_VIDEO_CAFE_CCIC is not set
++# CONFIG_RADIO_ADAPTERS is not set
++CONFIG_DVB_CORE=y
++# CONFIG_DVB_CORE_ATTACH is not set
++CONFIG_DVB_CAPTURE_DRIVERS=y
++
++#
++# Supported SAA7146 based PCI Adapters
++#
++
++#
++# Supported FlexCopII (B2C2) Adapters
++#
++# CONFIG_DVB_B2C2_FLEXCOP is not set
++
++#
++# Supported BT878 Adapters
++#
++
++#
++# Supported Pluto2 Adapters
++#
++# CONFIG_DVB_PLUTO2 is not set
++
++#
++# Supported DVB Frontends
++#
++
++#
++# Customise DVB Frontends
++#
++# CONFIG_DVB_FE_CUSTOMISE is not set
++
++#
++# DVB-S (satellite) frontends
++#
++# CONFIG_DVB_STV0299 is not set
++# CONFIG_DVB_CX24110 is not set
++# CONFIG_DVB_CX24123 is not set
++# CONFIG_DVB_TDA8083 is not set
++# CONFIG_DVB_MT312 is not set
++# CONFIG_DVB_VES1X93 is not set
++# CONFIG_DVB_S5H1420 is not set
++# CONFIG_DVB_TDA10086 is not set
++
++#
++# DVB-T (terrestrial) frontends
++#
++# CONFIG_DVB_SP8870 is not set
++# CONFIG_DVB_SP887X is not set
++# CONFIG_DVB_CX22700 is not set
++# CONFIG_DVB_CX22702 is not set
++# CONFIG_DVB_L64781 is not set
++# CONFIG_DVB_TDA1004X is not set
++# CONFIG_DVB_NXT6000 is not set
++# CONFIG_DVB_MT352 is not set
++# CONFIG_DVB_ZL10353 is not set
++# CONFIG_DVB_DIB3000MB is not set
++# CONFIG_DVB_DIB3000MC is not set
++# CONFIG_DVB_DIB7000M is not set
++# CONFIG_DVB_DIB7000P is not set
++
++#
++# DVB-C (cable) frontends
++#
++# CONFIG_DVB_VES1820 is not set
++# CONFIG_DVB_TDA10021 is not set
++# CONFIG_DVB_TDA10023 is not set
++# CONFIG_DVB_STV0297 is not set
++
++#
++# ATSC (North American/Korean Terrestrial/Cable DTV) frontends
++#
++# CONFIG_DVB_NXT200X is not set
++# CONFIG_DVB_OR51211 is not set
++# CONFIG_DVB_OR51132 is not set
++# CONFIG_DVB_BCM3510 is not set
++# CONFIG_DVB_LGDT330X is not set
++# CONFIG_DVB_S5H1409 is not set
++
++#
++# Tuners/PLL support
++#
++# CONFIG_DVB_PLL is not set
++# CONFIG_DVB_TDA826X is not set
++# CONFIG_DVB_TDA827X is not set
++# CONFIG_DVB_TUNER_QT1010 is not set
++# CONFIG_DVB_TUNER_MT2060 is not set
++# CONFIG_DVB_TUNER_MT2266 is not set
++# CONFIG_DVB_TUNER_MT2131 is not set
++# CONFIG_DVB_TUNER_DIB0070 is not set
++
++#
++# Miscellaneous devices
++#
++# CONFIG_DVB_LNBP21 is not set
++# CONFIG_DVB_ISL6421 is not set
++# CONFIG_DVB_TUA6100 is not set
++CONFIG_DAB=y
++
++#
++# Graphics support
++#
++# CONFIG_DRM is not set
++# CONFIG_VGASTATE is not set
++CONFIG_VIDEO_OUTPUT_CONTROL=y
++CONFIG_FB=y
++CONFIG_FIRMWARE_EDID=y
++# CONFIG_FB_DDC is not set
++# CONFIG_FB_CFB_FILLRECT is not set
++# CONFIG_FB_CFB_COPYAREA is not set
++# CONFIG_FB_CFB_IMAGEBLIT is not set
++# 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_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=y
++# 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_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_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 is not set
++CONFIG_FONT_8x16=y
++# 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=y
++# CONFIG_LOGO_LINUX_MONO is not set
++# CONFIG_LOGO_LINUX_VGA16 is not set
++# CONFIG_LOGO_LINUX_CLUT224 is not set
++# CONFIG_LOGO_SUPERH_MONO is not set
++# CONFIG_LOGO_SUPERH_VGA16 is not set
++CONFIG_LOGO_SUPERH_CLUT224=y
++
++#
++# Sound
++#
++# CONFIG_SOUND is not set
++CONFIG_HID_SUPPORT=y
++CONFIG_HID=y
++# CONFIG_HID_DEBUG is not set
++# CONFIG_HIDRAW 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 is not set
++
++#
++# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
++#
++
++#
++# USB Gadget Support
++#
++# CONFIG_USB_GADGET is not set
++# CONFIG_MMC is not set
++# CONFIG_NEW_LEDS is not set
++# CONFIG_INFINIBAND is not set
++# CONFIG_RTC_CLASS is not set
++
++#
++# Userspace I/O
++#
++# 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_JBD_DEBUG is not set
++CONFIG_FS_MBCACHE=y
++# CONFIG_REISERFS_FS is not set
++# CONFIG_JFS_FS is not set
++# CONFIG_FS_POSIX_ACL is not set
++# CONFIG_XFS_FS is not set
++# CONFIG_GFS2_FS is not set
++# CONFIG_OCFS2_FS is not set
++CONFIG_MINIX_FS=y
++CONFIG_ROMFS_FS=y
++CONFIG_INOTIFY=y
++CONFIG_INOTIFY_USER=y
++# CONFIG_QUOTA is not set
++CONFIG_DNOTIFY=y
++# CONFIG_AUTOFS_FS is not set
++# CONFIG_AUTOFS4_FS is not set
++# CONFIG_FUSE_FS is not set
++
++#
++# CD-ROM/DVD Filesystems
++#
++# CONFIG_ISO9660_FS is not set
++# CONFIG_UDF_FS is not set
++
++#
++# DOS/FAT/NT Filesystems
++#
++# CONFIG_MSDOS_FS is not set
++# CONFIG_VFAT_FS is not set
++# CONFIG_NTFS_FS is not set
++
++#
++# Pseudo filesystems
++#
++CONFIG_PROC_FS=y
++CONFIG_PROC_KCORE=y
++CONFIG_PROC_SYSCTL=y
++CONFIG_SYSFS=y
++CONFIG_TMPFS=y
++# CONFIG_TMPFS_POSIX_ACL is not set
++CONFIG_HUGETLBFS=y
++CONFIG_HUGETLB_PAGE=y
++# CONFIG_CONFIGFS_FS is not set
++
++#
++# Miscellaneous filesystems
++#
++# CONFIG_ADFS_FS is not set
++# CONFIG_AFFS_FS is not set
++# CONFIG_HFS_FS is not set
++# CONFIG_HFSPLUS_FS is not set
++# CONFIG_BEFS_FS is not set
++# CONFIG_BFS_FS is not set
++# CONFIG_EFS_FS is not set
++# CONFIG_CRAMFS is not set
++# CONFIG_VXFS_FS is not set
++# CONFIG_HPFS_FS is not set
++# CONFIG_QNX4FS_FS is not set
++# CONFIG_SYSV_FS is not set
++# CONFIG_UFS_FS is not set
++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_NFS_DIRECTIO is not set
++# CONFIG_NFSD is not set
++CONFIG_ROOT_NFS=y
++CONFIG_LOCKD=y
++CONFIG_LOCKD_V4=y
++CONFIG_NFS_COMMON=y
++CONFIG_SUNRPC=y
++# CONFIG_SUNRPC_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 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 is not set
++# CONFIG_DLM is not set
++CONFIG_INSTRUMENTATION=y
++# CONFIG_PROFILING is not set
++# CONFIG_MARKERS is not set
++
++#
++# Kernel hacking
++#
++CONFIG_TRACE_IRQFLAGS_SUPPORT=y
++# CONFIG_PRINTK_TIME is not set
++CONFIG_ENABLE_WARN_DEPRECATED=y
++CONFIG_ENABLE_MUST_CHECK=y
++CONFIG_MAGIC_SYSRQ=y
++# 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=y
++CONFIG_SCHED_DEBUG=y
++CONFIG_SCHEDSTATS=y
++# CONFIG_TIMER_STATS 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 is not set
++# CONFIG_DEBUG_VM is not set
++# CONFIG_DEBUG_LIST is not set
++# CONFIG_DEBUG_SG is not set
++CONFIG_FRAME_POINTER=y
++CONFIG_FORCED_INLINING=y
++# CONFIG_BOOT_PRINTK_DELAY is not set
++# CONFIG_RCU_TORTURE_TEST is not set
++# CONFIG_FAULT_INJECTION is not set
++# CONFIG_SAMPLES is not set
++# CONFIG_SH_STANDARD_BIOS is not set
++# CONFIG_EARLY_SCIF_CONSOLE is not set
++# CONFIG_DEBUG_BOOTMEM is not set
++# CONFIG_DEBUG_STACK_USAGE is not set
++# CONFIG_4KSTACKS is not set
++CONFIG_SH64_PROC_ASIDS=y
++CONFIG_SH64_SR_WATCH=y
++# CONFIG_POOR_MANS_STRACE is not set
++# CONFIG_SH_ALPHANUMERIC is not set
++# CONFIG_SH_NO_BSS_INIT 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_CRC_CCITT is not set
++# 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_PLIST=y
++CONFIG_HAS_IOMEM=y
++CONFIG_HAS_IOPORT=y
++CONFIG_HAS_DMA=y
+diff --git a/arch/sh/configs/hs7751rvoip_defconfig b/arch/sh/configs/hs7751rvoip_defconfig
+deleted file mode 100644
+index 5d9da5a..0000000
+--- a/arch/sh/configs/hs7751rvoip_defconfig
++++ /dev/null
+@@ -1,908 +0,0 @@
+-#
+-# Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.18
+-# Tue Oct  3 13:04:52 2006
+-#
+-CONFIG_SUPERH=y
+-CONFIG_RWSEM_GENERIC_SPINLOCK=y
+-CONFIG_GENERIC_FIND_NEXT_BIT=y
+-CONFIG_GENERIC_HWEIGHT=y
+-CONFIG_GENERIC_HARDIRQS=y
+-CONFIG_GENERIC_IRQ_PROBE=y
+-CONFIG_GENERIC_CALIBRATE_DELAY=y
+-CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+-
+-#
+-# Code maturity level options
+-#
+-CONFIG_EXPERIMENTAL=y
+-CONFIG_BROKEN_ON_SMP=y
+-CONFIG_LOCK_KERNEL=y
+-CONFIG_INIT_ENV_ARG_LIMIT=32
+-
+-#
+-# General setup
+-#
+-CONFIG_LOCALVERSION=""
+-CONFIG_LOCALVERSION_AUTO=y
+-CONFIG_SWAP=y
+-CONFIG_SYSVIPC=y
+-# CONFIG_IPC_NS is not set
+-CONFIG_POSIX_MQUEUE=y
+-CONFIG_BSD_PROCESS_ACCT=y
+-# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+-# CONFIG_TASKSTATS is not set
+-# CONFIG_UTS_NS is not set
+-# CONFIG_AUDIT is not set
+-# CONFIG_IKCONFIG is not set
+-# CONFIG_RELAY is not set
+-CONFIG_INITRAMFS_SOURCE=""
+-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+-CONFIG_SYSCTL=y
+-CONFIG_EMBEDDED=y
+-CONFIG_UID16=y
+-# CONFIG_SYSCTL_SYSCALL is not set
+-# CONFIG_KALLSYMS is not set
+-CONFIG_HOTPLUG=y
+-CONFIG_PRINTK=y
+-CONFIG_BUG=y
+-CONFIG_ELF_CORE=y
+-CONFIG_BASE_FULL=y
+-CONFIG_FUTEX=y
+-CONFIG_EPOLL=y
+-CONFIG_SHMEM=y
+-CONFIG_SLAB=y
+-CONFIG_VM_EVENT_COUNTERS=y
+-CONFIG_RT_MUTEXES=y
+-# CONFIG_TINY_SHMEM is not set
+-CONFIG_BASE_SMALL=0
+-# CONFIG_SLOB is not set
+-
+-#
+-# Loadable module support
+-#
+-CONFIG_MODULES=y
+-CONFIG_MODULE_UNLOAD=y
+-# CONFIG_MODULE_FORCE_UNLOAD is not set
+-# CONFIG_MODVERSIONS is not set
+-# CONFIG_MODULE_SRCVERSION_ALL is not set
+-CONFIG_KMOD=y
+-
+-#
+-# Block layer
+-#
+-CONFIG_BLOCK=y
+-# CONFIG_LBD is not set
+-# CONFIG_BLK_DEV_IO_TRACE is not set
+-# CONFIG_LSF is not set
+-
+-#
+-# IO Schedulers
+-#
+-CONFIG_IOSCHED_NOOP=y
+-CONFIG_IOSCHED_AS=y
+-CONFIG_IOSCHED_DEADLINE=y
+-CONFIG_IOSCHED_CFQ=y
+-CONFIG_DEFAULT_AS=y
+-# CONFIG_DEFAULT_DEADLINE is not set
+-# CONFIG_DEFAULT_CFQ is not set
+-# CONFIG_DEFAULT_NOOP is not set
+-CONFIG_DEFAULT_IOSCHED="anticipatory"
+-
+-#
+-# System type
+-#
+-# CONFIG_SH_SOLUTION_ENGINE is not set
+-# CONFIG_SH_7751_SOLUTION_ENGINE is not set
+-# CONFIG_SH_7300_SOLUTION_ENGINE is not set
+-# CONFIG_SH_7343_SOLUTION_ENGINE is not set
+-# CONFIG_SH_73180_SOLUTION_ENGINE is not set
+-# CONFIG_SH_7751_SYSTEMH is not set
+-# CONFIG_SH_HP6XX is not set
+-# CONFIG_SH_EC3104 is not set
+-# CONFIG_SH_SATURN is not set
+-# CONFIG_SH_DREAMCAST is not set
+-# CONFIG_SH_BIGSUR is not set
+-# CONFIG_SH_MPC1211 is not set
+-# CONFIG_SH_SH03 is not set
+-# CONFIG_SH_SECUREEDGE5410 is not set
+-CONFIG_SH_HS7751RVOIP=y
+-# CONFIG_SH_7710VOIPGW is not set
+-# CONFIG_SH_RTS7751R2D is not set
+-# CONFIG_SH_R7780RP is not set
+-# CONFIG_SH_EDOSK7705 is not set
+-# CONFIG_SH_SH4202_MICRODEV is not set
+-# CONFIG_SH_LANDISK is not set
+-# CONFIG_SH_TITAN is not set
+-# CONFIG_SH_SHMIN is not set
+-# CONFIG_SH_UNKNOWN is not set
+-
+-#
+-# Processor selection
+-#
+-CONFIG_CPU_SH4=y
+-
+-#
+-# SH-2 Processor Support
+-#
+-# CONFIG_CPU_SUBTYPE_SH7604 is not set
+-
+-#
+-# SH-3 Processor Support
+-#
+-# CONFIG_CPU_SUBTYPE_SH7300 is not set
+-# CONFIG_CPU_SUBTYPE_SH7705 is not set
+-# CONFIG_CPU_SUBTYPE_SH7706 is not set
+-# CONFIG_CPU_SUBTYPE_SH7707 is not set
+-# CONFIG_CPU_SUBTYPE_SH7708 is not set
+-# CONFIG_CPU_SUBTYPE_SH7709 is not set
+-# CONFIG_CPU_SUBTYPE_SH7710 is not set
+-
+-#
+-# SH-4 Processor Support
+-#
+-# CONFIG_CPU_SUBTYPE_SH7750 is not set
+-# CONFIG_CPU_SUBTYPE_SH7091 is not set
+-# CONFIG_CPU_SUBTYPE_SH7750R is not set
+-# CONFIG_CPU_SUBTYPE_SH7750S is not set
+-# CONFIG_CPU_SUBTYPE_SH7751 is not set
+-CONFIG_CPU_SUBTYPE_SH7751R=y
+-# CONFIG_CPU_SUBTYPE_SH7760 is not set
+-# CONFIG_CPU_SUBTYPE_SH4_202 is not set
+-
+-#
+-# ST40 Processor Support
+-#
+-# CONFIG_CPU_SUBTYPE_ST40STB1 is not set
+-# CONFIG_CPU_SUBTYPE_ST40GX1 is not set
+-
+-#
+-# SH-4A Processor Support
+-#
+-# CONFIG_CPU_SUBTYPE_SH7770 is not set
+-# CONFIG_CPU_SUBTYPE_SH7780 is not set
+-
+-#
+-# SH4AL-DSP Processor Support
+-#
+-# CONFIG_CPU_SUBTYPE_SH73180 is not set
+-# CONFIG_CPU_SUBTYPE_SH7343 is not set
+-
+-#
+-# Memory management options
+-#
+-CONFIG_MMU=y
+-CONFIG_PAGE_OFFSET=0x80000000
+-CONFIG_MEMORY_START=0x0c000000
+-CONFIG_MEMORY_SIZE=0x04000000
+-CONFIG_VSYSCALL=y
+-CONFIG_SELECT_MEMORY_MODEL=y
+-CONFIG_FLATMEM_MANUAL=y
+-# CONFIG_DISCONTIGMEM_MANUAL is not set
+-# CONFIG_SPARSEMEM_MANUAL is not set
+-CONFIG_FLATMEM=y
+-CONFIG_FLAT_NODE_MEM_MAP=y
+-# CONFIG_SPARSEMEM_STATIC is not set
+-CONFIG_SPLIT_PTLOCK_CPUS=4
+-# CONFIG_RESOURCES_64BIT is not set
+-
+-#
+-# Cache configuration
+-#
+-# CONFIG_SH_DIRECT_MAPPED is not set
+-# CONFIG_SH_WRITETHROUGH is not set
+-# CONFIG_SH_OCRAM is not set
+-
+-#
+-# Processor features
+-#
+-CONFIG_CPU_LITTLE_ENDIAN=y
+-CONFIG_SH_FPU=y
+-# CONFIG_SH_DSP is not set
+-# CONFIG_SH_STORE_QUEUES is not set
+-CONFIG_CPU_HAS_INTEVT=y
+-CONFIG_CPU_HAS_SR_RB=y
+-
+-#
+-# Timer support
+-#
+-CONFIG_SH_TMU=y
+-
+-#
+-# HS7751RVoIP options
+-#
+-CONFIG_HS7751RVOIP_CODEC=y
+-CONFIG_SH_PCLK_FREQ=60000000
+-
+-#
+-# CPU Frequency scaling
+-#
+-# CONFIG_CPU_FREQ is not set
+-
+-#
+-# DMA support
+-#
+-# CONFIG_SH_DMA is not set
+-
+-#
+-# Companion Chips
+-#
+-# CONFIG_HD6446X_SERIES is not set
+-
+-#
+-# Kernel features
+-#
+-# CONFIG_HZ_100 is not set
+-CONFIG_HZ_250=y
+-# CONFIG_HZ_1000 is not set
+-CONFIG_HZ=250
+-# CONFIG_KEXEC is not set
+-# CONFIG_SMP is not set
+-# CONFIG_PREEMPT_NONE is not set
+-# CONFIG_PREEMPT_VOLUNTARY is not set
+-CONFIG_PREEMPT=y
+-CONFIG_PREEMPT_BKL=y
+-
+-#
+-# Boot options
+-#
+-CONFIG_ZERO_PAGE_OFFSET=0x00001000
+-CONFIG_BOOT_LINK_OFFSET=0x00800000
+-# CONFIG_UBC_WAKEUP is not set
+-CONFIG_CMDLINE_BOOL=y
+-CONFIG_CMDLINE="mem=64M console=ttySC1,115200 root=/dev/hda1"
+-
+-#
+-# Bus options
+-#
+-# CONFIG_PCI is not set
+-
+-#
+-# PCCARD (PCMCIA/CardBus) support
+-#
+-# CONFIG_PCCARD is not set
+-
+-#
+-# PCI Hotplug Support
+-#
+-
+-#
+-# Executable file formats
+-#
+-CONFIG_BINFMT_ELF=y
+-# CONFIG_BINFMT_FLAT is not set
+-# CONFIG_BINFMT_MISC is not set
+-
+-#
+-# Power management options (EXPERIMENTAL)
+-#
+-# CONFIG_PM is not set
+-
+-#
+-# Networking
+-#
+-CONFIG_NET=y
+-
+-#
+-# Networking options
+-#
+-# CONFIG_NETDEBUG is not set
+-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_NET_KEY is not set
+-CONFIG_INET=y
+-CONFIG_IP_MULTICAST=y
+-CONFIG_IP_ADVANCED_ROUTER=y
+-CONFIG_ASK_IP_FIB_HASH=y
+-# CONFIG_IP_FIB_TRIE is not set
+-CONFIG_IP_FIB_HASH=y
+-# CONFIG_IP_MULTIPLE_TABLES is not set
+-# CONFIG_IP_ROUTE_MULTIPATH is not set
+-# CONFIG_IP_ROUTE_VERBOSE is not set
+-# CONFIG_IP_PNP is not set
+-# CONFIG_NET_IPIP is not set
+-# CONFIG_NET_IPGRE is not set
+-# CONFIG_IP_MROUTE is not set
+-# CONFIG_ARPD is not set
+-# CONFIG_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_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_IPV6 is not set
+-# CONFIG_INET6_XFRM_TUNNEL is not set
+-# CONFIG_INET6_TUNNEL is not set
+-# CONFIG_NETWORK_SECMARK is not set
+-# CONFIG_NETFILTER is not set
+-
+-#
+-# DCCP Configuration (EXPERIMENTAL)
+-#
+-# CONFIG_IP_DCCP is not set
+-
+-#
+-# SCTP Configuration (EXPERIMENTAL)
+-#
+-# CONFIG_IP_SCTP is not set
+-
+-#
+-# TIPC Configuration (EXPERIMENTAL)
+-#
+-# CONFIG_TIPC is not set
+-# CONFIG_ATM is not set
+-# CONFIG_BRIDGE is not set
+-# CONFIG_VLAN_8021Q is not set
+-# CONFIG_DECNET is not set
+-# CONFIG_LLC2 is not set
+-# CONFIG_IPX is not set
+-# CONFIG_ATALK is not set
+-# CONFIG_X25 is not set
+-# CONFIG_LAPB is not set
+-# CONFIG_ECONET is not set
+-# CONFIG_WAN_ROUTER is not set
+-
+-#
+-# QoS and/or fair queueing
+-#
+-# CONFIG_NET_SCHED is not set
+-
+-#
+-# Network testing
+-#
+-# CONFIG_NET_PKTGEN is not set
+-# CONFIG_HAMRADIO is not set
+-# CONFIG_IRDA is not set
+-# CONFIG_BT is not set
+-# CONFIG_IEEE80211 is not set
+-
+-#
+-# Device Drivers
+-#
+-
+-#
+-# Generic Driver Options
+-#
+-CONFIG_STANDALONE=y
+-CONFIG_PREVENT_FIRMWARE_BUILD=y
+-CONFIG_FW_LOADER=m
+-# CONFIG_SYS_HYPERVISOR is not set
+-
+-#
+-# Connector - unified userspace <-> kernelspace linker
+-#
+-# CONFIG_CONNECTOR is not set
+-
+-#
+-# Memory Technology Devices (MTD)
+-#
+-# CONFIG_MTD is not set
+-
+-#
+-# Parallel port support
+-#
+-# CONFIG_PARPORT is not set
+-
+-#
+-# Plug and Play support
+-#
+-
+-#
+-# Block devices
+-#
+-# CONFIG_BLK_DEV_COW_COMMON is not set
+-# CONFIG_BLK_DEV_LOOP is not set
+-# CONFIG_BLK_DEV_NBD is not set
+-# CONFIG_BLK_DEV_RAM is not set
+-# CONFIG_BLK_DEV_INITRD is not set
+-# CONFIG_CDROM_PKTCDVD is not set
+-# CONFIG_ATA_OVER_ETH is not set
+-
+-#
+-# ATA/ATAPI/MFM/RLL support
+-#
+-CONFIG_IDE=y
+-CONFIG_IDE_MAX_HWIFS=1
+-CONFIG_BLK_DEV_IDE=y
+-
+-#
+-# Please see Documentation/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_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
+-
+-#
+-# IDE chipset support/bugfixes
+-#
+-CONFIG_IDE_GENERIC=y
+-# CONFIG_IDE_ARM 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_RAID_ATTRS is not set
+-# CONFIG_SCSI is not set
+-# CONFIG_SCSI_NETLINK is not set
+-
+-#
+-# Serial ATA (prod) and Parallel ATA (experimental) drivers
+-#
+-# CONFIG_ATA is not set
+-
+-#
+-# Multi-device support (RAID and LVM)
+-#
+-# CONFIG_MD is not set
+-
+-#
+-# Fusion MPT device support
+-#
+-# CONFIG_FUSION is not set
+-
+-#
+-# IEEE 1394 (FireWire) support
+-#
+-
+-#
+-# I2O device support
+-#
+-
+-#
+-# Network device support
+-#
+-CONFIG_NETDEVICES=y
+-# CONFIG_DUMMY is not set
+-# CONFIG_BONDING is not set
+-# CONFIG_EQUALIZER is not set
+-# CONFIG_TUN is not set
+-
+-#
+-# PHY device support
+-#
+-# CONFIG_PHYLIB is not set
+-
+-#
+-# Ethernet (10 or 100Mbit)
+-#
+-CONFIG_NET_ETHERNET=y
+-CONFIG_MII=y
+-# CONFIG_STNIC is not set
+-# CONFIG_SMC91X is not set
+-
+-#
+-# Ethernet (1000 Mbit)
+-#
+-
+-#
+-# Ethernet (10000 Mbit)
+-#
+-
+-#
+-# Token Ring devices
+-#
+-
+-#
+-# Wireless LAN (non-hamradio)
+-#
+-# CONFIG_NET_RADIO is not set
+-
+-#
+-# Wan interfaces
+-#
+-# CONFIG_WAN is not set
+-# CONFIG_PPP is not set
+-# CONFIG_SLIP is not set
+-# CONFIG_SHAPER is not set
+-# CONFIG_NETCONSOLE is not set
+-# CONFIG_NETPOLL is not set
+-# CONFIG_NET_POLL_CONTROLLER is not set
+-
+-#
+-# ISDN subsystem
+-#
+-# CONFIG_ISDN is not set
+-
+-#
+-# Telephony Support
+-#
+-# CONFIG_PHONE is not set
+-
+-#
+-# Input device support
+-#
+-CONFIG_INPUT=y
+-# CONFIG_INPUT_FF_MEMLESS is not set
+-
+-#
+-# Userland interfaces
+-#
+-# CONFIG_INPUT_MOUSEDEV is not set
+-# CONFIG_INPUT_JOYDEV is not set
+-# CONFIG_INPUT_TSDEV is not set
+-# CONFIG_INPUT_EVDEV is not set
+-# CONFIG_INPUT_EVBUG is not set
+-
+-#
+-# Input Device Drivers
+-#
+-# CONFIG_INPUT_KEYBOARD is not set
+-# CONFIG_INPUT_MOUSE is not set
+-# CONFIG_INPUT_JOYSTICK is not set
+-# CONFIG_INPUT_TOUCHSCREEN is not set
+-# CONFIG_INPUT_MISC is not set
+-
+-#
+-# Hardware I/O ports
+-#
+-CONFIG_SERIO=y
+-CONFIG_SERIO_I8042=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 is not set
+-# CONFIG_SERIAL_NONSTANDARD is not set
+-
+-#
+-# Serial drivers
+-#
+-# CONFIG_SERIAL_8250 is not set
+-
+-#
+-# Non-8250 serial port support
+-#
+-CONFIG_SERIAL_SH_SCI=y
+-CONFIG_SERIAL_SH_SCI_NR_UARTS=2
+-CONFIG_SERIAL_SH_SCI_CONSOLE=y
+-CONFIG_SERIAL_CORE=y
+-CONFIG_SERIAL_CORE_CONSOLE=y
+-CONFIG_UNIX98_PTYS=y
+-# CONFIG_LEGACY_PTYS is not set
+-
+-#
+-# IPMI
+-#
+-# CONFIG_IPMI_HANDLER is not set
+-
+-#
+-# Watchdog Cards
+-#
+-# CONFIG_WATCHDOG is not set
+-CONFIG_HW_RANDOM=y
+-# CONFIG_GEN_RTC is not set
+-# CONFIG_DTLK is not set
+-# CONFIG_R3964 is not set
+-
+-#
+-# Ftape, the floppy tape device driver
+-#
+-# CONFIG_RAW_DRIVER is not set
+-
+-#
+-# TPM devices
+-#
+-# CONFIG_TCG_TPM is not set
+-# CONFIG_TELCLOCK is not set
+-
+-#
+-# I2C support
+-#
+-# CONFIG_I2C is not set
+-
+-#
+-# SPI support
+-#
+-# CONFIG_SPI is not set
+-# CONFIG_SPI_MASTER is not set
+-
+-#
+-# Dallas's 1-wire bus
+-#
+-
+-#
+-# Hardware Monitoring support
+-#
+-CONFIG_HWMON=y
+-# CONFIG_HWMON_VID is not set
+-# CONFIG_SENSORS_ABITUGURU is not set
+-# CONFIG_SENSORS_F71805F is not set
+-# CONFIG_SENSORS_VT1211 is not set
+-# CONFIG_HWMON_DEBUG_CHIP is not set
+-
+-#
+-# Misc devices
+-#
+-
+-#
+-# Multimedia devices
+-#
+-# CONFIG_VIDEO_DEV is not set
+-CONFIG_VIDEO_V4L2=y
+-
+-#
+-# Digital Video Broadcasting Devices
+-#
+-# CONFIG_DVB is not set
+-
+-#
+-# Graphics support
+-#
+-CONFIG_FIRMWARE_EDID=y
+-# CONFIG_FB is not set
+-# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+-
+-#
+-# Sound
+-#
+-# CONFIG_SOUND is not set
+-
+-#
+-# USB support
+-#
+-# CONFIG_USB_ARCH_HAS_HCD is not set
+-# CONFIG_USB_ARCH_HAS_OHCI is not set
+-# CONFIG_USB_ARCH_HAS_EHCI is not set
+-
+-#
+-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+-#
+-
+-#
+-# USB Gadget Support
+-#
+-# CONFIG_USB_GADGET is not set
+-
+-#
+-# MMC/SD Card support
+-#
+-# CONFIG_MMC is not set
+-
+-#
+-# LED devices
+-#
+-# CONFIG_NEW_LEDS is not set
+-
+-#
+-# LED drivers
+-#
+-
+-#
+-# LED Triggers
+-#
+-
+-#
+-# InfiniBand support
+-#
+-
+-#
+-# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
+-#
+-
+-#
+-# Real Time Clock
+-#
+-# CONFIG_RTC_CLASS is not set
+-
+-#
+-# DMA Engine support
+-#
+-# CONFIG_DMA_ENGINE is not set
+-
+-#
+-# DMA Clients
+-#
+-
+-#
+-# DMA Devices
+-#
+-
+-#
+-# File systems
+-#
+-CONFIG_EXT2_FS=y
+-# CONFIG_EXT2_FS_XATTR is not set
+-# CONFIG_EXT2_FS_XIP is not set
+-# CONFIG_EXT3_FS 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_MINIX_FS is not set
+-# CONFIG_ROMFS_FS is not set
+-CONFIG_INOTIFY=y
+-CONFIG_INOTIFY_USER=y
+-# CONFIG_QUOTA is not set
+-CONFIG_DNOTIFY=y
+-# CONFIG_AUTOFS_FS is not set
+-# CONFIG_AUTOFS4_FS is not set
+-# CONFIG_FUSE_FS is not set
+-
+-#
+-# CD-ROM/DVD Filesystems
+-#
+-# CONFIG_ISO9660_FS is not set
+-# CONFIG_UDF_FS is not set
+-
+-#
+-# DOS/FAT/NT Filesystems
+-#
+-# CONFIG_MSDOS_FS is not set
+-# CONFIG_VFAT_FS is not set
+-# CONFIG_NTFS_FS is not set
+-
+-#
+-# Pseudo filesystems
+-#
+-CONFIG_PROC_FS=y
+-CONFIG_PROC_KCORE=y
+-CONFIG_PROC_SYSCTL=y
+-CONFIG_SYSFS=y
+-CONFIG_TMPFS=y
+-# CONFIG_TMPFS_POSIX_ACL is not set
+-# CONFIG_HUGETLBFS is not set
+-# CONFIG_HUGETLB_PAGE is not set
+-CONFIG_RAMFS=y
+-# CONFIG_CONFIGFS_FS is not set
+-
+-#
+-# Miscellaneous filesystems
+-#
+-# CONFIG_ADFS_FS is not set
+-# CONFIG_AFFS_FS is not set
+-# CONFIG_HFS_FS is not set
+-# CONFIG_HFSPLUS_FS is not set
+-# CONFIG_BEFS_FS is not set
+-# CONFIG_BFS_FS is not set
+-# CONFIG_EFS_FS is not set
+-# CONFIG_CRAMFS is not set
+-# CONFIG_VXFS_FS is not set
+-# CONFIG_HPFS_FS is not set
+-# CONFIG_QNX4FS_FS is not set
+-# CONFIG_SYSV_FS is not set
+-# CONFIG_UFS_FS is not set
+-
+-#
+-# Network File Systems
+-#
+-CONFIG_NFS_FS=y
+-CONFIG_NFS_V3=y
+-# CONFIG_NFS_V3_ACL is not set
+-CONFIG_NFS_V4=y
+-CONFIG_NFS_DIRECTIO=y
+-# CONFIG_NFSD is not set
+-CONFIG_LOCKD=y
+-CONFIG_LOCKD_V4=y
+-CONFIG_NFS_COMMON=y
+-CONFIG_SUNRPC=y
+-CONFIG_SUNRPC_GSS=y
+-CONFIG_RPCSEC_GSS_KRB5=y
+-# CONFIG_RPCSEC_GSS_SPKM3 is not set
+-# CONFIG_SMB_FS is not set
+-# CONFIG_CIFS is not set
+-# CONFIG_NCP_FS is not set
+-# CONFIG_CODA_FS is not set
+-# CONFIG_AFS_FS is not set
+-# CONFIG_9P_FS is not set
+-
+-#
+-# Partition Types
+-#
+-CONFIG_PARTITION_ADVANCED=y
+-# CONFIG_ACORN_PARTITION is not set
+-# CONFIG_OSF_PARTITION is not set
+-# CONFIG_AMIGA_PARTITION is not set
+-# CONFIG_ATARI_PARTITION is not set
+-# CONFIG_MAC_PARTITION is not set
+-CONFIG_MSDOS_PARTITION=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
+-
+-#
+-# Native Language Support
+-#
+-# CONFIG_NLS is not set
+-
+-#
+-# Profiling support
+-#
+-# CONFIG_PROFILING is not set
+-
+-#
+-# Kernel hacking
+-#
+-# CONFIG_PRINTK_TIME is not set
+-CONFIG_ENABLE_MUST_CHECK=y
+-# CONFIG_MAGIC_SYSRQ is not set
+-# CONFIG_UNUSED_SYMBOLS is not set
+-# CONFIG_DEBUG_KERNEL is not set
+-CONFIG_LOG_BUF_SHIFT=14
+-# CONFIG_DEBUG_BUGVERBOSE is not set
+-# CONFIG_DEBUG_FS is not set
+-# CONFIG_SH_STANDARD_BIOS is not set
+-# CONFIG_EARLY_SCIF_CONSOLE is not set
+-# CONFIG_KGDB is not set
+-
+-#
+-# Security options
+-#
+-# CONFIG_KEYS is not set
+-# CONFIG_SECURITY is not set
+-
+-#
+-# Cryptographic options
+-#
+-CONFIG_CRYPTO=y
+-CONFIG_CRYPTO_ALGAPI=y
+-CONFIG_CRYPTO_BLKCIPHER=m
+-CONFIG_CRYPTO_MANAGER=m
+-# CONFIG_CRYPTO_HMAC is not set
+-# CONFIG_CRYPTO_NULL is not set
+-# CONFIG_CRYPTO_MD4 is not set
+-CONFIG_CRYPTO_MD5=y
+-# CONFIG_CRYPTO_SHA1 is not set
+-# CONFIG_CRYPTO_SHA256 is not set
+-# CONFIG_CRYPTO_SHA512 is not set
+-# CONFIG_CRYPTO_WP512 is not set
+-# CONFIG_CRYPTO_TGR192 is not set
+-CONFIG_CRYPTO_ECB=m
+-CONFIG_CRYPTO_CBC=m
+-CONFIG_CRYPTO_DES=y
+-# CONFIG_CRYPTO_BLOWFISH is not set
+-# CONFIG_CRYPTO_TWOFISH is not set
+-# CONFIG_CRYPTO_SERPENT is not set
+-# CONFIG_CRYPTO_AES is not set
+-# CONFIG_CRYPTO_CAST5 is not set
+-# CONFIG_CRYPTO_CAST6 is not set
+-# CONFIG_CRYPTO_TEA is not set
+-# CONFIG_CRYPTO_ARC4 is not set
+-# CONFIG_CRYPTO_KHAZAD is not set
+-# CONFIG_CRYPTO_ANUBIS is not set
+-# CONFIG_CRYPTO_DEFLATE is not set
+-# CONFIG_CRYPTO_MICHAEL_MIC is not set
+-# CONFIG_CRYPTO_CRC32C is not set
+-# CONFIG_CRYPTO_TEST is not set
+-
+-#
+-# Hardware crypto devices
+-#
+-
+-#
+-# Library routines
+-#
+-# CONFIG_CRC_CCITT is not set
+-# CONFIG_CRC16 is not set
+-CONFIG_CRC32=y
+-# CONFIG_LIBCRC32C is not set
+-CONFIG_PLIST=y
+diff --git a/arch/sh/configs/r7780rp_defconfig b/arch/sh/configs/r7780rp_defconfig
+deleted file mode 100644
+index 12cc019..0000000
+--- a/arch/sh/configs/r7780rp_defconfig
++++ /dev/null
+@@ -1,1328 +0,0 @@
+-#
+-# Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.21-rc7
+-# Tue May  1 12:28:39 2007
+-#
+-CONFIG_SUPERH=y
+-CONFIG_RWSEM_GENERIC_SPINLOCK=y
+-CONFIG_GENERIC_BUG=y
+-CONFIG_GENERIC_FIND_NEXT_BIT=y
+-CONFIG_GENERIC_HWEIGHT=y
+-CONFIG_GENERIC_HARDIRQS=y
+-CONFIG_GENERIC_IRQ_PROBE=y
+-CONFIG_GENERIC_CALIBRATE_DELAY=y
+-# CONFIG_GENERIC_TIME is not set
+-CONFIG_STACKTRACE_SUPPORT=y
+-CONFIG_LOCKDEP_SUPPORT=y
+-# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+-# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+-CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+-
+-#
+-# Code maturity level options
+-#
+-CONFIG_EXPERIMENTAL=y
+-CONFIG_BROKEN_ON_SMP=y
+-CONFIG_LOCK_KERNEL=y
+-CONFIG_INIT_ENV_ARG_LIMIT=32
+-
+-#
+-# General setup
+-#
+-CONFIG_LOCALVERSION=""
+-CONFIG_LOCALVERSION_AUTO=y
+-CONFIG_SWAP=y
+-CONFIG_SYSVIPC=y
+-# CONFIG_IPC_NS is not set
+-CONFIG_SYSVIPC_SYSCTL=y
+-# CONFIG_POSIX_MQUEUE is not set
+-CONFIG_BSD_PROCESS_ACCT=y
+-# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+-# CONFIG_TASKSTATS is not set
+-# CONFIG_UTS_NS is not set
+-# CONFIG_AUDIT is not set
+-CONFIG_IKCONFIG=y
+-CONFIG_IKCONFIG_PROC=y
+-# CONFIG_SYSFS_DEPRECATED is not set
+-# CONFIG_RELAY 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 is not set
+-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_BASE_FULL=y
+-# CONFIG_FUTEX is not set
+-# CONFIG_EPOLL is not set
+-CONFIG_SHMEM=y
+-CONFIG_SLAB=y
+-CONFIG_VM_EVENT_COUNTERS=y
+-# CONFIG_TINY_SHMEM is not set
+-CONFIG_BASE_SMALL=0
+-# CONFIG_SLOB is not set
+-
+-#
+-# Loadable module support
+-#
+-CONFIG_MODULES=y
+-CONFIG_MODULE_UNLOAD=y
+-# CONFIG_MODULE_FORCE_UNLOAD is not set
+-# CONFIG_MODVERSIONS is not set
+-# CONFIG_MODULE_SRCVERSION_ALL is not set
+-CONFIG_KMOD=y
+-
+-#
+-# Block layer
+-#
+-CONFIG_BLOCK=y
+-# CONFIG_LBD is not set
+-# CONFIG_BLK_DEV_IO_TRACE is not set
+-# CONFIG_LSF is not set
+-
+-#
+-# IO Schedulers
+-#
+-CONFIG_IOSCHED_NOOP=y
+-# CONFIG_IOSCHED_AS 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"
+-
+-#
+-# System type
+-#
+-# CONFIG_SH_SOLUTION_ENGINE is not set
+-# CONFIG_SH_7722_SOLUTION_ENGINE is not set
+-# CONFIG_SH_7751_SOLUTION_ENGINE is not set
+-# CONFIG_SH_7780_SOLUTION_ENGINE is not set
+-# CONFIG_SH_7300_SOLUTION_ENGINE is not set
+-# CONFIG_SH_7343_SOLUTION_ENGINE is not set
+-# CONFIG_SH_73180_SOLUTION_ENGINE is not set
+-# CONFIG_SH_7751_SYSTEMH is not set
+-# CONFIG_SH_HP6XX is not set
+-# CONFIG_SH_SATURN is not set
+-# CONFIG_SH_DREAMCAST is not set
+-# CONFIG_SH_MPC1211 is not set
+-# CONFIG_SH_SH03 is not set
+-# CONFIG_SH_SECUREEDGE5410 is not set
+-# CONFIG_SH_HS7751RVOIP is not set
+-# CONFIG_SH_7710VOIPGW is not set
+-# CONFIG_SH_RTS7751R2D is not set
+-CONFIG_SH_HIGHLANDER=y
+-# CONFIG_SH_EDOSK7705 is not set
+-# CONFIG_SH_SH4202_MICRODEV is not set
+-# CONFIG_SH_LANDISK is not set
+-# CONFIG_SH_TITAN is not set
+-# CONFIG_SH_SHMIN is not set
+-# CONFIG_SH_7206_SOLUTION_ENGINE is not set
+-# CONFIG_SH_7619_SOLUTION_ENGINE is not set
+-# CONFIG_SH_LBOX_RE2 is not set
+-# CONFIG_SH_UNKNOWN is not set
+-CONFIG_SH_R7780RP=y
+-# CONFIG_SH_R7780MP is not set
+-# CONFIG_SH_R7785RP is not set
+-
+-#
+-# Processor selection
+-#
+-CONFIG_CPU_SH4=y
+-CONFIG_CPU_SH4A=y
+-
+-#
+-# SH-2 Processor Support
+-#
+-# CONFIG_CPU_SUBTYPE_SH7604 is not set
+-# CONFIG_CPU_SUBTYPE_SH7619 is not set
+-
+-#
+-# SH-2A Processor Support
+-#
+-# CONFIG_CPU_SUBTYPE_SH7206 is not set
+-
+-#
+-# SH-3 Processor Support
+-#
+-# CONFIG_CPU_SUBTYPE_SH7300 is not set
+-# CONFIG_CPU_SUBTYPE_SH7705 is not set
+-# CONFIG_CPU_SUBTYPE_SH7706 is not set
+-# CONFIG_CPU_SUBTYPE_SH7707 is not set
+-# CONFIG_CPU_SUBTYPE_SH7708 is not set
+-# CONFIG_CPU_SUBTYPE_SH7709 is not set
+-# CONFIG_CPU_SUBTYPE_SH7710 is not set
+-# CONFIG_CPU_SUBTYPE_SH7712 is not set
+-
+-#
+-# SH-4 Processor Support
+-#
+-# CONFIG_CPU_SUBTYPE_SH7750 is not set
+-# CONFIG_CPU_SUBTYPE_SH7091 is not set
+-# CONFIG_CPU_SUBTYPE_SH7750R is not set
+-# CONFIG_CPU_SUBTYPE_SH7750S is not set
+-# CONFIG_CPU_SUBTYPE_SH7751 is not set
+-# CONFIG_CPU_SUBTYPE_SH7751R is not set
+-# CONFIG_CPU_SUBTYPE_SH7760 is not set
+-# CONFIG_CPU_SUBTYPE_SH4_202 is not set
+-
+-#
+-# ST40 Processor Support
+-#
+-# CONFIG_CPU_SUBTYPE_ST40STB1 is not set
+-# CONFIG_CPU_SUBTYPE_ST40GX1 is not set
+-
+-#
+-# SH-4A Processor Support
+-#
+-# CONFIG_CPU_SUBTYPE_SH7770 is not set
+-CONFIG_CPU_SUBTYPE_SH7780=y
+-# CONFIG_CPU_SUBTYPE_SH7785 is not set
+-
+-#
+-# SH4AL-DSP Processor Support
+-#
+-# CONFIG_CPU_SUBTYPE_SH73180 is not set
+-# CONFIG_CPU_SUBTYPE_SH7343 is not set
+-# CONFIG_CPU_SUBTYPE_SH7722 is not set
+-
+-#
+-# Memory management options
+-#
+-CONFIG_MMU=y
+-CONFIG_PAGE_OFFSET=0x80000000
+-CONFIG_MEMORY_START=0x08000000
+-CONFIG_MEMORY_SIZE=0x08000000
+-# CONFIG_32BIT is not set
+-CONFIG_VSYSCALL=y
+-CONFIG_ARCH_FLATMEM_ENABLE=y
+-CONFIG_ARCH_POPULATES_NODE_MAP=y
+-CONFIG_PAGE_SIZE_4KB=y
+-# CONFIG_PAGE_SIZE_8KB is not set
+-# CONFIG_PAGE_SIZE_64KB is not set
+-CONFIG_HUGETLB_PAGE_SIZE_64K=y
+-# CONFIG_HUGETLB_PAGE_SIZE_256K is not set
+-# CONFIG_HUGETLB_PAGE_SIZE_1MB is not set
+-# CONFIG_HUGETLB_PAGE_SIZE_4MB is not set
+-# CONFIG_HUGETLB_PAGE_SIZE_64MB 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_SPLIT_PTLOCK_CPUS=4
+-# CONFIG_RESOURCES_64BIT is not set
+-CONFIG_ZONE_DMA_FLAG=0
+-
+-#
+-# Cache configuration
+-#
+-# CONFIG_SH_DIRECT_MAPPED is not set
+-# CONFIG_SH_WRITETHROUGH is not set
+-# CONFIG_SH_OCRAM is not set
+-
+-#
+-# Processor features
+-#
+-CONFIG_CPU_LITTLE_ENDIAN=y
+-# CONFIG_CPU_BIG_ENDIAN is not set
+-CONFIG_SH_FPU=y
+-# CONFIG_SH_DSP is not set
+-CONFIG_SH_STORE_QUEUES=y
+-CONFIG_SPECULATIVE_EXECUTION=y
+-CONFIG_CPU_HAS_INTEVT=y
+-CONFIG_CPU_HAS_INTC_IRQ=y
+-CONFIG_CPU_HAS_SR_RB=y
+-
+-#
+-# Timer and clock configuration
+-#
+-CONFIG_SH_TMU=y
+-CONFIG_SH_TIMER_IRQ=28
+-CONFIG_NO_IDLE_HZ=y
+-CONFIG_SH_PCLK_FREQ=32000000
+-
+-#
+-# CPU Frequency scaling
+-#
+-# CONFIG_CPU_FREQ is not set
+-
+-#
+-# DMA support
+-#
+-# CONFIG_SH_DMA is not set
+-
+-#
+-# Companion Chips
+-#
+-# CONFIG_HD6446X_SERIES is not set
+-
+-#
+-# Additional SuperH Device Drivers
+-#
+-# CONFIG_HEARTBEAT is not set
+-CONFIG_PUSH_SWITCH=y
+-
+-#
+-# Kernel features
+-#
+-# 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_KEXEC=y
+-# CONFIG_CRASH_DUMP is not set
+-# CONFIG_SMP is not set
+-# CONFIG_PREEMPT_NONE is not set
+-# CONFIG_PREEMPT_VOLUNTARY is not set
+-CONFIG_PREEMPT=y
+-CONFIG_PREEMPT_BKL=y
+-
+-#
+-# Boot options
+-#
+-CONFIG_ZERO_PAGE_OFFSET=0x00001000
+-CONFIG_BOOT_LINK_OFFSET=0x00800000
+-# CONFIG_UBC_WAKEUP is not set
+-CONFIG_CMDLINE_BOOL=y
+-CONFIG_CMDLINE="mem=128M console=ttySC0,115200 root=/dev/sda1"
+-
+-#
+-# Bus options
+-#
+-CONFIG_PCI=y
+-CONFIG_SH_PCIDMA_NONCOHERENT=y
+-CONFIG_PCI_AUTO=y
+-CONFIG_PCI_AUTO_UPDATE_RESOURCES=y
+-# CONFIG_PCI_DEBUG is not set
+-
+-#
+-# PCCARD (PCMCIA/CardBus) support
+-#
+-# CONFIG_PCCARD is not set
+-
+-#
+-# PCI Hotplug Support
+-#
+-# CONFIG_HOTPLUG_PCI is not set
+-
+-#
+-# Executable file formats
+-#
+-CONFIG_BINFMT_ELF=y
+-# CONFIG_BINFMT_FLAT is not set
+-# CONFIG_BINFMT_MISC is not set
+-
+-#
+-# Power management options (EXPERIMENTAL)
+-#
+-# CONFIG_PM is not set
+-
+-#
+-# Networking
+-#
+-CONFIG_NET=y
+-
+-#
+-# Networking options
+-#
+-# CONFIG_NETDEBUG is not set
+-CONFIG_PACKET=y
+-# CONFIG_PACKET_MMAP is not set
+-CONFIG_UNIX=y
+-CONFIG_XFRM=y
+-# CONFIG_XFRM_USER is not set
+-# CONFIG_XFRM_SUB_POLICY is not set
+-# CONFIG_XFRM_MIGRATE is not set
+-# CONFIG_NET_KEY is not set
+-CONFIG_INET=y
+-# CONFIG_IP_MULTICAST is not set
+-CONFIG_IP_ADVANCED_ROUTER=y
+-CONFIG_ASK_IP_FIB_HASH=y
+-# CONFIG_IP_FIB_TRIE is not set
+-CONFIG_IP_FIB_HASH=y
+-# CONFIG_IP_MULTIPLE_TABLES is not set
+-# CONFIG_IP_ROUTE_MULTIPATH is not set
+-# CONFIG_IP_ROUTE_VERBOSE is not set
+-CONFIG_IP_PNP=y
+-CONFIG_IP_PNP_DHCP=y
+-# CONFIG_IP_PNP_BOOTP is not set
+-# CONFIG_IP_PNP_RARP is not set
+-# CONFIG_NET_IPIP is not set
+-# CONFIG_NET_IPGRE is not set
+-# CONFIG_ARPD is not set
+-# CONFIG_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_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_INET6_XFRM_TUNNEL is not set
+-# CONFIG_INET6_TUNNEL is not set
+-# CONFIG_NETWORK_SECMARK is not set
+-# CONFIG_NETFILTER is not set
+-
+-#
+-# DCCP Configuration (EXPERIMENTAL)
+-#
+-# CONFIG_IP_DCCP is not set
+-
+-#
+-# SCTP Configuration (EXPERIMENTAL)
+-#
+-# CONFIG_IP_SCTP is not set
+-
+-#
+-# TIPC Configuration (EXPERIMENTAL)
+-#
+-# CONFIG_TIPC is not set
+-# CONFIG_ATM is not set
+-CONFIG_BRIDGE=m
+-# CONFIG_VLAN_8021Q is not set
+-# CONFIG_DECNET is not set
+-CONFIG_LLC=m
+-# CONFIG_LLC2 is not set
+-# CONFIG_IPX is not set
+-# CONFIG_ATALK is not set
+-# CONFIG_X25 is not set
+-# CONFIG_LAPB is not set
+-# CONFIG_ECONET is not set
+-# CONFIG_WAN_ROUTER is not set
+-
+-#
+-# QoS and/or fair queueing
+-#
+-# CONFIG_NET_SCHED is not set
+-
+-#
+-# Network testing
+-#
+-# CONFIG_NET_PKTGEN is not set
+-# CONFIG_HAMRADIO is not set
+-# CONFIG_IRDA is not set
+-# CONFIG_BT is not set
+-# CONFIG_IEEE80211 is not set
+-CONFIG_WIRELESS_EXT=y
+-
+-#
+-# Device Drivers
+-#
+-
+-#
+-# Generic Driver Options
+-#
+-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
+-
+-#
+-# Connector - unified userspace <-> kernelspace linker
+-#
+-# CONFIG_CONNECTOR is not set
+-
+-#
+-# Memory Technology Devices (MTD)
+-#
+-# CONFIG_MTD is not set
+-
+-#
+-# Parallel port support
+-#
+-# CONFIG_PARPORT is not set
+-
+-#
+-# Plug and Play support
+-#
+-# CONFIG_PNPACPI is not set
+-
+-#
+-# Block devices
+-#
+-# CONFIG_BLK_CPQ_DA is not set
+-# CONFIG_BLK_CPQ_CISS_DA is not set
+-# CONFIG_BLK_DEV_DAC960 is not set
+-# CONFIG_BLK_DEV_UMEM is not set
+-# CONFIG_BLK_DEV_COW_COMMON is not set
+-# CONFIG_BLK_DEV_LOOP is not set
+-# CONFIG_BLK_DEV_NBD is not set
+-# CONFIG_BLK_DEV_SX8 is not set
+-CONFIG_BLK_DEV_RAM=y
+-CONFIG_BLK_DEV_RAM_COUNT=16
+-CONFIG_BLK_DEV_RAM_SIZE=4096
+-CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+-# CONFIG_CDROM_PKTCDVD is not set
+-# CONFIG_ATA_OVER_ETH is not set
+-
+-#
+-# Misc devices
+-#
+-# CONFIG_SGI_IOC4 is not set
+-# CONFIG_TIFM_CORE is not set
+-
+-#
+-# ATA/ATAPI/MFM/RLL support
+-#
+-# CONFIG_IDE is not set
+-
+-#
+-# SCSI device support
+-#
+-# CONFIG_RAID_ATTRS is not set
+-CONFIG_SCSI=y
+-# CONFIG_SCSI_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=m
+-# 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
+-
+-#
+-# 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_ATTRS is not set
+-# CONFIG_SCSI_SAS_LIBSAS is not set
+-
+-#
+-# SCSI low-level drivers
+-#
+-# CONFIG_ISCSI_TCP is not set
+-# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+-# CONFIG_SCSI_3W_9XXX is not set
+-# CONFIG_SCSI_ACARD is not set
+-# CONFIG_SCSI_AACRAID is not set
+-# CONFIG_SCSI_AIC7XXX is not set
+-# CONFIG_SCSI_AIC7XXX_OLD is not set
+-# CONFIG_SCSI_AIC79XX is not set
+-# CONFIG_SCSI_AIC94XX is not set
+-# CONFIG_SCSI_DPT_I2O 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_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
+-
+-#
+-# Serial ATA (prod) and Parallel ATA (experimental) drivers
+-#
+-CONFIG_ATA=y
+-# CONFIG_ATA_NONSTANDARD is not set
+-# CONFIG_SATA_AHCI is not set
+-# 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=y
+-# CONFIG_SATA_SIL24 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_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_NS87410 is not set
+-# CONFIG_PATA_OPTI is not set
+-# CONFIG_PATA_OPTIDMA is not set
+-# 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=y
+-
+-#
+-# Multi-device support (RAID and LVM)
+-#
+-# CONFIG_MD is not set
+-
+-#
+-# Fusion MPT device support
+-#
+-# CONFIG_FUSION is not set
+-# CONFIG_FUSION_SPI is not set
+-# CONFIG_FUSION_FC is not set
+-# CONFIG_FUSION_SAS is not set
+-
+-#
+-# IEEE 1394 (FireWire) support
+-#
+-# CONFIG_IEEE1394 is not set
+-
+-#
+-# I2O device support
+-#
+-# CONFIG_I2O is not set
+-
+-#
+-# Network device support
+-#
+-CONFIG_NETDEVICES=y
+-# CONFIG_DUMMY is not set
+-# CONFIG_BONDING is not set
+-# CONFIG_EQUALIZER is not set
+-# CONFIG_TUN is not set
+-
+-#
+-# ARCnet devices
+-#
+-# CONFIG_ARCNET is not set
+-
+-#
+-# PHY device support
+-#
+-# CONFIG_PHYLIB is not set
+-
+-#
+-# Ethernet (10 or 100Mbit)
+-#
+-CONFIG_NET_ETHERNET=y
+-CONFIG_MII=y
+-# CONFIG_STNIC 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
+-
+-#
+-# Tulip family network device support
+-#
+-# CONFIG_NET_TULIP is not set
+-# CONFIG_HP100 is not set
+-CONFIG_NET_PCI=y
+-CONFIG_PCNET32=m
+-# CONFIG_PCNET32_NAPI is not set
+-# CONFIG_AMD8111_ETH is not set
+-# CONFIG_ADAPTEC_STARFIRE is not set
+-# CONFIG_B44 is not set
+-# CONFIG_FORCEDETH is not set
+-# CONFIG_DGRS is not set
+-# CONFIG_EEPRO100 is not set
+-# CONFIG_E100 is not set
+-# CONFIG_FEALNX is not set
+-# CONFIG_NATSEMI is not set
+-# CONFIG_NE2K_PCI is not set
+-CONFIG_8139CP=m
+-CONFIG_8139TOO=m
+-# CONFIG_8139TOO_PIO is not set
+-# CONFIG_8139TOO_TUNE_TWISTER is not set
+-CONFIG_8139TOO_8129=y
+-# CONFIG_8139_OLD_RX_RESET is not set
+-# CONFIG_SIS900 is not set
+-# CONFIG_EPIC100 is not set
+-# CONFIG_SUNDANCE is not set
+-# CONFIG_TLAN is not set
+-CONFIG_VIA_RHINE=m
+-CONFIG_VIA_RHINE_MMIO=y
+-# CONFIG_VIA_RHINE_NAPI is not set
+-# CONFIG_SC92031 is not set
+-
+-#
+-# Ethernet (1000 Mbit)
+-#
+-# CONFIG_ACENIC is not set
+-# CONFIG_DL2K is not set
+-CONFIG_E1000=m
+-# CONFIG_E1000_NAPI is not set
+-# CONFIG_E1000_DISABLE_PACKET_SPLIT is not set
+-# CONFIG_NS83820 is not set
+-# CONFIG_HAMACHI is not set
+-# CONFIG_YELLOWFIN is not set
+-CONFIG_R8169=y
+-# CONFIG_R8169_NAPI is not set
+-# CONFIG_SIS190 is not set
+-# CONFIG_SKGE is not set
+-# CONFIG_SKY2 is not set
+-# CONFIG_SK98LIN is not set
+-# CONFIG_VIA_VELOCITY is not set
+-# CONFIG_TIGON3 is not set
+-# CONFIG_BNX2 is not set
+-# CONFIG_QLA3XXX is not set
+-# CONFIG_ATL1 is not set
+-
+-#
+-# Ethernet (10000 Mbit)
+-#
+-# CONFIG_CHELSIO_T1 is not set
+-# CONFIG_CHELSIO_T3 is not set
+-# CONFIG_IXGB is not set
+-# CONFIG_S2IO is not set
+-# CONFIG_MYRI10GE is not set
+-# CONFIG_NETXEN_NIC is not set
+-
+-#
+-# Token Ring devices
+-#
+-# CONFIG_TR is not set
+-
+-#
+-# Wireless LAN (non-hamradio)
+-#
+-CONFIG_NET_RADIO=y
+-# CONFIG_NET_WIRELESS_RTNETLINK is not set
+-
+-#
+-# Obsolete Wireless cards support (pre-802.11)
+-#
+-# CONFIG_STRIP is not set
+-
+-#
+-# Wireless 802.11b ISA/PCI cards support
+-#
+-# CONFIG_IPW2100 is not set
+-# CONFIG_IPW2200 is not set
+-CONFIG_HERMES=m
+-# CONFIG_PLX_HERMES is not set
+-# CONFIG_TMD_HERMES is not set
+-# CONFIG_NORTEL_HERMES is not set
+-# CONFIG_PCI_HERMES is not set
+-# CONFIG_ATMEL is not set
+-
+-#
+-# Prism GT/Duette 802.11(a/b/g) PCI/Cardbus support
+-#
+-CONFIG_PRISM54=m
+-# CONFIG_HOSTAP is not set
+-CONFIG_NET_WIRELESS=y
+-
+-#
+-# Wan interfaces
+-#
+-# CONFIG_WAN is not set
+-# CONFIG_FDDI is not set
+-# CONFIG_HIPPI is not set
+-# CONFIG_PPP is not set
+-# CONFIG_SLIP is not set
+-# CONFIG_NET_FC is not set
+-# CONFIG_SHAPER is not set
+-# CONFIG_NETCONSOLE is not set
+-# CONFIG_NETPOLL is not set
+-# CONFIG_NET_POLL_CONTROLLER is not set
+-
+-#
+-# ISDN subsystem
+-#
+-# CONFIG_ISDN is not set
+-
+-#
+-# Telephony Support
+-#
+-# CONFIG_PHONE is not set
+-
+-#
+-# Input device support
+-#
+-CONFIG_INPUT=y
+-# CONFIG_INPUT_FF_MEMLESS 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_TSDEV is not set
+-# CONFIG_INPUT_EVDEV is not set
+-# CONFIG_INPUT_EVBUG 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_INPUT_MOUSE is not set
+-# CONFIG_INPUT_JOYSTICK is not set
+-# CONFIG_INPUT_TOUCHSCREEN is not set
+-# CONFIG_INPUT_MISC is not set
+-
+-#
+-# Hardware I/O ports
+-#
+-CONFIG_SERIO=y
+-# CONFIG_SERIO_I8042 is not set
+-# 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 is not set
+-# CONFIG_SERIAL_NONSTANDARD is not set
+-
+-#
+-# Serial drivers
+-#
+-# CONFIG_SERIAL_8250 is not set
+-
+-#
+-# Non-8250 serial port support
+-#
+-CONFIG_SERIAL_SH_SCI=y
+-CONFIG_SERIAL_SH_SCI_NR_UARTS=2
+-CONFIG_SERIAL_SH_SCI_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=256
+-
+-#
+-# IPMI
+-#
+-# CONFIG_IPMI_HANDLER is not set
+-
+-#
+-# Watchdog Cards
+-#
+-# CONFIG_WATCHDOG is not set
+-CONFIG_HW_RANDOM=y
+-# CONFIG_GEN_RTC is not set
+-# CONFIG_DTLK is not set
+-# CONFIG_R3964 is not set
+-# CONFIG_APPLICOM is not set
+-# CONFIG_DRM is not set
+-# CONFIG_RAW_DRIVER is not set
+-
+-#
+-# TPM devices
+-#
+-# CONFIG_TCG_TPM is not set
+-
+-#
+-# I2C support
+-#
+-# CONFIG_I2C is not set
+-
+-#
+-# SPI support
+-#
+-# CONFIG_SPI is not set
+-# CONFIG_SPI_MASTER is not set
+-
+-#
+-# Dallas's 1-wire bus
+-#
+-# CONFIG_W1 is not set
+-
+-#
+-# Hardware Monitoring support
+-#
+-CONFIG_HWMON=y
+-# CONFIG_HWMON_VID is not set
+-# CONFIG_SENSORS_ABITUGURU is not set
+-# CONFIG_SENSORS_F71805F is not set
+-# CONFIG_SENSORS_PC87427 is not set
+-# CONFIG_SENSORS_VT1211 is not set
+-# CONFIG_HWMON_DEBUG_CHIP is not set
+-
+-#
+-# Multifunction device drivers
+-#
+-# CONFIG_MFD_SM501 is not set
+-
+-#
+-# Multimedia devices
+-#
+-# CONFIG_VIDEO_DEV is not set
+-
+-#
+-# Digital Video Broadcasting Devices
+-#
+-# CONFIG_DVB is not set
+-
+-#
+-# Graphics support
+-#
+-# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+-# CONFIG_FB is not set
+-
+-#
+-# Sound
+-#
+-CONFIG_SOUND=m
+-
+-#
+-# Advanced Linux Sound Architecture
+-#
+-# CONFIG_SND is not set
+-
+-#
+-# Open Sound System
+-#
+-CONFIG_SOUND_PRIME=m
+-# CONFIG_OBSOLETE_OSS is not set
+-# CONFIG_SOUND_BT878 is not set
+-# CONFIG_SOUND_ICH is not set
+-# CONFIG_SOUND_TRIDENT is not set
+-# CONFIG_SOUND_MSNDCLAS is not set
+-# CONFIG_SOUND_MSNDPIN is not set
+-# CONFIG_SOUND_VIA82CXXX is not set
+-
+-#
+-# HID Devices
+-#
+-CONFIG_HID=y
+-# CONFIG_HID_DEBUG is not set
+-
+-#
+-# USB support
+-#
+-CONFIG_USB_ARCH_HAS_HCD=y
+-CONFIG_USB_ARCH_HAS_OHCI=y
+-CONFIG_USB_ARCH_HAS_EHCI=y
+-# CONFIG_USB is not set
+-
+-#
+-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+-#
+-
+-#
+-# USB Gadget Support
+-#
+-# CONFIG_USB_GADGET is not set
+-
+-#
+-# MMC/SD Card support
+-#
+-# CONFIG_MMC is not set
+-
+-#
+-# LED devices
+-#
+-# CONFIG_NEW_LEDS is not set
+-
+-#
+-# LED drivers
+-#
+-
+-#
+-# LED Triggers
+-#
+-
+-#
+-# InfiniBand support
+-#
+-# CONFIG_INFINIBAND is not set
+-
+-#
+-# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
+-#
+-
+-#
+-# Real Time Clock
+-#
+-CONFIG_RTC_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
+-
+-#
+-# RTC drivers
+-#
+-# CONFIG_RTC_DRV_DS1553 is not set
+-# CONFIG_RTC_DRV_DS1742 is not set
+-# CONFIG_RTC_DRV_M48T86 is not set
+-CONFIG_RTC_DRV_SH=y
+-# CONFIG_RTC_DRV_TEST is not set
+-# CONFIG_RTC_DRV_V3020 is not set
+-
+-#
+-# DMA Engine support
+-#
+-# CONFIG_DMA_ENGINE is not set
+-
+-#
+-# DMA Clients
+-#
+-
+-#
+-# DMA Devices
+-#
+-
+-#
+-# Auxiliary Display support
+-#
+-
+-#
+-# Virtualization
+-#
+-
+-#
+-# 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_JBD_DEBUG is not set
+-CONFIG_FS_MBCACHE=y
+-# CONFIG_REISERFS_FS is not set
+-# CONFIG_JFS_FS is not set
+-CONFIG_FS_POSIX_ACL=y
+-# CONFIG_XFS_FS is not set
+-# CONFIG_GFS2_FS is not set
+-# CONFIG_OCFS2_FS is not set
+-CONFIG_MINIX_FS=y
+-# CONFIG_ROMFS_FS is not set
+-CONFIG_INOTIFY=y
+-CONFIG_INOTIFY_USER=y
+-# CONFIG_QUOTA is not set
+-CONFIG_DNOTIFY=y
+-# CONFIG_AUTOFS_FS is not set
+-# CONFIG_AUTOFS4_FS is not set
+-CONFIG_FUSE_FS=m
+-
+-#
+-# 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=437
+-CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+-CONFIG_NTFS_FS=y
+-# CONFIG_NTFS_DEBUG is not set
+-CONFIG_NTFS_RW=y
+-
+-#
+-# Pseudo filesystems
+-#
+-CONFIG_PROC_FS=y
+-CONFIG_PROC_KCORE=y
+-CONFIG_PROC_SYSCTL=y
+-CONFIG_SYSFS=y
+-CONFIG_TMPFS=y
+-# CONFIG_TMPFS_POSIX_ACL is not set
+-CONFIG_HUGETLBFS=y
+-CONFIG_HUGETLB_PAGE=y
+-CONFIG_RAMFS=y
+-CONFIG_CONFIGFS_FS=m
+-
+-#
+-# Miscellaneous filesystems
+-#
+-# CONFIG_ADFS_FS is not set
+-# CONFIG_AFFS_FS is not set
+-# CONFIG_HFS_FS is not set
+-# CONFIG_HFSPLUS_FS is not set
+-# CONFIG_BEFS_FS is not set
+-# CONFIG_BFS_FS is not set
+-# CONFIG_EFS_FS is not set
+-# CONFIG_CRAMFS is not set
+-# CONFIG_VXFS_FS is not set
+-# CONFIG_HPFS_FS is not set
+-# CONFIG_QNX4FS_FS is not set
+-# CONFIG_SYSV_FS is not set
+-# CONFIG_UFS_FS is not set
+-
+-#
+-# Network File Systems
+-#
+-CONFIG_NFS_FS=y
+-CONFIG_NFS_V3=y
+-# CONFIG_NFS_V3_ACL is not set
+-CONFIG_NFS_V4=y
+-# CONFIG_NFS_DIRECTIO is not set
+-CONFIG_NFSD=y
+-CONFIG_NFSD_V3=y
+-# CONFIG_NFSD_V3_ACL is not set
+-CONFIG_NFSD_V4=y
+-CONFIG_NFSD_TCP=y
+-CONFIG_ROOT_NFS=y
+-CONFIG_LOCKD=y
+-CONFIG_LOCKD_V4=y
+-CONFIG_EXPORTFS=y
+-CONFIG_NFS_COMMON=y
+-CONFIG_SUNRPC=y
+-CONFIG_SUNRPC_GSS=y
+-CONFIG_RPCSEC_GSS_KRB5=y
+-# CONFIG_RPCSEC_GSS_SPKM3 is not set
+-# CONFIG_SMB_FS is not set
+-# CONFIG_CIFS is not set
+-# CONFIG_NCP_FS is not set
+-# CONFIG_CODA_FS is not set
+-# CONFIG_AFS_FS is not set
+-# CONFIG_9P_FS is not set
+-
+-#
+-# Partition Types
+-#
+-# CONFIG_PARTITION_ADVANCED is not set
+-CONFIG_MSDOS_PARTITION=y
+-
+-#
+-# Native Language Support
+-#
+-CONFIG_NLS=y
+-CONFIG_NLS_DEFAULT="iso8859-1"
+-CONFIG_NLS_CODEPAGE_437=y
+-# CONFIG_NLS_CODEPAGE_737 is not set
+-# CONFIG_NLS_CODEPAGE_775 is not set
+-# CONFIG_NLS_CODEPAGE_850 is not set
+-# CONFIG_NLS_CODEPAGE_852 is not set
+-# CONFIG_NLS_CODEPAGE_855 is not set
+-# CONFIG_NLS_CODEPAGE_857 is not set
+-# CONFIG_NLS_CODEPAGE_860 is not set
+-# CONFIG_NLS_CODEPAGE_861 is not set
+-# CONFIG_NLS_CODEPAGE_862 is not set
+-# CONFIG_NLS_CODEPAGE_863 is not set
+-# CONFIG_NLS_CODEPAGE_864 is not set
+-# CONFIG_NLS_CODEPAGE_865 is not set
+-# CONFIG_NLS_CODEPAGE_866 is not set
+-# CONFIG_NLS_CODEPAGE_869 is not set
+-# CONFIG_NLS_CODEPAGE_936 is not set
+-# CONFIG_NLS_CODEPAGE_950 is not set
+-CONFIG_NLS_CODEPAGE_932=y
+-# 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
+-
+-#
+-# Distributed Lock Manager
+-#
+-# CONFIG_DLM is not set
+-
+-#
+-# Profiling support
+-#
+-CONFIG_PROFILING=y
+-CONFIG_OPROFILE=m
+-
+-#
+-# Kernel hacking
+-#
+-CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+-# CONFIG_PRINTK_TIME is not set
+-CONFIG_ENABLE_MUST_CHECK=y
+-CONFIG_MAGIC_SYSRQ=y
+-# 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_LOG_BUF_SHIFT=14
+-CONFIG_DETECT_SOFTLOCKUP=y
+-# CONFIG_SCHEDSTATS is not set
+-# CONFIG_TIMER_STATS is not set
+-# CONFIG_DEBUG_SLAB is not set
+-# CONFIG_DEBUG_PREEMPT 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_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_LIST is not set
+-# CONFIG_FRAME_POINTER is not set
+-CONFIG_FORCED_INLINING=y
+-# CONFIG_RCU_TORTURE_TEST is not set
+-# CONFIG_FAULT_INJECTION is not set
+-CONFIG_SH_STANDARD_BIOS=y
+-# CONFIG_EARLY_SCIF_CONSOLE is not set
+-CONFIG_EARLY_PRINTK=y
+-CONFIG_DEBUG_STACKOVERFLOW=y
+-# CONFIG_DEBUG_STACK_USAGE is not set
+-# CONFIG_4KSTACKS is not set
+-# CONFIG_SH_KGDB is not set
+-
+-#
+-# Security options
+-#
+-# CONFIG_KEYS is not set
+-# CONFIG_SECURITY is not set
+-
+-#
+-# Cryptographic options
+-#
+-CONFIG_CRYPTO=y
+-CONFIG_CRYPTO_ALGAPI=y
+-CONFIG_CRYPTO_BLKCIPHER=y
+-CONFIG_CRYPTO_HASH=y
+-CONFIG_CRYPTO_MANAGER=y
+-CONFIG_CRYPTO_HMAC=y
+-# CONFIG_CRYPTO_XCBC is not set
+-# CONFIG_CRYPTO_NULL is not set
+-# CONFIG_CRYPTO_MD4 is not set
+-CONFIG_CRYPTO_MD5=y
+-# CONFIG_CRYPTO_SHA1 is not set
+-# CONFIG_CRYPTO_SHA256 is not set
+-# CONFIG_CRYPTO_SHA512 is not set
+-# CONFIG_CRYPTO_WP512 is not set
+-# CONFIG_CRYPTO_TGR192 is not set
+-# CONFIG_CRYPTO_GF128MUL is not set
+-CONFIG_CRYPTO_ECB=m
+-CONFIG_CRYPTO_CBC=y
+-CONFIG_CRYPTO_PCBC=m
+-# CONFIG_CRYPTO_LRW is not set
+-CONFIG_CRYPTO_DES=y
+-# CONFIG_CRYPTO_FCRYPT is not set
+-# CONFIG_CRYPTO_BLOWFISH is not set
+-# CONFIG_CRYPTO_TWOFISH is not set
+-# CONFIG_CRYPTO_SERPENT is not set
+-# CONFIG_CRYPTO_AES is not set
+-# CONFIG_CRYPTO_CAST5 is not set
+-# CONFIG_CRYPTO_CAST6 is not set
+-# CONFIG_CRYPTO_TEA is not set
+-# CONFIG_CRYPTO_ARC4 is not set
+-# CONFIG_CRYPTO_KHAZAD is not set
+-# CONFIG_CRYPTO_ANUBIS is not set
+-# CONFIG_CRYPTO_DEFLATE is not set
+-# CONFIG_CRYPTO_MICHAEL_MIC is not set
+-# CONFIG_CRYPTO_CRC32C is not set
+-# CONFIG_CRYPTO_CAMELLIA is not set
+-# CONFIG_CRYPTO_TEST is not set
+-
+-#
+-# Hardware crypto devices
+-#
+-
+-#
+-# Library routines
+-#
+-CONFIG_BITREVERSE=y
+-# CONFIG_CRC_CCITT is not set
+-# CONFIG_CRC16 is not set
+-CONFIG_CRC32=y
+-# CONFIG_LIBCRC32C is not set
+-CONFIG_HAS_IOMEM=y
+-CONFIG_HAS_IOPORT=y
+diff --git a/arch/sh/configs/r7785rp_defconfig b/arch/sh/configs/r7785rp_defconfig
+index 2e43a2a..0dc1ce7 100644
+--- a/arch/sh/configs/r7785rp_defconfig
++++ b/arch/sh/configs/r7785rp_defconfig
+@@ -1,9 +1,10 @@
+ #
+ # Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.24-rc2
+-# Tue Nov 13 20:34:57 2007
++# Linux kernel version: 2.6.24-rc3
++# Fri Nov 23 14:03:57 2007
+ #
+ CONFIG_SUPERH=y
++CONFIG_SUPERH32=y
+ CONFIG_RWSEM_GENERIC_SPINLOCK=y
+ CONFIG_GENERIC_BUG=y
+ CONFIG_GENERIC_FIND_NEXT_BIT=y
+@@ -39,6 +40,7 @@ CONFIG_BSD_PROCESS_ACCT=y
+ # CONFIG_BSD_PROCESS_ACCT_V3 is not set
+ # CONFIG_TASKSTATS is not set
+ # CONFIG_USER_NS is not set
++# CONFIG_PID_NS is not set
+ # CONFIG_AUDIT is not set
+ CONFIG_IKCONFIG=y
+ CONFIG_IKCONFIG_PROC=y
+@@ -130,6 +132,8 @@ CONFIG_CPU_SUBTYPE_SH7785=y
+ # CONFIG_CPU_SUBTYPE_SHX3 is not set
+ # CONFIG_CPU_SUBTYPE_SH7343 is not set
+ # CONFIG_CPU_SUBTYPE_SH7722 is not set
++# CONFIG_CPU_SUBTYPE_SH5_101 is not set
++# CONFIG_CPU_SUBTYPE_SH5_103 is not set
+ 
+ #
+ # Memory management options
+@@ -139,7 +143,8 @@ CONFIG_MMU=y
+ CONFIG_PAGE_OFFSET=0x80000000
+ CONFIG_MEMORY_START=0x08000000
+ CONFIG_MEMORY_SIZE=0x08000000
+-# CONFIG_32BIT is not set
++CONFIG_29BIT=y
++# CONFIG_PMB is not set
+ # CONFIG_X2TLB is not set
+ CONFIG_VSYSCALL=y
+ # CONFIG_NUMA is not set
+@@ -158,6 +163,7 @@ CONFIG_PAGE_SIZE_4KB=y
+ CONFIG_HUGETLB_PAGE_SIZE_1MB=y
+ # CONFIG_HUGETLB_PAGE_SIZE_4MB is not set
+ # CONFIG_HUGETLB_PAGE_SIZE_64MB is not set
++# CONFIG_HUGETLB_PAGE_SIZE_512MB is not set
+ CONFIG_SELECT_MEMORY_MODEL=y
+ # CONFIG_FLATMEM_MANUAL is not set
+ # CONFIG_DISCONTIGMEM_MANUAL is not set
+@@ -701,6 +707,7 @@ CONFIG_DEVPORT=y
+ # CONFIG_POWER_SUPPLY is not set
+ CONFIG_HWMON=y
+ # CONFIG_HWMON_VID is not set
++# CONFIG_SENSORS_I5K_AMB is not set
+ # CONFIG_SENSORS_F71805F is not set
+ # CONFIG_SENSORS_F71882FG is not set
+ # CONFIG_SENSORS_IT87 is not set
+diff --git a/arch/sh/configs/sdk7780_defconfig b/arch/sh/configs/sdk7780_defconfig
+new file mode 100644
+index 0000000..bb9bcd6
+--- /dev/null
++++ b/arch/sh/configs/sdk7780_defconfig
+@@ -0,0 +1,1394 @@
++#
++# Automatically generated make config: don't edit
++# Linux kernel version: 2.6.24-rc7
++# Tue Jan 22 11:34:03 2008
++#
++CONFIG_SUPERH=y
++CONFIG_SUPERH32=y
++CONFIG_RWSEM_GENERIC_SPINLOCK=y
++CONFIG_GENERIC_BUG=y
++CONFIG_GENERIC_FIND_NEXT_BIT=y
++CONFIG_GENERIC_HWEIGHT=y
++CONFIG_GENERIC_HARDIRQS=y
++CONFIG_GENERIC_IRQ_PROBE=y
++CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_GENERIC_TIME=y
++CONFIG_GENERIC_CLOCKEVENTS=y
++CONFIG_SYS_SUPPORTS_PCI=y
++CONFIG_STACKTRACE_SUPPORT=y
++CONFIG_LOCKDEP_SUPPORT=y
++# CONFIG_ARCH_HAS_ILOG2_U32 is not set
++# CONFIG_ARCH_HAS_ILOG2_U64 is not set
++CONFIG_ARCH_NO_VIRT_TO_BUS=y
++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="_SDK7780"
++CONFIG_LOCALVERSION_AUTO=y
++CONFIG_SWAP=y
++CONFIG_SYSVIPC=y
++CONFIG_SYSVIPC_SYSCTL=y
++CONFIG_POSIX_MQUEUE=y
++CONFIG_BSD_PROCESS_ACCT=y
++# CONFIG_BSD_PROCESS_ACCT_V3 is not set
++# CONFIG_TASKSTATS is not set
++# CONFIG_USER_NS is not set
++# CONFIG_PID_NS 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_FAIR_GROUP_SCHED=y
++CONFIG_FAIR_USER_SCHED=y
++# CONFIG_FAIR_CGROUP_SCHED is not set
++CONFIG_SYSFS_DEPRECATED=y
++CONFIG_RELAY=y
++# 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=y
++# CONFIG_KALLSYMS_EXTRA_PASS is not set
++CONFIG_HOTPLUG=y
++CONFIG_PRINTK=y
++CONFIG_BUG=y
++CONFIG_ELF_CORE=y
++CONFIG_BASE_FULL=y
++CONFIG_FUTEX=y
++CONFIG_ANON_INODES=y
++CONFIG_EPOLL=y
++CONFIG_SIGNALFD=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_SLABINFO=y
++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=y
++# CONFIG_MODVERSIONS is not set
++# CONFIG_MODULE_SRCVERSION_ALL is not set
++CONFIG_KMOD=y
++CONFIG_BLOCK=y
++CONFIG_LBD=y
++# 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=y
++# CONFIG_DEFAULT_DEADLINE is not set
++# CONFIG_DEFAULT_CFQ is not set
++# CONFIG_DEFAULT_NOOP is not set
++CONFIG_DEFAULT_IOSCHED="anticipatory"
++
++#
++# System type
++#
++CONFIG_CPU_SH4=y
++CONFIG_CPU_SH4A=y
++# CONFIG_CPU_SUBTYPE_SH7619 is not set
++# CONFIG_CPU_SUBTYPE_SH7203 is not set
++# CONFIG_CPU_SUBTYPE_SH7206 is not set
++# CONFIG_CPU_SUBTYPE_SH7263 is not set
++# CONFIG_CPU_SUBTYPE_SH7705 is not set
++# CONFIG_CPU_SUBTYPE_SH7706 is not set
++# CONFIG_CPU_SUBTYPE_SH7707 is not set
++# CONFIG_CPU_SUBTYPE_SH7708 is not set
++# CONFIG_CPU_SUBTYPE_SH7709 is not set
++# CONFIG_CPU_SUBTYPE_SH7710 is not set
++# CONFIG_CPU_SUBTYPE_SH7712 is not set
++# CONFIG_CPU_SUBTYPE_SH7720 is not set
++# CONFIG_CPU_SUBTYPE_SH7721 is not set
++# CONFIG_CPU_SUBTYPE_SH7750 is not set
++# CONFIG_CPU_SUBTYPE_SH7091 is not set
++# CONFIG_CPU_SUBTYPE_SH7750R is not set
++# CONFIG_CPU_SUBTYPE_SH7750S is not set
++# CONFIG_CPU_SUBTYPE_SH7751 is not set
++# CONFIG_CPU_SUBTYPE_SH7751R is not set
++# CONFIG_CPU_SUBTYPE_SH7760 is not set
++# CONFIG_CPU_SUBTYPE_SH4_202 is not set
++# CONFIG_CPU_SUBTYPE_SH7763 is not set
++# CONFIG_CPU_SUBTYPE_SH7770 is not set
++CONFIG_CPU_SUBTYPE_SH7780=y
++# CONFIG_CPU_SUBTYPE_SH7785 is not set
++# CONFIG_CPU_SUBTYPE_SHX3 is not set
++# CONFIG_CPU_SUBTYPE_SH7343 is not set
++# CONFIG_CPU_SUBTYPE_SH7722 is not set
++# CONFIG_CPU_SUBTYPE_SH5_101 is not set
++# CONFIG_CPU_SUBTYPE_SH5_103 is not set
++
++#
++# Memory management options
++#
++CONFIG_QUICKLIST=y
++CONFIG_MMU=y
++CONFIG_PAGE_OFFSET=0x80000000
++CONFIG_MEMORY_START=0x08000000
++CONFIG_MEMORY_SIZE=0x08000000
++CONFIG_29BIT=y
++# CONFIG_PMB is not set
++CONFIG_VSYSCALL=y
++CONFIG_ARCH_FLATMEM_ENABLE=y
++CONFIG_ARCH_SPARSEMEM_ENABLE=y
++CONFIG_ARCH_SPARSEMEM_DEFAULT=y
++CONFIG_MAX_ACTIVE_REGIONS=1
++CONFIG_ARCH_POPULATES_NODE_MAP=y
++CONFIG_ARCH_SELECT_MEMORY_MODEL=y
++CONFIG_PAGE_SIZE_4KB=y
++# CONFIG_PAGE_SIZE_8KB is not set
++# CONFIG_PAGE_SIZE_64KB is not set
++CONFIG_HUGETLB_PAGE_SIZE_64K=y
++# CONFIG_HUGETLB_PAGE_SIZE_256K is not set
++# CONFIG_HUGETLB_PAGE_SIZE_1MB is not set
++# CONFIG_HUGETLB_PAGE_SIZE_4MB is not set
++# CONFIG_HUGETLB_PAGE_SIZE_64MB is not set
++# CONFIG_HUGETLB_PAGE_SIZE_512MB 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=y
++# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
++CONFIG_SPLIT_PTLOCK_CPUS=4
++CONFIG_RESOURCES_64BIT=y
++CONFIG_ZONE_DMA_FLAG=0
++CONFIG_NR_QUICK=2
++
++#
++# Cache configuration
++#
++# CONFIG_SH_DIRECT_MAPPED is not set
++CONFIG_CACHE_WRITEBACK=y
++# CONFIG_CACHE_WRITETHROUGH is not set
++# CONFIG_CACHE_OFF is not set
++
++#
++# Processor features
++#
++CONFIG_CPU_LITTLE_ENDIAN=y
++# CONFIG_CPU_BIG_ENDIAN is not set
++CONFIG_SH_FPU=y
++CONFIG_SH_STORE_QUEUES=y
++# CONFIG_SPECULATIVE_EXECUTION is not set
++CONFIG_CPU_HAS_INTEVT=y
++CONFIG_CPU_HAS_SR_RB=y
++CONFIG_CPU_HAS_FPU=y
++
++#
++# Board support
++#
++# CONFIG_SH_7780_SOLUTION_ENGINE is not set
++CONFIG_SH_SDK7780=y
++# CONFIG_SH_HIGHLANDER is not set
++# CONFIG_SH_SDK7780_STANDALONE is not set
++CONFIG_SH_SDK7780_BASE=y
++
++#
++# Timer and clock configuration
++#
++CONFIG_SH_TMU=y
++CONFIG_SH_TIMER_IRQ=28
++CONFIG_SH_PCLK_FREQ=33333333
++CONFIG_TICK_ONESHOT=y
++# CONFIG_NO_HZ is not set
++CONFIG_HIGH_RES_TIMERS=y
++CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
++
++#
++# CPU Frequency scaling
++#
++# CONFIG_CPU_FREQ is not set
++
++#
++# DMA support
++#
++CONFIG_SH_DMA_API=y
++CONFIG_SH_DMA=y
++CONFIG_NR_ONCHIP_DMA_CHANNELS=12
++# CONFIG_NR_DMA_CHANNELS_BOOL is not set
++
++#
++# Companion Chips
++#
++
++#
++# Additional SuperH Device Drivers
++#
++CONFIG_HEARTBEAT=y
++# CONFIG_PUSH_SWITCH is not set
++
++#
++# Kernel features
++#
++# 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_KEXEC is not set
++# CONFIG_CRASH_DUMP is not set
++# CONFIG_PREEMPT_NONE is not set
++# CONFIG_PREEMPT_VOLUNTARY is not set
++CONFIG_PREEMPT=y
++CONFIG_PREEMPT_BKL=y
++CONFIG_GUSA=y
++
++#
++# Boot options
++#
++CONFIG_ZERO_PAGE_OFFSET=0x00001000
++CONFIG_BOOT_LINK_OFFSET=0x01800000
++CONFIG_CMDLINE_BOOL=y
++CONFIG_CMDLINE="mem=128M console=tty0 console=ttySC0,115200 ip=bootp root=/dev/nfs nfsroot=192.168.0.1:/home/rootfs"
++
++#
++# Bus options
++#
++CONFIG_PCI=y
++CONFIG_SH_PCIDMA_NONCOHERENT=y
++CONFIG_PCI_AUTO=y
++CONFIG_PCI_AUTO_UPDATE_RESOURCES=y
++# CONFIG_ARCH_SUPPORTS_MSI is not set
++# CONFIG_PCI_LEGACY is not set
++CONFIG_PCI_DEBUG=y
++CONFIG_PCCARD=y
++# CONFIG_PCMCIA_DEBUG is not set
++CONFIG_PCMCIA=y
++CONFIG_PCMCIA_LOAD_CIS=y
++CONFIG_PCMCIA_IOCTL=y
++CONFIG_CARDBUS=y
++
++#
++# PC-card bridges
++#
++CONFIG_YENTA=y
++CONFIG_YENTA_O2=y
++CONFIG_YENTA_RICOH=y
++CONFIG_YENTA_TI=y
++CONFIG_YENTA_ENE_TUNE=y
++CONFIG_YENTA_TOSHIBA=y
++# CONFIG_PD6729 is not set
++# CONFIG_I82092 is not set
++CONFIG_PCCARD_NONSTATIC=y
++CONFIG_HOTPLUG_PCI=y
++# CONFIG_HOTPLUG_PCI_FAKE is not set
++# CONFIG_HOTPLUG_PCI_CPCI is not set
++# CONFIG_HOTPLUG_PCI_SHPC is not set
++
++#
++# Executable file formats
++#
++CONFIG_BINFMT_ELF=y
++# CONFIG_BINFMT_MISC 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_NET_KEY is not set
++CONFIG_INET=y
++CONFIG_IP_MULTICAST=y
++CONFIG_IP_ADVANCED_ROUTER=y
++CONFIG_ASK_IP_FIB_HASH=y
++# CONFIG_IP_FIB_TRIE is not set
++CONFIG_IP_FIB_HASH=y
++# CONFIG_IP_MULTIPLE_TABLES is not set
++# CONFIG_IP_ROUTE_MULTIPATH is not set
++# CONFIG_IP_ROUTE_VERBOSE is not set
++CONFIG_IP_PNP=y
++# CONFIG_IP_PNP_DHCP is not set
++CONFIG_IP_PNP_BOOTP=y
++# CONFIG_IP_PNP_RARP is not set
++# CONFIG_NET_IPIP is not set
++# CONFIG_NET_IPGRE is not set
++# CONFIG_IP_MROUTE is not set
++# CONFIG_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=y
++CONFIG_INET_XFRM_MODE_TRANSPORT=y
++CONFIG_INET_XFRM_MODE_TUNNEL=y
++# 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=y
++# CONFIG_IPV6_PRIVACY is not set
++# CONFIG_IPV6_ROUTER_PREF is not set
++# CONFIG_IPV6_OPTIMISTIC_DAD is not set
++# CONFIG_INET6_AH is not set
++# CONFIG_INET6_ESP is not set
++# CONFIG_INET6_IPCOMP is not set
++# CONFIG_IPV6_MIP6 is not set
++# CONFIG_INET6_XFRM_TUNNEL is not set
++# CONFIG_INET6_TUNNEL is not set
++CONFIG_INET6_XFRM_MODE_TRANSPORT=y
++CONFIG_INET6_XFRM_MODE_TUNNEL=y
++# CONFIG_INET6_XFRM_MODE_BEET is not set
++# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
++CONFIG_IPV6_SIT=y
++# CONFIG_IPV6_TUNNEL is not set
++# CONFIG_IPV6_MULTIPLE_TABLES 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=y
++
++#
++# Queueing/Scheduling
++#
++# CONFIG_NET_SCH_CBQ is not set
++# CONFIG_NET_SCH_HTB is not set
++# CONFIG_NET_SCH_HFSC is not set
++# CONFIG_NET_SCH_PRIO is not set
++# CONFIG_NET_SCH_RR is not set
++# CONFIG_NET_SCH_RED is not set
++# CONFIG_NET_SCH_SFQ is not set
++# CONFIG_NET_SCH_TEQL is not set
++# CONFIG_NET_SCH_TBF is not set
++# CONFIG_NET_SCH_GRED is not set
++# CONFIG_NET_SCH_DSMARK is not set
++# CONFIG_NET_SCH_NETEM is not set
++# CONFIG_NET_SCH_INGRESS is not set
++
++#
++# Classification
++#
++# CONFIG_NET_CLS_BASIC is not set
++# CONFIG_NET_CLS_TCINDEX is not set
++# CONFIG_NET_CLS_ROUTE4 is not set
++# CONFIG_NET_CLS_FW is not set
++# CONFIG_NET_CLS_U32 is not set
++# CONFIG_NET_CLS_RSVP is not set
++# CONFIG_NET_CLS_RSVP6 is not set
++# CONFIG_NET_EMATCH is not set
++# CONFIG_NET_CLS_ACT is not set
++# CONFIG_NET_CLS_POLICE is not set
++CONFIG_NET_SCH_FIFO=y
++
++#
++# Network testing
++#
++# CONFIG_NET_PKTGEN is not set
++# CONFIG_HAMRADIO 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_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=y
++# CONFIG_PARPORT_PC is not set
++# CONFIG_PARPORT_GSC is not set
++# CONFIG_PARPORT_AX88796 is not set
++# CONFIG_PARPORT_1284 is not set
++CONFIG_BLK_DEV=y
++# 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_RAM_BLOCKSIZE=1024
++# CONFIG_CDROM_PKTCDVD is not set
++# CONFIG_ATA_OVER_ETH is not set
++# CONFIG_MISC_DEVICES is not set
++CONFIG_IDE=y
++CONFIG_IDE_MAX_HWIFS=4
++CONFIG_BLK_DEV_IDE=y
++
++#
++# Please see Documentation/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=y
++# CONFIG_BLK_DEV_IDECS is not set
++# CONFIG_BLK_DEV_DELKIN is not set
++CONFIG_BLK_DEV_IDECD=y
++# CONFIG_BLK_DEV_IDETAPE is not set
++# CONFIG_BLK_DEV_IDEFLOPPY is not set
++# CONFIG_BLK_DEV_IDESCSI is not set
++# CONFIG_IDE_TASK_IOCTL is not set
++CONFIG_IDE_PROC_FS=y
++
++#
++# IDE chipset support/bugfixes
++#
++CONFIG_IDE_GENERIC=y
++CONFIG_BLK_DEV_PLATFORM=y
++
++#
++# PCI IDE chipsets support
++#
++CONFIG_BLK_DEV_IDEPCI=y
++# CONFIG_IDEPCI_SHARE_IRQ is not set
++CONFIG_IDEPCI_PCIBUS_ORDER=y
++# CONFIG_BLK_DEV_OFFBOARD is not set
++CONFIG_BLK_DEV_GENERIC=y
++# CONFIG_BLK_DEV_OPTI621 is not set
++# CONFIG_BLK_DEV_AEC62XX is not set
++# CONFIG_BLK_DEV_ALI15X3 is not set
++# CONFIG_BLK_DEV_AMD74XX is not set
++# CONFIG_BLK_DEV_CMD64X is not set
++# CONFIG_BLK_DEV_TRIFLEX is not set
++# CONFIG_BLK_DEV_CY82C693 is not set
++# CONFIG_BLK_DEV_CS5520 is not set
++# CONFIG_BLK_DEV_CS5530 is not set
++# CONFIG_BLK_DEV_HPT34X is not set
++# CONFIG_BLK_DEV_HPT366 is not set
++# CONFIG_BLK_DEV_JMICRON is not set
++# CONFIG_BLK_DEV_SC1200 is not set
++# CONFIG_BLK_DEV_PIIX is not set
++# CONFIG_BLK_DEV_IT8213 is not set
++# CONFIG_BLK_DEV_IT821X is not set
++# CONFIG_BLK_DEV_NS87415 is not set
++# CONFIG_BLK_DEV_PDC202XX_OLD is not set
++# CONFIG_BLK_DEV_PDC202XX_NEW is not set
++# CONFIG_BLK_DEV_SVWKS is not set
++# CONFIG_BLK_DEV_SIIMAGE is not set
++# CONFIG_BLK_DEV_SLC90E66 is not set
++# CONFIG_BLK_DEV_TRM290 is not set
++# CONFIG_BLK_DEV_VIA82CXXX is not set
++# CONFIG_BLK_DEV_TC86C001 is not set
++# CONFIG_IDE_ARM is not set
++# CONFIG_BLK_DEV_IDEDMA is not set
++# CONFIG_IDE_ARCH_OBSOLETE_INIT is not set
++# CONFIG_BLK_DEV_HD 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=y
++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=y
++# CONFIG_BLK_DEV_SR_VENDOR is not set
++CONFIG_CHR_DEV_SG=y
++# 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=y
++CONFIG_SCSI_FC_ATTRS=y
++# 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_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_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=y
++# CONFIG_ATA_NONSTANDARD is not set
++# CONFIG_SATA_AHCI is not set
++# 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_SIL24 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_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 is not set
++# 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=y
++# CONFIG_BLK_DEV_MD is not set
++CONFIG_BLK_DEV_DM=y
++# CONFIG_DM_DEBUG is not set
++# CONFIG_DM_CRYPT is not set
++# CONFIG_DM_SNAPSHOT is not set
++# CONFIG_DM_MIRROR is not set
++# CONFIG_DM_ZERO is not set
++# CONFIG_DM_MULTIPATH is not set
++# CONFIG_DM_DELAY is not set
++# CONFIG_DM_UEVENT 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_STNIC 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=y
++# 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 is not set
++# CONFIG_B44 is not set
++# CONFIG_NET_POCKET 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
++
++#
++# 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_PLIP is not set
++# CONFIG_PPP is not set
++# CONFIG_SLIP is not set
++# CONFIG_NET_FC is not set
++# CONFIG_SHAPER is not set
++CONFIG_NETCONSOLE=y
++# CONFIG_NETCONSOLE_DYNAMIC is not set
++CONFIG_NETPOLL=y
++# CONFIG_NETPOLL_TRAP is not set
++CONFIG_NET_POLL_CONTROLLER=y
++# 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=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
++
++#
++# 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_INPUT_MOUSE=y
++CONFIG_MOUSE_PS2=y
++CONFIG_MOUSE_PS2_ALPS=y
++CONFIG_MOUSE_PS2_LOGIPS2PP=y
++CONFIG_MOUSE_PS2_SYNAPTICS=y
++CONFIG_MOUSE_PS2_LIFEBOOK=y
++CONFIG_MOUSE_PS2_TRACKPOINT=y
++# CONFIG_MOUSE_PS2_TOUCHKIT is not set
++# CONFIG_MOUSE_SERIAL is not set
++# CONFIG_MOUSE_APPLETOUCH is not set
++# CONFIG_MOUSE_VSXXXAA 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=y
++# CONFIG_SERIO_I8042 is not set
++# CONFIG_SERIO_SERPORT is not set
++# CONFIG_SERIO_PARKBD 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_SERIAL_NONSTANDARD is not set
++
++#
++# Serial drivers
++#
++# CONFIG_SERIAL_8250 is not set
++
++#
++# Non-8250 serial port support
++#
++CONFIG_SERIAL_SH_SCI=y
++CONFIG_SERIAL_SH_SCI_NR_UARTS=2
++CONFIG_SERIAL_SH_SCI_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=256
++# CONFIG_PRINTER is not set
++# CONFIG_PPDEV is not set
++# CONFIG_IPMI_HANDLER is not set
++CONFIG_HW_RANDOM=y
++# 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_RAW_DRIVER is not set
++# CONFIG_TCG_TPM is not set
++CONFIG_DEVPORT=y
++# CONFIG_I2C is not set
++
++#
++# SPI support
++#
++# CONFIG_SPI is not set
++# CONFIG_SPI_MASTER is not set
++# CONFIG_W1 is not set
++CONFIG_POWER_SUPPLY=y
++# CONFIG_POWER_SUPPLY_DEBUG is not set
++# CONFIG_PDA_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=y
++CONFIG_SSB_PCIHOST_POSSIBLE=y
++CONFIG_SSB_PCIHOST=y
++CONFIG_SSB_PCMCIAHOST_POSSIBLE=y
++# CONFIG_SSB_PCMCIAHOST is not set
++# CONFIG_SSB_SILENT is not set
++# CONFIG_SSB_DEBUG is not set
++CONFIG_SSB_DRIVER_PCICORE_POSSIBLE=y
++CONFIG_SSB_DRIVER_PCICORE=y
++
++#
++# Multifunction device drivers
++#
++# CONFIG_MFD_SM501 is not set
++
++#
++# Multimedia devices
++#
++# CONFIG_VIDEO_DEV is not set
++# CONFIG_DVB_CORE is not set
++# 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 is not set
++# CONFIG_FB_CFB_COPYAREA is not set
++# CONFIG_FB_CFB_IMAGEBLIT is not set
++# 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_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_VIRTUAL is not set
++# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
++
++#
++# Display device support
++#
++CONFIG_DISPLAY_SUPPORT=y
++
++#
++# Display hardware drivers
++#
++
++#
++# Console display driver support
++#
++CONFIG_DUMMY_CONSOLE=y
++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=y
++CONFIG_LOGO_LINUX_MONO=y
++CONFIG_LOGO_LINUX_VGA16=y
++CONFIG_LOGO_LINUX_CLUT224=y
++CONFIG_LOGO_SUPERH_MONO=y
++CONFIG_LOGO_SUPERH_VGA16=y
++CONFIG_LOGO_SUPERH_CLUT224=y
++
++#
++# Sound
++#
++CONFIG_SOUND=y
++
++#
++# Advanced Linux Sound Architecture
++#
++# CONFIG_SND is not set
++
++#
++# Open Sound System
++#
++CONFIG_SOUND_PRIME=y
++# CONFIG_SOUND_TRIDENT is not set
++# CONFIG_SOUND_MSNDCLAS is not set
++# CONFIG_SOUND_MSNDPIN 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=y
++CONFIG_USB_ARCH_HAS_EHCI=y
++CONFIG_USB=y
++CONFIG_USB_DEBUG=y
++
++#
++# Miscellaneous USB options
++#
++CONFIG_USB_DEVICEFS=y
++# CONFIG_USB_DEVICE_CLASS is not set
++# CONFIG_USB_DYNAMIC_MINORS is not set
++# CONFIG_USB_OTG is not set
++
++#
++# USB Host Controller Drivers
++#
++CONFIG_USB_EHCI_HCD=y
++# CONFIG_USB_EHCI_SPLIT_ISO is not set
++# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
++# CONFIG_USB_EHCI_TT_NEWSCHED is not set
++# CONFIG_USB_ISP116X_HCD is not set
++# CONFIG_USB_OHCI_HCD is not set
++# 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=y
++
++#
++# 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_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_USS720 is not set
++
++#
++# USB Serial Converter support
++#
++# CONFIG_USB_SERIAL is not set
++
++#
++# USB Miscellaneous drivers
++#
++# CONFIG_USB_EMI62 is not set
++# CONFIG_USB_EMI26 is not set
++# CONFIG_USB_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_TEST is not set
++
++#
++# USB DSL modem support
++#
++
++#
++# USB Gadget Support
++#
++# CONFIG_USB_GADGET is not set
++# CONFIG_MMC is not set
++CONFIG_NEW_LEDS=y
++CONFIG_LEDS_CLASS=y
++
++#
++# LED drivers
++#
++
++#
++# LED Triggers
++#
++# CONFIG_LEDS_TRIGGERS is not set
++# CONFIG_INFINIBAND is not set
++# CONFIG_RTC_CLASS is not set
++# CONFIG_AUXDISPLAY is not set
++
++#
++# Userspace I/O
++#
++# CONFIG_UIO is not set
++
++#
++# File systems
++#
++CONFIG_EXT2_FS=y
++CONFIG_EXT2_FS_XATTR=y
++CONFIG_EXT2_FS_POSIX_ACL=y
++# CONFIG_EXT2_FS_SECURITY is not set
++# CONFIG_EXT2_FS_XIP is not set
++CONFIG_EXT3_FS=y
++CONFIG_EXT3_FS_XATTR=y
++CONFIG_EXT3_FS_POSIX_ACL=y
++# CONFIG_EXT3_FS_SECURITY is not set
++# CONFIG_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=y
++# CONFIG_XFS_FS is not set
++# CONFIG_GFS2_FS is not set
++# CONFIG_OCFS2_FS is not set
++CONFIG_MINIX_FS=y
++# CONFIG_ROMFS_FS is not set
++CONFIG_INOTIFY=y
++CONFIG_INOTIFY_USER=y
++# CONFIG_QUOTA is not set
++CONFIG_DNOTIFY=y
++# CONFIG_AUTOFS_FS is not set
++CONFIG_AUTOFS4_FS=y
++# CONFIG_FUSE_FS is not set
++CONFIG_GENERIC_ACL=y
++
++#
++# CD-ROM/DVD Filesystems
++#
++CONFIG_ISO9660_FS=y
++# CONFIG_JOLIET is not set
++# CONFIG_ZISOFS is not set
++# CONFIG_UDF_FS is not set
++
++#
++# DOS/FAT/NT Filesystems
++#
++CONFIG_FAT_FS=y
++CONFIG_MSDOS_FS=y
++CONFIG_VFAT_FS=y
++CONFIG_FAT_DEFAULT_CODEPAGE=437
++CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
++CONFIG_NTFS_FS=y
++CONFIG_NTFS_DEBUG=y
++CONFIG_NTFS_RW=y
++
++#
++# Pseudo filesystems
++#
++CONFIG_PROC_FS=y
++# CONFIG_PROC_KCORE is not set
++CONFIG_PROC_SYSCTL=y
++CONFIG_SYSFS=y
++CONFIG_TMPFS=y
++CONFIG_TMPFS_POSIX_ACL=y
++CONFIG_HUGETLBFS=y
++CONFIG_HUGETLB_PAGE=y
++# CONFIG_CONFIGFS_FS is not set
++
++#
++# Miscellaneous filesystems
++#
++# CONFIG_ADFS_FS is not set
++# CONFIG_AFFS_FS is not set
++# CONFIG_HFS_FS is not set
++# CONFIG_HFSPLUS_FS is not set
++# CONFIG_BEFS_FS is not set
++# CONFIG_BFS_FS is not set
++# CONFIG_EFS_FS is not set
++# CONFIG_CRAMFS is not set
++# CONFIG_VXFS_FS is not set
++# CONFIG_HPFS_FS is not set
++# CONFIG_QNX4FS_FS is not set
++# CONFIG_SYSV_FS is not set
++# CONFIG_UFS_FS is not set
++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_NFS_DIRECTIO is not set
++CONFIG_NFSD=y
++CONFIG_NFSD_V3=y
++# CONFIG_NFSD_V3_ACL is not set
++# CONFIG_NFSD_V4 is not set
++CONFIG_NFSD_TCP=y
++CONFIG_ROOT_NFS=y
++CONFIG_LOCKD=y
++CONFIG_LOCKD_V4=y
++CONFIG_EXPORTFS=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 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 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=y
++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=y
++# CONFIG_NLS_KOI8_R is not set
++# CONFIG_NLS_KOI8_U is not set
++CONFIG_NLS_UTF8=y
++# CONFIG_DLM is not set
++# CONFIG_INSTRUMENTATION is not set
++
++#
++# Kernel hacking
++#
++CONFIG_TRACE_IRQFLAGS_SUPPORT=y
++# CONFIG_PRINTK_TIME is not set
++CONFIG_ENABLE_WARN_DEPRECATED=y
++# CONFIG_ENABLE_MUST_CHECK is not set
++CONFIG_MAGIC_SYSRQ=y
++CONFIG_UNUSED_SYMBOLS=y
++# 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_SCHED_DEBUG is not set
++# CONFIG_SCHEDSTATS is not set
++CONFIG_TIMER_STATS=y
++# CONFIG_SLUB_DEBUG_ON 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_LIST is not set
++# CONFIG_DEBUG_SG is not set
++# CONFIG_FRAME_POINTER is not set
++# CONFIG_FORCED_INLINING is not set
++# CONFIG_BOOT_PRINTK_DELAY is not set
++# CONFIG_RCU_TORTURE_TEST is not set
++# CONFIG_FAULT_INJECTION is not set
++# CONFIG_SAMPLES is not set
++CONFIG_SH_STANDARD_BIOS=y
++# CONFIG_EARLY_SCIF_CONSOLE is not set
++# CONFIG_EARLY_PRINTK is not set
++# CONFIG_DEBUG_BOOTMEM is not set
++CONFIG_DEBUG_STACKOVERFLOW=y
++# CONFIG_DEBUG_STACK_USAGE is not set
++# CONFIG_4KSTACKS is not set
++# CONFIG_IRQSTACKS is not set
++# CONFIG_SH_KGDB 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
++CONFIG_CRYPTO_ALGAPI=y
++# CONFIG_CRYPTO_MANAGER is not set
++# CONFIG_CRYPTO_HMAC is not set
++# CONFIG_CRYPTO_XCBC is not set
++# CONFIG_CRYPTO_NULL is not set
++# CONFIG_CRYPTO_MD4 is not set
++CONFIG_CRYPTO_MD5=y
++# CONFIG_CRYPTO_SHA1 is not set
++# CONFIG_CRYPTO_SHA256 is not set
++# CONFIG_CRYPTO_SHA512 is not set
++# CONFIG_CRYPTO_WP512 is not set
++# CONFIG_CRYPTO_TGR192 is not set
++# CONFIG_CRYPTO_GF128MUL is not set
++# CONFIG_CRYPTO_ECB is not set
++# CONFIG_CRYPTO_CBC is not set
++# CONFIG_CRYPTO_PCBC is not set
++# CONFIG_CRYPTO_LRW is not set
++# CONFIG_CRYPTO_XTS is not set
++# CONFIG_CRYPTO_CRYPTD is not set
++CONFIG_CRYPTO_DES=y
++# CONFIG_CRYPTO_FCRYPT is not set
++# CONFIG_CRYPTO_BLOWFISH is not set
++# CONFIG_CRYPTO_TWOFISH is not set
++# CONFIG_CRYPTO_SERPENT is not set
++# CONFIG_CRYPTO_AES is not set
++# CONFIG_CRYPTO_CAST5 is not set
++# CONFIG_CRYPTO_CAST6 is not set
++# CONFIG_CRYPTO_TEA is not set
++# CONFIG_CRYPTO_ARC4 is not set
++# CONFIG_CRYPTO_KHAZAD is not set
++# CONFIG_CRYPTO_ANUBIS is not set
++# CONFIG_CRYPTO_SEED is not set
++# CONFIG_CRYPTO_DEFLATE is not set
++# CONFIG_CRYPTO_MICHAEL_MIC is not set
++# CONFIG_CRYPTO_CRC32C is not set
++# CONFIG_CRYPTO_CAMELLIA is not set
++# CONFIG_CRYPTO_TEST is not set
++# CONFIG_CRYPTO_AUTHENC is not set
++CONFIG_CRYPTO_HW=y
++
++#
++# Library routines
++#
++CONFIG_BITREVERSE=y
++# CONFIG_CRC_CCITT is not set
++# 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_PLIST=y
++CONFIG_HAS_IOMEM=y
++CONFIG_HAS_IOPORT=y
++CONFIG_HAS_DMA=y
+diff --git a/arch/sh/configs/se7712_defconfig b/arch/sh/configs/se7712_defconfig
+index a5e37db..240a1ce 100644
+--- a/arch/sh/configs/se7712_defconfig
++++ b/arch/sh/configs/se7712_defconfig
+@@ -237,7 +237,7 @@ CONFIG_CPU_HAS_SR_RB=y
+ CONFIG_SH_TMU=y
+ CONFIG_SH_TIMER_IRQ=16
+ # CONFIG_NO_IDLE_HZ is not set
+-CONFIG_SH_PCLK_FREQ=33333333
++CONFIG_SH_PCLK_FREQ=66666666
+ 
+ #
+ # CPU Frequency scaling
+diff --git a/arch/sh/drivers/dma/Kconfig b/arch/sh/drivers/dma/Kconfig
+index 4e711a0..0193636 100644
+--- a/arch/sh/drivers/dma/Kconfig
++++ b/arch/sh/drivers/dma/Kconfig
+@@ -12,7 +12,7 @@ config SH_DMA
+ config NR_ONCHIP_DMA_CHANNELS
+ 	int
+ 	depends on SH_DMA
+-	default "6" if CPU_SUBTYPE_SH7720
++	default "6" if CPU_SUBTYPE_SH7720 || CPU_SUBTYPE_SH7721
+ 	default "8" if CPU_SUBTYPE_SH7750R || CPU_SUBTYPE_SH7751R
+ 	default "12" if CPU_SUBTYPE_SH7780
+ 	default "4"
+diff --git a/arch/sh/drivers/dma/dma-sh.c b/arch/sh/drivers/dma/dma-sh.c
+index 958bac1..5c33597 100644
+--- a/arch/sh/drivers/dma/dma-sh.c
++++ b/arch/sh/drivers/dma/dma-sh.c
+@@ -25,6 +25,7 @@ static int dmte_irq_map[] = {
+ 	DMTE2_IRQ,
+ 	DMTE3_IRQ,
+ #if defined(CONFIG_CPU_SUBTYPE_SH7720)  ||	\
++    defined(CONFIG_CPU_SUBTYPE_SH7721)  ||	\
+     defined(CONFIG_CPU_SUBTYPE_SH7751R) ||	\
+     defined(CONFIG_CPU_SUBTYPE_SH7760)  ||	\
+     defined(CONFIG_CPU_SUBTYPE_SH7709)  ||	\
+@@ -203,6 +204,7 @@ static int sh_dmac_get_dma_residue(struct dma_channel *chan)
+ }
+ 
+ #if defined(CONFIG_CPU_SUBTYPE_SH7720) || \
++    defined(CONFIG_CPU_SUBTYPE_SH7721) || \
+     defined(CONFIG_CPU_SUBTYPE_SH7780)
+ #define dmaor_read_reg()	ctrl_inw(DMAOR)
+ #define dmaor_write_reg(data)	ctrl_outw(data, DMAOR)
+diff --git a/arch/sh/drivers/dma/dma-sysfs.c b/arch/sh/drivers/dma/dma-sysfs.c
+index eebcd47..51b57c0 100644
+--- a/arch/sh/drivers/dma/dma-sysfs.c
++++ b/arch/sh/drivers/dma/dma-sysfs.c
+@@ -19,7 +19,7 @@
+ #include <asm/dma.h>
+ 
+ static struct sysdev_class dma_sysclass = {
+-	set_kset_name("dma"),
++	.name = "dma",
+ };
+ EXPORT_SYMBOL(dma_sysclass);
+ 
+diff --git a/arch/sh/drivers/pci/Makefile b/arch/sh/drivers/pci/Makefile
+index fba6b5b..0718805 100644
+--- a/arch/sh/drivers/pci/Makefile
++++ b/arch/sh/drivers/pci/Makefile
+@@ -7,16 +7,19 @@ obj-$(CONFIG_PCI_AUTO)			+= pci-auto.o
+ 
+ obj-$(CONFIG_CPU_SUBTYPE_SH7751)	+= pci-sh7751.o ops-sh4.o
+ obj-$(CONFIG_CPU_SUBTYPE_SH7751R)	+= pci-sh7751.o ops-sh4.o
++obj-$(CONFIG_CPU_SUBTYPE_SH7763)	+= pci-sh7780.o ops-sh4.o
+ obj-$(CONFIG_CPU_SUBTYPE_SH7780)	+= pci-sh7780.o ops-sh4.o
+ obj-$(CONFIG_CPU_SUBTYPE_SH7785)	+= pci-sh7780.o ops-sh4.o
++obj-$(CONFIG_CPU_SH5)			+= pci-sh5.o ops-sh5.o
+ 
+-obj-$(CONFIG_SH_DREAMCAST)		+= ops-dreamcast.o fixups-dreamcast.o \
+-					   dma-dreamcast.o
++obj-$(CONFIG_SH_DREAMCAST)		+= ops-dreamcast.o fixups-dreamcast.o
+ obj-$(CONFIG_SH_SECUREEDGE5410)		+= ops-snapgear.o
+ obj-$(CONFIG_SH_RTS7751R2D)		+= ops-rts7751r2d.o fixups-rts7751r2d.o
+ obj-$(CONFIG_SH_SH03)			+= ops-sh03.o fixups-sh03.o
+ obj-$(CONFIG_SH_HIGHLANDER)		+= ops-r7780rp.o fixups-r7780rp.o
++obj-$(CONFIG_SH_SDK7780)		+= ops-sdk7780.o fixups-sdk7780.o
+ obj-$(CONFIG_SH_TITAN)			+= ops-titan.o
+ obj-$(CONFIG_SH_LANDISK)		+= ops-landisk.o
+ obj-$(CONFIG_SH_LBOX_RE2)		+= ops-lboxre2.o fixups-lboxre2.o
+ obj-$(CONFIG_SH_7780_SOLUTION_ENGINE)	+= ops-se7780.o fixups-se7780.o
++obj-$(CONFIG_SH_CAYMAN)			+= ops-cayman.o
+diff --git a/arch/sh/drivers/pci/dma-dreamcast.c b/arch/sh/drivers/pci/dma-dreamcast.c
+deleted file mode 100644
+index 888a340..0000000
+--- a/arch/sh/drivers/pci/dma-dreamcast.c
++++ /dev/null
+@@ -1,70 +0,0 @@
+-/*
+- * arch/sh/drivers/pci/dma-dreamcast.c
+- *
+- * PCI DMA support for the Sega Dreamcast
+- *
+- * Copyright (C) 2001, 2002  M. R. Brown
+- * Copyright (C) 2002, 2003  Paul Mundt
+- *
+- * This file originally bore the message (with enclosed-$):
+- *	Id: pci.c,v 1.3 2003/05/04 19:29:46 lethal Exp
+- *	Dreamcast PCI: Supports SEGA Broadband Adaptor only.
+- *
+- * 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/sched.h>
+-#include <linux/kernel.h>
+-#include <linux/param.h>
+-#include <linux/interrupt.h>
+-#include <linux/init.h>
+-#include <linux/irq.h>
+-#include <linux/pci.h>
+-#include <linux/dma-mapping.h>
+-#include <linux/device.h>
+-
+-#include <asm/io.h>
+-#include <asm/irq.h>
+-#include <asm/mach/pci.h>
+-
+-static int gapspci_dma_used = 0;
+-
+-void *dreamcast_consistent_alloc(struct device *dev, size_t size,
+-				 dma_addr_t *dma_handle, gfp_t flag)
+-{
+-	unsigned long buf;
+-
+-	if (dev && dev->bus != &pci_bus_type)
+-		return NULL;
+-
+-	if (gapspci_dma_used + size > GAPSPCI_DMA_SIZE)
+-		return ERR_PTR(-EINVAL);
+-
+-	buf = GAPSPCI_DMA_BASE + gapspci_dma_used;
+-
+-	gapspci_dma_used = PAGE_ALIGN(gapspci_dma_used+size);
+-
+-	*dma_handle = (dma_addr_t)buf;
+-
+-	buf = P2SEGADDR(buf);
+-
+-	/* Flush the dcache before we hand off the buffer */
+-	__flush_purge_region((void *)buf, size);
+-
+-	return (void *)buf;
+-}
+-
+-int dreamcast_consistent_free(struct device *dev, size_t size,
+-			 void *vaddr, dma_addr_t dma_handle)
+-{
+-	if (dev && dev->bus != &pci_bus_type)
+-		return -EINVAL;
+-
+-	/* XXX */
+-	gapspci_dma_used = 0;
+-
+-	return 0;
+-}
+-
+diff --git a/arch/sh/drivers/pci/fixups-dreamcast.c b/arch/sh/drivers/pci/fixups-dreamcast.c
+index 6f53f82..c446993 100644
+--- a/arch/sh/drivers/pci/fixups-dreamcast.c
++++ b/arch/sh/drivers/pci/fixups-dreamcast.c
+@@ -22,6 +22,7 @@
+ #include <linux/init.h>
+ #include <linux/irq.h>
+ #include <linux/pci.h>
++#include <linux/dma-mapping.h>
+ 
+ #include <asm/io.h>
+ #include <asm/irq.h>
+@@ -40,6 +41,15 @@ static void __init gapspci_fixup_resources(struct pci_dev *dev)
+ 		 */
+ 		dev->resource[1].start	= p->io_resource->start  + 0x100;
+ 		dev->resource[1].end	= dev->resource[1].start + 0x200 - 1;
++		/*
++		 * Redirect dma memory allocations to special memory window.
++		 */
++		BUG_ON(!dma_declare_coherent_memory(&dev->dev,
++						GAPSPCI_DMA_BASE,
++						GAPSPCI_DMA_BASE,
++						GAPSPCI_DMA_SIZE,
++						DMA_MEMORY_MAP |
++						DMA_MEMORY_EXCLUSIVE));
+ 		break;
+ 	default:
+ 		printk("PCI: Failed resource fixup\n");
+diff --git a/arch/sh/drivers/pci/fixups-sdk7780.c b/arch/sh/drivers/pci/fixups-sdk7780.c
+new file mode 100644
+index 0000000..2f88630
+--- /dev/null
++++ b/arch/sh/drivers/pci/fixups-sdk7780.c
+@@ -0,0 +1,59 @@
++/*
++ * arch/sh/drivers/pci/fixups-sdk7780.c
++ *
++ * PCI fixups for the SDK7780SE03
++ *
++ * Copyright (C) 2003  Lineo uSolutions, Inc.
++ * Copyright (C) 2004 - 2006  Paul Mundt
++ *
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License.  See the file "COPYING" in the main directory of this archive
++ * for more details.
++ */
++#include <linux/pci.h>
++#include "pci-sh4.h"
++#include <asm/io.h>
++
++int pci_fixup_pcic(void)
++{
++	ctrl_outl(0x00000001, SH7780_PCI_VCR2);
++
++	/* Enable all interrupts, so we know what to fix */
++	pci_write_reg(0x0000C3FF, SH7780_PCIIMR);
++	pci_write_reg(0x0000380F, SH7780_PCIAINTM);
++
++	/* Set up standard PCI config registers */
++	pci_write_reg(0xFB00, SH7780_PCISTATUS);
++	pci_write_reg(0x0047, SH7780_PCICMD);
++	pci_write_reg(0x00, SH7780_PCIPIF);
++	pci_write_reg(0x00, SH7780_PCISUB);
++	pci_write_reg(0x06, SH7780_PCIBCC);
++	pci_write_reg(0x1912, SH7780_PCISVID);
++	pci_write_reg(0x0001, SH7780_PCISID);
++
++	pci_write_reg(0x08000000, SH7780_PCIMBAR0);	/* PCI */
++	pci_write_reg(0x08000000, SH7780_PCILAR0);	/* SHwy */
++	pci_write_reg(0x07F00001, SH7780_PCILSR);	/* size 128M w/ MBAR */
++
++	pci_write_reg(0x00000000, SH7780_PCIMBAR1);
++	pci_write_reg(0x00000000, SH7780_PCILAR1);
++	pci_write_reg(0x00000000, SH7780_PCILSR1);
++
++	pci_write_reg(0xAB000801, SH7780_PCIIBAR);
++
++	/*
++	 * Set the MBR so PCI address is one-to-one with window,
++	 * meaning all calls go straight through... use ifdef to
++	 * catch erroneous assumption.
++	 */
++	pci_write_reg(0xFD000000 , SH7780_PCIMBR0);
++	pci_write_reg(0x00FC0000 , SH7780_PCIMBMR0);	/* 16M */
++
++	/* Set IOBR for window containing area specified in pci.h */
++	pci_write_reg(PCIBIOS_MIN_IO & ~(SH7780_PCI_IO_SIZE-1), SH7780_PCIIOBR);
++	pci_write_reg((SH7780_PCI_IO_SIZE-1) & (7 << 18), SH7780_PCIIOBMR);
++
++	pci_write_reg(0xA5000C01, SH7780_PCICR);
++
++	return 0;
++}
+diff --git a/arch/sh/drivers/pci/ops-cayman.c b/arch/sh/drivers/pci/ops-cayman.c
+new file mode 100644
+index 0000000..980275f
+--- /dev/null
++++ b/arch/sh/drivers/pci/ops-cayman.c
+@@ -0,0 +1,94 @@
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/pci.h>
++#include <linux/types.h>
++#include <asm/cpu/irq.h>
++#include "pci-sh5.h"
++
++static inline u8 bridge_swizzle(u8 pin, u8 slot)
++{
++	return (((pin - 1) + slot) % 4) + 1;
++}
++
++int __init pcibios_map_platform_irq(struct pci_dev *dev, u8 slot, u8 pin)
++{
++	int result = -1;
++
++	/* The complication here is that the PCI IRQ lines from the Cayman's 2
++	   5V slots get into the CPU via a different path from the IRQ lines
++	   from the 3 3.3V slots.  Thus, we have to detect whether the card's
++	   interrupts go via the 5V or 3.3V path, i.e. the 'bridge swizzling'
++	   at the point where we cross from 5V to 3.3V is not the normal case.
++
++	   The added complication is that we don't know that the 5V slots are
++	   always bus 2, because a card containing a PCI-PCI bridge may be
++	   plugged into a 3.3V slot, and this changes the bus numbering.
++
++	   Also, the Cayman has an intermediate PCI bus that goes a custom
++	   expansion board header (and to the secondary bridge).  This bus has
++	   never been used in practice.
++
++	   The 1ary onboard PCI-PCI bridge is device 3 on bus 0
++	   The 2ary onboard PCI-PCI bridge is device 0 on the 2ary bus of
++	   the 1ary bridge.
++	   */
++
++	struct slot_pin {
++		int slot;
++		int pin;
++	} path[4];
++	int i=0;
++
++	while (dev->bus->number > 0) {
++
++		slot = path[i].slot = PCI_SLOT(dev->devfn);
++		pin = path[i].pin = bridge_swizzle(pin, slot);
++		dev = dev->bus->self;
++		i++;
++		if (i > 3) panic("PCI path to root bus too long!\n");
++	}
++
++	slot = PCI_SLOT(dev->devfn);
++	/* This is the slot on bus 0 through which the device is eventually
++	   reachable. */
++
++	/* Now work back up. */
++	if ((slot < 3) || (i == 0)) {
++		/* Bus 0 (incl. PCI-PCI bridge itself) : perform the final
++		   swizzle now. */
++		result = IRQ_INTA + bridge_swizzle(pin, slot) - 1;
++	} else {
++		i--;
++		slot = path[i].slot;
++		pin  = path[i].pin;
++		if (slot > 0) {
++			panic("PCI expansion bus device found - not handled!\n");
++		} else {
++			if (i > 0) {
++				/* 5V slots */
++				i--;
++				slot = path[i].slot;
++				pin  = path[i].pin;
++				/* 'pin' was swizzled earlier wrt slot, don't do it again. */
++				result = IRQ_P2INTA + (pin - 1);
++			} else {
++				/* IRQ for 2ary PCI-PCI bridge : unused */
++				result = -1;
++			}
++		}
++	}
++
++	return result;
++}
++
++struct pci_channel board_pci_channels[] = {
++	{ &sh5_pci_ops, NULL, NULL, 0, 0xff },
++	{ NULL, NULL, NULL, 0, 0 },
++};
++EXPORT_SYMBOL(board_pci_channels);
++
++int __init pcibios_init_platform(void)
++{
++	return sh5pci_init(__pa(memory_start),
++			   __pa(memory_end) - __pa(memory_start));
++}
+diff --git a/arch/sh/drivers/pci/ops-r7780rp.c b/arch/sh/drivers/pci/ops-r7780rp.c
+index 48fe403..5fdadae 100644
+--- a/arch/sh/drivers/pci/ops-r7780rp.c
++++ b/arch/sh/drivers/pci/ops-r7780rp.c
+@@ -17,25 +17,13 @@
+ #include <asm/io.h>
+ #include "pci-sh4.h"
+ 
+-static char r7780rp_irq_tab[] __initdata = {
+-	0, 1, 2, 3,
+-};
+-
+-static char r7780mp_irq_tab[] __initdata = {
++static char irq_tab[] __initdata = {
+ 	65, 66, 67, 68,
+ };
+ 
+ int __init pcibios_map_platform_irq(struct pci_dev *pdev, u8 slot, u8 pin)
+ {
+-	if (mach_is_r7780rp())
+-		return r7780rp_irq_tab[slot];
+-	if (mach_is_r7780mp() || mach_is_r7785rp())
+-		return r7780mp_irq_tab[slot];
+-
+-	printk(KERN_ERR "PCI: Bad IRQ mapping "
+-	       "request for slot %d, func %d\n", slot, pin-1);
+-
+-	return -1;
++	return irq_tab[slot];
+ }
+ 
+ static struct resource sh7780_io_resource = {
+diff --git a/arch/sh/drivers/pci/ops-sdk7780.c b/arch/sh/drivers/pci/ops-sdk7780.c
+new file mode 100644
+index 0000000..66a9b40
+--- /dev/null
++++ b/arch/sh/drivers/pci/ops-sdk7780.c
+@@ -0,0 +1,73 @@
++/*
++ * linux/arch/sh/drivers/pci/ops-sdk7780.c
++ *
++ * Copyright (C) 2006  Nobuhiro Iwamatsu
++ *
++ * PCI initialization for the SDK7780SE03
++ *
++ * May be copied or modified under the terms of the GNU General Public
++ * License.  See linux/COPYING for more information.
++ */
++#include <linux/kernel.h>
++#include <linux/types.h>
++#include <linux/init.h>
++#include <linux/delay.h>
++#include <linux/pci.h>
++#include <asm/sdk7780.h>
++#include <asm/io.h>
++#include "pci-sh4.h"
++
++/* IDSEL [16][17][18][19][20][21][22][23][24][25][26][27][28][29][30][31] */
++static char sdk7780_irq_tab[4][16] __initdata = {
++	/* INTA */
++	{ 65, 68, 67, 68, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
++	/* INTB */
++	{ 66, 65, -1, 65, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
++	/* INTC */
++	{ 67, 66, -1, 66, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
++	/* INTD */
++	{ 68, 67, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
++};
++
++int __init pcibios_map_platform_irq(struct pci_dev *pdev, u8 slot, u8 pin)
++{
++       return sdk7780_irq_tab[pin-1][slot];
++}
++
++static struct resource sdk7780_io_resource = {
++	.name	= "SH7780_IO",
++	.start	= SH7780_PCI_IO_BASE,
++	.end	= SH7780_PCI_IO_BASE + SH7780_PCI_IO_SIZE - 1,
++	.flags	= IORESOURCE_IO
++};
++
++static struct resource sdk7780_mem_resource = {
++	.name	= "SH7780_mem",
++	.start	= SH7780_PCI_MEMORY_BASE,
++	.end	= SH7780_PCI_MEMORY_BASE + SH7780_PCI_MEM_SIZE - 1,
++	.flags	= IORESOURCE_MEM
++};
++
++struct pci_channel board_pci_channels[] = {
++	{ &sh4_pci_ops, &sdk7780_io_resource, &sdk7780_mem_resource, 0, 0xff },
++	{ NULL, NULL, NULL, 0, 0 },
++};
++EXPORT_SYMBOL(board_pci_channels);
++
++static struct sh4_pci_address_map sdk7780_pci_map = {
++	.window0	= {
++		.base	= SH7780_CS2_BASE_ADDR,
++		.size	= 0x04000000,
++	},
++	.window1	= {
++		.base	= SH7780_CS3_BASE_ADDR,
++		.size	= 0x04000000,
++	},
++	.flags	= SH4_PCIC_NO_RESET,
++};
++
++int __init pcibios_init_platform(void)
++{
++	printk(KERN_INFO "SH7780 PCI: Finished initializing PCI controller\n");
++	return sh7780_pcic_init(&sdk7780_pci_map);
++}
+diff --git a/arch/sh/drivers/pci/ops-sh5.c b/arch/sh/drivers/pci/ops-sh5.c
+new file mode 100644
+index 0000000..729e38a
+--- /dev/null
++++ b/arch/sh/drivers/pci/ops-sh5.c
+@@ -0,0 +1,93 @@
++/*
++ * Support functions for the SH5 PCI hardware.
++ *
++ * Copyright (C) 2001 David J. Mckay (david.mckay at st.com)
++ * Copyright (C) 2003, 2004 Paul Mundt
++ * Copyright (C) 2004 Richard Curnow
++ *
++ * May be copied or modified under the terms of the GNU General Public
++ * License.  See linux/COPYING for more information.
++ */
++#include <linux/kernel.h>
++#include <linux/rwsem.h>
++#include <linux/smp.h>
++#include <linux/interrupt.h>
++#include <linux/init.h>
++#include <linux/errno.h>
++#include <linux/pci.h>
++#include <linux/delay.h>
++#include <linux/types.h>
++#include <linux/irq.h>
++#include <asm/pci.h>
++#include <asm/io.h>
++#include "pci-sh5.h"
++
++static void __init pci_fixup_ide_bases(struct pci_dev *d)
++{
++	int i;
++
++	/*
++	 * PCI IDE controllers use non-standard I/O port decoding, respect it.
++	 */
++	if ((d->class >> 8) != PCI_CLASS_STORAGE_IDE)
++		return;
++	printk("PCI: IDE base address fixup for %s\n", pci_name(d));
++	for(i=0; i<4; i++) {
++		struct resource *r = &d->resource[i];
++		if ((r->start & ~0x80) == 0x374) {
++			r->start |= 2;
++			r->end = r->start;
++		}
++	}
++}
++DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pci_fixup_ide_bases);
++
++char * __devinit pcibios_setup(char *str)
++{
++	return str;
++}
++
++static int sh5pci_read(struct pci_bus *bus, unsigned int devfn, int where,
++			int size, u32 *val)
++{
++	SH5PCI_WRITE(PAR, CONFIG_CMD(bus, devfn, where));
++
++	switch (size) {
++		case 1:
++			*val = (u8)SH5PCI_READ_BYTE(PDR + (where & 3));
++			break;
++		case 2:
++			*val = (u16)SH5PCI_READ_SHORT(PDR + (where & 2));
++			break;
++		case 4:
++			*val = SH5PCI_READ(PDR);
++			break;
++	}
++
++	return PCIBIOS_SUCCESSFUL;
++}
++
++static int sh5pci_write(struct pci_bus *bus, unsigned int devfn, int where,
++			 int size, u32 val)
++{
++	SH5PCI_WRITE(PAR, CONFIG_CMD(bus, devfn, where));
++
++	switch (size) {
++		case 1:
++			SH5PCI_WRITE_BYTE(PDR + (where & 3), (u8)val);
++			break;
++		case 2:
++			SH5PCI_WRITE_SHORT(PDR + (where & 2), (u16)val);
++			break;
++		case 4:
++			SH5PCI_WRITE(PDR, val);
++			break;
++	}
++
++	return PCIBIOS_SUCCESSFUL;
++}
++
++struct pci_ops sh5_pci_ops = {
++	.read		= sh5pci_read,
++	.write		= sh5pci_write,
++};
+diff --git a/arch/sh/drivers/pci/pci-auto.c b/arch/sh/drivers/pci/pci-auto.c
+index 224e007..ea40470 100644
+--- a/arch/sh/drivers/pci/pci-auto.c
++++ b/arch/sh/drivers/pci/pci-auto.c
+@@ -516,10 +516,8 @@ pciauto_bus_scan(struct pci_channel *hose, int top_bus, int current_bus)
+ 					 PCI_COMMAND, cmdstat | PCI_COMMAND_IO |
+ 					 PCI_COMMAND_MEMORY |
+ 					 PCI_COMMAND_MASTER);
+-#if !defined(CONFIG_SH_HS7751RVOIP) && !defined(CONFIG_SH_RTS7751R2D)
+ 		early_write_config_byte(hose, top_bus, current_bus, pci_devfn,
+ 					PCI_LATENCY_TIMER, 0x80);
+-#endif
+ 
+ 		/* Allocate PCI I/O and/or memory space */
+ 		pciauto_setup_bars(hose, top_bus, current_bus, pci_devfn, PCI_BASE_ADDRESS_5);
+diff --git a/arch/sh/drivers/pci/pci-sh4.h b/arch/sh/drivers/pci/pci-sh4.h
+index 1901c33..4925c79 100644
+--- a/arch/sh/drivers/pci/pci-sh4.h
++++ b/arch/sh/drivers/pci/pci-sh4.h
+@@ -1,7 +1,9 @@
+ #ifndef __PCI_SH4_H
+ #define __PCI_SH4_H
+ 
+-#if defined(CONFIG_CPU_SUBTYPE_SH7780) || defined(CONFIG_CPU_SUBTYPE_SH7785)
++#if defined(CONFIG_CPU_SUBTYPE_SH7780) || \
++    defined(CONFIG_CPU_SUBTYPE_SH7785) || \
++    defined(CONFIG_CPU_SUBTYPE_SH7763)
+ #include "pci-sh7780.h"
+ #else
+ #include "pci-sh7751.h"
+diff --git a/arch/sh/drivers/pci/pci-sh5.c b/arch/sh/drivers/pci/pci-sh5.c
+new file mode 100644
+index 0000000..a00a4df
+--- /dev/null
++++ b/arch/sh/drivers/pci/pci-sh5.c
+@@ -0,0 +1,228 @@
++/*
++ * Copyright (C) 2001 David J. Mckay (david.mckay at st.com)
++ * Copyright (C) 2003, 2004 Paul Mundt
++ * Copyright (C) 2004 Richard Curnow
++ *
++ * May be copied or modified under the terms of the GNU General Public
++ * License.  See linux/COPYING for more information.
++ *
++ * Support functions for the SH5 PCI hardware.
++ */
++
++#include <linux/kernel.h>
++#include <linux/rwsem.h>
++#include <linux/smp.h>
++#include <linux/interrupt.h>
++#include <linux/init.h>
++#include <linux/errno.h>
++#include <linux/pci.h>
++#include <linux/delay.h>
++#include <linux/types.h>
++#include <linux/irq.h>
++#include <asm/cpu/irq.h>
++#include <asm/pci.h>
++#include <asm/io.h>
++#include "pci-sh5.h"
++
++unsigned long pcicr_virt;
++unsigned long PCI_IO_AREA;
++
++/* Rounds a number UP to the nearest power of two. Used for
++ * sizing the PCI window.
++ */
++static u32 __init r2p2(u32 num)
++{
++	int i = 31;
++	u32 tmp = num;
++
++	if (num == 0)
++		return 0;
++
++	do {
++		if (tmp & (1 << 31))
++			break;
++		i--;
++		tmp <<= 1;
++	} while (i >= 0);
++
++	tmp = 1 << i;
++	/* If the original number isn't a power of 2, round it up */
++	if (tmp != num)
++		tmp <<= 1;
++
++	return tmp;
++}
++
++static irqreturn_t pcish5_err_irq(int irq, void *dev_id)
++{
++	struct pt_regs *regs = get_irq_regs();
++	unsigned pci_int, pci_air, pci_cir, pci_aint;
++
++	pci_int = SH5PCI_READ(INT);
++	pci_cir = SH5PCI_READ(CIR);
++	pci_air = SH5PCI_READ(AIR);
++
++	if (pci_int) {
++		printk("PCI INTERRUPT (at %08llx)!\n", regs->pc);
++		printk("PCI INT -> 0x%x\n", pci_int & 0xffff);
++		printk("PCI AIR -> 0x%x\n", pci_air);
++		printk("PCI CIR -> 0x%x\n", pci_cir);
++		SH5PCI_WRITE(INT, ~0);
++	}
++
++	pci_aint = SH5PCI_READ(AINT);
++	if (pci_aint) {
++		printk("PCI ARB INTERRUPT!\n");
++		printk("PCI AINT -> 0x%x\n", pci_aint);
++		printk("PCI AIR -> 0x%x\n", pci_air);
++		printk("PCI CIR -> 0x%x\n", pci_cir);
++		SH5PCI_WRITE(AINT, ~0);
++	}
++
++	return IRQ_HANDLED;
++}
++
++static irqreturn_t pcish5_serr_irq(int irq, void *dev_id)
++{
++	printk("SERR IRQ\n");
++
++	return IRQ_NONE;
++}
++
++int __init sh5pci_init(unsigned long memStart, unsigned long memSize)
++{
++	u32 lsr0;
++	u32 uval;
++
++        if (request_irq(IRQ_ERR, pcish5_err_irq,
++                        IRQF_DISABLED, "PCI Error",NULL) < 0) {
++                printk(KERN_ERR "PCISH5: Cannot hook PCI_PERR interrupt\n");
++                return -EINVAL;
++        }
++
++        if (request_irq(IRQ_SERR, pcish5_serr_irq,
++                        IRQF_DISABLED, "PCI SERR interrupt", NULL) < 0) {
++                printk(KERN_ERR "PCISH5: Cannot hook PCI_SERR interrupt\n");
++                return -EINVAL;
++        }
++
++	pcicr_virt = onchip_remap(SH5PCI_ICR_BASE, 1024, "PCICR");
++	if (!pcicr_virt) {
++		panic("Unable to remap PCICR\n");
++	}
++
++	PCI_IO_AREA = onchip_remap(SH5PCI_IO_BASE, 0x10000, "PCIIO");
++	if (!PCI_IO_AREA) {
++		panic("Unable to remap PCIIO\n");
++	}
++
++	/* Clear snoop registers */
++        SH5PCI_WRITE(CSCR0, 0);
++        SH5PCI_WRITE(CSCR1, 0);
++
++        /* Switch off interrupts */
++        SH5PCI_WRITE(INTM,  0);
++        SH5PCI_WRITE(AINTM, 0);
++        SH5PCI_WRITE(PINTM, 0);
++
++        /* Set bus active, take it out of reset */
++        uval = SH5PCI_READ(CR);
++
++	/* Set command Register */
++        SH5PCI_WRITE(CR, uval | CR_LOCK_MASK | CR_CFINT| CR_FTO | CR_PFE |
++		     CR_PFCS | CR_BMAM);
++
++	uval=SH5PCI_READ(CR);
++
++        /* Allow it to be a master */
++	/* NB - WE DISABLE I/O ACCESS to stop overlap */
++        /* set WAIT bit to enable stepping, an attempt to improve stability */
++	SH5PCI_WRITE_SHORT(CSR_CMD,
++			    PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER |
++			    PCI_COMMAND_WAIT);
++
++        /*
++        ** Set translation mapping memory in order to convert the address
++        ** used for the main bus, to the PCI internal address.
++        */
++        SH5PCI_WRITE(MBR,0x40000000);
++
++        /* Always set the max size 512M */
++        SH5PCI_WRITE(MBMR, PCISH5_MEM_SIZCONV(512*1024*1024));
++
++        /*
++        ** I/O addresses are mapped at internal PCI specific address
++        ** as is described into the configuration bridge table.
++        ** These are changed to 0, to allow cards that have legacy
++        ** io such as vga to function correctly. We set the SH5 IOBAR to
++        ** 256K, which is a bit big as we can only have 64K of address space
++        */
++
++        SH5PCI_WRITE(IOBR,0x0);
++
++        /* Set up a 256K window. Totally pointless waste  of address space */
++        SH5PCI_WRITE(IOBMR,0);
++
++	/* The SH5 has a HUGE 256K I/O region, which breaks the PCI spec.
++	 * Ideally, we would want to map the I/O region somewhere, but it
++	 * is so big this is not that easy!
++         */
++	SH5PCI_WRITE(CSR_IBAR0,~0);
++	/* Set memory size value */
++        memSize = memory_end - memory_start;
++
++	/* Now we set up the mbars so the PCI bus can see the memory of
++	 * the machine */
++	if (memSize < (1024 * 1024)) {
++                printk(KERN_ERR "PCISH5: Ridiculous memory size of 0x%lx?\n",
++		       memSize);
++                return -EINVAL;
++        }
++
++        /* Set LSR 0 */
++        lsr0 = (memSize > (512 * 1024 * 1024)) ? 0x1ff00001 :
++		((r2p2(memSize) - 0x100000) | 0x1);
++        SH5PCI_WRITE(LSR0, lsr0);
++
++        /* Set MBAR 0 */
++        SH5PCI_WRITE(CSR_MBAR0, memory_start);
++        SH5PCI_WRITE(LAR0, memory_start);
++
++        SH5PCI_WRITE(CSR_MBAR1,0);
++        SH5PCI_WRITE(LAR1,0);
++        SH5PCI_WRITE(LSR1,0);
++
++        /* Enable the PCI interrupts on the device */
++        SH5PCI_WRITE(INTM,  ~0);
++        SH5PCI_WRITE(AINTM, ~0);
++        SH5PCI_WRITE(PINTM, ~0);
++
++	return 0;
++}
++
++void __devinit pcibios_fixup_bus(struct pci_bus *bus)
++{
++	struct pci_dev *dev = bus->self;
++	int i;
++
++	if (dev) {
++		for (i= 0; i < 3; i++) {
++			bus->resource[i] =
++				&dev->resource[PCI_BRIDGE_RESOURCES+i];
++			bus->resource[i]->name = bus->name;
++		}
++		bus->resource[0]->flags |= IORESOURCE_IO;
++		bus->resource[1]->flags |= IORESOURCE_MEM;
++
++		/* For now, propagate host limits to the bus;
++		 * we'll adjust them later. */
++		bus->resource[0]->end = 64*1024 - 1 ;
++		bus->resource[1]->end = PCIBIOS_MIN_MEM+(256*1024*1024)-1;
++		bus->resource[0]->start = PCIBIOS_MIN_IO;
++		bus->resource[1]->start = PCIBIOS_MIN_MEM;
++
++		/* Turn off downstream PF memory address range by default */
++		bus->resource[2]->start = 1024*1024;
++		bus->resource[2]->end = bus->resource[2]->start - 1;
++	}
++}
+diff --git a/arch/sh/drivers/pci/pci-sh5.h b/arch/sh/drivers/pci/pci-sh5.h
+new file mode 100644
+index 0000000..7cff3fc
+--- /dev/null
++++ b/arch/sh/drivers/pci/pci-sh5.h
+@@ -0,0 +1,113 @@
++/*
++ * Copyright (C) 2001 David J. Mckay (david.mckay at st.com)
++ *
++ * May be copied or modified under the terms of the GNU General Public
++ * License.  See linux/COPYING for more information.
++ *
++ * Definitions for the SH5 PCI hardware.
++ */
++#ifndef __PCI_SH5_H
++#define __PCI_SH5_H
++
++/* Product ID */
++#define PCISH5_PID		0x350d
++
++/* vendor ID */
++#define PCISH5_VID		0x1054
++
++/* Configuration types */
++#define ST_TYPE0                0x00    /* Configuration cycle type 0 */
++#define ST_TYPE1                0x01    /* Configuration cycle type 1 */
++
++/* VCR data */
++#define PCISH5_VCR_STATUS      0x00
++#define PCISH5_VCR_VERSION     0x08
++
++/*
++** ICR register offsets and bits
++*/
++#define PCISH5_ICR_CR          0x100   /* PCI control register values */
++#define CR_PBAM                 (1<<12)
++#define CR_PFCS                 (1<<11)
++#define CR_FTO                  (1<<10)
++#define CR_PFE                  (1<<9)
++#define CR_TBS                  (1<<8)
++#define CR_SPUE                 (1<<7)
++#define CR_BMAM                 (1<<6)
++#define CR_HOST                 (1<<5)
++#define CR_CLKEN                (1<<4)
++#define CR_SOCS                 (1<<3)
++#define CR_IOCS                 (1<<2)
++#define CR_RSTCTL               (1<<1)
++#define CR_CFINT                (1<<0)
++#define CR_LOCK_MASK            0xa5000000
++
++#define PCISH5_ICR_INT         0x114   /* Interrupt registert values     */
++#define INT_MADIM               (1<<2)
++
++#define PCISH5_ICR_LSR0        0X104   /* Local space register values    */
++#define PCISH5_ICR_LSR1        0X108   /* Local space register values    */
++#define PCISH5_ICR_LAR0        0x10c   /* Local address register values  */
++#define PCISH5_ICR_LAR1        0x110   /* Local address register values  */
++#define PCISH5_ICR_INTM        0x118   /* Interrupt mask register values                         */
++#define PCISH5_ICR_AIR         0x11c   /* Interrupt error address information register values    */
++#define PCISH5_ICR_CIR         0x120   /* Interrupt error command information register values    */
++#define PCISH5_ICR_AINT        0x130   /* Interrupt error arbiter interrupt register values      */
++#define PCISH5_ICR_AINTM       0x134   /* Interrupt error arbiter interrupt mask register values */
++#define PCISH5_ICR_BMIR        0x138   /* Interrupt error info register of bus master values     */
++#define PCISH5_ICR_PAR         0x1c0   /* Pio address register values                            */
++#define PCISH5_ICR_MBR         0x1c4   /* Memory space bank register values                      */
++#define PCISH5_ICR_IOBR        0x1c8   /* I/O space bank register values                         */
++#define PCISH5_ICR_PINT        0x1cc   /* power management interrupt register values             */
++#define PCISH5_ICR_PINTM       0x1d0   /* power management interrupt mask register values        */
++#define PCISH5_ICR_MBMR        0x1d8   /* memory space bank mask register values                 */
++#define PCISH5_ICR_IOBMR       0x1dc   /* I/O space bank mask register values                    */
++#define PCISH5_ICR_CSCR0       0x210   /* PCI cache snoop control register 0                     */
++#define PCISH5_ICR_CSCR1       0x214   /* PCI cache snoop control register 1                     */
++#define PCISH5_ICR_PDR         0x220   /* Pio data register values                               */
++
++/* These are configs space registers */
++#define PCISH5_ICR_CSR_VID     0x000	/* Vendor id                           */
++#define PCISH5_ICR_CSR_DID     0x002   /* Device id                           */
++#define PCISH5_ICR_CSR_CMD     0x004   /* Command register                    */
++#define PCISH5_ICR_CSR_STATUS  0x006   /* Stautus                             */
++#define PCISH5_ICR_CSR_IBAR0   0x010   /* I/O base address register           */
++#define PCISH5_ICR_CSR_MBAR0   0x014   /* First  Memory base address register */
++#define PCISH5_ICR_CSR_MBAR1   0x018   /* Second Memory base address register */
++
++/* Base address of registers */
++#define SH5PCI_ICR_BASE (PHYS_PCI_BLOCK + 0x00040000)
++#define SH5PCI_IO_BASE  (PHYS_PCI_BLOCK + 0x00800000)
++/* #define SH5PCI_VCR_BASE (P2SEG_PCICB_BLOCK + P2SEG)    */
++
++extern unsigned long pcicr_virt;
++/* Register selection macro */
++#define PCISH5_ICR_REG(x)                ( pcicr_virt + (PCISH5_ICR_##x))
++/* #define PCISH5_VCR_REG(x)                ( SH5PCI_VCR_BASE (PCISH5_VCR_##x)) */
++
++/* Write I/O functions */
++#define SH5PCI_WRITE(reg,val)        ctrl_outl((u32)(val),PCISH5_ICR_REG(reg))
++#define SH5PCI_WRITE_SHORT(reg,val)  ctrl_outw((u16)(val),PCISH5_ICR_REG(reg))
++#define SH5PCI_WRITE_BYTE(reg,val)   ctrl_outb((u8)(val),PCISH5_ICR_REG(reg))
++
++/* Read I/O functions */
++#define SH5PCI_READ(reg)             ctrl_inl(PCISH5_ICR_REG(reg))
++#define SH5PCI_READ_SHORT(reg)       ctrl_inw(PCISH5_ICR_REG(reg))
++#define SH5PCI_READ_BYTE(reg)        ctrl_inb(PCISH5_ICR_REG(reg))
++
++/* Set PCI config bits */
++#define SET_CONFIG_BITS(bus,devfn,where)  ((((bus) << 16) | ((devfn) << 8) | ((where) & ~3)) | 0x80000000)
++
++/* Set PCI command register */
++#define CONFIG_CMD(bus, devfn, where)            SET_CONFIG_BITS(bus->number,devfn,where)
++
++/* Size converters */
++#define PCISH5_MEM_SIZCONV(x)		  (((x / 0x40000) - 1) << 18)
++#define PCISH5_IO_SIZCONV(x)		  (((x / 0x40000) - 1) << 18)
++
++extern struct pci_ops sh5_pci_ops;
++
++/* arch/sh/drivers/pci/pci-sh5.c */
++int sh5pci_init(unsigned long memStart, unsigned long memSize);
++
++#endif /* __PCI_SH5_H */
+diff --git a/arch/sh/drivers/pci/pci-sh7780.c b/arch/sh/drivers/pci/pci-sh7780.c
+index e516087..7d797f4 100644
+--- a/arch/sh/drivers/pci/pci-sh7780.c
++++ b/arch/sh/drivers/pci/pci-sh7780.c
+@@ -58,6 +58,7 @@ static int __init sh7780_pci_init(void)
+ 	id = pci_read_reg(SH7780_PCIVID);
+ 	if ((id & 0xffff) == SH7780_VENDOR_ID) {
+ 		switch ((id >> 16) & 0xffff) {
++		case SH7763_DEVICE_ID:
+ 		case SH7780_DEVICE_ID:
+ 		case SH7781_DEVICE_ID:
+ 		case SH7785_DEVICE_ID:
+diff --git a/arch/sh/drivers/pci/pci-sh7780.h b/arch/sh/drivers/pci/pci-sh7780.h
+index 1d069a8..97b2c98 100644
+--- a/arch/sh/drivers/pci/pci-sh7780.h
++++ b/arch/sh/drivers/pci/pci-sh7780.h
+@@ -16,6 +16,7 @@
+ #define SH7780_VENDOR_ID	0x1912
+ #define SH7781_DEVICE_ID	0x0001
+ #define SH7780_DEVICE_ID	0x0002
++#define SH7763_DEVICE_ID	0x0004
+ #define SH7785_DEVICE_ID	0x0007
+ 
+ /* SH7780 Control Registers */
+diff --git a/arch/sh/drivers/pci/pci.c b/arch/sh/drivers/pci/pci.c
+index ccaba36..49b435c 100644
+--- a/arch/sh/drivers/pci/pci.c
++++ b/arch/sh/drivers/pci/pci.c
+@@ -71,7 +71,7 @@ subsys_initcall(pcibios_init);
+  *  Called after each bus is probed, but before its children
+  *  are examined.
+  */
+-void __devinit pcibios_fixup_bus(struct pci_bus *bus)
++void __devinit __weak pcibios_fixup_bus(struct pci_bus *bus)
+ {
+ 	pci_read_bridge_bases(bus);
+ }
+diff --git a/arch/sh/kernel/Makefile b/arch/sh/kernel/Makefile
+index 4b81d9c..349d833 100644
+--- a/arch/sh/kernel/Makefile
++++ b/arch/sh/kernel/Makefile
+@@ -1,25 +1,5 @@
+-#
+-# Makefile for the Linux/SuperH kernel.
+-#
+-
+-extra-y	:= head.o init_task.o vmlinux.lds
+-
+-obj-y	:= debugtraps.o io.o io_generic.o irq.o machvec.o process.o ptrace.o \
+-	   semaphore.o setup.o signal.o sys_sh.o syscalls.o \
+-	   time.o topology.o traps.o
+-
+-obj-y				+= cpu/ timers/
+-obj-$(CONFIG_VSYSCALL)		+= vsyscall/
+-obj-$(CONFIG_SMP)		+= smp.o
+-obj-$(CONFIG_CF_ENABLER)	+= cf-enabler.o
+-obj-$(CONFIG_SH_STANDARD_BIOS)	+= sh_bios.o
+-obj-$(CONFIG_SH_KGDB)		+= kgdb_stub.o kgdb_jmp.o
+-obj-$(CONFIG_SH_CPU_FREQ)	+= cpufreq.o
+-obj-$(CONFIG_MODULES)		+= sh_ksyms.o module.o
+-obj-$(CONFIG_EARLY_PRINTK)	+= early_printk.o
+-obj-$(CONFIG_KEXEC)		+= machine_kexec.o relocate_kernel.o
+-obj-$(CONFIG_CRASH_DUMP)	+= crash_dump.o
+-obj-$(CONFIG_PM)		+= pm.o
+-obj-$(CONFIG_STACKTRACE)	+= stacktrace.o
+-
+-EXTRA_CFLAGS += -Werror
++ifeq ($(CONFIG_SUPERH32),y)
++include ${srctree}/arch/sh/kernel/Makefile_32
++else
++include ${srctree}/arch/sh/kernel/Makefile_64
++endif
+diff --git a/arch/sh/kernel/Makefile_32 b/arch/sh/kernel/Makefile_32
+new file mode 100644
+index 0000000..c892898
+--- /dev/null
++++ b/arch/sh/kernel/Makefile_32
+@@ -0,0 +1,26 @@
++#
++# Makefile for the Linux/SuperH kernel.
++#
++
++extra-y	:= head_32.o init_task.o vmlinux.lds
++
++obj-y	:= debugtraps.o io.o io_generic.o irq.o machvec.o process_32.o \
++	   ptrace_32.o semaphore.o setup.o signal_32.o sys_sh.o sys_sh32.o \
++	   syscalls_32.o time_32.o topology.o traps.o traps_32.o
++
++obj-y				+= cpu/ timers/
++obj-$(CONFIG_VSYSCALL)		+= vsyscall/
++obj-$(CONFIG_SMP)		+= smp.o
++obj-$(CONFIG_CF_ENABLER)	+= cf-enabler.o
++obj-$(CONFIG_SH_STANDARD_BIOS)	+= sh_bios.o
++obj-$(CONFIG_SH_KGDB)		+= kgdb_stub.o kgdb_jmp.o
++obj-$(CONFIG_SH_CPU_FREQ)	+= cpufreq.o
++obj-$(CONFIG_MODULES)		+= sh_ksyms_32.o module.o
++obj-$(CONFIG_EARLY_PRINTK)	+= early_printk.o
++obj-$(CONFIG_KEXEC)		+= machine_kexec.o relocate_kernel.o
++obj-$(CONFIG_CRASH_DUMP)	+= crash_dump.o
++obj-$(CONFIG_PM)		+= pm.o
++obj-$(CONFIG_STACKTRACE)	+= stacktrace.o
++obj-$(CONFIG_BINFMT_ELF)	+= dump_task.o
++
++EXTRA_CFLAGS += -Werror
+diff --git a/arch/sh/kernel/Makefile_64 b/arch/sh/kernel/Makefile_64
+new file mode 100644
+index 0000000..1ef21cc
+--- /dev/null
++++ b/arch/sh/kernel/Makefile_64
+@@ -0,0 +1,22 @@
++extra-y	:= head_64.o init_task.o vmlinux.lds
++
++obj-y	:= debugtraps.o io.o io_generic.o irq.o machvec.o process_64.o \
++	   ptrace_64.o semaphore.o setup.o signal_64.o sys_sh.o sys_sh64.o \
++	   syscalls_64.o time_64.o topology.o traps.o traps_64.o
++
++obj-y				+= cpu/ timers/
++obj-$(CONFIG_VSYSCALL)		+= vsyscall/
++obj-$(CONFIG_SMP)		+= smp.o
++obj-$(CONFIG_CF_ENABLER)	+= cf-enabler.o
++obj-$(CONFIG_SH_STANDARD_BIOS)	+= sh_bios.o
++obj-$(CONFIG_SH_KGDB)		+= kgdb_stub.o kgdb_jmp.o
++obj-$(CONFIG_SH_CPU_FREQ)	+= cpufreq.o
++obj-$(CONFIG_MODULES)		+= sh_ksyms_64.o module.o
++obj-$(CONFIG_EARLY_PRINTK)	+= early_printk.o
++obj-$(CONFIG_KEXEC)		+= machine_kexec.o relocate_kernel.o
++obj-$(CONFIG_CRASH_DUMP)	+= crash_dump.o
++obj-$(CONFIG_PM)		+= pm.o
++obj-$(CONFIG_STACKTRACE)	+= stacktrace.o
++obj-$(CONFIG_BINFMT_ELF)	+= dump_task.o
++
++EXTRA_CFLAGS += -Werror
+diff --git a/arch/sh/kernel/cpu/Makefile b/arch/sh/kernel/cpu/Makefile
+index d055a3e..f471d24 100644
+--- a/arch/sh/kernel/cpu/Makefile
++++ b/arch/sh/kernel/cpu/Makefile
+@@ -6,8 +6,14 @@ obj-$(CONFIG_CPU_SH2)		= sh2/
+ obj-$(CONFIG_CPU_SH2A)		= sh2a/
+ obj-$(CONFIG_CPU_SH3)		= sh3/
+ obj-$(CONFIG_CPU_SH4)		= sh4/
++obj-$(CONFIG_CPU_SH5)		= sh5/
++
++# Special cases for family ancestry.
++
+ obj-$(CONFIG_CPU_SH4A)		+= sh4a/
+ 
++# Common interfaces.
++
+ obj-$(CONFIG_UBC_WAKEUP)	+= ubc.o
+ obj-$(CONFIG_SH_ADC)		+= adc.o
+ 
+diff --git a/arch/sh/kernel/cpu/init.c b/arch/sh/kernel/cpu/init.c
+index c217c4b..80a3132 100644
+--- a/arch/sh/kernel/cpu/init.c
++++ b/arch/sh/kernel/cpu/init.c
+@@ -13,6 +13,7 @@
+ #include <linux/init.h>
+ #include <linux/kernel.h>
+ #include <linux/mm.h>
++#include <linux/log2.h>
+ #include <asm/mmu_context.h>
+ #include <asm/processor.h>
+ #include <asm/uaccess.h>
+@@ -20,9 +21,12 @@
+ #include <asm/system.h>
+ #include <asm/cacheflush.h>
+ #include <asm/cache.h>
++#include <asm/elf.h>
+ #include <asm/io.h>
+-#include <asm/ubc.h>
+ #include <asm/smp.h>
++#ifdef CONFIG_SUPERH32
++#include <asm/ubc.h>
++#endif
+ 
+ /*
+  * Generic wrapper for command line arguments to disable on-chip
+@@ -61,25 +65,12 @@ static void __init speculative_execution_init(void)
+ /*
+  * Generic first-level cache init
+  */
+-static void __init cache_init(void)
++#ifdef CONFIG_SUPERH32
++static void __uses_jump_to_uncached cache_init(void)
+ {
+ 	unsigned long ccr, flags;
+ 
+-	/* First setup the rest of the I-cache info */
+-	current_cpu_data.icache.entry_mask = current_cpu_data.icache.way_incr -
+-				      current_cpu_data.icache.linesz;
+-
+-	current_cpu_data.icache.way_size = current_cpu_data.icache.sets *
+-				    current_cpu_data.icache.linesz;
+-
+-	/* And the D-cache too */
+-	current_cpu_data.dcache.entry_mask = current_cpu_data.dcache.way_incr -
+-				      current_cpu_data.dcache.linesz;
+-
+-	current_cpu_data.dcache.way_size = current_cpu_data.dcache.sets *
+-				    current_cpu_data.dcache.linesz;
+-
+-	jump_to_P2();
++	jump_to_uncached();
+ 	ccr = ctrl_inl(CCR);
+ 
+ 	/*
+@@ -156,7 +147,31 @@ static void __init cache_init(void)
+ #endif
+ 
+ 	ctrl_outl(flags, CCR);
+-	back_to_P1();
++	back_to_cached();
++}
++#else
++#define cache_init()	do { } while (0)
++#endif
++
++#define CSHAPE(totalsize, linesize, assoc) \
++	((totalsize & ~0xff) | (linesize << 4) | assoc)
++
++#define CACHE_DESC_SHAPE(desc)	\
++	CSHAPE((desc).way_size * (desc).ways, ilog2((desc).linesz), (desc).ways)
++
++static void detect_cache_shape(void)
++{
++	l1d_cache_shape = CACHE_DESC_SHAPE(current_cpu_data.dcache);
++
++	if (current_cpu_data.dcache.flags & SH_CACHE_COMBINED)
++		l1i_cache_shape = l1d_cache_shape;
++	else
++		l1i_cache_shape = CACHE_DESC_SHAPE(current_cpu_data.icache);
++
++	if (current_cpu_data.flags & CPU_HAS_L2_CACHE)
++		l2_cache_shape = CACHE_DESC_SHAPE(current_cpu_data.scache);
++	else
++		l2_cache_shape = -1; /* No S-cache */
+ }
+ 
+ #ifdef CONFIG_SH_DSP
+@@ -228,14 +243,32 @@ asmlinkage void __cpuinit sh_cpu_init(void)
+ 	if (current_cpu_data.type == CPU_SH_NONE)
+ 		panic("Unknown CPU");
+ 
++	/* First setup the rest of the I-cache info */
++	current_cpu_data.icache.entry_mask = current_cpu_data.icache.way_incr -
++				      current_cpu_data.icache.linesz;
++
++	current_cpu_data.icache.way_size = current_cpu_data.icache.sets *
++				    current_cpu_data.icache.linesz;
++
++	/* And the D-cache too */
++	current_cpu_data.dcache.entry_mask = current_cpu_data.dcache.way_incr -
++				      current_cpu_data.dcache.linesz;
++
++	current_cpu_data.dcache.way_size = current_cpu_data.dcache.sets *
++				    current_cpu_data.dcache.linesz;
++
+ 	/* Init the cache */
+ 	cache_init();
+ 
+-	if (raw_smp_processor_id() == 0)
++	if (raw_smp_processor_id() == 0) {
+ 		shm_align_mask = max_t(unsigned long,
+ 				       current_cpu_data.dcache.way_size - 1,
+ 				       PAGE_SIZE - 1);
+ 
++		/* Boot CPU sets the cache shape */
++		detect_cache_shape();
++	}
++
+ 	/* Disable the FPU */
+ 	if (fpu_disabled) {
+ 		printk("FPU Disabled\n");
+@@ -273,7 +306,10 @@ asmlinkage void __cpuinit sh_cpu_init(void)
+ 	 * like PTRACE_SINGLESTEP or doing hardware watchpoints in GDB.  So ..
+ 	 * we wake it up and hope that all is well.
+ 	 */
++#ifdef CONFIG_SUPERH32
+ 	if (raw_smp_processor_id() == 0)
+ 		ubc_wakeup();
++#endif
++
+ 	speculative_execution_init();
+ }
+diff --git a/arch/sh/kernel/cpu/irq/Makefile b/arch/sh/kernel/cpu/irq/Makefile
+index 8da8e17..cc1836e 100644
+--- a/arch/sh/kernel/cpu/irq/Makefile
++++ b/arch/sh/kernel/cpu/irq/Makefile
+@@ -1,7 +1,9 @@
+ #
+ # Makefile for the Linux/SuperH CPU-specifc IRQ handlers.
+ #
+-obj-y	+= imask.o intc.o
++obj-y	+= intc.o
+ 
++obj-$(CONFIG_SUPERH32)			+= imask.o
++obj-$(CONFIG_CPU_SH5)			+= intc-sh5.o
+ obj-$(CONFIG_CPU_HAS_IPR_IRQ)		+= ipr.o
+ obj-$(CONFIG_CPU_HAS_MASKREG_IRQ)	+= maskreg.o
+diff --git a/arch/sh/kernel/cpu/irq/intc-sh5.c b/arch/sh/kernel/cpu/irq/intc-sh5.c
+new file mode 100644
+index 0000000..43ee7a9
+--- /dev/null
++++ b/arch/sh/kernel/cpu/irq/intc-sh5.c
+@@ -0,0 +1,257 @@
++/*
++ * arch/sh/kernel/cpu/irq/intc-sh5.c
++ *
++ * Interrupt Controller support for SH5 INTC.
++ *
++ * Copyright (C) 2000, 2001  Paolo Alberelli
++ * Copyright (C) 2003  Paul Mundt
++ *
++ * Per-interrupt selective. IRLM=0 (Fixed priority) is not
++ * supported being useless without a cascaded interrupt
++ * controller.
++ *
++ * 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/interrupt.h>
++#include <linux/irq.h>
++#include <linux/io.h>
++#include <linux/kernel.h>
++#include <linux/bitops.h>
++#include <asm/cpu/irq.h>
++#include <asm/page.h>
++
++/*
++ * Maybe the generic Peripheral block could move to a more
++ * generic include file. INTC Block will be defined here
++ * and only here to make INTC self-contained in a single
++ * file.
++ */
++#define	INTC_BLOCK_OFFSET	0x01000000
++
++/* Base */
++#define INTC_BASE		PHYS_PERIPHERAL_BLOCK + \
++				INTC_BLOCK_OFFSET
++
++/* Address */
++#define INTC_ICR_SET		(intc_virt + 0x0)
++#define INTC_ICR_CLEAR		(intc_virt + 0x8)
++#define INTC_INTPRI_0		(intc_virt + 0x10)
++#define INTC_INTSRC_0		(intc_virt + 0x50)
++#define INTC_INTSRC_1		(intc_virt + 0x58)
++#define INTC_INTREQ_0		(intc_virt + 0x60)
++#define INTC_INTREQ_1		(intc_virt + 0x68)
++#define INTC_INTENB_0		(intc_virt + 0x70)
++#define INTC_INTENB_1		(intc_virt + 0x78)
++#define INTC_INTDSB_0		(intc_virt + 0x80)
++#define INTC_INTDSB_1		(intc_virt + 0x88)
++
++#define INTC_ICR_IRLM		0x1
++#define	INTC_INTPRI_PREGS	8		/* 8 Priority Registers */
++#define	INTC_INTPRI_PPREG	8		/* 8 Priorities per Register */
++
++
++/*
++ * Mapper between the vector ordinal and the IRQ number
++ * passed to kernel/device drivers.
++ */
++int intc_evt_to_irq[(0xE20/0x20)+1] = {
++	-1, -1, -1, -1, -1, -1, -1, -1,	/* 0x000 - 0x0E0 */
++	-1, -1, -1, -1, -1, -1, -1, -1,	/* 0x100 - 0x1E0 */
++	 0,  0,  0,  0,  0,  1,  0,  0,	/* 0x200 - 0x2E0 */
++	 2,  0,  0,  3,  0,  0,  0, -1,	/* 0x300 - 0x3E0 */
++	32, 33, 34, 35, 36, 37, 38, -1,	/* 0x400 - 0x4E0 */
++	-1, -1, -1, 63, -1, -1, -1, -1,	/* 0x500 - 0x5E0 */
++	-1, -1, 18, 19, 20, 21, 22, -1,	/* 0x600 - 0x6E0 */
++	39, 40, 41, 42, -1, -1, -1, -1,	/* 0x700 - 0x7E0 */
++	 4,  5,  6,  7, -1, -1, -1, -1,	/* 0x800 - 0x8E0 */
++	-1, -1, -1, -1, -1, -1, -1, -1,	/* 0x900 - 0x9E0 */
++	12, 13, 14, 15, 16, 17, -1, -1,	/* 0xA00 - 0xAE0 */
++	-1, -1, -1, -1, -1, -1, -1, -1,	/* 0xB00 - 0xBE0 */
++	-1, -1, -1, -1, -1, -1, -1, -1,	/* 0xC00 - 0xCE0 */
++	-1, -1, -1, -1, -1, -1, -1, -1,	/* 0xD00 - 0xDE0 */
++	-1, -1				/* 0xE00 - 0xE20 */
++};
++
++/*
++ * Opposite mapper.
++ */
++static int IRQ_to_vectorN[NR_INTC_IRQS] = {
++	0x12, 0x15, 0x18, 0x1B, 0x40, 0x41, 0x42, 0x43, /*  0- 7 */
++	  -1,   -1,   -1,   -1, 0x50, 0x51, 0x52, 0x53,	/*  8-15 */
++	0x54, 0x55, 0x32, 0x33, 0x34, 0x35, 0x36,   -1, /* 16-23 */
++	  -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, /* 24-31 */
++	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x38,	/* 32-39 */
++        0x39, 0x3A, 0x3B,   -1,   -1,   -1,   -1,   -1, /* 40-47 */
++	  -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, /* 48-55 */
++	  -1,   -1,   -1,   -1,   -1,   -1,   -1, 0x2B, /* 56-63 */
++
++};
++
++static unsigned long intc_virt;
++
++static unsigned int startup_intc_irq(unsigned int irq);
++static void shutdown_intc_irq(unsigned int irq);
++static void enable_intc_irq(unsigned int irq);
++static void disable_intc_irq(unsigned int irq);
++static void mask_and_ack_intc(unsigned int);
++static void end_intc_irq(unsigned int irq);
++
++static struct hw_interrupt_type intc_irq_type = {
++	.typename = "INTC",
++	.startup = startup_intc_irq,
++	.shutdown = shutdown_intc_irq,
++	.enable = enable_intc_irq,
++	.disable = disable_intc_irq,
++	.ack = mask_and_ack_intc,
++	.end = end_intc_irq
++};
++
++static int irlm;		/* IRL mode */
++
++static unsigned int startup_intc_irq(unsigned int irq)
++{
++	enable_intc_irq(irq);
++	return 0; /* never anything pending */
++}
++
++static void shutdown_intc_irq(unsigned int irq)
++{
++	disable_intc_irq(irq);
++}
++
++static void enable_intc_irq(unsigned int irq)
++{
++	unsigned long reg;
++	unsigned long bitmask;
++
++	if ((irq <= IRQ_IRL3) && (irlm == NO_PRIORITY))
++		printk("Trying to use straight IRL0-3 with an encoding platform.\n");
++
++	if (irq < 32) {
++		reg = INTC_INTENB_0;
++		bitmask = 1 << irq;
++	} else {
++		reg = INTC_INTENB_1;
++		bitmask = 1 << (irq - 32);
++	}
++
++	ctrl_outl(bitmask, reg);
++}
++
++static void disable_intc_irq(unsigned int irq)
++{
++	unsigned long reg;
++	unsigned long bitmask;
++
++	if (irq < 32) {
++		reg = INTC_INTDSB_0;
++		bitmask = 1 << irq;
++	} else {
++		reg = INTC_INTDSB_1;
++		bitmask = 1 << (irq - 32);
++	}
++
++	ctrl_outl(bitmask, reg);
++}
++
++static void mask_and_ack_intc(unsigned int irq)
++{
++	disable_intc_irq(irq);
++}
++
++static void end_intc_irq(unsigned int irq)
++{
++	enable_intc_irq(irq);
++}
++
++/* For future use, if we ever support IRLM=0) */
++void make_intc_irq(unsigned int irq)
++{
++	disable_irq_nosync(irq);
++	irq_desc[irq].chip = &intc_irq_type;
++	disable_intc_irq(irq);
++}
++
++#if defined(CONFIG_PROC_FS) && defined(CONFIG_SYSCTL)
++int intc_irq_describe(char* p, int irq)
++{
++	if (irq < NR_INTC_IRQS)
++		return sprintf(p, "(0x%3x)", IRQ_to_vectorN[irq]*0x20);
++	else
++		return 0;
++}
++#endif
++
++void __init plat_irq_setup(void)
++{
++        unsigned long long __dummy0, __dummy1=~0x00000000100000f0;
++	unsigned long reg;
++	unsigned long data;
++	int i;
++
++	intc_virt = onchip_remap(INTC_BASE, 1024, "INTC");
++	if (!intc_virt) {
++		panic("Unable to remap INTC\n");
++	}
++
++
++	/* Set default: per-line enable/disable, priority driven ack/eoi */
++	for (i = 0; i < NR_INTC_IRQS; i++) {
++		if (platform_int_priority[i] != NO_PRIORITY) {
++			irq_desc[i].chip = &intc_irq_type;
++		}
++	}
++
++
++	/* Disable all interrupts and set all priorities to 0 to avoid trouble */
++	ctrl_outl(-1, INTC_INTDSB_0);
++	ctrl_outl(-1, INTC_INTDSB_1);
++
++	for (reg = INTC_INTPRI_0, i = 0; i < INTC_INTPRI_PREGS; i++, reg += 8)
++		ctrl_outl( NO_PRIORITY, reg);
++
++
++	/* Set IRLM */
++	/* If all the priorities are set to 'no priority', then
++	 * assume we are using encoded mode.
++	 */
++	irlm = platform_int_priority[IRQ_IRL0] + platform_int_priority[IRQ_IRL1] + \
++		platform_int_priority[IRQ_IRL2] + platform_int_priority[IRQ_IRL3];
++
++	if (irlm == NO_PRIORITY) {
++		/* IRLM = 0 */
++		reg = INTC_ICR_CLEAR;
++		i = IRQ_INTA;
++		printk("Trying to use encoded IRL0-3. IRLs unsupported.\n");
++	} else {
++		/* IRLM = 1 */
++		reg = INTC_ICR_SET;
++		i = IRQ_IRL0;
++	}
++	ctrl_outl(INTC_ICR_IRLM, reg);
++
++	/* Set interrupt priorities according to platform description */
++	for (data = 0, reg = INTC_INTPRI_0; i < NR_INTC_IRQS; i++) {
++		data |= platform_int_priority[i] << ((i % INTC_INTPRI_PPREG) * 4);
++		if ((i % INTC_INTPRI_PPREG) == (INTC_INTPRI_PPREG - 1)) {
++			/* Upon the 7th, set Priority Register */
++			ctrl_outl(data, reg);
++			data = 0;
++			reg += 8;
++		}
++	}
++
++	/*
++	 * And now let interrupts come in.
++	 * sti() is not enough, we need to
++	 * lower priority, too.
++	 */
++        __asm__ __volatile__("getcon    " __SR ", %0\n\t"
++                             "and       %0, %1, %0\n\t"
++                             "putcon    %0, " __SR "\n\t"
++                             : "=&r" (__dummy0)
++                             : "r" (__dummy1));
++}
+diff --git a/arch/sh/kernel/cpu/irq/intc.c b/arch/sh/kernel/cpu/irq/intc.c
+index 6ac018c..84806b2 100644
+--- a/arch/sh/kernel/cpu/irq/intc.c
++++ b/arch/sh/kernel/cpu/irq/intc.c
+@@ -335,31 +335,6 @@ static intc_enum __init intc_grp_id(struct intc_desc *desc,
+ 	return 0;
+ }
+ 
+-static unsigned int __init intc_prio_value(struct intc_desc *desc,
+-					   intc_enum enum_id, int do_grps)
+-{
+-	struct intc_prio *p = desc->priorities;
+-	unsigned int i;
+-
+-	for (i = 0; p && enum_id && i < desc->nr_priorities; i++) {
+-		p = desc->priorities + i;
+-
+-		if (p->enum_id != enum_id)
+-			continue;
+-
+-		return p->priority;
+-	}
+-
+-	if (do_grps)
+-		return intc_prio_value(desc, intc_grp_id(desc, enum_id), 0);
+-
+-	/* default to the lowest priority possible if no priority is set
+-	 * - this needs to be at least 2 for 5-bit priorities on 7780
+-	 */
+-
+-	return 2;
+-}
+-
+ static unsigned int __init intc_mask_data(struct intc_desc *desc,
+ 					  struct intc_desc_int *d,
+ 					  intc_enum enum_id, int do_grps)
+@@ -518,8 +493,10 @@ static void __init intc_register_irq(struct intc_desc *desc,
+ 				      handle_level_irq, "level");
+ 	set_irq_chip_data(irq, (void *)data[primary]);
+ 
+-	/* record the desired priority level */
+-	intc_prio_level[irq] = intc_prio_value(desc, enum_id, 1);
++	/* set priority level
++	 * - this needs to be at least 2 for 5-bit priorities on 7780
++	 */
++	intc_prio_level[irq] = 2;
+ 
+ 	/* enable secondary masking method if present */
+ 	if (data[!primary])
+diff --git a/arch/sh/kernel/cpu/sh2/entry.S b/arch/sh/kernel/cpu/sh2/entry.S
+index ee8f1fe..7a26569 100644
+--- a/arch/sh/kernel/cpu/sh2/entry.S
++++ b/arch/sh/kernel/cpu/sh2/entry.S
+@@ -149,6 +149,14 @@ ENTRY(exception_handler)
+ 	mov	#32,r8
+ 	cmp/hs	r8,r9
+ 	bt	trap_entry	! 64 > vec >= 32  is trap
++
++#if defined(CONFIG_SH_FPU)
++	mov     #13,r8
++	cmp/eq  r8,r9
++	bt      10f             ! fpu
++	nop
++#endif
++
+ 	mov.l	4f,r8
+ 	mov	r9,r4
+ 	shll2	r9
+@@ -158,6 +166,10 @@ ENTRY(exception_handler)
+ 	cmp/eq	r9,r8
+ 	bf	3f
+ 	mov.l	8f,r8		! unhandled exception
++#if defined(CONFIG_SH_FPU)
++10:
++	mov.l	9f, r8		! unhandled exception
++#endif
+ 3:
+ 	mov.l	5f,r10
+ 	jmp	@r8
+@@ -177,7 +189,10 @@ interrupt_entry:
+ 6:	.long	ret_from_irq
+ 7:	.long	do_IRQ
+ 8:	.long	do_exception_error
+-	
++#ifdef CONFIG_SH_FPU
++9:	.long	fpu_error_trap_handler
++#endif
++
+ trap_entry:
+ 	mov	#0x30,r8
+ 	cmp/ge	r8,r9		! vector 0x20-0x2f is systemcall
+@@ -250,7 +265,7 @@ ENTRY(sh_bios_handler)
+ 1:	.long	gdb_vbr_vector
+ #endif /* CONFIG_SH_STANDARD_BIOS */
+ 
+-ENTRY(address_error_handler)
++ENTRY(address_error_trap_handler)
+ 	mov	r15,r4				! regs
+ 	add	#4,r4
+ 	mov	#OFF_PC,r0
+diff --git a/arch/sh/kernel/cpu/sh2/setup-sh7619.c b/arch/sh/kernel/cpu/sh2/setup-sh7619.c
+index ec6adc3..b230eb2 100644
+--- a/arch/sh/kernel/cpu/sh2/setup-sh7619.c
++++ b/arch/sh/kernel/cpu/sh2/setup-sh7619.c
+@@ -65,7 +65,7 @@ static struct intc_prio_reg prio_registers[] __initdata = {
+ };
+ 
+ static DECLARE_INTC_DESC(intc_desc, "sh7619", vectors, groups,
+-			 NULL, NULL, prio_registers, NULL);
++			 NULL, prio_registers, NULL);
+ 
+ static struct plat_sci_port sci_platform_data[] = {
+ 	{
+diff --git a/arch/sh/kernel/cpu/sh2a/Makefile b/arch/sh/kernel/cpu/sh2a/Makefile
+index 965fa25..b279cdc 100644
+--- a/arch/sh/kernel/cpu/sh2a/Makefile
++++ b/arch/sh/kernel/cpu/sh2a/Makefile
+@@ -6,4 +6,8 @@ obj-y	:= common.o probe.o opcode_helper.o
+ 
+ common-y	+= $(addprefix ../sh2/, ex.o entry.o)
+ 
++obj-$(CONFIG_SH_FPU)	+= fpu.o
++
+ obj-$(CONFIG_CPU_SUBTYPE_SH7206) += setup-sh7206.o clock-sh7206.o
++obj-$(CONFIG_CPU_SUBTYPE_SH7203) += setup-sh7203.o clock-sh7203.o
++obj-$(CONFIG_CPU_SUBTYPE_SH7263) += setup-sh7203.o clock-sh7203.o
+diff --git a/arch/sh/kernel/cpu/sh2a/clock-sh7203.c b/arch/sh/kernel/cpu/sh2a/clock-sh7203.c
+new file mode 100644
+index 0000000..3feb95a
+--- /dev/null
++++ b/arch/sh/kernel/cpu/sh2a/clock-sh7203.c
+@@ -0,0 +1,89 @@
++/*
++ * arch/sh/kernel/cpu/sh2a/clock-sh7203.c
++ *
++ * SH7203 support for the clock framework
++ *
++ *  Copyright (C) 2007 Kieran Bingham (MPC-Data Ltd)
++ *
++ * Based on clock-sh7263.c
++ *  Copyright (C) 2006  Yoshinori Sato
++ *
++ * Based on clock-sh4.c
++ *  Copyright (C) 2005  Paul Mundt
++ *
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License.  See the file "COPYING" in the main directory of this archive
++ * for more details.
++ */
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <asm/clock.h>
++#include <asm/freq.h>
++#include <asm/io.h>
++
++const static int pll1rate[]={8,12,16,0};
++const static int pfc_divisors[]={1,2,3,4,6,8,12};
++#define ifc_divisors pfc_divisors
++
++#if (CONFIG_SH_CLK_MD == 0)
++#define PLL2 (1)
++#elif (CONFIG_SH_CLK_MD == 1)
++#define PLL2 (2)
++#elif (CONFIG_SH_CLK_MD == 2)
++#define PLL2 (4)
++#elif (CONFIG_SH_CLK_MD == 3)
++#define PLL2 (4)
++#else
++#error "Illegal Clock Mode!"
++#endif
++
++static void master_clk_init(struct clk *clk)
++{
++	clk->rate *= pll1rate[(ctrl_inw(FREQCR) >> 8) & 0x0003] * PLL2 ;
++}
++
++static struct clk_ops sh7203_master_clk_ops = {
++	.init		= master_clk_init,
++};
++
++static void module_clk_recalc(struct clk *clk)
++{
++	int idx = (ctrl_inw(FREQCR) & 0x0007);
++	clk->rate = clk->parent->rate / pfc_divisors[idx];
++}
++
++static struct clk_ops sh7203_module_clk_ops = {
++	.recalc		= module_clk_recalc,
++};
++
++static void bus_clk_recalc(struct clk *clk)
++{
++	int idx = (ctrl_inw(FREQCR) & 0x0007);
++	clk->rate = clk->parent->rate / pfc_divisors[idx-2];
++}
++
++static struct clk_ops sh7203_bus_clk_ops = {
++	.recalc		= bus_clk_recalc,
++};
++
++static void cpu_clk_recalc(struct clk *clk)
++{
++	clk->rate = clk->parent->rate;
++}
++
++static struct clk_ops sh7203_cpu_clk_ops = {
++	.recalc		= cpu_clk_recalc,
++};
++
++static struct clk_ops *sh7203_clk_ops[] = {
++	&sh7203_master_clk_ops,
++	&sh7203_module_clk_ops,
++	&sh7203_bus_clk_ops,
++	&sh7203_cpu_clk_ops,
++};
++
++void __init arch_init_clk_ops(struct clk_ops **ops, int idx)
++{
++	if (idx < ARRAY_SIZE(sh7203_clk_ops))
++		*ops = sh7203_clk_ops[idx];
++}
+diff --git a/arch/sh/kernel/cpu/sh2a/fpu.c b/arch/sh/kernel/cpu/sh2a/fpu.c
+new file mode 100644
+index 0000000..ff99562
+--- /dev/null
++++ b/arch/sh/kernel/cpu/sh2a/fpu.c
+@@ -0,0 +1,633 @@
++/*
++ * Save/restore floating point context for signal handlers.
++ *
++ * Copyright (C) 1999, 2000  Kaz Kojima & Niibe Yutaka
++ *
++ * 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.
++ *
++ * FIXME! These routines can be optimized in big endian case.
++ */
++#include <linux/sched.h>
++#include <linux/signal.h>
++#include <asm/processor.h>
++#include <asm/io.h>
++
++/* The PR (precision) bit in the FP Status Register must be clear when
++ * an frchg instruction is executed, otherwise the instruction is undefined.
++ * Executing frchg with PR set causes a trap on some SH4 implementations.
++ */
++
++#define FPSCR_RCHG 0x00000000
++
++
++/*
++ * Save FPU registers onto task structure.
++ * Assume called with FPU enabled (SR.FD=0).
++ */
++void
++save_fpu(struct task_struct *tsk, struct pt_regs *regs)
++{
++	unsigned long dummy;
++
++	clear_tsk_thread_flag(tsk, TIF_USEDFPU);
++	enable_fpu();
++	asm volatile("sts.l	fpul, @-%0\n\t"
++		     "sts.l	fpscr, @-%0\n\t"
++		     "fmov.s	fr15, @-%0\n\t"
++		     "fmov.s	fr14, @-%0\n\t"
++		     "fmov.s	fr13, @-%0\n\t"
++		     "fmov.s	fr12, @-%0\n\t"
++		     "fmov.s	fr11, @-%0\n\t"
++		     "fmov.s	fr10, @-%0\n\t"
++		     "fmov.s	fr9, @-%0\n\t"
++		     "fmov.s	fr8, @-%0\n\t"
++		     "fmov.s	fr7, @-%0\n\t"
++		     "fmov.s	fr6, @-%0\n\t"
++		     "fmov.s	fr5, @-%0\n\t"
++		     "fmov.s	fr4, @-%0\n\t"
++		     "fmov.s	fr3, @-%0\n\t"
++		     "fmov.s	fr2, @-%0\n\t"
++		     "fmov.s	fr1, @-%0\n\t"
++		     "fmov.s	fr0, @-%0\n\t"
++		     "lds	%3, fpscr\n\t"
++		     : "=r" (dummy)
++		     : "0" ((char *)(&tsk->thread.fpu.hard.status)),
++		       "r" (FPSCR_RCHG),
++		       "r" (FPSCR_INIT)
++		     : "memory");
++
++	disable_fpu();
++	release_fpu(regs);
++}
++
++static void
++restore_fpu(struct task_struct *tsk)
++{
++	unsigned long dummy;
++
++	enable_fpu();
++	asm volatile("fmov.s	@%0+, fr0\n\t"
++		     "fmov.s	@%0+, fr1\n\t"
++		     "fmov.s	@%0+, fr2\n\t"
++		     "fmov.s	@%0+, fr3\n\t"
++		     "fmov.s	@%0+, fr4\n\t"
++		     "fmov.s	@%0+, fr5\n\t"
++		     "fmov.s	@%0+, fr6\n\t"
++		     "fmov.s	@%0+, fr7\n\t"
++		     "fmov.s	@%0+, fr8\n\t"
++		     "fmov.s	@%0+, fr9\n\t"
++		     "fmov.s	@%0+, fr10\n\t"
++		     "fmov.s	@%0+, fr11\n\t"
++		     "fmov.s	@%0+, fr12\n\t"
++		     "fmov.s	@%0+, fr13\n\t"
++		     "fmov.s	@%0+, fr14\n\t"
++		     "fmov.s	@%0+, fr15\n\t"
++		     "lds.l	@%0+, fpscr\n\t"
++		     "lds.l	@%0+, fpul\n\t"
++		     : "=r" (dummy)
++		     : "0" (&tsk->thread.fpu), "r" (FPSCR_RCHG)
++		     : "memory");
++	disable_fpu();
++}
++
++/*
++ * Load the FPU with signalling NANS.  This bit pattern we're using
++ * has the property that no matter wether considered as single or as
++ * double precission represents signaling NANS.
++ */
++
++static void
++fpu_init(void)
++{
++	enable_fpu();
++	asm volatile("lds	%0, fpul\n\t"
++		     "fsts	fpul, fr0\n\t"
++		     "fsts	fpul, fr1\n\t"
++		     "fsts	fpul, fr2\n\t"
++		     "fsts	fpul, fr3\n\t"
++		     "fsts	fpul, fr4\n\t"
++		     "fsts	fpul, fr5\n\t"
++		     "fsts	fpul, fr6\n\t"
++		     "fsts	fpul, fr7\n\t"
++		     "fsts	fpul, fr8\n\t"
++		     "fsts	fpul, fr9\n\t"
++		     "fsts	fpul, fr10\n\t"
++		     "fsts	fpul, fr11\n\t"
++		     "fsts	fpul, fr12\n\t"
++		     "fsts	fpul, fr13\n\t"
++		     "fsts	fpul, fr14\n\t"
++		     "fsts	fpul, fr15\n\t"
++		     "lds	%2, fpscr\n\t"
++		     : /* no output */
++		     : "r" (0), "r" (FPSCR_RCHG), "r" (FPSCR_INIT));
++	disable_fpu();
++}
++
++/*
++ *	Emulate arithmetic ops on denormalized number for some FPU insns.
++ */
++
++/* denormalized float * float */
++static int denormal_mulf(int hx, int hy)
++{
++	unsigned int ix, iy;
++	unsigned long long m, n;
++	int exp, w;
++
++	ix = hx & 0x7fffffff;
++	iy = hy & 0x7fffffff;
++	if (iy < 0x00800000 || ix == 0)
++		return ((hx ^ hy) & 0x80000000);
++
++	exp = (iy & 0x7f800000) >> 23;
++	ix &= 0x007fffff;
++	iy = (iy & 0x007fffff) | 0x00800000;
++	m = (unsigned long long)ix * iy;
++	n = m;
++	w = -1;
++	while (n) { n >>= 1; w++; }
++
++	/* FIXME: use guard bits */
++	exp += w - 126 - 46;
++	if (exp > 0)
++		ix = ((int) (m >> (w - 23)) & 0x007fffff) | (exp << 23);
++	else if (exp + 22 >= 0)
++		ix = (int) (m >> (w - 22 - exp)) & 0x007fffff;
++	else
++		ix = 0;
++
++	ix |= (hx ^ hy) & 0x80000000;
++	return ix;
++}
++
++/* denormalized double * double */
++static void mult64(unsigned long long x, unsigned long long y,
++		unsigned long long *highp, unsigned long long *lowp)
++{
++	unsigned long long sub0, sub1, sub2, sub3;
++	unsigned long long high, low;
++
++	sub0 = (x >> 32) * (unsigned long) (y >> 32);
++	sub1 = (x & 0xffffffffLL) * (unsigned long) (y >> 32);
++	sub2 = (x >> 32) * (unsigned long) (y & 0xffffffffLL);
++	sub3 = (x & 0xffffffffLL) * (unsigned long) (y & 0xffffffffLL);
++	low = sub3;
++	high = 0LL;
++	sub3 += (sub1 << 32);
++	if (low > sub3)
++		high++;
++	low = sub3;
++	sub3 += (sub2 << 32);
++	if (low > sub3)
++		high++;
++	low = sub3;
++	high += (sub1 >> 32) + (sub2 >> 32);
++	high += sub0;
++	*lowp = low;
++	*highp = high;
++}
++
++static inline long long rshift64(unsigned long long mh,
++		unsigned long long ml, int n)
++{
++	if (n >= 64)
++		return mh >> (n - 64);
++	return (mh << (64 - n)) | (ml >> n);
++}
++
++static long long denormal_muld(long long hx, long long hy)
++{
++	unsigned long long ix, iy;
++	unsigned long long mh, ml, nh, nl;
++	int exp, w;
++
++	ix = hx & 0x7fffffffffffffffLL;
++	iy = hy & 0x7fffffffffffffffLL;
++	if (iy < 0x0010000000000000LL || ix == 0)
++		return ((hx ^ hy) & 0x8000000000000000LL);
++
++	exp = (iy & 0x7ff0000000000000LL) >> 52;
++	ix &= 0x000fffffffffffffLL;
++	iy = (iy & 0x000fffffffffffffLL) | 0x0010000000000000LL;
++	mult64(ix, iy, &mh, &ml);
++	nh = mh;
++	nl = ml;
++	w = -1;
++	if (nh) {
++		while (nh) { nh >>= 1; w++;}
++		w += 64;
++	} else
++		while (nl) { nl >>= 1; w++;}
++
++	/* FIXME: use guard bits */
++	exp += w - 1022 - 52 * 2;
++	if (exp > 0)
++		ix = (rshift64(mh, ml, w - 52) & 0x000fffffffffffffLL)
++			| ((long long)exp << 52);
++	else if (exp + 51 >= 0)
++		ix = rshift64(mh, ml, w - 51 - exp) & 0x000fffffffffffffLL;
++	else
++		ix = 0;
++
++	ix |= (hx ^ hy) & 0x8000000000000000LL;
++	return ix;
++}
++
++/* ix - iy where iy: denormal and ix, iy >= 0 */
++static int denormal_subf1(unsigned int ix, unsigned int iy)
++{
++	int frac;
++	int exp;
++
++	if (ix < 0x00800000)
++		return ix - iy;
++
++	exp = (ix & 0x7f800000) >> 23;
++	if (exp - 1 > 31)
++		return ix;
++	iy >>= exp - 1;
++	if (iy == 0)
++		return ix;
++
++	frac = (ix & 0x007fffff) | 0x00800000;
++	frac -= iy;
++	while (frac < 0x00800000) {
++		if (--exp == 0)
++			return frac;
++		frac <<= 1;
++	}
++
++	return (exp << 23) | (frac & 0x007fffff);
++}
++
++/* ix + iy where iy: denormal and ix, iy >= 0 */
++static int denormal_addf1(unsigned int ix, unsigned int iy)
++{
++	int frac;
++	int exp;
++
++	if (ix < 0x00800000)
++		return ix + iy;
++
++	exp = (ix & 0x7f800000) >> 23;
++	if (exp - 1 > 31)
++		return ix;
++	iy >>= exp - 1;
++	if (iy == 0)
++	  return ix;
++
++	frac = (ix & 0x007fffff) | 0x00800000;
++	frac += iy;
++	if (frac >= 0x01000000) {
++		frac >>= 1;
++		++exp;
++	}
++
++	return (exp << 23) | (frac & 0x007fffff);
++}
++
++static int denormal_addf(int hx, int hy)
++{
++	unsigned int ix, iy;
++	int sign;
++
++	if ((hx ^ hy) & 0x80000000) {
++		sign = hx & 0x80000000;
++		ix = hx & 0x7fffffff;
++		iy = hy & 0x7fffffff;
++		if (iy < 0x00800000) {
++			ix = denormal_subf1(ix, iy);
++			if (ix < 0) {
++				ix = -ix;
++				sign ^= 0x80000000;
++			}
++		} else {
++			ix = denormal_subf1(iy, ix);
++			sign ^= 0x80000000;
++		}
++	} else {
++		sign = hx & 0x80000000;
++		ix = hx & 0x7fffffff;
++		iy = hy & 0x7fffffff;
++		if (iy < 0x00800000)
++			ix = denormal_addf1(ix, iy);
++		else
++			ix = denormal_addf1(iy, ix);
++	}
++
++	return sign | ix;
++}
++
++/* ix - iy where iy: denormal and ix, iy >= 0 */
++static long long denormal_subd1(unsigned long long ix, unsigned long long iy)
++{
++	long long frac;
++	int exp;
++
++	if (ix < 0x0010000000000000LL)
++		return ix - iy;
++
++	exp = (ix & 0x7ff0000000000000LL) >> 52;
++	if (exp - 1 > 63)
++		return ix;
++	iy >>= exp - 1;
++	if (iy == 0)
++		return ix;
++
++	frac = (ix & 0x000fffffffffffffLL) | 0x0010000000000000LL;
++	frac -= iy;
++	while (frac < 0x0010000000000000LL) {
++		if (--exp == 0)
++			return frac;
++		frac <<= 1;
++	}
++
++	return ((long long)exp << 52) | (frac & 0x000fffffffffffffLL);
++}
++
++/* ix + iy where iy: denormal and ix, iy >= 0 */
++static long long denormal_addd1(unsigned long long ix, unsigned long long iy)
++{
++	long long frac;
++	long long exp;
++
++	if (ix < 0x0010000000000000LL)
++		return ix + iy;
++
++	exp = (ix & 0x7ff0000000000000LL) >> 52;
++	if (exp - 1 > 63)
++		return ix;
++	iy >>= exp - 1;
++	if (iy == 0)
++	  return ix;
++
++	frac = (ix & 0x000fffffffffffffLL) | 0x0010000000000000LL;
++	frac += iy;
++	if (frac >= 0x0020000000000000LL) {
++		frac >>= 1;
++		++exp;
++	}
++
++	return (exp << 52) | (frac & 0x000fffffffffffffLL);
++}
++
++static long long denormal_addd(long long hx, long long hy)
++{
++	unsigned long long ix, iy;
++	long long sign;
++
++	if ((hx ^ hy) & 0x8000000000000000LL) {
++		sign = hx & 0x8000000000000000LL;
++		ix = hx & 0x7fffffffffffffffLL;
++		iy = hy & 0x7fffffffffffffffLL;
++		if (iy < 0x0010000000000000LL) {
++			ix = denormal_subd1(ix, iy);
++			if (ix < 0) {
++				ix = -ix;
++				sign ^= 0x8000000000000000LL;
++			}
++		} else {
++			ix = denormal_subd1(iy, ix);
++			sign ^= 0x8000000000000000LL;
++		}
++	} else {
++		sign = hx & 0x8000000000000000LL;
++		ix = hx & 0x7fffffffffffffffLL;
++		iy = hy & 0x7fffffffffffffffLL;
++		if (iy < 0x0010000000000000LL)
++			ix = denormal_addd1(ix, iy);
++		else
++			ix = denormal_addd1(iy, ix);
++	}
++
++	return sign | ix;
++}
++
++/**
++ *	denormal_to_double - Given denormalized float number,
++ *	                     store double float
++ *
++ *	@fpu: Pointer to sh_fpu_hard structure
++ *	@n: Index to FP register
++ */
++static void
++denormal_to_double (struct sh_fpu_hard_struct *fpu, int n)
++{
++	unsigned long du, dl;
++	unsigned long x = fpu->fpul;
++	int exp = 1023 - 126;
++
++	if (x != 0 && (x & 0x7f800000) == 0) {
++		du = (x & 0x80000000);
++		while ((x & 0x00800000) == 0) {
++			x <<= 1;
++			exp--;
++		}
++		x &= 0x007fffff;
++		du |= (exp << 20) | (x >> 3);
++		dl = x << 29;
++
++		fpu->fp_regs[n] = du;
++		fpu->fp_regs[n+1] = dl;
++	}
++}
++
++/**
++ *	ieee_fpe_handler - Handle denormalized number exception
++ *
++ *	@regs: Pointer to register structure
++ *
++ *	Returns 1 when it's handled (should not cause exception).
++ */
++static int
++ieee_fpe_handler (struct pt_regs *regs)
++{
++	unsigned short insn = *(unsigned short *) regs->pc;
++	unsigned short finsn;
++	unsigned long nextpc;
++	int nib[4] = {
++		(insn >> 12) & 0xf,
++		(insn >> 8) & 0xf,
++		(insn >> 4) & 0xf,
++		insn & 0xf};
++
++	if (nib[0] == 0xb ||
++	    (nib[0] == 0x4 && nib[2] == 0x0 && nib[3] == 0xb)) /* bsr & jsr */
++		regs->pr = regs->pc + 4;
++	if (nib[0] == 0xa || nib[0] == 0xb) { /* bra & bsr */
++		nextpc = regs->pc + 4 + ((short) ((insn & 0xfff) << 4) >> 3);
++		finsn = *(unsigned short *) (regs->pc + 2);
++	} else if (nib[0] == 0x8 && nib[1] == 0xd) { /* bt/s */
++		if (regs->sr & 1)
++			nextpc = regs->pc + 4 + ((char) (insn & 0xff) << 1);
++		else
++			nextpc = regs->pc + 4;
++		finsn = *(unsigned short *) (regs->pc + 2);
++	} else if (nib[0] == 0x8 && nib[1] == 0xf) { /* bf/s */
++		if (regs->sr & 1)
++			nextpc = regs->pc + 4;
++		else
++			nextpc = regs->pc + 4 + ((char) (insn & 0xff) << 1);
++		finsn = *(unsigned short *) (regs->pc + 2);
++	} else if (nib[0] == 0x4 && nib[3] == 0xb &&
++		 (nib[2] == 0x0 || nib[2] == 0x2)) { /* jmp & jsr */
++		nextpc = regs->regs[nib[1]];
++		finsn = *(unsigned short *) (regs->pc + 2);
++	} else if (nib[0] == 0x0 && nib[3] == 0x3 &&
++		 (nib[2] == 0x0 || nib[2] == 0x2)) { /* braf & bsrf */
++		nextpc = regs->pc + 4 + regs->regs[nib[1]];
++		finsn = *(unsigned short *) (regs->pc + 2);
++	} else if (insn == 0x000b) { /* rts */
++		nextpc = regs->pr;
++		finsn = *(unsigned short *) (regs->pc + 2);
++	} else {
++		nextpc = regs->pc + 2;
++		finsn = insn;
++	}
++
++#define FPSCR_FPU_ERROR (1 << 17)
++
++	if ((finsn & 0xf1ff) == 0xf0ad) { /* fcnvsd */
++		struct task_struct *tsk = current;
++
++		if ((tsk->thread.fpu.hard.fpscr & FPSCR_FPU_ERROR)) {
++			/* FPU error */
++			denormal_to_double (&tsk->thread.fpu.hard,
++					    (finsn >> 8) & 0xf);
++		} else
++			return 0;
++
++		regs->pc = nextpc;
++		return 1;
++	} else if ((finsn & 0xf00f) == 0xf002) { /* fmul */
++		struct task_struct *tsk = current;
++		int fpscr;
++		int n, m, prec;
++		unsigned int hx, hy;
++
++		n = (finsn >> 8) & 0xf;
++		m = (finsn >> 4) & 0xf;
++		hx = tsk->thread.fpu.hard.fp_regs[n];
++		hy = tsk->thread.fpu.hard.fp_regs[m];
++		fpscr = tsk->thread.fpu.hard.fpscr;
++		prec = fpscr & (1 << 19);
++
++		if ((fpscr & FPSCR_FPU_ERROR)
++		     && (prec && ((hx & 0x7fffffff) < 0x00100000
++				   || (hy & 0x7fffffff) < 0x00100000))) {
++			long long llx, lly;
++
++			/* FPU error because of denormal */
++			llx = ((long long) hx << 32)
++			       | tsk->thread.fpu.hard.fp_regs[n+1];
++			lly = ((long long) hy << 32)
++			       | tsk->thread.fpu.hard.fp_regs[m+1];
++			if ((hx & 0x7fffffff) >= 0x00100000)
++				llx = denormal_muld(lly, llx);
++			else
++				llx = denormal_muld(llx, lly);
++			tsk->thread.fpu.hard.fp_regs[n] = llx >> 32;
++			tsk->thread.fpu.hard.fp_regs[n+1] = llx & 0xffffffff;
++		} else if ((fpscr & FPSCR_FPU_ERROR)
++		     && (!prec && ((hx & 0x7fffffff) < 0x00800000
++				   || (hy & 0x7fffffff) < 0x00800000))) {
++			/* FPU error because of denormal */
++			if ((hx & 0x7fffffff) >= 0x00800000)
++				hx = denormal_mulf(hy, hx);
++			else
++				hx = denormal_mulf(hx, hy);
++			tsk->thread.fpu.hard.fp_regs[n] = hx;
++		} else
++			return 0;
++
++		regs->pc = nextpc;
++		return 1;
++	} else if ((finsn & 0xf00e) == 0xf000) { /* fadd, fsub */
++		struct task_struct *tsk = current;
++		int fpscr;
++		int n, m, prec;
++		unsigned int hx, hy;
++
++		n = (finsn >> 8) & 0xf;
++		m = (finsn >> 4) & 0xf;
++		hx = tsk->thread.fpu.hard.fp_regs[n];
++		hy = tsk->thread.fpu.hard.fp_regs[m];
++		fpscr = tsk->thread.fpu.hard.fpscr;
++		prec = fpscr & (1 << 19);
++
++		if ((fpscr & FPSCR_FPU_ERROR)
++		     && (prec && ((hx & 0x7fffffff) < 0x00100000
++				   || (hy & 0x7fffffff) < 0x00100000))) {
++			long long llx, lly;
++
++			/* FPU error because of denormal */
++			llx = ((long long) hx << 32)
++			       | tsk->thread.fpu.hard.fp_regs[n+1];
++			lly = ((long long) hy << 32)
++			       | tsk->thread.fpu.hard.fp_regs[m+1];
++			if ((finsn & 0xf00f) == 0xf000)
++				llx = denormal_addd(llx, lly);
++			else
++				llx = denormal_addd(llx, lly ^ (1LL << 63));
++			tsk->thread.fpu.hard.fp_regs[n] = llx >> 32;
++			tsk->thread.fpu.hard.fp_regs[n+1] = llx & 0xffffffff;
++		} else if ((fpscr & FPSCR_FPU_ERROR)
++		     && (!prec && ((hx & 0x7fffffff) < 0x00800000
++				   || (hy & 0x7fffffff) < 0x00800000))) {
++			/* FPU error because of denormal */
++			if ((finsn & 0xf00f) == 0xf000)
++				hx = denormal_addf(hx, hy);
++			else
++				hx = denormal_addf(hx, hy ^ 0x80000000);
++			tsk->thread.fpu.hard.fp_regs[n] = hx;
++		} else
++			return 0;
++
++		regs->pc = nextpc;
++		return 1;
++	}
++
++	return 0;
++}
++
++BUILD_TRAP_HANDLER(fpu_error)
++{
++	struct task_struct *tsk = current;
++	TRAP_HANDLER_DECL;
++
++	save_fpu(tsk, regs);
++	if (ieee_fpe_handler(regs)) {
++		tsk->thread.fpu.hard.fpscr &=
++			~(FPSCR_CAUSE_MASK | FPSCR_FLAG_MASK);
++		grab_fpu(regs);
++		restore_fpu(tsk);
++		set_tsk_thread_flag(tsk, TIF_USEDFPU);
++		return;
++	}
++
++	force_sig(SIGFPE, tsk);
++}
++
++BUILD_TRAP_HANDLER(fpu_state_restore)
++{
++	struct task_struct *tsk = current;
++	TRAP_HANDLER_DECL;
++
++	grab_fpu(regs);
++	if (!user_mode(regs)) {
++		printk(KERN_ERR "BUG: FPU is used in kernel mode.\n");
++		return;
++	}
++
++	if (used_math()) {
++		/* Using the FPU again.  */
++		restore_fpu(tsk);
++	} else	{
++		/* First time FPU user.  */
++		fpu_init();
++		set_used_math();
++	}
++	set_tsk_thread_flag(tsk, TIF_USEDFPU);
++}
+diff --git a/arch/sh/kernel/cpu/sh2a/probe.c b/arch/sh/kernel/cpu/sh2a/probe.c
+index 6d02465..6910e26 100644
+--- a/arch/sh/kernel/cpu/sh2a/probe.c
++++ b/arch/sh/kernel/cpu/sh2a/probe.c
+@@ -3,25 +3,36 @@
+  *
+  * CPU Subtype Probing for SH-2A.
+  *
+- * Copyright (C) 2004, 2005 Paul Mundt
++ * Copyright (C) 2004 - 2007  Paul Mundt
+  *
+  * This file is subject to the terms and conditions of the GNU General Public
+  * License.  See the file "COPYING" in the main directory of this archive
+  * for more details.
+  */
+-
+ #include <linux/init.h>
+ #include <asm/processor.h>
+ #include <asm/cache.h>
+ 
+ int __init detect_cpu_and_cache_system(void)
+ {
+-	/* Just SH7206 for now .. */
+-	boot_cpu_data.type			= CPU_SH7206;
++	/* All SH-2A CPUs have support for 16 and 32-bit opcodes.. */
+ 	boot_cpu_data.flags			|= CPU_HAS_OP32;
+ 
++#if defined(CONFIG_CPU_SUBTYPE_SH7203)
++	boot_cpu_data.type			= CPU_SH7203;
++	/* SH7203 has an FPU.. */
++	boot_cpu_data.flags			|= CPU_HAS_FPU;
++#elif defined(CONFIG_CPU_SUBTYPE_SH7263)
++	boot_cpu_data.type			= CPU_SH7263;
++	boot_cpu_data.flags			|= CPU_HAS_FPU;
++#elif defined(CONFIG_CPU_SUBTYPE_SH7206)
++	boot_cpu_data.type			= CPU_SH7206;
++	/* While SH7206 has a DSP.. */
++	boot_cpu_data.flags			|= CPU_HAS_DSP;
++#endif
++
+ 	boot_cpu_data.dcache.ways		= 4;
+-	boot_cpu_data.dcache.way_incr	= (1 << 11);
++	boot_cpu_data.dcache.way_incr		= (1 << 11);
+ 	boot_cpu_data.dcache.sets		= 128;
+ 	boot_cpu_data.dcache.entry_shift	= 4;
+ 	boot_cpu_data.dcache.linesz		= L1_CACHE_BYTES;
+@@ -37,4 +48,3 @@ int __init detect_cpu_and_cache_system(void)
+ 
+ 	return 0;
+ }
+-
+diff --git a/arch/sh/kernel/cpu/sh2a/setup-sh7203.c b/arch/sh/kernel/cpu/sh2a/setup-sh7203.c
+new file mode 100644
+index 0000000..db6ef5c
+--- /dev/null
++++ b/arch/sh/kernel/cpu/sh2a/setup-sh7203.c
+@@ -0,0 +1,319 @@
++/*
++ * SH7203 and SH7263 Setup
++ *
++ *  Copyright (C) 2007  Paul Mundt
++ *
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License.  See the file "COPYING" in the main directory of this archive
++ * for more details.
++ */
++#include <linux/platform_device.h>
++#include <linux/init.h>
++#include <linux/serial.h>
++#include <asm/sci.h>
++
++enum {
++	UNUSED = 0,
++
++	/* interrupt sources */
++	IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7,
++	PINT0, PINT1, PINT2, PINT3, PINT4, PINT5, PINT6, PINT7,
++	DMAC0_DEI, DMAC0_HEI, DMAC1_DEI, DMAC1_HEI,
++	DMAC2_DEI, DMAC2_HEI, DMAC3_DEI, DMAC3_HEI,
++	DMAC4_DEI, DMAC4_HEI, DMAC5_DEI, DMAC5_HEI,
++	DMAC6_DEI, DMAC6_HEI, DMAC7_DEI, DMAC7_HEI,
++	USB, LCDC, CMT0, CMT1, BSC, WDT,
++	MTU2_TGI0A, MTU2_TGI0B, MTU2_TGI0C, MTU2_TGI0D,
++	MTU2_TCI0V, MTU2_TGI0E, MTU2_TGI0F,
++	MTU2_TGI1A, MTU2_TGI1B, MTU2_TCI1V, MTU2_TCI1U,
++	MTU2_TGI2A, MTU2_TGI2B, MTU2_TCI2V, MTU2_TCI2U,
++	MTU2_TGI3A, MTU2_TGI3B, MTU2_TGI3C, MTU2_TGI3D, MTU2_TCI3V,
++	MTU2_TGI4A, MTU2_TGI4B, MTU2_TGI4C, MTU2_TGI4D, MTU2_TCI4V,
++	ADC_ADI,
++	IIC30_STPI, IIC30_NAKI, IIC30_RXI, IIC30_TXI, IIC30_TEI,
++	IIC31_STPI, IIC31_NAKI, IIC31_RXI, IIC31_TXI, IIC31_TEI,
++	IIC32_STPI, IIC32_NAKI, IIC32_RXI, IIC32_TXI, IIC32_TEI,
++	IIC33_STPI, IIC33_NAKI, IIC33_RXI, IIC33_TXI, IIC33_TEI,
++	SCIF0_BRI, SCIF0_ERI, SCIF0_RXI, SCIF0_TXI,
++	SCIF1_BRI, SCIF1_ERI, SCIF1_RXI, SCIF1_TXI,
++	SCIF2_BRI, SCIF2_ERI, SCIF2_RXI, SCIF2_TXI,
++	SCIF3_BRI, SCIF3_ERI, SCIF3_RXI, SCIF3_TXI,
++	SSU0_SSERI, SSU0_SSRXI, SSU0_SSTXI,
++	SSU1_SSERI, SSU1_SSRXI, SSU1_SSTXI,
++	SSI0_SSII, SSI1_SSII, SSI2_SSII, SSI3_SSII,
++
++	/* ROM-DEC, SDHI, SRC, and IEB are SH7263 specific */
++	ROMDEC_ISY, ROMDEC_IERR, ROMDEC_IARG, ROMDEC_ISEC, ROMDEC_IBUF,
++	ROMDEC_IREADY,
++
++	FLCTL_FLSTEI, FLCTL_FLTENDI, FLCTL_FLTREQ0I, FLCTL_FLTREQ1I,
++
++	SDHI3, SDHI0, SDHI1,
++
++	RTC_ARM, RTC_PRD, RTC_CUP,
++	RCAN0_ERS, RCAN0_OVR, RCAN0_RM0, RCAN0_RM1, RCAN0_SLE,
++	RCAN1_ERS, RCAN1_OVR, RCAN1_RM0, RCAN1_RM1, RCAN1_SLE,
++
++	SRC_OVF, SRC_ODFI, SRC_IDEI, IEBI,
++
++	/* interrupt groups */
++	PINT, DMAC0, DMAC1, DMAC2, DMAC3, DMAC4, DMAC5, DMAC6, DMAC7,
++	MTU0_ABCD, MTU0_VEF, MTU1_AB, MTU1_VU, MTU2_AB, MTU2_VU,
++	MTU3_ABCD, MTU4_ABCD,
++	IIC30, IIC31, IIC32, IIC33, SCIF0, SCIF1, SCIF2, SCIF3,
++	SSU0, SSU1, ROMDEC, SDHI, FLCTL, RTC, RCAN0, RCAN1, SRC
++};
++
++static struct intc_vect vectors[] __initdata = {
++	INTC_IRQ(IRQ0, 64), INTC_IRQ(IRQ1, 65),
++	INTC_IRQ(IRQ2, 66), INTC_IRQ(IRQ3, 67),
++	INTC_IRQ(IRQ4, 68), INTC_IRQ(IRQ5, 69),
++	INTC_IRQ(IRQ6, 70), INTC_IRQ(IRQ7, 71),
++	INTC_IRQ(PINT0, 80), INTC_IRQ(PINT1, 81),
++	INTC_IRQ(PINT2, 82), INTC_IRQ(PINT3, 83),
++	INTC_IRQ(PINT4, 84), INTC_IRQ(PINT5, 85),
++	INTC_IRQ(PINT6, 86), INTC_IRQ(PINT7, 87),
++	INTC_IRQ(DMAC0_DEI, 108), INTC_IRQ(DMAC0_HEI, 109),
++	INTC_IRQ(DMAC1_DEI, 112), INTC_IRQ(DMAC1_HEI, 113),
++	INTC_IRQ(DMAC2_DEI, 116), INTC_IRQ(DMAC2_HEI, 117),
++	INTC_IRQ(DMAC3_DEI, 120), INTC_IRQ(DMAC3_HEI, 121),
++	INTC_IRQ(DMAC4_DEI, 124), INTC_IRQ(DMAC4_HEI, 125),
++	INTC_IRQ(DMAC5_DEI, 128), INTC_IRQ(DMAC5_HEI, 129),
++	INTC_IRQ(DMAC6_DEI, 132), INTC_IRQ(DMAC6_HEI, 133),
++	INTC_IRQ(DMAC7_DEI, 136), INTC_IRQ(DMAC7_HEI, 137),
++	INTC_IRQ(USB, 140), INTC_IRQ(LCDC, 141),
++	INTC_IRQ(CMT0, 142), INTC_IRQ(CMT1, 143),
++	INTC_IRQ(BSC, 144), INTC_IRQ(WDT, 145),
++	INTC_IRQ(MTU2_TGI0A, 146), INTC_IRQ(MTU2_TGI0B, 147),
++	INTC_IRQ(MTU2_TGI0C, 148), INTC_IRQ(MTU2_TGI0D, 149),
++	INTC_IRQ(MTU2_TCI0V, 150),
++	INTC_IRQ(MTU2_TGI0E, 151), INTC_IRQ(MTU2_TGI0F, 152),
++	INTC_IRQ(MTU2_TGI1A, 153), INTC_IRQ(MTU2_TGI1B, 154),
++	INTC_IRQ(MTU2_TCI1V, 155), INTC_IRQ(MTU2_TCI1U, 156),
++	INTC_IRQ(MTU2_TGI2A, 157), INTC_IRQ(MTU2_TGI2B, 158),
++	INTC_IRQ(MTU2_TCI2V, 159), INTC_IRQ(MTU2_TCI2U, 160),
++	INTC_IRQ(MTU2_TGI3A, 161), INTC_IRQ(MTU2_TGI3B, 162),
++	INTC_IRQ(MTU2_TGI3C, 163), INTC_IRQ(MTU2_TGI3D, 164),
++	INTC_IRQ(MTU2_TCI3V, 165),
++	INTC_IRQ(MTU2_TGI4A, 166), INTC_IRQ(MTU2_TGI4B, 167),
++	INTC_IRQ(MTU2_TGI4C, 168), INTC_IRQ(MTU2_TGI4D, 169),
++	INTC_IRQ(MTU2_TCI4V, 170),
++	INTC_IRQ(ADC_ADI, 171),
++	INTC_IRQ(IIC30_STPI, 172), INTC_IRQ(IIC30_NAKI, 173),
++	INTC_IRQ(IIC30_RXI, 174), INTC_IRQ(IIC30_TXI, 175),
++	INTC_IRQ(IIC30_TEI, 176),
++	INTC_IRQ(IIC31_STPI, 177), INTC_IRQ(IIC31_NAKI, 178),
++	INTC_IRQ(IIC31_RXI, 179), INTC_IRQ(IIC31_TXI, 180),
++	INTC_IRQ(IIC31_TEI, 181),
++	INTC_IRQ(IIC32_STPI, 182), INTC_IRQ(IIC32_NAKI, 183),
++	INTC_IRQ(IIC32_RXI, 184), INTC_IRQ(IIC32_TXI, 185),
++	INTC_IRQ(IIC32_TEI, 186),
++	INTC_IRQ(IIC33_STPI, 187), INTC_IRQ(IIC33_NAKI, 188),
++	INTC_IRQ(IIC33_RXI, 189), INTC_IRQ(IIC33_TXI, 190),
++	INTC_IRQ(IIC33_TEI, 191),
++	INTC_IRQ(SCIF0_BRI, 192), INTC_IRQ(SCIF0_ERI, 193),
++	INTC_IRQ(SCIF0_RXI, 194), INTC_IRQ(SCIF0_TXI, 195),
++	INTC_IRQ(SCIF1_BRI, 196), INTC_IRQ(SCIF1_ERI, 197),
++	INTC_IRQ(SCIF1_RXI, 198), INTC_IRQ(SCIF1_TXI, 199),
++	INTC_IRQ(SCIF2_BRI, 200), INTC_IRQ(SCIF2_ERI, 201),
++	INTC_IRQ(SCIF2_RXI, 202), INTC_IRQ(SCIF2_TXI, 203),
++	INTC_IRQ(SCIF3_BRI, 204), INTC_IRQ(SCIF3_ERI, 205),
++	INTC_IRQ(SCIF3_RXI, 206), INTC_IRQ(SCIF3_TXI, 207),
++	INTC_IRQ(SSU0_SSERI, 208), INTC_IRQ(SSU0_SSRXI, 209),
++	INTC_IRQ(SSU0_SSTXI, 210),
++	INTC_IRQ(SSU1_SSERI, 211), INTC_IRQ(SSU1_SSRXI, 212),
++	INTC_IRQ(SSU1_SSTXI, 213),
++	INTC_IRQ(SSI0_SSII, 214), INTC_IRQ(SSI1_SSII, 215),
++	INTC_IRQ(SSI2_SSII, 216), INTC_IRQ(SSI3_SSII, 217),
++	INTC_IRQ(FLCTL_FLSTEI, 224), INTC_IRQ(FLCTL_FLTENDI, 225),
++	INTC_IRQ(FLCTL_FLTREQ0I, 226), INTC_IRQ(FLCTL_FLTREQ1I, 227),
++	INTC_IRQ(RTC_ARM, 231), INTC_IRQ(RTC_PRD, 232),
++	INTC_IRQ(RTC_CUP, 233),
++	INTC_IRQ(RCAN0_ERS, 234), INTC_IRQ(RCAN0_OVR, 235),
++	INTC_IRQ(RCAN0_RM0, 236), INTC_IRQ(RCAN0_RM1, 237),
++	INTC_IRQ(RCAN0_SLE, 238),
++	INTC_IRQ(RCAN1_ERS, 239), INTC_IRQ(RCAN1_OVR, 240),
++	INTC_IRQ(RCAN1_RM0, 241), INTC_IRQ(RCAN1_RM1, 242),
++	INTC_IRQ(RCAN1_SLE, 243),
++
++	/* SH7263-specific trash */
++#ifdef CONFIG_CPU_SUBTYPE_SH7263
++	INTC_IRQ(ROMDEC_ISY, 218), INTC_IRQ(ROMDEC_IERR, 219),
++	INTC_IRQ(ROMDEC_IARG, 220), INTC_IRQ(ROMDEC_ISEC, 221),
++	INTC_IRQ(ROMDEC_IBUF, 222), INTC_IRQ(ROMDEC_IREADY, 223),
++
++	INTC_IRQ(SDHI3, 228), INTC_IRQ(SDHI0, 229), INTC_IRQ(SDHI1, 230),
++
++	INTC_IRQ(SRC_OVF, 244), INTC_IRQ(SRC_ODFI, 245),
++	INTC_IRQ(SRC_IDEI, 246),
++
++	INTC_IRQ(IEBI, 247),
++#endif
++};
++
++static struct intc_group groups[] __initdata = {
++	INTC_GROUP(PINT, PINT0, PINT1, PINT2, PINT3,
++		   PINT4, PINT5, PINT6, PINT7),
++	INTC_GROUP(DMAC0, DMAC0_DEI, DMAC0_HEI),
++	INTC_GROUP(DMAC1, DMAC1_DEI, DMAC1_HEI),
++	INTC_GROUP(DMAC2, DMAC2_DEI, DMAC2_HEI),
++	INTC_GROUP(DMAC3, DMAC3_DEI, DMAC3_HEI),
++	INTC_GROUP(DMAC4, DMAC4_DEI, DMAC4_HEI),
++	INTC_GROUP(DMAC5, DMAC5_DEI, DMAC5_HEI),
++	INTC_GROUP(DMAC6, DMAC6_DEI, DMAC6_HEI),
++	INTC_GROUP(DMAC7, DMAC7_DEI, DMAC7_HEI),
++	INTC_GROUP(MTU0_ABCD, MTU2_TGI0A, MTU2_TGI0B, MTU2_TGI0C, MTU2_TGI0D),
++	INTC_GROUP(MTU0_VEF, MTU2_TCI0V, MTU2_TGI0E, MTU2_TGI0F),
++	INTC_GROUP(MTU1_AB, MTU2_TGI1A, MTU2_TGI1B),
++	INTC_GROUP(MTU1_VU, MTU2_TCI1V, MTU2_TCI1U),
++	INTC_GROUP(MTU2_AB, MTU2_TGI2A, MTU2_TGI2B),
++	INTC_GROUP(MTU2_VU, MTU2_TCI2V, MTU2_TCI2U),
++	INTC_GROUP(MTU3_ABCD, MTU2_TGI3A, MTU2_TGI3B, MTU2_TGI3C, MTU2_TGI3D),
++	INTC_GROUP(MTU4_ABCD, MTU2_TGI4A, MTU2_TGI4B, MTU2_TGI4C, MTU2_TGI4D),
++	INTC_GROUP(IIC30, IIC30_STPI, IIC30_NAKI, IIC30_RXI, IIC30_TXI,
++		   IIC30_TEI),
++	INTC_GROUP(IIC31, IIC31_STPI, IIC31_NAKI, IIC31_RXI, IIC31_TXI,
++		   IIC31_TEI),
++	INTC_GROUP(IIC32, IIC32_STPI, IIC32_NAKI, IIC32_RXI, IIC32_TXI,
++		   IIC32_TEI),
++	INTC_GROUP(IIC33, IIC33_STPI, IIC33_NAKI, IIC33_RXI, IIC33_TXI,
++		   IIC33_TEI),
++	INTC_GROUP(SCIF0, SCIF0_BRI, SCIF0_ERI, SCIF0_RXI, SCIF0_TXI),
++	INTC_GROUP(SCIF1, SCIF1_BRI, SCIF1_ERI, SCIF1_RXI, SCIF1_TXI),
++	INTC_GROUP(SCIF2, SCIF2_BRI, SCIF2_ERI, SCIF2_RXI, SCIF2_TXI),
++	INTC_GROUP(SCIF3, SCIF3_BRI, SCIF3_ERI, SCIF3_RXI, SCIF3_TXI),
++	INTC_GROUP(SSU0, SSU0_SSERI, SSU0_SSRXI, SSU0_SSTXI),
++	INTC_GROUP(SSU1, SSU1_SSERI, SSU1_SSRXI, SSU1_SSTXI),
++	INTC_GROUP(FLCTL, FLCTL_FLSTEI, FLCTL_FLTENDI, FLCTL_FLTREQ0I,
++		   FLCTL_FLTREQ1I),
++	INTC_GROUP(RTC, RTC_ARM, RTC_PRD, RTC_CUP),
++	INTC_GROUP(RCAN0, RCAN0_ERS, RCAN0_OVR, RCAN0_RM0, RCAN0_RM1,
++		   RCAN0_SLE),
++	INTC_GROUP(RCAN1, RCAN1_ERS, RCAN1_OVR, RCAN1_RM0, RCAN1_RM1,
++		   RCAN1_SLE),
++
++#ifdef CONFIG_CPU_SUBTYPE_SH7263
++	INTC_GROUP(ROMDEC, ROMDEC_ISY, ROMDEC_IERR, ROMDEC_IARG,
++		   ROMDEC_ISEC, ROMDEC_IBUF, ROMDEC_IREADY),
++	INTC_GROUP(SDHI, SDHI3, SDHI0, SDHI1),
++	INTC_GROUP(SRC, SRC_OVF, SRC_ODFI, SRC_IDEI),
++#endif
++};
++
++static struct intc_prio_reg prio_registers[] __initdata = {
++	{ 0xfffe0818, 0, 16, 4, /* IPR01 */ { IRQ0, IRQ1, IRQ2, IRQ3 } },
++	{ 0xfffe081a, 0, 16, 4, /* IPR02 */ { IRQ4, IRQ5, IRQ6, IRQ7 } },
++	{ 0xfffe0820, 0, 16, 4, /* IPR05 */ { PINT, 0, 0, 0 } },
++	{ 0xfffe0c00, 0, 16, 4, /* IPR06 */ { DMAC0, DMAC1, DMAC2, DMAC3 } },
++	{ 0xfffe0c02, 0, 16, 4, /* IPR07 */ { DMAC4, DMAC5, DMAC6, DMAC7 } },
++	{ 0xfffe0c04, 0, 16, 4, /* IPR08 */ { USB, LCDC, CMT0, CMT1 } },
++	{ 0xfffe0c06, 0, 16, 4, /* IPR09 */ { BSC, WDT, MTU0_ABCD, MTU0_VEF } },
++	{ 0xfffe0c08, 0, 16, 4, /* IPR10 */ { MTU1_AB, MTU1_VU, MTU2_AB,
++					      MTU2_VU } },
++	{ 0xfffe0c0a, 0, 16, 4, /* IPR11 */ { MTU3_ABCD, MTU2_TCI3V, MTU4_ABCD,
++					      MTU2_TCI4V } },
++	{ 0xfffe0c0c, 0, 16, 4, /* IPR12 */ { ADC_ADI, IIC30, IIC31, IIC32 } },
++	{ 0xfffe0c0e, 0, 16, 4, /* IPR13 */ { IIC33, SCIF0, SCIF1, SCIF2 } },
++	{ 0xfffe0c10, 0, 16, 4, /* IPR14 */ { SCIF3, SSU0, SSU1, SSI0_SSII } },
++#ifdef CONFIG_CPU_SUBTYPE_SH7203
++	{ 0xfffe0c12, 0, 16, 4, /* IPR15 */ { SSI1_SSII, SSI2_SSII,
++					      SSI3_SSII, 0 } },
++	{ 0xfffe0c14, 0, 16, 4, /* IPR16 */ { FLCTL, 0, RTC, RCAN0 } },
++	{ 0xfffe0c16, 0, 16, 4, /* IPR17 */ { RCAN1, 0, 0, 0 } },
++#else
++	{ 0xfffe0c12, 0, 16, 4, /* IPR15 */ { SSI1_SSII, SSI2_SSII,
++					      SSI3_SSII, ROMDEC } },
++	{ 0xfffe0c14, 0, 16, 4, /* IPR16 */ { FLCTL, SDHI, RTC, RCAN0 } },
++	{ 0xfffe0c16, 0, 16, 4, /* IPR17 */ { RCAN1, SRC, IEBI, 0 } },
++#endif
++};
++
++static struct intc_mask_reg mask_registers[] __initdata = {
++	{ 0xfffe0808, 0, 16, /* PINTER */
++	  { 0, 0, 0, 0, 0, 0, 0, 0,
++	    PINT7, PINT6, PINT5, PINT4, PINT3, PINT2, PINT1, PINT0 } },
++};
++
++static DECLARE_INTC_DESC(intc_desc, "sh7203", vectors, groups,
++			 mask_registers, prio_registers, NULL);
++
++static struct plat_sci_port sci_platform_data[] = {
++	{
++		.mapbase	= 0xfffe8000,
++		.flags		= UPF_BOOT_AUTOCONF,
++		.type		= PORT_SCIF,
++		.irqs		=  { 193, 194, 195, 192 },
++	}, {
++		.mapbase	= 0xfffe8800,
++		.flags		= UPF_BOOT_AUTOCONF,
++		.type		= PORT_SCIF,
++		.irqs		=  { 197, 198, 199, 196 },
++	}, {
++		.mapbase	= 0xfffe9000,
++		.flags		= UPF_BOOT_AUTOCONF,
++		.type		= PORT_SCIF,
++		.irqs		=  { 201, 202, 203, 200 },
++	}, {
++		.mapbase	= 0xfffe9800,
++		.flags		= UPF_BOOT_AUTOCONF,
++		.type		= PORT_SCIF,
++		.irqs		=  { 205, 206, 207, 204 },
++	}, {
++		.flags = 0,
++	}
++};
++
++static struct platform_device sci_device = {
++	.name		= "sh-sci",
++	.id		= -1,
++	.dev		= {
++		.platform_data	= sci_platform_data,
++	},
++};
++
++static struct resource rtc_resources[] = {
++	[0] = {
++		.start	= 0xffff2000,
++		.end	= 0xffff2000 + 0x58 - 1,
++		.flags	= IORESOURCE_IO,
++	},
++	[1] = {
++		/* Period IRQ */
++		.start	= 232,
++		.flags	= IORESOURCE_IRQ,
++	},
++	[2] = {
++		/* Carry IRQ */
++		.start	= 233,
++		.flags	= IORESOURCE_IRQ,
++	},
++	[3] = {
++		/* Alarm IRQ */
++		.start	= 231,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device rtc_device = {
++	.name		= "sh-rtc",
++	.id		= -1,
++	.num_resources	= ARRAY_SIZE(rtc_resources),
++	.resource	= rtc_resources,
++};
++
++static struct platform_device *sh7203_devices[] __initdata = {
++	&sci_device,
++	&rtc_device,
++};
++
++static int __init sh7203_devices_setup(void)
++{
++	return platform_add_devices(sh7203_devices,
++				    ARRAY_SIZE(sh7203_devices));
++}
++__initcall(sh7203_devices_setup);
++
++void __init plat_irq_setup(void)
++{
++	register_intc_controller(&intc_desc);
++}
+diff --git a/arch/sh/kernel/cpu/sh2a/setup-sh7206.c b/arch/sh/kernel/cpu/sh2a/setup-sh7206.c
+index bd745aa..a564425 100644
+--- a/arch/sh/kernel/cpu/sh2a/setup-sh7206.c
++++ b/arch/sh/kernel/cpu/sh2a/setup-sh7206.c
+@@ -167,7 +167,7 @@ static struct intc_mask_reg mask_registers[] __initdata = {
+ };
+ 
+ static DECLARE_INTC_DESC(intc_desc, "sh7206", vectors, groups,
+-			 NULL, mask_registers, prio_registers, NULL);
++			 mask_registers, prio_registers, NULL);
+ 
+ static struct plat_sci_port sci_platform_data[] = {
+ 	{
+diff --git a/arch/sh/kernel/cpu/sh3/Makefile b/arch/sh/kernel/cpu/sh3/Makefile
+index 646eb69..3ae4d91 100644
+--- a/arch/sh/kernel/cpu/sh3/Makefile
++++ b/arch/sh/kernel/cpu/sh3/Makefile
+@@ -13,6 +13,7 @@ obj-$(CONFIG_CPU_SUBTYPE_SH7709)	+= setup-sh770x.o
+ obj-$(CONFIG_CPU_SUBTYPE_SH7710)	+= setup-sh7710.o
+ obj-$(CONFIG_CPU_SUBTYPE_SH7712)	+= setup-sh7710.o
+ obj-$(CONFIG_CPU_SUBTYPE_SH7720)	+= setup-sh7720.o
++obj-$(CONFIG_CPU_SUBTYPE_SH7721)	+= setup-sh7720.o
+ 
+ # Primary on-chip clocks (common)
+ clock-$(CONFIG_CPU_SH3)			:= clock-sh3.o
+@@ -21,5 +22,6 @@ clock-$(CONFIG_CPU_SUBTYPE_SH7706)	:= clock-sh7706.o
+ clock-$(CONFIG_CPU_SUBTYPE_SH7709)	:= clock-sh7709.o
+ clock-$(CONFIG_CPU_SUBTYPE_SH7710)	:= clock-sh7710.o
+ clock-$(CONFIG_CPU_SUBTYPE_SH7720)	:= clock-sh7710.o
++clock-$(CONFIG_CPU_SUBTYPE_SH7712)	:= clock-sh7712.o
+ 
+ obj-y	+= $(clock-y)
+diff --git a/arch/sh/kernel/cpu/sh3/clock-sh7712.c b/arch/sh/kernel/cpu/sh3/clock-sh7712.c
+new file mode 100644
+index 0000000..54f54df
+--- /dev/null
++++ b/arch/sh/kernel/cpu/sh3/clock-sh7712.c
+@@ -0,0 +1,71 @@
++/*
++ * arch/sh/kernel/cpu/sh3/clock-sh7712.c
++ *
++ * SH7712 support for the clock framework
++ *
++ *  Copyright (C) 2007  Andrew Murray <amurray at mpc-data.co.uk>
++ *
++ * Based on arch/sh/kernel/cpu/sh3/clock-sh3.c
++ *  Copyright (C) 2005  Paul Mundt
++ *
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License.  See the file "COPYING" in the main directory of this archive
++ * for more details.
++ */
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <asm/clock.h>
++#include <asm/freq.h>
++#include <asm/io.h>
++
++static int multipliers[] = { 1, 2, 3 };
++static int divisors[]    = { 1, 2, 3, 4, 6 };
++
++static void master_clk_init(struct clk *clk)
++{
++	int frqcr = ctrl_inw(FRQCR);
++	int idx = (frqcr & 0x0300) >> 8;
++
++	clk->rate *= multipliers[idx];
++}
++
++static struct clk_ops sh7712_master_clk_ops = {
++	.init		= master_clk_init,
++};
++
++static void module_clk_recalc(struct clk *clk)
++{
++	int frqcr = ctrl_inw(FRQCR);
++	int idx = frqcr & 0x0007;
++
++	clk->rate = clk->parent->rate / divisors[idx];
++}
++
++static struct clk_ops sh7712_module_clk_ops = {
++	.recalc		= module_clk_recalc,
++};
++
++static void cpu_clk_recalc(struct clk *clk)
++{
++	int frqcr = ctrl_inw(FRQCR);
++	int idx = (frqcr & 0x0030) >> 4;
++
++	clk->rate = clk->parent->rate / divisors[idx];
++}
++
++static struct clk_ops sh7712_cpu_clk_ops = {
++	.recalc		= cpu_clk_recalc,
++};
++
++static struct clk_ops *sh7712_clk_ops[] = {
++	&sh7712_master_clk_ops,
++	&sh7712_module_clk_ops,
++	&sh7712_cpu_clk_ops,
++};
++
++void __init arch_init_clk_ops(struct clk_ops **ops, int idx)
++{
++	if (idx < ARRAY_SIZE(sh7712_clk_ops))
++		*ops = sh7712_clk_ops[idx];
++}
++
+diff --git a/arch/sh/kernel/cpu/sh3/entry.S b/arch/sh/kernel/cpu/sh3/entry.S
+index 0d12a12..4004073 100644
+--- a/arch/sh/kernel/cpu/sh3/entry.S
++++ b/arch/sh/kernel/cpu/sh3/entry.S
+@@ -13,8 +13,9 @@
+ #include <linux/linkage.h>
+ #include <asm/asm-offsets.h>
+ #include <asm/thread_info.h>
+-#include <asm/cpu/mmu_context.h>
+ #include <asm/unistd.h>
++#include <asm/cpu/mmu_context.h>
++#include <asm/page.h>
+ 
+ ! NOTE:
+ ! GNU as (as of 2.9.1) changes bf/s into bt/s and bra, when the address
+@@ -409,6 +410,27 @@ ENTRY(handle_exception)
+ 	! Using k0, k1 for scratch registers (r0_bank1, r1_bank),
+ 	! save all registers onto stack.
+ 	!
++
++#ifdef CONFIG_GUSA
++	! Check for roll back gRB (User and Kernel)
++	mov	r15, k0
++	shll	k0
++	bf/s	1f
++	 shll	k0
++	bf/s	1f
++	 stc	spc, k1
++	stc	r0_bank, k0
++	cmp/hs	k0, k1		! test k1 (saved PC) >= k0 (saved r0)
++	bt/s	2f
++	 stc	r1_bank, k1
++
++	add	#-2, k0
++	add	r15, k0
++	ldc	k0, spc		! PC = saved r0 + r15 - 2
++2:	mov	k1, r15		! SP = r1
++1:
++#endif
++
+ 	stc	ssr, k0		! Is it from kernel space?
+ 	shll	k0		! Check MD bit (bit30) by shifting it into...
+ 	shll	k0		!       ...the T bit
+diff --git a/arch/sh/kernel/cpu/sh3/ex.S b/arch/sh/kernel/cpu/sh3/ex.S
+index b6abf38..11b6d9c 100644
+--- a/arch/sh/kernel/cpu/sh3/ex.S
++++ b/arch/sh/kernel/cpu/sh3/ex.S
+@@ -36,7 +36,7 @@ ENTRY(exception_handling_table)
+ 	.long	exception_error	! address error store	/* 100 */
+ #endif
+ #if defined(CONFIG_SH_FPU)
+-	.long	do_fpu_error		/* 120 */
++	.long	fpu_error_trap_handler	/* 120 */
+ #else
+ 	.long	exception_error		/* 120 */
+ #endif
+diff --git a/arch/sh/kernel/cpu/sh3/probe.c b/arch/sh/kernel/cpu/sh3/probe.c
+index bf579e0..fcc80bb 100644
+--- a/arch/sh/kernel/cpu/sh3/probe.c
++++ b/arch/sh/kernel/cpu/sh3/probe.c
+@@ -16,11 +16,11 @@
+ #include <asm/cache.h>
+ #include <asm/io.h>
+ 
+-int __init detect_cpu_and_cache_system(void)
++int __uses_jump_to_uncached detect_cpu_and_cache_system(void)
+ {
+ 	unsigned long addr0, addr1, data0, data1, data2, data3;
+ 
+-	jump_to_P2();
++	jump_to_uncached();
+ 	/*
+ 	 * Check if the entry shadows or not.
+ 	 * When shadowed, it's 128-entry system.
+@@ -48,7 +48,7 @@ int __init detect_cpu_and_cache_system(void)
+ 	ctrl_outl(data0&~SH_CACHE_VALID, addr0);
+ 	ctrl_outl(data2&~SH_CACHE_VALID, addr1);
+ 
+-	back_to_P1();
++	back_to_cached();
+ 
+ 	boot_cpu_data.dcache.ways		= 4;
+ 	boot_cpu_data.dcache.entry_shift	= 4;
+@@ -84,6 +84,9 @@ int __init detect_cpu_and_cache_system(void)
+ #if defined(CONFIG_CPU_SUBTYPE_SH7720)
+ 		boot_cpu_data.type = CPU_SH7720;
+ #endif
++#if defined(CONFIG_CPU_SUBTYPE_SH7721)
++		boot_cpu_data.type = CPU_SH7721;
++#endif
+ #if defined(CONFIG_CPU_SUBTYPE_SH7705)
+ 		boot_cpu_data.type = CPU_SH7705;
+ 
+diff --git a/arch/sh/kernel/cpu/sh3/setup-sh7705.c b/arch/sh/kernel/cpu/sh3/setup-sh7705.c
+index f6c65f2..dd0a20a 100644
+--- a/arch/sh/kernel/cpu/sh3/setup-sh7705.c
++++ b/arch/sh/kernel/cpu/sh3/setup-sh7705.c
+@@ -66,12 +66,6 @@ static struct intc_group groups[] __initdata = {
+ 	INTC_GROUP(SCIF2, SCIF2_ERI, SCIF2_RXI, SCIF2_TXI),
+ };
+ 
+-static struct intc_prio priorities[] __initdata = {
+-	INTC_PRIO(DMAC, 7),
+-	INTC_PRIO(SCIF2, 3),
+-	INTC_PRIO(SCIF0, 3),
+-};
+-
+ static struct intc_prio_reg prio_registers[] __initdata = {
+ 	{ 0xfffffee2, 0, 16, 4, /* IPRA */ { TMU0, TMU1, TMU2, RTC } },
+ 	{ 0xfffffee4, 0, 16, 4, /* IPRB */ { WDT, REF_RCMI, 0, 0 } },
+@@ -85,7 +79,7 @@ static struct intc_prio_reg prio_registers[] __initdata = {
+ };
+ 
+ static DECLARE_INTC_DESC(intc_desc, "sh7705", vectors, groups,
+-			 priorities, NULL, prio_registers, NULL);
++			 NULL, prio_registers, NULL);
+ 
+ static struct intc_vect vectors_irq[] __initdata = {
+ 	INTC_VECT(IRQ0, 0x600), INTC_VECT(IRQ1, 0x620),
+@@ -93,7 +87,7 @@ static struct intc_vect vectors_irq[] __initdata = {
+ };
+ 
+ static DECLARE_INTC_DESC(intc_desc_irq, "sh7705-irq", vectors_irq, NULL,
+-			 priorities, NULL, prio_registers, NULL);
++			 NULL, prio_registers, NULL);
+ 
+ static struct plat_sci_port sci_platform_data[] = {
+ 	{
+diff --git a/arch/sh/kernel/cpu/sh3/setup-sh770x.c b/arch/sh/kernel/cpu/sh3/setup-sh770x.c
+index 60b04b1..969804b 100644
+--- a/arch/sh/kernel/cpu/sh3/setup-sh770x.c
++++ b/arch/sh/kernel/cpu/sh3/setup-sh770x.c
+@@ -81,13 +81,6 @@ static struct intc_group groups[] __initdata = {
+ 	INTC_GROUP(SCIF2, SCIF2_ERI, SCIF2_RXI, SCIF2_BRI, SCIF2_TXI),
+ };
+ 
+-static struct intc_prio priorities[] __initdata = {
+-	INTC_PRIO(DMAC, 7),
+-	INTC_PRIO(SCI, 3),
+-	INTC_PRIO(SCIF2, 3),
+-	INTC_PRIO(SCIF0, 3),
+-};
+-
+ static struct intc_prio_reg prio_registers[] __initdata = {
+ 	{ 0xfffffee2, 0, 16, 4, /* IPRA */ { TMU0, TMU1, TMU2, RTC } },
+ 	{ 0xfffffee4, 0, 16, 4, /* IPRB */ { WDT, REF, SCI, 0 } },
+@@ -109,7 +102,7 @@ static struct intc_prio_reg prio_registers[] __initdata = {
+ };
+ 
+ static DECLARE_INTC_DESC(intc_desc, "sh770x", vectors, groups,
+-			 priorities, NULL, prio_registers, NULL);
++			 NULL, prio_registers, NULL);
+ 
+ #if defined(CONFIG_CPU_SUBTYPE_SH7706) || \
+     defined(CONFIG_CPU_SUBTYPE_SH7707) || \
+@@ -120,7 +113,7 @@ static struct intc_vect vectors_irq[] __initdata = {
+ };
+ 
+ static DECLARE_INTC_DESC(intc_desc_irq, "sh770x-irq", vectors_irq, NULL,
+-			 priorities, NULL, prio_registers, NULL);
++			 NULL, prio_registers, NULL);
+ #endif
+ 
+ static struct resource rtc_resources[] = {
+diff --git a/arch/sh/kernel/cpu/sh3/setup-sh7710.c b/arch/sh/kernel/cpu/sh3/setup-sh7710.c
+index 84e5629..0cc0e2b 100644
+--- a/arch/sh/kernel/cpu/sh3/setup-sh7710.c
++++ b/arch/sh/kernel/cpu/sh3/setup-sh7710.c
+@@ -73,18 +73,6 @@ static struct intc_group groups[] __initdata = {
+ 	INTC_GROUP(SIOF1, SIOF1_ERI, SIOF1_TXI, SIOF1_RXI, SIOF1_CCI),
+ };
+ 
+-static struct intc_prio priorities[] __initdata = {
+-	INTC_PRIO(DMAC1, 7),
+-	INTC_PRIO(DMAC2, 7),
+-	INTC_PRIO(SCIF0, 3),
+-	INTC_PRIO(SCIF1, 3),
+-	INTC_PRIO(SIOF0, 3),
+-	INTC_PRIO(SIOF1, 3),
+-	INTC_PRIO(EDMAC0, 5),
+-	INTC_PRIO(EDMAC1, 5),
+-	INTC_PRIO(EDMAC2, 5),
+-};
+-
+ static struct intc_prio_reg prio_registers[] __initdata = {
+ 	{ 0xfffffee2, 0, 16, 4, /* IPRA */ { TMU0, TMU1, TMU2, RTC } },
+ 	{ 0xfffffee4, 0, 16, 4, /* IPRB */ { WDT, REF, 0, 0 } },
+@@ -101,7 +89,7 @@ static struct intc_prio_reg prio_registers[] __initdata = {
+ };
+ 
+ static DECLARE_INTC_DESC(intc_desc, "sh7710", vectors, groups,
+-			 priorities, NULL, prio_registers, NULL);
++			 NULL, prio_registers, NULL);
+ 
+ static struct intc_vect vectors_irq[] __initdata = {
+ 	INTC_VECT(IRQ0, 0x600), INTC_VECT(IRQ1, 0x620),
+@@ -109,7 +97,7 @@ static struct intc_vect vectors_irq[] __initdata = {
+ };
+ 
+ static DECLARE_INTC_DESC(intc_desc_irq, "sh7710-irq", vectors_irq, NULL,
+-			 priorities, NULL, prio_registers, NULL);
++			 NULL, prio_registers, NULL);
+ 
+ static struct resource rtc_resources[] = {
+ 	[0] =	{
+diff --git a/arch/sh/kernel/cpu/sh3/setup-sh7720.c b/arch/sh/kernel/cpu/sh3/setup-sh7720.c
+index a0929b8..3855ea4 100644
+--- a/arch/sh/kernel/cpu/sh3/setup-sh7720.c
++++ b/arch/sh/kernel/cpu/sh3/setup-sh7720.c
+@@ -85,9 +85,62 @@ static struct platform_device sci_device = {
+ 	},
+ };
+ 
++static struct resource usb_ohci_resources[] = {
++	[0] = {
++		.start	= 0xA4428000,
++		.end	= 0xA44280FF,
++		.flags	= IORESOURCE_MEM,
++	},
++	[1] = {
++		.start	= 67,
++		.end	= 67,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static u64 usb_ohci_dma_mask = 0xffffffffUL;
++static struct platform_device usb_ohci_device = {
++	.name		= "sh_ohci",
++	.id		= -1,
++	.dev = {
++		.dma_mask		= &usb_ohci_dma_mask,
++		.coherent_dma_mask	= 0xffffffff,
++	},
++	.num_resources	= ARRAY_SIZE(usb_ohci_resources),
++	.resource	= usb_ohci_resources,
++};
++
++static struct resource usbf_resources[] = {
++	[0] = {
++		.name	= "sh_udc",
++		.start	= 0xA4420000,
++		.end	= 0xA44200FF,
++		.flags	= IORESOURCE_MEM,
++	},
++	[1] = {
++		.name	= "sh_udc",
++		.start	= 65,
++		.end	= 65,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device usbf_device = {
++	.name		= "sh_udc",
++	.id		= -1,
++	.dev = {
++		.dma_mask		= NULL,
++		.coherent_dma_mask	= 0xffffffff,
++	},
++	.num_resources	= ARRAY_SIZE(usbf_resources),
++	.resource	= usbf_resources,
++};
++
+ static struct platform_device *sh7720_devices[] __initdata = {
+ 	&rtc_device,
+ 	&sci_device,
++	&usb_ohci_device,
++	&usbf_device,
+ };
+ 
+ static int __init sh7720_devices_setup(void)
+@@ -127,8 +180,11 @@ static struct intc_vect vectors[] __initdata = {
+ 	INTC_VECT(USBF_SPD, 0x6e0),   INTC_VECT(DMAC1_DEI0, 0x800),
+ 	INTC_VECT(DMAC1_DEI1, 0x820), INTC_VECT(DMAC1_DEI2, 0x840),
+ 	INTC_VECT(DMAC1_DEI3, 0x860), INTC_VECT(LCDC, 0x900),
+-	INTC_VECT(SSL, 0x980),        INTC_VECT(USBFI0, 0xa20),
+-	INTC_VECT(USBFI1, 0xa40),     INTC_VECT(USBHI, 0xa60),
++#if defined(CONFIG_CPU_SUBTYPE_SH7720)
++	INTC_VECT(SSL, 0x980),
++#endif
++	INTC_VECT(USBFI0, 0xa20),     INTC_VECT(USBFI1, 0xa40),
++	INTC_VECT(USBHI, 0xa60),
+ 	INTC_VECT(DMAC2_DEI4, 0xb80), INTC_VECT(DMAC2_DEI5, 0xba0),
+ 	INTC_VECT(ADC, 0xbe0),        INTC_VECT(SCIF0, 0xc00),
+ 	INTC_VECT(SCIF1, 0xc20),      INTC_VECT(PINT07, 0xc80),
+@@ -153,22 +209,16 @@ static struct intc_group groups[] __initdata = {
+ 	INTC_GROUP(MMC, MMCI0, MMCI1, MMCI2, MMCI3),
+ };
+ 
+-static struct intc_prio priorities[] __initdata = {
+-	INTC_PRIO(SCIF0, 2),
+-	INTC_PRIO(SCIF1, 2),
+-	INTC_PRIO(DMAC1, 1),
+-	INTC_PRIO(DMAC2, 1),
+-	INTC_PRIO(RTC, 2),
+-	INTC_PRIO(TMU, 2),
+-	INTC_PRIO(TPU, 2),
+-};
+-
+ static struct intc_prio_reg prio_registers[] __initdata = {
+ 	{ 0xA414FEE2UL, 0, 16, 4, /* IPRA */ { TMU0, TMU1, TMU2, RTC } },
+ 	{ 0xA414FEE4UL, 0, 16, 4, /* IPRB */ { WDT, REF_RCMI, SIM, 0 } },
+ 	{ 0xA4140016UL, 0, 16, 4, /* IPRC */ { IRQ3, IRQ2, IRQ1, IRQ0 } },
+ 	{ 0xA4140018UL, 0, 16, 4, /* IPRD */ { USBF_SPD, TMU_SUNI, IRQ5, IRQ4 } },
++#if defined(CONFIG_CPU_SUBTYPE_SH7720)
+ 	{ 0xA414001AUL, 0, 16, 4, /* IPRE */ { DMAC1, 0, LCDC, SSL } },
++#else
++	{ 0xA414001AUL, 0, 16, 4, /* IPRE */ { DMAC1, 0, LCDC, 0 } },
++#endif
+ 	{ 0xA4080000UL, 0, 16, 4, /* IPRF */ { ADC, DMAC2, USBFI, CMT } },
+ 	{ 0xA4080002UL, 0, 16, 4, /* IPRG */ { SCIF0, SCIF1, 0, 0 } },
+ 	{ 0xA4080004UL, 0, 16, 4, /* IPRH */ { PINT07, PINT815, TPU, IIC } },
+@@ -177,7 +227,7 @@ static struct intc_prio_reg prio_registers[] __initdata = {
+ };
+ 
+ static DECLARE_INTC_DESC(intc_desc, "sh7720", vectors, groups,
+-		priorities, NULL, prio_registers, NULL);
++		NULL, prio_registers, NULL);
+ 
+ static struct intc_sense_reg sense_registers[] __initdata = {
+ 	{ INTC_ICR1, 16, 2, { 0, 0, IRQ5, IRQ4, IRQ3, IRQ2, IRQ1, IRQ0 } },
+@@ -190,7 +240,7 @@ static struct intc_vect vectors_irq[] __initdata = {
+ };
+ 
+ static DECLARE_INTC_DESC(intc_irq_desc, "sh7720-irq", vectors_irq,
+-		NULL, priorities, NULL, prio_registers, sense_registers);
++		NULL, NULL, prio_registers, sense_registers);
+ 
+ void __init plat_irq_setup_pins(int mode)
+ {
+diff --git a/arch/sh/kernel/cpu/sh4/Makefile b/arch/sh/kernel/cpu/sh4/Makefile
+index dadd6bf..d608557 100644
+--- a/arch/sh/kernel/cpu/sh4/Makefile
++++ b/arch/sh/kernel/cpu/sh4/Makefile
+@@ -5,7 +5,7 @@
+ obj-y	:= probe.o common.o
+ common-y	+= $(addprefix ../sh3/, entry.o ex.o)
+ 
+-obj-$(CONFIG_SH_FPU)			+= fpu.o
++obj-$(CONFIG_SH_FPU)			+= fpu.o softfloat.o
+ obj-$(CONFIG_SH_STORE_QUEUES)		+= sq.o
+ 
+ # CPU subtype setup
+diff --git a/arch/sh/kernel/cpu/sh4/fpu.c b/arch/sh/kernel/cpu/sh4/fpu.c
+index c5a4fc7..817f993 100644
+--- a/arch/sh/kernel/cpu/sh4/fpu.c
++++ b/arch/sh/kernel/cpu/sh4/fpu.c
+@@ -1,7 +1,4 @@
+-/* $Id: fpu.c,v 1.4 2004/01/13 05:52:11 kkojima Exp $
+- *
+- * linux/arch/sh/kernel/fpu.c
+- *
++/*
+  * Save/restore floating point context for signal handlers.
+  *
+  * This file is subject to the terms and conditions of the GNU General Public
+@@ -9,15 +6,16 @@
+  * for more details.
+  *
+  * Copyright (C) 1999, 2000  Kaz Kojima & Niibe Yutaka
++ * Copyright (C) 2006  ST Microelectronics Ltd. (denorm support)
+  *
+- * FIXME! These routines can be optimized in big endian case.
++ * FIXME! These routines have not been tested for big endian case.
+  */
+-
+ #include <linux/sched.h>
+ #include <linux/signal.h>
++#include <linux/io.h>
++#include <asm/cpu/fpu.h>
+ #include <asm/processor.h>
+ #include <asm/system.h>
+-#include <asm/io.h>
+ 
+ /* The PR (precision) bit in the FP Status Register must be clear when
+  * an frchg instruction is executed, otherwise the instruction is undefined.
+@@ -25,177 +23,184 @@
+  */
+ 
+ #define FPSCR_RCHG 0x00000000
++extern unsigned long long float64_div(unsigned long long a,
++				      unsigned long long b);
++extern unsigned long int float32_div(unsigned long int a, unsigned long int b);
++extern unsigned long long float64_mul(unsigned long long a,
++				      unsigned long long b);
++extern unsigned long int float32_mul(unsigned long int a, unsigned long int b);
++extern unsigned long long float64_add(unsigned long long a,
++				      unsigned long long b);
++extern unsigned long int float32_add(unsigned long int a, unsigned long int b);
++extern unsigned long long float64_sub(unsigned long long a,
++				      unsigned long long b);
++extern unsigned long int float32_sub(unsigned long int a, unsigned long int b);
+ 
++static unsigned int fpu_exception_flags;
+ 
+ /*
+  * Save FPU registers onto task structure.
+  * Assume called with FPU enabled (SR.FD=0).
+  */
+-void
+-save_fpu(struct task_struct *tsk, struct pt_regs *regs)
++void save_fpu(struct task_struct *tsk, struct pt_regs *regs)
+ {
+ 	unsigned long dummy;
+ 
+ 	clear_tsk_thread_flag(tsk, TIF_USEDFPU);
+ 	enable_fpu();
+-	asm volatile("sts.l	fpul, @-%0\n\t"
+-		     "sts.l	fpscr, @-%0\n\t"
+-		     "lds	%2, fpscr\n\t"
+-		     "frchg\n\t"
+-		     "fmov.s	fr15, @-%0\n\t"
+-		     "fmov.s	fr14, @-%0\n\t"
+-		     "fmov.s	fr13, @-%0\n\t"
+-		     "fmov.s	fr12, @-%0\n\t"
+-		     "fmov.s	fr11, @-%0\n\t"
+-		     "fmov.s	fr10, @-%0\n\t"
+-		     "fmov.s	fr9, @-%0\n\t"
+-		     "fmov.s	fr8, @-%0\n\t"
+-		     "fmov.s	fr7, @-%0\n\t"
+-		     "fmov.s	fr6, @-%0\n\t"
+-		     "fmov.s	fr5, @-%0\n\t"
+-		     "fmov.s	fr4, @-%0\n\t"
+-		     "fmov.s	fr3, @-%0\n\t"
+-		     "fmov.s	fr2, @-%0\n\t"
+-		     "fmov.s	fr1, @-%0\n\t"
+-		     "fmov.s	fr0, @-%0\n\t"
+-		     "frchg\n\t"
+-		     "fmov.s	fr15, @-%0\n\t"
+-		     "fmov.s	fr14, @-%0\n\t"
+-		     "fmov.s	fr13, @-%0\n\t"
+-		     "fmov.s	fr12, @-%0\n\t"
+-		     "fmov.s	fr11, @-%0\n\t"
+-		     "fmov.s	fr10, @-%0\n\t"
+-		     "fmov.s	fr9, @-%0\n\t"
+-		     "fmov.s	fr8, @-%0\n\t"
+-		     "fmov.s	fr7, @-%0\n\t"
+-		     "fmov.s	fr6, @-%0\n\t"
+-		     "fmov.s	fr5, @-%0\n\t"
+-		     "fmov.s	fr4, @-%0\n\t"
+-		     "fmov.s	fr3, @-%0\n\t"
+-		     "fmov.s	fr2, @-%0\n\t"
+-		     "fmov.s	fr1, @-%0\n\t"
+-		     "fmov.s	fr0, @-%0\n\t"
+-		     "lds	%3, fpscr\n\t"
+-		     : "=r" (dummy)
+-		     : "0" ((char *)(&tsk->thread.fpu.hard.status)),
+-		       "r" (FPSCR_RCHG),
+-		       "r" (FPSCR_INIT)
+-		     : "memory");
+-
+- 	disable_fpu();
+- 	release_fpu(regs);
++	asm volatile ("sts.l	fpul, @-%0\n\t"
++		      "sts.l	fpscr, @-%0\n\t"
++		      "lds	%2, fpscr\n\t"
++		      "frchg\n\t"
++		      "fmov.s	fr15, @-%0\n\t"
++		      "fmov.s	fr14, @-%0\n\t"
++		      "fmov.s	fr13, @-%0\n\t"
++		      "fmov.s	fr12, @-%0\n\t"
++		      "fmov.s	fr11, @-%0\n\t"
++		      "fmov.s	fr10, @-%0\n\t"
++		      "fmov.s	fr9, @-%0\n\t"
++		      "fmov.s	fr8, @-%0\n\t"
++		      "fmov.s	fr7, @-%0\n\t"
++		      "fmov.s	fr6, @-%0\n\t"
++		      "fmov.s	fr5, @-%0\n\t"
++		      "fmov.s	fr4, @-%0\n\t"
++		      "fmov.s	fr3, @-%0\n\t"
++		      "fmov.s	fr2, @-%0\n\t"
++		      "fmov.s	fr1, @-%0\n\t"
++		      "fmov.s	fr0, @-%0\n\t"
++		      "frchg\n\t"
++		      "fmov.s	fr15, @-%0\n\t"
++		      "fmov.s	fr14, @-%0\n\t"
++		      "fmov.s	fr13, @-%0\n\t"
++		      "fmov.s	fr12, @-%0\n\t"
++		      "fmov.s	fr11, @-%0\n\t"
++		      "fmov.s	fr10, @-%0\n\t"
++		      "fmov.s	fr9, @-%0\n\t"
++		      "fmov.s	fr8, @-%0\n\t"
++		      "fmov.s	fr7, @-%0\n\t"
++		      "fmov.s	fr6, @-%0\n\t"
++		      "fmov.s	fr5, @-%0\n\t"
++		      "fmov.s	fr4, @-%0\n\t"
++		      "fmov.s	fr3, @-%0\n\t"
++		      "fmov.s	fr2, @-%0\n\t"
++		      "fmov.s	fr1, @-%0\n\t"
++		      "fmov.s	fr0, @-%0\n\t"
++		      "lds	%3, fpscr\n\t":"=r" (dummy)
++		      :"0"((char *)(&tsk->thread.fpu.hard.status)),
++		      "r"(FPSCR_RCHG), "r"(FPSCR_INIT)
++		      :"memory");
++
++	disable_fpu();
++	release_fpu(regs);
+ }
+ 
+-static void
+-restore_fpu(struct task_struct *tsk)
++static void restore_fpu(struct task_struct *tsk)
+ {
+ 	unsigned long dummy;
+ 
+- 	enable_fpu();
+-	asm volatile("lds	%2, fpscr\n\t"
+-		     "fmov.s	@%0+, fr0\n\t"
+-		     "fmov.s	@%0+, fr1\n\t"
+-		     "fmov.s	@%0+, fr2\n\t"
+-		     "fmov.s	@%0+, fr3\n\t"
+-		     "fmov.s	@%0+, fr4\n\t"
+-		     "fmov.s	@%0+, fr5\n\t"
+-		     "fmov.s	@%0+, fr6\n\t"
+-		     "fmov.s	@%0+, fr7\n\t"
+-		     "fmov.s	@%0+, fr8\n\t"
+-		     "fmov.s	@%0+, fr9\n\t"
+-		     "fmov.s	@%0+, fr10\n\t"
+-		     "fmov.s	@%0+, fr11\n\t"
+-		     "fmov.s	@%0+, fr12\n\t"
+-		     "fmov.s	@%0+, fr13\n\t"
+-		     "fmov.s	@%0+, fr14\n\t"
+-		     "fmov.s	@%0+, fr15\n\t"
+-		     "frchg\n\t"
+-		     "fmov.s	@%0+, fr0\n\t"
+-		     "fmov.s	@%0+, fr1\n\t"
+-		     "fmov.s	@%0+, fr2\n\t"
+-		     "fmov.s	@%0+, fr3\n\t"
+-		     "fmov.s	@%0+, fr4\n\t"
+-		     "fmov.s	@%0+, fr5\n\t"
+-		     "fmov.s	@%0+, fr6\n\t"
+-		     "fmov.s	@%0+, fr7\n\t"
+-		     "fmov.s	@%0+, fr8\n\t"
+-		     "fmov.s	@%0+, fr9\n\t"
+-		     "fmov.s	@%0+, fr10\n\t"
+-		     "fmov.s	@%0+, fr11\n\t"
+-		     "fmov.s	@%0+, fr12\n\t"
+-		     "fmov.s	@%0+, fr13\n\t"
+-		     "fmov.s	@%0+, fr14\n\t"
+-		     "fmov.s	@%0+, fr15\n\t"
+-		     "frchg\n\t"
+-		     "lds.l	@%0+, fpscr\n\t"
+-		     "lds.l	@%0+, fpul\n\t"
+-		     : "=r" (dummy)
+-		     : "0" (&tsk->thread.fpu), "r" (FPSCR_RCHG)
+-		     : "memory");
++	enable_fpu();
++	asm volatile ("lds	%2, fpscr\n\t"
++		      "fmov.s	@%0+, fr0\n\t"
++		      "fmov.s	@%0+, fr1\n\t"
++		      "fmov.s	@%0+, fr2\n\t"
++		      "fmov.s	@%0+, fr3\n\t"
++		      "fmov.s	@%0+, fr4\n\t"
++		      "fmov.s	@%0+, fr5\n\t"
++		      "fmov.s	@%0+, fr6\n\t"
++		      "fmov.s	@%0+, fr7\n\t"
++		      "fmov.s	@%0+, fr8\n\t"
++		      "fmov.s	@%0+, fr9\n\t"
++		      "fmov.s	@%0+, fr10\n\t"
++		      "fmov.s	@%0+, fr11\n\t"
++		      "fmov.s	@%0+, fr12\n\t"
++		      "fmov.s	@%0+, fr13\n\t"
++		      "fmov.s	@%0+, fr14\n\t"
++		      "fmov.s	@%0+, fr15\n\t"
++		      "frchg\n\t"
++		      "fmov.s	@%0+, fr0\n\t"
++		      "fmov.s	@%0+, fr1\n\t"
++		      "fmov.s	@%0+, fr2\n\t"
++		      "fmov.s	@%0+, fr3\n\t"
++		      "fmov.s	@%0+, fr4\n\t"
++		      "fmov.s	@%0+, fr5\n\t"
++		      "fmov.s	@%0+, fr6\n\t"
++		      "fmov.s	@%0+, fr7\n\t"
++		      "fmov.s	@%0+, fr8\n\t"
++		      "fmov.s	@%0+, fr9\n\t"
++		      "fmov.s	@%0+, fr10\n\t"
++		      "fmov.s	@%0+, fr11\n\t"
++		      "fmov.s	@%0+, fr12\n\t"
++		      "fmov.s	@%0+, fr13\n\t"
++		      "fmov.s	@%0+, fr14\n\t"
++		      "fmov.s	@%0+, fr15\n\t"
++		      "frchg\n\t"
++		      "lds.l	@%0+, fpscr\n\t"
++		      "lds.l	@%0+, fpul\n\t"
++		      :"=r" (dummy)
++		      :"0"(&tsk->thread.fpu), "r"(FPSCR_RCHG)
++		      :"memory");
+ 	disable_fpu();
+ }
+ 
+ /*
+  * Load the FPU with signalling NANS.  This bit pattern we're using
+  * has the property that no matter wether considered as single or as
+- * double precision represents signaling NANS.  
++ * double precision represents signaling NANS.
+  */
+ 
+-static void
+-fpu_init(void)
++static void fpu_init(void)
+ {
+ 	enable_fpu();
+-	asm volatile("lds	%0, fpul\n\t"
+-		     "lds	%1, fpscr\n\t"
+-		     "fsts	fpul, fr0\n\t"
+-		     "fsts	fpul, fr1\n\t"
+-		     "fsts	fpul, fr2\n\t"
+-		     "fsts	fpul, fr3\n\t"
+-		     "fsts	fpul, fr4\n\t"
+-		     "fsts	fpul, fr5\n\t"
+-		     "fsts	fpul, fr6\n\t"
+-		     "fsts	fpul, fr7\n\t"
+-		     "fsts	fpul, fr8\n\t"
+-		     "fsts	fpul, fr9\n\t"
+-		     "fsts	fpul, fr10\n\t"
+-		     "fsts	fpul, fr11\n\t"
+-		     "fsts	fpul, fr12\n\t"
+-		     "fsts	fpul, fr13\n\t"
+-		     "fsts	fpul, fr14\n\t"
+-		     "fsts	fpul, fr15\n\t"
+-		     "frchg\n\t"
+-		     "fsts	fpul, fr0\n\t"
+-		     "fsts	fpul, fr1\n\t"
+-		     "fsts	fpul, fr2\n\t"
+-		     "fsts	fpul, fr3\n\t"
+-		     "fsts	fpul, fr4\n\t"
+-		     "fsts	fpul, fr5\n\t"
+-		     "fsts	fpul, fr6\n\t"
+-		     "fsts	fpul, fr7\n\t"
+-		     "fsts	fpul, fr8\n\t"
+-		     "fsts	fpul, fr9\n\t"
+-		     "fsts	fpul, fr10\n\t"
+-		     "fsts	fpul, fr11\n\t"
+-		     "fsts	fpul, fr12\n\t"
+-		     "fsts	fpul, fr13\n\t"
+-		     "fsts	fpul, fr14\n\t"
+-		     "fsts	fpul, fr15\n\t"
+-		     "frchg\n\t"
+-		     "lds	%2, fpscr\n\t"
+-		     : /* no output */
+-		     : "r" (0), "r" (FPSCR_RCHG), "r" (FPSCR_INIT));
+- 	disable_fpu();
++	asm volatile (	"lds	%0, fpul\n\t"
++			"lds	%1, fpscr\n\t"
++			"fsts	fpul, fr0\n\t"
++			"fsts	fpul, fr1\n\t"
++			"fsts	fpul, fr2\n\t"
++			"fsts	fpul, fr3\n\t"
++			"fsts	fpul, fr4\n\t"
++			"fsts	fpul, fr5\n\t"
++			"fsts	fpul, fr6\n\t"
++			"fsts	fpul, fr7\n\t"
++			"fsts	fpul, fr8\n\t"
++			"fsts	fpul, fr9\n\t"
++			"fsts	fpul, fr10\n\t"
++			"fsts	fpul, fr11\n\t"
++			"fsts	fpul, fr12\n\t"
++			"fsts	fpul, fr13\n\t"
++			"fsts	fpul, fr14\n\t"
++			"fsts	fpul, fr15\n\t"
++			"frchg\n\t"
++			"fsts	fpul, fr0\n\t"
++			"fsts	fpul, fr1\n\t"
++			"fsts	fpul, fr2\n\t"
++			"fsts	fpul, fr3\n\t"
++			"fsts	fpul, fr4\n\t"
++			"fsts	fpul, fr5\n\t"
++			"fsts	fpul, fr6\n\t"
++			"fsts	fpul, fr7\n\t"
++			"fsts	fpul, fr8\n\t"
++			"fsts	fpul, fr9\n\t"
++			"fsts	fpul, fr10\n\t"
++			"fsts	fpul, fr11\n\t"
++			"fsts	fpul, fr12\n\t"
++			"fsts	fpul, fr13\n\t"
++			"fsts	fpul, fr14\n\t"
++			"fsts	fpul, fr15\n\t"
++			"frchg\n\t"
++			"lds	%2, fpscr\n\t"
++			:	/* no output */
++			:"r" (0), "r"(FPSCR_RCHG), "r"(FPSCR_INIT));
++	disable_fpu();
+ }
+ 
+ /**
+- *	denormal_to_double - Given denormalized float number,
+- *	                     store double float
++ *      denormal_to_double - Given denormalized float number,
++ *                           store double float
+  *
+- *	@fpu: Pointer to sh_fpu_hard structure
+- *	@n: Index to FP register
++ *      @fpu: Pointer to sh_fpu_hard structure
++ *      @n: Index to FP register
+  */
+-static void
+-denormal_to_double (struct sh_fpu_hard_struct *fpu, int n)
++static void denormal_to_double(struct sh_fpu_hard_struct *fpu, int n)
+ {
+ 	unsigned long du, dl;
+ 	unsigned long x = fpu->fpul;
+@@ -212,7 +217,7 @@ denormal_to_double (struct sh_fpu_hard_struct *fpu, int n)
+ 		dl = x << 29;
+ 
+ 		fpu->fp_regs[n] = du;
+-		fpu->fp_regs[n+1] = dl;
++		fpu->fp_regs[n + 1] = dl;
+ 	}
+ }
+ 
+@@ -223,68 +228,191 @@ denormal_to_double (struct sh_fpu_hard_struct *fpu, int n)
+  *
+  *	Returns 1 when it's handled (should not cause exception).
+  */
+-static int
+-ieee_fpe_handler (struct pt_regs *regs)
++static int ieee_fpe_handler(struct pt_regs *regs)
+ {
+-	unsigned short insn = *(unsigned short *) regs->pc;
++	unsigned short insn = *(unsigned short *)regs->pc;
+ 	unsigned short finsn;
+ 	unsigned long nextpc;
+ 	int nib[4] = {
+ 		(insn >> 12) & 0xf,
+ 		(insn >> 8) & 0xf,
+ 		(insn >> 4) & 0xf,
+-		insn & 0xf};
+-
+-	if (nib[0] == 0xb ||
+-	    (nib[0] == 0x4 && nib[2] == 0x0 && nib[3] == 0xb)) /* bsr & jsr */
+-		regs->pr = regs->pc + 4;
+-  
+-	if (nib[0] == 0xa || nib[0] == 0xb) { /* bra & bsr */
+-		nextpc = regs->pc + 4 + ((short) ((insn & 0xfff) << 4) >> 3);
+-		finsn = *(unsigned short *) (regs->pc + 2);
+-	} else if (nib[0] == 0x8 && nib[1] == 0xd) { /* bt/s */
++		insn & 0xf
++	};
++
++	if (nib[0] == 0xb || (nib[0] == 0x4 && nib[2] == 0x0 && nib[3] == 0xb))
++		regs->pr = regs->pc + 4;  /* bsr & jsr */
++
++	if (nib[0] == 0xa || nib[0] == 0xb) {
++		/* bra & bsr */
++		nextpc = regs->pc + 4 + ((short)((insn & 0xfff) << 4) >> 3);
++		finsn = *(unsigned short *)(regs->pc + 2);
++	} else if (nib[0] == 0x8 && nib[1] == 0xd) {
++		/* bt/s */
+ 		if (regs->sr & 1)
+-			nextpc = regs->pc + 4 + ((char) (insn & 0xff) << 1);
++			nextpc = regs->pc + 4 + ((char)(insn & 0xff) << 1);
+ 		else
+ 			nextpc = regs->pc + 4;
+-		finsn = *(unsigned short *) (regs->pc + 2);
+-	} else if (nib[0] == 0x8 && nib[1] == 0xf) { /* bf/s */
++		finsn = *(unsigned short *)(regs->pc + 2);
++	} else if (nib[0] == 0x8 && nib[1] == 0xf) {
++		/* bf/s */
+ 		if (regs->sr & 1)
+ 			nextpc = regs->pc + 4;
+ 		else
+-			nextpc = regs->pc + 4 + ((char) (insn & 0xff) << 1);
+-		finsn = *(unsigned short *) (regs->pc + 2);
++			nextpc = regs->pc + 4 + ((char)(insn & 0xff) << 1);
++		finsn = *(unsigned short *)(regs->pc + 2);
+ 	} else if (nib[0] == 0x4 && nib[3] == 0xb &&
+-		 (nib[2] == 0x0 || nib[2] == 0x2)) { /* jmp & jsr */
++		   (nib[2] == 0x0 || nib[2] == 0x2)) {
++		/* jmp & jsr */
+ 		nextpc = regs->regs[nib[1]];
+-		finsn = *(unsigned short *) (regs->pc + 2);
++		finsn = *(unsigned short *)(regs->pc + 2);
+ 	} else if (nib[0] == 0x0 && nib[3] == 0x3 &&
+-		 (nib[2] == 0x0 || nib[2] == 0x2)) { /* braf & bsrf */
++		   (nib[2] == 0x0 || nib[2] == 0x2)) {
++		/* braf & bsrf */
+ 		nextpc = regs->pc + 4 + regs->regs[nib[1]];
+-		finsn = *(unsigned short *) (regs->pc + 2);
+-	} else if (insn == 0x000b) { /* rts */
++		finsn = *(unsigned short *)(regs->pc + 2);
++	} else if (insn == 0x000b) {
++		/* rts */
+ 		nextpc = regs->pr;
+-		finsn = *(unsigned short *) (regs->pc + 2);
++		finsn = *(unsigned short *)(regs->pc + 2);
+ 	} else {
+ 		nextpc = regs->pc + instruction_size(insn);
+ 		finsn = insn;
+ 	}
+ 
+-	if ((finsn & 0xf1ff) == 0xf0ad) { /* fcnvsd */
++	if ((finsn & 0xf1ff) == 0xf0ad) {
++		/* fcnvsd */
+ 		struct task_struct *tsk = current;
+ 
+ 		save_fpu(tsk, regs);
+-		if ((tsk->thread.fpu.hard.fpscr & (1 << 17))) {
++		if ((tsk->thread.fpu.hard.fpscr & FPSCR_CAUSE_ERROR))
+ 			/* FPU error */
+-			denormal_to_double (&tsk->thread.fpu.hard,
+-					    (finsn >> 8) & 0xf);
+-			tsk->thread.fpu.hard.fpscr &=
+-				~(FPSCR_CAUSE_MASK | FPSCR_FLAG_MASK);
+-			grab_fpu(regs);
+-			restore_fpu(tsk);
+-			set_tsk_thread_flag(tsk, TIF_USEDFPU);
++			denormal_to_double(&tsk->thread.fpu.hard,
++					   (finsn >> 8) & 0xf);
++		else
++			return 0;
++
++		regs->pc = nextpc;
++		return 1;
++	} else if ((finsn & 0xf00f) == 0xf002) {
++		/* fmul */
++		struct task_struct *tsk = current;
++		int fpscr;
++		int n, m, prec;
++		unsigned int hx, hy;
++
++		n = (finsn >> 8) & 0xf;
++		m = (finsn >> 4) & 0xf;
++		hx = tsk->thread.fpu.hard.fp_regs[n];
++		hy = tsk->thread.fpu.hard.fp_regs[m];
++		fpscr = tsk->thread.fpu.hard.fpscr;
++		prec = fpscr & FPSCR_DBL_PRECISION;
++
++		if ((fpscr & FPSCR_CAUSE_ERROR)
++		    && (prec && ((hx & 0x7fffffff) < 0x00100000
++				 || (hy & 0x7fffffff) < 0x00100000))) {
++			long long llx, lly;
++
++			/* FPU error because of denormal (doubles) */
++			llx = ((long long)hx << 32)
++			    | tsk->thread.fpu.hard.fp_regs[n + 1];
++			lly = ((long long)hy << 32)
++			    | tsk->thread.fpu.hard.fp_regs[m + 1];
++			llx = float64_mul(llx, lly);
++			tsk->thread.fpu.hard.fp_regs[n] = llx >> 32;
++			tsk->thread.fpu.hard.fp_regs[n + 1] = llx & 0xffffffff;
++		} else if ((fpscr & FPSCR_CAUSE_ERROR)
++			   && (!prec && ((hx & 0x7fffffff) < 0x00800000
++					 || (hy & 0x7fffffff) < 0x00800000))) {
++			/* FPU error because of denormal (floats) */
++			hx = float32_mul(hx, hy);
++			tsk->thread.fpu.hard.fp_regs[n] = hx;
++		} else
++			return 0;
++
++		regs->pc = nextpc;
++		return 1;
++	} else if ((finsn & 0xf00e) == 0xf000) {
++		/* fadd, fsub */
++		struct task_struct *tsk = current;
++		int fpscr;
++		int n, m, prec;
++		unsigned int hx, hy;
++
++		n = (finsn >> 8) & 0xf;
++		m = (finsn >> 4) & 0xf;
++		hx = tsk->thread.fpu.hard.fp_regs[n];
++		hy = tsk->thread.fpu.hard.fp_regs[m];
++		fpscr = tsk->thread.fpu.hard.fpscr;
++		prec = fpscr & FPSCR_DBL_PRECISION;
++
++		if ((fpscr & FPSCR_CAUSE_ERROR)
++		    && (prec && ((hx & 0x7fffffff) < 0x00100000
++				 || (hy & 0x7fffffff) < 0x00100000))) {
++			long long llx, lly;
++
++			/* FPU error because of denormal (doubles) */
++			llx = ((long long)hx << 32)
++			    | tsk->thread.fpu.hard.fp_regs[n + 1];
++			lly = ((long long)hy << 32)
++			    | tsk->thread.fpu.hard.fp_regs[m + 1];
++			if ((finsn & 0xf00f) == 0xf000)
++				llx = float64_add(llx, lly);
++			else
++				llx = float64_sub(llx, lly);
++			tsk->thread.fpu.hard.fp_regs[n] = llx >> 32;
++			tsk->thread.fpu.hard.fp_regs[n + 1] = llx & 0xffffffff;
++		} else if ((fpscr & FPSCR_CAUSE_ERROR)
++			   && (!prec && ((hx & 0x7fffffff) < 0x00800000
++					 || (hy & 0x7fffffff) < 0x00800000))) {
++			/* FPU error because of denormal (floats) */
++			if ((finsn & 0xf00f) == 0xf000)
++				hx = float32_add(hx, hy);
++			else
++				hx = float32_sub(hx, hy);
++			tsk->thread.fpu.hard.fp_regs[n] = hx;
++		} else
++			return 0;
++
++		regs->pc = nextpc;
++		return 1;
++	} else if ((finsn & 0xf003) == 0xf003) {
++		/* fdiv */
++		struct task_struct *tsk = current;
++		int fpscr;
++		int n, m, prec;
++		unsigned int hx, hy;
++
++		n = (finsn >> 8) & 0xf;
++		m = (finsn >> 4) & 0xf;
++		hx = tsk->thread.fpu.hard.fp_regs[n];
++		hy = tsk->thread.fpu.hard.fp_regs[m];
++		fpscr = tsk->thread.fpu.hard.fpscr;
++		prec = fpscr & FPSCR_DBL_PRECISION;
++
++		if ((fpscr & FPSCR_CAUSE_ERROR)
++		    && (prec && ((hx & 0x7fffffff) < 0x00100000
++				 || (hy & 0x7fffffff) < 0x00100000))) {
++			long long llx, lly;
++
++			/* FPU error because of denormal (doubles) */
++			llx = ((long long)hx << 32)
++			    | tsk->thread.fpu.hard.fp_regs[n + 1];
++			lly = ((long long)hy << 32)
++			    | tsk->thread.fpu.hard.fp_regs[m + 1];
++
++			llx = float64_div(llx, lly);
++
++			tsk->thread.fpu.hard.fp_regs[n] = llx >> 32;
++			tsk->thread.fpu.hard.fp_regs[n + 1] = llx & 0xffffffff;
++		} else if ((fpscr & FPSCR_CAUSE_ERROR)
++			   && (!prec && ((hx & 0x7fffffff) < 0x00800000
++					 || (hy & 0x7fffffff) < 0x00800000))) {
++			/* FPU error because of denormal (floats) */
++			hx = float32_div(hx, hy);
++			tsk->thread.fpu.hard.fp_regs[n] = hx;
+ 		} else
+-			force_sig(SIGFPE, tsk);
++			return 0;
+ 
+ 		regs->pc = nextpc;
+ 		return 1;
+@@ -293,27 +421,48 @@ ieee_fpe_handler (struct pt_regs *regs)
+ 	return 0;
+ }
+ 
+-asmlinkage void
+-do_fpu_error(unsigned long r4, unsigned long r5, unsigned long r6,
+-	     unsigned long r7, struct pt_regs __regs)
++void float_raise(unsigned int flags)
++{
++	fpu_exception_flags |= flags;
++}
++
++int float_rounding_mode(void)
+ {
+-	struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
+ 	struct task_struct *tsk = current;
++	int roundingMode = FPSCR_ROUNDING_MODE(tsk->thread.fpu.hard.fpscr);
++	return roundingMode;
++}
+ 
+-	if (ieee_fpe_handler(regs))
+-		return;
++BUILD_TRAP_HANDLER(fpu_error)
++{
++	struct task_struct *tsk = current;
++	TRAP_HANDLER_DECL;
+ 
+-	regs->pc += 2;
+ 	save_fpu(tsk, regs);
++	fpu_exception_flags = 0;
++	if (ieee_fpe_handler(regs)) {
++		tsk->thread.fpu.hard.fpscr &=
++		    ~(FPSCR_CAUSE_MASK | FPSCR_FLAG_MASK);
++		tsk->thread.fpu.hard.fpscr |= fpu_exception_flags;
++		/* Set the FPSCR flag as well as cause bits - simply
++		 * replicate the cause */
++		tsk->thread.fpu.hard.fpscr |= (fpu_exception_flags >> 10);
++		grab_fpu(regs);
++		restore_fpu(tsk);
++		set_tsk_thread_flag(tsk, TIF_USEDFPU);
++		if ((((tsk->thread.fpu.hard.fpscr & FPSCR_ENABLE_MASK) >> 7) &
++		     (fpu_exception_flags >> 2)) == 0) {
++			return;
++		}
++	}
++
+ 	force_sig(SIGFPE, tsk);
+ }
+ 
+-asmlinkage void
+-do_fpu_state_restore(unsigned long r4, unsigned long r5, unsigned long r6,
+-		     unsigned long r7, struct pt_regs __regs)
++BUILD_TRAP_HANDLER(fpu_state_restore)
+ {
+-	struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
+ 	struct task_struct *tsk = current;
++	TRAP_HANDLER_DECL;
+ 
+ 	grab_fpu(regs);
+ 	if (!user_mode(regs)) {
+@@ -324,7 +473,7 @@ do_fpu_state_restore(unsigned long r4, unsigned long r5, unsigned long r6,
+ 	if (used_math()) {
+ 		/* Using the FPU again.  */
+ 		restore_fpu(tsk);
+-	} else	{
++	} else {
+ 		/* First time FPU user.  */
+ 		fpu_init();
+ 		set_used_math();
+diff --git a/arch/sh/kernel/cpu/sh4/probe.c b/arch/sh/kernel/cpu/sh4/probe.c
+index bc9c28a..f2b9238 100644
+--- a/arch/sh/kernel/cpu/sh4/probe.c
++++ b/arch/sh/kernel/cpu/sh4/probe.c
+@@ -98,6 +98,8 @@ int __init detect_cpu_and_cache_system(void)
+ 	case 0x200A:
+ 		if (prr == 0x61)
+ 			boot_cpu_data.type = CPU_SH7781;
++		else if (prr == 0xa1)
++			boot_cpu_data.type = CPU_SH7763;
+ 		else
+ 			boot_cpu_data.type = CPU_SH7780;
+ 
+diff --git a/arch/sh/kernel/cpu/sh4/setup-sh7750.c b/arch/sh/kernel/cpu/sh4/setup-sh7750.c
+index 523f68a..ae3603a 100644
+--- a/arch/sh/kernel/cpu/sh4/setup-sh7750.c
++++ b/arch/sh/kernel/cpu/sh4/setup-sh7750.c
+@@ -126,12 +126,6 @@ static struct intc_group groups[] __initdata = {
+ 	INTC_GROUP(REF, REF_RCMI, REF_ROVI),
+ };
+ 
+-static struct intc_prio priorities[] __initdata = {
+-	INTC_PRIO(SCIF, 3),
+-	INTC_PRIO(SCI1, 3),
+-	INTC_PRIO(DMAC, 7),
+-};
+-
+ static struct intc_prio_reg prio_registers[] __initdata = {
+ 	{ 0xffd00004, 0, 16, 4, /* IPRA */ { TMU0, TMU1, TMU2, RTC } },
+ 	{ 0xffd00008, 0, 16, 4, /* IPRB */ { WDT, REF, SCI1, 0 } },
+@@ -143,7 +137,7 @@ static struct intc_prio_reg prio_registers[] __initdata = {
+ };
+ 
+ static DECLARE_INTC_DESC(intc_desc, "sh7750", vectors, groups,
+-			 priorities, NULL, prio_registers, NULL);
++			 NULL, prio_registers, NULL);
+ 
+ /* SH7750, SH7750S, SH7751 and SH7091 all have 4-channel DMA controllers */
+ #if defined(CONFIG_CPU_SUBTYPE_SH7750) || \
+@@ -163,7 +157,7 @@ static struct intc_group groups_dma4[] __initdata = {
+ 
+ static DECLARE_INTC_DESC(intc_desc_dma4, "sh7750_dma4",
+ 			 vectors_dma4, groups_dma4,
+-			 priorities, NULL, prio_registers, NULL);
++			 NULL, prio_registers, NULL);
+ #endif
+ 
+ /* SH7750R and SH7751R both have 8-channel DMA controllers */
+@@ -184,7 +178,7 @@ static struct intc_group groups_dma8[] __initdata = {
+ 
+ static DECLARE_INTC_DESC(intc_desc_dma8, "sh7750_dma8",
+ 			 vectors_dma8, groups_dma8,
+-			 priorities, NULL, prio_registers, NULL);
++			 NULL, prio_registers, NULL);
+ #endif
+ 
+ /* SH7750R, SH7751 and SH7751R all have two extra timer channels */
+@@ -205,7 +199,7 @@ static struct intc_mask_reg mask_registers[] __initdata = {
+ };
+ 
+ static DECLARE_INTC_DESC(intc_desc_tmu34, "sh7750_tmu34",
+-			 vectors_tmu34, NULL, priorities,
++			 vectors_tmu34, NULL,
+ 			 mask_registers, prio_registers, NULL);
+ #endif
+ 
+@@ -216,7 +210,7 @@ static struct intc_vect vectors_irlm[] __initdata = {
+ };
+ 
+ static DECLARE_INTC_DESC(intc_desc_irlm, "sh7750_irlm", vectors_irlm, NULL,
+-			 priorities, NULL, prio_registers, NULL);
++			 NULL, prio_registers, NULL);
+ 
+ /* SH7751 and SH7751R both have PCI */
+ #if defined(CONFIG_CPU_SUBTYPE_SH7751) || defined(CONFIG_CPU_SUBTYPE_SH7751R)
+@@ -233,7 +227,7 @@ static struct intc_group groups_pci[] __initdata = {
+ };
+ 
+ static DECLARE_INTC_DESC(intc_desc_pci, "sh7750_pci", vectors_pci, groups_pci,
+-			 priorities, mask_registers, prio_registers, NULL);
++			 mask_registers, prio_registers, NULL);
+ #endif
+ 
+ #if defined(CONFIG_CPU_SUBTYPE_SH7750) || \
+diff --git a/arch/sh/kernel/cpu/sh4/setup-sh7760.c b/arch/sh/kernel/cpu/sh4/setup-sh7760.c
+index 7a898cb..85f8157 100644
+--- a/arch/sh/kernel/cpu/sh4/setup-sh7760.c
++++ b/arch/sh/kernel/cpu/sh4/setup-sh7760.c
+@@ -92,15 +92,6 @@ static struct intc_group groups[] __initdata = {
+ 	INTC_GROUP(REF, REF_RCMI, REF_ROVI),
+ };
+ 
+-static struct intc_prio priorities[] __initdata = {
+-	INTC_PRIO(SCIF0, 3),
+-	INTC_PRIO(SCIF1, 3),
+-	INTC_PRIO(SCIF2, 3),
+-	INTC_PRIO(SIM, 3),
+-	INTC_PRIO(DMAC, 7),
+-	INTC_PRIO(DMABRG, 13),
+-};
+-
+ static struct intc_mask_reg mask_registers[] __initdata = {
+ 	{ 0xfe080040, 0xfe080060, 32, /* INTMSK00 / INTMSKCLR00 */
+ 	  { IRQ4, IRQ5, IRQ6, IRQ7, 0, 0, HCAN20, HCAN21,
+@@ -132,7 +123,7 @@ static struct intc_prio_reg prio_registers[] __initdata = {
+ };
+ 
+ static DECLARE_INTC_DESC(intc_desc, "sh7760", vectors, groups,
+-			 priorities, mask_registers, prio_registers, NULL);
++			 mask_registers, prio_registers, NULL);
+ 
+ static struct intc_vect vectors_irq[] __initdata = {
+ 	INTC_VECT(IRL0, 0x240), INTC_VECT(IRL1, 0x2a0),
+@@ -140,7 +131,7 @@ static struct intc_vect vectors_irq[] __initdata = {
+ };
+ 
+ static DECLARE_INTC_DESC(intc_desc_irq, "sh7760-irq", vectors_irq, groups,
+-			 priorities, mask_registers, prio_registers, NULL);
++			 mask_registers, prio_registers, NULL);
+ 
+ static struct plat_sci_port sci_platform_data[] = {
+ 	{
+diff --git a/arch/sh/kernel/cpu/sh4/softfloat.c b/arch/sh/kernel/cpu/sh4/softfloat.c
+new file mode 100644
+index 0000000..7b2d337
+--- /dev/null
++++ b/arch/sh/kernel/cpu/sh4/softfloat.c
+@@ -0,0 +1,892 @@
++/*
++ * Floating point emulation support for subnormalised numbers on SH4
++ * architecture This file is derived from the SoftFloat IEC/IEEE
++ * Floating-point Arithmetic Package, Release 2 the original license of
++ * which is reproduced below.
++ *
++ * ========================================================================
++ *
++ * This C source file is part of the SoftFloat IEC/IEEE Floating-point
++ * Arithmetic Package, Release 2.
++ *
++ * Written by John R. Hauser.  This work was made possible in part by the
++ * International Computer Science Institute, located at Suite 600, 1947 Center
++ * Street, Berkeley, California 94704.  Funding was partially provided by the
++ * National Science Foundation under grant MIP-9311980.  The original version
++ * of this code was written as part of a project to build a fixed-point vector
++ * processor in collaboration with the University of California at Berkeley,
++ * overseen by Profs. Nelson Morgan and John Wawrzynek.  More information
++ * is available through the web page `http://HTTP.CS.Berkeley.EDU/~jhauser/
++ * arithmetic/softfloat.html'.
++ *
++ * THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE.  Although reasonable effort
++ * has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT
++ * TIMES RESULT IN INCORRECT BEHAVIOR.  USE OF THIS SOFTWARE IS RESTRICTED TO
++ * PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY
++ * AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE.
++ *
++ * Derivative works are acceptable, even for commercial purposes, so long as
++ * (1) they include prominent notice that the work is derivative, and (2) they
++ * include prominent notice akin to these three paragraphs for those parts of
++ * this code that are retained.
++ *
++ * ========================================================================
++ *
++ * SH4 modifications by Ismail Dhaoui <ismail.dhaoui at st.com>
++ * and Kamel Khelifi <kamel.khelifi at st.com>
++ */
++#include <linux/kernel.h>
++#include <asm/cpu/fpu.h>
++
++#define LIT64( a ) a##LL
++
++typedef char flag;
++typedef unsigned char uint8;
++typedef signed char int8;
++typedef int uint16;
++typedef int int16;
++typedef unsigned int uint32;
++typedef signed int int32;
++
++typedef unsigned long long int bits64;
++typedef signed long long int sbits64;
++
++typedef unsigned char bits8;
++typedef signed char sbits8;
++typedef unsigned short int bits16;
++typedef signed short int sbits16;
++typedef unsigned int bits32;
++typedef signed int sbits32;
++
++typedef unsigned long long int uint64;
++typedef signed long long int int64;
++
++typedef unsigned long int float32;
++typedef unsigned long long float64;
++
++extern void float_raise(unsigned int flags);	/* in fpu.c */
++extern int float_rounding_mode(void);	/* in fpu.c */
++
++inline bits64 extractFloat64Frac(float64 a);
++inline flag extractFloat64Sign(float64 a);
++inline int16 extractFloat64Exp(float64 a);
++inline int16 extractFloat32Exp(float32 a);
++inline flag extractFloat32Sign(float32 a);
++inline bits32 extractFloat32Frac(float32 a);
++inline float64 packFloat64(flag zSign, int16 zExp, bits64 zSig);
++inline void shift64RightJamming(bits64 a, int16 count, bits64 * zPtr);
++inline float32 packFloat32(flag zSign, int16 zExp, bits32 zSig);
++inline void shift32RightJamming(bits32 a, int16 count, bits32 * zPtr);
++float64 float64_sub(float64 a, float64 b);
++float32 float32_sub(float32 a, float32 b);
++float32 float32_add(float32 a, float32 b);
++float64 float64_add(float64 a, float64 b);
++float64 float64_div(float64 a, float64 b);
++float32 float32_div(float32 a, float32 b);
++float32 float32_mul(float32 a, float32 b);
++float64 float64_mul(float64 a, float64 b);
++inline void add128(bits64 a0, bits64 a1, bits64 b0, bits64 b1, bits64 * z0Ptr,
++		   bits64 * z1Ptr);
++inline void sub128(bits64 a0, bits64 a1, bits64 b0, bits64 b1, bits64 * z0Ptr,
++		   bits64 * z1Ptr);
++inline void mul64To128(bits64 a, bits64 b, bits64 * z0Ptr, bits64 * z1Ptr);
++
++static int8 countLeadingZeros32(bits32 a);
++static int8 countLeadingZeros64(bits64 a);
++static float64 normalizeRoundAndPackFloat64(flag zSign, int16 zExp,
++					    bits64 zSig);
++static float64 subFloat64Sigs(float64 a, float64 b, flag zSign);
++static float64 addFloat64Sigs(float64 a, float64 b, flag zSign);
++static float32 roundAndPackFloat32(flag zSign, int16 zExp, bits32 zSig);
++static float32 normalizeRoundAndPackFloat32(flag zSign, int16 zExp,
++					    bits32 zSig);
++static float64 roundAndPackFloat64(flag zSign, int16 zExp, bits64 zSig);
++static float32 subFloat32Sigs(float32 a, float32 b, flag zSign);
++static float32 addFloat32Sigs(float32 a, float32 b, flag zSign);
++static void normalizeFloat64Subnormal(bits64 aSig, int16 * zExpPtr,
++				      bits64 * zSigPtr);
++static bits64 estimateDiv128To64(bits64 a0, bits64 a1, bits64 b);
++static void normalizeFloat32Subnormal(bits32 aSig, int16 * zExpPtr,
++				      bits32 * zSigPtr);
++
++inline bits64 extractFloat64Frac(float64 a)
++{
++	return a & LIT64(0x000FFFFFFFFFFFFF);
++}
++
++inline flag extractFloat64Sign(float64 a)
++{
++	return a >> 63;
++}
++
++inline int16 extractFloat64Exp(float64 a)
++{
++	return (a >> 52) & 0x7FF;
++}
++
++inline int16 extractFloat32Exp(float32 a)
++{
++	return (a >> 23) & 0xFF;
++}
++
++inline flag extractFloat32Sign(float32 a)
++{
++	return a >> 31;
++}
++
++inline bits32 extractFloat32Frac(float32 a)
++{
++	return a & 0x007FFFFF;
++}
++
++inline float64 packFloat64(flag zSign, int16 zExp, bits64 zSig)
++{
++	return (((bits64) zSign) << 63) + (((bits64) zExp) << 52) + zSig;
++}
++
++inline void shift64RightJamming(bits64 a, int16 count, bits64 * zPtr)
++{
++	bits64 z;
++
++	if (count == 0) {
++		z = a;
++	} else if (count < 64) {
++		z = (a >> count) | ((a << ((-count) & 63)) != 0);
++	} else {
++		z = (a != 0);
++	}
++	*zPtr = z;
++}
++
++static int8 countLeadingZeros32(bits32 a)
++{
++	static const int8 countLeadingZerosHigh[] = {
++		8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4,
++		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, 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, 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, 1, 1, 1, 1, 1, 1,
++		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
++		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
++		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
++		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
++		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
++		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
++		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
++		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
++	};
++	int8 shiftCount;
++
++	shiftCount = 0;
++	if (a < 0x10000) {
++		shiftCount += 16;
++		a <<= 16;
++	}
++	if (a < 0x1000000) {
++		shiftCount += 8;
++		a <<= 8;
++	}
++	shiftCount += countLeadingZerosHigh[a >> 24];
++	return shiftCount;
++
++}
++
++static int8 countLeadingZeros64(bits64 a)
++{
++	int8 shiftCount;
++
++	shiftCount = 0;
++	if (a < ((bits64) 1) << 32) {
++		shiftCount += 32;
++	} else {
++		a >>= 32;
++	}
++	shiftCount += countLeadingZeros32(a);
++	return shiftCount;
++
++}
++
++static float64 normalizeRoundAndPackFloat64(flag zSign, int16 zExp, bits64 zSig)
++{
++	int8 shiftCount;
++
++	shiftCount = countLeadingZeros64(zSig) - 1;
++	return roundAndPackFloat64(zSign, zExp - shiftCount,
++				   zSig << shiftCount);
++
++}
++
++static float64 subFloat64Sigs(float64 a, float64 b, flag zSign)
++{
++	int16 aExp, bExp, zExp;
++	bits64 aSig, bSig, zSig;
++	int16 expDiff;
++
++	aSig = extractFloat64Frac(a);
++	aExp = extractFloat64Exp(a);
++	bSig = extractFloat64Frac(b);
++	bExp = extractFloat64Exp(b);
++	expDiff = aExp - bExp;
++	aSig <<= 10;
++	bSig <<= 10;
++	if (0 < expDiff)
++		goto aExpBigger;
++	if (expDiff < 0)
++		goto bExpBigger;
++	if (aExp == 0) {
++		aExp = 1;
++		bExp = 1;
++	}
++	if (bSig < aSig)
++		goto aBigger;
++	if (aSig < bSig)
++		goto bBigger;
++	return packFloat64(float_rounding_mode() == FPSCR_RM_ZERO, 0, 0);
++      bExpBigger:
++	if (bExp == 0x7FF) {
++		return packFloat64(zSign ^ 1, 0x7FF, 0);
++	}
++	if (aExp == 0) {
++		++expDiff;
++	} else {
++		aSig |= LIT64(0x4000000000000000);
++	}
++	shift64RightJamming(aSig, -expDiff, &aSig);
++	bSig |= LIT64(0x4000000000000000);
++      bBigger:
++	zSig = bSig - aSig;
++	zExp = bExp;
++	zSign ^= 1;
++	goto normalizeRoundAndPack;
++      aExpBigger:
++	if (aExp == 0x7FF) {
++		return a;
++	}
++	if (bExp == 0) {
++		--expDiff;
++	} else {
++		bSig |= LIT64(0x4000000000000000);
++	}
++	shift64RightJamming(bSig, expDiff, &bSig);
++	aSig |= LIT64(0x4000000000000000);
++      aBigger:
++	zSig = aSig - bSig;
++	zExp = aExp;
++      normalizeRoundAndPack:
++	--zExp;
++	return normalizeRoundAndPackFloat64(zSign, zExp, zSig);
++
++}
++static float64 addFloat64Sigs(float64 a, float64 b, flag zSign)
++{
++	int16 aExp, bExp, zExp;
++	bits64 aSig, bSig, zSig;
++	int16 expDiff;
++
++	aSig = extractFloat64Frac(a);
++	aExp = extractFloat64Exp(a);
++	bSig = extractFloat64Frac(b);
++	bExp = extractFloat64Exp(b);
++	expDiff = aExp - bExp;
++	aSig <<= 9;
++	bSig <<= 9;
++	if (0 < expDiff) {
++		if (aExp == 0x7FF) {
++			return a;
++		}
++		if (bExp == 0) {
++			--expDiff;
++		} else {
++			bSig |= LIT64(0x2000000000000000);
++		}
++		shift64RightJamming(bSig, expDiff, &bSig);
++		zExp = aExp;
++	} else if (expDiff < 0) {
++		if (bExp == 0x7FF) {
++			return packFloat64(zSign, 0x7FF, 0);
++		}
++		if (aExp == 0) {
++			++expDiff;
++		} else {
++			aSig |= LIT64(0x2000000000000000);
++		}
++		shift64RightJamming(aSig, -expDiff, &aSig);
++		zExp = bExp;
++	} else {
++		if (aExp == 0x7FF) {
++			return a;
++		}
++		if (aExp == 0)
++			return packFloat64(zSign, 0, (aSig + bSig) >> 9);
++		zSig = LIT64(0x4000000000000000) + aSig + bSig;
++		zExp = aExp;
++		goto roundAndPack;
++	}
++	aSig |= LIT64(0x2000000000000000);
++	zSig = (aSig + bSig) << 1;
++	--zExp;
++	if ((sbits64) zSig < 0) {
++		zSig = aSig + bSig;
++		++zExp;
++	}
++      roundAndPack:
++	return roundAndPackFloat64(zSign, zExp, zSig);
++
++}
++
++inline float32 packFloat32(flag zSign, int16 zExp, bits32 zSig)
++{
++	return (((bits32) zSign) << 31) + (((bits32) zExp) << 23) + zSig;
++}
++
++inline void shift32RightJamming(bits32 a, int16 count, bits32 * zPtr)
++{
++	bits32 z;
++	if (count == 0) {
++		z = a;
++	} else if (count < 32) {
++		z = (a >> count) | ((a << ((-count) & 31)) != 0);
++	} else {
++		z = (a != 0);
++	}
++	*zPtr = z;
++}
++
++static float32 roundAndPackFloat32(flag zSign, int16 zExp, bits32 zSig)
++{
++	flag roundNearestEven;
++	int8 roundIncrement, roundBits;
++	flag isTiny;
++
++	/* SH4 has only 2 rounding modes - round to nearest and round to zero */
++	roundNearestEven = (float_rounding_mode() == FPSCR_RM_NEAREST);
++	roundIncrement = 0x40;
++	if (!roundNearestEven) {
++		roundIncrement = 0;
++	}
++	roundBits = zSig & 0x7F;
++	if (0xFD <= (bits16) zExp) {
++		if ((0xFD < zExp)
++		    || ((zExp == 0xFD)
++			&& ((sbits32) (zSig + roundIncrement) < 0))
++		    ) {
++			float_raise(FPSCR_CAUSE_OVERFLOW | FPSCR_CAUSE_INEXACT);
++			return packFloat32(zSign, 0xFF,
++					   0) - (roundIncrement == 0);
++		}
++		if (zExp < 0) {
++			isTiny = (zExp < -1)
++			    || (zSig + roundIncrement < 0x80000000);
++			shift32RightJamming(zSig, -zExp, &zSig);
++			zExp = 0;
++			roundBits = zSig & 0x7F;
++			if (isTiny && roundBits)
++				float_raise(FPSCR_CAUSE_UNDERFLOW);
++		}
++	}
++	if (roundBits)
++		float_raise(FPSCR_CAUSE_INEXACT);
++	zSig = (zSig + roundIncrement) >> 7;
++	zSig &= ~(((roundBits ^ 0x40) == 0) & roundNearestEven);
++	if (zSig == 0)
++		zExp = 0;
++	return packFloat32(zSign, zExp, zSig);
++
++}
++
++static float32 normalizeRoundAndPackFloat32(flag zSign, int16 zExp, bits32 zSig)
++{
++	int8 shiftCount;
++
++	shiftCount = countLeadingZeros32(zSig) - 1;
++	return roundAndPackFloat32(zSign, zExp - shiftCount,
++				   zSig << shiftCount);
++}
++
++static float64 roundAndPackFloat64(flag zSign, int16 zExp, bits64 zSig)
++{
++	flag roundNearestEven;
++	int16 roundIncrement, roundBits;
++	flag isTiny;
++
++	/* SH4 has only 2 rounding modes - round to nearest and round to zero */
++	roundNearestEven = (float_rounding_mode() == FPSCR_RM_NEAREST);
++	roundIncrement = 0x200;
++	if (!roundNearestEven) {
++		roundIncrement = 0;
++	}
++	roundBits = zSig & 0x3FF;
++	if (0x7FD <= (bits16) zExp) {
++		if ((0x7FD < zExp)
++		    || ((zExp == 0x7FD)
++			&& ((sbits64) (zSig + roundIncrement) < 0))
++		    ) {
++			float_raise(FPSCR_CAUSE_OVERFLOW | FPSCR_CAUSE_INEXACT);
++			return packFloat64(zSign, 0x7FF,
++					   0) - (roundIncrement == 0);
++		}
++		if (zExp < 0) {
++			isTiny = (zExp < -1)
++			    || (zSig + roundIncrement <
++				LIT64(0x8000000000000000));
++			shift64RightJamming(zSig, -zExp, &zSig);
++			zExp = 0;
++			roundBits = zSig & 0x3FF;
++			if (isTiny && roundBits)
++				float_raise(FPSCR_CAUSE_UNDERFLOW);
++		}
++	}
++	if (roundBits)
++		float_raise(FPSCR_CAUSE_INEXACT);
++	zSig = (zSig + roundIncrement) >> 10;
++	zSig &= ~(((roundBits ^ 0x200) == 0) & roundNearestEven);
++	if (zSig == 0)
++		zExp = 0;
++	return packFloat64(zSign, zExp, zSig);
++
++}
++
++static float32 subFloat32Sigs(float32 a, float32 b, flag zSign)
++{
++	int16 aExp, bExp, zExp;
++	bits32 aSig, bSig, zSig;
++	int16 expDiff;
++
++	aSig = extractFloat32Frac(a);
++	aExp = extractFloat32Exp(a);
++	bSig = extractFloat32Frac(b);
++	bExp = extractFloat32Exp(b);
++	expDiff = aExp - bExp;
++	aSig <<= 7;
++	bSig <<= 7;
++	if (0 < expDiff)
++		goto aExpBigger;
++	if (expDiff < 0)
++		goto bExpBigger;
++	if (aExp == 0) {
++		aExp = 1;
++		bExp = 1;
++	}
++	if (bSig < aSig)
++		goto aBigger;
++	if (aSig < bSig)
++		goto bBigger;
++	return packFloat32(float_rounding_mode() == FPSCR_RM_ZERO, 0, 0);
++      bExpBigger:
++	if (bExp == 0xFF) {
++		return packFloat32(zSign ^ 1, 0xFF, 0);
++	}
++	if (aExp == 0) {
++		++expDiff;
++	} else {
++		aSig |= 0x40000000;
++	}
++	shift32RightJamming(aSig, -expDiff, &aSig);
++	bSig |= 0x40000000;
++      bBigger:
++	zSig = bSig - aSig;
++	zExp = bExp;
++	zSign ^= 1;
++	goto normalizeRoundAndPack;
++      aExpBigger:
++	if (aExp == 0xFF) {
++		return a;
++	}
++	if (bExp == 0) {
++		--expDiff;
++	} else {
++		bSig |= 0x40000000;
++	}
++	shift32RightJamming(bSig, expDiff, &bSig);
++	aSig |= 0x40000000;
++      aBigger:
++	zSig = aSig - bSig;
++	zExp = aExp;
++      normalizeRoundAndPack:
++	--zExp;
++	return normalizeRoundAndPackFloat32(zSign, zExp, zSig);
++
++}
++
++static float32 addFloat32Sigs(float32 a, float32 b, flag zSign)
++{
++	int16 aExp, bExp, zExp;
++	bits32 aSig, bSig, zSig;
++	int16 expDiff;
++
++	aSig = extractFloat32Frac(a);
++	aExp = extractFloat32Exp(a);
++	bSig = extractFloat32Frac(b);
++	bExp = extractFloat32Exp(b);
++	expDiff = aExp - bExp;
++	aSig <<= 6;
++	bSig <<= 6;
++	if (0 < expDiff) {
++		if (aExp == 0xFF) {
++			return a;
++		}
++		if (bExp == 0) {
++			--expDiff;
++		} else {
++			bSig |= 0x20000000;
++		}
++		shift32RightJamming(bSig, expDiff, &bSig);
++		zExp = aExp;
++	} else if (expDiff < 0) {
++		if (bExp == 0xFF) {
++			return packFloat32(zSign, 0xFF, 0);
++		}
++		if (aExp == 0) {
++			++expDiff;
++		} else {
++			aSig |= 0x20000000;
++		}
++		shift32RightJamming(aSig, -expDiff, &aSig);
++		zExp = bExp;
++	} else {
++		if (aExp == 0xFF) {
++			return a;
++		}
++		if (aExp == 0)
++			return packFloat32(zSign, 0, (aSig + bSig) >> 6);
++		zSig = 0x40000000 + aSig + bSig;
++		zExp = aExp;
++		goto roundAndPack;
++	}
++	aSig |= 0x20000000;
++	zSig = (aSig + bSig) << 1;
++	--zExp;
++	if ((sbits32) zSig < 0) {
++		zSig = aSig + bSig;
++		++zExp;
++	}
++      roundAndPack:
++	return roundAndPackFloat32(zSign, zExp, zSig);
++
++}
++
++float64 float64_sub(float64 a, float64 b)
++{
++	flag aSign, bSign;
++
++	aSign = extractFloat64Sign(a);
++	bSign = extractFloat64Sign(b);
++	if (aSign == bSign) {
++		return subFloat64Sigs(a, b, aSign);
++	} else {
++		return addFloat64Sigs(a, b, aSign);
++	}
++
++}
++
++float32 float32_sub(float32 a, float32 b)
++{
++	flag aSign, bSign;
++
++	aSign = extractFloat32Sign(a);
++	bSign = extractFloat32Sign(b);
++	if (aSign == bSign) {
++		return subFloat32Sigs(a, b, aSign);
++	} else {
++		return addFloat32Sigs(a, b, aSign);
++	}
++
++}
++
++float32 float32_add(float32 a, float32 b)
++{
++	flag aSign, bSign;
++
++	aSign = extractFloat32Sign(a);
++	bSign = extractFloat32Sign(b);
++	if (aSign == bSign) {
++		return addFloat32Sigs(a, b, aSign);
++	} else {
++		return subFloat32Sigs(a, b, aSign);
++	}
++
++}
++
++float64 float64_add(float64 a, float64 b)
++{
++	flag aSign, bSign;
++
++	aSign = extractFloat64Sign(a);
++	bSign = extractFloat64Sign(b);
++	if (aSign == bSign) {
++		return addFloat64Sigs(a, b, aSign);
++	} else {
++		return subFloat64Sigs(a, b, aSign);
++	}
++}
++
++static void
++normalizeFloat64Subnormal(bits64 aSig, int16 * zExpPtr, bits64 * zSigPtr)
++{
++	int8 shiftCount;
++
++	shiftCount = countLeadingZeros64(aSig) - 11;
++	*zSigPtr = aSig << shiftCount;
++	*zExpPtr = 1 - shiftCount;
++}
++
++inline void add128(bits64 a0, bits64 a1, bits64 b0, bits64 b1, bits64 * z0Ptr,
++		   bits64 * z1Ptr)
++{
++	bits64 z1;
++
++	z1 = a1 + b1;
++	*z1Ptr = z1;
++	*z0Ptr = a0 + b0 + (z1 < a1);
++}
++
++inline void
++sub128(bits64 a0, bits64 a1, bits64 b0, bits64 b1, bits64 * z0Ptr,
++       bits64 * z1Ptr)
++{
++	*z1Ptr = a1 - b1;
++	*z0Ptr = a0 - b0 - (a1 < b1);
++}
++
++static bits64 estimateDiv128To64(bits64 a0, bits64 a1, bits64 b)
++{
++	bits64 b0, b1;
++	bits64 rem0, rem1, term0, term1;
++	bits64 z;
++	if (b <= a0)
++		return LIT64(0xFFFFFFFFFFFFFFFF);
++	b0 = b >> 32;
++	z = (b0 << 32 <= a0) ? LIT64(0xFFFFFFFF00000000) : (a0 / b0) << 32;
++	mul64To128(b, z, &term0, &term1);
++	sub128(a0, a1, term0, term1, &rem0, &rem1);
++	while (((sbits64) rem0) < 0) {
++		z -= LIT64(0x100000000);
++		b1 = b << 32;
++		add128(rem0, rem1, b0, b1, &rem0, &rem1);
++	}
++	rem0 = (rem0 << 32) | (rem1 >> 32);
++	z |= (b0 << 32 <= rem0) ? 0xFFFFFFFF : rem0 / b0;
++	return z;
++}
++
++inline void mul64To128(bits64 a, bits64 b, bits64 * z0Ptr, bits64 * z1Ptr)
++{
++	bits32 aHigh, aLow, bHigh, bLow;
++	bits64 z0, zMiddleA, zMiddleB, z1;
++
++	aLow = a;
++	aHigh = a >> 32;
++	bLow = b;
++	bHigh = b >> 32;
++	z1 = ((bits64) aLow) * bLow;
++	zMiddleA = ((bits64) aLow) * bHigh;
++	zMiddleB = ((bits64) aHigh) * bLow;
++	z0 = ((bits64) aHigh) * bHigh;
++	zMiddleA += zMiddleB;
++	z0 += (((bits64) (zMiddleA < zMiddleB)) << 32) + (zMiddleA >> 32);
++	zMiddleA <<= 32;
++	z1 += zMiddleA;
++	z0 += (z1 < zMiddleA);
++	*z1Ptr = z1;
++	*z0Ptr = z0;
++
++}
++
++static void normalizeFloat32Subnormal(bits32 aSig, int16 * zExpPtr,
++				      bits32 * zSigPtr)
++{
++	int8 shiftCount;
++
++	shiftCount = countLeadingZeros32(aSig) - 8;
++	*zSigPtr = aSig << shiftCount;
++	*zExpPtr = 1 - shiftCount;
++
++}
++
++float64 float64_div(float64 a, float64 b)
++{
++	flag aSign, bSign, zSign;
++	int16 aExp, bExp, zExp;
++	bits64 aSig, bSig, zSig;
++	bits64 rem0, rem1;
++	bits64 term0, term1;
++
++	aSig = extractFloat64Frac(a);
++	aExp = extractFloat64Exp(a);
++	aSign = extractFloat64Sign(a);
++	bSig = extractFloat64Frac(b);
++	bExp = extractFloat64Exp(b);
++	bSign = extractFloat64Sign(b);
++	zSign = aSign ^ bSign;
++	if (aExp == 0x7FF) {
++		if (bExp == 0x7FF) {
++		}
++		return packFloat64(zSign, 0x7FF, 0);
++	}
++	if (bExp == 0x7FF) {
++		return packFloat64(zSign, 0, 0);
++	}
++	if (bExp == 0) {
++		if (bSig == 0) {
++			if ((aExp | aSig) == 0) {
++				float_raise(FPSCR_CAUSE_INVALID);
++			}
++			return packFloat64(zSign, 0x7FF, 0);
++		}
++		normalizeFloat64Subnormal(bSig, &bExp, &bSig);
++	}
++	if (aExp == 0) {
++		if (aSig == 0)
++			return packFloat64(zSign, 0, 0);
++		normalizeFloat64Subnormal(aSig, &aExp, &aSig);
++	}
++	zExp = aExp - bExp + 0x3FD;
++	aSig = (aSig | LIT64(0x0010000000000000)) << 10;
++	bSig = (bSig | LIT64(0x0010000000000000)) << 11;
++	if (bSig <= (aSig + aSig)) {
++		aSig >>= 1;
++		++zExp;
++	}
++	zSig = estimateDiv128To64(aSig, 0, bSig);
++	if ((zSig & 0x1FF) <= 2) {
++		mul64To128(bSig, zSig, &term0, &term1);
++		sub128(aSig, 0, term0, term1, &rem0, &rem1);
++		while ((sbits64) rem0 < 0) {
++			--zSig;
++			add128(rem0, rem1, 0, bSig, &rem0, &rem1);
++		}
++		zSig |= (rem1 != 0);
++	}
++	return roundAndPackFloat64(zSign, zExp, zSig);
++
++}
++
++float32 float32_div(float32 a, float32 b)
++{
++	flag aSign, bSign, zSign;
++	int16 aExp, bExp, zExp;
++	bits32 aSig, bSig, zSig;
++
++	aSig = extractFloat32Frac(a);
++	aExp = extractFloat32Exp(a);
++	aSign = extractFloat32Sign(a);
++	bSig = extractFloat32Frac(b);
++	bExp = extractFloat32Exp(b);
++	bSign = extractFloat32Sign(b);
++	zSign = aSign ^ bSign;
++	if (aExp == 0xFF) {
++		if (bExp == 0xFF) {
++		}
++		return packFloat32(zSign, 0xFF, 0);
++	}
++	if (bExp == 0xFF) {
++		return packFloat32(zSign, 0, 0);
++	}
++	if (bExp == 0) {
++		if (bSig == 0) {
++			return packFloat32(zSign, 0xFF, 0);
++		}
++		normalizeFloat32Subnormal(bSig, &bExp, &bSig);
++	}
++	if (aExp == 0) {
++		if (aSig == 0)
++			return packFloat32(zSign, 0, 0);
++		normalizeFloat32Subnormal(aSig, &aExp, &aSig);
++	}
++	zExp = aExp - bExp + 0x7D;
++	aSig = (aSig | 0x00800000) << 7;
++	bSig = (bSig | 0x00800000) << 8;
++	if (bSig <= (aSig + aSig)) {
++		aSig >>= 1;
++		++zExp;
++	}
++	zSig = (((bits64) aSig) << 32) / bSig;
++	if ((zSig & 0x3F) == 0) {
++		zSig |= (((bits64) bSig) * zSig != ((bits64) aSig) << 32);
++	}
++	return roundAndPackFloat32(zSign, zExp, zSig);
++
++}
++
++float32 float32_mul(float32 a, float32 b)
++{
++	char aSign, bSign, zSign;
++	int aExp, bExp, zExp;
++	unsigned int aSig, bSig;
++	unsigned long long zSig64;
++	unsigned int zSig;
++
++	aSig = extractFloat32Frac(a);
++	aExp = extractFloat32Exp(a);
++	aSign = extractFloat32Sign(a);
++	bSig = extractFloat32Frac(b);
++	bExp = extractFloat32Exp(b);
++	bSign = extractFloat32Sign(b);
++	zSign = aSign ^ bSign;
++	if (aExp == 0) {
++		if (aSig == 0)
++			return packFloat32(zSign, 0, 0);
++		normalizeFloat32Subnormal(aSig, &aExp, &aSig);
++	}
++	if (bExp == 0) {
++		if (bSig == 0)
++			return packFloat32(zSign, 0, 0);
++		normalizeFloat32Subnormal(bSig, &bExp, &bSig);
++	}
++	if ((bExp == 0xff && bSig == 0) || (aExp == 0xff && aSig == 0))
++		return roundAndPackFloat32(zSign, 0xff, 0);
++
++	zExp = aExp + bExp - 0x7F;
++	aSig = (aSig | 0x00800000) << 7;
++	bSig = (bSig | 0x00800000) << 8;
++	shift64RightJamming(((unsigned long long)aSig) * bSig, 32, &zSig64);
++	zSig = zSig64;
++	if (0 <= (signed int)(zSig << 1)) {
++		zSig <<= 1;
++		--zExp;
++	}
++	return roundAndPackFloat32(zSign, zExp, zSig);
++
++}
++
++float64 float64_mul(float64 a, float64 b)
++{
++	char aSign, bSign, zSign;
++	int aExp, bExp, zExp;
++	unsigned long long int aSig, bSig, zSig0, zSig1;
++
++	aSig = extractFloat64Frac(a);
++	aExp = extractFloat64Exp(a);
++	aSign = extractFloat64Sign(a);
++	bSig = extractFloat64Frac(b);
++	bExp = extractFloat64Exp(b);
++	bSign = extractFloat64Sign(b);
++	zSign = aSign ^ bSign;
++
++	if (aExp == 0) {
++		if (aSig == 0)
++			return packFloat64(zSign, 0, 0);
++		normalizeFloat64Subnormal(aSig, &aExp, &aSig);
++	}
++	if (bExp == 0) {
++		if (bSig == 0)
++			return packFloat64(zSign, 0, 0);
++		normalizeFloat64Subnormal(bSig, &bExp, &bSig);
++	}
++	if ((aExp == 0x7ff && aSig == 0) || (bExp == 0x7ff && bSig == 0))
++		return roundAndPackFloat64(zSign, 0x7ff, 0);
++
++	zExp = aExp + bExp - 0x3FF;
++	aSig = (aSig | 0x0010000000000000LL) << 10;
++	bSig = (bSig | 0x0010000000000000LL) << 11;
++	mul64To128(aSig, bSig, &zSig0, &zSig1);
++	zSig0 |= (zSig1 != 0);
++	if (0 <= (signed long long int)(zSig0 << 1)) {
++		zSig0 <<= 1;
++		--zExp;
++	}
++	return roundAndPackFloat64(zSign, zExp, zSig0);
++}
+diff --git a/arch/sh/kernel/cpu/sh4/sq.c b/arch/sh/kernel/cpu/sh4/sq.c
+index b22a78c..3008c00 100644
+--- a/arch/sh/kernel/cpu/sh4/sq.c
++++ b/arch/sh/kernel/cpu/sh4/sq.c
+@@ -341,17 +341,18 @@ static int __devinit sq_sysdev_add(struct sys_device *sysdev)
+ {
+ 	unsigned int cpu = sysdev->id;
+ 	struct kobject *kobj;
++	int error;
+ 
+ 	sq_kobject[cpu] = kzalloc(sizeof(struct kobject), GFP_KERNEL);
+ 	if (unlikely(!sq_kobject[cpu]))
+ 		return -ENOMEM;
+ 
+ 	kobj = sq_kobject[cpu];
+-	kobj->parent = &sysdev->kobj;
+-	kobject_set_name(kobj, "%s", "sq");
+-	kobj->ktype = &ktype_percpu_entry;
+-
+-	return kobject_register(kobj);
++	error = kobject_init_and_add(kobj, &ktype_percpu_entry, &sysdev->kobj,
++				     "%s", "sq");
++	if (!error)
++		kobject_uevent(kobj, KOBJ_ADD);
++	return error;
+ }
+ 
+ static int __devexit sq_sysdev_remove(struct sys_device *sysdev)
+@@ -359,7 +360,7 @@ static int __devexit sq_sysdev_remove(struct sys_device *sysdev)
+ 	unsigned int cpu = sysdev->id;
+ 	struct kobject *kobj = sq_kobject[cpu];
+ 
+-	kobject_unregister(kobj);
++	kobject_put(kobj);
+ 	return 0;
+ }
+ 
+diff --git a/arch/sh/kernel/cpu/sh4a/Makefile b/arch/sh/kernel/cpu/sh4a/Makefile
+index 2453987..08ac638 100644
+--- a/arch/sh/kernel/cpu/sh4a/Makefile
++++ b/arch/sh/kernel/cpu/sh4a/Makefile
+@@ -3,6 +3,7 @@
+ #
+ 
+ # CPU subtype setup
++obj-$(CONFIG_CPU_SUBTYPE_SH7763)	+= setup-sh7763.o
+ obj-$(CONFIG_CPU_SUBTYPE_SH7770)	+= setup-sh7770.o
+ obj-$(CONFIG_CPU_SUBTYPE_SH7780)	+= setup-sh7780.o
+ obj-$(CONFIG_CPU_SUBTYPE_SH7785)	+= setup-sh7785.o
+@@ -14,6 +15,7 @@ obj-$(CONFIG_CPU_SUBTYPE_SHX3)		+= setup-shx3.o
+ smp-$(CONFIG_CPU_SUBTYPE_SHX3)		:= smp-shx3.o
+ 
+ # Primary on-chip clocks (common)
++clock-$(CONFIG_CPU_SUBTYPE_SH7763)	:= clock-sh7763.o
+ clock-$(CONFIG_CPU_SUBTYPE_SH7770)	:= clock-sh7770.o
+ clock-$(CONFIG_CPU_SUBTYPE_SH7780)	:= clock-sh7780.o
+ clock-$(CONFIG_CPU_SUBTYPE_SH7785)	:= clock-sh7785.o
+diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7763.c b/arch/sh/kernel/cpu/sh4a/clock-sh7763.c
+new file mode 100644
+index 0000000..45889d4
+--- /dev/null
++++ b/arch/sh/kernel/cpu/sh4a/clock-sh7763.c
+@@ -0,0 +1,126 @@
++/*
++ * arch/sh/kernel/cpu/sh4a/clock-sh7763.c
++ *
++ * SH7763 support for the clock framework
++ *
++ *  Copyright (C) 2005  Paul Mundt
++ *  Copyright (C) 2007  Yoshihiro Shimoda
++ *
++ * 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/kernel.h>
++#include <asm/clock.h>
++#include <asm/freq.h>
++#include <asm/io.h>
++
++static int bfc_divisors[] = { 1, 1, 1, 8, 1, 1, 1, 1 };
++static int p0fc_divisors[] = { 1, 1, 1, 8, 1, 1, 1, 1 };
++static int p1fc_divisors[] = { 1, 1, 1, 16, 1, 1, 1, 1 };
++static int cfc_divisors[] = { 1, 1, 4, 1, 1, 1, 1, 1 };
++
++static void master_clk_init(struct clk *clk)
++{
++	clk->rate *= p0fc_divisors[(ctrl_inl(FRQCR) >> 4) & 0x07];
++}
++
++static struct clk_ops sh7763_master_clk_ops = {
++	.init		= master_clk_init,
++};
++
++static void module_clk_recalc(struct clk *clk)
++{
++	int idx = ((ctrl_inl(FRQCR) >> 4) & 0x07);
++	clk->rate = clk->parent->rate / p0fc_divisors[idx];
++}
++
++static struct clk_ops sh7763_module_clk_ops = {
++	.recalc		= module_clk_recalc,
++};
++
++static void bus_clk_recalc(struct clk *clk)
++{
++	int idx = ((ctrl_inl(FRQCR) >> 16) & 0x07);
++	clk->rate = clk->parent->rate / bfc_divisors[idx];
++}
++
++static struct clk_ops sh7763_bus_clk_ops = {
++	.recalc		= bus_clk_recalc,
++};
++
++static void cpu_clk_recalc(struct clk *clk)
++{
++	clk->rate = clk->parent->rate;
++}
++
++static struct clk_ops sh7763_cpu_clk_ops = {
++	.recalc		= cpu_clk_recalc,
++};
++
++static struct clk_ops *sh7763_clk_ops[] = {
++	&sh7763_master_clk_ops,
++	&sh7763_module_clk_ops,
++	&sh7763_bus_clk_ops,
++	&sh7763_cpu_clk_ops,
++};
++
++void __init arch_init_clk_ops(struct clk_ops **ops, int idx)
++{
++	if (idx < ARRAY_SIZE(sh7763_clk_ops))
++		*ops = sh7763_clk_ops[idx];
++}
++
++static void shyway_clk_recalc(struct clk *clk)
++{
++	int idx = ((ctrl_inl(FRQCR) >> 20) & 0x07);
++	clk->rate = clk->parent->rate / cfc_divisors[idx];
++}
++
++static struct clk_ops sh7763_shyway_clk_ops = {
++	.recalc		= shyway_clk_recalc,
++};
++
++static struct clk sh7763_shyway_clk = {
++	.name		= "shyway_clk",
++	.flags		= CLK_ALWAYS_ENABLED,
++	.ops		= &sh7763_shyway_clk_ops,
++};
++
++/*
++ * Additional SH7763-specific on-chip clocks that aren't already part of the
++ * clock framework
++ */
++static struct clk *sh7763_onchip_clocks[] = {
++	&sh7763_shyway_clk,
++};
++
++static int __init sh7763_clk_init(void)
++{
++	struct clk *clk = clk_get(NULL, "master_clk");
++	int i;
++
++	for (i = 0; i < ARRAY_SIZE(sh7763_onchip_clocks); i++) {
++		struct clk *clkp = sh7763_onchip_clocks[i];
++
++		clkp->parent = clk;
++		clk_register(clkp);
++		clk_enable(clkp);
++	}
++
++	/*
++	 * Now that we have the rest of the clocks registered, we need to
++	 * force the parent clock to propagate so that these clocks will
++	 * automatically figure out their rate. We cheat by handing the
++	 * parent clock its current rate and forcing child propagation.
++	 */
++	clk_set_rate(clk, clk_get_rate(clk));
++
++	clk_put(clk);
++
++	return 0;
++}
++
++arch_initcall(sh7763_clk_init);
++
+diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7722.c b/arch/sh/kernel/cpu/sh4a/setup-sh7722.c
+index b9c6547..73c778d 100644
+--- a/arch/sh/kernel/cpu/sh4a/setup-sh7722.c
++++ b/arch/sh/kernel/cpu/sh4a/setup-sh7722.c
+@@ -157,14 +157,6 @@ static struct intc_group groups[] __initdata = {
+ 	INTC_GROUP(SDHI, SDHI0, SDHI1, SDHI2, SDHI3),
+ };
+ 
+-static struct intc_prio priorities[] __initdata = {
+-	INTC_PRIO(SCIF0, 3),
+-	INTC_PRIO(SCIF1, 3),
+-	INTC_PRIO(SCIF2, 3),
+-	INTC_PRIO(TMU0, 2),
+-	INTC_PRIO(TMU1, 2),
+-};
+-
+ static struct intc_mask_reg mask_registers[] __initdata = {
+ 	{ 0xa4080080, 0xa40800c0, 8, /* IMR0 / IMCR0 */
+ 	  { } },
+@@ -217,7 +209,7 @@ static struct intc_sense_reg sense_registers[] __initdata = {
+ 	  { IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7 } },
+ };
+ 
+-static DECLARE_INTC_DESC(intc_desc, "sh7722", vectors, groups, priorities,
++static DECLARE_INTC_DESC(intc_desc, "sh7722", vectors, groups,
+ 			 mask_registers, prio_registers, sense_registers);
+ 
+ void __init plat_irq_setup(void)
+diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7763.c b/arch/sh/kernel/cpu/sh4a/setup-sh7763.c
+new file mode 100644
+index 0000000..eabd538
+--- /dev/null
++++ b/arch/sh/kernel/cpu/sh4a/setup-sh7763.c
+@@ -0,0 +1,390 @@
++/*
++ * SH7763 Setup
++ *
++ *  Copyright (C) 2006  Paul Mundt
++ *  Copyright (C) 2007  Yoshihiro Shimoda
++ *
++ * 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/platform_device.h>
++#include <linux/init.h>
++#include <linux/serial.h>
++#include <linux/io.h>
++#include <asm/sci.h>
++
++static struct resource rtc_resources[] = {
++	[0] = {
++		.start	= 0xffe80000,
++		.end	= 0xffe80000 + 0x58 - 1,
++		.flags	= IORESOURCE_IO,
++	},
++	[1] = {
++		/* Period IRQ */
++		.start	= 21,
++		.flags	= IORESOURCE_IRQ,
++	},
++	[2] = {
++		/* Carry IRQ */
++		.start	= 22,
++		.flags	= IORESOURCE_IRQ,
++	},
++	[3] = {
++		/* Alarm IRQ */
++		.start	= 20,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device rtc_device = {
++	.name		= "sh-rtc",
++	.id		= -1,
++	.num_resources	= ARRAY_SIZE(rtc_resources),
++	.resource	= rtc_resources,
++};
++
++static struct plat_sci_port sci_platform_data[] = {
++	{
++		.mapbase	= 0xffe00000,
++		.flags		= UPF_BOOT_AUTOCONF,
++		.type		= PORT_SCIF,
++		.irqs		= { 40, 41, 43, 42 },
++	}, {
++		.mapbase	= 0xffe08000,
++		.flags		= UPF_BOOT_AUTOCONF,
++		.type		= PORT_SCIF,
++		.irqs		= { 76, 77, 79, 78 },
++	}, {
++		.flags = 0,
++	}
++};
++
++static struct platform_device sci_device = {
++	.name		= "sh-sci",
++	.id		= -1,
++	.dev		= {
++		.platform_data	= sci_platform_data,
++	},
++};
++
++static struct resource usb_ohci_resources[] = {
++	[0] = {
++		.start	= 0xffec8000,
++		.end	= 0xffec80ff,
++		.flags	= IORESOURCE_MEM,
++	},
++	[1] = {
++		.start	= 83,
++		.end	= 83,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static u64 usb_ohci_dma_mask = 0xffffffffUL;
++static struct platform_device usb_ohci_device = {
++	.name		= "sh_ohci",
++	.id		= -1,
++	.dev = {
++		.dma_mask		= &usb_ohci_dma_mask,
++		.coherent_dma_mask	= 0xffffffff,
++	},
++	.num_resources	= ARRAY_SIZE(usb_ohci_resources),
++	.resource	= usb_ohci_resources,
++};
++
++static struct resource usbf_resources[] = {
++	[0] = {
++		.start	= 0xffec0000,
++		.end	= 0xffec00ff,
++		.flags	= IORESOURCE_MEM,
++	},
++	[1] = {
++		.start	= 84,
++		.end	= 84,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device usbf_device = {
++	.name		= "sh_udc",
++	.id		= -1,
++	.dev = {
++		.dma_mask		= NULL,
++		.coherent_dma_mask	= 0xffffffff,
++	},
++	.num_resources	= ARRAY_SIZE(usbf_resources),
++	.resource	= usbf_resources,
++};
++
++static struct platform_device *sh7763_devices[] __initdata = {
++	&rtc_device,
++	&sci_device,
++	&usb_ohci_device,
++	&usbf_device,
++};
++
++static int __init sh7763_devices_setup(void)
++{
++	return platform_add_devices(sh7763_devices,
++				    ARRAY_SIZE(sh7763_devices));
++}
++__initcall(sh7763_devices_setup);
++
++enum {
++	UNUSED = 0,
++
++	/* interrupt sources */
++
++	IRL_LLLL, IRL_LLLH, IRL_LLHL, IRL_LLHH,
++	IRL_LHLL, IRL_LHLH, IRL_LHHL, IRL_LHHH,
++	IRL_HLLL, IRL_HLLH, IRL_HLHL, IRL_HLHH,
++	IRL_HHLL, IRL_HHLH, IRL_HHHL,
++
++	IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7,
++	RTC_ATI, RTC_PRI, RTC_CUI,
++	WDT, TMU0, TMU1, TMU2, TMU2_TICPI,
++	HUDI, LCDC,
++	DMAC0_DMINT0, DMAC0_DMINT1, DMAC0_DMINT2, DMAC0_DMINT3, DMAC0_DMAE,
++	SCIF0_ERI, SCIF0_RXI, SCIF0_BRI, SCIF0_TXI,
++	DMAC0_DMINT4, DMAC0_DMINT5,
++	IIC0, IIC1,
++	CMT,
++	GEINT0, GEINT1, GEINT2,
++	HAC,
++	PCISERR, PCIINTA, PCIINTB, PCIINTC, PCIINTD,
++	PCIERR, PCIPWD3, PCIPWD2, PCIPWD1, PCIPWD0,
++	STIF0, STIF1,
++	SCIF1_ERI, SCIF1_RXI, SCIF1_BRI, SCIF1_TXI,
++	SIOF0, SIOF1, SIOF2,
++	USBH, USBFI0, USBFI1,
++	TPU, PCC,
++	MMCIF_FSTAT, MMCIF_TRAN, MMCIF_ERR, MMCIF_FRDY,
++	SIM_ERI, SIM_RXI, SIM_TXI, SIM_TEND,
++	TMU3, TMU4, TMU5, ADC, SSI0, SSI1, SSI2, SSI3,
++	SCIF2_ERI, SCIF2_RXI, SCIF2_BRI, SCIF2_TXI,
++	GPIO_CH0, GPIO_CH1, GPIO_CH2, GPIO_CH3,
++
++	/* interrupt groups */
++
++	TMU012, TMU345, RTC, DMAC, SCIF0, GETHER, PCIC5,
++	SCIF1, USBF, MMCIF, SIM, SCIF2, GPIO,
++};
++
++static struct intc_vect vectors[] __initdata = {
++	INTC_VECT(RTC_ATI, 0x480), INTC_VECT(RTC_PRI, 0x4a0),
++	INTC_VECT(RTC_CUI, 0x4c0),
++	INTC_VECT(WDT, 0x560), INTC_VECT(TMU0, 0x580),
++	INTC_VECT(TMU1, 0x5a0), INTC_VECT(TMU2, 0x5c0),
++	INTC_VECT(TMU2_TICPI, 0x5e0), INTC_VECT(HUDI, 0x600),
++	INTC_VECT(LCDC, 0x620),
++	INTC_VECT(DMAC0_DMINT0, 0x640), INTC_VECT(DMAC0_DMINT1, 0x660),
++	INTC_VECT(DMAC0_DMINT2, 0x680), INTC_VECT(DMAC0_DMINT3, 0x6a0),
++	INTC_VECT(DMAC0_DMAE, 0x6c0),
++	INTC_VECT(SCIF0_ERI, 0x700), INTC_VECT(SCIF0_RXI, 0x720),
++	INTC_VECT(SCIF0_BRI, 0x740), INTC_VECT(SCIF0_TXI, 0x760),
++	INTC_VECT(DMAC0_DMINT4, 0x780), INTC_VECT(DMAC0_DMINT5, 0x7a0),
++	INTC_VECT(IIC0, 0x8A0), INTC_VECT(IIC1, 0x8C0),
++	INTC_VECT(CMT, 0x900), INTC_VECT(GEINT0, 0x920),
++	INTC_VECT(GEINT1, 0x940), INTC_VECT(GEINT2, 0x960),
++	INTC_VECT(HAC, 0x980),
++	INTC_VECT(PCISERR, 0xa00), INTC_VECT(PCIINTA, 0xa20),
++	INTC_VECT(PCIINTB, 0xa40), INTC_VECT(PCIINTC, 0xa60),
++	INTC_VECT(PCIINTD, 0xa80), INTC_VECT(PCIERR, 0xaa0),
++	INTC_VECT(PCIPWD3, 0xac0), INTC_VECT(PCIPWD2, 0xae0),
++	INTC_VECT(PCIPWD1, 0xb00), INTC_VECT(PCIPWD0, 0xb20),
++	INTC_VECT(STIF0, 0xb40), INTC_VECT(STIF1, 0xb60),
++	INTC_VECT(SCIF1_ERI, 0xb80), INTC_VECT(SCIF1_RXI, 0xba0),
++	INTC_VECT(SCIF1_BRI, 0xbc0), INTC_VECT(SCIF1_TXI, 0xbe0),
++	INTC_VECT(SIOF0, 0xc00), INTC_VECT(SIOF1, 0xc20),
++	INTC_VECT(USBH, 0xc60), INTC_VECT(USBFI0, 0xc80),
++	INTC_VECT(USBFI1, 0xca0),
++	INTC_VECT(TPU, 0xcc0), INTC_VECT(PCC, 0xce0),
++	INTC_VECT(MMCIF_FSTAT, 0xd00), INTC_VECT(MMCIF_TRAN, 0xd20),
++	INTC_VECT(MMCIF_ERR, 0xd40), INTC_VECT(MMCIF_FRDY, 0xd60),
++	INTC_VECT(SIM_ERI, 0xd80), INTC_VECT(SIM_RXI, 0xda0),
++	INTC_VECT(SIM_TXI, 0xdc0), INTC_VECT(SIM_TEND, 0xde0),
++	INTC_VECT(TMU3, 0xe00), INTC_VECT(TMU4, 0xe20),
++	INTC_VECT(TMU5, 0xe40), INTC_VECT(ADC, 0xe60),
++	INTC_VECT(SSI0, 0xe80), INTC_VECT(SSI1, 0xea0),
++	INTC_VECT(SSI2, 0xec0), INTC_VECT(SSI3, 0xee0),
++	INTC_VECT(SCIF1_ERI, 0xf00), INTC_VECT(SCIF1_RXI, 0xf20),
++	INTC_VECT(SCIF1_BRI, 0xf40), INTC_VECT(SCIF1_TXI, 0xf60),
++	INTC_VECT(GPIO_CH0, 0xf80), INTC_VECT(GPIO_CH1, 0xfa0),
++	INTC_VECT(GPIO_CH2, 0xfc0), INTC_VECT(GPIO_CH3, 0xfe0),
++};
++
++static struct intc_group groups[] __initdata = {
++	INTC_GROUP(TMU012, TMU0, TMU1, TMU2, TMU2_TICPI),
++	INTC_GROUP(TMU345, TMU3, TMU4, TMU5),
++	INTC_GROUP(RTC, RTC_ATI, RTC_PRI, RTC_CUI),
++	INTC_GROUP(DMAC, DMAC0_DMINT0, DMAC0_DMINT1, DMAC0_DMINT2,
++		   DMAC0_DMINT3, DMAC0_DMINT4, DMAC0_DMINT5, DMAC0_DMAE),
++	INTC_GROUP(SCIF0, SCIF0_ERI, SCIF0_RXI, SCIF0_BRI, SCIF0_TXI),
++	INTC_GROUP(GETHER, GEINT0, GEINT1, GEINT2),
++	INTC_GROUP(PCIC5, PCIERR, PCIPWD3, PCIPWD2, PCIPWD1, PCIPWD0),
++	INTC_GROUP(SCIF1, SCIF1_ERI, SCIF1_RXI, SCIF1_BRI, SCIF1_TXI),
++	INTC_GROUP(USBF, USBFI0, USBFI1),
++	INTC_GROUP(MMCIF, MMCIF_FSTAT, MMCIF_TRAN, MMCIF_ERR, MMCIF_FRDY),
++	INTC_GROUP(SIM, SIM_ERI, SIM_RXI, SIM_TXI, SIM_TEND),
++	INTC_GROUP(SCIF2, SCIF2_ERI, SCIF2_RXI, SCIF2_BRI, SCIF2_TXI),
++	INTC_GROUP(GPIO, GPIO_CH0, GPIO_CH1, GPIO_CH2, GPIO_CH3),
++};
++
++static struct intc_prio priorities[] __initdata = {
++	INTC_PRIO(SCIF0, 3),
++	INTC_PRIO(SCIF1, 3),
++	INTC_PRIO(SCIF2, 3),
++};
++
++static struct intc_mask_reg mask_registers[] __initdata = {
++	{ 0xffd40038, 0xffd4003c, 32, /* INT2MSKR / INT2MSKCR */
++	  { 0, 0, 0, 0, 0, 0, GPIO, 0,
++	    SSI0, MMCIF, 0, SIOF0, PCIC5, PCIINTD, PCIINTC, PCIINTB,
++	    PCIINTA, PCISERR, HAC, CMT, 0, 0, 0, DMAC,
++	    HUDI, 0, WDT, SCIF1, SCIF0, RTC, TMU345, TMU012 } },
++	{ 0xffd400d0, 0xffd400d4, 32, /* INT2MSKR1 / INT2MSKCR1 */
++	  { 0, 0, 0, 0, 0, 0, SCIF2, USBF,
++	    0, 0, STIF1, STIF0, 0, 0, USBH, GETHER,
++	    PCC, 0, 0, ADC, TPU, SIM, SIOF2, SIOF1,
++	    LCDC, 0, IIC1, IIC0, SSI3, SSI2, SSI1, 0 } },
++};
++
++static struct intc_prio_reg prio_registers[] __initdata = {
++	{ 0xffd40000, 0, 32, 8, /* INT2PRI0 */ { TMU0, TMU1,
++						 TMU2, TMU2_TICPI } },
++	{ 0xffd40004, 0, 32, 8, /* INT2PRI1 */ { TMU3, TMU4, TMU5, RTC } },
++	{ 0xffd40008, 0, 32, 8, /* INT2PRI2 */ { SCIF0, SCIF1, WDT } },
++	{ 0xffd4000c, 0, 32, 8, /* INT2PRI3 */ { HUDI, DMAC, ADC } },
++	{ 0xffd40010, 0, 32, 8, /* INT2PRI4 */ { CMT, HAC,
++						 PCISERR, PCIINTA } },
++	{ 0xffd40014, 0, 32, 8, /* INT2PRI5 */ { PCIINTB, PCIINTC,
++						 PCIINTD, PCIC5 } },
++	{ 0xffd40018, 0, 32, 8, /* INT2PRI6 */ { SIOF0, USBF, MMCIF, SSI0 } },
++	{ 0xffd4001c, 0, 32, 8, /* INT2PRI7 */ { SCIF2, GPIO } },
++	{ 0xffd400a0, 0, 32, 8, /* INT2PRI8 */ { SSI3, SSI2, SSI1, 0 } },
++	{ 0xffd400a4, 0, 32, 8, /* INT2PRI9 */ { LCDC, 0, IIC1, IIC0 } },
++	{ 0xffd400a8, 0, 32, 8, /* INT2PRI10 */ { TPU, SIM, SIOF2, SIOF1 } },
++	{ 0xffd400ac, 0, 32, 8, /* INT2PRI11 */ { PCC } },
++	{ 0xffd400b0, 0, 32, 8, /* INT2PRI12 */ { 0, 0, USBH, GETHER } },
++	{ 0xffd400b4, 0, 32, 8, /* INT2PRI13 */ { 0, 0, STIF1, STIF0 } },
++};
++
++static DECLARE_INTC_DESC(intc_desc, "sh7763", vectors, groups, priorities,
++			 mask_registers, prio_registers, NULL);
++
++/* Support for external interrupt pins in IRQ mode */
++
++static struct intc_vect irq_vectors[] __initdata = {
++	INTC_VECT(IRQ0, 0x240), INTC_VECT(IRQ1, 0x280),
++	INTC_VECT(IRQ2, 0x2c0), INTC_VECT(IRQ3, 0x300),
++	INTC_VECT(IRQ4, 0x340), INTC_VECT(IRQ5, 0x380),
++	INTC_VECT(IRQ6, 0x3c0), INTC_VECT(IRQ7, 0x200),
++};
++
++static struct intc_mask_reg irq_mask_registers[] __initdata = {
++	{ 0xffd00044, 0xffd00064, 32, /* INTMSK0 / INTMSKCLR0 */
++	  { IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7 } },
++};
++
++static struct intc_prio_reg irq_prio_registers[] __initdata = {
++	{ 0xffd00010, 0, 32, 4, /* INTPRI */ { IRQ0, IRQ1, IRQ2, IRQ3,
++					       IRQ4, IRQ5, IRQ6, IRQ7 } },
++};
++
++static struct intc_sense_reg irq_sense_registers[] __initdata = {
++	{ 0xffd0001c, 32, 2, /* ICR1 */   { IRQ0, IRQ1, IRQ2, IRQ3,
++					    IRQ4, IRQ5, IRQ6, IRQ7 } },
++};
++
++static DECLARE_INTC_DESC(intc_irq_desc, "sh7763-irq", irq_vectors,
++			 NULL, NULL, irq_mask_registers, irq_prio_registers,
++			 irq_sense_registers);
++
++/* External interrupt pins in IRL mode */
++
++static struct intc_vect irl_vectors[] __initdata = {
++	INTC_VECT(IRL_LLLL, 0x200), INTC_VECT(IRL_LLLH, 0x220),
++	INTC_VECT(IRL_LLHL, 0x240), INTC_VECT(IRL_LLHH, 0x260),
++	INTC_VECT(IRL_LHLL, 0x280), INTC_VECT(IRL_LHLH, 0x2a0),
++	INTC_VECT(IRL_LHHL, 0x2c0), INTC_VECT(IRL_LHHH, 0x2e0),
++	INTC_VECT(IRL_HLLL, 0x300), INTC_VECT(IRL_HLLH, 0x320),
++	INTC_VECT(IRL_HLHL, 0x340), INTC_VECT(IRL_HLHH, 0x360),
++	INTC_VECT(IRL_HHLL, 0x380), INTC_VECT(IRL_HHLH, 0x3a0),
++	INTC_VECT(IRL_HHHL, 0x3c0),
++};
++
++static struct intc_mask_reg irl3210_mask_registers[] __initdata = {
++	{ 0xffd40080, 0xffd40084, 32, /* INTMSK2 / INTMSKCLR2 */
++	  { IRL_LLLL, IRL_LLLH, IRL_LLHL, IRL_LLHH,
++	    IRL_LHLL, IRL_LHLH, IRL_LHHL, IRL_LHHH,
++	    IRL_HLLL, IRL_HLLH, IRL_HLHL, IRL_HLHH,
++	    IRL_HHLL, IRL_HHLH, IRL_HHHL, } },
++};
++
++static struct intc_mask_reg irl7654_mask_registers[] __initdata = {
++	{ 0xffd40080, 0xffd40084, 32, /* INTMSK2 / INTMSKCLR2 */
++	  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
++	    IRL_LLLL, IRL_LLLH, IRL_LLHL, IRL_LLHH,
++	    IRL_LHLL, IRL_LHLH, IRL_LHHL, IRL_LHHH,
++	    IRL_HLLL, IRL_HLLH, IRL_HLHL, IRL_HLHH,
++	    IRL_HHLL, IRL_HHLH, IRL_HHHL, } },
++};
++
++static DECLARE_INTC_DESC(intc_irl7654_desc, "sh7763-irl7654", irl_vectors,
++			 NULL, NULL, irl7654_mask_registers, NULL, NULL);
++
++static DECLARE_INTC_DESC(intc_irl3210_desc, "sh7763-irl3210", irl_vectors,
++			 NULL, NULL, irl3210_mask_registers, NULL, NULL);
++
++#define INTC_ICR0	0xffd00000
++#define INTC_INTMSK0	0xffd00044
++#define INTC_INTMSK1	0xffd00048
++#define INTC_INTMSK2	0xffd40080
++#define INTC_INTMSKCLR1	0xffd00068
++#define INTC_INTMSKCLR2	0xffd40084
++
++void __init plat_irq_setup(void)
++{
++	/* disable IRQ7-0 */
++	ctrl_outl(0xff000000, INTC_INTMSK0);
++
++	/* disable IRL3-0 + IRL7-4 */
++	ctrl_outl(0xc0000000, INTC_INTMSK1);
++	ctrl_outl(0xfffefffe, INTC_INTMSK2);
++
++	register_intc_controller(&intc_desc);
++}
++
++void __init plat_irq_setup_pins(int mode)
++{
++	switch (mode) {
++	case IRQ_MODE_IRQ:
++		/* select IRQ mode for IRL3-0 + IRL7-4 */
++		ctrl_outl(ctrl_inl(INTC_ICR0) | 0x00c00000, INTC_ICR0);
++		register_intc_controller(&intc_irq_desc);
++		break;
++	case IRQ_MODE_IRL7654:
++		/* enable IRL7-4 but don't provide any masking */
++		ctrl_outl(0x40000000, INTC_INTMSKCLR1);
++		ctrl_outl(0x0000fffe, INTC_INTMSKCLR2);
++		break;
++	case IRQ_MODE_IRL3210:
++		/* enable IRL0-3 but don't provide any masking */
++		ctrl_outl(0x80000000, INTC_INTMSKCLR1);
++		ctrl_outl(0xfffe0000, INTC_INTMSKCLR2);
++		break;
++	case IRQ_MODE_IRL7654_MASK:
++		/* enable IRL7-4 and mask using cpu intc controller */
++		ctrl_outl(0x40000000, INTC_INTMSKCLR1);
++		register_intc_controller(&intc_irl7654_desc);
++		break;
++	case IRQ_MODE_IRL3210_MASK:
++		/* enable IRL0-3 and mask using cpu intc controller */
++		ctrl_outl(0x80000000, INTC_INTMSKCLR1);
++		register_intc_controller(&intc_irl3210_desc);
++		break;
++	default:
++		BUG();
++	}
++}
+diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7780.c b/arch/sh/kernel/cpu/sh4a/setup-sh7780.c
+index e8fd33f..293004b 100644
+--- a/arch/sh/kernel/cpu/sh4a/setup-sh7780.c
++++ b/arch/sh/kernel/cpu/sh4a/setup-sh7780.c
+@@ -168,11 +168,6 @@ static struct intc_group groups[] __initdata = {
+ 	INTC_GROUP(GPIO, GPIOI0, GPIOI1, GPIOI2, GPIOI3),
+ };
+ 
+-static struct intc_prio priorities[] __initdata = {
+-	INTC_PRIO(SCIF0, 3),
+-	INTC_PRIO(SCIF1, 3),
+-};
+-
+ static struct intc_mask_reg mask_registers[] __initdata = {
+ 	{ 0xffd40038, 0xffd4003c, 32, /* INT2MSKR / INT2MSKCR */
+ 	  { 0, 0, 0, 0, 0, 0, GPIO, FLCTL,
+@@ -195,7 +190,7 @@ static struct intc_prio_reg prio_registers[] __initdata = {
+ 	{ 0xffd4001c, 0, 32, 8, /* INT2PRI7 */ { FLCTL, GPIO } },
+ };
+ 
+-static DECLARE_INTC_DESC(intc_desc, "sh7780", vectors, groups, priorities,
++static DECLARE_INTC_DESC(intc_desc, "sh7780", vectors, groups,
+ 			 mask_registers, prio_registers, NULL);
+ 
+ /* Support for external interrupt pins in IRQ mode */
+@@ -223,7 +218,7 @@ static struct intc_sense_reg irq_sense_registers[] __initdata = {
+ };
+ 
+ static DECLARE_INTC_DESC(intc_irq_desc, "sh7780-irq", irq_vectors,
+-			 NULL, NULL, irq_mask_registers, irq_prio_registers,
++			 NULL, irq_mask_registers, irq_prio_registers,
+ 			 irq_sense_registers);
+ 
+ /* External interrupt pins in IRL mode */
+@@ -257,10 +252,10 @@ static struct intc_mask_reg irl7654_mask_registers[] __initdata = {
+ };
+ 
+ static DECLARE_INTC_DESC(intc_irl7654_desc, "sh7780-irl7654", irl_vectors,
+-			 NULL, NULL, irl7654_mask_registers, NULL, NULL);
++			 NULL, irl7654_mask_registers, NULL, NULL);
+ 
+ static DECLARE_INTC_DESC(intc_irl3210_desc, "sh7780-irl3210", irl_vectors,
+-			 NULL, NULL, irl3210_mask_registers, NULL, NULL);
++			 NULL, irl3210_mask_registers, NULL, NULL);
+ 
+ #define INTC_ICR0	0xffd00000
+ #define INTC_INTMSK0	0xffd00044
+diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7785.c b/arch/sh/kernel/cpu/sh4a/setup-sh7785.c
+index 39b215d..74b60e9 100644
+--- a/arch/sh/kernel/cpu/sh4a/setup-sh7785.c
++++ b/arch/sh/kernel/cpu/sh4a/setup-sh7785.c
+@@ -178,15 +178,6 @@ static struct intc_group groups[] __initdata = {
+ 	INTC_GROUP(GPIO, GPIOI0, GPIOI1, GPIOI2, GPIOI3),
+ };
+ 
+-static struct intc_prio priorities[] __initdata = {
+-	INTC_PRIO(SCIF0, 3),
+-	INTC_PRIO(SCIF1, 3),
+-	INTC_PRIO(SCIF2, 3),
+-	INTC_PRIO(SCIF3, 3),
+-	INTC_PRIO(SCIF4, 3),
+-	INTC_PRIO(SCIF5, 3),
+-};
+-
+ static struct intc_mask_reg mask_registers[] __initdata = {
+ 	{ 0xffd00044, 0xffd00064, 32, /* INTMSK0 / INTMSKCLR0 */
+ 	  { IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7 } },
+@@ -227,7 +218,7 @@ static struct intc_prio_reg prio_registers[] __initdata = {
+ 	{ 0xffd40024, 0, 32, 8, /* INT2PRI9 */ { DU, GDTA, } },
+ };
+ 
+-static DECLARE_INTC_DESC(intc_desc, "sh7785", vectors, groups, priorities,
++static DECLARE_INTC_DESC(intc_desc, "sh7785", vectors, groups,
+ 			 mask_registers, prio_registers, NULL);
+ 
+ /* Support for external interrupt pins in IRQ mode */
+@@ -248,11 +239,11 @@ static struct intc_sense_reg sense_registers[] __initdata = {
+ };
+ 
+ static DECLARE_INTC_DESC(intc_desc_irq0123, "sh7785-irq0123", vectors_irq0123,
+-			 NULL, NULL, mask_registers, prio_registers,
++			 NULL, mask_registers, prio_registers,
+ 			 sense_registers);
+ 
+ static DECLARE_INTC_DESC(intc_desc_irq4567, "sh7785-irq4567", vectors_irq4567,
+-			 NULL, NULL, mask_registers, prio_registers,
++			 NULL, mask_registers, prio_registers,
+ 			 sense_registers);
+ 
+ /* External interrupt pins in IRL mode */
+@@ -280,10 +271,10 @@ static struct intc_vect vectors_irl4567[] __initdata = {
+ };
+ 
+ static DECLARE_INTC_DESC(intc_desc_irl0123, "sh7785-irl0123", vectors_irl0123,
+-			 NULL, NULL, mask_registers, NULL, NULL);
++			 NULL, mask_registers, NULL, NULL);
+ 
+ static DECLARE_INTC_DESC(intc_desc_irl4567, "sh7785-irl4567", vectors_irl4567,
+-			 NULL, NULL, mask_registers, NULL, NULL);
++			 NULL, mask_registers, NULL, NULL);
+ 
+ #define INTC_ICR0	0xffd00000
+ #define INTC_INTMSK0	0xffd00044
+diff --git a/arch/sh/kernel/cpu/sh4a/setup-shx3.c b/arch/sh/kernel/cpu/sh4a/setup-shx3.c
+index c6cdd7e..4dc958b 100644
+--- a/arch/sh/kernel/cpu/sh4a/setup-shx3.c
++++ b/arch/sh/kernel/cpu/sh4a/setup-shx3.c
+@@ -165,13 +165,6 @@ static struct intc_group groups[] __initdata = {
+ 	INTC_GROUP(DTU3, DTU3_TEND, DTU3_AE, DTU3_TMISS),
+ };
+ 
+-static struct intc_prio priorities[] __initdata = {
+-	INTC_PRIO(SCIF0, 3),
+-	INTC_PRIO(SCIF1, 3),
+-	INTC_PRIO(SCIF2, 3),
+-	INTC_PRIO(SCIF3, 3),
+-};
+-
+ static struct intc_mask_reg mask_registers[] __initdata = {
+ 	{ 0xfe410030, 0xfe410050, 32, /* CnINTMSK0 / CnINTMSKCLR0 */
+ 	  { IRQ0, IRQ1, IRQ2, IRQ3 } },
+@@ -218,7 +211,7 @@ static struct intc_prio_reg prio_registers[] __initdata = {
+ 	    INTICI3, INTICI2, INTICI1, INTICI0 }, INTC_SMP(4, 4) },
+ };
+ 
+-static DECLARE_INTC_DESC(intc_desc, "shx3", vectors, groups, priorities,
++static DECLARE_INTC_DESC(intc_desc, "shx3", vectors, groups,
+ 			 mask_registers, prio_registers, NULL);
+ 
+ /* Support for external interrupt pins in IRQ mode */
+@@ -232,8 +225,7 @@ static struct intc_sense_reg sense_registers[] __initdata = {
+ };
+ 
+ static DECLARE_INTC_DESC(intc_desc_irq, "shx3-irq", vectors_irq, groups,
+-			 priorities, mask_registers, prio_registers,
+-			 sense_registers);
++			 mask_registers, prio_registers, sense_registers);
+ 
+ /* External interrupt pins in IRL mode */
+ static struct intc_vect vectors_irl[] __initdata = {
+@@ -248,7 +240,7 @@ static struct intc_vect vectors_irl[] __initdata = {
+ };
+ 
+ static DECLARE_INTC_DESC(intc_desc_irl, "shx3-irl", vectors_irl, groups,
+-			 priorities, mask_registers, prio_registers, NULL);
++			 mask_registers, prio_registers, NULL);
+ 
+ void __init plat_irq_setup_pins(int mode)
+ {
+diff --git a/arch/sh/kernel/cpu/sh5/Makefile b/arch/sh/kernel/cpu/sh5/Makefile
+new file mode 100644
+index 0000000..8646363
+--- /dev/null
++++ b/arch/sh/kernel/cpu/sh5/Makefile
+@@ -0,0 +1,7 @@
++#
++# Makefile for the Linux/SuperH SH-5 backends.
++#
++obj-y := entry.o probe.o switchto.o
++
++obj-$(CONFIG_SH_FPU)		+= fpu.o
++obj-$(CONFIG_KALLSYMS)		+= unwind.o
+diff --git a/arch/sh/kernel/cpu/sh5/entry.S b/arch/sh/kernel/cpu/sh5/entry.S
+new file mode 100644
+index 0000000..ba87501
+--- /dev/null
++++ b/arch/sh/kernel/cpu/sh5/entry.S
+@@ -0,0 +1,2101 @@
++/*
++ * arch/sh/kernel/cpu/sh5/entry.S
++ *
++ * Copyright (C) 2000, 2001  Paolo Alberelli
++ * Copyright (C) 2004 - 2007  Paul Mundt
++ * Copyright (C) 2003, 2004  Richard Curnow
++ *
++ * 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/errno.h>
++#include <linux/sys.h>
++#include <asm/cpu/registers.h>
++#include <asm/processor.h>
++#include <asm/unistd.h>
++#include <asm/thread_info.h>
++#include <asm/asm-offsets.h>
++
++/*
++ * SR fields.
++ */
++#define SR_ASID_MASK	0x00ff0000
++#define SR_FD_MASK	0x00008000
++#define SR_SS		0x08000000
++#define SR_BL		0x10000000
++#define SR_MD		0x40000000
++
++/*
++ * Event code.
++ */
++#define	EVENT_INTERRUPT		0
++#define	EVENT_FAULT_TLB		1
++#define	EVENT_FAULT_NOT_TLB	2
++#define	EVENT_DEBUG		3
++
++/* EXPEVT values */
++#define	RESET_CAUSE		0x20
++#define DEBUGSS_CAUSE		0x980
++
++/*
++ * Frame layout. Quad index.
++ */
++#define	FRAME_T(x)	FRAME_TBASE+(x*8)
++#define	FRAME_R(x)	FRAME_RBASE+(x*8)
++#define	FRAME_S(x)	FRAME_SBASE+(x*8)
++#define FSPC		0
++#define FSSR		1
++#define FSYSCALL_ID	2
++
++/* Arrange the save frame to be a multiple of 32 bytes long */
++#define FRAME_SBASE	0
++#define FRAME_RBASE	(FRAME_SBASE+(3*8))	/* SYSCALL_ID - SSR - SPC */
++#define FRAME_TBASE	(FRAME_RBASE+(63*8))	/* r0 - r62 */
++#define FRAME_PBASE	(FRAME_TBASE+(8*8))	/* tr0 -tr7 */
++#define	FRAME_SIZE	(FRAME_PBASE+(2*8))	/* pad0-pad1 */
++
++#define FP_FRAME_SIZE	FP_FRAME_BASE+(33*8)	/* dr0 - dr31 + fpscr */
++#define FP_FRAME_BASE	0
++
++#define	SAVED_R2	0*8
++#define	SAVED_R3	1*8
++#define	SAVED_R4	2*8
++#define	SAVED_R5	3*8
++#define	SAVED_R18	4*8
++#define	SAVED_R6	5*8
++#define	SAVED_TR0	6*8
++
++/* These are the registers saved in the TLB path that aren't saved in the first
++   level of the normal one. */
++#define	TLB_SAVED_R25	7*8
++#define	TLB_SAVED_TR1	8*8
++#define	TLB_SAVED_TR2	9*8
++#define	TLB_SAVED_TR3	10*8
++#define	TLB_SAVED_TR4	11*8
++/* Save R0/R1 : PT-migrating compiler currently dishounours -ffixed-r0 and -ffixed-r1 causing
++   breakage otherwise. */
++#define	TLB_SAVED_R0	12*8
++#define	TLB_SAVED_R1	13*8
++
++#define CLI()				\
++	getcon	SR, r6;			\
++	ori	r6, 0xf0, r6;		\
++	putcon	r6, SR;
++
++#define STI()				\
++	getcon	SR, r6;			\
++	andi	r6, ~0xf0, r6;		\
++	putcon	r6, SR;
++
++#ifdef CONFIG_PREEMPT
++#  define preempt_stop()	CLI()
++#else
++#  define preempt_stop()
++#  define resume_kernel		restore_all
++#endif
++
++	.section	.data, "aw"
++
++#define FAST_TLBMISS_STACK_CACHELINES 4
++#define FAST_TLBMISS_STACK_QUADWORDS (4*FAST_TLBMISS_STACK_CACHELINES)
++
++/* Register back-up area for all exceptions */
++	.balign	32
++	/* Allow for 16 quadwords to be pushed by fast tlbmiss handling
++	 * register saves etc. */
++	.fill FAST_TLBMISS_STACK_QUADWORDS, 8, 0x0
++/* This is 32 byte aligned by construction */
++/* Register back-up area for all exceptions */
++reg_save_area:
++	.quad	0
++	.quad	0
++	.quad	0
++	.quad	0
++
++	.quad	0
++	.quad	0
++	.quad	0
++	.quad	0
++
++	.quad	0
++	.quad	0
++	.quad	0
++	.quad	0
++
++	.quad	0
++	.quad   0
++
++/* Save area for RESVEC exceptions. We cannot use reg_save_area because of
++ * reentrancy. Note this area may be accessed via physical address.
++ * Align so this fits a whole single cache line, for ease of purging.
++ */
++	.balign 32,0,32
++resvec_save_area:
++	.quad	0
++	.quad	0
++	.quad	0
++	.quad	0
++	.quad	0
++	.balign 32,0,32
++
++/* Jump table of 3rd level handlers  */
++trap_jtable:
++	.long	do_exception_error		/* 0x000 */
++	.long	do_exception_error		/* 0x020 */
++	.long	tlb_miss_load				/* 0x040 */
++	.long	tlb_miss_store				/* 0x060 */
++	! ARTIFICIAL pseudo-EXPEVT setting
++	.long	do_debug_interrupt		/* 0x080 */
++	.long	tlb_miss_load				/* 0x0A0 */
++	.long	tlb_miss_store				/* 0x0C0 */
++	.long	do_address_error_load	/* 0x0E0 */
++	.long	do_address_error_store	/* 0x100 */
++#ifdef CONFIG_SH_FPU
++	.long	do_fpu_error		/* 0x120 */
++#else
++	.long	do_exception_error		/* 0x120 */
++#endif
++	.long	do_exception_error		/* 0x140 */
++	.long	system_call				/* 0x160 */
++	.long	do_reserved_inst		/* 0x180 */
++	.long	do_illegal_slot_inst	/* 0x1A0 */
++	.long	do_exception_error		/* 0x1C0 - NMI */
++	.long	do_exception_error		/* 0x1E0 */
++	.rept 15
++		.long do_IRQ		/* 0x200 - 0x3C0 */
++	.endr
++	.long	do_exception_error		/* 0x3E0 */
++	.rept 32
++		.long do_IRQ		/* 0x400 - 0x7E0 */
++	.endr
++	.long	fpu_error_or_IRQA			/* 0x800 */
++	.long	fpu_error_or_IRQB			/* 0x820 */
++	.long	do_IRQ			/* 0x840 */
++	.long	do_IRQ			/* 0x860 */
++	.rept 6
++		.long do_exception_error	/* 0x880 - 0x920 */
++	.endr
++	.long	do_software_break_point	/* 0x940 */
++	.long	do_exception_error		/* 0x960 */
++	.long	do_single_step		/* 0x980 */
++
++	.rept 3
++		.long do_exception_error	/* 0x9A0 - 0x9E0 */
++	.endr
++	.long	do_IRQ			/* 0xA00 */
++	.long	do_IRQ			/* 0xA20 */
++	.long	itlb_miss_or_IRQ			/* 0xA40 */
++	.long	do_IRQ			/* 0xA60 */
++	.long	do_IRQ			/* 0xA80 */
++	.long	itlb_miss_or_IRQ			/* 0xAA0 */
++	.long	do_exception_error		/* 0xAC0 */
++	.long	do_address_error_exec	/* 0xAE0 */
++	.rept 8
++		.long do_exception_error	/* 0xB00 - 0xBE0 */
++	.endr
++	.rept 18
++		.long do_IRQ		/* 0xC00 - 0xE20 */
++	.endr
++
++	.section	.text64, "ax"
++
++/*
++ * --- Exception/Interrupt/Event Handling Section
++ */
++
++/*
++ * VBR and RESVEC blocks.
++ *
++ * First level handler for VBR-based exceptions.
++ *
++ * To avoid waste of space, align to the maximum text block size.
++ * This is assumed to be at most 128 bytes or 32 instructions.
++ * DO NOT EXCEED 32 instructions on the first level handlers !
++ *
++ * Also note that RESVEC is contained within the VBR block
++ * where the room left (1KB - TEXT_SIZE) allows placing
++ * the RESVEC block (at most 512B + TEXT_SIZE).
++ *
++ * So first (and only) level handler for RESVEC-based exceptions.
++ *
++ * Where the fault/interrupt is handled (not_a_tlb_miss, tlb_miss
++ * and interrupt) we are a lot tight with register space until
++ * saving onto the stack frame, which is done in handle_exception().
++ *
++ */
++
++#define	TEXT_SIZE 	128
++#define	BLOCK_SIZE 	1664 		/* Dynamic check, 13*128 */
++
++	.balign TEXT_SIZE
++LVBR_block:
++	.space	256, 0			/* Power-on class handler, */
++					/* not required here       */
++not_a_tlb_miss:
++	synco	/* TAKum03020 (but probably a good idea anyway.) */
++	/* Save original stack pointer into KCR1 */
++	putcon	SP, KCR1
++
++	/* Save other original registers into reg_save_area */
++        movi  reg_save_area, SP
++	st.q	SP, SAVED_R2, r2
++	st.q	SP, SAVED_R3, r3
++	st.q	SP, SAVED_R4, r4
++	st.q	SP, SAVED_R5, r5
++	st.q	SP, SAVED_R6, r6
++	st.q	SP, SAVED_R18, r18
++	gettr	tr0, r3
++	st.q	SP, SAVED_TR0, r3
++
++	/* Set args for Non-debug, Not a TLB miss class handler */
++	getcon	EXPEVT, r2
++	movi	ret_from_exception, r3
++	ori	r3, 1, r3
++	movi	EVENT_FAULT_NOT_TLB, r4
++	or	SP, ZERO, r5
++	getcon	KCR1, SP
++	pta	handle_exception, tr0
++	blink	tr0, ZERO
++
++	.balign 256
++	! VBR+0x200
++	nop
++	.balign 256
++	! VBR+0x300
++	nop
++	.balign 256
++	/*
++	 * Instead of the natural .balign 1024 place RESVEC here
++	 * respecting the final 1KB alignment.
++	 */
++	.balign TEXT_SIZE
++	/*
++	 * Instead of '.space 1024-TEXT_SIZE' place the RESVEC
++	 * block making sure the final alignment is correct.
++	 */
++tlb_miss:
++	synco	/* TAKum03020 (but probably a good idea anyway.) */
++	putcon	SP, KCR1
++	movi	reg_save_area, SP
++	/* SP is guaranteed 32-byte aligned. */
++	st.q	SP, TLB_SAVED_R0 , r0
++	st.q	SP, TLB_SAVED_R1 , r1
++	st.q	SP, SAVED_R2 , r2
++	st.q	SP, SAVED_R3 , r3
++	st.q	SP, SAVED_R4 , r4
++	st.q	SP, SAVED_R5 , r5
++	st.q	SP, SAVED_R6 , r6
++	st.q	SP, SAVED_R18, r18
++
++	/* Save R25 for safety; as/ld may want to use it to achieve the call to
++	 * the code in mm/tlbmiss.c */
++	st.q	SP, TLB_SAVED_R25, r25
++	gettr	tr0, r2
++	gettr	tr1, r3
++	gettr	tr2, r4
++	gettr	tr3, r5
++	gettr	tr4, r18
++	st.q	SP, SAVED_TR0 , r2
++	st.q	SP, TLB_SAVED_TR1 , r3
++	st.q	SP, TLB_SAVED_TR2 , r4
++	st.q	SP, TLB_SAVED_TR3 , r5
++	st.q	SP, TLB_SAVED_TR4 , r18
++
++	pt	do_fast_page_fault, tr0
++	getcon	SSR, r2
++	getcon	EXPEVT, r3
++	getcon	TEA, r4
++	shlri	r2, 30, r2
++	andi	r2, 1, r2	/* r2 = SSR.MD */
++	blink 	tr0, LINK
++
++	pt	fixup_to_invoke_general_handler, tr1
++
++	/* If the fast path handler fixed the fault, just drop through quickly
++	   to the restore code right away to return to the excepting context.
++	   */
++	beqi/u	r2, 0, tr1
++
++fast_tlb_miss_restore:
++	ld.q	SP, SAVED_TR0, r2
++	ld.q	SP, TLB_SAVED_TR1, r3
++	ld.q	SP, TLB_SAVED_TR2, r4
++
++	ld.q	SP, TLB_SAVED_TR3, r5
++	ld.q	SP, TLB_SAVED_TR4, r18
++
++	ptabs	r2, tr0
++	ptabs	r3, tr1
++	ptabs	r4, tr2
++	ptabs	r5, tr3
++	ptabs	r18, tr4
++
++	ld.q	SP, TLB_SAVED_R0, r0
++	ld.q	SP, TLB_SAVED_R1, r1
++	ld.q	SP, SAVED_R2, r2
++	ld.q	SP, SAVED_R3, r3
++	ld.q	SP, SAVED_R4, r4
++	ld.q	SP, SAVED_R5, r5
++	ld.q	SP, SAVED_R6, r6
++	ld.q	SP, SAVED_R18, r18
++	ld.q	SP, TLB_SAVED_R25, r25
++
++	getcon	KCR1, SP
++	rte
++	nop /* for safety, in case the code is run on sh5-101 cut1.x */
++
++fixup_to_invoke_general_handler:
++
++	/* OK, new method.  Restore stuff that's not expected to get saved into
++	   the 'first-level' reg save area, then just fall through to setting
++	   up the registers and calling the second-level handler. */
++
++	/* 2nd level expects r2,3,4,5,6,18,tr0 to be saved.  So we must restore
++	   r25,tr1-4 and save r6 to get into the right state.  */
++
++	ld.q	SP, TLB_SAVED_TR1, r3
++	ld.q	SP, TLB_SAVED_TR2, r4
++	ld.q	SP, TLB_SAVED_TR3, r5
++	ld.q	SP, TLB_SAVED_TR4, r18
++	ld.q	SP, TLB_SAVED_R25, r25
++
++	ld.q	SP, TLB_SAVED_R0, r0
++	ld.q	SP, TLB_SAVED_R1, r1
++
++	ptabs/u	r3, tr1
++	ptabs/u	r4, tr2
++	ptabs/u	r5, tr3
++	ptabs/u	r18, tr4
++
++	/* Set args for Non-debug, TLB miss class handler */
++	getcon	EXPEVT, r2
++	movi	ret_from_exception, r3
++	ori	r3, 1, r3
++	movi	EVENT_FAULT_TLB, r4
++	or	SP, ZERO, r5
++	getcon	KCR1, SP
++	pta	handle_exception, tr0
++	blink	tr0, ZERO
++
++/* NB TAKE GREAT CARE HERE TO ENSURE THAT THE INTERRUPT CODE
++   DOES END UP AT VBR+0x600 */
++	nop
++	nop
++	nop
++	nop
++	nop
++	nop
++
++	.balign 256
++	/* VBR + 0x600 */
++
++interrupt:
++	synco	/* TAKum03020 (but probably a good idea anyway.) */
++	/* Save original stack pointer into KCR1 */
++	putcon	SP, KCR1
++
++	/* Save other original registers into reg_save_area */
++        movi  reg_save_area, SP
++	st.q	SP, SAVED_R2, r2
++	st.q	SP, SAVED_R3, r3
++	st.q	SP, SAVED_R4, r4
++	st.q	SP, SAVED_R5, r5
++	st.q	SP, SAVED_R6, r6
++	st.q	SP, SAVED_R18, r18
++	gettr	tr0, r3
++	st.q	SP, SAVED_TR0, r3
++
++	/* Set args for interrupt class handler */
++	getcon	INTEVT, r2
++	movi	ret_from_irq, r3
++	ori	r3, 1, r3
++	movi	EVENT_INTERRUPT, r4
++	or	SP, ZERO, r5
++	getcon	KCR1, SP
++	pta	handle_exception, tr0
++	blink	tr0, ZERO
++	.balign	TEXT_SIZE		/* let's waste the bare minimum */
++
++LVBR_block_end:				/* Marker. Used for total checking */
++
++	.balign 256
++LRESVEC_block:
++	/* Panic handler. Called with MMU off. Possible causes/actions:
++	 * - Reset:		Jump to program start.
++	 * - Single Step:	Turn off Single Step & return.
++	 * - Others:		Call panic handler, passing PC as arg.
++	 *			(this may need to be extended...)
++	 */
++reset_or_panic:
++	synco	/* TAKum03020 (but probably a good idea anyway.) */
++	putcon	SP, DCR
++	/* First save r0-1 and tr0, as we need to use these */
++	movi	resvec_save_area-CONFIG_PAGE_OFFSET, SP
++	st.q	SP, 0, r0
++	st.q	SP, 8, r1
++	gettr	tr0, r0
++	st.q	SP, 32, r0
++
++	/* Check cause */
++	getcon	EXPEVT, r0
++	movi	RESET_CAUSE, r1
++	sub	r1, r0, r1		/* r1=0 if reset */
++	movi	_stext-CONFIG_PAGE_OFFSET, r0
++	ori	r0, 1, r0
++	ptabs	r0, tr0
++	beqi	r1, 0, tr0		/* Jump to start address if reset */
++
++	getcon	EXPEVT, r0
++	movi	DEBUGSS_CAUSE, r1
++	sub	r1, r0, r1		/* r1=0 if single step */
++	pta	single_step_panic, tr0
++	beqi	r1, 0, tr0		/* jump if single step */
++
++	/* Now jump to where we save the registers. */
++	movi	panic_stash_regs-CONFIG_PAGE_OFFSET, r1
++	ptabs	r1, tr0
++	blink	tr0, r63
++
++single_step_panic:
++	/* We are in a handler with Single Step set. We need to resume the
++	 * handler, by turning on MMU & turning off Single Step. */
++	getcon	SSR, r0
++	movi	SR_MMU, r1
++	or	r0, r1, r0
++	movi	~SR_SS, r1
++	and	r0, r1, r0
++	putcon	r0, SSR
++	/* Restore EXPEVT, as the rte won't do this */
++	getcon	PEXPEVT, r0
++	putcon	r0, EXPEVT
++	/* Restore regs */
++	ld.q	SP, 32, r0
++	ptabs	r0, tr0
++	ld.q	SP, 0, r0
++	ld.q	SP, 8, r1
++	getcon	DCR, SP
++	synco
++	rte
++
++
++	.balign	256
++debug_exception:
++	synco	/* TAKum03020 (but probably a good idea anyway.) */
++	/*
++	 * Single step/software_break_point first level handler.
++	 * Called with MMU off, so the first thing we do is enable it
++	 * by doing an rte with appropriate SSR.
++	 */
++	putcon	SP, DCR
++	/* Save SSR & SPC, together with R0 & R1, as we need to use 2 regs. */
++	movi	resvec_save_area-CONFIG_PAGE_OFFSET, SP
++
++	/* With the MMU off, we are bypassing the cache, so purge any
++         * data that will be made stale by the following stores.
++         */
++	ocbp	SP, 0
++	synco
++
++	st.q	SP, 0, r0
++	st.q	SP, 8, r1
++	getcon	SPC, r0
++	st.q	SP, 16, r0
++	getcon	SSR, r0
++	st.q	SP, 24, r0
++
++	/* Enable MMU, block exceptions, set priv mode, disable single step */
++	movi	SR_MMU | SR_BL | SR_MD, r1
++	or	r0, r1, r0
++	movi	~SR_SS, r1
++	and	r0, r1, r0
++	putcon	r0, SSR
++	/* Force control to debug_exception_2 when rte is executed */
++	movi	debug_exeception_2, r0
++	ori	r0, 1, r0      /* force SHmedia, just in case */
++	putcon	r0, SPC
++	getcon	DCR, SP
++	synco
++	rte
++debug_exeception_2:
++	/* Restore saved regs */
++	putcon	SP, KCR1
++	movi	resvec_save_area, SP
++	ld.q	SP, 24, r0
++	putcon	r0, SSR
++	ld.q	SP, 16, r0
++	putcon	r0, SPC
++	ld.q	SP, 0, r0
++	ld.q	SP, 8, r1
++
++	/* Save other original registers into reg_save_area */
++        movi  reg_save_area, SP
++	st.q	SP, SAVED_R2, r2
++	st.q	SP, SAVED_R3, r3
++	st.q	SP, SAVED_R4, r4
++	st.q	SP, SAVED_R5, r5
++	st.q	SP, SAVED_R6, r6
++	st.q	SP, SAVED_R18, r18
++	gettr	tr0, r3
++	st.q	SP, SAVED_TR0, r3
++
++	/* Set args for debug class handler */
++	getcon	EXPEVT, r2
++	movi	ret_from_exception, r3
++	ori	r3, 1, r3
++	movi	EVENT_DEBUG, r4
++	or	SP, ZERO, r5
++	getcon	KCR1, SP
++	pta	handle_exception, tr0
++	blink	tr0, ZERO
++
++	.balign	256
++debug_interrupt:
++	/* !!! WE COME HERE IN REAL MODE !!! */
++	/* Hook-up debug interrupt to allow various debugging options to be
++	 * hooked into its handler. */
++	/* Save original stack pointer into KCR1 */
++	synco
++	putcon	SP, KCR1
++	movi	resvec_save_area-CONFIG_PAGE_OFFSET, SP
++	ocbp	SP, 0
++	ocbp	SP, 32
++	synco
++
++	/* Save other original registers into reg_save_area thru real addresses */
++	st.q	SP, SAVED_R2, r2
++	st.q	SP, SAVED_R3, r3
++	st.q	SP, SAVED_R4, r4
++	st.q	SP, SAVED_R5, r5
++	st.q	SP, SAVED_R6, r6
++	st.q	SP, SAVED_R18, r18
++	gettr	tr0, r3
++	st.q	SP, SAVED_TR0, r3
++
++	/* move (spc,ssr)->(pspc,pssr).  The rte will shift
++	   them back again, so that they look like the originals
++	   as far as the real handler code is concerned. */
++	getcon	spc, r6
++	putcon	r6, pspc
++	getcon	ssr, r6
++	putcon	r6, pssr
++
++	! construct useful SR for handle_exception
++	movi	3, r6
++	shlli	r6, 30, r6
++	getcon	sr, r18
++	or	r18, r6, r6
++	putcon	r6, ssr
++
++	! SSR is now the current SR with the MD and MMU bits set
++	! i.e. the rte will switch back to priv mode and put
++	! the mmu back on
++
++	! construct spc
++	movi	handle_exception, r18
++	ori	r18, 1, r18		! for safety (do we need this?)
++	putcon	r18, spc
++
++	/* Set args for Non-debug, Not a TLB miss class handler */
++
++	! EXPEVT==0x80 is unused, so 'steal' this value to put the
++	! debug interrupt handler in the vectoring table
++	movi	0x80, r2
++	movi	ret_from_exception, r3
++	ori	r3, 1, r3
++	movi	EVENT_FAULT_NOT_TLB, r4
++
++	or	SP, ZERO, r5
++	movi	CONFIG_PAGE_OFFSET, r6
++	add	r6, r5, r5
++	getcon	KCR1, SP
++
++	synco	! for safety
++	rte	! -> handle_exception, switch back to priv mode again
++
++LRESVEC_block_end:			/* Marker. Unused. */
++
++	.balign	TEXT_SIZE
++
++/*
++ * Second level handler for VBR-based exceptions. Pre-handler.
++ * In common to all stack-frame sensitive handlers.
++ *
++ * Inputs:
++ * (KCR0) Current [current task union]
++ * (KCR1) Original SP
++ * (r2)   INTEVT/EXPEVT
++ * (r3)   appropriate return address
++ * (r4)   Event (0 = interrupt, 1 = TLB miss fault, 2 = Not TLB miss fault, 3=debug)
++ * (r5)   Pointer to reg_save_area
++ * (SP)   Original SP
++ *
++ * Available registers:
++ * (r6)
++ * (r18)
++ * (tr0)
++ *
++ */
++handle_exception:
++	/* Common 2nd level handler. */
++
++	/* First thing we need an appropriate stack pointer */
++	getcon	SSR, r6
++	shlri	r6, 30, r6
++	andi	r6, 1, r6
++	pta	stack_ok, tr0
++	bne	r6, ZERO, tr0		/* Original stack pointer is fine */
++
++	/* Set stack pointer for user fault */
++	getcon	KCR0, SP
++	movi	THREAD_SIZE, r6		/* Point to the end */
++	add	SP, r6, SP
++
++stack_ok:
++
++/* DEBUG : check for underflow/overflow of the kernel stack */
++	pta	no_underflow, tr0
++	getcon  KCR0, r6
++	movi	1024, r18
++	add	r6, r18, r6
++	bge	SP, r6, tr0 	! ? below 1k from bottom of stack : danger zone
++
++/* Just panic to cause a crash. */
++bad_sp:
++	ld.b	r63, 0, r6
++	nop
++
++no_underflow:
++	pta	bad_sp, tr0
++	getcon	kcr0, r6
++	movi	THREAD_SIZE, r18
++	add	r18, r6, r6
++	bgt	SP, r6, tr0	! sp above the stack
++
++	/* Make some room for the BASIC frame. */
++	movi	-(FRAME_SIZE), r6
++	add	SP, r6, SP
++
++/* Could do this with no stalling if we had another spare register, but the
++   code below will be OK. */
++	ld.q	r5, SAVED_R2, r6
++	ld.q	r5, SAVED_R3, r18
++	st.q	SP, FRAME_R(2), r6
++	ld.q	r5, SAVED_R4, r6
++	st.q	SP, FRAME_R(3), r18
++	ld.q	r5, SAVED_R5, r18
++	st.q	SP, FRAME_R(4), r6
++	ld.q	r5, SAVED_R6, r6
++	st.q	SP, FRAME_R(5), r18
++	ld.q	r5, SAVED_R18, r18
++	st.q	SP, FRAME_R(6), r6
++	ld.q	r5, SAVED_TR0, r6
++	st.q	SP, FRAME_R(18), r18
++	st.q	SP, FRAME_T(0), r6
++
++	/* Keep old SP around */
++	getcon	KCR1, r6
++
++	/* Save the rest of the general purpose registers */
++	st.q	SP, FRAME_R(0), r0
++	st.q	SP, FRAME_R(1), r1
++	st.q	SP, FRAME_R(7), r7
++	st.q	SP, FRAME_R(8), r8
++	st.q	SP, FRAME_R(9), r9
++	st.q	SP, FRAME_R(10), r10
++	st.q	SP, FRAME_R(11), r11
++	st.q	SP, FRAME_R(12), r12
++	st.q	SP, FRAME_R(13), r13
++	st.q	SP, FRAME_R(14), r14
++
++	/* SP is somewhere else */
++	st.q	SP, FRAME_R(15), r6
++
++	st.q	SP, FRAME_R(16), r16
++	st.q	SP, FRAME_R(17), r17
++	/* r18 is saved earlier. */
++	st.q	SP, FRAME_R(19), r19
++	st.q	SP, FRAME_R(20), r20
++	st.q	SP, FRAME_R(21), r21
++	st.q	SP, FRAME_R(22), r22
++	st.q	SP, FRAME_R(23), r23
++	st.q	SP, FRAME_R(24), r24
++	st.q	SP, FRAME_R(25), r25
++	st.q	SP, FRAME_R(26), r26
++	st.q	SP, FRAME_R(27), r27
++	st.q	SP, FRAME_R(28), r28
++	st.q	SP, FRAME_R(29), r29
++	st.q	SP, FRAME_R(30), r30
++	st.q	SP, FRAME_R(31), r31
++	st.q	SP, FRAME_R(32), r32
++	st.q	SP, FRAME_R(33), r33
++	st.q	SP, FRAME_R(34), r34
++	st.q	SP, FRAME_R(35), r35
++	st.q	SP, FRAME_R(36), r36
++	st.q	SP, FRAME_R(37), r37
++	st.q	SP, FRAME_R(38), r38
++	st.q	SP, FRAME_R(39), r39
++	st.q	SP, FRAME_R(40), r40
++	st.q	SP, FRAME_R(41), r41
++	st.q	SP, FRAME_R(42), r42
++	st.q	SP, FRAME_R(43), r43
++	st.q	SP, FRAME_R(44), r44
++	st.q	SP, FRAME_R(45), r45
++	st.q	SP, FRAME_R(46), r46
++	st.q	SP, FRAME_R(47), r47
++	st.q	SP, FRAME_R(48), r48
++	st.q	SP, FRAME_R(49), r49
++	st.q	SP, FRAME_R(50), r50
++	st.q	SP, FRAME_R(51), r51
++	st.q	SP, FRAME_R(52), r52
++	st.q	SP, FRAME_R(53), r53
++	st.q	SP, FRAME_R(54), r54
++	st.q	SP, FRAME_R(55), r55
++	st.q	SP, FRAME_R(56), r56
++	st.q	SP, FRAME_R(57), r57
++	st.q	SP, FRAME_R(58), r58
++	st.q	SP, FRAME_R(59), r59
++	st.q	SP, FRAME_R(60), r60
++	st.q	SP, FRAME_R(61), r61
++	st.q	SP, FRAME_R(62), r62
++
++	/*
++	 * Save the S* registers.
++	 */
++	getcon	SSR, r61
++	st.q	SP, FRAME_S(FSSR), r61
++	getcon	SPC, r62
++	st.q	SP, FRAME_S(FSPC), r62
++	movi	-1, r62			/* Reset syscall_nr */
++	st.q	SP, FRAME_S(FSYSCALL_ID), r62
++
++	/* Save the rest of the target registers */
++	gettr	tr1, r6
++	st.q	SP, FRAME_T(1), r6
++	gettr	tr2, r6
++	st.q	SP, FRAME_T(2), r6
++	gettr	tr3, r6
++	st.q	SP, FRAME_T(3), r6
++	gettr	tr4, r6
++	st.q	SP, FRAME_T(4), r6
++	gettr	tr5, r6
++	st.q	SP, FRAME_T(5), r6
++	gettr	tr6, r6
++	st.q	SP, FRAME_T(6), r6
++	gettr	tr7, r6
++	st.q	SP, FRAME_T(7), r6
++
++	! setup FP so that unwinder can wind back through nested kernel mode
++	! exceptions
++	add	SP, ZERO, r14
++
++#ifdef CONFIG_POOR_MANS_STRACE
++	/* We've pushed all the registers now, so only r2-r4 hold anything
++	 * useful. Move them into callee save registers */
++	or	r2, ZERO, r28
++	or	r3, ZERO, r29
++	or	r4, ZERO, r30
++
++	/* Preserve r2 as the event code */
++	movi	evt_debug, r3
++	ori	r3, 1, r3
++	ptabs	r3, tr0
++
++	or	SP, ZERO, r6
++	getcon	TRA, r5
++	blink	tr0, LINK
++
++	or	r28, ZERO, r2
++	or	r29, ZERO, r3
++	or	r30, ZERO, r4
++#endif
++
++	/* For syscall and debug race condition, get TRA now */
++	getcon	TRA, r5
++
++	/* We are in a safe position to turn SR.BL off, but set IMASK=0xf
++	 * Also set FD, to catch FPU usage in the kernel.
++	 *
++	 * benedict.gaster at superh.com 29/07/2002
++	 *
++	 * On all SH5-101 revisions it is unsafe to raise the IMASK and at the
++	 * same time change BL from 1->0, as any pending interrupt of a level
++	 * higher than he previous value of IMASK will leak through and be
++	 * taken unexpectedly.
++	 *
++	 * To avoid this we raise the IMASK and then issue another PUTCON to
++	 * enable interrupts.
++         */
++	getcon	SR, r6
++	movi	SR_IMASK | SR_FD, r7
++	or	r6, r7, r6
++	putcon	r6, SR
++	movi	SR_UNBLOCK_EXC, r7
++	and	r6, r7, r6
++	putcon	r6, SR
++
++
++	/* Now call the appropriate 3rd level handler */
++	or	r3, ZERO, LINK
++	movi	trap_jtable, r3
++	shlri	r2, 3, r2
++	ldx.l	r2, r3, r3
++	shlri	r2, 2, r2
++	ptabs	r3, tr0
++	or	SP, ZERO, r3
++	blink	tr0, ZERO
++
++/*
++ * Second level handler for VBR-based exceptions. Post-handlers.
++ *
++ * Post-handlers for interrupts (ret_from_irq), exceptions
++ * (ret_from_exception) and common reentrance doors (restore_all
++ * to get back to the original context, ret_from_syscall loop to
++ * check kernel exiting).
++ *
++ * ret_with_reschedule and work_notifysig are an inner lables of
++ * the ret_from_syscall loop.
++ *
++ * In common to all stack-frame sensitive handlers.
++ *
++ * Inputs:
++ * (SP)   struct pt_regs *, original register's frame pointer (basic)
++ *
++ */
++	.global ret_from_irq
++ret_from_irq:
++#ifdef CONFIG_POOR_MANS_STRACE
++	pta	evt_debug_ret_from_irq, tr0
++	ori	SP, 0, r2
++	blink	tr0, LINK
++#endif
++	ld.q	SP, FRAME_S(FSSR), r6
++	shlri	r6, 30, r6
++	andi	r6, 1, r6
++	pta	resume_kernel, tr0
++	bne	r6, ZERO, tr0		/* no further checks */
++	STI()
++	pta	ret_with_reschedule, tr0
++	blink	tr0, ZERO		/* Do not check softirqs */
++
++	.global ret_from_exception
++ret_from_exception:
++	preempt_stop()
++
++#ifdef CONFIG_POOR_MANS_STRACE
++	pta	evt_debug_ret_from_exc, tr0
++	ori	SP, 0, r2
++	blink	tr0, LINK
++#endif
++
++	ld.q	SP, FRAME_S(FSSR), r6
++	shlri	r6, 30, r6
++	andi	r6, 1, r6
++	pta	resume_kernel, tr0
++	bne	r6, ZERO, tr0		/* no further checks */
++
++	/* Check softirqs */
++
++#ifdef CONFIG_PREEMPT
++	pta   ret_from_syscall, tr0
++	blink   tr0, ZERO
++
++resume_kernel:
++	pta	restore_all, tr0
++
++	getcon	KCR0, r6
++	ld.l	r6, TI_PRE_COUNT, r7
++	beq/u	r7, ZERO, tr0
++
++need_resched:
++	ld.l	r6, TI_FLAGS, r7
++	movi	(1 << TIF_NEED_RESCHED), r8
++	and	r8, r7, r8
++	bne	r8, ZERO, tr0
++
++	getcon	SR, r7
++	andi	r7, 0xf0, r7
++	bne	r7, ZERO, tr0
++
++	movi	((PREEMPT_ACTIVE >> 16) & 65535), r8
++	shori	(PREEMPT_ACTIVE & 65535), r8
++	st.l	r6, TI_PRE_COUNT, r8
++
++	STI()
++	movi	schedule, r7
++	ori	r7, 1, r7
++	ptabs	r7, tr1
++	blink	tr1, LINK
++
++	st.l	r6, TI_PRE_COUNT, ZERO
++	CLI()
++
++	pta	need_resched, tr1
++	blink	tr1, ZERO
++#endif
++
++	.global ret_from_syscall
++ret_from_syscall:
++
++ret_with_reschedule:
++	getcon	KCR0, r6		! r6 contains current_thread_info
++	ld.l	r6, TI_FLAGS, r7	! r7 contains current_thread_info->flags
++
++	movi	_TIF_NEED_RESCHED, r8
++	and	r8, r7, r8
++	pta	work_resched, tr0
++	bne	r8, ZERO, tr0
++
++	pta	restore_all, tr1
++
++	movi	(_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK), r8
++	and	r8, r7, r8
++	pta	work_notifysig, tr0
++	bne	r8, ZERO, tr0
++
++	blink	tr1, ZERO
++
++work_resched:
++	pta	ret_from_syscall, tr0
++	gettr	tr0, LINK
++	movi	schedule, r6
++	ptabs	r6, tr0
++	blink	tr0, ZERO		/* Call schedule(), return on top */
++
++work_notifysig:
++	gettr	tr1, LINK
++
++	movi	do_signal, r6
++	ptabs	r6, tr0
++	or	SP, ZERO, r2
++	or	ZERO, ZERO, r3
++	blink	tr0, LINK	    /* Call do_signal(regs, 0), return here */
++
++restore_all:
++	/* Do prefetches */
++
++	ld.q	SP, FRAME_T(0), r6
++	ld.q	SP, FRAME_T(1), r7
++	ld.q	SP, FRAME_T(2), r8
++	ld.q	SP, FRAME_T(3), r9
++	ptabs	r6, tr0
++	ptabs	r7, tr1
++	ptabs	r8, tr2
++	ptabs	r9, tr3
++	ld.q	SP, FRAME_T(4), r6
++	ld.q	SP, FRAME_T(5), r7
++	ld.q	SP, FRAME_T(6), r8
++	ld.q	SP, FRAME_T(7), r9
++	ptabs	r6, tr4
++	ptabs	r7, tr5
++	ptabs	r8, tr6
++	ptabs	r9, tr7
++
++	ld.q	SP, FRAME_R(0), r0
++	ld.q	SP, FRAME_R(1), r1
++	ld.q	SP, FRAME_R(2), r2
++	ld.q	SP, FRAME_R(3), r3
++	ld.q	SP, FRAME_R(4), r4
++	ld.q	SP, FRAME_R(5), r5
++	ld.q	SP, FRAME_R(6), r6
++	ld.q	SP, FRAME_R(7), r7
++	ld.q	SP, FRAME_R(8), r8
++	ld.q	SP, FRAME_R(9), r9
++	ld.q	SP, FRAME_R(10), r10
++	ld.q	SP, FRAME_R(11), r11
++	ld.q	SP, FRAME_R(12), r12
++	ld.q	SP, FRAME_R(13), r13
++	ld.q	SP, FRAME_R(14), r14
++
++	ld.q	SP, FRAME_R(16), r16
++	ld.q	SP, FRAME_R(17), r17
++	ld.q	SP, FRAME_R(18), r18
++	ld.q	SP, FRAME_R(19), r19
++	ld.q	SP, FRAME_R(20), r20
++	ld.q	SP, FRAME_R(21), r21
++	ld.q	SP, FRAME_R(22), r22
++	ld.q	SP, FRAME_R(23), r23
++	ld.q	SP, FRAME_R(24), r24
++	ld.q	SP, FRAME_R(25), r25
++	ld.q	SP, FRAME_R(26), r26
++	ld.q	SP, FRAME_R(27), r27
++	ld.q	SP, FRAME_R(28), r28
++	ld.q	SP, FRAME_R(29), r29
++	ld.q	SP, FRAME_R(30), r30
++	ld.q	SP, FRAME_R(31), r31
++	ld.q	SP, FRAME_R(32), r32
++	ld.q	SP, FRAME_R(33), r33
++	ld.q	SP, FRAME_R(34), r34
++	ld.q	SP, FRAME_R(35), r35
++	ld.q	SP, FRAME_R(36), r36
++	ld.q	SP, FRAME_R(37), r37
++	ld.q	SP, FRAME_R(38), r38
++	ld.q	SP, FRAME_R(39), r39
++	ld.q	SP, FRAME_R(40), r40
++	ld.q	SP, FRAME_R(41), r41
++	ld.q	SP, FRAME_R(42), r42
++	ld.q	SP, FRAME_R(43), r43
++	ld.q	SP, FRAME_R(44), r44
++	ld.q	SP, FRAME_R(45), r45
++	ld.q	SP, FRAME_R(46), r46
++	ld.q	SP, FRAME_R(47), r47
++	ld.q	SP, FRAME_R(48), r48
++	ld.q	SP, FRAME_R(49), r49
++	ld.q	SP, FRAME_R(50), r50
++	ld.q	SP, FRAME_R(51), r51
++	ld.q	SP, FRAME_R(52), r52
++	ld.q	SP, FRAME_R(53), r53
++	ld.q	SP, FRAME_R(54), r54
++	ld.q	SP, FRAME_R(55), r55
++	ld.q	SP, FRAME_R(56), r56
++	ld.q	SP, FRAME_R(57), r57
++	ld.q	SP, FRAME_R(58), r58
++
++	getcon	SR, r59
++	movi	SR_BLOCK_EXC, r60
++	or	r59, r60, r59
++	putcon	r59, SR			/* SR.BL = 1, keep nesting out */
++	ld.q	SP, FRAME_S(FSSR), r61
++	ld.q	SP, FRAME_S(FSPC), r62
++	movi	SR_ASID_MASK, r60
++	and	r59, r60, r59
++	andc	r61, r60, r61		/* Clear out older ASID */
++	or	r59, r61, r61		/* Retain current ASID */
++	putcon	r61, SSR
++	putcon	r62, SPC
++
++	/* Ignore FSYSCALL_ID */
++
++	ld.q	SP, FRAME_R(59), r59
++	ld.q	SP, FRAME_R(60), r60
++	ld.q	SP, FRAME_R(61), r61
++	ld.q	SP, FRAME_R(62), r62
++
++	/* Last touch */
++	ld.q	SP, FRAME_R(15), SP
++	rte
++	nop
++
++/*
++ * Third level handlers for VBR-based exceptions. Adapting args to
++ * and/or deflecting to fourth level handlers.
++ *
++ * Fourth level handlers interface.
++ * Most are C-coded handlers directly pointed by the trap_jtable.
++ * (Third = Fourth level)
++ * Inputs:
++ * (r2)   fault/interrupt code, entry number (e.g. NMI = 14,
++ *	  IRL0-3 (0000) = 16, RTLBMISS = 2, SYSCALL = 11, etc ...)
++ * (r3)   struct pt_regs *, original register's frame pointer
++ * (r4)   Event (0 = interrupt, 1 = TLB miss fault, 2 = Not TLB miss fault)
++ * (r5)   TRA control register (for syscall/debug benefit only)
++ * (LINK) return address
++ * (SP)   = r3
++ *
++ * Kernel TLB fault handlers will get a slightly different interface.
++ * (r2)   struct pt_regs *, original register's frame pointer
++ * (r3)   writeaccess, whether it's a store fault as opposed to load fault
++ * (r4)   execaccess, whether it's a ITLB fault as opposed to DTLB fault
++ * (r5)   Effective Address of fault
++ * (LINK) return address
++ * (SP)   = r2
++ *
++ * fpu_error_or_IRQ? is a helper to deflect to the right cause.
++ *
++ */
++tlb_miss_load:
++	or	SP, ZERO, r2
++	or	ZERO, ZERO, r3		/* Read */
++	or	ZERO, ZERO, r4		/* Data */
++	getcon	TEA, r5
++	pta	call_do_page_fault, tr0
++	beq	ZERO, ZERO, tr0
++
++tlb_miss_store:
++	or	SP, ZERO, r2
++	movi	1, r3			/* Write */
++	or	ZERO, ZERO, r4		/* Data */
++	getcon	TEA, r5
++	pta	call_do_page_fault, tr0
++	beq	ZERO, ZERO, tr0
++
++itlb_miss_or_IRQ:
++	pta	its_IRQ, tr0
++	beqi/u	r4, EVENT_INTERRUPT, tr0
++	or	SP, ZERO, r2
++	or	ZERO, ZERO, r3		/* Read */
++	movi	1, r4			/* Text */
++	getcon	TEA, r5
++	/* Fall through */
++
++call_do_page_fault:
++	movi	do_page_fault, r6
++        ptabs	r6, tr0
++        blink	tr0, ZERO
++
++fpu_error_or_IRQA:
++	pta	its_IRQ, tr0
++	beqi/l	r4, EVENT_INTERRUPT, tr0
++#ifdef CONFIG_SH_FPU
++	movi	do_fpu_state_restore, r6
++#else
++	movi	do_exception_error, r6
++#endif
++	ptabs	r6, tr0
++	blink	tr0, ZERO
++
++fpu_error_or_IRQB:
++	pta	its_IRQ, tr0
++	beqi/l	r4, EVENT_INTERRUPT, tr0
++#ifdef CONFIG_SH_FPU
++	movi	do_fpu_state_restore, r6
++#else
++	movi	do_exception_error, r6
++#endif
++	ptabs	r6, tr0
++	blink	tr0, ZERO
++
++its_IRQ:
++	movi	do_IRQ, r6
++	ptabs	r6, tr0
++	blink	tr0, ZERO
++
++/*
++ * system_call/unknown_trap third level handler:
++ *
++ * Inputs:
++ * (r2)   fault/interrupt code, entry number (TRAP = 11)
++ * (r3)   struct pt_regs *, original register's frame pointer
++ * (r4)   Not used. Event (0=interrupt, 1=TLB miss fault, 2=Not TLB miss fault)
++ * (r5)   TRA Control Reg (0x00xyzzzz: x=1 SYSCALL, y = #args, z=nr)
++ * (SP)   = r3
++ * (LINK) return address: ret_from_exception
++ * (*r3)  Syscall parms: SC#, arg0, arg1, ..., arg5 in order (Saved r2/r7)
++ *
++ * Outputs:
++ * (*r3)  Syscall reply (Saved r2)
++ * (LINK) In case of syscall only it can be scrapped.
++ *        Common second level post handler will be ret_from_syscall.
++ *        Common (non-trace) exit point to that is syscall_ret (saving
++ *        result to r2). Common bad exit point is syscall_bad (returning
++ *        ENOSYS then saved to r2).
++ *
++ */
++
++unknown_trap:
++	/* Unknown Trap or User Trace */
++	movi	do_unknown_trapa, r6
++	ptabs	r6, tr0
++        ld.q    r3, FRAME_R(9), r2	/* r2 = #arg << 16 | syscall # */
++        andi    r2, 0x1ff, r2		/* r2 = syscall # */
++	blink	tr0, LINK
++
++	pta	syscall_ret, tr0
++	blink	tr0, ZERO
++
++        /* New syscall implementation*/
++system_call:
++	pta	unknown_trap, tr0
++        or      r5, ZERO, r4            /* TRA (=r5) -> r4 */
++        shlri   r4, 20, r4
++	bnei	r4, 1, tr0		/* unknown_trap if not 0x1yzzzz */
++
++        /* It's a system call */
++	st.q    r3, FRAME_S(FSYSCALL_ID), r5 	/* ID (0x1yzzzz) -> stack */
++	andi    r5, 0x1ff, r5			/* syscall # -> r5	  */
++
++	STI()
++
++	pta	syscall_allowed, tr0
++	movi	NR_syscalls - 1, r4	/* Last valid */
++	bgeu/l	r4, r5, tr0
++
++syscall_bad:
++	/* Return ENOSYS ! */
++	movi	-(ENOSYS), r2		/* Fall-through */
++
++	.global syscall_ret
++syscall_ret:
++	st.q	SP, FRAME_R(9), r2	/* Expecting SP back to BASIC frame */
++
++#ifdef CONFIG_POOR_MANS_STRACE
++	/* nothing useful in registers at this point */
++
++	movi	evt_debug2, r5
++	ori	r5, 1, r5
++	ptabs	r5, tr0
++	ld.q	SP, FRAME_R(9), r2
++	or	SP, ZERO, r3
++	blink	tr0, LINK
++#endif
++
++	ld.q	SP, FRAME_S(FSPC), r2
++	addi	r2, 4, r2		/* Move PC, being pre-execution event */
++	st.q	SP, FRAME_S(FSPC), r2
++	pta	ret_from_syscall, tr0
++	blink	tr0, ZERO
++
++
++/*  A different return path for ret_from_fork, because we now need
++ *  to call schedule_tail with the later kernels. Because prev is
++ *  loaded into r2 by switch_to() means we can just call it straight  away
++ */
++
++.global	ret_from_fork
++ret_from_fork:
++
++	movi	schedule_tail,r5
++	ori	r5, 1, r5
++	ptabs	r5, tr0
++	blink	tr0, LINK
++
++#ifdef CONFIG_POOR_MANS_STRACE
++	/* nothing useful in registers at this point */
++
++	movi	evt_debug2, r5
++	ori	r5, 1, r5
++	ptabs	r5, tr0
++	ld.q	SP, FRAME_R(9), r2
++	or	SP, ZERO, r3
++	blink	tr0, LINK
++#endif
++
++	ld.q	SP, FRAME_S(FSPC), r2
++	addi	r2, 4, r2		/* Move PC, being pre-execution event */
++	st.q	SP, FRAME_S(FSPC), r2
++	pta	ret_from_syscall, tr0
++	blink	tr0, ZERO
++
++
++
++syscall_allowed:
++	/* Use LINK to deflect the exit point, default is syscall_ret */
++	pta	syscall_ret, tr0
++	gettr	tr0, LINK
++	pta	syscall_notrace, tr0
++
++	getcon	KCR0, r2
++	ld.l	r2, TI_FLAGS, r4
++	movi	(_TIF_SYSCALL_TRACE | _TIF_SINGLESTEP | _TIF_SYSCALL_AUDIT), r6
++	and	r6, r4, r6
++	beq/l	r6, ZERO, tr0
++
++	/* Trace it by calling syscall_trace before and after */
++	movi	syscall_trace, r4
++	or	SP, ZERO, r2
++	or	ZERO, ZERO, r3
++	ptabs	r4, tr0
++	blink	tr0, LINK
++
++	/* Reload syscall number as r5 is trashed by syscall_trace */
++	ld.q	SP, FRAME_S(FSYSCALL_ID), r5
++	andi	r5, 0x1ff, r5
++
++	pta	syscall_ret_trace, tr0
++	gettr	tr0, LINK
++
++syscall_notrace:
++	/* Now point to the appropriate 4th level syscall handler */
++	movi	sys_call_table, r4
++	shlli	r5, 2, r5
++	ldx.l	r4, r5, r5
++	ptabs	r5, tr0
++
++	/* Prepare original args */
++	ld.q	SP, FRAME_R(2), r2
++	ld.q	SP, FRAME_R(3), r3
++	ld.q	SP, FRAME_R(4), r4
++	ld.q	SP, FRAME_R(5), r5
++	ld.q	SP, FRAME_R(6), r6
++	ld.q	SP, FRAME_R(7), r7
++
++	/* And now the trick for those syscalls requiring regs * ! */
++	or	SP, ZERO, r8
++
++	/* Call it */
++	blink	tr0, ZERO	/* LINK is already properly set */
++
++syscall_ret_trace:
++	/* We get back here only if under trace */
++	st.q	SP, FRAME_R(9), r2	/* Save return value */
++
++	movi	syscall_trace, LINK
++	or	SP, ZERO, r2
++	movi	1, r3
++	ptabs	LINK, tr0
++	blink	tr0, LINK
++
++	/* This needs to be done after any syscall tracing */
++	ld.q	SP, FRAME_S(FSPC), r2
++	addi	r2, 4, r2	/* Move PC, being pre-execution event */
++	st.q	SP, FRAME_S(FSPC), r2
++
++	pta	ret_from_syscall, tr0
++	blink	tr0, ZERO		/* Resume normal return sequence */
++
++/*
++ * --- Switch to running under a particular ASID and return the previous ASID value
++ * --- The caller is assumed to have done a cli before calling this.
++ *
++ * Input r2 : new ASID
++ * Output r2 : old ASID
++ */
++
++	.global switch_and_save_asid
++switch_and_save_asid:
++	getcon	sr, r0
++	movi	255, r4
++	shlli 	r4, 16, r4	/* r4 = mask to select ASID */
++	and	r0, r4, r3	/* r3 = shifted old ASID */
++	andi	r2, 255, r2	/* mask down new ASID */
++	shlli	r2, 16, r2	/* align new ASID against SR.ASID */
++	andc	r0, r4, r0	/* efface old ASID from SR */
++	or	r0, r2, r0	/* insert the new ASID */
++	putcon	r0, ssr
++	movi	1f, r0
++	putcon	r0, spc
++	rte
++	nop
++1:
++	ptabs	LINK, tr0
++	shlri	r3, 16, r2	/* r2 = old ASID */
++	blink tr0, r63
++
++	.global	route_to_panic_handler
++route_to_panic_handler:
++	/* Switch to real mode, goto panic_handler, don't return.  Useful for
++	   last-chance debugging, e.g. if no output wants to go to the console.
++	   */
++
++	movi	panic_handler - CONFIG_PAGE_OFFSET, r1
++	ptabs	r1, tr0
++	pta	1f, tr1
++	gettr	tr1, r0
++	putcon	r0, spc
++	getcon	sr, r0
++	movi	1, r1
++	shlli	r1, 31, r1
++	andc	r0, r1, r0
++	putcon	r0, ssr
++	rte
++	nop
++1:	/* Now in real mode */
++	blink tr0, r63
++	nop
++
++	.global peek_real_address_q
++peek_real_address_q:
++	/* Two args:
++	   r2 : real mode address to peek
++	   r2(out) : result quadword
++
++	   This is provided as a cheapskate way of manipulating device
++	   registers for debugging (to avoid the need to onchip_remap the debug
++	   module, and to avoid the need to onchip_remap the watchpoint
++	   controller in a way that identity maps sufficient bits to avoid the
++	   SH5-101 cut2 silicon defect).
++
++	   This code is not performance critical
++	*/
++
++	add.l	r2, r63, r2	/* sign extend address */
++	getcon	sr, r0		/* r0 = saved original SR */
++	movi	1, r1
++	shlli	r1, 28, r1
++	or	r0, r1, r1	/* r0 with block bit set */
++	putcon	r1, sr		/* now in critical section */
++	movi	1, r36
++	shlli	r36, 31, r36
++	andc	r1, r36, r1	/* turn sr.mmu off in real mode section */
++
++	putcon	r1, ssr
++	movi	.peek0 - CONFIG_PAGE_OFFSET, r36 /* real mode target address */
++	movi	1f, r37		/* virtual mode return addr */
++	putcon	r36, spc
++
++	synco
++	rte
++	nop
++
++.peek0:	/* come here in real mode, don't touch caches!!
++           still in critical section (sr.bl==1) */
++	putcon	r0, ssr
++	putcon	r37, spc
++	/* Here's the actual peek.  If the address is bad, all bets are now off
++	 * what will happen (handlers invoked in real-mode = bad news) */
++	ld.q	r2, 0, r2
++	synco
++	rte	/* Back to virtual mode */
++	nop
++
++1:
++	ptabs	LINK, tr0
++	blink	tr0, r63
++
++	.global poke_real_address_q
++poke_real_address_q:
++	/* Two args:
++	   r2 : real mode address to poke
++	   r3 : quadword value to write.
++
++	   This is provided as a cheapskate way of manipulating device
++	   registers for debugging (to avoid the need to onchip_remap the debug
++	   module, and to avoid the need to onchip_remap the watchpoint
++	   controller in a way that identity maps sufficient bits to avoid the
++	   SH5-101 cut2 silicon defect).
++
++	   This code is not performance critical
++	*/
++
++	add.l	r2, r63, r2	/* sign extend address */
++	getcon	sr, r0		/* r0 = saved original SR */
++	movi	1, r1
++	shlli	r1, 28, r1
++	or	r0, r1, r1	/* r0 with block bit set */
++	putcon	r1, sr		/* now in critical section */
++	movi	1, r36
++	shlli	r36, 31, r36
++	andc	r1, r36, r1	/* turn sr.mmu off in real mode section */
++
++	putcon	r1, ssr
++	movi	.poke0-CONFIG_PAGE_OFFSET, r36 /* real mode target address */
++	movi	1f, r37		/* virtual mode return addr */
++	putcon	r36, spc
++
++	synco
++	rte
++	nop
++
++.poke0:	/* come here in real mode, don't touch caches!!
++           still in critical section (sr.bl==1) */
++	putcon	r0, ssr
++	putcon	r37, spc
++	/* Here's the actual poke.  If the address is bad, all bets are now off
++	 * what will happen (handlers invoked in real-mode = bad news) */
++	st.q	r2, 0, r3
++	synco
++	rte	/* Back to virtual mode */
++	nop
++
++1:
++	ptabs	LINK, tr0
++	blink	tr0, r63
++
++/*
++ * --- User Access Handling Section
++ */
++
++/*
++ * User Access support. It all moved to non inlined Assembler
++ * functions in here.
++ *
++ * __kernel_size_t __copy_user(void *__to, const void *__from,
++ *			       __kernel_size_t __n)
++ *
++ * Inputs:
++ * (r2)  target address
++ * (r3)  source address
++ * (r4)  size in bytes
++ *
++ * Ouputs:
++ * (*r2) target data
++ * (r2)  non-copied bytes
++ *
++ * If a fault occurs on the user pointer, bail out early and return the
++ * number of bytes not copied in r2.
++ * Strategy : for large blocks, call a real memcpy function which can
++ * move >1 byte at a time using unaligned ld/st instructions, and can
++ * manipulate the cache using prefetch + alloco to improve the speed
++ * further.  If a fault occurs in that function, just revert to the
++ * byte-by-byte approach used for small blocks; this is rare so the
++ * performance hit for that case does not matter.
++ *
++ * For small blocks it's not worth the overhead of setting up and calling
++ * the memcpy routine; do the copy a byte at a time.
++ *
++ */
++	.global	__copy_user
++__copy_user:
++	pta	__copy_user_byte_by_byte, tr1
++	movi	16, r0 ! this value is a best guess, should tune it by benchmarking
++	bge/u	r0, r4, tr1
++	pta copy_user_memcpy, tr0
++	addi	SP, -32, SP
++	/* Save arguments in case we have to fix-up unhandled page fault */
++	st.q	SP, 0, r2
++	st.q	SP, 8, r3
++	st.q	SP, 16, r4
++	st.q	SP, 24, r35 ! r35 is callee-save
++	/* Save LINK in a register to reduce RTS time later (otherwise
++	   ld SP,*,LINK;ptabs LINK;trn;blink trn,r63 becomes a critical path) */
++	ori	LINK, 0, r35
++	blink	tr0, LINK
++
++	/* Copy completed normally if we get back here */
++	ptabs	r35, tr0
++	ld.q	SP, 24, r35
++	/* don't restore r2-r4, pointless */
++	/* set result=r2 to zero as the copy must have succeeded. */
++	or	r63, r63, r2
++	addi	SP, 32, SP
++	blink	tr0, r63 ! RTS
++
++	.global __copy_user_fixup
++__copy_user_fixup:
++	/* Restore stack frame */
++	ori	r35, 0, LINK
++	ld.q	SP, 24, r35
++	ld.q	SP, 16, r4
++	ld.q	SP,  8, r3
++	ld.q	SP,  0, r2
++	addi	SP, 32, SP
++	/* Fall through to original code, in the 'same' state we entered with */
++
++/* The slow byte-by-byte method is used if the fast copy traps due to a bad
++   user address.  In that rare case, the speed drop can be tolerated. */
++__copy_user_byte_by_byte:
++	pta	___copy_user_exit, tr1
++	pta	___copy_user1, tr0
++	beq/u	r4, r63, tr1	/* early exit for zero length copy */
++	sub	r2, r3, r0
++	addi	r0, -1, r0
++
++___copy_user1:
++	ld.b	r3, 0, r5		/* Fault address 1 */
++
++	/* Could rewrite this to use just 1 add, but the second comes 'free'
++	   due to load latency */
++	addi	r3, 1, r3
++	addi	r4, -1, r4		/* No real fixup required */
++___copy_user2:
++	stx.b	r3, r0, r5		/* Fault address 2 */
++	bne     r4, ZERO, tr0
++
++___copy_user_exit:
++	or	r4, ZERO, r2
++	ptabs	LINK, tr0
++	blink	tr0, ZERO
++
++/*
++ * __kernel_size_t __clear_user(void *addr, __kernel_size_t size)
++ *
++ * Inputs:
++ * (r2)  target address
++ * (r3)  size in bytes
++ *
++ * Ouputs:
++ * (*r2) zero-ed target data
++ * (r2)  non-zero-ed bytes
++ */
++	.global	__clear_user
++__clear_user:
++	pta	___clear_user_exit, tr1
++	pta	___clear_user1, tr0
++	beq/u	r3, r63, tr1
++
++___clear_user1:
++	st.b	r2, 0, ZERO		/* Fault address */
++	addi	r2, 1, r2
++	addi	r3, -1, r3		/* No real fixup required */
++	bne     r3, ZERO, tr0
++
++___clear_user_exit:
++	or	r3, ZERO, r2
++	ptabs	LINK, tr0
++	blink	tr0, ZERO
++
++
++/*
++ * int __strncpy_from_user(unsigned long __dest, unsigned long __src,
++ *			   int __count)
++ *
++ * Inputs:
++ * (r2)  target address
++ * (r3)  source address
++ * (r4)  maximum size in bytes
++ *
++ * Ouputs:
++ * (*r2) copied data
++ * (r2)  -EFAULT (in case of faulting)
++ *       copied data (otherwise)
++ */
++	.global	__strncpy_from_user
++__strncpy_from_user:
++	pta	___strncpy_from_user1, tr0
++	pta	___strncpy_from_user_done, tr1
++	or	r4, ZERO, r5		/* r5 = original count */
++	beq/u	r4, r63, tr1		/* early exit if r4==0 */
++	movi	-(EFAULT), r6		/* r6 = reply, no real fixup */
++	or	ZERO, ZERO, r7		/* r7 = data, clear top byte of data */
++
++___strncpy_from_user1:
++	ld.b	r3, 0, r7		/* Fault address: only in reading */
++	st.b	r2, 0, r7
++	addi	r2, 1, r2
++	addi	r3, 1, r3
++	beq/u	ZERO, r7, tr1
++	addi	r4, -1, r4		/* return real number of copied bytes */
++	bne/l	ZERO, r4, tr0
++
++___strncpy_from_user_done:
++	sub	r5, r4, r6		/* If done, return copied */
++
++___strncpy_from_user_exit:
++	or	r6, ZERO, r2
++	ptabs	LINK, tr0
++	blink	tr0, ZERO
++
++/*
++ * extern long __strnlen_user(const char *__s, long __n)
++ *
++ * Inputs:
++ * (r2)  source address
++ * (r3)  source size in bytes
++ *
++ * Ouputs:
++ * (r2)  -EFAULT (in case of faulting)
++ *       string length (otherwise)
++ */
++	.global	__strnlen_user
++__strnlen_user:
++	pta	___strnlen_user_set_reply, tr0
++	pta	___strnlen_user1, tr1
++	or	ZERO, ZERO, r5		/* r5 = counter */
++	movi	-(EFAULT), r6		/* r6 = reply, no real fixup */
++	or	ZERO, ZERO, r7		/* r7 = data, clear top byte of data */
++	beq	r3, ZERO, tr0
++
++___strnlen_user1:
++	ldx.b	r2, r5, r7		/* Fault address: only in reading */
++	addi	r3, -1, r3		/* No real fixup */
++	addi	r5, 1, r5
++	beq	r3, ZERO, tr0
++	bne	r7, ZERO, tr1
++! The line below used to be active.  This meant led to a junk byte lying between each pair
++! of entries in the argv & envp structures in memory.  Whilst the program saw the right data
++! via the argv and envp arguments to main, it meant the 'flat' representation visible through
++! /proc/$pid/cmdline was corrupt, causing trouble with ps, for example.
++!	addi	r5, 1, r5		/* Include '\0' */
++
++___strnlen_user_set_reply:
++	or	r5, ZERO, r6		/* If done, return counter */
++
++___strnlen_user_exit:
++	or	r6, ZERO, r2
++	ptabs	LINK, tr0
++	blink	tr0, ZERO
++
++/*
++ * extern long __get_user_asm_?(void *val, long addr)
++ *
++ * Inputs:
++ * (r2)  dest address
++ * (r3)  source address (in User Space)
++ *
++ * Ouputs:
++ * (r2)  -EFAULT (faulting)
++ *       0 	 (not faulting)
++ */
++	.global	__get_user_asm_b
++__get_user_asm_b:
++	or	r2, ZERO, r4
++	movi	-(EFAULT), r2		/* r2 = reply, no real fixup */
++
++___get_user_asm_b1:
++	ld.b	r3, 0, r5		/* r5 = data */
++	st.b	r4, 0, r5
++	or	ZERO, ZERO, r2
++
++___get_user_asm_b_exit:
++	ptabs	LINK, tr0
++	blink	tr0, ZERO
++
++
++	.global	__get_user_asm_w
++__get_user_asm_w:
++	or	r2, ZERO, r4
++	movi	-(EFAULT), r2		/* r2 = reply, no real fixup */
++
++___get_user_asm_w1:
++	ld.w	r3, 0, r5		/* r5 = data */
++	st.w	r4, 0, r5
++	or	ZERO, ZERO, r2
++
++___get_user_asm_w_exit:
++	ptabs	LINK, tr0
++	blink	tr0, ZERO
++
++
++	.global	__get_user_asm_l
++__get_user_asm_l:
++	or	r2, ZERO, r4
++	movi	-(EFAULT), r2		/* r2 = reply, no real fixup */
++
++___get_user_asm_l1:
++	ld.l	r3, 0, r5		/* r5 = data */
++	st.l	r4, 0, r5
++	or	ZERO, ZERO, r2
++
++___get_user_asm_l_exit:
++	ptabs	LINK, tr0
++	blink	tr0, ZERO
++
++
++	.global	__get_user_asm_q
++__get_user_asm_q:
++	or	r2, ZERO, r4
++	movi	-(EFAULT), r2		/* r2 = reply, no real fixup */
++
++___get_user_asm_q1:
++	ld.q	r3, 0, r5		/* r5 = data */
++	st.q	r4, 0, r5
++	or	ZERO, ZERO, r2
++
++___get_user_asm_q_exit:
++	ptabs	LINK, tr0
++	blink	tr0, ZERO
++
++/*
++ * extern long __put_user_asm_?(void *pval, long addr)
++ *
++ * Inputs:
++ * (r2)  kernel pointer to value
++ * (r3)  dest address (in User Space)
++ *
++ * Ouputs:
++ * (r2)  -EFAULT (faulting)
++ *       0 	 (not faulting)
++ */
++	.global	__put_user_asm_b
++__put_user_asm_b:
++	ld.b	r2, 0, r4		/* r4 = data */
++	movi	-(EFAULT), r2		/* r2 = reply, no real fixup */
++
++___put_user_asm_b1:
++	st.b	r3, 0, r4
++	or	ZERO, ZERO, r2
++
++___put_user_asm_b_exit:
++	ptabs	LINK, tr0
++	blink	tr0, ZERO
++
++
++	.global	__put_user_asm_w
++__put_user_asm_w:
++	ld.w	r2, 0, r4		/* r4 = data */
++	movi	-(EFAULT), r2		/* r2 = reply, no real fixup */
++
++___put_user_asm_w1:
++	st.w	r3, 0, r4
++	or	ZERO, ZERO, r2
++
++___put_user_asm_w_exit:
++	ptabs	LINK, tr0
++	blink	tr0, ZERO
++
++
++	.global	__put_user_asm_l
++__put_user_asm_l:
++	ld.l	r2, 0, r4		/* r4 = data */
++	movi	-(EFAULT), r2		/* r2 = reply, no real fixup */
++
++___put_user_asm_l1:
++	st.l	r3, 0, r4
++	or	ZERO, ZERO, r2
++
++___put_user_asm_l_exit:
++	ptabs	LINK, tr0
++	blink	tr0, ZERO
++
++
++	.global	__put_user_asm_q
++__put_user_asm_q:
++	ld.q	r2, 0, r4		/* r4 = data */
++	movi	-(EFAULT), r2		/* r2 = reply, no real fixup */
++
++___put_user_asm_q1:
++	st.q	r3, 0, r4
++	or	ZERO, ZERO, r2
++
++___put_user_asm_q_exit:
++	ptabs	LINK, tr0
++	blink	tr0, ZERO
++
++panic_stash_regs:
++	/* The idea is : when we get an unhandled panic, we dump the registers
++	   to a known memory location, the just sit in a tight loop.
++	   This allows the human to look at the memory region through the GDB
++	   session (assuming the debug module's SHwy initiator isn't locked up
++	   or anything), to hopefully analyze the cause of the panic. */
++
++	/* On entry, former r15 (SP) is in DCR
++	   former r0  is at resvec_saved_area + 0
++	   former r1  is at resvec_saved_area + 8
++	   former tr0 is at resvec_saved_area + 32
++	   DCR is the only register whose value is lost altogether.
++	*/
++
++	movi	0xffffffff80000000, r0 ! phy of dump area
++	ld.q	SP, 0x000, r1	! former r0
++	st.q	r0,  0x000, r1
++	ld.q	SP, 0x008, r1	! former r1
++	st.q	r0,  0x008, r1
++	st.q	r0,  0x010, r2
++	st.q	r0,  0x018, r3
++	st.q	r0,  0x020, r4
++	st.q	r0,  0x028, r5
++	st.q	r0,  0x030, r6
++	st.q	r0,  0x038, r7
++	st.q	r0,  0x040, r8
++	st.q	r0,  0x048, r9
++	st.q	r0,  0x050, r10
++	st.q	r0,  0x058, r11
++	st.q	r0,  0x060, r12
++	st.q	r0,  0x068, r13
++	st.q	r0,  0x070, r14
++	getcon	dcr, r14
++	st.q	r0,  0x078, r14
++	st.q	r0,  0x080, r16
++	st.q	r0,  0x088, r17
++	st.q	r0,  0x090, r18
++	st.q	r0,  0x098, r19
++	st.q	r0,  0x0a0, r20
++	st.q	r0,  0x0a8, r21
++	st.q	r0,  0x0b0, r22
++	st.q	r0,  0x0b8, r23
++	st.q	r0,  0x0c0, r24
++	st.q	r0,  0x0c8, r25
++	st.q	r0,  0x0d0, r26
++	st.q	r0,  0x0d8, r27
++	st.q	r0,  0x0e0, r28
++	st.q	r0,  0x0e8, r29
++	st.q	r0,  0x0f0, r30
++	st.q	r0,  0x0f8, r31
++	st.q	r0,  0x100, r32
++	st.q	r0,  0x108, r33
++	st.q	r0,  0x110, r34
++	st.q	r0,  0x118, r35
++	st.q	r0,  0x120, r36
++	st.q	r0,  0x128, r37
++	st.q	r0,  0x130, r38
++	st.q	r0,  0x138, r39
++	st.q	r0,  0x140, r40
++	st.q	r0,  0x148, r41
++	st.q	r0,  0x150, r42
++	st.q	r0,  0x158, r43
++	st.q	r0,  0x160, r44
++	st.q	r0,  0x168, r45
++	st.q	r0,  0x170, r46
++	st.q	r0,  0x178, r47
++	st.q	r0,  0x180, r48
++	st.q	r0,  0x188, r49
++	st.q	r0,  0x190, r50
++	st.q	r0,  0x198, r51
++	st.q	r0,  0x1a0, r52
++	st.q	r0,  0x1a8, r53
++	st.q	r0,  0x1b0, r54
++	st.q	r0,  0x1b8, r55
++	st.q	r0,  0x1c0, r56
++	st.q	r0,  0x1c8, r57
++	st.q	r0,  0x1d0, r58
++	st.q	r0,  0x1d8, r59
++	st.q	r0,  0x1e0, r60
++	st.q	r0,  0x1e8, r61
++	st.q	r0,  0x1f0, r62
++	st.q	r0,  0x1f8, r63	! bogus, but for consistency's sake...
++
++	ld.q	SP, 0x020, r1  ! former tr0
++	st.q	r0,  0x200, r1
++	gettr	tr1, r1
++	st.q	r0,  0x208, r1
++	gettr	tr2, r1
++	st.q	r0,  0x210, r1
++	gettr	tr3, r1
++	st.q	r0,  0x218, r1
++	gettr	tr4, r1
++	st.q	r0,  0x220, r1
++	gettr	tr5, r1
++	st.q	r0,  0x228, r1
++	gettr	tr6, r1
++	st.q	r0,  0x230, r1
++	gettr	tr7, r1
++	st.q	r0,  0x238, r1
++
++	getcon	sr,  r1
++	getcon	ssr,  r2
++	getcon	pssr,  r3
++	getcon	spc,  r4
++	getcon	pspc,  r5
++	getcon	intevt,  r6
++	getcon	expevt,  r7
++	getcon	pexpevt,  r8
++	getcon	tra,  r9
++	getcon	tea,  r10
++	getcon	kcr0, r11
++	getcon	kcr1, r12
++	getcon	vbr,  r13
++	getcon	resvec,  r14
++
++	st.q	r0,  0x240, r1
++	st.q	r0,  0x248, r2
++	st.q	r0,  0x250, r3
++	st.q	r0,  0x258, r4
++	st.q	r0,  0x260, r5
++	st.q	r0,  0x268, r6
++	st.q	r0,  0x270, r7
++	st.q	r0,  0x278, r8
++	st.q	r0,  0x280, r9
++	st.q	r0,  0x288, r10
++	st.q	r0,  0x290, r11
++	st.q	r0,  0x298, r12
++	st.q	r0,  0x2a0, r13
++	st.q	r0,  0x2a8, r14
++
++	getcon	SPC,r2
++	getcon	SSR,r3
++	getcon	EXPEVT,r4
++	/* Prepare to jump to C - physical address */
++	movi	panic_handler-CONFIG_PAGE_OFFSET, r1
++	ori	r1, 1, r1
++	ptabs   r1, tr0
++	getcon	DCR, SP
++	blink	tr0, ZERO
++	nop
++	nop
++	nop
++	nop
++
++
++
++
++/*
++ * --- Signal Handling Section
++ */
++
++/*
++ * extern long long _sa_default_rt_restorer
++ * extern long long _sa_default_restorer
++ *
++ *		 or, better,
++ *
++ * extern void _sa_default_rt_restorer(void)
++ * extern void _sa_default_restorer(void)
++ *
++ * Code prototypes to do a sys_rt_sigreturn() or sys_sysreturn()
++ * from user space. Copied into user space by signal management.
++ * Both must be quad aligned and 2 quad long (4 instructions).
++ *
++ */
++	.balign 8
++	.global sa_default_rt_restorer
++sa_default_rt_restorer:
++	movi	0x10, r9
++	shori	__NR_rt_sigreturn, r9
++	trapa	r9
++	nop
++
++	.balign 8
++	.global sa_default_restorer
++sa_default_restorer:
++	movi	0x10, r9
++	shori	__NR_sigreturn, r9
++	trapa	r9
++	nop
++
++/*
++ * --- __ex_table Section
++ */
++
++/*
++ * User Access Exception Table.
++ */
++	.section	__ex_table,  "a"
++
++	.global asm_uaccess_start	/* Just a marker */
++asm_uaccess_start:
++
++	.long	___copy_user1, ___copy_user_exit
++	.long	___copy_user2, ___copy_user_exit
++	.long	___clear_user1, ___clear_user_exit
++	.long	___strncpy_from_user1, ___strncpy_from_user_exit
++	.long	___strnlen_user1, ___strnlen_user_exit
++	.long	___get_user_asm_b1, ___get_user_asm_b_exit
++	.long	___get_user_asm_w1, ___get_user_asm_w_exit
++	.long	___get_user_asm_l1, ___get_user_asm_l_exit
++	.long	___get_user_asm_q1, ___get_user_asm_q_exit
++	.long	___put_user_asm_b1, ___put_user_asm_b_exit
++	.long	___put_user_asm_w1, ___put_user_asm_w_exit
++	.long	___put_user_asm_l1, ___put_user_asm_l_exit
++	.long	___put_user_asm_q1, ___put_user_asm_q_exit
++
++	.global asm_uaccess_end		/* Just a marker */
++asm_uaccess_end:
++
++
++
++
++/*
++ * --- .text.init Section
++ */
++
++	.section	.text.init, "ax"
++
++/*
++ * void trap_init (void)
++ *
++ */
++	.global	trap_init
++trap_init:
++	addi	SP, -24, SP			/* Room to save r28/r29/r30 */
++	st.q	SP, 0, r28
++	st.q	SP, 8, r29
++	st.q	SP, 16, r30
++
++	/* Set VBR and RESVEC */
++	movi	LVBR_block, r19
++	andi	r19, -4, r19			/* reset MMUOFF + reserved */
++	/* For RESVEC exceptions we force the MMU off, which means we need the
++	   physical address. */
++	movi	LRESVEC_block-CONFIG_PAGE_OFFSET, r20
++	andi	r20, -4, r20			/* reset reserved */
++	ori	r20, 1, r20			/* set MMUOFF */
++	putcon	r19, VBR
++	putcon	r20, RESVEC
++
++	/* Sanity check */
++	movi	LVBR_block_end, r21
++	andi	r21, -4, r21
++	movi	BLOCK_SIZE, r29			/* r29 = expected size */
++	or	r19, ZERO, r30
++	add	r19, r29, r19
++
++	/*
++	 * Ugly, but better loop forever now than crash afterwards.
++	 * We should print a message, but if we touch LVBR or
++	 * LRESVEC blocks we should not be surprised if we get stuck
++	 * in trap_init().
++	 */
++	pta	trap_init_loop, tr1
++	gettr	tr1, r28			/* r28 = trap_init_loop */
++	sub	r21, r30, r30			/* r30 = actual size */
++
++	/*
++	 * VBR/RESVEC handlers overlap by being bigger than
++	 * allowed. Very bad. Just loop forever.
++	 * (r28) panic/loop address
++	 * (r29) expected size
++	 * (r30) actual size
++	 */
++trap_init_loop:
++	bne	r19, r21, tr1
++
++	/* Now that exception vectors are set up reset SR.BL */
++	getcon 	SR, r22
++	movi	SR_UNBLOCK_EXC, r23
++	and	r22, r23, r22
++	putcon	r22, SR
++
++	addi	SP, 24, SP
++	ptabs	LINK, tr0
++	blink	tr0, ZERO
++
+diff --git a/arch/sh/kernel/cpu/sh5/fpu.c b/arch/sh/kernel/cpu/sh5/fpu.c
+new file mode 100644
+index 0000000..30b76a9
+--- /dev/null
++++ b/arch/sh/kernel/cpu/sh5/fpu.c
+@@ -0,0 +1,166 @@
++/*
++ * arch/sh/kernel/cpu/sh5/fpu.c
++ *
++ * Copyright (C) 2001  Manuela Cirronis, Paolo Alberelli
++ * Copyright (C) 2002  STMicroelectronics Limited
++ *   Author : Stuart Menefy
++ *
++ * Started from SH4 version:
++ *   Copyright (C) 1999, 2000  Kaz Kojima & Niibe Yutaka
++ *
++ * 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/sched.h>
++#include <linux/signal.h>
++#include <asm/processor.h>
++#include <asm/user.h>
++#include <asm/io.h>
++
++/*
++ * Initially load the FPU with signalling NANS.  This bit pattern
++ * has the property that no matter whether considered as single or as
++ * double precision, it still represents a signalling NAN.
++ */
++#define sNAN64		0xFFFFFFFFFFFFFFFFULL
++#define sNAN32		0xFFFFFFFFUL
++
++static union sh_fpu_union init_fpuregs = {
++	.hard = {
++		.fp_regs = { [0 ... 63] = sNAN32 },
++		.fpscr = FPSCR_INIT
++	}
++};
++
++void save_fpu(struct task_struct *tsk, struct pt_regs *regs)
++{
++	asm volatile("fst.p     %0, (0*8), fp0\n\t"
++		     "fst.p     %0, (1*8), fp2\n\t"
++		     "fst.p     %0, (2*8), fp4\n\t"
++		     "fst.p     %0, (3*8), fp6\n\t"
++		     "fst.p     %0, (4*8), fp8\n\t"
++		     "fst.p     %0, (5*8), fp10\n\t"
++		     "fst.p     %0, (6*8), fp12\n\t"
++		     "fst.p     %0, (7*8), fp14\n\t"
++		     "fst.p     %0, (8*8), fp16\n\t"
++		     "fst.p     %0, (9*8), fp18\n\t"
++		     "fst.p     %0, (10*8), fp20\n\t"
++		     "fst.p     %0, (11*8), fp22\n\t"
++		     "fst.p     %0, (12*8), fp24\n\t"
++		     "fst.p     %0, (13*8), fp26\n\t"
++		     "fst.p     %0, (14*8), fp28\n\t"
++		     "fst.p     %0, (15*8), fp30\n\t"
++		     "fst.p     %0, (16*8), fp32\n\t"
++		     "fst.p     %0, (17*8), fp34\n\t"
++		     "fst.p     %0, (18*8), fp36\n\t"
++		     "fst.p     %0, (19*8), fp38\n\t"
++		     "fst.p     %0, (20*8), fp40\n\t"
++		     "fst.p     %0, (21*8), fp42\n\t"
++		     "fst.p     %0, (22*8), fp44\n\t"
++		     "fst.p     %0, (23*8), fp46\n\t"
++		     "fst.p     %0, (24*8), fp48\n\t"
++		     "fst.p     %0, (25*8), fp50\n\t"
++		     "fst.p     %0, (26*8), fp52\n\t"
++		     "fst.p     %0, (27*8), fp54\n\t"
++		     "fst.p     %0, (28*8), fp56\n\t"
++		     "fst.p     %0, (29*8), fp58\n\t"
++		     "fst.p     %0, (30*8), fp60\n\t"
++		     "fst.p     %0, (31*8), fp62\n\t"
++
++		     "fgetscr   fr63\n\t"
++		     "fst.s     %0, (32*8), fr63\n\t"
++		: /* no output */
++		: "r" (&tsk->thread.fpu.hard)
++		: "memory");
++}
++
++static inline void
++fpload(struct sh_fpu_hard_struct *fpregs)
++{
++	asm volatile("fld.p     %0, (0*8), fp0\n\t"
++		     "fld.p     %0, (1*8), fp2\n\t"
++		     "fld.p     %0, (2*8), fp4\n\t"
++		     "fld.p     %0, (3*8), fp6\n\t"
++		     "fld.p     %0, (4*8), fp8\n\t"
++		     "fld.p     %0, (5*8), fp10\n\t"
++		     "fld.p     %0, (6*8), fp12\n\t"
++		     "fld.p     %0, (7*8), fp14\n\t"
++		     "fld.p     %0, (8*8), fp16\n\t"
++		     "fld.p     %0, (9*8), fp18\n\t"
++		     "fld.p     %0, (10*8), fp20\n\t"
++		     "fld.p     %0, (11*8), fp22\n\t"
++		     "fld.p     %0, (12*8), fp24\n\t"
++		     "fld.p     %0, (13*8), fp26\n\t"
++		     "fld.p     %0, (14*8), fp28\n\t"
++		     "fld.p     %0, (15*8), fp30\n\t"
++		     "fld.p     %0, (16*8), fp32\n\t"
++		     "fld.p     %0, (17*8), fp34\n\t"
++		     "fld.p     %0, (18*8), fp36\n\t"
++		     "fld.p     %0, (19*8), fp38\n\t"
++		     "fld.p     %0, (20*8), fp40\n\t"
++		     "fld.p     %0, (21*8), fp42\n\t"
++		     "fld.p     %0, (22*8), fp44\n\t"
++		     "fld.p     %0, (23*8), fp46\n\t"
++		     "fld.p     %0, (24*8), fp48\n\t"
++		     "fld.p     %0, (25*8), fp50\n\t"
++		     "fld.p     %0, (26*8), fp52\n\t"
++		     "fld.p     %0, (27*8), fp54\n\t"
++		     "fld.p     %0, (28*8), fp56\n\t"
++		     "fld.p     %0, (29*8), fp58\n\t"
++		     "fld.p     %0, (30*8), fp60\n\t"
++
++		     "fld.s     %0, (32*8), fr63\n\t"
++		     "fputscr   fr63\n\t"
++
++		     "fld.p     %0, (31*8), fp62\n\t"
++		: /* no output */
++		: "r" (fpregs) );
++}
++
++void fpinit(struct sh_fpu_hard_struct *fpregs)
++{
++	*fpregs = init_fpuregs.hard;
++}
++
++asmlinkage void
++do_fpu_error(unsigned long ex, struct pt_regs *regs)
++{
++	struct task_struct *tsk = current;
++
++	regs->pc += 4;
++
++	tsk->thread.trap_no = 11;
++	tsk->thread.error_code = 0;
++	force_sig(SIGFPE, tsk);
++}
++
++
++asmlinkage void
++do_fpu_state_restore(unsigned long ex, struct pt_regs *regs)
++{
++	void die(const char *str, struct pt_regs *regs, long err);
++
++	if (! user_mode(regs))
++		die("FPU used in kernel", regs, ex);
++
++	regs->sr &= ~SR_FD;
++
++	if (last_task_used_math == current)
++		return;
++
++	enable_fpu();
++	if (last_task_used_math != NULL)
++		/* Other processes fpu state, save away */
++		save_fpu(last_task_used_math, regs);
++
++        last_task_used_math = current;
++        if (used_math()) {
++                fpload(&current->thread.fpu.hard);
++        } else {
++		/* First time FPU user.  */
++		fpload(&init_fpuregs.hard);
++                set_used_math();
++        }
++	disable_fpu();
++}
+diff --git a/arch/sh/kernel/cpu/sh5/probe.c b/arch/sh/kernel/cpu/sh5/probe.c
+new file mode 100644
+index 0000000..15d167f
+--- /dev/null
++++ b/arch/sh/kernel/cpu/sh5/probe.c
+@@ -0,0 +1,76 @@
++/*
++ * arch/sh/kernel/cpu/sh5/probe.c
++ *
++ * CPU Subtype Probing for SH-5.
++ *
++ * Copyright (C) 2000, 2001  Paolo Alberelli
++ * Copyright (C) 2003 - 2007  Paul Mundt
++ *
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License.  See the file "COPYING" in the main directory of this archive
++ * for more details.
++ */
++#include <linux/init.h>
++#include <linux/io.h>
++#include <linux/string.h>
++#include <asm/processor.h>
++#include <asm/cache.h>
++
++int __init detect_cpu_and_cache_system(void)
++{
++	unsigned long long cir;
++
++	/* Do peeks in real mode to avoid having to set up a mapping for the
++	   WPC registers. On SH5-101 cut2, such a mapping would be exposed to
++	   an address translation erratum which would make it hard to set up
++	   correctly. */
++	cir = peek_real_address_q(0x0d000008);
++	if ((cir & 0xffff) == 0x5103) {
++		boot_cpu_data.type = CPU_SH5_103;
++	} else if (((cir >> 32) & 0xffff) == 0x51e2) {
++		/* CPU.VCR aliased at CIR address on SH5-101 */
++		boot_cpu_data.type = CPU_SH5_101;
++	} else {
++		boot_cpu_data.type = CPU_SH_NONE;
++	}
++
++	/*
++	 * First, setup some sane values for the I-cache.
++	 */
++	boot_cpu_data.icache.ways		= 4;
++	boot_cpu_data.icache.sets		= 256;
++	boot_cpu_data.icache.linesz		= L1_CACHE_BYTES;
++
++#if 0
++	/*
++	 * FIXME: This can probably be cleaned up a bit as well.. for example,
++	 * do we really need the way shift _and_ the way_step_shift ?? Judging
++	 * by the existing code, I would guess no.. is there any valid reason
++	 * why we need to be tracking this around?
++	 */
++	boot_cpu_data.icache.way_shift		= 13;
++	boot_cpu_data.icache.entry_shift	= 5;
++	boot_cpu_data.icache.set_shift		= 4;
++	boot_cpu_data.icache.way_step_shift	= 16;
++	boot_cpu_data.icache.asid_shift		= 2;
++
++	/*
++	 * way offset = cache size / associativity, so just don't factor in
++	 * associativity in the first place..
++	 */
++	boot_cpu_data.icache.way_ofs	= boot_cpu_data.icache.sets *
++					  boot_cpu_data.icache.linesz;
++
++	boot_cpu_data.icache.asid_mask		= 0x3fc;
++	boot_cpu_data.icache.idx_mask		= 0x1fe0;
++	boot_cpu_data.icache.epn_mask		= 0xffffe000;
++#endif
++
++	boot_cpu_data.icache.flags		= 0;
++
++	/* A trivial starting point.. */
++	memcpy(&boot_cpu_data.dcache,
++	       &boot_cpu_data.icache, sizeof(struct cache_info));
++
++	return 0;
++}
+diff --git a/arch/sh/kernel/cpu/sh5/switchto.S b/arch/sh/kernel/cpu/sh5/switchto.S
+new file mode 100644
+index 0000000..45c351b
+--- /dev/null
++++ b/arch/sh/kernel/cpu/sh5/switchto.S
+@@ -0,0 +1,198 @@
++/*
++ * arch/sh/kernel/cpu/sh5/switchto.S
++ *
++ * sh64 context switch
++ *
++ * Copyright (C) 2004  Richard Curnow
++ *
++ * 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.
++*/
++
++	.section .text..SHmedia32,"ax"
++	.little
++
++	.balign 32
++
++	.type sh64_switch_to, at function
++	.global sh64_switch_to
++	.global __sh64_switch_to_end
++sh64_switch_to:
++
++/* Incoming args
++   r2 - prev
++   r3 - &prev->thread
++   r4 - next
++   r5 - &next->thread
++
++   Outgoing results
++   r2 - last (=prev) : this just stays in r2 throughout
++
++   Want to create a full (struct pt_regs) on the stack to allow backtracing
++   functions to work.  However, we only need to populate the callee-save
++   register slots in this structure; since we're a function our ancestors must
++   have themselves preserved all caller saved state in the stack.  This saves
++   some wasted effort since we won't need to look at the values.
++
++   In particular, all caller-save registers are immediately available for
++   scratch use.
++
++*/
++
++#define FRAME_SIZE (76*8 + 8)
++
++	movi	FRAME_SIZE, r0
++	sub.l	r15, r0, r15
++	! Do normal-style register save to support backtrace
++
++	st.l	r15,   0, r18	! save link reg
++	st.l	r15,   4, r14	! save fp
++	add.l	r15, r63, r14	! setup frame pointer
++
++	! hopefully this looks normal to the backtrace now.
++
++	addi.l	r15,   8, r1    ! base of pt_regs
++	addi.l	r1,   24, r0    ! base of pt_regs.regs
++	addi.l	r0, (63*8), r8	! base of pt_regs.trregs
++
++	/* Note : to be fixed?
++	   struct pt_regs is really designed for holding the state on entry
++	   to an exception, i.e. pc,sr,regs etc.  However, for the context
++	   switch state, some of this is not required.  But the unwinder takes
++	   struct pt_regs * as an arg so we have to build this structure
++	   to allow unwinding switched tasks in show_state() */
++
++	st.q	r0, ( 9*8), r9
++	st.q	r0, (10*8), r10
++	st.q	r0, (11*8), r11
++	st.q	r0, (12*8), r12
++	st.q	r0, (13*8), r13
++	st.q	r0, (14*8), r14 ! for unwind, want to look as though we took a trap at
++	! the point where the process is left in suspended animation, i.e. current
++	! fp here, not the saved one.
++	st.q	r0, (16*8), r16
++
++	st.q	r0, (24*8), r24
++	st.q	r0, (25*8), r25
++	st.q	r0, (26*8), r26
++	st.q	r0, (27*8), r27
++	st.q	r0, (28*8), r28
++	st.q	r0, (29*8), r29
++	st.q	r0, (30*8), r30
++	st.q	r0, (31*8), r31
++	st.q	r0, (32*8), r32
++	st.q	r0, (33*8), r33
++	st.q	r0, (34*8), r34
++	st.q	r0, (35*8), r35
++
++	st.q	r0, (44*8), r44
++	st.q	r0, (45*8), r45
++	st.q	r0, (46*8), r46
++	st.q	r0, (47*8), r47
++	st.q	r0, (48*8), r48
++	st.q	r0, (49*8), r49
++	st.q	r0, (50*8), r50
++	st.q	r0, (51*8), r51
++	st.q	r0, (52*8), r52
++	st.q	r0, (53*8), r53
++	st.q	r0, (54*8), r54
++	st.q	r0, (55*8), r55
++	st.q	r0, (56*8), r56
++	st.q	r0, (57*8), r57
++	st.q	r0, (58*8), r58
++	st.q	r0, (59*8), r59
++
++	! do this early as pta->gettr has no pipeline forwarding (=> 5 cycle latency)
++	! Use a local label to avoid creating a symbol that will confuse the !
++	! backtrace
++	pta	.Lsave_pc, tr0
++
++	gettr	tr5, r45
++	gettr	tr6, r46
++	gettr	tr7, r47
++	st.q	r8, (5*8), r45
++	st.q	r8, (6*8), r46
++	st.q	r8, (7*8), r47
++
++	! Now switch context
++	gettr	tr0, r9
++	st.l	r3, 0, r15	! prev->thread.sp
++	st.l	r3, 8, r1	! prev->thread.kregs
++	st.l	r3, 4, r9	! prev->thread.pc
++	st.q	r1, 0, r9	! save prev->thread.pc into pt_regs->pc
++
++	! Load PC for next task (init value or save_pc later)
++	ld.l	r5, 4, r18	! next->thread.pc
++	! Switch stacks
++	ld.l	r5, 0, r15	! next->thread.sp
++	ptabs	r18, tr0
++
++	! Update current
++	ld.l	r4, 4, r9	! next->thread_info (2nd element of next task_struct)
++	putcon	r9, kcr0	! current = next->thread_info
++
++	! go to save_pc for a reschedule, or the initial thread.pc for a new process
++	blink	tr0, r63
++
++	! Restore (when we come back to a previously saved task)
++.Lsave_pc:
++	addi.l	r15, 32, r0	! r0 = next's regs
++	addi.l	r0, (63*8), r8	! r8 = next's tr_regs
++
++	ld.q	r8, (5*8), r45
++	ld.q	r8, (6*8), r46
++	ld.q	r8, (7*8), r47
++	ptabs	r45, tr5
++	ptabs	r46, tr6
++	ptabs	r47, tr7
++
++	ld.q	r0, ( 9*8), r9
++	ld.q	r0, (10*8), r10
++	ld.q	r0, (11*8), r11
++	ld.q	r0, (12*8), r12
++	ld.q	r0, (13*8), r13
++	ld.q	r0, (14*8), r14
++	ld.q	r0, (16*8), r16
++
++	ld.q	r0, (24*8), r24
++	ld.q	r0, (25*8), r25
++	ld.q	r0, (26*8), r26
++	ld.q	r0, (27*8), r27
++	ld.q	r0, (28*8), r28
++	ld.q	r0, (29*8), r29
++	ld.q	r0, (30*8), r30
++	ld.q	r0, (31*8), r31
++	ld.q	r0, (32*8), r32
++	ld.q	r0, (33*8), r33
++	ld.q	r0, (34*8), r34
++	ld.q	r0, (35*8), r35
++
++	ld.q	r0, (44*8), r44
++	ld.q	r0, (45*8), r45
++	ld.q	r0, (46*8), r46
++	ld.q	r0, (47*8), r47
++	ld.q	r0, (48*8), r48
++	ld.q	r0, (49*8), r49
++	ld.q	r0, (50*8), r50
++	ld.q	r0, (51*8), r51
++	ld.q	r0, (52*8), r52
++	ld.q	r0, (53*8), r53
++	ld.q	r0, (54*8), r54
++	ld.q	r0, (55*8), r55
++	ld.q	r0, (56*8), r56
++	ld.q	r0, (57*8), r57
++	ld.q	r0, (58*8), r58
++	ld.q	r0, (59*8), r59
++
++	! epilogue
++	ld.l	r15, 0, r18
++	ld.l	r15, 4, r14
++	ptabs	r18, tr0
++	movi	FRAME_SIZE, r0
++	add	r15, r0, r15
++	blink	tr0, r63
++__sh64_switch_to_end:
++.LFE1:
++	.size	sh64_switch_to,.LFE1-sh64_switch_to
++
+diff --git a/arch/sh/kernel/cpu/sh5/unwind.c b/arch/sh/kernel/cpu/sh5/unwind.c
+new file mode 100644
+index 0000000..119c20a
+--- /dev/null
++++ b/arch/sh/kernel/cpu/sh5/unwind.c
+@@ -0,0 +1,326 @@
++/*
++ * arch/sh/kernel/cpu/sh5/unwind.c
++ *
++ * Copyright (C) 2004  Paul Mundt
++ * Copyright (C) 2004  Richard Curnow
++ *
++ * 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/kallsyms.h>
++#include <linux/kernel.h>
++#include <linux/types.h>
++#include <linux/errno.h>
++#include <asm/page.h>
++#include <asm/ptrace.h>
++#include <asm/processor.h>
++#include <asm/io.h>
++
++static u8 regcache[63];
++
++/*
++ * Finding the previous stack frame isn't horribly straightforward as it is
++ * on some other platforms. In the sh64 case, we don't have "linked" stack
++ * frames, so we need to do a bit of work to determine the previous frame,
++ * and in turn, the previous r14/r18 pair.
++ *
++ * There are generally a few cases which determine where we can find out
++ * the r14/r18 values. In the general case, this can be determined by poking
++ * around the prologue of the symbol PC is in (note that we absolutely must
++ * have frame pointer support as well as the kernel symbol table mapped,
++ * otherwise we can't even get this far).
++ *
++ * In other cases, such as the interrupt/exception path, we can poke around
++ * the sp/fp.
++ *
++ * Notably, this entire approach is somewhat error prone, and in the event
++ * that the previous frame cannot be determined, that's all we can do.
++ * Either way, this still leaves us with a more correct backtrace then what
++ * we would be able to come up with by walking the stack (which is garbage
++ * for anything beyond the first frame).
++ *						-- PFM.
++ */
++static int lookup_prev_stack_frame(unsigned long fp, unsigned long pc,
++		      unsigned long *pprev_fp, unsigned long *pprev_pc,
++		      struct pt_regs *regs)
++{
++	const char *sym;
++	char namebuf[128];
++	unsigned long offset;
++	unsigned long prologue = 0;
++	unsigned long fp_displacement = 0;
++	unsigned long fp_prev = 0;
++	unsigned long offset_r14 = 0, offset_r18 = 0;
++	int i, found_prologue_end = 0;
++
++	sym = kallsyms_lookup(pc, NULL, &offset, NULL, namebuf);
++	if (!sym)
++		return -EINVAL;
++
++	prologue = pc - offset;
++	if (!prologue)
++		return -EINVAL;
++
++	/* Validate fp, to avoid risk of dereferencing a bad pointer later.
++	   Assume 128Mb since that's the amount of RAM on a Cayman.  Modify
++	   when there is an SH-5 board with more. */
++	if ((fp < (unsigned long) phys_to_virt(__MEMORY_START)) ||
++	    (fp >= (unsigned long)(phys_to_virt(__MEMORY_START)) + 128*1024*1024) ||
++	    ((fp & 7) != 0)) {
++		return -EINVAL;
++	}
++
++	/*
++	 * Depth to walk, depth is completely arbitrary.
++	 */
++	for (i = 0; i < 100; i++, prologue += sizeof(unsigned long)) {
++		unsigned long op;
++		u8 major, minor;
++		u8 src, dest, disp;
++
++		op = *(unsigned long *)prologue;
++
++		major = (op >> 26) & 0x3f;
++		src   = (op >> 20) & 0x3f;
++		minor = (op >> 16) & 0xf;
++		disp  = (op >> 10) & 0x3f;
++		dest  = (op >>  4) & 0x3f;
++
++		/*
++		 * Stack frame creation happens in a number of ways.. in the
++		 * general case when the stack frame is less than 511 bytes,
++		 * it's generally created by an addi or addi.l:
++		 *
++		 *	addi/addi.l r15, -FRAME_SIZE, r15
++		 *
++		 * in the event that the frame size is bigger than this, it's
++		 * typically created using a movi/sub pair as follows:
++		 *
++		 *	movi	FRAME_SIZE, rX
++		 *	sub	r15, rX, r15
++		 */
++
++		switch (major) {
++		case (0x00 >> 2):
++			switch (minor) {
++			case 0x8: /* add.l */
++			case 0x9: /* add */
++				/* Look for r15, r63, r14 */
++				if (src == 15 && disp == 63 && dest == 14)
++					found_prologue_end = 1;
++
++				break;
++			case 0xa: /* sub.l */
++			case 0xb: /* sub */
++				if (src != 15 || dest != 15)
++					continue;
++
++				fp_displacement -= regcache[disp];
++				fp_prev = fp - fp_displacement;
++				break;
++			}
++			break;
++		case (0xa8 >> 2): /* st.l */
++			if (src != 15)
++				continue;
++
++			switch (dest) {
++			case 14:
++				if (offset_r14 || fp_displacement == 0)
++					continue;
++
++				offset_r14 = (u64)(((((s64)op >> 10) & 0x3ff) << 54) >> 54);
++				offset_r14 *= sizeof(unsigned long);
++				offset_r14 += fp_displacement;
++				break;
++			case 18:
++				if (offset_r18 || fp_displacement == 0)
++					continue;
++
++				offset_r18 = (u64)(((((s64)op >> 10) & 0x3ff) << 54) >> 54);
++				offset_r18 *= sizeof(unsigned long);
++				offset_r18 += fp_displacement;
++				break;
++			}
++
++			break;
++		case (0xcc >> 2): /* movi */
++			if (dest >= 63) {
++				printk(KERN_NOTICE "%s: Invalid dest reg %d "
++				       "specified in movi handler. Failed "
++				       "opcode was 0x%lx: ", __FUNCTION__,
++				       dest, op);
++
++				continue;
++			}
++
++			/* Sign extend */
++			regcache[dest] =
++				((((s64)(u64)op >> 10) & 0xffff) << 54) >> 54;
++			break;
++		case (0xd0 >> 2): /* addi */
++		case (0xd4 >> 2): /* addi.l */
++			/* Look for r15, -FRAME_SIZE, r15 */
++			if (src != 15 || dest != 15)
++				continue;
++
++			/* Sign extended frame size.. */
++			fp_displacement +=
++				(u64)(((((s64)op >> 10) & 0x3ff) << 54) >> 54);
++			fp_prev = fp - fp_displacement;
++			break;
++		}
++
++		if (found_prologue_end && offset_r14 && (offset_r18 || *pprev_pc) && fp_prev)
++			break;
++	}
++
++	if (offset_r14 == 0 || fp_prev == 0) {
++		if (!offset_r14)
++			pr_debug("Unable to find r14 offset\n");
++		if (!fp_prev)
++			pr_debug("Unable to find previous fp\n");
++
++		return -EINVAL;
++	}
++
++	/* For innermost leaf function, there might not be a offset_r18 */
++	if (!*pprev_pc && (offset_r18 == 0))
++		return -EINVAL;
++
++	*pprev_fp = *(unsigned long *)(fp_prev + offset_r14);
++
++	if (offset_r18)
++		*pprev_pc = *(unsigned long *)(fp_prev + offset_r18);
++
++	*pprev_pc &= ~1;
++
++	return 0;
++}
++
++/* Don't put this on the stack since we'll want to call sh64_unwind
++ * when we're close to underflowing the stack anyway. */
++static struct pt_regs here_regs;
++
++extern const char syscall_ret;
++extern const char ret_from_syscall;
++extern const char ret_from_exception;
++extern const char ret_from_irq;
++
++static void sh64_unwind_inner(struct pt_regs *regs);
++
++static void unwind_nested (unsigned long pc, unsigned long fp)
++{
++	if ((fp >= __MEMORY_START) &&
++	    ((fp & 7) == 0)) {
++		sh64_unwind_inner((struct pt_regs *) fp);
++	}
++}
++
++static void sh64_unwind_inner(struct pt_regs *regs)
++{
++	unsigned long pc, fp;
++	int ofs = 0;
++	int first_pass;
++
++	pc = regs->pc & ~1;
++	fp = regs->regs[14];
++
++	first_pass = 1;
++	for (;;) {
++		int cond;
++		unsigned long next_fp, next_pc;
++
++		if (pc == ((unsigned long) &syscall_ret & ~1)) {
++			printk("SYSCALL\n");
++			unwind_nested(pc,fp);
++			return;
++		}
++
++		if (pc == ((unsigned long) &ret_from_syscall & ~1)) {
++			printk("SYSCALL (PREEMPTED)\n");
++			unwind_nested(pc,fp);
++			return;
++		}
++
++		/* In this case, the PC is discovered by lookup_prev_stack_frame but
++		   it has 4 taken off it to look like the 'caller' */
++		if (pc == ((unsigned long) &ret_from_exception & ~1)) {
++			printk("EXCEPTION\n");
++			unwind_nested(pc,fp);
++			return;
++		}
++
++		if (pc == ((unsigned long) &ret_from_irq & ~1)) {
++			printk("IRQ\n");
++			unwind_nested(pc,fp);
++			return;
++		}
++
++		cond = ((pc >= __MEMORY_START) && (fp >= __MEMORY_START) &&
++			((pc & 3) == 0) && ((fp & 7) == 0));
++
++		pc -= ofs;
++
++		printk("[<%08lx>] ", pc);
++		print_symbol("%s\n", pc);
++
++		if (first_pass) {
++			/* If the innermost frame is a leaf function, it's
++			 * possible that r18 is never saved out to the stack.
++			 */
++			next_pc = regs->regs[18];
++		} else {
++			next_pc = 0;
++		}
++
++		if (lookup_prev_stack_frame(fp, pc, &next_fp, &next_pc, regs) == 0) {
++			ofs = sizeof(unsigned long);
++			pc = next_pc & ~1;
++			fp = next_fp;
++		} else {
++			printk("Unable to lookup previous stack frame\n");
++			break;
++		}
++		first_pass = 0;
++	}
++
++	printk("\n");
++
++}
++
++void sh64_unwind(struct pt_regs *regs)
++{
++	if (!regs) {
++		/*
++		 * Fetch current regs if we have no other saved state to back
++		 * trace from.
++		 */
++		regs = &here_regs;
++
++		__asm__ __volatile__ ("ori r14, 0, %0" : "=r" (regs->regs[14]));
++		__asm__ __volatile__ ("ori r15, 0, %0" : "=r" (regs->regs[15]));
++		__asm__ __volatile__ ("ori r18, 0, %0" : "=r" (regs->regs[18]));
++
++		__asm__ __volatile__ ("gettr tr0, %0" : "=r" (regs->tregs[0]));
++		__asm__ __volatile__ ("gettr tr1, %0" : "=r" (regs->tregs[1]));
++		__asm__ __volatile__ ("gettr tr2, %0" : "=r" (regs->tregs[2]));
++		__asm__ __volatile__ ("gettr tr3, %0" : "=r" (regs->tregs[3]));
++		__asm__ __volatile__ ("gettr tr4, %0" : "=r" (regs->tregs[4]));
++		__asm__ __volatile__ ("gettr tr5, %0" : "=r" (regs->tregs[5]));
++		__asm__ __volatile__ ("gettr tr6, %0" : "=r" (regs->tregs[6]));
++		__asm__ __volatile__ ("gettr tr7, %0" : "=r" (regs->tregs[7]));
++
++		__asm__ __volatile__ (
++			"pta 0f, tr0\n\t"
++			"blink tr0, %0\n\t"
++			"0: nop"
++			: "=r" (regs->pc)
++		);
++	}
++
++	printk("\nCall Trace:\n");
++	sh64_unwind_inner(regs);
++}
++
+diff --git a/arch/sh/kernel/dump_task.c b/arch/sh/kernel/dump_task.c
+new file mode 100644
+index 0000000..4a8a408
+--- /dev/null
++++ b/arch/sh/kernel/dump_task.c
+@@ -0,0 +1,31 @@
++#include <linux/elfcore.h>
++#include <linux/sched.h>
++
++/*
++ * 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)
++{
++	struct pt_regs ptregs;
++
++	ptregs = *task_pt_regs(tsk);
++	elf_core_copy_regs(regs, &ptregs);
++
++	return 1;
++}
++
++int dump_task_fpu(struct task_struct *tsk, elf_fpregset_t *fpu)
++{
++	int fpvalid = 0;
++
++#if defined(CONFIG_SH_FPU)
++	fpvalid = !!tsk_used_math(tsk);
++	if (fpvalid) {
++		unlazy_fpu(tsk, task_pt_regs(tsk));
++		memcpy(fpu, &tsk->thread.fpu.hard, sizeof(*fpu));
++	}
++#endif
++
++	return fpvalid;
++}
++
+diff --git a/arch/sh/kernel/early_printk.c b/arch/sh/kernel/early_printk.c
+index 2f30977..957f256 100644
+--- a/arch/sh/kernel/early_printk.c
++++ b/arch/sh/kernel/early_printk.c
+@@ -63,7 +63,8 @@ static struct console bios_console = {
+ #include <linux/serial_core.h>
+ #include "../../../drivers/serial/sh-sci.h"
+ 
+-#if defined(CONFIG_CPU_SUBTYPE_SH7720)
++#if defined(CONFIG_CPU_SUBTYPE_SH7720) || \
++    defined(CONFIG_CPU_SUBTYPE_SH7721)
+ #define EPK_SCSMR_VALUE 0x000
+ #define EPK_SCBRR_VALUE 0x00C
+ #define EPK_FIFO_SIZE 64
+@@ -117,7 +118,8 @@ static struct console scif_console = {
+ };
+ 
+ #if !defined(CONFIG_SH_STANDARD_BIOS)
+-#if defined(CONFIG_CPU_SUBTYPE_SH7720)
++#if defined(CONFIG_CPU_SUBTYPE_SH7720) || \
++    defined(CONFIG_CPU_SUBTYPE_SH7721)
+ static void scif_sercon_init(char *s)
+ {
+ 	sci_out(&scif_port, SCSCR, 0x0000);	/* clear TE and RE */
+@@ -208,10 +210,12 @@ static int __init setup_early_printk(char *buf)
+ 	if (!strncmp(buf, "serial", 6)) {
+ 		early_console = &scif_console;
+ 
+-#if (defined(CONFIG_CPU_SH4) || defined(CONFIG_CPU_SUBTYPE_SH7720)) && \
+-    !defined(CONFIG_SH_STANDARD_BIOS)
++#if !defined(CONFIG_SH_STANDARD_BIOS)
++#if defined(CONFIG_CPU_SH4) || defined(CONFIG_CPU_SUBTYPE_SH7720) || \
++    defined(CONFIG_CPU_SUBTYPE_SH7721)
+ 		scif_sercon_init(buf + 6);
+ #endif
++#endif
+ 	}
+ #endif
+ 
+diff --git a/arch/sh/kernel/entry-common.S b/arch/sh/kernel/entry-common.S
+index e0317ed..926b2e7 100644
+--- a/arch/sh/kernel/entry-common.S
++++ b/arch/sh/kernel/entry-common.S
+@@ -176,25 +176,6 @@ work_notifysig:
+ 	jmp	@r1
+ 	 lds	r0, pr
+ work_resched:
+-#if defined(CONFIG_GUSA) && !defined(CONFIG_PREEMPT)
+-	! gUSA handling
+-	mov.l	@(OFF_SP,r15), r0	! get user space stack pointer
+-	mov	r0, r1
+-	shll	r0
+-	bf/s	1f
+-	 shll	r0
+-	bf/s	1f
+-	 mov	#OFF_PC, r0
+-	! 				  SP >= 0xc0000000 : gUSA mark
+-	mov.l	@(r0,r15), r2		! get user space PC (program counter)
+-	mov.l	@(OFF_R0,r15), r3	! end point
+-	cmp/hs	r3, r2			! r2 >= r3? 
+-	bt	1f
+-	add	r3, r1			! rewind point #2
+-	mov.l	r1, @(r0,r15)		! reset PC to rewind point #2
+-	!
+-1:
+-#endif
+ 	mov.l	1f, r1
+ 	jsr	@r1				! schedule
+ 	 nop
+@@ -224,7 +205,7 @@ work_resched:
+ syscall_exit_work:
+ 	! r0: current_thread_info->flags
+ 	! r8: current_thread_info
+-	tst	#_TIF_SYSCALL_TRACE | _TIF_SINGLESTEP, r0
++	tst	#_TIF_SYSCALL_TRACE | _TIF_SINGLESTEP | _TIF_SYSCALL_AUDIT, r0
+ 	bt/s	work_pending
+ 	 tst	#_TIF_NEED_RESCHED, r0
+ #ifdef CONFIG_TRACE_IRQFLAGS
+@@ -234,6 +215,8 @@ syscall_exit_work:
+ #endif
+ 	sti
+ 	! XXX setup arguments...
++	mov	r15, r4
++	mov	#1, r5
+ 	mov.l	4f, r0			! do_syscall_trace
+ 	jsr	@r0
+ 	 nop
+@@ -244,6 +227,8 @@ syscall_exit_work:
+ syscall_trace_entry:
+ 	!                     	Yes it is traced.
+ 	! XXX setup arguments...
++	mov     r15, r4
++	mov     #0, r5
+ 	mov.l	4f, r11		! Call do_syscall_trace which notifies
+ 	jsr	@r11	    	! superior (will chomp R[0-7])
+ 	 nop
+@@ -366,7 +351,7 @@ ENTRY(system_call)
+ 	!
+ 	get_current_thread_info r8, r10
+ 	mov.l	@(TI_FLAGS,r8), r8
+-	mov	#_TIF_SYSCALL_TRACE, r10
++	mov	#(_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT), r10
+ 	tst	r10, r8
+ 	bf	syscall_trace_entry
+ 	!
+diff --git a/arch/sh/kernel/head.S b/arch/sh/kernel/head.S
+deleted file mode 100644
+index 3338239..0000000
+--- a/arch/sh/kernel/head.S
++++ /dev/null
+@@ -1,120 +0,0 @@
+-/* $Id: head.S,v 1.7 2003/09/01 17:58:19 lethal Exp $
+- *
+- *  arch/sh/kernel/head.S
+- *
+- *  Copyright (C) 1999, 2000  Niibe Yutaka & Kaz Kojima
+- *
+- * 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.
+- *
+- * Head.S contains the SH exception handlers and startup code.
+- */
+-#include <linux/linkage.h>
+-#include <asm/thread_info.h>
+-
+-#ifdef CONFIG_CPU_SH4A
+-#define SYNCO()		synco
+-
+-#define PREFI(label, reg)	\
+-	mov.l	label, reg;	\
+-	prefi	@reg
+-#else
+-#define SYNCO()
+-#define PREFI(label, reg)
+-#endif
+-
+-	.section	.empty_zero_page, "aw"
+-ENTRY(empty_zero_page)
+-	.long	1		/* MOUNT_ROOT_RDONLY */
+-	.long	0		/* RAMDISK_FLAGS */
+-	.long	0x0200		/* ORIG_ROOT_DEV */
+-	.long	1		/* LOADER_TYPE */
+-	.long	0x00360000	/* INITRD_START */
+-	.long	0x000a0000	/* INITRD_SIZE */
+-	.long	0
+-1:
+-	.skip	PAGE_SIZE - empty_zero_page - 1b
+-
+-	.section	.text.head, "ax"
+-
+-/*
+- * Condition at the entry of _stext:
+- *
+- *   BSC has already been initialized.
+- *   INTC may or may not be initialized.
+- *   VBR may or may not be initialized.
+- *   MMU may or may not be initialized.
+- *   Cache may or may not be initialized.
+- *   Hardware (including on-chip modules) may or may not be initialized. 
+- *
+- */
+-ENTRY(_stext)
+-	!			Initialize Status Register
+-	mov.l	1f, r0		! MD=1, RB=0, BL=0, IMASK=0xF
+-	ldc	r0, sr
+-	!			Initialize global interrupt mask
+-#ifdef CONFIG_CPU_HAS_SR_RB
+-	mov	#0, r0
+-	ldc	r0, r6_bank
+-#endif
+-	
+-	/*
+-	 * Prefetch if possible to reduce cache miss penalty.
+-	 *
+-	 * We do this early on for SH-4A as a micro-optimization,
+-	 * as later on we will have speculative execution enabled
+-	 * and this will become less of an issue.
+-	 */
+-	PREFI(5f, r0)
+-	PREFI(6f, r0)
+-
+-	!
+-	mov.l	2f, r0
+-	mov	r0, r15		! Set initial r15 (stack pointer)
+-#ifdef CONFIG_CPU_HAS_SR_RB
+-	mov.l	7f, r0
+-	ldc	r0, r7_bank	! ... and initial thread_info
+-#endif
+-	
+-	!			Clear BSS area
+-#ifdef CONFIG_SMP	
+-	mov.l	3f, r0
+-	cmp/eq	#0, r0		! skip clear if set to zero
+-	bt	10f
+-#endif
+-	
+-	mov.l	3f, r1
+-	add	#4, r1
+-	mov.l	4f, r2
+-	mov	#0, r0
+-9:	cmp/hs	r2, r1
+-	bf/s	9b		! while (r1 < r2)
+-	 mov.l	r0, at -r2
+-
+-10:		
+-	!			Additional CPU initialization
+-	mov.l	6f, r0
+-	jsr	@r0
+-	 nop
+-
+-	SYNCO()			! Wait for pending instructions..
+-	
+-	!			Start kernel
+-	mov.l	5f, r0
+-	jmp	@r0
+-	 nop
+-
+-	.balign 4
+-#if defined(CONFIG_CPU_SH2)
+-1:	.long	0x000000F0		! IMASK=0xF
+-#else
+-1:	.long	0x400080F0		! MD=1, RB=0, BL=0, FD=1, IMASK=0xF
+-#endif
+-ENTRY(stack_start)
+-2:	.long	init_thread_union+THREAD_SIZE
+-3:	.long	__bss_start
+-4:	.long	_end
+-5:	.long	start_kernel
+-6:	.long	sh_cpu_init
+-7:	.long	init_thread_union
+diff --git a/arch/sh/kernel/head_32.S b/arch/sh/kernel/head_32.S
+new file mode 100644
+index 0000000..d67d7ed
+--- /dev/null
++++ b/arch/sh/kernel/head_32.S
+@@ -0,0 +1,124 @@
++/* $Id: head.S,v 1.7 2003/09/01 17:58:19 lethal Exp $
++ *
++ *  arch/sh/kernel/head.S
++ *
++ *  Copyright (C) 1999, 2000  Niibe Yutaka & Kaz Kojima
++ *
++ * 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.
++ *
++ * Head.S contains the SH exception handlers and startup code.
++ */
++#include <linux/linkage.h>
++#include <asm/thread_info.h>
++
++#ifdef CONFIG_CPU_SH4A
++#define SYNCO()		synco
++
++#define PREFI(label, reg)	\
++	mov.l	label, reg;	\
++	prefi	@reg
++#else
++#define SYNCO()
++#define PREFI(label, reg)
++#endif
++
++	.section	.empty_zero_page, "aw"
++ENTRY(empty_zero_page)
++	.long	1		/* MOUNT_ROOT_RDONLY */
++	.long	0		/* RAMDISK_FLAGS */
++	.long	0x0200		/* ORIG_ROOT_DEV */
++	.long	1		/* LOADER_TYPE */
++	.long	0x00360000	/* INITRD_START */
++	.long	0x000a0000	/* INITRD_SIZE */
++#ifdef CONFIG_32BIT
++	.long	0x53453f00 + 32	/* "SE?" = 32 bit */
++#else
++	.long	0x53453f00 + 29	/* "SE?" = 29 bit */
++#endif
++1:
++	.skip	PAGE_SIZE - empty_zero_page - 1b
++
++	.section	.text.head, "ax"
++
++/*
++ * Condition at the entry of _stext:
++ *
++ *   BSC has already been initialized.
++ *   INTC may or may not be initialized.
++ *   VBR may or may not be initialized.
++ *   MMU may or may not be initialized.
++ *   Cache may or may not be initialized.
++ *   Hardware (including on-chip modules) may or may not be initialized. 
++ *
++ */
++ENTRY(_stext)
++	!			Initialize Status Register
++	mov.l	1f, r0		! MD=1, RB=0, BL=0, IMASK=0xF
++	ldc	r0, sr
++	!			Initialize global interrupt mask
++#ifdef CONFIG_CPU_HAS_SR_RB
++	mov	#0, r0
++	ldc	r0, r6_bank
++#endif
++	
++	/*
++	 * Prefetch if possible to reduce cache miss penalty.
++	 *
++	 * We do this early on for SH-4A as a micro-optimization,
++	 * as later on we will have speculative execution enabled
++	 * and this will become less of an issue.
++	 */
++	PREFI(5f, r0)
++	PREFI(6f, r0)
++
++	!
++	mov.l	2f, r0
++	mov	r0, r15		! Set initial r15 (stack pointer)
++#ifdef CONFIG_CPU_HAS_SR_RB
++	mov.l	7f, r0
++	ldc	r0, r7_bank	! ... and initial thread_info
++#endif
++	
++	!			Clear BSS area
++#ifdef CONFIG_SMP	
++	mov.l	3f, r0
++	cmp/eq	#0, r0		! skip clear if set to zero
++	bt	10f
++#endif
++	
++	mov.l	3f, r1
++	add	#4, r1
++	mov.l	4f, r2
++	mov	#0, r0
++9:	cmp/hs	r2, r1
++	bf/s	9b		! while (r1 < r2)
++	 mov.l	r0, at -r2
++
++10:		
++	!			Additional CPU initialization
++	mov.l	6f, r0
++	jsr	@r0
++	 nop
++
++	SYNCO()			! Wait for pending instructions..
++	
++	!			Start kernel
++	mov.l	5f, r0
++	jmp	@r0
++	 nop
++
++	.balign 4
++#if defined(CONFIG_CPU_SH2)
++1:	.long	0x000000F0		! IMASK=0xF
++#else
++1:	.long	0x400080F0		! MD=1, RB=0, BL=0, FD=1, IMASK=0xF
++#endif
++ENTRY(stack_start)
++2:	.long	init_thread_union+THREAD_SIZE
++3:	.long	__bss_start
++4:	.long	_end
++5:	.long	start_kernel
++6:	.long	sh_cpu_init
++7:	.long	init_thread_union
+diff --git a/arch/sh/kernel/head_64.S b/arch/sh/kernel/head_64.S
+new file mode 100644
+index 0000000..f42d4c0
+--- /dev/null
++++ b/arch/sh/kernel/head_64.S
+@@ -0,0 +1,356 @@
++/*
++ * arch/sh/kernel/head_64.S
++ *
++ * Copyright (C) 2000, 2001  Paolo Alberelli
++ * Copyright (C) 2003, 2004  Paul Mundt
++ *
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License.  See the file "COPYING" in the main directory of this archive
++ * for more details.
++ */
++#include <asm/page.h>
++#include <asm/cache.h>
++#include <asm/tlb.h>
++#include <asm/cpu/registers.h>
++#include <asm/cpu/mmu_context.h>
++#include <asm/thread_info.h>
++
++/*
++ * MMU defines: TLB boundaries.
++ */
++
++#define MMUIR_FIRST	ITLB_FIXED
++#define MMUIR_END	ITLB_LAST_VAR_UNRESTRICTED+TLB_STEP
++#define MMUIR_STEP	TLB_STEP
++
++#define MMUDR_FIRST	DTLB_FIXED
++#define MMUDR_END	DTLB_LAST_VAR_UNRESTRICTED+TLB_STEP
++#define MMUDR_STEP	TLB_STEP
++
++/* Safety check : CONFIG_PAGE_OFFSET has to be a multiple of 512Mb */
++#if (CONFIG_PAGE_OFFSET & ((1UL<<29)-1))
++#error "CONFIG_PAGE_OFFSET must be a multiple of 512Mb"
++#endif
++
++/*
++ * MMU defines: Fixed TLBs.
++ */
++/* Deal safely with the case where the base of RAM is not 512Mb aligned */
++
++#define ALIGN_512M_MASK (0xffffffffe0000000)
++#define ALIGNED_EFFECTIVE ((CONFIG_PAGE_OFFSET + CONFIG_MEMORY_START) & ALIGN_512M_MASK)
++#define ALIGNED_PHYSICAL (CONFIG_MEMORY_START & ALIGN_512M_MASK)
++
++#define MMUIR_TEXT_H	(0x0000000000000003 | ALIGNED_EFFECTIVE)
++			/* Enabled, Shared, ASID 0, Eff. Add. 0xA0000000 */
++
++#define MMUIR_TEXT_L	(0x000000000000009a | ALIGNED_PHYSICAL)
++			/* 512 Mb, Cacheable, Write-back, execute, Not User, Ph. Add. */
++
++#define MMUDR_CACHED_H	0x0000000000000003 | ALIGNED_EFFECTIVE
++			/* Enabled, Shared, ASID 0, Eff. Add. 0xA0000000 */
++#define MMUDR_CACHED_L	0x000000000000015a | ALIGNED_PHYSICAL
++			/* 512 Mb, Cacheable, Write-back, read/write, Not User, Ph. Add. */
++
++#ifdef CONFIG_CACHE_OFF
++#define	ICCR0_INIT_VAL	ICCR0_OFF			/* ICACHE off */
++#else
++#define	ICCR0_INIT_VAL	ICCR0_ON | ICCR0_ICI		/* ICE + ICI */
++#endif
++#define	ICCR1_INIT_VAL	ICCR1_NOLOCK			/* No locking */
++
++#if defined (CONFIG_CACHE_OFF)
++#define	OCCR0_INIT_VAL	OCCR0_OFF			   /* D-cache: off  */
++#elif defined (CONFIG_CACHE_WRITETHROUGH)
++#define	OCCR0_INIT_VAL	OCCR0_ON | OCCR0_OCI | OCCR0_WT	   /* D-cache: on,   */
++							   /* WT, invalidate */
++#elif defined (CONFIG_CACHE_WRITEBACK)
++#define	OCCR0_INIT_VAL	OCCR0_ON | OCCR0_OCI | OCCR0_WB	   /* D-cache: on,   */
++							   /* WB, invalidate */
++#else
++#error preprocessor flag CONFIG_CACHE_... not recognized!
++#endif
++
++#define	OCCR1_INIT_VAL	OCCR1_NOLOCK			   /* No locking     */
++
++	.section	.empty_zero_page, "aw"
++	.global empty_zero_page
++
++empty_zero_page:
++	.long	1		/* MOUNT_ROOT_RDONLY */
++	.long	0		/* RAMDISK_FLAGS */
++	.long	0x0200		/* ORIG_ROOT_DEV */
++	.long	1		/* LOADER_TYPE */
++	.long	0x00800000	/* INITRD_START */
++	.long	0x00800000	/* INITRD_SIZE */
++	.long	0
++
++	.text
++	.balign 4096,0,4096
++
++	.section	.data, "aw"
++	.balign	PAGE_SIZE
++
++	.section	.data, "aw"
++	.balign	PAGE_SIZE
++
++	.global mmu_pdtp_cache
++mmu_pdtp_cache:
++	.space PAGE_SIZE, 0
++
++	.global empty_bad_page
++empty_bad_page:
++	.space PAGE_SIZE, 0
++
++	.global empty_bad_pte_table
++empty_bad_pte_table:
++	.space PAGE_SIZE, 0
++
++	.global	fpu_in_use
++fpu_in_use:	.quad	0
++
++
++	.section	.text.head, "ax"
++	.balign L1_CACHE_BYTES
++/*
++ * Condition at the entry of __stext:
++ * . Reset state:
++ *   . SR.FD    = 1		(FPU disabled)
++ *   . SR.BL    = 1		(Exceptions disabled)
++ *   . SR.MD    = 1		(Privileged Mode)
++ *   . SR.MMU   = 0		(MMU Disabled)
++ *   . SR.CD    = 0		(CTC User Visible)
++ *   . SR.IMASK = Undefined	(Interrupt Mask)
++ *
++ * Operations supposed to be performed by __stext:
++ * . prevent speculative fetch onto device memory while MMU is off
++ * . reflect as much as possible SH5 ABI (r15, r26, r27, r18)
++ * . first, save CPU state and set it to something harmless
++ * . any CPU detection and/or endianness settings (?)
++ * . initialize EMI/LMI (but not TMU/RTC/INTC/SCIF): TBD
++ * . set initial TLB entries for cached and uncached regions
++ *   (no fine granularity paging)
++ * . set initial cache state
++ * . enable MMU and caches
++ * . set CPU to a consistent state
++ *   . registers (including stack pointer and current/KCR0)
++ *   . NOT expecting to set Exception handling nor VBR/RESVEC/DCR
++ *     at this stage. This is all to later Linux initialization steps.
++ *   . initialize FPU
++ * . clear BSS
++ * . jump into start_kernel()
++ * . be prepared to hopeless start_kernel() returns.
++ *
++ */
++	.global _stext
++_stext:
++	/*
++	 * Prevent speculative fetch on device memory due to
++	 * uninitialized target registers.
++	 */
++	ptabs/u	ZERO, tr0
++	ptabs/u	ZERO, tr1
++	ptabs/u	ZERO, tr2
++	ptabs/u	ZERO, tr3
++	ptabs/u	ZERO, tr4
++	ptabs/u	ZERO, tr5
++	ptabs/u	ZERO, tr6
++	ptabs/u	ZERO, tr7
++	synci
++
++	/*
++	 * Read/Set CPU state. After this block:
++	 * r29 = Initial SR
++	 */
++	getcon	SR, r29
++	movi	SR_HARMLESS, r20
++	putcon	r20, SR
++
++	/*
++	 * Initialize EMI/LMI. To Be Done.
++	 */
++
++	/*
++	 * CPU detection and/or endianness settings (?). To Be Done.
++	 * Pure PIC code here, please ! Just save state into r30.
++         * After this block:
++	 * r30 = CPU type/Platform Endianness
++	 */
++
++	/*
++	 * Set initial TLB entries for cached and uncached regions.
++	 * Note: PTA/BLINK is PIC code, PTABS/BLINK isn't !
++	 */
++	/* Clear ITLBs */
++	pta	clear_ITLB, tr1
++	movi	MMUIR_FIRST, r21
++	movi	MMUIR_END, r22
++clear_ITLB:
++	putcfg	r21, 0, ZERO		/* Clear MMUIR[n].PTEH.V */
++	addi	r21, MMUIR_STEP, r21
++        bne	r21, r22, tr1
++
++	/* Clear DTLBs */
++	pta	clear_DTLB, tr1
++	movi	MMUDR_FIRST, r21
++	movi	MMUDR_END, r22
++clear_DTLB:
++	putcfg	r21, 0, ZERO		/* Clear MMUDR[n].PTEH.V */
++	addi	r21, MMUDR_STEP, r21
++        bne	r21, r22, tr1
++
++	/* Map one big (512Mb) page for ITLB */
++	movi	MMUIR_FIRST, r21
++	movi	MMUIR_TEXT_L, r22	/* PTEL first */
++	add.l	r22, r63, r22		/* Sign extend */
++	putcfg	r21, 1, r22		/* Set MMUIR[0].PTEL */
++	movi	MMUIR_TEXT_H, r22	/* PTEH last */
++	add.l	r22, r63, r22		/* Sign extend */
++	putcfg	r21, 0, r22		/* Set MMUIR[0].PTEH */
++
++	/* Map one big CACHED (512Mb) page for DTLB */
++	movi	MMUDR_FIRST, r21
++	movi	MMUDR_CACHED_L, r22	/* PTEL first */
++	add.l	r22, r63, r22		/* Sign extend */
++	putcfg	r21, 1, r22		/* Set MMUDR[0].PTEL */
++	movi	MMUDR_CACHED_H, r22	/* PTEH last */
++	add.l	r22, r63, r22		/* Sign extend */
++	putcfg	r21, 0, r22		/* Set MMUDR[0].PTEH */
++
++#ifdef CONFIG_EARLY_PRINTK
++	/*
++	 * Setup a DTLB translation for SCIF phys.
++	 */
++	addi    r21, MMUDR_STEP, r21
++	movi    0x0a03, r22	/* SCIF phys */
++	shori   0x0148, r22
++	putcfg  r21, 1, r22	/* PTEL first */
++	movi    0xfa03, r22	/* 0xfa030000, fixed SCIF virt */
++	shori   0x0003, r22
++	putcfg  r21, 0, r22	/* PTEH last */
++#endif
++
++	/*
++	 * Set cache behaviours.
++	 */
++	/* ICache */
++	movi	ICCR_BASE, r21
++	movi	ICCR0_INIT_VAL, r22
++	movi	ICCR1_INIT_VAL, r23
++	putcfg	r21, ICCR_REG0, r22
++	putcfg	r21, ICCR_REG1, r23
++
++	/* OCache */
++	movi	OCCR_BASE, r21
++	movi	OCCR0_INIT_VAL, r22
++	movi	OCCR1_INIT_VAL, r23
++	putcfg	r21, OCCR_REG0, r22
++	putcfg	r21, OCCR_REG1, r23
++
++
++	/*
++	 * Enable Caches and MMU. Do the first non-PIC jump.
++         * Now head.S global variables, constants and externs
++	 * can be used.
++	 */
++	getcon	SR, r21
++	movi	SR_ENABLE_MMU, r22
++	or	r21, r22, r21
++	putcon	r21, SSR
++	movi	hyperspace, r22
++	ori	r22, 1, r22	    /* Make it SHmedia, not required but..*/
++	putcon	r22, SPC
++	synco
++	rte			    /* And now go into the hyperspace ... */
++hyperspace:			    /* ... that's the next instruction !  */
++
++	/*
++	 * Set CPU to a consistent state.
++	 * r31 = FPU support flag
++	 * tr0/tr7 in use. Others give a chance to loop somewhere safe
++	 */
++	movi	start_kernel, r32
++	ori	r32, 1, r32
++
++	ptabs	r32, tr0		    /* r32 = _start_kernel address        */
++	pta/u	hopeless, tr1
++	pta/u	hopeless, tr2
++	pta/u	hopeless, tr3
++	pta/u	hopeless, tr4
++	pta/u	hopeless, tr5
++	pta/u	hopeless, tr6
++	pta/u	hopeless, tr7
++	gettr	tr1, r28			/* r28 = hopeless address */
++
++	/* Set initial stack pointer */
++	movi	init_thread_union, SP
++	putcon	SP, KCR0		/* Set current to init_task */
++	movi	THREAD_SIZE, r22	/* Point to the end */
++	add	SP, r22, SP
++
++	/*
++	 * Initialize FPU.
++	 * Keep FPU flag in r31. After this block:
++	 * r31 = FPU flag
++	 */
++	movi fpu_in_use, r31	/* Temporary */
++
++#ifdef CONFIG_SH_FPU
++	getcon	SR, r21
++	movi	SR_ENABLE_FPU, r22
++	and	r21, r22, r22
++	putcon	r22, SR			/* Try to enable */
++	getcon	SR, r22
++	xor	r21, r22, r21
++	shlri	r21, 15, r21		/* Supposedly 0/1 */
++	st.q	r31, 0 , r21		/* Set fpu_in_use */
++#else
++	movi	0, r21
++	st.q	r31, 0 , r21		/* Set fpu_in_use */
++#endif
++	or	r21, ZERO, r31		/* Set FPU flag at last */
++
++#ifndef CONFIG_SH_NO_BSS_INIT
++/* Don't clear BSS if running on slow platforms such as an RTL simulation,
++   remote memory via SHdebug link, etc.  For these the memory can be guaranteed
++   to be all zero on boot anyway. */
++	/*
++	 * Clear bss
++	 */
++	pta	clear_quad, tr1
++	movi	__bss_start, r22
++	movi	_end, r23
++clear_quad:
++	st.q	r22, 0, ZERO
++	addi	r22, 8, r22
++	bne	r22, r23, tr1		/* Both quad aligned, see vmlinux.lds.S */
++#endif
++	pta/u	hopeless, tr1
++
++	/* Say bye to head.S but be prepared to wrongly get back ... */
++	blink	tr0, LINK
++
++	/* If we ever get back here through LINK/tr1-tr7 */
++	pta/u	hopeless, tr7
++
++hopeless:
++	/*
++	 * Something's badly wrong here. Loop endlessly,
++         * there's nothing more we can do about it.
++	 *
++	 * Note on hopeless: it can be jumped into invariably
++	 * before or after jumping into hyperspace. The only
++	 * requirement is to be PIC called (PTA) before and
++	 * any way (PTA/PTABS) after. According to Virtual
++	 * to Physical mapping a simulator/emulator can easily
++	 * tell where we came here from just looking at hopeless
++	 * (PC) address.
++	 *
++	 * For debugging purposes:
++	 * (r28) hopeless/loop address
++	 * (r29) Original SR
++	 * (r30) CPU type/Platform endianness
++	 * (r31) FPU Support
++	 * (r32) _start_kernel address
++	 */
++	blink	tr7, ZERO
+diff --git a/arch/sh/kernel/init_task.c b/arch/sh/kernel/init_task.c
+index 4b449c4..f9bcc60 100644
+--- a/arch/sh/kernel/init_task.c
++++ b/arch/sh/kernel/init_task.c
+@@ -11,8 +11,8 @@ static struct fs_struct init_fs = INIT_FS;
+ static struct files_struct init_files = INIT_FILES;
+ static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
+ static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
++struct pt_regs fake_swapper_regs;
+ struct mm_struct init_mm = INIT_MM(init_mm);
+-
+ EXPORT_SYMBOL(init_mm);
+ 
+ /*
+@@ -22,7 +22,7 @@ EXPORT_SYMBOL(init_mm);
+  * way process stacks are handled. This is done by having a special
+  * "init_task" linker map entry..
+  */
+-union thread_union init_thread_union 
++union thread_union init_thread_union
+ 	__attribute__((__section__(".data.init_task"))) =
+ 		{ INIT_THREAD_INFO(init_task) };
+ 
+diff --git a/arch/sh/kernel/io.c b/arch/sh/kernel/io.c
+index 501fe03..71c9fde 100644
+--- a/arch/sh/kernel/io.c
++++ b/arch/sh/kernel/io.c
+@@ -61,73 +61,6 @@ void memset_io(volatile void __iomem *dst, int c, unsigned long count)
+ }
+ EXPORT_SYMBOL(memset_io);
+ 
+-void __raw_readsl(unsigned long addr, void *datap, int len)
+-{
+-	u32 *data;
+-
+-	for (data = datap; (len != 0) && (((u32)data & 0x1f) != 0); len--)
+-		*data++ = ctrl_inl(addr);
+-
+-	if (likely(len >= (0x20 >> 2))) {
+-		int tmp2, tmp3, tmp4, tmp5, tmp6;
+-
+-		__asm__ __volatile__(
+-			"1:			\n\t"
+-			"mov.l	@%7, r0		\n\t"
+-			"mov.l	@%7, %2		\n\t"
+-#ifdef CONFIG_CPU_SH4
+-			"movca.l r0, @%0	\n\t"
+-#else
+-			"mov.l	r0, @%0		\n\t"
+-#endif
+-			"mov.l	@%7, %3		\n\t"
+-			"mov.l	@%7, %4		\n\t"
+-			"mov.l	@%7, %5		\n\t"
+-			"mov.l	@%7, %6		\n\t"
+-			"mov.l	@%7, r7		\n\t"
+-			"mov.l	@%7, r0		\n\t"
+-			"mov.l	%2, @(0x04,%0)	\n\t"
+-			"mov	#0x20>>2, %2	\n\t"
+-			"mov.l	%3, @(0x08,%0)	\n\t"
+-			"sub	%2, %1		\n\t"
+-			"mov.l	%4, @(0x0c,%0)	\n\t"
+-			"cmp/hi	%1, %2		! T if 32 > len	\n\t"
+-			"mov.l	%5, @(0x10,%0)	\n\t"
+-			"mov.l	%6, @(0x14,%0)	\n\t"
+-			"mov.l	r7, @(0x18,%0)	\n\t"
+-			"mov.l	r0, @(0x1c,%0)	\n\t"
+-			"bf.s	1b		\n\t"
+-			" add	#0x20, %0	\n\t"
+-			: "=&r" (data), "=&r" (len),
+-			  "=&r" (tmp2), "=&r" (tmp3), "=&r" (tmp4),
+-			  "=&r" (tmp5), "=&r" (tmp6)
+-			: "r"(addr), "0" (data), "1" (len)
+-			: "r0", "r7", "t", "memory");
+-	}
+-
+-	for (; len != 0; len--)
+-		*data++ = ctrl_inl(addr);
+-}
+-EXPORT_SYMBOL(__raw_readsl);
+-
+-void __raw_writesl(unsigned long addr, const void *data, int len)
+-{
+-	if (likely(len != 0)) {
+-		int tmp1;
+-
+-		__asm__ __volatile__ (
+-			"1:				\n\t"
+-			"mov.l	@%0+, %1	\n\t"
+-			"dt		%3		\n\t"
+-			"bf.s		1b		\n\t"
+-			" mov.l	%1, @%4		\n\t"
+-			: "=&r" (data), "=&r" (tmp1)
+-			: "0" (data), "r" (len), "r"(addr)
+-			: "t", "memory");
+-	}
+-}
+-EXPORT_SYMBOL(__raw_writesl);
+-
+ void __iomem *ioport_map(unsigned long port, unsigned int nr)
+ {
+ 	return sh_mv.mv_ioport_map(port, nr);
+diff --git a/arch/sh/kernel/module.c b/arch/sh/kernel/module.c
+index 142a4e5..b3d0a03 100644
+--- a/arch/sh/kernel/module.c
++++ b/arch/sh/kernel/module.c
+@@ -1,5 +1,15 @@
+ /*  Kernel module help for SH.
+ 
++    SHcompact version by Kaz Kojima and Paul Mundt.
++
++    SHmedia bits:
++
++	Copyright 2004 SuperH (UK) Ltd
++	Author: Richard Curnow
++
++	Based on the sh version, and on code from the sh64-specific parts of
++	modutils, originally written by Richard Curnow and Ben Gaster.
++
+     This program is free software; you can redistribute it and/or modify
+     it under the terms of the GNU General Public License as published by
+     the Free Software Foundation; either version 2 of the License, or
+@@ -21,12 +31,6 @@
+ #include <linux/string.h>
+ #include <linux/kernel.h>
+ 
+-#if 0
+-#define DEBUGP printk
+-#else
+-#define DEBUGP(fmt...)
+-#endif
+-
+ void *module_alloc(unsigned long size)
+ {
+ 	if (size == 0)
+@@ -52,6 +56,7 @@ int module_frob_arch_sections(Elf_Ehdr *hdr,
+ 	return 0;
+ }
+ 
++#ifdef CONFIG_SUPERH32
+ #define COPY_UNALIGNED_WORD(sw, tw, align) \
+ { \
+ 	void *__s = &(sw), *__t = &(tw); \
+@@ -74,6 +79,10 @@ int module_frob_arch_sections(Elf_Ehdr *hdr,
+ 		break; \
+ 	} \
+ }
++#else
++/* One thing SHmedia doesn't screw up! */
++#define COPY_UNALIGNED_WORD(sw, tw, align)	{ (tw) = (sw); }
++#endif
+ 
+ int apply_relocate_add(Elf32_Shdr *sechdrs,
+ 		   const char *strtab,
+@@ -89,8 +98,8 @@ int apply_relocate_add(Elf32_Shdr *sechdrs,
+ 	uint32_t value;
+ 	int align;
+ 
+-	DEBUGP("Applying relocate section %u to %u\n", relsec,
+-	       sechdrs[relsec].sh_info);
++	pr_debug("Applying relocate section %u to %u\n", relsec,
++		 sechdrs[relsec].sh_info);
+ 	for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
+ 		/* This is where to make the change */
+ 		location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
+@@ -102,17 +111,44 @@ int apply_relocate_add(Elf32_Shdr *sechdrs,
+ 		relocation = sym->st_value + rel[i].r_addend;
+ 		align = (int)location & 3;
+ 
++#ifdef CONFIG_SUPERH64
++		/* For text addresses, bit2 of the st_other field indicates
++		 * whether the symbol is SHmedia (1) or SHcompact (0).  If
++		 * SHmedia, the LSB of the symbol needs to be asserted
++		 * for the CPU to be in SHmedia mode when it starts executing
++		 * the branch target. */
++		relocation |= (sym->st_other & 4);
++#endif
++
+ 		switch (ELF32_R_TYPE(rel[i].r_info)) {
+ 		case R_SH_DIR32:
+-	    		COPY_UNALIGNED_WORD (*location, value, align);
++			COPY_UNALIGNED_WORD (*location, value, align);
+ 			value += relocation;
+-	    		COPY_UNALIGNED_WORD (value, *location, align);
++			COPY_UNALIGNED_WORD (value, *location, align);
+ 			break;
+ 		case R_SH_REL32:
+-	  		relocation = (relocation - (Elf32_Addr) location);
+-	    		COPY_UNALIGNED_WORD (*location, value, align);
++			relocation = (relocation - (Elf32_Addr) location);
++			COPY_UNALIGNED_WORD (*location, value, align);
+ 			value += relocation;
+-	    		COPY_UNALIGNED_WORD (value, *location, align);
++			COPY_UNALIGNED_WORD (value, *location, align);
++			break;
++		case R_SH_IMM_LOW16:
++			*location = (*location & ~0x3fffc00) |
++				((relocation & 0xffff) << 10);
++			break;
++		case R_SH_IMM_MEDLOW16:
++			*location = (*location & ~0x3fffc00) |
++				(((relocation >> 16) & 0xffff) << 10);
++			break;
++		case R_SH_IMM_LOW16_PCREL:
++			relocation -= (Elf32_Addr) location;
++			*location = (*location & ~0x3fffc00) |
++				((relocation & 0xffff) << 10);
++			break;
++		case R_SH_IMM_MEDLOW16_PCREL:
++			relocation -= (Elf32_Addr) location;
++			*location = (*location & ~0x3fffc00) |
++				(((relocation >> 16) & 0xffff) << 10);
+ 			break;
+ 		default:
+ 			printk(KERN_ERR "module %s: Unknown relocation: %u\n",
+diff --git a/arch/sh/kernel/process.c b/arch/sh/kernel/process.c
+deleted file mode 100644
+index 6d7f2b0..0000000
+--- a/arch/sh/kernel/process.c
++++ /dev/null
+@@ -1,558 +0,0 @@
+-/*
+- * arch/sh/kernel/process.c
+- *
+- * This file handles the architecture-dependent parts of process handling..
+- *
+- *  Copyright (C) 1995  Linus Torvalds
+- *
+- *  SuperH version:  Copyright (C) 1999, 2000  Niibe Yutaka & Kaz Kojima
+- *		     Copyright (C) 2006 Lineo Solutions Inc. support SH4A UBC
+- *		     Copyright (C) 2002 - 2007  Paul Mundt
+- */
+-#include <linux/module.h>
+-#include <linux/mm.h>
+-#include <linux/elfcore.h>
+-#include <linux/pm.h>
+-#include <linux/kallsyms.h>
+-#include <linux/kexec.h>
+-#include <linux/kdebug.h>
+-#include <linux/tick.h>
+-#include <linux/reboot.h>
+-#include <linux/fs.h>
+-#include <linux/preempt.h>
+-#include <asm/uaccess.h>
+-#include <asm/mmu_context.h>
+-#include <asm/pgalloc.h>
+-#include <asm/system.h>
+-#include <asm/ubc.h>
+-
+-static int hlt_counter;
+-int ubc_usercnt = 0;
+-
+-void (*pm_idle)(void);
+-void (*pm_power_off)(void);
+-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);
+-
+-static int __init nohlt_setup(char *__unused)
+-{
+-	hlt_counter = 1;
+-	return 1;
+-}
+-__setup("nohlt", nohlt_setup);
+-
+-static int __init hlt_setup(char *__unused)
+-{
+-	hlt_counter = 0;
+-	return 1;
+-}
+-__setup("hlt", hlt_setup);
+-
+-void default_idle(void)
+-{
+-	if (!hlt_counter) {
+-		clear_thread_flag(TIF_POLLING_NRFLAG);
+-		smp_mb__after_clear_bit();
+-		set_bl_bit();
+-		while (!need_resched())
+-			cpu_sleep();
+-		clear_bl_bit();
+-		set_thread_flag(TIF_POLLING_NRFLAG);
+-	} else
+-		while (!need_resched())
+-			cpu_relax();
+-}
+-
+-void cpu_idle(void)
+-{
+-	set_thread_flag(TIF_POLLING_NRFLAG);
+-
+-	/* endless idle loop with no priority at all */
+-	while (1) {
+-		void (*idle)(void) = pm_idle;
+-
+-		if (!idle)
+-			idle = default_idle;
+-
+-		tick_nohz_stop_sched_tick();
+-		while (!need_resched())
+-			idle();
+-		tick_nohz_restart_sched_tick();
+-
+-		preempt_enable_no_resched();
+-		schedule();
+-		preempt_disable();
+-		check_pgt_cache();
+-	}
+-}
+-
+-void machine_restart(char * __unused)
+-{
+-	/* SR.BL=1 and invoke address error to let CPU reset (manual reset) */
+-	asm volatile("ldc %0, sr\n\t"
+-		     "mov.l @%1, %0" : : "r" (0x10000000), "r" (0x80000001));
+-}
+-
+-void machine_halt(void)
+-{
+-	local_irq_disable();
+-
+-	while (1)
+-		cpu_sleep();
+-}
+-
+-void machine_power_off(void)
+-{
+-	if (pm_power_off)
+-		pm_power_off();
+-}
+-
+-void show_regs(struct pt_regs * regs)
+-{
+-	printk("\n");
+-	printk("Pid : %d, Comm: %20s\n", task_pid_nr(current), current->comm);
+-	print_symbol("PC is at %s\n", instruction_pointer(regs));
+-	printk("PC  : %08lx SP  : %08lx SR  : %08lx ",
+-	       regs->pc, regs->regs[15], regs->sr);
+-#ifdef CONFIG_MMU
+-	printk("TEA : %08x    ", ctrl_inl(MMU_TEA));
+-#else
+-	printk("                  ");
+-#endif
+-	printk("%s\n", print_tainted());
+-
+-	printk("R0  : %08lx R1  : %08lx R2  : %08lx R3  : %08lx\n",
+-	       regs->regs[0],regs->regs[1],
+-	       regs->regs[2],regs->regs[3]);
+-	printk("R4  : %08lx R5  : %08lx R6  : %08lx R7  : %08lx\n",
+-	       regs->regs[4],regs->regs[5],
+-	       regs->regs[6],regs->regs[7]);
+-	printk("R8  : %08lx R9  : %08lx R10 : %08lx R11 : %08lx\n",
+-	       regs->regs[8],regs->regs[9],
+-	       regs->regs[10],regs->regs[11]);
+-	printk("R12 : %08lx R13 : %08lx R14 : %08lx\n",
+-	       regs->regs[12],regs->regs[13],
+-	       regs->regs[14]);
+-	printk("MACH: %08lx MACL: %08lx GBR : %08lx PR  : %08lx\n",
+-	       regs->mach, regs->macl, regs->gbr, regs->pr);
+-
+-	show_trace(NULL, (unsigned long *)regs->regs[15], regs);
+-}
+-
+-/*
+- * Create a kernel thread
+- */
+-
+-/*
+- * This is the mechanism for creating a new kernel thread.
+- *
+- */
+-extern void kernel_thread_helper(void);
+-__asm__(".align 5\n"
+-	"kernel_thread_helper:\n\t"
+-	"jsr	@r5\n\t"
+-	" nop\n\t"
+-	"mov.l	1f, r1\n\t"
+-	"jsr	@r1\n\t"
+-	" mov	r0, r4\n\t"
+-	".align 2\n\t"
+-	"1:.long do_exit");
+-
+-/* Don't use this in BL=1(cli).  Or else, CPU resets! */
+-int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
+-{
+-	struct pt_regs regs;
+-
+-	memset(&regs, 0, sizeof(regs));
+-	regs.regs[4] = (unsigned long)arg;
+-	regs.regs[5] = (unsigned long)fn;
+-
+-	regs.pc = (unsigned long)kernel_thread_helper;
+-	regs.sr = (1 << 30);
+-
+-	/* Ok, create the new process.. */
+-	return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0,
+-		       &regs, 0, NULL, NULL);
+-}
+-
+-/*
+- * Free current thread data structures etc..
+- */
+-void exit_thread(void)
+-{
+-	if (current->thread.ubc_pc) {
+-		current->thread.ubc_pc = 0;
+-		ubc_usercnt -= 1;
+-	}
+-}
+-
+-void flush_thread(void)
+-{
+-#if defined(CONFIG_SH_FPU)
+-	struct task_struct *tsk = current;
+-	/* Forget lazy FPU state */
+-	clear_fpu(tsk, task_pt_regs(tsk));
+-	clear_used_math();
+-#endif
+-}
+-
+-void release_thread(struct task_struct *dead_task)
+-{
+-	/* do nothing */
+-}
+-
+-/* Fill in the fpu structure for a core dump.. */
+-int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu)
+-{
+-	int fpvalid = 0;
+-
+-#if defined(CONFIG_SH_FPU)
+-	struct task_struct *tsk = current;
+-
+-	fpvalid = !!tsk_used_math(tsk);
+-	if (fpvalid) {
+-		unlazy_fpu(tsk, regs);
+-		memcpy(fpu, &tsk->thread.fpu.hard, sizeof(*fpu));
+-	}
+-#endif
+-
+-	return fpvalid;
+-}
+-
+-/*
+- * 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)
+-{
+-	struct pt_regs ptregs;
+-
+-	ptregs = *task_pt_regs(tsk);
+-	elf_core_copy_regs(regs, &ptregs);
+-
+-	return 1;
+-}
+-
+-int dump_task_fpu(struct task_struct *tsk, elf_fpregset_t *fpu)
+-{
+-	int fpvalid = 0;
+-
+-#if defined(CONFIG_SH_FPU)
+-	fpvalid = !!tsk_used_math(tsk);
+-	if (fpvalid) {
+-		unlazy_fpu(tsk, task_pt_regs(tsk));
+-		memcpy(fpu, &tsk->thread.fpu.hard, sizeof(*fpu));
+-	}
+-#endif
+-
+-	return fpvalid;
+-}
+-
+-asmlinkage void ret_from_fork(void);
+-
+-int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
+-		unsigned long unused,
+-		struct task_struct *p, struct pt_regs *regs)
+-{
+-	struct thread_info *ti = task_thread_info(p);
+-	struct pt_regs *childregs;
+-#if defined(CONFIG_SH_FPU)
+-	struct task_struct *tsk = current;
+-
+-	unlazy_fpu(tsk, regs);
+-	p->thread.fpu = tsk->thread.fpu;
+-	copy_to_stopped_child_used_math(p);
+-#endif
+-
+-	childregs = task_pt_regs(p);
+-	*childregs = *regs;
+-
+-	if (user_mode(regs)) {
+-		childregs->regs[15] = usp;
+-		ti->addr_limit = USER_DS;
+-	} else {
+-		childregs->regs[15] = (unsigned long)childregs;
+-		ti->addr_limit = KERNEL_DS;
+-	}
+-
+-	if (clone_flags & CLONE_SETTLS)
+-		childregs->gbr = childregs->regs[0];
+-
+-	childregs->regs[0] = 0; /* Set return value for child */
+-
+-	p->thread.sp = (unsigned long) childregs;
+-	p->thread.pc = (unsigned long) ret_from_fork;
+-
+-	p->thread.ubc_pc = 0;
+-
+-	return 0;
+-}
+-
+-/* Tracing by user break controller.  */
+-static void ubc_set_tracing(int asid, unsigned long pc)
+-{
+-#if defined(CONFIG_CPU_SH4A)
+-	unsigned long val;
+-
+-	val = (UBC_CBR_ID_INST | UBC_CBR_RW_READ | UBC_CBR_CE);
+-	val |= (UBC_CBR_AIE | UBC_CBR_AIV_SET(asid));
+-
+-	ctrl_outl(val, UBC_CBR0);
+-	ctrl_outl(pc,  UBC_CAR0);
+-	ctrl_outl(0x0, UBC_CAMR0);
+-	ctrl_outl(0x0, UBC_CBCR);
+-
+-	val = (UBC_CRR_RES | UBC_CRR_PCB | UBC_CRR_BIE);
+-	ctrl_outl(val, UBC_CRR0);
+-
+-	/* Read UBC register that we wrote last, for checking update */
+-	val = ctrl_inl(UBC_CRR0);
+-
+-#else	/* CONFIG_CPU_SH4A */
+-	ctrl_outl(pc, UBC_BARA);
+-
+-#ifdef CONFIG_MMU
+-	ctrl_outb(asid, UBC_BASRA);
+-#endif
+-
+-	ctrl_outl(0, UBC_BAMRA);
+-
+-	if (current_cpu_data.type == CPU_SH7729 ||
+-	    current_cpu_data.type == CPU_SH7710 ||
+-	    current_cpu_data.type == CPU_SH7712) {
+-		ctrl_outw(BBR_INST | BBR_READ | BBR_CPU, UBC_BBRA);
+-		ctrl_outl(BRCR_PCBA | BRCR_PCTE, UBC_BRCR);
+-	} else {
+-		ctrl_outw(BBR_INST | BBR_READ, UBC_BBRA);
+-		ctrl_outw(BRCR_PCBA, UBC_BRCR);
+-	}
+-#endif	/* CONFIG_CPU_SH4A */
+-}
+-
+-/*
+- *	switch_to(x,y) should switch tasks from x to y.
+- *
+- */
+-struct task_struct *__switch_to(struct task_struct *prev,
+-				struct task_struct *next)
+-{
+-#if defined(CONFIG_SH_FPU)
+-	unlazy_fpu(prev, task_pt_regs(prev));
+-#endif
+-
+-#if defined(CONFIG_GUSA) && defined(CONFIG_PREEMPT)
+-	{
+-		struct pt_regs *regs;
+-
+-		preempt_disable();
+-		regs = task_pt_regs(prev);
+-		if (user_mode(regs) && regs->regs[15] >= 0xc0000000) {
+-			int offset = (int)regs->regs[15];
+-
+-			/* Reset stack pointer: clear critical region mark */
+-			regs->regs[15] = regs->regs[1];
+-			if (regs->pc < regs->regs[0])
+-				/* Go to rewind point */
+-				regs->pc = regs->regs[0] + offset;
+-		}
+-		preempt_enable_no_resched();
+-	}
+-#endif
+-
+-#ifdef CONFIG_MMU
+-	/*
+-	 * Restore the kernel mode register
+-	 *	k7 (r7_bank1)
+-	 */
+-	asm volatile("ldc	%0, r7_bank"
+-		     : /* no output */
+-		     : "r" (task_thread_info(next)));
+-#endif
+-
+-	/* If no tasks are using the UBC, we're done */
+-	if (ubc_usercnt == 0)
+-		/* If no tasks are using the UBC, we're done */;
+-	else if (next->thread.ubc_pc && next->mm) {
+-		int asid = 0;
+-#ifdef CONFIG_MMU
+-		asid |= cpu_asid(smp_processor_id(), next->mm);
+-#endif
+-		ubc_set_tracing(asid, next->thread.ubc_pc);
+-	} else {
+-#if defined(CONFIG_CPU_SH4A)
+-		ctrl_outl(UBC_CBR_INIT, UBC_CBR0);
+-		ctrl_outl(UBC_CRR_INIT, UBC_CRR0);
+-#else
+-		ctrl_outw(0, UBC_BBRA);
+-		ctrl_outw(0, UBC_BBRB);
+-#endif
+-	}
+-
+-	return prev;
+-}
+-
+-asmlinkage int sys_fork(unsigned long r4, unsigned long r5,
+-			unsigned long r6, unsigned long r7,
+-			struct pt_regs __regs)
+-{
+-#ifdef CONFIG_MMU
+-	struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
+-	return do_fork(SIGCHLD, regs->regs[15], regs, 0, NULL, NULL);
+-#else
+-	/* fork almost works, enough to trick you into looking elsewhere :-( */
+-	return -EINVAL;
+-#endif
+-}
+-
+-asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp,
+-			 unsigned long parent_tidptr,
+-			 unsigned long child_tidptr,
+-			 struct pt_regs __regs)
+-{
+-	struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
+-	if (!newsp)
+-		newsp = regs->regs[15];
+-	return do_fork(clone_flags, newsp, regs, 0,
+-			(int __user *)parent_tidptr,
+-			(int __user *)child_tidptr);
+-}
+-
+-/*
+- * This is trivial, and on the face of it looks like it
+- * could equally well be done in user mode.
+- *
+- * Not so, for quite unobvious reasons - register pressure.
+- * In user mode vfork() cannot have a stack frame, and if
+- * done by calling the "clone()" system call directly, you
+- * do not have enough call-clobbered registers to hold all
+- * the information you need.
+- */
+-asmlinkage int sys_vfork(unsigned long r4, unsigned long r5,
+-			 unsigned long r6, unsigned long r7,
+-			 struct pt_regs __regs)
+-{
+-	struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
+-	return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->regs[15], regs,
+-		       0, NULL, NULL);
+-}
+-
+-/*
+- * sys_execve() executes a new program.
+- */
+-asmlinkage int sys_execve(char __user *ufilename, char __user * __user *uargv,
+-			  char __user * __user *uenvp, unsigned long r7,
+-			  struct pt_regs __regs)
+-{
+-	struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
+-	int error;
+-	char *filename;
+-
+-	filename = getname(ufilename);
+-	error = PTR_ERR(filename);
+-	if (IS_ERR(filename))
+-		goto out;
+-
+-	error = do_execve(filename, uargv, uenvp, regs);
+-	if (error == 0) {
+-		task_lock(current);
+-		current->ptrace &= ~PT_DTRACE;
+-		task_unlock(current);
+-	}
+-	putname(filename);
+-out:
+-	return error;
+-}
+-
+-unsigned long get_wchan(struct task_struct *p)
+-{
+-	unsigned long pc;
+-
+-	if (!p || p == current || p->state == TASK_RUNNING)
+-		return 0;
+-
+-	/*
+-	 * The same comment as on the Alpha applies here, too ...
+-	 */
+-	pc = thread_saved_pc(p);
+-
+-#ifdef CONFIG_FRAME_POINTER
+-	if (in_sched_functions(pc)) {
+-		unsigned long schedule_frame = (unsigned long)p->thread.sp;
+-		return ((unsigned long *)schedule_frame)[21];
+-	}
+-#endif
+-
+-	return pc;
+-}
+-
+-asmlinkage void break_point_trap(void)
+-{
+-	/* Clear tracing.  */
+-#if defined(CONFIG_CPU_SH4A)
+-	ctrl_outl(UBC_CBR_INIT, UBC_CBR0);
+-	ctrl_outl(UBC_CRR_INIT, UBC_CRR0);
+-#else
+-	ctrl_outw(0, UBC_BBRA);
+-	ctrl_outw(0, UBC_BBRB);
+-#endif
+-	current->thread.ubc_pc = 0;
+-	ubc_usercnt -= 1;
+-
+-	force_sig(SIGTRAP, current);
+-}
+-
+-/*
+- * Generic trap handler.
+- */
+-asmlinkage void debug_trap_handler(unsigned long r4, unsigned long r5,
+-				   unsigned long r6, unsigned long r7,
+-				   struct pt_regs __regs)
+-{
+-	struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
+-
+-	/* Rewind */
+-	regs->pc -= instruction_size(ctrl_inw(regs->pc - 4));
+-
+-	if (notify_die(DIE_TRAP, "debug trap", regs, 0, regs->tra & 0xff,
+-		       SIGTRAP) == NOTIFY_STOP)
+-		return;
+-
+-	force_sig(SIGTRAP, current);
+-}
+-
+-/*
+- * Special handler for BUG() traps.
+- */
+-asmlinkage void bug_trap_handler(unsigned long r4, unsigned long r5,
+-				 unsigned long r6, unsigned long r7,
+-				 struct pt_regs __regs)
+-{
+-	struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
+-
+-	/* Rewind */
+-	regs->pc -= instruction_size(ctrl_inw(regs->pc - 4));
+-
+-	if (notify_die(DIE_TRAP, "bug trap", regs, 0, TRAPA_BUG_OPCODE & 0xff,
+-		       SIGTRAP) == NOTIFY_STOP)
+-		return;
+-
+-#ifdef CONFIG_BUG
+-	if (__kernel_text_address(instruction_pointer(regs))) {
+-		u16 insn = *(u16 *)instruction_pointer(regs);
+-		if (insn == TRAPA_BUG_OPCODE)
+-			handle_BUG(regs);
+-	}
+-#endif
+-
+-	force_sig(SIGTRAP, current);
+-}
+diff --git a/arch/sh/kernel/process_32.c b/arch/sh/kernel/process_32.c
+new file mode 100644
+index 0000000..9ab1926
+--- /dev/null
++++ b/arch/sh/kernel/process_32.c
+@@ -0,0 +1,465 @@
++/*
++ * arch/sh/kernel/process.c
++ *
++ * This file handles the architecture-dependent parts of process handling..
++ *
++ *  Copyright (C) 1995  Linus Torvalds
++ *
++ *  SuperH version:  Copyright (C) 1999, 2000  Niibe Yutaka & Kaz Kojima
++ *		     Copyright (C) 2006 Lineo Solutions Inc. support SH4A UBC
++ *		     Copyright (C) 2002 - 2007  Paul Mundt
++ */
++#include <linux/module.h>
++#include <linux/mm.h>
++#include <linux/elfcore.h>
++#include <linux/pm.h>
++#include <linux/kallsyms.h>
++#include <linux/kexec.h>
++#include <linux/kdebug.h>
++#include <linux/tick.h>
++#include <linux/reboot.h>
++#include <linux/fs.h>
++#include <linux/preempt.h>
++#include <asm/uaccess.h>
++#include <asm/mmu_context.h>
++#include <asm/pgalloc.h>
++#include <asm/system.h>
++#include <asm/ubc.h>
++
++static int hlt_counter;
++int ubc_usercnt = 0;
++
++void (*pm_idle)(void);
++void (*pm_power_off)(void);
++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);
++
++static int __init nohlt_setup(char *__unused)
++{
++	hlt_counter = 1;
++	return 1;
++}
++__setup("nohlt", nohlt_setup);
++
++static int __init hlt_setup(char *__unused)
++{
++	hlt_counter = 0;
++	return 1;
++}
++__setup("hlt", hlt_setup);
++
++void default_idle(void)
++{
++	if (!hlt_counter) {
++		clear_thread_flag(TIF_POLLING_NRFLAG);
++		smp_mb__after_clear_bit();
++		set_bl_bit();
++		while (!need_resched())
++			cpu_sleep();
++		clear_bl_bit();
++		set_thread_flag(TIF_POLLING_NRFLAG);
++	} else
++		while (!need_resched())
++			cpu_relax();
++}
++
++void cpu_idle(void)
++{
++	set_thread_flag(TIF_POLLING_NRFLAG);
++
++	/* endless idle loop with no priority at all */
++	while (1) {
++		void (*idle)(void) = pm_idle;
++
++		if (!idle)
++			idle = default_idle;
++
++		tick_nohz_stop_sched_tick();
++		while (!need_resched())
++			idle();
++		tick_nohz_restart_sched_tick();
++
++		preempt_enable_no_resched();
++		schedule();
++		preempt_disable();
++		check_pgt_cache();
++	}
++}
++
++void machine_restart(char * __unused)
++{
++	/* SR.BL=1 and invoke address error to let CPU reset (manual reset) */
++	asm volatile("ldc %0, sr\n\t"
++		     "mov.l @%1, %0" : : "r" (0x10000000), "r" (0x80000001));
++}
++
++void machine_halt(void)
++{
++	local_irq_disable();
++
++	while (1)
++		cpu_sleep();
++}
++
++void machine_power_off(void)
++{
++	if (pm_power_off)
++		pm_power_off();
++}
++
++void show_regs(struct pt_regs * regs)
++{
++	printk("\n");
++	printk("Pid : %d, Comm: %20s\n", task_pid_nr(current), current->comm);
++	print_symbol("PC is at %s\n", instruction_pointer(regs));
++	printk("PC  : %08lx SP  : %08lx SR  : %08lx ",
++	       regs->pc, regs->regs[15], regs->sr);
++#ifdef CONFIG_MMU
++	printk("TEA : %08x    ", ctrl_inl(MMU_TEA));
++#else
++	printk("                  ");
++#endif
++	printk("%s\n", print_tainted());
++
++	printk("R0  : %08lx R1  : %08lx R2  : %08lx R3  : %08lx\n",
++	       regs->regs[0],regs->regs[1],
++	       regs->regs[2],regs->regs[3]);
++	printk("R4  : %08lx R5  : %08lx R6  : %08lx R7  : %08lx\n",
++	       regs->regs[4],regs->regs[5],
++	       regs->regs[6],regs->regs[7]);
++	printk("R8  : %08lx R9  : %08lx R10 : %08lx R11 : %08lx\n",
++	       regs->regs[8],regs->regs[9],
++	       regs->regs[10],regs->regs[11]);
++	printk("R12 : %08lx R13 : %08lx R14 : %08lx\n",
++	       regs->regs[12],regs->regs[13],
++	       regs->regs[14]);
++	printk("MACH: %08lx MACL: %08lx GBR : %08lx PR  : %08lx\n",
++	       regs->mach, regs->macl, regs->gbr, regs->pr);
++
++	show_trace(NULL, (unsigned long *)regs->regs[15], regs);
++}
++
++/*
++ * Create a kernel thread
++ */
++
++/*
++ * This is the mechanism for creating a new kernel thread.
++ *
++ */
++extern void kernel_thread_helper(void);
++__asm__(".align 5\n"
++	"kernel_thread_helper:\n\t"
++	"jsr	@r5\n\t"
++	" nop\n\t"
++	"mov.l	1f, r1\n\t"
++	"jsr	@r1\n\t"
++	" mov	r0, r4\n\t"
++	".align 2\n\t"
++	"1:.long do_exit");
++
++/* Don't use this in BL=1(cli).  Or else, CPU resets! */
++int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
++{
++	struct pt_regs regs;
++
++	memset(&regs, 0, sizeof(regs));
++	regs.regs[4] = (unsigned long)arg;
++	regs.regs[5] = (unsigned long)fn;
++
++	regs.pc = (unsigned long)kernel_thread_helper;
++	regs.sr = (1 << 30);
++
++	/* Ok, create the new process.. */
++	return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0,
++		       &regs, 0, NULL, NULL);
++}
++
++/*
++ * Free current thread data structures etc..
++ */
++void exit_thread(void)
++{
++	if (current->thread.ubc_pc) {
++		current->thread.ubc_pc = 0;
++		ubc_usercnt -= 1;
++	}
++}
++
++void flush_thread(void)
++{
++#if defined(CONFIG_SH_FPU)
++	struct task_struct *tsk = current;
++	/* Forget lazy FPU state */
++	clear_fpu(tsk, task_pt_regs(tsk));
++	clear_used_math();
++#endif
++}
++
++void release_thread(struct task_struct *dead_task)
++{
++	/* do nothing */
++}
++
++/* Fill in the fpu structure for a core dump.. */
++int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu)
++{
++	int fpvalid = 0;
++
++#if defined(CONFIG_SH_FPU)
++	struct task_struct *tsk = current;
++
++	fpvalid = !!tsk_used_math(tsk);
++	if (fpvalid) {
++		unlazy_fpu(tsk, regs);
++		memcpy(fpu, &tsk->thread.fpu.hard, sizeof(*fpu));
++	}
++#endif
++
++	return fpvalid;
++}
++
++asmlinkage void ret_from_fork(void);
++
++int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
++		unsigned long unused,
++		struct task_struct *p, struct pt_regs *regs)
++{
++	struct thread_info *ti = task_thread_info(p);
++	struct pt_regs *childregs;
++#if defined(CONFIG_SH_FPU)
++	struct task_struct *tsk = current;
++
++	unlazy_fpu(tsk, regs);
++	p->thread.fpu = tsk->thread.fpu;
++	copy_to_stopped_child_used_math(p);
++#endif
++
++	childregs = task_pt_regs(p);
++	*childregs = *regs;
++
++	if (user_mode(regs)) {
++		childregs->regs[15] = usp;
++		ti->addr_limit = USER_DS;
++	} else {
++		childregs->regs[15] = (unsigned long)childregs;
++		ti->addr_limit = KERNEL_DS;
++	}
++
++	if (clone_flags & CLONE_SETTLS)
++		childregs->gbr = childregs->regs[0];
++
++	childregs->regs[0] = 0; /* Set return value for child */
++
++	p->thread.sp = (unsigned long) childregs;
++	p->thread.pc = (unsigned long) ret_from_fork;
++
++	p->thread.ubc_pc = 0;
++
++	return 0;
++}
++
++/* Tracing by user break controller.  */
++static void ubc_set_tracing(int asid, unsigned long pc)
++{
++#if defined(CONFIG_CPU_SH4A)
++	unsigned long val;
++
++	val = (UBC_CBR_ID_INST | UBC_CBR_RW_READ | UBC_CBR_CE);
++	val |= (UBC_CBR_AIE | UBC_CBR_AIV_SET(asid));
++
++	ctrl_outl(val, UBC_CBR0);
++	ctrl_outl(pc,  UBC_CAR0);
++	ctrl_outl(0x0, UBC_CAMR0);
++	ctrl_outl(0x0, UBC_CBCR);
++
++	val = (UBC_CRR_RES | UBC_CRR_PCB | UBC_CRR_BIE);
++	ctrl_outl(val, UBC_CRR0);
++
++	/* Read UBC register that we wrote last, for checking update */
++	val = ctrl_inl(UBC_CRR0);
++
++#else	/* CONFIG_CPU_SH4A */
++	ctrl_outl(pc, UBC_BARA);
++
++#ifdef CONFIG_MMU
++	ctrl_outb(asid, UBC_BASRA);
++#endif
++
++	ctrl_outl(0, UBC_BAMRA);
++
++	if (current_cpu_data.type == CPU_SH7729 ||
++	    current_cpu_data.type == CPU_SH7710 ||
++	    current_cpu_data.type == CPU_SH7712) {
++		ctrl_outw(BBR_INST | BBR_READ | BBR_CPU, UBC_BBRA);
++		ctrl_outl(BRCR_PCBA | BRCR_PCTE, UBC_BRCR);
++	} else {
++		ctrl_outw(BBR_INST | BBR_READ, UBC_BBRA);
++		ctrl_outw(BRCR_PCBA, UBC_BRCR);
++	}
++#endif	/* CONFIG_CPU_SH4A */
++}
++
++/*
++ *	switch_to(x,y) should switch tasks from x to y.
++ *
++ */
++struct task_struct *__switch_to(struct task_struct *prev,
++				struct task_struct *next)
++{
++#if defined(CONFIG_SH_FPU)
++	unlazy_fpu(prev, task_pt_regs(prev));
++#endif
++
++#ifdef CONFIG_MMU
++	/*
++	 * Restore the kernel mode register
++	 *	k7 (r7_bank1)
++	 */
++	asm volatile("ldc	%0, r7_bank"
++		     : /* no output */
++		     : "r" (task_thread_info(next)));
++#endif
++
++	/* If no tasks are using the UBC, we're done */
++	if (ubc_usercnt == 0)
++		/* If no tasks are using the UBC, we're done */;
++	else if (next->thread.ubc_pc && next->mm) {
++		int asid = 0;
++#ifdef CONFIG_MMU
++		asid |= cpu_asid(smp_processor_id(), next->mm);
++#endif
++		ubc_set_tracing(asid, next->thread.ubc_pc);
++	} else {
++#if defined(CONFIG_CPU_SH4A)
++		ctrl_outl(UBC_CBR_INIT, UBC_CBR0);
++		ctrl_outl(UBC_CRR_INIT, UBC_CRR0);
++#else
++		ctrl_outw(0, UBC_BBRA);
++		ctrl_outw(0, UBC_BBRB);
++#endif
++	}
++
++	return prev;
++}
++
++asmlinkage int sys_fork(unsigned long r4, unsigned long r5,
++			unsigned long r6, unsigned long r7,
++			struct pt_regs __regs)
++{
++#ifdef CONFIG_MMU
++	struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
++	return do_fork(SIGCHLD, regs->regs[15], regs, 0, NULL, NULL);
++#else
++	/* fork almost works, enough to trick you into looking elsewhere :-( */
++	return -EINVAL;
++#endif
++}
++
++asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp,
++			 unsigned long parent_tidptr,
++			 unsigned long child_tidptr,
++			 struct pt_regs __regs)
++{
++	struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
++	if (!newsp)
++		newsp = regs->regs[15];
++	return do_fork(clone_flags, newsp, regs, 0,
++			(int __user *)parent_tidptr,
++			(int __user *)child_tidptr);
++}
++
++/*
++ * This is trivial, and on the face of it looks like it
++ * could equally well be done in user mode.
++ *
++ * Not so, for quite unobvious reasons - register pressure.
++ * In user mode vfork() cannot have a stack frame, and if
++ * done by calling the "clone()" system call directly, you
++ * do not have enough call-clobbered registers to hold all
++ * the information you need.
++ */
++asmlinkage int sys_vfork(unsigned long r4, unsigned long r5,
++			 unsigned long r6, unsigned long r7,
++			 struct pt_regs __regs)
++{
++	struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
++	return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->regs[15], regs,
++		       0, NULL, NULL);
++}
++
++/*
++ * sys_execve() executes a new program.
++ */
++asmlinkage int sys_execve(char __user *ufilename, char __user * __user *uargv,
++			  char __user * __user *uenvp, unsigned long r7,
++			  struct pt_regs __regs)
++{
++	struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
++	int error;
++	char *filename;
++
++	filename = getname(ufilename);
++	error = PTR_ERR(filename);
++	if (IS_ERR(filename))
++		goto out;
++
++	error = do_execve(filename, uargv, uenvp, regs);
++	if (error == 0) {
++		task_lock(current);
++		current->ptrace &= ~PT_DTRACE;
++		task_unlock(current);
++	}
++	putname(filename);
++out:
++	return error;
++}
++
++unsigned long get_wchan(struct task_struct *p)
++{
++	unsigned long pc;
++
++	if (!p || p == current || p->state == TASK_RUNNING)
++		return 0;
++
++	/*
++	 * The same comment as on the Alpha applies here, too ...
++	 */
++	pc = thread_saved_pc(p);
++
++#ifdef CONFIG_FRAME_POINTER
++	if (in_sched_functions(pc)) {
++		unsigned long schedule_frame = (unsigned long)p->thread.sp;
++		return ((unsigned long *)schedule_frame)[21];
++	}
++#endif
++
++	return pc;
++}
++
++asmlinkage void break_point_trap(void)
++{
++	/* Clear tracing.  */
++#if defined(CONFIG_CPU_SH4A)
++	ctrl_outl(UBC_CBR_INIT, UBC_CBR0);
++	ctrl_outl(UBC_CRR_INIT, UBC_CRR0);
++#else
++	ctrl_outw(0, UBC_BBRA);
++	ctrl_outw(0, UBC_BBRB);
++#endif
++	current->thread.ubc_pc = 0;
++	ubc_usercnt -= 1;
++
++	force_sig(SIGTRAP, current);
++}
+diff --git a/arch/sh/kernel/process_64.c b/arch/sh/kernel/process_64.c
+new file mode 100644
+index 0000000..cff3b7d
+--- /dev/null
++++ b/arch/sh/kernel/process_64.c
+@@ -0,0 +1,701 @@
++/*
++ * arch/sh/kernel/process_64.c
++ *
++ * This file handles the architecture-dependent parts of process handling..
++ *
++ * Copyright (C) 2000, 2001  Paolo Alberelli
++ * Copyright (C) 2003 - 2007  Paul Mundt
++ * Copyright (C) 2003, 2004 Richard Curnow
++ *
++ * Started from SH3/4 version:
++ *   Copyright (C) 1999, 2000  Niibe Yutaka & Kaz Kojima
++ *
++ *   In turn started from i386 version:
++ *     Copyright (C) 1995  Linus Torvalds
++ *
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License.  See the file "COPYING" in the main directory of this archive
++ * for more details.
++ */
++#include <linux/mm.h>
++#include <linux/fs.h>
++#include <linux/ptrace.h>
++#include <linux/reboot.h>
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/proc_fs.h>
++#include <linux/io.h>
++#include <asm/uaccess.h>
++#include <asm/pgtable.h>
++#include <asm/mmu_context.h>
++
++struct task_struct *last_task_used_math = NULL;
++
++static int hlt_counter = 1;
++
++#define HARD_IDLE_TIMEOUT (HZ / 3)
++
++void disable_hlt(void)
++{
++	hlt_counter++;
++}
++
++void enable_hlt(void)
++{
++	hlt_counter--;
++}
++
++static int __init nohlt_setup(char *__unused)
++{
++	hlt_counter = 1;
++	return 1;
++}
++
++static int __init hlt_setup(char *__unused)
++{
++	hlt_counter = 0;
++	return 1;
++}
++
++__setup("nohlt", nohlt_setup);
++__setup("hlt", hlt_setup);
++
++static inline void hlt(void)
++{
++	__asm__ __volatile__ ("sleep" : : : "memory");
++}
++
++/*
++ * The idle loop on a uniprocessor SH..
++ */
++void cpu_idle(void)
++{
++	/* endless idle loop with no priority at all */
++	while (1) {
++		if (hlt_counter) {
++			while (!need_resched())
++				cpu_relax();
++		} else {
++			local_irq_disable();
++			while (!need_resched()) {
++				local_irq_enable();
++				hlt();
++				local_irq_disable();
++			}
++			local_irq_enable();
++		}
++		preempt_enable_no_resched();
++		schedule();
++		preempt_disable();
++	}
++
++}
++
++void machine_restart(char * __unused)
++{
++	extern void phys_stext(void);
++
++	phys_stext();
++}
++
++void machine_halt(void)
++{
++	for (;;);
++}
++
++void machine_power_off(void)
++{
++#if 0
++	/* Disable watchdog timer */
++	ctrl_outl(0xa5000000, WTCSR);
++	/* Configure deep standby on sleep */
++	ctrl_outl(0x03, STBCR);
++#endif
++
++	__asm__ __volatile__ (
++		"sleep\n\t"
++		"synci\n\t"
++		"nop;nop;nop;nop\n\t"
++	);
++
++	panic("Unexpected wakeup!\n");
++}
++
++void (*pm_power_off)(void) = machine_power_off;
++EXPORT_SYMBOL(pm_power_off);
++
++void show_regs(struct pt_regs * regs)
++{
++	unsigned long long ah, al, bh, bl, ch, cl;
++
++	printk("\n");
++
++	ah = (regs->pc) >> 32;
++	al = (regs->pc) & 0xffffffff;
++	bh = (regs->regs[18]) >> 32;
++	bl = (regs->regs[18]) & 0xffffffff;
++	ch = (regs->regs[15]) >> 32;
++	cl = (regs->regs[15]) & 0xffffffff;
++	printk("PC  : %08Lx%08Lx LINK: %08Lx%08Lx SP  : %08Lx%08Lx\n",
++	       ah, al, bh, bl, ch, cl);
++
++	ah = (regs->sr) >> 32;
++	al = (regs->sr) & 0xffffffff;
++        asm volatile ("getcon   " __TEA ", %0" : "=r" (bh));
++        asm volatile ("getcon   " __TEA ", %0" : "=r" (bl));
++	bh = (bh) >> 32;
++	bl = (bl) & 0xffffffff;
++        asm volatile ("getcon   " __KCR0 ", %0" : "=r" (ch));
++        asm volatile ("getcon   " __KCR0 ", %0" : "=r" (cl));
++	ch = (ch) >> 32;
++	cl = (cl) & 0xffffffff;
++	printk("SR  : %08Lx%08Lx TEA : %08Lx%08Lx KCR0: %08Lx%08Lx\n",
++	       ah, al, bh, bl, ch, cl);
++
++	ah = (regs->regs[0]) >> 32;
++	al = (regs->regs[0]) & 0xffffffff;
++	bh = (regs->regs[1]) >> 32;
++	bl = (regs->regs[1]) & 0xffffffff;
++	ch = (regs->regs[2]) >> 32;
++	cl = (regs->regs[2]) & 0xffffffff;
++	printk("R0  : %08Lx%08Lx R1  : %08Lx%08Lx R2  : %08Lx%08Lx\n",
++	       ah, al, bh, bl, ch, cl);
++
++	ah = (regs->regs[3]) >> 32;
++	al = (regs->regs[3]) & 0xffffffff;
++	bh = (regs->regs[4]) >> 32;
++	bl = (regs->regs[4]) & 0xffffffff;
++	ch = (regs->regs[5]) >> 32;
++	cl = (regs->regs[5]) & 0xffffffff;
++	printk("R3  : %08Lx%08Lx R4  : %08Lx%08Lx R5  : %08Lx%08Lx\n",
++	       ah, al, bh, bl, ch, cl);
++
++	ah = (regs->regs[6]) >> 32;
++	al = (regs->regs[6]) & 0xffffffff;
++	bh = (regs->regs[7]) >> 32;
++	bl = (regs->regs[7]) & 0xffffffff;
++	ch = (regs->regs[8]) >> 32;
++	cl = (regs->regs[8]) & 0xffffffff;
++	printk("R6  : %08Lx%08Lx R7  : %08Lx%08Lx R8  : %08Lx%08Lx\n",
++	       ah, al, bh, bl, ch, cl);
++
++	ah = (regs->regs[9]) >> 32;
++	al = (regs->regs[9]) & 0xffffffff;
++	bh = (regs->regs[10]) >> 32;
++	bl = (regs->regs[10]) & 0xffffffff;
++	ch = (regs->regs[11]) >> 32;
++	cl = (regs->regs[11]) & 0xffffffff;
++	printk("R9  : %08Lx%08Lx R10 : %08Lx%08Lx R11 : %08Lx%08Lx\n",
++	       ah, al, bh, bl, ch, cl);
++
++	ah = (regs->regs[12]) >> 32;
++	al = (regs->regs[12]) & 0xffffffff;
++	bh = (regs->regs[13]) >> 32;
++	bl = (regs->regs[13]) & 0xffffffff;
++	ch = (regs->regs[14]) >> 32;
++	cl = (regs->regs[14]) & 0xffffffff;
++	printk("R12 : %08Lx%08Lx R13 : %08Lx%08Lx R14 : %08Lx%08Lx\n",
++	       ah, al, bh, bl, ch, cl);
++
++	ah = (regs->regs[16]) >> 32;
++	al = (regs->regs[16]) & 0xffffffff;
++	bh = (regs->regs[17]) >> 32;
++	bl = (regs->regs[17]) & 0xffffffff;
++	ch = (regs->regs[19]) >> 32;
++	cl = (regs->regs[19]) & 0xffffffff;
++	printk("R16 : %08Lx%08Lx R17 : %08Lx%08Lx R19 : %08Lx%08Lx\n",
++	       ah, al, bh, bl, ch, cl);
++
++	ah = (regs->regs[20]) >> 32;
++	al = (regs->regs[20]) & 0xffffffff;
++	bh = (regs->regs[21]) >> 32;
++	bl = (regs->regs[21]) & 0xffffffff;
++	ch = (regs->regs[22]) >> 32;
++	cl = (regs->regs[22]) & 0xffffffff;
++	printk("R20 : %08Lx%08Lx R21 : %08Lx%08Lx R22 : %08Lx%08Lx\n",
++	       ah, al, bh, bl, ch, cl);
++
++	ah = (regs->regs[23]) >> 32;
++	al = (regs->regs[23]) & 0xffffffff;
++	bh = (regs->regs[24]) >> 32;
++	bl = (regs->regs[24]) & 0xffffffff;
++	ch = (regs->regs[25]) >> 32;
++	cl = (regs->regs[25]) & 0xffffffff;
++	printk("R23 : %08Lx%08Lx R24 : %08Lx%08Lx R25 : %08Lx%08Lx\n",
++	       ah, al, bh, bl, ch, cl);
++
++	ah = (regs->regs[26]) >> 32;
++	al = (regs->regs[26]) & 0xffffffff;
++	bh = (regs->regs[27]) >> 32;
++	bl = (regs->regs[27]) & 0xffffffff;
++	ch = (regs->regs[28]) >> 32;
++	cl = (regs->regs[28]) & 0xffffffff;
++	printk("R26 : %08Lx%08Lx R27 : %08Lx%08Lx R28 : %08Lx%08Lx\n",
++	       ah, al, bh, bl, ch, cl);
++
++	ah = (regs->regs[29]) >> 32;
++	al = (regs->regs[29]) & 0xffffffff;
++	bh = (regs->regs[30]) >> 32;
++	bl = (regs->regs[30]) & 0xffffffff;
++	ch = (regs->regs[31]) >> 32;
++	cl = (regs->regs[31]) & 0xffffffff;
++	printk("R29 : %08Lx%08Lx R30 : %08Lx%08Lx R31 : %08Lx%08Lx\n",
++	       ah, al, bh, bl, ch, cl);
++
++	ah = (regs->regs[32]) >> 32;
++	al = (regs->regs[32]) & 0xffffffff;
++	bh = (regs->regs[33]) >> 32;
++	bl = (regs->regs[33]) & 0xffffffff;
++	ch = (regs->regs[34]) >> 32;
++	cl = (regs->regs[34]) & 0xffffffff;
++	printk("R32 : %08Lx%08Lx R33 : %08Lx%08Lx R34 : %08Lx%08Lx\n",
++	       ah, al, bh, bl, ch, cl);
++
++	ah = (regs->regs[35]) >> 32;
++	al = (regs->regs[35]) & 0xffffffff;
++	bh = (regs->regs[36]) >> 32;
++	bl = (regs->regs[36]) & 0xffffffff;
++	ch = (regs->regs[37]) >> 32;
++	cl = (regs->regs[37]) & 0xffffffff;
++	printk("R35 : %08Lx%08Lx R36 : %08Lx%08Lx R37 : %08Lx%08Lx\n",
++	       ah, al, bh, bl, ch, cl);
++
++	ah = (regs->regs[38]) >> 32;
++	al = (regs->regs[38]) & 0xffffffff;
++	bh = (regs->regs[39]) >> 32;
++	bl = (regs->regs[39]) & 0xffffffff;
++	ch = (regs->regs[40]) >> 32;
++	cl = (regs->regs[40]) & 0xffffffff;
++	printk("R38 : %08Lx%08Lx R39 : %08Lx%08Lx R40 : %08Lx%08Lx\n",
++	       ah, al, bh, bl, ch, cl);
++
++	ah = (regs->regs[41]) >> 32;
++	al = (regs->regs[41]) & 0xffffffff;
++	bh = (regs->regs[42]) >> 32;
++	bl = (regs->regs[42]) & 0xffffffff;
++	ch = (regs->regs[43]) >> 32;
++	cl = (regs->regs[43]) & 0xffffffff;
++	printk("R41 : %08Lx%08Lx R42 : %08Lx%08Lx R43 : %08Lx%08Lx\n",
++	       ah, al, bh, bl, ch, cl);
++
++	ah = (regs->regs[44]) >> 32;
++	al = (regs->regs[44]) & 0xffffffff;
++	bh = (regs->regs[45]) >> 32;
++	bl = (regs->regs[45]) & 0xffffffff;
++	ch = (regs->regs[46]) >> 32;
++	cl = (regs->regs[46]) & 0xffffffff;
++	printk("R44 : %08Lx%08Lx R45 : %08Lx%08Lx R46 : %08Lx%08Lx\n",
++	       ah, al, bh, bl, ch, cl);
++
++	ah = (regs->regs[47]) >> 32;
++	al = (regs->regs[47]) & 0xffffffff;
++	bh = (regs->regs[48]) >> 32;
++	bl = (regs->regs[48]) & 0xffffffff;
++	ch = (regs->regs[49]) >> 32;
++	cl = (regs->regs[49]) & 0xffffffff;
++	printk("R47 : %08Lx%08Lx R48 : %08Lx%08Lx R49 : %08Lx%08Lx\n",
++	       ah, al, bh, bl, ch, cl);
++
++	ah = (regs->regs[50]) >> 32;
++	al = (regs->regs[50]) & 0xffffffff;
++	bh = (regs->regs[51]) >> 32;
++	bl = (regs->regs[51]) & 0xffffffff;
++	ch = (regs->regs[52]) >> 32;
++	cl = (regs->regs[52]) & 0xffffffff;
++	printk("R50 : %08Lx%08Lx R51 : %08Lx%08Lx R52 : %08Lx%08Lx\n",
++	       ah, al, bh, bl, ch, cl);
++
++	ah = (regs->regs[53]) >> 32;
++	al = (regs->regs[53]) & 0xffffffff;
++	bh = (regs->regs[54]) >> 32;
++	bl = (regs->regs[54]) & 0xffffffff;
++	ch = (regs->regs[55]) >> 32;
++	cl = (regs->regs[55]) & 0xffffffff;
++	printk("R53 : %08Lx%08Lx R54 : %08Lx%08Lx R55 : %08Lx%08Lx\n",
++	       ah, al, bh, bl, ch, cl);
++
++	ah = (regs->regs[56]) >> 32;
++	al = (regs->regs[56]) & 0xffffffff;
++	bh = (regs->regs[57]) >> 32;
++	bl = (regs->regs[57]) & 0xffffffff;
++	ch = (regs->regs[58]) >> 32;
++	cl = (regs->regs[58]) & 0xffffffff;
++	printk("R56 : %08Lx%08Lx R57 : %08Lx%08Lx R58 : %08Lx%08Lx\n",
++	       ah, al, bh, bl, ch, cl);
++
++	ah = (regs->regs[59]) >> 32;
++	al = (regs->regs[59]) & 0xffffffff;
++	bh = (regs->regs[60]) >> 32;
++	bl = (regs->regs[60]) & 0xffffffff;
++	ch = (regs->regs[61]) >> 32;
++	cl = (regs->regs[61]) & 0xffffffff;
++	printk("R59 : %08Lx%08Lx R60 : %08Lx%08Lx R61 : %08Lx%08Lx\n",
++	       ah, al, bh, bl, ch, cl);
++
++	ah = (regs->regs[62]) >> 32;
++	al = (regs->regs[62]) & 0xffffffff;
++	bh = (regs->tregs[0]) >> 32;
++	bl = (regs->tregs[0]) & 0xffffffff;
++	ch = (regs->tregs[1]) >> 32;
++	cl = (regs->tregs[1]) & 0xffffffff;
++	printk("R62 : %08Lx%08Lx T0  : %08Lx%08Lx T1  : %08Lx%08Lx\n",
++	       ah, al, bh, bl, ch, cl);
++
++	ah = (regs->tregs[2]) >> 32;
++	al = (regs->tregs[2]) & 0xffffffff;
++	bh = (regs->tregs[3]) >> 32;
++	bl = (regs->tregs[3]) & 0xffffffff;
++	ch = (regs->tregs[4]) >> 32;
++	cl = (regs->tregs[4]) & 0xffffffff;
++	printk("T2  : %08Lx%08Lx T3  : %08Lx%08Lx T4  : %08Lx%08Lx\n",
++	       ah, al, bh, bl, ch, cl);
++
++	ah = (regs->tregs[5]) >> 32;
++	al = (regs->tregs[5]) & 0xffffffff;
++	bh = (regs->tregs[6]) >> 32;
++	bl = (regs->tregs[6]) & 0xffffffff;
++	ch = (regs->tregs[7]) >> 32;
++	cl = (regs->tregs[7]) & 0xffffffff;
++	printk("T5  : %08Lx%08Lx T6  : %08Lx%08Lx T7  : %08Lx%08Lx\n",
++	       ah, al, bh, bl, ch, cl);
++
++	/*
++	 * If we're in kernel mode, dump the stack too..
++	 */
++	if (!user_mode(regs)) {
++		void show_stack(struct task_struct *tsk, unsigned long *sp);
++		unsigned long sp = regs->regs[15] & 0xffffffff;
++		struct task_struct *tsk = get_current();
++
++		tsk->thread.kregs = regs;
++
++		show_stack(tsk, (unsigned long *)sp);
++	}
++}
++
++struct task_struct * alloc_task_struct(void)
++{
++	/* Get task descriptor pages */
++	return (struct task_struct *)
++		__get_free_pages(GFP_KERNEL, get_order(THREAD_SIZE));
++}
++
++void free_task_struct(struct task_struct *p)
++{
++	free_pages((unsigned long) p, get_order(THREAD_SIZE));
++}
++
++/*
++ * Create a kernel thread
++ */
++ATTRIB_NORET void kernel_thread_helper(void *arg, int (*fn)(void *))
++{
++	do_exit(fn(arg));
++}
++
++/*
++ * This is the mechanism for creating a new kernel thread.
++ *
++ * NOTE! Only a kernel-only process(ie the swapper or direct descendants
++ * who haven't done an "execve()") should use this: it will work within
++ * a system call from a "real" process, but the process memory space will
++ * not be freed until both the parent and the child have exited.
++ */
++int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
++{
++	struct pt_regs regs;
++
++	memset(&regs, 0, sizeof(regs));
++	regs.regs[2] = (unsigned long)arg;
++	regs.regs[3] = (unsigned long)fn;
++
++	regs.pc = (unsigned long)kernel_thread_helper;
++	regs.sr = (1 << 30);
++
++	return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0,
++		       &regs, 0, NULL, NULL);
++}
++
++/*
++ * Free current thread data structures etc..
++ */
++void exit_thread(void)
++{
++	/*
++	 * See arch/sparc/kernel/process.c for the precedent for doing
++	 * this -- RPC.
++	 *
++	 * The SH-5 FPU save/restore approach relies on
++	 * last_task_used_math pointing to a live task_struct.  When
++	 * another task tries to use the FPU for the 1st time, the FPUDIS
++	 * trap handling (see arch/sh/kernel/cpu/sh5/fpu.c) will save the
++	 * existing FPU state to the FP regs field within
++	 * last_task_used_math before re-loading the new task's FPU state
++	 * (or initialising it if the FPU has been used before).  So if
++	 * last_task_used_math is stale, and its page has already been
++	 * re-allocated for another use, the consequences are rather
++	 * grim. Unless we null it here, there is no other path through
++	 * which it would get safely nulled.
++	 */
++#ifdef CONFIG_SH_FPU
++	if (last_task_used_math == current) {
++		last_task_used_math = NULL;
++	}
++#endif
++}
++
++void flush_thread(void)
++{
++
++	/* Called by fs/exec.c (flush_old_exec) to remove traces of a
++	 * previously running executable. */
++#ifdef CONFIG_SH_FPU
++	if (last_task_used_math == current) {
++		last_task_used_math = NULL;
++	}
++	/* Force FPU state to be reinitialised after exec */
++	clear_used_math();
++#endif
++
++	/* if we are a kernel thread, about to change to user thread,
++         * update kreg
++         */
++	if(current->thread.kregs==&fake_swapper_regs) {
++          current->thread.kregs =
++             ((struct pt_regs *)(THREAD_SIZE + (unsigned long) current) - 1);
++	  current->thread.uregs = current->thread.kregs;
++	}
++}
++
++void release_thread(struct task_struct *dead_task)
++{
++	/* do nothing */
++}
++
++/* Fill in the fpu structure for a core dump.. */
++int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu)
++{
++#ifdef CONFIG_SH_FPU
++	int fpvalid;
++	struct task_struct *tsk = current;
++
++	fpvalid = !!tsk_used_math(tsk);
++	if (fpvalid) {
++		if (current == last_task_used_math) {
++			enable_fpu();
++			save_fpu(tsk, regs);
++			disable_fpu();
++			last_task_used_math = 0;
++			regs->sr |= SR_FD;
++		}
++
++		memcpy(fpu, &tsk->thread.fpu.hard, sizeof(*fpu));
++	}
++
++	return fpvalid;
++#else
++	return 0; /* Task didn't use the fpu at all. */
++#endif
++}
++
++asmlinkage void ret_from_fork(void);
++
++int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
++		unsigned long unused,
++		struct task_struct *p, struct pt_regs *regs)
++{
++	struct pt_regs *childregs;
++	unsigned long long se;			/* Sign extension */
++
++#ifdef CONFIG_SH_FPU
++	if(last_task_used_math == current) {
++		enable_fpu();
++		save_fpu(current, regs);
++		disable_fpu();
++		last_task_used_math = NULL;
++		regs->sr |= SR_FD;
++	}
++#endif
++	/* Copy from sh version */
++	childregs = (struct pt_regs *)(THREAD_SIZE + task_stack_page(p)) - 1;
++
++	*childregs = *regs;
++
++	if (user_mode(regs)) {
++		childregs->regs[15] = usp;
++		p->thread.uregs = childregs;
++	} else {
++		childregs->regs[15] = (unsigned long)task_stack_page(p) + THREAD_SIZE;
++	}
++
++	childregs->regs[9] = 0; /* Set return value for child */
++	childregs->sr |= SR_FD; /* Invalidate FPU flag */
++
++	p->thread.sp = (unsigned long) childregs;
++	p->thread.pc = (unsigned long) ret_from_fork;
++
++	/*
++	 * Sign extend the edited stack.
++         * Note that thread.pc and thread.pc will stay
++	 * 32-bit wide and context switch must take care
++	 * of NEFF sign extension.
++	 */
++
++	se = childregs->regs[15];
++	se = (se & NEFF_SIGN) ? (se | NEFF_MASK) : se;
++	childregs->regs[15] = se;
++
++	return 0;
++}
++
++asmlinkage int sys_fork(unsigned long r2, unsigned long r3,
++			unsigned long r4, unsigned long r5,
++			unsigned long r6, unsigned long r7,
++			struct pt_regs *pregs)
++{
++	return do_fork(SIGCHLD, pregs->regs[15], pregs, 0, 0, 0);
++}
++
++asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp,
++			 unsigned long r4, unsigned long r5,
++			 unsigned long r6, unsigned long r7,
++			 struct pt_regs *pregs)
++{
++	if (!newsp)
++		newsp = pregs->regs[15];
++	return do_fork(clone_flags, newsp, pregs, 0, 0, 0);
++}
++
++/*
++ * This is trivial, and on the face of it looks like it
++ * could equally well be done in user mode.
++ *
++ * Not so, for quite unobvious reasons - register pressure.
++ * In user mode vfork() cannot have a stack frame, and if
++ * done by calling the "clone()" system call directly, you
++ * do not have enough call-clobbered registers to hold all
++ * the information you need.
++ */
++asmlinkage int sys_vfork(unsigned long r2, unsigned long r3,
++			 unsigned long r4, unsigned long r5,
++			 unsigned long r6, unsigned long r7,
++			 struct pt_regs *pregs)
++{
++	return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, pregs->regs[15], pregs, 0, 0, 0);
++}
++
++/*
++ * sys_execve() executes a new program.
++ */
++asmlinkage int sys_execve(char *ufilename, char **uargv,
++			  char **uenvp, unsigned long r5,
++			  unsigned long r6, unsigned long r7,
++			  struct pt_regs *pregs)
++{
++	int error;
++	char *filename;
++
++	lock_kernel();
++	filename = getname((char __user *)ufilename);
++	error = PTR_ERR(filename);
++	if (IS_ERR(filename))
++		goto out;
++
++	error = do_execve(filename,
++			  (char __user * __user *)uargv,
++			  (char __user * __user *)uenvp,
++			  pregs);
++	if (error == 0) {
++		task_lock(current);
++		current->ptrace &= ~PT_DTRACE;
++		task_unlock(current);
++	}
++	putname(filename);
++out:
++	unlock_kernel();
++	return error;
++}
++
++/*
++ * These bracket the sleeping functions..
++ */
++extern void interruptible_sleep_on(wait_queue_head_t *q);
++
++#define mid_sched	((unsigned long) interruptible_sleep_on)
++
++static int in_sh64_switch_to(unsigned long pc)
++{
++	extern char __sh64_switch_to_end;
++	/* For a sleeping task, the PC is somewhere in the middle of the function,
++	   so we don't have to worry about masking the LSB off */
++	return (pc >= (unsigned long) sh64_switch_to) &&
++	       (pc < (unsigned long) &__sh64_switch_to_end);
++}
++
++unsigned long get_wchan(struct task_struct *p)
++{
++	unsigned long schedule_fp;
++	unsigned long sh64_switch_to_fp;
++	unsigned long schedule_caller_pc;
++	unsigned long pc;
++
++	if (!p || p == current || p->state == TASK_RUNNING)
++		return 0;
++
++	/*
++	 * The same comment as on the Alpha applies here, too ...
++	 */
++	pc = thread_saved_pc(p);
++
++#ifdef CONFIG_FRAME_POINTER
++	if (in_sh64_switch_to(pc)) {
++		sh64_switch_to_fp = (long) p->thread.sp;
++		/* r14 is saved at offset 4 in the sh64_switch_to frame */
++		schedule_fp = *(unsigned long *) (long)(sh64_switch_to_fp + 4);
++
++		/* and the caller of 'schedule' is (currently!) saved at offset 24
++		   in the frame of schedule (from disasm) */
++		schedule_caller_pc = *(unsigned long *) (long)(schedule_fp + 24);
++		return schedule_caller_pc;
++	}
++#endif
++	return pc;
++}
++
++/* Provide a /proc/asids file that lists out the
++   ASIDs currently associated with the processes.  (If the DM.PC register is
++   examined through the debug link, this shows ASID + PC.  To make use of this,
++   the PID->ASID relationship needs to be known.  This is primarily for
++   debugging.)
++   */
++
++#if defined(CONFIG_SH64_PROC_ASIDS)
++static int
++asids_proc_info(char *buf, char **start, off_t fpos, int length, int *eof, void *data)
++{
++	int len=0;
++	struct task_struct *p;
++	read_lock(&tasklist_lock);
++	for_each_process(p) {
++		int pid = p->pid;
++
++		if (!pid)
++			continue;
++		if (p->mm)
++			len += sprintf(buf+len, "%5d : %02lx\n", pid,
++				       asid_cache(smp_processor_id()));
++		else
++			len += sprintf(buf+len, "%5d : (none)\n", pid);
++	}
++	read_unlock(&tasklist_lock);
++	*eof = 1;
++	return len;
++}
++
++static int __init register_proc_asids(void)
++{
++	create_proc_read_entry("asids", 0, NULL, asids_proc_info, NULL);
++	return 0;
++}
++__initcall(register_proc_asids);
++#endif
+diff --git a/arch/sh/kernel/ptrace.c b/arch/sh/kernel/ptrace.c
+deleted file mode 100644
+index ac725f0..0000000
+--- a/arch/sh/kernel/ptrace.c
++++ /dev/null
+@@ -1,274 +0,0 @@
+-/*
+- * linux/arch/sh/kernel/ptrace.c
+- *
+- * Original x86 implementation:
+- *	By Ross Biro 1/23/92
+- *	edited by Linus Torvalds
+- *
+- * SuperH version:   Copyright (C) 1999, 2000  Kaz Kojima & Niibe Yutaka
+- *
+- */
+-#include <linux/kernel.h>
+-#include <linux/sched.h>
+-#include <linux/mm.h>
+-#include <linux/smp.h>
+-#include <linux/errno.h>
+-#include <linux/ptrace.h>
+-#include <linux/user.h>
+-#include <linux/slab.h>
+-#include <linux/security.h>
+-#include <linux/signal.h>
+-#include <linux/io.h>
+-#include <asm/uaccess.h>
+-#include <asm/pgtable.h>
+-#include <asm/system.h>
+-#include <asm/processor.h>
+-#include <asm/mmu_context.h>
+-
+-/*
+- * does not yet catch signals sent when the child dies.
+- * in exit.c or in signal.c.
+- */
+-
+-/*
+- * This routine will get a word off of the process kernel stack.
+- */
+-static inline int get_stack_long(struct task_struct *task, int offset)
+-{
+-	unsigned char *stack;
+-
+-	stack = (unsigned char *)task_pt_regs(task);
+-	stack += offset;
+-	return (*((int *)stack));
+-}
+-
+-/*
+- * This routine will put a word on the process kernel stack.
+- */
+-static inline int put_stack_long(struct task_struct *task, int offset,
+-				 unsigned long data)
+-{
+-	unsigned char *stack;
+-
+-	stack = (unsigned char *)task_pt_regs(task);
+-	stack += offset;
+-	*(unsigned long *) stack = data;
+-	return 0;
+-}
+-
+-static void ptrace_disable_singlestep(struct task_struct *child)
+-{
+-	clear_tsk_thread_flag(child, TIF_SINGLESTEP);
+-
+-	/*
+-	 * Ensure the UBC is not programmed at the next context switch.
+-	 *
+-	 * Normally this is not needed but there are sequences such as
+-	 * singlestep, signal delivery, and continue that leave the
+-	 * ubc_pc non-zero leading to spurious SIGTRAPs.
+-	 */
+-	if (child->thread.ubc_pc != 0) {
+-		ubc_usercnt -= 1;
+-		child->thread.ubc_pc = 0;
+-	}
+-}
+-
+-/*
+- * Called by kernel/ptrace.c when detaching..
+- *
+- * Make sure single step bits etc are not set.
+- */
+-void ptrace_disable(struct task_struct *child)
+-{
+-	ptrace_disable_singlestep(child);
+-}
+-
+-long arch_ptrace(struct task_struct *child, long request, long addr, long data)
+-{
+-	struct user * dummy = NULL;
+-	int ret;
+-
+-	switch (request) {
+-	/* when I and D space are separate, these will need to be fixed. */
+-	case PTRACE_PEEKTEXT: /* read word at location addr. */
+-	case PTRACE_PEEKDATA:
+-		ret = generic_ptrace_peekdata(child, addr, data);
+-		break;
+-
+-	/* read the word at location addr in the USER area. */
+-	case PTRACE_PEEKUSR: {
+-		unsigned long tmp;
+-
+-		ret = -EIO;
+-		if ((addr & 3) || addr < 0 ||
+-		    addr > sizeof(struct user) - 3)
+-			break;
+-
+-		if (addr < sizeof(struct pt_regs))
+-			tmp = get_stack_long(child, addr);
+-		else if (addr >= (long) &dummy->fpu &&
+-			 addr < (long) &dummy->u_fpvalid) {
+-			if (!tsk_used_math(child)) {
+-				if (addr == (long)&dummy->fpu.fpscr)
+-					tmp = FPSCR_INIT;
+-				else
+-					tmp = 0;
+-			} else
+-				tmp = ((long *)&child->thread.fpu)
+-					[(addr - (long)&dummy->fpu) >> 2];
+-		} else if (addr == (long) &dummy->u_fpvalid)
+-			tmp = !!tsk_used_math(child);
+-		else
+-			tmp = 0;
+-		ret = put_user(tmp, (unsigned long __user *)data);
+-		break;
+-	}
+-
+-	/* when I and D space are separate, this will have to be fixed. */
+-	case PTRACE_POKETEXT: /* write the word at location addr. */
+-	case PTRACE_POKEDATA:
+-		ret = generic_ptrace_pokedata(child, addr, data);
+-		break;
+-
+-	case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
+-		ret = -EIO;
+-		if ((addr & 3) || addr < 0 ||
+-		    addr > sizeof(struct user) - 3)
+-			break;
+-
+-		if (addr < sizeof(struct pt_regs))
+-			ret = put_stack_long(child, addr, data);
+-		else if (addr >= (long) &dummy->fpu &&
+-			 addr < (long) &dummy->u_fpvalid) {
+-			set_stopped_child_used_math(child);
+-			((long *)&child->thread.fpu)
+-				[(addr - (long)&dummy->fpu) >> 2] = data;
+-			ret = 0;
+-		} else if (addr == (long) &dummy->u_fpvalid) {
+-			conditional_stopped_child_used_math(data, child);
+-			ret = 0;
+-		}
+-		break;
+-
+-	case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
+-	case PTRACE_CONT: { /* restart after signal. */
+-		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);
+-
+-		ptrace_disable_singlestep(child);
+-
+-		child->exit_code = data;
+-		wake_up_process(child);
+-		ret = 0;
+-		break;
+-	}
+-
+-/*
+- * make the child exit.  Best I can do is send it a sigkill.
+- * perhaps it should be put in the status that it wants to
+- * exit.
+- */
+-	case PTRACE_KILL: {
+-		ret = 0;
+-		if (child->exit_state == EXIT_ZOMBIE)	/* already dead */
+-			break;
+-		ptrace_disable_singlestep(child);
+-		child->exit_code = SIGKILL;
+-		wake_up_process(child);
+-		break;
+-	}
+-
+-	case PTRACE_SINGLESTEP: {  /* set the trap flag. */
+-		long pc;
+-		struct pt_regs *regs = NULL;
+-
+-		ret = -EIO;
+-		if (!valid_signal(data))
+-			break;
+-		clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+-		if ((child->ptrace & PT_DTRACE) == 0) {
+-			/* Spurious delayed TF traps may occur */
+-			child->ptrace |= PT_DTRACE;
+-		}
+-
+-		pc = get_stack_long(child, (long)&regs->pc);
+-
+-		/* Next scheduling will set up UBC */
+-		if (child->thread.ubc_pc == 0)
+-			ubc_usercnt += 1;
+-		child->thread.ubc_pc = pc;
+-
+-		set_tsk_thread_flag(child, TIF_SINGLESTEP);
+-		child->exit_code = data;
+-		/* give it a chance to run. */
+-		wake_up_process(child);
+-		ret = 0;
+-		break;
+-	}
+-
+-#ifdef CONFIG_SH_DSP
+-	case PTRACE_GETDSPREGS: {
+-		unsigned long dp;
+-
+-		ret = -EIO;
+-		dp = ((unsigned long) child) + THREAD_SIZE -
+-			 sizeof(struct pt_dspregs);
+-		if (*((int *) (dp - 4)) == SR_FD) {
+-			copy_to_user(addr, (void *) dp,
+-				sizeof(struct pt_dspregs));
+-			ret = 0;
+-		}
+-		break;
+-	}
+-
+-	case PTRACE_SETDSPREGS: {
+-		unsigned long dp;
+-
+-		ret = -EIO;
+-		dp = ((unsigned long) child) + THREAD_SIZE -
+-			 sizeof(struct pt_dspregs);
+-		if (*((int *) (dp - 4)) == SR_FD) {
+-			copy_from_user((void *) dp, addr,
+-				sizeof(struct pt_dspregs));
+-			ret = 0;
+-		}
+-		break;
+-	}
+-#endif
+-	default:
+-		ret = ptrace_request(child, request, addr, data);
+-		break;
+-	}
+-
+-	return ret;
+-}
+-
+-asmlinkage void do_syscall_trace(void)
+-{
+-	struct task_struct *tsk = current;
+-
+-	if (!test_thread_flag(TIF_SYSCALL_TRACE) &&
+-	    !test_thread_flag(TIF_SINGLESTEP))
+-		return;
+-	if (!(tsk->ptrace & PT_PTRACED))
+-		return;
+-	/* the 0x80 provides a way for the tracing parent to distinguish
+-	   between a syscall stop and SIGTRAP delivery */
+-	ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) &&
+-				 !test_thread_flag(TIF_SINGLESTEP) ? 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 (tsk->exit_code) {
+-		send_sig(tsk->exit_code, tsk, 1);
+-		tsk->exit_code = 0;
+-	}
+-}
+diff --git a/arch/sh/kernel/ptrace_32.c b/arch/sh/kernel/ptrace_32.c
+new file mode 100644
+index 0000000..ce0664a
+--- /dev/null
++++ b/arch/sh/kernel/ptrace_32.c
+@@ -0,0 +1,287 @@
++/*
++ * linux/arch/sh/kernel/ptrace.c
++ *
++ * Original x86 implementation:
++ *	By Ross Biro 1/23/92
++ *	edited by Linus Torvalds
++ *
++ * SuperH version:   Copyright (C) 1999, 2000  Kaz Kojima & Niibe Yutaka
++ * Audit support: Yuichi Nakamura <ynakam at hitachisoft.jp>
++ */
++#include <linux/kernel.h>
++#include <linux/sched.h>
++#include <linux/mm.h>
++#include <linux/smp.h>
++#include <linux/errno.h>
++#include <linux/ptrace.h>
++#include <linux/user.h>
++#include <linux/slab.h>
++#include <linux/security.h>
++#include <linux/signal.h>
++#include <linux/io.h>
++#include <linux/audit.h>
++#include <asm/uaccess.h>
++#include <asm/pgtable.h>
++#include <asm/system.h>
++#include <asm/processor.h>
++#include <asm/mmu_context.h>
++
++/*
++ * does not yet catch signals sent when the child dies.
++ * in exit.c or in signal.c.
++ */
++
++/*
++ * This routine will get a word off of the process kernel stack.
++ */
++static inline int get_stack_long(struct task_struct *task, int offset)
++{
++	unsigned char *stack;
++
++	stack = (unsigned char *)task_pt_regs(task);
++	stack += offset;
++	return (*((int *)stack));
++}
++
++/*
++ * This routine will put a word on the process kernel stack.
++ */
++static inline int put_stack_long(struct task_struct *task, int offset,
++				 unsigned long data)
++{
++	unsigned char *stack;
++
++	stack = (unsigned char *)task_pt_regs(task);
++	stack += offset;
++	*(unsigned long *) stack = data;
++	return 0;
++}
++
++static void ptrace_disable_singlestep(struct task_struct *child)
++{
++	clear_tsk_thread_flag(child, TIF_SINGLESTEP);
++
++	/*
++	 * Ensure the UBC is not programmed at the next context switch.
++	 *
++	 * Normally this is not needed but there are sequences such as
++	 * singlestep, signal delivery, and continue that leave the
++	 * ubc_pc non-zero leading to spurious SIGTRAPs.
++	 */
++	if (child->thread.ubc_pc != 0) {
++		ubc_usercnt -= 1;
++		child->thread.ubc_pc = 0;
++	}
++}
++
++/*
++ * Called by kernel/ptrace.c when detaching..
++ *
++ * Make sure single step bits etc are not set.
++ */
++void ptrace_disable(struct task_struct *child)
++{
++	ptrace_disable_singlestep(child);
++}
++
++long arch_ptrace(struct task_struct *child, long request, long addr, long data)
++{
++	struct user * dummy = NULL;
++	int ret;
++
++	switch (request) {
++	/* when I and D space are separate, these will need to be fixed. */
++	case PTRACE_PEEKTEXT: /* read word at location addr. */
++	case PTRACE_PEEKDATA:
++		ret = generic_ptrace_peekdata(child, addr, data);
++		break;
++
++	/* read the word at location addr in the USER area. */
++	case PTRACE_PEEKUSR: {
++		unsigned long tmp;
++
++		ret = -EIO;
++		if ((addr & 3) || addr < 0 ||
++		    addr > sizeof(struct user) - 3)
++			break;
++
++		if (addr < sizeof(struct pt_regs))
++			tmp = get_stack_long(child, addr);
++		else if (addr >= (long) &dummy->fpu &&
++			 addr < (long) &dummy->u_fpvalid) {
++			if (!tsk_used_math(child)) {
++				if (addr == (long)&dummy->fpu.fpscr)
++					tmp = FPSCR_INIT;
++				else
++					tmp = 0;
++			} else
++				tmp = ((long *)&child->thread.fpu)
++					[(addr - (long)&dummy->fpu) >> 2];
++		} else if (addr == (long) &dummy->u_fpvalid)
++			tmp = !!tsk_used_math(child);
++		else
++			tmp = 0;
++		ret = put_user(tmp, (unsigned long __user *)data);
++		break;
++	}
++
++	/* when I and D space are separate, this will have to be fixed. */
++	case PTRACE_POKETEXT: /* write the word at location addr. */
++	case PTRACE_POKEDATA:
++		ret = generic_ptrace_pokedata(child, addr, data);
++		break;
++
++	case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
++		ret = -EIO;
++		if ((addr & 3) || addr < 0 ||
++		    addr > sizeof(struct user) - 3)
++			break;
++
++		if (addr < sizeof(struct pt_regs))
++			ret = put_stack_long(child, addr, data);
++		else if (addr >= (long) &dummy->fpu &&
++			 addr < (long) &dummy->u_fpvalid) {
++			set_stopped_child_used_math(child);
++			((long *)&child->thread.fpu)
++				[(addr - (long)&dummy->fpu) >> 2] = data;
++			ret = 0;
++		} else if (addr == (long) &dummy->u_fpvalid) {
++			conditional_stopped_child_used_math(data, child);
++			ret = 0;
++		}
++		break;
++
++	case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
++	case PTRACE_CONT: { /* restart after signal. */
++		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);
++
++		ptrace_disable_singlestep(child);
++
++		child->exit_code = data;
++		wake_up_process(child);
++		ret = 0;
++		break;
++	}
++
++/*
++ * make the child exit.  Best I can do is send it a sigkill.
++ * perhaps it should be put in the status that it wants to
++ * exit.
++ */
++	case PTRACE_KILL: {
++		ret = 0;
++		if (child->exit_state == EXIT_ZOMBIE)	/* already dead */
++			break;
++		ptrace_disable_singlestep(child);
++		child->exit_code = SIGKILL;
++		wake_up_process(child);
++		break;
++	}
++
++	case PTRACE_SINGLESTEP: {  /* set the trap flag. */
++		long pc;
++		struct pt_regs *regs = NULL;
++
++		ret = -EIO;
++		if (!valid_signal(data))
++			break;
++		clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
++		if ((child->ptrace & PT_DTRACE) == 0) {
++			/* Spurious delayed TF traps may occur */
++			child->ptrace |= PT_DTRACE;
++		}
++
++		pc = get_stack_long(child, (long)&regs->pc);
++
++		/* Next scheduling will set up UBC */
++		if (child->thread.ubc_pc == 0)
++			ubc_usercnt += 1;
++		child->thread.ubc_pc = pc;
++
++		set_tsk_thread_flag(child, TIF_SINGLESTEP);
++		child->exit_code = data;
++		/* give it a chance to run. */
++		wake_up_process(child);
++		ret = 0;
++		break;
++	}
++
++#ifdef CONFIG_SH_DSP
++	case PTRACE_GETDSPREGS: {
++		unsigned long dp;
++
++		ret = -EIO;
++		dp = ((unsigned long) child) + THREAD_SIZE -
++			 sizeof(struct pt_dspregs);
++		if (*((int *) (dp - 4)) == SR_FD) {
++			copy_to_user(addr, (void *) dp,
++				sizeof(struct pt_dspregs));
++			ret = 0;
++		}
++		break;
++	}
++
++	case PTRACE_SETDSPREGS: {
++		unsigned long dp;
++
++		ret = -EIO;
++		dp = ((unsigned long) child) + THREAD_SIZE -
++			 sizeof(struct pt_dspregs);
++		if (*((int *) (dp - 4)) == SR_FD) {
++			copy_from_user((void *) dp, addr,
++				sizeof(struct pt_dspregs));
++			ret = 0;
++		}
++		break;
++	}
++#endif
++	default:
++		ret = ptrace_request(child, request, addr, data);
++		break;
++	}
++
++	return ret;
++}
++
++asmlinkage void do_syscall_trace(struct pt_regs *regs, int entryexit)
++{
++	struct task_struct *tsk = current;
++
++	if (unlikely(current->audit_context) && entryexit)
++		audit_syscall_exit(AUDITSC_RESULT(regs->regs[0]),
++				   regs->regs[0]);
++
++	if (!test_thread_flag(TIF_SYSCALL_TRACE) &&
++	    !test_thread_flag(TIF_SINGLESTEP))
++		goto out;
++	if (!(tsk->ptrace & PT_PTRACED))
++		goto out;
++
++	/* the 0x80 provides a way for the tracing parent to distinguish
++	   between a syscall stop and SIGTRAP delivery */
++	ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) &&
++				 !test_thread_flag(TIF_SINGLESTEP) ? 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 (tsk->exit_code) {
++		send_sig(tsk->exit_code, tsk, 1);
++		tsk->exit_code = 0;
++	}
++
++out:
++	if (unlikely(current->audit_context) && !entryexit)
++		audit_syscall_entry(AUDIT_ARCH_SH, regs->regs[3],
++				    regs->regs[4], regs->regs[5],
++				    regs->regs[6], regs->regs[7]);
++
++}
+diff --git a/arch/sh/kernel/ptrace_64.c b/arch/sh/kernel/ptrace_64.c
+new file mode 100644
+index 0000000..f6fbdfa
+--- /dev/null
++++ b/arch/sh/kernel/ptrace_64.c
+@@ -0,0 +1,341 @@
++/*
++ * arch/sh/kernel/ptrace_64.c
++ *
++ * Copyright (C) 2000, 2001  Paolo Alberelli
++ * Copyright (C) 2003 - 2007  Paul Mundt
++ *
++ * Started from SH3/4 version:
++ *   SuperH version:   Copyright (C) 1999, 2000  Kaz Kojima & Niibe Yutaka
++ *
++ *   Original x86 implementation:
++ *	By Ross Biro 1/23/92
++ *	edited by Linus Torvalds
++ *
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License.  See the file "COPYING" in the main directory of this archive
++ * for more details.
++ */
++#include <linux/kernel.h>
++#include <linux/rwsem.h>
++#include <linux/sched.h>
++#include <linux/mm.h>
++#include <linux/smp.h>
++#include <linux/smp_lock.h>
++#include <linux/errno.h>
++#include <linux/ptrace.h>
++#include <linux/user.h>
++#include <linux/signal.h>
++#include <linux/syscalls.h>
++#include <linux/audit.h>
++#include <asm/io.h>
++#include <asm/uaccess.h>
++#include <asm/pgtable.h>
++#include <asm/system.h>
++#include <asm/processor.h>
++#include <asm/mmu_context.h>
++
++/* This mask defines the bits of the SR which the user is not allowed to
++   change, which are everything except S, Q, M, PR, SZ, FR. */
++#define SR_MASK      (0xffff8cfd)
++
++/*
++ * does not yet catch signals sent when the child dies.
++ * in exit.c or in signal.c.
++ */
++
++/*
++ * This routine will get a word from the user area in the process kernel stack.
++ */
++static inline int get_stack_long(struct task_struct *task, int offset)
++{
++	unsigned char *stack;
++
++	stack = (unsigned char *)(task->thread.uregs);
++	stack += offset;
++	return (*((int *)stack));
++}
++
++static inline unsigned long
++get_fpu_long(struct task_struct *task, unsigned long addr)
++{
++	unsigned long tmp;
++	struct pt_regs *regs;
++	regs = (struct pt_regs*)((unsigned char *)task + THREAD_SIZE) - 1;
++
++	if (!tsk_used_math(task)) {
++		if (addr == offsetof(struct user_fpu_struct, fpscr)) {
++			tmp = FPSCR_INIT;
++		} else {
++			tmp = 0xffffffffUL; /* matches initial value in fpu.c */
++		}
++		return tmp;
++	}
++
++	if (last_task_used_math == task) {
++		enable_fpu();
++		save_fpu(task, regs);
++		disable_fpu();
++		last_task_used_math = 0;
++		regs->sr |= SR_FD;
++	}
++
++	tmp = ((long *)&task->thread.fpu)[addr / sizeof(unsigned long)];
++	return tmp;
++}
++
++/*
++ * This routine will put a word into the user area in the process kernel stack.
++ */
++static inline int put_stack_long(struct task_struct *task, int offset,
++				 unsigned long data)
++{
++	unsigned char *stack;
++
++	stack = (unsigned char *)(task->thread.uregs);
++	stack += offset;
++	*(unsigned long *) stack = data;
++	return 0;
++}
++
++static inline int
++put_fpu_long(struct task_struct *task, unsigned long addr, unsigned long data)
++{
++	struct pt_regs *regs;
++
++	regs = (struct pt_regs*)((unsigned char *)task + THREAD_SIZE) - 1;
++
++	if (!tsk_used_math(task)) {
++		fpinit(&task->thread.fpu.hard);
++		set_stopped_child_used_math(task);
++	} else if (last_task_used_math == task) {
++		enable_fpu();
++		save_fpu(task, regs);
++		disable_fpu();
++		last_task_used_math = 0;
++		regs->sr |= SR_FD;
++	}
++
++	((long *)&task->thread.fpu)[addr / sizeof(unsigned long)] = data;
++	return 0;
++}
++
++
++long arch_ptrace(struct task_struct *child, long request, long addr, long data)
++{
++	int ret;
++
++	switch (request) {
++	/* when I and D space are separate, these will need to be fixed. */
++	case PTRACE_PEEKTEXT: /* read word at location addr. */
++	case PTRACE_PEEKDATA:
++		ret = generic_ptrace_peekdata(child, addr, data);
++		break;
++
++	/* read the word at location addr in the USER area. */
++	case PTRACE_PEEKUSR: {
++		unsigned long tmp;
++
++		ret = -EIO;
++		if ((addr & 3) || addr < 0)
++			break;
++
++		if (addr < sizeof(struct pt_regs))
++			tmp = get_stack_long(child, addr);
++		else if ((addr >= offsetof(struct user, fpu)) &&
++			 (addr <  offsetof(struct user, u_fpvalid))) {
++			tmp = get_fpu_long(child, addr - offsetof(struct user, fpu));
++		} else if (addr == offsetof(struct user, u_fpvalid)) {
++			tmp = !!tsk_used_math(child);
++		} else {
++			break;
++		}
++		ret = put_user(tmp, (unsigned long *)data);
++		break;
++	}
++
++	/* when I and D space are separate, this will have to be fixed. */
++	case PTRACE_POKETEXT: /* write the word at location addr. */
++	case PTRACE_POKEDATA:
++		ret = generic_ptrace_pokedata(child, addr, data);
++		break;
++
++	case PTRACE_POKEUSR:
++                /* write the word at location addr in the USER area. We must
++                   disallow any changes to certain SR bits or u_fpvalid, since
++                   this could crash the kernel or result in a security
++                   loophole. */
++		ret = -EIO;
++		if ((addr & 3) || addr < 0)
++			break;
++
++		if (addr < sizeof(struct pt_regs)) {
++			/* Ignore change of top 32 bits of SR */
++			if (addr == offsetof (struct pt_regs, sr)+4)
++			{
++				ret = 0;
++				break;
++			}
++			/* If lower 32 bits of SR, ignore non-user bits */
++			if (addr == offsetof (struct pt_regs, sr))
++			{
++				long cursr = get_stack_long(child, addr);
++				data &= ~(SR_MASK);
++				data |= (cursr & SR_MASK);
++			}
++			ret = put_stack_long(child, addr, data);
++		}
++		else if ((addr >= offsetof(struct user, fpu)) &&
++			 (addr <  offsetof(struct user, u_fpvalid))) {
++			ret = put_fpu_long(child, addr - offsetof(struct user, fpu), data);
++		}
++		break;
++
++	case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
++	case PTRACE_CONT: { /* restart after signal. */
++		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;
++		wake_up_process(child);
++		ret = 0;
++		break;
++	}
++
++/*
++ * make the child exit.  Best I can do is send it a sigkill.
++ * perhaps it should be put in the status that it wants to
++ * exit.
++ */
++	case PTRACE_KILL: {
++		ret = 0;
++		if (child->exit_state == EXIT_ZOMBIE)	/* already dead */
++			break;
++		child->exit_code = SIGKILL;
++		wake_up_process(child);
++		break;
++	}
++
++	case PTRACE_SINGLESTEP: {  /* set the trap flag. */
++		struct pt_regs *regs;
++
++		ret = -EIO;
++		if (!valid_signal(data))
++			break;
++		clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
++		if ((child->ptrace & PT_DTRACE) == 0) {
++			/* Spurious delayed TF traps may occur */
++			child->ptrace |= PT_DTRACE;
++		}
++
++		regs = child->thread.uregs;
++
++		regs->sr |= SR_SSTEP;	/* auto-resetting upon exception */
++
++		child->exit_code = data;
++		/* give it a chance to run. */
++		wake_up_process(child);
++		ret = 0;
++		break;
++	}
++
++	default:
++		ret = ptrace_request(child, request, addr, data);
++		break;
++	}
++	return ret;
++}
++
++asmlinkage int sh64_ptrace(long request, long pid, long addr, long data)
++{
++#define WPC_DBRMODE 0x0d104008
++	static int first_call = 1;
++
++	lock_kernel();
++	if (first_call) {
++		/* Set WPC.DBRMODE to 0.  This makes all debug events get
++		 * delivered through RESVEC, i.e. into the handlers in entry.S.
++		 * (If the kernel was downloaded using a remote gdb, WPC.DBRMODE
++		 * would normally be left set to 1, which makes debug events get
++		 * delivered through DBRVEC, i.e. into the remote gdb's
++		 * handlers.  This prevents ptrace getting them, and confuses
++		 * the remote gdb.) */
++		printk("DBRMODE set to 0 to permit native debugging\n");
++		poke_real_address_q(WPC_DBRMODE, 0);
++		first_call = 0;
++	}
++	unlock_kernel();
++
++	return sys_ptrace(request, pid, addr, data);
++}
++
++asmlinkage void syscall_trace(struct pt_regs *regs, int entryexit)
++{
++	struct task_struct *tsk = current;
++
++	if (unlikely(current->audit_context) && entryexit)
++		audit_syscall_exit(AUDITSC_RESULT(regs->regs[9]),
++				   regs->regs[9]);
++
++	if (!test_thread_flag(TIF_SYSCALL_TRACE) &&
++	    !test_thread_flag(TIF_SINGLESTEP))
++		goto out;
++	if (!(tsk->ptrace & PT_PTRACED))
++		goto out;
++
++	ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) &&
++				!test_thread_flag(TIF_SINGLESTEP) ? 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 (tsk->exit_code) {
++		send_sig(tsk->exit_code, tsk, 1);
++		tsk->exit_code = 0;
++	}
++
++out:
++	if (unlikely(current->audit_context) && !entryexit)
++		audit_syscall_entry(AUDIT_ARCH_SH, regs->regs[1],
++				    regs->regs[2], regs->regs[3],
++				    regs->regs[4], regs->regs[5]);
++}
++
++/* Called with interrupts disabled */
++asmlinkage void do_single_step(unsigned long long vec, struct pt_regs *regs)
++{
++	/* This is called after a single step exception (DEBUGSS).
++	   There is no need to change the PC, as it is a post-execution
++	   exception, as entry.S does not do anything to the PC for DEBUGSS.
++	   We need to clear the Single Step setting in SR to avoid
++	   continually stepping. */
++	local_irq_enable();
++	regs->sr &= ~SR_SSTEP;
++	force_sig(SIGTRAP, current);
++}
++
++/* Called with interrupts disabled */
++asmlinkage void do_software_break_point(unsigned long long vec,
++					struct pt_regs *regs)
++{
++	/* We need to forward step the PC, to counteract the backstep done
++	   in signal.c. */
++	local_irq_enable();
++	force_sig(SIGTRAP, current);
++	regs->pc += 4;
++}
++
++/*
++ * Called by kernel/ptrace.c when detaching..
++ *
++ * Make sure single step bits etc are not set.
++ */
++void ptrace_disable(struct task_struct *child)
++{
++        /* nothing to do.. */
++}
+diff --git a/arch/sh/kernel/setup.c b/arch/sh/kernel/setup.c
+index 4156aac..855cdf9 100644
+--- a/arch/sh/kernel/setup.c
++++ b/arch/sh/kernel/setup.c
+@@ -26,6 +26,7 @@
+ #include <asm/uaccess.h>
+ #include <asm/io.h>
+ #include <asm/page.h>
++#include <asm/elf.h>
+ #include <asm/sections.h>
+ #include <asm/irq.h>
+ #include <asm/setup.h>
+@@ -78,12 +79,25 @@ EXPORT_SYMBOL(memory_start);
+ unsigned long memory_end = 0;
+ EXPORT_SYMBOL(memory_end);
+ 
++int l1i_cache_shape, l1d_cache_shape, l2_cache_shape;
++
+ static int __init early_parse_mem(char *p)
+ {
+ 	unsigned long size;
+ 
+-	memory_start = (unsigned long)PAGE_OFFSET+__MEMORY_START;
++	memory_start = (unsigned long)__va(__MEMORY_START);
+ 	size = memparse(p, &p);
++
++	if (size > __MEMORY_SIZE) {
++		static char msg[] __initdata = KERN_ERR
++			"Using mem= to increase the size of kernel memory "
++			"is not allowed.\n"
++			"  Recompile the kernel with the correct value for "
++			"CONFIG_MEMORY_SIZE.\n";
++		printk(msg);
++		return 0;
++	}
++
+ 	memory_end = memory_start + size;
+ 
+ 	return 0;
+@@ -243,7 +257,7 @@ void __init setup_arch(char **cmdline_p)
+ 	data_resource.start = virt_to_phys(_etext);
+ 	data_resource.end = virt_to_phys(_edata)-1;
+ 
+-	memory_start = (unsigned long)PAGE_OFFSET+__MEMORY_START;
++	memory_start = (unsigned long)__va(__MEMORY_START);
+ 	if (!memory_end)
+ 		memory_end = memory_start + __MEMORY_SIZE;
+ 
+@@ -294,20 +308,23 @@ void __init setup_arch(char **cmdline_p)
+ }
+ 
+ static const char *cpu_name[] = {
++	[CPU_SH7203]	= "SH7203",	[CPU_SH7263]	= "SH7263",
+ 	[CPU_SH7206]	= "SH7206",	[CPU_SH7619]	= "SH7619",
+ 	[CPU_SH7705]	= "SH7705",	[CPU_SH7706]	= "SH7706",
+ 	[CPU_SH7707]	= "SH7707",	[CPU_SH7708]	= "SH7708",
+ 	[CPU_SH7709]	= "SH7709",	[CPU_SH7710]	= "SH7710",
+ 	[CPU_SH7712]	= "SH7712",	[CPU_SH7720]	= "SH7720",
+-	[CPU_SH7729]	= "SH7729",	[CPU_SH7750]	= "SH7750",
+-	[CPU_SH7750S]	= "SH7750S",	[CPU_SH7750R]	= "SH7750R",
+-	[CPU_SH7751]	= "SH7751",	[CPU_SH7751R]	= "SH7751R",
+-	[CPU_SH7760]	= "SH7760",
++	[CPU_SH7721]	= "SH7721",	[CPU_SH7729]	= "SH7729",
++	[CPU_SH7750]	= "SH7750",	[CPU_SH7750S]	= "SH7750S",
++	[CPU_SH7750R]	= "SH7750R",	[CPU_SH7751]	= "SH7751",
++	[CPU_SH7751R]	= "SH7751R",	[CPU_SH7760]	= "SH7760",
+ 	[CPU_SH4_202]	= "SH4-202",	[CPU_SH4_501]	= "SH4-501",
+-	[CPU_SH7770]	= "SH7770",	[CPU_SH7780]	= "SH7780",
+-	[CPU_SH7781]	= "SH7781",	[CPU_SH7343]	= "SH7343",
+-	[CPU_SH7785]	= "SH7785",	[CPU_SH7722]	= "SH7722",
+-	[CPU_SHX3]	= "SH-X3",	[CPU_SH_NONE]	= "Unknown"
++	[CPU_SH7763]	= "SH7763",	[CPU_SH7770]	= "SH7770",
++	[CPU_SH7780]	= "SH7780",	[CPU_SH7781]	= "SH7781",
++	[CPU_SH7343]	= "SH7343",	[CPU_SH7785]	= "SH7785",
++	[CPU_SH7722]	= "SH7722",	[CPU_SHX3]	= "SH-X3",
++	[CPU_SH5_101]	= "SH5-101",	[CPU_SH5_103]	= "SH5-103",
++	[CPU_SH_NONE]	= "Unknown"
+ };
+ 
+ const char *get_cpu_subtype(struct sh_cpuinfo *c)
+@@ -410,7 +427,7 @@ static void *c_next(struct seq_file *m, void *v, loff_t *pos)
+ static void c_stop(struct seq_file *m, void *v)
+ {
+ }
+-struct seq_operations cpuinfo_op = {
++const struct seq_operations cpuinfo_op = {
+ 	.start	= c_start,
+ 	.next	= c_next,
+ 	.stop	= c_stop,
+diff --git a/arch/sh/kernel/sh_ksyms.c b/arch/sh/kernel/sh_ksyms.c
+deleted file mode 100644
+index e1a6de9..0000000
+--- a/arch/sh/kernel/sh_ksyms.c
++++ /dev/null
+@@ -1,150 +0,0 @@
+-#include <linux/module.h>
+-#include <linux/smp.h>
+-#include <linux/user.h>
+-#include <linux/elfcore.h>
+-#include <linux/sched.h>
+-#include <linux/in6.h>
+-#include <linux/interrupt.h>
+-#include <linux/vmalloc.h>
+-#include <linux/pci.h>
+-#include <linux/irq.h>
+-#include <asm/sections.h>
+-#include <asm/semaphore.h>
+-#include <asm/processor.h>
+-#include <asm/uaccess.h>
+-#include <asm/checksum.h>
+-#include <asm/io.h>
+-#include <asm/delay.h>
+-#include <asm/tlbflush.h>
+-#include <asm/cacheflush.h>
+-
+-extern int dump_fpu(struct pt_regs *, elf_fpregset_t *);
+-extern struct hw_interrupt_type no_irq_type;
+-
+-EXPORT_SYMBOL(sh_mv);
+-
+-/* platform dependent support */
+-EXPORT_SYMBOL(dump_fpu);
+-EXPORT_SYMBOL(kernel_thread);
+-EXPORT_SYMBOL(irq_desc);
+-EXPORT_SYMBOL(no_irq_type);
+-
+-EXPORT_SYMBOL(strlen);
+-
+-/* PCI exports */
+-#ifdef CONFIG_PCI
+-EXPORT_SYMBOL(pci_alloc_consistent);
+-EXPORT_SYMBOL(pci_free_consistent);
+-#endif
+-
+-/* mem exports */
+-EXPORT_SYMBOL(memchr);
+-EXPORT_SYMBOL(memcpy);
+-EXPORT_SYMBOL(memset);
+-EXPORT_SYMBOL(memmove);
+-EXPORT_SYMBOL(__copy_user);
+-
+-#ifdef CONFIG_MMU
+-EXPORT_SYMBOL(get_vm_area);
+-#endif
+-
+-/* semaphore exports */
+-EXPORT_SYMBOL(__up);
+-EXPORT_SYMBOL(__down);
+-EXPORT_SYMBOL(__down_interruptible);
+-EXPORT_SYMBOL(__down_trylock);
+-
+-EXPORT_SYMBOL(__udelay);
+-EXPORT_SYMBOL(__ndelay);
+-EXPORT_SYMBOL(__const_udelay);
+-
+-#define DECLARE_EXPORT(name) extern void name(void);EXPORT_SYMBOL(name)
+-
+-/* These symbols are generated by the compiler itself */
+-DECLARE_EXPORT(__udivsi3);
+-DECLARE_EXPORT(__sdivsi3);
+-DECLARE_EXPORT(__ashrsi3);
+-DECLARE_EXPORT(__ashlsi3);
+-DECLARE_EXPORT(__ashrdi3);
+-DECLARE_EXPORT(__ashldi3);
+-DECLARE_EXPORT(__ashiftrt_r4_6);
+-DECLARE_EXPORT(__ashiftrt_r4_7);
+-DECLARE_EXPORT(__ashiftrt_r4_8);
+-DECLARE_EXPORT(__ashiftrt_r4_9);
+-DECLARE_EXPORT(__ashiftrt_r4_10);
+-DECLARE_EXPORT(__ashiftrt_r4_11);
+-DECLARE_EXPORT(__ashiftrt_r4_12);
+-DECLARE_EXPORT(__ashiftrt_r4_13);
+-DECLARE_EXPORT(__ashiftrt_r4_14);
+-DECLARE_EXPORT(__ashiftrt_r4_15);
+-DECLARE_EXPORT(__ashiftrt_r4_20);
+-DECLARE_EXPORT(__ashiftrt_r4_21);
+-DECLARE_EXPORT(__ashiftrt_r4_22);
+-DECLARE_EXPORT(__ashiftrt_r4_23);
+-DECLARE_EXPORT(__ashiftrt_r4_24);
+-DECLARE_EXPORT(__ashiftrt_r4_27);
+-DECLARE_EXPORT(__ashiftrt_r4_30);
+-DECLARE_EXPORT(__lshrsi3);
+-DECLARE_EXPORT(__lshrdi3);
+-DECLARE_EXPORT(__movstrSI8);
+-DECLARE_EXPORT(__movstrSI12);
+-DECLARE_EXPORT(__movstrSI16);
+-DECLARE_EXPORT(__movstrSI20);
+-DECLARE_EXPORT(__movstrSI24);
+-DECLARE_EXPORT(__movstrSI28);
+-DECLARE_EXPORT(__movstrSI32);
+-DECLARE_EXPORT(__movstrSI36);
+-DECLARE_EXPORT(__movstrSI40);
+-DECLARE_EXPORT(__movstrSI44);
+-DECLARE_EXPORT(__movstrSI48);
+-DECLARE_EXPORT(__movstrSI52);
+-DECLARE_EXPORT(__movstrSI56);
+-DECLARE_EXPORT(__movstrSI60);
+-#if __GNUC__ == 4
+-DECLARE_EXPORT(__movmem);
+-#else
+-DECLARE_EXPORT(__movstr);
+-#endif
+-
+-#if __GNUC__ == 4
+-DECLARE_EXPORT(__movmem_i4_even);
+-DECLARE_EXPORT(__movmem_i4_odd);
+-DECLARE_EXPORT(__movmemSI12_i4);
+-
+-#if (__GNUC_MINOR__ == 2 || defined(__GNUC_STM_RELEASE__))
+-/*
+- * GCC 4.2 emits these for division, as do GCC 4.1.x versions of the ST
+- * compiler which include backported patches.
+- */
+-DECLARE_EXPORT(__sdivsi3_i4i);
+-DECLARE_EXPORT(__udiv_qrnnd_16);
+-DECLARE_EXPORT(__udivsi3_i4i);
+-#endif
+-#else /* GCC 3.x */
+-DECLARE_EXPORT(__movstr_i4_even);
+-DECLARE_EXPORT(__movstr_i4_odd);
+-DECLARE_EXPORT(__movstrSI12_i4);
+-#endif /* __GNUC__ == 4 */
+-
+-#if !defined(CONFIG_CACHE_OFF) && (defined(CONFIG_CPU_SH4) || \
+-	defined(CONFIG_SH7705_CACHE_32KB))
+-/* needed by some modules */
+-EXPORT_SYMBOL(flush_cache_all);
+-EXPORT_SYMBOL(flush_cache_range);
+-EXPORT_SYMBOL(flush_dcache_page);
+-EXPORT_SYMBOL(__flush_purge_region);
+-#endif
+-
+-#if !defined(CONFIG_CACHE_OFF) && defined(CONFIG_MMU) && \
+-	(defined(CONFIG_CPU_SH4) || defined(CONFIG_SH7705_CACHE_32KB))
+-EXPORT_SYMBOL(clear_user_page);
+-#endif
+-
+-EXPORT_SYMBOL(csum_partial);
+-EXPORT_SYMBOL(csum_partial_copy_generic);
+-#ifdef CONFIG_IPV6
+-EXPORT_SYMBOL(csum_ipv6_magic);
+-#endif
+-EXPORT_SYMBOL(clear_page);
+-EXPORT_SYMBOL(__clear_user);
+-EXPORT_SYMBOL(_ebss);
+diff --git a/arch/sh/kernel/sh_ksyms_32.c b/arch/sh/kernel/sh_ksyms_32.c
+new file mode 100644
+index 0000000..e1a6de9
+--- /dev/null
++++ b/arch/sh/kernel/sh_ksyms_32.c
+@@ -0,0 +1,150 @@
++#include <linux/module.h>
++#include <linux/smp.h>
++#include <linux/user.h>
++#include <linux/elfcore.h>
++#include <linux/sched.h>
++#include <linux/in6.h>
++#include <linux/interrupt.h>
++#include <linux/vmalloc.h>
++#include <linux/pci.h>
++#include <linux/irq.h>
++#include <asm/sections.h>
++#include <asm/semaphore.h>
++#include <asm/processor.h>
++#include <asm/uaccess.h>
++#include <asm/checksum.h>
++#include <asm/io.h>
++#include <asm/delay.h>
++#include <asm/tlbflush.h>
++#include <asm/cacheflush.h>
++
++extern int dump_fpu(struct pt_regs *, elf_fpregset_t *);
++extern struct hw_interrupt_type no_irq_type;
++
++EXPORT_SYMBOL(sh_mv);
++
++/* platform dependent support */
++EXPORT_SYMBOL(dump_fpu);
++EXPORT_SYMBOL(kernel_thread);
++EXPORT_SYMBOL(irq_desc);
++EXPORT_SYMBOL(no_irq_type);
++
++EXPORT_SYMBOL(strlen);
++
++/* PCI exports */
++#ifdef CONFIG_PCI
++EXPORT_SYMBOL(pci_alloc_consistent);
++EXPORT_SYMBOL(pci_free_consistent);
++#endif
++
++/* mem exports */
++EXPORT_SYMBOL(memchr);
++EXPORT_SYMBOL(memcpy);
++EXPORT_SYMBOL(memset);
++EXPORT_SYMBOL(memmove);
++EXPORT_SYMBOL(__copy_user);
++
++#ifdef CONFIG_MMU
++EXPORT_SYMBOL(get_vm_area);
++#endif
++
++/* semaphore exports */
++EXPORT_SYMBOL(__up);
++EXPORT_SYMBOL(__down);
++EXPORT_SYMBOL(__down_interruptible);
++EXPORT_SYMBOL(__down_trylock);
++
++EXPORT_SYMBOL(__udelay);
++EXPORT_SYMBOL(__ndelay);
++EXPORT_SYMBOL(__const_udelay);
++
++#define DECLARE_EXPORT(name) extern void name(void);EXPORT_SYMBOL(name)
++
++/* These symbols are generated by the compiler itself */
++DECLARE_EXPORT(__udivsi3);
++DECLARE_EXPORT(__sdivsi3);
++DECLARE_EXPORT(__ashrsi3);
++DECLARE_EXPORT(__ashlsi3);
++DECLARE_EXPORT(__ashrdi3);
++DECLARE_EXPORT(__ashldi3);
++DECLARE_EXPORT(__ashiftrt_r4_6);
++DECLARE_EXPORT(__ashiftrt_r4_7);
++DECLARE_EXPORT(__ashiftrt_r4_8);
++DECLARE_EXPORT(__ashiftrt_r4_9);
++DECLARE_EXPORT(__ashiftrt_r4_10);
++DECLARE_EXPORT(__ashiftrt_r4_11);
++DECLARE_EXPORT(__ashiftrt_r4_12);
++DECLARE_EXPORT(__ashiftrt_r4_13);
++DECLARE_EXPORT(__ashiftrt_r4_14);
++DECLARE_EXPORT(__ashiftrt_r4_15);
++DECLARE_EXPORT(__ashiftrt_r4_20);
++DECLARE_EXPORT(__ashiftrt_r4_21);
++DECLARE_EXPORT(__ashiftrt_r4_22);
++DECLARE_EXPORT(__ashiftrt_r4_23);
++DECLARE_EXPORT(__ashiftrt_r4_24);
++DECLARE_EXPORT(__ashiftrt_r4_27);
++DECLARE_EXPORT(__ashiftrt_r4_30);
++DECLARE_EXPORT(__lshrsi3);
++DECLARE_EXPORT(__lshrdi3);
++DECLARE_EXPORT(__movstrSI8);
++DECLARE_EXPORT(__movstrSI12);
++DECLARE_EXPORT(__movstrSI16);
++DECLARE_EXPORT(__movstrSI20);
++DECLARE_EXPORT(__movstrSI24);
++DECLARE_EXPORT(__movstrSI28);
++DECLARE_EXPORT(__movstrSI32);
++DECLARE_EXPORT(__movstrSI36);
++DECLARE_EXPORT(__movstrSI40);
++DECLARE_EXPORT(__movstrSI44);
++DECLARE_EXPORT(__movstrSI48);
++DECLARE_EXPORT(__movstrSI52);
++DECLARE_EXPORT(__movstrSI56);
++DECLARE_EXPORT(__movstrSI60);
++#if __GNUC__ == 4
++DECLARE_EXPORT(__movmem);
++#else
++DECLARE_EXPORT(__movstr);
++#endif
++
++#if __GNUC__ == 4
++DECLARE_EXPORT(__movmem_i4_even);
++DECLARE_EXPORT(__movmem_i4_odd);
++DECLARE_EXPORT(__movmemSI12_i4);
++
++#if (__GNUC_MINOR__ == 2 || defined(__GNUC_STM_RELEASE__))
++/*
++ * GCC 4.2 emits these for division, as do GCC 4.1.x versions of the ST
++ * compiler which include backported patches.
++ */
++DECLARE_EXPORT(__sdivsi3_i4i);
++DECLARE_EXPORT(__udiv_qrnnd_16);
++DECLARE_EXPORT(__udivsi3_i4i);
++#endif
++#else /* GCC 3.x */
++DECLARE_EXPORT(__movstr_i4_even);
++DECLARE_EXPORT(__movstr_i4_odd);
++DECLARE_EXPORT(__movstrSI12_i4);
++#endif /* __GNUC__ == 4 */
++
++#if !defined(CONFIG_CACHE_OFF) && (defined(CONFIG_CPU_SH4) || \
++	defined(CONFIG_SH7705_CACHE_32KB))
++/* needed by some modules */
++EXPORT_SYMBOL(flush_cache_all);
++EXPORT_SYMBOL(flush_cache_range);
++EXPORT_SYMBOL(flush_dcache_page);
++EXPORT_SYMBOL(__flush_purge_region);
++#endif
++
++#if !defined(CONFIG_CACHE_OFF) && defined(CONFIG_MMU) && \
++	(defined(CONFIG_CPU_SH4) || defined(CONFIG_SH7705_CACHE_32KB))
++EXPORT_SYMBOL(clear_user_page);
++#endif
++
++EXPORT_SYMBOL(csum_partial);
++EXPORT_SYMBOL(csum_partial_copy_generic);
++#ifdef CONFIG_IPV6
++EXPORT_SYMBOL(csum_ipv6_magic);
++#endif
++EXPORT_SYMBOL(clear_page);
++EXPORT_SYMBOL(__clear_user);
++EXPORT_SYMBOL(_ebss);
+diff --git a/arch/sh/kernel/sh_ksyms_64.c b/arch/sh/kernel/sh_ksyms_64.c
+new file mode 100644
+index 0000000..8004c38
+--- /dev/null
++++ b/arch/sh/kernel/sh_ksyms_64.c
+@@ -0,0 +1,55 @@
++/*
++ * arch/sh/kernel/sh_ksyms_64.c
++ *
++ * Copyright (C) 2000, 2001  Paolo Alberelli
++ *
++ * 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/rwsem.h>
++#include <linux/module.h>
++#include <linux/smp.h>
++#include <linux/user.h>
++#include <linux/elfcore.h>
++#include <linux/sched.h>
++#include <linux/in6.h>
++#include <linux/interrupt.h>
++#include <linux/screen_info.h>
++#include <asm/semaphore.h>
++#include <asm/processor.h>
++#include <asm/uaccess.h>
++#include <asm/checksum.h>
++#include <asm/io.h>
++#include <asm/delay.h>
++#include <asm/irq.h>
++
++extern int dump_fpu(struct pt_regs *, elf_fpregset_t *);
++
++/* platform dependent support */
++EXPORT_SYMBOL(dump_fpu);
++EXPORT_SYMBOL(kernel_thread);
++
++/* Networking helper routines. */
++EXPORT_SYMBOL(csum_partial_copy_nocheck);
++
++#ifdef CONFIG_VT
++EXPORT_SYMBOL(screen_info);
++#endif
++
++EXPORT_SYMBOL(__down);
++EXPORT_SYMBOL(__down_trylock);
++EXPORT_SYMBOL(__up);
++EXPORT_SYMBOL(__put_user_asm_l);
++EXPORT_SYMBOL(__get_user_asm_l);
++EXPORT_SYMBOL(__copy_user);
++EXPORT_SYMBOL(memcpy);
++EXPORT_SYMBOL(__udelay);
++EXPORT_SYMBOL(__ndelay);
++
++/* Ugh.  These come in from libgcc.a at link time. */
++#define DECLARE_EXPORT(name) extern void name(void);EXPORT_SYMBOL(name)
++
++DECLARE_EXPORT(__sdivsi3);
++DECLARE_EXPORT(__muldi3);
++DECLARE_EXPORT(__udivsi3);
+diff --git a/arch/sh/kernel/signal.c b/arch/sh/kernel/signal.c
+deleted file mode 100644
+index ca754fd..0000000
+--- a/arch/sh/kernel/signal.c
++++ /dev/null
+@@ -1,629 +0,0 @@
+-/*
+- *  linux/arch/sh/kernel/signal.c
+- *
+- *  Copyright (C) 1991, 1992  Linus Torvalds
+- *
+- *  1997-11-28  Modified for POSIX.1b signals by Richard Henderson
+- *
+- *  SuperH version:  Copyright (C) 1999, 2000  Niibe Yutaka & Kaz Kojima
+- *
+- */
+-#include <linux/sched.h>
+-#include <linux/mm.h>
+-#include <linux/smp.h>
+-#include <linux/kernel.h>
+-#include <linux/signal.h>
+-#include <linux/errno.h>
+-#include <linux/wait.h>
+-#include <linux/ptrace.h>
+-#include <linux/unistd.h>
+-#include <linux/stddef.h>
+-#include <linux/tty.h>
+-#include <linux/elf.h>
+-#include <linux/personality.h>
+-#include <linux/binfmts.h>
+-#include <linux/freezer.h>
+-#include <linux/io.h>
+-#include <asm/system.h>
+-#include <asm/ucontext.h>
+-#include <asm/uaccess.h>
+-#include <asm/pgtable.h>
+-#include <asm/cacheflush.h>
+-
+-#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
+-
+-/*
+- * Atomically swap in the new signal mask, and wait for a signal.
+- */
+-asmlinkage int
+-sys_sigsuspend(old_sigset_t mask,
+-	       unsigned long r5, unsigned long r6, unsigned long r7,
+-	       struct pt_regs __regs)
+-{
+-	mask &= _BLOCKABLE;
+-	spin_lock_irq(&current->sighand->siglock);
+-	current->saved_sigmask = current->blocked;
+-	siginitset(&current->blocked, mask);
+-	recalc_sigpending();
+-	spin_unlock_irq(&current->sighand->siglock);
+-
+-	current->state = TASK_INTERRUPTIBLE;
+-	schedule();
+-	set_thread_flag(TIF_RESTORE_SIGMASK);
+-	return -ERESTARTNOHAND;
+-}
+-
+-asmlinkage int
+-sys_sigaction(int sig, const struct old_sigaction __user *act,
+-	      struct old_sigaction __user *oact)
+-{
+-	struct k_sigaction new_ka, old_ka;
+-	int ret;
+-
+-	if (act) {
+-		old_sigset_t mask;
+-		if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
+-		    __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
+-		    __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
+-			return -EFAULT;
+-		__get_user(new_ka.sa.sa_flags, &act->sa_flags);
+-		__get_user(mask, &act->sa_mask);
+-		siginitset(&new_ka.sa.sa_mask, mask);
+-	}
+-
+-	ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
+-
+-	if (!ret && oact) {
+-		if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
+-		    __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
+-		    __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
+-			return -EFAULT;
+-		__put_user(old_ka.sa.sa_flags, &oact->sa_flags);
+-		__put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
+-	}
+-
+-	return ret;
+-}
+-
+-asmlinkage int
+-sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss,
+-		unsigned long r6, unsigned long r7,
+-		struct pt_regs __regs)
+-{
+-	struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
+-
+-	return do_sigaltstack(uss, uoss, regs->regs[15]);
+-}
+-
+-
+-/*
+- * Do a signal return; undo the signal stack.
+- */
+-
+-#define MOVW(n)	 (0x9300|((n)-2))	/* Move mem word at PC+n to R3 */
+-#if defined(CONFIG_CPU_SH2)
+-#define TRAP_NOARG 0xc320		/* Syscall w/no args (NR in R3) */
+-#else
+-#define TRAP_NOARG 0xc310		/* Syscall w/no args (NR in R3) */
+-#endif
+-#define OR_R0_R0 0x200b			/* or r0,r0 (insert to avoid hardware bug) */
+-
+-struct sigframe
+-{
+-	struct sigcontext sc;
+-	unsigned long extramask[_NSIG_WORDS-1];
+-	u16 retcode[8];
+-};
+-
+-struct rt_sigframe
+-{
+-	struct siginfo info;
+-	struct ucontext uc;
+-	u16 retcode[8];
+-};
+-
+-#ifdef CONFIG_SH_FPU
+-static inline int restore_sigcontext_fpu(struct sigcontext __user *sc)
+-{
+-	struct task_struct *tsk = current;
+-
+-	if (!(current_cpu_data.flags & CPU_HAS_FPU))
+-		return 0;
+-
+-	set_used_math();
+-	return __copy_from_user(&tsk->thread.fpu.hard, &sc->sc_fpregs[0],
+-				sizeof(long)*(16*2+2));
+-}
+-
+-static inline int save_sigcontext_fpu(struct sigcontext __user *sc,
+-				      struct pt_regs *regs)
+-{
+-	struct task_struct *tsk = current;
+-
+-	if (!(current_cpu_data.flags & CPU_HAS_FPU))
+-		return 0;
+-
+-	if (!used_math()) {
+-		__put_user(0, &sc->sc_ownedfp);
+-		return 0;
+-	}
+-
+-	__put_user(1, &sc->sc_ownedfp);
+-
+-	/* This will cause a "finit" to be triggered by the next
+-	   attempted FPU operation by the 'current' process.
+-	   */
+-	clear_used_math();
+-
+-	unlazy_fpu(tsk, regs);
+-	return __copy_to_user(&sc->sc_fpregs[0], &tsk->thread.fpu.hard,
+-			      sizeof(long)*(16*2+2));
+-}
+-#endif /* CONFIG_SH_FPU */
+-
+-static int
+-restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, int *r0_p)
+-{
+-	unsigned int err = 0;
+-
+-#define COPY(x)		err |= __get_user(regs->x, &sc->sc_##x)
+-			COPY(regs[1]);
+-	COPY(regs[2]);	COPY(regs[3]);
+-	COPY(regs[4]);	COPY(regs[5]);
+-	COPY(regs[6]);	COPY(regs[7]);
+-	COPY(regs[8]);	COPY(regs[9]);
+-	COPY(regs[10]);	COPY(regs[11]);
+-	COPY(regs[12]);	COPY(regs[13]);
+-	COPY(regs[14]);	COPY(regs[15]);
+-	COPY(gbr);	COPY(mach);
+-	COPY(macl);	COPY(pr);
+-	COPY(sr);	COPY(pc);
+-#undef COPY
+-
+-#ifdef CONFIG_SH_FPU
+-	if (current_cpu_data.flags & CPU_HAS_FPU) {
+-		int owned_fp;
+-		struct task_struct *tsk = current;
+-
+-		regs->sr |= SR_FD; /* Release FPU */
+-		clear_fpu(tsk, regs);
+-		clear_used_math();
+-		__get_user (owned_fp, &sc->sc_ownedfp);
+-		if (owned_fp)
+-			err |= restore_sigcontext_fpu(sc);
+-	}
+-#endif
+-
+-	regs->tra = -1;		/* disable syscall checks */
+-	err |= __get_user(*r0_p, &sc->sc_regs[0]);
+-	return err;
+-}
+-
+-asmlinkage int sys_sigreturn(unsigned long r4, unsigned long r5,
+-			     unsigned long r6, unsigned long r7,
+-			     struct pt_regs __regs)
+-{
+-	struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
+-	struct sigframe __user *frame = (struct sigframe __user *)regs->regs[15];
+-	sigset_t set;
+-	int r0;
+-
+-	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
+-		goto badframe;
+-
+-	if (__get_user(set.sig[0], &frame->sc.oldmask)
+-	    || (_NSIG_WORDS > 1
+-		&& __copy_from_user(&set.sig[1], &frame->extramask,
+-				    sizeof(frame->extramask))))
+-		goto badframe;
+-
+-	sigdelsetmask(&set, ~_BLOCKABLE);
+-
+-	spin_lock_irq(&current->sighand->siglock);
+-	current->blocked = set;
+-	recalc_sigpending();
+-	spin_unlock_irq(&current->sighand->siglock);
+-
+-	if (restore_sigcontext(regs, &frame->sc, &r0))
+-		goto badframe;
+-	return r0;
+-
+-badframe:
+-	force_sig(SIGSEGV, current);
+-	return 0;
+-}
+-
+-asmlinkage int sys_rt_sigreturn(unsigned long r4, unsigned long r5,
+-				unsigned long r6, unsigned long r7,
+-				struct pt_regs __regs)
+-{
+-	struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
+-	struct rt_sigframe __user *frame = (struct rt_sigframe __user *)regs->regs[15];
+-	sigset_t set;
+-	stack_t st;
+-	int r0;
+-
+-	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
+-		goto badframe;
+-
+-	if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
+-		goto badframe;
+-
+-	sigdelsetmask(&set, ~_BLOCKABLE);
+-	spin_lock_irq(&current->sighand->siglock);
+-	current->blocked = set;
+-	recalc_sigpending();
+-	spin_unlock_irq(&current->sighand->siglock);
+-
+-	if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &r0))
+-		goto badframe;
+-
+-	if (__copy_from_user(&st, &frame->uc.uc_stack, sizeof(st)))
+-		goto badframe;
+-	/* It is more difficult to avoid calling this function than to
+-	   call it and ignore errors.  */
+-	do_sigaltstack((const stack_t __user *)&st, NULL, (unsigned long)frame);
+-
+-	return r0;
+-
+-badframe:
+-	force_sig(SIGSEGV, current);
+-	return 0;
+-}
+-
+-/*
+- * Set up a signal frame.
+- */
+-
+-static int
+-setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs,
+-		 unsigned long mask)
+-{
+-	int err = 0;
+-
+-#define COPY(x)		err |= __put_user(regs->x, &sc->sc_##x)
+-	COPY(regs[0]);	COPY(regs[1]);
+-	COPY(regs[2]);	COPY(regs[3]);
+-	COPY(regs[4]);	COPY(regs[5]);
+-	COPY(regs[6]);	COPY(regs[7]);
+-	COPY(regs[8]);	COPY(regs[9]);
+-	COPY(regs[10]);	COPY(regs[11]);
+-	COPY(regs[12]);	COPY(regs[13]);
+-	COPY(regs[14]);	COPY(regs[15]);
+-	COPY(gbr);	COPY(mach);
+-	COPY(macl);	COPY(pr);
+-	COPY(sr);	COPY(pc);
+-#undef COPY
+-
+-#ifdef CONFIG_SH_FPU
+-	err |= save_sigcontext_fpu(sc, regs);
+-#endif
+-
+-	/* non-iBCS2 extensions.. */
+-	err |= __put_user(mask, &sc->oldmask);
+-
+-	return err;
+-}
+-
+-/*
+- * Determine which stack to use..
+- */
+-static inline void __user *
+-get_sigframe(struct k_sigaction *ka, unsigned long sp, size_t frame_size)
+-{
+-	if (ka->sa.sa_flags & SA_ONSTACK) {
+-		if (sas_ss_flags(sp) == 0)
+-			sp = current->sas_ss_sp + current->sas_ss_size;
+-	}
+-
+-	return (void __user *)((sp - frame_size) & -8ul);
+-}
+-
+-/* These symbols are defined with the addresses in the vsyscall page.
+-   See vsyscall-trapa.S.  */
+-extern void __user __kernel_sigreturn;
+-extern void __user __kernel_rt_sigreturn;
+-
+-static int setup_frame(int sig, struct k_sigaction *ka,
+-			sigset_t *set, struct pt_regs *regs)
+-{
+-	struct sigframe __user *frame;
+-	int err = 0;
+-	int signal;
+-
+-	frame = get_sigframe(ka, regs->regs[15], sizeof(*frame));
+-
+-	if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
+-		goto give_sigsegv;
+-
+-	signal = current_thread_info()->exec_domain
+-		&& current_thread_info()->exec_domain->signal_invmap
+-		&& sig < 32
+-		? current_thread_info()->exec_domain->signal_invmap[sig]
+-		: sig;
+-
+-	err |= setup_sigcontext(&frame->sc, regs, set->sig[0]);
+-
+-	if (_NSIG_WORDS > 1)
+-		err |= __copy_to_user(frame->extramask, &set->sig[1],
+-				      sizeof(frame->extramask));
+-
+-	/* Set up to return from userspace.  If provided, use a stub
+-	   already in userspace.  */
+-	if (ka->sa.sa_flags & SA_RESTORER) {
+-		regs->pr = (unsigned long) ka->sa.sa_restorer;
+-#ifdef CONFIG_VSYSCALL
+-	} else if (likely(current->mm->context.vdso)) {
+-		regs->pr = VDSO_SYM(&__kernel_sigreturn);
+-#endif
+-	} else {
+-		/* Generate return code (system call to sigreturn) */
+-		err |= __put_user(MOVW(7), &frame->retcode[0]);
+-		err |= __put_user(TRAP_NOARG, &frame->retcode[1]);
+-		err |= __put_user(OR_R0_R0, &frame->retcode[2]);
+-		err |= __put_user(OR_R0_R0, &frame->retcode[3]);
+-		err |= __put_user(OR_R0_R0, &frame->retcode[4]);
+-		err |= __put_user(OR_R0_R0, &frame->retcode[5]);
+-		err |= __put_user(OR_R0_R0, &frame->retcode[6]);
+-		err |= __put_user((__NR_sigreturn), &frame->retcode[7]);
+-		regs->pr = (unsigned long) frame->retcode;
+-	}
+-
+-	if (err)
+-		goto give_sigsegv;
+-
+-	/* Set up registers for signal handler */
+-	regs->regs[15] = (unsigned long) frame;
+-	regs->regs[4] = signal; /* Arg for signal handler */
+-	regs->regs[5] = 0;
+-	regs->regs[6] = (unsigned long) &frame->sc;
+-	regs->pc = (unsigned long) ka->sa.sa_handler;
+-
+-	set_fs(USER_DS);
+-
+-	pr_debug("SIG deliver (%s:%d): sp=%p pc=%08lx pr=%08lx\n",
+-		 current->comm, task_pid_nr(current), frame, regs->pc, regs->pr);
+-
+-	flush_cache_sigtramp(regs->pr);
+-
+-	if ((-regs->pr & (L1_CACHE_BYTES-1)) < sizeof(frame->retcode))
+-		flush_cache_sigtramp(regs->pr + L1_CACHE_BYTES);
+-
+-	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)
+-{
+-	struct rt_sigframe __user *frame;
+-	int err = 0;
+-	int signal;
+-
+-	frame = get_sigframe(ka, regs->regs[15], sizeof(*frame));
+-
+-	if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
+-		goto give_sigsegv;
+-
+-	signal = current_thread_info()->exec_domain
+-		&& current_thread_info()->exec_domain->signal_invmap
+-		&& sig < 32
+-		? current_thread_info()->exec_domain->signal_invmap[sig]
+-		: sig;
+-
+-	err |= copy_siginfo_to_user(&frame->info, info);
+-
+-	/* Create the ucontext.  */
+-	err |= __put_user(0, &frame->uc.uc_flags);
+-	err |= __put_user(0, &frame->uc.uc_link);
+-	err |= __put_user((void *)current->sas_ss_sp,
+-			  &frame->uc.uc_stack.ss_sp);
+-	err |= __put_user(sas_ss_flags(regs->regs[15]),
+-			  &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,
+-			        regs, set->sig[0]);
+-	err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
+-
+-	/* Set up to return from userspace.  If provided, use a stub
+-	   already in userspace.  */
+-	if (ka->sa.sa_flags & SA_RESTORER) {
+-		regs->pr = (unsigned long) ka->sa.sa_restorer;
+-#ifdef CONFIG_VSYSCALL
+-	} else if (likely(current->mm->context.vdso)) {
+-		regs->pr = VDSO_SYM(&__kernel_rt_sigreturn);
+-#endif
+-	} else {
+-		/* Generate return code (system call to rt_sigreturn) */
+-		err |= __put_user(MOVW(7), &frame->retcode[0]);
+-		err |= __put_user(TRAP_NOARG, &frame->retcode[1]);
+-		err |= __put_user(OR_R0_R0, &frame->retcode[2]);
+-		err |= __put_user(OR_R0_R0, &frame->retcode[3]);
+-		err |= __put_user(OR_R0_R0, &frame->retcode[4]);
+-		err |= __put_user(OR_R0_R0, &frame->retcode[5]);
+-		err |= __put_user(OR_R0_R0, &frame->retcode[6]);
+-		err |= __put_user((__NR_rt_sigreturn), &frame->retcode[7]);
+-		regs->pr = (unsigned long) frame->retcode;
+-	}
+-
+-	if (err)
+-		goto give_sigsegv;
+-
+-	/* Set up registers for signal handler */
+-	regs->regs[15] = (unsigned long) frame;
+-	regs->regs[4] = signal; /* Arg for signal handler */
+-	regs->regs[5] = (unsigned long) &frame->info;
+-	regs->regs[6] = (unsigned long) &frame->uc;
+-	regs->pc = (unsigned long) ka->sa.sa_handler;
+-
+-	set_fs(USER_DS);
+-
+-	pr_debug("SIG deliver (%s:%d): sp=%p pc=%08lx pr=%08lx\n",
+-		 current->comm, task_pid_nr(current), frame, regs->pc, regs->pr);
+-
+-	flush_cache_sigtramp(regs->pr);
+-
+-	if ((-regs->pr & (L1_CACHE_BYTES-1)) < sizeof(frame->retcode))
+-		flush_cache_sigtramp(regs->pr + L1_CACHE_BYTES);
+-
+-	return 0;
+-
+-give_sigsegv:
+-	force_sigsegv(sig, current);
+-	return -EFAULT;
+-}
+-
+-/*
+- * OK, we're invoking a handler
+- */
+-
+-static int
+-handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info,
+-	      sigset_t *oldset, struct pt_regs *regs, unsigned int save_r0)
+-{
+-	int ret;
+-
+-	/* Are we from a system call? */
+-	if (regs->tra >= 0) {
+-		/* If so, check system call restarting.. */
+-		switch (regs->regs[0]) {
+-			case -ERESTART_RESTARTBLOCK:
+-			case -ERESTARTNOHAND:
+-				regs->regs[0] = -EINTR;
+-				break;
+-
+-			case -ERESTARTSYS:
+-				if (!(ka->sa.sa_flags & SA_RESTART)) {
+-					regs->regs[0] = -EINTR;
+-					break;
+-				}
+-			/* fallthrough */
+-			case -ERESTARTNOINTR:
+-				regs->regs[0] = save_r0;
+-				regs->pc -= instruction_size(
+-						ctrl_inw(regs->pc - 4));
+-				break;
+-		}
+-#ifdef CONFIG_GUSA
+-	} else {
+-		/* gUSA handling */
+-		preempt_disable();
+-
+-		if (regs->regs[15] >= 0xc0000000) {
+-			int offset = (int)regs->regs[15];
+-
+-			/* Reset stack pointer: clear critical region mark */
+-			regs->regs[15] = regs->regs[1];
+-			if (regs->pc < regs->regs[0])
+-				/* Go to rewind point #1 */
+-				regs->pc = regs->regs[0] + offset -
+-					instruction_size(ctrl_inw(regs->pc-4));
+-		}
+-
+-		preempt_enable_no_resched();
+-#endif
+-	}
+-
+-	/* 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);
+-
+-	if (ka->sa.sa_flags & SA_ONESHOT)
+-		ka->sa.sa_handler = SIG_DFL;
+-
+-	if (ret == 0) {
+-		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);
+-	}
+-
+-	return ret;
+-}
+-
+-/*
+- * Note that 'init' is a special process: it doesn't get signals it doesn't
+- * want to handle. Thus you cannot kill init even with a SIGKILL even by
+- * mistake.
+- *
+- * Note that we go through the signals twice: once to check the signals that
+- * the kernel can handle, and then we build all the user-level signal handling
+- * stack-frames in one go after that.
+- */
+-static void do_signal(struct pt_regs *regs, unsigned int save_r0)
+-{
+-	siginfo_t info;
+-	int signr;
+-	struct k_sigaction ka;
+-	sigset_t *oldset;
+-
+-	/*
+-	 * We want the common case to go fast, which
+-	 * is why we may in certain cases get here from
+-	 * kernel mode. Just return without doing anything
+-	 * if so.
+-	 */
+-	if (!user_mode(regs))
+-		return;
+-
+-	if (try_to_freeze())
+-		goto no_signal;
+-
+-	if (test_thread_flag(TIF_RESTORE_SIGMASK))
+-		oldset = &current->saved_sigmask;
+-	else
+-		oldset = &current->blocked;
+-
+-	signr = get_signal_to_deliver(&info, &ka, regs, NULL);
+-	if (signr > 0) {
+-		/* Whee!  Actually deliver the signal.  */
+-		if (handle_signal(signr, &ka, &info, oldset,
+-				  regs, save_r0) == 0) {
+-			/* a signal was successfully delivered; the saved
+-			 * sigmask will have been stored in the signal frame,
+-			 * and will be restored by sigreturn, so we can simply
+-			 * clear the TIF_RESTORE_SIGMASK flag */
+-			if (test_thread_flag(TIF_RESTORE_SIGMASK))
+-				clear_thread_flag(TIF_RESTORE_SIGMASK);
+-		}
+-
+-		return;
+-	}
+-
+- no_signal:
+-	/* Did we come from a system call? */
+-	if (regs->tra >= 0) {
+-		/* Restart the system call - no handlers present */
+-		if (regs->regs[0] == -ERESTARTNOHAND ||
+-		    regs->regs[0] == -ERESTARTSYS ||
+-		    regs->regs[0] == -ERESTARTNOINTR) {
+-			regs->regs[0] = save_r0;
+-			regs->pc -= instruction_size(ctrl_inw(regs->pc - 4));
+-		} else if (regs->regs[0] == -ERESTART_RESTARTBLOCK) {
+-			regs->pc -= instruction_size(ctrl_inw(regs->pc - 4));
+-			regs->regs[3] = __NR_restart_syscall;
+-		}
+-	}
+-
+-	/* if there's no signal to deliver, we just put the saved sigmask
+-	 * back */
+-	if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
+-		clear_thread_flag(TIF_RESTORE_SIGMASK);
+-		sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
+-	}
+-}
+-
+-asmlinkage void do_notify_resume(struct pt_regs *regs, unsigned int save_r0,
+-				 __u32 thread_info_flags)
+-{
+-	/* deal with pending signal delivery */
+-	if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK))
+-		do_signal(regs, save_r0);
+-}
+diff --git a/arch/sh/kernel/signal_32.c b/arch/sh/kernel/signal_32.c
+new file mode 100644
+index 0000000..f6b5fbf
+--- /dev/null
++++ b/arch/sh/kernel/signal_32.c
+@@ -0,0 +1,611 @@
++/*
++ *  linux/arch/sh/kernel/signal.c
++ *
++ *  Copyright (C) 1991, 1992  Linus Torvalds
++ *
++ *  1997-11-28  Modified for POSIX.1b signals by Richard Henderson
++ *
++ *  SuperH version:  Copyright (C) 1999, 2000  Niibe Yutaka & Kaz Kojima
++ *
++ */
++#include <linux/sched.h>
++#include <linux/mm.h>
++#include <linux/smp.h>
++#include <linux/kernel.h>
++#include <linux/signal.h>
++#include <linux/errno.h>
++#include <linux/wait.h>
++#include <linux/ptrace.h>
++#include <linux/unistd.h>
++#include <linux/stddef.h>
++#include <linux/tty.h>
++#include <linux/elf.h>
++#include <linux/personality.h>
++#include <linux/binfmts.h>
++#include <linux/freezer.h>
++#include <linux/io.h>
++#include <asm/system.h>
++#include <asm/ucontext.h>
++#include <asm/uaccess.h>
++#include <asm/pgtable.h>
++#include <asm/cacheflush.h>
++
++#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
++
++/*
++ * Atomically swap in the new signal mask, and wait for a signal.
++ */
++asmlinkage int
++sys_sigsuspend(old_sigset_t mask,
++	       unsigned long r5, unsigned long r6, unsigned long r7,
++	       struct pt_regs __regs)
++{
++	mask &= _BLOCKABLE;
++	spin_lock_irq(&current->sighand->siglock);
++	current->saved_sigmask = current->blocked;
++	siginitset(&current->blocked, mask);
++	recalc_sigpending();
++	spin_unlock_irq(&current->sighand->siglock);
++
++	current->state = TASK_INTERRUPTIBLE;
++	schedule();
++	set_thread_flag(TIF_RESTORE_SIGMASK);
++	return -ERESTARTNOHAND;
++}
++
++asmlinkage int
++sys_sigaction(int sig, const struct old_sigaction __user *act,
++	      struct old_sigaction __user *oact)
++{
++	struct k_sigaction new_ka, old_ka;
++	int ret;
++
++	if (act) {
++		old_sigset_t mask;
++		if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
++		    __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
++		    __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
++			return -EFAULT;
++		__get_user(new_ka.sa.sa_flags, &act->sa_flags);
++		__get_user(mask, &act->sa_mask);
++		siginitset(&new_ka.sa.sa_mask, mask);
++	}
++
++	ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
++
++	if (!ret && oact) {
++		if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
++		    __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
++		    __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
++			return -EFAULT;
++		__put_user(old_ka.sa.sa_flags, &oact->sa_flags);
++		__put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
++	}
++
++	return ret;
++}
++
++asmlinkage int
++sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss,
++		unsigned long r6, unsigned long r7,
++		struct pt_regs __regs)
++{
++	struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
++
++	return do_sigaltstack(uss, uoss, regs->regs[15]);
++}
++
++
++/*
++ * Do a signal return; undo the signal stack.
++ */
++
++#define MOVW(n)	 (0x9300|((n)-2))	/* Move mem word at PC+n to R3 */
++#if defined(CONFIG_CPU_SH2)
++#define TRAP_NOARG 0xc320		/* Syscall w/no args (NR in R3) */
++#else
++#define TRAP_NOARG 0xc310		/* Syscall w/no args (NR in R3) */
++#endif
++#define OR_R0_R0 0x200b			/* or r0,r0 (insert to avoid hardware bug) */
++
++struct sigframe
++{
++	struct sigcontext sc;
++	unsigned long extramask[_NSIG_WORDS-1];
++	u16 retcode[8];
++};
++
++struct rt_sigframe
++{
++	struct siginfo info;
++	struct ucontext uc;
++	u16 retcode[8];
++};
++
++#ifdef CONFIG_SH_FPU
++static inline int restore_sigcontext_fpu(struct sigcontext __user *sc)
++{
++	struct task_struct *tsk = current;
++
++	if (!(current_cpu_data.flags & CPU_HAS_FPU))
++		return 0;
++
++	set_used_math();
++	return __copy_from_user(&tsk->thread.fpu.hard, &sc->sc_fpregs[0],
++				sizeof(long)*(16*2+2));
++}
++
++static inline int save_sigcontext_fpu(struct sigcontext __user *sc,
++				      struct pt_regs *regs)
++{
++	struct task_struct *tsk = current;
++
++	if (!(current_cpu_data.flags & CPU_HAS_FPU))
++		return 0;
++
++	if (!used_math()) {
++		__put_user(0, &sc->sc_ownedfp);
++		return 0;
++	}
++
++	__put_user(1, &sc->sc_ownedfp);
++
++	/* This will cause a "finit" to be triggered by the next
++	   attempted FPU operation by the 'current' process.
++	   */
++	clear_used_math();
++
++	unlazy_fpu(tsk, regs);
++	return __copy_to_user(&sc->sc_fpregs[0], &tsk->thread.fpu.hard,
++			      sizeof(long)*(16*2+2));
++}
++#endif /* CONFIG_SH_FPU */
++
++static int
++restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, int *r0_p)
++{
++	unsigned int err = 0;
++
++#define COPY(x)		err |= __get_user(regs->x, &sc->sc_##x)
++			COPY(regs[1]);
++	COPY(regs[2]);	COPY(regs[3]);
++	COPY(regs[4]);	COPY(regs[5]);
++	COPY(regs[6]);	COPY(regs[7]);
++	COPY(regs[8]);	COPY(regs[9]);
++	COPY(regs[10]);	COPY(regs[11]);
++	COPY(regs[12]);	COPY(regs[13]);
++	COPY(regs[14]);	COPY(regs[15]);
++	COPY(gbr);	COPY(mach);
++	COPY(macl);	COPY(pr);
++	COPY(sr);	COPY(pc);
++#undef COPY
++
++#ifdef CONFIG_SH_FPU
++	if (current_cpu_data.flags & CPU_HAS_FPU) {
++		int owned_fp;
++		struct task_struct *tsk = current;
++
++		regs->sr |= SR_FD; /* Release FPU */
++		clear_fpu(tsk, regs);
++		clear_used_math();
++		__get_user (owned_fp, &sc->sc_ownedfp);
++		if (owned_fp)
++			err |= restore_sigcontext_fpu(sc);
++	}
++#endif
++
++	regs->tra = -1;		/* disable syscall checks */
++	err |= __get_user(*r0_p, &sc->sc_regs[0]);
++	return err;
++}
++
++asmlinkage int sys_sigreturn(unsigned long r4, unsigned long r5,
++			     unsigned long r6, unsigned long r7,
++			     struct pt_regs __regs)
++{
++	struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
++	struct sigframe __user *frame = (struct sigframe __user *)regs->regs[15];
++	sigset_t set;
++	int r0;
++
++	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
++		goto badframe;
++
++	if (__get_user(set.sig[0], &frame->sc.oldmask)
++	    || (_NSIG_WORDS > 1
++		&& __copy_from_user(&set.sig[1], &frame->extramask,
++				    sizeof(frame->extramask))))
++		goto badframe;
++
++	sigdelsetmask(&set, ~_BLOCKABLE);
++
++	spin_lock_irq(&current->sighand->siglock);
++	current->blocked = set;
++	recalc_sigpending();
++	spin_unlock_irq(&current->sighand->siglock);
++
++	if (restore_sigcontext(regs, &frame->sc, &r0))
++		goto badframe;
++	return r0;
++
++badframe:
++	force_sig(SIGSEGV, current);
++	return 0;
++}
++
++asmlinkage int sys_rt_sigreturn(unsigned long r4, unsigned long r5,
++				unsigned long r6, unsigned long r7,
++				struct pt_regs __regs)
++{
++	struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
++	struct rt_sigframe __user *frame = (struct rt_sigframe __user *)regs->regs[15];
++	sigset_t set;
++	stack_t st;
++	int r0;
++
++	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
++		goto badframe;
++
++	if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
++		goto badframe;
++
++	sigdelsetmask(&set, ~_BLOCKABLE);
++	spin_lock_irq(&current->sighand->siglock);
++	current->blocked = set;
++	recalc_sigpending();
++	spin_unlock_irq(&current->sighand->siglock);
++
++	if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &r0))
++		goto badframe;
++
++	if (__copy_from_user(&st, &frame->uc.uc_stack, sizeof(st)))
++		goto badframe;
++	/* It is more difficult to avoid calling this function than to
++	   call it and ignore errors.  */
++	do_sigaltstack((const stack_t __user *)&st, NULL, (unsigned long)frame);
++
++	return r0;
++
++badframe:
++	force_sig(SIGSEGV, current);
++	return 0;
++}
++
++/*
++ * Set up a signal frame.
++ */
++
++static int
++setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs,
++		 unsigned long mask)
++{
++	int err = 0;
++
++#define COPY(x)		err |= __put_user(regs->x, &sc->sc_##x)
++	COPY(regs[0]);	COPY(regs[1]);
++	COPY(regs[2]);	COPY(regs[3]);
++	COPY(regs[4]);	COPY(regs[5]);
++	COPY(regs[6]);	COPY(regs[7]);
++	COPY(regs[8]);	COPY(regs[9]);
++	COPY(regs[10]);	COPY(regs[11]);
++	COPY(regs[12]);	COPY(regs[13]);
++	COPY(regs[14]);	COPY(regs[15]);
++	COPY(gbr);	COPY(mach);
++	COPY(macl);	COPY(pr);
++	COPY(sr);	COPY(pc);
++#undef COPY
++
++#ifdef CONFIG_SH_FPU
++	err |= save_sigcontext_fpu(sc, regs);
++#endif
++
++	/* non-iBCS2 extensions.. */
++	err |= __put_user(mask, &sc->oldmask);
++
++	return err;
++}
++
++/*
++ * Determine which stack to use..
++ */
++static inline void __user *
++get_sigframe(struct k_sigaction *ka, unsigned long sp, size_t frame_size)
++{
++	if (ka->sa.sa_flags & SA_ONSTACK) {
++		if (sas_ss_flags(sp) == 0)
++			sp = current->sas_ss_sp + current->sas_ss_size;
++	}
++
++	return (void __user *)((sp - frame_size) & -8ul);
++}
++
++/* These symbols are defined with the addresses in the vsyscall page.
++   See vsyscall-trapa.S.  */
++extern void __user __kernel_sigreturn;
++extern void __user __kernel_rt_sigreturn;
++
++static int setup_frame(int sig, struct k_sigaction *ka,
++			sigset_t *set, struct pt_regs *regs)
++{
++	struct sigframe __user *frame;
++	int err = 0;
++	int signal;
++
++	frame = get_sigframe(ka, regs->regs[15], sizeof(*frame));
++
++	if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
++		goto give_sigsegv;
++
++	signal = current_thread_info()->exec_domain
++		&& current_thread_info()->exec_domain->signal_invmap
++		&& sig < 32
++		? current_thread_info()->exec_domain->signal_invmap[sig]
++		: sig;
++
++	err |= setup_sigcontext(&frame->sc, regs, set->sig[0]);
++
++	if (_NSIG_WORDS > 1)
++		err |= __copy_to_user(frame->extramask, &set->sig[1],
++				      sizeof(frame->extramask));
++
++	/* Set up to return from userspace.  If provided, use a stub
++	   already in userspace.  */
++	if (ka->sa.sa_flags & SA_RESTORER) {
++		regs->pr = (unsigned long) ka->sa.sa_restorer;
++#ifdef CONFIG_VSYSCALL
++	} else if (likely(current->mm->context.vdso)) {
++		regs->pr = VDSO_SYM(&__kernel_sigreturn);
++#endif
++	} else {
++		/* Generate return code (system call to sigreturn) */
++		err |= __put_user(MOVW(7), &frame->retcode[0]);
++		err |= __put_user(TRAP_NOARG, &frame->retcode[1]);
++		err |= __put_user(OR_R0_R0, &frame->retcode[2]);
++		err |= __put_user(OR_R0_R0, &frame->retcode[3]);
++		err |= __put_user(OR_R0_R0, &frame->retcode[4]);
++		err |= __put_user(OR_R0_R0, &frame->retcode[5]);
++		err |= __put_user(OR_R0_R0, &frame->retcode[6]);
++		err |= __put_user((__NR_sigreturn), &frame->retcode[7]);
++		regs->pr = (unsigned long) frame->retcode;
++	}
++
++	if (err)
++		goto give_sigsegv;
++
++	/* Set up registers for signal handler */
++	regs->regs[15] = (unsigned long) frame;
++	regs->regs[4] = signal; /* Arg for signal handler */
++	regs->regs[5] = 0;
++	regs->regs[6] = (unsigned long) &frame->sc;
++	regs->pc = (unsigned long) ka->sa.sa_handler;
++
++	set_fs(USER_DS);
++
++	pr_debug("SIG deliver (%s:%d): sp=%p pc=%08lx pr=%08lx\n",
++		 current->comm, task_pid_nr(current), frame, regs->pc, regs->pr);
++
++	flush_cache_sigtramp(regs->pr);
++
++	if ((-regs->pr & (L1_CACHE_BYTES-1)) < sizeof(frame->retcode))
++		flush_cache_sigtramp(regs->pr + L1_CACHE_BYTES);
++
++	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)
++{
++	struct rt_sigframe __user *frame;
++	int err = 0;
++	int signal;
++
++	frame = get_sigframe(ka, regs->regs[15], sizeof(*frame));
++
++	if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
++		goto give_sigsegv;
++
++	signal = current_thread_info()->exec_domain
++		&& current_thread_info()->exec_domain->signal_invmap
++		&& sig < 32
++		? current_thread_info()->exec_domain->signal_invmap[sig]
++		: sig;
++
++	err |= copy_siginfo_to_user(&frame->info, info);
++
++	/* Create the ucontext.  */
++	err |= __put_user(0, &frame->uc.uc_flags);
++	err |= __put_user(0, &frame->uc.uc_link);
++	err |= __put_user((void *)current->sas_ss_sp,
++			  &frame->uc.uc_stack.ss_sp);
++	err |= __put_user(sas_ss_flags(regs->regs[15]),
++			  &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,
++			        regs, set->sig[0]);
++	err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
++
++	/* Set up to return from userspace.  If provided, use a stub
++	   already in userspace.  */
++	if (ka->sa.sa_flags & SA_RESTORER) {
++		regs->pr = (unsigned long) ka->sa.sa_restorer;
++#ifdef CONFIG_VSYSCALL
++	} else if (likely(current->mm->context.vdso)) {
++		regs->pr = VDSO_SYM(&__kernel_rt_sigreturn);
++#endif
++	} else {
++		/* Generate return code (system call to rt_sigreturn) */
++		err |= __put_user(MOVW(7), &frame->retcode[0]);
++		err |= __put_user(TRAP_NOARG, &frame->retcode[1]);
++		err |= __put_user(OR_R0_R0, &frame->retcode[2]);
++		err |= __put_user(OR_R0_R0, &frame->retcode[3]);
++		err |= __put_user(OR_R0_R0, &frame->retcode[4]);
++		err |= __put_user(OR_R0_R0, &frame->retcode[5]);
++		err |= __put_user(OR_R0_R0, &frame->retcode[6]);
++		err |= __put_user((__NR_rt_sigreturn), &frame->retcode[7]);
++		regs->pr = (unsigned long) frame->retcode;
++	}
++
++	if (err)
++		goto give_sigsegv;
++
++	/* Set up registers for signal handler */
++	regs->regs[15] = (unsigned long) frame;
++	regs->regs[4] = signal; /* Arg for signal handler */
++	regs->regs[5] = (unsigned long) &frame->info;
++	regs->regs[6] = (unsigned long) &frame->uc;
++	regs->pc = (unsigned long) ka->sa.sa_handler;
++
++	set_fs(USER_DS);
++
++	pr_debug("SIG deliver (%s:%d): sp=%p pc=%08lx pr=%08lx\n",
++		 current->comm, task_pid_nr(current), frame, regs->pc, regs->pr);
++
++	flush_cache_sigtramp(regs->pr);
++
++	if ((-regs->pr & (L1_CACHE_BYTES-1)) < sizeof(frame->retcode))
++		flush_cache_sigtramp(regs->pr + L1_CACHE_BYTES);
++
++	return 0;
++
++give_sigsegv:
++	force_sigsegv(sig, current);
++	return -EFAULT;
++}
++
++/*
++ * OK, we're invoking a handler
++ */
++
++static int
++handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info,
++	      sigset_t *oldset, struct pt_regs *regs, unsigned int save_r0)
++{
++	int ret;
++
++	/* Are we from a system call? */
++	if (regs->tra >= 0) {
++		/* If so, check system call restarting.. */
++		switch (regs->regs[0]) {
++			case -ERESTART_RESTARTBLOCK:
++			case -ERESTARTNOHAND:
++				regs->regs[0] = -EINTR;
++				break;
++
++			case -ERESTARTSYS:
++				if (!(ka->sa.sa_flags & SA_RESTART)) {
++					regs->regs[0] = -EINTR;
++					break;
++				}
++			/* fallthrough */
++			case -ERESTARTNOINTR:
++				regs->regs[0] = save_r0;
++				regs->pc -= instruction_size(
++						ctrl_inw(regs->pc - 4));
++				break;
++		}
++	}
++
++	/* 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);
++
++	if (ka->sa.sa_flags & SA_ONESHOT)
++		ka->sa.sa_handler = SIG_DFL;
++
++	if (ret == 0) {
++		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);
++	}
++
++	return ret;
++}
++
++/*
++ * Note that 'init' is a special process: it doesn't get signals it doesn't
++ * want to handle. Thus you cannot kill init even with a SIGKILL even by
++ * mistake.
++ *
++ * Note that we go through the signals twice: once to check the signals that
++ * the kernel can handle, and then we build all the user-level signal handling
++ * stack-frames in one go after that.
++ */
++static void do_signal(struct pt_regs *regs, unsigned int save_r0)
++{
++	siginfo_t info;
++	int signr;
++	struct k_sigaction ka;
++	sigset_t *oldset;
++
++	/*
++	 * We want the common case to go fast, which
++	 * is why we may in certain cases get here from
++	 * kernel mode. Just return without doing anything
++	 * if so.
++	 */
++	if (!user_mode(regs))
++		return;
++
++	if (try_to_freeze())
++		goto no_signal;
++
++	if (test_thread_flag(TIF_RESTORE_SIGMASK))
++		oldset = &current->saved_sigmask;
++	else
++		oldset = &current->blocked;
++
++	signr = get_signal_to_deliver(&info, &ka, regs, NULL);
++	if (signr > 0) {
++		/* Whee!  Actually deliver the signal.  */
++		if (handle_signal(signr, &ka, &info, oldset,
++				  regs, save_r0) == 0) {
++			/* a signal was successfully delivered; the saved
++			 * sigmask will have been stored in the signal frame,
++			 * and will be restored by sigreturn, so we can simply
++			 * clear the TIF_RESTORE_SIGMASK flag */
++			if (test_thread_flag(TIF_RESTORE_SIGMASK))
++				clear_thread_flag(TIF_RESTORE_SIGMASK);
++		}
++
++		return;
++	}
++
++ no_signal:
++	/* Did we come from a system call? */
++	if (regs->tra >= 0) {
++		/* Restart the system call - no handlers present */
++		if (regs->regs[0] == -ERESTARTNOHAND ||
++		    regs->regs[0] == -ERESTARTSYS ||
++		    regs->regs[0] == -ERESTARTNOINTR) {
++			regs->regs[0] = save_r0;
++			regs->pc -= instruction_size(ctrl_inw(regs->pc - 4));
++		} else if (regs->regs[0] == -ERESTART_RESTARTBLOCK) {
++			regs->pc -= instruction_size(ctrl_inw(regs->pc - 4));
++			regs->regs[3] = __NR_restart_syscall;
++		}
++	}
++
++	/* if there's no signal to deliver, we just put the saved sigmask
++	 * back */
++	if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
++		clear_thread_flag(TIF_RESTORE_SIGMASK);
++		sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
++	}
++}
++
++asmlinkage void do_notify_resume(struct pt_regs *regs, unsigned int save_r0,
++				 __u32 thread_info_flags)
++{
++	/* deal with pending signal delivery */
++	if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK))
++		do_signal(regs, save_r0);
++}
+diff --git a/arch/sh/kernel/signal_64.c b/arch/sh/kernel/signal_64.c
+new file mode 100644
+index 0000000..80bde19
+--- /dev/null
++++ b/arch/sh/kernel/signal_64.c
+@@ -0,0 +1,751 @@
++/*
++ * arch/sh/kernel/signal_64.c
++ *
++ * Copyright (C) 2000, 2001  Paolo Alberelli
++ * Copyright (C) 2003  Paul Mundt
++ * Copyright (C) 2004  Richard Curnow
++ *
++ * 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/rwsem.h>
++#include <linux/sched.h>
++#include <linux/mm.h>
++#include <linux/smp.h>
++#include <linux/kernel.h>
++#include <linux/signal.h>
++#include <linux/errno.h>
++#include <linux/wait.h>
++#include <linux/personality.h>
++#include <linux/freezer.h>
++#include <linux/ptrace.h>
++#include <linux/unistd.h>
++#include <linux/stddef.h>
++#include <asm/ucontext.h>
++#include <asm/uaccess.h>
++#include <asm/pgtable.h>
++#include <asm/cacheflush.h>
++
++#define REG_RET 9
++#define REG_ARG1 2
++#define REG_ARG2 3
++#define REG_ARG3 4
++#define REG_SP 15
++#define REG_PR 18
++#define REF_REG_RET regs->regs[REG_RET]
++#define REF_REG_SP regs->regs[REG_SP]
++#define DEREF_REG_PR regs->regs[REG_PR]
++
++#define DEBUG_SIG 0
++
++#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
++
++asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset);
++
++/*
++ * Atomically swap in the new signal mask, and wait for a signal.
++ */
++
++asmlinkage int
++sys_sigsuspend(old_sigset_t mask,
++	       unsigned long r3, unsigned long r4, unsigned long r5,
++	       unsigned long r6, unsigned long r7,
++	       struct pt_regs * regs)
++{
++	sigset_t saveset;
++
++	mask &= _BLOCKABLE;
++	spin_lock_irq(&current->sighand->siglock);
++	saveset = current->blocked;
++	siginitset(&current->blocked, mask);
++	recalc_sigpending();
++	spin_unlock_irq(&current->sighand->siglock);
++
++	REF_REG_RET = -EINTR;
++	while (1) {
++		current->state = TASK_INTERRUPTIBLE;
++		schedule();
++		regs->pc += 4;    /* because sys_sigreturn decrements the pc */
++		if (do_signal(regs, &saveset)) {
++			/* pc now points at signal handler. Need to decrement
++			   it because entry.S will increment it. */
++			regs->pc -= 4;
++			return -EINTR;
++		}
++	}
++}
++
++asmlinkage int
++sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize,
++	          unsigned long r4, unsigned long r5, unsigned long r6,
++	          unsigned long r7,
++	          struct pt_regs * regs)
++{
++	sigset_t saveset, newset;
++
++	/* XXX: Don't preclude handling different sized sigset_t's.  */
++	if (sigsetsize != sizeof(sigset_t))
++		return -EINVAL;
++
++	if (copy_from_user(&newset, unewset, sizeof(newset)))
++		return -EFAULT;
++	sigdelsetmask(&newset, ~_BLOCKABLE);
++	spin_lock_irq(&current->sighand->siglock);
++	saveset = current->blocked;
++	current->blocked = newset;
++	recalc_sigpending();
++	spin_unlock_irq(&current->sighand->siglock);
++
++	REF_REG_RET = -EINTR;
++	while (1) {
++		current->state = TASK_INTERRUPTIBLE;
++		schedule();
++		regs->pc += 4;    /* because sys_sigreturn decrements the pc */
++		if (do_signal(regs, &saveset)) {
++			/* pc now points at signal handler. Need to decrement
++			   it because entry.S will increment it. */
++			regs->pc -= 4;
++			return -EINTR;
++		}
++	}
++}
++
++asmlinkage int
++sys_sigaction(int sig, const struct old_sigaction __user *act,
++	      struct old_sigaction __user *oact)
++{
++	struct k_sigaction new_ka, old_ka;
++	int ret;
++
++	if (act) {
++		old_sigset_t mask;
++		if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
++		    __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
++		    __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
++			return -EFAULT;
++		__get_user(new_ka.sa.sa_flags, &act->sa_flags);
++		__get_user(mask, &act->sa_mask);
++		siginitset(&new_ka.sa.sa_mask, mask);
++	}
++
++	ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
++
++	if (!ret && oact) {
++		if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
++		    __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
++		    __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
++			return -EFAULT;
++		__put_user(old_ka.sa.sa_flags, &oact->sa_flags);
++		__put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
++	}
++
++	return ret;
++}
++
++asmlinkage int
++sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss,
++	        unsigned long r4, unsigned long r5, unsigned long r6,
++	        unsigned long r7,
++	        struct pt_regs * regs)
++{
++	return do_sigaltstack(uss, uoss, REF_REG_SP);
++}
++
++
++/*
++ * Do a signal return; undo the signal stack.
++ */
++
++struct sigframe
++{
++	struct sigcontext sc;
++	unsigned long extramask[_NSIG_WORDS-1];
++	long long retcode[2];
++};
++
++struct rt_sigframe
++{
++	struct siginfo __user *pinfo;
++	void *puc;
++	struct siginfo info;
++	struct ucontext uc;
++	long long retcode[2];
++};
++
++#ifdef CONFIG_SH_FPU
++static inline int
++restore_sigcontext_fpu(struct pt_regs *regs, struct sigcontext __user *sc)
++{
++	int err = 0;
++	int fpvalid;
++
++	err |= __get_user (fpvalid, &sc->sc_fpvalid);
++	conditional_used_math(fpvalid);
++	if (! fpvalid)
++		return err;
++
++	if (current == last_task_used_math) {
++		last_task_used_math = NULL;
++		regs->sr |= SR_FD;
++	}
++
++	err |= __copy_from_user(&current->thread.fpu.hard, &sc->sc_fpregs[0],
++				(sizeof(long long) * 32) + (sizeof(int) * 1));
++
++	return err;
++}
++
++static inline int
++setup_sigcontext_fpu(struct pt_regs *regs, struct sigcontext __user *sc)
++{
++	int err = 0;
++	int fpvalid;
++
++	fpvalid = !!used_math();
++	err |= __put_user(fpvalid, &sc->sc_fpvalid);
++	if (! fpvalid)
++		return err;
++
++	if (current == last_task_used_math) {
++		enable_fpu();
++		save_fpu(current, regs);
++		disable_fpu();
++		last_task_used_math = NULL;
++		regs->sr |= SR_FD;
++	}
++
++	err |= __copy_to_user(&sc->sc_fpregs[0], &current->thread.fpu.hard,
++			      (sizeof(long long) * 32) + (sizeof(int) * 1));
++	clear_used_math();
++
++	return err;
++}
++#else
++static inline int
++restore_sigcontext_fpu(struct pt_regs *regs, struct sigcontext __user *sc)
++{
++	return 0;
++}
++static inline int
++setup_sigcontext_fpu(struct pt_regs *regs, struct sigcontext __user *sc)
++{
++	return 0;
++}
++#endif
++
++static int
++restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, long long *r2_p)
++{
++	unsigned int err = 0;
++        unsigned long long current_sr, new_sr;
++#define SR_MASK 0xffff8cfd
++
++#define COPY(x)		err |= __get_user(regs->x, &sc->sc_##x)
++
++	COPY(regs[0]);	COPY(regs[1]);	COPY(regs[2]);	COPY(regs[3]);
++	COPY(regs[4]);	COPY(regs[5]);	COPY(regs[6]);	COPY(regs[7]);
++	COPY(regs[8]);	COPY(regs[9]);  COPY(regs[10]);	COPY(regs[11]);
++	COPY(regs[12]);	COPY(regs[13]);	COPY(regs[14]);	COPY(regs[15]);
++	COPY(regs[16]);	COPY(regs[17]);	COPY(regs[18]);	COPY(regs[19]);
++	COPY(regs[20]);	COPY(regs[21]);	COPY(regs[22]);	COPY(regs[23]);
++	COPY(regs[24]);	COPY(regs[25]);	COPY(regs[26]);	COPY(regs[27]);
++	COPY(regs[28]);	COPY(regs[29]);	COPY(regs[30]);	COPY(regs[31]);
++	COPY(regs[32]);	COPY(regs[33]);	COPY(regs[34]);	COPY(regs[35]);
++	COPY(regs[36]);	COPY(regs[37]);	COPY(regs[38]);	COPY(regs[39]);
++	COPY(regs[40]);	COPY(regs[41]);	COPY(regs[42]);	COPY(regs[43]);
++	COPY(regs[44]);	COPY(regs[45]);	COPY(regs[46]);	COPY(regs[47]);
++	COPY(regs[48]);	COPY(regs[49]);	COPY(regs[50]);	COPY(regs[51]);
++	COPY(regs[52]);	COPY(regs[53]);	COPY(regs[54]);	COPY(regs[55]);
++	COPY(regs[56]);	COPY(regs[57]);	COPY(regs[58]);	COPY(regs[59]);
++	COPY(regs[60]);	COPY(regs[61]);	COPY(regs[62]);
++	COPY(tregs[0]);	COPY(tregs[1]);	COPY(tregs[2]);	COPY(tregs[3]);
++	COPY(tregs[4]);	COPY(tregs[5]);	COPY(tregs[6]);	COPY(tregs[7]);
++
++        /* Prevent the signal handler manipulating SR in a way that can
++           crash the kernel. i.e. only allow S, Q, M, PR, SZ, FR to be
++           modified */
++        current_sr = regs->sr;
++        err |= __get_user(new_sr, &sc->sc_sr);
++        regs->sr &= SR_MASK;
++        regs->sr |= (new_sr & ~SR_MASK);
++
++	COPY(pc);
++
++#undef COPY
++
++	/* Must do this last in case it sets regs->sr.fd (i.e. after rest of sr
++	 * has been restored above.) */
++	err |= restore_sigcontext_fpu(regs, sc);
++
++	regs->syscall_nr = -1;		/* disable syscall checks */
++	err |= __get_user(*r2_p, &sc->sc_regs[REG_RET]);
++	return err;
++}
++
++asmlinkage int sys_sigreturn(unsigned long r2, unsigned long r3,
++				   unsigned long r4, unsigned long r5,
++				   unsigned long r6, unsigned long r7,
++				   struct pt_regs * regs)
++{
++	struct sigframe __user *frame = (struct sigframe __user *) (long) REF_REG_SP;
++	sigset_t set;
++	long long ret;
++
++	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
++		goto badframe;
++
++	if (__get_user(set.sig[0], &frame->sc.oldmask)
++	    || (_NSIG_WORDS > 1
++		&& __copy_from_user(&set.sig[1], &frame->extramask,
++				    sizeof(frame->extramask))))
++		goto badframe;
++
++	sigdelsetmask(&set, ~_BLOCKABLE);
++
++	spin_lock_irq(&current->sighand->siglock);
++	current->blocked = set;
++	recalc_sigpending();
++	spin_unlock_irq(&current->sighand->siglock);
++
++	if (restore_sigcontext(regs, &frame->sc, &ret))
++		goto badframe;
++	regs->pc -= 4;
++
++	return (int) ret;
++
++badframe:
++	force_sig(SIGSEGV, current);
++	return 0;
++}
++
++asmlinkage int sys_rt_sigreturn(unsigned long r2, unsigned long r3,
++				unsigned long r4, unsigned long r5,
++				unsigned long r6, unsigned long r7,
++				struct pt_regs * regs)
++{
++	struct rt_sigframe __user *frame = (struct rt_sigframe __user *) (long) REF_REG_SP;
++	sigset_t set;
++	stack_t __user st;
++	long long ret;
++
++	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
++		goto badframe;
++
++	if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
++		goto badframe;
++
++	sigdelsetmask(&set, ~_BLOCKABLE);
++	spin_lock_irq(&current->sighand->siglock);
++	current->blocked = set;
++	recalc_sigpending();
++	spin_unlock_irq(&current->sighand->siglock);
++
++	if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &ret))
++		goto badframe;
++	regs->pc -= 4;
++
++	if (__copy_from_user(&st, &frame->uc.uc_stack, sizeof(st)))
++		goto badframe;
++	/* It is more difficult to avoid calling this function than to
++	   call it and ignore errors.  */
++	do_sigaltstack(&st, NULL, REF_REG_SP);
++
++	return (int) ret;
++
++badframe:
++	force_sig(SIGSEGV, current);
++	return 0;
++}
++
++/*
++ * Set up a signal frame.
++ */
++
++static int
++setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs,
++		 unsigned long mask)
++{
++	int err = 0;
++
++	/* Do this first, otherwise is this sets sr->fd, that value isn't preserved. */
++	err |= setup_sigcontext_fpu(regs, sc);
++
++#define COPY(x)		err |= __put_user(regs->x, &sc->sc_##x)
++
++	COPY(regs[0]);	COPY(regs[1]);	COPY(regs[2]);	COPY(regs[3]);
++	COPY(regs[4]);	COPY(regs[5]);	COPY(regs[6]);	COPY(regs[7]);
++	COPY(regs[8]);	COPY(regs[9]);	COPY(regs[10]);	COPY(regs[11]);
++	COPY(regs[12]);	COPY(regs[13]);	COPY(regs[14]);	COPY(regs[15]);
++	COPY(regs[16]);	COPY(regs[17]);	COPY(regs[18]);	COPY(regs[19]);
++	COPY(regs[20]);	COPY(regs[21]);	COPY(regs[22]);	COPY(regs[23]);
++	COPY(regs[24]);	COPY(regs[25]);	COPY(regs[26]);	COPY(regs[27]);
++	COPY(regs[28]);	COPY(regs[29]);	COPY(regs[30]);	COPY(regs[31]);
++	COPY(regs[32]);	COPY(regs[33]);	COPY(regs[34]);	COPY(regs[35]);
++	COPY(regs[36]);	COPY(regs[37]);	COPY(regs[38]);	COPY(regs[39]);
++	COPY(regs[40]);	COPY(regs[41]);	COPY(regs[42]);	COPY(regs[43]);
++	COPY(regs[44]);	COPY(regs[45]);	COPY(regs[46]);	COPY(regs[47]);
++	COPY(regs[48]);	COPY(regs[49]);	COPY(regs[50]);	COPY(regs[51]);
++	COPY(regs[52]);	COPY(regs[53]);	COPY(regs[54]);	COPY(regs[55]);
++	COPY(regs[56]);	COPY(regs[57]);	COPY(regs[58]);	COPY(regs[59]);
++	COPY(regs[60]);	COPY(regs[61]);	COPY(regs[62]);
++	COPY(tregs[0]);	COPY(tregs[1]);	COPY(tregs[2]);	COPY(tregs[3]);
++	COPY(tregs[4]);	COPY(tregs[5]);	COPY(tregs[6]);	COPY(tregs[7]);
++	COPY(sr);	COPY(pc);
++
++#undef COPY
++
++	err |= __put_user(mask, &sc->oldmask);
++
++	return err;
++}
++
++/*
++ * Determine which stack to use..
++ */
++static inline void __user *
++get_sigframe(struct k_sigaction *ka, unsigned long sp, size_t frame_size)
++{
++	if ((ka->sa.sa_flags & SA_ONSTACK) != 0 && ! sas_ss_flags(sp))
++		sp = current->sas_ss_sp + current->sas_ss_size;
++
++	return (void __user *)((sp - frame_size) & -8ul);
++}
++
++void sa_default_restorer(void);		/* See comments below */
++void sa_default_rt_restorer(void);	/* See comments below */
++
++static void setup_frame(int sig, struct k_sigaction *ka,
++			sigset_t *set, struct pt_regs *regs)
++{
++	struct sigframe __user *frame;
++	int err = 0;
++	int signal;
++
++	frame = get_sigframe(ka, regs->regs[REG_SP], sizeof(*frame));
++
++	if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
++		goto give_sigsegv;
++
++	signal = current_thread_info()->exec_domain
++		&& current_thread_info()->exec_domain->signal_invmap
++		&& sig < 32
++		? current_thread_info()->exec_domain->signal_invmap[sig]
++		: sig;
++
++	err |= setup_sigcontext(&frame->sc, regs, set->sig[0]);
++
++	/* Give up earlier as i386, in case */
++	if (err)
++		goto give_sigsegv;
++
++	if (_NSIG_WORDS > 1) {
++		err |= __copy_to_user(frame->extramask, &set->sig[1],
++				      sizeof(frame->extramask)); }
++
++	/* Give up earlier as i386, in case */
++	if (err)
++		goto give_sigsegv;
++
++	/* Set up to return from userspace.  If provided, use a stub
++	   already in userspace.  */
++	if (ka->sa.sa_flags & SA_RESTORER) {
++		DEREF_REG_PR = (unsigned long) ka->sa.sa_restorer | 0x1;
++
++		/*
++		 * On SH5 all edited pointers are subject to NEFF
++		 */
++		DEREF_REG_PR = (DEREF_REG_PR & NEFF_SIGN) ?
++        		 	(DEREF_REG_PR | NEFF_MASK) : DEREF_REG_PR;
++	} else {
++		/*
++		 * Different approach on SH5.
++	         * . Endianness independent asm code gets placed in entry.S .
++		 *   This is limited to four ASM instructions corresponding
++		 *   to two long longs in size.
++		 * . err checking is done on the else branch only
++		 * . flush_icache_range() is called upon __put_user() only
++		 * . all edited pointers are subject to NEFF
++		 * . being code, linker turns ShMedia bit on, always
++		 *   dereference index -1.
++		 */
++		DEREF_REG_PR = (unsigned long) frame->retcode | 0x01;
++		DEREF_REG_PR = (DEREF_REG_PR & NEFF_SIGN) ?
++        		 	(DEREF_REG_PR | NEFF_MASK) : DEREF_REG_PR;
++
++		if (__copy_to_user(frame->retcode,
++			(unsigned long long)sa_default_restorer & (~1), 16) != 0)
++			goto give_sigsegv;
++
++		/* Cohere the trampoline with the I-cache. */
++		flush_cache_sigtramp(DEREF_REG_PR-1);
++	}
++
++	/*
++	 * Set up registers for signal handler.
++	 * All edited pointers are subject to NEFF.
++	 */
++	regs->regs[REG_SP] = (unsigned long) frame;
++	regs->regs[REG_SP] = (regs->regs[REG_SP] & NEFF_SIGN) ?
++        		 (regs->regs[REG_SP] | NEFF_MASK) : regs->regs[REG_SP];
++	regs->regs[REG_ARG1] = signal; /* Arg for signal handler */
++
++        /* FIXME:
++           The glibc profiling support for SH-5 needs to be passed a sigcontext
++           so it can retrieve the PC.  At some point during 2003 the glibc
++           support was changed to receive the sigcontext through the 2nd
++           argument, but there are still versions of libc.so in use that use
++           the 3rd argument.  Until libc.so is stabilised, pass the sigcontext
++           through both 2nd and 3rd arguments.
++        */
++
++	regs->regs[REG_ARG2] = (unsigned long long)(unsigned long)(signed long)&frame->sc;
++	regs->regs[REG_ARG3] = (unsigned long long)(unsigned long)(signed long)&frame->sc;
++
++	regs->pc = (unsigned long) ka->sa.sa_handler;
++	regs->pc = (regs->pc & NEFF_SIGN) ? (regs->pc | NEFF_MASK) : regs->pc;
++
++	set_fs(USER_DS);
++
++#if DEBUG_SIG
++	/* Broken %016Lx */
++	printk("SIG deliver (#%d,%s:%d): sp=%p pc=%08Lx%08Lx link=%08Lx%08Lx\n",
++		signal,
++		current->comm, current->pid, frame,
++		regs->pc >> 32, regs->pc & 0xffffffff,
++		DEREF_REG_PR >> 32, DEREF_REG_PR & 0xffffffff);
++#endif
++
++	return;
++
++give_sigsegv:
++	force_sigsegv(sig, current);
++}
++
++static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
++			   sigset_t *set, struct pt_regs *regs)
++{
++	struct rt_sigframe __user *frame;
++	int err = 0;
++	int signal;
++
++	frame = get_sigframe(ka, regs->regs[REG_SP], sizeof(*frame));
++
++	if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
++		goto give_sigsegv;
++
++	signal = 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(&frame->info, &frame->pinfo);
++	err |= __put_user(&frame->uc, &frame->puc);
++	err |= copy_siginfo_to_user(&frame->info, info);
++
++	/* Give up earlier as i386, in case */
++	if (err)
++		goto give_sigsegv;
++
++	/* Create the ucontext.  */
++	err |= __put_user(0, &frame->uc.uc_flags);
++	err |= __put_user(0, &frame->uc.uc_link);
++	err |= __put_user((void *)current->sas_ss_sp,
++			  &frame->uc.uc_stack.ss_sp);
++	err |= __put_user(sas_ss_flags(regs->regs[REG_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,
++			        regs, set->sig[0]);
++	err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
++
++	/* Give up earlier as i386, in case */
++	if (err)
++		goto give_sigsegv;
++
++	/* Set up to return from userspace.  If provided, use a stub
++	   already in userspace.  */
++	if (ka->sa.sa_flags & SA_RESTORER) {
++		DEREF_REG_PR = (unsigned long) ka->sa.sa_restorer | 0x1;
++
++		/*
++		 * On SH5 all edited pointers are subject to NEFF
++		 */
++		DEREF_REG_PR = (DEREF_REG_PR & NEFF_SIGN) ?
++        		 	(DEREF_REG_PR | NEFF_MASK) : DEREF_REG_PR;
++	} else {
++		/*
++		 * Different approach on SH5.
++	         * . Endianness independent asm code gets placed in entry.S .
++		 *   This is limited to four ASM instructions corresponding
++		 *   to two long longs in size.
++		 * . err checking is done on the else branch only
++		 * . flush_icache_range() is called upon __put_user() only
++		 * . all edited pointers are subject to NEFF
++		 * . being code, linker turns ShMedia bit on, always
++		 *   dereference index -1.
++		 */
++
++		DEREF_REG_PR = (unsigned long) frame->retcode | 0x01;
++		DEREF_REG_PR = (DEREF_REG_PR & NEFF_SIGN) ?
++        		 	(DEREF_REG_PR | NEFF_MASK) : DEREF_REG_PR;
++
++		if (__copy_to_user(frame->retcode,
++			(unsigned long long)sa_default_rt_restorer & (~1), 16) != 0)
++			goto give_sigsegv;
++
++		flush_icache_range(DEREF_REG_PR-1, DEREF_REG_PR-1+15);
++	}
++
++	/*
++	 * Set up registers for signal handler.
++	 * All edited pointers are subject to NEFF.
++	 */
++	regs->regs[REG_SP] = (unsigned long) frame;
++	regs->regs[REG_SP] = (regs->regs[REG_SP] & NEFF_SIGN) ?
++        		 (regs->regs[REG_SP] | NEFF_MASK) : regs->regs[REG_SP];
++	regs->regs[REG_ARG1] = signal; /* Arg for signal handler */
++	regs->regs[REG_ARG2] = (unsigned long long)(unsigned long)(signed long)&frame->info;
++	regs->regs[REG_ARG3] = (unsigned long long)(unsigned long)(signed long)&frame->uc.uc_mcontext;
++	regs->pc = (unsigned long) ka->sa.sa_handler;
++	regs->pc = (regs->pc & NEFF_SIGN) ? (regs->pc | NEFF_MASK) : regs->pc;
++
++	set_fs(USER_DS);
++
++#if DEBUG_SIG
++	/* Broken %016Lx */
++	printk("SIG deliver (#%d,%s:%d): sp=%p pc=%08Lx%08Lx link=%08Lx%08Lx\n",
++		signal,
++		current->comm, current->pid, frame,
++		regs->pc >> 32, regs->pc & 0xffffffff,
++		DEREF_REG_PR >> 32, DEREF_REG_PR & 0xffffffff);
++#endif
++
++	return;
++
++give_sigsegv:
++	force_sigsegv(sig, current);
++}
++
++/*
++ * OK, we're invoking a handler
++ */
++
++static void
++handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
++		sigset_t *oldset, struct pt_regs * regs)
++{
++	/* Are we from a system call? */
++	if (regs->syscall_nr >= 0) {
++		/* If so, check system call restarting.. */
++		switch (regs->regs[REG_RET]) {
++			case -ERESTART_RESTARTBLOCK:
++			case -ERESTARTNOHAND:
++				regs->regs[REG_RET] = -EINTR;
++				break;
++
++			case -ERESTARTSYS:
++				if (!(ka->sa.sa_flags & SA_RESTART)) {
++					regs->regs[REG_RET] = -EINTR;
++					break;
++				}
++			/* fallthrough */
++			case -ERESTARTNOINTR:
++				/* Decode syscall # */
++				regs->regs[REG_RET] = regs->syscall_nr;
++				regs->pc -= 4;
++		}
++	}
++
++	/* Set up the stack frame */
++	if (ka->sa.sa_flags & SA_SIGINFO)
++		setup_rt_frame(sig, ka, info, oldset, regs);
++	else
++		setup_frame(sig, ka, oldset, regs);
++
++	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);
++}
++
++/*
++ * Note that 'init' is a special process: it doesn't get signals it doesn't
++ * want to handle. Thus you cannot kill init even with a SIGKILL even by
++ * mistake.
++ *
++ * Note that we go through the signals twice: once to check the signals that
++ * the kernel can handle, and then we build all the user-level signal handling
++ * stack-frames in one go after that.
++ */
++int do_signal(struct pt_regs *regs, sigset_t *oldset)
++{
++	siginfo_t info;
++	int signr;
++	struct k_sigaction ka;
++
++	/*
++	 * We want the common case to go fast, which
++	 * is why we may in certain cases get here from
++	 * kernel mode. Just return without doing anything
++	 * if so.
++	 */
++	if (!user_mode(regs))
++		return 1;
++
++	if (try_to_freeze())
++		goto no_signal;
++
++	if (test_thread_flag(TIF_RESTORE_SIGMASK))
++		oldset = &current->saved_sigmask;
++	else if (!oldset)
++		oldset = &current->blocked;
++
++	signr = get_signal_to_deliver(&info, &ka, regs, 0);
++
++	if (signr > 0) {
++		/* Whee!  Actually deliver the signal.  */
++		handle_signal(signr, &info, &ka, oldset, regs);
++
++		/*
++		 * If a signal was successfully delivered, the saved sigmask
++		 * is in its frame, and we can clear the TIF_RESTORE_SIGMASK
++		 * flag.
++		 */
++		if (test_thread_flag(TIF_RESTORE_SIGMASK))
++			clear_thread_flag(TIF_RESTORE_SIGMASK);
++
++		return 1;
++	}
++
++no_signal:
++	/* Did we come from a system call? */
++	if (regs->syscall_nr >= 0) {
++		/* Restart the system call - no handlers present */
++		switch (regs->regs[REG_RET]) {
++		case -ERESTARTNOHAND:
++		case -ERESTARTSYS:
++		case -ERESTARTNOINTR:
++			/* Decode Syscall # */
++			regs->regs[REG_RET] = regs->syscall_nr;
++			regs->pc -= 4;
++			break;
++
++		case -ERESTART_RESTARTBLOCK:
++			regs->regs[REG_RET] = __NR_restart_syscall;
++			regs->pc -= 4;
++			break;
++		}
++	}
++
++	/* No signal to deliver -- put the saved sigmask back */
++	if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
++		clear_thread_flag(TIF_RESTORE_SIGMASK);
++		sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
++	}
++
++	return 0;
++}
+diff --git a/arch/sh/kernel/sys_sh.c b/arch/sh/kernel/sys_sh.c
+index d545a68..59cd285 100644
+--- a/arch/sh/kernel/sys_sh.c
++++ b/arch/sh/kernel/sys_sh.c
+@@ -7,7 +7,6 @@
+  *
+  * Taken from i386 version.
+  */
+-
+ #include <linux/errno.h>
+ #include <linux/sched.h>
+ #include <linux/mm.h>
+@@ -27,28 +26,7 @@
+ #include <asm/uaccess.h>
+ #include <asm/unistd.h>
+ 
+-/*
+- * sys_pipe() is the normal C calling standard for creating
+- * a pipe. It's not the way Unix traditionally does this, though.
+- */
+-asmlinkage int sys_pipe(unsigned long r4, unsigned long r5,
+-	unsigned long r6, unsigned long r7,
+-	struct pt_regs __regs)
+-{
+-	struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
+-	int fd[2];
+-	int error;
+-
+-	error = do_pipe(fd);
+-	if (!error) {
+-		regs->regs[1] = fd[1];
+-		return fd[0];
+-	}
+-	return error;
+-}
+-
+ unsigned long shm_align_mask = PAGE_SIZE - 1;	/* Sane caches */
+-
+ EXPORT_SYMBOL(shm_align_mask);
+ 
+ #ifdef CONFIG_MMU
+@@ -140,7 +118,7 @@ full_search:
+ #endif /* CONFIG_MMU */
+ 
+ static inline long
+-do_mmap2(unsigned long addr, unsigned long len, unsigned long prot, 
++do_mmap2(unsigned long addr, unsigned long len, unsigned long prot,
+ 	 unsigned long flags, int fd, unsigned long pgoff)
+ {
+ 	int error = -EBADF;
+@@ -195,12 +173,13 @@ asmlinkage int sys_ipc(uint call, int first, int second,
+ 	if (call <= SEMCTL)
+ 		switch (call) {
+ 		case SEMOP:
+-			return sys_semtimedop(first, (struct sembuf __user *)ptr,
++			return sys_semtimedop(first,
++					      (struct sembuf __user *)ptr,
+ 					      second, NULL);
+ 		case SEMTIMEDOP:
+-			return sys_semtimedop(first, (struct sembuf __user *)ptr,
+-					      second,
+-					      (const struct timespec __user *)fifth);
++			return sys_semtimedop(first,
++				(struct sembuf __user *)ptr, second,
++			        (const struct timespec __user *)fifth);
+ 		case SEMGET:
+ 			return sys_semget (first, second, third);
+ 		case SEMCTL: {
+@@ -215,25 +194,28 @@ asmlinkage int sys_ipc(uint call, int first, int second,
+ 			return -EINVAL;
+ 		}
+ 
+-	if (call <= MSGCTL) 
++	if (call <= MSGCTL)
+ 		switch (call) {
+ 		case MSGSND:
+-			return sys_msgsnd (first, (struct msgbuf __user *) ptr, 
++			return sys_msgsnd (first, (struct msgbuf __user *) ptr,
+ 					  second, third);
+ 		case MSGRCV:
+ 			switch (version) {
+-			case 0: {
++			case 0:
++			{
+ 				struct ipc_kludge tmp;
++
+ 				if (!ptr)
+ 					return -EINVAL;
+-				
++
+ 				if (copy_from_user(&tmp,
+-						   (struct ipc_kludge __user *) ptr, 
++					(struct ipc_kludge __user *) ptr,
+ 						   sizeof (tmp)))
+ 					return -EFAULT;
++
+ 				return sys_msgrcv (first, tmp.msgp, second,
+ 						   tmp.msgtyp, third);
+-				}
++			}
+ 			default:
+ 				return sys_msgrcv (first,
+ 						   (struct msgbuf __user *) ptr,
+@@ -247,7 +229,7 @@ asmlinkage int sys_ipc(uint call, int first, int second,
+ 		default:
+ 			return -EINVAL;
+ 		}
+-	if (call <= SHMCTL) 
++	if (call <= SHMCTL)
+ 		switch (call) {
+ 		case SHMAT:
+ 			switch (version) {
+@@ -265,7 +247,7 @@ asmlinkage int sys_ipc(uint call, int first, int second,
+ 				return do_shmat (first, (char __user *) ptr,
+ 						  second, (ulong *) third);
+ 			}
+-		case SHMDT: 
++		case SHMDT:
+ 			return sys_shmdt ((char __user *)ptr);
+ 		case SHMGET:
+ 			return sys_shmget (first, second, third);
+@@ -275,7 +257,7 @@ asmlinkage int sys_ipc(uint call, int first, int second,
+ 		default:
+ 			return -EINVAL;
+ 		}
+-	
++
+ 	return -EINVAL;
+ }
+ 
+@@ -289,49 +271,3 @@ asmlinkage int sys_uname(struct old_utsname * name)
+ 	up_read(&uts_sem);
+ 	return err?-EFAULT:0;
+ }
+-
+-asmlinkage ssize_t sys_pread_wrapper(unsigned int fd, char * buf,
+-			     size_t count, long dummy, loff_t pos)
+-{
+-	return sys_pread64(fd, buf, count, pos);
+-}
+-
+-asmlinkage ssize_t sys_pwrite_wrapper(unsigned int fd, const char * buf,
+-			      size_t count, long dummy, loff_t pos)
+-{
+-	return sys_pwrite64(fd, buf, count, pos);
+-}
+-
+-asmlinkage int sys_fadvise64_64_wrapper(int fd, u32 offset0, u32 offset1,
+-				u32 len0, u32 len1, int advice)
+-{
+-#ifdef  __LITTLE_ENDIAN__
+-	return sys_fadvise64_64(fd, (u64)offset1 << 32 | offset0,
+-				(u64)len1 << 32 | len0,	advice);
+-#else
+-	return sys_fadvise64_64(fd, (u64)offset0 << 32 | offset1,
+-				(u64)len0 << 32 | len1,	advice);
+-#endif
+-}
+-
+-#if defined(CONFIG_CPU_SH2) || defined(CONFIG_CPU_SH2A)
+-#define SYSCALL_ARG3	"trapa #0x23"
+-#else
+-#define SYSCALL_ARG3	"trapa #0x13"
+-#endif
+-
+-/*
+- * Do a system call from kernel instead of calling sys_execve so we
+- * end up with proper pt_regs.
+- */
+-int kernel_execve(const char *filename, char *const argv[], char *const envp[])
+-{
+-	register long __sc0 __asm__ ("r3") = __NR_execve;
+-	register long __sc4 __asm__ ("r4") = (long) filename;
+-	register long __sc5 __asm__ ("r5") = (long) argv;
+-	register long __sc6 __asm__ ("r6") = (long) envp;
+-	__asm__ __volatile__ (SYSCALL_ARG3 : "=z" (__sc0)	
+-			: "0" (__sc0), "r" (__sc4), "r" (__sc5), "r" (__sc6)
+-			: "memory");
+-	return __sc0;
+-}
+diff --git a/arch/sh/kernel/sys_sh32.c b/arch/sh/kernel/sys_sh32.c
+new file mode 100644
+index 0000000..125e493
+--- /dev/null
++++ b/arch/sh/kernel/sys_sh32.c
+@@ -0,0 +1,84 @@
++#include <linux/errno.h>
++#include <linux/sched.h>
++#include <linux/mm.h>
++#include <linux/smp.h>
++#include <linux/sem.h>
++#include <linux/msg.h>
++#include <linux/shm.h>
++#include <linux/stat.h>
++#include <linux/syscalls.h>
++#include <linux/mman.h>
++#include <linux/file.h>
++#include <linux/utsname.h>
++#include <linux/module.h>
++#include <linux/fs.h>
++#include <linux/ipc.h>
++#include <asm/cacheflush.h>
++#include <asm/uaccess.h>
++#include <asm/unistd.h>
++
++/*
++ * sys_pipe() is the normal C calling standard for creating
++ * a pipe. It's not the way Unix traditionally does this, though.
++ */
++asmlinkage int sys_pipe(unsigned long r4, unsigned long r5,
++	unsigned long r6, unsigned long r7,
++	struct pt_regs __regs)
++{
++	struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
++	int fd[2];
++	int error;
++
++	error = do_pipe(fd);
++	if (!error) {
++		regs->regs[1] = fd[1];
++		return fd[0];
++	}
++	return error;
++}
++
++asmlinkage ssize_t sys_pread_wrapper(unsigned int fd, char * buf,
++			     size_t count, long dummy, loff_t pos)
++{
++	return sys_pread64(fd, buf, count, pos);
++}
++
++asmlinkage ssize_t sys_pwrite_wrapper(unsigned int fd, const char * buf,
++			      size_t count, long dummy, loff_t pos)
++{
++	return sys_pwrite64(fd, buf, count, pos);
++}
++
++asmlinkage int sys_fadvise64_64_wrapper(int fd, u32 offset0, u32 offset1,
++				u32 len0, u32 len1, int advice)
++{
++#ifdef  __LITTLE_ENDIAN__
++	return sys_fadvise64_64(fd, (u64)offset1 << 32 | offset0,
++				(u64)len1 << 32 | len0,	advice);
++#else
++	return sys_fadvise64_64(fd, (u64)offset0 << 32 | offset1,
++				(u64)len0 << 32 | len1,	advice);
++#endif
++}
++
++#if defined(CONFIG_CPU_SH2) || defined(CONFIG_CPU_SH2A)
++#define SYSCALL_ARG3	"trapa #0x23"
++#else
++#define SYSCALL_ARG3	"trapa #0x13"
++#endif
++
++/*
++ * Do a system call from kernel instead of calling sys_execve so we
++ * end up with proper pt_regs.
++ */
++int kernel_execve(const char *filename, char *const argv[], char *const envp[])
++{
++	register long __sc0 __asm__ ("r3") = __NR_execve;
++	register long __sc4 __asm__ ("r4") = (long) filename;
++	register long __sc5 __asm__ ("r5") = (long) argv;
++	register long __sc6 __asm__ ("r6") = (long) envp;
++	__asm__ __volatile__ (SYSCALL_ARG3 : "=z" (__sc0)
++			: "0" (__sc0), "r" (__sc4), "r" (__sc5), "r" (__sc6)
++			: "memory");
++	return __sc0;
++}
+diff --git a/arch/sh/kernel/sys_sh64.c b/arch/sh/kernel/sys_sh64.c
+new file mode 100644
+index 0000000..578004d
+--- /dev/null
++++ b/arch/sh/kernel/sys_sh64.c
+@@ -0,0 +1,66 @@
++/*
++ * arch/sh/kernel/sys_sh64.c
++ *
++ * Copyright (C) 2000, 2001  Paolo Alberelli
++ *
++ * This file contains various random system calls that
++ * have a non-standard calling sequence on the Linux/SH5
++ * platform.
++ *
++ * 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/errno.h>
++#include <linux/rwsem.h>
++#include <linux/sched.h>
++#include <linux/mm.h>
++#include <linux/fs.h>
++#include <linux/smp.h>
++#include <linux/sem.h>
++#include <linux/msg.h>
++#include <linux/shm.h>
++#include <linux/stat.h>
++#include <linux/mman.h>
++#include <linux/file.h>
++#include <linux/utsname.h>
++#include <linux/syscalls.h>
++#include <linux/ipc.h>
++#include <asm/uaccess.h>
++#include <asm/ptrace.h>
++#include <asm/unistd.h>
++
++/*
++ * sys_pipe() is the normal C calling standard for creating
++ * a pipe. It's not the way Unix traditionally does this, though.
++ */
++asmlinkage int sys_pipe(unsigned long * fildes)
++{
++        int fd[2];
++        int error;
++
++        error = do_pipe(fd);
++        if (!error) {
++                if (copy_to_user(fildes, fd, 2*sizeof(int)))
++                        error = -EFAULT;
++        }
++        return error;
++}
++
++/*
++ * Do a system call from kernel instead of calling sys_execve so we
++ * end up with proper pt_regs.
++ */
++int kernel_execve(const char *filename, char *const argv[], char *const envp[])
++{
++	register unsigned long __sc0 __asm__ ("r9") = ((0x13 << 16) | __NR_execve);
++	register unsigned long __sc2 __asm__ ("r2") = (unsigned long) filename;
++	register unsigned long __sc3 __asm__ ("r3") = (unsigned long) argv;
++	register unsigned long __sc4 __asm__ ("r4") = (unsigned long) envp;
++	__asm__ __volatile__ ("trapa	%1 !\t\t\t execve(%2,%3,%4)"
++	: "=r" (__sc0)
++	: "r" (__sc0), "r" (__sc2), "r" (__sc3), "r" (__sc4) );
++	__asm__ __volatile__ ("!dummy	%0 %1 %2 %3"
++	: : "r" (__sc0), "r" (__sc2), "r" (__sc3), "r" (__sc4) : "memory");
++	return __sc0;
++}
+diff --git a/arch/sh/kernel/syscalls.S b/arch/sh/kernel/syscalls.S
+deleted file mode 100644
+index 10bec45..0000000
+--- a/arch/sh/kernel/syscalls.S
++++ /dev/null
+@@ -1,343 +0,0 @@
+-/*
+- * arch/sh/kernel/syscalls.S
+- *
+- * System call table for SuperH
+- *
+- *  Copyright (C) 1999, 2000, 2002  Niibe Yutaka
+- *  Copyright (C) 2003  Paul Mundt
+- *
+- * This file is subject to the terms and conditions of the GNU General Public
+- * License.  See the file "COPYING" in the main directory of this archive
+- * for more details.
+- *
+- */
+-#include <linux/sys.h>
+-#include <linux/linkage.h>
+-
+-	.data
+-ENTRY(sys_call_table)
+-	.long sys_restart_syscall	/* 0  -  old "setup()" system call*/
+-	.long sys_exit
+-	.long sys_fork
+-	.long sys_read
+-	.long sys_write
+-	.long sys_open		/* 5 */
+-	.long sys_close
+-	.long sys_waitpid
+-	.long sys_creat
+-	.long sys_link
+-	.long sys_unlink		/* 10 */
+-	.long sys_execve
+-	.long sys_chdir
+-	.long sys_time
+-	.long sys_mknod
+-	.long sys_chmod		/* 15 */
+-	.long sys_lchown16
+-	.long sys_ni_syscall	/* old break syscall holder */
+-	.long sys_stat
+-	.long sys_lseek
+-	.long sys_getpid		/* 20 */
+-	.long sys_mount
+-	.long sys_oldumount
+-	.long sys_setuid16
+-	.long sys_getuid16
+-	.long sys_stime		/* 25 */
+-	.long sys_ptrace
+-	.long sys_alarm
+-	.long sys_fstat
+-	.long sys_pause
+-	.long sys_utime		/* 30 */
+-	.long sys_ni_syscall	/* old stty syscall holder */
+-	.long sys_ni_syscall	/* old gtty syscall holder */
+-	.long sys_access
+-	.long sys_nice
+-	.long sys_ni_syscall	/* 35 */		/* old ftime syscall holder */
+-	.long sys_sync
+-	.long sys_kill
+-	.long sys_rename
+-	.long sys_mkdir
+-	.long sys_rmdir		/* 40 */
+-	.long sys_dup
+-	.long sys_pipe
+-	.long sys_times
+-	.long sys_ni_syscall	/* old prof syscall holder */
+-	.long sys_brk		/* 45 */
+-	.long sys_setgid16
+-	.long sys_getgid16
+-	.long sys_signal
+-	.long sys_geteuid16
+-	.long sys_getegid16	/* 50 */
+-	.long sys_acct
+-	.long sys_umount		/* recycled never used phys() */
+-	.long sys_ni_syscall	/* old lock syscall holder */
+-	.long sys_ioctl
+-	.long sys_fcntl		/* 55 */
+-	.long sys_ni_syscall	/* old mpx syscall holder */
+-	.long sys_setpgid
+-	.long sys_ni_syscall	/* old ulimit syscall holder */
+-	.long sys_ni_syscall	/* sys_olduname */
+-	.long sys_umask		/* 60 */
+-	.long sys_chroot
+-	.long sys_ustat
+-	.long sys_dup2
+-	.long sys_getppid
+-	.long sys_getpgrp		/* 65 */
+-	.long sys_setsid
+-	.long sys_sigaction
+-	.long sys_sgetmask
+-	.long sys_ssetmask
+-	.long sys_setreuid16	/* 70 */
+-	.long sys_setregid16
+-	.long sys_sigsuspend
+-	.long sys_sigpending
+-	.long sys_sethostname
+-	.long sys_setrlimit	/* 75 */
+-	.long sys_old_getrlimit
+-	.long sys_getrusage
+-	.long sys_gettimeofday
+-	.long sys_settimeofday
+-	.long sys_getgroups16	/* 80 */
+-	.long sys_setgroups16
+-	.long sys_ni_syscall	/* sys_oldselect */
+-	.long sys_symlink
+-	.long sys_lstat
+-	.long sys_readlink		/* 85 */
+-	.long sys_uselib
+-	.long sys_swapon
+-	.long sys_reboot
+-	.long old_readdir
+-	.long old_mmap		/* 90 */
+-	.long sys_munmap
+-	.long sys_truncate
+-	.long sys_ftruncate
+-	.long sys_fchmod
+-	.long sys_fchown16		/* 95 */
+-	.long sys_getpriority
+-	.long sys_setpriority
+-	.long sys_ni_syscall	/* old profil syscall holder */
+-	.long sys_statfs
+-	.long sys_fstatfs		/* 100 */
+-	.long sys_ni_syscall	/* ioperm */
+-	.long sys_socketcall
+-	.long sys_syslog
+-	.long sys_setitimer
+-	.long sys_getitimer	/* 105 */
+-	.long sys_newstat
+-	.long sys_newlstat
+-	.long sys_newfstat
+-	.long sys_uname
+-	.long sys_ni_syscall	/* 110 */ /* iopl */
+-	.long sys_vhangup
+-	.long sys_ni_syscall	/* idle */
+-	.long sys_ni_syscall	/* vm86old */
+-	.long sys_wait4
+-	.long sys_swapoff		/* 115 */
+-	.long sys_sysinfo
+-	.long sys_ipc
+-	.long sys_fsync
+-	.long sys_sigreturn
+-	.long sys_clone		/* 120 */
+-	.long sys_setdomainname
+-	.long sys_newuname
+-	.long sys_ni_syscall	/* sys_modify_ldt */
+-	.long sys_adjtimex
+-	.long sys_mprotect		/* 125 */
+-	.long sys_sigprocmask
+-	.long sys_ni_syscall	/* old "create_module" */
+-	.long sys_init_module
+-	.long sys_delete_module
+-	.long sys_ni_syscall	/* 130: old "get_kernel_syms" */
+-	.long sys_quotactl
+-	.long sys_getpgid
+-	.long sys_fchdir
+-	.long sys_bdflush
+-	.long sys_sysfs		/* 135 */
+-	.long sys_personality
+-	.long sys_ni_syscall	/* for afs_syscall */
+-	.long sys_setfsuid16
+-	.long sys_setfsgid16
+-	.long sys_llseek		/* 140 */
+-	.long sys_getdents
+-	.long sys_select
+-	.long sys_flock
+-	.long sys_msync
+-	.long sys_readv		/* 145 */
+-	.long sys_writev
+-	.long sys_getsid
+-	.long sys_fdatasync
+-	.long sys_sysctl
+-	.long sys_mlock		/* 150 */
+-	.long sys_munlock
+-	.long sys_mlockall
+-	.long sys_munlockall
+-	.long sys_sched_setparam
+-	.long sys_sched_getparam   /* 155 */
+-	.long sys_sched_setscheduler
+-	.long sys_sched_getscheduler
+-	.long sys_sched_yield
+-	.long sys_sched_get_priority_max
+-	.long sys_sched_get_priority_min  /* 160 */
+-	.long sys_sched_rr_get_interval
+-	.long sys_nanosleep
+-	.long sys_mremap
+-	.long sys_setresuid16
+-	.long sys_getresuid16	/* 165 */
+-	.long sys_ni_syscall	/* vm86 */
+-	.long sys_ni_syscall	/* old "query_module" */
+-	.long sys_poll
+-	.long sys_nfsservctl
+-	.long sys_setresgid16	/* 170 */
+-	.long sys_getresgid16
+-	.long sys_prctl
+-	.long sys_rt_sigreturn
+-	.long sys_rt_sigaction
+-	.long sys_rt_sigprocmask	/* 175 */
+-	.long sys_rt_sigpending
+-	.long sys_rt_sigtimedwait
+-	.long sys_rt_sigqueueinfo
+-	.long sys_rt_sigsuspend
+-	.long sys_pread_wrapper	   /* 180 */
+-	.long sys_pwrite_wrapper
+-	.long sys_chown16
+-	.long sys_getcwd
+-	.long sys_capget
+-	.long sys_capset           /* 185 */
+-	.long sys_sigaltstack
+-	.long sys_sendfile
+-	.long sys_ni_syscall	/* streams1 */
+-	.long sys_ni_syscall	/* streams2 */
+-	.long sys_vfork            /* 190 */
+-	.long sys_getrlimit
+-	.long sys_mmap2
+-	.long sys_truncate64
+-	.long sys_ftruncate64
+-	.long sys_stat64		/* 195 */
+-	.long sys_lstat64
+-	.long sys_fstat64
+-	.long sys_lchown
+-	.long sys_getuid
+-	.long sys_getgid		/* 200 */
+-	.long sys_geteuid
+-	.long sys_getegid
+-	.long sys_setreuid
+-	.long sys_setregid
+-	.long sys_getgroups	/* 205 */
+-	.long sys_setgroups
+-	.long sys_fchown
+-	.long sys_setresuid
+-	.long sys_getresuid
+-	.long sys_setresgid	/* 210 */
+-	.long sys_getresgid
+-	.long sys_chown
+-	.long sys_setuid
+-	.long sys_setgid
+-	.long sys_setfsuid		/* 215 */
+-	.long sys_setfsgid
+-	.long sys_pivot_root
+-	.long sys_mincore
+-	.long sys_madvise
+-	.long sys_getdents64	/* 220 */
+-	.long sys_fcntl64
+-	.long sys_ni_syscall	/* reserved for TUX */
+-	.long sys_ni_syscall	/* Reserved for Security */
+-	.long sys_gettid
+-	.long sys_readahead	/* 225 */
+-	.long sys_setxattr
+-	.long sys_lsetxattr
+-	.long sys_fsetxattr
+-	.long sys_getxattr
+-	.long sys_lgetxattr	/* 230 */
+-	.long sys_fgetxattr
+-	.long sys_listxattr
+-	.long sys_llistxattr
+-	.long sys_flistxattr
+-	.long sys_removexattr	/* 235 */
+-	.long sys_lremovexattr
+-	.long sys_fremovexattr
+-	.long sys_tkill
+-	.long sys_sendfile64
+-	.long sys_futex		/* 240 */
+-	.long sys_sched_setaffinity
+-	.long sys_sched_getaffinity
+-	.long sys_ni_syscall
+-	.long sys_ni_syscall
+-	.long sys_io_setup	/* 245 */
+-	.long sys_io_destroy
+-	.long sys_io_getevents
+-	.long sys_io_submit
+-	.long sys_io_cancel
+-	.long sys_fadvise64	/* 250 */
+-	.long sys_ni_syscall
+-	.long sys_exit_group
+-	.long sys_lookup_dcookie
+-	.long sys_epoll_create
+-	.long sys_epoll_ctl	/* 255 */
+-	.long sys_epoll_wait
+- 	.long sys_remap_file_pages
+- 	.long sys_set_tid_address
+- 	.long sys_timer_create
+- 	.long sys_timer_settime		/* 260 */
+- 	.long sys_timer_gettime
+- 	.long sys_timer_getoverrun
+- 	.long sys_timer_delete
+- 	.long sys_clock_settime
+- 	.long sys_clock_gettime		/* 265 */
+- 	.long sys_clock_getres
+- 	.long sys_clock_nanosleep
+-	.long sys_statfs64
+-	.long sys_fstatfs64
+-	.long sys_tgkill		/* 270 */
+-	.long sys_utimes
+- 	.long sys_fadvise64_64_wrapper
+-	.long sys_ni_syscall	/* Reserved for vserver */
+-	.long sys_mbind
+-	.long sys_get_mempolicy		/* 275 */
+-	.long sys_set_mempolicy
+-	.long sys_mq_open
+-	.long sys_mq_unlink
+-	.long sys_mq_timedsend
+-	.long sys_mq_timedreceive       /* 280 */
+-	.long sys_mq_notify
+-	.long sys_mq_getsetattr
+-	.long sys_kexec_load
+-	.long sys_waitid
+-	.long sys_add_key		/* 285 */
+-	.long sys_request_key
+-	.long sys_keyctl
+-	.long sys_ioprio_set
+-	.long sys_ioprio_get
+-	.long sys_inotify_init		/* 290 */
+-	.long sys_inotify_add_watch
+-	.long sys_inotify_rm_watch
+-	.long sys_ni_syscall
+-	.long sys_migrate_pages
+-	.long sys_openat		/* 295 */
+-	.long sys_mkdirat
+-	.long sys_mknodat
+-	.long sys_fchownat
+-	.long sys_futimesat
+-	.long sys_fstatat64		/* 300 */
+-	.long sys_unlinkat
+-	.long sys_renameat
+-	.long sys_linkat
+-	.long sys_symlinkat
+-	.long sys_readlinkat		/* 305 */
+-	.long sys_fchmodat
+-	.long sys_faccessat
+-	.long sys_pselect6
+-	.long sys_ppoll
+-	.long sys_unshare		/* 310 */
+-	.long sys_set_robust_list
+-	.long sys_get_robust_list
+-	.long sys_splice
+-	.long sys_sync_file_range
+-	.long sys_tee			/* 315 */
+-	.long sys_vmsplice
+-	.long sys_move_pages
+-	.long sys_getcpu
+-	.long sys_epoll_pwait
+-	.long sys_utimensat		/* 320 */
+-	.long sys_signalfd
+-	.long sys_timerfd
+-	.long sys_eventfd
+-	.long sys_fallocate
+diff --git a/arch/sh/kernel/syscalls_32.S b/arch/sh/kernel/syscalls_32.S
+new file mode 100644
+index 0000000..10bec45
+--- /dev/null
++++ b/arch/sh/kernel/syscalls_32.S
+@@ -0,0 +1,343 @@
++/*
++ * arch/sh/kernel/syscalls.S
++ *
++ * System call table for SuperH
++ *
++ *  Copyright (C) 1999, 2000, 2002  Niibe Yutaka
++ *  Copyright (C) 2003  Paul Mundt
++ *
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License.  See the file "COPYING" in the main directory of this archive
++ * for more details.
++ *
++ */
++#include <linux/sys.h>
++#include <linux/linkage.h>
++
++	.data
++ENTRY(sys_call_table)
++	.long sys_restart_syscall	/* 0  -  old "setup()" system call*/
++	.long sys_exit
++	.long sys_fork
++	.long sys_read
++	.long sys_write
++	.long sys_open		/* 5 */
++	.long sys_close
++	.long sys_waitpid
++	.long sys_creat
++	.long sys_link
++	.long sys_unlink		/* 10 */
++	.long sys_execve
++	.long sys_chdir
++	.long sys_time
++	.long sys_mknod
++	.long sys_chmod		/* 15 */
++	.long sys_lchown16
++	.long sys_ni_syscall	/* old break syscall holder */
++	.long sys_stat
++	.long sys_lseek
++	.long sys_getpid		/* 20 */
++	.long sys_mount
++	.long sys_oldumount
++	.long sys_setuid16
++	.long sys_getuid16
++	.long sys_stime		/* 25 */
++	.long sys_ptrace
++	.long sys_alarm
++	.long sys_fstat
++	.long sys_pause
++	.long sys_utime		/* 30 */
++	.long sys_ni_syscall	/* old stty syscall holder */
++	.long sys_ni_syscall	/* old gtty syscall holder */
++	.long sys_access
++	.long sys_nice
++	.long sys_ni_syscall	/* 35 */		/* old ftime syscall holder */
++	.long sys_sync
++	.long sys_kill
++	.long sys_rename
++	.long sys_mkdir
++	.long sys_rmdir		/* 40 */
++	.long sys_dup
++	.long sys_pipe
++	.long sys_times
++	.long sys_ni_syscall	/* old prof syscall holder */
++	.long sys_brk		/* 45 */
++	.long sys_setgid16
++	.long sys_getgid16
++	.long sys_signal
++	.long sys_geteuid16
++	.long sys_getegid16	/* 50 */
++	.long sys_acct
++	.long sys_umount		/* recycled never used phys() */
++	.long sys_ni_syscall	/* old lock syscall holder */
++	.long sys_ioctl
++	.long sys_fcntl		/* 55 */
++	.long sys_ni_syscall	/* old mpx syscall holder */
++	.long sys_setpgid
++	.long sys_ni_syscall	/* old ulimit syscall holder */
++	.long sys_ni_syscall	/* sys_olduname */
++	.long sys_umask		/* 60 */
++	.long sys_chroot
++	.long sys_ustat
++	.long sys_dup2
++	.long sys_getppid
++	.long sys_getpgrp		/* 65 */
++	.long sys_setsid
++	.long sys_sigaction
++	.long sys_sgetmask
++	.long sys_ssetmask
++	.long sys_setreuid16	/* 70 */
++	.long sys_setregid16
++	.long sys_sigsuspend
++	.long sys_sigpending
++	.long sys_sethostname
++	.long sys_setrlimit	/* 75 */
++	.long sys_old_getrlimit
++	.long sys_getrusage
++	.long sys_gettimeofday
++	.long sys_settimeofday
++	.long sys_getgroups16	/* 80 */
++	.long sys_setgroups16
++	.long sys_ni_syscall	/* sys_oldselect */
++	.long sys_symlink
++	.long sys_lstat
++	.long sys_readlink		/* 85 */
++	.long sys_uselib
++	.long sys_swapon
++	.long sys_reboot
++	.long old_readdir
++	.long old_mmap		/* 90 */
++	.long sys_munmap
++	.long sys_truncate
++	.long sys_ftruncate
++	.long sys_fchmod
++	.long sys_fchown16		/* 95 */
++	.long sys_getpriority
++	.long sys_setpriority
++	.long sys_ni_syscall	/* old profil syscall holder */
++	.long sys_statfs
++	.long sys_fstatfs		/* 100 */
++	.long sys_ni_syscall	/* ioperm */
++	.long sys_socketcall
++	.long sys_syslog
++	.long sys_setitimer
++	.long sys_getitimer	/* 105 */
++	.long sys_newstat
++	.long sys_newlstat
++	.long sys_newfstat
++	.long sys_uname
++	.long sys_ni_syscall	/* 110 */ /* iopl */
++	.long sys_vhangup
++	.long sys_ni_syscall	/* idle */
++	.long sys_ni_syscall	/* vm86old */
++	.long sys_wait4
++	.long sys_swapoff		/* 115 */
++	.long sys_sysinfo
++	.long sys_ipc
++	.long sys_fsync
++	.long sys_sigreturn
++	.long sys_clone		/* 120 */
++	.long sys_setdomainname
++	.long sys_newuname
++	.long sys_ni_syscall	/* sys_modify_ldt */
++	.long sys_adjtimex
++	.long sys_mprotect		/* 125 */
++	.long sys_sigprocmask
++	.long sys_ni_syscall	/* old "create_module" */
++	.long sys_init_module
++	.long sys_delete_module
++	.long sys_ni_syscall	/* 130: old "get_kernel_syms" */
++	.long sys_quotactl
++	.long sys_getpgid
++	.long sys_fchdir
++	.long sys_bdflush
++	.long sys_sysfs		/* 135 */
++	.long sys_personality
++	.long sys_ni_syscall	/* for afs_syscall */
++	.long sys_setfsuid16
++	.long sys_setfsgid16
++	.long sys_llseek		/* 140 */
++	.long sys_getdents
++	.long sys_select
++	.long sys_flock
++	.long sys_msync
++	.long sys_readv		/* 145 */
++	.long sys_writev
++	.long sys_getsid
++	.long sys_fdatasync
++	.long sys_sysctl
++	.long sys_mlock		/* 150 */
++	.long sys_munlock
++	.long sys_mlockall
++	.long sys_munlockall
++	.long sys_sched_setparam
++	.long sys_sched_getparam   /* 155 */
++	.long sys_sched_setscheduler
++	.long sys_sched_getscheduler
++	.long sys_sched_yield
++	.long sys_sched_get_priority_max
++	.long sys_sched_get_priority_min  /* 160 */
++	.long sys_sched_rr_get_interval
++	.long sys_nanosleep
++	.long sys_mremap
++	.long sys_setresuid16
++	.long sys_getresuid16	/* 165 */
++	.long sys_ni_syscall	/* vm86 */
++	.long sys_ni_syscall	/* old "query_module" */
++	.long sys_poll
++	.long sys_nfsservctl
++	.long sys_setresgid16	/* 170 */
++	.long sys_getresgid16
++	.long sys_prctl
++	.long sys_rt_sigreturn
++	.long sys_rt_sigaction
++	.long sys_rt_sigprocmask	/* 175 */
++	.long sys_rt_sigpending
++	.long sys_rt_sigtimedwait
++	.long sys_rt_sigqueueinfo
++	.long sys_rt_sigsuspend
++	.long sys_pread_wrapper	   /* 180 */
++	.long sys_pwrite_wrapper
++	.long sys_chown16
++	.long sys_getcwd
++	.long sys_capget
++	.long sys_capset           /* 185 */
++	.long sys_sigaltstack
++	.long sys_sendfile
++	.long sys_ni_syscall	/* streams1 */
++	.long sys_ni_syscall	/* streams2 */
++	.long sys_vfork            /* 190 */
++	.long sys_getrlimit
++	.long sys_mmap2
++	.long sys_truncate64
++	.long sys_ftruncate64
++	.long sys_stat64		/* 195 */
++	.long sys_lstat64
++	.long sys_fstat64
++	.long sys_lchown
++	.long sys_getuid
++	.long sys_getgid		/* 200 */
++	.long sys_geteuid
++	.long sys_getegid
++	.long sys_setreuid
++	.long sys_setregid
++	.long sys_getgroups	/* 205 */
++	.long sys_setgroups
++	.long sys_fchown
++	.long sys_setresuid
++	.long sys_getresuid
++	.long sys_setresgid	/* 210 */
++	.long sys_getresgid
++	.long sys_chown
++	.long sys_setuid
++	.long sys_setgid
++	.long sys_setfsuid		/* 215 */
++	.long sys_setfsgid
++	.long sys_pivot_root
++	.long sys_mincore
++	.long sys_madvise
++	.long sys_getdents64	/* 220 */
++	.long sys_fcntl64
++	.long sys_ni_syscall	/* reserved for TUX */
++	.long sys_ni_syscall	/* Reserved for Security */
++	.long sys_gettid
++	.long sys_readahead	/* 225 */
++	.long sys_setxattr
++	.long sys_lsetxattr
++	.long sys_fsetxattr
++	.long sys_getxattr
++	.long sys_lgetxattr	/* 230 */
++	.long sys_fgetxattr
++	.long sys_listxattr
++	.long sys_llistxattr
++	.long sys_flistxattr
++	.long sys_removexattr	/* 235 */
++	.long sys_lremovexattr
++	.long sys_fremovexattr
++	.long sys_tkill
++	.long sys_sendfile64
++	.long sys_futex		/* 240 */
++	.long sys_sched_setaffinity
++	.long sys_sched_getaffinity
++	.long sys_ni_syscall
++	.long sys_ni_syscall
++	.long sys_io_setup	/* 245 */
++	.long sys_io_destroy
++	.long sys_io_getevents
++	.long sys_io_submit
++	.long sys_io_cancel
++	.long sys_fadvise64	/* 250 */
++	.long sys_ni_syscall
++	.long sys_exit_group
++	.long sys_lookup_dcookie
++	.long sys_epoll_create
++	.long sys_epoll_ctl	/* 255 */
++	.long sys_epoll_wait
++ 	.long sys_remap_file_pages
++ 	.long sys_set_tid_address
++ 	.long sys_timer_create
++ 	.long sys_timer_settime		/* 260 */
++ 	.long sys_timer_gettime
++ 	.long sys_timer_getoverrun
++ 	.long sys_timer_delete
++ 	.long sys_clock_settime
++ 	.long sys_clock_gettime		/* 265 */
++ 	.long sys_clock_getres
++ 	.long sys_clock_nanosleep
++	.long sys_statfs64
++	.long sys_fstatfs64
++	.long sys_tgkill		/* 270 */
++	.long sys_utimes
++ 	.long sys_fadvise64_64_wrapper
++	.long sys_ni_syscall	/* Reserved for vserver */
++	.long sys_mbind
++	.long sys_get_mempolicy		/* 275 */
++	.long sys_set_mempolicy
++	.long sys_mq_open
++	.long sys_mq_unlink
++	.long sys_mq_timedsend
++	.long sys_mq_timedreceive       /* 280 */
++	.long sys_mq_notify
++	.long sys_mq_getsetattr
++	.long sys_kexec_load
++	.long sys_waitid
++	.long sys_add_key		/* 285 */
++	.long sys_request_key
++	.long sys_keyctl
++	.long sys_ioprio_set
++	.long sys_ioprio_get
++	.long sys_inotify_init		/* 290 */
++	.long sys_inotify_add_watch
++	.long sys_inotify_rm_watch
++	.long sys_ni_syscall
++	.long sys_migrate_pages
++	.long sys_openat		/* 295 */
++	.long sys_mkdirat
++	.long sys_mknodat
++	.long sys_fchownat
++	.long sys_futimesat
++	.long sys_fstatat64		/* 300 */
++	.long sys_unlinkat
++	.long sys_renameat
++	.long sys_linkat
++	.long sys_symlinkat
++	.long sys_readlinkat		/* 305 */
++	.long sys_fchmodat
++	.long sys_faccessat
++	.long sys_pselect6
++	.long sys_ppoll
++	.long sys_unshare		/* 310 */
++	.long sys_set_robust_list
++	.long sys_get_robust_list
++	.long sys_splice
++	.long sys_sync_file_range
++	.long sys_tee			/* 315 */
++	.long sys_vmsplice
++	.long sys_move_pages
++	.long sys_getcpu
++	.long sys_epoll_pwait
++	.long sys_utimensat		/* 320 */
++	.long sys_signalfd
++	.long sys_timerfd
++	.long sys_eventfd
++	.long sys_fallocate
+diff --git a/arch/sh/kernel/syscalls_64.S b/arch/sh/kernel/syscalls_64.S
+new file mode 100644
+index 0000000..98a93ef
+--- /dev/null
++++ b/arch/sh/kernel/syscalls_64.S
+@@ -0,0 +1,381 @@
++/*
++ * arch/sh/kernel/syscalls_64.S
++ *
++ * Copyright (C) 2000, 2001  Paolo Alberelli
++ * Copyright (C) 2004 - 2007  Paul Mundt
++ * Copyright (C) 2003, 2004 Richard Curnow
++ *
++ * 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/sys.h>
++
++	.section .data, "aw"
++	.balign 32
++
++/*
++ * System calls jump table
++ */
++	.globl  sys_call_table
++sys_call_table:
++	.long sys_restart_syscall	/* 0  -  old "setup()" system call  */
++	.long sys_exit
++	.long sys_fork
++	.long sys_read
++	.long sys_write
++	.long sys_open			/* 5 */
++	.long sys_close
++	.long sys_waitpid
++	.long sys_creat
++	.long sys_link
++	.long sys_unlink		/* 10 */
++	.long sys_execve
++	.long sys_chdir
++	.long sys_time
++	.long sys_mknod
++	.long sys_chmod			/* 15 */
++	.long sys_lchown16
++	.long sys_ni_syscall	/* old break syscall holder */
++	.long sys_stat
++	.long sys_lseek
++	.long sys_getpid		/* 20 */
++	.long sys_mount
++	.long sys_oldumount
++	.long sys_setuid16
++	.long sys_getuid16
++	.long sys_stime			/* 25 */
++	.long sh64_ptrace
++	.long sys_alarm
++	.long sys_fstat
++	.long sys_pause
++	.long sys_utime			/* 30 */
++	.long sys_ni_syscall	/* old stty syscall holder */
++	.long sys_ni_syscall	/* old gtty syscall holder */
++	.long sys_access
++	.long sys_nice
++	.long sys_ni_syscall		/* 35 */ /* old ftime syscall holder */
++	.long sys_sync
++	.long sys_kill
++	.long sys_rename
++	.long sys_mkdir
++	.long sys_rmdir			/* 40 */
++	.long sys_dup
++	.long sys_pipe
++	.long sys_times
++	.long sys_ni_syscall	/* old prof syscall holder */
++	.long sys_brk			/* 45 */
++	.long sys_setgid16
++	.long sys_getgid16
++	.long sys_signal
++	.long sys_geteuid16
++	.long sys_getegid16		/* 50 */
++	.long sys_acct
++	.long sys_umount		/* recycled never used phys( */
++	.long sys_ni_syscall	/* old lock syscall holder */
++	.long sys_ioctl
++	.long sys_fcntl			/* 55 */
++	.long sys_ni_syscall	/* old mpx syscall holder */
++	.long sys_setpgid
++	.long sys_ni_syscall	/* old ulimit syscall holder */
++	.long sys_ni_syscall	/* sys_olduname */
++	.long sys_umask			/* 60 */
++	.long sys_chroot
++	.long sys_ustat
++	.long sys_dup2
++	.long sys_getppid
++	.long sys_getpgrp		/* 65 */
++	.long sys_setsid
++	.long sys_sigaction
++	.long sys_sgetmask
++	.long sys_ssetmask
++	.long sys_setreuid16		/* 70 */
++	.long sys_setregid16
++	.long sys_sigsuspend
++	.long sys_sigpending
++	.long sys_sethostname
++	.long sys_setrlimit		/* 75 */
++	.long sys_old_getrlimit
++	.long sys_getrusage
++	.long sys_gettimeofday
++	.long sys_settimeofday
++	.long sys_getgroups16		/* 80 */
++	.long sys_setgroups16
++	.long sys_ni_syscall	/* sys_oldselect */
++	.long sys_symlink
++	.long sys_lstat
++	.long sys_readlink		/* 85 */
++	.long sys_uselib
++	.long sys_swapon
++	.long sys_reboot
++	.long old_readdir
++	.long old_mmap			/* 90 */
++	.long sys_munmap
++	.long sys_truncate
++	.long sys_ftruncate
++	.long sys_fchmod
++	.long sys_fchown16		/* 95 */
++	.long sys_getpriority
++	.long sys_setpriority
++	.long sys_ni_syscall	/* old profil syscall holder */
++	.long sys_statfs
++	.long sys_fstatfs		/* 100 */
++	.long sys_ni_syscall	/* ioperm */
++	.long sys_socketcall	/* Obsolete implementation of socket syscall */
++	.long sys_syslog
++	.long sys_setitimer
++	.long sys_getitimer		/* 105 */
++	.long sys_newstat
++	.long sys_newlstat
++	.long sys_newfstat
++	.long sys_uname
++	.long sys_ni_syscall		/* 110 */ /* iopl */
++	.long sys_vhangup
++	.long sys_ni_syscall	/* idle */
++	.long sys_ni_syscall	/* vm86old */
++	.long sys_wait4
++	.long sys_swapoff		/* 115 */
++	.long sys_sysinfo
++	.long sys_ipc		/* Obsolete ipc syscall implementation */
++	.long sys_fsync
++	.long sys_sigreturn
++	.long sys_clone			/* 120 */
++	.long sys_setdomainname
++	.long sys_newuname
++	.long sys_ni_syscall	/* sys_modify_ldt */
++	.long sys_adjtimex
++	.long sys_mprotect		/* 125 */
++	.long sys_sigprocmask
++	.long sys_ni_syscall		/* old "create_module" */
++	.long sys_init_module
++	.long sys_delete_module
++	.long sys_ni_syscall		/* 130: old "get_kernel_syms" */
++	.long sys_quotactl
++	.long sys_getpgid
++	.long sys_fchdir
++	.long sys_bdflush
++	.long sys_sysfs			/* 135 */
++	.long sys_personality
++	.long sys_ni_syscall	/* for afs_syscall */
++	.long sys_setfsuid16
++	.long sys_setfsgid16
++	.long sys_llseek		/* 140 */
++	.long sys_getdents
++	.long sys_select
++	.long sys_flock
++	.long sys_msync
++	.long sys_readv			/* 145 */
++	.long sys_writev
++	.long sys_getsid
++	.long sys_fdatasync
++	.long sys_sysctl
++	.long sys_mlock			/* 150 */
++	.long sys_munlock
++	.long sys_mlockall
++	.long sys_munlockall
++	.long sys_sched_setparam
++	.long sys_sched_getparam	/* 155 */
++	.long sys_sched_setscheduler
++	.long sys_sched_getscheduler
++	.long sys_sched_yield
++	.long sys_sched_get_priority_max
++	.long sys_sched_get_priority_min  /* 160 */
++	.long sys_sched_rr_get_interval
++	.long sys_nanosleep
++	.long sys_mremap
++	.long sys_setresuid16
++	.long sys_getresuid16		/* 165 */
++	.long sys_ni_syscall	/* vm86 */
++	.long sys_ni_syscall	/* old "query_module" */
++	.long sys_poll
++	.long sys_nfsservctl
++	.long sys_setresgid16		/* 170 */
++	.long sys_getresgid16
++	.long sys_prctl
++	.long sys_rt_sigreturn
++	.long sys_rt_sigaction
++	.long sys_rt_sigprocmask	/* 175 */
++	.long sys_rt_sigpending
++	.long sys_rt_sigtimedwait
++	.long sys_rt_sigqueueinfo
++	.long sys_rt_sigsuspend
++	.long sys_pread64		/* 180 */
++	.long sys_pwrite64
++	.long sys_chown16
++	.long sys_getcwd
++	.long sys_capget
++	.long sys_capset		/* 185 */
++	.long sys_sigaltstack
++	.long sys_sendfile
++	.long sys_ni_syscall	/* streams1 */
++	.long sys_ni_syscall	/* streams2 */
++	.long sys_vfork			/* 190 */
++	.long sys_getrlimit
++	.long sys_mmap2
++	.long sys_truncate64
++	.long sys_ftruncate64
++	.long sys_stat64		/* 195 */
++	.long sys_lstat64
++	.long sys_fstat64
++	.long sys_lchown
++	.long sys_getuid
++	.long sys_getgid		/* 200 */
++	.long sys_geteuid
++	.long sys_getegid
++	.long sys_setreuid
++	.long sys_setregid
++	.long sys_getgroups		/* 205 */
++	.long sys_setgroups
++	.long sys_fchown
++	.long sys_setresuid
++	.long sys_getresuid
++	.long sys_setresgid		/* 210 */
++	.long sys_getresgid
++	.long sys_chown
++	.long sys_setuid
++	.long sys_setgid
++	.long sys_setfsuid		/* 215 */
++	.long sys_setfsgid
++	.long sys_pivot_root
++	.long sys_mincore
++	.long sys_madvise
++	/* Broken-out socket family (maintain backwards compatibility in syscall
++	   numbering with 2.4) */
++	.long sys_socket		/* 220 */
++	.long sys_bind
++	.long sys_connect
++	.long sys_listen
++	.long sys_accept
++	.long sys_getsockname		/* 225 */
++	.long sys_getpeername
++	.long sys_socketpair
++	.long sys_send
++	.long sys_sendto
++	.long sys_recv			/* 230*/
++	.long sys_recvfrom
++	.long sys_shutdown
++	.long sys_setsockopt
++	.long sys_getsockopt
++	.long sys_sendmsg		/* 235 */
++	.long sys_recvmsg
++	/* Broken-out IPC family (maintain backwards compatibility in syscall
++	   numbering with 2.4) */
++	.long sys_semop
++	.long sys_semget
++	.long sys_semctl
++	.long sys_msgsnd		/* 240 */
++	.long sys_msgrcv
++	.long sys_msgget
++	.long sys_msgctl
++	.long sys_shmat
++	.long sys_shmdt			/* 245 */
++	.long sys_shmget
++	.long sys_shmctl
++	/* Rest of syscalls listed in 2.4 i386 unistd.h */
++	.long sys_getdents64
++	.long sys_fcntl64
++	.long sys_ni_syscall		/* 250 reserved for TUX */
++	.long sys_ni_syscall		/* Reserved for Security */
++	.long sys_gettid
++	.long sys_readahead
++	.long sys_setxattr
++	.long sys_lsetxattr		/* 255 */
++	.long sys_fsetxattr
++	.long sys_getxattr
++	.long sys_lgetxattr
++	.long sys_fgetxattr
++	.long sys_listxattr		/* 260 */
++	.long sys_llistxattr
++	.long sys_flistxattr
++	.long sys_removexattr
++	.long sys_lremovexattr
++	.long sys_fremovexattr  	/* 265 */
++	.long sys_tkill
++	.long sys_sendfile64
++	.long sys_futex
++	.long sys_sched_setaffinity
++	.long sys_sched_getaffinity	/* 270 */
++	.long sys_ni_syscall
++	.long sys_ni_syscall
++	.long sys_io_setup
++	.long sys_io_destroy
++	.long sys_io_getevents		/* 275 */
++	.long sys_io_submit
++	.long sys_io_cancel
++	.long sys_fadvise64
++	.long sys_ni_syscall
++	.long sys_exit_group		/* 280 */
++	/* Rest of new 2.6 syscalls */
++	.long sys_lookup_dcookie
++	.long sys_epoll_create
++	.long sys_epoll_ctl
++	.long sys_epoll_wait
++ 	.long sys_remap_file_pages	/* 285 */
++ 	.long sys_set_tid_address
++ 	.long sys_timer_create
++ 	.long sys_timer_settime
++ 	.long sys_timer_gettime
++ 	.long sys_timer_getoverrun	/* 290 */
++ 	.long sys_timer_delete
++ 	.long sys_clock_settime
++ 	.long sys_clock_gettime
++ 	.long sys_clock_getres
++ 	.long sys_clock_nanosleep	/* 295 */
++	.long sys_statfs64
++	.long sys_fstatfs64
++	.long sys_tgkill
++	.long sys_utimes
++ 	.long sys_fadvise64_64		/* 300 */
++	.long sys_ni_syscall	/* Reserved for vserver */
++	.long sys_ni_syscall	/* Reserved for mbind */
++	.long sys_ni_syscall	/* get_mempolicy */
++	.long sys_ni_syscall	/* set_mempolicy */
++	.long sys_mq_open		/* 305 */
++	.long sys_mq_unlink
++	.long sys_mq_timedsend
++	.long sys_mq_timedreceive
++	.long sys_mq_notify
++	.long sys_mq_getsetattr		/* 310 */
++	.long sys_ni_syscall	/* Reserved for kexec */
++	.long sys_waitid
++	.long sys_add_key
++	.long sys_request_key
++	.long sys_keyctl		/* 315 */
++	.long sys_ioprio_set
++	.long sys_ioprio_get
++	.long sys_inotify_init
++	.long sys_inotify_add_watch
++	.long sys_inotify_rm_watch	/* 320 */
++	.long sys_ni_syscall
++	.long sys_migrate_pages
++	.long sys_openat
++	.long sys_mkdirat
++	.long sys_mknodat		/* 325 */
++	.long sys_fchownat
++	.long sys_futimesat
++	.long sys_fstatat64
++	.long sys_unlinkat
++	.long sys_renameat		/* 330 */
++	.long sys_linkat
++	.long sys_symlinkat
++	.long sys_readlinkat
++	.long sys_fchmodat
++	.long sys_faccessat		/* 335 */
++	.long sys_pselect6
++	.long sys_ppoll
++	.long sys_unshare
++	.long sys_set_robust_list
++	.long sys_get_robust_list	/* 340 */
++	.long sys_splice
++	.long sys_sync_file_range
++	.long sys_tee
++	.long sys_vmsplice
++	.long sys_move_pages		/* 345 */
++	.long sys_getcpu
++	.long sys_epoll_pwait
++	.long sys_utimensat
++	.long sys_signalfd
++	.long sys_timerfd		/* 350 */
++	.long sys_eventfd
++	.long sys_fallocate
+diff --git a/arch/sh/kernel/time.c b/arch/sh/kernel/time.c
+deleted file mode 100644
+index a3a67d1..0000000
+--- a/arch/sh/kernel/time.c
++++ /dev/null
+@@ -1,269 +0,0 @@
+-/*
+- *  arch/sh/kernel/time.c
+- *
+- *  Copyright (C) 1999  Tetsuya Okada & Niibe Yutaka
+- *  Copyright (C) 2000  Philipp Rumpf <prumpf at tux.org>
+- *  Copyright (C) 2002 - 2007  Paul Mundt
+- *  Copyright (C) 2002  M. R. Brown  <mrbrown at linux-sh.org>
+- *
+- *  Some code taken from i386 version.
+- *    Copyright (C) 1991, 1992, 1995  Linus Torvalds
+- */
+-#include <linux/kernel.h>
+-#include <linux/module.h>
+-#include <linux/init.h>
+-#include <linux/profile.h>
+-#include <linux/timex.h>
+-#include <linux/sched.h>
+-#include <linux/clockchips.h>
+-#include <asm/clock.h>
+-#include <asm/rtc.h>
+-#include <asm/timer.h>
+-#include <asm/kgdb.h>
+-
+-struct sys_timer *sys_timer;
+-
+-/* Move this somewhere more sensible.. */
+-DEFINE_SPINLOCK(rtc_lock);
+-EXPORT_SYMBOL(rtc_lock);
+-
+-/* Dummy RTC ops */
+-static void null_rtc_get_time(struct timespec *tv)
+-{
+-	tv->tv_sec = mktime(2000, 1, 1, 0, 0, 0);
+-	tv->tv_nsec = 0;
+-}
+-
+-static int null_rtc_set_time(const time_t secs)
+-{
+-	return 0;
+-}
+-
+-/*
+- * Null high precision timer functions for systems lacking one.
+- */
+-static cycle_t null_hpt_read(void)
+-{
+-	return 0;
+-}
+-
+-void (*rtc_sh_get_time)(struct timespec *) = null_rtc_get_time;
+-int (*rtc_sh_set_time)(const time_t) = null_rtc_set_time;
+-
+-#ifndef CONFIG_GENERIC_TIME
+-void do_gettimeofday(struct timeval *tv)
+-{
+-	unsigned long flags;
+-	unsigned long seq;
+-	unsigned long usec, sec;
+-
+-	do {
+-		/*
+-		 * Turn off IRQs when grabbing xtime_lock, so that
+-		 * the sys_timer get_offset code doesn't have to handle it.
+-		 */
+-		seq = read_seqbegin_irqsave(&xtime_lock, flags);
+-		usec = get_timer_offset();
+-		sec = xtime.tv_sec;
+-		usec += xtime.tv_nsec / NSEC_PER_USEC;
+-	} while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
+-
+-	while (usec >= 1000000) {
+-		usec -= 1000000;
+-		sec++;
+-	}
+-
+-	tv->tv_sec = sec;
+-	tv->tv_usec = usec;
+-}
+-EXPORT_SYMBOL(do_gettimeofday);
+-
+-int do_settimeofday(struct timespec *tv)
+-{
+-	time_t wtm_sec, sec = tv->tv_sec;
+-	long wtm_nsec, nsec = tv->tv_nsec;
+-
+-	if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC)
+-		return -EINVAL;
+-
+-	write_seqlock_irq(&xtime_lock);
+-	/*
+-	 * This is revolting. We need to set "xtime" correctly. However, the
+-	 * value in this location is the value at the most recent update of
+-	 * wall time.  Discover what correction gettimeofday() would have
+-	 * made, and then undo it!
+-	 */
+-	nsec -= get_timer_offset() * NSEC_PER_USEC;
+-
+-	wtm_sec  = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec);
+-	wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec);
+-
+-	set_normalized_timespec(&xtime, sec, nsec);
+-	set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);
+-
+-	ntp_clear();
+-	write_sequnlock_irq(&xtime_lock);
+-	clock_was_set();
+-
+-	return 0;
+-}
+-EXPORT_SYMBOL(do_settimeofday);
+-#endif /* !CONFIG_GENERIC_TIME */
+-
+-#ifndef CONFIG_GENERIC_CLOCKEVENTS
+-/* last time the RTC clock got updated */
+-static long last_rtc_update;
+-
+-/*
+- * handle_timer_tick() needs to keep up the real-time clock,
+- * as well as call the "do_timer()" routine every clocktick
+- */
+-void handle_timer_tick(void)
+-{
+-	do_timer(1);
+-#ifndef CONFIG_SMP
+-	update_process_times(user_mode(get_irq_regs()));
+-#endif
+-	if (current->pid)
+-		profile_tick(CPU_PROFILING);
+-
+-#ifdef CONFIG_HEARTBEAT
+-	if (sh_mv.mv_heartbeat != NULL)
+-		sh_mv.mv_heartbeat();
+-#endif
+-
+-	/*
+-	 * If we have an externally synchronized Linux clock, then update
+-	 * RTC clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
+-	 * called as close as possible to 500 ms before the new second starts.
+-	 */
+-	if (ntp_synced() &&
+-	    xtime.tv_sec > last_rtc_update + 660 &&
+-	    (xtime.tv_nsec / 1000) >= 500000 - ((unsigned) TICK_SIZE) / 2 &&
+-	    (xtime.tv_nsec / 1000) <= 500000 + ((unsigned) TICK_SIZE) / 2) {
+-		if (rtc_sh_set_time(xtime.tv_sec) == 0)
+-			last_rtc_update = xtime.tv_sec;
+-		else
+-			/* do it again in 60s */
+-			last_rtc_update = xtime.tv_sec - 600;
+-	}
+-}
+-#endif /* !CONFIG_GENERIC_CLOCKEVENTS */
+-
+-#ifdef CONFIG_PM
+-int timer_suspend(struct sys_device *dev, pm_message_t state)
+-{
+-	struct sys_timer *sys_timer = container_of(dev, struct sys_timer, dev);
+-
+-	sys_timer->ops->stop();
+-
+-	return 0;
+-}
+-
+-int timer_resume(struct sys_device *dev)
+-{
+-	struct sys_timer *sys_timer = container_of(dev, struct sys_timer, dev);
+-
+-	sys_timer->ops->start();
+-
+-	return 0;
+-}
+-#else
+-#define timer_suspend NULL
+-#define timer_resume NULL
+-#endif
+-
+-static struct sysdev_class timer_sysclass = {
+-	set_kset_name("timer"),
+-	.suspend = timer_suspend,
+-	.resume	 = timer_resume,
+-};
+-
+-static int __init timer_init_sysfs(void)
+-{
+-	int ret = sysdev_class_register(&timer_sysclass);
+-	if (ret != 0)
+-		return ret;
+-
+-	sys_timer->dev.cls = &timer_sysclass;
+-	return sysdev_register(&sys_timer->dev);
+-}
+-device_initcall(timer_init_sysfs);
+-
+-void (*board_time_init)(void);
+-
+-/*
+- * Shamelessly based on the MIPS and Sparc64 work.
+- */
+-static unsigned long timer_ticks_per_nsec_quotient __read_mostly;
+-unsigned long sh_hpt_frequency = 0;
+-
+-#define NSEC_PER_CYC_SHIFT	10
+-
+-struct clocksource clocksource_sh = {
+-	.name		= "SuperH",
+-	.rating		= 200,
+-	.mask		= CLOCKSOURCE_MASK(32),
+-	.read		= null_hpt_read,
+-	.shift		= 16,
+-	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
+-};
+-
+-static void __init init_sh_clocksource(void)
+-{
+-	if (!sh_hpt_frequency || clocksource_sh.read == null_hpt_read)
+-		return;
+-
+-	clocksource_sh.mult = clocksource_hz2mult(sh_hpt_frequency,
+-						  clocksource_sh.shift);
+-
+-	timer_ticks_per_nsec_quotient =
+-		clocksource_hz2mult(sh_hpt_frequency, NSEC_PER_CYC_SHIFT);
+-
+-	clocksource_register(&clocksource_sh);
+-}
+-
+-#ifdef CONFIG_GENERIC_TIME
+-unsigned long long sched_clock(void)
+-{
+-	unsigned long long ticks = clocksource_sh.read();
+-	return (ticks * timer_ticks_per_nsec_quotient) >> NSEC_PER_CYC_SHIFT;
+-}
+-#endif
+-
+-void __init time_init(void)
+-{
+-	if (board_time_init)
+-		board_time_init();
+-
+-	clk_init();
+-
+-	rtc_sh_get_time(&xtime);
+-	set_normalized_timespec(&wall_to_monotonic,
+-				-xtime.tv_sec, -xtime.tv_nsec);
+-
+-	/*
+-	 * Find the timer to use as the system timer, it will be
+-	 * initialized for us.
+-	 */
+-	sys_timer = get_sys_timer();
+-	printk(KERN_INFO "Using %s for system timer\n", sys_timer->name);
+-
+-	if (sys_timer->ops->read)
+-		clocksource_sh.read = sys_timer->ops->read;
+-
+-	init_sh_clocksource();
+-
+-	if (sh_hpt_frequency)
+-		printk("Using %lu.%03lu MHz high precision timer.\n",
+-		       ((sh_hpt_frequency + 500) / 1000) / 1000,
+-		       ((sh_hpt_frequency + 500) / 1000) % 1000);
+-
+-#if defined(CONFIG_SH_KGDB)
+-	/*
+-	 * Set up kgdb as requested. We do it here because the serial
+-	 * init uses the timer vars we just set up for figuring baud.
+-	 */
+-	kgdb_init();
+-#endif
+-}
+diff --git a/arch/sh/kernel/time_32.c b/arch/sh/kernel/time_32.c
+new file mode 100644
+index 0000000..2bc04bf
+--- /dev/null
++++ b/arch/sh/kernel/time_32.c
+@@ -0,0 +1,269 @@
++/*
++ *  arch/sh/kernel/time.c
++ *
++ *  Copyright (C) 1999  Tetsuya Okada & Niibe Yutaka
++ *  Copyright (C) 2000  Philipp Rumpf <prumpf at tux.org>
++ *  Copyright (C) 2002 - 2007  Paul Mundt
++ *  Copyright (C) 2002  M. R. Brown  <mrbrown at linux-sh.org>
++ *
++ *  Some code taken from i386 version.
++ *    Copyright (C) 1991, 1992, 1995  Linus Torvalds
++ */
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/profile.h>
++#include <linux/timex.h>
++#include <linux/sched.h>
++#include <linux/clockchips.h>
++#include <asm/clock.h>
++#include <asm/rtc.h>
++#include <asm/timer.h>
++#include <asm/kgdb.h>
++
++struct sys_timer *sys_timer;
++
++/* Move this somewhere more sensible.. */
++DEFINE_SPINLOCK(rtc_lock);
++EXPORT_SYMBOL(rtc_lock);
++
++/* Dummy RTC ops */
++static void null_rtc_get_time(struct timespec *tv)
++{
++	tv->tv_sec = mktime(2000, 1, 1, 0, 0, 0);
++	tv->tv_nsec = 0;
++}
++
++static int null_rtc_set_time(const time_t secs)
++{
++	return 0;
++}
++
++/*
++ * Null high precision timer functions for systems lacking one.
++ */
++static cycle_t null_hpt_read(void)
++{
++	return 0;
++}
++
++void (*rtc_sh_get_time)(struct timespec *) = null_rtc_get_time;
++int (*rtc_sh_set_time)(const time_t) = null_rtc_set_time;
++
++#ifndef CONFIG_GENERIC_TIME
++void do_gettimeofday(struct timeval *tv)
++{
++	unsigned long flags;
++	unsigned long seq;
++	unsigned long usec, sec;
++
++	do {
++		/*
++		 * Turn off IRQs when grabbing xtime_lock, so that
++		 * the sys_timer get_offset code doesn't have to handle it.
++		 */
++		seq = read_seqbegin_irqsave(&xtime_lock, flags);
++		usec = get_timer_offset();
++		sec = xtime.tv_sec;
++		usec += xtime.tv_nsec / NSEC_PER_USEC;
++	} while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
++
++	while (usec >= 1000000) {
++		usec -= 1000000;
++		sec++;
++	}
++
++	tv->tv_sec = sec;
++	tv->tv_usec = usec;
++}
++EXPORT_SYMBOL(do_gettimeofday);
++
++int do_settimeofday(struct timespec *tv)
++{
++	time_t wtm_sec, sec = tv->tv_sec;
++	long wtm_nsec, nsec = tv->tv_nsec;
++
++	if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC)
++		return -EINVAL;
++
++	write_seqlock_irq(&xtime_lock);
++	/*
++	 * This is revolting. We need to set "xtime" correctly. However, the
++	 * value in this location is the value at the most recent update of
++	 * wall time.  Discover what correction gettimeofday() would have
++	 * made, and then undo it!
++	 */
++	nsec -= get_timer_offset() * NSEC_PER_USEC;
++
++	wtm_sec  = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec);
++	wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec);
++
++	set_normalized_timespec(&xtime, sec, nsec);
++	set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);
++
++	ntp_clear();
++	write_sequnlock_irq(&xtime_lock);
++	clock_was_set();
++
++	return 0;
++}
++EXPORT_SYMBOL(do_settimeofday);
++#endif /* !CONFIG_GENERIC_TIME */
++
++#ifndef CONFIG_GENERIC_CLOCKEVENTS
++/* last time the RTC clock got updated */
++static long last_rtc_update;
++
++/*
++ * handle_timer_tick() needs to keep up the real-time clock,
++ * as well as call the "do_timer()" routine every clocktick
++ */
++void handle_timer_tick(void)
++{
++	do_timer(1);
++#ifndef CONFIG_SMP
++	update_process_times(user_mode(get_irq_regs()));
++#endif
++	if (current->pid)
++		profile_tick(CPU_PROFILING);
++
++#ifdef CONFIG_HEARTBEAT
++	if (sh_mv.mv_heartbeat != NULL)
++		sh_mv.mv_heartbeat();
++#endif
++
++	/*
++	 * If we have an externally synchronized Linux clock, then update
++	 * RTC clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
++	 * called as close as possible to 500 ms before the new second starts.
++	 */
++	if (ntp_synced() &&
++	    xtime.tv_sec > last_rtc_update + 660 &&
++	    (xtime.tv_nsec / 1000) >= 500000 - ((unsigned) TICK_SIZE) / 2 &&
++	    (xtime.tv_nsec / 1000) <= 500000 + ((unsigned) TICK_SIZE) / 2) {
++		if (rtc_sh_set_time(xtime.tv_sec) == 0)
++			last_rtc_update = xtime.tv_sec;
++		else
++			/* do it again in 60s */
++			last_rtc_update = xtime.tv_sec - 600;
++	}
++}
++#endif /* !CONFIG_GENERIC_CLOCKEVENTS */
++
++#ifdef CONFIG_PM
++int timer_suspend(struct sys_device *dev, pm_message_t state)
++{
++	struct sys_timer *sys_timer = container_of(dev, struct sys_timer, dev);
++
++	sys_timer->ops->stop();
++
++	return 0;
++}
++
++int timer_resume(struct sys_device *dev)
++{
++	struct sys_timer *sys_timer = container_of(dev, struct sys_timer, dev);
++
++	sys_timer->ops->start();
++
++	return 0;
++}
++#else
++#define timer_suspend NULL
++#define timer_resume NULL
++#endif
++
++static struct sysdev_class timer_sysclass = {
++	.name	 = "timer",
++	.suspend = timer_suspend,
++	.resume	 = timer_resume,
++};
++
++static int __init timer_init_sysfs(void)
++{
++	int ret = sysdev_class_register(&timer_sysclass);
++	if (ret != 0)
++		return ret;
++
++	sys_timer->dev.cls = &timer_sysclass;
++	return sysdev_register(&sys_timer->dev);
++}
++device_initcall(timer_init_sysfs);
++
++void (*board_time_init)(void);
++
++/*
++ * Shamelessly based on the MIPS and Sparc64 work.
++ */
++static unsigned long timer_ticks_per_nsec_quotient __read_mostly;
++unsigned long sh_hpt_frequency = 0;
++
++#define NSEC_PER_CYC_SHIFT	10
++
++struct clocksource clocksource_sh = {
++	.name		= "SuperH",
++	.rating		= 200,
++	.mask		= CLOCKSOURCE_MASK(32),
++	.read		= null_hpt_read,
++	.shift		= 16,
++	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
++};
++
++static void __init init_sh_clocksource(void)
++{
++	if (!sh_hpt_frequency || clocksource_sh.read == null_hpt_read)
++		return;
++
++	clocksource_sh.mult = clocksource_hz2mult(sh_hpt_frequency,
++						  clocksource_sh.shift);
++
++	timer_ticks_per_nsec_quotient =
++		clocksource_hz2mult(sh_hpt_frequency, NSEC_PER_CYC_SHIFT);
++
++	clocksource_register(&clocksource_sh);
++}
++
++#ifdef CONFIG_GENERIC_TIME
++unsigned long long sched_clock(void)
++{
++	unsigned long long ticks = clocksource_sh.read();
++	return (ticks * timer_ticks_per_nsec_quotient) >> NSEC_PER_CYC_SHIFT;
++}
++#endif
++
++void __init time_init(void)
++{
++	if (board_time_init)
++		board_time_init();
++
++	clk_init();
++
++	rtc_sh_get_time(&xtime);
++	set_normalized_timespec(&wall_to_monotonic,
++				-xtime.tv_sec, -xtime.tv_nsec);
++
++	/*
++	 * Find the timer to use as the system timer, it will be
++	 * initialized for us.
++	 */
++	sys_timer = get_sys_timer();
++	printk(KERN_INFO "Using %s for system timer\n", sys_timer->name);
++
++	if (sys_timer->ops->read)
++		clocksource_sh.read = sys_timer->ops->read;
++
++	init_sh_clocksource();
++
++	if (sh_hpt_frequency)
++		printk("Using %lu.%03lu MHz high precision timer.\n",
++		       ((sh_hpt_frequency + 500) / 1000) / 1000,
++		       ((sh_hpt_frequency + 500) / 1000) % 1000);
++
++#if defined(CONFIG_SH_KGDB)
++	/*
++	 * Set up kgdb as requested. We do it here because the serial
++	 * init uses the timer vars we just set up for figuring baud.
++	 */
++	kgdb_init();
++#endif
++}
+diff --git a/arch/sh/kernel/time_64.c b/arch/sh/kernel/time_64.c
+new file mode 100644
+index 0000000..f819ba3
+--- /dev/null
++++ b/arch/sh/kernel/time_64.c
+@@ -0,0 +1,519 @@
++/*
++ * arch/sh/kernel/time_64.c
++ *
++ * Copyright (C) 2000, 2001  Paolo Alberelli
++ * Copyright (C) 2003 - 2007  Paul Mundt
++ * Copyright (C) 2003  Richard Curnow
++ *
++ *    Original TMU/RTC code taken from sh version.
++ *    Copyright (C) 1999  Tetsuya Okada & Niibe Yutaka
++ *      Some code taken from i386 version.
++ *      Copyright (C) 1991, 1992, 1995  Linus Torvalds
++ *
++ * 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/errno.h>
++#include <linux/rwsem.h>
++#include <linux/sched.h>
++#include <linux/kernel.h>
++#include <linux/param.h>
++#include <linux/string.h>
++#include <linux/mm.h>
++#include <linux/interrupt.h>
++#include <linux/time.h>
++#include <linux/delay.h>
++#include <linux/init.h>
++#include <linux/profile.h>
++#include <linux/smp.h>
++#include <linux/module.h>
++#include <linux/bcd.h>
++#include <linux/timex.h>
++#include <linux/irq.h>
++#include <linux/io.h>
++#include <linux/platform_device.h>
++#include <asm/cpu/registers.h>	 /* required by inline __asm__ stmt. */
++#include <asm/cpu/irq.h>
++#include <asm/addrspace.h>
++#include <asm/processor.h>
++#include <asm/uaccess.h>
++#include <asm/delay.h>
++
++#define TMU_TOCR_INIT	0x00
++#define TMU0_TCR_INIT	0x0020
++#define TMU_TSTR_INIT	1
++#define TMU_TSTR_OFF	0
++
++/* Real Time Clock */
++#define	RTC_BLOCK_OFF	0x01040000
++#define RTC_BASE	PHYS_PERIPHERAL_BLOCK + RTC_BLOCK_OFF
++#define RTC_RCR1_CIE	0x10	/* Carry Interrupt Enable */
++#define RTC_RCR1	(rtc_base + 0x38)
++
++/* Clock, Power and Reset Controller */
++#define	CPRC_BLOCK_OFF	0x01010000
++#define CPRC_BASE	PHYS_PERIPHERAL_BLOCK + CPRC_BLOCK_OFF
++
++#define FRQCR		(cprc_base+0x0)
++#define WTCSR		(cprc_base+0x0018)
++#define STBCR		(cprc_base+0x0030)
++
++/* Time Management Unit */
++#define	TMU_BLOCK_OFF	0x01020000
++#define TMU_BASE	PHYS_PERIPHERAL_BLOCK + TMU_BLOCK_OFF
++#define TMU0_BASE	tmu_base + 0x8 + (0xc * 0x0)
++#define TMU1_BASE	tmu_base + 0x8 + (0xc * 0x1)
++#define TMU2_BASE	tmu_base + 0x8 + (0xc * 0x2)
++
++#define TMU_TOCR	tmu_base+0x0	/* Byte access */
++#define TMU_TSTR	tmu_base+0x4	/* Byte access */
++
++#define TMU0_TCOR	TMU0_BASE+0x0	/* Long access */
++#define TMU0_TCNT	TMU0_BASE+0x4	/* Long access */
++#define TMU0_TCR	TMU0_BASE+0x8	/* Word access */
++
++#define TICK_SIZE (tick_nsec / 1000)
++
++static unsigned long tmu_base, rtc_base;
++unsigned long cprc_base;
++
++/* Variables to allow interpolation of time of day to resolution better than a
++ * jiffy. */
++
++/* This is effectively protected by xtime_lock */
++static unsigned long ctc_last_interrupt;
++static unsigned long long usecs_per_jiffy = 1000000/HZ; /* Approximation */
++
++#define CTC_JIFFY_SCALE_SHIFT 40
++
++/* 2**CTC_JIFFY_SCALE_SHIFT / ctc_ticks_per_jiffy */
++static unsigned long long scaled_recip_ctc_ticks_per_jiffy;
++
++/* Estimate number of microseconds that have elapsed since the last timer tick,
++   by scaling the delta that has occurred in the CTC register.
++
++   WARNING WARNING WARNING : This algorithm relies on the CTC decrementing at
++   the CPU clock rate.  If the CPU sleeps, the CTC stops counting.  Bear this
++   in mind if enabling SLEEP_WORKS in process.c.  In that case, this algorithm
++   probably needs to use TMU.TCNT0 instead.  This will work even if the CPU is
++   sleeping, though will be coarser.
++
++   FIXME : What if usecs_per_tick is moving around too much, e.g. if an adjtime
++   is running or if the freq or tick arguments of adjtimex are modified after
++   we have calibrated the scaling factor?  This will result in either a jump at
++   the end of a tick period, or a wrap backwards at the start of the next one,
++   if the application is reading the time of day often enough.  I think we
++   ought to do better than this.  For this reason, usecs_per_jiffy is left
++   separated out in the calculation below.  This allows some future hook into
++   the adjtime-related stuff in kernel/timer.c to remove this hazard.
++
++*/
++
++static unsigned long usecs_since_tick(void)
++{
++	unsigned long long current_ctc;
++	long ctc_ticks_since_interrupt;
++	unsigned long long ull_ctc_ticks_since_interrupt;
++	unsigned long result;
++
++	unsigned long long mul1_out;
++	unsigned long long mul1_out_high;
++	unsigned long long mul2_out_low, mul2_out_high;
++
++	/* Read CTC register */
++	asm ("getcon cr62, %0" : "=r" (current_ctc));
++	/* Note, the CTC counts down on each CPU clock, not up.
++	   Note(2), use long type to get correct wraparound arithmetic when
++	   the counter crosses zero. */
++	ctc_ticks_since_interrupt = (long) ctc_last_interrupt - (long) current_ctc;
++	ull_ctc_ticks_since_interrupt = (unsigned long long) ctc_ticks_since_interrupt;
++
++	/* Inline assembly to do 32x32x32->64 multiplier */
++	asm volatile ("mulu.l %1, %2, %0" :
++	     "=r" (mul1_out) :
++	     "r" (ull_ctc_ticks_since_interrupt), "r" (usecs_per_jiffy));
++
++	mul1_out_high = mul1_out >> 32;
++
++	asm volatile ("mulu.l %1, %2, %0" :
++	     "=r" (mul2_out_low) :
++	     "r" (mul1_out), "r" (scaled_recip_ctc_ticks_per_jiffy));
++
++#if 1
++	asm volatile ("mulu.l %1, %2, %0" :
++	     "=r" (mul2_out_high) :
++	     "r" (mul1_out_high), "r" (scaled_recip_ctc_ticks_per_jiffy));
++#endif
++
++	result = (unsigned long) (((mul2_out_high << 32) + mul2_out_low) >> CTC_JIFFY_SCALE_SHIFT);
++
++	return result;
++}
++
++void do_gettimeofday(struct timeval *tv)
++{
++	unsigned long flags;
++	unsigned long seq;
++	unsigned long usec, sec;
++
++	do {
++		seq = read_seqbegin_irqsave(&xtime_lock, flags);
++		usec = usecs_since_tick();
++		sec = xtime.tv_sec;
++		usec += xtime.tv_nsec / 1000;
++	} while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
++
++	while (usec >= 1000000) {
++		usec -= 1000000;
++		sec++;
++	}
++
++	tv->tv_sec = sec;
++	tv->tv_usec = usec;
++}
++
++int do_settimeofday(struct timespec *tv)
++{
++	time_t wtm_sec, sec = tv->tv_sec;
++	long wtm_nsec, nsec = tv->tv_nsec;
++
++	if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC)
++		return -EINVAL;
++
++	write_seqlock_irq(&xtime_lock);
++	/*
++	 * This is revolting. We need to set "xtime" correctly. However, the
++	 * value in this location is the value at the most recent update of
++	 * wall time.  Discover what correction gettimeofday() would have
++	 * made, and then undo it!
++	 */
++	nsec -= 1000 * usecs_since_tick();
++
++	wtm_sec  = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec);
++	wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec);
++
++	set_normalized_timespec(&xtime, sec, nsec);
++	set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);
++
++	ntp_clear();
++	write_sequnlock_irq(&xtime_lock);
++	clock_was_set();
++
++	return 0;
++}
++EXPORT_SYMBOL(do_settimeofday);
++
++/* Dummy RTC ops */
++static void null_rtc_get_time(struct timespec *tv)
++{
++	tv->tv_sec = mktime(2000, 1, 1, 0, 0, 0);
++	tv->tv_nsec = 0;
++}
++
++static int null_rtc_set_time(const time_t secs)
++{
++	return 0;
++}
++
++void (*rtc_sh_get_time)(struct timespec *) = null_rtc_get_time;
++int (*rtc_sh_set_time)(const time_t) = null_rtc_set_time;
++
++/* last time the RTC clock got updated */
++static long last_rtc_update;
++
++/*
++ * timer_interrupt() needs to keep up the real-time clock,
++ * as well as call the "do_timer()" routine every clocktick
++ */
++static inline void do_timer_interrupt(void)
++{
++	unsigned long long current_ctc;
++	asm ("getcon cr62, %0" : "=r" (current_ctc));
++	ctc_last_interrupt = (unsigned long) current_ctc;
++
++	do_timer(1);
++#ifndef CONFIG_SMP
++	update_process_times(user_mode(get_irq_regs()));
++#endif
++	if (current->pid)
++		profile_tick(CPU_PROFILING);
++
++#ifdef CONFIG_HEARTBEAT
++	if (sh_mv.mv_heartbeat != NULL)
++		sh_mv.mv_heartbeat();
++#endif
++
++	/*
++	 * If we have an externally synchronized Linux clock, then update
++	 * RTC clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
++	 * called as close as possible to 500 ms before the new second starts.
++	 */
++	if (ntp_synced() &&
++	    xtime.tv_sec > last_rtc_update + 660 &&
++	    (xtime.tv_nsec / 1000) >= 500000 - ((unsigned) TICK_SIZE) / 2 &&
++	    (xtime.tv_nsec / 1000) <= 500000 + ((unsigned) TICK_SIZE) / 2) {
++		if (rtc_sh_set_time(xtime.tv_sec) == 0)
++			last_rtc_update = xtime.tv_sec;
++		else
++			/* do it again in 60 s */
++			last_rtc_update = xtime.tv_sec - 600;
++	}
++}
++
++/*
++ * This is the same as the above, except we _also_ save the current
++ * Time Stamp Counter value at the time of the timer interrupt, so that
++ * we later on can estimate the time of day more exactly.
++ */
++static irqreturn_t timer_interrupt(int irq, void *dev_id)
++{
++	unsigned long timer_status;
++
++	/* Clear UNF bit */
++	timer_status = ctrl_inw(TMU0_TCR);
++	timer_status &= ~0x100;
++	ctrl_outw(timer_status, TMU0_TCR);
++
++	/*
++	 * Here we are in the timer irq handler. We just have irqs locally
++	 * disabled but we don't know if the timer_bh is running on the other
++	 * CPU. We need to avoid to SMP race with it. NOTE: we don' t need
++	 * the irq version of write_lock because as just said we have irq
++	 * locally disabled. -arca
++	 */
++	write_lock(&xtime_lock);
++	do_timer_interrupt();
++	write_unlock(&xtime_lock);
++
++	return IRQ_HANDLED;
++}
++
++
++static __init unsigned int get_cpu_hz(void)
++{
++	unsigned int count;
++	unsigned long __dummy;
++	unsigned long ctc_val_init, ctc_val;
++
++	/*
++	** Regardless the toolchain, force the compiler to use the
++	** arbitrary register r3 as a clock tick counter.
++	** NOTE: r3 must be in accordance with sh64_rtc_interrupt()
++	*/
++	register unsigned long long  __rtc_irq_flag __asm__ ("r3");
++
++	local_irq_enable();
++	do {} while (ctrl_inb(rtc_base) != 0);
++	ctrl_outb(RTC_RCR1_CIE, RTC_RCR1); /* Enable carry interrupt */
++
++	/*
++	 * r3 is arbitrary. CDC does not support "=z".
++	 */
++	ctc_val_init = 0xffffffff;
++	ctc_val = ctc_val_init;
++
++	asm volatile("gettr	tr0, %1\n\t"
++		     "putcon	%0, " __CTC "\n\t"
++		     "and	%2, r63, %2\n\t"
++		     "pta	$+4, tr0\n\t"
++		     "beq/l	%2, r63, tr0\n\t"
++		     "ptabs	%1, tr0\n\t"
++		     "getcon	" __CTC ", %0\n\t"
++		: "=r"(ctc_val), "=r" (__dummy), "=r" (__rtc_irq_flag)
++		: "0" (0));
++	local_irq_disable();
++	/*
++	 * SH-3:
++	 * CPU clock = 4 stages * loop
++	 * tst    rm,rm      if id ex
++	 * bt/s   1b            if id ex
++	 * add    #1,rd            if id ex
++         *                            (if) pipe line stole
++	 * tst    rm,rm                  if id ex
++         * ....
++	 *
++	 *
++	 * SH-4:
++	 * CPU clock = 6 stages * loop
++	 * I don't know why.
++         * ....
++	 *
++	 * SH-5:
++	 * Use CTC register to count.  This approach returns the right value
++	 * even if the I-cache is disabled (e.g. whilst debugging.)
++	 *
++	 */
++
++	count = ctc_val_init - ctc_val; /* CTC counts down */
++
++	/*
++	 * This really is count by the number of clock cycles
++         * by the ratio between a complete R64CNT
++         * wrap-around (128) and CUI interrupt being raised (64).
++	 */
++	return count*2;
++}
++
++static irqreturn_t sh64_rtc_interrupt(int irq, void *dev_id)
++{
++	struct pt_regs *regs = get_irq_regs();
++
++	ctrl_outb(0, RTC_RCR1);	/* Disable Carry Interrupts */
++	regs->regs[3] = 1;	/* Using r3 */
++
++	return IRQ_HANDLED;
++}
++
++static struct irqaction irq0  = {
++	.handler = timer_interrupt,
++	.flags = IRQF_DISABLED,
++	.mask = CPU_MASK_NONE,
++	.name = "timer",
++};
++static struct irqaction irq1  = {
++	.handler = sh64_rtc_interrupt,
++	.flags = IRQF_DISABLED,
++	.mask = CPU_MASK_NONE,
++	.name = "rtc",
++};
++
++void __init time_init(void)
++{
++	unsigned int cpu_clock, master_clock, bus_clock, module_clock;
++	unsigned long interval;
++	unsigned long frqcr, ifc, pfc;
++	static int ifc_table[] = { 2, 4, 6, 8, 10, 12, 16, 24 };
++#define bfc_table ifc_table	/* Same */
++#define pfc_table ifc_table	/* Same */
++
++	tmu_base = onchip_remap(TMU_BASE, 1024, "TMU");
++	if (!tmu_base) {
++		panic("Unable to remap TMU\n");
++	}
++
++	rtc_base = onchip_remap(RTC_BASE, 1024, "RTC");
++	if (!rtc_base) {
++		panic("Unable to remap RTC\n");
++	}
++
++	cprc_base = onchip_remap(CPRC_BASE, 1024, "CPRC");
++	if (!cprc_base) {
++		panic("Unable to remap CPRC\n");
++	}
++
++	rtc_sh_get_time(&xtime);
++
++	setup_irq(TIMER_IRQ, &irq0);
++	setup_irq(RTC_IRQ, &irq1);
++
++	/* Check how fast it is.. */
++	cpu_clock = get_cpu_hz();
++
++	/* Note careful order of operations to maintain reasonable precision and avoid overflow. */
++	scaled_recip_ctc_ticks_per_jiffy = ((1ULL << CTC_JIFFY_SCALE_SHIFT) / (unsigned long long)(cpu_clock / HZ));
++
++	free_irq(RTC_IRQ, NULL);
++
++	printk("CPU clock: %d.%02dMHz\n",
++	       (cpu_clock / 1000000), (cpu_clock % 1000000)/10000);
++	{
++		unsigned short bfc;
++		frqcr = ctrl_inl(FRQCR);
++		ifc  = ifc_table[(frqcr>> 6) & 0x0007];
++		bfc  = bfc_table[(frqcr>> 3) & 0x0007];
++		pfc  = pfc_table[(frqcr>> 12) & 0x0007];
++		master_clock = cpu_clock * ifc;
++		bus_clock = master_clock/bfc;
++	}
++
++	printk("Bus clock: %d.%02dMHz\n",
++	       (bus_clock/1000000), (bus_clock % 1000000)/10000);
++	module_clock = master_clock/pfc;
++	printk("Module clock: %d.%02dMHz\n",
++	       (module_clock/1000000), (module_clock % 1000000)/10000);
++	interval = (module_clock/(HZ*4));
++
++	printk("Interval = %ld\n", interval);
++
++	current_cpu_data.cpu_clock    = cpu_clock;
++	current_cpu_data.master_clock = master_clock;
++	current_cpu_data.bus_clock    = bus_clock;
++	current_cpu_data.module_clock = module_clock;
++
++	/* Start TMU0 */
++	ctrl_outb(TMU_TSTR_OFF, TMU_TSTR);
++	ctrl_outb(TMU_TOCR_INIT, TMU_TOCR);
++	ctrl_outw(TMU0_TCR_INIT, TMU0_TCR);
++	ctrl_outl(interval, TMU0_TCOR);
++	ctrl_outl(interval, TMU0_TCNT);
++	ctrl_outb(TMU_TSTR_INIT, TMU_TSTR);
++}
++
++void enter_deep_standby(void)
++{
++	/* Disable watchdog timer */
++	ctrl_outl(0xa5000000, WTCSR);
++	/* Configure deep standby on sleep */
++	ctrl_outl(0x03, STBCR);
++
++#ifdef CONFIG_SH_ALPHANUMERIC
++	{
++		extern void mach_alphanum(int position, unsigned char value);
++		extern void mach_alphanum_brightness(int setting);
++		char halted[] = "Halted. ";
++		int i;
++		mach_alphanum_brightness(6); /* dimmest setting above off */
++		for (i=0; i<8; i++) {
++			mach_alphanum(i, halted[i]);
++		}
++		asm __volatile__ ("synco");
++	}
++#endif
++
++	asm __volatile__ ("sleep");
++	asm __volatile__ ("synci");
++	asm __volatile__ ("nop");
++	asm __volatile__ ("nop");
++	asm __volatile__ ("nop");
++	asm __volatile__ ("nop");
++	panic("Unexpected wakeup!\n");
++}
++
++static struct resource rtc_resources[] = {
++	[0] = {
++		/* RTC base, filled in by rtc_init */
++		.flags	= IORESOURCE_IO,
++	},
++	[1] = {
++		/* Period IRQ */
++		.start	= IRQ_PRI,
++		.flags	= IORESOURCE_IRQ,
++	},
++	[2] = {
++		/* Carry IRQ */
++		.start	= IRQ_CUI,
++		.flags	= IORESOURCE_IRQ,
++	},
++	[3] = {
++		/* Alarm IRQ */
++		.start	= IRQ_ATI,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device rtc_device = {
++	.name		= "sh-rtc",
++	.id		= -1,
++	.num_resources	= ARRAY_SIZE(rtc_resources),
++	.resource	= rtc_resources,
++};
++
++static int __init rtc_init(void)
++{
++	rtc_resources[0].start	= rtc_base;
++	rtc_resources[0].end	= rtc_resources[0].start + 0x58 - 1;
++
++	return platform_device_register(&rtc_device);
++}
++device_initcall(rtc_init);
+diff --git a/arch/sh/kernel/timers/timer-cmt.c b/arch/sh/kernel/timers/timer-cmt.c
+index 82de689..499e07b 100644
+--- a/arch/sh/kernel/timers/timer-cmt.c
++++ b/arch/sh/kernel/timers/timer-cmt.c
+@@ -31,7 +31,9 @@
+ #define cmt_clock_enable() do {	ctrl_outb(ctrl_inb(STBCR3) & ~0x10, STBCR3); } while(0)
+ #define CMT_CMCSR_INIT	0x0040
+ #define CMT_CMCSR_CALIB	0x0000
+-#elif defined(CONFIG_CPU_SUBTYPE_SH7206)
++#elif defined(CONFIG_CPU_SUBTYPE_SH7203) || \
++      defined(CONFIG_CPU_SUBTYPE_SH7206) || \
++      defined(CONFIG_CPU_SUBTYPE_SH7263)
+ #define CMT_CMSTR	0xfffec000
+ #define CMT_CMCSR_0	0xfffec002
+ #define CMT_CMCNT_0	0xfffec004
+diff --git a/arch/sh/kernel/timers/timer-tmu.c b/arch/sh/kernel/timers/timer-tmu.c
+index 628ec9a..8935570 100644
+--- a/arch/sh/kernel/timers/timer-tmu.c
++++ b/arch/sh/kernel/timers/timer-tmu.c
+@@ -174,6 +174,7 @@ static int tmu_timer_init(void)
+ 	tmu_timer_stop();
+ 
+ #if !defined(CONFIG_CPU_SUBTYPE_SH7720) && \
++    !defined(CONFIG_CPU_SUBTYPE_SH7721) && \
+     !defined(CONFIG_CPU_SUBTYPE_SH7760) && \
+     !defined(CONFIG_CPU_SUBTYPE_SH7785) && \
+     !defined(CONFIG_CPU_SUBTYPE_SHX3)
+diff --git a/arch/sh/kernel/traps.c b/arch/sh/kernel/traps.c
+index cf99111..a3bdc68 100644
+--- a/arch/sh/kernel/traps.c
++++ b/arch/sh/kernel/traps.c
+@@ -1,947 +1,68 @@
+-/*
+- * 'traps.c' handles hardware traps and faults after we have saved some
+- * state in 'entry.S'.
+- *
+- *  SuperH version: Copyright (C) 1999 Niibe Yutaka
+- *                  Copyright (C) 2000 Philipp Rumpf
+- *                  Copyright (C) 2000 David Howells
+- *                  Copyright (C) 2002 - 2007 Paul Mundt
+- *
+- * This file is subject to the terms and conditions of the GNU General Public
+- * License.  See the file "COPYING" in the main directory of this archive
+- * for more details.
+- */
+-#include <linux/kernel.h>
+-#include <linux/ptrace.h>
+-#include <linux/init.h>
+-#include <linux/spinlock.h>
+-#include <linux/module.h>
+-#include <linux/kallsyms.h>
+-#include <linux/io.h>
+ #include <linux/bug.h>
+-#include <linux/debug_locks.h>
++#include <linux/io.h>
++#include <linux/types.h>
+ #include <linux/kdebug.h>
+-#include <linux/kexec.h>
+-#include <linux/limits.h>
++#include <linux/signal.h>
++#include <linux/sched.h>
+ #include <asm/system.h>
+-#include <asm/uaccess.h>
+-
+-#ifdef CONFIG_SH_KGDB
+-#include <asm/kgdb.h>
+-#define CHK_REMOTE_DEBUG(regs)			\
+-{						\
+-	if (kgdb_debug_hook && !user_mode(regs))\
+-		(*kgdb_debug_hook)(regs);       \
+-}
+-#else
+-#define CHK_REMOTE_DEBUG(regs)
+-#endif
+-
+-#ifdef CONFIG_CPU_SH2
+-# define TRAP_RESERVED_INST	4
+-# define TRAP_ILLEGAL_SLOT_INST	6
+-# define TRAP_ADDRESS_ERROR	9
+-# ifdef CONFIG_CPU_SH2A
+-#  define TRAP_DIVZERO_ERROR	17
+-#  define TRAP_DIVOVF_ERROR	18
+-# endif
+-#else
+-#define TRAP_RESERVED_INST	12
+-#define TRAP_ILLEGAL_SLOT_INST	13
+-#endif
+-
+-static void dump_mem(const char *str, unsigned long bottom, unsigned long top)
+-{
+-	unsigned long p;
+-	int i;
+-
+-	printk("%s(0x%08lx to 0x%08lx)\n", str, bottom, top);
+-
+-	for (p = bottom & ~31; p < top; ) {
+-		printk("%04lx: ", p & 0xffff);
+-
+-		for (i = 0; i < 8; i++, p += 4) {
+-			unsigned int val;
+-
+-			if (p < bottom || p >= top)
+-				printk("         ");
+-			else {
+-				if (__get_user(val, (unsigned int __user *)p)) {
+-					printk("\n");
+-					return;
+-				}
+-				printk("%08x ", val);
+-			}
+-		}
+-		printk("\n");
+-	}
+-}
+-
+-static DEFINE_SPINLOCK(die_lock);
+-
+-void die(const char * str, struct pt_regs * regs, long err)
+-{
+-	static int die_counter;
+-
+-	oops_enter();
+-
+-	console_verbose();
+-	spin_lock_irq(&die_lock);
+-	bust_spinlocks(1);
+-
+-	printk("%s: %04lx [#%d]\n", str, err & 0xffff, ++die_counter);
+-
+-	CHK_REMOTE_DEBUG(regs);
+-	print_modules();
+-	show_regs(regs);
+-
+-	printk("Process: %s (pid: %d, stack limit = %p)\n", current->comm,
+-			task_pid_nr(current), task_stack_page(current) + 1);
+-
+-	if (!user_mode(regs) || in_interrupt())
+-		dump_mem("Stack: ", regs->regs[15], THREAD_SIZE +
+-			 (unsigned long)task_stack_page(current));
+-
+-	bust_spinlocks(0);
+-	add_taint(TAINT_DIE);
+-	spin_unlock_irq(&die_lock);
+-
+-	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(SIGSEGV);
+-}
+-
+-static inline void die_if_kernel(const char *str, struct pt_regs *regs,
+-				 long err)
+-{
+-	if (!user_mode(regs))
+-		die(str, regs, err);
+-}
+-
+-/*
+- * try and fix up kernelspace address errors
+- * - userspace errors just cause EFAULT to be returned, resulting in SEGV
+- * - kernel/userspace interfaces cause a jump to an appropriate handler
+- * - other kernel errors are bad
+- * - return 0 if fixed-up, -EFAULT if non-fatal (to the kernel) fault
+- */
+-static int die_if_no_fixup(const char * str, struct pt_regs * regs, long err)
+-{
+-	if (!user_mode(regs)) {
+-		const struct exception_table_entry *fixup;
+-		fixup = search_exception_tables(regs->pc);
+-		if (fixup) {
+-			regs->pc = fixup->fixup;
+-			return 0;
+-		}
+-		die(str, regs, err);
+-	}
+-	return -EFAULT;
+-}
+-
+-/*
+- * handle an instruction that does an unaligned memory access by emulating the
+- * desired behaviour
+- * - note that PC _may not_ point to the faulting instruction
+- *   (if that instruction is in a branch delay slot)
+- * - return 0 if emulation okay, -EFAULT on existential error
+- */
+-static int handle_unaligned_ins(u16 instruction, struct pt_regs *regs)
+-{
+-	int ret, index, count;
+-	unsigned long *rm, *rn;
+-	unsigned char *src, *dst;
+-
+-	index = (instruction>>8)&15;	/* 0x0F00 */
+-	rn = &regs->regs[index];
+-
+-	index = (instruction>>4)&15;	/* 0x00F0 */
+-	rm = &regs->regs[index];
+-
+-	count = 1<<(instruction&3);
+-
+-	ret = -EFAULT;
+-	switch (instruction>>12) {
+-	case 0: /* mov.[bwl] to/from memory via r0+rn */
+-		if (instruction & 8) {
+-			/* from memory */
+-			src = (unsigned char*) *rm;
+-			src += regs->regs[0];
+-			dst = (unsigned char*) rn;
+-			*(unsigned long*)dst = 0;
+-
+-#ifdef __LITTLE_ENDIAN__
+-			if (copy_from_user(dst, src, count))
+-				goto fetch_fault;
+-
+-			if ((count == 2) && dst[1] & 0x80) {
+-				dst[2] = 0xff;
+-				dst[3] = 0xff;
+-			}
+-#else
+-			dst += 4-count;
+-
+-			if (__copy_user(dst, src, count))
+-				goto fetch_fault;
+-
+-			if ((count == 2) && dst[2] & 0x80) {
+-				dst[0] = 0xff;
+-				dst[1] = 0xff;
+-			}
+-#endif
+-		} else {
+-			/* to memory */
+-			src = (unsigned char*) rm;
+-#if !defined(__LITTLE_ENDIAN__)
+-			src += 4-count;
+-#endif
+-			dst = (unsigned char*) *rn;
+-			dst += regs->regs[0];
+-
+-			if (copy_to_user(dst, src, count))
+-				goto fetch_fault;
+-		}
+-		ret = 0;
+-		break;
+-
+-	case 1: /* mov.l Rm,@(disp,Rn) */
+-		src = (unsigned char*) rm;
+-		dst = (unsigned char*) *rn;
+-		dst += (instruction&0x000F)<<2;
+-
+-		if (copy_to_user(dst,src,4))
+-			goto fetch_fault;
+-		ret = 0;
+-		break;
+-
+-	case 2: /* mov.[bwl] to memory, possibly with pre-decrement */
+-		if (instruction & 4)
+-			*rn -= count;
+-		src = (unsigned char*) rm;
+-		dst = (unsigned char*) *rn;
+-#if !defined(__LITTLE_ENDIAN__)
+-		src += 4-count;
+-#endif
+-		if (copy_to_user(dst, src, count))
+-			goto fetch_fault;
+-		ret = 0;
+-		break;
+-
+-	case 5: /* mov.l @(disp,Rm),Rn */
+-		src = (unsigned char*) *rm;
+-		src += (instruction&0x000F)<<2;
+-		dst = (unsigned char*) rn;
+-		*(unsigned long*)dst = 0;
+-
+-		if (copy_from_user(dst,src,4))
+-			goto fetch_fault;
+-		ret = 0;
+-		break;
+ 
+-	case 6:	/* mov.[bwl] from memory, possibly with post-increment */
+-		src = (unsigned char*) *rm;
+-		if (instruction & 4)
+-			*rm += count;
+-		dst = (unsigned char*) rn;
+-		*(unsigned long*)dst = 0;
+-
+-#ifdef __LITTLE_ENDIAN__
+-		if (copy_from_user(dst, src, count))
+-			goto fetch_fault;
+-
+-		if ((count == 2) && dst[1] & 0x80) {
+-			dst[2] = 0xff;
+-			dst[3] = 0xff;
+-		}
+-#else
+-		dst += 4-count;
+-
+-		if (copy_from_user(dst, src, count))
+-			goto fetch_fault;
+-
+-		if ((count == 2) && dst[2] & 0x80) {
+-			dst[0] = 0xff;
+-			dst[1] = 0xff;
+-		}
+-#endif
+-		ret = 0;
+-		break;
+-
+-	case 8:
+-		switch ((instruction&0xFF00)>>8) {
+-		case 0x81: /* mov.w R0,@(disp,Rn) */
+-			src = (unsigned char*) &regs->regs[0];
+-#if !defined(__LITTLE_ENDIAN__)
+-			src += 2;
+-#endif
+-			dst = (unsigned char*) *rm; /* called Rn in the spec */
+-			dst += (instruction&0x000F)<<1;
+-
+-			if (copy_to_user(dst, src, 2))
+-				goto fetch_fault;
+-			ret = 0;
+-			break;
+-
+-		case 0x85: /* mov.w @(disp,Rm),R0 */
+-			src = (unsigned char*) *rm;
+-			src += (instruction&0x000F)<<1;
+-			dst = (unsigned char*) &regs->regs[0];
+-			*(unsigned long*)dst = 0;
+-
+-#if !defined(__LITTLE_ENDIAN__)
+-			dst += 2;
+-#endif
+-
+-			if (copy_from_user(dst, src, 2))
+-				goto fetch_fault;
+-
+-#ifdef __LITTLE_ENDIAN__
+-			if (dst[1] & 0x80) {
+-				dst[2] = 0xff;
+-				dst[3] = 0xff;
+-			}
+-#else
+-			if (dst[2] & 0x80) {
+-				dst[0] = 0xff;
+-				dst[1] = 0xff;
+-			}
+-#endif
+-			ret = 0;
+-			break;
+-		}
+-		break;
+-	}
+-	return ret;
+-
+- fetch_fault:
+-	/* Argh. Address not only misaligned but also non-existent.
+-	 * Raise an EFAULT and see if it's trapped
+-	 */
+-	return die_if_no_fixup("Fault in unaligned fixup", regs, 0);
+-}
+-
+-/*
+- * emulate the instruction in the delay slot
+- * - fetches the instruction from PC+2
+- */
+-static inline int handle_unaligned_delayslot(struct pt_regs *regs)
++#ifdef CONFIG_BUG
++static void handle_BUG(struct pt_regs *regs)
+ {
+-	u16 instruction;
+-
+-	if (copy_from_user(&instruction, (u16 *)(regs->pc+2), 2)) {
+-		/* the instruction-fetch faulted */
+-		if (user_mode(regs))
+-			return -EFAULT;
+-
+-		/* kernel */
+-		die("delay-slot-insn faulting in handle_unaligned_delayslot",
+-		    regs, 0);
++	enum bug_trap_type tt;
++	tt = report_bug(regs->pc, regs);
++	if (tt == BUG_TRAP_TYPE_WARN) {
++		regs->pc += instruction_size(regs->pc);
++		return;
+ 	}
+ 
+-	return handle_unaligned_ins(instruction,regs);
++	die("Kernel BUG", regs, TRAPA_BUG_OPCODE & 0xff);
+ }
+ 
+-/*
+- * handle an instruction that does an unaligned memory access
+- * - have to be careful of branch delay-slot instructions that fault
+- *  SH3:
+- *   - if the branch would be taken PC points to the branch
+- *   - if the branch would not be taken, PC points to delay-slot
+- *  SH4:
+- *   - PC always points to delayed branch
+- * - return 0 if handled, -EFAULT if failed (may not return if in kernel)
+- */
+-
+-/* Macros to determine offset from current PC for branch instructions */
+-/* Explicit type coercion is used to force sign extension where needed */
+-#define SH_PC_8BIT_OFFSET(instr) ((((signed char)(instr))*2) + 4)
+-#define SH_PC_12BIT_OFFSET(instr) ((((signed short)(instr<<4))>>3) + 4)
+-
+-/*
+- * XXX: SH-2A needs this too, but it needs an overhaul thanks to mixed 32-bit
+- * opcodes..
+- */
+-#ifndef CONFIG_CPU_SH2A
+-static int handle_unaligned_notify_count = 10;
+-
+-static int handle_unaligned_access(u16 instruction, struct pt_regs *regs)
++int is_valid_bugaddr(unsigned long addr)
+ {
+-	u_int rm;
+-	int ret, index;
+-
+-	index = (instruction>>8)&15;	/* 0x0F00 */
+-	rm = regs->regs[index];
+-
+-	/* shout about the first ten userspace fixups */
+-	if (user_mode(regs) && handle_unaligned_notify_count>0) {
+-		handle_unaligned_notify_count--;
+-
+-		printk(KERN_NOTICE "Fixing up unaligned userspace access "
+-		       "in \"%s\" pid=%d pc=0x%p ins=0x%04hx\n",
+-		       current->comm, task_pid_nr(current),
+-		       (u16 *)regs->pc, instruction);
+-	}
+-
+-	ret = -EFAULT;
+-	switch (instruction&0xF000) {
+-	case 0x0000:
+-		if (instruction==0x000B) {
+-			/* rts */
+-			ret = handle_unaligned_delayslot(regs);
+-			if (ret==0)
+-				regs->pc = regs->pr;
+-		}
+-		else if ((instruction&0x00FF)==0x0023) {
+-			/* braf @Rm */
+-			ret = handle_unaligned_delayslot(regs);
+-			if (ret==0)
+-				regs->pc += rm + 4;
+-		}
+-		else if ((instruction&0x00FF)==0x0003) {
+-			/* bsrf @Rm */
+-			ret = handle_unaligned_delayslot(regs);
+-			if (ret==0) {
+-				regs->pr = regs->pc + 4;
+-				regs->pc += rm + 4;
+-			}
+-		}
+-		else {
+-			/* mov.[bwl] to/from memory via r0+rn */
+-			goto simple;
+-		}
+-		break;
+-
+-	case 0x1000: /* mov.l Rm,@(disp,Rn) */
+-		goto simple;
+-
+-	case 0x2000: /* mov.[bwl] to memory, possibly with pre-decrement */
+-		goto simple;
+-
+-	case 0x4000:
+-		if ((instruction&0x00FF)==0x002B) {
+-			/* jmp @Rm */
+-			ret = handle_unaligned_delayslot(regs);
+-			if (ret==0)
+-				regs->pc = rm;
+-		}
+-		else if ((instruction&0x00FF)==0x000B) {
+-			/* jsr @Rm */
+-			ret = handle_unaligned_delayslot(regs);
+-			if (ret==0) {
+-				regs->pr = regs->pc + 4;
+-				regs->pc = rm;
+-			}
+-		}
+-		else {
+-			/* mov.[bwl] to/from memory via r0+rn */
+-			goto simple;
+-		}
+-		break;
+-
+-	case 0x5000: /* mov.l @(disp,Rm),Rn */
+-		goto simple;
+-
+-	case 0x6000: /* mov.[bwl] from memory, possibly with post-increment */
+-		goto simple;
+-
+-	case 0x8000: /* bf lab, bf/s lab, bt lab, bt/s lab */
+-		switch (instruction&0x0F00) {
+-		case 0x0100: /* mov.w R0,@(disp,Rm) */
+-			goto simple;
+-		case 0x0500: /* mov.w @(disp,Rm),R0 */
+-			goto simple;
+-		case 0x0B00: /* bf   lab - no delayslot*/
+-			break;
+-		case 0x0F00: /* bf/s lab */
+-			ret = handle_unaligned_delayslot(regs);
+-			if (ret==0) {
+-#if defined(CONFIG_CPU_SH4) || defined(CONFIG_SH7705_CACHE_32KB)
+-				if ((regs->sr & 0x00000001) != 0)
+-					regs->pc += 4; /* next after slot */
+-				else
+-#endif
+-					regs->pc += SH_PC_8BIT_OFFSET(instruction);
+-			}
+-			break;
+-		case 0x0900: /* bt   lab - no delayslot */
+-			break;
+-		case 0x0D00: /* bt/s lab */
+-			ret = handle_unaligned_delayslot(regs);
+-			if (ret==0) {
+-#if defined(CONFIG_CPU_SH4) || defined(CONFIG_SH7705_CACHE_32KB)
+-				if ((regs->sr & 0x00000001) == 0)
+-					regs->pc += 4; /* next after slot */
+-				else
+-#endif
+-					regs->pc += SH_PC_8BIT_OFFSET(instruction);
+-			}
+-			break;
+-		}
+-		break;
+-
+-	case 0xA000: /* bra label */
+-		ret = handle_unaligned_delayslot(regs);
+-		if (ret==0)
+-			regs->pc += SH_PC_12BIT_OFFSET(instruction);
+-		break;
+-
+-	case 0xB000: /* bsr label */
+-		ret = handle_unaligned_delayslot(regs);
+-		if (ret==0) {
+-			regs->pr = regs->pc + 4;
+-			regs->pc += SH_PC_12BIT_OFFSET(instruction);
+-		}
+-		break;
+-	}
+-	return ret;
+-
+-	/* handle non-delay-slot instruction */
+- simple:
+-	ret = handle_unaligned_ins(instruction,regs);
+-	if (ret==0)
+-		regs->pc += instruction_size(instruction);
+-	return ret;
++	return addr >= PAGE_OFFSET;
+ }
+-#endif /* CONFIG_CPU_SH2A */
+-
+-#ifdef CONFIG_CPU_HAS_SR_RB
+-#define lookup_exception_vector(x)	\
+-	__asm__ __volatile__ ("stc r2_bank, %0\n\t" : "=r" ((x)))
+-#else
+-#define lookup_exception_vector(x)	\
+-	__asm__ __volatile__ ("mov r4, %0\n\t" : "=r" ((x)))
+ #endif
+ 
+ /*
+- * Handle various address error exceptions:
+- *  - instruction address error:
+- *       misaligned PC
+- *       PC >= 0x80000000 in user mode
+- *  - data address error (read and write)
+- *       misaligned data access
+- *       access to >= 0x80000000 is user mode
+- * Unfortuntaly we can't distinguish between instruction address error
+- * and data address errors caused by read accesses.
++ * Generic trap handler.
+  */
+-asmlinkage void do_address_error(struct pt_regs *regs,
+-				 unsigned long writeaccess,
+-				 unsigned long address)
++BUILD_TRAP_HANDLER(debug)
+ {
+-	unsigned long error_code = 0;
+-	mm_segment_t oldfs;
+-	siginfo_t info;
+-#ifndef CONFIG_CPU_SH2A
+-	u16 instruction;
+-	int tmp;
+-#endif
+-
+-	/* Intentional ifdef */
+-#ifdef CONFIG_CPU_HAS_SR_RB
+-	lookup_exception_vector(error_code);
+-#endif
+-
+-	oldfs = get_fs();
+-
+-	if (user_mode(regs)) {
+-		int si_code = BUS_ADRERR;
+-
+-		local_irq_enable();
++	TRAP_HANDLER_DECL;
+ 
+-		/* bad PC is not something we can fix */
+-		if (regs->pc & 1) {
+-			si_code = BUS_ADRALN;
+-			goto uspace_segv;
+-		}
++	/* Rewind */
++	regs->pc -= instruction_size(ctrl_inw(regs->pc - 4));
+ 
+-#ifndef CONFIG_CPU_SH2A
+-		set_fs(USER_DS);
+-		if (copy_from_user(&instruction, (u16 *)(regs->pc), 2)) {
+-			/* Argh. Fault on the instruction itself.
+-			   This should never happen non-SMP
+-			*/
+-			set_fs(oldfs);
+-			goto uspace_segv;
+-		}
+-
+-		tmp = handle_unaligned_access(instruction, regs);
+-		set_fs(oldfs);
+-
+-		if (tmp==0)
+-			return; /* sorted */
+-#endif
+-
+-uspace_segv:
+-		printk(KERN_NOTICE "Sending SIGBUS to \"%s\" due to unaligned "
+-		       "access (PC %lx PR %lx)\n", current->comm, regs->pc,
+-		       regs->pr);
+-
+-		info.si_signo = SIGBUS;
+-		info.si_errno = 0;
+-		info.si_code = si_code;
+-		info.si_addr = (void __user *)address;
+-		force_sig_info(SIGBUS, &info, current);
+-	} else {
+-		if (regs->pc & 1)
+-			die("unaligned program counter", regs, error_code);
+-
+-#ifndef CONFIG_CPU_SH2A
+-		set_fs(KERNEL_DS);
+-		if (copy_from_user(&instruction, (u16 *)(regs->pc), 2)) {
+-			/* Argh. Fault on the instruction itself.
+-			   This should never happen non-SMP
+-			*/
+-			set_fs(oldfs);
+-			die("insn faulting in do_address_error", regs, 0);
+-		}
+-
+-		handle_unaligned_access(instruction, regs);
+-		set_fs(oldfs);
+-#else
+-		printk(KERN_NOTICE "Killing process \"%s\" due to unaligned "
+-		       "access\n", current->comm);
++	if (notify_die(DIE_TRAP, "debug trap", regs, 0, vec & 0xff,
++		       SIGTRAP) == NOTIFY_STOP)
++		return;
+ 
+-		force_sig(SIGSEGV, current);
+-#endif
+-	}
++	force_sig(SIGTRAP, current);
+ }
+ 
+-#ifdef CONFIG_SH_DSP
+ /*
+- *	SH-DSP support gerg at snapgear.com.
++ * Special handler for BUG() traps.
+  */
+-int is_dsp_inst(struct pt_regs *regs)
++BUILD_TRAP_HANDLER(bug)
+ {
+-	unsigned short inst = 0;
+-
+-	/*
+-	 * Safe guard if DSP mode is already enabled or we're lacking
+-	 * the DSP altogether.
+-	 */
+-	if (!(current_cpu_data.flags & CPU_HAS_DSP) || (regs->sr & SR_DSP))
+-		return 0;
+-
+-	get_user(inst, ((unsigned short *) regs->pc));
+-
+-	inst &= 0xf000;
+-
+-	/* Check for any type of DSP or support instruction */
+-	if ((inst == 0xf000) || (inst == 0x4000))
+-		return 1;
+-
+-	return 0;
+-}
+-#else
+-#define is_dsp_inst(regs)	(0)
+-#endif /* CONFIG_SH_DSP */
++	TRAP_HANDLER_DECL;
+ 
+-#ifdef CONFIG_CPU_SH2A
+-asmlinkage void do_divide_error(unsigned long r4, unsigned long r5,
+-				unsigned long r6, unsigned long r7,
+-				struct pt_regs __regs)
+-{
+-	siginfo_t info;
+-
+-	switch (r4) {
+-	case TRAP_DIVZERO_ERROR:
+-		info.si_code = FPE_INTDIV;
+-		break;
+-	case TRAP_DIVOVF_ERROR:
+-		info.si_code = FPE_INTOVF;
+-		break;
+-	}
+-
+-	force_sig_info(SIGFPE, &info, current);
+-}
+-#endif
+-
+-/* arch/sh/kernel/cpu/sh4/fpu.c */
+-extern int do_fpu_inst(unsigned short, struct pt_regs *);
+-extern asmlinkage void do_fpu_state_restore(unsigned long r4, unsigned long r5,
+-		unsigned long r6, unsigned long r7, struct pt_regs __regs);
+-
+-asmlinkage void do_reserved_inst(unsigned long r4, unsigned long r5,
+-				unsigned long r6, unsigned long r7,
+-				struct pt_regs __regs)
+-{
+-	struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
+-	unsigned long error_code;
+-	struct task_struct *tsk = current;
+-
+-#ifdef CONFIG_SH_FPU_EMU
+-	unsigned short inst = 0;
+-	int err;
+-
+-	get_user(inst, (unsigned short*)regs->pc);
+-
+-	err = do_fpu_inst(inst, regs);
+-	if (!err) {
+-		regs->pc += instruction_size(inst);
+-		return;
+-	}
+-	/* not a FPU inst. */
+-#endif
++	/* Rewind */
++	regs->pc -= instruction_size(ctrl_inw(regs->pc - 4));
+ 
+-#ifdef CONFIG_SH_DSP
+-	/* Check if it's a DSP instruction */
+-	if (is_dsp_inst(regs)) {
+-		/* Enable DSP mode, and restart instruction. */
+-		regs->sr |= SR_DSP;
++	if (notify_die(DIE_TRAP, "bug trap", regs, 0, TRAPA_BUG_OPCODE & 0xff,
++		       SIGTRAP) == NOTIFY_STOP)
+ 		return;
+-	}
+-#endif
+-
+-	lookup_exception_vector(error_code);
+-
+-	local_irq_enable();
+-	CHK_REMOTE_DEBUG(regs);
+-	force_sig(SIGILL, tsk);
+-	die_if_no_fixup("reserved instruction", regs, error_code);
+-}
+-
+-#ifdef CONFIG_SH_FPU_EMU
+-static int emulate_branch(unsigned short inst, struct pt_regs* regs)
+-{
+-	/*
+-	 * bfs: 8fxx: PC+=d*2+4;
+-	 * bts: 8dxx: PC+=d*2+4;
+-	 * bra: axxx: PC+=D*2+4;
+-	 * bsr: bxxx: PC+=D*2+4  after PR=PC+4;
+-	 * braf:0x23: PC+=Rn*2+4;
+-	 * bsrf:0x03: PC+=Rn*2+4 after PR=PC+4;
+-	 * jmp: 4x2b: PC=Rn;
+-	 * jsr: 4x0b: PC=Rn      after PR=PC+4;
+-	 * rts: 000b: PC=PR;
+-	 */
+-	if ((inst & 0xfd00) == 0x8d00) {
+-		regs->pc += SH_PC_8BIT_OFFSET(inst);
+-		return 0;
+-	}
+-
+-	if ((inst & 0xe000) == 0xa000) {
+-		regs->pc += SH_PC_12BIT_OFFSET(inst);
+-		return 0;
+-	}
+-
+-	if ((inst & 0xf0df) == 0x0003) {
+-		regs->pc += regs->regs[(inst & 0x0f00) >> 8] + 4;
+-		return 0;
+-	}
+-
+-	if ((inst & 0xf0df) == 0x400b) {
+-		regs->pc = regs->regs[(inst & 0x0f00) >> 8];
+-		return 0;
+-	}
+-
+-	if ((inst & 0xffff) == 0x000b) {
+-		regs->pc = regs->pr;
+-		return 0;
+-	}
+-
+-	return 1;
+-}
+-#endif
+-
+-asmlinkage void do_illegal_slot_inst(unsigned long r4, unsigned long r5,
+-				unsigned long r6, unsigned long r7,
+-				struct pt_regs __regs)
+-{
+-	struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
+-	unsigned long error_code;
+-	struct task_struct *tsk = current;
+-#ifdef CONFIG_SH_FPU_EMU
+-	unsigned short inst = 0;
+-
+-	get_user(inst, (unsigned short *)regs->pc + 1);
+-	if (!do_fpu_inst(inst, regs)) {
+-		get_user(inst, (unsigned short *)regs->pc);
+-		if (!emulate_branch(inst, regs))
+-			return;
+-		/* fault in branch.*/
+-	}
+-	/* not a FPU inst. */
+-#endif
+-
+-	lookup_exception_vector(error_code);
+-
+-	local_irq_enable();
+-	CHK_REMOTE_DEBUG(regs);
+-	force_sig(SIGILL, tsk);
+-	die_if_no_fixup("illegal slot instruction", regs, error_code);
+-}
+-
+-asmlinkage void do_exception_error(unsigned long r4, unsigned long r5,
+-				   unsigned long r6, unsigned long r7,
+-				   struct pt_regs __regs)
+-{
+-	struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
+-	long ex;
+-
+-	lookup_exception_vector(ex);
+-	die_if_kernel("exception", regs, ex);
+-}
+-
+-#if defined(CONFIG_SH_STANDARD_BIOS)
+-void *gdb_vbr_vector;
+-
+-static inline void __init gdb_vbr_init(void)
+-{
+-	register unsigned long vbr;
+-
+-	/*
+-	 * Read the old value of the VBR register to initialise
+-	 * the vector through which debug and BIOS traps are
+-	 * delegated by the Linux trap handler.
+-	 */
+-	asm volatile("stc vbr, %0" : "=r" (vbr));
+-
+-	gdb_vbr_vector = (void *)(vbr + 0x100);
+-	printk("Setting GDB trap vector to 0x%08lx\n",
+-	       (unsigned long)gdb_vbr_vector);
+-}
+-#endif
+-
+-void __cpuinit per_cpu_trap_init(void)
+-{
+-	extern void *vbr_base;
+-
+-#ifdef CONFIG_SH_STANDARD_BIOS
+-	if (raw_smp_processor_id() == 0)
+-		gdb_vbr_init();
+-#endif
+-
+-	/* NOTE: The VBR value should be at P1
+-	   (or P2, virtural "fixed" address space).
+-	   It's definitely should not in physical address.  */
+-
+-	asm volatile("ldc	%0, vbr"
+-		     : /* no output */
+-		     : "r" (&vbr_base)
+-		     : "memory");
+-}
+-
+-void *set_exception_table_vec(unsigned int vec, void *handler)
+-{
+-	extern void *exception_handling_table[];
+-	void *old_handler;
+-
+-	old_handler = exception_handling_table[vec];
+-	exception_handling_table[vec] = handler;
+-	return old_handler;
+-}
+-
+-extern asmlinkage void address_error_handler(unsigned long r4, unsigned long r5,
+-					     unsigned long r6, unsigned long r7,
+-					     struct pt_regs __regs);
+-
+-void __init trap_init(void)
+-{
+-	set_exception_table_vec(TRAP_RESERVED_INST, do_reserved_inst);
+-	set_exception_table_vec(TRAP_ILLEGAL_SLOT_INST, do_illegal_slot_inst);
+-
+-#if defined(CONFIG_CPU_SH4) && !defined(CONFIG_SH_FPU) || \
+-    defined(CONFIG_SH_FPU_EMU)
+-	/*
+-	 * For SH-4 lacking an FPU, treat floating point instructions as
+-	 * reserved. They'll be handled in the math-emu case, or faulted on
+-	 * otherwise.
+-	 */
+-	set_exception_table_evt(0x800, do_reserved_inst);
+-	set_exception_table_evt(0x820, do_illegal_slot_inst);
+-#elif defined(CONFIG_SH_FPU)
+-#ifdef CONFIG_CPU_SUBTYPE_SHX3
+-	set_exception_table_evt(0xd80, do_fpu_state_restore);
+-	set_exception_table_evt(0xda0, do_fpu_state_restore);
+-#else
+-	set_exception_table_evt(0x800, do_fpu_state_restore);
+-	set_exception_table_evt(0x820, do_fpu_state_restore);
+-#endif
+-#endif
+-
+-#ifdef CONFIG_CPU_SH2
+-	set_exception_table_vec(TRAP_ADDRESS_ERROR, address_error_handler);
+-#endif
+-#ifdef CONFIG_CPU_SH2A
+-	set_exception_table_vec(TRAP_DIVZERO_ERROR, do_divide_error);
+-	set_exception_table_vec(TRAP_DIVOVF_ERROR, do_divide_error);
+-#endif
+-
+-	/* Setup VBR for boot cpu */
+-	per_cpu_trap_init();
+-}
+ 
+ #ifdef CONFIG_BUG
+-void handle_BUG(struct pt_regs *regs)
+-{
+-	enum bug_trap_type tt;
+-	tt = report_bug(regs->pc, regs);
+-	if (tt == BUG_TRAP_TYPE_WARN) {
+-		regs->pc += 2;
+-		return;
++	if (__kernel_text_address(instruction_pointer(regs))) {
++		opcode_t insn = *(opcode_t *)instruction_pointer(regs);
++		if (insn == TRAPA_BUG_OPCODE)
++			handle_BUG(regs);
+ 	}
+-
+-	die("Kernel BUG", regs, TRAPA_BUG_OPCODE & 0xff);
+-}
+-
+-int is_valid_bugaddr(unsigned long addr)
+-{
+-	return addr >= PAGE_OFFSET;
+-}
+-#endif
+-
+-void show_trace(struct task_struct *tsk, unsigned long *sp,
+-		struct pt_regs *regs)
+-{
+-	unsigned long addr;
+-
+-	if (regs && user_mode(regs))
+-		return;
+-
+-	printk("\nCall trace: ");
+-#ifdef CONFIG_KALLSYMS
+-	printk("\n");
+ #endif
+ 
+-	while (!kstack_end(sp)) {
+-		addr = *sp++;
+-		if (kernel_text_address(addr))
+-			print_ip_sym(addr);
+-	}
+-
+-	printk("\n");
+-
+-	if (!tsk)
+-		tsk = current;
+-
+-	debug_show_held_locks(tsk);
+-}
+-
+-void show_stack(struct task_struct *tsk, unsigned long *sp)
+-{
+-	unsigned long stack;
+-
+-	if (!tsk)
+-		tsk = current;
+-	if (tsk == current)
+-		sp = (unsigned long *)current_stack_pointer;
+-	else
+-		sp = (unsigned long *)tsk->thread.sp;
+-
+-	stack = (unsigned long)sp;
+-	dump_mem("Stack: ", stack, THREAD_SIZE +
+-		 (unsigned long)task_stack_page(tsk));
+-	show_trace(tsk, sp, NULL);
+-}
+-
+-void dump_stack(void)
+-{
+-	show_stack(NULL, NULL);
++	force_sig(SIGTRAP, current);
+ }
+-EXPORT_SYMBOL(dump_stack);
+diff --git a/arch/sh/kernel/traps_32.c b/arch/sh/kernel/traps_32.c
+new file mode 100644
+index 0000000..2e58f7a
+--- /dev/null
++++ b/arch/sh/kernel/traps_32.c
+@@ -0,0 +1,919 @@
++/*
++ * 'traps.c' handles hardware traps and faults after we have saved some
++ * state in 'entry.S'.
++ *
++ *  SuperH version: Copyright (C) 1999 Niibe Yutaka
++ *                  Copyright (C) 2000 Philipp Rumpf
++ *                  Copyright (C) 2000 David Howells
++ *                  Copyright (C) 2002 - 2007 Paul Mundt
++ *
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License.  See the file "COPYING" in the main directory of this archive
++ * for more details.
++ */
++#include <linux/kernel.h>
++#include <linux/ptrace.h>
++#include <linux/init.h>
++#include <linux/spinlock.h>
++#include <linux/module.h>
++#include <linux/kallsyms.h>
++#include <linux/io.h>
++#include <linux/bug.h>
++#include <linux/debug_locks.h>
++#include <linux/kdebug.h>
++#include <linux/kexec.h>
++#include <linux/limits.h>
++#include <asm/system.h>
++#include <asm/uaccess.h>
++
++#ifdef CONFIG_SH_KGDB
++#include <asm/kgdb.h>
++#define CHK_REMOTE_DEBUG(regs)			\
++{						\
++	if (kgdb_debug_hook && !user_mode(regs))\
++		(*kgdb_debug_hook)(regs);       \
++}
++#else
++#define CHK_REMOTE_DEBUG(regs)
++#endif
++
++#ifdef CONFIG_CPU_SH2
++# define TRAP_RESERVED_INST	4
++# define TRAP_ILLEGAL_SLOT_INST	6
++# define TRAP_ADDRESS_ERROR	9
++# ifdef CONFIG_CPU_SH2A
++#  define TRAP_DIVZERO_ERROR	17
++#  define TRAP_DIVOVF_ERROR	18
++# endif
++#else
++#define TRAP_RESERVED_INST	12
++#define TRAP_ILLEGAL_SLOT_INST	13
++#endif
++
++static void dump_mem(const char *str, unsigned long bottom, unsigned long top)
++{
++	unsigned long p;
++	int i;
++
++	printk("%s(0x%08lx to 0x%08lx)\n", str, bottom, top);
++
++	for (p = bottom & ~31; p < top; ) {
++		printk("%04lx: ", p & 0xffff);
++
++		for (i = 0; i < 8; i++, p += 4) {
++			unsigned int val;
++
++			if (p < bottom || p >= top)
++				printk("         ");
++			else {
++				if (__get_user(val, (unsigned int __user *)p)) {
++					printk("\n");
++					return;
++				}
++				printk("%08x ", val);
++			}
++		}
++		printk("\n");
++	}
++}
++
++static DEFINE_SPINLOCK(die_lock);
++
++void die(const char * str, struct pt_regs * regs, long err)
++{
++	static int die_counter;
++
++	oops_enter();
++
++	console_verbose();
++	spin_lock_irq(&die_lock);
++	bust_spinlocks(1);
++
++	printk("%s: %04lx [#%d]\n", str, err & 0xffff, ++die_counter);
++
++	CHK_REMOTE_DEBUG(regs);
++	print_modules();
++	show_regs(regs);
++
++	printk("Process: %s (pid: %d, stack limit = %p)\n", current->comm,
++			task_pid_nr(current), task_stack_page(current) + 1);
++
++	if (!user_mode(regs) || in_interrupt())
++		dump_mem("Stack: ", regs->regs[15], THREAD_SIZE +
++			 (unsigned long)task_stack_page(current));
++
++	bust_spinlocks(0);
++	add_taint(TAINT_DIE);
++	spin_unlock_irq(&die_lock);
++
++	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(SIGSEGV);
++}
++
++static inline void die_if_kernel(const char *str, struct pt_regs *regs,
++				 long err)
++{
++	if (!user_mode(regs))
++		die(str, regs, err);
++}
++
++/*
++ * try and fix up kernelspace address errors
++ * - userspace errors just cause EFAULT to be returned, resulting in SEGV
++ * - kernel/userspace interfaces cause a jump to an appropriate handler
++ * - other kernel errors are bad
++ * - return 0 if fixed-up, -EFAULT if non-fatal (to the kernel) fault
++ */
++static int die_if_no_fixup(const char * str, struct pt_regs * regs, long err)
++{
++	if (!user_mode(regs)) {
++		const struct exception_table_entry *fixup;
++		fixup = search_exception_tables(regs->pc);
++		if (fixup) {
++			regs->pc = fixup->fixup;
++			return 0;
++		}
++		die(str, regs, err);
++	}
++	return -EFAULT;
++}
++
++/*
++ * handle an instruction that does an unaligned memory access by emulating the
++ * desired behaviour
++ * - note that PC _may not_ point to the faulting instruction
++ *   (if that instruction is in a branch delay slot)
++ * - return 0 if emulation okay, -EFAULT on existential error
++ */
++static int handle_unaligned_ins(u16 instruction, struct pt_regs *regs)
++{
++	int ret, index, count;
++	unsigned long *rm, *rn;
++	unsigned char *src, *dst;
++
++	index = (instruction>>8)&15;	/* 0x0F00 */
++	rn = &regs->regs[index];
++
++	index = (instruction>>4)&15;	/* 0x00F0 */
++	rm = &regs->regs[index];
++
++	count = 1<<(instruction&3);
++
++	ret = -EFAULT;
++	switch (instruction>>12) {
++	case 0: /* mov.[bwl] to/from memory via r0+rn */
++		if (instruction & 8) {
++			/* from memory */
++			src = (unsigned char*) *rm;
++			src += regs->regs[0];
++			dst = (unsigned char*) rn;
++			*(unsigned long*)dst = 0;
++
++#ifdef __LITTLE_ENDIAN__
++			if (copy_from_user(dst, src, count))
++				goto fetch_fault;
++
++			if ((count == 2) && dst[1] & 0x80) {
++				dst[2] = 0xff;
++				dst[3] = 0xff;
++			}
++#else
++			dst += 4-count;
++
++			if (__copy_user(dst, src, count))
++				goto fetch_fault;
++
++			if ((count == 2) && dst[2] & 0x80) {
++				dst[0] = 0xff;
++				dst[1] = 0xff;
++			}
++#endif
++		} else {
++			/* to memory */
++			src = (unsigned char*) rm;
++#if !defined(__LITTLE_ENDIAN__)
++			src += 4-count;
++#endif
++			dst = (unsigned char*) *rn;
++			dst += regs->regs[0];
++
++			if (copy_to_user(dst, src, count))
++				goto fetch_fault;
++		}
++		ret = 0;
++		break;
++
++	case 1: /* mov.l Rm,@(disp,Rn) */
++		src = (unsigned char*) rm;
++		dst = (unsigned char*) *rn;
++		dst += (instruction&0x000F)<<2;
++
++		if (copy_to_user(dst,src,4))
++			goto fetch_fault;
++		ret = 0;
++		break;
++
++	case 2: /* mov.[bwl] to memory, possibly with pre-decrement */
++		if (instruction & 4)
++			*rn -= count;
++		src = (unsigned char*) rm;
++		dst = (unsigned char*) *rn;
++#if !defined(__LITTLE_ENDIAN__)
++		src += 4-count;
++#endif
++		if (copy_to_user(dst, src, count))
++			goto fetch_fault;
++		ret = 0;
++		break;
++
++	case 5: /* mov.l @(disp,Rm),Rn */
++		src = (unsigned char*) *rm;
++		src += (instruction&0x000F)<<2;
++		dst = (unsigned char*) rn;
++		*(unsigned long*)dst = 0;
++
++		if (copy_from_user(dst,src,4))
++			goto fetch_fault;
++		ret = 0;
++		break;
++
++	case 6:	/* mov.[bwl] from memory, possibly with post-increment */
++		src = (unsigned char*) *rm;
++		if (instruction & 4)
++			*rm += count;
++		dst = (unsigned char*) rn;
++		*(unsigned long*)dst = 0;
++
++#ifdef __LITTLE_ENDIAN__
++		if (copy_from_user(dst, src, count))
++			goto fetch_fault;
++
++		if ((count == 2) && dst[1] & 0x80) {
++			dst[2] = 0xff;
++			dst[3] = 0xff;
++		}
++#else
++		dst += 4-count;
++
++		if (copy_from_user(dst, src, count))
++			goto fetch_fault;
++
++		if ((count == 2) && dst[2] & 0x80) {
++			dst[0] = 0xff;
++			dst[1] = 0xff;
++		}
++#endif
++		ret = 0;
++		break;
++
++	case 8:
++		switch ((instruction&0xFF00)>>8) {
++		case 0x81: /* mov.w R0,@(disp,Rn) */
++			src = (unsigned char*) &regs->regs[0];
++#if !defined(__LITTLE_ENDIAN__)
++			src += 2;
++#endif
++			dst = (unsigned char*) *rm; /* called Rn in the spec */
++			dst += (instruction&0x000F)<<1;
++
++			if (copy_to_user(dst, src, 2))
++				goto fetch_fault;
++			ret = 0;
++			break;
++
++		case 0x85: /* mov.w @(disp,Rm),R0 */
++			src = (unsigned char*) *rm;
++			src += (instruction&0x000F)<<1;
++			dst = (unsigned char*) &regs->regs[0];
++			*(unsigned long*)dst = 0;
++
++#if !defined(__LITTLE_ENDIAN__)
++			dst += 2;
++#endif
++
++			if (copy_from_user(dst, src, 2))
++				goto fetch_fault;
++
++#ifdef __LITTLE_ENDIAN__
++			if (dst[1] & 0x80) {
++				dst[2] = 0xff;
++				dst[3] = 0xff;
++			}
++#else
++			if (dst[2] & 0x80) {
++				dst[0] = 0xff;
++				dst[1] = 0xff;
++			}
++#endif
++			ret = 0;
++			break;
++		}
++		break;
++	}
++	return ret;
++
++ fetch_fault:
++	/* Argh. Address not only misaligned but also non-existent.
++	 * Raise an EFAULT and see if it's trapped
++	 */
++	return die_if_no_fixup("Fault in unaligned fixup", regs, 0);
++}
++
++/*
++ * emulate the instruction in the delay slot
++ * - fetches the instruction from PC+2
++ */
++static inline int handle_unaligned_delayslot(struct pt_regs *regs)
++{
++	u16 instruction;
++
++	if (copy_from_user(&instruction, (u16 *)(regs->pc+2), 2)) {
++		/* the instruction-fetch faulted */
++		if (user_mode(regs))
++			return -EFAULT;
++
++		/* kernel */
++		die("delay-slot-insn faulting in handle_unaligned_delayslot",
++		    regs, 0);
++	}
++
++	return handle_unaligned_ins(instruction,regs);
++}
++
++/*
++ * handle an instruction that does an unaligned memory access
++ * - have to be careful of branch delay-slot instructions that fault
++ *  SH3:
++ *   - if the branch would be taken PC points to the branch
++ *   - if the branch would not be taken, PC points to delay-slot
++ *  SH4:
++ *   - PC always points to delayed branch
++ * - return 0 if handled, -EFAULT if failed (may not return if in kernel)
++ */
++
++/* Macros to determine offset from current PC for branch instructions */
++/* Explicit type coercion is used to force sign extension where needed */
++#define SH_PC_8BIT_OFFSET(instr) ((((signed char)(instr))*2) + 4)
++#define SH_PC_12BIT_OFFSET(instr) ((((signed short)(instr<<4))>>3) + 4)
++
++/*
++ * XXX: SH-2A needs this too, but it needs an overhaul thanks to mixed 32-bit
++ * opcodes..
++ */
++#ifndef CONFIG_CPU_SH2A
++static int handle_unaligned_notify_count = 10;
++
++static int handle_unaligned_access(u16 instruction, struct pt_regs *regs)
++{
++	u_int rm;
++	int ret, index;
++
++	index = (instruction>>8)&15;	/* 0x0F00 */
++	rm = regs->regs[index];
++
++	/* shout about the first ten userspace fixups */
++	if (user_mode(regs) && handle_unaligned_notify_count>0) {
++		handle_unaligned_notify_count--;
++
++		printk(KERN_NOTICE "Fixing up unaligned userspace access "
++		       "in \"%s\" pid=%d pc=0x%p ins=0x%04hx\n",
++		       current->comm, task_pid_nr(current),
++		       (u16 *)regs->pc, instruction);
++	}
++
++	ret = -EFAULT;
++	switch (instruction&0xF000) {
++	case 0x0000:
++		if (instruction==0x000B) {
++			/* rts */
++			ret = handle_unaligned_delayslot(regs);
++			if (ret==0)
++				regs->pc = regs->pr;
++		}
++		else if ((instruction&0x00FF)==0x0023) {
++			/* braf @Rm */
++			ret = handle_unaligned_delayslot(regs);
++			if (ret==0)
++				regs->pc += rm + 4;
++		}
++		else if ((instruction&0x00FF)==0x0003) {
++			/* bsrf @Rm */
++			ret = handle_unaligned_delayslot(regs);
++			if (ret==0) {
++				regs->pr = regs->pc + 4;
++				regs->pc += rm + 4;
++			}
++		}
++		else {
++			/* mov.[bwl] to/from memory via r0+rn */
++			goto simple;
++		}
++		break;
++
++	case 0x1000: /* mov.l Rm,@(disp,Rn) */
++		goto simple;
++
++	case 0x2000: /* mov.[bwl] to memory, possibly with pre-decrement */
++		goto simple;
++
++	case 0x4000:
++		if ((instruction&0x00FF)==0x002B) {
++			/* jmp @Rm */
++			ret = handle_unaligned_delayslot(regs);
++			if (ret==0)
++				regs->pc = rm;
++		}
++		else if ((instruction&0x00FF)==0x000B) {
++			/* jsr @Rm */
++			ret = handle_unaligned_delayslot(regs);
++			if (ret==0) {
++				regs->pr = regs->pc + 4;
++				regs->pc = rm;
++			}
++		}
++		else {
++			/* mov.[bwl] to/from memory via r0+rn */
++			goto simple;
++		}
++		break;
++
++	case 0x5000: /* mov.l @(disp,Rm),Rn */
++		goto simple;
++
++	case 0x6000: /* mov.[bwl] from memory, possibly with post-increment */
++		goto simple;
++
++	case 0x8000: /* bf lab, bf/s lab, bt lab, bt/s lab */
++		switch (instruction&0x0F00) {
++		case 0x0100: /* mov.w R0,@(disp,Rm) */
++			goto simple;
++		case 0x0500: /* mov.w @(disp,Rm),R0 */
++			goto simple;
++		case 0x0B00: /* bf   lab - no delayslot*/
++			break;
++		case 0x0F00: /* bf/s lab */
++			ret = handle_unaligned_delayslot(regs);
++			if (ret==0) {
++#if defined(CONFIG_CPU_SH4) || defined(CONFIG_SH7705_CACHE_32KB)
++				if ((regs->sr & 0x00000001) != 0)
++					regs->pc += 4; /* next after slot */
++				else
++#endif
++					regs->pc += SH_PC_8BIT_OFFSET(instruction);
++			}
++			break;
++		case 0x0900: /* bt   lab - no delayslot */
++			break;
++		case 0x0D00: /* bt/s lab */
++			ret = handle_unaligned_delayslot(regs);
++			if (ret==0) {
++#if defined(CONFIG_CPU_SH4) || defined(CONFIG_SH7705_CACHE_32KB)
++				if ((regs->sr & 0x00000001) == 0)
++					regs->pc += 4; /* next after slot */
++				else
++#endif
++					regs->pc += SH_PC_8BIT_OFFSET(instruction);
++			}
++			break;
++		}
++		break;
++
++	case 0xA000: /* bra label */
++		ret = handle_unaligned_delayslot(regs);
++		if (ret==0)
++			regs->pc += SH_PC_12BIT_OFFSET(instruction);
++		break;
++
++	case 0xB000: /* bsr label */
++		ret = handle_unaligned_delayslot(regs);
++		if (ret==0) {
++			regs->pr = regs->pc + 4;
++			regs->pc += SH_PC_12BIT_OFFSET(instruction);
++		}
++		break;
++	}
++	return ret;
++
++	/* handle non-delay-slot instruction */
++ simple:
++	ret = handle_unaligned_ins(instruction,regs);
++	if (ret==0)
++		regs->pc += instruction_size(instruction);
++	return ret;
++}
++#endif /* CONFIG_CPU_SH2A */
++
++#ifdef CONFIG_CPU_HAS_SR_RB
++#define lookup_exception_vector(x)	\
++	__asm__ __volatile__ ("stc r2_bank, %0\n\t" : "=r" ((x)))
++#else
++#define lookup_exception_vector(x)	\
++	__asm__ __volatile__ ("mov r4, %0\n\t" : "=r" ((x)))
++#endif
++
++/*
++ * Handle various address error exceptions:
++ *  - instruction address error:
++ *       misaligned PC
++ *       PC >= 0x80000000 in user mode
++ *  - data address error (read and write)
++ *       misaligned data access
++ *       access to >= 0x80000000 is user mode
++ * Unfortuntaly we can't distinguish between instruction address error
++ * and data address errors caused by read accesses.
++ */
++asmlinkage void do_address_error(struct pt_regs *regs,
++				 unsigned long writeaccess,
++				 unsigned long address)
++{
++	unsigned long error_code = 0;
++	mm_segment_t oldfs;
++	siginfo_t info;
++#ifndef CONFIG_CPU_SH2A
++	u16 instruction;
++	int tmp;
++#endif
++
++	/* Intentional ifdef */
++#ifdef CONFIG_CPU_HAS_SR_RB
++	lookup_exception_vector(error_code);
++#endif
++
++	oldfs = get_fs();
++
++	if (user_mode(regs)) {
++		int si_code = BUS_ADRERR;
++
++		local_irq_enable();
++
++		/* bad PC is not something we can fix */
++		if (regs->pc & 1) {
++			si_code = BUS_ADRALN;
++			goto uspace_segv;
++		}
++
++#ifndef CONFIG_CPU_SH2A
++		set_fs(USER_DS);
++		if (copy_from_user(&instruction, (u16 *)(regs->pc), 2)) {
++			/* Argh. Fault on the instruction itself.
++			   This should never happen non-SMP
++			*/
++			set_fs(oldfs);
++			goto uspace_segv;
++		}
++
++		tmp = handle_unaligned_access(instruction, regs);
++		set_fs(oldfs);
++
++		if (tmp==0)
++			return; /* sorted */
++#endif
++
++uspace_segv:
++		printk(KERN_NOTICE "Sending SIGBUS to \"%s\" due to unaligned "
++		       "access (PC %lx PR %lx)\n", current->comm, regs->pc,
++		       regs->pr);
++
++		info.si_signo = SIGBUS;
++		info.si_errno = 0;
++		info.si_code = si_code;
++		info.si_addr = (void __user *)address;
++		force_sig_info(SIGBUS, &info, current);
++	} else {
++		if (regs->pc & 1)
++			die("unaligned program counter", regs, error_code);
++
++#ifndef CONFIG_CPU_SH2A
++		set_fs(KERNEL_DS);
++		if (copy_from_user(&instruction, (u16 *)(regs->pc), 2)) {
++			/* Argh. Fault on the instruction itself.
++			   This should never happen non-SMP
++			*/
++			set_fs(oldfs);
++			die("insn faulting in do_address_error", regs, 0);
++		}
++
++		handle_unaligned_access(instruction, regs);
++		set_fs(oldfs);
++#else
++		printk(KERN_NOTICE "Killing process \"%s\" due to unaligned "
++		       "access\n", current->comm);
++
++		force_sig(SIGSEGV, current);
++#endif
++	}
++}
++
++#ifdef CONFIG_SH_DSP
++/*
++ *	SH-DSP support gerg at snapgear.com.
++ */
++int is_dsp_inst(struct pt_regs *regs)
++{
++	unsigned short inst = 0;
++
++	/*
++	 * Safe guard if DSP mode is already enabled or we're lacking
++	 * the DSP altogether.
++	 */
++	if (!(current_cpu_data.flags & CPU_HAS_DSP) || (regs->sr & SR_DSP))
++		return 0;
++
++	get_user(inst, ((unsigned short *) regs->pc));
++
++	inst &= 0xf000;
++
++	/* Check for any type of DSP or support instruction */
++	if ((inst == 0xf000) || (inst == 0x4000))
++		return 1;
++
++	return 0;
++}
++#else
++#define is_dsp_inst(regs)	(0)
++#endif /* CONFIG_SH_DSP */
++
++#ifdef CONFIG_CPU_SH2A
++asmlinkage void do_divide_error(unsigned long r4, unsigned long r5,
++				unsigned long r6, unsigned long r7,
++				struct pt_regs __regs)
++{
++	siginfo_t info;
++
++	switch (r4) {
++	case TRAP_DIVZERO_ERROR:
++		info.si_code = FPE_INTDIV;
++		break;
++	case TRAP_DIVOVF_ERROR:
++		info.si_code = FPE_INTOVF;
++		break;
++	}
++
++	force_sig_info(SIGFPE, &info, current);
++}
++#endif
++
++asmlinkage void do_reserved_inst(unsigned long r4, unsigned long r5,
++				unsigned long r6, unsigned long r7,
++				struct pt_regs __regs)
++{
++	struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
++	unsigned long error_code;
++	struct task_struct *tsk = current;
++
++#ifdef CONFIG_SH_FPU_EMU
++	unsigned short inst = 0;
++	int err;
++
++	get_user(inst, (unsigned short*)regs->pc);
++
++	err = do_fpu_inst(inst, regs);
++	if (!err) {
++		regs->pc += instruction_size(inst);
++		return;
++	}
++	/* not a FPU inst. */
++#endif
++
++#ifdef CONFIG_SH_DSP
++	/* Check if it's a DSP instruction */
++	if (is_dsp_inst(regs)) {
++		/* Enable DSP mode, and restart instruction. */
++		regs->sr |= SR_DSP;
++		return;
++	}
++#endif
++
++	lookup_exception_vector(error_code);
++
++	local_irq_enable();
++	CHK_REMOTE_DEBUG(regs);
++	force_sig(SIGILL, tsk);
++	die_if_no_fixup("reserved instruction", regs, error_code);
++}
++
++#ifdef CONFIG_SH_FPU_EMU
++static int emulate_branch(unsigned short inst, struct pt_regs* regs)
++{
++	/*
++	 * bfs: 8fxx: PC+=d*2+4;
++	 * bts: 8dxx: PC+=d*2+4;
++	 * bra: axxx: PC+=D*2+4;
++	 * bsr: bxxx: PC+=D*2+4  after PR=PC+4;
++	 * braf:0x23: PC+=Rn*2+4;
++	 * bsrf:0x03: PC+=Rn*2+4 after PR=PC+4;
++	 * jmp: 4x2b: PC=Rn;
++	 * jsr: 4x0b: PC=Rn      after PR=PC+4;
++	 * rts: 000b: PC=PR;
++	 */
++	if ((inst & 0xfd00) == 0x8d00) {
++		regs->pc += SH_PC_8BIT_OFFSET(inst);
++		return 0;
++	}
++
++	if ((inst & 0xe000) == 0xa000) {
++		regs->pc += SH_PC_12BIT_OFFSET(inst);
++		return 0;
++	}
++
++	if ((inst & 0xf0df) == 0x0003) {
++		regs->pc += regs->regs[(inst & 0x0f00) >> 8] + 4;
++		return 0;
++	}
++
++	if ((inst & 0xf0df) == 0x400b) {
++		regs->pc = regs->regs[(inst & 0x0f00) >> 8];
++		return 0;
++	}
++
++	if ((inst & 0xffff) == 0x000b) {
++		regs->pc = regs->pr;
++		return 0;
++	}
++
++	return 1;
++}
++#endif
++
++asmlinkage void do_illegal_slot_inst(unsigned long r4, unsigned long r5,
++				unsigned long r6, unsigned long r7,
++				struct pt_regs __regs)
++{
++	struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
++	unsigned long error_code;
++	struct task_struct *tsk = current;
++#ifdef CONFIG_SH_FPU_EMU
++	unsigned short inst = 0;
++
++	get_user(inst, (unsigned short *)regs->pc + 1);
++	if (!do_fpu_inst(inst, regs)) {
++		get_user(inst, (unsigned short *)regs->pc);
++		if (!emulate_branch(inst, regs))
++			return;
++		/* fault in branch.*/
++	}
++	/* not a FPU inst. */
++#endif
++
++	lookup_exception_vector(error_code);
++
++	local_irq_enable();
++	CHK_REMOTE_DEBUG(regs);
++	force_sig(SIGILL, tsk);
++	die_if_no_fixup("illegal slot instruction", regs, error_code);
++}
++
++asmlinkage void do_exception_error(unsigned long r4, unsigned long r5,
++				   unsigned long r6, unsigned long r7,
++				   struct pt_regs __regs)
++{
++	struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
++	long ex;
++
++	lookup_exception_vector(ex);
++	die_if_kernel("exception", regs, ex);
++}
++
++#if defined(CONFIG_SH_STANDARD_BIOS)
++void *gdb_vbr_vector;
++
++static inline void __init gdb_vbr_init(void)
++{
++	register unsigned long vbr;
++
++	/*
++	 * Read the old value of the VBR register to initialise
++	 * the vector through which debug and BIOS traps are
++	 * delegated by the Linux trap handler.
++	 */
++	asm volatile("stc vbr, %0" : "=r" (vbr));
++
++	gdb_vbr_vector = (void *)(vbr + 0x100);
++	printk("Setting GDB trap vector to 0x%08lx\n",
++	       (unsigned long)gdb_vbr_vector);
++}
++#endif
++
++void __cpuinit per_cpu_trap_init(void)
++{
++	extern void *vbr_base;
++
++#ifdef CONFIG_SH_STANDARD_BIOS
++	if (raw_smp_processor_id() == 0)
++		gdb_vbr_init();
++#endif
++
++	/* NOTE: The VBR value should be at P1
++	   (or P2, virtural "fixed" address space).
++	   It's definitely should not in physical address.  */
++
++	asm volatile("ldc	%0, vbr"
++		     : /* no output */
++		     : "r" (&vbr_base)
++		     : "memory");
++}
++
++void *set_exception_table_vec(unsigned int vec, void *handler)
++{
++	extern void *exception_handling_table[];
++	void *old_handler;
++
++	old_handler = exception_handling_table[vec];
++	exception_handling_table[vec] = handler;
++	return old_handler;
++}
++
++void __init trap_init(void)
++{
++	set_exception_table_vec(TRAP_RESERVED_INST, do_reserved_inst);
++	set_exception_table_vec(TRAP_ILLEGAL_SLOT_INST, do_illegal_slot_inst);
++
++#if defined(CONFIG_CPU_SH4) && !defined(CONFIG_SH_FPU) || \
++    defined(CONFIG_SH_FPU_EMU)
++	/*
++	 * For SH-4 lacking an FPU, treat floating point instructions as
++	 * reserved. They'll be handled in the math-emu case, or faulted on
++	 * otherwise.
++	 */
++	set_exception_table_evt(0x800, do_reserved_inst);
++	set_exception_table_evt(0x820, do_illegal_slot_inst);
++#elif defined(CONFIG_SH_FPU)
++#ifdef CONFIG_CPU_SUBTYPE_SHX3
++	set_exception_table_evt(0xd80, fpu_state_restore_trap_handler);
++	set_exception_table_evt(0xda0, fpu_state_restore_trap_handler);
++#else
++	set_exception_table_evt(0x800, fpu_state_restore_trap_handler);
++	set_exception_table_evt(0x820, fpu_state_restore_trap_handler);
++#endif
++#endif
++
++#ifdef CONFIG_CPU_SH2
++	set_exception_table_vec(TRAP_ADDRESS_ERROR, address_error_trap_handler);
++#endif
++#ifdef CONFIG_CPU_SH2A
++	set_exception_table_vec(TRAP_DIVZERO_ERROR, do_divide_error);
++	set_exception_table_vec(TRAP_DIVOVF_ERROR, do_divide_error);
++#endif
++
++	/* Setup VBR for boot cpu */
++	per_cpu_trap_init();
++}
++
++void show_trace(struct task_struct *tsk, unsigned long *sp,
++		struct pt_regs *regs)
++{
++	unsigned long addr;
++
++	if (regs && user_mode(regs))
++		return;
++
++	printk("\nCall trace: ");
++#ifdef CONFIG_KALLSYMS
++	printk("\n");
++#endif
++
++	while (!kstack_end(sp)) {
++		addr = *sp++;
++		if (kernel_text_address(addr))
++			print_ip_sym(addr);
++	}
++
++	printk("\n");
++
++	if (!tsk)
++		tsk = current;
++
++	debug_show_held_locks(tsk);
++}
++
++void show_stack(struct task_struct *tsk, unsigned long *sp)
++{
++	unsigned long stack;
++
++	if (!tsk)
++		tsk = current;
++	if (tsk == current)
++		sp = (unsigned long *)current_stack_pointer;
++	else
++		sp = (unsigned long *)tsk->thread.sp;
++
++	stack = (unsigned long)sp;
++	dump_mem("Stack: ", stack, THREAD_SIZE +
++		 (unsigned long)task_stack_page(tsk));
++	show_trace(tsk, sp, NULL);
++}
++
++void dump_stack(void)
++{
++	show_stack(NULL, NULL);
++}
++EXPORT_SYMBOL(dump_stack);
+diff --git a/arch/sh/kernel/traps_64.c b/arch/sh/kernel/traps_64.c
+new file mode 100644
+index 0000000..c0b3c6f
+--- /dev/null
++++ b/arch/sh/kernel/traps_64.c
+@@ -0,0 +1,975 @@
++/*
++ * arch/sh/kernel/traps_64.c
++ *
++ * Copyright (C) 2000, 2001  Paolo Alberelli
++ * Copyright (C) 2003, 2004  Paul Mundt
++ * Copyright (C) 2003, 2004  Richard Curnow
++ *
++ * 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/sched.h>
++#include <linux/kernel.h>
++#include <linux/string.h>
++#include <linux/errno.h>
++#include <linux/ptrace.h>
++#include <linux/timer.h>
++#include <linux/mm.h>
++#include <linux/smp.h>
++#include <linux/init.h>
++#include <linux/delay.h>
++#include <linux/spinlock.h>
++#include <linux/kallsyms.h>
++#include <linux/interrupt.h>
++#include <linux/sysctl.h>
++#include <linux/module.h>
++#include <asm/system.h>
++#include <asm/uaccess.h>
++#include <asm/io.h>
++#include <asm/atomic.h>
++#include <asm/processor.h>
++#include <asm/pgtable.h>
++
++#undef DEBUG_EXCEPTION
++#ifdef DEBUG_EXCEPTION
++/* implemented in ../lib/dbg.c */
++extern void show_excp_regs(char *fname, int trapnr, int signr,
++			   struct pt_regs *regs);
++#else
++#define show_excp_regs(a, b, c, d)
++#endif
++
++static void do_unhandled_exception(int trapnr, int signr, char *str, char *fn_name,
++		unsigned long error_code, struct pt_regs *regs, struct task_struct *tsk);
++
++#define DO_ERROR(trapnr, signr, str, name, tsk) \
++asmlinkage void do_##name(unsigned long error_code, struct pt_regs *regs) \
++{ \
++	do_unhandled_exception(trapnr, signr, str, __stringify(name), error_code, regs, current); \
++}
++
++spinlock_t die_lock;
++
++void die(const char * str, struct pt_regs * regs, long err)
++{
++	console_verbose();
++	spin_lock_irq(&die_lock);
++	printk("%s: %lx\n", str, (err & 0xffffff));
++	show_regs(regs);
++	spin_unlock_irq(&die_lock);
++	do_exit(SIGSEGV);
++}
++
++static inline void die_if_kernel(const char * str, struct pt_regs * regs, long err)
++{
++	if (!user_mode(regs))
++		die(str, regs, err);
++}
++
++static void die_if_no_fixup(const char * str, struct pt_regs * regs, long err)
++{
++	if (!user_mode(regs)) {
++		const struct exception_table_entry *fixup;
++		fixup = search_exception_tables(regs->pc);
++		if (fixup) {
++			regs->pc = fixup->fixup;
++			return;
++		}
++		die(str, regs, err);
++	}
++}
++
++DO_ERROR(13, SIGILL,  "illegal slot instruction", illegal_slot_inst, current)
++DO_ERROR(87, SIGSEGV, "address error (exec)", address_error_exec, current)
++
++
++/* Implement misaligned load/store handling for kernel (and optionally for user
++   mode too).  Limitation : only SHmedia mode code is handled - there is no
++   handling at all for misaligned accesses occurring in SHcompact code yet. */
++
++static int misaligned_fixup(struct pt_regs *regs);
++
++asmlinkage void do_address_error_load(unsigned long error_code, struct pt_regs *regs)
++{
++	if (misaligned_fixup(regs) < 0) {
++		do_unhandled_exception(7, SIGSEGV, "address error(load)",
++				"do_address_error_load",
++				error_code, regs, current);
++	}
++	return;
++}
++
++asmlinkage void do_address_error_store(unsigned long error_code, struct pt_regs *regs)
++{
++	if (misaligned_fixup(regs) < 0) {
++		do_unhandled_exception(8, SIGSEGV, "address error(store)",
++				"do_address_error_store",
++				error_code, regs, current);
++	}
++	return;
++}
++
++#if defined(CONFIG_SH64_ID2815_WORKAROUND)
++
++#define OPCODE_INVALID      0
++#define OPCODE_USER_VALID   1
++#define OPCODE_PRIV_VALID   2
++
++/* getcon/putcon - requires checking which control register is referenced. */
++#define OPCODE_CTRL_REG     3
++
++/* Table of valid opcodes for SHmedia mode.
++   Form a 10-bit value by concatenating the major/minor opcodes i.e.
++   opcode[31:26,20:16].  The 6 MSBs of this value index into the following
++   array.  The 4 LSBs select the bit-pair in the entry (bits 1:0 correspond to
++   LSBs==4'b0000 etc). */
++static unsigned long shmedia_opcode_table[64] = {
++	0x55554044,0x54445055,0x15141514,0x14541414,0x00000000,0x10001000,0x01110055,0x04050015,
++	0x00000444,0xc0000000,0x44545515,0x40405555,0x55550015,0x10005555,0x55555505,0x04050000,
++	0x00000555,0x00000404,0x00040445,0x15151414,0x00000000,0x00000000,0x00000000,0x00000000,
++	0x00000055,0x40404444,0x00000404,0xc0009495,0x00000000,0x00000000,0x00000000,0x00000000,
++	0x55555555,0x55555555,0x55555555,0x55555555,0x55555555,0x55555555,0x55555555,0x55555555,
++	0x55555555,0x55555555,0x55555555,0x55555555,0x55555555,0x55555555,0x55555555,0x55555555,
++	0x80005050,0x04005055,0x55555555,0x55555555,0x55555555,0x55555555,0x55555555,0x55555555,
++	0x81055554,0x00000404,0x55555555,0x55555555,0x00000000,0x00000000,0x00000000,0x00000000
++};
++
++void do_reserved_inst(unsigned long error_code, struct pt_regs *regs)
++{
++	/* Workaround SH5-101 cut2 silicon defect #2815 :
++	   in some situations, inter-mode branches from SHcompact -> SHmedia
++	   which should take ITLBMISS or EXECPROT exceptions at the target
++	   falsely take RESINST at the target instead. */
++
++	unsigned long opcode = 0x6ff4fff0; /* guaranteed reserved opcode */
++	unsigned long pc, aligned_pc;
++	int get_user_error;
++	int trapnr = 12;
++	int signr = SIGILL;
++	char *exception_name = "reserved_instruction";
++
++	pc = regs->pc;
++	if ((pc & 3) == 1) {
++		/* SHmedia : check for defect.  This requires executable vmas
++		   to be readable too. */
++		aligned_pc = pc & ~3;
++		if (!access_ok(VERIFY_READ, aligned_pc, sizeof(unsigned long))) {
++			get_user_error = -EFAULT;
++		} else {
++			get_user_error = __get_user(opcode, (unsigned long *)aligned_pc);
++		}
++		if (get_user_error >= 0) {
++			unsigned long index, shift;
++			unsigned long major, minor, combined;
++			unsigned long reserved_field;
++			reserved_field = opcode & 0xf; /* These bits are currently reserved as zero in all valid opcodes */
++			major = (opcode >> 26) & 0x3f;
++			minor = (opcode >> 16) & 0xf;
++			combined = (major << 4) | minor;
++			index = major;
++			shift = minor << 1;
++			if (reserved_field == 0) {
++				int opcode_state = (shmedia_opcode_table[index] >> shift) & 0x3;
++				switch (opcode_state) {
++					case OPCODE_INVALID:
++						/* Trap. */
++						break;
++					case OPCODE_USER_VALID:
++						/* Restart the instruction : the branch to the instruction will now be from an RTE
++						   not from SHcompact so the silicon defect won't be triggered. */
++						return;
++					case OPCODE_PRIV_VALID:
++						if (!user_mode(regs)) {
++							/* Should only ever get here if a module has
++							   SHcompact code inside it.  If so, the same fix up is needed. */
++							return; /* same reason */
++						}
++						/* Otherwise, user mode trying to execute a privileged instruction -
++						   fall through to trap. */
++						break;
++					case OPCODE_CTRL_REG:
++						/* If in privileged mode, return as above. */
++						if (!user_mode(regs)) return;
++						/* In user mode ... */
++						if (combined == 0x9f) { /* GETCON */
++							unsigned long regno = (opcode >> 20) & 0x3f;
++							if (regno >= 62) {
++								return;
++							}
++							/* Otherwise, reserved or privileged control register, => trap */
++						} else if (combined == 0x1bf) { /* PUTCON */
++							unsigned long regno = (opcode >> 4) & 0x3f;
++							if (regno >= 62) {
++								return;
++							}
++							/* Otherwise, reserved or privileged control register, => trap */
++						} else {
++							/* Trap */
++						}
++						break;
++					default:
++						/* Fall through to trap. */
++						break;
++				}
++			}
++			/* fall through to normal resinst processing */
++		} else {
++			/* Error trying to read opcode.  This typically means a
++			   real fault, not a RESINST any more.  So change the
++			   codes. */
++			trapnr = 87;
++			exception_name = "address error (exec)";
++			signr = SIGSEGV;
++		}
++	}
++
++	do_unhandled_exception(trapnr, signr, exception_name, "do_reserved_inst", error_code, regs, current);
++}
++
++#else /* CONFIG_SH64_ID2815_WORKAROUND */
++
++/* If the workaround isn't needed, this is just a straightforward reserved
++   instruction */
++DO_ERROR(12, SIGILL,  "reserved instruction", reserved_inst, current)
++
++#endif /* CONFIG_SH64_ID2815_WORKAROUND */
++
++/* Called with interrupts disabled */
++asmlinkage void do_exception_error(unsigned long ex, struct pt_regs *regs)
++{
++	show_excp_regs(__FUNCTION__, -1, -1, regs);
++	die_if_kernel("exception", regs, ex);
++}
++
++int do_unknown_trapa(unsigned long scId, struct pt_regs *regs)
++{
++	/* Syscall debug */
++        printk("System call ID error: [0x1#args:8 #syscall:16  0x%lx]\n", scId);
++
++	die_if_kernel("unknown trapa", regs, scId);
++
++	return -ENOSYS;
++}
++
++void show_stack(struct task_struct *tsk, unsigned long *sp)
++{
++#ifdef CONFIG_KALLSYMS
++	extern void sh64_unwind(struct pt_regs *regs);
++	struct pt_regs *regs;
++
++	regs = tsk ? tsk->thread.kregs : NULL;
++
++	sh64_unwind(regs);
++#else
++	printk(KERN_ERR "Can't backtrace on sh64 without CONFIG_KALLSYMS\n");
++#endif
++}
++
++void show_task(unsigned long *sp)
++{
++	show_stack(NULL, sp);
++}
++
++void dump_stack(void)
++{
++	show_task(NULL);
++}
++/* Needed by any user of WARN_ON in view of the defn in include/asm-sh/bug.h */
++EXPORT_SYMBOL(dump_stack);
++
++static void do_unhandled_exception(int trapnr, int signr, char *str, char *fn_name,
++		unsigned long error_code, struct pt_regs *regs, struct task_struct *tsk)
++{
++	show_excp_regs(fn_name, trapnr, signr, regs);
++	tsk->thread.error_code = error_code;
++	tsk->thread.trap_no = trapnr;
++
++	if (user_mode(regs))
++		force_sig(signr, tsk);
++
++	die_if_no_fixup(str, regs, error_code);
++}
++
++static int read_opcode(unsigned long long pc, unsigned long *result_opcode, int from_user_mode)
++{
++	int get_user_error;
++	unsigned long aligned_pc;
++	unsigned long opcode;
++
++	if ((pc & 3) == 1) {
++		/* SHmedia */
++		aligned_pc = pc & ~3;
++		if (from_user_mode) {
++			if (!access_ok(VERIFY_READ, aligned_pc, sizeof(unsigned long))) {
++				get_user_error = -EFAULT;
++			} else {
++				get_user_error = __get_user(opcode, (unsigned long *)aligned_pc);
++				*result_opcode = opcode;
++			}
++			return get_user_error;
++		} else {
++			/* If the fault was in the kernel, we can either read
++			 * this directly, or if not, we fault.
++			*/
++			*result_opcode = *(unsigned long *) aligned_pc;
++			return 0;
++		}
++	} else if ((pc & 1) == 0) {
++		/* SHcompact */
++		/* TODO : provide handling for this.  We don't really support
++		   user-mode SHcompact yet, and for a kernel fault, this would
++		   have to come from a module built for SHcompact.  */
++		return -EFAULT;
++	} else {
++		/* misaligned */
++		return -EFAULT;
++	}
++}
++
++static int address_is_sign_extended(__u64 a)
++{
++	__u64 b;
++#if (NEFF == 32)
++	b = (__u64)(__s64)(__s32)(a & 0xffffffffUL);
++	return (b == a) ? 1 : 0;
++#else
++#error "Sign extend check only works for NEFF==32"
++#endif
++}
++
++static int generate_and_check_address(struct pt_regs *regs,
++				      __u32 opcode,
++				      int displacement_not_indexed,
++				      int width_shift,
++				      __u64 *address)
++{
++	/* return -1 for fault, 0 for OK */
++
++	__u64 base_address, addr;
++	int basereg;
++
++	basereg = (opcode >> 20) & 0x3f;
++	base_address = regs->regs[basereg];
++	if (displacement_not_indexed) {
++		__s64 displacement;
++		displacement = (opcode >> 10) & 0x3ff;
++		displacement = ((displacement << 54) >> 54); /* sign extend */
++		addr = (__u64)((__s64)base_address + (displacement << width_shift));
++	} else {
++		__u64 offset;
++		int offsetreg;
++		offsetreg = (opcode >> 10) & 0x3f;
++		offset = regs->regs[offsetreg];
++		addr = base_address + offset;
++	}
++
++	/* Check sign extended */
++	if (!address_is_sign_extended(addr)) {
++		return -1;
++	}
++
++#if defined(CONFIG_SH64_USER_MISALIGNED_FIXUP)
++	/* Check accessible.  For misaligned access in the kernel, assume the
++	   address is always accessible (and if not, just fault when the
++	   load/store gets done.) */
++	if (user_mode(regs)) {
++		if (addr >= TASK_SIZE) {
++			return -1;
++		}
++		/* Do access_ok check later - it depends on whether it's a load or a store. */
++	}
++#endif
++
++	*address = addr;
++	return 0;
++}
++
++/* Default value as for sh */
++#if defined(CONFIG_SH64_USER_MISALIGNED_FIXUP)
++static int user_mode_unaligned_fixup_count = 10;
++static int user_mode_unaligned_fixup_enable = 1;
++#endif
++
++static int kernel_mode_unaligned_fixup_count = 32;
++
++static void misaligned_kernel_word_load(__u64 address, int do_sign_extend, __u64 *result)
++{
++	unsigned short x;
++	unsigned char *p, *q;
++	p = (unsigned char *) (int) address;
++	q = (unsigned char *) &x;
++	q[0] = p[0];
++	q[1] = p[1];
++
++	if (do_sign_extend) {
++		*result = (__u64)(__s64) *(short *) &x;
++	} else {
++		*result = (__u64) x;
++	}
++}
++
++static void misaligned_kernel_word_store(__u64 address, __u64 value)
++{
++	unsigned short x;
++	unsigned char *p, *q;
++	p = (unsigned char *) (int) address;
++	q = (unsigned char *) &x;
++
++	x = (__u16) value;
++	p[0] = q[0];
++	p[1] = q[1];
++}
++
++static int misaligned_load(struct pt_regs *regs,
++			   __u32 opcode,
++			   int displacement_not_indexed,
++			   int width_shift,
++			   int do_sign_extend)
++{
++	/* Return -1 for a fault, 0 for OK */
++	int error;
++	int destreg;
++	__u64 address;
++
++	error = generate_and_check_address(regs, opcode,
++			displacement_not_indexed, width_shift, &address);
++	if (error < 0) {
++		return error;
++	}
++
++	destreg = (opcode >> 4) & 0x3f;
++#if defined(CONFIG_SH64_USER_MISALIGNED_FIXUP)
++	if (user_mode(regs)) {
++		__u64 buffer;
++
++		if (!access_ok(VERIFY_READ, (unsigned long) address, 1UL<<width_shift)) {
++			return -1;
++		}
++
++		if (__copy_user(&buffer, (const void *)(int)address, (1 << width_shift)) > 0) {
++			return -1; /* fault */
++		}
++		switch (width_shift) {
++		case 1:
++			if (do_sign_extend) {
++				regs->regs[destreg] = (__u64)(__s64) *(__s16 *) &buffer;
++			} else {
++				regs->regs[destreg] = (__u64) *(__u16 *) &buffer;
++			}
++			break;
++		case 2:
++			regs->regs[destreg] = (__u64)(__s64) *(__s32 *) &buffer;
++			break;
++		case 3:
++			regs->regs[destreg] = buffer;
++			break;
++		default:
++			printk("Unexpected width_shift %d in misaligned_load, PC=%08lx\n",
++				width_shift, (unsigned long) regs->pc);
++			break;
++		}
++	} else
++#endif
++	{
++		/* kernel mode - we can take short cuts since if we fault, it's a genuine bug */
++		__u64 lo, hi;
++
++		switch (width_shift) {
++		case 1:
++			misaligned_kernel_word_load(address, do_sign_extend, &regs->regs[destreg]);
++			break;
++		case 2:
++			asm ("ldlo.l %1, 0, %0" : "=r" (lo) : "r" (address));
++			asm ("ldhi.l %1, 3, %0" : "=r" (hi) : "r" (address));
++			regs->regs[destreg] = lo | hi;
++			break;
++		case 3:
++			asm ("ldlo.q %1, 0, %0" : "=r" (lo) : "r" (address));
++			asm ("ldhi.q %1, 7, %0" : "=r" (hi) : "r" (address));
++			regs->regs[destreg] = lo | hi;
++			break;
++
++		default:
++			printk("Unexpected width_shift %d in misaligned_load, PC=%08lx\n",
++				width_shift, (unsigned long) regs->pc);
++			break;
++		}
++	}
++
++	return 0;
++
++}
++
++static int misaligned_store(struct pt_regs *regs,
++			    __u32 opcode,
++			    int displacement_not_indexed,
++			    int width_shift)
++{
++	/* Return -1 for a fault, 0 for OK */
++	int error;
++	int srcreg;
++	__u64 address;
++
++	error = generate_and_check_address(regs, opcode,
++			displacement_not_indexed, width_shift, &address);
++	if (error < 0) {
++		return error;
++	}
++
++	srcreg = (opcode >> 4) & 0x3f;
++#if defined(CONFIG_SH64_USER_MISALIGNED_FIXUP)
++	if (user_mode(regs)) {
++		__u64 buffer;
++
++		if (!access_ok(VERIFY_WRITE, (unsigned long) address, 1UL<<width_shift)) {
++			return -1;
++		}
++
++		switch (width_shift) {
++		case 1:
++			*(__u16 *) &buffer = (__u16) regs->regs[srcreg];
++			break;
++		case 2:
++			*(__u32 *) &buffer = (__u32) regs->regs[srcreg];
++			break;
++		case 3:
++			buffer = regs->regs[srcreg];
++			break;
++		default:
++			printk("Unexpected width_shift %d in misaligned_store, PC=%08lx\n",
++				width_shift, (unsigned long) regs->pc);
++			break;
++		}
++
++		if (__copy_user((void *)(int)address, &buffer, (1 << width_shift)) > 0) {
++			return -1; /* fault */
++		}
++	} else
++#endif
++	{
++		/* kernel mode - we can take short cuts since if we fault, it's a genuine bug */
++		__u64 val = regs->regs[srcreg];
++
++		switch (width_shift) {
++		case 1:
++			misaligned_kernel_word_store(address, val);
++			break;
++		case 2:
++			asm ("stlo.l %1, 0, %0" : : "r" (val), "r" (address));
++			asm ("sthi.l %1, 3, %0" : : "r" (val), "r" (address));
++			break;
++		case 3:
++			asm ("stlo.q %1, 0, %0" : : "r" (val), "r" (address));
++			asm ("sthi.q %1, 7, %0" : : "r" (val), "r" (address));
++			break;
++
++		default:
++			printk("Unexpected width_shift %d in misaligned_store, PC=%08lx\n",
++				width_shift, (unsigned long) regs->pc);
++			break;
++		}
++	}
++
++	return 0;
++
++}
++
++#if defined(CONFIG_SH64_USER_MISALIGNED_FIXUP)
++/* Never need to fix up misaligned FPU accesses within the kernel since that's a real
++   error. */
++static int misaligned_fpu_load(struct pt_regs *regs,
++			   __u32 opcode,
++			   int displacement_not_indexed,
++			   int width_shift,
++			   int do_paired_load)
++{
++	/* Return -1 for a fault, 0 for OK */
++	int error;
++	int destreg;
++	__u64 address;
++
++	error = generate_and_check_address(regs, opcode,
++			displacement_not_indexed, width_shift, &address);
++	if (error < 0) {
++		return error;
++	}
++
++	destreg = (opcode >> 4) & 0x3f;
++	if (user_mode(regs)) {
++		__u64 buffer;
++		__u32 buflo, bufhi;
++
++		if (!access_ok(VERIFY_READ, (unsigned long) address, 1UL<<width_shift)) {
++			return -1;
++		}
++
++		if (__copy_user(&buffer, (const void *)(int)address, (1 << width_shift)) > 0) {
++			return -1; /* fault */
++		}
++		/* 'current' may be the current owner of the FPU state, so
++		   context switch the registers into memory so they can be
++		   indexed by register number. */
++		if (last_task_used_math == current) {
++			enable_fpu();
++			save_fpu(current, regs);
++			disable_fpu();
++			last_task_used_math = NULL;
++			regs->sr |= SR_FD;
++		}
++
++		buflo = *(__u32*) &buffer;
++		bufhi = *(1 + (__u32*) &buffer);
++
++		switch (width_shift) {
++		case 2:
++			current->thread.fpu.hard.fp_regs[destreg] = buflo;
++			break;
++		case 3:
++			if (do_paired_load) {
++				current->thread.fpu.hard.fp_regs[destreg] = buflo;
++				current->thread.fpu.hard.fp_regs[destreg+1] = bufhi;
++			} else {
++#if defined(CONFIG_LITTLE_ENDIAN)
++				current->thread.fpu.hard.fp_regs[destreg] = bufhi;
++				current->thread.fpu.hard.fp_regs[destreg+1] = buflo;
++#else
++				current->thread.fpu.hard.fp_regs[destreg] = buflo;
++				current->thread.fpu.hard.fp_regs[destreg+1] = bufhi;
++#endif
++			}
++			break;
++		default:
++			printk("Unexpected width_shift %d in misaligned_fpu_load, PC=%08lx\n",
++				width_shift, (unsigned long) regs->pc);
++			break;
++		}
++		return 0;
++	} else {
++		die ("Misaligned FPU load inside kernel", regs, 0);
++		return -1;
++	}
++
++
++}
++
++static int misaligned_fpu_store(struct pt_regs *regs,
++			   __u32 opcode,
++			   int displacement_not_indexed,
++			   int width_shift,
++			   int do_paired_load)
++{
++	/* Return -1 for a fault, 0 for OK */
++	int error;
++	int srcreg;
++	__u64 address;
++
++	error = generate_and_check_address(regs, opcode,
++			displacement_not_indexed, width_shift, &address);
++	if (error < 0) {
++		return error;
++	}
++
++	srcreg = (opcode >> 4) & 0x3f;
++	if (user_mode(regs)) {
++		__u64 buffer;
++		/* Initialise these to NaNs. */
++		__u32 buflo=0xffffffffUL, bufhi=0xffffffffUL;
++
++		if (!access_ok(VERIFY_WRITE, (unsigned long) address, 1UL<<width_shift)) {
++			return -1;
++		}
++
++		/* 'current' may be the current owner of the FPU state, so
++		   context switch the registers into memory so they can be
++		   indexed by register number. */
++		if (last_task_used_math == current) {
++			enable_fpu();
++			save_fpu(current, regs);
++			disable_fpu();
++			last_task_used_math = NULL;
++			regs->sr |= SR_FD;
++		}
++
++		switch (width_shift) {
++		case 2:
++			buflo = current->thread.fpu.hard.fp_regs[srcreg];
++			break;
++		case 3:
++			if (do_paired_load) {
++				buflo = current->thread.fpu.hard.fp_regs[srcreg];
++				bufhi = current->thread.fpu.hard.fp_regs[srcreg+1];
++			} else {
++#if defined(CONFIG_LITTLE_ENDIAN)
++				bufhi = current->thread.fpu.hard.fp_regs[srcreg];
++				buflo = current->thread.fpu.hard.fp_regs[srcreg+1];
++#else
++				buflo = current->thread.fpu.hard.fp_regs[srcreg];
++				bufhi = current->thread.fpu.hard.fp_regs[srcreg+1];
++#endif
++			}
++			break;
++		default:
++			printk("Unexpected width_shift %d in misaligned_fpu_store, PC=%08lx\n",
++				width_shift, (unsigned long) regs->pc);
++			break;
++		}
++
++		*(__u32*) &buffer = buflo;
++		*(1 + (__u32*) &buffer) = bufhi;
++		if (__copy_user((void *)(int)address, &buffer, (1 << width_shift)) > 0) {
++			return -1; /* fault */
++		}
++		return 0;
++	} else {
++		die ("Misaligned FPU load inside kernel", regs, 0);
++		return -1;
++	}
++}
++#endif
++
++static int misaligned_fixup(struct pt_regs *regs)
++{
++	unsigned long opcode;
++	int error;
++	int major, minor;
++
++#if !defined(CONFIG_SH64_USER_MISALIGNED_FIXUP)
++	/* Never fixup user mode misaligned accesses without this option enabled. */
++	return -1;
++#else
++	if (!user_mode_unaligned_fixup_enable) return -1;
++#endif
++
++	error = read_opcode(regs->pc, &opcode, user_mode(regs));
++	if (error < 0) {
++		return error;
++	}
++	major = (opcode >> 26) & 0x3f;
++	minor = (opcode >> 16) & 0xf;
++
++#if defined(CONFIG_SH64_USER_MISALIGNED_FIXUP)
++	if (user_mode(regs) && (user_mode_unaligned_fixup_count > 0)) {
++		--user_mode_unaligned_fixup_count;
++		/* Only do 'count' worth of these reports, to remove a potential DoS against syslog */
++		printk("Fixing up unaligned userspace access in \"%s\" pid=%d pc=0x%08x ins=0x%08lx\n",
++		       current->comm, task_pid_nr(current), (__u32)regs->pc, opcode);
++	} else
++#endif
++	if (!user_mode(regs) && (kernel_mode_unaligned_fixup_count > 0)) {
++		--kernel_mode_unaligned_fixup_count;
++		if (in_interrupt()) {
++			printk("Fixing up unaligned kernelspace access in interrupt pc=0x%08x ins=0x%08lx\n",
++			       (__u32)regs->pc, opcode);
++		} else {
++			printk("Fixing up unaligned kernelspace access in \"%s\" pid=%d pc=0x%08x ins=0x%08lx\n",
++			       current->comm, task_pid_nr(current), (__u32)regs->pc, opcode);
++		}
++	}
++
++
++	switch (major) {
++		case (0x84>>2): /* LD.W */
++			error = misaligned_load(regs, opcode, 1, 1, 1);
++			break;
++		case (0xb0>>2): /* LD.UW */
++			error = misaligned_load(regs, opcode, 1, 1, 0);
++			break;
++		case (0x88>>2): /* LD.L */
++			error = misaligned_load(regs, opcode, 1, 2, 1);
++			break;
++		case (0x8c>>2): /* LD.Q */
++			error = misaligned_load(regs, opcode, 1, 3, 0);
++			break;
++
++		case (0xa4>>2): /* ST.W */
++			error = misaligned_store(regs, opcode, 1, 1);
++			break;
++		case (0xa8>>2): /* ST.L */
++			error = misaligned_store(regs, opcode, 1, 2);
++			break;
++		case (0xac>>2): /* ST.Q */
++			error = misaligned_store(regs, opcode, 1, 3);
++			break;
++
++		case (0x40>>2): /* indexed loads */
++			switch (minor) {
++				case 0x1: /* LDX.W */
++					error = misaligned_load(regs, opcode, 0, 1, 1);
++					break;
++				case 0x5: /* LDX.UW */
++					error = misaligned_load(regs, opcode, 0, 1, 0);
++					break;
++				case 0x2: /* LDX.L */
++					error = misaligned_load(regs, opcode, 0, 2, 1);
++					break;
++				case 0x3: /* LDX.Q */
++					error = misaligned_load(regs, opcode, 0, 3, 0);
++					break;
++				default:
++					error = -1;
++					break;
++			}
++			break;
++
++		case (0x60>>2): /* indexed stores */
++			switch (minor) {
++				case 0x1: /* STX.W */
++					error = misaligned_store(regs, opcode, 0, 1);
++					break;
++				case 0x2: /* STX.L */
++					error = misaligned_store(regs, opcode, 0, 2);
++					break;
++				case 0x3: /* STX.Q */
++					error = misaligned_store(regs, opcode, 0, 3);
++					break;
++				default:
++					error = -1;
++					break;
++			}
++			break;
++
++#if defined(CONFIG_SH64_USER_MISALIGNED_FIXUP)
++		case (0x94>>2): /* FLD.S */
++			error = misaligned_fpu_load(regs, opcode, 1, 2, 0);
++			break;
++		case (0x98>>2): /* FLD.P */
++			error = misaligned_fpu_load(regs, opcode, 1, 3, 1);
++			break;
++		case (0x9c>>2): /* FLD.D */
++			error = misaligned_fpu_load(regs, opcode, 1, 3, 0);
++			break;
++		case (0x1c>>2): /* floating indexed loads */
++			switch (minor) {
++			case 0x8: /* FLDX.S */
++				error = misaligned_fpu_load(regs, opcode, 0, 2, 0);
++				break;
++			case 0xd: /* FLDX.P */
++				error = misaligned_fpu_load(regs, opcode, 0, 3, 1);
++				break;
++			case 0x9: /* FLDX.D */
++				error = misaligned_fpu_load(regs, opcode, 0, 3, 0);
++				break;
++			default:
++				error = -1;
++				break;
++			}
++			break;
++		case (0xb4>>2): /* FLD.S */
++			error = misaligned_fpu_store(regs, opcode, 1, 2, 0);
++			break;
++		case (0xb8>>2): /* FLD.P */
++			error = misaligned_fpu_store(regs, opcode, 1, 3, 1);
++			break;
++		case (0xbc>>2): /* FLD.D */
++			error = misaligned_fpu_store(regs, opcode, 1, 3, 0);
++			break;
++		case (0x3c>>2): /* floating indexed stores */
++			switch (minor) {
++			case 0x8: /* FSTX.S */
++				error = misaligned_fpu_store(regs, opcode, 0, 2, 0);
++				break;
++			case 0xd: /* FSTX.P */
++				error = misaligned_fpu_store(regs, opcode, 0, 3, 1);
++				break;
++			case 0x9: /* FSTX.D */
++				error = misaligned_fpu_store(regs, opcode, 0, 3, 0);
++				break;
++			default:
++				error = -1;
++				break;
++			}
++			break;
++#endif
++
++		default:
++			/* Fault */
++			error = -1;
++			break;
++	}
++
++	if (error < 0) {
++		return error;
++	} else {
++		regs->pc += 4; /* Skip the instruction that's just been emulated */
++		return 0;
++	}
++
++}
++
++static ctl_table unaligned_table[] = {
++	{
++		.ctl_name	= CTL_UNNUMBERED,
++		.procname	= "kernel_reports",
++		.data		= &kernel_mode_unaligned_fixup_count,
++		.maxlen		= sizeof(int),
++		.mode		= 0644,
++		.proc_handler	= &proc_dointvec
++	},
++#if defined(CONFIG_SH64_USER_MISALIGNED_FIXUP)
++	{
++		.ctl_name	= CTL_UNNUMBERED,
++		.procname	= "user_reports",
++		.data		= &user_mode_unaligned_fixup_count,
++		.maxlen		= sizeof(int),
++		.mode		= 0644,
++		.proc_handler	= &proc_dointvec
++	},
++	{
++		.ctl_name	= CTL_UNNUMBERED,
++		.procname	= "user_enable",
++		.data		= &user_mode_unaligned_fixup_enable,
++		.maxlen		= sizeof(int),
++		.mode		= 0644,
++		.proc_handler	= &proc_dointvec},
++#endif
++	{}
++};
++
++static ctl_table unaligned_root[] = {
++	{
++		.ctl_name	= CTL_UNNUMBERED,
++		.procname	= "unaligned_fixup",
++		.mode		= 0555,
++		unaligned_table
++	},
++	{}
++};
++
++static ctl_table sh64_root[] = {
++	{
++		.ctl_name	= CTL_UNNUMBERED,
++		.procname	= "sh64",
++		.mode		= 0555,
++		.child		= unaligned_root
++	},
++	{}
++};
++static struct ctl_table_header *sysctl_header;
++static int __init init_sysctl(void)
++{
++	sysctl_header = register_sysctl_table(sh64_root);
++	return 0;
++}
++
++__initcall(init_sysctl);
++
++
++asmlinkage void do_debug_interrupt(unsigned long code, struct pt_regs *regs)
++{
++	u64 peek_real_address_q(u64 addr);
++	u64 poke_real_address_q(u64 addr, u64 val);
++	unsigned long long DM_EXP_CAUSE_PHY = 0x0c100010;
++	unsigned long long exp_cause;
++	/* It's not worth ioremapping the debug module registers for the amount
++	   of access we make to them - just go direct to their physical
++	   addresses. */
++	exp_cause = peek_real_address_q(DM_EXP_CAUSE_PHY);
++	if (exp_cause & ~4) {
++		printk("DM.EXP_CAUSE had unexpected bits set (=%08lx)\n",
++			(unsigned long)(exp_cause & 0xffffffff));
++	}
++	show_state();
++	/* Clear all DEBUGINT causes */
++	poke_real_address_q(DM_EXP_CAUSE_PHY, 0x0);
++}
+diff --git a/arch/sh/kernel/vmlinux.lds.S b/arch/sh/kernel/vmlinux.lds.S
+index 0956fb3..d7d4991 100644
+--- a/arch/sh/kernel/vmlinux.lds.S
++++ b/arch/sh/kernel/vmlinux.lds.S
+@@ -1,138 +1,5 @@
+-/*
+- * ld script to make SuperH Linux kernel
+- * Written by Niibe Yutaka
+- */
+-#include <asm/thread_info.h>
+-#include <asm/cache.h>
+-#include <asm-generic/vmlinux.lds.h>
+-
+-#ifdef CONFIG_CPU_LITTLE_ENDIAN
+-OUTPUT_FORMAT("elf32-sh-linux", "elf32-sh-linux", "elf32-sh-linux")
++#ifdef CONFIG_SUPERH32
++# include "vmlinux_32.lds.S"
+ #else
+-OUTPUT_FORMAT("elf32-shbig-linux", "elf32-shbig-linux", "elf32-shbig-linux")
++# include "vmlinux_64.lds.S"
+ #endif
+-OUTPUT_ARCH(sh)
+-ENTRY(_start)
+-SECTIONS
+-{
+-	. = CONFIG_PAGE_OFFSET + CONFIG_MEMORY_START + CONFIG_ZERO_PAGE_OFFSET;
+-	_text = .;			/* Text and read-only data */
+-
+-	.empty_zero_page : {
+-		*(.empty_zero_page)
+-	} = 0
+-
+-	.text : {
+-		*(.text.head)
+-		TEXT_TEXT
+-		SCHED_TEXT
+-		LOCK_TEXT
+-		KPROBES_TEXT
+-		*(.fixup)
+-		*(.gnu.warning)
+-	} = 0x0009
+-
+-	. = ALIGN(16);		/* Exception table */
+-	__start___ex_table = .;
+-	__ex_table : { *(__ex_table) }
+-	__stop___ex_table = .;
+-
+-	_etext = .;			/* End of text section */
+-
+-	BUG_TABLE
+-	NOTES
+-	RO_DATA(PAGE_SIZE)
+-
+-	. = ALIGN(THREAD_SIZE);
+-	.data : {			/* Data */
+-		*(.data.init_task)
+-
+-		. = ALIGN(L1_CACHE_BYTES);
+-		*(.data.cacheline_aligned)
+-
+-		. = ALIGN(L1_CACHE_BYTES);
+-		*(.data.read_mostly)
+-
+-		. = ALIGN(PAGE_SIZE);
+-		*(.data.page_aligned)
+-
+-		__nosave_begin = .;
+-		*(.data.nosave)
+-		. = ALIGN(PAGE_SIZE);
+-		__nosave_end = .;
+-
+-		DATA_DATA
+-		CONSTRUCTORS
+-	}
+-
+-	_edata = .;			/* End of data section */
+-
+-	. = ALIGN(PAGE_SIZE);		/* Init code and data */
+-	__init_begin = .;
+-	_sinittext = .;
+-	.init.text : { *(.init.text) }
+-	_einittext = .;
+-	.init.data : { *(.init.data) }
+-
+-	. = ALIGN(16);
+-	__setup_start = .;
+-	.init.setup : { *(.init.setup) }
+-	__setup_end = .;
+-
+-	__initcall_start = .;
+-	.initcall.init : {
+-		INITCALLS
+-	}
+-	__initcall_end = .;
+-	__con_initcall_start = .;
+-	.con_initcall.init : { *(.con_initcall.init) }
+-	__con_initcall_end = .;
+-
+-	SECURITY_INIT
+-
+-#ifdef CONFIG_BLK_DEV_INITRD
+-	. = ALIGN(PAGE_SIZE);
+-	__initramfs_start = .;
+-	.init.ramfs : { *(.init.ramfs) }
+-	__initramfs_end = .;
+-#endif
+-
+-	. = ALIGN(4);
+-	__machvec_start = .;
+-	.machvec.init : { *(.machvec.init) }
+-	__machvec_end = .;
+-
+-	PERCPU(PAGE_SIZE)
+-
+-	/*
+-	 * .exit.text is discarded at runtime, not link time, to deal with
+-	 * references from __bug_table
+-	 */
+-	.exit.text : { *(.exit.text) }
+-	.exit.data : { *(.exit.data) }
+-
+-	. = ALIGN(PAGE_SIZE);
+-	.bss : {
+-		__init_end = .;
+-		__bss_start = .;		/* BSS */
+-		*(.bss.page_aligned)
+-		*(.bss)
+-		*(COMMON)
+-		. = ALIGN(4);
+-		_ebss = .;			/* uClinux MTD sucks */
+-		_end = . ;
+-	}
+-
+-	/*
+-	 * When something in the kernel is NOT compiled as a module, the
+-	 * module cleanup code and data are put into these segments. Both
+-	 * can then be thrown away, as cleanup code is never called unless
+-	 * it's a module.
+-	 */
+-	/DISCARD/ : {
+-		*(.exitcall.exit)
+-	}
+-
+-	STABS_DEBUG
+-	DWARF_DEBUG
+-}
+diff --git a/arch/sh/kernel/vmlinux_32.lds.S b/arch/sh/kernel/vmlinux_32.lds.S
+new file mode 100644
+index 0000000..d549fac
+--- /dev/null
++++ b/arch/sh/kernel/vmlinux_32.lds.S
+@@ -0,0 +1,152 @@
++/*
++ * ld script to make SuperH Linux kernel
++ * Written by Niibe Yutaka
++ */
++#include <asm/thread_info.h>
++#include <asm/cache.h>
++#include <asm-generic/vmlinux.lds.h>
++
++#ifdef CONFIG_CPU_LITTLE_ENDIAN
++OUTPUT_FORMAT("elf32-sh-linux", "elf32-sh-linux", "elf32-sh-linux")
++#else
++OUTPUT_FORMAT("elf32-shbig-linux", "elf32-shbig-linux", "elf32-shbig-linux")
++#endif
++OUTPUT_ARCH(sh)
++ENTRY(_start)
++SECTIONS
++{
++#ifdef CONFIG_32BIT
++	. = CONFIG_PAGE_OFFSET + CONFIG_ZERO_PAGE_OFFSET;
++#else
++	. = CONFIG_PAGE_OFFSET + CONFIG_MEMORY_START + CONFIG_ZERO_PAGE_OFFSET;
++#endif
++
++	_text = .;			/* Text and read-only data */
++
++	.empty_zero_page : {
++		*(.empty_zero_page)
++	} = 0
++
++	.text : {
++		*(.text.head)
++		TEXT_TEXT
++		SCHED_TEXT
++		LOCK_TEXT
++		KPROBES_TEXT
++		*(.fixup)
++		*(.gnu.warning)
++	} = 0x0009
++
++	. = ALIGN(16);		/* Exception table */
++	__start___ex_table = .;
++	__ex_table : { *(__ex_table) }
++	__stop___ex_table = .;
++
++	_etext = .;			/* End of text section */
++
++	BUG_TABLE
++	NOTES
++	RO_DATA(PAGE_SIZE)
++
++	/*
++	 * Code which must be executed uncached and the associated data
++	 */
++	. = ALIGN(PAGE_SIZE);
++	__uncached_start = .;
++	.uncached.text : { *(.uncached.text) }
++	.uncached.data : { *(.uncached.data) }
++	__uncached_end = .;
++
++	. = ALIGN(THREAD_SIZE);
++	.data : {			/* Data */
++		*(.data.init_task)
++
++		. = ALIGN(L1_CACHE_BYTES);
++		*(.data.cacheline_aligned)
++
++		. = ALIGN(L1_CACHE_BYTES);
++		*(.data.read_mostly)
++
++		. = ALIGN(PAGE_SIZE);
++		*(.data.page_aligned)
++
++		__nosave_begin = .;
++		*(.data.nosave)
++		. = ALIGN(PAGE_SIZE);
++		__nosave_end = .;
++
++		DATA_DATA
++		CONSTRUCTORS
++	}
++
++	_edata = .;			/* End of data section */
++
++	. = ALIGN(PAGE_SIZE);		/* Init code and data */
++	__init_begin = .;
++	_sinittext = .;
++	.init.text : { *(.init.text) }
++	_einittext = .;
++	.init.data : { *(.init.data) }
++
++	. = ALIGN(16);
++	__setup_start = .;
++	.init.setup : { *(.init.setup) }
++	__setup_end = .;
++
++	__initcall_start = .;
++	.initcall.init : {
++		INITCALLS
++	}
++	__initcall_end = .;
++	__con_initcall_start = .;
++	.con_initcall.init : { *(.con_initcall.init) }
++	__con_initcall_end = .;
++
++	SECURITY_INIT
++
++#ifdef CONFIG_BLK_DEV_INITRD
++	. = ALIGN(PAGE_SIZE);
++	__initramfs_start = .;
++	.init.ramfs : { *(.init.ramfs) }
++	__initramfs_end = .;
++#endif
++
++	. = ALIGN(4);
++	__machvec_start = .;
++	.machvec.init : { *(.machvec.init) }
++	__machvec_end = .;
++
++	PERCPU(PAGE_SIZE)
++
++	/*
++	 * .exit.text is discarded at runtime, not link time, to deal with
++	 * references from __bug_table
++	 */
++	.exit.text : { *(.exit.text) }
++	.exit.data : { *(.exit.data) }
++
++	. = ALIGN(PAGE_SIZE);
++	.bss : {
++		__init_end = .;
++		__bss_start = .;		/* BSS */
++		*(.bss.page_aligned)
++		*(.bss)
++		*(COMMON)
++		. = ALIGN(4);
++		_ebss = .;			/* uClinux MTD sucks */
++		_end = . ;
++	}
++
++	/*
++	 * When something in the kernel is NOT compiled as a module, the
++	 * module cleanup code and data are put into these segments. Both
++	 * can then be thrown away, as cleanup code is never called unless
++	 * it's a module.
++	 */
++	/DISCARD/ : {
++		*(.exitcall.exit)
++	}
++
++	STABS_DEBUG
++	DWARF_DEBUG
++}
+diff --git a/arch/sh/kernel/vmlinux_64.lds.S b/arch/sh/kernel/vmlinux_64.lds.S
+new file mode 100644
+index 0000000..2fd0f74
+--- /dev/null
++++ b/arch/sh/kernel/vmlinux_64.lds.S
+@@ -0,0 +1,164 @@
++/*
++ * ld script to make SH64 Linux kernel
++ *
++ * Copyright (C) 2000, 2001  Paolo Alberelli
++ *
++ * benedict.gaster at superh.com:	 2nd May 2002
++ *    Add definition of empty_zero_page to be the first page of kernel image.
++ *
++ * benedict.gaster at superh.com:	 3rd May 2002
++ *    Added support for ramdisk, removing statically linked romfs at the
++ *    same time.
++ *
++ * lethal at linux-sh.org:          9th May 2003
++ *    Kill off GLOBAL_NAME() usage and other CDC-isms.
++ *
++ * lethal at linux-sh.org:         19th May 2003
++ *    Remove support for ancient toolchains.
++ *
++ * 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 <asm/page.h>
++#include <asm/cache.h>
++#include <asm/thread_info.h>
++
++#define LOAD_OFFSET	CONFIG_PAGE_OFFSET
++#include <asm-generic/vmlinux.lds.h>
++
++OUTPUT_ARCH(sh:sh5)
++
++#define C_PHYS(x) AT (ADDR(x) - LOAD_OFFSET)
++
++ENTRY(__start)
++SECTIONS
++{
++	. = CONFIG_PAGE_OFFSET + CONFIG_MEMORY_START + PAGE_SIZE;
++	_text = .;			/* Text and read-only data */
++
++	.empty_zero_page : C_PHYS(.empty_zero_page) {
++		*(.empty_zero_page)
++	} = 0
++
++	.text : C_PHYS(.text) {
++		*(.text.head)
++		TEXT_TEXT
++		*(.text64)
++		*(.text..SHmedia32)
++		SCHED_TEXT
++		LOCK_TEXT
++		KPROBES_TEXT
++		*(.fixup)
++		*(.gnu.warning)
++#ifdef CONFIG_LITTLE_ENDIAN
++	} = 0x6ff0fff0
++#else
++	} = 0xf0fff06f
++#endif
++
++	/* We likely want __ex_table to be Cache Line aligned */
++	. = ALIGN(L1_CACHE_BYTES);		/* Exception table */
++	__start___ex_table = .;
++	__ex_table : C_PHYS(__ex_table) { *(__ex_table) }
++	__stop___ex_table = .;
++
++	_etext = .;			/* End of text section */
++
++	BUG_TABLE
++	NOTES 
++	RO_DATA(PAGE_SIZE)
++
++	. = ALIGN(THREAD_SIZE);
++	.data : C_PHYS(.data) {			/* Data */
++		*(.data.init_task)
++
++		. = ALIGN(L1_CACHE_BYTES);
++		*(.data.cacheline_aligned)
++
++		. = ALIGN(L1_CACHE_BYTES);
++		*(.data.read_mostly)
++
++		. = ALIGN(PAGE_SIZE);
++		*(.data.page_aligned)
++
++		__nosave_begin = .;
++		*(.data.nosave)
++		. = ALIGN(PAGE_SIZE);
++		__nosave_end = .;
++
++		DATA_DATA
++		CONSTRUCTORS
++	}
++
++	_edata = .;			/* End of data section */
++
++	. = ALIGN(PAGE_SIZE);		/* Init code and data */
++	__init_begin = .;
++	_sinittext = .;
++	.init.text : C_PHYS(.init.text) { *(.init.text) }
++	_einittext = .;
++	.init.data : C_PHYS(.init.data) { *(.init.data) }
++	. = ALIGN(L1_CACHE_BYTES);	/* Better if Cache Line aligned */
++	__setup_start = .;
++	.init.setup : C_PHYS(.init.setup) { *(.init.setup) }
++	__setup_end = .;
++	__initcall_start = .;
++	.initcall.init : C_PHYS(.initcall.init) {
++		INITCALLS
++	}
++	__initcall_end = .;
++	__con_initcall_start = .;
++	.con_initcall.init : C_PHYS(.con_initcall.init) {
++		*(.con_initcall.init)
++	}
++	__con_initcall_end = .;
++
++	SECURITY_INIT
++
++#ifdef CONFIG_BLK_DEV_INITRD
++	. = ALIGN(PAGE_SIZE);
++	__initramfs_start = .;
++	.init.ramfs : C_PHYS(.init.ramfs) { *(.init.ramfs) }
++	__initramfs_end = .;
++#endif
++
++	. = ALIGN(8);
++	__machvec_start = .;
++	.machvec.init : C_PHYS(.machvec.init) { *(.machvec.init) }
++	__machvec_end = .;
++
++	PERCPU(PAGE_SIZE)
++
++	/*
++	 * .exit.text is discarded at runtime, not link time, to deal with
++	 * references from __bug_table
++	 */
++	.exit.text : C_PHYS(.exit.text) { *(.exit.text) }
++	.exit.data : C_PHYS(.exit.data) { *(.exit.data) }
++
++	. = ALIGN(PAGE_SIZE);
++	.bss : C_PHYS(.bss) {
++		__init_end = .;
++		__bss_start = .;		/* BSS */
++		*(.bss.page_aligned)
++		*(.bss)
++		*(COMMON)
++		. = ALIGN(4);
++		_ebss = .;			/* uClinux MTD sucks */
++		_end = . ;
++	}
++
++	/*
++	 * When something in the kernel is NOT compiled as a module, the
++	 * module cleanup code and data are put into these segments. Both
++	 * can then be thrown away, as cleanup code is never called unless
++	 * it's a module.
++	 */
++	/DISCARD/ : {
++		*(.exitcall.exit)
++	}
++
++	STABS_DEBUG
++	DWARF_DEBUG
++}
+diff --git a/arch/sh/lib/Makefile b/arch/sh/lib/Makefile
+index 9dc7b69..ebb55d1 100644
+--- a/arch/sh/lib/Makefile
++++ b/arch/sh/lib/Makefile
+@@ -2,12 +2,13 @@
+ # Makefile for SuperH-specific library files..
+ #
+ 
+-lib-y  = delay.o memset.o memmove.o memchr.o \
++lib-y  = delay.o io.o memset.o memmove.o memchr.o \
+ 	 checksum.o strlen.o div64.o div64-generic.o
+ 
+ memcpy-y			:= memcpy.o
+ memcpy-$(CONFIG_CPU_SH4)	:= memcpy-sh4.o
+ 
+-lib-y	+= $(memcpy-y)
++lib-$(CONFIG_MMU)		+= copy_page.o clear_page.o
++lib-y				+= $(memcpy-y)
+ 
+ EXTRA_CFLAGS += -Werror
+diff --git a/arch/sh/lib/clear_page.S b/arch/sh/lib/clear_page.S
+new file mode 100644
+index 0000000..3539123
+--- /dev/null
++++ b/arch/sh/lib/clear_page.S
+@@ -0,0 +1,154 @@
++/*
++ * __clear_user_page, __clear_user, clear_page implementation of SuperH
++ *
++ * Copyright (C) 2001  Kaz Kojima
++ * Copyright (C) 2001, 2002  Niibe Yutaka
++ * Copyright (C) 2006  Paul Mundt
++ */
++#include <linux/linkage.h>
++#include <asm/page.h>
++
++/*
++ * clear_page
++ * @to: P1 address
++ *
++ * void clear_page(void *to)
++ */
++
++/*
++ * r0 --- scratch
++ * r4 --- to
++ * r5 --- to + PAGE_SIZE
++ */
++ENTRY(clear_page)
++	mov	r4,r5
++	mov.l	.Llimit,r0
++	add	r0,r5
++	mov	#0,r0
++	!
++1:
++#if defined(CONFIG_CPU_SH3)
++	mov.l	r0, at r4
++#elif defined(CONFIG_CPU_SH4)
++	movca.l	r0, at r4
++	mov	r4,r1
++#endif
++	add	#32,r4
++	mov.l	r0, at -r4
++	mov.l	r0, at -r4
++	mov.l	r0, at -r4
++	mov.l	r0, at -r4
++	mov.l	r0, at -r4
++	mov.l	r0, at -r4
++	mov.l	r0, at -r4
++#if defined(CONFIG_CPU_SH4)
++	ocbwb	@r1
++#endif
++	cmp/eq	r5,r4
++	bf/s	1b
++	 add	#28,r4
++	!
++	rts
++	 nop
++
++	.balign 4
++.Llimit:	.long	(PAGE_SIZE-28)
++
++ENTRY(__clear_user)
++	!
++	mov	#0, r0
++	mov	#0xe0, r1	! 0xffffffe0
++	!
++	! r4..(r4+31)&~32 	   -------- not aligned	[ Area 0 ]
++	! (r4+31)&~32..(r4+r5)&~32 -------- aligned	[ Area 1 ]
++	! (r4+r5)&~32..r4+r5       -------- not aligned	[ Area 2 ]
++	!
++	! Clear area 0
++	mov	r4, r2
++	!
++	tst	r1, r5		! length < 32
++	bt	.Larea2		! skip to remainder
++	!
++	add	#31, r2
++	and	r1, r2
++	cmp/eq	r4, r2
++	bt	.Larea1
++	mov	r2, r3
++	sub	r4, r3
++	mov	r3, r7
++	mov	r4, r2
++	!
++.L0:	dt	r3
++0:	mov.b	r0, @r2
++	bf/s	.L0
++	 add	#1, r2
++	!
++	sub	r7, r5
++	mov	r2, r4
++.Larea1:
++	mov	r4, r3
++	add	r5, r3
++	and	r1, r3
++	cmp/hi	r2, r3
++	bf	.Larea2
++	!
++	! Clear area 1
++#if defined(CONFIG_CPU_SH4)
++1:	movca.l	r0, @r2
++#else
++1:	mov.l	r0, @r2
++#endif
++	add	#4, r2
++2:	mov.l	r0, @r2
++	add	#4, r2
++3:	mov.l	r0, @r2
++	add	#4, r2
++4:	mov.l	r0, @r2
++	add	#4, r2
++5:	mov.l	r0, @r2
++	add	#4, r2
++6:	mov.l	r0, @r2
++	add	#4, r2
++7:	mov.l	r0, @r2
++	add	#4, r2
++8:	mov.l	r0, @r2
++	add	#4, r2
++	cmp/hi	r2, r3
++	bt/s	1b
++	 nop
++	!
++	! Clear area 2
++.Larea2:
++	mov	r4, r3
++	add	r5, r3
++	cmp/hs	r3, r2
++	bt/s	.Ldone
++	 sub	r2, r3
++.L2:	dt	r3
++9:	mov.b	r0, @r2
++	bf/s	.L2
++	 add	#1, r2
++	!
++.Ldone:	rts
++	 mov	#0, r0	! return 0 as normal return
++
++	! return the number of bytes remained
++.Lbad_clear_user:
++	mov	r4, r0
++	add	r5, r0
++	rts
++	 sub	r2, r0
++
++.section __ex_table,"a"
++	.align 2
++	.long	0b, .Lbad_clear_user
++	.long	1b, .Lbad_clear_user
++	.long	2b, .Lbad_clear_user
++	.long	3b, .Lbad_clear_user
++	.long	4b, .Lbad_clear_user
++	.long	5b, .Lbad_clear_user
++	.long	6b, .Lbad_clear_user
++	.long	7b, .Lbad_clear_user
++	.long	8b, .Lbad_clear_user
++	.long	9b, .Lbad_clear_user
++.previous
+diff --git a/arch/sh/lib/copy_page.S b/arch/sh/lib/copy_page.S
+new file mode 100644
+index 0000000..e002b91
+--- /dev/null
++++ b/arch/sh/lib/copy_page.S
+@@ -0,0 +1,389 @@
++/*
++ * copy_page, __copy_user_page, __copy_user implementation of SuperH
++ *
++ * Copyright (C) 2001  Niibe Yutaka & Kaz Kojima
++ * Copyright (C) 2002  Toshinobu Sugioka
++ * Copyright (C) 2006  Paul Mundt
++ */
++#include <linux/linkage.h>
++#include <asm/page.h>
++
++/*
++ * copy_page
++ * @to: P1 address
++ * @from: P1 address
++ *
++ * void copy_page(void *to, void *from)
++ */
++
++/*
++ * r0, r1, r2, r3, r4, r5, r6, r7 --- scratch 
++ * r8 --- from + PAGE_SIZE
++ * r9 --- not used
++ * r10 --- to
++ * r11 --- from
++ */
++ENTRY(copy_page)
++	mov.l	r8, at -r15
++	mov.l	r10, at -r15
++	mov.l	r11, at -r15
++	mov	r4,r10
++	mov	r5,r11
++	mov	r5,r8
++	mov.l	.Lpsz,r0
++	add	r0,r8
++	!
++1:	mov.l	@r11+,r0
++	mov.l	@r11+,r1
++	mov.l	@r11+,r2
++	mov.l	@r11+,r3
++	mov.l	@r11+,r4
++	mov.l	@r11+,r5
++	mov.l	@r11+,r6
++	mov.l	@r11+,r7
++#if defined(CONFIG_CPU_SH3)
++	mov.l	r0, at r10
++#elif defined(CONFIG_CPU_SH4)
++	movca.l	r0, at r10
++	mov	r10,r0
++#endif
++	add	#32,r10
++	mov.l	r7, at -r10
++	mov.l	r6, at -r10
++	mov.l	r5, at -r10
++	mov.l	r4, at -r10
++	mov.l	r3, at -r10
++	mov.l	r2, at -r10
++	mov.l	r1, at -r10
++#if defined(CONFIG_CPU_SH4)
++	ocbwb	@r0
++#endif
++	cmp/eq	r11,r8
++	bf/s	1b
++	 add	#28,r10
++	!
++	mov.l	@r15+,r11
++	mov.l	@r15+,r10
++	mov.l	@r15+,r8
++	rts
++	 nop
++
++	.balign 4
++.Lpsz:	.long	PAGE_SIZE
++
++/*
++ * __kernel_size_t __copy_user(void *to, const void *from, __kernel_size_t n);
++ * Return the number of bytes NOT copied
++ */
++#define EX(...)			\
++	9999: __VA_ARGS__ ;		\
++	.section __ex_table, "a";	\
++	.long 9999b, 6000f	;	\
++	.previous
++ENTRY(__copy_user)
++	! Check if small number of bytes
++	mov	#11,r0
++	mov	r4,r3
++	cmp/gt	r0,r6		! r6 (len) > r0 (11)
++	bf/s	.L_cleanup_loop_no_pop
++	 add	r6,r3		! last destination address
++
++	! Calculate bytes needed to align to src
++	mov.l	r11, at -r15
++	neg	r5,r0
++	mov.l	r10, at -r15
++	add	#4,r0
++	mov.l	r9, at -r15
++	and	#3,r0
++	mov.l	r8, at -r15
++	tst	r0,r0
++	bt	2f
++
++1:
++	! Copy bytes to long word align src
++EX(	mov.b	@r5+,r1		)
++	dt	r0
++	add	#-1,r6
++EX(	mov.b	r1, at r4		)
++	bf/s	1b
++	 add	#1,r4
++
++	! Jump to appropriate routine depending on dest
++2:	mov	#3,r1
++	mov	r6, r2
++	and	r4,r1
++	shlr2	r2
++	shll2	r1
++	mova	.L_jump_tbl,r0
++	mov.l	@(r0,r1),r1
++	jmp	@r1
++	 nop
++
++	.align 2
++.L_jump_tbl:
++	.long	.L_dest00
++	.long	.L_dest01
++	.long	.L_dest10
++	.long	.L_dest11
++
++/*
++ * Come here if there are less than 12 bytes to copy
++ *
++ * Keep the branch target close, so the bf/s callee doesn't overflow
++ * and result in a more expensive branch being inserted. This is the
++ * fast-path for small copies, the jump via the jump table will hit the
++ * default slow-path cleanup. -PFM.
++ */
++.L_cleanup_loop_no_pop:
++	tst	r6,r6		! Check explicitly for zero
++	bt	1f
++
++2:
++EX(	mov.b	@r5+,r0		)
++	dt	r6
++EX(	mov.b	r0, at r4		)
++	bf/s	2b
++	 add	#1,r4
++
++1:	mov	#0,r0		! normal return
++5000:
++
++# Exception handler:
++.section .fixup, "ax"
++6000:
++	mov.l	8000f,r1
++	mov	r3,r0
++	jmp	@r1
++	 sub	r4,r0
++	.align	2
++8000:	.long	5000b
++
++.previous
++	rts
++	 nop
++
++! Destination = 00
++
++.L_dest00:
++	! Skip the large copy for small transfers
++	mov	#(32+32-4), r0
++	cmp/gt	r6, r0		! r0 (60) > r6 (len)
++	bt	1f
++
++	! Align dest to a 32 byte boundary
++	neg	r4,r0
++	add	#0x20, r0
++	and	#0x1f, r0
++	tst	r0, r0
++	bt	2f
++
++	sub	r0, r6
++	shlr2	r0
++3:
++EX(	mov.l	@r5+,r1		)
++	dt	r0
++EX(	mov.l	r1, at r4		)
++	bf/s	3b
++	 add	#4,r4
++
++2:
++EX(	mov.l	@r5+,r0		)
++EX(	mov.l	@r5+,r1		)
++EX(	mov.l	@r5+,r2		)
++EX(	mov.l	@r5+,r7		)
++EX(	mov.l	@r5+,r8		)
++EX(	mov.l	@r5+,r9		)
++EX(	mov.l	@r5+,r10	)
++EX(	mov.l	@r5+,r11	)
++#ifdef CONFIG_CPU_SH4
++EX(	movca.l	r0, at r4		)
++#else
++EX(	mov.l	r0, at r4		)
++#endif
++	add	#-32, r6
++EX(	mov.l	r1,@(4,r4)	)
++	mov	#32, r0
++EX(	mov.l	r2,@(8,r4)	)
++	cmp/gt	r6, r0		! r0 (32) > r6 (len)
++EX(	mov.l	r7,@(12,r4)	)
++EX(	mov.l	r8,@(16,r4)	)
++EX(	mov.l	r9,@(20,r4)	)
++EX(	mov.l	r10,@(24,r4)	)
++EX(	mov.l	r11,@(28,r4)	)
++	bf/s	2b
++	 add	#32,r4
++
++1:	mov	r6, r0
++	shlr2	r0
++	tst	r0, r0
++	bt	.L_cleanup
++1:
++EX(	mov.l	@r5+,r1		)
++	dt	r0
++EX(	mov.l	r1, at r4		)
++	bf/s	1b
++	 add	#4,r4
++
++	bra	.L_cleanup
++	 nop
++
++! Destination = 10
++
++.L_dest10:
++	mov	r2,r7
++	shlr2	r7
++	shlr	r7
++	tst	r7,r7
++	mov	#7,r0
++	bt/s	1f
++	 and	r0,r2
++2:
++	dt	r7
++#ifdef CONFIG_CPU_LITTLE_ENDIAN
++EX(	mov.l	@r5+,r0		)
++EX(	mov.l	@r5+,r1		)
++EX(	mov.l	@r5+,r8		)
++EX(	mov.l	@r5+,r9		)
++EX(	mov.l	@r5+,r10	)
++EX(	mov.w	r0, at r4		)
++	add	#2,r4
++	xtrct	r1,r0
++	xtrct	r8,r1
++	xtrct	r9,r8
++	xtrct	r10,r9
++
++EX(	mov.l	r0, at r4		)
++EX(	mov.l	r1,@(4,r4)	)
++EX(	mov.l	r8,@(8,r4)	)
++EX(	mov.l	r9,@(12,r4)	)
++
++EX(	mov.l	@r5+,r1		)
++EX(	mov.l	@r5+,r8		)
++EX(	mov.l	@r5+,r0		)
++	xtrct	r1,r10
++	xtrct	r8,r1
++	xtrct	r0,r8
++	shlr16	r0
++EX(	mov.l	r10,@(16,r4)	)
++EX(	mov.l	r1,@(20,r4)	)
++EX(	mov.l	r8,@(24,r4)	)
++EX(	mov.w	r0,@(28,r4)	)
++	bf/s	2b
++	 add	#30,r4
++#else
++EX(	mov.l	@(28,r5),r0	)
++EX(	mov.l	@(24,r5),r8	)
++EX(	mov.l	@(20,r5),r9	)
++EX(	mov.l	@(16,r5),r10	)
++EX(	mov.w	r0,@(30,r4)	)
++	add	#-2,r4
++	xtrct	r8,r0
++	xtrct	r9,r8
++	xtrct	r10,r9
++EX(	mov.l	r0,@(28,r4)	)
++EX(	mov.l	r8,@(24,r4)	)
++EX(	mov.l	r9,@(20,r4)	)
++
++EX(	mov.l	@(12,r5),r0	)
++EX(	mov.l	@(8,r5),r8	)
++	xtrct	r0,r10
++EX(	mov.l	@(4,r5),r9	)
++	mov.l	r10,@(16,r4)
++EX(	mov.l	@r5,r10		)
++	xtrct	r8,r0
++	xtrct	r9,r8
++	xtrct	r10,r9
++EX(	mov.l	r0,@(12,r4)	)
++EX(	mov.l	r8,@(8,r4)	)
++	swap.w	r10,r0
++EX(	mov.l	r9,@(4,r4)	)
++EX(	mov.w	r0,@(2,r4)	)
++
++	add	#32,r5
++	bf/s	2b
++	 add	#34,r4
++#endif
++	tst	r2,r2
++	bt	.L_cleanup
++
++1:	! Read longword, write two words per iteration
++EX(	mov.l	@r5+,r0		)
++	dt	r2
++#ifdef CONFIG_CPU_LITTLE_ENDIAN
++EX(	mov.w	r0, at r4		)
++	shlr16	r0
++EX(	mov.w 	r0,@(2,r4)	)
++#else
++EX(	mov.w	r0,@(2,r4)	)
++	shlr16	r0
++EX(	mov.w	r0, at r4		)
++#endif
++	bf/s	1b
++	 add	#4,r4
++
++	bra	.L_cleanup
++	 nop
++
++! Destination = 01 or 11
++
++.L_dest01:
++.L_dest11:
++	! Read longword, write byte, word, byte per iteration
++EX(	mov.l	@r5+,r0		)
++	dt	r2
++#ifdef CONFIG_CPU_LITTLE_ENDIAN
++EX(	mov.b	r0, at r4		)
++	shlr8	r0
++	add	#1,r4
++EX(	mov.w	r0, at r4		)
++	shlr16	r0
++EX(	mov.b	r0,@(2,r4)	)
++	bf/s	.L_dest01
++	 add	#3,r4
++#else
++EX(	mov.b	r0,@(3,r4)	)
++	shlr8	r0
++	swap.w	r0,r7
++EX(	mov.b	r7, at r4		)
++	add	#1,r4
++EX(	mov.w	r0, at r4		)
++	bf/s	.L_dest01
++	 add	#3,r4
++#endif
++
++! Cleanup last few bytes
++.L_cleanup:
++	mov	r6,r0
++	and	#3,r0
++	tst	r0,r0
++	bt	.L_exit
++	mov	r0,r6
++
++.L_cleanup_loop:
++EX(	mov.b	@r5+,r0		)
++	dt	r6
++EX(	mov.b	r0, at r4		)
++	bf/s	.L_cleanup_loop
++	 add	#1,r4
++
++.L_exit:
++	mov	#0,r0		! normal return
++
++5000:
++
++# Exception handler:
++.section .fixup, "ax"
++6000:
++	mov.l	8000f,r1
++	mov	r3,r0
++	jmp	@r1
++	 sub	r4,r0
++	.align	2
++8000:	.long	5000b
++
++.previous
++	mov.l	@r15+,r8
++	mov.l	@r15+,r9
++	mov.l	@r15+,r10
++	rts
++	 mov.l	@r15+,r11
+diff --git a/arch/sh/lib/io.c b/arch/sh/lib/io.c
+new file mode 100644
+index 0000000..4f54ec4
+--- /dev/null
++++ b/arch/sh/lib/io.c
+@@ -0,0 +1,82 @@
++/*
++ * arch/sh/lib/io.c - SH32 optimized I/O routines
++ *
++ * Copyright (C) 2000  Stuart Menefy
++ * Copyright (C) 2005  Paul Mundt
++ *
++ * Provide real functions which expand to whatever the header file defined.
++ * Also definitions of machine independent IO functions.
++ *
++ * 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/io.h>
++
++void __raw_readsl(unsigned long addr, void *datap, int len)
++{
++	u32 *data;
++
++	for (data = datap; (len != 0) && (((u32)data & 0x1f) != 0); len--)
++		*data++ = ctrl_inl(addr);
++
++	if (likely(len >= (0x20 >> 2))) {
++		int tmp2, tmp3, tmp4, tmp5, tmp6;
++
++		__asm__ __volatile__(
++			"1:			\n\t"
++			"mov.l	@%7, r0		\n\t"
++			"mov.l	@%7, %2		\n\t"
++#ifdef CONFIG_CPU_SH4
++			"movca.l r0, @%0	\n\t"
++#else
++			"mov.l	r0, @%0		\n\t"
++#endif
++			"mov.l	@%7, %3		\n\t"
++			"mov.l	@%7, %4		\n\t"
++			"mov.l	@%7, %5		\n\t"
++			"mov.l	@%7, %6		\n\t"
++			"mov.l	@%7, r7		\n\t"
++			"mov.l	@%7, r0		\n\t"
++			"mov.l	%2, @(0x04,%0)	\n\t"
++			"mov	#0x20>>2, %2	\n\t"
++			"mov.l	%3, @(0x08,%0)	\n\t"
++			"sub	%2, %1		\n\t"
++			"mov.l	%4, @(0x0c,%0)	\n\t"
++			"cmp/hi	%1, %2		! T if 32 > len	\n\t"
++			"mov.l	%5, @(0x10,%0)	\n\t"
++			"mov.l	%6, @(0x14,%0)	\n\t"
++			"mov.l	r7, @(0x18,%0)	\n\t"
++			"mov.l	r0, @(0x1c,%0)	\n\t"
++			"bf.s	1b		\n\t"
++			" add	#0x20, %0	\n\t"
++			: "=&r" (data), "=&r" (len),
++			  "=&r" (tmp2), "=&r" (tmp3), "=&r" (tmp4),
++			  "=&r" (tmp5), "=&r" (tmp6)
++			: "r"(addr), "0" (data), "1" (len)
++			: "r0", "r7", "t", "memory");
++	}
++
++	for (; len != 0; len--)
++		*data++ = ctrl_inl(addr);
++}
++EXPORT_SYMBOL(__raw_readsl);
++
++void __raw_writesl(unsigned long addr, const void *data, int len)
++{
++	if (likely(len != 0)) {
++		int tmp1;
++
++		__asm__ __volatile__ (
++			"1:				\n\t"
++			"mov.l	@%0+, %1	\n\t"
++			"dt		%3		\n\t"
++			"bf.s		1b		\n\t"
++			" mov.l	%1, @%4		\n\t"
++			: "=&r" (data), "=&r" (tmp1)
++			: "0" (data), "r" (len), "r"(addr)
++			: "t", "memory");
++	}
++}
++EXPORT_SYMBOL(__raw_writesl);
+diff --git a/arch/sh/lib64/.gitignore b/arch/sh/lib64/.gitignore
+new file mode 100644
+index 0000000..3508c2c
+--- /dev/null
++++ b/arch/sh/lib64/.gitignore
+@@ -0,0 +1 @@
++syscalltab.h
+diff --git a/arch/sh/lib64/Makefile b/arch/sh/lib64/Makefile
+new file mode 100644
+index 0000000..9950966
+--- /dev/null
++++ b/arch/sh/lib64/Makefile
+@@ -0,0 +1,15 @@
++#
++# Makefile for the SH-5 specific library files..
++#
++# Copyright (C) 2000, 2001  Paolo Alberelli
++# Copyright (C) 2003  Paul Mundt
++#
++# This file is subject to the terms and conditions of the GNU General Public
++# License.  See the file "COPYING" in the main directory of this archive
++# for more details.
++#
++
++# Panic should really be compiled as PIC
++lib-y  := udelay.o c-checksum.o dbg.o panic.o memcpy.o copy_user_memcpy.o \
++		copy_page.o clear_page.o
++
+diff --git a/arch/sh/lib64/c-checksum.c b/arch/sh/lib64/c-checksum.c
+new file mode 100644
+index 0000000..5dfbd8b
+--- /dev/null
++++ b/arch/sh/lib64/c-checksum.c
+@@ -0,0 +1,214 @@
++/*
++ * arch/sh/lib64/c-checksum.c
++ *
++ * This file contains network checksum routines that are better done
++ * in an architecture-specific manner due to speed..
++ */
++#include <linux/string.h>
++#include <linux/errno.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <asm/byteorder.h>
++#include <asm/uaccess.h>
++
++static inline unsigned short from64to16(unsigned long long x)
++{
++	/* add up 32-bit words for 33 bits */
++	x = (x & 0xffffffff) + (x >> 32);
++	/* add up 16-bit and 17-bit words for 17+c bits */
++	x = (x & 0xffff) + (x >> 16);
++	/* add up 16-bit and 2-bit for 16+c bit */
++	x = (x & 0xffff) + (x >> 16);
++	/* add up carry.. */
++	x = (x & 0xffff) + (x >> 16);
++	return x;
++}
++
++static inline unsigned short foldto16(unsigned long x)
++{
++	/* add up 16-bit for 17 bits */
++	x = (x & 0xffff) + (x >> 16);
++	/* add up carry.. */
++	x = (x & 0xffff) + (x >> 16);
++	return x;
++}
++
++static inline unsigned short myfoldto16(unsigned long long x)
++{
++	/* Fold down to 32-bits so we don't loose in the typedef-less
++	   network stack.  */
++	/* 64 to 33 */
++	x = (x & 0xffffffff) + (x >> 32);
++	/* 33 to 32 */
++	x = (x & 0xffffffff) + (x >> 32);
++
++	/* add up 16-bit for 17 bits */
++	x = (x & 0xffff) + (x >> 16);
++	/* add up carry.. */
++	x = (x & 0xffff) + (x >> 16);
++	return x;
++}
++
++#define odd(x) ((x)&1)
++#define U16(x) ntohs(x)
++
++static unsigned long do_csum(const unsigned char *buff, int len)
++{
++	int odd, count;
++	unsigned long result = 0;
++
++	pr_debug("do_csum buff %p, len %d (0x%x)\n", buff, len, len);
++#ifdef DEBUG
++	for (i = 0; i < len; i++) {
++		if ((i % 26) == 0)
++			printk("\n");
++		printk("%02X ", buff[i]);
++	}
++#endif
++
++	if (len <= 0)
++		goto out;
++
++	odd = 1 & (unsigned long) buff;
++	if (odd) {
++		result = *buff << 8;
++		len--;
++		buff++;
++	}
++	count = len >> 1;	/* nr of 16-bit words.. */
++	if (count) {
++		if (2 & (unsigned long) buff) {
++			result += *(unsigned short *) buff;
++			count--;
++			len -= 2;
++			buff += 2;
++		}
++		count >>= 1;	/* nr of 32-bit words.. */
++		if (count) {
++			unsigned long carry = 0;
++			do {
++				unsigned long w = *(unsigned long *) buff;
++				buff += 4;
++				count--;
++				result += carry;
++				result += w;
++				carry = (w > result);
++			} while (count);
++			result += carry;
++			result = (result & 0xffff) + (result >> 16);
++		}
++		if (len & 2) {
++			result += *(unsigned short *) buff;
++			buff += 2;
++		}
++	}
++	if (len & 1)
++		result += *buff;
++	result = foldto16(result);
++	if (odd)
++		result = ((result >> 8) & 0xff) | ((result & 0xff) << 8);
++
++	pr_debug("\nCHECKSUM is 0x%lx\n", result);
++
++      out:
++	return result;
++}
++
++/* computes the checksum of a memory block at buff, length len,
++   and adds in "sum" (32-bit)  */
++__wsum csum_partial(const void *buff, int len, __wsum sum)
++{
++	unsigned long long result = do_csum(buff, len);
++
++	/* add in old sum, and carry.. */
++	result += (__force u32)sum;
++	/* 32+c bits -> 32 bits */
++	result = (result & 0xffffffff) + (result >> 32);
++
++	pr_debug("csum_partial, buff %p len %d sum 0x%x result=0x%016Lx\n",
++		buff, len, sum, result);
++
++	return (__force __wsum)result;
++}
++
++/* Copy while checksumming, otherwise like csum_partial.  */
++__wsum
++csum_partial_copy_nocheck(const void *src, void *dst, int len, __wsum sum)
++{
++	sum = csum_partial(src, len, sum);
++	memcpy(dst, src, len);
++
++	return sum;
++}
++
++/* Copy from userspace and compute checksum.  If we catch an exception
++   then zero the rest of the buffer.  */
++__wsum
++csum_partial_copy_from_user(const void __user *src, void *dst, int len,
++			    __wsum sum, int *err_ptr)
++{
++	int missing;
++
++	pr_debug
++	    ("csum_partial_copy_from_user src %p, dest %p, len %d, sum %08x, err_ptr %p\n",
++	     src, dst, len, sum, err_ptr);
++	missing = copy_from_user(dst, src, len);
++	pr_debug("  access_ok %d\n", __access_ok((unsigned long) src, len));
++	pr_debug("  missing %d\n", missing);
++	if (missing) {
++		memset(dst + len - missing, 0, missing);
++		*err_ptr = -EFAULT;
++	}
++
++	return csum_partial(dst, len, sum);
++}
++
++/* Copy to userspace and compute checksum.  */
++__wsum
++csum_partial_copy_to_user(const unsigned char *src, unsigned char *dst, int len,
++			  __wsum sum, int *err_ptr)
++{
++	sum = csum_partial(src, len, sum);
++
++	if (copy_to_user(dst, src, len))
++		*err_ptr = -EFAULT;
++
++	return sum;
++}
++
++/*
++ *	This is a version of ip_compute_csum() optimized for IP headers,
++ *	which always checksum on 4 octet boundaries.
++ */
++__sum16 ip_fast_csum(const void *iph, unsigned int ihl)
++{
++	pr_debug("ip_fast_csum %p,%d\n", iph, ihl);
++
++	return (__force __sum16)~do_csum(iph, ihl * 4);
++}
++
++__wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr,
++				unsigned short len,
++				unsigned short proto, __wsum sum)
++{
++	unsigned long long result;
++
++	pr_debug("ntohs(0x%x)=0x%x\n", 0xdead, ntohs(0xdead));
++	pr_debug("htons(0x%x)=0x%x\n", 0xdead, htons(0xdead));
++
++	result = (__force u64) saddr + (__force u64) daddr +
++		 (__force u64) sum + ((len + proto) << 8);
++
++	/* Fold down to 32-bits so we don't loose in the typedef-less
++	   network stack.  */
++	/* 64 to 33 */
++	result = (result & 0xffffffff) + (result >> 32);
++	/* 33 to 32 */
++	result = (result & 0xffffffff) + (result >> 32);
++
++	pr_debug("%s saddr %x daddr %x len %x proto %x sum %x result %08Lx\n",
++		__FUNCTION__, saddr, daddr, len, proto, sum, result);
++
++	return (__wsum)result;
++}
++EXPORT_SYMBOL(csum_tcpudp_nofold);
+diff --git a/arch/sh/lib64/clear_page.S b/arch/sh/lib64/clear_page.S
+new file mode 100644
+index 0000000..007ab48
+--- /dev/null
++++ b/arch/sh/lib64/clear_page.S
+@@ -0,0 +1,54 @@
++/*
++   Copyright 2003 Richard Curnow, SuperH (UK) Ltd.
++
++   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.
++
++   Tight version of memset for the case of just clearing a page.  It turns out
++   that having the alloco's spaced out slightly due to the increment/branch
++   pair causes them to contend less for access to the cache.  Similarly,
++   keeping the stores apart from the allocos causes less contention.  => Do two
++   separate loops.  Do multiple stores per loop to amortise the
++   increment/branch cost a little.
++
++   Parameters:
++   r2 : source effective address (start of page)
++
++   Always clears 4096 bytes.
++
++   Note : alloco guarded by synco to avoid TAKum03020 erratum
++
++*/
++
++	.section .text..SHmedia32,"ax"
++	.little
++
++	.balign 8
++	.global clear_page
++clear_page:
++	pta/l 1f, tr1
++	pta/l 2f, tr2
++	ptabs/l r18, tr0
++
++	movi 4096, r7
++	add  r2, r7, r7
++	add  r2, r63, r6
++1:
++	alloco r6, 0
++	synco	! TAKum03020
++	addi	r6, 32, r6
++	bgt/l	r7, r6, tr1
++
++	add  r2, r63, r6
++2:
++	st.q  r6,   0, r63
++	st.q  r6,   8, r63
++	st.q  r6,  16, r63
++	st.q  r6,  24, r63
++	addi r6, 32, r6
++	bgt/l r7, r6, tr2
++
++	blink tr0, r63
++
++
+diff --git a/arch/sh/lib64/copy_page.S b/arch/sh/lib64/copy_page.S
+new file mode 100644
+index 0000000..0ec6fca
+--- /dev/null
++++ b/arch/sh/lib64/copy_page.S
+@@ -0,0 +1,89 @@
++/*
++   Copyright 2003 Richard Curnow, SuperH (UK) Ltd.
++
++   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.
++
++   Tight version of mempy for the case of just copying a page.
++   Prefetch strategy empirically optimised against RTL simulations
++   of SH5-101 cut2 eval chip with Cayman board DDR memory.
++
++   Parameters:
++   r2 : destination effective address (start of page)
++   r3 : source effective address (start of page)
++
++   Always copies 4096 bytes.
++
++   Points to review.
++   * Currently the prefetch is 4 lines ahead and the alloco is 2 lines ahead.
++     It seems like the prefetch needs to be at at least 4 lines ahead to get
++     the data into the cache in time, and the allocos contend with outstanding
++     prefetches for the same cache set, so it's better to have the numbers
++     different.
++   */
++
++	.section .text..SHmedia32,"ax"
++	.little
++
++	.balign 8
++	.global copy_page
++copy_page:
++
++	/* Copy 4096 bytes worth of data from r3 to r2.
++	   Do prefetches 4 lines ahead.
++	   Do alloco 2 lines ahead */
++
++	pta 1f, tr1
++	pta 2f, tr2
++	pta 3f, tr3
++	ptabs r18, tr0
++
++#if 0
++	/* TAKum03020 */
++	ld.q r3, 0x00, r63
++	ld.q r3, 0x20, r63
++	ld.q r3, 0x40, r63
++	ld.q r3, 0x60, r63
++#endif
++	alloco r2, 0x00
++	synco		! TAKum03020
++	alloco r2, 0x20
++	synco		! TAKum03020
++
++	movi 3968, r6
++	add  r2, r6, r6
++	addi r6, 64, r7
++	addi r7, 64, r8
++	sub r3, r2, r60
++	addi r60, 8, r61
++	addi r61, 8, r62
++	addi r62, 8, r23
++	addi r60, 0x80, r22
++
++/* Minimal code size.  The extra branches inside the loop don't cost much
++   because they overlap with the time spent waiting for prefetches to
++   complete. */
++1:
++#if 0
++	/* TAKum03020 */
++	bge/u r2, r6, tr2  ! skip prefetch for last 4 lines
++	ldx.q r2, r22, r63 ! prefetch 4 lines hence
++#endif
++2:
++	bge/u r2, r7, tr3  ! skip alloco for last 2 lines
++	alloco r2, 0x40    ! alloc destination line 2 lines ahead
++	synco		! TAKum03020
++3:
++	ldx.q r2, r60, r36
++	ldx.q r2, r61, r37
++	ldx.q r2, r62, r38
++	ldx.q r2, r23, r39
++	st.q  r2,   0, r36
++	st.q  r2,   8, r37
++	st.q  r2,  16, r38
++	st.q  r2,  24, r39
++	addi r2, 32, r2
++	bgt/l r8, r2, tr1
++
++	blink tr0, r63	   ! return
+diff --git a/arch/sh/lib64/copy_user_memcpy.S b/arch/sh/lib64/copy_user_memcpy.S
+new file mode 100644
+index 0000000..2a62816
+--- /dev/null
++++ b/arch/sh/lib64/copy_user_memcpy.S
+@@ -0,0 +1,217 @@
++!
++! Fast SH memcpy
++!
++! by Toshiyasu Morita (tm at netcom.com)
++! hacked by J"orn Rernnecke (joern.rennecke at superh.com) ("o for o-umlaut)
++! SH5 code Copyright 2002 SuperH Ltd.
++!
++! Entry: ARG0: destination pointer
++!        ARG1: source pointer
++!        ARG2: byte count
++!
++! Exit:  RESULT: destination pointer
++!        any other registers in the range r0-r7: trashed
++!
++! Notes: Usually one wants to do small reads and write a longword, but
++!        unfortunately it is difficult in some cases to concatanate bytes
++!        into a longword on the SH, so this does a longword read and small
++!        writes.
++!
++! This implementation makes two assumptions about how it is called:
++!
++! 1.: If the byte count is nonzero, the address of the last byte to be
++!     copied is unsigned greater than the address of the first byte to
++!     be copied.  This could be easily swapped for a signed comparison,
++!     but the algorithm used needs some comparison.
++!
++! 2.: When there are two or three bytes in the last word of an 11-or-more
++!     bytes memory chunk to b copied, the rest of the word can be read
++!     without side effects.
++!     This could be easily changed by increasing the minumum size of
++!     a fast memcpy and the amount subtracted from r7 before L_2l_loop be 2,
++!     however, this would cost a few extra cyles on average.
++!     For SHmedia, the assumption is that any quadword can be read in its
++!     enirety if at least one byte is included in the copy.
++
++/* Imported into Linux kernel by Richard Curnow.  This is used to implement the
++   __copy_user function in the general case, so it has to be a distinct
++   function from intra-kernel memcpy to allow for exception fix-ups in the
++   event that the user pointer is bad somewhere in the copy (e.g. due to
++   running off the end of the vma).
++
++   Note, this algorithm will be slightly wasteful in the case where the source
++   and destination pointers are equally aligned, because the stlo/sthi pairs
++   could then be merged back into single stores.  If there are a lot of cache
++   misses, this is probably offset by the stall lengths on the preloads.
++
++*/
++
++/* NOTE : Prefetches removed and allocos guarded by synco to avoid TAKum03020
++ * erratum.  The first two prefetches are nop-ed out to avoid upsetting the
++ * instruction counts used in the jump address calculation.
++ * */
++
++	.section .text..SHmedia32,"ax"
++	.little
++	.balign 32
++	.global copy_user_memcpy
++	.global copy_user_memcpy_end
++copy_user_memcpy:
++
++#define LDUAQ(P,O,D0,D1) ldlo.q P,O,D0; ldhi.q P,O+7,D1
++#define STUAQ(P,O,D0,D1) stlo.q P,O,D0; sthi.q P,O+7,D1
++#define LDUAL(P,O,D0,D1) ldlo.l P,O,D0; ldhi.l P,O+3,D1
++#define STUAL(P,O,D0,D1) stlo.l P,O,D0; sthi.l P,O+3,D1
++
++	nop ! ld.b r3,0,r63 ! TAKum03020
++	pta/l Large,tr0
++	movi 25,r0
++	bgeu/u r4,r0,tr0
++	nsb r4,r0
++	shlli r0,5,r0
++	movi (L1-L0+63*32 + 1) & 0xffff,r1
++	sub r1, r0, r0
++L0:	ptrel r0,tr0
++	add r2,r4,r5
++	ptabs r18,tr1
++	add r3,r4,r6
++	blink tr0,r63
++
++/* Rearranged to make cut2 safe */
++	.balign 8
++L4_7:	/* 4..7 byte memcpy cntd. */
++	stlo.l r2, 0, r0
++	or r6, r7, r6
++	sthi.l r5, -1, r6
++	stlo.l r5, -4, r6
++	blink tr1,r63
++
++	.balign 8
++L1:	/* 0 byte memcpy */
++	nop
++	blink tr1,r63
++	nop
++	nop
++	nop
++	nop
++
++L2_3:	/* 2 or 3 byte memcpy cntd. */
++	st.b r5,-1,r6
++	blink tr1,r63
++
++	/* 1 byte memcpy */
++	ld.b r3,0,r0
++	st.b r2,0,r0
++	blink tr1,r63
++
++L8_15:	/* 8..15 byte memcpy cntd. */
++	stlo.q r2, 0, r0
++	or r6, r7, r6
++	sthi.q r5, -1, r6
++	stlo.q r5, -8, r6
++	blink tr1,r63
++
++	/* 2 or 3 byte memcpy */
++	ld.b r3,0,r0
++	nop ! ld.b r2,0,r63 ! TAKum03020
++	ld.b r3,1,r1
++	st.b r2,0,r0
++	pta/l L2_3,tr0
++	ld.b r6,-1,r6
++	st.b r2,1,r1
++	blink tr0, r63
++
++	/* 4 .. 7 byte memcpy */
++	LDUAL (r3, 0, r0, r1)
++	pta L4_7, tr0
++	ldlo.l r6, -4, r7
++	or r0, r1, r0
++	sthi.l r2, 3, r0
++	ldhi.l r6, -1, r6
++	blink tr0, r63
++
++	/* 8 .. 15 byte memcpy */
++	LDUAQ (r3, 0, r0, r1)
++	pta L8_15, tr0
++	ldlo.q r6, -8, r7
++	or r0, r1, r0
++	sthi.q r2, 7, r0
++	ldhi.q r6, -1, r6
++	blink tr0, r63
++
++	/* 16 .. 24 byte memcpy */
++	LDUAQ (r3, 0, r0, r1)
++	LDUAQ (r3, 8, r8, r9)
++	or r0, r1, r0
++	sthi.q r2, 7, r0
++	or r8, r9, r8
++	sthi.q r2, 15, r8
++	ldlo.q r6, -8, r7
++	ldhi.q r6, -1, r6
++	stlo.q r2, 8, r8
++	stlo.q r2, 0, r0
++	or r6, r7, r6
++	sthi.q r5, -1, r6
++	stlo.q r5, -8, r6
++	blink tr1,r63
++
++Large:
++	! ld.b r2, 0, r63 ! TAKum03020
++	pta/l  Loop_ua, tr1
++	ori r3, -8, r7
++	sub r2, r7, r22
++	sub r3, r2, r6
++	add r2, r4, r5
++	ldlo.q r3, 0, r0
++	addi r5, -16, r5
++	movi 64+8, r27 ! could subtract r7 from that.
++	stlo.q r2, 0, r0
++	sthi.q r2, 7, r0
++	ldx.q r22, r6, r0
++	bgtu/l r27, r4, tr1
++
++	addi r5, -48, r27
++	pta/l Loop_line, tr0
++	addi r6, 64, r36
++	addi r6, -24, r19
++	addi r6, -16, r20
++	addi r6, -8, r21
++
++Loop_line:
++	! ldx.q r22, r36, r63 ! TAKum03020
++	alloco r22, 32
++	synco
++	addi r22, 32, r22
++	ldx.q r22, r19, r23
++	sthi.q r22, -25, r0
++	ldx.q r22, r20, r24
++	ldx.q r22, r21, r25
++	stlo.q r22, -32, r0
++	ldx.q r22, r6,  r0
++	sthi.q r22, -17, r23
++	sthi.q r22,  -9, r24
++	sthi.q r22,  -1, r25
++	stlo.q r22, -24, r23
++	stlo.q r22, -16, r24
++	stlo.q r22,  -8, r25
++	bgeu r27, r22, tr0
++
++Loop_ua:
++	addi r22, 8, r22
++	sthi.q r22, -1, r0
++	stlo.q r22, -8, r0
++	ldx.q r22, r6, r0
++	bgtu/l r5, r22, tr1
++
++	add r3, r4, r7
++	ldlo.q r7, -8, r1
++	sthi.q r22, 7, r0
++	ldhi.q r7, -1, r7
++	ptabs r18,tr1
++	stlo.q r22, 0, r0
++	or r1, r7, r1
++	sthi.q r5, 15, r1
++	stlo.q r5, 8, r1
++	blink tr1, r63
++copy_user_memcpy_end:
++	nop
+diff --git a/arch/sh/lib64/dbg.c b/arch/sh/lib64/dbg.c
+new file mode 100644
+index 0000000..75825ef
+--- /dev/null
++++ b/arch/sh/lib64/dbg.c
+@@ -0,0 +1,430 @@
++/*--------------------------------------------------------------------------
++--
++-- Identity : Linux50 Debug Funcions
++--
++-- File     : arch/sh/lib64/dbg.c
++--
++-- Copyright 2000, 2001 STMicroelectronics Limited.
++-- Copyright 2004 Richard Curnow (evt_debug etc)
++--
++--------------------------------------------------------------------------*/
++#include <linux/types.h>
++#include <linux/kernel.h>
++#include <linux/sched.h>
++#include <linux/mm.h>
++#include <linux/fs.h>
++#include <asm/mmu_context.h>
++
++typedef u64 regType_t;
++
++static regType_t getConfigReg(u64 id)
++{
++	register u64 reg __asm__("r2");
++	asm volatile ("getcfg   %1, 0, %0":"=r" (reg):"r"(id));
++	return (reg);
++}
++
++/* ======================================================================= */
++
++static char *szTab[] = { "4k", "64k", "1M", "512M" };
++static char *protTab[] = { "----",
++	"---R",
++	"--X-",
++	"--XR",
++	"-W--",
++	"-W-R",
++	"-WX-",
++	"-WXR",
++	"U---",
++	"U--R",
++	"U-X-",
++	"U-XR",
++	"UW--",
++	"UW-R",
++	"UWX-",
++	"UWXR"
++};
++#define  ITLB_BASE	0x00000000
++#define  DTLB_BASE	0x00800000
++#define  MAX_TLBs		64
++/* PTE High */
++#define  GET_VALID(pte)        ((pte) & 0x1)
++#define  GET_SHARED(pte)       ((pte) & 0x2)
++#define  GET_ASID(pte)         ((pte >> 2) & 0x0ff)
++#define  GET_EPN(pte)          ((pte) & 0xfffff000)
++
++/* PTE Low */
++#define  GET_CBEHAVIOR(pte)    ((pte) & 0x3)
++#define  GET_PAGE_SIZE(pte)    szTab[((pte >> 3) & 0x3)]
++#define  GET_PROTECTION(pte)   protTab[((pte >> 6) & 0xf)]
++#define  GET_PPN(pte)          ((pte) & 0xfffff000)
++
++#define PAGE_1K_MASK           0x00000000
++#define PAGE_4K_MASK           0x00000010
++#define PAGE_64K_MASK          0x00000080
++#define MMU_PAGESIZE_MASK      (PAGE_64K_MASK | PAGE_4K_MASK)
++#define PAGE_1MB_MASK          MMU_PAGESIZE_MASK
++#define PAGE_1K                (1024)
++#define PAGE_4K                (1024 * 4)
++#define PAGE_64K               (1024 * 64)
++#define PAGE_1MB               (1024 * 1024)
++
++#define HOW_TO_READ_TLB_CONTENT  \
++       "[ ID]  PPN         EPN        ASID  Share  CB  P.Size   PROT.\n"
++
++void print_single_tlb(unsigned long tlb, int single_print)
++{
++	regType_t pteH;
++	regType_t pteL;
++	unsigned int valid, shared, asid, epn, cb, ppn;
++	char *pSize;
++	char *pProt;
++
++	/*
++	   ** in case of single print <single_print> is true, this implies:
++	   **   1) print the TLB in any case also if NOT VALID
++	   **   2) print out the header
++	 */
++
++	pteH = getConfigReg(tlb);
++	valid = GET_VALID(pteH);
++	if (single_print)
++		printk(HOW_TO_READ_TLB_CONTENT);
++	else if (!valid)
++		return;
++
++	pteL = getConfigReg(tlb + 1);
++
++	shared = GET_SHARED(pteH);
++	asid = GET_ASID(pteH);
++	epn = GET_EPN(pteH);
++	cb = GET_CBEHAVIOR(pteL);
++	pSize = GET_PAGE_SIZE(pteL);
++	pProt = GET_PROTECTION(pteL);
++	ppn = GET_PPN(pteL);
++	printk("[%c%2ld]  0x%08x  0x%08x  %03d   %02x    %02x   %4s    %s\n",
++	       ((valid) ? ' ' : 'u'), ((tlb & 0x0ffff) / TLB_STEP),
++	       ppn, epn, asid, shared, cb, pSize, pProt);
++}
++
++void print_dtlb(void)
++{
++	int count;
++	unsigned long tlb;
++
++	printk(" ================= SH-5 D-TLBs Status ===================\n");
++	printk(HOW_TO_READ_TLB_CONTENT);
++	tlb = DTLB_BASE;
++	for (count = 0; count < MAX_TLBs; count++, tlb += TLB_STEP)
++		print_single_tlb(tlb, 0);
++	printk
++	    (" =============================================================\n");
++}
++
++void print_itlb(void)
++{
++	int count;
++	unsigned long tlb;
++
++	printk(" ================= SH-5 I-TLBs Status ===================\n");
++	printk(HOW_TO_READ_TLB_CONTENT);
++	tlb = ITLB_BASE;
++	for (count = 0; count < MAX_TLBs; count++, tlb += TLB_STEP)
++		print_single_tlb(tlb, 0);
++	printk
++	    (" =============================================================\n");
++}
++
++/* ======================================================================= */
++
++#ifdef CONFIG_POOR_MANS_STRACE
++
++#include "syscalltab.h"
++
++struct ring_node {
++	int evt;
++	int ret_addr;
++	int event;
++	int tra;
++	int pid;
++	unsigned long sp;
++	unsigned long pc;
++};
++
++static struct ring_node event_ring[16];
++static int event_ptr = 0;
++
++struct stored_syscall_data {
++	int pid;
++	int syscall_number;
++};
++
++#define N_STORED_SYSCALLS 16
++
++static struct stored_syscall_data stored_syscalls[N_STORED_SYSCALLS];
++static int syscall_next=0;
++static int syscall_next_print=0;
++
++void evt_debug(int evt, int ret_addr, int event, int tra, struct pt_regs *regs)
++{
++	int syscallno = tra & 0xff;
++	unsigned long sp;
++	unsigned long stack_bottom;
++	int pid;
++	struct ring_node *rr;
++
++	pid = current->pid;
++	stack_bottom = (unsigned long) task_stack_page(current);
++	asm volatile("ori r15, 0, %0" : "=r" (sp));
++	rr = event_ring + event_ptr;
++	rr->evt = evt;
++	rr->ret_addr = ret_addr;
++	rr->event = event;
++	rr->tra = tra;
++	rr->pid = pid;
++	rr->sp = sp;
++	rr->pc = regs->pc;
++
++	if (sp < stack_bottom + 3092) {
++		printk("evt_debug : stack underflow report\n");
++		int i, j;
++		for (j=0, i = event_ptr; j<16; j++) {
++			rr = event_ring + i;
++			printk("evt=%08x event=%08x tra=%08x pid=%5d sp=%08lx pc=%08lx\n",
++				rr->evt, rr->event, rr->tra, rr->pid, rr->sp, rr->pc);
++			i--;
++			i &= 15;
++		}
++		panic("STACK UNDERFLOW\n");
++	}
++
++	event_ptr = (event_ptr + 1) & 15;
++
++	if ((event == 2) && (evt == 0x160)) {
++		if (syscallno < NUM_SYSCALL_INFO_ENTRIES) {
++			/* Store the syscall information to print later.  We
++			 * can't print this now - currently we're running with
++			 * SR.BL=1, so we can't take a tlbmiss (which could occur
++			 * in the console drivers under printk).
++			 *
++			 * Just overwrite old entries on ring overflow - this
++			 * is only for last-hope debugging. */
++			stored_syscalls[syscall_next].pid = current->pid;
++			stored_syscalls[syscall_next].syscall_number = syscallno;
++			syscall_next++;
++			syscall_next &= (N_STORED_SYSCALLS - 1);
++		}
++	}
++}
++
++static void drain_syscalls(void) {
++	while (syscall_next_print != syscall_next) {
++		printk("Task %d: %s()\n",
++			stored_syscalls[syscall_next_print].pid,
++			syscall_info_table[stored_syscalls[syscall_next_print].syscall_number].name);
++			syscall_next_print++;
++			syscall_next_print &= (N_STORED_SYSCALLS - 1);
++	}
++}
++
++void evt_debug2(unsigned int ret)
++{
++	drain_syscalls();
++	printk("Task %d: syscall returns %08x\n", current->pid, ret);
++}
++
++void evt_debug_ret_from_irq(struct pt_regs *regs)
++{
++	int pid;
++	struct ring_node *rr;
++
++	pid = current->pid;
++	rr = event_ring + event_ptr;
++	rr->evt = 0xffff;
++	rr->ret_addr = 0;
++	rr->event = 0;
++	rr->tra = 0;
++	rr->pid = pid;
++	rr->pc = regs->pc;
++	event_ptr = (event_ptr + 1) & 15;
++}
++
++void evt_debug_ret_from_exc(struct pt_regs *regs)
++{
++	int pid;
++	struct ring_node *rr;
++
++	pid = current->pid;
++	rr = event_ring + event_ptr;
++	rr->evt = 0xfffe;
++	rr->ret_addr = 0;
++	rr->event = 0;
++	rr->tra = 0;
++	rr->pid = pid;
++	rr->pc = regs->pc;
++	event_ptr = (event_ptr + 1) & 15;
++}
++
++#endif /* CONFIG_POOR_MANS_STRACE */
++
++/* ======================================================================= */
++
++void show_excp_regs(char *from, int trapnr, int signr, struct pt_regs *regs)
++{
++
++	unsigned long long ah, al, bh, bl, ch, cl;
++
++	printk("\n");
++	printk("EXCEPTION - %s: task %d; Linux trap # %d; signal = %d\n",
++	       ((from) ? from : "???"), current->pid, trapnr, signr);
++
++	asm volatile ("getcon   " __EXPEVT ", %0":"=r"(ah));
++	asm volatile ("getcon   " __EXPEVT ", %0":"=r"(al));
++	ah = (ah) >> 32;
++	al = (al) & 0xffffffff;
++	asm volatile ("getcon   " __KCR1 ", %0":"=r"(bh));
++	asm volatile ("getcon   " __KCR1 ", %0":"=r"(bl));
++	bh = (bh) >> 32;
++	bl = (bl) & 0xffffffff;
++	asm volatile ("getcon   " __INTEVT ", %0":"=r"(ch));
++	asm volatile ("getcon   " __INTEVT ", %0":"=r"(cl));
++	ch = (ch) >> 32;
++	cl = (cl) & 0xffffffff;
++	printk("EXPE: %08Lx%08Lx KCR1: %08Lx%08Lx INTE: %08Lx%08Lx\n",
++	       ah, al, bh, bl, ch, cl);
++
++	asm volatile ("getcon   " __PEXPEVT ", %0":"=r"(ah));
++	asm volatile ("getcon   " __PEXPEVT ", %0":"=r"(al));
++	ah = (ah) >> 32;
++	al = (al) & 0xffffffff;
++	asm volatile ("getcon   " __PSPC ", %0":"=r"(bh));
++	asm volatile ("getcon   " __PSPC ", %0":"=r"(bl));
++	bh = (bh) >> 32;
++	bl = (bl) & 0xffffffff;
++	asm volatile ("getcon   " __PSSR ", %0":"=r"(ch));
++	asm volatile ("getcon   " __PSSR ", %0":"=r"(cl));
++	ch = (ch) >> 32;
++	cl = (cl) & 0xffffffff;
++	printk("PEXP: %08Lx%08Lx PSPC: %08Lx%08Lx PSSR: %08Lx%08Lx\n",
++	       ah, al, bh, bl, ch, cl);
++
++	ah = (regs->pc) >> 32;
++	al = (regs->pc) & 0xffffffff;
++	bh = (regs->regs[18]) >> 32;
++	bl = (regs->regs[18]) & 0xffffffff;
++	ch = (regs->regs[15]) >> 32;
++	cl = (regs->regs[15]) & 0xffffffff;
++	printk("PC  : %08Lx%08Lx LINK: %08Lx%08Lx SP  : %08Lx%08Lx\n",
++	       ah, al, bh, bl, ch, cl);
++
++	ah = (regs->sr) >> 32;
++	al = (regs->sr) & 0xffffffff;
++	asm volatile ("getcon   " __TEA ", %0":"=r"(bh));
++	asm volatile ("getcon   " __TEA ", %0":"=r"(bl));
++	bh = (bh) >> 32;
++	bl = (bl) & 0xffffffff;
++	asm volatile ("getcon   " __KCR0 ", %0":"=r"(ch));
++	asm volatile ("getcon   " __KCR0 ", %0":"=r"(cl));
++	ch = (ch) >> 32;
++	cl = (cl) & 0xffffffff;
++	printk("SR  : %08Lx%08Lx TEA : %08Lx%08Lx KCR0: %08Lx%08Lx\n",
++	       ah, al, bh, bl, ch, cl);
++
++	ah = (regs->regs[0]) >> 32;
++	al = (regs->regs[0]) & 0xffffffff;
++	bh = (regs->regs[1]) >> 32;
++	bl = (regs->regs[1]) & 0xffffffff;
++	ch = (regs->regs[2]) >> 32;
++	cl = (regs->regs[2]) & 0xffffffff;
++	printk("R0  : %08Lx%08Lx R1  : %08Lx%08Lx R2  : %08Lx%08Lx\n",
++	       ah, al, bh, bl, ch, cl);
++
++	ah = (regs->regs[3]) >> 32;
++	al = (regs->regs[3]) & 0xffffffff;
++	bh = (regs->regs[4]) >> 32;
++	bl = (regs->regs[4]) & 0xffffffff;
++	ch = (regs->regs[5]) >> 32;
++	cl = (regs->regs[5]) & 0xffffffff;
++	printk("R3  : %08Lx%08Lx R4  : %08Lx%08Lx R5  : %08Lx%08Lx\n",
++	       ah, al, bh, bl, ch, cl);
++
++	ah = (regs->regs[6]) >> 32;
++	al = (regs->regs[6]) & 0xffffffff;
++	bh = (regs->regs[7]) >> 32;
++	bl = (regs->regs[7]) & 0xffffffff;
++	ch = (regs->regs[8]) >> 32;
++	cl = (regs->regs[8]) & 0xffffffff;
++	printk("R6  : %08Lx%08Lx R7  : %08Lx%08Lx R8  : %08Lx%08Lx\n",
++	       ah, al, bh, bl, ch, cl);
++
++	ah = (regs->regs[9]) >> 32;
++	al = (regs->regs[9]) & 0xffffffff;
++	bh = (regs->regs[10]) >> 32;
++	bl = (regs->regs[10]) & 0xffffffff;
++	ch = (regs->regs[11]) >> 32;
++	cl = (regs->regs[11]) & 0xffffffff;
++	printk("R9  : %08Lx%08Lx R10 : %08Lx%08Lx R11 : %08Lx%08Lx\n",
++	       ah, al, bh, bl, ch, cl);
++	printk("....\n");
++
++	ah = (regs->tregs[0]) >> 32;
++	al = (regs->tregs[0]) & 0xffffffff;
++	bh = (regs->tregs[1]) >> 32;
++	bl = (regs->tregs[1]) & 0xffffffff;
++	ch = (regs->tregs[2]) >> 32;
++	cl = (regs->tregs[2]) & 0xffffffff;
++	printk("T0  : %08Lx%08Lx T1  : %08Lx%08Lx T2  : %08Lx%08Lx\n",
++	       ah, al, bh, bl, ch, cl);
++	printk("....\n");
++
++	print_dtlb();
++	print_itlb();
++}
++
++/* ======================================================================= */
++
++/*
++** Depending on <base> scan the MMU, Data or Instruction side
++** looking for a valid mapping matching Eaddr & asid.
++** Return -1 if not found or the TLB id entry otherwise.
++** Note: it works only for 4k pages!
++*/
++static unsigned long
++lookup_mmu_side(unsigned long base, unsigned long Eaddr, unsigned long asid)
++{
++	regType_t pteH;
++	unsigned long epn;
++	int count;
++
++	epn = Eaddr & 0xfffff000;
++
++	for (count = 0; count < MAX_TLBs; count++, base += TLB_STEP) {
++		pteH = getConfigReg(base);
++		if (GET_VALID(pteH))
++			if ((unsigned long) GET_EPN(pteH) == epn)
++				if ((unsigned long) GET_ASID(pteH) == asid)
++					break;
++	}
++	return ((unsigned long) ((count < MAX_TLBs) ? base : -1));
++}
++
++unsigned long lookup_dtlb(unsigned long Eaddr)
++{
++	unsigned long asid = get_asid();
++	return (lookup_mmu_side((u64) DTLB_BASE, Eaddr, asid));
++}
++
++unsigned long lookup_itlb(unsigned long Eaddr)
++{
++	unsigned long asid = get_asid();
++	return (lookup_mmu_side((u64) ITLB_BASE, Eaddr, asid));
++}
++
++void print_page(struct page *page)
++{
++	printk("  page[%p] -> index 0x%lx,  count 0x%x,  flags 0x%lx\n",
++	       page, page->index, page_count(page), page->flags);
++	printk("       address_space = %p, pages =%ld\n", page->mapping,
++	       page->mapping->nrpages);
++
++}
+diff --git a/arch/sh/lib64/memcpy.c b/arch/sh/lib64/memcpy.c
+new file mode 100644
+index 0000000..fba436a
+--- /dev/null
++++ b/arch/sh/lib64/memcpy.c
+@@ -0,0 +1,81 @@
++/*
++ * Copyright (C) 2002 Mark Debbage (Mark.Debbage at superh.com)
++ *
++ * May be copied or modified under the terms of the GNU General Public
++ * License.  See linux/COPYING for more information.
++ *
++ */
++
++#include <linux/types.h>
++#include <asm/string.h>
++
++// This is a simplistic optimization of memcpy to increase the
++// granularity of access beyond one byte using aligned
++// loads and stores. This is not an optimal implementation
++// for SH-5 (especially with regard to prefetching and the cache),
++// and a better version should be provided later ...
++
++void *memcpy(void *dest, const void *src, size_t count)
++{
++	char *d = (char *) dest, *s = (char *) src;
++
++	if (count >= 32) {
++		int i = 8 - (((unsigned long) d) & 0x7);
++
++		if (i != 8)
++			while (i-- && count--) {
++				*d++ = *s++;
++			}
++
++		if (((((unsigned long) d) & 0x7) == 0) &&
++		    ((((unsigned long) s) & 0x7) == 0)) {
++			while (count >= 32) {
++				unsigned long long t1, t2, t3, t4;
++				t1 = *(unsigned long long *) (s);
++				t2 = *(unsigned long long *) (s + 8);
++				t3 = *(unsigned long long *) (s + 16);
++				t4 = *(unsigned long long *) (s + 24);
++				*(unsigned long long *) (d) = t1;
++				*(unsigned long long *) (d + 8) = t2;
++				*(unsigned long long *) (d + 16) = t3;
++				*(unsigned long long *) (d + 24) = t4;
++				d += 32;
++				s += 32;
++				count -= 32;
++			}
++			while (count >= 8) {
++				*(unsigned long long *) d =
++				    *(unsigned long long *) s;
++				d += 8;
++				s += 8;
++				count -= 8;
++			}
++		}
++
++		if (((((unsigned long) d) & 0x3) == 0) &&
++		    ((((unsigned long) s) & 0x3) == 0)) {
++			while (count >= 4) {
++				*(unsigned long *) d = *(unsigned long *) s;
++				d += 4;
++				s += 4;
++				count -= 4;
++			}
++		}
++
++		if (((((unsigned long) d) & 0x1) == 0) &&
++		    ((((unsigned long) s) & 0x1) == 0)) {
++			while (count >= 2) {
++				*(unsigned short *) d = *(unsigned short *) s;
++				d += 2;
++				s += 2;
++				count -= 2;
++			}
++		}
++	}
++
++	while (count--) {
++		*d++ = *s++;
++	}
++
++	return d;
++}
+diff --git a/arch/sh/lib64/panic.c b/arch/sh/lib64/panic.c
+new file mode 100644
+index 0000000..ff559e2
+--- /dev/null
++++ b/arch/sh/lib64/panic.c
+@@ -0,0 +1,58 @@
++/*
++ * Copyright (C) 2003  Richard Curnow, SuperH UK Limited
++ *
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License.  See the file "COPYING" in the main directory of this archive
++ * for more details.
++ */
++
++#include <linux/kernel.h>
++#include <asm/io.h>
++#include <asm/cpu/registers.h>
++
++/* THIS IS A PHYSICAL ADDRESS */
++#define HDSP2534_ADDR (0x04002100)
++
++#ifdef CONFIG_SH_CAYMAN
++
++static void poor_mans_delay(void)
++{
++	int i;
++	for (i = 0; i < 2500000; i++) {
++	}		/* poor man's delay */
++}
++
++static void show_value(unsigned long x)
++{
++	int i;
++	unsigned nibble;
++	for (i = 0; i < 8; i++) {
++		nibble = ((x >> (i * 4)) & 0xf);
++
++		ctrl_outb(nibble + ((nibble > 9) ? 55 : 48),
++			  HDSP2534_ADDR + 0xe0 + ((7 - i) << 2));
++	}
++}
++
++#endif
++
++void
++panic_handler(unsigned long panicPC, unsigned long panicSSR,
++	      unsigned long panicEXPEVT)
++{
++#ifdef CONFIG_SH_CAYMAN
++	while (1) {
++		/* This piece of code displays the PC on the LED display */
++		show_value(panicPC);
++		poor_mans_delay();
++		show_value(panicSSR);
++		poor_mans_delay();
++		show_value(panicEXPEVT);
++		poor_mans_delay();
++	}
++#endif
++
++	/* Never return from the panic handler */
++	for (;;) ;
++
++}
+diff --git a/arch/sh/lib64/udelay.c b/arch/sh/lib64/udelay.c
+new file mode 100644
+index 0000000..23c7d17
+--- /dev/null
++++ b/arch/sh/lib64/udelay.c
+@@ -0,0 +1,56 @@
++/*
++ * arch/sh/lib64/udelay.c
++ *
++ * Delay routines, using a pre-computed "loops_per_jiffy" value.
++ *
++ * Copyright (C) 2000, 2001  Paolo Alberelli
++ * Copyright (C) 2003, 2004  Paul Mundt
++ *
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License.  See the file "COPYING" in the main directory of this archive
++ * for more details.
++ */
++#include <linux/sched.h>
++#include <asm/param.h>
++
++/*
++ * Use only for very small delays (< 1 msec).
++ *
++ * The active part of our cycle counter is only 32-bits wide, and
++ * we're treating the difference between two marks as signed.  On
++ * a 1GHz box, that's about 2 seconds.
++ */
++
++void __delay(int loops)
++{
++	long long dummy;
++	__asm__ __volatile__("gettr	tr0, %1\n\t"
++			     "pta	$+4, tr0\n\t"
++			     "addi	%0, -1, %0\n\t"
++			     "bne	%0, r63, tr0\n\t"
++			     "ptabs	%1, tr0\n\t":"=r"(loops),
++			     "=r"(dummy)
++			     :"0"(loops));
++}
++
++void __udelay(unsigned long long usecs, unsigned long lpj)
++{
++	usecs *= (((unsigned long long) HZ << 32) / 1000000) * lpj;
++	__delay((long long) usecs >> 32);
++}
++
++void __ndelay(unsigned long long nsecs, unsigned long lpj)
++{
++	nsecs *= (((unsigned long long) HZ << 32) / 1000000000) * lpj;
++	__delay((long long) nsecs >> 32);
++}
++
++void udelay(unsigned long usecs)
++{
++	__udelay(usecs, cpu_data[raw_smp_processor_id()].loops_per_jiffy);
++}
++
++void ndelay(unsigned long nsecs)
++{
++	__ndelay(nsecs, cpu_data[raw_smp_processor_id()].loops_per_jiffy);
++}
+diff --git a/arch/sh/mm/Kconfig b/arch/sh/mm/Kconfig
+index 1265f20..f549b8c 100644
+--- a/arch/sh/mm/Kconfig
++++ b/arch/sh/mm/Kconfig
+@@ -1,193 +1,3 @@
+-#
+-# Processor families
+-#
+-config CPU_SH2
+-	bool
+-
+-config CPU_SH2A
+-	bool
+-	select CPU_SH2
+-
+-config CPU_SH3
+-	bool
+-	select CPU_HAS_INTEVT
+-	select CPU_HAS_SR_RB
+-
+-config CPU_SH4
+-	bool
+-	select CPU_HAS_INTEVT
+-	select CPU_HAS_SR_RB
+-	select CPU_HAS_PTEA if !CPU_SH4A || CPU_SHX2
+-	select CPU_HAS_FPU if !CPU_SH4AL_DSP
+-
+-config CPU_SH4A
+-	bool
+-	select CPU_SH4
+-
+-config CPU_SH4AL_DSP
+-	bool
+-	select CPU_SH4A
+-	select CPU_HAS_DSP
+-
+-config CPU_SHX2
+-	bool
+-
+-config CPU_SHX3
+-	bool
+-
+-choice
+-	prompt "Processor sub-type selection"
+-
+-#
+-# Processor subtypes
+-#
+-
+-# SH-2 Processor Support
+-
+-config CPU_SUBTYPE_SH7619
+-	bool "Support SH7619 processor"
+-	select CPU_SH2
+-
+-# SH-2A Processor Support
+-
+-config CPU_SUBTYPE_SH7206
+-	bool "Support SH7206 processor"
+-	select CPU_SH2A
+-
+-# SH-3 Processor Support
+-
+-config CPU_SUBTYPE_SH7705
+-	bool "Support SH7705 processor"
+-	select CPU_SH3
+-
+-config CPU_SUBTYPE_SH7706
+-	bool "Support SH7706 processor"
+-	select CPU_SH3
+-	help
+-	  Select SH7706 if you have a 133 Mhz SH-3 HD6417706 CPU.
+-
+-config CPU_SUBTYPE_SH7707
+-	bool "Support SH7707 processor"
+-	select CPU_SH3
+-	help
+-	  Select SH7707 if you have a  60 Mhz SH-3 HD6417707 CPU.
+-
+-config CPU_SUBTYPE_SH7708
+-	bool "Support SH7708 processor"
+-	select CPU_SH3
+-	help
+-	  Select SH7708 if you have a  60 Mhz SH-3 HD6417708S or
+-	  if you have a 100 Mhz SH-3 HD6417708R CPU.
+-
+-config CPU_SUBTYPE_SH7709
+-	bool "Support SH7709 processor"
+-	select CPU_SH3
+-	help
+-	  Select SH7709 if you have a  80 Mhz SH-3 HD6417709 CPU.
+-
+-config CPU_SUBTYPE_SH7710
+-	bool "Support SH7710 processor"
+-	select CPU_SH3
+-	select CPU_HAS_DSP
+-	help
+-	  Select SH7710 if you have a SH3-DSP SH7710 CPU.
+-
+-config CPU_SUBTYPE_SH7712
+-	bool "Support SH7712 processor"
+-	select CPU_SH3
+-	select CPU_HAS_DSP
+-	help
+-	  Select SH7712 if you have a SH3-DSP SH7712 CPU.
+-
+-config CPU_SUBTYPE_SH7720
+-	bool "Support SH7720 processor"
+-	select CPU_SH3
+-	select CPU_HAS_DSP
+-	help
+-	  Select SH7720 if you have a SH3-DSP SH7720 CPU.
+-
+-# SH-4 Processor Support
+-
+-config CPU_SUBTYPE_SH7750
+-	bool "Support SH7750 processor"
+-	select CPU_SH4
+-	help
+-	  Select SH7750 if you have a 200 Mhz SH-4 HD6417750 CPU.
+-
+-config CPU_SUBTYPE_SH7091
+-	bool "Support SH7091 processor"
+-	select CPU_SH4
+-	help
+-	  Select SH7091 if you have an SH-4 based Sega device (such as
+-	  the Dreamcast, Naomi, and Naomi 2).
+-
+-config CPU_SUBTYPE_SH7750R
+-	bool "Support SH7750R processor"
+-	select CPU_SH4
+-
+-config CPU_SUBTYPE_SH7750S
+-	bool "Support SH7750S processor"
+-	select CPU_SH4
+-
+-config CPU_SUBTYPE_SH7751
+-	bool "Support SH7751 processor"
+-	select CPU_SH4
+-	help
+-	  Select SH7751 if you have a 166 Mhz SH-4 HD6417751 CPU,
+-	  or if you have a HD6417751R CPU.
+-
+-config CPU_SUBTYPE_SH7751R
+-	bool "Support SH7751R processor"
+-	select CPU_SH4
+-
+-config CPU_SUBTYPE_SH7760
+-	bool "Support SH7760 processor"
+-	select CPU_SH4
+-
+-config CPU_SUBTYPE_SH4_202
+-	bool "Support SH4-202 processor"
+-	select CPU_SH4
+-
+-# SH-4A Processor Support
+-
+-config CPU_SUBTYPE_SH7770
+-	bool "Support SH7770 processor"
+-	select CPU_SH4A
+-
+-config CPU_SUBTYPE_SH7780
+-	bool "Support SH7780 processor"
+-	select CPU_SH4A
+-
+-config CPU_SUBTYPE_SH7785
+-	bool "Support SH7785 processor"
+-	select CPU_SH4A
+-	select CPU_SHX2
+-	select ARCH_SPARSEMEM_ENABLE
+-	select SYS_SUPPORTS_NUMA
+-
+-config CPU_SUBTYPE_SHX3
+-	bool "Support SH-X3 processor"
+-	select CPU_SH4A
+-	select CPU_SHX3
+-	select ARCH_SPARSEMEM_ENABLE
+-	select SYS_SUPPORTS_NUMA
+-	select SYS_SUPPORTS_SMP
+-
+-# SH4AL-DSP Processor Support
+-
+-config CPU_SUBTYPE_SH7343
+-	bool "Support SH7343 processor"
+-	select CPU_SH4AL_DSP
+-
+-config CPU_SUBTYPE_SH7722
+-	bool "Support SH7722 processor"
+-	select CPU_SH4AL_DSP
+-	select CPU_SHX2
+-	select ARCH_SPARSEMEM_ENABLE
+-	select SYS_SUPPORTS_NUMA
+-
+-endchoice
+-
+ menu "Memory management options"
+ 
+ config QUICKLIST
+@@ -207,7 +17,8 @@ config MMU
+ 
+ config PAGE_OFFSET
+ 	hex
+-	default "0x80000000" if MMU
++	default "0x80000000" if MMU && SUPERH32
++	default "0x20000000" if MMU && SUPERH64
+ 	default "0x00000000"
+ 
+ config MEMORY_START
+@@ -228,17 +39,28 @@ config MEMORY_START
+ 
+ config MEMORY_SIZE
+ 	hex "Physical memory size"
+-	default "0x00400000"
++	default "0x04000000"
+ 	help
+ 	  This sets the default memory size assumed by your SH kernel. It can
+ 	  be overridden as normal by the 'mem=' argument on the kernel command
+ 	  line. If unsure, consult your board specifications or just leave it
+-	  as 0x00400000 which was the default value before this became
++	  as 0x04000000 which was the default value before this became
+ 	  configurable.
+ 
++# Physical addressing modes
++
++config 29BIT
++	def_bool !32BIT
++	depends on SUPERH32
++
+ config 32BIT
++	bool
++	default y if CPU_SH5
++
++config PMB
+ 	bool "Support 32-bit physical addressing through PMB"
+ 	depends on MMU && (CPU_SUBTYPE_SH7780 || CPU_SUBTYPE_SH7785)
++	select 32BIT
+ 	default y
+ 	help
+ 	  If you say Y here, physical addressing will be extended to
+@@ -256,7 +78,7 @@ config X2TLB
+ 
+ config VSYSCALL
+ 	bool "Support vsyscall page"
+-	depends on MMU
++	depends on MMU && (CPU_SH3 || CPU_SH4)
+ 	default y
+ 	help
+ 	  This will enable support for the kernel mapping a vDSO page
+@@ -335,7 +157,7 @@ config PAGE_SIZE_8KB
+ 
+ config PAGE_SIZE_64KB
+ 	bool "64kB"
+-	depends on CPU_SH4
++	depends on CPU_SH4 || CPU_SH5
+ 	help
+ 	  This enables support for 64kB pages, possible on all SH-4
+ 	  CPUs and later.
+@@ -344,7 +166,7 @@ endchoice
+ 
+ choice
+ 	prompt "HugeTLB page size"
+-	depends on HUGETLB_PAGE && CPU_SH4 && MMU
++	depends on HUGETLB_PAGE && (CPU_SH4 || CPU_SH5) && MMU
+ 	default HUGETLB_PAGE_SIZE_64K
+ 
+ config HUGETLB_PAGE_SIZE_64K
+@@ -365,6 +187,10 @@ config HUGETLB_PAGE_SIZE_64MB
+ 	bool "64MB"
+ 	depends on X2TLB
+ 
++config HUGETLB_PAGE_SIZE_512MB
++	bool "512MB"
++	depends on CPU_SH5
++
+ endchoice
+ 
+ source "mm/Kconfig"
+@@ -392,12 +218,12 @@ config SH_DIRECT_MAPPED
+ 
+ choice
+ 	prompt "Cache mode"
+-	default CACHE_WRITEBACK if CPU_SH2A || CPU_SH3 || CPU_SH4
++	default CACHE_WRITEBACK if CPU_SH2A || CPU_SH3 || CPU_SH4 || CPU_SH5
+ 	default CACHE_WRITETHROUGH if (CPU_SH2 && !CPU_SH2A)
+ 
+ config CACHE_WRITEBACK
+ 	bool "Write-back"
+-	depends on CPU_SH2A || CPU_SH3 || CPU_SH4
++	depends on CPU_SH2A || CPU_SH3 || CPU_SH4 || CPU_SH5
+ 
+ config CACHE_WRITETHROUGH
+ 	bool "Write-through"
+diff --git a/arch/sh/mm/Makefile b/arch/sh/mm/Makefile
+index aa44607..9f4bc3d 100644
+--- a/arch/sh/mm/Makefile
++++ b/arch/sh/mm/Makefile
+@@ -1,37 +1,5 @@
+-#
+-# Makefile for the Linux SuperH-specific parts of the memory manager.
+-#
+-
+-obj-y			:= init.o extable.o consistent.o
+-
+-ifndef CONFIG_CACHE_OFF
+-obj-$(CONFIG_CPU_SH2)		+= cache-sh2.o
+-obj-$(CONFIG_CPU_SH3)		+= cache-sh3.o
+-obj-$(CONFIG_CPU_SH4)		+= cache-sh4.o
+-obj-$(CONFIG_SH7705_CACHE_32KB)	+= cache-sh7705.o
++ifeq ($(CONFIG_SUPERH32),y)
++include ${srctree}/arch/sh/mm/Makefile_32
++else
++include ${srctree}/arch/sh/mm/Makefile_64
+ endif
+-
+-mmu-y			:= tlb-nommu.o pg-nommu.o
+-mmu-$(CONFIG_MMU)	:= fault.o clear_page.o copy_page.o tlb-flush.o	\
+-			   ioremap.o
+-
+-obj-y			+= $(mmu-y)
+-
+-ifdef CONFIG_DEBUG_FS
+-obj-$(CONFIG_CPU_SH4)	+= cache-debugfs.o
+-endif
+-
+-ifdef CONFIG_MMU
+-obj-$(CONFIG_CPU_SH3)	+= tlb-sh3.o
+-obj-$(CONFIG_CPU_SH4)	+= tlb-sh4.o
+-ifndef CONFIG_CACHE_OFF
+-obj-$(CONFIG_CPU_SH4)		+= pg-sh4.o
+-obj-$(CONFIG_SH7705_CACHE_32KB)	+= pg-sh7705.o
+-endif
+-endif
+-
+-obj-$(CONFIG_HUGETLB_PAGE)	+= hugetlbpage.o
+-obj-$(CONFIG_32BIT)		+= pmb.o
+-obj-$(CONFIG_NUMA)		+= numa.o
+-
+-EXTRA_CFLAGS += -Werror
+diff --git a/arch/sh/mm/Makefile_32 b/arch/sh/mm/Makefile_32
+new file mode 100644
+index 0000000..e295db6
+--- /dev/null
++++ b/arch/sh/mm/Makefile_32
+@@ -0,0 +1,36 @@
++#
++# Makefile for the Linux SuperH-specific parts of the memory manager.
++#
++
++obj-y			:= init.o extable_32.o consistent.o
++
++ifndef CONFIG_CACHE_OFF
++obj-$(CONFIG_CPU_SH2)		+= cache-sh2.o
++obj-$(CONFIG_CPU_SH3)		+= cache-sh3.o
++obj-$(CONFIG_CPU_SH4)		+= cache-sh4.o
++obj-$(CONFIG_SH7705_CACHE_32KB)	+= cache-sh7705.o
++endif
++
++mmu-y			:= tlb-nommu.o pg-nommu.o
++mmu-$(CONFIG_MMU)	:= fault_32.o tlbflush_32.o ioremap_32.o
++
++obj-y			+= $(mmu-y)
++
++ifdef CONFIG_DEBUG_FS
++obj-$(CONFIG_CPU_SH4)	+= cache-debugfs.o
++endif
++
++ifdef CONFIG_MMU
++obj-$(CONFIG_CPU_SH3)	+= tlb-sh3.o
++obj-$(CONFIG_CPU_SH4)	+= tlb-sh4.o
++ifndef CONFIG_CACHE_OFF
++obj-$(CONFIG_CPU_SH4)		+= pg-sh4.o
++obj-$(CONFIG_SH7705_CACHE_32KB)	+= pg-sh7705.o
++endif
++endif
++
++obj-$(CONFIG_HUGETLB_PAGE)	+= hugetlbpage.o
++obj-$(CONFIG_PMB)		+= pmb.o
++obj-$(CONFIG_NUMA)		+= numa.o
++
++EXTRA_CFLAGS += -Werror
+diff --git a/arch/sh/mm/Makefile_64 b/arch/sh/mm/Makefile_64
+new file mode 100644
+index 0000000..cbd6aa3
+--- /dev/null
++++ b/arch/sh/mm/Makefile_64
+@@ -0,0 +1,44 @@
++#
++# Makefile for the Linux SuperH-specific parts of the memory manager.
++#
++
++obj-y			:= init.o extable_64.o consistent.o
++
++mmu-y			:= tlb-nommu.o pg-nommu.o
++mmu-$(CONFIG_MMU)	:= fault_64.o ioremap_64.o tlbflush_64.o tlb-sh5.o
++
++ifndef CONFIG_CACHE_OFF
++obj-y			+= cache-sh5.o
++endif
++
++obj-y			+= $(mmu-y)
++
++obj-$(CONFIG_HUGETLB_PAGE)	+= hugetlbpage.o
++obj-$(CONFIG_NUMA)		+= numa.o
++
++EXTRA_CFLAGS += -Werror
++
++# Special flags for fault_64.o.  This puts restrictions on the number of
++# caller-save registers that the compiler can target when building this file.
++# This is required because the code is called from a context in entry.S where
++# very few registers have been saved in the exception handler (for speed
++# reasons).
++# The caller save registers that have been saved and which can be used are
++# r2,r3,r4,r5 : argument passing
++# r15, r18 : SP and LINK
++# tr0-4 : allow all caller-save TR's.  The compiler seems to be able to make
++#         use of them, so it's probably beneficial to performance to save them
++#         and have them available for it.
++#
++# The resources not listed below are callee save, i.e. the compiler is free to
++# use any of them and will spill them to the stack itself.
++
++CFLAGS_fault_64.o += -ffixed-r7 \
++	-ffixed-r8 -ffixed-r9 -ffixed-r10 -ffixed-r11 -ffixed-r12 \
++	-ffixed-r13 -ffixed-r14 -ffixed-r16 -ffixed-r17 -ffixed-r19 \
++	-ffixed-r20 -ffixed-r21 -ffixed-r22 -ffixed-r23 \
++	-ffixed-r24 -ffixed-r25 -ffixed-r26 -ffixed-r27 \
++	-ffixed-r36 -ffixed-r37 -ffixed-r38 -ffixed-r39 -ffixed-r40 \
++	-ffixed-r41 -ffixed-r42 -ffixed-r43  \
++	-ffixed-r60 -ffixed-r61 -ffixed-r62 \
++	-fomit-frame-pointer
+diff --git a/arch/sh/mm/cache-debugfs.c b/arch/sh/mm/cache-debugfs.c
+index de6d2c9..db6d950 100644
+--- a/arch/sh/mm/cache-debugfs.c
++++ b/arch/sh/mm/cache-debugfs.c
+@@ -22,7 +22,8 @@ enum cache_type {
+ 	CACHE_TYPE_UNIFIED,
+ };
+ 
+-static int cache_seq_show(struct seq_file *file, void *iter)
++static int __uses_jump_to_uncached cache_seq_show(struct seq_file *file,
++						  void *iter)
+ {
+ 	unsigned int cache_type = (unsigned int)file->private;
+ 	struct cache_info *cache;
+@@ -34,11 +35,11 @@ static int cache_seq_show(struct seq_file *file, void *iter)
+ 	 * Go uncached immediately so we don't skew the results any
+ 	 * more than we already are..
+ 	 */
+-	jump_to_P2();
++	jump_to_uncached();
+ 
+ 	ccr = ctrl_inl(CCR);
+ 	if ((ccr & CCR_CACHE_ENABLE) == 0) {
+-		back_to_P1();
++		back_to_cached();
+ 
+ 		seq_printf(file, "disabled\n");
+ 		return 0;
+@@ -104,7 +105,7 @@ static int cache_seq_show(struct seq_file *file, void *iter)
+ 		addrstart += cache->way_incr;
+ 	}
+ 
+-	back_to_P1();
++	back_to_cached();
+ 
+ 	return 0;
+ }
+diff --git a/arch/sh/mm/cache-sh4.c b/arch/sh/mm/cache-sh4.c
+index 226b190..43d7ff6 100644
+--- a/arch/sh/mm/cache-sh4.c
++++ b/arch/sh/mm/cache-sh4.c
+@@ -190,7 +190,7 @@ void flush_icache_range(unsigned long start, unsigned long end)
+  * .. which happens to be the same behavior as flush_icache_range().
+  * So, we simply flush out a line.
+  */
+-void flush_cache_sigtramp(unsigned long addr)
++void __uses_jump_to_uncached flush_cache_sigtramp(unsigned long addr)
+ {
+ 	unsigned long v, index;
+ 	unsigned long flags;
+@@ -205,13 +205,13 @@ void flush_cache_sigtramp(unsigned long addr)
+ 			(v & boot_cpu_data.icache.entry_mask);
+ 
+ 	local_irq_save(flags);
+-	jump_to_P2();
++	jump_to_uncached();
+ 
+ 	for (i = 0; i < boot_cpu_data.icache.ways;
+ 	     i++, index += boot_cpu_data.icache.way_incr)
+ 		ctrl_outl(0, index);	/* Clear out Valid-bit */
+ 
+-	back_to_P1();
++	back_to_cached();
+ 	wmb();
+ 	local_irq_restore(flags);
+ }
+@@ -256,12 +256,12 @@ void flush_dcache_page(struct page *page)
+ }
+ 
+ /* TODO: Selective icache invalidation through IC address array.. */
+-static inline void flush_icache_all(void)
++static inline void __uses_jump_to_uncached flush_icache_all(void)
+ {
+ 	unsigned long flags, ccr;
+ 
+ 	local_irq_save(flags);
+-	jump_to_P2();
++	jump_to_uncached();
+ 
+ 	/* Flush I-cache */
+ 	ccr = ctrl_inl(CCR);
+@@ -269,11 +269,11 @@ static inline void flush_icache_all(void)
+ 	ctrl_outl(ccr, CCR);
+ 
+ 	/*
+-	 * back_to_P1() will take care of the barrier for us, don't add
++	 * back_to_cached() will take care of the barrier for us, don't add
+ 	 * another one!
+ 	 */
+ 
+-	back_to_P1();
++	back_to_cached();
+ 	local_irq_restore(flags);
+ }
+ 
+diff --git a/arch/sh/mm/cache-sh5.c b/arch/sh/mm/cache-sh5.c
+new file mode 100644
+index 0000000..4617e3a
+--- /dev/null
++++ b/arch/sh/mm/cache-sh5.c
+@@ -0,0 +1,1029 @@
++/*
++ * arch/sh/mm/cache-sh5.c
++ *
++ * Original version Copyright (C) 2000, 2001  Paolo Alberelli
++ * Second version Copyright (C) benedict.gaster at superh.com 2002
++ * Third version Copyright Richard.Curnow at superh.com 2003
++ * Hacks to third version Copyright (C) 2003 Paul Mundt
++ *
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License.  See the file "COPYING" in the main directory of this archive
++ * for more details.
++ */
++#include <linux/init.h>
++#include <linux/mman.h>
++#include <linux/mm.h>
++#include <linux/threads.h>
++#include <asm/page.h>
++#include <asm/pgtable.h>
++#include <asm/processor.h>
++#include <asm/cache.h>
++#include <asm/tlb.h>
++#include <asm/io.h>
++#include <asm/uaccess.h>
++#include <asm/mmu_context.h>
++#include <asm/pgalloc.h> /* for flush_itlb_range */
++
++#include <linux/proc_fs.h>
++
++/* This function is in entry.S */
++extern unsigned long switch_and_save_asid(unsigned long new_asid);
++
++/* Wired TLB entry for the D-cache */
++static unsigned long long dtlb_cache_slot;
++
++/**
++ * sh64_cache_init()
++ *
++ * This is pretty much just a straightforward clone of the SH
++ * detect_cpu_and_cache_system().
++ *
++ * This function is responsible for setting up all of the cache
++ * info dynamically as well as taking care of CPU probing and
++ * setting up the relevant subtype data.
++ *
++ * FIXME: For the time being, we only really support the SH5-101
++ * out of the box, and don't support dynamic probing for things
++ * like the SH5-103 or even cut2 of the SH5-101. Implement this
++ * later!
++ */
++int __init sh64_cache_init(void)
++{
++	/*
++	 * First, setup some sane values for the I-cache.
++	 */
++	cpu_data->icache.ways		= 4;
++	cpu_data->icache.sets		= 256;
++	cpu_data->icache.linesz		= L1_CACHE_BYTES;
++
++	/*
++	 * FIXME: This can probably be cleaned up a bit as well.. for example,
++	 * do we really need the way shift _and_ the way_step_shift ?? Judging
++	 * by the existing code, I would guess no.. is there any valid reason
++	 * why we need to be tracking this around?
++	 */
++	cpu_data->icache.way_shift	= 13;
++	cpu_data->icache.entry_shift	= 5;
++	cpu_data->icache.set_shift	= 4;
++	cpu_data->icache.way_step_shift	= 16;
++	cpu_data->icache.asid_shift	= 2;
++
++	/*
++	 * way offset = cache size / associativity, so just don't factor in
++	 * associativity in the first place..
++	 */
++	cpu_data->icache.way_ofs	= cpu_data->icache.sets *
++					  cpu_data->icache.linesz;
++
++	cpu_data->icache.asid_mask	= 0x3fc;
++	cpu_data->icache.idx_mask	= 0x1fe0;
++	cpu_data->icache.epn_mask	= 0xffffe000;
++	cpu_data->icache.flags		= 0;
++
++	/*
++	 * Next, setup some sane values for the D-cache.
++	 *
++	 * On the SH5, these are pretty consistent with the I-cache settings,
++	 * so we just copy over the existing definitions.. these can be fixed
++	 * up later, especially if we add runtime CPU probing.
++	 *
++	 * Though in the meantime it saves us from having to duplicate all of
++	 * the above definitions..
++	 */
++	cpu_data->dcache		= cpu_data->icache;
++
++	/*
++	 * Setup any cache-related flags here
++	 */
++#if defined(CONFIG_DCACHE_WRITE_THROUGH)
++	set_bit(SH_CACHE_MODE_WT, &(cpu_data->dcache.flags));
++#elif defined(CONFIG_DCACHE_WRITE_BACK)
++	set_bit(SH_CACHE_MODE_WB, &(cpu_data->dcache.flags));
++#endif
++
++	/*
++	 * We also need to reserve a slot for the D-cache in the DTLB, so we
++	 * do this now ..
++	 */
++	dtlb_cache_slot			= sh64_get_wired_dtlb_entry();
++
++	return 0;
++}
++
++#ifdef CONFIG_DCACHE_DISABLED
++#define sh64_dcache_purge_all()					do { } while (0)
++#define sh64_dcache_purge_coloured_phy_page(paddr, eaddr)	do { } while (0)
++#define sh64_dcache_purge_user_range(mm, start, end)		do { } while (0)
++#define sh64_dcache_purge_phy_page(paddr)			do { } while (0)
++#define sh64_dcache_purge_virt_page(mm, eaddr)			do { } while (0)
++#define sh64_dcache_purge_kernel_range(start, end)		do { } while (0)
++#define sh64_dcache_wback_current_user_range(start, end)	do { } while (0)
++#endif
++
++/*##########################################################################*/
++
++/* From here onwards, a rewrite of the implementation,
++   by Richard.Curnow at superh.com.
++
++   The major changes in this compared to the old version are;
++   1. use more selective purging through OCBP instead of using ALLOCO to purge
++      by natural replacement.  This avoids purging out unrelated cache lines
++      that happen to be in the same set.
++   2. exploit the APIs copy_user_page and clear_user_page better
++   3. be more selective about I-cache purging, in particular use invalidate_all
++      more sparingly.
++
++   */
++
++/*##########################################################################
++			       SUPPORT FUNCTIONS
++  ##########################################################################*/
++
++/****************************************************************************/
++/* The following group of functions deal with mapping and unmapping a temporary
++   page into the DTLB slot that have been set aside for our exclusive use. */
++/* In order to accomplish this, we use the generic interface for adding and
++   removing a wired slot entry as defined in arch/sh/mm/tlb-sh5.c */
++/****************************************************************************/
++
++static unsigned long slot_own_flags;
++
++static inline void sh64_setup_dtlb_cache_slot(unsigned long eaddr, unsigned long asid, unsigned long paddr)
++{
++	local_irq_save(slot_own_flags);
++	sh64_setup_tlb_slot(dtlb_cache_slot, eaddr, asid, paddr);
++}
++
++static inline void sh64_teardown_dtlb_cache_slot(void)
++{
++	sh64_teardown_tlb_slot(dtlb_cache_slot);
++	local_irq_restore(slot_own_flags);
++}
++
++/****************************************************************************/
++
++#ifndef CONFIG_ICACHE_DISABLED
++
++static void __inline__ sh64_icache_inv_all(void)
++{
++	unsigned long long addr, flag, data;
++	unsigned int flags;
++
++	addr=ICCR0;
++	flag=ICCR0_ICI;
++	data=0;
++
++	/* Make this a critical section for safety (probably not strictly necessary.) */
++	local_irq_save(flags);
++
++	/* Without %1 it gets unexplicably wrong */
++	asm volatile("getcfg	%3, 0, %0\n\t"
++			"or	%0, %2, %0\n\t"
++			"putcfg	%3, 0, %0\n\t"
++			"synci"
++			: "=&r" (data)
++			: "0" (data), "r" (flag), "r" (addr));
++
++	local_irq_restore(flags);
++}
++
++static void sh64_icache_inv_kernel_range(unsigned long start, unsigned long end)
++{
++	/* Invalidate range of addresses [start,end] from the I-cache, where
++	 * the addresses lie in the kernel superpage. */
++
++	unsigned long long ullend, addr, aligned_start;
++#if (NEFF == 32)
++	aligned_start = (unsigned long long)(signed long long)(signed long) start;
++#else
++#error "NEFF != 32"
++#endif
++	aligned_start &= L1_CACHE_ALIGN_MASK;
++	addr = aligned_start;
++#if (NEFF == 32)
++	ullend = (unsigned long long) (signed long long) (signed long) end;
++#else
++#error "NEFF != 32"
++#endif
++	while (addr <= ullend) {
++		asm __volatile__ ("icbi %0, 0" : : "r" (addr));
++		addr += L1_CACHE_BYTES;
++	}
++}
++
++static void sh64_icache_inv_user_page(struct vm_area_struct *vma, unsigned long eaddr)
++{
++	/* If we get called, we know that vma->vm_flags contains VM_EXEC.
++	   Also, eaddr is page-aligned. */
++
++	unsigned long long addr, end_addr;
++	unsigned long flags = 0;
++	unsigned long running_asid, vma_asid;
++	addr = eaddr;
++	end_addr = addr + PAGE_SIZE;
++
++	/* Check whether we can use the current ASID for the I-cache
++	   invalidation.  For example, if we're called via
++	   access_process_vm->flush_cache_page->here, (e.g. when reading from
++	   /proc), 'running_asid' will be that of the reader, not of the
++	   victim.
++
++	   Also, note the risk that we might get pre-empted between the ASID
++	   compare and blocking IRQs, and before we regain control, the
++	   pid->ASID mapping changes.  However, the whole cache will get
++	   invalidated when the mapping is renewed, so the worst that can
++	   happen is that the loop below ends up invalidating somebody else's
++	   cache entries.
++	*/
++
++	running_asid = get_asid();
++	vma_asid = (vma->vm_mm->context & MMU_CONTEXT_ASID_MASK);
++	if (running_asid != vma_asid) {
++		local_irq_save(flags);
++		switch_and_save_asid(vma_asid);
++	}
++	while (addr < end_addr) {
++		/* Worth unrolling a little */
++		asm __volatile__("icbi %0,  0" : : "r" (addr));
++		asm __volatile__("icbi %0, 32" : : "r" (addr));
++		asm __volatile__("icbi %0, 64" : : "r" (addr));
++		asm __volatile__("icbi %0, 96" : : "r" (addr));
++		addr += 128;
++	}
++	if (running_asid != vma_asid) {
++		switch_and_save_asid(running_asid);
++		local_irq_restore(flags);
++	}
++}
++
++/****************************************************************************/
++
++static void sh64_icache_inv_user_page_range(struct mm_struct *mm,
++			  unsigned long start, unsigned long end)
++{
++	/* Used for invalidating big chunks of I-cache, i.e. assume the range
++	   is whole pages.  If 'start' or 'end' is not page aligned, the code
++	   is conservative and invalidates to the ends of the enclosing pages.
++	   This is functionally OK, just a performance loss. */
++
++	/* See the comments below in sh64_dcache_purge_user_range() regarding
++	   the choice of algorithm.  However, for the I-cache option (2) isn't
++	   available because there are no physical tags so aliases can't be
++	   resolved.  The icbi instruction has to be used through the user
++	   mapping.   Because icbi is cheaper than ocbp on a cache hit, it
++	   would be cheaper to use the selective code for a large range than is
++	   possible with the D-cache.  Just assume 64 for now as a working
++	   figure.
++	   */
++
++	int n_pages;
++
++	if (!mm) return;
++
++	n_pages = ((end - start) >> PAGE_SHIFT);
++	if (n_pages >= 64) {
++		sh64_icache_inv_all();
++	} else {
++		unsigned long aligned_start;
++		unsigned long eaddr;
++		unsigned long after_last_page_start;
++		unsigned long mm_asid, current_asid;
++		unsigned long long flags = 0ULL;
++
++		mm_asid = mm->context & MMU_CONTEXT_ASID_MASK;
++		current_asid = get_asid();
++
++		if (mm_asid != current_asid) {
++			/* Switch ASID and run the invalidate loop under cli */
++			local_irq_save(flags);
++			switch_and_save_asid(mm_asid);
++		}
++
++		aligned_start = start & PAGE_MASK;
++		after_last_page_start = PAGE_SIZE + ((end - 1) & PAGE_MASK);
++
++		while (aligned_start < after_last_page_start) {
++			struct vm_area_struct *vma;
++			unsigned long vma_end;
++			vma = find_vma(mm, aligned_start);
++			if (!vma || (aligned_start <= vma->vm_end)) {
++				/* Avoid getting stuck in an error condition */
++				aligned_start += PAGE_SIZE;
++				continue;
++			}
++			vma_end = vma->vm_end;
++			if (vma->vm_flags & VM_EXEC) {
++				/* Executable */
++				eaddr = aligned_start;
++				while (eaddr < vma_end) {
++					sh64_icache_inv_user_page(vma, eaddr);
++					eaddr += PAGE_SIZE;
++				}
++			}
++			aligned_start = vma->vm_end; /* Skip to start of next region */
++		}
++		if (mm_asid != current_asid) {
++			switch_and_save_asid(current_asid);
++			local_irq_restore(flags);
++		}
++	}
++}
++
++static void sh64_icache_inv_user_small_range(struct mm_struct *mm,
++						unsigned long start, int len)
++{
++
++	/* Invalidate a small range of user context I-cache, not necessarily
++	   page (or even cache-line) aligned. */
++
++	unsigned long long eaddr = start;
++	unsigned long long eaddr_end = start + len;
++	unsigned long current_asid, mm_asid;
++	unsigned long long flags;
++	unsigned long long epage_start;
++
++	/* Since this is used inside ptrace, the ASID in the mm context
++	   typically won't match current_asid.  We'll have to switch ASID to do
++	   this.  For safety, and given that the range will be small, do all
++	   this under cli.
++
++	   Note, there is a hazard that the ASID in mm->context is no longer
++	   actually associated with mm, i.e. if the mm->context has started a
++	   new cycle since mm was last active.  However, this is just a
++	   performance issue: all that happens is that we invalidate lines
++	   belonging to another mm, so the owning process has to refill them
++	   when that mm goes live again.  mm itself can't have any cache
++	   entries because there will have been a flush_cache_all when the new
++	   mm->context cycle started. */
++
++	/* Align to start of cache line.  Otherwise, suppose len==8 and start
++	   was at 32N+28 : the last 4 bytes wouldn't get invalidated. */
++	eaddr = start & L1_CACHE_ALIGN_MASK;
++	eaddr_end = start + len;
++
++	local_irq_save(flags);
++	mm_asid = mm->context & MMU_CONTEXT_ASID_MASK;
++	current_asid = switch_and_save_asid(mm_asid);
++
++	epage_start = eaddr & PAGE_MASK;
++
++	while (eaddr < eaddr_end)
++	{
++		asm __volatile__("icbi %0, 0" : : "r" (eaddr));
++		eaddr += L1_CACHE_BYTES;
++	}
++	switch_and_save_asid(current_asid);
++	local_irq_restore(flags);
++}
++
++static void sh64_icache_inv_current_user_range(unsigned long start, unsigned long end)
++{
++	/* The icbi instruction never raises ITLBMISS.  i.e. if there's not a
++	   cache hit on the virtual tag the instruction ends there, without a
++	   TLB lookup. */
++
++	unsigned long long aligned_start;
++	unsigned long long ull_end;
++	unsigned long long addr;
++
++	ull_end = end;
++
++	/* Just invalidate over the range using the natural addresses.  TLB
++	   miss handling will be OK (TBC).  Since it's for the current process,
++	   either we're already in the right ASID context, or the ASIDs have
++	   been recycled since we were last active in which case we might just
++	   invalidate another processes I-cache entries : no worries, just a
++	   performance drop for him. */
++	aligned_start = start & L1_CACHE_ALIGN_MASK;
++	addr = aligned_start;
++	while (addr < ull_end) {
++		asm __volatile__ ("icbi %0, 0" : : "r" (addr));
++		asm __volatile__ ("nop");
++		asm __volatile__ ("nop");
++		addr += L1_CACHE_BYTES;
++	}
++}
++
++#endif /* !CONFIG_ICACHE_DISABLED */
++
++/****************************************************************************/
++
++#ifndef CONFIG_DCACHE_DISABLED
++
++/* Buffer used as the target of alloco instructions to purge data from cache
++   sets by natural eviction. -- RPC */
++#define DUMMY_ALLOCO_AREA_SIZE L1_CACHE_SIZE_BYTES + (1024 * 4)
++static unsigned char dummy_alloco_area[DUMMY_ALLOCO_AREA_SIZE] __cacheline_aligned = { 0, };
++
++/****************************************************************************/
++
++static void __inline__ sh64_dcache_purge_sets(int sets_to_purge_base, int n_sets)
++{
++	/* Purge all ways in a particular block of sets, specified by the base
++	   set number and number of sets.  Can handle wrap-around, if that's
++	   needed.  */
++
++	int dummy_buffer_base_set;
++	unsigned long long eaddr, eaddr0, eaddr1;
++	int j;
++	int set_offset;
++
++	dummy_buffer_base_set = ((int)&dummy_alloco_area & cpu_data->dcache.idx_mask) >> cpu_data->dcache.entry_shift;
++	set_offset = sets_to_purge_base - dummy_buffer_base_set;
++
++	for (j=0; j<n_sets; j++, set_offset++) {
++		set_offset &= (cpu_data->dcache.sets - 1);
++		eaddr0 = (unsigned long long)dummy_alloco_area + (set_offset << cpu_data->dcache.entry_shift);
++
++		/* Do one alloco which hits the required set per cache way.  For
++		   write-back mode, this will purge the #ways resident lines.   There's
++		   little point unrolling this loop because the allocos stall more if
++		   they're too close together. */
++		eaddr1 = eaddr0 + cpu_data->dcache.way_ofs * cpu_data->dcache.ways;
++		for (eaddr=eaddr0; eaddr<eaddr1; eaddr+=cpu_data->dcache.way_ofs) {
++			asm __volatile__ ("alloco %0, 0" : : "r" (eaddr));
++			asm __volatile__ ("synco"); /* TAKum03020 */
++		}
++
++		eaddr1 = eaddr0 + cpu_data->dcache.way_ofs * cpu_data->dcache.ways;
++		for (eaddr=eaddr0; eaddr<eaddr1; eaddr+=cpu_data->dcache.way_ofs) {
++			/* Load from each address.  Required because alloco is a NOP if
++			   the cache is write-through.  Write-through is a config option. */
++			if (test_bit(SH_CACHE_MODE_WT, &(cpu_data->dcache.flags)))
++				*(volatile unsigned char *)(int)eaddr;
++		}
++	}
++
++	/* Don't use OCBI to invalidate the lines.  That costs cycles directly.
++	   If the dummy block is just left resident, it will naturally get
++	   evicted as required.  */
++
++	return;
++}
++
++/****************************************************************************/
++
++static void sh64_dcache_purge_all(void)
++{
++	/* Purge the entire contents of the dcache.  The most efficient way to
++	   achieve this is to use alloco instructions on a region of unused
++	   memory equal in size to the cache, thereby causing the current
++	   contents to be discarded by natural eviction.  The alternative,
++	   namely reading every tag, setting up a mapping for the corresponding
++	   page and doing an OCBP for the line, would be much more expensive.
++	   */
++
++	sh64_dcache_purge_sets(0, cpu_data->dcache.sets);
++
++	return;
++
++}
++
++/****************************************************************************/
++
++static void sh64_dcache_purge_kernel_range(unsigned long start, unsigned long end)
++{
++	/* Purge the range of addresses [start,end] from the D-cache.  The
++	   addresses lie in the superpage mapping.  There's no harm if we
++	   overpurge at either end - just a small performance loss. */
++	unsigned long long ullend, addr, aligned_start;
++#if (NEFF == 32)
++	aligned_start = (unsigned long long)(signed long long)(signed long) start;
++#else
++#error "NEFF != 32"
++#endif
++	aligned_start &= L1_CACHE_ALIGN_MASK;
++	addr = aligned_start;
++#if (NEFF == 32)
++	ullend = (unsigned long long) (signed long long) (signed long) end;
++#else
++#error "NEFF != 32"
++#endif
++	while (addr <= ullend) {
++		asm __volatile__ ("ocbp %0, 0" : : "r" (addr));
++		addr += L1_CACHE_BYTES;
++	}
++	return;
++}
++
++/* Assumes this address (+ (2**n_synbits) pages up from it) aren't used for
++   anything else in the kernel */
++#define MAGIC_PAGE0_START 0xffffffffec000000ULL
++
++static void sh64_dcache_purge_coloured_phy_page(unsigned long paddr, unsigned long eaddr)
++{
++	/* Purge the physical page 'paddr' from the cache.  It's known that any
++	   cache lines requiring attention have the same page colour as the the
++	   address 'eaddr'.
++
++	   This relies on the fact that the D-cache matches on physical tags
++	   when no virtual tag matches.  So we create an alias for the original
++	   page and purge through that.  (Alternatively, we could have done
++	   this by switching ASID to match the original mapping and purged
++	   through that, but that involves ASID switching cost + probably a
++	   TLBMISS + refill anyway.)
++	   */
++
++	unsigned long long magic_page_start;
++	unsigned long long magic_eaddr, magic_eaddr_end;
++
++	magic_page_start = MAGIC_PAGE0_START + (eaddr & CACHE_OC_SYN_MASK);
++
++	/* As long as the kernel is not pre-emptible, this doesn't need to be
++	   under cli/sti. */
++
++	sh64_setup_dtlb_cache_slot(magic_page_start, get_asid(), paddr);
++
++	magic_eaddr = magic_page_start;
++	magic_eaddr_end = magic_eaddr + PAGE_SIZE;
++	while (magic_eaddr < magic_eaddr_end) {
++		/* Little point in unrolling this loop - the OCBPs are blocking
++		   and won't go any quicker (i.e. the loop overhead is parallel
++		   to part of the OCBP execution.) */
++		asm __volatile__ ("ocbp %0, 0" : : "r" (magic_eaddr));
++		magic_eaddr += L1_CACHE_BYTES;
++	}
++
++	sh64_teardown_dtlb_cache_slot();
++}
++
++/****************************************************************************/
++
++static void sh64_dcache_purge_phy_page(unsigned long paddr)
++{
++	/* Pure a page given its physical start address, by creating a
++	   temporary 1 page mapping and purging across that.  Even if we know
++	   the virtual address (& vma or mm) of the page, the method here is
++	   more elegant because it avoids issues of coping with page faults on
++	   the purge instructions (i.e. no special-case code required in the
++	   critical path in the TLB miss handling). */
++
++	unsigned long long eaddr_start, eaddr, eaddr_end;
++	int i;
++
++	/* As long as the kernel is not pre-emptible, this doesn't need to be
++	   under cli/sti. */
++
++	eaddr_start = MAGIC_PAGE0_START;
++	for (i=0; i < (1 << CACHE_OC_N_SYNBITS); i++) {
++		sh64_setup_dtlb_cache_slot(eaddr_start, get_asid(), paddr);
++
++		eaddr = eaddr_start;
++		eaddr_end = eaddr + PAGE_SIZE;
++		while (eaddr < eaddr_end) {
++			asm __volatile__ ("ocbp %0, 0" : : "r" (eaddr));
++			eaddr += L1_CACHE_BYTES;
++		}
++
++		sh64_teardown_dtlb_cache_slot();
++		eaddr_start += PAGE_SIZE;
++	}
++}
++
++static void sh64_dcache_purge_user_pages(struct mm_struct *mm,
++				unsigned long addr, unsigned long end)
++{
++	pgd_t *pgd;
++	pmd_t *pmd;
++	pte_t *pte;
++	pte_t entry;
++	spinlock_t *ptl;
++	unsigned long paddr;
++
++	if (!mm)
++		return; /* No way to find physical address of page */
++
++	pgd = pgd_offset(mm, addr);
++	if (pgd_bad(*pgd))
++		return;
++
++	pmd = pmd_offset(pgd, addr);
++	if (pmd_none(*pmd) || pmd_bad(*pmd))
++		return;
++
++	pte = pte_offset_map_lock(mm, pmd, addr, &ptl);
++	do {
++		entry = *pte;
++		if (pte_none(entry) || !pte_present(entry))
++			continue;
++		paddr = pte_val(entry) & PAGE_MASK;
++		sh64_dcache_purge_coloured_phy_page(paddr, addr);
++	} while (pte++, addr += PAGE_SIZE, addr != end);
++	pte_unmap_unlock(pte - 1, ptl);
++}
++/****************************************************************************/
++
++static void sh64_dcache_purge_user_range(struct mm_struct *mm,
++			  unsigned long start, unsigned long end)
++{
++	/* There are at least 5 choices for the implementation of this, with
++	   pros (+), cons(-), comments(*):
++
++	   1. ocbp each line in the range through the original user's ASID
++	      + no lines spuriously evicted
++	      - tlbmiss handling (must either handle faults on demand => extra
++		special-case code in tlbmiss critical path), or map the page in
++		advance (=> flush_tlb_range in advance to avoid multiple hits)
++	      - ASID switching
++	      - expensive for large ranges
++
++	   2. temporarily map each page in the range to a special effective
++	      address and ocbp through the temporary mapping; relies on the
++	      fact that SH-5 OCB* always do TLB lookup and match on ptags (they
++	      never look at the etags)
++	      + no spurious evictions
++	      - expensive for large ranges
++	      * surely cheaper than (1)
++
++	   3. walk all the lines in the cache, check the tags, if a match
++	      occurs create a page mapping to ocbp the line through
++	      + no spurious evictions
++	      - tag inspection overhead
++	      - (especially for small ranges)
++	      - potential cost of setting up/tearing down page mapping for
++		every line that matches the range
++	      * cost partly independent of range size
++
++	   4. walk all the lines in the cache, check the tags, if a match
++	      occurs use 4 * alloco to purge the line (+3 other probably
++	      innocent victims) by natural eviction
++	      + no tlb mapping overheads
++	      - spurious evictions
++	      - tag inspection overhead
++
++	   5. implement like flush_cache_all
++	      + no tag inspection overhead
++	      - spurious evictions
++	      - bad for small ranges
++
++	   (1) can be ruled out as more expensive than (2).  (2) appears best
++	   for small ranges.  The choice between (3), (4) and (5) for large
++	   ranges and the range size for the large/small boundary need
++	   benchmarking to determine.
++
++	   For now use approach (2) for small ranges and (5) for large ones.
++
++	   */
++
++	int n_pages;
++
++	n_pages = ((end - start) >> PAGE_SHIFT);
++	if (n_pages >= 64 || ((start ^ (end - 1)) & PMD_MASK)) {
++#if 1
++		sh64_dcache_purge_all();
++#else
++		unsigned long long set, way;
++		unsigned long mm_asid = mm->context & MMU_CONTEXT_ASID_MASK;
++		for (set = 0; set < cpu_data->dcache.sets; set++) {
++			unsigned long long set_base_config_addr = CACHE_OC_ADDRESS_ARRAY + (set << cpu_data->dcache.set_shift);
++			for (way = 0; way < cpu_data->dcache.ways; way++) {
++				unsigned long long config_addr = set_base_config_addr + (way << cpu_data->dcache.way_step_shift);
++				unsigned long long tag0;
++				unsigned long line_valid;
++
++				asm __volatile__("getcfg %1, 0, %0" : "=r" (tag0) : "r" (config_addr));
++				line_valid = tag0 & SH_CACHE_VALID;
++				if (line_valid) {
++					unsigned long cache_asid;
++					unsigned long epn;
++
++					cache_asid = (tag0 & cpu_data->dcache.asid_mask) >> cpu_data->dcache.asid_shift;
++					/* The next line needs some
++					   explanation.  The virtual tags
++					   encode bits [31:13] of the virtual
++					   address, bit [12] of the 'tag' being
++					   implied by the cache set index. */
++					epn = (tag0 & cpu_data->dcache.epn_mask) | ((set & 0x80) << cpu_data->dcache.entry_shift);
++
++					if ((cache_asid == mm_asid) && (start <= epn) && (epn < end)) {
++						/* TODO : could optimise this
++						   call by batching multiple
++						   adjacent sets together. */
++						sh64_dcache_purge_sets(set, 1);
++						break; /* Don't waste time inspecting other ways for this set */
++					}
++				}
++			}
++		}
++#endif
++	} else {
++		/* Small range, covered by a single page table page */
++		start &= PAGE_MASK;	/* should already be so */
++		end = PAGE_ALIGN(end);	/* should already be so */
++		sh64_dcache_purge_user_pages(mm, start, end);
++	}
++	return;
++}
++
++static void sh64_dcache_wback_current_user_range(unsigned long start, unsigned long end)
++{
++	unsigned long long aligned_start;
++	unsigned long long ull_end;
++	unsigned long long addr;
++
++	ull_end = end;
++
++	/* Just wback over the range using the natural addresses.  TLB miss
++	   handling will be OK (TBC) : the range has just been written to by
++	   the signal frame setup code, so the PTEs must exist.
++
++	   Note, if we have CONFIG_PREEMPT and get preempted inside this loop,
++	   it doesn't matter, even if the pid->ASID mapping changes whilst
++	   we're away.  In that case the cache will have been flushed when the
++	   mapping was renewed.  So the writebacks below will be nugatory (and
++	   we'll doubtless have to fault the TLB entry/ies in again with the
++	   new ASID), but it's a rare case.
++	   */
++	aligned_start = start & L1_CACHE_ALIGN_MASK;
++	addr = aligned_start;
++	while (addr < ull_end) {
++		asm __volatile__ ("ocbwb %0, 0" : : "r" (addr));
++		addr += L1_CACHE_BYTES;
++	}
++}
++
++/****************************************************************************/
++
++/* These *MUST* lie in an area of virtual address space that's otherwise unused. */
++#define UNIQUE_EADDR_START 0xe0000000UL
++#define UNIQUE_EADDR_END   0xe8000000UL
++
++static unsigned long sh64_make_unique_eaddr(unsigned long user_eaddr, unsigned long paddr)
++{
++	/* Given a physical address paddr, and a user virtual address
++	   user_eaddr which will eventually be mapped to it, create a one-off
++	   kernel-private eaddr mapped to the same paddr.  This is used for
++	   creating special destination pages for copy_user_page and
++	   clear_user_page */
++
++	static unsigned long current_pointer = UNIQUE_EADDR_START;
++	unsigned long coloured_pointer;
++
++	if (current_pointer == UNIQUE_EADDR_END) {
++		sh64_dcache_purge_all();
++		current_pointer = UNIQUE_EADDR_START;
++	}
++
++	coloured_pointer = (current_pointer & ~CACHE_OC_SYN_MASK) | (user_eaddr & CACHE_OC_SYN_MASK);
++	sh64_setup_dtlb_cache_slot(coloured_pointer, get_asid(), paddr);
++
++	current_pointer += (PAGE_SIZE << CACHE_OC_N_SYNBITS);
++
++	return coloured_pointer;
++}
++
++/****************************************************************************/
++
++static void sh64_copy_user_page_coloured(void *to, void *from, unsigned long address)
++{
++	void *coloured_to;
++
++	/* Discard any existing cache entries of the wrong colour.  These are
++	   present quite often, if the kernel has recently used the page
++	   internally, then given it up, then it's been allocated to the user.
++	   */
++	sh64_dcache_purge_coloured_phy_page(__pa(to), (unsigned long) to);
++
++	coloured_to = (void *) sh64_make_unique_eaddr(address, __pa(to));
++	sh64_page_copy(from, coloured_to);
++
++	sh64_teardown_dtlb_cache_slot();
++}
++
++static void sh64_clear_user_page_coloured(void *to, unsigned long address)
++{
++	void *coloured_to;
++
++	/* Discard any existing kernel-originated lines of the wrong colour (as
++	   above) */
++	sh64_dcache_purge_coloured_phy_page(__pa(to), (unsigned long) to);
++
++	coloured_to = (void *) sh64_make_unique_eaddr(address, __pa(to));
++	sh64_page_clear(coloured_to);
++
++	sh64_teardown_dtlb_cache_slot();
++}
++
++#endif /* !CONFIG_DCACHE_DISABLED */
++
++/****************************************************************************/
++
++/*##########################################################################
++			    EXTERNALLY CALLABLE API.
++  ##########################################################################*/
++
++/* These functions are described in Documentation/cachetlb.txt.
++   Each one of these functions varies in behaviour depending on whether the
++   I-cache and/or D-cache are configured out.
++
++   Note that the Linux term 'flush' corresponds to what is termed 'purge' in
++   the sh/sh64 jargon for the D-cache, i.e. write back dirty data then
++   invalidate the cache lines, and 'invalidate' for the I-cache.
++   */
++
++#undef FLUSH_TRACE
++
++void flush_cache_all(void)
++{
++	/* Invalidate the entire contents of both caches, after writing back to
++	   memory any dirty data from the D-cache. */
++	sh64_dcache_purge_all();
++	sh64_icache_inv_all();
++}
++
++/****************************************************************************/
++
++void flush_cache_mm(struct mm_struct *mm)
++{
++	/* Invalidate an entire user-address space from both caches, after
++	   writing back dirty data (e.g. for shared mmap etc). */
++
++	/* This could be coded selectively by inspecting all the tags then
++	   doing 4*alloco on any set containing a match (as for
++	   flush_cache_range), but fork/exit/execve (where this is called from)
++	   are expensive anyway. */
++
++	/* Have to do a purge here, despite the comments re I-cache below.
++	   There could be odd-coloured dirty data associated with the mm still
++	   in the cache - if this gets written out through natural eviction
++	   after the kernel has reused the page there will be chaos.
++	   */
++
++	sh64_dcache_purge_all();
++
++	/* The mm being torn down won't ever be active again, so any Icache
++	   lines tagged with its ASID won't be visible for the rest of the
++	   lifetime of this ASID cycle.  Before the ASID gets reused, there
++	   will be a flush_cache_all.  Hence we don't need to touch the
++	   I-cache.  This is similar to the lack of action needed in
++	   flush_tlb_mm - see fault.c. */
++}
++
++/****************************************************************************/
++
++void flush_cache_range(struct vm_area_struct *vma, unsigned long start,
++		       unsigned long end)
++{
++	struct mm_struct *mm = vma->vm_mm;
++
++	/* Invalidate (from both caches) the range [start,end) of virtual
++	   addresses from the user address space specified by mm, after writing
++	   back any dirty data.
++
++	   Note, 'end' is 1 byte beyond the end of the range to flush. */
++
++	sh64_dcache_purge_user_range(mm, start, end);
++	sh64_icache_inv_user_page_range(mm, start, end);
++}
++
++/****************************************************************************/
++
++void flush_cache_page(struct vm_area_struct *vma, unsigned long eaddr, unsigned long pfn)
++{
++	/* Invalidate any entries in either cache for the vma within the user
++	   address space vma->vm_mm for the page starting at virtual address
++	   'eaddr'.   This seems to be used primarily in breaking COW.  Note,
++	   the I-cache must be searched too in case the page in question is
++	   both writable and being executed from (e.g. stack trampolines.)
++
++	   Note, this is called with pte lock held.
++	   */
++
++	sh64_dcache_purge_phy_page(pfn << PAGE_SHIFT);
++
++	if (vma->vm_flags & VM_EXEC) {
++		sh64_icache_inv_user_page(vma, eaddr);
++	}
++}
++
++/****************************************************************************/
++
++#ifndef CONFIG_DCACHE_DISABLED
++
++void copy_user_page(void *to, void *from, unsigned long address, struct page *page)
++{
++	/* 'from' and 'to' are kernel virtual addresses (within the superpage
++	   mapping of the physical RAM).  'address' is the user virtual address
++	   where the copy 'to' will be mapped after.  This allows a custom
++	   mapping to be used to ensure that the new copy is placed in the
++	   right cache sets for the user to see it without having to bounce it
++	   out via memory.  Note however : the call to flush_page_to_ram in
++	   (generic)/mm/memory.c:(break_cow) undoes all this good work in that one
++	   very important case!
++
++	   TBD : can we guarantee that on every call, any cache entries for
++	   'from' are in the same colour sets as 'address' also?  i.e. is this
++	   always used just to deal with COW?  (I suspect not). */
++
++	/* There are two possibilities here for when the page 'from' was last accessed:
++	   * by the kernel : this is OK, no purge required.
++	   * by the/a user (e.g. for break_COW) : need to purge.
++
++	   If the potential user mapping at 'address' is the same colour as
++	   'from' there is no need to purge any cache lines from the 'from'
++	   page mapped into cache sets of colour 'address'.  (The copy will be
++	   accessing the page through 'from').
++	   */
++
++	if (((address ^ (unsigned long) from) & CACHE_OC_SYN_MASK) != 0) {
++		sh64_dcache_purge_coloured_phy_page(__pa(from), address);
++	}
++
++	if (((address ^ (unsigned long) to) & CACHE_OC_SYN_MASK) == 0) {
++		/* No synonym problem on destination */
++		sh64_page_copy(from, to);
++	} else {
++		sh64_copy_user_page_coloured(to, from, address);
++	}
++
++	/* Note, don't need to flush 'from' page from the cache again - it's
++	   done anyway by the generic code */
++}
++
++void clear_user_page(void *to, unsigned long address, struct page *page)
++{
++	/* 'to' is a kernel virtual address (within the superpage
++	   mapping of the physical RAM).  'address' is the user virtual address
++	   where the 'to' page will be mapped after.  This allows a custom
++	   mapping to be used to ensure that the new copy is placed in the
++	   right cache sets for the user to see it without having to bounce it
++	   out via memory.
++	*/
++
++	if (((address ^ (unsigned long) to) & CACHE_OC_SYN_MASK) == 0) {
++		/* No synonym problem on destination */
++		sh64_page_clear(to);
++	} else {
++		sh64_clear_user_page_coloured(to, address);
++	}
++}
++
++#endif /* !CONFIG_DCACHE_DISABLED */
++
++/****************************************************************************/
++
++void flush_dcache_page(struct page *page)
++{
++	sh64_dcache_purge_phy_page(page_to_phys(page));
++	wmb();
++}
++
++/****************************************************************************/
++
++void flush_icache_range(unsigned long start, unsigned long end)
++{
++	/* Flush the range [start,end] of kernel virtual adddress space from
++	   the I-cache.  The corresponding range must be purged from the
++	   D-cache also because the SH-5 doesn't have cache snooping between
++	   the caches.  The addresses will be visible through the superpage
++	   mapping, therefore it's guaranteed that there no cache entries for
++	   the range in cache sets of the wrong colour.
++
++	   Primarily used for cohering the I-cache after a module has
++	   been loaded.  */
++
++	/* We also make sure to purge the same range from the D-cache since
++	   flush_page_to_ram() won't be doing this for us! */
++
++	sh64_dcache_purge_kernel_range(start, end);
++	wmb();
++	sh64_icache_inv_kernel_range(start, end);
++}
++
++/****************************************************************************/
++
++void flush_icache_user_range(struct vm_area_struct *vma,
++			struct page *page, unsigned long addr, int len)
++{
++	/* Flush the range of user (defined by vma->vm_mm) address space
++	   starting at 'addr' for 'len' bytes from the cache.  The range does
++	   not straddle a page boundary, the unique physical page containing
++	   the range is 'page'.  This seems to be used mainly for invalidating
++	   an address range following a poke into the program text through the
++	   ptrace() call from another process (e.g. for BRK instruction
++	   insertion). */
++
++	sh64_dcache_purge_coloured_phy_page(page_to_phys(page), addr);
++	mb();
++
++	if (vma->vm_flags & VM_EXEC) {
++		sh64_icache_inv_user_small_range(vma->vm_mm, addr, len);
++	}
++}
++
++/*##########################################################################
++			ARCH/SH64 PRIVATE CALLABLE API.
++  ##########################################################################*/
++
++void flush_cache_sigtramp(unsigned long start, unsigned long end)
++{
++	/* For the address range [start,end), write back the data from the
++	   D-cache and invalidate the corresponding region of the I-cache for
++	   the current process.  Used to flush signal trampolines on the stack
++	   to make them executable. */
++
++	sh64_dcache_wback_current_user_range(start, end);
++	wmb();
++	sh64_icache_inv_current_user_range(start, end);
++}
++
+diff --git a/arch/sh/mm/cache-sh7705.c b/arch/sh/mm/cache-sh7705.c
+index 4896d73..22dacc7 100644
+--- a/arch/sh/mm/cache-sh7705.c
++++ b/arch/sh/mm/cache-sh7705.c
+@@ -71,7 +71,7 @@ void flush_icache_range(unsigned long start, unsigned long end)
+ /*
+  * Writeback&Invalidate the D-cache of the page
+  */
+-static void __flush_dcache_page(unsigned long phys)
++static void __uses_jump_to_uncached __flush_dcache_page(unsigned long phys)
+ {
+ 	unsigned long ways, waysize, addrstart;
+ 	unsigned long flags;
+@@ -92,7 +92,7 @@ static void __flush_dcache_page(unsigned long phys)
+ 	 * possible.
+ 	 */
+ 	local_irq_save(flags);
+-	jump_to_P2();
++	jump_to_uncached();
+ 
+ 	ways = current_cpu_data.dcache.ways;
+ 	waysize = current_cpu_data.dcache.sets;
+@@ -118,7 +118,7 @@ static void __flush_dcache_page(unsigned long phys)
+ 		addrstart += current_cpu_data.dcache.way_incr;
+ 	} while (--ways);
+ 
+-	back_to_P1();
++	back_to_cached();
+ 	local_irq_restore(flags);
+ }
+ 
+@@ -132,15 +132,15 @@ void flush_dcache_page(struct page *page)
+ 		__flush_dcache_page(PHYSADDR(page_address(page)));
+ }
+ 
+-void flush_cache_all(void)
++void __uses_jump_to_uncached flush_cache_all(void)
+ {
+ 	unsigned long flags;
+ 
+ 	local_irq_save(flags);
+-	jump_to_P2();
++	jump_to_uncached();
+ 
+ 	cache_wback_all();
+-	back_to_P1();
++	back_to_cached();
+ 	local_irq_restore(flags);
+ }
+ 
+diff --git a/arch/sh/mm/clear_page.S b/arch/sh/mm/clear_page.S
+deleted file mode 100644
+index 7a7c81e..0000000
+--- a/arch/sh/mm/clear_page.S
++++ /dev/null
+@@ -1,152 +0,0 @@
+-/*
+- * __clear_user_page, __clear_user, clear_page implementation of SuperH
+- *
+- * Copyright (C) 2001  Kaz Kojima
+- * Copyright (C) 2001, 2002  Niibe Yutaka
+- * Copyright (C) 2006  Paul Mundt
+- */
+-#include <linux/linkage.h>
+-#include <asm/page.h>
+-
+-/*
+- * clear_page_slow
+- * @to: P1 address
+- *
+- * void clear_page_slow(void *to)
+- */
+-
+-/*
+- * r0 --- scratch
+- * r4 --- to
+- * r5 --- to + PAGE_SIZE
+- */
+-ENTRY(clear_page_slow)
+-	mov	r4,r5
+-	mov.l	.Llimit,r0
+-	add	r0,r5
+-	mov	#0,r0
+-	!
+-1:
+-#if defined(CONFIG_CPU_SH3)
+-	mov.l	r0, at r4
+-#elif defined(CONFIG_CPU_SH4)
+-	movca.l	r0, at r4
+-	mov	r4,r1
+-#endif
+-	add	#32,r4
+-	mov.l	r0, at -r4
+-	mov.l	r0, at -r4
+-	mov.l	r0, at -r4
+-	mov.l	r0, at -r4
+-	mov.l	r0, at -r4
+-	mov.l	r0, at -r4
+-	mov.l	r0, at -r4
+-#if defined(CONFIG_CPU_SH4)
+-	ocbwb	@r1
+-#endif
+-	cmp/eq	r5,r4
+-	bf/s	1b
+-	 add	#28,r4
+-	!
+-	rts
+-	 nop
+-.Llimit:	.long	(PAGE_SIZE-28)
+-
+-ENTRY(__clear_user)
+-	!
+-	mov	#0, r0
+-	mov	#0xe0, r1	! 0xffffffe0
+-	!
+-	! r4..(r4+31)&~32 	   -------- not aligned	[ Area 0 ]
+-	! (r4+31)&~32..(r4+r5)&~32 -------- aligned	[ Area 1 ]
+-	! (r4+r5)&~32..r4+r5       -------- not aligned	[ Area 2 ]
+-	!
+-	! Clear area 0
+-	mov	r4, r2
+-	!
+-	tst	r1, r5		! length < 32
+-	bt	.Larea2		! skip to remainder
+-	!
+-	add	#31, r2
+-	and	r1, r2
+-	cmp/eq	r4, r2
+-	bt	.Larea1
+-	mov	r2, r3
+-	sub	r4, r3
+-	mov	r3, r7
+-	mov	r4, r2
+-	!
+-.L0:	dt	r3
+-0:	mov.b	r0, @r2
+-	bf/s	.L0
+-	 add	#1, r2
+-	!
+-	sub	r7, r5
+-	mov	r2, r4
+-.Larea1:
+-	mov	r4, r3
+-	add	r5, r3
+-	and	r1, r3
+-	cmp/hi	r2, r3
+-	bf	.Larea2
+-	!
+-	! Clear area 1
+-#if defined(CONFIG_CPU_SH4)
+-1:	movca.l	r0, @r2
+-#else
+-1:	mov.l	r0, @r2
+-#endif
+-	add	#4, r2
+-2:	mov.l	r0, @r2
+-	add	#4, r2
+-3:	mov.l	r0, @r2
+-	add	#4, r2
+-4:	mov.l	r0, @r2
+-	add	#4, r2
+-5:	mov.l	r0, @r2
+-	add	#4, r2
+-6:	mov.l	r0, @r2
+-	add	#4, r2
+-7:	mov.l	r0, @r2
+-	add	#4, r2
+-8:	mov.l	r0, @r2
+-	add	#4, r2
+-	cmp/hi	r2, r3
+-	bt/s	1b
+-	 nop
+-	!
+-	! Clear area 2
+-.Larea2:
+-	mov	r4, r3
+-	add	r5, r3
+-	cmp/hs	r3, r2
+-	bt/s	.Ldone
+-	 sub	r2, r3
+-.L2:	dt	r3
+-9:	mov.b	r0, @r2
+-	bf/s	.L2
+-	 add	#1, r2
+-	!
+-.Ldone:	rts
+-	 mov	#0, r0	! return 0 as normal return
+-
+-	! return the number of bytes remained
+-.Lbad_clear_user:
+-	mov	r4, r0
+-	add	r5, r0
+-	rts
+-	 sub	r2, r0
+-
+-.section __ex_table,"a"
+-	.align 2
+-	.long	0b, .Lbad_clear_user
+-	.long	1b, .Lbad_clear_user
+-	.long	2b, .Lbad_clear_user
+-	.long	3b, .Lbad_clear_user
+-	.long	4b, .Lbad_clear_user
+-	.long	5b, .Lbad_clear_user
+-	.long	6b, .Lbad_clear_user
+-	.long	7b, .Lbad_clear_user
+-	.long	8b, .Lbad_clear_user
+-	.long	9b, .Lbad_clear_user
+-.previous
+diff --git a/arch/sh/mm/consistent.c b/arch/sh/mm/consistent.c
+index e220c29..7b2131c 100644
+--- a/arch/sh/mm/consistent.c
++++ b/arch/sh/mm/consistent.c
+@@ -1,7 +1,9 @@
+ /*
+  * arch/sh/mm/consistent.c
+  *
+- * Copyright (C) 2004  Paul Mundt
++ * Copyright (C) 2004 - 2007  Paul Mundt
++ *
++ * Declared coherent memory functions based on arch/x86/kernel/pci-dma_32.c
+  *
+  * This file is subject to the terms and conditions of the GNU General Public
+  * License.  See the file "COPYING" in the main directory of this archive
+@@ -13,58 +15,152 @@
+ #include <asm/addrspace.h>
+ #include <asm/io.h>
+ 
+-void *consistent_alloc(gfp_t gfp, size_t size, dma_addr_t *handle)
++struct dma_coherent_mem {
++	void		*virt_base;
++	u32		device_base;
++	int		size;
++	int		flags;
++	unsigned long	*bitmap;
++};
++
++void *dma_alloc_coherent(struct device *dev, size_t size,
++			   dma_addr_t *dma_handle, gfp_t gfp)
+ {
+-	struct page *page, *end, *free;
+ 	void *ret;
+-	int order;
++	struct dma_coherent_mem *mem = dev ? dev->dma_mem : NULL;
++	int order = get_order(size);
+ 
+-	size = PAGE_ALIGN(size);
+-	order = get_order(size);
++	if (mem) {
++		int page = bitmap_find_free_region(mem->bitmap, mem->size,
++						     order);
++		if (page >= 0) {
++			*dma_handle = mem->device_base + (page << PAGE_SHIFT);
++			ret = mem->virt_base + (page << PAGE_SHIFT);
++			memset(ret, 0, size);
++			return ret;
++		}
++		if (mem->flags & DMA_MEMORY_EXCLUSIVE)
++			return NULL;
++	}
+ 
+-	page = alloc_pages(gfp, order);
+-	if (!page)
+-		return NULL;
+-	split_page(page, order);
++	ret = (void *)__get_free_pages(gfp, order);
+ 
+-	ret = page_address(page);
+-	memset(ret, 0, size);
+-	*handle = virt_to_phys(ret);
++	if (ret != NULL) {
++		memset(ret, 0, size);
++		/*
++		 * Pages from the page allocator may have data present in
++		 * cache. So flush the cache before using uncached memory.
++		 */
++		dma_cache_sync(NULL, ret, size, DMA_BIDIRECTIONAL);
++		*dma_handle = virt_to_phys(ret);
++	}
++	return ret;
++}
++EXPORT_SYMBOL(dma_alloc_coherent);
+ 
+-	/*
+-	 * We must flush the cache before we pass it on to the device
+-	 */
+-	__flush_purge_region(ret, size);
++void dma_free_coherent(struct device *dev, size_t size,
++			 void *vaddr, dma_addr_t dma_handle)
++{
++	struct dma_coherent_mem *mem = dev ? dev->dma_mem : NULL;
++	int order = get_order(size);
+ 
+-	page = virt_to_page(ret);
+-	free = page + (size >> PAGE_SHIFT);
+-	end  = page + (1 << order);
++	if (mem && vaddr >= mem->virt_base && vaddr < (mem->virt_base + (mem->size << PAGE_SHIFT))) {
++		int page = (vaddr - mem->virt_base) >> PAGE_SHIFT;
+ 
+-	while (++page < end) {
+-		/* Free any unused pages */
+-		if (page >= free) {
+-			__free_page(page);
+-		}
++		bitmap_release_region(mem->bitmap, page, order);
++	} else {
++		WARN_ON(irqs_disabled());	/* for portability */
++		BUG_ON(mem && mem->flags & DMA_MEMORY_EXCLUSIVE);
++		free_pages((unsigned long)vaddr, order);
+ 	}
++}
++EXPORT_SYMBOL(dma_free_coherent);
++
++int dma_declare_coherent_memory(struct device *dev, dma_addr_t bus_addr,
++				dma_addr_t device_addr, size_t size, int flags)
++{
++	void __iomem *mem_base = NULL;
++	int pages = size >> PAGE_SHIFT;
++	int bitmap_size = BITS_TO_LONGS(pages) * sizeof(long);
++
++	if ((flags & (DMA_MEMORY_MAP | DMA_MEMORY_IO)) == 0)
++		goto out;
++	if (!size)
++		goto out;
++	if (dev->dma_mem)
++		goto out;
++
++	/* FIXME: this routine just ignores DMA_MEMORY_INCLUDES_CHILDREN */
+ 
+-	return P2SEGADDR(ret);
++	mem_base = ioremap_nocache(bus_addr, size);
++	if (!mem_base)
++		goto out;
++
++	dev->dma_mem = kmalloc(sizeof(struct dma_coherent_mem), GFP_KERNEL);
++	if (!dev->dma_mem)
++		goto out;
++	dev->dma_mem->bitmap = kzalloc(bitmap_size, GFP_KERNEL);
++	if (!dev->dma_mem->bitmap)
++		goto free1_out;
++
++	dev->dma_mem->virt_base = mem_base;
++	dev->dma_mem->device_base = device_addr;
++	dev->dma_mem->size = pages;
++	dev->dma_mem->flags = flags;
++
++	if (flags & DMA_MEMORY_MAP)
++		return DMA_MEMORY_MAP;
++
++	return DMA_MEMORY_IO;
++
++ free1_out:
++	kfree(dev->dma_mem);
++ out:
++	if (mem_base)
++		iounmap(mem_base);
++	return 0;
+ }
++EXPORT_SYMBOL(dma_declare_coherent_memory);
+ 
+-void consistent_free(void *vaddr, size_t size)
++void dma_release_declared_memory(struct device *dev)
+ {
+-	unsigned long addr = P1SEGADDR((unsigned long)vaddr);
+-	struct page *page=virt_to_page(addr);
+-	int num_pages=(size+PAGE_SIZE-1) >> PAGE_SHIFT;
+-	int i;
++	struct dma_coherent_mem *mem = dev->dma_mem;
+ 
+-	for(i=0;i<num_pages;i++) {
+-		__free_page((page+i));
+-	}
++	if (!mem)
++		return;
++	dev->dma_mem = NULL;
++	iounmap(mem->virt_base);
++	kfree(mem->bitmap);
++	kfree(mem);
+ }
++EXPORT_SYMBOL(dma_release_declared_memory);
+ 
+-void consistent_sync(void *vaddr, size_t size, int direction)
++void *dma_mark_declared_memory_occupied(struct device *dev,
++					dma_addr_t device_addr, size_t size)
+ {
+-	void * p1addr = (void*) P1SEGADDR((unsigned long)vaddr);
++	struct dma_coherent_mem *mem = dev->dma_mem;
++	int pages = (size + (device_addr & ~PAGE_MASK) + PAGE_SIZE - 1) >> PAGE_SHIFT;
++	int pos, err;
++
++	if (!mem)
++		return ERR_PTR(-EINVAL);
++
++	pos = (device_addr - mem->device_base) >> PAGE_SHIFT;
++	err = bitmap_allocate_region(mem->bitmap, pos, get_order(pages));
++	if (err != 0)
++		return ERR_PTR(err);
++	return mem->virt_base + (pos << PAGE_SHIFT);
++}
++EXPORT_SYMBOL(dma_mark_declared_memory_occupied);
++
++void dma_cache_sync(struct device *dev, void *vaddr, size_t size,
++		    enum dma_data_direction direction)
++{
++#ifdef CONFIG_CPU_SH5
++	void *p1addr = vaddr;
++#else
++	void *p1addr = (void*) P1SEGADDR((unsigned long)vaddr);
++#endif
+ 
+ 	switch (direction) {
+ 	case DMA_FROM_DEVICE:		/* invalidate only */
+@@ -80,8 +176,4 @@ void consistent_sync(void *vaddr, size_t size, int direction)
+ 		BUG();
+ 	}
+ }
+-
+-EXPORT_SYMBOL(consistent_alloc);
+-EXPORT_SYMBOL(consistent_free);
+-EXPORT_SYMBOL(consistent_sync);
+-
++EXPORT_SYMBOL(dma_cache_sync);
+diff --git a/arch/sh/mm/copy_page.S b/arch/sh/mm/copy_page.S
+deleted file mode 100644
+index 4068501..0000000
+--- a/arch/sh/mm/copy_page.S
++++ /dev/null
+@@ -1,388 +0,0 @@
+-/*
+- * copy_page, __copy_user_page, __copy_user implementation of SuperH
+- *
+- * Copyright (C) 2001  Niibe Yutaka & Kaz Kojima
+- * Copyright (C) 2002  Toshinobu Sugioka
+- * Copyright (C) 2006  Paul Mundt
+- */
+-#include <linux/linkage.h>
+-#include <asm/page.h>
+-
+-/*
+- * copy_page_slow
+- * @to: P1 address
+- * @from: P1 address
+- *
+- * void copy_page_slow(void *to, void *from)
+- */
+-
+-/*
+- * r0, r1, r2, r3, r4, r5, r6, r7 --- scratch 
+- * r8 --- from + PAGE_SIZE
+- * r9 --- not used
+- * r10 --- to
+- * r11 --- from
+- */
+-ENTRY(copy_page_slow)
+-	mov.l	r8, at -r15
+-	mov.l	r10, at -r15
+-	mov.l	r11, at -r15
+-	mov	r4,r10
+-	mov	r5,r11
+-	mov	r5,r8
+-	mov.l	.Lpsz,r0
+-	add	r0,r8
+-	!
+-1:	mov.l	@r11+,r0
+-	mov.l	@r11+,r1
+-	mov.l	@r11+,r2
+-	mov.l	@r11+,r3
+-	mov.l	@r11+,r4
+-	mov.l	@r11+,r5
+-	mov.l	@r11+,r6
+-	mov.l	@r11+,r7
+-#if defined(CONFIG_CPU_SH3)
+-	mov.l	r0, at r10
+-#elif defined(CONFIG_CPU_SH4)
+-	movca.l	r0, at r10
+-	mov	r10,r0
+-#endif
+-	add	#32,r10
+-	mov.l	r7, at -r10
+-	mov.l	r6, at -r10
+-	mov.l	r5, at -r10
+-	mov.l	r4, at -r10
+-	mov.l	r3, at -r10
+-	mov.l	r2, at -r10
+-	mov.l	r1, at -r10
+-#if defined(CONFIG_CPU_SH4)
+-	ocbwb	@r0
+-#endif
+-	cmp/eq	r11,r8
+-	bf/s	1b
+-	 add	#28,r10
+-	!
+-	mov.l	@r15+,r11
+-	mov.l	@r15+,r10
+-	mov.l	@r15+,r8
+-	rts
+-	 nop
+-
+-	.align 2
+-.Lpsz:	.long	PAGE_SIZE
+-/*
+- * __kernel_size_t __copy_user(void *to, const void *from, __kernel_size_t n);
+- * Return the number of bytes NOT copied
+- */
+-#define EX(...)			\
+-	9999: __VA_ARGS__ ;		\
+-	.section __ex_table, "a";	\
+-	.long 9999b, 6000f	;	\
+-	.previous
+-ENTRY(__copy_user)
+-	! Check if small number of bytes
+-	mov	#11,r0
+-	mov	r4,r3
+-	cmp/gt	r0,r6		! r6 (len) > r0 (11)
+-	bf/s	.L_cleanup_loop_no_pop
+-	 add	r6,r3		! last destination address
+-
+-	! Calculate bytes needed to align to src
+-	mov.l	r11, at -r15
+-	neg	r5,r0
+-	mov.l	r10, at -r15
+-	add	#4,r0
+-	mov.l	r9, at -r15
+-	and	#3,r0
+-	mov.l	r8, at -r15
+-	tst	r0,r0
+-	bt	2f
+-
+-1:
+-	! Copy bytes to long word align src
+-EX(	mov.b	@r5+,r1		)
+-	dt	r0
+-	add	#-1,r6
+-EX(	mov.b	r1, at r4		)
+-	bf/s	1b
+-	 add	#1,r4
+-
+-	! Jump to appropriate routine depending on dest
+-2:	mov	#3,r1
+-	mov	r6, r2
+-	and	r4,r1
+-	shlr2	r2
+-	shll2	r1
+-	mova	.L_jump_tbl,r0
+-	mov.l	@(r0,r1),r1
+-	jmp	@r1
+-	 nop
+-
+-	.align 2
+-.L_jump_tbl:
+-	.long	.L_dest00
+-	.long	.L_dest01
+-	.long	.L_dest10
+-	.long	.L_dest11
+-
+-/*
+- * Come here if there are less than 12 bytes to copy
+- *
+- * Keep the branch target close, so the bf/s callee doesn't overflow
+- * and result in a more expensive branch being inserted. This is the
+- * fast-path for small copies, the jump via the jump table will hit the
+- * default slow-path cleanup. -PFM.
+- */
+-.L_cleanup_loop_no_pop:
+-	tst	r6,r6		! Check explicitly for zero
+-	bt	1f
+-
+-2:
+-EX(	mov.b	@r5+,r0		)
+-	dt	r6
+-EX(	mov.b	r0, at r4		)
+-	bf/s	2b
+-	 add	#1,r4
+-
+-1:	mov	#0,r0		! normal return
+-5000:
+-
+-# Exception handler:
+-.section .fixup, "ax"
+-6000:
+-	mov.l	8000f,r1
+-	mov	r3,r0
+-	jmp	@r1
+-	 sub	r4,r0
+-	.align	2
+-8000:	.long	5000b
+-
+-.previous
+-	rts
+-	 nop
+-
+-! Destination = 00
+-
+-.L_dest00:
+-	! Skip the large copy for small transfers
+-	mov	#(32+32-4), r0
+-	cmp/gt	r6, r0		! r0 (60) > r6 (len)
+-	bt	1f
+-
+-	! Align dest to a 32 byte boundary
+-	neg	r4,r0
+-	add	#0x20, r0
+-	and	#0x1f, r0
+-	tst	r0, r0
+-	bt	2f
+-
+-	sub	r0, r6
+-	shlr2	r0
+-3:
+-EX(	mov.l	@r5+,r1		)
+-	dt	r0
+-EX(	mov.l	r1, at r4		)
+-	bf/s	3b
+-	 add	#4,r4
+-
+-2:
+-EX(	mov.l	@r5+,r0		)
+-EX(	mov.l	@r5+,r1		)
+-EX(	mov.l	@r5+,r2		)
+-EX(	mov.l	@r5+,r7		)
+-EX(	mov.l	@r5+,r8		)
+-EX(	mov.l	@r5+,r9		)
+-EX(	mov.l	@r5+,r10	)
+-EX(	mov.l	@r5+,r11	)
+-#ifdef CONFIG_CPU_SH4
+-EX(	movca.l	r0, at r4		)
+-#else
+-EX(	mov.l	r0, at r4		)
+-#endif
+-	add	#-32, r6
+-EX(	mov.l	r1,@(4,r4)	)
+-	mov	#32, r0
+-EX(	mov.l	r2,@(8,r4)	)
+-	cmp/gt	r6, r0		! r0 (32) > r6 (len)
+-EX(	mov.l	r7,@(12,r4)	)
+-EX(	mov.l	r8,@(16,r4)	)
+-EX(	mov.l	r9,@(20,r4)	)
+-EX(	mov.l	r10,@(24,r4)	)
+-EX(	mov.l	r11,@(28,r4)	)
+-	bf/s	2b
+-	 add	#32,r4
+-
+-1:	mov	r6, r0
+-	shlr2	r0
+-	tst	r0, r0
+-	bt	.L_cleanup
+-1:
+-EX(	mov.l	@r5+,r1		)
+-	dt	r0
+-EX(	mov.l	r1, at r4		)
+-	bf/s	1b
+-	 add	#4,r4
+-
+-	bra	.L_cleanup
+-	 nop
+-
+-! Destination = 10
+-
+-.L_dest10:
+-	mov	r2,r7
+-	shlr2	r7
+-	shlr	r7
+-	tst	r7,r7
+-	mov	#7,r0
+-	bt/s	1f
+-	 and	r0,r2
+-2:
+-	dt	r7
+-#ifdef CONFIG_CPU_LITTLE_ENDIAN
+-EX(	mov.l	@r5+,r0		)
+-EX(	mov.l	@r5+,r1		)
+-EX(	mov.l	@r5+,r8		)
+-EX(	mov.l	@r5+,r9		)
+-EX(	mov.l	@r5+,r10	)
+-EX(	mov.w	r0, at r4		)
+-	add	#2,r4
+-	xtrct	r1,r0
+-	xtrct	r8,r1
+-	xtrct	r9,r8
+-	xtrct	r10,r9
+-
+-EX(	mov.l	r0, at r4		)
+-EX(	mov.l	r1,@(4,r4)	)
+-EX(	mov.l	r8,@(8,r4)	)
+-EX(	mov.l	r9,@(12,r4)	)
+-
+-EX(	mov.l	@r5+,r1		)
+-EX(	mov.l	@r5+,r8		)
+-EX(	mov.l	@r5+,r0		)
+-	xtrct	r1,r10
+-	xtrct	r8,r1
+-	xtrct	r0,r8
+-	shlr16	r0
+-EX(	mov.l	r10,@(16,r4)	)
+-EX(	mov.l	r1,@(20,r4)	)
+-EX(	mov.l	r8,@(24,r4)	)
+-EX(	mov.w	r0,@(28,r4)	)
+-	bf/s	2b
+-	 add	#30,r4
+-#else
+-EX(	mov.l	@(28,r5),r0	)
+-EX(	mov.l	@(24,r5),r8	)
+-EX(	mov.l	@(20,r5),r9	)
+-EX(	mov.l	@(16,r5),r10	)
+-EX(	mov.w	r0,@(30,r4)	)
+-	add	#-2,r4
+-	xtrct	r8,r0
+-	xtrct	r9,r8
+-	xtrct	r10,r9
+-EX(	mov.l	r0,@(28,r4)	)
+-EX(	mov.l	r8,@(24,r4)	)
+-EX(	mov.l	r9,@(20,r4)	)
+-
+-EX(	mov.l	@(12,r5),r0	)
+-EX(	mov.l	@(8,r5),r8	)
+-	xtrct	r0,r10
+-EX(	mov.l	@(4,r5),r9	)
+-	mov.l	r10,@(16,r4)
+-EX(	mov.l	@r5,r10		)
+-	xtrct	r8,r0
+-	xtrct	r9,r8
+-	xtrct	r10,r9
+-EX(	mov.l	r0,@(12,r4)	)
+-EX(	mov.l	r8,@(8,r4)	)
+-	swap.w	r10,r0
+-EX(	mov.l	r9,@(4,r4)	)
+-EX(	mov.w	r0,@(2,r4)	)
+-
+-	add	#32,r5
+-	bf/s	2b
+-	 add	#34,r4
+-#endif
+-	tst	r2,r2
+-	bt	.L_cleanup
+-
+-1:	! Read longword, write two words per iteration
+-EX(	mov.l	@r5+,r0		)
+-	dt	r2
+-#ifdef CONFIG_CPU_LITTLE_ENDIAN
+-EX(	mov.w	r0, at r4		)
+-	shlr16	r0
+-EX(	mov.w 	r0,@(2,r4)	)
+-#else
+-EX(	mov.w	r0,@(2,r4)	)
+-	shlr16	r0
+-EX(	mov.w	r0, at r4		)
+-#endif
+-	bf/s	1b
+-	 add	#4,r4
+-
+-	bra	.L_cleanup
+-	 nop
+-
+-! Destination = 01 or 11
+-
+-.L_dest01:
+-.L_dest11:
+-	! Read longword, write byte, word, byte per iteration
+-EX(	mov.l	@r5+,r0		)
+-	dt	r2
+-#ifdef CONFIG_CPU_LITTLE_ENDIAN
+-EX(	mov.b	r0, at r4		)
+-	shlr8	r0
+-	add	#1,r4
+-EX(	mov.w	r0, at r4		)
+-	shlr16	r0
+-EX(	mov.b	r0,@(2,r4)	)
+-	bf/s	.L_dest01
+-	 add	#3,r4
+-#else
+-EX(	mov.b	r0,@(3,r4)	)
+-	shlr8	r0
+-	swap.w	r0,r7
+-EX(	mov.b	r7, at r4		)
+-	add	#1,r4
+-EX(	mov.w	r0, at r4		)
+-	bf/s	.L_dest01
+-	 add	#3,r4
+-#endif
+-
+-! Cleanup last few bytes
+-.L_cleanup:
+-	mov	r6,r0
+-	and	#3,r0
+-	tst	r0,r0
+-	bt	.L_exit
+-	mov	r0,r6
+-
+-.L_cleanup_loop:
+-EX(	mov.b	@r5+,r0		)
+-	dt	r6
+-EX(	mov.b	r0, at r4		)
+-	bf/s	.L_cleanup_loop
+-	 add	#1,r4
+-
+-.L_exit:
+-	mov	#0,r0		! normal return
+-
+-5000:
+-
+-# Exception handler:
+-.section .fixup, "ax"
+-6000:
+-	mov.l	8000f,r1
+-	mov	r3,r0
+-	jmp	@r1
+-	 sub	r4,r0
+-	.align	2
+-8000:	.long	5000b
+-
+-.previous
+-	mov.l	@r15+,r8
+-	mov.l	@r15+,r9
+-	mov.l	@r15+,r10
+-	rts
+-	 mov.l	@r15+,r11
+diff --git a/arch/sh/mm/extable.c b/arch/sh/mm/extable.c
+deleted file mode 100644
+index c1cf446..0000000
+--- a/arch/sh/mm/extable.c
++++ /dev/null
+@@ -1,21 +0,0 @@
+-/*
+- * linux/arch/sh/mm/extable.c
+- *  Taken from:
+- *   linux/arch/i386/mm/extable.c
+- */
+-
+-#include <linux/module.h>
+-#include <asm/uaccess.h>
+-
+-int fixup_exception(struct pt_regs *regs)
+-{
+-	const struct exception_table_entry *fixup;
+-
+-	fixup = search_exception_tables(regs->pc);
+-	if (fixup) {
+-		regs->pc = fixup->fixup;
+-		return 1;
+-	}
+-
+-	return 0;
+-}
+diff --git a/arch/sh/mm/extable_32.c b/arch/sh/mm/extable_32.c
+new file mode 100644
+index 0000000..c1cf446
+--- /dev/null
++++ b/arch/sh/mm/extable_32.c
+@@ -0,0 +1,21 @@
++/*
++ * linux/arch/sh/mm/extable.c
++ *  Taken from:
++ *   linux/arch/i386/mm/extable.c
++ */
++
++#include <linux/module.h>
++#include <asm/uaccess.h>
++
++int fixup_exception(struct pt_regs *regs)
++{
++	const struct exception_table_entry *fixup;
++
++	fixup = search_exception_tables(regs->pc);
++	if (fixup) {
++		regs->pc = fixup->fixup;
++		return 1;
++	}
++
++	return 0;
++}
+diff --git a/arch/sh/mm/extable_64.c b/arch/sh/mm/extable_64.c
+new file mode 100644
+index 0000000..f054996
+--- /dev/null
++++ b/arch/sh/mm/extable_64.c
+@@ -0,0 +1,82 @@
++/*
++ * arch/sh/mm/extable_64.c
++ *
++ * Copyright (C) 2003 Richard Curnow
++ * Copyright (C) 2003, 2004  Paul Mundt
++ *
++ * Cloned from the 2.5 SH version..
++ *
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License.  See the file "COPYING" in the main directory of this archive
++ * for more details.
++ */
++#include <linux/rwsem.h>
++#include <linux/module.h>
++#include <asm/uaccess.h>
++
++extern unsigned long copy_user_memcpy, copy_user_memcpy_end;
++extern void __copy_user_fixup(void);
++
++static const struct exception_table_entry __copy_user_fixup_ex = {
++	.fixup = (unsigned long)&__copy_user_fixup,
++};
++
++/*
++ * Some functions that may trap due to a bad user-mode address have too
++ * many loads and stores in them to make it at all practical to label
++ * each one and put them all in the main exception table.
++ *
++ * In particular, the fast memcpy routine is like this.  It's fix-up is
++ * just to fall back to a slow byte-at-a-time copy, which is handled the
++ * conventional way.  So it's functionally OK to just handle any trap
++ * occurring in the fast memcpy with that fixup.
++ */
++static const struct exception_table_entry *check_exception_ranges(unsigned long addr)
++{
++	if ((addr >= (unsigned long)&copy_user_memcpy) &&
++	    (addr <= (unsigned long)&copy_user_memcpy_end))
++		return &__copy_user_fixup_ex;
++
++	return NULL;
++}
++
++/* Simple binary search */
++const struct exception_table_entry *
++search_extable(const struct exception_table_entry *first,
++		 const struct exception_table_entry *last,
++		 unsigned long value)
++{
++	const struct exception_table_entry *mid;
++
++	mid = check_exception_ranges(value);
++	if (mid)
++		return mid;
++
++        while (first <= last) {
++		long diff;
++
++		mid = (last - first) / 2 + first;
++		diff = mid->insn - value;
++                if (diff == 0)
++                        return mid;
++                else if (diff < 0)
++                        first = mid+1;
++                else
++                        last = mid-1;
++        }
++
++        return NULL;
++}
++
++int fixup_exception(struct pt_regs *regs)
++{
++	const struct exception_table_entry *fixup;
++
++	fixup = search_exception_tables(regs->pc);
++	if (fixup) {
++		regs->pc = fixup->fixup;
++		return 1;
++	}
++
++	return 0;
++}
+diff --git a/arch/sh/mm/fault.c b/arch/sh/mm/fault.c
+deleted file mode 100644
+index 60d74f7..0000000
+--- a/arch/sh/mm/fault.c
++++ /dev/null
+@@ -1,303 +0,0 @@
+-/*
+- * Page fault handler for SH with an MMU.
+- *
+- *  Copyright (C) 1999  Niibe Yutaka
+- *  Copyright (C) 2003 - 2007  Paul Mundt
+- *
+- *  Based on linux/arch/i386/mm/fault.c:
+- *   Copyright (C) 1995  Linus Torvalds
+- *
+- * This file is subject to the terms and conditions of the GNU General Public
+- * License.  See the file "COPYING" in the main directory of this archive
+- * for more details.
+- */
+-#include <linux/kernel.h>
+-#include <linux/mm.h>
+-#include <linux/hardirq.h>
+-#include <linux/kprobes.h>
+-#include <asm/system.h>
+-#include <asm/mmu_context.h>
+-#include <asm/tlbflush.h>
+-#include <asm/kgdb.h>
+-
+-/*
+- * This routine handles page faults.  It determines the address,
+- * and the problem, and then passes it off to one of the appropriate
+- * routines.
+- */
+-asmlinkage void __kprobes do_page_fault(struct pt_regs *regs,
+-					unsigned long writeaccess,
+-					unsigned long address)
+-{
+-	struct task_struct *tsk;
+-	struct mm_struct *mm;
+-	struct vm_area_struct * vma;
+-	int si_code;
+-	int fault;
+-	siginfo_t info;
+-
+-	trace_hardirqs_on();
+-	local_irq_enable();
+-
+-#ifdef CONFIG_SH_KGDB
+-	if (kgdb_nofault && kgdb_bus_err_hook)
+-		kgdb_bus_err_hook();
+-#endif
+-
+-	tsk = current;
+-	mm = tsk->mm;
+-	si_code = SEGV_MAPERR;
+-
+-	if (unlikely(address >= TASK_SIZE)) {
+-		/*
+-		 * Synchronize this task's top level page-table
+-		 * with the 'reference' page table.
+-		 *
+-		 * Do _not_ use "tsk" here. We might be inside
+-		 * an interrupt in the middle of a task switch..
+-		 */
+-		int offset = pgd_index(address);
+-		pgd_t *pgd, *pgd_k;
+-		pud_t *pud, *pud_k;
+-		pmd_t *pmd, *pmd_k;
+-
+-		pgd = get_TTB() + offset;
+-		pgd_k = swapper_pg_dir + offset;
+-
+-		/* This will never happen with the folded page table. */
+-		if (!pgd_present(*pgd)) {
+-			if (!pgd_present(*pgd_k))
+-				goto bad_area_nosemaphore;
+-			set_pgd(pgd, *pgd_k);
+-			return;
+-		}
+-
+-		pud = pud_offset(pgd, address);
+-		pud_k = pud_offset(pgd_k, address);
+-		if (pud_present(*pud) || !pud_present(*pud_k))
+-			goto bad_area_nosemaphore;
+-		set_pud(pud, *pud_k);
+-
+-		pmd = pmd_offset(pud, address);
+-		pmd_k = pmd_offset(pud_k, address);
+-		if (pmd_present(*pmd) || !pmd_present(*pmd_k))
+-			goto bad_area_nosemaphore;
+-		set_pmd(pmd, *pmd_k);
+-
+-		return;
+-	}
+-
+-	/*
+-	 * If we're in an interrupt or have no user
+-	 * context, we must not take the fault..
+-	 */
+-	if (in_atomic() || !mm)
+-		goto no_context;
+-
+-	down_read(&mm->mmap_sem);
+-
+-	vma = find_vma(mm, address);
+-	if (!vma)
+-		goto bad_area;
+-	if (vma->vm_start <= address)
+-		goto good_area;
+-	if (!(vma->vm_flags & VM_GROWSDOWN))
+-		goto bad_area;
+-	if (expand_stack(vma, address))
+-		goto bad_area;
+-/*
+- * Ok, we have a good vm_area for this memory access, so
+- * we can handle it..
+- */
+-good_area:
+-	si_code = SEGV_ACCERR;
+-	if (writeaccess) {
+-		if (!(vma->vm_flags & VM_WRITE))
+-			goto bad_area;
+-	} else {
+-		if (!(vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE)))
+-			goto bad_area;
+-	}
+-
+-	/*
+-	 * If for any reason at all we couldn't handle the fault,
+-	 * make sure we exit gracefully rather than endlessly redo
+-	 * the fault.
+-	 */
+-survive:
+-	fault = handle_mm_fault(mm, vma, address, writeaccess);
+-	if (unlikely(fault & VM_FAULT_ERROR)) {
+-		if (fault & VM_FAULT_OOM)
+-			goto out_of_memory;
+-		else if (fault & VM_FAULT_SIGBUS)
+-			goto do_sigbus;
+-		BUG();
+-	}
+-	if (fault & VM_FAULT_MAJOR)
+-		tsk->maj_flt++;
+-	else
+-		tsk->min_flt++;
+-
+-	up_read(&mm->mmap_sem);
+-	return;
+-
+-/*
+- * Something tried to access memory that isn't in our memory map..
+- * Fix it, but check if it's kernel or user first..
+- */
+-bad_area:
+-	up_read(&mm->mmap_sem);
+-
+-bad_area_nosemaphore:
+-	if (user_mode(regs)) {
+-		info.si_signo = SIGSEGV;
+-		info.si_errno = 0;
+-		info.si_code = si_code;
+-		info.si_addr = (void *) address;
+-		force_sig_info(SIGSEGV, &info, tsk);
+-		return;
+-	}
+-
+-no_context:
+-	/* Are we prepared to handle this kernel fault?  */
+-	if (fixup_exception(regs))
+-		return;
+-
+-/*
+- * Oops. The kernel tried to access some bad page. We'll have to
+- * terminate things with extreme prejudice.
+- *
+- */
+-
+-	bust_spinlocks(1);
+-
+-	if (oops_may_print()) {
+-		__typeof__(pte_val(__pte(0))) page;
+-
+-		if (address < PAGE_SIZE)
+-			printk(KERN_ALERT "Unable to handle kernel NULL "
+-					  "pointer dereference");
+-		else
+-			printk(KERN_ALERT "Unable to handle kernel paging "
+-					  "request");
+-		printk(" at virtual address %08lx\n", address);
+-		printk(KERN_ALERT "pc = %08lx\n", regs->pc);
+-		page = (unsigned long)get_TTB();
+-		if (page) {
+-			page = ((__typeof__(page) *)page)[address >> PGDIR_SHIFT];
+-			printk(KERN_ALERT "*pde = %08lx\n", page);
+-			if (page & _PAGE_PRESENT) {
+-				page &= PAGE_MASK;
+-				address &= 0x003ff000;
+-				page = ((__typeof__(page) *)
+-						__va(page))[address >>
+-							    PAGE_SHIFT];
+-				printk(KERN_ALERT "*pte = %08lx\n", page);
+-			}
+-		}
+-	}
+-
+-	die("Oops", regs, writeaccess);
+-	bust_spinlocks(0);
+-	do_exit(SIGKILL);
+-
+-/*
+- * We ran out of memory, or some other thing happened to us that made
+- * us unable to handle the page fault gracefully.
+- */
+-out_of_memory:
+-	up_read(&mm->mmap_sem);
+-	if (is_global_init(current)) {
+-		yield();
+-		down_read(&mm->mmap_sem);
+-		goto survive;
+-	}
+-	printk("VM: killing process %s\n", tsk->comm);
+-	if (user_mode(regs))
+-		do_group_exit(SIGKILL);
+-	goto no_context;
+-
+-do_sigbus:
+-	up_read(&mm->mmap_sem);
+-
+-	/*
+-	 * Send a sigbus, regardless of whether we were in kernel
+-	 * or user mode.
+-	 */
+-	info.si_signo = SIGBUS;
+-	info.si_errno = 0;
+-	info.si_code = BUS_ADRERR;
+-	info.si_addr = (void *)address;
+-	force_sig_info(SIGBUS, &info, tsk);
+-
+-	/* Kernel mode? Handle exceptions or die */
+-	if (!user_mode(regs))
+-		goto no_context;
+-}
+-
+-#ifdef CONFIG_SH_STORE_QUEUES
+-/*
+- * This is a special case for the SH-4 store queues, as pages for this
+- * space still need to be faulted in before it's possible to flush the
+- * store queue cache for writeout to the remapped region.
+- */
+-#define P3_ADDR_MAX		(P4SEG_STORE_QUE + 0x04000000)
+-#else
+-#define P3_ADDR_MAX		P4SEG
+-#endif
+-
+-/*
+- * Called with interrupts disabled.
+- */
+-asmlinkage int __kprobes __do_page_fault(struct pt_regs *regs,
+-					 unsigned long writeaccess,
+-					 unsigned long address)
+-{
+-	pgd_t *pgd;
+-	pud_t *pud;
+-	pmd_t *pmd;
+-	pte_t *pte;
+-	pte_t entry;
+-
+-#ifdef CONFIG_SH_KGDB
+-	if (kgdb_nofault && kgdb_bus_err_hook)
+-		kgdb_bus_err_hook();
+-#endif
+-
+-	/*
+-	 * We don't take page faults for P1, P2, and parts of P4, these
+-	 * are always mapped, whether it be due to legacy behaviour in
+-	 * 29-bit mode, or due to PMB configuration in 32-bit mode.
+-	 */
+-	if (address >= P3SEG && address < P3_ADDR_MAX) {
+-		pgd = pgd_offset_k(address);
+-	} else {
+-		if (unlikely(address >= TASK_SIZE || !current->mm))
+-			return 1;
+-
+-		pgd = pgd_offset(current->mm, address);
+-	}
+-
+-	pud = pud_offset(pgd, address);
+-	if (pud_none_or_clear_bad(pud))
+-		return 1;
+-	pmd = pmd_offset(pud, address);
+-	if (pmd_none_or_clear_bad(pmd))
+-		return 1;
+-
+-	pte = pte_offset_kernel(pmd, address);
+-	entry = *pte;
+-	if (unlikely(pte_none(entry) || pte_not_present(entry)))
+-		return 1;
+-	if (unlikely(writeaccess && !pte_write(entry)))
+-		return 1;
+-
+-	if (writeaccess)
+-		entry = pte_mkdirty(entry);
+-	entry = pte_mkyoung(entry);
+-
+-	set_pte(pte, entry);
+-	update_mmu_cache(NULL, address, entry);
+-
+-	return 0;
+-}
+diff --git a/arch/sh/mm/fault_32.c b/arch/sh/mm/fault_32.c
+new file mode 100644
+index 0000000..33b43d2
+--- /dev/null
++++ b/arch/sh/mm/fault_32.c
+@@ -0,0 +1,303 @@
++/*
++ * Page fault handler for SH with an MMU.
++ *
++ *  Copyright (C) 1999  Niibe Yutaka
++ *  Copyright (C) 2003 - 2007  Paul Mundt
++ *
++ *  Based on linux/arch/i386/mm/fault.c:
++ *   Copyright (C) 1995  Linus Torvalds
++ *
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License.  See the file "COPYING" in the main directory of this archive
++ * for more details.
++ */
++#include <linux/kernel.h>
++#include <linux/mm.h>
++#include <linux/hardirq.h>
++#include <linux/kprobes.h>
++#include <asm/system.h>
++#include <asm/mmu_context.h>
++#include <asm/tlbflush.h>
++#include <asm/kgdb.h>
++
++/*
++ * This routine handles page faults.  It determines the address,
++ * and the problem, and then passes it off to one of the appropriate
++ * routines.
++ */
++asmlinkage void __kprobes do_page_fault(struct pt_regs *regs,
++					unsigned long writeaccess,
++					unsigned long address)
++{
++	struct task_struct *tsk;
++	struct mm_struct *mm;
++	struct vm_area_struct * vma;
++	int si_code;
++	int fault;
++	siginfo_t info;
++
++	trace_hardirqs_on();
++	local_irq_enable();
++
++#ifdef CONFIG_SH_KGDB
++	if (kgdb_nofault && kgdb_bus_err_hook)
++		kgdb_bus_err_hook();
++#endif
++
++	tsk = current;
++	mm = tsk->mm;
++	si_code = SEGV_MAPERR;
++
++	if (unlikely(address >= TASK_SIZE)) {
++		/*
++		 * Synchronize this task's top level page-table
++		 * with the 'reference' page table.
++		 *
++		 * Do _not_ use "tsk" here. We might be inside
++		 * an interrupt in the middle of a task switch..
++		 */
++		int offset = pgd_index(address);
++		pgd_t *pgd, *pgd_k;
++		pud_t *pud, *pud_k;
++		pmd_t *pmd, *pmd_k;
++
++		pgd = get_TTB() + offset;
++		pgd_k = swapper_pg_dir + offset;
++
++		/* This will never happen with the folded page table. */
++		if (!pgd_present(*pgd)) {
++			if (!pgd_present(*pgd_k))
++				goto bad_area_nosemaphore;
++			set_pgd(pgd, *pgd_k);
++			return;
++		}
++
++		pud = pud_offset(pgd, address);
++		pud_k = pud_offset(pgd_k, address);
++		if (pud_present(*pud) || !pud_present(*pud_k))
++			goto bad_area_nosemaphore;
++		set_pud(pud, *pud_k);
++
++		pmd = pmd_offset(pud, address);
++		pmd_k = pmd_offset(pud_k, address);
++		if (pmd_present(*pmd) || !pmd_present(*pmd_k))
++			goto bad_area_nosemaphore;
++		set_pmd(pmd, *pmd_k);
++
++		return;
++	}
++
++	/*
++	 * If we're in an interrupt or have no user
++	 * context, we must not take the fault..
++	 */
++	if (in_atomic() || !mm)
++		goto no_context;
++
++	down_read(&mm->mmap_sem);
++
++	vma = find_vma(mm, address);
++	if (!vma)
++		goto bad_area;
++	if (vma->vm_start <= address)
++		goto good_area;
++	if (!(vma->vm_flags & VM_GROWSDOWN))
++		goto bad_area;
++	if (expand_stack(vma, address))
++		goto bad_area;
++/*
++ * Ok, we have a good vm_area for this memory access, so
++ * we can handle it..
++ */
++good_area:
++	si_code = SEGV_ACCERR;
++	if (writeaccess) {
++		if (!(vma->vm_flags & VM_WRITE))
++			goto bad_area;
++	} else {
++		if (!(vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE)))
++			goto bad_area;
++	}
++
++	/*
++	 * If for any reason at all we couldn't handle the fault,
++	 * make sure we exit gracefully rather than endlessly redo
++	 * the fault.
++	 */
++survive:
++	fault = handle_mm_fault(mm, vma, address, writeaccess);
++	if (unlikely(fault & VM_FAULT_ERROR)) {
++		if (fault & VM_FAULT_OOM)
++			goto out_of_memory;
++		else if (fault & VM_FAULT_SIGBUS)
++			goto do_sigbus;
++		BUG();
++	}
++	if (fault & VM_FAULT_MAJOR)
++		tsk->maj_flt++;
++	else
++		tsk->min_flt++;
++
++	up_read(&mm->mmap_sem);
++	return;
++
++/*
++ * Something tried to access memory that isn't in our memory map..
++ * Fix it, but check if it's kernel or user first..
++ */
++bad_area:
++	up_read(&mm->mmap_sem);
++
++bad_area_nosemaphore:
++	if (user_mode(regs)) {
++		info.si_signo = SIGSEGV;
++		info.si_errno = 0;
++		info.si_code = si_code;
++		info.si_addr = (void *) address;
++		force_sig_info(SIGSEGV, &info, tsk);
++		return;
++	}
++
++no_context:
++	/* Are we prepared to handle this kernel fault?  */
++	if (fixup_exception(regs))
++		return;
++
++/*
++ * Oops. The kernel tried to access some bad page. We'll have to
++ * terminate things with extreme prejudice.
++ *
++ */
++
++	bust_spinlocks(1);
++
++	if (oops_may_print()) {
++		unsigned long page;
++
++		if (address < PAGE_SIZE)
++			printk(KERN_ALERT "Unable to handle kernel NULL "
++					  "pointer dereference");
++		else
++			printk(KERN_ALERT "Unable to handle kernel paging "
++					  "request");
++		printk(" at virtual address %08lx\n", address);
++		printk(KERN_ALERT "pc = %08lx\n", regs->pc);
++		page = (unsigned long)get_TTB();
++		if (page) {
++			page = ((__typeof__(page) *)page)[address >> PGDIR_SHIFT];
++			printk(KERN_ALERT "*pde = %08lx\n", page);
++			if (page & _PAGE_PRESENT) {
++				page &= PAGE_MASK;
++				address &= 0x003ff000;
++				page = ((__typeof__(page) *)
++						__va(page))[address >>
++							    PAGE_SHIFT];
++				printk(KERN_ALERT "*pte = %08lx\n", page);
++			}
++		}
++	}
++
++	die("Oops", regs, writeaccess);
++	bust_spinlocks(0);
++	do_exit(SIGKILL);
++
++/*
++ * We ran out of memory, or some other thing happened to us that made
++ * us unable to handle the page fault gracefully.
++ */
++out_of_memory:
++	up_read(&mm->mmap_sem);
++	if (is_global_init(current)) {
++		yield();
++		down_read(&mm->mmap_sem);
++		goto survive;
++	}
++	printk("VM: killing process %s\n", tsk->comm);
++	if (user_mode(regs))
++		do_group_exit(SIGKILL);
++	goto no_context;
++
++do_sigbus:
++	up_read(&mm->mmap_sem);
++
++	/*
++	 * Send a sigbus, regardless of whether we were in kernel
++	 * or user mode.
++	 */
++	info.si_signo = SIGBUS;
++	info.si_errno = 0;
++	info.si_code = BUS_ADRERR;
++	info.si_addr = (void *)address;
++	force_sig_info(SIGBUS, &info, tsk);
++
++	/* Kernel mode? Handle exceptions or die */
++	if (!user_mode(regs))
++		goto no_context;
++}
++
++#ifdef CONFIG_SH_STORE_QUEUES
++/*
++ * This is a special case for the SH-4 store queues, as pages for this
++ * space still need to be faulted in before it's possible to flush the
++ * store queue cache for writeout to the remapped region.
++ */
++#define P3_ADDR_MAX		(P4SEG_STORE_QUE + 0x04000000)
++#else
++#define P3_ADDR_MAX		P4SEG
++#endif
++
++/*
++ * Called with interrupts disabled.
++ */
++asmlinkage int __kprobes __do_page_fault(struct pt_regs *regs,
++					 unsigned long writeaccess,
++					 unsigned long address)
++{
++	pgd_t *pgd;
++	pud_t *pud;
++	pmd_t *pmd;
++	pte_t *pte;
++	pte_t entry;
++
++#ifdef CONFIG_SH_KGDB
++	if (kgdb_nofault && kgdb_bus_err_hook)
++		kgdb_bus_err_hook();
++#endif
++
++	/*
++	 * We don't take page faults for P1, P2, and parts of P4, these
++	 * are always mapped, whether it be due to legacy behaviour in
++	 * 29-bit mode, or due to PMB configuration in 32-bit mode.
++	 */
++	if (address >= P3SEG && address < P3_ADDR_MAX) {
++		pgd = pgd_offset_k(address);
++	} else {
++		if (unlikely(address >= TASK_SIZE || !current->mm))
++			return 1;
++
++		pgd = pgd_offset(current->mm, address);
++	}
++
++	pud = pud_offset(pgd, address);
++	if (pud_none_or_clear_bad(pud))
++		return 1;
++	pmd = pmd_offset(pud, address);
++	if (pmd_none_or_clear_bad(pmd))
++		return 1;
++
++	pte = pte_offset_kernel(pmd, address);
++	entry = *pte;
++	if (unlikely(pte_none(entry) || pte_not_present(entry)))
++		return 1;
++	if (unlikely(writeaccess && !pte_write(entry)))
++		return 1;
++
++	if (writeaccess)
++		entry = pte_mkdirty(entry);
++	entry = pte_mkyoung(entry);
++
++	set_pte(pte, entry);
++	update_mmu_cache(NULL, address, entry);
++
++	return 0;
++}
+diff --git a/arch/sh/mm/fault_64.c b/arch/sh/mm/fault_64.c
+new file mode 100644
+index 0000000..399d537
+--- /dev/null
++++ b/arch/sh/mm/fault_64.c
+@@ -0,0 +1,275 @@
++/*
++ * The SH64 TLB miss.
++ *
++ * Original code from fault.c
++ * Copyright (C) 2000, 2001  Paolo Alberelli
++ *
++ * Fast PTE->TLB refill path
++ * Copyright (C) 2003 Richard.Curnow at superh.com
++ *
++ * IMPORTANT NOTES :
++ * The do_fast_page_fault function is called from a context in entry.S
++ * where very few registers have been saved.  In particular, the code in
++ * this file must be compiled not to use ANY caller-save registers that
++ * are not part of the restricted save set.  Also, it means that code in
++ * this file must not make calls to functions elsewhere in the kernel, or
++ * else the excepting context will see corruption in its caller-save
++ * registers.  Plus, the entry.S save area is non-reentrant, so this code
++ * has to run with SR.BL==1, i.e. no interrupts taken inside it and panic
++ * on any exception.
++ *
++ * 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/signal.h>
++#include <linux/sched.h>
++#include <linux/kernel.h>
++#include <linux/errno.h>
++#include <linux/string.h>
++#include <linux/types.h>
++#include <linux/ptrace.h>
++#include <linux/mman.h>
++#include <linux/mm.h>
++#include <linux/smp.h>
++#include <linux/interrupt.h>
++#include <asm/system.h>
++#include <asm/tlb.h>
++#include <asm/io.h>
++#include <asm/uaccess.h>
++#include <asm/pgalloc.h>
++#include <asm/mmu_context.h>
++#include <asm/cpu/registers.h>
++
++/* Callable from fault.c, so not static */
++inline void __do_tlb_refill(unsigned long address,
++                            unsigned long long is_text_not_data, pte_t *pte)
++{
++	unsigned long long ptel;
++	unsigned long long pteh=0;
++	struct tlb_info *tlbp;
++	unsigned long long next;
++
++	/* Get PTEL first */
++	ptel = pte_val(*pte);
++
++	/*
++	 * Set PTEH register
++	 */
++	pteh = address & MMU_VPN_MASK;
++
++	/* Sign extend based on neff. */
++#if (NEFF == 32)
++	/* Faster sign extension */
++	pteh = (unsigned long long)(signed long long)(signed long)pteh;
++#else
++	/* General case */
++	pteh = (pteh & NEFF_SIGN) ? (pteh | NEFF_MASK) : pteh;
++#endif
++
++	/* Set the ASID. */
++	pteh |= get_asid() << PTEH_ASID_SHIFT;
++	pteh |= PTEH_VALID;
++
++	/* Set PTEL register, set_pte has performed the sign extension */
++	ptel &= _PAGE_FLAGS_HARDWARE_MASK; /* drop software flags */
++
++	tlbp = is_text_not_data ? &(cpu_data->itlb) : &(cpu_data->dtlb);
++	next = tlbp->next;
++	__flush_tlb_slot(next);
++	asm volatile ("putcfg %0,1,%2\n\n\t"
++		      "putcfg %0,0,%1\n"
++		      :  : "r" (next), "r" (pteh), "r" (ptel) );
++
++	next += TLB_STEP;
++	if (next > tlbp->last) next = tlbp->first;
++	tlbp->next = next;
++
++}
++
++static int handle_vmalloc_fault(struct mm_struct *mm,
++				unsigned long protection_flags,
++                                unsigned long long textaccess,
++				unsigned long address)
++{
++	pgd_t *dir;
++	pud_t *pud;
++	pmd_t *pmd;
++	static pte_t *pte;
++	pte_t entry;
++
++	dir = pgd_offset_k(address);
++
++	pud = pud_offset(dir, address);
++	if (pud_none_or_clear_bad(pud))
++		return 0;
++
++	pmd = pmd_offset(pud, address);
++	if (pmd_none_or_clear_bad(pmd))
++		return 0;
++
++	pte = pte_offset_kernel(pmd, address);
++	entry = *pte;
++
++	if (pte_none(entry) || !pte_present(entry))
++		return 0;
++	if ((pte_val(entry) & protection_flags) != protection_flags)
++		return 0;
++
++        __do_tlb_refill(address, textaccess, pte);
++
++	return 1;
++}
++
++static int handle_tlbmiss(struct mm_struct *mm,
++			  unsigned long long protection_flags,
++			  unsigned long long textaccess,
++			  unsigned long address)
++{
++	pgd_t *dir;
++	pud_t *pud;
++	pmd_t *pmd;
++	pte_t *pte;
++	pte_t entry;
++
++	/* NB. The PGD currently only contains a single entry - there is no
++	   page table tree stored for the top half of the address space since
++	   virtual pages in that region should never be mapped in user mode.
++	   (In kernel mode, the only things in that region are the 512Mb super
++	   page (locked in), and vmalloc (modules) +  I/O device pages (handled
++	   by handle_vmalloc_fault), so no PGD for the upper half is required
++	   by kernel mode either).
++
++	   See how mm->pgd is allocated and initialised in pgd_alloc to see why
++	   the next test is necessary.  - RPC */
++	if (address >= (unsigned long) TASK_SIZE)
++		/* upper half - never has page table entries. */
++		return 0;
++
++	dir = pgd_offset(mm, address);
++	if (pgd_none(*dir) || !pgd_present(*dir))
++		return 0;
++	if (!pgd_present(*dir))
++		return 0;
++
++	pud = pud_offset(dir, address);
++	if (pud_none(*pud) || !pud_present(*pud))
++		return 0;
++
++	pmd = pmd_offset(pud, address);
++	if (pmd_none(*pmd) || !pmd_present(*pmd))
++		return 0;
++
++	pte = pte_offset_kernel(pmd, address);
++	entry = *pte;
++
++	if (pte_none(entry) || !pte_present(entry))
++		return 0;
++
++	/*
++	 * If the page doesn't have sufficient protection bits set to
++	 * service the kind of fault being handled, there's not much
++	 * point doing the TLB refill.  Punt the fault to the general
++	 * handler.
++	 */
++	if ((pte_val(entry) & protection_flags) != protection_flags)
++		return 0;
++
++        __do_tlb_refill(address, textaccess, pte);
++
++	return 1;
++}
++
++/*
++ * Put all this information into one structure so that everything is just
++ * arithmetic relative to a single base address.  This reduces the number
++ * of movi/shori pairs needed just to load addresses of static data.
++ */
++struct expevt_lookup {
++	unsigned short protection_flags[8];
++	unsigned char  is_text_access[8];
++	unsigned char  is_write_access[8];
++};
++
++#define PRU (1<<9)
++#define PRW (1<<8)
++#define PRX (1<<7)
++#define PRR (1<<6)
++
++#define DIRTY (_PAGE_DIRTY | _PAGE_ACCESSED)
++#define YOUNG (_PAGE_ACCESSED)
++
++/* Sized as 8 rather than 4 to allow checking the PTE's PRU bit against whether
++   the fault happened in user mode or privileged mode. */
++static struct expevt_lookup expevt_lookup_table = {
++	.protection_flags = {PRX, PRX, 0, 0, PRR, PRR, PRW, PRW},
++	.is_text_access   = {1,   1,   0, 0, 0,   0,   0,   0}
++};
++
++/*
++   This routine handles page faults that can be serviced just by refilling a
++   TLB entry from an existing page table entry.  (This case represents a very
++   large majority of page faults.) Return 1 if the fault was successfully
++   handled.  Return 0 if the fault could not be handled.  (This leads into the
++   general fault handling in fault.c which deals with mapping file-backed
++   pages, stack growth, segmentation faults, swapping etc etc)
++ */
++asmlinkage int do_fast_page_fault(unsigned long long ssr_md,
++				  unsigned long long expevt,
++			          unsigned long address)
++{
++	struct task_struct *tsk;
++	struct mm_struct *mm;
++	unsigned long long textaccess;
++	unsigned long long protection_flags;
++	unsigned long long index;
++	unsigned long long expevt4;
++
++	/* The next few lines implement a way of hashing EXPEVT into a
++	 * small array index which can be used to lookup parameters
++	 * specific to the type of TLBMISS being handled.
++	 *
++	 * Note:
++	 *	ITLBMISS has EXPEVT==0xa40
++	 *	RTLBMISS has EXPEVT==0x040
++	 *	WTLBMISS has EXPEVT==0x060
++	 */
++	expevt4 = (expevt >> 4);
++	/* TODO : xor ssr_md into this expression too. Then we can check
++	 * that PRU is set when it needs to be. */
++	index = expevt4 ^ (expevt4 >> 5);
++	index &= 7;
++	protection_flags = expevt_lookup_table.protection_flags[index];
++	textaccess       = expevt_lookup_table.is_text_access[index];
++
++	/* SIM
++	 * Note this is now called with interrupts still disabled
++	 * This is to cope with being called for a missing IO port
++	 * address with interrupts disabled. This should be fixed as
++	 * soon as we have a better 'fast path' miss handler.
++	 *
++	 * Plus take care how you try and debug this stuff.
++	 * For example, writing debug data to a port which you
++	 * have just faulted on is not going to work.
++	 */
++
++	tsk = current;
++	mm = tsk->mm;
++
++	if ((address >= VMALLOC_START && address < VMALLOC_END) ||
++	    (address >= IOBASE_VADDR  && address < IOBASE_END)) {
++		if (ssr_md)
++			/*
++			 * Process-contexts can never have this address
++			 * range mapped
++			 */
++			if (handle_vmalloc_fault(mm, protection_flags,
++						 textaccess, address))
++				return 1;
++	} else if (!in_interrupt() && mm) {
++		if (handle_tlbmiss(mm, protection_flags, textaccess, address))
++			return 1;
++	}
++
++	return 0;
++}
+diff --git a/arch/sh/mm/init.c b/arch/sh/mm/init.c
+index d5e160d..2918c6b 100644
+--- a/arch/sh/mm/init.c
++++ b/arch/sh/mm/init.c
+@@ -23,9 +23,7 @@
+ 
+ DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
+ pgd_t swapper_pg_dir[PTRS_PER_PGD];
+-
+-void (*copy_page)(void *from, void *to);
+-void (*clear_page)(void *to);
++unsigned long cached_to_uncached = 0;
+ 
+ void show_mem(void)
+ {
+@@ -102,7 +100,8 @@ static void set_pte_phys(unsigned long addr, unsigned long phys, pgprot_t prot)
+ 
+ 	set_pte(pte, pfn_pte(phys >> PAGE_SHIFT, prot));
+ 
+-	flush_tlb_one(get_asid(), addr);
++	if (cached_to_uncached)
++		flush_tlb_one(get_asid(), addr);
+ }
+ 
+ /*
+@@ -131,6 +130,37 @@ void __set_fixmap(enum fixed_addresses idx, unsigned long phys, pgprot_t prot)
+ 
+ 	set_pte_phys(address, phys, prot);
+ }
++
++void __init page_table_range_init(unsigned long start, unsigned long end,
++					 pgd_t *pgd_base)
++{
++	pgd_t *pgd;
++	pud_t *pud;
++	pmd_t *pmd;
++	int pgd_idx;
++	unsigned long vaddr;
++
++	vaddr = start & PMD_MASK;
++	end = (end + PMD_SIZE - 1) & PMD_MASK;
++	pgd_idx = pgd_index(vaddr);
++	pgd = pgd_base + pgd_idx;
++
++	for ( ; (pgd_idx < PTRS_PER_PGD) && (vaddr != end); pgd++, pgd_idx++) {
++		BUG_ON(pgd_none(*pgd));
++		pud = pud_offset(pgd, 0);
++		BUG_ON(pud_none(*pud));
++		pmd = pmd_offset(pud, 0);
++
++		if (!pmd_present(*pmd)) {
++			pte_t *pte_table;
++			pte_table = (pte_t *)alloc_bootmem_low_pages(PAGE_SIZE);
++			memset(pte_table, 0, PAGE_SIZE);
++			pmd_populate_kernel(&init_mm, pmd, pte_table);
++		}
++
++		vaddr += PMD_SIZE;
++	}
++}
+ #endif	/* CONFIG_MMU */
+ 
+ /*
+@@ -150,6 +180,11 @@ void __init paging_init(void)
+ 	 * check for a null value. */
+ 	set_TTB(swapper_pg_dir);
+ 
++	/* Populate the relevant portions of swapper_pg_dir so that
++	 * we can use the fixmap entries without calling kmalloc.
++	 * pte's will be filled in by __set_fixmap(). */
++	page_table_range_init(FIXADDR_START, FIXADDR_TOP, swapper_pg_dir);
++
+ 	memset(max_zone_pfns, 0, sizeof(max_zone_pfns));
+ 
+ 	for_each_online_node(nid) {
+@@ -167,9 +202,22 @@ void __init paging_init(void)
+ 	}
+ 
+ 	free_area_init_nodes(max_zone_pfns);
++
++	/* Set up the uncached fixmap */
++	set_fixmap_nocache(FIX_UNCACHED, __pa(&__uncached_start));
++
++#ifdef CONFIG_29BIT
++	/*
++	 * Handle trivial transitions between cached and uncached
++	 * segments, making use of the 1:1 mapping relationship in
++	 * 512MB lowmem.
++	 */
++	cached_to_uncached = P2SEG - P1SEG;
++#endif
+ }
+ 
+ static struct kcore_list kcore_mem, kcore_vmalloc;
++int after_bootmem = 0;
+ 
+ void __init mem_init(void)
+ {
+@@ -202,17 +250,7 @@ void __init mem_init(void)
+ 	memset(empty_zero_page, 0, PAGE_SIZE);
+ 	__flush_wback_region(empty_zero_page, PAGE_SIZE);
+ 
+-	/*
+-	 * Setup wrappers for copy/clear_page(), these will get overridden
+-	 * later in the boot process if a better method is available.
+-	 */
+-#ifdef CONFIG_MMU
+-	copy_page = copy_page_slow;
+-	clear_page = clear_page_slow;
+-#else
+-	copy_page = copy_page_nommu;
+-	clear_page = clear_page_nommu;
+-#endif
++	after_bootmem = 1;
+ 
+ 	codesize =  (unsigned long) &_etext - (unsigned long) &_text;
+ 	datasize =  (unsigned long) &_edata - (unsigned long) &_etext;
+diff --git a/arch/sh/mm/ioremap.c b/arch/sh/mm/ioremap.c
+deleted file mode 100644
+index 0c7b7e3..0000000
+--- a/arch/sh/mm/ioremap.c
++++ /dev/null
+@@ -1,150 +0,0 @@
+-/*
+- * arch/sh/mm/ioremap.c
+- *
+- * Re-map IO memory to kernel address space so that we can access it.
+- * This is needed for high PCI addresses that aren't mapped in the
+- * 640k-1MB IO memory area on PC's
+- *
+- * (C) Copyright 1995 1996 Linus Torvalds
+- * (C) Copyright 2005, 2006 Paul Mundt
+- *
+- * This file is subject to the terms and conditions of the GNU General
+- * Public License. See the file "COPYING" in the main directory of this
+- * archive for more details.
+- */
+-#include <linux/vmalloc.h>
+-#include <linux/module.h>
+-#include <linux/mm.h>
+-#include <linux/pci.h>
+-#include <linux/io.h>
+-#include <asm/page.h>
+-#include <asm/pgalloc.h>
+-#include <asm/addrspace.h>
+-#include <asm/cacheflush.h>
+-#include <asm/tlbflush.h>
+-#include <asm/mmu.h>
+-
+-/*
+- * Remap an arbitrary physical address space into the kernel virtual
+- * address space. Needed when the kernel wants to access high addresses
+- * directly.
+- *
+- * NOTE! We need to allow non-page-aligned mappings too: we will obviously
+- * have to convert them into an offset in a page-aligned mapping, but the
+- * caller shouldn't need to know that small detail.
+- */
+-void __iomem *__ioremap(unsigned long phys_addr, unsigned long size,
+-			unsigned long flags)
+-{
+-	struct vm_struct * area;
+-	unsigned long offset, last_addr, addr, orig_addr;
+-	pgprot_t pgprot;
+-
+-	/* Don't allow wraparound or zero size */
+-	last_addr = phys_addr + size - 1;
+-	if (!size || last_addr < phys_addr)
+-		return NULL;
+-
+-	/*
+-	 * If we're on an SH7751 or SH7780 PCI controller, PCI memory is
+-	 * mapped at the end of the address space (typically 0xfd000000)
+-	 * in a non-translatable area, so mapping through page tables for
+-	 * this area is not only pointless, but also fundamentally
+-	 * broken. Just return the physical address instead.
+-	 *
+-	 * For boards that map a small PCI memory aperture somewhere in
+-	 * P1/P2 space, ioremap() will already do the right thing,
+-	 * and we'll never get this far.
+-	 */
+-	if (is_pci_memaddr(phys_addr) && is_pci_memaddr(last_addr))
+-		return (void __iomem *)phys_addr;
+-
+-	/*
+-	 * Don't allow anybody to remap normal RAM that we're using..
+-	 */
+-	if (phys_addr < virt_to_phys(high_memory))
+-		return NULL;
+-
+-	/*
+-	 * Mappings have to be page-aligned
+-	 */
+-	offset = phys_addr & ~PAGE_MASK;
+-	phys_addr &= PAGE_MASK;
+-	size = PAGE_ALIGN(last_addr+1) - phys_addr;
+-
+-	/*
+-	 * Ok, go for it..
+-	 */
+-	area = get_vm_area(size, VM_IOREMAP);
+-	if (!area)
+-		return NULL;
+-	area->phys_addr = phys_addr;
+-	orig_addr = addr = (unsigned long)area->addr;
+-
+-#ifdef CONFIG_32BIT
+-	/*
+-	 * First try to remap through the PMB once a valid VMA has been
+-	 * established. Smaller allocations (or the rest of the size
+-	 * remaining after a PMB mapping due to the size not being
+-	 * perfectly aligned on a PMB size boundary) are then mapped
+-	 * through the UTLB using conventional page tables.
+-	 *
+-	 * PMB entries are all pre-faulted.
+-	 */
+-	if (unlikely(size >= 0x1000000)) {
+-		unsigned long mapped = pmb_remap(addr, phys_addr, size, flags);
+-
+-		if (likely(mapped)) {
+-			addr		+= mapped;
+-			phys_addr	+= mapped;
+-			size		-= mapped;
+-		}
+-	}
+-#endif
+-
+-	pgprot = __pgprot(pgprot_val(PAGE_KERNEL_NOCACHE) | flags);
+-	if (likely(size))
+-		if (ioremap_page_range(addr, addr + size, phys_addr, pgprot)) {
+-			vunmap((void *)orig_addr);
+-			return NULL;
+-		}
+-
+-	return (void __iomem *)(offset + (char *)orig_addr);
+-}
+-EXPORT_SYMBOL(__ioremap);
+-
+-void __iounmap(void __iomem *addr)
+-{
+-	unsigned long vaddr = (unsigned long __force)addr;
+-	struct vm_struct *p;
+-
+-	if (PXSEG(vaddr) < P3SEG || is_pci_memaddr(vaddr))
+-		return;
+-
+-#ifdef CONFIG_32BIT
+-	/*
+-	 * Purge any PMB entries that may have been established for this
+-	 * mapping, then proceed with conventional VMA teardown.
+-	 *
+-	 * XXX: Note that due to the way that remove_vm_area() does
+-	 * matching of the resultant VMA, we aren't able to fast-forward
+-	 * the address past the PMB space until the end of the VMA where
+-	 * the page tables reside. As such, unmap_vm_area() will be
+-	 * forced to linearly scan over the area until it finds the page
+-	 * tables where PTEs that need to be unmapped actually reside,
+-	 * which is far from optimal. Perhaps we need to use a separate
+-	 * VMA for the PMB mappings?
+-	 *					-- PFM.
+-	 */
+-	pmb_unmap(vaddr);
+-#endif
+-
+-	p = remove_vm_area((void *)(vaddr & PAGE_MASK));
+-	if (!p) {
+-		printk(KERN_ERR "%s: bad address %p\n", __FUNCTION__, addr);
+-		return;
+-	}
+-
+-	kfree(p);
+-}
+-EXPORT_SYMBOL(__iounmap);
+diff --git a/arch/sh/mm/ioremap_32.c b/arch/sh/mm/ioremap_32.c
+new file mode 100644
+index 0000000..0c7b7e3
+--- /dev/null
++++ b/arch/sh/mm/ioremap_32.c
+@@ -0,0 +1,150 @@
++/*
++ * arch/sh/mm/ioremap.c
++ *
++ * Re-map IO memory to kernel address space so that we can access it.
++ * This is needed for high PCI addresses that aren't mapped in the
++ * 640k-1MB IO memory area on PC's
++ *
++ * (C) Copyright 1995 1996 Linus Torvalds
++ * (C) Copyright 2005, 2006 Paul Mundt
++ *
++ * This file is subject to the terms and conditions of the GNU General
++ * Public License. See the file "COPYING" in the main directory of this
++ * archive for more details.
++ */
++#include <linux/vmalloc.h>
++#include <linux/module.h>
++#include <linux/mm.h>
++#include <linux/pci.h>
++#include <linux/io.h>
++#include <asm/page.h>
++#include <asm/pgalloc.h>
++#include <asm/addrspace.h>
++#include <asm/cacheflush.h>
++#include <asm/tlbflush.h>
++#include <asm/mmu.h>
++
++/*
++ * Remap an arbitrary physical address space into the kernel virtual
++ * address space. Needed when the kernel wants to access high addresses
++ * directly.
++ *
++ * NOTE! We need to allow non-page-aligned mappings too: we will obviously
++ * have to convert them into an offset in a page-aligned mapping, but the
++ * caller shouldn't need to know that small detail.
++ */
++void __iomem *__ioremap(unsigned long phys_addr, unsigned long size,
++			unsigned long flags)
++{
++	struct vm_struct * area;
++	unsigned long offset, last_addr, addr, orig_addr;
++	pgprot_t pgprot;
++
++	/* Don't allow wraparound or zero size */
++	last_addr = phys_addr + size - 1;
++	if (!size || last_addr < phys_addr)
++		return NULL;
++
++	/*
++	 * If we're on an SH7751 or SH7780 PCI controller, PCI memory is
++	 * mapped at the end of the address space (typically 0xfd000000)
++	 * in a non-translatable area, so mapping through page tables for
++	 * this area is not only pointless, but also fundamentally
++	 * broken. Just return the physical address instead.
++	 *
++	 * For boards that map a small PCI memory aperture somewhere in
++	 * P1/P2 space, ioremap() will already do the right thing,
++	 * and we'll never get this far.
++	 */
++	if (is_pci_memaddr(phys_addr) && is_pci_memaddr(last_addr))
++		return (void __iomem *)phys_addr;
++
++	/*
++	 * Don't allow anybody to remap normal RAM that we're using..
++	 */
++	if (phys_addr < virt_to_phys(high_memory))
++		return NULL;
++
++	/*
++	 * Mappings have to be page-aligned
++	 */
++	offset = phys_addr & ~PAGE_MASK;
++	phys_addr &= PAGE_MASK;
++	size = PAGE_ALIGN(last_addr+1) - phys_addr;
++
++	/*
++	 * Ok, go for it..
++	 */
++	area = get_vm_area(size, VM_IOREMAP);
++	if (!area)
++		return NULL;
++	area->phys_addr = phys_addr;
++	orig_addr = addr = (unsigned long)area->addr;
++
++#ifdef CONFIG_32BIT
++	/*
++	 * First try to remap through the PMB once a valid VMA has been
++	 * established. Smaller allocations (or the rest of the size
++	 * remaining after a PMB mapping due to the size not being
++	 * perfectly aligned on a PMB size boundary) are then mapped
++	 * through the UTLB using conventional page tables.
++	 *
++	 * PMB entries are all pre-faulted.
++	 */
++	if (unlikely(size >= 0x1000000)) {
++		unsigned long mapped = pmb_remap(addr, phys_addr, size, flags);
++
++		if (likely(mapped)) {
++			addr		+= mapped;
++			phys_addr	+= mapped;
++			size		-= mapped;
++		}
++	}
++#endif
++
++	pgprot = __pgprot(pgprot_val(PAGE_KERNEL_NOCACHE) | flags);
++	if (likely(size))
++		if (ioremap_page_range(addr, addr + size, phys_addr, pgprot)) {
++			vunmap((void *)orig_addr);
++			return NULL;
++		}
++
++	return (void __iomem *)(offset + (char *)orig_addr);
++}
++EXPORT_SYMBOL(__ioremap);
++
++void __iounmap(void __iomem *addr)
++{
++	unsigned long vaddr = (unsigned long __force)addr;
++	struct vm_struct *p;
++
++	if (PXSEG(vaddr) < P3SEG || is_pci_memaddr(vaddr))
++		return;
++
++#ifdef CONFIG_32BIT
++	/*
++	 * Purge any PMB entries that may have been established for this
++	 * mapping, then proceed with conventional VMA teardown.
++	 *
++	 * XXX: Note that due to the way that remove_vm_area() does
++	 * matching of the resultant VMA, we aren't able to fast-forward
++	 * the address past the PMB space until the end of the VMA where
++	 * the page tables reside. As such, unmap_vm_area() will be
++	 * forced to linearly scan over the area until it finds the page
++	 * tables where PTEs that need to be unmapped actually reside,
++	 * which is far from optimal. Perhaps we need to use a separate
++	 * VMA for the PMB mappings?
++	 *					-- PFM.
++	 */
++	pmb_unmap(vaddr);
++#endif
++
++	p = remove_vm_area((void *)(vaddr & PAGE_MASK));
++	if (!p) {
++		printk(KERN_ERR "%s: bad address %p\n", __FUNCTION__, addr);
++		return;
++	}
++
++	kfree(p);
++}
++EXPORT_SYMBOL(__iounmap);
+diff --git a/arch/sh/mm/ioremap_64.c b/arch/sh/mm/ioremap_64.c
+new file mode 100644
+index 0000000..e27d165
+--- /dev/null
++++ b/arch/sh/mm/ioremap_64.c
+@@ -0,0 +1,404 @@
++/*
++ * arch/sh/mm/ioremap_64.c
++ *
++ * Copyright (C) 2000, 2001  Paolo Alberelli
++ * Copyright (C) 2003 - 2007  Paul Mundt
++ *
++ * Mostly derived from arch/sh/mm/ioremap.c which, in turn is mostly
++ * derived from arch/i386/mm/ioremap.c .
++ *
++ *   (C) Copyright 1995 1996 Linus Torvalds
++ *
++ * 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/vmalloc.h>
++#include <linux/ioport.h>
++#include <linux/module.h>
++#include <linux/mm.h>
++#include <linux/io.h>
++#include <linux/bootmem.h>
++#include <linux/proc_fs.h>
++#include <asm/page.h>
++#include <asm/pgalloc.h>
++#include <asm/addrspace.h>
++#include <asm/cacheflush.h>
++#include <asm/tlbflush.h>
++#include <asm/mmu.h>
++
++static void shmedia_mapioaddr(unsigned long, unsigned long);
++static unsigned long shmedia_ioremap(struct resource *, u32, int);
++
++/*
++ * Generic mapping function (not visible outside):
++ */
++
++/*
++ * Remap an arbitrary physical address space into the kernel virtual
++ * address space. Needed when the kernel wants to access high addresses
++ * directly.
++ *
++ * NOTE! We need to allow non-page-aligned mappings too: we will obviously
++ * have to convert them into an offset in a page-aligned mapping, but the
++ * caller shouldn't need to know that small detail.
++ */
++void *__ioremap(unsigned long phys_addr, unsigned long size,
++		unsigned long flags)
++{
++	void * addr;
++	struct vm_struct * area;
++	unsigned long offset, last_addr;
++	pgprot_t pgprot;
++
++	/* Don't allow wraparound or zero size */
++	last_addr = phys_addr + size - 1;
++	if (!size || last_addr < phys_addr)
++		return NULL;
++
++	pgprot = __pgprot(_PAGE_PRESENT  | _PAGE_READ   |
++			  _PAGE_WRITE    | _PAGE_DIRTY  |
++			  _PAGE_ACCESSED | _PAGE_SHARED | flags);
++
++	/*
++	 * Mappings have to be page-aligned
++	 */
++	offset = phys_addr & ~PAGE_MASK;
++	phys_addr &= PAGE_MASK;
++	size = PAGE_ALIGN(last_addr + 1) - phys_addr;
++
++	/*
++	 * Ok, go for it..
++	 */
++	area = get_vm_area(size, VM_IOREMAP);
++	pr_debug("Get vm_area returns %p addr %p\n",area,area->addr);
++	if (!area)
++		return NULL;
++	area->phys_addr = phys_addr;
++	addr = area->addr;
++	if (ioremap_page_range((unsigned long)addr, (unsigned long)addr + size,
++			       phys_addr, pgprot)) {
++		vunmap(addr);
++		return NULL;
++	}
++	return (void *) (offset + (char *)addr);
++}
++EXPORT_SYMBOL(__ioremap);
++
++void __iounmap(void *addr)
++{
++	struct vm_struct *area;
++
++	vfree((void *) (PAGE_MASK & (unsigned long) addr));
++	area = remove_vm_area((void *) (PAGE_MASK & (unsigned long) addr));
++	if (!area) {
++		printk(KERN_ERR "iounmap: bad address %p\n", addr);
++		return;
++	}
++
++	kfree(area);
++}
++EXPORT_SYMBOL(__iounmap);
++
++static struct resource shmedia_iomap = {
++	.name	= "shmedia_iomap",
++	.start	= IOBASE_VADDR + PAGE_SIZE,
++	.end	= IOBASE_END - 1,
++};
++
++static void shmedia_mapioaddr(unsigned long pa, unsigned long va);
++static void shmedia_unmapioaddr(unsigned long vaddr);
++static unsigned long shmedia_ioremap(struct resource *res, u32 pa, int sz);
++
++/*
++ * We have the same problem as the SPARC, so lets have the same comment:
++ * Our mini-allocator...
++ * Boy this is gross! We need it because we must map I/O for
++ * timers and interrupt controller before the kmalloc is available.
++ */
++
++#define XNMLN  15
++#define XNRES  10
++
++struct xresource {
++	struct resource xres;   /* Must be first */
++	int xflag;              /* 1 == used */
++	char xname[XNMLN+1];
++};
++
++static struct xresource xresv[XNRES];
++
++static struct xresource *xres_alloc(void)
++{
++        struct xresource *xrp;
++        int n;
++
++        xrp = xresv;
++        for (n = 0; n < XNRES; n++) {
++                if (xrp->xflag == 0) {
++                        xrp->xflag = 1;
++                        return xrp;
++                }
++                xrp++;
++        }
++        return NULL;
++}
++
++static void xres_free(struct xresource *xrp)
++{
++	xrp->xflag = 0;
++}
++
++static struct resource *shmedia_find_resource(struct resource *root,
++					      unsigned long vaddr)
++{
++	struct resource *res;
++
++	for (res = root->child; res; res = res->sibling)
++		if (res->start <= vaddr && res->end >= vaddr)
++			return res;
++
++	return NULL;
++}
++
++static unsigned long shmedia_alloc_io(unsigned long phys, unsigned long size,
++				      const char *name)
++{
++        static int printed_full = 0;
++        struct xresource *xres;
++        struct resource *res;
++        char *tack;
++        int tlen;
++
++        if (name == NULL) name = "???";
++
++        if ((xres = xres_alloc()) != 0) {
++                tack = xres->xname;
++                res = &xres->xres;
++        } else {
++                if (!printed_full) {
++                        printk("%s: done with statics, switching to kmalloc\n",
++			       __FUNCTION__);
++                        printed_full = 1;
++                }
++                tlen = strlen(name);
++                tack = kmalloc(sizeof (struct resource) + tlen + 1, GFP_KERNEL);
++                if (!tack)
++			return -ENOMEM;
++                memset(tack, 0, sizeof(struct resource));
++                res = (struct resource *) tack;
++                tack += sizeof (struct resource);
++        }
++
++        strncpy(tack, name, XNMLN);
++        tack[XNMLN] = 0;
++        res->name = tack;
++
++        return shmedia_ioremap(res, phys, size);
++}
++
++static unsigned long shmedia_ioremap(struct resource *res, u32 pa, int sz)
++{
++        unsigned long offset = ((unsigned long) pa) & (~PAGE_MASK);
++	unsigned long round_sz = (offset + sz + PAGE_SIZE-1) & PAGE_MASK;
++        unsigned long va;
++        unsigned int psz;
++
++        if (allocate_resource(&shmedia_iomap, res, round_sz,
++			      shmedia_iomap.start, shmedia_iomap.end,
++			      PAGE_SIZE, NULL, NULL) != 0) {
++                panic("alloc_io_res(%s): cannot occupy\n",
++                    (res->name != NULL)? res->name: "???");
++        }
++
++        va = res->start;
++        pa &= PAGE_MASK;
++
++	psz = (res->end - res->start + (PAGE_SIZE - 1)) / PAGE_SIZE;
++
++	/* log at boot time ... */
++	printk("mapioaddr: %6s  [%2d page%s]  va 0x%08lx   pa 0x%08x\n",
++	       ((res->name != NULL) ? res->name : "???"),
++	       psz, psz == 1 ? " " : "s", va, pa);
++
++        for (psz = res->end - res->start + 1; psz != 0; psz -= PAGE_SIZE) {
++                shmedia_mapioaddr(pa, va);
++                va += PAGE_SIZE;
++                pa += PAGE_SIZE;
++        }
++
++        res->start += offset;
++        res->end = res->start + sz - 1;         /* not strictly necessary.. */
++
++        return res->start;
++}
++
++static void shmedia_free_io(struct resource *res)
++{
++	unsigned long len = res->end - res->start + 1;
++
++	BUG_ON((len & (PAGE_SIZE - 1)) != 0);
++
++	while (len) {
++		len -= PAGE_SIZE;
++		shmedia_unmapioaddr(res->start + len);
++	}
++
++	release_resource(res);
++}
++
++static __init_refok void *sh64_get_page(void)
++{
++	extern int after_bootmem;
++	void *page;
++
++	if (after_bootmem) {
++		page = (void *)get_zeroed_page(GFP_ATOMIC);
++	} else {
++		page = alloc_bootmem_pages(PAGE_SIZE);
++	}
++
++	if (!page || ((unsigned long)page & ~PAGE_MASK))
++		panic("sh64_get_page: Out of memory already?\n");
++
++	return page;
++}
++
++static void shmedia_mapioaddr(unsigned long pa, unsigned long va)
++{
++	pgd_t *pgdp;
++	pud_t *pudp;
++	pmd_t *pmdp;
++	pte_t *ptep, pte;
++	pgprot_t prot;
++	unsigned long flags = 1; /* 1 = CB0-1 device */
++
++	pr_debug("shmedia_mapiopage pa %08lx va %08lx\n",  pa, va);
++
++	pgdp = pgd_offset_k(va);
++	if (pgd_none(*pgdp) || !pgd_present(*pgdp)) {
++		pudp = (pud_t *)sh64_get_page();
++		set_pgd(pgdp, __pgd((unsigned long)pudp | _KERNPG_TABLE));
++	}
++
++	pudp = pud_offset(pgdp, va);
++	if (pud_none(*pudp) || !pud_present(*pudp)) {
++		pmdp = (pmd_t *)sh64_get_page();
++		set_pud(pudp, __pud((unsigned long)pmdp | _KERNPG_TABLE));
++	}
++
++	pmdp = pmd_offset(pudp, va);
++	if (pmd_none(*pmdp) || !pmd_present(*pmdp) ) {
++		ptep = (pte_t *)sh64_get_page();
++		set_pmd(pmdp, __pmd((unsigned long)ptep + _PAGE_TABLE));
++	}
++
++	prot = __pgprot(_PAGE_PRESENT | _PAGE_READ     | _PAGE_WRITE  |
++			_PAGE_DIRTY   | _PAGE_ACCESSED | _PAGE_SHARED | flags);
++
++	pte = pfn_pte(pa >> PAGE_SHIFT, prot);
++	ptep = pte_offset_kernel(pmdp, va);
++
++	if (!pte_none(*ptep) &&
++	    pte_val(*ptep) != pte_val(pte))
++		pte_ERROR(*ptep);
++
++	set_pte(ptep, pte);
++
++	flush_tlb_kernel_range(va, PAGE_SIZE);
++}
++
++static void shmedia_unmapioaddr(unsigned long vaddr)
++{
++	pgd_t *pgdp;
++	pud_t *pudp;
++	pmd_t *pmdp;
++	pte_t *ptep;
++
++	pgdp = pgd_offset_k(vaddr);
++	if (pgd_none(*pgdp) || pgd_bad(*pgdp))
++		return;
++
++	pudp = pud_offset(pgdp, vaddr);
++	if (pud_none(*pudp) || pud_bad(*pudp))
++		return;
++
++	pmdp = pmd_offset(pudp, vaddr);
++	if (pmd_none(*pmdp) || pmd_bad(*pmdp))
++		return;
++
++	ptep = pte_offset_kernel(pmdp, vaddr);
++
++	if (pte_none(*ptep) || !pte_present(*ptep))
++		return;
++
++	clear_page((void *)ptep);
++	pte_clear(&init_mm, vaddr, ptep);
++}
++
++unsigned long onchip_remap(unsigned long phys, unsigned long size, const char *name)
++{
++	if (size < PAGE_SIZE)
++		size = PAGE_SIZE;
++
++	return shmedia_alloc_io(phys, size, name);
++}
++
++void onchip_unmap(unsigned long vaddr)
++{
++	struct resource *res;
++	unsigned int psz;
++
++	res = shmedia_find_resource(&shmedia_iomap, vaddr);
++	if (!res) {
++		printk(KERN_ERR "%s: Failed to free 0x%08lx\n",
++		       __FUNCTION__, vaddr);
++		return;
++	}
++
++        psz = (res->end - res->start + (PAGE_SIZE - 1)) / PAGE_SIZE;
++
++        printk(KERN_DEBUG "unmapioaddr: %6s  [%2d page%s] freed\n",
++	       res->name, psz, psz == 1 ? " " : "s");
++
++	shmedia_free_io(res);
++
++	if ((char *)res >= (char *)xresv &&
++	    (char *)res <  (char *)&xresv[XNRES]) {
++		xres_free((struct xresource *)res);
++	} else {
++		kfree(res);
++	}
++}
++
++#ifdef CONFIG_PROC_FS
++static int
++ioremap_proc_info(char *buf, char **start, off_t fpos, int length, int *eof,
++		  void *data)
++{
++	char *p = buf, *e = buf + length;
++	struct resource *r;
++	const char *nm;
++
++	for (r = ((struct resource *)data)->child; r != NULL; r = r->sibling) {
++		if (p + 32 >= e)        /* Better than nothing */
++			break;
++		if ((nm = r->name) == 0) nm = "???";
++		p += sprintf(p, "%08lx-%08lx: %s\n",
++			     (unsigned long)r->start,
++			     (unsigned long)r->end, nm);
++	}
++
++	return p-buf;
++}
++#endif /* CONFIG_PROC_FS */
++
++static int __init register_proc_onchip(void)
++{
++#ifdef CONFIG_PROC_FS
++	create_proc_read_entry("io_map",0,0, ioremap_proc_info, &shmedia_iomap);
++#endif
++	return 0;
++}
++
++__initcall(register_proc_onchip);
+diff --git a/arch/sh/mm/pg-nommu.c b/arch/sh/mm/pg-nommu.c
+index d15221b..677dd57 100644
+--- a/arch/sh/mm/pg-nommu.c
++++ b/arch/sh/mm/pg-nommu.c
+@@ -14,12 +14,12 @@
+ #include <linux/string.h>
+ #include <asm/page.h>
+ 
+-void copy_page_nommu(void *to, void *from)
++void copy_page(void *to, void *from)
+ {
+ 	memcpy(to, from, PAGE_SIZE);
+ }
+ 
+-void clear_page_nommu(void *to)
++void clear_page(void *to)
+ {
+ 	memset(to, 0, PAGE_SIZE);
+ }
+diff --git a/arch/sh/mm/pmb.c b/arch/sh/mm/pmb.c
+index 1d45b82..ab81c60 100644
+--- a/arch/sh/mm/pmb.c
++++ b/arch/sh/mm/pmb.c
+@@ -27,6 +27,7 @@
+ #include <asm/pgtable.h>
+ #include <asm/mmu.h>
+ #include <asm/io.h>
++#include <asm/mmu_context.h>
+ 
+ #define NR_PMB_ENTRIES	16
+ 
+@@ -162,18 +163,18 @@ repeat:
+ 	return 0;
+ }
+ 
+-int set_pmb_entry(struct pmb_entry *pmbe)
++int __uses_jump_to_uncached set_pmb_entry(struct pmb_entry *pmbe)
+ {
+ 	int ret;
+ 
+-	jump_to_P2();
++	jump_to_uncached();
+ 	ret = __set_pmb_entry(pmbe->vpn, pmbe->ppn, pmbe->flags, &pmbe->entry);
+-	back_to_P1();
++	back_to_cached();
+ 
+ 	return ret;
+ }
+ 
+-void clear_pmb_entry(struct pmb_entry *pmbe)
++void __uses_jump_to_uncached clear_pmb_entry(struct pmb_entry *pmbe)
+ {
+ 	unsigned int entry = pmbe->entry;
+ 	unsigned long addr;
+@@ -187,7 +188,7 @@ void clear_pmb_entry(struct pmb_entry *pmbe)
+ 		     entry >= NR_PMB_ENTRIES))
+ 		return;
+ 
+-	jump_to_P2();
++	jump_to_uncached();
+ 
+ 	/* Clear V-bit */
+ 	addr = mk_pmb_addr(entry);
+@@ -196,7 +197,7 @@ void clear_pmb_entry(struct pmb_entry *pmbe)
+ 	addr = mk_pmb_data(entry);
+ 	ctrl_outl(ctrl_inl(addr) & ~PMB_V, addr);
+ 
+-	back_to_P1();
++	back_to_cached();
+ 
+ 	clear_bit(entry, &pmb_map);
+ }
+@@ -301,17 +302,17 @@ static void pmb_cache_ctor(struct kmem_cache *cachep, void *pmb)
+ 	pmbe->entry = PMB_NO_ENTRY;
+ }
+ 
+-static int __init pmb_init(void)
++static int __uses_jump_to_uncached pmb_init(void)
+ {
+ 	unsigned int nr_entries = ARRAY_SIZE(pmb_init_map);
+-	unsigned int entry;
++	unsigned int entry, i;
+ 
+ 	BUG_ON(unlikely(nr_entries >= NR_PMB_ENTRIES));
+ 
+ 	pmb_cache = kmem_cache_create("pmb", sizeof(struct pmb_entry), 0,
+ 				      SLAB_PANIC, pmb_cache_ctor);
+ 
+-	jump_to_P2();
++	jump_to_uncached();
+ 
+ 	/*
+ 	 * Ordering is important, P2 must be mapped in the PMB before we
+@@ -329,7 +330,12 @@ static int __init pmb_init(void)
+ 	/* PMB.SE and UB[7] */
+ 	ctrl_outl((1 << 31) | (1 << 7), PMB_PASCR);
+ 
+-	back_to_P1();
++	/* Flush out the TLB */
++	i =  ctrl_inl(MMUCR);
++	i |= MMUCR_TI;
++	ctrl_outl(i, MMUCR);
++
++	back_to_cached();
+ 
+ 	return 0;
+ }
+diff --git a/arch/sh/mm/tlb-flush.c b/arch/sh/mm/tlb-flush.c
+deleted file mode 100644
+index 6f45c1f..0000000
+--- a/arch/sh/mm/tlb-flush.c
++++ /dev/null
+@@ -1,140 +0,0 @@
+-/*
+- * TLB flushing operations for SH with an MMU.
+- *
+- *  Copyright (C) 1999  Niibe Yutaka
+- *  Copyright (C) 2003  Paul Mundt
+- *
+- * This file is subject to the terms and conditions of the GNU General Public
+- * License.  See the file "COPYING" in the main directory of this archive
+- * for more details.
+- */
+-#include <linux/mm.h>
+-#include <asm/mmu_context.h>
+-#include <asm/tlbflush.h>
+-
+-void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
+-{
+-	unsigned int cpu = smp_processor_id();
+-
+-	if (vma->vm_mm && cpu_context(cpu, vma->vm_mm) != NO_CONTEXT) {
+-		unsigned long flags;
+-		unsigned long asid;
+-		unsigned long saved_asid = MMU_NO_ASID;
+-
+-		asid = cpu_asid(cpu, vma->vm_mm);
+-		page &= PAGE_MASK;
+-
+-		local_irq_save(flags);
+-		if (vma->vm_mm != current->mm) {
+-			saved_asid = get_asid();
+-			set_asid(asid);
+-		}
+-		local_flush_tlb_one(asid, page);
+-		if (saved_asid != MMU_NO_ASID)
+-			set_asid(saved_asid);
+-		local_irq_restore(flags);
+-	}
+-}
+-
+-void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
+-			   unsigned long end)
+-{
+-	struct mm_struct *mm = vma->vm_mm;
+-	unsigned int cpu = smp_processor_id();
+-
+-	if (cpu_context(cpu, mm) != NO_CONTEXT) {
+-		unsigned long flags;
+-		int size;
+-
+-		local_irq_save(flags);
+-		size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
+-		if (size > (MMU_NTLB_ENTRIES/4)) { /* Too many TLB to flush */
+-			cpu_context(cpu, mm) = NO_CONTEXT;
+-			if (mm == current->mm)
+-				activate_context(mm, cpu);
+-		} else {
+-			unsigned long asid;
+-			unsigned long saved_asid = MMU_NO_ASID;
+-
+-			asid = cpu_asid(cpu, mm);
+-			start &= PAGE_MASK;
+-			end += (PAGE_SIZE - 1);
+-			end &= PAGE_MASK;
+-			if (mm != current->mm) {
+-				saved_asid = get_asid();
+-				set_asid(asid);
+-			}
+-			while (start < end) {
+-				local_flush_tlb_one(asid, start);
+-				start += PAGE_SIZE;
+-			}
+-			if (saved_asid != MMU_NO_ASID)
+-				set_asid(saved_asid);
+-		}
+-		local_irq_restore(flags);
+-	}
+-}
+-
+-void local_flush_tlb_kernel_range(unsigned long start, unsigned long end)
+-{
+-	unsigned int cpu = smp_processor_id();
+-	unsigned long flags;
+-	int size;
+-
+-	local_irq_save(flags);
+-	size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
+-	if (size > (MMU_NTLB_ENTRIES/4)) { /* Too many TLB to flush */
+-		local_flush_tlb_all();
+-	} else {
+-		unsigned long asid;
+-		unsigned long saved_asid = get_asid();
+-
+-		asid = cpu_asid(cpu, &init_mm);
+-		start &= PAGE_MASK;
+-		end += (PAGE_SIZE - 1);
+-		end &= PAGE_MASK;
+-		set_asid(asid);
+-		while (start < end) {
+-			local_flush_tlb_one(asid, start);
+-			start += PAGE_SIZE;
+-		}
+-		set_asid(saved_asid);
+-	}
+-	local_irq_restore(flags);
+-}
+-
+-void local_flush_tlb_mm(struct mm_struct *mm)
+-{
+-	unsigned int cpu = smp_processor_id();
+-
+-	/* Invalidate all TLB of this process. */
+-	/* Instead of invalidating each TLB, we get new MMU context. */
+-	if (cpu_context(cpu, mm) != NO_CONTEXT) {
+-		unsigned long flags;
+-
+-		local_irq_save(flags);
+-		cpu_context(cpu, mm) = NO_CONTEXT;
+-		if (mm == current->mm)
+-			activate_context(mm, cpu);
+-		local_irq_restore(flags);
+-	}
+-}
+-
+-void local_flush_tlb_all(void)
+-{
+-	unsigned long flags, status;
+-
+-	/*
+-	 * Flush all the TLB.
+-	 *
+-	 * Write to the MMU control register's bit:
+-	 *	TF-bit for SH-3, TI-bit for SH-4.
+-	 *      It's same position, bit #2.
+-	 */
+-	local_irq_save(flags);
+-	status = ctrl_inl(MMUCR);
+-	status |= 0x04;
+-	ctrl_outl(status, MMUCR);
+-	ctrl_barrier();
+-	local_irq_restore(flags);
+-}
+diff --git a/arch/sh/mm/tlb-nommu.c b/arch/sh/mm/tlb-nommu.c
+index 1ccca7c..15111bc 100644
+--- a/arch/sh/mm/tlb-nommu.c
++++ b/arch/sh/mm/tlb-nommu.c
+@@ -9,6 +9,7 @@
+  */
+ #include <linux/kernel.h>
+ #include <linux/mm.h>
++#include <asm/pgtable.h>
+ 
+ /*
+  * Nothing too terribly exciting here ..
+@@ -49,3 +50,12 @@ void update_mmu_cache(struct vm_area_struct * vma,
+ {
+ 	BUG();
+ }
++
++void __init page_table_range_init(unsigned long start, unsigned long end,
++				  pgd_t *pgd_base)
++{
++}
++
++void __set_fixmap(enum fixed_addresses idx, unsigned long phys, pgprot_t prot)
++{
++}
+diff --git a/arch/sh/mm/tlb-sh4.c b/arch/sh/mm/tlb-sh4.c
+index 2d1dd60..f0c7b73 100644
+--- a/arch/sh/mm/tlb-sh4.c
++++ b/arch/sh/mm/tlb-sh4.c
+@@ -79,7 +79,8 @@ void update_mmu_cache(struct vm_area_struct * vma,
+ 	local_irq_restore(flags);
+ }
+ 
+-void local_flush_tlb_one(unsigned long asid, unsigned long page)
++void __uses_jump_to_uncached local_flush_tlb_one(unsigned long asid,
++						 unsigned long page)
+ {
+ 	unsigned long addr, data;
+ 
+@@ -91,7 +92,7 @@ void local_flush_tlb_one(unsigned long asid, unsigned long page)
+ 	 */
+ 	addr = MMU_UTLB_ADDRESS_ARRAY | MMU_PAGE_ASSOC_BIT;
+ 	data = page | asid; /* VALID bit is off */
+-	jump_to_P2();
++	jump_to_uncached();
+ 	ctrl_outl(data, addr);
+-	back_to_P1();
++	back_to_cached();
+ }
+diff --git a/arch/sh/mm/tlb-sh5.c b/arch/sh/mm/tlb-sh5.c
+new file mode 100644
+index 0000000..f34274a
+--- /dev/null
++++ b/arch/sh/mm/tlb-sh5.c
+@@ -0,0 +1,164 @@
++/*
++ * arch/sh/mm/tlb-sh5.c
++ *
++ * Copyright (C) 2003  Paul Mundt <lethal at linux-sh.org>
++ * Copyright (C) 2003  Richard Curnow <richard.curnow at superh.com>
++ *
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License.  See the file "COPYING" in the main directory of this archive
++ * for more details.
++ */
++#include <linux/mm.h>
++#include <linux/init.h>
++#include <asm/page.h>
++#include <asm/tlb.h>
++#include <asm/mmu_context.h>
++
++/**
++ * sh64_tlb_init
++ *
++ * Perform initial setup for the DTLB and ITLB.
++ */
++int __init sh64_tlb_init(void)
++{
++	/* Assign some sane DTLB defaults */
++	cpu_data->dtlb.entries	= 64;
++	cpu_data->dtlb.step	= 0x10;
++
++	cpu_data->dtlb.first	= DTLB_FIXED | cpu_data->dtlb.step;
++	cpu_data->dtlb.next	= cpu_data->dtlb.first;
++
++	cpu_data->dtlb.last	= DTLB_FIXED |
++				  ((cpu_data->dtlb.entries - 1) *
++				   cpu_data->dtlb.step);
++
++	/* And again for the ITLB */
++	cpu_data->itlb.entries	= 64;
++	cpu_data->itlb.step	= 0x10;
++
++	cpu_data->itlb.first	= ITLB_FIXED | cpu_data->itlb.step;
++	cpu_data->itlb.next	= cpu_data->itlb.first;
++	cpu_data->itlb.last	= ITLB_FIXED |
++				  ((cpu_data->itlb.entries - 1) *
++				   cpu_data->itlb.step);
++
++	return 0;
++}
++
++/**
++ * sh64_next_free_dtlb_entry
++ *
++ * Find the next available DTLB entry
++ */
++unsigned long long sh64_next_free_dtlb_entry(void)
++{
++	return cpu_data->dtlb.next;
++}
++
++/**
++ * sh64_get_wired_dtlb_entry
++ *
++ * Allocate a wired (locked-in) entry in the DTLB
++ */
++unsigned long long sh64_get_wired_dtlb_entry(void)
++{
++	unsigned long long entry = sh64_next_free_dtlb_entry();
++
++	cpu_data->dtlb.first += cpu_data->dtlb.step;
++	cpu_data->dtlb.next  += cpu_data->dtlb.step;
++
++	return entry;
++}
++
++/**
++ * sh64_put_wired_dtlb_entry
++ *
++ * @entry:	Address of TLB slot.
++ *
++ * Free a wired (locked-in) entry in the DTLB.
++ *
++ * Works like a stack, last one to allocate must be first one to free.
++ */
++int sh64_put_wired_dtlb_entry(unsigned long long entry)
++{
++	__flush_tlb_slot(entry);
++
++	/*
++	 * We don't do any particularly useful tracking of wired entries,
++	 * so this approach works like a stack .. last one to be allocated
++	 * has to be the first one to be freed.
++	 *
++	 * We could potentially load wired entries into a list and work on
++	 * rebalancing the list periodically (which also entails moving the
++	 * contents of a TLB entry) .. though I have a feeling that this is
++	 * more trouble than it's worth.
++	 */
++
++	/*
++	 * Entry must be valid .. we don't want any ITLB addresses!
++	 */
++	if (entry <= DTLB_FIXED)
++		return -EINVAL;
++
++	/*
++	 * Next, check if we're within range to be freed. (ie, must be the
++	 * entry beneath the first 'free' entry!
++	 */
++	if (entry < (cpu_data->dtlb.first - cpu_data->dtlb.step))
++		return -EINVAL;
++
++	/* If we are, then bring this entry back into the list */
++	cpu_data->dtlb.first	-= cpu_data->dtlb.step;
++	cpu_data->dtlb.next	= entry;
++
++	return 0;
++}
++
++/**
++ * sh64_setup_tlb_slot
++ *
++ * @config_addr:	Address of TLB slot.
++ * @eaddr:		Virtual address.
++ * @asid:		Address Space Identifier.
++ * @paddr:		Physical address.
++ *
++ * Load up a virtual<->physical translation for @eaddr<->@paddr in the
++ * pre-allocated TLB slot @config_addr (see sh64_get_wired_dtlb_entry).
++ */
++inline void sh64_setup_tlb_slot(unsigned long long config_addr,
++				unsigned long eaddr,
++				unsigned long asid,
++				unsigned long paddr)
++{
++	unsigned long long pteh, ptel;
++
++	/* Sign extension */
++#if (NEFF == 32)
++	pteh = (unsigned long long)(signed long long)(signed long) eaddr;
++#else
++#error "Can't sign extend more than 32 bits yet"
++#endif
++	pteh &= PAGE_MASK;
++	pteh |= (asid << PTEH_ASID_SHIFT) | PTEH_VALID;
++#if (NEFF == 32)
++	ptel = (unsigned long long)(signed long long)(signed long) paddr;
++#else
++#error "Can't sign extend more than 32 bits yet"
++#endif
++	ptel &= PAGE_MASK;
++	ptel |= (_PAGE_CACHABLE | _PAGE_READ | _PAGE_WRITE);
++
++	asm volatile("putcfg %0, 1, %1\n\t"
++			"putcfg %0, 0, %2\n"
++			: : "r" (config_addr), "r" (ptel), "r" (pteh));
++}
++
++/**
++ * sh64_teardown_tlb_slot
++ *
++ * @config_addr:	Address of TLB slot.
++ *
++ * Teardown any existing mapping in the TLB slot @config_addr.
++ */
++inline void sh64_teardown_tlb_slot(unsigned long long config_addr)
++	__attribute__ ((alias("__flush_tlb_slot")));
+diff --git a/arch/sh/mm/tlbflush_32.c b/arch/sh/mm/tlbflush_32.c
+new file mode 100644
+index 0000000..6f45c1f
+--- /dev/null
++++ b/arch/sh/mm/tlbflush_32.c
+@@ -0,0 +1,140 @@
++/*
++ * TLB flushing operations for SH with an MMU.
++ *
++ *  Copyright (C) 1999  Niibe Yutaka
++ *  Copyright (C) 2003  Paul Mundt
++ *
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License.  See the file "COPYING" in the main directory of this archive
++ * for more details.
++ */
++#include <linux/mm.h>
++#include <asm/mmu_context.h>
++#include <asm/tlbflush.h>
++
++void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
++{
++	unsigned int cpu = smp_processor_id();
++
++	if (vma->vm_mm && cpu_context(cpu, vma->vm_mm) != NO_CONTEXT) {
++		unsigned long flags;
++		unsigned long asid;
++		unsigned long saved_asid = MMU_NO_ASID;
++
++		asid = cpu_asid(cpu, vma->vm_mm);
++		page &= PAGE_MASK;
++
++		local_irq_save(flags);
++		if (vma->vm_mm != current->mm) {
++			saved_asid = get_asid();
++			set_asid(asid);
++		}
++		local_flush_tlb_one(asid, page);
++		if (saved_asid != MMU_NO_ASID)
++			set_asid(saved_asid);
++		local_irq_restore(flags);
++	}
++}
++
++void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
++			   unsigned long end)
++{
++	struct mm_struct *mm = vma->vm_mm;
++	unsigned int cpu = smp_processor_id();
++
++	if (cpu_context(cpu, mm) != NO_CONTEXT) {
++		unsigned long flags;
++		int size;
++
++		local_irq_save(flags);
++		size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
++		if (size > (MMU_NTLB_ENTRIES/4)) { /* Too many TLB to flush */
++			cpu_context(cpu, mm) = NO_CONTEXT;
++			if (mm == current->mm)
++				activate_context(mm, cpu);
++		} else {
++			unsigned long asid;
++			unsigned long saved_asid = MMU_NO_ASID;
++
++			asid = cpu_asid(cpu, mm);
++			start &= PAGE_MASK;
++			end += (PAGE_SIZE - 1);
++			end &= PAGE_MASK;
++			if (mm != current->mm) {
++				saved_asid = get_asid();
++				set_asid(asid);
++			}
++			while (start < end) {
++				local_flush_tlb_one(asid, start);
++				start += PAGE_SIZE;
++			}
++			if (saved_asid != MMU_NO_ASID)
++				set_asid(saved_asid);
++		}
++		local_irq_restore(flags);
++	}
++}
++
++void local_flush_tlb_kernel_range(unsigned long start, unsigned long end)
++{
++	unsigned int cpu = smp_processor_id();
++	unsigned long flags;
++	int size;
++
++	local_irq_save(flags);
++	size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
++	if (size > (MMU_NTLB_ENTRIES/4)) { /* Too many TLB to flush */
++		local_flush_tlb_all();
++	} else {
++		unsigned long asid;
++		unsigned long saved_asid = get_asid();
++
++		asid = cpu_asid(cpu, &init_mm);
++		start &= PAGE_MASK;
++		end += (PAGE_SIZE - 1);
++		end &= PAGE_MASK;
++		set_asid(asid);
++		while (start < end) {
++			local_flush_tlb_one(asid, start);
++			start += PAGE_SIZE;
++		}
++		set_asid(saved_asid);
++	}
++	local_irq_restore(flags);
++}
++
++void local_flush_tlb_mm(struct mm_struct *mm)
++{
++	unsigned int cpu = smp_processor_id();
++
++	/* Invalidate all TLB of this process. */
++	/* Instead of invalidating each TLB, we get new MMU context. */
++	if (cpu_context(cpu, mm) != NO_CONTEXT) {
++		unsigned long flags;
++
++		local_irq_save(flags);
++		cpu_context(cpu, mm) = NO_CONTEXT;
++		if (mm == current->mm)
++			activate_context(mm, cpu);
++		local_irq_restore(flags);
++	}
++}
++
++void local_flush_tlb_all(void)
++{
++	unsigned long flags, status;
++
++	/*
++	 * Flush all the TLB.
++	 *
++	 * Write to the MMU control register's bit:
++	 *	TF-bit for SH-3, TI-bit for SH-4.
++	 *      It's same position, bit #2.
++	 */
++	local_irq_save(flags);
++	status = ctrl_inl(MMUCR);
++	status |= 0x04;
++	ctrl_outl(status, MMUCR);
++	ctrl_barrier();
++	local_irq_restore(flags);
++}
+diff --git a/arch/sh/mm/tlbflush_64.c b/arch/sh/mm/tlbflush_64.c
+new file mode 100644
+index 0000000..2a98c9e
+--- /dev/null
++++ b/arch/sh/mm/tlbflush_64.c
+@@ -0,0 +1,475 @@
++/*
++ * arch/sh/mm/tlb-flush_64.c
++ *
++ * Copyright (C) 2000, 2001  Paolo Alberelli
++ * Copyright (C) 2003  Richard Curnow (/proc/tlb, bug fixes)
++ * Copyright (C) 2003  Paul Mundt
++ *
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License.  See the file "COPYING" in the main directory of this archive
++ * for more details.
++ */
++#include <linux/signal.h>
++#include <linux/rwsem.h>
++#include <linux/sched.h>
++#include <linux/kernel.h>
++#include <linux/errno.h>
++#include <linux/string.h>
++#include <linux/types.h>
++#include <linux/ptrace.h>
++#include <linux/mman.h>
++#include <linux/mm.h>
++#include <linux/smp.h>
++#include <linux/interrupt.h>
++#include <asm/system.h>
++#include <asm/io.h>
++#include <asm/tlb.h>
++#include <asm/uaccess.h>
++#include <asm/pgalloc.h>
++#include <asm/mmu_context.h>
++
++extern void die(const char *,struct pt_regs *,long);
++
++#define PFLAG(val,flag)   (( (val) & (flag) ) ? #flag : "" )
++#define PPROT(flag) PFLAG(pgprot_val(prot),flag)
++
++static inline void print_prots(pgprot_t prot)
++{
++	printk("prot is 0x%08lx\n",pgprot_val(prot));
++
++	printk("%s %s %s %s %s\n",PPROT(_PAGE_SHARED),PPROT(_PAGE_READ),
++	       PPROT(_PAGE_EXECUTE),PPROT(_PAGE_WRITE),PPROT(_PAGE_USER));
++}
++
++static inline void print_vma(struct vm_area_struct *vma)
++{
++	printk("vma start 0x%08lx\n", vma->vm_start);
++	printk("vma end   0x%08lx\n", vma->vm_end);
++
++	print_prots(vma->vm_page_prot);
++	printk("vm_flags 0x%08lx\n", vma->vm_flags);
++}
++
++static inline void print_task(struct task_struct *tsk)
++{
++	printk("Task pid %d\n", task_pid_nr(tsk));
++}
++
++static pte_t *lookup_pte(struct mm_struct *mm, unsigned long address)
++{
++	pgd_t *dir;
++	pud_t *pud;
++	pmd_t *pmd;
++	pte_t *pte;
++	pte_t entry;
++
++	dir = pgd_offset(mm, address);
++	if (pgd_none(*dir))
++		return NULL;
++
++	pud = pud_offset(dir, address);
++	if (pud_none(*pud))
++		return NULL;
++
++	pmd = pmd_offset(pud, address);
++	if (pmd_none(*pmd))
++		return NULL;
++
++	pte = pte_offset_kernel(pmd, address);
++	entry = *pte;
++	if (pte_none(entry) || !pte_present(entry))
++		return NULL;
++
++	return pte;
++}
++
++/*
++ * This routine handles page faults.  It determines the address,
++ * and the problem, and then passes it off to one of the appropriate
++ * routines.
++ */
++asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long writeaccess,
++			      unsigned long textaccess, unsigned long address)
++{
++	struct task_struct *tsk;
++	struct mm_struct *mm;
++	struct vm_area_struct * vma;
++	const struct exception_table_entry *fixup;
++	pte_t *pte;
++	int fault;
++
++	/* SIM
++	 * Note this is now called with interrupts still disabled
++	 * This is to cope with being called for a missing IO port
++	 * address with interrupts disabled. This should be fixed as
++	 * soon as we have a better 'fast path' miss handler.
++	 *
++	 * Plus take care how you try and debug this stuff.
++	 * For example, writing debug data to a port which you
++	 * have just faulted on is not going to work.
++	 */
++
++	tsk = current;
++	mm = tsk->mm;
++
++	/* Not an IO address, so reenable interrupts */
++	local_irq_enable();
++
++	/*
++	 * If we're in an interrupt or have no user
++	 * context, we must not take the fault..
++	 */
++	if (in_atomic() || !mm)
++		goto no_context;
++
++	/* TLB misses upon some cache flushes get done under cli() */
++	down_read(&mm->mmap_sem);
++
++	vma = find_vma(mm, address);
++
++	if (!vma) {
++#ifdef DEBUG_FAULT
++		print_task(tsk);
++		printk("%s:%d fault, address is 0x%08x PC %016Lx textaccess %d writeaccess %d\n",
++		       __FUNCTION__,__LINE__,
++		       address,regs->pc,textaccess,writeaccess);
++		show_regs(regs);
++#endif
++		goto bad_area;
++	}
++	if (vma->vm_start <= address) {
++		goto good_area;
++	}
++
++	if (!(vma->vm_flags & VM_GROWSDOWN)) {
++#ifdef DEBUG_FAULT
++		print_task(tsk);
++		printk("%s:%d fault, address is 0x%08x PC %016Lx textaccess %d writeaccess %d\n",
++		       __FUNCTION__,__LINE__,
++		       address,regs->pc,textaccess,writeaccess);
++		show_regs(regs);
++
++		print_vma(vma);
++#endif
++		goto bad_area;
++	}
++	if (expand_stack(vma, address)) {
++#ifdef DEBUG_FAULT
++		print_task(tsk);
++		printk("%s:%d fault, address is 0x%08x PC %016Lx textaccess %d writeaccess %d\n",
++		       __FUNCTION__,__LINE__,
++		       address,regs->pc,textaccess,writeaccess);
++		show_regs(regs);
++#endif
++		goto bad_area;
++	}
++/*
++ * Ok, we have a good vm_area for this memory access, so
++ * we can handle it..
++ */
++good_area:
++	if (textaccess) {
++		if (!(vma->vm_flags & VM_EXEC))
++			goto bad_area;
++	} else {
++		if (writeaccess) {
++			if (!(vma->vm_flags & VM_WRITE))
++				goto bad_area;
++		} else {
++			if (!(vma->vm_flags & VM_READ))
++				goto bad_area;
++		}
++	}
++
++	/*
++	 * If for any reason at all we couldn't handle the fault,
++	 * make sure we exit gracefully rather than endlessly redo
++	 * the fault.
++	 */
++survive:
++	fault = handle_mm_fault(mm, vma, address, writeaccess);
++	if (unlikely(fault & VM_FAULT_ERROR)) {
++		if (fault & VM_FAULT_OOM)
++			goto out_of_memory;
++		else if (fault & VM_FAULT_SIGBUS)
++			goto do_sigbus;
++		BUG();
++	}
++	if (fault & VM_FAULT_MAJOR)
++		tsk->maj_flt++;
++	else
++		tsk->min_flt++;
++
++	/* If we get here, the page fault has been handled.  Do the TLB refill
++	   now from the newly-setup PTE, to avoid having to fault again right
++	   away on the same instruction. */
++	pte = lookup_pte (mm, address);
++	if (!pte) {
++		/* From empirical evidence, we can get here, due to
++		   !pte_present(pte).  (e.g. if a swap-in occurs, and the page
++		   is swapped back out again before the process that wanted it
++		   gets rescheduled?) */
++		goto no_pte;
++	}
++
++	__do_tlb_refill(address, textaccess, pte);
++
++no_pte:
++
++	up_read(&mm->mmap_sem);
++	return;
++
++/*
++ * Something tried to access memory that isn't in our memory map..
++ * Fix it, but check if it's kernel or user first..
++ */
++bad_area:
++#ifdef DEBUG_FAULT
++	printk("fault:bad area\n");
++#endif
++	up_read(&mm->mmap_sem);
++
++	if (user_mode(regs)) {
++		static int count=0;
++		siginfo_t info;
++		if (count < 4) {
++			/* This is really to help debug faults when starting
++			 * usermode, so only need a few */
++			count++;
++			printk("user mode bad_area address=%08lx pid=%d (%s) pc=%08lx\n",
++				address, task_pid_nr(current), current->comm,
++				(unsigned long) regs->pc);
++#if 0
++			show_regs(regs);
++#endif
++		}
++		if (is_global_init(tsk)) {
++			panic("INIT had user mode bad_area\n");
++		}
++		tsk->thread.address = address;
++		tsk->thread.error_code = writeaccess;
++		info.si_signo = SIGSEGV;
++		info.si_errno = 0;
++		info.si_addr = (void *) address;
++		force_sig_info(SIGSEGV, &info, tsk);
++		return;
++	}
++
++no_context:
++#ifdef DEBUG_FAULT
++	printk("fault:No context\n");
++#endif
++	/* Are we prepared to handle this kernel fault?  */
++	fixup = search_exception_tables(regs->pc);
++	if (fixup) {
++		regs->pc = fixup->fixup;
++		return;
++	}
++
++/*
++ * Oops. The kernel tried to access some bad page. We'll have to
++ * terminate things with extreme prejudice.
++ *
++ */
++	if (address < PAGE_SIZE)
++		printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference");
++	else
++		printk(KERN_ALERT "Unable to handle kernel paging request");
++	printk(" at virtual address %08lx\n", address);
++	printk(KERN_ALERT "pc = %08Lx%08Lx\n", regs->pc >> 32, regs->pc & 0xffffffff);
++	die("Oops", regs, writeaccess);
++	do_exit(SIGKILL);
++
++/*
++ * We ran out of memory, or some other thing happened to us that made
++ * us unable to handle the page fault gracefully.
++ */
++out_of_memory:
++	if (is_global_init(current)) {
++		panic("INIT out of memory\n");
++		yield();
++		goto survive;
++	}
++	printk("fault:Out of memory\n");
++	up_read(&mm->mmap_sem);
++	if (is_global_init(current)) {
++		yield();
++		down_read(&mm->mmap_sem);
++		goto survive;
++	}
++	printk("VM: killing process %s\n", tsk->comm);
++	if (user_mode(regs))
++		do_group_exit(SIGKILL);
++	goto no_context;
++
++do_sigbus:
++	printk("fault:Do sigbus\n");
++	up_read(&mm->mmap_sem);
++
++	/*
++	 * Send a sigbus, regardless of whether we were in kernel
++	 * or user mode.
++	 */
++	tsk->thread.address = address;
++	tsk->thread.error_code = writeaccess;
++	tsk->thread.trap_no = 14;
++	force_sig(SIGBUS, tsk);
++
++	/* Kernel mode? Handle exceptions or die */
++	if (!user_mode(regs))
++		goto no_context;
++}
++
++void update_mmu_cache(struct vm_area_struct * vma,
++			unsigned long address, pte_t pte)
++{
++	/*
++	 * This appears to get called once for every pte entry that gets
++	 * established => I don't think it's efficient to try refilling the
++	 * TLBs with the pages - some may not get accessed even.  Also, for
++	 * executable pages, it is impossible to determine reliably here which
++	 * TLB they should be mapped into (or both even).
++	 *
++	 * So, just do nothing here and handle faults on demand.  In the
++	 * TLBMISS handling case, the refill is now done anyway after the pte
++	 * has been fixed up, so that deals with most useful cases.
++	 */
++}
++
++void local_flush_tlb_one(unsigned long asid, unsigned long page)
++{
++	unsigned long long match, pteh=0, lpage;
++	unsigned long tlb;
++
++	/*
++	 * Sign-extend based on neff.
++	 */
++	lpage = (page & NEFF_SIGN) ? (page | NEFF_MASK) : page;
++	match = (asid << PTEH_ASID_SHIFT) | PTEH_VALID;
++	match |= lpage;
++
++	for_each_itlb_entry(tlb) {
++		asm volatile ("getcfg	%1, 0, %0"
++			      : "=r" (pteh)
++			      : "r" (tlb) );
++
++		if (pteh == match) {
++			__flush_tlb_slot(tlb);
++			break;
++		}
++	}
++
++	for_each_dtlb_entry(tlb) {
++		asm volatile ("getcfg	%1, 0, %0"
++			      : "=r" (pteh)
++			      : "r" (tlb) );
++
++		if (pteh == match) {
++			__flush_tlb_slot(tlb);
++			break;
++		}
++
++	}
++}
++
++void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
++{
++	unsigned long flags;
++
++	if (vma->vm_mm) {
++		page &= PAGE_MASK;
++		local_irq_save(flags);
++		local_flush_tlb_one(get_asid(), page);
++		local_irq_restore(flags);
++	}
++}
++
++void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
++			   unsigned long end)
++{
++	unsigned long flags;
++	unsigned long long match, pteh=0, pteh_epn, pteh_low;
++	unsigned long tlb;
++	unsigned int cpu = smp_processor_id();
++	struct mm_struct *mm;
++
++	mm = vma->vm_mm;
++	if (cpu_context(cpu, mm) == NO_CONTEXT)
++		return;
++
++	local_irq_save(flags);
++
++	start &= PAGE_MASK;
++	end &= PAGE_MASK;
++
++	match = (cpu_asid(cpu, mm) << PTEH_ASID_SHIFT) | PTEH_VALID;
++
++	/* Flush ITLB */
++	for_each_itlb_entry(tlb) {
++		asm volatile ("getcfg	%1, 0, %0"
++			      : "=r" (pteh)
++			      : "r" (tlb) );
++
++		pteh_epn = pteh & PAGE_MASK;
++		pteh_low = pteh & ~PAGE_MASK;
++
++		if (pteh_low == match && pteh_epn >= start && pteh_epn <= end)
++			__flush_tlb_slot(tlb);
++	}
++
++	/* Flush DTLB */
++	for_each_dtlb_entry(tlb) {
++		asm volatile ("getcfg	%1, 0, %0"
++			      : "=r" (pteh)
++			      : "r" (tlb) );
++
++		pteh_epn = pteh & PAGE_MASK;
++		pteh_low = pteh & ~PAGE_MASK;
++
++		if (pteh_low == match && pteh_epn >= start && pteh_epn <= end)
++			__flush_tlb_slot(tlb);
++	}
++
++	local_irq_restore(flags);
++}
++
++void local_flush_tlb_mm(struct mm_struct *mm)
++{
++	unsigned long flags;
++	unsigned int cpu = smp_processor_id();
++
++	if (cpu_context(cpu, mm) == NO_CONTEXT)
++		return;
++
++	local_irq_save(flags);
++
++	cpu_context(cpu, mm) = NO_CONTEXT;
++	if (mm == current->mm)
++		activate_context(mm, cpu);
++
++	local_irq_restore(flags);
++}
++
++void local_flush_tlb_all(void)
++{
++	/* Invalidate all, including shared pages, excluding fixed TLBs */
++	unsigned long flags, tlb;
++
++	local_irq_save(flags);
++
++	/* Flush each ITLB entry */
++	for_each_itlb_entry(tlb)
++		__flush_tlb_slot(tlb);
++
++	/* Flush each DTLB entry */
++	for_each_dtlb_entry(tlb)
++		__flush_tlb_slot(tlb);
++
++	local_irq_restore(flags);
++}
++
++void local_flush_tlb_kernel_range(unsigned long start, unsigned long end)
++{
++        /* FIXME: Optimize this later.. */
++        flush_tlb_all();
++}
+diff --git a/arch/sh/tools/mach-types b/arch/sh/tools/mach-types
+index ff07169..2581067 100644
+--- a/arch/sh/tools/mach-types
++++ b/arch/sh/tools/mach-types
+@@ -29,7 +29,6 @@ HP6XX			SH_HP6XX
+ DREAMCAST		SH_DREAMCAST
+ MPC1211			SH_MPC1211
+ SNAPGEAR		SH_SECUREEDGE5410
+-HS7751RVOIP		SH_HS7751RVOIP
+ EDOSK7705		SH_EDOSK7705
+ SH4202_MICRODEV		SH_SH4202_MICRODEV
+ SH03			SH_SH03
+@@ -45,3 +44,4 @@ X3PROTO			SH_X3PROTO
+ MAGICPANELR2		SH_MAGIC_PANEL_R2
+ R2D_PLUS		RTS7751R2D_PLUS
+ R2D_1			RTS7751R2D_1
++CAYMAN			SH_CAYMAN
+diff --git a/arch/sh64/Kconfig b/arch/sh64/Kconfig
+deleted file mode 100644
+index 6884d5a..0000000
+--- a/arch/sh64/Kconfig
++++ /dev/null
+@@ -1,295 +0,0 @@
+-#
+-# For a description of the syntax of this configuration file,
+-# see Documentation/kbuild/kconfig-language.txt.
+-#
+-
+-mainmenu "Linux/SH64 Kernel Configuration"
+-
+-config SUPERH
+-	bool
+-	default y
+-
+-config SUPERH64
+-	bool
+-	default y
+-
+-config MMU
+-	bool
+-	default y
+-
+-config QUICKLIST
+-	def_bool y
+-
+-config RWSEM_GENERIC_SPINLOCK
+-	bool
+-	default y
+-
+-config GENERIC_FIND_NEXT_BIT
+-	bool
+-	default y
+-
+-config GENERIC_HWEIGHT
+-	bool
+-	default y
+-
+-config GENERIC_CALIBRATE_DELAY
+-	bool
+-	default y
+-
+-config GENERIC_HARDIRQS
+-	bool
+-	default y
+-
+-config GENERIC_IRQ_PROBE
+-	bool
+-	default y
+-
+-config RWSEM_XCHGADD_ALGORITHM
+-	bool
+-
+-config ARCH_HAS_ILOG2_U32
+-	bool
+-	default n
+-
+-config ARCH_HAS_ILOG2_U64
+-	bool
+-	default n
+-
+-config ARCH_NO_VIRT_TO_BUS
+-	def_bool y
+-
+-source init/Kconfig
+-
+-menu "System type"
+-
+-choice
+-	prompt "SuperH system type"
+-	default SH_SIMULATOR
+-
+-config SH_SIMULATOR
+-	bool "Simulator"
+-
+-config SH_CAYMAN
+-	bool "Cayman"
+-
+-config SH_HARP
+-	bool "ST50-Harp"
+-
+-endchoice
+-
+-choice
+-	prompt "Processor family"
+-	default CPU_SH5
+-
+-config CPU_SH5
+-	bool "SH-5"
+-
+-endchoice
+-
+-choice
+-	prompt "Processor type"
+-
+-config CPU_SUBTYPE_SH5_101
+-	bool "SH5-101"
+-	depends on CPU_SH5
+-
+-config CPU_SUBTYPE_SH5_103
+-	bool "SH5-103"
+-	depends on CPU_SH5
+-
+-endchoice
+-
+-choice
+-	prompt "Endianness"
+-	default LITTLE_ENDIAN
+-
+-config LITTLE_ENDIAN
+-	bool "Little-Endian"
+-
+-config BIG_ENDIAN
+-	bool "Big-Endian"
+-
+-endchoice
+-
+-config SH_FPU
+-	bool "FPU support"
+-	default y
+-
+-config SH64_FPU_DENORM_FLUSH
+-	depends on SH_FPU
+-	bool "Flush floating point denorms to zero"
+-
+-choice
+-	prompt "Page table levels"
+-	default SH64_PGTABLE_2_LEVEL
+-
+-config SH64_PGTABLE_2_LEVEL
+-	bool "2"
+-
+-config SH64_PGTABLE_3_LEVEL
+-	bool "3"
+-
+-endchoice
+-
+-choice
+-	prompt "HugeTLB page size"
+-	depends on HUGETLB_PAGE && MMU
+-	default HUGETLB_PAGE_SIZE_64K
+-
+-config HUGETLB_PAGE_SIZE_64K
+-	bool "64K"
+-
+-config HUGETLB_PAGE_SIZE_1MB
+-	bool "1MB"
+-
+-config HUGETLB_PAGE_SIZE_512MB
+-	bool "512MB"
+-
+-endchoice
+-
+-config SH64_USER_MISALIGNED_FIXUP
+-	bool "Fixup misaligned loads/stores occurring in user mode"
+-
+-comment "Memory options"
+-
+-config CACHED_MEMORY_OFFSET
+-	hex "Cached Area Offset"
+-	default "20000000"
+-
+-config MEMORY_START
+-	hex "Physical memory start address"
+-	default "80000000"
+-
+-config MEMORY_SIZE_IN_MB
+-	int "Memory size (in MB)"
+-	default "8" if SH_SIMULATOR
+-	default "64"
+-
+-comment "Cache options"
+-
+-choice
+-	prompt "DCache mode"
+-	default DCACHE_DISABLED if SH_SIMULATOR
+-	default DCACHE_WRITE_BACK
+-
+-config DCACHE_WRITE_BACK
+-	bool "Write-back"
+-	depends on !SH_SIMULATOR
+-
+-config DCACHE_WRITE_THROUGH
+-	bool "Write-through"
+-	depends on !SH_SIMULATOR
+-
+-config DCACHE_DISABLED
+-	bool "Disabled"
+-
+-endchoice
+-
+-config ICACHE_DISABLED
+-	bool "ICache Disabling"
+-
+-config PCIDEVICE_MEMORY_START
+-	hex
+-	default "C0000000"
+-
+-config DEVICE_MEMORY_START
+-	hex
+-	default "E0000000"
+-
+-config FLASH_MEMORY_START
+-	hex "Flash memory/on-chip devices start address"
+-	default "00000000"
+-
+-config PCI_BLOCK_START
+-	hex "PCI block start address"
+-	default "40000000"
+-
+-comment "CPU Subtype specific options"
+-
+-config SH64_ID2815_WORKAROUND
+-	bool "Include workaround for SH5-101 cut2 silicon defect ID2815"
+-
+-comment "Misc options"
+-
+-config HEARTBEAT
+-	bool "Heartbeat LED"
+-	depends on SH_CAYMAN
+-
+-config HDSP253_LED
+-	bool "Support for HDSP-253 LED"
+-	depends on SH_CAYMAN
+-
+-config SH_DMA
+-	tristate "DMA controller (DMAC) support"
+-
+-config PREEMPT
+-	bool "Preemptible Kernel (EXPERIMENTAL)"
+-	depends on EXPERIMENTAL
+-
+-source "mm/Kconfig"
+-
+-endmenu
+-
+-menu "Bus options (PCI, PCMCIA, EISA, MCA, ISA)"
+-
+-config ISA
+-	bool
+-
+-config SBUS
+-	bool
+-
+-config PCI
+-	bool "PCI support"
+-	depends on SH_CAYMAN
+-	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.
+-
+-	  The PCI-HOWTO, available from
+-	  <http://www.tldp.org/docs.html#howto>, contains valuable
+-	  information about which PCI hardware does work under Linux and which
+-	  doesn't.
+-
+-config SH_PCIDMA_NONCOHERENT
+-	bool "Cache and PCI noncoherent"
+-	depends on PCI
+-	default y
+-	help
+-	  Enable this option if your platform does not have a CPU cache which
+-	  remains coherent with PCI DMA. It is safest to say 'Y', although you
+-	  will see better performance if you can say 'N', because the PCI DMA
+-	  code will not have to flush the CPU's caches. If you have a PCI host
+-	  bridge integrated with your SH CPU, refer carefully to the chip specs
+-	  to see if you can say 'N' here. Otherwise, leave it as 'Y'.
+-
+-source "drivers/pci/Kconfig"
+-
+-source "drivers/pcmcia/Kconfig"
+-
+-source "drivers/pci/hotplug/Kconfig"
+-
+-endmenu
+-
+-menu "Executable file formats"
+-
+-source "fs/Kconfig.binfmt"
+-
+-endmenu
+-
+-source "net/Kconfig"
+-
+-source "drivers/Kconfig"
+-
+-source "fs/Kconfig"
+-
+-source "kernel/Kconfig.instrumentation"
+-
+-source "arch/sh64/Kconfig.debug"
+-
+-source "security/Kconfig"
+-
+-source "crypto/Kconfig"
+-
+-source "lib/Kconfig"
+diff --git a/arch/sh64/Kconfig.debug b/arch/sh64/Kconfig.debug
+deleted file mode 100644
+index 05c07c4..0000000
+--- a/arch/sh64/Kconfig.debug
++++ /dev/null
+@@ -1,33 +0,0 @@
+-menu "Kernel hacking"
+-
+-source "lib/Kconfig.debug"
+-
+-config EARLY_PRINTK
+-	bool "Early SCIF console support"
+-
+-config SH64_PROC_TLB
+-	bool "Debug: report TLB fill/purge activity through /proc/tlb"
+-	depends on PROC_FS
+-
+-config SH64_PROC_ASIDS
+-	bool "Debug: report ASIDs through /proc/asids"
+-	depends on PROC_FS
+-
+-config SH64_SR_WATCH
+-	bool "Debug: set SR.WATCH to enable hardware watchpoints and trace"
+-
+-config POOR_MANS_STRACE
+-	bool "Debug: enable rudimentary strace facility"
+-	help
+-	  This option allows system calls to be traced to the console.  It also
+-	  aids in detecting kernel stack underflow.  It is useful for debugging
+-	  early-userland problems (e.g. init incurring fatal exceptions.)
+-
+-config SH_ALPHANUMERIC
+-	bool "Enable debug outputs to on-board alphanumeric display"
+-	depends on SH_CAYMAN
+-
+-config SH_NO_BSS_INIT
+-	bool "Avoid zeroing BSS (to speed-up startup on suitable platforms)"
+-
+-endmenu
+diff --git a/arch/sh64/Makefile b/arch/sh64/Makefile
+deleted file mode 100644
+index 8dac7e1..0000000
+--- a/arch/sh64/Makefile
++++ /dev/null
+@@ -1,111 +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, 2001  Paolo Alberelli
+-# Copyright (C) 2003, 2004  Paul Mundt
+-#
+-# This file is included by the global makefile so that you can add your own
+-# architecture-specific flags and dependencies. Remember to do have actions
+-# for "archclean" and "archdep" for cleaning up and making dependencies for
+-# this architecture
+-#
+-
+-cpu-y				:= -mb
+-cpu-$(CONFIG_LITTLE_ENDIAN)	:= -ml
+-
+-cpu-$(CONFIG_CPU_SH5)		+= -m5-32media-nofpu
+-
+-ifdef CONFIG_LITTLE_ENDIAN
+-LDFLAGS_vmlinux		+= --defsym 'jiffies=jiffies_64'
+-LDFLAGS			+= -EL  -mshlelf32_linux
+-else
+-LDFLAGS_vmlinux		+= --defsym 'jiffies=jiffies_64+4'
+-LDFLAGS			+= -EB  -mshelf32_linux
+-endif
+-
+-# No requirements for endianess support from AFLAGS, 'as' always run through gcc
+-KBUILD_CFLAGS		+= $(cpu-y)
+-
+-LDFLAGS_vmlinux	+= --defsym phys_stext=_stext-$(CONFIG_CACHED_MEMORY_OFFSET) \
+-		  --defsym phys_stext_shmedia=phys_stext+1 \
+-		  -e phys_stext_shmedia
+-
+-OBJCOPYFLAGS	:= -O binary -R .note -R .comment -R .stab -R .stabstr -S
+-
+-#
+-# arch/sh64/defconfig never had any hope of being
+-# frequently updated, so use one that does
+-#
+-KBUILD_DEFCONFIG	:= cayman_defconfig
+-
+-KBUILD_IMAGE		:= arch/$(ARCH)/boot/zImage
+-
+-ifdef LOADADDR
+-LINKFLAGS     += -Ttext $(word 1,$(LOADADDR))
+-endif
+-
+-machine-$(CONFIG_SH_CAYMAN)	:= cayman
+-machine-$(CONFIG_SH_SIMULATOR)	:= sim
+-machine-$(CONFIG_SH_HARP)	:= harp
+-
+-head-y := arch/$(ARCH)/kernel/head.o arch/$(ARCH)/kernel/init_task.o
+-
+-core-y	+= arch/sh64/kernel/ arch/sh64/mm/
+-
+-ifneq ($(machine-y),)
+-core-y	+= arch/sh64/mach-$(machine-y)/
+-endif
+-
+-LIBGCC := $(shell $(CC) $(KBUILD_CFLAGS) -print-libgcc-file-name)
+-libs-y	+= arch/$(ARCH)/lib/ $(LIBGCC)
+-
+-drivers-$(CONFIG_OPROFILE)	+= arch/sh64/oprofile/
+-
+-boot := arch/$(ARCH)/boot
+-
+-zImage: vmlinux
+-	$(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
+-
+-compressed: zImage
+-
+-archclean:
+-	$(Q)$(MAKE) $(clean)=$(boot)
+-
+-archprepare: arch/$(ARCH)/lib/syscalltab.h
+-
+-define filechk_gen-syscalltab
+-       (set -e; \
+-	echo "/*"; \
+-	echo " * DO NOT MODIFY."; \
+-	echo " *"; \
+-	echo " * This file was generated by arch/$(ARCH)/Makefile"; \
+-	echo " * Any changes will be reverted at build time."; \
+-	echo " */"; \
+-	echo ""; \
+-	echo "#ifndef __SYSCALLTAB_H"; \
+-	echo "#define __SYSCALLTAB_H"; \
+-	echo ""; \
+-	echo "#include <linux/kernel.h>"; \
+-	echo ""; \
+-	echo "struct syscall_info {"; \
+-	echo "	const char *name;"; \
+-	echo "} syscall_info_table[] = {"; \
+-	sed -e '/^.*\.long /!d;s//    { "/;s/\(\([^/]*\)\/\)\{1\}.*/\2/; \
+-		s/[ \t]*$$//g;s/$$/" },/;s/\("\)sys_/\1/g'; \
+-	echo "};"; \
+-	echo ""; \
+-	echo "#define NUM_SYSCALL_INFO_ENTRIES	ARRAY_SIZE(syscall_info_table)"; \
+-	echo ""; \
+-	echo "#endif /* __SYSCALLTAB_H */" )
+-endef
+-
+-arch/$(ARCH)/lib/syscalltab.h: arch/sh64/kernel/syscalls.S
+-	$(call filechk,gen-syscalltab)
+-
+-CLEAN_FILES += arch/$(ARCH)/lib/syscalltab.h
+-
+-define archhelp
+-	@echo '* zImage 	           - Compressed kernel image'
+-endef
+diff --git a/arch/sh64/boot/Makefile b/arch/sh64/boot/Makefile
+deleted file mode 100644
+index fb71087..0000000
+--- a/arch/sh64/boot/Makefile
++++ /dev/null
+@@ -1,20 +0,0 @@
+-#
+-# arch/sh64/boot/Makefile
+-#
+-# This file is subject to the terms and conditions of the GNU General Public
+-# License.  See the file "COPYING" in the main directory of this archive
+-# for more details.
+-#
+-# Copyright (C) 2002 Stuart Menefy
+-#
+-
+-targets := zImage
+-subdir- := compressed
+-
+-$(obj)/zImage: $(obj)/compressed/vmlinux FORCE
+-	$(call if_changed,objcopy)
+-	@echo 'Kernel: $@ is ready'
+-
+-$(obj)/compressed/vmlinux: FORCE
+-	$(Q)$(MAKE) $(build)=$(obj)/compressed $@
+-
+diff --git a/arch/sh64/boot/compressed/Makefile b/arch/sh64/boot/compressed/Makefile
+deleted file mode 100644
+index 9cd2167..0000000
+--- a/arch/sh64/boot/compressed/Makefile
++++ /dev/null
+@@ -1,46 +0,0 @@
+-#
+-# linux/arch/sh64/boot/compressed/Makefile
+-#
+-# This file is subject to the terms and conditions of the GNU General Public
+-# License.  See the file "COPYING" in the main directory of this archive
+-# for more details.
+-#
+-# Copyright (C) 2002 Stuart Menefy
+-# Copyright (C) 2004 Paul Mundt
+-#
+-# create a compressed vmlinux image from the original vmlinux
+-#
+-
+-targets		:= vmlinux vmlinux.bin vmlinux.bin.gz \
+-		   head.o misc.o cache.o piggy.o vmlinux.lds
+-
+-EXTRA_AFLAGS	:= -traditional
+-
+-OBJECTS		:= $(obj)/head.o $(obj)/misc.o $(obj)/cache.o
+-
+-#
+-# ZIMAGE_OFFSET is the load offset of the compression loader
+-# (4M for the kernel plus 64K for this loader)
+-#
+-ZIMAGE_OFFSET = $(shell printf "0x%8x" $$[$(CONFIG_MEMORY_START)+0x400000+0x10000])
+-
+-LDFLAGS_vmlinux := -Ttext $(ZIMAGE_OFFSET) -e startup \
+-		    -T $(obj)/../../kernel/vmlinux.lds \
+-		    --no-warn-mismatch
+-
+-$(obj)/vmlinux: $(OBJECTS) $(obj)/piggy.o FORCE
+-	$(call if_changed,ld)
+-	@:
+-
+-$(obj)/vmlinux.bin: vmlinux FORCE
+-	$(call if_changed,objcopy)
+-
+-$(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin FORCE
+-	$(call if_changed,gzip)
+-
+-LDFLAGS_piggy.o := -r --format binary --oformat elf32-sh64-linux -T
+-OBJCOPYFLAGS += -R .empty_zero_page
+-
+-$(obj)/piggy.o: $(obj)/vmlinux.lds $(obj)/vmlinux.bin.gz FORCE
+-	$(call if_changed,ld)
+-
+diff --git a/arch/sh64/boot/compressed/cache.c b/arch/sh64/boot/compressed/cache.c
+deleted file mode 100644
+index 7087073..0000000
+--- a/arch/sh64/boot/compressed/cache.c
++++ /dev/null
+@@ -1,39 +0,0 @@
+-/*
+- * arch/shmedia/boot/compressed/cache.c -- simple cache management functions
+- *
+- * Code extracted from sh-ipl+g, sh-stub.c, which has the copyright:
+- *
+- *   This is originally based on an m68k software stub written by Glenn
+- *   Engel at HP, but has changed quite a bit.
+- *
+- *   Modifications for the SH by Ben Lee and Steve Chamberlain
+- *
+-****************************************************************************
+-
+-		THIS SOFTWARE IS NOT COPYRIGHTED
+-
+-   HP offers the following for use in the public domain.  HP makes no
+-   warranty with regard to the software or it's performance and the
+-   user accepts the software "AS IS" with all faults.
+-
+-   HP DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD
+-   TO THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+-   OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+-
+-****************************************************************************/
+-
+-#define CACHE_ENABLE      0
+-#define CACHE_DISABLE     1
+-
+-int cache_control(unsigned int command)
+-{
+-	volatile unsigned int *p = (volatile unsigned int *) 0x80000000;
+-	int i;
+-
+-	for (i = 0; i < (32 * 1024); i += 32) {
+-		(void *) *p;
+-		p += (32 / sizeof (int));
+-	}
+-
+-	return 0;
+-}
+diff --git a/arch/sh64/boot/compressed/head.S b/arch/sh64/boot/compressed/head.S
+deleted file mode 100644
+index 82040b1..0000000
+--- a/arch/sh64/boot/compressed/head.S
++++ /dev/null
+@@ -1,164 +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.
+- *
+- * arch/shmedia/boot/compressed/head.S
+- *
+- * Copied from
+- *   arch/shmedia/kernel/head.S
+- * which carried the copyright:
+- *   Copyright (C) 2000, 2001  Paolo Alberelli
+- *
+- * Modification for compressed loader:
+- *   Copyright (C) 2002 Stuart Menefy (stuart.menefy at st.com)
+- */
+-
+-#include <linux/linkage.h>
+-#include <asm/registers.h>
+-#include <asm/cache.h>
+-#include <asm/mmu_context.h>
+-
+-/*
+- * Fixed TLB entries to identity map the beginning of RAM
+- */
+-#define MMUIR_TEXT_H	0x0000000000000003 | CONFIG_MEMORY_START
+-			/* Enabled, Shared, ASID 0, Eff. Add. 0xA0000000 */
+-#define MMUIR_TEXT_L	0x000000000000009a | CONFIG_MEMORY_START
+-			/* 512 Mb, Cacheable (Write-back), execute, Not User, Ph. Add. */
+-
+-#define MMUDR_CACHED_H	0x0000000000000003 | CONFIG_MEMORY_START
+-			/* Enabled, Shared, ASID 0, Eff. Add. 0xA0000000 */
+-#define MMUDR_CACHED_L	0x000000000000015a | CONFIG_MEMORY_START
+-			/* 512 Mb, Cacheable (Write-back), read/write, Not User, Ph. Add. */
+-
+-#define	ICCR0_INIT_VAL	ICCR0_ON | ICCR0_ICI		/* ICE + ICI */
+-#define	ICCR1_INIT_VAL	ICCR1_NOLOCK			/* No locking */
+-
+-#if 1
+-#define	OCCR0_INIT_VAL	OCCR0_ON | OCCR0_OCI | OCCR0_WB	/* OCE + OCI + WB */
+-#else
+-#define	OCCR0_INIT_VAL	OCCR0_OFF
+-#endif
+-#define	OCCR1_INIT_VAL	OCCR1_NOLOCK			/* No locking */
+-
+-	.text
+-
+-	.global	startup
+-startup:
+-	/*
+-	 * Prevent speculative fetch on device memory due to
+-	 * uninitialized target registers.
+-	 * This must be executed before the first branch.
+-	 */
+-	ptabs/u	ZERO, tr0
+-	ptabs/u	ZERO, tr1
+-	ptabs/u	ZERO, tr2
+-	ptabs/u	ZERO, tr3
+-	ptabs/u	ZERO, tr4
+-	ptabs/u	ZERO, tr5
+-	ptabs/u	ZERO, tr6
+-	ptabs/u	ZERO, tr7
+-	synci
+-
+-	/*
+-	 * Set initial TLB entries for cached and uncached regions.
+-	 * Note: PTA/BLINK is PIC code, PTABS/BLINK isn't !
+-	 */
+-	/* Clear ITLBs */
+-	pta	1f, tr1
+-	movi	ITLB_FIXED, r21
+-	movi	ITLB_LAST_VAR_UNRESTRICTED+TLB_STEP, r22
+-1:	putcfg	r21, 0, ZERO		/* Clear MMUIR[n].PTEH.V */
+-	addi	r21, TLB_STEP, r21
+-        bne	r21, r22, tr1
+-
+-	/* Clear DTLBs */
+-	pta	1f, tr1
+-	movi	DTLB_FIXED, r21
+-	movi	DTLB_LAST_VAR_UNRESTRICTED+TLB_STEP, r22
+-1:	putcfg	r21, 0, ZERO		/* Clear MMUDR[n].PTEH.V */
+-	addi	r21, TLB_STEP, r21
+-        bne	r21, r22, tr1
+-
+-	/* Map one big (512Mb) page for ITLB */
+-	movi	ITLB_FIXED, r21
+-	movi	MMUIR_TEXT_L, r22	/* PTEL first */
+-	putcfg	r21, 1, r22		/* Set MMUIR[0].PTEL */
+-	movi	MMUIR_TEXT_H, r22	/* PTEH last */
+-	putcfg	r21, 0, r22		/* Set MMUIR[0].PTEH */
+-
+-	/* Map one big CACHED (512Mb) page for DTLB */
+-	movi	DTLB_FIXED, r21
+-	movi	MMUDR_CACHED_L, r22	/* PTEL first */
+-	putcfg	r21, 1, r22		/* Set MMUDR[0].PTEL */
+-	movi	MMUDR_CACHED_H, r22	/* PTEH last */
+-	putcfg	r21, 0, r22		/* Set MMUDR[0].PTEH */
+-
+-	/* ICache */
+-	movi	ICCR_BASE, r21
+-	movi	ICCR0_INIT_VAL, r22
+-	movi	ICCR1_INIT_VAL, r23
+-	putcfg	r21, ICCR_REG0, r22
+-	putcfg	r21, ICCR_REG1, r23
+-	synci
+-
+-	/* OCache */
+-	movi	OCCR_BASE, r21
+-	movi	OCCR0_INIT_VAL, r22
+-	movi	OCCR1_INIT_VAL, r23
+-	putcfg	r21, OCCR_REG0, r22
+-	putcfg	r21, OCCR_REG1, r23
+-	synco
+-
+-	/*
+-	 * Enable the MMU.
+-	 * From here-on code can be non-PIC.
+-	 */
+-	movi	SR_HARMLESS | SR_ENABLE_MMU, r22
+-	putcon	r22, SSR
+-	movi	1f, r22
+-	putcon	r22, SPC
+-	synco
+-	rte				/* And now go into the hyperspace ... */
+-1:					/* ... that's the next instruction ! */
+-
+-	/* Set initial stack pointer */
+-	movi	datalabel stack_start, r0
+-	ld.l	r0, 0, r15
+-
+-	/*
+-	 * Clear bss
+-	 */
+-	pt	1f, tr1
+-	movi	datalabel __bss_start, r22
+-	movi	datalabel _end, r23
+-1:	st.l	r22, 0, ZERO
+-	addi	r22, 4, r22
+-	bne	r22, r23, tr1
+-
+-	/*
+-	 * Decompress the kernel.
+-	 */
+-	pt	decompress_kernel, tr0
+-	blink	tr0, r18
+-
+-	/*
+-	 * Disable the MMU.
+-	 */
+-	movi	SR_HARMLESS, r22
+-	putcon	r22, SSR
+-	movi	1f, r22
+-	putcon	r22, SPC
+-	synco
+-	rte				/* And now go into the hyperspace ... */
+-1:					/* ... that's the next instruction ! */
+-
+-	/* Jump into the decompressed kernel */
+-	movi	datalabel (CONFIG_MEMORY_START + 0x2000)+1, r19
+-	ptabs	r19, tr0
+-	blink	tr0, r18
+-
+-	/* Shouldn't return here, but just in case, loop forever */
+-	pt	1f, tr0
+-1:	blink	tr0, ZERO
+diff --git a/arch/sh64/boot/compressed/install.sh b/arch/sh64/boot/compressed/install.sh
+deleted file mode 100644
+index 90589f0..0000000
+--- a/arch/sh64/boot/compressed/install.sh
++++ /dev/null
+@@ -1,56 +0,0 @@
+-#!/bin/sh
+-#
+-# arch/sh/boot/install.sh
+-#
+-# 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) 1995 by Linus Torvalds
+-#
+-# Adapted from code in arch/i386/boot/Makefile by H. Peter Anvin
+-# Adapted from code in arch/i386/boot/install.sh by Russell King
+-# Adapted from code in arch/arm/boot/install.sh by Stuart Menefy
+-#
+-# "make install" script for sh architecture
+-#
+-# Arguments:
+-#   $1 - kernel version
+-#   $2 - kernel image file
+-#   $3 - kernel map file
+-#   $4 - default install path (blank if root directory)
+-#
+-
+-# User may have a custom install script
+-
+-if [ -x /sbin/installkernel ]; then
+-  exec /sbin/installkernel "$@"
+-fi
+-
+-if [ "$2" = "zImage" ]; then
+-# Compressed install
+-  echo "Installing compressed kernel"
+-  if [ -f $4/vmlinuz-$1 ]; then
+-    mv $4/vmlinuz-$1 $4/vmlinuz.old
+-  fi
+-
+-  if [ -f $4/System.map-$1 ]; then
+-    mv $4/System.map-$1 $4/System.old
+-  fi
+-
+-  cat $2 > $4/vmlinuz-$1
+-  cp $3 $4/System.map-$1
+-else
+-# Normal install
+-  echo "Installing normal kernel"
+-  if [ -f $4/vmlinux-$1 ]; then
+-    mv $4/vmlinux-$1 $4/vmlinux.old
+-  fi
+-
+-  if [ -f $4/System.map ]; then
+-    mv $4/System.map $4/System.old
+-  fi
+-
+-  cat $2 > $4/vmlinux-$1
+-  cp $3 $4/System.map
+-fi
+diff --git a/arch/sh64/boot/compressed/misc.c b/arch/sh64/boot/compressed/misc.c
+deleted file mode 100644
+index aea00c5..0000000
+--- a/arch/sh64/boot/compressed/misc.c
++++ /dev/null
+@@ -1,250 +0,0 @@
+-/*
+- * arch/sh64/boot/compressed/misc.c
+- *
+- * This is a collection of several routines from gzip-1.0.3
+- * adapted for Linux.
+- *
+- * malloc by Hannu Savolainen 1993 and Matthias Urlichs 1994
+- *
+- * Adapted for SHmedia from sh by Stuart Menefy, May 2002
+- */
+-
+-#include <asm/uaccess.h>
+-
+-/* cache.c */
+-#define CACHE_ENABLE      0
+-#define CACHE_DISABLE     1
+-int cache_control(unsigned int command);
+-
+-/*
+- * gzip declarations
+- */
+-
+-#define OF(args)  args
+-#define STATIC static
+-
+-#undef memset
+-#undef memcpy
+-#define memzero(s, n)     memset ((s), 0, (n))
+-
+-typedef unsigned char uch;
+-typedef unsigned short ush;
+-typedef unsigned long ulg;
+-
+-#define WSIZE 0x8000		/* Window size must be at least 32k, */
+-				/* and a power of two */
+-
+-static uch *inbuf;		/* input buffer */
+-static uch window[WSIZE];	/* Sliding window buffer */
+-
+-static unsigned insize = 0;	/* valid bytes in inbuf */
+-static unsigned inptr = 0;	/* index of next byte to be processed in inbuf */
+-static unsigned outcnt = 0;	/* bytes in output buffer */
+-
+-/* gzip flag byte */
+-#define ASCII_FLAG   0x01	/* bit 0 set: file probably ASCII text */
+-#define CONTINUATION 0x02	/* bit 1 set: continuation of multi-part gzip file */
+-#define EXTRA_FIELD  0x04	/* bit 2 set: extra field present */
+-#define ORIG_NAME    0x08	/* bit 3 set: original file name present */
+-#define COMMENT      0x10	/* bit 4 set: file comment present */
+-#define ENCRYPTED    0x20	/* bit 5 set: file is encrypted */
+-#define RESERVED     0xC0	/* bit 6,7:   reserved */
+-
+-#define get_byte()  (inptr < insize ? inbuf[inptr++] : fill_inbuf())
+-
+-/* Diagnostic functions */
+-#ifdef DEBUG
+-#  define Assert(cond,msg) {if(!(cond)) error(msg);}
+-#  define Trace(x) fprintf x
+-#  define Tracev(x) {if (verbose) fprintf x ;}
+-#  define Tracevv(x) {if (verbose>1) fprintf x ;}
+-#  define Tracec(c,x) {if (verbose && (c)) fprintf x ;}
+-#  define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;}
+-#else
+-#  define Assert(cond,msg)
+-#  define Trace(x)
+-#  define Tracev(x)
+-#  define Tracevv(x)
+-#  define Tracec(c,x)
+-#  define Tracecv(c,x)
+-#endif
+-
+-static int fill_inbuf(void);
+-static void flush_window(void);
+-static void error(char *m);
+-static void gzip_mark(void **);
+-static void gzip_release(void **);
+-
+-extern char input_data[];
+-extern int input_len;
+-
+-static long bytes_out = 0;
+-static uch *output_data;
+-static unsigned long output_ptr = 0;
+-
+-static void *malloc(int size);
+-static void free(void *where);
+-static void error(char *m);
+-static void gzip_mark(void **);
+-static void gzip_release(void **);
+-
+-static void puts(const char *);
+-
+-extern int _text;		/* Defined in vmlinux.lds.S */
+-extern int _end;
+-static unsigned long free_mem_ptr;
+-static unsigned long free_mem_end_ptr;
+-
+-#define HEAP_SIZE             0x10000
+-
+-#include "../../../../lib/inflate.c"
+-
+-static void *malloc(int size)
+-{
+-	void *p;
+-
+-	if (size < 0)
+-		error("Malloc error\n");
+-	if (free_mem_ptr == 0)
+-		error("Memory error\n");
+-
+-	free_mem_ptr = (free_mem_ptr + 3) & ~3;	/* Align */
+-
+-	p = (void *) free_mem_ptr;
+-	free_mem_ptr += size;
+-
+-	if (free_mem_ptr >= free_mem_end_ptr)
+-		error("\nOut of memory\n");
+-
+-	return p;
+-}
+-
+-static void free(void *where)
+-{				/* Don't care */
+-}
+-
+-static void gzip_mark(void **ptr)
+-{
+-	*ptr = (void *) free_mem_ptr;
+-}
+-
+-static void gzip_release(void **ptr)
+-{
+-	free_mem_ptr = (long) *ptr;
+-}
+-
+-void puts(const char *s)
+-{
+-}
+-
+-void *memset(void *s, int c, size_t n)
+-{
+-	int i;
+-	char *ss = (char *) s;
+-
+-	for (i = 0; i < n; i++)
+-		ss[i] = c;
+-	return s;
+-}
+-
+-void *memcpy(void *__dest, __const void *__src, size_t __n)
+-{
+-	int i;
+-	char *d = (char *) __dest, *s = (char *) __src;
+-
+-	for (i = 0; i < __n; i++)
+-		d[i] = s[i];
+-	return __dest;
+-}
+-
+-/* ===========================================================================
+- * Fill the input buffer. This is called only when the buffer is empty
+- * and at least one byte is really needed.
+- */
+-static int fill_inbuf(void)
+-{
+-	if (insize != 0) {
+-		error("ran out of input data\n");
+-	}
+-
+-	inbuf = input_data;
+-	insize = input_len;
+-	inptr = 1;
+-	return inbuf[0];
+-}
+-
+-/* ===========================================================================
+- * Write the output window window[0..outcnt-1] and update crc and bytes_out.
+- * (Used for the decompressed data only.)
+- */
+-static void flush_window(void)
+-{
+-	ulg c = crc;		/* temporary variable */
+-	unsigned n;
+-	uch *in, *out, ch;
+-
+-	in = window;
+-	out = &output_data[output_ptr];
+-	for (n = 0; n < outcnt; n++) {
+-		ch = *out++ = *in++;
+-		c = crc_32_tab[((int) c ^ ch) & 0xff] ^ (c >> 8);
+-	}
+-	crc = c;
+-	bytes_out += (ulg) outcnt;
+-	output_ptr += (ulg) outcnt;
+-	outcnt = 0;
+-	puts(".");
+-}
+-
+-static void error(char *x)
+-{
+-	puts("\n\n");
+-	puts(x);
+-	puts("\n\n -- System halted");
+-
+-	while (1) ;		/* Halt */
+-}
+-
+-#define STACK_SIZE (4096)
+-long __attribute__ ((aligned(8))) user_stack[STACK_SIZE];
+-long *stack_start = &user_stack[STACK_SIZE];
+-
+-void decompress_kernel(void)
+-{
+-	output_data = (uch *) (CONFIG_MEMORY_START + 0x2000);
+-	free_mem_ptr = (unsigned long) &_end;
+-	free_mem_end_ptr = free_mem_ptr + HEAP_SIZE;
+-
+-	makecrc();
+-	puts("Uncompressing Linux... ");
+-	cache_control(CACHE_ENABLE);
+-	gunzip();
+-	puts("\n");
+-
+-#if 0
+-	/* When booting from ROM may want to do something like this if the
+-	 * boot loader doesn't.
+-	 */
+-
+-	/* Set up the parameters and command line */
+-	{
+-		volatile unsigned int *parambase =
+-		    (int *) (CONFIG_MEMORY_START + 0x1000);
+-
+-		parambase[0] = 0x1;	/* MOUNT_ROOT_RDONLY */
+-		parambase[1] = 0x0;	/* RAMDISK_FLAGS */
+-		parambase[2] = 0x0200;	/* ORIG_ROOT_DEV */
+-		parambase[3] = 0x0;	/* LOADER_TYPE */
+-		parambase[4] = 0x0;	/* INITRD_START */
+-		parambase[5] = 0x0;	/* INITRD_SIZE */
+-		parambase[6] = 0;
+-
+-		strcpy((char *) ((int) parambase + 0x100),
+-		       "console=ttySC0,38400");
+-	}
+-#endif
+-
+-	puts("Ok, booting the kernel.\n");
+-
+-	cache_control(CACHE_DISABLE);
+-}
+diff --git a/arch/sh64/boot/compressed/vmlinux.lds.S b/arch/sh64/boot/compressed/vmlinux.lds.S
+deleted file mode 100644
+index 59c2ef4..0000000
+--- a/arch/sh64/boot/compressed/vmlinux.lds.S
++++ /dev/null
+@@ -1,64 +0,0 @@
+-/*
+- * ld script to make compressed SuperH/shmedia Linux kernel+decompression
+- *		bootstrap
+- * Modified by Stuart Menefy from arch/sh/vmlinux.lds.S written by Niibe Yutaka
+- */
+-
+-
+-#ifdef CONFIG_LITTLE_ENDIAN
+-/* OUTPUT_FORMAT("elf32-sh64l-linux", "elf32-sh64l-linux", "elf32-sh64l-linux") */
+-#define NOP 0x6ff0fff0
+-#else
+-/* OUTPUT_FORMAT("elf32-sh64", "elf32-sh64", "elf32-sh64") */
+-#define NOP 0xf0fff06f
+-#endif
+-
+-OUTPUT_FORMAT("elf32-sh64-linux")
+-OUTPUT_ARCH(sh)
+-ENTRY(_start)
+-
+-#define ALIGNED_GAP(section, align) (((ADDR(section)+SIZEOF(section)+(align)-1) & ~((align)-1))-ADDR(section))
+-#define FOLLOWING(section, align) AT (LOADADDR(section) + ALIGNED_GAP(section,align))
+-
+-SECTIONS
+-{
+-  _text = .;			/* Text and read-only data */
+-
+-  .text : {
+-	*(.text)
+-	*(.text64)
+-	*(.text..SHmedia32)
+-	*(.fixup)
+-	*(.gnu.warning)
+-	} = NOP
+-  . = ALIGN(4);
+-  .rodata : { *(.rodata) }
+-
+-  /* There is no 'real' reason for eight byte alignment, four would work
+-   * as well, but gdb downloads much (*4) faster with this.
+-   */
+-  . = ALIGN(8);
+-  .image : { *(.image) }
+-  . = ALIGN(4);
+-  _etext = .;			/* End of text section */
+-
+-  .data :			/* Data */
+-	FOLLOWING(.image, 4)
+-	{
+-	_data = .;
+-	*(.data)
+-	}
+-  _data_image = LOADADDR(.data);/* Address of data section in ROM */
+-
+-  _edata = .;			/* End of data section */
+-
+-  .stack : { stack = .;  _stack = .; }
+-
+-  . = ALIGN(4);
+-  __bss_start = .;		/* BSS */
+-  .bss : {
+-	*(.bss)
+-	}
+-  . = ALIGN(4);
+-  _end = . ;
+-}
+diff --git a/arch/sh64/configs/cayman_defconfig b/arch/sh64/configs/cayman_defconfig
+deleted file mode 100644
+index 75552bb..0000000
+--- a/arch/sh64/configs/cayman_defconfig
++++ /dev/null
+@@ -1,1126 +0,0 @@
+-#
+-# Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.24-rc1
+-# Fri Nov  2 14:35:27 2007
+-#
+-CONFIG_SUPERH=y
+-CONFIG_SUPERH64=y
+-CONFIG_MMU=y
+-CONFIG_QUICKLIST=y
+-CONFIG_RWSEM_GENERIC_SPINLOCK=y
+-CONFIG_GENERIC_FIND_NEXT_BIT=y
+-CONFIG_GENERIC_HWEIGHT=y
+-CONFIG_GENERIC_CALIBRATE_DELAY=y
+-CONFIG_GENERIC_HARDIRQS=y
+-CONFIG_GENERIC_IRQ_PROBE=y
+-# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+-# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+-CONFIG_ARCH_NO_VIRT_TO_BUS=y
+-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=y
+-CONFIG_SWAP=y
+-# CONFIG_SYSVIPC is not set
+-CONFIG_POSIX_MQUEUE=y
+-# CONFIG_BSD_PROCESS_ACCT is not set
+-# CONFIG_TASKSTATS is not set
+-# CONFIG_USER_NS is not set
+-# CONFIG_AUDIT is not set
+-# CONFIG_IKCONFIG is not set
+-CONFIG_LOG_BUF_SHIFT=14
+-# CONFIG_CGROUPS is not set
+-CONFIG_FAIR_GROUP_SCHED=y
+-CONFIG_FAIR_USER_SCHED=y
+-# CONFIG_FAIR_CGROUP_SCHED is not set
+-CONFIG_SYSFS_DEPRECATED=y
+-# CONFIG_RELAY is not set
+-# CONFIG_BLK_DEV_INITRD is not set
+-# 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_BASE_FULL=y
+-CONFIG_FUTEX=y
+-CONFIG_ANON_INODES=y
+-CONFIG_EPOLL=y
+-CONFIG_SIGNALFD=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_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"
+-
+-#
+-# System type
+-#
+-# CONFIG_SH_SIMULATOR is not set
+-CONFIG_SH_CAYMAN=y
+-# CONFIG_SH_HARP is not set
+-CONFIG_CPU_SH5=y
+-CONFIG_CPU_SUBTYPE_SH5_101=y
+-# CONFIG_CPU_SUBTYPE_SH5_103 is not set
+-CONFIG_LITTLE_ENDIAN=y
+-# CONFIG_BIG_ENDIAN is not set
+-CONFIG_SH_FPU=y
+-# CONFIG_SH64_FPU_DENORM_FLUSH is not set
+-CONFIG_SH64_PGTABLE_2_LEVEL=y
+-# CONFIG_SH64_PGTABLE_3_LEVEL is not set
+-CONFIG_HUGETLB_PAGE_SIZE_64K=y
+-# CONFIG_HUGETLB_PAGE_SIZE_1MB is not set
+-# CONFIG_HUGETLB_PAGE_SIZE_512MB is not set
+-CONFIG_SH64_USER_MISALIGNED_FIXUP=y
+-
+-#
+-# Memory options
+-#
+-CONFIG_CACHED_MEMORY_OFFSET=0x20000000
+-CONFIG_MEMORY_START=0x80000000
+-CONFIG_MEMORY_SIZE_IN_MB=128
+-
+-#
+-# Cache options
+-#
+-CONFIG_DCACHE_WRITE_BACK=y
+-# CONFIG_DCACHE_WRITE_THROUGH is not set
+-# CONFIG_DCACHE_DISABLED is not set
+-# CONFIG_ICACHE_DISABLED is not set
+-CONFIG_PCIDEVICE_MEMORY_START=C0000000
+-CONFIG_DEVICE_MEMORY_START=E0000000
+-CONFIG_FLASH_MEMORY_START=0x00000000
+-CONFIG_PCI_BLOCK_START=0x40000000
+-
+-#
+-# CPU Subtype specific options
+-#
+-CONFIG_SH64_ID2815_WORKAROUND=y
+-
+-#
+-# Misc options
+-#
+-CONFIG_HEARTBEAT=y
+-CONFIG_HDSP253_LED=y
+-# CONFIG_SH_DMA is not set
+-CONFIG_PREEMPT=y
+-CONFIG_SELECT_MEMORY_MODEL=y
+-CONFIG_FLATMEM_MANUAL=y
+-# CONFIG_DISCONTIGMEM_MANUAL is not set
+-# CONFIG_SPARSEMEM_MANUAL is not set
+-CONFIG_FLATMEM=y
+-CONFIG_FLAT_NODE_MEM_MAP=y
+-# CONFIG_SPARSEMEM_STATIC is not set
+-# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
+-CONFIG_SPLIT_PTLOCK_CPUS=4
+-# CONFIG_RESOURCES_64BIT is not set
+-CONFIG_ZONE_DMA_FLAG=0
+-CONFIG_NR_QUICK=1
+-
+-#
+-# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
+-#
+-CONFIG_PCI=y
+-CONFIG_SH_PCIDMA_NONCOHERENT=y
+-# CONFIG_ARCH_SUPPORTS_MSI is not set
+-# CONFIG_PCI_DEBUG is not set
+-# CONFIG_PCCARD is not set
+-# CONFIG_HOTPLUG_PCI is not set
+-
+-#
+-# Executable file formats
+-#
+-CONFIG_BINFMT_ELF=y
+-# CONFIG_BINFMT_MISC 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_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 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=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_INET6_XFRM_TUNNEL is not set
+-# CONFIG_INET6_TUNNEL 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_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_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_BLK_DEV=y
+-# CONFIG_BLK_CPQ_CISS_DA is not set
+-# CONFIG_BLK_DEV_DAC960 is not set
+-# CONFIG_BLK_DEV_UMEM is not set
+-# CONFIG_BLK_DEV_COW_COMMON is not set
+-CONFIG_BLK_DEV_LOOP=y
+-# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+-# CONFIG_BLK_DEV_NBD is not set
+-# CONFIG_BLK_DEV_SX8 is not set
+-CONFIG_BLK_DEV_RAM=y
+-CONFIG_BLK_DEV_RAM_COUNT=16
+-CONFIG_BLK_DEV_RAM_SIZE=4096
+-CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+-# CONFIG_CDROM_PKTCDVD is not set
+-# CONFIG_ATA_OVER_ETH is not set
+-CONFIG_MISC_DEVICES=y
+-# CONFIG_PHANTOM is not set
+-# CONFIG_EEPROM_93CX6 is not set
+-# CONFIG_SGI_IOC4 is not set
+-# CONFIG_TIFM_CORE is not set
+-# 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=y
+-# 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_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_STEX is not set
+-CONFIG_SCSI_SYM53C8XX_2=y
+-CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=0
+-CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16
+-CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64
+-CONFIG_SCSI_SYM53C8XX_MMIO=y
+-# 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_ATA 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_IP1000 is not set
+-# CONFIG_ARCNET is not set
+-# CONFIG_PHYLIB is not set
+-CONFIG_NET_ETHERNET=y
+-# CONFIG_MII is not set
+-# CONFIG_STNIC is not set
+-# CONFIG_HAPPYMEAL is not set
+-# CONFIG_SUNGEM is not set
+-# CONFIG_CASSINI is not set
+-# CONFIG_NET_VENDOR_3COM is not set
+-# CONFIG_SMC91X is not set
+-# CONFIG_SMC911X is not set
+-CONFIG_NET_TULIP=y
+-# CONFIG_DE2104X is not set
+-CONFIG_TULIP=y
+-# CONFIG_TULIP_MWI is not set
+-# CONFIG_TULIP_MMIO is not set
+-# CONFIG_TULIP_NAPI is not set
+-# CONFIG_DE4X5 is not set
+-# CONFIG_WINBOND_840 is not set
+-# CONFIG_DM9102 is not set
+-# CONFIG_ULI526X 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 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=y
+-# CONFIG_ACENIC is not set
+-# CONFIG_DL2K is not set
+-# CONFIG_E1000 is not set
+-# CONFIG_E1000E is not set
+-# CONFIG_NS83820 is not set
+-# CONFIG_HAMACHI is not set
+-# CONFIG_YELLOWFIN is not set
+-# CONFIG_R8169 is not set
+-# CONFIG_SIS190 is not set
+-# CONFIG_SKGE is not set
+-# CONFIG_SKY2 is not set
+-# CONFIG_SK98LIN is not set
+-# CONFIG_VIA_VELOCITY is not set
+-# CONFIG_TIGON3 is not set
+-# CONFIG_BNX2 is not set
+-# CONFIG_QLA3XXX is not set
+-# CONFIG_ATL1 is not set
+-CONFIG_NETDEV_10000=y
+-# CONFIG_CHELSIO_T1 is not set
+-# CONFIG_CHELSIO_T3 is not set
+-# CONFIG_IXGBE is not set
+-# CONFIG_IXGB is not set
+-# CONFIG_S2IO is not set
+-# CONFIG_MYRI10GE is not set
+-# CONFIG_NETXEN_NIC is not set
+-# CONFIG_NIU is not set
+-# CONFIG_MLX4_CORE is not set
+-# CONFIG_TEHUTI is not set
+-# CONFIG_TR is not set
+-
+-#
+-# Wireless LAN
+-#
+-# CONFIG_WLAN_PRE80211 is not set
+-# CONFIG_WLAN_80211 is not set
+-# CONFIG_WAN is not set
+-# CONFIG_FDDI is not set
+-# CONFIG_HIPPI is not set
+-# CONFIG_PPP is not set
+-# CONFIG_SLIP is not set
+-# CONFIG_NET_FC is not set
+-# CONFIG_SHAPER is not set
+-# CONFIG_NETCONSOLE is not set
+-# CONFIG_NETPOLL is not set
+-# CONFIG_NET_POLL_CONTROLLER is not set
+-# 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=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 is not set
+-# CONFIG_INPUT_EVBUG 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_INPUT_MOUSE=y
+-CONFIG_MOUSE_PS2=y
+-CONFIG_MOUSE_PS2_ALPS=y
+-CONFIG_MOUSE_PS2_LOGIPS2PP=y
+-CONFIG_MOUSE_PS2_SYNAPTICS=y
+-CONFIG_MOUSE_PS2_LIFEBOOK=y
+-CONFIG_MOUSE_PS2_TRACKPOINT=y
+-# CONFIG_MOUSE_PS2_TOUCHKIT is not set
+-# CONFIG_MOUSE_SERIAL is not set
+-# CONFIG_MOUSE_APPLETOUCH is not set
+-# CONFIG_MOUSE_VSXXXAA 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=y
+-CONFIG_SERIO_I8042=y
+-CONFIG_SERIO_SERPORT=y
+-# 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_SERIAL_NONSTANDARD is not set
+-
+-#
+-# Serial drivers
+-#
+-# CONFIG_SERIAL_8250 is not set
+-
+-#
+-# Non-8250 serial port support
+-#
+-CONFIG_SERIAL_SH_SCI=y
+-CONFIG_SERIAL_SH_SCI_NR_UARTS=2
+-CONFIG_SERIAL_SH_SCI_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=256
+-# CONFIG_IPMI_HANDLER is not set
+-CONFIG_HW_RANDOM=y
+-# CONFIG_R3964 is not set
+-# CONFIG_APPLICOM is not set
+-# CONFIG_RAW_DRIVER is not set
+-# CONFIG_TCG_TPM is not set
+-CONFIG_DEVPORT=y
+-CONFIG_I2C=m
+-CONFIG_I2C_BOARDINFO=y
+-# CONFIG_I2C_CHARDEV is not set
+-
+-#
+-# I2C Algorithms
+-#
+-# CONFIG_I2C_ALGOBIT is not set
+-# CONFIG_I2C_ALGOPCF is not set
+-# CONFIG_I2C_ALGOPCA is not set
+-
+-#
+-# I2C Hardware Bus support
+-#
+-# CONFIG_I2C_ALI1535 is not set
+-# CONFIG_I2C_ALI1563 is not set
+-# CONFIG_I2C_ALI15X3 is not set
+-# CONFIG_I2C_AMD756 is not set
+-# CONFIG_I2C_AMD8111 is not set
+-# CONFIG_I2C_I801 is not set
+-# CONFIG_I2C_I810 is not set
+-# CONFIG_I2C_PIIX4 is not set
+-# CONFIG_I2C_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_VIA is not set
+-# CONFIG_I2C_VIAPRO is not set
+-# CONFIG_I2C_VOODOO3 is not set
+-
+-#
+-# Miscellaneous I2C Chip support
+-#
+-# CONFIG_SENSORS_DS1337 is not set
+-# CONFIG_SENSORS_DS1374 is not set
+-# CONFIG_DS1682 is not set
+-# CONFIG_SENSORS_EEPROM is not set
+-# CONFIG_SENSORS_PCF8574 is not set
+-# CONFIG_SENSORS_PCA9539 is not set
+-# CONFIG_SENSORS_PCF8591 is not set
+-# CONFIG_SENSORS_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
+-
+-#
+-# SPI support
+-#
+-# CONFIG_SPI is not set
+-# CONFIG_SPI_MASTER 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_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_SIS5595 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_THMC50 is not set
+-# CONFIG_SENSORS_VIA686A is not set
+-# CONFIG_SENSORS_VT1211 is not set
+-# CONFIG_SENSORS_VT8231 is not set
+-# CONFIG_SENSORS_W83781D is not set
+-# CONFIG_SENSORS_W83791D is not set
+-# CONFIG_SENSORS_W83792D is not set
+-# CONFIG_SENSORS_W83793 is not set
+-# CONFIG_SENSORS_W83L785TS is not set
+-# CONFIG_SENSORS_W83627HF is not set
+-# CONFIG_SENSORS_W83627EHF is not set
+-# CONFIG_HWMON_DEBUG_CHIP is not set
+-CONFIG_WATCHDOG=y
+-# CONFIG_WATCHDOG_NOWAYOUT is not set
+-
+-#
+-# Watchdog Device Drivers
+-#
+-# CONFIG_SOFT_WATCHDOG is not set
+-
+-#
+-# PCI-based Watchdog Cards
+-#
+-# CONFIG_PCIPCWATCHDOG is not set
+-# CONFIG_WDTPCI is not set
+-
+-#
+-# Sonics Silicon Backplane
+-#
+-CONFIG_SSB_POSSIBLE=y
+-# CONFIG_SSB is not set
+-
+-#
+-# Multifunction device drivers
+-#
+-# CONFIG_MFD_SM501 is not set
+-
+-#
+-# Multimedia devices
+-#
+-CONFIG_VIDEO_DEV=m
+-# CONFIG_VIDEO_V4L1 is not set
+-# CONFIG_VIDEO_V4L1_COMPAT is not set
+-CONFIG_VIDEO_V4L2=y
+-CONFIG_VIDEO_CAPTURE_DRIVERS=y
+-# CONFIG_VIDEO_ADV_DEBUG is not set
+-CONFIG_VIDEO_HELPER_CHIPS_AUTO=y
+-# CONFIG_VIDEO_VIVI is not set
+-# CONFIG_VIDEO_SAA5246A is not set
+-# CONFIG_VIDEO_SAA5249 is not set
+-# CONFIG_VIDEO_SAA7134 is not set
+-# CONFIG_VIDEO_HEXIUM_ORION is not set
+-# CONFIG_VIDEO_HEXIUM_GEMINI is not set
+-# CONFIG_VIDEO_CX88 is not set
+-# CONFIG_VIDEO_CX23885 is not set
+-# CONFIG_VIDEO_CAFE_CCIC is not set
+-# CONFIG_RADIO_ADAPTERS is not set
+-CONFIG_DVB_CORE=y
+-# CONFIG_DVB_CORE_ATTACH is not set
+-CONFIG_DVB_CAPTURE_DRIVERS=y
+-
+-#
+-# Supported SAA7146 based PCI Adapters
+-#
+-
+-#
+-# Supported FlexCopII (B2C2) Adapters
+-#
+-# CONFIG_DVB_B2C2_FLEXCOP is not set
+-
+-#
+-# Supported BT878 Adapters
+-#
+-
+-#
+-# Supported Pluto2 Adapters
+-#
+-# CONFIG_DVB_PLUTO2 is not set
+-
+-#
+-# Supported DVB Frontends
+-#
+-
+-#
+-# Customise DVB Frontends
+-#
+-# CONFIG_DVB_FE_CUSTOMISE is not set
+-
+-#
+-# DVB-S (satellite) frontends
+-#
+-# CONFIG_DVB_STV0299 is not set
+-# CONFIG_DVB_CX24110 is not set
+-# CONFIG_DVB_CX24123 is not set
+-# CONFIG_DVB_TDA8083 is not set
+-# CONFIG_DVB_MT312 is not set
+-# CONFIG_DVB_VES1X93 is not set
+-# CONFIG_DVB_S5H1420 is not set
+-# CONFIG_DVB_TDA10086 is not set
+-
+-#
+-# DVB-T (terrestrial) frontends
+-#
+-# CONFIG_DVB_SP8870 is not set
+-# CONFIG_DVB_SP887X is not set
+-# CONFIG_DVB_CX22700 is not set
+-# CONFIG_DVB_CX22702 is not set
+-# CONFIG_DVB_L64781 is not set
+-# CONFIG_DVB_TDA1004X is not set
+-# CONFIG_DVB_NXT6000 is not set
+-# CONFIG_DVB_MT352 is not set
+-# CONFIG_DVB_ZL10353 is not set
+-# CONFIG_DVB_DIB3000MB is not set
+-# CONFIG_DVB_DIB3000MC is not set
+-# CONFIG_DVB_DIB7000M is not set
+-# CONFIG_DVB_DIB7000P is not set
+-
+-#
+-# DVB-C (cable) frontends
+-#
+-# CONFIG_DVB_VES1820 is not set
+-# CONFIG_DVB_TDA10021 is not set
+-# CONFIG_DVB_TDA10023 is not set
+-# CONFIG_DVB_STV0297 is not set
+-
+-#
+-# ATSC (North American/Korean Terrestrial/Cable DTV) frontends
+-#
+-# CONFIG_DVB_NXT200X is not set
+-# CONFIG_DVB_OR51211 is not set
+-# CONFIG_DVB_OR51132 is not set
+-# CONFIG_DVB_BCM3510 is not set
+-# CONFIG_DVB_LGDT330X is not set
+-# CONFIG_DVB_S5H1409 is not set
+-
+-#
+-# Tuners/PLL support
+-#
+-# CONFIG_DVB_PLL is not set
+-# CONFIG_DVB_TDA826X is not set
+-# CONFIG_DVB_TDA827X is not set
+-# CONFIG_DVB_TUNER_QT1010 is not set
+-# CONFIG_DVB_TUNER_MT2060 is not set
+-# CONFIG_DVB_TUNER_MT2266 is not set
+-# CONFIG_DVB_TUNER_MT2131 is not set
+-# CONFIG_DVB_TUNER_DIB0070 is not set
+-
+-#
+-# Miscellaneous devices
+-#
+-# CONFIG_DVB_LNBP21 is not set
+-# CONFIG_DVB_ISL6421 is not set
+-# CONFIG_DVB_TUA6100 is not set
+-CONFIG_DAB=y
+-
+-#
+-# Graphics support
+-#
+-# CONFIG_DRM is not set
+-# CONFIG_VGASTATE is not set
+-CONFIG_VIDEO_OUTPUT_CONTROL=y
+-CONFIG_FB=y
+-CONFIG_FIRMWARE_EDID=y
+-# 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_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=y
+-# 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=y
+-# 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_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_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 is not set
+-CONFIG_FONT_8x16=y
+-# 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=y
+-# CONFIG_LOGO_LINUX_MONO is not set
+-# CONFIG_LOGO_LINUX_VGA16 is not set
+-# CONFIG_LOGO_LINUX_CLUT224 is not set
+-# CONFIG_LOGO_SUPERH_MONO is not set
+-# CONFIG_LOGO_SUPERH_VGA16 is not set
+-CONFIG_LOGO_SUPERH_CLUT224=y
+-
+-#
+-# Sound
+-#
+-# CONFIG_SOUND is not set
+-CONFIG_HID_SUPPORT=y
+-CONFIG_HID=y
+-# CONFIG_HID_DEBUG is not set
+-# CONFIG_HIDRAW 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 is not set
+-
+-#
+-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+-#
+-
+-#
+-# USB Gadget Support
+-#
+-# CONFIG_USB_GADGET is not set
+-# CONFIG_MMC is not set
+-# CONFIG_NEW_LEDS is not set
+-# CONFIG_INFINIBAND is not set
+-# CONFIG_RTC_CLASS is not set
+-
+-#
+-# Userspace I/O
+-#
+-# 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_JBD_DEBUG is not set
+-CONFIG_FS_MBCACHE=y
+-# CONFIG_REISERFS_FS is not set
+-# CONFIG_JFS_FS is not set
+-# CONFIG_FS_POSIX_ACL is not set
+-# CONFIG_XFS_FS is not set
+-# CONFIG_GFS2_FS is not set
+-# CONFIG_OCFS2_FS is not set
+-CONFIG_MINIX_FS=y
+-CONFIG_ROMFS_FS=y
+-CONFIG_INOTIFY=y
+-CONFIG_INOTIFY_USER=y
+-# CONFIG_QUOTA is not set
+-CONFIG_DNOTIFY=y
+-# CONFIG_AUTOFS_FS is not set
+-# CONFIG_AUTOFS4_FS is not set
+-# CONFIG_FUSE_FS is not set
+-
+-#
+-# CD-ROM/DVD Filesystems
+-#
+-# CONFIG_ISO9660_FS is not set
+-# CONFIG_UDF_FS is not set
+-
+-#
+-# DOS/FAT/NT Filesystems
+-#
+-# CONFIG_MSDOS_FS is not set
+-# CONFIG_VFAT_FS is not set
+-# CONFIG_NTFS_FS is not set
+-
+-#
+-# Pseudo filesystems
+-#
+-CONFIG_PROC_FS=y
+-CONFIG_PROC_KCORE=y
+-CONFIG_PROC_SYSCTL=y
+-CONFIG_SYSFS=y
+-CONFIG_TMPFS=y
+-# CONFIG_TMPFS_POSIX_ACL is not set
+-CONFIG_HUGETLBFS=y
+-CONFIG_HUGETLB_PAGE=y
+-# CONFIG_CONFIGFS_FS is not set
+-
+-#
+-# Miscellaneous filesystems
+-#
+-# CONFIG_ADFS_FS is not set
+-# CONFIG_AFFS_FS is not set
+-# CONFIG_HFS_FS is not set
+-# CONFIG_HFSPLUS_FS is not set
+-# CONFIG_BEFS_FS is not set
+-# CONFIG_BFS_FS is not set
+-# CONFIG_EFS_FS is not set
+-# CONFIG_CRAMFS is not set
+-# CONFIG_VXFS_FS is not set
+-# CONFIG_HPFS_FS is not set
+-# CONFIG_QNX4FS_FS is not set
+-# CONFIG_SYSV_FS is not set
+-# CONFIG_UFS_FS is not set
+-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_NFS_DIRECTIO is not set
+-# CONFIG_NFSD is not set
+-CONFIG_ROOT_NFS=y
+-CONFIG_LOCKD=y
+-CONFIG_LOCKD_V4=y
+-CONFIG_NFS_COMMON=y
+-CONFIG_SUNRPC=y
+-# CONFIG_SUNRPC_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 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 is not set
+-# CONFIG_DLM is not set
+-CONFIG_INSTRUMENTATION=y
+-# CONFIG_PROFILING is not set
+-# CONFIG_MARKERS is not set
+-
+-#
+-# Kernel hacking
+-#
+-# CONFIG_PRINTK_TIME is not set
+-CONFIG_ENABLE_WARN_DEPRECATED=y
+-CONFIG_ENABLE_MUST_CHECK=y
+-CONFIG_MAGIC_SYSRQ=y
+-# 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=y
+-CONFIG_SCHED_DEBUG=y
+-CONFIG_SCHEDSTATS=y
+-# CONFIG_TIMER_STATS 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 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_LIST is not set
+-# CONFIG_DEBUG_SG is not set
+-CONFIG_FRAME_POINTER=y
+-CONFIG_FORCED_INLINING=y
+-# CONFIG_BOOT_PRINTK_DELAY is not set
+-# CONFIG_RCU_TORTURE_TEST is not set
+-# CONFIG_FAULT_INJECTION is not set
+-# CONFIG_SAMPLES is not set
+-# CONFIG_EARLY_PRINTK is not set
+-CONFIG_SH64_PROC_TLB=y
+-CONFIG_SH64_PROC_ASIDS=y
+-CONFIG_SH64_SR_WATCH=y
+-# CONFIG_POOR_MANS_STRACE is not set
+-# CONFIG_SH_ALPHANUMERIC is not set
+-# CONFIG_SH_NO_BSS_INIT 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_CRC_CCITT is not set
+-# 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_PLIST=y
+-CONFIG_HAS_IOMEM=y
+-CONFIG_HAS_IOPORT=y
+-CONFIG_HAS_DMA=y
+diff --git a/arch/sh64/configs/harp_defconfig b/arch/sh64/configs/harp_defconfig
+deleted file mode 100644
+index ba302cd..0000000
+--- a/arch/sh64/configs/harp_defconfig
++++ /dev/null
+@@ -1,745 +0,0 @@
+-#
+-# Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.24-rc1
+-# Fri Nov  2 14:35:57 2007
+-#
+-CONFIG_SUPERH=y
+-CONFIG_SUPERH64=y
+-CONFIG_MMU=y
+-CONFIG_QUICKLIST=y
+-CONFIG_RWSEM_GENERIC_SPINLOCK=y
+-CONFIG_GENERIC_FIND_NEXT_BIT=y
+-CONFIG_GENERIC_HWEIGHT=y
+-CONFIG_GENERIC_CALIBRATE_DELAY=y
+-CONFIG_GENERIC_HARDIRQS=y
+-CONFIG_GENERIC_IRQ_PROBE=y
+-# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+-# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+-CONFIG_ARCH_NO_VIRT_TO_BUS=y
+-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=y
+-CONFIG_SWAP=y
+-# CONFIG_SYSVIPC is not set
+-CONFIG_POSIX_MQUEUE=y
+-# CONFIG_BSD_PROCESS_ACCT is not set
+-# CONFIG_TASKSTATS is not set
+-# CONFIG_USER_NS is not set
+-# CONFIG_AUDIT is not set
+-# CONFIG_IKCONFIG is not set
+-CONFIG_LOG_BUF_SHIFT=14
+-# CONFIG_CGROUPS is not set
+-CONFIG_FAIR_GROUP_SCHED=y
+-CONFIG_FAIR_USER_SCHED=y
+-# CONFIG_FAIR_CGROUP_SCHED is not set
+-CONFIG_SYSFS_DEPRECATED=y
+-# CONFIG_RELAY is not set
+-# CONFIG_BLK_DEV_INITRD is not set
+-# 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_BASE_FULL=y
+-CONFIG_FUTEX=y
+-CONFIG_ANON_INODES=y
+-CONFIG_EPOLL=y
+-CONFIG_SIGNALFD=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_RT_MUTEXES=y
+-# CONFIG_TINY_SHMEM is not set
+-CONFIG_BASE_SMALL=0
+-# CONFIG_MODULES is not set
+-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"
+-
+-#
+-# System type
+-#
+-# CONFIG_SH_SIMULATOR is not set
+-# CONFIG_SH_CAYMAN is not set
+-CONFIG_SH_HARP=y
+-CONFIG_CPU_SH5=y
+-CONFIG_CPU_SUBTYPE_SH5_101=y
+-# CONFIG_CPU_SUBTYPE_SH5_103 is not set
+-CONFIG_LITTLE_ENDIAN=y
+-# CONFIG_BIG_ENDIAN is not set
+-CONFIG_SH_FPU=y
+-# CONFIG_SH64_FPU_DENORM_FLUSH is not set
+-CONFIG_SH64_PGTABLE_2_LEVEL=y
+-# CONFIG_SH64_PGTABLE_3_LEVEL is not set
+-CONFIG_HUGETLB_PAGE_SIZE_64K=y
+-# CONFIG_HUGETLB_PAGE_SIZE_1MB is not set
+-# CONFIG_HUGETLB_PAGE_SIZE_512MB is not set
+-CONFIG_SH64_USER_MISALIGNED_FIXUP=y
+-
+-#
+-# Memory options
+-#
+-CONFIG_CACHED_MEMORY_OFFSET=0x20000000
+-CONFIG_MEMORY_START=0x80000000
+-CONFIG_MEMORY_SIZE_IN_MB=128
+-
+-#
+-# Cache options
+-#
+-CONFIG_DCACHE_WRITE_BACK=y
+-# CONFIG_DCACHE_WRITE_THROUGH is not set
+-# CONFIG_DCACHE_DISABLED is not set
+-# CONFIG_ICACHE_DISABLED is not set
+-CONFIG_PCIDEVICE_MEMORY_START=C0000000
+-CONFIG_DEVICE_MEMORY_START=E0000000
+-CONFIG_FLASH_MEMORY_START=0x00000000
+-CONFIG_PCI_BLOCK_START=0x40000000
+-
+-#
+-# CPU Subtype specific options
+-#
+-CONFIG_SH64_ID2815_WORKAROUND=y
+-
+-#
+-# Misc options
+-#
+-# CONFIG_SH_DMA is not set
+-CONFIG_PREEMPT=y
+-CONFIG_SELECT_MEMORY_MODEL=y
+-CONFIG_FLATMEM_MANUAL=y
+-# CONFIG_DISCONTIGMEM_MANUAL is not set
+-# CONFIG_SPARSEMEM_MANUAL is not set
+-CONFIG_FLATMEM=y
+-CONFIG_FLAT_NODE_MEM_MAP=y
+-# CONFIG_SPARSEMEM_STATIC is not set
+-# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
+-CONFIG_SPLIT_PTLOCK_CPUS=4
+-# CONFIG_RESOURCES_64BIT is not set
+-CONFIG_ZONE_DMA_FLAG=0
+-CONFIG_NR_QUICK=1
+-
+-#
+-# 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=y
+-# CONFIG_BINFMT_MISC 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_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 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=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_INET6_XFRM_TUNNEL is not set
+-# CONFIG_INET6_TUNNEL 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_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_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_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=y
+-CONFIG_BLK_DEV_RAM_COUNT=16
+-CONFIG_BLK_DEV_RAM_SIZE=4096
+-CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+-# CONFIG_CDROM_PKTCDVD is not set
+-# CONFIG_ATA_OVER_ETH is not set
+-CONFIG_MISC_DEVICES=y
+-# CONFIG_EEPROM_93CX6 is not set
+-# 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
+-
+-#
+-# SCSI Transports
+-#
+-CONFIG_SCSI_SPI_ATTRS=y
+-# 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_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 is not set
+-CONFIG_NET_ETHERNET=y
+-# CONFIG_MII is not set
+-# CONFIG_STNIC is not set
+-# CONFIG_SMC91X is not set
+-# 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=y
+-CONFIG_NETDEV_10000=y
+-
+-#
+-# Wireless LAN
+-#
+-# CONFIG_WLAN_PRE80211 is not set
+-# CONFIG_WLAN_80211 is not set
+-# CONFIG_WAN is not set
+-# CONFIG_PPP is not set
+-# CONFIG_SLIP is not set
+-# CONFIG_SHAPER is not set
+-# CONFIG_NETCONSOLE is not set
+-# CONFIG_NETPOLL is not set
+-# CONFIG_NET_POLL_CONTROLLER is not set
+-# 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=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_VT_CONSOLE=y
+-CONFIG_HW_CONSOLE=y
+-# CONFIG_VT_HW_CONSOLE_BINDING is not set
+-# CONFIG_SERIAL_NONSTANDARD is not set
+-
+-#
+-# Serial drivers
+-#
+-# CONFIG_SERIAL_8250 is not set
+-
+-#
+-# Non-8250 serial port support
+-#
+-CONFIG_SERIAL_SH_SCI=y
+-CONFIG_SERIAL_SH_SCI_NR_UARTS=2
+-CONFIG_SERIAL_SH_SCI_CONSOLE=y
+-CONFIG_SERIAL_CORE=y
+-CONFIG_SERIAL_CORE_CONSOLE=y
+-CONFIG_UNIX98_PTYS=y
+-CONFIG_LEGACY_PTYS=y
+-CONFIG_LEGACY_PTY_COUNT=256
+-# 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 is not set
+-
+-#
+-# SPI support
+-#
+-# CONFIG_SPI is not set
+-# CONFIG_SPI_MASTER 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_F71805F is not set
+-# CONFIG_SENSORS_F71882FG is not set
+-# CONFIG_SENSORS_IT87 is not set
+-# CONFIG_SENSORS_PC87360 is not set
+-# CONFIG_SENSORS_PC87427 is not set
+-# CONFIG_SENSORS_SMSC47M1 is not set
+-# CONFIG_SENSORS_SMSC47B397 is not set
+-# CONFIG_SENSORS_VT1211 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
+-
+-#
+-# Sonics Silicon Backplane
+-#
+-CONFIG_SSB_POSSIBLE=y
+-# CONFIG_SSB is not set
+-
+-#
+-# Multifunction device drivers
+-#
+-# CONFIG_MFD_SM501 is not set
+-
+-#
+-# Multimedia devices
+-#
+-# CONFIG_VIDEO_DEV is not set
+-# CONFIG_DVB_CORE is not set
+-CONFIG_DAB=y
+-
+-#
+-# Graphics support
+-#
+-# CONFIG_VGASTATE is not set
+-CONFIG_VIDEO_OUTPUT_CONTROL=y
+-CONFIG_FB=y
+-CONFIG_FIRMWARE_EDID=y
+-# CONFIG_FB_DDC is not set
+-# CONFIG_FB_CFB_FILLRECT is not set
+-# CONFIG_FB_CFB_COPYAREA is not set
+-# CONFIG_FB_CFB_IMAGEBLIT is not set
+-# 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_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=y
+-# CONFIG_FB_TILEBLITTING is not set
+-
+-#
+-# Frame buffer hardware drivers
+-#
+-# CONFIG_FB_S1D13XXX 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_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 is not set
+-CONFIG_FONT_8x16=y
+-# 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=y
+-# CONFIG_LOGO_LINUX_MONO is not set
+-# CONFIG_LOGO_LINUX_VGA16 is not set
+-# CONFIG_LOGO_LINUX_CLUT224 is not set
+-# CONFIG_LOGO_SUPERH_MONO is not set
+-# CONFIG_LOGO_SUPERH_VGA16 is not set
+-CONFIG_LOGO_SUPERH_CLUT224=y
+-
+-#
+-# Sound
+-#
+-# CONFIG_SOUND is not set
+-CONFIG_HID_SUPPORT=y
+-CONFIG_HID=y
+-# CONFIG_HID_DEBUG is not set
+-# CONFIG_HIDRAW 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 is not set
+-
+-#
+-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+-#
+-
+-#
+-# USB Gadget Support
+-#
+-# CONFIG_USB_GADGET is not set
+-# CONFIG_MMC is not set
+-# CONFIG_NEW_LEDS is not set
+-# CONFIG_RTC_CLASS is not set
+-
+-#
+-# Userspace I/O
+-#
+-# 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_JBD_DEBUG is not set
+-CONFIG_FS_MBCACHE=y
+-# CONFIG_REISERFS_FS is not set
+-# CONFIG_JFS_FS is not set
+-# CONFIG_FS_POSIX_ACL is not set
+-# CONFIG_XFS_FS is not set
+-# CONFIG_GFS2_FS is not set
+-# CONFIG_OCFS2_FS is not set
+-CONFIG_MINIX_FS=y
+-CONFIG_ROMFS_FS=y
+-CONFIG_INOTIFY=y
+-CONFIG_INOTIFY_USER=y
+-# CONFIG_QUOTA is not set
+-CONFIG_DNOTIFY=y
+-# CONFIG_AUTOFS_FS is not set
+-# CONFIG_AUTOFS4_FS is not set
+-# CONFIG_FUSE_FS is not set
+-
+-#
+-# CD-ROM/DVD Filesystems
+-#
+-# CONFIG_ISO9660_FS is not set
+-# CONFIG_UDF_FS is not set
+-
+-#
+-# DOS/FAT/NT Filesystems
+-#
+-# CONFIG_MSDOS_FS is not set
+-# CONFIG_VFAT_FS is not set
+-# CONFIG_NTFS_FS is not set
+-
+-#
+-# Pseudo filesystems
+-#
+-CONFIG_PROC_FS=y
+-CONFIG_PROC_KCORE=y
+-CONFIG_PROC_SYSCTL=y
+-CONFIG_SYSFS=y
+-CONFIG_TMPFS=y
+-# CONFIG_TMPFS_POSIX_ACL is not set
+-CONFIG_HUGETLBFS=y
+-CONFIG_HUGETLB_PAGE=y
+-# CONFIG_CONFIGFS_FS is not set
+-
+-#
+-# Miscellaneous filesystems
+-#
+-# CONFIG_ADFS_FS is not set
+-# CONFIG_AFFS_FS is not set
+-# CONFIG_HFS_FS is not set
+-# CONFIG_HFSPLUS_FS is not set
+-# CONFIG_BEFS_FS is not set
+-# CONFIG_BFS_FS is not set
+-# CONFIG_EFS_FS is not set
+-# CONFIG_CRAMFS is not set
+-# CONFIG_VXFS_FS is not set
+-# CONFIG_HPFS_FS is not set
+-# CONFIG_QNX4FS_FS is not set
+-# CONFIG_SYSV_FS is not set
+-# CONFIG_UFS_FS is not set
+-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_NFS_DIRECTIO is not set
+-# CONFIG_NFSD is not set
+-CONFIG_ROOT_NFS=y
+-CONFIG_LOCKD=y
+-CONFIG_LOCKD_V4=y
+-CONFIG_NFS_COMMON=y
+-CONFIG_SUNRPC=y
+-# CONFIG_SUNRPC_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 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 is not set
+-# CONFIG_DLM is not set
+-CONFIG_INSTRUMENTATION=y
+-# CONFIG_PROFILING is not set
+-# CONFIG_MARKERS is not set
+-
+-#
+-# Kernel hacking
+-#
+-# CONFIG_PRINTK_TIME is not set
+-CONFIG_ENABLE_WARN_DEPRECATED=y
+-CONFIG_ENABLE_MUST_CHECK=y
+-CONFIG_MAGIC_SYSRQ=y
+-# 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=y
+-CONFIG_SCHED_DEBUG=y
+-CONFIG_SCHEDSTATS=y
+-# CONFIG_TIMER_STATS 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 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_LIST is not set
+-# CONFIG_DEBUG_SG is not set
+-CONFIG_FRAME_POINTER=y
+-CONFIG_FORCED_INLINING=y
+-# CONFIG_BOOT_PRINTK_DELAY is not set
+-# CONFIG_FAULT_INJECTION is not set
+-# CONFIG_SAMPLES is not set
+-# CONFIG_EARLY_PRINTK is not set
+-CONFIG_SH64_PROC_TLB=y
+-CONFIG_SH64_PROC_ASIDS=y
+-CONFIG_SH64_SR_WATCH=y
+-# CONFIG_POOR_MANS_STRACE is not set
+-# CONFIG_SH_NO_BSS_INIT 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_CRC_CCITT is not set
+-# 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_PLIST=y
+-CONFIG_HAS_IOMEM=y
+-CONFIG_HAS_IOPORT=y
+-CONFIG_HAS_DMA=y
+diff --git a/arch/sh64/configs/sim_defconfig b/arch/sh64/configs/sim_defconfig
+deleted file mode 100644
+index 18476cc..0000000
+--- a/arch/sh64/configs/sim_defconfig
++++ /dev/null
+@@ -1,558 +0,0 @@
+-#
+-# Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.24-rc1
+-# Fri Nov  2 14:36:08 2007
+-#
+-CONFIG_SUPERH=y
+-CONFIG_SUPERH64=y
+-CONFIG_MMU=y
+-CONFIG_QUICKLIST=y
+-CONFIG_RWSEM_GENERIC_SPINLOCK=y
+-CONFIG_GENERIC_FIND_NEXT_BIT=y
+-CONFIG_GENERIC_HWEIGHT=y
+-CONFIG_GENERIC_CALIBRATE_DELAY=y
+-CONFIG_GENERIC_HARDIRQS=y
+-CONFIG_GENERIC_IRQ_PROBE=y
+-# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+-# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+-CONFIG_ARCH_NO_VIRT_TO_BUS=y
+-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=y
+-CONFIG_SWAP=y
+-# CONFIG_SYSVIPC is not set
+-# CONFIG_BSD_PROCESS_ACCT is not set
+-# CONFIG_USER_NS is not set
+-# CONFIG_IKCONFIG is not set
+-CONFIG_LOG_BUF_SHIFT=14
+-# CONFIG_CGROUPS is not set
+-CONFIG_FAIR_GROUP_SCHED=y
+-CONFIG_FAIR_USER_SCHED=y
+-# CONFIG_FAIR_CGROUP_SCHED is not set
+-CONFIG_SYSFS_DEPRECATED=y
+-# CONFIG_RELAY is not set
+-# CONFIG_BLK_DEV_INITRD is not set
+-# 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_BASE_FULL=y
+-CONFIG_FUTEX=y
+-CONFIG_ANON_INODES=y
+-CONFIG_EPOLL=y
+-CONFIG_SIGNALFD=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_RT_MUTEXES=y
+-# CONFIG_TINY_SHMEM is not set
+-CONFIG_BASE_SMALL=0
+-# CONFIG_MODULES is not set
+-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"
+-
+-#
+-# System type
+-#
+-CONFIG_SH_SIMULATOR=y
+-# CONFIG_SH_CAYMAN is not set
+-# CONFIG_SH_HARP is not set
+-CONFIG_CPU_SH5=y
+-CONFIG_CPU_SUBTYPE_SH5_101=y
+-# CONFIG_CPU_SUBTYPE_SH5_103 is not set
+-CONFIG_LITTLE_ENDIAN=y
+-# CONFIG_BIG_ENDIAN is not set
+-CONFIG_SH_FPU=y
+-# CONFIG_SH64_FPU_DENORM_FLUSH is not set
+-CONFIG_SH64_PGTABLE_2_LEVEL=y
+-# CONFIG_SH64_PGTABLE_3_LEVEL is not set
+-CONFIG_HUGETLB_PAGE_SIZE_64K=y
+-# CONFIG_HUGETLB_PAGE_SIZE_1MB is not set
+-# CONFIG_HUGETLB_PAGE_SIZE_512MB is not set
+-CONFIG_SH64_USER_MISALIGNED_FIXUP=y
+-
+-#
+-# Memory options
+-#
+-CONFIG_CACHED_MEMORY_OFFSET=0x20000000
+-CONFIG_MEMORY_START=0x80000000
+-CONFIG_MEMORY_SIZE_IN_MB=128
+-
+-#
+-# Cache options
+-#
+-# CONFIG_DCACHE_WRITE_BACK is not set
+-# CONFIG_DCACHE_WRITE_THROUGH is not set
+-CONFIG_DCACHE_DISABLED=y
+-# CONFIG_ICACHE_DISABLED is not set
+-CONFIG_PCIDEVICE_MEMORY_START=C0000000
+-CONFIG_DEVICE_MEMORY_START=E0000000
+-CONFIG_FLASH_MEMORY_START=0x00000000
+-CONFIG_PCI_BLOCK_START=0x40000000
+-
+-#
+-# CPU Subtype specific options
+-#
+-CONFIG_SH64_ID2815_WORKAROUND=y
+-
+-#
+-# Misc options
+-#
+-# CONFIG_SH_DMA is not set
+-CONFIG_PREEMPT=y
+-CONFIG_SELECT_MEMORY_MODEL=y
+-CONFIG_FLATMEM_MANUAL=y
+-# CONFIG_DISCONTIGMEM_MANUAL is not set
+-# CONFIG_SPARSEMEM_MANUAL is not set
+-CONFIG_FLATMEM=y
+-CONFIG_FLAT_NODE_MEM_MAP=y
+-# CONFIG_SPARSEMEM_STATIC is not set
+-# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
+-CONFIG_SPLIT_PTLOCK_CPUS=4
+-# CONFIG_RESOURCES_64BIT is not set
+-CONFIG_ZONE_DMA_FLAG=0
+-CONFIG_NR_QUICK=1
+-
+-#
+-# 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=y
+-# CONFIG_BINFMT_MISC is not set
+-
+-#
+-# Networking
+-#
+-# CONFIG_NET 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_DEBUG_DRIVER is not set
+-# CONFIG_DEBUG_DEVRES is not set
+-# CONFIG_SYS_HYPERVISOR is not set
+-# CONFIG_MTD is not set
+-# CONFIG_PARPORT is not set
+-# CONFIG_BLK_DEV is not set
+-# CONFIG_MISC_DEVICES is not set
+-# 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
+-
+-#
+-# SCSI Transports
+-#
+-CONFIG_SCSI_SPI_ATTRS=y
+-# CONFIG_SCSI_FC_ATTRS is not set
+-# CONFIG_SCSI_SAS_LIBSAS is not set
+-# CONFIG_SCSI_SRP_ATTRS is not set
+-CONFIG_SCSI_LOWLEVEL=y
+-# CONFIG_SCSI_DEBUG is not set
+-# CONFIG_ATA is not set
+-# CONFIG_MD 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=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_VT_CONSOLE=y
+-CONFIG_HW_CONSOLE=y
+-# CONFIG_VT_HW_CONSOLE_BINDING is not set
+-# CONFIG_SERIAL_NONSTANDARD is not set
+-
+-#
+-# Serial drivers
+-#
+-# CONFIG_SERIAL_8250 is not set
+-
+-#
+-# Non-8250 serial port support
+-#
+-CONFIG_SERIAL_SH_SCI=y
+-CONFIG_SERIAL_SH_SCI_NR_UARTS=2
+-CONFIG_SERIAL_SH_SCI_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_R3964 is not set
+-# CONFIG_RAW_DRIVER is not set
+-# CONFIG_TCG_TPM is not set
+-# CONFIG_I2C is not set
+-
+-#
+-# SPI support
+-#
+-# CONFIG_SPI is not set
+-# CONFIG_SPI_MASTER is not set
+-# 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
+-
+-#
+-# Multimedia devices
+-#
+-# CONFIG_VIDEO_DEV is not set
+-CONFIG_DAB=y
+-
+-#
+-# Graphics support
+-#
+-# CONFIG_VGASTATE is not set
+-CONFIG_VIDEO_OUTPUT_CONTROL=y
+-CONFIG_FB=y
+-CONFIG_FIRMWARE_EDID=y
+-# CONFIG_FB_DDC is not set
+-# CONFIG_FB_CFB_FILLRECT is not set
+-# CONFIG_FB_CFB_COPYAREA is not set
+-# CONFIG_FB_CFB_IMAGEBLIT is not set
+-# 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_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=y
+-# CONFIG_FB_TILEBLITTING is not set
+-
+-#
+-# Frame buffer hardware drivers
+-#
+-# CONFIG_FB_S1D13XXX 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_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 is not set
+-CONFIG_FONT_8x16=y
+-# 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=y
+-# CONFIG_LOGO_LINUX_MONO is not set
+-# CONFIG_LOGO_LINUX_VGA16 is not set
+-# CONFIG_LOGO_LINUX_CLUT224 is not set
+-# CONFIG_LOGO_SUPERH_MONO is not set
+-# CONFIG_LOGO_SUPERH_VGA16 is not set
+-CONFIG_LOGO_SUPERH_CLUT224=y
+-
+-#
+-# Sound
+-#
+-# CONFIG_SOUND is not set
+-# 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_CLASS is not set
+-
+-#
+-# Userspace I/O
+-#
+-# 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_JBD_DEBUG is not set
+-CONFIG_FS_MBCACHE=y
+-# CONFIG_REISERFS_FS is not set
+-# CONFIG_JFS_FS is not set
+-# CONFIG_FS_POSIX_ACL is not set
+-# CONFIG_XFS_FS is not set
+-# CONFIG_GFS2_FS is not set
+-CONFIG_MINIX_FS=y
+-CONFIG_ROMFS_FS=y
+-CONFIG_INOTIFY=y
+-CONFIG_INOTIFY_USER=y
+-# CONFIG_QUOTA is not set
+-CONFIG_DNOTIFY=y
+-# CONFIG_AUTOFS_FS is not set
+-# CONFIG_AUTOFS4_FS is not set
+-# CONFIG_FUSE_FS is not set
+-
+-#
+-# CD-ROM/DVD Filesystems
+-#
+-# CONFIG_ISO9660_FS is not set
+-# CONFIG_UDF_FS is not set
+-
+-#
+-# DOS/FAT/NT Filesystems
+-#
+-# CONFIG_MSDOS_FS is not set
+-# CONFIG_VFAT_FS is not set
+-# CONFIG_NTFS_FS is not set
+-
+-#
+-# Pseudo filesystems
+-#
+-CONFIG_PROC_FS=y
+-CONFIG_PROC_KCORE=y
+-CONFIG_PROC_SYSCTL=y
+-CONFIG_SYSFS=y
+-CONFIG_TMPFS=y
+-# CONFIG_TMPFS_POSIX_ACL is not set
+-CONFIG_HUGETLBFS=y
+-CONFIG_HUGETLB_PAGE=y
+-# CONFIG_CONFIGFS_FS is not set
+-
+-#
+-# Miscellaneous filesystems
+-#
+-# CONFIG_ADFS_FS is not set
+-# CONFIG_AFFS_FS is not set
+-# CONFIG_HFS_FS is not set
+-# CONFIG_HFSPLUS_FS is not set
+-# CONFIG_BEFS_FS is not set
+-# CONFIG_BFS_FS is not set
+-# CONFIG_EFS_FS is not set
+-# CONFIG_CRAMFS is not set
+-# CONFIG_VXFS_FS is not set
+-# CONFIG_HPFS_FS is not set
+-# CONFIG_QNX4FS_FS is not set
+-# CONFIG_SYSV_FS is not set
+-# CONFIG_UFS_FS is not set
+-
+-#
+-# 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 is not set
+-CONFIG_INSTRUMENTATION=y
+-CONFIG_PROFILING=y
+-# CONFIG_OPROFILE is not set
+-# CONFIG_MARKERS is not set
+-
+-#
+-# Kernel hacking
+-#
+-# CONFIG_PRINTK_TIME is not set
+-CONFIG_ENABLE_WARN_DEPRECATED=y
+-CONFIG_ENABLE_MUST_CHECK=y
+-CONFIG_MAGIC_SYSRQ=y
+-# 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=y
+-CONFIG_SCHED_DEBUG=y
+-CONFIG_SCHEDSTATS=y
+-# CONFIG_TIMER_STATS 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 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_LIST is not set
+-# CONFIG_DEBUG_SG is not set
+-CONFIG_FRAME_POINTER=y
+-CONFIG_FORCED_INLINING=y
+-# CONFIG_BOOT_PRINTK_DELAY is not set
+-# CONFIG_FAULT_INJECTION is not set
+-# CONFIG_SAMPLES is not set
+-# CONFIG_EARLY_PRINTK is not set
+-CONFIG_SH64_PROC_TLB=y
+-CONFIG_SH64_PROC_ASIDS=y
+-CONFIG_SH64_SR_WATCH=y
+-# CONFIG_POOR_MANS_STRACE is not set
+-CONFIG_SH_NO_BSS_INIT=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_CRC_CCITT is not set
+-# 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_PLIST=y
+-CONFIG_HAS_IOMEM=y
+-CONFIG_HAS_IOPORT=y
+-CONFIG_HAS_DMA=y
+diff --git a/arch/sh64/kernel/Makefile b/arch/sh64/kernel/Makefile
+deleted file mode 100644
+index e3467bd..0000000
+--- a/arch/sh64/kernel/Makefile
++++ /dev/null
+@@ -1,36 +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, 2001  Paolo Alberelli
+-# Copyright (C) 2003  Paul Mundt
+-#
+-# Makefile for the Linux sh64 kernel.
+-#
+-# Note! Dependencies are done automagically by 'make dep', which also
+-# removes any old dependencies. DON'T put your own dependencies here
+-# unless it's something special (ie not a .c file).
+-#
+-
+-extra-y	:= head.o init_task.o vmlinux.lds
+-
+-obj-y	:= process.o signal.o entry.o traps.o irq.o irq_intc.o \
+-	   ptrace.o setup.o time.o sys_sh64.o semaphore.o sh_ksyms.o \
+-	   switchto.o syscalls.o
+-
+-obj-$(CONFIG_HEARTBEAT)		+= led.o
+-obj-$(CONFIG_SH_ALPHANUMERIC)	+= alphanum.o
+-obj-$(CONFIG_SH_DMA)		+= dma.o
+-obj-$(CONFIG_SH_FPU)		+= fpu.o
+-obj-$(CONFIG_EARLY_PRINTK)	+= early_printk.o
+-obj-$(CONFIG_KALLSYMS)		+= unwind.o
+-obj-$(CONFIG_PCI)		+= pcibios.o
+-obj-$(CONFIG_MODULES)		+= module.o
+-
+-ifeq ($(CONFIG_PCI),y)
+-obj-$(CONFIG_CPU_SH5)		+= pci_sh5.o
+-endif
+-
+-USE_STANDARD_AS_RULE := true
+-
+diff --git a/arch/sh64/kernel/alphanum.c b/arch/sh64/kernel/alphanum.c
+deleted file mode 100644
+index d1619d9..0000000
+--- a/arch/sh64/kernel/alphanum.c
++++ /dev/null
+@@ -1,43 +0,0 @@
+-/*
+- * arch/sh64/kernel/alphanum.c
+- *
+- * Copyright (C) 2002 Stuart Menefy <stuart.menefy at st.com>
+- *
+- * May be copied or modified under the terms of the GNU General Public
+- * License.  See linux/COPYING for more information.
+- *
+- * Machine-independent functions for handling 8-digit alphanumeric display
+- * (e.g. Agilent HDSP-253x)
+- */
+-#include <linux/stddef.h>
+-#include <linux/sched.h>
+-
+-void mach_alphanum(int pos, unsigned char val);
+-
+-void print_seg(char *file, int line)
+-{
+-	int i;
+-	unsigned int nibble;
+-
+-	for (i = 0; i < 5; i++) {
+-		mach_alphanum(i, file[i]);
+-	}
+-
+-	for (i = 0; i < 3; i++) {
+-		nibble = ((line >> (i * 4)) & 0xf);
+-		mach_alphanum(7 - i, nibble + ((nibble > 9) ? 55 : 48));
+-	}
+-}
+-
+-void print_seg_num(unsigned num)
+-{
+-	int i;
+-	unsigned int nibble;
+-
+-	for (i = 0; i < 8; i++) {
+-		nibble = ((num >> (i * 4)) & 0xf);
+-
+-		mach_alphanum(7 - i, nibble + ((nibble > 9) ? 55 : 48));
+-	}
+-}
+-
+diff --git a/arch/sh64/kernel/asm-offsets.c b/arch/sh64/kernel/asm-offsets.c
+deleted file mode 100644
+index ca76537..0000000
+--- a/arch/sh64/kernel/asm-offsets.c
++++ /dev/null
+@@ -1,33 +0,0 @@
+-/*
+- * This program is used to generate definitions needed by
+- * assembly language modules.
+- *
+- * We use the technique used in the OSF Mach kernel code:
+- * generate asm statements containing #defines,
+- * compile this file to assembler, and then extract the
+- * #defines from the assembly-language output.
+- */
+-
+-#include <linux/stddef.h>
+-#include <linux/types.h>
+-#include <linux/mm.h>
+-#include <asm/thread_info.h>
+-
+-#define DEFINE(sym, val) \
+-        asm volatile("\n->" #sym " %0 " #val : : "i" (val))
+-
+-#define BLANK() asm volatile("\n->" : : )
+-
+-int main(void)
+-{
+-	/* offsets into the thread_info struct */
+-	DEFINE(TI_TASK,		offsetof(struct thread_info, task));
+-	DEFINE(TI_EXEC_DOMAIN,	offsetof(struct thread_info, exec_domain));
+-	DEFINE(TI_FLAGS,	offsetof(struct thread_info, flags));
+-	DEFINE(TI_PRE_COUNT,	offsetof(struct thread_info, preempt_count));
+-	DEFINE(TI_CPU,		offsetof(struct thread_info, cpu));
+-	DEFINE(TI_ADDR_LIMIT,	offsetof(struct thread_info, addr_limit));
+-	DEFINE(TI_RESTART_BLOCK,offsetof(struct thread_info, restart_block));
+-
+-	return 0;
+-}
+diff --git a/arch/sh64/kernel/dma.c b/arch/sh64/kernel/dma.c
+deleted file mode 100644
+index 32c6f05..0000000
+--- a/arch/sh64/kernel/dma.c
++++ /dev/null
+@@ -1,297 +0,0 @@
+-/*
+- * arch/sh64/kernel/dma.c
+- *
+- * DMA routines for the SH-5 DMAC.
+- *
+- * Copyright (C) 2003  Paul Mundt
+- *
+- * This file is subject to the terms and conditions of the GNU General Public
+- * License.  See the file "COPYING" in the main directory of this archive
+- * for more details.
+- */
+-#include <linux/init.h>
+-#include <linux/module.h>
+-#include <linux/interrupt.h>
+-#include <linux/types.h>
+-#include <linux/irq.h>
+-#include <linux/spinlock.h>
+-#include <linux/mm.h>
+-#include <asm/hardware.h>
+-#include <asm/dma.h>
+-#include <asm/signal.h>
+-#include <asm/errno.h>
+-#include <asm/io.h>
+-
+-typedef struct {
+-	unsigned long dev_addr;
+-	unsigned long mem_addr;
+-
+-	unsigned int mode;
+-	unsigned int count;
+-} dma_info_t;
+-
+-static dma_info_t dma_info[MAX_DMA_CHANNELS];
+-static DEFINE_SPINLOCK(dma_spin_lock);
+-
+-/* arch/sh64/kernel/irq_intc.c */
+-extern void make_intc_irq(unsigned int irq);
+-
+-/* DMAC Interrupts */
+-#define DMA_IRQ_DMTE0	18
+-#define DMA_IRQ_DERR	22
+-
+-#define DMAC_COMMON_BASE	(dmac_base + 0x08)
+-#define DMAC_SAR_BASE		(dmac_base + 0x10)
+-#define DMAC_DAR_BASE		(dmac_base + 0x18)
+-#define DMAC_COUNT_BASE		(dmac_base + 0x20)
+-#define DMAC_CTRL_BASE		(dmac_base + 0x28)
+-#define DMAC_STATUS_BASE	(dmac_base + 0x30)
+-
+-#define DMAC_SAR(n)	(DMAC_SAR_BASE    + ((n) * 0x28))
+-#define DMAC_DAR(n)	(DMAC_DAR_BASE    + ((n) * 0x28))
+-#define DMAC_COUNT(n)	(DMAC_COUNT_BASE  + ((n) * 0x28))
+-#define DMAC_CTRL(n)	(DMAC_CTRL_BASE   + ((n) * 0x28))
+-#define DMAC_STATUS(n)	(DMAC_STATUS_BASE + ((n) * 0x28))
+-
+-/* DMAC.COMMON Bit Definitions */
+-#define DMAC_COMMON_PR	0x00000001	/* Priority */
+-					/* Bits 1-2 Reserved */
+-#define DMAC_COMMON_ME	0x00000008	/* Master Enable */
+-#define DMAC_COMMON_NMI	0x00000010	/* NMI Flag */
+-					/* Bits 5-6 Reserved */
+-#define DMAC_COMMON_ER	0x00000780	/* Error Response */
+-#define DMAC_COMMON_AAE	0x00007800	/* Address Alignment Error */
+-					/* Bits 15-63 Reserved */
+-
+-/* DMAC.SAR Bit Definitions */
+-#define DMAC_SAR_ADDR	0xffffffff	/* Source Address */
+-
+-/* DMAC.DAR Bit Definitions */
+-#define DMAC_DAR_ADDR	0xffffffff	/* Destination Address */
+-
+-/* DMAC.COUNT Bit Definitions */
+-#define DMAC_COUNT_CNT	0xffffffff	/* Transfer Count */
+-
+-/* DMAC.CTRL Bit Definitions */
+-#define DMAC_CTRL_TS	0x00000007	/* Transfer Size */
+-#define DMAC_CTRL_SI	0x00000018	/* Source Increment */
+-#define DMAC_CTRL_DI	0x00000060	/* Destination Increment */
+-#define DMAC_CTRL_RS	0x00000780	/* Resource Select */
+-#define DMAC_CTRL_IE	0x00000800	/* Interrupt Enable */
+-#define DMAC_CTRL_TE	0x00001000	/* Transfer Enable */
+-					/* Bits 15-63 Reserved */
+-
+-/* DMAC.STATUS Bit Definitions */
+-#define DMAC_STATUS_TE	0x00000001	/* Transfer End */
+-#define DMAC_STATUS_AAE	0x00000002	/* Address Alignment Error */
+-					/* Bits 2-63 Reserved */
+-
+-static unsigned long dmac_base;
+-
+-void set_dma_count(unsigned int chan, unsigned int count);
+-void set_dma_addr(unsigned int chan, unsigned int addr);
+-
+-static irqreturn_t dma_mte(int irq, void *dev_id, struct pt_regs *regs)
+-{
+-	unsigned int chan = irq - DMA_IRQ_DMTE0;
+-	dma_info_t *info = dma_info + chan;
+-	u64 status;
+-
+-	if (info->mode & DMA_MODE_WRITE) {
+-		sh64_out64(info->mem_addr & DMAC_SAR_ADDR, DMAC_SAR(chan));
+-	} else {
+-		sh64_out64(info->mem_addr & DMAC_DAR_ADDR, DMAC_DAR(chan));
+-	}
+-
+-	set_dma_count(chan, info->count);
+-
+-	/* Clear the TE bit */
+-	status = sh64_in64(DMAC_STATUS(chan));
+-	status &= ~DMAC_STATUS_TE;
+-	sh64_out64(status, DMAC_STATUS(chan));
+-
+-	return IRQ_HANDLED;
+-}
+-
+-static struct irqaction irq_dmte = {
+-	.handler	= dma_mte,
+-	.flags		= IRQF_DISABLED,
+-	.name		= "DMA MTE",
+-};
+-
+-static irqreturn_t dma_err(int irq, void *dev_id, struct pt_regs *regs)
+-{
+-	u64 tmp;
+-	u8 chan;
+-
+-	printk(KERN_NOTICE "DMAC: Got a DMA Error!\n");
+-
+-	tmp = sh64_in64(DMAC_COMMON_BASE);
+-
+-	/* Check for the type of error */
+-	if ((chan = tmp & DMAC_COMMON_AAE)) {
+-		/* It's an address alignment error.. */
+-		printk(KERN_NOTICE "DMAC: Alignment error on channel %d, ", chan);
+-
+-		printk(KERN_NOTICE "SAR: 0x%08llx, DAR: 0x%08llx, COUNT: %lld\n",
+-		       (sh64_in64(DMAC_SAR(chan)) & DMAC_SAR_ADDR),
+-		       (sh64_in64(DMAC_DAR(chan)) & DMAC_DAR_ADDR),
+-		       (sh64_in64(DMAC_COUNT(chan)) & DMAC_COUNT_CNT));
+-
+-	} else if ((chan = tmp & DMAC_COMMON_ER)) {
+-		/* Something else went wrong.. */
+-		printk(KERN_NOTICE "DMAC: Error on channel %d\n", chan);
+-	}
+-
+-	/* Reset the ME bit to clear the interrupt */
+-	tmp |= DMAC_COMMON_ME;
+-	sh64_out64(tmp, DMAC_COMMON_BASE);
+-
+-	return IRQ_HANDLED;
+-}
+-
+-static struct irqaction irq_derr = {
+-	.handler	= dma_err,
+-	.flags		= IRQF_DISABLED,
+-	.name		= "DMA Error",
+-};
+-
+-static inline unsigned long calc_xmit_shift(unsigned int chan)
+-{
+-	return sh64_in64(DMAC_CTRL(chan)) & 0x03;
+-}
+-
+-void setup_dma(unsigned int chan, dma_info_t *info)
+-{
+-	unsigned int irq = DMA_IRQ_DMTE0 + chan;
+-	dma_info_t *dma = dma_info + chan;
+-
+-	make_intc_irq(irq);
+-	setup_irq(irq, &irq_dmte);
+-	dma = info;
+-}
+-
+-void enable_dma(unsigned int chan)
+-{
+-	u64 ctrl;
+-
+-	ctrl = sh64_in64(DMAC_CTRL(chan));
+-	ctrl |= DMAC_CTRL_TE;
+-	sh64_out64(ctrl, DMAC_CTRL(chan));
+-}
+-
+-void disable_dma(unsigned int chan)
+-{
+-	u64 ctrl;
+-
+-	ctrl = sh64_in64(DMAC_CTRL(chan));
+-	ctrl &= ~DMAC_CTRL_TE;
+-	sh64_out64(ctrl, DMAC_CTRL(chan));
+-}
+-
+-void set_dma_mode(unsigned int chan, char mode)
+-{
+-	dma_info_t *info = dma_info + chan;
+-
+-	info->mode = mode;
+-
+-	set_dma_addr(chan, info->mem_addr);
+-	set_dma_count(chan, info->count);
+-}
+-
+-void set_dma_addr(unsigned int chan, unsigned int addr)
+-{
+-	dma_info_t *info = dma_info + chan;
+-	unsigned long sar, dar;
+-
+-	info->mem_addr = addr;
+-	sar = (info->mode & DMA_MODE_WRITE) ? info->mem_addr : info->dev_addr;
+-	dar = (info->mode & DMA_MODE_WRITE) ? info->dev_addr : info->mem_addr;
+-
+-	sh64_out64(sar & DMAC_SAR_ADDR, DMAC_SAR(chan));
+-	sh64_out64(dar & DMAC_SAR_ADDR, DMAC_DAR(chan));
+-}
+-
+-void set_dma_count(unsigned int chan, unsigned int count)
+-{
+-	dma_info_t *info = dma_info + chan;
+-	u64 tmp;
+-
+-	info->count = count;
+-
+-	tmp = (info->count >> calc_xmit_shift(chan)) & DMAC_COUNT_CNT;
+-
+-	sh64_out64(tmp, DMAC_COUNT(chan));
+-}
+-
+-unsigned long claim_dma_lock(void)
+-{
+-	unsigned long flags;
+-
+-	spin_lock_irqsave(&dma_spin_lock, flags);
+-
+-	return flags;
+-}
+-
+-void release_dma_lock(unsigned long flags)
+-{
+-	spin_unlock_irqrestore(&dma_spin_lock, flags);
+-}
+-
+-int get_dma_residue(unsigned int chan)
+-{
+-	return sh64_in64(DMAC_COUNT(chan) << calc_xmit_shift(chan));
+-}
+-
+-int __init init_dma(void)
+-{
+-	struct vcr_info vcr;
+-	u64 tmp;
+-
+-	/* Remap the DMAC */
+-	dmac_base = onchip_remap(PHYS_DMAC_BLOCK, 1024, "DMAC");
+-	if (!dmac_base) {
+-		printk(KERN_ERR "Unable to remap DMAC\n");
+-		return -ENOMEM;
+-	}
+-
+-	/* Report DMAC.VCR Info */
+-	vcr = sh64_get_vcr_info(dmac_base);
+-	printk("DMAC: Module ID: 0x%04x, Module version: 0x%04x\n",
+-	       vcr.mod_id, vcr.mod_vers);
+-
+-	/* Set the ME bit */
+-	tmp = sh64_in64(DMAC_COMMON_BASE);
+-	tmp |= DMAC_COMMON_ME;
+-	sh64_out64(tmp, DMAC_COMMON_BASE);
+-
+-	/* Enable the DMAC Error Interrupt */
+-	make_intc_irq(DMA_IRQ_DERR);
+-	setup_irq(DMA_IRQ_DERR, &irq_derr);
+-
+-	return 0;
+-}
+-
+-static void __exit exit_dma(void)
+-{
+-	onchip_unmap(dmac_base);
+-	free_irq(DMA_IRQ_DERR, 0);
+-}
+-
+-module_init(init_dma);
+-module_exit(exit_dma);
+-
+-MODULE_AUTHOR("Paul Mundt");
+-MODULE_DESCRIPTION("DMA API for SH-5 DMAC");
+-MODULE_LICENSE("GPL");
+-
+-EXPORT_SYMBOL(setup_dma);
+-EXPORT_SYMBOL(claim_dma_lock);
+-EXPORT_SYMBOL(release_dma_lock);
+-EXPORT_SYMBOL(enable_dma);
+-EXPORT_SYMBOL(disable_dma);
+-EXPORT_SYMBOL(set_dma_mode);
+-EXPORT_SYMBOL(set_dma_addr);
+-EXPORT_SYMBOL(set_dma_count);
+-EXPORT_SYMBOL(get_dma_residue);
+-
+diff --git a/arch/sh64/kernel/early_printk.c b/arch/sh64/kernel/early_printk.c
+deleted file mode 100644
+index 4f91311..0000000
+--- a/arch/sh64/kernel/early_printk.c
++++ /dev/null
+@@ -1,99 +0,0 @@
+-/*
+- * arch/sh64/kernel/early_printk.c
+- *
+- * SH-5 Early SCIF console (cloned and hacked from sh implementation)
+- *
+- * Copyright (C) 2003, 2004  Paul Mundt <lethal at linux-sh.org>
+- * Copyright (C) 2002  M. R. Brown <mrbrown at 0xd6.org>
+- *
+- * 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/console.h>
+-#include <linux/tty.h>
+-#include <linux/init.h>
+-#include <asm/io.h>
+-#include <asm/hardware.h>
+-
+-#define SCIF_BASE_ADDR	0x01030000
+-#define SCIF_ADDR_SH5	PHYS_PERIPHERAL_BLOCK+SCIF_BASE_ADDR
+-
+-/*
+- * Fixed virtual address where SCIF is mapped (should already be done
+- * in arch/sh64/kernel/head.S!).
+- */
+-#define SCIF_REG	0xfa030000
+-
+-enum {
+-	SCIF_SCSMR2	= SCIF_REG + 0x00,
+-	SCIF_SCBRR2	= SCIF_REG + 0x04,
+-	SCIF_SCSCR2	= SCIF_REG + 0x08,
+-	SCIF_SCFTDR2	= SCIF_REG + 0x0c,
+-	SCIF_SCFSR2	= SCIF_REG + 0x10,
+-	SCIF_SCFRDR2	= SCIF_REG + 0x14,
+-	SCIF_SCFCR2	= SCIF_REG + 0x18,
+-	SCIF_SCFDR2	= SCIF_REG + 0x1c,
+-	SCIF_SCSPTR2	= SCIF_REG + 0x20,
+-	SCIF_SCLSR2	= SCIF_REG + 0x24,
+-};
+-
+-static void sh_console_putc(int c)
+-{
+-	while (!(ctrl_inw(SCIF_SCFSR2) & 0x20))
+-		cpu_relax();
+-
+-	ctrl_outb(c, SCIF_SCFTDR2);
+-	ctrl_outw((ctrl_inw(SCIF_SCFSR2) & 0x9f), SCIF_SCFSR2);
+-
+-	if (c == '\n')
+-		sh_console_putc('\r');
+-}
+-
+-static void sh_console_flush(void)
+-{
+-	ctrl_outw((ctrl_inw(SCIF_SCFSR2) & 0xbf), SCIF_SCFSR2);
+-
+-	while (!(ctrl_inw(SCIF_SCFSR2) & 0x40))
+-		cpu_relax();
+-
+-	ctrl_outw((ctrl_inw(SCIF_SCFSR2) & 0xbf), SCIF_SCFSR2);
+-}
+-
+-static void sh_console_write(struct console *con, const char *s, unsigned count)
+-{
+-	while (count-- > 0)
+-		sh_console_putc(*s++);
+-
+-	sh_console_flush();
+-}
+-
+-static int __init sh_console_setup(struct console *con, char *options)
+-{
+-	con->cflag = CREAD | HUPCL | CLOCAL | B19200 | CS8;
+-
+-	return 0;
+-}
+-
+-static struct console sh_console = {
+-	.name		= "scifcon",
+-	.write		= sh_console_write,
+-	.setup		= sh_console_setup,
+-	.flags		= CON_PRINTBUFFER | CON_BOOT,
+-	.index		= -1,
+-};
+-
+-void __init enable_early_printk(void)
+-{
+-	ctrl_outb(0x2a, SCIF_SCBRR2);	/* 19200bps */
+-
+-	ctrl_outw(0x04, SCIF_SCFCR2);	/* Reset TFRST */
+-	ctrl_outw(0x10, SCIF_SCFCR2);	/* TTRG0=1 */
+-
+-	ctrl_outw(0, SCIF_SCSPTR2);
+-	ctrl_outw(0x60, SCIF_SCFSR2);
+-	ctrl_outw(0, SCIF_SCLSR2);
+-	ctrl_outw(0x30, SCIF_SCSCR2);
+-
+-	register_console(&sh_console);
+-}
+diff --git a/arch/sh64/kernel/entry.S b/arch/sh64/kernel/entry.S
+deleted file mode 100644
+index 7013fcb..0000000
+--- a/arch/sh64/kernel/entry.S
++++ /dev/null
+@@ -1,2102 +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.
+- *
+- * arch/sh64/kernel/entry.S
+- *
+- * Copyright (C) 2000, 2001  Paolo Alberelli
+- * Copyright (C) 2004, 2005  Paul Mundt
+- * Copyright (C) 2003, 2004 Richard Curnow
+- *
+- */
+-
+-#include <linux/errno.h>
+-#include <linux/sys.h>
+-
+-#include <asm/processor.h>
+-#include <asm/registers.h>
+-#include <asm/unistd.h>
+-#include <asm/thread_info.h>
+-#include <asm/asm-offsets.h>
+-
+-/*
+- * SR fields.
+- */
+-#define SR_ASID_MASK	0x00ff0000
+-#define SR_FD_MASK	0x00008000
+-#define SR_SS		0x08000000
+-#define SR_BL		0x10000000
+-#define SR_MD		0x40000000
+-
+-/*
+- * Event code.
+- */
+-#define	EVENT_INTERRUPT		0
+-#define	EVENT_FAULT_TLB		1
+-#define	EVENT_FAULT_NOT_TLB	2
+-#define	EVENT_DEBUG		3
+-
+-/* EXPEVT values */
+-#define	RESET_CAUSE		0x20
+-#define DEBUGSS_CAUSE		0x980
+-
+-/*
+- * Frame layout. Quad index.
+- */
+-#define	FRAME_T(x)	FRAME_TBASE+(x*8)
+-#define	FRAME_R(x)	FRAME_RBASE+(x*8)
+-#define	FRAME_S(x)	FRAME_SBASE+(x*8)
+-#define FSPC		0
+-#define FSSR		1
+-#define FSYSCALL_ID	2
+-
+-/* Arrange the save frame to be a multiple of 32 bytes long */
+-#define FRAME_SBASE	0
+-#define FRAME_RBASE	(FRAME_SBASE+(3*8))	/* SYSCALL_ID - SSR - SPC */
+-#define FRAME_TBASE	(FRAME_RBASE+(63*8))	/* r0 - r62 */
+-#define FRAME_PBASE	(FRAME_TBASE+(8*8))	/* tr0 -tr7 */
+-#define	FRAME_SIZE	(FRAME_PBASE+(2*8))	/* pad0-pad1 */
+-
+-#define FP_FRAME_SIZE	FP_FRAME_BASE+(33*8)	/* dr0 - dr31 + fpscr */
+-#define FP_FRAME_BASE	0
+-
+-#define	SAVED_R2	0*8
+-#define	SAVED_R3	1*8
+-#define	SAVED_R4	2*8
+-#define	SAVED_R5	3*8
+-#define	SAVED_R18	4*8
+-#define	SAVED_R6	5*8
+-#define	SAVED_TR0	6*8
+-
+-/* These are the registers saved in the TLB path that aren't saved in the first
+-   level of the normal one. */
+-#define	TLB_SAVED_R25	7*8
+-#define	TLB_SAVED_TR1	8*8
+-#define	TLB_SAVED_TR2	9*8
+-#define	TLB_SAVED_TR3	10*8
+-#define	TLB_SAVED_TR4	11*8
+-/* Save R0/R1 : PT-migrating compiler currently dishounours -ffixed-r0 and -ffixed-r1 causing
+-   breakage otherwise. */
+-#define	TLB_SAVED_R0	12*8
+-#define	TLB_SAVED_R1	13*8
+-
+-#define CLI()				\
+-	getcon	SR, r6;			\
+-	ori	r6, 0xf0, r6;		\
+-	putcon	r6, SR;
+-
+-#define STI()				\
+-	getcon	SR, r6;			\
+-	andi	r6, ~0xf0, r6;		\
+-	putcon	r6, SR;
+-
+-#ifdef CONFIG_PREEMPT
+-#  define preempt_stop()	CLI()
+-#else
+-#  define preempt_stop()
+-#  define resume_kernel		restore_all
+-#endif
+-
+-	.section	.data, "aw"
+-
+-#define FAST_TLBMISS_STACK_CACHELINES 4
+-#define FAST_TLBMISS_STACK_QUADWORDS (4*FAST_TLBMISS_STACK_CACHELINES)
+-
+-/* Register back-up area for all exceptions */
+-	.balign	32
+-	/* Allow for 16 quadwords to be pushed by fast tlbmiss handling
+-	 * register saves etc. */
+-	.fill FAST_TLBMISS_STACK_QUADWORDS, 8, 0x0
+-/* This is 32 byte aligned by construction */
+-/* Register back-up area for all exceptions */
+-reg_save_area:
+-	.quad	0
+-	.quad	0
+-	.quad	0
+-	.quad	0
+-
+-	.quad	0
+-	.quad	0
+-	.quad	0
+-	.quad	0
+-
+-	.quad	0
+-	.quad	0
+-	.quad	0
+-	.quad	0
+-
+-	.quad	0
+-	.quad   0
+-
+-/* Save area for RESVEC exceptions. We cannot use reg_save_area because of
+- * reentrancy. Note this area may be accessed via physical address.
+- * Align so this fits a whole single cache line, for ease of purging.
+- */
+-	.balign 32,0,32
+-resvec_save_area:
+-	.quad	0
+-	.quad	0
+-	.quad	0
+-	.quad	0
+-	.quad	0
+-	.balign 32,0,32
+-
+-/* Jump table of 3rd level handlers  */
+-trap_jtable:
+-	.long	do_exception_error		/* 0x000 */
+-	.long	do_exception_error		/* 0x020 */
+-	.long	tlb_miss_load				/* 0x040 */
+-	.long	tlb_miss_store				/* 0x060 */
+-	! ARTIFICIAL pseudo-EXPEVT setting
+-	.long	do_debug_interrupt		/* 0x080 */
+-	.long	tlb_miss_load				/* 0x0A0 */
+-	.long	tlb_miss_store				/* 0x0C0 */
+-	.long	do_address_error_load	/* 0x0E0 */
+-	.long	do_address_error_store	/* 0x100 */
+-#ifdef CONFIG_SH_FPU
+-	.long	do_fpu_error		/* 0x120 */
+-#else
+-	.long	do_exception_error		/* 0x120 */
+-#endif
+-	.long	do_exception_error		/* 0x140 */
+-	.long	system_call				/* 0x160 */
+-	.long	do_reserved_inst		/* 0x180 */
+-	.long	do_illegal_slot_inst	/* 0x1A0 */
+-	.long	do_NMI			/* 0x1C0 */
+-	.long	do_exception_error		/* 0x1E0 */
+-	.rept 15
+-		.long do_IRQ		/* 0x200 - 0x3C0 */
+-	.endr
+-	.long	do_exception_error		/* 0x3E0 */
+-	.rept 32
+-		.long do_IRQ		/* 0x400 - 0x7E0 */
+-	.endr
+-	.long	fpu_error_or_IRQA			/* 0x800 */
+-	.long	fpu_error_or_IRQB			/* 0x820 */
+-	.long	do_IRQ			/* 0x840 */
+-	.long	do_IRQ			/* 0x860 */
+-	.rept 6
+-		.long do_exception_error	/* 0x880 - 0x920 */
+-	.endr
+-	.long	do_software_break_point	/* 0x940 */
+-	.long	do_exception_error		/* 0x960 */
+-	.long	do_single_step		/* 0x980 */
+-
+-	.rept 3
+-		.long do_exception_error	/* 0x9A0 - 0x9E0 */
+-	.endr
+-	.long	do_IRQ			/* 0xA00 */
+-	.long	do_IRQ			/* 0xA20 */
+-	.long	itlb_miss_or_IRQ			/* 0xA40 */
+-	.long	do_IRQ			/* 0xA60 */
+-	.long	do_IRQ			/* 0xA80 */
+-	.long	itlb_miss_or_IRQ			/* 0xAA0 */
+-	.long	do_exception_error		/* 0xAC0 */
+-	.long	do_address_error_exec	/* 0xAE0 */
+-	.rept 8
+-		.long do_exception_error	/* 0xB00 - 0xBE0 */
+-	.endr
+-	.rept 18
+-		.long do_IRQ		/* 0xC00 - 0xE20 */
+-	.endr
+-
+-	.section	.text64, "ax"
+-
+-/*
+- * --- Exception/Interrupt/Event Handling Section
+- */
+-
+-/*
+- * VBR and RESVEC blocks.
+- *
+- * First level handler for VBR-based exceptions.
+- *
+- * To avoid waste of space, align to the maximum text block size.
+- * This is assumed to be at most 128 bytes or 32 instructions.
+- * DO NOT EXCEED 32 instructions on the first level handlers !
+- *
+- * Also note that RESVEC is contained within the VBR block
+- * where the room left (1KB - TEXT_SIZE) allows placing
+- * the RESVEC block (at most 512B + TEXT_SIZE).
+- *
+- * So first (and only) level handler for RESVEC-based exceptions.
+- *
+- * Where the fault/interrupt is handled (not_a_tlb_miss, tlb_miss
+- * and interrupt) we are a lot tight with register space until
+- * saving onto the stack frame, which is done in handle_exception().
+- *
+- */
+-
+-#define	TEXT_SIZE 	128
+-#define	BLOCK_SIZE 	1664 		/* Dynamic check, 13*128 */
+-
+-	.balign TEXT_SIZE
+-LVBR_block:
+-	.space	256, 0			/* Power-on class handler, */
+-					/* not required here       */
+-not_a_tlb_miss:
+-	synco	/* TAKum03020 (but probably a good idea anyway.) */
+-	/* Save original stack pointer into KCR1 */
+-	putcon	SP, KCR1
+-
+-	/* Save other original registers into reg_save_area */
+-        movi  reg_save_area, SP
+-	st.q	SP, SAVED_R2, r2
+-	st.q	SP, SAVED_R3, r3
+-	st.q	SP, SAVED_R4, r4
+-	st.q	SP, SAVED_R5, r5
+-	st.q	SP, SAVED_R6, r6
+-	st.q	SP, SAVED_R18, r18
+-	gettr	tr0, r3
+-	st.q	SP, SAVED_TR0, r3
+-
+-	/* Set args for Non-debug, Not a TLB miss class handler */
+-	getcon	EXPEVT, r2
+-	movi	ret_from_exception, r3
+-	ori	r3, 1, r3
+-	movi	EVENT_FAULT_NOT_TLB, r4
+-	or	SP, ZERO, r5
+-	getcon	KCR1, SP
+-	pta	handle_exception, tr0
+-	blink	tr0, ZERO
+-
+-	.balign 256
+-	! VBR+0x200
+-	nop
+-	.balign 256
+-	! VBR+0x300
+-	nop
+-	.balign 256
+-	/*
+-	 * Instead of the natural .balign 1024 place RESVEC here
+-	 * respecting the final 1KB alignment.
+-	 */
+-	.balign TEXT_SIZE
+-	/*
+-	 * Instead of '.space 1024-TEXT_SIZE' place the RESVEC
+-	 * block making sure the final alignment is correct.
+-	 */
+-tlb_miss:
+-	synco	/* TAKum03020 (but probably a good idea anyway.) */
+-	putcon	SP, KCR1
+-	movi	reg_save_area, SP
+-	/* SP is guaranteed 32-byte aligned. */
+-	st.q	SP, TLB_SAVED_R0 , r0
+-	st.q	SP, TLB_SAVED_R1 , r1
+-	st.q	SP, SAVED_R2 , r2
+-	st.q	SP, SAVED_R3 , r3
+-	st.q	SP, SAVED_R4 , r4
+-	st.q	SP, SAVED_R5 , r5
+-	st.q	SP, SAVED_R6 , r6
+-	st.q	SP, SAVED_R18, r18
+-
+-	/* Save R25 for safety; as/ld may want to use it to achieve the call to
+-	 * the code in mm/tlbmiss.c */
+-	st.q	SP, TLB_SAVED_R25, r25
+-	gettr	tr0, r2
+-	gettr	tr1, r3
+-	gettr	tr2, r4
+-	gettr	tr3, r5
+-	gettr	tr4, r18
+-	st.q	SP, SAVED_TR0 , r2
+-	st.q	SP, TLB_SAVED_TR1 , r3
+-	st.q	SP, TLB_SAVED_TR2 , r4
+-	st.q	SP, TLB_SAVED_TR3 , r5
+-	st.q	SP, TLB_SAVED_TR4 , r18
+-
+-	pt	do_fast_page_fault, tr0
+-	getcon	SSR, r2
+-	getcon	EXPEVT, r3
+-	getcon	TEA, r4
+-	shlri	r2, 30, r2
+-	andi	r2, 1, r2	/* r2 = SSR.MD */
+-	blink 	tr0, LINK
+-
+-	pt	fixup_to_invoke_general_handler, tr1
+-
+-	/* If the fast path handler fixed the fault, just drop through quickly
+-	   to the restore code right away to return to the excepting context.
+-	   */
+-	beqi/u	r2, 0, tr1
+-
+-fast_tlb_miss_restore:
+-	ld.q	SP, SAVED_TR0, r2
+-	ld.q	SP, TLB_SAVED_TR1, r3
+-	ld.q	SP, TLB_SAVED_TR2, r4
+-
+-	ld.q	SP, TLB_SAVED_TR3, r5
+-	ld.q	SP, TLB_SAVED_TR4, r18
+-
+-	ptabs	r2, tr0
+-	ptabs	r3, tr1
+-	ptabs	r4, tr2
+-	ptabs	r5, tr3
+-	ptabs	r18, tr4
+-
+-	ld.q	SP, TLB_SAVED_R0, r0
+-	ld.q	SP, TLB_SAVED_R1, r1
+-	ld.q	SP, SAVED_R2, r2
+-	ld.q	SP, SAVED_R3, r3
+-	ld.q	SP, SAVED_R4, r4
+-	ld.q	SP, SAVED_R5, r5
+-	ld.q	SP, SAVED_R6, r6
+-	ld.q	SP, SAVED_R18, r18
+-	ld.q	SP, TLB_SAVED_R25, r25
+-
+-	getcon	KCR1, SP
+-	rte
+-	nop /* for safety, in case the code is run on sh5-101 cut1.x */
+-
+-fixup_to_invoke_general_handler:
+-
+-	/* OK, new method.  Restore stuff that's not expected to get saved into
+-	   the 'first-level' reg save area, then just fall through to setting
+-	   up the registers and calling the second-level handler. */
+-
+-	/* 2nd level expects r2,3,4,5,6,18,tr0 to be saved.  So we must restore
+-	   r25,tr1-4 and save r6 to get into the right state.  */
+-
+-	ld.q	SP, TLB_SAVED_TR1, r3
+-	ld.q	SP, TLB_SAVED_TR2, r4
+-	ld.q	SP, TLB_SAVED_TR3, r5
+-	ld.q	SP, TLB_SAVED_TR4, r18
+-	ld.q	SP, TLB_SAVED_R25, r25
+-
+-	ld.q	SP, TLB_SAVED_R0, r0
+-	ld.q	SP, TLB_SAVED_R1, r1
+-
+-	ptabs/u	r3, tr1
+-	ptabs/u	r4, tr2
+-	ptabs/u	r5, tr3
+-	ptabs/u	r18, tr4
+-
+-	/* Set args for Non-debug, TLB miss class handler */
+-	getcon	EXPEVT, r2
+-	movi	ret_from_exception, r3
+-	ori	r3, 1, r3
+-	movi	EVENT_FAULT_TLB, r4
+-	or	SP, ZERO, r5
+-	getcon	KCR1, SP
+-	pta	handle_exception, tr0
+-	blink	tr0, ZERO
+-
+-/* NB TAKE GREAT CARE HERE TO ENSURE THAT THE INTERRUPT CODE
+-   DOES END UP AT VBR+0x600 */
+-	nop
+-	nop
+-	nop
+-	nop
+-	nop
+-	nop
+-
+-	.balign 256
+-	/* VBR + 0x600 */
+-
+-interrupt:
+-	synco	/* TAKum03020 (but probably a good idea anyway.) */
+-	/* Save original stack pointer into KCR1 */
+-	putcon	SP, KCR1
+-
+-	/* Save other original registers into reg_save_area */
+-        movi  reg_save_area, SP
+-	st.q	SP, SAVED_R2, r2
+-	st.q	SP, SAVED_R3, r3
+-	st.q	SP, SAVED_R4, r4
+-	st.q	SP, SAVED_R5, r5
+-	st.q	SP, SAVED_R6, r6
+-	st.q	SP, SAVED_R18, r18
+-	gettr	tr0, r3
+-	st.q	SP, SAVED_TR0, r3
+-
+-	/* Set args for interrupt class handler */
+-	getcon	INTEVT, r2
+-	movi	ret_from_irq, r3
+-	ori	r3, 1, r3
+-	movi	EVENT_INTERRUPT, r4
+-	or	SP, ZERO, r5
+-	getcon	KCR1, SP
+-	pta	handle_exception, tr0
+-	blink	tr0, ZERO
+-	.balign	TEXT_SIZE		/* let's waste the bare minimum */
+-
+-LVBR_block_end:				/* Marker. Used for total checking */
+-
+-	.balign 256
+-LRESVEC_block:
+-	/* Panic handler. Called with MMU off. Possible causes/actions:
+-	 * - Reset:		Jump to program start.
+-	 * - Single Step:	Turn off Single Step & return.
+-	 * - Others:		Call panic handler, passing PC as arg.
+-	 *			(this may need to be extended...)
+-	 */
+-reset_or_panic:
+-	synco	/* TAKum03020 (but probably a good idea anyway.) */
+-	putcon	SP, DCR
+-	/* First save r0-1 and tr0, as we need to use these */
+-	movi	resvec_save_area-CONFIG_CACHED_MEMORY_OFFSET, SP
+-	st.q	SP, 0, r0
+-	st.q	SP, 8, r1
+-	gettr	tr0, r0
+-	st.q	SP, 32, r0
+-
+-	/* Check cause */
+-	getcon	EXPEVT, r0
+-	movi	RESET_CAUSE, r1
+-	sub	r1, r0, r1		/* r1=0 if reset */
+-	movi	_stext-CONFIG_CACHED_MEMORY_OFFSET, r0
+-	ori	r0, 1, r0
+-	ptabs	r0, tr0
+-	beqi	r1, 0, tr0		/* Jump to start address if reset */
+-
+-	getcon	EXPEVT, r0
+-	movi	DEBUGSS_CAUSE, r1
+-	sub	r1, r0, r1		/* r1=0 if single step */
+-	pta	single_step_panic, tr0
+-	beqi	r1, 0, tr0		/* jump if single step */
+-
+-	/* Now jump to where we save the registers. */
+-	movi	panic_stash_regs-CONFIG_CACHED_MEMORY_OFFSET, r1
+-	ptabs	r1, tr0
+-	blink	tr0, r63
+-
+-single_step_panic:
+-	/* We are in a handler with Single Step set. We need to resume the
+-	 * handler, by turning on MMU & turning off Single Step. */
+-	getcon	SSR, r0
+-	movi	SR_MMU, r1
+-	or	r0, r1, r0
+-	movi	~SR_SS, r1
+-	and	r0, r1, r0
+-	putcon	r0, SSR
+-	/* Restore EXPEVT, as the rte won't do this */
+-	getcon	PEXPEVT, r0
+-	putcon	r0, EXPEVT
+-	/* Restore regs */
+-	ld.q	SP, 32, r0
+-	ptabs	r0, tr0
+-	ld.q	SP, 0, r0
+-	ld.q	SP, 8, r1
+-	getcon	DCR, SP
+-	synco
+-	rte
+-
+-
+-	.balign	256
+-debug_exception:
+-	synco	/* TAKum03020 (but probably a good idea anyway.) */
+-	/*
+-	 * Single step/software_break_point first level handler.
+-	 * Called with MMU off, so the first thing we do is enable it
+-	 * by doing an rte with appropriate SSR.
+-	 */
+-	putcon	SP, DCR
+-	/* Save SSR & SPC, together with R0 & R1, as we need to use 2 regs. */
+-	movi	resvec_save_area-CONFIG_CACHED_MEMORY_OFFSET, SP
+-
+-	/* With the MMU off, we are bypassing the cache, so purge any
+-         * data that will be made stale by the following stores.
+-         */
+-	ocbp	SP, 0
+-	synco
+-
+-	st.q	SP, 0, r0
+-	st.q	SP, 8, r1
+-	getcon	SPC, r0
+-	st.q	SP, 16, r0
+-	getcon	SSR, r0
+-	st.q	SP, 24, r0
+-
+-	/* Enable MMU, block exceptions, set priv mode, disable single step */
+-	movi	SR_MMU | SR_BL | SR_MD, r1
+-	or	r0, r1, r0
+-	movi	~SR_SS, r1
+-	and	r0, r1, r0
+-	putcon	r0, SSR
+-	/* Force control to debug_exception_2 when rte is executed */
+-	movi	debug_exeception_2, r0
+-	ori	r0, 1, r0      /* force SHmedia, just in case */
+-	putcon	r0, SPC
+-	getcon	DCR, SP
+-	synco
+-	rte
+-debug_exeception_2:
+-	/* Restore saved regs */
+-	putcon	SP, KCR1
+-	movi	resvec_save_area, SP
+-	ld.q	SP, 24, r0
+-	putcon	r0, SSR
+-	ld.q	SP, 16, r0
+-	putcon	r0, SPC
+-	ld.q	SP, 0, r0
+-	ld.q	SP, 8, r1
+-
+-	/* Save other original registers into reg_save_area */
+-        movi  reg_save_area, SP
+-	st.q	SP, SAVED_R2, r2
+-	st.q	SP, SAVED_R3, r3
+-	st.q	SP, SAVED_R4, r4
+-	st.q	SP, SAVED_R5, r5
+-	st.q	SP, SAVED_R6, r6
+-	st.q	SP, SAVED_R18, r18
+-	gettr	tr0, r3
+-	st.q	SP, SAVED_TR0, r3
+-
+-	/* Set args for debug class handler */
+-	getcon	EXPEVT, r2
+-	movi	ret_from_exception, r3
+-	ori	r3, 1, r3
+-	movi	EVENT_DEBUG, r4
+-	or	SP, ZERO, r5
+-	getcon	KCR1, SP
+-	pta	handle_exception, tr0
+-	blink	tr0, ZERO
+-
+-	.balign	256
+-debug_interrupt:
+-	/* !!! WE COME HERE IN REAL MODE !!! */
+-	/* Hook-up debug interrupt to allow various debugging options to be
+-	 * hooked into its handler. */
+-	/* Save original stack pointer into KCR1 */
+-	synco
+-	putcon	SP, KCR1
+-	movi	resvec_save_area-CONFIG_CACHED_MEMORY_OFFSET, SP
+-	ocbp	SP, 0
+-	ocbp	SP, 32
+-	synco
+-
+-	/* Save other original registers into reg_save_area thru real addresses */
+-	st.q	SP, SAVED_R2, r2
+-	st.q	SP, SAVED_R3, r3
+-	st.q	SP, SAVED_R4, r4
+-	st.q	SP, SAVED_R5, r5
+-	st.q	SP, SAVED_R6, r6
+-	st.q	SP, SAVED_R18, r18
+-	gettr	tr0, r3
+-	st.q	SP, SAVED_TR0, r3
+-
+-	/* move (spc,ssr)->(pspc,pssr).  The rte will shift
+-	   them back again, so that they look like the originals
+-	   as far as the real handler code is concerned. */
+-	getcon	spc, r6
+-	putcon	r6, pspc
+-	getcon	ssr, r6
+-	putcon	r6, pssr
+-
+-	! construct useful SR for handle_exception
+-	movi	3, r6
+-	shlli	r6, 30, r6
+-	getcon	sr, r18
+-	or	r18, r6, r6
+-	putcon	r6, ssr
+-
+-	! SSR is now the current SR with the MD and MMU bits set
+-	! i.e. the rte will switch back to priv mode and put
+-	! the mmu back on
+-
+-	! construct spc
+-	movi	handle_exception, r18
+-	ori	r18, 1, r18		! for safety (do we need this?)
+-	putcon	r18, spc
+-
+-	/* Set args for Non-debug, Not a TLB miss class handler */
+-
+-	! EXPEVT==0x80 is unused, so 'steal' this value to put the
+-	! debug interrupt handler in the vectoring table
+-	movi	0x80, r2
+-	movi	ret_from_exception, r3
+-	ori	r3, 1, r3
+-	movi	EVENT_FAULT_NOT_TLB, r4
+-
+-	or	SP, ZERO, r5
+-	movi	CONFIG_CACHED_MEMORY_OFFSET, r6
+-	add	r6, r5, r5
+-	getcon	KCR1, SP
+-
+-	synco	! for safety
+-	rte	! -> handle_exception, switch back to priv mode again
+-
+-LRESVEC_block_end:			/* Marker. Unused. */
+-
+-	.balign	TEXT_SIZE
+-
+-/*
+- * Second level handler for VBR-based exceptions. Pre-handler.
+- * In common to all stack-frame sensitive handlers.
+- *
+- * Inputs:
+- * (KCR0) Current [current task union]
+- * (KCR1) Original SP
+- * (r2)   INTEVT/EXPEVT
+- * (r3)   appropriate return address
+- * (r4)   Event (0 = interrupt, 1 = TLB miss fault, 2 = Not TLB miss fault, 3=debug)
+- * (r5)   Pointer to reg_save_area
+- * (SP)   Original SP
+- *
+- * Available registers:
+- * (r6)
+- * (r18)
+- * (tr0)
+- *
+- */
+-handle_exception:
+-	/* Common 2nd level handler. */
+-
+-	/* First thing we need an appropriate stack pointer */
+-	getcon	SSR, r6
+-	shlri	r6, 30, r6
+-	andi	r6, 1, r6
+-	pta	stack_ok, tr0
+-	bne	r6, ZERO, tr0		/* Original stack pointer is fine */
+-
+-	/* Set stack pointer for user fault */
+-	getcon	KCR0, SP
+-	movi	THREAD_SIZE, r6		/* Point to the end */
+-	add	SP, r6, SP
+-
+-stack_ok:
+-
+-/* DEBUG : check for underflow/overflow of the kernel stack */
+-	pta	no_underflow, tr0
+-	getcon  KCR0, r6
+-	movi	1024, r18
+-	add	r6, r18, r6
+-	bge	SP, r6, tr0 	! ? below 1k from bottom of stack : danger zone
+-
+-/* Just panic to cause a crash. */
+-bad_sp:
+-	ld.b	r63, 0, r6
+-	nop
+-
+-no_underflow:
+-	pta	bad_sp, tr0
+-	getcon	kcr0, r6
+-	movi	THREAD_SIZE, r18
+-	add	r18, r6, r6
+-	bgt	SP, r6, tr0	! sp above the stack
+-
+-	/* Make some room for the BASIC frame. */
+-	movi	-(FRAME_SIZE), r6
+-	add	SP, r6, SP
+-
+-/* Could do this with no stalling if we had another spare register, but the
+-   code below will be OK. */
+-	ld.q	r5, SAVED_R2, r6
+-	ld.q	r5, SAVED_R3, r18
+-	st.q	SP, FRAME_R(2), r6
+-	ld.q	r5, SAVED_R4, r6
+-	st.q	SP, FRAME_R(3), r18
+-	ld.q	r5, SAVED_R5, r18
+-	st.q	SP, FRAME_R(4), r6
+-	ld.q	r5, SAVED_R6, r6
+-	st.q	SP, FRAME_R(5), r18
+-	ld.q	r5, SAVED_R18, r18
+-	st.q	SP, FRAME_R(6), r6
+-	ld.q	r5, SAVED_TR0, r6
+-	st.q	SP, FRAME_R(18), r18
+-	st.q	SP, FRAME_T(0), r6
+-
+-	/* Keep old SP around */
+-	getcon	KCR1, r6
+-
+-	/* Save the rest of the general purpose registers */
+-	st.q	SP, FRAME_R(0), r0
+-	st.q	SP, FRAME_R(1), r1
+-	st.q	SP, FRAME_R(7), r7
+-	st.q	SP, FRAME_R(8), r8
+-	st.q	SP, FRAME_R(9), r9
+-	st.q	SP, FRAME_R(10), r10
+-	st.q	SP, FRAME_R(11), r11
+-	st.q	SP, FRAME_R(12), r12
+-	st.q	SP, FRAME_R(13), r13
+-	st.q	SP, FRAME_R(14), r14
+-
+-	/* SP is somewhere else */
+-	st.q	SP, FRAME_R(15), r6
+-
+-	st.q	SP, FRAME_R(16), r16
+-	st.q	SP, FRAME_R(17), r17
+-	/* r18 is saved earlier. */
+-	st.q	SP, FRAME_R(19), r19
+-	st.q	SP, FRAME_R(20), r20
+-	st.q	SP, FRAME_R(21), r21
+-	st.q	SP, FRAME_R(22), r22
+-	st.q	SP, FRAME_R(23), r23
+-	st.q	SP, FRAME_R(24), r24
+-	st.q	SP, FRAME_R(25), r25
+-	st.q	SP, FRAME_R(26), r26
+-	st.q	SP, FRAME_R(27), r27
+-	st.q	SP, FRAME_R(28), r28
+-	st.q	SP, FRAME_R(29), r29
+-	st.q	SP, FRAME_R(30), r30
+-	st.q	SP, FRAME_R(31), r31
+-	st.q	SP, FRAME_R(32), r32
+-	st.q	SP, FRAME_R(33), r33
+-	st.q	SP, FRAME_R(34), r34
+-	st.q	SP, FRAME_R(35), r35
+-	st.q	SP, FRAME_R(36), r36
+-	st.q	SP, FRAME_R(37), r37
+-	st.q	SP, FRAME_R(38), r38
+-	st.q	SP, FRAME_R(39), r39
+-	st.q	SP, FRAME_R(40), r40
+-	st.q	SP, FRAME_R(41), r41
+-	st.q	SP, FRAME_R(42), r42
+-	st.q	SP, FRAME_R(43), r43
+-	st.q	SP, FRAME_R(44), r44
+-	st.q	SP, FRAME_R(45), r45
+-	st.q	SP, FRAME_R(46), r46
+-	st.q	SP, FRAME_R(47), r47
+-	st.q	SP, FRAME_R(48), r48
+-	st.q	SP, FRAME_R(49), r49
+-	st.q	SP, FRAME_R(50), r50
+-	st.q	SP, FRAME_R(51), r51
+-	st.q	SP, FRAME_R(52), r52
+-	st.q	SP, FRAME_R(53), r53
+-	st.q	SP, FRAME_R(54), r54
+-	st.q	SP, FRAME_R(55), r55
+-	st.q	SP, FRAME_R(56), r56
+-	st.q	SP, FRAME_R(57), r57
+-	st.q	SP, FRAME_R(58), r58
+-	st.q	SP, FRAME_R(59), r59
+-	st.q	SP, FRAME_R(60), r60
+-	st.q	SP, FRAME_R(61), r61
+-	st.q	SP, FRAME_R(62), r62
+-
+-	/*
+-	 * Save the S* registers.
+-	 */
+-	getcon	SSR, r61
+-	st.q	SP, FRAME_S(FSSR), r61
+-	getcon	SPC, r62
+-	st.q	SP, FRAME_S(FSPC), r62
+-	movi	-1, r62			/* Reset syscall_nr */
+-	st.q	SP, FRAME_S(FSYSCALL_ID), r62
+-
+-	/* Save the rest of the target registers */
+-	gettr	tr1, r6
+-	st.q	SP, FRAME_T(1), r6
+-	gettr	tr2, r6
+-	st.q	SP, FRAME_T(2), r6
+-	gettr	tr3, r6
+-	st.q	SP, FRAME_T(3), r6
+-	gettr	tr4, r6
+-	st.q	SP, FRAME_T(4), r6
+-	gettr	tr5, r6
+-	st.q	SP, FRAME_T(5), r6
+-	gettr	tr6, r6
+-	st.q	SP, FRAME_T(6), r6
+-	gettr	tr7, r6
+-	st.q	SP, FRAME_T(7), r6
+-
+-	! setup FP so that unwinder can wind back through nested kernel mode
+-	! exceptions
+-	add	SP, ZERO, r14
+-
+-#ifdef CONFIG_POOR_MANS_STRACE
+-	/* We've pushed all the registers now, so only r2-r4 hold anything
+-	 * useful. Move them into callee save registers */
+-	or	r2, ZERO, r28
+-	or	r3, ZERO, r29
+-	or	r4, ZERO, r30
+-
+-	/* Preserve r2 as the event code */
+-	movi	evt_debug, r3
+-	ori	r3, 1, r3
+-	ptabs	r3, tr0
+-
+-	or	SP, ZERO, r6
+-	getcon	TRA, r5
+-	blink	tr0, LINK
+-
+-	or	r28, ZERO, r2
+-	or	r29, ZERO, r3
+-	or	r30, ZERO, r4
+-#endif
+-
+-	/* For syscall and debug race condition, get TRA now */
+-	getcon	TRA, r5
+-
+-	/* We are in a safe position to turn SR.BL off, but set IMASK=0xf
+-	 * Also set FD, to catch FPU usage in the kernel.
+-	 *
+-	 * benedict.gaster at superh.com 29/07/2002
+-	 *
+-	 * On all SH5-101 revisions it is unsafe to raise the IMASK and at the
+-	 * same time change BL from 1->0, as any pending interrupt of a level
+-	 * higher than he previous value of IMASK will leak through and be
+-	 * taken unexpectedly.
+-	 *
+-	 * To avoid this we raise the IMASK and then issue another PUTCON to
+-	 * enable interrupts.
+-         */
+-	getcon	SR, r6
+-	movi	SR_IMASK | SR_FD, r7
+-	or	r6, r7, r6
+-	putcon	r6, SR
+-	movi	SR_UNBLOCK_EXC, r7
+-	and	r6, r7, r6
+-	putcon	r6, SR
+-
+-
+-	/* Now call the appropriate 3rd level handler */
+-	or	r3, ZERO, LINK
+-	movi	trap_jtable, r3
+-	shlri	r2, 3, r2
+-	ldx.l	r2, r3, r3
+-	shlri	r2, 2, r2
+-	ptabs	r3, tr0
+-	or	SP, ZERO, r3
+-	blink	tr0, ZERO
+-
+-/*
+- * Second level handler for VBR-based exceptions. Post-handlers.
+- *
+- * Post-handlers for interrupts (ret_from_irq), exceptions
+- * (ret_from_exception) and common reentrance doors (restore_all
+- * to get back to the original context, ret_from_syscall loop to
+- * check kernel exiting).
+- *
+- * ret_with_reschedule and work_notifysig are an inner lables of
+- * the ret_from_syscall loop.
+- *
+- * In common to all stack-frame sensitive handlers.
+- *
+- * Inputs:
+- * (SP)   struct pt_regs *, original register's frame pointer (basic)
+- *
+- */
+-	.global ret_from_irq
+-ret_from_irq:
+-#ifdef CONFIG_POOR_MANS_STRACE
+-	pta	evt_debug_ret_from_irq, tr0
+-	ori	SP, 0, r2
+-	blink	tr0, LINK
+-#endif
+-	ld.q	SP, FRAME_S(FSSR), r6
+-	shlri	r6, 30, r6
+-	andi	r6, 1, r6
+-	pta	resume_kernel, tr0
+-	bne	r6, ZERO, tr0		/* no further checks */
+-	STI()
+-	pta	ret_with_reschedule, tr0
+-	blink	tr0, ZERO		/* Do not check softirqs */
+-
+-	.global ret_from_exception
+-ret_from_exception:
+-	preempt_stop()
+-
+-#ifdef CONFIG_POOR_MANS_STRACE
+-	pta	evt_debug_ret_from_exc, tr0
+-	ori	SP, 0, r2
+-	blink	tr0, LINK
+-#endif
+-
+-	ld.q	SP, FRAME_S(FSSR), r6
+-	shlri	r6, 30, r6
+-	andi	r6, 1, r6
+-	pta	resume_kernel, tr0
+-	bne	r6, ZERO, tr0		/* no further checks */
+-
+-	/* Check softirqs */
+-
+-#ifdef CONFIG_PREEMPT
+-	pta   ret_from_syscall, tr0
+-	blink   tr0, ZERO
+-
+-resume_kernel:
+-	pta	restore_all, tr0
+-
+-	getcon	KCR0, r6
+-	ld.l	r6, TI_PRE_COUNT, r7
+-	beq/u	r7, ZERO, tr0
+-
+-need_resched:
+-	ld.l	r6, TI_FLAGS, r7
+-	movi	(1 << TIF_NEED_RESCHED), r8
+-	and	r8, r7, r8
+-	bne	r8, ZERO, tr0
+-
+-	getcon	SR, r7
+-	andi	r7, 0xf0, r7
+-	bne	r7, ZERO, tr0
+-
+-	movi	((PREEMPT_ACTIVE >> 16) & 65535), r8
+-	shori	(PREEMPT_ACTIVE & 65535), r8
+-	st.l	r6, TI_PRE_COUNT, r8
+-
+-	STI()
+-	movi	schedule, r7
+-	ori	r7, 1, r7
+-	ptabs	r7, tr1
+-	blink	tr1, LINK
+-
+-	st.l	r6, TI_PRE_COUNT, ZERO
+-	CLI()
+-
+-	pta	need_resched, tr1
+-	blink	tr1, ZERO
+-#endif
+-
+-	.global ret_from_syscall
+-ret_from_syscall:
+-
+-ret_with_reschedule:
+-	getcon	KCR0, r6		! r6 contains current_thread_info
+-	ld.l	r6, TI_FLAGS, r7	! r7 contains current_thread_info->flags
+-
+-	! FIXME:!!!
+-	! no handling of TIF_SYSCALL_TRACE yet!!
+-
+-	movi	_TIF_NEED_RESCHED, r8
+-	and	r8, r7, r8
+-	pta	work_resched, tr0
+-	bne	r8, ZERO, tr0
+-
+-	pta	restore_all, tr1
+-
+-	movi	(_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK), r8
+-	and	r8, r7, r8
+-	pta	work_notifysig, tr0
+-	bne	r8, ZERO, tr0
+-
+-	blink	tr1, ZERO
+-
+-work_resched:
+-	pta	ret_from_syscall, tr0
+-	gettr	tr0, LINK
+-	movi	schedule, r6
+-	ptabs	r6, tr0
+-	blink	tr0, ZERO		/* Call schedule(), return on top */
+-
+-work_notifysig:
+-	gettr	tr1, LINK
+-
+-	movi	do_signal, r6
+-	ptabs	r6, tr0
+-	or	SP, ZERO, r2
+-	or	ZERO, ZERO, r3
+-	blink	tr0, LINK	    /* Call do_signal(regs, 0), return here */
+-
+-restore_all:
+-	/* Do prefetches */
+-
+-	ld.q	SP, FRAME_T(0), r6
+-	ld.q	SP, FRAME_T(1), r7
+-	ld.q	SP, FRAME_T(2), r8
+-	ld.q	SP, FRAME_T(3), r9
+-	ptabs	r6, tr0
+-	ptabs	r7, tr1
+-	ptabs	r8, tr2
+-	ptabs	r9, tr3
+-	ld.q	SP, FRAME_T(4), r6
+-	ld.q	SP, FRAME_T(5), r7
+-	ld.q	SP, FRAME_T(6), r8
+-	ld.q	SP, FRAME_T(7), r9
+-	ptabs	r6, tr4
+-	ptabs	r7, tr5
+-	ptabs	r8, tr6
+-	ptabs	r9, tr7
+-
+-	ld.q	SP, FRAME_R(0), r0
+-	ld.q	SP, FRAME_R(1), r1
+-	ld.q	SP, FRAME_R(2), r2
+-	ld.q	SP, FRAME_R(3), r3
+-	ld.q	SP, FRAME_R(4), r4
+-	ld.q	SP, FRAME_R(5), r5
+-	ld.q	SP, FRAME_R(6), r6
+-	ld.q	SP, FRAME_R(7), r7
+-	ld.q	SP, FRAME_R(8), r8
+-	ld.q	SP, FRAME_R(9), r9
+-	ld.q	SP, FRAME_R(10), r10
+-	ld.q	SP, FRAME_R(11), r11
+-	ld.q	SP, FRAME_R(12), r12
+-	ld.q	SP, FRAME_R(13), r13
+-	ld.q	SP, FRAME_R(14), r14
+-
+-	ld.q	SP, FRAME_R(16), r16
+-	ld.q	SP, FRAME_R(17), r17
+-	ld.q	SP, FRAME_R(18), r18
+-	ld.q	SP, FRAME_R(19), r19
+-	ld.q	SP, FRAME_R(20), r20
+-	ld.q	SP, FRAME_R(21), r21
+-	ld.q	SP, FRAME_R(22), r22
+-	ld.q	SP, FRAME_R(23), r23
+-	ld.q	SP, FRAME_R(24), r24
+-	ld.q	SP, FRAME_R(25), r25
+-	ld.q	SP, FRAME_R(26), r26
+-	ld.q	SP, FRAME_R(27), r27
+-	ld.q	SP, FRAME_R(28), r28
+-	ld.q	SP, FRAME_R(29), r29
+-	ld.q	SP, FRAME_R(30), r30
+-	ld.q	SP, FRAME_R(31), r31
+-	ld.q	SP, FRAME_R(32), r32
+-	ld.q	SP, FRAME_R(33), r33
+-	ld.q	SP, FRAME_R(34), r34
+-	ld.q	SP, FRAME_R(35), r35
+-	ld.q	SP, FRAME_R(36), r36
+-	ld.q	SP, FRAME_R(37), r37
+-	ld.q	SP, FRAME_R(38), r38
+-	ld.q	SP, FRAME_R(39), r39
+-	ld.q	SP, FRAME_R(40), r40
+-	ld.q	SP, FRAME_R(41), r41
+-	ld.q	SP, FRAME_R(42), r42
+-	ld.q	SP, FRAME_R(43), r43
+-	ld.q	SP, FRAME_R(44), r44
+-	ld.q	SP, FRAME_R(45), r45
+-	ld.q	SP, FRAME_R(46), r46
+-	ld.q	SP, FRAME_R(47), r47
+-	ld.q	SP, FRAME_R(48), r48
+-	ld.q	SP, FRAME_R(49), r49
+-	ld.q	SP, FRAME_R(50), r50
+-	ld.q	SP, FRAME_R(51), r51
+-	ld.q	SP, FRAME_R(52), r52
+-	ld.q	SP, FRAME_R(53), r53
+-	ld.q	SP, FRAME_R(54), r54
+-	ld.q	SP, FRAME_R(55), r55
+-	ld.q	SP, FRAME_R(56), r56
+-	ld.q	SP, FRAME_R(57), r57
+-	ld.q	SP, FRAME_R(58), r58
+-
+-	getcon	SR, r59
+-	movi	SR_BLOCK_EXC, r60
+-	or	r59, r60, r59
+-	putcon	r59, SR			/* SR.BL = 1, keep nesting out */
+-	ld.q	SP, FRAME_S(FSSR), r61
+-	ld.q	SP, FRAME_S(FSPC), r62
+-	movi	SR_ASID_MASK, r60
+-	and	r59, r60, r59
+-	andc	r61, r60, r61		/* Clear out older ASID */
+-	or	r59, r61, r61		/* Retain current ASID */
+-	putcon	r61, SSR
+-	putcon	r62, SPC
+-
+-	/* Ignore FSYSCALL_ID */
+-
+-	ld.q	SP, FRAME_R(59), r59
+-	ld.q	SP, FRAME_R(60), r60
+-	ld.q	SP, FRAME_R(61), r61
+-	ld.q	SP, FRAME_R(62), r62
+-
+-	/* Last touch */
+-	ld.q	SP, FRAME_R(15), SP
+-	rte
+-	nop
+-
+-/*
+- * Third level handlers for VBR-based exceptions. Adapting args to
+- * and/or deflecting to fourth level handlers.
+- *
+- * Fourth level handlers interface.
+- * Most are C-coded handlers directly pointed by the trap_jtable.
+- * (Third = Fourth level)
+- * Inputs:
+- * (r2)   fault/interrupt code, entry number (e.g. NMI = 14,
+- *	  IRL0-3 (0000) = 16, RTLBMISS = 2, SYSCALL = 11, etc ...)
+- * (r3)   struct pt_regs *, original register's frame pointer
+- * (r4)   Event (0 = interrupt, 1 = TLB miss fault, 2 = Not TLB miss fault)
+- * (r5)   TRA control register (for syscall/debug benefit only)
+- * (LINK) return address
+- * (SP)   = r3
+- *
+- * Kernel TLB fault handlers will get a slightly different interface.
+- * (r2)   struct pt_regs *, original register's frame pointer
+- * (r3)   writeaccess, whether it's a store fault as opposed to load fault
+- * (r4)   execaccess, whether it's a ITLB fault as opposed to DTLB fault
+- * (r5)   Effective Address of fault
+- * (LINK) return address
+- * (SP)   = r2
+- *
+- * fpu_error_or_IRQ? is a helper to deflect to the right cause.
+- *
+- */
+-tlb_miss_load:
+-	or	SP, ZERO, r2
+-	or	ZERO, ZERO, r3		/* Read */
+-	or	ZERO, ZERO, r4		/* Data */
+-	getcon	TEA, r5
+-	pta	call_do_page_fault, tr0
+-	beq	ZERO, ZERO, tr0
+-
+-tlb_miss_store:
+-	or	SP, ZERO, r2
+-	movi	1, r3			/* Write */
+-	or	ZERO, ZERO, r4		/* Data */
+-	getcon	TEA, r5
+-	pta	call_do_page_fault, tr0
+-	beq	ZERO, ZERO, tr0
+-
+-itlb_miss_or_IRQ:
+-	pta	its_IRQ, tr0
+-	beqi/u	r4, EVENT_INTERRUPT, tr0
+-	or	SP, ZERO, r2
+-	or	ZERO, ZERO, r3		/* Read */
+-	movi	1, r4			/* Text */
+-	getcon	TEA, r5
+-	/* Fall through */
+-
+-call_do_page_fault:
+-	movi	do_page_fault, r6
+-        ptabs	r6, tr0
+-        blink	tr0, ZERO
+-
+-fpu_error_or_IRQA:
+-	pta	its_IRQ, tr0
+-	beqi/l	r4, EVENT_INTERRUPT, tr0
+-#ifdef CONFIG_SH_FPU
+-	movi	do_fpu_state_restore, r6
+-#else
+-	movi	do_exception_error, r6
+-#endif
+-	ptabs	r6, tr0
+-	blink	tr0, ZERO
+-
+-fpu_error_or_IRQB:
+-	pta	its_IRQ, tr0
+-	beqi/l	r4, EVENT_INTERRUPT, tr0
+-#ifdef CONFIG_SH_FPU
+-	movi	do_fpu_state_restore, r6
+-#else
+-	movi	do_exception_error, r6
+-#endif
+-	ptabs	r6, tr0
+-	blink	tr0, ZERO
+-
+-its_IRQ:
+-	movi	do_IRQ, r6
+-	ptabs	r6, tr0
+-	blink	tr0, ZERO
+-
+-/*
+- * system_call/unknown_trap third level handler:
+- *
+- * Inputs:
+- * (r2)   fault/interrupt code, entry number (TRAP = 11)
+- * (r3)   struct pt_regs *, original register's frame pointer
+- * (r4)   Not used. Event (0=interrupt, 1=TLB miss fault, 2=Not TLB miss fault)
+- * (r5)   TRA Control Reg (0x00xyzzzz: x=1 SYSCALL, y = #args, z=nr)
+- * (SP)   = r3
+- * (LINK) return address: ret_from_exception
+- * (*r3)  Syscall parms: SC#, arg0, arg1, ..., arg5 in order (Saved r2/r7)
+- *
+- * Outputs:
+- * (*r3)  Syscall reply (Saved r2)
+- * (LINK) In case of syscall only it can be scrapped.
+- *        Common second level post handler will be ret_from_syscall.
+- *        Common (non-trace) exit point to that is syscall_ret (saving
+- *        result to r2). Common bad exit point is syscall_bad (returning
+- *        ENOSYS then saved to r2).
+- *
+- */
+-
+-unknown_trap:
+-	/* Unknown Trap or User Trace */
+-	movi	do_unknown_trapa, r6
+-	ptabs	r6, tr0
+-        ld.q    r3, FRAME_R(9), r2	/* r2 = #arg << 16 | syscall # */
+-        andi    r2, 0x1ff, r2		/* r2 = syscall # */
+-	blink	tr0, LINK
+-
+-	pta	syscall_ret, tr0
+-	blink	tr0, ZERO
+-
+-        /* New syscall implementation*/
+-system_call:
+-	pta	unknown_trap, tr0
+-        or      r5, ZERO, r4            /* TRA (=r5) -> r4 */
+-        shlri   r4, 20, r4
+-	bnei	r4, 1, tr0		/* unknown_trap if not 0x1yzzzz */
+-
+-        /* It's a system call */
+-	st.q    r3, FRAME_S(FSYSCALL_ID), r5 	/* ID (0x1yzzzz) -> stack */
+-	andi    r5, 0x1ff, r5			/* syscall # -> r5	  */
+-
+-	STI()
+-
+-	pta	syscall_allowed, tr0
+-	movi	NR_syscalls - 1, r4	/* Last valid */
+-	bgeu/l	r4, r5, tr0
+-
+-syscall_bad:
+-	/* Return ENOSYS ! */
+-	movi	-(ENOSYS), r2		/* Fall-through */
+-
+-	.global syscall_ret
+-syscall_ret:
+-	st.q	SP, FRAME_R(9), r2	/* Expecting SP back to BASIC frame */
+-
+-#ifdef CONFIG_POOR_MANS_STRACE
+-	/* nothing useful in registers at this point */
+-
+-	movi	evt_debug2, r5
+-	ori	r5, 1, r5
+-	ptabs	r5, tr0
+-	ld.q	SP, FRAME_R(9), r2
+-	or	SP, ZERO, r3
+-	blink	tr0, LINK
+-#endif
+-
+-	ld.q	SP, FRAME_S(FSPC), r2
+-	addi	r2, 4, r2		/* Move PC, being pre-execution event */
+-	st.q	SP, FRAME_S(FSPC), r2
+-	pta	ret_from_syscall, tr0
+-	blink	tr0, ZERO
+-
+-
+-/*  A different return path for ret_from_fork, because we now need
+- *  to call schedule_tail with the later kernels. Because prev is
+- *  loaded into r2 by switch_to() means we can just call it straight  away
+- */
+-
+-.global	ret_from_fork
+-ret_from_fork:
+-
+-	movi	schedule_tail,r5
+-	ori	r5, 1, r5
+-	ptabs	r5, tr0
+-	blink	tr0, LINK
+-
+-#ifdef CONFIG_POOR_MANS_STRACE
+-	/* nothing useful in registers at this point */
+-
+-	movi	evt_debug2, r5
+-	ori	r5, 1, r5
+-	ptabs	r5, tr0
+-	ld.q	SP, FRAME_R(9), r2
+-	or	SP, ZERO, r3
+-	blink	tr0, LINK
+-#endif
+-
+-	ld.q	SP, FRAME_S(FSPC), r2
+-	addi	r2, 4, r2		/* Move PC, being pre-execution event */
+-	st.q	SP, FRAME_S(FSPC), r2
+-	pta	ret_from_syscall, tr0
+-	blink	tr0, ZERO
+-
+-
+-
+-syscall_allowed:
+-	/* Use LINK to deflect the exit point, default is syscall_ret */
+-	pta	syscall_ret, tr0
+-	gettr	tr0, LINK
+-	pta	syscall_notrace, tr0
+-
+-	getcon	KCR0, r2
+-	ld.l	r2, TI_FLAGS, r4
+-	movi	(1 << TIF_SYSCALL_TRACE), r6
+-	and	r6, r4, r6
+-	beq/l	r6, ZERO, tr0
+-
+-	/* Trace it by calling syscall_trace before and after */
+-	movi	syscall_trace, r4
+-	ptabs	r4, tr0
+-	blink	tr0, LINK
+-	/* Reload syscall number as r5 is trashed by syscall_trace */
+-	ld.q	SP, FRAME_S(FSYSCALL_ID), r5
+-	andi	r5, 0x1ff, r5
+-
+-	pta	syscall_ret_trace, tr0
+-	gettr	tr0, LINK
+-
+-syscall_notrace:
+-	/* Now point to the appropriate 4th level syscall handler */
+-	movi	sys_call_table, r4
+-	shlli	r5, 2, r5
+-	ldx.l	r4, r5, r5
+-	ptabs	r5, tr0
+-
+-	/* Prepare original args */
+-	ld.q	SP, FRAME_R(2), r2
+-	ld.q	SP, FRAME_R(3), r3
+-	ld.q	SP, FRAME_R(4), r4
+-	ld.q	SP, FRAME_R(5), r5
+-	ld.q	SP, FRAME_R(6), r6
+-	ld.q	SP, FRAME_R(7), r7
+-
+-	/* And now the trick for those syscalls requiring regs * ! */
+-	or	SP, ZERO, r8
+-
+-	/* Call it */
+-	blink	tr0, ZERO	/* LINK is already properly set */
+-
+-syscall_ret_trace:
+-	/* We get back here only if under trace */
+-	st.q	SP, FRAME_R(9), r2	/* Save return value */
+-
+-	movi	syscall_trace, LINK
+-	ptabs	LINK, tr0
+-	blink	tr0, LINK
+-
+-	/* This needs to be done after any syscall tracing */
+-	ld.q	SP, FRAME_S(FSPC), r2
+-	addi	r2, 4, r2	/* Move PC, being pre-execution event */
+-	st.q	SP, FRAME_S(FSPC), r2
+-
+-	pta	ret_from_syscall, tr0
+-	blink	tr0, ZERO		/* Resume normal return sequence */
+-
+-/*
+- * --- Switch to running under a particular ASID and return the previous ASID value
+- * --- The caller is assumed to have done a cli before calling this.
+- *
+- * Input r2 : new ASID
+- * Output r2 : old ASID
+- */
+-
+-	.global switch_and_save_asid
+-switch_and_save_asid:
+-	getcon	sr, r0
+-	movi	255, r4
+-	shlli 	r4, 16, r4	/* r4 = mask to select ASID */
+-	and	r0, r4, r3	/* r3 = shifted old ASID */
+-	andi	r2, 255, r2	/* mask down new ASID */
+-	shlli	r2, 16, r2	/* align new ASID against SR.ASID */
+-	andc	r0, r4, r0	/* efface old ASID from SR */
+-	or	r0, r2, r0	/* insert the new ASID */
+-	putcon	r0, ssr
+-	movi	1f, r0
+-	putcon	r0, spc
+-	rte
+-	nop
+-1:
+-	ptabs	LINK, tr0
+-	shlri	r3, 16, r2	/* r2 = old ASID */
+-	blink tr0, r63
+-
+-	.global	route_to_panic_handler
+-route_to_panic_handler:
+-	/* Switch to real mode, goto panic_handler, don't return.  Useful for
+-	   last-chance debugging, e.g. if no output wants to go to the console.
+-	   */
+-
+-	movi	panic_handler - CONFIG_CACHED_MEMORY_OFFSET, r1
+-	ptabs	r1, tr0
+-	pta	1f, tr1
+-	gettr	tr1, r0
+-	putcon	r0, spc
+-	getcon	sr, r0
+-	movi	1, r1
+-	shlli	r1, 31, r1
+-	andc	r0, r1, r0
+-	putcon	r0, ssr
+-	rte
+-	nop
+-1:	/* Now in real mode */
+-	blink tr0, r63
+-	nop
+-
+-	.global peek_real_address_q
+-peek_real_address_q:
+-	/* Two args:
+-	   r2 : real mode address to peek
+-	   r2(out) : result quadword
+-
+-	   This is provided as a cheapskate way of manipulating device
+-	   registers for debugging (to avoid the need to onchip_remap the debug
+-	   module, and to avoid the need to onchip_remap the watchpoint
+-	   controller in a way that identity maps sufficient bits to avoid the
+-	   SH5-101 cut2 silicon defect).
+-
+-	   This code is not performance critical
+-	*/
+-
+-	add.l	r2, r63, r2	/* sign extend address */
+-	getcon	sr, r0		/* r0 = saved original SR */
+-	movi	1, r1
+-	shlli	r1, 28, r1
+-	or	r0, r1, r1	/* r0 with block bit set */
+-	putcon	r1, sr		/* now in critical section */
+-	movi	1, r36
+-	shlli	r36, 31, r36
+-	andc	r1, r36, r1	/* turn sr.mmu off in real mode section */
+-
+-	putcon	r1, ssr
+-	movi	.peek0 - CONFIG_CACHED_MEMORY_OFFSET, r36 /* real mode target address */
+-	movi	1f, r37		/* virtual mode return addr */
+-	putcon	r36, spc
+-
+-	synco
+-	rte
+-	nop
+-
+-.peek0:	/* come here in real mode, don't touch caches!!
+-           still in critical section (sr.bl==1) */
+-	putcon	r0, ssr
+-	putcon	r37, spc
+-	/* Here's the actual peek.  If the address is bad, all bets are now off
+-	 * what will happen (handlers invoked in real-mode = bad news) */
+-	ld.q	r2, 0, r2
+-	synco
+-	rte	/* Back to virtual mode */
+-	nop
+-
+-1:
+-	ptabs	LINK, tr0
+-	blink	tr0, r63
+-
+-	.global poke_real_address_q
+-poke_real_address_q:
+-	/* Two args:
+-	   r2 : real mode address to poke
+-	   r3 : quadword value to write.
+-
+-	   This is provided as a cheapskate way of manipulating device
+-	   registers for debugging (to avoid the need to onchip_remap the debug
+-	   module, and to avoid the need to onchip_remap the watchpoint
+-	   controller in a way that identity maps sufficient bits to avoid the
+-	   SH5-101 cut2 silicon defect).
+-
+-	   This code is not performance critical
+-	*/
+-
+-	add.l	r2, r63, r2	/* sign extend address */
+-	getcon	sr, r0		/* r0 = saved original SR */
+-	movi	1, r1
+-	shlli	r1, 28, r1
+-	or	r0, r1, r1	/* r0 with block bit set */
+-	putcon	r1, sr		/* now in critical section */
+-	movi	1, r36
+-	shlli	r36, 31, r36
+-	andc	r1, r36, r1	/* turn sr.mmu off in real mode section */
+-
+-	putcon	r1, ssr
+-	movi	.poke0-CONFIG_CACHED_MEMORY_OFFSET, r36 /* real mode target address */
+-	movi	1f, r37		/* virtual mode return addr */
+-	putcon	r36, spc
+-
+-	synco
+-	rte
+-	nop
+-
+-.poke0:	/* come here in real mode, don't touch caches!!
+-           still in critical section (sr.bl==1) */
+-	putcon	r0, ssr
+-	putcon	r37, spc
+-	/* Here's the actual poke.  If the address is bad, all bets are now off
+-	 * what will happen (handlers invoked in real-mode = bad news) */
+-	st.q	r2, 0, r3
+-	synco
+-	rte	/* Back to virtual mode */
+-	nop
+-
+-1:
+-	ptabs	LINK, tr0
+-	blink	tr0, r63
+-
+-/*
+- * --- User Access Handling Section
+- */
+-
+-/*
+- * User Access support. It all moved to non inlined Assembler
+- * functions in here.
+- *
+- * __kernel_size_t __copy_user(void *__to, const void *__from,
+- *			       __kernel_size_t __n)
+- *
+- * Inputs:
+- * (r2)  target address
+- * (r3)  source address
+- * (r4)  size in bytes
+- *
+- * Ouputs:
+- * (*r2) target data
+- * (r2)  non-copied bytes
+- *
+- * If a fault occurs on the user pointer, bail out early and return the
+- * number of bytes not copied in r2.
+- * Strategy : for large blocks, call a real memcpy function which can
+- * move >1 byte at a time using unaligned ld/st instructions, and can
+- * manipulate the cache using prefetch + alloco to improve the speed
+- * further.  If a fault occurs in that function, just revert to the
+- * byte-by-byte approach used for small blocks; this is rare so the
+- * performance hit for that case does not matter.
+- *
+- * For small blocks it's not worth the overhead of setting up and calling
+- * the memcpy routine; do the copy a byte at a time.
+- *
+- */
+-	.global	__copy_user
+-__copy_user:
+-	pta	__copy_user_byte_by_byte, tr1
+-	movi	16, r0 ! this value is a best guess, should tune it by benchmarking
+-	bge/u	r0, r4, tr1
+-	pta copy_user_memcpy, tr0
+-	addi	SP, -32, SP
+-	/* Save arguments in case we have to fix-up unhandled page fault */
+-	st.q	SP, 0, r2
+-	st.q	SP, 8, r3
+-	st.q	SP, 16, r4
+-	st.q	SP, 24, r35 ! r35 is callee-save
+-	/* Save LINK in a register to reduce RTS time later (otherwise
+-	   ld SP,*,LINK;ptabs LINK;trn;blink trn,r63 becomes a critical path) */
+-	ori	LINK, 0, r35
+-	blink	tr0, LINK
+-
+-	/* Copy completed normally if we get back here */
+-	ptabs	r35, tr0
+-	ld.q	SP, 24, r35
+-	/* don't restore r2-r4, pointless */
+-	/* set result=r2 to zero as the copy must have succeeded. */
+-	or	r63, r63, r2
+-	addi	SP, 32, SP
+-	blink	tr0, r63 ! RTS
+-
+-	.global __copy_user_fixup
+-__copy_user_fixup:
+-	/* Restore stack frame */
+-	ori	r35, 0, LINK
+-	ld.q	SP, 24, r35
+-	ld.q	SP, 16, r4
+-	ld.q	SP,  8, r3
+-	ld.q	SP,  0, r2
+-	addi	SP, 32, SP
+-	/* Fall through to original code, in the 'same' state we entered with */
+-
+-/* The slow byte-by-byte method is used if the fast copy traps due to a bad
+-   user address.  In that rare case, the speed drop can be tolerated. */
+-__copy_user_byte_by_byte:
+-	pta	___copy_user_exit, tr1
+-	pta	___copy_user1, tr0
+-	beq/u	r4, r63, tr1	/* early exit for zero length copy */
+-	sub	r2, r3, r0
+-	addi	r0, -1, r0
+-
+-___copy_user1:
+-	ld.b	r3, 0, r5		/* Fault address 1 */
+-
+-	/* Could rewrite this to use just 1 add, but the second comes 'free'
+-	   due to load latency */
+-	addi	r3, 1, r3
+-	addi	r4, -1, r4		/* No real fixup required */
+-___copy_user2:
+-	stx.b	r3, r0, r5		/* Fault address 2 */
+-	bne     r4, ZERO, tr0
+-
+-___copy_user_exit:
+-	or	r4, ZERO, r2
+-	ptabs	LINK, tr0
+-	blink	tr0, ZERO
+-
+-/*
+- * __kernel_size_t __clear_user(void *addr, __kernel_size_t size)
+- *
+- * Inputs:
+- * (r2)  target address
+- * (r3)  size in bytes
+- *
+- * Ouputs:
+- * (*r2) zero-ed target data
+- * (r2)  non-zero-ed bytes
+- */
+-	.global	__clear_user
+-__clear_user:
+-	pta	___clear_user_exit, tr1
+-	pta	___clear_user1, tr0
+-	beq/u	r3, r63, tr1
+-
+-___clear_user1:
+-	st.b	r2, 0, ZERO		/* Fault address */
+-	addi	r2, 1, r2
+-	addi	r3, -1, r3		/* No real fixup required */
+-	bne     r3, ZERO, tr0
+-
+-___clear_user_exit:
+-	or	r3, ZERO, r2
+-	ptabs	LINK, tr0
+-	blink	tr0, ZERO
+-
+-
+-/*
+- * int __strncpy_from_user(unsigned long __dest, unsigned long __src,
+- *			   int __count)
+- *
+- * Inputs:
+- * (r2)  target address
+- * (r3)  source address
+- * (r4)  maximum size in bytes
+- *
+- * Ouputs:
+- * (*r2) copied data
+- * (r2)  -EFAULT (in case of faulting)
+- *       copied data (otherwise)
+- */
+-	.global	__strncpy_from_user
+-__strncpy_from_user:
+-	pta	___strncpy_from_user1, tr0
+-	pta	___strncpy_from_user_done, tr1
+-	or	r4, ZERO, r5		/* r5 = original count */
+-	beq/u	r4, r63, tr1		/* early exit if r4==0 */
+-	movi	-(EFAULT), r6		/* r6 = reply, no real fixup */
+-	or	ZERO, ZERO, r7		/* r7 = data, clear top byte of data */
+-
+-___strncpy_from_user1:
+-	ld.b	r3, 0, r7		/* Fault address: only in reading */
+-	st.b	r2, 0, r7
+-	addi	r2, 1, r2
+-	addi	r3, 1, r3
+-	beq/u	ZERO, r7, tr1
+-	addi	r4, -1, r4		/* return real number of copied bytes */
+-	bne/l	ZERO, r4, tr0
+-
+-___strncpy_from_user_done:
+-	sub	r5, r4, r6		/* If done, return copied */
+-
+-___strncpy_from_user_exit:
+-	or	r6, ZERO, r2
+-	ptabs	LINK, tr0
+-	blink	tr0, ZERO
+-
+-/*
+- * extern long __strnlen_user(const char *__s, long __n)
+- *
+- * Inputs:
+- * (r2)  source address
+- * (r3)  source size in bytes
+- *
+- * Ouputs:
+- * (r2)  -EFAULT (in case of faulting)
+- *       string length (otherwise)
+- */
+-	.global	__strnlen_user
+-__strnlen_user:
+-	pta	___strnlen_user_set_reply, tr0
+-	pta	___strnlen_user1, tr1
+-	or	ZERO, ZERO, r5		/* r5 = counter */
+-	movi	-(EFAULT), r6		/* r6 = reply, no real fixup */
+-	or	ZERO, ZERO, r7		/* r7 = data, clear top byte of data */
+-	beq	r3, ZERO, tr0
+-
+-___strnlen_user1:
+-	ldx.b	r2, r5, r7		/* Fault address: only in reading */
+-	addi	r3, -1, r3		/* No real fixup */
+-	addi	r5, 1, r5
+-	beq	r3, ZERO, tr0
+-	bne	r7, ZERO, tr1
+-! The line below used to be active.  This meant led to a junk byte lying between each pair
+-! of entries in the argv & envp structures in memory.  Whilst the program saw the right data
+-! via the argv and envp arguments to main, it meant the 'flat' representation visible through
+-! /proc/$pid/cmdline was corrupt, causing trouble with ps, for example.
+-!	addi	r5, 1, r5		/* Include '\0' */
+-
+-___strnlen_user_set_reply:
+-	or	r5, ZERO, r6		/* If done, return counter */
+-
+-___strnlen_user_exit:
+-	or	r6, ZERO, r2
+-	ptabs	LINK, tr0
+-	blink	tr0, ZERO
+-
+-/*
+- * extern long __get_user_asm_?(void *val, long addr)
+- *
+- * Inputs:
+- * (r2)  dest address
+- * (r3)  source address (in User Space)
+- *
+- * Ouputs:
+- * (r2)  -EFAULT (faulting)
+- *       0 	 (not faulting)
+- */
+-	.global	__get_user_asm_b
+-__get_user_asm_b:
+-	or	r2, ZERO, r4
+-	movi	-(EFAULT), r2		/* r2 = reply, no real fixup */
+-
+-___get_user_asm_b1:
+-	ld.b	r3, 0, r5		/* r5 = data */
+-	st.b	r4, 0, r5
+-	or	ZERO, ZERO, r2
+-
+-___get_user_asm_b_exit:
+-	ptabs	LINK, tr0
+-	blink	tr0, ZERO
+-
+-
+-	.global	__get_user_asm_w
+-__get_user_asm_w:
+-	or	r2, ZERO, r4
+-	movi	-(EFAULT), r2		/* r2 = reply, no real fixup */
+-
+-___get_user_asm_w1:
+-	ld.w	r3, 0, r5		/* r5 = data */
+-	st.w	r4, 0, r5
+-	or	ZERO, ZERO, r2
+-
+-___get_user_asm_w_exit:
+-	ptabs	LINK, tr0
+-	blink	tr0, ZERO
+-
+-
+-	.global	__get_user_asm_l
+-__get_user_asm_l:
+-	or	r2, ZERO, r4
+-	movi	-(EFAULT), r2		/* r2 = reply, no real fixup */
+-
+-___get_user_asm_l1:
+-	ld.l	r3, 0, r5		/* r5 = data */
+-	st.l	r4, 0, r5
+-	or	ZERO, ZERO, r2
+-
+-___get_user_asm_l_exit:
+-	ptabs	LINK, tr0
+-	blink	tr0, ZERO
+-
+-
+-	.global	__get_user_asm_q
+-__get_user_asm_q:
+-	or	r2, ZERO, r4
+-	movi	-(EFAULT), r2		/* r2 = reply, no real fixup */
+-
+-___get_user_asm_q1:
+-	ld.q	r3, 0, r5		/* r5 = data */
+-	st.q	r4, 0, r5
+-	or	ZERO, ZERO, r2
+-
+-___get_user_asm_q_exit:
+-	ptabs	LINK, tr0
+-	blink	tr0, ZERO
+-
+-/*
+- * extern long __put_user_asm_?(void *pval, long addr)
+- *
+- * Inputs:
+- * (r2)  kernel pointer to value
+- * (r3)  dest address (in User Space)
+- *
+- * Ouputs:
+- * (r2)  -EFAULT (faulting)
+- *       0 	 (not faulting)
+- */
+-	.global	__put_user_asm_b
+-__put_user_asm_b:
+-	ld.b	r2, 0, r4		/* r4 = data */
+-	movi	-(EFAULT), r2		/* r2 = reply, no real fixup */
+-
+-___put_user_asm_b1:
+-	st.b	r3, 0, r4
+-	or	ZERO, ZERO, r2
+-
+-___put_user_asm_b_exit:
+-	ptabs	LINK, tr0
+-	blink	tr0, ZERO
+-
+-
+-	.global	__put_user_asm_w
+-__put_user_asm_w:
+-	ld.w	r2, 0, r4		/* r4 = data */
+-	movi	-(EFAULT), r2		/* r2 = reply, no real fixup */
+-
+-___put_user_asm_w1:
+-	st.w	r3, 0, r4
+-	or	ZERO, ZERO, r2
+-
+-___put_user_asm_w_exit:
+-	ptabs	LINK, tr0
+-	blink	tr0, ZERO
+-
+-
+-	.global	__put_user_asm_l
+-__put_user_asm_l:
+-	ld.l	r2, 0, r4		/* r4 = data */
+-	movi	-(EFAULT), r2		/* r2 = reply, no real fixup */
+-
+-___put_user_asm_l1:
+-	st.l	r3, 0, r4
+-	or	ZERO, ZERO, r2
+-
+-___put_user_asm_l_exit:
+-	ptabs	LINK, tr0
+-	blink	tr0, ZERO
+-
+-
+-	.global	__put_user_asm_q
+-__put_user_asm_q:
+-	ld.q	r2, 0, r4		/* r4 = data */
+-	movi	-(EFAULT), r2		/* r2 = reply, no real fixup */
+-
+-___put_user_asm_q1:
+-	st.q	r3, 0, r4
+-	or	ZERO, ZERO, r2
+-
+-___put_user_asm_q_exit:
+-	ptabs	LINK, tr0
+-	blink	tr0, ZERO
+-
+-panic_stash_regs:
+-	/* The idea is : when we get an unhandled panic, we dump the registers
+-	   to a known memory location, the just sit in a tight loop.
+-	   This allows the human to look at the memory region through the GDB
+-	   session (assuming the debug module's SHwy initiator isn't locked up
+-	   or anything), to hopefully analyze the cause of the panic. */
+-
+-	/* On entry, former r15 (SP) is in DCR
+-	   former r0  is at resvec_saved_area + 0
+-	   former r1  is at resvec_saved_area + 8
+-	   former tr0 is at resvec_saved_area + 32
+-	   DCR is the only register whose value is lost altogether.
+-	*/
+-
+-	movi	0xffffffff80000000, r0 ! phy of dump area
+-	ld.q	SP, 0x000, r1	! former r0
+-	st.q	r0,  0x000, r1
+-	ld.q	SP, 0x008, r1	! former r1
+-	st.q	r0,  0x008, r1
+-	st.q	r0,  0x010, r2
+-	st.q	r0,  0x018, r3
+-	st.q	r0,  0x020, r4
+-	st.q	r0,  0x028, r5
+-	st.q	r0,  0x030, r6
+-	st.q	r0,  0x038, r7
+-	st.q	r0,  0x040, r8
+-	st.q	r0,  0x048, r9
+-	st.q	r0,  0x050, r10
+-	st.q	r0,  0x058, r11
+-	st.q	r0,  0x060, r12
+-	st.q	r0,  0x068, r13
+-	st.q	r0,  0x070, r14
+-	getcon	dcr, r14
+-	st.q	r0,  0x078, r14
+-	st.q	r0,  0x080, r16
+-	st.q	r0,  0x088, r17
+-	st.q	r0,  0x090, r18
+-	st.q	r0,  0x098, r19
+-	st.q	r0,  0x0a0, r20
+-	st.q	r0,  0x0a8, r21
+-	st.q	r0,  0x0b0, r22
+-	st.q	r0,  0x0b8, r23
+-	st.q	r0,  0x0c0, r24
+-	st.q	r0,  0x0c8, r25
+-	st.q	r0,  0x0d0, r26
+-	st.q	r0,  0x0d8, r27
+-	st.q	r0,  0x0e0, r28
+-	st.q	r0,  0x0e8, r29
+-	st.q	r0,  0x0f0, r30
+-	st.q	r0,  0x0f8, r31
+-	st.q	r0,  0x100, r32
+-	st.q	r0,  0x108, r33
+-	st.q	r0,  0x110, r34
+-	st.q	r0,  0x118, r35
+-	st.q	r0,  0x120, r36
+-	st.q	r0,  0x128, r37
+-	st.q	r0,  0x130, r38
+-	st.q	r0,  0x138, r39
+-	st.q	r0,  0x140, r40
+-	st.q	r0,  0x148, r41
+-	st.q	r0,  0x150, r42
+-	st.q	r0,  0x158, r43
+-	st.q	r0,  0x160, r44
+-	st.q	r0,  0x168, r45
+-	st.q	r0,  0x170, r46
+-	st.q	r0,  0x178, r47
+-	st.q	r0,  0x180, r48
+-	st.q	r0,  0x188, r49
+-	st.q	r0,  0x190, r50
+-	st.q	r0,  0x198, r51
+-	st.q	r0,  0x1a0, r52
+-	st.q	r0,  0x1a8, r53
+-	st.q	r0,  0x1b0, r54
+-	st.q	r0,  0x1b8, r55
+-	st.q	r0,  0x1c0, r56
+-	st.q	r0,  0x1c8, r57
+-	st.q	r0,  0x1d0, r58
+-	st.q	r0,  0x1d8, r59
+-	st.q	r0,  0x1e0, r60
+-	st.q	r0,  0x1e8, r61
+-	st.q	r0,  0x1f0, r62
+-	st.q	r0,  0x1f8, r63	! bogus, but for consistency's sake...
+-
+-	ld.q	SP, 0x020, r1  ! former tr0
+-	st.q	r0,  0x200, r1
+-	gettr	tr1, r1
+-	st.q	r0,  0x208, r1
+-	gettr	tr2, r1
+-	st.q	r0,  0x210, r1
+-	gettr	tr3, r1
+-	st.q	r0,  0x218, r1
+-	gettr	tr4, r1
+-	st.q	r0,  0x220, r1
+-	gettr	tr5, r1
+-	st.q	r0,  0x228, r1
+-	gettr	tr6, r1
+-	st.q	r0,  0x230, r1
+-	gettr	tr7, r1
+-	st.q	r0,  0x238, r1
+-
+-	getcon	sr,  r1
+-	getcon	ssr,  r2
+-	getcon	pssr,  r3
+-	getcon	spc,  r4
+-	getcon	pspc,  r5
+-	getcon	intevt,  r6
+-	getcon	expevt,  r7
+-	getcon	pexpevt,  r8
+-	getcon	tra,  r9
+-	getcon	tea,  r10
+-	getcon	kcr0, r11
+-	getcon	kcr1, r12
+-	getcon	vbr,  r13
+-	getcon	resvec,  r14
+-
+-	st.q	r0,  0x240, r1
+-	st.q	r0,  0x248, r2
+-	st.q	r0,  0x250, r3
+-	st.q	r0,  0x258, r4
+-	st.q	r0,  0x260, r5
+-	st.q	r0,  0x268, r6
+-	st.q	r0,  0x270, r7
+-	st.q	r0,  0x278, r8
+-	st.q	r0,  0x280, r9
+-	st.q	r0,  0x288, r10
+-	st.q	r0,  0x290, r11
+-	st.q	r0,  0x298, r12
+-	st.q	r0,  0x2a0, r13
+-	st.q	r0,  0x2a8, r14
+-
+-	getcon	SPC,r2
+-	getcon	SSR,r3
+-	getcon	EXPEVT,r4
+-	/* Prepare to jump to C - physical address */
+-	movi	panic_handler-CONFIG_CACHED_MEMORY_OFFSET, r1
+-	ori	r1, 1, r1
+-	ptabs   r1, tr0
+-	getcon	DCR, SP
+-	blink	tr0, ZERO
+-	nop
+-	nop
+-	nop
+-	nop
+-
+-
+-
+-
+-/*
+- * --- Signal Handling Section
+- */
+-
+-/*
+- * extern long long _sa_default_rt_restorer
+- * extern long long _sa_default_restorer
+- *
+- *		 or, better,
+- *
+- * extern void _sa_default_rt_restorer(void)
+- * extern void _sa_default_restorer(void)
+- *
+- * Code prototypes to do a sys_rt_sigreturn() or sys_sysreturn()
+- * from user space. Copied into user space by signal management.
+- * Both must be quad aligned and 2 quad long (4 instructions).
+- *
+- */
+-	.balign 8
+-	.global sa_default_rt_restorer
+-sa_default_rt_restorer:
+-	movi	0x10, r9
+-	shori	__NR_rt_sigreturn, r9
+-	trapa	r9
+-	nop
+-
+-	.balign 8
+-	.global sa_default_restorer
+-sa_default_restorer:
+-	movi	0x10, r9
+-	shori	__NR_sigreturn, r9
+-	trapa	r9
+-	nop
+-
+-/*
+- * --- __ex_table Section
+- */
+-
+-/*
+- * User Access Exception Table.
+- */
+-	.section	__ex_table,  "a"
+-
+-	.global asm_uaccess_start	/* Just a marker */
+-asm_uaccess_start:
+-
+-	.long	___copy_user1, ___copy_user_exit
+-	.long	___copy_user2, ___copy_user_exit
+-	.long	___clear_user1, ___clear_user_exit
+-	.long	___strncpy_from_user1, ___strncpy_from_user_exit
+-	.long	___strnlen_user1, ___strnlen_user_exit
+-	.long	___get_user_asm_b1, ___get_user_asm_b_exit
+-	.long	___get_user_asm_w1, ___get_user_asm_w_exit
+-	.long	___get_user_asm_l1, ___get_user_asm_l_exit
+-	.long	___get_user_asm_q1, ___get_user_asm_q_exit
+-	.long	___put_user_asm_b1, ___put_user_asm_b_exit
+-	.long	___put_user_asm_w1, ___put_user_asm_w_exit
+-	.long	___put_user_asm_l1, ___put_user_asm_l_exit
+-	.long	___put_user_asm_q1, ___put_user_asm_q_exit
+-
+-	.global asm_uaccess_end		/* Just a marker */
+-asm_uaccess_end:
+-
+-
+-
+-
+-/*
+- * --- .text.init Section
+- */
+-
+-	.section	.text.init, "ax"
+-
+-/*
+- * void trap_init (void)
+- *
+- */
+-	.global	trap_init
+-trap_init:
+-	addi	SP, -24, SP			/* Room to save r28/r29/r30 */
+-	st.q	SP, 0, r28
+-	st.q	SP, 8, r29
+-	st.q	SP, 16, r30
+-
+-	/* Set VBR and RESVEC */
+-	movi	LVBR_block, r19
+-	andi	r19, -4, r19			/* reset MMUOFF + reserved */
+-	/* For RESVEC exceptions we force the MMU off, which means we need the
+-	   physical address. */
+-	movi	LRESVEC_block-CONFIG_CACHED_MEMORY_OFFSET, r20
+-	andi	r20, -4, r20			/* reset reserved */
+-	ori	r20, 1, r20			/* set MMUOFF */
+-	putcon	r19, VBR
+-	putcon	r20, RESVEC
+-
+-	/* Sanity check */
+-	movi	LVBR_block_end, r21
+-	andi	r21, -4, r21
+-	movi	BLOCK_SIZE, r29			/* r29 = expected size */
+-	or	r19, ZERO, r30
+-	add	r19, r29, r19
+-
+-	/*
+-	 * Ugly, but better loop forever now than crash afterwards.
+-	 * We should print a message, but if we touch LVBR or
+-	 * LRESVEC blocks we should not be surprised if we get stuck
+-	 * in trap_init().
+-	 */
+-	pta	trap_init_loop, tr1
+-	gettr	tr1, r28			/* r28 = trap_init_loop */
+-	sub	r21, r30, r30			/* r30 = actual size */
+-
+-	/*
+-	 * VBR/RESVEC handlers overlap by being bigger than
+-	 * allowed. Very bad. Just loop forever.
+-	 * (r28) panic/loop address
+-	 * (r29) expected size
+-	 * (r30) actual size
+-	 */
+-trap_init_loop:
+-	bne	r19, r21, tr1
+-
+-	/* Now that exception vectors are set up reset SR.BL */
+-	getcon 	SR, r22
+-	movi	SR_UNBLOCK_EXC, r23
+-	and	r22, r23, r22
+-	putcon	r22, SR
+-
+-	addi	SP, 24, SP
+-	ptabs	LINK, tr0
+-	blink	tr0, ZERO
+-
+diff --git a/arch/sh64/kernel/fpu.c b/arch/sh64/kernel/fpu.c
+deleted file mode 100644
+index 8ad4ed6..0000000
+--- a/arch/sh64/kernel/fpu.c
++++ /dev/null
+@@ -1,170 +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.
+- *
+- * arch/sh64/kernel/fpu.c
+- *
+- * Copyright (C) 2001  Manuela Cirronis, Paolo Alberelli
+- * Copyright (C) 2002  STMicroelectronics Limited
+- *   Author : Stuart Menefy
+- *
+- * Started from SH4 version:
+- *   Copyright (C) 1999, 2000  Kaz Kojima & Niibe Yutaka
+- *
+- */
+-
+-#include <linux/sched.h>
+-#include <linux/signal.h>
+-#include <asm/processor.h>
+-#include <asm/user.h>
+-#include <asm/io.h>
+-
+-/*
+- * Initially load the FPU with signalling NANS.  This bit pattern
+- * has the property that no matter whether considered as single or as
+- * double precision, it still represents a signalling NAN.
+- */
+-#define sNAN64		0xFFFFFFFFFFFFFFFFULL
+-#define sNAN32		0xFFFFFFFFUL
+-
+-static union sh_fpu_union init_fpuregs = {
+-	.hard = {
+-	  .fp_regs = { [0 ... 63] = sNAN32 },
+-	  .fpscr = FPSCR_INIT
+-	}
+-};
+-
+-inline void fpsave(struct sh_fpu_hard_struct *fpregs)
+-{
+-	asm volatile("fst.p     %0, (0*8), fp0\n\t"
+-		     "fst.p     %0, (1*8), fp2\n\t"
+-		     "fst.p     %0, (2*8), fp4\n\t"
+-		     "fst.p     %0, (3*8), fp6\n\t"
+-		     "fst.p     %0, (4*8), fp8\n\t"
+-		     "fst.p     %0, (5*8), fp10\n\t"
+-		     "fst.p     %0, (6*8), fp12\n\t"
+-		     "fst.p     %0, (7*8), fp14\n\t"
+-		     "fst.p     %0, (8*8), fp16\n\t"
+-		     "fst.p     %0, (9*8), fp18\n\t"
+-		     "fst.p     %0, (10*8), fp20\n\t"
+-		     "fst.p     %0, (11*8), fp22\n\t"
+-		     "fst.p     %0, (12*8), fp24\n\t"
+-		     "fst.p     %0, (13*8), fp26\n\t"
+-		     "fst.p     %0, (14*8), fp28\n\t"
+-		     "fst.p     %0, (15*8), fp30\n\t"
+-		     "fst.p     %0, (16*8), fp32\n\t"
+-		     "fst.p     %0, (17*8), fp34\n\t"
+-		     "fst.p     %0, (18*8), fp36\n\t"
+-		     "fst.p     %0, (19*8), fp38\n\t"
+-		     "fst.p     %0, (20*8), fp40\n\t"
+-		     "fst.p     %0, (21*8), fp42\n\t"
+-		     "fst.p     %0, (22*8), fp44\n\t"
+-		     "fst.p     %0, (23*8), fp46\n\t"
+-		     "fst.p     %0, (24*8), fp48\n\t"
+-		     "fst.p     %0, (25*8), fp50\n\t"
+-		     "fst.p     %0, (26*8), fp52\n\t"
+-		     "fst.p     %0, (27*8), fp54\n\t"
+-		     "fst.p     %0, (28*8), fp56\n\t"
+-		     "fst.p     %0, (29*8), fp58\n\t"
+-		     "fst.p     %0, (30*8), fp60\n\t"
+-		     "fst.p     %0, (31*8), fp62\n\t"
+-
+-		     "fgetscr   fr63\n\t"
+-		     "fst.s     %0, (32*8), fr63\n\t"
+-		: /* no output */
+-		: "r" (fpregs)
+-		: "memory");
+-}
+-
+-
+-static inline void
+-fpload(struct sh_fpu_hard_struct *fpregs)
+-{
+-	asm volatile("fld.p     %0, (0*8), fp0\n\t"
+-		     "fld.p     %0, (1*8), fp2\n\t"
+-		     "fld.p     %0, (2*8), fp4\n\t"
+-		     "fld.p     %0, (3*8), fp6\n\t"
+-		     "fld.p     %0, (4*8), fp8\n\t"
+-		     "fld.p     %0, (5*8), fp10\n\t"
+-		     "fld.p     %0, (6*8), fp12\n\t"
+-		     "fld.p     %0, (7*8), fp14\n\t"
+-		     "fld.p     %0, (8*8), fp16\n\t"
+-		     "fld.p     %0, (9*8), fp18\n\t"
+-		     "fld.p     %0, (10*8), fp20\n\t"
+-		     "fld.p     %0, (11*8), fp22\n\t"
+-		     "fld.p     %0, (12*8), fp24\n\t"
+-		     "fld.p     %0, (13*8), fp26\n\t"
+-		     "fld.p     %0, (14*8), fp28\n\t"
+-		     "fld.p     %0, (15*8), fp30\n\t"
+-		     "fld.p     %0, (16*8), fp32\n\t"
+-		     "fld.p     %0, (17*8), fp34\n\t"
+-		     "fld.p     %0, (18*8), fp36\n\t"
+-		     "fld.p     %0, (19*8), fp38\n\t"
+-		     "fld.p     %0, (20*8), fp40\n\t"
+-		     "fld.p     %0, (21*8), fp42\n\t"
+-		     "fld.p     %0, (22*8), fp44\n\t"
+-		     "fld.p     %0, (23*8), fp46\n\t"
+-		     "fld.p     %0, (24*8), fp48\n\t"
+-		     "fld.p     %0, (25*8), fp50\n\t"
+-		     "fld.p     %0, (26*8), fp52\n\t"
+-		     "fld.p     %0, (27*8), fp54\n\t"
+-		     "fld.p     %0, (28*8), fp56\n\t"
+-		     "fld.p     %0, (29*8), fp58\n\t"
+-		     "fld.p     %0, (30*8), fp60\n\t"
+-
+-		     "fld.s     %0, (32*8), fr63\n\t"
+-		     "fputscr   fr63\n\t"
+-
+-		     "fld.p     %0, (31*8), fp62\n\t"
+-		: /* no output */
+-		: "r" (fpregs) );
+-}
+-
+-void fpinit(struct sh_fpu_hard_struct *fpregs)
+-{
+-	*fpregs = init_fpuregs.hard;
+-}
+-
+-asmlinkage void
+-do_fpu_error(unsigned long ex, struct pt_regs *regs)
+-{
+-	struct task_struct *tsk = current;
+-
+-	regs->pc += 4;
+-
+-	tsk->thread.trap_no = 11;
+-	tsk->thread.error_code = 0;
+-	force_sig(SIGFPE, tsk);
+-}
+-
+-
+-asmlinkage void
+-do_fpu_state_restore(unsigned long ex, struct pt_regs *regs)
+-{
+-	void die(const char *str, struct pt_regs *regs, long err);
+-
+-	if (! user_mode(regs))
+-		die("FPU used in kernel", regs, ex);
+-
+-	regs->sr &= ~SR_FD;
+-
+-	if (last_task_used_math == current)
+-		return;
+-
+-	grab_fpu();
+-	if (last_task_used_math != NULL) {
+-		/* Other processes fpu state, save away */
+-		fpsave(&last_task_used_math->thread.fpu.hard);
+-        }
+-        last_task_used_math = current;
+-        if (used_math()) {
+-                fpload(&current->thread.fpu.hard);
+-        } else {
+-		/* First time FPU user.  */
+-		fpload(&init_fpuregs.hard);
+-                set_used_math();
+-        }
+-	release_fpu();
+-}
+-
+diff --git a/arch/sh64/kernel/head.S b/arch/sh64/kernel/head.S
+deleted file mode 100644
+index 186406d..0000000
+--- a/arch/sh64/kernel/head.S
++++ /dev/null
+@@ -1,372 +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.
+- *
+- * arch/sh64/kernel/head.S
+- *
+- * Copyright (C) 2000, 2001  Paolo Alberelli
+- * Copyright (C) 2003, 2004  Paul Mundt
+- *
+- *
+- * benedict.gaster at superh.com:	 2nd May 2002
+- *    Moved definition of empty_zero_page to its own section allowing
+- *    it to be placed at an absolute address known at load time.
+- *
+- * lethal at linux-sh.org:          9th May 2003
+- *    Kill off GLOBAL_NAME() usage.
+- *
+- * lethal at linux-sh.org:          8th May 2004
+- *    Add early SCIF console DTLB mapping.
+- */
+-
+-
+-#include <asm/page.h>
+-#include <asm/mmu_context.h>
+-#include <asm/cache.h>
+-#include <asm/tlb.h>
+-#include <asm/processor.h>
+-#include <asm/registers.h>
+-#include <asm/thread_info.h>
+-
+-/*
+- * MMU defines: TLB boundaries.
+- */
+-
+-#define MMUIR_FIRST	ITLB_FIXED
+-#define MMUIR_END	ITLB_LAST_VAR_UNRESTRICTED+TLB_STEP
+-#define MMUIR_STEP	TLB_STEP
+-
+-#define MMUDR_FIRST	DTLB_FIXED
+-#define MMUDR_END	DTLB_LAST_VAR_UNRESTRICTED+TLB_STEP
+-#define MMUDR_STEP	TLB_STEP
+-
+-/* Safety check : CONFIG_CACHED_MEMORY_OFFSET has to be a multiple of 512Mb */
+-#if (CONFIG_CACHED_MEMORY_OFFSET & ((1UL<<29)-1))
+-#error "CONFIG_CACHED_MEMORY_OFFSET must be a multiple of 512Mb"
+-#endif
+-
+-/*
+- * MMU defines: Fixed TLBs.
+- */
+-/* Deal safely with the case where the base of RAM is not 512Mb aligned */
+-
+-#define ALIGN_512M_MASK (0xffffffffe0000000)
+-#define ALIGNED_EFFECTIVE ((CONFIG_CACHED_MEMORY_OFFSET + CONFIG_MEMORY_START) & ALIGN_512M_MASK)
+-#define ALIGNED_PHYSICAL (CONFIG_MEMORY_START & ALIGN_512M_MASK)
+-
+-#define MMUIR_TEXT_H	(0x0000000000000003 | ALIGNED_EFFECTIVE)
+-			/* Enabled, Shared, ASID 0, Eff. Add. 0xA0000000 */
+-
+-#define MMUIR_TEXT_L	(0x000000000000009a | ALIGNED_PHYSICAL)
+-			/* 512 Mb, Cacheable, Write-back, execute, Not User, Ph. Add. */
+-
+-#define MMUDR_CACHED_H	0x0000000000000003 | ALIGNED_EFFECTIVE
+-			/* Enabled, Shared, ASID 0, Eff. Add. 0xA0000000 */
+-#define MMUDR_CACHED_L	0x000000000000015a | ALIGNED_PHYSICAL
+-			/* 512 Mb, Cacheable, Write-back, read/write, Not User, Ph. Add. */
+-
+-#ifdef CONFIG_ICACHE_DISABLED
+-#define	ICCR0_INIT_VAL	ICCR0_OFF			/* ICACHE off */
+-#else
+-#define	ICCR0_INIT_VAL	ICCR0_ON | ICCR0_ICI		/* ICE + ICI */
+-#endif
+-#define	ICCR1_INIT_VAL	ICCR1_NOLOCK			/* No locking */
+-
+-#if defined (CONFIG_DCACHE_DISABLED)
+-#define	OCCR0_INIT_VAL	OCCR0_OFF			   /* D-cache: off  */
+-#elif defined (CONFIG_DCACHE_WRITE_THROUGH)
+-#define	OCCR0_INIT_VAL	OCCR0_ON | OCCR0_OCI | OCCR0_WT	   /* D-cache: on,   */
+-							   /* WT, invalidate */
+-#elif defined (CONFIG_DCACHE_WRITE_BACK)
+-#define	OCCR0_INIT_VAL	OCCR0_ON | OCCR0_OCI | OCCR0_WB	   /* D-cache: on,   */
+-							   /* WB, invalidate */
+-#else
+-#error preprocessor flag CONFIG_DCACHE_... not recognized!
+-#endif
+-
+-#define	OCCR1_INIT_VAL	OCCR1_NOLOCK			   /* No locking     */
+-
+-	.section	.empty_zero_page, "aw"
+-	.global empty_zero_page
+-
+-empty_zero_page:
+-	.long	1		/* MOUNT_ROOT_RDONLY */
+-	.long	0		/* RAMDISK_FLAGS */
+-	.long	0x0200		/* ORIG_ROOT_DEV */
+-	.long	1		/* LOADER_TYPE */
+-	.long	0x00800000	/* INITRD_START */
+-	.long	0x00800000	/* INITRD_SIZE */
+-	.long	0
+-
+-	.text
+-	.balign 4096,0,4096
+-
+-	.section	.data, "aw"
+-	.balign	PAGE_SIZE
+-
+-	.section	.data, "aw"
+-	.balign	PAGE_SIZE
+-
+-	.global swapper_pg_dir
+-swapper_pg_dir:
+-	.space PAGE_SIZE, 0
+-
+-	.global empty_bad_page
+-empty_bad_page:
+-	.space PAGE_SIZE, 0
+-
+-	.global empty_bad_pte_table
+-empty_bad_pte_table:
+-	.space PAGE_SIZE, 0
+-
+-	.global	fpu_in_use
+-fpu_in_use:	.quad	0
+-
+-
+-	.section	.text.head, "ax"
+-	.balign L1_CACHE_BYTES
+-/*
+- * Condition at the entry of __stext:
+- * . Reset state:
+- *   . SR.FD    = 1		(FPU disabled)
+- *   . SR.BL    = 1		(Exceptions disabled)
+- *   . SR.MD    = 1		(Privileged Mode)
+- *   . SR.MMU   = 0		(MMU Disabled)
+- *   . SR.CD    = 0		(CTC User Visible)
+- *   . SR.IMASK = Undefined	(Interrupt Mask)
+- *
+- * Operations supposed to be performed by __stext:
+- * . prevent speculative fetch onto device memory while MMU is off
+- * . reflect as much as possible SH5 ABI (r15, r26, r27, r18)
+- * . first, save CPU state and set it to something harmless
+- * . any CPU detection and/or endianness settings (?)
+- * . initialize EMI/LMI (but not TMU/RTC/INTC/SCIF): TBD
+- * . set initial TLB entries for cached and uncached regions
+- *   (no fine granularity paging)
+- * . set initial cache state
+- * . enable MMU and caches
+- * . set CPU to a consistent state
+- *   . registers (including stack pointer and current/KCR0)
+- *   . NOT expecting to set Exception handling nor VBR/RESVEC/DCR
+- *     at this stage. This is all to later Linux initialization steps.
+- *   . initialize FPU
+- * . clear BSS
+- * . jump into start_kernel()
+- * . be prepared to hopeless start_kernel() returns.
+- *
+- */
+-	.global _stext
+-_stext:
+-	/*
+-	 * Prevent speculative fetch on device memory due to
+-	 * uninitialized target registers.
+-	 */
+-	ptabs/u	ZERO, tr0
+-	ptabs/u	ZERO, tr1
+-	ptabs/u	ZERO, tr2
+-	ptabs/u	ZERO, tr3
+-	ptabs/u	ZERO, tr4
+-	ptabs/u	ZERO, tr5
+-	ptabs/u	ZERO, tr6
+-	ptabs/u	ZERO, tr7
+-	synci
+-
+-	/*
+-	 * Read/Set CPU state. After this block:
+-	 * r29 = Initial SR
+-	 */
+-	getcon	SR, r29
+-	movi	SR_HARMLESS, r20
+-	putcon	r20, SR
+-
+-	/*
+-	 * Initialize EMI/LMI. To Be Done.
+-	 */
+-
+-	/*
+-	 * CPU detection and/or endianness settings (?). To Be Done.
+-	 * Pure PIC code here, please ! Just save state into r30.
+-         * After this block:
+-	 * r30 = CPU type/Platform Endianness
+-	 */
+-
+-	/*
+-	 * Set initial TLB entries for cached and uncached regions.
+-	 * Note: PTA/BLINK is PIC code, PTABS/BLINK isn't !
+-	 */
+-	/* Clear ITLBs */
+-	pta	clear_ITLB, tr1
+-	movi	MMUIR_FIRST, r21
+-	movi	MMUIR_END, r22
+-clear_ITLB:
+-	putcfg	r21, 0, ZERO		/* Clear MMUIR[n].PTEH.V */
+-	addi	r21, MMUIR_STEP, r21
+-        bne	r21, r22, tr1
+-
+-	/* Clear DTLBs */
+-	pta	clear_DTLB, tr1
+-	movi	MMUDR_FIRST, r21
+-	movi	MMUDR_END, r22
+-clear_DTLB:
+-	putcfg	r21, 0, ZERO		/* Clear MMUDR[n].PTEH.V */
+-	addi	r21, MMUDR_STEP, r21
+-        bne	r21, r22, tr1
+-
+-	/* Map one big (512Mb) page for ITLB */
+-	movi	MMUIR_FIRST, r21
+-	movi	MMUIR_TEXT_L, r22	/* PTEL first */
+-	add.l	r22, r63, r22		/* Sign extend */
+-	putcfg	r21, 1, r22		/* Set MMUIR[0].PTEL */
+-	movi	MMUIR_TEXT_H, r22	/* PTEH last */
+-	add.l	r22, r63, r22		/* Sign extend */
+-	putcfg	r21, 0, r22		/* Set MMUIR[0].PTEH */
+-
+-	/* Map one big CACHED (512Mb) page for DTLB */
+-	movi	MMUDR_FIRST, r21
+-	movi	MMUDR_CACHED_L, r22	/* PTEL first */
+-	add.l	r22, r63, r22		/* Sign extend */
+-	putcfg	r21, 1, r22		/* Set MMUDR[0].PTEL */
+-	movi	MMUDR_CACHED_H, r22	/* PTEH last */
+-	add.l	r22, r63, r22		/* Sign extend */
+-	putcfg	r21, 0, r22		/* Set MMUDR[0].PTEH */
+-
+-#ifdef CONFIG_EARLY_PRINTK
+-	/*
+-	 * Setup a DTLB translation for SCIF phys.
+-	 */
+-	addi    r21, MMUDR_STEP, r21
+-	movi    0x0a03, r22	/* SCIF phys */
+-	shori   0x0148, r22
+-	putcfg  r21, 1, r22	/* PTEL first */
+-	movi    0xfa03, r22	/* 0xfa030000, fixed SCIF virt */
+-	shori   0x0003, r22
+-	putcfg  r21, 0, r22	/* PTEH last */
+-#endif
+-
+-	/*
+-	 * Set cache behaviours.
+-	 */
+-	/* ICache */
+-	movi	ICCR_BASE, r21
+-	movi	ICCR0_INIT_VAL, r22
+-	movi	ICCR1_INIT_VAL, r23
+-	putcfg	r21, ICCR_REG0, r22
+-	putcfg	r21, ICCR_REG1, r23
+-
+-	/* OCache */
+-	movi	OCCR_BASE, r21
+-	movi	OCCR0_INIT_VAL, r22
+-	movi	OCCR1_INIT_VAL, r23
+-	putcfg	r21, OCCR_REG0, r22
+-	putcfg	r21, OCCR_REG1, r23
+-
+-
+-	/*
+-	 * Enable Caches and MMU. Do the first non-PIC jump.
+-         * Now head.S global variables, constants and externs
+-	 * can be used.
+-	 */
+-	getcon	SR, r21
+-	movi	SR_ENABLE_MMU, r22
+-	or	r21, r22, r21
+-	putcon	r21, SSR
+-	movi	hyperspace, r22
+-	ori	r22, 1, r22	    /* Make it SHmedia, not required but..*/
+-	putcon	r22, SPC
+-	synco
+-	rte			    /* And now go into the hyperspace ... */
+-hyperspace:			    /* ... that's the next instruction !  */
+-
+-	/*
+-	 * Set CPU to a consistent state.
+-	 * r31 = FPU support flag
+-	 * tr0/tr7 in use. Others give a chance to loop somewhere safe
+-	 */
+-	movi	start_kernel, r32
+-	ori	r32, 1, r32
+-
+-	ptabs	r32, tr0		    /* r32 = _start_kernel address        */
+-	pta/u	hopeless, tr1
+-	pta/u	hopeless, tr2
+-	pta/u	hopeless, tr3
+-	pta/u	hopeless, tr4
+-	pta/u	hopeless, tr5
+-	pta/u	hopeless, tr6
+-	pta/u	hopeless, tr7
+-	gettr	tr1, r28			/* r28 = hopeless address */
+-
+-	/* Set initial stack pointer */
+-	movi	init_thread_union, SP
+-	putcon	SP, KCR0		/* Set current to init_task */
+-	movi	THREAD_SIZE, r22	/* Point to the end */
+-	add	SP, r22, SP
+-
+-	/*
+-	 * Initialize FPU.
+-	 * Keep FPU flag in r31. After this block:
+-	 * r31 = FPU flag
+-	 */
+-	movi fpu_in_use, r31	/* Temporary */
+-
+-#ifdef CONFIG_SH_FPU
+-	getcon	SR, r21
+-	movi	SR_ENABLE_FPU, r22
+-	and	r21, r22, r22
+-	putcon	r22, SR			/* Try to enable */
+-	getcon	SR, r22
+-	xor	r21, r22, r21
+-	shlri	r21, 15, r21		/* Supposedly 0/1 */
+-	st.q	r31, 0 , r21		/* Set fpu_in_use */
+-#else
+-	movi	0, r21
+-	st.q	r31, 0 , r21		/* Set fpu_in_use */
+-#endif
+-	or	r21, ZERO, r31		/* Set FPU flag at last */
+-
+-#ifndef CONFIG_SH_NO_BSS_INIT
+-/* Don't clear BSS if running on slow platforms such as an RTL simulation,
+-   remote memory via SHdebug link, etc.  For these the memory can be guaranteed
+-   to be all zero on boot anyway. */
+-	/*
+-	 * Clear bss
+-	 */
+-	pta	clear_quad, tr1
+-	movi	__bss_start, r22
+-	movi	_end, r23
+-clear_quad:
+-	st.q	r22, 0, ZERO
+-	addi	r22, 8, r22
+-	bne	r22, r23, tr1		/* Both quad aligned, see vmlinux.lds.S */
+-#endif
+-	pta/u	hopeless, tr1
+-
+-	/* Say bye to head.S but be prepared to wrongly get back ... */
+-	blink	tr0, LINK
+-
+-	/* If we ever get back here through LINK/tr1-tr7 */
+-	pta/u	hopeless, tr7
+-
+-hopeless:
+-	/*
+-	 * Something's badly wrong here. Loop endlessly,
+-         * there's nothing more we can do about it.
+-	 *
+-	 * Note on hopeless: it can be jumped into invariably
+-	 * before or after jumping into hyperspace. The only
+-	 * requirement is to be PIC called (PTA) before and
+-	 * any way (PTA/PTABS) after. According to Virtual
+-	 * to Physical mapping a simulator/emulator can easily
+-	 * tell where we came here from just looking at hopeless
+-	 * (PC) address.
+-	 *
+-	 * For debugging purposes:
+-	 * (r28) hopeless/loop address
+-	 * (r29) Original SR
+-	 * (r30) CPU type/Platform endianness
+-	 * (r31) FPU Support
+-	 * (r32) _start_kernel address
+-	 */
+-	blink	tr7, ZERO
+-
+-
+diff --git a/arch/sh64/kernel/init_task.c b/arch/sh64/kernel/init_task.c
+deleted file mode 100644
+index deee8bf..0000000
+--- a/arch/sh64/kernel/init_task.c
++++ /dev/null
+@@ -1,46 +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.
+- *
+- * arch/sh64/kernel/init_task.c
+- *
+- * Copyright (C) 2000, 2001  Paolo Alberelli
+- * Copyright (C) 2003  Paul Mundt
+- *
+- */
+-#include <linux/rwsem.h>
+-#include <linux/mm.h>
+-#include <linux/sched.h>
+-#include <linux/init_task.h>
+-#include <linux/mqueue.h>
+-#include <linux/fs.h>
+-#include <asm/uaccess.h>
+-#include <asm/pgtable.h>
+-
+-static struct fs_struct init_fs = INIT_FS;
+-static struct files_struct init_files = INIT_FILES;
+-static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
+-static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
+-struct mm_struct init_mm = INIT_MM(init_mm);
+-
+-struct pt_regs fake_swapper_regs;
+-
+-/*
+- * Initial thread structure.
+- *
+- * We need to make sure that this is THREAD_SIZE-byte aligned due
+- * to the way process stacks are handled. This is done by having a
+- * special "init_task" linker map entry..
+- */
+-union thread_union init_thread_union
+-	__attribute__((__section__(".data.init_task"))) =
+-		{ INIT_THREAD_INFO(init_task) };
+-
+-/*
+- * Initial task structure.
+- *
+- * All other task structs will be allocated on slabs in fork.c
+- */
+-struct task_struct init_task = INIT_TASK(init_task);
+-
+diff --git a/arch/sh64/kernel/irq.c b/arch/sh64/kernel/irq.c
+deleted file mode 100644
+index 9412b71..0000000
+--- a/arch/sh64/kernel/irq.c
++++ /dev/null
+@@ -1,115 +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.
+- *
+- * arch/sh64/kernel/irq.c
+- *
+- * Copyright (C) 2000, 2001  Paolo Alberelli
+- * Copyright (C) 2003  Paul Mundt
+- *
+- */
+-
+-/*
+- * IRQs are in fact implemented a bit like signal handlers for the kernel.
+- * Naturally it's not a 1:1 relation, but there are similarities.
+- */
+-
+-#include <linux/errno.h>
+-#include <linux/kernel_stat.h>
+-#include <linux/signal.h>
+-#include <linux/rwsem.h>
+-#include <linux/sched.h>
+-#include <linux/ioport.h>
+-#include <linux/interrupt.h>
+-#include <linux/timex.h>
+-#include <linux/slab.h>
+-#include <linux/random.h>
+-#include <linux/smp.h>
+-#include <linux/init.h>
+-#include <linux/seq_file.h>
+-#include <linux/bitops.h>
+-#include <asm/system.h>
+-#include <asm/io.h>
+-#include <asm/smp.h>
+-#include <asm/pgalloc.h>
+-#include <asm/delay.h>
+-#include <asm/irq.h>
+-#include <linux/irq.h>
+-
+-void ack_bad_irq(unsigned int irq)
+-{
+-	printk("unexpected IRQ trap at irq %02x\n", irq);
+-}
+-
+-#if defined(CONFIG_PROC_FS)
+-int show_interrupts(struct seq_file *p, void *v)
+-{
+-	int i = *(loff_t *) v, j;
+-	struct irqaction * action;
+-	unsigned long flags;
+-
+-	if (i == 0) {
+-		seq_puts(p, "           ");
+-		for_each_online_cpu(j)
+-			seq_printf(p, "CPU%d       ",j);
+-		seq_putc(p, '\n');
+-	}
+-
+-	if (i < NR_IRQS) {
+-		spin_lock_irqsave(&irq_desc[i].lock, flags);
+-		action = irq_desc[i].action;
+-		if (!action)
+-			goto unlock;
+-		seq_printf(p, "%3d: ",i);
+-		seq_printf(p, "%10u ", kstat_irqs(i));
+-		seq_printf(p, " %14s", irq_desc[i].chip->typename);
+-		seq_printf(p, "  %s", action->name);
+-
+-		for (action=action->next; action; action = action->next)
+-			seq_printf(p, ", %s", action->name);
+-		seq_putc(p, '\n');
+-unlock:
+-		spin_unlock_irqrestore(&irq_desc[i].lock, flags);
+-	}
+-	return 0;
+-}
+-#endif
+-
+-/*
+- * do_NMI handles all Non-Maskable Interrupts.
+- */
+-asmlinkage void do_NMI(unsigned long vector_num, struct pt_regs * regs)
+-{
+-	if (regs->sr & 0x40000000)
+-		printk("unexpected NMI trap in system mode\n");
+-	else
+-		printk("unexpected NMI trap in user mode\n");
+-
+-	/* No statistics */
+-}
+-
+-/*
+- * do_IRQ handles all normal device IRQ's.
+- */
+-asmlinkage int do_IRQ(unsigned long vector_num, struct pt_regs * regs)
+-{
+-	struct pt_regs *old_regs = set_irq_regs(regs);
+-	int irq;
+-
+-	irq_enter();
+-
+-	irq = irq_demux(vector_num);
+-
+-	if (irq >= 0) {
+-		__do_IRQ(irq);
+-	} else {
+-		printk("unexpected IRQ trap at vector %03lx\n", vector_num);
+-	}
+-
+-	irq_exit();
+-
+-	set_irq_regs(old_regs);
+-	return 1;
+-}
+-
+diff --git a/arch/sh64/kernel/irq_intc.c b/arch/sh64/kernel/irq_intc.c
+deleted file mode 100644
+index 3b63a93..0000000
+--- a/arch/sh64/kernel/irq_intc.c
++++ /dev/null
+@@ -1,272 +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.
+- *
+- * arch/sh64/kernel/irq_intc.c
+- *
+- * Copyright (C) 2000, 2001  Paolo Alberelli
+- * Copyright (C) 2003  Paul Mundt
+- *
+- * Interrupt Controller support for SH5 INTC.
+- * Per-interrupt selective. IRLM=0 (Fixed priority) is not
+- * supported being useless without a cascaded interrupt
+- * controller.
+- *
+- */
+-
+-#include <linux/init.h>
+-#include <linux/interrupt.h>
+-#include <linux/irq.h>
+-#include <linux/kernel.h>
+-#include <linux/stddef.h>
+-#include <linux/bitops.h>       /* this includes also <asm/registers.h */
+-                                /* which is required to remap register */
+-                                /* names used into __asm__ blocks...   */
+-
+-#include <asm/hardware.h>
+-#include <asm/platform.h>
+-#include <asm/page.h>
+-#include <asm/io.h>
+-#include <asm/irq.h>
+-
+-/*
+- * Maybe the generic Peripheral block could move to a more
+- * generic include file. INTC Block will be defined here
+- * and only here to make INTC self-contained in a single
+- * file.
+- */
+-#define	INTC_BLOCK_OFFSET	0x01000000
+-
+-/* Base */
+-#define INTC_BASE		PHYS_PERIPHERAL_BLOCK + \
+-				INTC_BLOCK_OFFSET
+-
+-/* Address */
+-#define INTC_ICR_SET		(intc_virt + 0x0)
+-#define INTC_ICR_CLEAR		(intc_virt + 0x8)
+-#define INTC_INTPRI_0		(intc_virt + 0x10)
+-#define INTC_INTSRC_0		(intc_virt + 0x50)
+-#define INTC_INTSRC_1		(intc_virt + 0x58)
+-#define INTC_INTREQ_0		(intc_virt + 0x60)
+-#define INTC_INTREQ_1		(intc_virt + 0x68)
+-#define INTC_INTENB_0		(intc_virt + 0x70)
+-#define INTC_INTENB_1		(intc_virt + 0x78)
+-#define INTC_INTDSB_0		(intc_virt + 0x80)
+-#define INTC_INTDSB_1		(intc_virt + 0x88)
+-
+-#define INTC_ICR_IRLM		0x1
+-#define	INTC_INTPRI_PREGS	8		/* 8 Priority Registers */
+-#define	INTC_INTPRI_PPREG	8		/* 8 Priorities per Register */
+-
+-
+-/*
+- * Mapper between the vector ordinal and the IRQ number
+- * passed to kernel/device drivers.
+- */
+-int intc_evt_to_irq[(0xE20/0x20)+1] = {
+-	-1, -1, -1, -1, -1, -1, -1, -1,	/* 0x000 - 0x0E0 */
+-	-1, -1, -1, -1, -1, -1, -1, -1,	/* 0x100 - 0x1E0 */
+-	 0,  0,  0,  0,  0,  1,  0,  0,	/* 0x200 - 0x2E0 */
+-	 2,  0,  0,  3,  0,  0,  0, -1,	/* 0x300 - 0x3E0 */
+-	32, 33, 34, 35, 36, 37, 38, -1,	/* 0x400 - 0x4E0 */
+-	-1, -1, -1, 63, -1, -1, -1, -1,	/* 0x500 - 0x5E0 */
+-	-1, -1, 18, 19, 20, 21, 22, -1,	/* 0x600 - 0x6E0 */
+-	39, 40, 41, 42, -1, -1, -1, -1,	/* 0x700 - 0x7E0 */
+-	 4,  5,  6,  7, -1, -1, -1, -1,	/* 0x800 - 0x8E0 */
+-	-1, -1, -1, -1, -1, -1, -1, -1,	/* 0x900 - 0x9E0 */
+-	12, 13, 14, 15, 16, 17, -1, -1,	/* 0xA00 - 0xAE0 */
+-	-1, -1, -1, -1, -1, -1, -1, -1,	/* 0xB00 - 0xBE0 */
+-	-1, -1, -1, -1, -1, -1, -1, -1,	/* 0xC00 - 0xCE0 */
+-	-1, -1, -1, -1, -1, -1, -1, -1,	/* 0xD00 - 0xDE0 */
+-	-1, -1				/* 0xE00 - 0xE20 */
+-};
+-
+-/*
+- * Opposite mapper.
+- */
+-static int IRQ_to_vectorN[NR_INTC_IRQS] = {
+-	0x12, 0x15, 0x18, 0x1B, 0x40, 0x41, 0x42, 0x43, /*  0- 7 */
+-	  -1,   -1,   -1,   -1, 0x50, 0x51, 0x52, 0x53,	/*  8-15 */
+-	0x54, 0x55, 0x32, 0x33, 0x34, 0x35, 0x36,   -1, /* 16-23 */
+-	  -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, /* 24-31 */
+-	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x38,	/* 32-39 */
+-        0x39, 0x3A, 0x3B,   -1,   -1,   -1,   -1,   -1, /* 40-47 */
+-	  -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, /* 48-55 */
+-	  -1,   -1,   -1,   -1,   -1,   -1,   -1, 0x2B, /* 56-63 */
+-
+-};
+-
+-static unsigned long intc_virt;
+-
+-static unsigned int startup_intc_irq(unsigned int irq);
+-static void shutdown_intc_irq(unsigned int irq);
+-static void enable_intc_irq(unsigned int irq);
+-static void disable_intc_irq(unsigned int irq);
+-static void mask_and_ack_intc(unsigned int);
+-static void end_intc_irq(unsigned int irq);
+-
+-static struct hw_interrupt_type intc_irq_type = {
+-	.typename = "INTC",
+-	.startup = startup_intc_irq,
+-	.shutdown = shutdown_intc_irq,
+-	.enable = enable_intc_irq,
+-	.disable = disable_intc_irq,
+-	.ack = mask_and_ack_intc,
+-	.end = end_intc_irq
+-};
+-
+-static int irlm;		/* IRL mode */
+-
+-static unsigned int startup_intc_irq(unsigned int irq)
+-{
+-	enable_intc_irq(irq);
+-	return 0; /* never anything pending */
+-}
+-
+-static void shutdown_intc_irq(unsigned int irq)
+-{
+-	disable_intc_irq(irq);
+-}
+-
+-static void enable_intc_irq(unsigned int irq)
+-{
+-	unsigned long reg;
+-	unsigned long bitmask;
+-
+-	if ((irq <= IRQ_IRL3) && (irlm == NO_PRIORITY))
+-		printk("Trying to use straight IRL0-3 with an encoding platform.\n");
+-
+-	if (irq < 32) {
+-		reg = INTC_INTENB_0;
+-		bitmask = 1 << irq;
+-	} else {
+-		reg = INTC_INTENB_1;
+-		bitmask = 1 << (irq - 32);
+-	}
+-
+-	ctrl_outl(bitmask, reg);
+-}
+-
+-static void disable_intc_irq(unsigned int irq)
+-{
+-	unsigned long reg;
+-	unsigned long bitmask;
+-
+-	if (irq < 32) {
+-		reg = INTC_INTDSB_0;
+-		bitmask = 1 << irq;
+-	} else {
+-		reg = INTC_INTDSB_1;
+-		bitmask = 1 << (irq - 32);
+-	}
+-
+-	ctrl_outl(bitmask, reg);
+-}
+-
+-static void mask_and_ack_intc(unsigned int irq)
+-{
+-	disable_intc_irq(irq);
+-}
+-
+-static void end_intc_irq(unsigned int irq)
+-{
+-	enable_intc_irq(irq);
+-}
+-
+-/* For future use, if we ever support IRLM=0) */
+-void make_intc_irq(unsigned int irq)
+-{
+-	disable_irq_nosync(irq);
+-	irq_desc[irq].chip = &intc_irq_type;
+-	disable_intc_irq(irq);
+-}
+-
+-#if defined(CONFIG_PROC_FS) && defined(CONFIG_SYSCTL)
+-int intc_irq_describe(char* p, int irq)
+-{
+-	if (irq < NR_INTC_IRQS)
+-		return sprintf(p, "(0x%3x)", IRQ_to_vectorN[irq]*0x20);
+-	else
+-		return 0;
+-}
+-#endif
+-
+-void __init init_IRQ(void)
+-{
+-        unsigned long long __dummy0, __dummy1=~0x00000000100000f0;
+-	unsigned long reg;
+-	unsigned long data;
+-	int i;
+-
+-	intc_virt = onchip_remap(INTC_BASE, 1024, "INTC");
+-	if (!intc_virt) {
+-		panic("Unable to remap INTC\n");
+-	}
+-
+-
+-	/* Set default: per-line enable/disable, priority driven ack/eoi */
+-	for (i = 0; i < NR_INTC_IRQS; i++) {
+-		if (platform_int_priority[i] != NO_PRIORITY) {
+-			irq_desc[i].chip = &intc_irq_type;
+-		}
+-	}
+-
+-
+-	/* Disable all interrupts and set all priorities to 0 to avoid trouble */
+-	ctrl_outl(-1, INTC_INTDSB_0);
+-	ctrl_outl(-1, INTC_INTDSB_1);
+-
+-	for (reg = INTC_INTPRI_0, i = 0; i < INTC_INTPRI_PREGS; i++, reg += 8)
+-		ctrl_outl( NO_PRIORITY, reg);
+-
+-
+-	/* Set IRLM */
+-	/* If all the priorities are set to 'no priority', then
+-	 * assume we are using encoded mode.
+-	 */
+-	irlm = platform_int_priority[IRQ_IRL0] + platform_int_priority[IRQ_IRL1] + \
+-		platform_int_priority[IRQ_IRL2] + platform_int_priority[IRQ_IRL3];
+-
+-	if (irlm == NO_PRIORITY) {
+-		/* IRLM = 0 */
+-		reg = INTC_ICR_CLEAR;
+-		i = IRQ_INTA;
+-		printk("Trying to use encoded IRL0-3. IRLs unsupported.\n");
+-	} else {
+-		/* IRLM = 1 */
+-		reg = INTC_ICR_SET;
+-		i = IRQ_IRL0;
+-	}
+-	ctrl_outl(INTC_ICR_IRLM, reg);
+-
+-	/* Set interrupt priorities according to platform description */
+-	for (data = 0, reg = INTC_INTPRI_0; i < NR_INTC_IRQS; i++) {
+-		data |= platform_int_priority[i] << ((i % INTC_INTPRI_PPREG) * 4);
+-		if ((i % INTC_INTPRI_PPREG) == (INTC_INTPRI_PPREG - 1)) {
+-			/* Upon the 7th, set Priority Register */
+-			ctrl_outl(data, reg);
+-			data = 0;
+-			reg += 8;
+-		}
+-	}
+-
+-#ifdef CONFIG_SH_CAYMAN
+-	{
+-		extern void init_cayman_irq(void);
+-
+-		init_cayman_irq();
+-	}
+-#endif
+-
+-	/*
+-	 * And now let interrupts come in.
+-	 * sti() is not enough, we need to
+-	 * lower priority, too.
+-	 */
+-        __asm__ __volatile__("getcon    " __SR ", %0\n\t"
+-                             "and       %0, %1, %0\n\t"
+-                             "putcon    %0, " __SR "\n\t"
+-                             : "=&r" (__dummy0)
+-                             : "r" (__dummy1));
+-}
+diff --git a/arch/sh64/kernel/led.c b/arch/sh64/kernel/led.c
+deleted file mode 100644
+index e35d3f6..0000000
+--- a/arch/sh64/kernel/led.c
++++ /dev/null
+@@ -1,40 +0,0 @@
+-/*
+- * arch/sh64/kernel/led.c
+- *
+- * Copyright (C) 2002 Stuart Menefy <stuart.menefy at st.com>
+- *
+- * May be copied or modified under the terms of the GNU General Public
+- * License.  See linux/COPYING for more information.
+- *
+- * Flash the LEDs
+- */
+-#include <linux/stddef.h>
+-#include <linux/sched.h>
+-
+-void mach_led(int pos, int val);
+-
+-/* acts like an actual heart beat -- ie thump-thump-pause... */
+-void heartbeat(void)
+-{
+-	static unsigned int cnt = 0, period = 0, dist = 0;
+-
+-	if (cnt == 0 || cnt == dist) {
+-		mach_led(-1, 1);
+-	} else if (cnt == 7 || cnt == dist + 7) {
+-		mach_led(-1, 0);
+-	}
+-
+-	if (++cnt > period) {
+-		cnt = 0;
+-
+-		/*
+-		 * The hyperbolic function below modifies the heartbeat period
+-		 * length in dependency of the current (5min) load. It goes
+-		 * through the points f(0)=126, f(1)=86, f(5)=51, f(inf)->30.
+-		 */
+-		period = ((672 << FSHIFT) / (5 * avenrun[0] +
+-					    (7 << FSHIFT))) + 30;
+-		dist = period / 4;
+-	}
+-}
+-
+diff --git a/arch/sh64/kernel/module.c b/arch/sh64/kernel/module.c
+deleted file mode 100644
+index 2598f6b..0000000
+--- a/arch/sh64/kernel/module.c
++++ /dev/null
+@@ -1,161 +0,0 @@
+-/*  Kernel module help for sh64.
+-
+-    This program is free software; you can redistribute it and/or modify
+-    it under the terms of the GNU General Public License as published by
+-    the Free Software Foundation; either version 2 of the License, or
+-    (at your option) any later version.
+-
+-    This program is distributed in the hope that it will be useful,
+-    but WITHOUT ANY WARRANTY; without even the implied warranty of
+-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+-    GNU General Public License for more details.
+-
+-    You 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 2004 SuperH (UK) Ltd
+-    Author: Richard Curnow
+-
+-    Based on the sh version, and on code from the sh64-specific parts of
+-    modutils, originally written by Richard Curnow and Ben Gaster.
+-
+-*/
+-#include <linux/moduleloader.h>
+-#include <linux/elf.h>
+-#include <linux/vmalloc.h>
+-#include <linux/fs.h>
+-#include <linux/string.h>
+-#include <linux/kernel.h>
+-
+-#if 0
+-#define DEBUGP printk
+-#else
+-#define DEBUGP(fmt...)
+-#endif
+-
+-void *module_alloc(unsigned long size)
+-{
+-	if (size == 0)
+-		return NULL;
+-	return vmalloc(size);
+-}
+-
+-
+-/* Free memory returned from module_alloc */
+-void module_free(struct module *mod, void *module_region)
+-{
+-	vfree(module_region);
+-	/* FIXME: If module_region == mod->init_region, trim exception
+-           table entries. */
+-}
+-
+-/* We don't need anything special. */
+-int module_frob_arch_sections(Elf_Ehdr *hdr,
+-			      Elf_Shdr *sechdrs,
+-			      char *secstrings,
+-			      struct module *mod)
+-{
+-	return 0;
+-}
+-
+-int apply_relocate_add(Elf32_Shdr *sechdrs,
+-		   const char *strtab,
+-		   unsigned int symindex,
+-		   unsigned int relsec,
+-		   struct module *me)
+-{
+-	unsigned int i;
+-	Elf32_Rela *rel = (void *)sechdrs[relsec].sh_addr;
+-	Elf32_Sym *sym;
+-	Elf32_Addr relocation;
+-	uint32_t *location;
+-	int align;
+-	int is_shmedia;
+-
+-	DEBUGP("Applying relocate section %u to %u\n", relsec,
+-	       sechdrs[relsec].sh_info);
+-	for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
+-		/* This is where to make the change */
+-		location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
+-			+ rel[i].r_offset;
+-		/* This is the symbol it is referring to.  Note that all
+-		   undefined symbols have been resolved.  */
+-		sym = (Elf32_Sym *)sechdrs[symindex].sh_addr
+-			+ ELF32_R_SYM(rel[i].r_info);
+-		relocation = sym->st_value + rel[i].r_addend;
+-		align = (int)location & 3;
+-
+-		/* For text addresses, bit2 of the st_other field indicates
+-		 * whether the symbol is SHmedia (1) or SHcompact (0).  If
+-		 * SHmedia, the LSB of the symbol needs to be asserted
+-		 * for the CPU to be in SHmedia mode when it starts executing
+-		 * the branch target. */
+-		is_shmedia = (sym->st_other & 4) ? 1 : 0;
+-		if (is_shmedia) {
+-			relocation |= 1;
+-		}
+-
+-		switch (ELF32_R_TYPE(rel[i].r_info)) {
+-		case R_SH_DIR32:
+-			DEBUGP("R_SH_DIR32 @%08lx = %08lx\n", (unsigned long) location, (unsigned long) relocation);
+-			*location += relocation;
+-			break;
+-		case R_SH_REL32:
+-			DEBUGP("R_SH_REL32 @%08lx = %08lx\n", (unsigned long) location, (unsigned long) relocation);
+-			relocation -= (Elf32_Addr) location;
+-			*location += relocation;
+-			break;
+-		case R_SH_IMM_LOW16:
+-			DEBUGP("R_SH_IMM_LOW16 @%08lx = %08lx\n", (unsigned long) location, (unsigned long) relocation);
+-			*location = (*location & ~0x3fffc00) |
+-				((relocation & 0xffff) << 10);
+-			break;
+-		case R_SH_IMM_MEDLOW16:
+-			DEBUGP("R_SH_IMM_MEDLOW16 @%08lx = %08lx\n", (unsigned long) location, (unsigned long) relocation);
+-			*location = (*location & ~0x3fffc00) |
+-				(((relocation >> 16) & 0xffff) << 10);
+-			break;
+-		case R_SH_IMM_LOW16_PCREL:
+-			DEBUGP("R_SH_IMM_LOW16_PCREL @%08lx = %08lx\n", (unsigned long) location, (unsigned long) relocation);
+-			relocation -= (Elf32_Addr) location;
+-			*location = (*location & ~0x3fffc00) |
+-				((relocation & 0xffff) << 10);
+-			break;
+-		case R_SH_IMM_MEDLOW16_PCREL:
+-			DEBUGP("R_SH_IMM_MEDLOW16_PCREL @%08lx = %08lx\n", (unsigned long) location, (unsigned long) relocation);
+-			relocation -= (Elf32_Addr) location;
+-			*location = (*location & ~0x3fffc00) |
+-				(((relocation >> 16) & 0xffff) << 10);
+-			break;
+-		default:
+-			printk(KERN_ERR "module %s: Unknown relocation: %u\n",
+-			       me->name, ELF32_R_TYPE(rel[i].r_info));
+-			return -ENOEXEC;
+-		}
+-	}
+-	return 0;
+-}
+-
+-int apply_relocate(Elf32_Shdr *sechdrs,
+-		       const char *strtab,
+-		       unsigned int symindex,
+-		       unsigned int relsec,
+-		       struct module *me)
+-{
+-	printk(KERN_ERR "module %s: REL RELOCATION unsupported\n",
+-	       me->name);
+-	return -ENOEXEC;
+-}
+-
+-int module_finalize(const Elf_Ehdr *hdr,
+-		    const Elf_Shdr *sechdrs,
+-		    struct module *me)
+-{
+-	return 0;
+-}
+-
+-void module_arch_cleanup(struct module *mod)
+-{
+-}
+-
+diff --git a/arch/sh64/kernel/pci_sh5.c b/arch/sh64/kernel/pci_sh5.c
 deleted file mode 100644
-index 6320bc4..0000000
---- a/arch/blackfin/kernel/cplbinit.c
+index b4d9534..0000000
+--- a/arch/sh64/kernel/pci_sh5.c
 +++ /dev/null
-@@ -1,437 +0,0 @@
+@@ -1,536 +0,0 @@
 -/*
-- * Blackfin CPLB initialization
-- *
-- *               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.
+- * Copyright (C) 2001 David J. Mckay (david.mckay at st.com)
+- * Copyright (C) 2003, 2004 Paul Mundt
+- * Copyright (C) 2004 Richard Curnow
 - *
-- * This program is distributed in the hope that it will be useful,
-- * but WITHOUT ANY WARRANTY; without even the implied warranty of
-- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-- * GNU General Public License for more details.
+- * May be copied or modified under the terms of the GNU General Public
+- * License.  See linux/COPYING for more information.
 - *
-- * 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
+- * Support functions for the SH5 PCI hardware.
 - */
--#include <linux/module.h>
 -
--#include <asm/blackfin.h>
--#include <asm/cplb.h>
--#include <asm/cplbinit.h>
+-#include <linux/kernel.h>
+-#include <linux/rwsem.h>
+-#include <linux/smp.h>
+-#include <linux/interrupt.h>
+-#include <linux/init.h>
+-#include <linux/errno.h>
+-#include <linux/pci.h>
+-#include <linux/delay.h>
+-#include <linux/types.h>
+-#include <asm/pci.h>
+-#include <linux/irq.h>
 -
--u_long icplb_table[MAX_CPLBS + 1];
--u_long dcplb_table[MAX_CPLBS + 1];
+-#include <asm/io.h>
+-#include <asm/hardware.h>
+-#include "pci_sh5.h"
 -
--#ifdef CONFIG_CPLB_SWITCH_TAB_L1
--# define PDT_ATTR __attribute__((l1_data))
--#else
--# define PDT_ATTR
--#endif
+-static unsigned long pcicr_virt;
+-unsigned long pciio_virt;
 -
--u_long ipdt_table[MAX_SWITCH_I_CPLBS + 1] PDT_ATTR;
--u_long dpdt_table[MAX_SWITCH_D_CPLBS + 1] PDT_ATTR;
+-static void __init pci_fixup_ide_bases(struct pci_dev *d)
+-{
+-	int i;
 -
--#ifdef CONFIG_CPLB_INFO
--u_long ipdt_swapcount_table[MAX_SWITCH_I_CPLBS] PDT_ATTR;
--u_long dpdt_swapcount_table[MAX_SWITCH_D_CPLBS] PDT_ATTR;
--#endif
+-	/*
+-	 * PCI IDE controllers use non-standard I/O port decoding, respect it.
+-	 */
+-	if ((d->class >> 8) != PCI_CLASS_STORAGE_IDE)
+-		return;
+-	printk("PCI: IDE base address fixup for %s\n", pci_name(d));
+-	for(i=0; i<4; i++) {
+-		struct resource *r = &d->resource[i];
+-		if ((r->start & ~0x80) == 0x374) {
+-			r->start |= 2;
+-			r->end = r->start;
+-		}
+-	}
+-}
+-DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pci_fixup_ide_bases);
 -
--struct s_cplb {
--	struct cplb_tab init_i;
--	struct cplb_tab init_d;
--	struct cplb_tab switch_i;
--	struct cplb_tab switch_d;
--};
+-char * __devinit pcibios_setup(char *str)
+-{
+-	return str;
+-}
 -
--#if defined(CONFIG_BFIN_DCACHE) || defined(CONFIG_BFIN_ICACHE)
--static struct cplb_desc cplb_data[] = {
--	{
--		.start = 0,
--		.end = SIZE_1K,
--		.psize = SIZE_1K,
--		.attr = INITIAL_T | SWITCH_T | I_CPLB | D_CPLB,
--		.i_conf = SDRAM_OOPS,
--		.d_conf = SDRAM_OOPS,
--#if defined(CONFIG_DEBUG_HUNT_FOR_ZERO)
--		.valid = 1,
--#else
--		.valid = 0,
--#endif
--		.name = "Zero Pointer Guard Page",
--	},
--	{
--		.start = L1_CODE_START,
--		.end = L1_CODE_START + L1_CODE_LENGTH,
--		.psize = SIZE_4M,
--		.attr = INITIAL_T | SWITCH_T | I_CPLB,
--		.i_conf = L1_IMEMORY,
--		.d_conf = 0,
--		.valid = 1,
--		.name = "L1 I-Memory",
--	},
--	{
--		.start = L1_DATA_A_START,
--		.end = L1_DATA_B_START + L1_DATA_B_LENGTH,
--		.psize = SIZE_4M,
--		.attr = INITIAL_T | SWITCH_T | D_CPLB,
--		.i_conf = 0,
--		.d_conf = L1_DMEMORY,
--#if ((L1_DATA_A_LENGTH > 0) || (L1_DATA_B_LENGTH > 0))
--		.valid = 1,
--#else
--		.valid = 0,
--#endif
--		.name = "L1 D-Memory",
--	},
--	{
--		.start = 0,
--		.end = 0,  /* dynamic */
--		.psize = 0,
--		.attr = INITIAL_T | SWITCH_T | I_CPLB | D_CPLB,
--		.i_conf = SDRAM_IGENERIC,
--		.d_conf = SDRAM_DGENERIC,
--		.valid = 1,
--		.name = "Kernel Memory",
--	},
--	{
--		.start = 0, /* dynamic */
--		.end = 0, /* dynamic */
--		.psize = 0,
--		.attr = INITIAL_T | SWITCH_T | D_CPLB,
--		.i_conf = SDRAM_IGENERIC,
--		.d_conf = SDRAM_DNON_CHBL,
--		.valid = 1,
--		.name = "uClinux MTD Memory",
--	},
--	{
--		.start = 0, /* dynamic */
--		.end = 0,   /* dynamic */
--		.psize = SIZE_1M,
--		.attr = INITIAL_T | SWITCH_T | D_CPLB,
--		.d_conf = SDRAM_DNON_CHBL,
--		.valid = 1,
--		.name = "Uncached DMA Zone",
--	},
--	{
--		.start = 0, /* dynamic */
--		.end = 0, /* dynamic */
--		.psize = 0,
--		.attr = SWITCH_T | D_CPLB,
--		.i_conf = 0, /* dynamic */
--		.d_conf = 0, /* dynamic */
--		.valid = 1,
--		.name = "Reserved Memory",
--	},
--	{
--		.start = ASYNC_BANK0_BASE,
--		.end = ASYNC_BANK3_BASE + ASYNC_BANK3_SIZE,
--		.psize = 0,
--		.attr = SWITCH_T | D_CPLB,
--		.d_conf = SDRAM_EBIU,
--		.valid = 1,
--		.name = "Asynchronous Memory Banks",
--	},
--	{
--#ifdef L2_START
--		.start = L2_START,
--		.end = L2_START + L2_LENGTH,
--		.psize = SIZE_1M,
--		.attr = SWITCH_T | I_CPLB | D_CPLB,
--		.i_conf = L2_MEMORY,
--		.d_conf = L2_MEMORY,
--		.valid = 1,
--#else
--		.valid = 0,
--#endif
--		.name = "L2 Memory",
--	},
--	{
--		.start = BOOT_ROM_START,
--		.end = BOOT_ROM_START + BOOT_ROM_LENGTH,
--		.psize = SIZE_1M,
--		.attr = SWITCH_T | I_CPLB | D_CPLB,
--		.i_conf = SDRAM_IGENERIC,
--		.d_conf = SDRAM_DGENERIC,
--		.valid = 1,
--		.name = "On-Chip BootROM",
--	},
+-/* Rounds a number UP to the nearest power of two. Used for
+- * sizing the PCI window.
+- */
+-static u32 __init r2p2(u32 num)
+-{
+-	int i = 31;
+-	u32 tmp = num;
+-
+-	if (num == 0)
+-		return 0;
+-
+-	do {
+-		if (tmp & (1 << 31))
+-			break;
+-		i--;
+-		tmp <<= 1;
+-	} while (i >= 0);
+-
+-	tmp = 1 << i;
+-	/* If the original number isn't a power of 2, round it up */
+-	if (tmp != num)
+-		tmp <<= 1;
+-
+-	return tmp;
+-}
+-
+-extern unsigned long long memory_start, memory_end;
+-
+-int __init sh5pci_init(unsigned memStart, unsigned memSize)
+-{
+-	u32 lsr0;
+-	u32 uval;
+-
+-	pcicr_virt = onchip_remap(SH5PCI_ICR_BASE, 1024, "PCICR");
+-	if (!pcicr_virt) {
+-		panic("Unable to remap PCICR\n");
+-	}
+-
+-	pciio_virt = onchip_remap(SH5PCI_IO_BASE, 0x10000, "PCIIO");
+-	if (!pciio_virt) {
+-		panic("Unable to remap PCIIO\n");
+-	}
+-
+-	pr_debug("Register base addres is 0x%08lx\n", pcicr_virt);
+-
+-	/* Clear snoop registers */
+-        SH5PCI_WRITE(CSCR0, 0);
+-        SH5PCI_WRITE(CSCR1, 0);
+-
+-	pr_debug("Wrote to reg\n");
+-
+-        /* Switch off interrupts */
+-        SH5PCI_WRITE(INTM,  0);
+-        SH5PCI_WRITE(AINTM, 0);
+-        SH5PCI_WRITE(PINTM, 0);
+-
+-        /* Set bus active, take it out of reset */
+-        uval = SH5PCI_READ(CR);
+-
+-	/* Set command Register */
+-        SH5PCI_WRITE(CR, uval | CR_LOCK_MASK | CR_CFINT| CR_FTO | CR_PFE | CR_PFCS | CR_BMAM);
+-
+-	uval=SH5PCI_READ(CR);
+-        pr_debug("CR is actually 0x%08x\n",uval);
+-
+-        /* Allow it to be a master */
+-	/* NB - WE DISABLE I/O ACCESS to stop overlap */
+-        /* set WAIT bit to enable stepping, an attempt to improve stability */
+-	SH5PCI_WRITE_SHORT(CSR_CMD,
+-			    PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_WAIT);
+-
+-        /*
+-        ** Set translation mapping memory in order to convert the address
+-        ** used for the main bus, to the PCI internal address.
+-        */
+-        SH5PCI_WRITE(MBR,0x40000000);
+-
+-        /* Always set the max size 512M */
+-        SH5PCI_WRITE(MBMR, PCISH5_MEM_SIZCONV(512*1024*1024));
+-
+-        /*
+-        ** I/O addresses are mapped at internal PCI specific address
+-        ** as is described into the configuration bridge table.
+-        ** These are changed to 0, to allow cards that have legacy
+-        ** io such as vga to function correctly. We set the SH5 IOBAR to
+-        ** 256K, which is a bit big as we can only have 64K of address space
+-        */
+-
+-        SH5PCI_WRITE(IOBR,0x0);
+-
+-	pr_debug("PCI:Writing 0x%08x to IOBR\n",0);
+-
+-        /* Set up a 256K window. Totally pointless waste  of address space */
+-        SH5PCI_WRITE(IOBMR,0);
+-	pr_debug("PCI:Writing 0x%08x to IOBMR\n",0);
+-
+-	/* The SH5 has a HUGE 256K I/O region, which breaks the PCI spec. Ideally,
+-         * we would want to map the I/O region somewhere, but it is so big this is not
+-         * that easy!
+-         */
+-	SH5PCI_WRITE(CSR_IBAR0,~0);
+-	/* Set memory size value */
+-        memSize = memory_end - memory_start;
+-
+-        /* Now we set up the mbars so the PCI bus can see the memory of the machine */
+-        if (memSize < (1024 * 1024)) {
+-                printk(KERN_ERR "PCISH5: Ridiculous memory size of 0x%x?\n", memSize);
+-                return -EINVAL;
+-        }
+-
+-        /* Set LSR 0 */
+-        lsr0 = (memSize > (512 * 1024 * 1024)) ? 0x1ff00001 : ((r2p2(memSize) - 0x100000) | 0x1);
+-        SH5PCI_WRITE(LSR0, lsr0);
+-
+-	pr_debug("PCI:Writing 0x%08x to LSR0\n",lsr0);
+-
+-        /* Set MBAR 0 */
+-        SH5PCI_WRITE(CSR_MBAR0, memory_start);
+-        SH5PCI_WRITE(LAR0, memory_start);
+-
+-        SH5PCI_WRITE(CSR_MBAR1,0);
+-        SH5PCI_WRITE(LAR1,0);
+-        SH5PCI_WRITE(LSR1,0);
+-
+-	pr_debug("PCI:Writing 0x%08llx to CSR_MBAR0\n",memory_start);
+-	pr_debug("PCI:Writing 0x%08llx to LAR0\n",memory_start);
+-
+-        /* Enable the PCI interrupts on the device */
+-        SH5PCI_WRITE(INTM,  ~0);
+-        SH5PCI_WRITE(AINTM, ~0);
+-        SH5PCI_WRITE(PINTM, ~0);
+-
+-	pr_debug("Switching on all error interrupts\n");
+-
+-        return(0);
+-}
+-
+-static int sh5pci_read(struct pci_bus *bus, unsigned int devfn, int where,
+-			int size, u32 *val)
+-{
+-	SH5PCI_WRITE(PAR, CONFIG_CMD(bus, devfn, where));
+-
+-	switch (size) {
+-		case 1:
+-			*val = (u8)SH5PCI_READ_BYTE(PDR + (where & 3));
+-			break;
+-		case 2:
+-			*val = (u16)SH5PCI_READ_SHORT(PDR + (where & 2));
+-			break;
+-		case 4:
+-			*val = SH5PCI_READ(PDR);
+-			break;
+-	}
+-
+-	return PCIBIOS_SUCCESSFUL;
+-}
+-
+-static int sh5pci_write(struct pci_bus *bus, unsigned int devfn, int where,
+-			 int size, u32 val)
+-{
+-	SH5PCI_WRITE(PAR, CONFIG_CMD(bus, devfn, where));
+-
+-	switch (size) {
+-		case 1:
+-			SH5PCI_WRITE_BYTE(PDR + (where & 3), (u8)val);
+-			break;
+-		case 2:
+-			SH5PCI_WRITE_SHORT(PDR + (where & 2), (u16)val);
+-			break;
+-		case 4:
+-			SH5PCI_WRITE(PDR, val);
+-			break;
+-	}
+-
+-	return PCIBIOS_SUCCESSFUL;
+-}
+-
+-static struct pci_ops pci_config_ops = {
+-	.read =		sh5pci_read,
+-	.write =	sh5pci_write,
 -};
 -
--static u16 __init lock_kernel_check(u32 start, u32 end)
+-/* Everything hangs off this */
+-static struct pci_bus *pci_root_bus;
+-
+-
+-static u8 __init no_swizzle(struct pci_dev *dev, u8 * pin)
 -{
--	if ((end   <= (u32) _end && end   >= (u32)_stext) ||
--	    (start <= (u32) _end && start >= (u32)_stext))
--		return IN_KERNEL;
--	return 0;
+-	pr_debug("swizzle for dev %d on bus %d slot %d pin is %d\n",
+-	         dev->devfn,dev->bus->number, PCI_SLOT(dev->devfn),*pin);
+-	return PCI_SLOT(dev->devfn);
 -}
 -
--static unsigned short __init
--fill_cplbtab(struct cplb_tab *table,
--	     unsigned long start, unsigned long end,
--	     unsigned long block_size, unsigned long cplb_data)
+-static inline u8 bridge_swizzle(u8 pin, u8 slot)
 -{
--	int i;
+-	return (((pin-1) + slot) % 4) + 1;
+-}
 -
--	switch (block_size) {
--	case SIZE_4M:
--		i = 3;
--		break;
--	case SIZE_1M:
--		i = 2;
--		break;
--	case SIZE_4K:
--		i = 1;
--		break;
--	case SIZE_1K:
--	default:
--		i = 0;
--		break;
+-u8 __init common_swizzle(struct pci_dev *dev, u8 *pinp)
+-{
+-	if (dev->bus->number != 0) {
+-		u8 pin = *pinp;
+-		do {
+-			pin = bridge_swizzle(pin, PCI_SLOT(dev->devfn));
+-			/* Move up the chain of bridges. */
+-			dev = dev->bus->self;
+-		} while (dev->bus->self);
+-		*pinp = pin;
+-
+-		/* The slot is the slot of the last bridge. */
 -	}
 -
--	cplb_data = (cplb_data & ~(3 << 16)) | (i << 16);
+-	return PCI_SLOT(dev->devfn);
+-}
 -
--	while ((start < end) && (table->pos < table->size)) {
+-/* This needs to be shunted out of here into the board specific bit */
 -
--		table->tab[table->pos++] = start;
+-static int __init map_cayman_irq(struct pci_dev *dev, u8 slot, u8 pin)
+-{
+-	int result = -1;
 -
--		if (lock_kernel_check(start, start + block_size) == IN_KERNEL)
--			table->tab[table->pos++] =
--			    cplb_data | CPLB_LOCK | CPLB_DIRTY;
--		else
--			table->tab[table->pos++] = cplb_data;
+-	/* The complication here is that the PCI IRQ lines from the Cayman's 2
+-	   5V slots get into the CPU via a different path from the IRQ lines
+-	   from the 3 3.3V slots.  Thus, we have to detect whether the card's
+-	   interrupts go via the 5V or 3.3V path, i.e. the 'bridge swizzling'
+-	   at the point where we cross from 5V to 3.3V is not the normal case.
 -
--		start += block_size;
+-	   The added complication is that we don't know that the 5V slots are
+-	   always bus 2, because a card containing a PCI-PCI bridge may be
+-	   plugged into a 3.3V slot, and this changes the bus numbering.
+-
+-	   Also, the Cayman has an intermediate PCI bus that goes a custom
+-	   expansion board header (and to the secondary bridge).  This bus has
+-	   never been used in practice.
+-
+-	   The 1ary onboard PCI-PCI bridge is device 3 on bus 0
+-	   The 2ary onboard PCI-PCI bridge is device 0 on the 2ary bus of the 1ary bridge.
+-	   */
+-
+-	struct slot_pin {
+-		int slot;
+-		int pin;
+-	} path[4];
+-	int i=0;
+-
+-	while (dev->bus->number > 0) {
+-
+-		slot = path[i].slot = PCI_SLOT(dev->devfn);
+-		pin = path[i].pin = bridge_swizzle(pin, slot);
+-		dev = dev->bus->self;
+-		i++;
+-		if (i > 3) panic("PCI path to root bus too long!\n");
 -	}
--	return 0;
+-
+-	slot = PCI_SLOT(dev->devfn);
+-	/* This is the slot on bus 0 through which the device is eventually
+-	   reachable. */
+-
+-	/* Now work back up. */
+-	if ((slot < 3) || (i == 0)) {
+-		/* Bus 0 (incl. PCI-PCI bridge itself) : perform the final
+-		   swizzle now. */
+-		result = IRQ_INTA + bridge_swizzle(pin, slot) - 1;
+-	} else {
+-		i--;
+-		slot = path[i].slot;
+-		pin  = path[i].pin;
+-		if (slot > 0) {
+-			panic("PCI expansion bus device found - not handled!\n");
+-		} else {
+-			if (i > 0) {
+-				/* 5V slots */
+-				i--;
+-				slot = path[i].slot;
+-				pin  = path[i].pin;
+-				/* 'pin' was swizzled earlier wrt slot, don't do it again. */
+-				result = IRQ_P2INTA + (pin - 1);
+-			} else {
+-				/* IRQ for 2ary PCI-PCI bridge : unused */
+-				result = -1;
+-			}
+-		}
+-	}
+-
+-	return result;
 -}
 -
--static unsigned short __init
--close_cplbtab(struct cplb_tab *table)
+-static irqreturn_t pcish5_err_irq(int irq, void *dev_id)
 -{
+-	struct pt_regs *regs = get_irq_regs();
+-	unsigned pci_int, pci_air, pci_cir, pci_aint;
 -
--	while (table->pos < table->size) {
+-	pci_int = SH5PCI_READ(INT);
+-	pci_cir = SH5PCI_READ(CIR);
+-	pci_air = SH5PCI_READ(AIR);
 -
--		table->tab[table->pos++] = 0;
--		table->tab[table->pos++] = 0; /* !CPLB_VALID */
+-	if (pci_int) {
+-		printk("PCI INTERRUPT (at %08llx)!\n", regs->pc);
+-		printk("PCI INT -> 0x%x\n", pci_int & 0xffff);
+-		printk("PCI AIR -> 0x%x\n", pci_air);
+-		printk("PCI CIR -> 0x%x\n", pci_cir);
+-		SH5PCI_WRITE(INT, ~0);
+-	}
+-
+-	pci_aint = SH5PCI_READ(AINT);
+-	if (pci_aint) {
+-		printk("PCI ARB INTERRUPT!\n");
+-		printk("PCI AINT -> 0x%x\n", pci_aint);
+-		printk("PCI AIR -> 0x%x\n", pci_air);
+-		printk("PCI CIR -> 0x%x\n", pci_cir);
+-		SH5PCI_WRITE(AINT, ~0);
+-	}
+-
+-	return IRQ_HANDLED;
+-}
+-
+-static irqreturn_t pcish5_serr_irq(int irq, void *dev_id)
+-{
+-	printk("SERR IRQ\n");
+-
+-	return IRQ_NONE;
+-}
+-
+-static void __init
+-pcibios_size_bridge(struct pci_bus *bus, struct resource *ior,
+-		    struct resource *memr)
+-{
+-	struct resource io_res, mem_res;
+-	struct pci_dev *dev;
+-	struct pci_dev *bridge = bus->self;
+-	struct list_head *ln;
+-
+-	if (!bridge)
+-		return;	/* host bridge, nothing to do */
+-
+-	/* set reasonable default locations for pcibios_align_resource */
+-	io_res.start = PCIBIOS_MIN_IO;
+-	mem_res.start = PCIBIOS_MIN_MEM;
+-
+-	io_res.end = io_res.start;
+-	mem_res.end = mem_res.start;
+-
+-	/* Collect information about how our direct children are layed out. */
+-	for (ln=bus->devices.next; ln != &bus->devices; ln=ln->next) {
+-		int i;
+-		dev = pci_dev_b(ln);
+-
+-		/* Skip bridges for now */
+-		if (dev->class >> 8 == PCI_CLASS_BRIDGE_PCI)
+-			continue;
+-
+-		for (i = 0; i < PCI_NUM_RESOURCES; i++) {
+-			struct resource res;
+-			unsigned long size;
+-
+-			memcpy(&res, &dev->resource[i], sizeof(res));
+-			size = res.end - res.start + 1;
+-
+-			if (res.flags & IORESOURCE_IO) {
+-				res.start = io_res.end;
+-				pcibios_align_resource(dev, &res, size, 0);
+-				io_res.end = res.start + size;
+-			} else if (res.flags & IORESOURCE_MEM) {
+-				res.start = mem_res.end;
+-				pcibios_align_resource(dev, &res, size, 0);
+-				mem_res.end = res.start + size;
+-			}
+-		}
+-	}
+-
+-	/* And for all of the subordinate busses. */
+-	for (ln=bus->children.next; ln != &bus->children; ln=ln->next)
+-		pcibios_size_bridge(pci_bus_b(ln), &io_res, &mem_res);
+-
+-	/* turn the ending locations into sizes (subtract start) */
+-	io_res.end -= io_res.start;
+-	mem_res.end -= mem_res.start;
+-
+-	/* Align the sizes up by bridge rules */
+-	io_res.end = ALIGN(io_res.end, 4*1024) - 1;
+-	mem_res.end = ALIGN(mem_res.end, 1*1024*1024) - 1;
+-
+-	/* Adjust the bridge's allocation requirements */
+-	bridge->resource[0].end = bridge->resource[0].start + io_res.end;
+-	bridge->resource[1].end = bridge->resource[1].start + mem_res.end;
+-
+-	bridge->resource[PCI_BRIDGE_RESOURCES].end =
+-	    bridge->resource[PCI_BRIDGE_RESOURCES].start + io_res.end;
+-	bridge->resource[PCI_BRIDGE_RESOURCES+1].end =
+-	    bridge->resource[PCI_BRIDGE_RESOURCES+1].start + mem_res.end;
+-
+-	/* adjust parent's resource requirements */
+-	if (ior) {
+-		ior->end = ALIGN(ior->end, 4*1024);
+-		ior->end += io_res.end;
 -	}
+-
+-	if (memr) {
+-		memr->end = ALIGN(memr->end, 1*1024*1024);
+-		memr->end += mem_res.end;
+-	}
+-}
+-
+-static void __init pcibios_size_bridges(void)
+-{
+-	struct resource io_res, mem_res;
+-
+-	memset(&io_res, 0, sizeof(io_res));
+-	memset(&mem_res, 0, sizeof(mem_res));
+-
+-	pcibios_size_bridge(pci_root_bus, &io_res, &mem_res);
+-}
+-
+-static int __init pcibios_init(void)
+-{
+-        if (request_irq(IRQ_ERR, pcish5_err_irq,
+-                        IRQF_DISABLED, "PCI Error",NULL) < 0) {
+-                printk(KERN_ERR "PCISH5: Cannot hook PCI_PERR interrupt\n");
+-                return -EINVAL;
+-        }
+-
+-        if (request_irq(IRQ_SERR, pcish5_serr_irq,
+-                        IRQF_DISABLED, "PCI SERR interrupt", NULL) < 0) {
+-                printk(KERN_ERR "PCISH5: Cannot hook PCI_SERR interrupt\n");
+-                return -EINVAL;
+-        }
+-
+-	/* The pci subsystem needs to know where memory is and how much
+-	 * of it there is. I've simply made these globals. A better mechanism
+-	 * is probably needed.
+-	 */
+-	sh5pci_init(__pa(memory_start),
+-		     __pa(memory_end) - __pa(memory_start));
+-
+-	pci_root_bus = pci_scan_bus(0, &pci_config_ops, NULL);
+-	pcibios_size_bridges();
+-	pci_assign_unassigned_resources();
+-	pci_fixup_irqs(no_swizzle, map_cayman_irq);
+-
 -	return 0;
 -}
 -
--/* helper function */
--static void __fill_code_cplbtab(struct cplb_tab *t, int i, u32 a_start, u32 a_end)
+-subsys_initcall(pcibios_init);
+-
+-void __devinit pcibios_fixup_bus(struct pci_bus *bus)
 -{
--	if (cplb_data[i].psize) {
--		fill_cplbtab(t,
--				cplb_data[i].start,
--				cplb_data[i].end,
--				cplb_data[i].psize,
--				cplb_data[i].i_conf);
--	} else {
--#if defined(CONFIG_BFIN_ICACHE)
--		if (ANOMALY_05000263 && i == SDRAM_KERN) {
--			fill_cplbtab(t,
--					cplb_data[i].start,
--					cplb_data[i].end,
--					SIZE_4M,
--					cplb_data[i].i_conf);
--		} else
--#endif
--		{
--			fill_cplbtab(t,
--					cplb_data[i].start,
--					a_start,
--					SIZE_1M,
--					cplb_data[i].i_conf);
--			fill_cplbtab(t,
--					a_start,
--					a_end,
--					SIZE_4M,
--					cplb_data[i].i_conf);
--			fill_cplbtab(t, a_end,
--					cplb_data[i].end,
--					SIZE_1M,
--					cplb_data[i].i_conf);
+-	struct pci_dev *dev = bus->self;
+-	int i;
+-
+-#if 1
+-	if(dev) {
+-		for(i=0; i<3; i++) {
+-			bus->resource[i] =
+-				&dev->resource[PCI_BRIDGE_RESOURCES+i];
+-			bus->resource[i]->name = bus->name;
 -		}
+-		bus->resource[0]->flags |= IORESOURCE_IO;
+-		bus->resource[1]->flags |= IORESOURCE_MEM;
+-
+-		/* For now, propagate host limits to the bus;
+-		 * we'll adjust them later. */
+-
+-#if 1
+-		bus->resource[0]->end = 64*1024 - 1 ;
+-		bus->resource[1]->end = PCIBIOS_MIN_MEM+(256*1024*1024)-1;
+-		bus->resource[0]->start = PCIBIOS_MIN_IO;
+-		bus->resource[1]->start = PCIBIOS_MIN_MEM;
+-#else
+-		bus->resource[0]->end = 0;
+-		bus->resource[1]->end = 0;
+-		bus->resource[0]->start =0;
+-		bus->resource[1]->start = 0;
+-#endif
+-		/* Turn off downstream PF memory address range by default */
+-		bus->resource[2]->start = 1024*1024;
+-		bus->resource[2]->end = bus->resource[2]->start - 1;
 -	}
+-#endif
+-
 -}
 -
--static void __fill_data_cplbtab(struct cplb_tab *t, int i, u32 a_start, u32 a_end)
+diff --git a/arch/sh64/kernel/pci_sh5.h b/arch/sh64/kernel/pci_sh5.h
+deleted file mode 100644
+index c71159d..0000000
+--- a/arch/sh64/kernel/pci_sh5.h
++++ /dev/null
+@@ -1,107 +0,0 @@
+-/*
+- * Copyright (C) 2001 David J. Mckay (david.mckay at st.com)
+- *
+- * May be copied or modified under the terms of the GNU General Public
+- * License.  See linux/COPYING for more information.
+- *
+- * Definitions for the SH5 PCI hardware.
+- */
+-
+-/* Product ID */
+-#define PCISH5_PID		0x350d
+-
+-/* vendor ID */
+-#define PCISH5_VID		0x1054
+-
+-/* Configuration types */
+-#define ST_TYPE0                0x00    /* Configuration cycle type 0 */
+-#define ST_TYPE1                0x01    /* Configuration cycle type 1 */
+-
+-/* VCR data */
+-#define PCISH5_VCR_STATUS      0x00
+-#define PCISH5_VCR_VERSION     0x08
+-
+-/*
+-** ICR register offsets and bits
+-*/
+-#define PCISH5_ICR_CR          0x100   /* PCI control register values */
+-#define CR_PBAM                 (1<<12)
+-#define CR_PFCS                 (1<<11)
+-#define CR_FTO                  (1<<10)
+-#define CR_PFE                  (1<<9)
+-#define CR_TBS                  (1<<8)
+-#define CR_SPUE                 (1<<7)
+-#define CR_BMAM                 (1<<6)
+-#define CR_HOST                 (1<<5)
+-#define CR_CLKEN                (1<<4)
+-#define CR_SOCS                 (1<<3)
+-#define CR_IOCS                 (1<<2)
+-#define CR_RSTCTL               (1<<1)
+-#define CR_CFINT                (1<<0)
+-#define CR_LOCK_MASK            0xa5000000
+-
+-#define PCISH5_ICR_INT         0x114   /* Interrupt registert values     */
+-#define INT_MADIM               (1<<2)
+-
+-#define PCISH5_ICR_LSR0        0X104   /* Local space register values    */
+-#define PCISH5_ICR_LSR1        0X108   /* Local space register values    */
+-#define PCISH5_ICR_LAR0        0x10c   /* Local address register values  */
+-#define PCISH5_ICR_LAR1        0x110   /* Local address register values  */
+-#define PCISH5_ICR_INTM        0x118   /* Interrupt mask register values                         */
+-#define PCISH5_ICR_AIR         0x11c   /* Interrupt error address information register values    */
+-#define PCISH5_ICR_CIR         0x120   /* Interrupt error command information register values    */
+-#define PCISH5_ICR_AINT        0x130   /* Interrupt error arbiter interrupt register values      */
+-#define PCISH5_ICR_AINTM       0x134   /* Interrupt error arbiter interrupt mask register values */
+-#define PCISH5_ICR_BMIR        0x138   /* Interrupt error info register of bus master values     */
+-#define PCISH5_ICR_PAR         0x1c0   /* Pio address register values                            */
+-#define PCISH5_ICR_MBR         0x1c4   /* Memory space bank register values                      */
+-#define PCISH5_ICR_IOBR        0x1c8   /* I/O space bank register values                         */
+-#define PCISH5_ICR_PINT        0x1cc   /* power management interrupt register values             */
+-#define PCISH5_ICR_PINTM       0x1d0   /* power management interrupt mask register values        */
+-#define PCISH5_ICR_MBMR        0x1d8   /* memory space bank mask register values                 */
+-#define PCISH5_ICR_IOBMR       0x1dc   /* I/O space bank mask register values                    */
+-#define PCISH5_ICR_CSCR0       0x210   /* PCI cache snoop control register 0                     */
+-#define PCISH5_ICR_CSCR1       0x214   /* PCI cache snoop control register 1                     */
+-#define PCISH5_ICR_PDR         0x220   /* Pio data register values                               */
+-
+-/* These are configs space registers */
+-#define PCISH5_ICR_CSR_VID     0x000	/* Vendor id                           */
+-#define PCISH5_ICR_CSR_DID     0x002   /* Device id                           */
+-#define PCISH5_ICR_CSR_CMD     0x004   /* Command register                    */
+-#define PCISH5_ICR_CSR_STATUS  0x006   /* Stautus                             */
+-#define PCISH5_ICR_CSR_IBAR0   0x010   /* I/O base address register           */
+-#define PCISH5_ICR_CSR_MBAR0   0x014   /* First  Memory base address register */
+-#define PCISH5_ICR_CSR_MBAR1   0x018   /* Second Memory base address register */
+-
+-
+-
+-/* Base address of registers */
+-#define SH5PCI_ICR_BASE (PHYS_PCI_BLOCK + 0x00040000)
+-#define SH5PCI_IO_BASE  (PHYS_PCI_BLOCK + 0x00800000)
+-/* #define SH5PCI_VCR_BASE (P2SEG_PCICB_BLOCK + P2SEG)    */
+-
+-/* Register selection macro */
+-#define PCISH5_ICR_REG(x)                ( pcicr_virt + (PCISH5_ICR_##x))
+-/* #define PCISH5_VCR_REG(x)                ( SH5PCI_VCR_BASE (PCISH5_VCR_##x)) */
+-
+-/* Write I/O functions */
+-#define SH5PCI_WRITE(reg,val)        ctrl_outl((u32)(val),PCISH5_ICR_REG(reg))
+-#define SH5PCI_WRITE_SHORT(reg,val)  ctrl_outw((u16)(val),PCISH5_ICR_REG(reg))
+-#define SH5PCI_WRITE_BYTE(reg,val)   ctrl_outb((u8)(val),PCISH5_ICR_REG(reg))
+-
+-/* Read I/O functions */
+-#define SH5PCI_READ(reg)             ctrl_inl(PCISH5_ICR_REG(reg))
+-#define SH5PCI_READ_SHORT(reg)       ctrl_inw(PCISH5_ICR_REG(reg))
+-#define SH5PCI_READ_BYTE(reg)        ctrl_inb(PCISH5_ICR_REG(reg))
+-
+-/* Set PCI config bits */
+-#define SET_CONFIG_BITS(bus,devfn,where)  ((((bus) << 16) | ((devfn) << 8) | ((where) & ~3)) | 0x80000000)
+-
+-/* Set PCI command register */
+-#define CONFIG_CMD(bus, devfn, where)            SET_CONFIG_BITS(bus->number,devfn,where)
+-
+-/* Size converters */
+-#define PCISH5_MEM_SIZCONV(x)		  (((x / 0x40000) - 1) << 18)
+-#define PCISH5_IO_SIZCONV(x)		  (((x / 0x40000) - 1) << 18)
+-
+-
+diff --git a/arch/sh64/kernel/pcibios.c b/arch/sh64/kernel/pcibios.c
+deleted file mode 100644
+index 945920b..0000000
+--- a/arch/sh64/kernel/pcibios.c
++++ /dev/null
+@@ -1,168 +0,0 @@
+-/*
+- * $Id: pcibios.c,v 1.1 2001/08/24 12:38:19 dwmw2 Exp $
+- *
+- * arch/sh/kernel/pcibios.c
+- *
+- * Copyright (C) 2002 STMicroelectronics Limited
+- *   Author : David J. McKay
+- *
+- * Copyright (C) 2004 Richard Curnow, SuperH UK Limited
+- *
+- * 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 is GPL'd.
+- *
+- * Provided here are generic versions of:
+- *	pcibios_update_resource()
+- *	pcibios_align_resource()
+- *	pcibios_enable_device()
+- *	pcibios_set_master()
+- *	pcibios_update_irq()
+- *
+- * These functions are collected here to reduce duplication of common
+- * code amongst the many platform-specific PCI support code files.
+- *
+- * Platform-specific files are expected to provide:
+- *	pcibios_fixup_bus()
+- *	pcibios_init()
+- *	pcibios_setup()
+- *	pcibios_fixup_pbus_ranges()
+- */
+-
+-#include <linux/kernel.h>
+-#include <linux/pci.h>
+-#include <linux/init.h>
+-
+-void
+-pcibios_update_resource(struct pci_dev *dev, struct resource *root,
+-			struct resource *res, int resource)
 -{
--	if (cplb_data[i].psize) {
--		fill_cplbtab(t,
--				cplb_data[i].start,
--				cplb_data[i].end,
--				cplb_data[i].psize,
--				cplb_data[i].d_conf);
+-	u32 new, check;
+-	int reg;
+-
+-	new = res->start | (res->flags & PCI_REGION_FLAG_MASK);
+-	if (resource < 6) {
+-		reg = PCI_BASE_ADDRESS_0 + 4*resource;
+-	} else if (resource == PCI_ROM_RESOURCE) {
+-		res->flags |= IORESOURCE_ROM_ENABLE;
+-		new |= PCI_ROM_ADDRESS_ENABLE;
+-		reg = dev->rom_base_reg;
 -	} else {
--		fill_cplbtab(t,
--				cplb_data[i].start,
--				a_start, SIZE_1M,
--				cplb_data[i].d_conf);
--		fill_cplbtab(t, a_start,
--				a_end, SIZE_4M,
--				cplb_data[i].d_conf);
--		fill_cplbtab(t, a_end,
--				cplb_data[i].end,
--				SIZE_1M,
--				cplb_data[i].d_conf);
+-		/* Somebody might have asked allocation of a non-standard resource */
+-		return;
+-	}
+-
+-	pci_write_config_dword(dev, reg, new);
+-	pci_read_config_dword(dev, reg, &check);
+-	if ((new ^ check) & ((new & PCI_BASE_ADDRESS_SPACE_IO) ? PCI_BASE_ADDRESS_IO_MASK : PCI_BASE_ADDRESS_MEM_MASK)) {
+-		printk(KERN_ERR "PCI: Error while updating region "
+-		       "%s/%d (%08x != %08x)\n", pci_name(dev), resource,
+-		       new, check);
 -	}
 -}
 -
--void __init generate_cpl_tables(void)
+-/*
+- * We need to avoid collisions with `mirrored' VGA ports
+- * and other strange ISA hardware, so we always want the
+- * addresses to be allocated in the 0x000-0x0ff region
+- * modulo 0x400.
+- */
+-void pcibios_align_resource(void *data, struct resource *res,
+-			    resource_size_t size, resource_size_t align)
 -{
+-	if (res->flags & IORESOURCE_IO) {
+-		resource_size_t start = res->start;
 -
--	u16 i, j, process;
--	u32 a_start, a_end, as, ae, as_1m;
+-		if (start & 0x300) {
+-			start = (start + 0x3ff) & ~0x3ff;
+-			res->start = start;
+-		}
+-	}
+-}
 -
--	struct cplb_tab *t_i = NULL;
--	struct cplb_tab *t_d = NULL;
--	struct s_cplb cplb;
+-static void pcibios_enable_bridge(struct pci_dev *dev)
+-{
+-	struct pci_bus *bus = dev->subordinate;
+-	u16 cmd, old_cmd;
 -
--	cplb.init_i.size = MAX_CPLBS;
--	cplb.init_d.size = MAX_CPLBS;
--	cplb.switch_i.size = MAX_SWITCH_I_CPLBS;
--	cplb.switch_d.size = MAX_SWITCH_D_CPLBS;
+-	pci_read_config_word(dev, PCI_COMMAND, &cmd);
+-	old_cmd = cmd;
 -
--	cplb.init_i.pos = 0;
--	cplb.init_d.pos = 0;
--	cplb.switch_i.pos = 0;
--	cplb.switch_d.pos = 0;
+-	if (bus->resource[0]->flags & IORESOURCE_IO) {
+-		cmd |= PCI_COMMAND_IO;
+-	}
+-	if ((bus->resource[1]->flags & IORESOURCE_MEM) ||
+-	    (bus->resource[2]->flags & IORESOURCE_PREFETCH)) {
+-		cmd |= PCI_COMMAND_MEMORY;
+-	}
 -
--	cplb.init_i.tab = icplb_table;
--	cplb.init_d.tab = dcplb_table;
--	cplb.switch_i.tab = ipdt_table;
--	cplb.switch_d.tab = dpdt_table;
+-	if (cmd != old_cmd) {
+-		pci_write_config_word(dev, PCI_COMMAND, cmd);
+-	}
 -
--	cplb_data[SDRAM_KERN].end = memory_end;
+-	printk("PCI bridge %s, command register -> %04x\n",
+-		pci_name(dev), cmd);
 -
--#ifdef CONFIG_MTD_UCLINUX
--	cplb_data[SDRAM_RAM_MTD].start = memory_mtd_start;
--	cplb_data[SDRAM_RAM_MTD].end = memory_mtd_start + mtd_size;
--	cplb_data[SDRAM_RAM_MTD].valid = mtd_size > 0;
--# if defined(CONFIG_ROMFS_FS)
--	cplb_data[SDRAM_RAM_MTD].attr |= I_CPLB;
+-}
+-
+-
+-
+-int pcibios_enable_device(struct pci_dev *dev, int mask)
+-{
+-	u16 cmd, old_cmd;
+-	int idx;
+-	struct resource *r;
+-
+-	if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) {
+-		pcibios_enable_bridge(dev);
+-	}
+-
+-	pci_read_config_word(dev, PCI_COMMAND, &cmd);
+-	old_cmd = cmd;
+-	for(idx=0; idx<6; idx++) {
+-		if (!(mask & (1 << idx)))
+-			continue;
+-		r = &dev->resource[idx];
+-		if (!r->start && r->end) {
+-			printk(KERN_ERR "PCI: Device %s not available because of resource collisions\n", pci_name(dev));
+-			return -EINVAL;
+-		}
+-		if (r->flags & IORESOURCE_IO)
+-			cmd |= PCI_COMMAND_IO;
+-		if (r->flags & IORESOURCE_MEM)
+-			cmd |= PCI_COMMAND_MEMORY;
+-	}
+-	if (dev->resource[PCI_ROM_RESOURCE].start)
+-		cmd |= PCI_COMMAND_MEMORY;
+-	if (cmd != old_cmd) {
+-		printk(KERN_INFO "PCI: Enabling device %s (%04x -> %04x)\n", pci_name(dev), old_cmd, cmd);
+-		pci_write_config_word(dev, PCI_COMMAND, cmd);
+-	}
+-	return 0;
+-}
+-
+-/*
+- *  If we set up a device for bus mastering, we need to check and set
+- *  the latency timer as it may not be properly set.
+- */
+-unsigned int pcibios_max_latency = 255;
+-
+-void pcibios_set_master(struct pci_dev *dev)
+-{
+-	u8 lat;
+-	pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
+-	if (lat < 16)
+-		lat = (64 <= pcibios_max_latency) ? 64 : pcibios_max_latency;
+-	else if (lat > pcibios_max_latency)
+-		lat = pcibios_max_latency;
+-	else
+-		return;
+-	printk(KERN_INFO "PCI: Setting latency timer of device %s to %d\n", pci_name(dev), lat);
+-	pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat);
+-}
+-
+-void __init pcibios_update_irq(struct pci_dev *dev, int irq)
+-{
+-	pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
+-}
+diff --git a/arch/sh64/kernel/process.c b/arch/sh64/kernel/process.c
+deleted file mode 100644
+index 0761af4..0000000
+--- a/arch/sh64/kernel/process.c
++++ /dev/null
+@@ -1,691 +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.
+- *
+- * arch/sh64/kernel/process.c
+- *
+- * Copyright (C) 2000, 2001  Paolo Alberelli
+- * Copyright (C) 2003  Paul Mundt
+- * Copyright (C) 2003, 2004 Richard Curnow
+- *
+- * Started from SH3/4 version:
+- *   Copyright (C) 1999, 2000  Niibe Yutaka & Kaz Kojima
+- *
+- *   In turn started from i386 version:
+- *     Copyright (C) 1995  Linus Torvalds
+- *
+- */
+-
+-/*
+- * This file handles the architecture-dependent parts of process handling..
+- */
+-#include <linux/mm.h>
+-#include <linux/fs.h>
+-#include <linux/ptrace.h>
+-#include <linux/reboot.h>
+-#include <linux/init.h>
+-#include <linux/module.h>
+-#include <linux/proc_fs.h>
+-#include <asm/uaccess.h>
+-#include <asm/pgtable.h>
+-
+-struct task_struct *last_task_used_math = NULL;
+-
+-static int hlt_counter = 1;
+-
+-#define HARD_IDLE_TIMEOUT (HZ / 3)
+-
+-void disable_hlt(void)
+-{
+-	hlt_counter++;
+-}
+-
+-void enable_hlt(void)
+-{
+-	hlt_counter--;
+-}
+-
+-static int __init nohlt_setup(char *__unused)
+-{
+-	hlt_counter = 1;
+-	return 1;
+-}
+-
+-static int __init hlt_setup(char *__unused)
+-{
+-	hlt_counter = 0;
+-	return 1;
+-}
+-
+-__setup("nohlt", nohlt_setup);
+-__setup("hlt", hlt_setup);
+-
+-static inline void hlt(void)
+-{
+-	__asm__ __volatile__ ("sleep" : : : "memory");
+-}
+-
+-/*
+- * The idle loop on a uniprocessor SH..
+- */
+-void cpu_idle(void)
+-{
+-	/* endless idle loop with no priority at all */
+-	while (1) {
+-		if (hlt_counter) {
+-			while (!need_resched())
+-				cpu_relax();
+-		} else {
+-			local_irq_disable();
+-			while (!need_resched()) {
+-				local_irq_enable();
+-				hlt();
+-				local_irq_disable();
+-			}
+-			local_irq_enable();
+-		}
+-		preempt_enable_no_resched();
+-		schedule();
+-		preempt_disable();
+-	}
+-
+-}
+-
+-void machine_restart(char * __unused)
+-{
+-	extern void phys_stext(void);
+-
+-	phys_stext();
+-}
+-
+-void machine_halt(void)
+-{
+-	for (;;);
+-}
+-
+-void machine_power_off(void)
+-{
+-	extern void enter_deep_standby(void);
+-
+-	enter_deep_standby();
+-}
+-
+-void (*pm_power_off)(void) = machine_power_off;
+-EXPORT_SYMBOL(pm_power_off);
+-
+-void show_regs(struct pt_regs * regs)
+-{
+-	unsigned long long ah, al, bh, bl, ch, cl;
+-
+-	printk("\n");
+-
+-	ah = (regs->pc) >> 32;
+-	al = (regs->pc) & 0xffffffff;
+-	bh = (regs->regs[18]) >> 32;
+-	bl = (regs->regs[18]) & 0xffffffff;
+-	ch = (regs->regs[15]) >> 32;
+-	cl = (regs->regs[15]) & 0xffffffff;
+-	printk("PC  : %08Lx%08Lx LINK: %08Lx%08Lx SP  : %08Lx%08Lx\n",
+-	       ah, al, bh, bl, ch, cl);
+-
+-	ah = (regs->sr) >> 32;
+-	al = (regs->sr) & 0xffffffff;
+-        asm volatile ("getcon   " __TEA ", %0" : "=r" (bh));
+-        asm volatile ("getcon   " __TEA ", %0" : "=r" (bl));
+-	bh = (bh) >> 32;
+-	bl = (bl) & 0xffffffff;
+-        asm volatile ("getcon   " __KCR0 ", %0" : "=r" (ch));
+-        asm volatile ("getcon   " __KCR0 ", %0" : "=r" (cl));
+-	ch = (ch) >> 32;
+-	cl = (cl) & 0xffffffff;
+-	printk("SR  : %08Lx%08Lx TEA : %08Lx%08Lx KCR0: %08Lx%08Lx\n",
+-	       ah, al, bh, bl, ch, cl);
+-
+-	ah = (regs->regs[0]) >> 32;
+-	al = (regs->regs[0]) & 0xffffffff;
+-	bh = (regs->regs[1]) >> 32;
+-	bl = (regs->regs[1]) & 0xffffffff;
+-	ch = (regs->regs[2]) >> 32;
+-	cl = (regs->regs[2]) & 0xffffffff;
+-	printk("R0  : %08Lx%08Lx R1  : %08Lx%08Lx R2  : %08Lx%08Lx\n",
+-	       ah, al, bh, bl, ch, cl);
+-
+-	ah = (regs->regs[3]) >> 32;
+-	al = (regs->regs[3]) & 0xffffffff;
+-	bh = (regs->regs[4]) >> 32;
+-	bl = (regs->regs[4]) & 0xffffffff;
+-	ch = (regs->regs[5]) >> 32;
+-	cl = (regs->regs[5]) & 0xffffffff;
+-	printk("R3  : %08Lx%08Lx R4  : %08Lx%08Lx R5  : %08Lx%08Lx\n",
+-	       ah, al, bh, bl, ch, cl);
+-
+-	ah = (regs->regs[6]) >> 32;
+-	al = (regs->regs[6]) & 0xffffffff;
+-	bh = (regs->regs[7]) >> 32;
+-	bl = (regs->regs[7]) & 0xffffffff;
+-	ch = (regs->regs[8]) >> 32;
+-	cl = (regs->regs[8]) & 0xffffffff;
+-	printk("R6  : %08Lx%08Lx R7  : %08Lx%08Lx R8  : %08Lx%08Lx\n",
+-	       ah, al, bh, bl, ch, cl);
+-
+-	ah = (regs->regs[9]) >> 32;
+-	al = (regs->regs[9]) & 0xffffffff;
+-	bh = (regs->regs[10]) >> 32;
+-	bl = (regs->regs[10]) & 0xffffffff;
+-	ch = (regs->regs[11]) >> 32;
+-	cl = (regs->regs[11]) & 0xffffffff;
+-	printk("R9  : %08Lx%08Lx R10 : %08Lx%08Lx R11 : %08Lx%08Lx\n",
+-	       ah, al, bh, bl, ch, cl);
+-
+-	ah = (regs->regs[12]) >> 32;
+-	al = (regs->regs[12]) & 0xffffffff;
+-	bh = (regs->regs[13]) >> 32;
+-	bl = (regs->regs[13]) & 0xffffffff;
+-	ch = (regs->regs[14]) >> 32;
+-	cl = (regs->regs[14]) & 0xffffffff;
+-	printk("R12 : %08Lx%08Lx R13 : %08Lx%08Lx R14 : %08Lx%08Lx\n",
+-	       ah, al, bh, bl, ch, cl);
+-
+-	ah = (regs->regs[16]) >> 32;
+-	al = (regs->regs[16]) & 0xffffffff;
+-	bh = (regs->regs[17]) >> 32;
+-	bl = (regs->regs[17]) & 0xffffffff;
+-	ch = (regs->regs[19]) >> 32;
+-	cl = (regs->regs[19]) & 0xffffffff;
+-	printk("R16 : %08Lx%08Lx R17 : %08Lx%08Lx R19 : %08Lx%08Lx\n",
+-	       ah, al, bh, bl, ch, cl);
+-
+-	ah = (regs->regs[20]) >> 32;
+-	al = (regs->regs[20]) & 0xffffffff;
+-	bh = (regs->regs[21]) >> 32;
+-	bl = (regs->regs[21]) & 0xffffffff;
+-	ch = (regs->regs[22]) >> 32;
+-	cl = (regs->regs[22]) & 0xffffffff;
+-	printk("R20 : %08Lx%08Lx R21 : %08Lx%08Lx R22 : %08Lx%08Lx\n",
+-	       ah, al, bh, bl, ch, cl);
+-
+-	ah = (regs->regs[23]) >> 32;
+-	al = (regs->regs[23]) & 0xffffffff;
+-	bh = (regs->regs[24]) >> 32;
+-	bl = (regs->regs[24]) & 0xffffffff;
+-	ch = (regs->regs[25]) >> 32;
+-	cl = (regs->regs[25]) & 0xffffffff;
+-	printk("R23 : %08Lx%08Lx R24 : %08Lx%08Lx R25 : %08Lx%08Lx\n",
+-	       ah, al, bh, bl, ch, cl);
+-
+-	ah = (regs->regs[26]) >> 32;
+-	al = (regs->regs[26]) & 0xffffffff;
+-	bh = (regs->regs[27]) >> 32;
+-	bl = (regs->regs[27]) & 0xffffffff;
+-	ch = (regs->regs[28]) >> 32;
+-	cl = (regs->regs[28]) & 0xffffffff;
+-	printk("R26 : %08Lx%08Lx R27 : %08Lx%08Lx R28 : %08Lx%08Lx\n",
+-	       ah, al, bh, bl, ch, cl);
+-
+-	ah = (regs->regs[29]) >> 32;
+-	al = (regs->regs[29]) & 0xffffffff;
+-	bh = (regs->regs[30]) >> 32;
+-	bl = (regs->regs[30]) & 0xffffffff;
+-	ch = (regs->regs[31]) >> 32;
+-	cl = (regs->regs[31]) & 0xffffffff;
+-	printk("R29 : %08Lx%08Lx R30 : %08Lx%08Lx R31 : %08Lx%08Lx\n",
+-	       ah, al, bh, bl, ch, cl);
+-
+-	ah = (regs->regs[32]) >> 32;
+-	al = (regs->regs[32]) & 0xffffffff;
+-	bh = (regs->regs[33]) >> 32;
+-	bl = (regs->regs[33]) & 0xffffffff;
+-	ch = (regs->regs[34]) >> 32;
+-	cl = (regs->regs[34]) & 0xffffffff;
+-	printk("R32 : %08Lx%08Lx R33 : %08Lx%08Lx R34 : %08Lx%08Lx\n",
+-	       ah, al, bh, bl, ch, cl);
+-
+-	ah = (regs->regs[35]) >> 32;
+-	al = (regs->regs[35]) & 0xffffffff;
+-	bh = (regs->regs[36]) >> 32;
+-	bl = (regs->regs[36]) & 0xffffffff;
+-	ch = (regs->regs[37]) >> 32;
+-	cl = (regs->regs[37]) & 0xffffffff;
+-	printk("R35 : %08Lx%08Lx R36 : %08Lx%08Lx R37 : %08Lx%08Lx\n",
+-	       ah, al, bh, bl, ch, cl);
+-
+-	ah = (regs->regs[38]) >> 32;
+-	al = (regs->regs[38]) & 0xffffffff;
+-	bh = (regs->regs[39]) >> 32;
+-	bl = (regs->regs[39]) & 0xffffffff;
+-	ch = (regs->regs[40]) >> 32;
+-	cl = (regs->regs[40]) & 0xffffffff;
+-	printk("R38 : %08Lx%08Lx R39 : %08Lx%08Lx R40 : %08Lx%08Lx\n",
+-	       ah, al, bh, bl, ch, cl);
+-
+-	ah = (regs->regs[41]) >> 32;
+-	al = (regs->regs[41]) & 0xffffffff;
+-	bh = (regs->regs[42]) >> 32;
+-	bl = (regs->regs[42]) & 0xffffffff;
+-	ch = (regs->regs[43]) >> 32;
+-	cl = (regs->regs[43]) & 0xffffffff;
+-	printk("R41 : %08Lx%08Lx R42 : %08Lx%08Lx R43 : %08Lx%08Lx\n",
+-	       ah, al, bh, bl, ch, cl);
+-
+-	ah = (regs->regs[44]) >> 32;
+-	al = (regs->regs[44]) & 0xffffffff;
+-	bh = (regs->regs[45]) >> 32;
+-	bl = (regs->regs[45]) & 0xffffffff;
+-	ch = (regs->regs[46]) >> 32;
+-	cl = (regs->regs[46]) & 0xffffffff;
+-	printk("R44 : %08Lx%08Lx R45 : %08Lx%08Lx R46 : %08Lx%08Lx\n",
+-	       ah, al, bh, bl, ch, cl);
+-
+-	ah = (regs->regs[47]) >> 32;
+-	al = (regs->regs[47]) & 0xffffffff;
+-	bh = (regs->regs[48]) >> 32;
+-	bl = (regs->regs[48]) & 0xffffffff;
+-	ch = (regs->regs[49]) >> 32;
+-	cl = (regs->regs[49]) & 0xffffffff;
+-	printk("R47 : %08Lx%08Lx R48 : %08Lx%08Lx R49 : %08Lx%08Lx\n",
+-	       ah, al, bh, bl, ch, cl);
+-
+-	ah = (regs->regs[50]) >> 32;
+-	al = (regs->regs[50]) & 0xffffffff;
+-	bh = (regs->regs[51]) >> 32;
+-	bl = (regs->regs[51]) & 0xffffffff;
+-	ch = (regs->regs[52]) >> 32;
+-	cl = (regs->regs[52]) & 0xffffffff;
+-	printk("R50 : %08Lx%08Lx R51 : %08Lx%08Lx R52 : %08Lx%08Lx\n",
+-	       ah, al, bh, bl, ch, cl);
+-
+-	ah = (regs->regs[53]) >> 32;
+-	al = (regs->regs[53]) & 0xffffffff;
+-	bh = (regs->regs[54]) >> 32;
+-	bl = (regs->regs[54]) & 0xffffffff;
+-	ch = (regs->regs[55]) >> 32;
+-	cl = (regs->regs[55]) & 0xffffffff;
+-	printk("R53 : %08Lx%08Lx R54 : %08Lx%08Lx R55 : %08Lx%08Lx\n",
+-	       ah, al, bh, bl, ch, cl);
+-
+-	ah = (regs->regs[56]) >> 32;
+-	al = (regs->regs[56]) & 0xffffffff;
+-	bh = (regs->regs[57]) >> 32;
+-	bl = (regs->regs[57]) & 0xffffffff;
+-	ch = (regs->regs[58]) >> 32;
+-	cl = (regs->regs[58]) & 0xffffffff;
+-	printk("R56 : %08Lx%08Lx R57 : %08Lx%08Lx R58 : %08Lx%08Lx\n",
+-	       ah, al, bh, bl, ch, cl);
+-
+-	ah = (regs->regs[59]) >> 32;
+-	al = (regs->regs[59]) & 0xffffffff;
+-	bh = (regs->regs[60]) >> 32;
+-	bl = (regs->regs[60]) & 0xffffffff;
+-	ch = (regs->regs[61]) >> 32;
+-	cl = (regs->regs[61]) & 0xffffffff;
+-	printk("R59 : %08Lx%08Lx R60 : %08Lx%08Lx R61 : %08Lx%08Lx\n",
+-	       ah, al, bh, bl, ch, cl);
+-
+-	ah = (regs->regs[62]) >> 32;
+-	al = (regs->regs[62]) & 0xffffffff;
+-	bh = (regs->tregs[0]) >> 32;
+-	bl = (regs->tregs[0]) & 0xffffffff;
+-	ch = (regs->tregs[1]) >> 32;
+-	cl = (regs->tregs[1]) & 0xffffffff;
+-	printk("R62 : %08Lx%08Lx T0  : %08Lx%08Lx T1  : %08Lx%08Lx\n",
+-	       ah, al, bh, bl, ch, cl);
+-
+-	ah = (regs->tregs[2]) >> 32;
+-	al = (regs->tregs[2]) & 0xffffffff;
+-	bh = (regs->tregs[3]) >> 32;
+-	bl = (regs->tregs[3]) & 0xffffffff;
+-	ch = (regs->tregs[4]) >> 32;
+-	cl = (regs->tregs[4]) & 0xffffffff;
+-	printk("T2  : %08Lx%08Lx T3  : %08Lx%08Lx T4  : %08Lx%08Lx\n",
+-	       ah, al, bh, bl, ch, cl);
+-
+-	ah = (regs->tregs[5]) >> 32;
+-	al = (regs->tregs[5]) & 0xffffffff;
+-	bh = (regs->tregs[6]) >> 32;
+-	bl = (regs->tregs[6]) & 0xffffffff;
+-	ch = (regs->tregs[7]) >> 32;
+-	cl = (regs->tregs[7]) & 0xffffffff;
+-	printk("T5  : %08Lx%08Lx T6  : %08Lx%08Lx T7  : %08Lx%08Lx\n",
+-	       ah, al, bh, bl, ch, cl);
 -
 -	/*
--	 * The ROMFS_FS size is often not multiple of 1MB.
--	 * This can cause multiple CPLB sets covering the same memory area.
--	 * This will then cause multiple CPLB hit exceptions.
--	 * Workaround: We ensure a contiguous memory area by extending the kernel
--	 * memory section over the mtd section.
--	 * For ROMFS_FS memory must be covered with ICPLBs anyways.
--	 * So there is no difference between kernel and mtd memory setup.
+-	 * If we're in kernel mode, dump the stack too..
 -	 */
+-	if (!user_mode(regs)) {
+-		void show_stack(struct task_struct *tsk, unsigned long *sp);
+-		unsigned long sp = regs->regs[15] & 0xffffffff;
+-		struct task_struct *tsk = get_current();
 -
--	cplb_data[SDRAM_KERN].end = memory_mtd_start + mtd_size;;
--	cplb_data[SDRAM_RAM_MTD].valid = 0;
+-		tsk->thread.kregs = regs;
 -
--# endif
--#else
--	cplb_data[SDRAM_RAM_MTD].valid = 0;
--#endif
+-		show_stack(tsk, (unsigned long *)sp);
+-	}
+-}
 -
--	cplb_data[SDRAM_DMAZ].start = _ramend - DMA_UNCACHED_REGION;
--	cplb_data[SDRAM_DMAZ].end = _ramend;
+-struct task_struct * alloc_task_struct(void)
+-{
+-	/* Get task descriptor pages */
+-	return (struct task_struct *)
+-		__get_free_pages(GFP_KERNEL, get_order(THREAD_SIZE));
+-}
 -
--	cplb_data[RES_MEM].start = _ramend;
--	cplb_data[RES_MEM].end = physical_mem_end;
+-void free_task_struct(struct task_struct *p)
+-{
+-	free_pages((unsigned long) p, get_order(THREAD_SIZE));
+-}
 -
--	if (reserved_mem_dcache_on)
--		cplb_data[RES_MEM].d_conf = SDRAM_DGENERIC;
--	else
--		cplb_data[RES_MEM].d_conf = SDRAM_DNON_CHBL;
+-/*
+- * Create a kernel thread
+- */
+-ATTRIB_NORET void kernel_thread_helper(void *arg, int (*fn)(void *))
+-{
+-	do_exit(fn(arg));
+-}
 -
--	if (reserved_mem_icache_on)
--		cplb_data[RES_MEM].i_conf = SDRAM_IGENERIC;
--	else
--		cplb_data[RES_MEM].i_conf = SDRAM_INON_CHBL;
+-/*
+- * This is the mechanism for creating a new kernel thread.
+- *
+- * NOTE! Only a kernel-only process(ie the swapper or direct descendants
+- * who haven't done an "execve()") should use this: it will work within
+- * a system call from a "real" process, but the process memory space will
+- * not be freed until both the parent and the child have exited.
+- */
+-int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
+-{
+-	struct pt_regs regs;
 -
--	for (i = ZERO_P; i < ARRAY_SIZE(cplb_data); ++i) {
--		if (!cplb_data[i].valid)
--			continue;
+-	memset(&regs, 0, sizeof(regs));
+-	regs.regs[2] = (unsigned long)arg;
+-	regs.regs[3] = (unsigned long)fn;
 -
--		as_1m = cplb_data[i].start % SIZE_1M;
+-	regs.pc = (unsigned long)kernel_thread_helper;
+-	regs.sr = (1 << 30);
 -
--		/* We need to make sure all sections are properly 1M aligned
--		 * However between Kernel Memory and the Kernel mtd section, depending on the
--		 * rootfs size, there can be overlapping memory areas.
--		 */
+-	return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0,
+-		       &regs, 0, NULL, NULL);
+-}
 -
--		if (as_1m && i != L1I_MEM && i != L1D_MEM) {
--#ifdef CONFIG_MTD_UCLINUX
--			if (i == SDRAM_RAM_MTD) {
--				if ((cplb_data[SDRAM_KERN].end + 1) > cplb_data[SDRAM_RAM_MTD].start)
--					cplb_data[SDRAM_RAM_MTD].start = (cplb_data[i].start & (-2*SIZE_1M)) + SIZE_1M;
--				else
--					cplb_data[SDRAM_RAM_MTD].start = (cplb_data[i].start & (-2*SIZE_1M));
--			} else
+-/*
+- * Free current thread data structures etc..
+- */
+-void exit_thread(void)
+-{
+-	/* See arch/sparc/kernel/process.c for the precedent for doing this -- RPC.
+-
+-	   The SH-5 FPU save/restore approach relies on last_task_used_math
+-	   pointing to a live task_struct.  When another task tries to use the
+-	   FPU for the 1st time, the FPUDIS trap handling (see
+-	   arch/sh64/kernel/fpu.c) will save the existing FPU state to the
+-	   FP regs field within last_task_used_math before re-loading the new
+-	   task's FPU state (or initialising it if the FPU has been used
+-	   before).  So if last_task_used_math is stale, and its page has already been
+-	   re-allocated for another use, the consequences are rather grim. Unless we
+-	   null it here, there is no other path through which it would get safely
+-	   nulled. */
+-
+-#ifdef CONFIG_SH_FPU
+-	if (last_task_used_math == current) {
+-		last_task_used_math = NULL;
+-	}
 -#endif
--				printk(KERN_WARNING "Unaligned Start of %s at 0x%X\n",
--				       cplb_data[i].name, cplb_data[i].start);
+-}
+-
+-void flush_thread(void)
+-{
+-
+-	/* Called by fs/exec.c (flush_old_exec) to remove traces of a
+-	 * previously running executable. */
+-#ifdef CONFIG_SH_FPU
+-	if (last_task_used_math == current) {
+-		last_task_used_math = NULL;
+-	}
+-	/* Force FPU state to be reinitialised after exec */
+-	clear_used_math();
+-#endif
+-
+-	/* if we are a kernel thread, about to change to user thread,
+-         * update kreg
+-         */
+-	if(current->thread.kregs==&fake_swapper_regs) {
+-          current->thread.kregs =
+-             ((struct pt_regs *)(THREAD_SIZE + (unsigned long) current) - 1);
+-	  current->thread.uregs = current->thread.kregs;
+-	}
+-}
+-
+-void release_thread(struct task_struct *dead_task)
+-{
+-	/* do nothing */
+-}
+-
+-/* Fill in the fpu structure for a core dump.. */
+-int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu)
+-{
+-#ifdef CONFIG_SH_FPU
+-	int fpvalid;
+-	struct task_struct *tsk = current;
+-
+-	fpvalid = !!tsk_used_math(tsk);
+-	if (fpvalid) {
+-		if (current == last_task_used_math) {
+-			grab_fpu();
+-			fpsave(&tsk->thread.fpu.hard);
+-			release_fpu();
+-			last_task_used_math = 0;
+-			regs->sr |= SR_FD;
 -		}
 -
--		as = cplb_data[i].start % SIZE_4M;
--		ae = cplb_data[i].end % SIZE_4M;
+-		memcpy(fpu, &tsk->thread.fpu.hard, sizeof(*fpu));
+-	}
 -
--		if (as)
--			a_start = cplb_data[i].start + (SIZE_4M - (as));
--		else
--			a_start = cplb_data[i].start;
+-	return fpvalid;
+-#else
+-	return 0; /* Task didn't use the fpu at all. */
+-#endif
+-}
 -
--		a_end = cplb_data[i].end - ae;
+-asmlinkage void ret_from_fork(void);
 -
--		for (j = INITIAL_T; j <= SWITCH_T; j++) {
+-int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
+-		unsigned long unused,
+-		struct task_struct *p, struct pt_regs *regs)
+-{
+-	struct pt_regs *childregs;
+-	unsigned long long se;			/* Sign extension */
+-
+-#ifdef CONFIG_SH_FPU
+-	if(last_task_used_math == current) {
+-		grab_fpu();
+-		fpsave(&current->thread.fpu.hard);
+-		release_fpu();
+-		last_task_used_math = NULL;
+-		regs->sr |= SR_FD;
+-	}
+-#endif
+-	/* Copy from sh version */
+-	childregs = (struct pt_regs *)(THREAD_SIZE + task_stack_page(p)) - 1;
 -
--			switch (j) {
--			case INITIAL_T:
--				if (cplb_data[i].attr & INITIAL_T) {
--					t_i = &cplb.init_i;
--					t_d = &cplb.init_d;
--					process = 1;
--				} else
--					process = 0;
--				break;
--			case SWITCH_T:
--				if (cplb_data[i].attr & SWITCH_T) {
--					t_i = &cplb.switch_i;
--					t_d = &cplb.switch_d;
--					process = 1;
--				} else
--					process = 0;
--				break;
--			default:
--					process = 0;
--				break;
--			}
+-	*childregs = *regs;
 -
--			if (!process)
--				continue;
--			if (cplb_data[i].attr & I_CPLB)
--				__fill_code_cplbtab(t_i, i, a_start, a_end);
+-	if (user_mode(regs)) {
+-		childregs->regs[15] = usp;
+-		p->thread.uregs = childregs;
+-	} else {
+-		childregs->regs[15] = (unsigned long)task_stack_page(p) + THREAD_SIZE;
+-	}
 -
--			if (cplb_data[i].attr & D_CPLB)
--				__fill_data_cplbtab(t_d, i, a_start, a_end);
--		}
+-	childregs->regs[9] = 0; /* Set return value for child */
+-	childregs->sr |= SR_FD; /* Invalidate FPU flag */
+-
+-	p->thread.sp = (unsigned long) childregs;
+-	p->thread.pc = (unsigned long) ret_from_fork;
+-
+-	/*
+-	 * Sign extend the edited stack.
+-         * Note that thread.pc and thread.pc will stay
+-	 * 32-bit wide and context switch must take care
+-	 * of NEFF sign extension.
+-	 */
+-
+-	se = childregs->regs[15];
+-	se = (se & NEFF_SIGN) ? (se | NEFF_MASK) : se;
+-	childregs->regs[15] = se;
+-
+-	return 0;
+-}
+-
+-asmlinkage int sys_fork(unsigned long r2, unsigned long r3,
+-			unsigned long r4, unsigned long r5,
+-			unsigned long r6, unsigned long r7,
+-			struct pt_regs *pregs)
+-{
+-	return do_fork(SIGCHLD, pregs->regs[15], pregs, 0, 0, 0);
+-}
+-
+-asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp,
+-			 unsigned long r4, unsigned long r5,
+-			 unsigned long r6, unsigned long r7,
+-			 struct pt_regs *pregs)
+-{
+-	if (!newsp)
+-		newsp = pregs->regs[15];
+-	return do_fork(clone_flags, newsp, pregs, 0, 0, 0);
+-}
+-
+-/*
+- * This is trivial, and on the face of it looks like it
+- * could equally well be done in user mode.
+- *
+- * Not so, for quite unobvious reasons - register pressure.
+- * In user mode vfork() cannot have a stack frame, and if
+- * done by calling the "clone()" system call directly, you
+- * do not have enough call-clobbered registers to hold all
+- * the information you need.
+- */
+-asmlinkage int sys_vfork(unsigned long r2, unsigned long r3,
+-			 unsigned long r4, unsigned long r5,
+-			 unsigned long r6, unsigned long r7,
+-			 struct pt_regs *pregs)
+-{
+-	return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, pregs->regs[15], pregs, 0, 0, 0);
+-}
+-
+-/*
+- * sys_execve() executes a new program.
+- */
+-asmlinkage int sys_execve(char *ufilename, char **uargv,
+-			  char **uenvp, unsigned long r5,
+-			  unsigned long r6, unsigned long r7,
+-			  struct pt_regs *pregs)
+-{
+-	int error;
+-	char *filename;
+-
+-	lock_kernel();
+-	filename = getname((char __user *)ufilename);
+-	error = PTR_ERR(filename);
+-	if (IS_ERR(filename))
+-		goto out;
+-
+-	error = do_execve(filename,
+-			  (char __user * __user *)uargv,
+-			  (char __user * __user *)uenvp,
+-			  pregs);
+-	if (error == 0) {
+-		task_lock(current);
+-		current->ptrace &= ~PT_DTRACE;
+-		task_unlock(current);
 -	}
+-	putname(filename);
+-out:
+-	unlock_kernel();
+-	return error;
+-}
 -
--/* close tables */
+-/*
+- * These bracket the sleeping functions..
+- */
+-extern void interruptible_sleep_on(wait_queue_head_t *q);
 -
--	close_cplbtab(&cplb.init_i);
--	close_cplbtab(&cplb.init_d);
+-#define mid_sched	((unsigned long) interruptible_sleep_on)
 -
--	cplb.init_i.tab[cplb.init_i.pos] = -1;
--	cplb.init_d.tab[cplb.init_d.pos] = -1;
--	cplb.switch_i.tab[cplb.switch_i.pos] = -1;
--	cplb.switch_d.tab[cplb.switch_d.pos] = -1;
+-static int in_sh64_switch_to(unsigned long pc)
+-{
+-	extern char __sh64_switch_to_end;
+-	/* For a sleeping task, the PC is somewhere in the middle of the function,
+-	   so we don't have to worry about masking the LSB off */
+-	return (pc >= (unsigned long) sh64_switch_to) &&
+-	       (pc < (unsigned long) &__sh64_switch_to_end);
+-}
+-
+-unsigned long get_wchan(struct task_struct *p)
+-{
+-	unsigned long schedule_fp;
+-	unsigned long sh64_switch_to_fp;
+-	unsigned long schedule_caller_pc;
+-	unsigned long pc;
+-
+-	if (!p || p == current || p->state == TASK_RUNNING)
+-		return 0;
+-
+-	/*
+-	 * The same comment as on the Alpha applies here, too ...
+-	 */
+-	pc = thread_saved_pc(p);
+-
+-#ifdef CONFIG_FRAME_POINTER
+-	if (in_sh64_switch_to(pc)) {
+-		sh64_switch_to_fp = (long) p->thread.sp;
+-		/* r14 is saved at offset 4 in the sh64_switch_to frame */
+-		schedule_fp = *(unsigned long *) (long)(sh64_switch_to_fp + 4);
+-
+-		/* and the caller of 'schedule' is (currently!) saved at offset 24
+-		   in the frame of schedule (from disasm) */
+-		schedule_caller_pc = *(unsigned long *) (long)(schedule_fp + 24);
+-		return schedule_caller_pc;
+-	}
+-#endif
+-	return pc;
+-}
+-
+-/* Provide a /proc/asids file that lists out the
+-   ASIDs currently associated with the processes.  (If the DM.PC register is
+-   examined through the debug link, this shows ASID + PC.  To make use of this,
+-   the PID->ASID relationship needs to be known.  This is primarily for
+-   debugging.)
+-   */
 -
+-#if defined(CONFIG_SH64_PROC_ASIDS)
+-static int
+-asids_proc_info(char *buf, char **start, off_t fpos, int length, int *eof, void *data)
+-{
+-	int len=0;
+-	struct task_struct *p;
+-	read_lock(&tasklist_lock);
+-	for_each_process(p) {
+-		int pid = p->pid;
+-		struct mm_struct *mm;
+-		if (!pid) continue;
+-		mm = p->mm;
+-		if (mm) {
+-			unsigned long asid, context;
+-			context = mm->context;
+-			asid = (context & 0xff);
+-			len += sprintf(buf+len, "%5d : %02lx\n", pid, asid);
+-		} else {
+-			len += sprintf(buf+len, "%5d : (none)\n", pid);
+-		}
+-	}
+-	read_unlock(&tasklist_lock);
+-	*eof = 1;
+-	return len;
 -}
 -
+-static int __init register_proc_asids(void)
+-{
+-	create_proc_read_entry("asids", 0, NULL, asids_proc_info, NULL);
+-	return 0;
+-}
+-__initcall(register_proc_asids);
 -#endif
+diff --git a/arch/sh64/kernel/ptrace.c b/arch/sh64/kernel/ptrace.c
+deleted file mode 100644
+index 8a2d339..0000000
+--- a/arch/sh64/kernel/ptrace.c
++++ /dev/null
+@@ -1,332 +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.
+- *
+- * arch/sh64/kernel/ptrace.c
+- *
+- * Copyright (C) 2000, 2001  Paolo Alberelli
+- * Copyright (C) 2003  Paul Mundt
+- *
+- * Started from SH3/4 version:
+- *   SuperH version:   Copyright (C) 1999, 2000  Kaz Kojima & Niibe Yutaka
+- *
+- *   Original x86 implementation:
+- *	By Ross Biro 1/23/92
+- *	edited by Linus Torvalds
+- *
+- */
 -
-diff --git a/arch/blackfin/kernel/early_printk.c b/arch/blackfin/kernel/early_printk.c
-index 724f4a5..60f67f9 100644
---- a/arch/blackfin/kernel/early_printk.c
-+++ b/arch/blackfin/kernel/early_printk.c
-@@ -187,7 +187,7 @@ asmlinkage void __init init_early_exception_vectors(void)
- 	bfin_write_EVT15(early_trap);
- 	CSYNC();
- 
--	/* Set all the return from interupt, exception, NMI to a known place
-+	/* Set all the return from interrupt, exception, NMI to a known place
- 	 * so if we do a RETI, RETX or RETN by mistake - we go somewhere known
- 	 * Note - don't change RETS - we are in a subroutine, or
- 	 * RETE - since it might screw up if emulator is attached
-@@ -205,7 +205,7 @@ asmlinkage void __init early_trap_c(struct pt_regs *fp, void *retaddr)
- 	if (likely(early_console == NULL))
- 		setup_early_printk(DEFAULT_EARLY_PORT);
- 
--	dump_bfin_mem((void *)fp->retx);
-+	dump_bfin_mem(fp);
- 	show_regs(fp);
- 	dump_bfin_trace_buffer();
- 
-diff --git a/arch/blackfin/kernel/process.c b/arch/blackfin/kernel/process.c
-index 5bf1512..023dc80 100644
---- a/arch/blackfin/kernel/process.c
-+++ b/arch/blackfin/kernel/process.c
-@@ -39,9 +39,6 @@
- #include <asm/blackfin.h>
- #include <asm/fixed_code.h>
- 
--#define	LED_ON	0
--#define	LED_OFF	1
+-#include <linux/kernel.h>
+-#include <linux/rwsem.h>
+-#include <linux/sched.h>
+-#include <linux/mm.h>
+-#include <linux/smp.h>
+-#include <linux/smp_lock.h>
+-#include <linux/errno.h>
+-#include <linux/ptrace.h>
+-#include <linux/user.h>
+-#include <linux/signal.h>
+-#include <linux/syscalls.h>
 -
- asmlinkage void ret_from_fork(void);
- 
- /* Points to the SDRAM backup memory for the stack that is currently in
-@@ -70,32 +67,6 @@ void (*pm_power_off)(void) = NULL;
- EXPORT_SYMBOL(pm_power_off);
- 
- /*
-- * We are using a different LED from the one used to indicate timer interrupt.
+-#include <asm/io.h>
+-#include <asm/uaccess.h>
+-#include <asm/pgtable.h>
+-#include <asm/system.h>
+-#include <asm/processor.h>
+-#include <asm/mmu_context.h>
+-
+-/* This mask defines the bits of the SR which the user is not allowed to
+-   change, which are everything except S, Q, M, PR, SZ, FR. */
+-#define SR_MASK      (0xffff8cfd)
+-
+-/*
+- * does not yet catch signals sent when the child dies.
+- * in exit.c or in signal.c.
 - */
--#if defined(CONFIG_BFIN_IDLE_LED)
--static inline void leds_switch(int flag)
+-
+-/*
+- * This routine will get a word from the user area in the process kernel stack.
+- */
+-static inline int get_stack_long(struct task_struct *task, int offset)
 -{
--	unsigned short tmp = 0;
+-	unsigned char *stack;
 -
--	tmp = bfin_read_CONFIG_BFIN_IDLE_LED_PORT();
--	SSYNC();
+-	stack = (unsigned char *)(task->thread.uregs);
+-	stack += offset;
+-	return (*((int *)stack));
+-}
 -
--	if (flag == LED_ON)
--		tmp &= ~CONFIG_BFIN_IDLE_LED_PIN;	/* light on */
--	else
--		tmp |= CONFIG_BFIN_IDLE_LED_PIN;	/* light off */
+-static inline unsigned long
+-get_fpu_long(struct task_struct *task, unsigned long addr)
+-{
+-	unsigned long tmp;
+-	struct pt_regs *regs;
+-	regs = (struct pt_regs*)((unsigned char *)task + THREAD_SIZE) - 1;
 -
--	bfin_write_CONFIG_BFIN_IDLE_LED_PORT(tmp);
--	SSYNC();
+-	if (!tsk_used_math(task)) {
+-		if (addr == offsetof(struct user_fpu_struct, fpscr)) {
+-			tmp = FPSCR_INIT;
+-		} else {
+-			tmp = 0xffffffffUL; /* matches initial value in fpu.c */
+-		}
+-		return tmp;
+-	}
 -
+-	if (last_task_used_math == task) {
+-		grab_fpu();
+-		fpsave(&task->thread.fpu.hard);
+-		release_fpu();
+-		last_task_used_math = 0;
+-		regs->sr |= SR_FD;
+-	}
+-
+-	tmp = ((long *)&task->thread.fpu)[addr / sizeof(unsigned long)];
+-	return tmp;
 -}
--#else
--static inline void leds_switch(int flag)
+-
+-/*
+- * This routine will put a word into the user area in the process kernel stack.
+- */
+-static inline int put_stack_long(struct task_struct *task, int offset,
+-				 unsigned long data)
 -{
+-	unsigned char *stack;
+-
+-	stack = (unsigned char *)(task->thread.uregs);
+-	stack += offset;
+-	*(unsigned long *) stack = data;
+-	return 0;
 -}
--#endif
+-
+-static inline int
+-put_fpu_long(struct task_struct *task, unsigned long addr, unsigned long data)
+-{
+-	struct pt_regs *regs;
+-
+-	regs = (struct pt_regs*)((unsigned char *)task + THREAD_SIZE) - 1;
+-
+-	if (!tsk_used_math(task)) {
+-		fpinit(&task->thread.fpu.hard);
+-		set_stopped_child_used_math(task);
+-	} else if (last_task_used_math == task) {
+-		grab_fpu();
+-		fpsave(&task->thread.fpu.hard);
+-		release_fpu();
+-		last_task_used_math = 0;
+-		regs->sr |= SR_FD;
+-	}
+-
+-	((long *)&task->thread.fpu)[addr / sizeof(unsigned long)] = data;
+-	return 0;
+-}
+-
+-
+-long arch_ptrace(struct task_struct *child, long request, long addr, long data)
+-{
+-	int ret;
+-
+-	switch (request) {
+-	/* when I and D space are separate, these will need to be fixed. */
+-	case PTRACE_PEEKTEXT: /* read word at location addr. */
+-	case PTRACE_PEEKDATA:
+-		ret = generic_ptrace_peekdata(child, addr, data);
+-		break;
+-
+-	/* read the word at location addr in the USER area. */
+-	case PTRACE_PEEKUSR: {
+-		unsigned long tmp;
+-
+-		ret = -EIO;
+-		if ((addr & 3) || addr < 0)
+-			break;
+-
+-		if (addr < sizeof(struct pt_regs))
+-			tmp = get_stack_long(child, addr);
+-		else if ((addr >= offsetof(struct user, fpu)) &&
+-			 (addr <  offsetof(struct user, u_fpvalid))) {
+-			tmp = get_fpu_long(child, addr - offsetof(struct user, fpu));
+-		} else if (addr == offsetof(struct user, u_fpvalid)) {
+-			tmp = !!tsk_used_math(child);
+-		} else {
+-			break;
+-		}
+-		ret = put_user(tmp, (unsigned long *)data);
+-		break;
+-	}
+-
+-	/* when I and D space are separate, this will have to be fixed. */
+-	case PTRACE_POKETEXT: /* write the word at location addr. */
+-	case PTRACE_POKEDATA:
+-		ret = generic_ptrace_pokedata(child, addr, data);
+-		break;
+-
+-	case PTRACE_POKEUSR:
+-                /* write the word at location addr in the USER area. We must
+-                   disallow any changes to certain SR bits or u_fpvalid, since
+-                   this could crash the kernel or result in a security
+-                   loophole. */
+-		ret = -EIO;
+-		if ((addr & 3) || addr < 0)
+-			break;
+-
+-		if (addr < sizeof(struct pt_regs)) {
+-			/* Ignore change of top 32 bits of SR */
+-			if (addr == offsetof (struct pt_regs, sr)+4)
+-			{
+-				ret = 0;
+-				break;
+-			}
+-			/* If lower 32 bits of SR, ignore non-user bits */
+-			if (addr == offsetof (struct pt_regs, sr))
+-			{
+-				long cursr = get_stack_long(child, addr);
+-				data &= ~(SR_MASK);
+-				data |= (cursr & SR_MASK);
+-			}
+-			ret = put_stack_long(child, addr, data);
+-		}
+-		else if ((addr >= offsetof(struct user, fpu)) &&
+-			 (addr <  offsetof(struct user, u_fpvalid))) {
+-			ret = put_fpu_long(child, addr - offsetof(struct user, fpu), data);
+-		}
+-		break;
+-
+-	case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
+-	case PTRACE_CONT: { /* restart after signal. */
+-		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;
+-		wake_up_process(child);
+-		ret = 0;
+-		break;
+-	}
 -
 -/*
-  * The idle loop on BFIN
-  */
- #ifdef CONFIG_IDLE_L1
-@@ -106,12 +77,10 @@ void cpu_idle(void)__attribute__((l1_text));
- void default_idle(void)
- {
- 	while (!need_resched()) {
--		leds_switch(LED_OFF);
- 		local_irq_disable();
- 		if (likely(!need_resched()))
- 			idle_with_irq_disabled();
- 		local_irq_enable();
--		leds_switch(LED_ON);
- 	}
- }
- 
-@@ -327,6 +296,7 @@ void finish_atomic_sections (struct pt_regs *regs)
- }
- 
- #if defined(CONFIG_ACCESS_CHECK)
-+/* Return 1 if access to memory range is OK, 0 otherwise */
- int _access_ok(unsigned long addr, unsigned long size)
- {
- 	if (size == 0)
-diff --git a/arch/blackfin/kernel/reboot.c b/arch/blackfin/kernel/reboot.c
-index ae28aac..483f93d 100644
---- a/arch/blackfin/kernel/reboot.c
-+++ b/arch/blackfin/kernel/reboot.c
-@@ -19,6 +19,11 @@
- #define SYSCR_VAL 	0x10
- #endif
- 
-+/*
-+ * Delay min 5 SCLK cycles using worst case CCLK/SCLK ratio (15)
-+ */
-+#define SWRST_DELAY	(5 * 15)
-+
- /* A system soft reset makes external memory unusable
-  * so force this function into L1.
-  */
-@@ -34,7 +39,13 @@ void bfin_reset(void)
- 	while (1) {
- 		/* initiate system soft reset with magic 0x7 */
- 		bfin_write_SWRST(0x7);
--		asm("ssync;");
-+
-+		/* Wait for System reset to actually reset, needs to be 5 SCLKs, */
-+		/* Assume CCLK / SCLK ratio is worst case (15), and use 5*15     */
-+
-+		asm("LSETUP(.Lfoo,.Lfoo) LC0 = %0\n .Lfoo: NOP;\n"
-+		 : : "a" (SWRST_DELAY) : "LC0", "LT0", "LB0");
-+
- 		/* clear system soft reset */
- 		bfin_write_SWRST(0);
- 		asm("ssync;");
-diff --git a/arch/blackfin/kernel/setup.c b/arch/blackfin/kernel/setup.c
-index d282201..462cae8 100644
---- a/arch/blackfin/kernel/setup.c
-+++ b/arch/blackfin/kernel/setup.c
-@@ -238,7 +238,13 @@ void __init setup_arch(char **cmdline_p)
- 	memory_end = _ramend - DMA_UNCACHED_REGION;
- 
- 	_ramstart = (unsigned long)__bss_stop;
-+	_rambase = (unsigned long)_stext;
-+#ifdef CONFIG_MPU
-+	/* Round up to multiple of 4MB.  */
-+	memory_start = (_ramstart + 0x3fffff) & ~0x3fffff;
-+#else
- 	memory_start = PAGE_ALIGN(_ramstart);
-+#endif
- 
- #if defined(CONFIG_MTD_UCLINUX)
- 	/* generic memory mapped MTD driver */
-@@ -307,6 +313,11 @@ void __init setup_arch(char **cmdline_p)
- 	printk(KERN_NOTICE "Warning: limiting memory to %liMB due to hardware anomaly 05000263\n", memory_end >> 20);
- #endif				/* ANOMALY_05000263 */
- 
-+#ifdef CONFIG_MPU
-+	page_mask_nelts = ((_ramend >> PAGE_SHIFT) + 31) / 32;
-+	page_mask_order = get_order(3 * page_mask_nelts * sizeof(long));
-+#endif
-+
- #if !defined(CONFIG_MTD_UCLINUX)
- 	memory_end -= SIZE_4K; /*In case there is no valid CPLB behind memory_end make sure we don't get to close*/
- #endif
-@@ -315,8 +326,6 @@ void __init setup_arch(char **cmdline_p)
- 	init_mm.end_data = (unsigned long)_edata;
- 	init_mm.brk = (unsigned long)0;
- 
--	init_leds();
+- * make the child exit.  Best I can do is send it a sigkill.
+- * perhaps it should be put in the status that it wants to
+- * exit.
+- */
+-	case PTRACE_KILL: {
+-		ret = 0;
+-		if (child->exit_state == EXIT_ZOMBIE)	/* already dead */
+-			break;
+-		child->exit_code = SIGKILL;
+-		wake_up_process(child);
+-		break;
+-	}
 -
- 	_bfin_swrst = bfin_read_SWRST();
- 
- 	if (_bfin_swrst & RESET_DOUBLE)
-diff --git a/arch/blackfin/kernel/time.c b/arch/blackfin/kernel/time.c
-index beef057..5bd64e3 100644
---- a/arch/blackfin/kernel/time.c
-+++ b/arch/blackfin/kernel/time.c
-@@ -42,75 +42,6 @@
- static void time_sched_init(irqreturn_t(*timer_routine)
- 			(int, void *));
- static unsigned long gettimeoffset(void);
--static inline void do_leds(void);
+-	case PTRACE_SINGLESTEP: {  /* set the trap flag. */
+-		struct pt_regs *regs;
+-
+-		ret = -EIO;
+-		if (!valid_signal(data))
+-			break;
+-		clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+-		if ((child->ptrace & PT_DTRACE) == 0) {
+-			/* Spurious delayed TF traps may occur */
+-			child->ptrace |= PT_DTRACE;
+-		}
+-
+-		regs = child->thread.uregs;
+-
+-		regs->sr |= SR_SSTEP;	/* auto-resetting upon exception */
+-
+-		child->exit_code = data;
+-		/* give it a chance to run. */
+-		wake_up_process(child);
+-		ret = 0;
+-		break;
+-	}
+-
+-	default:
+-		ret = ptrace_request(child, request, addr, data);
+-		break;
+-	}
+-	return ret;
+-}
+-
+-asmlinkage int sh64_ptrace(long request, long pid, long addr, long data)
+-{
+-	extern void poke_real_address_q(unsigned long long addr, unsigned long long data);
+-#define WPC_DBRMODE 0x0d104008
+-	static int first_call = 1;
+-
+-	lock_kernel();
+-	if (first_call) {
+-		/* Set WPC.DBRMODE to 0.  This makes all debug events get
+-		 * delivered through RESVEC, i.e. into the handlers in entry.S.
+-		 * (If the kernel was downloaded using a remote gdb, WPC.DBRMODE
+-		 * would normally be left set to 1, which makes debug events get
+-		 * delivered through DBRVEC, i.e. into the remote gdb's
+-		 * handlers.  This prevents ptrace getting them, and confuses
+-		 * the remote gdb.) */
+-		printk("DBRMODE set to 0 to permit native debugging\n");
+-		poke_real_address_q(WPC_DBRMODE, 0);
+-		first_call = 0;
+-	}
+-	unlock_kernel();
+-
+-	return sys_ptrace(request, pid, addr, data);
+-}
+-
+-asmlinkage void syscall_trace(void)
+-{
+-	struct task_struct *tsk = current;
+-
+-	if (!test_thread_flag(TIF_SYSCALL_TRACE))
+-		return;
+-	if (!(tsk->ptrace & PT_PTRACED))
+-		return;
+-
+-	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 (tsk->exit_code) {
+-		send_sig(tsk->exit_code, tsk, 1);
+-		tsk->exit_code = 0;
+-	}
+-}
 -
--#if (defined(CONFIG_BFIN_ALIVE_LED) || defined(CONFIG_BFIN_IDLE_LED))
--void __init init_leds(void)
+-/* Called with interrupts disabled */
+-asmlinkage void do_single_step(unsigned long long vec, struct pt_regs *regs)
 -{
--	unsigned int tmp = 0;
+-	/* This is called after a single step exception (DEBUGSS).
+-	   There is no need to change the PC, as it is a post-execution
+-	   exception, as entry.S does not do anything to the PC for DEBUGSS.
+-	   We need to clear the Single Step setting in SR to avoid
+-	   continually stepping. */
+-	local_irq_enable();
+-	regs->sr &= ~SR_SSTEP;
+-	force_sig(SIGTRAP, current);
+-}
 -
--#if defined(CONFIG_BFIN_ALIVE_LED)
--	/* config pins as output. */
--	tmp = bfin_read_CONFIG_BFIN_ALIVE_LED_DPORT();
--	SSYNC();
--	bfin_write_CONFIG_BFIN_ALIVE_LED_DPORT(tmp | CONFIG_BFIN_ALIVE_LED_PIN);
--	SSYNC();
+-/* Called with interrupts disabled */
+-asmlinkage void do_software_break_point(unsigned long long vec,
+-					struct pt_regs *regs)
+-{
+-	/* We need to forward step the PC, to counteract the backstep done
+-	   in signal.c. */
+-	local_irq_enable();
+-	force_sig(SIGTRAP, current);
+-	regs->pc += 4;
+-}
 -
--	/*      First set led be off */
--	tmp = bfin_read_CONFIG_BFIN_ALIVE_LED_PORT();
--	SSYNC();
--	bfin_write_CONFIG_BFIN_ALIVE_LED_PORT(tmp | CONFIG_BFIN_ALIVE_LED_PIN);	/* light off */
--	SSYNC();
--#endif
+-/*
+- * Called by kernel/ptrace.c when detaching..
+- *
+- * Make sure single step bits etc are not set.
+- */
+-void ptrace_disable(struct task_struct *child)
+-{
+-        /* nothing to do.. */
+-}
+diff --git a/arch/sh64/kernel/semaphore.c b/arch/sh64/kernel/semaphore.c
+deleted file mode 100644
+index 72c1653..0000000
+--- a/arch/sh64/kernel/semaphore.c
++++ /dev/null
+@@ -1,140 +0,0 @@
+-/*
+- * Just taken from alpha implementation.
+- * This can't work well, perhaps.
+- */
+-/*
+- *  Generic semaphore code. Buyer beware. Do your own
+- * specific changes in <asm/semaphore-helper.h>
+- */
 -
--#if defined(CONFIG_BFIN_IDLE_LED)
--	/* config pins as output. */
--	tmp = bfin_read_CONFIG_BFIN_IDLE_LED_DPORT();
--	SSYNC();
--	bfin_write_CONFIG_BFIN_IDLE_LED_DPORT(tmp | CONFIG_BFIN_IDLE_LED_PIN);
--	SSYNC();
+-#include <linux/errno.h>
+-#include <linux/rwsem.h>
+-#include <linux/sched.h>
+-#include <linux/wait.h>
+-#include <linux/init.h>
+-#include <asm/semaphore.h>
+-#include <asm/semaphore-helper.h>
 -
--	/*      First set led be off */
--	tmp = bfin_read_CONFIG_BFIN_IDLE_LED_PORT();
--	SSYNC();
--	bfin_write_CONFIG_BFIN_IDLE_LED_PORT(tmp | CONFIG_BFIN_IDLE_LED_PIN);	/* light off */
--	SSYNC();
--#endif
--}
--#else
--void __init init_leds(void)
+-spinlock_t semaphore_wake_lock;
+-
+-/*
+- * Semaphores are implemented using a two-way counter:
+- * The "count" variable is decremented for each process
+- * that tries to sleep, while the "waking" variable is
+- * incremented when the "up()" code goes to wake up waiting
+- * processes.
+- *
+- * Notably, the inline "up()" and "down()" functions can
+- * efficiently test if they need to do any extra work (up
+- * needs to do something only if count was negative before
+- * the increment operation.
+- *
+- * waking_non_zero() (from asm/semaphore.h) must execute
+- * atomically.
+- *
+- * When __up() is called, the count was negative before
+- * incrementing it, and we need to wake up somebody.
+- *
+- * This routine adds one to the count of processes that need to
+- * wake up and exit.  ALL waiting processes actually wake up but
+- * only the one that gets to the "waking" field first will gate
+- * through and acquire the semaphore.  The others will go back
+- * to sleep.
+- *
+- * Note that these functions are only called when there is
+- * contention on the lock, and as such all this is the
+- * "non-critical" part of the whole semaphore business. The
+- * critical part is the inline stuff in <asm/semaphore.h>
+- * where we want to avoid any extra jumps and calls.
+- */
+-void __up(struct semaphore *sem)
 -{
+-	wake_one_more(sem);
+-	wake_up(&sem->wait);
 -}
--#endif
 -
--#if defined(CONFIG_BFIN_ALIVE_LED)
--static inline void do_leds(void)
+-/*
+- * Perform the "down" function.  Return zero for semaphore acquired,
+- * return negative for signalled out of the function.
+- *
+- * If called from __down, the return is ignored and the wait loop is
+- * not interruptible.  This means that a task waiting on a semaphore
+- * using "down()" cannot be killed until someone does an "up()" on
+- * the semaphore.
+- *
+- * If called from __down_interruptible, the return value gets checked
+- * upon return.  If the return value is negative then the task continues
+- * with the negative value in the return register (it can be tested by
+- * the caller).
+- *
+- * Either form may be used in conjunction with "up()".
+- *
+- */
+-
+-#define DOWN_VAR				\
+-	struct task_struct *tsk = current;	\
+-	wait_queue_t wait;			\
+-	init_waitqueue_entry(&wait, tsk);
+-
+-#define DOWN_HEAD(task_state)						\
+-									\
+-									\
+-	tsk->state = (task_state);					\
+-	add_wait_queue(&sem->wait, &wait);				\
+-									\
+-	/*								\
+-	 * Ok, we're set up.  sem->count is known to be less than zero	\
+-	 * so we must wait.						\
+-	 *								\
+-	 * We can let go the lock for purposes of waiting.		\
+-	 * We re-acquire it after awaking so as to protect		\
+-	 * all semaphore operations.					\
+-	 *								\
+-	 * If "up()" is called before we call waking_non_zero() then	\
+-	 * we will catch it right away.  If it is called later then	\
+-	 * we will have to go through a wakeup cycle to catch it.	\
+-	 *								\
+-	 * Multiple waiters contend for the semaphore lock to see	\
+-	 * who gets to gate through and who has to wait some more.	\
+-	 */								\
+-	for (;;) {
+-
+-#define DOWN_TAIL(task_state)			\
+-		tsk->state = (task_state);	\
+-	}					\
+-	tsk->state = TASK_RUNNING;		\
+-	remove_wait_queue(&sem->wait, &wait);
+-
+-void __sched __down(struct semaphore * sem)
+-{
+-	DOWN_VAR
+-	DOWN_HEAD(TASK_UNINTERRUPTIBLE)
+-	if (waking_non_zero(sem))
+-		break;
+-	schedule();
+-	DOWN_TAIL(TASK_UNINTERRUPTIBLE)
+-}
+-
+-int __sched __down_interruptible(struct semaphore * sem)
 -{
--	static unsigned int count = 50;
--	static int flag;
--	unsigned short tmp = 0;
+-	int ret = 0;
+-	DOWN_VAR
+-	DOWN_HEAD(TASK_INTERRUPTIBLE)
 -
--	if (--count == 0) {
--		count = 50;
--		flag = ~flag;
+-	ret = waking_non_zero_interruptible(sem, tsk);
+-	if (ret)
+-	{
+-		if (ret == 1)
+-			/* ret != 0 only if we get interrupted -arca */
+-			ret = 0;
+-		break;
 -	}
--	tmp = bfin_read_CONFIG_BFIN_ALIVE_LED_PORT();
--	SSYNC();
+-	schedule();
+-	DOWN_TAIL(TASK_INTERRUPTIBLE)
+-	return ret;
+-}
 -
--	if (flag)
--		tmp &= ~CONFIG_BFIN_ALIVE_LED_PIN;	/* light on */
--	else
--		tmp |= CONFIG_BFIN_ALIVE_LED_PIN;	/* light off */
+-int __down_trylock(struct semaphore * sem)
+-{
+-	return waking_non_zero_trylock(sem);
+-}
+diff --git a/arch/sh64/kernel/setup.c b/arch/sh64/kernel/setup.c
+deleted file mode 100644
+index 2b7264c..0000000
+--- a/arch/sh64/kernel/setup.c
++++ /dev/null
+@@ -1,379 +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.
+- *
+- * arch/sh64/kernel/setup.c
+- *
+- * sh64 Arch Support
+- *
+- * This file handles the architecture-dependent parts of initialization
+- *
+- * Copyright (C) 2000, 2001  Paolo Alberelli
+- * Copyright (C) 2003, 2004  Paul Mundt
+- *
+- * benedict.gaster at superh.com:   2nd May 2002
+- *    Modified to use the empty_zero_page to pass command line arguments.
+- *
+- * benedict.gaster at superh.com:	 3rd May 2002
+- *    Added support for ramdisk, removing statically linked romfs at the same time.
+- *
+- * lethal at linux-sh.org:          15th May 2003
+- *    Added generic procfs cpuinfo reporting. Make boards just export their name.
+- *
+- * lethal at linux-sh.org:          25th May 2003
+- *    Added generic get_cpu_subtype() for subtype reporting from cpu_data->type.
+- *
+- */
+-#include <linux/errno.h>
+-#include <linux/rwsem.h>
+-#include <linux/sched.h>
+-#include <linux/kernel.h>
+-#include <linux/mm.h>
+-#include <linux/stddef.h>
+-#include <linux/unistd.h>
+-#include <linux/ptrace.h>
+-#include <linux/slab.h>
+-#include <linux/user.h>
+-#include <linux/a.out.h>
+-#include <linux/screen_info.h>
+-#include <linux/ioport.h>
+-#include <linux/delay.h>
+-#include <linux/init.h>
+-#include <linux/seq_file.h>
+-#include <linux/blkdev.h>
+-#include <linux/bootmem.h>
+-#include <linux/console.h>
+-#include <linux/root_dev.h>
+-#include <linux/cpu.h>
+-#include <linux/initrd.h>
+-#include <linux/pfn.h>
+-#include <asm/processor.h>
+-#include <asm/page.h>
+-#include <asm/pgtable.h>
+-#include <asm/platform.h>
+-#include <asm/uaccess.h>
+-#include <asm/system.h>
+-#include <asm/io.h>
+-#include <asm/sections.h>
+-#include <asm/setup.h>
+-#include <asm/smp.h>
+-
+-struct screen_info screen_info;
+-
+-#ifdef CONFIG_BLK_DEV_RAM
+-extern int rd_doload;		/* 1 = load ramdisk, 0 = don't load */
+-extern int rd_prompt;		/* 1 = prompt for ramdisk, 0 = don't prompt */
+-extern int rd_image_start;	/* starting block # of image */
+-#endif
 -
--	bfin_write_CONFIG_BFIN_ALIVE_LED_PORT(tmp);
--	SSYNC();
+-extern int root_mountflags;
+-extern char *get_system_type(void);
+-extern void platform_setup(void);
+-extern void platform_monitor(void);
+-extern void platform_reserve(void);
+-extern int sh64_cache_init(void);
+-extern int sh64_tlb_init(void);
+-
+-#define RAMDISK_IMAGE_START_MASK	0x07FF
+-#define RAMDISK_PROMPT_FLAG		0x8000
+-#define RAMDISK_LOAD_FLAG		0x4000
+-
+-static char __initdata command_line[COMMAND_LINE_SIZE] = { 0, };
+-unsigned long long memory_start = CONFIG_MEMORY_START;
+-unsigned long long memory_end = CONFIG_MEMORY_START + (CONFIG_MEMORY_SIZE_IN_MB * 1024 * 1024);
+-
+-struct sh_cpuinfo boot_cpu_data;
+-
+-static inline void parse_mem_cmdline (char ** cmdline_p)
+-{
+-        char c = ' ', *to = command_line, *from = COMMAND_LINE;
+-	int len = 0;
+-
+-	/* Save unparsed command line copy for /proc/cmdline */
+-	memcpy(boot_command_line, COMMAND_LINE, COMMAND_LINE_SIZE);
+-	boot_command_line[COMMAND_LINE_SIZE-1] = '\0';
 -
+-	for (;;) {
+-	  /*
+-	   * "mem=XXX[kKmM]" defines a size of memory.
+-	   */
+-	        if (c == ' ' && !memcmp(from, "mem=", 4)) {
+-		      if (to != command_line)
+-			to--;
+-		      {
+-			unsigned long mem_size;
+-
+-			mem_size = memparse(from+4, &from);
+-			memory_end = memory_start + mem_size;
+-		      }
+-		}
+-		c = *(from++);
+-		if (!c)
+-		  break;
+-		if (COMMAND_LINE_SIZE <= ++len)
+-		  break;
+-		*(to++) = c;
+-	}
+-	*to = '\0';
+-
+-	*cmdline_p = command_line;
+-}
+-
+-static void __init sh64_cpu_type_detect(void)
+-{
+-	extern unsigned long long peek_real_address_q(unsigned long long addr);
+-	unsigned long long cir;
+-	/* Do peeks in real mode to avoid having to set up a mapping for the
+-	   WPC registers.  On SH5-101 cut2, such a mapping would be exposed to
+-	   an address translation erratum which would make it hard to set up
+-	   correctly. */
+-	cir = peek_real_address_q(0x0d000008);
+-
+-	if ((cir & 0xffff) == 0x5103) {
+-		boot_cpu_data.type = CPU_SH5_103;
+-	} else if (((cir >> 32) & 0xffff) == 0x51e2) {
+-		/* CPU.VCR aliased at CIR address on SH5-101 */
+-		boot_cpu_data.type = CPU_SH5_101;
+-	} else {
+-		boot_cpu_data.type = CPU_SH_NONE;
+-	}
 -}
--#else
--static inline void do_leds(void)
+-
+-void __init setup_arch(char **cmdline_p)
 -{
--}
+-	unsigned long bootmap_size, i;
+-	unsigned long first_pfn, start_pfn, last_pfn, pages;
+-
+-#ifdef CONFIG_EARLY_PRINTK
+-	extern void enable_early_printk(void);
+-
+-	/*
+-	 * Setup Early SCIF console
+-	 */
+-	enable_early_printk();
 -#endif
- 
- static struct irqaction bfin_timer_irq = {
- 	.name = "BFIN Timer Tick",
-@@ -205,7 +136,6 @@ irqreturn_t timer_interrupt(int irq, void *dummy)
- 	write_seqlock(&xtime_lock);
- 
- 	do_timer(1);
--	do_leds();
- 
- #ifndef CONFIG_SMP
- 	update_process_times(user_mode(get_irq_regs()));
-diff --git a/arch/blackfin/kernel/traps.c b/arch/blackfin/kernel/traps.c
-index 21a55ef..66b5f3e 100644
---- a/arch/blackfin/kernel/traps.c
-+++ b/arch/blackfin/kernel/traps.c
-@@ -36,8 +36,10 @@
- #include <asm/cacheflush.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>
-@@ -170,7 +172,7 @@ asmlinkage void double_fault_c(struct pt_regs *fp)
- 	oops_in_progress = 1;
- 	printk(KERN_EMERG "\n" KERN_EMERG "Double Fault\n");
- 	dump_bfin_process(fp);
--	dump_bfin_mem((void *)fp->retx);
-+	dump_bfin_mem(fp);
- 	show_regs(fp);
- 	panic("Double Fault - unrecoverable event\n");
- 
-@@ -195,9 +197,13 @@ asmlinkage void trap_c(struct pt_regs *fp)
- 	 * we will kernel panic, so the system reboots.
- 	 * If KGDB is enabled, don't set this for kernel breakpoints
- 	*/
--	if ((bfin_read_IPEND() & 0xFFC0)
-+
-+	/* TODO: check to see if we are in some sort of deferred HWERR
-+	 * that we should be able to recover from, not kernel panic
-+	 */
-+	if ((bfin_read_IPEND() & 0xFFC0) && (trapnr != VEC_STEP)
- #ifdef CONFIG_KGDB
--		&& trapnr != VEC_EXCPT02
-+		&& (trapnr != VEC_EXCPT02)
- #endif
- 	){
- 		console_verbose();
-@@ -433,6 +439,36 @@ asmlinkage void trap_c(struct pt_regs *fp)
- 	/* 0x3D - Reserved, Caught by default */
- 	/* 0x3E - Reserved, Caught by default */
- 	/* 0x3F - Reserved, Caught by default */
-+	case VEC_HWERR:
-+		info.si_code = BUS_ADRALN;
-+		sig = SIGBUS;
-+		switch (fp->seqstat & SEQSTAT_HWERRCAUSE) {
-+		/* System MMR Error */
-+		case (SEQSTAT_HWERRCAUSE_SYSTEM_MMR):
-+			info.si_code = BUS_ADRALN;
-+			sig = SIGBUS;
-+			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));
-+			break;
-+		/* Performance Monitor Overflow */
-+		case (SEQSTAT_HWERRCAUSE_PERF_FLOW):
-+			printk(KERN_NOTICE HWC_x12(KERN_NOTICE));
-+			break;
-+		/* RAISE 5 instruction */
-+		case (SEQSTAT_HWERRCAUSE_RAISE_5):
-+			printk(KERN_NOTICE HWC_x18(KERN_NOTICE));
-+			break;
-+		default:        /* Reserved */
-+			printk(KERN_NOTICE HWC_default(KERN_NOTICE));
-+			break;
-+		}
-+		CHK_DEBUGGER_TRAP();
-+		break;
- 	default:
- 		info.si_code = TRAP_ILLTRAP;
- 		sig = SIGTRAP;
-@@ -447,7 +483,7 @@ asmlinkage void trap_c(struct pt_regs *fp)
- 	if (sig != SIGTRAP) {
- 		unsigned long stack;
- 		dump_bfin_process(fp);
--		dump_bfin_mem((void *)fp->retx);
-+		dump_bfin_mem(fp);
- 		show_regs(fp);
- 
- 		/* Print out the trace buffer if it makes sense */
-@@ -461,6 +497,7 @@ asmlinkage void trap_c(struct pt_regs *fp)
- 			dump_bfin_trace_buffer();
- 		show_stack(current, &stack);
- 		if (oops_in_progress) {
-+			print_modules();
- #ifndef CONFIG_ACCESS_CHECK
- 			printk(KERN_EMERG "Please turn on "
- 			       "CONFIG_ACCESS_CHECK\n");
-@@ -474,13 +511,6 @@ asmlinkage void trap_c(struct pt_regs *fp)
- 	info.si_addr = (void *)fp->pc;
- 	force_sig_info(sig, &info, current);
- 
--	/* Ensure that bad return addresses don't end up in an infinite
--	 * loop, due to speculative loads/reads. This needs to be done after
--	 * the signal has been sent.
+-
+-	/*
+-	 * Setup TLB mappings
 -	 */
--	if (trapnr == VEC_CPLB_I_M && sig != SIGTRAP)
--		fp->pc = SAFE_USER_INSTRUCTION;
+-	sh64_tlb_init();
 -
- 	trace_buffer_restore(j);
- 	return;
- }
-@@ -616,8 +646,10 @@ void dump_bfin_process(struct pt_regs *fp)
- 	if (oops_in_progress)
- 		printk(KERN_EMERG "Kernel OOPS in progress\n");
- 
--	if (context & 0x0020)
--		printk(KERN_NOTICE "Deferred excecption or HW Error context\n");
-+	if (context & 0x0020 && (fp->seqstat & SEQSTAT_EXCAUSE) == VEC_HWERR)
-+		printk(KERN_NOTICE "HW Error context\n");
-+	else if (context & 0x0020)
-+		printk(KERN_NOTICE "Defered Exception context\n");
- 	else if (context & 0x3FC0)
- 		printk(KERN_NOTICE "Interrupt context\n");
- 	else if (context & 0x4000)
-@@ -645,59 +677,124 @@ void dump_bfin_process(struct pt_regs *fp)
- 		     "No Valid process in current context\n");
- }
- 
--void dump_bfin_mem(void *retaddr)
-+void dump_bfin_mem(struct pt_regs *fp)
- {
-+	unsigned short *addr, *erraddr, val = 0, err = 0;
-+	char sti = 0, buf[6];
- 
--	if (retaddr >= (void *)FIXED_CODE_START  && retaddr < (void *)physical_mem_end
--#if L1_CODE_LENGTH != 0
--	    /* FIXME: Copy the code out of L1 Instruction SRAM through dma
--	       memcpy.  */
--	    && !(retaddr >= (void *)L1_CODE_START
--	         && retaddr < (void *)(L1_CODE_START + L1_CODE_LENGTH))
--#endif
--	) {
--		int i = ((unsigned int)retaddr & 0xFFFFFFF0) - 32;
--		unsigned short x = 0;
--		printk(KERN_NOTICE "return address: [0x%p]; contents of:", retaddr);
--		for (; i < ((unsigned int)retaddr & 0xFFFFFFF0) + 32; i += 2) {
--			if (!(i & 0xF))
--				printk("\n" KERN_NOTICE "0x%08x: ", i);
+-	/*
+-	 * Caches are already initialized by the time we get here, so we just
+-	 * fill in cpu_data info for the caches.
+-	 */
+-	sh64_cache_init();
 -
--			if (get_user(x, (unsigned short *)i))
--				break;
-+	if (unlikely((fp->seqstat & SEQSTAT_EXCAUSE) == VEC_HWERR))
-+		erraddr = (void *)fp->pc;
-+	else
-+		erraddr = (void *)fp->retx;
-+
-+	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);
-+
-+		if (get_user(val, addr)) {
-+			if (addr >= (unsigned short *)L1_CODE_START &&
-+			    addr < (unsigned short *)(L1_CODE_START + L1_CODE_LENGTH)) {
-+				dma_memcpy(&val, addr, sizeof(val));
-+				sprintf(buf, "%04x", val);
-+			} else if (addr >= (unsigned short *)FIXED_CODE_START &&
-+				addr <= (unsigned short *)memory_start) {
-+				val = bfin_read16(addr);
-+				sprintf(buf, "%04x", val);
-+			} else {
-+				val = 0;
-+				sprintf(buf, "????");
-+			}
-+		} else
-+			sprintf(buf, "%04x", val);
-+
-+		if (addr == erraddr) {
-+			printk("[%s]", buf);
-+			err = val;
-+		} else
-+			printk(" %s ", buf);
-+
-+		/* Do any previous instructions turn on interrupts? */
-+		if (addr <= erraddr &&				/* in the past */
-+		    ((val >= 0x0040 && val <= 0x0047) ||	/* STI instruction */
-+		      val == 0x017b))				/* [SP++] = RETI */
-+			sti = 1;
-+	}
-+
-+	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");
- #ifndef CONFIG_DEBUG_HWERR
--			/* If one of the last few instructions was a STI
--			 * it is likely that the error occured awhile ago
--			 * and we just noticed. This only happens in kernel
--			 * context, which should mean an oops is happening
--			 */
--			if (oops_in_progress && x >= 0x0040 && x <= 0x0047 && i <= 0)
--				panic("\n\nWARNING : You should reconfigure"
--					" the kernel to turn on\n"
--					" 'Hardware error interrupt"
--					" debugging'\n"
--					" The rest of this error"
--					" is meanless\n");
+-	platform_setup();
+-	platform_monitor();
+-
+-	sh64_cpu_type_detect();
+-
+-	ROOT_DEV = old_decode_dev(ORIG_ROOT_DEV);
+-
+-#ifdef CONFIG_BLK_DEV_RAM
+-	rd_image_start = RAMDISK_FLAGS & RAMDISK_IMAGE_START_MASK;
+-	rd_prompt = ((RAMDISK_FLAGS & RAMDISK_PROMPT_FLAG) != 0);
+-	rd_doload = ((RAMDISK_FLAGS & RAMDISK_LOAD_FLAG) != 0);
 -#endif
--			if (i == (unsigned int)retaddr)
--				printk("[%04x]", x);
--			else
--				printk(" %04x ", x);
-+		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
-+		/* If we are handling only one peripheral interrupt
-+		 * and current mm and pid are valid, and the last error
-+		 * was in that user space process's text area
-+		 * print it out - because that is where the problem exists
-+		 */
-+		if ((!(((fp)->ipend & ~0x30) & (((fp)->ipend & ~0x30) - 1))) &&
-+		     (current->pid && current->mm)) {
-+			/* 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");
-+				show_regs(fp + 1);
-+				printk(KERN_NOTICE "-------------------------------------------\n");
-+			}
- 		}
--		printk("\n");
--	} else
--		printk("\n" KERN_NOTICE
--			"Cannot look at the [PC] <%p> for it is"
--			" in unreadable memory - sorry\n", retaddr);
-+#endif
-+	}
- }
- 
- void show_regs(struct pt_regs *fp)
- {
- 	char buf [150];
-+	struct irqaction *action;
-+	unsigned int i;
-+	unsigned long flags;
- 
--	printk(KERN_NOTICE "\n" KERN_NOTICE "SEQUENCER STATUS:\n");
-+	printk(KERN_NOTICE "\n" KERN_NOTICE "SEQUENCER STATUS:\t\t%s\n", print_tainted());
- 	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",
-+		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);
-+		}
-+	}
-+
-+	/* if no interrupts are going off, don't print this out */
-+	if (fp->ipend & ~0x3F) {
-+		for (i = 0; i < (NR_IRQS - 1); i++) {
-+			spin_lock_irqsave(&irq_desc[i].lock, flags);
-+			action = irq_desc[i].action;
-+			if (!action)
-+				goto unlock;
-+
-+			decode_address(buf, (unsigned int)action->handler);
-+			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);
-+			}
-+			printk("\n");
-+unlock:
-+			spin_unlock_irqrestore(&irq_desc[i].lock, flags);
-+		}
-+	}
- 
- 	decode_address(buf, fp->rete);
- 	printk(KERN_NOTICE " RETE: %s\n", buf);
-@@ -708,9 +805,10 @@ void show_regs(struct pt_regs *fp)
- 	decode_address(buf, fp->rets);
- 	printk(KERN_NOTICE " RETS: %s\n", buf);
- 	decode_address(buf, fp->pc);
--	printk(KERN_NOTICE " PC: %s\n", buf);
-+	printk(KERN_NOTICE " PC  : %s\n", buf);
- 
--	if ((long)fp->seqstat & SEQSTAT_EXCAUSE) {
-+	if (((long)fp->seqstat &  SEQSTAT_EXCAUSE) &&
-+	    (((long)fp->seqstat & SEQSTAT_EXCAUSE) != VEC_HWERR)) {
- 		decode_address(buf, bfin_read_DCPLB_FAULT_ADDR());
- 		printk(KERN_NOTICE "DCPLB_FAULT_ADDR: %s\n", buf);
- 		decode_address(buf, bfin_read_ICPLB_FAULT_ADDR());
-@@ -824,7 +922,7 @@ void panic_cplb_error(int cplb_panic, struct pt_regs *fp)
- 	printk(KERN_EMERG "DCPLB_FAULT_ADDR=%p\n", (void *)bfin_read_DCPLB_FAULT_ADDR());
- 	printk(KERN_EMERG "ICPLB_FAULT_ADDR=%p\n", (void *)bfin_read_ICPLB_FAULT_ADDR());
- 	dump_bfin_process(fp);
--	dump_bfin_mem((void *)fp->retx);
-+	dump_bfin_mem(fp);
- 	show_regs(fp);
- 	dump_stack();
- 	panic("Unrecoverable event\n");
-diff --git a/arch/blackfin/lib/memcpy.S b/arch/blackfin/lib/memcpy.S
-index 2e63364..e654a18 100644
---- a/arch/blackfin/lib/memcpy.S
-+++ b/arch/blackfin/lib/memcpy.S
-@@ -70,8 +70,8 @@ ENTRY(_memcpy)
- 	/* Check for aligned data.*/
- 
- 	R3 = R1 | R0;
--	R0 = 0x3;
--	R3 = R3 & R0;
-+	R1 = 0x3;
-+	R3 = R3 & R1;
- 	CC = R3;	/* low bits set on either address? */
- 	IF CC JUMP .Lnot_aligned;
- 
-@@ -83,7 +83,6 @@ ENTRY(_memcpy)
- 	/* less than eight bytes... */
- 	P2 = R2;
- 	LSETUP(.Lthree_start, .Lthree_end) LC0=P2;
--	R0 = R1;	/* setup src address for return */
- .Lthree_start:
- 	R3 = B[P1++] (X);
- .Lthree_end:
-@@ -95,7 +94,6 @@ ENTRY(_memcpy)
- 	/* There's at least eight bytes to copy. */
- 	P2 += -1;	/* because we unroll one iteration */
- 	LSETUP(.Lword_loops, .Lword_loope) LC0=P2;
--	R0 = R1;
- 	I1 = P1;
- 	R3 = [I1++];
- #if ANOMALY_05000202
-@@ -120,7 +118,6 @@ ENTRY(_memcpy)
- .Lnot_aligned:
- 	/* From here, we're copying byte-by-byte. */
- 	LSETUP (.Lbyte_start, .Lbyte_end) LC0=P2;
--	R0 = R1;	/* Save src address for return */
- .Lbyte_start:
- 	R1 = B[P1++] (X);
- .Lbyte_end:
-@@ -135,7 +132,6 @@ ENTRY(_memcpy)
- 	 * Don't bother to work out alignment for
- 	 * the reverse case.
- 	 */
--	R0 = R1;	/* save src for later. */
- 	P0 = P0 + P2;
- 	P0 += -1;
- 	P1 = P1 + P2;
-diff --git a/arch/blackfin/mach-bf527/Kconfig b/arch/blackfin/mach-bf527/Kconfig
-index 5c73683..3cde4be 100644
---- a/arch/blackfin/mach-bf527/Kconfig
-+++ b/arch/blackfin/mach-bf527/Kconfig
-@@ -43,7 +43,7 @@ endchoice
- 
- choice
- 	prompt "UART1"
--	default BF527_UART1_PORTG
-+	default BF527_UART1_PORTF
- 	help
- 	  Select PORT used for UART1. See Hardware Reference Manual
- 
-diff --git a/arch/blackfin/mach-bf527/boards/ezkit.c b/arch/blackfin/mach-bf527/boards/ezkit.c
-index 003e2ac..f8c411a 100644
---- a/arch/blackfin/mach-bf527/boards/ezkit.c
-+++ b/arch/blackfin/mach-bf527/boards/ezkit.c
-@@ -8,7 +8,7 @@
-  *
-  * Modified:
-  *               Copyright 2005 National ICT Australia (NICTA)
-- *               Copyright 2004-2007 Analog Devices Inc.
-+ *               Copyright 2004-2008 Analog Devices Inc.
-  *
-  * Bugs:         Enter bugs at http://blackfin.uclinux.org/
-  *
-@@ -41,6 +41,7 @@
- #include <linux/irq.h>
- #include <linux/interrupt.h>
- #include <linux/usb/sl811.h>
-+#include <linux/usb/musb.h>
- #include <asm/cplb.h>
- #include <asm/dma.h>
- #include <asm/bfin5xx_spi.h>
-@@ -105,6 +106,69 @@ void __exit bfin_isp1761_exit(void)
- arch_initcall(bfin_isp1761_init);
- #endif
- 
-+#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_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
-+	.multipoint	= 0,
-+};
-+
-+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_FB_BFIN_T350MCQB) || defined(CONFIG_FB_BFIN_T350MCQB_MODULE)
-+
-+static struct resource bf52x_t350mcqb_resources[] = {
-+	{
-+		.start = IRQ_PPI_ERROR,
-+		.end = IRQ_PPI_ERROR,
-+		.flags = IORESOURCE_IRQ,
-+	},
-+};
-+
-+static struct platform_device bf52x_t350mcqb_device = {
-+	.name		= "bfin-t350mcqb",
-+	.id		= -1,
-+	.num_resources 	= ARRAY_SIZE(bf52x_t350mcqb_resources),
-+	.resource 	= bf52x_t350mcqb_resources,
-+};
-+#endif
-+
- #if defined(CONFIG_MTD_NAND_BF5XX) || defined(CONFIG_MTD_NAND_BF5XX_MODULE)
- static struct mtd_partition partition_info[] = {
- 	{
-@@ -253,12 +317,7 @@ static struct resource sl811_hcd_resources[] = {
- void sl811_port_power(struct device *dev, int is_on)
- {
- 	gpio_request(CONFIG_USB_SL811_BFIN_GPIO_VBUS, "usb:SL811_VBUS");
--	gpio_direction_output(CONFIG_USB_SL811_BFIN_GPIO_VBUS);
 -
--	if (is_on)
--		gpio_set_value(CONFIG_USB_SL811_BFIN_GPIO_VBUS, 1);
--	else
--		gpio_set_value(CONFIG_USB_SL811_BFIN_GPIO_VBUS, 0);
-+	gpio_direction_output(CONFIG_USB_SL811_BFIN_GPIO_VBUS, is_on);
- }
- #endif
- 
-@@ -718,6 +777,28 @@ static struct platform_device bfin_pata_device = {
- };
- #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 platform_device *stamp_devices[] __initdata = {
- #if defined(CONFIG_MTD_NAND_BF5XX) || defined(CONFIG_MTD_NAND_BF5XX_MODULE)
- 	&bf5xx_nand_device,
-@@ -739,6 +820,10 @@ static struct platform_device *stamp_devices[] __initdata = {
- 	&isp1362_hcd_device,
- #endif
- 
-+#if defined(CONFIG_USB_MUSB_HDRC) || defined(CONFIG_USB_MUSB_HDRC_MODULE)
-+	&musb_device,
-+#endif
-+
- #if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
- 	&smc91x_device,
- #endif
-@@ -763,6 +848,10 @@ static struct platform_device *stamp_devices[] __initdata = {
- 	&bfin_fb_device,
- #endif
- 
-+#if defined(CONFIG_FB_BFIN_T350MCQB) || defined(CONFIG_FB_BFIN_T350MCQB_MODULE)
-+	&bf52x_t350mcqb_device,
-+#endif
-+
- #if defined(CONFIG_FB_BFIN_7393) || defined(CONFIG_FB_BFIN_7393_MODULE)
- 	&bfin_fb_adv7393_device,
- #endif
-@@ -783,6 +872,10 @@ static struct platform_device *stamp_devices[] __initdata = {
- #if defined(CONFIG_PATA_PLATFORM) || defined(CONFIG_PATA_PLATFORM_MODULE)
- 	&bfin_pata_device,
- #endif
-+
-+#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
-+	&bfin_device_gpiokeys,
-+#endif
- };
- 
- static int __init stamp_init(void)
-diff --git a/arch/blackfin/mach-bf533/boards/H8606.c b/arch/blackfin/mach-bf533/boards/H8606.c
-index 6bcf404..a72c7a6 100644
---- a/arch/blackfin/mach-bf533/boards/H8606.c
-+++ b/arch/blackfin/mach-bf533/boards/H8606.c
-@@ -40,6 +40,7 @@
- #endif
- #include <linux/pata_platform.h>
- #include <linux/irq.h>
-+
- #include <asm/dma.h>
- #include <asm/bfin5xx_spi.h>
- #include <asm/reboot.h>
-@@ -303,7 +304,77 @@ static struct platform_device bfin_uart_device = {
- };
- #endif
- 
--static struct platform_device *stamp_devices[] __initdata = {
-+#if defined(CONFIG_SERIAL_8250) || defined(CONFIG_SERIAL_8250_MODULE)
-+
-+#include <linux/serial_8250.h>
-+#include <linux/serial.h>
-+
-+/*
-+ * Configuration for two 16550 UARTS in FPGA at addresses 0x20200000 and 0x202000010.
-+ * running at half system clock, both with interrupt output or-ed to PF8. Change to
-+ * suit different FPGA configuration, or to suit real 16550 UARTS connected to the bus
-+ */
-+
-+static struct plat_serial8250_port serial8250_platform_data [] = {
-+	{
-+		.membase = 0x20200000,
-+		.mapbase = 0x20200000,
-+		.irq = IRQ_PF8,
-+		.flags = UPF_BOOT_AUTOCONF | UART_CONFIG_TYPE,
-+		.iotype = UPIO_MEM,
-+		.regshift = 1,
-+		.uartclk = 66666667,
-+	}, {
-+		.membase = 0x20200010,
-+		.mapbase = 0x20200010,
-+		.irq = IRQ_PF8,
-+		.flags = UPF_BOOT_AUTOCONF | UART_CONFIG_TYPE,
-+		.iotype = UPIO_MEM,
-+		.regshift = 1,
-+		.uartclk = 66666667,
-+	}, {
-+	}
-+};
-+
-+static struct platform_device serial8250_device = {
-+	.id		= PLAT8250_DEV_PLATFORM,
-+	.name		= "serial8250",
-+	.dev		= {
-+		.platform_data = serial8250_platform_data,
-+	},
-+};
-+
-+#endif
-+
-+#if defined(CONFIG_KEYBOARD_OPENCORES) || defined(CONFIG_KEYBOARD_OPENCORES_MODULE)
-+
-+/*
-+ * Configuration for one OpenCores keyboard controller in FPGA at address 0x20200030,
-+ * interrupt output wired to PF9. Change to suit different FPGA configuration
-+ */
-+
-+static struct resource opencores_kbd_resources[] = {
-+	[0] = {
-+		.start	= 0x20200030,
-+		.end	= 0x20300030 + 2,
-+		.flags	= IORESOURCE_MEM,
-+	},
-+	[1] = {
-+		.start	= IRQ_PF9,
-+		.end	= IRQ_PF9,
-+		.flags	= IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE,
-+	},
-+};
-+
-+static struct platform_device opencores_kbd_device = {
-+	.id		= -1,
-+	.name		= "opencores-kbd",
-+	.resource	= opencores_kbd_resources,
-+	.num_resources	= ARRAY_SIZE(opencores_kbd_resources),
-+};
-+#endif
-+
-+static struct platform_device *h8606_devices[] __initdata = {
- #if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE)
- 	&rtc_device,
- #endif
-@@ -327,13 +398,21 @@ static struct platform_device *stamp_devices[] __initdata = {
- #if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
- 	&bfin_uart_device,
- #endif
-+
-+#if defined(CONFIG_SERIAL_8250) || defined(CONFIG_SERIAL_8250_MODULE)
-+	&serial8250_device,
-+#endif
-+
-+#if defined(CONFIG_KEYBOARD_OPENCORES) || defined(CONFIG_KEYBOARD_OPENCORES_MODULE)
-+	&opencores_kbd_device,
-+#endif
- };
- 
- static int __init H8606_init(void)
- {
- 	printk(KERN_INFO "HV Sistemas H8606 board support by http://www.hvsistemas.com\n");
- 	printk(KERN_INFO "%s(): registering device resources\n", __FUNCTION__);
--	platform_add_devices(stamp_devices, ARRAY_SIZE(stamp_devices));
-+	platform_add_devices(h8606_devices, ARRAY_SIZE(h8606_devices));
- #if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
- 	spi_register_board_info(bfin_spi_board_info, ARRAY_SIZE(bfin_spi_board_info));
- #endif
-diff --git a/arch/blackfin/mach-bf533/boards/ezkit.c b/arch/blackfin/mach-bf533/boards/ezkit.c
-index be85203..c37dd45 100644
---- a/arch/blackfin/mach-bf533/boards/ezkit.c
-+++ b/arch/blackfin/mach-bf533/boards/ezkit.c
-@@ -256,6 +256,50 @@ static struct platform_device bfin_pata_device = {
- };
- #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_PF7, 1, "gpio-keys: BTN0"},
-+	{BTN_1, GPIO_PF8, 1, "gpio-keys: BTN1"},
-+	{BTN_2, GPIO_PF9, 1, "gpio-keys: BTN2"},
-+	{BTN_3, GPIO_PF10, 1, "gpio-keys: BTN3"},
-+};
-+
-+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
-+
-+#if defined(CONFIG_I2C_GPIO) || defined(CONFIG_I2C_GPIO_MODULE)
-+#include <linux/i2c-gpio.h>
-+
-+static struct i2c_gpio_platform_data i2c_gpio_data = {
-+	.sda_pin		= 1,
-+	.scl_pin		= 0,
-+	.sda_is_open_drain	= 0,
-+	.scl_is_open_drain	= 0,
-+	.udelay			= 40,
-+};
-+
-+static struct platform_device i2c_gpio_device = {
-+	.name		= "i2c-gpio",
-+	.id		= 0,
-+	.dev		= {
-+		.platform_data	= &i2c_gpio_data,
-+	},
-+};
-+#endif
-+
- static struct platform_device *ezkit_devices[] __initdata = {
- #if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
- 	&smc91x_device,
-@@ -280,6 +324,14 @@ static struct platform_device *ezkit_devices[] __initdata = {
- #if defined(CONFIG_PATA_PLATFORM) || defined(CONFIG_PATA_PLATFORM_MODULE)
- 	&bfin_pata_device,
- #endif
-+
-+#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
-+	&bfin_device_gpiokeys,
-+#endif
-+
-+#if defined(CONFIG_I2C_GPIO) || defined(CONFIG_I2C_GPIO_MODULE)
-+	&i2c_gpio_device,
-+#endif
- };
- 
- static int __init ezkit_init(void)
-diff --git a/arch/blackfin/mach-bf533/boards/stamp.c b/arch/blackfin/mach-bf533/boards/stamp.c
-index 8fde8d8..ac52b04 100644
---- a/arch/blackfin/mach-bf533/boards/stamp.c
-+++ b/arch/blackfin/mach-bf533/boards/stamp.c
-@@ -32,6 +32,7 @@
- #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>
- #if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE)
-@@ -108,6 +109,50 @@ static struct platform_device net2272_bfin_device = {
- };
- #endif
- 
-+static struct mtd_partition stamp_partitions[] = {
-+	{
-+		.name   = "Bootloader",
-+		.size   = 0x20000,
-+		.offset = 0,
-+	}, {
-+		.name   = "Kernel",
-+		.size   = 0xE0000,
-+		.offset = MTDPART_OFS_APPEND,
-+	}, {
-+		.name   = "RootFS",
-+		.size   = MTDPART_SIZ_FULL,
-+		.offset = MTDPART_OFS_APPEND,
-+	}
-+};
-+
-+static struct physmap_flash_data stamp_flash_data = {
-+	.width    = 2,
-+	.parts    = stamp_partitions,
-+	.nr_parts = ARRAY_SIZE(stamp_partitions),
-+};
-+
-+static struct resource stamp_flash_resource[] = {
-+	{
-+		.name  = "cfi_probe",
-+		.start = 0x20000000,
-+		.end   = 0x203fffff,
-+		.flags = IORESOURCE_MEM,
-+	}, {
-+		.start = CONFIG_ENET_FLASH_PIN,
-+		.flags = IORESOURCE_IRQ,
-+	}
-+};
-+
-+static struct platform_device stamp_flash_device = {
-+	.name          = "BF5xx-Flash",
-+	.id            = 0,
-+	.dev = {
-+		.platform_data = &stamp_flash_data,
-+	},
-+	.num_resources = ARRAY_SIZE(stamp_flash_resource),
-+	.resource      = stamp_flash_resource,
-+};
-+
- #if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
- /* all SPI peripherals info goes here */
- 
-@@ -373,6 +418,49 @@ static struct platform_device bfin_pata_device = {
- };
- #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_PF5, 1, "gpio-keys: BTN0"},
-+	{BTN_1, GPIO_PF6, 1, "gpio-keys: BTN1"},
-+	{BTN_2, GPIO_PF8, 1, "gpio-keys: BTN2"},
-+};
-+
-+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
-+
-+#if defined(CONFIG_I2C_GPIO) || defined(CONFIG_I2C_GPIO_MODULE)
-+#include <linux/i2c-gpio.h>
-+
-+static struct i2c_gpio_platform_data i2c_gpio_data = {
-+	.sda_pin		= 2,
-+	.scl_pin		= 3,
-+	.sda_is_open_drain	= 0,
-+	.scl_is_open_drain	= 0,
-+	.udelay			= 40,
-+};
-+
-+static struct platform_device i2c_gpio_device = {
-+	.name		= "i2c-gpio",
-+	.id		= 0,
-+	.dev		= {
-+		.platform_data	= &i2c_gpio_data,
-+	},
-+};
-+#endif
-+
- static struct platform_device *stamp_devices[] __initdata = {
- #if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE)
- 	&rtc_device,
-@@ -406,6 +494,15 @@ static struct platform_device *stamp_devices[] __initdata = {
- #if defined(CONFIG_PATA_PLATFORM) || defined(CONFIG_PATA_PLATFORM_MODULE)
- 	&bfin_pata_device,
- #endif
-+
-+#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
-+	&bfin_device_gpiokeys,
-+#endif
-+
-+#if defined(CONFIG_I2C_GPIO) || defined(CONFIG_I2C_GPIO_MODULE)
-+	&i2c_gpio_device,
-+#endif
-+	&stamp_flash_device,
- };
- 
- static int __init stamp_init(void)
-@@ -418,12 +515,10 @@ static int __init stamp_init(void)
- 		return ret;
- 
- #if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
--# if defined(CONFIG_BFIN_SHARED_FLASH_ENET)
- 	/* setup BF533_STAMP CPLD to route AMS3 to Ethernet MAC */
- 	bfin_write_FIO_DIR(bfin_read_FIO_DIR() | (1 << CONFIG_ENET_FLASH_PIN));
- 	bfin_write_FIO_FLAG_S(1 << CONFIG_ENET_FLASH_PIN);
- 	SSYNC();
--# endif
- #endif
- 
- #if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
-@@ -440,10 +535,8 @@ arch_initcall(stamp_init);
- 
- void native_machine_restart(char *cmd)
- {
--#if defined(CONFIG_BFIN_SHARED_FLASH_ENET)
--# define BIT_TO_SET (1 << CONFIG_ENET_FLASH_PIN)
-+#define BIT_TO_SET (1 << CONFIG_ENET_FLASH_PIN)
- 	bfin_write_FIO_INEN(~BIT_TO_SET);
- 	bfin_write_FIO_DIR(BIT_TO_SET);
- 	bfin_write_FIO_FLAG_C(BIT_TO_SET);
+-	if (!MOUNT_ROOT_RDONLY)
+-		root_mountflags &= ~MS_RDONLY;
+-	init_mm.start_code = (unsigned long) _text;
+-	init_mm.end_code = (unsigned long) _etext;
+-	init_mm.end_data = (unsigned long) _edata;
+-	init_mm.brk = (unsigned long) _end;
+-
+-	code_resource.start = __pa(_text);
+-	code_resource.end = __pa(_etext)-1;
+-	data_resource.start = __pa(_etext);
+-	data_resource.end = __pa(_edata)-1;
+-
+-	parse_mem_cmdline(cmdline_p);
+-
+-	/*
+-	 * Find the lowest and highest page frame numbers we have available
+-	 */
+-	first_pfn = PFN_DOWN(memory_start);
+-	last_pfn = PFN_DOWN(memory_end);
+-	pages = last_pfn - first_pfn;
+-
+-	/*
+-	 * Partially used pages are not usable - thus
+-	 * we are rounding upwards:
+-	 */
+-	start_pfn = PFN_UP(__pa(_end));
+-
+-	/*
+-	 * Find a proper area for the bootmem bitmap. After this
+-	 * bootstrap step all allocations (until the page allocator
+-	 * is intact) must be done via bootmem_alloc().
+-	 */
+-	bootmap_size = init_bootmem_node(NODE_DATA(0), start_pfn,
+-					 first_pfn,
+-					 last_pfn);
+-        /*
+-         * Round it up.
+-         */
+-        bootmap_size = PFN_PHYS(PFN_UP(bootmap_size));
+-
+-	/*
+-	 * Register fully available RAM pages with the bootmem allocator.
+-	 */
+-	free_bootmem_node(NODE_DATA(0), PFN_PHYS(first_pfn), PFN_PHYS(pages));
+-
+-	/*
+-	 * Reserve all kernel sections + bootmem bitmap + a guard page.
+-	 */
+-	reserve_bootmem_node(NODE_DATA(0), PFN_PHYS(first_pfn),
+-		        (PFN_PHYS(start_pfn) + bootmap_size + PAGE_SIZE) - PFN_PHYS(first_pfn));
+-
+-	/*
+-	 * Reserve platform dependent sections
+-	 */
+-	platform_reserve();
+-
+-#ifdef CONFIG_BLK_DEV_INITRD
+-	if (LOADER_TYPE && INITRD_START) {
+-		if (INITRD_START + INITRD_SIZE <= (PFN_PHYS(last_pfn))) {
+-		        reserve_bootmem_node(NODE_DATA(0), INITRD_START + __MEMORY_START, INITRD_SIZE);
+-
+-			initrd_start = (long) INITRD_START + PAGE_OFFSET + __MEMORY_START;
+-			initrd_end = initrd_start + INITRD_SIZE;
+-		} else {
+-			printk("initrd extends beyond end of memory "
+-			    "(0x%08lx > 0x%08lx)\ndisabling initrd\n",
+-				    (long) INITRD_START + INITRD_SIZE,
+-				    PFN_PHYS(last_pfn));
+-			initrd_start = 0;
+-		}
+-	}
 -#endif
- }
-diff --git a/arch/blackfin/mach-bf537/boards/Kconfig b/arch/blackfin/mach-bf537/boards/Kconfig
-index 96a1519..7e789db 100644
---- a/arch/blackfin/mach-bf537/boards/Kconfig
-+++ b/arch/blackfin/mach-bf537/boards/Kconfig
-@@ -21,6 +21,12 @@ config PNAV10
- 	help
- 	  PNAV board support.
- 
-+config CAMSIG_MINOTAUR
-+	bool "Cambridge Signal Processing LTD Minotaur"
-+	depends on (BF537)
-+	help
-+	  Board supply package for CSP Minotaur
-+
- config GENERIC_BF537_BOARD
- 	bool "Generic"
- 	help
-diff --git a/arch/blackfin/mach-bf537/boards/Makefile b/arch/blackfin/mach-bf537/boards/Makefile
-index 94a8517..87e450f 100644
---- a/arch/blackfin/mach-bf537/boards/Makefile
-+++ b/arch/blackfin/mach-bf537/boards/Makefile
-@@ -6,3 +6,4 @@ obj-$(CONFIG_GENERIC_BF537_BOARD)      += generic_board.o
- obj-$(CONFIG_BFIN537_STAMP)            += stamp.o led.o
- obj-$(CONFIG_BFIN537_BLUETECHNIX_CM)   += cm_bf537.o
- obj-$(CONFIG_PNAV10)                   += pnav10.o
-+obj-$(CONFIG_CAMSIG_MINOTAUR)          += minotaur.o
-diff --git a/arch/blackfin/mach-bf537/boards/cm_bf537.c b/arch/blackfin/mach-bf537/boards/cm_bf537.c
-index c0fb06d..8703b67 100644
---- a/arch/blackfin/mach-bf537/boards/cm_bf537.c
-+++ b/arch/blackfin/mach-bf537/boards/cm_bf537.c
-@@ -29,6 +29,7 @@
-  */
- 
- #include <linux/device.h>
-+#include <linux/etherdevice.h>
- #include <linux/platform_device.h>
- #include <linux/mtd/mtd.h>
- #include <linux/mtd/partitions.h>
-@@ -216,6 +217,12 @@ static struct platform_device rtc_device = {
- };
- #endif
- 
-+#if defined(CONFIG_FB_HITACHI_TX09) || defined(CONFIG_FB_HITACHI_TX09_MODULE)
-+static struct platform_device hitachi_fb_device = {
-+	.name = "hitachi-tx09",
-+};
-+#endif
-+
- #if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
- static struct resource smc91x_resources[] = {
- 	{
-@@ -374,6 +381,10 @@ static struct platform_device bfin_pata_device = {
- #endif
- 
- static struct platform_device *cm_bf537_devices[] __initdata = {
-+#if defined(CONFIG_FB_HITACHI_TX09) || defined(CONFIG_FB_HITACHI_TX09_MODULE)
-+	&hitachi_fb_device,
-+#endif
-+
- #if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE)
- 	&rtc_device,
- #endif
-diff --git a/arch/blackfin/mach-bf537/boards/generic_board.c b/arch/blackfin/mach-bf537/boards/generic_board.c
-index 09f4bfb..3e52f3f 100644
---- a/arch/blackfin/mach-bf537/boards/generic_board.c
-+++ b/arch/blackfin/mach-bf537/boards/generic_board.c
-@@ -8,7 +8,7 @@
-  *
-  * Modified:
-  *               Copyright 2005 National ICT Australia (NICTA)
-- *               Copyright 2004-2007 Analog Devices Inc.
-+ *               Copyright 2004-2008 Analog Devices Inc.
-  *
-  * Bugs:         Enter bugs at http://blackfin.uclinux.org/
-  *
-@@ -29,6 +29,7 @@
-  */
- 
- #include <linux/device.h>
-+#include <linux/etherdevice.h>
- #include <linux/platform_device.h>
- #include <linux/mtd/mtd.h>
- #include <linux/mtd/partitions.h>
-@@ -204,12 +205,8 @@ static struct resource sl811_hcd_resources[] = {
- void sl811_port_power(struct device *dev, int is_on)
- {
- 	gpio_request(CONFIG_USB_SL811_BFIN_GPIO_VBUS, "usb:SL811_VBUS");
--	gpio_direction_output(CONFIG_USB_SL811_BFIN_GPIO_VBUS);
-+	gpio_direction_output(CONFIG_USB_SL811_BFIN_GPIO_VBUS, is_on);
- 
--	if (is_on)
--		gpio_set_value(CONFIG_USB_SL811_BFIN_GPIO_VBUS, 1);
+-
+-	/*
+-	 * Claim all RAM, ROM, and I/O resources.
+-	 */
+-
+-	/* Kernel RAM */
+-	request_resource(&iomem_resource, &code_resource);
+-	request_resource(&iomem_resource, &data_resource);
+-
+-	/* Other KRAM space */
+-	for (i = 0; i < STANDARD_KRAM_RESOURCES - 2; i++)
+-		request_resource(&iomem_resource,
+-				 &platform_parms.kram_res_p[i]);
+-
+-	/* XRAM space */
+-	for (i = 0; i < STANDARD_XRAM_RESOURCES; i++)
+-		request_resource(&iomem_resource,
+-				 &platform_parms.xram_res_p[i]);
+-
+-	/* ROM space */
+-	for (i = 0; i < STANDARD_ROM_RESOURCES; i++)
+-		request_resource(&iomem_resource,
+-				 &platform_parms.rom_res_p[i]);
+-
+-	/* I/O space */
+-	for (i = 0; i < STANDARD_IO_RESOURCES; i++)
+-		request_resource(&ioport_resource,
+-				 &platform_parms.io_res_p[i]);
+-
+-
+-#ifdef CONFIG_VT
+-#if defined(CONFIG_VGA_CONSOLE)
+-	conswitchp = &vga_con;
+-#elif defined(CONFIG_DUMMY_CONSOLE)
+-	conswitchp = &dummy_con;
+-#endif
+-#endif
+-
+-	printk("Hardware FPU: %s\n", fpu_in_use ? "enabled" : "disabled");
+-
+-	paging_init();
+-}
+-
+-void __xchg_called_with_bad_pointer(void)
+-{
+-	printk(KERN_EMERG "xchg() called with bad pointer !\n");
+-}
+-
+-static struct cpu cpu[1];
+-
+-static int __init topology_init(void)
+-{
+-	return register_cpu(cpu, 0);
+-}
+-
+-subsys_initcall(topology_init);
+-
+-/*
+- *	Get CPU information
+- */
+-static const char *cpu_name[] = {
+-	[CPU_SH5_101]	= "SH5-101",
+-	[CPU_SH5_103]	= "SH5-103",
+-	[CPU_SH_NONE]	= "Unknown",
+-};
+-
+-const char *get_cpu_subtype(void)
+-{
+-	return cpu_name[boot_cpu_data.type];
+-}
+-
+-#ifdef CONFIG_PROC_FS
+-static int show_cpuinfo(struct seq_file *m,void *v)
+-{
+-	unsigned int cpu = smp_processor_id();
+-
+-	if (!cpu)
+-		seq_printf(m, "machine\t\t: %s\n", get_system_type());
+-
+-	seq_printf(m, "processor\t: %d\n", cpu);
+-	seq_printf(m, "cpu family\t: SH-5\n");
+-	seq_printf(m, "cpu type\t: %s\n", get_cpu_subtype());
+-
+-	seq_printf(m, "icache size\t: %dK-bytes\n",
+-		   (boot_cpu_data.icache.ways *
+-		    boot_cpu_data.icache.sets *
+-		    boot_cpu_data.icache.linesz) >> 10);
+-	seq_printf(m, "dcache size\t: %dK-bytes\n",
+-		   (boot_cpu_data.dcache.ways *
+-		    boot_cpu_data.dcache.sets *
+-		    boot_cpu_data.dcache.linesz) >> 10);
+-	seq_printf(m, "itlb entries\t: %d\n", boot_cpu_data.itlb.entries);
+-	seq_printf(m, "dtlb entries\t: %d\n", boot_cpu_data.dtlb.entries);
+-
+-#define PRINT_CLOCK(name, value) \
+-	seq_printf(m, name " clock\t: %d.%02dMHz\n", \
+-		     ((value) / 1000000), ((value) % 1000000)/10000)
+-
+-	PRINT_CLOCK("cpu", boot_cpu_data.cpu_clock);
+-	PRINT_CLOCK("bus", boot_cpu_data.bus_clock);
+-	PRINT_CLOCK("module", boot_cpu_data.module_clock);
+-
+-        seq_printf(m, "bogomips\t: %lu.%02lu\n\n",
+-		     (loops_per_jiffy*HZ+2500)/500000,
+-		     ((loops_per_jiffy*HZ+2500)/5000) % 100);
+-
+-	return 0;
+-}
+-
+-static void *c_start(struct seq_file *m, loff_t *pos)
+-{
+-	return (void*)(*pos == 0);
+-}
+-static void *c_next(struct seq_file *m, void *v, loff_t *pos)
+-{
+-	return NULL;
+-}
+-static void c_stop(struct seq_file *m, void *v)
+-{
+-}
+-struct seq_operations cpuinfo_op = {
+-	.start	= c_start,
+-	.next	= c_next,
+-	.stop	= c_stop,
+-	.show	= show_cpuinfo,
+-};
+-#endif /* CONFIG_PROC_FS */
+diff --git a/arch/sh64/kernel/sh_ksyms.c b/arch/sh64/kernel/sh_ksyms.c
+deleted file mode 100644
+index b1705ac..0000000
+--- a/arch/sh64/kernel/sh_ksyms.c
++++ /dev/null
+@@ -1,62 +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.
+- *
+- * arch/sh64/kernel/sh_ksyms.c
+- *
+- * Copyright (C) 2000, 2001  Paolo Alberelli
+- *
+- */
+-
+-#include <linux/rwsem.h>
+-#include <linux/module.h>
+-#include <linux/smp.h>
+-#include <linux/user.h>
+-#include <linux/elfcore.h>
+-#include <linux/sched.h>
+-#include <linux/in6.h>
+-#include <linux/interrupt.h>
+-#include <linux/screen_info.h>
+-
+-#include <asm/semaphore.h>
+-#include <asm/processor.h>
+-#include <asm/uaccess.h>
+-#include <asm/checksum.h>
+-#include <asm/io.h>
+-#include <asm/delay.h>
+-#include <asm/irq.h>
+-
+-extern int dump_fpu(struct pt_regs *, elf_fpregset_t *);
+-
+-/* platform dependent support */
+-EXPORT_SYMBOL(dump_fpu);
+-EXPORT_SYMBOL(kernel_thread);
+-
+-/* Networking helper routines. */
+-EXPORT_SYMBOL(csum_partial_copy_nocheck);
+-
+-#ifdef CONFIG_VT
+-EXPORT_SYMBOL(screen_info);
+-#endif
+-
+-EXPORT_SYMBOL(__down);
+-EXPORT_SYMBOL(__down_trylock);
+-EXPORT_SYMBOL(__up);
+-EXPORT_SYMBOL(__put_user_asm_l);
+-EXPORT_SYMBOL(__get_user_asm_l);
+-EXPORT_SYMBOL(__copy_user);
+-EXPORT_SYMBOL(memcpy);
+-EXPORT_SYMBOL(udelay);
+-EXPORT_SYMBOL(__udelay);
+-EXPORT_SYMBOL(ndelay);
+-EXPORT_SYMBOL(__ndelay);
+-EXPORT_SYMBOL(flush_dcache_page);
+-EXPORT_SYMBOL(sh64_page_clear);
+-
+-/* Ugh.  These come in from libgcc.a at link time. */
+-#define DECLARE_EXPORT(name) extern void name(void);EXPORT_SYMBOL(name)
+-
+-DECLARE_EXPORT(__sdivsi3);
+-DECLARE_EXPORT(__muldi3);
+-DECLARE_EXPORT(__udivsi3);
+diff --git a/arch/sh64/kernel/signal.c b/arch/sh64/kernel/signal.c
+deleted file mode 100644
+index 79fc48c..0000000
+--- a/arch/sh64/kernel/signal.c
++++ /dev/null
+@@ -1,750 +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.
+- *
+- * arch/sh64/kernel/signal.c
+- *
+- * Copyright (C) 2000, 2001  Paolo Alberelli
+- * Copyright (C) 2003  Paul Mundt
+- * Copyright (C) 2004  Richard Curnow
+- *
+- * Started from sh version.
+- *
+- */
+-#include <linux/rwsem.h>
+-#include <linux/sched.h>
+-#include <linux/mm.h>
+-#include <linux/smp.h>
+-#include <linux/kernel.h>
+-#include <linux/signal.h>
+-#include <linux/errno.h>
+-#include <linux/wait.h>
+-#include <linux/personality.h>
+-#include <linux/freezer.h>
+-#include <linux/ptrace.h>
+-#include <linux/unistd.h>
+-#include <linux/stddef.h>
+-#include <asm/ucontext.h>
+-#include <asm/uaccess.h>
+-#include <asm/pgtable.h>
+-
+-
+-#define REG_RET 9
+-#define REG_ARG1 2
+-#define REG_ARG2 3
+-#define REG_ARG3 4
+-#define REG_SP 15
+-#define REG_PR 18
+-#define REF_REG_RET regs->regs[REG_RET]
+-#define REF_REG_SP regs->regs[REG_SP]
+-#define DEREF_REG_PR regs->regs[REG_PR]
+-
+-#define DEBUG_SIG 0
+-
+-#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
+-
+-asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset);
+-
+-/*
+- * Atomically swap in the new signal mask, and wait for a signal.
+- */
+-
+-asmlinkage int
+-sys_sigsuspend(old_sigset_t mask,
+-	       unsigned long r3, unsigned long r4, unsigned long r5,
+-	       unsigned long r6, unsigned long r7,
+-	       struct pt_regs * regs)
+-{
+-	sigset_t saveset;
+-
+-	mask &= _BLOCKABLE;
+-	spin_lock_irq(&current->sighand->siglock);
+-	saveset = current->blocked;
+-	siginitset(&current->blocked, mask);
+-	recalc_sigpending();
+-	spin_unlock_irq(&current->sighand->siglock);
+-
+-	REF_REG_RET = -EINTR;
+-	while (1) {
+-		current->state = TASK_INTERRUPTIBLE;
+-		schedule();
+-		regs->pc += 4;    /* because sys_sigreturn decrements the pc */
+-		if (do_signal(regs, &saveset)) {
+-			/* pc now points at signal handler. Need to decrement
+-			   it because entry.S will increment it. */
+-			regs->pc -= 4;
+-			return -EINTR;
+-		}
+-	}
+-}
+-
+-asmlinkage int
+-sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize,
+-	          unsigned long r4, unsigned long r5, unsigned long r6,
+-	          unsigned long r7,
+-	          struct pt_regs * regs)
+-{
+-	sigset_t saveset, newset;
+-
+-	/* XXX: Don't preclude handling different sized sigset_t's.  */
+-	if (sigsetsize != sizeof(sigset_t))
+-		return -EINVAL;
+-
+-	if (copy_from_user(&newset, unewset, sizeof(newset)))
+-		return -EFAULT;
+-	sigdelsetmask(&newset, ~_BLOCKABLE);
+-	spin_lock_irq(&current->sighand->siglock);
+-	saveset = current->blocked;
+-	current->blocked = newset;
+-	recalc_sigpending();
+-	spin_unlock_irq(&current->sighand->siglock);
+-
+-	REF_REG_RET = -EINTR;
+-	while (1) {
+-		current->state = TASK_INTERRUPTIBLE;
+-		schedule();
+-		regs->pc += 4;    /* because sys_sigreturn decrements the pc */
+-		if (do_signal(regs, &saveset)) {
+-			/* pc now points at signal handler. Need to decrement
+-			   it because entry.S will increment it. */
+-			regs->pc -= 4;
+-			return -EINTR;
+-		}
+-	}
+-}
+-
+-asmlinkage int
+-sys_sigaction(int sig, const struct old_sigaction __user *act,
+-	      struct old_sigaction __user *oact)
+-{
+-	struct k_sigaction new_ka, old_ka;
+-	int ret;
+-
+-	if (act) {
+-		old_sigset_t mask;
+-		if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
+-		    __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
+-		    __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
+-			return -EFAULT;
+-		__get_user(new_ka.sa.sa_flags, &act->sa_flags);
+-		__get_user(mask, &act->sa_mask);
+-		siginitset(&new_ka.sa.sa_mask, mask);
+-	}
+-
+-	ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
+-
+-	if (!ret && oact) {
+-		if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
+-		    __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
+-		    __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
+-			return -EFAULT;
+-		__put_user(old_ka.sa.sa_flags, &oact->sa_flags);
+-		__put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
+-	}
+-
+-	return ret;
+-}
+-
+-asmlinkage int
+-sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss,
+-	        unsigned long r4, unsigned long r5, unsigned long r6,
+-	        unsigned long r7,
+-	        struct pt_regs * regs)
+-{
+-	return do_sigaltstack(uss, uoss, REF_REG_SP);
+-}
+-
+-
+-/*
+- * Do a signal return; undo the signal stack.
+- */
+-
+-struct sigframe
+-{
+-	struct sigcontext sc;
+-	unsigned long extramask[_NSIG_WORDS-1];
+-	long long retcode[2];
+-};
+-
+-struct rt_sigframe
+-{
+-	struct siginfo __user *pinfo;
+-	void *puc;
+-	struct siginfo info;
+-	struct ucontext uc;
+-	long long retcode[2];
+-};
+-
+-#ifdef CONFIG_SH_FPU
+-static inline int
+-restore_sigcontext_fpu(struct pt_regs *regs, struct sigcontext __user *sc)
+-{
+-	int err = 0;
+-	int fpvalid;
+-
+-	err |= __get_user (fpvalid, &sc->sc_fpvalid);
+-	conditional_used_math(fpvalid);
+-	if (! fpvalid)
+-		return err;
+-
+-	if (current == last_task_used_math) {
+-		last_task_used_math = NULL;
+-		regs->sr |= SR_FD;
+-	}
+-
+-	err |= __copy_from_user(&current->thread.fpu.hard, &sc->sc_fpregs[0],
+-				(sizeof(long long) * 32) + (sizeof(int) * 1));
+-
+-	return err;
+-}
+-
+-static inline int
+-setup_sigcontext_fpu(struct pt_regs *regs, struct sigcontext __user *sc)
+-{
+-	int err = 0;
+-	int fpvalid;
+-
+-	fpvalid = !!used_math();
+-	err |= __put_user(fpvalid, &sc->sc_fpvalid);
+-	if (! fpvalid)
+-		return err;
+-
+-	if (current == last_task_used_math) {
+-		grab_fpu();
+-		fpsave(&current->thread.fpu.hard);
+-		release_fpu();
+-		last_task_used_math = NULL;
+-		regs->sr |= SR_FD;
+-	}
+-
+-	err |= __copy_to_user(&sc->sc_fpregs[0], &current->thread.fpu.hard,
+-			      (sizeof(long long) * 32) + (sizeof(int) * 1));
+-	clear_used_math();
+-
+-	return err;
+-}
+-#else
+-static inline int
+-restore_sigcontext_fpu(struct pt_regs *regs, struct sigcontext __user *sc)
+-{}
+-static inline int
+-setup_sigcontext_fpu(struct pt_regs *regs, struct sigcontext __user *sc)
+-{}
+-#endif
+-
+-static int
+-restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, long long *r2_p)
+-{
+-	unsigned int err = 0;
+-        unsigned long long current_sr, new_sr;
+-#define SR_MASK 0xffff8cfd
+-
+-#define COPY(x)		err |= __get_user(regs->x, &sc->sc_##x)
+-
+-	COPY(regs[0]);	COPY(regs[1]);	COPY(regs[2]);	COPY(regs[3]);
+-	COPY(regs[4]);	COPY(regs[5]);	COPY(regs[6]);	COPY(regs[7]);
+-	COPY(regs[8]);	COPY(regs[9]);  COPY(regs[10]);	COPY(regs[11]);
+-	COPY(regs[12]);	COPY(regs[13]);	COPY(regs[14]);	COPY(regs[15]);
+-	COPY(regs[16]);	COPY(regs[17]);	COPY(regs[18]);	COPY(regs[19]);
+-	COPY(regs[20]);	COPY(regs[21]);	COPY(regs[22]);	COPY(regs[23]);
+-	COPY(regs[24]);	COPY(regs[25]);	COPY(regs[26]);	COPY(regs[27]);
+-	COPY(regs[28]);	COPY(regs[29]);	COPY(regs[30]);	COPY(regs[31]);
+-	COPY(regs[32]);	COPY(regs[33]);	COPY(regs[34]);	COPY(regs[35]);
+-	COPY(regs[36]);	COPY(regs[37]);	COPY(regs[38]);	COPY(regs[39]);
+-	COPY(regs[40]);	COPY(regs[41]);	COPY(regs[42]);	COPY(regs[43]);
+-	COPY(regs[44]);	COPY(regs[45]);	COPY(regs[46]);	COPY(regs[47]);
+-	COPY(regs[48]);	COPY(regs[49]);	COPY(regs[50]);	COPY(regs[51]);
+-	COPY(regs[52]);	COPY(regs[53]);	COPY(regs[54]);	COPY(regs[55]);
+-	COPY(regs[56]);	COPY(regs[57]);	COPY(regs[58]);	COPY(regs[59]);
+-	COPY(regs[60]);	COPY(regs[61]);	COPY(regs[62]);
+-	COPY(tregs[0]);	COPY(tregs[1]);	COPY(tregs[2]);	COPY(tregs[3]);
+-	COPY(tregs[4]);	COPY(tregs[5]);	COPY(tregs[6]);	COPY(tregs[7]);
+-
+-        /* Prevent the signal handler manipulating SR in a way that can
+-           crash the kernel. i.e. only allow S, Q, M, PR, SZ, FR to be
+-           modified */
+-        current_sr = regs->sr;
+-        err |= __get_user(new_sr, &sc->sc_sr);
+-        regs->sr &= SR_MASK;
+-        regs->sr |= (new_sr & ~SR_MASK);
+-
+-	COPY(pc);
+-
+-#undef COPY
+-
+-	/* Must do this last in case it sets regs->sr.fd (i.e. after rest of sr
+-	 * has been restored above.) */
+-	err |= restore_sigcontext_fpu(regs, sc);
+-
+-	regs->syscall_nr = -1;		/* disable syscall checks */
+-	err |= __get_user(*r2_p, &sc->sc_regs[REG_RET]);
+-	return err;
+-}
+-
+-asmlinkage int sys_sigreturn(unsigned long r2, unsigned long r3,
+-				   unsigned long r4, unsigned long r5,
+-				   unsigned long r6, unsigned long r7,
+-				   struct pt_regs * regs)
+-{
+-	struct sigframe __user *frame = (struct sigframe __user *) (long) REF_REG_SP;
+-	sigset_t set;
+-	long long ret;
+-
+-	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
+-		goto badframe;
+-
+-	if (__get_user(set.sig[0], &frame->sc.oldmask)
+-	    || (_NSIG_WORDS > 1
+-		&& __copy_from_user(&set.sig[1], &frame->extramask,
+-				    sizeof(frame->extramask))))
+-		goto badframe;
+-
+-	sigdelsetmask(&set, ~_BLOCKABLE);
+-
+-	spin_lock_irq(&current->sighand->siglock);
+-	current->blocked = set;
+-	recalc_sigpending();
+-	spin_unlock_irq(&current->sighand->siglock);
+-
+-	if (restore_sigcontext(regs, &frame->sc, &ret))
+-		goto badframe;
+-	regs->pc -= 4;
+-
+-	return (int) ret;
+-
+-badframe:
+-	force_sig(SIGSEGV, current);
+-	return 0;
+-}
+-
+-asmlinkage int sys_rt_sigreturn(unsigned long r2, unsigned long r3,
+-				unsigned long r4, unsigned long r5,
+-				unsigned long r6, unsigned long r7,
+-				struct pt_regs * regs)
+-{
+-	struct rt_sigframe __user *frame = (struct rt_sigframe __user *) (long) REF_REG_SP;
+-	sigset_t set;
+-	stack_t __user st;
+-	long long ret;
+-
+-	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
+-		goto badframe;
+-
+-	if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
+-		goto badframe;
+-
+-	sigdelsetmask(&set, ~_BLOCKABLE);
+-	spin_lock_irq(&current->sighand->siglock);
+-	current->blocked = set;
+-	recalc_sigpending();
+-	spin_unlock_irq(&current->sighand->siglock);
+-
+-	if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &ret))
+-		goto badframe;
+-	regs->pc -= 4;
+-
+-	if (__copy_from_user(&st, &frame->uc.uc_stack, sizeof(st)))
+-		goto badframe;
+-	/* It is more difficult to avoid calling this function than to
+-	   call it and ignore errors.  */
+-	do_sigaltstack(&st, NULL, REF_REG_SP);
+-
+-	return (int) ret;
+-
+-badframe:
+-	force_sig(SIGSEGV, current);
+-	return 0;
+-}
+-
+-/*
+- * Set up a signal frame.
+- */
+-
+-static int
+-setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs,
+-		 unsigned long mask)
+-{
+-	int err = 0;
+-
+-	/* Do this first, otherwise is this sets sr->fd, that value isn't preserved. */
+-	err |= setup_sigcontext_fpu(regs, sc);
+-
+-#define COPY(x)		err |= __put_user(regs->x, &sc->sc_##x)
+-
+-	COPY(regs[0]);	COPY(regs[1]);	COPY(regs[2]);	COPY(regs[3]);
+-	COPY(regs[4]);	COPY(regs[5]);	COPY(regs[6]);	COPY(regs[7]);
+-	COPY(regs[8]);	COPY(regs[9]);	COPY(regs[10]);	COPY(regs[11]);
+-	COPY(regs[12]);	COPY(regs[13]);	COPY(regs[14]);	COPY(regs[15]);
+-	COPY(regs[16]);	COPY(regs[17]);	COPY(regs[18]);	COPY(regs[19]);
+-	COPY(regs[20]);	COPY(regs[21]);	COPY(regs[22]);	COPY(regs[23]);
+-	COPY(regs[24]);	COPY(regs[25]);	COPY(regs[26]);	COPY(regs[27]);
+-	COPY(regs[28]);	COPY(regs[29]);	COPY(regs[30]);	COPY(regs[31]);
+-	COPY(regs[32]);	COPY(regs[33]);	COPY(regs[34]);	COPY(regs[35]);
+-	COPY(regs[36]);	COPY(regs[37]);	COPY(regs[38]);	COPY(regs[39]);
+-	COPY(regs[40]);	COPY(regs[41]);	COPY(regs[42]);	COPY(regs[43]);
+-	COPY(regs[44]);	COPY(regs[45]);	COPY(regs[46]);	COPY(regs[47]);
+-	COPY(regs[48]);	COPY(regs[49]);	COPY(regs[50]);	COPY(regs[51]);
+-	COPY(regs[52]);	COPY(regs[53]);	COPY(regs[54]);	COPY(regs[55]);
+-	COPY(regs[56]);	COPY(regs[57]);	COPY(regs[58]);	COPY(regs[59]);
+-	COPY(regs[60]);	COPY(regs[61]);	COPY(regs[62]);
+-	COPY(tregs[0]);	COPY(tregs[1]);	COPY(tregs[2]);	COPY(tregs[3]);
+-	COPY(tregs[4]);	COPY(tregs[5]);	COPY(tregs[6]);	COPY(tregs[7]);
+-	COPY(sr);	COPY(pc);
+-
+-#undef COPY
+-
+-	err |= __put_user(mask, &sc->oldmask);
+-
+-	return err;
+-}
+-
+-/*
+- * Determine which stack to use..
+- */
+-static inline void __user *
+-get_sigframe(struct k_sigaction *ka, unsigned long sp, size_t frame_size)
+-{
+-	if ((ka->sa.sa_flags & SA_ONSTACK) != 0 && ! sas_ss_flags(sp))
+-		sp = current->sas_ss_sp + current->sas_ss_size;
+-
+-	return (void __user *)((sp - frame_size) & -8ul);
+-}
+-
+-void sa_default_restorer(void);		/* See comments below */
+-void sa_default_rt_restorer(void);	/* See comments below */
+-
+-static void setup_frame(int sig, struct k_sigaction *ka,
+-			sigset_t *set, struct pt_regs *regs)
+-{
+-	struct sigframe __user *frame;
+-	int err = 0;
+-	int signal;
+-
+-	frame = get_sigframe(ka, regs->regs[REG_SP], sizeof(*frame));
+-
+-	if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
+-		goto give_sigsegv;
+-
+-	signal = current_thread_info()->exec_domain
+-		&& current_thread_info()->exec_domain->signal_invmap
+-		&& sig < 32
+-		? current_thread_info()->exec_domain->signal_invmap[sig]
+-		: sig;
+-
+-	err |= setup_sigcontext(&frame->sc, regs, set->sig[0]);
+-
+-	/* Give up earlier as i386, in case */
+-	if (err)
+-		goto give_sigsegv;
+-
+-	if (_NSIG_WORDS > 1) {
+-		err |= __copy_to_user(frame->extramask, &set->sig[1],
+-				      sizeof(frame->extramask)); }
+-
+-	/* Give up earlier as i386, in case */
+-	if (err)
+-		goto give_sigsegv;
+-
+-	/* Set up to return from userspace.  If provided, use a stub
+-	   already in userspace.  */
+-	if (ka->sa.sa_flags & SA_RESTORER) {
+-		DEREF_REG_PR = (unsigned long) ka->sa.sa_restorer | 0x1;
+-
+-		/*
+-		 * On SH5 all edited pointers are subject to NEFF
+-		 */
+-		DEREF_REG_PR = (DEREF_REG_PR & NEFF_SIGN) ?
+-        		 	(DEREF_REG_PR | NEFF_MASK) : DEREF_REG_PR;
+-	} else {
+-		/*
+-		 * Different approach on SH5.
+-	         * . Endianness independent asm code gets placed in entry.S .
+-		 *   This is limited to four ASM instructions corresponding
+-		 *   to two long longs in size.
+-		 * . err checking is done on the else branch only
+-		 * . flush_icache_range() is called upon __put_user() only
+-		 * . all edited pointers are subject to NEFF
+-		 * . being code, linker turns ShMedia bit on, always
+-		 *   dereference index -1.
+-		 */
+-		DEREF_REG_PR = (unsigned long) frame->retcode | 0x01;
+-		DEREF_REG_PR = (DEREF_REG_PR & NEFF_SIGN) ?
+-        		 	(DEREF_REG_PR | NEFF_MASK) : DEREF_REG_PR;
+-
+-		if (__copy_to_user(frame->retcode,
+-			(unsigned long long)sa_default_restorer & (~1), 16) != 0)
+-			goto give_sigsegv;
+-
+-		/* Cohere the trampoline with the I-cache. */
+-		flush_cache_sigtramp(DEREF_REG_PR-1, DEREF_REG_PR-1+16);
+-	}
+-
+-	/*
+-	 * Set up registers for signal handler.
+-	 * All edited pointers are subject to NEFF.
+-	 */
+-	regs->regs[REG_SP] = (unsigned long) frame;
+-	regs->regs[REG_SP] = (regs->regs[REG_SP] & NEFF_SIGN) ?
+-        		 (regs->regs[REG_SP] | NEFF_MASK) : regs->regs[REG_SP];
+-	regs->regs[REG_ARG1] = signal; /* Arg for signal handler */
+-
+-        /* FIXME:
+-           The glibc profiling support for SH-5 needs to be passed a sigcontext
+-           so it can retrieve the PC.  At some point during 2003 the glibc
+-           support was changed to receive the sigcontext through the 2nd
+-           argument, but there are still versions of libc.so in use that use
+-           the 3rd argument.  Until libc.so is stabilised, pass the sigcontext
+-           through both 2nd and 3rd arguments.
+-        */
+-
+-	regs->regs[REG_ARG2] = (unsigned long long)(unsigned long)(signed long)&frame->sc;
+-	regs->regs[REG_ARG3] = (unsigned long long)(unsigned long)(signed long)&frame->sc;
+-
+-	regs->pc = (unsigned long) ka->sa.sa_handler;
+-	regs->pc = (regs->pc & NEFF_SIGN) ? (regs->pc | NEFF_MASK) : regs->pc;
+-
+-	set_fs(USER_DS);
+-
+-#if DEBUG_SIG
+-	/* Broken %016Lx */
+-	printk("SIG deliver (#%d,%s:%d): sp=%p pc=%08Lx%08Lx link=%08Lx%08Lx\n",
+-		signal,
+-		current->comm, current->pid, frame,
+-		regs->pc >> 32, regs->pc & 0xffffffff,
+-		DEREF_REG_PR >> 32, DEREF_REG_PR & 0xffffffff);
+-#endif
+-
+-	return;
+-
+-give_sigsegv:
+-	force_sigsegv(sig, current);
+-}
+-
+-static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
+-			   sigset_t *set, struct pt_regs *regs)
+-{
+-	struct rt_sigframe __user *frame;
+-	int err = 0;
+-	int signal;
+-
+-	frame = get_sigframe(ka, regs->regs[REG_SP], sizeof(*frame));
+-
+-	if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
+-		goto give_sigsegv;
+-
+-	signal = 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(&frame->info, &frame->pinfo);
+-	err |= __put_user(&frame->uc, &frame->puc);
+-	err |= copy_siginfo_to_user(&frame->info, info);
+-
+-	/* Give up earlier as i386, in case */
+-	if (err)
+-		goto give_sigsegv;
+-
+-	/* Create the ucontext.  */
+-	err |= __put_user(0, &frame->uc.uc_flags);
+-	err |= __put_user(0, &frame->uc.uc_link);
+-	err |= __put_user((void *)current->sas_ss_sp,
+-			  &frame->uc.uc_stack.ss_sp);
+-	err |= __put_user(sas_ss_flags(regs->regs[REG_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,
+-			        regs, set->sig[0]);
+-	err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
+-
+-	/* Give up earlier as i386, in case */
+-	if (err)
+-		goto give_sigsegv;
+-
+-	/* Set up to return from userspace.  If provided, use a stub
+-	   already in userspace.  */
+-	if (ka->sa.sa_flags & SA_RESTORER) {
+-		DEREF_REG_PR = (unsigned long) ka->sa.sa_restorer | 0x1;
+-
+-		/*
+-		 * On SH5 all edited pointers are subject to NEFF
+-		 */
+-		DEREF_REG_PR = (DEREF_REG_PR & NEFF_SIGN) ?
+-        		 	(DEREF_REG_PR | NEFF_MASK) : DEREF_REG_PR;
+-	} else {
+-		/*
+-		 * Different approach on SH5.
+-	         * . Endianness independent asm code gets placed in entry.S .
+-		 *   This is limited to four ASM instructions corresponding
+-		 *   to two long longs in size.
+-		 * . err checking is done on the else branch only
+-		 * . flush_icache_range() is called upon __put_user() only
+-		 * . all edited pointers are subject to NEFF
+-		 * . being code, linker turns ShMedia bit on, always
+-		 *   dereference index -1.
+-		 */
+-
+-		DEREF_REG_PR = (unsigned long) frame->retcode | 0x01;
+-		DEREF_REG_PR = (DEREF_REG_PR & NEFF_SIGN) ?
+-        		 	(DEREF_REG_PR | NEFF_MASK) : DEREF_REG_PR;
+-
+-		if (__copy_to_user(frame->retcode,
+-			(unsigned long long)sa_default_rt_restorer & (~1), 16) != 0)
+-			goto give_sigsegv;
+-
+-		flush_icache_range(DEREF_REG_PR-1, DEREF_REG_PR-1+15);
+-	}
+-
+-	/*
+-	 * Set up registers for signal handler.
+-	 * All edited pointers are subject to NEFF.
+-	 */
+-	regs->regs[REG_SP] = (unsigned long) frame;
+-	regs->regs[REG_SP] = (regs->regs[REG_SP] & NEFF_SIGN) ?
+-        		 (regs->regs[REG_SP] | NEFF_MASK) : regs->regs[REG_SP];
+-	regs->regs[REG_ARG1] = signal; /* Arg for signal handler */
+-	regs->regs[REG_ARG2] = (unsigned long long)(unsigned long)(signed long)&frame->info;
+-	regs->regs[REG_ARG3] = (unsigned long long)(unsigned long)(signed long)&frame->uc.uc_mcontext;
+-	regs->pc = (unsigned long) ka->sa.sa_handler;
+-	regs->pc = (regs->pc & NEFF_SIGN) ? (regs->pc | NEFF_MASK) : regs->pc;
+-
+-	set_fs(USER_DS);
+-
+-#if DEBUG_SIG
+-	/* Broken %016Lx */
+-	printk("SIG deliver (#%d,%s:%d): sp=%p pc=%08Lx%08Lx link=%08Lx%08Lx\n",
+-		signal,
+-		current->comm, current->pid, frame,
+-		regs->pc >> 32, regs->pc & 0xffffffff,
+-		DEREF_REG_PR >> 32, DEREF_REG_PR & 0xffffffff);
+-#endif
+-
+-	return;
+-
+-give_sigsegv:
+-	force_sigsegv(sig, current);
+-}
+-
+-/*
+- * OK, we're invoking a handler
+- */
+-
+-static void
+-handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
+-		sigset_t *oldset, struct pt_regs * regs)
+-{
+-	/* Are we from a system call? */
+-	if (regs->syscall_nr >= 0) {
+-		/* If so, check system call restarting.. */
+-		switch (regs->regs[REG_RET]) {
+-			case -ERESTART_RESTARTBLOCK:
+-			case -ERESTARTNOHAND:
+-				regs->regs[REG_RET] = -EINTR;
+-				break;
+-
+-			case -ERESTARTSYS:
+-				if (!(ka->sa.sa_flags & SA_RESTART)) {
+-					regs->regs[REG_RET] = -EINTR;
+-					break;
+-				}
+-			/* fallthrough */
+-			case -ERESTARTNOINTR:
+-				/* Decode syscall # */
+-				regs->regs[REG_RET] = regs->syscall_nr;
+-				regs->pc -= 4;
+-		}
+-	}
+-
+-	/* Set up the stack frame */
+-	if (ka->sa.sa_flags & SA_SIGINFO)
+-		setup_rt_frame(sig, ka, info, oldset, regs);
 -	else
--		gpio_set_value(CONFIG_USB_SL811_BFIN_GPIO_VBUS, 0);
- }
- #endif
- 
-@@ -733,9 +730,11 @@ void native_machine_restart(char *cmd)
- 		bfin_gpio_reset_spi0_ssel1();
- }
- 
-+#if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
- void bfin_get_ether_addr(char *addr)
- {
- 	random_ether_addr(addr);
- 	printk(KERN_WARNING "%s:%s: Setting Ethernet MAC to a random one\n", __FILE__, __func__);
- }
- EXPORT_SYMBOL(bfin_get_ether_addr);
-+#endif
-diff --git a/arch/blackfin/mach-bf537/boards/minotaur.c b/arch/blackfin/mach-bf537/boards/minotaur.c
-new file mode 100644
-index 0000000..b8bbba8
---- /dev/null
-+++ b/arch/blackfin/mach-bf537/boards/minotaur.c
-@@ -0,0 +1,317 @@
-+/*
-+ */
-+
-+#include <linux/device.h>
-+#include <linux/platform_device.h>
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/partitions.h>
-+#include <linux/spi/spi.h>
-+#include <linux/spi/flash.h>
-+#if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE)
-+#include <linux/usb_isp1362.h>
-+#endif
-+#include <linux/pata_platform.h>
-+#include <linux/irq.h>
-+#include <linux/interrupt.h>
-+#include <linux/usb_sl811.h>
-+#include <asm/dma.h>
-+#include <asm/bfin5xx_spi.h>
-+#include <asm/reboot.h>
-+#include <linux/spi/ad7877.h>
-+
-+/*
-+ * Name the Board for the /proc/cpuinfo
-+ */
-+char *bfin_board_name = "CamSig Minotaur BF537";
-+
-+#if defined(CONFIG_BFIN_CFPCMCIA) || defined(CONFIG_BFIN_CFPCMCIA_MODULE)
-+static struct resource bfin_pcmcia_cf_resources[] = {
-+	{
-+		.start = 0x20310000, /* IO PORT */
-+		.end = 0x20312000,
-+		.flags = IORESOURCE_MEM,
-+	}, {
-+		.start = 0x20311000, /* Attribute Memory */
-+		.end = 0x20311FFF,
-+		.flags = IORESOURCE_MEM,
-+	}, {
-+		.start = IRQ_PF4,
-+		.end = IRQ_PF4,
-+		.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL,
-+	}, {
-+		.start = IRQ_PF6, /* Card Detect PF6 */
-+		.end = IRQ_PF6,
-+		.flags = IORESOURCE_IRQ,
-+	},
-+};
-+
-+static struct platform_device bfin_pcmcia_cf_device = {
-+	.name = "bfin_cf_pcmcia",
-+	.id = -1,
-+	.num_resources = ARRAY_SIZE(bfin_pcmcia_cf_resources),
-+	.resource = bfin_pcmcia_cf_resources,
-+};
-+#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_USB_NET2272) || defined(CONFIG_USB_NET2272_MODULE)
-+static struct resource net2272_bfin_resources[] = {
-+	{
-+		.start = 0x20300000,
-+		.end = 0x20300000 + 0x100,
-+		.flags = IORESOURCE_MEM,
-+	}, {
-+		.start = IRQ_PF7,
-+		.end = IRQ_PF7,
-+		.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
-+	},
-+};
-+
-+static struct platform_device net2272_bfin_device = {
-+	.name = "net2272",
-+	.id = -1,
-+	.num_resources = ARRAY_SIZE(net2272_bfin_resources),
-+	.resource = net2272_bfin_resources,
-+};
-+#endif
-+
-+#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
-+/* all SPI peripherals info goes here */
-+
-+#if defined(CONFIG_MTD_M25P80) \
-+	|| defined(CONFIG_MTD_M25P80_MODULE)
-+
-+/* Partition sizes */
-+#define FLASH_SIZE       0x00400000
-+#define PSIZE_UBOOT      0x00030000
-+#define PSIZE_INITRAMFS  0x00240000
-+
-+static struct mtd_partition bfin_spi_flash_partitions[] = {
-+	{
-+		.name       = "uboot",
-+		.size       = PSIZE_UBOOT,
-+		.offset     = 0x000000,
-+		.mask_flags = MTD_CAP_ROM
-+	}, {
-+		.name       = "initramfs",
-+		.size       = PSIZE_INITRAMFS,
-+		.offset     = PSIZE_UBOOT
-+	}, {
-+		.name       = "opt",
-+		.size       = FLASH_SIZE - (PSIZE_UBOOT + PSIZE_INITRAMFS),
-+		.offset     = PSIZE_UBOOT + PSIZE_INITRAMFS,
-+	}
-+};
-+
-+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 = "m25p64",
-+};
-+
-+/* 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_MMC) || defined(CONFIG_SPI_MMC_MODULE)
-+static struct bfin5xx_spi_chip spi_mmc_chip_info = {
-+	.enable_dma = 1,
-+	.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_MMC) || defined(CONFIG_SPI_MMC_MODULE)
-+	{
-+		.modalias = "spi_mmc_dummy",
-+		.max_speed_hz = 5000000,     /* 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 = 5000000,     /* 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
-+};
-+
-+/* 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 */
-+};
-+
-+/* 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[] = {
-+	{
-+		.start = 0xFFC00400,
-+		.end = 0xFFC004FF,
-+		.flags = IORESOURCE_MEM,
-+	}, {
-+		.start = 0xFFC02000,
-+		.end = 0xFFC020FF,
-+		.flags = IORESOURCE_MEM,
-+	},
-+};
-+
-+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_I2C_BLACKFIN_TWI) || defined(CONFIG_I2C_BLACKFIN_TWI_MODULE)
-+static struct resource bfin_twi0_resource[] = {
-+	[0] = {
-+		.start = TWI0_REGBASE,
-+		.end   = TWI0_REGBASE + 0xFF,
-+		.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
-+
-+#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
-+
-+static struct platform_device *minotaur_devices[] __initdata = {
-+#if defined(CONFIG_BFIN_CFPCMCIA) || defined(CONFIG_BFIN_CFPCMCIA_MODULE)
-+	&bfin_pcmcia_cf_device,
-+#endif
-+
-+#if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE)
-+	&rtc_device,
-+#endif
-+
-+#if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
-+	&bfin_mac_device,
-+#endif
-+
-+#if defined(CONFIG_USB_NET2272) || defined(CONFIG_USB_NET2272_MODULE)
-+	&net2272_bfin_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_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
-+
-+};
-+
-+static int __init minotaur_init(void)
-+{
-+	printk(KERN_INFO "%s(): registering device resources\n", __FUNCTION__);
-+	platform_add_devices(minotaur_devices, ARRAY_SIZE(minotaur_devices));
-+#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
-+	spi_register_board_info(bfin_spi_board_info,
-+				ARRAY_SIZE(bfin_spi_board_info));
-+#endif
-+
-+	return 0;
-+}
-+
-+arch_initcall(minotaur_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();
-+}
-diff --git a/arch/blackfin/mach-bf537/boards/pnav10.c b/arch/blackfin/mach-bf537/boards/pnav10.c
-index fd5f4a6..509a8a2 100644
---- a/arch/blackfin/mach-bf537/boards/pnav10.c
-+++ b/arch/blackfin/mach-bf537/boards/pnav10.c
-@@ -8,7 +8,7 @@
-  *
-  * Modified:
-  *               Copyright 2005 National ICT Australia (NICTA)
-- *               Copyright 2004-2006 Analog Devices Inc.
-+ *               Copyright 2004-2008 Analog Devices Inc.
-  *
-  * Bugs:         Enter bugs at http://blackfin.uclinux.org/
-  *
-@@ -29,6 +29,7 @@
-  */
- 
- #include <linux/device.h>
-+#include <linux/etherdevice.h>
- #include <linux/platform_device.h>
- #include <linux/mtd/mtd.h>
- #include <linux/mtd/partitions.h>
-@@ -133,12 +134,8 @@ static struct resource sl811_hcd_resources[] = {
- void sl811_port_power(struct device *dev, int is_on)
- {
- 	gpio_request(CONFIG_USB_SL811_BFIN_GPIO_VBUS, "usb:SL811_VBUS");
--	gpio_direction_output(CONFIG_USB_SL811_BFIN_GPIO_VBUS);
-+	gpio_direction_output(CONFIG_USB_SL811_BFIN_GPIO_VBUS, is_on);
- 
--	if (is_on)
--		gpio_set_value(CONFIG_USB_SL811_BFIN_GPIO_VBUS, 1);
+-		setup_frame(sig, ka, oldset, regs);
+-
+-	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);
+-}
+-
+-/*
+- * Note that 'init' is a special process: it doesn't get signals it doesn't
+- * want to handle. Thus you cannot kill init even with a SIGKILL even by
+- * mistake.
+- *
+- * Note that we go through the signals twice: once to check the signals that
+- * the kernel can handle, and then we build all the user-level signal handling
+- * stack-frames in one go after that.
+- */
+-int do_signal(struct pt_regs *regs, sigset_t *oldset)
+-{
+-	siginfo_t info;
+-	int signr;
+-	struct k_sigaction ka;
+-
+-	/*
+-	 * We want the common case to go fast, which
+-	 * is why we may in certain cases get here from
+-	 * kernel mode. Just return without doing anything
+-	 * if so.
+-	 */
+-	if (!user_mode(regs))
+-		return 1;
+-
+-	if (try_to_freeze())
+-		goto no_signal;
+-
+-	if (test_thread_flag(TIF_RESTORE_SIGMASK))
+-		oldset = &current->saved_sigmask;
+-	else if (!oldset)
+-		oldset = &current->blocked;
+-
+-	signr = get_signal_to_deliver(&info, &ka, regs, 0);
+-
+-	if (signr > 0) {
+-		/* Whee!  Actually deliver the signal.  */
+-		handle_signal(signr, &info, &ka, oldset, regs);
+-
+-		/*
+-		 * If a signal was successfully delivered, the saved sigmask
+-		 * is in its frame, and we can clear the TIF_RESTORE_SIGMASK
+-		 * flag.
+-		 */
+-		if (test_thread_flag(TIF_RESTORE_SIGMASK))
+-			clear_thread_flag(TIF_RESTORE_SIGMASK);
+-
+-		return 1;
+-	}
+-
+-no_signal:
+-	/* Did we come from a system call? */
+-	if (regs->syscall_nr >= 0) {
+-		/* Restart the system call - no handlers present */
+-		switch (regs->regs[REG_RET]) {
+-		case -ERESTARTNOHAND:
+-		case -ERESTARTSYS:
+-		case -ERESTARTNOINTR:
+-			/* Decode Syscall # */
+-			regs->regs[REG_RET] = regs->syscall_nr;
+-			regs->pc -= 4;
+-			break;
+-
+-		case -ERESTART_RESTARTBLOCK:
+-			regs->regs[REG_RET] = __NR_restart_syscall;
+-			regs->pc -= 4;
+-			break;
+-		}
+-	}
+-
+-	/* No signal to deliver -- put the saved sigmask back */
+-	if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
+-		clear_thread_flag(TIF_RESTORE_SIGMASK);
+-		sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
+-	}
+-
+-	return 0;
+-}
+diff --git a/arch/sh64/kernel/switchto.S b/arch/sh64/kernel/switchto.S
+deleted file mode 100644
+index 45b2d90..0000000
+--- a/arch/sh64/kernel/switchto.S
++++ /dev/null
+@@ -1,198 +0,0 @@
+-/*
+- * arch/sh64/kernel/switchto.S
+- *
+- * sh64 context switch
+- *
+- * Copyright (C) 2004  Richard Curnow
+- *
+- * 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.
+-*/
+-
+-	.section .text..SHmedia32,"ax"
+-	.little
+-
+-	.balign 32
+-
+-	.type sh64_switch_to, at function
+-	.global sh64_switch_to
+-	.global __sh64_switch_to_end
+-sh64_switch_to:
+-
+-/* Incoming args
+-   r2 - prev
+-   r3 - &prev->thread
+-   r4 - next
+-   r5 - &next->thread
+-
+-   Outgoing results
+-   r2 - last (=prev) : this just stays in r2 throughout
+-
+-   Want to create a full (struct pt_regs) on the stack to allow backtracing
+-   functions to work.  However, we only need to populate the callee-save
+-   register slots in this structure; since we're a function our ancestors must
+-   have themselves preserved all caller saved state in the stack.  This saves
+-   some wasted effort since we won't need to look at the values.
+-
+-   In particular, all caller-save registers are immediately available for
+-   scratch use.
+-
+-*/
+-
+-#define FRAME_SIZE (76*8 + 8)
+-
+-	movi	FRAME_SIZE, r0
+-	sub.l	r15, r0, r15
+-	! Do normal-style register save to support backtrace
+-
+-	st.l	r15,   0, r18	! save link reg
+-	st.l	r15,   4, r14	! save fp
+-	add.l	r15, r63, r14	! setup frame pointer
+-
+-	! hopefully this looks normal to the backtrace now.
+-
+-	addi.l	r15,   8, r1    ! base of pt_regs
+-	addi.l	r1,   24, r0    ! base of pt_regs.regs
+-	addi.l	r0, (63*8), r8	! base of pt_regs.trregs
+-
+-	/* Note : to be fixed?
+-	   struct pt_regs is really designed for holding the state on entry
+-	   to an exception, i.e. pc,sr,regs etc.  However, for the context
+-	   switch state, some of this is not required.  But the unwinder takes
+-	   struct pt_regs * as an arg so we have to build this structure
+-	   to allow unwinding switched tasks in show_state() */
+-
+-	st.q	r0, ( 9*8), r9
+-	st.q	r0, (10*8), r10
+-	st.q	r0, (11*8), r11
+-	st.q	r0, (12*8), r12
+-	st.q	r0, (13*8), r13
+-	st.q	r0, (14*8), r14 ! for unwind, want to look as though we took a trap at
+-	! the point where the process is left in suspended animation, i.e. current
+-	! fp here, not the saved one.
+-	st.q	r0, (16*8), r16
+-
+-	st.q	r0, (24*8), r24
+-	st.q	r0, (25*8), r25
+-	st.q	r0, (26*8), r26
+-	st.q	r0, (27*8), r27
+-	st.q	r0, (28*8), r28
+-	st.q	r0, (29*8), r29
+-	st.q	r0, (30*8), r30
+-	st.q	r0, (31*8), r31
+-	st.q	r0, (32*8), r32
+-	st.q	r0, (33*8), r33
+-	st.q	r0, (34*8), r34
+-	st.q	r0, (35*8), r35
+-
+-	st.q	r0, (44*8), r44
+-	st.q	r0, (45*8), r45
+-	st.q	r0, (46*8), r46
+-	st.q	r0, (47*8), r47
+-	st.q	r0, (48*8), r48
+-	st.q	r0, (49*8), r49
+-	st.q	r0, (50*8), r50
+-	st.q	r0, (51*8), r51
+-	st.q	r0, (52*8), r52
+-	st.q	r0, (53*8), r53
+-	st.q	r0, (54*8), r54
+-	st.q	r0, (55*8), r55
+-	st.q	r0, (56*8), r56
+-	st.q	r0, (57*8), r57
+-	st.q	r0, (58*8), r58
+-	st.q	r0, (59*8), r59
+-
+-	! do this early as pta->gettr has no pipeline forwarding (=> 5 cycle latency)
+-	! Use a local label to avoid creating a symbol that will confuse the !
+-	! backtrace
+-	pta	.Lsave_pc, tr0
+-
+-	gettr	tr5, r45
+-	gettr	tr6, r46
+-	gettr	tr7, r47
+-	st.q	r8, (5*8), r45
+-	st.q	r8, (6*8), r46
+-	st.q	r8, (7*8), r47
+-
+-	! Now switch context
+-	gettr	tr0, r9
+-	st.l	r3, 0, r15	! prev->thread.sp
+-	st.l	r3, 8, r1	! prev->thread.kregs
+-	st.l	r3, 4, r9	! prev->thread.pc
+-	st.q	r1, 0, r9	! save prev->thread.pc into pt_regs->pc
+-
+-	! Load PC for next task (init value or save_pc later)
+-	ld.l	r5, 4, r18	! next->thread.pc
+-	! Switch stacks
+-	ld.l	r5, 0, r15	! next->thread.sp
+-	ptabs	r18, tr0
+-
+-	! Update current
+-	ld.l	r4, 4, r9	! next->thread_info (2nd element of next task_struct)
+-	putcon	r9, kcr0	! current = next->thread_info
+-
+-	! go to save_pc for a reschedule, or the initial thread.pc for a new process
+-	blink	tr0, r63
+-
+-	! Restore (when we come back to a previously saved task)
+-.Lsave_pc:
+-	addi.l	r15, 32, r0	! r0 = next's regs
+-	addi.l	r0, (63*8), r8	! r8 = next's tr_regs
+-
+-	ld.q	r8, (5*8), r45
+-	ld.q	r8, (6*8), r46
+-	ld.q	r8, (7*8), r47
+-	ptabs	r45, tr5
+-	ptabs	r46, tr6
+-	ptabs	r47, tr7
+-
+-	ld.q	r0, ( 9*8), r9
+-	ld.q	r0, (10*8), r10
+-	ld.q	r0, (11*8), r11
+-	ld.q	r0, (12*8), r12
+-	ld.q	r0, (13*8), r13
+-	ld.q	r0, (14*8), r14
+-	ld.q	r0, (16*8), r16
+-
+-	ld.q	r0, (24*8), r24
+-	ld.q	r0, (25*8), r25
+-	ld.q	r0, (26*8), r26
+-	ld.q	r0, (27*8), r27
+-	ld.q	r0, (28*8), r28
+-	ld.q	r0, (29*8), r29
+-	ld.q	r0, (30*8), r30
+-	ld.q	r0, (31*8), r31
+-	ld.q	r0, (32*8), r32
+-	ld.q	r0, (33*8), r33
+-	ld.q	r0, (34*8), r34
+-	ld.q	r0, (35*8), r35
+-
+-	ld.q	r0, (44*8), r44
+-	ld.q	r0, (45*8), r45
+-	ld.q	r0, (46*8), r46
+-	ld.q	r0, (47*8), r47
+-	ld.q	r0, (48*8), r48
+-	ld.q	r0, (49*8), r49
+-	ld.q	r0, (50*8), r50
+-	ld.q	r0, (51*8), r51
+-	ld.q	r0, (52*8), r52
+-	ld.q	r0, (53*8), r53
+-	ld.q	r0, (54*8), r54
+-	ld.q	r0, (55*8), r55
+-	ld.q	r0, (56*8), r56
+-	ld.q	r0, (57*8), r57
+-	ld.q	r0, (58*8), r58
+-	ld.q	r0, (59*8), r59
+-
+-	! epilogue
+-	ld.l	r15, 0, r18
+-	ld.l	r15, 4, r14
+-	ptabs	r18, tr0
+-	movi	FRAME_SIZE, r0
+-	add	r15, r0, r15
+-	blink	tr0, r63
+-__sh64_switch_to_end:
+-.LFE1:
+-	.size	sh64_switch_to,.LFE1-sh64_switch_to
+-
+diff --git a/arch/sh64/kernel/sys_sh64.c b/arch/sh64/kernel/sys_sh64.c
+deleted file mode 100644
+index de0a303..0000000
+--- a/arch/sh64/kernel/sys_sh64.c
++++ /dev/null
+@@ -1,304 +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.
+- *
+- * arch/sh64/kernel/sys_sh64.c
+- *
+- * Copyright (C) 2000, 2001  Paolo Alberelli
+- *
+- * This file contains various random system calls that
+- * have a non-standard calling sequence on the Linux/SH5
+- * platform.
+- *
+- * Mostly taken from i386 version.
+- *
+- */
+-
+-#include <linux/errno.h>
+-#include <linux/rwsem.h>
+-#include <linux/sched.h>
+-#include <linux/mm.h>
+-#include <linux/fs.h>
+-#include <linux/smp.h>
+-#include <linux/sem.h>
+-#include <linux/msg.h>
+-#include <linux/shm.h>
+-#include <linux/stat.h>
+-#include <linux/mman.h>
+-#include <linux/file.h>
+-#include <linux/utsname.h>
+-#include <linux/syscalls.h>
+-#include <linux/ipc.h>
+-#include <asm/uaccess.h>
+-#include <asm/ptrace.h>
+-#include <asm/unistd.h>
+-
+-#define REG_3	3
+-
+-/*
+- * sys_pipe() is the normal C calling standard for creating
+- * a pipe. It's not the way Unix traditionally does this, though.
+- */
+-#ifdef NEW_PIPE_IMPLEMENTATION
+-asmlinkage int sys_pipe(unsigned long * fildes,
+-			unsigned long   dummy_r3,
+-			unsigned long   dummy_r4,
+-			unsigned long   dummy_r5,
+-			unsigned long   dummy_r6,
+-			unsigned long   dummy_r7,
+-			struct pt_regs * regs)	   /* r8 = pt_regs  forced by entry.S */
+-{
+-	int fd[2];
+-	int ret;
+-
+-	ret = do_pipe(fd);
+-	if (ret == 0)
+-		/*
+-		 ***********************************************************************
+-		 *   To avoid the copy_to_user we prefer to break the ABIs convention, *
+-		 *   packing the valid pair of file IDs into a single register (r3);   *
+-		 *   while r2 is the return code as defined by the sh5-ABIs.	       *
+-		 *   BE CAREFUL: pipe stub, into glibc, must be aware of this solution *
+-		 ***********************************************************************
+-
+-#ifdef __LITTLE_ENDIAN__
+-		regs->regs[REG_3] = (((unsigned long long) fd[1]) << 32) | ((unsigned long long) fd[0]);
+-#else
+-		regs->regs[REG_3] = (((unsigned long long) fd[0]) << 32) | ((unsigned long long) fd[1]);
+-#endif
+-
+-		*/
+-	       /* although not very clever this is endianess independent */
+-		regs->regs[REG_3] = (unsigned long long) *((unsigned long long *) fd);
+-
+-	return ret;
+-}
+-
+-#else
+-asmlinkage int sys_pipe(unsigned long * fildes)
+-{
+-        int fd[2];
+-        int error;
+-
+-        error = do_pipe(fd);
+-        if (!error) {
+-                if (copy_to_user(fildes, fd, 2*sizeof(int)))
+-                        error = -EFAULT;
+-        }
+-        return error;
+-}
+-
+-#endif
+-
+-/*
+- * To avoid cache alias, we map the shard page with same color.
+- */
+-#define COLOUR_ALIGN(addr)	(((addr)+SHMLBA-1)&~(SHMLBA-1))
+-
+-unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr,
+-	unsigned long len, unsigned long pgoff, unsigned long flags)
+-{
+-	struct vm_area_struct *vma;
+-
+-	if (flags & MAP_FIXED) {
+-		/* We do not accept a shared mapping if it would violate
+-		 * cache aliasing constraints.
+-		 */
+-		if ((flags & MAP_SHARED) && (addr & (SHMLBA - 1)))
+-			return -EINVAL;
+-		return addr;
+-	}
+-
+-	if (len > TASK_SIZE)
+-		return -ENOMEM;
+-	if (!addr)
+-		addr = TASK_UNMAPPED_BASE;
+-
+-	if (flags & MAP_PRIVATE)
+-		addr = PAGE_ALIGN(addr);
 -	else
--		gpio_set_value(CONFIG_USB_SL811_BFIN_GPIO_VBUS, 0);
- }
- #endif
- 
-diff --git a/arch/blackfin/mach-bf537/boards/stamp.c b/arch/blackfin/mach-bf537/boards/stamp.c
-index 07b0dc2..7725415 100644
---- a/arch/blackfin/mach-bf537/boards/stamp.c
-+++ b/arch/blackfin/mach-bf537/boards/stamp.c
-@@ -32,6 +32,7 @@
- #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>
- #if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE)
-@@ -103,6 +104,30 @@ void __exit bfin_isp1761_exit(void)
- arch_initcall(bfin_isp1761_init);
- #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_PF2, 1, "gpio-keys: BTN0"},
-+	{BTN_1, GPIO_PF3, 1, "gpio-keys: BTN1"},
-+	{BTN_2, GPIO_PF4, 1, "gpio-keys: BTN2"},
-+	{BTN_3, GPIO_PF5, 1, "gpio-keys: BTN3"},
-+};
-+
-+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
-+
- #if defined(CONFIG_BFIN_CFPCMCIA) || defined(CONFIG_BFIN_CFPCMCIA_MODULE)
- static struct resource bfin_pcmcia_cf_resources[] = {
- 	{
-@@ -226,12 +251,7 @@ static struct resource sl811_hcd_resources[] = {
- void sl811_port_power(struct device *dev, int is_on)
- {
- 	gpio_request(CONFIG_USB_SL811_BFIN_GPIO_VBUS, "usb:SL811_VBUS");
--	gpio_direction_output(CONFIG_USB_SL811_BFIN_GPIO_VBUS);
+-		addr = COLOUR_ALIGN(addr);
+-
+-	for (vma = find_vma(current->mm, addr); ; vma = vma->vm_next) {
+-		/* At this point:  (!vma || addr < vma->vm_end). */
+-		if (TASK_SIZE - len < addr)
+-			return -ENOMEM;
+-		if (!vma || addr + len <= vma->vm_start)
+-			return addr;
+-		addr = vma->vm_end;
+-		if (!(flags & MAP_PRIVATE))
+-			addr = COLOUR_ALIGN(addr);
+-	}
+-}
+-
+-/* common code for old and new mmaps */
+-static inline long do_mmap2(
+-	unsigned long addr, unsigned long len,
+-	unsigned long prot, unsigned long flags,
+-	unsigned long fd, unsigned long pgoff)
+-{
+-	int error = -EBADF;
+-	struct file * file = NULL;
+-
+-	flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
+-	if (!(flags & MAP_ANONYMOUS)) {
+-		file = fget(fd);
+-		if (!file)
+-			goto out;
+-	}
+-
+-	down_write(&current->mm->mmap_sem);
+-	error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
+-	up_write(&current->mm->mmap_sem);
+-
+-	if (file)
+-		fput(file);
+-out:
+-	return error;
+-}
+-
+-asmlinkage long sys_mmap2(unsigned long addr, unsigned long len,
+-	unsigned long prot, unsigned long flags,
+-	unsigned long fd, unsigned long pgoff)
+-{
+-	return do_mmap2(addr, len, prot, flags, fd, pgoff);
+-}
+-
+-asmlinkage int old_mmap(unsigned long addr, unsigned long len,
+-	unsigned long prot, unsigned long flags,
+-	int fd, unsigned long off)
+-{
+-	if (off & ~PAGE_MASK)
+-		return -EINVAL;
+-	return do_mmap2(addr, len, prot, flags, fd, off>>PAGE_SHIFT);
+-}
+-
+-/*
+- * sys_ipc() is the de-multiplexer for the SysV IPC calls..
+- *
+- * This is really horribly ugly.
+- */
+-asmlinkage int sys_ipc(uint call, int first, int second,
+-		       int third, void __user *ptr, long fifth)
+-{
+-	int version, ret;
+-
+-	version = call >> 16; /* hack for backward compatibility */
+-	call &= 0xffff;
+-
+-	if (call <= SEMCTL)
+-		switch (call) {
+-		case SEMOP:
+-			return sys_semtimedop(first, (struct sembuf __user *)ptr,
+-					      second, NULL);
+-		case SEMTIMEDOP:
+-			return sys_semtimedop(first, (struct sembuf __user *)ptr,
+-					      second,
+-					      (const struct timespec __user *)fifth);
+-		case SEMGET:
+-			return sys_semget (first, second, third);
+-		case SEMCTL: {
+-			union semun fourth;
+-			if (!ptr)
+-				return -EINVAL;
+-			if (get_user(fourth.__pad, (void * __user *) ptr))
+-				return -EFAULT;
+-			return sys_semctl (first, second, third, fourth);
+-			}
+-		default:
+-			return -EINVAL;
+-		}
+-
+-	if (call <= MSGCTL)
+-		switch (call) {
+-		case MSGSND:
+-			return sys_msgsnd (first, (struct msgbuf __user *) ptr,
+-					  second, third);
+-		case MSGRCV:
+-			switch (version) {
+-			case 0: {
+-				struct ipc_kludge tmp;
+-				if (!ptr)
+-					return -EINVAL;
+-
+-				if (copy_from_user(&tmp,
+-						   (struct ipc_kludge __user *) ptr,
+-						   sizeof (tmp)))
+-					return -EFAULT;
+-				return sys_msgrcv (first, tmp.msgp, second,
+-						   tmp.msgtyp, third);
+-				}
+-			default:
+-				return sys_msgrcv (first,
+-						   (struct msgbuf __user *) ptr,
+-						   second, fifth, third);
+-			}
+-		case MSGGET:
+-			return sys_msgget ((key_t) first, second);
+-		case MSGCTL:
+-			return sys_msgctl (first, second,
+-					   (struct msqid_ds __user *) ptr);
+-		default:
+-			return -EINVAL;
+-		}
+-	if (call <= SHMCTL)
+-		switch (call) {
+-		case SHMAT:
+-			switch (version) {
+-			default: {
+-				ulong raddr;
+-				ret = do_shmat (first, (char __user *) ptr,
+-						 second, &raddr);
+-				if (ret)
+-					return ret;
+-				return put_user (raddr, (ulong __user *) third);
+-			}
+-			case 1:	/* iBCS2 emulator entry point */
+-				if (!segment_eq(get_fs(), get_ds()))
+-					return -EINVAL;
+-				return do_shmat (first, (char __user *) ptr,
+-						  second, (ulong *) third);
+-			}
+-		case SHMDT:
+-			return sys_shmdt ((char __user *)ptr);
+-		case SHMGET:
+-			return sys_shmget (first, second, third);
+-		case SHMCTL:
+-			return sys_shmctl (first, second,
+-					   (struct shmid_ds __user *) ptr);
+-		default:
+-			return -EINVAL;
+-		}
+-
+-	return -EINVAL;
+-}
+-
+-asmlinkage int sys_uname(struct old_utsname * name)
+-{
+-	int err;
+-	if (!name)
+-		return -EFAULT;
+-	down_read(&uts_sem);
+-	err = copy_to_user(name, utsname(), sizeof (*name));
+-	up_read(&uts_sem);
+-	return err?-EFAULT:0;
+-}
+-
+-/*
+- * Do a system call from kernel instead of calling sys_execve so we
+- * end up with proper pt_regs.
+- */
+-int kernel_execve(const char *filename, char *const argv[], char *const envp[])
+-{
+-	register unsigned long __sc0 __asm__ ("r9") = ((0x13 << 16) | __NR_execve);
+-	register unsigned long __sc2 __asm__ ("r2") = (unsigned long) filename;
+-	register unsigned long __sc3 __asm__ ("r3") = (unsigned long) argv;
+-	register unsigned long __sc4 __asm__ ("r4") = (unsigned long) envp;
+-	__asm__ __volatile__ ("trapa	%1 !\t\t\t execve(%2,%3,%4)"
+-	: "=r" (__sc0)
+-	: "r" (__sc0), "r" (__sc2), "r" (__sc3), "r" (__sc4) );
+-	__asm__ __volatile__ ("!dummy	%0 %1 %2 %3"
+-	: : "r" (__sc0), "r" (__sc2), "r" (__sc3), "r" (__sc4) : "memory");
+-	return __sc0;
+-}
+diff --git a/arch/sh64/kernel/syscalls.S b/arch/sh64/kernel/syscalls.S
+deleted file mode 100644
+index abb94c0..0000000
+--- a/arch/sh64/kernel/syscalls.S
++++ /dev/null
+@@ -1,381 +0,0 @@
+-/*
+- * arch/sh64/kernel/syscalls.S
+- *
+- * Copyright (C) 2000, 2001  Paolo Alberelli
+- * Copyright (C) 2004 - 2007  Paul Mundt
+- * Copyright (C) 2003, 2004 Richard Curnow
+- *
+- * 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/sys.h>
+-
+-	.section .data, "aw"
+-	.balign 32
+-
+-/*
+- * System calls jump table
+- */
+-	.globl  sys_call_table
+-sys_call_table:
+-	.long sys_restart_syscall	/* 0  -  old "setup()" system call  */
+-	.long sys_exit
+-	.long sys_fork
+-	.long sys_read
+-	.long sys_write
+-	.long sys_open			/* 5 */
+-	.long sys_close
+-	.long sys_waitpid
+-	.long sys_creat
+-	.long sys_link
+-	.long sys_unlink		/* 10 */
+-	.long sys_execve
+-	.long sys_chdir
+-	.long sys_time
+-	.long sys_mknod
+-	.long sys_chmod			/* 15 */
+-	.long sys_lchown16
+-	.long sys_ni_syscall	/* old break syscall holder */
+-	.long sys_stat
+-	.long sys_lseek
+-	.long sys_getpid		/* 20 */
+-	.long sys_mount
+-	.long sys_oldumount
+-	.long sys_setuid16
+-	.long sys_getuid16
+-	.long sys_stime			/* 25 */
+-	.long sh64_ptrace
+-	.long sys_alarm
+-	.long sys_fstat
+-	.long sys_pause
+-	.long sys_utime			/* 30 */
+-	.long sys_ni_syscall	/* old stty syscall holder */
+-	.long sys_ni_syscall	/* old gtty syscall holder */
+-	.long sys_access
+-	.long sys_nice
+-	.long sys_ni_syscall		/* 35 */ /* old ftime syscall holder */
+-	.long sys_sync
+-	.long sys_kill
+-	.long sys_rename
+-	.long sys_mkdir
+-	.long sys_rmdir			/* 40 */
+-	.long sys_dup
+-	.long sys_pipe
+-	.long sys_times
+-	.long sys_ni_syscall	/* old prof syscall holder */
+-	.long sys_brk			/* 45 */
+-	.long sys_setgid16
+-	.long sys_getgid16
+-	.long sys_signal
+-	.long sys_geteuid16
+-	.long sys_getegid16		/* 50 */
+-	.long sys_acct
+-	.long sys_umount		/* recycled never used phys( */
+-	.long sys_ni_syscall	/* old lock syscall holder */
+-	.long sys_ioctl
+-	.long sys_fcntl			/* 55 */
+-	.long sys_ni_syscall	/* old mpx syscall holder */
+-	.long sys_setpgid
+-	.long sys_ni_syscall	/* old ulimit syscall holder */
+-	.long sys_ni_syscall	/* sys_olduname */
+-	.long sys_umask			/* 60 */
+-	.long sys_chroot
+-	.long sys_ustat
+-	.long sys_dup2
+-	.long sys_getppid
+-	.long sys_getpgrp		/* 65 */
+-	.long sys_setsid
+-	.long sys_sigaction
+-	.long sys_sgetmask
+-	.long sys_ssetmask
+-	.long sys_setreuid16		/* 70 */
+-	.long sys_setregid16
+-	.long sys_sigsuspend
+-	.long sys_sigpending
+-	.long sys_sethostname
+-	.long sys_setrlimit		/* 75 */
+-	.long sys_old_getrlimit
+-	.long sys_getrusage
+-	.long sys_gettimeofday
+-	.long sys_settimeofday
+-	.long sys_getgroups16		/* 80 */
+-	.long sys_setgroups16
+-	.long sys_ni_syscall	/* sys_oldselect */
+-	.long sys_symlink
+-	.long sys_lstat
+-	.long sys_readlink		/* 85 */
+-	.long sys_uselib
+-	.long sys_swapon
+-	.long sys_reboot
+-	.long old_readdir
+-	.long old_mmap			/* 90 */
+-	.long sys_munmap
+-	.long sys_truncate
+-	.long sys_ftruncate
+-	.long sys_fchmod
+-	.long sys_fchown16		/* 95 */
+-	.long sys_getpriority
+-	.long sys_setpriority
+-	.long sys_ni_syscall	/* old profil syscall holder */
+-	.long sys_statfs
+-	.long sys_fstatfs		/* 100 */
+-	.long sys_ni_syscall	/* ioperm */
+-	.long sys_socketcall	/* Obsolete implementation of socket syscall */
+-	.long sys_syslog
+-	.long sys_setitimer
+-	.long sys_getitimer		/* 105 */
+-	.long sys_newstat
+-	.long sys_newlstat
+-	.long sys_newfstat
+-	.long sys_uname
+-	.long sys_ni_syscall		/* 110 */ /* iopl */
+-	.long sys_vhangup
+-	.long sys_ni_syscall	/* idle */
+-	.long sys_ni_syscall	/* vm86old */
+-	.long sys_wait4
+-	.long sys_swapoff		/* 115 */
+-	.long sys_sysinfo
+-	.long sys_ipc		/* Obsolete ipc syscall implementation */
+-	.long sys_fsync
+-	.long sys_sigreturn
+-	.long sys_clone			/* 120 */
+-	.long sys_setdomainname
+-	.long sys_newuname
+-	.long sys_ni_syscall	/* sys_modify_ldt */
+-	.long sys_adjtimex
+-	.long sys_mprotect		/* 125 */
+-	.long sys_sigprocmask
+-	.long sys_ni_syscall		/* old "create_module" */
+-	.long sys_init_module
+-	.long sys_delete_module
+-	.long sys_ni_syscall		/* 130: old "get_kernel_syms" */
+-	.long sys_quotactl
+-	.long sys_getpgid
+-	.long sys_fchdir
+-	.long sys_bdflush
+-	.long sys_sysfs			/* 135 */
+-	.long sys_personality
+-	.long sys_ni_syscall	/* for afs_syscall */
+-	.long sys_setfsuid16
+-	.long sys_setfsgid16
+-	.long sys_llseek		/* 140 */
+-	.long sys_getdents
+-	.long sys_select
+-	.long sys_flock
+-	.long sys_msync
+-	.long sys_readv			/* 145 */
+-	.long sys_writev
+-	.long sys_getsid
+-	.long sys_fdatasync
+-	.long sys_sysctl
+-	.long sys_mlock			/* 150 */
+-	.long sys_munlock
+-	.long sys_mlockall
+-	.long sys_munlockall
+-	.long sys_sched_setparam
+-	.long sys_sched_getparam	/* 155 */
+-	.long sys_sched_setscheduler
+-	.long sys_sched_getscheduler
+-	.long sys_sched_yield
+-	.long sys_sched_get_priority_max
+-	.long sys_sched_get_priority_min  /* 160 */
+-	.long sys_sched_rr_get_interval
+-	.long sys_nanosleep
+-	.long sys_mremap
+-	.long sys_setresuid16
+-	.long sys_getresuid16		/* 165 */
+-	.long sys_ni_syscall	/* vm86 */
+-	.long sys_ni_syscall	/* old "query_module" */
+-	.long sys_poll
+-	.long sys_nfsservctl
+-	.long sys_setresgid16		/* 170 */
+-	.long sys_getresgid16
+-	.long sys_prctl
+-	.long sys_rt_sigreturn
+-	.long sys_rt_sigaction
+-	.long sys_rt_sigprocmask	/* 175 */
+-	.long sys_rt_sigpending
+-	.long sys_rt_sigtimedwait
+-	.long sys_rt_sigqueueinfo
+-	.long sys_rt_sigsuspend
+-	.long sys_pread64		/* 180 */
+-	.long sys_pwrite64
+-	.long sys_chown16
+-	.long sys_getcwd
+-	.long sys_capget
+-	.long sys_capset		/* 185 */
+-	.long sys_sigaltstack
+-	.long sys_sendfile
+-	.long sys_ni_syscall	/* streams1 */
+-	.long sys_ni_syscall	/* streams2 */
+-	.long sys_vfork			/* 190 */
+-	.long sys_getrlimit
+-	.long sys_mmap2
+-	.long sys_truncate64
+-	.long sys_ftruncate64
+-	.long sys_stat64		/* 195 */
+-	.long sys_lstat64
+-	.long sys_fstat64
+-	.long sys_lchown
+-	.long sys_getuid
+-	.long sys_getgid		/* 200 */
+-	.long sys_geteuid
+-	.long sys_getegid
+-	.long sys_setreuid
+-	.long sys_setregid
+-	.long sys_getgroups		/* 205 */
+-	.long sys_setgroups
+-	.long sys_fchown
+-	.long sys_setresuid
+-	.long sys_getresuid
+-	.long sys_setresgid		/* 210 */
+-	.long sys_getresgid
+-	.long sys_chown
+-	.long sys_setuid
+-	.long sys_setgid
+-	.long sys_setfsuid		/* 215 */
+-	.long sys_setfsgid
+-	.long sys_pivot_root
+-	.long sys_mincore
+-	.long sys_madvise
+-	/* Broken-out socket family (maintain backwards compatibility in syscall
+-	   numbering with 2.4) */
+-	.long sys_socket		/* 220 */
+-	.long sys_bind
+-	.long sys_connect
+-	.long sys_listen
+-	.long sys_accept
+-	.long sys_getsockname		/* 225 */
+-	.long sys_getpeername
+-	.long sys_socketpair
+-	.long sys_send
+-	.long sys_sendto
+-	.long sys_recv			/* 230*/
+-	.long sys_recvfrom
+-	.long sys_shutdown
+-	.long sys_setsockopt
+-	.long sys_getsockopt
+-	.long sys_sendmsg		/* 235 */
+-	.long sys_recvmsg
+-	/* Broken-out IPC family (maintain backwards compatibility in syscall
+-	   numbering with 2.4) */
+-	.long sys_semop
+-	.long sys_semget
+-	.long sys_semctl
+-	.long sys_msgsnd		/* 240 */
+-	.long sys_msgrcv
+-	.long sys_msgget
+-	.long sys_msgctl
+-	.long sys_shmat
+-	.long sys_shmdt			/* 245 */
+-	.long sys_shmget
+-	.long sys_shmctl
+-	/* Rest of syscalls listed in 2.4 i386 unistd.h */
+-	.long sys_getdents64
+-	.long sys_fcntl64
+-	.long sys_ni_syscall		/* 250 reserved for TUX */
+-	.long sys_ni_syscall		/* Reserved for Security */
+-	.long sys_gettid
+-	.long sys_readahead
+-	.long sys_setxattr
+-	.long sys_lsetxattr		/* 255 */
+-	.long sys_fsetxattr
+-	.long sys_getxattr
+-	.long sys_lgetxattr
+-	.long sys_fgetxattr
+-	.long sys_listxattr		/* 260 */
+-	.long sys_llistxattr
+-	.long sys_flistxattr
+-	.long sys_removexattr
+-	.long sys_lremovexattr
+-	.long sys_fremovexattr  	/* 265 */
+-	.long sys_tkill
+-	.long sys_sendfile64
+-	.long sys_futex
+-	.long sys_sched_setaffinity
+-	.long sys_sched_getaffinity	/* 270 */
+-	.long sys_ni_syscall
+-	.long sys_ni_syscall
+-	.long sys_io_setup
+-	.long sys_io_destroy
+-	.long sys_io_getevents		/* 275 */
+-	.long sys_io_submit
+-	.long sys_io_cancel
+-	.long sys_fadvise64
+-	.long sys_ni_syscall
+-	.long sys_exit_group		/* 280 */
+-	/* Rest of new 2.6 syscalls */
+-	.long sys_lookup_dcookie
+-	.long sys_epoll_create
+-	.long sys_epoll_ctl
+-	.long sys_epoll_wait
+- 	.long sys_remap_file_pages	/* 285 */
+- 	.long sys_set_tid_address
+- 	.long sys_timer_create
+- 	.long sys_timer_settime
+- 	.long sys_timer_gettime
+- 	.long sys_timer_getoverrun	/* 290 */
+- 	.long sys_timer_delete
+- 	.long sys_clock_settime
+- 	.long sys_clock_gettime
+- 	.long sys_clock_getres
+- 	.long sys_clock_nanosleep	/* 295 */
+-	.long sys_statfs64
+-	.long sys_fstatfs64
+-	.long sys_tgkill
+-	.long sys_utimes
+- 	.long sys_fadvise64_64		/* 300 */
+-	.long sys_ni_syscall	/* Reserved for vserver */
+-	.long sys_ni_syscall	/* Reserved for mbind */
+-	.long sys_ni_syscall	/* get_mempolicy */
+-	.long sys_ni_syscall	/* set_mempolicy */
+-	.long sys_mq_open		/* 305 */
+-	.long sys_mq_unlink
+-	.long sys_mq_timedsend
+-	.long sys_mq_timedreceive
+-	.long sys_mq_notify
+-	.long sys_mq_getsetattr		/* 310 */
+-	.long sys_ni_syscall	/* Reserved for kexec */
+-	.long sys_waitid
+-	.long sys_add_key
+-	.long sys_request_key
+-	.long sys_keyctl		/* 315 */
+-	.long sys_ioprio_set
+-	.long sys_ioprio_get
+-	.long sys_inotify_init
+-	.long sys_inotify_add_watch
+-	.long sys_inotify_rm_watch	/* 320 */
+-	.long sys_ni_syscall
+-	.long sys_migrate_pages
+-	.long sys_openat
+-	.long sys_mkdirat
+-	.long sys_mknodat		/* 325 */
+-	.long sys_fchownat
+-	.long sys_futimesat
+-	.long sys_fstatat64
+-	.long sys_unlinkat
+-	.long sys_renameat		/* 330 */
+-	.long sys_linkat
+-	.long sys_symlinkat
+-	.long sys_readlinkat
+-	.long sys_fchmodat
+-	.long sys_faccessat		/* 335 */
+-	.long sys_pselect6
+-	.long sys_ppoll
+-	.long sys_unshare
+-	.long sys_set_robust_list
+-	.long sys_get_robust_list	/* 340 */
+-	.long sys_splice
+-	.long sys_sync_file_range
+-	.long sys_tee
+-	.long sys_vmsplice
+-	.long sys_move_pages		/* 345 */
+-	.long sys_getcpu
+-	.long sys_epoll_pwait
+-	.long sys_utimensat
+-	.long sys_signalfd
+-	.long sys_timerfd		/* 350 */
+-	.long sys_eventfd
+-	.long sys_fallocate
+diff --git a/arch/sh64/kernel/time.c b/arch/sh64/kernel/time.c
+deleted file mode 100644
+index 06f3c17..0000000
+--- a/arch/sh64/kernel/time.c
++++ /dev/null
+@@ -1,593 +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.
+- *
+- * arch/sh64/kernel/time.c
+- *
+- * Copyright (C) 2000, 2001  Paolo Alberelli
+- * Copyright (C) 2003, 2004  Paul Mundt
+- * Copyright (C) 2003  Richard Curnow
+- *
+- *    Original TMU/RTC code taken from sh version.
+- *    Copyright (C) 1999  Tetsuya Okada & Niibe Yutaka
+- *      Some code taken from i386 version.
+- *      Copyright (C) 1991, 1992, 1995  Linus Torvalds
+- */
+-
+-#include <linux/errno.h>
+-#include <linux/rwsem.h>
+-#include <linux/sched.h>
+-#include <linux/kernel.h>
+-#include <linux/param.h>
+-#include <linux/string.h>
+-#include <linux/mm.h>
+-#include <linux/interrupt.h>
+-#include <linux/time.h>
+-#include <linux/delay.h>
+-#include <linux/init.h>
+-#include <linux/profile.h>
+-#include <linux/smp.h>
+-#include <linux/module.h>
+-#include <linux/bcd.h>
+-
+-#include <asm/registers.h>	 /* required by inline __asm__ stmt. */
+-
+-#include <asm/processor.h>
+-#include <asm/uaccess.h>
+-#include <asm/io.h>
+-#include <asm/irq.h>
+-#include <asm/delay.h>
+-
+-#include <linux/timex.h>
+-#include <linux/irq.h>
+-#include <asm/hardware.h>
+-
+-#define TMU_TOCR_INIT	0x00
+-#define TMU0_TCR_INIT	0x0020
+-#define TMU_TSTR_INIT	1
+-#define TMU_TSTR_OFF	0
+-
+-/* RCR1 Bits */
+-#define RCR1_CF		0x80	/* Carry Flag             */
+-#define RCR1_CIE	0x10	/* Carry Interrupt Enable */
+-#define RCR1_AIE	0x08	/* Alarm Interrupt Enable */
+-#define RCR1_AF		0x01	/* Alarm Flag             */
+-
+-/* RCR2 Bits */
+-#define RCR2_PEF	0x80	/* PEriodic interrupt Flag */
+-#define RCR2_PESMASK	0x70	/* Periodic interrupt Set  */
+-#define RCR2_RTCEN	0x08	/* ENable RTC              */
+-#define RCR2_ADJ	0x04	/* ADJustment (30-second)  */
+-#define RCR2_RESET	0x02	/* Reset bit               */
+-#define RCR2_START	0x01	/* Start bit               */
+-
+-/* Clock, Power and Reset Controller */
+-#define	CPRC_BLOCK_OFF	0x01010000
+-#define CPRC_BASE	PHYS_PERIPHERAL_BLOCK + CPRC_BLOCK_OFF
+-
+-#define FRQCR		(cprc_base+0x0)
+-#define WTCSR		(cprc_base+0x0018)
+-#define STBCR		(cprc_base+0x0030)
+-
+-/* Time Management Unit */
+-#define	TMU_BLOCK_OFF	0x01020000
+-#define TMU_BASE	PHYS_PERIPHERAL_BLOCK + TMU_BLOCK_OFF
+-#define TMU0_BASE	tmu_base + 0x8 + (0xc * 0x0)
+-#define TMU1_BASE	tmu_base + 0x8 + (0xc * 0x1)
+-#define TMU2_BASE	tmu_base + 0x8 + (0xc * 0x2)
+-
+-#define TMU_TOCR	tmu_base+0x0	/* Byte access */
+-#define TMU_TSTR	tmu_base+0x4	/* Byte access */
+-
+-#define TMU0_TCOR	TMU0_BASE+0x0	/* Long access */
+-#define TMU0_TCNT	TMU0_BASE+0x4	/* Long access */
+-#define TMU0_TCR	TMU0_BASE+0x8	/* Word access */
+-
+-/* Real Time Clock */
+-#define	RTC_BLOCK_OFF	0x01040000
+-#define RTC_BASE	PHYS_PERIPHERAL_BLOCK + RTC_BLOCK_OFF
+-
+-#define R64CNT  	rtc_base+0x00
+-#define RSECCNT 	rtc_base+0x04
+-#define RMINCNT 	rtc_base+0x08
+-#define RHRCNT  	rtc_base+0x0c
+-#define RWKCNT  	rtc_base+0x10
+-#define RDAYCNT 	rtc_base+0x14
+-#define RMONCNT 	rtc_base+0x18
+-#define RYRCNT  	rtc_base+0x1c	/* 16bit */
+-#define RSECAR  	rtc_base+0x20
+-#define RMINAR  	rtc_base+0x24
+-#define RHRAR   	rtc_base+0x28
+-#define RWKAR   	rtc_base+0x2c
+-#define RDAYAR  	rtc_base+0x30
+-#define RMONAR  	rtc_base+0x34
+-#define RCR1    	rtc_base+0x38
+-#define RCR2    	rtc_base+0x3c
+-
+-#define TICK_SIZE (tick_nsec / 1000)
+-
+-static unsigned long tmu_base, rtc_base;
+-unsigned long cprc_base;
+-
+-/* Variables to allow interpolation of time of day to resolution better than a
+- * jiffy. */
+-
+-/* This is effectively protected by xtime_lock */
+-static unsigned long ctc_last_interrupt;
+-static unsigned long long usecs_per_jiffy = 1000000/HZ; /* Approximation */
+-
+-#define CTC_JIFFY_SCALE_SHIFT 40
+-
+-/* 2**CTC_JIFFY_SCALE_SHIFT / ctc_ticks_per_jiffy */
+-static unsigned long long scaled_recip_ctc_ticks_per_jiffy;
+-
+-/* Estimate number of microseconds that have elapsed since the last timer tick,
+-   by scaling the delta that has occurred in the CTC register.
+-
+-   WARNING WARNING WARNING : This algorithm relies on the CTC decrementing at
+-   the CPU clock rate.  If the CPU sleeps, the CTC stops counting.  Bear this
+-   in mind if enabling SLEEP_WORKS in process.c.  In that case, this algorithm
+-   probably needs to use TMU.TCNT0 instead.  This will work even if the CPU is
+-   sleeping, though will be coarser.
+-
+-   FIXME : What if usecs_per_tick is moving around too much, e.g. if an adjtime
+-   is running or if the freq or tick arguments of adjtimex are modified after
+-   we have calibrated the scaling factor?  This will result in either a jump at
+-   the end of a tick period, or a wrap backwards at the start of the next one,
+-   if the application is reading the time of day often enough.  I think we
+-   ought to do better than this.  For this reason, usecs_per_jiffy is left
+-   separated out in the calculation below.  This allows some future hook into
+-   the adjtime-related stuff in kernel/timer.c to remove this hazard.
+-
+-*/
+-
+-static unsigned long usecs_since_tick(void)
+-{
+-	unsigned long long current_ctc;
+-	long ctc_ticks_since_interrupt;
+-	unsigned long long ull_ctc_ticks_since_interrupt;
+-	unsigned long result;
+-
+-	unsigned long long mul1_out;
+-	unsigned long long mul1_out_high;
+-	unsigned long long mul2_out_low, mul2_out_high;
+-
+-	/* Read CTC register */
+-	asm ("getcon cr62, %0" : "=r" (current_ctc));
+-	/* Note, the CTC counts down on each CPU clock, not up.
+-	   Note(2), use long type to get correct wraparound arithmetic when
+-	   the counter crosses zero. */
+-	ctc_ticks_since_interrupt = (long) ctc_last_interrupt - (long) current_ctc;
+-	ull_ctc_ticks_since_interrupt = (unsigned long long) ctc_ticks_since_interrupt;
+-
+-	/* Inline assembly to do 32x32x32->64 multiplier */
+-	asm volatile ("mulu.l %1, %2, %0" :
+-	     "=r" (mul1_out) :
+-	     "r" (ull_ctc_ticks_since_interrupt), "r" (usecs_per_jiffy));
+-
+-	mul1_out_high = mul1_out >> 32;
+-
+-	asm volatile ("mulu.l %1, %2, %0" :
+-	     "=r" (mul2_out_low) :
+-	     "r" (mul1_out), "r" (scaled_recip_ctc_ticks_per_jiffy));
+-
+-#if 1
+-	asm volatile ("mulu.l %1, %2, %0" :
+-	     "=r" (mul2_out_high) :
+-	     "r" (mul1_out_high), "r" (scaled_recip_ctc_ticks_per_jiffy));
+-#endif
+-
+-	result = (unsigned long) (((mul2_out_high << 32) + mul2_out_low) >> CTC_JIFFY_SCALE_SHIFT);
+-
+-	return result;
+-}
+-
+-void do_gettimeofday(struct timeval *tv)
+-{
+-	unsigned long flags;
+-	unsigned long seq;
+-	unsigned long usec, sec;
+-
+-	do {
+-		seq = read_seqbegin_irqsave(&xtime_lock, flags);
+-		usec = usecs_since_tick();
+-		sec = xtime.tv_sec;
+-		usec += xtime.tv_nsec / 1000;
+-	} while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
+-
+-	while (usec >= 1000000) {
+-		usec -= 1000000;
+-		sec++;
+-	}
+-
+-	tv->tv_sec = sec;
+-	tv->tv_usec = usec;
+-}
+-
+-int do_settimeofday(struct timespec *tv)
+-{
+-	time_t wtm_sec, sec = tv->tv_sec;
+-	long wtm_nsec, nsec = tv->tv_nsec;
+-
+-	if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC)
+-		return -EINVAL;
+-
+-	write_seqlock_irq(&xtime_lock);
+-	/*
+-	 * This is revolting. We need to set "xtime" correctly. However, the
+-	 * value in this location is the value at the most recent update of
+-	 * wall time.  Discover what correction gettimeofday() would have
+-	 * made, and then undo it!
+-	 */
+-	nsec -= 1000 * usecs_since_tick();
+-
+-	wtm_sec  = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec);
+-	wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec);
+-
+-	set_normalized_timespec(&xtime, sec, nsec);
+-	set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);
+-
+-	ntp_clear();
+-	write_sequnlock_irq(&xtime_lock);
+-	clock_was_set();
+-
+-	return 0;
+-}
+-EXPORT_SYMBOL(do_settimeofday);
+-
+-static int set_rtc_time(unsigned long nowtime)
+-{
+-	int retval = 0;
+-	int real_seconds, real_minutes, cmos_minutes;
 -
--	if (is_on)
--		gpio_set_value(CONFIG_USB_SL811_BFIN_GPIO_VBUS, 1);
--	else
--		gpio_set_value(CONFIG_USB_SL811_BFIN_GPIO_VBUS, 0);
-+	gpio_direction_output(CONFIG_USB_SL811_BFIN_GPIO_VBUS, is_on);
- }
- #endif
- 
-@@ -320,6 +340,49 @@ static struct platform_device net2272_bfin_device = {
- };
- #endif
- 
-+static struct mtd_partition stamp_partitions[] = {
-+	{
-+		.name       = "Bootloader",
-+		.size       = 0x20000,
-+		.offset     = 0,
-+	}, {
-+		.name       = "Kernel",
-+		.size       = 0xE0000,
-+		.offset     = MTDPART_OFS_APPEND,
-+	}, {
-+		.name       = "RootFS",
-+		.size       = 0x400000 - 0x20000 - 0xE0000 - 0x10000,
-+		.offset     = MTDPART_OFS_APPEND,
-+	}, {
-+		.name       = "MAC Address",
-+		.size       = MTDPART_SIZ_FULL,
-+		.offset     = 0x3F0000,
-+		.mask_flags = MTD_WRITEABLE,
-+	}
-+};
-+
-+static struct physmap_flash_data stamp_flash_data = {
-+	.width      = 2,
-+	.parts      = stamp_partitions,
-+	.nr_parts   = ARRAY_SIZE(stamp_partitions),
-+};
-+
-+static struct resource stamp_flash_resource = {
-+	.start = 0x20000000,
-+	.end   = 0x203fffff,
-+	.flags = IORESOURCE_MEM,
-+};
-+
-+static struct platform_device stamp_flash_device = {
-+	.name          = "physmap-flash",
-+	.id            = 0,
-+	.dev = {
-+		.platform_data = &stamp_flash_data,
-+	},
-+	.num_resources = 1,
-+	.resource      = &stamp_flash_resource,
-+};
-+
- #if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
- /* all SPI peripherals info goes here */
- 
-@@ -738,6 +801,11 @@ static struct platform_device *stamp_devices[] __initdata = {
- #if defined(CONFIG_PATA_PLATFORM) || defined(CONFIG_PATA_PLATFORM_MODULE)
- 	&bfin_pata_device,
- #endif
-+
-+#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
-+	&bfin_device_gpiokeys,
-+#endif
-+	&stamp_flash_device,
- };
- 
- static int __init stamp_init(void)
-diff --git a/arch/blackfin/mach-bf548/Kconfig b/arch/blackfin/mach-bf548/Kconfig
-index d8bd3b4..1bfcd8f 100644
---- a/arch/blackfin/mach-bf548/Kconfig
-+++ b/arch/blackfin/mach-bf548/Kconfig
-@@ -7,7 +7,7 @@ menu "BF548 Specific Configuration"
- config DEB_DMA_URGENT
- 	bool "DMA has priority over core for ext. accesses"
- 	depends on BF54x
--	default n
-+	default y
- 	help
- 	  Treat any DEB1, DEB2 and DEB3 request as Urgent
- 
-diff --git a/arch/blackfin/mach-bf548/boards/ezkit.c b/arch/blackfin/mach-bf548/boards/ezkit.c
-index d37d665..14860f0 100644
---- a/arch/blackfin/mach-bf548/boards/ezkit.c
-+++ b/arch/blackfin/mach-bf548/boards/ezkit.c
-@@ -32,6 +32,7 @@
- #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/irq.h>
-@@ -206,23 +207,6 @@ static struct platform_device smsc911x_device = {
- };
- #endif
- 
--#if defined(CONFIG_USB_BF54x_HCD) || defined(CONFIG_USB_BF54x_HCD_MODULE)
--static struct resource bf54x_hcd_resources[] = {
+-	ctrl_outb(RCR2_RESET, RCR2);  /* Reset pre-scaler & stop RTC */
+-
+-	cmos_minutes = ctrl_inb(RMINCNT);
+-	BCD_TO_BIN(cmos_minutes);
+-
+-	/*
+-	 * 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 - cmos_minutes) + 15)/30) & 1)
+-		real_minutes += 30;	/* correct for half hour time zone */
+-	real_minutes %= 60;
+-
+-	if (abs(real_minutes - cmos_minutes) < 30) {
+-		BIN_TO_BCD(real_seconds);
+-		BIN_TO_BCD(real_minutes);
+-		ctrl_outb(real_seconds, RSECCNT);
+-		ctrl_outb(real_minutes, RMINCNT);
+-	} else {
+-		printk(KERN_WARNING
+-		       "set_rtc_time: can't update from %d to %d\n",
+-		       cmos_minutes, real_minutes);
+-		retval = -1;
+-	}
+-
+-	ctrl_outb(RCR2_RTCEN|RCR2_START, RCR2);  /* Start RTC */
+-
+-	return retval;
+-}
+-
+-/* last time the RTC clock got updated */
+-static long last_rtc_update = 0;
+-
+-/*
+- * timer_interrupt() needs to keep up the real-time clock,
+- * as well as call the "do_timer()" routine every clocktick
+- */
+-static inline void do_timer_interrupt(void)
+-{
+-	unsigned long long current_ctc;
+-	asm ("getcon cr62, %0" : "=r" (current_ctc));
+-	ctc_last_interrupt = (unsigned long) current_ctc;
+-
+-	do_timer(1);
+-#ifndef CONFIG_SMP
+-	update_process_times(user_mode(get_irq_regs()));
+-#endif
+-	if (current->pid)
+-		profile_tick(CPU_PROFILING);
+-
+-#ifdef CONFIG_HEARTBEAT
 -	{
--		.start = 0xFFC03C00,
--		.end = 0xFFC040FF,
--		.flags = IORESOURCE_MEM,
--	},
+-		extern void heartbeat(void);
+-
+-		heartbeat();
+-	}
+-#endif
+-
+-	/*
+-	 * If we have an externally synchronized Linux clock, then update
+-	 * RTC clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
+-	 * called as close as possible to 500 ms before the new second starts.
+-	 */
+-	if (ntp_synced() &&
+-	    xtime.tv_sec > last_rtc_update + 660 &&
+-	    (xtime.tv_nsec / 1000) >= 500000 - ((unsigned) TICK_SIZE) / 2 &&
+-	    (xtime.tv_nsec / 1000) <= 500000 + ((unsigned) TICK_SIZE) / 2) {
+-		if (set_rtc_time(xtime.tv_sec) == 0)
+-			last_rtc_update = xtime.tv_sec;
+-		else
+-			last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */
+-	}
+-}
+-
+-/*
+- * This is the same as the above, except we _also_ save the current
+- * Time Stamp Counter value at the time of the timer interrupt, so that
+- * we later on can estimate the time of day more exactly.
+- */
+-static irqreturn_t timer_interrupt(int irq, void *dev_id)
+-{
+-	unsigned long timer_status;
+-
+-	/* Clear UNF bit */
+-	timer_status = ctrl_inw(TMU0_TCR);
+-	timer_status &= ~0x100;
+-	ctrl_outw(timer_status, TMU0_TCR);
+-
+-	/*
+-	 * Here we are in the timer irq handler. We just have irqs locally
+-	 * disabled but we don't know if the timer_bh is running on the other
+-	 * CPU. We need to avoid to SMP race with it. NOTE: we don' t need
+-	 * the irq version of write_lock because as just said we have irq
+-	 * locally disabled. -arca
+-	 */
+-	write_lock(&xtime_lock);
+-	do_timer_interrupt();
+-	write_unlock(&xtime_lock);
+-
+-	return IRQ_HANDLED;
+-}
+-
+-static unsigned long get_rtc_time(void)
+-{
+-	unsigned int sec, min, hr, wk, day, mon, yr, yr100;
+-
+- again:
+-	do {
+-		ctrl_outb(0, RCR1);  /* Clear CF-bit */
+-		sec = ctrl_inb(RSECCNT);
+-		min = ctrl_inb(RMINCNT);
+-		hr  = ctrl_inb(RHRCNT);
+-		wk  = ctrl_inb(RWKCNT);
+-		day = ctrl_inb(RDAYCNT);
+-		mon = ctrl_inb(RMONCNT);
+-		yr  = ctrl_inw(RYRCNT);
+-		yr100 = (yr >> 8);
+-		yr &= 0xff;
+-	} while ((ctrl_inb(RCR1) & RCR1_CF) != 0);
+-
+-	BCD_TO_BIN(yr100);
+-	BCD_TO_BIN(yr);
+-	BCD_TO_BIN(mon);
+-	BCD_TO_BIN(day);
+-	BCD_TO_BIN(hr);
+-	BCD_TO_BIN(min);
+-	BCD_TO_BIN(sec);
+-
+-	if (yr > 99 || mon < 1 || mon > 12 || day > 31 || day < 1 ||
+-	    hr > 23 || min > 59 || sec > 59) {
+-		printk(KERN_ERR
+-		       "SH RTC: invalid value, resetting to 1 Jan 2000\n");
+-		ctrl_outb(RCR2_RESET, RCR2);  /* Reset & Stop */
+-		ctrl_outb(0, RSECCNT);
+-		ctrl_outb(0, RMINCNT);
+-		ctrl_outb(0, RHRCNT);
+-		ctrl_outb(6, RWKCNT);
+-		ctrl_outb(1, RDAYCNT);
+-		ctrl_outb(1, RMONCNT);
+-		ctrl_outw(0x2000, RYRCNT);
+-		ctrl_outb(RCR2_RTCEN|RCR2_START, RCR2);  /* Start */
+-		goto again;
+-	}
+-
+-	return mktime(yr100 * 100 + yr, mon, day, hr, min, sec);
+-}
+-
+-static __init unsigned int get_cpu_hz(void)
+-{
+-	unsigned int count;
+-	unsigned long __dummy;
+-	unsigned long ctc_val_init, ctc_val;
+-
+-	/*
+-	** Regardless the toolchain, force the compiler to use the
+-	** arbitrary register r3 as a clock tick counter.
+-	** NOTE: r3 must be in accordance with sh64_rtc_interrupt()
+-	*/
+-	register unsigned long long  __rtc_irq_flag __asm__ ("r3");
+-
+-	local_irq_enable();
+-	do {} while (ctrl_inb(R64CNT) != 0);
+-	ctrl_outb(RCR1_CIE, RCR1); /* Enable carry interrupt */
+-
+-	/*
+-	 * r3 is arbitrary. CDC does not support "=z".
+-	 */
+-	ctc_val_init = 0xffffffff;
+-	ctc_val = ctc_val_init;
+-
+-	asm volatile("gettr	tr0, %1\n\t"
+-		     "putcon	%0, " __CTC "\n\t"
+-		     "and	%2, r63, %2\n\t"
+-		     "pta	$+4, tr0\n\t"
+-		     "beq/l	%2, r63, tr0\n\t"
+-		     "ptabs	%1, tr0\n\t"
+-		     "getcon	" __CTC ", %0\n\t"
+-		: "=r"(ctc_val), "=r" (__dummy), "=r" (__rtc_irq_flag)
+-		: "0" (0));
+-	local_irq_disable();
+-	/*
+-	 * SH-3:
+-	 * CPU clock = 4 stages * loop
+-	 * tst    rm,rm      if id ex
+-	 * bt/s   1b            if id ex
+-	 * add    #1,rd            if id ex
+-         *                            (if) pipe line stole
+-	 * tst    rm,rm                  if id ex
+-         * ....
+-	 *
+-	 *
+-	 * SH-4:
+-	 * CPU clock = 6 stages * loop
+-	 * I don't know why.
+-         * ....
+-	 *
+-	 * SH-5:
+-	 * Use CTC register to count.  This approach returns the right value
+-	 * even if the I-cache is disabled (e.g. whilst debugging.)
+-	 *
+-	 */
+-
+-	count = ctc_val_init - ctc_val; /* CTC counts down */
+-
+-#if defined (CONFIG_SH_SIMULATOR)
+-	/*
+-	 * Let's pretend we are a 5MHz SH-5 to avoid a too
+-	 * little timer interval. Also to keep delay
+-	 * calibration within a reasonable time.
+-	 */
+-	return 5000000;
+-#else
+-	/*
+-	 * This really is count by the number of clock cycles
+-         * by the ratio between a complete R64CNT
+-         * wrap-around (128) and CUI interrupt being raised (64).
+-	 */
+-	return count*2;
+-#endif
+-}
+-
+-static irqreturn_t sh64_rtc_interrupt(int irq, void *dev_id)
+-{
+-	struct pt_regs *regs = get_irq_regs();
+-
+-	ctrl_outb(0, RCR1);	/* Disable Carry Interrupts */
+-	regs->regs[3] = 1;	/* Using r3 */
+-
+-	return IRQ_HANDLED;
+-}
+-
+-static struct irqaction irq0  = {
+-	.handler = timer_interrupt,
+-	.flags = IRQF_DISABLED,
+-	.mask = CPU_MASK_NONE,
+-	.name = "timer",
+-};
+-static struct irqaction irq1  = {
+-	.handler = sh64_rtc_interrupt,
+-	.flags = IRQF_DISABLED,
+-	.mask = CPU_MASK_NONE,
+-	.name = "rtc",
 -};
 -
--static struct platform_device bf54x_hcd = {
--	.name = "bf54x-hcd",
--	.id = 0,
--	.num_resources = ARRAY_SIZE(bf54x_hcd_resources),
--	.resource = bf54x_hcd_resources,
+-void __init time_init(void)
+-{
+-	unsigned int cpu_clock, master_clock, bus_clock, module_clock;
+-	unsigned long interval;
+-	unsigned long frqcr, ifc, pfc;
+-	static int ifc_table[] = { 2, 4, 6, 8, 10, 12, 16, 24 };
+-#define bfc_table ifc_table	/* Same */
+-#define pfc_table ifc_table	/* Same */
+-
+-	tmu_base = onchip_remap(TMU_BASE, 1024, "TMU");
+-	if (!tmu_base) {
+-		panic("Unable to remap TMU\n");
+-	}
+-
+-	rtc_base = onchip_remap(RTC_BASE, 1024, "RTC");
+-	if (!rtc_base) {
+-		panic("Unable to remap RTC\n");
+-	}
+-
+-	cprc_base = onchip_remap(CPRC_BASE, 1024, "CPRC");
+-	if (!cprc_base) {
+-		panic("Unable to remap CPRC\n");
+-	}
+-
+-	xtime.tv_sec = get_rtc_time();
+-	xtime.tv_nsec = 0;
+-
+-	setup_irq(TIMER_IRQ, &irq0);
+-	setup_irq(RTC_IRQ, &irq1);
+-
+-	/* Check how fast it is.. */
+-	cpu_clock = get_cpu_hz();
+-
+-	/* Note careful order of operations to maintain reasonable precision and avoid overflow. */
+-	scaled_recip_ctc_ticks_per_jiffy = ((1ULL << CTC_JIFFY_SCALE_SHIFT) / (unsigned long long)(cpu_clock / HZ));
+-
+-	disable_irq(RTC_IRQ);
+-
+-	printk("CPU clock: %d.%02dMHz\n",
+-	       (cpu_clock / 1000000), (cpu_clock % 1000000)/10000);
+-	{
+-		unsigned short bfc;
+-		frqcr = ctrl_inl(FRQCR);
+-		ifc  = ifc_table[(frqcr>> 6) & 0x0007];
+-		bfc  = bfc_table[(frqcr>> 3) & 0x0007];
+-		pfc  = pfc_table[(frqcr>> 12) & 0x0007];
+-		master_clock = cpu_clock * ifc;
+-		bus_clock = master_clock/bfc;
+-	}
+-
+-	printk("Bus clock: %d.%02dMHz\n",
+-	       (bus_clock/1000000), (bus_clock % 1000000)/10000);
+-	module_clock = master_clock/pfc;
+-	printk("Module clock: %d.%02dMHz\n",
+-	       (module_clock/1000000), (module_clock % 1000000)/10000);
+-	interval = (module_clock/(HZ*4));
+-
+-	printk("Interval = %ld\n", interval);
+-
+-	current_cpu_data.cpu_clock    = cpu_clock;
+-	current_cpu_data.master_clock = master_clock;
+-	current_cpu_data.bus_clock    = bus_clock;
+-	current_cpu_data.module_clock = module_clock;
+-
+-	/* Start TMU0 */
+-	ctrl_outb(TMU_TSTR_OFF, TMU_TSTR);
+-	ctrl_outb(TMU_TOCR_INIT, TMU_TOCR);
+-	ctrl_outw(TMU0_TCR_INIT, TMU0_TCR);
+-	ctrl_outl(interval, TMU0_TCOR);
+-	ctrl_outl(interval, TMU0_TCNT);
+-	ctrl_outb(TMU_TSTR_INIT, TMU_TSTR);
+-}
+-
+-void enter_deep_standby(void)
+-{
+-	/* Disable watchdog timer */
+-	ctrl_outl(0xa5000000, WTCSR);
+-	/* Configure deep standby on sleep */
+-	ctrl_outl(0x03, STBCR);
+-
+-#ifdef CONFIG_SH_ALPHANUMERIC
+-	{
+-		extern void mach_alphanum(int position, unsigned char value);
+-		extern void mach_alphanum_brightness(int setting);
+-		char halted[] = "Halted. ";
+-		int i;
+-		mach_alphanum_brightness(6); /* dimmest setting above off */
+-		for (i=0; i<8; i++) {
+-			mach_alphanum(i, halted[i]);
+-		}
+-		asm __volatile__ ("synco");
+-	}
+-#endif
+-
+-	asm __volatile__ ("sleep");
+-	asm __volatile__ ("synci");
+-	asm __volatile__ ("nop");
+-	asm __volatile__ ("nop");
+-	asm __volatile__ ("nop");
+-	asm __volatile__ ("nop");
+-	panic("Unexpected wakeup!\n");
+-}
+diff --git a/arch/sh64/kernel/traps.c b/arch/sh64/kernel/traps.c
+deleted file mode 100644
+index f32df38..0000000
+--- a/arch/sh64/kernel/traps.c
++++ /dev/null
+@@ -1,982 +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.
+- *
+- * arch/sh64/kernel/traps.c
+- *
+- * Copyright (C) 2000, 2001  Paolo Alberelli
+- * Copyright (C) 2003, 2004  Paul Mundt
+- * Copyright (C) 2003, 2004  Richard Curnow
+- *
+- */
+-
+-/*
+- * 'Traps.c' handles hardware traps and faults after we have saved some
+- * state in 'entry.S'.
+- */
+-#include <linux/sched.h>
+-#include <linux/kernel.h>
+-#include <linux/string.h>
+-#include <linux/errno.h>
+-#include <linux/ptrace.h>
+-#include <linux/timer.h>
+-#include <linux/mm.h>
+-#include <linux/smp.h>
+-#include <linux/init.h>
+-#include <linux/delay.h>
+-#include <linux/spinlock.h>
+-#include <linux/kallsyms.h>
+-#include <linux/interrupt.h>
+-#include <linux/sysctl.h>
+-#include <linux/module.h>
+-#include <asm/system.h>
+-#include <asm/uaccess.h>
+-#include <asm/io.h>
+-#include <asm/atomic.h>
+-#include <asm/processor.h>
+-#include <asm/pgtable.h>
+-
+-#undef DEBUG_EXCEPTION
+-#ifdef DEBUG_EXCEPTION
+-/* implemented in ../lib/dbg.c */
+-extern void show_excp_regs(char *fname, int trapnr, int signr,
+-			   struct pt_regs *regs);
+-#else
+-#define show_excp_regs(a, b, c, d)
+-#endif
+-
+-static void do_unhandled_exception(int trapnr, int signr, char *str, char *fn_name,
+-		unsigned long error_code, struct pt_regs *regs, struct task_struct *tsk);
+-
+-#define DO_ERROR(trapnr, signr, str, name, tsk) \
+-asmlinkage void do_##name(unsigned long error_code, struct pt_regs *regs) \
+-{ \
+-	do_unhandled_exception(trapnr, signr, str, __stringify(name), error_code, regs, current); \
+-}
+-
+-spinlock_t die_lock;
+-
+-void die(const char * str, struct pt_regs * regs, long err)
+-{
+-	console_verbose();
+-	spin_lock_irq(&die_lock);
+-	printk("%s: %lx\n", str, (err & 0xffffff));
+-	show_regs(regs);
+-	spin_unlock_irq(&die_lock);
+-	do_exit(SIGSEGV);
+-}
+-
+-static inline void die_if_kernel(const char * str, struct pt_regs * regs, long err)
+-{
+-	if (!user_mode(regs))
+-		die(str, regs, err);
+-}
+-
+-static void die_if_no_fixup(const char * str, struct pt_regs * regs, long err)
+-{
+-	if (!user_mode(regs)) {
+-		const struct exception_table_entry *fixup;
+-		fixup = search_exception_tables(regs->pc);
+-		if (fixup) {
+-			regs->pc = fixup->fixup;
+-			return;
+-		}
+-		die(str, regs, err);
+-	}
+-}
+-
+-DO_ERROR(13, SIGILL,  "illegal slot instruction", illegal_slot_inst, current)
+-DO_ERROR(87, SIGSEGV, "address error (exec)", address_error_exec, current)
+-
+-
+-/* Implement misaligned load/store handling for kernel (and optionally for user
+-   mode too).  Limitation : only SHmedia mode code is handled - there is no
+-   handling at all for misaligned accesses occurring in SHcompact code yet. */
+-
+-static int misaligned_fixup(struct pt_regs *regs);
+-
+-asmlinkage void do_address_error_load(unsigned long error_code, struct pt_regs *regs)
+-{
+-	if (misaligned_fixup(regs) < 0) {
+-		do_unhandled_exception(7, SIGSEGV, "address error(load)",
+-				"do_address_error_load",
+-				error_code, regs, current);
+-	}
+-	return;
+-}
+-
+-asmlinkage void do_address_error_store(unsigned long error_code, struct pt_regs *regs)
+-{
+-	if (misaligned_fixup(regs) < 0) {
+-		do_unhandled_exception(8, SIGSEGV, "address error(store)",
+-				"do_address_error_store",
+-				error_code, regs, current);
+-	}
+-	return;
+-}
+-
+-#if defined(CONFIG_SH64_ID2815_WORKAROUND)
+-
+-#define OPCODE_INVALID      0
+-#define OPCODE_USER_VALID   1
+-#define OPCODE_PRIV_VALID   2
+-
+-/* getcon/putcon - requires checking which control register is referenced. */
+-#define OPCODE_CTRL_REG     3
+-
+-/* Table of valid opcodes for SHmedia mode.
+-   Form a 10-bit value by concatenating the major/minor opcodes i.e.
+-   opcode[31:26,20:16].  The 6 MSBs of this value index into the following
+-   array.  The 4 LSBs select the bit-pair in the entry (bits 1:0 correspond to
+-   LSBs==4'b0000 etc). */
+-static unsigned long shmedia_opcode_table[64] = {
+-	0x55554044,0x54445055,0x15141514,0x14541414,0x00000000,0x10001000,0x01110055,0x04050015,
+-	0x00000444,0xc0000000,0x44545515,0x40405555,0x55550015,0x10005555,0x55555505,0x04050000,
+-	0x00000555,0x00000404,0x00040445,0x15151414,0x00000000,0x00000000,0x00000000,0x00000000,
+-	0x00000055,0x40404444,0x00000404,0xc0009495,0x00000000,0x00000000,0x00000000,0x00000000,
+-	0x55555555,0x55555555,0x55555555,0x55555555,0x55555555,0x55555555,0x55555555,0x55555555,
+-	0x55555555,0x55555555,0x55555555,0x55555555,0x55555555,0x55555555,0x55555555,0x55555555,
+-	0x80005050,0x04005055,0x55555555,0x55555555,0x55555555,0x55555555,0x55555555,0x55555555,
+-	0x81055554,0x00000404,0x55555555,0x55555555,0x00000000,0x00000000,0x00000000,0x00000000
 -};
+-
+-void do_reserved_inst(unsigned long error_code, struct pt_regs *regs)
+-{
+-	/* Workaround SH5-101 cut2 silicon defect #2815 :
+-	   in some situations, inter-mode branches from SHcompact -> SHmedia
+-	   which should take ITLBMISS or EXECPROT exceptions at the target
+-	   falsely take RESINST at the target instead. */
+-
+-	unsigned long opcode = 0x6ff4fff0; /* guaranteed reserved opcode */
+-	unsigned long pc, aligned_pc;
+-	int get_user_error;
+-	int trapnr = 12;
+-	int signr = SIGILL;
+-	char *exception_name = "reserved_instruction";
+-
+-	pc = regs->pc;
+-	if ((pc & 3) == 1) {
+-		/* SHmedia : check for defect.  This requires executable vmas
+-		   to be readable too. */
+-		aligned_pc = pc & ~3;
+-		if (!access_ok(VERIFY_READ, aligned_pc, sizeof(unsigned long))) {
+-			get_user_error = -EFAULT;
+-		} else {
+-			get_user_error = __get_user(opcode, (unsigned long *)aligned_pc);
+-		}
+-		if (get_user_error >= 0) {
+-			unsigned long index, shift;
+-			unsigned long major, minor, combined;
+-			unsigned long reserved_field;
+-			reserved_field = opcode & 0xf; /* These bits are currently reserved as zero in all valid opcodes */
+-			major = (opcode >> 26) & 0x3f;
+-			minor = (opcode >> 16) & 0xf;
+-			combined = (major << 4) | minor;
+-			index = major;
+-			shift = minor << 1;
+-			if (reserved_field == 0) {
+-				int opcode_state = (shmedia_opcode_table[index] >> shift) & 0x3;
+-				switch (opcode_state) {
+-					case OPCODE_INVALID:
+-						/* Trap. */
+-						break;
+-					case OPCODE_USER_VALID:
+-						/* Restart the instruction : the branch to the instruction will now be from an RTE
+-						   not from SHcompact so the silicon defect won't be triggered. */
+-						return;
+-					case OPCODE_PRIV_VALID:
+-						if (!user_mode(regs)) {
+-							/* Should only ever get here if a module has
+-							   SHcompact code inside it.  If so, the same fix up is needed. */
+-							return; /* same reason */
+-						}
+-						/* Otherwise, user mode trying to execute a privileged instruction -
+-						   fall through to trap. */
+-						break;
+-					case OPCODE_CTRL_REG:
+-						/* If in privileged mode, return as above. */
+-						if (!user_mode(regs)) return;
+-						/* In user mode ... */
+-						if (combined == 0x9f) { /* GETCON */
+-							unsigned long regno = (opcode >> 20) & 0x3f;
+-							if (regno >= 62) {
+-								return;
+-							}
+-							/* Otherwise, reserved or privileged control register, => trap */
+-						} else if (combined == 0x1bf) { /* PUTCON */
+-							unsigned long regno = (opcode >> 4) & 0x3f;
+-							if (regno >= 62) {
+-								return;
+-							}
+-							/* Otherwise, reserved or privileged control register, => trap */
+-						} else {
+-							/* Trap */
+-						}
+-						break;
+-					default:
+-						/* Fall through to trap. */
+-						break;
+-				}
+-			}
+-			/* fall through to normal resinst processing */
+-		} else {
+-			/* Error trying to read opcode.  This typically means a
+-			   real fault, not a RESINST any more.  So change the
+-			   codes. */
+-			trapnr = 87;
+-			exception_name = "address error (exec)";
+-			signr = SIGSEGV;
+-		}
+-	}
+-
+-	do_unhandled_exception(trapnr, signr, exception_name, "do_reserved_inst", error_code, regs, current);
+-}
+-
+-#else /* CONFIG_SH64_ID2815_WORKAROUND */
+-
+-/* If the workaround isn't needed, this is just a straightforward reserved
+-   instruction */
+-DO_ERROR(12, SIGILL,  "reserved instruction", reserved_inst, current)
+-
+-#endif /* CONFIG_SH64_ID2815_WORKAROUND */
+-
+-/* Called with interrupts disabled */
+-asmlinkage void do_exception_error(unsigned long ex, struct pt_regs *regs)
+-{
+-	PLS();
+-	show_excp_regs(__FUNCTION__, -1, -1, regs);
+-	die_if_kernel("exception", regs, ex);
+-}
+-
+-int do_unknown_trapa(unsigned long scId, struct pt_regs *regs)
+-{
+-	/* Syscall debug */
+-        printk("System call ID error: [0x1#args:8 #syscall:16  0x%lx]\n", scId);
+-
+-	die_if_kernel("unknown trapa", regs, scId);
+-
+-	return -ENOSYS;
+-}
+-
+-void show_stack(struct task_struct *tsk, unsigned long *sp)
+-{
+-#ifdef CONFIG_KALLSYMS
+-	extern void sh64_unwind(struct pt_regs *regs);
+-	struct pt_regs *regs;
+-
+-	regs = tsk ? tsk->thread.kregs : NULL;
+-
+-	sh64_unwind(regs);
+-#else
+-	printk(KERN_ERR "Can't backtrace on sh64 without CONFIG_KALLSYMS\n");
 -#endif
+-}
 -
- #if defined(CONFIG_USB_MUSB_HDRC) || defined(CONFIG_USB_MUSB_HDRC_MODULE)
- static struct resource musb_resources[] = {
- 	[0] = {
-@@ -243,14 +227,14 @@ static struct resource musb_resources[] = {
- };
- 
- static struct musb_hdrc_platform_data musb_plat = {
--#ifdef CONFIG_USB_MUSB_OTG
-+#if defined(CONFIG_USB_MUSB_OTG)
- 	.mode		= MUSB_OTG,
--#elif CONFIG_USB_MUSB_HDRC_HCD
-+#elif defined(CONFIG_USB_MUSB_HDRC_HCD)
- 	.mode		= MUSB_HOST,
--#elif CONFIG_USB_GADGET_MUSB_HDRC
-+#elif defined(CONFIG_USB_GADGET_MUSB_HDRC)
- 	.mode		= MUSB_PERIPHERAL,
- #endif
--	.multipoint	= 1,
-+	.multipoint	= 0,
- };
- 
- static u64 musb_dmamask = ~(u32)0;
-@@ -344,6 +328,44 @@ static struct platform_device bf54x_sdh_device = {
- };
- #endif
- 
-+static struct mtd_partition ezkit_partitions[] = {
-+	{
-+		.name       = "Bootloader",
-+		.size       = 0x20000,
-+		.offset     = 0,
-+	}, {
-+		.name       = "Kernel",
-+		.size       = 0xE0000,
-+		.offset     = MTDPART_OFS_APPEND,
-+	}, {
-+		.name       = "RootFS",
-+		.size       = MTDPART_SIZ_FULL,
-+		.offset     = MTDPART_OFS_APPEND,
-+	}
-+};
-+
-+static struct physmap_flash_data ezkit_flash_data = {
-+	.width      = 2,
-+	.parts      = ezkit_partitions,
-+	.nr_parts   = ARRAY_SIZE(ezkit_partitions),
-+};
-+
-+static struct resource ezkit_flash_resource = {
-+	.start = 0x20000000,
-+	.end   = 0x20ffffff,
-+	.flags = IORESOURCE_MEM,
-+};
-+
-+static struct platform_device ezkit_flash_device = {
-+	.name          = "physmap-flash",
-+	.id            = 0,
-+	.dev = {
-+		.platform_data = &ezkit_flash_data,
-+	},
-+	.num_resources = 1,
-+	.resource      = &ezkit_flash_resource,
-+};
-+
- #if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
- /* all SPI peripherals info goes here */
- #if defined(CONFIG_MTD_M25P80) \
-@@ -531,6 +553,29 @@ static struct platform_device i2c_bfin_twi1_device = {
- #endif
- #endif
- 
-+#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
-+#include <linux/gpio_keys.h>
-+
-+static struct gpio_keys_button bfin_gpio_keys_table[] = {
-+	{BTN_0, GPIO_PB8, 1, "gpio-keys: BTN0"},
-+	{BTN_1, GPIO_PB9, 1, "gpio-keys: BTN1"},
-+	{BTN_2, GPIO_PB10, 1, "gpio-keys: BTN2"},
-+	{BTN_3, GPIO_PB11, 1, "gpio-keys: BTN3"},
-+};
-+
-+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 platform_device *ezkit_devices[] __initdata = {
- #if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE)
- 	&rtc_device,
-@@ -548,10 +593,6 @@ static struct platform_device *ezkit_devices[] __initdata = {
- 	&smsc911x_device,
- #endif
- 
--#if defined(CONFIG_USB_BF54x_HCD) || defined(CONFIG_USB_BF54x_HCD_MODULE)
--	&bf54x_hcd,
+-void show_task(unsigned long *sp)
+-{
+-	show_stack(NULL, sp);
+-}
+-
+-void dump_stack(void)
+-{
+-	show_task(NULL);
+-}
+-/* Needed by any user of WARN_ON in view of the defn in include/asm-sh/bug.h */
+-EXPORT_SYMBOL(dump_stack);
+-
+-static void do_unhandled_exception(int trapnr, int signr, char *str, char *fn_name,
+-		unsigned long error_code, struct pt_regs *regs, struct task_struct *tsk)
+-{
+-	show_excp_regs(fn_name, trapnr, signr, regs);
+-	tsk->thread.error_code = error_code;
+-	tsk->thread.trap_no = trapnr;
+-
+-	if (user_mode(regs))
+-		force_sig(signr, tsk);
+-
+-	die_if_no_fixup(str, regs, error_code);
+-}
+-
+-static int read_opcode(unsigned long long pc, unsigned long *result_opcode, int from_user_mode)
+-{
+-	int get_user_error;
+-	unsigned long aligned_pc;
+-	unsigned long opcode;
+-
+-	if ((pc & 3) == 1) {
+-		/* SHmedia */
+-		aligned_pc = pc & ~3;
+-		if (from_user_mode) {
+-			if (!access_ok(VERIFY_READ, aligned_pc, sizeof(unsigned long))) {
+-				get_user_error = -EFAULT;
+-			} else {
+-				get_user_error = __get_user(opcode, (unsigned long *)aligned_pc);
+-				*result_opcode = opcode;
+-			}
+-			return get_user_error;
+-		} else {
+-			/* If the fault was in the kernel, we can either read
+-			 * this directly, or if not, we fault.
+-			*/
+-			*result_opcode = *(unsigned long *) aligned_pc;
+-			return 0;
+-		}
+-	} else if ((pc & 1) == 0) {
+-		/* SHcompact */
+-		/* TODO : provide handling for this.  We don't really support
+-		   user-mode SHcompact yet, and for a kernel fault, this would
+-		   have to come from a module built for SHcompact.  */
+-		return -EFAULT;
+-	} else {
+-		/* misaligned */
+-		return -EFAULT;
+-	}
+-}
+-
+-static int address_is_sign_extended(__u64 a)
+-{
+-	__u64 b;
+-#if (NEFF == 32)
+-	b = (__u64)(__s64)(__s32)(a & 0xffffffffUL);
+-	return (b == a) ? 1 : 0;
+-#else
+-#error "Sign extend check only works for NEFF==32"
 -#endif
+-}
 -
- #if defined(CONFIG_USB_MUSB_HDRC) || defined(CONFIG_USB_MUSB_HDRC_MODULE)
- 	&musb_device,
- #endif
-@@ -583,6 +624,11 @@ static struct platform_device *ezkit_devices[] __initdata = {
- 	&i2c_bfin_twi1_device,
- #endif
- #endif
-+
-+#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
-+	&bfin_device_gpiokeys,
-+#endif
-+	&ezkit_flash_device,
- };
- 
- static int __init stamp_init(void)
-diff --git a/arch/blackfin/mach-bf548/head.S b/arch/blackfin/mach-bf548/head.S
-index 74b34c7..74fe258 100644
---- a/arch/blackfin/mach-bf548/head.S
-+++ b/arch/blackfin/mach-bf548/head.S
-@@ -298,8 +298,8 @@ ENTRY(_start_dma_code)
- 	w[p0] = r0.l;
- 	ssync;
- 
--	p0.h = hi(SIC_IWR);
--	p0.l = lo(SIC_IWR);
-+	p0.h = hi(SIC_IWR0);
-+	p0.l = lo(SIC_IWR0);
- 	r0.l = 0x1;
- 	r0.h = 0x0;
- 	[p0] = r0;
-@@ -324,12 +324,25 @@ ENTRY(_start_dma_code)
- 	w[p0] = r0.l;
- 	ssync;
- 
-+#if defined(CONFIG_BF54x)
-+	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)
-+.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,                  */
-@@ -361,6 +374,39 @@ ENTRY(_start_dma_code)
- 	w[p0] = r0.l;
- 	ssync;
- 
-+#if defined(CONFIG_BF54x)
-+	P2.H = hi(EBIU_RSTCTL);
-+	P2.L = lo(EBIU_RSTCTL);
-+	R0 = [P2];
-+	CC = BITTST(R0, 0);
-+	if CC jump .Lskipddrrst;
-+	BITSET (R0, 0);
-+.Lskipddrrst:
-+	BITCLR (R0, 3);
-+	[P2] = R0;
-+	SSYNC;
-+
-+	p0.l = lo(EBIU_DDRCTL0);
-+	p0.h = hi(EBIU_DDRCTL0);
-+	r0.l = lo(mem_DDRCTL0);
-+	r0.h = hi(mem_DDRCTL0);
-+	[p0] = r0;
-+	ssync;
-+
-+	p0.l = lo(EBIU_DDRCTL1);
-+	p0.h = hi(EBIU_DDRCTL1);
-+	r0.l = lo(mem_DDRCTL1);
-+	r0.h = hi(mem_DDRCTL1);
-+	[p0] = r0;
-+	ssync;
-+
-+	p0.l = lo(EBIU_DDRCTL2);
-+	p0.h = hi(EBIU_DDRCTL2);
-+	r0.l = lo(mem_DDRCTL2);
-+	r0.h = hi(mem_DDRCTL2);
-+	[p0] = r0;
-+	ssync;
-+#else
- 	p0.l = lo(EBIU_SDRRC);
- 	p0.h = hi(EBIU_SDRRC);
- 	r0 = mem_SDRRC;
-@@ -394,9 +440,10 @@ ENTRY(_start_dma_code)
- 	R1 = R1 | R0;
- 	[P2] = R1;
- 	SSYNC;
-+#endif
- 
--	p0.h = hi(SIC_IWR);
--	p0.l = lo(SIC_IWR);
-+	p0.h = hi(SIC_IWR0);
-+	p0.l = lo(SIC_IWR0);
- 	r0.l = lo(IWR_ENABLE_ALL);
- 	r0.h = hi(IWR_ENABLE_ALL);
- 	[p0] = r0;
-diff --git a/arch/blackfin/mach-bf548/ints-priority.c b/arch/blackfin/mach-bf548/ints-priority.c
-index cb0ebac..2665653 100644
---- a/arch/blackfin/mach-bf548/ints-priority.c
-+++ b/arch/blackfin/mach-bf548/ints-priority.c
-@@ -4,7 +4,7 @@
-  * Author:       Michael Hennerich
-  *
-  * Created:
-- * Description:  Set up the interupt priorities
-+ * Description:  Set up the interrupt priorities
-  *
-  * Modified:
-  *               Copyright 2004-2006 Analog Devices Inc.
-@@ -58,7 +58,7 @@ void program_IAR(void)
- 			    ((CONFIG_IRQ_PINT1 - 7) << IRQ_PINT1_POS) |
- 			    ((CONFIG_IRQ_MDMAS0 - 7) << IRQ_MDMAS0_POS) |
- 			    ((CONFIG_IRQ_MDMAS1 - 7) << IRQ_MDMAS1_POS) |
--			    ((CONFIG_IRQ_WATCHDOG - 7) << IRQ_WATCHDOG_POS));
-+			    ((CONFIG_IRQ_WATCHDOG - 7) << IRQ_WATCH_POS));
- 
- 	bfin_write_SIC_IAR3(((CONFIG_IRQ_DMAC1_ERR - 7) << IRQ_DMAC1_ERR_POS) |
- 			    ((CONFIG_IRQ_SPORT2_ERR - 7) << IRQ_SPORT2_ERR_POS) |
-diff --git a/arch/blackfin/mach-bf561/boards/cm_bf561.c b/arch/blackfin/mach-bf561/boards/cm_bf561.c
-index c19cd29..3a79a90 100644
---- a/arch/blackfin/mach-bf561/boards/cm_bf561.c
-+++ b/arch/blackfin/mach-bf561/boards/cm_bf561.c
-@@ -198,6 +198,13 @@ static struct platform_device bfin_spi0_device = {
- #endif  /* spi master and devices */
- 
- 
-+#if defined(CONFIG_FB_HITACHI_TX09) || defined(CONFIG_FB_HITACHI_TX09_MODULE)
-+static struct platform_device hitachi_fb_device = {
-+	.name = "hitachi-tx09",
-+};
-+#endif
-+
-+
- #if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
- 
- static struct resource smc91x_resources[] = {
-@@ -315,6 +322,10 @@ static struct platform_device bfin_pata_device = {
- 
- static struct platform_device *cm_bf561_devices[] __initdata = {
- 
-+#if defined(CONFIG_FB_HITACHI_TX09) || defined(CONFIG_FB_HITACHI_TX09_MODULE)
-+	&hitachi_fb_device,
-+#endif
-+
- #if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
- 	&bfin_uart_device,
- #endif
-diff --git a/arch/blackfin/mach-bf561/boards/ezkit.c b/arch/blackfin/mach-bf561/boards/ezkit.c
-index 4ff8f6e..7601c3b 100644
---- a/arch/blackfin/mach-bf561/boards/ezkit.c
-+++ b/arch/blackfin/mach-bf561/boards/ezkit.c
-@@ -29,6 +29,9 @@
- 
- #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/irq.h>
- #include <linux/interrupt.h>
-@@ -155,6 +158,44 @@ static struct platform_device bfin_uart_device = {
- };
- #endif
- 
-+static struct mtd_partition ezkit_partitions[] = {
-+	{
-+		.name       = "Bootloader",
-+		.size       = 0x20000,
-+		.offset     = 0,
-+	}, {
-+		.name       = "Kernel",
-+		.size       = 0xE0000,
-+		.offset     = MTDPART_OFS_APPEND,
-+	}, {
-+		.name       = "RootFS",
-+		.size       = MTDPART_SIZ_FULL,
-+		.offset     = MTDPART_OFS_APPEND,
-+	}
-+};
-+
-+static struct physmap_flash_data ezkit_flash_data = {
-+	.width      = 2,
-+	.parts      = ezkit_partitions,
-+	.nr_parts   = ARRAY_SIZE(ezkit_partitions),
-+};
-+
-+static struct resource ezkit_flash_resource = {
-+	.start = 0x20000000,
-+	.end   = 0x207fffff,
-+	.flags = IORESOURCE_MEM,
-+};
-+
-+static struct platform_device ezkit_flash_device = {
-+	.name          = "physmap-flash",
-+	.id            = 0,
-+	.dev = {
-+		.platform_data = &ezkit_flash_data,
-+	},
-+	.num_resources = 1,
-+	.resource      = &ezkit_flash_resource,
-+};
-+
- #ifdef CONFIG_SPI_BFIN
- #if defined(CONFIG_SND_BLACKFIN_AD1836) \
- 	|| defined(CONFIG_SND_BLACKFIN_AD1836_MODULE)
-@@ -246,6 +287,50 @@ static struct platform_device bfin_pata_device = {
- };
- #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_PF5, 1, "gpio-keys: BTN0"},
-+	{BTN_1, GPIO_PF6, 1, "gpio-keys: BTN1"},
-+	{BTN_2, GPIO_PF7, 1, "gpio-keys: BTN2"},
-+	{BTN_3, GPIO_PF8, 1, "gpio-keys: BTN3"},
-+};
-+
-+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
-+
-+#if defined(CONFIG_I2C_GPIO) || defined(CONFIG_I2C_GPIO_MODULE)
-+#include <linux/i2c-gpio.h>
-+
-+static struct i2c_gpio_platform_data i2c_gpio_data = {
-+	.sda_pin		= 1,
-+	.scl_pin		= 0,
-+	.sda_is_open_drain	= 0,
-+	.scl_is_open_drain	= 0,
-+	.udelay			= 40,
-+};
-+
-+static struct platform_device i2c_gpio_device = {
-+	.name		= "i2c-gpio",
-+	.id		= 0,
-+	.dev		= {
-+		.platform_data	= &i2c_gpio_data,
-+	},
-+};
-+#endif
-+
- static struct platform_device *ezkit_devices[] __initdata = {
- #if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
- 	&smc91x_device,
-@@ -258,12 +343,23 @@ static struct platform_device *ezkit_devices[] __initdata = {
- #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_PATA_PLATFORM) || defined(CONFIG_PATA_PLATFORM_MODULE)
- 	&bfin_pata_device,
- #endif
-+
-+#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
-+	&bfin_device_gpiokeys,
-+#endif
-+
-+#if defined(CONFIG_I2C_GPIO) || defined(CONFIG_I2C_GPIO_MODULE)
-+	&i2c_gpio_device,
-+#endif
-+	&ezkit_flash_device,
- };
- 
- static int __init ezkit_init(void)
-diff --git a/arch/blackfin/mach-bf561/coreb.c b/arch/blackfin/mach-bf561/coreb.c
-index 5d1d21b..1b44e9e 100644
---- a/arch/blackfin/mach-bf561/coreb.c
-+++ b/arch/blackfin/mach-bf561/coreb.c
-@@ -33,7 +33,9 @@
- #include <linux/ioport.h>
- #include <linux/module.h>
- #include <linux/uaccess.h>
-+#include <linux/fs.h>
- #include <asm/dma.h>
-+#include <asm/cacheflush.h>
- 
- #define MODULE_VER		"v0.1"
- 
-@@ -90,11 +92,12 @@ static ssize_t coreb_write(struct file *file, const char *buf, size_t count,
- 
- 		coreb_dma_done = 0;
- 
-+		flush_dcache_range((unsigned long)buf, (unsigned long)(buf+len));
- 		/* Source Channel */
- 		set_dma_start_addr(CH_MEM_STREAM2_SRC, (unsigned long)buf);
- 		set_dma_x_count(CH_MEM_STREAM2_SRC, len);
- 		set_dma_x_modify(CH_MEM_STREAM2_SRC, sizeof(char));
--		set_dma_config(CH_MEM_STREAM2_SRC, RESTART);
-+		set_dma_config(CH_MEM_STREAM2_SRC, 0);
- 		/* Destination Channel */
- 		set_dma_start_addr(CH_MEM_STREAM2_DEST, coreb_base + p);
- 		set_dma_x_count(CH_MEM_STREAM2_DEST, len);
-@@ -135,11 +138,12 @@ static ssize_t coreb_read(struct file *file, char *buf, size_t count,
- 
- 		coreb_dma_done = 0;
- 
-+		invalidate_dcache_range((unsigned long)buf, (unsigned long)(buf+len));
- 		/* Source Channel */
- 		set_dma_start_addr(CH_MEM_STREAM2_SRC, coreb_base + p);
- 		set_dma_x_count(CH_MEM_STREAM2_SRC, len);
- 		set_dma_x_modify(CH_MEM_STREAM2_SRC, sizeof(char));
--		set_dma_config(CH_MEM_STREAM2_SRC, RESTART);
-+		set_dma_config(CH_MEM_STREAM2_SRC, 0);
- 		/* Destination Channel */
- 		set_dma_start_addr(CH_MEM_STREAM2_DEST, (unsigned long)buf);
- 		set_dma_x_count(CH_MEM_STREAM2_DEST, len);
-@@ -266,7 +270,7 @@ static int coreb_ioctl(struct inode *inode, struct file *file,
- 		coreb_status |= COREB_IS_RUNNING;
- 		bfin_write_SICA_SYSCR(bfin_read_SICA_SYSCR() & ~0x0020);
- 		SSYNC();
--		spin_lock_irq(&coreb_lock);
-+		spin_unlock_irq(&coreb_lock);
- 		break;
- #if defined(CONFIG_BF561_COREB_RESET)
- 	case CMD_COREB_STOP:
-@@ -275,7 +279,7 @@ static int coreb_ioctl(struct inode *inode, struct file *file,
- 		bfin_write_SICA_SYSCR(bfin_read_SICA_SYSCR() | 0x0020);
- 		bfin_write_SICB_SYSCR(bfin_read_SICB_SYSCR() | 0x0080);
- 		coreb_status &= ~COREB_IS_RUNNING;
--		spin_lock_irq(&coreb_lock);
-+		spin_unlock_irq(&coreb_lock);
- 		break;
- 	case CMD_COREB_RESET:
- 		printk(KERN_INFO "Resetting Core B\n");
-diff --git a/arch/blackfin/mach-common/Makefile b/arch/blackfin/mach-common/Makefile
-index 4d7733d..8636d42 100644
---- a/arch/blackfin/mach-common/Makefile
-+++ b/arch/blackfin/mach-common/Makefile
-@@ -3,10 +3,9 @@
- #
- 
- obj-y := \
--	cache.o cacheinit.o cplbhdlr.o cplbmgr.o entry.o \
-+	cache.o cacheinit.o entry.o \
- 	interrupt.o lock.o irqpanic.o arch_checks.o
- 
--obj-$(CONFIG_CPLB_INFO)          += cplbinfo.o
- obj-$(CONFIG_BFIN_SINGLE_CORE)   += ints-priority-sc.o
- obj-$(CONFIG_BFIN_DUAL_CORE)     += ints-priority-dc.o
- obj-$(CONFIG_PM)                 += pm.o dpmc.o
-diff --git a/arch/blackfin/mach-common/cplbhdlr.S b/arch/blackfin/mach-common/cplbhdlr.S
+-static int generate_and_check_address(struct pt_regs *regs,
+-				      __u32 opcode,
+-				      int displacement_not_indexed,
+-				      int width_shift,
+-				      __u64 *address)
+-{
+-	/* return -1 for fault, 0 for OK */
+-
+-	__u64 base_address, addr;
+-	int basereg;
+-
+-	basereg = (opcode >> 20) & 0x3f;
+-	base_address = regs->regs[basereg];
+-	if (displacement_not_indexed) {
+-		__s64 displacement;
+-		displacement = (opcode >> 10) & 0x3ff;
+-		displacement = ((displacement << 54) >> 54); /* sign extend */
+-		addr = (__u64)((__s64)base_address + (displacement << width_shift));
+-	} else {
+-		__u64 offset;
+-		int offsetreg;
+-		offsetreg = (opcode >> 10) & 0x3f;
+-		offset = regs->regs[offsetreg];
+-		addr = base_address + offset;
+-	}
+-
+-	/* Check sign extended */
+-	if (!address_is_sign_extended(addr)) {
+-		return -1;
+-	}
+-
+-#if defined(CONFIG_SH64_USER_MISALIGNED_FIXUP)
+-	/* Check accessible.  For misaligned access in the kernel, assume the
+-	   address is always accessible (and if not, just fault when the
+-	   load/store gets done.) */
+-	if (user_mode(regs)) {
+-		if (addr >= TASK_SIZE) {
+-			return -1;
+-		}
+-		/* Do access_ok check later - it depends on whether it's a load or a store. */
+-	}
+-#endif
+-
+-	*address = addr;
+-	return 0;
+-}
+-
+-/* Default value as for sh */
+-#if defined(CONFIG_SH64_USER_MISALIGNED_FIXUP)
+-static int user_mode_unaligned_fixup_count = 10;
+-static int user_mode_unaligned_fixup_enable = 1;
+-#endif
+-
+-static int kernel_mode_unaligned_fixup_count = 32;
+-
+-static void misaligned_kernel_word_load(__u64 address, int do_sign_extend, __u64 *result)
+-{
+-	unsigned short x;
+-	unsigned char *p, *q;
+-	p = (unsigned char *) (int) address;
+-	q = (unsigned char *) &x;
+-	q[0] = p[0];
+-	q[1] = p[1];
+-
+-	if (do_sign_extend) {
+-		*result = (__u64)(__s64) *(short *) &x;
+-	} else {
+-		*result = (__u64) x;
+-	}
+-}
+-
+-static void misaligned_kernel_word_store(__u64 address, __u64 value)
+-{
+-	unsigned short x;
+-	unsigned char *p, *q;
+-	p = (unsigned char *) (int) address;
+-	q = (unsigned char *) &x;
+-
+-	x = (__u16) value;
+-	p[0] = q[0];
+-	p[1] = q[1];
+-}
+-
+-static int misaligned_load(struct pt_regs *regs,
+-			   __u32 opcode,
+-			   int displacement_not_indexed,
+-			   int width_shift,
+-			   int do_sign_extend)
+-{
+-	/* Return -1 for a fault, 0 for OK */
+-	int error;
+-	int destreg;
+-	__u64 address;
+-
+-	error = generate_and_check_address(regs, opcode,
+-			displacement_not_indexed, width_shift, &address);
+-	if (error < 0) {
+-		return error;
+-	}
+-
+-	destreg = (opcode >> 4) & 0x3f;
+-#if defined(CONFIG_SH64_USER_MISALIGNED_FIXUP)
+-	if (user_mode(regs)) {
+-		__u64 buffer;
+-
+-		if (!access_ok(VERIFY_READ, (unsigned long) address, 1UL<<width_shift)) {
+-			return -1;
+-		}
+-
+-		if (__copy_user(&buffer, (const void *)(int)address, (1 << width_shift)) > 0) {
+-			return -1; /* fault */
+-		}
+-		switch (width_shift) {
+-		case 1:
+-			if (do_sign_extend) {
+-				regs->regs[destreg] = (__u64)(__s64) *(__s16 *) &buffer;
+-			} else {
+-				regs->regs[destreg] = (__u64) *(__u16 *) &buffer;
+-			}
+-			break;
+-		case 2:
+-			regs->regs[destreg] = (__u64)(__s64) *(__s32 *) &buffer;
+-			break;
+-		case 3:
+-			regs->regs[destreg] = buffer;
+-			break;
+-		default:
+-			printk("Unexpected width_shift %d in misaligned_load, PC=%08lx\n",
+-				width_shift, (unsigned long) regs->pc);
+-			break;
+-		}
+-	} else
+-#endif
+-	{
+-		/* kernel mode - we can take short cuts since if we fault, it's a genuine bug */
+-		__u64 lo, hi;
+-
+-		switch (width_shift) {
+-		case 1:
+-			misaligned_kernel_word_load(address, do_sign_extend, &regs->regs[destreg]);
+-			break;
+-		case 2:
+-			asm ("ldlo.l %1, 0, %0" : "=r" (lo) : "r" (address));
+-			asm ("ldhi.l %1, 3, %0" : "=r" (hi) : "r" (address));
+-			regs->regs[destreg] = lo | hi;
+-			break;
+-		case 3:
+-			asm ("ldlo.q %1, 0, %0" : "=r" (lo) : "r" (address));
+-			asm ("ldhi.q %1, 7, %0" : "=r" (hi) : "r" (address));
+-			regs->regs[destreg] = lo | hi;
+-			break;
+-
+-		default:
+-			printk("Unexpected width_shift %d in misaligned_load, PC=%08lx\n",
+-				width_shift, (unsigned long) regs->pc);
+-			break;
+-		}
+-	}
+-
+-	return 0;
+-
+-}
+-
+-static int misaligned_store(struct pt_regs *regs,
+-			    __u32 opcode,
+-			    int displacement_not_indexed,
+-			    int width_shift)
+-{
+-	/* Return -1 for a fault, 0 for OK */
+-	int error;
+-	int srcreg;
+-	__u64 address;
+-
+-	error = generate_and_check_address(regs, opcode,
+-			displacement_not_indexed, width_shift, &address);
+-	if (error < 0) {
+-		return error;
+-	}
+-
+-	srcreg = (opcode >> 4) & 0x3f;
+-#if defined(CONFIG_SH64_USER_MISALIGNED_FIXUP)
+-	if (user_mode(regs)) {
+-		__u64 buffer;
+-
+-		if (!access_ok(VERIFY_WRITE, (unsigned long) address, 1UL<<width_shift)) {
+-			return -1;
+-		}
+-
+-		switch (width_shift) {
+-		case 1:
+-			*(__u16 *) &buffer = (__u16) regs->regs[srcreg];
+-			break;
+-		case 2:
+-			*(__u32 *) &buffer = (__u32) regs->regs[srcreg];
+-			break;
+-		case 3:
+-			buffer = regs->regs[srcreg];
+-			break;
+-		default:
+-			printk("Unexpected width_shift %d in misaligned_store, PC=%08lx\n",
+-				width_shift, (unsigned long) regs->pc);
+-			break;
+-		}
+-
+-		if (__copy_user((void *)(int)address, &buffer, (1 << width_shift)) > 0) {
+-			return -1; /* fault */
+-		}
+-	} else
+-#endif
+-	{
+-		/* kernel mode - we can take short cuts since if we fault, it's a genuine bug */
+-		__u64 val = regs->regs[srcreg];
+-
+-		switch (width_shift) {
+-		case 1:
+-			misaligned_kernel_word_store(address, val);
+-			break;
+-		case 2:
+-			asm ("stlo.l %1, 0, %0" : : "r" (val), "r" (address));
+-			asm ("sthi.l %1, 3, %0" : : "r" (val), "r" (address));
+-			break;
+-		case 3:
+-			asm ("stlo.q %1, 0, %0" : : "r" (val), "r" (address));
+-			asm ("sthi.q %1, 7, %0" : : "r" (val), "r" (address));
+-			break;
+-
+-		default:
+-			printk("Unexpected width_shift %d in misaligned_store, PC=%08lx\n",
+-				width_shift, (unsigned long) regs->pc);
+-			break;
+-		}
+-	}
+-
+-	return 0;
+-
+-}
+-
+-#if defined(CONFIG_SH64_USER_MISALIGNED_FIXUP)
+-/* Never need to fix up misaligned FPU accesses within the kernel since that's a real
+-   error. */
+-static int misaligned_fpu_load(struct pt_regs *regs,
+-			   __u32 opcode,
+-			   int displacement_not_indexed,
+-			   int width_shift,
+-			   int do_paired_load)
+-{
+-	/* Return -1 for a fault, 0 for OK */
+-	int error;
+-	int destreg;
+-	__u64 address;
+-
+-	error = generate_and_check_address(regs, opcode,
+-			displacement_not_indexed, width_shift, &address);
+-	if (error < 0) {
+-		return error;
+-	}
+-
+-	destreg = (opcode >> 4) & 0x3f;
+-	if (user_mode(regs)) {
+-		__u64 buffer;
+-		__u32 buflo, bufhi;
+-
+-		if (!access_ok(VERIFY_READ, (unsigned long) address, 1UL<<width_shift)) {
+-			return -1;
+-		}
+-
+-		if (__copy_user(&buffer, (const void *)(int)address, (1 << width_shift)) > 0) {
+-			return -1; /* fault */
+-		}
+-		/* 'current' may be the current owner of the FPU state, so
+-		   context switch the registers into memory so they can be
+-		   indexed by register number. */
+-		if (last_task_used_math == current) {
+-			grab_fpu();
+-			fpsave(&current->thread.fpu.hard);
+-			release_fpu();
+-			last_task_used_math = NULL;
+-			regs->sr |= SR_FD;
+-		}
+-
+-		buflo = *(__u32*) &buffer;
+-		bufhi = *(1 + (__u32*) &buffer);
+-
+-		switch (width_shift) {
+-		case 2:
+-			current->thread.fpu.hard.fp_regs[destreg] = buflo;
+-			break;
+-		case 3:
+-			if (do_paired_load) {
+-				current->thread.fpu.hard.fp_regs[destreg] = buflo;
+-				current->thread.fpu.hard.fp_regs[destreg+1] = bufhi;
+-			} else {
+-#if defined(CONFIG_LITTLE_ENDIAN)
+-				current->thread.fpu.hard.fp_regs[destreg] = bufhi;
+-				current->thread.fpu.hard.fp_regs[destreg+1] = buflo;
+-#else
+-				current->thread.fpu.hard.fp_regs[destreg] = buflo;
+-				current->thread.fpu.hard.fp_regs[destreg+1] = bufhi;
+-#endif
+-			}
+-			break;
+-		default:
+-			printk("Unexpected width_shift %d in misaligned_fpu_load, PC=%08lx\n",
+-				width_shift, (unsigned long) regs->pc);
+-			break;
+-		}
+-		return 0;
+-	} else {
+-		die ("Misaligned FPU load inside kernel", regs, 0);
+-		return -1;
+-	}
+-
+-
+-}
+-
+-static int misaligned_fpu_store(struct pt_regs *regs,
+-			   __u32 opcode,
+-			   int displacement_not_indexed,
+-			   int width_shift,
+-			   int do_paired_load)
+-{
+-	/* Return -1 for a fault, 0 for OK */
+-	int error;
+-	int srcreg;
+-	__u64 address;
+-
+-	error = generate_and_check_address(regs, opcode,
+-			displacement_not_indexed, width_shift, &address);
+-	if (error < 0) {
+-		return error;
+-	}
+-
+-	srcreg = (opcode >> 4) & 0x3f;
+-	if (user_mode(regs)) {
+-		__u64 buffer;
+-		/* Initialise these to NaNs. */
+-		__u32 buflo=0xffffffffUL, bufhi=0xffffffffUL;
+-
+-		if (!access_ok(VERIFY_WRITE, (unsigned long) address, 1UL<<width_shift)) {
+-			return -1;
+-		}
+-
+-		/* 'current' may be the current owner of the FPU state, so
+-		   context switch the registers into memory so they can be
+-		   indexed by register number. */
+-		if (last_task_used_math == current) {
+-			grab_fpu();
+-			fpsave(&current->thread.fpu.hard);
+-			release_fpu();
+-			last_task_used_math = NULL;
+-			regs->sr |= SR_FD;
+-		}
+-
+-		switch (width_shift) {
+-		case 2:
+-			buflo = current->thread.fpu.hard.fp_regs[srcreg];
+-			break;
+-		case 3:
+-			if (do_paired_load) {
+-				buflo = current->thread.fpu.hard.fp_regs[srcreg];
+-				bufhi = current->thread.fpu.hard.fp_regs[srcreg+1];
+-			} else {
+-#if defined(CONFIG_LITTLE_ENDIAN)
+-				bufhi = current->thread.fpu.hard.fp_regs[srcreg];
+-				buflo = current->thread.fpu.hard.fp_regs[srcreg+1];
+-#else
+-				buflo = current->thread.fpu.hard.fp_regs[srcreg];
+-				bufhi = current->thread.fpu.hard.fp_regs[srcreg+1];
+-#endif
+-			}
+-			break;
+-		default:
+-			printk("Unexpected width_shift %d in misaligned_fpu_store, PC=%08lx\n",
+-				width_shift, (unsigned long) regs->pc);
+-			break;
+-		}
+-
+-		*(__u32*) &buffer = buflo;
+-		*(1 + (__u32*) &buffer) = bufhi;
+-		if (__copy_user((void *)(int)address, &buffer, (1 << width_shift)) > 0) {
+-			return -1; /* fault */
+-		}
+-		return 0;
+-	} else {
+-		die ("Misaligned FPU load inside kernel", regs, 0);
+-		return -1;
+-	}
+-}
+-#endif
+-
+-static int misaligned_fixup(struct pt_regs *regs)
+-{
+-	unsigned long opcode;
+-	int error;
+-	int major, minor;
+-
+-#if !defined(CONFIG_SH64_USER_MISALIGNED_FIXUP)
+-	/* Never fixup user mode misaligned accesses without this option enabled. */
+-	return -1;
+-#else
+-	if (!user_mode_unaligned_fixup_enable) return -1;
+-#endif
+-
+-	error = read_opcode(regs->pc, &opcode, user_mode(regs));
+-	if (error < 0) {
+-		return error;
+-	}
+-	major = (opcode >> 26) & 0x3f;
+-	minor = (opcode >> 16) & 0xf;
+-
+-#if defined(CONFIG_SH64_USER_MISALIGNED_FIXUP)
+-	if (user_mode(regs) && (user_mode_unaligned_fixup_count > 0)) {
+-		--user_mode_unaligned_fixup_count;
+-		/* Only do 'count' worth of these reports, to remove a potential DoS against syslog */
+-		printk("Fixing up unaligned userspace access in \"%s\" pid=%d pc=0x%08x ins=0x%08lx\n",
+-		       current->comm, task_pid_nr(current), (__u32)regs->pc, opcode);
+-	} else
+-#endif
+-	if (!user_mode(regs) && (kernel_mode_unaligned_fixup_count > 0)) {
+-		--kernel_mode_unaligned_fixup_count;
+-		if (in_interrupt()) {
+-			printk("Fixing up unaligned kernelspace access in interrupt pc=0x%08x ins=0x%08lx\n",
+-			       (__u32)regs->pc, opcode);
+-		} else {
+-			printk("Fixing up unaligned kernelspace access in \"%s\" pid=%d pc=0x%08x ins=0x%08lx\n",
+-			       current->comm, task_pid_nr(current), (__u32)regs->pc, opcode);
+-		}
+-	}
+-
+-
+-	switch (major) {
+-		case (0x84>>2): /* LD.W */
+-			error = misaligned_load(regs, opcode, 1, 1, 1);
+-			break;
+-		case (0xb0>>2): /* LD.UW */
+-			error = misaligned_load(regs, opcode, 1, 1, 0);
+-			break;
+-		case (0x88>>2): /* LD.L */
+-			error = misaligned_load(regs, opcode, 1, 2, 1);
+-			break;
+-		case (0x8c>>2): /* LD.Q */
+-			error = misaligned_load(regs, opcode, 1, 3, 0);
+-			break;
+-
+-		case (0xa4>>2): /* ST.W */
+-			error = misaligned_store(regs, opcode, 1, 1);
+-			break;
+-		case (0xa8>>2): /* ST.L */
+-			error = misaligned_store(regs, opcode, 1, 2);
+-			break;
+-		case (0xac>>2): /* ST.Q */
+-			error = misaligned_store(regs, opcode, 1, 3);
+-			break;
+-
+-		case (0x40>>2): /* indexed loads */
+-			switch (minor) {
+-				case 0x1: /* LDX.W */
+-					error = misaligned_load(regs, opcode, 0, 1, 1);
+-					break;
+-				case 0x5: /* LDX.UW */
+-					error = misaligned_load(regs, opcode, 0, 1, 0);
+-					break;
+-				case 0x2: /* LDX.L */
+-					error = misaligned_load(regs, opcode, 0, 2, 1);
+-					break;
+-				case 0x3: /* LDX.Q */
+-					error = misaligned_load(regs, opcode, 0, 3, 0);
+-					break;
+-				default:
+-					error = -1;
+-					break;
+-			}
+-			break;
+-
+-		case (0x60>>2): /* indexed stores */
+-			switch (minor) {
+-				case 0x1: /* STX.W */
+-					error = misaligned_store(regs, opcode, 0, 1);
+-					break;
+-				case 0x2: /* STX.L */
+-					error = misaligned_store(regs, opcode, 0, 2);
+-					break;
+-				case 0x3: /* STX.Q */
+-					error = misaligned_store(regs, opcode, 0, 3);
+-					break;
+-				default:
+-					error = -1;
+-					break;
+-			}
+-			break;
+-
+-#if defined(CONFIG_SH64_USER_MISALIGNED_FIXUP)
+-		case (0x94>>2): /* FLD.S */
+-			error = misaligned_fpu_load(regs, opcode, 1, 2, 0);
+-			break;
+-		case (0x98>>2): /* FLD.P */
+-			error = misaligned_fpu_load(regs, opcode, 1, 3, 1);
+-			break;
+-		case (0x9c>>2): /* FLD.D */
+-			error = misaligned_fpu_load(regs, opcode, 1, 3, 0);
+-			break;
+-		case (0x1c>>2): /* floating indexed loads */
+-			switch (minor) {
+-			case 0x8: /* FLDX.S */
+-				error = misaligned_fpu_load(regs, opcode, 0, 2, 0);
+-				break;
+-			case 0xd: /* FLDX.P */
+-				error = misaligned_fpu_load(regs, opcode, 0, 3, 1);
+-				break;
+-			case 0x9: /* FLDX.D */
+-				error = misaligned_fpu_load(regs, opcode, 0, 3, 0);
+-				break;
+-			default:
+-				error = -1;
+-				break;
+-			}
+-			break;
+-		case (0xb4>>2): /* FLD.S */
+-			error = misaligned_fpu_store(regs, opcode, 1, 2, 0);
+-			break;
+-		case (0xb8>>2): /* FLD.P */
+-			error = misaligned_fpu_store(regs, opcode, 1, 3, 1);
+-			break;
+-		case (0xbc>>2): /* FLD.D */
+-			error = misaligned_fpu_store(regs, opcode, 1, 3, 0);
+-			break;
+-		case (0x3c>>2): /* floating indexed stores */
+-			switch (minor) {
+-			case 0x8: /* FSTX.S */
+-				error = misaligned_fpu_store(regs, opcode, 0, 2, 0);
+-				break;
+-			case 0xd: /* FSTX.P */
+-				error = misaligned_fpu_store(regs, opcode, 0, 3, 1);
+-				break;
+-			case 0x9: /* FSTX.D */
+-				error = misaligned_fpu_store(regs, opcode, 0, 3, 0);
+-				break;
+-			default:
+-				error = -1;
+-				break;
+-			}
+-			break;
+-#endif
+-
+-		default:
+-			/* Fault */
+-			error = -1;
+-			break;
+-	}
+-
+-	if (error < 0) {
+-		return error;
+-	} else {
+-		regs->pc += 4; /* Skip the instruction that's just been emulated */
+-		return 0;
+-	}
+-
+-}
+-
+-static ctl_table unaligned_table[] = {
+-	{
+-		.ctl_name	= CTL_UNNUMBERED,
+-		.procname	= "kernel_reports",
+-		.data		= &kernel_mode_unaligned_fixup_count,
+-		.maxlen		= sizeof(int),
+-		.mode		= 0644,
+-		.proc_handler	= &proc_dointvec
+-	},
+-#if defined(CONFIG_SH64_USER_MISALIGNED_FIXUP)
+-	{
+-		.ctl_name	= CTL_UNNUMBERED,
+-		.procname	= "user_reports",
+-		.data		= &user_mode_unaligned_fixup_count,
+-		.maxlen		= sizeof(int),
+-		.mode		= 0644,
+-		.proc_handler	= &proc_dointvec
+-	},
+-	{
+-		.ctl_name	= CTL_UNNUMBERED,
+-		.procname	= "user_enable",
+-		.data		= &user_mode_unaligned_fixup_enable,
+-		.maxlen		= sizeof(int),
+-		.mode		= 0644,
+-		.proc_handler	= &proc_dointvec},
+-#endif
+-	{}
+-};
+-
+-static ctl_table unaligned_root[] = {
+-	{
+-		.ctl_name	= CTL_UNNUMBERED,
+-		.procname	= "unaligned_fixup",
+-		.mode		= 0555,
+-		unaligned_table
+-	},
+-	{}
+-};
+-
+-static ctl_table sh64_root[] = {
+-	{
+-		.ctl_name	= CTL_UNNUMBERED,
+-		.procname	= "sh64",
+-		.mode		= 0555,
+-		.child		= unaligned_root
+-	},
+-	{}
+-};
+-static struct ctl_table_header *sysctl_header;
+-static int __init init_sysctl(void)
+-{
+-	sysctl_header = register_sysctl_table(sh64_root);
+-	return 0;
+-}
+-
+-__initcall(init_sysctl);
+-
+-
+-asmlinkage void do_debug_interrupt(unsigned long code, struct pt_regs *regs)
+-{
+-	u64 peek_real_address_q(u64 addr);
+-	u64 poke_real_address_q(u64 addr, u64 val);
+-	unsigned long long DM_EXP_CAUSE_PHY = 0x0c100010;
+-	unsigned long long exp_cause;
+-	/* It's not worth ioremapping the debug module registers for the amount
+-	   of access we make to them - just go direct to their physical
+-	   addresses. */
+-	exp_cause = peek_real_address_q(DM_EXP_CAUSE_PHY);
+-	if (exp_cause & ~4) {
+-		printk("DM.EXP_CAUSE had unexpected bits set (=%08lx)\n",
+-			(unsigned long)(exp_cause & 0xffffffff));
+-	}
+-	show_state();
+-	/* Clear all DEBUGINT causes */
+-	poke_real_address_q(DM_EXP_CAUSE_PHY, 0x0);
+-}
+diff --git a/arch/sh64/kernel/unwind.c b/arch/sh64/kernel/unwind.c
 deleted file mode 100644
-index 2788532..0000000
---- a/arch/blackfin/mach-common/cplbhdlr.S
+index 1214c78..0000000
+--- a/arch/sh64/kernel/unwind.c
 +++ /dev/null
-@@ -1,130 +0,0 @@
+@@ -1,326 +0,0 @@
 -/*
-- * File:         arch/blackfin/mach-common/cplbhdlr.S
-- * Based on:
-- * Author:       LG Soft India
+- * arch/sh64/kernel/unwind.c
 - *
-- * Created:      ?
-- * Description:  CPLB exception handler
+- * Copyright (C) 2004  Paul Mundt
+- * Copyright (C) 2004  Richard Curnow
 - *
-- * Modified:
-- *               Copyright 2004-2006 Analog Devices Inc.
+- * This file is subject to the terms and conditions of the GNU General Public
+- * License.  See the file "COPYING" in the main directory of this archive
+- * for more details.
+- */
+-#include <linux/kallsyms.h>
+-#include <linux/kernel.h>
+-#include <linux/types.h>
+-#include <linux/errno.h>
+-#include <asm/page.h>
+-#include <asm/ptrace.h>
+-#include <asm/processor.h>
+-#include <asm/io.h>
+-
+-static u8 regcache[63];
+-
+-/*
+- * Finding the previous stack frame isn't horribly straightforward as it is
+- * on some other platforms. In the sh64 case, we don't have "linked" stack
+- * frames, so we need to do a bit of work to determine the previous frame,
+- * and in turn, the previous r14/r18 pair.
+- *
+- * There are generally a few cases which determine where we can find out
+- * the r14/r18 values. In the general case, this can be determined by poking
+- * around the prologue of the symbol PC is in (note that we absolutely must
+- * have frame pointer support as well as the kernel symbol table mapped,
+- * otherwise we can't even get this far).
+- *
+- * In other cases, such as the interrupt/exception path, we can poke around
+- * the sp/fp.
+- *
+- * Notably, this entire approach is somewhat error prone, and in the event
+- * that the previous frame cannot be determined, that's all we can do.
+- * Either way, this still leaves us with a more correct backtrace then what
+- * we would be able to come up with by walking the stack (which is garbage
+- * for anything beyond the first frame).
+- *						-- PFM.
+- */
+-static int lookup_prev_stack_frame(unsigned long fp, unsigned long pc,
+-		      unsigned long *pprev_fp, unsigned long *pprev_pc,
+-		      struct pt_regs *regs)
+-{
+-	const char *sym;
+-	char namebuf[128];
+-	unsigned long offset;
+-	unsigned long prologue = 0;
+-	unsigned long fp_displacement = 0;
+-	unsigned long fp_prev = 0;
+-	unsigned long offset_r14 = 0, offset_r18 = 0;
+-	int i, found_prologue_end = 0;
+-
+-	sym = kallsyms_lookup(pc, NULL, &offset, NULL, namebuf);
+-	if (!sym)
+-		return -EINVAL;
+-
+-	prologue = pc - offset;
+-	if (!prologue)
+-		return -EINVAL;
+-
+-	/* Validate fp, to avoid risk of dereferencing a bad pointer later.
+-	   Assume 128Mb since that's the amount of RAM on a Cayman.  Modify
+-	   when there is an SH-5 board with more. */
+-	if ((fp < (unsigned long) phys_to_virt(__MEMORY_START)) ||
+-	    (fp >= (unsigned long)(phys_to_virt(__MEMORY_START)) + 128*1024*1024) ||
+-	    ((fp & 7) != 0)) {
+-		return -EINVAL;
+-	}
+-
+-	/*
+-	 * Depth to walk, depth is completely arbitrary.
+-	 */
+-	for (i = 0; i < 100; i++, prologue += sizeof(unsigned long)) {
+-		unsigned long op;
+-		u8 major, minor;
+-		u8 src, dest, disp;
+-
+-		op = *(unsigned long *)prologue;
+-
+-		major = (op >> 26) & 0x3f;
+-		src   = (op >> 20) & 0x3f;
+-		minor = (op >> 16) & 0xf;
+-		disp  = (op >> 10) & 0x3f;
+-		dest  = (op >>  4) & 0x3f;
+-
+-		/*
+-		 * Stack frame creation happens in a number of ways.. in the
+-		 * general case when the stack frame is less than 511 bytes,
+-		 * it's generally created by an addi or addi.l:
+-		 *
+-		 *	addi/addi.l r15, -FRAME_SIZE, r15
+-		 *
+-		 * in the event that the frame size is bigger than this, it's
+-		 * typically created using a movi/sub pair as follows:
+-		 *
+-		 *	movi	FRAME_SIZE, rX
+-		 *	sub	r15, rX, r15
+-		 */
+-
+-		switch (major) {
+-		case (0x00 >> 2):
+-			switch (minor) {
+-			case 0x8: /* add.l */
+-			case 0x9: /* add */
+-				/* Look for r15, r63, r14 */
+-				if (src == 15 && disp == 63 && dest == 14)
+-					found_prologue_end = 1;
+-
+-				break;
+-			case 0xa: /* sub.l */
+-			case 0xb: /* sub */
+-				if (src != 15 || dest != 15)
+-					continue;
+-
+-				fp_displacement -= regcache[disp];
+-				fp_prev = fp - fp_displacement;
+-				break;
+-			}
+-			break;
+-		case (0xa8 >> 2): /* st.l */
+-			if (src != 15)
+-				continue;
+-
+-			switch (dest) {
+-			case 14:
+-				if (offset_r14 || fp_displacement == 0)
+-					continue;
+-
+-				offset_r14 = (u64)(((((s64)op >> 10) & 0x3ff) << 54) >> 54);
+-				offset_r14 *= sizeof(unsigned long);
+-				offset_r14 += fp_displacement;
+-				break;
+-			case 18:
+-				if (offset_r18 || fp_displacement == 0)
+-					continue;
+-
+-				offset_r18 = (u64)(((((s64)op >> 10) & 0x3ff) << 54) >> 54);
+-				offset_r18 *= sizeof(unsigned long);
+-				offset_r18 += fp_displacement;
+-				break;
+-			}
+-
+-			break;
+-		case (0xcc >> 2): /* movi */
+-			if (dest >= 63) {
+-				printk(KERN_NOTICE "%s: Invalid dest reg %d "
+-				       "specified in movi handler. Failed "
+-				       "opcode was 0x%lx: ", __FUNCTION__,
+-				       dest, op);
+-
+-				continue;
+-			}
+-
+-			/* Sign extend */
+-			regcache[dest] =
+-				((((s64)(u64)op >> 10) & 0xffff) << 54) >> 54;
+-			break;
+-		case (0xd0 >> 2): /* addi */
+-		case (0xd4 >> 2): /* addi.l */
+-			/* Look for r15, -FRAME_SIZE, r15 */
+-			if (src != 15 || dest != 15)
+-				continue;
+-
+-			/* Sign extended frame size.. */
+-			fp_displacement +=
+-				(u64)(((((s64)op >> 10) & 0x3ff) << 54) >> 54);
+-			fp_prev = fp - fp_displacement;
+-			break;
+-		}
+-
+-		if (found_prologue_end && offset_r14 && (offset_r18 || *pprev_pc) && fp_prev)
+-			break;
+-	}
+-
+-	if (offset_r14 == 0 || fp_prev == 0) {
+-		if (!offset_r14)
+-			pr_debug("Unable to find r14 offset\n");
+-		if (!fp_prev)
+-			pr_debug("Unable to find previous fp\n");
+-
+-		return -EINVAL;
+-	}
+-
+-	/* For innermost leaf function, there might not be a offset_r18 */
+-	if (!*pprev_pc && (offset_r18 == 0))
+-		return -EINVAL;
+-
+-	*pprev_fp = *(unsigned long *)(fp_prev + offset_r14);
+-
+-	if (offset_r18)
+-		*pprev_pc = *(unsigned long *)(fp_prev + offset_r18);
+-
+-	*pprev_pc &= ~1;
+-
+-	return 0;
+-}
+-
+-/* Don't put this on the stack since we'll want to call sh64_unwind
+- * when we're close to underflowing the stack anyway. */
+-static struct pt_regs here_regs;
+-
+-extern const char syscall_ret;
+-extern const char ret_from_syscall;
+-extern const char ret_from_exception;
+-extern const char ret_from_irq;
+-
+-static void sh64_unwind_inner(struct pt_regs *regs);
+-
+-static void unwind_nested (unsigned long pc, unsigned long fp)
+-{
+-	if ((fp >= __MEMORY_START) &&
+-	    ((fp & 7) == 0)) {
+-		sh64_unwind_inner((struct pt_regs *) fp);
+-	}
+-}
+-
+-static void sh64_unwind_inner(struct pt_regs *regs)
+-{
+-	unsigned long pc, fp;
+-	int ofs = 0;
+-	int first_pass;
+-
+-	pc = regs->pc & ~1;
+-	fp = regs->regs[14];
+-
+-	first_pass = 1;
+-	for (;;) {
+-		int cond;
+-		unsigned long next_fp, next_pc;
+-
+-		if (pc == ((unsigned long) &syscall_ret & ~1)) {
+-			printk("SYSCALL\n");
+-			unwind_nested(pc,fp);
+-			return;
+-		}
+-
+-		if (pc == ((unsigned long) &ret_from_syscall & ~1)) {
+-			printk("SYSCALL (PREEMPTED)\n");
+-			unwind_nested(pc,fp);
+-			return;
+-		}
+-
+-		/* In this case, the PC is discovered by lookup_prev_stack_frame but
+-		   it has 4 taken off it to look like the 'caller' */
+-		if (pc == ((unsigned long) &ret_from_exception & ~1)) {
+-			printk("EXCEPTION\n");
+-			unwind_nested(pc,fp);
+-			return;
+-		}
+-
+-		if (pc == ((unsigned long) &ret_from_irq & ~1)) {
+-			printk("IRQ\n");
+-			unwind_nested(pc,fp);
+-			return;
+-		}
+-
+-		cond = ((pc >= __MEMORY_START) && (fp >= __MEMORY_START) &&
+-			((pc & 3) == 0) && ((fp & 7) == 0));
+-
+-		pc -= ofs;
+-
+-		printk("[<%08lx>] ", pc);
+-		print_symbol("%s\n", pc);
+-
+-		if (first_pass) {
+-			/* If the innermost frame is a leaf function, it's
+-			 * possible that r18 is never saved out to the stack.
+-			 */
+-			next_pc = regs->regs[18];
+-		} else {
+-			next_pc = 0;
+-		}
+-
+-		if (lookup_prev_stack_frame(fp, pc, &next_fp, &next_pc, regs) == 0) {
+-			ofs = sizeof(unsigned long);
+-			pc = next_pc & ~1;
+-			fp = next_fp;
+-		} else {
+-			printk("Unable to lookup previous stack frame\n");
+-			break;
+-		}
+-		first_pass = 0;
+-	}
+-
+-	printk("\n");
+-
+-}
+-
+-void sh64_unwind(struct pt_regs *regs)
+-{
+-	if (!regs) {
+-		/*
+-		 * Fetch current regs if we have no other saved state to back
+-		 * trace from.
+-		 */
+-		regs = &here_regs;
+-
+-		__asm__ __volatile__ ("ori r14, 0, %0" : "=r" (regs->regs[14]));
+-		__asm__ __volatile__ ("ori r15, 0, %0" : "=r" (regs->regs[15]));
+-		__asm__ __volatile__ ("ori r18, 0, %0" : "=r" (regs->regs[18]));
+-
+-		__asm__ __volatile__ ("gettr tr0, %0" : "=r" (regs->tregs[0]));
+-		__asm__ __volatile__ ("gettr tr1, %0" : "=r" (regs->tregs[1]));
+-		__asm__ __volatile__ ("gettr tr2, %0" : "=r" (regs->tregs[2]));
+-		__asm__ __volatile__ ("gettr tr3, %0" : "=r" (regs->tregs[3]));
+-		__asm__ __volatile__ ("gettr tr4, %0" : "=r" (regs->tregs[4]));
+-		__asm__ __volatile__ ("gettr tr5, %0" : "=r" (regs->tregs[5]));
+-		__asm__ __volatile__ ("gettr tr6, %0" : "=r" (regs->tregs[6]));
+-		__asm__ __volatile__ ("gettr tr7, %0" : "=r" (regs->tregs[7]));
+-
+-		__asm__ __volatile__ (
+-			"pta 0f, tr0\n\t"
+-			"blink tr0, %0\n\t"
+-			"0: nop"
+-			: "=r" (regs->pc)
+-		);
+-	}
+-
+-	printk("\nCall Trace:\n");
+-	sh64_unwind_inner(regs);
+-}
+-
+diff --git a/arch/sh64/kernel/vmlinux.lds.S b/arch/sh64/kernel/vmlinux.lds.S
+deleted file mode 100644
+index f533a06..0000000
+--- a/arch/sh64/kernel/vmlinux.lds.S
++++ /dev/null
+@@ -1,140 +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.
 - *
-- * Bugs:         Enter bugs at http://blackfin.uclinux.org/
+- * arch/sh5/vmlinux.lds.S
 - *
-- * This program is free software; you can redistribute it and/or modify
-- * it under the terms of the GNU General Public License as published by
-- * the Free Software Foundation; either version 2 of the License, or
-- * (at your option) any later version.
+- * ld script to make ST50 Linux kernel
 - *
-- * This program is distributed in the hope that it will be useful,
-- * but WITHOUT ANY WARRANTY; without even the implied warranty of
-- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-- * GNU General Public License for more details.
+- * Copyright (C) 2000, 2001  Paolo Alberelli
 - *
-- * 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
+- * benedict.gaster at superh.com:	 2nd May 2002
+- *    Add definition of empty_zero_page to be the first page of kernel image.
+- *
+- * benedict.gaster at superh.com:	 3rd May 2002
+- *    Added support for ramdisk, removing statically linked romfs at the same time.
+- *
+- * lethal at linux-sh.org:          9th May 2003
+- *    Kill off GLOBAL_NAME() usage and other CDC-isms.
+- *
+- * lethal at linux-sh.org:         19th May 2003
+- *    Remove support for ancient toolchains.
 - */
 -
--#include <linux/linkage.h>
--#include <asm/cplb.h>
--#include <asm/entry.h>
--
--#ifdef CONFIG_EXCPT_IRQ_SYSC_L1
--.section .l1.text
+-#include <asm/page.h>
+-#include <asm/cache.h>
+-#include <asm/processor.h>
+-#include <asm/thread_info.h>
+-
+-#define LOAD_OFFSET	CONFIG_CACHED_MEMORY_OFFSET
+-#include <asm-generic/vmlinux.lds.h>
+-
+-OUTPUT_ARCH(sh:sh5)
+-
+-#define C_PHYS(x) AT (ADDR(x) - LOAD_OFFSET)
+-
+-ENTRY(__start)
+-SECTIONS
+-{
+-  . = CONFIG_CACHED_MEMORY_OFFSET + CONFIG_MEMORY_START + PAGE_SIZE;
+-  _text = .;			/* Text and read-only data */
+-  text = .;			/* Text and read-only data */
+-
+-  .empty_zero_page : C_PHYS(.empty_zero_page) {
+-	*(.empty_zero_page)
+-	} = 0
+-
+-  .text : C_PHYS(.text) {
+-  	*(.text.head)
+-	TEXT_TEXT
+-	*(.text64)
+-        *(.text..SHmedia32)
+-	SCHED_TEXT
+-	LOCK_TEXT
+-	*(.fixup)
+-	*(.gnu.warning)
+-#ifdef CONFIG_LITTLE_ENDIAN
+-	} = 0x6ff0fff0
 -#else
--.text
+-	} = 0xf0fff06f
 -#endif
 -
--.type _cplb_mgr, STT_FUNC;
--.type _panic_cplb_error, STT_FUNC;
+-  /* We likely want __ex_table to be Cache Line aligned */
+-  . = ALIGN(L1_CACHE_BYTES);		/* Exception table */
+-  __start___ex_table = .;
+-  __ex_table : C_PHYS(__ex_table) { *(__ex_table) }
+-  __stop___ex_table = .;
+-
+-  _etext = .;			/* End of text section */
+-
+-  NOTES 
+-
+-  RODATA
+-
+-  .data : C_PHYS(.data) {			/* Data */
+-	DATA_DATA
+-	CONSTRUCTORS
+-	}
+-
+-  . = ALIGN(PAGE_SIZE);
+-  .data.page_aligned : C_PHYS(.data.page_aligned) { *(.data.page_aligned) }
+-
+-  PERCPU(PAGE_SIZE)
+-
+-  . = ALIGN(L1_CACHE_BYTES);
+-  .data.cacheline_aligned : C_PHYS(.data.cacheline_aligned) { *(.data.cacheline_aligned) }
+-
+-  _edata = .;			/* End of data section */
+-
+-  . = ALIGN(THREAD_SIZE);	/* init_task: structure size aligned */
+-  .data.init_task : C_PHYS(.data.init_task) { *(.data.init_task) }
+-
+-  . = ALIGN(PAGE_SIZE);		/* Init code and data */
+-  __init_begin = .;
+-  _sinittext = .;
+-  .init.text : C_PHYS(.init.text) { *(.init.text) }
+-  _einittext = .;
+-  .init.data : C_PHYS(.init.data) { *(.init.data) }
+-  . = ALIGN(L1_CACHE_BYTES);	/* Better if Cache Line aligned */
+-  __setup_start = .;
+-  .init.setup : C_PHYS(.init.setup) { *(.init.setup) }
+-  __setup_end = .;
+-  __initcall_start = .;
+-  .initcall.init : C_PHYS(.initcall.init) {
+-	INITCALLS
+-  }
+-  __initcall_end = .;
+-  __con_initcall_start = .;
+-  .con_initcall.init : C_PHYS(.con_initcall.init) { *(.con_initcall.init) }
+-  __con_initcall_end = .;
+-  SECURITY_INIT
+-
+-#ifdef CONFIG_BLK_DEV_INITRD
+-  __initramfs_start = .;
+-  .init.ramfs : C_PHYS(.init.ramfs) { *(.init.ramfs) }
+-  __initramfs_end = .;
+-#endif
 -
--.align 2
+-  . = ALIGN(PAGE_SIZE);
+-  __init_end = .;
 -
--ENTRY(__cplb_hdr)
--	R2 = SEQSTAT;
+-  /* Align to the biggest single data representation, head and tail */
+-  . = ALIGN(8);
+-  __bss_start = .;		/* BSS */
+-  .bss : C_PHYS(.bss) {
+-	*(.bss)
+-	}
+-  . = ALIGN(8);
+-  _end = . ;
 -
--	/* Mask the contents of SEQSTAT and leave only EXCAUSE in R2 */
--	R2 <<= 26;
--	R2 >>= 26;
+-  /* Sections to be discarded */
+-  /DISCARD/ : {
+-	*(.exit.text)
+-	*(.exit.data)
+-	*(.exitcall.exit)
+-	}
 -
--	R1 = 0x23; /* Data access CPLB protection violation */
--	CC = R2 == R1;
--	IF !CC JUMP .Lnot_data_write;
--	R0 = 2;		/* is a write to data space*/
--	JUMP .Lis_icplb_miss;
+-  STABS_DEBUG
+-  DWARF_DEBUG
+-}
+diff --git a/arch/sh64/lib/.gitignore b/arch/sh64/lib/.gitignore
+deleted file mode 100644
+index 3508c2c..0000000
+--- a/arch/sh64/lib/.gitignore
++++ /dev/null
+@@ -1 +0,0 @@
+-syscalltab.h
+diff --git a/arch/sh64/lib/Makefile b/arch/sh64/lib/Makefile
+deleted file mode 100644
+index 6a4cc3f..0000000
+--- a/arch/sh64/lib/Makefile
++++ /dev/null
+@@ -1,19 +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, 2001  Paolo Alberelli
+-# Coprygith (C) 2003  Paul Mundt
+-#
+-# Makefile for the SH-5 specific library files..
+-#
+-# Note! Dependencies are done automagically by 'make dep', which also
+-# removes any old dependencies. DON'T put your own dependencies here
+-# unless it's something special (ie not a .c file).
+-#
 -
--.Lnot_data_write:
--	R1 = 0x2C; /* CPLB miss on an instruction fetch */
--	CC = R2 == R1;
--	R0 = 0;		/* is_data_miss == False*/
--	IF CC JUMP .Lis_icplb_miss;
+-# Panic should really be compiled as PIC
+-lib-y  := udelay.o c-checksum.o dbg.o io.o panic.o memcpy.o copy_user_memcpy.o \
+-		page_copy.o page_clear.o iomap.o
 -
--	R1 = 0x26;
--	CC = R2 == R1;
--	IF !CC JUMP .Lunknown;
+diff --git a/arch/sh64/lib/c-checksum.c b/arch/sh64/lib/c-checksum.c
+deleted file mode 100644
+index 053137a..0000000
+--- a/arch/sh64/lib/c-checksum.c
++++ /dev/null
+@@ -1,217 +0,0 @@
+-/*
+- * arch/sh64/lib/c-checksum.c
+- *
+- * This file contains network checksum routines that are better done
+- * in an architecture-specific manner due to speed..
+- */
 -
--	R0 = 1;		/* is_data_miss == True*/
+-#undef DEBUG
 -
--.Lis_icplb_miss:
+-#include <linux/string.h>
+-#include <linux/errno.h>
+-#include <linux/kernel.h>
+-#include <linux/module.h>
+-#include <asm/byteorder.h>
+-#include <asm/uaccess.h>
 -
--#if defined(CONFIG_BFIN_ICACHE) || defined(CONFIG_BFIN_DCACHE)
--# if defined(CONFIG_BFIN_ICACHE) && !defined(CONFIG_BFIN_DCACHE)
--	R1 = CPLB_ENABLE_ICACHE;
--# endif
--# if !defined(CONFIG_BFIN_ICACHE) && defined(CONFIG_BFIN_DCACHE)
--	R1 = CPLB_ENABLE_DCACHE;
--# endif
--# if defined(CONFIG_BFIN_ICACHE) && defined(CONFIG_BFIN_DCACHE)
--	R1 = CPLB_ENABLE_DCACHE | CPLB_ENABLE_ICACHE;
--# endif
--#else
--	R1 = 0;
+-static inline unsigned short from64to16(unsigned long long x)
+-{
+-	/* add up 32-bit words for 33 bits */
+-	x = (x & 0xffffffff) + (x >> 32);
+-	/* add up 16-bit and 17-bit words for 17+c bits */
+-	x = (x & 0xffff) + (x >> 16);
+-	/* add up 16-bit and 2-bit for 16+c bit */
+-	x = (x & 0xffff) + (x >> 16);
+-	/* add up carry.. */
+-	x = (x & 0xffff) + (x >> 16);
+-	return x;
+-}
+-
+-static inline unsigned short foldto16(unsigned long x)
+-{
+-	/* add up 16-bit for 17 bits */
+-	x = (x & 0xffff) + (x >> 16);
+-	/* add up carry.. */
+-	x = (x & 0xffff) + (x >> 16);
+-	return x;
+-}
+-
+-static inline unsigned short myfoldto16(unsigned long long x)
+-{
+-	/* Fold down to 32-bits so we don't loose in the typedef-less
+-	   network stack.  */
+-	/* 64 to 33 */
+-	x = (x & 0xffffffff) + (x >> 32);
+-	/* 33 to 32 */
+-	x = (x & 0xffffffff) + (x >> 32);
+-
+-	/* add up 16-bit for 17 bits */
+-	x = (x & 0xffff) + (x >> 16);
+-	/* add up carry.. */
+-	x = (x & 0xffff) + (x >> 16);
+-	return x;
+-}
+-
+-#define odd(x) ((x)&1)
+-#define U16(x) ntohs(x)
+-
+-static unsigned long do_csum(const unsigned char *buff, int len)
+-{
+-	int odd, count;
+-	unsigned long result = 0;
+-
+-	pr_debug("do_csum buff %p, len %d (0x%x)\n", buff, len, len);
+-#ifdef DEBUG
+-	for (i = 0; i < len; i++) {
+-		if ((i % 26) == 0)
+-			printk("\n");
+-		printk("%02X ", buff[i]);
+-	}
 -#endif
 -
--	[--SP] = RETS;
--	CALL _cplb_mgr;
--	RETS = [SP++];
--	CC = R0 == 0;
--	IF !CC JUMP .Lnot_replaced;
--	RTS;
+-	if (len <= 0)
+-		goto out;
+-
+-	odd = 1 & (unsigned long) buff;
+-	if (odd) {
+-		result = *buff << 8;
+-		len--;
+-		buff++;
+-	}
+-	count = len >> 1;	/* nr of 16-bit words.. */
+-	if (count) {
+-		if (2 & (unsigned long) buff) {
+-			result += *(unsigned short *) buff;
+-			count--;
+-			len -= 2;
+-			buff += 2;
+-		}
+-		count >>= 1;	/* nr of 32-bit words.. */
+-		if (count) {
+-			unsigned long carry = 0;
+-			do {
+-				unsigned long w = *(unsigned long *) buff;
+-				buff += 4;
+-				count--;
+-				result += carry;
+-				result += w;
+-				carry = (w > result);
+-			} while (count);
+-			result += carry;
+-			result = (result & 0xffff) + (result >> 16);
+-		}
+-		if (len & 2) {
+-			result += *(unsigned short *) buff;
+-			buff += 2;
+-		}
+-	}
+-	if (len & 1)
+-		result += *buff;
+-	result = foldto16(result);
+-	if (odd)
+-		result = ((result >> 8) & 0xff) | ((result & 0xff) << 8);
+-
+-	pr_debug("\nCHECKSUM is 0x%lx\n", result);
+-
+-      out:
+-	return result;
+-}
+-
+-/* computes the checksum of a memory block at buff, length len,
+-   and adds in "sum" (32-bit)  */
+-__wsum csum_partial(const void *buff, int len, __wsum sum)
+-{
+-	unsigned long long result = do_csum(buff, len);
+-
+-	/* add in old sum, and carry.. */
+-	result += (__force u32)sum;
+-	/* 32+c bits -> 32 bits */
+-	result = (result & 0xffffffff) + (result >> 32);
+-
+-	pr_debug("csum_partial, buff %p len %d sum 0x%x result=0x%016Lx\n",
+-		buff, len, sum, result);
+-
+-	return (__force __wsum)result;
+-}
+-
+-/* Copy while checksumming, otherwise like csum_partial.  */
+-__wsum
+-csum_partial_copy_nocheck(const void *src, void *dst, int len, __wsum sum)
+-{
+-	sum = csum_partial(src, len, sum);
+-	memcpy(dst, src, len);
+-
+-	return sum;
+-}
+-
+-/* Copy from userspace and compute checksum.  If we catch an exception
+-   then zero the rest of the buffer.  */
+-__wsum
+-csum_partial_copy_from_user(const void __user *src, void *dst, int len,
+-			    __wsum sum, int *err_ptr)
+-{
+-	int missing;
+-
+-	pr_debug
+-	    ("csum_partial_copy_from_user src %p, dest %p, len %d, sum %08x, err_ptr %p\n",
+-	     src, dst, len, sum, err_ptr);
+-	missing = copy_from_user(dst, src, len);
+-	pr_debug("  access_ok %d\n", __access_ok((unsigned long) src, len));
+-	pr_debug("  missing %d\n", missing);
+-	if (missing) {
+-		memset(dst + len - missing, 0, missing);
+-		*err_ptr = -EFAULT;
+-	}
+-
+-	return csum_partial(dst, len, sum);
+-}
+-
+-/* Copy to userspace and compute checksum.  */
+-__wsum
+-csum_partial_copy_to_user(const unsigned char *src, unsigned char *dst, int len,
+-			  __wsum sum, int *err_ptr)
+-{
+-	sum = csum_partial(src, len, sum);
+-
+-	if (copy_to_user(dst, src, len))
+-		*err_ptr = -EFAULT;
+-
+-	return sum;
+-}
 -
 -/*
-- * Diagnostic exception handlers
+- *	This is a version of ip_compute_csum() optimized for IP headers,
+- *	which always checksum on 4 octet boundaries.
 - */
--.Lunknown:
--	R0 = CPLB_UNKNOWN_ERR;
--	JUMP .Lcplb_error;
+-__sum16 ip_fast_csum(const void *iph, unsigned int ihl)
+-{
+-	pr_debug("ip_fast_csum %p,%d\n", iph, ihl);
 -
--.Lnot_replaced:
--	CC = R0 == CPLB_NO_UNLOCKED;
--	IF !CC JUMP .Lnext_check;
--	R0 = CPLB_NO_UNLOCKED;
--	JUMP .Lcplb_error;
+-	return (__force __sum16)~do_csum(iph, ihl * 4);
+-}
 -
--.Lnext_check:
--	CC = R0 == CPLB_NO_ADDR_MATCH;
--	IF !CC JUMP .Lnext_check2;
--	R0 = CPLB_NO_ADDR_MATCH;
--	JUMP .Lcplb_error;
+-__wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr,
+-				unsigned short len,
+-				unsigned short proto, __wsum sum)
+-{
+-	unsigned long long result;
 -
--.Lnext_check2:
--	CC = R0 == CPLB_PROT_VIOL;
--	IF !CC JUMP .Lstrange_return_from_cplb_mgr;
--	R0 = CPLB_PROT_VIOL;
--	JUMP .Lcplb_error;
+-	pr_debug("ntohs(0x%x)=0x%x\n", 0xdead, ntohs(0xdead));
+-	pr_debug("htons(0x%x)=0x%x\n", 0xdead, htons(0xdead));
 -
--.Lstrange_return_from_cplb_mgr:
--	IDLE;
--	CSYNC;
--	JUMP .Lstrange_return_from_cplb_mgr;
+-	result = (__force u64) saddr + (__force u64) daddr +
+-		 (__force u64) sum + ((len + proto) << 8);
 -
--.Lcplb_error:
--	R1 = sp;
--	SP += -12;
--	call _panic_cplb_error;
--	SP += 12;
--	JUMP _handle_bad_cplb;
+-	/* Fold down to 32-bits so we don't loose in the typedef-less
+-	   network stack.  */
+-	/* 64 to 33 */
+-	result = (result & 0xffffffff) + (result >> 32);
+-	/* 33 to 32 */
+-	result = (result & 0xffffffff) + (result >> 32);
 -
--ENDPROC(__cplb_hdr)
-diff --git a/arch/blackfin/mach-common/cplbinfo.c b/arch/blackfin/mach-common/cplbinfo.c
+-	pr_debug("%s saddr %x daddr %x len %x proto %x sum %x result %08Lx\n",
+-		__FUNCTION__, saddr, daddr, len, proto, sum, result);
+-
+-	return (__wsum)result;
+-}
+-EXPORT_SYMBOL(csum_tcpudp_nofold);
+diff --git a/arch/sh64/lib/copy_user_memcpy.S b/arch/sh64/lib/copy_user_memcpy.S
 deleted file mode 100644
-index a4f0b42..0000000
---- a/arch/blackfin/mach-common/cplbinfo.c
+index 2a62816..0000000
+--- a/arch/sh64/lib/copy_user_memcpy.S
 +++ /dev/null
-@@ -1,208 +0,0 @@
+@@ -1,217 +0,0 @@
+-!
+-! Fast SH memcpy
+-!
+-! by Toshiyasu Morita (tm at netcom.com)
+-! hacked by J"orn Rernnecke (joern.rennecke at superh.com) ("o for o-umlaut)
+-! SH5 code Copyright 2002 SuperH Ltd.
+-!
+-! Entry: ARG0: destination pointer
+-!        ARG1: source pointer
+-!        ARG2: byte count
+-!
+-! Exit:  RESULT: destination pointer
+-!        any other registers in the range r0-r7: trashed
+-!
+-! Notes: Usually one wants to do small reads and write a longword, but
+-!        unfortunately it is difficult in some cases to concatanate bytes
+-!        into a longword on the SH, so this does a longword read and small
+-!        writes.
+-!
+-! This implementation makes two assumptions about how it is called:
+-!
+-! 1.: If the byte count is nonzero, the address of the last byte to be
+-!     copied is unsigned greater than the address of the first byte to
+-!     be copied.  This could be easily swapped for a signed comparison,
+-!     but the algorithm used needs some comparison.
+-!
+-! 2.: When there are two or three bytes in the last word of an 11-or-more
+-!     bytes memory chunk to b copied, the rest of the word can be read
+-!     without side effects.
+-!     This could be easily changed by increasing the minumum size of
+-!     a fast memcpy and the amount subtracted from r7 before L_2l_loop be 2,
+-!     however, this would cost a few extra cyles on average.
+-!     For SHmedia, the assumption is that any quadword can be read in its
+-!     enirety if at least one byte is included in the copy.
+-
+-/* Imported into Linux kernel by Richard Curnow.  This is used to implement the
+-   __copy_user function in the general case, so it has to be a distinct
+-   function from intra-kernel memcpy to allow for exception fix-ups in the
+-   event that the user pointer is bad somewhere in the copy (e.g. due to
+-   running off the end of the vma).
+-
+-   Note, this algorithm will be slightly wasteful in the case where the source
+-   and destination pointers are equally aligned, because the stlo/sthi pairs
+-   could then be merged back into single stores.  If there are a lot of cache
+-   misses, this is probably offset by the stall lengths on the preloads.
+-
+-*/
+-
+-/* NOTE : Prefetches removed and allocos guarded by synco to avoid TAKum03020
+- * erratum.  The first two prefetches are nop-ed out to avoid upsetting the
+- * instruction counts used in the jump address calculation.
+- * */
+-
+-	.section .text..SHmedia32,"ax"
+-	.little
+-	.balign 32
+-	.global copy_user_memcpy
+-	.global copy_user_memcpy_end
+-copy_user_memcpy:
+-
+-#define LDUAQ(P,O,D0,D1) ldlo.q P,O,D0; ldhi.q P,O+7,D1
+-#define STUAQ(P,O,D0,D1) stlo.q P,O,D0; sthi.q P,O+7,D1
+-#define LDUAL(P,O,D0,D1) ldlo.l P,O,D0; ldhi.l P,O+3,D1
+-#define STUAL(P,O,D0,D1) stlo.l P,O,D0; sthi.l P,O+3,D1
+-
+-	nop ! ld.b r3,0,r63 ! TAKum03020
+-	pta/l Large,tr0
+-	movi 25,r0
+-	bgeu/u r4,r0,tr0
+-	nsb r4,r0
+-	shlli r0,5,r0
+-	movi (L1-L0+63*32 + 1) & 0xffff,r1
+-	sub r1, r0, r0
+-L0:	ptrel r0,tr0
+-	add r2,r4,r5
+-	ptabs r18,tr1
+-	add r3,r4,r6
+-	blink tr0,r63
+-
+-/* Rearranged to make cut2 safe */
+-	.balign 8
+-L4_7:	/* 4..7 byte memcpy cntd. */
+-	stlo.l r2, 0, r0
+-	or r6, r7, r6
+-	sthi.l r5, -1, r6
+-	stlo.l r5, -4, r6
+-	blink tr1,r63
+-
+-	.balign 8
+-L1:	/* 0 byte memcpy */
+-	nop
+-	blink tr1,r63
+-	nop
+-	nop
+-	nop
+-	nop
+-
+-L2_3:	/* 2 or 3 byte memcpy cntd. */
+-	st.b r5,-1,r6
+-	blink tr1,r63
+-
+-	/* 1 byte memcpy */
+-	ld.b r3,0,r0
+-	st.b r2,0,r0
+-	blink tr1,r63
+-
+-L8_15:	/* 8..15 byte memcpy cntd. */
+-	stlo.q r2, 0, r0
+-	or r6, r7, r6
+-	sthi.q r5, -1, r6
+-	stlo.q r5, -8, r6
+-	blink tr1,r63
+-
+-	/* 2 or 3 byte memcpy */
+-	ld.b r3,0,r0
+-	nop ! ld.b r2,0,r63 ! TAKum03020
+-	ld.b r3,1,r1
+-	st.b r2,0,r0
+-	pta/l L2_3,tr0
+-	ld.b r6,-1,r6
+-	st.b r2,1,r1
+-	blink tr0, r63
+-
+-	/* 4 .. 7 byte memcpy */
+-	LDUAL (r3, 0, r0, r1)
+-	pta L4_7, tr0
+-	ldlo.l r6, -4, r7
+-	or r0, r1, r0
+-	sthi.l r2, 3, r0
+-	ldhi.l r6, -1, r6
+-	blink tr0, r63
+-
+-	/* 8 .. 15 byte memcpy */
+-	LDUAQ (r3, 0, r0, r1)
+-	pta L8_15, tr0
+-	ldlo.q r6, -8, r7
+-	or r0, r1, r0
+-	sthi.q r2, 7, r0
+-	ldhi.q r6, -1, r6
+-	blink tr0, r63
+-
+-	/* 16 .. 24 byte memcpy */
+-	LDUAQ (r3, 0, r0, r1)
+-	LDUAQ (r3, 8, r8, r9)
+-	or r0, r1, r0
+-	sthi.q r2, 7, r0
+-	or r8, r9, r8
+-	sthi.q r2, 15, r8
+-	ldlo.q r6, -8, r7
+-	ldhi.q r6, -1, r6
+-	stlo.q r2, 8, r8
+-	stlo.q r2, 0, r0
+-	or r6, r7, r6
+-	sthi.q r5, -1, r6
+-	stlo.q r5, -8, r6
+-	blink tr1,r63
+-
+-Large:
+-	! ld.b r2, 0, r63 ! TAKum03020
+-	pta/l  Loop_ua, tr1
+-	ori r3, -8, r7
+-	sub r2, r7, r22
+-	sub r3, r2, r6
+-	add r2, r4, r5
+-	ldlo.q r3, 0, r0
+-	addi r5, -16, r5
+-	movi 64+8, r27 ! could subtract r7 from that.
+-	stlo.q r2, 0, r0
+-	sthi.q r2, 7, r0
+-	ldx.q r22, r6, r0
+-	bgtu/l r27, r4, tr1
+-
+-	addi r5, -48, r27
+-	pta/l Loop_line, tr0
+-	addi r6, 64, r36
+-	addi r6, -24, r19
+-	addi r6, -16, r20
+-	addi r6, -8, r21
+-
+-Loop_line:
+-	! ldx.q r22, r36, r63 ! TAKum03020
+-	alloco r22, 32
+-	synco
+-	addi r22, 32, r22
+-	ldx.q r22, r19, r23
+-	sthi.q r22, -25, r0
+-	ldx.q r22, r20, r24
+-	ldx.q r22, r21, r25
+-	stlo.q r22, -32, r0
+-	ldx.q r22, r6,  r0
+-	sthi.q r22, -17, r23
+-	sthi.q r22,  -9, r24
+-	sthi.q r22,  -1, r25
+-	stlo.q r22, -24, r23
+-	stlo.q r22, -16, r24
+-	stlo.q r22,  -8, r25
+-	bgeu r27, r22, tr0
+-
+-Loop_ua:
+-	addi r22, 8, r22
+-	sthi.q r22, -1, r0
+-	stlo.q r22, -8, r0
+-	ldx.q r22, r6, r0
+-	bgtu/l r5, r22, tr1
+-
+-	add r3, r4, r7
+-	ldlo.q r7, -8, r1
+-	sthi.q r22, 7, r0
+-	ldhi.q r7, -1, r7
+-	ptabs r18,tr1
+-	stlo.q r22, 0, r0
+-	or r1, r7, r1
+-	sthi.q r5, 15, r1
+-	stlo.q r5, 8, r1
+-	blink tr1, r63
+-copy_user_memcpy_end:
+-	nop
+diff --git a/arch/sh64/lib/dbg.c b/arch/sh64/lib/dbg.c
+deleted file mode 100644
+index 97816e0..0000000
+--- a/arch/sh64/lib/dbg.c
++++ /dev/null
+@@ -1,430 +0,0 @@
+-/*--------------------------------------------------------------------------
+---
+--- Identity : Linux50 Debug Funcions
+---
+--- File     : arch/sh64/lib/dbg.C
+---
+--- Copyright 2000, 2001 STMicroelectronics Limited.
+--- Copyright 2004 Richard Curnow (evt_debug etc)
+---
+---------------------------------------------------------------------------*/
+-#include <linux/types.h>
+-#include <linux/kernel.h>
+-#include <linux/sched.h>
+-#include <linux/mm.h>
+-#include <linux/fs.h>
+-#include <asm/mmu_context.h>
+-
+-typedef u64 regType_t;
+-
+-static regType_t getConfigReg(u64 id)
+-{
+-	register u64 reg __asm__("r2");
+-	asm volatile ("getcfg   %1, 0, %0":"=r" (reg):"r"(id));
+-	return (reg);
+-}
+-
+-/* ======================================================================= */
+-
+-static char *szTab[] = { "4k", "64k", "1M", "512M" };
+-static char *protTab[] = { "----",
+-	"---R",
+-	"--X-",
+-	"--XR",
+-	"-W--",
+-	"-W-R",
+-	"-WX-",
+-	"-WXR",
+-	"U---",
+-	"U--R",
+-	"U-X-",
+-	"U-XR",
+-	"UW--",
+-	"UW-R",
+-	"UWX-",
+-	"UWXR"
+-};
+-#define  ITLB_BASE	0x00000000
+-#define  DTLB_BASE	0x00800000
+-#define  MAX_TLBs		64
+-/* PTE High */
+-#define  GET_VALID(pte)        ((pte) & 0x1)
+-#define  GET_SHARED(pte)       ((pte) & 0x2)
+-#define  GET_ASID(pte)         ((pte >> 2) & 0x0ff)
+-#define  GET_EPN(pte)          ((pte) & 0xfffff000)
+-
+-/* PTE Low */
+-#define  GET_CBEHAVIOR(pte)    ((pte) & 0x3)
+-#define  GET_PAGE_SIZE(pte)    szTab[((pte >> 3) & 0x3)]
+-#define  GET_PROTECTION(pte)   protTab[((pte >> 6) & 0xf)]
+-#define  GET_PPN(pte)          ((pte) & 0xfffff000)
+-
+-#define PAGE_1K_MASK           0x00000000
+-#define PAGE_4K_MASK           0x00000010
+-#define PAGE_64K_MASK          0x00000080
+-#define MMU_PAGESIZE_MASK      (PAGE_64K_MASK | PAGE_4K_MASK)
+-#define PAGE_1MB_MASK          MMU_PAGESIZE_MASK
+-#define PAGE_1K                (1024)
+-#define PAGE_4K                (1024 * 4)
+-#define PAGE_64K               (1024 * 64)
+-#define PAGE_1MB               (1024 * 1024)
+-
+-#define HOW_TO_READ_TLB_CONTENT  \
+-       "[ ID]  PPN         EPN        ASID  Share  CB  P.Size   PROT.\n"
+-
+-void print_single_tlb(unsigned long tlb, int single_print)
+-{
+-	regType_t pteH;
+-	regType_t pteL;
+-	unsigned int valid, shared, asid, epn, cb, ppn;
+-	char *pSize;
+-	char *pProt;
+-
+-	/*
+-	   ** in case of single print <single_print> is true, this implies:
+-	   **   1) print the TLB in any case also if NOT VALID
+-	   **   2) print out the header
+-	 */
+-
+-	pteH = getConfigReg(tlb);
+-	valid = GET_VALID(pteH);
+-	if (single_print)
+-		printk(HOW_TO_READ_TLB_CONTENT);
+-	else if (!valid)
+-		return;
+-
+-	pteL = getConfigReg(tlb + 1);
+-
+-	shared = GET_SHARED(pteH);
+-	asid = GET_ASID(pteH);
+-	epn = GET_EPN(pteH);
+-	cb = GET_CBEHAVIOR(pteL);
+-	pSize = GET_PAGE_SIZE(pteL);
+-	pProt = GET_PROTECTION(pteL);
+-	ppn = GET_PPN(pteL);
+-	printk("[%c%2ld]  0x%08x  0x%08x  %03d   %02x    %02x   %4s    %s\n",
+-	       ((valid) ? ' ' : 'u'), ((tlb & 0x0ffff) / TLB_STEP),
+-	       ppn, epn, asid, shared, cb, pSize, pProt);
+-}
+-
+-void print_dtlb(void)
+-{
+-	int count;
+-	unsigned long tlb;
+-
+-	printk(" ================= SH-5 D-TLBs Status ===================\n");
+-	printk(HOW_TO_READ_TLB_CONTENT);
+-	tlb = DTLB_BASE;
+-	for (count = 0; count < MAX_TLBs; count++, tlb += TLB_STEP)
+-		print_single_tlb(tlb, 0);
+-	printk
+-	    (" =============================================================\n");
+-}
+-
+-void print_itlb(void)
+-{
+-	int count;
+-	unsigned long tlb;
+-
+-	printk(" ================= SH-5 I-TLBs Status ===================\n");
+-	printk(HOW_TO_READ_TLB_CONTENT);
+-	tlb = ITLB_BASE;
+-	for (count = 0; count < MAX_TLBs; count++, tlb += TLB_STEP)
+-		print_single_tlb(tlb, 0);
+-	printk
+-	    (" =============================================================\n");
+-}
+-
+-/* ======================================================================= */
+-
+-#ifdef CONFIG_POOR_MANS_STRACE
+-
+-#include "syscalltab.h"
+-
+-struct ring_node {
+-	int evt;
+-	int ret_addr;
+-	int event;
+-	int tra;
+-	int pid;
+-	unsigned long sp;
+-	unsigned long pc;
+-};
+-
+-static struct ring_node event_ring[16];
+-static int event_ptr = 0;
+-
+-struct stored_syscall_data {
+-	int pid;
+-	int syscall_number;
+-};
+-
+-#define N_STORED_SYSCALLS 16
+-
+-static struct stored_syscall_data stored_syscalls[N_STORED_SYSCALLS];
+-static int syscall_next=0;
+-static int syscall_next_print=0;
+-
+-void evt_debug(int evt, int ret_addr, int event, int tra, struct pt_regs *regs)
+-{
+-	int syscallno = tra & 0xff;
+-	unsigned long sp;
+-	unsigned long stack_bottom;
+-	int pid;
+-	struct ring_node *rr;
+-
+-	pid = current->pid;
+-	stack_bottom = (unsigned long) task_stack_page(current);
+-	asm volatile("ori r15, 0, %0" : "=r" (sp));
+-	rr = event_ring + event_ptr;
+-	rr->evt = evt;
+-	rr->ret_addr = ret_addr;
+-	rr->event = event;
+-	rr->tra = tra;
+-	rr->pid = pid;
+-	rr->sp = sp;
+-	rr->pc = regs->pc;
+-
+-	if (sp < stack_bottom + 3092) {
+-		printk("evt_debug : stack underflow report\n");
+-		int i, j;
+-		for (j=0, i = event_ptr; j<16; j++) {
+-			rr = event_ring + i;
+-			printk("evt=%08x event=%08x tra=%08x pid=%5d sp=%08lx pc=%08lx\n",
+-				rr->evt, rr->event, rr->tra, rr->pid, rr->sp, rr->pc);
+-			i--;
+-			i &= 15;
+-		}
+-		panic("STACK UNDERFLOW\n");
+-	}
+-
+-	event_ptr = (event_ptr + 1) & 15;
+-
+-	if ((event == 2) && (evt == 0x160)) {
+-		if (syscallno < NUM_SYSCALL_INFO_ENTRIES) {
+-			/* Store the syscall information to print later.  We
+-			 * can't print this now - currently we're running with
+-			 * SR.BL=1, so we can't take a tlbmiss (which could occur
+-			 * in the console drivers under printk).
+-			 *
+-			 * Just overwrite old entries on ring overflow - this
+-			 * is only for last-hope debugging. */
+-			stored_syscalls[syscall_next].pid = current->pid;
+-			stored_syscalls[syscall_next].syscall_number = syscallno;
+-			syscall_next++;
+-			syscall_next &= (N_STORED_SYSCALLS - 1);
+-		}
+-	}
+-}
+-
+-static void drain_syscalls(void) {
+-	while (syscall_next_print != syscall_next) {
+-		printk("Task %d: %s()\n",
+-			stored_syscalls[syscall_next_print].pid,
+-			syscall_info_table[stored_syscalls[syscall_next_print].syscall_number].name);
+-			syscall_next_print++;
+-			syscall_next_print &= (N_STORED_SYSCALLS - 1);
+-	}
+-}
+-
+-void evt_debug2(unsigned int ret)
+-{
+-	drain_syscalls();
+-	printk("Task %d: syscall returns %08x\n", current->pid, ret);
+-}
+-
+-void evt_debug_ret_from_irq(struct pt_regs *regs)
+-{
+-	int pid;
+-	struct ring_node *rr;
+-
+-	pid = current->pid;
+-	rr = event_ring + event_ptr;
+-	rr->evt = 0xffff;
+-	rr->ret_addr = 0;
+-	rr->event = 0;
+-	rr->tra = 0;
+-	rr->pid = pid;
+-	rr->pc = regs->pc;
+-	event_ptr = (event_ptr + 1) & 15;
+-}
+-
+-void evt_debug_ret_from_exc(struct pt_regs *regs)
+-{
+-	int pid;
+-	struct ring_node *rr;
+-
+-	pid = current->pid;
+-	rr = event_ring + event_ptr;
+-	rr->evt = 0xfffe;
+-	rr->ret_addr = 0;
+-	rr->event = 0;
+-	rr->tra = 0;
+-	rr->pid = pid;
+-	rr->pc = regs->pc;
+-	event_ptr = (event_ptr + 1) & 15;
+-}
+-
+-#endif /* CONFIG_POOR_MANS_STRACE */
+-
+-/* ======================================================================= */
+-
+-void show_excp_regs(char *from, int trapnr, int signr, struct pt_regs *regs)
+-{
+-
+-	unsigned long long ah, al, bh, bl, ch, cl;
+-
+-	printk("\n");
+-	printk("EXCEPTION - %s: task %d; Linux trap # %d; signal = %d\n",
+-	       ((from) ? from : "???"), current->pid, trapnr, signr);
+-
+-	asm volatile ("getcon   " __EXPEVT ", %0":"=r"(ah));
+-	asm volatile ("getcon   " __EXPEVT ", %0":"=r"(al));
+-	ah = (ah) >> 32;
+-	al = (al) & 0xffffffff;
+-	asm volatile ("getcon   " __KCR1 ", %0":"=r"(bh));
+-	asm volatile ("getcon   " __KCR1 ", %0":"=r"(bl));
+-	bh = (bh) >> 32;
+-	bl = (bl) & 0xffffffff;
+-	asm volatile ("getcon   " __INTEVT ", %0":"=r"(ch));
+-	asm volatile ("getcon   " __INTEVT ", %0":"=r"(cl));
+-	ch = (ch) >> 32;
+-	cl = (cl) & 0xffffffff;
+-	printk("EXPE: %08Lx%08Lx KCR1: %08Lx%08Lx INTE: %08Lx%08Lx\n",
+-	       ah, al, bh, bl, ch, cl);
+-
+-	asm volatile ("getcon   " __PEXPEVT ", %0":"=r"(ah));
+-	asm volatile ("getcon   " __PEXPEVT ", %0":"=r"(al));
+-	ah = (ah) >> 32;
+-	al = (al) & 0xffffffff;
+-	asm volatile ("getcon   " __PSPC ", %0":"=r"(bh));
+-	asm volatile ("getcon   " __PSPC ", %0":"=r"(bl));
+-	bh = (bh) >> 32;
+-	bl = (bl) & 0xffffffff;
+-	asm volatile ("getcon   " __PSSR ", %0":"=r"(ch));
+-	asm volatile ("getcon   " __PSSR ", %0":"=r"(cl));
+-	ch = (ch) >> 32;
+-	cl = (cl) & 0xffffffff;
+-	printk("PEXP: %08Lx%08Lx PSPC: %08Lx%08Lx PSSR: %08Lx%08Lx\n",
+-	       ah, al, bh, bl, ch, cl);
+-
+-	ah = (regs->pc) >> 32;
+-	al = (regs->pc) & 0xffffffff;
+-	bh = (regs->regs[18]) >> 32;
+-	bl = (regs->regs[18]) & 0xffffffff;
+-	ch = (regs->regs[15]) >> 32;
+-	cl = (regs->regs[15]) & 0xffffffff;
+-	printk("PC  : %08Lx%08Lx LINK: %08Lx%08Lx SP  : %08Lx%08Lx\n",
+-	       ah, al, bh, bl, ch, cl);
+-
+-	ah = (regs->sr) >> 32;
+-	al = (regs->sr) & 0xffffffff;
+-	asm volatile ("getcon   " __TEA ", %0":"=r"(bh));
+-	asm volatile ("getcon   " __TEA ", %0":"=r"(bl));
+-	bh = (bh) >> 32;
+-	bl = (bl) & 0xffffffff;
+-	asm volatile ("getcon   " __KCR0 ", %0":"=r"(ch));
+-	asm volatile ("getcon   " __KCR0 ", %0":"=r"(cl));
+-	ch = (ch) >> 32;
+-	cl = (cl) & 0xffffffff;
+-	printk("SR  : %08Lx%08Lx TEA : %08Lx%08Lx KCR0: %08Lx%08Lx\n",
+-	       ah, al, bh, bl, ch, cl);
+-
+-	ah = (regs->regs[0]) >> 32;
+-	al = (regs->regs[0]) & 0xffffffff;
+-	bh = (regs->regs[1]) >> 32;
+-	bl = (regs->regs[1]) & 0xffffffff;
+-	ch = (regs->regs[2]) >> 32;
+-	cl = (regs->regs[2]) & 0xffffffff;
+-	printk("R0  : %08Lx%08Lx R1  : %08Lx%08Lx R2  : %08Lx%08Lx\n",
+-	       ah, al, bh, bl, ch, cl);
+-
+-	ah = (regs->regs[3]) >> 32;
+-	al = (regs->regs[3]) & 0xffffffff;
+-	bh = (regs->regs[4]) >> 32;
+-	bl = (regs->regs[4]) & 0xffffffff;
+-	ch = (regs->regs[5]) >> 32;
+-	cl = (regs->regs[5]) & 0xffffffff;
+-	printk("R3  : %08Lx%08Lx R4  : %08Lx%08Lx R5  : %08Lx%08Lx\n",
+-	       ah, al, bh, bl, ch, cl);
+-
+-	ah = (regs->regs[6]) >> 32;
+-	al = (regs->regs[6]) & 0xffffffff;
+-	bh = (regs->regs[7]) >> 32;
+-	bl = (regs->regs[7]) & 0xffffffff;
+-	ch = (regs->regs[8]) >> 32;
+-	cl = (regs->regs[8]) & 0xffffffff;
+-	printk("R6  : %08Lx%08Lx R7  : %08Lx%08Lx R8  : %08Lx%08Lx\n",
+-	       ah, al, bh, bl, ch, cl);
+-
+-	ah = (regs->regs[9]) >> 32;
+-	al = (regs->regs[9]) & 0xffffffff;
+-	bh = (regs->regs[10]) >> 32;
+-	bl = (regs->regs[10]) & 0xffffffff;
+-	ch = (regs->regs[11]) >> 32;
+-	cl = (regs->regs[11]) & 0xffffffff;
+-	printk("R9  : %08Lx%08Lx R10 : %08Lx%08Lx R11 : %08Lx%08Lx\n",
+-	       ah, al, bh, bl, ch, cl);
+-	printk("....\n");
+-
+-	ah = (regs->tregs[0]) >> 32;
+-	al = (regs->tregs[0]) & 0xffffffff;
+-	bh = (regs->tregs[1]) >> 32;
+-	bl = (regs->tregs[1]) & 0xffffffff;
+-	ch = (regs->tregs[2]) >> 32;
+-	cl = (regs->tregs[2]) & 0xffffffff;
+-	printk("T0  : %08Lx%08Lx T1  : %08Lx%08Lx T2  : %08Lx%08Lx\n",
+-	       ah, al, bh, bl, ch, cl);
+-	printk("....\n");
+-
+-	print_dtlb();
+-	print_itlb();
+-}
+-
+-/* ======================================================================= */
+-
 -/*
-- * File:         arch/blackfin/mach-common/cplbinfo.c
-- * Based on:
-- * Author:       Sonic Zhang <sonic.zhang at analog.com>
+-** Depending on <base> scan the MMU, Data or Instruction side
+-** looking for a valid mapping matching Eaddr & asid.
+-** Return -1 if not found or the TLB id entry otherwise.
+-** Note: it works only for 4k pages!
+-*/
+-static unsigned long
+-lookup_mmu_side(unsigned long base, unsigned long Eaddr, unsigned long asid)
+-{
+-	regType_t pteH;
+-	unsigned long epn;
+-	int count;
+-
+-	epn = Eaddr & 0xfffff000;
+-
+-	for (count = 0; count < MAX_TLBs; count++, base += TLB_STEP) {
+-		pteH = getConfigReg(base);
+-		if (GET_VALID(pteH))
+-			if ((unsigned long) GET_EPN(pteH) == epn)
+-				if ((unsigned long) GET_ASID(pteH) == asid)
+-					break;
+-	}
+-	return ((unsigned long) ((count < MAX_TLBs) ? base : -1));
+-}
+-
+-unsigned long lookup_dtlb(unsigned long Eaddr)
+-{
+-	unsigned long asid = get_asid();
+-	return (lookup_mmu_side((u64) DTLB_BASE, Eaddr, asid));
+-}
+-
+-unsigned long lookup_itlb(unsigned long Eaddr)
+-{
+-	unsigned long asid = get_asid();
+-	return (lookup_mmu_side((u64) ITLB_BASE, Eaddr, asid));
+-}
+-
+-void print_page(struct page *page)
+-{
+-	printk("  page[%p] -> index 0x%lx,  count 0x%x,  flags 0x%lx\n",
+-	       page, page->index, page_count(page), page->flags);
+-	printk("       address_space = %p, pages =%ld\n", page->mapping,
+-	       page->mapping->nrpages);
+-
+-}
+diff --git a/arch/sh64/lib/io.c b/arch/sh64/lib/io.c
+deleted file mode 100644
+index a3f3a2b..0000000
+--- a/arch/sh64/lib/io.c
++++ /dev/null
+@@ -1,128 +0,0 @@
+-/*
+- * Copyright (C) 2000 David J. Mckay (david.mckay at st.com)
 - *
-- * Created:      Jan. 2005
-- * Description:  Display CPLB status
+- * May be copied or modified under the terms of the GNU General Public
+- * License.  See linux/COPYING for more information.
 - *
-- * Modified:
-- *               Copyright 2004-2006 Analog Devices Inc.
+- * This file contains the I/O routines for use on the overdrive board
 - *
-- * Bugs:         Enter bugs at http://blackfin.uclinux.org/
+- */
+-
+-#include <linux/kernel.h>
+-#include <linux/types.h>
+-#include <linux/delay.h>
+-#include <linux/module.h>
+-#include <asm/system.h>
+-#include <asm/processor.h>
+-#include <asm/io.h>
+-
+-/*  Now for the string version of these functions */
+-void outsb(unsigned long port, const void *addr, unsigned long count)
+-{
+-	int i;
+-	unsigned char *p = (unsigned char *) addr;
+-
+-	for (i = 0; i < count; i++, p++) {
+-		outb(*p, port);
+-	}
+-}
+-EXPORT_SYMBOL(outsb);
+-
+-void insb(unsigned long port, void *addr, unsigned long count)
+-{
+-	int i;
+-	unsigned char *p = (unsigned char *) addr;
+-
+-	for (i = 0; i < count; i++, p++) {
+-		*p = inb(port);
+-	}
+-}
+-EXPORT_SYMBOL(insb);
+-
+-/* For the 16 and 32 bit string functions, we have to worry about alignment.
+- * The SH does not do unaligned accesses, so we have to read as bytes and
+- * then write as a word or dword.
+- * This can be optimised a lot more, especially in the case where the data
+- * is aligned
+- */
+-
+-void outsw(unsigned long port, const void *addr, unsigned long count)
+-{
+-	int i;
+-	unsigned short tmp;
+-	unsigned char *p = (unsigned char *) addr;
+-
+-	for (i = 0; i < count; i++, p += 2) {
+-		tmp = (*p) | ((*(p + 1)) << 8);
+-		outw(tmp, port);
+-	}
+-}
+-EXPORT_SYMBOL(outsw);
+-
+-void insw(unsigned long port, void *addr, unsigned long count)
+-{
+-	int i;
+-	unsigned short tmp;
+-	unsigned char *p = (unsigned char *) addr;
+-
+-	for (i = 0; i < count; i++, p += 2) {
+-		tmp = inw(port);
+-		p[0] = tmp & 0xff;
+-		p[1] = (tmp >> 8) & 0xff;
+-	}
+-}
+-EXPORT_SYMBOL(insw);
+-
+-void outsl(unsigned long port, const void *addr, unsigned long count)
+-{
+-	int i;
+-	unsigned tmp;
+-	unsigned char *p = (unsigned char *) addr;
+-
+-	for (i = 0; i < count; i++, p += 4) {
+-		tmp = (*p) | ((*(p + 1)) << 8) | ((*(p + 2)) << 16) |
+-		    ((*(p + 3)) << 24);
+-		outl(tmp, port);
+-	}
+-}
+-EXPORT_SYMBOL(outsl);
+-
+-void insl(unsigned long port, void *addr, unsigned long count)
+-{
+-	int i;
+-	unsigned tmp;
+-	unsigned char *p = (unsigned char *) addr;
+-
+-	for (i = 0; i < count; i++, p += 4) {
+-		tmp = inl(port);
+-		p[0] = tmp & 0xff;
+-		p[1] = (tmp >> 8) & 0xff;
+-		p[2] = (tmp >> 16) & 0xff;
+-		p[3] = (tmp >> 24) & 0xff;
+-
+-	}
+-}
+-EXPORT_SYMBOL(insl);
+-
+-void memcpy_toio(void __iomem *to, const void *from, long count)
+-{
+-	unsigned char *p = (unsigned char *) from;
+-
+-	while (count) {
+-		count--;
+-		writeb(*p++, to++);
+-	}
+-}
+-EXPORT_SYMBOL(memcpy_toio);
+-
+-void memcpy_fromio(void *to, void __iomem *from, long count)
+-{
+-	int i;
+-	unsigned char *p = (unsigned char *) to;
+-
+-	for (i = 0; i < count; i++) {
+-		p[i] = readb(from);
+-		from++;
+-	}
+-}
+-EXPORT_SYMBOL(memcpy_fromio);
+diff --git a/arch/sh64/lib/iomap.c b/arch/sh64/lib/iomap.c
+deleted file mode 100644
+index 253d1e3..0000000
+--- a/arch/sh64/lib/iomap.c
++++ /dev/null
+@@ -1,54 +0,0 @@
+-/*
+- * arch/sh64/lib/iomap.c
 - *
-- * This program is free software; you can redistribute it and/or modify
-- * it under the terms of the GNU General Public License as published by
-- * the Free Software Foundation; either version 2 of the License, or
-- * (at your option) any later version.
+- * Generic sh64 iomap interface
 - *
-- * This program is distributed in the hope that it will be useful,
-- * but WITHOUT 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  Paul Mundt
 - *
-- * 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
+- * 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/pci.h>
+-#include <asm/io.h>
+-
+-void __iomem *__attribute__ ((weak))
+-ioport_map(unsigned long port, unsigned int len)
+-{
+-	return (void __iomem *)port;
+-}
+-EXPORT_SYMBOL(ioport_map);
+-
+-void ioport_unmap(void __iomem *addr)
+-{
+-	/* Nothing .. */
+-}
+-EXPORT_SYMBOL(ioport_unmap);
+-
+-#ifdef CONFIG_PCI
+-void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max)
+-{
+-	unsigned long start = pci_resource_start(dev, bar);
+-	unsigned long len = pci_resource_len(dev, bar);
+-	unsigned long flags = pci_resource_flags(dev, bar);
+-
+-	if (!len)
+-		return NULL;
+-	if (max && len > max)
+-		len = max;
+-	if (flags & IORESOURCE_IO)
+-		return ioport_map(start + pciio_virt, len);
+-	if (flags & IORESOURCE_MEM)
+-		return (void __iomem *)start;
+-
+-	/* What? */
+-	return NULL;
+-}
+-EXPORT_SYMBOL(pci_iomap);
+-
+-void pci_iounmap(struct pci_dev *dev, void __iomem *addr)
+-{
+-	/* Nothing .. */
+-}
+-EXPORT_SYMBOL(pci_iounmap);
+-#endif
+diff --git a/arch/sh64/lib/memcpy.c b/arch/sh64/lib/memcpy.c
+deleted file mode 100644
+index fba436a..0000000
+--- a/arch/sh64/lib/memcpy.c
++++ /dev/null
+@@ -1,81 +0,0 @@
+-/*
+- * Copyright (C) 2002 Mark Debbage (Mark.Debbage at superh.com)
+- *
+- * May be copied or modified under the terms of the GNU General Public
+- * License.  See linux/COPYING for more information.
+- *
+- */
+-
+-#include <linux/types.h>
+-#include <asm/string.h>
+-
+-// This is a simplistic optimization of memcpy to increase the
+-// granularity of access beyond one byte using aligned
+-// loads and stores. This is not an optimal implementation
+-// for SH-5 (especially with regard to prefetching and the cache),
+-// and a better version should be provided later ...
+-
+-void *memcpy(void *dest, const void *src, size_t count)
+-{
+-	char *d = (char *) dest, *s = (char *) src;
+-
+-	if (count >= 32) {
+-		int i = 8 - (((unsigned long) d) & 0x7);
+-
+-		if (i != 8)
+-			while (i-- && count--) {
+-				*d++ = *s++;
+-			}
+-
+-		if (((((unsigned long) d) & 0x7) == 0) &&
+-		    ((((unsigned long) s) & 0x7) == 0)) {
+-			while (count >= 32) {
+-				unsigned long long t1, t2, t3, t4;
+-				t1 = *(unsigned long long *) (s);
+-				t2 = *(unsigned long long *) (s + 8);
+-				t3 = *(unsigned long long *) (s + 16);
+-				t4 = *(unsigned long long *) (s + 24);
+-				*(unsigned long long *) (d) = t1;
+-				*(unsigned long long *) (d + 8) = t2;
+-				*(unsigned long long *) (d + 16) = t3;
+-				*(unsigned long long *) (d + 24) = t4;
+-				d += 32;
+-				s += 32;
+-				count -= 32;
+-			}
+-			while (count >= 8) {
+-				*(unsigned long long *) d =
+-				    *(unsigned long long *) s;
+-				d += 8;
+-				s += 8;
+-				count -= 8;
+-			}
+-		}
+-
+-		if (((((unsigned long) d) & 0x3) == 0) &&
+-		    ((((unsigned long) s) & 0x3) == 0)) {
+-			while (count >= 4) {
+-				*(unsigned long *) d = *(unsigned long *) s;
+-				d += 4;
+-				s += 4;
+-				count -= 4;
+-			}
+-		}
+-
+-		if (((((unsigned long) d) & 0x1) == 0) &&
+-		    ((((unsigned long) s) & 0x1) == 0)) {
+-			while (count >= 2) {
+-				*(unsigned short *) d = *(unsigned short *) s;
+-				d += 2;
+-				s += 2;
+-				count -= 2;
+-			}
+-		}
+-	}
+-
+-	while (count--) {
+-		*d++ = *s++;
+-	}
+-
+-	return d;
+-}
+diff --git a/arch/sh64/lib/page_clear.S b/arch/sh64/lib/page_clear.S
+deleted file mode 100644
+index ac0111d..0000000
+--- a/arch/sh64/lib/page_clear.S
++++ /dev/null
+@@ -1,54 +0,0 @@
+-/*
+-   Copyright 2003 Richard Curnow, SuperH (UK) Ltd.
+-
+-   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.
+-
+-   Tight version of memset for the case of just clearing a page.  It turns out
+-   that having the alloco's spaced out slightly due to the increment/branch
+-   pair causes them to contend less for access to the cache.  Similarly,
+-   keeping the stores apart from the allocos causes less contention.  => Do two
+-   separate loops.  Do multiple stores per loop to amortise the
+-   increment/branch cost a little.
+-
+-   Parameters:
+-   r2 : source effective address (start of page)
+-
+-   Always clears 4096 bytes.
+-
+-   Note : alloco guarded by synco to avoid TAKum03020 erratum
+-
+-*/
+-
+-	.section .text..SHmedia32,"ax"
+-	.little
+-
+-	.balign 8
+-	.global sh64_page_clear
+-sh64_page_clear:
+-	pta/l 1f, tr1
+-	pta/l 2f, tr2
+-	ptabs/l r18, tr0
+-
+-	movi 4096, r7
+-	add  r2, r7, r7
+-	add  r2, r63, r6
+-1:
+-	alloco r6, 0
+-	synco	! TAKum03020
+-	addi	r6, 32, r6
+-	bgt/l	r7, r6, tr1
+-
+-	add  r2, r63, r6
+-2:
+-	st.q  r6,   0, r63
+-	st.q  r6,   8, r63
+-	st.q  r6,  16, r63
+-	st.q  r6,  24, r63
+-	addi r6, 32, r6
+-	bgt/l r7, r6, tr2
+-
+-	blink tr0, r63
+-
+-
+diff --git a/arch/sh64/lib/page_copy.S b/arch/sh64/lib/page_copy.S
+deleted file mode 100644
+index e159c3c..0000000
+--- a/arch/sh64/lib/page_copy.S
++++ /dev/null
+@@ -1,91 +0,0 @@
+-/*
+-   Copyright 2003 Richard Curnow, SuperH (UK) Ltd.
+-
+-   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.
+-
+-   Tight version of mempy for the case of just copying a page.
+-   Prefetch strategy empirically optimised against RTL simulations
+-   of SH5-101 cut2 eval chip with Cayman board DDR memory.
+-
+-   Parameters:
+-   r2 : source effective address (start of page)
+-   r3 : destination effective address (start of page)
+-
+-   Always copies 4096 bytes.
+-
+-   Points to review.
+-   * Currently the prefetch is 4 lines ahead and the alloco is 2 lines ahead.
+-     It seems like the prefetch needs to be at at least 4 lines ahead to get
+-     the data into the cache in time, and the allocos contend with outstanding
+-     prefetches for the same cache set, so it's better to have the numbers
+-     different.
+-   */
+-
+-	.section .text..SHmedia32,"ax"
+-	.little
+-
+-	.balign 8
+-	.global sh64_page_copy
+-sh64_page_copy:
+-
+-	/* Copy 4096 bytes worth of data from r2 to r3.
+-	   Do prefetches 4 lines ahead.
+-	   Do alloco 2 lines ahead */
+-
+-	pta 1f, tr1
+-	pta 2f, tr2
+-	pta 3f, tr3
+-	ptabs r18, tr0
+-
+-#if 0
+-	/* TAKum03020 */
+-	ld.q r2, 0x00, r63
+-	ld.q r2, 0x20, r63
+-	ld.q r2, 0x40, r63
+-	ld.q r2, 0x60, r63
+-#endif
+-	alloco r3, 0x00
+-	synco		! TAKum03020
+-	alloco r3, 0x20
+-	synco		! TAKum03020
+-
+-	movi 3968, r6
+-	add  r3, r6, r6
+-	addi r6, 64, r7
+-	addi r7, 64, r8
+-	sub r2, r3, r60
+-	addi r60, 8, r61
+-	addi r61, 8, r62
+-	addi r62, 8, r23
+-	addi r60, 0x80, r22
+-
+-/* Minimal code size.  The extra branches inside the loop don't cost much
+-   because they overlap with the time spent waiting for prefetches to
+-   complete. */
+-1:
+-#if 0
+-	/* TAKum03020 */
+-	bge/u r3, r6, tr2  ! skip prefetch for last 4 lines
+-	ldx.q r3, r22, r63 ! prefetch 4 lines hence
+-#endif
+-2:
+-	bge/u r3, r7, tr3  ! skip alloco for last 2 lines
+-	alloco r3, 0x40    ! alloc destination line 2 lines ahead
+-	synco		! TAKum03020
+-3:
+-	ldx.q r3, r60, r36
+-	ldx.q r3, r61, r37
+-	ldx.q r3, r62, r38
+-	ldx.q r3, r23, r39
+-	st.q  r3,   0, r36
+-	st.q  r3,   8, r37
+-	st.q  r3,  16, r38
+-	st.q  r3,  24, r39
+-	addi r3, 32, r3
+-	bgt/l r8, r3, tr1
+-
+-	blink tr0, r63	   ! return
+-
+-
+diff --git a/arch/sh64/lib/panic.c b/arch/sh64/lib/panic.c
+deleted file mode 100644
+index c9eb1cb..0000000
+--- a/arch/sh64/lib/panic.c
++++ /dev/null
+@@ -1,58 +0,0 @@
+-/*
+- * Copyright (C) 2003  Richard Curnow, SuperH UK Limited
+- *
+- * 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/kernel.h>
--#include <linux/init.h>
--#include <linux/proc_fs.h>
--#include <linux/uaccess.h>
+-#include <asm/io.h>
+-#include <asm/registers.h>
 -
--#include <asm/current.h>
--#include <asm/system.h>
--#include <asm/cplb.h>
--#include <asm/blackfin.h>
+-/* THIS IS A PHYSICAL ADDRESS */
+-#define HDSP2534_ADDR (0x04002100)
 -
--#define CPLB_I 1
--#define CPLB_D 2
+-#ifdef CONFIG_SH_CAYMAN
 -
--#define SYNC_SYS    SSYNC()
--#define SYNC_CORE   CSYNC()
+-static void poor_mans_delay(void)
+-{
+-	int i;
+-	for (i = 0; i < 2500000; i++) {
+-	}		/* poor man's delay */
+-}
 -
--#define CPLB_BIT_PAGESIZE 0x30000
+-static void show_value(unsigned long x)
+-{
+-	int i;
+-	unsigned nibble;
+-	for (i = 0; i < 8; i++) {
+-		nibble = ((x >> (i * 4)) & 0xf);
 -
--static int page_size_table[4] = {
--	0x00000400,		/* 1K */
--	0x00001000,		/* 4K */
--	0x00100000,		/* 1M */
--	0x00400000		/* 4M */
+-		ctrl_outb(nibble + ((nibble > 9) ? 55 : 48),
+-			  HDSP2534_ADDR + 0xe0 + ((7 - i) << 2));
+-	}
+-}
+-
+-#endif
+-
+-void
+-panic_handler(unsigned long panicPC, unsigned long panicSSR,
+-	      unsigned long panicEXPEVT)
+-{
+-#ifdef CONFIG_SH_CAYMAN
+-	while (1) {
+-		/* This piece of code displays the PC on the LED display */
+-		show_value(panicPC);
+-		poor_mans_delay();
+-		show_value(panicSSR);
+-		poor_mans_delay();
+-		show_value(panicEXPEVT);
+-		poor_mans_delay();
+-	}
+-#endif
+-
+-	/* Never return from the panic handler */
+-	for (;;) ;
+-
+-}
+diff --git a/arch/sh64/lib/udelay.c b/arch/sh64/lib/udelay.c
+deleted file mode 100644
+index 3276539..0000000
+--- a/arch/sh64/lib/udelay.c
++++ /dev/null
+@@ -1,59 +0,0 @@
+-/*
+- * arch/sh64/lib/udelay.c
+- *
+- * Delay routines, using a pre-computed "loops_per_jiffy" value.
+- *
+- * Copyright (C) 2000, 2001  Paolo Alberelli
+- * Copyright (C) 2003, 2004  Paul Mundt
+- *
+- * This file is subject to the terms and conditions of the GNU General Public
+- * License.  See the file "COPYING" in the main directory of this archive
+- * for more details.
+- */
+-#include <linux/sched.h>
+-#include <asm/param.h>
+-
+-extern unsigned long loops_per_jiffy;
+-
+-/*
+- * Use only for very small delays (< 1 msec).
+- *
+- * The active part of our cycle counter is only 32-bits wide, and
+- * we're treating the difference between two marks as signed.  On
+- * a 1GHz box, that's about 2 seconds.
+- */
+-
+-void __delay(int loops)
+-{
+-	long long dummy;
+-	__asm__ __volatile__("gettr	tr0, %1\n\t"
+-			     "pta	$+4, tr0\n\t"
+-			     "addi	%0, -1, %0\n\t"
+-			     "bne	%0, r63, tr0\n\t"
+-			     "ptabs	%1, tr0\n\t":"=r"(loops),
+-			     "=r"(dummy)
+-			     :"0"(loops));
+-}
+-
+-void __udelay(unsigned long long usecs, unsigned long lpj)
+-{
+-	usecs *= (((unsigned long long) HZ << 32) / 1000000) * lpj;
+-	__delay((long long) usecs >> 32);
+-}
+-
+-void __ndelay(unsigned long long nsecs, unsigned long lpj)
+-{
+-	nsecs *= (((unsigned long long) HZ << 32) / 1000000000) * lpj;
+-	__delay((long long) nsecs >> 32);
+-}
+-
+-void udelay(unsigned long usecs)
+-{
+-	__udelay(usecs, loops_per_jiffy);
+-}
+-
+-void ndelay(unsigned long nsecs)
+-{
+-	__ndelay(nsecs, loops_per_jiffy);
+-}
+-
+diff --git a/arch/sh64/mach-cayman/Makefile b/arch/sh64/mach-cayman/Makefile
+deleted file mode 100644
+index 67a2258..0000000
+--- a/arch/sh64/mach-cayman/Makefile
++++ /dev/null
+@@ -1,11 +0,0 @@
+-#
+-# Makefile for the Hitachi Cayman specific parts of the kernel
+-#
+-# Note! Dependencies are done automagically by 'make dep', which also
+-# removes any old dependencies. DON'T put your own dependencies here
+-# unless it's something special (ie not a .c file).
+-#
+-
+-obj-y := setup.o irq.o iomap.o
+-obj-$(CONFIG_HEARTBEAT)	+= led.o
+-
+diff --git a/arch/sh64/mach-cayman/iomap.c b/arch/sh64/mach-cayman/iomap.c
+deleted file mode 100644
+index a5c645f..0000000
+--- a/arch/sh64/mach-cayman/iomap.c
++++ /dev/null
+@@ -1,22 +0,0 @@
+-/*
+- * arch/sh64/mach-cayman/iomap.c
+- *
+- * Cayman iomap interface
+- *
+- * Copyright (C) 2004  Paul Mundt
+- *
+- * This file is subject to the terms and conditions of the GNU General Public
+- * License.  See the file "COPYING" in the main directory of this archive
+- * for more details.
+- */
+-#include <asm/io.h>
+-#include <asm/cayman.h>
+-
+-void __iomem *ioport_map(unsigned long port, unsigned int len)
+-{
+-	if (port < 0x400)
+-		return (void __iomem *)((port << 2) | smsc_superio_virt);
+-
+-	return (void __iomem *)port;
+-}
+-
+diff --git a/arch/sh64/mach-cayman/irq.c b/arch/sh64/mach-cayman/irq.c
+deleted file mode 100644
+index aaad36d..0000000
+--- a/arch/sh64/mach-cayman/irq.c
++++ /dev/null
+@@ -1,195 +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.
+- *
+- * arch/sh64/kernel/irq_cayman.c
+- *
+- * SH-5 Cayman Interrupt Support
+- *
+- * This file handles the board specific parts of the Cayman interrupt system
+- *
+- * Copyright (C) 2002 Stuart Menefy
+- */
+-
+-#include <asm/irq.h>
+-#include <asm/page.h>
+-#include <asm/io.h>
+-#include <linux/irq.h>
+-#include <linux/interrupt.h>
+-#include <linux/signal.h>
+-#include <asm/cayman.h>
+-
+-unsigned long epld_virt;
+-
+-#define EPLD_BASE        0x04002000
+-#define EPLD_STATUS_BASE (epld_virt + 0x10)
+-#define EPLD_MASK_BASE   (epld_virt + 0x20)
+-
+-/* Note the SMSC SuperIO chip and SMSC LAN chip interrupts are all muxed onto
+-   the same SH-5 interrupt */
+-
+-static irqreturn_t cayman_interrupt_smsc(int irq, void *dev_id)
+-{
+-        printk(KERN_INFO "CAYMAN: spurious SMSC interrupt\n");
+-	return IRQ_NONE;
+-}
+-
+-static irqreturn_t cayman_interrupt_pci2(int irq, void *dev_id)
+-{
+-        printk(KERN_INFO "CAYMAN: spurious PCI interrupt, IRQ %d\n", irq);
+-	return IRQ_NONE;
+-}
+-
+-static struct irqaction cayman_action_smsc = {
+-	.name		= "Cayman SMSC Mux",
+-	.handler	= cayman_interrupt_smsc,
+-	.flags		= IRQF_DISABLED,
 -};
 -
--static char page_size_string_table[][4] = { "1K", "4K", "1M", "4M" };
+-static struct irqaction cayman_action_pci2 = {
+-	.name		= "Cayman PCI2 Mux",
+-	.handler	= cayman_interrupt_pci2,
+-	.flags		= IRQF_DISABLED,
+-};
 -
--static int cplb_find_entry(unsigned long *cplb_addr,
--			   unsigned long *cplb_data, unsigned long addr,
--			   unsigned long data)
+-static void enable_cayman_irq(unsigned int irq)
 -{
--	int ii;
+-	unsigned long flags;
+-	unsigned long mask;
+-	unsigned int reg;
+-	unsigned char bit;
+-
+-	irq -= START_EXT_IRQS;
+-	reg = EPLD_MASK_BASE + ((irq / 8) << 2);
+-	bit = 1<<(irq % 8);
+-	local_irq_save(flags);
+-	mask = ctrl_inl(reg);
+-	mask |= bit;
+-	ctrl_outl(mask, reg);
+-	local_irq_restore(flags);
+-}
 -
--	for (ii = 0; ii < 16; ii++)
--		if (addr >= cplb_addr[ii] && addr < cplb_addr[ii] +
--		    page_size_table[(cplb_data[ii] & CPLB_BIT_PAGESIZE) >> 16]
--			&& (cplb_data[ii] == data))
--			return ii;
+-void disable_cayman_irq(unsigned int irq)
+-{
+-	unsigned long flags;
+-	unsigned long mask;
+-	unsigned int reg;
+-	unsigned char bit;
+-
+-	irq -= START_EXT_IRQS;
+-	reg = EPLD_MASK_BASE + ((irq / 8) << 2);
+-	bit = 1<<(irq % 8);
+-	local_irq_save(flags);
+-	mask = ctrl_inl(reg);
+-	mask &= ~bit;
+-	ctrl_outl(mask, reg);
+-	local_irq_restore(flags);
+-}
 -
--	return -1;
+-static void ack_cayman_irq(unsigned int irq)
+-{
+-	disable_cayman_irq(irq);
 -}
 -
--static char *cplb_print_entry(char *buf, int type)
+-static void end_cayman_irq(unsigned int irq)
 -{
--	unsigned long *p_addr = dpdt_table;
--	unsigned long *p_data = dpdt_table + 1;
--	unsigned long *p_icount = dpdt_swapcount_table;
--	unsigned long *p_ocount = dpdt_swapcount_table + 1;
--	unsigned long *cplb_addr = (unsigned long *)DCPLB_ADDR0;
--	unsigned long *cplb_data = (unsigned long *)DCPLB_DATA0;
--	int entry = 0, used_cplb = 0;
+-	if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
+-		enable_cayman_irq(irq);
+-}
 -
--	if (type == CPLB_I) {
--		buf += sprintf(buf, "Instruction CPLB entry:\n");
--		p_addr = ipdt_table;
--		p_data = ipdt_table + 1;
--		p_icount = ipdt_swapcount_table;
--		p_ocount = ipdt_swapcount_table + 1;
--		cplb_addr = (unsigned long *)ICPLB_ADDR0;
--		cplb_data = (unsigned long *)ICPLB_DATA0;
--	} else
--		buf += sprintf(buf, "Data CPLB entry:\n");
+-static unsigned int startup_cayman_irq(unsigned int irq)
+-{
+-	enable_cayman_irq(irq);
+-	return 0; /* never anything pending */
+-}
 -
--	buf += sprintf(buf, "Address\t\tData\tSize\tValid\tLocked\tSwapin\tiCount\toCount\n");
+-static void shutdown_cayman_irq(unsigned int irq)
+-{
+-	disable_cayman_irq(irq);
+-}
 -
--	while (*p_addr != 0xffffffff) {
--		entry = cplb_find_entry(cplb_addr, cplb_data, *p_addr, *p_data);
--		if (entry >= 0)
--			used_cplb |= 1 << entry;
+-struct hw_interrupt_type cayman_irq_type = {
+-	.typename	= "Cayman-IRQ",
+-	.startup	= startup_cayman_irq,
+-	.shutdown	= shutdown_cayman_irq,
+-	.enable		= enable_cayman_irq,
+-	.disable	= disable_cayman_irq,
+-	.ack		= ack_cayman_irq,
+-	.end		= end_cayman_irq,
+-};
 -
--		buf +=
--		    sprintf(buf,
--			    "0x%08lx\t0x%05lx\t%s\t%c\t%c\t%2d\t%ld\t%ld\n",
--			    *p_addr, *p_data,
--			    page_size_string_table[(*p_data & 0x30000) >> 16],
--			    (*p_data & CPLB_VALID) ? 'Y' : 'N',
--			    (*p_data & CPLB_LOCK) ? 'Y' : 'N', entry, *p_icount,
--			    *p_ocount);
+-int cayman_irq_demux(int evt)
+-{
+-	int irq = intc_evt_to_irq[evt];
 -
--		p_addr += 2;
--		p_data += 2;
--		p_icount += 2;
--		p_ocount += 2;
+-	if (irq == SMSC_IRQ) {
+-		unsigned long status;
+-		int i;
+-
+-		status = ctrl_inl(EPLD_STATUS_BASE) &
+-			 ctrl_inl(EPLD_MASK_BASE) & 0xff;
+-		if (status == 0) {
+-			irq = -1;
+-		} else {
+-			for (i=0; i<8; i++) {
+-				if (status & (1<<i))
+-					break;
+-			}
+-			irq = START_EXT_IRQS + i;
+-		}
 -	}
 -
--	if (used_cplb != 0xffff) {
--		buf += sprintf(buf, "Unused/mismatched CPLBs:\n");
+-	if (irq == PCI2_IRQ) {
+-		unsigned long status;
+-		int i;
 -
--		for (entry = 0; entry < 16; entry++)
--			if (0 == ((1 << entry) & used_cplb)) {
--				int flags = cplb_data[entry];
--				buf +=
--				    sprintf(buf,
--					    "%2d: 0x%08lx\t0x%05x\t%s\t%c\t%c\n",
--					    entry, cplb_addr[entry], flags,
--					    page_size_string_table[(flags &
--								    0x30000) >>
--								   16],
--					    (flags & CPLB_VALID) ? 'Y' : 'N',
--					    (flags & CPLB_LOCK) ? 'Y' : 'N');
+-		status = ctrl_inl(EPLD_STATUS_BASE + 3 * sizeof(u32)) &
+-			 ctrl_inl(EPLD_MASK_BASE + 3 * sizeof(u32)) & 0xff;
+-		if (status == 0) {
+-			irq = -1;
+-		} else {
+-			for (i=0; i<8; i++) {
+-				if (status & (1<<i))
+-					break;
 -			}
+-			irq = START_EXT_IRQS + (3 * 8) + i;
+-		}
 -	}
 -
--	buf += sprintf(buf, "\n");
+-	return irq;
+-}
 -
--	return buf;
+-#if defined(CONFIG_PROC_FS) && defined(CONFIG_SYSCTL)
+-int cayman_irq_describe(char* p, int irq)
+-{
+-	if (irq < NR_INTC_IRQS) {
+-		return intc_irq_describe(p, irq);
+-	} else if (irq < NR_INTC_IRQS + 8) {
+-		return sprintf(p, "(SMSC %d)", irq - NR_INTC_IRQS);
+-	} else if ((irq >= NR_INTC_IRQS + 24) && (irq < NR_INTC_IRQS + 32)) {
+-		return sprintf(p, "(PCI2 %d)", irq - (NR_INTC_IRQS + 24));
+-	}
+-
+-	return 0;
 -}
+-#endif
 -
--static int cplbinfo_proc_output(char *buf)
+-void init_cayman_irq(void)
 -{
--	char *p;
+-	int i;
 -
--	p = buf;
+-	epld_virt = onchip_remap(EPLD_BASE, 1024, "EPLD");
+-	if (!epld_virt) {
+-		printk(KERN_ERR "Cayman IRQ: Unable to remap EPLD\n");
+-		return;
+-	}
 -
--	p += sprintf(p, "------------------ CPLB Information ------------------\n\n");
+-	for (i=0; i<NR_EXT_IRQS; i++) {
+-		irq_desc[START_EXT_IRQS + i].chip = &cayman_irq_type;
+-	}
 -
--	if (bfin_read_IMEM_CONTROL() & ENICPLB)
--		p = cplb_print_entry(p, CPLB_I);
--	else
--		p += sprintf(p, "Instruction CPLB is disabled.\n\n");
+-	/* Setup the SMSC interrupt */
+-	setup_irq(SMSC_IRQ, &cayman_action_smsc);
+-	setup_irq(PCI2_IRQ, &cayman_action_pci2);
+-}
+diff --git a/arch/sh64/mach-cayman/led.c b/arch/sh64/mach-cayman/led.c
+deleted file mode 100644
+index b4e122f..0000000
+--- a/arch/sh64/mach-cayman/led.c
++++ /dev/null
+@@ -1,51 +0,0 @@
+-/*
+- * arch/sh64/mach-cayman/led.c
+- *
+- * Copyright (C) 2002 Stuart Menefy <stuart.menefy at st.com>
+- *
+- * May be copied or modified under the terms of the GNU General Public
+- * License.  See linux/COPYING for more information.
+- *
+- * Flash the LEDs
+- */
+-#include <asm/io.h>
 -
--	if (bfin_read_DMEM_CONTROL() & ENDCPLB)
--		p = cplb_print_entry(p, CPLB_D);
+-/*
+-** It is supposed these functions to be used for a low level
+-** debugging (via Cayman LEDs), hence to be available as soon
+-** as possible.
+-** Unfortunately Cayman LEDs relies on Cayman EPLD to be mapped
+-** (this happen when IRQ are initialized... quite late).
+-** These triky dependencies should be removed. Temporary, it
+-** may be enough to NOP until EPLD is mapped.
+-*/
+-
+-extern unsigned long epld_virt;
+-
+-#define LED_ADDR      (epld_virt + 0x008)
+-#define HDSP2534_ADDR (epld_virt + 0x100)
+-
+-void mach_led(int position, int value)
+-{
+-	if (!epld_virt)
+-		return;
+-
+-	if (value)
+-		ctrl_outl(0, LED_ADDR);
 -	else
--		p += sprintf(p, "Data CPLB is disabled.\n");
+-		ctrl_outl(1, LED_ADDR);
 -
--	return p - buf;
 -}
 -
--static int cplbinfo_read_proc(char *page, char **start, off_t off,
--			      int count, int *eof, void *data)
+-void mach_alphanum(int position, unsigned char value)
 -{
--	int len;
+-	if (!epld_virt)
+-		return;
 -
--	len = cplbinfo_proc_output(page);
--	if (len <= off + count)
--		*eof = 1;
--	*start = page + off;
--	len -= off;
--	if (len > count)
--		len = count;
--	if (len < 0)
--		len = 0;
--	return len;
+-	ctrl_outb(value, HDSP2534_ADDR + 0xe0 + (position << 2));
 -}
 -
--static int cplbinfo_write_proc(struct file *file, const char __user *buffer,
--			       unsigned long count, void *data)
+-void mach_alphanum_brightness(int setting)
 -{
--	printk(KERN_INFO "Reset the CPLB swap in/out counts.\n");
--	memset(ipdt_swapcount_table, 0, MAX_SWITCH_I_CPLBS * sizeof(unsigned long));
--	memset(dpdt_swapcount_table, 0, MAX_SWITCH_D_CPLBS * sizeof(unsigned long));
--
--	return count;
+-	ctrl_outb(setting & 7, HDSP2534_ADDR + 0xc0);
 -}
+diff --git a/arch/sh64/mach-cayman/setup.c b/arch/sh64/mach-cayman/setup.c
+deleted file mode 100644
+index 726c520..0000000
+--- a/arch/sh64/mach-cayman/setup.c
++++ /dev/null
+@@ -1,239 +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.
+- *
+- * arch/sh64/mach-cayman/setup.c
+- *
+- * SH5 Cayman support
+- *
+- * This file handles the architecture-dependent parts of initialization
+- *
+- * Copyright David J. Mckay.
+- * Needs major work!
+- *
+- * benedict.gaster at superh.com:	 3rd May 2002
+- *    Added support for ramdisk, removing statically linked romfs at the same time.
+- *
+- * lethal at linux-sh.org:          15th May 2003
+- *    Use the generic procfs cpuinfo interface, just return a valid board name.
+- */
+-#include <linux/init.h>
+-#include <linux/kernel.h>
+-#include <asm/platform.h>
+-#include <asm/irq.h>
+-#include <asm/io.h>
 -
--static int __init cplbinfo_init(void)
+-/*
+- * Platform Dependent Interrupt Priorities.
+- */
+-
+-/* Using defaults defined in irq.h */
+-#define	RES NO_PRIORITY		/* Disabled */
+-#define IR0 IRL0_PRIORITY	/* IRLs */
+-#define IR1 IRL1_PRIORITY
+-#define IR2 IRL2_PRIORITY
+-#define IR3 IRL3_PRIORITY
+-#define PCA INTA_PRIORITY	/* PCI Ints */
+-#define PCB INTB_PRIORITY
+-#define PCC INTC_PRIORITY
+-#define PCD INTD_PRIORITY
+-#define SER TOP_PRIORITY
+-#define ERR TOP_PRIORITY
+-#define PW0 TOP_PRIORITY
+-#define PW1 TOP_PRIORITY
+-#define PW2 TOP_PRIORITY
+-#define PW3 TOP_PRIORITY
+-#define DM0 NO_PRIORITY		/* DMA Ints */
+-#define DM1 NO_PRIORITY
+-#define DM2 NO_PRIORITY
+-#define DM3 NO_PRIORITY
+-#define DAE NO_PRIORITY
+-#define TU0 TIMER_PRIORITY	/* TMU Ints */
+-#define TU1 NO_PRIORITY
+-#define TU2 NO_PRIORITY
+-#define TI2 NO_PRIORITY
+-#define ATI NO_PRIORITY		/* RTC Ints */
+-#define PRI NO_PRIORITY
+-#define CUI RTC_PRIORITY
+-#define ERI SCIF_PRIORITY	/* SCIF Ints */
+-#define RXI SCIF_PRIORITY
+-#define BRI SCIF_PRIORITY
+-#define TXI SCIF_PRIORITY
+-#define ITI TOP_PRIORITY	/* WDT Ints */
+-
+-/* Setup for the SMSC FDC37C935 */
+-#define SMSC_SUPERIO_BASE	0x04000000
+-#define SMSC_CONFIG_PORT_ADDR	0x3f0
+-#define SMSC_INDEX_PORT_ADDR	SMSC_CONFIG_PORT_ADDR
+-#define SMSC_DATA_PORT_ADDR	0x3f1
+-
+-#define SMSC_ENTER_CONFIG_KEY	0x55
+-#define SMSC_EXIT_CONFIG_KEY	0xaa
+-
+-#define SMCS_LOGICAL_DEV_INDEX	0x07
+-#define SMSC_DEVICE_ID_INDEX	0x20
+-#define SMSC_DEVICE_REV_INDEX	0x21
+-#define SMSC_ACTIVATE_INDEX	0x30
+-#define SMSC_PRIMARY_BASE_INDEX  0x60
+-#define SMSC_SECONDARY_BASE_INDEX 0x62
+-#define SMSC_PRIMARY_INT_INDEX	0x70
+-#define SMSC_SECONDARY_INT_INDEX 0x72
+-
+-#define SMSC_IDE1_DEVICE	1
+-#define SMSC_KEYBOARD_DEVICE	7
+-#define SMSC_CONFIG_REGISTERS	8
+-
+-#define SMSC_SUPERIO_READ_INDEXED(index) ({ \
+-	outb((index), SMSC_INDEX_PORT_ADDR); \
+-	inb(SMSC_DATA_PORT_ADDR); })
+-#define SMSC_SUPERIO_WRITE_INDEXED(val, index) ({ \
+-	outb((index), SMSC_INDEX_PORT_ADDR); \
+-	outb((val),   SMSC_DATA_PORT_ADDR); })
+-
+-#define IDE1_PRIMARY_BASE	0x01f0
+-#define IDE1_SECONDARY_BASE	0x03f6
+-
+-unsigned long smsc_superio_virt;
+-
+-/*
+- * Platform dependent structures: maps and parms block.
+- */
+-struct resource io_resources[] = {
+-	/* To be updated with external devices */
+-};
+-
+-struct resource kram_resources[] = {
+-	/* These must be last in the array */
+-	{ .name = "Kernel code", .start = 0, .end = 0 },
+-	/* These must be last in the array */
+-	{ .name = "Kernel data", .start = 0, .end = 0 }
+-};
+-
+-struct resource xram_resources[] = {
+-	/* To be updated with external devices */
+-};
+-
+-struct resource rom_resources[] = {
+-	/* To be updated with external devices */
+-};
+-
+-struct sh64_platform platform_parms = {
+-	.readonly_rootfs =	1,
+-	.initial_root_dev =	0x0100,
+-	.loader_type =		1,
+-	.io_res_p =		io_resources,
+-	.io_res_count =		ARRAY_SIZE(io_resources),
+-	.kram_res_p =		kram_resources,
+-	.kram_res_count =	ARRAY_SIZE(kram_resources),
+-	.xram_res_p =		xram_resources,
+-	.xram_res_count =	ARRAY_SIZE(xram_resources),
+-	.rom_res_p =		rom_resources,
+-	.rom_res_count =	ARRAY_SIZE(rom_resources),
+-};
+-
+-int platform_int_priority[NR_INTC_IRQS] = {
+-	IR0, IR1, IR2, IR3, PCA, PCB, PCC, PCD,	/* IRQ  0- 7 */
+-	RES, RES, RES, RES, SER, ERR, PW3, PW2,	/* IRQ  8-15 */
+-	PW1, PW0, DM0, DM1, DM2, DM3, DAE, RES,	/* IRQ 16-23 */
+-	RES, RES, RES, RES, RES, RES, RES, RES,	/* IRQ 24-31 */
+-	TU0, TU1, TU2, TI2, ATI, PRI, CUI, ERI,	/* IRQ 32-39 */
+-	RXI, BRI, TXI, RES, RES, RES, RES, RES,	/* IRQ 40-47 */
+-	RES, RES, RES, RES, RES, RES, RES, RES,	/* IRQ 48-55 */
+-	RES, RES, RES, RES, RES, RES, RES, ITI,	/* IRQ 56-63 */
+-};
+-
+-static int __init smsc_superio_setup(void)
 -{
--	struct proc_dir_entry *entry;
+-	unsigned char devid, devrev;
 -
--	entry = create_proc_entry("cplbinfo", 0, NULL);
--	if (!entry)
--		return -ENOMEM;
+-	smsc_superio_virt = onchip_remap(SMSC_SUPERIO_BASE, 1024, "SMSC SuperIO");
+-	if (!smsc_superio_virt) {
+-		panic("Unable to remap SMSC SuperIO\n");
+-	}
 -
--	entry->read_proc = cplbinfo_read_proc;
--	entry->write_proc = cplbinfo_write_proc;
--	entry->data = NULL;
+-	/* Initially the chip is in run state */
+-	/* Put it into configuration state */
+-	outb(SMSC_ENTER_CONFIG_KEY, SMSC_CONFIG_PORT_ADDR);
+-	outb(SMSC_ENTER_CONFIG_KEY, SMSC_CONFIG_PORT_ADDR);
+-
+-	/* Read device ID info */
+-	devid = SMSC_SUPERIO_READ_INDEXED(SMSC_DEVICE_ID_INDEX);
+-	devrev = SMSC_SUPERIO_READ_INDEXED(SMSC_DEVICE_REV_INDEX);
+-	printk("SMSC SuperIO devid %02x rev %02x\n", devid, devrev);
+-
+-	/* Select the keyboard device */
+-	SMSC_SUPERIO_WRITE_INDEXED(SMSC_KEYBOARD_DEVICE, SMCS_LOGICAL_DEV_INDEX);
+-
+-	/* enable it */
+-	SMSC_SUPERIO_WRITE_INDEXED(1, SMSC_ACTIVATE_INDEX);
+-
+-	/* Select the interrupts */
+-	/* On a PC keyboard is IRQ1, mouse is IRQ12 */
+-	SMSC_SUPERIO_WRITE_INDEXED(1, SMSC_PRIMARY_INT_INDEX);
+-	SMSC_SUPERIO_WRITE_INDEXED(12, SMSC_SECONDARY_INT_INDEX);
+-
+-#ifdef CONFIG_IDE
+-	/*
+-	 * Only IDE1 exists on the Cayman
+-	 */
+-
+-	/* Power it on */
+-	SMSC_SUPERIO_WRITE_INDEXED(1 << SMSC_IDE1_DEVICE, 0x22);
+-
+-	SMSC_SUPERIO_WRITE_INDEXED(SMSC_IDE1_DEVICE, SMCS_LOGICAL_DEV_INDEX);
+-	SMSC_SUPERIO_WRITE_INDEXED(1, SMSC_ACTIVATE_INDEX);
+-
+-	SMSC_SUPERIO_WRITE_INDEXED(IDE1_PRIMARY_BASE >> 8,
+-				   SMSC_PRIMARY_BASE_INDEX + 0);
+-	SMSC_SUPERIO_WRITE_INDEXED(IDE1_PRIMARY_BASE & 0xff,
+-				   SMSC_PRIMARY_BASE_INDEX + 1);
+-
+-	SMSC_SUPERIO_WRITE_INDEXED(IDE1_SECONDARY_BASE >> 8,
+-				   SMSC_SECONDARY_BASE_INDEX + 0);
+-	SMSC_SUPERIO_WRITE_INDEXED(IDE1_SECONDARY_BASE & 0xff,
+-				   SMSC_SECONDARY_BASE_INDEX + 1);
+-
+-	SMSC_SUPERIO_WRITE_INDEXED(14, SMSC_PRIMARY_INT_INDEX);
+-
+-	SMSC_SUPERIO_WRITE_INDEXED(SMSC_CONFIG_REGISTERS,
+-				   SMCS_LOGICAL_DEV_INDEX);
+-
+-	SMSC_SUPERIO_WRITE_INDEXED(0x00, 0xc2); /* GP42 = nIDE1_OE */
+-	SMSC_SUPERIO_WRITE_INDEXED(0x01, 0xc5); /* GP45 = IDE1_IRQ */
+-	SMSC_SUPERIO_WRITE_INDEXED(0x00, 0xc6); /* GP46 = nIOROP */
+-	SMSC_SUPERIO_WRITE_INDEXED(0x00, 0xc7); /* GP47 = nIOWOP */
+-#endif
+-
+-	/* Exit the configuration state */
+-	outb(SMSC_EXIT_CONFIG_KEY, SMSC_CONFIG_PORT_ADDR);
 -
 -	return 0;
 -}
 -
--static void __exit cplbinfo_exit(void)
+-/* This is grotty, but, because kernel is always referenced on the link line
+- * before any devices, this is safe.
+- */
+-__initcall(smsc_superio_setup);
+-
+-void __init platform_setup(void)
 -{
--	remove_proc_entry("cplbinfo", NULL);
+-	/* Cayman platform leaves the decision to head.S, for now */
+-	platform_parms.fpu_flags = fpu_in_use;
 -}
 -
--module_init(cplbinfo_init);
--module_exit(cplbinfo_exit);
-diff --git a/arch/blackfin/mach-common/cplbmgr.S b/arch/blackfin/mach-common/cplbmgr.S
+-void __init platform_monitor(void)
+-{
+-	/* Nothing yet .. */
+-}
+-
+-void __init platform_reserve(void)
+-{
+-	/* Nothing yet .. */
+-}
+-
+-const char *get_system_type(void)
+-{
+-	return "Hitachi Cayman";
+-}
+-
+diff --git a/arch/sh64/mach-harp/Makefile b/arch/sh64/mach-harp/Makefile
 deleted file mode 100644
-index 6f909cb..0000000
---- a/arch/blackfin/mach-common/cplbmgr.S
+index 2f2963f..0000000
+--- a/arch/sh64/mach-harp/Makefile
 +++ /dev/null
-@@ -1,619 +0,0 @@
+@@ -1 +0,0 @@
+-obj-y := setup.o
+diff --git a/arch/sh64/mach-harp/setup.c b/arch/sh64/mach-harp/setup.c
+deleted file mode 100644
+index 05011cb..0000000
+--- a/arch/sh64/mach-harp/setup.c
++++ /dev/null
+@@ -1,129 +0,0 @@
 -/*
-- * File:         arch/blackfin/mach-common/cplbmgtr.S
-- * Based on:
-- * Author:       LG Soft India
+- * 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.
 - *
-- * Created:      ?
-- * Description:  CPLB replacement routine for CPLB mismatch
+- * arch/sh64/mach-harp/setup.c
 - *
-- * Modified:
-- *               Copyright 2004-2006 Analog Devices Inc.
+- * SH-5 Simulator Platform Support
 - *
-- * Bugs:         Enter bugs at http://blackfin.uclinux.org/
+- * This file handles the architecture-dependent parts of 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.
+- * Copyright (C) 2000, 2001  Paolo Alberelli
 - *
-- * This program is distributed in the hope that it will be useful,
-- * but WITHOUT ANY WARRANTY; without even the implied warranty of
-- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-- * GNU General Public License for more details.
+- * benedict.gaster at superh.com:	 3rd May 2002
+- *    Added support for ramdisk, removing statically linked romfs at the same time. *
 - *
-- * 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
+- * lethal at linux-sh.org:          15th May 2003
+- *    Use the generic procfs cpuinfo interface, just return a valid board name.
 - */
+-#include <linux/init.h>
+-#include <linux/kernel.h>
+-#include <asm/platform.h>
+-#include <asm/irq.h>
 -
--/* Usage: int _cplb_mgr(is_data_miss,int enable_cache)
-- * is_data_miss==2 => Mark as Dirty, write to the clean data page
-- * is_data_miss==1 => Replace a data CPLB.
-- * is_data_miss==0 => Replace an instruction CPLB.
-- *
-- * Returns:
-- * CPLB_RELOADED	=> Successfully updated CPLB table.
-- * CPLB_NO_UNLOCKED	=> All CPLBs are locked, so cannot be evicted.
-- *			   This indicates that the CPLBs in the configuration
-- *			   tablei are badly configured, as this should never
-- *			   occur.
-- * CPLB_NO_ADDR_MATCH	=> The address being accessed, that triggered the
-- *			   exception, is not covered by any of the CPLBs in
-- *			   the configuration table. The application is
-- *			   presumably misbehaving.
-- * CPLB_PROT_VIOL	=> The address being accessed, that triggered the
-- *			   exception, was not a first-write to a clean Write
-- *			   Back Data page, and so presumably is a genuine
-- *			   violation of the page's protection attributes.
-- *			   The application is misbehaving.
+-/*
+- * Platform Dependent Interrupt Priorities.
 - */
 -
--#include <linux/linkage.h>
--#include <asm/blackfin.h>
--#include <asm/cplb.h>
+-/* Using defaults defined in irq.h */
+-#define	RES NO_PRIORITY		/* Disabled */
+-#define IR0 IRL0_PRIORITY	/* IRLs */
+-#define IR1 IRL1_PRIORITY
+-#define IR2 IRL2_PRIORITY
+-#define IR3 IRL3_PRIORITY
+-#define PCA INTA_PRIORITY	/* PCI Ints */
+-#define PCB INTB_PRIORITY
+-#define PCC INTC_PRIORITY
+-#define PCD INTD_PRIORITY
+-#define SER TOP_PRIORITY
+-#define ERR TOP_PRIORITY
+-#define PW0 TOP_PRIORITY
+-#define PW1 TOP_PRIORITY
+-#define PW2 TOP_PRIORITY
+-#define PW3 TOP_PRIORITY
+-#define DM0 NO_PRIORITY		/* DMA Ints */
+-#define DM1 NO_PRIORITY
+-#define DM2 NO_PRIORITY
+-#define DM3 NO_PRIORITY
+-#define DAE NO_PRIORITY
+-#define TU0 TIMER_PRIORITY	/* TMU Ints */
+-#define TU1 NO_PRIORITY
+-#define TU2 NO_PRIORITY
+-#define TI2 NO_PRIORITY
+-#define ATI NO_PRIORITY		/* RTC Ints */
+-#define PRI NO_PRIORITY
+-#define CUI RTC_PRIORITY
+-#define ERI SCIF_PRIORITY	/* SCIF Ints */
+-#define RXI SCIF_PRIORITY
+-#define BRI SCIF_PRIORITY
+-#define TXI SCIF_PRIORITY
+-#define ITI TOP_PRIORITY	/* WDT Ints */
 -
--#ifdef CONFIG_EXCPT_IRQ_SYSC_L1
--.section .l1.text
--#else
--.text
--#endif
+-/*
+- * Platform dependent structures: maps and parms block.
+- */
+-struct resource io_resources[] = {
+-	/* To be updated with external devices */
+-};
 -
--.align 2;
--ENTRY(_cplb_mgr)
+-struct resource kram_resources[] = {
+-	/* These must be last in the array */
+-	{ .name = "Kernel code", .start = 0, .end = 0 },
+-	/* These must be last in the array */
+-	{ .name = "Kernel data", .start = 0, .end = 0 }
+-};
 -
--	[--SP]=( R7:4,P5:3 );
+-struct resource xram_resources[] = {
+-	/* To be updated with external devices */
+-};
 -
--	CC = R0 == 2;
--	IF CC JUMP .Ldcplb_write;
+-struct resource rom_resources[] = {
+-	/* To be updated with external devices */
+-};
 -
--	CC = R0 == 0;
--	IF !CC JUMP .Ldcplb_miss_compare;
+-struct sh64_platform platform_parms = {
+-	.readonly_rootfs =	1,
+-	.initial_root_dev =	0x0100,
+-	.loader_type =		1,
+-	.io_res_p =		io_resources,
+-	.io_res_count =		ARRAY_SIZE(io_resources),
+-	.kram_res_p =		kram_resources,
+-	.kram_res_count =	ARRAY_SIZE(kram_resources),
+-	.xram_res_p =		xram_resources,
+-	.xram_res_count =	ARRAY_SIZE(xram_resources),
+-	.rom_res_p =		rom_resources,
+-	.rom_res_count =	ARRAY_SIZE(rom_resources),
+-};
 -
--	/* ICPLB Miss Exception. We need to choose one of the
--	* currently-installed CPLBs, and replace it with one
--	* from the configuration table.
--	*/
+-int platform_int_priority[NR_INTC_IRQS] = {
+-	IR0, IR1, IR2, IR3, PCA, PCB, PCC, PCD,	/* IRQ  0- 7 */
+-	RES, RES, RES, RES, SER, ERR, PW3, PW2,	/* IRQ  8-15 */
+-	PW1, PW0, DM0, DM1, DM2, DM3, DAE, RES,	/* IRQ 16-23 */
+-	RES, RES, RES, RES, RES, RES, RES, RES,	/* IRQ 24-31 */
+-	TU0, TU1, TU2, TI2, ATI, PRI, CUI, ERI,	/* IRQ 32-39 */
+-	RXI, BRI, TXI, RES, RES, RES, RES, RES,	/* IRQ 40-47 */
+-	RES, RES, RES, RES, RES, RES, RES, RES,	/* IRQ 48-55 */
+-	RES, RES, RES, RES, RES, RES, RES, ITI,	/* IRQ 56-63 */
+-};
 -
--	P4.L = LO(ICPLB_FAULT_ADDR);
--	P4.H = HI(ICPLB_FAULT_ADDR);
+-void __init platform_setup(void)
+-{
+-	/* Harp platform leaves the decision to head.S, for now */
+-	platform_parms.fpu_flags = fpu_in_use;
+-}
 -
--	P1 = 16;
--	P5.L = _page_size_table;
--	P5.H = _page_size_table;
+-void __init platform_monitor(void)
+-{
+-	/* Nothing yet .. */
+-}
 -
--	P0.L = LO(ICPLB_DATA0);
--	P0.H = HI(ICPLB_DATA0);
--	R4 = [P4];		/* Get faulting address*/
--	R6 = 64;		/* Advance past the fault address, which*/
--	R6 = R6 + R4;		/* we'll use if we find a match*/
--	R3 = ((16 << 8) | 2);	/* Extract mask, bits 16 and 17.*/
+-void __init platform_reserve(void)
+-{
+-	/* Nothing yet .. */
+-}
+-
+-const char *get_system_type(void)
+-{
+-	return "ST50 Harp";
+-}
+diff --git a/arch/sh64/mach-sim/Makefile b/arch/sh64/mach-sim/Makefile
+deleted file mode 100644
+index 2f2963f..0000000
+--- a/arch/sh64/mach-sim/Makefile
++++ /dev/null
+@@ -1 +0,0 @@
+-obj-y := setup.o
+diff --git a/arch/sh64/mach-sim/setup.c b/arch/sh64/mach-sim/setup.c
+deleted file mode 100644
+index e3386ec..0000000
+--- a/arch/sh64/mach-sim/setup.c
++++ /dev/null
+@@ -1,126 +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.
+- *
+- * arch/sh64/mach-sim/setup.c
+- *
+- * ST50 Simulator Platform Support
+- *
+- * This file handles the architecture-dependent parts of initialization
+- *
+- * Copyright (C) 2000, 2001  Paolo Alberelli
+- *
+- * lethal at linux-sh.org:          15th May 2003
+- *    Use the generic procfs cpuinfo interface, just return a valid board name.
+- */
+-#include <linux/init.h>
+-#include <linux/kernel.h>
+-#include <asm/platform.h>
+-#include <asm/irq.h>
+-
+-/*
+- * Platform Dependent Interrupt Priorities.
+- */
+-
+-/* Using defaults defined in irq.h */
+-#define	RES NO_PRIORITY		/* Disabled */
+-#define IR0 IRL0_PRIORITY	/* IRLs */
+-#define IR1 IRL1_PRIORITY
+-#define IR2 IRL2_PRIORITY
+-#define IR3 IRL3_PRIORITY
+-#define PCA INTA_PRIORITY	/* PCI Ints */
+-#define PCB INTB_PRIORITY
+-#define PCC INTC_PRIORITY
+-#define PCD INTD_PRIORITY
+-#define SER TOP_PRIORITY
+-#define ERR TOP_PRIORITY
+-#define PW0 TOP_PRIORITY
+-#define PW1 TOP_PRIORITY
+-#define PW2 TOP_PRIORITY
+-#define PW3 TOP_PRIORITY
+-#define DM0 NO_PRIORITY		/* DMA Ints */
+-#define DM1 NO_PRIORITY
+-#define DM2 NO_PRIORITY
+-#define DM3 NO_PRIORITY
+-#define DAE NO_PRIORITY
+-#define TU0 TIMER_PRIORITY	/* TMU Ints */
+-#define TU1 NO_PRIORITY
+-#define TU2 NO_PRIORITY
+-#define TI2 NO_PRIORITY
+-#define ATI NO_PRIORITY		/* RTC Ints */
+-#define PRI NO_PRIORITY
+-#define CUI RTC_PRIORITY
+-#define ERI SCIF_PRIORITY	/* SCIF Ints */
+-#define RXI SCIF_PRIORITY
+-#define BRI SCIF_PRIORITY
+-#define TXI SCIF_PRIORITY
+-#define ITI TOP_PRIORITY	/* WDT Ints */
 -
--	R5 = 0;
--.Lisearch:
+-/*
+- * Platform dependent structures: maps and parms block.
+- */
+-struct resource io_resources[] = {
+-	/* Nothing yet .. */
+-};
 -
--	R1 = [P0-0x100];	/* Address for this CPLB */
+-struct resource kram_resources[] = {
+-	/* These must be last in the array */
+-	{ .name = "Kernel code", .start = 0, .end = 0 },
+-	/* These must be last in the array */
+-	{ .name = "Kernel data", .start = 0, .end = 0 }
+-};
 -
--	R0 = [P0++];		/* Info for this CPLB*/
--	CC = BITTST(R0,0);	/* Is the CPLB valid?*/
--	IF !CC JUMP .Lnomatch;	/* Skip it, if not.*/
--	CC = R4 < R1(IU);	/* If fault address less than page start*/
--	IF CC JUMP .Lnomatch;	/* then skip this one.*/
--	R2 = EXTRACT(R0,R3.L) (Z);	/* Get page size*/
--	P1 = R2;
--	P1 = P5 + (P1<<2);	/* index into page-size table*/
--	R2 = [P1];		/* Get the page size*/
--	R1 = R1 + R2;		/* and add to page start, to get page end*/
--	CC = R4 < R1(IU);	/* and see whether fault addr is in page.*/
--	IF !CC R4 = R6;		/* If so, advance the address and finish loop.*/
--	IF !CC JUMP .Lisearch_done;
--.Lnomatch:
--	/* Go around again*/
--	R5 += 1;
--	CC = BITTST(R5, 4);	/* i.e CC = R5 >= 16*/
--	IF !CC JUMP .Lisearch;
+-struct resource xram_resources[] = {
+-	/* Nothing yet .. */
+-};
 -
--.Lisearch_done:
--	I0 = R4;		/* Fault address we'll search for*/
+-struct resource rom_resources[] = {
+-	/* Nothing yet .. */
+-};
 -
--	/* set up pointers */
--	P0.L = LO(ICPLB_DATA0);
--	P0.H = HI(ICPLB_DATA0);
+-struct sh64_platform platform_parms = {
+-	.readonly_rootfs =	1,
+-	.initial_root_dev =	0x0100,
+-	.loader_type =		1,
+-	.io_res_p =		io_resources,
+-	.io_res_count =		ARRAY_SIZE(io_resources),
+-	.kram_res_p =		kram_resources,
+-	.kram_res_count =	ARRAY_SIZE(kram_resources),
+-	.xram_res_p =		xram_resources,
+-	.xram_res_count =	ARRAY_SIZE(xram_resources),
+-	.rom_res_p =		rom_resources,
+-	.rom_res_count =	ARRAY_SIZE(rom_resources),
+-};
 -
--	/* The replacement procedure for ICPLBs */
+-int platform_int_priority[NR_IRQS] = {
+-	IR0, IR1, IR2, IR3, PCA, PCB, PCC, PCD,	/* IRQ  0- 7 */
+-	RES, RES, RES, RES, SER, ERR, PW3, PW2,	/* IRQ  8-15 */
+-	PW1, PW0, DM0, DM1, DM2, DM3, DAE, RES,	/* IRQ 16-23 */
+-	RES, RES, RES, RES, RES, RES, RES, RES,	/* IRQ 24-31 */
+-	TU0, TU1, TU2, TI2, ATI, PRI, CUI, ERI,	/* IRQ 32-39 */
+-	RXI, BRI, TXI, RES, RES, RES, RES, RES,	/* IRQ 40-47 */
+-	RES, RES, RES, RES, RES, RES, RES, RES,	/* IRQ 48-55 */
+-	RES, RES, RES, RES, RES, RES, RES, ITI,	/* IRQ 56-63 */
+-};
 -
--	P4.L = LO(IMEM_CONTROL);
--	P4.H = HI(IMEM_CONTROL);
+-void __init platform_setup(void)
+-{
+-	/* Simulator platform leaves the decision to head.S */
+-	platform_parms.fpu_flags = fpu_in_use;
+-}
 -
--	/* disable cplbs */
--	R5 = [P4];		/* Control Register*/
--	BITCLR(R5,ENICPLB_P);
--	CLI R1;
--	SSYNC;		/* SSYNC required before writing to IMEM_CONTROL. */
--	.align 8;
--	[P4] = R5;
--	SSYNC;
--	STI R1;
+-void __init platform_monitor(void)
+-{
+-	/* Nothing yet .. */
+-}
 -
--	R1 = -1;		/* end point comparison */
--	R3 = 16;		/* counter */
+-void __init platform_reserve(void)
+-{
+-	/* Nothing yet .. */
+-}
 -
--	/* Search through CPLBs for first non-locked entry */
--	/* Overwrite it by moving everyone else up by 1 */
--.Licheck_lock:
--	R0 = [P0++];
--	R3 = R3 + R1;
--	CC = R3 == R1;
--	IF CC JUMP .Lall_locked;
--	CC = BITTST(R0, 0);		/* an invalid entry is good */
--	IF !CC JUMP .Lifound_victim;
--	CC = BITTST(R0,1);		/* but a locked entry isn't */
--	IF CC JUMP .Licheck_lock;
+-const char *get_system_type(void)
+-{
+-	return "SH-5 Simulator";
+-}
+diff --git a/arch/sh64/mm/Makefile b/arch/sh64/mm/Makefile
+deleted file mode 100644
+index d0e8136..0000000
+--- a/arch/sh64/mm/Makefile
++++ /dev/null
+@@ -1,44 +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, 2001  Paolo Alberelli
+-# Copyright (C) 2003, 2004  Paul Mundt
+-#
+-# Makefile for the sh64-specific parts of the Linux memory manager.
+-#
+-# Note! Dependencies are done automagically by 'make dep', which also
+-# removes any old dependencies. DON'T put your own dependencies here
+-# unless it's something special (ie not a .c file).
+-#
 -
--.Lifound_victim:
--#ifdef CONFIG_CPLB_INFO
--	R7 = [P0 - 0x104];
--	P2.L = _ipdt_table;
--	P2.H = _ipdt_table;
--	P3.L = _ipdt_swapcount_table;
--	P3.H = _ipdt_swapcount_table;
--	P3 += -4;
--.Licount:
--	R2 = [P2];	/* address from config table */
--	P2 += 8;
--	P3 += 8;
--	CC = R2==-1;
--	IF CC JUMP .Licount_done;
--	CC = R7==R2;
--	IF !CC JUMP .Licount;
--	R7 = [P3];
--	R7 += 1;
--	[P3] = R7;
--	CSYNC;
--.Licount_done:
--#endif
--	LC0=R3;
--	LSETUP(.Lis_move,.Lie_move) LC0;
--.Lis_move:
--	R0 = [P0];
--	[P0 - 4] = R0;
--	R0 = [P0 - 0x100];
--	[P0-0x104] = R0;
--.Lie_move:P0+=4;
+-obj-y := cache.o consistent.o extable.o fault.o init.o ioremap.o \
+-	 tlbmiss.o tlb.o
 -
--	/* We've made space in the ICPLB table, so that ICPLB15
--	 * is now free to be overwritten. Next, we have to determine
--	 * which CPLB we need to install, from the configuration
--	 * table. This is a matter of getting the start-of-page
--	 * addresses and page-lengths from the config table, and
--	 * determining whether the fault address falls within that
--	 * range.
-- 	 */
+-obj-$(CONFIG_HUGETLB_PAGE)	+= hugetlbpage.o
 -
--	P2.L = _ipdt_table;
--	P2.H = _ipdt_table;
--#ifdef	CONFIG_CPLB_INFO
--	P3.L = _ipdt_swapcount_table;
--	P3.H = _ipdt_swapcount_table;
--	P3 += -8;
--#endif
--	P0.L = _page_size_table;
--	P0.H = _page_size_table;
+-# Special flags for tlbmiss.o.  This puts restrictions on the number of
+-# caller-save registers that the compiler can target when building this file.
+-# This is required because the code is called from a context in entry.S where
+-# very few registers have been saved in the exception handler (for speed
+-# reasons).
+-# The caller save registers that have been saved and which can be used are
+-# r2,r3,r4,r5 : argument passing
+-# r15, r18 : SP and LINK
+-# tr0-4 : allow all caller-save TR's.  The compiler seems to be able to make
+-#         use of them, so it's probably beneficial to performance to save them
+-#         and have them available for it.
+-#
+-# The resources not listed below are callee save, i.e. the compiler is free to
+-# use any of them and will spill them to the stack itself.
 -
--	/* Retrieve our fault address (which may have been advanced
--	 * because the faulting instruction crossed a page boundary).
--	 */
+-CFLAGS_tlbmiss.o += -ffixed-r7 \
+-	-ffixed-r8 -ffixed-r9 -ffixed-r10 -ffixed-r11 -ffixed-r12 \
+-	-ffixed-r13 -ffixed-r14 -ffixed-r16 -ffixed-r17 -ffixed-r19 \
+-	-ffixed-r20 -ffixed-r21 -ffixed-r22 -ffixed-r23 \
+-	-ffixed-r24 -ffixed-r25 -ffixed-r26 -ffixed-r27 \
+-	-ffixed-r36 -ffixed-r37 -ffixed-r38 -ffixed-r39 -ffixed-r40 \
+-	-ffixed-r41 -ffixed-r42 -ffixed-r43  \
+-	-ffixed-r60 -ffixed-r61 -ffixed-r62 \
+-	-fomit-frame-pointer
+diff --git a/arch/sh64/mm/cache.c b/arch/sh64/mm/cache.c
+deleted file mode 100644
+index 421487c..0000000
+--- a/arch/sh64/mm/cache.c
++++ /dev/null
+@@ -1,1032 +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.
+- *
+- * arch/sh64/mm/cache.c
+- *
+- * Original version Copyright (C) 2000, 2001  Paolo Alberelli
+- * Second version Copyright (C) benedict.gaster at superh.com 2002
+- * Third version Copyright Richard.Curnow at superh.com 2003
+- * Hacks to third version Copyright (C) 2003 Paul Mundt
+- */
 -
--	R0 = I0;
+-/****************************************************************************/
 -
--	/* An extraction pattern, to get the page-size bits from
--	 * the CPLB data entry. Bits 16-17, so two bits at posn 16.
--	 */
+-#include <linux/init.h>
+-#include <linux/mman.h>
+-#include <linux/mm.h>
+-#include <linux/threads.h>
+-#include <asm/page.h>
+-#include <asm/pgtable.h>
+-#include <asm/processor.h>
+-#include <asm/cache.h>
+-#include <asm/tlb.h>
+-#include <asm/io.h>
+-#include <asm/uaccess.h>
+-#include <asm/mmu_context.h>
+-#include <asm/pgalloc.h> /* for flush_itlb_range */
 -
--	R1 = ((16<<8)|2);
--.Linext:	R4 = [P2++];	/* address from config table */
--	R2 = [P2++];	/* data from config table */
--#ifdef	CONFIG_CPLB_INFO
--	P3 += 8;
--#endif
+-#include <linux/proc_fs.h>
 -
--	CC = R4 == -1;	/* End of config table*/
--	IF CC JUMP .Lno_page_in_table;
+-/* This function is in entry.S */
+-extern unsigned long switch_and_save_asid(unsigned long new_asid);
 -
--	/* See if failed address > start address */
--	CC = R4 <= R0(IU);
--	IF !CC JUMP .Linext;
+-/* Wired TLB entry for the D-cache */
+-static unsigned long long dtlb_cache_slot;
 -
--	/* extract page size (17:16)*/
--	R3 = EXTRACT(R2, R1.L) (Z);
+-/**
+- * sh64_cache_init()
+- *
+- * This is pretty much just a straightforward clone of the SH
+- * detect_cpu_and_cache_system().
+- *
+- * This function is responsible for setting up all of the cache
+- * info dynamically as well as taking care of CPU probing and
+- * setting up the relevant subtype data.
+- *
+- * FIXME: For the time being, we only really support the SH5-101
+- * out of the box, and don't support dynamic probing for things
+- * like the SH5-103 or even cut2 of the SH5-101. Implement this
+- * later!
+- */
+-int __init sh64_cache_init(void)
+-{
+-	/*
+-	 * First, setup some sane values for the I-cache.
+-	 */
+-	cpu_data->icache.ways		= 4;
+-	cpu_data->icache.sets		= 256;
+-	cpu_data->icache.linesz		= L1_CACHE_BYTES;
 -
--	/* add page size to addr to get range */
+-	/*
+-	 * FIXME: This can probably be cleaned up a bit as well.. for example,
+-	 * do we really need the way shift _and_ the way_step_shift ?? Judging
+-	 * by the existing code, I would guess no.. is there any valid reason
+-	 * why we need to be tracking this around?
+-	 */
+-	cpu_data->icache.way_shift	= 13;
+-	cpu_data->icache.entry_shift	= 5;
+-	cpu_data->icache.set_shift	= 4;
+-	cpu_data->icache.way_step_shift	= 16;
+-	cpu_data->icache.asid_shift	= 2;
 -
--	P5 = R3;
--	P5 = P0 + (P5 << 2);	/* scaled, for int access*/
--	R3 = [P5];
--	R3 = R3 + R4;
+-	/*
+-	 * way offset = cache size / associativity, so just don't factor in
+-	 * associativity in the first place..
+-	 */
+-	cpu_data->icache.way_ofs	= cpu_data->icache.sets *
+-					  cpu_data->icache.linesz;
 -
--	/* See if failed address < (start address + page size) */
--	CC = R0 < R3(IU);
--	IF !CC JUMP .Linext;
+-	cpu_data->icache.asid_mask	= 0x3fc;
+-	cpu_data->icache.idx_mask	= 0x1fe0;
+-	cpu_data->icache.epn_mask	= 0xffffe000;
+-	cpu_data->icache.flags		= 0;
 -
--	/* We've found a CPLB in the config table that covers
--	 * the faulting address, so install this CPLB into the
--	 * last entry of the table.
+-	/*
+-	 * Next, setup some sane values for the D-cache.
+-	 *
+-	 * On the SH5, these are pretty consistent with the I-cache settings,
+-	 * so we just copy over the existing definitions.. these can be fixed
+-	 * up later, especially if we add runtime CPU probing.
+-	 *
+-	 * Though in the meantime it saves us from having to duplicate all of
+-	 * the above definitions..
 -	 */
+-	cpu_data->dcache		= cpu_data->icache;
 -
--	P1.L = LO(ICPLB_DATA15);		/* ICPLB_DATA15 */
--	P1.H = HI(ICPLB_DATA15);
--	[P1] = R2;
--	[P1-0x100] = R4;
--#ifdef	CONFIG_CPLB_INFO
--	R3 = [P3];
--	R3 += 1;
--	[P3] = R3;
+-	/*
+-	 * Setup any cache-related flags here
+-	 */
+-#if defined(CONFIG_DCACHE_WRITE_THROUGH)
+-	set_bit(SH_CACHE_MODE_WT, &(cpu_data->dcache.flags));
+-#elif defined(CONFIG_DCACHE_WRITE_BACK)
+-	set_bit(SH_CACHE_MODE_WB, &(cpu_data->dcache.flags));
 -#endif
 -
--	/* P4 points to IMEM_CONTROL, and R5 contains its old
--	 * value, after we disabled ICPLBS. Re-enable them.
+-	/*
+-	 * We also need to reserve a slot for the D-cache in the DTLB, so we
+-	 * do this now ..
 -	 */
+-	dtlb_cache_slot			= sh64_get_wired_dtlb_entry();
 -
--	BITSET(R5,ENICPLB_P);
--	CLI R2;
--	SSYNC;		/* SSYNC required before writing to IMEM_CONTROL. */
--	.align 8;
--	[P4] = R5;
--	SSYNC;
--	STI R2;
+-	return 0;
+-}
 -
--	( R7:4,P5:3 ) = [SP++];
--	R0 = CPLB_RELOADED;
--	RTS;
+-#ifdef CONFIG_DCACHE_DISABLED
+-#define sh64_dcache_purge_all()					do { } while (0)
+-#define sh64_dcache_purge_coloured_phy_page(paddr, eaddr)	do { } while (0)
+-#define sh64_dcache_purge_user_range(mm, start, end)		do { } while (0)
+-#define sh64_dcache_purge_phy_page(paddr)			do { } while (0)
+-#define sh64_dcache_purge_virt_page(mm, eaddr)			do { } while (0)
+-#define sh64_dcache_purge_kernel_range(start, end)		do { } while (0)
+-#define sh64_dcache_wback_current_user_range(start, end)	do { } while (0)
+-#endif
 -
--/* FAILED CASES*/
--.Lno_page_in_table:
--	R0 = CPLB_NO_ADDR_MATCH;
--	JUMP .Lfail_ret;
+-/*##########################################################################*/
 -
--.Lall_locked:
--	R0 = CPLB_NO_UNLOCKED;
--	JUMP .Lfail_ret;
+-/* From here onwards, a rewrite of the implementation,
+-   by Richard.Curnow at superh.com.
 -
--.Lprot_violation:
--	R0 = CPLB_PROT_VIOL;
+-   The major changes in this compared to the old version are;
+-   1. use more selective purging through OCBP instead of using ALLOCO to purge
+-      by natural replacement.  This avoids purging out unrelated cache lines
+-      that happen to be in the same set.
+-   2. exploit the APIs copy_user_page and clear_user_page better
+-   3. be more selective about I-cache purging, in particular use invalidate_all
+-      more sparingly.
 -
--.Lfail_ret:
--	/* Make sure we turn protection/cache back on, even in the failing case */
--	BITSET(R5,ENICPLB_P);
--	CLI R2;
--	SSYNC;          /* SSYNC required before writing to IMEM_CONTROL. */
--	.align 8;
--	[P4] = R5;
--	SSYNC;
--	STI R2;
+-   */
 -
--	( R7:4,P5:3 ) = [SP++];
--	RTS;
+-/*##########################################################################
+-			       SUPPORT FUNCTIONS
+-  ##########################################################################*/
 -
--.Ldcplb_write:
+-/****************************************************************************/
+-/* The following group of functions deal with mapping and unmapping a temporary
+-   page into the DTLB slot that have been set aside for our exclusive use. */
+-/* In order to accomplish this, we use the generic interface for adding and
+-   removing a wired slot entry as defined in arch/sh64/mm/tlb.c */
+-/****************************************************************************/
 -
--	/* if a DCPLB is marked as write-back (CPLB_WT==0), and
--	 * it is clean (CPLB_DIRTY==0), then a write to the
--	 * CPLB's page triggers a protection violation. We have to
--	 * mark the CPLB as dirty, to indicate that there are
--	 * pending writes associated with the CPLB.
--	 */
+-static unsigned long slot_own_flags;
 -
--	P4.L = LO(DCPLB_STATUS);
--	P4.H = HI(DCPLB_STATUS);
--	P3.L = LO(DCPLB_DATA0);
--	P3.H = HI(DCPLB_DATA0);
--	R5 = [P4];
+-static inline void sh64_setup_dtlb_cache_slot(unsigned long eaddr, unsigned long asid, unsigned long paddr)
+-{
+-	local_irq_save(slot_own_flags);
+-	sh64_setup_tlb_slot(dtlb_cache_slot, eaddr, asid, paddr);
+-}
 -
--	/* A protection violation can be caused by more than just writes
--	 * to a clean WB page, so we have to ensure that:
--	 * - It's a write
--	 * - to a clean WB page
--	 * - and is allowed in the mode the access occurred.
--	 */
+-static inline void sh64_teardown_dtlb_cache_slot(void)
+-{
+-	sh64_teardown_tlb_slot(dtlb_cache_slot);
+-	local_irq_restore(slot_own_flags);
+-}
 -
--	CC = BITTST(R5, 16);	/* ensure it was a write*/
--	IF !CC JUMP .Lprot_violation;
+-/****************************************************************************/
 -
--	/* to check the rest, we have to retrieve the DCPLB.*/
+-#ifndef CONFIG_ICACHE_DISABLED
 -
--	/* The low half of DCPLB_STATUS is a bit mask*/
+-static void __inline__ sh64_icache_inv_all(void)
+-{
+-	unsigned long long addr, flag, data;
+-	unsigned int flags;
 -
--	R2 = R5.L (Z);	/* indicating which CPLB triggered the event.*/
--	R3 = 30;	/* so we can use this to determine the offset*/
--	R2.L = SIGNBITS R2;
--	R2 = R2.L (Z);	/* into the DCPLB table.*/
--	R3 = R3 - R2;
--	P4 = R3;
--	P3 = P3 + (P4<<2);
--	R3 = [P3];	/* Retrieve the CPLB*/
+-	addr=ICCR0;
+-	flag=ICCR0_ICI;
+-	data=0;
 -
--	/* Now we can check whether it's a clean WB page*/
+-	/* Make this a critical section for safety (probably not strictly necessary.) */
+-	local_irq_save(flags);
 -
--	CC = BITTST(R3, 14);	/* 0==WB, 1==WT*/
--	IF CC JUMP .Lprot_violation;
--	CC = BITTST(R3, 7);	/* 0 == clean, 1 == dirty*/
--	IF CC JUMP .Lprot_violation;
+-	/* Without %1 it gets unexplicably wrong */
+-	asm volatile("getcfg	%3, 0, %0\n\t"
+-			"or	%0, %2, %0\n\t"
+-			"putcfg	%3, 0, %0\n\t"
+-			"synci"
+-			: "=&r" (data)
+-			: "0" (data), "r" (flag), "r" (addr));
 -
--	/* Check whether the write is allowed in the mode that was active.*/
+-	local_irq_restore(flags);
+-}
 -
--	R2 = 1<<3;		/* checking write in user mode*/
--	CC = BITTST(R5, 17);	/* 0==was user, 1==was super*/
--	R5 = CC;
--	R2 <<= R5;		/* if was super, check write in super mode*/
--	R2 = R3 & R2;
--	CC = R2 == 0;
--	IF CC JUMP .Lprot_violation;
+-static void sh64_icache_inv_kernel_range(unsigned long start, unsigned long end)
+-{
+-	/* Invalidate range of addresses [start,end] from the I-cache, where
+-	 * the addresses lie in the kernel superpage. */
 -
--	/* It's a genuine write-to-clean-page.*/
+-	unsigned long long ullend, addr, aligned_start;
+-#if (NEFF == 32)
+-	aligned_start = (unsigned long long)(signed long long)(signed long) start;
+-#else
+-#error "NEFF != 32"
+-#endif
+-	aligned_start &= L1_CACHE_ALIGN_MASK;
+-	addr = aligned_start;
+-#if (NEFF == 32)
+-	ullend = (unsigned long long) (signed long long) (signed long) end;
+-#else
+-#error "NEFF != 32"
+-#endif
+-	while (addr <= ullend) {
+-		asm __volatile__ ("icbi %0, 0" : : "r" (addr));
+-		addr += L1_CACHE_BYTES;
+-	}
+-}
 -
--	BITSET(R3, 7);		/* mark as dirty*/
--	[P3] = R3;		/* and write back.*/
--	NOP;
--	CSYNC;
--	( R7:4,P5:3 ) = [SP++];
--	R0 = CPLB_RELOADED;
--	RTS;
+-static void sh64_icache_inv_user_page(struct vm_area_struct *vma, unsigned long eaddr)
+-{
+-	/* If we get called, we know that vma->vm_flags contains VM_EXEC.
+-	   Also, eaddr is page-aligned. */
+-
+-	unsigned long long addr, end_addr;
+-	unsigned long flags = 0;
+-	unsigned long running_asid, vma_asid;
+-	addr = eaddr;
+-	end_addr = addr + PAGE_SIZE;
+-
+-	/* Check whether we can use the current ASID for the I-cache
+-	   invalidation.  For example, if we're called via
+-	   access_process_vm->flush_cache_page->here, (e.g. when reading from
+-	   /proc), 'running_asid' will be that of the reader, not of the
+-	   victim.
+-
+-	   Also, note the risk that we might get pre-empted between the ASID
+-	   compare and blocking IRQs, and before we regain control, the
+-	   pid->ASID mapping changes.  However, the whole cache will get
+-	   invalidated when the mapping is renewed, so the worst that can
+-	   happen is that the loop below ends up invalidating somebody else's
+-	   cache entries.
+-	*/
 -
--.Ldcplb_miss_compare:
+-	running_asid = get_asid();
+-	vma_asid = (vma->vm_mm->context & MMU_CONTEXT_ASID_MASK);
+-	if (running_asid != vma_asid) {
+-		local_irq_save(flags);
+-		switch_and_save_asid(vma_asid);
+-	}
+-	while (addr < end_addr) {
+-		/* Worth unrolling a little */
+-		asm __volatile__("icbi %0,  0" : : "r" (addr));
+-		asm __volatile__("icbi %0, 32" : : "r" (addr));
+-		asm __volatile__("icbi %0, 64" : : "r" (addr));
+-		asm __volatile__("icbi %0, 96" : : "r" (addr));
+-		addr += 128;
+-	}
+-	if (running_asid != vma_asid) {
+-		switch_and_save_asid(running_asid);
+-		local_irq_restore(flags);
+-	}
+-}
 -
--	/* Data CPLB Miss event. We need to choose a CPLB to
--	 * evict, and then locate a new CPLB to install from the
--	 * config table, that covers the faulting address.
--	 */
+-/****************************************************************************/
 -
--	P1.L = LO(DCPLB_DATA15);
--	P1.H = HI(DCPLB_DATA15);
+-static void sh64_icache_inv_user_page_range(struct mm_struct *mm,
+-			  unsigned long start, unsigned long end)
+-{
+-	/* Used for invalidating big chunks of I-cache, i.e. assume the range
+-	   is whole pages.  If 'start' or 'end' is not page aligned, the code
+-	   is conservative and invalidates to the ends of the enclosing pages.
+-	   This is functionally OK, just a performance loss. */
 -
--	P4.L = LO(DCPLB_FAULT_ADDR);
--	P4.H = HI(DCPLB_FAULT_ADDR);
--	R4 = [P4];
--	I0 = R4;
+-	/* See the comments below in sh64_dcache_purge_user_range() regarding
+-	   the choice of algorithm.  However, for the I-cache option (2) isn't
+-	   available because there are no physical tags so aliases can't be
+-	   resolved.  The icbi instruction has to be used through the user
+-	   mapping.   Because icbi is cheaper than ocbp on a cache hit, it
+-	   would be cheaper to use the selective code for a large range than is
+-	   possible with the D-cache.  Just assume 64 for now as a working
+-	   figure.
+-	   */
 -
--	/* The replacement procedure for DCPLBs*/
+-	int n_pages;
 -
--	R6 = R1;	/* Save for later*/
+-	if (!mm) return;
 -
--	/* Turn off CPLBs while we work.*/
--	P4.L = LO(DMEM_CONTROL);
--	P4.H = HI(DMEM_CONTROL);
--	R5 = [P4];
--	BITCLR(R5,ENDCPLB_P);
--	CLI R0;
--	SSYNC;		/* SSYNC required before writing to DMEM_CONTROL. */
--	.align 8;
--	[P4] = R5;
--	SSYNC;
--	STI R0;
+-	n_pages = ((end - start) >> PAGE_SHIFT);
+-	if (n_pages >= 64) {
+-		sh64_icache_inv_all();
+-	} else {
+-		unsigned long aligned_start;
+-		unsigned long eaddr;
+-		unsigned long after_last_page_start;
+-		unsigned long mm_asid, current_asid;
+-		unsigned long long flags = 0ULL;
+-
+-		mm_asid = mm->context & MMU_CONTEXT_ASID_MASK;
+-		current_asid = get_asid();
+-
+-		if (mm_asid != current_asid) {
+-			/* Switch ASID and run the invalidate loop under cli */
+-			local_irq_save(flags);
+-			switch_and_save_asid(mm_asid);
+-		}
+-
+-		aligned_start = start & PAGE_MASK;
+-		after_last_page_start = PAGE_SIZE + ((end - 1) & PAGE_MASK);
+-
+-		while (aligned_start < after_last_page_start) {
+-			struct vm_area_struct *vma;
+-			unsigned long vma_end;
+-			vma = find_vma(mm, aligned_start);
+-			if (!vma || (aligned_start <= vma->vm_end)) {
+-				/* Avoid getting stuck in an error condition */
+-				aligned_start += PAGE_SIZE;
+-				continue;
+-			}
+-			vma_end = vma->vm_end;
+-			if (vma->vm_flags & VM_EXEC) {
+-				/* Executable */
+-				eaddr = aligned_start;
+-				while (eaddr < vma_end) {
+-					sh64_icache_inv_user_page(vma, eaddr);
+-					eaddr += PAGE_SIZE;
+-				}
+-			}
+-			aligned_start = vma->vm_end; /* Skip to start of next region */
+-		}
+-		if (mm_asid != current_asid) {
+-			switch_and_save_asid(current_asid);
+-			local_irq_restore(flags);
+-		}
+-	}
+-}
 -
--	/* Start looking for a CPLB to evict. Our order of preference
--	 * is: invalid CPLBs, clean CPLBs, dirty CPLBs. Locked CPLBs
--	 * are no good.
--	 */
+-static void sh64_icache_inv_user_small_range(struct mm_struct *mm,
+-						unsigned long start, int len)
+-{
 -
--	I1.L = LO(DCPLB_DATA0);
--	I1.H = HI(DCPLB_DATA0);
--	P1 = 2;
--	P2 = 16;
--	I2.L = _dcplb_preference;
--	I2.H = _dcplb_preference;
--	LSETUP(.Lsdsearch1, .Ledsearch1) LC0 = P1;
--.Lsdsearch1:
--	R0 = [I2++];		/* Get the bits we're interested in*/
--	P0 = I1;		/* Go back to start of table*/
--	LSETUP (.Lsdsearch2, .Ledsearch2) LC1 = P2;
--.Lsdsearch2:
--	R1 = [P0++];		/* Fetch each installed CPLB in turn*/
--	R2 = R1 & R0;		/* and test for interesting bits.*/
--	CC = R2 == 0;		/* If none are set, it'll do.*/
--	IF !CC JUMP .Lskip_stack_check;
+-	/* Invalidate a small range of user context I-cache, not necessarily
+-	   page (or even cache-line) aligned. */
 -
--	R2 = [P0 - 0x104]; 	/* R2 - PageStart */
--	P3.L = _page_size_table; /* retrieve end address */
--	P3.H = _page_size_table; /* retrieve end address */
--	R3 = 0x1002;		/* 16th - position, 2 bits -length */
--#if ANOMALY_05000209
--	nop;			/* Anomaly 05000209 */
--#endif
--	R7 = EXTRACT(R1,R3.l);
--	R7 = R7 << 2;		/* Page size index offset */
--	P5 = R7;
--	P3 = P3 + P5;
--	R7 = [P3];		/* page size in bytes */
+-	unsigned long long eaddr = start;
+-	unsigned long long eaddr_end = start + len;
+-	unsigned long current_asid, mm_asid;
+-	unsigned long long flags;
+-	unsigned long long epage_start;
 -
--	R7 = R2 + R7;		/* R7 - PageEnd */
--	R4 = SP; 		/* Test SP is in range */
+-	/* Since this is used inside ptrace, the ASID in the mm context
+-	   typically won't match current_asid.  We'll have to switch ASID to do
+-	   this.  For safety, and given that the range will be small, do all
+-	   this under cli.
 -
--	CC = R7 < R4;		/* if PageEnd < SP */
--	IF CC JUMP .Ldfound_victim;
--	R3 = 0x284;		/* stack length from start of trap till
--				 * the point.
--				 * 20 stack locations for future modifications
--				 */
--	R4 = R4 + R3;
--	CC = R4 < R2;		/* if SP + stacklen < PageStart */
--	IF CC JUMP .Ldfound_victim;
--.Lskip_stack_check:
+-	   Note, there is a hazard that the ASID in mm->context is no longer
+-	   actually associated with mm, i.e. if the mm->context has started a
+-	   new cycle since mm was last active.  However, this is just a
+-	   performance issue: all that happens is that we invalidate lines
+-	   belonging to another mm, so the owning process has to refill them
+-	   when that mm goes live again.  mm itself can't have any cache
+-	   entries because there will have been a flush_cache_all when the new
+-	   mm->context cycle started. */
 -
--.Ledsearch2: NOP;
--.Ledsearch1: NOP;
+-	/* Align to start of cache line.  Otherwise, suppose len==8 and start
+-	   was at 32N+28 : the last 4 bytes wouldn't get invalidated. */
+-	eaddr = start & L1_CACHE_ALIGN_MASK;
+-	eaddr_end = start + len;
 -
--	/* If we got here, we didn't find a DCPLB we considered
--	 * replacable, which means all of them were locked.
--	 */
+-	local_irq_save(flags);
+-	mm_asid = mm->context & MMU_CONTEXT_ASID_MASK;
+-	current_asid = switch_and_save_asid(mm_asid);
 -
--	JUMP .Lall_locked;
--.Ldfound_victim:
+-	epage_start = eaddr & PAGE_MASK;
 -
--#ifdef CONFIG_CPLB_INFO
--	R7 = [P0 - 0x104];
--	P2.L = _dpdt_table;
--	P2.H = _dpdt_table;
--	P3.L = _dpdt_swapcount_table;
--	P3.H = _dpdt_swapcount_table;
--	P3 += -4;
--.Ldicount:
--	R2 = [P2];
--	P2 += 8;
--	P3 += 8;
--	CC = R2==-1;
--	IF CC JUMP .Ldicount_done;
--	CC = R7==R2;
--	IF !CC JUMP .Ldicount;
--	R7 = [P3];
--	R7 += 1;
--	[P3] = R7;
--.Ldicount_done:
--#endif
+-	while (eaddr < eaddr_end)
+-	{
+-		asm __volatile__("icbi %0, 0" : : "r" (eaddr));
+-		eaddr += L1_CACHE_BYTES;
+-	}
+-	switch_and_save_asid(current_asid);
+-	local_irq_restore(flags);
+-}
 -
--	/* Clean down the hardware loops*/
--	R2 = 0;
--	LC1 = R2;
--	LC0 = R2;
+-static void sh64_icache_inv_current_user_range(unsigned long start, unsigned long end)
+-{
+-	/* The icbi instruction never raises ITLBMISS.  i.e. if there's not a
+-	   cache hit on the virtual tag the instruction ends there, without a
+-	   TLB lookup. */
 -
--	/* There's a suitable victim in [P0-4] (because we've
--	 * advanced already).
--	 */
+-	unsigned long long aligned_start;
+-	unsigned long long ull_end;
+-	unsigned long long addr;
 -
--.LDdoverwrite:
+-	ull_end = end;
 -
--	/* [P0-4] is a suitable victim CPLB, so we want to
--	 * overwrite it by moving all the following CPLBs
--	 * one space closer to the start.
--	 */
+-	/* Just invalidate over the range using the natural addresses.  TLB
+-	   miss handling will be OK (TBC).  Since it's for the current process,
+-	   either we're already in the right ASID context, or the ASIDs have
+-	   been recycled since we were last active in which case we might just
+-	   invalidate another processes I-cache entries : no worries, just a
+-	   performance drop for him. */
+-	aligned_start = start & L1_CACHE_ALIGN_MASK;
+-	addr = aligned_start;
+-	while (addr < ull_end) {
+-		asm __volatile__ ("icbi %0, 0" : : "r" (addr));
+-		asm __volatile__ ("nop");
+-		asm __volatile__ ("nop");
+-		addr += L1_CACHE_BYTES;
+-	}
+-}
 -
--	R1.L = LO(DCPLB_DATA16);		/* DCPLB_DATA15 + 4 */
--	R1.H = HI(DCPLB_DATA16);
--	R0 = P0;
+-#endif /* !CONFIG_ICACHE_DISABLED */
 -
--	/* If the victim happens to be in DCPLB15,
--	 * we don't need to move anything.
--	 */
+-/****************************************************************************/
 -
--	CC = R1 == R0;
--	IF CC JUMP .Lde_moved;
--	R1 = R1 - R0;
--	R1 >>= 2;
--	P1 = R1;
--	LSETUP(.Lds_move, .Lde_move) LC0=P1;
--.Lds_move:
--	R0 = [P0++];	/* move data */
--	[P0 - 8] = R0;
--	R0 = [P0-0x104]	/* move address */
--.Lde_move: [P0-0x108] = R0;
+-#ifndef CONFIG_DCACHE_DISABLED
 -
--	/* We've now made space in DCPLB15 for the new CPLB to be
--	 * installed. The next stage is to locate a CPLB in the
--	 * config table that covers the faulting address.
--	 */
+-/* Buffer used as the target of alloco instructions to purge data from cache
+-   sets by natural eviction. -- RPC */
+-#define DUMMY_ALLOCO_AREA_SIZE L1_CACHE_SIZE_BYTES + (1024 * 4)
+-static unsigned char dummy_alloco_area[DUMMY_ALLOCO_AREA_SIZE] __cacheline_aligned = { 0, };
 -
--.Lde_moved:NOP;
--	R0 = I0;		/* Our faulting address */
+-/****************************************************************************/
 -
--	P2.L = _dpdt_table;
--	P2.H = _dpdt_table;
--#ifdef	CONFIG_CPLB_INFO
--	P3.L = _dpdt_swapcount_table;
--	P3.H = _dpdt_swapcount_table;
--	P3 += -8;
--#endif
+-static void __inline__ sh64_dcache_purge_sets(int sets_to_purge_base, int n_sets)
+-{
+-	/* Purge all ways in a particular block of sets, specified by the base
+-	   set number and number of sets.  Can handle wrap-around, if that's
+-	   needed.  */
 -
--	P1.L = _page_size_table;
--	P1.H = _page_size_table;
+-	int dummy_buffer_base_set;
+-	unsigned long long eaddr, eaddr0, eaddr1;
+-	int j;
+-	int set_offset;
 -
--	/* An extraction pattern, to retrieve bits 17:16.*/
+-	dummy_buffer_base_set = ((int)&dummy_alloco_area & cpu_data->dcache.idx_mask) >> cpu_data->dcache.entry_shift;
+-	set_offset = sets_to_purge_base - dummy_buffer_base_set;
 -
--	R1 = (16<<8)|2;
--.Ldnext:	R4 = [P2++];	/* address */
--	R2 = [P2++];	/* data */
--#ifdef	CONFIG_CPLB_INFO
--	P3 += 8;
--#endif
+-	for (j=0; j<n_sets; j++, set_offset++) {
+-		set_offset &= (cpu_data->dcache.sets - 1);
+-		eaddr0 = (unsigned long long)dummy_alloco_area + (set_offset << cpu_data->dcache.entry_shift);
 -
--	CC = R4 == -1;
--	IF CC JUMP .Lno_page_in_table;
+-		/* Do one alloco which hits the required set per cache way.  For
+-		   write-back mode, this will purge the #ways resident lines.   There's
+-		   little point unrolling this loop because the allocos stall more if
+-		   they're too close together. */
+-		eaddr1 = eaddr0 + cpu_data->dcache.way_ofs * cpu_data->dcache.ways;
+-		for (eaddr=eaddr0; eaddr<eaddr1; eaddr+=cpu_data->dcache.way_ofs) {
+-			asm __volatile__ ("alloco %0, 0" : : "r" (eaddr));
+-			asm __volatile__ ("synco"); /* TAKum03020 */
+-		}
 -
--	/* See if failed address > start address */
--	CC = R4 <= R0(IU);
--	IF !CC JUMP .Ldnext;
+-		eaddr1 = eaddr0 + cpu_data->dcache.way_ofs * cpu_data->dcache.ways;
+-		for (eaddr=eaddr0; eaddr<eaddr1; eaddr+=cpu_data->dcache.way_ofs) {
+-			/* Load from each address.  Required because alloco is a NOP if
+-			   the cache is write-through.  Write-through is a config option. */
+-			if (test_bit(SH_CACHE_MODE_WT, &(cpu_data->dcache.flags)))
+-				*(volatile unsigned char *)(int)eaddr;
+-		}
+-	}
 -
--	/* extract page size (17:16)*/
--	R3 = EXTRACT(R2, R1.L) (Z);
+-	/* Don't use OCBI to invalidate the lines.  That costs cycles directly.
+-	   If the dummy block is just left resident, it will naturally get
+-	   evicted as required.  */
 -
--	/* add page size to addr to get range */
+-	return;
+-}
 -
--	P5 = R3;
--	P5 = P1 + (P5 << 2);
--	R3 = [P5];
--	R3 = R3 + R4;
+-/****************************************************************************/
 -
--	/* See if failed address < (start address + page size) */
--	CC = R0 < R3(IU);
--	IF !CC JUMP .Ldnext;
+-static void sh64_dcache_purge_all(void)
+-{
+-	/* Purge the entire contents of the dcache.  The most efficient way to
+-	   achieve this is to use alloco instructions on a region of unused
+-	   memory equal in size to the cache, thereby causing the current
+-	   contents to be discarded by natural eviction.  The alternative,
+-	   namely reading every tag, setting up a mapping for the corresponding
+-	   page and doing an OCBP for the line, would be much more expensive.
+-	   */
 -
--	/* We've found the CPLB that should be installed, so
--	 * write it into CPLB15, masking off any caching bits
--	 * if necessary.
--	 */
+-	sh64_dcache_purge_sets(0, cpu_data->dcache.sets);
 -
--	P1.L = LO(DCPLB_DATA15);
--	P1.H = HI(DCPLB_DATA15);
+-	return;
 -
--	/* If the DCPLB has cache bits set, but caching hasn't
--	 * been enabled, then we want to mask off the cache-in-L1
--	 * bit before installing. Moreover, if caching is off, we
--	 * also want to ensure that the DCPLB has WT mode set, rather
--	 * than WB, since WB pages still trigger first-write exceptions
--	 * even when not caching is off, and the page isn't marked as
--	 * cachable. Finally, we could mark the page as clean, not dirty,
--	 * but we choose to leave that decision to the user; if the user
--	 * chooses to have a CPLB pre-defined as dirty, then they always
--	 * pay the cost of flushing during eviction, but don't pay the
--	 * cost of first-write exceptions to mark the page as dirty.
--	 */
+-}
 -
--#ifdef CONFIG_BFIN_WT
--	BITSET(R6, 14);		/* Set WT*/
--#endif
+-/****************************************************************************/
 -
--	[P1] = R2;
--	[P1-0x100] = R4;
--#ifdef	CONFIG_CPLB_INFO
--	R3 = [P3];
--	R3 += 1;
--	[P3] = R3;
+-static void sh64_dcache_purge_kernel_range(unsigned long start, unsigned long end)
+-{
+-	/* Purge the range of addresses [start,end] from the D-cache.  The
+-	   addresses lie in the superpage mapping.  There's no harm if we
+-	   overpurge at either end - just a small performance loss. */
+-	unsigned long long ullend, addr, aligned_start;
+-#if (NEFF == 32)
+-	aligned_start = (unsigned long long)(signed long long)(signed long) start;
+-#else
+-#error "NEFF != 32"
 -#endif
+-	aligned_start &= L1_CACHE_ALIGN_MASK;
+-	addr = aligned_start;
+-#if (NEFF == 32)
+-	ullend = (unsigned long long) (signed long long) (signed long) end;
+-#else
+-#error "NEFF != 32"
+-#endif
+-	while (addr <= ullend) {
+-		asm __volatile__ ("ocbp %0, 0" : : "r" (addr));
+-		addr += L1_CACHE_BYTES;
+-	}
+-	return;
+-}
 -
--	/* We've installed the CPLB, so re-enable CPLBs. P4
--	 * points to DMEM_CONTROL, and R5 is the value we
--	 * last wrote to it, when we were disabling CPLBs.
--	 */
+-/* Assumes this address (+ (2**n_synbits) pages up from it) aren't used for
+-   anything else in the kernel */
+-#define MAGIC_PAGE0_START 0xffffffffec000000ULL
 -
--	BITSET(R5,ENDCPLB_P);
--	CLI R2;
--	.align 8;
--	[P4] = R5;
--	SSYNC;
--	STI R2;
+-static void sh64_dcache_purge_coloured_phy_page(unsigned long paddr, unsigned long eaddr)
+-{
+-	/* Purge the physical page 'paddr' from the cache.  It's known that any
+-	   cache lines requiring attention have the same page colour as the the
+-	   address 'eaddr'.
 -
--	( R7:4,P5:3 ) = [SP++];
--	R0 = CPLB_RELOADED;
--	RTS;
--ENDPROC(_cplb_mgr)
+-	   This relies on the fact that the D-cache matches on physical tags
+-	   when no virtual tag matches.  So we create an alias for the original
+-	   page and purge through that.  (Alternatively, we could have done
+-	   this by switching ASID to match the original mapping and purged
+-	   through that, but that involves ASID switching cost + probably a
+-	   TLBMISS + refill anyway.)
+-	   */
 -
--.data
--.align 4;
--_page_size_table:
--.byte4	0x00000400;	/* 1K */
--.byte4	0x00001000;	/* 4K */
--.byte4	0x00100000;	/* 1M */
--.byte4	0x00400000;	/* 4M */
+-	unsigned long long magic_page_start;
+-	unsigned long long magic_eaddr, magic_eaddr_end;
 -
--.align 4;
--_dcplb_preference:
--.byte4	0x00000001;	/* valid bit */
--.byte4	0x00000002;	/* lock bit */
-diff --git a/arch/blackfin/mach-common/dpmc.S b/arch/blackfin/mach-common/dpmc.S
-index 39fbc28..b82c096 100644
---- a/arch/blackfin/mach-common/dpmc.S
-+++ b/arch/blackfin/mach-common/dpmc.S
-@@ -38,6 +38,9 @@ ENTRY(_unmask_wdog_wakeup_evt)
- #if defined(CONFIG_BF561)
- 	P0.H = hi(SICA_IWR1);
- 	P0.L = lo(SICA_IWR1);
-+#elif defined(CONFIG_BF54x) || defined(CONFIG_BF52x)
-+	P0.h = HI(SIC_IWR0);
-+	P0.l = LO(SIC_IWR0);
- #else
- 	P0.h = HI(SIC_IWR);
- 	P0.l = LO(SIC_IWR);
-@@ -172,7 +175,7 @@ ENTRY(_sleep_mode)
- 	call _set_sic_iwr;
- 
- 	R0 = 0xFFFF (Z);
--	call _set_rtc_istat
-+	call _set_rtc_istat;
- 
- 	P0.H = hi(PLL_CTL);
- 	P0.L = lo(PLL_CTL);
-@@ -210,7 +213,7 @@ ENTRY(_hibernate_mode)
- 	call _set_sic_iwr;
- 
- 	R0 = 0xFFFF (Z);
--	call _set_rtc_istat
-+	call _set_rtc_istat;
- 
- 	P0.H = hi(VR_CTL);
- 	P0.L = lo(VR_CTL);
-@@ -236,7 +239,7 @@ ENTRY(_deep_sleep)
- 
- 	call _set_sic_iwr;
- 
--	call _set_sdram_srfs;
-+	call _set_dram_srfs;
- 
- 	/* Clear all the interrupts,bits sticky */
- 	R0 = 0xFFFF (Z);
-@@ -253,7 +256,7 @@ ENTRY(_deep_sleep)
- 	SSYNC;
- 	IDLE;
- 
--	call _unset_sdram_srfs;
-+	call _unset_dram_srfs;
- 
- 	call _test_pll_locked;
- 
-@@ -285,23 +288,22 @@ ENTRY(_sleep_deeper)
- 	P3 = R0;
- 	R0 = IWR_ENABLE(0);
- 	call _set_sic_iwr;
--	call _set_sdram_srfs;
-+	call _set_dram_srfs;	/* Set SDRAM Self Refresh */
- 
- 	/* Clear all the interrupts,bits sticky */
- 	R0 = 0xFFFF (Z);
--	call _set_rtc_istat
+-	magic_page_start = MAGIC_PAGE0_START + (eaddr & CACHE_OC_SYN_MASK);
 -
-+	call _set_rtc_istat;
- 	P0.H = hi(PLL_DIV);
- 	P0.L = lo(PLL_DIV);
- 	R6 = W[P0](z);
- 	R0.L = 0xF;
--	W[P0] = R0.l;
-+	W[P0] = R0.l;		/* Set Max VCO to SCLK divider */
- 
- 	P0.H = hi(PLL_CTL);
- 	P0.L = lo(PLL_CTL);
- 	R5 = W[P0](z);
- 	R0.L = (CONFIG_MIN_VCO_HZ/CONFIG_CLKIN_HZ) << 9;
--	W[P0] = R0.l;
-+	W[P0] = R0.l;		/* Set Min CLKIN to VCO multiplier */
- 
- 	SSYNC;
- 	IDLE;
-@@ -317,29 +319,28 @@ ENTRY(_sleep_deeper)
- 	R1 = R1|R2;
- 
- 	R2 = DEPOSIT(R7, R1);
--	W[P0] = R2;
-+	W[P0] = R2;		/* Set Min Core Voltage */
- 
- 	SSYNC;
- 	IDLE;
- 
- 	call _test_pll_locked;
- 
-+	R0 = P3;
-+	call _set_sic_iwr;	/* Set Awake from IDLE */
-+
- 	P0.H = hi(PLL_CTL);
- 	P0.L = lo(PLL_CTL);
- 	R0 = W[P0](z);
- 	BITSET (R0, 3);
--	W[P0] = R0.L;
+-	/* As long as the kernel is not pre-emptible, this doesn't need to be
+-	   under cli/sti. */
 -
--	R0 = P3;
--	call _set_sic_iwr;
+-	sh64_setup_dtlb_cache_slot(magic_page_start, get_asid(), paddr);
 -
-+	W[P0] = R0.L;		/* Turn CCLK OFF */
- 	SSYNC;
- 	IDLE;
- 
- 	call _test_pll_locked;
- 
- 	R0 = IWR_ENABLE(0);
--	call _set_sic_iwr;
-+	call _set_sic_iwr;	/* Set Awake from IDLE PLL */
- 
- 	P0.H = hi(VR_CTL);
- 	P0.L = lo(VR_CTL);
-@@ -352,15 +353,15 @@ ENTRY(_sleep_deeper)
- 
- 	P0.H = hi(PLL_DIV);
- 	P0.L = lo(PLL_DIV);
--	W[P0]= R6;
-+	W[P0]= R6;		/* Restore CCLK and SCLK divider */
- 
- 	P0.H = hi(PLL_CTL);
- 	P0.L = lo(PLL_CTL);
--	w[p0] = R5;
-+	w[p0] = R5;		/* Restore VCO multiplier */
- 	IDLE;
- 	call _test_pll_locked;
- 
--	call _unset_sdram_srfs;
-+	call _unset_dram_srfs;	/* SDRAM Self Refresh Off */
- 
- 	STI R4;
- 
-@@ -368,25 +369,47 @@ ENTRY(_sleep_deeper)
- 	( R7:0, P5:0 ) = [SP++];
- 	RTS;
- 
--ENTRY(_set_sdram_srfs)
--	/*  set the sdram to self refresh mode */
-+ENTRY(_set_dram_srfs)
-+	/*  set the dram to self refresh mode */
-+#if defined(CONFIG_BF54x)
-+	P0.H = hi(EBIU_RSTCTL);
-+	P0.L = lo(EBIU_RSTCTL);
-+	R2 = [P0];
-+	R3.H = hi(SRREQ);
-+	R3.L = lo(SRREQ);
-+#else
- 	P0.H = hi(EBIU_SDGCTL);
- 	P0.L = lo(EBIU_SDGCTL);
- 	R2 = [P0];
- 	R3.H = hi(SRFS);
- 	R3.L = lo(SRFS);
-+#endif
- 	R2 = R2|R3;
- 	[P0] = R2;
- 	ssync;
-+#if defined(CONFIG_BF54x)
-+.LSRR_MODE:
-+	R2 = [P0];
-+	CC = BITTST(R2, 4);
-+	if !CC JUMP .LSRR_MODE;
-+#endif
- 	RTS;
- 
--ENTRY(_unset_sdram_srfs)
--	/*  set the sdram out of self refresh mode */
-+ENTRY(_unset_dram_srfs)
-+	/*  set the dram out of self refresh mode */
-+#if defined(CONFIG_BF54x)
-+	P0.H = hi(EBIU_RSTCTL);
-+	P0.L = lo(EBIU_RSTCTL);
-+	R2 = [P0];
-+	R3.H = hi(SRREQ);
-+	R3.L = lo(SRREQ);
-+#else
- 	P0.H = hi(EBIU_SDGCTL);
- 	P0.L = lo(EBIU_SDGCTL);
- 	R2 = [P0];
- 	R3.H = hi(SRFS);
- 	R3.L = lo(SRFS);
-+#endif
- 	R3 = ~R3;
- 	R2 = R2&R3;
- 	[P0] = R2;
-@@ -394,8 +417,13 @@ ENTRY(_unset_sdram_srfs)
- 	RTS;
- 
- ENTRY(_set_sic_iwr)
-+#if defined(CONFIG_BF54x) || defined(CONFIG_BF52x)
-+	P0.H = hi(SIC_IWR0);
-+	P0.L = lo(SIC_IWR0);
-+#else
- 	P0.H = hi(SIC_IWR);
- 	P0.L = lo(SIC_IWR);
-+#endif
- 	[P0] = R0;
- 	SSYNC;
- 	RTS;
-diff --git a/arch/blackfin/mach-common/entry.S b/arch/blackfin/mach-common/entry.S
-index dc9d3ee..56ff51b 100644
---- a/arch/blackfin/mach-common/entry.S
-+++ b/arch/blackfin/mach-common/entry.S
-@@ -95,6 +95,9 @@ ENTRY(_ex_workaround_261)
- 	R6 = 0x26;	/* Data CPLB Miss */
- 	cc = R6 == R7;
- 	if cc jump _ex_dcplb_miss (BP);
-+	R6 = 0x23;	/* Data CPLB Miss */
-+	cc = R6 == R7;
-+	if cc jump _ex_dcplb_viol (BP);
- 	/* Handle 0x23 Data CPLB Protection Violation
- 	 * and Data CPLB Multiple Hits - Linux Trap Zero
- 	 */
-@@ -102,17 +105,33 @@ ENTRY(_ex_workaround_261)
- ENDPROC(_ex_workaround_261)
- 
- #else
-+#ifdef CONFIG_MPU
-+#define _ex_dviol _ex_dcplb_viol
-+#else
- #define _ex_dviol _ex_trap_c
-+#endif
- #define _ex_dmiss _ex_dcplb_miss
- #define _ex_dmult _ex_trap_c
- #endif
- 
-+
-+ENTRY(_ex_dcplb_viol)
- ENTRY(_ex_dcplb_miss)
- ENTRY(_ex_icplb_miss)
- 	(R7:6,P5:4) = [sp++];
- 	ASTAT = [sp++];
- 	SAVE_ALL_SYS
-+#ifdef CONFIG_MPU
-+	R0 = SEQSTAT;
-+	R1 = SP;
-+	sp += -12;
-+	call _cplb_hdr;
-+	sp += 12;
-+	CC = R0 == 0;
-+	IF !CC JUMP _handle_bad_cplb;
-+#else
- 	call __cplb_hdr;
-+#endif
- 	DEBUG_START_HWTRACE(p5, r7)
- 	RESTORE_ALL_SYS
- 	SP = EX_SCRATCH_REG;
-@@ -329,7 +348,7 @@ ENTRY(_exception_to_level5)
- 	R7 = R7 + R6;
- 	P5 = R7;
- 	R1 = [P5];
--	[SP + 8] = r1;
-+	[SP + PT_SEQSTAT] = r1;
- 
- 	r0 = sp; 	/* stack frame pt_regs pointer argument ==> r0 */
- 	SP += -12;
-@@ -633,9 +652,7 @@ ENTRY(_ret_from_exception)
- 	[sp + PT_IPEND] = r0;
- 
- 1:
--	r1 = 0x37(Z);
--	r2 = ~r1;
--	r2.h = 0;
-+	r2 = LO(~0x37) (Z);
- 	r0 = r2 & r0;
- 	cc = r0 == 0;
- 	if !cc jump 4f;	/* if not return to user mode, get out */
-@@ -1364,6 +1381,7 @@ ENTRY(_sys_call_table)
- 	.long _sys_set_robust_list
- 	.long _sys_get_robust_list	/* 355 */
- 	.long _sys_fallocate
-+	.long _sys_semtimedop
- 	.rept NR_syscalls-(.-_sys_call_table)/4
- 	.long _sys_ni_syscall
- 	.endr
-diff --git a/arch/blackfin/mach-common/interrupt.S b/arch/blackfin/mach-common/interrupt.S
-index 4de3764..7f752c8 100644
---- a/arch/blackfin/mach-common/interrupt.S
-+++ b/arch/blackfin/mach-common/interrupt.S
-@@ -34,9 +34,13 @@
- #include <asm/entry.h>
- #include <asm/asm-offsets.h>
- #include <asm/trace.h>
-+#include <asm/traps.h>
-+#include <asm/thread_info.h>
- 
- #include <asm/mach-common/context.S>
- 
-+.extern _ret_from_exception
-+
- #ifdef CONFIG_I_ENTRY_L1
- .section .l1.text
- #else
-@@ -117,8 +121,8 @@ __common_int_entry:
- 
- #if ANOMALY_05000283 || ANOMALY_05000315
- 	cc = r7 == r7;
--	p5.h = 0xffc0;
--	p5.l = 0x0014;
-+	p5.h = HI(CHIPID);
-+	p5.l = LO(CHIPID);
- 	if cc jump 1f;
- 	r7.l = W[p5];
- 1:
-@@ -134,26 +138,22 @@ __common_int_entry:
- 
- /* interrupt routine for ivhw - 5 */
- ENTRY(_evt_ivhw)
--	SAVE_CONTEXT
-+	SAVE_ALL_SYS
- #ifdef CONFIG_FRAME_POINTER
- 	fp = 0;
- #endif
-+
- #if ANOMALY_05000283
- 	cc = r7 == r7;
--	p5.h = 0xffc0;
--	p5.l = 0x0014;
-+	p5.h = HI(CHIPID);
-+	p5.l = LO(CHIPID);
- 	if cc jump 1f;
- 	r7.l = W[p5];
- 1:
- #endif
- 
--	trace_buffer_stop(p0, r0);
+-	magic_eaddr = magic_page_start;
+-	magic_eaddr_end = magic_eaddr + PAGE_SIZE;
+-	while (magic_eaddr < magic_eaddr_end) {
+-		/* Little point in unrolling this loop - the OCBPs are blocking
+-		   and won't go any quicker (i.e. the loop overhead is parallel
+-		   to part of the OCBP execution.) */
+-		asm __volatile__ ("ocbp %0, 0" : : "r" (magic_eaddr));
+-		magic_eaddr += L1_CACHE_BYTES;
+-	}
 -
--	r0 = IRQ_HWERR;
--	r1 = sp;
+-	sh64_teardown_dtlb_cache_slot();
+-}
 -
- #ifdef CONFIG_HARDWARE_PM
--	r7 = SEQSTAT;
-+	r7 = [sp + PT_SEQSTAT];
- 	r7 = r7 >>> 0xe;
- 	r6 = 0x1F;
- 	r7 = r7 & r6;
-@@ -161,11 +161,29 @@ ENTRY(_evt_ivhw)
- 	cc = r7 == r5;
- 	if cc jump .Lcall_do_ovf; /* deal with performance counter overflow */
- #endif
+-/****************************************************************************/
 -
-+	# We are going to dump something out, so make sure we print IPEND properly
-+	p2.l = lo(IPEND);
-+	p2.h = hi(IPEND);
-+	r0 = [p2];
-+	[sp + PT_IPEND] = r0;
-+
-+	/* set the EXCAUSE to HWERR for trap_c */
-+	r0 = [sp + PT_SEQSTAT];
-+	R1.L = LO(VEC_HWERR);
-+	R1.H = HI(VEC_HWERR);
-+	R0 = R0 | R1;
-+	[sp + PT_SEQSTAT] = R0;
-+
-+	r0 = sp;        /* stack frame pt_regs pointer argument ==> r0 */
- 	SP += -12;
--	call _irq_panic;
-+	call _trap_c;
- 	SP += 12;
-+
-+	call _ret_from_exception;
-+.Lcommon_restore_all_sys:
-+	RESTORE_ALL_SYS
- 	rti;
-+
- #ifdef CONFIG_HARDWARE_PM
- .Lcall_do_ovf:
- 
-@@ -173,9 +191,11 @@ ENTRY(_evt_ivhw)
- 	call _pm_overflow;
- 	SP += 12;
- 
--	jump .Lcommon_restore_context;
-+	jump .Lcommon_restore_all_sys;
- #endif
- 
-+ENDPROC(_evt_ivhw)
-+
- /* Interrupt routine for evt2 (NMI).
-  * We don't actually use this, so just return.
-  * For inner circle type details, please see:
-diff --git a/arch/blackfin/mach-common/ints-priority-dc.c b/arch/blackfin/mach-common/ints-priority-dc.c
-index 4882f0e..8d18d6b 100644
---- a/arch/blackfin/mach-common/ints-priority-dc.c
-+++ b/arch/blackfin/mach-common/ints-priority-dc.c
-@@ -222,11 +222,12 @@ static void bf561_gpio_unmask_irq(unsigned int irq)
- static unsigned int bf561_gpio_irq_startup(unsigned int irq)
- {
- 	unsigned int ret;
-+	char buf[8];
- 	u16 gpionr = irq - IRQ_PF0;
- 
- 	if (!(gpio_enabled[gpio_bank(gpionr)] & gpio_bit(gpionr))) {
+-static void sh64_dcache_purge_phy_page(unsigned long paddr)
+-{
+-	/* Pure a page given its physical start address, by creating a
+-	   temporary 1 page mapping and purging across that.  Even if we know
+-	   the virtual address (& vma or mm) of the page, the method here is
+-	   more elegant because it avoids issues of coping with page faults on
+-	   the purge instructions (i.e. no special-case code required in the
+-	   critical path in the TLB miss handling). */
 -
--		ret = gpio_request(gpionr, "IRQ");
-+		snprintf(buf, sizeof buf, "IRQ %d", irq);
-+		ret = gpio_request(gpionr, buf);
- 		if (ret)
- 			return ret;
- 
-@@ -250,6 +251,7 @@ static int bf561_gpio_irq_type(unsigned int irq, unsigned int type)
- {
- 
- 	unsigned int ret;
-+	char buf[8];
- 	u16 gpionr = irq - IRQ_PF0;
- 
- 
-@@ -265,8 +267,8 @@ static int bf561_gpio_irq_type(unsigned int irq, unsigned int type)
- 			    IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) {
- 
- 		if (!(gpio_enabled[gpio_bank(gpionr)] & gpio_bit(gpionr))) {
+-	unsigned long long eaddr_start, eaddr, eaddr_end;
+-	int i;
 -
--			ret = gpio_request(gpionr, "IRQ");
-+			snprintf(buf, sizeof buf, "IRQ %d", irq);
-+			ret = gpio_request(gpionr, buf);
- 			if (ret)
- 				return ret;
- 
-diff --git a/arch/blackfin/mach-common/ints-priority-sc.c b/arch/blackfin/mach-common/ints-priority-sc.c
-index 147f073..dec42ac 100644
---- a/arch/blackfin/mach-common/ints-priority-sc.c
-+++ b/arch/blackfin/mach-common/ints-priority-sc.c
-@@ -313,6 +313,7 @@ static void bfin_demux_error_irq(unsigned int int_err_irq,
- static unsigned short gpio_enabled[gpio_bank(MAX_BLACKFIN_GPIOS)];
- static unsigned short gpio_edge_triggered[gpio_bank(MAX_BLACKFIN_GPIOS)];
- 
-+
- static void bfin_gpio_ack_irq(unsigned int irq)
- {
- 	u16 gpionr = irq - IRQ_PF0;
-@@ -352,9 +353,11 @@ static unsigned int bfin_gpio_irq_startup(unsigned int irq)
- {
- 	unsigned int ret;
- 	u16 gpionr = irq - IRQ_PF0;
-+	char buf[8];
- 
- 	if (!(gpio_enabled[gpio_bank(gpionr)] & gpio_bit(gpionr))) {
--		ret = gpio_request(gpionr, "IRQ");
-+		snprintf(buf, sizeof buf, "IRQ %d", irq);
-+		ret = gpio_request(gpionr, buf);
- 		if (ret)
- 			return ret;
- 	}
-@@ -376,6 +379,7 @@ static int bfin_gpio_irq_type(unsigned int irq, unsigned int type)
- {
- 
- 	unsigned int ret;
-+	char buf[8];
- 	u16 gpionr = irq - IRQ_PF0;
- 
- 	if (type == IRQ_TYPE_PROBE) {
-@@ -388,7 +392,8 @@ static int bfin_gpio_irq_type(unsigned int irq, unsigned int type)
- 	if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING |
- 		    IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) {
- 		if (!(gpio_enabled[gpio_bank(gpionr)] & gpio_bit(gpionr))) {
--			ret = gpio_request(gpionr, "IRQ");
-+			snprintf(buf, sizeof buf, "IRQ %d", irq);
-+			ret = gpio_request(gpionr, buf);
- 			if (ret)
- 				return ret;
- 		}
-@@ -478,6 +483,10 @@ static void bfin_demux_gpio_irq(unsigned int intb_irq,
- static unsigned char irq2pint_lut[NR_PINTS];
- static unsigned char pint2irq_lut[NR_PINT_SYS_IRQS * NR_PINT_BITS];
- 
-+static unsigned int gpio_both_edge_triggered[NR_PINT_SYS_IRQS];
-+static unsigned short gpio_enabled[gpio_bank(MAX_BLACKFIN_GPIOS)];
-+
-+
- struct pin_int_t {
- 	unsigned int mask_set;
- 	unsigned int mask_clear;
-@@ -544,13 +553,20 @@ void init_pint_lut(void)
- 
- }
- 
--static unsigned short gpio_enabled[gpio_bank(MAX_BLACKFIN_GPIOS)];
+-	/* As long as the kernel is not pre-emptible, this doesn't need to be
+-	   under cli/sti. */
+-
+-	eaddr_start = MAGIC_PAGE0_START;
+-	for (i=0; i < (1 << CACHE_OC_N_SYNBITS); i++) {
+-		sh64_setup_dtlb_cache_slot(eaddr_start, get_asid(), paddr);
+-
+-		eaddr = eaddr_start;
+-		eaddr_end = eaddr + PAGE_SIZE;
+-		while (eaddr < eaddr_end) {
+-			asm __volatile__ ("ocbp %0, 0" : : "r" (eaddr));
+-			eaddr += L1_CACHE_BYTES;
+-		}
+-
+-		sh64_teardown_dtlb_cache_slot();
+-		eaddr_start += PAGE_SIZE;
+-	}
+-}
+-
+-static void sh64_dcache_purge_user_pages(struct mm_struct *mm,
+-				unsigned long addr, unsigned long end)
+-{
+-	pgd_t *pgd;
+-	pmd_t *pmd;
+-	pte_t *pte;
+-	pte_t entry;
+-	spinlock_t *ptl;
+-	unsigned long paddr;
 -
- static void bfin_gpio_ack_irq(unsigned int irq)
- {
- 	u8 pint_val = irq2pint_lut[irq - SYS_IRQS];
-+	u32 pintbit = PINT_BIT(pint_val);
-+	u8 bank = PINT_2_BANK(pint_val);
-+
-+	if (unlikely(gpio_both_edge_triggered[bank] & pintbit)) {
-+		if (pint[bank]->invert_set & pintbit)
-+			pint[bank]->invert_clear = pintbit;
-+		else
-+			pint[bank]->invert_set = pintbit;
-+	}
-+	pint[bank]->request = pintbit;
- 
--	pint[PINT_2_BANK(pint_val)]->request = PINT_BIT(pint_val);
- 	SSYNC();
- }
- 
-@@ -560,6 +576,13 @@ static void bfin_gpio_mask_ack_irq(unsigned int irq)
- 	u32 pintbit = PINT_BIT(pint_val);
- 	u8 bank = PINT_2_BANK(pint_val);
- 
-+	if (unlikely(gpio_both_edge_triggered[bank] & pintbit)) {
-+		if (pint[bank]->invert_set & pintbit)
-+			pint[bank]->invert_clear = pintbit;
-+		else
-+			pint[bank]->invert_set = pintbit;
-+	}
-+
- 	pint[bank]->request = pintbit;
- 	pint[bank]->mask_clear = pintbit;
- 	SSYNC();
-@@ -587,7 +610,8 @@ static void bfin_gpio_unmask_irq(unsigned int irq)
- static unsigned int bfin_gpio_irq_startup(unsigned int irq)
- {
- 	unsigned int ret;
--	u16 gpionr = irq - IRQ_PA0;
-+	char buf[8];
-+	u16 gpionr = irq_to_gpio(irq);
- 	u8 pint_val = irq2pint_lut[irq - SYS_IRQS];
- 
- 	if (pint_val == IRQ_NOT_AVAIL) {
-@@ -598,7 +622,8 @@ static unsigned int bfin_gpio_irq_startup(unsigned int irq)
- 	}
- 
- 	if (!(gpio_enabled[gpio_bank(gpionr)] & gpio_bit(gpionr))) {
--		ret = gpio_request(gpionr, "IRQ");
-+		snprintf(buf, sizeof buf, "IRQ %d", irq);
-+		ret = gpio_request(gpionr, buf);
- 		if (ret)
- 			return ret;
- 	}
-@@ -611,16 +636,19 @@ static unsigned int bfin_gpio_irq_startup(unsigned int irq)
- 
- static void bfin_gpio_irq_shutdown(unsigned int irq)
- {
-+	u16 gpionr = irq_to_gpio(irq);
-+
- 	bfin_gpio_mask_irq(irq);
--	gpio_free(irq - IRQ_PA0);
--	gpio_enabled[gpio_bank(irq - IRQ_PA0)] &= ~gpio_bit(irq - IRQ_PA0);
-+	gpio_free(gpionr);
-+	gpio_enabled[gpio_bank(gpionr)] &= ~gpio_bit(gpionr);
- }
- 
- static int bfin_gpio_irq_type(unsigned int irq, unsigned int type)
- {
- 
- 	unsigned int ret;
--	u16 gpionr = irq - IRQ_PA0;
-+	char buf[8];
-+	u16 gpionr = irq_to_gpio(irq);
- 	u8 pint_val = irq2pint_lut[irq - SYS_IRQS];
- 	u32 pintbit = PINT_BIT(pint_val);
- 	u8 bank = PINT_2_BANK(pint_val);
-@@ -638,7 +666,8 @@ static int bfin_gpio_irq_type(unsigned int irq, unsigned int type)
- 	if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING |
- 		    IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) {
- 		if (!(gpio_enabled[gpio_bank(gpionr)] & gpio_bit(gpionr))) {
--			ret = gpio_request(gpionr, "IRQ");
-+			snprintf(buf, sizeof buf, "IRQ %d", irq);
-+			ret = gpio_request(gpionr, buf);
- 			if (ret)
- 				return ret;
- 		}
-@@ -651,28 +680,33 @@ static int bfin_gpio_irq_type(unsigned int irq, unsigned int type)
- 
- 	gpio_direction_input(gpionr);
- 
--	if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) {
--		pint[bank]->edge_set = pintbit;
+-	if (!mm)
+-		return; /* No way to find physical address of page */
+-
+-	pgd = pgd_offset(mm, addr);
+-	if (pgd_bad(*pgd))
+-		return;
+-
+-	pmd = pmd_offset(pgd, addr);
+-	if (pmd_none(*pmd) || pmd_bad(*pmd))
+-		return;
+-
+-	pte = pte_offset_map_lock(mm, pmd, addr, &ptl);
+-	do {
+-		entry = *pte;
+-		if (pte_none(entry) || !pte_present(entry))
+-			continue;
+-		paddr = pte_val(entry) & PAGE_MASK;
+-		sh64_dcache_purge_coloured_phy_page(paddr, addr);
+-	} while (pte++, addr += PAGE_SIZE, addr != end);
+-	pte_unmap_unlock(pte - 1, ptl);
+-}
+-/****************************************************************************/
+-
+-static void sh64_dcache_purge_user_range(struct mm_struct *mm,
+-			  unsigned long start, unsigned long end)
+-{
+-	/* There are at least 5 choices for the implementation of this, with
+-	   pros (+), cons(-), comments(*):
+-
+-	   1. ocbp each line in the range through the original user's ASID
+-	      + no lines spuriously evicted
+-	      - tlbmiss handling (must either handle faults on demand => extra
+-		special-case code in tlbmiss critical path), or map the page in
+-		advance (=> flush_tlb_range in advance to avoid multiple hits)
+-	      - ASID switching
+-	      - expensive for large ranges
+-
+-	   2. temporarily map each page in the range to a special effective
+-	      address and ocbp through the temporary mapping; relies on the
+-	      fact that SH-5 OCB* always do TLB lookup and match on ptags (they
+-	      never look at the etags)
+-	      + no spurious evictions
+-	      - expensive for large ranges
+-	      * surely cheaper than (1)
+-
+-	   3. walk all the lines in the cache, check the tags, if a match
+-	      occurs create a page mapping to ocbp the line through
+-	      + no spurious evictions
+-	      - tag inspection overhead
+-	      - (especially for small ranges)
+-	      - potential cost of setting up/tearing down page mapping for
+-		every line that matches the range
+-	      * cost partly independent of range size
+-
+-	   4. walk all the lines in the cache, check the tags, if a match
+-	      occurs use 4 * alloco to purge the line (+3 other probably
+-	      innocent victims) by natural eviction
+-	      + no tlb mapping overheads
+-	      - spurious evictions
+-	      - tag inspection overhead
+-
+-	   5. implement like flush_cache_all
+-	      + no tag inspection overhead
+-	      - spurious evictions
+-	      - bad for small ranges
+-
+-	   (1) can be ruled out as more expensive than (2).  (2) appears best
+-	   for small ranges.  The choice between (3), (4) and (5) for large
+-	   ranges and the range size for the large/small boundary need
+-	   benchmarking to determine.
+-
+-	   For now use approach (2) for small ranges and (5) for large ones.
+-
+-	   */
+-
+-	int n_pages;
+-
+-	n_pages = ((end - start) >> PAGE_SHIFT);
+-	if (n_pages >= 64 || ((start ^ (end - 1)) & PMD_MASK)) {
+-#if 1
+-		sh64_dcache_purge_all();
+-#else
+-		unsigned long long set, way;
+-		unsigned long mm_asid = mm->context & MMU_CONTEXT_ASID_MASK;
+-		for (set = 0; set < cpu_data->dcache.sets; set++) {
+-			unsigned long long set_base_config_addr = CACHE_OC_ADDRESS_ARRAY + (set << cpu_data->dcache.set_shift);
+-			for (way = 0; way < cpu_data->dcache.ways; way++) {
+-				unsigned long long config_addr = set_base_config_addr + (way << cpu_data->dcache.way_step_shift);
+-				unsigned long long tag0;
+-				unsigned long line_valid;
+-
+-				asm __volatile__("getcfg %1, 0, %0" : "=r" (tag0) : "r" (config_addr));
+-				line_valid = tag0 & SH_CACHE_VALID;
+-				if (line_valid) {
+-					unsigned long cache_asid;
+-					unsigned long epn;
+-
+-					cache_asid = (tag0 & cpu_data->dcache.asid_mask) >> cpu_data->dcache.asid_shift;
+-					/* The next line needs some
+-					   explanation.  The virtual tags
+-					   encode bits [31:13] of the virtual
+-					   address, bit [12] of the 'tag' being
+-					   implied by the cache set index. */
+-					epn = (tag0 & cpu_data->dcache.epn_mask) | ((set & 0x80) << cpu_data->dcache.entry_shift);
+-
+-					if ((cache_asid == mm_asid) && (start <= epn) && (epn < end)) {
+-						/* TODO : could optimise this
+-						   call by batching multiple
+-						   adjacent sets together. */
+-						sh64_dcache_purge_sets(set, 1);
+-						break; /* Don't waste time inspecting other ways for this set */
+-					}
+-				}
+-			}
+-		}
+-#endif
 -	} else {
--		pint[bank]->edge_clear = pintbit;
+-		/* Small range, covered by a single page table page */
+-		start &= PAGE_MASK;	/* should already be so */
+-		end = PAGE_ALIGN(end);	/* should already be so */
+-		sh64_dcache_purge_user_pages(mm, start, end);
 -	}
+-	return;
+-}
 -
- 	if ((type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_LEVEL_LOW)))
- 		pint[bank]->invert_set = pintbit;	/* low or falling edge denoted by one */
- 	else
--		pint[bank]->invert_set = pintbit;	/* high or rising edge denoted by zero */
-+		pint[bank]->invert_clear = pintbit;	/* high or rising edge denoted by zero */
- 
--	if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))
--		pint[bank]->invert_set = pintbit;
--	else
--		pint[bank]->invert_set = pintbit;
-+	if ((type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))
-+	    == (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) {
- 
--	SSYNC();
-+		gpio_both_edge_triggered[bank] |= pintbit;
- 
--	if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))
-+		if (gpio_get_value(gpionr))
-+			pint[bank]->invert_set = pintbit;
-+		else
-+			pint[bank]->invert_clear = pintbit;
-+	} else {
-+		gpio_both_edge_triggered[bank] &= ~pintbit;
-+	}
-+
-+	if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) {
-+		pint[bank]->edge_set = pintbit;
- 		set_irq_handler(irq, handle_edge_irq);
--	else
-+	} else {
-+		pint[bank]->edge_clear = pintbit;
- 		set_irq_handler(irq, handle_level_irq);
-+	}
-+
-+	SSYNC();
- 
- 	return 0;
- }
-diff --git a/arch/blackfin/mach-common/irqpanic.c b/arch/blackfin/mach-common/irqpanic.c
-index b22959b..606ded9 100644
---- a/arch/blackfin/mach-common/irqpanic.c
-+++ b/arch/blackfin/mach-common/irqpanic.c
-@@ -46,9 +46,6 @@ void irq_panic(int reason, struct pt_regs *regs) __attribute__ ((l1_text));
-  */
- asmlinkage void irq_panic(int reason, struct pt_regs *regs)
- {
--	int sig = 0;
--	siginfo_t info;
+-static void sh64_dcache_wback_current_user_range(unsigned long start, unsigned long end)
+-{
+-	unsigned long long aligned_start;
+-	unsigned long long ull_end;
+-	unsigned long long addr;
 -
- #ifdef CONFIG_DEBUG_ICACHE_CHECK
- 	unsigned int cmd, tag, ca, cache_hi, cache_lo, *pa;
- 	unsigned short i, j, die;
-@@ -136,53 +133,6 @@ asmlinkage void irq_panic(int reason, struct pt_regs *regs)
- 	}
- #endif
- 
--	printk(KERN_EMERG "\n");
--	printk(KERN_EMERG "Exception: IRQ 0x%x entered\n", reason);
--	printk(KERN_EMERG " code=[0x%08lx],   stack frame=0x%08lx,  "
--	    " bad PC=0x%08lx\n",
--	    (unsigned long)regs->seqstat,
--	    (unsigned long)regs,
--	    (unsigned long)regs->pc);
--	if (reason == 0x5) {
--		printk(KERN_EMERG "----------- HARDWARE ERROR -----------\n");
+-	ull_end = end;
 -
--		/* There is only need to check for Hardware Errors, since other
--		 * EXCEPTIONS are handled in TRAPS.c (MH)
--		 */
--		switch (regs->seqstat & SEQSTAT_HWERRCAUSE) {
--		case (SEQSTAT_HWERRCAUSE_SYSTEM_MMR):	/* System MMR Error */
--			info.si_code = BUS_ADRALN;
--			sig = SIGBUS;
--			printk(KERN_EMERG HWC_x2(KERN_EMERG));
--			break;
--		case (SEQSTAT_HWERRCAUSE_EXTERN_ADDR):	/* External Memory Addressing Error */
--			info.si_code = BUS_ADRERR;
--			sig = SIGBUS;
--			printk(KERN_EMERG HWC_x3(KERN_EMERG));
--			break;
--		case (SEQSTAT_HWERRCAUSE_PERF_FLOW):	/* Performance Monitor Overflow */
--			printk(KERN_EMERG HWC_x12(KERN_EMERG));
--			break;
--		case (SEQSTAT_HWERRCAUSE_RAISE_5):	/* RAISE 5 instruction */
--			printk(KERN_EMERG HWC_x18(KERN_EMERG));
--			break;
--		default:	/* Reserved */
--			printk(KERN_EMERG HWC_default(KERN_EMERG));
--			break;
--		}
+-	/* Just wback over the range using the natural addresses.  TLB miss
+-	   handling will be OK (TBC) : the range has just been written to by
+-	   the signal frame setup code, so the PTEs must exist.
+-
+-	   Note, if we have CONFIG_PREEMPT and get preempted inside this loop,
+-	   it doesn't matter, even if the pid->ASID mapping changes whilst
+-	   we're away.  In that case the cache will have been flushed when the
+-	   mapping was renewed.  So the writebacks below will be nugatory (and
+-	   we'll doubtless have to fault the TLB entry/ies in again with the
+-	   new ASID), but it's a rare case.
+-	   */
+-	aligned_start = start & L1_CACHE_ALIGN_MASK;
+-	addr = aligned_start;
+-	while (addr < ull_end) {
+-		asm __volatile__ ("ocbwb %0, 0" : : "r" (addr));
+-		addr += L1_CACHE_BYTES;
 -	}
+-}
 -
--	regs->ipend = bfin_read_IPEND();
--	dump_bfin_process(regs);
--	dump_bfin_mem((void *)regs->pc);
--	show_regs(regs);
--	if (0 == (info.si_signo = sig) || 0 == user_mode(regs))	/* in kernelspace */
--		panic("Unhandled IRQ or exceptions!\n");
--	else {			/* in userspace */
--		info.si_errno = 0;
--		info.si_addr = (void *)regs->pc;
--		force_sig_info(sig, &info, current);
+-/****************************************************************************/
+-
+-/* These *MUST* lie in an area of virtual address space that's otherwise unused. */
+-#define UNIQUE_EADDR_START 0xe0000000UL
+-#define UNIQUE_EADDR_END   0xe8000000UL
+-
+-static unsigned long sh64_make_unique_eaddr(unsigned long user_eaddr, unsigned long paddr)
+-{
+-	/* Given a physical address paddr, and a user virtual address
+-	   user_eaddr which will eventually be mapped to it, create a one-off
+-	   kernel-private eaddr mapped to the same paddr.  This is used for
+-	   creating special destination pages for copy_user_page and
+-	   clear_user_page */
+-
+-	static unsigned long current_pointer = UNIQUE_EADDR_START;
+-	unsigned long coloured_pointer;
+-
+-	if (current_pointer == UNIQUE_EADDR_END) {
+-		sh64_dcache_purge_all();
+-		current_pointer = UNIQUE_EADDR_START;
 -	}
- }
- 
- #ifdef CONFIG_HARDWARE_PM
-diff --git a/arch/blackfin/mach-common/pm.c b/arch/blackfin/mach-common/pm.c
-index dac51fb..81930f7 100644
---- a/arch/blackfin/mach-common/pm.c
-+++ b/arch/blackfin/mach-common/pm.c
-@@ -77,7 +77,15 @@ void bfin_pm_suspend_standby_enter(void)
- 
- 		gpio_pm_restore();
- 
-+#if defined(CONFIG_BF54x) || defined(CONFIG_BF52x)
-+		bfin_write_SIC_IWR0(IWR_ENABLE_ALL);
-+		bfin_write_SIC_IWR1(IWR_ENABLE_ALL);
-+# ifdef CONFIG_BF54x
-+		bfin_write_SIC_IWR2(IWR_ENABLE_ALL);
-+# endif
-+#else
- 		bfin_write_SIC_IWR(IWR_ENABLE_ALL);
-+#endif
- 
- 		local_irq_restore(flags);
- 	}
-@@ -85,7 +93,15 @@ void bfin_pm_suspend_standby_enter(void)
- 
- #if defined(CONFIG_PM_WAKEUP_GPIO_BY_SIC_IWR)
- 	sleep_deeper(CONFIG_PM_WAKEUP_SIC_IWR);
-+# if defined(CONFIG_BF54x) || defined(CONFIG_BF52x)
-+	bfin_write_SIC_IWR0(IWR_ENABLE_ALL);
-+	bfin_write_SIC_IWR1(IWR_ENABLE_ALL);
-+#  ifdef CONFIG_BF54x
-+	bfin_write_SIC_IWR2(IWR_ENABLE_ALL);
-+#  endif
-+# else
- 	bfin_write_SIC_IWR(IWR_ENABLE_ALL);
-+# endif
- #endif				/* CONFIG_PM_WAKEUP_GPIO_BY_SIC_IWR */
- }
- 
-diff --git a/arch/blackfin/mm/init.c b/arch/blackfin/mm/init.c
-index e97ea8f..eb1a12a 100644
---- a/arch/blackfin/mm/init.c
-+++ b/arch/blackfin/mm/init.c
-@@ -128,8 +128,8 @@ void __init paging_init(void)
- void __init mem_init(void)
- {
- 	unsigned int codek = 0, datak = 0, initk = 0;
-+	unsigned int reservedpages = 0, freepages = 0;
- 	unsigned long tmp;
--	unsigned int len = _ramend - _rambase;
- 	unsigned long start_mem = memory_start;
- 	unsigned long end_mem = memory_end;
- 
-@@ -138,19 +138,36 @@ void __init mem_init(void)
- 
- 	start_mem = PAGE_ALIGN(start_mem);
- 	max_mapnr = num_physpages = MAP_NR(high_memory);
--	printk(KERN_INFO "Physical pages: %lx\n", num_physpages);
-+	printk(KERN_INFO "Kernel managed physical pages: %lu\n",
-+		num_physpages);
- 
- 	/* This will put all memory onto the freelists. */
- 	totalram_pages = free_all_bootmem();
- 
-+	reservedpages = 0;
-+	for (tmp = 0; tmp < max_mapnr; tmp++)
-+		if (PageReserved(pfn_to_page(tmp)))
-+			reservedpages++;
-+	freepages =  max_mapnr - reservedpages;
-+
-+	/* do not count in kernel image between _rambase and _ramstart */
-+	reservedpages -= (_ramstart - _rambase) >> PAGE_SHIFT;
-+#if (defined(CONFIG_BFIN_ICACHE) && ANOMALY_05000263)
-+	reservedpages += (_ramend - memory_end - DMA_UNCACHED_REGION) >>
-+				PAGE_SHIFT;
-+#endif
-+
- 	codek = (_etext - _stext) >> 10;
--	datak = (__bss_stop - __bss_start) >> 10;
- 	initk = (__init_end - __init_begin) >> 10;
-+	datak = ((_ramstart - _rambase) >> 10) - codek - initk;
- 
--	tmp = nr_free_pages() << PAGE_SHIFT;
- 	printk(KERN_INFO
--	     "Memory available: %luk/%uk RAM, (%uk init code, %uk kernel code, %uk data, %uk dma)\n",
--	     tmp >> 10, len >> 10, initk, codek, datak, DMA_UNCACHED_REGION >> 10);
-+	     "Memory available: %luk/%luk RAM, "
-+		"(%uk init code, %uk kernel code, "
-+		"%uk data, %uk dma, %uk reserved)\n",
-+		(unsigned long) freepages << (PAGE_SHIFT-10), _ramend >> 10,
-+		initk, codek, datak, DMA_UNCACHED_REGION >> 10,
-+		(reservedpages << (PAGE_SHIFT-10)));
- 
- 	/* Initialize the blackfin L1 Memory. */
- 	l1sram_init();
-@@ -184,13 +201,15 @@ static __init void free_init_pages(const char *what, unsigned long begin, unsign
- #ifdef CONFIG_BLK_DEV_INITRD
- void __init free_initrd_mem(unsigned long start, unsigned long end)
- {
-+#ifndef CONFIG_MPU
- 	free_init_pages("initrd memory", start, end);
-+#endif
- }
- #endif
- 
- void __init free_initmem(void)
- {
--#ifdef CONFIG_RAMKERNEL
-+#if defined CONFIG_RAMKERNEL && !defined CONFIG_MPU
- 	free_init_pages("unused kernel memory",
- 			(unsigned long)(&__init_begin),
- 			(unsigned long)(&__init_end));
-diff --git a/arch/cris/arch-v32/drivers/iop_fw_load.c b/arch/cris/arch-v32/drivers/iop_fw_load.c
-index 11f9895..f4bdc1d 100644
---- a/arch/cris/arch-v32/drivers/iop_fw_load.c
-+++ b/arch/cris/arch-v32/drivers/iop_fw_load.c
-@@ -20,6 +20,9 @@
- 
- #define IOP_TIMEOUT 100
- 
-+#error "This driver is broken with regard to its driver core usage."
-+#error "Please contact <greg at kroah.com> for details on how to fix it properly."
-+
- static struct device iop_spu_device[2] = {
- 	{ .bus_id =     "iop-spu0", },
- 	{ .bus_id =     "iop-spu1", },
-@@ -192,6 +195,13 @@ int iop_start_mpu(unsigned int start_addr)
- 
- static int __init iop_fw_load_init(void)
- {
-+#if 0
-+	/*
-+	 * static struct devices can not be added directly to sysfs by ignoring
-+	 * the driver model infrastructure.  To fix this properly, please use
-+	 * the platform_bus to register these devices to be able to properly
-+	 * use the firmware infrastructure.
-+	 */
- 	device_initialize(&iop_spu_device[0]);
- 	kobject_set_name(&iop_spu_device[0].kobj, "iop-spu0");
- 	kobject_add(&iop_spu_device[0].kobj);
-@@ -201,6 +211,7 @@ static int __init iop_fw_load_init(void)
- 	device_initialize(&iop_mpu_device);
- 	kobject_set_name(&iop_mpu_device.kobj, "iop-mpu");
- 	kobject_add(&iop_mpu_device.kobj);
-+#endif
- 	return 0;
- }
- 
-diff --git a/arch/ia64/kernel/setup.c b/arch/ia64/kernel/setup.c
-index 4ac2b1f..86028c6 100644
---- a/arch/ia64/kernel/setup.c
-+++ b/arch/ia64/kernel/setup.c
-@@ -71,8 +71,6 @@ unsigned long __per_cpu_offset[NR_CPUS];
- EXPORT_SYMBOL(__per_cpu_offset);
- #endif
- 
--extern void ia64_setup_printk_clock(void);
 -
- DEFINE_PER_CPU(struct cpuinfo_ia64, cpu_info);
- DEFINE_PER_CPU(unsigned long, local_per_cpu_offset);
- unsigned long ia64_cycles_per_usec;
-@@ -507,8 +505,6 @@ setup_arch (char **cmdline_p)
- 	/* process SAL system table: */
- 	ia64_sal_init(__va(efi.sal_systab));
- 
--	ia64_setup_printk_clock();
+-	coloured_pointer = (current_pointer & ~CACHE_OC_SYN_MASK) | (user_eaddr & CACHE_OC_SYN_MASK);
+-	sh64_setup_dtlb_cache_slot(coloured_pointer, get_asid(), paddr);
 -
- #ifdef CONFIG_SMP
- 	cpu_physical_id(0) = hard_smp_processor_id();
- #endif
-diff --git a/arch/ia64/kernel/time.c b/arch/ia64/kernel/time.c
-index 2bb8421..3ab0427 100644
---- a/arch/ia64/kernel/time.c
-+++ b/arch/ia64/kernel/time.c
-@@ -344,33 +344,6 @@ udelay (unsigned long usecs)
- }
- EXPORT_SYMBOL(udelay);
- 
--static unsigned long long ia64_itc_printk_clock(void)
+-	current_pointer += (PAGE_SIZE << CACHE_OC_N_SYNBITS);
+-
+-	return coloured_pointer;
+-}
+-
+-/****************************************************************************/
+-
+-static void sh64_copy_user_page_coloured(void *to, void *from, unsigned long address)
 -{
--	if (ia64_get_kr(IA64_KR_PER_CPU_DATA))
--		return sched_clock();
--	return 0;
+-	void *coloured_to;
+-
+-	/* Discard any existing cache entries of the wrong colour.  These are
+-	   present quite often, if the kernel has recently used the page
+-	   internally, then given it up, then it's been allocated to the user.
+-	   */
+-	sh64_dcache_purge_coloured_phy_page(__pa(to), (unsigned long) to);
+-
+-	coloured_to = (void *) sh64_make_unique_eaddr(address, __pa(to));
+-	sh64_page_copy(from, coloured_to);
+-
+-	sh64_teardown_dtlb_cache_slot();
 -}
 -
--static unsigned long long ia64_default_printk_clock(void)
+-static void sh64_clear_user_page_coloured(void *to, unsigned long address)
 -{
--	return (unsigned long long)(jiffies_64 - INITIAL_JIFFIES) *
--		(1000000000/HZ);
+-	void *coloured_to;
+-
+-	/* Discard any existing kernel-originated lines of the wrong colour (as
+-	   above) */
+-	sh64_dcache_purge_coloured_phy_page(__pa(to), (unsigned long) to);
+-
+-	coloured_to = (void *) sh64_make_unique_eaddr(address, __pa(to));
+-	sh64_page_clear(coloured_to);
+-
+-	sh64_teardown_dtlb_cache_slot();
 -}
 -
--unsigned long long (*ia64_printk_clock)(void) = &ia64_default_printk_clock;
+-#endif /* !CONFIG_DCACHE_DISABLED */
 -
--unsigned long long printk_clock(void)
+-/****************************************************************************/
+-
+-/*##########################################################################
+-			    EXTERNALLY CALLABLE API.
+-  ##########################################################################*/
+-
+-/* These functions are described in Documentation/cachetlb.txt.
+-   Each one of these functions varies in behaviour depending on whether the
+-   I-cache and/or D-cache are configured out.
+-
+-   Note that the Linux term 'flush' corresponds to what is termed 'purge' in
+-   the sh/sh64 jargon for the D-cache, i.e. write back dirty data then
+-   invalidate the cache lines, and 'invalidate' for the I-cache.
+-   */
+-
+-#undef FLUSH_TRACE
+-
+-void flush_cache_all(void)
 -{
--	return ia64_printk_clock();
+-	/* Invalidate the entire contents of both caches, after writing back to
+-	   memory any dirty data from the D-cache. */
+-	sh64_dcache_purge_all();
+-	sh64_icache_inv_all();
 -}
 -
--void __init
--ia64_setup_printk_clock(void)
+-/****************************************************************************/
+-
+-void flush_cache_mm(struct mm_struct *mm)
 -{
--	if (!(sal_platform_features & IA64_SAL_PLATFORM_FEATURE_ITC_DRIFT))
--		ia64_printk_clock = ia64_itc_printk_clock;
+-	/* Invalidate an entire user-address space from both caches, after
+-	   writing back dirty data (e.g. for shared mmap etc). */
+-
+-	/* This could be coded selectively by inspecting all the tags then
+-	   doing 4*alloco on any set containing a match (as for
+-	   flush_cache_range), but fork/exit/execve (where this is called from)
+-	   are expensive anyway. */
+-
+-	/* Have to do a purge here, despite the comments re I-cache below.
+-	   There could be odd-coloured dirty data associated with the mm still
+-	   in the cache - if this gets written out through natural eviction
+-	   after the kernel has reused the page there will be chaos.
+-	   */
+-
+-	sh64_dcache_purge_all();
+-
+-	/* The mm being torn down won't ever be active again, so any Icache
+-	   lines tagged with its ASID won't be visible for the rest of the
+-	   lifetime of this ASID cycle.  Before the ASID gets reused, there
+-	   will be a flush_cache_all.  Hence we don't need to touch the
+-	   I-cache.  This is similar to the lack of action needed in
+-	   flush_tlb_mm - see fault.c. */
 -}
 -
- /* IA64 doesn't cache the timezone */
- void update_vsyscall_tz(void)
- {
-diff --git a/arch/ia64/kernel/topology.c b/arch/ia64/kernel/topology.c
-index 14261fe..a2484fc 100644
---- a/arch/ia64/kernel/topology.c
-+++ b/arch/ia64/kernel/topology.c
-@@ -354,27 +354,27 @@ static int __cpuinit cache_add_dev(struct sys_device * sys_dev)
- 	if (unlikely(retval < 0))
- 		return retval;
- 
--	all_cpu_cache_info[cpu].kobj.parent = &sys_dev->kobj;
--	kobject_set_name(&all_cpu_cache_info[cpu].kobj, "%s", "cache");
--	all_cpu_cache_info[cpu].kobj.ktype = &cache_ktype_percpu_entry;
--	retval = kobject_register(&all_cpu_cache_info[cpu].kobj);
-+	retval = kobject_init_and_add(&all_cpu_cache_info[cpu].kobj,
-+				      &cache_ktype_percpu_entry, &sys_dev->kobj,
-+				      "%s", "cache");
- 
- 	for (i = 0; i < all_cpu_cache_info[cpu].num_cache_leaves; i++) {
- 		this_object = LEAF_KOBJECT_PTR(cpu,i);
--		this_object->kobj.parent = &all_cpu_cache_info[cpu].kobj;
--		kobject_set_name(&(this_object->kobj), "index%1lu", i);
--		this_object->kobj.ktype = &cache_ktype;
--		retval = kobject_register(&(this_object->kobj));
-+		retval = kobject_init_and_add(&(this_object->kobj),
-+					      &cache_ktype,
-+					      &all_cpu_cache_info[cpu].kobj,
-+					      "index%1lu", i);
- 		if (unlikely(retval)) {
- 			for (j = 0; j < i; j++) {
--				kobject_unregister(
--					&(LEAF_KOBJECT_PTR(cpu,j)->kobj));
-+				kobject_put(&(LEAF_KOBJECT_PTR(cpu,j)->kobj));
- 			}
--			kobject_unregister(&all_cpu_cache_info[cpu].kobj);
-+			kobject_put(&all_cpu_cache_info[cpu].kobj);
- 			cpu_cache_sysfs_exit(cpu);
- 			break;
- 		}
-+		kobject_uevent(&(this_object->kobj), KOBJ_ADD);
- 	}
-+	kobject_uevent(&all_cpu_cache_info[cpu].kobj, KOBJ_ADD);
- 	return retval;
- }
- 
-@@ -385,10 +385,10 @@ static int __cpuinit cache_remove_dev(struct sys_device * sys_dev)
- 	unsigned long i;
- 
- 	for (i = 0; i < all_cpu_cache_info[cpu].num_cache_leaves; i++)
--		kobject_unregister(&(LEAF_KOBJECT_PTR(cpu,i)->kobj));
-+		kobject_put(&(LEAF_KOBJECT_PTR(cpu,i)->kobj));
- 
- 	if (all_cpu_cache_info[cpu].kobj.parent) {
--		kobject_unregister(&all_cpu_cache_info[cpu].kobj);
-+		kobject_put(&all_cpu_cache_info[cpu].kobj);
- 		memset(&all_cpu_cache_info[cpu].kobj,
- 			0,
- 			sizeof(struct kobject));
-diff --git a/arch/ia64/sn/kernel/setup.c b/arch/ia64/sn/kernel/setup.c
-index 1f38a3a..bb1d249 100644
---- a/arch/ia64/sn/kernel/setup.c
-+++ b/arch/ia64/sn/kernel/setup.c
-@@ -64,7 +64,6 @@ extern void sn_timer_init(void);
- extern unsigned long last_time_offset;
- extern void (*ia64_mark_idle) (int);
- extern void snidle(int);
--extern unsigned long long (*ia64_printk_clock)(void);
- 
- unsigned long sn_rtc_cycles_per_second;
- EXPORT_SYMBOL(sn_rtc_cycles_per_second);
-@@ -360,14 +359,6 @@ sn_scan_pcdp(void)
- 
- static unsigned long sn2_rtc_initial;
- 
--static unsigned long long ia64_sn2_printk_clock(void)
+-/****************************************************************************/
+-
+-void flush_cache_range(struct vm_area_struct *vma, unsigned long start,
+-		       unsigned long end)
 -{
--	unsigned long rtc_now = rtc_time();
+-	struct mm_struct *mm = vma->vm_mm;
 -
--	return (rtc_now - sn2_rtc_initial) *
--		(1000000000 / sn_rtc_cycles_per_second);
+-	/* Invalidate (from both caches) the range [start,end) of virtual
+-	   addresses from the user address space specified by mm, after writing
+-	   back any dirty data.
+-
+-	   Note, 'end' is 1 byte beyond the end of the range to flush. */
+-
+-	sh64_dcache_purge_user_range(mm, start, end);
+-	sh64_icache_inv_user_page_range(mm, start, end);
 -}
 -
- /**
-  * sn_setup - SN platform setup routine
-  * @cmdline_p: kernel command line
-@@ -468,8 +459,6 @@ void __init sn_setup(char **cmdline_p)
- 
- 	platform_intr_list[ACPI_INTERRUPT_CPEI] = IA64_CPE_VECTOR;
- 
--	ia64_printk_clock = ia64_sn2_printk_clock;
+-/****************************************************************************/
 -
- 	printk("SGI SAL version %x.%02x\n", version >> 8, version & 0x00FF);
- 
- 	/*
-diff --git a/arch/mips/au1000/common/platform.c b/arch/mips/au1000/common/platform.c
-index d51e18f..841904c 100644
---- a/arch/mips/au1000/common/platform.c
-+++ b/arch/mips/au1000/common/platform.c
-@@ -270,6 +270,24 @@ static struct platform_device smc91x_device = {
- 
- #endif
- 
-+/* All Alchemy demoboards with I2C have this #define in their headers */
-+#ifdef SMBUS_PSC_BASE
-+static struct resource pbdb_smbus_resources[] = {
-+	{
-+		.start	= SMBUS_PSC_BASE,
-+		.end	= SMBUS_PSC_BASE + 0x24 - 1,
-+		.flags	= IORESOURCE_MEM,
-+	},
-+};
-+
-+static struct platform_device pbdb_smbus_device = {
-+	.name		= "au1xpsc_smbus",
-+	.id		= 0,	/* bus number */
-+	.num_resources	= ARRAY_SIZE(pbdb_smbus_resources),
-+	.resource	= pbdb_smbus_resources,
-+};
-+#endif
-+
- static struct platform_device *au1xxx_platform_devices[] __initdata = {
- 	&au1xxx_usb_ohci_device,
- 	&au1x00_pcmcia_device,
-@@ -287,6 +305,9 @@ static struct platform_device *au1xxx_platform_devices[] __initdata = {
- #ifdef CONFIG_MIPS_DB1200
- 	&smc91x_device,
- #endif
-+#ifdef SMBUS_PSC_BASE
-+	&pbdb_smbus_device,
-+#endif
- };
- 
- int __init au1xxx_platform_init(void)
-diff --git a/arch/mips/kernel/i8259.c b/arch/mips/kernel/i8259.c
-index 4710135..197d797 100644
---- a/arch/mips/kernel/i8259.c
-+++ b/arch/mips/kernel/i8259.c
-@@ -238,7 +238,7 @@ static int i8259A_shutdown(struct sys_device *dev)
- }
- 
- static struct sysdev_class i8259_sysdev_class = {
--	set_kset_name("i8259"),
-+	.name = "i8259",
- 	.resume = i8259A_resume,
- 	.shutdown = i8259A_shutdown,
- };
-diff --git a/arch/mips/kernel/mips-mt-fpaff.c b/arch/mips/kernel/mips-mt-fpaff.c
-index 892665b..bb4f00c 100644
---- a/arch/mips/kernel/mips-mt-fpaff.c
-+++ b/arch/mips/kernel/mips-mt-fpaff.c
-@@ -58,13 +58,13 @@ asmlinkage long mipsmt_sys_sched_setaffinity(pid_t pid, unsigned int len,
- 	if (copy_from_user(&new_mask, user_mask_ptr, sizeof(new_mask)))
- 		return -EFAULT;
- 
--	lock_cpu_hotplug();
-+	get_online_cpus();
- 	read_lock(&tasklist_lock);
- 
- 	p = find_process_by_pid(pid);
- 	if (!p) {
- 		read_unlock(&tasklist_lock);
--		unlock_cpu_hotplug();
-+		put_online_cpus();
- 		return -ESRCH;
- 	}
- 
-@@ -106,7 +106,7 @@ asmlinkage long mipsmt_sys_sched_setaffinity(pid_t pid, unsigned int len,
- 
- out_unlock:
- 	put_task_struct(p);
--	unlock_cpu_hotplug();
-+	put_online_cpus();
- 	return retval;
- }
- 
-@@ -125,7 +125,7 @@ asmlinkage long mipsmt_sys_sched_getaffinity(pid_t pid, unsigned int len,
- 	if (len < real_len)
- 		return -EINVAL;
- 
--	lock_cpu_hotplug();
-+	get_online_cpus();
- 	read_lock(&tasklist_lock);
- 
- 	retval = -ESRCH;
-@@ -140,7 +140,7 @@ asmlinkage long mipsmt_sys_sched_getaffinity(pid_t pid, unsigned int len,
- 
- out_unlock:
- 	read_unlock(&tasklist_lock);
--	unlock_cpu_hotplug();
-+	put_online_cpus();
- 	if (retval)
- 		return retval;
- 	if (copy_to_user(user_mask_ptr, &mask, real_len))
-diff --git a/arch/powerpc/platforms/cell/spu_base.c b/arch/powerpc/platforms/cell/spu_base.c
-index c83c3e3..a088622 100644
---- a/arch/powerpc/platforms/cell/spu_base.c
-+++ b/arch/powerpc/platforms/cell/spu_base.c
-@@ -459,7 +459,7 @@ static int spu_shutdown(struct sys_device *sysdev)
- }
- 
- static struct sysdev_class spu_sysdev_class = {
--	set_kset_name("spu"),
-+	.name = "spu",
- 	.shutdown = spu_shutdown,
- };
- 
-diff --git a/arch/powerpc/platforms/powermac/pic.c b/arch/powerpc/platforms/powermac/pic.c
-index 999f5e1..84c0d4e 100644
---- a/arch/powerpc/platforms/powermac/pic.c
-+++ b/arch/powerpc/platforms/powermac/pic.c
-@@ -663,7 +663,7 @@ static int pmacpic_resume(struct sys_device *sysdev)
- #endif /* CONFIG_PM && CONFIG_PPC32 */
- 
- static struct sysdev_class pmacpic_sysclass = {
--	set_kset_name("pmac_pic"),
-+	.name = "pmac_pic",
- };
- 
- static struct sys_device device_pmacpic = {
-diff --git a/arch/powerpc/platforms/pseries/hotplug-cpu.c b/arch/powerpc/platforms/pseries/hotplug-cpu.c
-index 412e6b4..c4ad54e 100644
---- a/arch/powerpc/platforms/pseries/hotplug-cpu.c
-+++ b/arch/powerpc/platforms/pseries/hotplug-cpu.c
-@@ -153,7 +153,7 @@ static int pseries_add_processor(struct device_node *np)
- 	for (i = 0; i < nthreads; i++)
- 		cpu_set(i, tmp);
- 
--	lock_cpu_hotplug();
-+	cpu_maps_update_begin();
- 
- 	BUG_ON(!cpus_subset(cpu_present_map, cpu_possible_map));
- 
-@@ -190,7 +190,7 @@ static int pseries_add_processor(struct device_node *np)
- 	}
- 	err = 0;
- out_unlock:
--	unlock_cpu_hotplug();
-+	cpu_maps_update_done();
- 	return err;
- }
- 
-@@ -211,7 +211,7 @@ static void pseries_remove_processor(struct device_node *np)
- 
- 	nthreads = len / sizeof(u32);
- 
--	lock_cpu_hotplug();
-+	cpu_maps_update_begin();
- 	for (i = 0; i < nthreads; i++) {
- 		for_each_present_cpu(cpu) {
- 			if (get_hard_smp_processor_id(cpu) != intserv[i])
-@@ -225,7 +225,7 @@ static void pseries_remove_processor(struct device_node *np)
- 			printk(KERN_WARNING "Could not find cpu to remove "
- 			       "with physical id 0x%x\n", intserv[i]);
- 	}
--	unlock_cpu_hotplug();
-+	cpu_maps_update_done();
- }
- 
- static int pseries_smp_notifier(struct notifier_block *nb,
-diff --git a/arch/powerpc/platforms/pseries/power.c b/arch/powerpc/platforms/pseries/power.c
-index 73e6902..e95fc15 100644
---- a/arch/powerpc/platforms/pseries/power.c
-+++ b/arch/powerpc/platforms/pseries/power.c
-@@ -28,13 +28,15 @@
- 
- unsigned long rtas_poweron_auto; /* default and normal state is 0 */
- 
--static ssize_t auto_poweron_show(struct kset *kset, char *buf)
-+static ssize_t auto_poweron_show(struct kobject *kobj,
-+				 struct kobj_attribute *attr, char *buf)
- {
-         return sprintf(buf, "%lu\n", rtas_poweron_auto);
- }
- 
--static ssize_t
--auto_poweron_store(struct kset *kset, const char *buf, size_t n)
-+static ssize_t auto_poweron_store(struct kobject *kobj,
-+				  struct kobj_attribute *attr,
-+				  const char *buf, size_t n)
- {
- 	int ret;
- 	unsigned long ups_restart;
-@@ -47,17 +49,11 @@ auto_poweron_store(struct kset *kset, const char *buf, size_t n)
- 	return -EINVAL;
- }
- 
--static struct subsys_attribute auto_poweron_attr = {
--        .attr   = {
--                .name = __stringify(auto_poweron),
--                .mode = 0644,
--        },
--        .show   = auto_poweron_show,
--        .store  = auto_poweron_store,
--};
-+static struct kobj_attribute auto_poweron_attr =
-+	__ATTR(auto_poweron, 0644, auto_poweron_show, auto_poweron_store);
- 
- #ifndef CONFIG_PM
--decl_subsys(power,NULL,NULL);
-+struct kobject *power_kobj;
- 
- static struct attribute *g[] = {
-         &auto_poweron_attr.attr,
-@@ -70,18 +66,16 @@ static struct attribute_group attr_group = {
- 
- static int __init pm_init(void)
- {
--        int error = subsystem_register(&power_subsys);
--        if (!error)
--                error = sysfs_create_group(&power_subsys.kobj, &attr_group);
--        return error;
-+	power_kobj = kobject_create_and_add("power", NULL);
-+	if (!power_kobj)
-+		return -ENOMEM;
-+	return sysfs_create_group(power_kobj, &attr_group);
- }
- core_initcall(pm_init);
- #else
--extern struct kset power_subsys;
+-void flush_cache_page(struct vm_area_struct *vma, unsigned long eaddr, unsigned long pfn)
+-{
+-	/* Invalidate any entries in either cache for the vma within the user
+-	   address space vma->vm_mm for the page starting at virtual address
+-	   'eaddr'.   This seems to be used primarily in breaking COW.  Note,
+-	   the I-cache must be searched too in case the page in question is
+-	   both writable and being executed from (e.g. stack trampolines.)
 -
- static int __init apo_pm_init(void)
- {
--	return (subsys_create_file(&power_subsys, &auto_poweron_attr));
-+	return (sysfs_create_file(power_kobj, &auto_poweron_attr));
- }
- __initcall(apo_pm_init);
- #endif
-diff --git a/arch/powerpc/platforms/pseries/rtasd.c b/arch/powerpc/platforms/pseries/rtasd.c
-index 73401c8..e3078ce 100644
---- a/arch/powerpc/platforms/pseries/rtasd.c
-+++ b/arch/powerpc/platforms/pseries/rtasd.c
-@@ -382,7 +382,7 @@ static void do_event_scan_all_cpus(long delay)
- {
- 	int cpu;
- 
--	lock_cpu_hotplug();
-+	get_online_cpus();
- 	cpu = first_cpu(cpu_online_map);
- 	for (;;) {
- 		set_cpus_allowed(current, cpumask_of_cpu(cpu));
-@@ -390,15 +390,15 @@ static void do_event_scan_all_cpus(long delay)
- 		set_cpus_allowed(current, CPU_MASK_ALL);
- 
- 		/* Drop hotplug lock, and sleep for the specified delay */
--		unlock_cpu_hotplug();
-+		put_online_cpus();
- 		msleep_interruptible(delay);
--		lock_cpu_hotplug();
-+		get_online_cpus();
- 
- 		cpu = next_cpu(cpu, cpu_online_map);
- 		if (cpu == NR_CPUS)
- 			break;
- 	}
--	unlock_cpu_hotplug();
-+	put_online_cpus();
- }
- 
- static int rtasd(void *unused)
-diff --git a/arch/powerpc/sysdev/ipic.c b/arch/powerpc/sysdev/ipic.c
-index 05a56e5..e898ff4 100644
---- a/arch/powerpc/sysdev/ipic.c
-+++ b/arch/powerpc/sysdev/ipic.c
-@@ -725,7 +725,7 @@ unsigned int ipic_get_irq(void)
- }
- 
- static struct sysdev_class ipic_sysclass = {
--	set_kset_name("ipic"),
-+	.name = "ipic",
- };
- 
- static struct sys_device device_ipic = {
-diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c
-index e479388..212a94f 100644
---- a/arch/powerpc/sysdev/mpic.c
-+++ b/arch/powerpc/sysdev/mpic.c
-@@ -1584,7 +1584,7 @@ static struct sysdev_class mpic_sysclass = {
- 	.resume = mpic_resume,
- 	.suspend = mpic_suspend,
- #endif
--	set_kset_name("mpic"),
-+	.name = "mpic",
- };
- 
- static int mpic_init_sys(void)
-diff --git a/arch/powerpc/sysdev/qe_lib/qe_ic.c b/arch/powerpc/sysdev/qe_lib/qe_ic.c
-index e1c0fd6..f59444d 100644
---- a/arch/powerpc/sysdev/qe_lib/qe_ic.c
-+++ b/arch/powerpc/sysdev/qe_lib/qe_ic.c
-@@ -483,7 +483,7 @@ int qe_ic_set_high_priority(unsigned int virq, unsigned int priority, int high)
- }
- 
- static struct sysdev_class qe_ic_sysclass = {
--	set_kset_name("qe_ic"),
-+	.name = "qe_ic",
- };
- 
- static struct sys_device device_qe_ic = {
-diff --git a/arch/ppc/platforms/83xx/mpc834x_sys.c b/arch/ppc/platforms/83xx/mpc834x_sys.c
-index b84f8df..cb0a749 100644
---- a/arch/ppc/platforms/83xx/mpc834x_sys.c
-+++ b/arch/ppc/platforms/83xx/mpc834x_sys.c
-@@ -224,26 +224,6 @@ mpc834x_sys_init_IRQ(void)
- 	ipic_set_default_priority();
- }
- 
--#if defined(CONFIG_I2C_MPC) && defined(CONFIG_SENSORS_DS1374)
--extern ulong	ds1374_get_rtc_time(void);
--extern int	ds1374_set_rtc_time(ulong);
+-	   Note, this is called with pte lock held.
+-	   */
 -
--static int __init
--mpc834x_rtc_hookup(void)
+-	sh64_dcache_purge_phy_page(pfn << PAGE_SHIFT);
+-
+-	if (vma->vm_flags & VM_EXEC) {
+-		sh64_icache_inv_user_page(vma, eaddr);
+-	}
+-}
+-
+-/****************************************************************************/
+-
+-#ifndef CONFIG_DCACHE_DISABLED
+-
+-void copy_user_page(void *to, void *from, unsigned long address, struct page *page)
 -{
--	struct timespec	tv;
+-	/* 'from' and 'to' are kernel virtual addresses (within the superpage
+-	   mapping of the physical RAM).  'address' is the user virtual address
+-	   where the copy 'to' will be mapped after.  This allows a custom
+-	   mapping to be used to ensure that the new copy is placed in the
+-	   right cache sets for the user to see it without having to bounce it
+-	   out via memory.  Note however : the call to flush_page_to_ram in
+-	   (generic)/mm/memory.c:(break_cow) undoes all this good work in that one
+-	   very important case!
 -
--	ppc_md.get_rtc_time = ds1374_get_rtc_time;
--	ppc_md.set_rtc_time = ds1374_set_rtc_time;
+-	   TBD : can we guarantee that on every call, any cache entries for
+-	   'from' are in the same colour sets as 'address' also?  i.e. is this
+-	   always used just to deal with COW?  (I suspect not). */
 -
--	tv.tv_nsec = 0;
--	tv.tv_sec = (ppc_md.get_rtc_time)();
--	do_settimeofday(&tv);
+-	/* There are two possibilities here for when the page 'from' was last accessed:
+-	   * by the kernel : this is OK, no purge required.
+-	   * by the/a user (e.g. for break_COW) : need to purge.
 -
--	return 0;
+-	   If the potential user mapping at 'address' is the same colour as
+-	   'from' there is no need to purge any cache lines from the 'from'
+-	   page mapped into cache sets of colour 'address'.  (The copy will be
+-	   accessing the page through 'from').
+-	   */
+-
+-	if (((address ^ (unsigned long) from) & CACHE_OC_SYN_MASK) != 0) {
+-		sh64_dcache_purge_coloured_phy_page(__pa(from), address);
+-	}
+-
+-	if (((address ^ (unsigned long) to) & CACHE_OC_SYN_MASK) == 0) {
+-		/* No synonym problem on destination */
+-		sh64_page_copy(from, to);
+-	} else {
+-		sh64_copy_user_page_coloured(to, from, address);
+-	}
+-
+-	/* Note, don't need to flush 'from' page from the cache again - it's
+-	   done anyway by the generic code */
 -}
--late_initcall(mpc834x_rtc_hookup);
--#endif
- static __inline__ void
- mpc834x_sys_set_bat(void)
- {
-diff --git a/arch/ppc/platforms/85xx/tqm85xx.c b/arch/ppc/platforms/85xx/tqm85xx.c
-index 4ee2bd1..27ce389 100644
---- a/arch/ppc/platforms/85xx/tqm85xx.c
-+++ b/arch/ppc/platforms/85xx/tqm85xx.c
-@@ -258,27 +258,6 @@ int tqm85xx_show_cpuinfo(struct seq_file *m)
- 	return 0;
- }
- 
--#if defined(CONFIG_I2C) && defined(CONFIG_SENSORS_DS1337)
--extern ulong ds1337_get_rtc_time(void);
--extern int ds1337_set_rtc_time(unsigned long nowtime);
 -
--static int __init
--tqm85xx_rtc_hookup(void)
+-void clear_user_page(void *to, unsigned long address, struct page *page)
 -{
--	struct timespec	tv;
+-	/* 'to' is a kernel virtual address (within the superpage
+-	   mapping of the physical RAM).  'address' is the user virtual address
+-	   where the 'to' page will be mapped after.  This allows a custom
+-	   mapping to be used to ensure that the new copy is placed in the
+-	   right cache sets for the user to see it without having to bounce it
+-	   out via memory.
+-	*/
 -
--        ppc_md.set_rtc_time = ds1337_set_rtc_time;
--        ppc_md.get_rtc_time = ds1337_get_rtc_time;
+-	if (((address ^ (unsigned long) to) & CACHE_OC_SYN_MASK) == 0) {
+-		/* No synonym problem on destination */
+-		sh64_page_clear(to);
+-	} else {
+-		sh64_clear_user_page_coloured(to, address);
+-	}
+-}
 -
--	tv.tv_nsec = 0;
--	tv.tv_sec = (ppc_md.get_rtc_time)();
--	do_settimeofday(&tv);
+-#endif /* !CONFIG_DCACHE_DISABLED */
 -
--	return 0;
+-/****************************************************************************/
+-
+-void flush_dcache_page(struct page *page)
+-{
+-	sh64_dcache_purge_phy_page(page_to_phys(page));
+-	wmb();
 -}
--late_initcall(tqm85xx_rtc_hookup);
--#endif
 -
- #ifdef CONFIG_PCI
- /*
-  * interrupt routing
-diff --git a/arch/ppc/platforms/katana.c b/arch/ppc/platforms/katana.c
-index 52f63e6..fe6e88c 100644
---- a/arch/ppc/platforms/katana.c
-+++ b/arch/ppc/platforms/katana.c
-@@ -838,27 +838,6 @@ katana_find_end_of_memory(void)
- 	return bdp->bi_memsize;
- }
- 
--#if defined(CONFIG_I2C_MV64XXX) && defined(CONFIG_SENSORS_M41T00)
--extern ulong	m41t00_get_rtc_time(void);
--extern int	m41t00_set_rtc_time(ulong);
+-/****************************************************************************/
 -
--static int __init
--katana_rtc_hookup(void)
+-void flush_icache_range(unsigned long start, unsigned long end)
 -{
--	struct timespec	tv;
+-	/* Flush the range [start,end] of kernel virtual adddress space from
+-	   the I-cache.  The corresponding range must be purged from the
+-	   D-cache also because the SH-5 doesn't have cache snooping between
+-	   the caches.  The addresses will be visible through the superpage
+-	   mapping, therefore it's guaranteed that there no cache entries for
+-	   the range in cache sets of the wrong colour.
 -
--	ppc_md.get_rtc_time = m41t00_get_rtc_time;
--	ppc_md.set_rtc_time = m41t00_set_rtc_time;
+-	   Primarily used for cohering the I-cache after a module has
+-	   been loaded.  */
 -
--	tv.tv_nsec = 0;
--	tv.tv_sec = (ppc_md.get_rtc_time)();
--	do_settimeofday(&tv);
+-	/* We also make sure to purge the same range from the D-cache since
+-	   flush_page_to_ram() won't be doing this for us! */
 -
--	return 0;
+-	sh64_dcache_purge_kernel_range(start, end);
+-	wmb();
+-	sh64_icache_inv_kernel_range(start, end);
 -}
--late_initcall(katana_rtc_hookup);
--#endif
 -
- #if defined(CONFIG_SERIAL_TEXT_DEBUG) && defined(CONFIG_SERIAL_MPSC_CONSOLE)
- static void __init
- katana_map_io(void)
-diff --git a/arch/ppc/syslib/ipic.c b/arch/ppc/syslib/ipic.c
-index 9192777..4f163e2 100644
---- a/arch/ppc/syslib/ipic.c
-+++ b/arch/ppc/syslib/ipic.c
-@@ -614,7 +614,7 @@ int ipic_get_irq(void)
- }
- 
- static struct sysdev_class ipic_sysclass = {
--	set_kset_name("ipic"),
-+	.name = "ipic",
- };
- 
- static struct sys_device device_ipic = {
-diff --git a/arch/ppc/syslib/open_pic.c b/arch/ppc/syslib/open_pic.c
-index 18ec947..da36522 100644
---- a/arch/ppc/syslib/open_pic.c
-+++ b/arch/ppc/syslib/open_pic.c
-@@ -1043,7 +1043,7 @@ int openpic_resume(struct sys_device *sysdev)
- #endif /* CONFIG_PM */
- 
- static struct sysdev_class openpic_sysclass = {
--	set_kset_name("openpic"),
-+	.name = "openpic",
- };
- 
- static struct sys_device device_openpic = {
-diff --git a/arch/ppc/syslib/open_pic2.c b/arch/ppc/syslib/open_pic2.c
-index d585207..449075a 100644
---- a/arch/ppc/syslib/open_pic2.c
-+++ b/arch/ppc/syslib/open_pic2.c
-@@ -666,7 +666,7 @@ int openpic2_resume(struct sys_device *sysdev)
- 
- /* HACK ALERT */
- static struct sysdev_class openpic2_sysclass = {
--	set_kset_name("openpic2"),
-+	.name = "openpic2",
- };
- 
- static struct sys_device device_openpic2 = {
-diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig
-index 1330061..6ef54d2 100644
---- a/arch/s390/Kconfig
-+++ b/arch/s390/Kconfig
-@@ -276,9 +276,6 @@ source "kernel/Kconfig.preempt"
- 
- source "mm/Kconfig"
- 
--config HOLES_IN_ZONE
--	def_bool y
+-/****************************************************************************/
+-
+-void flush_icache_user_range(struct vm_area_struct *vma,
+-			struct page *page, unsigned long addr, int len)
+-{
+-	/* Flush the range of user (defined by vma->vm_mm) address space
+-	   starting at 'addr' for 'len' bytes from the cache.  The range does
+-	   not straddle a page boundary, the unique physical page containing
+-	   the range is 'page'.  This seems to be used mainly for invalidating
+-	   an address range following a poke into the program text through the
+-	   ptrace() call from another process (e.g. for BRK instruction
+-	   insertion). */
+-
+-	sh64_dcache_purge_coloured_phy_page(page_to_phys(page), addr);
+-	mb();
+-
+-	if (vma->vm_flags & VM_EXEC) {
+-		sh64_icache_inv_user_small_range(vma->vm_mm, addr, len);
+-	}
+-}
+-
+-/*##########################################################################
+-			ARCH/SH64 PRIVATE CALLABLE API.
+-  ##########################################################################*/
+-
+-void flush_cache_sigtramp(unsigned long start, unsigned long end)
+-{
+-	/* For the address range [start,end), write back the data from the
+-	   D-cache and invalidate the corresponding region of the I-cache for
+-	   the current process.  Used to flush signal trampolines on the stack
+-	   to make them executable. */
+-
+-	sh64_dcache_wback_current_user_range(start, end);
+-	wmb();
+-	sh64_icache_inv_current_user_range(start, end);
+-}
+-
+diff --git a/arch/sh64/mm/consistent.c b/arch/sh64/mm/consistent.c
+deleted file mode 100644
+index c439620..0000000
+--- a/arch/sh64/mm/consistent.c
++++ /dev/null
+@@ -1,53 +0,0 @@
+-/*
+- * Copyright (C) 2001 David J. Mckay (david.mckay at st.com)
+- * Copyright (C) 2003 Paul Mundt (lethal at linux-sh.org)
+- *
+- * May be copied or modified under the terms of the GNU General Public
+- * License.  See linux/COPYING for more information.
+- *
+- * Dynamic DMA mapping support.
+- */
+-#include <linux/types.h>
+-#include <linux/mm.h>
+-#include <linux/string.h>
+-#include <linux/pci.h>
+-#include <linux/dma-mapping.h>
+-#include <linux/module.h>
+-#include <asm/io.h>
+-
+-void *consistent_alloc(struct pci_dev *hwdev, size_t size,
+-			   dma_addr_t *dma_handle)
+-{
+-	void *ret;
+-	int gfp = GFP_ATOMIC;
+-        void *vp;
+-
+-	if (hwdev == NULL || hwdev->dma_mask != 0xffffffff)
+-		gfp |= GFP_DMA;
+-
+-	ret = (void *)__get_free_pages(gfp, get_order(size));
+-
+-	/* now call our friend ioremap_nocache to give us an uncached area */
+-        vp = ioremap_nocache(virt_to_phys(ret), size);
+-
+-	if (vp != NULL) {
+-		memset(vp, 0, size);
+-		*dma_handle = virt_to_phys(ret);
+-		dma_cache_sync(NULL, ret, size, DMA_BIDIRECTIONAL);
+-	}
+-
+-	return vp;
+-}
+-EXPORT_SYMBOL(consistent_alloc);
+-
+-void consistent_free(struct pci_dev *hwdev, size_t size,
+-			 void *vaddr, dma_addr_t dma_handle)
+-{
+-	void *alloc;
+-
+-	alloc = phys_to_virt((unsigned long)dma_handle);
+-	free_pages((unsigned long)alloc, get_order(size));
+-
+-	iounmap(vaddr);
+-}
+-EXPORT_SYMBOL(consistent_free);
+diff --git a/arch/sh64/mm/extable.c b/arch/sh64/mm/extable.c
+deleted file mode 100644
+index a2e6e05..0000000
+--- a/arch/sh64/mm/extable.c
++++ /dev/null
+@@ -1,80 +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.
+- *
+- * arch/sh64/mm/extable.c
+- *
+- * Copyright (C) 2003 Richard Curnow
+- * Copyright (C) 2003, 2004  Paul Mundt
+- *
+- * Cloned from the 2.5 SH version..
+- */
+-#include <linux/rwsem.h>
+-#include <linux/module.h>
+-#include <asm/uaccess.h>
+-
+-extern unsigned long copy_user_memcpy, copy_user_memcpy_end;
+-extern void __copy_user_fixup(void);
+-
+-static const struct exception_table_entry __copy_user_fixup_ex = {
+-	.fixup = (unsigned long)&__copy_user_fixup,
+-};
+-
+-/* Some functions that may trap due to a bad user-mode address have too many loads
+-   and stores in them to make it at all practical to label each one and put them all in
+-   the main exception table.
+-
+-   In particular, the fast memcpy routine is like this.  It's fix-up is just to fall back
+-   to a slow byte-at-a-time copy, which is handled the conventional way.  So it's functionally
+-   OK to just handle any trap occurring in the fast memcpy with that fixup. */
+-static const struct exception_table_entry *check_exception_ranges(unsigned long addr)
+-{
+-	if ((addr >= (unsigned long)&copy_user_memcpy) &&
+-	    (addr <= (unsigned long)&copy_user_memcpy_end))
+-		return &__copy_user_fixup_ex;
+-
+-	return NULL;
+-}
 -
- comment "I/O subsystem configuration"
- 
- config MACHCHK_WARNING
-diff --git a/arch/s390/crypto/Kconfig b/arch/s390/crypto/Kconfig
+-/* Simple binary search */
+-const struct exception_table_entry *
+-search_extable(const struct exception_table_entry *first,
+-		 const struct exception_table_entry *last,
+-		 unsigned long value)
+-{
+-	const struct exception_table_entry *mid;
+-
+-	mid = check_exception_ranges(value);
+-	if (mid)
+-		return mid;
+-
+-        while (first <= last) {
+-		long diff;
+-
+-		mid = (last - first) / 2 + first;
+-		diff = mid->insn - value;
+-                if (diff == 0)
+-                        return mid;
+-                else if (diff < 0)
+-                        first = mid+1;
+-                else
+-                        last = mid-1;
+-        }
+-
+-        return NULL;
+-}
+-
+-int fixup_exception(struct pt_regs *regs)
+-{
+-	const struct exception_table_entry *fixup;
+-
+-	fixup = search_exception_tables(regs->pc);
+-	if (fixup) {
+-		regs->pc = fixup->fixup;
+-		return 1;
+-	}
+-
+-	return 0;
+-}
+-
+diff --git a/arch/sh64/mm/fault.c b/arch/sh64/mm/fault.c
 deleted file mode 100644
-index d1defbb..0000000
---- a/arch/s390/crypto/Kconfig
+index 7c79a1b..0000000
+--- a/arch/sh64/mm/fault.c
 +++ /dev/null
-@@ -1,60 +0,0 @@
--config CRYPTO_SHA1_S390
--	tristate "SHA1 digest algorithm"
--	depends on S390
--	select CRYPTO_ALGAPI
--	help
--	  This is the s390 hardware accelerated implementation of the
--	  SHA-1 secure hash standard (FIPS 180-1/DFIPS 180-2).
+@@ -1,602 +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.
+- *
+- * arch/sh64/mm/fault.c
+- *
+- * Copyright (C) 2000, 2001  Paolo Alberelli
+- * Copyright (C) 2003  Richard Curnow (/proc/tlb, bug fixes)
+- * Copyright (C) 2003  Paul Mundt
+- *
+- */
 -
--config CRYPTO_SHA256_S390
--	tristate "SHA256 digest algorithm"
--	depends on S390
--	select CRYPTO_ALGAPI
--	help
--	  This is the s390 hardware accelerated implementation of the
--	  SHA256 secure hash standard (DFIPS 180-2).
+-#include <linux/signal.h>
+-#include <linux/rwsem.h>
+-#include <linux/sched.h>
+-#include <linux/kernel.h>
+-#include <linux/errno.h>
+-#include <linux/string.h>
+-#include <linux/types.h>
+-#include <linux/ptrace.h>
+-#include <linux/mman.h>
+-#include <linux/mm.h>
+-#include <linux/smp.h>
+-#include <linux/interrupt.h>
 -
--	  This version of SHA implements a 256 bit hash with 128 bits of
--	  security against collision attacks.
+-#include <asm/system.h>
+-#include <asm/io.h>
+-#include <asm/tlb.h>
+-#include <asm/uaccess.h>
+-#include <asm/pgalloc.h>
+-#include <asm/mmu_context.h>
+-#include <asm/registers.h>		/* required by inline asm statements */
 -
--config CRYPTO_DES_S390
--	tristate "DES and Triple DES cipher algorithms"
--	depends on S390
--	select CRYPTO_ALGAPI
--	select CRYPTO_BLKCIPHER
--	help
--	  This us the s390 hardware accelerated implementation of the
--	  DES cipher algorithm (FIPS 46-2), and Triple DES EDE (FIPS 46-3).
+-#if defined(CONFIG_SH64_PROC_TLB)
+-#include <linux/init.h>
+-#include <linux/proc_fs.h>
+-/* Count numbers of tlb refills in each region */
+-static unsigned long long calls_to_update_mmu_cache = 0ULL;
+-static unsigned long long calls_to_flush_tlb_page   = 0ULL;
+-static unsigned long long calls_to_flush_tlb_range  = 0ULL;
+-static unsigned long long calls_to_flush_tlb_mm     = 0ULL;
+-static unsigned long long calls_to_flush_tlb_all    = 0ULL;
+-unsigned long long calls_to_do_slow_page_fault = 0ULL;
+-unsigned long long calls_to_do_fast_page_fault = 0ULL;
+-
+-/* Count size of ranges for flush_tlb_range */
+-static unsigned long long flush_tlb_range_1         = 0ULL;
+-static unsigned long long flush_tlb_range_2         = 0ULL;
+-static unsigned long long flush_tlb_range_3_4       = 0ULL;
+-static unsigned long long flush_tlb_range_5_7       = 0ULL;
+-static unsigned long long flush_tlb_range_8_11      = 0ULL;
+-static unsigned long long flush_tlb_range_12_15     = 0ULL;
+-static unsigned long long flush_tlb_range_16_up     = 0ULL;
 -
--config CRYPTO_AES_S390
--	tristate "AES cipher algorithms"
--	depends on S390
--	select CRYPTO_ALGAPI
--	select CRYPTO_BLKCIPHER
--	help
--	  This is the s390 hardware accelerated implementation of the
--	  AES cipher algorithms (FIPS-197). AES uses the Rijndael
--	  algorithm.
+-static unsigned long long page_not_present          = 0ULL;
 -
--	  Rijndael appears to be consistently a very good performer in
--	  both hardware and software across a wide range of computing
--	  environments regardless of its use in feedback or non-feedback
--	  modes. Its key setup time is excellent, and its key agility is
--	  good. Rijndael's very low memory requirements make it very well
--	  suited for restricted-space environments, in which it also
--	  demonstrates excellent performance. Rijndael's operations are
--	  among the easiest to defend against power and timing attacks.
+-#endif
 -
--	  On s390 the System z9-109 currently only supports the key size
--	  of 128 bit.
+-extern void die(const char *,struct pt_regs *,long);
 -
--config S390_PRNG
--	tristate "Pseudo random number generator device driver"
--	depends on S390
--	default "m"
--	help
--	  Select this option if you want to use the s390 pseudo random number
--	  generator. The PRNG is part of the cryptographic processor functions
--	  and uses triple-DES to generate secure random numbers like the
--	  ANSI X9.17 standard. The PRNG is usable via the char device
--	  /dev/prandom.
-diff --git a/arch/s390/crypto/aes_s390.c b/arch/s390/crypto/aes_s390.c
-index 5126696..a3f67f8 100644
---- a/arch/s390/crypto/aes_s390.c
-+++ b/arch/s390/crypto/aes_s390.c
-@@ -6,6 +6,7 @@
-  * s390 Version:
-  *   Copyright IBM Corp. 2005,2007
-  *   Author(s): Jan Glauber (jang at de.ibm.com)
-+ *		Sebastian Siewior (sebastian at breakpoint.cc> SW-Fallback
-  *
-  * Derived from "crypto/aes_generic.c"
-  *
-@@ -16,17 +17,13 @@
-  *
-  */
- 
-+#include <crypto/aes.h>
- #include <crypto/algapi.h>
-+#include <linux/err.h>
- #include <linux/module.h>
- #include <linux/init.h>
- #include "crypt_s390.h"
- 
--#define AES_MIN_KEY_SIZE	16
--#define AES_MAX_KEY_SIZE	32
+-#define PFLAG(val,flag)   (( (val) & (flag) ) ? #flag : "" )
+-#define PPROT(flag) PFLAG(pgprot_val(prot),flag)
 -
--/* data block size for all key lengths */
--#define AES_BLOCK_SIZE		16
+-static inline void print_prots(pgprot_t prot)
+-{
+-	printk("prot is 0x%08lx\n",pgprot_val(prot));
 -
- #define AES_KEYLEN_128		1
- #define AES_KEYLEN_192		2
- #define AES_KEYLEN_256		4
-@@ -39,45 +36,89 @@ struct s390_aes_ctx {
- 	long enc;
- 	long dec;
- 	int key_len;
-+	union {
-+		struct crypto_blkcipher *blk;
-+		struct crypto_cipher *cip;
-+	} fallback;
- };
- 
--static int aes_set_key(struct crypto_tfm *tfm, const u8 *in_key,
--		       unsigned int key_len)
-+/*
-+ * Check if the key_len is supported by the HW.
-+ * Returns 0 if it is, a positive number if it is not and software fallback is
-+ * required or a negative number in case the key size is not valid
-+ */
-+static int need_fallback(unsigned int key_len)
- {
--	struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm);
--	u32 *flags = &tfm->crt_flags;
+-	printk("%s %s %s %s %s\n",PPROT(_PAGE_SHARED),PPROT(_PAGE_READ),
+-	       PPROT(_PAGE_EXECUTE),PPROT(_PAGE_WRITE),PPROT(_PAGE_USER));
+-}
 -
- 	switch (key_len) {
- 	case 16:
- 		if (!(keylen_flag & AES_KEYLEN_128))
--			goto fail;
-+			return 1;
- 		break;
- 	case 24:
- 		if (!(keylen_flag & AES_KEYLEN_192))
--			goto fail;
+-static inline void print_vma(struct vm_area_struct *vma)
+-{
+-	printk("vma start 0x%08lx\n", vma->vm_start);
+-	printk("vma end   0x%08lx\n", vma->vm_end);
 -
-+			return 1;
- 		break;
- 	case 32:
- 		if (!(keylen_flag & AES_KEYLEN_256))
--			goto fail;
-+			return 1;
- 		break;
- 	default:
--		goto fail;
-+		return -1;
- 		break;
- 	}
-+	return 0;
-+}
-+
-+static int setkey_fallback_cip(struct crypto_tfm *tfm, const u8 *in_key,
-+		unsigned int key_len)
-+{
-+	struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm);
-+	int ret;
-+
-+	sctx->fallback.blk->base.crt_flags &= ~CRYPTO_TFM_REQ_MASK;
-+	sctx->fallback.blk->base.crt_flags |= (tfm->crt_flags &
-+			CRYPTO_TFM_REQ_MASK);
-+
-+	ret = crypto_cipher_setkey(sctx->fallback.cip, in_key, key_len);
-+	if (ret) {
-+		tfm->crt_flags &= ~CRYPTO_TFM_RES_MASK;
-+		tfm->crt_flags |= (sctx->fallback.blk->base.crt_flags &
-+				CRYPTO_TFM_RES_MASK);
-+	}
-+	return ret;
-+}
-+
-+static int aes_set_key(struct crypto_tfm *tfm, const u8 *in_key,
-+		       unsigned int key_len)
-+{
-+	struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm);
-+	u32 *flags = &tfm->crt_flags;
-+	int ret;
-+
-+	ret = need_fallback(key_len);
-+	if (ret < 0) {
-+		*flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
-+		return -EINVAL;
-+	}
- 
- 	sctx->key_len = key_len;
--	memcpy(sctx->key, in_key, key_len);
--	return 0;
--fail:
--	*flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
--	return -EINVAL;
-+	if (!ret) {
-+		memcpy(sctx->key, in_key, key_len);
-+		return 0;
-+	}
-+
-+	return setkey_fallback_cip(tfm, in_key, key_len);
- }
- 
- static void aes_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
- {
- 	const struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm);
- 
-+	if (unlikely(need_fallback(sctx->key_len))) {
-+		crypto_cipher_encrypt_one(sctx->fallback.cip, out, in);
-+		return;
-+	}
-+
- 	switch (sctx->key_len) {
- 	case 16:
- 		crypt_s390_km(KM_AES_128_ENCRYPT, &sctx->key, out, in,
-@@ -98,6 +139,11 @@ static void aes_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
- {
- 	const struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm);
- 
-+	if (unlikely(need_fallback(sctx->key_len))) {
-+		crypto_cipher_decrypt_one(sctx->fallback.cip, out, in);
-+		return;
-+	}
-+
- 	switch (sctx->key_len) {
- 	case 16:
- 		crypt_s390_km(KM_AES_128_DECRYPT, &sctx->key, out, in,
-@@ -114,6 +160,29 @@ static void aes_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
- 	}
- }
- 
-+static int fallback_init_cip(struct crypto_tfm *tfm)
-+{
-+	const char *name = tfm->__crt_alg->cra_name;
-+	struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm);
-+
-+	sctx->fallback.cip = crypto_alloc_cipher(name, 0,
-+			CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK);
-+
-+	if (IS_ERR(sctx->fallback.cip)) {
-+		printk(KERN_ERR "Error allocating fallback algo %s\n", name);
-+		return PTR_ERR(sctx->fallback.blk);
-+	}
-+
-+	return 0;
-+}
-+
-+static void fallback_exit_cip(struct crypto_tfm *tfm)
-+{
-+	struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm);
-+
-+	crypto_free_cipher(sctx->fallback.cip);
-+	sctx->fallback.cip = NULL;
-+}
- 
- static struct crypto_alg aes_alg = {
- 	.cra_name		=	"aes",
-@@ -125,6 +194,8 @@ static struct crypto_alg aes_alg = {
- 	.cra_ctxsize		=	sizeof(struct s390_aes_ctx),
- 	.cra_module		=	THIS_MODULE,
- 	.cra_list		=	LIST_HEAD_INIT(aes_alg.cra_list),
-+	.cra_init               =       fallback_init_cip,
-+	.cra_exit               =       fallback_exit_cip,
- 	.cra_u			=	{
- 		.cipher = {
- 			.cia_min_keysize	=	AES_MIN_KEY_SIZE,
-@@ -136,10 +207,70 @@ static struct crypto_alg aes_alg = {
- 	}
- };
- 
-+static int setkey_fallback_blk(struct crypto_tfm *tfm, const u8 *key,
-+		unsigned int len)
-+{
-+	struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm);
-+	unsigned int ret;
-+
-+	sctx->fallback.blk->base.crt_flags &= ~CRYPTO_TFM_REQ_MASK;
-+	sctx->fallback.blk->base.crt_flags |= (tfm->crt_flags &
-+			CRYPTO_TFM_REQ_MASK);
-+
-+	ret = crypto_blkcipher_setkey(sctx->fallback.blk, key, len);
-+	if (ret) {
-+		tfm->crt_flags &= ~CRYPTO_TFM_RES_MASK;
-+		tfm->crt_flags |= (sctx->fallback.blk->base.crt_flags &
-+				CRYPTO_TFM_RES_MASK);
-+	}
-+	return ret;
-+}
-+
-+static int fallback_blk_dec(struct blkcipher_desc *desc,
-+		struct scatterlist *dst, struct scatterlist *src,
-+		unsigned int nbytes)
-+{
-+	unsigned int ret;
-+	struct crypto_blkcipher *tfm;
-+	struct s390_aes_ctx *sctx = crypto_blkcipher_ctx(desc->tfm);
-+
-+	tfm = desc->tfm;
-+	desc->tfm = sctx->fallback.blk;
-+
-+	ret = crypto_blkcipher_decrypt_iv(desc, dst, src, nbytes);
-+
-+	desc->tfm = tfm;
-+	return ret;
-+}
-+
-+static int fallback_blk_enc(struct blkcipher_desc *desc,
-+		struct scatterlist *dst, struct scatterlist *src,
-+		unsigned int nbytes)
-+{
-+	unsigned int ret;
-+	struct crypto_blkcipher *tfm;
-+	struct s390_aes_ctx *sctx = crypto_blkcipher_ctx(desc->tfm);
-+
-+	tfm = desc->tfm;
-+	desc->tfm = sctx->fallback.blk;
-+
-+	ret = crypto_blkcipher_encrypt_iv(desc, dst, src, nbytes);
-+
-+	desc->tfm = tfm;
-+	return ret;
-+}
-+
- static int ecb_aes_set_key(struct crypto_tfm *tfm, const u8 *in_key,
- 			   unsigned int key_len)
- {
- 	struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm);
-+	int ret;
-+
-+	ret = need_fallback(key_len);
-+	if (ret > 0) {
-+		sctx->key_len = key_len;
-+		return setkey_fallback_blk(tfm, in_key, key_len);
-+	}
- 
- 	switch (key_len) {
- 	case 16:
-@@ -188,6 +319,9 @@ static int ecb_aes_encrypt(struct blkcipher_desc *desc,
- 	struct s390_aes_ctx *sctx = crypto_blkcipher_ctx(desc->tfm);
- 	struct blkcipher_walk walk;
- 
-+	if (unlikely(need_fallback(sctx->key_len)))
-+		return fallback_blk_enc(desc, dst, src, nbytes);
-+
- 	blkcipher_walk_init(&walk, dst, src, nbytes);
- 	return ecb_aes_crypt(desc, sctx->enc, sctx->key, &walk);
- }
-@@ -199,10 +333,37 @@ static int ecb_aes_decrypt(struct blkcipher_desc *desc,
- 	struct s390_aes_ctx *sctx = crypto_blkcipher_ctx(desc->tfm);
- 	struct blkcipher_walk walk;
- 
-+	if (unlikely(need_fallback(sctx->key_len)))
-+		return fallback_blk_dec(desc, dst, src, nbytes);
-+
- 	blkcipher_walk_init(&walk, dst, src, nbytes);
- 	return ecb_aes_crypt(desc, sctx->dec, sctx->key, &walk);
- }
- 
-+static int fallback_init_blk(struct crypto_tfm *tfm)
-+{
-+	const char *name = tfm->__crt_alg->cra_name;
-+	struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm);
-+
-+	sctx->fallback.blk = crypto_alloc_blkcipher(name, 0,
-+			CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK);
-+
-+	if (IS_ERR(sctx->fallback.blk)) {
-+		printk(KERN_ERR "Error allocating fallback algo %s\n", name);
-+		return PTR_ERR(sctx->fallback.blk);
-+	}
-+
-+	return 0;
-+}
-+
-+static void fallback_exit_blk(struct crypto_tfm *tfm)
-+{
-+	struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm);
-+
-+	crypto_free_blkcipher(sctx->fallback.blk);
-+	sctx->fallback.blk = NULL;
-+}
-+
- static struct crypto_alg ecb_aes_alg = {
- 	.cra_name		=	"ecb(aes)",
- 	.cra_driver_name	=	"ecb-aes-s390",
-@@ -214,6 +375,8 @@ static struct crypto_alg ecb_aes_alg = {
- 	.cra_type		=	&crypto_blkcipher_type,
- 	.cra_module		=	THIS_MODULE,
- 	.cra_list		=	LIST_HEAD_INIT(ecb_aes_alg.cra_list),
-+	.cra_init		=	fallback_init_blk,
-+	.cra_exit		=	fallback_exit_blk,
- 	.cra_u			=	{
- 		.blkcipher = {
- 			.min_keysize		=	AES_MIN_KEY_SIZE,
-@@ -229,6 +392,13 @@ static int cbc_aes_set_key(struct crypto_tfm *tfm, const u8 *in_key,
- 			   unsigned int key_len)
- {
- 	struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm);
-+	int ret;
-+
-+	ret = need_fallback(key_len);
-+	if (ret > 0) {
-+		sctx->key_len = key_len;
-+		return setkey_fallback_blk(tfm, in_key, key_len);
-+	}
- 
- 	switch (key_len) {
- 	case 16:
-@@ -283,6 +453,9 @@ static int cbc_aes_encrypt(struct blkcipher_desc *desc,
- 	struct s390_aes_ctx *sctx = crypto_blkcipher_ctx(desc->tfm);
- 	struct blkcipher_walk walk;
- 
-+	if (unlikely(need_fallback(sctx->key_len)))
-+		return fallback_blk_enc(desc, dst, src, nbytes);
-+
- 	blkcipher_walk_init(&walk, dst, src, nbytes);
- 	return cbc_aes_crypt(desc, sctx->enc, sctx->iv, &walk);
- }
-@@ -294,6 +467,9 @@ static int cbc_aes_decrypt(struct blkcipher_desc *desc,
- 	struct s390_aes_ctx *sctx = crypto_blkcipher_ctx(desc->tfm);
- 	struct blkcipher_walk walk;
- 
-+	if (unlikely(need_fallback(sctx->key_len)))
-+		return fallback_blk_dec(desc, dst, src, nbytes);
-+
- 	blkcipher_walk_init(&walk, dst, src, nbytes);
- 	return cbc_aes_crypt(desc, sctx->dec, sctx->iv, &walk);
- }
-@@ -309,6 +485,8 @@ static struct crypto_alg cbc_aes_alg = {
- 	.cra_type		=	&crypto_blkcipher_type,
- 	.cra_module		=	THIS_MODULE,
- 	.cra_list		=	LIST_HEAD_INIT(cbc_aes_alg.cra_list),
-+	.cra_init		=	fallback_init_blk,
-+	.cra_exit		=	fallback_exit_blk,
- 	.cra_u			=	{
- 		.blkcipher = {
- 			.min_keysize		=	AES_MIN_KEY_SIZE,
-@@ -336,14 +514,10 @@ static int __init aes_init(void)
- 		return -EOPNOTSUPP;
- 
- 	/* z9 109 and z9 BC/EC only support 128 bit key length */
--	if (keylen_flag == AES_KEYLEN_128) {
--		aes_alg.cra_u.cipher.cia_max_keysize = AES_MIN_KEY_SIZE;
--		ecb_aes_alg.cra_u.blkcipher.max_keysize = AES_MIN_KEY_SIZE;
--		cbc_aes_alg.cra_u.blkcipher.max_keysize = AES_MIN_KEY_SIZE;
-+	if (keylen_flag == AES_KEYLEN_128)
- 		printk(KERN_INFO
--		       "aes_s390: hardware acceleration only available for"
-+		       "aes_s390: hardware acceleration only available for "
- 		       "128 bit keys\n");
--	}
- 
- 	ret = crypto_register_alg(&aes_alg);
- 	if (ret)
-@@ -382,4 +556,3 @@ MODULE_ALIAS("aes");
- 
- MODULE_DESCRIPTION("Rijndael (AES) Cipher Algorithm");
- MODULE_LICENSE("GPL");
+-	print_prots(vma->vm_page_prot);
+-	printk("vm_flags 0x%08lx\n", vma->vm_flags);
+-}
 -
-diff --git a/arch/s390/crypto/prng.c b/arch/s390/crypto/prng.c
-index 8eb3a1a..0cfefdd 100644
---- a/arch/s390/crypto/prng.c
-+++ b/arch/s390/crypto/prng.c
-@@ -90,7 +90,7 @@ static ssize_t prng_read(struct file *file, char __user *ubuf, size_t nbytes,
- 	int ret = 0;
- 	int tmp;
- 
--	/* nbytes can be arbitrary long, we spilt it into chunks */
-+	/* nbytes can be arbitrary length, we split it into chunks */
- 	while (nbytes) {
- 		/* same as in extract_entropy_user in random.c */
- 		if (need_resched()) {
-@@ -146,7 +146,7 @@ static ssize_t prng_read(struct file *file, char __user *ubuf, size_t nbytes,
- 	return ret;
- }
- 
--static struct file_operations prng_fops = {
-+static const struct file_operations prng_fops = {
- 	.owner		= THIS_MODULE,
- 	.open		= &prng_open,
- 	.release	= NULL,
-diff --git a/arch/s390/hypfs/inode.c b/arch/s390/hypfs/inode.c
-index 5245717..4b010ff 100644
---- a/arch/s390/hypfs/inode.c
-+++ b/arch/s390/hypfs/inode.c
-@@ -490,7 +490,7 @@ static struct super_operations hypfs_s_ops = {
- 	.show_options	= hypfs_show_options,
- };
- 
--static decl_subsys(s390, NULL, NULL);
-+static struct kobject *s390_kobj;
- 
- static int __init hypfs_init(void)
- {
-@@ -506,17 +506,18 @@ static int __init hypfs_init(void)
- 			goto fail_diag;
- 		}
- 	}
--	kobj_set_kset_s(&s390_subsys, hypervisor_subsys);
--	rc = subsystem_register(&s390_subsys);
--	if (rc)
-+	s390_kobj = kobject_create_and_add("s390", hypervisor_kobj);
-+	if (!s390_kobj) {
-+		rc = -ENOMEM;;
- 		goto fail_sysfs;
-+	}
- 	rc = register_filesystem(&hypfs_type);
- 	if (rc)
- 		goto fail_filesystem;
- 	return 0;
- 
- fail_filesystem:
--	subsystem_unregister(&s390_subsys);
-+	kobject_put(s390_kobj);
- fail_sysfs:
- 	if (!MACHINE_IS_VM)
- 		hypfs_diag_exit();
-@@ -530,7 +531,7 @@ static void __exit hypfs_exit(void)
- 	if (!MACHINE_IS_VM)
- 		hypfs_diag_exit();
- 	unregister_filesystem(&hypfs_type);
--	subsystem_unregister(&s390_subsys);
-+	kobject_put(s390_kobj);
- }
- 
- module_init(hypfs_init)
-diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile
-index 56cb710..b3b650a 100644
---- a/arch/s390/kernel/Makefile
-+++ b/arch/s390/kernel/Makefile
-@@ -31,7 +31,3 @@ S390_KEXEC_OBJS := machine_kexec.o crash.o
- S390_KEXEC_OBJS += $(if $(CONFIG_64BIT),relocate_kernel64.o,relocate_kernel.o)
- obj-$(CONFIG_KEXEC) += $(S390_KEXEC_OBJS)
- 
--#
--# This is just to get the dependencies...
--#
--binfmt_elf32.o:	$(TOPDIR)/fs/binfmt_elf.c
-diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c
-index 1b3af7d..9f7b73b 100644
---- a/arch/s390/kernel/early.c
-+++ b/arch/s390/kernel/early.c
-@@ -276,7 +276,7 @@ void __init startup_init(void)
- 	create_kernel_nss();
- 	sort_main_extable();
- 	setup_lowcore_early();
--	sclp_readinfo_early();
-+	sclp_read_info_early();
- 	sclp_facilities_detect();
- 	memsize = sclp_memory_detect();
- #ifndef CONFIG_64BIT
-diff --git a/arch/s390/kernel/head64.S b/arch/s390/kernel/head64.S
-index a87b197..79dccd2 100644
---- a/arch/s390/kernel/head64.S
-+++ b/arch/s390/kernel/head64.S
-@@ -157,7 +157,7 @@ startup_continue:
- 	.long	0xb2b10000		# store facility list
- 	tm	0xc8,0x08		# check bit for clearing-by-ASCE
- 	bno	0f-.LPG1(%r13)
--	lhi	%r1,2094
-+	lhi	%r1,2048
- 	lhi	%r2,0
- 	.long	0xb98e2001
- 	oi	7(%r12),0x80		# set IDTE flag
-diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c
-index ce0856d..db28cca 100644
---- a/arch/s390/kernel/ipl.c
-+++ b/arch/s390/kernel/ipl.c
-@@ -2,7 +2,7 @@
-  *  arch/s390/kernel/ipl.c
-  *    ipl/reipl/dump support for Linux on s390.
-  *
-- *    Copyright (C) IBM Corp. 2005,2006
-+ *    Copyright IBM Corp. 2005,2007
-  *    Author(s): Michael Holzheu <holzheu at de.ibm.com>
-  *		 Heiko Carstens <heiko.carstens at de.ibm.com>
-  *		 Volker Sameske <sameske at de.ibm.com>
-@@ -31,6 +31,43 @@
- #define IPL_FCP_DUMP_STR	"fcp_dump"
- #define IPL_NSS_STR		"nss"
- 
-+#define DUMP_CCW_STR		"ccw"
-+#define DUMP_FCP_STR		"fcp"
-+#define DUMP_NONE_STR		"none"
-+
-+/*
-+ * Four shutdown trigger types are supported:
-+ * - panic
-+ * - halt
-+ * - power off
-+ * - reipl
-+ */
-+#define ON_PANIC_STR		"on_panic"
-+#define ON_HALT_STR		"on_halt"
-+#define ON_POFF_STR		"on_poff"
-+#define ON_REIPL_STR		"on_reboot"
-+
-+struct shutdown_action;
-+struct shutdown_trigger {
-+	char *name;
-+	struct shutdown_action *action;
-+};
-+
-+/*
-+ * Five shutdown action types are supported:
-+ */
-+#define SHUTDOWN_ACTION_IPL_STR		"ipl"
-+#define SHUTDOWN_ACTION_REIPL_STR	"reipl"
-+#define SHUTDOWN_ACTION_DUMP_STR	"dump"
-+#define SHUTDOWN_ACTION_VMCMD_STR	"vmcmd"
-+#define SHUTDOWN_ACTION_STOP_STR	"stop"
-+
-+struct shutdown_action {
-+	char *name;
-+	void (*fn) (struct shutdown_trigger *trigger);
-+	int (*init) (void);
-+};
-+
- static char *ipl_type_str(enum ipl_type type)
- {
- 	switch (type) {
-@@ -54,10 +91,6 @@ enum dump_type {
- 	DUMP_TYPE_FCP	= 4,
- };
- 
--#define DUMP_NONE_STR	 "none"
--#define DUMP_CCW_STR	 "ccw"
--#define DUMP_FCP_STR	 "fcp"
+-static inline void print_task(struct task_struct *tsk)
+-{
+-	printk("Task pid %d\n", task_pid_nr(tsk));
+-}
 -
- static char *dump_type_str(enum dump_type type)
- {
- 	switch (type) {
-@@ -99,30 +132,6 @@ enum dump_method {
- 	DUMP_METHOD_FCP_DIAG,
- };
- 
--enum shutdown_action {
--	SHUTDOWN_REIPL,
--	SHUTDOWN_DUMP,
--	SHUTDOWN_STOP,
--};
+-static pte_t *lookup_pte(struct mm_struct *mm, unsigned long address)
+-{
+-	pgd_t *dir;
+-	pmd_t *pmd;
+-	pte_t *pte;
+-	pte_t entry;
 -
--#define SHUTDOWN_REIPL_STR "reipl"
--#define SHUTDOWN_DUMP_STR  "dump"
--#define SHUTDOWN_STOP_STR  "stop"
+-	dir = pgd_offset(mm, address);
+-	if (pgd_none(*dir)) {
+-		return NULL;
+-	}
 -
--static char *shutdown_action_str(enum shutdown_action action)
--{
--	switch (action) {
--	case SHUTDOWN_REIPL:
--		return SHUTDOWN_REIPL_STR;
--	case SHUTDOWN_DUMP:
--		return SHUTDOWN_DUMP_STR;
--	case SHUTDOWN_STOP:
--		return SHUTDOWN_STOP_STR;
--	default:
+-	pmd = pmd_offset(dir, address);
+-	if (pmd_none(*pmd)) {
 -		return NULL;
 -	}
--}
 -
- static int diag308_set_works = 0;
- 
- static int reipl_capabilities = IPL_TYPE_UNKNOWN;
-@@ -140,8 +149,6 @@ static enum dump_method dump_method = DUMP_METHOD_NONE;
- static struct ipl_parameter_block *dump_block_fcp;
- static struct ipl_parameter_block *dump_block_ccw;
- 
--static enum shutdown_action on_panic_action = SHUTDOWN_STOP;
+-	pte = pte_offset_kernel(pmd, address);
+-	entry = *pte;
 -
- static struct sclp_ipl_info sclp_ipl_info;
- 
- int diag308(unsigned long subcode, void *addr)
-@@ -162,22 +169,25 @@ EXPORT_SYMBOL_GPL(diag308);
- /* SYSFS */
- 
- #define DEFINE_IPL_ATTR_RO(_prefix, _name, _format, _value)		\
--static ssize_t sys_##_prefix##_##_name##_show(struct kset *kset,	\
-+static ssize_t sys_##_prefix##_##_name##_show(struct kobject *kobj,	\
-+		struct kobj_attribute *attr,				\
- 		char *page)						\
- {									\
- 	return sprintf(page, _format, _value);				\
- }									\
--static struct subsys_attribute sys_##_prefix##_##_name##_attr =		\
-+static struct kobj_attribute sys_##_prefix##_##_name##_attr =		\
- 	__ATTR(_name, S_IRUGO, sys_##_prefix##_##_name##_show, NULL);
- 
- #define DEFINE_IPL_ATTR_RW(_prefix, _name, _fmt_out, _fmt_in, _value)	\
--static ssize_t sys_##_prefix##_##_name##_show(struct kset *kset,	\
-+static ssize_t sys_##_prefix##_##_name##_show(struct kobject *kobj,	\
-+		struct kobj_attribute *attr,				\
- 		char *page)						\
- {									\
- 	return sprintf(page, _fmt_out,					\
- 			(unsigned long long) _value);			\
- }									\
--static ssize_t sys_##_prefix##_##_name##_store(struct kset *kset,	\
-+static ssize_t sys_##_prefix##_##_name##_store(struct kobject *kobj,	\
-+		struct kobj_attribute *attr,				\
- 		const char *buf, size_t len)				\
- {									\
- 	unsigned long long value;					\
-@@ -186,25 +196,27 @@ static ssize_t sys_##_prefix##_##_name##_store(struct kset *kset,	\
- 	_value = value;							\
- 	return len;							\
- }									\
--static struct subsys_attribute sys_##_prefix##_##_name##_attr =		\
-+static struct kobj_attribute sys_##_prefix##_##_name##_attr =		\
- 	__ATTR(_name,(S_IRUGO | S_IWUSR),				\
- 			sys_##_prefix##_##_name##_show,			\
- 			sys_##_prefix##_##_name##_store);
- 
- #define DEFINE_IPL_ATTR_STR_RW(_prefix, _name, _fmt_out, _fmt_in, _value)\
--static ssize_t sys_##_prefix##_##_name##_show(struct kset *kset,	\
-+static ssize_t sys_##_prefix##_##_name##_show(struct kobject *kobj,	\
-+		struct kobj_attribute *attr,				\
- 		char *page)						\
- {									\
- 	return sprintf(page, _fmt_out, _value);				\
- }									\
--static ssize_t sys_##_prefix##_##_name##_store(struct kset *kset,	\
-+static ssize_t sys_##_prefix##_##_name##_store(struct kobject *kobj,	\
-+		struct kobj_attribute *attr,				\
- 		const char *buf, size_t len)				\
- {									\
--	if (sscanf(buf, _fmt_in, _value) != 1)				\
--		return -EINVAL;						\
-+	strncpy(_value, buf, sizeof(_value) - 1);			\
-+	strstrip(_value);						\
- 	return len;							\
- }									\
--static struct subsys_attribute sys_##_prefix##_##_name##_attr =		\
-+static struct kobj_attribute sys_##_prefix##_##_name##_attr =		\
- 	__ATTR(_name,(S_IRUGO | S_IWUSR),				\
- 			sys_##_prefix##_##_name##_show,			\
- 			sys_##_prefix##_##_name##_store);
-@@ -240,44 +252,19 @@ static __init enum ipl_type get_ipl_type(void)
- 	return IPL_TYPE_FCP;
- }
- 
--void __init setup_ipl_info(void)
--{
--	ipl_info.type = get_ipl_type();
--	switch (ipl_info.type) {
--	case IPL_TYPE_CCW:
--		ipl_info.data.ccw.dev_id.devno = ipl_devno;
--		ipl_info.data.ccw.dev_id.ssid = 0;
--		break;
--	case IPL_TYPE_FCP:
--	case IPL_TYPE_FCP_DUMP:
--		ipl_info.data.fcp.dev_id.devno =
--			IPL_PARMBLOCK_START->ipl_info.fcp.devno;
--		ipl_info.data.fcp.dev_id.ssid = 0;
--		ipl_info.data.fcp.wwpn = IPL_PARMBLOCK_START->ipl_info.fcp.wwpn;
--		ipl_info.data.fcp.lun = IPL_PARMBLOCK_START->ipl_info.fcp.lun;
--		break;
--	case IPL_TYPE_NSS:
--		strncpy(ipl_info.data.nss.name, kernel_nss_name,
--			sizeof(ipl_info.data.nss.name));
--		break;
--	case IPL_TYPE_UNKNOWN:
--	default:
--		/* We have no info to copy */
--		break;
+-	if (pte_none(entry)) {
+-		return NULL;
+-	}
+-	if (!pte_present(entry)) {
+-		return NULL;
 -	}
+-
+-	return pte;
 -}
 -
- struct ipl_info ipl_info;
- EXPORT_SYMBOL_GPL(ipl_info);
- 
--static ssize_t ipl_type_show(struct kset *kset, char *page)
-+static ssize_t ipl_type_show(struct kobject *kobj, struct kobj_attribute *attr,
-+			     char *page)
- {
- 	return sprintf(page, "%s\n", ipl_type_str(ipl_info.type));
- }
- 
--static struct subsys_attribute sys_ipl_type_attr = __ATTR_RO(ipl_type);
-+static struct kobj_attribute sys_ipl_type_attr = __ATTR_RO(ipl_type);
- 
--static ssize_t sys_ipl_device_show(struct kset *kset, char *page)
-+static ssize_t sys_ipl_device_show(struct kobject *kobj,
-+				   struct kobj_attribute *attr, char *page)
- {
- 	struct ipl_parameter_block *ipl = IPL_PARMBLOCK_START;
- 
-@@ -292,7 +279,7 @@ static ssize_t sys_ipl_device_show(struct kset *kset, char *page)
- 	}
- }
- 
--static struct subsys_attribute sys_ipl_device_attr =
-+static struct kobj_attribute sys_ipl_device_attr =
- 	__ATTR(device, S_IRUGO, sys_ipl_device_show, NULL);
- 
- static ssize_t ipl_parameter_read(struct kobject *kobj, struct bin_attribute *attr,
-@@ -367,7 +354,8 @@ static struct attribute_group ipl_fcp_attr_group = {
- 
- /* CCW ipl device attributes */
- 
--static ssize_t ipl_ccw_loadparm_show(struct kset *kset, char *page)
-+static ssize_t ipl_ccw_loadparm_show(struct kobject *kobj,
-+				     struct kobj_attribute *attr, char *page)
- {
- 	char loadparm[LOADPARM_LEN + 1] = {};
- 
-@@ -379,7 +367,7 @@ static ssize_t ipl_ccw_loadparm_show(struct kset *kset, char *page)
- 	return sprintf(page, "%s\n", loadparm);
- }
- 
--static struct subsys_attribute sys_ipl_ccw_loadparm_attr =
-+static struct kobj_attribute sys_ipl_ccw_loadparm_attr =
- 	__ATTR(loadparm, 0444, ipl_ccw_loadparm_show, NULL);
- 
- static struct attribute *ipl_ccw_attrs[] = {
-@@ -418,10 +406,76 @@ static struct attribute_group ipl_unknown_attr_group = {
- 	.attrs = ipl_unknown_attrs,
- };
- 
--static decl_subsys(ipl, NULL, NULL);
-+static struct kset *ipl_kset;
-+
-+static int __init ipl_register_fcp_files(void)
-+{
-+	int rc;
-+
-+	rc = sysfs_create_group(&ipl_kset->kobj, &ipl_fcp_attr_group);
-+	if (rc)
-+		goto out;
-+	rc = sysfs_create_bin_file(&ipl_kset->kobj, &ipl_parameter_attr);
-+	if (rc)
-+		goto out_ipl_parm;
-+	rc = sysfs_create_bin_file(&ipl_kset->kobj, &ipl_scp_data_attr);
-+	if (!rc)
-+		goto out;
-+
-+	sysfs_remove_bin_file(&ipl_kset->kobj, &ipl_parameter_attr);
-+
-+out_ipl_parm:
-+	sysfs_remove_group(&ipl_kset->kobj, &ipl_fcp_attr_group);
-+out:
-+	return rc;
-+}
-+
-+static void ipl_run(struct shutdown_trigger *trigger)
-+{
-+	diag308(DIAG308_IPL, NULL);
-+	if (MACHINE_IS_VM)
-+		__cpcmd("IPL", NULL, 0, NULL);
-+	else if (ipl_info.type == IPL_TYPE_CCW)
-+		reipl_ccw_dev(&ipl_info.data.ccw.dev_id);
-+}
-+
-+static int ipl_init(void)
-+{
-+	int rc;
-+
-+	ipl_kset = kset_create_and_add("ipl", NULL, firmware_kobj);
-+	if (!ipl_kset) {
-+		rc = -ENOMEM;
-+		goto out;
-+	}
-+	switch (ipl_info.type) {
-+	case IPL_TYPE_CCW:
-+		rc = sysfs_create_group(&ipl_kset->kobj, &ipl_ccw_attr_group);
-+		break;
-+	case IPL_TYPE_FCP:
-+	case IPL_TYPE_FCP_DUMP:
-+		rc = ipl_register_fcp_files();
-+		break;
-+	case IPL_TYPE_NSS:
-+		rc = sysfs_create_group(&ipl_kset->kobj, &ipl_nss_attr_group);
-+		break;
-+	default:
-+		rc = sysfs_create_group(&ipl_kset->kobj,
-+					&ipl_unknown_attr_group);
-+		break;
-+	}
-+out:
-+	if (rc)
-+		panic("ipl_init failed: rc = %i\n", rc);
-+
-+	return 0;
-+}
-+
-+static struct shutdown_action ipl_action = {SHUTDOWN_ACTION_IPL_STR, ipl_run,
-+					    ipl_init};
- 
- /*
-- * reipl section
-+ * reipl shutdown action: Reboot Linux on shutdown.
-  */
- 
- /* FCP reipl device attributes */
-@@ -465,7 +519,8 @@ static void reipl_get_ascii_loadparm(char *loadparm)
- 	strstrip(loadparm);
- }
- 
--static ssize_t reipl_ccw_loadparm_show(struct kset *kset, char *page)
-+static ssize_t reipl_ccw_loadparm_show(struct kobject *kobj,
-+				       struct kobj_attribute *attr, char *page)
- {
- 	char buf[LOADPARM_LEN + 1];
- 
-@@ -473,7 +528,8 @@ static ssize_t reipl_ccw_loadparm_show(struct kset *kset, char *page)
- 	return sprintf(page, "%s\n", buf);
- }
- 
--static ssize_t reipl_ccw_loadparm_store(struct kset *kset,
-+static ssize_t reipl_ccw_loadparm_store(struct kobject *kobj,
-+					struct kobj_attribute *attr,
- 					const char *buf, size_t len)
- {
- 	int i, lp_len;
-@@ -500,7 +556,7 @@ static ssize_t reipl_ccw_loadparm_store(struct kset *kset,
- 	return len;
- }
- 
--static struct subsys_attribute sys_reipl_ccw_loadparm_attr =
-+static struct kobj_attribute sys_reipl_ccw_loadparm_attr =
- 	__ATTR(loadparm, 0644, reipl_ccw_loadparm_show,
- 	       reipl_ccw_loadparm_store);
- 
-@@ -539,7 +595,9 @@ static int reipl_set_type(enum ipl_type type)
- 
- 	switch(type) {
- 	case IPL_TYPE_CCW:
--		if (MACHINE_IS_VM)
-+		if (diag308_set_works)
-+			reipl_method = REIPL_METHOD_CCW_DIAG;
-+		else if (MACHINE_IS_VM)
- 			reipl_method = REIPL_METHOD_CCW_VM;
- 		else
- 			reipl_method = REIPL_METHOD_CCW_CIO;
-@@ -568,13 +626,15 @@ static int reipl_set_type(enum ipl_type type)
- 	return 0;
- }
- 
--static ssize_t reipl_type_show(struct kset *kset, char *page)
-+static ssize_t reipl_type_show(struct kobject *kobj,
-+			       struct kobj_attribute *attr, char *page)
- {
- 	return sprintf(page, "%s\n", ipl_type_str(reipl_type));
- }
- 
--static ssize_t reipl_type_store(struct kset *kset, const char *buf,
--				size_t len)
-+static ssize_t reipl_type_store(struct kobject *kobj,
-+				struct kobj_attribute *attr,
-+				const char *buf, size_t len)
- {
- 	int rc = -EINVAL;
- 
-@@ -587,140 +647,12 @@ static ssize_t reipl_type_store(struct kset *kset, const char *buf,
- 	return (rc != 0) ? rc : len;
- }
- 
--static struct subsys_attribute reipl_type_attr =
--		__ATTR(reipl_type, 0644, reipl_type_show, reipl_type_store);
+-/*
+- * This routine handles page faults.  It determines the address,
+- * and the problem, and then passes it off to one of the appropriate
+- * routines.
+- */
+-asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long writeaccess,
+-			      unsigned long textaccess, unsigned long address)
+-{
+-	struct task_struct *tsk;
+-	struct mm_struct *mm;
+-	struct vm_area_struct * vma;
+-	const struct exception_table_entry *fixup;
+-	pte_t *pte;
+-	int fault;
+-
+-#if defined(CONFIG_SH64_PROC_TLB)
+-        ++calls_to_do_slow_page_fault;
+-#endif
+-
+-	/* SIM
+-	 * Note this is now called with interrupts still disabled
+-	 * This is to cope with being called for a missing IO port
+-	 * address with interrupts disabled. This should be fixed as
+-	 * soon as we have a better 'fast path' miss handler.
+-	 *
+-	 * Plus take care how you try and debug this stuff.
+-	 * For example, writing debug data to a port which you
+-	 * have just faulted on is not going to work.
+-	 */
+-
+-	tsk = current;
+-	mm = tsk->mm;
+-
+-	/* Not an IO address, so reenable interrupts */
+-	local_irq_enable();
+-
+-	/*
+-	 * If we're in an interrupt or have no user
+-	 * context, we must not take the fault..
+-	 */
+-	if (in_atomic() || !mm)
+-		goto no_context;
+-
+-	/* TLB misses upon some cache flushes get done under cli() */
+-	down_read(&mm->mmap_sem);
+-
+-	vma = find_vma(mm, address);
+-
+-	if (!vma) {
+-#ifdef DEBUG_FAULT
+-		print_task(tsk);
+-		printk("%s:%d fault, address is 0x%08x PC %016Lx textaccess %d writeaccess %d\n",
+-		       __FUNCTION__,__LINE__,
+-		       address,regs->pc,textaccess,writeaccess);
+-		show_regs(regs);
+-#endif
+-		goto bad_area;
+-	}
+-	if (vma->vm_start <= address) {
+-		goto good_area;
+-	}
+-
+-	if (!(vma->vm_flags & VM_GROWSDOWN)) {
+-#ifdef DEBUG_FAULT
+-		print_task(tsk);
+-		printk("%s:%d fault, address is 0x%08x PC %016Lx textaccess %d writeaccess %d\n",
+-		       __FUNCTION__,__LINE__,
+-		       address,regs->pc,textaccess,writeaccess);
+-		show_regs(regs);
+-
+-		print_vma(vma);
+-#endif
+-		goto bad_area;
+-	}
+-	if (expand_stack(vma, address)) {
+-#ifdef DEBUG_FAULT
+-		print_task(tsk);
+-		printk("%s:%d fault, address is 0x%08x PC %016Lx textaccess %d writeaccess %d\n",
+-		       __FUNCTION__,__LINE__,
+-		       address,regs->pc,textaccess,writeaccess);
+-		show_regs(regs);
+-#endif
+-		goto bad_area;
+-	}
+-/*
+- * Ok, we have a good vm_area for this memory access, so
+- * we can handle it..
+- */
+-good_area:
+-	if (textaccess) {
+-		if (!(vma->vm_flags & VM_EXEC))
+-			goto bad_area;
+-	} else {
+-		if (writeaccess) {
+-			if (!(vma->vm_flags & VM_WRITE))
+-				goto bad_area;
+-		} else {
+-			if (!(vma->vm_flags & VM_READ))
+-				goto bad_area;
+-		}
+-	}
+-
+-	/*
+-	 * If for any reason at all we couldn't handle the fault,
+-	 * make sure we exit gracefully rather than endlessly redo
+-	 * the fault.
+-	 */
+-survive:
+-	fault = handle_mm_fault(mm, vma, address, writeaccess);
+-	if (unlikely(fault & VM_FAULT_ERROR)) {
+-		if (fault & VM_FAULT_OOM)
+-			goto out_of_memory;
+-		else if (fault & VM_FAULT_SIGBUS)
+-			goto do_sigbus;
+-		BUG();
+-	}
+-	if (fault & VM_FAULT_MAJOR)
+-		tsk->maj_flt++;
+-	else
+-		tsk->min_flt++;
+-
+-	/* If we get here, the page fault has been handled.  Do the TLB refill
+-	   now from the newly-setup PTE, to avoid having to fault again right
+-	   away on the same instruction. */
+-	pte = lookup_pte (mm, address);
+-	if (!pte) {
+-		/* From empirical evidence, we can get here, due to
+-		   !pte_present(pte).  (e.g. if a swap-in occurs, and the page
+-		   is swapped back out again before the process that wanted it
+-		   gets rescheduled?) */
+-		goto no_pte;
+-	}
+-
+-	__do_tlb_refill(address, textaccess, pte);
+-
+-no_pte:
+-
+-	up_read(&mm->mmap_sem);
+-	return;
+-
+-/*
+- * Something tried to access memory that isn't in our memory map..
+- * Fix it, but check if it's kernel or user first..
+- */
+-bad_area:
+-#ifdef DEBUG_FAULT
+-	printk("fault:bad area\n");
+-#endif
+-	up_read(&mm->mmap_sem);
+-
+-	if (user_mode(regs)) {
+-		static int count=0;
+-		siginfo_t info;
+-		if (count < 4) {
+-			/* This is really to help debug faults when starting
+-			 * usermode, so only need a few */
+-			count++;
+-			printk("user mode bad_area address=%08lx pid=%d (%s) pc=%08lx\n",
+-				address, task_pid_nr(current), current->comm,
+-				(unsigned long) regs->pc);
+-#if 0
+-			show_regs(regs);
+-#endif
+-		}
+-		if (is_global_init(tsk)) {
+-			panic("INIT had user mode bad_area\n");
+-		}
+-		tsk->thread.address = address;
+-		tsk->thread.error_code = writeaccess;
+-		info.si_signo = SIGSEGV;
+-		info.si_errno = 0;
+-		info.si_addr = (void *) address;
+-		force_sig_info(SIGSEGV, &info, tsk);
+-		return;
+-	}
 -
--static decl_subsys(reipl, NULL, NULL);
+-no_context:
+-#ifdef DEBUG_FAULT
+-	printk("fault:No context\n");
+-#endif
+-	/* Are we prepared to handle this kernel fault?  */
+-	fixup = search_exception_tables(regs->pc);
+-	if (fixup) {
+-		regs->pc = fixup->fixup;
+-		return;
+-	}
 -
 -/*
-- * dump section
+- * Oops. The kernel tried to access some bad page. We'll have to
+- * terminate things with extreme prejudice.
+- *
 - */
+-	if (address < PAGE_SIZE)
+-		printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference");
+-	else
+-		printk(KERN_ALERT "Unable to handle kernel paging request");
+-	printk(" at virtual address %08lx\n", address);
+-	printk(KERN_ALERT "pc = %08Lx%08Lx\n", regs->pc >> 32, regs->pc & 0xffffffff);
+-	die("Oops", regs, writeaccess);
+-	do_exit(SIGKILL);
 -
--/* FCP dump device attributes */
+-/*
+- * We ran out of memory, or some other thing happened to us that made
+- * us unable to handle the page fault gracefully.
+- */
+-out_of_memory:
+-	if (is_global_init(current)) {
+-		panic("INIT out of memory\n");
+-		yield();
+-		goto survive;
+-	}
+-	printk("fault:Out of memory\n");
+-	up_read(&mm->mmap_sem);
+-	if (is_global_init(current)) {
+-		yield();
+-		down_read(&mm->mmap_sem);
+-		goto survive;
+-	}
+-	printk("VM: killing process %s\n", tsk->comm);
+-	if (user_mode(regs))
+-		do_group_exit(SIGKILL);
+-	goto no_context;
+-
+-do_sigbus:
+-	printk("fault:Do sigbus\n");
+-	up_read(&mm->mmap_sem);
 -
--DEFINE_IPL_ATTR_RW(dump_fcp, wwpn, "0x%016llx\n", "%016llx\n",
--		   dump_block_fcp->ipl_info.fcp.wwpn);
--DEFINE_IPL_ATTR_RW(dump_fcp, lun, "0x%016llx\n", "%016llx\n",
--		   dump_block_fcp->ipl_info.fcp.lun);
--DEFINE_IPL_ATTR_RW(dump_fcp, bootprog, "%lld\n", "%lld\n",
--		   dump_block_fcp->ipl_info.fcp.bootprog);
--DEFINE_IPL_ATTR_RW(dump_fcp, br_lba, "%lld\n", "%lld\n",
--		   dump_block_fcp->ipl_info.fcp.br_lba);
--DEFINE_IPL_ATTR_RW(dump_fcp, device, "0.0.%04llx\n", "0.0.%llx\n",
--		   dump_block_fcp->ipl_info.fcp.devno);
+-	/*
+-	 * Send a sigbus, regardless of whether we were in kernel
+-	 * or user mode.
+-	 */
+-	tsk->thread.address = address;
+-	tsk->thread.error_code = writeaccess;
+-	tsk->thread.trap_no = 14;
+-	force_sig(SIGBUS, tsk);
 -
--static struct attribute *dump_fcp_attrs[] = {
--	&sys_dump_fcp_device_attr.attr,
--	&sys_dump_fcp_wwpn_attr.attr,
--	&sys_dump_fcp_lun_attr.attr,
--	&sys_dump_fcp_bootprog_attr.attr,
--	&sys_dump_fcp_br_lba_attr.attr,
--	NULL,
--};
+-	/* Kernel mode? Handle exceptions or die */
+-	if (!user_mode(regs))
+-		goto no_context;
+-}
 -
--static struct attribute_group dump_fcp_attr_group = {
--	.name  = IPL_FCP_STR,
--	.attrs = dump_fcp_attrs,
--};
 -
--/* CCW dump device attributes */
+-void flush_tlb_all(void);
 -
--DEFINE_IPL_ATTR_RW(dump_ccw, device, "0.0.%04llx\n", "0.0.%llx\n",
--		   dump_block_ccw->ipl_info.ccw.devno);
+-void update_mmu_cache(struct vm_area_struct * vma,
+-			unsigned long address, pte_t pte)
+-{
+-#if defined(CONFIG_SH64_PROC_TLB)
+-	++calls_to_update_mmu_cache;
+-#endif
 -
--static struct attribute *dump_ccw_attrs[] = {
--	&sys_dump_ccw_device_attr.attr,
--	NULL,
--};
+-	/*
+-	 * This appears to get called once for every pte entry that gets
+-	 * established => I don't think it's efficient to try refilling the
+-	 * TLBs with the pages - some may not get accessed even.  Also, for
+-	 * executable pages, it is impossible to determine reliably here which
+-	 * TLB they should be mapped into (or both even).
+-	 *
+-	 * So, just do nothing here and handle faults on demand.  In the
+-	 * TLBMISS handling case, the refill is now done anyway after the pte
+-	 * has been fixed up, so that deals with most useful cases.
+-	 */
+-}
 -
--static struct attribute_group dump_ccw_attr_group = {
--	.name  = IPL_CCW_STR,
--	.attrs = dump_ccw_attrs,
--};
+-static void __flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
+-{
+-	unsigned long long match, pteh=0, lpage;
+-	unsigned long tlb;
+-	struct mm_struct *mm;
 -
--/* dump type */
+-	mm = vma->vm_mm;
 -
--static int dump_set_type(enum dump_type type)
+-	if (mm->context == NO_CONTEXT)
+-		return;
+-
+-	/*
+-	 * Sign-extend based on neff.
+-	 */
+-	lpage = (page & NEFF_SIGN) ? (page | NEFF_MASK) : page;
+-	match = ((mm->context & MMU_CONTEXT_ASID_MASK) << PTEH_ASID_SHIFT) | PTEH_VALID;
+-	match |= lpage;
+-
+-        /* Do ITLB : don't bother for pages in non-exectutable VMAs */
+-	if (vma->vm_flags & VM_EXEC) {
+-		for_each_itlb_entry(tlb) {
+-			asm volatile ("getcfg	%1, 0, %0"
+-				      : "=r" (pteh)
+-				      : "r" (tlb) );
+-
+-			if (pteh == match) {
+-				__flush_tlb_slot(tlb);
+-				break;
+-			}
+-
+-		}
+-	}
+-
+-        /* Do DTLB : any page could potentially be in here. */
+-	for_each_dtlb_entry(tlb) {
+-		asm volatile ("getcfg	%1, 0, %0"
+-			      : "=r" (pteh)
+-			      : "r" (tlb) );
+-
+-		if (pteh == match) {
+-			__flush_tlb_slot(tlb);
+-			break;
+-		}
+-
+-	}
+-}
+-
+-void flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
 -{
--	if (!(dump_capabilities & type))
--		return -EINVAL;
--	switch(type) {
--	case DUMP_TYPE_CCW:
--		if (MACHINE_IS_VM)
--			dump_method = DUMP_METHOD_CCW_VM;
--		else if (diag308_set_works)
--			dump_method = DUMP_METHOD_CCW_DIAG;
--		else
--			dump_method = DUMP_METHOD_CCW_CIO;
--		break;
--	case DUMP_TYPE_FCP:
--		dump_method = DUMP_METHOD_FCP_DIAG;
--		break;
--	default:
--		dump_method = DUMP_METHOD_NONE;
+-	unsigned long flags;
+-
+-#if defined(CONFIG_SH64_PROC_TLB)
+-        ++calls_to_flush_tlb_page;
+-#endif
+-
+-	if (vma->vm_mm) {
+-		page &= PAGE_MASK;
+-		local_irq_save(flags);
+-		__flush_tlb_page(vma, page);
+-		local_irq_restore(flags);
 -	}
--	dump_type = type;
--	return 0;
 -}
 -
--static ssize_t dump_type_show(struct kset *kset, char *page)
+-void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
+-		     unsigned long end)
 -{
--	return sprintf(page, "%s\n", dump_type_str(dump_type));
+-	unsigned long flags;
+-	unsigned long long match, pteh=0, pteh_epn, pteh_low;
+-	unsigned long tlb;
+-	struct mm_struct *mm;
+-
+-	mm = vma->vm_mm;
+-
+-#if defined(CONFIG_SH64_PROC_TLB)
+-	++calls_to_flush_tlb_range;
+-
+-	{
+-		unsigned long size = (end - 1) - start;
+-		size >>= 12; /* divide by PAGE_SIZE */
+-		size++; /* end=start+4096 => 1 page */
+-		switch (size) {
+-		  case  1        : flush_tlb_range_1++;     break;
+-		  case  2        : flush_tlb_range_2++;     break;
+-		  case  3 ...  4 : flush_tlb_range_3_4++;   break;
+-		  case  5 ...  7 : flush_tlb_range_5_7++;   break;
+-		  case  8 ... 11 : flush_tlb_range_8_11++;  break;
+-		  case 12 ... 15 : flush_tlb_range_12_15++; break;
+-		  default        : flush_tlb_range_16_up++; break;
+-		}
+-	}
+-#endif
+-
+-	if (mm->context == NO_CONTEXT)
+-		return;
+-
+-	local_irq_save(flags);
+-
+-	start &= PAGE_MASK;
+-	end &= PAGE_MASK;
+-
+-	match = ((mm->context & MMU_CONTEXT_ASID_MASK) << PTEH_ASID_SHIFT) | PTEH_VALID;
+-
+-	/* Flush ITLB */
+-	for_each_itlb_entry(tlb) {
+-		asm volatile ("getcfg	%1, 0, %0"
+-			      : "=r" (pteh)
+-			      : "r" (tlb) );
+-
+-		pteh_epn = pteh & PAGE_MASK;
+-		pteh_low = pteh & ~PAGE_MASK;
+-
+-		if (pteh_low == match && pteh_epn >= start && pteh_epn <= end)
+-			__flush_tlb_slot(tlb);
+-	}
+-
+-	/* Flush DTLB */
+-	for_each_dtlb_entry(tlb) {
+-		asm volatile ("getcfg	%1, 0, %0"
+-			      : "=r" (pteh)
+-			      : "r" (tlb) );
+-
+-		pteh_epn = pteh & PAGE_MASK;
+-		pteh_low = pteh & ~PAGE_MASK;
+-
+-		if (pteh_low == match && pteh_epn >= start && pteh_epn <= end)
+-			__flush_tlb_slot(tlb);
+-	}
+-
+-	local_irq_restore(flags);
 -}
 -
--static ssize_t dump_type_store(struct kset *kset, const char *buf,
--			       size_t len)
+-void flush_tlb_mm(struct mm_struct *mm)
 -{
--	int rc = -EINVAL;
+-	unsigned long flags;
+-
+-#if defined(CONFIG_SH64_PROC_TLB)
+-	++calls_to_flush_tlb_mm;
+-#endif
+-
+-	if (mm->context == NO_CONTEXT)
+-		return;
+-
+-	local_irq_save(flags);
+-
+-	mm->context=NO_CONTEXT;
+-	if(mm==current->mm)
+-		activate_context(mm);
+-
+-	local_irq_restore(flags);
 -
--	if (strncmp(buf, DUMP_NONE_STR, strlen(DUMP_NONE_STR)) == 0)
--		rc = dump_set_type(DUMP_TYPE_NONE);
--	else if (strncmp(buf, DUMP_CCW_STR, strlen(DUMP_CCW_STR)) == 0)
--		rc = dump_set_type(DUMP_TYPE_CCW);
--	else if (strncmp(buf, DUMP_FCP_STR, strlen(DUMP_FCP_STR)) == 0)
--		rc = dump_set_type(DUMP_TYPE_FCP);
--	return (rc != 0) ? rc : len;
 -}
 -
--static struct subsys_attribute dump_type_attr =
--		__ATTR(dump_type, 0644, dump_type_show, dump_type_store);
+-void flush_tlb_all(void)
+-{
+-	/* Invalidate all, including shared pages, excluding fixed TLBs */
 -
--static decl_subsys(dump, NULL, NULL);
+-	unsigned long flags, tlb;
+-
+-#if defined(CONFIG_SH64_PROC_TLB)
+-	++calls_to_flush_tlb_all;
+-#endif
+-
+-	local_irq_save(flags);
+-
+-	/* Flush each ITLB entry */
+-	for_each_itlb_entry(tlb) {
+-		__flush_tlb_slot(tlb);
+-	}
+-
+-	/* Flush each DTLB entry */
+-	for_each_dtlb_entry(tlb) {
+-		__flush_tlb_slot(tlb);
+-	}
+-
+-	local_irq_restore(flags);
+-}
+-
+-void flush_tlb_kernel_range(unsigned long start, unsigned long end)
+-{
+-        /* FIXME: Optimize this later.. */
+-        flush_tlb_all();
+-}
 -
+-#if defined(CONFIG_SH64_PROC_TLB)
+-/* Procfs interface to read the performance information */
+-
+-static int
+-tlb_proc_info(char *buf, char **start, off_t fpos, int length, int *eof, void *data)
+-{
+-  int len=0;
+-  len += sprintf(buf+len, "do_fast_page_fault   called %12lld times\n", calls_to_do_fast_page_fault);
+-  len += sprintf(buf+len, "do_slow_page_fault   called %12lld times\n", calls_to_do_slow_page_fault);
+-  len += sprintf(buf+len, "update_mmu_cache     called %12lld times\n", calls_to_update_mmu_cache);
+-  len += sprintf(buf+len, "flush_tlb_page       called %12lld times\n", calls_to_flush_tlb_page);
+-  len += sprintf(buf+len, "flush_tlb_range      called %12lld times\n", calls_to_flush_tlb_range);
+-  len += sprintf(buf+len, "flush_tlb_mm         called %12lld times\n", calls_to_flush_tlb_mm);
+-  len += sprintf(buf+len, "flush_tlb_all        called %12lld times\n", calls_to_flush_tlb_all);
+-  len += sprintf(buf+len, "flush_tlb_range_sizes\n"
+-                          " 1      : %12lld\n"
+-                          " 2      : %12lld\n"
+-                          " 3 -  4 : %12lld\n"
+-                          " 5 -  7 : %12lld\n"
+-                          " 8 - 11 : %12lld\n"
+-                          "12 - 15 : %12lld\n"
+-                          "16+     : %12lld\n",
+-                          flush_tlb_range_1, flush_tlb_range_2, flush_tlb_range_3_4,
+-                          flush_tlb_range_5_7, flush_tlb_range_8_11, flush_tlb_range_12_15,
+-                          flush_tlb_range_16_up);
+-  len += sprintf(buf+len, "page not present           %12lld times\n", page_not_present);
+-  *eof = 1;
+-  return len;
+-}
+-
+-static int __init register_proc_tlb(void)
+-{
+-  create_proc_read_entry("tlb", 0, NULL, tlb_proc_info, NULL);
+-  return 0;
+-}
+-
+-__initcall(register_proc_tlb);
+-
+-#endif
+diff --git a/arch/sh64/mm/hugetlbpage.c b/arch/sh64/mm/hugetlbpage.c
+deleted file mode 100644
+index fa66daa..0000000
+--- a/arch/sh64/mm/hugetlbpage.c
++++ /dev/null
+@@ -1,105 +0,0 @@
 -/*
-- * Shutdown actions section
+- * arch/sh64/mm/hugetlbpage.c
+- *
+- * SuperH HugeTLB page support.
+- *
+- * Cloned from sparc64 by Paul Mundt.
+- *
+- * Copyright (C) 2002, 2003 David S. Miller (davem at redhat.com)
 - */
 -
--static decl_subsys(shutdown_actions, NULL, NULL);
+-#include <linux/init.h>
+-#include <linux/fs.h>
+-#include <linux/mm.h>
+-#include <linux/hugetlb.h>
+-#include <linux/pagemap.h>
+-#include <linux/slab.h>
+-#include <linux/sysctl.h>
 -
--/* on panic */
+-#include <asm/mman.h>
+-#include <asm/pgalloc.h>
+-#include <asm/tlb.h>
+-#include <asm/tlbflush.h>
+-#include <asm/cacheflush.h>
 -
--static ssize_t on_panic_show(struct kset *kset, char *page)
+-pte_t *huge_pte_alloc(struct mm_struct *mm, unsigned long addr)
 -{
--	return sprintf(page, "%s\n", shutdown_action_str(on_panic_action));
+-	pgd_t *pgd;
+-	pmd_t *pmd;
+-	pte_t *pte = NULL;
+-
+-	pgd = pgd_offset(mm, addr);
+-	if (pgd) {
+-		pmd = pmd_alloc(mm, pgd, addr);
+-		if (pmd)
+-			pte = pte_alloc_map(mm, pmd, addr);
+-	}
+-	return pte;
 -}
 -
--static ssize_t on_panic_store(struct kset *kset, const char *buf,
--			      size_t len)
+-pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr)
 -{
--	if (strncmp(buf, SHUTDOWN_REIPL_STR, strlen(SHUTDOWN_REIPL_STR)) == 0)
--		on_panic_action = SHUTDOWN_REIPL;
--	else if (strncmp(buf, SHUTDOWN_DUMP_STR,
--			 strlen(SHUTDOWN_DUMP_STR)) == 0)
--		on_panic_action = SHUTDOWN_DUMP;
--	else if (strncmp(buf, SHUTDOWN_STOP_STR,
--			 strlen(SHUTDOWN_STOP_STR)) == 0)
--		on_panic_action = SHUTDOWN_STOP;
--	else
--		return -EINVAL;
+-	pgd_t *pgd;
+-	pmd_t *pmd;
+-	pte_t *pte = NULL;
 -
--	return len;
+-	pgd = pgd_offset(mm, addr);
+-	if (pgd) {
+-		pmd = pmd_offset(pgd, addr);
+-		if (pmd)
+-			pte = pte_offset_map(pmd, addr);
+-	}
+-	return pte;
 -}
-+static struct kobj_attribute reipl_type_attr =
-+	__ATTR(reipl_type, 0644, reipl_type_show, reipl_type_store);
- 
--static struct subsys_attribute on_panic_attr =
--		__ATTR(on_panic, 0644, on_panic_show, on_panic_store);
-+static struct kset *reipl_kset;
- 
--void do_reipl(void)
-+void reipl_run(struct shutdown_trigger *trigger)
- {
- 	struct ccw_dev_id devid;
- 	static char buf[100];
-@@ -729,8 +661,6 @@ void do_reipl(void)
- 	switch (reipl_method) {
- 	case REIPL_METHOD_CCW_CIO:
- 		devid.devno = reipl_block_ccw->ipl_info.ccw.devno;
--		if (ipl_info.type == IPL_TYPE_CCW && devid.devno == ipl_devno)
--			diag308(DIAG308_IPL, NULL);
- 		devid.ssid  = 0;
- 		reipl_ccw_dev(&devid);
- 		break;
-@@ -771,98 +701,6 @@ void do_reipl(void)
- 	default:
- 		break;
- 	}
--	signal_processor(smp_processor_id(), sigp_stop_and_store_status);
+-
+-int huge_pmd_unshare(struct mm_struct *mm, unsigned long *addr, pte_t *ptep)
+-{
+-	return 0;
 -}
 -
--static void do_dump(void)
+-void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
+-		     pte_t *ptep, pte_t entry)
 -{
--	struct ccw_dev_id devid;
--	static char buf[100];
+-	int i;
 -
--	switch (dump_method) {
--	case DUMP_METHOD_CCW_CIO:
--		smp_send_stop();
--		devid.devno = dump_block_ccw->ipl_info.ccw.devno;
--		devid.ssid  = 0;
--		reipl_ccw_dev(&devid);
--		break;
--	case DUMP_METHOD_CCW_VM:
--		smp_send_stop();
--		sprintf(buf, "STORE STATUS");
--		__cpcmd(buf, NULL, 0, NULL);
--		sprintf(buf, "IPL %X", dump_block_ccw->ipl_info.ccw.devno);
--		__cpcmd(buf, NULL, 0, NULL);
--		break;
--	case DUMP_METHOD_CCW_DIAG:
--		diag308(DIAG308_SET, dump_block_ccw);
--		diag308(DIAG308_DUMP, NULL);
--		break;
--	case DUMP_METHOD_FCP_DIAG:
--		diag308(DIAG308_SET, dump_block_fcp);
--		diag308(DIAG308_DUMP, NULL);
--		break;
--	case DUMP_METHOD_NONE:
--	default:
--		return;
+-	for (i = 0; i < (1 << HUGETLB_PAGE_ORDER); i++) {
+-		set_pte_at(mm, addr, ptep, entry);
+-		ptep++;
+-		addr += PAGE_SIZE;
+-		pte_val(entry) += PAGE_SIZE;
 -	}
--	printk(KERN_EMERG "Dump failed!\n");
 -}
 -
--/* init functions */
--
--static int __init ipl_register_fcp_files(void)
+-pte_t huge_ptep_get_and_clear(struct mm_struct *mm, unsigned long addr,
+-			      pte_t *ptep)
 -{
--	int rc;
+-	pte_t entry;
+-	int i;
 -
--	rc = sysfs_create_group(&ipl_subsys.kobj,
--				&ipl_fcp_attr_group);
--	if (rc)
--		goto out;
--	rc = sysfs_create_bin_file(&ipl_subsys.kobj,
--				   &ipl_parameter_attr);
--	if (rc)
--		goto out_ipl_parm;
--	rc = sysfs_create_bin_file(&ipl_subsys.kobj,
--				   &ipl_scp_data_attr);
--	if (!rc)
--		goto out;
+-	entry = *ptep;
 -
--	sysfs_remove_bin_file(&ipl_subsys.kobj, &ipl_parameter_attr);
+-	for (i = 0; i < (1 << HUGETLB_PAGE_ORDER); i++) {
+-		pte_clear(mm, addr, ptep);
+-		addr += PAGE_SIZE;
+-		ptep++;
+-	}
 -
--out_ipl_parm:
--	sysfs_remove_group(&ipl_subsys.kobj, &ipl_fcp_attr_group);
--out:
--	return rc;
+-	return entry;
 -}
 -
--static int __init ipl_init(void)
+-struct page *follow_huge_addr(struct mm_struct *mm,
+-			      unsigned long address, int write)
 -{
--	int rc;
+-	return ERR_PTR(-EINVAL);
+-}
 -
--	rc = firmware_register(&ipl_subsys);
--	if (rc)
--		return rc;
--	switch (ipl_info.type) {
--	case IPL_TYPE_CCW:
--		rc = sysfs_create_group(&ipl_subsys.kobj,
--					&ipl_ccw_attr_group);
--		break;
--	case IPL_TYPE_FCP:
--	case IPL_TYPE_FCP_DUMP:
--		rc = ipl_register_fcp_files();
--		break;
--	case IPL_TYPE_NSS:
--		rc = sysfs_create_group(&ipl_subsys.kobj,
--					&ipl_nss_attr_group);
--		break;
--	default:
--		rc = sysfs_create_group(&ipl_subsys.kobj,
--					&ipl_unknown_attr_group);
--		break;
--	}
--	if (rc)
--		firmware_unregister(&ipl_subsys);
--	return rc;
- }
- 
- static void __init reipl_probe(void)
-@@ -883,7 +721,7 @@ static int __init reipl_nss_init(void)
- 
- 	if (!MACHINE_IS_VM)
- 		return 0;
--	rc = sysfs_create_group(&reipl_subsys.kobj, &reipl_nss_attr_group);
-+	rc = sysfs_create_group(&reipl_kset->kobj, &reipl_nss_attr_group);
- 	if (rc)
- 		return rc;
- 	strncpy(reipl_nss_name, kernel_nss_name, NSS_NAME_SIZE + 1);
-@@ -898,7 +736,7 @@ static int __init reipl_ccw_init(void)
- 	reipl_block_ccw = (void *) get_zeroed_page(GFP_KERNEL);
- 	if (!reipl_block_ccw)
- 		return -ENOMEM;
--	rc = sysfs_create_group(&reipl_subsys.kobj, &reipl_ccw_attr_group);
-+	rc = sysfs_create_group(&reipl_kset->kobj, &reipl_ccw_attr_group);
- 	if (rc) {
- 		free_page((unsigned long)reipl_block_ccw);
- 		return rc;
-@@ -907,6 +745,7 @@ static int __init reipl_ccw_init(void)
- 	reipl_block_ccw->hdr.version = IPL_PARM_BLOCK_VERSION;
- 	reipl_block_ccw->hdr.blk0_len = IPL_PARM_BLK0_CCW_LEN;
- 	reipl_block_ccw->hdr.pbt = DIAG308_IPL_TYPE_CCW;
-+	reipl_block_ccw->hdr.flags = DIAG308_FLAGS_LP_VALID;
- 	/* check if read scp info worked and set loadparm */
- 	if (sclp_ipl_info.is_valid)
- 		memcpy(reipl_block_ccw->ipl_info.ccw.load_param,
-@@ -915,8 +754,7 @@ static int __init reipl_ccw_init(void)
- 		/* read scp info failed: set empty loadparm (EBCDIC blanks) */
- 		memset(reipl_block_ccw->ipl_info.ccw.load_param, 0x40,
- 		       LOADPARM_LEN);
--	/* FIXME: check for diag308_set_works when enabling diag ccw reipl */
--	if (!MACHINE_IS_VM)
-+	if (!MACHINE_IS_VM && !diag308_set_works)
- 		sys_reipl_ccw_loadparm_attr.attr.mode = S_IRUGO;
- 	if (ipl_info.type == IPL_TYPE_CCW)
- 		reipl_block_ccw->ipl_info.ccw.devno = ipl_devno;
-@@ -936,7 +774,7 @@ static int __init reipl_fcp_init(void)
- 	reipl_block_fcp = (void *) get_zeroed_page(GFP_KERNEL);
- 	if (!reipl_block_fcp)
- 		return -ENOMEM;
--	rc = sysfs_create_group(&reipl_subsys.kobj, &reipl_fcp_attr_group);
-+	rc = sysfs_create_group(&reipl_kset->kobj, &reipl_fcp_attr_group);
- 	if (rc) {
- 		free_page((unsigned long)reipl_block_fcp);
- 		return rc;
-@@ -954,16 +792,16 @@ static int __init reipl_fcp_init(void)
- 	return 0;
- }
- 
--static int __init reipl_init(void)
-+static int reipl_init(void)
- {
- 	int rc;
- 
--	rc = firmware_register(&reipl_subsys);
--	if (rc)
--		return rc;
--	rc = subsys_create_file(&reipl_subsys, &reipl_type_attr);
-+	reipl_kset = kset_create_and_add("reipl", NULL, firmware_kobj);
-+	if (!reipl_kset)
-+		return -ENOMEM;
-+	rc = sysfs_create_file(&reipl_kset->kobj, &reipl_type_attr.attr);
- 	if (rc) {
--		firmware_unregister(&reipl_subsys);
-+		kset_unregister(reipl_kset);
- 		return rc;
- 	}
- 	rc = reipl_ccw_init();
-@@ -981,6 +819,140 @@ static int __init reipl_init(void)
- 	return 0;
- }
- 
-+static struct shutdown_action reipl_action = {SHUTDOWN_ACTION_REIPL_STR,
-+					      reipl_run, reipl_init};
-+
-+/*
-+ * dump shutdown action: Dump Linux on shutdown.
-+ */
-+
-+/* FCP dump device attributes */
-+
-+DEFINE_IPL_ATTR_RW(dump_fcp, wwpn, "0x%016llx\n", "%016llx\n",
-+		   dump_block_fcp->ipl_info.fcp.wwpn);
-+DEFINE_IPL_ATTR_RW(dump_fcp, lun, "0x%016llx\n", "%016llx\n",
-+		   dump_block_fcp->ipl_info.fcp.lun);
-+DEFINE_IPL_ATTR_RW(dump_fcp, bootprog, "%lld\n", "%lld\n",
-+		   dump_block_fcp->ipl_info.fcp.bootprog);
-+DEFINE_IPL_ATTR_RW(dump_fcp, br_lba, "%lld\n", "%lld\n",
-+		   dump_block_fcp->ipl_info.fcp.br_lba);
-+DEFINE_IPL_ATTR_RW(dump_fcp, device, "0.0.%04llx\n", "0.0.%llx\n",
-+		   dump_block_fcp->ipl_info.fcp.devno);
-+
-+static struct attribute *dump_fcp_attrs[] = {
-+	&sys_dump_fcp_device_attr.attr,
-+	&sys_dump_fcp_wwpn_attr.attr,
-+	&sys_dump_fcp_lun_attr.attr,
-+	&sys_dump_fcp_bootprog_attr.attr,
-+	&sys_dump_fcp_br_lba_attr.attr,
-+	NULL,
-+};
-+
-+static struct attribute_group dump_fcp_attr_group = {
-+	.name  = IPL_FCP_STR,
-+	.attrs = dump_fcp_attrs,
-+};
-+
-+/* CCW dump device attributes */
-+
-+DEFINE_IPL_ATTR_RW(dump_ccw, device, "0.0.%04llx\n", "0.0.%llx\n",
-+		   dump_block_ccw->ipl_info.ccw.devno);
-+
-+static struct attribute *dump_ccw_attrs[] = {
-+	&sys_dump_ccw_device_attr.attr,
-+	NULL,
-+};
-+
-+static struct attribute_group dump_ccw_attr_group = {
-+	.name  = IPL_CCW_STR,
-+	.attrs = dump_ccw_attrs,
-+};
-+
-+/* dump type */
-+
-+static int dump_set_type(enum dump_type type)
-+{
-+	if (!(dump_capabilities & type))
-+		return -EINVAL;
-+	switch (type) {
-+	case DUMP_TYPE_CCW:
-+		if (diag308_set_works)
-+			dump_method = DUMP_METHOD_CCW_DIAG;
-+		else if (MACHINE_IS_VM)
-+			dump_method = DUMP_METHOD_CCW_VM;
-+		else
-+			dump_method = DUMP_METHOD_CCW_CIO;
-+		break;
-+	case DUMP_TYPE_FCP:
-+		dump_method = DUMP_METHOD_FCP_DIAG;
-+		break;
-+	default:
-+		dump_method = DUMP_METHOD_NONE;
-+	}
-+	dump_type = type;
-+	return 0;
-+}
-+
-+static ssize_t dump_type_show(struct kobject *kobj,
-+			      struct kobj_attribute *attr, char *page)
-+{
-+	return sprintf(page, "%s\n", dump_type_str(dump_type));
-+}
-+
-+static ssize_t dump_type_store(struct kobject *kobj,
-+			       struct kobj_attribute *attr,
-+			       const char *buf, size_t len)
-+{
-+	int rc = -EINVAL;
-+
-+	if (strncmp(buf, DUMP_NONE_STR, strlen(DUMP_NONE_STR)) == 0)
-+		rc = dump_set_type(DUMP_TYPE_NONE);
-+	else if (strncmp(buf, DUMP_CCW_STR, strlen(DUMP_CCW_STR)) == 0)
-+		rc = dump_set_type(DUMP_TYPE_CCW);
-+	else if (strncmp(buf, DUMP_FCP_STR, strlen(DUMP_FCP_STR)) == 0)
-+		rc = dump_set_type(DUMP_TYPE_FCP);
-+	return (rc != 0) ? rc : len;
-+}
-+
-+static struct kobj_attribute dump_type_attr =
-+	__ATTR(dump_type, 0644, dump_type_show, dump_type_store);
-+
-+static struct kset *dump_kset;
-+
-+static void dump_run(struct shutdown_trigger *trigger)
-+{
-+	struct ccw_dev_id devid;
-+	static char buf[100];
-+
-+	switch (dump_method) {
-+	case DUMP_METHOD_CCW_CIO:
-+		smp_send_stop();
-+		devid.devno = dump_block_ccw->ipl_info.ccw.devno;
-+		devid.ssid  = 0;
-+		reipl_ccw_dev(&devid);
-+		break;
-+	case DUMP_METHOD_CCW_VM:
-+		smp_send_stop();
-+		sprintf(buf, "STORE STATUS");
-+		__cpcmd(buf, NULL, 0, NULL);
-+		sprintf(buf, "IPL %X", dump_block_ccw->ipl_info.ccw.devno);
-+		__cpcmd(buf, NULL, 0, NULL);
-+		break;
-+	case DUMP_METHOD_CCW_DIAG:
-+		diag308(DIAG308_SET, dump_block_ccw);
-+		diag308(DIAG308_DUMP, NULL);
-+		break;
-+	case DUMP_METHOD_FCP_DIAG:
-+		diag308(DIAG308_SET, dump_block_fcp);
-+		diag308(DIAG308_DUMP, NULL);
-+		break;
-+	case DUMP_METHOD_NONE:
-+	default:
-+		return;
-+	}
-+	printk(KERN_EMERG "Dump failed!\n");
-+}
-+
- static int __init dump_ccw_init(void)
- {
- 	int rc;
-@@ -988,7 +960,7 @@ static int __init dump_ccw_init(void)
- 	dump_block_ccw = (void *) get_zeroed_page(GFP_KERNEL);
- 	if (!dump_block_ccw)
- 		return -ENOMEM;
--	rc = sysfs_create_group(&dump_subsys.kobj, &dump_ccw_attr_group);
-+	rc = sysfs_create_group(&dump_kset->kobj, &dump_ccw_attr_group);
- 	if (rc) {
- 		free_page((unsigned long)dump_block_ccw);
- 		return rc;
-@@ -1012,7 +984,7 @@ static int __init dump_fcp_init(void)
- 	dump_block_fcp = (void *) get_zeroed_page(GFP_KERNEL);
- 	if (!dump_block_fcp)
- 		return -ENOMEM;
--	rc = sysfs_create_group(&dump_subsys.kobj, &dump_fcp_attr_group);
-+	rc = sysfs_create_group(&dump_kset->kobj, &dump_fcp_attr_group);
- 	if (rc) {
- 		free_page((unsigned long)dump_block_fcp);
- 		return rc;
-@@ -1026,33 +998,16 @@ static int __init dump_fcp_init(void)
- 	return 0;
- }
- 
--#define SHUTDOWN_ON_PANIC_PRIO 0
+-int pmd_huge(pmd_t pmd)
+-{
+-	return 0;
+-}
 -
--static int shutdown_on_panic_notify(struct notifier_block *self,
--				    unsigned long event, void *data)
+-struct page *follow_huge_pmd(struct mm_struct *mm, unsigned long address,
+-			     pmd_t *pmd, int write)
 -{
--	if (on_panic_action == SHUTDOWN_DUMP)
--		do_dump();
--	else if (on_panic_action == SHUTDOWN_REIPL)
--		do_reipl();
--	return NOTIFY_OK;
+-	return NULL;
 -}
+diff --git a/arch/sh64/mm/init.c b/arch/sh64/mm/init.c
+deleted file mode 100644
+index 21cf42d..0000000
+--- a/arch/sh64/mm/init.c
++++ /dev/null
+@@ -1,189 +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.
+- *
+- * arch/sh64/mm/init.c
+- *
+- * Copyright (C) 2000, 2001  Paolo Alberelli
+- * Copyright (C) 2003, 2004  Paul Mundt
+- *
+- */
 -
--static struct notifier_block shutdown_on_panic_nb = {
--	.notifier_call = shutdown_on_panic_notify,
--	.priority = SHUTDOWN_ON_PANIC_PRIO
--};
+-#include <linux/init.h>
+-#include <linux/rwsem.h>
+-#include <linux/mm.h>
+-#include <linux/swap.h>
+-#include <linux/bootmem.h>
 -
--static int __init dump_init(void)
-+static int dump_init(void)
- {
- 	int rc;
- 
--	rc = firmware_register(&dump_subsys);
--	if (rc)
--		return rc;
--	rc = subsys_create_file(&dump_subsys, &dump_type_attr);
-+	dump_kset = kset_create_and_add("dump", NULL, firmware_kobj);
-+	if (!dump_kset)
-+		return -ENOMEM;
-+	rc = sysfs_create_file(&dump_kset->kobj, &dump_type_attr.attr);
- 	if (rc) {
--		firmware_unregister(&dump_subsys);
-+		kset_unregister(dump_kset);
- 		return rc;
- 	}
- 	rc = dump_ccw_init();
-@@ -1065,46 +1020,381 @@ static int __init dump_init(void)
- 	return 0;
- }
- 
--static int __init shutdown_actions_init(void)
-+static struct shutdown_action dump_action = {SHUTDOWN_ACTION_DUMP_STR,
-+					     dump_run, dump_init};
-+
-+/*
-+ * vmcmd shutdown action: Trigger vm command on shutdown.
-+ */
-+
-+static char vmcmd_on_reboot[128];
-+static char vmcmd_on_panic[128];
-+static char vmcmd_on_halt[128];
-+static char vmcmd_on_poff[128];
-+
-+DEFINE_IPL_ATTR_STR_RW(vmcmd, on_reboot, "%s\n", "%s\n", vmcmd_on_reboot);
-+DEFINE_IPL_ATTR_STR_RW(vmcmd, on_panic, "%s\n", "%s\n", vmcmd_on_panic);
-+DEFINE_IPL_ATTR_STR_RW(vmcmd, on_halt, "%s\n", "%s\n", vmcmd_on_halt);
-+DEFINE_IPL_ATTR_STR_RW(vmcmd, on_poff, "%s\n", "%s\n", vmcmd_on_poff);
-+
-+static struct attribute *vmcmd_attrs[] = {
-+	&sys_vmcmd_on_reboot_attr.attr,
-+	&sys_vmcmd_on_panic_attr.attr,
-+	&sys_vmcmd_on_halt_attr.attr,
-+	&sys_vmcmd_on_poff_attr.attr,
-+	NULL,
-+};
-+
-+static struct attribute_group vmcmd_attr_group = {
-+	.attrs = vmcmd_attrs,
-+};
-+
-+static struct kset *vmcmd_kset;
-+
-+static void vmcmd_run(struct shutdown_trigger *trigger)
-+{
-+	char *cmd, *next_cmd;
-+
-+	if (strcmp(trigger->name, ON_REIPL_STR) == 0)
-+		cmd = vmcmd_on_reboot;
-+	else if (strcmp(trigger->name, ON_PANIC_STR) == 0)
-+		cmd = vmcmd_on_panic;
-+	else if (strcmp(trigger->name, ON_HALT_STR) == 0)
-+		cmd = vmcmd_on_halt;
-+	else if (strcmp(trigger->name, ON_POFF_STR) == 0)
-+		cmd = vmcmd_on_poff;
-+	else
-+		return;
-+
-+	if (strlen(cmd) == 0)
-+		return;
-+	do {
-+		next_cmd = strchr(cmd, '\n');
-+		if (next_cmd) {
-+			next_cmd[0] = 0;
-+			next_cmd += 1;
-+		}
-+		__cpcmd(cmd, NULL, 0, NULL);
-+		cmd = next_cmd;
-+	} while (cmd != NULL);
-+}
-+
-+static int vmcmd_init(void)
- {
--	int rc;
-+	if (!MACHINE_IS_VM)
-+		return -ENOTSUPP;
-+	vmcmd_kset = kset_create_and_add("vmcmd", NULL, firmware_kobj);
-+	if (!vmcmd_kset)
-+		return -ENOMEM;
-+	return sysfs_create_group(&vmcmd_kset->kobj, &vmcmd_attr_group);
-+}
- 
--	rc = firmware_register(&shutdown_actions_subsys);
--	if (rc)
--		return rc;
--	rc = subsys_create_file(&shutdown_actions_subsys, &on_panic_attr);
--	if (rc) {
--		firmware_unregister(&shutdown_actions_subsys);
--		return rc;
-+static struct shutdown_action vmcmd_action = {SHUTDOWN_ACTION_VMCMD_STR,
-+					      vmcmd_run, vmcmd_init};
-+
-+/*
-+ * stop shutdown action: Stop Linux on shutdown.
-+ */
-+
-+static void stop_run(struct shutdown_trigger *trigger)
-+{
-+	if (strcmp(trigger->name, ON_PANIC_STR) == 0)
-+		disabled_wait((unsigned long) __builtin_return_address(0));
-+	else {
-+		signal_processor(smp_processor_id(), sigp_stop);
-+		for (;;);
- 	}
--	atomic_notifier_chain_register(&panic_notifier_list,
--				       &shutdown_on_panic_nb);
--	return 0;
- }
- 
--static int __init s390_ipl_init(void)
-+static struct shutdown_action stop_action = {SHUTDOWN_ACTION_STOP_STR,
-+					     stop_run, NULL};
-+
-+/* action list */
-+
-+static struct shutdown_action *shutdown_actions_list[] = {
-+	&ipl_action, &reipl_action, &dump_action, &vmcmd_action, &stop_action};
-+#define SHUTDOWN_ACTIONS_COUNT (sizeof(shutdown_actions_list) / sizeof(void *))
-+
-+/*
-+ * Trigger section
-+ */
-+
-+static struct kset *shutdown_actions_kset;
-+
-+static int set_trigger(const char *buf, struct shutdown_trigger *trigger,
-+		       size_t len)
- {
--	int rc;
-+	int i;
-+	for (i = 0; i < SHUTDOWN_ACTIONS_COUNT; i++) {
-+		if (!shutdown_actions_list[i])
-+			continue;
-+		if (strncmp(buf, shutdown_actions_list[i]->name,
-+			    strlen(shutdown_actions_list[i]->name)) == 0) {
-+			trigger->action = shutdown_actions_list[i];
-+			return len;
-+		}
-+	}
-+	return -EINVAL;
-+}
- 
--	sclp_get_ipl_info(&sclp_ipl_info);
-+/* on reipl */
-+
-+static struct shutdown_trigger on_reboot_trigger = {ON_REIPL_STR,
-+						    &reipl_action};
-+
-+static ssize_t on_reboot_show(struct kobject *kobj,
-+			      struct kobj_attribute *attr, char *page)
-+{
-+	return sprintf(page, "%s\n", on_reboot_trigger.action->name);
-+}
-+
-+static ssize_t on_reboot_store(struct kobject *kobj,
-+			       struct kobj_attribute *attr,
-+			       const char *buf, size_t len)
-+{
-+	return set_trigger(buf, &on_reboot_trigger, len);
-+}
-+
-+static struct kobj_attribute on_reboot_attr =
-+	__ATTR(on_reboot, 0644, on_reboot_show, on_reboot_store);
-+
-+static void do_machine_restart(char *__unused)
-+{
-+	smp_send_stop();
-+	on_reboot_trigger.action->fn(&on_reboot_trigger);
-+	reipl_run(NULL);
-+}
-+void (*_machine_restart)(char *command) = do_machine_restart;
-+
-+/* on panic */
-+
-+static struct shutdown_trigger on_panic_trigger = {ON_PANIC_STR, &stop_action};
-+
-+static ssize_t on_panic_show(struct kobject *kobj,
-+			     struct kobj_attribute *attr, char *page)
-+{
-+	return sprintf(page, "%s\n", on_panic_trigger.action->name);
-+}
-+
-+static ssize_t on_panic_store(struct kobject *kobj,
-+			      struct kobj_attribute *attr,
-+			      const char *buf, size_t len)
-+{
-+	return set_trigger(buf, &on_panic_trigger, len);
-+}
-+
-+static struct kobj_attribute on_panic_attr =
-+	__ATTR(on_panic, 0644, on_panic_show, on_panic_store);
-+
-+static void do_panic(void)
-+{
-+	on_panic_trigger.action->fn(&on_panic_trigger);
-+	stop_run(&on_panic_trigger);
-+}
-+
-+/* on halt */
-+
-+static struct shutdown_trigger on_halt_trigger = {ON_HALT_STR, &stop_action};
-+
-+static ssize_t on_halt_show(struct kobject *kobj,
-+			    struct kobj_attribute *attr, char *page)
-+{
-+	return sprintf(page, "%s\n", on_halt_trigger.action->name);
-+}
-+
-+static ssize_t on_halt_store(struct kobject *kobj,
-+			     struct kobj_attribute *attr,
-+			     const char *buf, size_t len)
-+{
-+	return set_trigger(buf, &on_halt_trigger, len);
-+}
-+
-+static struct kobj_attribute on_halt_attr =
-+	__ATTR(on_halt, 0644, on_halt_show, on_halt_store);
-+
-+
-+static void do_machine_halt(void)
-+{
-+	smp_send_stop();
-+	on_halt_trigger.action->fn(&on_halt_trigger);
-+	stop_run(&on_halt_trigger);
-+}
-+void (*_machine_halt)(void) = do_machine_halt;
-+
-+/* on power off */
-+
-+static struct shutdown_trigger on_poff_trigger = {ON_POFF_STR, &stop_action};
-+
-+static ssize_t on_poff_show(struct kobject *kobj,
-+			    struct kobj_attribute *attr, char *page)
-+{
-+	return sprintf(page, "%s\n", on_poff_trigger.action->name);
-+}
-+
-+static ssize_t on_poff_store(struct kobject *kobj,
-+			     struct kobj_attribute *attr,
-+			     const char *buf, size_t len)
-+{
-+	return set_trigger(buf, &on_poff_trigger, len);
-+}
-+
-+static struct kobj_attribute on_poff_attr =
-+	__ATTR(on_poff, 0644, on_poff_show, on_poff_store);
-+
-+
-+static void do_machine_power_off(void)
-+{
-+	smp_send_stop();
-+	on_poff_trigger.action->fn(&on_poff_trigger);
-+	stop_run(&on_poff_trigger);
-+}
-+void (*_machine_power_off)(void) = do_machine_power_off;
-+
-+static void __init shutdown_triggers_init(void)
-+{
-+	shutdown_actions_kset = kset_create_and_add("shutdown_actions", NULL,
-+						    firmware_kobj);
-+	if (!shutdown_actions_kset)
-+		goto fail;
-+	if (sysfs_create_file(&shutdown_actions_kset->kobj,
-+			      &on_reboot_attr.attr))
-+		goto fail;
-+	if (sysfs_create_file(&shutdown_actions_kset->kobj,
-+			      &on_panic_attr.attr))
-+		goto fail;
-+	if (sysfs_create_file(&shutdown_actions_kset->kobj,
-+			      &on_halt_attr.attr))
-+		goto fail;
-+	if (sysfs_create_file(&shutdown_actions_kset->kobj,
-+			      &on_poff_attr.attr))
-+		goto fail;
-+
-+	return;
-+fail:
-+	panic("shutdown_triggers_init failed\n");
-+}
-+
-+static void __init shutdown_actions_init(void)
-+{
-+	int i;
-+
-+	for (i = 0; i < SHUTDOWN_ACTIONS_COUNT; i++) {
-+		if (!shutdown_actions_list[i]->init)
-+			continue;
-+		if (shutdown_actions_list[i]->init())
-+			shutdown_actions_list[i] = NULL;
-+	}
-+}
-+
-+static int __init s390_ipl_init(void)
-+{
- 	reipl_probe();
--	rc = ipl_init();
--	if (rc)
--		return rc;
--	rc = reipl_init();
--	if (rc)
--		return rc;
--	rc = dump_init();
--	if (rc)
--		return rc;
--	rc = shutdown_actions_init();
--	if (rc)
--		return rc;
-+	sclp_get_ipl_info(&sclp_ipl_info);
-+	shutdown_actions_init();
-+	shutdown_triggers_init();
- 	return 0;
- }
- 
- __initcall(s390_ipl_init);
- 
-+static void __init strncpy_skip_quote(char *dst, char *src, int n)
-+{
-+	int sx, dx;
-+
-+	dx = 0;
-+	for (sx = 0; src[sx] != 0; sx++) {
-+		if (src[sx] == '"')
-+			continue;
-+		dst[dx++] = src[sx];
-+		if (dx >= n)
-+			break;
-+	}
-+}
-+
-+static int __init vmcmd_on_reboot_setup(char *str)
-+{
-+	if (!MACHINE_IS_VM)
-+		return 1;
-+	strncpy_skip_quote(vmcmd_on_reboot, str, 127);
-+	vmcmd_on_reboot[127] = 0;
-+	on_reboot_trigger.action = &vmcmd_action;
-+	return 1;
-+}
-+__setup("vmreboot=", vmcmd_on_reboot_setup);
-+
-+static int __init vmcmd_on_panic_setup(char *str)
-+{
-+	if (!MACHINE_IS_VM)
-+		return 1;
-+	strncpy_skip_quote(vmcmd_on_panic, str, 127);
-+	vmcmd_on_panic[127] = 0;
-+	on_panic_trigger.action = &vmcmd_action;
-+	return 1;
-+}
-+__setup("vmpanic=", vmcmd_on_panic_setup);
-+
-+static int __init vmcmd_on_halt_setup(char *str)
-+{
-+	if (!MACHINE_IS_VM)
-+		return 1;
-+	strncpy_skip_quote(vmcmd_on_halt, str, 127);
-+	vmcmd_on_halt[127] = 0;
-+	on_halt_trigger.action = &vmcmd_action;
-+	return 1;
-+}
-+__setup("vmhalt=", vmcmd_on_halt_setup);
-+
-+static int __init vmcmd_on_poff_setup(char *str)
-+{
-+	if (!MACHINE_IS_VM)
-+		return 1;
-+	strncpy_skip_quote(vmcmd_on_poff, str, 127);
-+	vmcmd_on_poff[127] = 0;
-+	on_poff_trigger.action = &vmcmd_action;
-+	return 1;
-+}
-+__setup("vmpoff=", vmcmd_on_poff_setup);
-+
-+static int on_panic_notify(struct notifier_block *self,
-+			   unsigned long event, void *data)
-+{
-+	do_panic();
-+	return NOTIFY_OK;
-+}
-+
-+static struct notifier_block on_panic_nb = {
-+	.notifier_call = on_panic_notify,
-+	.priority = 0,
-+};
-+
-+void __init setup_ipl(void)
-+{
-+	ipl_info.type = get_ipl_type();
-+	switch (ipl_info.type) {
-+	case IPL_TYPE_CCW:
-+		ipl_info.data.ccw.dev_id.devno = ipl_devno;
-+		ipl_info.data.ccw.dev_id.ssid = 0;
-+		break;
-+	case IPL_TYPE_FCP:
-+	case IPL_TYPE_FCP_DUMP:
-+		ipl_info.data.fcp.dev_id.devno =
-+			IPL_PARMBLOCK_START->ipl_info.fcp.devno;
-+		ipl_info.data.fcp.dev_id.ssid = 0;
-+		ipl_info.data.fcp.wwpn = IPL_PARMBLOCK_START->ipl_info.fcp.wwpn;
-+		ipl_info.data.fcp.lun = IPL_PARMBLOCK_START->ipl_info.fcp.lun;
-+		break;
-+	case IPL_TYPE_NSS:
-+		strncpy(ipl_info.data.nss.name, kernel_nss_name,
-+			sizeof(ipl_info.data.nss.name));
-+		break;
-+	case IPL_TYPE_UNKNOWN:
-+	default:
-+		/* We have no info to copy */
-+		break;
-+	}
-+	atomic_notifier_chain_register(&panic_notifier_list, &on_panic_nb);
-+}
-+
- void __init ipl_save_parameters(void)
- {
- 	struct cio_iplinfo iplinfo;
-@@ -1185,3 +1475,4 @@ void s390_reset_system(void)
- 
- 	do_reset_calls();
- }
-+
-diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c
-index 29f7884..0e7aca0 100644
---- a/arch/s390/kernel/process.c
-+++ b/arch/s390/kernel/process.c
-@@ -36,7 +36,7 @@
- #include <linux/init.h>
- #include <linux/module.h>
- #include <linux/notifier.h>
+-#include <asm/mmu_context.h>
+-#include <asm/page.h>
+-#include <asm/pgalloc.h>
+-#include <asm/pgtable.h>
+-#include <asm/tlb.h>
+-
+-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
+-
+-/*
+- * Cache of MMU context last used.
+- */
+-unsigned long mmu_context_cache;
+-pgd_t * mmu_pdtp_cache;
+-int after_bootmem = 0;
+-
+-/*
+- * BAD_PAGE is the page that is used for page faults when linux
+- * is out-of-memory. Older versions of linux just did a
+- * do_exit(), but using this instead means there is less risk
+- * for a process dying in kernel mode, possibly leaving an inode
+- * unused etc..
+- *
+- * BAD_PAGETABLE is the accompanying page-table: it is initialized
+- * to point to BAD_PAGE entries.
+- *
+- * ZERO_PAGE is a special page that is used for zero-initialized
+- * data and COW.
+- */
+-
+-extern unsigned char empty_zero_page[PAGE_SIZE];
+-extern unsigned char empty_bad_page[PAGE_SIZE];
+-extern pte_t empty_bad_pte_table[PTRS_PER_PTE];
+-extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
+-
+-extern char _text, _etext, _edata, __bss_start, _end;
+-extern char __init_begin, __init_end;
+-
+-/* It'd be good if these lines were in the standard header file. */
+-#define START_PFN	(NODE_DATA(0)->bdata->node_boot_start >> PAGE_SHIFT)
+-#define MAX_LOW_PFN	(NODE_DATA(0)->bdata->node_low_pfn)
+-
+-
+-void show_mem(void)
+-{
+-	int i, total = 0, reserved = 0;
+-	int shared = 0, cached = 0;
+-
+-	printk("Mem-info:\n");
+-	show_free_areas();
+-	printk("Free swap:       %6ldkB\n",nr_swap_pages<<(PAGE_SHIFT-10));
+-	i = max_mapnr;
+-	while (i-- > 0) {
+-		total++;
+-		if (PageReserved(mem_map+i))
+-			reserved++;
+-		else if (PageSwapCache(mem_map+i))
+-			cached++;
+-		else if (page_count(mem_map+i))
+-			shared += page_count(mem_map+i) - 1;
+-	}
+-	printk("%d pages of RAM\n",total);
+-	printk("%d reserved pages\n",reserved);
+-	printk("%d pages shared\n",shared);
+-	printk("%d pages swap cached\n",cached);
+-	printk("%ld pages in page table cache\n", quicklist_total_size());
+-}
+-
+-/*
+- * paging_init() sets up the page tables.
+- *
+- * head.S already did a lot to set up address translation for the kernel.
+- * Here we comes with:
+- * . MMU enabled
+- * . ASID set (SR)
+- * .  some 512MB regions being mapped of which the most relevant here is:
+- *   . CACHED segment (ASID 0 [irrelevant], shared AND NOT user)
+- * . possible variable length regions being mapped as:
+- *   . UNCACHED segment (ASID 0 [irrelevant], shared AND NOT user)
+- * . All of the memory regions are placed, independently from the platform
+- *   on high addresses, above 0x80000000.
+- * . swapper_pg_dir is already cleared out by the .space directive
+- *   in any case swapper does not require a real page directory since
+- *   it's all kernel contained.
+- *
+- * Those pesky NULL-reference errors in the kernel are then
+- * dealt with by not mapping address 0x00000000 at all.
+- *
+- */
+-void __init paging_init(void)
+-{
+-	unsigned long zones_size[MAX_NR_ZONES] = {0, };
 -
-+#include <linux/utsname.h>
- #include <asm/uaccess.h>
- #include <asm/pgtable.h>
- #include <asm/system.h>
-@@ -182,13 +182,15 @@ void cpu_idle(void)
- 
- void show_regs(struct pt_regs *regs)
- {
--	struct task_struct *tsk = current;
+-	pgd_init((unsigned long)swapper_pg_dir);
+-	pgd_init((unsigned long)swapper_pg_dir +
+-		 sizeof(pgd_t) * USER_PTRS_PER_PGD);
 -
--        printk("CPU:    %d    %s\n", task_thread_info(tsk)->cpu, print_tainted());
--        printk("Process %s (pid: %d, task: %p, ksp: %p)\n",
--	       current->comm, task_pid_nr(current), (void *) tsk,
--	       (void *) tsk->thread.ksp);
+-	mmu_context_cache = MMU_CONTEXT_FIRST_VERSION;
 -
-+	print_modules();
-+	printk("CPU: %d %s %s %.*s\n",
-+	       task_thread_info(current)->cpu, print_tainted(),
-+	       init_utsname()->release,
-+	       (int)strcspn(init_utsname()->version, " "),
-+	       init_utsname()->version);
-+	printk("Process %s (pid: %d, task: %p, ksp: %p)\n",
-+	       current->comm, current->pid, current,
-+	       (void *) current->thread.ksp);
- 	show_registers(regs);
- 	/* Show stack backtrace if pt_regs is from kernel mode */
- 	if (!(regs->psw.mask & PSW_MASK_PSTATE))
-diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c
-index 1d81bf9..6e036ba 100644
---- a/arch/s390/kernel/ptrace.c
-+++ b/arch/s390/kernel/ptrace.c
-@@ -86,13 +86,13 @@ FixPerRegisters(struct task_struct *task)
- 		per_info->control_regs.bits.storage_alt_space_ctl = 0;
- }
- 
--static void set_single_step(struct task_struct *task)
-+void user_enable_single_step(struct task_struct *task)
- {
- 	task->thread.per_info.single_step = 1;
- 	FixPerRegisters(task);
- }
- 
--static void clear_single_step(struct task_struct *task)
-+void user_disable_single_step(struct task_struct *task)
- {
- 	task->thread.per_info.single_step = 0;
- 	FixPerRegisters(task);
-@@ -107,7 +107,7 @@ void
- ptrace_disable(struct task_struct *child)
- {
- 	/* make sure the single step bit is not set. */
--	clear_single_step(child);
-+	user_disable_single_step(child);
- }
- 
- #ifndef CONFIG_64BIT
-@@ -651,7 +651,7 @@ do_ptrace(struct task_struct *child, long request, long addr, long data)
- 			clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
- 		child->exit_code = data;
- 		/* make sure the single step bit is not set. */
--		clear_single_step(child);
-+		user_disable_single_step(child);
- 		wake_up_process(child);
- 		return 0;
- 
-@@ -665,7 +665,7 @@ do_ptrace(struct task_struct *child, long request, long addr, long data)
- 			return 0;
- 		child->exit_code = SIGKILL;
- 		/* make sure the single step bit is not set. */
--		clear_single_step(child);
-+		user_disable_single_step(child);
- 		wake_up_process(child);
- 		return 0;
- 
-@@ -675,10 +675,7 @@ do_ptrace(struct task_struct *child, long request, long addr, long data)
- 			return -EIO;
- 		clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
- 		child->exit_code = data;
--		if (data)
--			set_tsk_thread_flag(child, TIF_SINGLE_STEP);
--		else
--			set_single_step(child);
-+		user_enable_single_step(child);
- 		/* give it a chance to run. */
- 		wake_up_process(child);
- 		return 0;
-diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c
-index 577aa7d..766c783 100644
---- a/arch/s390/kernel/setup.c
-+++ b/arch/s390/kernel/setup.c
-@@ -126,75 +126,6 @@ void __cpuinit cpu_init(void)
- }
- 
- /*
-- * VM halt and poweroff setup routines
+-	zones_size[ZONE_NORMAL] = MAX_LOW_PFN - START_PFN;
+-	NODE_DATA(0)->node_mem_map = NULL;
+-	free_area_init_node(0, NODE_DATA(0), zones_size, __MEMORY_START >> PAGE_SHIFT, 0);
+-}
+-
+-void __init mem_init(void)
+-{
+-	int codesize, reservedpages, datasize, initsize;
+-	int tmp;
+-
+-	max_mapnr = num_physpages = MAX_LOW_PFN - START_PFN;
+-	high_memory = (void *)__va(MAX_LOW_PFN * PAGE_SIZE);
+-
+-	/*
+-         * Clear the zero-page.
+-         * This is not required but we might want to re-use
+-         * this very page to pass boot parameters, one day.
+-         */
+-	memset(empty_zero_page, 0, PAGE_SIZE);
+-
+-	/* this will put all low memory onto the freelists */
+-	totalram_pages += free_all_bootmem_node(NODE_DATA(0));
+-	reservedpages = 0;
+-	for (tmp = 0; tmp < num_physpages; tmp++)
+-		/*
+-		 * Only count reserved RAM pages
+-		 */
+-		if (PageReserved(mem_map+tmp))
+-			reservedpages++;
+-
+-	after_bootmem = 1;
+-
+-	codesize =  (unsigned long) &_etext - (unsigned long) &_text;
+-	datasize =  (unsigned long) &_edata - (unsigned long) &_etext;
+-	initsize =  (unsigned long) &__init_end - (unsigned long) &__init_begin;
+-
+-	printk("Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data, %dk init)\n",
+-		(unsigned long) nr_free_pages() << (PAGE_SHIFT-10),
+-		max_mapnr << (PAGE_SHIFT-10),
+-		codesize >> 10,
+-		reservedpages << (PAGE_SHIFT-10),
+-		datasize >> 10,
+-		initsize >> 10);
+-}
+-
+-void free_initmem(void)
+-{
+-	unsigned long addr;
+-
+-	addr = (unsigned long)(&__init_begin);
+-	for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) {
+-		ClearPageReserved(virt_to_page(addr));
+-		init_page_count(virt_to_page(addr));
+-		free_page(addr);
+-		totalram_pages++;
+-	}
+-	printk ("Freeing unused kernel memory: %ldk freed\n", (&__init_end - &__init_begin) >> 10);
+-}
+-
+-#ifdef CONFIG_BLK_DEV_INITRD
+-void free_initrd_mem(unsigned long start, unsigned long end)
+-{
+-	unsigned long p;
+-	for (p = start; p < end; p += PAGE_SIZE) {
+-		ClearPageReserved(virt_to_page(p));
+-		init_page_count(virt_to_page(p));
+-		free_page(p);
+-		totalram_pages++;
+-	}
+-	printk ("Freeing initrd memory: %ldk freed\n", (end - start) >> 10);
+-}
+-#endif
+-
+diff --git a/arch/sh64/mm/ioremap.c b/arch/sh64/mm/ioremap.c
+deleted file mode 100644
+index 535304e..0000000
+--- a/arch/sh64/mm/ioremap.c
++++ /dev/null
+@@ -1,388 +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.
+- *
+- * arch/sh64/mm/ioremap.c
+- *
+- * Copyright (C) 2000, 2001  Paolo Alberelli
+- * Copyright (C) 2003, 2004  Paul Mundt
+- *
+- * Mostly derived from arch/sh/mm/ioremap.c which, in turn is mostly
+- * derived from arch/i386/mm/ioremap.c .
+- *
+- *   (C) Copyright 1995 1996 Linus Torvalds
 - */
--char vmhalt_cmd[128] = "";
--char vmpoff_cmd[128] = "";
--static char vmpanic_cmd[128] = "";
+-#include <linux/kernel.h>
+-#include <linux/slab.h>
+-#include <linux/vmalloc.h>
+-#include <linux/sched.h>
+-#include <linux/string.h>
+-#include <linux/io.h>
+-#include <linux/ioport.h>
+-#include <linux/bootmem.h>
+-#include <linux/proc_fs.h>
+-#include <linux/module.h>
+-#include <asm/pgalloc.h>
+-#include <asm/tlbflush.h>
 -
--static void strncpy_skip_quote(char *dst, char *src, int n)
+-static void shmedia_mapioaddr(unsigned long, unsigned long);
+-static unsigned long shmedia_ioremap(struct resource *, u32, int);
+-
+-/*
+- * Generic mapping function (not visible outside):
+- */
+-
+-/*
+- * Remap an arbitrary physical address space into the kernel virtual
+- * address space. Needed when the kernel wants to access high addresses
+- * directly.
+- *
+- * NOTE! We need to allow non-page-aligned mappings too: we will obviously
+- * have to convert them into an offset in a page-aligned mapping, but the
+- * caller shouldn't need to know that small detail.
+- */
+-void * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flags)
 -{
--        int sx, dx;
+-	void * addr;
+-	struct vm_struct * area;
+-	unsigned long offset, last_addr;
+-	pgprot_t pgprot;
+-
+-	/* Don't allow wraparound or zero size */
+-	last_addr = phys_addr + size - 1;
+-	if (!size || last_addr < phys_addr)
+-		return NULL;
 -
--        dx = 0;
--        for (sx = 0; src[sx] != 0; sx++) {
--                if (src[sx] == '"') continue;
--                dst[dx++] = src[sx];
--                if (dx >= n) break;
+-	pgprot = __pgprot(_PAGE_PRESENT  | _PAGE_READ   |
+-			  _PAGE_WRITE    | _PAGE_DIRTY  |
+-			  _PAGE_ACCESSED | _PAGE_SHARED | flags);
+-
+-	/*
+-	 * Mappings have to be page-aligned
+-	 */
+-	offset = phys_addr & ~PAGE_MASK;
+-	phys_addr &= PAGE_MASK;
+-	size = PAGE_ALIGN(last_addr + 1) - phys_addr;
+-
+-	/*
+-	 * Ok, go for it..
+-	 */
+-	area = get_vm_area(size, VM_IOREMAP);
+-	pr_debug("Get vm_area returns %p addr %p\n",area,area->addr);
+-	if (!area)
+-		return NULL;
+-	area->phys_addr = phys_addr;
+-	addr = area->addr;
+-	if (ioremap_page_range((unsigned long)addr, (unsigned long)addr + size,
+-			       phys_addr, pgprot)) {
+-		vunmap(addr);
+-		return NULL;
+-	}
+-	return (void *) (offset + (char *)addr);
+-}
+-EXPORT_SYMBOL(__ioremap);
+-
+-void iounmap(void *addr)
+-{
+-	struct vm_struct *area;
+-
+-	vfree((void *) (PAGE_MASK & (unsigned long) addr));
+-	area = remove_vm_area((void *) (PAGE_MASK & (unsigned long) addr));
+-	if (!area) {
+-		printk(KERN_ERR "iounmap: bad address %p\n", addr);
+-		return;
+-	}
+-
+-	kfree(area);
+-}
+-EXPORT_SYMBOL(iounmap);
+-
+-static struct resource shmedia_iomap = {
+-	.name	= "shmedia_iomap",
+-	.start	= IOBASE_VADDR + PAGE_SIZE,
+-	.end	= IOBASE_END - 1,
+-};
+-
+-static void shmedia_mapioaddr(unsigned long pa, unsigned long va);
+-static void shmedia_unmapioaddr(unsigned long vaddr);
+-static unsigned long shmedia_ioremap(struct resource *res, u32 pa, int sz);
+-
+-/*
+- * We have the same problem as the SPARC, so lets have the same comment:
+- * Our mini-allocator...
+- * Boy this is gross! We need it because we must map I/O for
+- * timers and interrupt controller before the kmalloc is available.
+- */
+-
+-#define XNMLN  15
+-#define XNRES  10
+-
+-struct xresource {
+-	struct resource xres;   /* Must be first */
+-	int xflag;              /* 1 == used */
+-	char xname[XNMLN+1];
+-};
+-
+-static struct xresource xresv[XNRES];
+-
+-static struct xresource *xres_alloc(void)
+-{
+-        struct xresource *xrp;
+-        int n;
+-
+-        xrp = xresv;
+-        for (n = 0; n < XNRES; n++) {
+-                if (xrp->xflag == 0) {
+-                        xrp->xflag = 1;
+-                        return xrp;
+-                }
+-                xrp++;
 -        }
+-        return NULL;
 -}
 -
--static int __init vmhalt_setup(char *str)
+-static void xres_free(struct xresource *xrp)
 -{
--        strncpy_skip_quote(vmhalt_cmd, str, 127);
--        vmhalt_cmd[127] = 0;
--        return 1;
+-	xrp->xflag = 0;
 -}
 -
--__setup("vmhalt=", vmhalt_setup);
+-static struct resource *shmedia_find_resource(struct resource *root,
+-					      unsigned long vaddr)
+-{
+-	struct resource *res;
 -
--static int __init vmpoff_setup(char *str)
+-	for (res = root->child; res; res = res->sibling)
+-		if (res->start <= vaddr && res->end >= vaddr)
+-			return res;
+-
+-	return NULL;
+-}
+-
+-static unsigned long shmedia_alloc_io(unsigned long phys, unsigned long size,
+-				      const char *name)
 -{
--        strncpy_skip_quote(vmpoff_cmd, str, 127);
--        vmpoff_cmd[127] = 0;
--        return 1;
+-        static int printed_full = 0;
+-        struct xresource *xres;
+-        struct resource *res;
+-        char *tack;
+-        int tlen;
+-
+-        if (name == NULL) name = "???";
+-
+-        if ((xres = xres_alloc()) != 0) {
+-                tack = xres->xname;
+-                res = &xres->xres;
+-        } else {
+-                if (!printed_full) {
+-                        printk("%s: done with statics, switching to kmalloc\n",
+-			       __FUNCTION__);
+-                        printed_full = 1;
+-                }
+-                tlen = strlen(name);
+-                tack = kmalloc(sizeof (struct resource) + tlen + 1, GFP_KERNEL);
+-                if (!tack)
+-			return -ENOMEM;
+-                memset(tack, 0, sizeof(struct resource));
+-                res = (struct resource *) tack;
+-                tack += sizeof (struct resource);
+-        }
+-
+-        strncpy(tack, name, XNMLN);
+-        tack[XNMLN] = 0;
+-        res->name = tack;
+-
+-        return shmedia_ioremap(res, phys, size);
 -}
 -
--__setup("vmpoff=", vmpoff_setup);
+-static unsigned long shmedia_ioremap(struct resource *res, u32 pa, int sz)
+-{
+-        unsigned long offset = ((unsigned long) pa) & (~PAGE_MASK);
+-	unsigned long round_sz = (offset + sz + PAGE_SIZE-1) & PAGE_MASK;
+-        unsigned long va;
+-        unsigned int psz;
 -
--static int vmpanic_notify(struct notifier_block *self, unsigned long event,
--			  void *data)
+-        if (allocate_resource(&shmedia_iomap, res, round_sz,
+-			      shmedia_iomap.start, shmedia_iomap.end,
+-			      PAGE_SIZE, NULL, NULL) != 0) {
+-                panic("alloc_io_res(%s): cannot occupy\n",
+-                    (res->name != NULL)? res->name: "???");
+-        }
+-
+-        va = res->start;
+-        pa &= PAGE_MASK;
+-
+-	psz = (res->end - res->start + (PAGE_SIZE - 1)) / PAGE_SIZE;
+-
+-	/* log at boot time ... */
+-	printk("mapioaddr: %6s  [%2d page%s]  va 0x%08lx   pa 0x%08x\n",
+-	       ((res->name != NULL) ? res->name : "???"),
+-	       psz, psz == 1 ? " " : "s", va, pa);
+-
+-        for (psz = res->end - res->start + 1; psz != 0; psz -= PAGE_SIZE) {
+-                shmedia_mapioaddr(pa, va);
+-                va += PAGE_SIZE;
+-                pa += PAGE_SIZE;
+-        }
+-
+-        res->start += offset;
+-        res->end = res->start + sz - 1;         /* not strictly necessary.. */
+-
+-        return res->start;
+-}
+-
+-static void shmedia_free_io(struct resource *res)
 -{
--	if (MACHINE_IS_VM && strlen(vmpanic_cmd) > 0)
--		cpcmd(vmpanic_cmd, NULL, 0, NULL);
+-	unsigned long len = res->end - res->start + 1;
 -
--	return NOTIFY_OK;
+-	BUG_ON((len & (PAGE_SIZE - 1)) != 0);
+-
+-	while (len) {
+-		len -= PAGE_SIZE;
+-		shmedia_unmapioaddr(res->start + len);
+-	}
+-
+-	release_resource(res);
 -}
 -
--#define PANIC_PRI_VMPANIC	0
+-static __init_refok void *sh64_get_page(void)
+-{
+-	extern int after_bootmem;
+-	void *page;
 -
--static struct notifier_block vmpanic_nb = {
--	.notifier_call = vmpanic_notify,
--	.priority = PANIC_PRI_VMPANIC
--};
+-	if (after_bootmem) {
+-		page = (void *)get_zeroed_page(GFP_ATOMIC);
+-	} else {
+-		page = alloc_bootmem_pages(PAGE_SIZE);
+-	}
 -
--static int __init vmpanic_setup(char *str)
+-	if (!page || ((unsigned long)page & ~PAGE_MASK))
+-		panic("sh64_get_page: Out of memory already?\n");
+-
+-	return page;
+-}
+-
+-static void shmedia_mapioaddr(unsigned long pa, unsigned long va)
 -{
--	static int register_done __initdata = 0;
+-	pgd_t *pgdp;
+-	pmd_t *pmdp;
+-	pte_t *ptep, pte;
+-	pgprot_t prot;
+-	unsigned long flags = 1; /* 1 = CB0-1 device */
 -
--	strncpy_skip_quote(vmpanic_cmd, str, 127);
--	vmpanic_cmd[127] = 0;
--	if (!register_done) {
--		register_done = 1;
--		atomic_notifier_chain_register(&panic_notifier_list,
--					       &vmpanic_nb);
+-	pr_debug("shmedia_mapiopage pa %08lx va %08lx\n",  pa, va);
+-
+-	pgdp = pgd_offset_k(va);
+-	if (pgd_none(*pgdp) || !pgd_present(*pgdp)) {
+-		pmdp = (pmd_t *)sh64_get_page();
+-		set_pgd(pgdp, __pgd((unsigned long)pmdp | _KERNPG_TABLE));
 -	}
--	return 1;
+-
+-	pmdp = pmd_offset(pgdp, va);
+-	if (pmd_none(*pmdp) || !pmd_present(*pmdp) ) {
+-		ptep = (pte_t *)sh64_get_page();
+-		set_pmd(pmdp, __pmd((unsigned long)ptep + _PAGE_TABLE));
+-	}
+-
+-	prot = __pgprot(_PAGE_PRESENT | _PAGE_READ     | _PAGE_WRITE  |
+-			_PAGE_DIRTY   | _PAGE_ACCESSED | _PAGE_SHARED | flags);
+-
+-	pte = pfn_pte(pa >> PAGE_SHIFT, prot);
+-	ptep = pte_offset_kernel(pmdp, va);
+-
+-	if (!pte_none(*ptep) &&
+-	    pte_val(*ptep) != pte_val(pte))
+-		pte_ERROR(*ptep);
+-
+-	set_pte(ptep, pte);
+-
+-	flush_tlb_kernel_range(va, PAGE_SIZE);
 -}
 -
--__setup("vmpanic=", vmpanic_setup);
+-static void shmedia_unmapioaddr(unsigned long vaddr)
+-{
+-	pgd_t *pgdp;
+-	pmd_t *pmdp;
+-	pte_t *ptep;
 -
--/*
-  * condev= and conmode= setup parameter.
-  */
- 
-@@ -308,38 +239,6 @@ static void __init setup_zfcpdump(unsigned int console_devno)
- static inline void setup_zfcpdump(unsigned int console_devno) {}
- #endif /* CONFIG_ZFCPDUMP */
- 
--#ifdef CONFIG_SMP
--void (*_machine_restart)(char *command) = machine_restart_smp;
--void (*_machine_halt)(void) = machine_halt_smp;
--void (*_machine_power_off)(void) = machine_power_off_smp;
--#else
--/*
-- * Reboot, halt and power_off routines for non SMP.
-- */
--static void do_machine_restart_nonsmp(char * __unused)
+-	pgdp = pgd_offset_k(vaddr);
+-	pmdp = pmd_offset(pgdp, vaddr);
+-
+-	if (pmd_none(*pmdp) || pmd_bad(*pmdp))
+-		return;
+-
+-	ptep = pte_offset_kernel(pmdp, vaddr);
+-
+-	if (pte_none(*ptep) || !pte_present(*ptep))
+-		return;
+-
+-	clear_page((void *)ptep);
+-	pte_clear(&init_mm, vaddr, ptep);
+-}
+-
+-unsigned long onchip_remap(unsigned long phys, unsigned long size, const char *name)
 -{
--	do_reipl();
+-	if (size < PAGE_SIZE)
+-		size = PAGE_SIZE;
+-
+-	return shmedia_alloc_io(phys, size, name);
 -}
 -
--static void do_machine_halt_nonsmp(void)
+-void onchip_unmap(unsigned long vaddr)
 -{
--        if (MACHINE_IS_VM && strlen(vmhalt_cmd) > 0)
--		__cpcmd(vmhalt_cmd, NULL, 0, NULL);
--        signal_processor(smp_processor_id(), sigp_stop_and_store_status);
+-	struct resource *res;
+-	unsigned int psz;
+-
+-	res = shmedia_find_resource(&shmedia_iomap, vaddr);
+-	if (!res) {
+-		printk(KERN_ERR "%s: Failed to free 0x%08lx\n",
+-		       __FUNCTION__, vaddr);
+-		return;
+-	}
+-
+-        psz = (res->end - res->start + (PAGE_SIZE - 1)) / PAGE_SIZE;
+-
+-        printk(KERN_DEBUG "unmapioaddr: %6s  [%2d page%s] freed\n",
+-	       res->name, psz, psz == 1 ? " " : "s");
+-
+-	shmedia_free_io(res);
+-
+-	if ((char *)res >= (char *)xresv &&
+-	    (char *)res <  (char *)&xresv[XNRES]) {
+-		xres_free((struct xresource *)res);
+-	} else {
+-		kfree(res);
+-	}
 -}
 -
--static void do_machine_power_off_nonsmp(void)
+-#ifdef CONFIG_PROC_FS
+-static int
+-ioremap_proc_info(char *buf, char **start, off_t fpos, int length, int *eof,
+-		  void *data)
 -{
--        if (MACHINE_IS_VM && strlen(vmpoff_cmd) > 0)
--		__cpcmd(vmpoff_cmd, NULL, 0, NULL);
--        signal_processor(smp_processor_id(), sigp_stop_and_store_status);
+-	char *p = buf, *e = buf + length;
+-	struct resource *r;
+-	const char *nm;
+-
+-	for (r = ((struct resource *)data)->child; r != NULL; r = r->sibling) {
+-		if (p + 32 >= e)        /* Better than nothing */
+-			break;
+-		if ((nm = r->name) == 0) nm = "???";
+-		p += sprintf(p, "%08lx-%08lx: %s\n",
+-			     (unsigned long)r->start,
+-			     (unsigned long)r->end, nm);
+-	}
+-
+-	return p-buf;
 -}
+-#endif /* CONFIG_PROC_FS */
 -
--void (*_machine_restart)(char *command) = do_machine_restart_nonsmp;
--void (*_machine_halt)(void) = do_machine_halt_nonsmp;
--void (*_machine_power_off)(void) = do_machine_power_off_nonsmp;
+-static int __init register_proc_onchip(void)
+-{
+-#ifdef CONFIG_PROC_FS
+-	create_proc_read_entry("io_map",0,0, ioremap_proc_info, &shmedia_iomap);
 -#endif
+-	return 0;
+-}
 -
-  /*
-  * Reboot, halt and power_off stubs. They just call _machine_restart,
-  * _machine_halt or _machine_power_off. 
-@@ -559,7 +458,9 @@ setup_resources(void)
- 	data_resource.start = (unsigned long) &_etext;
- 	data_resource.end = (unsigned long) &_edata - 1;
- 
--	for (i = 0; i < MEMORY_CHUNKS && memory_chunk[i].size > 0; i++) {
-+	for (i = 0; i < MEMORY_CHUNKS; i++) {
-+		if (!memory_chunk[i].size)
-+			continue;
- 		res = alloc_bootmem_low(sizeof(struct resource));
- 		res->flags = IORESOURCE_BUSY | IORESOURCE_MEM;
- 		switch (memory_chunk[i].type) {
-@@ -617,7 +518,7 @@ EXPORT_SYMBOL_GPL(real_memory_size);
- static void __init setup_memory_end(void)
- {
- 	unsigned long memory_size;
--	unsigned long max_mem, max_phys;
-+	unsigned long max_mem;
- 	int i;
- 
- #if defined(CONFIG_ZFCPDUMP) || defined(CONFIG_ZFCPDUMP_MODULE)
-@@ -625,10 +526,31 @@ static void __init setup_memory_end(void)
- 		memory_end = ZFCPDUMP_HSA_SIZE;
- #endif
- 	memory_size = 0;
--	max_phys = VMALLOC_END_INIT - VMALLOC_MIN_SIZE;
- 	memory_end &= PAGE_MASK;
- 
--	max_mem = memory_end ? min(max_phys, memory_end) : max_phys;
-+	max_mem = memory_end ? min(VMALLOC_START, memory_end) : VMALLOC_START;
-+	memory_end = min(max_mem, memory_end);
-+
-+	/*
-+	 * Make sure all chunks are MAX_ORDER aligned so we don't need the
-+	 * extra checks that HOLES_IN_ZONE would require.
-+	 */
-+	for (i = 0; i < MEMORY_CHUNKS; i++) {
-+		unsigned long start, end;
-+		struct mem_chunk *chunk;
-+		unsigned long align;
-+
-+		chunk = &memory_chunk[i];
-+		align = 1UL << (MAX_ORDER + PAGE_SHIFT - 1);
-+		start = (chunk->addr + align - 1) & ~(align - 1);
-+		end = (chunk->addr + chunk->size) & ~(align - 1);
-+		if (start >= end)
-+			memset(chunk, 0, sizeof(*chunk));
-+		else {
-+			chunk->addr = start;
-+			chunk->size = end - start;
-+		}
-+	}
- 
- 	for (i = 0; i < MEMORY_CHUNKS; i++) {
- 		struct mem_chunk *chunk = &memory_chunk[i];
-@@ -890,7 +812,7 @@ setup_arch(char **cmdline_p)
- 
- 	parse_early_param();
- 
--	setup_ipl_info();
-+	setup_ipl();
- 	setup_memory_end();
- 	setup_addressing_mode();
- 	setup_memory();
-@@ -899,7 +821,6 @@ setup_arch(char **cmdline_p)
- 
-         cpu_init();
-         __cpu_logical_map[0] = S390_lowcore.cpu_data.cpu_addr;
--	smp_setup_cpu_possible_map();
- 
- 	/*
- 	 * Setup capabilities (ELF_HWCAP & ELF_PLATFORM).
-@@ -920,7 +841,7 @@ setup_arch(char **cmdline_p)
- 
- void __cpuinit print_cpu_info(struct cpuinfo_S390 *cpuinfo)
- {
--   printk("cpu %d "
-+   printk(KERN_INFO "cpu %d "
- #ifdef CONFIG_SMP
-            "phys_idx=%d "
- #endif
-@@ -996,7 +917,7 @@ static void *c_next(struct seq_file *m, void *v, loff_t *pos)
- static void c_stop(struct seq_file *m, void *v)
- {
- }
--struct seq_operations cpuinfo_op = {
-+const struct seq_operations cpuinfo_op = {
- 	.start	= c_start,
- 	.next	= c_next,
- 	.stop	= c_stop,
-diff --git a/arch/s390/kernel/signal.c b/arch/s390/kernel/signal.c
-index d264671..4449bf3 100644
---- a/arch/s390/kernel/signal.c
-+++ b/arch/s390/kernel/signal.c
-@@ -471,6 +471,7 @@ void do_signal(struct pt_regs *regs)
- 
- 	if (signr > 0) {
- 		/* Whee!  Actually deliver the signal.  */
-+		int ret;
- #ifdef CONFIG_COMPAT
- 		if (test_thread_flag(TIF_31BIT)) {
- 			extern int handle_signal32(unsigned long sig,
-@@ -478,15 +479,12 @@ void do_signal(struct pt_regs *regs)
- 						   siginfo_t *info,
- 						   sigset_t *oldset,
- 						   struct pt_regs *regs);
--			if (handle_signal32(
--				    signr, &ka, &info, oldset, regs) == 0) {
--				if (test_thread_flag(TIF_RESTORE_SIGMASK))
--					clear_thread_flag(TIF_RESTORE_SIGMASK);
--			}
--			return;
-+			ret = handle_signal32(signr, &ka, &info, oldset, regs);
- 	        }
-+		else
- #endif
--		if (handle_signal(signr, &ka, &info, oldset, regs) == 0) {
-+			ret = handle_signal(signr, &ka, &info, oldset, regs);
-+		if (!ret) {
- 			/*
- 			 * A signal was successfully delivered; the saved
- 			 * sigmask will have been stored in the signal frame,
-@@ -495,6 +493,14 @@ void do_signal(struct pt_regs *regs)
- 			 */
- 			if (test_thread_flag(TIF_RESTORE_SIGMASK))
- 				clear_thread_flag(TIF_RESTORE_SIGMASK);
-+
-+			/*
-+			 * If we would have taken a single-step trap
-+			 * for a normal instruction, act like we took
-+			 * one for the handler setup.
-+			 */
-+			if (current->thread.per_info.single_step)
-+				set_thread_flag(TIF_SINGLE_STEP);
- 		}
- 		return;
- 	}
-diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c
-index 264ea90..aa37fa1 100644
---- a/arch/s390/kernel/smp.c
-+++ b/arch/s390/kernel/smp.c
-@@ -42,6 +42,7 @@
- #include <asm/tlbflush.h>
- #include <asm/timer.h>
- #include <asm/lowcore.h>
-+#include <asm/sclp.h>
- #include <asm/cpu.h>
- 
- /*
-@@ -53,11 +54,27 @@ EXPORT_SYMBOL(lowcore_ptr);
- cpumask_t cpu_online_map = CPU_MASK_NONE;
- EXPORT_SYMBOL(cpu_online_map);
- 
--cpumask_t cpu_possible_map = CPU_MASK_NONE;
-+cpumask_t cpu_possible_map = CPU_MASK_ALL;
- EXPORT_SYMBOL(cpu_possible_map);
- 
- static struct task_struct *current_set[NR_CPUS];
- 
-+static u8 smp_cpu_type;
-+static int smp_use_sigp_detection;
-+
-+enum s390_cpu_state {
-+	CPU_STATE_STANDBY,
-+	CPU_STATE_CONFIGURED,
-+};
-+
-+#ifdef CONFIG_HOTPLUG_CPU
-+static DEFINE_MUTEX(smp_cpu_state_mutex);
-+#endif
-+static int smp_cpu_state[NR_CPUS];
-+
-+static DEFINE_PER_CPU(struct cpu, cpu_devices);
-+DEFINE_PER_CPU(struct s390_idle_data, s390_idle);
-+
- static void smp_ext_bitcall(int, ec_bit_sig);
- 
- /*
-@@ -193,6 +210,33 @@ int smp_call_function_single(int cpu, void (*func) (void *info), void *info,
- }
- EXPORT_SYMBOL(smp_call_function_single);
- 
-+/**
-+ * smp_call_function_mask(): Run a function on a set of other CPUs.
-+ * @mask: The set of cpus to run on.  Must not include the current cpu.
-+ * @func: The function to run. This must be fast and non-blocking.
-+ * @info: An arbitrary pointer to pass to the function.
-+ * @wait: If true, wait (atomically) until function has completed on other CPUs.
-+ *
-+ * Returns 0 on success, else a negative status code.
-+ *
-+ * If @wait is true, then returns once @func has returned; otherwise
-+ * it returns just before the target cpu calls @func.
-+ *
-+ * You must not call this function with disabled interrupts or from a
-+ * hardware interrupt handler or from a bottom half handler.
-+ */
-+int
-+smp_call_function_mask(cpumask_t mask,
-+			void (*func)(void *), void *info,
-+			int wait)
-+{
-+	preempt_disable();
-+	__smp_call_function_map(func, info, 0, wait, mask);
-+	preempt_enable();
-+	return 0;
-+}
-+EXPORT_SYMBOL(smp_call_function_mask);
-+
- void smp_send_stop(void)
- {
- 	int cpu, rc;
-@@ -217,33 +261,6 @@ void smp_send_stop(void)
- }
- 
- /*
-- * Reboot, halt and power_off routines for SMP.
+-__initcall(register_proc_onchip);
+diff --git a/arch/sh64/mm/tlb.c b/arch/sh64/mm/tlb.c
+deleted file mode 100644
+index d517e7d..0000000
+--- a/arch/sh64/mm/tlb.c
++++ /dev/null
+@@ -1,166 +0,0 @@
+-/*
+- * arch/sh64/mm/tlb.c
+- *
+- * Copyright (C) 2003  Paul Mundt <lethal at linux-sh.org>
+- * Copyright (C) 2003  Richard Curnow <richard.curnow at superh.com>
+- *
+- * This file is subject to the terms and conditions of the GNU General Public
+- * License.  See the file "COPYING" in the main directory of this archive
+- * for more details.
+- *
 - */
--void machine_restart_smp(char *__unused)
+-#include <linux/mm.h>
+-#include <linux/init.h>
+-#include <asm/page.h>
+-#include <asm/tlb.h>
+-#include <asm/mmu_context.h>
+-
+-/**
+- * sh64_tlb_init
+- *
+- * Perform initial setup for the DTLB and ITLB.
+- */
+-int __init sh64_tlb_init(void)
 -{
--	smp_send_stop();
--	do_reipl();
+-	/* Assign some sane DTLB defaults */
+-	cpu_data->dtlb.entries	= 64;
+-	cpu_data->dtlb.step	= 0x10;
+-
+-	cpu_data->dtlb.first	= DTLB_FIXED | cpu_data->dtlb.step;
+-	cpu_data->dtlb.next	= cpu_data->dtlb.first;
+-
+-	cpu_data->dtlb.last	= DTLB_FIXED |
+-				  ((cpu_data->dtlb.entries - 1) *
+-				   cpu_data->dtlb.step);
+-
+-	/* And again for the ITLB */
+-	cpu_data->itlb.entries	= 64;
+-	cpu_data->itlb.step	= 0x10;
+-
+-	cpu_data->itlb.first	= ITLB_FIXED | cpu_data->itlb.step;
+-	cpu_data->itlb.next	= cpu_data->itlb.first;
+-	cpu_data->itlb.last	= ITLB_FIXED |
+-				  ((cpu_data->itlb.entries - 1) *
+-				   cpu_data->itlb.step);
+-
+-	return 0;
 -}
 -
--void machine_halt_smp(void)
+-/**
+- * sh64_next_free_dtlb_entry
+- *
+- * Find the next available DTLB entry
+- */
+-unsigned long long sh64_next_free_dtlb_entry(void)
 -{
--	smp_send_stop();
--	if (MACHINE_IS_VM && strlen(vmhalt_cmd) > 0)
--		__cpcmd(vmhalt_cmd, NULL, 0, NULL);
--	signal_processor(smp_processor_id(), sigp_stop_and_store_status);
--	for (;;);
+-	return cpu_data->dtlb.next;
 -}
 -
--void machine_power_off_smp(void)
+-/**
+- * sh64_get_wired_dtlb_entry
+- *
+- * Allocate a wired (locked-in) entry in the DTLB
+- */
+-unsigned long long sh64_get_wired_dtlb_entry(void)
 -{
--	smp_send_stop();
--	if (MACHINE_IS_VM && strlen(vmpoff_cmd) > 0)
--		__cpcmd(vmpoff_cmd, NULL, 0, NULL);
--	signal_processor(smp_processor_id(), sigp_stop_and_store_status);
--	for (;;);
+-	unsigned long long entry = sh64_next_free_dtlb_entry();
+-
+-	cpu_data->dtlb.first += cpu_data->dtlb.step;
+-	cpu_data->dtlb.next  += cpu_data->dtlb.step;
+-
+-	return entry;
 -}
 -
+-/**
+- * sh64_put_wired_dtlb_entry
+- *
+- * @entry:	Address of TLB slot.
+- *
+- * Free a wired (locked-in) entry in the DTLB.
+- *
+- * Works like a stack, last one to allocate must be first one to free.
+- */
+-int sh64_put_wired_dtlb_entry(unsigned long long entry)
+-{
+-	__flush_tlb_slot(entry);
+-
+-	/*
+-	 * We don't do any particularly useful tracking of wired entries,
+-	 * so this approach works like a stack .. last one to be allocated
+-	 * has to be the first one to be freed.
+-	 *
+-	 * We could potentially load wired entries into a list and work on
+-	 * rebalancing the list periodically (which also entails moving the
+-	 * contents of a TLB entry) .. though I have a feeling that this is
+-	 * more trouble than it's worth.
+-	 */
+-
+-	/*
+-	 * Entry must be valid .. we don't want any ITLB addresses!
+-	 */
+-	if (entry <= DTLB_FIXED)
+-		return -EINVAL;
+-
+-	/*
+-	 * Next, check if we're within range to be freed. (ie, must be the
+-	 * entry beneath the first 'free' entry!
+-	 */
+-	if (entry < (cpu_data->dtlb.first - cpu_data->dtlb.step))
+-		return -EINVAL;
+-
+-	/* If we are, then bring this entry back into the list */
+-	cpu_data->dtlb.first	-= cpu_data->dtlb.step;
+-	cpu_data->dtlb.next	= entry;
+-
+-	return 0;
+-}
+-
+-/**
+- * sh64_setup_tlb_slot
+- *
+- * @config_addr:	Address of TLB slot.
+- * @eaddr:		Virtual address.
+- * @asid:		Address Space Identifier.
+- * @paddr:		Physical address.
+- *
+- * Load up a virtual<->physical translation for @eaddr<->@paddr in the
+- * pre-allocated TLB slot @config_addr (see sh64_get_wired_dtlb_entry).
+- */
+-inline void sh64_setup_tlb_slot(unsigned long long config_addr,
+-				unsigned long eaddr,
+-				unsigned long asid,
+-				unsigned long paddr)
+-{
+-	unsigned long long pteh, ptel;
+-
+-	/* Sign extension */
+-#if (NEFF == 32)
+-	pteh = (unsigned long long)(signed long long)(signed long) eaddr;
+-#else
+-#error "Can't sign extend more than 32 bits yet"
+-#endif
+-	pteh &= PAGE_MASK;
+-	pteh |= (asid << PTEH_ASID_SHIFT) | PTEH_VALID;
+-#if (NEFF == 32)
+-	ptel = (unsigned long long)(signed long long)(signed long) paddr;
+-#else
+-#error "Can't sign extend more than 32 bits yet"
+-#endif
+-	ptel &= PAGE_MASK;
+-	ptel |= (_PAGE_CACHABLE | _PAGE_READ | _PAGE_WRITE);
+-
+-	asm volatile("putcfg %0, 1, %1\n\t"
+-			"putcfg %0, 0, %2\n"
+-			: : "r" (config_addr), "r" (ptel), "r" (pteh));
+-}
+-
+-/**
+- * sh64_teardown_tlb_slot
+- *
+- * @config_addr:	Address of TLB slot.
+- *
+- * Teardown any existing mapping in the TLB slot @config_addr.
+- */
+-inline void sh64_teardown_tlb_slot(unsigned long long config_addr)
+-	__attribute__ ((alias("__flush_tlb_slot")));
+-
+diff --git a/arch/sh64/mm/tlbmiss.c b/arch/sh64/mm/tlbmiss.c
+deleted file mode 100644
+index b767d6c..0000000
+--- a/arch/sh64/mm/tlbmiss.c
++++ /dev/null
+@@ -1,279 +0,0 @@
 -/*
-  * This is the main routine where commands issued by other
-  * cpus are handled.
-  */
-@@ -355,6 +372,13 @@ void smp_ctl_clear_bit(int cr, int bit)
- }
- EXPORT_SYMBOL(smp_ctl_clear_bit);
- 
-+/*
-+ * In early ipl state a temp. logically cpu number is needed, so the sigp
-+ * functions can be used to sense other cpus. Since NR_CPUS is >= 2 on
-+ * CONFIG_SMP and the ipl cpu is logical cpu 0, it must be 1.
-+ */
-+#define CPU_INIT_NO	1
-+
- #if defined(CONFIG_ZFCPDUMP) || defined(CONFIG_ZFCPDUMP_MODULE)
- 
- /*
-@@ -375,9 +399,10 @@ static void __init smp_get_save_area(unsigned int cpu, unsigned int phy_cpu)
- 		       "kernel was compiled with NR_CPUS=%i\n", cpu, NR_CPUS);
- 		return;
- 	}
--	zfcpdump_save_areas[cpu] = alloc_bootmem(sizeof(union save_area));
--	__cpu_logical_map[1] = (__u16) phy_cpu;
--	while (signal_processor(1, sigp_stop_and_store_status) == sigp_busy)
-+	zfcpdump_save_areas[cpu] = kmalloc(sizeof(union save_area), GFP_KERNEL);
-+	__cpu_logical_map[CPU_INIT_NO] = (__u16) phy_cpu;
-+	while (signal_processor(CPU_INIT_NO, sigp_stop_and_store_status) ==
-+	       sigp_busy)
- 		cpu_relax();
- 	memcpy(zfcpdump_save_areas[cpu],
- 	       (void *)(unsigned long) store_prefix() + SAVE_AREA_BASE,
-@@ -397,32 +422,155 @@ static inline void smp_get_save_area(unsigned int cpu, unsigned int phy_cpu) { }
- 
- #endif /* CONFIG_ZFCPDUMP || CONFIG_ZFCPDUMP_MODULE */
- 
--/*
-- * Lets check how many CPUs we have.
+- * 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.
+- *
+- * arch/sh64/mm/tlbmiss.c
+- *
+- * Original code from fault.c
+- * Copyright (C) 2000, 2001  Paolo Alberelli
+- *
+- * Fast PTE->TLB refill path
+- * Copyright (C) 2003 Richard.Curnow at superh.com
+- *
+- * IMPORTANT NOTES :
+- * The do_fast_page_fault function is called from a context in entry.S where very few registers
+- * have been saved.  In particular, the code in this file must be compiled not to use ANY
+- * caller-save registers that are not part of the restricted save set.  Also, it means that
+- * code in this file must not make calls to functions elsewhere in the kernel, or else the
+- * excepting context will see corruption in its caller-save registers.  Plus, the entry.S save
+- * area is non-reentrant, so this code has to run with SR.BL==1, i.e. no interrupts taken inside
+- * it and panic on any exception.
+- *
 - */
--static unsigned int __init smp_count_cpus(void)
-+static int cpu_stopped(int cpu)
- {
--	unsigned int cpu, num_cpus;
--	__u16 boot_cpu_addr;
-+	__u32 status;
- 
+-
+-#include <linux/signal.h>
+-#include <linux/sched.h>
+-#include <linux/kernel.h>
+-#include <linux/errno.h>
+-#include <linux/string.h>
+-#include <linux/types.h>
+-#include <linux/ptrace.h>
+-#include <linux/mman.h>
+-#include <linux/mm.h>
+-#include <linux/smp.h>
+-#include <linux/interrupt.h>
+-
+-#include <asm/system.h>
+-#include <asm/tlb.h>
+-#include <asm/io.h>
+-#include <asm/uaccess.h>
+-#include <asm/pgalloc.h>
+-#include <asm/mmu_context.h>
+-#include <asm/registers.h>		/* required by inline asm statements */
+-
+-/* Callable from fault.c, so not static */
+-inline void __do_tlb_refill(unsigned long address,
+-                            unsigned long long is_text_not_data, pte_t *pte)
+-{
+-	unsigned long long ptel;
+-	unsigned long long pteh=0;
+-	struct tlb_info *tlbp;
+-	unsigned long long next;
+-
+-	/* Get PTEL first */
+-	ptel = pte_val(*pte);
+-
 -	/*
--	 * cpu 0 is the boot cpu. See smp_prepare_boot_cpu.
+-	 * Set PTEH register
 -	 */
-+	/* Check for stopped state */
-+	if (signal_processor_ps(&status, 0, cpu, sigp_sense) ==
-+	    sigp_status_stored) {
-+		if (status & 0x40)
-+			return 1;
-+	}
-+	return 0;
-+}
-+
-+static int cpu_known(int cpu_id)
-+{
-+	int cpu;
-+
-+	for_each_present_cpu(cpu) {
-+		if (__cpu_logical_map[cpu] == cpu_id)
-+			return 1;
-+	}
-+	return 0;
-+}
-+
-+static int smp_rescan_cpus_sigp(cpumask_t avail)
-+{
-+	int cpu_id, logical_cpu;
-+
-+	logical_cpu = first_cpu(avail);
-+	if (logical_cpu == NR_CPUS)
-+		return 0;
-+	for (cpu_id = 0; cpu_id <= 65535; cpu_id++) {
-+		if (cpu_known(cpu_id))
-+			continue;
-+		__cpu_logical_map[logical_cpu] = cpu_id;
-+		if (!cpu_stopped(logical_cpu))
-+			continue;
-+		cpu_set(logical_cpu, cpu_present_map);
-+		smp_cpu_state[logical_cpu] = CPU_STATE_CONFIGURED;
-+		logical_cpu = next_cpu(logical_cpu, avail);
-+		if (logical_cpu == NR_CPUS)
-+			break;
-+	}
-+	return 0;
-+}
-+
-+static int smp_rescan_cpus_sclp(cpumask_t avail)
-+{
-+	struct sclp_cpu_info *info;
-+	int cpu_id, logical_cpu, cpu;
-+	int rc;
-+
-+	logical_cpu = first_cpu(avail);
-+	if (logical_cpu == NR_CPUS)
-+		return 0;
-+	info = kmalloc(sizeof(*info), GFP_KERNEL);
-+	if (!info)
-+		return -ENOMEM;
-+	rc = sclp_get_cpu_info(info);
-+	if (rc)
-+		goto out;
-+	for (cpu = 0; cpu < info->combined; cpu++) {
-+		if (info->has_cpu_type && info->cpu[cpu].type != smp_cpu_type)
-+			continue;
-+		cpu_id = info->cpu[cpu].address;
-+		if (cpu_known(cpu_id))
-+			continue;
-+		__cpu_logical_map[logical_cpu] = cpu_id;
-+		cpu_set(logical_cpu, cpu_present_map);
-+		if (cpu >= info->configured)
-+			smp_cpu_state[logical_cpu] = CPU_STATE_STANDBY;
-+		else
-+			smp_cpu_state[logical_cpu] = CPU_STATE_CONFIGURED;
-+		logical_cpu = next_cpu(logical_cpu, avail);
-+		if (logical_cpu == NR_CPUS)
-+			break;
-+	}
-+out:
-+	kfree(info);
-+	return rc;
-+}
-+
-+static int smp_rescan_cpus(void)
-+{
-+	cpumask_t avail;
-+
-+	cpus_xor(avail, cpu_possible_map, cpu_present_map);
-+	if (smp_use_sigp_detection)
-+		return smp_rescan_cpus_sigp(avail);
-+	else
-+		return smp_rescan_cpus_sclp(avail);
-+}
-+
-+static void __init smp_detect_cpus(void)
-+{
-+	unsigned int cpu, c_cpus, s_cpus;
-+	struct sclp_cpu_info *info;
-+	u16 boot_cpu_addr, cpu_addr;
-+
-+	c_cpus = 1;
-+	s_cpus = 0;
- 	boot_cpu_addr = S390_lowcore.cpu_data.cpu_addr;
--	current_thread_info()->cpu = 0;
--	num_cpus = 1;
--	for (cpu = 0; cpu <= 65535; cpu++) {
--		if ((__u16) cpu == boot_cpu_addr)
-+	info = kmalloc(sizeof(*info), GFP_KERNEL);
-+	if (!info)
-+		panic("smp_detect_cpus failed to allocate memory\n");
-+	/* Use sigp detection algorithm if sclp doesn't work. */
-+	if (sclp_get_cpu_info(info)) {
-+		smp_use_sigp_detection = 1;
-+		for (cpu = 0; cpu <= 65535; cpu++) {
-+			if (cpu == boot_cpu_addr)
-+				continue;
-+			__cpu_logical_map[CPU_INIT_NO] = cpu;
-+			if (!cpu_stopped(CPU_INIT_NO))
-+				continue;
-+			smp_get_save_area(c_cpus, cpu);
-+			c_cpus++;
-+		}
-+		goto out;
-+	}
-+
-+	if (info->has_cpu_type) {
-+		for (cpu = 0; cpu < info->combined; cpu++) {
-+			if (info->cpu[cpu].address == boot_cpu_addr) {
-+				smp_cpu_type = info->cpu[cpu].type;
-+				break;
-+			}
-+		}
-+	}
-+
-+	for (cpu = 0; cpu < info->combined; cpu++) {
-+		if (info->has_cpu_type && info->cpu[cpu].type != smp_cpu_type)
-+			continue;
-+		cpu_addr = info->cpu[cpu].address;
-+		if (cpu_addr == boot_cpu_addr)
- 			continue;
--		__cpu_logical_map[1] = (__u16) cpu;
--		if (signal_processor(1, sigp_sense) == sigp_not_operational)
-+		__cpu_logical_map[CPU_INIT_NO] = cpu_addr;
-+		if (!cpu_stopped(CPU_INIT_NO)) {
-+			s_cpus++;
- 			continue;
--		smp_get_save_area(num_cpus, cpu);
--		num_cpus++;
-+		}
-+		smp_get_save_area(c_cpus, cpu_addr);
-+		c_cpus++;
- 	}
--	printk("Detected %d CPU's\n", (int) num_cpus);
--	printk("Boot cpu address %2X\n", boot_cpu_addr);
--	return num_cpus;
-+out:
-+	kfree(info);
-+	printk(KERN_INFO "CPUs: %d configured, %d standby\n", c_cpus, s_cpus);
-+	get_online_cpus();
-+	smp_rescan_cpus();
-+	put_online_cpus();
- }
- 
- /*
-@@ -453,8 +601,6 @@ int __cpuinit start_secondary(void *cpuvoid)
- 	return 0;
- }
- 
--DEFINE_PER_CPU(struct s390_idle_data, s390_idle);
+-	pteh = address & MMU_VPN_MASK;
 -
- static void __init smp_create_idle(unsigned int cpu)
- {
- 	struct task_struct *p;
-@@ -470,37 +616,82 @@ static void __init smp_create_idle(unsigned int cpu)
- 	spin_lock_init(&(&per_cpu(s390_idle, cpu))->lock);
- }
- 
--static int cpu_stopped(int cpu)
-+static int __cpuinit smp_alloc_lowcore(int cpu)
- {
--	__u32 status;
-+	unsigned long async_stack, panic_stack;
-+	struct _lowcore *lowcore;
-+	int lc_order;
-+
-+	lc_order = sizeof(long) == 8 ? 1 : 0;
-+	lowcore = (void *) __get_free_pages(GFP_KERNEL | GFP_DMA, lc_order);
-+	if (!lowcore)
-+		return -ENOMEM;
-+	async_stack = __get_free_pages(GFP_KERNEL, ASYNC_ORDER);
-+	if (!async_stack)
-+		goto out_async_stack;
-+	panic_stack = __get_free_page(GFP_KERNEL);
-+	if (!panic_stack)
-+		goto out_panic_stack;
-+
-+	*lowcore = S390_lowcore;
-+	lowcore->async_stack = async_stack + ASYNC_SIZE;
-+	lowcore->panic_stack = panic_stack + PAGE_SIZE;
- 
--	/* Check for stopped state */
--	if (signal_processor_ps(&status, 0, cpu, sigp_sense) ==
--	    sigp_status_stored) {
--		if (status & 0x40)
--			return 1;
-+#ifndef CONFIG_64BIT
-+	if (MACHINE_HAS_IEEE) {
-+		unsigned long save_area;
-+
-+		save_area = get_zeroed_page(GFP_KERNEL);
-+		if (!save_area)
-+			goto out_save_area;
-+		lowcore->extended_save_area_addr = (u32) save_area;
- 	}
-+#endif
-+	lowcore_ptr[cpu] = lowcore;
- 	return 0;
-+
-+#ifndef CONFIG_64BIT
-+out_save_area:
-+	free_page(panic_stack);
-+#endif
-+out_panic_stack:
-+	free_pages(async_stack, ASYNC_ORDER);
-+out_async_stack:
-+	free_pages((unsigned long) lowcore, lc_order);
-+	return -ENOMEM;
- }
- 
--/* Upping and downing of CPUs */
-+#ifdef CONFIG_HOTPLUG_CPU
-+static void smp_free_lowcore(int cpu)
-+{
-+	struct _lowcore *lowcore;
-+	int lc_order;
-+
-+	lc_order = sizeof(long) == 8 ? 1 : 0;
-+	lowcore = lowcore_ptr[cpu];
-+#ifndef CONFIG_64BIT
-+	if (MACHINE_HAS_IEEE)
-+		free_page((unsigned long) lowcore->extended_save_area_addr);
-+#endif
-+	free_page(lowcore->panic_stack - PAGE_SIZE);
-+	free_pages(lowcore->async_stack - ASYNC_SIZE, ASYNC_ORDER);
-+	free_pages((unsigned long) lowcore, lc_order);
-+	lowcore_ptr[cpu] = NULL;
-+}
-+#endif /* CONFIG_HOTPLUG_CPU */
- 
--int __cpu_up(unsigned int cpu)
-+/* Upping and downing of CPUs */
-+int __cpuinit __cpu_up(unsigned int cpu)
- {
- 	struct task_struct *idle;
- 	struct _lowcore *cpu_lowcore;
- 	struct stack_frame *sf;
- 	sigp_ccode ccode;
--	int curr_cpu;
- 
--	for (curr_cpu = 0; curr_cpu <= 65535; curr_cpu++) {
--		__cpu_logical_map[cpu] = (__u16) curr_cpu;
--		if (cpu_stopped(cpu))
--			break;
+-	/* Sign extend based on neff. */
+-#if (NEFF == 32)
+-	/* Faster sign extension */
+-	pteh = (unsigned long long)(signed long long)(signed long)pteh;
+-#else
+-	/* General case */
+-	pteh = (pteh & NEFF_SIGN) ? (pteh | NEFF_MASK) : pteh;
+-#endif
+-
+-	/* Set the ASID. */
+-	pteh |= get_asid() << PTEH_ASID_SHIFT;
+-	pteh |= PTEH_VALID;
+-
+-	/* Set PTEL register, set_pte has performed the sign extension */
+-	ptel &= _PAGE_FLAGS_HARDWARE_MASK; /* drop software flags */
+-
+-	tlbp = is_text_not_data ? &(cpu_data->itlb) : &(cpu_data->dtlb);
+-	next = tlbp->next;
+-	__flush_tlb_slot(next);
+-	asm volatile ("putcfg %0,1,%2\n\n\t"
+-		      "putcfg %0,0,%1\n"
+-		      :  : "r" (next), "r" (pteh), "r" (ptel) );
+-
+-	next += TLB_STEP;
+-	if (next > tlbp->last) next = tlbp->first;
+-	tlbp->next = next;
+-
+-}
+-
+-static int handle_vmalloc_fault(struct mm_struct *mm, unsigned long protection_flags,
+-                                unsigned long long textaccess,
+-				unsigned long address)
+-{
+-	pgd_t *dir;
+-	pmd_t *pmd;
+-	static pte_t *pte;
+-	pte_t entry;
+-
+-	dir = pgd_offset_k(address);
+-	pmd = pmd_offset(dir, address);
+-
+-	if (pmd_none(*pmd)) {
+-		return 0;
 -	}
 -
--	if (!cpu_stopped(cpu))
--		return -ENODEV;
-+	if (smp_cpu_state[cpu] != CPU_STATE_CONFIGURED)
-+		return -EIO;
-+	if (smp_alloc_lowcore(cpu))
-+		return -ENOMEM;
- 
- 	ccode = signal_processor_p((__u32)(unsigned long)(lowcore_ptr[cpu]),
- 				   cpu, sigp_set_prefix);
-@@ -515,6 +706,7 @@ int __cpu_up(unsigned int cpu)
- 	cpu_lowcore = lowcore_ptr[cpu];
- 	cpu_lowcore->kernel_stack = (unsigned long)
- 		task_stack_page(idle) + THREAD_SIZE;
-+	cpu_lowcore->thread_info = (unsigned long) task_thread_info(idle);
- 	sf = (struct stack_frame *) (cpu_lowcore->kernel_stack
- 				     - sizeof(struct pt_regs)
- 				     - sizeof(struct stack_frame));
-@@ -528,6 +720,8 @@ int __cpu_up(unsigned int cpu)
- 	cpu_lowcore->percpu_offset = __per_cpu_offset[cpu];
- 	cpu_lowcore->current_task = (unsigned long) idle;
- 	cpu_lowcore->cpu_data.cpu_nr = cpu;
-+	cpu_lowcore->softirq_pending = 0;
-+	cpu_lowcore->ext_call_fast = 0;
- 	eieio();
- 
- 	while (signal_processor(cpu, sigp_restart) == sigp_busy)
-@@ -538,44 +732,20 @@ int __cpu_up(unsigned int cpu)
- 	return 0;
- }
- 
--static unsigned int __initdata additional_cpus;
--static unsigned int __initdata possible_cpus;
+-	if (pmd_bad(*pmd)) {
+-		pmd_clear(pmd);
+-		return 0;
+-	}
 -
--void __init smp_setup_cpu_possible_map(void)
-+static int __init setup_possible_cpus(char *s)
- {
--	unsigned int phy_cpus, pos_cpus, cpu;
+-	pte = pte_offset_kernel(pmd, address);
+-	entry = *pte;
 -
--	phy_cpus = smp_count_cpus();
--	pos_cpus = min(phy_cpus + additional_cpus, (unsigned int) NR_CPUS);
+-	if (pte_none(entry) || !pte_present(entry)) {
+-		return 0;
+-	}
 -
--	if (possible_cpus)
--		pos_cpus = min(possible_cpus, (unsigned int) NR_CPUS);
-+	int pcpus, cpu;
- 
--	for (cpu = 0; cpu < pos_cpus; cpu++)
-+	pcpus = simple_strtoul(s, NULL, 0);
-+	cpu_possible_map = cpumask_of_cpu(0);
-+	for (cpu = 1; cpu < pcpus && cpu < NR_CPUS; cpu++)
- 		cpu_set(cpu, cpu_possible_map);
+-	if ((pte_val(entry) & protection_flags) != protection_flags) {
+-		return 0;
+-	}
 -
--	phy_cpus = min(phy_cpus, pos_cpus);
+-        __do_tlb_refill(address, textaccess, pte);
 -
--	for (cpu = 0; cpu < phy_cpus; cpu++)
--		cpu_set(cpu, cpu_present_map);
+-	return 1;
 -}
 -
--#ifdef CONFIG_HOTPLUG_CPU
+-static int handle_tlbmiss(struct mm_struct *mm, unsigned long long protection_flags,
+-			unsigned long long textaccess,
+-			unsigned long address)
+-{
+-	pgd_t *dir;
+-	pmd_t *pmd;
+-	pte_t *pte;
+-	pte_t entry;
+-
+-	/* NB. The PGD currently only contains a single entry - there is no
+-	   page table tree stored for the top half of the address space since
+-	   virtual pages in that region should never be mapped in user mode.
+-	   (In kernel mode, the only things in that region are the 512Mb super
+-	   page (locked in), and vmalloc (modules) +  I/O device pages (handled
+-	   by handle_vmalloc_fault), so no PGD for the upper half is required
+-	   by kernel mode either).
+-
+-	   See how mm->pgd is allocated and initialised in pgd_alloc to see why
+-	   the next test is necessary.  - RPC */
+-	if (address >= (unsigned long) TASK_SIZE) {
+-		/* upper half - never has page table entries. */
+-		return 0;
+-	}
+-	dir = pgd_offset(mm, address);
+-	if (pgd_none(*dir)) {
+-		return 0;
+-	}
+-	if (!pgd_present(*dir)) {
+-		return 0;
+-	}
 -
--static int __init setup_additional_cpus(char *s)
--{
--	additional_cpus = simple_strtoul(s, NULL, 0);
--	return 0;
+-	pmd = pmd_offset(dir, address);
+-	if (pmd_none(*pmd)) {
+-		return 0;
+-	}
+-	if (!pmd_present(*pmd)) {
+-		return 0;
+-	}
+-	pte = pte_offset_kernel(pmd, address);
+-	entry = *pte;
+-	if (pte_none(entry)) {
+-		return 0;
+-	}
+-	if (!pte_present(entry)) {
+-		return 0;
+-	}
+-
+-	/* If the page doesn't have sufficient protection bits set to service the
+-	   kind of fault being handled, there's not much point doing the TLB refill.
+-	   Punt the fault to the general handler. */
+-	if ((pte_val(entry) & protection_flags) != protection_flags) {
+-		return 0;
+-	}
+-
+-        __do_tlb_refill(address, textaccess, pte);
+-
+-	return 1;
 -}
--early_param("additional_cpus", setup_additional_cpus);
 -
--static int __init setup_possible_cpus(char *s)
--{
--	possible_cpus = simple_strtoul(s, NULL, 0);
- 	return 0;
- }
- early_param("possible_cpus", setup_possible_cpus);
- 
-+#ifdef CONFIG_HOTPLUG_CPU
-+
- int __cpu_disable(void)
- {
- 	struct ec_creg_mask_parms cr_parms;
-@@ -612,7 +782,8 @@ void __cpu_die(unsigned int cpu)
- 	/* Wait until target cpu is down */
- 	while (!smp_cpu_not_running(cpu))
- 		cpu_relax();
--	printk("Processor %d spun down\n", cpu);
-+	smp_free_lowcore(cpu);
-+	printk(KERN_INFO "Processor %d spun down\n", cpu);
- }
- 
- void cpu_die(void)
-@@ -625,49 +796,19 @@ void cpu_die(void)
- 
- #endif /* CONFIG_HOTPLUG_CPU */
- 
+-/* Put all this information into one structure so that everything is just arithmetic
+-   relative to a single base address.  This reduces the number of movi/shori pairs needed
+-   just to load addresses of static data. */
+-struct expevt_lookup {
+-	unsigned short protection_flags[8];
+-	unsigned char  is_text_access[8];
+-	unsigned char  is_write_access[8];
+-};
+-
+-#define PRU (1<<9)
+-#define PRW (1<<8)
+-#define PRX (1<<7)
+-#define PRR (1<<6)
+-
+-#define DIRTY (_PAGE_DIRTY | _PAGE_ACCESSED)
+-#define YOUNG (_PAGE_ACCESSED)
+-
+-/* Sized as 8 rather than 4 to allow checking the PTE's PRU bit against whether
+-   the fault happened in user mode or privileged mode. */
+-static struct expevt_lookup expevt_lookup_table = {
+-	.protection_flags = {PRX, PRX, 0, 0, PRR, PRR, PRW, PRW},
+-	.is_text_access   = {1,   1,   0, 0, 0,   0,   0,   0}
+-};
+-
 -/*
-- *	Cycle through the processors and setup structures.
+-   This routine handles page faults that can be serviced just by refilling a
+-   TLB entry from an existing page table entry.  (This case represents a very
+-   large majority of page faults.) Return 1 if the fault was successfully
+-   handled.  Return 0 if the fault could not be handled.  (This leads into the
+-   general fault handling in fault.c which deals with mapping file-backed
+-   pages, stack growth, segmentation faults, swapping etc etc)
 - */
+-asmlinkage int do_fast_page_fault(unsigned long long ssr_md, unsigned long long expevt,
+-			          unsigned long address)
+-{
+-	struct task_struct *tsk;
+-	struct mm_struct *mm;
+-	unsigned long long textaccess;
+-	unsigned long long protection_flags;
+-	unsigned long long index;
+-	unsigned long long expevt4;
+-
+-	/* The next few lines implement a way of hashing EXPEVT into a small array index
+-	   which can be used to lookup parameters specific to the type of TLBMISS being
+-	   handled.  Note:
+-	   ITLBMISS has EXPEVT==0xa40
+-	   RTLBMISS has EXPEVT==0x040
+-	   WTLBMISS has EXPEVT==0x060
+-	*/
 -
- void __init smp_prepare_cpus(unsigned int max_cpus)
- {
--	unsigned long stack;
- 	unsigned int cpu;
--	int i;
-+
-+	smp_detect_cpus();
- 
- 	/* request the 0x1201 emergency signal external interrupt */
- 	if (register_external_interrupt(0x1201, do_ext_call_interrupt) != 0)
- 		panic("Couldn't request external interrupt 0x1201");
- 	memset(lowcore_ptr, 0, sizeof(lowcore_ptr));
--	/*
--	 *  Initialize prefix pages and stacks for all possible cpus
--	 */
- 	print_cpu_info(&S390_lowcore.cpu_data);
-+	smp_alloc_lowcore(smp_processor_id());
- 
--	for_each_possible_cpu(i) {
--		lowcore_ptr[i] = (struct _lowcore *)
--			__get_free_pages(GFP_KERNEL | GFP_DMA,
--					 sizeof(void*) == 8 ? 1 : 0);
--		stack = __get_free_pages(GFP_KERNEL, ASYNC_ORDER);
--		if (!lowcore_ptr[i] || !stack)
--			panic("smp_boot_cpus failed to allocate memory\n");
+-	expevt4 = (expevt >> 4);
+-	/* TODO : xor ssr_md into this expression too.  Then we can check that PRU is set
+-	   when it needs to be. */
+-	index = expevt4 ^ (expevt4 >> 5);
+-	index &= 7;
+-	protection_flags = expevt_lookup_table.protection_flags[index];
+-	textaccess       = expevt_lookup_table.is_text_access[index];
 -
--		*(lowcore_ptr[i]) = S390_lowcore;
--		lowcore_ptr[i]->async_stack = stack + ASYNC_SIZE;
--		stack = __get_free_pages(GFP_KERNEL, 0);
--		if (!stack)
--			panic("smp_boot_cpus failed to allocate memory\n");
--		lowcore_ptr[i]->panic_stack = stack + PAGE_SIZE;
--#ifndef CONFIG_64BIT
--		if (MACHINE_HAS_IEEE) {
--			lowcore_ptr[i]->extended_save_area_addr =
--				(__u32) __get_free_pages(GFP_KERNEL, 0);
--			if (!lowcore_ptr[i]->extended_save_area_addr)
--				panic("smp_boot_cpus failed to "
--				      "allocate memory\n");
--		}
+-#ifdef CONFIG_SH64_PROC_TLB
+-	++calls_to_do_fast_page_fault;
 -#endif
--	}
- #ifndef CONFIG_64BIT
- 	if (MACHINE_HAS_IEEE)
- 		ctl_set_bit(14, 29); /* enable extended save area */
-@@ -683,15 +824,17 @@ void __init smp_prepare_boot_cpu(void)
- {
- 	BUG_ON(smp_processor_id() != 0);
- 
-+	current_thread_info()->cpu = 0;
-+	cpu_set(0, cpu_present_map);
- 	cpu_set(0, cpu_online_map);
- 	S390_lowcore.percpu_offset = __per_cpu_offset[0];
- 	current_set[0] = current;
-+	smp_cpu_state[0] = CPU_STATE_CONFIGURED;
- 	spin_lock_init(&(&__get_cpu_var(s390_idle))->lock);
- }
- 
- void __init smp_cpus_done(unsigned int max_cpus)
- {
--	cpu_present_map = cpu_possible_map;
- }
- 
- /*
-@@ -705,7 +848,79 @@ int setup_profiling_timer(unsigned int multiplier)
- 	return 0;
- }
- 
--static DEFINE_PER_CPU(struct cpu, cpu_devices);
-+#ifdef CONFIG_HOTPLUG_CPU
-+static ssize_t cpu_configure_show(struct sys_device *dev, char *buf)
-+{
-+	ssize_t count;
-+
-+	mutex_lock(&smp_cpu_state_mutex);
-+	count = sprintf(buf, "%d\n", smp_cpu_state[dev->id]);
-+	mutex_unlock(&smp_cpu_state_mutex);
-+	return count;
-+}
-+
-+static ssize_t cpu_configure_store(struct sys_device *dev, const char *buf,
-+				   size_t count)
-+{
-+	int cpu = dev->id;
-+	int val, rc;
-+	char delim;
-+
-+	if (sscanf(buf, "%d %c", &val, &delim) != 1)
-+		return -EINVAL;
-+	if (val != 0 && val != 1)
-+		return -EINVAL;
-+
-+	mutex_lock(&smp_cpu_state_mutex);
-+	get_online_cpus();
-+	rc = -EBUSY;
-+	if (cpu_online(cpu))
-+		goto out;
-+	rc = 0;
-+	switch (val) {
-+	case 0:
-+		if (smp_cpu_state[cpu] == CPU_STATE_CONFIGURED) {
-+			rc = sclp_cpu_deconfigure(__cpu_logical_map[cpu]);
-+			if (!rc)
-+				smp_cpu_state[cpu] = CPU_STATE_STANDBY;
-+		}
-+		break;
-+	case 1:
-+		if (smp_cpu_state[cpu] == CPU_STATE_STANDBY) {
-+			rc = sclp_cpu_configure(__cpu_logical_map[cpu]);
-+			if (!rc)
-+				smp_cpu_state[cpu] = CPU_STATE_CONFIGURED;
-+		}
-+		break;
-+	default:
-+		break;
-+	}
-+out:
-+	put_online_cpus();
-+	mutex_unlock(&smp_cpu_state_mutex);
-+	return rc ? rc : count;
-+}
-+static SYSDEV_ATTR(configure, 0644, cpu_configure_show, cpu_configure_store);
-+#endif /* CONFIG_HOTPLUG_CPU */
-+
-+static ssize_t show_cpu_address(struct sys_device *dev, char *buf)
-+{
-+	return sprintf(buf, "%d\n", __cpu_logical_map[dev->id]);
-+}
-+static SYSDEV_ATTR(address, 0444, show_cpu_address, NULL);
-+
-+
-+static struct attribute *cpu_common_attrs[] = {
-+#ifdef CONFIG_HOTPLUG_CPU
-+	&attr_configure.attr,
-+#endif
-+	&attr_address.attr,
-+	NULL,
-+};
-+
-+static struct attribute_group cpu_common_attr_group = {
-+	.attrs = cpu_common_attrs,
-+};
- 
- static ssize_t show_capability(struct sys_device *dev, char *buf)
- {
-@@ -750,15 +965,15 @@ static ssize_t show_idle_time(struct sys_device *dev, char *buf)
- }
- static SYSDEV_ATTR(idle_time_us, 0444, show_idle_time, NULL);
- 
--static struct attribute *cpu_attrs[] = {
-+static struct attribute *cpu_online_attrs[] = {
- 	&attr_capability.attr,
- 	&attr_idle_count.attr,
- 	&attr_idle_time_us.attr,
- 	NULL,
- };
- 
--static struct attribute_group cpu_attr_group = {
--	.attrs = cpu_attrs,
-+static struct attribute_group cpu_online_attr_group = {
-+	.attrs = cpu_online_attrs,
- };
- 
- static int __cpuinit smp_cpu_notify(struct notifier_block *self,
-@@ -778,12 +993,12 @@ static int __cpuinit smp_cpu_notify(struct notifier_block *self,
- 		idle->idle_time = 0;
- 		idle->idle_count = 0;
- 		spin_unlock_irq(&idle->lock);
--		if (sysfs_create_group(&s->kobj, &cpu_attr_group))
-+		if (sysfs_create_group(&s->kobj, &cpu_online_attr_group))
- 			return NOTIFY_BAD;
- 		break;
- 	case CPU_DEAD:
- 	case CPU_DEAD_FROZEN:
--		sysfs_remove_group(&s->kobj, &cpu_attr_group);
-+		sysfs_remove_group(&s->kobj, &cpu_online_attr_group);
- 		break;
- 	}
- 	return NOTIFY_OK;
-@@ -793,6 +1008,62 @@ static struct notifier_block __cpuinitdata smp_cpu_nb = {
- 	.notifier_call = smp_cpu_notify,
- };
- 
-+static int smp_add_present_cpu(int cpu)
-+{
-+	struct cpu *c = &per_cpu(cpu_devices, cpu);
-+	struct sys_device *s = &c->sysdev;
-+	int rc;
-+
-+	c->hotpluggable = 1;
-+	rc = register_cpu(c, cpu);
-+	if (rc)
-+		goto out;
-+	rc = sysfs_create_group(&s->kobj, &cpu_common_attr_group);
-+	if (rc)
-+		goto out_cpu;
-+	if (!cpu_online(cpu))
-+		goto out;
-+	rc = sysfs_create_group(&s->kobj, &cpu_online_attr_group);
-+	if (!rc)
-+		return 0;
-+	sysfs_remove_group(&s->kobj, &cpu_common_attr_group);
-+out_cpu:
-+#ifdef CONFIG_HOTPLUG_CPU
-+	unregister_cpu(c);
-+#endif
-+out:
-+	return rc;
-+}
-+
-+#ifdef CONFIG_HOTPLUG_CPU
-+static ssize_t rescan_store(struct sys_device *dev, const char *buf,
-+			    size_t count)
-+{
-+	cpumask_t newcpus;
-+	int cpu;
-+	int rc;
-+
-+	mutex_lock(&smp_cpu_state_mutex);
-+	get_online_cpus();
-+	newcpus = cpu_present_map;
-+	rc = smp_rescan_cpus();
-+	if (rc)
-+		goto out;
-+	cpus_andnot(newcpus, cpu_present_map, newcpus);
-+	for_each_cpu_mask(cpu, newcpus) {
-+		rc = smp_add_present_cpu(cpu);
-+		if (rc)
-+			cpu_clear(cpu, cpu_present_map);
-+	}
-+	rc = 0;
-+out:
-+	put_online_cpus();
-+	mutex_unlock(&smp_cpu_state_mutex);
-+	return rc ? rc : count;
-+}
-+static SYSDEV_ATTR(rescan, 0200, NULL, rescan_store);
-+#endif /* CONFIG_HOTPLUG_CPU */
-+
- static int __init topology_init(void)
- {
- 	int cpu;
-@@ -800,16 +1071,14 @@ static int __init topology_init(void)
- 
- 	register_cpu_notifier(&smp_cpu_nb);
- 
--	for_each_possible_cpu(cpu) {
--		struct cpu *c = &per_cpu(cpu_devices, cpu);
--		struct sys_device *s = &c->sysdev;
 -
--		c->hotpluggable = 1;
--		register_cpu(c, cpu);
--		if (!cpu_online(cpu))
--			continue;
--		s = &c->sysdev;
--		rc = sysfs_create_group(&s->kobj, &cpu_attr_group);
-+#ifdef CONFIG_HOTPLUG_CPU
-+	rc = sysfs_create_file(&cpu_sysdev_class.kset.kobj,
-+			       &attr_rescan.attr);
-+	if (rc)
-+		return rc;
-+#endif
-+	for_each_present_cpu(cpu) {
-+		rc = smp_add_present_cpu(cpu);
- 		if (rc)
- 			return rc;
- 	}
-diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c
-index 22b800c..3bbac12 100644
---- a/arch/s390/kernel/time.c
-+++ b/arch/s390/kernel/time.c
-@@ -1145,7 +1145,7 @@ static void etr_work_fn(struct work_struct *work)
-  * Sysfs interface functions
-  */
- static struct sysdev_class etr_sysclass = {
--	set_kset_name("etr")
-+	.name	= "etr",
- };
- 
- static struct sys_device etr_port0_dev = {
-diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c
-index 8ed16a8..52b8342 100644
---- a/arch/s390/kernel/traps.c
-+++ b/arch/s390/kernel/traps.c
-@@ -31,6 +31,7 @@
- #include <linux/reboot.h>
- #include <linux/kprobes.h>
- #include <linux/bug.h>
-+#include <linux/utsname.h>
- #include <asm/system.h>
- #include <asm/uaccess.h>
- #include <asm/io.h>
-@@ -168,9 +169,16 @@ void show_stack(struct task_struct *task, unsigned long *sp)
-  */
- void dump_stack(void)
- {
-+	printk("CPU: %d %s %s %.*s\n",
-+	       task_thread_info(current)->cpu, print_tainted(),
-+	       init_utsname()->release,
-+	       (int)strcspn(init_utsname()->version, " "),
-+	       init_utsname()->version);
-+	printk("Process %s (pid: %d, task: %p, ksp: %p)\n",
-+	       current->comm, current->pid, current,
-+	       (void *) current->thread.ksp);
- 	show_stack(NULL, NULL);
- }
+-	/* SIM
+-	 * Note this is now called with interrupts still disabled
+-	 * This is to cope with being called for a missing IO port
+-	 * address with interrupts disabled. This should be fixed as
+-	 * soon as we have a better 'fast path' miss handler.
+-	 *
+-	 * Plus take care how you try and debug this stuff.
+-	 * For example, writing debug data to a port which you
+-	 * have just faulted on is not going to work.
+-	 */
 -
- EXPORT_SYMBOL(dump_stack);
- 
- static inline int mask_bits(struct pt_regs *regs, unsigned long bits)
-@@ -258,8 +266,14 @@ void die(const char * str, struct pt_regs * regs, long err)
- 	console_verbose();
- 	spin_lock_irq(&die_lock);
- 	bust_spinlocks(1);
--	printk("%s: %04lx [#%d]\n", str, err & 0xffff, ++die_counter);
--	print_modules();
-+	printk("%s: %04lx [#%d] ", str, err & 0xffff, ++die_counter);
-+#ifdef CONFIG_PREEMPT
-+	printk("PREEMPT ");
-+#endif
-+#ifdef CONFIG_SMP
-+	printk("SMP");
-+#endif
-+	printk("\n");
- 	notify_die(DIE_OOPS, str, regs, err, current->thread.trap_no, SIGSEGV);
- 	show_regs(regs);
- 	bust_spinlocks(0);
-diff --git a/arch/s390/kernel/vmlinux.lds.S b/arch/s390/kernel/vmlinux.lds.S
-index 849120e..9361591 100644
---- a/arch/s390/kernel/vmlinux.lds.S
-+++ b/arch/s390/kernel/vmlinux.lds.S
-@@ -17,6 +17,12 @@ ENTRY(_start)
- jiffies = jiffies_64;
- #endif
- 
-+PHDRS {
-+	text PT_LOAD FLAGS(5);	/* R_E */
-+	data PT_LOAD FLAGS(7);	/* RWE */
-+	note PT_NOTE FLAGS(0);	/* ___ */
-+}
-+
- SECTIONS
- {
- 	. = 0x00000000;
-@@ -33,6 +39,9 @@ SECTIONS
- 
- 	_etext = .;		/* End of text section */
- 
-+	NOTES :text :note
-+	BUG_TABLE :text
-+
- 	RODATA
- 
- #ifdef CONFIG_SHARED_KERNEL
-@@ -49,9 +58,6 @@ SECTIONS
- 		__stop___ex_table = .;
- 	}
- 
--	NOTES
--	BUG_TABLE
+-	tsk = current;
+-	mm = tsk->mm;
 -
- 	.data : {		/* Data */
- 		DATA_DATA
- 		CONSTRUCTORS
-diff --git a/arch/s390/lib/spinlock.c b/arch/s390/lib/spinlock.c
-index 8d76403..e41f400 100644
---- a/arch/s390/lib/spinlock.c
-+++ b/arch/s390/lib/spinlock.c
-@@ -39,7 +39,7 @@ static inline void _raw_yield_cpu(int cpu)
- 		_raw_yield();
- }
- 
--void _raw_spin_lock_wait(raw_spinlock_t *lp, unsigned int pc)
-+void _raw_spin_lock_wait(raw_spinlock_t *lp)
- {
- 	int count = spin_retry;
- 	unsigned int cpu = ~smp_processor_id();
-@@ -53,15 +53,36 @@ void _raw_spin_lock_wait(raw_spinlock_t *lp, unsigned int pc)
- 		}
- 		if (__raw_spin_is_locked(lp))
- 			continue;
--		if (_raw_compare_and_swap(&lp->owner_cpu, 0, cpu) == 0) {
--			lp->owner_pc = pc;
-+		if (_raw_compare_and_swap(&lp->owner_cpu, 0, cpu) == 0)
- 			return;
+-	if ((address >= VMALLOC_START && address < VMALLOC_END) ||
+-	    (address >= IOBASE_VADDR  && address < IOBASE_END)) {
+-		if (ssr_md) {
+-			/* Process-contexts can never have this address range mapped */
+-			if (handle_vmalloc_fault(mm, protection_flags, textaccess, address)) {
+-				return 1;
+-			}
 -		}
- 	}
- }
- EXPORT_SYMBOL(_raw_spin_lock_wait);
- 
--int _raw_spin_trylock_retry(raw_spinlock_t *lp, unsigned int pc)
-+void _raw_spin_lock_wait_flags(raw_spinlock_t *lp, unsigned long flags)
-+{
-+	int count = spin_retry;
-+	unsigned int cpu = ~smp_processor_id();
-+
-+	local_irq_restore(flags);
-+	while (1) {
-+		if (count-- <= 0) {
-+			unsigned int owner = lp->owner_cpu;
-+			if (owner != 0)
-+				_raw_yield_cpu(~owner);
-+			count = spin_retry;
-+		}
-+		if (__raw_spin_is_locked(lp))
-+			continue;
-+		local_irq_disable();
-+		if (_raw_compare_and_swap(&lp->owner_cpu, 0, cpu) == 0)
-+			return;
-+		local_irq_restore(flags);
-+	}
-+}
-+EXPORT_SYMBOL(_raw_spin_lock_wait_flags);
-+
-+int _raw_spin_trylock_retry(raw_spinlock_t *lp)
- {
- 	unsigned int cpu = ~smp_processor_id();
- 	int count;
-@@ -69,10 +90,8 @@ int _raw_spin_trylock_retry(raw_spinlock_t *lp, unsigned int pc)
- 	for (count = spin_retry; count > 0; count--) {
- 		if (__raw_spin_is_locked(lp))
- 			continue;
--		if (_raw_compare_and_swap(&lp->owner_cpu, 0, cpu) == 0) {
--			lp->owner_pc = pc;
-+		if (_raw_compare_and_swap(&lp->owner_cpu, 0, cpu) == 0)
- 			return 1;
+-	} else if (!in_interrupt() && mm) {
+-		if (handle_tlbmiss(mm, protection_flags, textaccess, address)) {
+-			return 1;
 -		}
- 	}
- 	return 0;
- }
-diff --git a/arch/s390/mm/extmem.c b/arch/s390/mm/extmem.c
-index 394980b..880b0eb 100644
---- a/arch/s390/mm/extmem.c
-+++ b/arch/s390/mm/extmem.c
-@@ -83,7 +83,7 @@ struct dcss_segment {
- };
- 
- static DEFINE_MUTEX(dcss_lock);
--static struct list_head dcss_list = LIST_HEAD_INIT(dcss_list);
-+static LIST_HEAD(dcss_list);
- static char *segtype_string[] = { "SW", "EW", "SR", "ER", "SN", "EN", "SC",
- 					"EW/EN-MIXED" };
- 
-diff --git a/arch/s390/mm/vmem.c b/arch/s390/mm/vmem.c
-index fb9c5a8..79d13a1 100644
---- a/arch/s390/mm/vmem.c
-+++ b/arch/s390/mm/vmem.c
-@@ -15,10 +15,6 @@
- #include <asm/setup.h>
- #include <asm/tlbflush.h>
- 
--unsigned long vmalloc_end;
--EXPORT_SYMBOL(vmalloc_end);
+-	}
 -
--static struct page *vmem_map;
- static DEFINE_MUTEX(vmem_mutex);
- 
- struct memory_segment {
-@@ -188,8 +184,8 @@ static int vmem_add_mem_map(unsigned long start, unsigned long size)
- 	pte_t  pte;
- 	int ret = -ENOMEM;
- 
--	map_start = vmem_map + PFN_DOWN(start);
--	map_end	= vmem_map + PFN_DOWN(start + size);
-+	map_start = VMEM_MAP + PFN_DOWN(start);
-+	map_end	= VMEM_MAP + PFN_DOWN(start + size);
- 
- 	start_addr = (unsigned long) map_start & PAGE_MASK;
- 	end_addr = PFN_ALIGN((unsigned long) map_end);
-@@ -240,10 +236,10 @@ static int vmem_add_mem(unsigned long start, unsigned long size)
- {
- 	int ret;
- 
--	ret = vmem_add_range(start, size);
-+	ret = vmem_add_mem_map(start, size);
- 	if (ret)
- 		return ret;
--	return vmem_add_mem_map(start, size);
-+	return vmem_add_range(start, size);
- }
- 
- /*
-@@ -254,7 +250,7 @@ static int insert_memory_segment(struct memory_segment *seg)
- {
- 	struct memory_segment *tmp;
- 
--	if (PFN_DOWN(seg->start + seg->size) > max_pfn ||
-+	if (seg->start + seg->size >= VMALLOC_START ||
- 	    seg->start + seg->size < seg->start)
- 		return -ERANGE;
- 
-@@ -357,17 +353,15 @@ out:
- 
- /*
-  * map whole physical memory to virtual memory (identity mapping)
-+ * we reserve enough space in the vmalloc area for vmemmap to hotplug
-+ * additional memory segments.
-  */
- void __init vmem_map_init(void)
- {
--	unsigned long map_size;
- 	int i;
- 
--	map_size = ALIGN(max_low_pfn, MAX_ORDER_NR_PAGES) * sizeof(struct page);
--	vmalloc_end = PFN_ALIGN(VMALLOC_END_INIT) - PFN_ALIGN(map_size);
--	vmem_map = (struct page *) vmalloc_end;
--	NODE_DATA(0)->node_mem_map = vmem_map;
+-	return 0;
+-}
 -
-+	BUILD_BUG_ON((unsigned long)VMEM_MAP + VMEM_MAP_SIZE > VMEM_MAP_MAX);
-+	NODE_DATA(0)->node_mem_map = VMEM_MAP;
- 	for (i = 0; i < MEMORY_CHUNKS && memory_chunk[i].size > 0; i++)
- 		vmem_add_mem(memory_chunk[i].addr, memory_chunk[i].size);
- }
-@@ -382,7 +376,7 @@ static int __init vmem_convert_memory_chunk(void)
- 	int i;
- 
- 	mutex_lock(&vmem_mutex);
--	for (i = 0; i < MEMORY_CHUNKS && memory_chunk[i].size > 0; i++) {
-+	for (i = 0; i < MEMORY_CHUNKS; i++) {
- 		if (!memory_chunk[i].size)
- 			continue;
- 		seg = kzalloc(sizeof(*seg), GFP_KERNEL);
-diff --git a/arch/sh/drivers/dma/dma-sysfs.c b/arch/sh/drivers/dma/dma-sysfs.c
-index eebcd47..51b57c0 100644
---- a/arch/sh/drivers/dma/dma-sysfs.c
-+++ b/arch/sh/drivers/dma/dma-sysfs.c
-@@ -19,7 +19,7 @@
- #include <asm/dma.h>
- 
- static struct sysdev_class dma_sysclass = {
--	set_kset_name("dma"),
-+	.name = "dma",
- };
- EXPORT_SYMBOL(dma_sysclass);
+diff --git a/arch/sh64/oprofile/Makefile b/arch/sh64/oprofile/Makefile
+deleted file mode 100644
+index 11a451f..0000000
+--- a/arch/sh64/oprofile/Makefile
++++ /dev/null
+@@ -1,12 +0,0 @@
+-obj-$(CONFIG_OPROFILE) += oprofile.o
+-
+-DRIVER_OBJS = $(addprefix ../../../drivers/oprofile/, \
+-		oprof.o cpu_buffer.o buffer_sync.o \
+-		event_buffer.o oprofile_files.o \
+-		oprofilefs.o oprofile_stats.o \
+-		timer_int.o )
+-
+-profdrvr-y				:= op_model_null.o
+-
+-oprofile-y				:= $(DRIVER_OBJS) $(profdrvr-y)
+-
+diff --git a/arch/sh64/oprofile/op_model_null.c b/arch/sh64/oprofile/op_model_null.c
+deleted file mode 100644
+index a750ea1..0000000
+--- a/arch/sh64/oprofile/op_model_null.c
++++ /dev/null
+@@ -1,23 +0,0 @@
+-/*
+- * arch/sh64/oprofile/op_model_null.c
+- *
+- * Copyright (C) 2003  Paul Mundt
+- *
+- * This file is subject to the terms and conditions of the GNU General Public
+- * License.  See the file "COPYING" in the main directory of this archive
+- * for more details.
+- */
+-#include <linux/kernel.h>
+-#include <linux/oprofile.h>
+-#include <linux/init.h>
+-#include <linux/errno.h>
+-
+-int __init oprofile_arch_init(struct oprofile_operations *ops)
+-{
+-	return -ENODEV;
+-}
+-
+-void oprofile_arch_exit(void)
+-{
+-}
+-
+diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c
+index b1a77b1..99f9f96 100644
+--- a/arch/um/drivers/ubd_kern.c
++++ b/arch/um/drivers/ubd_kern.c
+@@ -475,17 +475,9 @@ static void do_ubd_request(struct request_queue * q);
+ /* Only changed by ubd_init, which is an initcall. */
+ int thread_fd = -1;
  
-diff --git a/arch/sh/kernel/cpu/sh4/sq.c b/arch/sh/kernel/cpu/sh4/sq.c
-index b22a78c..3008c00 100644
---- a/arch/sh/kernel/cpu/sh4/sq.c
-+++ b/arch/sh/kernel/cpu/sh4/sq.c
-@@ -341,17 +341,18 @@ static int __devinit sq_sysdev_add(struct sys_device *sysdev)
+-static void ubd_end_request(struct request *req, int bytes, int uptodate)
++static void ubd_end_request(struct request *req, int bytes, int error)
  {
- 	unsigned int cpu = sysdev->id;
- 	struct kobject *kobj;
-+	int error;
- 
- 	sq_kobject[cpu] = kzalloc(sizeof(struct kobject), GFP_KERNEL);
- 	if (unlikely(!sq_kobject[cpu]))
- 		return -ENOMEM;
- 
- 	kobj = sq_kobject[cpu];
--	kobj->parent = &sysdev->kobj;
--	kobject_set_name(kobj, "%s", "sq");
--	kobj->ktype = &ktype_percpu_entry;
+-	if (!end_that_request_first(req, uptodate, bytes >> 9)) {
+-		struct ubd *dev = req->rq_disk->private_data;
+-		unsigned long flags;
 -
--	return kobject_register(kobj);
-+	error = kobject_init_and_add(kobj, &ktype_percpu_entry, &sysdev->kobj,
-+				     "%s", "sq");
-+	if (!error)
-+		kobject_uevent(kobj, KOBJ_ADD);
-+	return error;
+-		add_disk_randomness(req->rq_disk);
+-		spin_lock_irqsave(&dev->lock, flags);
+-		end_that_request_last(req, uptodate);
+-		spin_unlock_irqrestore(&dev->lock, flags);
+-	}
++	blk_end_request(req, error, bytes);
  }
  
- static int __devexit sq_sysdev_remove(struct sys_device *sysdev)
-@@ -359,7 +360,7 @@ static int __devexit sq_sysdev_remove(struct sys_device *sysdev)
- 	unsigned int cpu = sysdev->id;
- 	struct kobject *kobj = sq_kobject[cpu];
- 
--	kobject_unregister(kobj);
-+	kobject_put(kobj);
- 	return 0;
+ /* Callable only from interrupt context - otherwise you need to do
+@@ -493,10 +485,10 @@ static void ubd_end_request(struct request *req, int bytes, int uptodate)
+ static inline void ubd_finish(struct request *req, int bytes)
+ {
+ 	if(bytes < 0){
+-		ubd_end_request(req, 0, 0);
++		ubd_end_request(req, 0, -EIO);
+ 		return;
+ 	}
+-	ubd_end_request(req, bytes, 1);
++	ubd_end_request(req, bytes, 0);
  }
  
-diff --git a/arch/sh/kernel/time.c b/arch/sh/kernel/time.c
-index a3a67d1..2bc04bf 100644
---- a/arch/sh/kernel/time.c
-+++ b/arch/sh/kernel/time.c
-@@ -174,7 +174,7 @@ int timer_resume(struct sys_device *dev)
- #endif
- 
- static struct sysdev_class timer_sysclass = {
--	set_kset_name("timer"),
-+	.name	 = "timer",
- 	.suspend = timer_suspend,
- 	.resume	 = timer_resume,
- };
+ static LIST_HEAD(restart);
 diff --git a/arch/x86/crypto/Makefile b/arch/x86/crypto/Makefile
 index 46bb609..3874c2d 100644
 --- a/arch/x86/crypto/Makefile
@@ -31611,78 +121484,1180 @@
 +	.address = save_stack_address_nosched,
 +};
 +
- /*
-  * Save stack-backtrace addresses into a stack_trace buffer.
-  */
-@@ -50,3 +70,10 @@ void save_stack_trace(struct stack_trace *trace)
- 		trace->entries[trace->nr_entries++] = ULONG_MAX;
+ /*
+  * Save stack-backtrace addresses into a stack_trace buffer.
+  */
+@@ -50,3 +70,10 @@ void save_stack_trace(struct stack_trace *trace)
+ 		trace->entries[trace->nr_entries++] = ULONG_MAX;
+ }
+ EXPORT_SYMBOL(save_stack_trace);
++
++void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
++{
++	dump_trace(tsk, NULL, NULL, &save_stack_ops_nosched, trace);
++	if (trace->nr_entries < trace->max_entries)
++		trace->entries[trace->nr_entries++] = ULONG_MAX;
++}
+diff --git a/arch/x86/oprofile/nmi_int.c b/arch/x86/oprofile/nmi_int.c
+index 944bbcd..c8ab79e 100644
+--- a/arch/x86/oprofile/nmi_int.c
++++ b/arch/x86/oprofile/nmi_int.c
+@@ -51,7 +51,7 @@ static int nmi_resume(struct sys_device *dev)
+ 
+ 
+ static struct sysdev_class oprofile_sysclass = {
+-	set_kset_name("oprofile"),
++	.name		= "oprofile",
+ 	.resume		= nmi_resume,
+ 	.suspend	= nmi_suspend,
+ };
+diff --git a/block/as-iosched.c b/block/as-iosched.c
+index cb5e53b..b201d16 100644
+--- a/block/as-iosched.c
++++ b/block/as-iosched.c
+@@ -170,9 +170,11 @@ static void free_as_io_context(struct as_io_context *aic)
+ 
+ static void as_trim(struct io_context *ioc)
+ {
++	spin_lock(&ioc->lock);
+ 	if (ioc->aic)
+ 		free_as_io_context(ioc->aic);
+ 	ioc->aic = NULL;
++	spin_unlock(&ioc->lock);
+ }
+ 
+ /* Called when the task exits */
+@@ -462,7 +464,9 @@ static void as_antic_timeout(unsigned long data)
+ 	spin_lock_irqsave(q->queue_lock, flags);
+ 	if (ad->antic_status == ANTIC_WAIT_REQ
+ 			|| ad->antic_status == ANTIC_WAIT_NEXT) {
+-		struct as_io_context *aic = ad->io_context->aic;
++		struct as_io_context *aic;
++		spin_lock(&ad->io_context->lock);
++		aic = ad->io_context->aic;
+ 
+ 		ad->antic_status = ANTIC_FINISHED;
+ 		kblockd_schedule_work(&ad->antic_work);
+@@ -475,6 +479,7 @@ static void as_antic_timeout(unsigned long data)
+ 			/* process not "saved" by a cooperating request */
+ 			ad->exit_no_coop = (7*ad->exit_no_coop + 256)/8;
+ 		}
++		spin_unlock(&ad->io_context->lock);
+ 	}
+ 	spin_unlock_irqrestore(q->queue_lock, flags);
+ }
+@@ -635,9 +640,11 @@ static int as_can_break_anticipation(struct as_data *ad, struct request *rq)
+ 
+ 	ioc = ad->io_context;
+ 	BUG_ON(!ioc);
++	spin_lock(&ioc->lock);
+ 
+ 	if (rq && ioc == RQ_IOC(rq)) {
+ 		/* request from same process */
++		spin_unlock(&ioc->lock);
+ 		return 1;
+ 	}
+ 
+@@ -646,20 +653,25 @@ static int as_can_break_anticipation(struct as_data *ad, struct request *rq)
+ 		 * In this situation status should really be FINISHED,
+ 		 * however the timer hasn't had the chance to run yet.
+ 		 */
++		spin_unlock(&ioc->lock);
+ 		return 1;
+ 	}
+ 
+ 	aic = ioc->aic;
+-	if (!aic)
++	if (!aic) {
++		spin_unlock(&ioc->lock);
+ 		return 0;
++	}
+ 
+ 	if (atomic_read(&aic->nr_queued) > 0) {
+ 		/* process has more requests queued */
++		spin_unlock(&ioc->lock);
+ 		return 1;
+ 	}
+ 
+ 	if (atomic_read(&aic->nr_dispatched) > 0) {
+ 		/* process has more requests dispatched */
++		spin_unlock(&ioc->lock);
+ 		return 1;
+ 	}
+ 
+@@ -680,6 +692,7 @@ static int as_can_break_anticipation(struct as_data *ad, struct request *rq)
+ 		}
+ 
+ 		as_update_iohist(ad, aic, rq);
++		spin_unlock(&ioc->lock);
+ 		return 1;
+ 	}
+ 
+@@ -688,20 +701,27 @@ static int as_can_break_anticipation(struct as_data *ad, struct request *rq)
+ 		if (aic->ttime_samples == 0)
+ 			ad->exit_prob = (7*ad->exit_prob + 256)/8;
+ 
+-		if (ad->exit_no_coop > 128)
++		if (ad->exit_no_coop > 128) {
++			spin_unlock(&ioc->lock);
+ 			return 1;
++		}
+ 	}
+ 
+ 	if (aic->ttime_samples == 0) {
+-		if (ad->new_ttime_mean > ad->antic_expire)
++		if (ad->new_ttime_mean > ad->antic_expire) {
++			spin_unlock(&ioc->lock);
+ 			return 1;
+-		if (ad->exit_prob * ad->exit_no_coop > 128*256)
++		}
++		if (ad->exit_prob * ad->exit_no_coop > 128*256) {
++			spin_unlock(&ioc->lock);
+ 			return 1;
++		}
+ 	} else if (aic->ttime_mean > ad->antic_expire) {
+ 		/* the process thinks too much between requests */
++		spin_unlock(&ioc->lock);
+ 		return 1;
+ 	}
+-
++	spin_unlock(&ioc->lock);
+ 	return 0;
+ }
+ 
+@@ -1255,7 +1275,9 @@ static void as_merged_requests(struct request_queue *q, struct request *req,
+ 			 * Don't copy here but swap, because when anext is
+ 			 * removed below, it must contain the unused context
+ 			 */
++			double_spin_lock(&rioc->lock, &nioc->lock, rioc < nioc);
+ 			swap_io_context(&rioc, &nioc);
++			double_spin_unlock(&rioc->lock, &nioc->lock, rioc < nioc);
+ 		}
+ 	}
+ 
+diff --git a/block/blktrace.c b/block/blktrace.c
+index 9b4da4a..568588c 100644
+--- a/block/blktrace.c
++++ b/block/blktrace.c
+@@ -235,7 +235,7 @@ static void blk_trace_cleanup(struct blk_trace *bt)
+ 	kfree(bt);
+ }
+ 
+-static int blk_trace_remove(struct request_queue *q)
++int blk_trace_remove(struct request_queue *q)
+ {
+ 	struct blk_trace *bt;
+ 
+@@ -249,6 +249,7 @@ static int blk_trace_remove(struct request_queue *q)
+ 
+ 	return 0;
+ }
++EXPORT_SYMBOL_GPL(blk_trace_remove);
+ 
+ static int blk_dropped_open(struct inode *inode, struct file *filp)
+ {
+@@ -316,18 +317,17 @@ static struct rchan_callbacks blk_relay_callbacks = {
+ /*
+  * Setup everything required to start tracing
+  */
+-int do_blk_trace_setup(struct request_queue *q, struct block_device *bdev,
++int do_blk_trace_setup(struct request_queue *q, char *name, dev_t dev,
+ 			struct blk_user_trace_setup *buts)
+ {
+ 	struct blk_trace *old_bt, *bt = NULL;
+ 	struct dentry *dir = NULL;
+-	char b[BDEVNAME_SIZE];
+ 	int ret, i;
+ 
+ 	if (!buts->buf_size || !buts->buf_nr)
+ 		return -EINVAL;
+ 
+-	strcpy(buts->name, bdevname(bdev, b));
++	strcpy(buts->name, name);
+ 
+ 	/*
+ 	 * some device names have larger paths - convert the slashes
+@@ -352,7 +352,7 @@ int do_blk_trace_setup(struct request_queue *q, struct block_device *bdev,
+ 		goto err;
+ 
+ 	bt->dir = dir;
+-	bt->dev = bdev->bd_dev;
++	bt->dev = dev;
+ 	atomic_set(&bt->dropped, 0);
+ 
+ 	ret = -EIO;
+@@ -399,8 +399,8 @@ err:
+ 	return ret;
+ }
+ 
+-static int blk_trace_setup(struct request_queue *q, struct block_device *bdev,
+-			   char __user *arg)
++int blk_trace_setup(struct request_queue *q, char *name, dev_t dev,
++		    char __user *arg)
+ {
+ 	struct blk_user_trace_setup buts;
+ 	int ret;
+@@ -409,7 +409,7 @@ static int blk_trace_setup(struct request_queue *q, struct block_device *bdev,
+ 	if (ret)
+ 		return -EFAULT;
+ 
+-	ret = do_blk_trace_setup(q, bdev, &buts);
++	ret = do_blk_trace_setup(q, name, dev, &buts);
+ 	if (ret)
+ 		return ret;
+ 
+@@ -418,8 +418,9 @@ static int blk_trace_setup(struct request_queue *q, struct block_device *bdev,
+ 
+ 	return 0;
+ }
++EXPORT_SYMBOL_GPL(blk_trace_setup);
+ 
+-static int blk_trace_startstop(struct request_queue *q, int start)
++int blk_trace_startstop(struct request_queue *q, int start)
+ {
+ 	struct blk_trace *bt;
+ 	int ret;
+@@ -452,6 +453,7 @@ static int blk_trace_startstop(struct request_queue *q, int start)
+ 
+ 	return ret;
+ }
++EXPORT_SYMBOL_GPL(blk_trace_startstop);
+ 
+ /**
+  * blk_trace_ioctl: - handle the ioctls associated with tracing
+@@ -464,6 +466,7 @@ int blk_trace_ioctl(struct block_device *bdev, unsigned cmd, char __user *arg)
+ {
+ 	struct request_queue *q;
+ 	int ret, start = 0;
++	char b[BDEVNAME_SIZE];
+ 
+ 	q = bdev_get_queue(bdev);
+ 	if (!q)
+@@ -473,7 +476,8 @@ int blk_trace_ioctl(struct block_device *bdev, unsigned cmd, char __user *arg)
+ 
+ 	switch (cmd) {
+ 	case BLKTRACESETUP:
+-		ret = blk_trace_setup(q, bdev, arg);
++		strcpy(b, bdevname(bdev, b));
++		ret = blk_trace_setup(q, b, bdev->bd_dev, arg);
+ 		break;
+ 	case BLKTRACESTART:
+ 		start = 1;
+diff --git a/block/bsg.c b/block/bsg.c
+index 8e181ab..69b0a9d 100644
+--- a/block/bsg.c
++++ b/block/bsg.c
+@@ -445,6 +445,15 @@ static int blk_complete_sgv4_hdr_rq(struct request *rq, struct sg_io_v4 *hdr,
+ 	else
+ 		hdr->dout_resid = rq->data_len;
+ 
++	/*
++	 * If the request generated a negative error number, return it
++	 * (providing we aren't already returning an error); if it's
++	 * just a protocol response (i.e. non negative), that gets
++	 * processed above.
++	 */
++	if (!ret && rq->errors < 0)
++		ret = rq->errors;
++
+ 	blk_rq_unmap_user(bio);
+ 	blk_put_request(rq);
+ 
+@@ -837,6 +846,7 @@ static long bsg_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+ {
+ 	struct bsg_device *bd = file->private_data;
+ 	int __user *uarg = (int __user *) arg;
++	int ret;
+ 
+ 	switch (cmd) {
+ 		/*
+@@ -889,12 +899,12 @@ static long bsg_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+ 		if (rq->next_rq)
+ 			bidi_bio = rq->next_rq->bio;
+ 		blk_execute_rq(bd->queue, NULL, rq, 0);
+-		blk_complete_sgv4_hdr_rq(rq, &hdr, bio, bidi_bio);
++		ret = blk_complete_sgv4_hdr_rq(rq, &hdr, bio, bidi_bio);
+ 
+ 		if (copy_to_user(uarg, &hdr, sizeof(hdr)))
+ 			return -EFAULT;
+ 
+-		return 0;
++		return ret;
+ 	}
+ 	/*
+ 	 * block device ioctls
+diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c
+index 13553e0..f28d1fb 100644
+--- a/block/cfq-iosched.c
++++ b/block/cfq-iosched.c
+@@ -26,9 +26,9 @@ static const int cfq_slice_async_rq = 2;
+ static int cfq_slice_idle = HZ / 125;
+ 
+ /*
+- * grace period before allowing idle class to get disk access
++ * offset from end of service tree
+  */
+-#define CFQ_IDLE_GRACE		(HZ / 10)
++#define CFQ_IDLE_DELAY		(HZ / 5)
+ 
+ /*
+  * below this threshold, we consider thinktime immediate
+@@ -98,8 +98,6 @@ struct cfq_data {
+ 	struct cfq_queue *async_cfqq[2][IOPRIO_BE_NR];
+ 	struct cfq_queue *async_idle_cfqq;
+ 
+-	struct timer_list idle_class_timer;
+-
+ 	sector_t last_position;
+ 	unsigned long last_end_request;
+ 
+@@ -199,8 +197,8 @@ CFQ_CFQQ_FNS(sync);
+ 
+ static void cfq_dispatch_insert(struct request_queue *, struct request *);
+ static struct cfq_queue *cfq_get_queue(struct cfq_data *, int,
+-				       struct task_struct *, gfp_t);
+-static struct cfq_io_context *cfq_cic_rb_lookup(struct cfq_data *,
++				       struct io_context *, gfp_t);
++static struct cfq_io_context *cfq_cic_lookup(struct cfq_data *,
+ 						struct io_context *);
+ 
+ static inline struct cfq_queue *cic_to_cfqq(struct cfq_io_context *cic,
+@@ -384,12 +382,15 @@ cfq_choose_req(struct cfq_data *cfqd, struct request *rq1, struct request *rq2)
+ /*
+  * The below is leftmost cache rbtree addon
+  */
+-static struct rb_node *cfq_rb_first(struct cfq_rb_root *root)
++static struct cfq_queue *cfq_rb_first(struct cfq_rb_root *root)
+ {
+ 	if (!root->left)
+ 		root->left = rb_first(&root->rb);
+ 
+-	return root->left;
++	if (root->left)
++		return rb_entry(root->left, struct cfq_queue, rb_node);
++
++	return NULL;
+ }
+ 
+ static void cfq_rb_erase(struct rb_node *n, struct cfq_rb_root *root)
+@@ -446,12 +447,20 @@ static unsigned long cfq_slice_offset(struct cfq_data *cfqd,
+ static void cfq_service_tree_add(struct cfq_data *cfqd,
+ 				    struct cfq_queue *cfqq, int add_front)
+ {
+-	struct rb_node **p = &cfqd->service_tree.rb.rb_node;
+-	struct rb_node *parent = NULL;
++	struct rb_node **p, *parent;
++	struct cfq_queue *__cfqq;
+ 	unsigned long rb_key;
+ 	int left;
+ 
+-	if (!add_front) {
++	if (cfq_class_idle(cfqq)) {
++		rb_key = CFQ_IDLE_DELAY;
++		parent = rb_last(&cfqd->service_tree.rb);
++		if (parent && parent != &cfqq->rb_node) {
++			__cfqq = rb_entry(parent, struct cfq_queue, rb_node);
++			rb_key += __cfqq->rb_key;
++		} else
++			rb_key += jiffies;
++	} else if (!add_front) {
+ 		rb_key = cfq_slice_offset(cfqd, cfqq) + jiffies;
+ 		rb_key += cfqq->slice_resid;
+ 		cfqq->slice_resid = 0;
+@@ -469,8 +478,9 @@ static void cfq_service_tree_add(struct cfq_data *cfqd,
+ 	}
+ 
+ 	left = 1;
++	parent = NULL;
++	p = &cfqd->service_tree.rb.rb_node;
+ 	while (*p) {
+-		struct cfq_queue *__cfqq;
+ 		struct rb_node **n;
+ 
+ 		parent = *p;
+@@ -524,8 +534,7 @@ static void cfq_resort_rr_list(struct cfq_data *cfqd, struct cfq_queue *cfqq)
+  * add to busy list of queues for service, trying to be fair in ordering
+  * the pending list according to last request service
+  */
+-static inline void
+-cfq_add_cfqq_rr(struct cfq_data *cfqd, struct cfq_queue *cfqq)
++static void cfq_add_cfqq_rr(struct cfq_data *cfqd, struct cfq_queue *cfqq)
+ {
+ 	BUG_ON(cfq_cfqq_on_rr(cfqq));
+ 	cfq_mark_cfqq_on_rr(cfqq);
+@@ -538,8 +547,7 @@ cfq_add_cfqq_rr(struct cfq_data *cfqd, struct cfq_queue *cfqq)
+  * Called when the cfqq no longer has requests pending, remove it from
+  * the service tree.
+  */
+-static inline void
+-cfq_del_cfqq_rr(struct cfq_data *cfqd, struct cfq_queue *cfqq)
++static void cfq_del_cfqq_rr(struct cfq_data *cfqd, struct cfq_queue *cfqq)
+ {
+ 	BUG_ON(!cfq_cfqq_on_rr(cfqq));
+ 	cfq_clear_cfqq_on_rr(cfqq);
+@@ -554,7 +562,7 @@ cfq_del_cfqq_rr(struct cfq_data *cfqd, struct cfq_queue *cfqq)
+ /*
+  * rb tree support functions
+  */
+-static inline void cfq_del_rq_rb(struct request *rq)
++static void cfq_del_rq_rb(struct request *rq)
+ {
+ 	struct cfq_queue *cfqq = RQ_CFQQ(rq);
+ 	struct cfq_data *cfqd = cfqq->cfqd;
+@@ -594,8 +602,7 @@ static void cfq_add_rq_rb(struct request *rq)
+ 	BUG_ON(!cfqq->next_rq);
+ }
+ 
+-static inline void
+-cfq_reposition_rq_rb(struct cfq_queue *cfqq, struct request *rq)
++static void cfq_reposition_rq_rb(struct cfq_queue *cfqq, struct request *rq)
+ {
+ 	elv_rb_del(&cfqq->sort_list, rq);
+ 	cfqq->queued[rq_is_sync(rq)]--;
+@@ -609,7 +616,7 @@ cfq_find_rq_fmerge(struct cfq_data *cfqd, struct bio *bio)
+ 	struct cfq_io_context *cic;
+ 	struct cfq_queue *cfqq;
+ 
+-	cic = cfq_cic_rb_lookup(cfqd, tsk->io_context);
++	cic = cfq_cic_lookup(cfqd, tsk->io_context);
+ 	if (!cic)
+ 		return NULL;
+ 
+@@ -721,7 +728,7 @@ static int cfq_allow_merge(struct request_queue *q, struct request *rq,
+ 	 * Lookup the cfqq that this bio will be queued with. Allow
+ 	 * merge only if rq is queued there.
+ 	 */
+-	cic = cfq_cic_rb_lookup(cfqd, current->io_context);
++	cic = cfq_cic_lookup(cfqd, current->io_context);
+ 	if (!cic)
+ 		return 0;
+ 
+@@ -732,15 +739,10 @@ static int cfq_allow_merge(struct request_queue *q, struct request *rq,
+ 	return 0;
+ }
+ 
+-static inline void
+-__cfq_set_active_queue(struct cfq_data *cfqd, struct cfq_queue *cfqq)
++static void __cfq_set_active_queue(struct cfq_data *cfqd,
++				   struct cfq_queue *cfqq)
+ {
+ 	if (cfqq) {
+-		/*
+-		 * stop potential idle class queues waiting service
+-		 */
+-		del_timer(&cfqd->idle_class_timer);
+-
+ 		cfqq->slice_end = 0;
+ 		cfq_clear_cfqq_must_alloc_slice(cfqq);
+ 		cfq_clear_cfqq_fifo_expire(cfqq);
+@@ -789,47 +791,16 @@ static inline void cfq_slice_expired(struct cfq_data *cfqd, int timed_out)
+ 		__cfq_slice_expired(cfqd, cfqq, timed_out);
+ }
+ 
+-static int start_idle_class_timer(struct cfq_data *cfqd)
+-{
+-	unsigned long end = cfqd->last_end_request + CFQ_IDLE_GRACE;
+-	unsigned long now = jiffies;
+-
+-	if (time_before(now, end) &&
+-	    time_after_eq(now, cfqd->last_end_request)) {
+-		mod_timer(&cfqd->idle_class_timer, end);
+-		return 1;
+-	}
+-
+-	return 0;
+-}
+-
+ /*
+  * Get next queue for service. Unless we have a queue preemption,
+  * we'll simply select the first cfqq in the service tree.
+  */
+ static struct cfq_queue *cfq_get_next_queue(struct cfq_data *cfqd)
+ {
+-	struct cfq_queue *cfqq;
+-	struct rb_node *n;
+-
+ 	if (RB_EMPTY_ROOT(&cfqd->service_tree.rb))
+ 		return NULL;
+ 
+-	n = cfq_rb_first(&cfqd->service_tree);
+-	cfqq = rb_entry(n, struct cfq_queue, rb_node);
+-
+-	if (cfq_class_idle(cfqq)) {
+-		/*
+-		 * if we have idle queues and no rt or be queues had
+-		 * pending requests, either allow immediate service if
+-		 * the grace period has passed or arm the idle grace
+-		 * timer
+-		 */
+-		if (start_idle_class_timer(cfqd))
+-			cfqq = NULL;
+-	}
+-
+-	return cfqq;
++	return cfq_rb_first(&cfqd->service_tree);
+ }
+ 
+ /*
+@@ -895,7 +866,7 @@ static void cfq_arm_slice_timer(struct cfq_data *cfqd)
+ 	 * task has exited, don't wait
+ 	 */
+ 	cic = cfqd->active_cic;
+-	if (!cic || !cic->ioc->task)
++	if (!cic || !atomic_read(&cic->ioc->nr_tasks))
+ 		return;
+ 
+ 	/*
+@@ -939,7 +910,7 @@ static void cfq_dispatch_insert(struct request_queue *q, struct request *rq)
+ /*
+  * return expired entry, or NULL to just start from scratch in rbtree
+  */
+-static inline struct request *cfq_check_fifo(struct cfq_queue *cfqq)
++static struct request *cfq_check_fifo(struct cfq_queue *cfqq)
+ {
+ 	struct cfq_data *cfqd = cfqq->cfqd;
+ 	struct request *rq;
+@@ -1068,7 +1039,7 @@ __cfq_dispatch_requests(struct cfq_data *cfqd, struct cfq_queue *cfqq,
+ 	return dispatched;
+ }
+ 
+-static inline int __cfq_forced_dispatch_cfqq(struct cfq_queue *cfqq)
++static int __cfq_forced_dispatch_cfqq(struct cfq_queue *cfqq)
+ {
+ 	int dispatched = 0;
+ 
+@@ -1087,14 +1058,11 @@ static inline int __cfq_forced_dispatch_cfqq(struct cfq_queue *cfqq)
+  */
+ static int cfq_forced_dispatch(struct cfq_data *cfqd)
+ {
++	struct cfq_queue *cfqq;
+ 	int dispatched = 0;
+-	struct rb_node *n;
+-
+-	while ((n = cfq_rb_first(&cfqd->service_tree)) != NULL) {
+-		struct cfq_queue *cfqq = rb_entry(n, struct cfq_queue, rb_node);
+ 
++	while ((cfqq = cfq_rb_first(&cfqd->service_tree)) != NULL)
+ 		dispatched += __cfq_forced_dispatch_cfqq(cfqq);
+-	}
+ 
+ 	cfq_slice_expired(cfqd, 0);
+ 
+@@ -1170,20 +1138,69 @@ static void cfq_put_queue(struct cfq_queue *cfqq)
+ 	kmem_cache_free(cfq_pool, cfqq);
+ }
+ 
+-static void cfq_free_io_context(struct io_context *ioc)
++/*
++ * Call func for each cic attached to this ioc. Returns number of cic's seen.
++ */
++#define CIC_GANG_NR	16
++static unsigned int
++call_for_each_cic(struct io_context *ioc,
++		  void (*func)(struct io_context *, struct cfq_io_context *))
+ {
+-	struct cfq_io_context *__cic;
+-	struct rb_node *n;
+-	int freed = 0;
++	struct cfq_io_context *cics[CIC_GANG_NR];
++	unsigned long index = 0;
++	unsigned int called = 0;
++	int nr;
+ 
+-	ioc->ioc_data = NULL;
++	rcu_read_lock();
+ 
+-	while ((n = rb_first(&ioc->cic_root)) != NULL) {
+-		__cic = rb_entry(n, struct cfq_io_context, rb_node);
+-		rb_erase(&__cic->rb_node, &ioc->cic_root);
+-		kmem_cache_free(cfq_ioc_pool, __cic);
+-		freed++;
+-	}
++	do {
++		int i;
++
++		/*
++		 * Perhaps there's a better way - this just gang lookups from
++		 * 0 to the end, restarting after each CIC_GANG_NR from the
++		 * last key + 1.
++		 */
++		nr = radix_tree_gang_lookup(&ioc->radix_root, (void **) cics,
++						index, CIC_GANG_NR);
++		if (!nr)
++			break;
++
++		called += nr;
++		index = 1 + (unsigned long) cics[nr - 1]->key;
++
++		for (i = 0; i < nr; i++)
++			func(ioc, cics[i]);
++	} while (nr == CIC_GANG_NR);
++
++	rcu_read_unlock();
++
++	return called;
++}
++
++static void cic_free_func(struct io_context *ioc, struct cfq_io_context *cic)
++{
++	unsigned long flags;
++
++	BUG_ON(!cic->dead_key);
++
++	spin_lock_irqsave(&ioc->lock, flags);
++	radix_tree_delete(&ioc->radix_root, cic->dead_key);
++	spin_unlock_irqrestore(&ioc->lock, flags);
++
++	kmem_cache_free(cfq_ioc_pool, cic);
++}
++
++static void cfq_free_io_context(struct io_context *ioc)
++{
++	int freed;
++
++	/*
++	 * ioc->refcount is zero here, so no more cic's are allowed to be
++	 * linked into this ioc. So it should be ok to iterate over the known
++	 * list, we will see all cic's since no new ones are added.
++	 */
++	freed = call_for_each_cic(ioc, cic_free_func);
+ 
+ 	elv_ioc_count_mod(ioc_count, -freed);
+ 
+@@ -1205,7 +1222,12 @@ static void __cfq_exit_single_io_context(struct cfq_data *cfqd,
+ 					 struct cfq_io_context *cic)
+ {
+ 	list_del_init(&cic->queue_list);
++
++	/*
++	 * Make sure key == NULL is seen for dead queues
++	 */
+ 	smp_wmb();
++	cic->dead_key = (unsigned long) cic->key;
+ 	cic->key = NULL;
+ 
+ 	if (cic->cfqq[ASYNC]) {
+@@ -1219,16 +1241,18 @@ static void __cfq_exit_single_io_context(struct cfq_data *cfqd,
+ 	}
+ }
+ 
+-static void cfq_exit_single_io_context(struct cfq_io_context *cic)
++static void cfq_exit_single_io_context(struct io_context *ioc,
++				       struct cfq_io_context *cic)
+ {
+ 	struct cfq_data *cfqd = cic->key;
+ 
+ 	if (cfqd) {
+ 		struct request_queue *q = cfqd->queue;
++		unsigned long flags;
+ 
+-		spin_lock_irq(q->queue_lock);
++		spin_lock_irqsave(q->queue_lock, flags);
+ 		__cfq_exit_single_io_context(cfqd, cic);
+-		spin_unlock_irq(q->queue_lock);
++		spin_unlock_irqrestore(q->queue_lock, flags);
+ 	}
+ }
+ 
+@@ -1238,21 +1262,8 @@ static void cfq_exit_single_io_context(struct cfq_io_context *cic)
+  */
+ static void cfq_exit_io_context(struct io_context *ioc)
+ {
+-	struct cfq_io_context *__cic;
+-	struct rb_node *n;
+-
+-	ioc->ioc_data = NULL;
+-
+-	/*
+-	 * put the reference this task is holding to the various queues
+-	 */
+-	n = rb_first(&ioc->cic_root);
+-	while (n != NULL) {
+-		__cic = rb_entry(n, struct cfq_io_context, rb_node);
+-
+-		cfq_exit_single_io_context(__cic);
+-		n = rb_next(n);
+-	}
++	rcu_assign_pointer(ioc->ioc_data, NULL);
++	call_for_each_cic(ioc, cfq_exit_single_io_context);
+ }
+ 
+ static struct cfq_io_context *
+@@ -1273,7 +1284,7 @@ cfq_alloc_io_context(struct cfq_data *cfqd, gfp_t gfp_mask)
+ 	return cic;
+ }
+ 
+-static void cfq_init_prio_data(struct cfq_queue *cfqq)
++static void cfq_init_prio_data(struct cfq_queue *cfqq, struct io_context *ioc)
+ {
+ 	struct task_struct *tsk = current;
+ 	int ioprio_class;
+@@ -1281,7 +1292,7 @@ static void cfq_init_prio_data(struct cfq_queue *cfqq)
+ 	if (!cfq_cfqq_prio_changed(cfqq))
+ 		return;
+ 
+-	ioprio_class = IOPRIO_PRIO_CLASS(tsk->ioprio);
++	ioprio_class = IOPRIO_PRIO_CLASS(ioc->ioprio);
+ 	switch (ioprio_class) {
+ 		default:
+ 			printk(KERN_ERR "cfq: bad prio %x\n", ioprio_class);
+@@ -1293,11 +1304,11 @@ static void cfq_init_prio_data(struct cfq_queue *cfqq)
+ 			cfqq->ioprio_class = IOPRIO_CLASS_BE;
+ 			break;
+ 		case IOPRIO_CLASS_RT:
+-			cfqq->ioprio = task_ioprio(tsk);
++			cfqq->ioprio = task_ioprio(ioc);
+ 			cfqq->ioprio_class = IOPRIO_CLASS_RT;
+ 			break;
+ 		case IOPRIO_CLASS_BE:
+-			cfqq->ioprio = task_ioprio(tsk);
++			cfqq->ioprio = task_ioprio(ioc);
+ 			cfqq->ioprio_class = IOPRIO_CLASS_BE;
+ 			break;
+ 		case IOPRIO_CLASS_IDLE:
+@@ -1316,7 +1327,7 @@ static void cfq_init_prio_data(struct cfq_queue *cfqq)
+ 	cfq_clear_cfqq_prio_changed(cfqq);
+ }
+ 
+-static inline void changed_ioprio(struct cfq_io_context *cic)
++static void changed_ioprio(struct io_context *ioc, struct cfq_io_context *cic)
+ {
+ 	struct cfq_data *cfqd = cic->key;
+ 	struct cfq_queue *cfqq;
+@@ -1330,8 +1341,7 @@ static inline void changed_ioprio(struct cfq_io_context *cic)
+ 	cfqq = cic->cfqq[ASYNC];
+ 	if (cfqq) {
+ 		struct cfq_queue *new_cfqq;
+-		new_cfqq = cfq_get_queue(cfqd, ASYNC, cic->ioc->task,
+-					 GFP_ATOMIC);
++		new_cfqq = cfq_get_queue(cfqd, ASYNC, cic->ioc, GFP_ATOMIC);
+ 		if (new_cfqq) {
+ 			cic->cfqq[ASYNC] = new_cfqq;
+ 			cfq_put_queue(cfqq);
+@@ -1347,29 +1357,19 @@ static inline void changed_ioprio(struct cfq_io_context *cic)
+ 
+ static void cfq_ioc_set_ioprio(struct io_context *ioc)
+ {
+-	struct cfq_io_context *cic;
+-	struct rb_node *n;
+-
++	call_for_each_cic(ioc, changed_ioprio);
+ 	ioc->ioprio_changed = 0;
+-
+-	n = rb_first(&ioc->cic_root);
+-	while (n != NULL) {
+-		cic = rb_entry(n, struct cfq_io_context, rb_node);
+-
+-		changed_ioprio(cic);
+-		n = rb_next(n);
+-	}
+ }
+ 
+ static struct cfq_queue *
+ cfq_find_alloc_queue(struct cfq_data *cfqd, int is_sync,
+-		     struct task_struct *tsk, gfp_t gfp_mask)
++		     struct io_context *ioc, gfp_t gfp_mask)
+ {
+ 	struct cfq_queue *cfqq, *new_cfqq = NULL;
+ 	struct cfq_io_context *cic;
+ 
+ retry:
+-	cic = cfq_cic_rb_lookup(cfqd, tsk->io_context);
++	cic = cfq_cic_lookup(cfqd, ioc);
+ 	/* cic always exists here */
+ 	cfqq = cic_to_cfqq(cic, is_sync);
+ 
+@@ -1404,15 +1404,16 @@ retry:
+ 		atomic_set(&cfqq->ref, 0);
+ 		cfqq->cfqd = cfqd;
+ 
+-		if (is_sync) {
+-			cfq_mark_cfqq_idle_window(cfqq);
+-			cfq_mark_cfqq_sync(cfqq);
+-		}
+-
+ 		cfq_mark_cfqq_prio_changed(cfqq);
+ 		cfq_mark_cfqq_queue_new(cfqq);
+ 
+-		cfq_init_prio_data(cfqq);
++		cfq_init_prio_data(cfqq, ioc);
++
++		if (is_sync) {
++			if (!cfq_class_idle(cfqq))
++				cfq_mark_cfqq_idle_window(cfqq);
++			cfq_mark_cfqq_sync(cfqq);
++		}
+ 	}
+ 
+ 	if (new_cfqq)
+@@ -1439,11 +1440,11 @@ cfq_async_queue_prio(struct cfq_data *cfqd, int ioprio_class, int ioprio)
+ }
+ 
+ static struct cfq_queue *
+-cfq_get_queue(struct cfq_data *cfqd, int is_sync, struct task_struct *tsk,
++cfq_get_queue(struct cfq_data *cfqd, int is_sync, struct io_context *ioc,
+ 	      gfp_t gfp_mask)
+ {
+-	const int ioprio = task_ioprio(tsk);
+-	const int ioprio_class = task_ioprio_class(tsk);
++	const int ioprio = task_ioprio(ioc);
++	const int ioprio_class = task_ioprio_class(ioc);
+ 	struct cfq_queue **async_cfqq = NULL;
+ 	struct cfq_queue *cfqq = NULL;
+ 
+@@ -1453,7 +1454,7 @@ cfq_get_queue(struct cfq_data *cfqd, int is_sync, struct task_struct *tsk,
+ 	}
+ 
+ 	if (!cfqq) {
+-		cfqq = cfq_find_alloc_queue(cfqd, is_sync, tsk, gfp_mask);
++		cfqq = cfq_find_alloc_queue(cfqd, is_sync, ioc, gfp_mask);
+ 		if (!cfqq)
+ 			return NULL;
+ 	}
+@@ -1470,28 +1471,42 @@ cfq_get_queue(struct cfq_data *cfqd, int is_sync, struct task_struct *tsk,
+ 	return cfqq;
+ }
+ 
++static void cfq_cic_free(struct cfq_io_context *cic)
++{
++	kmem_cache_free(cfq_ioc_pool, cic);
++	elv_ioc_count_dec(ioc_count);
++
++	if (ioc_gone && !elv_ioc_count_read(ioc_count))
++		complete(ioc_gone);
++}
++
+ /*
+  * We drop cfq io contexts lazily, so we may find a dead one.
+  */
+ static void
+-cfq_drop_dead_cic(struct io_context *ioc, struct cfq_io_context *cic)
++cfq_drop_dead_cic(struct cfq_data *cfqd, struct io_context *ioc,
++		  struct cfq_io_context *cic)
+ {
++	unsigned long flags;
++
+ 	WARN_ON(!list_empty(&cic->queue_list));
+ 
++	spin_lock_irqsave(&ioc->lock, flags);
++
+ 	if (ioc->ioc_data == cic)
+-		ioc->ioc_data = NULL;
++		rcu_assign_pointer(ioc->ioc_data, NULL);
+ 
+-	rb_erase(&cic->rb_node, &ioc->cic_root);
+-	kmem_cache_free(cfq_ioc_pool, cic);
+-	elv_ioc_count_dec(ioc_count);
++	radix_tree_delete(&ioc->radix_root, (unsigned long) cfqd);
++	spin_unlock_irqrestore(&ioc->lock, flags);
++
++	cfq_cic_free(cic);
+ }
+ 
+ static struct cfq_io_context *
+-cfq_cic_rb_lookup(struct cfq_data *cfqd, struct io_context *ioc)
++cfq_cic_lookup(struct cfq_data *cfqd, struct io_context *ioc)
+ {
+-	struct rb_node *n;
+ 	struct cfq_io_context *cic;
+-	void *k, *key = cfqd;
++	void *k;
+ 
+ 	if (unlikely(!ioc))
+ 		return NULL;
+@@ -1499,74 +1514,64 @@ cfq_cic_rb_lookup(struct cfq_data *cfqd, struct io_context *ioc)
+ 	/*
+ 	 * we maintain a last-hit cache, to avoid browsing over the tree
+ 	 */
+-	cic = ioc->ioc_data;
++	cic = rcu_dereference(ioc->ioc_data);
+ 	if (cic && cic->key == cfqd)
+ 		return cic;
+ 
+-restart:
+-	n = ioc->cic_root.rb_node;
+-	while (n) {
+-		cic = rb_entry(n, struct cfq_io_context, rb_node);
++	do {
++		rcu_read_lock();
++		cic = radix_tree_lookup(&ioc->radix_root, (unsigned long) cfqd);
++		rcu_read_unlock();
++		if (!cic)
++			break;
+ 		/* ->key must be copied to avoid race with cfq_exit_queue() */
+ 		k = cic->key;
+ 		if (unlikely(!k)) {
+-			cfq_drop_dead_cic(ioc, cic);
+-			goto restart;
++			cfq_drop_dead_cic(cfqd, ioc, cic);
++			continue;
+ 		}
+ 
+-		if (key < k)
+-			n = n->rb_left;
+-		else if (key > k)
+-			n = n->rb_right;
+-		else {
+-			ioc->ioc_data = cic;
+-			return cic;
+-		}
+-	}
++		rcu_assign_pointer(ioc->ioc_data, cic);
++		break;
++	} while (1);
+ 
+-	return NULL;
++	return cic;
+ }
+ 
+-static inline void
+-cfq_cic_link(struct cfq_data *cfqd, struct io_context *ioc,
+-	     struct cfq_io_context *cic)
++/*
++ * Add cic into ioc, using cfqd as the search key. This enables us to lookup
++ * the process specific cfq io context when entered from the block layer.
++ * Also adds the cic to a per-cfqd list, used when this queue is removed.
++ */
++static int cfq_cic_link(struct cfq_data *cfqd, struct io_context *ioc,
++			struct cfq_io_context *cic, gfp_t gfp_mask)
+ {
+-	struct rb_node **p;
+-	struct rb_node *parent;
+-	struct cfq_io_context *__cic;
+ 	unsigned long flags;
+-	void *k;
++	int ret;
+ 
+-	cic->ioc = ioc;
+-	cic->key = cfqd;
++	ret = radix_tree_preload(gfp_mask);
++	if (!ret) {
++		cic->ioc = ioc;
++		cic->key = cfqd;
+ 
+-restart:
+-	parent = NULL;
+-	p = &ioc->cic_root.rb_node;
+-	while (*p) {
+-		parent = *p;
+-		__cic = rb_entry(parent, struct cfq_io_context, rb_node);
+-		/* ->key must be copied to avoid race with cfq_exit_queue() */
+-		k = __cic->key;
+-		if (unlikely(!k)) {
+-			cfq_drop_dead_cic(ioc, __cic);
+-			goto restart;
+-		}
++		spin_lock_irqsave(&ioc->lock, flags);
++		ret = radix_tree_insert(&ioc->radix_root,
++						(unsigned long) cfqd, cic);
++		spin_unlock_irqrestore(&ioc->lock, flags);
+ 
+-		if (cic->key < k)
+-			p = &(*p)->rb_left;
+-		else if (cic->key > k)
+-			p = &(*p)->rb_right;
+-		else
+-			BUG();
++		radix_tree_preload_end();
++
++		if (!ret) {
++			spin_lock_irqsave(cfqd->queue->queue_lock, flags);
++			list_add(&cic->queue_list, &cfqd->cic_list);
++			spin_unlock_irqrestore(cfqd->queue->queue_lock, flags);
++		}
+ 	}
+ 
+-	rb_link_node(&cic->rb_node, parent, p);
+-	rb_insert_color(&cic->rb_node, &ioc->cic_root);
++	if (ret)
++		printk(KERN_ERR "cfq: cic link failed!\n");
+ 
+-	spin_lock_irqsave(cfqd->queue->queue_lock, flags);
+-	list_add(&cic->queue_list, &cfqd->cic_list);
+-	spin_unlock_irqrestore(cfqd->queue->queue_lock, flags);
++	return ret;
  }
- EXPORT_SYMBOL(save_stack_trace);
-+
-+void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
-+{
-+	dump_trace(tsk, NULL, NULL, &save_stack_ops_nosched, trace);
-+	if (trace->nr_entries < trace->max_entries)
-+		trace->entries[trace->nr_entries++] = ULONG_MAX;
-+}
-diff --git a/arch/x86/oprofile/nmi_int.c b/arch/x86/oprofile/nmi_int.c
-index 944bbcd..c8ab79e 100644
---- a/arch/x86/oprofile/nmi_int.c
-+++ b/arch/x86/oprofile/nmi_int.c
-@@ -51,7 +51,7 @@ static int nmi_resume(struct sys_device *dev)
  
+ /*
+@@ -1586,7 +1591,7 @@ cfq_get_io_context(struct cfq_data *cfqd, gfp_t gfp_mask)
+ 	if (!ioc)
+ 		return NULL;
  
- static struct sysdev_class oprofile_sysclass = {
--	set_kset_name("oprofile"),
-+	.name		= "oprofile",
- 	.resume		= nmi_resume,
- 	.suspend	= nmi_suspend,
- };
-diff --git a/block/bsg.c b/block/bsg.c
-index 8e181ab..69b0a9d 100644
---- a/block/bsg.c
-+++ b/block/bsg.c
-@@ -445,6 +445,15 @@ static int blk_complete_sgv4_hdr_rq(struct request *rq, struct sg_io_v4 *hdr,
- 	else
- 		hdr->dout_resid = rq->data_len;
+-	cic = cfq_cic_rb_lookup(cfqd, ioc);
++	cic = cfq_cic_lookup(cfqd, ioc);
+ 	if (cic)
+ 		goto out;
+ 
+@@ -1594,13 +1599,17 @@ cfq_get_io_context(struct cfq_data *cfqd, gfp_t gfp_mask)
+ 	if (cic == NULL)
+ 		goto err;
+ 
+-	cfq_cic_link(cfqd, ioc, cic);
++	if (cfq_cic_link(cfqd, ioc, cic, gfp_mask))
++		goto err_free;
++
+ out:
+ 	smp_read_barrier_depends();
+ 	if (unlikely(ioc->ioprio_changed))
+ 		cfq_ioc_set_ioprio(ioc);
  
+ 	return cic;
++err_free:
++	cfq_cic_free(cic);
+ err:
+ 	put_io_context(ioc);
+ 	return NULL;
+@@ -1655,12 +1664,15 @@ cfq_update_idle_window(struct cfq_data *cfqd, struct cfq_queue *cfqq,
+ {
+ 	int enable_idle;
+ 
+-	if (!cfq_cfqq_sync(cfqq))
 +	/*
-+	 * If the request generated a negative error number, return it
-+	 * (providing we aren't already returning an error); if it's
-+	 * just a protocol response (i.e. non negative), that gets
-+	 * processed above.
++	 * Don't idle for async or idle io prio class
 +	 */
-+	if (!ret && rq->errors < 0)
-+		ret = rq->errors;
-+
- 	blk_rq_unmap_user(bio);
- 	blk_put_request(rq);
++	if (!cfq_cfqq_sync(cfqq) || cfq_class_idle(cfqq))
+ 		return;
  
-@@ -837,6 +846,7 @@ static long bsg_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+ 	enable_idle = cfq_cfqq_idle_window(cfqq);
+ 
+-	if (!cic->ioc->task || !cfqd->cfq_slice_idle ||
++	if (!atomic_read(&cic->ioc->nr_tasks) || !cfqd->cfq_slice_idle ||
+ 	    (cfqd->hw_tag && CIC_SEEKY(cic)))
+ 		enable_idle = 0;
+ 	else if (sample_valid(cic->ttime_samples)) {
+@@ -1793,7 +1805,7 @@ static void cfq_insert_request(struct request_queue *q, struct request *rq)
+ 	struct cfq_data *cfqd = q->elevator->elevator_data;
+ 	struct cfq_queue *cfqq = RQ_CFQQ(rq);
+ 
+-	cfq_init_prio_data(cfqq);
++	cfq_init_prio_data(cfqq, RQ_CIC(rq)->ioc);
+ 
+ 	cfq_add_rq_rb(rq);
+ 
+@@ -1834,7 +1846,7 @@ static void cfq_completed_request(struct request_queue *q, struct request *rq)
+ 			cfq_set_prio_slice(cfqd, cfqq);
+ 			cfq_clear_cfqq_slice_new(cfqq);
+ 		}
+-		if (cfq_slice_used(cfqq))
++		if (cfq_slice_used(cfqq) || cfq_class_idle(cfqq))
+ 			cfq_slice_expired(cfqd, 1);
+ 		else if (sync && RB_EMPTY_ROOT(&cfqq->sort_list))
+ 			cfq_arm_slice_timer(cfqd);
+@@ -1894,13 +1906,13 @@ static int cfq_may_queue(struct request_queue *q, int rw)
+ 	 * so just lookup a possibly existing queue, or return 'may queue'
+ 	 * if that fails
+ 	 */
+-	cic = cfq_cic_rb_lookup(cfqd, tsk->io_context);
++	cic = cfq_cic_lookup(cfqd, tsk->io_context);
+ 	if (!cic)
+ 		return ELV_MQUEUE_MAY;
+ 
+ 	cfqq = cic_to_cfqq(cic, rw & REQ_RW_SYNC);
+ 	if (cfqq) {
+-		cfq_init_prio_data(cfqq);
++		cfq_init_prio_data(cfqq, cic->ioc);
+ 		cfq_prio_boost(cfqq);
+ 
+ 		return __cfq_may_queue(cfqq);
+@@ -1938,7 +1950,6 @@ static int
+ cfq_set_request(struct request_queue *q, struct request *rq, gfp_t gfp_mask)
  {
- 	struct bsg_device *bd = file->private_data;
- 	int __user *uarg = (int __user *) arg;
-+	int ret;
+ 	struct cfq_data *cfqd = q->elevator->elevator_data;
+-	struct task_struct *tsk = current;
+ 	struct cfq_io_context *cic;
+ 	const int rw = rq_data_dir(rq);
+ 	const int is_sync = rq_is_sync(rq);
+@@ -1956,7 +1967,7 @@ cfq_set_request(struct request_queue *q, struct request *rq, gfp_t gfp_mask)
+ 
+ 	cfqq = cic_to_cfqq(cic, is_sync);
+ 	if (!cfqq) {
+-		cfqq = cfq_get_queue(cfqd, is_sync, tsk, gfp_mask);
++		cfqq = cfq_get_queue(cfqd, is_sync, cic->ioc, gfp_mask);
+ 
+ 		if (!cfqq)
+ 			goto queue_fail;
+@@ -2039,29 +2050,9 @@ out_cont:
+ 	spin_unlock_irqrestore(cfqd->queue->queue_lock, flags);
+ }
  
- 	switch (cmd) {
- 		/*
-@@ -889,12 +899,12 @@ static long bsg_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
- 		if (rq->next_rq)
- 			bidi_bio = rq->next_rq->bio;
- 		blk_execute_rq(bd->queue, NULL, rq, 0);
--		blk_complete_sgv4_hdr_rq(rq, &hdr, bio, bidi_bio);
-+		ret = blk_complete_sgv4_hdr_rq(rq, &hdr, bio, bidi_bio);
+-/*
+- * Timer running if an idle class queue is waiting for service
+- */
+-static void cfq_idle_class_timer(unsigned long data)
+-{
+-	struct cfq_data *cfqd = (struct cfq_data *) data;
+-	unsigned long flags;
+-
+-	spin_lock_irqsave(cfqd->queue->queue_lock, flags);
+-
+-	/*
+-	 * race with a non-idle queue, reset timer
+-	 */
+-	if (!start_idle_class_timer(cfqd))
+-		cfq_schedule_dispatch(cfqd);
+-
+-	spin_unlock_irqrestore(cfqd->queue->queue_lock, flags);
+-}
+-
+ static void cfq_shutdown_timer_wq(struct cfq_data *cfqd)
+ {
+ 	del_timer_sync(&cfqd->idle_slice_timer);
+-	del_timer_sync(&cfqd->idle_class_timer);
+ 	kblockd_flush_work(&cfqd->unplug_work);
+ }
  
- 		if (copy_to_user(uarg, &hdr, sizeof(hdr)))
- 			return -EFAULT;
+@@ -2126,10 +2117,6 @@ static void *cfq_init_queue(struct request_queue *q)
+ 	cfqd->idle_slice_timer.function = cfq_idle_slice_timer;
+ 	cfqd->idle_slice_timer.data = (unsigned long) cfqd;
  
--		return 0;
-+		return ret;
- 	}
- 	/*
- 	 * block device ioctls
+-	init_timer(&cfqd->idle_class_timer);
+-	cfqd->idle_class_timer.function = cfq_idle_class_timer;
+-	cfqd->idle_class_timer.data = (unsigned long) cfqd;
+-
+ 	INIT_WORK(&cfqd->unplug_work, cfq_kick_queue);
+ 
+ 	cfqd->last_end_request = jiffies;
+@@ -2160,7 +2147,7 @@ static int __init cfq_slab_setup(void)
+ 	if (!cfq_pool)
+ 		goto fail;
+ 
+-	cfq_ioc_pool = KMEM_CACHE(cfq_io_context, 0);
++	cfq_ioc_pool = KMEM_CACHE(cfq_io_context, SLAB_DESTROY_BY_RCU);
+ 	if (!cfq_ioc_pool)
+ 		goto fail;
+ 
+diff --git a/block/compat_ioctl.c b/block/compat_ioctl.c
+index cae0a85..b733732 100644
+--- a/block/compat_ioctl.c
++++ b/block/compat_ioctl.c
+@@ -545,6 +545,7 @@ static int compat_blk_trace_setup(struct block_device *bdev, char __user *arg)
+ 	struct blk_user_trace_setup buts;
+ 	struct compat_blk_user_trace_setup cbuts;
+ 	struct request_queue *q;
++	char b[BDEVNAME_SIZE];
+ 	int ret;
+ 
+ 	q = bdev_get_queue(bdev);
+@@ -554,6 +555,8 @@ static int compat_blk_trace_setup(struct block_device *bdev, char __user *arg)
+ 	if (copy_from_user(&cbuts, arg, sizeof(cbuts)))
+ 		return -EFAULT;
+ 
++	strcpy(b, bdevname(bdev, b));
++
+ 	buts = (struct blk_user_trace_setup) {
+ 		.act_mask = cbuts.act_mask,
+ 		.buf_size = cbuts.buf_size,
+@@ -565,7 +568,7 @@ static int compat_blk_trace_setup(struct block_device *bdev, char __user *arg)
+ 	memcpy(&buts.name, &cbuts.name, 32);
+ 
+ 	mutex_lock(&bdev->bd_mutex);
+-	ret = do_blk_trace_setup(q, bdev, &buts);
++	ret = do_blk_trace_setup(q, b, bdev->bd_dev, &buts);
+ 	mutex_unlock(&bdev->bd_mutex);
+ 	if (ret)
+ 		return ret;
 diff --git a/block/elevator.c b/block/elevator.c
-index e452deb..f9736fb 100644
+index e452deb..8cd5775 100644
 --- a/block/elevator.c
 +++ b/block/elevator.c
 @@ -185,9 +185,7 @@ static elevator_t *elevator_alloc(struct request_queue *q,
@@ -31696,7 +122671,47 @@
  	mutex_init(&eq->sysfs_lock);
  
  	eq->hash = kmalloc_node(sizeof(struct hlist_head) * ELV_HASH_ENTRIES,
-@@ -931,9 +929,7 @@ int elv_register_queue(struct request_queue *q)
+@@ -743,7 +741,21 @@ struct request *elv_next_request(struct request_queue *q)
+ 			q->boundary_rq = NULL;
+ 		}
+ 
+-		if ((rq->cmd_flags & REQ_DONTPREP) || !q->prep_rq_fn)
++		if (rq->cmd_flags & REQ_DONTPREP)
++			break;
++
++		if (q->dma_drain_size && rq->data_len) {
++			/*
++			 * make sure space for the drain appears we
++			 * know we can do this because max_hw_segments
++			 * has been adjusted to be one fewer than the
++			 * device can handle
++			 */
++			rq->nr_phys_segments++;
++			rq->nr_hw_segments++;
++		}
++
++		if (!q->prep_rq_fn)
+ 			break;
+ 
+ 		ret = q->prep_rq_fn(q, rq);
+@@ -756,6 +768,16 @@ struct request *elv_next_request(struct request_queue *q)
+ 			 * avoid resource deadlock.  REQ_STARTED will
+ 			 * prevent other fs requests from passing this one.
+ 			 */
++			if (q->dma_drain_size && rq->data_len &&
++			    !(rq->cmd_flags & REQ_DONTPREP)) {
++				/*
++				 * remove the space for the drain we added
++				 * so that we don't add it again
++				 */
++				--rq->nr_phys_segments;
++				--rq->nr_hw_segments;
++			}
++
+ 			rq = NULL;
+ 			break;
+ 		} else if (ret == BLKPREP_KILL) {
+@@ -931,9 +953,7 @@ int elv_register_queue(struct request_queue *q)
  	elevator_t *e = q->elevator;
  	int error;
  
@@ -32406,10 +123421,95 @@
  
  EXPORT_SYMBOL(put_disk);
 diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c
-index 8b91994..3d0422f 100644
+index 8b91994..1932a56 100644
 --- a/block/ll_rw_blk.c
 +++ b/block/ll_rw_blk.c
-@@ -760,6 +760,30 @@ void blk_queue_dma_alignment(struct request_queue *q, int mask)
+@@ -347,7 +347,6 @@ unsigned blk_ordered_req_seq(struct request *rq)
+ void blk_ordered_complete_seq(struct request_queue *q, unsigned seq, int error)
+ {
+ 	struct request *rq;
+-	int uptodate;
+ 
+ 	if (error && !q->orderr)
+ 		q->orderr = error;
+@@ -361,15 +360,11 @@ void blk_ordered_complete_seq(struct request_queue *q, unsigned seq, int error)
+ 	/*
+ 	 * Okay, sequence complete.
+ 	 */
+-	uptodate = 1;
+-	if (q->orderr)
+-		uptodate = q->orderr;
+-
+ 	q->ordseq = 0;
+ 	rq = q->orig_bar_rq;
+ 
+-	end_that_request_first(rq, uptodate, rq->hard_nr_sectors);
+-	end_that_request_last(rq, uptodate);
++	if (__blk_end_request(rq, q->orderr, blk_rq_bytes(rq)))
++		BUG();
+ }
+ 
+ static void pre_flush_end_io(struct request *rq, int error)
+@@ -486,9 +481,9 @@ int blk_do_ordered(struct request_queue *q, struct request **rqp)
+ 			 * ORDERED_NONE while this request is on it.
+ 			 */
+ 			blkdev_dequeue_request(rq);
+-			end_that_request_first(rq, -EOPNOTSUPP,
+-					       rq->hard_nr_sectors);
+-			end_that_request_last(rq, -EOPNOTSUPP);
++			if (__blk_end_request(rq, -EOPNOTSUPP,
++					      blk_rq_bytes(rq)))
++				BUG();
+ 			*rqp = NULL;
+ 			return 0;
+ 		}
+@@ -726,6 +721,45 @@ void blk_queue_stack_limits(struct request_queue *t, struct request_queue *b)
+ EXPORT_SYMBOL(blk_queue_stack_limits);
+ 
+ /**
++ * blk_queue_dma_drain - Set up a drain buffer for excess dma.
++ *
++ * @q:  the request queue for the device
++ * @buf:	physically contiguous buffer
++ * @size:	size of the buffer in bytes
++ *
++ * Some devices have excess DMA problems and can't simply discard (or
++ * zero fill) the unwanted piece of the transfer.  They have to have a
++ * real area of memory to transfer it into.  The use case for this is
++ * ATAPI devices in DMA mode.  If the packet command causes a transfer
++ * bigger than the transfer size some HBAs will lock up if there
++ * aren't DMA elements to contain the excess transfer.  What this API
++ * does is adjust the queue so that the buf is always appended
++ * silently to the scatterlist.
++ *
++ * Note: This routine adjusts max_hw_segments to make room for
++ * appending the drain buffer.  If you call
++ * blk_queue_max_hw_segments() or blk_queue_max_phys_segments() after
++ * calling this routine, you must set the limit to one fewer than your
++ * device can support otherwise there won't be room for the drain
++ * buffer.
++ */
++int blk_queue_dma_drain(struct request_queue *q, void *buf,
++				unsigned int size)
++{
++	if (q->max_hw_segments < 2 || q->max_phys_segments < 2)
++		return -EINVAL;
++	/* make room for appending the drain */
++	--q->max_hw_segments;
++	--q->max_phys_segments;
++	q->dma_drain_buffer = buf;
++	q->dma_drain_size = size;
++
++	return 0;
++}
++
++EXPORT_SYMBOL_GPL(blk_queue_dma_drain);
++
++/**
+  * blk_queue_segment_boundary - set boundary rules for segment merging
+  * @q:  the request queue for the device
+  * @mask:  the memory boundary mask
+@@ -760,6 +794,30 @@ void blk_queue_dma_alignment(struct request_queue *q, int mask)
  EXPORT_SYMBOL(blk_queue_dma_alignment);
  
  /**
@@ -32440,7 +123540,24 @@
   * blk_queue_find_tag - find a request by its tag and queue
   * @q:	 The request queue for the device
   * @tag: The tag of the request
-@@ -1862,9 +1886,7 @@ struct request_queue *blk_alloc_queue_node(gfp_t gfp_mask, int node_id)
+@@ -1355,6 +1413,16 @@ new_segment:
+ 		bvprv = bvec;
+ 	} /* segments in rq */
+ 
++	if (q->dma_drain_size) {
++		sg->page_link &= ~0x02;
++		sg = sg_next(sg);
++		sg_set_page(sg, virt_to_page(q->dma_drain_buffer),
++			    q->dma_drain_size,
++			    ((unsigned long)q->dma_drain_buffer) &
++			    (PAGE_SIZE - 1));
++		nsegs++;
++	}
++
+ 	if (sg)
+ 		sg_mark_end(sg);
+ 
+@@ -1862,9 +1930,7 @@ struct request_queue *blk_alloc_queue_node(gfp_t gfp_mask, int node_id)
  
  	init_timer(&q->unplug_timer);
  
@@ -32451,7 +123568,534 @@
  
  	mutex_init(&q->sysfs_lock);
  
-@@ -4182,9 +4204,8 @@ int blk_register_queue(struct gendisk *disk)
+@@ -3415,29 +3481,36 @@ static void blk_recalc_rq_sectors(struct request *rq, int nsect)
+ 	}
+ }
+ 
+-static int __end_that_request_first(struct request *req, int uptodate,
++/**
++ * __end_that_request_first - end I/O on a request
++ * @req:      the request being processed
++ * @error:    0 for success, < 0 for error
++ * @nr_bytes: number of bytes to complete
++ *
++ * Description:
++ *     Ends I/O on a number of bytes attached to @req, and sets it up
++ *     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
++ **/
++static int __end_that_request_first(struct request *req, int error,
+ 				    int nr_bytes)
+ {
+-	int total_bytes, bio_nbytes, error, next_idx = 0;
++	int total_bytes, bio_nbytes, next_idx = 0;
+ 	struct bio *bio;
+ 
+ 	blk_add_trace_rq(req->q, req, BLK_TA_COMPLETE);
+ 
+ 	/*
+-	 * extend uptodate bool to allow < 0 value to be direct io error
+-	 */
+-	error = 0;
+-	if (end_io_error(uptodate))
+-		error = !uptodate ? -EIO : uptodate;
+-
+-	/*
+ 	 * for a REQ_BLOCK_PC request, we want to carry any eventual
+ 	 * sense key with us all the way through
+ 	 */
+ 	if (!blk_pc_request(req))
+ 		req->errors = 0;
+ 
+-	if (!uptodate) {
++	if (error) {
+ 		if (blk_fs_request(req) && !(req->cmd_flags & REQ_QUIET))
+ 			printk("end_request: I/O error, dev %s, sector %llu\n",
+ 				req->rq_disk ? req->rq_disk->disk_name : "?",
+@@ -3531,49 +3604,6 @@ static int __end_that_request_first(struct request *req, int uptodate,
+ 	return 1;
+ }
+ 
+-/**
+- * end_that_request_first - end I/O on a request
+- * @req:      the request being processed
+- * @uptodate: 1 for success, 0 for I/O error, < 0 for specific error
+- * @nr_sectors: number of sectors to end I/O on
+- *
+- * Description:
+- *     Ends I/O on a number of sectors attached to @req, and sets it up
+- *     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
+- **/
+-int end_that_request_first(struct request *req, int uptodate, int nr_sectors)
+-{
+-	return __end_that_request_first(req, uptodate, nr_sectors << 9);
+-}
+-
+-EXPORT_SYMBOL(end_that_request_first);
+-
+-/**
+- * end_that_request_chunk - end I/O on a request
+- * @req:      the request being processed
+- * @uptodate: 1 for success, 0 for I/O error, < 0 for specific error
+- * @nr_bytes: number of bytes to complete
+- *
+- * Description:
+- *     Ends I/O on a number of bytes attached to @req, and sets it up
+- *     for the next range of segments (if any). Like end_that_request_first(),
+- *     but deals with bytes instead of sectors.
+- *
+- * Return:
+- *     0 - we are done with this request, call end_that_request_last()
+- *     1 - still buffers pending for this request
+- **/
+-int end_that_request_chunk(struct request *req, int uptodate, int nr_bytes)
+-{
+-	return __end_that_request_first(req, uptodate, nr_bytes);
+-}
+-
+-EXPORT_SYMBOL(end_that_request_chunk);
+-
+ /*
+  * splice the completion data to a local structure and hand off to
+  * process_completion_queue() to complete the requests
+@@ -3653,17 +3683,15 @@ EXPORT_SYMBOL(blk_complete_request);
+ /*
+  * queue lock must be held
+  */
+-void end_that_request_last(struct request *req, int uptodate)
++static void end_that_request_last(struct request *req, int error)
+ {
+ 	struct gendisk *disk = req->rq_disk;
+-	int error;
+ 
+-	/*
+-	 * extend uptodate bool to allow < 0 value to be direct io error
+-	 */
+-	error = 0;
+-	if (end_io_error(uptodate))
+-		error = !uptodate ? -EIO : uptodate;
++	if (blk_rq_tagged(req))
++		blk_queue_end_tag(req->q, req);
++
++	if (blk_queued_rq(req))
++		blkdev_dequeue_request(req);
+ 
+ 	if (unlikely(laptop_mode) && blk_fs_request(req))
+ 		laptop_io_completion();
+@@ -3682,32 +3710,54 @@ void end_that_request_last(struct request *req, int uptodate)
+ 		disk_round_stats(disk);
+ 		disk->in_flight--;
+ 	}
++
+ 	if (req->end_io)
+ 		req->end_io(req, error);
+-	else
++	else {
++		if (blk_bidi_rq(req))
++			__blk_put_request(req->next_rq->q, req->next_rq);
++
+ 		__blk_put_request(req->q, req);
++	}
+ }
+ 
+-EXPORT_SYMBOL(end_that_request_last);
+-
+ static inline void __end_request(struct request *rq, int uptodate,
+-				 unsigned int nr_bytes, int dequeue)
++				 unsigned int nr_bytes)
+ {
+-	if (!end_that_request_chunk(rq, uptodate, nr_bytes)) {
+-		if (dequeue)
+-			blkdev_dequeue_request(rq);
+-		add_disk_randomness(rq->rq_disk);
+-		end_that_request_last(rq, uptodate);
+-	}
++	int error = 0;
++
++	if (uptodate <= 0)
++		error = uptodate ? uptodate : -EIO;
++
++	__blk_end_request(rq, error, nr_bytes);
+ }
+ 
+-static unsigned int rq_byte_size(struct request *rq)
++/**
++ * blk_rq_bytes - Returns bytes left to complete in the entire request
++ **/
++unsigned int blk_rq_bytes(struct request *rq)
+ {
+ 	if (blk_fs_request(rq))
+ 		return rq->hard_nr_sectors << 9;
+ 
+ 	return rq->data_len;
+ }
++EXPORT_SYMBOL_GPL(blk_rq_bytes);
++
++/**
++ * blk_rq_cur_bytes - Returns bytes left to complete in the current segment
++ **/
++unsigned int blk_rq_cur_bytes(struct request *rq)
++{
++	if (blk_fs_request(rq))
++		return rq->current_nr_sectors << 9;
++
++	if (rq->bio)
++		return rq->bio->bi_size;
++
++	return rq->data_len;
++}
++EXPORT_SYMBOL_GPL(blk_rq_cur_bytes);
+ 
+ /**
+  * end_queued_request - end all I/O on a queued request
+@@ -3722,7 +3772,7 @@ static unsigned int rq_byte_size(struct request *rq)
+  **/
+ void end_queued_request(struct request *rq, int uptodate)
+ {
+-	__end_request(rq, uptodate, rq_byte_size(rq), 1);
++	__end_request(rq, uptodate, blk_rq_bytes(rq));
+ }
+ EXPORT_SYMBOL(end_queued_request);
+ 
+@@ -3739,7 +3789,7 @@ EXPORT_SYMBOL(end_queued_request);
+  **/
+ void end_dequeued_request(struct request *rq, int uptodate)
+ {
+-	__end_request(rq, uptodate, rq_byte_size(rq), 0);
++	__end_request(rq, uptodate, blk_rq_bytes(rq));
+ }
+ EXPORT_SYMBOL(end_dequeued_request);
+ 
+@@ -3765,10 +3815,159 @@ EXPORT_SYMBOL(end_dequeued_request);
+  **/
+ void end_request(struct request *req, int uptodate)
+ {
+-	__end_request(req, uptodate, req->hard_cur_sectors << 9, 1);
++	__end_request(req, uptodate, 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, int nr_bytes,
++		      int bidi_bytes, int (drv_callback)(struct request *))
++{
++	struct request_queue *q = rq->q;
++	unsigned long flags = 0UL;
++
++	if (blk_fs_request(rq) || blk_pc_request(rq)) {
++		if (__end_that_request_first(rq, error, nr_bytes))
++			return 1;
++
++		/* Bidi request must be completed as a whole */
++		if (blk_bidi_rq(rq) &&
++		    __end_that_request_first(rq->next_rq, error, bidi_bytes))
++			return 1;
++	}
++
++	/* Special feature for tricky drivers */
++	if (drv_callback && drv_callback(rq))
++		return 1;
++
++	add_disk_randomness(rq->rq_disk);
++
++	spin_lock_irqsave(q->queue_lock, flags);
++	end_that_request_last(rq, error);
++	spin_unlock_irqrestore(q->queue_lock, flags);
++
++	return 0;
++}
++
++/**
++ * blk_end_request - Helper function for drivers to complete the request.
++ * @rq:       the request being processed
++ * @error:    0 for success, < 0 for error
++ * @nr_bytes: number of bytes to complete
++ *
++ * Description:
++ *     Ends I/O on a number of bytes attached to @rq.
++ *     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
++ **/
++int blk_end_request(struct request *rq, int error, int nr_bytes)
++{
++	return blk_end_io(rq, error, nr_bytes, 0, NULL);
++}
++EXPORT_SYMBOL_GPL(blk_end_request);
++
++/**
++ * __blk_end_request - Helper function for drivers to complete the request.
++ * @rq:       the request being processed
++ * @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
++ **/
++int __blk_end_request(struct request *rq, int error, int nr_bytes)
++{
++	if (blk_fs_request(rq) || blk_pc_request(rq)) {
++		if (__end_that_request_first(rq, error, nr_bytes))
++			return 1;
++	}
++
++	add_disk_randomness(rq->rq_disk);
++
++	end_that_request_last(rq, error);
++
++	return 0;
++}
++EXPORT_SYMBOL_GPL(__blk_end_request);
++
++/**
++ * 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
++ * @nr_bytes:   number of bytes to complete @rq
++ * @bidi_bytes: number of bytes to complete @rq->next_rq
++ *
++ * Description:
++ *     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
++ **/
++int blk_end_bidi_request(struct request *rq, int error, int nr_bytes,
++			 int bidi_bytes)
++{
++	return blk_end_io(rq, error, nr_bytes, bidi_bytes, NULL);
++}
++EXPORT_SYMBOL_GPL(blk_end_bidi_request);
++
++/**
++ * blk_end_request_callback - Special helper function for tricky drivers
++ * @rq:           the request being processed
++ * @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
++ *                completion of the request.
++ *
++ * Description:
++ *     Ends I/O on a number of bytes attached to @rq.
++ *     If @rq has leftover, sets it up for the next range of segments.
++ *
++ *     This special helper function is used only for existing tricky drivers.
++ *     (e.g. cdrom_newpc_intr() of ide-cd)
++ *     This interface will be removed when such drivers are rewritten.
++ *     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.
++ **/
++int blk_end_request_callback(struct request *rq, int error, int nr_bytes,
++			     int (drv_callback)(struct request *))
++{
++	return blk_end_io(rq, error, nr_bytes, 0, drv_callback);
++}
++EXPORT_SYMBOL_GPL(blk_end_request_callback);
++
+ static void blk_rq_bio_prep(struct request_queue *q, struct request *rq,
+ 			    struct bio *bio)
+ {
+@@ -3831,55 +4030,100 @@ int __init blk_dev_init(void)
+ 	return 0;
+ }
+ 
++static void cfq_dtor(struct io_context *ioc)
++{
++	struct cfq_io_context *cic[1];
++	int r;
++
++	/*
++	 * We don't have a specific key to lookup with, so use the gang
++	 * lookup to just retrieve the first item stored. The cfq exit
++	 * function will iterate the full tree, so any member will do.
++	 */
++	r = radix_tree_gang_lookup(&ioc->radix_root, (void **) cic, 0, 1);
++	if (r > 0)
++		cic[0]->dtor(ioc);
++}
++
+ /*
+- * IO Context helper functions
++ * IO Context helper functions. put_io_context() returns 1 if there are no
++ * more users of this io context, 0 otherwise.
+  */
+-void put_io_context(struct io_context *ioc)
++int put_io_context(struct io_context *ioc)
+ {
+ 	if (ioc == NULL)
+-		return;
++		return 1;
+ 
+ 	BUG_ON(atomic_read(&ioc->refcount) == 0);
+ 
+ 	if (atomic_dec_and_test(&ioc->refcount)) {
+-		struct cfq_io_context *cic;
+-
+ 		rcu_read_lock();
+ 		if (ioc->aic && ioc->aic->dtor)
+ 			ioc->aic->dtor(ioc->aic);
+-		if (ioc->cic_root.rb_node != NULL) {
+-			struct rb_node *n = rb_first(&ioc->cic_root);
+-
+-			cic = rb_entry(n, struct cfq_io_context, rb_node);
+-			cic->dtor(ioc);
+-		}
+ 		rcu_read_unlock();
++		cfq_dtor(ioc);
+ 
+ 		kmem_cache_free(iocontext_cachep, ioc);
++		return 1;
+ 	}
++	return 0;
+ }
+ EXPORT_SYMBOL(put_io_context);
+ 
++static void cfq_exit(struct io_context *ioc)
++{
++	struct cfq_io_context *cic[1];
++	int r;
++
++	rcu_read_lock();
++	/*
++	 * See comment for cfq_dtor()
++	 */
++	r = radix_tree_gang_lookup(&ioc->radix_root, (void **) cic, 0, 1);
++	rcu_read_unlock();
++
++	if (r > 0)
++		cic[0]->exit(ioc);
++}
++
+ /* Called by the exitting task */
+ void exit_io_context(void)
+ {
+ 	struct io_context *ioc;
+-	struct cfq_io_context *cic;
+ 
+ 	task_lock(current);
+ 	ioc = current->io_context;
+ 	current->io_context = NULL;
+ 	task_unlock(current);
+ 
+-	ioc->task = NULL;
+-	if (ioc->aic && ioc->aic->exit)
+-		ioc->aic->exit(ioc->aic);
+-	if (ioc->cic_root.rb_node != NULL) {
+-		cic = rb_entry(rb_first(&ioc->cic_root), struct cfq_io_context, rb_node);
+-		cic->exit(ioc);
++	if (atomic_dec_and_test(&ioc->nr_tasks)) {
++		if (ioc->aic && ioc->aic->exit)
++			ioc->aic->exit(ioc->aic);
++		cfq_exit(ioc);
++
++		put_io_context(ioc);
+ 	}
++}
++
++struct io_context *alloc_io_context(gfp_t gfp_flags, int node)
++{
++	struct io_context *ret;
+ 
+-	put_io_context(ioc);
++	ret = kmem_cache_alloc_node(iocontext_cachep, gfp_flags, node);
++	if (ret) {
++		atomic_set(&ret->refcount, 1);
++		atomic_set(&ret->nr_tasks, 1);
++		spin_lock_init(&ret->lock);
++		ret->ioprio_changed = 0;
++		ret->ioprio = 0;
++		ret->last_waited = jiffies; /* doesn't matter... */
++		ret->nr_batch_requests = 0; /* because this is 0 */
++		ret->aic = NULL;
++		INIT_RADIX_TREE(&ret->radix_root, GFP_ATOMIC | __GFP_HIGH);
++		ret->ioc_data = NULL;
++	}
++
++	return ret;
+ }
+ 
+ /*
+@@ -3899,16 +4143,8 @@ static struct io_context *current_io_context(gfp_t gfp_flags, int node)
+ 	if (likely(ret))
+ 		return ret;
+ 
+-	ret = kmem_cache_alloc_node(iocontext_cachep, gfp_flags, node);
++	ret = alloc_io_context(gfp_flags, node);
+ 	if (ret) {
+-		atomic_set(&ret->refcount, 1);
+-		ret->task = current;
+-		ret->ioprio_changed = 0;
+-		ret->last_waited = jiffies; /* doesn't matter... */
+-		ret->nr_batch_requests = 0; /* because this is 0 */
+-		ret->aic = NULL;
+-		ret->cic_root.rb_node = NULL;
+-		ret->ioc_data = NULL;
+ 		/* make sure set_task_ioprio() sees the settings above */
+ 		smp_wmb();
+ 		tsk->io_context = ret;
+@@ -3925,10 +4161,18 @@ static struct io_context *current_io_context(gfp_t gfp_flags, int node)
+  */
+ struct io_context *get_io_context(gfp_t gfp_flags, int node)
+ {
+-	struct io_context *ret;
+-	ret = current_io_context(gfp_flags, node);
+-	if (likely(ret))
+-		atomic_inc(&ret->refcount);
++	struct io_context *ret = NULL;
++
++	/*
++	 * Check for unlikely race with exiting task. ioc ref count is
++	 * zero when ioc is being detached.
++	 */
++	do {
++		ret = current_io_context(gfp_flags, node);
++		if (unlikely(!ret))
++			break;
++	} while (!atomic_inc_not_zero(&ret->refcount));
++
+ 	return ret;
+ }
+ EXPORT_SYMBOL(get_io_context);
+@@ -4182,9 +4426,8 @@ int blk_register_queue(struct gendisk *disk)
  	if (!q || !q->request_fn)
  		return -ENXIO;
  
@@ -32463,7 +124107,7 @@
  	if (ret < 0)
  		return ret;
  
-@@ -4209,6 +4230,6 @@ void blk_unregister_queue(struct gendisk *disk)
+@@ -4209,6 +4452,6 @@ void blk_unregister_queue(struct gendisk *disk)
  
  		kobject_uevent(&q->kobj, KOBJ_REMOVE);
  		kobject_del(&q->kobj);
@@ -47049,7 +138693,7 @@
   * @dev: target ATA device
   *
 diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
-index 6380726..ce803d1 100644
+index 6380726..bdbd55a 100644
 --- a/drivers/ata/libata-core.c
 +++ b/drivers/ata/libata-core.c
 @@ -119,6 +119,10 @@ int libata_noacpi = 0;
@@ -48038,7 +139682,7 @@
  
  	return 0;
  }
-@@ -4985,7 +4921,7 @@ void swap_buf_le16(u16 *buf, unsigned int buf_words)
+@@ -4985,63 +4921,77 @@ void swap_buf_le16(u16 *buf, unsigned int buf_words)
  
  /**
   *	ata_data_xfer - Transfer data by PIO
@@ -48046,8 +139690,10 @@
 + *	@dev: device to target
   *	@buf: data buffer
   *	@buflen: buffer length
-  *	@write_data: read/write
-@@ -4994,37 +4930,44 @@ void swap_buf_le16(u16 *buf, unsigned int buf_words)
+- *	@write_data: read/write
++ *	@rw: read/write
+  *
+  *	Transfer data from/to the device data register by PIO.
   *
   *	LOCKING:
   *	Inherited from caller.
@@ -48104,8 +139750,11 @@
 + *	@dev: device to target
   *	@buf: data buffer
   *	@buflen: buffer length
-  *	@write_data: read/write
-@@ -5034,14 +4977,21 @@ void ata_data_xfer(struct ata_device *adev, unsigned char *buf,
+- *	@write_data: read/write
++ *	@rw: read/write
+  *
+  *	Transfer data from/to the device data register by PIO. Do the
+  *	transfer with interrupts disabled.
   *
   *	LOCKING:
   *	Inherited from caller.
@@ -57578,304 +149227,1915 @@
 +	if (!system_kset)
 +		return -ENOMEM;
 +	return 0;
- }
- 
- EXPORT_SYMBOL_GPL(sysdev_register);
-diff --git a/drivers/block/aoe/aoeblk.c b/drivers/block/aoe/aoeblk.c
-index ad00b3d..826d123 100644
---- a/drivers/block/aoe/aoeblk.c
-+++ b/drivers/block/aoe/aoeblk.c
-@@ -15,8 +15,10 @@
- 
- static struct kmem_cache *buf_pool_cache;
- 
--static ssize_t aoedisk_show_state(struct gendisk * disk, char *page)
-+static ssize_t aoedisk_show_state(struct device *dev,
-+				  struct device_attribute *attr, char *page)
- {
-+	struct gendisk *disk = dev_to_disk(dev);
- 	struct aoedev *d = disk->private_data;
- 
- 	return snprintf(page, PAGE_SIZE,
-@@ -26,50 +28,47 @@ static ssize_t aoedisk_show_state(struct gendisk * disk, char *page)
- 			(d->nopen && !(d->flags & DEVFL_UP)) ? ",closewait" : "");
- 	/* I'd rather see nopen exported so we can ditch closewait */
- }
--static ssize_t aoedisk_show_mac(struct gendisk * disk, char *page)
-+static ssize_t aoedisk_show_mac(struct device *dev,
-+				struct device_attribute *attr, char *page)
- {
-+	struct gendisk *disk = dev_to_disk(dev);
- 	struct aoedev *d = disk->private_data;
- 
- 	return snprintf(page, PAGE_SIZE, "%012llx\n",
- 			(unsigned long long)mac_addr(d->addr));
- }
--static ssize_t aoedisk_show_netif(struct gendisk * disk, char *page)
-+static ssize_t aoedisk_show_netif(struct device *dev,
-+				  struct device_attribute *attr, char *page)
- {
-+	struct gendisk *disk = dev_to_disk(dev);
- 	struct aoedev *d = disk->private_data;
- 
- 	return snprintf(page, PAGE_SIZE, "%s\n", d->ifp->name);
- }
- /* firmware version */
--static ssize_t aoedisk_show_fwver(struct gendisk * disk, char *page)
-+static ssize_t aoedisk_show_fwver(struct device *dev,
-+				  struct device_attribute *attr, char *page)
- {
-+	struct gendisk *disk = dev_to_disk(dev);
- 	struct aoedev *d = disk->private_data;
- 
- 	return snprintf(page, PAGE_SIZE, "0x%04x\n", (unsigned int) d->fw_ver);
- }
- 
--static struct disk_attribute disk_attr_state = {
--	.attr = {.name = "state", .mode = S_IRUGO },
--	.show = aoedisk_show_state
--};
--static struct disk_attribute disk_attr_mac = {
--	.attr = {.name = "mac", .mode = S_IRUGO },
--	.show = aoedisk_show_mac
--};
--static struct disk_attribute disk_attr_netif = {
--	.attr = {.name = "netif", .mode = S_IRUGO },
--	.show = aoedisk_show_netif
--};
--static struct disk_attribute disk_attr_fwver = {
--	.attr = {.name = "firmware-version", .mode = S_IRUGO },
--	.show = aoedisk_show_fwver
-+static DEVICE_ATTR(state, S_IRUGO, aoedisk_show_state, NULL);
-+static DEVICE_ATTR(mac, S_IRUGO, aoedisk_show_mac, NULL);
-+static DEVICE_ATTR(netif, S_IRUGO, aoedisk_show_netif, NULL);
-+static struct device_attribute dev_attr_firmware_version = {
-+	.attr = { .name = "firmware-version", .mode = S_IRUGO, .owner = THIS_MODULE },
-+	.show = aoedisk_show_fwver,
- };
- 
- static struct attribute *aoe_attrs[] = {
--	&disk_attr_state.attr,
--	&disk_attr_mac.attr,
--	&disk_attr_netif.attr,
--	&disk_attr_fwver.attr,
--	NULL
-+	&dev_attr_state.attr,
-+	&dev_attr_mac.attr,
-+	&dev_attr_netif.attr,
-+	&dev_attr_firmware_version.attr,
-+	NULL,
- };
- 
- static const struct attribute_group attr_group = {
-@@ -79,12 +78,12 @@ static const struct attribute_group attr_group = {
- static int
- aoedisk_add_sysfs(struct aoedev *d)
- {
--	return sysfs_create_group(&d->gd->kobj, &attr_group);
-+	return sysfs_create_group(&d->gd->dev.kobj, &attr_group);
- }
- void
- aoedisk_rm_sysfs(struct aoedev *d)
- {
--	sysfs_remove_group(&d->gd->kobj, &attr_group);
-+	sysfs_remove_group(&d->gd->dev.kobj, &attr_group);
- }
- 
- static int
-diff --git a/drivers/block/aoe/aoechr.c b/drivers/block/aoe/aoechr.c
-index 39e563e..d5480e3 100644
---- a/drivers/block/aoe/aoechr.c
-+++ b/drivers/block/aoe/aoechr.c
-@@ -259,9 +259,8 @@ aoechr_init(void)
- 		return PTR_ERR(aoe_class);
- 	}
- 	for (i = 0; i < ARRAY_SIZE(chardevs); ++i)
--		class_device_create(aoe_class, NULL,
--					MKDEV(AOE_MAJOR, chardevs[i].minor),
--					NULL, chardevs[i].name);
-+		device_create(aoe_class, NULL,
-+			      MKDEV(AOE_MAJOR, chardevs[i].minor), chardevs[i].name);
- 
+ }
+ 
+ EXPORT_SYMBOL_GPL(sysdev_register);
+diff --git a/drivers/block/DAC960.c b/drivers/block/DAC960.c
+index 9030c37..cd03473 100644
+--- a/drivers/block/DAC960.c
++++ b/drivers/block/DAC960.c
+@@ -3455,19 +3455,12 @@ static inline bool DAC960_ProcessCompletedRequest(DAC960_Command_T *Command,
+ 						 bool SuccessfulIO)
+ {
+ 	struct request *Request = Command->Request;
+-	int UpToDate;
+-
+-	UpToDate = 0;
+-	if (SuccessfulIO)
+-		UpToDate = 1;
++	int Error = SuccessfulIO ? 0 : -EIO;
+ 
+ 	pci_unmap_sg(Command->Controller->PCIDevice, Command->cmd_sglist,
+ 		Command->SegmentCount, Command->DmaDirection);
+ 
+-	 if (!end_that_request_first(Request, UpToDate, Command->BlockCount)) {
+-		add_disk_randomness(Request->rq_disk);
+- 	 	end_that_request_last(Request, UpToDate);
+-
++	 if (!__blk_end_request(Request, Error, Command->BlockCount << 9)) {
+ 		if (Command->Completion) {
+ 			complete(Command->Completion);
+ 			Command->Completion = NULL;
+diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig
+index 4d0119e..f212285 100644
+--- a/drivers/block/Kconfig
++++ b/drivers/block/Kconfig
+@@ -105,6 +105,17 @@ config PARIDE
+ 	  "MicroSolutions backpack protocol", "DataStor Commuter protocol"
+ 	  etc.).
+ 
++config GDROM
++	tristate "SEGA Dreamcast GD-ROM drive"
++	depends on SH_DREAMCAST
++	help
++	  A standard SEGA Dreamcast comes with a modified CD ROM drive called a
++	  "GD-ROM" by SEGA to signify it is capable of reading special disks
++	  with up to 1 GB of data. This drive will also read standard CD ROM
++	  disks. Select this option to access any disks in your GD ROM drive.
++	  Most users will want to say "Y" here.
++	  You can also build this as a module which will be called gdrom.ko
++
+ source "drivers/block/paride/Kconfig"
+ 
+ config BLK_CPQ_DA
+diff --git a/drivers/block/aoe/aoeblk.c b/drivers/block/aoe/aoeblk.c
+index ad00b3d..826d123 100644
+--- a/drivers/block/aoe/aoeblk.c
++++ b/drivers/block/aoe/aoeblk.c
+@@ -15,8 +15,10 @@
+ 
+ static struct kmem_cache *buf_pool_cache;
+ 
+-static ssize_t aoedisk_show_state(struct gendisk * disk, char *page)
++static ssize_t aoedisk_show_state(struct device *dev,
++				  struct device_attribute *attr, char *page)
+ {
++	struct gendisk *disk = dev_to_disk(dev);
+ 	struct aoedev *d = disk->private_data;
+ 
+ 	return snprintf(page, PAGE_SIZE,
+@@ -26,50 +28,47 @@ static ssize_t aoedisk_show_state(struct gendisk * disk, char *page)
+ 			(d->nopen && !(d->flags & DEVFL_UP)) ? ",closewait" : "");
+ 	/* I'd rather see nopen exported so we can ditch closewait */
+ }
+-static ssize_t aoedisk_show_mac(struct gendisk * disk, char *page)
++static ssize_t aoedisk_show_mac(struct device *dev,
++				struct device_attribute *attr, char *page)
+ {
++	struct gendisk *disk = dev_to_disk(dev);
+ 	struct aoedev *d = disk->private_data;
+ 
+ 	return snprintf(page, PAGE_SIZE, "%012llx\n",
+ 			(unsigned long long)mac_addr(d->addr));
+ }
+-static ssize_t aoedisk_show_netif(struct gendisk * disk, char *page)
++static ssize_t aoedisk_show_netif(struct device *dev,
++				  struct device_attribute *attr, char *page)
+ {
++	struct gendisk *disk = dev_to_disk(dev);
+ 	struct aoedev *d = disk->private_data;
+ 
+ 	return snprintf(page, PAGE_SIZE, "%s\n", d->ifp->name);
+ }
+ /* firmware version */
+-static ssize_t aoedisk_show_fwver(struct gendisk * disk, char *page)
++static ssize_t aoedisk_show_fwver(struct device *dev,
++				  struct device_attribute *attr, char *page)
+ {
++	struct gendisk *disk = dev_to_disk(dev);
+ 	struct aoedev *d = disk->private_data;
+ 
+ 	return snprintf(page, PAGE_SIZE, "0x%04x\n", (unsigned int) d->fw_ver);
+ }
+ 
+-static struct disk_attribute disk_attr_state = {
+-	.attr = {.name = "state", .mode = S_IRUGO },
+-	.show = aoedisk_show_state
+-};
+-static struct disk_attribute disk_attr_mac = {
+-	.attr = {.name = "mac", .mode = S_IRUGO },
+-	.show = aoedisk_show_mac
+-};
+-static struct disk_attribute disk_attr_netif = {
+-	.attr = {.name = "netif", .mode = S_IRUGO },
+-	.show = aoedisk_show_netif
+-};
+-static struct disk_attribute disk_attr_fwver = {
+-	.attr = {.name = "firmware-version", .mode = S_IRUGO },
+-	.show = aoedisk_show_fwver
++static DEVICE_ATTR(state, S_IRUGO, aoedisk_show_state, NULL);
++static DEVICE_ATTR(mac, S_IRUGO, aoedisk_show_mac, NULL);
++static DEVICE_ATTR(netif, S_IRUGO, aoedisk_show_netif, NULL);
++static struct device_attribute dev_attr_firmware_version = {
++	.attr = { .name = "firmware-version", .mode = S_IRUGO, .owner = THIS_MODULE },
++	.show = aoedisk_show_fwver,
+ };
+ 
+ static struct attribute *aoe_attrs[] = {
+-	&disk_attr_state.attr,
+-	&disk_attr_mac.attr,
+-	&disk_attr_netif.attr,
+-	&disk_attr_fwver.attr,
+-	NULL
++	&dev_attr_state.attr,
++	&dev_attr_mac.attr,
++	&dev_attr_netif.attr,
++	&dev_attr_firmware_version.attr,
++	NULL,
+ };
+ 
+ static const struct attribute_group attr_group = {
+@@ -79,12 +78,12 @@ static const struct attribute_group attr_group = {
+ static int
+ aoedisk_add_sysfs(struct aoedev *d)
+ {
+-	return sysfs_create_group(&d->gd->kobj, &attr_group);
++	return sysfs_create_group(&d->gd->dev.kobj, &attr_group);
+ }
+ void
+ aoedisk_rm_sysfs(struct aoedev *d)
+ {
+-	sysfs_remove_group(&d->gd->kobj, &attr_group);
++	sysfs_remove_group(&d->gd->dev.kobj, &attr_group);
+ }
+ 
+ static int
+diff --git a/drivers/block/aoe/aoechr.c b/drivers/block/aoe/aoechr.c
+index 39e563e..d5480e3 100644
+--- a/drivers/block/aoe/aoechr.c
++++ b/drivers/block/aoe/aoechr.c
+@@ -259,9 +259,8 @@ aoechr_init(void)
+ 		return PTR_ERR(aoe_class);
+ 	}
+ 	for (i = 0; i < ARRAY_SIZE(chardevs); ++i)
+-		class_device_create(aoe_class, NULL,
+-					MKDEV(AOE_MAJOR, chardevs[i].minor),
+-					NULL, chardevs[i].name);
++		device_create(aoe_class, NULL,
++			      MKDEV(AOE_MAJOR, chardevs[i].minor), chardevs[i].name);
+ 
+ 	return 0;
+ }
+@@ -272,7 +271,7 @@ aoechr_exit(void)
+ 	int i;
+ 
+ 	for (i = 0; i < ARRAY_SIZE(chardevs); ++i)
+-		class_device_destroy(aoe_class, MKDEV(AOE_MAJOR, chardevs[i].minor));
++		device_destroy(aoe_class, MKDEV(AOE_MAJOR, chardevs[i].minor));
+ 	class_destroy(aoe_class);
+ 	unregister_chrdev(AOE_MAJOR, "aoechr");
+ }
+diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c
+index 509b649..ef50068 100644
+--- a/drivers/block/cciss.c
++++ b/drivers/block/cciss.c
+@@ -1187,17 +1187,6 @@ static int cciss_ioctl(struct inode *inode, struct file *filep,
+ 	}
+ }
+ 
+-static inline void complete_buffers(struct bio *bio, int status)
+-{
+-	while (bio) {
+-		struct bio *xbh = bio->bi_next;
+-
+-		bio->bi_next = NULL;
+-		bio_endio(bio, status ? 0 : -EIO);
+-		bio = xbh;
+-	}
+-}
+-
+ static void cciss_check_queues(ctlr_info_t *h)
+ {
+ 	int start_queue = h->next_to_run;
+@@ -1263,21 +1252,14 @@ static void cciss_softirq_done(struct request *rq)
+ 		pci_unmap_page(h->pdev, temp64.val, cmd->SG[i].Len, ddir);
+ 	}
+ 
+-	complete_buffers(rq->bio, (rq->errors == 0));
+-
+-	if (blk_fs_request(rq)) {
+-		const int rw = rq_data_dir(rq);
+-
+-		disk_stat_add(rq->rq_disk, sectors[rw], rq->nr_sectors);
+-	}
+-
+ #ifdef CCISS_DEBUG
+ 	printk("Done with %p\n", rq);
+ #endif				/* CCISS_DEBUG */
+ 
+-	add_disk_randomness(rq->rq_disk);
++	if (blk_end_request(rq, (rq->errors == 0) ? 0 : -EIO, blk_rq_bytes(rq)))
++		BUG();
++
+ 	spin_lock_irqsave(&h->lock, flags);
+-	end_that_request_last(rq, (rq->errors == 0));
+ 	cmd_free(h, cmd, 1);
+ 	cciss_check_queues(h);
+ 	spin_unlock_irqrestore(&h->lock, flags);
+@@ -2544,7 +2526,6 @@ after_error_processing:
+ 	}
+ 	cmd->rq->data_len = 0;
+ 	cmd->rq->completion_data = cmd;
+-	blk_add_trace_rq(cmd->rq->q, cmd->rq, BLK_TA_COMPLETE);
+ 	blk_complete_request(cmd->rq);
+ }
+ 
+diff --git a/drivers/block/cpqarray.c b/drivers/block/cpqarray.c
+index c8132d9..6919918 100644
+--- a/drivers/block/cpqarray.c
++++ b/drivers/block/cpqarray.c
+@@ -167,7 +167,6 @@ static void start_io(ctlr_info_t *h);
+ 
+ static inline void addQ(cmdlist_t **Qptr, cmdlist_t *c);
+ static inline cmdlist_t *removeQ(cmdlist_t **Qptr, cmdlist_t *c);
+-static inline void complete_buffers(struct bio *bio, int ok);
+ static inline void complete_command(cmdlist_t *cmd, int timeout);
+ 
+ static irqreturn_t do_ida_intr(int irq, void *dev_id);
+@@ -980,26 +979,13 @@ static void start_io(ctlr_info_t *h)
+ 	}
+ }
+ 
+-static inline void complete_buffers(struct bio *bio, int ok)
+-{
+-	struct bio *xbh;
+-
+-	while (bio) {
+-		xbh = bio->bi_next;
+-		bio->bi_next = NULL;
+-		
+-		bio_endio(bio, ok ? 0 : -EIO);
+-
+-		bio = xbh;
+-	}
+-}
+ /*
+  * Mark all buffers that cmd was responsible for
+  */
+ static inline void complete_command(cmdlist_t *cmd, int timeout)
+ {
+ 	struct request *rq = cmd->rq;
+-	int ok=1;
++	int error = 0;
+ 	int i, ddir;
+ 
+ 	if (cmd->req.hdr.rcode & RCODE_NONFATAL &&
+@@ -1011,16 +997,17 @@ static inline void complete_command(cmdlist_t *cmd, int timeout)
+ 	if (cmd->req.hdr.rcode & RCODE_FATAL) {
+ 		printk(KERN_WARNING "Fatal error on ida/c%dd%d\n",
+ 				cmd->ctlr, cmd->hdr.unit);
+-		ok = 0;
++		error = -EIO;
+ 	}
+ 	if (cmd->req.hdr.rcode & RCODE_INVREQ) {
+ 				printk(KERN_WARNING "Invalid request on ida/c%dd%d = (cmd=%x sect=%d cnt=%d sg=%d ret=%x)\n",
+ 				cmd->ctlr, cmd->hdr.unit, cmd->req.hdr.cmd,
+ 				cmd->req.hdr.blk, cmd->req.hdr.blk_cnt,
+ 				cmd->req.hdr.sg_cnt, cmd->req.hdr.rcode);
+-		ok = 0;	
++		error = -EIO;
+ 	}
+-	if (timeout) ok = 0;
++	if (timeout)
++		error = -EIO;
+ 	/* unmap the DMA mapping for all the scatter gather elements */
+ 	if (cmd->req.hdr.cmd == IDA_READ)
+ 		ddir = PCI_DMA_FROMDEVICE;
+@@ -1030,18 +1017,9 @@ static inline void complete_command(cmdlist_t *cmd, int timeout)
+                 pci_unmap_page(hba[cmd->ctlr]->pci_dev, cmd->req.sg[i].addr,
+ 				cmd->req.sg[i].size, ddir);
+ 
+-	complete_buffers(rq->bio, ok);
+-
+-	if (blk_fs_request(rq)) {
+-		const int rw = rq_data_dir(rq);
+-
+-		disk_stat_add(rq->rq_disk, sectors[rw], rq->nr_sectors);
+-	}
+-
+-	add_disk_randomness(rq->rq_disk);
+-
+ 	DBGPX(printk("Done with %p\n", rq););
+-	end_that_request_last(rq, ok ? 1 : -EIO);
++	if (__blk_end_request(rq, error, blk_rq_bytes(rq)))
++		BUG();
+ }
+ 
+ /*
+diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c
+index 639ed14..32c79a5 100644
+--- a/drivers/block/floppy.c
++++ b/drivers/block/floppy.c
+@@ -2287,21 +2287,19 @@ static int do_format(int drive, struct format_descr *tmp_format_req)
+  * =============================
+  */
+ 
+-static void floppy_end_request(struct request *req, int uptodate)
++static void floppy_end_request(struct request *req, int error)
+ {
+ 	unsigned int nr_sectors = current_count_sectors;
++	unsigned int drive = (unsigned long)req->rq_disk->private_data;
+ 
+ 	/* current_count_sectors can be zero if transfer failed */
+-	if (!uptodate)
++	if (error)
+ 		nr_sectors = req->current_nr_sectors;
+-	if (end_that_request_first(req, uptodate, nr_sectors))
++	if (__blk_end_request(req, error, nr_sectors << 9))
+ 		return;
+-	add_disk_randomness(req->rq_disk);
+-	floppy_off((long)req->rq_disk->private_data);
+-	blkdev_dequeue_request(req);
+-	end_that_request_last(req, uptodate);
+ 
+ 	/* We're done with the request */
++	floppy_off(drive);
+ 	current_req = NULL;
+ }
+ 
+@@ -2332,7 +2330,7 @@ static void request_done(int uptodate)
+ 
+ 		/* unlock chained buffers */
+ 		spin_lock_irqsave(q->queue_lock, flags);
+-		floppy_end_request(req, 1);
++		floppy_end_request(req, 0);
+ 		spin_unlock_irqrestore(q->queue_lock, flags);
+ 	} else {
+ 		if (rq_data_dir(req) == WRITE) {
+@@ -2346,7 +2344,7 @@ static void request_done(int uptodate)
+ 			DRWE->last_error_generation = DRS->generation;
+ 		}
+ 		spin_lock_irqsave(q->queue_lock, flags);
+-		floppy_end_request(req, 0);
++		floppy_end_request(req, -EIO);
+ 		spin_unlock_irqrestore(q->queue_lock, flags);
+ 	}
+ }
+diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c
+index b4c0888..ae31060 100644
+--- a/drivers/block/nbd.c
++++ b/drivers/block/nbd.c
+@@ -100,17 +100,15 @@ static const char *nbdcmd_to_ascii(int cmd)
+ 
+ static void nbd_end_request(struct request *req)
+ {
+-	int uptodate = (req->errors == 0) ? 1 : 0;
++	int error = req->errors ? -EIO : 0;
+ 	struct request_queue *q = req->q;
+ 	unsigned long flags;
+ 
+ 	dprintk(DBG_BLKDEV, "%s: request %p: %s\n", req->rq_disk->disk_name,
+-			req, uptodate? "done": "failed");
++			req, error ? "failed" : "done");
+ 
+ 	spin_lock_irqsave(q->queue_lock, flags);
+-	if (!end_that_request_first(req, uptodate, req->nr_sectors)) {
+-		end_that_request_last(req, uptodate);
+-	}
++	__blk_end_request(req, error, req->nr_sectors << 9);
+ 	spin_unlock_irqrestore(q->queue_lock, flags);
+ }
+ 
+@@ -375,14 +373,17 @@ harderror:
+ 	return NULL;
+ }
+ 
+-static ssize_t pid_show(struct gendisk *disk, char *page)
++static ssize_t pid_show(struct device *dev,
++			struct device_attribute *attr, char *buf)
+ {
+-	return sprintf(page, "%ld\n",
++	struct gendisk *disk = dev_to_disk(dev);
++
++	return sprintf(buf, "%ld\n",
+ 		(long) ((struct nbd_device *)disk->private_data)->pid);
+ }
+ 
+-static struct disk_attribute pid_attr = {
+-	.attr = { .name = "pid", .mode = S_IRUGO },
++static struct device_attribute pid_attr = {
++	.attr = { .name = "pid", .mode = S_IRUGO, .owner = THIS_MODULE },
+ 	.show = pid_show,
+ };
+ 
+@@ -394,7 +395,7 @@ static int nbd_do_it(struct nbd_device *lo)
+ 	BUG_ON(lo->magic != LO_MAGIC);
+ 
+ 	lo->pid = current->pid;
+-	ret = sysfs_create_file(&lo->disk->kobj, &pid_attr.attr);
++	ret = sysfs_create_file(&lo->disk->dev.kobj, &pid_attr.attr);
+ 	if (ret) {
+ 		printk(KERN_ERR "nbd: sysfs_create_file failed!");
+ 		return ret;
+@@ -403,7 +404,7 @@ static int nbd_do_it(struct nbd_device *lo)
+ 	while ((req = nbd_read_stat(lo)) != NULL)
+ 		nbd_end_request(req);
+ 
+-	sysfs_remove_file(&lo->disk->kobj, &pid_attr.attr);
++	sysfs_remove_file(&lo->disk->dev.kobj, &pid_attr.attr);
+ 	return 0;
+ }
+ 
+diff --git a/drivers/block/paride/pg.c b/drivers/block/paride/pg.c
+index d89e7d3..ab86e23 100644
+--- a/drivers/block/paride/pg.c
++++ b/drivers/block/paride/pg.c
+@@ -676,8 +676,8 @@ static int __init pg_init(void)
+ 	for (unit = 0; unit < PG_UNITS; unit++) {
+ 		struct pg *dev = &devices[unit];
+ 		if (dev->present)
+-			class_device_create(pg_class, NULL, MKDEV(major, unit),
+-					NULL, "pg%u", unit);
++			device_create(pg_class, NULL, MKDEV(major, unit),
++				      "pg%u", unit);
+ 	}
+ 	err = 0;
+ 	goto out;
+@@ -695,7 +695,7 @@ static void __exit pg_exit(void)
+ 	for (unit = 0; unit < PG_UNITS; unit++) {
+ 		struct pg *dev = &devices[unit];
+ 		if (dev->present)
+-			class_device_destroy(pg_class, MKDEV(major, unit));
++			device_destroy(pg_class, MKDEV(major, unit));
+ 	}
+ 	class_destroy(pg_class);
+ 	unregister_chrdev(major, name);
+diff --git a/drivers/block/paride/pt.c b/drivers/block/paride/pt.c
+index b91accf..76096ca 100644
+--- a/drivers/block/paride/pt.c
++++ b/drivers/block/paride/pt.c
+@@ -972,10 +972,10 @@ static int __init pt_init(void)
+ 
+ 	for (unit = 0; unit < PT_UNITS; unit++)
+ 		if (pt[unit].present) {
+-			class_device_create(pt_class, NULL, MKDEV(major, unit),
+-					NULL, "pt%d", unit);
+-			class_device_create(pt_class, NULL, MKDEV(major, unit + 128),
+-					NULL, "pt%dn", unit);
++			device_create(pt_class, NULL, MKDEV(major, unit),
++				      "pt%d", unit);
++			device_create(pt_class, NULL, MKDEV(major, unit + 128),
++				      "pt%dn", unit);
+ 		}
+ 	goto out;
+ 
+@@ -990,8 +990,8 @@ static void __exit pt_exit(void)
+ 	int unit;
+ 	for (unit = 0; unit < PT_UNITS; unit++)
+ 		if (pt[unit].present) {
+-			class_device_destroy(pt_class, MKDEV(major, unit));
+-			class_device_destroy(pt_class, MKDEV(major, unit + 128));
++			device_destroy(pt_class, MKDEV(major, unit));
++			device_destroy(pt_class, MKDEV(major, unit + 128));
+ 		}
+ 	class_destroy(pt_class);
+ 	unregister_chrdev(major, name);
+diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c
+index 3535ef8..e9de171 100644
+--- a/drivers/block/pktcdvd.c
++++ b/drivers/block/pktcdvd.c
+@@ -110,17 +110,18 @@ static struct pktcdvd_kobj* pkt_kobj_create(struct pktcdvd_device *pd,
+ 					struct kobj_type* ktype)
+ {
+ 	struct pktcdvd_kobj *p;
++	int error;
++
+ 	p = kzalloc(sizeof(*p), GFP_KERNEL);
+ 	if (!p)
+ 		return NULL;
+-	kobject_set_name(&p->kobj, "%s", name);
+-	p->kobj.parent = parent;
+-	p->kobj.ktype = ktype;
+ 	p->pd = pd;
+-	if (kobject_register(&p->kobj) != 0) {
++	error = kobject_init_and_add(&p->kobj, ktype, parent, "%s", name);
++	if (error) {
+ 		kobject_put(&p->kobj);
+ 		return NULL;
+ 	}
++	kobject_uevent(&p->kobj, KOBJ_ADD);
+ 	return p;
+ }
+ /*
+@@ -129,7 +130,7 @@ static struct pktcdvd_kobj* pkt_kobj_create(struct pktcdvd_device *pd,
+ static void pkt_kobj_remove(struct pktcdvd_kobj *p)
+ {
+ 	if (p)
+-		kobject_unregister(&p->kobj);
++		kobject_put(&p->kobj);
+ }
+ /*
+  * default release function for pktcdvd kernel objects.
+@@ -301,18 +302,16 @@ static struct kobj_type kobj_pkt_type_wqueue = {
+ static void pkt_sysfs_dev_new(struct pktcdvd_device *pd)
+ {
+ 	if (class_pktcdvd) {
+-		pd->clsdev = class_device_create(class_pktcdvd,
+-					NULL, pd->pkt_dev,
+-					NULL, "%s", pd->name);
+-		if (IS_ERR(pd->clsdev))
+-			pd->clsdev = NULL;
++		pd->dev = device_create(class_pktcdvd, NULL, pd->pkt_dev, "%s", pd->name);
++		if (IS_ERR(pd->dev))
++			pd->dev = NULL;
+ 	}
+-	if (pd->clsdev) {
++	if (pd->dev) {
+ 		pd->kobj_stat = pkt_kobj_create(pd, "stat",
+-					&pd->clsdev->kobj,
++					&pd->dev->kobj,
+ 					&kobj_pkt_type_stat);
+ 		pd->kobj_wqueue = pkt_kobj_create(pd, "write_queue",
+-					&pd->clsdev->kobj,
++					&pd->dev->kobj,
+ 					&kobj_pkt_type_wqueue);
+ 	}
+ }
+@@ -322,7 +321,7 @@ static void pkt_sysfs_dev_remove(struct pktcdvd_device *pd)
+ 	pkt_kobj_remove(pd->kobj_stat);
+ 	pkt_kobj_remove(pd->kobj_wqueue);
+ 	if (class_pktcdvd)
+-		class_device_destroy(class_pktcdvd, pd->pkt_dev);
++		device_destroy(class_pktcdvd, pd->pkt_dev);
+ }
+ 
+ 
+diff --git a/drivers/block/ps3disk.c b/drivers/block/ps3disk.c
+index e354bfc..7483f94 100644
+--- a/drivers/block/ps3disk.c
++++ b/drivers/block/ps3disk.c
+@@ -229,7 +229,7 @@ static irqreturn_t ps3disk_interrupt(int irq, void *data)
+ 	struct ps3_storage_device *dev = data;
+ 	struct ps3disk_private *priv;
+ 	struct request *req;
+-	int res, read, uptodate;
++	int res, read, error;
+ 	u64 tag, status;
+ 	unsigned long num_sectors;
+ 	const char *op;
+@@ -270,21 +270,17 @@ static irqreturn_t ps3disk_interrupt(int irq, void *data)
+ 	if (status) {
+ 		dev_dbg(&dev->sbd.core, "%s:%u: %s failed 0x%lx\n", __func__,
+ 			__LINE__, op, status);
+-		uptodate = 0;
++		error = -EIO;
+ 	} else {
+ 		dev_dbg(&dev->sbd.core, "%s:%u: %s completed\n", __func__,
+ 			__LINE__, op);
+-		uptodate = 1;
++		error = 0;
+ 		if (read)
+ 			ps3disk_scatter_gather(dev, req, 0);
+ 	}
+ 
+ 	spin_lock(&priv->lock);
+-	if (!end_that_request_first(req, uptodate, num_sectors)) {
+-		add_disk_randomness(req->rq_disk);
+-		blkdev_dequeue_request(req);
+-		end_that_request_last(req, uptodate);
+-	}
++	__blk_end_request(req, error, num_sectors << 9);
+ 	priv->req = NULL;
+ 	ps3disk_do_request(dev, priv->queue);
+ 	spin_unlock(&priv->lock);
+diff --git a/drivers/block/sunvdc.c b/drivers/block/sunvdc.c
+index fac4c6c..66e3015 100644
+--- a/drivers/block/sunvdc.c
++++ b/drivers/block/sunvdc.c
+@@ -212,12 +212,9 @@ static void vdc_end_special(struct vdc_port *port, struct vio_disk_desc *desc)
+ 	vdc_finish(&port->vio, -err, WAITING_FOR_GEN_CMD);
+ }
+ 
+-static void vdc_end_request(struct request *req, int uptodate, int num_sectors)
++static void vdc_end_request(struct request *req, int error, int num_sectors)
+ {
+-	if (end_that_request_first(req, uptodate, num_sectors))
+-		return;
+-	add_disk_randomness(req->rq_disk);
+-	end_that_request_last(req, uptodate);
++	__blk_end_request(req, error, num_sectors << 9);
+ }
+ 
+ static void vdc_end_one(struct vdc_port *port, struct vio_dring_state *dr,
+@@ -242,7 +239,7 @@ static void vdc_end_one(struct vdc_port *port, struct vio_dring_state *dr,
+ 
+ 	rqe->req = NULL;
+ 
+-	vdc_end_request(req, !desc->status, desc->size >> 9);
++	vdc_end_request(req, (desc->status ? -EIO : 0), desc->size >> 9);
+ 
+ 	if (blk_queue_stopped(port->disk->queue))
+ 		blk_start_queue(port->disk->queue);
+@@ -456,7 +453,7 @@ static void do_vdc_request(struct request_queue *q)
+ 
+ 		blkdev_dequeue_request(req);
+ 		if (__send_request(req) < 0)
+-			vdc_end_request(req, 0, req->hard_nr_sectors);
++			vdc_end_request(req, -EIO, req->hard_nr_sectors);
+ 	}
+ }
+ 
+diff --git a/drivers/block/sx8.c b/drivers/block/sx8.c
+index 52dc5e1..cd5674b 100644
+--- a/drivers/block/sx8.c
++++ b/drivers/block/sx8.c
+@@ -744,16 +744,14 @@ static unsigned int carm_fill_get_fw_ver(struct carm_host *host,
+ 
+ static inline void carm_end_request_queued(struct carm_host *host,
+ 					   struct carm_request *crq,
+-					   int uptodate)
++					   int error)
+ {
+ 	struct request *req = crq->rq;
+ 	int rc;
+ 
+-	rc = end_that_request_first(req, uptodate, req->hard_nr_sectors);
++	rc = __blk_end_request(req, error, blk_rq_bytes(req));
+ 	assert(rc == 0);
+ 
+-	end_that_request_last(req, uptodate);
+-
+ 	rc = carm_put_request(host, crq);
+ 	assert(rc == 0);
+ }
+@@ -793,9 +791,9 @@ static inline void carm_round_robin(struct carm_host *host)
+ }
+ 
+ static inline void carm_end_rq(struct carm_host *host, struct carm_request *crq,
+-			int is_ok)
++			       int error)
+ {
+-	carm_end_request_queued(host, crq, is_ok);
++	carm_end_request_queued(host, crq, error);
+ 	if (max_queue == 1)
+ 		carm_round_robin(host);
+ 	else if ((host->n_msgs <= CARM_MSG_LOW_WATER) &&
+@@ -873,14 +871,14 @@ queue_one_request:
+ 	sg = &crq->sg[0];
+ 	n_elem = blk_rq_map_sg(q, rq, sg);
+ 	if (n_elem <= 0) {
+-		carm_end_rq(host, crq, 0);
++		carm_end_rq(host, crq, -EIO);
+ 		return;		/* request with no s/g entries? */
+ 	}
+ 
+ 	/* map scatterlist to PCI bus addresses */
+ 	n_elem = pci_map_sg(host->pdev, sg, n_elem, pci_dir);
+ 	if (n_elem <= 0) {
+-		carm_end_rq(host, crq, 0);
++		carm_end_rq(host, crq, -EIO);
+ 		return;		/* request with no s/g entries? */
+ 	}
+ 	crq->n_elem = n_elem;
+@@ -941,7 +939,7 @@ queue_one_request:
+ 
+ static void carm_handle_array_info(struct carm_host *host,
+ 				   struct carm_request *crq, u8 *mem,
+-				   int is_ok)
++				   int error)
+ {
+ 	struct carm_port *port;
+ 	u8 *msg_data = mem + sizeof(struct carm_array_info);
+@@ -952,9 +950,9 @@ static void carm_handle_array_info(struct carm_host *host,
+ 
+ 	DPRINTK("ENTER\n");
+ 
+-	carm_end_rq(host, crq, is_ok);
++	carm_end_rq(host, crq, error);
+ 
+-	if (!is_ok)
++	if (error)
+ 		goto out;
+ 	if (le32_to_cpu(desc->array_status) & ARRAY_NO_EXIST)
+ 		goto out;
+@@ -1001,7 +999,7 @@ out:
+ 
+ static void carm_handle_scan_chan(struct carm_host *host,
+ 				  struct carm_request *crq, u8 *mem,
+-				  int is_ok)
++				  int error)
+ {
+ 	u8 *msg_data = mem + IOC_SCAN_CHAN_OFFSET;
+ 	unsigned int i, dev_count = 0;
+@@ -1009,9 +1007,9 @@ static void carm_handle_scan_chan(struct carm_host *host,
+ 
+ 	DPRINTK("ENTER\n");
+ 
+-	carm_end_rq(host, crq, is_ok);
++	carm_end_rq(host, crq, error);
+ 
+-	if (!is_ok) {
++	if (error) {
+ 		new_state = HST_ERROR;
+ 		goto out;
+ 	}
+@@ -1033,23 +1031,23 @@ out:
+ }
+ 
+ static void carm_handle_generic(struct carm_host *host,
+-				struct carm_request *crq, int is_ok,
++				struct carm_request *crq, int error,
+ 				int cur_state, int next_state)
+ {
+ 	DPRINTK("ENTER\n");
+ 
+-	carm_end_rq(host, crq, is_ok);
++	carm_end_rq(host, crq, error);
+ 
+ 	assert(host->state == cur_state);
+-	if (is_ok)
+-		host->state = next_state;
+-	else
++	if (error)
+ 		host->state = HST_ERROR;
++	else
++		host->state = next_state;
+ 	schedule_work(&host->fsm_task);
+ }
+ 
+ static inline void carm_handle_rw(struct carm_host *host,
+-				  struct carm_request *crq, int is_ok)
++				  struct carm_request *crq, int error)
+ {
+ 	int pci_dir;
+ 
+@@ -1062,7 +1060,7 @@ static inline void carm_handle_rw(struct carm_host *host,
+ 
+ 	pci_unmap_sg(host->pdev, &crq->sg[0], crq->n_elem, pci_dir);
+ 
+-	carm_end_rq(host, crq, is_ok);
++	carm_end_rq(host, crq, error);
+ }
+ 
+ static inline void carm_handle_resp(struct carm_host *host,
+@@ -1071,7 +1069,7 @@ static inline void carm_handle_resp(struct carm_host *host,
+ 	u32 handle = le32_to_cpu(ret_handle_le);
+ 	unsigned int msg_idx;
+ 	struct carm_request *crq;
+-	int is_ok = (status == RMSG_OK);
++	int error = (status == RMSG_OK) ? 0 : -EIO;
+ 	u8 *mem;
+ 
+ 	VPRINTK("ENTER, handle == 0x%x\n", handle);
+@@ -1090,7 +1088,7 @@ static inline void carm_handle_resp(struct carm_host *host,
+ 	/* fast path */
+ 	if (likely(crq->msg_type == CARM_MSG_READ ||
+ 		   crq->msg_type == CARM_MSG_WRITE)) {
+-		carm_handle_rw(host, crq, is_ok);
++		carm_handle_rw(host, crq, error);
+ 		return;
+ 	}
+ 
+@@ -1100,7 +1098,7 @@ static inline void carm_handle_resp(struct carm_host *host,
+ 	case CARM_MSG_IOCTL: {
+ 		switch (crq->msg_subtype) {
+ 		case CARM_IOC_SCAN_CHAN:
+-			carm_handle_scan_chan(host, crq, mem, is_ok);
++			carm_handle_scan_chan(host, crq, mem, error);
+ 			break;
+ 		default:
+ 			/* unknown / invalid response */
+@@ -1112,21 +1110,21 @@ static inline void carm_handle_resp(struct carm_host *host,
+ 	case CARM_MSG_MISC: {
+ 		switch (crq->msg_subtype) {
+ 		case MISC_ALLOC_MEM:
+-			carm_handle_generic(host, crq, is_ok,
++			carm_handle_generic(host, crq, error,
+ 					    HST_ALLOC_BUF, HST_SYNC_TIME);
+ 			break;
+ 		case MISC_SET_TIME:
+-			carm_handle_generic(host, crq, is_ok,
++			carm_handle_generic(host, crq, error,
+ 					    HST_SYNC_TIME, HST_GET_FW_VER);
+ 			break;
+ 		case MISC_GET_FW_VER: {
+ 			struct carm_fw_ver *ver = (struct carm_fw_ver *)
+ 				mem + sizeof(struct carm_msg_get_fw_ver);
+-			if (is_ok) {
++			if (!error) {
+ 				host->fw_ver = le32_to_cpu(ver->version);
+ 				host->flags |= (ver->features & FL_FW_VER_MASK);
+ 			}
+-			carm_handle_generic(host, crq, is_ok,
++			carm_handle_generic(host, crq, error,
+ 					    HST_GET_FW_VER, HST_PORT_SCAN);
+ 			break;
+ 		}
+@@ -1140,7 +1138,7 @@ static inline void carm_handle_resp(struct carm_host *host,
+ 	case CARM_MSG_ARRAY: {
+ 		switch (crq->msg_subtype) {
+ 		case CARM_ARRAY_INFO:
+-			carm_handle_array_info(host, crq, mem, is_ok);
++			carm_handle_array_info(host, crq, mem, error);
+ 			break;
+ 		default:
+ 			/* unknown / invalid response */
+@@ -1159,7 +1157,7 @@ static inline void carm_handle_resp(struct carm_host *host,
+ err_out:
+ 	printk(KERN_WARNING DRV_NAME "(%s): BUG: unhandled message type %d/%d\n",
+ 	       pci_name(host->pdev), crq->msg_type, crq->msg_subtype);
+-	carm_end_rq(host, crq, 0);
++	carm_end_rq(host, crq, -EIO);
+ }
+ 
+ static inline void carm_handle_responses(struct carm_host *host)
+diff --git a/drivers/block/ub.c b/drivers/block/ub.c
+index 08e909d..c6179d6 100644
+--- a/drivers/block/ub.c
++++ b/drivers/block/ub.c
+@@ -808,16 +808,16 @@ static void ub_rw_cmd_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
+ 
+ static void ub_end_rq(struct request *rq, unsigned int scsi_status)
+ {
+-	int uptodate;
++	int error;
+ 
+ 	if (scsi_status == 0) {
+-		uptodate = 1;
++		error = 0;
+ 	} else {
+-		uptodate = 0;
++		error = -EIO;
+ 		rq->errors = scsi_status;
+ 	}
+-	end_that_request_first(rq, uptodate, rq->hard_nr_sectors);
+-	end_that_request_last(rq, uptodate);
++	if (__blk_end_request(rq, error, blk_rq_bytes(rq)))
++		BUG();
+ }
+ 
+ static int ub_rw_cmd_retry(struct ub_dev *sc, struct ub_lun *lun,
+diff --git a/drivers/block/viodasd.c b/drivers/block/viodasd.c
+index ab5d404..9e61fca 100644
+--- a/drivers/block/viodasd.c
++++ b/drivers/block/viodasd.c
+@@ -229,13 +229,10 @@ static struct block_device_operations viodasd_fops = {
+ /*
+  * End a request
+  */
+-static void viodasd_end_request(struct request *req, int uptodate,
++static void viodasd_end_request(struct request *req, int error,
+ 		int num_sectors)
+ {
+-	if (end_that_request_first(req, uptodate, num_sectors))
+-		return;
+-	add_disk_randomness(req->rq_disk);
+-	end_that_request_last(req, uptodate);
++	__blk_end_request(req, error, num_sectors << 9);
+ }
+ 
+ /*
+@@ -374,12 +371,12 @@ static void do_viodasd_request(struct request_queue *q)
+ 		blkdev_dequeue_request(req);
+ 		/* check that request contains a valid command */
+ 		if (!blk_fs_request(req)) {
+-			viodasd_end_request(req, 0, req->hard_nr_sectors);
++			viodasd_end_request(req, -EIO, req->hard_nr_sectors);
+ 			continue;
+ 		}
+ 		/* Try sending the request */
+ 		if (send_request(req) != 0)
+-			viodasd_end_request(req, 0, req->hard_nr_sectors);
++			viodasd_end_request(req, -EIO, req->hard_nr_sectors);
+ 	}
+ }
+ 
+@@ -591,7 +588,7 @@ static int viodasd_handle_read_write(struct vioblocklpevent *bevent)
+ 	num_req_outstanding--;
+ 	spin_unlock_irqrestore(&viodasd_spinlock, irq_flags);
+ 
+-	error = event->xRc != HvLpEvent_Rc_Good;
++	error = (event->xRc == HvLpEvent_Rc_Good) ? 0 : -EIO;
+ 	if (error) {
+ 		const struct vio_error_entry *err;
+ 		err = vio_lookup_rc(viodasd_err_table, bevent->sub_result);
+@@ -601,7 +598,7 @@ static int viodasd_handle_read_write(struct vioblocklpevent *bevent)
+ 	}
+ 	qlock = req->q->queue_lock;
+ 	spin_lock_irqsave(qlock, irq_flags);
+-	viodasd_end_request(req, !error, num_sect);
++	viodasd_end_request(req, error, num_sect);
+ 	spin_unlock_irqrestore(qlock, irq_flags);
+ 
+ 	/* Finally, try to get more requests off of this device's queue */
+diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c
+index 2bdebcb..8afce67 100644
+--- a/drivers/block/xen-blkfront.c
++++ b/drivers/block/xen-blkfront.c
+@@ -452,7 +452,7 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id)
+ 	RING_IDX i, rp;
+ 	unsigned long flags;
+ 	struct blkfront_info *info = (struct blkfront_info *)dev_id;
+-	int uptodate;
++	int error;
+ 
+ 	spin_lock_irqsave(&blkif_io_lock, flags);
+ 
+@@ -477,13 +477,13 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id)
+ 
+ 		add_id_to_freelist(info, id);
+ 
+-		uptodate = (bret->status == BLKIF_RSP_OKAY);
++		error = (bret->status == BLKIF_RSP_OKAY) ? 0 : -EIO;
+ 		switch (bret->operation) {
+ 		case BLKIF_OP_WRITE_BARRIER:
+ 			if (unlikely(bret->status == BLKIF_RSP_EOPNOTSUPP)) {
+ 				printk(KERN_WARNING "blkfront: %s: write barrier op failed\n",
+ 				       info->gd->disk_name);
+-				uptodate = -EOPNOTSUPP;
++				error = -EOPNOTSUPP;
+ 				info->feature_barrier = 0;
+ 				xlvbd_barrier(info);
+ 			}
+@@ -494,10 +494,8 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id)
+ 				dev_dbg(&info->xbdev->dev, "Bad return from blkdev data "
+ 					"request: %x\n", bret->status);
+ 
+-			ret = end_that_request_first(req, uptodate,
+-				req->hard_nr_sectors);
++			ret = __blk_end_request(req, error, blk_rq_bytes(req));
+ 			BUG_ON(ret);
+-			end_that_request_last(req, uptodate);
+ 			break;
+ 		default:
+ 			BUG();
+diff --git a/drivers/block/xsysace.c b/drivers/block/xsysace.c
+index 82effce..2c81465 100644
+--- a/drivers/block/xsysace.c
++++ b/drivers/block/xsysace.c
+@@ -703,7 +703,7 @@ static void ace_fsm_dostate(struct ace_device *ace)
+ 
+ 		/* bio finished; is there another one? */
+ 		i = ace->req->current_nr_sectors;
+-		if (end_that_request_first(ace->req, 1, i)) {
++		if (__blk_end_request(ace->req, 0, i)) {
+ 			/* dev_dbg(ace->dev, "next block; h=%li c=%i\n",
+ 			 *      ace->req->hard_nr_sectors,
+ 			 *      ace->req->current_nr_sectors);
+@@ -718,9 +718,6 @@ static void ace_fsm_dostate(struct ace_device *ace)
+ 		break;
+ 
+ 	case ACE_FSM_STATE_REQ_COMPLETE:
+-		/* Complete the block request */
+-		blkdev_dequeue_request(ace->req);
+-		end_that_request_last(ace->req, 1);
+ 		ace->req = NULL;
+ 
+ 		/* Finished request; go to idle state */
+diff --git a/drivers/cdrom/Makefile b/drivers/cdrom/Makefile
+index 774c180..ecf85fd 100644
+--- a/drivers/cdrom/Makefile
++++ b/drivers/cdrom/Makefile
+@@ -11,3 +11,4 @@ obj-$(CONFIG_PARIDE_PCD)	+=		cdrom.o
+ obj-$(CONFIG_CDROM_PKTCDVD)	+=		cdrom.o
+ 
+ obj-$(CONFIG_VIOCD)		+= viocd.o      cdrom.o
++obj-$(CONFIG_GDROM)		+= gdrom.o      cdrom.o
+diff --git a/drivers/cdrom/gdrom.c b/drivers/cdrom/gdrom.c
+new file mode 100644
+index 0000000..4e2bbcc
+--- /dev/null
++++ b/drivers/cdrom/gdrom.c
+@@ -0,0 +1,867 @@
++/* GD ROM driver for the SEGA Dreamcast
++ * copyright Adrian McMenamin, 2007
++ * With thanks to Marcus Comstedt and Nathan Keynes
++ * for work in reversing PIO and DMA
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You 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/init.h>
++#include <linux/module.h>
++#include <linux/fs.h>
++#include <linux/kernel.h>
++#include <linux/list.h>
++#include <linux/slab.h>
++#include <linux/dma-mapping.h>
++#include <linux/cdrom.h>
++#include <linux/genhd.h>
++#include <linux/bio.h>
++#include <linux/blkdev.h>
++#include <linux/interrupt.h>
++#include <linux/device.h>
++#include <linux/wait.h>
++#include <linux/workqueue.h>
++#include <linux/platform_device.h>
++#include <scsi/scsi.h>
++#include <asm/io.h>
++#include <asm/dma.h>
++#include <asm/delay.h>
++#include <asm/mach/dma.h>
++#include <asm/mach/sysasic.h>
++
++#define GDROM_DEV_NAME "gdrom"
++#define GD_SESSION_OFFSET 150
++
++/* GD Rom commands */
++#define GDROM_COM_SOFTRESET 0x08
++#define GDROM_COM_EXECDIAG 0x90
++#define GDROM_COM_PACKET 0xA0
++#define GDROM_COM_IDDEV 0xA1
++
++/* GD Rom registers */
++#define GDROM_BASE_REG			0xA05F7000
++#define GDROM_ALTSTATUS_REG		(GDROM_BASE_REG + 0x18)
++#define GDROM_DATA_REG			(GDROM_BASE_REG + 0x80)
++#define GDROM_ERROR_REG		(GDROM_BASE_REG + 0x84)
++#define GDROM_INTSEC_REG		(GDROM_BASE_REG + 0x88)
++#define GDROM_SECNUM_REG		(GDROM_BASE_REG + 0x8C)
++#define GDROM_BCL_REG			(GDROM_BASE_REG + 0x90)
++#define GDROM_BCH_REG			(GDROM_BASE_REG + 0x94)
++#define GDROM_DSEL_REG			(GDROM_BASE_REG + 0x98)
++#define GDROM_STATUSCOMMAND_REG	(GDROM_BASE_REG + 0x9C)
++#define GDROM_RESET_REG		(GDROM_BASE_REG + 0x4E4)
++
++#define GDROM_DMA_STARTADDR_REG	(GDROM_BASE_REG + 0x404)
++#define GDROM_DMA_LENGTH_REG		(GDROM_BASE_REG + 0x408)
++#define GDROM_DMA_DIRECTION_REG	(GDROM_BASE_REG + 0x40C)
++#define GDROM_DMA_ENABLE_REG		(GDROM_BASE_REG + 0x414)
++#define GDROM_DMA_STATUS_REG		(GDROM_BASE_REG + 0x418)
++#define GDROM_DMA_WAIT_REG		(GDROM_BASE_REG + 0x4A0)
++#define GDROM_DMA_ACCESS_CTRL_REG	(GDROM_BASE_REG + 0x4B8)
++
++#define GDROM_HARD_SECTOR	2048
++#define BLOCK_LAYER_SECTOR	512
++#define GD_TO_BLK		4
++
++#define GDROM_DEFAULT_TIMEOUT	(HZ * 7)
++
++static const struct {
++	int sense_key;
++	const char * const text;
++} sense_texts[] = {
++	{NO_SENSE, "OK"},
++	{RECOVERED_ERROR, "Recovered from error"},
++	{NOT_READY, "Device not ready"},
++	{MEDIUM_ERROR, "Disk not ready"},
++	{HARDWARE_ERROR, "Hardware error"},
++	{ILLEGAL_REQUEST, "Command has failed"},
++	{UNIT_ATTENTION, "Device needs attention - disk may have been changed"},
++	{DATA_PROTECT, "Data protection error"},
++	{ABORTED_COMMAND, "Command aborted"},
++};
++
++static struct platform_device *pd;
++static int gdrom_major;
++static DECLARE_WAIT_QUEUE_HEAD(command_queue);
++static DECLARE_WAIT_QUEUE_HEAD(request_queue);
++
++static DEFINE_SPINLOCK(gdrom_lock);
++static void gdrom_readdisk_dma(struct work_struct *work);
++static DECLARE_WORK(work, gdrom_readdisk_dma);
++static LIST_HEAD(gdrom_deferred);
++
++struct gdromtoc {
++	unsigned int entry[99];
++	unsigned int first, last;
++	unsigned int leadout;
++};
++
++static struct gdrom_unit {
++	struct gendisk *disk;
++	struct cdrom_device_info *cd_info;
++	int status;
++	int pending;
++	int transfer;
++	char disk_type;
++	struct gdromtoc *toc;
++	struct request_queue *gdrom_rq;
++} gd;
++
++struct gdrom_id {
++	char mid;
++	char modid;
++	char verid;
++	char padA[13];
++	char mname[16];
++	char modname[16];
++	char firmver[16];
++	char padB[16];
++};
++
++static int gdrom_getsense(short *bufstring);
++static int gdrom_packetcommand(struct cdrom_device_info *cd_info,
++	struct packet_command *command);
++static int gdrom_hardreset(struct cdrom_device_info *cd_info);
++
++static bool gdrom_is_busy(void)
++{
++	return (ctrl_inb(GDROM_ALTSTATUS_REG) & 0x80) != 0;
++}
++
++static bool gdrom_data_request(void)
++{
++	return (ctrl_inb(GDROM_ALTSTATUS_REG) & 0x88) == 8;
++}
++
++static bool gdrom_wait_clrbusy(void)
++{
++	unsigned long timeout = jiffies + GDROM_DEFAULT_TIMEOUT;
++	while ((ctrl_inb(GDROM_ALTSTATUS_REG) & 0x80) &&
++		(time_before(jiffies, timeout)))
++		cpu_relax();
++	return time_before(jiffies, timeout + 1);
++}
++
++static bool gdrom_wait_busy_sleeps(void)
++{
++	unsigned long timeout;
++	/* Wait to get busy first */
++	timeout = jiffies + GDROM_DEFAULT_TIMEOUT;
++	while (!gdrom_is_busy() && time_before(jiffies, timeout))
++		cpu_relax();
++	/* Now wait for busy to clear */
++	return gdrom_wait_clrbusy();
++}
++
++static void gdrom_identifydevice(void *buf)
++{
++	int c;
++	short *data = buf;
++	/* If the device won't clear it has probably
++	* been hit by a serious failure - but we'll
++	* try to return a sense key even so */
++	if (!gdrom_wait_clrbusy()) {
++		gdrom_getsense(NULL);
++		return;
++	}
++	ctrl_outb(GDROM_COM_IDDEV, GDROM_STATUSCOMMAND_REG);
++	if (!gdrom_wait_busy_sleeps()) {
++		gdrom_getsense(NULL);
++		return;
++	}
++	/* now read in the data */
++	for (c = 0; c < 40; c++)
++		data[c] = ctrl_inw(GDROM_DATA_REG);
++}
++
++static void gdrom_spicommand(void *spi_string, int buflen)
++{
++	short *cmd = spi_string;
++	unsigned long timeout;
++
++	/* ensure IRQ_WAIT is set */
++	ctrl_outb(0x08, GDROM_ALTSTATUS_REG);
++	/* specify how many bytes we expect back */
++	ctrl_outb(buflen & 0xFF, GDROM_BCL_REG);
++	ctrl_outb((buflen >> 8) & 0xFF, GDROM_BCH_REG);
++	/* other parameters */
++	ctrl_outb(0, GDROM_INTSEC_REG);
++	ctrl_outb(0, GDROM_SECNUM_REG);
++	ctrl_outb(0, GDROM_ERROR_REG);
++	/* Wait until we can go */
++	if (!gdrom_wait_clrbusy()) {
++		gdrom_getsense(NULL);
++		return;
++	}
++	timeout = jiffies + GDROM_DEFAULT_TIMEOUT;
++	ctrl_outb(GDROM_COM_PACKET, GDROM_STATUSCOMMAND_REG);
++	while (!gdrom_data_request() && time_before(jiffies, timeout))
++		cpu_relax();
++	if (!time_before(jiffies, timeout + 1)) {
++		gdrom_getsense(NULL);
++		return;
++	}
++	outsw(PHYSADDR(GDROM_DATA_REG), cmd, 6);
++}
++
++
++/* gdrom_command_executediagnostic:
++ * Used to probe for presence of working GDROM
++ * Restarts GDROM device and then applies standard ATA 3
++ * Execute Diagnostic Command: a return of '1' indicates device 0
++ * present and device 1 absent
++ */
++static char gdrom_execute_diagnostic(void)
++{
++	gdrom_hardreset(gd.cd_info);
++	if (!gdrom_wait_clrbusy())
++		return 0;
++	ctrl_outb(GDROM_COM_EXECDIAG, GDROM_STATUSCOMMAND_REG);
++	if (!gdrom_wait_busy_sleeps())
++		return 0;
++	return ctrl_inb(GDROM_ERROR_REG);
++}
++
++/*
++ * Prepare disk command
++ * byte 0 = 0x70
++ * byte 1 = 0x1f
++ */
++static int gdrom_preparedisk_cmd(void)
++{
++	struct packet_command *spin_command;
++	spin_command = kzalloc(sizeof(struct packet_command), GFP_KERNEL);
++	if (!spin_command)
++		return -ENOMEM;
++	spin_command->cmd[0] = 0x70;
++	spin_command->cmd[2] = 0x1f;
++	spin_command->buflen = 0;
++	gd.pending = 1;
++	gdrom_packetcommand(gd.cd_info, spin_command);
++	/* 60 second timeout */
++	wait_event_interruptible_timeout(command_queue, gd.pending == 0,
++		GDROM_DEFAULT_TIMEOUT);
++	gd.pending = 0;
++	kfree(spin_command);
++	if (gd.status & 0x01) {
++		/* log an error */
++		gdrom_getsense(NULL);
++		return -EIO;
++	}
++	return 0;
++}
++
++/*
++ * Read TOC command
++ * byte 0 = 0x14
++ * byte 1 = session
++ * byte 3 = sizeof TOC >> 8  ie upper byte
++ * byte 4 = sizeof TOC & 0xff ie lower byte
++ */
++static int gdrom_readtoc_cmd(struct gdromtoc *toc, int session)
++{
++	int tocsize;
++	struct packet_command *toc_command;
++	int err = 0;
++
++	toc_command = kzalloc(sizeof(struct packet_command), GFP_KERNEL);
++	if (!toc_command)
++		return -ENOMEM;
++	tocsize = sizeof(struct gdromtoc);
++	toc_command->cmd[0] = 0x14;
++	toc_command->cmd[1] = session;
++	toc_command->cmd[3] = tocsize >> 8;
++	toc_command->cmd[4] = tocsize & 0xff;
++	toc_command->buflen = tocsize;
++	if (gd.pending) {
++		err = -EBUSY;
++		goto cleanup_readtoc_final;
++	}
++	gd.pending = 1;
++	gdrom_packetcommand(gd.cd_info, toc_command);
++	wait_event_interruptible_timeout(command_queue, gd.pending == 0,
++		GDROM_DEFAULT_TIMEOUT);
++	if (gd.pending) {
++		err = -EINVAL;
++		goto cleanup_readtoc;
++	}
++	insw(PHYSADDR(GDROM_DATA_REG), toc, tocsize/2);
++	if (gd.status & 0x01)
++		err = -EINVAL;
++
++cleanup_readtoc:
++	gd.pending = 0;
++cleanup_readtoc_final:
++	kfree(toc_command);
++	return err;
++}
++
++/* TOC helpers */
++static int get_entry_lba(int track)
++{
++	return (cpu_to_be32(track & 0xffffff00) - GD_SESSION_OFFSET);
++}
++
++static int get_entry_q_ctrl(int track)
++{
++	return (track & 0x000000f0) >> 4;
++}
++
++static int get_entry_track(int track)
++{
++	return (track & 0x0000ff00) >> 8;
++}
++
++static int gdrom_get_last_session(struct cdrom_device_info *cd_info,
++	struct cdrom_multisession *ms_info)
++{
++	int fentry, lentry, track, data, tocuse, err;
++	if (!gd.toc)
++		return -ENOMEM;
++	tocuse = 1;
++	/* Check if GD-ROM */
++	err = gdrom_readtoc_cmd(gd.toc, 1);
++	/* Not a GD-ROM so check if standard CD-ROM */
++	if (err) {
++		tocuse = 0;
++		err = gdrom_readtoc_cmd(gd.toc, 0);
++		if (err) {
++			printk(KERN_INFO "GDROM: Could not get CD "
++				"table of contents\n");
++			return -ENXIO;
++		}
++	}
++
++	fentry = get_entry_track(gd.toc->first);
++	lentry = get_entry_track(gd.toc->last);
++	/* Find the first data track */
++	track = get_entry_track(gd.toc->last);
++	do {
++		data = gd.toc->entry[track - 1];
++		if (get_entry_q_ctrl(data))
++			break;	/* ie a real data track */
++		track--;
++	} while (track >= fentry);
++
++	if ((track > 100) || (track < get_entry_track(gd.toc->first))) {
++		printk(KERN_INFO "GDROM: No data on the last "
++			"session of the CD\n");
++		gdrom_getsense(NULL);
++		return -ENXIO;
++	}
++
++	ms_info->addr_format = CDROM_LBA;
++	ms_info->addr.lba = get_entry_lba(data);
++	ms_info->xa_flag = 1;
++	return 0;
++}
++
++static int gdrom_open(struct cdrom_device_info *cd_info, int purpose)
++{
++	/* spin up the disk */
++	return gdrom_preparedisk_cmd();
++}
++
++/* this function is required even if empty */
++static void gdrom_release(struct cdrom_device_info *cd_info)
++{
++}
++
++static int gdrom_drivestatus(struct cdrom_device_info *cd_info, int ignore)
++{
++	/* read the sense key */
++	char sense = ctrl_inb(GDROM_ERROR_REG);
++	sense &= 0xF0;
++	if (sense == 0)
++		return CDS_DISC_OK;
++	if (sense == 0x20)
++		return CDS_DRIVE_NOT_READY;
++	/* default */
++	return CDS_NO_INFO;
++}
++
++static int gdrom_mediachanged(struct cdrom_device_info *cd_info, int ignore)
++{
++	/* check the sense key */
++	return (ctrl_inb(GDROM_ERROR_REG) & 0xF0) == 0x60;
++}
++
++/* reset the G1 bus */
++static int gdrom_hardreset(struct cdrom_device_info *cd_info)
++{
++	int count;
++	ctrl_outl(0x1fffff, GDROM_RESET_REG);
++	for (count = 0xa0000000; count < 0xa0200000; count += 4)
++		ctrl_inl(count);
++	return 0;
++}
++
++/* keep the function looking like the universal
++ * CD Rom specification  - returning int */
++static int gdrom_packetcommand(struct cdrom_device_info *cd_info,
++	struct packet_command *command)
++{
++	gdrom_spicommand(&command->cmd, command->buflen);
++	return 0;
++}
++
++/* Get Sense SPI command
++ * From Marcus Comstedt
++ * cmd = 0x13
++ * cmd + 4 = length of returned buffer
++ * Returns 5 16 bit words
++ */
++static int gdrom_getsense(short *bufstring)
++{
++	struct packet_command *sense_command;
++	short sense[5];
++	int sense_key;
++	int err = -EIO;
++
++	sense_command = kzalloc(sizeof(struct packet_command), GFP_KERNEL);
++	if (!sense_command)
++		return -ENOMEM;
++	sense_command->cmd[0] = 0x13;
++	sense_command->cmd[4] = 10;
++	sense_command->buflen = 10;
++	/* even if something is pending try to get
++	* the sense key if possible */
++	if (gd.pending && !gdrom_wait_clrbusy()) {
++		err = -EBUSY;
++		goto cleanup_sense_final;
++	}
++	gd.pending = 1;
++	gdrom_packetcommand(gd.cd_info, sense_command);
++	wait_event_interruptible_timeout(command_queue, gd.pending == 0,
++		GDROM_DEFAULT_TIMEOUT);
++	if (gd.pending)
++		goto cleanup_sense;
++	insw(PHYSADDR(GDROM_DATA_REG), &sense, sense_command->buflen/2);
++	if (sense[1] & 40) {
++		printk(KERN_INFO "GDROM: Drive not ready - command aborted\n");
++		goto cleanup_sense;
++	}
++	sense_key = sense[1] & 0x0F;
++	if (sense_key < ARRAY_SIZE(sense_texts))
++		printk(KERN_INFO "GDROM: %s\n", sense_texts[sense_key].text);
++	else
++		printk(KERN_ERR "GDROM: Unknown sense key: %d\n", sense_key);
++	if (bufstring) /* return addional sense data */
++		memcpy(bufstring, &sense[4], 2);
++	if (sense_key < 2)
++		err = 0;
++
++cleanup_sense:
++	gd.pending = 0;
++cleanup_sense_final:
++	kfree(sense_command);
++	return err;
++}
++
++static struct cdrom_device_ops gdrom_ops = {
++	.open			= gdrom_open,
++	.release		= gdrom_release,
++	.drive_status		= gdrom_drivestatus,
++	.media_changed		= gdrom_mediachanged,
++	.get_last_session	= gdrom_get_last_session,
++	.reset			= gdrom_hardreset,
++	.capability		= CDC_MULTI_SESSION | CDC_MEDIA_CHANGED |
++				  CDC_RESET | CDC_DRIVE_STATUS | CDC_CD_R,
++	.n_minors		= 1,
++};
++
++static int gdrom_bdops_open(struct inode *inode, struct file *file)
++{
++	return cdrom_open(gd.cd_info, inode, file);
++}
++
++static int gdrom_bdops_release(struct inode *inode, struct file *file)
++{
++	return cdrom_release(gd.cd_info, file);
++}
++
++static int gdrom_bdops_mediachanged(struct gendisk *disk)
++{
++	return cdrom_media_changed(gd.cd_info);
++}
++
++static int gdrom_bdops_ioctl(struct inode *inode, struct file *file,
++	unsigned cmd, unsigned long arg)
++{
++	return cdrom_ioctl(file, gd.cd_info, inode, cmd, arg);
++}
++
++static struct block_device_operations gdrom_bdops = {
++	.owner			= THIS_MODULE,
++	.open			= gdrom_bdops_open,
++	.release		= gdrom_bdops_release,
++	.media_changed		= gdrom_bdops_mediachanged,
++	.ioctl			= gdrom_bdops_ioctl,
++};
++
++static irqreturn_t gdrom_command_interrupt(int irq, void *dev_id)
++{
++	gd.status = ctrl_inb(GDROM_STATUSCOMMAND_REG);
++	if (gd.pending != 1)
++		return IRQ_HANDLED;
++	gd.pending = 0;
++	wake_up_interruptible(&command_queue);
++	return IRQ_HANDLED;
++}
++
++static irqreturn_t gdrom_dma_interrupt(int irq, void *dev_id)
++{
++	gd.status = ctrl_inb(GDROM_STATUSCOMMAND_REG);
++	if (gd.transfer != 1)
++		return IRQ_HANDLED;
++	gd.transfer = 0;
++	wake_up_interruptible(&request_queue);
++	return IRQ_HANDLED;
++}
++
++static int __devinit gdrom_set_interrupt_handlers(void)
++{
++	int err;
++
++	err = request_irq(HW_EVENT_GDROM_CMD, gdrom_command_interrupt,
++		IRQF_DISABLED, "gdrom_command", &gd);
++	if (err)
++		return err;
++	err = request_irq(HW_EVENT_GDROM_DMA, gdrom_dma_interrupt,
++		IRQF_DISABLED, "gdrom_dma", &gd);
++	if (err)
++		free_irq(HW_EVENT_GDROM_CMD, &gd);
++	return err;
++}
++
++/* Implement DMA read using SPI command
++ * 0 -> 0x30
++ * 1 -> mode
++ * 2 -> block >> 16
++ * 3 -> block >> 8
++ * 4 -> block
++ * 8 -> sectors >> 16
++ * 9 -> sectors >> 8
++ * 10 -> sectors
++ */
++static void gdrom_readdisk_dma(struct work_struct *work)
++{
++	int err, block, block_cnt;
++	struct packet_command *read_command;
++	struct list_head *elem, *next;
++	struct request *req;
++	unsigned long timeout;
++
++	if (list_empty(&gdrom_deferred))
++		return;
++	read_command = kzalloc(sizeof(struct packet_command), GFP_KERNEL);
++	if (!read_command)
++		return; /* get more memory later? */
++	read_command->cmd[0] = 0x30;
++	read_command->cmd[1] = 0x20;
++	spin_lock(&gdrom_lock);
++	list_for_each_safe(elem, next, &gdrom_deferred) {
++		req = list_entry(elem, struct request, queuelist);
++		spin_unlock(&gdrom_lock);
++		block = req->sector/GD_TO_BLK + GD_SESSION_OFFSET;
++		block_cnt = req->nr_sectors/GD_TO_BLK;
++		ctrl_outl(PHYSADDR(req->buffer), GDROM_DMA_STARTADDR_REG);
++		ctrl_outl(block_cnt * GDROM_HARD_SECTOR, GDROM_DMA_LENGTH_REG);
++		ctrl_outl(1, GDROM_DMA_DIRECTION_REG);
++		ctrl_outl(1, GDROM_DMA_ENABLE_REG);
++		read_command->cmd[2] = (block >> 16) & 0xFF;
++		read_command->cmd[3] = (block >> 8) & 0xFF;
++		read_command->cmd[4] = block & 0xFF;
++		read_command->cmd[8] = (block_cnt >> 16) & 0xFF;
++		read_command->cmd[9] = (block_cnt >> 8) & 0xFF;
++		read_command->cmd[10] = block_cnt & 0xFF;
++		/* set for DMA */
++		ctrl_outb(1, GDROM_ERROR_REG);
++		/* other registers */
++		ctrl_outb(0, GDROM_SECNUM_REG);
++		ctrl_outb(0, GDROM_BCL_REG);
++		ctrl_outb(0, GDROM_BCH_REG);
++		ctrl_outb(0, GDROM_DSEL_REG);
++		ctrl_outb(0, GDROM_INTSEC_REG);
++		/* Wait for registers to reset after any previous activity */
++		timeout = jiffies + HZ / 2;
++		while (gdrom_is_busy() && time_before(jiffies, timeout))
++			cpu_relax();
++		ctrl_outb(GDROM_COM_PACKET, GDROM_STATUSCOMMAND_REG);
++		timeout = jiffies + HZ / 2;
++		/* Wait for packet command to finish */
++		while (gdrom_is_busy() && time_before(jiffies, timeout))
++			cpu_relax();
++		gd.pending = 1;
++		gd.transfer = 1;
++		outsw(PHYSADDR(GDROM_DATA_REG), &read_command->cmd, 6);
++		timeout = jiffies + HZ / 2;
++		/* Wait for any pending DMA to finish */
++		while (ctrl_inb(GDROM_DMA_STATUS_REG) &&
++			time_before(jiffies, timeout))
++			cpu_relax();
++		/* start transfer */
++		ctrl_outb(1, GDROM_DMA_STATUS_REG);
++		wait_event_interruptible_timeout(request_queue,
++			gd.transfer == 0, GDROM_DEFAULT_TIMEOUT);
++		err = gd.transfer;
++		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);
++	}
++	spin_unlock(&gdrom_lock);
++	kfree(read_command);
++}
++
++static void gdrom_request_handler_dma(struct request *req)
++{
++	/* dequeue, add to list of deferred work
++	* and then schedule workqueue */
++	blkdev_dequeue_request(req);
++	list_add_tail(&req->queuelist, &gdrom_deferred);
++	schedule_work(&work);
++}
++
++static void gdrom_request(struct request_queue *rq)
++{
++	struct request *req;
++
++	while ((req = elv_next_request(rq)) != NULL) {
++		if (!blk_fs_request(req)) {
++			printk(KERN_DEBUG "GDROM: Non-fs request ignored\n");
++			end_request(req, 0);
++		}
++		if (rq_data_dir(req) != READ) {
++			printk(KERN_NOTICE "GDROM: Read only device -");
++			printk(" write request ignored\n");
++			end_request(req, 0);
++		}
++		if (req->nr_sectors)
++			gdrom_request_handler_dma(req);
++		else
++			end_request(req, 0);
++	}
++}
++
++/* Print string identifying GD ROM device */
++static int __devinit gdrom_outputversion(void)
++{
++	struct gdrom_id *id;
++	char *model_name, *manuf_name, *firmw_ver;
++	int err = -ENOMEM;
++
++	/* query device ID */
++	id = kzalloc(sizeof(struct gdrom_id), GFP_KERNEL);
++	if (!id)
++		return err;
++	gdrom_identifydevice(id);
++	model_name = kstrndup(id->modname, 16, GFP_KERNEL);
++	if (!model_name)
++		goto free_id;
++	manuf_name = kstrndup(id->mname, 16, GFP_KERNEL);
++	if (!manuf_name)
++		goto free_model_name;
++	firmw_ver = kstrndup(id->firmver, 16, GFP_KERNEL);
++	if (!firmw_ver)
++		goto free_manuf_name;
++	printk(KERN_INFO "GDROM: %s from %s with firmware %s\n",
++		model_name, manuf_name, firmw_ver);
++	err = 0;
++	kfree(firmw_ver);
++free_manuf_name:
++	kfree(manuf_name);
++free_model_name:
++	kfree(model_name);
++free_id:
++	kfree(id);
++	return err;
++}
++
++/* set the default mode for DMA transfer */
++static int __devinit gdrom_init_dma_mode(void)
++{
++	ctrl_outb(0x13, GDROM_ERROR_REG);
++	ctrl_outb(0x22, GDROM_INTSEC_REG);
++	if (!gdrom_wait_clrbusy())
++		return -EBUSY;
++	ctrl_outb(0xEF, GDROM_STATUSCOMMAND_REG);
++	if (!gdrom_wait_busy_sleeps())
++		return -EBUSY;
++	/* Memory protection setting for GDROM DMA
++	* Bits 31 - 16 security: 0x8843
++	* Bits 15 and 7 reserved (0)
++	* Bits 14 - 8 start of transfer range in 1 MB blocks OR'ed with 0x80
++	* Bits 6 - 0 end of transfer range in 1 MB blocks OR'ed with 0x80
++	* (0x40 | 0x80) = start range at 0x0C000000
++	* (0x7F | 0x80) = end range at 0x0FFFFFFF */
++	ctrl_outl(0x8843407F, GDROM_DMA_ACCESS_CTRL_REG);
++	ctrl_outl(9, GDROM_DMA_WAIT_REG); /* DMA word setting */
++	return 0;
++}
++
++static void __devinit probe_gdrom_setupcd(void)
++{
++	gd.cd_info->ops = &gdrom_ops;
++	gd.cd_info->capacity = 1;
++	strcpy(gd.cd_info->name, GDROM_DEV_NAME);
++	gd.cd_info->mask = CDC_CLOSE_TRAY|CDC_OPEN_TRAY|CDC_LOCK|
++		CDC_SELECT_DISC;
++}
++
++static void __devinit probe_gdrom_setupdisk(void)
++{
++	gd.disk->major = gdrom_major;
++	gd.disk->first_minor = 1;
++	gd.disk->minors = 1;
++	strcpy(gd.disk->disk_name, GDROM_DEV_NAME);
++}
++
++static int __devinit probe_gdrom_setupqueue(void)
++{
++	blk_queue_hardsect_size(gd.gdrom_rq, GDROM_HARD_SECTOR);
++	/* using DMA so memory will need to be contiguous */
++	blk_queue_max_hw_segments(gd.gdrom_rq, 1);
++	/* set a large max size to get most from DMA */
++	blk_queue_max_segment_size(gd.gdrom_rq, 0x40000);
++	gd.disk->queue = gd.gdrom_rq;
++	return gdrom_init_dma_mode();
++}
++
++/*
++ * register this as a block device and as compliant with the
++ * universal CD Rom driver interface
++ */
++static int __devinit probe_gdrom(struct platform_device *devptr)
++{
++	int err;
++	/* Start the device */
++	if (gdrom_execute_diagnostic() != 1) {
++		printk(KERN_WARNING "GDROM: ATA Probe for GDROM failed.\n");
++		return -ENODEV;
++	}
++	/* Print out firmware ID */
++	if (gdrom_outputversion())
++		return -ENOMEM;
++	/* Register GDROM */
++	gdrom_major = register_blkdev(0, GDROM_DEV_NAME);
++	if (gdrom_major <= 0)
++		return gdrom_major;
++	printk(KERN_INFO "GDROM: Registered with major number %d\n",
++		gdrom_major);
++	/* Specify basic properties of drive */
++	gd.cd_info = kzalloc(sizeof(struct cdrom_device_info), GFP_KERNEL);
++	if (!gd.cd_info) {
++		err = -ENOMEM;
++		goto probe_fail_no_mem;
++	}
++	probe_gdrom_setupcd();
++	gd.disk = alloc_disk(1);
++	if (!gd.disk) {
++		err = -ENODEV;
++		goto probe_fail_no_disk;
++	}
++	probe_gdrom_setupdisk();
++	if (register_cdrom(gd.cd_info)) {
++		err = -ENODEV;
++		goto probe_fail_cdrom_register;
++	}
++	gd.disk->fops = &gdrom_bdops;
++	/* latch on to the interrupt */
++	err = gdrom_set_interrupt_handlers();
++	if (err)
++		goto probe_fail_cmdirq_register;
++	gd.gdrom_rq = blk_init_queue(gdrom_request, &gdrom_lock);
++	if (!gd.gdrom_rq)
++		goto probe_fail_requestq;
++
++	err = probe_gdrom_setupqueue();
++	if (err)
++		goto probe_fail_toc;
++
++	gd.toc = kzalloc(sizeof(struct gdromtoc), GFP_KERNEL);
++	if (!gd.toc)
++		goto probe_fail_toc;
++	add_disk(gd.disk);
++	return 0;
++
++probe_fail_toc:
++	blk_cleanup_queue(gd.gdrom_rq);
++probe_fail_requestq:
++	free_irq(HW_EVENT_GDROM_DMA, &gd);
++	free_irq(HW_EVENT_GDROM_CMD, &gd);
++probe_fail_cmdirq_register:
++probe_fail_cdrom_register:
++	del_gendisk(gd.disk);
++probe_fail_no_disk:
++	kfree(gd.cd_info);
++	unregister_blkdev(gdrom_major, GDROM_DEV_NAME);
++	gdrom_major = 0;
++probe_fail_no_mem:
++	printk(KERN_WARNING "GDROM: Probe failed - error is 0x%X\n", err);
++	return err;
++}
++
++static int __devexit remove_gdrom(struct platform_device *devptr)
++{
++	flush_scheduled_work();
++	blk_cleanup_queue(gd.gdrom_rq);
++	free_irq(HW_EVENT_GDROM_CMD, &gd);
++	free_irq(HW_EVENT_GDROM_DMA, &gd);
++	del_gendisk(gd.disk);
++	if (gdrom_major)
++		unregister_blkdev(gdrom_major, GDROM_DEV_NAME);
++	return unregister_cdrom(gd.cd_info);
++}
++
++static struct platform_driver gdrom_driver = {
++	.probe = probe_gdrom,
++	.remove = __devexit_p(remove_gdrom),
++	.driver = {
++			.name = GDROM_DEV_NAME,
++	},
++};
++
++static int __init init_gdrom(void)
++{
++	int rc;
++	gd.toc = NULL;
++	rc = platform_driver_register(&gdrom_driver);
++	if (rc)
++		return rc;
++	pd = platform_device_register_simple(GDROM_DEV_NAME, -1, NULL, 0);
++	if (IS_ERR(pd)) {
++		platform_driver_unregister(&gdrom_driver);
++		return PTR_ERR(pd);
++	}
++	return 0;
++}
++
++static void __exit exit_gdrom(void)
++{
++	platform_device_unregister(pd);
++	platform_driver_unregister(&gdrom_driver);
++	kfree(gd.toc);
++}
++
++module_init(init_gdrom);
++module_exit(exit_gdrom);
++MODULE_AUTHOR("Adrian McMenamin <adrian at mcmen.demon.co.uk>");
++MODULE_DESCRIPTION("SEGA Dreamcast GD-ROM Driver");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/cdrom/viocd.c b/drivers/cdrom/viocd.c
+index d8bb44b..8473b9f 100644
+--- a/drivers/cdrom/viocd.c
++++ b/drivers/cdrom/viocd.c
+@@ -289,7 +289,7 @@ static int send_request(struct request *req)
  	return 0;
  }
-@@ -272,7 +271,7 @@ aoechr_exit(void)
- 	int i;
- 
- 	for (i = 0; i < ARRAY_SIZE(chardevs); ++i)
--		class_device_destroy(aoe_class, MKDEV(AOE_MAJOR, chardevs[i].minor));
-+		device_destroy(aoe_class, MKDEV(AOE_MAJOR, chardevs[i].minor));
- 	class_destroy(aoe_class);
- 	unregister_chrdev(AOE_MAJOR, "aoechr");
- }
-diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c
-index b4c0888..ba9b17e 100644
---- a/drivers/block/nbd.c
-+++ b/drivers/block/nbd.c
-@@ -375,14 +375,17 @@ harderror:
- 	return NULL;
- }
  
--static ssize_t pid_show(struct gendisk *disk, char *page)
-+static ssize_t pid_show(struct device *dev,
-+			struct device_attribute *attr, char *buf)
+-static void viocd_end_request(struct request *req, int uptodate)
++static void viocd_end_request(struct request *req, int error)
  {
--	return sprintf(page, "%ld\n",
-+	struct gendisk *disk = dev_to_disk(dev);
-+
-+	return sprintf(buf, "%ld\n",
- 		(long) ((struct nbd_device *)disk->private_data)->pid);
- }
- 
--static struct disk_attribute pid_attr = {
--	.attr = { .name = "pid", .mode = S_IRUGO },
-+static struct device_attribute pid_attr = {
-+	.attr = { .name = "pid", .mode = S_IRUGO, .owner = THIS_MODULE },
- 	.show = pid_show,
- };
- 
-@@ -394,7 +397,7 @@ static int nbd_do_it(struct nbd_device *lo)
- 	BUG_ON(lo->magic != LO_MAGIC);
+ 	int nsectors = req->hard_nr_sectors;
  
- 	lo->pid = current->pid;
--	ret = sysfs_create_file(&lo->disk->kobj, &pid_attr.attr);
-+	ret = sysfs_create_file(&lo->disk->dev.kobj, &pid_attr.attr);
- 	if (ret) {
- 		printk(KERN_ERR "nbd: sysfs_create_file failed!");
- 		return ret;
-@@ -403,7 +406,7 @@ static int nbd_do_it(struct nbd_device *lo)
- 	while ((req = nbd_read_stat(lo)) != NULL)
- 		nbd_end_request(req);
+@@ -302,11 +302,8 @@ static void viocd_end_request(struct request *req, int uptodate)
+ 	if (!nsectors)
+ 		nsectors = 1;
  
--	sysfs_remove_file(&lo->disk->kobj, &pid_attr.attr);
-+	sysfs_remove_file(&lo->disk->dev.kobj, &pid_attr.attr);
- 	return 0;
+-	if (end_that_request_first(req, uptodate, nsectors))
++	if (__blk_end_request(req, error, nsectors << 9))
+ 		BUG();
+-	add_disk_randomness(req->rq_disk);
+-	blkdev_dequeue_request(req);
+-	end_that_request_last(req, uptodate);
  }
  
-diff --git a/drivers/block/paride/pg.c b/drivers/block/paride/pg.c
-index d89e7d3..ab86e23 100644
---- a/drivers/block/paride/pg.c
-+++ b/drivers/block/paride/pg.c
-@@ -676,8 +676,8 @@ static int __init pg_init(void)
- 	for (unit = 0; unit < PG_UNITS; unit++) {
- 		struct pg *dev = &devices[unit];
- 		if (dev->present)
--			class_device_create(pg_class, NULL, MKDEV(major, unit),
--					NULL, "pg%u", unit);
-+			device_create(pg_class, NULL, MKDEV(major, unit),
-+				      "pg%u", unit);
- 	}
- 	err = 0;
- 	goto out;
-@@ -695,7 +695,7 @@ static void __exit pg_exit(void)
- 	for (unit = 0; unit < PG_UNITS; unit++) {
- 		struct pg *dev = &devices[unit];
- 		if (dev->present)
--			class_device_destroy(pg_class, MKDEV(major, unit));
-+			device_destroy(pg_class, MKDEV(major, unit));
- 	}
- 	class_destroy(pg_class);
- 	unregister_chrdev(major, name);
-diff --git a/drivers/block/paride/pt.c b/drivers/block/paride/pt.c
-index b91accf..76096ca 100644
---- a/drivers/block/paride/pt.c
-+++ b/drivers/block/paride/pt.c
-@@ -972,10 +972,10 @@ static int __init pt_init(void)
- 
- 	for (unit = 0; unit < PT_UNITS; unit++)
- 		if (pt[unit].present) {
--			class_device_create(pt_class, NULL, MKDEV(major, unit),
--					NULL, "pt%d", unit);
--			class_device_create(pt_class, NULL, MKDEV(major, unit + 128),
--					NULL, "pt%dn", unit);
-+			device_create(pt_class, NULL, MKDEV(major, unit),
-+				      "pt%d", unit);
-+			device_create(pt_class, NULL, MKDEV(major, unit + 128),
-+				      "pt%dn", unit);
- 		}
- 	goto out;
+ static int rwreq;
+@@ -317,11 +314,11 @@ static void do_viocd_request(struct request_queue *q)
  
-@@ -990,8 +990,8 @@ static void __exit pt_exit(void)
- 	int unit;
- 	for (unit = 0; unit < PT_UNITS; unit++)
- 		if (pt[unit].present) {
--			class_device_destroy(pt_class, MKDEV(major, unit));
--			class_device_destroy(pt_class, MKDEV(major, unit + 128));
-+			device_destroy(pt_class, MKDEV(major, unit));
-+			device_destroy(pt_class, MKDEV(major, unit + 128));
- 		}
- 	class_destroy(pt_class);
- 	unregister_chrdev(major, name);
-diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c
-index 3535ef8..e9de171 100644
---- a/drivers/block/pktcdvd.c
-+++ b/drivers/block/pktcdvd.c
-@@ -110,17 +110,18 @@ static struct pktcdvd_kobj* pkt_kobj_create(struct pktcdvd_device *pd,
- 					struct kobj_type* ktype)
- {
- 	struct pktcdvd_kobj *p;
-+	int error;
-+
- 	p = kzalloc(sizeof(*p), GFP_KERNEL);
- 	if (!p)
- 		return NULL;
--	kobject_set_name(&p->kobj, "%s", name);
--	p->kobj.parent = parent;
--	p->kobj.ktype = ktype;
- 	p->pd = pd;
--	if (kobject_register(&p->kobj) != 0) {
-+	error = kobject_init_and_add(&p->kobj, ktype, parent, "%s", name);
-+	if (error) {
- 		kobject_put(&p->kobj);
- 		return NULL;
- 	}
-+	kobject_uevent(&p->kobj, KOBJ_ADD);
- 	return p;
- }
- /*
-@@ -129,7 +130,7 @@ static struct pktcdvd_kobj* pkt_kobj_create(struct pktcdvd_device *pd,
- static void pkt_kobj_remove(struct pktcdvd_kobj *p)
- {
- 	if (p)
--		kobject_unregister(&p->kobj);
-+		kobject_put(&p->kobj);
- }
- /*
-  * default release function for pktcdvd kernel objects.
-@@ -301,18 +302,16 @@ static struct kobj_type kobj_pkt_type_wqueue = {
- static void pkt_sysfs_dev_new(struct pktcdvd_device *pd)
- {
- 	if (class_pktcdvd) {
--		pd->clsdev = class_device_create(class_pktcdvd,
--					NULL, pd->pkt_dev,
--					NULL, "%s", pd->name);
--		if (IS_ERR(pd->clsdev))
--			pd->clsdev = NULL;
-+		pd->dev = device_create(class_pktcdvd, NULL, pd->pkt_dev, "%s", pd->name);
-+		if (IS_ERR(pd->dev))
-+			pd->dev = NULL;
- 	}
--	if (pd->clsdev) {
-+	if (pd->dev) {
- 		pd->kobj_stat = pkt_kobj_create(pd, "stat",
--					&pd->clsdev->kobj,
-+					&pd->dev->kobj,
- 					&kobj_pkt_type_stat);
- 		pd->kobj_wqueue = pkt_kobj_create(pd, "write_queue",
--					&pd->clsdev->kobj,
-+					&pd->dev->kobj,
- 					&kobj_pkt_type_wqueue);
+ 	while ((rwreq == 0) && ((req = elv_next_request(q)) != NULL)) {
+ 		if (!blk_fs_request(req))
+-			viocd_end_request(req, 0);
++			viocd_end_request(req, -EIO);
+ 		else if (send_request(req) < 0) {
+ 			printk(VIOCD_KERN_WARNING
+ 					"unable to send message to OS/400!");
+-			viocd_end_request(req, 0);
++			viocd_end_request(req, -EIO);
+ 		} else
+ 			rwreq++;
  	}
- }
-@@ -322,7 +321,7 @@ static void pkt_sysfs_dev_remove(struct pktcdvd_device *pd)
- 	pkt_kobj_remove(pd->kobj_stat);
- 	pkt_kobj_remove(pd->kobj_wqueue);
- 	if (class_pktcdvd)
--		class_device_destroy(class_pktcdvd, pd->pkt_dev);
-+		device_destroy(class_pktcdvd, pd->pkt_dev);
- }
- 
+@@ -532,9 +529,9 @@ return_complete:
+ 					"with rc %d:0x%04X: %s\n",
+ 					req, event->xRc,
+ 					bevent->sub_result, err->msg);
+-			viocd_end_request(req, 0);
++			viocd_end_request(req, -EIO);
+ 		} else
+-			viocd_end_request(req, 1);
++			viocd_end_request(req, 0);
  
+ 		/* restart handling of incoming requests */
+ 		spin_unlock_irqrestore(&viocd_reqlock, flags);
 diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
 index 2e3a0d4..4666295 100644
 --- a/drivers/char/Kconfig
@@ -63612,28996 +156872,33324 @@
 +	return hifn_handle_req(req);
 +}
 +
-+static int hifn_process_queue(struct hifn_device *dev)
++static int hifn_process_queue(struct hifn_device *dev)
++{
++	struct crypto_async_request *async_req;
++	struct hifn_context *ctx;
++	struct ablkcipher_request *req;
++	unsigned long flags;
++	int err = 0;
++
++	while (dev->started < HIFN_QUEUE_LENGTH) {
++		spin_lock_irqsave(&dev->lock, flags);
++		async_req = crypto_dequeue_request(&dev->queue);
++		spin_unlock_irqrestore(&dev->lock, flags);
++
++		if (!async_req)
++			break;
++
++		ctx = crypto_tfm_ctx(async_req->tfm);
++		req = container_of(async_req, struct ablkcipher_request, base);
++
++		err = hifn_handle_req(req);
++		if (err)
++			break;
++	}
++
++	return err;
++}
++
++static int hifn_setup_crypto(struct ablkcipher_request *req, u8 op,
++		u8 type, u8 mode)
++{
++	int err;
++	struct hifn_context *ctx = crypto_tfm_ctx(req->base.tfm);
++	struct hifn_device *dev = ctx->dev;
++
++	err = hifn_setup_crypto_req(req, op, type, mode);
++	if (err)
++		return err;
++
++	if (dev->started < HIFN_QUEUE_LENGTH &&	dev->queue.qlen)
++		err = hifn_process_queue(dev);
++
++	return err;
++}
++
++/*
++ * AES ecryption functions.
++ */
++static inline int hifn_encrypt_aes_ecb(struct ablkcipher_request *req)
++{
++	return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT,
++			ACRYPTO_TYPE_AES_128, ACRYPTO_MODE_ECB);
++}
++static inline int hifn_encrypt_aes_cbc(struct ablkcipher_request *req)
++{
++	return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT,
++			ACRYPTO_TYPE_AES_128, ACRYPTO_MODE_CBC);
++}
++static inline int hifn_encrypt_aes_cfb(struct ablkcipher_request *req)
++{
++	return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT,
++			ACRYPTO_TYPE_AES_128, ACRYPTO_MODE_CFB);
++}
++static inline int hifn_encrypt_aes_ofb(struct ablkcipher_request *req)
++{
++	return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT,
++			ACRYPTO_TYPE_AES_128, ACRYPTO_MODE_OFB);
++}
++
++/*
++ * AES decryption functions.
++ */
++static inline int hifn_decrypt_aes_ecb(struct ablkcipher_request *req)
++{
++	return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT,
++			ACRYPTO_TYPE_AES_128, ACRYPTO_MODE_ECB);
++}
++static inline int hifn_decrypt_aes_cbc(struct ablkcipher_request *req)
++{
++	return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT,
++			ACRYPTO_TYPE_AES_128, ACRYPTO_MODE_CBC);
++}
++static inline int hifn_decrypt_aes_cfb(struct ablkcipher_request *req)
++{
++	return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT,
++			ACRYPTO_TYPE_AES_128, ACRYPTO_MODE_CFB);
++}
++static inline int hifn_decrypt_aes_ofb(struct ablkcipher_request *req)
++{
++	return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT,
++			ACRYPTO_TYPE_AES_128, ACRYPTO_MODE_OFB);
++}
++
++/*
++ * DES ecryption functions.
++ */
++static inline int hifn_encrypt_des_ecb(struct ablkcipher_request *req)
++{
++	return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT,
++			ACRYPTO_TYPE_DES, ACRYPTO_MODE_ECB);
++}
++static inline int hifn_encrypt_des_cbc(struct ablkcipher_request *req)
++{
++	return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT,
++			ACRYPTO_TYPE_DES, ACRYPTO_MODE_CBC);
++}
++static inline int hifn_encrypt_des_cfb(struct ablkcipher_request *req)
++{
++	return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT,
++			ACRYPTO_TYPE_DES, ACRYPTO_MODE_CFB);
++}
++static inline int hifn_encrypt_des_ofb(struct ablkcipher_request *req)
++{
++	return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT,
++			ACRYPTO_TYPE_DES, ACRYPTO_MODE_OFB);
++}
++
++/*
++ * DES decryption functions.
++ */
++static inline int hifn_decrypt_des_ecb(struct ablkcipher_request *req)
++{
++	return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT,
++			ACRYPTO_TYPE_DES, ACRYPTO_MODE_ECB);
++}
++static inline int hifn_decrypt_des_cbc(struct ablkcipher_request *req)
++{
++	return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT,
++			ACRYPTO_TYPE_DES, ACRYPTO_MODE_CBC);
++}
++static inline int hifn_decrypt_des_cfb(struct ablkcipher_request *req)
++{
++	return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT,
++			ACRYPTO_TYPE_DES, ACRYPTO_MODE_CFB);
++}
++static inline int hifn_decrypt_des_ofb(struct ablkcipher_request *req)
++{
++	return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT,
++			ACRYPTO_TYPE_DES, ACRYPTO_MODE_OFB);
++}
++
++/*
++ * 3DES ecryption functions.
++ */
++static inline int hifn_encrypt_3des_ecb(struct ablkcipher_request *req)
++{
++	return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT,
++			ACRYPTO_TYPE_3DES, ACRYPTO_MODE_ECB);
++}
++static inline int hifn_encrypt_3des_cbc(struct ablkcipher_request *req)
++{
++	return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT,
++			ACRYPTO_TYPE_3DES, ACRYPTO_MODE_CBC);
++}
++static inline int hifn_encrypt_3des_cfb(struct ablkcipher_request *req)
++{
++	return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT,
++			ACRYPTO_TYPE_3DES, ACRYPTO_MODE_CFB);
++}
++static inline int hifn_encrypt_3des_ofb(struct ablkcipher_request *req)
++{
++	return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT,
++			ACRYPTO_TYPE_3DES, ACRYPTO_MODE_OFB);
++}
++
++/*
++ * 3DES decryption functions.
++ */
++static inline int hifn_decrypt_3des_ecb(struct ablkcipher_request *req)
++{
++	return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT,
++			ACRYPTO_TYPE_3DES, ACRYPTO_MODE_ECB);
++}
++static inline int hifn_decrypt_3des_cbc(struct ablkcipher_request *req)
++{
++	return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT,
++			ACRYPTO_TYPE_3DES, ACRYPTO_MODE_CBC);
++}
++static inline int hifn_decrypt_3des_cfb(struct ablkcipher_request *req)
++{
++	return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT,
++			ACRYPTO_TYPE_3DES, ACRYPTO_MODE_CFB);
++}
++static inline int hifn_decrypt_3des_ofb(struct ablkcipher_request *req)
++{
++	return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT,
++			ACRYPTO_TYPE_3DES, ACRYPTO_MODE_OFB);
++}
++
++struct hifn_alg_template
++{
++	char name[CRYPTO_MAX_ALG_NAME];
++	char drv_name[CRYPTO_MAX_ALG_NAME];
++	unsigned int bsize;
++	struct ablkcipher_alg ablkcipher;
++};
++
++static struct hifn_alg_template hifn_alg_templates[] = {
++	/*
++	 * 3DES ECB, CBC, CFB and OFB modes.
++	 */
++	{
++		.name = "cfb(des3_ede)", .drv_name = "hifn-3des", .bsize = 8,
++		.ablkcipher = {
++			.min_keysize	=	HIFN_3DES_KEY_LENGTH,
++			.max_keysize	=	HIFN_3DES_KEY_LENGTH,
++			.setkey		=	hifn_setkey,
++			.encrypt	=	hifn_encrypt_3des_cfb,
++			.decrypt	=	hifn_decrypt_3des_cfb,
++		},
++	},
++	{
++		.name = "ofb(des3_ede)", .drv_name = "hifn-3des", .bsize = 8,
++		.ablkcipher = {
++			.min_keysize	=	HIFN_3DES_KEY_LENGTH,
++			.max_keysize	=	HIFN_3DES_KEY_LENGTH,
++			.setkey		=	hifn_setkey,
++			.encrypt	=	hifn_encrypt_3des_ofb,
++			.decrypt	=	hifn_decrypt_3des_ofb,
++		},
++	},
++	{
++		.name = "cbc(des3_ede)", .drv_name = "hifn-3des", .bsize = 8,
++		.ablkcipher = {
++			.min_keysize	=	HIFN_3DES_KEY_LENGTH,
++			.max_keysize	=	HIFN_3DES_KEY_LENGTH,
++			.setkey		=	hifn_setkey,
++			.encrypt	=	hifn_encrypt_3des_cbc,
++			.decrypt	=	hifn_decrypt_3des_cbc,
++		},
++	},
++	{
++		.name = "ecb(des3_ede)", .drv_name = "hifn-3des", .bsize = 8,
++		.ablkcipher = {
++			.min_keysize	=	HIFN_3DES_KEY_LENGTH,
++			.max_keysize	=	HIFN_3DES_KEY_LENGTH,
++			.setkey		=	hifn_setkey,
++			.encrypt	=	hifn_encrypt_3des_ecb,
++			.decrypt	=	hifn_decrypt_3des_ecb,
++		},
++	},
++
++	/*
++	 * DES ECB, CBC, CFB and OFB modes.
++	 */
++	{
++		.name = "cfb(des)", .drv_name = "hifn-des", .bsize = 8,
++		.ablkcipher = {
++			.min_keysize	=	HIFN_DES_KEY_LENGTH,
++			.max_keysize	=	HIFN_DES_KEY_LENGTH,
++			.setkey		=	hifn_setkey,
++			.encrypt	=	hifn_encrypt_des_cfb,
++			.decrypt	=	hifn_decrypt_des_cfb,
++		},
++	},
++	{
++		.name = "ofb(des)", .drv_name = "hifn-des", .bsize = 8,
++		.ablkcipher = {
++			.min_keysize	=	HIFN_DES_KEY_LENGTH,
++			.max_keysize	=	HIFN_DES_KEY_LENGTH,
++			.setkey		=	hifn_setkey,
++			.encrypt	=	hifn_encrypt_des_ofb,
++			.decrypt	=	hifn_decrypt_des_ofb,
++		},
++	},
++	{
++		.name = "cbc(des)", .drv_name = "hifn-des", .bsize = 8,
++		.ablkcipher = {
++			.min_keysize	=	HIFN_DES_KEY_LENGTH,
++			.max_keysize	=	HIFN_DES_KEY_LENGTH,
++			.setkey		=	hifn_setkey,
++			.encrypt	=	hifn_encrypt_des_cbc,
++			.decrypt	=	hifn_decrypt_des_cbc,
++		},
++	},
++	{
++		.name = "ecb(des)", .drv_name = "hifn-des", .bsize = 8,
++		.ablkcipher = {
++			.min_keysize	=	HIFN_DES_KEY_LENGTH,
++			.max_keysize	=	HIFN_DES_KEY_LENGTH,
++			.setkey		=	hifn_setkey,
++			.encrypt	=	hifn_encrypt_des_ecb,
++			.decrypt	=	hifn_decrypt_des_ecb,
++		},
++	},
++
++	/*
++	 * AES ECB, CBC, CFB and OFB modes.
++	 */
++	{
++		.name = "ecb(aes)", .drv_name = "hifn-aes", .bsize = 16,
++		.ablkcipher = {
++			.min_keysize	=	AES_MIN_KEY_SIZE,
++			.max_keysize	=	AES_MAX_KEY_SIZE,
++			.setkey		=	hifn_setkey,
++			.encrypt	=	hifn_encrypt_aes_ecb,
++			.decrypt	=	hifn_decrypt_aes_ecb,
++		},
++	},
++	{
++		.name = "cbc(aes)", .drv_name = "hifn-aes", .bsize = 16,
++		.ablkcipher = {
++			.min_keysize	=	AES_MIN_KEY_SIZE,
++			.max_keysize	=	AES_MAX_KEY_SIZE,
++			.setkey		=	hifn_setkey,
++			.encrypt	=	hifn_encrypt_aes_cbc,
++			.decrypt	=	hifn_decrypt_aes_cbc,
++		},
++	},
++	{
++		.name = "cfb(aes)", .drv_name = "hifn-aes", .bsize = 16,
++		.ablkcipher = {
++			.min_keysize	=	AES_MIN_KEY_SIZE,
++			.max_keysize	=	AES_MAX_KEY_SIZE,
++			.setkey		=	hifn_setkey,
++			.encrypt	=	hifn_encrypt_aes_cfb,
++			.decrypt	=	hifn_decrypt_aes_cfb,
++		},
++	},
++	{
++		.name = "ofb(aes)", .drv_name = "hifn-aes", .bsize = 16,
++		.ablkcipher = {
++			.min_keysize	=	AES_MIN_KEY_SIZE,
++			.max_keysize	=	AES_MAX_KEY_SIZE,
++			.setkey		=	hifn_setkey,
++			.encrypt	=	hifn_encrypt_aes_ofb,
++			.decrypt	=	hifn_decrypt_aes_ofb,
++		},
++	},
++};
++
++static int hifn_cra_init(struct crypto_tfm *tfm)
++{
++	struct crypto_alg *alg = tfm->__crt_alg;
++	struct hifn_crypto_alg *ha = crypto_alg_to_hifn(alg);
++	struct hifn_context *ctx = crypto_tfm_ctx(tfm);
++
++	ctx->dev = ha->dev;
++
++	return 0;
++}
++
++static int hifn_alg_alloc(struct hifn_device *dev, struct hifn_alg_template *t)
++{
++	struct hifn_crypto_alg *alg;
++	int err;
++
++	alg = kzalloc(sizeof(struct hifn_crypto_alg), GFP_KERNEL);
++	if (!alg)
++		return -ENOMEM;
++
++	snprintf(alg->alg.cra_name, CRYPTO_MAX_ALG_NAME, "%s", t->name);
++	snprintf(alg->alg.cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s", t->drv_name);
++
++	alg->alg.cra_priority = 300;
++	alg->alg.cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC;
++	alg->alg.cra_blocksize = t->bsize;
++	alg->alg.cra_ctxsize = sizeof(struct hifn_context);
++	alg->alg.cra_alignmask = 15;
++	if (t->bsize == 8)
++		alg->alg.cra_alignmask = 3;
++	alg->alg.cra_type = &crypto_ablkcipher_type;
++	alg->alg.cra_module = THIS_MODULE;
++	alg->alg.cra_u.ablkcipher = t->ablkcipher;
++	alg->alg.cra_init = hifn_cra_init;
++
++	alg->dev = dev;
++
++	list_add_tail(&alg->entry, &dev->alg_list);
++
++	err = crypto_register_alg(&alg->alg);
++	if (err) {
++		list_del(&alg->entry);
++		kfree(alg);
++	}
++
++	return err;
++}
++
++static void hifn_unregister_alg(struct hifn_device *dev)
++{
++	struct hifn_crypto_alg *a, *n;
++
++	list_for_each_entry_safe(a, n, &dev->alg_list, entry) {
++		list_del(&a->entry);
++		crypto_unregister_alg(&a->alg);
++		kfree(a);
++	}
++}
++
++static int hifn_register_alg(struct hifn_device *dev)
++{
++	int i, err;
++
++	for (i=0; i<ARRAY_SIZE(hifn_alg_templates); ++i) {
++		err = hifn_alg_alloc(dev, &hifn_alg_templates[i]);
++		if (err)
++			goto err_out_exit;
++	}
++
++	return 0;
++
++err_out_exit:
++	hifn_unregister_alg(dev);
++	return err;
++}
++
++static void hifn_tasklet_callback(unsigned long data)
++{
++	struct hifn_device *dev = (struct hifn_device *)data;
++
++	/*
++	 * This is ok to call this without lock being held,
++	 * althogh it modifies some parameters used in parallel,
++	 * (like dev->success), but they are used in process
++	 * context or update is atomic (like setting dev->sa[i] to NULL).
++	 */
++	hifn_check_for_completion(dev, 0);
++}
++
++static int hifn_probe(struct pci_dev *pdev, const struct pci_device_id *id)
++{
++	int err, i;
++	struct hifn_device *dev;
++	char name[8];
++
++	err = pci_enable_device(pdev);
++	if (err)
++		return err;
++	pci_set_master(pdev);
++
++	err = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
++	if (err)
++		goto err_out_disable_pci_device;
++
++	snprintf(name, sizeof(name), "hifn%d",
++			atomic_inc_return(&hifn_dev_number)-1);
++
++	err = pci_request_regions(pdev, name);
++	if (err)
++		goto err_out_disable_pci_device;
++
++	if (pci_resource_len(pdev, 0) < HIFN_BAR0_SIZE ||
++	    pci_resource_len(pdev, 1) < HIFN_BAR1_SIZE ||
++	    pci_resource_len(pdev, 2) < HIFN_BAR2_SIZE) {
++		dprintk("%s: Broken hardware - I/O regions are too small.\n",
++				pci_name(pdev));
++		err = -ENODEV;
++		goto err_out_free_regions;
++	}
++
++	dev = kzalloc(sizeof(struct hifn_device) + sizeof(struct crypto_alg),
++			GFP_KERNEL);
++	if (!dev) {
++		err = -ENOMEM;
++		goto err_out_free_regions;
++	}
++
++	INIT_LIST_HEAD(&dev->alg_list);
++
++	snprintf(dev->name, sizeof(dev->name), "%s", name);
++	spin_lock_init(&dev->lock);
++
++	for (i=0; i<3; ++i) {
++		unsigned long addr, size;
++
++		addr = pci_resource_start(pdev, i);
++		size = pci_resource_len(pdev, i);
++
++		dev->bar[i] = ioremap_nocache(addr, size);
++		if (!dev->bar[i])
++			goto err_out_unmap_bars;
++	}
++
++	dev->result_mem = __get_free_pages(GFP_KERNEL, HIFN_MAX_RESULT_ORDER);
++	if (!dev->result_mem) {
++		dprintk("Failed to allocate %d pages for result_mem.\n",
++				HIFN_MAX_RESULT_ORDER);
++		goto err_out_unmap_bars;
++	}
++	memset((void *)dev->result_mem, 0, PAGE_SIZE*(1<<HIFN_MAX_RESULT_ORDER));
++
++	dev->dst = pci_map_single(pdev, (void *)dev->result_mem,
++			PAGE_SIZE << HIFN_MAX_RESULT_ORDER, PCI_DMA_FROMDEVICE);
++
++	dev->desc_virt = pci_alloc_consistent(pdev, sizeof(struct hifn_dma),
++			&dev->desc_dma);
++	if (!dev->desc_virt) {
++		dprintk("Failed to allocate descriptor rings.\n");
++		goto err_out_free_result_pages;
++	}
++	memset(dev->desc_virt, 0, sizeof(struct hifn_dma));
++
++	dev->pdev = pdev;
++	dev->irq = pdev->irq;
++
++	for (i=0; i<HIFN_D_RES_RSIZE; ++i)
++		dev->sa[i] = NULL;
++
++	pci_set_drvdata(pdev, dev);
++
++	tasklet_init(&dev->tasklet, hifn_tasklet_callback, (unsigned long)dev);
++
++	crypto_init_queue(&dev->queue, 1);
++
++	err = request_irq(dev->irq, hifn_interrupt, IRQF_SHARED, dev->name, dev);
++	if (err) {
++		dprintk("Failed to request IRQ%d: err: %d.\n", dev->irq, err);
++		dev->irq = 0;
++		goto err_out_free_desc;
++	}
++
++	err = hifn_start_device(dev);
++	if (err)
++		goto err_out_free_irq;
++
++	err = hifn_test(dev, 1, 0);
++	if (err)
++		goto err_out_stop_device;
++
++	err = hifn_register_rng(dev);
++	if (err)
++		goto err_out_stop_device;
++
++	err = hifn_register_alg(dev);
++	if (err)
++		goto err_out_unregister_rng;
++
++	INIT_DELAYED_WORK(&dev->work, hifn_work);
++	schedule_delayed_work(&dev->work, HZ);
++
++	dprintk("HIFN crypto accelerator card at %s has been "
++			"successfully registered as %s.\n",
++			pci_name(pdev), dev->name);
++
++	return 0;
++
++err_out_unregister_rng:
++	hifn_unregister_rng(dev);
++err_out_stop_device:
++	hifn_reset_dma(dev, 1);
++	hifn_stop_device(dev);
++err_out_free_irq:
++	free_irq(dev->irq, dev->name);
++	tasklet_kill(&dev->tasklet);
++err_out_free_desc:
++	pci_free_consistent(pdev, sizeof(struct hifn_dma),
++			dev->desc_virt, dev->desc_dma);
++
++err_out_free_result_pages:
++	pci_unmap_single(pdev, dev->dst, PAGE_SIZE << HIFN_MAX_RESULT_ORDER,
++			PCI_DMA_FROMDEVICE);
++	free_pages(dev->result_mem, HIFN_MAX_RESULT_ORDER);
++
++err_out_unmap_bars:
++	for (i=0; i<3; ++i)
++		if (dev->bar[i])
++			iounmap(dev->bar[i]);
++
++err_out_free_regions:
++	pci_release_regions(pdev);
++
++err_out_disable_pci_device:
++	pci_disable_device(pdev);
++
++	return err;
++}
++
++static void hifn_remove(struct pci_dev *pdev)
++{
++	int i;
++	struct hifn_device *dev;
++
++	dev = pci_get_drvdata(pdev);
++
++	if (dev) {
++		cancel_delayed_work(&dev->work);
++		flush_scheduled_work();
++
++		hifn_unregister_rng(dev);
++		hifn_unregister_alg(dev);
++		hifn_reset_dma(dev, 1);
++		hifn_stop_device(dev);
++
++		free_irq(dev->irq, dev->name);
++		tasklet_kill(&dev->tasklet);
++
++		hifn_flush(dev);
++
++		pci_free_consistent(pdev, sizeof(struct hifn_dma),
++				dev->desc_virt, dev->desc_dma);
++		pci_unmap_single(pdev, dev->dst,
++				PAGE_SIZE << HIFN_MAX_RESULT_ORDER,
++				PCI_DMA_FROMDEVICE);
++		free_pages(dev->result_mem, HIFN_MAX_RESULT_ORDER);
++		for (i=0; i<3; ++i)
++			if (dev->bar[i])
++				iounmap(dev->bar[i]);
++
++		kfree(dev);
++	}
++
++	pci_release_regions(pdev);
++	pci_disable_device(pdev);
++}
++
++static struct pci_device_id hifn_pci_tbl[] = {
++	{ PCI_DEVICE(PCI_VENDOR_ID_HIFN, PCI_DEVICE_ID_HIFN_7955) },
++	{ PCI_DEVICE(PCI_VENDOR_ID_HIFN, PCI_DEVICE_ID_HIFN_7956) },
++	{ 0 }
++};
++MODULE_DEVICE_TABLE(pci, hifn_pci_tbl);
++
++static struct pci_driver hifn_pci_driver = {
++	.name     = "hifn795x",
++	.id_table = hifn_pci_tbl,
++	.probe    = hifn_probe,
++	.remove   = __devexit_p(hifn_remove),
++};
++
++static int __devinit hifn_init(void)
++{
++	unsigned int freq;
++	int err;
++
++	if (strncmp(hifn_pll_ref, "ext", 3) &&
++	    strncmp(hifn_pll_ref, "pci", 3)) {
++		printk(KERN_ERR "hifn795x: invalid hifn_pll_ref clock, "
++				"must be pci or ext");
++		return -EINVAL;
++	}
++
++	/*
++	 * For the 7955/7956 the reference clock frequency must be in the
++	 * range of 20MHz-100MHz. For the 7954 the upper bound is 66.67MHz,
++	 * but this chip is currently not supported.
++	 */
++	if (hifn_pll_ref[3] != '\0') {
++		freq = simple_strtoul(hifn_pll_ref + 3, NULL, 10);
++		if (freq < 20 || freq > 100) {
++			printk(KERN_ERR "hifn795x: invalid hifn_pll_ref "
++					"frequency, must be in the range "
++					"of 20-100");
++			return -EINVAL;
++		}
++	}
++
++	err = pci_register_driver(&hifn_pci_driver);
++	if (err < 0) {
++		dprintk("Failed to register PCI driver for %s device.\n",
++				hifn_pci_driver.name);
++		return -ENODEV;
++	}
++
++	printk(KERN_INFO "Driver for HIFN 795x crypto accelerator chip "
++			"has been successfully registered.\n");
++
++	return 0;
++}
++
++static void __devexit hifn_fini(void)
 +{
-+	struct crypto_async_request *async_req;
-+	struct hifn_context *ctx;
-+	struct ablkcipher_request *req;
-+	unsigned long flags;
-+	int err = 0;
++	pci_unregister_driver(&hifn_pci_driver);
 +
-+	while (dev->started < HIFN_QUEUE_LENGTH) {
-+		spin_lock_irqsave(&dev->lock, flags);
-+		async_req = crypto_dequeue_request(&dev->queue);
-+		spin_unlock_irqrestore(&dev->lock, flags);
++	printk(KERN_INFO "Driver for HIFN 795x crypto accelerator chip "
++			"has been successfully unregistered.\n");
++}
 +
-+		if (!async_req)
-+			break;
++module_init(hifn_init);
++module_exit(hifn_fini);
 +
-+		ctx = crypto_tfm_ctx(async_req->tfm);
-+		req = container_of(async_req, struct ablkcipher_request, base);
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Evgeniy Polyakov <johnpol at 2ka.mipt.ru>");
++MODULE_DESCRIPTION("Driver for HIFN 795x crypto accelerator chip.");
+diff --git a/drivers/crypto/padlock-aes.c b/drivers/crypto/padlock-aes.c
+index 5f7e718..2f3ad3f 100644
+--- a/drivers/crypto/padlock-aes.c
++++ b/drivers/crypto/padlock-aes.c
+@@ -44,6 +44,7 @@
+  */
+ 
+ #include <crypto/algapi.h>
++#include <crypto/aes.h>
+ #include <linux/module.h>
+ #include <linux/init.h>
+ #include <linux/types.h>
+@@ -53,9 +54,6 @@
+ #include <asm/byteorder.h>
+ #include "padlock.h"
+ 
+-#define AES_MIN_KEY_SIZE	16	/* in uint8_t units */
+-#define AES_MAX_KEY_SIZE	32	/* ditto */
+-#define AES_BLOCK_SIZE		16	/* ditto */
+ #define AES_EXTENDED_KEY_SIZE	64	/* in uint32_t units */
+ #define AES_EXTENDED_KEY_SIZE_B	(AES_EXTENDED_KEY_SIZE * sizeof(uint32_t))
+ 
+@@ -419,6 +417,11 @@ static int aes_set_key(struct crypto_tfm *tfm, const u8 *in_key,
+ /* ====== Encryption/decryption routines ====== */
+ 
+ /* These are the real call to PadLock. */
++static inline void padlock_reset_key(void)
++{
++	asm volatile ("pushfl; popfl");
++}
 +
-+		err = hifn_handle_req(req);
-+		if (err)
-+			break;
-+	}
+ static inline void padlock_xcrypt(const u8 *input, u8 *output, void *key,
+ 				  void *control_word)
+ {
+@@ -439,8 +442,6 @@ static void aes_crypt_copy(const u8 *in, u8 *out, u32 *key, struct cword *cword)
+ static inline void aes_crypt(const u8 *in, u8 *out, u32 *key,
+ 			     struct cword *cword)
+ {
+-	asm volatile ("pushfl; popfl");
+-
+ 	/* padlock_xcrypt requires at least two blocks of data. */
+ 	if (unlikely(!(((unsigned long)in ^ (PAGE_SIZE - AES_BLOCK_SIZE)) &
+ 		       (PAGE_SIZE - 1)))) {
+@@ -459,7 +460,6 @@ static inline void padlock_xcrypt_ecb(const u8 *input, u8 *output, void *key,
+ 		return;
+ 	}
+ 
+-	asm volatile ("pushfl; popfl");		/* enforce key reload. */
+ 	asm volatile ("test $1, %%cl;"
+ 		      "je 1f;"
+ 		      "lea -1(%%ecx), %%eax;"
+@@ -476,8 +476,6 @@ static inline void padlock_xcrypt_ecb(const u8 *input, u8 *output, void *key,
+ static inline u8 *padlock_xcrypt_cbc(const u8 *input, u8 *output, void *key,
+ 				     u8 *iv, void *control_word, u32 count)
+ {
+-	/* Enforce key reload. */
+-	asm volatile ("pushfl; popfl");
+ 	/* rep xcryptcbc */
+ 	asm volatile (".byte 0xf3,0x0f,0xa7,0xd0"
+ 		      : "+S" (input), "+D" (output), "+a" (iv)
+@@ -488,12 +486,14 @@ static inline u8 *padlock_xcrypt_cbc(const u8 *input, u8 *output, void *key,
+ static void aes_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
+ {
+ 	struct aes_ctx *ctx = aes_ctx(tfm);
++	padlock_reset_key();
+ 	aes_crypt(in, out, ctx->E, &ctx->cword.encrypt);
+ }
+ 
+ static void aes_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
+ {
+ 	struct aes_ctx *ctx = aes_ctx(tfm);
++	padlock_reset_key();
+ 	aes_crypt(in, out, ctx->D, &ctx->cword.decrypt);
+ }
+ 
+@@ -526,6 +526,8 @@ static int ecb_aes_encrypt(struct blkcipher_desc *desc,
+ 	struct blkcipher_walk walk;
+ 	int err;
+ 
++	padlock_reset_key();
 +
-+	return err;
-+}
+ 	blkcipher_walk_init(&walk, dst, src, nbytes);
+ 	err = blkcipher_walk_virt(desc, &walk);
+ 
+@@ -548,6 +550,8 @@ static int ecb_aes_decrypt(struct blkcipher_desc *desc,
+ 	struct blkcipher_walk walk;
+ 	int err;
+ 
++	padlock_reset_key();
 +
-+static int hifn_setup_crypto(struct ablkcipher_request *req, u8 op,
-+		u8 type, u8 mode)
-+{
-+	int err;
-+	struct hifn_context *ctx = crypto_tfm_ctx(req->base.tfm);
-+	struct hifn_device *dev = ctx->dev;
+ 	blkcipher_walk_init(&walk, dst, src, nbytes);
+ 	err = blkcipher_walk_virt(desc, &walk);
+ 
+@@ -592,6 +596,8 @@ static int cbc_aes_encrypt(struct blkcipher_desc *desc,
+ 	struct blkcipher_walk walk;
+ 	int err;
+ 
++	padlock_reset_key();
 +
-+	err = hifn_setup_crypto_req(req, op, type, mode);
-+	if (err)
-+		return err;
+ 	blkcipher_walk_init(&walk, dst, src, nbytes);
+ 	err = blkcipher_walk_virt(desc, &walk);
+ 
+@@ -616,6 +622,8 @@ static int cbc_aes_decrypt(struct blkcipher_desc *desc,
+ 	struct blkcipher_walk walk;
+ 	int err;
+ 
++	padlock_reset_key();
 +
-+	if (dev->started < HIFN_QUEUE_LENGTH &&	dev->queue.qlen)
-+		err = hifn_process_queue(dev);
+ 	blkcipher_walk_init(&walk, dst, src, nbytes);
+ 	err = blkcipher_walk_virt(desc, &walk);
+ 
+diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c
+index d59b2f4..bcf52df 100644
+--- a/drivers/dma/dmaengine.c
++++ b/drivers/dma/dmaengine.c
+@@ -41,12 +41,12 @@
+  * the definition of dma_event_callback in dmaengine.h.
+  *
+  * Each device has a kref, which is initialized to 1 when the device is
+- * registered. A kref_get is done for each class_device registered.  When the
+- * class_device is released, the coresponding kref_put is done in the release
++ * registered. A kref_get is done for each device registered.  When the
++ * device is released, the coresponding kref_put is done in the release
+  * method. Every time one of the device's channels is allocated to a client,
+  * a kref_get occurs.  When the channel is freed, the coresponding kref_put
+  * happens. The device's release function does a completion, so
+- * unregister_device does a remove event, class_device_unregister, a kref_put
++ * unregister_device does a remove event, device_unregister, a kref_put
+  * for the first reference, then waits on the completion for all other
+  * references to finish.
+  *
+@@ -77,9 +77,9 @@ static LIST_HEAD(dma_client_list);
+ 
+ /* --- sysfs implementation --- */
+ 
+-static ssize_t show_memcpy_count(struct class_device *cd, char *buf)
++static ssize_t show_memcpy_count(struct device *dev, struct device_attribute *attr, char *buf)
+ {
+-	struct dma_chan *chan = container_of(cd, struct dma_chan, class_dev);
++	struct dma_chan *chan = to_dma_chan(dev);
+ 	unsigned long count = 0;
+ 	int i;
+ 
+@@ -89,9 +89,10 @@ static ssize_t show_memcpy_count(struct class_device *cd, char *buf)
+ 	return sprintf(buf, "%lu\n", count);
+ }
+ 
+-static ssize_t show_bytes_transferred(struct class_device *cd, char *buf)
++static ssize_t show_bytes_transferred(struct device *dev, struct device_attribute *attr,
++				      char *buf)
+ {
+-	struct dma_chan *chan = container_of(cd, struct dma_chan, class_dev);
++	struct dma_chan *chan = to_dma_chan(dev);
+ 	unsigned long count = 0;
+ 	int i;
+ 
+@@ -101,9 +102,9 @@ static ssize_t show_bytes_transferred(struct class_device *cd, char *buf)
+ 	return sprintf(buf, "%lu\n", count);
+ }
+ 
+-static ssize_t show_in_use(struct class_device *cd, char *buf)
++static ssize_t show_in_use(struct device *dev, struct device_attribute *attr, char *buf)
+ {
+-	struct dma_chan *chan = container_of(cd, struct dma_chan, class_dev);
++	struct dma_chan *chan = to_dma_chan(dev);
+ 	int in_use = 0;
+ 
+ 	if (unlikely(chan->slow_ref) &&
+@@ -119,7 +120,7 @@ static ssize_t show_in_use(struct class_device *cd, char *buf)
+ 	return sprintf(buf, "%d\n", in_use);
+ }
+ 
+-static struct class_device_attribute dma_class_attrs[] = {
++static struct device_attribute dma_attrs[] = {
+ 	__ATTR(memcpy_count, S_IRUGO, show_memcpy_count, NULL),
+ 	__ATTR(bytes_transferred, S_IRUGO, show_bytes_transferred, NULL),
+ 	__ATTR(in_use, S_IRUGO, show_in_use, NULL),
+@@ -128,16 +129,16 @@ static struct class_device_attribute dma_class_attrs[] = {
+ 
+ static void dma_async_device_cleanup(struct kref *kref);
+ 
+-static void dma_class_dev_release(struct class_device *cd)
++static void dma_dev_release(struct device *dev)
+ {
+-	struct dma_chan *chan = container_of(cd, struct dma_chan, class_dev);
++	struct dma_chan *chan = to_dma_chan(dev);
+ 	kref_put(&chan->device->refcount, dma_async_device_cleanup);
+ }
+ 
+ static struct class dma_devclass = {
+-	.name            = "dma",
+-	.class_dev_attrs = dma_class_attrs,
+-	.release = dma_class_dev_release,
++	.name		= "dma",
++	.dev_attrs	= dma_attrs,
++	.dev_release	= dma_dev_release,
+ };
+ 
+ /* --- client and device registration --- */
+@@ -377,12 +378,12 @@ int dma_async_device_register(struct dma_device *device)
+ 			continue;
+ 
+ 		chan->chan_id = chancnt++;
+-		chan->class_dev.class = &dma_devclass;
+-		chan->class_dev.dev = NULL;
+-		snprintf(chan->class_dev.class_id, BUS_ID_SIZE, "dma%dchan%d",
++		chan->dev.class = &dma_devclass;
++		chan->dev.parent = NULL;
++		snprintf(chan->dev.bus_id, BUS_ID_SIZE, "dma%dchan%d",
+ 		         device->dev_id, chan->chan_id);
+ 
+-		rc = class_device_register(&chan->class_dev);
++		rc = device_register(&chan->dev);
+ 		if (rc) {
+ 			chancnt--;
+ 			free_percpu(chan->local);
+@@ -411,7 +412,7 @@ err_out:
+ 		if (chan->local == NULL)
+ 			continue;
+ 		kref_put(&device->refcount, dma_async_device_cleanup);
+-		class_device_unregister(&chan->class_dev);
++		device_unregister(&chan->dev);
+ 		chancnt--;
+ 		free_percpu(chan->local);
+ 	}
+@@ -445,7 +446,7 @@ void dma_async_device_unregister(struct dma_device *device)
+ 
+ 	list_for_each_entry(chan, &device->channels, device_node) {
+ 		dma_clients_notify_removed(chan);
+-		class_device_unregister(&chan->class_dev);
++		device_unregister(&chan->dev);
+ 		dma_chan_release(chan);
+ 	}
+ 
+diff --git a/drivers/edac/edac_device_sysfs.c b/drivers/edac/edac_device_sysfs.c
+index 70b837f..5376457 100644
+--- a/drivers/edac/edac_device_sysfs.c
++++ b/drivers/edac/edac_device_sysfs.c
+@@ -246,16 +246,6 @@ int edac_device_register_sysfs_main_kobj(struct edac_device_ctl_info *edac_dev)
+ 
+ 	/* Init the devices's kobject */
+ 	memset(&edac_dev->kobj, 0, sizeof(struct kobject));
+-	edac_dev->kobj.ktype = &ktype_device_ctrl;
+-
+-	/* set this new device under the edac_class kobject */
+-	edac_dev->kobj.parent = &edac_class->kset.kobj;
+-
+-	/* generate sysfs "..../edac/<name>"   */
+-	debugf4("%s() set name of kobject to: %s\n", __func__, edac_dev->name);
+-	err = kobject_set_name(&edac_dev->kobj, "%s", edac_dev->name);
+-	if (err)
+-		goto err_out;
+ 
+ 	/* Record which module 'owns' this control structure
+ 	 * and bump the ref count of the module
+@@ -268,12 +258,15 @@ int edac_device_register_sysfs_main_kobj(struct edac_device_ctl_info *edac_dev)
+ 	}
+ 
+ 	/* register */
+-	err = kobject_register(&edac_dev->kobj);
++	err = kobject_init_and_add(&edac_dev->kobj, &ktype_device_ctrl,
++				   &edac_class->kset.kobj,
++				   "%s", edac_dev->name);
+ 	if (err) {
+ 		debugf1("%s()Failed to register '.../edac/%s'\n",
+ 			__func__, edac_dev->name);
+ 		goto err_kobj_reg;
+ 	}
++	kobject_uevent(&edac_dev->kobj, KOBJ_ADD);
+ 
+ 	/* At this point, to 'free' the control struct,
+ 	 * edac_device_unregister_sysfs_main_kobj() must be used
+@@ -310,7 +303,7 @@ void edac_device_unregister_sysfs_main_kobj(
+ 	 *   a) module_put() this module
+ 	 *   b) 'kfree' the memory
+ 	 */
+-	kobject_unregister(&edac_dev->kobj);
++	kobject_put(&edac_dev->kobj);
+ }
+ 
+ /* edac_dev -> instance information */
+@@ -533,12 +526,6 @@ static int edac_device_create_block(struct edac_device_ctl_info *edac_dev,
+ 
+ 	/* init this block's kobject */
+ 	memset(&block->kobj, 0, sizeof(struct kobject));
+-	block->kobj.parent = &instance->kobj;
+-	block->kobj.ktype = &ktype_block_ctrl;
+-
+-	err = kobject_set_name(&block->kobj, "%s", block->name);
+-	if (err)
+-		return err;
+ 
+ 	/* bump the main kobject's reference count for this controller
+ 	 * and this instance is dependant on the main
+@@ -550,7 +537,9 @@ static int edac_device_create_block(struct edac_device_ctl_info *edac_dev,
+ 	}
+ 
+ 	/* Add this block's kobject */
+-	err = kobject_register(&block->kobj);
++	err = kobject_init_and_add(&block->kobj, &ktype_block_ctrl,
++				   &instance->kobj,
++				   "%s", block->name);
+ 	if (err) {
+ 		debugf1("%s() Failed to register instance '%s'\n",
+ 			__func__, block->name);
+@@ -579,12 +568,13 @@ static int edac_device_create_block(struct edac_device_ctl_info *edac_dev,
+ 				goto err_on_attrib;
+ 		}
+ 	}
++	kobject_uevent(&block->kobj, KOBJ_ADD);
+ 
+ 	return 0;
+ 
+ 	/* Error unwind stack */
+ err_on_attrib:
+-	kobject_unregister(&block->kobj);
++	kobject_put(&block->kobj);
+ 
+ err_out:
+ 	return err;
+@@ -615,7 +605,7 @@ static void edac_device_delete_block(struct edac_device_ctl_info *edac_dev,
+ 	/* unregister this block's kobject, SEE:
+ 	 *	edac_device_ctrl_block_release() callback operation
+ 	 */
+-	kobject_unregister(&block->kobj);
++	kobject_put(&block->kobj);
+ }
+ 
+ /* instance ctor/dtor code */
+@@ -637,15 +627,8 @@ static int edac_device_create_instance(struct edac_device_ctl_info *edac_dev,
+ 	/* Init the instance's kobject */
+ 	memset(&instance->kobj, 0, sizeof(struct kobject));
+ 
+-	/* set this new device under the edac_device main kobject */
+-	instance->kobj.parent = &edac_dev->kobj;
+-	instance->kobj.ktype = &ktype_instance_ctrl;
+ 	instance->ctl = edac_dev;
+ 
+-	err = kobject_set_name(&instance->kobj, "%s", instance->name);
+-	if (err)
+-		goto err_out;
+-
+ 	/* bump the main kobject's reference count for this controller
+ 	 * and this instance is dependant on the main
+ 	 */
+@@ -655,8 +638,9 @@ static int edac_device_create_instance(struct edac_device_ctl_info *edac_dev,
+ 		goto err_out;
+ 	}
+ 
+-	/* Formally register this instance's kobject */
+-	err = kobject_register(&instance->kobj);
++	/* Formally register this instance's kobject under the edac_device */
++	err = kobject_init_and_add(&instance->kobj, &ktype_instance_ctrl,
++				   &edac_dev->kobj, "%s", instance->name);
+ 	if (err != 0) {
+ 		debugf2("%s() Failed to register instance '%s'\n",
+ 			__func__, instance->name);
+@@ -679,6 +663,7 @@ static int edac_device_create_instance(struct edac_device_ctl_info *edac_dev,
+ 			goto err_release_instance_kobj;
+ 		}
+ 	}
++	kobject_uevent(&instance->kobj, KOBJ_ADD);
+ 
+ 	debugf4("%s() Registered instance %d '%s' kobject\n",
+ 		__func__, idx, instance->name);
+@@ -687,7 +672,7 @@ static int edac_device_create_instance(struct edac_device_ctl_info *edac_dev,
+ 
+ 	/* error unwind stack */
+ err_release_instance_kobj:
+-	kobject_unregister(&instance->kobj);
++	kobject_put(&instance->kobj);
+ 
+ err_out:
+ 	return err;
+@@ -712,7 +697,7 @@ static void edac_device_delete_instance(struct edac_device_ctl_info *edac_dev,
+ 	/* unregister this instance's kobject, SEE:
+ 	 *	edac_device_ctrl_instance_release() for callback operation
+ 	 */
+-	kobject_unregister(&instance->kobj);
++	kobject_put(&instance->kobj);
+ }
+ 
+ /*
+diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c
+index 3706b2b..9aac880 100644
+--- a/drivers/edac/edac_mc_sysfs.c
++++ b/drivers/edac/edac_mc_sysfs.c
+@@ -380,13 +380,6 @@ static int edac_create_csrow_object(struct mem_ctl_info *mci,
+ 	/* generate ..../edac/mc/mc<id>/csrow<index>   */
+ 	memset(&csrow->kobj, 0, sizeof(csrow->kobj));
+ 	csrow->mci = mci;	/* include container up link */
+-	csrow->kobj.parent = kobj_mci;
+-	csrow->kobj.ktype = &ktype_csrow;
+-
+-	/* name this instance of csrow<id> */
+-	err = kobject_set_name(&csrow->kobj, "csrow%d", index);
+-	if (err)
+-		goto err_out;
+ 
+ 	/* bump the mci instance's kobject's ref count */
+ 	kobj = kobject_get(&mci->edac_mci_kobj);
+@@ -396,12 +389,13 @@ static int edac_create_csrow_object(struct mem_ctl_info *mci,
+ 	}
+ 
+ 	/* Instanstiate the csrow object */
+-	err = kobject_register(&csrow->kobj);
++	err = kobject_init_and_add(&csrow->kobj, &ktype_csrow, kobj_mci,
++				   "csrow%d", index);
+ 	if (err)
+ 		goto err_release_top_kobj;
+ 
+ 	/* At this point, to release a csrow kobj, one must
+-	 * call the kobject_unregister and allow that tear down
++	 * call the kobject_put and allow that tear down
+ 	 * to work the releasing
+ 	 */
+ 
+@@ -412,11 +406,11 @@ static int edac_create_csrow_object(struct mem_ctl_info *mci,
+ 		err = edac_create_channel_files(&csrow->kobj, chan);
+ 		if (err) {
+ 			/* special case the unregister here */
+-			kobject_unregister(&csrow->kobj);
++			kobject_put(&csrow->kobj);
+ 			goto err_out;
+ 		}
+ 	}
+-
++	kobject_uevent(&csrow->kobj, KOBJ_ADD);
+ 	return 0;
+ 
+ 	/* error unwind stack */
+@@ -744,7 +738,6 @@ static struct kobj_type ktype_mc_set_attribs = {
+  */
+ static struct kset mc_kset = {
+ 	.kobj = {.ktype = &ktype_mc_set_attribs },
+-	.ktype = &ktype_mci,
+ };
+ 
+ 
+@@ -765,14 +758,6 @@ int edac_mc_register_sysfs_main_kobj(struct mem_ctl_info *mci)
+ 	/* Init the mci's kobject */
+ 	memset(kobj_mci, 0, sizeof(*kobj_mci));
+ 
+-	/* this instance become part of the mc_kset */
+-	kobj_mci->kset = &mc_kset;
+-
+-	/* set the name of the mc<id> object */
+-	err = kobject_set_name(kobj_mci, "mc%d", mci->mc_idx);
+-	if (err)
+-		goto fail_out;
+-
+ 	/* Record which module 'owns' this control structure
+ 	 * and bump the ref count of the module
+ 	 */
+@@ -784,13 +769,18 @@ int edac_mc_register_sysfs_main_kobj(struct mem_ctl_info *mci)
+ 		goto fail_out;
+ 	}
+ 
++	/* this instance become part of the mc_kset */
++	kobj_mci->kset = &mc_kset;
 +
-+	return err;
-+}
+ 	/* register the mc<id> kobject to the mc_kset */
+-	err = kobject_register(kobj_mci);
++	err = kobject_init_and_add(kobj_mci, &ktype_mci, NULL,
++				   "mc%d", mci->mc_idx);
+ 	if (err) {
+ 		debugf1("%s()Failed to register '.../edac/mc%d'\n",
+ 			__func__, mci->mc_idx);
+ 		goto kobj_reg_fail;
+ 	}
++	kobject_uevent(kobj_mci, KOBJ_ADD);
+ 
+ 	/* At this point, to 'free' the control struct,
+ 	 * edac_mc_unregister_sysfs_main_kobj() must be used
+@@ -818,7 +808,7 @@ fail_out:
+ void edac_mc_unregister_sysfs_main_kobj(struct mem_ctl_info *mci)
+ {
+ 	/* delete the kobj from the mc_kset */
+-	kobject_unregister(&mci->edac_mci_kobj);
++	kobject_put(&mci->edac_mci_kobj);
+ }
+ 
+ #define EDAC_DEVICE_SYMLINK	"device"
+@@ -933,7 +923,7 @@ int edac_create_sysfs_mci_device(struct mem_ctl_info *mci)
+ fail1:
+ 	for (i--; i >= 0; i--) {
+ 		if (csrow->nr_pages > 0) {
+-			kobject_unregister(&mci->csrows[i].kobj);
++			kobject_put(&mci->csrows[i].kobj);
+ 		}
+ 	}
+ 
+@@ -960,7 +950,7 @@ void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci)
+ 	for (i = 0; i < mci->nr_csrows; i++) {
+ 		if (mci->csrows[i].nr_pages > 0) {
+ 			debugf0("%s()  unreg csrow-%d\n", __func__, i);
+-			kobject_unregister(&mci->csrows[i].kobj);
++			kobject_put(&mci->csrows[i].kobj);
+ 		}
+ 	}
+ 
+@@ -977,7 +967,7 @@ void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci)
+ 	debugf0("%s()  unregister this mci kobj\n", __func__);
+ 
+ 	/* unregister this instance's kobject */
+-	kobject_unregister(&mci->edac_mci_kobj);
++	kobject_put(&mci->edac_mci_kobj);
+ }
+ 
+ 
+diff --git a/drivers/edac/edac_module.c b/drivers/edac/edac_module.c
+index e0c4a40..7e1374a 100644
+--- a/drivers/edac/edac_module.c
++++ b/drivers/edac/edac_module.c
+@@ -31,7 +31,7 @@ struct workqueue_struct *edac_workqueue;
+  *	need to export to other files in this modules
+  */
+ static struct sysdev_class edac_class = {
+-	set_kset_name("edac"),
++	.name = "edac",
+ };
+ static int edac_class_valid;
+ 
+diff --git a/drivers/edac/edac_pci_sysfs.c b/drivers/edac/edac_pci_sysfs.c
+index 69f5ddd..5b075da 100644
+--- a/drivers/edac/edac_pci_sysfs.c
++++ b/drivers/edac/edac_pci_sysfs.c
+@@ -162,14 +162,6 @@ static int edac_pci_create_instance_kobj(struct edac_pci_ctl_info *pci, int idx)
+ 
+ 	debugf0("%s()\n", __func__);
+ 
+-	/* Set the parent and the instance's ktype */
+-	pci->kobj.parent = &edac_pci_top_main_kobj;
+-	pci->kobj.ktype = &ktype_pci_instance;
+-
+-	err = kobject_set_name(&pci->kobj, "pci%d", idx);
+-	if (err)
+-		return err;
+-
+ 	/* First bump the ref count on the top main kobj, which will
+ 	 * track the number of PCI instances we have, and thus nest
+ 	 * properly on keeping the module loaded
+@@ -181,7 +173,8 @@ static int edac_pci_create_instance_kobj(struct edac_pci_ctl_info *pci, int idx)
+ 	}
+ 
+ 	/* And now register this new kobject under the main kobj */
+-	err = kobject_register(&pci->kobj);
++	err = kobject_init_and_add(&pci->kobj, &ktype_pci_instance,
++				   &edac_pci_top_main_kobj, "pci%d", idx);
+ 	if (err != 0) {
+ 		debugf2("%s() failed to register instance pci%d\n",
+ 			__func__, idx);
+@@ -189,6 +182,7 @@ static int edac_pci_create_instance_kobj(struct edac_pci_ctl_info *pci, int idx)
+ 		goto error_out;
+ 	}
+ 
++	kobject_uevent(&pci->kobj, KOBJ_ADD);
+ 	debugf1("%s() Register instance 'pci%d' kobject\n", __func__, idx);
+ 
+ 	return 0;
+@@ -211,7 +205,7 @@ void edac_pci_unregister_sysfs_instance_kobj(struct edac_pci_ctl_info *pci)
+ 	 * function release the main reference count and then
+ 	 * kfree the memory
+ 	 */
+-	kobject_unregister(&pci->kobj);
++	kobject_put(&pci->kobj);
+ }
+ 
+ /***************************** EDAC PCI sysfs root **********************/
+@@ -364,14 +358,6 @@ int edac_pci_main_kobj_setup(void)
+ 		goto decrement_count_fail;
+ 	}
+ 
+-	/* Need the kobject hook ups, and name setting */
+-	edac_pci_top_main_kobj.ktype = &ktype_edac_pci_main_kobj;
+-	edac_pci_top_main_kobj.parent = &edac_class->kset.kobj;
+-
+-	err = kobject_set_name(&edac_pci_top_main_kobj, "pci");
+-	if (err)
+-		goto decrement_count_fail;
+-
+ 	/* Bump the reference count on this module to ensure the
+ 	 * modules isn't unloaded until we deconstruct the top
+ 	 * level main kobj for EDAC PCI
+@@ -383,23 +369,24 @@ int edac_pci_main_kobj_setup(void)
+ 	}
+ 
+ 	/* Instanstiate the pci object */
+-	/* FIXME: maybe new sysdev_create_subdir() */
+-	err = kobject_register(&edac_pci_top_main_kobj);
++	err = kobject_init_and_add(&edac_pci_top_main_kobj, &ktype_edac_pci_main_kobj,
++				   &edac_class->kset.kobj, "pci");
+ 	if (err) {
+ 		debugf1("Failed to register '.../edac/pci'\n");
+-		goto kobject_register_fail;
++		goto kobject_init_and_add_fail;
+ 	}
+ 
+ 	/* At this point, to 'release' the top level kobject
+ 	 * for EDAC PCI, then edac_pci_main_kobj_teardown()
+ 	 * must be used, for resources to be cleaned up properly
+ 	 */
++	kobject_uevent(&edac_pci_top_main_kobj, KOBJ_ADD);
+ 	debugf1("Registered '.../edac/pci' kobject\n");
+ 
+ 	return 0;
+ 
+ 	/* Error unwind statck */
+-kobject_register_fail:
++kobject_init_and_add_fail:
+ 	module_put(THIS_MODULE);
+ 
+ decrement_count_fail:
+@@ -424,9 +411,9 @@ static void edac_pci_main_kobj_teardown(void)
+ 	 * main kobj
+ 	 */
+ 	if (atomic_dec_return(&edac_pci_sysfs_refcount) == 0) {
+-		debugf0("%s() called kobject_unregister on main kobj\n",
++		debugf0("%s() called kobject_put on main kobj\n",
+ 			__func__);
+-		kobject_unregister(&edac_pci_top_main_kobj);
++		kobject_put(&edac_pci_top_main_kobj);
+ 	}
+ }
+ 
+diff --git a/drivers/firewire/fw-sbp2.c b/drivers/firewire/fw-sbp2.c
+index 624ff3e..c2169d2 100644
+--- a/drivers/firewire/fw-sbp2.c
++++ b/drivers/firewire/fw-sbp2.c
+@@ -1238,6 +1238,12 @@ static int sbp2_scsi_slave_alloc(struct scsi_device *sdev)
+ 
+ 	sdev->allow_restart = 1;
+ 
++	/*
++	 * Update the dma alignment (minimum alignment requirements for
++	 * start and end of DMA transfers) to be a sector
++	 */
++	blk_queue_update_dma_alignment(sdev->request_queue, 511);
 +
-+/*
-+ * AES ecryption functions.
-+ */
-+static inline int hifn_encrypt_aes_ecb(struct ablkcipher_request *req)
-+{
-+	return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT,
-+			ACRYPTO_TYPE_AES_128, ACRYPTO_MODE_ECB);
-+}
-+static inline int hifn_encrypt_aes_cbc(struct ablkcipher_request *req)
-+{
-+	return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT,
-+			ACRYPTO_TYPE_AES_128, ACRYPTO_MODE_CBC);
-+}
-+static inline int hifn_encrypt_aes_cfb(struct ablkcipher_request *req)
-+{
-+	return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT,
-+			ACRYPTO_TYPE_AES_128, ACRYPTO_MODE_CFB);
-+}
-+static inline int hifn_encrypt_aes_ofb(struct ablkcipher_request *req)
-+{
-+	return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT,
-+			ACRYPTO_TYPE_AES_128, ACRYPTO_MODE_OFB);
-+}
+ 	if (lu->tgt->workarounds & SBP2_WORKAROUND_INQUIRY_36)
+ 		sdev->inquiry_len = 36;
+ 
+diff --git a/drivers/firmware/edd.c b/drivers/firmware/edd.c
+index 6942e06..d168223 100644
+--- a/drivers/firmware/edd.c
++++ b/drivers/firmware/edd.c
+@@ -631,7 +631,7 @@ static struct kobj_type edd_ktype = {
+ 	.default_attrs	= def_attrs,
+ };
+ 
+-static decl_subsys(edd, &edd_ktype, NULL);
++static struct kset *edd_kset;
+ 
+ 
+ /**
+@@ -693,7 +693,7 @@ edd_create_symlink_to_pcidev(struct edd_device *edev)
+ static inline void
+ edd_device_unregister(struct edd_device *edev)
+ {
+-	kobject_unregister(&edev->kobj);
++	kobject_put(&edev->kobj);
+ }
+ 
+ static void edd_populate_dir(struct edd_device * edev)
+@@ -721,12 +721,13 @@ edd_device_register(struct edd_device *edev, int i)
+ 	if (!edev)
+ 		return 1;
+ 	edd_dev_set_info(edev, i);
+-	kobject_set_name(&edev->kobj, "int13_dev%02x",
+-			 0x80 + i);
+-	kobj_set_kset_s(edev,edd_subsys);
+-	error = kobject_register(&edev->kobj);
+-	if (!error)
++	edev->kobj.kset = edd_kset;
++	error = kobject_init_and_add(&edev->kobj, &edd_ktype, NULL,
++				     "int13_dev%02x", 0x80 + i);
++	if (!error) {
+ 		edd_populate_dir(edev);
++		kobject_uevent(&edev->kobj, KOBJ_ADD);
++	}
+ 	return error;
+ }
+ 
+@@ -755,9 +756,9 @@ edd_init(void)
+ 		return 1;
+ 	}
+ 
+-	rc = firmware_register(&edd_subsys);
+-	if (rc)
+-		return rc;
++	edd_kset = kset_create_and_add("edd", NULL, firmware_kobj);
++	if (!edd_kset)
++		return -ENOMEM;
+ 
+ 	for (i = 0; i < edd_num_devices() && !rc; i++) {
+ 		edev = kzalloc(sizeof (*edev), GFP_KERNEL);
+@@ -773,7 +774,7 @@ edd_init(void)
+ 	}
+ 
+ 	if (rc)
+-		firmware_unregister(&edd_subsys);
++		kset_unregister(edd_kset);
+ 	return rc;
+ }
+ 
+@@ -787,7 +788,7 @@ edd_exit(void)
+ 		if ((edev = edd_devices[i]))
+ 			edd_device_unregister(edev);
+ 	}
+-	firmware_unregister(&edd_subsys);
++	kset_unregister(edd_kset);
+ }
+ 
+ late_initcall(edd_init);
+diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c
+index 858a7b9..f4f709d 100644
+--- a/drivers/firmware/efivars.c
++++ b/drivers/firmware/efivars.c
+@@ -129,13 +129,6 @@ struct efivar_attribute {
+ };
+ 
+ 
+-#define EFI_ATTR(_name, _mode, _show, _store) \
+-struct subsys_attribute efi_attr_##_name = { \
+-	.attr = {.name = __stringify(_name), .mode = _mode}, \
+-	.show = _show, \
+-	.store = _store, \
+-};
+-
+ #define EFIVAR_ATTR(_name, _mode, _show, _store) \
+ struct efivar_attribute efivar_attr_##_name = { \
+ 	.attr = {.name = __stringify(_name), .mode = _mode}, \
+@@ -143,13 +136,6 @@ struct efivar_attribute efivar_attr_##_name = { \
+ 	.store = _store, \
+ };
+ 
+-#define VAR_SUBSYS_ATTR(_name, _mode, _show, _store) \
+-struct subsys_attribute var_subsys_attr_##_name = { \
+-	.attr = {.name = __stringify(_name), .mode = _mode}, \
+-	.show = _show, \
+-	.store = _store, \
+-};
+-
+ #define to_efivar_attr(_attr) container_of(_attr, struct efivar_attribute, attr)
+ #define to_efivar_entry(obj)  container_of(obj, struct efivar_entry, kobj)
+ 
+@@ -408,21 +394,16 @@ static struct kobj_type efivar_ktype = {
+ 	.default_attrs = def_attrs,
+ };
+ 
+-static ssize_t
+-dummy(struct kset *kset, char *buf)
+-{
+-	return -ENODEV;
+-}
+-
+ static inline void
+ efivar_unregister(struct efivar_entry *var)
+ {
+-	kobject_unregister(&var->kobj);
++	kobject_put(&var->kobj);
+ }
+ 
+ 
+-static ssize_t
+-efivar_create(struct kset *kset, const char *buf, size_t count)
++static ssize_t efivar_create(struct kobject *kobj,
++			     struct bin_attribute *bin_attr,
++			     char *buf, loff_t pos, size_t count)
+ {
+ 	struct efi_variable *new_var = (struct efi_variable *)buf;
+ 	struct efivar_entry *search_efivar, *n;
+@@ -479,8 +460,9 @@ efivar_create(struct kset *kset, const char *buf, size_t count)
+ 	return count;
+ }
+ 
+-static ssize_t
+-efivar_delete(struct kset *kset, const char *buf, size_t count)
++static ssize_t efivar_delete(struct kobject *kobj,
++			     struct bin_attribute *bin_attr,
++			     char *buf, loff_t pos, size_t count)
+ {
+ 	struct efi_variable *del_var = (struct efi_variable *)buf;
+ 	struct efivar_entry *search_efivar, *n;
+@@ -537,25 +519,26 @@ efivar_delete(struct kset *kset, const char *buf, size_t count)
+ 	return count;
+ }
+ 
+-static VAR_SUBSYS_ATTR(new_var, 0200, dummy, efivar_create);
+-static VAR_SUBSYS_ATTR(del_var, 0200, dummy, efivar_delete);
++static struct bin_attribute var_subsys_attr_new_var = {
++	.attr = {.name = "new_var", .mode = 0200},
++	.write = efivar_create,
++};
+ 
+-static struct subsys_attribute *var_subsys_attrs[] = {
+-	&var_subsys_attr_new_var,
+-	&var_subsys_attr_del_var,
+-	NULL,
++static struct bin_attribute var_subsys_attr_del_var = {
++	.attr = {.name = "del_var", .mode = 0200},
++	.write = efivar_delete,
+ };
+ 
+ /*
+  * Let's not leave out systab information that snuck into
+  * the efivars driver
+  */
+-static ssize_t
+-systab_read(struct kset *kset, char *buf)
++static ssize_t systab_show(struct kobject *kobj,
++			   struct kobj_attribute *attr, char *buf)
+ {
+ 	char *str = buf;
+ 
+-	if (!kset || !buf)
++	if (!kobj || !buf)
+ 		return -EINVAL;
+ 
+ 	if (efi.mps != EFI_INVALID_TABLE_ADDR)
+@@ -576,15 +559,21 @@ systab_read(struct kset *kset, char *buf)
+ 	return str - buf;
+ }
+ 
+-static EFI_ATTR(systab, 0400, systab_read, NULL);
++static struct kobj_attribute efi_attr_systab =
++			__ATTR(systab, 0400, systab_show, NULL);
+ 
+-static struct subsys_attribute *efi_subsys_attrs[] = {
+-	&efi_attr_systab,
++static struct attribute *efi_subsys_attrs[] = {
++	&efi_attr_systab.attr,
+ 	NULL,	/* maybe more in the future? */
+ };
+ 
+-static decl_subsys(vars, &efivar_ktype, NULL);
+-static decl_subsys(efi, NULL, NULL);
++static struct attribute_group efi_subsys_attr_group = {
++	.attrs = efi_subsys_attrs,
++};
 +
++
++static struct kset *vars_kset;
++static struct kobject *efi_kobj;
+ 
+ /*
+  * efivar_create_sysfs_entry()
+@@ -628,15 +617,16 @@ efivar_create_sysfs_entry(unsigned long variable_name_size,
+ 	*(short_name + strlen(short_name)) = '-';
+ 	efi_guid_unparse(vendor_guid, short_name + strlen(short_name));
+ 
+-	kobject_set_name(&new_efivar->kobj, "%s", short_name);
+-	kobj_set_kset_s(new_efivar, vars_subsys);
+-	i = kobject_register(&new_efivar->kobj);
++	new_efivar->kobj.kset = vars_kset;
++	i = kobject_init_and_add(&new_efivar->kobj, &efivar_ktype, NULL,
++				 "%s", short_name);
+ 	if (i) {
+ 		kfree(short_name);
+ 		kfree(new_efivar);
+ 		return 1;
+ 	}
+ 
++	kobject_uevent(&new_efivar->kobj, KOBJ_ADD);
+ 	kfree(short_name);
+ 	short_name = NULL;
+ 
+@@ -660,9 +650,8 @@ efivars_init(void)
+ 	efi_status_t status = EFI_NOT_FOUND;
+ 	efi_guid_t vendor_guid;
+ 	efi_char16_t *variable_name;
+-	struct subsys_attribute *attr;
+ 	unsigned long variable_name_size = 1024;
+-	int i, error = 0;
++	int error = 0;
+ 
+ 	if (!efi_enabled)
+ 		return -ENODEV;
+@@ -676,23 +665,18 @@ efivars_init(void)
+ 	printk(KERN_INFO "EFI Variables Facility v%s %s\n", EFIVARS_VERSION,
+ 	       EFIVARS_DATE);
+ 
+-	/*
+-	 * For now we'll register the efi subsys within this driver
+-	 */
+-
+-	error = firmware_register(&efi_subsys);
+-
+-	if (error) {
+-		printk(KERN_ERR "efivars: Firmware registration failed with error %d.\n", error);
++	/* For now we'll register the efi directory at /sys/firmware/efi */
++	efi_kobj = kobject_create_and_add("efi", firmware_kobj);
++	if (!efi_kobj) {
++		printk(KERN_ERR "efivars: Firmware registration failed.\n");
++		error = -ENOMEM;
+ 		goto out_free;
+ 	}
+ 
+-	kobj_set_kset_s(&vars_subsys, efi_subsys);
+-
+-	error = subsystem_register(&vars_subsys);
+-
+-	if (error) {
+-		printk(KERN_ERR "efivars: Subsystem registration failed with error %d.\n", error);
++	vars_kset = kset_create_and_add("vars", NULL, efi_kobj);
++	if (!vars_kset) {
++		printk(KERN_ERR "efivars: Subsystem registration failed.\n");
++		error = -ENOMEM;
+ 		goto out_firmware_unregister;
+ 	}
+ 
+@@ -727,28 +711,28 @@ efivars_init(void)
+ 	 * Now add attributes to allow creation of new vars
+ 	 * and deletion of existing ones...
+ 	 */
+-
+-	for (i = 0; (attr = var_subsys_attrs[i]) && !error; i++) {
+-		if (attr->show && attr->store)
+-			error = subsys_create_file(&vars_subsys, attr);
+-	}
++	error = sysfs_create_bin_file(&vars_kset->kobj,
++				      &var_subsys_attr_new_var);
++	if (error)
++		printk(KERN_ERR "efivars: unable to create new_var sysfs file"
++			" due to error %d\n", error);
++	error = sysfs_create_bin_file(&vars_kset->kobj,
++				      &var_subsys_attr_del_var);
++	if (error)
++		printk(KERN_ERR "efivars: unable to create del_var sysfs file"
++			" due to error %d\n", error);
+ 
+ 	/* Don't forget the systab entry */
+-
+-	for (i = 0; (attr = efi_subsys_attrs[i]) && !error; i++) {
+-		if (attr->show)
+-			error = subsys_create_file(&efi_subsys, attr);
+-	}
+-
++	error = sysfs_create_group(efi_kobj, &efi_subsys_attr_group);
+ 	if (error)
+ 		printk(KERN_ERR "efivars: Sysfs attribute export failed with error %d.\n", error);
+ 	else
+ 		goto out_free;
+ 
+-	subsystem_unregister(&vars_subsys);
++	kset_unregister(vars_kset);
+ 
+ out_firmware_unregister:
+-	firmware_unregister(&efi_subsys);
++	kobject_put(efi_kobj);
+ 
+ out_free:
+ 	kfree(variable_name);
+@@ -768,8 +752,8 @@ efivars_exit(void)
+ 		efivar_unregister(entry);
+ 	}
+ 
+-	subsystem_unregister(&vars_subsys);
+-	firmware_unregister(&efi_subsys);
++	kset_unregister(vars_kset);
++	kobject_put(efi_kobj);
+ }
+ 
+ module_init(efivars_init);
+diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
+index 1ac5103..275dc52 100644
+--- a/drivers/hid/Makefile
++++ b/drivers/hid/Makefile
+@@ -1,7 +1,7 @@
+ #
+ # Makefile for the HID driver
+ #
+-hid-objs			:= hid-core.o hid-input.o
++hid-objs			:= hid-core.o hid-input.o hid-input-quirks.o
+ 
+ obj-$(CONFIG_HID)		+= hid.o
+ 
+diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
+index 2884b03..d73a768 100644
+--- a/drivers/hid/hid-core.c
++++ b/drivers/hid/hid-core.c
+@@ -26,6 +26,7 @@
+ #include <linux/input.h>
+ #include <linux/wait.h>
+ #include <linux/vmalloc.h>
++#include <linux/sched.h>
+ 
+ #include <linux/hid.h>
+ #include <linux/hiddev.h>
+@@ -758,7 +759,9 @@ static __inline__ __u32 extract(__u8 *report, unsigned offset, unsigned n)
+ {
+ 	u64 x;
+ 
+-	WARN_ON(n > 32);
++	if (n > 32)
++		printk(KERN_WARNING "HID: extract() called with n (%d) > 32! (%s)\n",
++				n, current->comm);
+ 
+ 	report += offset >> 3;  /* adjust byte index */
+ 	offset &= 7;            /* now only need bit offset into one byte */
+@@ -780,8 +783,13 @@ static __inline__ void implement(__u8 *report, unsigned offset, unsigned n, __u3
+ 	__le64 x;
+ 	u64 m = (1ULL << n) - 1;
+ 
+-	WARN_ON(n > 32);
++	if (n > 32)
++		printk(KERN_WARNING "HID: implement() called with n (%d) > 32! (%s)\n",
++				n, current->comm);
+ 
++	if (value > m)
++		printk(KERN_WARNING "HID: implement() called with too large value %d! (%s)\n",
++				value, current->comm);
+ 	WARN_ON(value > m);
+ 	value &= m;
+ 
+diff --git a/drivers/hid/hid-input-quirks.c b/drivers/hid/hid-input-quirks.c
+new file mode 100644
+index 0000000..a870ba5
+--- /dev/null
++++ b/drivers/hid/hid-input-quirks.c
+@@ -0,0 +1,423 @@
 +/*
-+ * AES decryption functions.
++ *  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
 + */
-+static inline int hifn_decrypt_aes_ecb(struct ablkcipher_request *req)
-+{
-+	return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT,
-+			ACRYPTO_TYPE_AES_128, ACRYPTO_MODE_ECB);
-+}
-+static inline int hifn_decrypt_aes_cbc(struct ablkcipher_request *req)
-+{
-+	return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT,
-+			ACRYPTO_TYPE_AES_128, ACRYPTO_MODE_CBC);
-+}
-+static inline int hifn_decrypt_aes_cfb(struct ablkcipher_request *req)
-+{
-+	return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT,
-+			ACRYPTO_TYPE_AES_128, ACRYPTO_MODE_CFB);
-+}
-+static inline int hifn_decrypt_aes_ofb(struct ablkcipher_request *req)
-+{
-+	return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT,
-+			ACRYPTO_TYPE_AES_128, ACRYPTO_MODE_OFB);
-+}
 +
 +/*
-+ * DES ecryption functions.
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the Free
++ * Software Foundation; either version 2 of the License
 + */
-+static inline int hifn_encrypt_des_ecb(struct ablkcipher_request *req)
-+{
-+	return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT,
-+			ACRYPTO_TYPE_DES, ACRYPTO_MODE_ECB);
-+}
-+static inline int hifn_encrypt_des_cbc(struct ablkcipher_request *req)
-+{
-+	return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT,
-+			ACRYPTO_TYPE_DES, ACRYPTO_MODE_CBC);
-+}
-+static inline int hifn_encrypt_des_cfb(struct ablkcipher_request *req)
-+{
-+	return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT,
-+			ACRYPTO_TYPE_DES, ACRYPTO_MODE_CFB);
-+}
-+static inline int hifn_encrypt_des_ofb(struct ablkcipher_request *req)
-+{
-+	return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT,
-+			ACRYPTO_TYPE_DES, ACRYPTO_MODE_OFB);
-+}
 +
-+/*
-+ * DES decryption functions.
-+ */
-+static inline int hifn_decrypt_des_ecb(struct ablkcipher_request *req)
-+{
-+	return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT,
-+			ACRYPTO_TYPE_DES, ACRYPTO_MODE_ECB);
-+}
-+static inline int hifn_decrypt_des_cbc(struct ablkcipher_request *req)
++#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)
 +{
-+	return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT,
-+			ACRYPTO_TYPE_DES, ACRYPTO_MODE_CBC);
++	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 inline int hifn_decrypt_des_cfb(struct ablkcipher_request *req)
++
++static int quirk_cherry_cymotion(struct hid_usage *usage, struct input_dev *input,
++			      unsigned long **bit, int *max)
 +{
-+	return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT,
-+			ACRYPTO_TYPE_DES, ACRYPTO_MODE_CFB);
++	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 inline int hifn_decrypt_des_ofb(struct ablkcipher_request *req)
++
++static int quirk_logitech_ultrax_remote(struct hid_usage *usage, struct input_dev *input,
++			      unsigned long **bit, int *max)
 +{
-+	return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT,
-+			ACRYPTO_TYPE_DES, ACRYPTO_MODE_OFB);
++	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;
 +}
 +
-+/*
-+ * 3DES ecryption functions.
-+ */
-+static inline int hifn_encrypt_3des_ecb(struct ablkcipher_request *req)
++static int quirk_chicony_tactical_pad(struct hid_usage *usage, struct input_dev *input,
++			      unsigned long **bit, int *max)
 +{
-+	return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT,
-+			ACRYPTO_TYPE_3DES, ACRYPTO_MODE_ECB);
++	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 inline int hifn_encrypt_3des_cbc(struct ablkcipher_request *req)
++
++static int quirk_microsoft_ergonomy_kb(struct hid_usage *usage, struct input_dev *input,
++			      unsigned long **bit, int *max)
 +{
-+	return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT,
-+			ACRYPTO_TYPE_3DES, ACRYPTO_MODE_CBC);
++	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 inline int hifn_encrypt_3des_cfb(struct ablkcipher_request *req)
++
++static int quirk_microsoft_presenter_8k(struct hid_usage *usage, struct input_dev *input,
++			      unsigned long **bit, int *max)
 +{
-+	return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT,
-+			ACRYPTO_TYPE_3DES, ACRYPTO_MODE_CFB);
++	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 inline int hifn_encrypt_3des_ofb(struct ablkcipher_request *req)
++
++static int quirk_petalynx_remote(struct hid_usage *usage, struct input_dev *input,
++			      unsigned long **bit, int *max)
 +{
-+	return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT,
-+			ACRYPTO_TYPE_3DES, ACRYPTO_MODE_OFB);
++	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;
 +}
 +
-+/*
-+ * 3DES decryption functions.
-+ */
-+static inline int hifn_decrypt_3des_ecb(struct ablkcipher_request *req)
++static int quirk_logitech_wireless(struct hid_usage *usage, struct input_dev *input,
++			      unsigned long **bit, int *max)
 +{
-+	return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT,
-+			ACRYPTO_TYPE_3DES, ACRYPTO_MODE_ECB);
++	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 inline int hifn_decrypt_3des_cbc(struct ablkcipher_request *req)
++
++static int quirk_cherry_genius_29e(struct hid_usage *usage, struct input_dev *input,
++			      unsigned long **bit, int *max)
 +{
-+	return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT,
-+			ACRYPTO_TYPE_3DES, ACRYPTO_MODE_CBC);
++	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 inline int hifn_decrypt_3des_cfb(struct ablkcipher_request *req)
++
++static int quirk_btc_8193(struct hid_usage *usage, struct input_dev *input,
++			      unsigned long **bit, int *max)
 +{
-+	return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT,
-+			ACRYPTO_TYPE_3DES, ACRYPTO_MODE_CFB);
++	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 inline int hifn_decrypt_3des_ofb(struct ablkcipher_request *req)
++
++#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_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
++
++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_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 },
++	
++	{ 0, 0, 0 }
++};
++
++int hidinput_mapping_quirks(struct hid_usage *usage, 
++				   struct input_dev *input, 
++				   unsigned long **bit, int *max)
 +{
-+	return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT,
-+			ACRYPTO_TYPE_3DES, ACRYPTO_MODE_OFB);
++	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;
 +}
 +
-+struct hifn_alg_template
++void hidinput_event_quirks(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value)
 +{
-+	char name[CRYPTO_MAX_ALG_NAME];
-+	char drv_name[CRYPTO_MAX_ALG_NAME];
-+	unsigned int bsize;
-+	struct ablkcipher_alg ablkcipher;
-+};
++	struct input_dev *input;
 +
-+static struct hifn_alg_template hifn_alg_templates[] = {
-+	/*
-+	 * 3DES ECB, CBC, CFB and OFB modes.
-+	 */
-+	{
-+		.name = "cfb(des3_ede)", .drv_name = "hifn-3des", .bsize = 8,
-+		.ablkcipher = {
-+			.min_keysize	=	HIFN_3DES_KEY_LENGTH,
-+			.max_keysize	=	HIFN_3DES_KEY_LENGTH,
-+			.setkey		=	hifn_setkey,
-+			.encrypt	=	hifn_encrypt_3des_cfb,
-+			.decrypt	=	hifn_decrypt_3des_cfb,
-+		},
-+	},
-+	{
-+		.name = "ofb(des3_ede)", .drv_name = "hifn-3des", .bsize = 8,
-+		.ablkcipher = {
-+			.min_keysize	=	HIFN_3DES_KEY_LENGTH,
-+			.max_keysize	=	HIFN_3DES_KEY_LENGTH,
-+			.setkey		=	hifn_setkey,
-+			.encrypt	=	hifn_encrypt_3des_ofb,
-+			.decrypt	=	hifn_decrypt_3des_ofb,
-+		},
-+	},
-+	{
-+		.name = "cbc(des3_ede)", .drv_name = "hifn-3des", .bsize = 8,
-+		.ablkcipher = {
-+			.min_keysize	=	HIFN_3DES_KEY_LENGTH,
-+			.max_keysize	=	HIFN_3DES_KEY_LENGTH,
-+			.setkey		=	hifn_setkey,
-+			.encrypt	=	hifn_encrypt_3des_cbc,
-+			.decrypt	=	hifn_decrypt_3des_cbc,
-+		},
-+	},
-+	{
-+		.name = "ecb(des3_ede)", .drv_name = "hifn-3des", .bsize = 8,
-+		.ablkcipher = {
-+			.min_keysize	=	HIFN_3DES_KEY_LENGTH,
-+			.max_keysize	=	HIFN_3DES_KEY_LENGTH,
-+			.setkey		=	hifn_setkey,
-+			.encrypt	=	hifn_encrypt_3des_ecb,
-+			.decrypt	=	hifn_decrypt_3des_ecb,
-+		},
-+	},
++	input = field->hidinput->input;
 +
-+	/*
-+	 * DES ECB, CBC, CFB and OFB modes.
-+	 */
-+	{
-+		.name = "cfb(des)", .drv_name = "hifn-des", .bsize = 8,
-+		.ablkcipher = {
-+			.min_keysize	=	HIFN_DES_KEY_LENGTH,
-+			.max_keysize	=	HIFN_DES_KEY_LENGTH,
-+			.setkey		=	hifn_setkey,
-+			.encrypt	=	hifn_encrypt_des_cfb,
-+			.decrypt	=	hifn_decrypt_des_cfb,
-+		},
-+	},
-+	{
-+		.name = "ofb(des)", .drv_name = "hifn-des", .bsize = 8,
-+		.ablkcipher = {
-+			.min_keysize	=	HIFN_DES_KEY_LENGTH,
-+			.max_keysize	=	HIFN_DES_KEY_LENGTH,
-+			.setkey		=	hifn_setkey,
-+			.encrypt	=	hifn_encrypt_des_ofb,
-+			.decrypt	=	hifn_decrypt_des_ofb,
-+		},
-+	},
-+	{
-+		.name = "cbc(des)", .drv_name = "hifn-des", .bsize = 8,
-+		.ablkcipher = {
-+			.min_keysize	=	HIFN_DES_KEY_LENGTH,
-+			.max_keysize	=	HIFN_DES_KEY_LENGTH,
-+			.setkey		=	hifn_setkey,
-+			.encrypt	=	hifn_encrypt_des_cbc,
-+			.decrypt	=	hifn_decrypt_des_cbc,
-+		},
-+	},
-+	{
-+		.name = "ecb(des)", .drv_name = "hifn-des", .bsize = 8,
-+		.ablkcipher = {
-+			.min_keysize	=	HIFN_DES_KEY_LENGTH,
-+			.max_keysize	=	HIFN_DES_KEY_LENGTH,
-+			.setkey		=	hifn_setkey,
-+			.encrypt	=	hifn_encrypt_des_ecb,
-+			.decrypt	=	hifn_decrypt_des_ecb,
-+		},
-+	},
++	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;
++	}
 +
-+	/*
-+	 * AES ECB, CBC, CFB and OFB modes.
-+	 */
-+	{
-+		.name = "ecb(aes)", .drv_name = "hifn-aes", .bsize = 16,
-+		.ablkcipher = {
-+			.min_keysize	=	AES_MIN_KEY_SIZE,
-+			.max_keysize	=	AES_MAX_KEY_SIZE,
-+			.setkey		=	hifn_setkey,
-+			.encrypt	=	hifn_encrypt_aes_ecb,
-+			.decrypt	=	hifn_decrypt_aes_ecb,
-+		},
-+	},
-+	{
-+		.name = "cbc(aes)", .drv_name = "hifn-aes", .bsize = 16,
-+		.ablkcipher = {
-+			.min_keysize	=	AES_MIN_KEY_SIZE,
-+			.max_keysize	=	AES_MAX_KEY_SIZE,
-+			.setkey		=	hifn_setkey,
-+			.encrypt	=	hifn_encrypt_aes_cbc,
-+			.decrypt	=	hifn_decrypt_aes_cbc,
-+		},
-+	},
-+	{
-+		.name = "cfb(aes)", .drv_name = "hifn-aes", .bsize = 16,
-+		.ablkcipher = {
-+			.min_keysize	=	AES_MIN_KEY_SIZE,
-+			.max_keysize	=	AES_MAX_KEY_SIZE,
-+			.setkey		=	hifn_setkey,
-+			.encrypt	=	hifn_encrypt_aes_cfb,
-+			.decrypt	=	hifn_decrypt_aes_cfb,
-+		},
-+	},
-+	{
-+		.name = "ofb(aes)", .drv_name = "hifn-aes", .bsize = 16,
-+		.ablkcipher = {
-+			.min_keysize	=	AES_MIN_KEY_SIZE,
-+			.max_keysize	=	AES_MAX_KEY_SIZE,
-+			.setkey		=	hifn_setkey,
-+			.encrypt	=	hifn_encrypt_aes_ofb,
-+			.decrypt	=	hifn_decrypt_aes_ofb,
-+		},
-+	},
++	if ((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_B8) &&
++			(usage->type == EV_REL) &&
++			(usage->code == REL_WHEEL)) {
++		hid->delayed_value = value;
++		return;
++	}
++
++	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;
++	}
++
++	if ((hid->quirks & HID_QUIRK_INVERT_HWHEEL) && (usage->code == REL_HWHEEL)) {
++		input_event(input, usage->type, usage->code, -value);
++		return;
++	}
++
++	if ((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_ON) && (usage->code == REL_WHEEL)) {
++		input_event(input, usage->type, REL_HWHEEL, value);
++		return;
++	}
++
++	if ((hid->quirks & HID_QUIRK_APPLE_HAS_FN) && hidinput_apple_event(hid, input, usage, value))
++		return;
++
++	/* 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;
++	}
++}
++
++
+diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
+index 0b27da7..5325d98 100644
+--- a/drivers/hid/hid-input.c
++++ b/drivers/hid/hid-input.c
+@@ -34,10 +34,10 @@
+ #include <linux/hid.h>
+ #include <linux/hid-debug.h>
+ 
+-static int hid_pb_fnmode = 1;
+-module_param_named(pb_fnmode, hid_pb_fnmode, int, 0644);
++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 PowerBooks (0 = disabled, 1 = fkeyslast, 2 = fkeysfirst)");
++		"Mode of fn key on Apple keyboards (0 = disabled, 1 = fkeyslast, 2 = fkeysfirst)");
+ 
+ #define unk	KEY_UNKNOWN
+ 
+@@ -86,10 +86,6 @@ static const struct {
+ #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)
+ 
+-/* hardware needing special handling due to colliding MSVENDOR page usages */
+-#define IS_CHICONY_TACTICAL_PAD(x) (x->vendor == 0x04f2 && device->product == 0x0418)
+-#define IS_MS_KB(x) (x->vendor == 0x045e && (x->product == 0x00db || x->product == 0x00f9))
+-
+ #ifdef CONFIG_USB_HIDINPUT_POWERBOOK
+ 
+ struct hidinput_key_translation {
+@@ -98,20 +94,36 @@ struct hidinput_key_translation {
+ 	u8 flags;
+ };
+ 
+-#define POWERBOOK_FLAG_FKEY 0x01
++#define APPLE_FLAG_FKEY 0x01
++
++static struct hidinput_key_translation apple_fn_keys[] = {
++	{ KEY_F1,       KEY_BRIGHTNESSDOWN,     APPLE_FLAG_FKEY },
++	{ KEY_F2,       KEY_BRIGHTNESSUP,       APPLE_FLAG_FKEY },
++	{ KEY_F3,       KEY_CYCLEWINDOWS,       APPLE_FLAG_FKEY }, /* Exposé */
++	{ KEY_F4,       KEY_FN_F4,              APPLE_FLAG_FKEY }, /* Dashboard */
++	{ KEY_F5,       KEY_FN_F5 },
++	{ KEY_F6,       KEY_FN_F6 },
++	{ KEY_F7,       KEY_BACK,               APPLE_FLAG_FKEY },
++	{ KEY_F8,       KEY_PLAYPAUSE,          APPLE_FLAG_FKEY },
++	{ KEY_F9,       KEY_FORWARD,            APPLE_FLAG_FKEY },
++	{ KEY_F10,      KEY_MUTE,               APPLE_FLAG_FKEY },
++	{ KEY_F11,      KEY_VOLUMEDOWN,         APPLE_FLAG_FKEY },
++	{ KEY_F12,      KEY_VOLUMEUP,           APPLE_FLAG_FKEY },
++	{ }
 +};
+ 
+ static struct hidinput_key_translation powerbook_fn_keys[] = {
+ 	{ KEY_BACKSPACE, KEY_DELETE },
+-	{ KEY_F1,       KEY_BRIGHTNESSDOWN,     POWERBOOK_FLAG_FKEY },
+-	{ KEY_F2,       KEY_BRIGHTNESSUP,       POWERBOOK_FLAG_FKEY },
+-	{ KEY_F3,       KEY_MUTE,               POWERBOOK_FLAG_FKEY },
+-	{ KEY_F4,       KEY_VOLUMEDOWN,         POWERBOOK_FLAG_FKEY },
+-	{ KEY_F5,       KEY_VOLUMEUP,           POWERBOOK_FLAG_FKEY },
+-	{ KEY_F6,       KEY_NUMLOCK,            POWERBOOK_FLAG_FKEY },
+-	{ KEY_F7,       KEY_SWITCHVIDEOMODE,    POWERBOOK_FLAG_FKEY },
+-	{ KEY_F8,       KEY_KBDILLUMTOGGLE,     POWERBOOK_FLAG_FKEY },
+-	{ KEY_F9,       KEY_KBDILLUMDOWN,       POWERBOOK_FLAG_FKEY },
+-	{ KEY_F10,      KEY_KBDILLUMUP,         POWERBOOK_FLAG_FKEY },
++	{ 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 },
+@@ -142,7 +154,7 @@ static struct hidinput_key_translation powerbook_numlock_keys[] = {
+ 	{ }
+ };
+ 
+-static struct hidinput_key_translation powerbook_iso_keyboard[] = {
++static struct hidinput_key_translation apple_iso_keyboard[] = {
+ 	{ KEY_GRAVE,    KEY_102ND },
+ 	{ KEY_102ND,    KEY_GRAVE },
+ 	{ }
+@@ -160,39 +172,42 @@ static struct hidinput_key_translation *find_translation(struct hidinput_key_tra
+ 	return NULL;
+ }
+ 
+-static int hidinput_pb_event(struct hid_device *hid, struct input_dev *input,
++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_POWERBOOK_FN_ON;
+-		else       hid->quirks &= ~HID_QUIRK_POWERBOOK_FN_ON;
++		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_pb_fnmode) {
++	if (hid_apple_fnmode) {
+ 		int do_translate;
+ 
+-		trans = find_translation(powerbook_fn_keys, usage->code);
++		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->pb_pressed_fn))
++			if (test_bit(usage->code, hid->apple_pressed_fn))
+ 				do_translate = 1;
+-			else if (trans->flags & POWERBOOK_FLAG_FKEY)
++			else if (trans->flags & APPLE_FLAG_FKEY)
+ 				do_translate =
+-					(hid_pb_fnmode == 2 &&  (hid->quirks & HID_QUIRK_POWERBOOK_FN_ON)) ||
+-					(hid_pb_fnmode == 1 && !(hid->quirks & HID_QUIRK_POWERBOOK_FN_ON));
++					(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_POWERBOOK_FN_ON);
++				do_translate = (hid->quirks & HID_QUIRK_APPLE_FN_ON);
+ 
+ 			if (do_translate) {
+ 				if (value)
+-					set_bit(usage->code, hid->pb_pressed_fn);
++					set_bit(usage->code, hid->apple_pressed_fn);
+ 				else
+-					clear_bit(usage->code, hid->pb_pressed_fn);
++					clear_bit(usage->code, hid->apple_pressed_fn);
+ 
+ 				input_event(input, usage->type, trans->to, value);
+ 
+@@ -217,8 +232,8 @@ static int hidinput_pb_event(struct hid_device *hid, struct input_dev *input,
+ 		}
+ 	}
+ 
+-	if (hid->quirks & HID_QUIRK_POWERBOOK_ISO_KEYBOARD) {
+-		trans = find_translation(powerbook_iso_keyboard, usage->code);
++	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;
+@@ -228,31 +243,35 @@ static int hidinput_pb_event(struct hid_device *hid, struct input_dev *input,
+ 	return 0;
+ }
+ 
+-static void hidinput_pb_setup(struct input_dev *input)
++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);
 +
-+static int hifn_cra_init(struct crypto_tfm *tfm)
-+{
-+	struct crypto_alg *alg = tfm->__crt_alg;
-+	struct hifn_crypto_alg *ha = crypto_alg_to_hifn(alg);
-+	struct hifn_context *ctx = crypto_tfm_ctx(tfm);
+ 	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 = powerbook_iso_keyboard; trans->from; trans++)
++	for (trans = apple_iso_keyboard; trans->from; trans++)
+ 		set_bit(trans->to, input->keybit);
+ 
+ }
+ #else
+-static inline int hidinput_pb_event(struct hid_device *hid, struct input_dev *input,
+-		struct hid_usage *usage, __s32 value)
++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_pb_setup(struct input_dev *input)
++static inline void hidinput_apple_setup(struct input_dev *input)
+ {
+ }
+ #endif
+@@ -343,7 +362,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
+ {
+ 	struct input_dev *input = hidinput->input;
+ 	struct hid_device *device = input_get_drvdata(input);
+-	int max = 0, code;
++	int max = 0, code, ret;
+ 	unsigned long *bit = NULL;
+ 
+ 	field->hidinput = hidinput;
+@@ -362,6 +381,11 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
+ 		goto ignore;
+ 	}
+ 
++	/* handle input mappings for quirky devices */
++	ret = hidinput_mapping_quirks(usage, input, &bit, &max);
++	if (ret)
++		goto mapped;
 +
-+	ctx->dev = ha->dev;
+ 	switch (usage->hid & HID_USAGE_PAGE) {
+ 
+ 		case HID_UP_UNDEFINED:
+@@ -549,14 +573,6 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
+ 				case 0x000: goto ignore;
+ 				case 0x034: map_key_clear(KEY_SLEEP);		break;
+ 				case 0x036: map_key_clear(BTN_MISC);		break;
+-				/*
+-				 * The next three are reported by Belkin wireless
+-				 * keyboard (1020:0006). These values are "reserved"
+-				 * in HUT 1.12.
+-				 */
+-				case 0x03a: map_key_clear(KEY_SOUND);           break;
+-				case 0x03b: map_key_clear(KEY_CAMERA);          break;
+-				case 0x03c: map_key_clear(KEY_DOCUMENTS);       break;
+ 
+ 				case 0x040: map_key_clear(KEY_MENU);		break;
+ 				case 0x045: map_key_clear(KEY_RADIO);		break;
+@@ -602,10 +618,6 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
+ 				case 0x0e9: map_key_clear(KEY_VOLUMEUP);	break;
+ 				case 0x0ea: map_key_clear(KEY_VOLUMEDOWN);	break;
+ 
+-				/* reserved in HUT 1.12. Reported on Petalynx remote */
+-				case 0x0f6: map_key_clear(KEY_NEXT);		break;
+-				case 0x0fa: map_key_clear(KEY_BACK);		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;
+@@ -665,51 +677,6 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
+ 				case 0x28b: map_key_clear(KEY_FORWARDMAIL);	break;
+ 				case 0x28c: map_key_clear(KEY_SEND);		break;
+ 
+-				/* Reported on a Cherry Cymotion keyboard */
+-				case 0x301: map_key_clear(KEY_PROG1);		break;
+-				case 0x302: map_key_clear(KEY_PROG2);		break;
+-				case 0x303: map_key_clear(KEY_PROG3);		break;
+-
+-				/* Reported on certain Logitech wireless keyboards */
+-				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:    goto ignore;
+ 			}
+ 			break;
+@@ -736,63 +703,16 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
+ 
+ 		case HID_UP_MSVENDOR:
+ 
+-			/* Unfortunately, there are multiple devices which
+-			 * emit usages from MSVENDOR page that require different
+-			 * handling. If this list grows too much in the future,
+-			 * more general handling will have to be introduced here
+-			 * (i.e. another blacklist).
+-			 */
+-
+-			/* Chicony Chicony KU-0418 tactical pad */
+-			if (IS_CHICONY_TACTICAL_PAD(device)) {
+-				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:    goto ignore;
+-				}
+-
+-			/* Microsoft Natural Ergonomic Keyboard 4000 */
+-			} else if (IS_MS_KB(device)) {
+-				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:	goto ignore;
+-				}
+-			} else {
+-				goto ignore;
+-			}
+-			break;
++			goto ignore;
+ 
+-		case HID_UP_CUSTOM: /* Reported on Logitech and Powerbook USB keyboards */
++		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 PowerBooks */
++					/* The fn key on Apple USB keyboards */
+ 					map_key_clear(KEY_FN);
+-					hidinput_pb_setup(input);
++					hidinput_apple_setup(input);
+ 					break;
+ 
+ 				default:    goto ignore;
+@@ -800,38 +720,9 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
+ 			break;
+ 
+ 		case HID_UP_LOGIVENDOR:
+-			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;
+-
+-				/* Reported on Petalynx Maxter remote */
+-				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:    goto ignore;
+-			}
+-			break;
+ 
++			goto ignore;
++		
+ 		case HID_UP_PID:
+ 
+ 			switch(usage->hid & HID_USAGE) {
+@@ -858,6 +749,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
+ 			break;
+ 	}
+ 
++mapped:
+ 	if (device->quirks & HID_QUIRK_MIGHTYMOUSE) {
+ 		if (usage->hid == HID_GD_Z)
+ 			map_rel(REL_HWHEEL);
+@@ -867,9 +759,10 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
+ 			map_key(BTN_1);
+ 	}
+ 
+-	if ((device->quirks & (HID_QUIRK_2WHEEL_MOUSE_HACK_7 | HID_QUIRK_2WHEEL_MOUSE_HACK_5)) &&
+-		 (usage->type == EV_REL) && (usage->code == REL_WHEEL))
+-			set_bit(REL_HWHEEL, bit);
++	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)))
+@@ -960,25 +853,8 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct
+ 	if (!usage->type)
+ 		return;
+ 
+-	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;
+-	}
+-
+-	if ((hid->quirks & HID_QUIRK_INVERT_HWHEEL) && (usage->code == REL_HWHEEL)) {
+-		input_event(input, usage->type, usage->code, -value);
+-		return;
+-	}
+-
+-	if ((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_ON) && (usage->code == REL_WHEEL)) {
+-		input_event(input, usage->type, REL_HWHEEL, value);
+-		return;
+-	}
+-
+-	if ((hid->quirks & HID_QUIRK_POWERBOOK_HAS_FN) && hidinput_pb_event(hid, input, usage, value))
+-		return;
++	/* handle input events for quirky devices */
++	hidinput_event_quirks(hid, field, usage, value);
+ 
+ 	if (usage->hat_min < usage->hat_max || usage->hat_dir) {
+ 		int hat_dir = usage->hat_dir;
+@@ -1039,25 +915,6 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct
+ 		return;
+ 	}
+ 
+-	/* Handling MS keyboards special buttons */
+-	if (IS_MS_KB(hid) && 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);
+-		}
+-	}
+ 	/* report the usage code as scancode if the key status has changed */
+ 	if (usage->type == EV_KEY && !!test_bit(usage->code, input->key) != value)
+ 		input_event(input, EV_MSC, MSC_SCAN, usage->hid);
+diff --git a/drivers/hid/usbhid/Kconfig b/drivers/hid/usbhid/Kconfig
+index c557d70..7160fa6 100644
+--- a/drivers/hid/usbhid/Kconfig
++++ b/drivers/hid/usbhid/Kconfig
+@@ -25,12 +25,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 iBook/PowerBook/MacBook/MacBookPro special keys"
++	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 and MacBook Pros.
++	  Apple iBooks, PowerBooks, MacBooks, MacBook Pros and aluminum USB
++	  keyboards.
+ 
+ 	  If unsure, say N.
+ 
+diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c
+index a255285..b77b61e 100644
+--- a/drivers/hid/usbhid/hid-quirks.c
++++ b/drivers/hid/usbhid/hid-quirks.c
+@@ -19,6 +19,7 @@
+ 
+ #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
+@@ -28,6 +29,9 @@
+ #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_AIPTEK		0x08ca
+ #define USB_DEVICE_ID_AIPTEK_01		0x0001
+ #define USB_DEVICE_ID_AIPTEK_10		0x0010
+@@ -59,6 +63,9 @@
+ #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_FOUNTAIN_TP_ONLY	0x030a
+ #define USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY	0x030b
+ #define USB_DEVICE_ID_APPLE_IRCONTROL4	0x8242
+@@ -94,6 +101,9 @@
+ #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
+@@ -114,6 +124,9 @@
+ #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
+ 
+@@ -134,6 +147,9 @@
+ #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
+@@ -278,7 +294,9 @@
+ #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
+@@ -296,6 +314,12 @@
+ 
+ #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_VENDOR_ID_MONTEREY		0x0566
++#define USB_DEVICE_ID_GENIUS_KB29E	0x3004
+ 
+ #define USB_VENDOR_ID_NCR		0x0404
+ #define USB_DEVICE_ID_NCR_FIRST		0x0300
+@@ -324,6 +348,9 @@
+ #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
+ 
+@@ -368,6 +395,7 @@ static const struct hid_blacklist {
+ } 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 },
+@@ -390,6 +418,9 @@ static const struct hid_blacklist {
+ 	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4, 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 },
+@@ -402,6 +433,7 @@ static const struct hid_blacklist {
+ 	{ 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 },
+@@ -423,6 +455,7 @@ static const struct hid_blacklist {
+ 	{ 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 },
+@@ -516,14 +549,18 @@ static const struct hid_blacklist {
+ 	{ 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_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_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 },
++	{ 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 },
+@@ -531,7 +568,9 @@ static const struct hid_blacklist {
+ 	{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVM, HID_QUIRK_NOGET },
+ 	{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVMC, HID_QUIRK_NOGET },
+ 	{ USB_VENDOR_ID_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 },
+@@ -540,19 +579,22 @@ static const struct hid_blacklist {
+ 
+ 	{ 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_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+-	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+-	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ANSI, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+-	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_POWERBOOK_ISO_KEYBOARD},
+-	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_JIS, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+-	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ANSI, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+-	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_POWERBOOK_ISO_KEYBOARD},
+-	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_JIS, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+-	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ANSI, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+-	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_POWERBOOK_ISO_KEYBOARD},
+-	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_JIS, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+-	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+-	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
++	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
++	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ISO, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
++	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ANSI, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
++	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ISO, 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_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
++	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ANSI, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
++	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ISO, 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_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
++	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ANSI, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
++	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ISO, 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_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_FOUNTAIN_TP_ONLY, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
++	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY, 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 },
+@@ -638,10 +680,14 @@ static const struct hid_rdesc_blacklist {
+ 	{ 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_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_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 },
+ 
+@@ -884,6 +930,8 @@ u32 usbhid_lookup_quirk(const u16 idVendor, const u16 idProduct)
+ 	return quirks;
+ }
+ 
++EXPORT_SYMBOL_GPL(usbhid_lookup_quirk);
++
+ /*
+  * Cherry Cymotion keyboard have an invalid HID report descriptor,
+  * that needs fixing before we can parse it.
+@@ -914,6 +962,33 @@ static void usbhid_fixup_logitech_descriptor(unsigned char *rdesc, int rsize)
+ 	}
+ }
+ 
++/*
++ * 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)
+ {
+@@ -965,6 +1040,14 @@ static void usbhid_fixup_macbook_descriptor(unsigned char *rdesc, int rsize)
+ 	}
+ }
+ 
++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;
++	}
++}
+ 
+ static void __usbhid_fixup_report_descriptor(__u32 quirks, char *rdesc, unsigned rsize)
+ {
+@@ -982,6 +1065,13 @@ static void __usbhid_fixup_report_descriptor(__u32 quirks, char *rdesc, unsigned
+ 
+ 	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);
++
+ }
+ 
+ /**
+diff --git a/drivers/hid/usbhid/hid-tmff.c b/drivers/hid/usbhid/hid-tmff.c
+index 69882a7..144578b 100644
+--- a/drivers/hid/usbhid/hid-tmff.c
++++ b/drivers/hid/usbhid/hid-tmff.c
+@@ -137,7 +137,8 @@ static int hid_tmff_play(struct input_dev *dev, void *data, struct ff_effect *ef
+ int hid_tmff_init(struct hid_device *hid)
+ {
+ 	struct tmff_device *tmff;
+-	struct list_head *pos;
++	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;
+@@ -149,8 +150,8 @@ int hid_tmff_init(struct hid_device *hid)
+ 		return -ENOMEM;
+ 
+ 	/* Find the report to use */
+-	list_for_each(pos, &hid->report_enum[HID_OUTPUT_REPORT].report_list) {
+-		struct hid_report *report = (struct hid_report *)pos;
++	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) {
+diff --git a/drivers/hid/usbhid/usbkbd.c b/drivers/hid/usbhid/usbkbd.c
+index 775a1ef..5d9dbb4 100644
+--- a/drivers/hid/usbhid/usbkbd.c
++++ b/drivers/hid/usbhid/usbkbd.c
+@@ -235,6 +235,14 @@ static int usb_kbd_probe(struct usb_interface *iface,
+ 	if (!usb_endpoint_is_int_in(endpoint))
+ 		return -ENODEV;
+ 
++#ifdef CONFIG_USB_HID
++	if (usbhid_lookup_quirk(le16_to_cpu(dev->descriptor.idVendor),
++				le16_to_cpu(dev->descriptor.idProduct))
++			& HID_QUIRK_IGNORE) {
++		return -ENODEV;
++	}
++#endif
 +
-+	return 0;
+ 	pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
+ 	maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
+ 
+diff --git a/drivers/hid/usbhid/usbmouse.c b/drivers/hid/usbhid/usbmouse.c
+index f8ad691..df0d96d 100644
+--- a/drivers/hid/usbhid/usbmouse.c
++++ b/drivers/hid/usbhid/usbmouse.c
+@@ -131,6 +131,14 @@ static int usb_mouse_probe(struct usb_interface *intf, const struct usb_device_i
+ 	if (!usb_endpoint_is_int_in(endpoint))
+ 		return -ENODEV;
+ 
++#ifdef CONFIG_USB_HID
++	if (usbhid_lookup_quirk(le16_to_cpu(dev->descriptor.idVendor),
++				le16_to_cpu(dev->descriptor.idProduct))
++			& (HID_QUIRK_IGNORE|HID_QUIRK_IGNORE_MOUSE)) {
++		return -ENODEV;
++	}
++#endif
++
+ 	pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
+ 	maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
+ 
+diff --git a/drivers/i2c/algos/i2c-algo-bit.c b/drivers/i2c/algos/i2c-algo-bit.c
+index a37cb6b..3581282 100644
+--- a/drivers/i2c/algos/i2c-algo-bit.c
++++ b/drivers/i2c/algos/i2c-algo-bit.c
+@@ -1,7 +1,7 @@
+-/* ------------------------------------------------------------------------- */
+-/* i2c-algo-bit.c i2c driver algorithms for bit-shift adapters		     */
+-/* ------------------------------------------------------------------------- */
+-/*   Copyright (C) 1995-2000 Simon G. Vogl
++/* -------------------------------------------------------------------------
++ * i2c-algo-bit.c i2c driver algorithms for bit-shift adapters
++ * -------------------------------------------------------------------------
++ *   Copyright (C) 1995-2000 Simon G. Vogl
+ 
+     This program is free software; you can redistribute it and/or modify
+     it under the terms of the GNU General Public License as published by
+@@ -15,8 +15,8 @@
+ 
+     You 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.		     */
+-/* ------------------------------------------------------------------------- */
++    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ * ------------------------------------------------------------------------- */
+ 
+ /* With some changes from Frodo Looijaard <frodol at dds.nl>, Kyösti Mälkki
+    <kmalkki at cc.hut.fi> and Jean Delvare <khali at linux-fr.org> */
+@@ -60,26 +60,26 @@ MODULE_PARM_DESC(i2c_debug,
+ 
+ /* --- setting states on the bus with the right timing: ---------------	*/
+ 
+-#define setsda(adap,val) adap->setsda(adap->data, val)
+-#define setscl(adap,val) adap->setscl(adap->data, val)
+-#define getsda(adap) adap->getsda(adap->data)
+-#define getscl(adap) adap->getscl(adap->data)
++#define setsda(adap, val)	adap->setsda(adap->data, val)
++#define setscl(adap, val)	adap->setscl(adap->data, val)
++#define getsda(adap)		adap->getsda(adap->data)
++#define getscl(adap)		adap->getscl(adap->data)
+ 
+ static inline void sdalo(struct i2c_algo_bit_data *adap)
+ {
+-	setsda(adap,0);
++	setsda(adap, 0);
+ 	udelay((adap->udelay + 1) / 2);
+ }
+ 
+ static inline void sdahi(struct i2c_algo_bit_data *adap)
+ {
+-	setsda(adap,1);
++	setsda(adap, 1);
+ 	udelay((adap->udelay + 1) / 2);
+ }
+ 
+ static inline void scllo(struct i2c_algo_bit_data *adap)
+ {
+-	setscl(adap,0);
++	setscl(adap, 0);
+ 	udelay(adap->udelay / 2);
+ }
+ 
+@@ -91,22 +91,21 @@ static int sclhi(struct i2c_algo_bit_data *adap)
+ {
+ 	unsigned long start;
+ 
+-	setscl(adap,1);
++	setscl(adap, 1);
+ 
+ 	/* Not all adapters have scl sense line... */
+ 	if (!adap->getscl)
+ 		goto done;
+ 
+-	start=jiffies;
+-	while (! getscl(adap) ) {	
+- 		/* the hw knows how to read the clock line,
+- 		 * so we wait until it actually gets high.
+- 		 * This is safer as some chips may hold it low
+- 		 * while they are processing data internally. 
+- 		 */
+-		if (time_after_eq(jiffies, start+adap->timeout)) {
++	start = jiffies;
++	while (!getscl(adap)) {
++		/* This hw knows how to read the clock line, so we wait
++		 * until it actually gets high.  This is safer as some
++		 * chips may hold it low ("clock stretching") while they
++		 * are processing data internally.
++		 */
++		if (time_after_eq(jiffies, start + adap->timeout))
+ 			return -ETIMEDOUT;
+-		}
+ 		cond_resched();
+ 	}
+ #ifdef DEBUG
+@@ -118,11 +117,11 @@ static int sclhi(struct i2c_algo_bit_data *adap)
+ done:
+ 	udelay(adap->udelay);
+ 	return 0;
+-} 
 +}
+ 
+ 
+ /* --- other auxiliary functions --------------------------------------	*/
+-static void i2c_start(struct i2c_algo_bit_data *adap) 
++static void i2c_start(struct i2c_algo_bit_data *adap)
+ {
+ 	/* assert: scl, sda are high */
+ 	setsda(adap, 0);
+@@ -130,7 +129,7 @@ static void i2c_start(struct i2c_algo_bit_data *adap)
+ 	scllo(adap);
+ }
+ 
+-static void i2c_repstart(struct i2c_algo_bit_data *adap) 
++static void i2c_repstart(struct i2c_algo_bit_data *adap)
+ {
+ 	/* assert: scl is low */
+ 	sdahi(adap);
+@@ -141,18 +140,18 @@ static void i2c_repstart(struct i2c_algo_bit_data *adap)
+ }
+ 
+ 
+-static void i2c_stop(struct i2c_algo_bit_data *adap) 
++static void i2c_stop(struct i2c_algo_bit_data *adap)
+ {
+ 	/* assert: scl is low */
+ 	sdalo(adap);
+-	sclhi(adap); 
++	sclhi(adap);
+ 	setsda(adap, 1);
+ 	udelay(adap->udelay);
+ }
+ 
+ 
+ 
+-/* send a byte without start cond., look for arbitration, 
++/* send a byte without start cond., look for arbitration,
+    check ackn. from slave */
+ /* returns:
+  * 1 if the device acknowledged
+@@ -167,27 +166,33 @@ static int i2c_outb(struct i2c_adapter *i2c_adap, unsigned char c)
+ 	struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
+ 
+ 	/* assert: scl is low */
+-	for ( i=7 ; i>=0 ; i-- ) {
++	for (i = 7; i >= 0; i--) {
+ 		sb = (c >> i) & 1;
+-		setsda(adap,sb);
++		setsda(adap, sb);
+ 		udelay((adap->udelay + 1) / 2);
+-		if (sclhi(adap)<0) { /* timed out */
++		if (sclhi(adap) < 0) { /* timed out */
+ 			bit_dbg(1, &i2c_adap->dev, "i2c_outb: 0x%02x, "
+ 				"timeout at bit #%d\n", (int)c, i);
+ 			return -ETIMEDOUT;
+-		};
+-		/* do arbitration here: 
+-		 * if ( sb && ! getsda(adap) ) -> ouch! Get out of here.
++		}
++		/* FIXME do arbitration here:
++		 * if (sb && !getsda(adap)) -> ouch! Get out of here.
++		 *
++		 * Report a unique code, so higher level code can retry
++		 * the whole (combined) message and *NOT* issue STOP.
+ 		 */
+ 		scllo(adap);
+ 	}
+ 	sdahi(adap);
+-	if (sclhi(adap)<0){ /* timeout */
++	if (sclhi(adap) < 0) { /* timeout */
+ 		bit_dbg(1, &i2c_adap->dev, "i2c_outb: 0x%02x, "
+ 			"timeout at ack\n", (int)c);
+ 		return -ETIMEDOUT;
+-	};
+-	/* read ack: SDA should be pulled down by slave */
++	}
 +
-+static int hifn_alg_alloc(struct hifn_device *dev, struct hifn_alg_template *t)
++	/* read ack: SDA should be pulled down by slave, or it may
++	 * NAK (usually to report problems with the data we wrote).
++	 */
+ 	ack = !getsda(adap);    /* ack: sda is pulled low -> success */
+ 	bit_dbg(2, &i2c_adap->dev, "i2c_outb: 0x%02x %s\n", (int)c,
+ 		ack ? "A" : "NA");
+@@ -198,24 +203,24 @@ static int i2c_outb(struct i2c_adapter *i2c_adap, unsigned char c)
+ }
+ 
+ 
+-static int i2c_inb(struct i2c_adapter *i2c_adap) 
++static int i2c_inb(struct i2c_adapter *i2c_adap)
+ {
+ 	/* read byte via i2c port, without start/stop sequence	*/
+ 	/* acknowledge is sent in i2c_read.			*/
+ 	int i;
+-	unsigned char indata=0;
++	unsigned char indata = 0;
+ 	struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
+ 
+ 	/* assert: scl is low */
+ 	sdahi(adap);
+-	for (i=0;i<8;i++) {
+-		if (sclhi(adap)<0) { /* timeout */
++	for (i = 0; i < 8; i++) {
++		if (sclhi(adap) < 0) { /* timeout */
+ 			bit_dbg(1, &i2c_adap->dev, "i2c_inb: timeout at bit "
+ 				"#%d\n", 7 - i);
+ 			return -ETIMEDOUT;
+-		};
++		}
+ 		indata *= 2;
+-		if ( getsda(adap) ) 
++		if (getsda(adap))
+ 			indata |= 0x01;
+ 		setscl(adap, 0);
+ 		udelay(i == 7 ? adap->udelay / 2 : adap->udelay);
+@@ -228,66 +233,67 @@ static int i2c_inb(struct i2c_adapter *i2c_adap)
+  * Sanity check for the adapter hardware - check the reaction of
+  * the bus lines only if it seems to be idle.
+  */
+-static int test_bus(struct i2c_algo_bit_data *adap, char* name) {
+-	int scl,sda;
++static int test_bus(struct i2c_algo_bit_data *adap, char *name)
 +{
-+	struct hifn_crypto_alg *alg;
-+	int err;
++	int scl, sda;
+ 
+-	if (adap->getscl==NULL)
++	if (adap->getscl == NULL)
+ 		pr_info("%s: Testing SDA only, SCL is not readable\n", name);
+ 
+-	sda=getsda(adap);
+-	scl=(adap->getscl==NULL?1:getscl(adap));
+-	if (!scl || !sda ) {
++	sda = getsda(adap);
++	scl = (adap->getscl == NULL) ? 1 : getscl(adap);
++	if (!scl || !sda) {
+ 		printk(KERN_WARNING "%s: bus seems to be busy\n", name);
+ 		goto bailout;
+ 	}
+ 
+ 	sdalo(adap);
+-	sda=getsda(adap);
+-	scl=(adap->getscl==NULL?1:getscl(adap));
+-	if ( 0 != sda ) {
++	sda = getsda(adap);
++	scl = (adap->getscl == NULL) ? 1 : getscl(adap);
++	if (sda) {
+ 		printk(KERN_WARNING "%s: SDA stuck high!\n", name);
+ 		goto bailout;
+ 	}
+-	if ( 0 == scl ) {
++	if (!scl) {
+ 		printk(KERN_WARNING "%s: SCL unexpected low "
+ 		       "while pulling SDA low!\n", name);
+ 		goto bailout;
+-	}		
++	}
+ 
+ 	sdahi(adap);
+-	sda=getsda(adap);
+-	scl=(adap->getscl==NULL?1:getscl(adap));
+-	if ( 0 == sda ) {
++	sda = getsda(adap);
++	scl = (adap->getscl == NULL) ? 1 : getscl(adap);
++	if (!sda) {
+ 		printk(KERN_WARNING "%s: SDA stuck low!\n", name);
+ 		goto bailout;
+ 	}
+-	if ( 0 == scl ) {
++	if (!scl) {
+ 		printk(KERN_WARNING "%s: SCL unexpected low "
+ 		       "while pulling SDA high!\n", name);
+ 		goto bailout;
+ 	}
+ 
+ 	scllo(adap);
+-	sda=getsda(adap);
+-	scl=(adap->getscl==NULL?0:getscl(adap));
+-	if ( 0 != scl ) {
++	sda = getsda(adap);
++	scl = (adap->getscl == NULL) ? 0 : getscl(adap);
++	if (scl) {
+ 		printk(KERN_WARNING "%s: SCL stuck high!\n", name);
+ 		goto bailout;
+ 	}
+-	if ( 0 == sda ) {
++	if (!sda) {
+ 		printk(KERN_WARNING "%s: SDA unexpected low "
+ 		       "while pulling SCL low!\n", name);
+ 		goto bailout;
+ 	}
+-	
 +
-+	alg = kzalloc(sizeof(struct hifn_crypto_alg), GFP_KERNEL);
-+	if (!alg)
-+		return -ENOMEM;
+ 	sclhi(adap);
+-	sda=getsda(adap);
+-	scl=(adap->getscl==NULL?1:getscl(adap));
+-	if ( 0 == scl ) {
++	sda = getsda(adap);
++	scl = (adap->getscl == NULL) ? 1 : getscl(adap);
++	if (!scl) {
+ 		printk(KERN_WARNING "%s: SCL stuck low!\n", name);
+ 		goto bailout;
+ 	}
+-	if ( 0 == sda ) {
++	if (!sda) {
+ 		printk(KERN_WARNING "%s: SDA unexpected low "
+ 		       "while pulling SCL high!\n", name);
+ 		goto bailout;
+@@ -314,9 +320,10 @@ static int try_address(struct i2c_adapter *i2c_adap,
+ 		       unsigned char addr, int retries)
+ {
+ 	struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
+-	int i,ret = -1;
+-	for (i=0;i<=retries;i++) {
+-		ret = i2c_outb(i2c_adap,addr);
++	int i, ret = -1;
++
++	for (i = 0; i <= retries; i++) {
++		ret = i2c_outb(i2c_adap, addr);
+ 		if (ret == 1 || i == retries)
+ 			break;
+ 		bit_dbg(3, &i2c_adap->dev, "emitting stop condition\n");
+@@ -338,20 +345,38 @@ static int sendbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
+ {
+ 	const unsigned char *temp = msg->buf;
+ 	int count = msg->len;
+-	unsigned short nak_ok = msg->flags & I2C_M_IGNORE_NAK; 
++	unsigned short nak_ok = msg->flags & I2C_M_IGNORE_NAK;
+ 	int retval;
+-	int wrcount=0;
++	int wrcount = 0;
+ 
+ 	while (count > 0) {
+ 		retval = i2c_outb(i2c_adap, *temp);
+-		if ((retval>0) || (nak_ok && (retval==0)))  { /* ok or ignored NAK */
+-			count--; 
++
++		/* OK/ACK; or ignored NAK */
++		if ((retval > 0) || (nak_ok && (retval == 0))) {
++			count--;
+ 			temp++;
+ 			wrcount++;
+-		} else { /* arbitration or no acknowledge */
+-			dev_err(&i2c_adap->dev, "sendbytes: error - bailout.\n");
+-			return (retval<0)? retval : -EFAULT;
+-			        /* got a better one ?? */
++
++		/* A slave NAKing the master means the slave didn't like
++		 * something about the data it saw.  For example, maybe
++		 * the SMBus PEC was wrong.
++		 */
++		} else if (retval == 0) {
++			dev_err(&i2c_adap->dev, "sendbytes: NAK bailout.\n");
++			return -EIO;
++
++		/* Timeout; or (someday) lost arbitration
++		 *
++		 * FIXME Lost ARB implies retrying the transaction from
++		 * the first message, after the "winning" master issues
++		 * its STOP.  As a rule, upper layer code has no reason
++		 * to know or care about this ... it is *NOT* an error.
++		 */
++		} else {
++			dev_err(&i2c_adap->dev, "sendbytes: error %d\n",
++					retval);
++			return retval;
+ 		}
+ 	}
+ 	return wrcount;
+@@ -376,14 +401,14 @@ static int acknak(struct i2c_adapter *i2c_adap, int is_ack)
+ static int readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
+ {
+ 	int inval;
+-	int rdcount=0;   	/* counts bytes read */
++	int rdcount = 0;	/* counts bytes read */
+ 	unsigned char *temp = msg->buf;
+ 	int count = msg->len;
+ 	const unsigned flags = msg->flags;
+ 
+ 	while (count > 0) {
+ 		inval = i2c_inb(i2c_adap);
+-		if (inval>=0) {
++		if (inval >= 0) {
+ 			*temp = inval;
+ 			rdcount++;
+ 		} else {   /* read timed out */
+@@ -431,7 +456,7 @@ static int readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
+  * returns:
+  *  0 everything went okay, the chip ack'ed, or IGNORE_NAK flag was set
+  * -x an error occurred (like: -EREMOTEIO if the device did not answer, or
+- *	-ETIMEDOUT, for example if the lines are stuck...) 
++ *	-ETIMEDOUT, for example if the lines are stuck...)
+  */
+ static int bit_doAddress(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
+ {
+@@ -443,10 +468,10 @@ static int bit_doAddress(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
+ 	int ret, retries;
+ 
+ 	retries = nak_ok ? 0 : i2c_adap->retries;
+-	
+-	if ( (flags & I2C_M_TEN)  ) { 
++
++	if (flags & I2C_M_TEN) {
+ 		/* a ten bit address */
+-		addr = 0xf0 | (( msg->addr >> 7) & 0x03);
++		addr = 0xf0 | ((msg->addr >> 7) & 0x03);
+ 		bit_dbg(2, &i2c_adap->dev, "addr0: %d\n", addr);
+ 		/* try extended address code...*/
+ 		ret = try_address(i2c_adap, addr, retries);
+@@ -456,33 +481,33 @@ static int bit_doAddress(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
+ 			return -EREMOTEIO;
+ 		}
+ 		/* the remaining 8 bit address */
+-		ret = i2c_outb(i2c_adap,msg->addr & 0x7f);
++		ret = i2c_outb(i2c_adap, msg->addr & 0x7f);
+ 		if ((ret != 1) && !nak_ok) {
+ 			/* the chip did not ack / xmission error occurred */
+ 			dev_err(&i2c_adap->dev, "died at 2nd address code\n");
+ 			return -EREMOTEIO;
+ 		}
+-		if ( flags & I2C_M_RD ) {
++		if (flags & I2C_M_RD) {
+ 			bit_dbg(3, &i2c_adap->dev, "emitting repeated "
+ 				"start condition\n");
+ 			i2c_repstart(adap);
+ 			/* okay, now switch into reading mode */
+ 			addr |= 0x01;
+ 			ret = try_address(i2c_adap, addr, retries);
+-			if ((ret!=1) && !nak_ok) {
++			if ((ret != 1) && !nak_ok) {
+ 				dev_err(&i2c_adap->dev,
+ 					"died at repeated address code\n");
+ 				return -EREMOTEIO;
+ 			}
+ 		}
+ 	} else {		/* normal 7bit address	*/
+-		addr = ( msg->addr << 1 );
+-		if (flags & I2C_M_RD )
++		addr = msg->addr << 1;
++		if (flags & I2C_M_RD)
+ 			addr |= 1;
+-		if (flags & I2C_M_REV_DIR_ADDR )
++		if (flags & I2C_M_REV_DIR_ADDR)
+ 			addr ^= 1;
+ 		ret = try_address(i2c_adap, addr, retries);
+-		if ((ret!=1) && !nak_ok)
++		if ((ret != 1) && !nak_ok)
+ 			return -EREMOTEIO;
+ 	}
+ 
+@@ -494,15 +519,14 @@ static int bit_xfer(struct i2c_adapter *i2c_adap,
+ {
+ 	struct i2c_msg *pmsg;
+ 	struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
+-	
+-	int i,ret;
++	int i, ret;
+ 	unsigned short nak_ok;
+ 
+ 	bit_dbg(3, &i2c_adap->dev, "emitting start condition\n");
+ 	i2c_start(adap);
+-	for (i=0;i<num;i++) {
++	for (i = 0; i < num; i++) {
+ 		pmsg = &msgs[i];
+-		nak_ok = pmsg->flags & I2C_M_IGNORE_NAK; 
++		nak_ok = pmsg->flags & I2C_M_IGNORE_NAK;
+ 		if (!(pmsg->flags & I2C_M_NOSTART)) {
+ 			if (i) {
+ 				bit_dbg(3, &i2c_adap->dev, "emitting "
+@@ -517,7 +541,7 @@ static int bit_xfer(struct i2c_adapter *i2c_adap,
+ 				goto bailout;
+ 			}
+ 		}
+-		if (pmsg->flags & I2C_M_RD ) {
++		if (pmsg->flags & I2C_M_RD) {
+ 			/* read bytes into buffer*/
+ 			ret = readbytes(i2c_adap, pmsg);
+ 			if (ret >= 1)
+@@ -551,7 +575,7 @@ bailout:
+ 
+ static u32 bit_func(struct i2c_adapter *adap)
+ {
+-	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | 
++	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL |
+ 	       I2C_FUNC_SMBUS_READ_BLOCK_DATA |
+ 	       I2C_FUNC_SMBUS_BLOCK_PROC_CALL |
+ 	       I2C_FUNC_10BIT_ADDR | I2C_FUNC_PROTOCOL_MANGLING;
+@@ -565,8 +589,8 @@ static const struct i2c_algorithm i2c_bit_algo = {
+ 	.functionality	= bit_func,
+ };
+ 
+-/* 
+- * registering functions to load algorithms at runtime 
++/*
++ * registering functions to load algorithms at runtime
+  */
+ static int i2c_bit_prepare_bus(struct i2c_adapter *adap)
+ {
+@@ -574,7 +598,7 @@ static int i2c_bit_prepare_bus(struct i2c_adapter *adap)
+ 
+ 	if (bit_test) {
+ 		int ret = test_bus(bit_adap, adap->name);
+-		if (ret<0)
++		if (ret < 0)
+ 			return -ENODEV;
+ 	}
+ 
+diff --git a/drivers/i2c/algos/i2c-algo-pcf.c b/drivers/i2c/algos/i2c-algo-pcf.c
+index ab2e6f3..8907b01 100644
+--- a/drivers/i2c/algos/i2c-algo-pcf.c
++++ b/drivers/i2c/algos/i2c-algo-pcf.c
+@@ -203,35 +203,6 @@ static int pcf_init_8584 (struct i2c_algo_pcf_data *adap)
+ /* ----- Utility functions
+  */
+ 
+-static inline int try_address(struct i2c_algo_pcf_data *adap,
+-		       unsigned char addr, int retries)
+-{
+-	int i, status, ret = -1;
+-	int wfp;
+-	for (i=0;i<retries;i++) {
+-		i2c_outb(adap, addr);
+-		i2c_start(adap);
+-		status = get_pcf(adap, 1);
+-		if ((wfp = wait_for_pin(adap, &status)) >= 0) {
+-			if ((status & I2C_PCF_LRB) == 0) { 
+-				i2c_stop(adap);
+-				break;	/* success! */
+-			}
+-		}
+-		if (wfp == -EINTR) {
+-			/* arbitration lost */
+-			udelay(adap->udelay);
+-			return -EINTR;
+-		}
+-		i2c_stop(adap);
+-		udelay(adap->udelay);
+-	}
+-	DEB2(if (i) printk(KERN_DEBUG "i2c-algo-pcf.o: needed %d retries for %d\n",i,
+-	                   addr));
+-	return ret;
+-}
+-
+-
+ static int pcf_sendbytes(struct i2c_adapter *i2c_adap, const char *buf,
+                          int count, int last)
+ {
+@@ -321,47 +292,19 @@ static int pcf_readbytes(struct i2c_adapter *i2c_adap, char *buf,
+ }
+ 
+ 
+-static inline int pcf_doAddress(struct i2c_algo_pcf_data *adap,
+-                                struct i2c_msg *msg, int retries) 
++static int pcf_doAddress(struct i2c_algo_pcf_data *adap,
++			 struct i2c_msg *msg)
+ {
+ 	unsigned short flags = msg->flags;
+ 	unsigned char addr;
+-	int ret;
+-	if ( (flags & I2C_M_TEN)  ) { 
+-		/* a ten bit address */
+-		addr = 0xf0 | (( msg->addr >> 7) & 0x03);
+-		DEB2(printk(KERN_DEBUG "addr0: %d\n",addr));
+-		/* try extended address code...*/
+-		ret = try_address(adap, addr, retries);
+-		if (ret!=1) {
+-			printk(KERN_ERR "died at extended address code.\n");
+-			return -EREMOTEIO;
+-		}
+-		/* the remaining 8 bit address */
+-		i2c_outb(adap,msg->addr & 0x7f);
+-/* Status check comes here */
+-		if (ret != 1) {
+-			printk(KERN_ERR "died at 2nd address code.\n");
+-			return -EREMOTEIO;
+-		}
+-		if ( flags & I2C_M_RD ) {
+-			i2c_repstart(adap);
+-			/* okay, now switch into reading mode */
+-			addr |= 0x01;
+-			ret = try_address(adap, addr, retries);
+-			if (ret!=1) {
+-				printk(KERN_ERR "died at extended address code.\n");
+-				return -EREMOTEIO;
+-			}
+-		}
+-	} else {		/* normal 7bit address	*/
+-		addr = ( msg->addr << 1 );
+-		if (flags & I2C_M_RD )
+-			addr |= 1;
+-		if (flags & I2C_M_REV_DIR_ADDR )
+-			addr ^= 1;
+-		i2c_outb(adap, addr);
+-	}
 +
-+	snprintf(alg->alg.cra_name, CRYPTO_MAX_ALG_NAME, "%s", t->name);
-+	snprintf(alg->alg.cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s", t->drv_name);
++	addr = msg->addr << 1;
++	if (flags & I2C_M_RD)
++		addr |= 1;
++	if (flags & I2C_M_REV_DIR_ADDR)
++		addr ^= 1;
++	i2c_outb(adap, addr);
 +
-+	alg->alg.cra_priority = 300;
-+	alg->alg.cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC;
-+	alg->alg.cra_blocksize = t->bsize;
-+	alg->alg.cra_ctxsize = sizeof(struct hifn_context);
-+	alg->alg.cra_alignmask = 15;
-+	if (t->bsize == 8)
-+		alg->alg.cra_alignmask = 3;
-+	alg->alg.cra_type = &crypto_ablkcipher_type;
-+	alg->alg.cra_module = THIS_MODULE;
-+	alg->alg.cra_u.ablkcipher = t->ablkcipher;
-+	alg->alg.cra_init = hifn_cra_init;
+ 	return 0;
+ }
+ 
+@@ -390,7 +333,7 @@ static int pcf_xfer(struct i2c_adapter *i2c_adap,
+ 		     pmsg->flags & I2C_M_RD ? "read" : "write",
+                      pmsg->len, pmsg->addr, i + 1, num);)
+     
+-		ret = pcf_doAddress(adap, pmsg, i2c_adap->retries);
++		ret = pcf_doAddress(adap, pmsg);
+ 
+ 		/* Send START */
+ 		if (i == 0) {
+@@ -453,7 +396,7 @@ static int pcf_xfer(struct i2c_adapter *i2c_adap,
+ static u32 pcf_func(struct i2c_adapter *adap)
+ {
+ 	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | 
+-	       I2C_FUNC_10BIT_ADDR | I2C_FUNC_PROTOCOL_MANGLING; 
++	       I2C_FUNC_PROTOCOL_MANGLING;
+ }
+ 
+ /* -----exported algorithm data: -------------------------------------	*/
+@@ -475,9 +418,7 @@ int i2c_pcf_add_bus(struct i2c_adapter *adap)
+ 
+ 	/* register new adapter to i2c module... */
+ 	adap->algo = &pcf_algo;
+-
+-	adap->timeout = 100;		/* default values, should	*/
+-	adap->retries = 3;		/* be replaced by defines	*/
++	adap->timeout = 100;
+ 
+ 	if ((rval = pcf_init_8584(pcf_adap)))
+ 		return rval;
+diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
+index c466c6c..b61f56b 100644
+--- a/drivers/i2c/busses/Kconfig
++++ b/drivers/i2c/busses/Kconfig
+@@ -182,7 +182,8 @@ config I2C_I801
+ 	  will be called i2c-i801.
+ 
+ config I2C_I810
+-	tristate "Intel 810/815"
++	tristate "Intel 810/815 (DEPRECATED)"
++	default n
+ 	depends on PCI
+ 	select I2C_ALGOBIT
+ 	help
+@@ -195,6 +196,8 @@ config I2C_I810
+ 	    i815
+ 	    i845G
+ 
++	  This driver is deprecated in favor of the i810fb and intelfb drivers.
 +
-+	alg->dev = dev;
+ 	  This driver can also be built as a module.  If so, the module
+ 	  will be called i2c-i810.
+ 
+@@ -259,20 +262,6 @@ config I2C_IOP3XX
+ 	  This driver can also be built as a module.  If so, the module
+ 	  will be called i2c-iop3xx.
+ 
+-config I2C_IXP4XX
+-	tristate "IXP4xx GPIO-Based I2C Interface (DEPRECATED)"
+-	depends on ARCH_IXP4XX
+-	select I2C_ALGOBIT
+-	help
+-	  Say Y here if you have an Intel IXP4xx(420,421,422,425) based 
+-	  system and are using GPIO lines for an I2C bus.
+-
+-	  This support is also available as a module. If so, the module
+-	  will be called i2c-ixp4xx.
+-
+-	  This driver is deprecated and will be dropped soon. Use i2c-gpio
+-	  instead.
+-
+ config I2C_IXP2000
+ 	tristate "IXP2000 GPIO-Based I2C Interface (DEPRECATED)"
+ 	depends on ARCH_IXP2000
+@@ -396,7 +385,8 @@ config I2C_PASEMI
+ 	  Supports the PA Semi PWRficient on-chip SMBus interfaces.
+ 
+ config I2C_PROSAVAGE
+-	tristate "S3/VIA (Pro)Savage"
++	tristate "S3/VIA (Pro)Savage (DEPRECATED)"
++	default n
+ 	depends on PCI
+ 	select I2C_ALGOBIT
+ 	help
+@@ -407,6 +397,8 @@ config I2C_PROSAVAGE
+ 	    S3/VIA KM266/VT8375 aka ProSavage8
+ 	    S3/VIA KM133/VT8365 aka Savage4
+ 
++	  This driver is deprecated in favor of the savagefb driver.
 +
-+	list_add_tail(&alg->entry, &dev->alg_list);
+ 	  This support is also available as a module.  If so, the module 
+ 	  will be called i2c-prosavage.
+ 
+@@ -418,13 +410,16 @@ config I2C_S3C2410
+ 	  Samsung S3C2410 based System-on-Chip devices.
+ 
+ config I2C_SAVAGE4
+-	tristate "S3 Savage 4"
+-	depends on PCI && EXPERIMENTAL
++	tristate "S3 Savage 4 (DEPRECATED)"
++	default n
++	depends on PCI
+ 	select I2C_ALGOBIT
+ 	help
+ 	  If you say yes to this option, support will be included for the 
+ 	  S3 Savage 4 I2C interface.
+ 
++	  This driver is deprecated in favor of the savagefb driver.
 +
-+	err = crypto_register_alg(&alg->alg);
-+	if (err) {
-+		list_del(&alg->entry);
-+		kfree(alg);
-+	}
+ 	  This driver can also be built as a module.  If so, the module
+ 	  will be called i2c-savage4.
+ 
+@@ -611,7 +606,7 @@ config I2C_VIAPRO
+ 	    VT8231
+ 	    VT8233/A
+ 	    VT8235
+-	    VT8237R/A
++	    VT8237R/A/S
+ 	    VT8251
+ 	    CX700
+ 
+@@ -648,7 +643,7 @@ config I2C_PCA_ISA
+ 
+ config I2C_MV64XXX
+ 	tristate "Marvell mv64xxx I2C Controller"
+-	depends on MV64X60 && EXPERIMENTAL
++	depends on (MV64X60 || ARCH_ORION) && EXPERIMENTAL
+ 	help
+ 	  If you say yes to this option, support will be included for the
+ 	  built-in I2C interface on the Marvell 64xxx line of host bridges.
+diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
+index 81d43c2..ea7068f 100644
+--- a/drivers/i2c/busses/Makefile
++++ b/drivers/i2c/busses/Makefile
+@@ -20,7 +20,6 @@ obj-$(CONFIG_I2C_I810)		+= i2c-i810.o
+ obj-$(CONFIG_I2C_IBM_IIC)	+= i2c-ibm_iic.o
+ obj-$(CONFIG_I2C_IOP3XX)	+= i2c-iop3xx.o
+ obj-$(CONFIG_I2C_IXP2000)	+= i2c-ixp2000.o
+-obj-$(CONFIG_I2C_IXP4XX)	+= i2c-ixp4xx.o
+ obj-$(CONFIG_I2C_POWERMAC)	+= i2c-powermac.o
+ obj-$(CONFIG_I2C_MPC)		+= i2c-mpc.o
+ obj-$(CONFIG_I2C_MV64XXX)	+= i2c-mv64xxx.o
+diff --git a/drivers/i2c/busses/i2c-amd756.c b/drivers/i2c/busses/i2c-amd756.c
+index 7490dc1..573abe4 100644
+--- a/drivers/i2c/busses/i2c-amd756.c
++++ b/drivers/i2c/busses/i2c-amd756.c
+@@ -334,6 +334,10 @@ static int __devinit amd756_probe(struct pci_dev *pdev,
+ 	int error;
+ 	u8 temp;
+ 	
++	/* driver_data might come from user-space, so check it */
++	if (id->driver_data > ARRAY_SIZE(chipname))
++		return -EINVAL;
 +
-+	return err;
-+}
+ 	if (amd756_ioport) {
+ 		dev_err(&pdev->dev, "Only one device supported "
+ 		       "(you have a strange motherboard, btw)\n");
+@@ -405,6 +409,7 @@ static struct pci_driver amd756_driver = {
+ 	.id_table	= amd756_ids,
+ 	.probe		= amd756_probe,
+ 	.remove		= __devexit_p(amd756_remove),
++	.dynids.use_driver_data = 1,
+ };
+ 
+ static int __init amd756_init(void)
+diff --git a/drivers/i2c/busses/i2c-au1550.c b/drivers/i2c/busses/i2c-au1550.c
+index 2f68416..1953b26 100644
+--- a/drivers/i2c/busses/i2c-au1550.c
++++ b/drivers/i2c/busses/i2c-au1550.c
+@@ -30,14 +30,22 @@
+ #include <linux/delay.h>
+ #include <linux/kernel.h>
+ #include <linux/module.h>
++#include <linux/platform_device.h>
+ #include <linux/init.h>
+ #include <linux/errno.h>
+ #include <linux/i2c.h>
++#include <linux/slab.h>
+ 
+ #include <asm/mach-au1x00/au1xxx.h>
+ #include <asm/mach-au1x00/au1xxx_psc.h>
+ 
+-#include "i2c-au1550.h"
++struct i2c_au1550_data {
++	u32	psc_base;
++	int	xfer_timeout;
++	int	ack_timeout;
++	struct i2c_adapter adap;
++	struct resource *ioarea;
++};
+ 
+ static int
+ wait_xfer_done(struct i2c_au1550_data *adap)
+@@ -105,7 +113,7 @@ wait_master_done(struct i2c_au1550_data *adap)
+ }
+ 
+ static int
+-do_address(struct i2c_au1550_data *adap, unsigned int addr, int rd)
++do_address(struct i2c_au1550_data *adap, unsigned int addr, int rd, int q)
+ {
+ 	volatile psc_smb_t	*sp;
+ 	u32			stat;
+@@ -134,6 +142,10 @@ do_address(struct i2c_au1550_data *adap, unsigned int addr, int rd)
+ 	if (rd)
+ 		addr |= 1;
+ 
++	/* zero-byte xfers stop immediately */
++	if (q)
++		addr |= PSC_SMBTXRX_STP;
 +
-+static void hifn_unregister_alg(struct hifn_device *dev)
-+{
-+	struct hifn_crypto_alg *a, *n;
+ 	/* Put byte into fifo, start up master.
+ 	*/
+ 	sp->psc_smbtxrx = addr;
+@@ -142,7 +154,7 @@ do_address(struct i2c_au1550_data *adap, unsigned int addr, int rd)
+ 	au_sync();
+ 	if (wait_ack(adap))
+ 		return -EIO;
+-	return 0;
++	return (q) ? wait_master_done(adap) : 0;
+ }
+ 
+ static u32
+@@ -262,7 +274,8 @@ au1550_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num)
+ 
+ 	for (i = 0; !err && i < num; i++) {
+ 		p = &msgs[i];
+-		err = do_address(adap, p->addr, p->flags & I2C_M_RD);
++		err = do_address(adap, p->addr, p->flags & I2C_M_RD,
++				 (p->len == 0));
+ 		if (err || !p->len)
+ 			continue;
+ 		if (p->flags & I2C_M_RD)
+@@ -294,18 +307,48 @@ static const struct i2c_algorithm au1550_algo = {
+  * Prior to calling us, the 50MHz clock frequency and routing
+  * must have been set up for the PSC indicated by the adapter.
+  */
+-int
+-i2c_au1550_add_bus(struct i2c_adapter *i2c_adap)
++static int __devinit
++i2c_au1550_probe(struct platform_device *pdev)
+ {
+-	struct i2c_au1550_data *adap = i2c_adap->algo_data;
+-	volatile psc_smb_t	*sp;
+-	u32	stat;
++	struct i2c_au1550_data *priv;
++	volatile psc_smb_t *sp;
++	struct resource *r;
++	u32 stat;
++	int ret;
 +
-+	list_for_each_entry_safe(a, n, &dev->alg_list, entry) {
-+		list_del(&a->entry);
-+		crypto_unregister_alg(&a->alg);
-+		kfree(a);
++	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	if (!r) {
++		ret = -ENODEV;
++		goto out;
 +	}
-+}
-+
-+static int hifn_register_alg(struct hifn_device *dev)
-+{
-+	int i, err;
 +
-+	for (i=0; i<ARRAY_SIZE(hifn_alg_templates); ++i) {
-+		err = hifn_alg_alloc(dev, &hifn_alg_templates[i]);
-+		if (err)
-+			goto err_out_exit;
++	priv = kzalloc(sizeof(struct i2c_au1550_data), GFP_KERNEL);
++	if (!priv) {
++		ret = -ENOMEM;
++		goto out;
 +	}
 +
-+	return 0;
-+
-+err_out_exit:
-+	hifn_unregister_alg(dev);
-+	return err;
-+}
-+
-+static void hifn_tasklet_callback(unsigned long data)
-+{
-+	struct hifn_device *dev = (struct hifn_device *)data;
-+
-+	/*
-+	 * This is ok to call this without lock being held,
-+	 * althogh it modifies some parameters used in parallel,
-+	 * (like dev->success), but they are used in process
-+	 * context or update is atomic (like setting dev->sa[i] to NULL).
-+	 */
-+	hifn_check_for_completion(dev, 0);
-+}
-+
-+static int hifn_probe(struct pci_dev *pdev, const struct pci_device_id *id)
-+{
-+	int err, i;
-+	struct hifn_device *dev;
-+	char name[8];
-+
-+	err = pci_enable_device(pdev);
-+	if (err)
-+		return err;
-+	pci_set_master(pdev);
-+
-+	err = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
-+	if (err)
-+		goto err_out_disable_pci_device;
-+
-+	snprintf(name, sizeof(name), "hifn%d",
-+			atomic_inc_return(&hifn_dev_number)-1);
-+
-+	err = pci_request_regions(pdev, name);
-+	if (err)
-+		goto err_out_disable_pci_device;
-+
-+	if (pci_resource_len(pdev, 0) < HIFN_BAR0_SIZE ||
-+	    pci_resource_len(pdev, 1) < HIFN_BAR1_SIZE ||
-+	    pci_resource_len(pdev, 2) < HIFN_BAR2_SIZE) {
-+		dprintk("%s: Broken hardware - I/O regions are too small.\n",
-+				pci_name(pdev));
-+		err = -ENODEV;
-+		goto err_out_free_regions;
++	priv->ioarea = request_mem_region(r->start, r->end - r->start + 1,
++					  pdev->name);
++	if (!priv->ioarea) {
++		ret = -EBUSY;
++		goto out_mem;
 +	}
+ 
+-	i2c_adap->algo = &au1550_algo;
++	priv->psc_base = r->start;
++	priv->xfer_timeout = 200;
++	priv->ack_timeout = 200;
 +
-+	dev = kzalloc(sizeof(struct hifn_device) + sizeof(struct crypto_alg),
-+			GFP_KERNEL);
-+	if (!dev) {
-+		err = -ENOMEM;
-+		goto err_out_free_regions;
++	priv->adap.id = I2C_HW_AU1550_PSC;
++	priv->adap.nr = pdev->id;
++	priv->adap.algo = &au1550_algo;
++	priv->adap.algo_data = priv;
++	priv->adap.dev.parent = &pdev->dev;
++	strlcpy(priv->adap.name, "Au1xxx PSC I2C", sizeof(priv->adap.name));
+ 
+ 	/* Now, set up the PSC for SMBus PIO mode.
+ 	*/
+-	sp = (volatile psc_smb_t *)(adap->psc_base);
++	sp = (volatile psc_smb_t *)priv->psc_base;
+ 	sp->psc_ctrl = PSC_CTRL_DISABLE;
+ 	au_sync();
+ 	sp->psc_sel = PSC_SEL_PS_SMBUSMODE;
+@@ -343,87 +386,87 @@ i2c_au1550_add_bus(struct i2c_adapter *i2c_adap)
+ 		au_sync();
+ 	} while ((stat & PSC_SMBSTAT_DR) == 0);
+ 
+-	return i2c_add_adapter(i2c_adap);
+-}
++	ret = i2c_add_numbered_adapter(&priv->adap);
++	if (ret == 0) {
++		platform_set_drvdata(pdev, priv);
++		return 0;
 +	}
+ 
++	/* disable the PSC */
++	sp->psc_smbcfg = 0;
++	sp->psc_ctrl = PSC_CTRL_DISABLE;
++	au_sync();
+ 
+-int
+-i2c_au1550_del_bus(struct i2c_adapter *adap)
++	release_resource(priv->ioarea);
++	kfree(priv->ioarea);
++out_mem:
++	kfree(priv);
++out:
++	return ret;
++}
 +
-+	INIT_LIST_HEAD(&dev->alg_list);
-+
-+	snprintf(dev->name, sizeof(dev->name), "%s", name);
-+	spin_lock_init(&dev->lock);
-+
-+	for (i=0; i<3; ++i) {
-+		unsigned long addr, size;
++static int __devexit
++i2c_au1550_remove(struct platform_device *pdev)
+ {
+-	return i2c_del_adapter(adap);
++	struct i2c_au1550_data *priv = platform_get_drvdata(pdev);
++	volatile psc_smb_t *sp = (volatile psc_smb_t *)priv->psc_base;
 +
-+		addr = pci_resource_start(pdev, i);
-+		size = pci_resource_len(pdev, i);
++	platform_set_drvdata(pdev, NULL);
++	i2c_del_adapter(&priv->adap);
++	sp->psc_smbcfg = 0;
++	sp->psc_ctrl = PSC_CTRL_DISABLE;
++	au_sync();
++	release_resource(priv->ioarea);
++	kfree(priv->ioarea);
++	kfree(priv);
++	return 0;
+ }
+ 
+ static int
+-pb1550_reg(struct i2c_client *client)
++i2c_au1550_suspend(struct platform_device *pdev, pm_message_t state)
+ {
++	struct i2c_au1550_data *priv = platform_get_drvdata(pdev);
++	volatile psc_smb_t *sp = (volatile psc_smb_t *)priv->psc_base;
 +
-+		dev->bar[i] = ioremap_nocache(addr, size);
-+		if (!dev->bar[i])
-+			goto err_out_unmap_bars;
-+	}
++	sp->psc_ctrl = PSC_CTRL_SUSPEND;
++	au_sync();
+ 	return 0;
+ }
+ 
+ static int
+-pb1550_unreg(struct i2c_client *client)
++i2c_au1550_resume(struct platform_device *pdev)
+ {
++	struct i2c_au1550_data *priv = platform_get_drvdata(pdev);
++	volatile psc_smb_t *sp = (volatile psc_smb_t *)priv->psc_base;
 +
-+	dev->result_mem = __get_free_pages(GFP_KERNEL, HIFN_MAX_RESULT_ORDER);
-+	if (!dev->result_mem) {
-+		dprintk("Failed to allocate %d pages for result_mem.\n",
-+				HIFN_MAX_RESULT_ORDER);
-+		goto err_out_unmap_bars;
-+	}
-+	memset((void *)dev->result_mem, 0, PAGE_SIZE*(1<<HIFN_MAX_RESULT_ORDER));
++	sp->psc_ctrl = PSC_CTRL_ENABLE;
++	au_sync();
++	while (!(sp->psc_smbstat & PSC_SMBSTAT_SR))
++		au_sync();
+ 	return 0;
+ }
+ 
+-static struct i2c_au1550_data pb1550_i2c_info = {
+-	SMBUS_PSC_BASE, 200, 200
+-};
+-
+-static struct i2c_adapter pb1550_board_adapter = {
+-	name:              "pb1550 adapter",
+-	id:                I2C_HW_AU1550_PSC,
+-	algo:              NULL,
+-	algo_data:         &pb1550_i2c_info,
+-	client_register:   pb1550_reg,
+-	client_unregister: pb1550_unreg,
++static struct platform_driver au1xpsc_smbus_driver = {
++	.driver = {
++		.name	= "au1xpsc_smbus",
++		.owner	= THIS_MODULE,
++	},
++	.probe		= i2c_au1550_probe,
++	.remove		= __devexit_p(i2c_au1550_remove),
++	.suspend	= i2c_au1550_suspend,
++	.resume		= i2c_au1550_resume,
+ };
+ 
+-/* BIG hack to support the control interface on the Wolfson WM8731
+- * audio codec on the Pb1550 board.  We get an address and two data
+- * bytes to write, create an i2c message, and send it across the
+- * i2c transfer function.  We do this here because we have access to
+- * the i2c adapter structure.
+- */
+-static struct i2c_msg wm_i2c_msg;  /* We don't want this stuff on the stack */
+-static	u8 i2cbuf[2];
+-
+-int
+-pb1550_wm_codec_write(u8 addr, u8 reg, u8 val)
+-{
+-	wm_i2c_msg.addr = addr;
+-	wm_i2c_msg.flags = 0;
+-	wm_i2c_msg.buf = i2cbuf;
+-	wm_i2c_msg.len = 2;
+-	i2cbuf[0] = reg;
+-	i2cbuf[1] = val;
+-
+-	return pb1550_board_adapter.algo->master_xfer(&pb1550_board_adapter, &wm_i2c_msg, 1);
+-}
+-
+ static int __init
+ i2c_au1550_init(void)
+ {
+-	printk(KERN_INFO "Au1550 I2C: ");
+-
+-	/* This is where we would set up a 50MHz clock source
+-	 * and routing.  On the Pb1550, the SMBus is PSC2, which
+-	 * uses a shared clock with USB.  This has been already
+-	 * configured by Yamon as a 48MHz clock, close enough
+-	 * for our work.
+-	 */
+-        if (i2c_au1550_add_bus(&pb1550_board_adapter) < 0) {
+-		printk("failed to initialize.\n");
+-                return -ENODEV;
+-	}
+-
+-	printk("initialized.\n");
+-	return 0;
++	return platform_driver_register(&au1xpsc_smbus_driver);
+ }
+ 
+ static void __exit
+ i2c_au1550_exit(void)
+ {
+-	i2c_au1550_del_bus(&pb1550_board_adapter);
++	platform_driver_unregister(&au1xpsc_smbus_driver);
+ }
+ 
+ MODULE_AUTHOR("Dan Malek, Embedded Edge, LLC.");
+diff --git a/drivers/i2c/busses/i2c-au1550.h b/drivers/i2c/busses/i2c-au1550.h
+deleted file mode 100644
+index fce15d1..0000000
+--- a/drivers/i2c/busses/i2c-au1550.h
++++ /dev/null
+@@ -1,32 +0,0 @@
+-/*
+- * Copyright (C) 2004 Embedded Edge, LLC <dan at embeddededge.com>
+- * 2.6 port by Matt Porter <mporter at kernel.crashing.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 I2C_AU1550_H
+-#define I2C_AU1550_H
+-
+-struct i2c_au1550_data {
+-	u32	psc_base;
+-	int	xfer_timeout;
+-	int	ack_timeout;
+-};
+-
+-int i2c_au1550_add_bus(struct i2c_adapter *);
+-int i2c_au1550_del_bus(struct i2c_adapter *);
+-
+-#endif /* I2C_AU1550_H */
+diff --git a/drivers/i2c/busses/i2c-bfin-twi.c b/drivers/i2c/busses/i2c-bfin-twi.c
+index 67224a4..7dbdaeb 100644
+--- a/drivers/i2c/busses/i2c-bfin-twi.c
++++ b/drivers/i2c/busses/i2c-bfin-twi.c
+@@ -550,6 +550,7 @@ static int i2c_bfin_twi_probe(struct platform_device *dev)
+ 
+ 	p_adap = &iface->adap;
+ 	p_adap->id = I2C_HW_BLACKFIN;
++	p_adap->nr = dev->id;
+ 	strlcpy(p_adap->name, dev->name, sizeof(p_adap->name));
+ 	p_adap->algo = &bfin_twi_algorithm;
+ 	p_adap->algo_data = iface;
+@@ -576,7 +577,7 @@ static int i2c_bfin_twi_probe(struct platform_device *dev)
+ 	bfin_write_TWI_CONTROL(bfin_read_TWI_CONTROL() | TWI_ENA);
+ 	SSYNC();
+ 
+-	rc = i2c_add_adapter(p_adap);
++	rc = i2c_add_numbered_adapter(p_adap);
+ 	if (rc < 0)
+ 		free_irq(iface->irq, iface);
+ 	else
+diff --git a/drivers/i2c/busses/i2c-davinci.c b/drivers/i2c/busses/i2c-davinci.c
+index 6767988..cce5a61 100644
+--- a/drivers/i2c/busses/i2c-davinci.c
++++ b/drivers/i2c/busses/i2c-davinci.c
+@@ -510,7 +510,6 @@ static int davinci_i2c_probe(struct platform_device *pdev)
+ 
+ 	/* FIXME */
+ 	adap->timeout = 1;
+-	adap->retries = 1;
+ 
+ 	adap->nr = pdev->id;
+ 	r = i2c_add_numbered_adapter(adap);
+diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c
+index ac27e5f..aa91579 100644
+--- a/drivers/i2c/busses/i2c-i801.c
++++ b/drivers/i2c/busses/i2c-i801.c
+@@ -4,6 +4,7 @@
+     Copyright (c) 1998 - 2002  Frodo Looijaard <frodol at dds.nl>,
+     Philip Edelbrock <phil at netroedge.com>, and Mark D. Studebaker
+     <mdsxyz123 at yahoo.com>
++    Copyright (C) 2007         Jean Delvare <khali at linux-fr.org>
+ 
+     This program is free software; you can redistribute it and/or modify
+     it under the terms of the GNU General Public License as published by
+@@ -21,25 +22,34 @@
+ */
+ 
+ /*
+-    SUPPORTED DEVICES	PCI ID
+-    82801AA		2413
+-    82801AB		2423
+-    82801BA		2443
+-    82801CA/CAM		2483
+-    82801DB		24C3   (HW PEC supported)
+-    82801EB		24D3   (HW PEC supported)
+-    6300ESB		25A4
+-    ICH6		266A
+-    ICH7		27DA
+-    ESB2		269B
+-    ICH8		283E
+-    ICH9		2930
+-    Tolapai		5032
+-    This driver supports several versions of Intel's I/O Controller Hubs (ICH).
+-    For SMBus support, they are similar to the PIIX4 and are part
+-    of Intel's '810' and other chipsets.
+-    See the file Documentation/i2c/busses/i2c-i801 for details.
+-    I2C Block Read and Process Call are not supported.
++  Supports the following Intel I/O Controller Hubs (ICH):
 +
-+	dev->dst = pci_map_single(pdev, (void *)dev->result_mem,
-+			PAGE_SIZE << HIFN_MAX_RESULT_ORDER, PCI_DMA_FROMDEVICE);
++                                  I/O                     Block   I2C
++                                  region  SMBus   Block   proc.   block
++  Chip name             PCI ID    size    PEC     buffer  call    read
++  ----------------------------------------------------------------------
++  82801AA  (ICH)        0x2413     16      no      no      no      no
++  82801AB  (ICH0)       0x2423     16      no      no      no      no
++  82801BA  (ICH2)       0x2443     16      no      no      no      no
++  82801CA  (ICH3)       0x2483     32     soft     no      no      no
++  82801DB  (ICH4)       0x24c3     32     hard     yes     no      no
++  82801E   (ICH5)       0x24d3     32     hard     yes     yes     yes
++  6300ESB               0x25a4     32     hard     yes     yes     yes
++  82801F   (ICH6)       0x266a     32     hard     yes     yes     yes
++  6310ESB/6320ESB       0x269b     32     hard     yes     yes     yes
++  82801G   (ICH7)       0x27da     32     hard     yes     yes     yes
++  82801H   (ICH8)       0x283e     32     hard     yes     yes     yes
++  82801I   (ICH9)       0x2930     32     hard     yes     yes     yes
++  Tolapai               0x5032     32     hard     yes     ?       ?
 +
-+	dev->desc_virt = pci_alloc_consistent(pdev, sizeof(struct hifn_dma),
-+			&dev->desc_dma);
-+	if (!dev->desc_virt) {
-+		dprintk("Failed to allocate descriptor rings.\n");
-+		goto err_out_free_result_pages;
-+	}
-+	memset(dev->desc_virt, 0, sizeof(struct hifn_dma));
++  Features supported by this driver:
++  Software PEC                     no
++  Hardware PEC                     yes
++  Block buffer                     yes
++  Block process call transaction   no
++  I2C block read transaction       yes  (doesn't use the block buffer)
 +
-+	dev->pdev = pdev;
-+	dev->irq = pdev->irq;
++  See the file Documentation/i2c/busses/i2c-i801 for details.
+ */
+ 
+ /* Note: we assume there can only be one I801, with one SMBus interface */
+@@ -62,9 +72,9 @@
+ #define SMBHSTDAT0	(5 + i801_smba)
+ #define SMBHSTDAT1	(6 + i801_smba)
+ #define SMBBLKDAT	(7 + i801_smba)
+-#define SMBPEC		(8 + i801_smba)	/* ICH4 only */
+-#define SMBAUXSTS	(12 + i801_smba)	/* ICH4 only */
+-#define SMBAUXCTL	(13 + i801_smba)	/* ICH4 only */
++#define SMBPEC		(8 + i801_smba)		/* ICH3 and later */
++#define SMBAUXSTS	(12 + i801_smba)	/* ICH4 and later */
++#define SMBAUXCTL	(13 + i801_smba)	/* ICH4 and later */
+ 
+ /* PCI Address Constants */
+ #define SMBBAR		4
+@@ -91,13 +101,13 @@
+ #define I801_BYTE		0x04
+ #define I801_BYTE_DATA		0x08
+ #define I801_WORD_DATA		0x0C
+-#define I801_PROC_CALL		0x10	/* later chips only, unimplemented */
++#define I801_PROC_CALL		0x10	/* unimplemented */
+ #define I801_BLOCK_DATA		0x14
+-#define I801_I2C_BLOCK_DATA	0x18	/* unimplemented */
++#define I801_I2C_BLOCK_DATA	0x18	/* ICH5 and later */
+ #define I801_BLOCK_LAST		0x34
+-#define I801_I2C_BLOCK_LAST	0x38	/* unimplemented */
++#define I801_I2C_BLOCK_LAST	0x38	/* ICH5 and later */
+ #define I801_START		0x40
+-#define I801_PEC_EN		0x80	/* ICH4 only */
++#define I801_PEC_EN		0x80	/* ICH3 and later */
+ 
+ /* I801 Hosts Status register bits */
+ #define SMBHSTSTS_BYTE_DONE	0x80
+@@ -113,7 +123,12 @@ static unsigned long i801_smba;
+ static unsigned char i801_original_hstcfg;
+ static struct pci_driver i801_driver;
+ static struct pci_dev *I801_dev;
+-static int isich4;
 +
-+	for (i=0; i<HIFN_D_RES_RSIZE; ++i)
-+		dev->sa[i] = NULL;
++#define FEATURE_SMBUS_PEC	(1 << 0)
++#define FEATURE_BLOCK_BUFFER	(1 << 1)
++#define FEATURE_BLOCK_PROC	(1 << 2)
++#define FEATURE_I2C_BLOCK_READ	(1 << 3)
++static unsigned int i801_features;
+ 
+ static int i801_transaction(int xact)
+ {
+@@ -242,7 +257,8 @@ static int i801_block_transaction_by_block(union i2c_smbus_data *data,
+ }
+ 
+ static int i801_block_transaction_byte_by_byte(union i2c_smbus_data *data,
+-					       char read_write, int hwpec)
++					       char read_write, int command,
++					       int hwpec)
+ {
+ 	int i, len;
+ 	int smbcmd;
+@@ -259,16 +275,24 @@ static int i801_block_transaction_byte_by_byte(union i2c_smbus_data *data,
+ 	}
+ 
+ 	for (i = 1; i <= len; i++) {
+-		if (i == len && read_write == I2C_SMBUS_READ)
+-			smbcmd = I801_BLOCK_LAST;
+-		else
+-			smbcmd = I801_BLOCK_DATA;
++		if (i == len && read_write == I2C_SMBUS_READ) {
++			if (command == I2C_SMBUS_I2C_BLOCK_DATA)
++				smbcmd = I801_I2C_BLOCK_LAST;
++			else
++				smbcmd = I801_BLOCK_LAST;
++		} else {
++			if (command == I2C_SMBUS_I2C_BLOCK_DATA
++			 && read_write == I2C_SMBUS_READ)
++				smbcmd = I801_I2C_BLOCK_DATA;
++			else
++				smbcmd = I801_BLOCK_DATA;
++		}
+ 		outb_p(smbcmd | ENABLE_INT9, SMBHSTCNT);
+ 
+ 		dev_dbg(&I801_dev->dev, "Block (pre %d): CNT=%02x, CMD=%02x, "
+-			"ADD=%02x, DAT0=%02x, BLKDAT=%02x\n", i,
++			"ADD=%02x, DAT0=%02x, DAT1=%02x, BLKDAT=%02x\n", i,
+ 			inb_p(SMBHSTCNT), inb_p(SMBHSTCMD), inb_p(SMBHSTADD),
+-			inb_p(SMBHSTDAT0), inb_p(SMBBLKDAT));
++			inb_p(SMBHSTDAT0), inb_p(SMBHSTDAT1), inb_p(SMBBLKDAT));
+ 
+ 		/* Make sure the SMBus host is ready to start transmitting */
+ 		temp = inb_p(SMBHSTSTS);
+@@ -332,7 +356,8 @@ static int i801_block_transaction_byte_by_byte(union i2c_smbus_data *data,
+ 			dev_dbg(&I801_dev->dev, "Error: no response!\n");
+ 		}
+ 
+-		if (i == 1 && read_write == I2C_SMBUS_READ) {
++		if (i == 1 && read_write == I2C_SMBUS_READ
++		 && command != I2C_SMBUS_I2C_BLOCK_DATA) {
+ 			len = inb_p(SMBHSTDAT0);
+ 			if (len < 1 || len > I2C_SMBUS_BLOCK_MAX)
+ 				return -1;
+@@ -353,9 +378,9 @@ static int i801_block_transaction_byte_by_byte(union i2c_smbus_data *data,
+ 				temp);
+ 		}
+ 		dev_dbg(&I801_dev->dev, "Block (post %d): CNT=%02x, CMD=%02x, "
+-			"ADD=%02x, DAT0=%02x, BLKDAT=%02x\n", i,
++			"ADD=%02x, DAT0=%02x, DAT1=%02x, BLKDAT=%02x\n", i,
+ 			inb_p(SMBHSTCNT), inb_p(SMBHSTCMD), inb_p(SMBHSTADD),
+-			inb_p(SMBHSTDAT0), inb_p(SMBBLKDAT));
++			inb_p(SMBHSTDAT0), inb_p(SMBHSTDAT1), inb_p(SMBBLKDAT));
+ 
+ 		if (result < 0)
+ 			return result;
+@@ -384,33 +409,38 @@ static int i801_block_transaction(union i2c_smbus_data *data, char read_write,
+ 			pci_read_config_byte(I801_dev, SMBHSTCFG, &hostc);
+ 			pci_write_config_byte(I801_dev, SMBHSTCFG,
+ 					      hostc | SMBHSTCFG_I2C_EN);
+-		} else {
++		} else if (!(i801_features & FEATURE_I2C_BLOCK_READ)) {
+ 			dev_err(&I801_dev->dev,
+-				"I2C_SMBUS_I2C_BLOCK_READ not DB!\n");
++				"I2C block read is unsupported!\n");
+ 			return -1;
+ 		}
+ 	}
+ 
+-	if (read_write == I2C_SMBUS_WRITE) {
++	if (read_write == I2C_SMBUS_WRITE
++	 || command == I2C_SMBUS_I2C_BLOCK_DATA) {
+ 		if (data->block[0] < 1)
+ 			data->block[0] = 1;
+ 		if (data->block[0] > I2C_SMBUS_BLOCK_MAX)
+ 			data->block[0] = I2C_SMBUS_BLOCK_MAX;
+ 	} else {
+-		data->block[0] = 32;	/* max for reads */
++		data->block[0] = 32;	/* max for SMBus block reads */
+ 	}
+ 
+-	if (isich4 && i801_set_block_buffer_mode() == 0 )
++	if ((i801_features & FEATURE_BLOCK_BUFFER)
++	 && !(command == I2C_SMBUS_I2C_BLOCK_DATA
++	      && read_write == I2C_SMBUS_READ)
++	 && i801_set_block_buffer_mode() == 0)
+ 		result = i801_block_transaction_by_block(data, read_write,
+ 							 hwpec);
+ 	else
+ 		result = i801_block_transaction_byte_by_byte(data, read_write,
+-							     hwpec);
++							     command, hwpec);
+ 
+ 	if (result == 0 && hwpec)
+ 		i801_wait_hwpec();
+ 
+-	if (command == I2C_SMBUS_I2C_BLOCK_DATA) {
++	if (command == I2C_SMBUS_I2C_BLOCK_DATA
++	 && read_write == I2C_SMBUS_WRITE) {
+ 		/* restore saved configuration register value */
+ 		pci_write_config_byte(I801_dev, SMBHSTCFG, hostc);
+ 	}
+@@ -426,7 +456,7 @@ static s32 i801_access(struct i2c_adapter * adap, u16 addr,
+ 	int block = 0;
+ 	int ret, xact = 0;
+ 
+-	hwpec = isich4 && (flags & I2C_CLIENT_PEC)
++	hwpec = (i801_features & FEATURE_SMBUS_PEC) && (flags & I2C_CLIENT_PEC)
+ 		&& size != I2C_SMBUS_QUICK
+ 		&& size != I2C_SMBUS_I2C_BLOCK_DATA;
+ 
+@@ -462,12 +492,23 @@ static s32 i801_access(struct i2c_adapter * adap, u16 addr,
+ 		xact = I801_WORD_DATA;
+ 		break;
+ 	case I2C_SMBUS_BLOCK_DATA:
+-	case I2C_SMBUS_I2C_BLOCK_DATA:
+ 		outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
+ 		       SMBHSTADD);
+ 		outb_p(command, SMBHSTCMD);
+ 		block = 1;
+ 		break;
++	case I2C_SMBUS_I2C_BLOCK_DATA:
++		/* NB: page 240 of ICH5 datasheet shows that the R/#W
++		 * bit should be cleared here, even when reading */
++		outb_p((addr & 0x7f) << 1, SMBHSTADD);
++		if (read_write == I2C_SMBUS_READ) {
++			/* NB: page 240 of ICH5 datasheet also shows
++			 * that DATA1 is the cmd field when reading */
++			outb_p(command, SMBHSTDAT1);
++		} else
++			outb_p(command, SMBHSTCMD);
++		block = 1;
++		break;
+ 	case I2C_SMBUS_PROC_CALL:
+ 	default:
+ 		dev_err(&I801_dev->dev, "Unsupported transaction %d\n", size);
+@@ -487,7 +528,7 @@ static s32 i801_access(struct i2c_adapter * adap, u16 addr,
+ 	/* Some BIOSes don't like it when PEC is enabled at reboot or resume
+ 	   time, so we forcibly disable it after every transaction. Turn off
+ 	   E32B for the same reason. */
+-	if (hwpec)
++	if (hwpec || block)
+ 		outb_p(inb_p(SMBAUXCTL) & ~(SMBAUXCTL_CRC | SMBAUXCTL_E32B),
+ 		       SMBAUXCTL);
+ 
+@@ -514,9 +555,11 @@ static s32 i801_access(struct i2c_adapter * adap, u16 addr,
+ static u32 i801_func(struct i2c_adapter *adapter)
+ {
+ 	return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
+-	    I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
+-	    I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_WRITE_I2C_BLOCK
+-	     | (isich4 ? I2C_FUNC_SMBUS_PEC : 0);
++	       I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
++	       I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_WRITE_I2C_BLOCK |
++	       ((i801_features & FEATURE_SMBUS_PEC) ? I2C_FUNC_SMBUS_PEC : 0) |
++	       ((i801_features & FEATURE_I2C_BLOCK_READ) ?
++		I2C_FUNC_SMBUS_READ_I2C_BLOCK : 0);
+ }
+ 
+ static const struct i2c_algorithm smbus_algorithm = {
+@@ -556,8 +599,8 @@ static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id
+ 	int err;
+ 
+ 	I801_dev = dev;
++	i801_features = 0;
+ 	switch (dev->device) {
+-	case PCI_DEVICE_ID_INTEL_82801DB_3:
+ 	case PCI_DEVICE_ID_INTEL_82801EB_3:
+ 	case PCI_DEVICE_ID_INTEL_ESB_4:
+ 	case PCI_DEVICE_ID_INTEL_ICH6_16:
+@@ -565,11 +608,13 @@ static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id
+ 	case PCI_DEVICE_ID_INTEL_ESB2_17:
+ 	case PCI_DEVICE_ID_INTEL_ICH8_5:
+ 	case PCI_DEVICE_ID_INTEL_ICH9_6:
++		i801_features |= FEATURE_I2C_BLOCK_READ;
++		/* fall through */
++	case PCI_DEVICE_ID_INTEL_82801DB_3:
+ 	case PCI_DEVICE_ID_INTEL_TOLAPAI_1:
+-		isich4 = 1;
++		i801_features |= FEATURE_SMBUS_PEC;
++		i801_features |= FEATURE_BLOCK_BUFFER;
+ 		break;
+-	default:
+-		isich4 = 0;
+ 	}
+ 
+ 	err = pci_enable_device(dev);
+@@ -610,6 +655,11 @@ static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id
+ 	else
+ 		dev_dbg(&dev->dev, "SMBus using PCI Interrupt\n");
+ 
++	/* Clear special mode bits */
++	if (i801_features & (FEATURE_SMBUS_PEC | FEATURE_BLOCK_BUFFER))
++		outb_p(inb_p(SMBAUXCTL) & ~(SMBAUXCTL_CRC | SMBAUXCTL_E32B),
++		       SMBAUXCTL);
 +
-+	pci_set_drvdata(pdev, dev);
+ 	/* set up the sysfs linkage to our parent device */
+ 	i801_adapter.dev.parent = &dev->dev;
+ 
+@@ -678,9 +728,8 @@ static void __exit i2c_i801_exit(void)
+ 	pci_unregister_driver(&i801_driver);
+ }
+ 
+-MODULE_AUTHOR ("Frodo Looijaard <frodol at dds.nl>, "
+-		"Philip Edelbrock <phil at netroedge.com>, "
+-		"and Mark D. Studebaker <mdsxyz123 at yahoo.com>");
++MODULE_AUTHOR("Mark D. Studebaker <mdsxyz123 at yahoo.com>, "
++	      "Jean Delvare <khali at linux-fr.org>");
+ MODULE_DESCRIPTION("I801 SMBus driver");
+ MODULE_LICENSE("GPL");
+ 
+diff --git a/drivers/i2c/busses/i2c-ibm_iic.c b/drivers/i2c/busses/i2c-ibm_iic.c
+index 9b43ff7..7c7eb0c 100644
+--- a/drivers/i2c/busses/i2c-ibm_iic.c
++++ b/drivers/i2c/busses/i2c-ibm_iic.c
+@@ -6,7 +6,7 @@
+  * Copyright (c) 2003, 2004 Zultys Technologies.
+  * Eugene Surovegin <eugene.surovegin at zultys.com> or <ebs at ebshome.net>
+  *
+- * Based on original work by 
++ * Based on original work by
+  * 	Ian DaSilva  <idasilva at mvista.com>
+  *      Armin Kuster <akuster at mvista.com>
+  * 	Matt Porter  <mporter at mvista.com>
+@@ -86,8 +86,8 @@ static void dump_iic_regs(const char* header, struct ibm_iic_private* dev)
+ 	       KERN_DEBUG "  sts      = 0x%02x, extsts = 0x%02x\n"
+ 	       KERN_DEBUG "  clkdiv   = 0x%02x, xfrcnt = 0x%02x\n"
+ 	       KERN_DEBUG "  xtcntlss = 0x%02x, directcntl = 0x%02x\n",
+-		in_8(&iic->cntl), in_8(&iic->mdcntl), in_8(&iic->sts), 
+-		in_8(&iic->extsts), in_8(&iic->clkdiv), in_8(&iic->xfrcnt), 
++		in_8(&iic->cntl), in_8(&iic->mdcntl), in_8(&iic->sts),
++		in_8(&iic->extsts), in_8(&iic->clkdiv), in_8(&iic->xfrcnt),
+ 		in_8(&iic->xtcntlss), in_8(&iic->directcntl));
+ }
+ #  define DUMP_REGS(h,dev)	dump_iic_regs((h),(dev))
+@@ -125,7 +125,7 @@ static inline void iic_interrupt_mode(struct ibm_iic_private* dev, int enable)
+ {
+ 	out_8(&dev->vaddr->intmsk, enable ? INTRMSK_EIMTC : 0);
+ }
+- 
 +
-+	tasklet_init(&dev->tasklet, hifn_tasklet_callback, (unsigned long)dev);
+ /*
+  * Initialize IIC interface.
+  */
+@@ -134,7 +134,7 @@ static void iic_dev_init(struct ibm_iic_private* dev)
+ 	volatile struct iic_regs __iomem *iic = dev->vaddr;
+ 
+ 	DBG("%d: init\n", dev->idx);
+-	
 +
-+	crypto_init_queue(&dev->queue, 1);
+ 	/* Clear master address */
+ 	out_8(&iic->lmadr, 0);
+ 	out_8(&iic->hmadr, 0);
+@@ -160,7 +160,7 @@ static void iic_dev_init(struct ibm_iic_private* dev)
+ 
+ 	/* Clear control register */
+ 	out_8(&iic->cntl, 0);
+-	
 +
-+	err = request_irq(dev->irq, hifn_interrupt, IRQF_SHARED, dev->name, dev);
-+	if (err) {
-+		dprintk("Failed to request IRQ%d: err: %d.\n", dev->irq, err);
-+		dev->irq = 0;
-+		goto err_out_free_desc;
-+	}
+ 	/* Enable interrupts if possible */
+ 	iic_interrupt_mode(dev, dev->irq >= 0);
+ 
+@@ -171,7 +171,7 @@ static void iic_dev_init(struct ibm_iic_private* dev)
+ 	DUMP_REGS("iic_init", dev);
+ }
+ 
+-/* 
++/*
+  * Reset IIC interface
+  */
+ static void iic_dev_reset(struct ibm_iic_private* dev)
+@@ -179,42 +179,42 @@ static void iic_dev_reset(struct ibm_iic_private* dev)
+ 	volatile struct iic_regs __iomem *iic = dev->vaddr;
+ 	int i;
+ 	u8 dc;
+-	
 +
-+	err = hifn_start_device(dev);
-+	if (err)
-+		goto err_out_free_irq;
+ 	DBG("%d: soft reset\n", dev->idx);
+ 	DUMP_REGS("reset", dev);
+-	
 +
-+	err = hifn_test(dev, 1, 0);
-+	if (err)
-+		goto err_out_stop_device;
+     	/* Place chip in the reset state */
+ 	out_8(&iic->xtcntlss, XTCNTLSS_SRST);
+-	
 +
-+	err = hifn_register_rng(dev);
-+	if (err)
-+		goto err_out_stop_device;
+ 	/* Check if bus is free */
+-	dc = in_8(&iic->directcntl);	
++	dc = in_8(&iic->directcntl);
+ 	if (!DIRCTNL_FREE(dc)){
+ 		DBG("%d: trying to regain bus control\n", dev->idx);
+-	
 +
-+	err = hifn_register_alg(dev);
-+	if (err)
-+		goto err_out_unregister_rng;
+ 		/* Try to set bus free state */
+-		out_8(&iic->directcntl, DIRCNTL_SDAC | DIRCNTL_SCC);	
+-	
++		out_8(&iic->directcntl, DIRCNTL_SDAC | DIRCNTL_SCC);
 +
-+	INIT_DELAYED_WORK(&dev->work, hifn_work);
-+	schedule_delayed_work(&dev->work, HZ);
+ 		/* Wait until we regain bus control */
+ 		for (i = 0; i < 100; ++i){
+ 			dc = in_8(&iic->directcntl);
+ 			if (DIRCTNL_FREE(dc))
+ 				break;
+-			
 +
-+	dprintk("HIFN crypto accelerator card at %s has been "
-+			"successfully registered as %s.\n",
-+			pci_name(pdev), dev->name);
+ 			/* Toggle SCL line */
+ 			dc ^= DIRCNTL_SCC;
+ 			out_8(&iic->directcntl, dc);
+ 			udelay(10);
+ 			dc ^= DIRCNTL_SCC;
+ 			out_8(&iic->directcntl, dc);
+-			
 +
-+	return 0;
+ 			/* be nice */
+ 			cond_resched();
+ 		}
+ 	}
+-	
 +
-+err_out_unregister_rng:
-+	hifn_unregister_rng(dev);
-+err_out_stop_device:
-+	hifn_reset_dma(dev, 1);
-+	hifn_stop_device(dev);
-+err_out_free_irq:
-+	free_irq(dev->irq, dev->name);
-+	tasklet_kill(&dev->tasklet);
-+err_out_free_desc:
-+	pci_free_consistent(pdev, sizeof(struct hifn_dma),
-+			dev->desc_virt, dev->desc_dma);
+ 	/* Remove reset */
+ 	out_8(&iic->xtcntlss, 0);
+-	
 +
-+err_out_free_result_pages:
-+	pci_unmap_single(pdev, dev->dst, PAGE_SIZE << HIFN_MAX_RESULT_ORDER,
-+			PCI_DMA_FROMDEVICE);
-+	free_pages(dev->result_mem, HIFN_MAX_RESULT_ORDER);
+ 	/* Reinitialize interface */
+ 	iic_dev_init(dev);
+ }
+@@ -324,14 +324,14 @@ static irqreturn_t iic_handler(int irq, void *dev_id)
+ {
+ 	struct ibm_iic_private* dev = (struct ibm_iic_private*)dev_id;
+ 	volatile struct iic_regs __iomem *iic = dev->vaddr;
+-	
+-	DBG2("%d: irq handler, STS = 0x%02x, EXTSTS = 0x%02x\n", 
 +
-+err_out_unmap_bars:
-+	for (i=0; i<3; ++i)
-+		if (dev->bar[i])
-+			iounmap(dev->bar[i]);
++	DBG2("%d: irq handler, STS = 0x%02x, EXTSTS = 0x%02x\n",
+ 	     dev->idx, in_8(&iic->sts), in_8(&iic->extsts));
+-	
 +
-+err_out_free_regions:
-+	pci_release_regions(pdev);
+ 	/* Acknowledge IRQ and wakeup iic_wait_for_tc */
+ 	out_8(&iic->sts, STS_IRQA | STS_SCMP);
+ 	wake_up_interruptible(&dev->wq);
+-	
 +
-+err_out_disable_pci_device:
-+	pci_disable_device(pdev);
+ 	return IRQ_HANDLED;
+ }
+ 
+@@ -341,19 +341,19 @@ static irqreturn_t iic_handler(int irq, void *dev_id)
+  */
+ static int iic_xfer_result(struct ibm_iic_private* dev)
+ {
+-	volatile struct iic_regs __iomem *iic = dev->vaddr;	
+-	
++	volatile struct iic_regs __iomem *iic = dev->vaddr;
 +
-+	return err;
-+}
+ 	if (unlikely(in_8(&iic->sts) & STS_ERR)){
+-		DBG("%d: xfer error, EXTSTS = 0x%02x\n", dev->idx, 
++		DBG("%d: xfer error, EXTSTS = 0x%02x\n", dev->idx,
+ 			in_8(&iic->extsts));
+-				
 +
-+static void hifn_remove(struct pci_dev *pdev)
-+{
-+	int i;
-+	struct hifn_device *dev;
+ 		/* Clear errors and possible pending IRQs */
+-		out_8(&iic->extsts, EXTSTS_IRQP | EXTSTS_IRQD | 
++		out_8(&iic->extsts, EXTSTS_IRQP | EXTSTS_IRQD |
+ 			EXTSTS_LA | EXTSTS_ICT | EXTSTS_XFRA);
+-			
 +
-+	dev = pci_get_drvdata(pdev);
+ 		/* Flush master data buffer */
+ 		out_8(&iic->mdcntl, in_8(&iic->mdcntl) | MDCNTL_FMDB);
+-		
 +
-+	if (dev) {
-+		cancel_delayed_work(&dev->work);
-+		flush_scheduled_work();
+ 		/* Is bus free?
+ 		 * If error happened during combined xfer
+ 		 * IIC interface is usually stuck in some strange
+@@ -376,11 +376,11 @@ static void iic_abort_xfer(struct ibm_iic_private* dev)
+ {
+ 	volatile struct iic_regs __iomem *iic = dev->vaddr;
+ 	unsigned long x;
+-	
 +
-+		hifn_unregister_rng(dev);
-+		hifn_unregister_alg(dev);
-+		hifn_reset_dma(dev, 1);
-+		hifn_stop_device(dev);
+ 	DBG("%d: iic_abort_xfer\n", dev->idx);
+-	
 +
-+		free_irq(dev->irq, dev->name);
-+		tasklet_kill(&dev->tasklet);
+ 	out_8(&iic->cntl, CNTL_HMT);
+-	
 +
-+		hifn_flush(dev);
+ 	/*
+ 	 * Wait for the abort command to complete.
+ 	 * It's not worth to be optimized, just poll (timeout >= 1 tick)
+@@ -405,13 +405,13 @@ static void iic_abort_xfer(struct ibm_iic_private* dev)
+  * Returns the number of transferred bytes or error (<0)
+  */
+ static int iic_wait_for_tc(struct ibm_iic_private* dev){
+-	
 +
-+		pci_free_consistent(pdev, sizeof(struct hifn_dma),
-+				dev->desc_virt, dev->desc_dma);
-+		pci_unmap_single(pdev, dev->dst,
-+				PAGE_SIZE << HIFN_MAX_RESULT_ORDER,
-+				PCI_DMA_FROMDEVICE);
-+		free_pages(dev->result_mem, HIFN_MAX_RESULT_ORDER);
-+		for (i=0; i<3; ++i)
-+			if (dev->bar[i])
-+				iounmap(dev->bar[i]);
+ 	volatile struct iic_regs __iomem *iic = dev->vaddr;
+ 	int ret = 0;
+-	
 +
-+		kfree(dev);
-+	}
+ 	if (dev->irq >= 0){
+ 		/* Interrupt mode */
+-		ret = wait_event_interruptible_timeout(dev->wq, 
++		ret = wait_event_interruptible_timeout(dev->wq,
+ 			!(in_8(&iic->sts) & STS_PT), dev->adap.timeout * HZ);
+ 
+ 		if (unlikely(ret < 0))
+@@ -424,37 +424,37 @@ static int iic_wait_for_tc(struct ibm_iic_private* dev){
+ 	else {
+ 		/* Polling mode */
+ 		unsigned long x = jiffies + dev->adap.timeout * HZ;
+-		
 +
-+	pci_release_regions(pdev);
-+	pci_disable_device(pdev);
-+}
+ 		while (in_8(&iic->sts) & STS_PT){
+ 			if (unlikely(time_after(jiffies, x))){
+ 				DBG("%d: poll timeout\n", dev->idx);
+ 				ret = -ETIMEDOUT;
+ 				break;
+ 			}
+-		
 +
-+static struct pci_device_id hifn_pci_tbl[] = {
-+	{ PCI_DEVICE(PCI_VENDOR_ID_HIFN, PCI_DEVICE_ID_HIFN_7955) },
-+	{ PCI_DEVICE(PCI_VENDOR_ID_HIFN, PCI_DEVICE_ID_HIFN_7956) },
-+	{ 0 }
-+};
-+MODULE_DEVICE_TABLE(pci, hifn_pci_tbl);
+ 			if (unlikely(signal_pending(current))){
+ 				DBG("%d: poll interrupted\n", dev->idx);
+ 				ret = -ERESTARTSYS;
+ 				break;
+ 			}
+ 			schedule();
+-		}	
++		}
+ 	}
+-	
 +
-+static struct pci_driver hifn_pci_driver = {
-+	.name     = "hifn795x",
-+	.id_table = hifn_pci_tbl,
-+	.probe    = hifn_probe,
-+	.remove   = __devexit_p(hifn_remove),
-+};
+ 	if (unlikely(ret < 0))
+ 		iic_abort_xfer(dev);
+ 	else
+ 		ret = iic_xfer_result(dev);
+-	
 +
-+static int __devinit hifn_init(void)
-+{
-+	unsigned int freq;
-+	int err;
+ 	DBG2("%d: iic_wait_for_tc -> %d\n", dev->idx, ret);
+-	
 +
-+	if (strncmp(hifn_pll_ref, "ext", 3) &&
-+	    strncmp(hifn_pll_ref, "pci", 3)) {
-+		printk(KERN_ERR "hifn795x: invalid hifn_pll_ref clock, "
-+				"must be pci or ext");
-+		return -EINVAL;
-+	}
+ 	return ret;
+ }
+ 
+ /*
+  * Low level master transfer routine
+  */
+-static int iic_xfer_bytes(struct ibm_iic_private* dev, struct i2c_msg* pm, 
++static int iic_xfer_bytes(struct ibm_iic_private* dev, struct i2c_msg* pm,
+ 			  int combined_xfer)
+ {
+ 	volatile struct iic_regs __iomem *iic = dev->vaddr;
+@@ -465,48 +465,48 @@ static int iic_xfer_bytes(struct ibm_iic_private* dev, struct i2c_msg* pm,
+ 	u8 cntl = (in_8(&iic->cntl) & CNTL_AMD) | CNTL_PT;
+ 	if (pm->flags & I2C_M_RD)
+ 		cntl |= CNTL_RW;
+-	
 +
-+	/*
-+	 * For the 7955/7956 the reference clock frequency must be in the
-+	 * range of 20MHz-100MHz. For the 7954 the upper bound is 66.67MHz,
-+	 * but this chip is currently not supported.
-+	 */
-+	if (hifn_pll_ref[3] != '\0') {
-+		freq = simple_strtoul(hifn_pll_ref + 3, NULL, 10);
-+		if (freq < 20 || freq > 100) {
-+			printk(KERN_ERR "hifn795x: invalid hifn_pll_ref "
-+					"frequency, must be in the range "
-+					"of 20-100");
-+			return -EINVAL;
-+		}
-+	}
+ 	loops = (len + 3) / 4;
+ 	for (i = 0; i < loops; ++i, len -= 4){
+ 		int count = len > 4 ? 4 : len;
+ 		u8 cmd = cntl | ((count - 1) << CNTL_TCT_SHIFT);
+-		
 +
-+	err = pci_register_driver(&hifn_pci_driver);
-+	if (err < 0) {
-+		dprintk("Failed to register PCI driver for %s device.\n",
-+				hifn_pci_driver.name);
-+		return -ENODEV;
-+	}
+ 		if (!(cntl & CNTL_RW))
+ 			for (j = 0; j < count; ++j)
+ 				out_8((void __iomem *)&iic->mdbuf, *buf++);
+-		
 +
-+	printk(KERN_INFO "Driver for HIFN 795x crypto accelerator chip "
-+			"has been successfully registered.\n");
+ 		if (i < loops - 1)
+ 			cmd |= CNTL_CHT;
+ 		else if (combined_xfer)
+ 			cmd |= CNTL_RPST;
+-		
 +
-+	return 0;
-+}
+ 		DBG2("%d: xfer_bytes, %d, CNTL = 0x%02x\n", dev->idx, count, cmd);
+-		
 +
-+static void __devexit hifn_fini(void)
-+{
-+	pci_unregister_driver(&hifn_pci_driver);
+ 		/* Start transfer */
+ 		out_8(&iic->cntl, cmd);
+-		
 +
-+	printk(KERN_INFO "Driver for HIFN 795x crypto accelerator chip "
-+			"has been successfully unregistered.\n");
-+}
+ 		/* Wait for completion */
+ 		ret = iic_wait_for_tc(dev);
+ 
+ 		if (unlikely(ret < 0))
+ 			break;
+ 		else if (unlikely(ret != count)){
+-			DBG("%d: xfer_bytes, requested %d, transfered %d\n", 
++			DBG("%d: xfer_bytes, requested %d, transfered %d\n",
+ 				dev->idx, count, ret);
+-			
 +
-+module_init(hifn_init);
-+module_exit(hifn_fini);
+ 			/* If it's not a last part of xfer, abort it */
+ 			if (combined_xfer || (i < loops - 1))
+     				iic_abort_xfer(dev);
+-				
 +
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Evgeniy Polyakov <johnpol at 2ka.mipt.ru>");
-+MODULE_DESCRIPTION("Driver for HIFN 795x crypto accelerator chip.");
-diff --git a/drivers/crypto/padlock-aes.c b/drivers/crypto/padlock-aes.c
-index 5f7e718..2f3ad3f 100644
---- a/drivers/crypto/padlock-aes.c
-+++ b/drivers/crypto/padlock-aes.c
-@@ -44,6 +44,7 @@
-  */
- 
- #include <crypto/algapi.h>
-+#include <crypto/aes.h>
- #include <linux/module.h>
- #include <linux/init.h>
- #include <linux/types.h>
-@@ -53,9 +54,6 @@
- #include <asm/byteorder.h>
- #include "padlock.h"
- 
--#define AES_MIN_KEY_SIZE	16	/* in uint8_t units */
--#define AES_MAX_KEY_SIZE	32	/* ditto */
--#define AES_BLOCK_SIZE		16	/* ditto */
- #define AES_EXTENDED_KEY_SIZE	64	/* in uint32_t units */
- #define AES_EXTENDED_KEY_SIZE_B	(AES_EXTENDED_KEY_SIZE * sizeof(uint32_t))
- 
-@@ -419,6 +417,11 @@ static int aes_set_key(struct crypto_tfm *tfm, const u8 *in_key,
- /* ====== Encryption/decryption routines ====== */
- 
- /* These are the real call to PadLock. */
-+static inline void padlock_reset_key(void)
-+{
-+	asm volatile ("pushfl; popfl");
-+}
+ 			ret = -EREMOTEIO;
+-			break;				
++			break;
+ 		}
+-		
 +
- static inline void padlock_xcrypt(const u8 *input, u8 *output, void *key,
- 				  void *control_word)
- {
-@@ -439,8 +442,6 @@ static void aes_crypt_copy(const u8 *in, u8 *out, u32 *key, struct cword *cword)
- static inline void aes_crypt(const u8 *in, u8 *out, u32 *key,
- 			     struct cword *cword)
- {
--	asm volatile ("pushfl; popfl");
--
- 	/* padlock_xcrypt requires at least two blocks of data. */
- 	if (unlikely(!(((unsigned long)in ^ (PAGE_SIZE - AES_BLOCK_SIZE)) &
- 		       (PAGE_SIZE - 1)))) {
-@@ -459,7 +460,6 @@ static inline void padlock_xcrypt_ecb(const u8 *input, u8 *output, void *key,
- 		return;
+ 		if (cntl & CNTL_RW)
+ 			for (j = 0; j < count; ++j)
+ 				*buf++ = in_8((void __iomem *)&iic->mdbuf);
  	}
- 
--	asm volatile ("pushfl; popfl");		/* enforce key reload. */
- 	asm volatile ("test $1, %%cl;"
- 		      "je 1f;"
- 		      "lea -1(%%ecx), %%eax;"
-@@ -476,8 +476,6 @@ static inline void padlock_xcrypt_ecb(const u8 *input, u8 *output, void *key,
- static inline u8 *padlock_xcrypt_cbc(const u8 *input, u8 *output, void *key,
- 				     u8 *iv, void *control_word, u32 count)
- {
--	/* Enforce key reload. */
--	asm volatile ("pushfl; popfl");
- 	/* rep xcryptcbc */
- 	asm volatile (".byte 0xf3,0x0f,0xa7,0xd0"
- 		      : "+S" (input), "+D" (output), "+a" (iv)
-@@ -488,12 +486,14 @@ static inline u8 *padlock_xcrypt_cbc(const u8 *input, u8 *output, void *key,
- static void aes_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
- {
- 	struct aes_ctx *ctx = aes_ctx(tfm);
-+	padlock_reset_key();
- 	aes_crypt(in, out, ctx->E, &ctx->cword.encrypt);
+-	
++
+ 	return ret > 0 ? 0 : ret;
  }
  
- static void aes_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
+@@ -517,10 +517,10 @@ static inline void iic_address(struct ibm_iic_private* dev, struct i2c_msg* msg)
  {
- 	struct aes_ctx *ctx = aes_ctx(tfm);
-+	padlock_reset_key();
- 	aes_crypt(in, out, ctx->D, &ctx->cword.decrypt);
- }
- 
-@@ -526,6 +526,8 @@ static int ecb_aes_encrypt(struct blkcipher_desc *desc,
- 	struct blkcipher_walk walk;
- 	int err;
- 
-+	padlock_reset_key();
-+
- 	blkcipher_walk_init(&walk, dst, src, nbytes);
- 	err = blkcipher_walk_virt(desc, &walk);
- 
-@@ -548,6 +550,8 @@ static int ecb_aes_decrypt(struct blkcipher_desc *desc,
- 	struct blkcipher_walk walk;
- 	int err;
- 
-+	padlock_reset_key();
-+
- 	blkcipher_walk_init(&walk, dst, src, nbytes);
- 	err = blkcipher_walk_virt(desc, &walk);
- 
-@@ -592,6 +596,8 @@ static int cbc_aes_encrypt(struct blkcipher_desc *desc,
- 	struct blkcipher_walk walk;
- 	int err;
- 
-+	padlock_reset_key();
+ 	volatile struct iic_regs __iomem *iic = dev->vaddr;
+ 	u16 addr = msg->addr;
+-	
+-	DBG2("%d: iic_address, 0x%03x (%d-bit)\n", dev->idx, 
 +
- 	blkcipher_walk_init(&walk, dst, src, nbytes);
- 	err = blkcipher_walk_virt(desc, &walk);
- 
-@@ -616,6 +622,8 @@ static int cbc_aes_decrypt(struct blkcipher_desc *desc,
- 	struct blkcipher_walk walk;
- 	int err;
- 
-+	padlock_reset_key();
++	DBG2("%d: iic_address, 0x%03x (%d-bit)\n", dev->idx,
+ 		addr, msg->flags & I2C_M_TEN ? 10 : 7);
+-	
 +
- 	blkcipher_walk_init(&walk, dst, src, nbytes);
- 	err = blkcipher_walk_virt(desc, &walk);
- 
-diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c
-index d59b2f4..bcf52df 100644
---- a/drivers/dma/dmaengine.c
-+++ b/drivers/dma/dmaengine.c
-@@ -41,12 +41,12 @@
-  * the definition of dma_event_callback in dmaengine.h.
-  *
-  * Each device has a kref, which is initialized to 1 when the device is
-- * registered. A kref_get is done for each class_device registered.  When the
-- * class_device is released, the coresponding kref_put is done in the release
-+ * registered. A kref_get is done for each device registered.  When the
-+ * device is released, the coresponding kref_put is done in the release
-  * method. Every time one of the device's channels is allocated to a client,
-  * a kref_get occurs.  When the channel is freed, the coresponding kref_put
-  * happens. The device's release function does a completion, so
-- * unregister_device does a remove event, class_device_unregister, a kref_put
-+ * unregister_device does a remove event, device_unregister, a kref_put
-  * for the first reference, then waits on the completion for all other
-  * references to finish.
-  *
-@@ -77,9 +77,9 @@ static LIST_HEAD(dma_client_list);
- 
- /* --- sysfs implementation --- */
- 
--static ssize_t show_memcpy_count(struct class_device *cd, char *buf)
-+static ssize_t show_memcpy_count(struct device *dev, struct device_attribute *attr, char *buf)
- {
--	struct dma_chan *chan = container_of(cd, struct dma_chan, class_dev);
-+	struct dma_chan *chan = to_dma_chan(dev);
- 	unsigned long count = 0;
- 	int i;
- 
-@@ -89,9 +89,10 @@ static ssize_t show_memcpy_count(struct class_device *cd, char *buf)
- 	return sprintf(buf, "%lu\n", count);
- }
- 
--static ssize_t show_bytes_transferred(struct class_device *cd, char *buf)
-+static ssize_t show_bytes_transferred(struct device *dev, struct device_attribute *attr,
-+				      char *buf)
- {
--	struct dma_chan *chan = container_of(cd, struct dma_chan, class_dev);
-+	struct dma_chan *chan = to_dma_chan(dev);
- 	unsigned long count = 0;
- 	int i;
- 
-@@ -101,9 +102,9 @@ static ssize_t show_bytes_transferred(struct class_device *cd, char *buf)
- 	return sprintf(buf, "%lu\n", count);
- }
- 
--static ssize_t show_in_use(struct class_device *cd, char *buf)
-+static ssize_t show_in_use(struct device *dev, struct device_attribute *attr, char *buf)
- {
--	struct dma_chan *chan = container_of(cd, struct dma_chan, class_dev);
-+	struct dma_chan *chan = to_dma_chan(dev);
- 	int in_use = 0;
- 
- 	if (unlikely(chan->slow_ref) &&
-@@ -119,7 +120,7 @@ static ssize_t show_in_use(struct class_device *cd, char *buf)
- 	return sprintf(buf, "%d\n", in_use);
+ 	if (msg->flags & I2C_M_TEN){
+ 	    out_8(&iic->cntl, CNTL_AMD);
+ 	    out_8(&iic->lmadr, addr);
+@@ -537,15 +537,15 @@ static inline int iic_invalid_address(const struct i2c_msg* p)
+ 	return (p->addr > 0x3ff) || (!(p->flags & I2C_M_TEN) && (p->addr > 0x7f));
  }
  
--static struct class_device_attribute dma_class_attrs[] = {
-+static struct device_attribute dma_attrs[] = {
- 	__ATTR(memcpy_count, S_IRUGO, show_memcpy_count, NULL),
- 	__ATTR(bytes_transferred, S_IRUGO, show_bytes_transferred, NULL),
- 	__ATTR(in_use, S_IRUGO, show_in_use, NULL),
-@@ -128,16 +129,16 @@ static struct class_device_attribute dma_class_attrs[] = {
- 
- static void dma_async_device_cleanup(struct kref *kref);
- 
--static void dma_class_dev_release(struct class_device *cd)
-+static void dma_dev_release(struct device *dev)
+-static inline int iic_address_neq(const struct i2c_msg* p1, 
++static inline int iic_address_neq(const struct i2c_msg* p1,
+ 				  const struct i2c_msg* p2)
  {
--	struct dma_chan *chan = container_of(cd, struct dma_chan, class_dev);
-+	struct dma_chan *chan = to_dma_chan(dev);
- 	kref_put(&chan->device->refcount, dma_async_device_cleanup);
- }
- 
- static struct class dma_devclass = {
--	.name            = "dma",
--	.class_dev_attrs = dma_class_attrs,
--	.release = dma_class_dev_release,
-+	.name		= "dma",
-+	.dev_attrs	= dma_attrs,
-+	.dev_release	= dma_dev_release,
- };
- 
- /* --- client and device registration --- */
-@@ -377,12 +378,12 @@ int dma_async_device_register(struct dma_device *device)
- 			continue;
- 
- 		chan->chan_id = chancnt++;
--		chan->class_dev.class = &dma_devclass;
--		chan->class_dev.dev = NULL;
--		snprintf(chan->class_dev.class_id, BUS_ID_SIZE, "dma%dchan%d",
-+		chan->dev.class = &dma_devclass;
-+		chan->dev.parent = NULL;
-+		snprintf(chan->dev.bus_id, BUS_ID_SIZE, "dma%dchan%d",
- 		         device->dev_id, chan->chan_id);
- 
--		rc = class_device_register(&chan->class_dev);
-+		rc = device_register(&chan->dev);
- 		if (rc) {
- 			chancnt--;
- 			free_percpu(chan->local);
-@@ -411,7 +412,7 @@ err_out:
- 		if (chan->local == NULL)
- 			continue;
- 		kref_put(&device->refcount, dma_async_device_cleanup);
--		class_device_unregister(&chan->class_dev);
-+		device_unregister(&chan->dev);
- 		chancnt--;
- 		free_percpu(chan->local);
- 	}
-@@ -445,7 +446,7 @@ void dma_async_device_unregister(struct dma_device *device)
- 
- 	list_for_each_entry(chan, &device->channels, device_node) {
- 		dma_clients_notify_removed(chan);
--		class_device_unregister(&chan->class_dev);
-+		device_unregister(&chan->dev);
- 		dma_chan_release(chan);
- 	}
- 
-diff --git a/drivers/edac/edac_device_sysfs.c b/drivers/edac/edac_device_sysfs.c
-index 70b837f..5376457 100644
---- a/drivers/edac/edac_device_sysfs.c
-+++ b/drivers/edac/edac_device_sysfs.c
-@@ -246,16 +246,6 @@ int edac_device_register_sysfs_main_kobj(struct edac_device_ctl_info *edac_dev)
- 
- 	/* Init the devices's kobject */
- 	memset(&edac_dev->kobj, 0, sizeof(struct kobject));
--	edac_dev->kobj.ktype = &ktype_device_ctrl;
--
--	/* set this new device under the edac_class kobject */
--	edac_dev->kobj.parent = &edac_class->kset.kobj;
--
--	/* generate sysfs "..../edac/<name>"   */
--	debugf4("%s() set name of kobject to: %s\n", __func__, edac_dev->name);
--	err = kobject_set_name(&edac_dev->kobj, "%s", edac_dev->name);
--	if (err)
--		goto err_out;
- 
- 	/* Record which module 'owns' this control structure
- 	 * and bump the ref count of the module
-@@ -268,12 +258,15 @@ int edac_device_register_sysfs_main_kobj(struct edac_device_ctl_info *edac_dev)
- 	}
- 
- 	/* register */
--	err = kobject_register(&edac_dev->kobj);
-+	err = kobject_init_and_add(&edac_dev->kobj, &ktype_device_ctrl,
-+				   &edac_class->kset.kobj,
-+				   "%s", edac_dev->name);
- 	if (err) {
- 		debugf1("%s()Failed to register '.../edac/%s'\n",
- 			__func__, edac_dev->name);
- 		goto err_kobj_reg;
- 	}
-+	kobject_uevent(&edac_dev->kobj, KOBJ_ADD);
+-	return (p1->addr != p2->addr) 
++	return (p1->addr != p2->addr)
+ 		|| ((p1->flags & I2C_M_TEN) != (p2->flags & I2C_M_TEN));
+-} 
++}
  
- 	/* At this point, to 'free' the control struct,
- 	 * edac_device_unregister_sysfs_main_kobj() must be used
-@@ -310,7 +303,7 @@ void edac_device_unregister_sysfs_main_kobj(
- 	 *   a) module_put() this module
- 	 *   b) 'kfree' the memory
+ /*
+- * Generic master transfer entrypoint. 
++ * Generic master transfer entrypoint.
+  * Returns the number of processed messages or error (<0)
+  */
+ static int iic_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
+@@ -553,20 +553,20 @@ static int iic_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
+     	struct ibm_iic_private* dev = (struct ibm_iic_private*)(i2c_get_adapdata(adap));
+ 	volatile struct iic_regs __iomem *iic = dev->vaddr;
+ 	int i, ret = 0;
+-	
++
+ 	DBG2("%d: iic_xfer, %d msg(s)\n", dev->idx, num);
+-	
++
+ 	if (!num)
+ 		return 0;
+-	
++
+ 	/* Check the sanity of the passed messages.
+ 	 * Uhh, generic i2c layer is more suitable place for such code...
  	 */
--	kobject_unregister(&edac_dev->kobj);
-+	kobject_put(&edac_dev->kobj);
- }
- 
- /* edac_dev -> instance information */
-@@ -533,12 +526,6 @@ static int edac_device_create_block(struct edac_device_ctl_info *edac_dev,
- 
- 	/* init this block's kobject */
- 	memset(&block->kobj, 0, sizeof(struct kobject));
--	block->kobj.parent = &instance->kobj;
--	block->kobj.ktype = &ktype_block_ctrl;
--
--	err = kobject_set_name(&block->kobj, "%s", block->name);
--	if (err)
--		return err;
- 
- 	/* bump the main kobject's reference count for this controller
- 	 * and this instance is dependant on the main
-@@ -550,7 +537,9 @@ static int edac_device_create_block(struct edac_device_ctl_info *edac_dev,
+ 	if (unlikely(iic_invalid_address(&msgs[0]))){
+-		DBG("%d: invalid address 0x%03x (%d-bit)\n", dev->idx, 
++		DBG("%d: invalid address 0x%03x (%d-bit)\n", dev->idx,
+ 			msgs[0].addr, msgs[0].flags & I2C_M_TEN ? 10 : 7);
+ 		return -EINVAL;
+-	}		
++	}
+ 	for (i = 0; i < num; ++i){
+ 		if (unlikely(msgs[i].len <= 0)){
+ 			if (num == 1 && !msgs[0].len){
+@@ -576,7 +576,7 @@ static int iic_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
+ 				 */
+ 				return iic_smbus_quick(dev, &msgs[0]);
+ 			}
+-			DBG("%d: invalid len %d in msg[%d]\n", dev->idx, 
++			DBG("%d: invalid len %d in msg[%d]\n", dev->idx,
+ 				msgs[i].len, i);
+ 			return -EINVAL;
+ 		}
+@@ -585,34 +585,34 @@ static int iic_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
+ 			return -EINVAL;
+ 		}
  	}
- 
- 	/* Add this block's kobject */
--	err = kobject_register(&block->kobj);
-+	err = kobject_init_and_add(&block->kobj, &ktype_block_ctrl,
-+				   &instance->kobj,
-+				   "%s", block->name);
- 	if (err) {
- 		debugf1("%s() Failed to register instance '%s'\n",
- 			__func__, block->name);
-@@ -579,12 +568,13 @@ static int edac_device_create_block(struct edac_device_ctl_info *edac_dev,
- 				goto err_on_attrib;
+-	
++
+ 	/* Check bus state */
+ 	if (unlikely((in_8(&iic->extsts) & EXTSTS_BCS_MASK) != EXTSTS_BCS_FREE)){
+ 		DBG("%d: iic_xfer, bus is not free\n", dev->idx);
+-		
++
+ 		/* Usually it means something serious has happend.
+ 		 * We *cannot* have unfinished previous transfer
+ 		 * so it doesn't make any sense to try to stop it.
+-		 * Probably we were not able to recover from the 
++		 * Probably we were not able to recover from the
+ 		 * previous error.
+ 		 * The only *reasonable* thing I can think of here
+ 		 * is soft reset.  --ebs
+ 		 */
+ 		iic_dev_reset(dev);
+-		
++
+ 		if ((in_8(&iic->extsts) & EXTSTS_BCS_MASK) != EXTSTS_BCS_FREE){
+ 			DBG("%d: iic_xfer, bus is still not free\n", dev->idx);
+ 			return -EREMOTEIO;
  		}
+-	} 
++	}
+ 	else {
+ 		/* Flush master data buffer (just in case) */
+ 		out_8(&iic->mdcntl, in_8(&iic->mdcntl) | MDCNTL_FMDB);
  	}
-+	kobject_uevent(&block->kobj, KOBJ_ADD);
- 
- 	return 0;
- 
- 	/* Error unwind stack */
- err_on_attrib:
--	kobject_unregister(&block->kobj);
-+	kobject_put(&block->kobj);
- 
- err_out:
- 	return err;
-@@ -615,7 +605,7 @@ static void edac_device_delete_block(struct edac_device_ctl_info *edac_dev,
- 	/* unregister this block's kobject, SEE:
- 	 *	edac_device_ctrl_block_release() callback operation
- 	 */
--	kobject_unregister(&block->kobj);
-+	kobject_put(&block->kobj);
- }
- 
- /* instance ctor/dtor code */
-@@ -637,15 +627,8 @@ static int edac_device_create_instance(struct edac_device_ctl_info *edac_dev,
- 	/* Init the instance's kobject */
- 	memset(&instance->kobj, 0, sizeof(struct kobject));
+-	
++
+ 	/* Load slave address */
+ 	iic_address(dev, &msgs[0]);
+-	
++
+ 	/* Do real transfer */
+     	for (i = 0; i < num && !ret; ++i)
+ 		ret = iic_xfer_bytes(dev, &msgs[i], i < num - 1);
+@@ -648,7 +648,7 @@ static inline u8 iic_clckdiv(unsigned int opb)
  
--	/* set this new device under the edac_device main kobject */
--	instance->kobj.parent = &edac_dev->kobj;
--	instance->kobj.ktype = &ktype_instance_ctrl;
- 	instance->ctl = edac_dev;
+ 	/* Convert to MHz */
+ 	opb /= 1000000;
+-	
++
+ 	if (opb < 20 || opb > 150){
+ 		printk(KERN_CRIT "ibm-iic: invalid OPB clock frequency %u MHz\n",
+ 			opb);
+@@ -666,7 +666,7 @@ static int __devinit iic_probe(struct ocp_device *ocp){
+ 	struct i2c_adapter* adap;
+ 	struct ocp_func_iic_data* iic_data = ocp->def->additions;
+ 	int ret;
+-	
++
+ 	if (!iic_data)
+ 		printk(KERN_WARNING"ibm-iic%d: missing additional data!\n",
+ 			ocp->def->index);
+@@ -679,7 +679,7 @@ static int __devinit iic_probe(struct ocp_device *ocp){
  
--	err = kobject_set_name(&instance->kobj, "%s", instance->name);
--	if (err)
--		goto err_out;
--
- 	/* bump the main kobject's reference count for this controller
- 	 * and this instance is dependant on the main
- 	 */
-@@ -655,8 +638,9 @@ static int edac_device_create_instance(struct edac_device_ctl_info *edac_dev,
- 		goto err_out;
+ 	dev->idx = ocp->def->index;
+ 	ocp_set_drvdata(ocp, dev);
+-	
++
+ 	if (!request_mem_region(ocp->def->paddr, sizeof(struct iic_regs),
+ 				"ibm_iic")) {
+ 		ret = -EBUSY;
+@@ -692,7 +692,7 @@ static int __devinit iic_probe(struct ocp_device *ocp){
+ 		ret = -ENXIO;
+ 		goto fail2;
  	}
+-	
++
+ 	init_waitqueue_head(&dev->wq);
  
--	/* Formally register this instance's kobject */
--	err = kobject_register(&instance->kobj);
-+	/* Formally register this instance's kobject under the edac_device */
-+	err = kobject_init_and_add(&instance->kobj, &ktype_instance_ctrl,
-+				   &edac_dev->kobj, "%s", instance->name);
- 	if (err != 0) {
- 		debugf2("%s() Failed to register instance '%s'\n",
- 			__func__, instance->name);
-@@ -679,6 +663,7 @@ static int edac_device_create_instance(struct edac_device_ctl_info *edac_dev,
- 			goto err_release_instance_kobj;
+ 	dev->irq = iic_force_poll ? -1 : ocp->def->irq;
+@@ -702,29 +702,29 @@ static int __devinit iic_probe(struct ocp_device *ocp){
+ 		 */
+ 		iic_interrupt_mode(dev, 0);
+ 		if (request_irq(dev->irq, iic_handler, 0, "IBM IIC", dev)){
+-			printk(KERN_ERR "ibm-iic%d: request_irq %d failed\n", 
++			printk(KERN_ERR "ibm-iic%d: request_irq %d failed\n",
+ 				dev->idx, dev->irq);
+-			/* Fallback to the polling mode */	
++			/* Fallback to the polling mode */
+ 			dev->irq = -1;
  		}
  	}
-+	kobject_uevent(&instance->kobj, KOBJ_ADD);
- 
- 	debugf4("%s() Registered instance %d '%s' kobject\n",
- 		__func__, idx, instance->name);
-@@ -687,7 +672,7 @@ static int edac_device_create_instance(struct edac_device_ctl_info *edac_dev,
- 
- 	/* error unwind stack */
- err_release_instance_kobj:
--	kobject_unregister(&instance->kobj);
-+	kobject_put(&instance->kobj);
- 
- err_out:
- 	return err;
-@@ -712,7 +697,7 @@ static void edac_device_delete_instance(struct edac_device_ctl_info *edac_dev,
- 	/* unregister this instance's kobject, SEE:
- 	 *	edac_device_ctrl_instance_release() for callback operation
+-	
++
+ 	if (dev->irq < 0)
+-		printk(KERN_WARNING "ibm-iic%d: using polling mode\n", 
++		printk(KERN_WARNING "ibm-iic%d: using polling mode\n",
+ 			dev->idx);
+-		
++
+ 	/* Board specific settings */
+ 	dev->fast_mode = iic_force_fast ? 1 : (iic_data ? iic_data->fast_mode : 0);
+-	
+-	/* clckdiv is the same for *all* IIC interfaces, 
++
++	/* clckdiv is the same for *all* IIC interfaces,
+ 	 * but I'd rather make a copy than introduce another global. --ebs
  	 */
--	kobject_unregister(&instance->kobj);
-+	kobject_put(&instance->kobj);
- }
- 
- /*
-diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c
-index 3706b2b..9aac880 100644
---- a/drivers/edac/edac_mc_sysfs.c
-+++ b/drivers/edac/edac_mc_sysfs.c
-@@ -380,13 +380,6 @@ static int edac_create_csrow_object(struct mem_ctl_info *mci,
- 	/* generate ..../edac/mc/mc<id>/csrow<index>   */
- 	memset(&csrow->kobj, 0, sizeof(csrow->kobj));
- 	csrow->mci = mci;	/* include container up link */
--	csrow->kobj.parent = kobj_mci;
--	csrow->kobj.ktype = &ktype_csrow;
--
--	/* name this instance of csrow<id> */
--	err = kobject_set_name(&csrow->kobj, "csrow%d", index);
--	if (err)
--		goto err_out;
+ 	dev->clckdiv = iic_clckdiv(ocp_sys_info.opb_bus_freq);
+ 	DBG("%d: clckdiv = %d\n", dev->idx, dev->clckdiv);
+-	
++
+ 	/* Initialize IIC interface */
+ 	iic_dev_init(dev);
+-	
++
+ 	/* Register it with i2c layer */
+ 	adap = &dev->adap;
+ 	adap->dev.parent = &ocp->dev;
+@@ -736,7 +736,6 @@ static int __devinit iic_probe(struct ocp_device *ocp){
+ 	adap->client_register = NULL;
+ 	adap->client_unregister = NULL;
+ 	adap->timeout = 1;
+-	adap->retries = 1;
  
- 	/* bump the mci instance's kobject's ref count */
- 	kobj = kobject_get(&mci->edac_mci_kobj);
-@@ -396,12 +389,13 @@ static int edac_create_csrow_object(struct mem_ctl_info *mci,
+ 	/*
+ 	 * If "dev->idx" is negative we consider it as zero.
+@@ -750,24 +749,24 @@ static int __devinit iic_probe(struct ocp_device *ocp){
+ 			dev->idx);
+ 		goto fail;
  	}
+-	
++
+ 	printk(KERN_INFO "ibm-iic%d: using %s mode\n", dev->idx,
+ 		dev->fast_mode ? "fast (400 kHz)" : "standard (100 kHz)");
  
- 	/* Instanstiate the csrow object */
--	err = kobject_register(&csrow->kobj);
-+	err = kobject_init_and_add(&csrow->kobj, &ktype_csrow, kobj_mci,
-+				   "csrow%d", index);
- 	if (err)
- 		goto err_release_top_kobj;
- 
- 	/* At this point, to release a csrow kobj, one must
--	 * call the kobject_unregister and allow that tear down
-+	 * call the kobject_put and allow that tear down
- 	 * to work the releasing
- 	 */
- 
-@@ -412,11 +406,11 @@ static int edac_create_csrow_object(struct mem_ctl_info *mci,
- 		err = edac_create_channel_files(&csrow->kobj, chan);
- 		if (err) {
- 			/* special case the unregister here */
--			kobject_unregister(&csrow->kobj);
-+			kobject_put(&csrow->kobj);
- 			goto err_out;
- 		}
- 	}
--
-+	kobject_uevent(&csrow->kobj, KOBJ_ADD);
  	return 0;
  
- 	/* error unwind stack */
-@@ -744,7 +738,6 @@ static struct kobj_type ktype_mc_set_attribs = {
-  */
- static struct kset mc_kset = {
- 	.kobj = {.ktype = &ktype_mc_set_attribs },
--	.ktype = &ktype_mci,
- };
- 
- 
-@@ -765,14 +758,6 @@ int edac_mc_register_sysfs_main_kobj(struct mem_ctl_info *mci)
- 	/* Init the mci's kobject */
- 	memset(kobj_mci, 0, sizeof(*kobj_mci));
- 
--	/* this instance become part of the mc_kset */
--	kobj_mci->kset = &mc_kset;
--
--	/* set the name of the mc<id> object */
--	err = kobject_set_name(kobj_mci, "mc%d", mci->mc_idx);
--	if (err)
--		goto fail_out;
--
- 	/* Record which module 'owns' this control structure
- 	 * and bump the ref count of the module
- 	 */
-@@ -784,13 +769,18 @@ int edac_mc_register_sysfs_main_kobj(struct mem_ctl_info *mci)
- 		goto fail_out;
- 	}
- 
-+	/* this instance become part of the mc_kset */
-+	kobj_mci->kset = &mc_kset;
-+
- 	/* register the mc<id> kobject to the mc_kset */
--	err = kobject_register(kobj_mci);
-+	err = kobject_init_and_add(kobj_mci, &ktype_mci, NULL,
-+				   "mc%d", mci->mc_idx);
- 	if (err) {
- 		debugf1("%s()Failed to register '.../edac/mc%d'\n",
- 			__func__, mci->mc_idx);
- 		goto kobj_reg_fail;
- 	}
-+	kobject_uevent(kobj_mci, KOBJ_ADD);
- 
- 	/* At this point, to 'free' the control struct,
- 	 * edac_mc_unregister_sysfs_main_kobj() must be used
-@@ -818,7 +808,7 @@ fail_out:
- void edac_mc_unregister_sysfs_main_kobj(struct mem_ctl_info *mci)
- {
- 	/* delete the kobj from the mc_kset */
--	kobject_unregister(&mci->edac_mci_kobj);
-+	kobject_put(&mci->edac_mci_kobj);
- }
+-fail:	
++fail:
+ 	if (dev->irq >= 0){
+ 		iic_interrupt_mode(dev, 0);
+ 		free_irq(dev->irq, dev);
+-	}	
++	}
  
- #define EDAC_DEVICE_SYMLINK	"device"
-@@ -933,7 +923,7 @@ int edac_create_sysfs_mci_device(struct mem_ctl_info *mci)
- fail1:
- 	for (i--; i >= 0; i--) {
- 		if (csrow->nr_pages > 0) {
--			kobject_unregister(&mci->csrows[i].kobj);
-+			kobject_put(&mci->csrows[i].kobj);
- 		}
- 	}
+ 	iounmap(dev->vaddr);
+-fail2:	
++fail2:
+ 	release_mem_region(ocp->def->paddr, sizeof(struct iic_regs));
+ fail1:
+ 	ocp_set_drvdata(ocp, NULL);
+-	kfree(dev);	
++	kfree(dev);
+ 	return ret;
+ }
  
-@@ -960,7 +950,7 @@ void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci)
- 	for (i = 0; i < mci->nr_csrows; i++) {
- 		if (mci->csrows[i].nr_pages > 0) {
- 			debugf0("%s()  unreg csrow-%d\n", __func__, i);
--			kobject_unregister(&mci->csrows[i].kobj);
-+			kobject_put(&mci->csrows[i].kobj);
+@@ -783,13 +782,13 @@ static void __devexit iic_remove(struct ocp_device *ocp)
+ 			dev->idx);
+ 		/* That's *very* bad, just shutdown IRQ ... */
+ 		if (dev->irq >= 0){
+-		    iic_interrupt_mode(dev, 0);	
++		    iic_interrupt_mode(dev, 0);
+ 		    free_irq(dev->irq, dev);
+ 		    dev->irq = -1;
+ 		}
+ 	} else {
+ 		if (dev->irq >= 0){
+-		    iic_interrupt_mode(dev, 0);	
++		    iic_interrupt_mode(dev, 0);
+ 		    free_irq(dev->irq, dev);
  		}
+ 		iounmap(dev->vaddr);
+@@ -798,7 +797,7 @@ static void __devexit iic_remove(struct ocp_device *ocp)
  	}
- 
-@@ -977,7 +967,7 @@ void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci)
- 	debugf0("%s()  unregister this mci kobj\n", __func__);
- 
- 	/* unregister this instance's kobject */
--	kobject_unregister(&mci->edac_mci_kobj);
-+	kobject_put(&mci->edac_mci_kobj);
  }
  
+-static struct ocp_device_id ibm_iic_ids[] __devinitdata = 
++static struct ocp_device_id ibm_iic_ids[] __devinitdata =
+ {
+ 	{ .vendor = OCP_VENDOR_IBM, .function = OCP_FUNC_IIC },
+ 	{ .vendor = OCP_VENDOR_INVALID }
+diff --git a/drivers/i2c/busses/i2c-ibm_iic.h b/drivers/i2c/busses/i2c-ibm_iic.h
+index 59d7b43..fdaa482 100644
+--- a/drivers/i2c/busses/i2c-ibm_iic.h
++++ b/drivers/i2c/busses/i2c-ibm_iic.h
+@@ -2,11 +2,11 @@
+  * drivers/i2c/busses/i2c-ibm_iic.h
+  *
+  * Support for the IIC peripheral on IBM PPC 4xx
+- * 
++ *
+  * Copyright (c) 2003 Zultys Technologies.
+  * Eugene Surovegin <eugene.surovegin at zultys.com> or <ebs at ebshome.net>
+  *
+- * Based on original work by 
++ * Based on original work by
+  * 	Ian DaSilva  <idasilva at mvista.com>
+  *      Armin Kuster <akuster at mvista.com>
+  * 	Matt Porter  <mporter at mvista.com>
+@@ -22,7 +22,7 @@
+ #ifndef __I2C_IBM_IIC_H_
+ #define __I2C_IBM_IIC_H_
  
-diff --git a/drivers/edac/edac_module.c b/drivers/edac/edac_module.c
-index e0c4a40..7e1374a 100644
---- a/drivers/edac/edac_module.c
-+++ b/drivers/edac/edac_module.c
-@@ -31,7 +31,7 @@ struct workqueue_struct *edac_workqueue;
-  *	need to export to other files in this modules
-  */
- static struct sysdev_class edac_class = {
--	set_kset_name("edac"),
-+	.name = "edac",
- };
- static int edac_class_valid;
+-#include <linux/i2c.h> 
++#include <linux/i2c.h>
  
-diff --git a/drivers/edac/edac_pci_sysfs.c b/drivers/edac/edac_pci_sysfs.c
-index 69f5ddd..5b075da 100644
---- a/drivers/edac/edac_pci_sysfs.c
-+++ b/drivers/edac/edac_pci_sysfs.c
-@@ -162,14 +162,6 @@ static int edac_pci_create_instance_kobj(struct edac_pci_ctl_info *pci, int idx)
+ struct iic_regs {
+ 	u16 mdbuf;
+@@ -58,7 +58,7 @@ struct ibm_iic_private {
+ #define CNTL_TCT_MASK	0x30
+ #define CNTL_TCT_SHIFT	4
+ #define CNTL_RPST	0x08
+-#define CNTL_CHT	0x04 
++#define CNTL_CHT	0x04
+ #define CNTL_RW		0x02
+ #define CNTL_PT		0x01
  
- 	debugf0("%s()\n", __func__);
+diff --git a/drivers/i2c/busses/i2c-iop3xx.c b/drivers/i2c/busses/i2c-iop3xx.c
+index c70146e..ab41400 100644
+--- a/drivers/i2c/busses/i2c-iop3xx.c
++++ b/drivers/i2c/busses/i2c-iop3xx.c
+@@ -490,7 +490,6 @@ iop3xx_i2c_probe(struct platform_device *pdev)
+ 	 * Default values...should these come in from board code?
+ 	 */
+ 	new_adapter->timeout = 100;	
+-	new_adapter->retries = 3;
+ 	new_adapter->algo = &iop3xx_i2c_algo;
  
--	/* Set the parent and the instance's ktype */
--	pci->kobj.parent = &edac_pci_top_main_kobj;
--	pci->kobj.ktype = &ktype_pci_instance;
+ 	init_waitqueue_head(&adapter_data->waitq);
+diff --git a/drivers/i2c/busses/i2c-ixp4xx.c b/drivers/i2c/busses/i2c-ixp4xx.c
+deleted file mode 100644
+index 069ed7f..0000000
+--- a/drivers/i2c/busses/i2c-ixp4xx.c
++++ /dev/null
+@@ -1,178 +0,0 @@
+-/*
+- * drivers/i2c/busses/i2c-ixp4xx.c
+- *
+- * Intel's IXP4xx XScale NPU chipsets (IXP420, 421, 422, 425) do not have
+- * an on board I2C controller but provide 16 GPIO pins that are often
+- * used to create an I2C bus. This driver provides an i2c_adapter 
+- * interface that plugs in under algo_bit and drives the GPIO pins
+- * as instructed by the alogorithm driver.
+- *
+- * Author: Deepak Saxena <dsaxena at plexity.net>
+- *
+- * Copyright (c) 2003-2004 MontaVista Software Inc.
+- *
+- * This file is licensed under the terms of the GNU General Public 
+- * License version 2. This program is licensed "as is" without any 
+- * warranty of any kind, whether express or implied.
+- *
+- * NOTE: Since different platforms will use different GPIO pins for
+- *       I2C, this driver uses an IXP4xx-specific platform_data
+- *       pointer to pass the GPIO numbers to the driver. This 
+- *       allows us to support all the different IXP4xx platforms
+- *       w/o having to put #ifdefs in this driver.
+- *
+- *       See arch/arm/mach-ixp4xx/ixdp425.c for an example of building a 
+- *       device list and filling in the ixp4xx_i2c_pins data structure 
+- *       that is passed as the platform_data to this driver.
+- */
 -
--	err = kobject_set_name(&pci->kobj, "pci%d", idx);
--	if (err)
+-#include <linux/kernel.h>
+-#include <linux/init.h>
+-#include <linux/platform_device.h>
+-#include <linux/module.h>
+-#include <linux/i2c.h>
+-#include <linux/i2c-algo-bit.h>
+-
+-#include <asm/hardware.h>	/* Pick up IXP4xx-specific bits */
+-
+-static inline int ixp4xx_scl_pin(void *data)
+-{
+-	return ((struct ixp4xx_i2c_pins*)data)->scl_pin;
+-}
+-
+-static inline int ixp4xx_sda_pin(void *data)
+-{
+-	return ((struct ixp4xx_i2c_pins*)data)->sda_pin;
+-}
+-
+-static void ixp4xx_bit_setscl(void *data, int val)
+-{
+-	gpio_line_set(ixp4xx_scl_pin(data), 0);
+-	gpio_line_config(ixp4xx_scl_pin(data),
+-		val ? IXP4XX_GPIO_IN : IXP4XX_GPIO_OUT );
+-}
+-
+-static void ixp4xx_bit_setsda(void *data, int val)
+-{
+-	gpio_line_set(ixp4xx_sda_pin(data), 0);
+-	gpio_line_config(ixp4xx_sda_pin(data),
+-		val ? IXP4XX_GPIO_IN : IXP4XX_GPIO_OUT );
+-}
+-
+-static int ixp4xx_bit_getscl(void *data)
+-{
+-	int scl;
+-
+-	gpio_line_config(ixp4xx_scl_pin(data), IXP4XX_GPIO_IN );
+-	gpio_line_get(ixp4xx_scl_pin(data), &scl);
+-
+-	return scl;
+-}	
+-
+-static int ixp4xx_bit_getsda(void *data)
+-{
+-	int sda;
+-
+-	gpio_line_config(ixp4xx_sda_pin(data), IXP4XX_GPIO_IN );
+-	gpio_line_get(ixp4xx_sda_pin(data), &sda);
+-
+-	return sda;
+-}	
+-
+-struct ixp4xx_i2c_data {
+-	struct ixp4xx_i2c_pins *gpio_pins;
+-	struct i2c_adapter adapter;
+-	struct i2c_algo_bit_data algo_data;
+-};
+-
+-static int ixp4xx_i2c_remove(struct platform_device *plat_dev)
+-{
+-	struct ixp4xx_i2c_data *drv_data = platform_get_drvdata(plat_dev);
+-
+-	platform_set_drvdata(plat_dev, NULL);
+-
+-	i2c_del_adapter(&drv_data->adapter);
+-
+-	kfree(drv_data);
+-
+-	return 0;
+-}
+-
+-static int ixp4xx_i2c_probe(struct platform_device *plat_dev)
+-{
+-	int err;
+-	struct ixp4xx_i2c_pins *gpio = plat_dev->dev.platform_data;
+-	struct ixp4xx_i2c_data *drv_data = 
+-		kzalloc(sizeof(struct ixp4xx_i2c_data), GFP_KERNEL);
+-
+-	if(!drv_data)
+-		return -ENOMEM;
+-
+-	drv_data->gpio_pins = gpio;
+-
+-	/*
+-	 * We could make a lot of these structures static, but
+-	 * certain platforms may have multiple GPIO-based I2C
+-	 * buses for various device domains, so we need per-device
+-	 * algo_data->data. 
+-	 */
+-	drv_data->algo_data.data = gpio;
+-	drv_data->algo_data.setsda = ixp4xx_bit_setsda;
+-	drv_data->algo_data.setscl = ixp4xx_bit_setscl;
+-	drv_data->algo_data.getsda = ixp4xx_bit_getsda;
+-	drv_data->algo_data.getscl = ixp4xx_bit_getscl;
+-	drv_data->algo_data.udelay = 10;
+-	drv_data->algo_data.timeout = 100;
+-
+-	drv_data->adapter.id = I2C_HW_B_IXP4XX;
+-	drv_data->adapter.class = I2C_CLASS_HWMON;
+-	strlcpy(drv_data->adapter.name, plat_dev->dev.driver->name,
+-		sizeof(drv_data->adapter.name));
+-	drv_data->adapter.algo_data = &drv_data->algo_data;
+-
+-	drv_data->adapter.dev.parent = &plat_dev->dev;
+-
+-	gpio_line_config(gpio->scl_pin, IXP4XX_GPIO_IN);
+-	gpio_line_config(gpio->sda_pin, IXP4XX_GPIO_IN);
+-	gpio_line_set(gpio->scl_pin, 0);
+-	gpio_line_set(gpio->sda_pin, 0);
+-
+-	err = i2c_bit_add_bus(&drv_data->adapter);
+-	if (err) {
+-		printk(KERN_ERR "ERROR: Could not install %s\n", plat_dev->dev.bus_id);
+-
+-		kfree(drv_data);
 -		return err;
+-	}
 -
- 	/* First bump the ref count on the top main kobj, which will
- 	 * track the number of PCI instances we have, and thus nest
- 	 * properly on keeping the module loaded
-@@ -181,7 +173,8 @@ static int edac_pci_create_instance_kobj(struct edac_pci_ctl_info *pci, int idx)
- 	}
- 
- 	/* And now register this new kobject under the main kobj */
--	err = kobject_register(&pci->kobj);
-+	err = kobject_init_and_add(&pci->kobj, &ktype_pci_instance,
-+				   &edac_pci_top_main_kobj, "pci%d", idx);
- 	if (err != 0) {
- 		debugf2("%s() failed to register instance pci%d\n",
- 			__func__, idx);
-@@ -189,6 +182,7 @@ static int edac_pci_create_instance_kobj(struct edac_pci_ctl_info *pci, int idx)
- 		goto error_out;
- 	}
- 
-+	kobject_uevent(&pci->kobj, KOBJ_ADD);
- 	debugf1("%s() Register instance 'pci%d' kobject\n", __func__, idx);
+-	platform_set_drvdata(plat_dev, drv_data);
+-
+-	return 0;
+-}
+-
+-static struct platform_driver ixp4xx_i2c_driver = {
+-	.probe		= ixp4xx_i2c_probe,
+-	.remove		= ixp4xx_i2c_remove,
+-	.driver		= {
+-		.name	= "IXP4XX-I2C",
+-		.owner	= THIS_MODULE,
+-	},
+-};
+-
+-static int __init ixp4xx_i2c_init(void)
+-{
+-	return platform_driver_register(&ixp4xx_i2c_driver);
+-}
+-
+-static void __exit ixp4xx_i2c_exit(void)
+-{
+-	platform_driver_unregister(&ixp4xx_i2c_driver);
+-}
+-
+-module_init(ixp4xx_i2c_init);
+-module_exit(ixp4xx_i2c_exit);
+-
+-MODULE_DESCRIPTION("GPIO-based I2C adapter for IXP4xx systems");
+-MODULE_LICENSE("GPL");
+-MODULE_AUTHOR("Deepak Saxena <dsaxena at plexity.net>");
+-
+diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c
+index d8de4ac..bbe787b 100644
+--- a/drivers/i2c/busses/i2c-mpc.c
++++ b/drivers/i2c/busses/i2c-mpc.c
+@@ -180,7 +180,7 @@ static void mpc_i2c_stop(struct mpc_i2c *i2c)
+ static int mpc_write(struct mpc_i2c *i2c, int target,
+ 		     const u8 * data, int length, int restart)
+ {
+-	int i;
++	int i, result;
+ 	unsigned timeout = i2c->adap.timeout;
+ 	u32 flags = restart ? CCR_RSTA : 0;
  
- 	return 0;
-@@ -211,7 +205,7 @@ void edac_pci_unregister_sysfs_instance_kobj(struct edac_pci_ctl_info *pci)
- 	 * function release the main reference count and then
- 	 * kfree the memory
- 	 */
--	kobject_unregister(&pci->kobj);
-+	kobject_put(&pci->kobj);
- }
+@@ -192,15 +192,17 @@ static int mpc_write(struct mpc_i2c *i2c, int target,
+ 	/* Write target byte */
+ 	writeb((target << 1), i2c->base + MPC_I2C_DR);
  
- /***************************** EDAC PCI sysfs root **********************/
-@@ -364,14 +358,6 @@ int edac_pci_main_kobj_setup(void)
- 		goto decrement_count_fail;
- 	}
+-	if (i2c_wait(i2c, timeout, 1) < 0)
+-		return -1;
++	result = i2c_wait(i2c, timeout, 1);
++	if (result < 0)
++		return result;
  
--	/* Need the kobject hook ups, and name setting */
--	edac_pci_top_main_kobj.ktype = &ktype_edac_pci_main_kobj;
--	edac_pci_top_main_kobj.parent = &edac_class->kset.kobj;
--
--	err = kobject_set_name(&edac_pci_top_main_kobj, "pci");
--	if (err)
--		goto decrement_count_fail;
--
- 	/* Bump the reference count on this module to ensure the
- 	 * modules isn't unloaded until we deconstruct the top
- 	 * level main kobj for EDAC PCI
-@@ -383,23 +369,24 @@ int edac_pci_main_kobj_setup(void)
- 	}
+ 	for (i = 0; i < length; i++) {
+ 		/* Write data byte */
+ 		writeb(data[i], i2c->base + MPC_I2C_DR);
  
- 	/* Instanstiate the pci object */
--	/* FIXME: maybe new sysdev_create_subdir() */
--	err = kobject_register(&edac_pci_top_main_kobj);
-+	err = kobject_init_and_add(&edac_pci_top_main_kobj, &ktype_edac_pci_main_kobj,
-+				   &edac_class->kset.kobj, "pci");
- 	if (err) {
- 		debugf1("Failed to register '.../edac/pci'\n");
--		goto kobject_register_fail;
-+		goto kobject_init_and_add_fail;
+-		if (i2c_wait(i2c, timeout, 1) < 0)
+-			return -1;
++		result = i2c_wait(i2c, timeout, 1);
++		if (result < 0)
++			return result;
  	}
  
- 	/* At this point, to 'release' the top level kobject
- 	 * for EDAC PCI, then edac_pci_main_kobj_teardown()
- 	 * must be used, for resources to be cleaned up properly
- 	 */
-+	kobject_uevent(&edac_pci_top_main_kobj, KOBJ_ADD);
- 	debugf1("Registered '.../edac/pci' kobject\n");
- 
  	return 0;
+@@ -210,7 +212,7 @@ static int mpc_read(struct mpc_i2c *i2c, int target,
+ 		    u8 * data, int length, int restart)
+ {
+ 	unsigned timeout = i2c->adap.timeout;
+-	int i;
++	int i, result;
+ 	u32 flags = restart ? CCR_RSTA : 0;
  
- 	/* Error unwind statck */
--kobject_register_fail:
-+kobject_init_and_add_fail:
- 	module_put(THIS_MODULE);
+ 	/* Start with MEN */
+@@ -221,8 +223,9 @@ static int mpc_read(struct mpc_i2c *i2c, int target,
+ 	/* Write target address byte - this time with the read flag set */
+ 	writeb((target << 1) | 1, i2c->base + MPC_I2C_DR);
  
- decrement_count_fail:
-@@ -424,9 +411,9 @@ static void edac_pci_main_kobj_teardown(void)
- 	 * main kobj
- 	 */
- 	if (atomic_dec_return(&edac_pci_sysfs_refcount) == 0) {
--		debugf0("%s() called kobject_unregister on main kobj\n",
-+		debugf0("%s() called kobject_put on main kobj\n",
- 			__func__);
--		kobject_unregister(&edac_pci_top_main_kobj);
-+		kobject_put(&edac_pci_top_main_kobj);
+-	if (i2c_wait(i2c, timeout, 1) < 0)
+-		return -1;
++	result = i2c_wait(i2c, timeout, 1);
++	if (result < 0)
++		return result;
+ 
+ 	if (length) {
+ 		if (length == 1)
+@@ -234,8 +237,9 @@ static int mpc_read(struct mpc_i2c *i2c, int target,
  	}
- }
  
-diff --git a/drivers/firewire/fw-sbp2.c b/drivers/firewire/fw-sbp2.c
-index 624ff3e..c2169d2 100644
---- a/drivers/firewire/fw-sbp2.c
-+++ b/drivers/firewire/fw-sbp2.c
-@@ -1238,6 +1238,12 @@ static int sbp2_scsi_slave_alloc(struct scsi_device *sdev)
+ 	for (i = 0; i < length; i++) {
+-		if (i2c_wait(i2c, timeout, 0) < 0)
+-			return -1;
++		result = i2c_wait(i2c, timeout, 0);
++		if (result < 0)
++			return result;
  
- 	sdev->allow_restart = 1;
+ 		/* Generate txack on next to last byte */
+ 		if (i == length - 2)
+@@ -309,7 +313,6 @@ static struct i2c_adapter mpc_ops = {
+ 	.algo = &mpc_algo,
+ 	.class = I2C_CLASS_HWMON,
+ 	.timeout = 1,
+-	.retries = 1
+ };
  
-+	/*
-+	 * Update the dma alignment (minimum alignment requirements for
-+	 * start and end of DMA transfers) to be a sector
-+	 */
-+	blk_queue_update_dma_alignment(sdev->request_queue, 511);
-+
- 	if (lu->tgt->workarounds & SBP2_WORKAROUND_INQUIRY_36)
- 		sdev->inquiry_len = 36;
+ static int fsl_i2c_probe(struct platform_device *pdev)
+@@ -321,9 +324,9 @@ static int fsl_i2c_probe(struct platform_device *pdev)
  
-diff --git a/drivers/firmware/edd.c b/drivers/firmware/edd.c
-index 6942e06..d168223 100644
---- a/drivers/firmware/edd.c
-+++ b/drivers/firmware/edd.c
-@@ -631,7 +631,7 @@ static struct kobj_type edd_ktype = {
- 	.default_attrs	= def_attrs,
- };
+ 	pdata = (struct fsl_i2c_platform_data *) pdev->dev.platform_data;
  
--static decl_subsys(edd, &edd_ktype, NULL);
-+static struct kset *edd_kset;
+-	if (!(i2c = kzalloc(sizeof(*i2c), GFP_KERNEL))) {
++	i2c = kzalloc(sizeof(*i2c), GFP_KERNEL);
++	if (!i2c)
+ 		return -ENOMEM;
+-	}
  
+ 	i2c->irq = platform_get_irq(pdev, 0);
+ 	if (i2c->irq < 0) {
+diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c
+index bb7bf68..036e6a8 100644
+--- a/drivers/i2c/busses/i2c-mv64xxx.c
++++ b/drivers/i2c/busses/i2c-mv64xxx.c
+@@ -1,6 +1,6 @@
+ /*
+- * Driver for the i2c controller on the Marvell line of host bridges for MIPS
+- * and PPC (e.g, gt642[46]0, mv643[46]0, mv644[46]0).
++ * Driver for the i2c controller on the Marvell line of host bridges
++ * (e.g, gt642[46]0, mv643[46]0, mv644[46]0, and Orion SoC family).
+  *
+  * Author: Mark A. Greer <mgreer at mvista.com>
+  *
+@@ -14,7 +14,7 @@
+ #include <linux/spinlock.h>
+ #include <linux/i2c.h>
+ #include <linux/interrupt.h>
+-#include <linux/mv643xx.h>
++#include <linux/mv643xx_i2c.h>
+ #include <linux/platform_device.h>
  
- /**
-@@ -693,7 +693,7 @@ edd_create_symlink_to_pcidev(struct edd_device *edev)
- static inline void
- edd_device_unregister(struct edd_device *edev)
+ #include <asm/io.h>
+@@ -86,6 +86,7 @@ struct mv64xxx_i2c_data {
+ 	u32			cntl_bits;
+ 	void __iomem		*reg_base;
+ 	u32			reg_base_p;
++	u32			reg_size;
+ 	u32			addr1;
+ 	u32			addr2;
+ 	u32			bytes_left;
+@@ -463,17 +464,20 @@ static int __devinit
+ mv64xxx_i2c_map_regs(struct platform_device *pd,
+ 	struct mv64xxx_i2c_data *drv_data)
  {
--	kobject_unregister(&edev->kobj);
-+	kobject_put(&edev->kobj);
- }
+-	struct resource	*r;
++	int size;
++	struct resource	*r = platform_get_resource(pd, IORESOURCE_MEM, 0);
  
- static void edd_populate_dir(struct edd_device * edev)
-@@ -721,12 +721,13 @@ edd_device_register(struct edd_device *edev, int i)
- 	if (!edev)
- 		return 1;
- 	edd_dev_set_info(edev, i);
--	kobject_set_name(&edev->kobj, "int13_dev%02x",
--			 0x80 + i);
--	kobj_set_kset_s(edev,edd_subsys);
--	error = kobject_register(&edev->kobj);
--	if (!error)
-+	edev->kobj.kset = edd_kset;
-+	error = kobject_init_and_add(&edev->kobj, &edd_ktype, NULL,
-+				     "int13_dev%02x", 0x80 + i);
-+	if (!error) {
- 		edd_populate_dir(edev);
-+		kobject_uevent(&edev->kobj, KOBJ_ADD);
-+	}
- 	return error;
+-	if ((r = platform_get_resource(pd, IORESOURCE_MEM, 0)) &&
+-		request_mem_region(r->start, MV64XXX_I2C_REG_BLOCK_SIZE,
+-			drv_data->adapter.name)) {
++	if (!r)
++		return -ENODEV;
+ 
+-		drv_data->reg_base = ioremap(r->start,
+-			MV64XXX_I2C_REG_BLOCK_SIZE);
+-		drv_data->reg_base_p = r->start;
+-	} else
+-		return -ENOMEM;
++	size = r->end - r->start + 1;
++
++	if (!request_mem_region(r->start, size, drv_data->adapter.name))
++		return -EBUSY;
++
++	drv_data->reg_base = ioremap(r->start, size);
++	drv_data->reg_base_p = r->start;
++	drv_data->reg_size = size;
+ 
+ 	return 0;
  }
+@@ -483,8 +487,7 @@ mv64xxx_i2c_unmap_regs(struct mv64xxx_i2c_data *drv_data)
+ {
+ 	if (drv_data->reg_base) {
+ 		iounmap(drv_data->reg_base);
+-		release_mem_region(drv_data->reg_base_p,
+-			MV64XXX_I2C_REG_BLOCK_SIZE);
++		release_mem_region(drv_data->reg_base_p, drv_data->reg_size);
+ 	}
+ 
+ 	drv_data->reg_base = NULL;
+@@ -529,7 +532,6 @@ mv64xxx_i2c_probe(struct platform_device *pd)
+ 	drv_data->adapter.owner = THIS_MODULE;
+ 	drv_data->adapter.class = I2C_CLASS_HWMON;
+ 	drv_data->adapter.timeout = pdata->timeout;
+-	drv_data->adapter.retries = pdata->retries;
+ 	drv_data->adapter.nr = pd->id;
+ 	platform_set_drvdata(pd, drv_data);
+ 	i2c_set_adapdata(&drv_data->adapter, drv_data);
+diff --git a/drivers/i2c/busses/i2c-nforce2.c b/drivers/i2c/busses/i2c-nforce2.c
+index 1bf590c..3dac920 100644
+--- a/drivers/i2c/busses/i2c-nforce2.c
++++ b/drivers/i2c/busses/i2c-nforce2.c
+@@ -351,6 +351,7 @@ static int __devinit nforce2_probe(struct pci_dev *dev, const struct pci_device_
+ 	pci_set_drvdata(dev, smbuses);
  
-@@ -755,9 +756,9 @@ edd_init(void)
- 		return 1;
- 	}
+ 	switch(dev->device) {
++	case PCI_DEVICE_ID_NVIDIA_NFORCE2_SMBUS:
+ 	case PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SMBUS:
+ 	case PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SMBUS:
+ 		smbuses[0].blockops = 1;
+diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c
+index f2552b1..da66397 100644
+--- a/drivers/i2c/busses/i2c-omap.c
++++ b/drivers/i2c/busses/i2c-omap.c
+@@ -362,8 +362,6 @@ omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
  
--	rc = firmware_register(&edd_subsys);
--	if (rc)
--		return rc;
-+	edd_kset = kset_create_and_add("edd", NULL, firmware_kobj);
-+	if (!edd_kset)
-+		return -ENOMEM;
+ 	omap_i2c_enable_clocks(dev);
  
- 	for (i = 0; i < edd_num_devices() && !rc; i++) {
- 		edev = kzalloc(sizeof (*edev), GFP_KERNEL);
-@@ -773,7 +774,7 @@ edd_init(void)
- 	}
+-	/* REVISIT: initialize and use adap->retries. This is an optional
+-	 * feature */
+ 	if ((r = omap_i2c_wait_for_bb(dev)) < 0)
+ 		goto out;
  
- 	if (rc)
--		firmware_unregister(&edd_subsys);
-+		kset_unregister(edd_kset);
- 	return rc;
- }
+diff --git a/drivers/i2c/busses/i2c-pasemi.c b/drivers/i2c/busses/i2c-pasemi.c
+index ca18e0b..1603c81 100644
+--- a/drivers/i2c/busses/i2c-pasemi.c
++++ b/drivers/i2c/busses/i2c-pasemi.c
+@@ -368,6 +368,7 @@ static int __devinit pasemi_smb_probe(struct pci_dev *dev,
+ 	smbus->adapter.class = I2C_CLASS_HWMON;
+ 	smbus->adapter.algo = &smbus_algorithm;
+ 	smbus->adapter.algo_data = smbus;
++	smbus->adapter.nr = PCI_FUNC(dev->devfn);
  
-@@ -787,7 +788,7 @@ edd_exit(void)
- 		if ((edev = edd_devices[i]))
- 			edd_device_unregister(edev);
- 	}
--	firmware_unregister(&edd_subsys);
-+	kset_unregister(edd_kset);
- }
+ 	/* set up the sysfs linkage to our parent device */
+ 	smbus->adapter.dev.parent = &dev->dev;
+@@ -375,7 +376,7 @@ static int __devinit pasemi_smb_probe(struct pci_dev *dev,
+ 	reg_write(smbus, REG_CTL, (CTL_MTR | CTL_MRR |
+ 		  (CLK_100K_DIV & CTL_CLK_M)));
  
- late_initcall(edd_init);
-diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c
-index 858a7b9..f4f709d 100644
---- a/drivers/firmware/efivars.c
-+++ b/drivers/firmware/efivars.c
-@@ -129,13 +129,6 @@ struct efivar_attribute {
- };
+-	error = i2c_add_adapter(&smbus->adapter);
++	error = i2c_add_numbered_adapter(&smbus->adapter);
+ 	if (error)
+ 		goto out_release_region;
  
+diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c
+index 167e413..9bbe96c 100644
+--- a/drivers/i2c/busses/i2c-piix4.c
++++ b/drivers/i2c/busses/i2c-piix4.c
+@@ -121,10 +121,6 @@ static int __devinit piix4_setup(struct pci_dev *PIIX4_dev,
+ {
+ 	unsigned char temp;
  
--#define EFI_ATTR(_name, _mode, _show, _store) \
--struct subsys_attribute efi_attr_##_name = { \
--	.attr = {.name = __stringify(_name), .mode = _mode}, \
--	.show = _show, \
--	.store = _store, \
--};
+-	/* match up the function */
+-	if (PCI_FUNC(PIIX4_dev->devfn) != id->driver_data)
+-		return -ENODEV;
 -
- #define EFIVAR_ATTR(_name, _mode, _show, _store) \
- struct efivar_attribute efivar_attr_##_name = { \
- 	.attr = {.name = __stringify(_name), .mode = _mode}, \
-@@ -143,13 +136,6 @@ struct efivar_attribute efivar_attr_##_name = { \
- 	.store = _store, \
+ 	dev_info(&PIIX4_dev->dev, "Found %s device\n", pci_name(PIIX4_dev));
+ 
+ 	/* Don't access SMBus on IBM systems which get corrupted eeproms */
+@@ -389,28 +385,21 @@ static struct i2c_adapter piix4_adapter = {
  };
  
--#define VAR_SUBSYS_ATTR(_name, _mode, _show, _store) \
--struct subsys_attribute var_subsys_attr_##_name = { \
--	.attr = {.name = __stringify(_name), .mode = _mode}, \
--	.show = _show, \
--	.store = _store, \
--};
--
- #define to_efivar_attr(_attr) container_of(_attr, struct efivar_attribute, attr)
- #define to_efivar_entry(obj)  container_of(obj, struct efivar_entry, kobj)
+ static struct pci_device_id piix4_ids[] = {
+-	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3),
+-	  .driver_data = 3 },
+-	{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP200_SMBUS),
+-	  .driver_data = 0 },
+-	{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP300_SMBUS),
+-	  .driver_data = 0 },
+-	{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP400_SMBUS),
+-	  .driver_data = 0 },
+-	{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_SBX00_SMBUS),
+-	  .driver_data = 0 },
+-	{ PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4),
+-	  .driver_data = 0 },
+-	{ PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5),
+-	  .driver_data = 0 },
+-	{ PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6),
+-	  .driver_data = 0 },
+-	{ PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_HT1000SB),
+-	  .driver_data = 0 },
+-	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_3),
+-	  .driver_data = 3 },
+-	{ PCI_DEVICE(PCI_VENDOR_ID_EFAR, PCI_DEVICE_ID_EFAR_SLC90E66_3),
+-	  .driver_data = 0 },
++	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3) },
++	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_3) },
++	{ PCI_DEVICE(PCI_VENDOR_ID_EFAR, PCI_DEVICE_ID_EFAR_SLC90E66_3) },
++	{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP200_SMBUS) },
++	{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP300_SMBUS) },
++	{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP400_SMBUS) },
++	{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_SBX00_SMBUS) },
++	{ PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS,
++		     PCI_DEVICE_ID_SERVERWORKS_OSB4) },
++	{ PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS,
++		     PCI_DEVICE_ID_SERVERWORKS_CSB5) },
++	{ PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS,
++		     PCI_DEVICE_ID_SERVERWORKS_CSB6) },
++	{ PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS,
++		     PCI_DEVICE_ID_SERVERWORKS_HT1000SB) },
+ 	{ 0, }
+ };
  
-@@ -408,21 +394,16 @@ static struct kobj_type efivar_ktype = {
- 	.default_attrs = def_attrs,
+diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c
+index 6426a61..2598d29 100644
+--- a/drivers/i2c/busses/i2c-pxa.c
++++ b/drivers/i2c/busses/i2c-pxa.c
+@@ -65,6 +65,7 @@ struct pxa_i2c {
+ 	unsigned long		iosize;
+ 
+ 	int			irq;
++	int			use_pio;
  };
  
--static ssize_t
--dummy(struct kset *kset, char *buf)
--{
--	return -ENODEV;
--}
--
- static inline void
- efivar_unregister(struct efivar_entry *var)
- {
--	kobject_unregister(&var->kobj);
-+	kobject_put(&var->kobj);
- }
+ #define _IBMR(i2c)	((i2c)->reg_base + 0)
+@@ -163,6 +164,7 @@ static void i2c_pxa_show_state(struct pxa_i2c *i2c, int lno, const char *fname)
+ #define eedbg(lvl, x...) do { if ((lvl) < 1) { printk(KERN_DEBUG "" x); } } while(0)
  
+ static void i2c_pxa_master_complete(struct pxa_i2c *i2c, int ret);
++static irqreturn_t i2c_pxa_handler(int this_irq, void *dev_id);
  
--static ssize_t
--efivar_create(struct kset *kset, const char *buf, size_t count)
-+static ssize_t efivar_create(struct kobject *kobj,
-+			     struct bin_attribute *bin_attr,
-+			     char *buf, loff_t pos, size_t count)
+ static void i2c_pxa_scream_blue_murder(struct pxa_i2c *i2c, const char *why)
  {
- 	struct efi_variable *new_var = (struct efi_variable *)buf;
- 	struct efivar_entry *search_efivar, *n;
-@@ -479,8 +460,9 @@ efivar_create(struct kset *kset, const char *buf, size_t count)
- 	return count;
+@@ -554,6 +556,71 @@ static inline void i2c_pxa_stop_message(struct pxa_i2c *i2c)
+ 	writel(icr, _ICR(i2c));
  }
  
--static ssize_t
--efivar_delete(struct kset *kset, const char *buf, size_t count)
-+static ssize_t efivar_delete(struct kobject *kobj,
-+			     struct bin_attribute *bin_attr,
-+			     char *buf, loff_t pos, size_t count)
- {
- 	struct efi_variable *del_var = (struct efi_variable *)buf;
- 	struct efivar_entry *search_efivar, *n;
-@@ -537,25 +519,26 @@ efivar_delete(struct kset *kset, const char *buf, size_t count)
- 	return count;
++static int i2c_pxa_pio_set_master(struct pxa_i2c *i2c)
++{
++	/* make timeout the same as for interrupt based functions */
++	long timeout = 2 * DEF_TIMEOUT;
++
++	/*
++	 * Wait for the bus to become free.
++	 */
++	while (timeout-- && readl(_ISR(i2c)) & (ISR_IBB | ISR_UB)) {
++		udelay(1000);
++		show_state(i2c);
++	}
++
++	if (timeout <= 0) {
++		show_state(i2c);
++		dev_err(&i2c->adap.dev,
++			"i2c_pxa: timeout waiting for bus free\n");
++		return I2C_RETRY;
++	}
++
++	/*
++	 * Set master mode.
++	 */
++	writel(readl(_ICR(i2c)) | ICR_SCLE, _ICR(i2c));
++
++	return 0;
++}
++
++static int i2c_pxa_do_pio_xfer(struct pxa_i2c *i2c,
++			       struct i2c_msg *msg, int num)
++{
++	unsigned long timeout = 500000; /* 5 seconds */
++	int ret = 0;
++
++	ret = i2c_pxa_pio_set_master(i2c);
++	if (ret)
++		goto out;
++
++	i2c->msg = msg;
++	i2c->msg_num = num;
++	i2c->msg_idx = 0;
++	i2c->msg_ptr = 0;
++	i2c->irqlogidx = 0;
++
++	i2c_pxa_start_message(i2c);
++
++	while (timeout-- && i2c->msg_num > 0) {
++		i2c_pxa_handler(0, i2c);
++		udelay(10);
++	}
++
++	i2c_pxa_stop_message(i2c);
++
++	/*
++	 * We place the return code in i2c->msg_idx.
++	 */
++	ret = i2c->msg_idx;
++
++out:
++	if (timeout == 0)
++		i2c_pxa_scream_blue_murder(i2c, "timeout");
++
++	return ret;
++}
++
+ /*
+  * We are protected by the adapter bus mutex.
+  */
+@@ -610,6 +677,35 @@ static int i2c_pxa_do_xfer(struct pxa_i2c *i2c, struct i2c_msg *msg, int num)
+ 	return ret;
  }
  
--static VAR_SUBSYS_ATTR(new_var, 0200, dummy, efivar_create);
--static VAR_SUBSYS_ATTR(del_var, 0200, dummy, efivar_delete);
-+static struct bin_attribute var_subsys_attr_new_var = {
-+	.attr = {.name = "new_var", .mode = 0200},
-+	.write = efivar_create,
-+};
- 
--static struct subsys_attribute *var_subsys_attrs[] = {
--	&var_subsys_attr_new_var,
--	&var_subsys_attr_del_var,
--	NULL,
-+static struct bin_attribute var_subsys_attr_del_var = {
-+	.attr = {.name = "del_var", .mode = 0200},
-+	.write = efivar_delete,
- };
- 
++static int i2c_pxa_pio_xfer(struct i2c_adapter *adap,
++			    struct i2c_msg msgs[], int num)
++{
++	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_pio_xfer(i2c, msgs, num);
++		if (ret != I2C_RETRY)
++			goto out;
++
++		if (i2c_debug)
++			dev_dbg(&adap->dev, "Retrying transmission\n");
++		udelay(100);
++	}
++	i2c_pxa_scream_blue_murder(i2c, "exhausted retries");
++	ret = -EREMOTEIO;
++ out:
++	i2c_pxa_set_slave(i2c, ret);
++	return ret;
++}
++
  /*
-  * Let's not leave out systab information that snuck into
-  * the efivars driver
+  * i2c_pxa_master_complete - complete the message and wake up.
   */
--static ssize_t
--systab_read(struct kset *kset, char *buf)
-+static ssize_t systab_show(struct kobject *kobj,
-+			   struct kobj_attribute *attr, char *buf)
- {
- 	char *str = buf;
- 
--	if (!kset || !buf)
-+	if (!kobj || !buf)
- 		return -EINVAL;
- 
- 	if (efi.mps != EFI_INVALID_TABLE_ADDR)
-@@ -576,15 +559,21 @@ systab_read(struct kset *kset, char *buf)
- 	return str - buf;
+@@ -621,7 +717,8 @@ static void i2c_pxa_master_complete(struct pxa_i2c *i2c, int ret)
+ 	i2c->msg_num = 0;
+ 	if (ret)
+ 		i2c->msg_idx = ret;
+-	wake_up(&i2c->wait);
++	if (!i2c->use_pio)
++		wake_up(&i2c->wait);
  }
  
--static EFI_ATTR(systab, 0400, systab_read, NULL);
-+static struct kobj_attribute efi_attr_systab =
-+			__ATTR(systab, 0400, systab_show, NULL);
- 
--static struct subsys_attribute *efi_subsys_attrs[] = {
--	&efi_attr_systab,
-+static struct attribute *efi_subsys_attrs[] = {
-+	&efi_attr_systab.attr,
- 	NULL,	/* maybe more in the future? */
+ static void i2c_pxa_irq_txempty(struct pxa_i2c *i2c, u32 isr)
+@@ -840,6 +937,37 @@ static const struct i2c_algorithm i2c_pxa_algorithm = {
+ 	.functionality	= i2c_pxa_functionality,
  };
  
--static decl_subsys(vars, &efivar_ktype, NULL);
--static decl_subsys(efi, NULL, NULL);
-+static struct attribute_group efi_subsys_attr_group = {
-+	.attrs = efi_subsys_attrs,
++static const struct i2c_algorithm i2c_pxa_pio_algorithm = {
++	.master_xfer	= i2c_pxa_pio_xfer,
++	.functionality	= i2c_pxa_functionality,
 +};
 +
++static void i2c_pxa_enable(struct platform_device *dev)
++{
++	if (cpu_is_pxa27x()) {
++		switch (dev->id) {
++		case 0:
++			pxa_gpio_mode(GPIO117_I2CSCL_MD);
++			pxa_gpio_mode(GPIO118_I2CSDA_MD);
++			break;
++		case 1:
++			local_irq_disable();
++			PCFR |= PCFR_PI2CEN;
++			local_irq_enable();
++			break;
++		}
++	}
++}
 +
-+static struct kset *vars_kset;
-+static struct kobject *efi_kobj;
- 
- /*
-  * efivar_create_sysfs_entry()
-@@ -628,15 +617,16 @@ efivar_create_sysfs_entry(unsigned long variable_name_size,
- 	*(short_name + strlen(short_name)) = '-';
- 	efi_guid_unparse(vendor_guid, short_name + strlen(short_name));
- 
--	kobject_set_name(&new_efivar->kobj, "%s", short_name);
--	kobj_set_kset_s(new_efivar, vars_subsys);
--	i = kobject_register(&new_efivar->kobj);
-+	new_efivar->kobj.kset = vars_kset;
-+	i = kobject_init_and_add(&new_efivar->kobj, &efivar_ktype, NULL,
-+				 "%s", short_name);
- 	if (i) {
- 		kfree(short_name);
- 		kfree(new_efivar);
- 		return 1;
- 	}
- 
-+	kobject_uevent(&new_efivar->kobj, KOBJ_ADD);
- 	kfree(short_name);
- 	short_name = NULL;
- 
-@@ -660,9 +650,8 @@ efivars_init(void)
- 	efi_status_t status = EFI_NOT_FOUND;
- 	efi_guid_t vendor_guid;
- 	efi_char16_t *variable_name;
--	struct subsys_attribute *attr;
- 	unsigned long variable_name_size = 1024;
--	int i, error = 0;
-+	int error = 0;
- 
- 	if (!efi_enabled)
- 		return -ENODEV;
-@@ -676,23 +665,18 @@ efivars_init(void)
- 	printk(KERN_INFO "EFI Variables Facility v%s %s\n", EFIVARS_VERSION,
- 	       EFIVARS_DATE);
- 
--	/*
--	 * For now we'll register the efi subsys within this driver
--	 */
--
--	error = firmware_register(&efi_subsys);
--
--	if (error) {
--		printk(KERN_ERR "efivars: Firmware registration failed with error %d.\n", error);
-+	/* For now we'll register the efi directory at /sys/firmware/efi */
-+	efi_kobj = kobject_create_and_add("efi", firmware_kobj);
-+	if (!efi_kobj) {
-+		printk(KERN_ERR "efivars: Firmware registration failed.\n");
-+		error = -ENOMEM;
- 		goto out_free;
- 	}
- 
--	kobj_set_kset_s(&vars_subsys, efi_subsys);
--
--	error = subsystem_register(&vars_subsys);
--
--	if (error) {
--		printk(KERN_ERR "efivars: Subsystem registration failed with error %d.\n", error);
-+	vars_kset = kset_create_and_add("vars", NULL, efi_kobj);
-+	if (!vars_kset) {
-+		printk(KERN_ERR "efivars: Subsystem registration failed.\n");
-+		error = -ENOMEM;
- 		goto out_firmware_unregister;
- 	}
- 
-@@ -727,28 +711,28 @@ efivars_init(void)
- 	 * Now add attributes to allow creation of new vars
- 	 * and deletion of existing ones...
- 	 */
--
--	for (i = 0; (attr = var_subsys_attrs[i]) && !error; i++) {
--		if (attr->show && attr->store)
--			error = subsys_create_file(&vars_subsys, attr);
--	}
-+	error = sysfs_create_bin_file(&vars_kset->kobj,
-+				      &var_subsys_attr_new_var);
-+	if (error)
-+		printk(KERN_ERR "efivars: unable to create new_var sysfs file"
-+			" due to error %d\n", error);
-+	error = sysfs_create_bin_file(&vars_kset->kobj,
-+				      &var_subsys_attr_del_var);
-+	if (error)
-+		printk(KERN_ERR "efivars: unable to create del_var sysfs file"
-+			" due to error %d\n", error);
- 
- 	/* Don't forget the systab entry */
--
--	for (i = 0; (attr = efi_subsys_attrs[i]) && !error; i++) {
--		if (attr->show)
--			error = subsys_create_file(&efi_subsys, attr);
--	}
--
-+	error = sysfs_create_group(efi_kobj, &efi_subsys_attr_group);
- 	if (error)
- 		printk(KERN_ERR "efivars: Sysfs attribute export failed with error %d.\n", error);
- 	else
- 		goto out_free;
- 
--	subsystem_unregister(&vars_subsys);
-+	kset_unregister(vars_kset);
- 
- out_firmware_unregister:
--	firmware_unregister(&efi_subsys);
-+	kobject_put(efi_kobj);
- 
- out_free:
- 	kfree(variable_name);
-@@ -768,8 +752,8 @@ efivars_exit(void)
- 		efivar_unregister(entry);
- 	}
- 
--	subsystem_unregister(&vars_subsys);
--	firmware_unregister(&efi_subsys);
-+	kset_unregister(vars_kset);
-+	kobject_put(efi_kobj);
- }
- 
- module_init(efivars_init);
-diff --git a/drivers/i2c/algos/i2c-algo-bit.c b/drivers/i2c/algos/i2c-algo-bit.c
-index a37cb6b..3581282 100644
---- a/drivers/i2c/algos/i2c-algo-bit.c
-+++ b/drivers/i2c/algos/i2c-algo-bit.c
-@@ -1,7 +1,7 @@
--/* ------------------------------------------------------------------------- */
--/* i2c-algo-bit.c i2c driver algorithms for bit-shift adapters		     */
--/* ------------------------------------------------------------------------- */
--/*   Copyright (C) 1995-2000 Simon G. Vogl
-+/* -------------------------------------------------------------------------
-+ * i2c-algo-bit.c i2c driver algorithms for bit-shift adapters
-+ * -------------------------------------------------------------------------
-+ *   Copyright (C) 1995-2000 Simon G. Vogl
- 
-     This program is free software; you can redistribute it and/or modify
-     it under the terms of the GNU General Public License as published by
-@@ -15,8 +15,8 @@
++static void i2c_pxa_disable(struct platform_device *dev)
++{
++	if (cpu_is_pxa27x() && dev->id == 1) {
++		local_irq_disable();
++		PCFR &= ~PCFR_PI2CEN;
++		local_irq_enable();
++	}
++}
++
+ #define res_len(r)		((r)->end - (r)->start + 1)
+ static int i2c_pxa_probe(struct platform_device *dev)
+ {
+@@ -864,7 +992,6 @@ static int i2c_pxa_probe(struct platform_device *dev)
+ 	}
  
-     You 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.		     */
--/* ------------------------------------------------------------------------- */
-+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-+ * ------------------------------------------------------------------------- */
+ 	i2c->adap.owner   = THIS_MODULE;
+-	i2c->adap.algo    = &i2c_pxa_algorithm;
+ 	i2c->adap.retries = 5;
  
- /* With some changes from Frodo Looijaard <frodol at dds.nl>, Kyösti Mälkki
-    <kmalkki at cc.hut.fi> and Jean Delvare <khali at linux-fr.org> */
-@@ -60,26 +60,26 @@ MODULE_PARM_DESC(i2c_debug,
+ 	spin_lock_init(&i2c->lock);
+@@ -899,34 +1026,28 @@ static int i2c_pxa_probe(struct platform_device *dev)
+ #endif
  
- /* --- setting states on the bus with the right timing: ---------------	*/
+ 	clk_enable(i2c->clk);
+-#ifdef CONFIG_PXA27x
+-	switch (dev->id) {
+-	case 0:
+-		pxa_gpio_mode(GPIO117_I2CSCL_MD);
+-		pxa_gpio_mode(GPIO118_I2CSDA_MD);
+-		break;
+-	case 1:
+-		local_irq_disable();
+-		PCFR |= PCFR_PI2CEN;
+-		local_irq_enable();
+-	}
+-#endif
++	i2c_pxa_enable(dev);
  
--#define setsda(adap,val) adap->setsda(adap->data, val)
--#define setscl(adap,val) adap->setscl(adap->data, val)
--#define getsda(adap) adap->getsda(adap->data)
--#define getscl(adap) adap->getscl(adap->data)
-+#define setsda(adap, val)	adap->setsda(adap->data, val)
-+#define setscl(adap, val)	adap->setscl(adap->data, val)
-+#define getsda(adap)		adap->getsda(adap->data)
-+#define getscl(adap)		adap->getscl(adap->data)
+-	ret = request_irq(irq, i2c_pxa_handler, IRQF_DISABLED,
+-			  i2c->adap.name, i2c);
+-	if (ret)
+-		goto ereqirq;
++	if (plat) {
++		i2c->adap.class = plat->class;
++		i2c->use_pio = plat->use_pio;
++	}
  
- static inline void sdalo(struct i2c_algo_bit_data *adap)
- {
--	setsda(adap,0);
-+	setsda(adap, 0);
- 	udelay((adap->udelay + 1) / 2);
- }
++	if (i2c->use_pio) {
++		i2c->adap.algo = &i2c_pxa_pio_algorithm;
++	} else {
++		i2c->adap.algo = &i2c_pxa_algorithm;
++		ret = request_irq(irq, i2c_pxa_handler, IRQF_DISABLED,
++				  i2c->adap.name, i2c);
++		if (ret)
++			goto ereqirq;
++	}
  
- static inline void sdahi(struct i2c_algo_bit_data *adap)
- {
--	setsda(adap,1);
-+	setsda(adap, 1);
- 	udelay((adap->udelay + 1) / 2);
- }
+ 	i2c_pxa_reset(i2c);
  
- static inline void scllo(struct i2c_algo_bit_data *adap)
- {
--	setscl(adap,0);
-+	setscl(adap, 0);
- 	udelay(adap->udelay / 2);
- }
+ 	i2c->adap.algo_data = i2c;
+ 	i2c->adap.dev.parent = &dev->dev;
  
-@@ -91,22 +91,21 @@ static int sclhi(struct i2c_algo_bit_data *adap)
- {
- 	unsigned long start;
+-	if (plat) {
+-		i2c->adap.class = plat->class;
+-	}
+-
+ 	/*
+ 	 * If "dev->id" is negative we consider it as zero.
+ 	 * The reason to do so is to avoid sysfs names that only make
+@@ -952,17 +1073,11 @@ static int i2c_pxa_probe(struct platform_device *dev)
+ 	return 0;
  
--	setscl(adap,1);
-+	setscl(adap, 1);
+ eadapt:
+-	free_irq(irq, i2c);
++	if (!i2c->use_pio)
++		free_irq(irq, i2c);
+ ereqirq:
+ 	clk_disable(i2c->clk);
+-
+-#ifdef CONFIG_PXA27x
+-	if (dev->id == 1) {
+-		local_irq_disable();
+-		PCFR &= ~PCFR_PI2CEN;
+-		local_irq_enable();
+-	}
+-#endif
++	i2c_pxa_disable(dev);
+ eremap:
+ 	clk_put(i2c->clk);
+ eclk:
+@@ -979,18 +1094,12 @@ static int i2c_pxa_remove(struct platform_device *dev)
+ 	platform_set_drvdata(dev, NULL);
  
- 	/* Not all adapters have scl sense line... */
- 	if (!adap->getscl)
- 		goto done;
+ 	i2c_del_adapter(&i2c->adap);
+-	free_irq(i2c->irq, i2c);
++	if (!i2c->use_pio)
++		free_irq(i2c->irq, i2c);
  
--	start=jiffies;
--	while (! getscl(adap) ) {	
-- 		/* the hw knows how to read the clock line,
-- 		 * so we wait until it actually gets high.
-- 		 * This is safer as some chips may hold it low
-- 		 * while they are processing data internally. 
-- 		 */
--		if (time_after_eq(jiffies, start+adap->timeout)) {
-+	start = jiffies;
-+	while (!getscl(adap)) {
-+		/* This hw knows how to read the clock line, so we wait
-+		 * until it actually gets high.  This is safer as some
-+		 * chips may hold it low ("clock stretching") while they
-+		 * are processing data internally.
-+		 */
-+		if (time_after_eq(jiffies, start + adap->timeout))
- 			return -ETIMEDOUT;
--		}
- 		cond_resched();
- 	}
- #ifdef DEBUG
-@@ -118,11 +117,11 @@ static int sclhi(struct i2c_algo_bit_data *adap)
- done:
- 	udelay(adap->udelay);
- 	return 0;
--} 
-+}
+ 	clk_disable(i2c->clk);
+ 	clk_put(i2c->clk);
+-
+-#ifdef CONFIG_PXA27x
+-	if (dev->id == 1) {
+-		local_irq_disable();
+-		PCFR &= ~PCFR_PI2CEN;
+-		local_irq_enable();
+-	}
+-#endif
++	i2c_pxa_disable(dev);
  
+ 	release_mem_region(i2c->iobase, i2c->iosize);
+ 	kfree(i2c);
+diff --git a/drivers/i2c/busses/i2c-sibyte.c b/drivers/i2c/busses/i2c-sibyte.c
+index 503a134..8fbbdb4 100644
+--- a/drivers/i2c/busses/i2c-sibyte.c
++++ b/drivers/i2c/busses/i2c-sibyte.c
+@@ -36,14 +36,6 @@ struct i2c_algo_sibyte_data {
+ /* ----- global defines ----------------------------------------------- */
+ #define SMB_CSR(a,r) ((long)(a->reg_base + r))
  
- /* --- other auxiliary functions --------------------------------------	*/
--static void i2c_start(struct i2c_algo_bit_data *adap) 
-+static void i2c_start(struct i2c_algo_bit_data *adap)
- {
- 	/* assert: scl, sda are high */
- 	setsda(adap, 0);
-@@ -130,7 +129,7 @@ static void i2c_start(struct i2c_algo_bit_data *adap)
- 	scllo(adap);
- }
+-/* ----- global variables --------------------------------------------- */
+-
+-/* module parameters:
+- */
+-static int bit_scan;	/* have a look at what's hanging 'round */
+-module_param(bit_scan, int, 0);
+-MODULE_PARM_DESC(bit_scan, "Scan for active chips on the bus");
+-
  
--static void i2c_repstart(struct i2c_algo_bit_data *adap) 
-+static void i2c_repstart(struct i2c_algo_bit_data *adap)
+ static int smbus_xfer(struct i2c_adapter *i2c_adap, u16 addr,
+ 		      unsigned short flags, char read_write,
+@@ -140,9 +132,8 @@ static const struct i2c_algorithm i2c_sibyte_algo = {
+ /*
+  * registering functions to load algorithms at runtime
+  */
+-int i2c_sibyte_add_bus(struct i2c_adapter *i2c_adap, int speed)
++int __init i2c_sibyte_add_bus(struct i2c_adapter *i2c_adap, int speed)
  {
- 	/* assert: scl is low */
- 	sdahi(adap);
-@@ -141,18 +140,18 @@ static void i2c_repstart(struct i2c_algo_bit_data *adap)
- }
+-	int i;
+ 	struct i2c_algo_sibyte_data *adap = i2c_adap->algo_data;
  
+ 	/* register new adapter to i2c module... */
+@@ -152,24 +143,6 @@ int i2c_sibyte_add_bus(struct i2c_adapter *i2c_adap, int speed)
+ 	csr_out32(speed, SMB_CSR(adap,R_SMB_FREQ));
+ 	csr_out32(0, SMB_CSR(adap,R_SMB_CONTROL));
  
--static void i2c_stop(struct i2c_algo_bit_data *adap) 
-+static void i2c_stop(struct i2c_algo_bit_data *adap)
- {
- 	/* assert: scl is low */
- 	sdalo(adap);
--	sclhi(adap); 
-+	sclhi(adap);
- 	setsda(adap, 1);
- 	udelay(adap->udelay);
+-	/* scan bus */
+-	if (bit_scan) {
+-		union i2c_smbus_data data;
+-		int rc;
+-		printk(KERN_INFO " i2c-algo-sibyte.o: scanning bus %s.\n",
+-		       i2c_adap->name);
+-		for (i = 0x00; i < 0x7f; i++) {
+-			/* XXXKW is this a realistic probe? */
+-			rc = smbus_xfer(i2c_adap, i, 0, I2C_SMBUS_READ, 0,
+-					I2C_SMBUS_BYTE_DATA, &data);
+-			if (!rc) {
+-				printk("(%02x)",i);
+-			} else
+-				printk(".");
+-		}
+-		printk("\n");
+-	}
+-
+ 	return i2c_add_adapter(i2c_adap);
  }
  
+diff --git a/drivers/i2c/busses/i2c-stub.c b/drivers/i2c/busses/i2c-stub.c
+index 84df29d..c2a9f8c 100644
+--- a/drivers/i2c/busses/i2c-stub.c
++++ b/drivers/i2c/busses/i2c-stub.c
+@@ -1,8 +1,8 @@
+ /*
+-    i2c-stub.c - Part of lm_sensors, Linux kernel modules for hardware
+-              monitoring
++    i2c-stub.c - I2C/SMBus chip emulator
  
+     Copyright (c) 2004 Mark M. Hoffman <mhoffman at lightlink.com>
++    Copyright (C) 2007 Jean Delvare <khali at linux-fr.org>
  
--/* send a byte without start cond., look for arbitration, 
-+/* send a byte without start cond., look for arbitration,
-    check ackn. from slave */
- /* returns:
-  * 1 if the device acknowledged
-@@ -167,27 +166,33 @@ static int i2c_outb(struct i2c_adapter *i2c_adap, unsigned char c)
- 	struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
+     This program is free software; you can redistribute it and/or modify
+     it under the terms of the GNU General Public License as published by
+@@ -37,8 +37,8 @@ MODULE_PARM_DESC(chip_addr,
  
- 	/* assert: scl is low */
--	for ( i=7 ; i>=0 ; i-- ) {
-+	for (i = 7; i >= 0; i--) {
- 		sb = (c >> i) & 1;
--		setsda(adap,sb);
-+		setsda(adap, sb);
- 		udelay((adap->udelay + 1) / 2);
--		if (sclhi(adap)<0) { /* timed out */
-+		if (sclhi(adap) < 0) { /* timed out */
- 			bit_dbg(1, &i2c_adap->dev, "i2c_outb: 0x%02x, "
- 				"timeout at bit #%d\n", (int)c, i);
- 			return -ETIMEDOUT;
--		};
--		/* do arbitration here: 
--		 * if ( sb && ! getsda(adap) ) -> ouch! Get out of here.
-+		}
-+		/* FIXME do arbitration here:
-+		 * if (sb && !getsda(adap)) -> ouch! Get out of here.
-+		 *
-+		 * Report a unique code, so higher level code can retry
-+		 * the whole (combined) message and *NOT* issue STOP.
- 		 */
- 		scllo(adap);
- 	}
- 	sdahi(adap);
--	if (sclhi(adap)<0){ /* timeout */
-+	if (sclhi(adap) < 0) { /* timeout */
- 		bit_dbg(1, &i2c_adap->dev, "i2c_outb: 0x%02x, "
- 			"timeout at ack\n", (int)c);
- 		return -ETIMEDOUT;
--	};
--	/* read ack: SDA should be pulled down by slave */
-+	}
-+
-+	/* read ack: SDA should be pulled down by slave, or it may
-+	 * NAK (usually to report problems with the data we wrote).
-+	 */
- 	ack = !getsda(adap);    /* ack: sda is pulled low -> success */
- 	bit_dbg(2, &i2c_adap->dev, "i2c_outb: 0x%02x %s\n", (int)c,
- 		ack ? "A" : "NA");
-@@ -198,24 +203,24 @@ static int i2c_outb(struct i2c_adapter *i2c_adap, unsigned char c)
- }
+ struct stub_chip {
+ 	u8 pointer;
+-	u8 bytes[256];
+-	u16 words[256];
++	u16 words[256];		/* Byte operations use the LSB as per SMBus
++				   specification */
+ };
  
+ static struct stub_chip *stub_chips;
+@@ -75,7 +75,7 @@ static s32 stub_xfer(struct i2c_adapter * adap, u16 addr, unsigned short flags,
+ 					"wrote 0x%02x.\n",
+ 					addr, command);
+ 		} else {
+-			data->byte = chip->bytes[chip->pointer++];
++			data->byte = chip->words[chip->pointer++] & 0xff;
+ 			dev_dbg(&adap->dev, "smbus byte - addr 0x%02x, "
+ 					"read  0x%02x.\n",
+ 					addr, data->byte);
+@@ -86,12 +86,13 @@ static s32 stub_xfer(struct i2c_adapter * adap, u16 addr, unsigned short flags,
  
--static int i2c_inb(struct i2c_adapter *i2c_adap) 
-+static int i2c_inb(struct i2c_adapter *i2c_adap)
- {
- 	/* read byte via i2c port, without start/stop sequence	*/
- 	/* acknowledge is sent in i2c_read.			*/
- 	int i;
--	unsigned char indata=0;
-+	unsigned char indata = 0;
- 	struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
+ 	case I2C_SMBUS_BYTE_DATA:
+ 		if (read_write == I2C_SMBUS_WRITE) {
+-			chip->bytes[command] = data->byte;
++			chip->words[command] &= 0xff00;
++			chip->words[command] |= data->byte;
+ 			dev_dbg(&adap->dev, "smbus byte data - addr 0x%02x, "
+ 					"wrote 0x%02x at 0x%02x.\n",
+ 					addr, data->byte, command);
+ 		} else {
+-			data->byte = chip->bytes[command];
++			data->byte = chip->words[command] & 0xff;
+ 			dev_dbg(&adap->dev, "smbus byte data - addr 0x%02x, "
+ 					"read  0x%02x at 0x%02x.\n",
+ 					addr, data->byte, command);
+diff --git a/drivers/i2c/busses/i2c-viapro.c b/drivers/i2c/busses/i2c-viapro.c
+index c9ce77f..77b13d0 100644
+--- a/drivers/i2c/busses/i2c-viapro.c
++++ b/drivers/i2c/busses/i2c-viapro.c
+@@ -4,7 +4,7 @@
+     Copyright (c) 1998 - 2002  Frodo Looijaard <frodol at dds.nl>,
+     Philip Edelbrock <phil at netroedge.com>, Kyösti Mälkki <kmalkki at cc.hut.fi>,
+     Mark D. Studebaker <mdsxyz123 at yahoo.com>
+-    Copyright (C) 2005 - 2007  Jean Delvare <khali at linux-fr.org>
++    Copyright (C) 2005 - 2008  Jean Delvare <khali at linux-fr.org>
  
- 	/* assert: scl is low */
- 	sdahi(adap);
--	for (i=0;i<8;i++) {
--		if (sclhi(adap)<0) { /* timeout */
-+	for (i = 0; i < 8; i++) {
-+		if (sclhi(adap) < 0) { /* timeout */
- 			bit_dbg(1, &i2c_adap->dev, "i2c_inb: timeout at bit "
- 				"#%d\n", 7 - i);
- 			return -ETIMEDOUT;
--		};
-+		}
- 		indata *= 2;
--		if ( getsda(adap) ) 
-+		if (getsda(adap))
- 			indata |= 0x01;
- 		setscl(adap, 0);
- 		udelay(i == 7 ? adap->udelay / 2 : adap->udelay);
-@@ -228,66 +233,67 @@ static int i2c_inb(struct i2c_adapter *i2c_adap)
-  * Sanity check for the adapter hardware - check the reaction of
-  * the bus lines only if it seems to be idle.
-  */
--static int test_bus(struct i2c_algo_bit_data *adap, char* name) {
--	int scl,sda;
-+static int test_bus(struct i2c_algo_bit_data *adap, char *name)
-+{
-+	int scl, sda;
+     This program is free software; you can redistribute it and/or modify
+     it under the terms of the GNU General Public License as published by
+@@ -35,6 +35,7 @@
+    VT8235             0x3177             yes
+    VT8237R            0x3227             yes
+    VT8237A            0x3337             yes
++   VT8237S            0x3372             yes
+    VT8251             0x3287             yes
+    CX700              0x8324             yes
  
--	if (adap->getscl==NULL)
-+	if (adap->getscl == NULL)
- 		pr_info("%s: Testing SDA only, SCL is not readable\n", name);
+@@ -318,6 +319,10 @@ static int __devinit vt596_probe(struct pci_dev *pdev,
+ 	unsigned char temp;
+ 	int error = -ENODEV;
  
--	sda=getsda(adap);
--	scl=(adap->getscl==NULL?1:getscl(adap));
--	if (!scl || !sda ) {
-+	sda = getsda(adap);
-+	scl = (adap->getscl == NULL) ? 1 : getscl(adap);
-+	if (!scl || !sda) {
- 		printk(KERN_WARNING "%s: bus seems to be busy\n", name);
- 		goto bailout;
- 	}
++	/* driver_data might come from user-space, so check it */
++	if (id->driver_data & 1 || id->driver_data > 0xff)
++		return -EINVAL;
++
+ 	/* Determine the address of the SMBus areas */
+ 	if (force_addr) {
+ 		vt596_smba = force_addr & 0xfff0;
+@@ -389,6 +394,7 @@ found:
+ 	case PCI_DEVICE_ID_VIA_8251:
+ 	case PCI_DEVICE_ID_VIA_8237:
+ 	case PCI_DEVICE_ID_VIA_8237A:
++	case PCI_DEVICE_ID_VIA_8237S:
+ 	case PCI_DEVICE_ID_VIA_8235:
+ 	case PCI_DEVICE_ID_VIA_8233A:
+ 	case PCI_DEVICE_ID_VIA_8233_0:
+@@ -440,6 +446,8 @@ static struct pci_device_id vt596_ids[] = {
+ 	  .driver_data = SMBBA3 },
+ 	{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237A),
+ 	  .driver_data = SMBBA3 },
++	{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237S),
++	  .driver_data = SMBBA3 },
+ 	{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8231_4),
+ 	  .driver_data = SMBBA1 },
+ 	{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8251),
+@@ -455,6 +463,7 @@ static struct pci_driver vt596_driver = {
+ 	.name		= "vt596_smbus",
+ 	.id_table	= vt596_ids,
+ 	.probe		= vt596_probe,
++	.dynids.use_driver_data = 1,
+ };
  
- 	sdalo(adap);
--	sda=getsda(adap);
--	scl=(adap->getscl==NULL?1:getscl(adap));
--	if ( 0 != sda ) {
-+	sda = getsda(adap);
-+	scl = (adap->getscl == NULL) ? 1 : getscl(adap);
-+	if (sda) {
- 		printk(KERN_WARNING "%s: SDA stuck high!\n", name);
- 		goto bailout;
- 	}
--	if ( 0 == scl ) {
-+	if (!scl) {
- 		printk(KERN_WARNING "%s: SCL unexpected low "
- 		       "while pulling SDA low!\n", name);
- 		goto bailout;
--	}		
-+	}
+ static int __init i2c_vt596_init(void)
+diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig
+index 2e1c24f..bd7082c 100644
+--- a/drivers/i2c/chips/Kconfig
++++ b/drivers/i2c/chips/Kconfig
+@@ -4,32 +4,6 @@
  
- 	sdahi(adap);
--	sda=getsda(adap);
--	scl=(adap->getscl==NULL?1:getscl(adap));
--	if ( 0 == sda ) {
-+	sda = getsda(adap);
-+	scl = (adap->getscl == NULL) ? 1 : getscl(adap);
-+	if (!sda) {
- 		printk(KERN_WARNING "%s: SDA stuck low!\n", name);
- 		goto bailout;
- 	}
--	if ( 0 == scl ) {
-+	if (!scl) {
- 		printk(KERN_WARNING "%s: SCL unexpected low "
- 		       "while pulling SDA high!\n", name);
- 		goto bailout;
- 	}
+ menu "Miscellaneous I2C Chip support"
  
- 	scllo(adap);
--	sda=getsda(adap);
--	scl=(adap->getscl==NULL?0:getscl(adap));
--	if ( 0 != scl ) {
-+	sda = getsda(adap);
-+	scl = (adap->getscl == NULL) ? 0 : getscl(adap);
-+	if (scl) {
- 		printk(KERN_WARNING "%s: SCL stuck high!\n", name);
- 		goto bailout;
- 	}
--	if ( 0 == sda ) {
-+	if (!sda) {
- 		printk(KERN_WARNING "%s: SDA unexpected low "
- 		       "while pulling SCL low!\n", name);
- 		goto bailout;
- 	}
--	
-+
- 	sclhi(adap);
--	sda=getsda(adap);
--	scl=(adap->getscl==NULL?1:getscl(adap));
--	if ( 0 == scl ) {
-+	sda = getsda(adap);
-+	scl = (adap->getscl == NULL) ? 1 : getscl(adap);
-+	if (!scl) {
- 		printk(KERN_WARNING "%s: SCL stuck low!\n", name);
- 		goto bailout;
- 	}
--	if ( 0 == sda ) {
-+	if (!sda) {
- 		printk(KERN_WARNING "%s: SDA unexpected low "
- 		       "while pulling SCL high!\n", name);
- 		goto bailout;
-@@ -314,9 +320,10 @@ static int try_address(struct i2c_adapter *i2c_adap,
- 		       unsigned char addr, int retries)
- {
- 	struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
--	int i,ret = -1;
--	for (i=0;i<=retries;i++) {
--		ret = i2c_outb(i2c_adap,addr);
-+	int i, ret = -1;
-+
-+	for (i = 0; i <= retries; i++) {
-+		ret = i2c_outb(i2c_adap, addr);
- 		if (ret == 1 || i == retries)
- 			break;
- 		bit_dbg(3, &i2c_adap->dev, "emitting stop condition\n");
-@@ -338,20 +345,38 @@ static int sendbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
- {
- 	const unsigned char *temp = msg->buf;
- 	int count = msg->len;
--	unsigned short nak_ok = msg->flags & I2C_M_IGNORE_NAK; 
-+	unsigned short nak_ok = msg->flags & I2C_M_IGNORE_NAK;
- 	int retval;
--	int wrcount=0;
-+	int wrcount = 0;
+-config SENSORS_DS1337
+-	tristate "Dallas DS1337 and DS1339 Real Time Clock (DEPRECATED)"
+-	depends on EXPERIMENTAL
+-	help
+-	  If you say yes here you get support for Dallas Semiconductor
+-	  DS1337 and DS1339 real-time clock chips.
+-
+-	  This driver can also be built as a module.  If so, the module
+-	  will be called ds1337.
+-
+-	  This driver is deprecated and will be dropped soon. Use
+-	  rtc-ds1307 instead.
+-
+-config SENSORS_DS1374
+-	tristate "Dallas DS1374 Real Time Clock (DEPRECATED)"
+-	depends on EXPERIMENTAL
+-	help
+-	  If you say yes here you get support for Dallas Semiconductor
+-	  DS1374 real-time clock chips.
+-
+-	  This driver can also be built as a module.  If so, the module
+-	  will be called ds1374.
+-
+-	  This driver is deprecated and will be dropped soon. Use
+-	  rtc-ds1374 instead.
+-
+ config DS1682
+ 	tristate "Dallas DS1682 Total Elapsed Time Recorder with Alarm"
+ 	depends on EXPERIMENTAL
+@@ -57,7 +31,7 @@ config SENSORS_PCF8574
+ 	default n
+ 	help
+ 	  If you say yes here you get support for Philips PCF8574 and 
+-	  PCF8574A chips.
++	  PCF8574A chips. These chips are 8-bit I/O expanders for the I2C bus.
  
- 	while (count > 0) {
- 		retval = i2c_outb(i2c_adap, *temp);
--		if ((retval>0) || (nak_ok && (retval==0)))  { /* ok or ignored NAK */
--			count--; 
-+
-+		/* OK/ACK; or ignored NAK */
-+		if ((retval > 0) || (nak_ok && (retval == 0))) {
-+			count--;
- 			temp++;
- 			wrcount++;
--		} else { /* arbitration or no acknowledge */
--			dev_err(&i2c_adap->dev, "sendbytes: error - bailout.\n");
--			return (retval<0)? retval : -EFAULT;
--			        /* got a better one ?? */
+ 	  This driver can also be built as a module.  If so, the module
+ 	  will be called pcf8574.
+@@ -65,6 +39,20 @@ config SENSORS_PCF8574
+ 	  These devices are hard to detect and rarely found on mainstream
+ 	  hardware.  If unsure, say N.
+ 
++config PCF8575
++	tristate "Philips PCF8575"
++	default n
++	help
++	  If you say yes here you get support for Philips PCF8575 chip.
++	  This chip is a 16-bit I/O expander for the I2C bus.  Several other
++	  chip manufacturers sell equivalent chips, e.g. Texas Instruments.
 +
-+		/* A slave NAKing the master means the slave didn't like
-+		 * something about the data it saw.  For example, maybe
-+		 * the SMBus PEC was wrong.
-+		 */
-+		} else if (retval == 0) {
-+			dev_err(&i2c_adap->dev, "sendbytes: NAK bailout.\n");
-+			return -EIO;
++	  This driver can also be built as a module.  If so, the module
++	  will be called pcf8575.
 +
-+		/* Timeout; or (someday) lost arbitration
-+		 *
-+		 * FIXME Lost ARB implies retrying the transaction from
-+		 * the first message, after the "winning" master issues
-+		 * its STOP.  As a rule, upper layer code has no reason
-+		 * to know or care about this ... it is *NOT* an error.
-+		 */
-+		} else {
-+			dev_err(&i2c_adap->dev, "sendbytes: error %d\n",
-+					retval);
-+			return retval;
- 		}
- 	}
- 	return wrcount;
-@@ -376,14 +401,14 @@ static int acknak(struct i2c_adapter *i2c_adap, int is_ack)
- static int readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
- {
- 	int inval;
--	int rdcount=0;   	/* counts bytes read */
-+	int rdcount = 0;	/* counts bytes read */
- 	unsigned char *temp = msg->buf;
- 	int count = msg->len;
- 	const unsigned flags = msg->flags;
- 
- 	while (count > 0) {
- 		inval = i2c_inb(i2c_adap);
--		if (inval>=0) {
-+		if (inval >= 0) {
- 			*temp = inval;
- 			rdcount++;
- 		} else {   /* read timed out */
-@@ -431,7 +456,7 @@ static int readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
-  * returns:
-  *  0 everything went okay, the chip ack'ed, or IGNORE_NAK flag was set
-  * -x an error occurred (like: -EREMOTEIO if the device did not answer, or
-- *	-ETIMEDOUT, for example if the lines are stuck...) 
-+ *	-ETIMEDOUT, for example if the lines are stuck...)
-  */
- static int bit_doAddress(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
- {
-@@ -443,10 +468,10 @@ static int bit_doAddress(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
- 	int ret, retries;
- 
- 	retries = nak_ok ? 0 : i2c_adap->retries;
--	
--	if ( (flags & I2C_M_TEN)  ) { 
++	  This device is hard to detect and is rarely found on mainstream
++	  hardware.  If unsure, say N.
 +
-+	if (flags & I2C_M_TEN) {
- 		/* a ten bit address */
--		addr = 0xf0 | (( msg->addr >> 7) & 0x03);
-+		addr = 0xf0 | ((msg->addr >> 7) & 0x03);
- 		bit_dbg(2, &i2c_adap->dev, "addr0: %d\n", addr);
- 		/* try extended address code...*/
- 		ret = try_address(i2c_adap, addr, retries);
-@@ -456,33 +481,33 @@ static int bit_doAddress(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
- 			return -EREMOTEIO;
- 		}
- 		/* the remaining 8 bit address */
--		ret = i2c_outb(i2c_adap,msg->addr & 0x7f);
-+		ret = i2c_outb(i2c_adap, msg->addr & 0x7f);
- 		if ((ret != 1) && !nak_ok) {
- 			/* the chip did not ack / xmission error occurred */
- 			dev_err(&i2c_adap->dev, "died at 2nd address code\n");
- 			return -EREMOTEIO;
- 		}
--		if ( flags & I2C_M_RD ) {
-+		if (flags & I2C_M_RD) {
- 			bit_dbg(3, &i2c_adap->dev, "emitting repeated "
- 				"start condition\n");
- 			i2c_repstart(adap);
- 			/* okay, now switch into reading mode */
- 			addr |= 0x01;
- 			ret = try_address(i2c_adap, addr, retries);
--			if ((ret!=1) && !nak_ok) {
-+			if ((ret != 1) && !nak_ok) {
- 				dev_err(&i2c_adap->dev,
- 					"died at repeated address code\n");
- 				return -EREMOTEIO;
- 			}
- 		}
- 	} else {		/* normal 7bit address	*/
--		addr = ( msg->addr << 1 );
--		if (flags & I2C_M_RD )
-+		addr = msg->addr << 1;
-+		if (flags & I2C_M_RD)
- 			addr |= 1;
--		if (flags & I2C_M_REV_DIR_ADDR )
-+		if (flags & I2C_M_REV_DIR_ADDR)
- 			addr ^= 1;
- 		ret = try_address(i2c_adap, addr, retries);
--		if ((ret!=1) && !nak_ok)
-+		if ((ret != 1) && !nak_ok)
- 			return -EREMOTEIO;
- 	}
- 
-@@ -494,15 +519,14 @@ static int bit_xfer(struct i2c_adapter *i2c_adap,
- {
- 	struct i2c_msg *pmsg;
- 	struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
--	
--	int i,ret;
-+	int i, ret;
- 	unsigned short nak_ok;
- 
- 	bit_dbg(3, &i2c_adap->dev, "emitting start condition\n");
- 	i2c_start(adap);
--	for (i=0;i<num;i++) {
-+	for (i = 0; i < num; i++) {
- 		pmsg = &msgs[i];
--		nak_ok = pmsg->flags & I2C_M_IGNORE_NAK; 
-+		nak_ok = pmsg->flags & I2C_M_IGNORE_NAK;
- 		if (!(pmsg->flags & I2C_M_NOSTART)) {
- 			if (i) {
- 				bit_dbg(3, &i2c_adap->dev, "emitting "
-@@ -517,7 +541,7 @@ static int bit_xfer(struct i2c_adapter *i2c_adap,
- 				goto bailout;
- 			}
- 		}
--		if (pmsg->flags & I2C_M_RD ) {
-+		if (pmsg->flags & I2C_M_RD) {
- 			/* read bytes into buffer*/
- 			ret = readbytes(i2c_adap, pmsg);
- 			if (ret >= 1)
-@@ -551,7 +575,7 @@ bailout:
- 
- static u32 bit_func(struct i2c_adapter *adap)
- {
--	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | 
-+	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL |
- 	       I2C_FUNC_SMBUS_READ_BLOCK_DATA |
- 	       I2C_FUNC_SMBUS_BLOCK_PROC_CALL |
- 	       I2C_FUNC_10BIT_ADDR | I2C_FUNC_PROTOCOL_MANGLING;
-@@ -565,8 +589,8 @@ static const struct i2c_algorithm i2c_bit_algo = {
- 	.functionality	= bit_func,
- };
- 
--/* 
-- * registering functions to load algorithms at runtime 
-+/*
-+ * registering functions to load algorithms at runtime
-  */
- static int i2c_bit_prepare_bus(struct i2c_adapter *adap)
- {
-@@ -574,7 +598,7 @@ static int i2c_bit_prepare_bus(struct i2c_adapter *adap)
+ config SENSORS_PCA9539
+ 	tristate "Philips PCA9539 16-bit I/O port"
+ 	depends on EXPERIMENTAL
+@@ -100,12 +88,8 @@ config ISP1301_OMAP
+ 	  This driver can also be built as a module.  If so, the module
+ 	  will be called isp1301_omap.
  
- 	if (bit_test) {
- 		int ret = test_bus(bit_adap, adap->name);
--		if (ret<0)
-+		if (ret < 0)
- 			return -ENODEV;
- 	}
+-# NOTE:  This isn't really OMAP-specific, except for the current
+-# interface location in  <include/asm-arm/arch-omap/tps65010.h>
+-# and having mostly OMAP-specific board support
+ config TPS65010
+ 	tristate "TPS6501x Power Management chips"
+-	depends on ARCH_OMAP
+ 	default y if MACH_OMAP_H2 || MACH_OMAP_H3 || MACH_OMAP_OSK
+ 	help
+ 	  If you say yes here you get support for the TPS6501x series of
+@@ -116,18 +100,6 @@ config TPS65010
+ 	  This driver can also be built as a module.  If so, the module
+ 	  will be called tps65010.
  
-diff --git a/drivers/i2c/algos/i2c-algo-pcf.c b/drivers/i2c/algos/i2c-algo-pcf.c
-index ab2e6f3..8907b01 100644
---- a/drivers/i2c/algos/i2c-algo-pcf.c
-+++ b/drivers/i2c/algos/i2c-algo-pcf.c
-@@ -203,35 +203,6 @@ static int pcf_init_8584 (struct i2c_algo_pcf_data *adap)
- /* ----- Utility functions
-  */
+-config SENSORS_M41T00
+-	tristate "ST M41T00 RTC chip (DEPRECATED)"
+-	depends on PPC32
+-	help
+-	  If you say yes here you get support for the ST M41T00 RTC chip.
+-
+-	  This driver can also be built as a module.  If so, the module
+-	  will be called m41t00.
+-
+-	  This driver is deprecated and will be dropped soon. Use
+-	  rtc-ds1307 or rtc-m41t80 instead.
+-
+ config SENSORS_MAX6875
+ 	tristate "Maxim MAX6875 Power supply supervisor"
+ 	depends on EXPERIMENTAL
+diff --git a/drivers/i2c/chips/Makefile b/drivers/i2c/chips/Makefile
+index ca924e1..501f00c 100644
+--- a/drivers/i2c/chips/Makefile
++++ b/drivers/i2c/chips/Makefile
+@@ -2,14 +2,12 @@
+ # Makefile for miscellaneous I2C chip drivers.
+ #
  
--static inline int try_address(struct i2c_algo_pcf_data *adap,
--		       unsigned char addr, int retries)
+-obj-$(CONFIG_SENSORS_DS1337)	+= ds1337.o
+-obj-$(CONFIG_SENSORS_DS1374)	+= ds1374.o
+ obj-$(CONFIG_DS1682)		+= ds1682.o
+ obj-$(CONFIG_SENSORS_EEPROM)	+= eeprom.o
+ obj-$(CONFIG_SENSORS_MAX6875)	+= max6875.o
+-obj-$(CONFIG_SENSORS_M41T00)	+= m41t00.o
+ obj-$(CONFIG_SENSORS_PCA9539)	+= pca9539.o
+ obj-$(CONFIG_SENSORS_PCF8574)	+= pcf8574.o
++obj-$(CONFIG_PCF8575)		+= pcf8575.o
+ obj-$(CONFIG_SENSORS_PCF8591)	+= pcf8591.o
+ obj-$(CONFIG_ISP1301_OMAP)	+= isp1301_omap.o
+ obj-$(CONFIG_TPS65010)		+= tps65010.o
+diff --git a/drivers/i2c/chips/ds1337.c b/drivers/i2c/chips/ds1337.c
+deleted file mode 100644
+index ec17d6b..0000000
+--- a/drivers/i2c/chips/ds1337.c
++++ /dev/null
+@@ -1,410 +0,0 @@
+-/*
+- *  linux/drivers/i2c/chips/ds1337.c
+- *
+- *  Copyright (C) 2005 James Chapman <jchapman at katalix.com>
+- *
+- *	based on linux/drivers/acorn/char/pcf8583.c
+- *  Copyright (C) 2000 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.
+- *
+- * Driver for Dallas Semiconductor DS1337 and DS1339 real time clock chip
+- */
+-
+-#include <linux/module.h>
+-#include <linux/init.h>
+-#include <linux/slab.h>
+-#include <linux/i2c.h>
+-#include <linux/string.h>
+-#include <linux/rtc.h>		/* get the user-level API */
+-#include <linux/bcd.h>
+-#include <linux/list.h>
+-
+-/* Device registers */
+-#define DS1337_REG_HOUR		2
+-#define DS1337_REG_DAY		3
+-#define DS1337_REG_DATE		4
+-#define DS1337_REG_MONTH	5
+-#define DS1337_REG_CONTROL	14
+-#define DS1337_REG_STATUS	15
+-
+-/* FIXME - how do we export these interface constants? */
+-#define DS1337_GET_DATE		0
+-#define DS1337_SET_DATE		1
+-
+-/*
+- * Functions declaration
+- */
+-static unsigned short normal_i2c[] = { 0x68, I2C_CLIENT_END };
+-
+-I2C_CLIENT_INSMOD_1(ds1337);
+-
+-static int ds1337_attach_adapter(struct i2c_adapter *adapter);
+-static int ds1337_detect(struct i2c_adapter *adapter, int address, int kind);
+-static void ds1337_init_client(struct i2c_client *client);
+-static int ds1337_detach_client(struct i2c_client *client);
+-static int ds1337_command(struct i2c_client *client, unsigned int cmd,
+-			  void *arg);
+-
+-/*
+- * Driver data (common to all clients)
+- */
+-static struct i2c_driver ds1337_driver = {
+-	.driver = {
+-		.name	= "ds1337",
+-	},
+-	.attach_adapter	= ds1337_attach_adapter,
+-	.detach_client	= ds1337_detach_client,
+-	.command	= ds1337_command,
+-};
+-
+-/*
+- * Client data (each client gets its own)
+- */
+-struct ds1337_data {
+-	struct i2c_client client;
+-	struct list_head list;
+-};
+-
+-/*
+- * Internal variables
+- */
+-static LIST_HEAD(ds1337_clients);
+-
+-static inline int ds1337_read(struct i2c_client *client, u8 reg, u8 *value)
+-{
+-	s32 tmp = i2c_smbus_read_byte_data(client, reg);
+-
+-	if (tmp < 0)
+-		return -EIO;
+-
+-	*value = tmp;
+-
+-	return 0;
+-}
+-
+-/*
+- * Chip access functions
+- */
+-static int ds1337_get_datetime(struct i2c_client *client, struct rtc_time *dt)
+-{
+-	int result;
+-	u8 buf[7];
+-	u8 val;
+-	struct i2c_msg msg[2];
+-	u8 offs = 0;
+-
+-	if (!dt) {
+-		dev_dbg(&client->dev, "%s: EINVAL: dt=NULL\n", __FUNCTION__);
+-		return -EINVAL;
+-	}
+-
+-	msg[0].addr = client->addr;
+-	msg[0].flags = 0;
+-	msg[0].len = 1;
+-	msg[0].buf = &offs;
+-
+-	msg[1].addr = client->addr;
+-	msg[1].flags = I2C_M_RD;
+-	msg[1].len = sizeof(buf);
+-	msg[1].buf = &buf[0];
+-
+-	result = i2c_transfer(client->adapter, msg, 2);
+-
+-	dev_dbg(&client->dev, "%s: [%d] %02x %02x %02x %02x %02x %02x %02x\n",
+-		__FUNCTION__, result, buf[0], buf[1], buf[2], buf[3],
+-		buf[4], buf[5], buf[6]);
+-
+-	if (result == 2) {
+-		dt->tm_sec = BCD2BIN(buf[0]);
+-		dt->tm_min = BCD2BIN(buf[1]);
+-		val = buf[2] & 0x3f;
+-		dt->tm_hour = BCD2BIN(val);
+-		dt->tm_wday = BCD2BIN(buf[3]) - 1;
+-		dt->tm_mday = BCD2BIN(buf[4]);
+-		val = buf[5] & 0x7f;
+-		dt->tm_mon = BCD2BIN(val) - 1;
+-		dt->tm_year = BCD2BIN(buf[6]);
+-		if (buf[5] & 0x80)
+-			dt->tm_year += 100;
+-
+-		dev_dbg(&client->dev, "%s: secs=%d, mins=%d, "
+-			"hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n",
+-			__FUNCTION__, dt->tm_sec, dt->tm_min,
+-			dt->tm_hour, dt->tm_mday,
+-			dt->tm_mon, dt->tm_year, dt->tm_wday);
+-
+-		return 0;
+-	}
+-
+-	dev_err(&client->dev, "error reading data! %d\n", result);
+-	return -EIO;
+-}
+-
+-static int ds1337_set_datetime(struct i2c_client *client, struct rtc_time *dt)
+-{
+-	int result;
+-	u8 buf[8];
+-	u8 val;
+-	struct i2c_msg msg[1];
+-
+-	if (!dt) {
+-		dev_dbg(&client->dev, "%s: EINVAL: dt=NULL\n", __FUNCTION__);
+-		return -EINVAL;
+-	}
+-
+-	dev_dbg(&client->dev, "%s: secs=%d, mins=%d, hours=%d, "
+-		"mday=%d, mon=%d, year=%d, wday=%d\n", __FUNCTION__,
+-		dt->tm_sec, dt->tm_min, dt->tm_hour,
+-		dt->tm_mday, dt->tm_mon, dt->tm_year, dt->tm_wday);
+-
+-	buf[0] = 0;		/* reg offset */
+-	buf[1] = BIN2BCD(dt->tm_sec);
+-	buf[2] = BIN2BCD(dt->tm_min);
+-	buf[3] = BIN2BCD(dt->tm_hour);
+-	buf[4] = BIN2BCD(dt->tm_wday + 1);
+-	buf[5] = BIN2BCD(dt->tm_mday);
+-	buf[6] = BIN2BCD(dt->tm_mon + 1);
+-	val = dt->tm_year;
+-	if (val >= 100) {
+-		val -= 100;
+-		buf[6] |= (1 << 7);
+-	}
+-	buf[7] = BIN2BCD(val);
+-
+-	msg[0].addr = client->addr;
+-	msg[0].flags = 0;
+-	msg[0].len = sizeof(buf);
+-	msg[0].buf = &buf[0];
+-
+-	result = i2c_transfer(client->adapter, msg, 1);
+-	if (result == 1)
+-		return 0;
+-
+-	dev_err(&client->dev, "error writing data! %d\n", result);
+-	return -EIO;
+-}
+-
+-static int ds1337_command(struct i2c_client *client, unsigned int cmd,
+-			  void *arg)
+-{
+-	dev_dbg(&client->dev, "%s: cmd=%d\n", __FUNCTION__, cmd);
+-
+-	switch (cmd) {
+-	case DS1337_GET_DATE:
+-		return ds1337_get_datetime(client, arg);
+-
+-	case DS1337_SET_DATE:
+-		return ds1337_set_datetime(client, arg);
+-
+-	default:
+-		return -EINVAL;
+-	}
+-}
+-
+-/*
+- * Public API for access to specific device. Useful for low-level
+- * RTC access from kernel code.
+- */
+-int ds1337_do_command(int bus, int cmd, void *arg)
+-{
+-	struct list_head *walk;
+-	struct list_head *tmp;
+-	struct ds1337_data *data;
+-
+-	list_for_each_safe(walk, tmp, &ds1337_clients) {
+-		data = list_entry(walk, struct ds1337_data, list);
+-		if (data->client.adapter->nr == bus)
+-			return ds1337_command(&data->client, cmd, arg);
+-	}
+-
+-	return -ENODEV;
+-}
+-
+-static int ds1337_attach_adapter(struct i2c_adapter *adapter)
 -{
--	int i, status, ret = -1;
--	int wfp;
--	for (i=0;i<retries;i++) {
--		i2c_outb(adap, addr);
--		i2c_start(adap);
--		status = get_pcf(adap, 1);
--		if ((wfp = wait_for_pin(adap, &status)) >= 0) {
--			if ((status & I2C_PCF_LRB) == 0) { 
--				i2c_stop(adap);
--				break;	/* success! */
--			}
--		}
--		if (wfp == -EINTR) {
--			/* arbitration lost */
--			udelay(adap->udelay);
--			return -EINTR;
--		}
--		i2c_stop(adap);
--		udelay(adap->udelay);
+-	return i2c_probe(adapter, &addr_data, ds1337_detect);
+-}
+-
+-/*
+- * The following function does more than just detection. If detection
+- * succeeds, it also registers the new chip.
+- */
+-static int ds1337_detect(struct i2c_adapter *adapter, int address, int kind)
+-{
+-	struct i2c_client *new_client;
+-	struct ds1337_data *data;
+-	int err = 0;
+-	const char *name = "";
+-
+-	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
+-				     I2C_FUNC_I2C))
+-		goto exit;
+-
+-	if (!(data = kzalloc(sizeof(struct ds1337_data), GFP_KERNEL))) {
+-		err = -ENOMEM;
+-		goto exit;
 -	}
--	DEB2(if (i) printk(KERN_DEBUG "i2c-algo-pcf.o: needed %d retries for %d\n",i,
--	                   addr));
--	return ret;
+-	INIT_LIST_HEAD(&data->list);
+-
+-	/* The common I2C client data is placed right before the
+-	 * DS1337-specific data. 
+-	 */
+-	new_client = &data->client;
+-	i2c_set_clientdata(new_client, data);
+-	new_client->addr = address;
+-	new_client->adapter = adapter;
+-	new_client->driver = &ds1337_driver;
+-	new_client->flags = 0;
+-
+-	/*
+-	 * Now we do the remaining detection. A negative kind means that
+-	 * the driver was loaded with no force parameter (default), so we
+-	 * must both detect and identify the chip. A zero kind means that
+-	 * the driver was loaded with the force parameter, the detection
+-	 * step shall be skipped. A positive kind means that the driver
+-	 * was loaded with the force parameter and a given kind of chip is
+-	 * requested, so both the detection and the identification steps
+-	 * are skipped.
+-	 *
+-	 * For detection, we read registers that are most likely to cause
+-	 * detection failure, i.e. those that have more bits with fixed
+-	 * or reserved values.
+-	 */
+-
+-	/* Default to an DS1337 if forced */
+-	if (kind == 0)
+-		kind = ds1337;
+-
+-	if (kind < 0) {		/* detection and identification */
+-		u8 data;
+-
+-		/* Check that status register bits 6-2 are zero */
+-		if ((ds1337_read(new_client, DS1337_REG_STATUS, &data) < 0) ||
+-		    (data & 0x7c))
+-			goto exit_free;
+-
+-		/* Check for a valid day register value */
+-		if ((ds1337_read(new_client, DS1337_REG_DAY, &data) < 0) ||
+-		    (data == 0) || (data & 0xf8))
+-			goto exit_free;
+-
+-		/* Check for a valid date register value */
+-		if ((ds1337_read(new_client, DS1337_REG_DATE, &data) < 0) ||
+-		    (data == 0) || (data & 0xc0) || ((data & 0x0f) > 9) ||
+-		    (data >= 0x32))
+-			goto exit_free;
+-
+-		/* Check for a valid month register value */
+-		if ((ds1337_read(new_client, DS1337_REG_MONTH, &data) < 0) ||
+-		    (data == 0) || (data & 0x60) || ((data & 0x0f) > 9) ||
+-		    ((data >= 0x13) && (data <= 0x19)))
+-			goto exit_free;
+-
+-		/* Check that control register bits 6-5 are zero */
+-		if ((ds1337_read(new_client, DS1337_REG_CONTROL, &data) < 0) ||
+-		    (data & 0x60))
+-			goto exit_free;
+-
+-		kind = ds1337;
+-	}
+-
+-	if (kind == ds1337)
+-		name = "ds1337";
+-
+-	/* We can fill in the remaining client fields */
+-	strlcpy(new_client->name, name, I2C_NAME_SIZE);
+-
+-	/* Tell the I2C layer a new client has arrived */
+-	if ((err = i2c_attach_client(new_client)))
+-		goto exit_free;
+-
+-	/* Initialize the DS1337 chip */
+-	ds1337_init_client(new_client);
+-
+-	/* Add client to local list */
+-	list_add(&data->list, &ds1337_clients);
+-
+-	return 0;
+-
+-exit_free:
+-	kfree(data);
+-exit:
+-	return err;
 -}
 -
+-static void ds1337_init_client(struct i2c_client *client)
+-{
+-	u8 status, control;
 -
- static int pcf_sendbytes(struct i2c_adapter *i2c_adap, const char *buf,
-                          int count, int last)
- {
-@@ -321,47 +292,19 @@ static int pcf_readbytes(struct i2c_adapter *i2c_adap, char *buf,
- }
- 
- 
--static inline int pcf_doAddress(struct i2c_algo_pcf_data *adap,
--                                struct i2c_msg *msg, int retries) 
-+static int pcf_doAddress(struct i2c_algo_pcf_data *adap,
-+			 struct i2c_msg *msg)
- {
- 	unsigned short flags = msg->flags;
- 	unsigned char addr;
--	int ret;
--	if ( (flags & I2C_M_TEN)  ) { 
--		/* a ten bit address */
--		addr = 0xf0 | (( msg->addr >> 7) & 0x03);
--		DEB2(printk(KERN_DEBUG "addr0: %d\n",addr));
--		/* try extended address code...*/
--		ret = try_address(adap, addr, retries);
--		if (ret!=1) {
--			printk(KERN_ERR "died at extended address code.\n");
--			return -EREMOTEIO;
--		}
--		/* the remaining 8 bit address */
--		i2c_outb(adap,msg->addr & 0x7f);
--/* Status check comes here */
--		if (ret != 1) {
--			printk(KERN_ERR "died at 2nd address code.\n");
--			return -EREMOTEIO;
+-	/* On some boards, the RTC isn't configured by boot firmware.
+-	 * Handle that case by starting/configuring the RTC now.
+-	 */
+-	status = i2c_smbus_read_byte_data(client, DS1337_REG_STATUS);
+-	control = i2c_smbus_read_byte_data(client, DS1337_REG_CONTROL);
+-
+-	if ((status & 0x80) || (control & 0x80)) {
+-		/* RTC not running */
+-		u8 buf[1+16];	/* First byte is interpreted as address */
+-		struct i2c_msg msg[1];
+-
+-		dev_dbg(&client->dev, "%s: RTC not running!\n", __FUNCTION__);
+-
+-		/* Initialize all, including STATUS and CONTROL to zero */
+-		memset(buf, 0, sizeof(buf));
+-
+-		/* Write valid values in the date/time registers */
+-		buf[1+DS1337_REG_DAY] = 1;
+-		buf[1+DS1337_REG_DATE] = 1;
+-		buf[1+DS1337_REG_MONTH] = 1;
+-
+-		msg[0].addr = client->addr;
+-		msg[0].flags = 0;
+-		msg[0].len = sizeof(buf);
+-		msg[0].buf = &buf[0];
+-
+-		i2c_transfer(client->adapter, msg, 1);
+-	} else {
+-		/* Running: ensure that device is set in 24-hour mode */
+-		s32 val;
+-
+-		val = i2c_smbus_read_byte_data(client, DS1337_REG_HOUR);
+-		if ((val >= 0) && (val & (1 << 6)))
+-			i2c_smbus_write_byte_data(client, DS1337_REG_HOUR,
+-						  val & 0x3f);
+-	}
+-}
+-
+-static int ds1337_detach_client(struct i2c_client *client)
+-{
+-	int err;
+-	struct ds1337_data *data = i2c_get_clientdata(client);
+-
+-	if ((err = i2c_detach_client(client)))
+-		return err;
+-
+-	list_del(&data->list);
+-	kfree(data);
+-	return 0;
+-}
+-
+-static int __init ds1337_init(void)
+-{
+-	return i2c_add_driver(&ds1337_driver);
+-}
+-
+-static void __exit ds1337_exit(void)
+-{
+-	i2c_del_driver(&ds1337_driver);
+-}
+-
+-MODULE_AUTHOR("James Chapman <jchapman at katalix.com>");
+-MODULE_DESCRIPTION("DS1337 RTC driver");
+-MODULE_LICENSE("GPL");
+-
+-EXPORT_SYMBOL_GPL(ds1337_do_command);
+-
+-module_init(ds1337_init);
+-module_exit(ds1337_exit);
+diff --git a/drivers/i2c/chips/ds1374.c b/drivers/i2c/chips/ds1374.c
+deleted file mode 100644
+index 8a2ff0c..0000000
+--- a/drivers/i2c/chips/ds1374.c
++++ /dev/null
+@@ -1,267 +0,0 @@
+-/*
+- * drivers/i2c/chips/ds1374.c
+- *
+- * I2C client/driver for the Maxim/Dallas DS1374 Real-Time Clock
+- *
+- * Author: Randy Vinson <rvinson at mvista.com>
+- *
+- * Based on the m41t00.c by Mark Greer <mgreer at mvista.com>
+- *
+- * 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.
+- */
+-/*
+- * This i2c client/driver wedges between the drivers/char/genrtc.c RTC
+- * interface and the SMBus interface of the i2c subsystem.
+- * It would be more efficient to use i2c msgs/i2c_transfer directly but, as
+- * recommened in .../Documentation/i2c/writing-clients section
+- * "Sending and receiving", using SMBus level communication is preferred.
+- */
+-
+-#include <linux/kernel.h>
+-#include <linux/module.h>
+-#include <linux/interrupt.h>
+-#include <linux/i2c.h>
+-#include <linux/rtc.h>
+-#include <linux/bcd.h>
+-#include <linux/mutex.h>
+-#include <linux/workqueue.h>
+-
+-#define DS1374_REG_TOD0		0x00
+-#define DS1374_REG_TOD1		0x01
+-#define DS1374_REG_TOD2		0x02
+-#define DS1374_REG_TOD3		0x03
+-#define DS1374_REG_WDALM0	0x04
+-#define DS1374_REG_WDALM1	0x05
+-#define DS1374_REG_WDALM2	0x06
+-#define DS1374_REG_CR		0x07
+-#define DS1374_REG_SR		0x08
+-#define DS1374_REG_SR_OSF	0x80
+-#define DS1374_REG_TCR		0x09
+-
+-#define	DS1374_DRV_NAME		"ds1374"
+-
+-static DEFINE_MUTEX(ds1374_mutex);
+-
+-static struct i2c_driver ds1374_driver;
+-static struct i2c_client *save_client;
+-
+-static unsigned short ignore[] = { I2C_CLIENT_END };
+-static unsigned short normal_addr[] = { 0x68, I2C_CLIENT_END };
+-
+-static struct i2c_client_address_data addr_data = {
+-	.normal_i2c = normal_addr,
+-	.probe = ignore,
+-	.ignore = ignore,
+-};
+-
+-static ulong ds1374_read_rtc(void)
+-{
+-	ulong time = 0;
+-	int reg = DS1374_REG_WDALM0;
+-
+-	while (reg--) {
+-		s32 tmp;
+-		if ((tmp = i2c_smbus_read_byte_data(save_client, reg)) < 0) {
+-			dev_warn(&save_client->dev,
+-				 "can't read from rtc chip\n");
+-			return 0;
 -		}
--		if ( flags & I2C_M_RD ) {
--			i2c_repstart(adap);
--			/* okay, now switch into reading mode */
--			addr |= 0x01;
--			ret = try_address(adap, addr, retries);
--			if (ret!=1) {
--				printk(KERN_ERR "died at extended address code.\n");
--				return -EREMOTEIO;
--			}
+-		time = (time << 8) | (tmp & 0xff);
+-	}
+-	return time;
+-}
+-
+-static void ds1374_write_rtc(ulong time)
+-{
+-	int reg;
+-
+-	for (reg = DS1374_REG_TOD0; reg < DS1374_REG_WDALM0; reg++) {
+-		if (i2c_smbus_write_byte_data(save_client, reg, time & 0xff)
+-		    < 0) {
+-			dev_warn(&save_client->dev,
+-				 "can't write to rtc chip\n");
+-			break;
 -		}
--	} else {		/* normal 7bit address	*/
--		addr = ( msg->addr << 1 );
--		if (flags & I2C_M_RD )
--			addr |= 1;
--		if (flags & I2C_M_REV_DIR_ADDR )
--			addr ^= 1;
--		i2c_outb(adap, addr);
+-		time = time >> 8;
 -	}
-+
-+	addr = msg->addr << 1;
-+	if (flags & I2C_M_RD)
-+		addr |= 1;
-+	if (flags & I2C_M_REV_DIR_ADDR)
-+		addr ^= 1;
-+	i2c_outb(adap, addr);
-+
- 	return 0;
- }
- 
-@@ -390,7 +333,7 @@ static int pcf_xfer(struct i2c_adapter *i2c_adap,
- 		     pmsg->flags & I2C_M_RD ? "read" : "write",
-                      pmsg->len, pmsg->addr, i + 1, num);)
-     
--		ret = pcf_doAddress(adap, pmsg, i2c_adap->retries);
-+		ret = pcf_doAddress(adap, pmsg);
- 
- 		/* Send START */
- 		if (i == 0) {
-@@ -453,7 +396,7 @@ static int pcf_xfer(struct i2c_adapter *i2c_adap,
- static u32 pcf_func(struct i2c_adapter *adap)
- {
- 	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | 
--	       I2C_FUNC_10BIT_ADDR | I2C_FUNC_PROTOCOL_MANGLING; 
-+	       I2C_FUNC_PROTOCOL_MANGLING;
- }
- 
- /* -----exported algorithm data: -------------------------------------	*/
-@@ -475,9 +418,7 @@ int i2c_pcf_add_bus(struct i2c_adapter *adap)
- 
- 	/* register new adapter to i2c module... */
- 	adap->algo = &pcf_algo;
+-}
 -
--	adap->timeout = 100;		/* default values, should	*/
--	adap->retries = 3;		/* be replaced by defines	*/
-+	adap->timeout = 100;
- 
- 	if ((rval = pcf_init_8584(pcf_adap)))
- 		return rval;
-diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
-index c466c6c..8d12b26 100644
---- a/drivers/i2c/busses/Kconfig
-+++ b/drivers/i2c/busses/Kconfig
-@@ -182,7 +182,8 @@ config I2C_I801
- 	  will be called i2c-i801.
- 
- config I2C_I810
--	tristate "Intel 810/815"
-+	tristate "Intel 810/815 (DEPRECATED)"
-+	default n
- 	depends on PCI
- 	select I2C_ALGOBIT
- 	help
-@@ -195,6 +196,8 @@ config I2C_I810
- 	    i815
- 	    i845G
- 
-+	  This driver is deprecated in favor of the i810fb and intelfb drivers.
-+
- 	  This driver can also be built as a module.  If so, the module
- 	  will be called i2c-i810.
- 
-@@ -259,20 +262,6 @@ config I2C_IOP3XX
- 	  This driver can also be built as a module.  If so, the module
- 	  will be called i2c-iop3xx.
- 
--config I2C_IXP4XX
--	tristate "IXP4xx GPIO-Based I2C Interface (DEPRECATED)"
--	depends on ARCH_IXP4XX
--	select I2C_ALGOBIT
--	help
--	  Say Y here if you have an Intel IXP4xx(420,421,422,425) based 
--	  system and are using GPIO lines for an I2C bus.
+-static void ds1374_check_rtc_status(void)
+-{
+-	s32 tmp;
 -
--	  This support is also available as a module. If so, the module
--	  will be called i2c-ixp4xx.
+-	tmp = i2c_smbus_read_byte_data(save_client, DS1374_REG_SR);
+-	if (tmp < 0) {
+-		dev_warn(&save_client->dev,
+-			 "can't read status from rtc chip\n");
+-		return;
+-	}
+-	if (tmp & DS1374_REG_SR_OSF) {
+-		dev_warn(&save_client->dev,
+-			 "oscillator discontinuity flagged, time unreliable\n");
+-		tmp &= ~DS1374_REG_SR_OSF;
+-		tmp = i2c_smbus_write_byte_data(save_client, DS1374_REG_SR,
+-						tmp & 0xff);
+-		if (tmp < 0)
+-			dev_warn(&save_client->dev,
+-				 "can't clear discontinuity notification\n");
+-	}
+-}
 -
--	  This driver is deprecated and will be dropped soon. Use i2c-gpio
--	  instead.
+-ulong ds1374_get_rtc_time(void)
+-{
+-	ulong t1, t2;
+-	int limit = 10;		/* arbitrary retry limit */
 -
- config I2C_IXP2000
- 	tristate "IXP2000 GPIO-Based I2C Interface (DEPRECATED)"
- 	depends on ARCH_IXP2000
-@@ -396,7 +385,8 @@ config I2C_PASEMI
- 	  Supports the PA Semi PWRficient on-chip SMBus interfaces.
- 
- config I2C_PROSAVAGE
--	tristate "S3/VIA (Pro)Savage"
-+	tristate "S3/VIA (Pro)Savage (DEPRECATED)"
-+	default n
- 	depends on PCI
- 	select I2C_ALGOBIT
- 	help
-@@ -407,6 +397,8 @@ config I2C_PROSAVAGE
- 	    S3/VIA KM266/VT8375 aka ProSavage8
- 	    S3/VIA KM133/VT8365 aka Savage4
- 
-+	  This driver is deprecated in favor of the savagefb driver.
-+
- 	  This support is also available as a module.  If so, the module 
- 	  will be called i2c-prosavage.
- 
-@@ -418,13 +410,16 @@ config I2C_S3C2410
- 	  Samsung S3C2410 based System-on-Chip devices.
- 
- config I2C_SAVAGE4
--	tristate "S3 Savage 4"
--	depends on PCI && EXPERIMENTAL
-+	tristate "S3 Savage 4 (DEPRECATED)"
-+	default n
-+	depends on PCI
- 	select I2C_ALGOBIT
- 	help
- 	  If you say yes to this option, support will be included for the 
- 	  S3 Savage 4 I2C interface.
- 
-+	  This driver is deprecated in favor of the savagefb driver.
-+
- 	  This driver can also be built as a module.  If so, the module
- 	  will be called i2c-savage4.
+-	mutex_lock(&ds1374_mutex);
+-
+-	/*
+-	 * Since the reads are being performed one byte at a time using
+-	 * the SMBus vs a 4-byte i2c transfer, there is a chance that a
+-	 * carry will occur during the read. To detect this, 2 reads are
+-	 * performed and compared.
+-	 */
+-	do {
+-		t1 = ds1374_read_rtc();
+-		t2 = ds1374_read_rtc();
+-	} while (t1 != t2 && limit--);
+-
+-	mutex_unlock(&ds1374_mutex);
+-
+-	if (t1 != t2) {
+-		dev_warn(&save_client->dev,
+-			 "can't get consistent time from rtc chip\n");
+-		t1 = 0;
+-	}
+-
+-	return t1;
+-}
+-
+-static ulong new_time;
+-
+-static void ds1374_set_work(struct work_struct *work)
+-{
+-	ulong t1, t2;
+-	int limit = 10;		/* arbitrary retry limit */
+-
+-	t1 = new_time;
+-
+-	mutex_lock(&ds1374_mutex);
+-
+-	/*
+-	 * Since the writes are being performed one byte at a time using
+-	 * the SMBus vs a 4-byte i2c transfer, there is a chance that a
+-	 * carry will occur during the write. To detect this, the write
+-	 * value is read back and compared.
+-	 */
+-	do {
+-		ds1374_write_rtc(t1);
+-		t2 = ds1374_read_rtc();
+-	} while (t1 != t2 && limit--);
+-
+-	mutex_unlock(&ds1374_mutex);
+-
+-	if (t1 != t2)
+-		dev_warn(&save_client->dev,
+-			 "can't confirm time set from rtc chip\n");
+-}
+-
+-static struct workqueue_struct *ds1374_workqueue;
+-
+-static DECLARE_WORK(ds1374_work, ds1374_set_work);
+-
+-int ds1374_set_rtc_time(ulong nowtime)
+-{
+-	new_time = nowtime;
+-
+-	if (in_interrupt())
+-		queue_work(ds1374_workqueue, &ds1374_work);
+-	else
+-		ds1374_set_work(NULL);
+-
+-	return 0;
+-}
+-
+-/*
+- *****************************************************************************
+- *
+- *	Driver Interface
+- *
+- *****************************************************************************
+- */
+-static int ds1374_probe(struct i2c_adapter *adap, int addr, int kind)
+-{
+-	struct i2c_client *client;
+-	int rc;
+-
+-	client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
+-	if (!client)
+-		return -ENOMEM;
+-
+-	strncpy(client->name, DS1374_DRV_NAME, I2C_NAME_SIZE);
+-	client->addr = addr;
+-	client->adapter = adap;
+-	client->driver = &ds1374_driver;
+-
+-	ds1374_workqueue = create_singlethread_workqueue("ds1374");
+-	if (!ds1374_workqueue) {
+-		kfree(client);
+-		return -ENOMEM;	/* most expected reason */
+-	}
+-
+-	if ((rc = i2c_attach_client(client)) != 0) {
+-		kfree(client);
+-		return rc;
+-	}
+-
+-	save_client = client;
+-
+-	ds1374_check_rtc_status();
+-
+-	return 0;
+-}
+-
+-static int ds1374_attach(struct i2c_adapter *adap)
+-{
+-	return i2c_probe(adap, &addr_data, ds1374_probe);
+-}
+-
+-static int ds1374_detach(struct i2c_client *client)
+-{
+-	int rc;
+-
+-	if ((rc = i2c_detach_client(client)) == 0) {
+-		kfree(i2c_get_clientdata(client));
+-		destroy_workqueue(ds1374_workqueue);
+-	}
+-	return rc;
+-}
+-
+-static struct i2c_driver ds1374_driver = {
+-	.driver = {
+-		.name	= DS1374_DRV_NAME,
+-	},
+-	.id = I2C_DRIVERID_DS1374,
+-	.attach_adapter = ds1374_attach,
+-	.detach_client = ds1374_detach,
+-};
+-
+-static int __init ds1374_init(void)
+-{
+-	return i2c_add_driver(&ds1374_driver);
+-}
+-
+-static void __exit ds1374_exit(void)
+-{
+-	i2c_del_driver(&ds1374_driver);
+-}
+-
+-module_init(ds1374_init);
+-module_exit(ds1374_exit);
+-
+-MODULE_AUTHOR("Randy Vinson <rvinson at mvista.com>");
+-MODULE_DESCRIPTION("Maxim/Dallas DS1374 RTC I2C Client Driver");
+-MODULE_LICENSE("GPL");
+diff --git a/drivers/i2c/chips/eeprom.c b/drivers/i2c/chips/eeprom.c
+index 1a7eeeb..fde297b 100644
+--- a/drivers/i2c/chips/eeprom.c
++++ b/drivers/i2c/chips/eeprom.c
+@@ -35,7 +35,7 @@
+ #include <linux/mutex.h>
  
-@@ -611,7 +606,7 @@ config I2C_VIAPRO
- 	    VT8231
- 	    VT8233/A
- 	    VT8235
--	    VT8237R/A
-+	    VT8237R/A/S
- 	    VT8251
- 	    CX700
+ /* Addresses to scan */
+-static unsigned short normal_i2c[] = { 0x50, 0x51, 0x52, 0x53, 0x54,
++static const unsigned short normal_i2c[] = { 0x50, 0x51, 0x52, 0x53, 0x54,
+ 					0x55, 0x56, 0x57, I2C_CLIENT_END };
  
-diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
-index 81d43c2..ea7068f 100644
---- a/drivers/i2c/busses/Makefile
-+++ b/drivers/i2c/busses/Makefile
-@@ -20,7 +20,6 @@ obj-$(CONFIG_I2C_I810)		+= i2c-i810.o
- obj-$(CONFIG_I2C_IBM_IIC)	+= i2c-ibm_iic.o
- obj-$(CONFIG_I2C_IOP3XX)	+= i2c-iop3xx.o
- obj-$(CONFIG_I2C_IXP2000)	+= i2c-ixp2000.o
--obj-$(CONFIG_I2C_IXP4XX)	+= i2c-ixp4xx.o
- obj-$(CONFIG_I2C_POWERMAC)	+= i2c-powermac.o
- obj-$(CONFIG_I2C_MPC)		+= i2c-mpc.o
- obj-$(CONFIG_I2C_MV64XXX)	+= i2c-mv64xxx.o
-diff --git a/drivers/i2c/busses/i2c-amd756.c b/drivers/i2c/busses/i2c-amd756.c
-index 7490dc1..573abe4 100644
---- a/drivers/i2c/busses/i2c-amd756.c
-+++ b/drivers/i2c/busses/i2c-amd756.c
-@@ -334,6 +334,10 @@ static int __devinit amd756_probe(struct pci_dev *pdev,
- 	int error;
- 	u8 temp;
- 	
-+	/* driver_data might come from user-space, so check it */
-+	if (id->driver_data > ARRAY_SIZE(chipname))
-+		return -EINVAL;
-+
- 	if (amd756_ioport) {
- 		dev_err(&pdev->dev, "Only one device supported "
- 		       "(you have a strange motherboard, btw)\n");
-@@ -405,6 +409,7 @@ static struct pci_driver amd756_driver = {
- 	.id_table	= amd756_ids,
- 	.probe		= amd756_probe,
- 	.remove		= __devexit_p(amd756_remove),
-+	.dynids.use_driver_data = 1,
- };
+ /* Insmod parameters */
+diff --git a/drivers/i2c/chips/isp1301_omap.c b/drivers/i2c/chips/isp1301_omap.c
+index b767603..2a31601 100644
+--- a/drivers/i2c/chips/isp1301_omap.c
++++ b/drivers/i2c/chips/isp1301_omap.c
+@@ -100,7 +100,7 @@ struct isp1301 {
  
- static int __init amd756_init(void)
-diff --git a/drivers/i2c/busses/i2c-au1550.c b/drivers/i2c/busses/i2c-au1550.c
-index 2f68416..1953b26 100644
---- a/drivers/i2c/busses/i2c-au1550.c
-+++ b/drivers/i2c/busses/i2c-au1550.c
-@@ -30,14 +30,22 @@
- #include <linux/delay.h>
- #include <linux/kernel.h>
- #include <linux/module.h>
-+#include <linux/platform_device.h>
- #include <linux/init.h>
- #include <linux/errno.h>
- #include <linux/i2c.h>
-+#include <linux/slab.h>
+ #if	defined(CONFIG_TPS65010) || defined(CONFIG_TPS65010_MODULE)
  
- #include <asm/mach-au1x00/au1xxx.h>
- #include <asm/mach-au1x00/au1xxx_psc.h>
+-#include <asm/arch/tps65010.h>
++#include <linux/i2c/tps65010.h>
  
--#include "i2c-au1550.h"
-+struct i2c_au1550_data {
-+	u32	psc_base;
-+	int	xfer_timeout;
-+	int	ack_timeout;
-+	struct i2c_adapter adap;
-+	struct resource *ioarea;
-+};
+ #else
  
- static int
- wait_xfer_done(struct i2c_au1550_data *adap)
-@@ -105,7 +113,7 @@ wait_master_done(struct i2c_au1550_data *adap)
+@@ -259,12 +259,6 @@ static inline const char *state_name(struct isp1301 *isp)
+ 	return state_string(isp->otg.state);
  }
  
- static int
--do_address(struct i2c_au1550_data *adap, unsigned int addr, int rd)
-+do_address(struct i2c_au1550_data *adap, unsigned int addr, int rd, int q)
- {
- 	volatile psc_smb_t	*sp;
- 	u32			stat;
-@@ -134,6 +142,10 @@ do_address(struct i2c_au1550_data *adap, unsigned int addr, int rd)
- 	if (rd)
- 		addr |= 1;
+-#ifdef	VERBOSE
+-#define	dev_vdbg			dev_dbg
+-#else
+-#define	dev_vdbg(dev, fmt, arg...)	do{}while(0)
+-#endif
+-
+ /*-------------------------------------------------------------------------*/
  
-+	/* zero-byte xfers stop immediately */
-+	if (q)
-+		addr |= PSC_SMBTXRX_STP;
-+
- 	/* Put byte into fifo, start up master.
- 	*/
- 	sp->psc_smbtxrx = addr;
-@@ -142,7 +154,7 @@ do_address(struct i2c_au1550_data *adap, unsigned int addr, int rd)
- 	au_sync();
- 	if (wait_ack(adap))
- 		return -EIO;
+ /* NOTE:  some of this ISP1301 setup is specific to H2 boards;
+diff --git a/drivers/i2c/chips/m41t00.c b/drivers/i2c/chips/m41t00.c
+deleted file mode 100644
+index 3fcb646..0000000
+--- a/drivers/i2c/chips/m41t00.c
++++ /dev/null
+@@ -1,413 +0,0 @@
+-/*
+- * I2C client/driver for the ST M41T00 family of i2c rtc chips.
+- *
+- * Author: Mark A. Greer <mgreer at mvista.com>
+- *
+- * 2005, 2006 (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.
+- */
+-/*
+- * This i2c client/driver wedges between the drivers/char/genrtc.c RTC
+- * interface and the SMBus interface of the i2c subsystem.
+- */
+-
+-#include <linux/kernel.h>
+-#include <linux/module.h>
+-#include <linux/interrupt.h>
+-#include <linux/i2c.h>
+-#include <linux/rtc.h>
+-#include <linux/bcd.h>
+-#include <linux/workqueue.h>
+-#include <linux/platform_device.h>
+-#include <linux/m41t00.h>
+-#include <asm/time.h>
+-#include <asm/rtc.h>
+-
+-static struct i2c_driver m41t00_driver;
+-static struct i2c_client *save_client;
+-
+-static unsigned short ignore[] = { I2C_CLIENT_END };
+-static unsigned short normal_addr[] = { I2C_CLIENT_END, I2C_CLIENT_END };
+-
+-static struct i2c_client_address_data addr_data = {
+-	.normal_i2c	= normal_addr,
+-	.probe		= ignore,
+-	.ignore		= ignore,
+-};
+-
+-struct m41t00_chip_info {
+-	u8	type;
+-	char	*name;
+-	u8	read_limit;
+-	u8	sec;		/* Offsets for chip regs */
+-	u8	min;
+-	u8	hour;
+-	u8	day;
+-	u8	mon;
+-	u8	year;
+-	u8	alarm_mon;
+-	u8	alarm_hour;
+-	u8	sqw;
+-	u8	sqw_freq;
+-};
+-
+-static struct m41t00_chip_info m41t00_chip_info_tbl[] = {
+-	{
+-		.type		= M41T00_TYPE_M41T00,
+-		.name		= "m41t00",
+-		.read_limit	= 5,
+-		.sec		= 0,
+-		.min		= 1,
+-		.hour		= 2,
+-		.day		= 4,
+-		.mon		= 5,
+-		.year		= 6,
+-	},
+-	{
+-		.type		= M41T00_TYPE_M41T81,
+-		.name		= "m41t81",
+-		.read_limit	= 1,
+-		.sec		= 1,
+-		.min		= 2,
+-		.hour		= 3,
+-		.day		= 5,
+-		.mon		= 6,
+-		.year		= 7,
+-		.alarm_mon	= 0xa,
+-		.alarm_hour	= 0xc,
+-		.sqw		= 0x13,
+-	},
+-	{
+-		.type		= M41T00_TYPE_M41T85,
+-		.name		= "m41t85",
+-		.read_limit	= 1,
+-		.sec		= 1,
+-		.min		= 2,
+-		.hour		= 3,
+-		.day		= 5,
+-		.mon		= 6,
+-		.year		= 7,
+-		.alarm_mon	= 0xa,
+-		.alarm_hour	= 0xc,
+-		.sqw		= 0x13,
+-	},
+-};
+-static struct m41t00_chip_info *m41t00_chip;
+-
+-ulong
+-m41t00_get_rtc_time(void)
+-{
+-	s32 sec, min, hour, day, mon, year;
+-	s32 sec1, min1, hour1, day1, mon1, year1;
+-	u8 reads = 0;
+-	u8 buf[8], msgbuf[1] = { 0 }; /* offset into rtc's regs */
+-	struct i2c_msg msgs[] = {
+-		{
+-			.addr	= save_client->addr,
+-			.flags	= 0,
+-			.len	= 1,
+-			.buf	= msgbuf,
+-		},
+-		{
+-			.addr	= save_client->addr,
+-			.flags	= I2C_M_RD,
+-			.len	= 8,
+-			.buf	= buf,
+-		},
+-	};
+-
+-	sec = min = hour = day = mon = year = 0;
+-
+-	do {
+-		if (i2c_transfer(save_client->adapter, msgs, 2) < 0)
+-			goto read_err;
+-
+-		sec1 = sec;
+-		min1 = min;
+-		hour1 = hour;
+-		day1 = day;
+-		mon1 = mon;
+-		year1 = year;
+-
+-		sec = buf[m41t00_chip->sec] & 0x7f;
+-		min = buf[m41t00_chip->min] & 0x7f;
+-		hour = buf[m41t00_chip->hour] & 0x3f;
+-		day = buf[m41t00_chip->day] & 0x3f;
+-		mon = buf[m41t00_chip->mon] & 0x1f;
+-		year = buf[m41t00_chip->year];
+-	} while ((++reads < m41t00_chip->read_limit) && ((sec != sec1)
+-			|| (min != min1) || (hour != hour1) || (day != day1)
+-			|| (mon != mon1) || (year != year1)));
+-
+-	if ((m41t00_chip->read_limit > 1) && ((sec != sec1) || (min != min1)
+-			|| (hour != hour1) || (day != day1) || (mon != mon1)
+-			|| (year != year1)))
+-		goto read_err;
+-
+-	sec = BCD2BIN(sec);
+-	min = BCD2BIN(min);
+-	hour = BCD2BIN(hour);
+-	day = BCD2BIN(day);
+-	mon = BCD2BIN(mon);
+-	year = BCD2BIN(year);
+-
+-	year += 1900;
+-	if (year < 1970)
+-		year += 100;
+-
+-	return mktime(year, mon, day, hour, min, sec);
+-
+-read_err:
+-	dev_err(&save_client->dev, "m41t00_get_rtc_time: Read error\n");
 -	return 0;
-+	return (q) ? wait_master_done(adap) : 0;
- }
- 
- static u32
-@@ -262,7 +274,8 @@ au1550_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num)
- 
- 	for (i = 0; !err && i < num; i++) {
- 		p = &msgs[i];
--		err = do_address(adap, p->addr, p->flags & I2C_M_RD);
-+		err = do_address(adap, p->addr, p->flags & I2C_M_RD,
-+				 (p->len == 0));
- 		if (err || !p->len)
- 			continue;
- 		if (p->flags & I2C_M_RD)
-@@ -294,18 +307,48 @@ static const struct i2c_algorithm au1550_algo = {
-  * Prior to calling us, the 50MHz clock frequency and routing
-  * must have been set up for the PSC indicated by the adapter.
-  */
--int
--i2c_au1550_add_bus(struct i2c_adapter *i2c_adap)
-+static int __devinit
-+i2c_au1550_probe(struct platform_device *pdev)
- {
--	struct i2c_au1550_data *adap = i2c_adap->algo_data;
--	volatile psc_smb_t	*sp;
--	u32	stat;
-+	struct i2c_au1550_data *priv;
-+	volatile psc_smb_t *sp;
-+	struct resource *r;
-+	u32 stat;
-+	int ret;
-+
-+	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-+	if (!r) {
-+		ret = -ENODEV;
-+		goto out;
-+	}
-+
-+	priv = kzalloc(sizeof(struct i2c_au1550_data), GFP_KERNEL);
-+	if (!priv) {
-+		ret = -ENOMEM;
-+		goto out;
-+	}
-+
-+	priv->ioarea = request_mem_region(r->start, r->end - r->start + 1,
-+					  pdev->name);
-+	if (!priv->ioarea) {
-+		ret = -EBUSY;
-+		goto out_mem;
-+	}
- 
--	i2c_adap->algo = &au1550_algo;
-+	priv->psc_base = r->start;
-+	priv->xfer_timeout = 200;
-+	priv->ack_timeout = 200;
-+
-+	priv->adap.id = I2C_HW_AU1550_PSC;
-+	priv->adap.nr = pdev->id;
-+	priv->adap.algo = &au1550_algo;
-+	priv->adap.algo_data = priv;
-+	priv->adap.dev.parent = &pdev->dev;
-+	strlcpy(priv->adap.name, "Au1xxx PSC I2C", sizeof(priv->adap.name));
- 
- 	/* Now, set up the PSC for SMBus PIO mode.
- 	*/
--	sp = (volatile psc_smb_t *)(adap->psc_base);
-+	sp = (volatile psc_smb_t *)priv->psc_base;
- 	sp->psc_ctrl = PSC_CTRL_DISABLE;
- 	au_sync();
- 	sp->psc_sel = PSC_SEL_PS_SMBUSMODE;
-@@ -343,87 +386,87 @@ i2c_au1550_add_bus(struct i2c_adapter *i2c_adap)
- 		au_sync();
- 	} while ((stat & PSC_SMBSTAT_DR) == 0);
- 
--	return i2c_add_adapter(i2c_adap);
 -}
-+	ret = i2c_add_numbered_adapter(&priv->adap);
-+	if (ret == 0) {
-+		platform_set_drvdata(pdev, priv);
-+		return 0;
-+	}
- 
-+	/* disable the PSC */
-+	sp->psc_smbcfg = 0;
-+	sp->psc_ctrl = PSC_CTRL_DISABLE;
-+	au_sync();
- 
--int
--i2c_au1550_del_bus(struct i2c_adapter *adap)
-+	release_resource(priv->ioarea);
-+	kfree(priv->ioarea);
-+out_mem:
-+	kfree(priv);
-+out:
-+	return ret;
-+}
-+
-+static int __devexit
-+i2c_au1550_remove(struct platform_device *pdev)
- {
--	return i2c_del_adapter(adap);
-+	struct i2c_au1550_data *priv = platform_get_drvdata(pdev);
-+	volatile psc_smb_t *sp = (volatile psc_smb_t *)priv->psc_base;
-+
-+	platform_set_drvdata(pdev, NULL);
-+	i2c_del_adapter(&priv->adap);
-+	sp->psc_smbcfg = 0;
-+	sp->psc_ctrl = PSC_CTRL_DISABLE;
-+	au_sync();
-+	release_resource(priv->ioarea);
-+	kfree(priv->ioarea);
-+	kfree(priv);
-+	return 0;
- }
- 
- static int
--pb1550_reg(struct i2c_client *client)
-+i2c_au1550_suspend(struct platform_device *pdev, pm_message_t state)
- {
-+	struct i2c_au1550_data *priv = platform_get_drvdata(pdev);
-+	volatile psc_smb_t *sp = (volatile psc_smb_t *)priv->psc_base;
-+
-+	sp->psc_ctrl = PSC_CTRL_SUSPEND;
-+	au_sync();
- 	return 0;
- }
- 
- static int
--pb1550_unreg(struct i2c_client *client)
-+i2c_au1550_resume(struct platform_device *pdev)
- {
-+	struct i2c_au1550_data *priv = platform_get_drvdata(pdev);
-+	volatile psc_smb_t *sp = (volatile psc_smb_t *)priv->psc_base;
-+
-+	sp->psc_ctrl = PSC_CTRL_ENABLE;
-+	au_sync();
-+	while (!(sp->psc_smbstat & PSC_SMBSTAT_SR))
-+		au_sync();
- 	return 0;
- }
- 
--static struct i2c_au1550_data pb1550_i2c_info = {
--	SMBUS_PSC_BASE, 200, 200
--};
+-EXPORT_SYMBOL_GPL(m41t00_get_rtc_time);
+-
+-static void
+-m41t00_set(void *arg)
+-{
+-	struct rtc_time	tm;
+-	int nowtime = *(int *)arg;
+-	s32 sec, min, hour, day, mon, year;
+-	u8 wbuf[9], *buf = &wbuf[1], msgbuf[1] = { 0 };
+-	struct i2c_msg msgs[] = {
+-		{
+-			.addr	= save_client->addr,
+-			.flags	= 0,
+-			.len	= 1,
+-			.buf	= msgbuf,
+-		},
+-		{
+-			.addr	= save_client->addr,
+-			.flags	= I2C_M_RD,
+-			.len	= 8,
+-			.buf	= buf,
+-		},
+-	};
+-
+-	to_tm(nowtime, &tm);
+-	tm.tm_year = (tm.tm_year - 1900) % 100;
+-
+-	sec = BIN2BCD(tm.tm_sec);
+-	min = BIN2BCD(tm.tm_min);
+-	hour = BIN2BCD(tm.tm_hour);
+-	day = BIN2BCD(tm.tm_mday);
+-	mon = BIN2BCD(tm.tm_mon);
+-	year = BIN2BCD(tm.tm_year);
+-
+-	/* Read reg values into buf[0..7]/wbuf[1..8] */
+-	if (i2c_transfer(save_client->adapter, msgs, 2) < 0) {
+-		dev_err(&save_client->dev, "m41t00_set: Read error\n");
+-		return;
+-	}
+-
+-	wbuf[0] = 0; /* offset into rtc's regs */
+-	buf[m41t00_chip->sec] = (buf[m41t00_chip->sec] & ~0x7f) | (sec & 0x7f);
+-	buf[m41t00_chip->min] = (buf[m41t00_chip->min] & ~0x7f) | (min & 0x7f);
+-	buf[m41t00_chip->hour] = (buf[m41t00_chip->hour] & ~0x3f) | (hour& 0x3f);
+-	buf[m41t00_chip->day] = (buf[m41t00_chip->day] & ~0x3f) | (day & 0x3f);
+-	buf[m41t00_chip->mon] = (buf[m41t00_chip->mon] & ~0x1f) | (mon & 0x1f);
+-	buf[m41t00_chip->year] = year;
+-
+-	if (i2c_master_send(save_client, wbuf, 9) < 0)
+-		dev_err(&save_client->dev, "m41t00_set: Write error\n");
+-}
 -
--static struct i2c_adapter pb1550_board_adapter = {
--	name:              "pb1550 adapter",
--	id:                I2C_HW_AU1550_PSC,
--	algo:              NULL,
--	algo_data:         &pb1550_i2c_info,
--	client_register:   pb1550_reg,
--	client_unregister: pb1550_unreg,
-+static struct platform_driver au1xpsc_smbus_driver = {
-+	.driver = {
-+		.name	= "au1xpsc_smbus",
-+		.owner	= THIS_MODULE,
-+	},
-+	.probe		= i2c_au1550_probe,
-+	.remove		= __devexit_p(i2c_au1550_remove),
-+	.suspend	= i2c_au1550_suspend,
-+	.resume		= i2c_au1550_resume,
- };
- 
--/* BIG hack to support the control interface on the Wolfson WM8731
-- * audio codec on the Pb1550 board.  We get an address and two data
-- * bytes to write, create an i2c message, and send it across the
-- * i2c transfer function.  We do this here because we have access to
-- * the i2c adapter structure.
-- */
--static struct i2c_msg wm_i2c_msg;  /* We don't want this stuff on the stack */
--static	u8 i2cbuf[2];
+-static ulong new_time;
+-/* well, isn't this API just _lovely_? */
+-static void
+-m41t00_barf(struct work_struct *unusable)
+-{
+-	m41t00_set(&new_time);
+-}
+-
+-static struct workqueue_struct *m41t00_wq;
+-static DECLARE_WORK(m41t00_work, m41t00_barf);
 -
 -int
--pb1550_wm_codec_write(u8 addr, u8 reg, u8 val)
+-m41t00_set_rtc_time(ulong nowtime)
 -{
--	wm_i2c_msg.addr = addr;
--	wm_i2c_msg.flags = 0;
--	wm_i2c_msg.buf = i2cbuf;
--	wm_i2c_msg.len = 2;
--	i2cbuf[0] = reg;
--	i2cbuf[1] = val;
+-	new_time = nowtime;
 -
--	return pb1550_board_adapter.algo->master_xfer(&pb1550_board_adapter, &wm_i2c_msg, 1);
+-	if (in_interrupt())
+-		queue_work(m41t00_wq, &m41t00_work);
+-	else
+-		m41t00_set(&new_time);
+-
+-	return 0;
 -}
+-EXPORT_SYMBOL_GPL(m41t00_set_rtc_time);
 -
- static int __init
- i2c_au1550_init(void)
- {
--	printk(KERN_INFO "Au1550 I2C: ");
+-/*
+- *****************************************************************************
+- *
+- *	platform_data Driver Interface
+- *
+- *****************************************************************************
+- */
+-static int __init
+-m41t00_platform_probe(struct platform_device *pdev)
+-{
+-	struct m41t00_platform_data *pdata;
+-	int i;
 -
--	/* This is where we would set up a 50MHz clock source
--	 * and routing.  On the Pb1550, the SMBus is PSC2, which
--	 * uses a shared clock with USB.  This has been already
--	 * configured by Yamon as a 48MHz clock, close enough
--	 * for our work.
--	 */
--        if (i2c_au1550_add_bus(&pb1550_board_adapter) < 0) {
--		printk("failed to initialize.\n");
--                return -ENODEV;
+-	if (pdev && (pdata = pdev->dev.platform_data)) {
+-		normal_addr[0] = pdata->i2c_addr;
+-
+-		for (i=0; i<ARRAY_SIZE(m41t00_chip_info_tbl); i++)
+-			if (m41t00_chip_info_tbl[i].type == pdata->type) {
+-				m41t00_chip = &m41t00_chip_info_tbl[i];
+-				m41t00_chip->sqw_freq = pdata->sqw_freq;
+-				return 0;
+-			}
 -	}
+-	return -ENODEV;
+-}
 -
--	printk("initialized.\n");
+-static int __exit
+-m41t00_platform_remove(struct platform_device *pdev)
+-{
 -	return 0;
-+	return platform_driver_register(&au1xpsc_smbus_driver);
- }
- 
- static void __exit
- i2c_au1550_exit(void)
- {
--	i2c_au1550_del_bus(&pb1550_board_adapter);
-+	platform_driver_unregister(&au1xpsc_smbus_driver);
- }
- 
- MODULE_AUTHOR("Dan Malek, Embedded Edge, LLC.");
-diff --git a/drivers/i2c/busses/i2c-au1550.h b/drivers/i2c/busses/i2c-au1550.h
-deleted file mode 100644
-index fce15d1..0000000
---- a/drivers/i2c/busses/i2c-au1550.h
-+++ /dev/null
-@@ -1,32 +0,0 @@
+-}
+-
+-static struct platform_driver m41t00_platform_driver = {
+-	.probe  = m41t00_platform_probe,
+-	.remove = m41t00_platform_remove,
+-	.driver = {
+-		.owner = THIS_MODULE,
+-		.name  = M41T00_DRV_NAME,
+-	},
+-};
+-
 -/*
-- * Copyright (C) 2004 Embedded Edge, LLC <dan at embeddededge.com>
-- * 2.6 port by Matt Porter <mporter at kernel.crashing.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.
+- *	Driver Interface
 - *
-- *  You 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.
+- *****************************************************************************
 - */
+-static int
+-m41t00_probe(struct i2c_adapter *adap, int addr, int kind)
+-{
+-	struct i2c_client *client;
+-	int rc;
 -
--#ifndef I2C_AU1550_H
--#define I2C_AU1550_H
+-	if (!i2c_check_functionality(adap, I2C_FUNC_I2C
+-			| I2C_FUNC_SMBUS_BYTE_DATA))
+-		return 0;
 -
--struct i2c_au1550_data {
--	u32	psc_base;
--	int	xfer_timeout;
--	int	ack_timeout;
+-	client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
+-	if (!client)
+-		return -ENOMEM;
+-
+-	strlcpy(client->name, m41t00_chip->name, I2C_NAME_SIZE);
+-	client->addr = addr;
+-	client->adapter = adap;
+-	client->driver = &m41t00_driver;
+-
+-	if ((rc = i2c_attach_client(client)))
+-		goto attach_err;
+-
+-	if (m41t00_chip->type != M41T00_TYPE_M41T00) {
+-		/* If asked, disable SQW, set SQW frequency & re-enable */
+-		if (m41t00_chip->sqw_freq)
+-			if (((rc = i2c_smbus_read_byte_data(client,
+-					m41t00_chip->alarm_mon)) < 0)
+-			 || ((rc = i2c_smbus_write_byte_data(client,
+-					m41t00_chip->alarm_mon, rc & ~0x40)) <0)
+-			 || ((rc = i2c_smbus_write_byte_data(client,
+-					m41t00_chip->sqw,
+-					m41t00_chip->sqw_freq)) < 0)
+-			 || ((rc = i2c_smbus_write_byte_data(client,
+-					m41t00_chip->alarm_mon, rc | 0x40)) <0))
+-				goto sqw_err;
+-
+-		/* Make sure HT (Halt Update) bit is cleared */
+-		if ((rc = i2c_smbus_read_byte_data(client,
+-				m41t00_chip->alarm_hour)) < 0)
+-			goto ht_err;
+-
+-		if (rc & 0x40)
+-			if ((rc = i2c_smbus_write_byte_data(client,
+-					m41t00_chip->alarm_hour, rc & ~0x40))<0)
+-				goto ht_err;
+-	}
+-
+-	/* Make sure ST (stop) bit is cleared */
+-	if ((rc = i2c_smbus_read_byte_data(client, m41t00_chip->sec)) < 0)
+-		goto st_err;
+-
+-	if (rc & 0x80)
+-		if ((rc = i2c_smbus_write_byte_data(client, m41t00_chip->sec,
+-				rc & ~0x80)) < 0)
+-			goto st_err;
+-
+-	m41t00_wq = create_singlethread_workqueue(m41t00_chip->name);
+-	save_client = client;
+-	return 0;
+-
+-st_err:
+-	dev_err(&client->dev, "m41t00_probe: Can't clear ST bit\n");
+-	goto attach_err;
+-ht_err:
+-	dev_err(&client->dev, "m41t00_probe: Can't clear HT bit\n");
+-	goto attach_err;
+-sqw_err:
+-	dev_err(&client->dev, "m41t00_probe: Can't set SQW Frequency\n");
+-attach_err:
+-	kfree(client);
+-	return rc;
+-}
+-
+-static int
+-m41t00_attach(struct i2c_adapter *adap)
+-{
+-	return i2c_probe(adap, &addr_data, m41t00_probe);
+-}
+-
+-static int
+-m41t00_detach(struct i2c_client *client)
+-{
+-	int rc;
+-
+-	if ((rc = i2c_detach_client(client)) == 0) {
+-		kfree(client);
+-		destroy_workqueue(m41t00_wq);
+-	}
+-	return rc;
+-}
+-
+-static struct i2c_driver m41t00_driver = {
+-	.driver = {
+-		.name	= M41T00_DRV_NAME,
+-	},
+-	.id		= I2C_DRIVERID_STM41T00,
+-	.attach_adapter	= m41t00_attach,
+-	.detach_client	= m41t00_detach,
 -};
 -
--int i2c_au1550_add_bus(struct i2c_adapter *);
--int i2c_au1550_del_bus(struct i2c_adapter *);
+-static int __init
+-m41t00_init(void)
+-{
+-	int rc;
 -
--#endif /* I2C_AU1550_H */
-diff --git a/drivers/i2c/busses/i2c-bfin-twi.c b/drivers/i2c/busses/i2c-bfin-twi.c
-index 67224a4..7dbdaeb 100644
---- a/drivers/i2c/busses/i2c-bfin-twi.c
-+++ b/drivers/i2c/busses/i2c-bfin-twi.c
-@@ -550,6 +550,7 @@ static int i2c_bfin_twi_probe(struct platform_device *dev)
- 
- 	p_adap = &iface->adap;
- 	p_adap->id = I2C_HW_BLACKFIN;
-+	p_adap->nr = dev->id;
- 	strlcpy(p_adap->name, dev->name, sizeof(p_adap->name));
- 	p_adap->algo = &bfin_twi_algorithm;
- 	p_adap->algo_data = iface;
-@@ -576,7 +577,7 @@ static int i2c_bfin_twi_probe(struct platform_device *dev)
- 	bfin_write_TWI_CONTROL(bfin_read_TWI_CONTROL() | TWI_ENA);
- 	SSYNC();
- 
--	rc = i2c_add_adapter(p_adap);
-+	rc = i2c_add_numbered_adapter(p_adap);
- 	if (rc < 0)
- 		free_irq(iface->irq, iface);
- 	else
-diff --git a/drivers/i2c/busses/i2c-davinci.c b/drivers/i2c/busses/i2c-davinci.c
-index 6767988..cce5a61 100644
---- a/drivers/i2c/busses/i2c-davinci.c
-+++ b/drivers/i2c/busses/i2c-davinci.c
-@@ -510,7 +510,6 @@ static int davinci_i2c_probe(struct platform_device *pdev)
+-	if (!(rc = platform_driver_register(&m41t00_platform_driver)))
+-		rc = i2c_add_driver(&m41t00_driver);
+-	return rc;
+-}
+-
+-static void __exit
+-m41t00_exit(void)
+-{
+-	i2c_del_driver(&m41t00_driver);
+-	platform_driver_unregister(&m41t00_platform_driver);
+-}
+-
+-module_init(m41t00_init);
+-module_exit(m41t00_exit);
+-
+-MODULE_AUTHOR("Mark A. Greer <mgreer at mvista.com>");
+-MODULE_DESCRIPTION("ST Microelectronics M41T00 RTC I2C Client Driver");
+-MODULE_LICENSE("GPL");
+diff --git a/drivers/i2c/chips/max6875.c b/drivers/i2c/chips/max6875.c
+index 64692f6..fb7ea56 100644
+--- a/drivers/i2c/chips/max6875.c
++++ b/drivers/i2c/chips/max6875.c
+@@ -34,7 +34,7 @@
+ #include <linux/mutex.h>
  
- 	/* FIXME */
- 	adap->timeout = 1;
--	adap->retries = 1;
+ /* Do not scan - the MAX6875 access method will write to some EEPROM chips */
+-static unsigned short normal_i2c[] = {I2C_CLIENT_END};
++static const unsigned short normal_i2c[] = { I2C_CLIENT_END };
  
- 	adap->nr = pdev->id;
- 	r = i2c_add_numbered_adapter(adap);
-diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c
-index ac27e5f..aa91579 100644
---- a/drivers/i2c/busses/i2c-i801.c
-+++ b/drivers/i2c/busses/i2c-i801.c
-@@ -4,6 +4,7 @@
-     Copyright (c) 1998 - 2002  Frodo Looijaard <frodol at dds.nl>,
-     Philip Edelbrock <phil at netroedge.com>, and Mark D. Studebaker
-     <mdsxyz123 at yahoo.com>
-+    Copyright (C) 2007         Jean Delvare <khali at linux-fr.org>
+ /* Insmod parameters */
+ I2C_CLIENT_INSMOD_1(max6875);
+diff --git a/drivers/i2c/chips/pcf8574.c b/drivers/i2c/chips/pcf8574.c
+index 21c6dd6..b3b830c 100644
+--- a/drivers/i2c/chips/pcf8574.c
++++ b/drivers/i2c/chips/pcf8574.c
+@@ -41,9 +41,11 @@
+ #include <linux/i2c.h>
  
-     This program is free software; you can redistribute it and/or modify
-     it under the terms of the GNU General Public License as published by
-@@ -21,25 +22,34 @@
- */
+ /* Addresses to scan */
+-static unsigned short normal_i2c[] = { 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+-					0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+-					I2C_CLIENT_END };
++static const unsigned short normal_i2c[] = {
++	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
++	0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
++	I2C_CLIENT_END
++};
  
- /*
--    SUPPORTED DEVICES	PCI ID
--    82801AA		2413
--    82801AB		2423
--    82801BA		2443
--    82801CA/CAM		2483
--    82801DB		24C3   (HW PEC supported)
--    82801EB		24D3   (HW PEC supported)
--    6300ESB		25A4
--    ICH6		266A
--    ICH7		27DA
--    ESB2		269B
--    ICH8		283E
--    ICH9		2930
--    Tolapai		5032
--    This driver supports several versions of Intel's I/O Controller Hubs (ICH).
--    For SMBus support, they are similar to the PIIX4 and are part
--    of Intel's '810' and other chipsets.
--    See the file Documentation/i2c/busses/i2c-i801 for details.
--    I2C Block Read and Process Call are not supported.
-+  Supports the following Intel I/O Controller Hubs (ICH):
+ /* Insmod parameters */
+ I2C_CLIENT_INSMOD_2(pcf8574, pcf8574a);
+diff --git a/drivers/i2c/chips/pcf8575.c b/drivers/i2c/chips/pcf8575.c
+new file mode 100644
+index 0000000..3ea08ac
+--- /dev/null
++++ b/drivers/i2c/chips/pcf8575.c
+@@ -0,0 +1,214 @@
++/*
++  pcf8575.c
 +
-+                                  I/O                     Block   I2C
-+                                  region  SMBus   Block   proc.   block
-+  Chip name             PCI ID    size    PEC     buffer  call    read
-+  ----------------------------------------------------------------------
-+  82801AA  (ICH)        0x2413     16      no      no      no      no
-+  82801AB  (ICH0)       0x2423     16      no      no      no      no
-+  82801BA  (ICH2)       0x2443     16      no      no      no      no
-+  82801CA  (ICH3)       0x2483     32     soft     no      no      no
-+  82801DB  (ICH4)       0x24c3     32     hard     yes     no      no
-+  82801E   (ICH5)       0x24d3     32     hard     yes     yes     yes
-+  6300ESB               0x25a4     32     hard     yes     yes     yes
-+  82801F   (ICH6)       0x266a     32     hard     yes     yes     yes
-+  6310ESB/6320ESB       0x269b     32     hard     yes     yes     yes
-+  82801G   (ICH7)       0x27da     32     hard     yes     yes     yes
-+  82801H   (ICH8)       0x283e     32     hard     yes     yes     yes
-+  82801I   (ICH9)       0x2930     32     hard     yes     yes     yes
-+  Tolapai               0x5032     32     hard     yes     ?       ?
++  About the PCF8575 chip: the PCF8575 is a 16-bit I/O expander for the I2C bus
++  produced by a.o. Philips Semiconductors.
 +
-+  Features supported by this driver:
-+  Software PEC                     no
-+  Hardware PEC                     yes
-+  Block buffer                     yes
-+  Block process call transaction   no
-+  I2C block read transaction       yes  (doesn't use the block buffer)
++  Copyright (C) 2006 Michael Hennerich, Analog Devices Inc.
++  <hennerich at blackfin.uclinux.org>
++  Based on pcf8574.c.
 +
-+  See the file Documentation/i2c/busses/i2c-i801 for details.
- */
- 
- /* Note: we assume there can only be one I801, with one SMBus interface */
-@@ -62,9 +72,9 @@
- #define SMBHSTDAT0	(5 + i801_smba)
- #define SMBHSTDAT1	(6 + i801_smba)
- #define SMBBLKDAT	(7 + i801_smba)
--#define SMBPEC		(8 + i801_smba)	/* ICH4 only */
--#define SMBAUXSTS	(12 + i801_smba)	/* ICH4 only */
--#define SMBAUXCTL	(13 + i801_smba)	/* ICH4 only */
-+#define SMBPEC		(8 + i801_smba)		/* ICH3 and later */
-+#define SMBAUXSTS	(12 + i801_smba)	/* ICH4 and later */
-+#define SMBAUXCTL	(13 + i801_smba)	/* ICH4 and later */
- 
- /* PCI Address Constants */
- #define SMBBAR		4
-@@ -91,13 +101,13 @@
- #define I801_BYTE		0x04
- #define I801_BYTE_DATA		0x08
- #define I801_WORD_DATA		0x0C
--#define I801_PROC_CALL		0x10	/* later chips only, unimplemented */
-+#define I801_PROC_CALL		0x10	/* unimplemented */
- #define I801_BLOCK_DATA		0x14
--#define I801_I2C_BLOCK_DATA	0x18	/* unimplemented */
-+#define I801_I2C_BLOCK_DATA	0x18	/* ICH5 and later */
- #define I801_BLOCK_LAST		0x34
--#define I801_I2C_BLOCK_LAST	0x38	/* unimplemented */
-+#define I801_I2C_BLOCK_LAST	0x38	/* ICH5 and later */
- #define I801_START		0x40
--#define I801_PEC_EN		0x80	/* ICH4 only */
-+#define I801_PEC_EN		0x80	/* ICH3 and later */
- 
- /* I801 Hosts Status register bits */
- #define SMBHSTSTS_BYTE_DONE	0x80
-@@ -113,7 +123,12 @@ static unsigned long i801_smba;
- static unsigned char i801_original_hstcfg;
- static struct pci_driver i801_driver;
- static struct pci_dev *I801_dev;
--static int isich4;
++  Copyright (c) 2007 Bart Van Assche <bart.vanassche at gmail.com>.
++  Ported this driver from ucLinux to the mainstream Linux kernel.
 +
-+#define FEATURE_SMBUS_PEC	(1 << 0)
-+#define FEATURE_BLOCK_BUFFER	(1 << 1)
-+#define FEATURE_BLOCK_PROC	(1 << 2)
-+#define FEATURE_I2C_BLOCK_READ	(1 << 3)
-+static unsigned int i801_features;
- 
- static int i801_transaction(int xact)
- {
-@@ -242,7 +257,8 @@ static int i801_block_transaction_by_block(union i2c_smbus_data *data,
- }
- 
- static int i801_block_transaction_byte_by_byte(union i2c_smbus_data *data,
--					       char read_write, int hwpec)
-+					       char read_write, int command,
-+					       int hwpec)
- {
- 	int i, len;
- 	int smbcmd;
-@@ -259,16 +275,24 @@ static int i801_block_transaction_byte_by_byte(union i2c_smbus_data *data,
- 	}
- 
- 	for (i = 1; i <= len; i++) {
--		if (i == len && read_write == I2C_SMBUS_READ)
--			smbcmd = I801_BLOCK_LAST;
--		else
--			smbcmd = I801_BLOCK_DATA;
-+		if (i == len && read_write == I2C_SMBUS_READ) {
-+			if (command == I2C_SMBUS_I2C_BLOCK_DATA)
-+				smbcmd = I801_I2C_BLOCK_LAST;
-+			else
-+				smbcmd = I801_BLOCK_LAST;
-+		} else {
-+			if (command == I2C_SMBUS_I2C_BLOCK_DATA
-+			 && read_write == I2C_SMBUS_READ)
-+				smbcmd = I801_I2C_BLOCK_DATA;
-+			else
-+				smbcmd = I801_BLOCK_DATA;
-+		}
- 		outb_p(smbcmd | ENABLE_INT9, SMBHSTCNT);
- 
- 		dev_dbg(&I801_dev->dev, "Block (pre %d): CNT=%02x, CMD=%02x, "
--			"ADD=%02x, DAT0=%02x, BLKDAT=%02x\n", i,
-+			"ADD=%02x, DAT0=%02x, DAT1=%02x, BLKDAT=%02x\n", i,
- 			inb_p(SMBHSTCNT), inb_p(SMBHSTCMD), inb_p(SMBHSTADD),
--			inb_p(SMBHSTDAT0), inb_p(SMBBLKDAT));
-+			inb_p(SMBHSTDAT0), inb_p(SMBHSTDAT1), inb_p(SMBBLKDAT));
- 
- 		/* Make sure the SMBus host is ready to start transmitting */
- 		temp = inb_p(SMBHSTSTS);
-@@ -332,7 +356,8 @@ static int i801_block_transaction_byte_by_byte(union i2c_smbus_data *data,
- 			dev_dbg(&I801_dev->dev, "Error: no response!\n");
- 		}
- 
--		if (i == 1 && read_write == I2C_SMBUS_READ) {
-+		if (i == 1 && read_write == I2C_SMBUS_READ
-+		 && command != I2C_SMBUS_I2C_BLOCK_DATA) {
- 			len = inb_p(SMBHSTDAT0);
- 			if (len < 1 || len > I2C_SMBUS_BLOCK_MAX)
- 				return -1;
-@@ -353,9 +378,9 @@ static int i801_block_transaction_byte_by_byte(union i2c_smbus_data *data,
- 				temp);
- 		}
- 		dev_dbg(&I801_dev->dev, "Block (post %d): CNT=%02x, CMD=%02x, "
--			"ADD=%02x, DAT0=%02x, BLKDAT=%02x\n", i,
-+			"ADD=%02x, DAT0=%02x, DAT1=%02x, BLKDAT=%02x\n", i,
- 			inb_p(SMBHSTCNT), inb_p(SMBHSTCMD), inb_p(SMBHSTADD),
--			inb_p(SMBHSTDAT0), inb_p(SMBBLKDAT));
-+			inb_p(SMBHSTDAT0), inb_p(SMBHSTDAT1), inb_p(SMBBLKDAT));
- 
- 		if (result < 0)
- 			return result;
-@@ -384,33 +409,38 @@ static int i801_block_transaction(union i2c_smbus_data *data, char read_write,
- 			pci_read_config_byte(I801_dev, SMBHSTCFG, &hostc);
- 			pci_write_config_byte(I801_dev, SMBHSTCFG,
- 					      hostc | SMBHSTCFG_I2C_EN);
--		} else {
-+		} else if (!(i801_features & FEATURE_I2C_BLOCK_READ)) {
- 			dev_err(&I801_dev->dev,
--				"I2C_SMBUS_I2C_BLOCK_READ not DB!\n");
-+				"I2C block read is unsupported!\n");
- 			return -1;
- 		}
- 	}
- 
--	if (read_write == I2C_SMBUS_WRITE) {
-+	if (read_write == I2C_SMBUS_WRITE
-+	 || command == I2C_SMBUS_I2C_BLOCK_DATA) {
- 		if (data->block[0] < 1)
- 			data->block[0] = 1;
- 		if (data->block[0] > I2C_SMBUS_BLOCK_MAX)
- 			data->block[0] = I2C_SMBUS_BLOCK_MAX;
- 	} else {
--		data->block[0] = 32;	/* max for reads */
-+		data->block[0] = 32;	/* max for SMBus block reads */
- 	}
- 
--	if (isich4 && i801_set_block_buffer_mode() == 0 )
-+	if ((i801_features & FEATURE_BLOCK_BUFFER)
-+	 && !(command == I2C_SMBUS_I2C_BLOCK_DATA
-+	      && read_write == I2C_SMBUS_READ)
-+	 && i801_set_block_buffer_mode() == 0)
- 		result = i801_block_transaction_by_block(data, read_write,
- 							 hwpec);
- 	else
- 		result = i801_block_transaction_byte_by_byte(data, read_write,
--							     hwpec);
-+							     command, hwpec);
- 
- 	if (result == 0 && hwpec)
- 		i801_wait_hwpec();
- 
--	if (command == I2C_SMBUS_I2C_BLOCK_DATA) {
-+	if (command == I2C_SMBUS_I2C_BLOCK_DATA
-+	 && read_write == I2C_SMBUS_WRITE) {
- 		/* restore saved configuration register value */
- 		pci_write_config_byte(I801_dev, SMBHSTCFG, hostc);
- 	}
-@@ -426,7 +456,7 @@ static s32 i801_access(struct i2c_adapter * adap, u16 addr,
- 	int block = 0;
- 	int ret, xact = 0;
- 
--	hwpec = isich4 && (flags & I2C_CLIENT_PEC)
-+	hwpec = (i801_features & FEATURE_SMBUS_PEC) && (flags & I2C_CLIENT_PEC)
- 		&& size != I2C_SMBUS_QUICK
- 		&& size != I2C_SMBUS_I2C_BLOCK_DATA;
- 
-@@ -462,12 +492,23 @@ static s32 i801_access(struct i2c_adapter * adap, u16 addr,
- 		xact = I801_WORD_DATA;
- 		break;
- 	case I2C_SMBUS_BLOCK_DATA:
--	case I2C_SMBUS_I2C_BLOCK_DATA:
- 		outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
- 		       SMBHSTADD);
- 		outb_p(command, SMBHSTCMD);
- 		block = 1;
- 		break;
-+	case I2C_SMBUS_I2C_BLOCK_DATA:
-+		/* NB: page 240 of ICH5 datasheet shows that the R/#W
-+		 * bit should be cleared here, even when reading */
-+		outb_p((addr & 0x7f) << 1, SMBHSTADD);
-+		if (read_write == I2C_SMBUS_READ) {
-+			/* NB: page 240 of ICH5 datasheet also shows
-+			 * that DATA1 is the cmd field when reading */
-+			outb_p(command, SMBHSTDAT1);
-+		} else
-+			outb_p(command, SMBHSTCMD);
-+		block = 1;
-+		break;
- 	case I2C_SMBUS_PROC_CALL:
- 	default:
- 		dev_err(&I801_dev->dev, "Unsupported transaction %d\n", size);
-@@ -487,7 +528,7 @@ static s32 i801_access(struct i2c_adapter * adap, u16 addr,
- 	/* Some BIOSes don't like it when PEC is enabled at reboot or resume
- 	   time, so we forcibly disable it after every transaction. Turn off
- 	   E32B for the same reason. */
--	if (hwpec)
-+	if (hwpec || block)
- 		outb_p(inb_p(SMBAUXCTL) & ~(SMBAUXCTL_CRC | SMBAUXCTL_E32B),
- 		       SMBAUXCTL);
- 
-@@ -514,9 +555,11 @@ static s32 i801_access(struct i2c_adapter * adap, u16 addr,
- static u32 i801_func(struct i2c_adapter *adapter)
- {
- 	return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
--	    I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
--	    I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_WRITE_I2C_BLOCK
--	     | (isich4 ? I2C_FUNC_SMBUS_PEC : 0);
-+	       I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
-+	       I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_WRITE_I2C_BLOCK |
-+	       ((i801_features & FEATURE_SMBUS_PEC) ? I2C_FUNC_SMBUS_PEC : 0) |
-+	       ((i801_features & FEATURE_I2C_BLOCK_READ) ?
-+		I2C_FUNC_SMBUS_READ_I2C_BLOCK : 0);
- }
- 
- static const struct i2c_algorithm smbus_algorithm = {
-@@ -556,8 +599,8 @@ static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id
- 	int err;
- 
- 	I801_dev = dev;
-+	i801_features = 0;
- 	switch (dev->device) {
--	case PCI_DEVICE_ID_INTEL_82801DB_3:
- 	case PCI_DEVICE_ID_INTEL_82801EB_3:
- 	case PCI_DEVICE_ID_INTEL_ESB_4:
- 	case PCI_DEVICE_ID_INTEL_ICH6_16:
-@@ -565,11 +608,13 @@ static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id
- 	case PCI_DEVICE_ID_INTEL_ESB2_17:
- 	case PCI_DEVICE_ID_INTEL_ICH8_5:
- 	case PCI_DEVICE_ID_INTEL_ICH9_6:
-+		i801_features |= FEATURE_I2C_BLOCK_READ;
-+		/* fall through */
-+	case PCI_DEVICE_ID_INTEL_82801DB_3:
- 	case PCI_DEVICE_ID_INTEL_TOLAPAI_1:
--		isich4 = 1;
-+		i801_features |= FEATURE_SMBUS_PEC;
-+		i801_features |= FEATURE_BLOCK_BUFFER;
- 		break;
--	default:
--		isich4 = 0;
- 	}
- 
- 	err = pci_enable_device(dev);
-@@ -610,6 +655,11 @@ static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id
- 	else
- 		dev_dbg(&dev->dev, "SMBus using PCI Interrupt\n");
- 
-+	/* Clear special mode bits */
-+	if (i801_features & (FEATURE_SMBUS_PEC | FEATURE_BLOCK_BUFFER))
-+		outb_p(inb_p(SMBAUXCTL) & ~(SMBAUXCTL_CRC | SMBAUXCTL_E32B),
-+		       SMBAUXCTL);
++  This program is free software; you can redistribute it and/or modify
++  it under the terms of the GNU General Public License as published by
++  the Free Software Foundation; either version 2 of the License, or
++  (at your option) any later version.
 +
- 	/* set up the sysfs linkage to our parent device */
- 	i801_adapter.dev.parent = &dev->dev;
- 
-@@ -678,9 +728,8 @@ static void __exit i2c_i801_exit(void)
- 	pci_unregister_driver(&i801_driver);
- }
- 
--MODULE_AUTHOR ("Frodo Looijaard <frodol at dds.nl>, "
--		"Philip Edelbrock <phil at netroedge.com>, "
--		"and Mark D. Studebaker <mdsxyz123 at yahoo.com>");
-+MODULE_AUTHOR("Mark D. Studebaker <mdsxyz123 at yahoo.com>, "
-+	      "Jean Delvare <khali at linux-fr.org>");
- MODULE_DESCRIPTION("I801 SMBus driver");
- MODULE_LICENSE("GPL");
- 
-diff --git a/drivers/i2c/busses/i2c-ibm_iic.c b/drivers/i2c/busses/i2c-ibm_iic.c
-index 9b43ff7..7c7eb0c 100644
---- a/drivers/i2c/busses/i2c-ibm_iic.c
-+++ b/drivers/i2c/busses/i2c-ibm_iic.c
-@@ -6,7 +6,7 @@
-  * Copyright (c) 2003, 2004 Zultys Technologies.
-  * Eugene Surovegin <eugene.surovegin at zultys.com> or <ebs at ebshome.net>
-  *
-- * Based on original work by 
-+ * Based on original work by
-  * 	Ian DaSilva  <idasilva at mvista.com>
-  *      Armin Kuster <akuster at mvista.com>
-  * 	Matt Porter  <mporter at mvista.com>
-@@ -86,8 +86,8 @@ static void dump_iic_regs(const char* header, struct ibm_iic_private* dev)
- 	       KERN_DEBUG "  sts      = 0x%02x, extsts = 0x%02x\n"
- 	       KERN_DEBUG "  clkdiv   = 0x%02x, xfrcnt = 0x%02x\n"
- 	       KERN_DEBUG "  xtcntlss = 0x%02x, directcntl = 0x%02x\n",
--		in_8(&iic->cntl), in_8(&iic->mdcntl), in_8(&iic->sts), 
--		in_8(&iic->extsts), in_8(&iic->clkdiv), in_8(&iic->xfrcnt), 
-+		in_8(&iic->cntl), in_8(&iic->mdcntl), in_8(&iic->sts),
-+		in_8(&iic->extsts), in_8(&iic->clkdiv), in_8(&iic->xfrcnt),
- 		in_8(&iic->xtcntlss), in_8(&iic->directcntl));
- }
- #  define DUMP_REGS(h,dev)	dump_iic_regs((h),(dev))
-@@ -125,7 +125,7 @@ static inline void iic_interrupt_mode(struct ibm_iic_private* dev, int enable)
- {
- 	out_8(&dev->vaddr->intmsk, enable ? INTRMSK_EIMTC : 0);
- }
-- 
++  This program is distributed in the hope that it will be useful,
++  but WITHOUT ANY WARRANTY; without even the implied warranty of
++  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++  GNU General Public License for more details.
 +
- /*
-  * Initialize IIC interface.
-  */
-@@ -134,7 +134,7 @@ static void iic_dev_init(struct ibm_iic_private* dev)
- 	volatile struct iic_regs __iomem *iic = dev->vaddr;
- 
- 	DBG("%d: init\n", dev->idx);
--	
++  You 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.
++*/
 +
- 	/* Clear master address */
- 	out_8(&iic->lmadr, 0);
- 	out_8(&iic->hmadr, 0);
-@@ -160,7 +160,7 @@ static void iic_dev_init(struct ibm_iic_private* dev)
- 
- 	/* Clear control register */
- 	out_8(&iic->cntl, 0);
--	
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/i2c.h>
++#include <linux/slab.h>  /* kzalloc() */
++#include <linux/sysfs.h> /* sysfs_create_group() */
 +
- 	/* Enable interrupts if possible */
- 	iic_interrupt_mode(dev, dev->irq >= 0);
- 
-@@ -171,7 +171,7 @@ static void iic_dev_init(struct ibm_iic_private* dev)
- 	DUMP_REGS("iic_init", dev);
- }
- 
--/* 
-+/*
-  * Reset IIC interface
-  */
- static void iic_dev_reset(struct ibm_iic_private* dev)
-@@ -179,42 +179,42 @@ static void iic_dev_reset(struct ibm_iic_private* dev)
- 	volatile struct iic_regs __iomem *iic = dev->vaddr;
- 	int i;
- 	u8 dc;
--	
++/* Addresses to scan */
++static const unsigned short normal_i2c[] = {
++	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
++	I2C_CLIENT_END
++};
 +
- 	DBG("%d: soft reset\n", dev->idx);
- 	DUMP_REGS("reset", dev);
--	
++/* Insmod parameters */
++I2C_CLIENT_INSMOD;
 +
-     	/* Place chip in the reset state */
- 	out_8(&iic->xtcntlss, XTCNTLSS_SRST);
--	
 +
- 	/* Check if bus is free */
--	dc = in_8(&iic->directcntl);	
-+	dc = in_8(&iic->directcntl);
- 	if (!DIRCTNL_FREE(dc)){
- 		DBG("%d: trying to regain bus control\n", dev->idx);
--	
++/* Each client has this additional data */
++struct pcf8575_data {
++	struct i2c_client client;
++	int write;		/* last written value, or error code */
++};
 +
- 		/* Try to set bus free state */
--		out_8(&iic->directcntl, DIRCNTL_SDAC | DIRCNTL_SCC);	
--	
-+		out_8(&iic->directcntl, DIRCNTL_SDAC | DIRCNTL_SCC);
++static int pcf8575_attach_adapter(struct i2c_adapter *adapter);
++static int pcf8575_detect(struct i2c_adapter *adapter, int address, int kind);
++static int pcf8575_detach_client(struct i2c_client *client);
 +
- 		/* Wait until we regain bus control */
- 		for (i = 0; i < 100; ++i){
- 			dc = in_8(&iic->directcntl);
- 			if (DIRCTNL_FREE(dc))
- 				break;
--			
++/* This is the driver that will be inserted */
++static struct i2c_driver pcf8575_driver = {
++	.driver = {
++		.owner	= THIS_MODULE,
++		.name	= "pcf8575",
++	},
++	.attach_adapter	= pcf8575_attach_adapter,
++	.detach_client	= pcf8575_detach_client,
++};
 +
- 			/* Toggle SCL line */
- 			dc ^= DIRCNTL_SCC;
- 			out_8(&iic->directcntl, dc);
- 			udelay(10);
- 			dc ^= DIRCNTL_SCC;
- 			out_8(&iic->directcntl, dc);
--			
++/* following are the sysfs callback functions */
++static ssize_t show_read(struct device *dev, struct device_attribute *attr,
++			 char *buf)
++{
++	struct i2c_client *client = to_i2c_client(dev);
++	u16 val;
++	u8 iopin_state[2];
 +
- 			/* be nice */
- 			cond_resched();
- 		}
- 	}
--	
++	i2c_master_recv(client, iopin_state, 2);
 +
- 	/* Remove reset */
- 	out_8(&iic->xtcntlss, 0);
--	
++	val = iopin_state[0];
++	val |= iopin_state[1] << 8;
 +
- 	/* Reinitialize interface */
- 	iic_dev_init(dev);
- }
-@@ -324,14 +324,14 @@ static irqreturn_t iic_handler(int irq, void *dev_id)
- {
- 	struct ibm_iic_private* dev = (struct ibm_iic_private*)dev_id;
- 	volatile struct iic_regs __iomem *iic = dev->vaddr;
--	
--	DBG2("%d: irq handler, STS = 0x%02x, EXTSTS = 0x%02x\n", 
++	return sprintf(buf, "%u\n", val);
++}
 +
-+	DBG2("%d: irq handler, STS = 0x%02x, EXTSTS = 0x%02x\n",
- 	     dev->idx, in_8(&iic->sts), in_8(&iic->extsts));
--	
++static DEVICE_ATTR(read, S_IRUGO, show_read, NULL);
 +
- 	/* Acknowledge IRQ and wakeup iic_wait_for_tc */
- 	out_8(&iic->sts, STS_IRQA | STS_SCMP);
- 	wake_up_interruptible(&dev->wq);
--	
++static ssize_t show_write(struct device *dev, struct device_attribute *attr,
++			  char *buf)
++{
++	struct pcf8575_data *data = dev_get_drvdata(dev);
++	if (data->write < 0)
++		return data->write;
++	return sprintf(buf, "%d\n", data->write);
++}
 +
- 	return IRQ_HANDLED;
- }
- 
-@@ -341,19 +341,19 @@ static irqreturn_t iic_handler(int irq, void *dev_id)
-  */
- static int iic_xfer_result(struct ibm_iic_private* dev)
- {
--	volatile struct iic_regs __iomem *iic = dev->vaddr;	
--	
-+	volatile struct iic_regs __iomem *iic = dev->vaddr;
++static ssize_t set_write(struct device *dev, struct device_attribute *attr,
++			 const char *buf, size_t count)
++{
++	struct i2c_client *client = to_i2c_client(dev);
++	struct pcf8575_data *data = i2c_get_clientdata(client);
++	unsigned long val = simple_strtoul(buf, NULL, 10);
++	u8 iopin_state[2];
 +
- 	if (unlikely(in_8(&iic->sts) & STS_ERR)){
--		DBG("%d: xfer error, EXTSTS = 0x%02x\n", dev->idx, 
-+		DBG("%d: xfer error, EXTSTS = 0x%02x\n", dev->idx,
- 			in_8(&iic->extsts));
--				
++	if (val > 0xffff)
++		return -EINVAL;
 +
- 		/* Clear errors and possible pending IRQs */
--		out_8(&iic->extsts, EXTSTS_IRQP | EXTSTS_IRQD | 
-+		out_8(&iic->extsts, EXTSTS_IRQP | EXTSTS_IRQD |
- 			EXTSTS_LA | EXTSTS_ICT | EXTSTS_XFRA);
--			
++	data->write = val;
++
++	iopin_state[0] = val & 0xFF;
++	iopin_state[1] = val >> 8;
++
++	i2c_master_send(client, iopin_state, 2);
++
++	return count;
++}
++
++static DEVICE_ATTR(write, S_IWUSR | S_IRUGO, show_write, set_write);
++
++static struct attribute *pcf8575_attributes[] = {
++	&dev_attr_read.attr,
++	&dev_attr_write.attr,
++	NULL
++};
++
++static const struct attribute_group pcf8575_attr_group = {
++	.attrs = pcf8575_attributes,
++};
++
++/*
++ * Real code
++ */
++
++static int pcf8575_attach_adapter(struct i2c_adapter *adapter)
++{
++	return i2c_probe(adapter, &addr_data, pcf8575_detect);
++}
++
++/* This function is called by i2c_probe */
++static int pcf8575_detect(struct i2c_adapter *adapter, int address, int kind)
++{
++	struct i2c_client *client;
++	struct pcf8575_data *data;
++	int err = 0;
++
++	if (!i2c_check_functionality(adapter, I2C_FUNC_I2C))
++		goto exit;
++
++	/* OK. For now, we presume we have a valid client. We now create the
++	   client structure, even though we cannot fill it completely yet. */
++	data = kzalloc(sizeof(struct pcf8575_data), GFP_KERNEL);
++	if (!data) {
++		err = -ENOMEM;
++		goto exit;
++	}
++
++	client = &data->client;
++	i2c_set_clientdata(client, data);
++	client->addr = address;
++	client->adapter = adapter;
++	client->driver = &pcf8575_driver;
++	strlcpy(client->name, "pcf8575", I2C_NAME_SIZE);
++	data->write = -EAGAIN;
++
++	/* This is the place to detect whether the chip at the specified
++	   address really is a PCF8575 chip. However, there is no method known
++	   to detect whether an I2C chip is a PCF8575 or any other I2C chip. */
 +
- 		/* Flush master data buffer */
- 		out_8(&iic->mdcntl, in_8(&iic->mdcntl) | MDCNTL_FMDB);
--		
++	/* Tell the I2C layer a new client has arrived */
++	err = i2c_attach_client(client);
++	if (err)
++		goto exit_free;
 +
- 		/* Is bus free?
- 		 * If error happened during combined xfer
- 		 * IIC interface is usually stuck in some strange
-@@ -376,11 +376,11 @@ static void iic_abort_xfer(struct ibm_iic_private* dev)
- {
- 	volatile struct iic_regs __iomem *iic = dev->vaddr;
- 	unsigned long x;
--	
++	/* Register sysfs hooks */
++	err = sysfs_create_group(&client->dev.kobj, &pcf8575_attr_group);
++	if (err)
++		goto exit_detach;
 +
- 	DBG("%d: iic_abort_xfer\n", dev->idx);
--	
++	return 0;
 +
- 	out_8(&iic->cntl, CNTL_HMT);
--	
++exit_detach:
++	i2c_detach_client(client);
++exit_free:
++	kfree(data);
++exit:
++	return err;
++}
 +
- 	/*
- 	 * Wait for the abort command to complete.
- 	 * It's not worth to be optimized, just poll (timeout >= 1 tick)
-@@ -405,13 +405,13 @@ static void iic_abort_xfer(struct ibm_iic_private* dev)
-  * Returns the number of transferred bytes or error (<0)
-  */
- static int iic_wait_for_tc(struct ibm_iic_private* dev){
--	
++static int pcf8575_detach_client(struct i2c_client *client)
++{
++	int err;
 +
- 	volatile struct iic_regs __iomem *iic = dev->vaddr;
- 	int ret = 0;
--	
++	sysfs_remove_group(&client->dev.kobj, &pcf8575_attr_group);
 +
- 	if (dev->irq >= 0){
- 		/* Interrupt mode */
--		ret = wait_event_interruptible_timeout(dev->wq, 
-+		ret = wait_event_interruptible_timeout(dev->wq,
- 			!(in_8(&iic->sts) & STS_PT), dev->adap.timeout * HZ);
- 
- 		if (unlikely(ret < 0))
-@@ -424,37 +424,37 @@ static int iic_wait_for_tc(struct ibm_iic_private* dev){
- 	else {
- 		/* Polling mode */
- 		unsigned long x = jiffies + dev->adap.timeout * HZ;
--		
++	err = i2c_detach_client(client);
++	if (err)
++		return err;
 +
- 		while (in_8(&iic->sts) & STS_PT){
- 			if (unlikely(time_after(jiffies, x))){
- 				DBG("%d: poll timeout\n", dev->idx);
- 				ret = -ETIMEDOUT;
- 				break;
- 			}
--		
++	kfree(i2c_get_clientdata(client));
++	return 0;
++}
 +
- 			if (unlikely(signal_pending(current))){
- 				DBG("%d: poll interrupted\n", dev->idx);
- 				ret = -ERESTARTSYS;
- 				break;
- 			}
- 			schedule();
--		}	
-+		}
- 	}
--	
++static int __init pcf8575_init(void)
++{
++	return i2c_add_driver(&pcf8575_driver);
++}
 +
- 	if (unlikely(ret < 0))
- 		iic_abort_xfer(dev);
- 	else
- 		ret = iic_xfer_result(dev);
--	
++static void __exit pcf8575_exit(void)
++{
++	i2c_del_driver(&pcf8575_driver);
++}
 +
- 	DBG2("%d: iic_wait_for_tc -> %d\n", dev->idx, ret);
--	
++MODULE_AUTHOR("Michael Hennerich <hennerich at blackfin.uclinux.org>, "
++	      "Bart Van Assche <bart.vanassche at gmail.com>");
++MODULE_DESCRIPTION("pcf8575 driver");
++MODULE_LICENSE("GPL");
 +
- 	return ret;
++module_init(pcf8575_init);
++module_exit(pcf8575_exit);
+diff --git a/drivers/i2c/chips/pcf8591.c b/drivers/i2c/chips/pcf8591.c
+index 4dc3637..865f440 100644
+--- a/drivers/i2c/chips/pcf8591.c
++++ b/drivers/i2c/chips/pcf8591.c
+@@ -27,7 +27,7 @@
+ #include <linux/mutex.h>
+ 
+ /* Addresses to scan */
+-static unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, 0x4c,
++static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, 0x4c,
+ 					0x4d, 0x4e, 0x4f, I2C_CLIENT_END };
+ 
+ /* Insmod parameters */
+diff --git a/drivers/i2c/chips/tps65010.c b/drivers/i2c/chips/tps65010.c
+index e320994..4154a91 100644
+--- a/drivers/i2c/chips/tps65010.c
++++ b/drivers/i2c/chips/tps65010.c
+@@ -31,7 +31,7 @@
+ #include <linux/seq_file.h>
+ #include <linux/mutex.h>
+ 
+-#include <asm/arch/tps65010.h>
++#include <linux/i2c/tps65010.h>
+ 
+ /*-------------------------------------------------------------------------*/
+ 
+diff --git a/drivers/i2c/chips/tsl2550.c b/drivers/i2c/chips/tsl2550.c
+index 3de4b19..a10fd27 100644
+--- a/drivers/i2c/chips/tsl2550.c
++++ b/drivers/i2c/chips/tsl2550.c
+@@ -432,11 +432,32 @@ static int __devexit tsl2550_remove(struct i2c_client *client)
+ 	return 0;
  }
  
- /*
-  * Low level master transfer routine
-  */
--static int iic_xfer_bytes(struct ibm_iic_private* dev, struct i2c_msg* pm, 
-+static int iic_xfer_bytes(struct ibm_iic_private* dev, struct i2c_msg* pm,
- 			  int combined_xfer)
- {
- 	volatile struct iic_regs __iomem *iic = dev->vaddr;
-@@ -465,48 +465,48 @@ static int iic_xfer_bytes(struct ibm_iic_private* dev, struct i2c_msg* pm,
- 	u8 cntl = (in_8(&iic->cntl) & CNTL_AMD) | CNTL_PT;
- 	if (pm->flags & I2C_M_RD)
- 		cntl |= CNTL_RW;
--	
++#ifdef CONFIG_PM
 +
- 	loops = (len + 3) / 4;
- 	for (i = 0; i < loops; ++i, len -= 4){
- 		int count = len > 4 ? 4 : len;
- 		u8 cmd = cntl | ((count - 1) << CNTL_TCT_SHIFT);
--		
++static int tsl2550_suspend(struct i2c_client *client, pm_message_t mesg)
++{
++	return tsl2550_set_power_state(client, 0);
++}
 +
- 		if (!(cntl & CNTL_RW))
- 			for (j = 0; j < count; ++j)
- 				out_8((void __iomem *)&iic->mdbuf, *buf++);
--		
++static int tsl2550_resume(struct i2c_client *client)
++{
++	return tsl2550_set_power_state(client, 1);
++}
 +
- 		if (i < loops - 1)
- 			cmd |= CNTL_CHT;
- 		else if (combined_xfer)
- 			cmd |= CNTL_RPST;
--		
++#else
 +
- 		DBG2("%d: xfer_bytes, %d, CNTL = 0x%02x\n", dev->idx, count, cmd);
--		
++#define tsl2550_suspend		NULL
++#define tsl2550_resume		NULL
 +
- 		/* Start transfer */
- 		out_8(&iic->cntl, cmd);
--		
++#endif /* CONFIG_PM */
 +
- 		/* Wait for completion */
- 		ret = iic_wait_for_tc(dev);
+ static struct i2c_driver tsl2550_driver = {
+ 	.driver = {
+ 		.name	= TSL2550_DRV_NAME,
+ 		.owner	= THIS_MODULE,
+ 	},
++	.suspend = tsl2550_suspend,
++	.resume	= tsl2550_resume,
+ 	.probe	= tsl2550_probe,
+ 	.remove	= __devexit_p(tsl2550_remove),
+ };
+diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
+index b5e13e4..96da22e 100644
+--- a/drivers/i2c/i2c-core.c
++++ b/drivers/i2c/i2c-core.c
+@@ -33,14 +33,15 @@
+ #include <linux/platform_device.h>
+ #include <linux/mutex.h>
+ #include <linux/completion.h>
++#include <linux/hardirq.h>
++#include <linux/irqflags.h>
+ #include <asm/uaccess.h>
++#include <asm/semaphore.h>
+ 
+ #include "i2c-core.h"
+ 
+ 
+-static LIST_HEAD(adapters);
+-static LIST_HEAD(drivers);
+-static DEFINE_MUTEX(core_lists);
++static DEFINE_MUTEX(core_lock);
+ static DEFINE_IDR(i2c_adapter_idr);
+ 
+ #define is_newstyle_driver(d) ((d)->probe || (d)->remove)
+@@ -198,6 +199,25 @@ static struct bus_type i2c_bus_type = {
+ 	.resume		= i2c_device_resume,
+ };
  
- 		if (unlikely(ret < 0))
- 			break;
- 		else if (unlikely(ret != count)){
--			DBG("%d: xfer_bytes, requested %d, transfered %d\n", 
-+			DBG("%d: xfer_bytes, requested %d, transfered %d\n",
- 				dev->idx, count, ret);
--			
-+
- 			/* If it's not a last part of xfer, abort it */
- 			if (combined_xfer || (i < loops - 1))
-     				iic_abort_xfer(dev);
--				
 +
- 			ret = -EREMOTEIO;
--			break;				
-+			break;
- 		}
--		
++/**
++ * i2c_verify_client - return parameter as i2c_client, or NULL
++ * @dev: device, probably from some driver model iterator
++ *
++ * When traversing the driver model tree, perhaps using driver model
++ * iterators like @device_for_each_child(), you can't assume very much
++ * about the nodes you find.  Use this function to avoid oopses caused
++ * by wrongly treating some non-I2C device as an i2c_client.
++ */
++struct i2c_client *i2c_verify_client(struct device *dev)
++{
++	return (dev->bus == &i2c_bus_type)
++			? to_i2c_client(dev)
++			: NULL;
++}
++EXPORT_SYMBOL(i2c_verify_client);
 +
- 		if (cntl & CNTL_RW)
- 			for (j = 0; j < count; ++j)
- 				*buf++ = in_8((void __iomem *)&iic->mdbuf);
- 	}
--	
 +
- 	return ret > 0 ? 0 : ret;
- }
+ /**
+  * i2c_new_device - instantiate an i2c device for use with a new style driver
+  * @adap: the adapter managing the device
+@@ -276,6 +296,50 @@ void i2c_unregister_device(struct i2c_client *client)
+ EXPORT_SYMBOL_GPL(i2c_unregister_device);
  
-@@ -517,10 +517,10 @@ static inline void iic_address(struct ibm_iic_private* dev, struct i2c_msg* msg)
- {
- 	volatile struct iic_regs __iomem *iic = dev->vaddr;
- 	u16 addr = msg->addr;
--	
--	DBG2("%d: iic_address, 0x%03x (%d-bit)\n", dev->idx, 
-+
-+	DBG2("%d: iic_address, 0x%03x (%d-bit)\n", dev->idx,
- 		addr, msg->flags & I2C_M_TEN ? 10 : 7);
--	
-+
- 	if (msg->flags & I2C_M_TEN){
- 	    out_8(&iic->cntl, CNTL_AMD);
- 	    out_8(&iic->lmadr, addr);
-@@ -537,15 +537,15 @@ static inline int iic_invalid_address(const struct i2c_msg* p)
- 	return (p->addr > 0x3ff) || (!(p->flags & I2C_M_TEN) && (p->addr > 0x7f));
- }
  
--static inline int iic_address_neq(const struct i2c_msg* p1, 
-+static inline int iic_address_neq(const struct i2c_msg* p1,
- 				  const struct i2c_msg* p2)
- {
--	return (p1->addr != p2->addr) 
-+	return (p1->addr != p2->addr)
- 		|| ((p1->flags & I2C_M_TEN) != (p2->flags & I2C_M_TEN));
--} 
++static int dummy_nop(struct i2c_client *client)
++{
++	return 0;
 +}
- 
- /*
-- * Generic master transfer entrypoint. 
-+ * Generic master transfer entrypoint.
-  * Returns the number of processed messages or error (<0)
-  */
- static int iic_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
-@@ -553,20 +553,20 @@ static int iic_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
-     	struct ibm_iic_private* dev = (struct ibm_iic_private*)(i2c_get_adapdata(adap));
- 	volatile struct iic_regs __iomem *iic = dev->vaddr;
- 	int i, ret = 0;
--	
 +
- 	DBG2("%d: iic_xfer, %d msg(s)\n", dev->idx, num);
--	
-+
- 	if (!num)
- 		return 0;
--	
++static struct i2c_driver dummy_driver = {
++	.driver.name	= "dummy",
++	.probe		= dummy_nop,
++	.remove		= dummy_nop,
++};
 +
- 	/* Check the sanity of the passed messages.
- 	 * Uhh, generic i2c layer is more suitable place for such code...
- 	 */
- 	if (unlikely(iic_invalid_address(&msgs[0]))){
--		DBG("%d: invalid address 0x%03x (%d-bit)\n", dev->idx, 
-+		DBG("%d: invalid address 0x%03x (%d-bit)\n", dev->idx,
- 			msgs[0].addr, msgs[0].flags & I2C_M_TEN ? 10 : 7);
- 		return -EINVAL;
--	}		
-+	}
- 	for (i = 0; i < num; ++i){
- 		if (unlikely(msgs[i].len <= 0)){
- 			if (num == 1 && !msgs[0].len){
-@@ -576,7 +576,7 @@ static int iic_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
- 				 */
- 				return iic_smbus_quick(dev, &msgs[0]);
- 			}
--			DBG("%d: invalid len %d in msg[%d]\n", dev->idx, 
-+			DBG("%d: invalid len %d in msg[%d]\n", dev->idx,
- 				msgs[i].len, i);
- 			return -EINVAL;
- 		}
-@@ -585,34 +585,34 @@ static int iic_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
- 			return -EINVAL;
- 		}
- 	}
--	
++/**
++ * i2c_new_dummy - return a new i2c device bound to a dummy driver
++ * @adapter: the adapter managing the device
++ * @address: seven bit address to be used
++ * @type: optional label used for i2c_client.name
++ * Context: can sleep
++ *
++ * This returns an I2C client bound to the "dummy" driver, intended for use
++ * with devices that consume multiple addresses.  Examples of such chips
++ * include various EEPROMS (like 24c04 and 24c08 models).
++ *
++ * These dummy devices have two main uses.  First, most I2C and SMBus calls
++ * except i2c_transfer() need a client handle; the dummy will be that handle.
++ * And second, this prevents the specified address from being bound to a
++ * different driver.
++ *
++ * This returns the new i2c client, which should be saved for later use with
++ * i2c_unregister_device(); or NULL to indicate an error.
++ */
++struct i2c_client *
++i2c_new_dummy(struct i2c_adapter *adapter, u16 address, const char *type)
++{
++	struct i2c_board_info info = {
++		.driver_name	= "dummy",
++		.addr		= address,
++	};
 +
- 	/* Check bus state */
- 	if (unlikely((in_8(&iic->extsts) & EXTSTS_BCS_MASK) != EXTSTS_BCS_FREE)){
- 		DBG("%d: iic_xfer, bus is not free\n", dev->idx);
--		
++	if (type)
++		strlcpy(info.type, type, sizeof info.type);
++	return i2c_new_device(adapter, &info);
++}
++EXPORT_SYMBOL_GPL(i2c_new_dummy);
 +
- 		/* Usually it means something serious has happend.
- 		 * We *cannot* have unfinished previous transfer
- 		 * so it doesn't make any sense to try to stop it.
--		 * Probably we were not able to recover from the 
-+		 * Probably we were not able to recover from the
- 		 * previous error.
- 		 * The only *reasonable* thing I can think of here
- 		 * is soft reset.  --ebs
- 		 */
- 		iic_dev_reset(dev);
--		
+ /* ------------------------------------------------------------------------- */
+ 
+ /* I2C bus adapters -- one roots each I2C or SMBUS segment */
+@@ -320,18 +384,27 @@ static void i2c_scan_static_board_info(struct i2c_adapter *adapter)
+ 	mutex_unlock(&__i2c_board_lock);
+ }
+ 
++static int i2c_do_add_adapter(struct device_driver *d, void *data)
++{
++	struct i2c_driver *driver = to_i2c_driver(d);
++	struct i2c_adapter *adap = data;
 +
- 		if ((in_8(&iic->extsts) & EXTSTS_BCS_MASK) != EXTSTS_BCS_FREE){
- 			DBG("%d: iic_xfer, bus is still not free\n", dev->idx);
- 			return -EREMOTEIO;
- 		}
--	} 
++	if (driver->attach_adapter) {
++		/* We ignore the return code; if it fails, too bad */
++		driver->attach_adapter(adap);
 +	}
- 	else {
- 		/* Flush master data buffer (just in case) */
- 		out_8(&iic->mdcntl, in_8(&iic->mdcntl) | MDCNTL_FMDB);
- 	}
--	
-+
- 	/* Load slave address */
- 	iic_address(dev, &msgs[0]);
--	
++	return 0;
++}
 +
- 	/* Do real transfer */
-     	for (i = 0; i < num && !ret; ++i)
- 		ret = iic_xfer_bytes(dev, &msgs[i], i < num - 1);
-@@ -648,7 +648,7 @@ static inline u8 iic_clckdiv(unsigned int opb)
+ static int i2c_register_adapter(struct i2c_adapter *adap)
+ {
+-	int res = 0;
+-	struct list_head   *item;
+-	struct i2c_driver  *driver;
++	int res = 0, dummy;
  
- 	/* Convert to MHz */
- 	opb /= 1000000;
--	
-+
- 	if (opb < 20 || opb > 150){
- 		printk(KERN_CRIT "ibm-iic: invalid OPB clock frequency %u MHz\n",
- 			opb);
-@@ -666,7 +666,7 @@ static int __devinit iic_probe(struct ocp_device *ocp){
- 	struct i2c_adapter* adap;
- 	struct ocp_func_iic_data* iic_data = ocp->def->additions;
- 	int ret;
--	
-+
- 	if (!iic_data)
- 		printk(KERN_WARNING"ibm-iic%d: missing additional data!\n",
- 			ocp->def->index);
-@@ -679,7 +679,7 @@ static int __devinit iic_probe(struct ocp_device *ocp){
+ 	mutex_init(&adap->bus_lock);
+ 	mutex_init(&adap->clist_lock);
+ 	INIT_LIST_HEAD(&adap->clients);
  
- 	dev->idx = ocp->def->index;
- 	ocp_set_drvdata(ocp, dev);
--	
-+
- 	if (!request_mem_region(ocp->def->paddr, sizeof(struct iic_regs),
- 				"ibm_iic")) {
- 		ret = -EBUSY;
-@@ -692,7 +692,7 @@ static int __devinit iic_probe(struct ocp_device *ocp){
- 		ret = -ENXIO;
- 		goto fail2;
- 	}
--	
-+
- 	init_waitqueue_head(&dev->wq);
+-	mutex_lock(&core_lists);
+-	list_add_tail(&adap->list, &adapters);
++	mutex_lock(&core_lock);
  
- 	dev->irq = iic_force_poll ? -1 : ocp->def->irq;
-@@ -702,29 +702,29 @@ static int __devinit iic_probe(struct ocp_device *ocp){
- 		 */
- 		iic_interrupt_mode(dev, 0);
- 		if (request_irq(dev->irq, iic_handler, 0, "IBM IIC", dev)){
--			printk(KERN_ERR "ibm-iic%d: request_irq %d failed\n", 
-+			printk(KERN_ERR "ibm-iic%d: request_irq %d failed\n",
- 				dev->idx, dev->irq);
--			/* Fallback to the polling mode */	
-+			/* Fallback to the polling mode */
- 			dev->irq = -1;
- 		}
- 	}
--	
-+
- 	if (dev->irq < 0)
--		printk(KERN_WARNING "ibm-iic%d: using polling mode\n", 
-+		printk(KERN_WARNING "ibm-iic%d: using polling mode\n",
- 			dev->idx);
--		
-+
- 	/* Board specific settings */
- 	dev->fast_mode = iic_force_fast ? 1 : (iic_data ? iic_data->fast_mode : 0);
--	
--	/* clckdiv is the same for *all* IIC interfaces, 
-+
-+	/* clckdiv is the same for *all* IIC interfaces,
- 	 * but I'd rather make a copy than introduce another global. --ebs
+ 	/* Add the adapter to the driver core.
+ 	 * If the parent pointer is not set up,
+@@ -356,19 +429,14 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
+ 		i2c_scan_static_board_info(adap);
+ 
+ 	/* let legacy drivers scan this bus for matching devices */
+-	list_for_each(item,&drivers) {
+-		driver = list_entry(item, struct i2c_driver, list);
+-		if (driver->attach_adapter)
+-			/* We ignore the return code; if it fails, too bad */
+-			driver->attach_adapter(adap);
+-	}
++	dummy = bus_for_each_drv(&i2c_bus_type, NULL, adap,
++				 i2c_do_add_adapter);
+ 
+ out_unlock:
+-	mutex_unlock(&core_lists);
++	mutex_unlock(&core_lock);
+ 	return res;
+ 
+ out_list:
+-	list_del(&adap->list);
+ 	idr_remove(&i2c_adapter_idr, adap->nr);
+ 	goto out_unlock;
+ }
+@@ -394,11 +462,11 @@ retry:
+ 	if (idr_pre_get(&i2c_adapter_idr, GFP_KERNEL) == 0)
+ 		return -ENOMEM;
+ 
+-	mutex_lock(&core_lists);
++	mutex_lock(&core_lock);
+ 	/* "above" here means "above or equal to", sigh */
+ 	res = idr_get_new_above(&i2c_adapter_idr, adapter,
+ 				__i2c_first_dynamic_bus_num, &id);
+-	mutex_unlock(&core_lists);
++	mutex_unlock(&core_lock);
+ 
+ 	if (res < 0) {
+ 		if (res == -EAGAIN)
+@@ -443,7 +511,7 @@ retry:
+ 	if (idr_pre_get(&i2c_adapter_idr, GFP_KERNEL) == 0)
+ 		return -ENOMEM;
+ 
+-	mutex_lock(&core_lists);
++	mutex_lock(&core_lock);
+ 	/* "above" here means "above or equal to", sigh;
+ 	 * we need the "equal to" result to force the result
  	 */
- 	dev->clckdiv = iic_clckdiv(ocp_sys_info.opb_bus_freq);
- 	DBG("%d: clckdiv = %d\n", dev->idx, dev->clckdiv);
--	
+@@ -452,7 +520,7 @@ retry:
+ 		status = -EBUSY;
+ 		idr_remove(&i2c_adapter_idr, id);
+ 	}
+-	mutex_unlock(&core_lists);
++	mutex_unlock(&core_lock);
+ 	if (status == -EAGAIN)
+ 		goto retry;
+ 
+@@ -462,6 +530,21 @@ retry:
+ }
+ EXPORT_SYMBOL_GPL(i2c_add_numbered_adapter);
+ 
++static int i2c_do_del_adapter(struct device_driver *d, void *data)
++{
++	struct i2c_driver *driver = to_i2c_driver(d);
++	struct i2c_adapter *adapter = data;
++	int res;
 +
- 	/* Initialize IIC interface */
- 	iic_dev_init(dev);
--	
++	if (!driver->detach_adapter)
++		return 0;
++	res = driver->detach_adapter(adapter);
++	if (res)
++		dev_err(&adapter->dev, "detach_adapter failed (%d) "
++			"for driver [%s]\n", res, driver->driver.name);
++	return res;
++}
 +
- 	/* Register it with i2c layer */
- 	adap = &dev->adap;
- 	adap->dev.parent = &ocp->dev;
-@@ -736,7 +736,6 @@ static int __devinit iic_probe(struct ocp_device *ocp){
- 	adap->client_register = NULL;
- 	adap->client_unregister = NULL;
- 	adap->timeout = 1;
--	adap->retries = 1;
+ /**
+  * i2c_del_adapter - unregister I2C adapter
+  * @adap: the adapter being unregistered
+@@ -473,35 +556,24 @@ EXPORT_SYMBOL_GPL(i2c_add_numbered_adapter);
+ int i2c_del_adapter(struct i2c_adapter *adap)
+ {
+ 	struct list_head  *item, *_n;
+-	struct i2c_adapter *adap_from_list;
+-	struct i2c_driver *driver;
+ 	struct i2c_client *client;
+ 	int res = 0;
  
- 	/*
- 	 * If "dev->idx" is negative we consider it as zero.
-@@ -750,24 +749,24 @@ static int __devinit iic_probe(struct ocp_device *ocp){
- 			dev->idx);
- 		goto fail;
+-	mutex_lock(&core_lists);
++	mutex_lock(&core_lock);
+ 
+ 	/* First make sure that this adapter was ever added */
+-	list_for_each_entry(adap_from_list, &adapters, list) {
+-		if (adap_from_list == adap)
+-			break;
+-	}
+-	if (adap_from_list != adap) {
++	if (idr_find(&i2c_adapter_idr, adap->nr) != adap) {
+ 		pr_debug("i2c-core: attempting to delete unregistered "
+ 			 "adapter [%s]\n", adap->name);
+ 		res = -EINVAL;
+ 		goto out_unlock;
  	}
--	
-+
- 	printk(KERN_INFO "ibm-iic%d: using %s mode\n", dev->idx,
- 		dev->fast_mode ? "fast (400 kHz)" : "standard (100 kHz)");
  
- 	return 0;
+-	list_for_each(item,&drivers) {
+-		driver = list_entry(item, struct i2c_driver, list);
+-		if (driver->detach_adapter)
+-			if ((res = driver->detach_adapter(adap))) {
+-				dev_err(&adap->dev, "detach_adapter failed "
+-					"for driver [%s]\n",
+-					driver->driver.name);
+-				goto out_unlock;
+-			}
+-	}
++	/* Tell drivers about this removal */
++	res = bus_for_each_drv(&i2c_bus_type, NULL, adap,
++			       i2c_do_del_adapter);
++	if (res)
++		goto out_unlock;
  
--fail:	
-+fail:
- 	if (dev->irq >= 0){
- 		iic_interrupt_mode(dev, 0);
- 		free_irq(dev->irq, dev);
--	}	
-+	}
+ 	/* detach any active clients. This must be done first, because
+ 	 * it can fail; in which case we give up. */
+@@ -529,7 +601,6 @@ int i2c_del_adapter(struct i2c_adapter *adap)
+ 	/* clean up the sysfs representation */
+ 	init_completion(&adap->dev_released);
+ 	device_unregister(&adap->dev);
+-	list_del(&adap->list);
  
- 	iounmap(dev->vaddr);
--fail2:	
-+fail2:
- 	release_mem_region(ocp->def->paddr, sizeof(struct iic_regs));
- fail1:
- 	ocp_set_drvdata(ocp, NULL);
--	kfree(dev);	
-+	kfree(dev);
- 	return ret;
+ 	/* wait for sysfs to drop all references */
+ 	wait_for_completion(&adap->dev_released);
+@@ -540,7 +611,7 @@ int i2c_del_adapter(struct i2c_adapter *adap)
+ 	dev_dbg(&adap->dev, "adapter [%s] unregistered\n", adap->name);
+ 
+  out_unlock:
+-	mutex_unlock(&core_lists);
++	mutex_unlock(&core_lock);
+ 	return res;
  }
+ EXPORT_SYMBOL(i2c_del_adapter);
+@@ -583,21 +654,23 @@ int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
+ 	if (res)
+ 		return res;
  
-@@ -783,13 +782,13 @@ static void __devexit iic_remove(struct ocp_device *ocp)
- 			dev->idx);
- 		/* That's *very* bad, just shutdown IRQ ... */
- 		if (dev->irq >= 0){
--		    iic_interrupt_mode(dev, 0);	
-+		    iic_interrupt_mode(dev, 0);
- 		    free_irq(dev->irq, dev);
- 		    dev->irq = -1;
- 		}
- 	} else {
- 		if (dev->irq >= 0){
--		    iic_interrupt_mode(dev, 0);	
-+		    iic_interrupt_mode(dev, 0);
- 		    free_irq(dev->irq, dev);
+-	mutex_lock(&core_lists);
++	mutex_lock(&core_lock);
+ 
+-	list_add_tail(&driver->list,&drivers);
+ 	pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name);
+ 
+ 	/* legacy drivers scan i2c busses directly */
+ 	if (driver->attach_adapter) {
+ 		struct i2c_adapter *adapter;
+ 
+-		list_for_each_entry(adapter, &adapters, list) {
++		down(&i2c_adapter_class.sem);
++		list_for_each_entry(adapter, &i2c_adapter_class.devices,
++				    dev.node) {
+ 			driver->attach_adapter(adapter);
  		}
- 		iounmap(dev->vaddr);
-@@ -798,7 +797,7 @@ static void __devexit iic_remove(struct ocp_device *ocp)
++		up(&i2c_adapter_class.sem);
  	}
- }
  
--static struct ocp_device_id ibm_iic_ids[] __devinitdata = 
-+static struct ocp_device_id ibm_iic_ids[] __devinitdata =
+-	mutex_unlock(&core_lists);
++	mutex_unlock(&core_lock);
+ 	return 0;
+ }
+ EXPORT_SYMBOL(i2c_register_driver);
+@@ -609,11 +682,11 @@ EXPORT_SYMBOL(i2c_register_driver);
+  */
+ void i2c_del_driver(struct i2c_driver *driver)
  {
- 	{ .vendor = OCP_VENDOR_IBM, .function = OCP_FUNC_IIC },
- 	{ .vendor = OCP_VENDOR_INVALID }
-diff --git a/drivers/i2c/busses/i2c-ibm_iic.h b/drivers/i2c/busses/i2c-ibm_iic.h
-index 59d7b43..fdaa482 100644
---- a/drivers/i2c/busses/i2c-ibm_iic.h
-+++ b/drivers/i2c/busses/i2c-ibm_iic.h
-@@ -2,11 +2,11 @@
-  * drivers/i2c/busses/i2c-ibm_iic.h
-  *
-  * Support for the IIC peripheral on IBM PPC 4xx
-- * 
-+ *
-  * Copyright (c) 2003 Zultys Technologies.
-  * Eugene Surovegin <eugene.surovegin at zultys.com> or <ebs at ebshome.net>
-  *
-- * Based on original work by 
-+ * Based on original work by
-  * 	Ian DaSilva  <idasilva at mvista.com>
-  *      Armin Kuster <akuster at mvista.com>
-  * 	Matt Porter  <mporter at mvista.com>
-@@ -22,7 +22,7 @@
- #ifndef __I2C_IBM_IIC_H_
- #define __I2C_IBM_IIC_H_
- 
--#include <linux/i2c.h> 
-+#include <linux/i2c.h>
+-	struct list_head   *item1, *item2, *_n;
++	struct list_head   *item2, *_n;
+ 	struct i2c_client  *client;
+ 	struct i2c_adapter *adap;
  
- struct iic_regs {
- 	u16 mdbuf;
-@@ -58,7 +58,7 @@ struct ibm_iic_private {
- #define CNTL_TCT_MASK	0x30
- #define CNTL_TCT_SHIFT	4
- #define CNTL_RPST	0x08
--#define CNTL_CHT	0x04 
-+#define CNTL_CHT	0x04
- #define CNTL_RW		0x02
- #define CNTL_PT		0x01
+-	mutex_lock(&core_lists);
++	mutex_lock(&core_lock);
  
-diff --git a/drivers/i2c/busses/i2c-iop3xx.c b/drivers/i2c/busses/i2c-iop3xx.c
-index c70146e..ab41400 100644
---- a/drivers/i2c/busses/i2c-iop3xx.c
-+++ b/drivers/i2c/busses/i2c-iop3xx.c
-@@ -490,7 +490,6 @@ iop3xx_i2c_probe(struct platform_device *pdev)
- 	 * Default values...should these come in from board code?
+ 	/* new-style driver? */
+ 	if (is_newstyle_driver(driver))
+@@ -623,8 +696,8 @@ void i2c_del_driver(struct i2c_driver *driver)
+ 	 * attached. If so, detach them to be able to kill the driver
+ 	 * afterwards.
  	 */
- 	new_adapter->timeout = 100;	
--	new_adapter->retries = 3;
- 	new_adapter->algo = &iop3xx_i2c_algo;
+-	list_for_each(item1,&adapters) {
+-		adap = list_entry(item1, struct i2c_adapter, list);
++	down(&i2c_adapter_class.sem);
++	list_for_each_entry(adap, &i2c_adapter_class.devices, dev.node) {
+ 		if (driver->detach_adapter) {
+ 			if (driver->detach_adapter(adap)) {
+ 				dev_err(&adap->dev, "detach_adapter failed "
+@@ -648,40 +721,31 @@ void i2c_del_driver(struct i2c_driver *driver)
+ 			}
+ 		}
+ 	}
++	up(&i2c_adapter_class.sem);
  
- 	init_waitqueue_head(&adapter_data->waitq);
-diff --git a/drivers/i2c/busses/i2c-ixp4xx.c b/drivers/i2c/busses/i2c-ixp4xx.c
-deleted file mode 100644
-index 069ed7f..0000000
---- a/drivers/i2c/busses/i2c-ixp4xx.c
-+++ /dev/null
-@@ -1,178 +0,0 @@
--/*
-- * drivers/i2c/busses/i2c-ixp4xx.c
-- *
-- * Intel's IXP4xx XScale NPU chipsets (IXP420, 421, 422, 425) do not have
-- * an on board I2C controller but provide 16 GPIO pins that are often
-- * used to create an I2C bus. This driver provides an i2c_adapter 
-- * interface that plugs in under algo_bit and drives the GPIO pins
-- * as instructed by the alogorithm driver.
-- *
-- * Author: Deepak Saxena <dsaxena at plexity.net>
-- *
-- * Copyright (c) 2003-2004 MontaVista Software Inc.
-- *
-- * This file is licensed under the terms of the GNU General Public 
-- * License version 2. This program is licensed "as is" without any 
-- * warranty of any kind, whether express or implied.
-- *
-- * NOTE: Since different platforms will use different GPIO pins for
-- *       I2C, this driver uses an IXP4xx-specific platform_data
-- *       pointer to pass the GPIO numbers to the driver. This 
-- *       allows us to support all the different IXP4xx platforms
-- *       w/o having to put #ifdefs in this driver.
-- *
-- *       See arch/arm/mach-ixp4xx/ixdp425.c for an example of building a 
-- *       device list and filling in the ixp4xx_i2c_pins data structure 
-- *       that is passed as the platform_data to this driver.
-- */
--
--#include <linux/kernel.h>
--#include <linux/init.h>
--#include <linux/platform_device.h>
--#include <linux/module.h>
--#include <linux/i2c.h>
--#include <linux/i2c-algo-bit.h>
--
--#include <asm/hardware.h>	/* Pick up IXP4xx-specific bits */
--
--static inline int ixp4xx_scl_pin(void *data)
--{
--	return ((struct ixp4xx_i2c_pins*)data)->scl_pin;
--}
--
--static inline int ixp4xx_sda_pin(void *data)
--{
--	return ((struct ixp4xx_i2c_pins*)data)->sda_pin;
--}
--
--static void ixp4xx_bit_setscl(void *data, int val)
--{
--	gpio_line_set(ixp4xx_scl_pin(data), 0);
--	gpio_line_config(ixp4xx_scl_pin(data),
--		val ? IXP4XX_GPIO_IN : IXP4XX_GPIO_OUT );
--}
--
--static void ixp4xx_bit_setsda(void *data, int val)
--{
--	gpio_line_set(ixp4xx_sda_pin(data), 0);
--	gpio_line_config(ixp4xx_sda_pin(data),
--		val ? IXP4XX_GPIO_IN : IXP4XX_GPIO_OUT );
--}
--
--static int ixp4xx_bit_getscl(void *data)
--{
--	int scl;
--
--	gpio_line_config(ixp4xx_scl_pin(data), IXP4XX_GPIO_IN );
--	gpio_line_get(ixp4xx_scl_pin(data), &scl);
--
--	return scl;
--}	
--
--static int ixp4xx_bit_getsda(void *data)
--{
--	int sda;
--
--	gpio_line_config(ixp4xx_sda_pin(data), IXP4XX_GPIO_IN );
--	gpio_line_get(ixp4xx_sda_pin(data), &sda);
--
--	return sda;
--}	
--
--struct ixp4xx_i2c_data {
--	struct ixp4xx_i2c_pins *gpio_pins;
--	struct i2c_adapter adapter;
--	struct i2c_algo_bit_data algo_data;
--};
--
--static int ixp4xx_i2c_remove(struct platform_device *plat_dev)
--{
--	struct ixp4xx_i2c_data *drv_data = platform_get_drvdata(plat_dev);
--
--	platform_set_drvdata(plat_dev, NULL);
--
--	i2c_del_adapter(&drv_data->adapter);
--
--	kfree(drv_data);
--
--	return 0;
--}
--
--static int ixp4xx_i2c_probe(struct platform_device *plat_dev)
--{
--	int err;
--	struct ixp4xx_i2c_pins *gpio = plat_dev->dev.platform_data;
--	struct ixp4xx_i2c_data *drv_data = 
--		kzalloc(sizeof(struct ixp4xx_i2c_data), GFP_KERNEL);
--
--	if(!drv_data)
--		return -ENOMEM;
--
--	drv_data->gpio_pins = gpio;
+  unregister:
+ 	driver_unregister(&driver->driver);
+-	list_del(&driver->list);
+ 	pr_debug("i2c-core: driver [%s] unregistered\n", driver->driver.name);
+ 
+-	mutex_unlock(&core_lists);
++	mutex_unlock(&core_lock);
+ }
+ EXPORT_SYMBOL(i2c_del_driver);
+ 
+ /* ------------------------------------------------------------------------- */
+ 
+-static int __i2c_check_addr(struct i2c_adapter *adapter, unsigned int addr)
++static int __i2c_check_addr(struct device *dev, void *addrp)
+ {
+-	struct list_head   *item;
+-	struct i2c_client  *client;
++	struct i2c_client	*client = i2c_verify_client(dev);
++	int			addr = *(int *)addrp;
+ 
+-	list_for_each(item,&adapter->clients) {
+-		client = list_entry(item, struct i2c_client, list);
+-		if (client->addr == addr)
+-			return -EBUSY;
+-	}
++	if (client && client->addr == addr)
++		return -EBUSY;
+ 	return 0;
+ }
+ 
+ static int i2c_check_addr(struct i2c_adapter *adapter, int addr)
+ {
+-	int rval;
 -
--	/*
--	 * We could make a lot of these structures static, but
--	 * certain platforms may have multiple GPIO-based I2C
--	 * buses for various device domains, so we need per-device
--	 * algo_data->data. 
--	 */
--	drv_data->algo_data.data = gpio;
--	drv_data->algo_data.setsda = ixp4xx_bit_setsda;
--	drv_data->algo_data.setscl = ixp4xx_bit_setscl;
--	drv_data->algo_data.getsda = ixp4xx_bit_getsda;
--	drv_data->algo_data.getscl = ixp4xx_bit_getscl;
--	drv_data->algo_data.udelay = 10;
--	drv_data->algo_data.timeout = 100;
+-	mutex_lock(&adapter->clist_lock);
+-	rval = __i2c_check_addr(adapter, addr);
+-	mutex_unlock(&adapter->clist_lock);
 -
--	drv_data->adapter.id = I2C_HW_B_IXP4XX;
--	drv_data->adapter.class = I2C_CLASS_HWMON;
--	strlcpy(drv_data->adapter.name, plat_dev->dev.driver->name,
--		sizeof(drv_data->adapter.name));
--	drv_data->adapter.algo_data = &drv_data->algo_data;
+-	return rval;
++	return device_for_each_child(&adapter->dev, &addr, __i2c_check_addr);
+ }
+ 
+ int i2c_attach_client(struct i2c_client *client)
+@@ -689,15 +753,6 @@ int i2c_attach_client(struct i2c_client *client)
+ 	struct i2c_adapter *adapter = client->adapter;
+ 	int res = 0;
+ 
+-	mutex_lock(&adapter->clist_lock);
+-	if (__i2c_check_addr(client->adapter, client->addr)) {
+-		res = -EBUSY;
+-		goto out_unlock;
+-	}
+-	list_add_tail(&client->list,&adapter->clients);
 -
--	drv_data->adapter.dev.parent = &plat_dev->dev;
+-	client->usage_count = 0;
 -
--	gpio_line_config(gpio->scl_pin, IXP4XX_GPIO_IN);
--	gpio_line_config(gpio->sda_pin, IXP4XX_GPIO_IN);
--	gpio_line_set(gpio->scl_pin, 0);
--	gpio_line_set(gpio->sda_pin, 0);
+ 	client->dev.parent = &client->adapter->dev;
+ 	client->dev.bus = &i2c_bus_type;
+ 
+@@ -712,13 +767,17 @@ int i2c_attach_client(struct i2c_client *client)
+ 
+ 	snprintf(&client->dev.bus_id[0], sizeof(client->dev.bus_id),
+ 		"%d-%04x", i2c_adapter_id(adapter), client->addr);
+-	dev_dbg(&adapter->dev, "client [%s] registered with bus id %s\n",
+-		client->name, client->dev.bus_id);
+ 	res = device_register(&client->dev);
+ 	if (res)
+-		goto out_list;
++		goto out_err;
++
++	mutex_lock(&adapter->clist_lock);
++	list_add_tail(&client->list, &adapter->clients);
+ 	mutex_unlock(&adapter->clist_lock);
+ 
++	dev_dbg(&adapter->dev, "client [%s] registered with bus id %s\n",
++		client->name, client->dev.bus_id);
++
+ 	if (adapter->client_register)  {
+ 		if (adapter->client_register(client)) {
+ 			dev_dbg(&adapter->dev, "client_register "
+@@ -729,12 +788,9 @@ int i2c_attach_client(struct i2c_client *client)
+ 
+ 	return 0;
+ 
+-out_list:
+-	list_del(&client->list);
++out_err:
+ 	dev_err(&adapter->dev, "Failed to attach i2c client %s at 0x%02x "
+ 		"(%d)\n", client->name, client->addr, res);
+-out_unlock:
+-	mutex_unlock(&adapter->clist_lock);
+ 	return res;
+ }
+ EXPORT_SYMBOL(i2c_attach_client);
+@@ -744,12 +800,6 @@ int i2c_detach_client(struct i2c_client *client)
+ 	struct i2c_adapter *adapter = client->adapter;
+ 	int res = 0;
+ 
+-	if (client->usage_count > 0) {
+-		dev_warn(&client->dev, "Client [%s] still busy, "
+-			 "can't detach\n", client->name);
+-		return -EBUSY;
+-	}
 -
--	err = i2c_bit_add_bus(&drv_data->adapter);
--	if (err) {
--		printk(KERN_ERR "ERROR: Could not install %s\n", plat_dev->dev.bus_id);
+ 	if (adapter->client_unregister)  {
+ 		res = adapter->client_unregister(client);
+ 		if (res) {
+@@ -762,9 +812,10 @@ int i2c_detach_client(struct i2c_client *client)
+ 
+ 	mutex_lock(&adapter->clist_lock);
+ 	list_del(&client->list);
++	mutex_unlock(&adapter->clist_lock);
++
+ 	init_completion(&client->released);
+ 	device_unregister(&client->dev);
+-	mutex_unlock(&adapter->clist_lock);
+ 	wait_for_completion(&client->released);
+ 
+  out:
+@@ -772,72 +823,58 @@ int i2c_detach_client(struct i2c_client *client)
+ }
+ EXPORT_SYMBOL(i2c_detach_client);
+ 
+-static int i2c_inc_use_client(struct i2c_client *client)
++/**
++ * i2c_use_client - increments the reference count of the i2c client structure
++ * @client: the client being referenced
++ *
++ * Each live reference to a client should be refcounted. The driver model does
++ * that automatically as part of driver binding, so that most drivers don't
++ * need to do this explicitly: they hold a reference until they're unbound
++ * from the device.
++ *
++ * A pointer to the client with the incremented reference counter is returned.
++ */
++struct i2c_client *i2c_use_client(struct i2c_client *client)
+ {
 -
--		kfree(drv_data);
--		return err;
+-	if (!try_module_get(client->driver->driver.owner))
+-		return -ENODEV;
+-	if (!try_module_get(client->adapter->owner)) {
+-		module_put(client->driver->driver.owner);
+-		return -ENODEV;
 -	}
 -
--	platform_set_drvdata(plat_dev, drv_data);
--
 -	return 0;
--}
--
--static struct platform_driver ixp4xx_i2c_driver = {
--	.probe		= ixp4xx_i2c_probe,
--	.remove		= ixp4xx_i2c_remove,
--	.driver		= {
--		.name	= "IXP4XX-I2C",
--		.owner	= THIS_MODULE,
--	},
--};
--
--static int __init ixp4xx_i2c_init(void)
--{
--	return platform_driver_register(&ixp4xx_i2c_driver);
--}
--
--static void __exit ixp4xx_i2c_exit(void)
++	get_device(&client->dev);
++	return client;
+ }
++EXPORT_SYMBOL(i2c_use_client);
+ 
+-static void i2c_dec_use_client(struct i2c_client *client)
++/**
++ * i2c_release_client - release a use of the i2c client structure
++ * @client: the client being no longer referenced
++ *
++ * Must be called when a user of a client is finished with it.
++ */
++void i2c_release_client(struct i2c_client *client)
+ {
+-	module_put(client->driver->driver.owner);
+-	module_put(client->adapter->owner);
++	put_device(&client->dev);
+ }
++EXPORT_SYMBOL(i2c_release_client);
+ 
+-int i2c_use_client(struct i2c_client *client)
 -{
--	platform_driver_unregister(&ixp4xx_i2c_driver);
--}
+-	int ret;
 -
--module_init(ixp4xx_i2c_init);
--module_exit(ixp4xx_i2c_exit);
+-	ret = i2c_inc_use_client(client);
+-	if (ret)
+-		return ret;
 -
--MODULE_DESCRIPTION("GPIO-based I2C adapter for IXP4xx systems");
--MODULE_LICENSE("GPL");
--MODULE_AUTHOR("Deepak Saxena <dsaxena at plexity.net>");
+-	client->usage_count++;
 -
-diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c
-index d8de4ac..bbe787b 100644
---- a/drivers/i2c/busses/i2c-mpc.c
-+++ b/drivers/i2c/busses/i2c-mpc.c
-@@ -180,7 +180,7 @@ static void mpc_i2c_stop(struct mpc_i2c *i2c)
- static int mpc_write(struct mpc_i2c *i2c, int target,
- 		     const u8 * data, int length, int restart)
+-	return 0;
+-}
+-EXPORT_SYMBOL(i2c_use_client);
++struct i2c_cmd_arg {
++	unsigned	cmd;
++	void		*arg;
++};
+ 
+-int i2c_release_client(struct i2c_client *client)
++static int i2c_cmd(struct device *dev, void *_arg)
  {
--	int i;
-+	int i, result;
- 	unsigned timeout = i2c->adap.timeout;
- 	u32 flags = restart ? CCR_RSTA : 0;
+-	if (!client->usage_count) {
+-		pr_debug("i2c-core: %s used one too many times\n",
+-			 __FUNCTION__);
+-		return -EPERM;
+-	}
+-
+-	client->usage_count--;
+-	i2c_dec_use_client(client);
++	struct i2c_client	*client = i2c_verify_client(dev);
++	struct i2c_cmd_arg	*arg = _arg;
  
-@@ -192,15 +192,17 @@ static int mpc_write(struct mpc_i2c *i2c, int target,
- 	/* Write target byte */
- 	writeb((target << 1), i2c->base + MPC_I2C_DR);
++	if (client && client->driver && client->driver->command)
++		client->driver->command(client, arg->cmd, arg->arg);
+ 	return 0;
+ }
+-EXPORT_SYMBOL(i2c_release_client);
  
--	if (i2c_wait(i2c, timeout, 1) < 0)
--		return -1;
-+	result = i2c_wait(i2c, timeout, 1);
-+	if (result < 0)
-+		return result;
+ void i2c_clients_command(struct i2c_adapter *adap, unsigned int cmd, void *arg)
+ {
+-	struct list_head  *item;
+-	struct i2c_client *client;
++	struct i2c_cmd_arg	cmd_arg;
  
- 	for (i = 0; i < length; i++) {
- 		/* Write data byte */
- 		writeb(data[i], i2c->base + MPC_I2C_DR);
+-	mutex_lock(&adap->clist_lock);
+-	list_for_each(item,&adap->clients) {
+-		client = list_entry(item, struct i2c_client, list);
+-		if (!try_module_get(client->driver->driver.owner))
+-			continue;
+-		if (NULL != client->driver->command) {
+-			mutex_unlock(&adap->clist_lock);
+-			client->driver->command(client,cmd,arg);
+-			mutex_lock(&adap->clist_lock);
+-		}
+-		module_put(client->driver->driver.owner);
+-       }
+-       mutex_unlock(&adap->clist_lock);
++	cmd_arg.cmd = cmd;
++	cmd_arg.arg = arg;
++	device_for_each_child(&adap->dev, &cmd_arg, i2c_cmd);
+ }
+ EXPORT_SYMBOL(i2c_clients_command);
  
--		if (i2c_wait(i2c, timeout, 1) < 0)
--			return -1;
-+		result = i2c_wait(i2c, timeout, 1);
-+		if (result < 0)
-+			return result;
- 	}
+@@ -848,11 +885,24 @@ static int __init i2c_init(void)
+ 	retval = bus_register(&i2c_bus_type);
+ 	if (retval)
+ 		return retval;
+-	return class_register(&i2c_adapter_class);
++	retval = class_register(&i2c_adapter_class);
++	if (retval)
++		goto bus_err;
++	retval = i2c_add_driver(&dummy_driver);
++	if (retval)
++		goto class_err;
++	return 0;
++
++class_err:
++	class_unregister(&i2c_adapter_class);
++bus_err:
++	bus_unregister(&i2c_bus_type);
++	return retval;
+ }
  
- 	return 0;
-@@ -210,7 +212,7 @@ static int mpc_read(struct mpc_i2c *i2c, int target,
- 		    u8 * data, int length, int restart)
+ static void __exit i2c_exit(void)
  {
- 	unsigned timeout = i2c->adap.timeout;
--	int i;
-+	int i, result;
- 	u32 flags = restart ? CCR_RSTA : 0;
++	i2c_del_driver(&dummy_driver);
+ 	class_unregister(&i2c_adapter_class);
+ 	bus_unregister(&i2c_bus_type);
+ }
+@@ -879,7 +929,15 @@ int i2c_transfer(struct i2c_adapter * adap, struct i2c_msg *msgs, int num)
+ 		}
+ #endif
  
- 	/* Start with MEN */
-@@ -221,8 +223,9 @@ static int mpc_read(struct mpc_i2c *i2c, int target,
- 	/* Write target address byte - this time with the read flag set */
- 	writeb((target << 1) | 1, i2c->base + MPC_I2C_DR);
+-		mutex_lock_nested(&adap->bus_lock, adap->level);
++		if (in_atomic() || irqs_disabled()) {
++			ret = mutex_trylock(&adap->bus_lock);
++			if (!ret)
++				/* I2C activity is ongoing. */
++				return -EAGAIN;
++		} else {
++			mutex_lock_nested(&adap->bus_lock, adap->level);
++		}
++
+ 		ret = adap->algo->master_xfer(adap,msgs,num);
+ 		mutex_unlock(&adap->bus_lock);
  
--	if (i2c_wait(i2c, timeout, 1) < 0)
--		return -1;
-+	result = i2c_wait(i2c, timeout, 1);
-+	if (result < 0)
-+		return result;
+@@ -978,7 +1036,7 @@ static int i2c_probe_address(struct i2c_adapter *adapter, int addr, int kind,
+ }
  
- 	if (length) {
- 		if (length == 1)
-@@ -234,8 +237,9 @@ static int mpc_read(struct mpc_i2c *i2c, int target,
+ int i2c_probe(struct i2c_adapter *adapter,
+-	      struct i2c_client_address_data *address_data,
++	      const struct i2c_client_address_data *address_data,
+ 	      int (*found_proc) (struct i2c_adapter *, int, int))
+ {
+ 	int i, err;
+@@ -987,7 +1045,7 @@ int i2c_probe(struct i2c_adapter *adapter,
+ 	/* Force entries are done first, and are not affected by ignore
+ 	   entries */
+ 	if (address_data->forces) {
+-		unsigned short **forces = address_data->forces;
++		const unsigned short * const *forces = address_data->forces;
+ 		int kind;
+ 
+ 		for (kind = 0; forces[kind]; kind++) {
+@@ -1085,7 +1143,6 @@ i2c_new_probed_device(struct i2c_adapter *adap,
+ 		return NULL;
  	}
  
- 	for (i = 0; i < length; i++) {
--		if (i2c_wait(i2c, timeout, 0) < 0)
--			return -1;
-+		result = i2c_wait(i2c, timeout, 0);
-+		if (result < 0)
-+			return result;
+-	mutex_lock(&adap->clist_lock);
+ 	for (i = 0; addr_list[i] != I2C_CLIENT_END; i++) {
+ 		/* Check address validity */
+ 		if (addr_list[i] < 0x03 || addr_list[i] > 0x77) {
+@@ -1095,7 +1152,7 @@ i2c_new_probed_device(struct i2c_adapter *adap,
+ 		}
  
- 		/* Generate txack on next to last byte */
- 		if (i == length - 2)
-@@ -309,7 +313,6 @@ static struct i2c_adapter mpc_ops = {
- 	.algo = &mpc_algo,
- 	.class = I2C_CLASS_HWMON,
- 	.timeout = 1,
--	.retries = 1
- };
+ 		/* Check address availability */
+-		if (__i2c_check_addr(adap, addr_list[i])) {
++		if (i2c_check_addr(adap, addr_list[i])) {
+ 			dev_dbg(&adap->dev, "Address 0x%02x already in "
+ 				"use, not probing\n", addr_list[i]);
+ 			continue;
+@@ -1123,7 +1180,6 @@ i2c_new_probed_device(struct i2c_adapter *adap,
+ 				break;
+ 		}
+ 	}
+-	mutex_unlock(&adap->clist_lock);
  
- static int fsl_i2c_probe(struct platform_device *pdev)
-@@ -321,9 +324,9 @@ static int fsl_i2c_probe(struct platform_device *pdev)
+ 	if (addr_list[i] == I2C_CLIENT_END) {
+ 		dev_dbg(&adap->dev, "Probing failed, no device found\n");
+@@ -1139,12 +1195,12 @@ struct i2c_adapter* i2c_get_adapter(int id)
+ {
+ 	struct i2c_adapter *adapter;
  
- 	pdata = (struct fsl_i2c_platform_data *) pdev->dev.platform_data;
+-	mutex_lock(&core_lists);
++	mutex_lock(&core_lock);
+ 	adapter = (struct i2c_adapter *)idr_find(&i2c_adapter_idr, id);
+ 	if (adapter && !try_module_get(adapter->owner))
+ 		adapter = NULL;
  
--	if (!(i2c = kzalloc(sizeof(*i2c), GFP_KERNEL))) {
-+	i2c = kzalloc(sizeof(*i2c), GFP_KERNEL);
-+	if (!i2c)
- 		return -ENOMEM;
+-	mutex_unlock(&core_lists);
++	mutex_unlock(&core_lock);
+ 	return adapter;
+ }
+ EXPORT_SYMBOL(i2c_get_adapter);
+diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c
+index df540d5..393e679 100644
+--- a/drivers/i2c/i2c-dev.c
++++ b/drivers/i2c/i2c-dev.c
+@@ -182,27 +182,22 @@ static ssize_t i2cdev_write (struct file *file, const char __user *buf, size_t c
+ 	return ret;
+ }
+ 
++static int i2cdev_check(struct device *dev, void *addrp)
++{
++	struct i2c_client *client = i2c_verify_client(dev);
++
++	if (!client || client->addr != *(unsigned int *)addrp)
++		return 0;
++
++	return dev->driver ? -EBUSY : 0;
++}
++
+ /* This address checking function differs from the one in i2c-core
+    in that it considers an address with a registered device, but no
+-   bound driver, as NOT busy. */
++   driver bound to it, as NOT busy. */
+ static int i2cdev_check_addr(struct i2c_adapter *adapter, unsigned int addr)
+ {
+-	struct list_head *item;
+-	struct i2c_client *client;
+-	int res = 0;
+-
+-	mutex_lock(&adapter->clist_lock);
+-	list_for_each(item, &adapter->clients) {
+-		client = list_entry(item, struct i2c_client, list);
+-		if (client->addr == addr) {
+-			if (client->driver)
+-				res = -EBUSY;
+-			break;
+-		}
 -	}
+-	mutex_unlock(&adapter->clist_lock);
+-
+-	return res;
++	return device_for_each_child(&adapter->dev, &addr, i2cdev_check);
+ }
  
- 	i2c->irq = platform_get_irq(pdev, 0);
- 	if (i2c->irq < 0) {
-diff --git a/drivers/i2c/busses/i2c-nforce2.c b/drivers/i2c/busses/i2c-nforce2.c
-index 1bf590c..3dac920 100644
---- a/drivers/i2c/busses/i2c-nforce2.c
-+++ b/drivers/i2c/busses/i2c-nforce2.c
-@@ -351,6 +351,7 @@ static int __devinit nforce2_probe(struct pci_dev *dev, const struct pci_device_
- 	pci_set_drvdata(dev, smbuses);
+ static int i2cdev_ioctl(struct inode *inode, struct file *file,
+diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig
+index fb06555..64df55e 100644
+--- a/drivers/ide/Kconfig
++++ b/drivers/ide/Kconfig
+@@ -325,7 +325,7 @@ config BLK_DEV_PLATFORM
+ 	  If unsure, say N.
  
- 	switch(dev->device) {
-+	case PCI_DEVICE_ID_NVIDIA_NFORCE2_SMBUS:
- 	case PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SMBUS:
- 	case PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SMBUS:
- 		smbuses[0].blockops = 1;
-diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c
-index f2552b1..da66397 100644
---- a/drivers/i2c/busses/i2c-omap.c
-+++ b/drivers/i2c/busses/i2c-omap.c
-@@ -362,8 +362,6 @@ omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
+ config BLK_DEV_CMD640
+-	bool "CMD640 chipset bugfix/support"
++	tristate "CMD640 chipset bugfix/support"
+ 	depends on X86
+ 	---help---
+ 	  The CMD-Technologies CMD640 IDE chip is used on many common 486 and
+@@ -359,9 +359,8 @@ config BLK_DEV_CMD640_ENHANCED
+ 	  Otherwise say N.
  
- 	omap_i2c_enable_clocks(dev);
+ config BLK_DEV_IDEPNP
+-	bool "PNP EIDE support"
++	tristate "PNP EIDE support"
+ 	depends on PNP
+-	select IDE_GENERIC
+ 	help
+ 	  If you have a PnP (Plug and Play) compatible EIDE card and
+ 	  would like the kernel to automatically detect and activate
+@@ -374,19 +373,20 @@ comment "PCI IDE chipsets support"
+ config BLK_DEV_IDEPCI
+ 	bool
  
--	/* REVISIT: initialize and use adap->retries. This is an optional
--	 * feature */
- 	if ((r = omap_i2c_wait_for_bb(dev)) < 0)
- 		goto out;
+-config IDEPCI_SHARE_IRQ
+-	bool "Sharing PCI IDE interrupts support"
+-	depends on BLK_DEV_IDEPCI
++config IDEPCI_PCIBUS_ORDER
++	bool "Probe IDE PCI devices in the PCI bus order (DEPRECATED)"
++	depends on BLK_DEV_IDE=y && BLK_DEV_IDEPCI
++	default y
+ 	help
+-	  Some ATA/IDE chipsets have hardware support which allows for
+-	  sharing a single IRQ with other cards. To enable support for
+-	  this in the ATA/IDE driver, say Y here.
++	  Probe IDE PCI devices in the order in which they appear on the
++	  PCI bus (i.e. 00:1f.1 PCI device before 02:01.0 PCI device)
++	  instead of the order in which IDE PCI host drivers are loaded.
  
-diff --git a/drivers/i2c/busses/i2c-pasemi.c b/drivers/i2c/busses/i2c-pasemi.c
-index ca18e0b..1603c81 100644
---- a/drivers/i2c/busses/i2c-pasemi.c
-+++ b/drivers/i2c/busses/i2c-pasemi.c
-@@ -368,6 +368,7 @@ static int __devinit pasemi_smb_probe(struct pci_dev *dev,
- 	smbus->adapter.class = I2C_CLASS_HWMON;
- 	smbus->adapter.algo = &smbus_algorithm;
- 	smbus->adapter.algo_data = smbus;
-+	smbus->adapter.nr = PCI_FUNC(dev->devfn);
+-	  It is safe to say Y to this question, in most cases.
+-	  If unsure, say N.
++	  Please note that this method of assuring stable naming of
++	  IDE devices is unreliable and use other means for achieving
++	  it (i.e. udev).
  
- 	/* set up the sysfs linkage to our parent device */
- 	smbus->adapter.dev.parent = &dev->dev;
-@@ -375,7 +376,7 @@ static int __devinit pasemi_smb_probe(struct pci_dev *dev,
- 	reg_write(smbus, REG_CTL, (CTL_MTR | CTL_MRR |
- 		  (CLK_100K_DIV & CTL_CLK_M)));
+-config IDEPCI_PCIBUS_ORDER
+-	def_bool BLK_DEV_IDE=y && BLK_DEV_IDEPCI
++	  If in doubt, say N.
  
--	error = i2c_add_adapter(&smbus->adapter);
-+	error = i2c_add_numbered_adapter(&smbus->adapter);
- 	if (error)
- 		goto out_release_region;
+ # TODO: split it on per host driver config options (or module parameters)
+ config BLK_DEV_OFFBOARD
+@@ -707,7 +707,6 @@ config BLK_DEV_SVWKS
+ config BLK_DEV_SGIIOC4
+ 	tristate "Silicon Graphics IOC4 chipset ATA/ATAPI support"
+ 	depends on (IA64_SGI_SN2 || IA64_GENERIC) && SGI_IOC4
+-	select IDEPCI_SHARE_IRQ
+ 	select BLK_DEV_IDEDMA_PCI
+ 	help
+ 	  This driver adds PIO & MultiMode DMA-2 support for the SGI IOC4
+@@ -801,7 +800,7 @@ config BLK_DEV_CELLEB
+ endif
  
-diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c
-index 167e413..9bbe96c 100644
---- a/drivers/i2c/busses/i2c-piix4.c
-+++ b/drivers/i2c/busses/i2c-piix4.c
-@@ -121,10 +121,6 @@ static int __devinit piix4_setup(struct pci_dev *PIIX4_dev,
- {
- 	unsigned char temp;
+ config BLK_DEV_IDE_PMAC
+-	bool "Builtin PowerMac IDE support"
++	tristate "Builtin PowerMac IDE support"
+ 	depends on PPC_PMAC && IDE=y && BLK_DEV_IDE=y
+ 	help
+ 	  This driver provides support for the built-in IDE controller on
+@@ -855,8 +854,9 @@ config BLK_DEV_IDE_AU1XXX_SEQTS_PER_RQ
+        depends on BLK_DEV_IDE_AU1XXX
  
--	/* match up the function */
--	if (PCI_FUNC(PIIX4_dev->devfn) != id->driver_data)
--		return -ENODEV;
--
- 	dev_info(&PIIX4_dev->dev, "Found %s device\n", pci_name(PIIX4_dev));
+ config IDE_ARM
+-	def_bool ARM && (ARCH_CLPS7500 || ARCH_RPC || ARCH_SHARK)
+-	select IDE_GENERIC
++	tristate "ARM IDE support"
++	depends on ARM && (ARCH_CLPS7500 || ARCH_RPC || ARCH_SHARK)
++	default y
  
- 	/* Don't access SMBus on IBM systems which get corrupted eeproms */
-@@ -389,28 +385,21 @@ static struct i2c_adapter piix4_adapter = {
- };
+ config BLK_DEV_IDE_ICSIDE
+ 	tristate "ICS IDE interface support"
+@@ -888,10 +888,9 @@ config BLK_DEV_IDE_BAST
+ 	  Simtec BAST or the Thorcom VR1000
  
- static struct pci_device_id piix4_ids[] = {
--	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3),
--	  .driver_data = 3 },
--	{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP200_SMBUS),
--	  .driver_data = 0 },
--	{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP300_SMBUS),
--	  .driver_data = 0 },
--	{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP400_SMBUS),
--	  .driver_data = 0 },
--	{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_SBX00_SMBUS),
--	  .driver_data = 0 },
--	{ PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4),
--	  .driver_data = 0 },
--	{ PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5),
--	  .driver_data = 0 },
--	{ PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6),
--	  .driver_data = 0 },
--	{ PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_HT1000SB),
--	  .driver_data = 0 },
--	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_3),
--	  .driver_data = 3 },
--	{ PCI_DEVICE(PCI_VENDOR_ID_EFAR, PCI_DEVICE_ID_EFAR_SLC90E66_3),
--	  .driver_data = 0 },
-+	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3) },
-+	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_3) },
-+	{ PCI_DEVICE(PCI_VENDOR_ID_EFAR, PCI_DEVICE_ID_EFAR_SLC90E66_3) },
-+	{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP200_SMBUS) },
-+	{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP300_SMBUS) },
-+	{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP400_SMBUS) },
-+	{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_SBX00_SMBUS) },
-+	{ PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS,
-+		     PCI_DEVICE_ID_SERVERWORKS_OSB4) },
-+	{ PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS,
-+		     PCI_DEVICE_ID_SERVERWORKS_CSB5) },
-+	{ PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS,
-+		     PCI_DEVICE_ID_SERVERWORKS_CSB6) },
-+	{ PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS,
-+		     PCI_DEVICE_ID_SERVERWORKS_HT1000SB) },
- 	{ 0, }
- };
+ config ETRAX_IDE
+-	bool "ETRAX IDE support"
++	tristate "ETRAX IDE support"
+ 	depends on CRIS && BROKEN
+ 	select BLK_DEV_IDEDMA
+-	select IDE_GENERIC
+ 	help
+ 	  Enables the ETRAX IDE driver.
  
-diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c
-index 6426a61..2598d29 100644
---- a/drivers/i2c/busses/i2c-pxa.c
-+++ b/drivers/i2c/busses/i2c-pxa.c
-@@ -65,6 +65,7 @@ struct pxa_i2c {
- 	unsigned long		iosize;
+@@ -923,17 +922,15 @@ config ETRAX_IDE_G27_RESET
+ endchoice
  
- 	int			irq;
-+	int			use_pio;
- };
+ config IDE_H8300
+-	bool "H8300 IDE support"
++	tristate "H8300 IDE support"
+ 	depends on H8300
+-	select IDE_GENERIC
+ 	default y
+ 	help
+ 	  Enables the H8300 IDE driver.
  
- #define _IBMR(i2c)	((i2c)->reg_base + 0)
-@@ -163,6 +164,7 @@ static void i2c_pxa_show_state(struct pxa_i2c *i2c, int lno, const char *fname)
- #define eedbg(lvl, x...) do { if ((lvl) < 1) { printk(KERN_DEBUG "" x); } } while(0)
+ config BLK_DEV_GAYLE
+-	bool "Amiga Gayle IDE interface support"
++	tristate "Amiga Gayle IDE interface support"
+ 	depends on AMIGA
+-	select IDE_GENERIC
+ 	help
+ 	  This is the IDE driver for the Amiga Gayle IDE interface. It supports
+ 	  both the `A1200 style' and `A4000 style' of the Gayle IDE interface,
+@@ -963,9 +960,8 @@ config BLK_DEV_IDEDOUBLER
+ 	  runtime using the "ide=doubler" kernel boot parameter.
  
- static void i2c_pxa_master_complete(struct pxa_i2c *i2c, int ret);
-+static irqreturn_t i2c_pxa_handler(int this_irq, void *dev_id);
+ config BLK_DEV_BUDDHA
+-	bool "Buddha/Catweasel/X-Surf IDE interface support (EXPERIMENTAL)"
++	tristate "Buddha/Catweasel/X-Surf IDE interface support (EXPERIMENTAL)"
+ 	depends on ZORRO && EXPERIMENTAL
+-	select IDE_GENERIC
+ 	help
+ 	  This is the IDE driver for the IDE interfaces on the Buddha, 
+ 	  Catweasel and X-Surf expansion boards.  It supports up to two interfaces 
+@@ -976,9 +972,8 @@ config BLK_DEV_BUDDHA
+ 	  to one of its IDE interfaces.
  
- static void i2c_pxa_scream_blue_murder(struct pxa_i2c *i2c, const char *why)
- {
-@@ -554,6 +556,71 @@ static inline void i2c_pxa_stop_message(struct pxa_i2c *i2c)
- 	writel(icr, _ICR(i2c));
- }
+ config BLK_DEV_FALCON_IDE
+-	bool "Falcon IDE interface support"
++	tristate "Falcon IDE interface support"
+ 	depends on ATARI
+-	select IDE_GENERIC
+ 	help
+ 	  This is the IDE driver for the builtin IDE interface on the Atari
+ 	  Falcon. Say Y if you have a Falcon and want to use IDE devices (hard
+@@ -986,9 +981,8 @@ config BLK_DEV_FALCON_IDE
+ 	  interface.
  
-+static int i2c_pxa_pio_set_master(struct pxa_i2c *i2c)
-+{
-+	/* make timeout the same as for interrupt based functions */
-+	long timeout = 2 * DEF_TIMEOUT;
-+
-+	/*
-+	 * Wait for the bus to become free.
-+	 */
-+	while (timeout-- && readl(_ISR(i2c)) & (ISR_IBB | ISR_UB)) {
-+		udelay(1000);
-+		show_state(i2c);
-+	}
-+
-+	if (timeout <= 0) {
-+		show_state(i2c);
-+		dev_err(&i2c->adap.dev,
-+			"i2c_pxa: timeout waiting for bus free\n");
-+		return I2C_RETRY;
-+	}
-+
-+	/*
-+	 * Set master mode.
-+	 */
-+	writel(readl(_ICR(i2c)) | ICR_SCLE, _ICR(i2c));
-+
-+	return 0;
-+}
-+
-+static int i2c_pxa_do_pio_xfer(struct pxa_i2c *i2c,
-+			       struct i2c_msg *msg, int num)
-+{
-+	unsigned long timeout = 500000; /* 5 seconds */
-+	int ret = 0;
-+
-+	ret = i2c_pxa_pio_set_master(i2c);
-+	if (ret)
-+		goto out;
-+
-+	i2c->msg = msg;
-+	i2c->msg_num = num;
-+	i2c->msg_idx = 0;
-+	i2c->msg_ptr = 0;
-+	i2c->irqlogidx = 0;
-+
-+	i2c_pxa_start_message(i2c);
-+
-+	while (timeout-- && i2c->msg_num > 0) {
-+		i2c_pxa_handler(0, i2c);
-+		udelay(10);
-+	}
+ config BLK_DEV_MAC_IDE
+-	bool "Macintosh Quadra/Powerbook IDE interface support"
++	tristate "Macintosh Quadra/Powerbook IDE interface support"
+ 	depends on MAC
+-	select IDE_GENERIC
+ 	help
+ 	  This is the IDE driver for the builtin IDE interface on some m68k
+ 	  Macintosh models. It supports both the `Quadra style' (used in
+@@ -1000,18 +994,16 @@ config BLK_DEV_MAC_IDE
+ 	  builtin IDE interface.
+ 
+ config BLK_DEV_Q40IDE
+-	bool "Q40/Q60 IDE interface support"
++	tristate "Q40/Q60 IDE interface support"
+ 	depends on Q40
+-	select IDE_GENERIC
+ 	help
+ 	  Enable the on-board IDE controller in the Q40/Q60.  This should
+ 	  normally be on; disable it only if you are running a custom hard
+ 	  drive subsystem through an expansion card.
+ 
+ config BLK_DEV_MPC8xx_IDE
+-	bool "MPC8xx IDE support"
++	tristate "MPC8xx IDE support"
+ 	depends on 8xx && (LWMON || IVMS8 || IVML24 || TQM8xxL) && IDE=y && BLK_DEV_IDE=y && !PPC_MERGE
+-	select IDE_GENERIC
+ 	help
+ 	  This option provides support for IDE on Motorola MPC8xx Systems.
+ 	  Please see 'Type of MPC8xx IDE interface' for details.
+diff --git a/drivers/ide/Makefile b/drivers/ide/Makefile
+index b181fc6..0d2da89 100644
+--- a/drivers/ide/Makefile
++++ b/drivers/ide/Makefile
+@@ -7,41 +7,37 @@
+ # Note : at this point, these files are compiled on all systems.
+ # In the future, some of these should be built conditionally.
+ #
+-# First come modules that register themselves with the core
++# link order is important here
+ 
+ EXTRA_CFLAGS				+= -Idrivers/ide
+ 
+-obj-$(CONFIG_BLK_DEV_IDE)		+= pci/
+-
+ ide-core-y += ide.o ide-io.o ide-iops.o ide-lib.o ide-probe.o ide-taskfile.o
+ 
+-ide-core-$(CONFIG_BLK_DEV_CMD640)	+= pci/cmd640.o
+-
+-# Core IDE code - must come before legacy
++# core IDE code
+ ide-core-$(CONFIG_BLK_DEV_IDEPCI)	+= setup-pci.o
+ ide-core-$(CONFIG_BLK_DEV_IDEDMA)	+= ide-dma.o
+ ide-core-$(CONFIG_IDE_PROC_FS)		+= ide-proc.o
+-ide-core-$(CONFIG_BLK_DEV_IDEPNP)	+= ide-pnp.o
+ ide-core-$(CONFIG_BLK_DEV_IDEACPI)	+= ide-acpi.o
+ 
+-# built-in only drivers from arm/
+-ide-core-$(CONFIG_IDE_ARM)		+= arm/ide_arm.o
++obj-$(CONFIG_BLK_DEV_IDE)		+= ide-core.o
+ 
+-# built-in only drivers from legacy/
+-ide-core-$(CONFIG_BLK_DEV_BUDDHA)	+= legacy/buddha.o
+-ide-core-$(CONFIG_BLK_DEV_FALCON_IDE)	+= legacy/falconide.o
+-ide-core-$(CONFIG_BLK_DEV_GAYLE)	+= legacy/gayle.o
+-ide-core-$(CONFIG_BLK_DEV_MAC_IDE)	+= legacy/macide.o
+-ide-core-$(CONFIG_BLK_DEV_Q40IDE)	+= legacy/q40ide.o
++ifeq ($(CONFIG_IDE_ARM), y)
++	ide-arm-core-y += arm/ide_arm.o
++	obj-y += ide-arm-core.o
++endif
+ 
+-# built-in only drivers from ppc/
+-ide-core-$(CONFIG_BLK_DEV_MPC8xx_IDE)	+= ppc/mpc8xx.o
+-ide-core-$(CONFIG_BLK_DEV_IDE_PMAC)	+= ppc/pmac.o
++obj-$(CONFIG_BLK_DEV_IDE)		+= legacy/ pci/
+ 
+-# built-in only drivers from h8300/
+-ide-core-$(CONFIG_IDE_H8300)		+= h8300/ide-h8300.o
++obj-$(CONFIG_IDEPCI_PCIBUS_ORDER)	+= ide-scan-pci.o
+ 
+-obj-$(CONFIG_BLK_DEV_IDE)		+= ide-core.o
++ifeq ($(CONFIG_BLK_DEV_CMD640), y)
++	cmd640-core-y += pci/cmd640.o
++	obj-y += cmd640-core.o
++endif
 +
-+	i2c_pxa_stop_message(i2c);
++obj-$(CONFIG_BLK_DEV_IDE)		+= cris/ ppc/
++obj-$(CONFIG_BLK_DEV_IDEPNP)		+= ide-pnp.o
++obj-$(CONFIG_IDE_H8300)			+= h8300/
+ obj-$(CONFIG_IDE_GENERIC)		+= ide-generic.o
+ 
+ obj-$(CONFIG_BLK_DEV_IDEDISK)		+= ide-disk.o
+@@ -49,6 +45,20 @@ obj-$(CONFIG_BLK_DEV_IDECD)		+= ide-cd.o
+ obj-$(CONFIG_BLK_DEV_IDETAPE)		+= ide-tape.o
+ obj-$(CONFIG_BLK_DEV_IDEFLOPPY)		+= ide-floppy.o
+ 
+-obj-$(CONFIG_BLK_DEV_IDE)		+= legacy/ arm/ mips/
+-obj-$(CONFIG_BLK_DEV_HD)		+= legacy/
+-obj-$(CONFIG_ETRAX_IDE)		+= cris/
++ifeq ($(CONFIG_BLK_DEV_IDECS), y)
++	ide-cs-core-y += legacy/ide-cs.o
++	obj-y += ide-cs-core.o
++endif
 +
-+	/*
-+	 * We place the return code in i2c->msg_idx.
-+	 */
-+	ret = i2c->msg_idx;
++ifeq ($(CONFIG_BLK_DEV_PLATFORM), y)
++	ide-platform-core-y += legacy/ide_platform.o
++	obj-y += ide-platform-core.o
++endif
 +
-+out:
-+	if (timeout == 0)
-+		i2c_pxa_scream_blue_murder(i2c, "timeout");
++obj-$(CONFIG_BLK_DEV_IDE)		+= arm/ mips/
 +
-+	return ret;
-+}
++# old hd driver must be last
++ifeq ($(CONFIG_BLK_DEV_HD), y)
++	hd-core-y += legacy/hd.o
++	obj-y += hd-core.o
++endif
+diff --git a/drivers/ide/arm/Makefile b/drivers/ide/arm/Makefile
+index 6a78f07..5f63ad2 100644
+--- a/drivers/ide/arm/Makefile
++++ b/drivers/ide/arm/Makefile
+@@ -3,4 +3,8 @@ obj-$(CONFIG_BLK_DEV_IDE_ICSIDE)	+= icside.o
+ obj-$(CONFIG_BLK_DEV_IDE_RAPIDE)	+= rapide.o
+ obj-$(CONFIG_BLK_DEV_IDE_BAST)		+= bast-ide.o
+ 
++ifeq ($(CONFIG_IDE_ARM), m)
++	obj-m += ide_arm.o
++endif
 +
- /*
-  * We are protected by the adapter bus mutex.
-  */
-@@ -610,6 +677,35 @@ static int i2c_pxa_do_xfer(struct pxa_i2c *i2c, struct i2c_msg *msg, int num)
- 	return ret;
+ EXTRA_CFLAGS	:= -Idrivers/ide
+diff --git a/drivers/ide/arm/bast-ide.c b/drivers/ide/arm/bast-ide.c
+index 48db616..45bf9c8 100644
+--- a/drivers/ide/arm/bast-ide.c
++++ b/drivers/ide/arm/bast-ide.c
+@@ -45,7 +45,7 @@ bastide_register(unsigned int base, unsigned int aux, int irq,
+ 	hw.io_ports[IDE_CONTROL_OFFSET] = aux + (6 * 0x20);
+ 	hw.irq = irq;
+ 
+-	ide_register_hw(&hw, NULL, 0, hwif);
++	ide_register_hw(&hw, NULL, hwif);
+ 
+ 	return 0;
  }
+diff --git a/drivers/ide/arm/icside.c b/drivers/ide/arm/icside.c
+index 93f71fc..8a5c720 100644
+--- a/drivers/ide/arm/icside.c
++++ b/drivers/ide/arm/icside.c
+@@ -272,8 +272,6 @@ static void icside_set_dma_mode(ide_drive_t *drive, const u8 xfer_mode)
+ 	case XFER_SW_DMA_0:
+ 		cycle_time = 480;
+ 		break;
+-	default:
+-		return;
+ 	}
  
-+static int i2c_pxa_pio_xfer(struct i2c_adapter *adap,
-+			    struct i2c_msg msgs[], int num)
-+{
-+	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_pio_xfer(i2c, msgs, num);
-+		if (ret != I2C_RETRY)
-+			goto out;
-+
-+		if (i2c_debug)
-+			dev_dbg(&adap->dev, "Retrying transmission\n");
-+		udelay(100);
-+	}
-+	i2c_pxa_scream_blue_murder(i2c, "exhausted retries");
-+	ret = -EREMOTEIO;
-+ out:
-+	i2c_pxa_set_slave(i2c, ret);
-+	return ret;
-+}
-+
- /*
-  * i2c_pxa_master_complete - complete the message and wake up.
-  */
-@@ -621,7 +717,8 @@ static void i2c_pxa_master_complete(struct pxa_i2c *i2c, int ret)
- 	i2c->msg_num = 0;
- 	if (ret)
- 		i2c->msg_idx = ret;
--	wake_up(&i2c->wait);
-+	if (!i2c->use_pio)
-+		wake_up(&i2c->wait);
+ 	/*
+@@ -289,26 +287,10 @@ static void icside_set_dma_mode(ide_drive_t *drive, const u8 xfer_mode)
+ 		ide_xfer_verbose(xfer_mode), 2000 / drive->drive_data);
  }
  
- static void i2c_pxa_irq_txempty(struct pxa_i2c *i2c, u32 isr)
-@@ -840,6 +937,37 @@ static const struct i2c_algorithm i2c_pxa_algorithm = {
- 	.functionality	= i2c_pxa_functionality,
- };
+-static void icside_dma_host_off(ide_drive_t *drive)
++static void icside_dma_host_set(ide_drive_t *drive, int on)
+ {
+ }
  
-+static const struct i2c_algorithm i2c_pxa_pio_algorithm = {
-+	.master_xfer	= i2c_pxa_pio_xfer,
-+	.functionality	= i2c_pxa_functionality,
-+};
+-static void icside_dma_off_quietly(ide_drive_t *drive)
+-{
+-	drive->using_dma = 0;
+-}
+-
+-static void icside_dma_host_on(ide_drive_t *drive)
+-{
+-}
+-
+-static int icside_dma_on(ide_drive_t *drive)
+-{
+-	drive->using_dma = 1;
+-
+-	return 0;
+-}
+-
+ static int icside_dma_end(ide_drive_t *drive)
+ {
+ 	ide_hwif_t *hwif = HWIF(drive);
+@@ -424,10 +406,7 @@ static void icside_dma_init(ide_hwif_t *hwif)
+ 	hwif->dmatable_dma	= 0;
+ 	hwif->set_dma_mode	= icside_set_dma_mode;
+ 
+-	hwif->dma_host_off	= icside_dma_host_off;
+-	hwif->dma_off_quietly	= icside_dma_off_quietly;
+-	hwif->dma_host_on	= icside_dma_host_on;
+-	hwif->ide_dma_on	= icside_dma_on;
++	hwif->dma_host_set	= icside_dma_host_set;
+ 	hwif->dma_setup		= icside_dma_setup;
+ 	hwif->dma_exec_cmd	= icside_dma_exec_cmd;
+ 	hwif->dma_start		= icside_dma_start;
+diff --git a/drivers/ide/arm/ide_arm.c b/drivers/ide/arm/ide_arm.c
+index 8957cba..60f2497 100644
+--- a/drivers/ide/arm/ide_arm.c
++++ b/drivers/ide/arm/ide_arm.c
+@@ -24,12 +24,25 @@
+ # define IDE_ARM_IRQ	IRQ_HARDDISK
+ #endif
+ 
+-void __init ide_arm_init(void)
++static int __init ide_arm_init(void)
+ {
++	ide_hwif_t *hwif;
+ 	hw_regs_t hw;
++	u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
+ 
+ 	memset(&hw, 0, sizeof(hw));
+ 	ide_std_init_ports(&hw, IDE_ARM_IO, IDE_ARM_IO + 0x206);
+ 	hw.irq = IDE_ARM_IRQ;
+-	ide_register_hw(&hw, NULL, 1, NULL);
 +
-+static void i2c_pxa_enable(struct platform_device *dev)
-+{
-+	if (cpu_is_pxa27x()) {
-+		switch (dev->id) {
-+		case 0:
-+			pxa_gpio_mode(GPIO117_I2CSCL_MD);
-+			pxa_gpio_mode(GPIO118_I2CSDA_MD);
-+			break;
-+		case 1:
-+			local_irq_disable();
-+			PCFR |= PCFR_PI2CEN;
-+			local_irq_enable();
-+			break;
-+		}
-+	}
-+}
++	hwif = ide_find_port(hw.io_ports[IDE_DATA_OFFSET]);
++	if (hwif) {
++		ide_init_port_hw(hwif, &hw);
++		idx[0] = hwif->index;
 +
-+static void i2c_pxa_disable(struct platform_device *dev)
-+{
-+	if (cpu_is_pxa27x() && dev->id == 1) {
-+		local_irq_disable();
-+		PCFR &= ~PCFR_PI2CEN;
-+		local_irq_enable();
++		ide_device_add(idx);
 +	}
-+}
 +
- #define res_len(r)		((r)->end - (r)->start + 1)
- static int i2c_pxa_probe(struct platform_device *dev)
- {
-@@ -864,7 +992,6 @@ static int i2c_pxa_probe(struct platform_device *dev)
- 	}
- 
- 	i2c->adap.owner   = THIS_MODULE;
--	i2c->adap.algo    = &i2c_pxa_algorithm;
- 	i2c->adap.retries = 5;
++	return 0;
+ }
++
++module_init(ide_arm_init);
+diff --git a/drivers/ide/arm/rapide.c b/drivers/ide/arm/rapide.c
+index 0775a3a..e6b56d1 100644
+--- a/drivers/ide/arm/rapide.c
++++ b/drivers/ide/arm/rapide.c
+@@ -13,26 +13,18 @@
  
- 	spin_lock_init(&i2c->lock);
-@@ -899,34 +1026,28 @@ static int i2c_pxa_probe(struct platform_device *dev)
- #endif
+ #include <asm/ecard.h>
  
- 	clk_enable(i2c->clk);
--#ifdef CONFIG_PXA27x
--	switch (dev->id) {
--	case 0:
--		pxa_gpio_mode(GPIO117_I2CSCL_MD);
--		pxa_gpio_mode(GPIO118_I2CSDA_MD);
--		break;
--	case 1:
--		local_irq_disable();
--		PCFR |= PCFR_PI2CEN;
--		local_irq_enable();
--	}
--#endif
-+	i2c_pxa_enable(dev);
+-static ide_hwif_t *
+-rapide_locate_hwif(void __iomem *base, void __iomem *ctrl, unsigned int sz, int irq)
++static void rapide_setup_ports(hw_regs_t *hw, void __iomem *base,
++			       void __iomem *ctrl, unsigned int sz, int irq)
+ {
+ 	unsigned long port = (unsigned long)base;
+-	ide_hwif_t *hwif = ide_find_port(port);
+ 	int i;
  
--	ret = request_irq(irq, i2c_pxa_handler, IRQF_DISABLED,
--			  i2c->adap.name, i2c);
--	if (ret)
--		goto ereqirq;
-+	if (plat) {
-+		i2c->adap.class = plat->class;
-+		i2c->use_pio = plat->use_pio;
-+	}
+-	if (hwif == NULL)
+-		goto out;
+-
+ 	for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
+-		hwif->io_ports[i] = port;
++		hw->io_ports[i] = port;
+ 		port += sz;
+ 	}
+-	hwif->io_ports[IDE_CONTROL_OFFSET] = (unsigned long)ctrl;
+-	hwif->irq = irq;
+-	hwif->mmio = 1;
+-	default_hwif_mmiops(hwif);
+-out:
+-	return hwif;
++	hw->io_ports[IDE_CONTROL_OFFSET] = (unsigned long)ctrl;
++	hw->irq = irq;
+ }
  
-+	if (i2c->use_pio) {
-+		i2c->adap.algo = &i2c_pxa_pio_algorithm;
-+	} else {
-+		i2c->adap.algo = &i2c_pxa_algorithm;
-+		ret = request_irq(irq, i2c_pxa_handler, IRQF_DISABLED,
-+				  i2c->adap.name, i2c);
-+		if (ret)
-+			goto ereqirq;
-+	}
+ static int __devinit
+@@ -42,6 +34,7 @@ rapide_probe(struct expansion_card *ec, const struct ecard_id *id)
+ 	void __iomem *base;
+ 	int ret;
+ 	u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
++	hw_regs_t hw;
  
- 	i2c_pxa_reset(i2c);
+ 	ret = ecard_request_resources(ec);
+ 	if (ret)
+@@ -53,11 +46,17 @@ rapide_probe(struct expansion_card *ec, const struct ecard_id *id)
+ 		goto release;
+ 	}
  
- 	i2c->adap.algo_data = i2c;
- 	i2c->adap.dev.parent = &dev->dev;
+-	hwif = rapide_locate_hwif(base, base + 0x818, 1 << 6, ec->irq);
++	hwif = ide_find_port((unsigned long)base);
+ 	if (hwif) {
+-		hwif->hwif_data = base;
+-		hwif->gendev.parent = &ec->dev;
+-		hwif->noprobe = 0;
++		memset(&hw, 0, sizeof(hw));
++		rapide_setup_ports(&hw, base, base + 0x818, 1 << 6, ec->irq);
++		hw.chipset = ide_generic;
++		hw.dev = &ec->dev;
++
++		ide_init_port_hw(hwif, &hw);
++
++		hwif->mmio = 1;
++		default_hwif_mmiops(hwif);
  
--	if (plat) {
--		i2c->adap.class = plat->class;
--	}
--
- 	/*
- 	 * If "dev->id" is negative we consider it as zero.
- 	 * The reason to do so is to avoid sysfs names that only make
-@@ -952,17 +1073,11 @@ static int i2c_pxa_probe(struct platform_device *dev)
- 	return 0;
+ 		idx[0] = hwif->index;
  
- eadapt:
--	free_irq(irq, i2c);
-+	if (!i2c->use_pio)
-+		free_irq(irq, i2c);
- ereqirq:
- 	clk_disable(i2c->clk);
--
--#ifdef CONFIG_PXA27x
--	if (dev->id == 1) {
--		local_irq_disable();
--		PCFR &= ~PCFR_PI2CEN;
--		local_irq_enable();
--	}
--#endif
-+	i2c_pxa_disable(dev);
- eremap:
- 	clk_put(i2c->clk);
- eclk:
-@@ -979,18 +1094,12 @@ static int i2c_pxa_remove(struct platform_device *dev)
- 	platform_set_drvdata(dev, NULL);
+diff --git a/drivers/ide/cris/Makefile b/drivers/ide/cris/Makefile
+index 6176e8d..20b9596 100644
+--- a/drivers/ide/cris/Makefile
++++ b/drivers/ide/cris/Makefile
+@@ -1,3 +1,3 @@
+ EXTRA_CFLAGS				+= -Idrivers/ide
  
- 	i2c_del_adapter(&i2c->adap);
--	free_irq(i2c->irq, i2c);
-+	if (!i2c->use_pio)
-+		free_irq(i2c->irq, i2c);
+-obj-y					+= ide-cris.o
++obj-$(CONFIG_IDE_ETRAX)			+= ide-cris.o
+diff --git a/drivers/ide/cris/ide-cris.c b/drivers/ide/cris/ide-cris.c
+index 476e0d6..8c3294c 100644
+--- a/drivers/ide/cris/ide-cris.c
++++ b/drivers/ide/cris/ide-cris.c
+@@ -673,9 +673,8 @@ static void cris_ide_input_data (ide_drive_t *drive, void *, unsigned int);
+ static void cris_ide_output_data (ide_drive_t *drive, void *, unsigned int);
+ static void cris_atapi_input_bytes(ide_drive_t *drive, void *, unsigned int);
+ static void cris_atapi_output_bytes(ide_drive_t *drive, void *, unsigned int);
+-static int cris_dma_on (ide_drive_t *drive);
  
- 	clk_disable(i2c->clk);
- 	clk_put(i2c->clk);
--
--#ifdef CONFIG_PXA27x
--	if (dev->id == 1) {
--		local_irq_disable();
--		PCFR &= ~PCFR_PI2CEN;
--		local_irq_enable();
--	}
--#endif
-+	i2c_pxa_disable(dev);
+-static void cris_dma_off(ide_drive_t *drive)
++static void cris_dma_host_set(ide_drive_t *drive, int on)
+ {
+ }
  
- 	release_mem_region(i2c->iobase, i2c->iosize);
- 	kfree(i2c);
-diff --git a/drivers/i2c/busses/i2c-sibyte.c b/drivers/i2c/busses/i2c-sibyte.c
-index 503a134..8fbbdb4 100644
---- a/drivers/i2c/busses/i2c-sibyte.c
-+++ b/drivers/i2c/busses/i2c-sibyte.c
-@@ -36,14 +36,6 @@ struct i2c_algo_sibyte_data {
- /* ----- global defines ----------------------------------------------- */
- #define SMB_CSR(a,r) ((long)(a->reg_base + r))
+@@ -747,8 +746,6 @@ static void cris_set_dma_mode(ide_drive_t *drive, const u8 speed)
+ 			strobe = ATA_DMA2_STROBE;
+ 			hold = ATA_DMA2_HOLD;
+ 			break;
+-		default:
+-			return;
+ 	}
  
--/* ----- global variables --------------------------------------------- */
--
--/* module parameters:
-- */
--static int bit_scan;	/* have a look at what's hanging 'round */
--module_param(bit_scan, int, 0);
--MODULE_PARM_DESC(bit_scan, "Scan for active chips on the bus");
--
+ 	if (speed >= XFER_UDMA_0)
+@@ -757,13 +754,11 @@ static void cris_set_dma_mode(ide_drive_t *drive, const u8 speed)
+ 		cris_ide_set_speed(TYPE_DMA, 0, strobe, hold);
+ }
  
- static int smbus_xfer(struct i2c_adapter *i2c_adap, u16 addr,
- 		      unsigned short flags, char read_write,
-@@ -140,9 +132,8 @@ static const struct i2c_algorithm i2c_sibyte_algo = {
- /*
-  * registering functions to load algorithms at runtime
-  */
--int i2c_sibyte_add_bus(struct i2c_adapter *i2c_adap, int speed)
-+int __init i2c_sibyte_add_bus(struct i2c_adapter *i2c_adap, int speed)
+-void __init
+-init_e100_ide (void)
++static int __init init_e100_ide(void)
  {
+ 	hw_regs_t hw;
+-	int ide_offsets[IDE_NR_PORTS];
+-	int h;
 -	int i;
- 	struct i2c_algo_sibyte_data *adap = i2c_adap->algo_data;
++	int ide_offsets[IDE_NR_PORTS], h, i;
++	u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
  
- 	/* register new adapter to i2c module... */
-@@ -152,24 +143,6 @@ int i2c_sibyte_add_bus(struct i2c_adapter *i2c_adap, int speed)
- 	csr_out32(speed, SMB_CSR(adap,R_SMB_FREQ));
- 	csr_out32(0, SMB_CSR(adap,R_SMB_CONTROL));
+ 	printk("ide: ETRAX FS built-in ATA DMA controller\n");
  
--	/* scan bus */
--	if (bit_scan) {
--		union i2c_smbus_data data;
--		int rc;
--		printk(KERN_INFO " i2c-algo-sibyte.o: scanning bus %s.\n",
--		       i2c_adap->name);
--		for (i = 0x00; i < 0x7f; i++) {
--			/* XXXKW is this a realistic probe? */
--			rc = smbus_xfer(i2c_adap, i, 0, I2C_SMBUS_READ, 0,
--					I2C_SMBUS_BYTE_DATA, &data);
--			if (!rc) {
--				printk("(%02x)",i);
--			} else
--				printk(".");
--		}
--		printk("\n");
--	}
--
- 	return i2c_add_adapter(i2c_adap);
+@@ -780,9 +775,11 @@ init_e100_ide (void)
+ 		                ide_offsets,
+ 		                0, 0, cris_ide_ack_intr,
+ 		                ide_default_irq(0));
+-		ide_register_hw(&hw, NULL, 1, &hwif);
++		hwif = ide_find_port(hw.io_ports[IDE_DATA_OFFSET]);
+ 		if (hwif == NULL)
+ 			continue;
++		ide_init_port_data(hwif, hwif->index);
++		ide_init_port_hw(hwif, &hw);
+ 		hwif->mmio = 1;
+ 		hwif->chipset = ide_etrax100;
+ 		hwif->set_pio_mode = &cris_set_pio_mode;
+@@ -791,6 +788,7 @@ init_e100_ide (void)
+ 		hwif->ata_output_data = &cris_ide_output_data;
+ 		hwif->atapi_input_bytes = &cris_atapi_input_bytes;
+ 		hwif->atapi_output_bytes = &cris_atapi_output_bytes;
++		hwif->dma_host_set = &cris_dma_host_set;
+ 		hwif->ide_dma_end = &cris_dma_end;
+ 		hwif->dma_setup = &cris_dma_setup;
+ 		hwif->dma_exec_cmd = &cris_dma_exec_cmd;
+@@ -801,9 +799,6 @@ init_e100_ide (void)
+ 		hwif->OUTBSYNC = &cris_ide_outbsync;
+ 		hwif->INB = &cris_ide_inb;
+ 		hwif->INW = &cris_ide_inw;
+-		hwif->dma_host_off = &cris_dma_off;
+-		hwif->dma_host_on = &cris_dma_on;
+-		hwif->dma_off_quietly = &cris_dma_off;
+ 		hwif->cbl = ATA_CBL_PATA40;
+ 		hwif->host_flags |= IDE_HFLAG_NO_ATAPI_DMA;
+ 		hwif->pio_mask = ATA_PIO4,
+@@ -811,6 +806,8 @@ init_e100_ide (void)
+ 		hwif->drives[1].autotune = 1;
+ 		hwif->ultra_mask = cris_ultra_mask;
+ 		hwif->mwdma_mask = 0x07; /* Multiword DMA 0-2 */
++
++		idx[h] = hwif->index;
+ 	}
+ 
+ 	/* Reset pulse */
+@@ -823,14 +820,12 @@ init_e100_ide (void)
+ 	cris_ide_set_speed(TYPE_PIO, ATA_PIO4_SETUP, ATA_PIO4_STROBE, ATA_PIO4_HOLD);
+ 	cris_ide_set_speed(TYPE_DMA, 0, ATA_DMA2_STROBE, ATA_DMA2_HOLD);
+ 	cris_ide_set_speed(TYPE_UDMA, ATA_UDMA2_CYC, ATA_UDMA2_DVS, 0);
+-}
+ 
+-static int cris_dma_on (ide_drive_t *drive)
+-{
++	ide_device_add(idx);
++
+ 	return 0;
  }
  
-diff --git a/drivers/i2c/busses/i2c-stub.c b/drivers/i2c/busses/i2c-stub.c
-index 84df29d..c2a9f8c 100644
---- a/drivers/i2c/busses/i2c-stub.c
-+++ b/drivers/i2c/busses/i2c-stub.c
-@@ -1,8 +1,8 @@
+-
+ static cris_dma_descr_type mydescr __attribute__ ((__aligned__(16)));
+ 
  /*
--    i2c-stub.c - Part of lm_sensors, Linux kernel modules for hardware
--              monitoring
-+    i2c-stub.c - I2C/SMBus chip emulator
+@@ -1062,3 +1057,5 @@ static void cris_dma_start(ide_drive_t *drive)
+ 		LED_DISK_READ(1);
+ 	}
+ }
++
++module_init(init_e100_ide);
+diff --git a/drivers/ide/h8300/Makefile b/drivers/ide/h8300/Makefile
+new file mode 100644
+index 0000000..5eba16f
+--- /dev/null
++++ b/drivers/ide/h8300/Makefile
+@@ -0,0 +1,2 @@
++
++obj-$(CONFIG_IDE_H8300)			+= ide-h8300.o
+diff --git a/drivers/ide/h8300/ide-h8300.c b/drivers/ide/h8300/ide-h8300.c
+index 4a49b5c..4f6d019 100644
+--- a/drivers/ide/h8300/ide-h8300.c
++++ b/drivers/ide/h8300/ide-h8300.c
+@@ -84,11 +84,12 @@ static inline void hwif_setup(ide_hwif_t *hwif)
+ 	hwif->INSL  = NULL;
+ }
  
-     Copyright (c) 2004 Mark M. Hoffman <mhoffman at lightlink.com>
-+    Copyright (C) 2007 Jean Delvare <khali at linux-fr.org>
+-void __init h8300_ide_init(void)
++static int __init h8300_ide_init(void)
+ {
+ 	hw_regs_t hw;
+ 	ide_hwif_t *hwif;
+-	int idx;
++	int index;
++	u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
  
-     This program is free software; you can redistribute it and/or modify
-     it under the terms of the GNU General Public License as published by
-@@ -37,8 +37,8 @@ MODULE_PARM_DESC(chip_addr,
+ 	if (!request_region(CONFIG_H8300_IDE_BASE, H8300_IDE_GAP*8, "ide-h8300"))
+ 		goto out_busy;
+@@ -100,16 +101,28 @@ void __init h8300_ide_init(void)
+ 	hw_setup(&hw);
  
- struct stub_chip {
- 	u8 pointer;
--	u8 bytes[256];
--	u16 words[256];
-+	u16 words[256];		/* Byte operations use the LSB as per SMBus
-+				   specification */
- };
+ 	/* register if */
+-	idx = ide_register_hw(&hw, NULL, 1, &hwif);
+-	if (idx == -1) {
++	hwif = ide_find_port(hw.io_ports[IDE_DATA_OFFSET]);
++	if (hwif == NULL) {
+ 		printk(KERN_ERR "ide-h8300: IDE I/F register failed\n");
+-		return;
++		return -ENOENT;
+ 	}
  
- static struct stub_chip *stub_chips;
-@@ -75,7 +75,7 @@ static s32 stub_xfer(struct i2c_adapter * adap, u16 addr, unsigned short flags,
- 					"wrote 0x%02x.\n",
- 					addr, command);
- 		} else {
--			data->byte = chip->bytes[chip->pointer++];
-+			data->byte = chip->words[chip->pointer++] & 0xff;
- 			dev_dbg(&adap->dev, "smbus byte - addr 0x%02x, "
- 					"read  0x%02x.\n",
- 					addr, data->byte);
-@@ -86,12 +86,13 @@ static s32 stub_xfer(struct i2c_adapter * adap, u16 addr, unsigned short flags,
++	index = hwif->index;
++	ide_init_port_data(hwif, index);
++	ide_init_port_hw(hwif, &hw);
+ 	hwif_setup(hwif);
+-	printk(KERN_INFO "ide%d: H8/300 generic IDE interface\n", idx);
+-	return;
++	printk(KERN_INFO "ide%d: H8/300 generic IDE interface\n", index);
++
++	idx[0] = index;
++
++	ide_device_add(idx);
++
++	return 0;
  
- 	case I2C_SMBUS_BYTE_DATA:
- 		if (read_write == I2C_SMBUS_WRITE) {
--			chip->bytes[command] = data->byte;
-+			chip->words[command] &= 0xff00;
-+			chip->words[command] |= data->byte;
- 			dev_dbg(&adap->dev, "smbus byte data - addr 0x%02x, "
- 					"wrote 0x%02x at 0x%02x.\n",
- 					addr, data->byte, command);
- 		} else {
--			data->byte = chip->bytes[command];
-+			data->byte = chip->words[command] & 0xff;
- 			dev_dbg(&adap->dev, "smbus byte data - addr 0x%02x, "
- 					"read  0x%02x at 0x%02x.\n",
- 					addr, data->byte, command);
-diff --git a/drivers/i2c/busses/i2c-viapro.c b/drivers/i2c/busses/i2c-viapro.c
-index c9ce77f..77b13d0 100644
---- a/drivers/i2c/busses/i2c-viapro.c
-+++ b/drivers/i2c/busses/i2c-viapro.c
-@@ -4,7 +4,7 @@
-     Copyright (c) 1998 - 2002  Frodo Looijaard <frodol at dds.nl>,
-     Philip Edelbrock <phil at netroedge.com>, Kyösti Mälkki <kmalkki at cc.hut.fi>,
-     Mark D. Studebaker <mdsxyz123 at yahoo.com>
--    Copyright (C) 2005 - 2007  Jean Delvare <khali at linux-fr.org>
-+    Copyright (C) 2005 - 2008  Jean Delvare <khali at linux-fr.org>
+ out_busy:
+ 	printk(KERN_ERR "ide-h8300: IDE I/F resource already used.\n");
++
++	return -EBUSY;
+ }
++
++module_init(h8300_ide_init);
+diff --git a/drivers/ide/ide-acpi.c b/drivers/ide/ide-acpi.c
+index 899d565..e888fc3 100644
+--- a/drivers/ide/ide-acpi.c
++++ b/drivers/ide/ide-acpi.c
+@@ -383,27 +383,19 @@ static int taskfile_load_raw(ide_drive_t *drive,
+ 	       gtf->tfa[3], gtf->tfa[4], gtf->tfa[5], gtf->tfa[6]);
  
-     This program is free software; you can redistribute it and/or modify
-     it under the terms of the GNU General Public License as published by
-@@ -35,6 +35,7 @@
-    VT8235             0x3177             yes
-    VT8237R            0x3227             yes
-    VT8237A            0x3337             yes
-+   VT8237S            0x3372             yes
-    VT8251             0x3287             yes
-    CX700              0x8324             yes
+ 	memset(&args, 0, sizeof(ide_task_t));
+-	args.command_type = IDE_DRIVE_TASK_NO_DATA;
+-	args.data_phase   = TASKFILE_NO_DATA;
+-	args.handler      = &task_no_data_intr;
  
-@@ -318,6 +319,10 @@ static int __devinit vt596_probe(struct pci_dev *pdev,
- 	unsigned char temp;
- 	int error = -ENODEV;
+ 	/* convert gtf to IDE Taskfile */
+-	args.tfRegister[1] = gtf->tfa[0];	/* 0x1f1 */
+-	args.tfRegister[2] = gtf->tfa[1];	/* 0x1f2 */
+-	args.tfRegister[3] = gtf->tfa[2];	/* 0x1f3 */
+-	args.tfRegister[4] = gtf->tfa[3];	/* 0x1f4 */
+-	args.tfRegister[5] = gtf->tfa[4];	/* 0x1f5 */
+-	args.tfRegister[6] = gtf->tfa[5];	/* 0x1f6 */
+-	args.tfRegister[7] = gtf->tfa[6];	/* 0x1f7 */
++	memcpy(&args.tf_array[7], &gtf->tfa, 7);
++	args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
  
-+	/* driver_data might come from user-space, so check it */
-+	if (id->driver_data & 1 || id->driver_data > 0xff)
-+		return -EINVAL;
-+
- 	/* Determine the address of the SMBus areas */
- 	if (force_addr) {
- 		vt596_smba = force_addr & 0xfff0;
-@@ -389,6 +394,7 @@ found:
- 	case PCI_DEVICE_ID_VIA_8251:
- 	case PCI_DEVICE_ID_VIA_8237:
- 	case PCI_DEVICE_ID_VIA_8237A:
-+	case PCI_DEVICE_ID_VIA_8237S:
- 	case PCI_DEVICE_ID_VIA_8235:
- 	case PCI_DEVICE_ID_VIA_8233A:
- 	case PCI_DEVICE_ID_VIA_8233_0:
-@@ -440,6 +446,8 @@ static struct pci_device_id vt596_ids[] = {
- 	  .driver_data = SMBBA3 },
- 	{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237A),
- 	  .driver_data = SMBBA3 },
-+	{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237S),
-+	  .driver_data = SMBBA3 },
- 	{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8231_4),
- 	  .driver_data = SMBBA1 },
- 	{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8251),
-@@ -455,6 +463,7 @@ static struct pci_driver vt596_driver = {
- 	.name		= "vt596_smbus",
- 	.id_table	= vt596_ids,
- 	.probe		= vt596_probe,
-+	.dynids.use_driver_data = 1,
- };
+ 	if (ide_noacpitfs) {
+ 		DEBPRINT("_GTF execution disabled\n");
+ 		return err;
+ 	}
  
- static int __init i2c_vt596_init(void)
-diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig
-index 2e1c24f..bd7082c 100644
---- a/drivers/i2c/chips/Kconfig
-+++ b/drivers/i2c/chips/Kconfig
-@@ -4,32 +4,6 @@
+-	err = ide_raw_taskfile(drive, &args, NULL);
++	err = ide_no_data_taskfile(drive, &args);
+ 	if (err)
+-		printk(KERN_ERR "%s: ide_raw_taskfile failed: %u\n",
++		printk(KERN_ERR "%s: ide_no_data_taskfile failed: %u\n",
+ 		       __FUNCTION__, err);
  
- menu "Miscellaneous I2C Chip support"
+ 	return err;
+diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c
+index c7d77f0..74c6087 100644
+--- a/drivers/ide/ide-cd.c
++++ b/drivers/ide/ide-cd.c
+@@ -655,9 +655,9 @@ static void cdrom_end_request (ide_drive_t *drive, int uptodate)
+ 					BUG();
+ 			} else {
+ 				spin_lock_irqsave(&ide_lock, flags);
+-				end_that_request_chunk(failed, 0,
+-							failed->data_len);
+-				end_that_request_last(failed, 0);
++				if (__blk_end_request(failed, -EIO,
++						      failed->data_len))
++					BUG();
+ 				spin_unlock_irqrestore(&ide_lock, flags);
+ 			}
+ 		} else
+@@ -917,19 +917,13 @@ static ide_startstop_t cdrom_start_packet_command(ide_drive_t *drive,
+ 	if (ide_wait_stat(&startstop, drive, 0, BUSY_STAT, WAIT_READY))
+ 		return startstop;
  
--config SENSORS_DS1337
--	tristate "Dallas DS1337 and DS1339 Real Time Clock (DEPRECATED)"
--	depends on EXPERIMENTAL
--	help
--	  If you say yes here you get support for Dallas Semiconductor
--	  DS1337 and DS1339 real-time clock chips.
--
--	  This driver can also be built as a module.  If so, the module
--	  will be called ds1337.
--
--	  This driver is deprecated and will be dropped soon. Use
--	  rtc-ds1307 instead.
--
--config SENSORS_DS1374
--	tristate "Dallas DS1374 Real Time Clock (DEPRECATED)"
--	depends on EXPERIMENTAL
--	help
--	  If you say yes here you get support for Dallas Semiconductor
--	  DS1374 real-time clock chips.
--
--	  This driver can also be built as a module.  If so, the module
--	  will be called ds1374.
--
--	  This driver is deprecated and will be dropped soon. Use
--	  rtc-ds1374 instead.
--
- config DS1682
- 	tristate "Dallas DS1682 Total Elapsed Time Recorder with Alarm"
- 	depends on EXPERIMENTAL
-@@ -57,7 +31,7 @@ config SENSORS_PCF8574
- 	default n
- 	help
- 	  If you say yes here you get support for Philips PCF8574 and 
--	  PCF8574A chips.
-+	  PCF8574A chips. These chips are 8-bit I/O expanders for the I2C bus.
++	/* FIXME: for Virtual DMA we must check harder */
+ 	if (info->dma)
+ 		info->dma = !hwif->dma_setup(drive);
  
- 	  This driver can also be built as a module.  If so, the module
- 	  will be called pcf8574.
-@@ -65,6 +39,20 @@ config SENSORS_PCF8574
- 	  These devices are hard to detect and rarely found on mainstream
- 	  hardware.  If unsure, say N.
+ 	/* Set up the controller registers. */
+-	/* FIXME: for Virtual DMA we must check harder */
+-	HWIF(drive)->OUTB(info->dma, IDE_FEATURE_REG);
+-	HWIF(drive)->OUTB(0, IDE_IREASON_REG);
+-	HWIF(drive)->OUTB(0, IDE_SECTOR_REG);
+-
+-	HWIF(drive)->OUTB(xferlen & 0xff, IDE_BCOUNTL_REG);
+-	HWIF(drive)->OUTB(xferlen >> 8  , IDE_BCOUNTH_REG);
+-	if (IDE_CONTROL_REG)
+-		HWIF(drive)->OUTB(drive->ctl, IDE_CONTROL_REG);
++	ide_pktcmd_tf_load(drive, IDE_TFLAG_OUT_NSECT | IDE_TFLAG_OUT_LBAL |
++			   IDE_TFLAG_NO_SELECT_MASK, xferlen, info->dma);
+  
+ 	if (CDROM_CONFIG_FLAGS (drive)->drq_interrupt) {
+ 		/* waiting for CDB interrupt, not DMA yet. */
+@@ -1653,6 +1647,17 @@ static int cdrom_write_check_ireason(ide_drive_t *drive, int len, int ireason)
+ 	return 1;
+ }
  
-+config PCF8575
-+	tristate "Philips PCF8575"
-+	default n
-+	help
-+	  If you say yes here you get support for Philips PCF8575 chip.
-+	  This chip is a 16-bit I/O expander for the I2C bus.  Several other
-+	  chip manufacturers sell equivalent chips, e.g. Texas Instruments.
++/*
++ * Called from blk_end_request_callback() after the data of the request
++ * is completed and before the request is completed.
++ * By returning value '1', blk_end_request_callback() returns immediately
++ * without completing the request.
++ */
++static int cdrom_newpc_intr_dummy_cb(struct request *rq)
++{
++	return 1;
++}
 +
-+	  This driver can also be built as a module.  If so, the module
-+	  will be called pcf8575.
+ typedef void (xfer_func_t)(ide_drive_t *, void *, u32);
+ 
+ /*
+@@ -1691,9 +1696,13 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
+ 			return ide_error(drive, "dma error", stat);
+ 		}
+ 
+-		end_that_request_chunk(rq, 1, rq->data_len);
+-		rq->data_len = 0;
+-		goto end_request;
++		spin_lock_irqsave(&ide_lock, flags);
++		if (__blk_end_request(rq, 0, rq->data_len))
++			BUG();
++		HWGROUP(drive)->rq = NULL;
++		spin_unlock_irqrestore(&ide_lock, flags);
 +
-+	  This device is hard to detect and is rarely found on mainstream
-+	  hardware.  If unsure, say N.
++		return ide_stopped;
+ 	}
+ 
+ 	/*
+@@ -1711,8 +1720,15 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
+ 	/*
+ 	 * If DRQ is clear, the command has completed.
+ 	 */
+-	if ((stat & DRQ_STAT) == 0)
+-		goto end_request;
++	if ((stat & DRQ_STAT) == 0) {
++		spin_lock_irqsave(&ide_lock, flags);
++		if (__blk_end_request(rq, 0, 0))
++			BUG();
++		HWGROUP(drive)->rq = NULL;
++		spin_unlock_irqrestore(&ide_lock, flags);
 +
- config SENSORS_PCA9539
- 	tristate "Philips PCA9539 16-bit I/O port"
- 	depends on EXPERIMENTAL
-@@ -100,12 +88,8 @@ config ISP1301_OMAP
- 	  This driver can also be built as a module.  If so, the module
- 	  will be called isp1301_omap.
++		return ide_stopped;
++	}
  
--# NOTE:  This isn't really OMAP-specific, except for the current
--# interface location in  <include/asm-arm/arch-omap/tps65010.h>
--# and having mostly OMAP-specific board support
- config TPS65010
- 	tristate "TPS6501x Power Management chips"
--	depends on ARCH_OMAP
- 	default y if MACH_OMAP_H2 || MACH_OMAP_H3 || MACH_OMAP_OSK
- 	help
- 	  If you say yes here you get support for the TPS6501x series of
-@@ -116,18 +100,6 @@ config TPS65010
- 	  This driver can also be built as a module.  If so, the module
- 	  will be called tps65010.
+ 	/*
+ 	 * check which way to transfer data
+@@ -1765,7 +1781,14 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
+ 		rq->data_len -= blen;
  
--config SENSORS_M41T00
--	tristate "ST M41T00 RTC chip (DEPRECATED)"
--	depends on PPC32
--	help
--	  If you say yes here you get support for the ST M41T00 RTC chip.
--
--	  This driver can also be built as a module.  If so, the module
--	  will be called m41t00.
--
--	  This driver is deprecated and will be dropped soon. Use
--	  rtc-ds1307 or rtc-m41t80 instead.
--
- config SENSORS_MAX6875
- 	tristate "Maxim MAX6875 Power supply supervisor"
- 	depends on EXPERIMENTAL
-diff --git a/drivers/i2c/chips/Makefile b/drivers/i2c/chips/Makefile
-index ca924e1..501f00c 100644
---- a/drivers/i2c/chips/Makefile
-+++ b/drivers/i2c/chips/Makefile
-@@ -2,14 +2,12 @@
- # Makefile for miscellaneous I2C chip drivers.
- #
+ 		if (rq->bio)
+-			end_that_request_chunk(rq, 1, blen);
++			/*
++			 * The request can't be completed until DRQ is cleared.
++			 * So complete the data, but don't complete the request
++			 * using the dummy function for the callback feature
++			 * of blk_end_request_callback().
++			 */
++			blk_end_request_callback(rq, 0, blen,
++						 cdrom_newpc_intr_dummy_cb);
+ 		else
+ 			rq->data += blen;
+ 	}
+@@ -1786,14 +1809,6 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
  
--obj-$(CONFIG_SENSORS_DS1337)	+= ds1337.o
--obj-$(CONFIG_SENSORS_DS1374)	+= ds1374.o
- obj-$(CONFIG_DS1682)		+= ds1682.o
- obj-$(CONFIG_SENSORS_EEPROM)	+= eeprom.o
- obj-$(CONFIG_SENSORS_MAX6875)	+= max6875.o
--obj-$(CONFIG_SENSORS_M41T00)	+= m41t00.o
- obj-$(CONFIG_SENSORS_PCA9539)	+= pca9539.o
- obj-$(CONFIG_SENSORS_PCF8574)	+= pcf8574.o
-+obj-$(CONFIG_PCF8575)		+= pcf8575.o
- obj-$(CONFIG_SENSORS_PCF8591)	+= pcf8591.o
- obj-$(CONFIG_ISP1301_OMAP)	+= isp1301_omap.o
- obj-$(CONFIG_TPS65010)		+= tps65010.o
-diff --git a/drivers/i2c/chips/ds1337.c b/drivers/i2c/chips/ds1337.c
-deleted file mode 100644
-index ec17d6b..0000000
---- a/drivers/i2c/chips/ds1337.c
-+++ /dev/null
-@@ -1,410 +0,0 @@
--/*
-- *  linux/drivers/i2c/chips/ds1337.c
-- *
-- *  Copyright (C) 2005 James Chapman <jchapman at katalix.com>
-- *
-- *	based on linux/drivers/acorn/char/pcf8583.c
-- *  Copyright (C) 2000 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.
-- *
-- * Driver for Dallas Semiconductor DS1337 and DS1339 real time clock chip
-- */
--
--#include <linux/module.h>
--#include <linux/init.h>
--#include <linux/slab.h>
--#include <linux/i2c.h>
--#include <linux/string.h>
--#include <linux/rtc.h>		/* get the user-level API */
--#include <linux/bcd.h>
--#include <linux/list.h>
--
--/* Device registers */
--#define DS1337_REG_HOUR		2
--#define DS1337_REG_DAY		3
--#define DS1337_REG_DATE		4
--#define DS1337_REG_MONTH	5
--#define DS1337_REG_CONTROL	14
--#define DS1337_REG_STATUS	15
--
--/* FIXME - how do we export these interface constants? */
--#define DS1337_GET_DATE		0
--#define DS1337_SET_DATE		1
--
--/*
-- * Functions declaration
-- */
--static unsigned short normal_i2c[] = { 0x68, I2C_CLIENT_END };
--
--I2C_CLIENT_INSMOD_1(ds1337);
--
--static int ds1337_attach_adapter(struct i2c_adapter *adapter);
--static int ds1337_detect(struct i2c_adapter *adapter, int address, int kind);
--static void ds1337_init_client(struct i2c_client *client);
--static int ds1337_detach_client(struct i2c_client *client);
--static int ds1337_command(struct i2c_client *client, unsigned int cmd,
--			  void *arg);
--
--/*
-- * Driver data (common to all clients)
-- */
--static struct i2c_driver ds1337_driver = {
--	.driver = {
--		.name	= "ds1337",
--	},
--	.attach_adapter	= ds1337_attach_adapter,
--	.detach_client	= ds1337_detach_client,
--	.command	= ds1337_command,
--};
--
--/*
-- * Client data (each client gets its own)
-- */
--struct ds1337_data {
--	struct i2c_client client;
--	struct list_head list;
--};
--
--/*
-- * Internal variables
-- */
--static LIST_HEAD(ds1337_clients);
--
--static inline int ds1337_read(struct i2c_client *client, u8 reg, u8 *value)
--{
--	s32 tmp = i2c_smbus_read_byte_data(client, reg);
--
--	if (tmp < 0)
--		return -EIO;
--
--	*value = tmp;
--
--	return 0;
--}
--
--/*
-- * Chip access functions
-- */
--static int ds1337_get_datetime(struct i2c_client *client, struct rtc_time *dt)
--{
--	int result;
--	u8 buf[7];
--	u8 val;
--	struct i2c_msg msg[2];
--	u8 offs = 0;
--
--	if (!dt) {
--		dev_dbg(&client->dev, "%s: EINVAL: dt=NULL\n", __FUNCTION__);
--		return -EINVAL;
--	}
--
--	msg[0].addr = client->addr;
--	msg[0].flags = 0;
--	msg[0].len = 1;
--	msg[0].buf = &offs;
--
--	msg[1].addr = client->addr;
--	msg[1].flags = I2C_M_RD;
--	msg[1].len = sizeof(buf);
--	msg[1].buf = &buf[0];
--
--	result = i2c_transfer(client->adapter, msg, 2);
--
--	dev_dbg(&client->dev, "%s: [%d] %02x %02x %02x %02x %02x %02x %02x\n",
--		__FUNCTION__, result, buf[0], buf[1], buf[2], buf[3],
--		buf[4], buf[5], buf[6]);
--
--	if (result == 2) {
--		dt->tm_sec = BCD2BIN(buf[0]);
--		dt->tm_min = BCD2BIN(buf[1]);
--		val = buf[2] & 0x3f;
--		dt->tm_hour = BCD2BIN(val);
--		dt->tm_wday = BCD2BIN(buf[3]) - 1;
--		dt->tm_mday = BCD2BIN(buf[4]);
--		val = buf[5] & 0x7f;
--		dt->tm_mon = BCD2BIN(val) - 1;
--		dt->tm_year = BCD2BIN(buf[6]);
--		if (buf[5] & 0x80)
--			dt->tm_year += 100;
--
--		dev_dbg(&client->dev, "%s: secs=%d, mins=%d, "
--			"hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n",
--			__FUNCTION__, dt->tm_sec, dt->tm_min,
--			dt->tm_hour, dt->tm_mday,
--			dt->tm_mon, dt->tm_year, dt->tm_wday);
--
--		return 0;
--	}
--
--	dev_err(&client->dev, "error reading data! %d\n", result);
--	return -EIO;
--}
--
--static int ds1337_set_datetime(struct i2c_client *client, struct rtc_time *dt)
--{
--	int result;
--	u8 buf[8];
--	u8 val;
--	struct i2c_msg msg[1];
--
--	if (!dt) {
--		dev_dbg(&client->dev, "%s: EINVAL: dt=NULL\n", __FUNCTION__);
--		return -EINVAL;
--	}
--
--	dev_dbg(&client->dev, "%s: secs=%d, mins=%d, hours=%d, "
--		"mday=%d, mon=%d, year=%d, wday=%d\n", __FUNCTION__,
--		dt->tm_sec, dt->tm_min, dt->tm_hour,
--		dt->tm_mday, dt->tm_mon, dt->tm_year, dt->tm_wday);
--
--	buf[0] = 0;		/* reg offset */
--	buf[1] = BIN2BCD(dt->tm_sec);
--	buf[2] = BIN2BCD(dt->tm_min);
--	buf[3] = BIN2BCD(dt->tm_hour);
--	buf[4] = BIN2BCD(dt->tm_wday + 1);
--	buf[5] = BIN2BCD(dt->tm_mday);
--	buf[6] = BIN2BCD(dt->tm_mon + 1);
--	val = dt->tm_year;
--	if (val >= 100) {
--		val -= 100;
--		buf[6] |= (1 << 7);
--	}
--	buf[7] = BIN2BCD(val);
--
--	msg[0].addr = client->addr;
--	msg[0].flags = 0;
--	msg[0].len = sizeof(buf);
--	msg[0].buf = &buf[0];
--
--	result = i2c_transfer(client->adapter, msg, 1);
--	if (result == 1)
--		return 0;
--
--	dev_err(&client->dev, "error writing data! %d\n", result);
--	return -EIO;
--}
--
--static int ds1337_command(struct i2c_client *client, unsigned int cmd,
--			  void *arg)
--{
--	dev_dbg(&client->dev, "%s: cmd=%d\n", __FUNCTION__, cmd);
--
--	switch (cmd) {
--	case DS1337_GET_DATE:
--		return ds1337_get_datetime(client, arg);
--
--	case DS1337_SET_DATE:
--		return ds1337_set_datetime(client, arg);
--
--	default:
--		return -EINVAL;
--	}
--}
--
--/*
-- * Public API for access to specific device. Useful for low-level
-- * RTC access from kernel code.
-- */
--int ds1337_do_command(int bus, int cmd, void *arg)
--{
--	struct list_head *walk;
--	struct list_head *tmp;
--	struct ds1337_data *data;
--
--	list_for_each_safe(walk, tmp, &ds1337_clients) {
--		data = list_entry(walk, struct ds1337_data, list);
--		if (data->client.adapter->nr == bus)
--			return ds1337_command(&data->client, cmd, arg);
--	}
--
--	return -ENODEV;
--}
--
--static int ds1337_attach_adapter(struct i2c_adapter *adapter)
--{
--	return i2c_probe(adapter, &addr_data, ds1337_detect);
--}
--
--/*
-- * The following function does more than just detection. If detection
-- * succeeds, it also registers the new chip.
-- */
--static int ds1337_detect(struct i2c_adapter *adapter, int address, int kind)
--{
--	struct i2c_client *new_client;
--	struct ds1337_data *data;
--	int err = 0;
--	const char *name = "";
--
--	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
--				     I2C_FUNC_I2C))
--		goto exit;
--
--	if (!(data = kzalloc(sizeof(struct ds1337_data), GFP_KERNEL))) {
--		err = -ENOMEM;
--		goto exit;
--	}
--	INIT_LIST_HEAD(&data->list);
--
--	/* The common I2C client data is placed right before the
--	 * DS1337-specific data. 
--	 */
--	new_client = &data->client;
--	i2c_set_clientdata(new_client, data);
--	new_client->addr = address;
--	new_client->adapter = adapter;
--	new_client->driver = &ds1337_driver;
--	new_client->flags = 0;
--
--	/*
--	 * Now we do the remaining detection. A negative kind means that
--	 * the driver was loaded with no force parameter (default), so we
--	 * must both detect and identify the chip. A zero kind means that
--	 * the driver was loaded with the force parameter, the detection
--	 * step shall be skipped. A positive kind means that the driver
--	 * was loaded with the force parameter and a given kind of chip is
--	 * requested, so both the detection and the identification steps
--	 * are skipped.
--	 *
--	 * For detection, we read registers that are most likely to cause
--	 * detection failure, i.e. those that have more bits with fixed
--	 * or reserved values.
--	 */
--
--	/* Default to an DS1337 if forced */
--	if (kind == 0)
--		kind = ds1337;
--
--	if (kind < 0) {		/* detection and identification */
--		u8 data;
--
--		/* Check that status register bits 6-2 are zero */
--		if ((ds1337_read(new_client, DS1337_REG_STATUS, &data) < 0) ||
--		    (data & 0x7c))
--			goto exit_free;
--
--		/* Check for a valid day register value */
--		if ((ds1337_read(new_client, DS1337_REG_DAY, &data) < 0) ||
--		    (data == 0) || (data & 0xf8))
--			goto exit_free;
--
--		/* Check for a valid date register value */
--		if ((ds1337_read(new_client, DS1337_REG_DATE, &data) < 0) ||
--		    (data == 0) || (data & 0xc0) || ((data & 0x0f) > 9) ||
--		    (data >= 0x32))
--			goto exit_free;
--
--		/* Check for a valid month register value */
--		if ((ds1337_read(new_client, DS1337_REG_MONTH, &data) < 0) ||
--		    (data == 0) || (data & 0x60) || ((data & 0x0f) > 9) ||
--		    ((data >= 0x13) && (data <= 0x19)))
--			goto exit_free;
--
--		/* Check that control register bits 6-5 are zero */
--		if ((ds1337_read(new_client, DS1337_REG_CONTROL, &data) < 0) ||
--		    (data & 0x60))
--			goto exit_free;
--
--		kind = ds1337;
--	}
--
--	if (kind == ds1337)
--		name = "ds1337";
--
--	/* We can fill in the remaining client fields */
--	strlcpy(new_client->name, name, I2C_NAME_SIZE);
--
--	/* Tell the I2C layer a new client has arrived */
--	if ((err = i2c_attach_client(new_client)))
--		goto exit_free;
--
--	/* Initialize the DS1337 chip */
--	ds1337_init_client(new_client);
--
--	/* Add client to local list */
--	list_add(&data->list, &ds1337_clients);
--
--	return 0;
--
--exit_free:
--	kfree(data);
--exit:
--	return err;
--}
--
--static void ds1337_init_client(struct i2c_client *client)
--{
--	u8 status, control;
--
--	/* On some boards, the RTC isn't configured by boot firmware.
--	 * Handle that case by starting/configuring the RTC now.
--	 */
--	status = i2c_smbus_read_byte_data(client, DS1337_REG_STATUS);
--	control = i2c_smbus_read_byte_data(client, DS1337_REG_CONTROL);
--
--	if ((status & 0x80) || (control & 0x80)) {
--		/* RTC not running */
--		u8 buf[1+16];	/* First byte is interpreted as address */
--		struct i2c_msg msg[1];
--
--		dev_dbg(&client->dev, "%s: RTC not running!\n", __FUNCTION__);
--
--		/* Initialize all, including STATUS and CONTROL to zero */
--		memset(buf, 0, sizeof(buf));
--
--		/* Write valid values in the date/time registers */
--		buf[1+DS1337_REG_DAY] = 1;
--		buf[1+DS1337_REG_DATE] = 1;
--		buf[1+DS1337_REG_MONTH] = 1;
--
--		msg[0].addr = client->addr;
--		msg[0].flags = 0;
--		msg[0].len = sizeof(buf);
--		msg[0].buf = &buf[0];
--
--		i2c_transfer(client->adapter, msg, 1);
--	} else {
--		/* Running: ensure that device is set in 24-hour mode */
--		s32 val;
--
--		val = i2c_smbus_read_byte_data(client, DS1337_REG_HOUR);
--		if ((val >= 0) && (val & (1 << 6)))
--			i2c_smbus_write_byte_data(client, DS1337_REG_HOUR,
--						  val & 0x3f);
--	}
--}
--
--static int ds1337_detach_client(struct i2c_client *client)
--{
--	int err;
--	struct ds1337_data *data = i2c_get_clientdata(client);
--
--	if ((err = i2c_detach_client(client)))
--		return err;
--
--	list_del(&data->list);
--	kfree(data);
--	return 0;
--}
--
--static int __init ds1337_init(void)
--{
--	return i2c_add_driver(&ds1337_driver);
--}
--
--static void __exit ds1337_exit(void)
--{
--	i2c_del_driver(&ds1337_driver);
--}
--
--MODULE_AUTHOR("James Chapman <jchapman at katalix.com>");
--MODULE_DESCRIPTION("DS1337 RTC driver");
--MODULE_LICENSE("GPL");
--
--EXPORT_SYMBOL_GPL(ds1337_do_command);
--
--module_init(ds1337_init);
--module_exit(ds1337_exit);
-diff --git a/drivers/i2c/chips/ds1374.c b/drivers/i2c/chips/ds1374.c
-deleted file mode 100644
-index 8a2ff0c..0000000
---- a/drivers/i2c/chips/ds1374.c
-+++ /dev/null
-@@ -1,267 +0,0 @@
--/*
-- * drivers/i2c/chips/ds1374.c
-- *
-- * I2C client/driver for the Maxim/Dallas DS1374 Real-Time Clock
-- *
-- * Author: Randy Vinson <rvinson at mvista.com>
-- *
-- * Based on the m41t00.c by Mark Greer <mgreer at mvista.com>
-- *
-- * 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.
-- */
--/*
-- * This i2c client/driver wedges between the drivers/char/genrtc.c RTC
-- * interface and the SMBus interface of the i2c subsystem.
-- * It would be more efficient to use i2c msgs/i2c_transfer directly but, as
-- * recommened in .../Documentation/i2c/writing-clients section
-- * "Sending and receiving", using SMBus level communication is preferred.
-- */
--
--#include <linux/kernel.h>
--#include <linux/module.h>
--#include <linux/interrupt.h>
--#include <linux/i2c.h>
--#include <linux/rtc.h>
--#include <linux/bcd.h>
--#include <linux/mutex.h>
--#include <linux/workqueue.h>
--
--#define DS1374_REG_TOD0		0x00
--#define DS1374_REG_TOD1		0x01
--#define DS1374_REG_TOD2		0x02
--#define DS1374_REG_TOD3		0x03
--#define DS1374_REG_WDALM0	0x04
--#define DS1374_REG_WDALM1	0x05
--#define DS1374_REG_WDALM2	0x06
--#define DS1374_REG_CR		0x07
--#define DS1374_REG_SR		0x08
--#define DS1374_REG_SR_OSF	0x80
--#define DS1374_REG_TCR		0x09
--
--#define	DS1374_DRV_NAME		"ds1374"
--
--static DEFINE_MUTEX(ds1374_mutex);
+ 	ide_set_handler(drive, cdrom_newpc_intr, rq->timeout, NULL);
+ 	return ide_started;
 -
--static struct i2c_driver ds1374_driver;
--static struct i2c_client *save_client;
+-end_request:
+-	spin_lock_irqsave(&ide_lock, flags);
+-	blkdev_dequeue_request(rq);
+-	end_that_request_last(rq, 1);
+-	HWGROUP(drive)->rq = NULL;
+-	spin_unlock_irqrestore(&ide_lock, flags);
+-	return ide_stopped;
+ }
+ 
+ static ide_startstop_t cdrom_write_intr(ide_drive_t *drive)
+diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c
+index b178190..717e114 100644
+--- a/drivers/ide/ide-disk.c
++++ b/drivers/ide/ide-disk.c
+@@ -129,6 +129,50 @@ static int lba_capacity_is_ok (struct hd_driveid *id)
+ 	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,
++};
++
++static const u8 ide_data_phases[] = {
++	TASKFILE_MULTI_IN,
++	TASKFILE_MULTI_OUT,
++	TASKFILE_IN,
++	TASKFILE_OUT,
++	TASKFILE_IN_DMA,
++	TASKFILE_OUT_DMA,
++};
++
++static void ide_tf_set_cmd(ide_drive_t *drive, ide_task_t *task, u8 dma)
++{
++	u8 index, lba48, write;
++
++	lba48 = (task->tf_flags & IDE_TFLAG_LBA48) ? 2 : 0;
++	write = (task->tf_flags & IDE_TFLAG_WRITE) ? 1 : 0;
++
++	if (dma)
++		index = drive->vdma ? 4 : 8;
++	else
++		index = drive->mult_count ? 0 : 4;
++
++	task->tf.command = ide_rw_cmds[index + lba48 + write];
++
++	if (dma)
++		index = 8; /* fixup index */
++
++	task->data_phase = ide_data_phases[index / 2 + write];
++}
++
+ /*
+  * __ide_do_rw_disk() issues READ and WRITE commands to a disk,
+  * using LBA if supported, or CHS otherwise, to address sectors.
+@@ -137,11 +181,11 @@ static ide_startstop_t __ide_do_rw_disk(ide_drive_t *drive, struct request *rq,
+ {
+ 	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;
+-	task_ioreg_t command	= WIN_NOP;
+-	ata_nsector_t		nsectors;
 -
--static unsigned short ignore[] = { I2C_CLIENT_END };
--static unsigned short normal_addr[] = { 0x68, I2C_CLIENT_END };
+-	nsectors.all		= (u16) rq->nr_sectors;
++	ide_task_t		task;
++	struct ide_taskfile	*tf = &task.tf;
++	ide_startstop_t		rc;
+ 
+ 	if ((hwif->host_flags & IDE_HFLAG_NO_LBA48_DMA) && lba48 && dma) {
+ 		if (block + rq->nr_sectors > 1ULL << 28)
+@@ -155,121 +199,71 @@ static ide_startstop_t __ide_do_rw_disk(ide_drive_t *drive, struct request *rq,
+ 		ide_map_sg(drive, rq);
+ 	}
+ 
+-	if (IDE_CONTROL_REG)
+-		hwif->OUTB(drive->ctl, IDE_CONTROL_REG);
 -
--static struct i2c_client_address_data addr_data = {
--	.normal_i2c = normal_addr,
--	.probe = ignore,
--	.ignore = ignore,
--};
+-	/* FIXME: SELECT_MASK(drive, 0) ? */
++	memset(&task, 0, sizeof(task));
++	task.tf_flags = IDE_TFLAG_NO_SELECT_MASK;  /* FIXME? */
++	task.tf_flags |= (IDE_TFLAG_TF | IDE_TFLAG_DEVICE);
+ 
+ 	if (drive->select.b.lba) {
+ 		if (lba48) {
+-			task_ioreg_t tasklets[10];
 -
--static ulong ds1374_read_rtc(void)
--{
--	ulong time = 0;
--	int reg = DS1374_REG_WDALM0;
+ 			pr_debug("%s: LBA=0x%012llx\n", drive->name,
+ 					(unsigned long long)block);
+ 
+-			tasklets[0] = 0;
+-			tasklets[1] = 0;
+-			tasklets[2] = nsectors.b.low;
+-			tasklets[3] = nsectors.b.high;
+-			tasklets[4] = (task_ioreg_t) block;
+-			tasklets[5] = (task_ioreg_t) (block>>8);
+-			tasklets[6] = (task_ioreg_t) (block>>16);
+-			tasklets[7] = (task_ioreg_t) (block>>24);
+-			if (sizeof(block) == 4) {
+-				tasklets[8] = (task_ioreg_t) 0;
+-				tasklets[9] = (task_ioreg_t) 0;
+-			} else {
+-				tasklets[8] = (task_ioreg_t)((u64)block >> 32);
+-				tasklets[9] = (task_ioreg_t)((u64)block >> 40);
++			tf->hob_nsect = (nsectors >> 8) & 0xff;
++			tf->hob_lbal  = (u8)(block >> 24);
++			if (sizeof(block) != 4) {
++				tf->hob_lbam = (u8)((u64)block >> 32);
++				tf->hob_lbah = (u8)((u64)block >> 40);
+ 			}
+-#ifdef DEBUG
+-			printk("%s: 0x%02x%02x 0x%02x%02x%02x%02x%02x%02x\n",
+-				drive->name, tasklets[3], tasklets[2],
+-				tasklets[9], tasklets[8], tasklets[7],
+-				tasklets[6], tasklets[5], tasklets[4]);
+-#endif
+-			hwif->OUTB(tasklets[1], IDE_FEATURE_REG);
+-			hwif->OUTB(tasklets[3], IDE_NSECTOR_REG);
+-			hwif->OUTB(tasklets[7], IDE_SECTOR_REG);
+-			hwif->OUTB(tasklets[8], IDE_LCYL_REG);
+-			hwif->OUTB(tasklets[9], IDE_HCYL_REG);
 -
--	while (reg--) {
--		s32 tmp;
--		if ((tmp = i2c_smbus_read_byte_data(save_client, reg)) < 0) {
--			dev_warn(&save_client->dev,
--				 "can't read from rtc chip\n");
--			return 0;
+-			hwif->OUTB(tasklets[0], IDE_FEATURE_REG);
+-			hwif->OUTB(tasklets[2], IDE_NSECTOR_REG);
+-			hwif->OUTB(tasklets[4], IDE_SECTOR_REG);
+-			hwif->OUTB(tasklets[5], IDE_LCYL_REG);
+-			hwif->OUTB(tasklets[6], IDE_HCYL_REG);
+-			hwif->OUTB(0x00|drive->select.all,IDE_SELECT_REG);
++
++			tf->nsect  = nsectors & 0xff;
++			tf->lbal   = (u8) block;
++			tf->lbam   = (u8)(block >>  8);
++			tf->lbah   = (u8)(block >> 16);
++
++			task.tf_flags |= (IDE_TFLAG_LBA48 | IDE_TFLAG_HOB);
+ 		} else {
+-			hwif->OUTB(0x00, IDE_FEATURE_REG);
+-			hwif->OUTB(nsectors.b.low, IDE_NSECTOR_REG);
+-			hwif->OUTB(block, IDE_SECTOR_REG);
+-			hwif->OUTB(block>>=8, IDE_LCYL_REG);
+-			hwif->OUTB(block>>=8, IDE_HCYL_REG);
+-			hwif->OUTB(((block>>8)&0x0f)|drive->select.all,IDE_SELECT_REG);
++			tf->nsect  = nsectors & 0xff;
++			tf->lbal   = block;
++			tf->lbam   = block >>= 8;
++			tf->lbah   = block >>= 8;
++			tf->device = (block >> 8) & 0xf;
+ 		}
+ 	} else {
+ 		unsigned int sect,head,cyl,track;
+ 		track = (int)block / drive->sect;
+ 		sect  = (int)block % drive->sect + 1;
+-		hwif->OUTB(sect, IDE_SECTOR_REG);
+ 		head  = track % drive->head;
+ 		cyl   = track / drive->head;
+ 
+ 		pr_debug("%s: CHS=%u/%u/%u\n", drive->name, cyl, head, sect);
+ 
+-		hwif->OUTB(0x00, IDE_FEATURE_REG);
+-		hwif->OUTB(nsectors.b.low, IDE_NSECTOR_REG);
+-		hwif->OUTB(cyl, IDE_LCYL_REG);
+-		hwif->OUTB(cyl>>8, IDE_HCYL_REG);
+-		hwif->OUTB(head|drive->select.all,IDE_SELECT_REG);
++		tf->nsect  = nsectors & 0xff;
++		tf->lbal   = sect;
++		tf->lbam   = cyl;
++		tf->lbah   = cyl >> 8;
++		tf->device = head;
+ 	}
+ 
+-	if (dma) {
+-		if (!hwif->dma_setup(drive)) {
+-			if (rq_data_dir(rq)) {
+-				command = lba48 ? WIN_WRITEDMA_EXT : WIN_WRITEDMA;
+-				if (drive->vdma)
+-					command = lba48 ? WIN_WRITE_EXT: WIN_WRITE;
+-			} else {
+-				command = lba48 ? WIN_READDMA_EXT : WIN_READDMA;
+-				if (drive->vdma)
+-					command = lba48 ? WIN_READ_EXT: WIN_READ;
+-			}
+-			hwif->dma_exec_cmd(drive, command);
+-			hwif->dma_start(drive);
+-			return ide_started;
 -		}
--		time = (time << 8) | (tmp & 0xff);
+-		/* fallback to PIO */
+-		ide_init_sg_cmd(drive, rq);
 -	}
--	return time;
--}
 -
--static void ds1374_write_rtc(ulong time)
--{
--	int reg;
+-	if (rq_data_dir(rq) == READ) {
 -
--	for (reg = DS1374_REG_TOD0; reg < DS1374_REG_WDALM0; reg++) {
--		if (i2c_smbus_write_byte_data(save_client, reg, time & 0xff)
--		    < 0) {
--			dev_warn(&save_client->dev,
--				 "can't write to rtc chip\n");
--			break;
+-		if (drive->mult_count) {
+-			hwif->data_phase = TASKFILE_MULTI_IN;
+-			command = lba48 ? WIN_MULTREAD_EXT : WIN_MULTREAD;
+-		} else {
+-			hwif->data_phase = TASKFILE_IN;
+-			command = lba48 ? WIN_READ_EXT : WIN_READ;
 -		}
--		time = time >> 8;
--	}
--}
--
--static void ds1374_check_rtc_status(void)
--{
--	s32 tmp;
--
--	tmp = i2c_smbus_read_byte_data(save_client, DS1374_REG_SR);
--	if (tmp < 0) {
--		dev_warn(&save_client->dev,
--			 "can't read status from rtc chip\n");
--		return;
--	}
--	if (tmp & DS1374_REG_SR_OSF) {
--		dev_warn(&save_client->dev,
--			 "oscillator discontinuity flagged, time unreliable\n");
--		tmp &= ~DS1374_REG_SR_OSF;
--		tmp = i2c_smbus_write_byte_data(save_client, DS1374_REG_SR,
--						tmp & 0xff);
--		if (tmp < 0)
--			dev_warn(&save_client->dev,
--				 "can't clear discontinuity notification\n");
++	if (rq_data_dir(rq))
++		task.tf_flags |= IDE_TFLAG_WRITE;
+ 
+-		ide_execute_command(drive, command, &task_in_intr, WAIT_CMD, NULL);
+-		return ide_started;
+-	} else {
+-		if (drive->mult_count) {
+-			hwif->data_phase = TASKFILE_MULTI_OUT;
+-			command = lba48 ? WIN_MULTWRITE_EXT : WIN_MULTWRITE;
+-		} else {
+-			hwif->data_phase = TASKFILE_OUT;
+-			command = lba48 ? WIN_WRITE_EXT : WIN_WRITE;
+-		}
++	ide_tf_set_cmd(drive, &task, dma);
++	if (!dma)
++		hwif->data_phase = task.data_phase;
++	task.rq = rq;
+ 
+-		/* FIXME: ->OUTBSYNC ? */
+-		hwif->OUTB(command, IDE_COMMAND_REG);
++	rc = do_rw_taskfile(drive, &task);
+ 
+-		return pre_task_out_intr(drive, rq);
++	if (rc == ide_stopped && dma) {
++		/* fallback to PIO */
++		task.tf_flags |= IDE_TFLAG_DMA_PIO_FALLBACK;
++		ide_tf_set_cmd(drive, &task, 0);
++		hwif->data_phase = task.data_phase;
++		ide_init_sg_cmd(drive, rq);
++		rc = do_rw_taskfile(drive, &task);
+ 	}
++
++	return rc;
+ }
+ 
+ /*
+@@ -307,57 +301,29 @@ static ide_startstop_t ide_do_rw_disk (ide_drive_t *drive, struct request *rq, s
+  * Queries for true maximum capacity of the drive.
+  * Returns maximum LBA address (> 0) of the drive, 0 if failed.
+  */
+-static unsigned long idedisk_read_native_max_address(ide_drive_t *drive)
++static u64 idedisk_read_native_max_address(ide_drive_t *drive, int lba48)
+ {
+ 	ide_task_t args;
+-	unsigned long addr = 0;
++	struct ide_taskfile *tf = &args.tf;
++	u64 addr = 0;
+ 
+ 	/* Create IDE/ATA command request structure */
+ 	memset(&args, 0, sizeof(ide_task_t));
+-	args.tfRegister[IDE_SELECT_OFFSET]	= 0x40;
+-	args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_READ_NATIVE_MAX;
+-	args.command_type			= IDE_DRIVE_TASK_NO_DATA;
+-	args.handler				= &task_no_data_intr;
++	if (lba48)
++		tf->command = WIN_READ_NATIVE_MAX_EXT;
++	else
++		tf->command = WIN_READ_NATIVE_MAX;
++	tf->device  = ATA_LBA;
++	args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
++	if (lba48)
++		args.tf_flags |= (IDE_TFLAG_LBA48 | IDE_TFLAG_HOB);
+ 	/* submit command request */
+-	ide_raw_taskfile(drive, &args, NULL);
++	ide_no_data_taskfile(drive, &args);
+ 
+ 	/* if OK, compute maximum address value */
+-	if ((args.tfRegister[IDE_STATUS_OFFSET] & 0x01) == 0) {
+-		addr = ((args.tfRegister[IDE_SELECT_OFFSET] & 0x0f) << 24)
+-		     | ((args.tfRegister[  IDE_HCYL_OFFSET]       ) << 16)
+-		     | ((args.tfRegister[  IDE_LCYL_OFFSET]       ) <<  8)
+-		     | ((args.tfRegister[IDE_SECTOR_OFFSET]       ));
+-		addr++;	/* since the return value is (maxlba - 1), we add 1 */
 -	}
+-	return addr;
 -}
--
--ulong ds1374_get_rtc_time(void)
++	if ((tf->status & 0x01) == 0)
++		addr = ide_get_lba_addr(tf, lba48) + 1;
+ 
+-static unsigned long long idedisk_read_native_max_address_ext(ide_drive_t *drive)
 -{
--	ulong t1, t2;
--	int limit = 10;		/* arbitrary retry limit */
--
--	mutex_lock(&ds1374_mutex);
+-	ide_task_t args;
+-	unsigned long long addr = 0;
 -
--	/*
--	 * Since the reads are being performed one byte at a time using
--	 * the SMBus vs a 4-byte i2c transfer, there is a chance that a
--	 * carry will occur during the read. To detect this, 2 reads are
--	 * performed and compared.
--	 */
--	do {
--		t1 = ds1374_read_rtc();
--		t2 = ds1374_read_rtc();
--	} while (t1 != t2 && limit--);
+-	/* Create IDE/ATA command request structure */
+-	memset(&args, 0, sizeof(ide_task_t));
 -
--	mutex_unlock(&ds1374_mutex);
+-	args.tfRegister[IDE_SELECT_OFFSET]	= 0x40;
+-	args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_READ_NATIVE_MAX_EXT;
+-	args.command_type			= IDE_DRIVE_TASK_NO_DATA;
+-	args.handler				= &task_no_data_intr;
+-        /* submit command request */
+-        ide_raw_taskfile(drive, &args, NULL);
 -
--	if (t1 != t2) {
--		dev_warn(&save_client->dev,
--			 "can't get consistent time from rtc chip\n");
--		t1 = 0;
+-	/* if OK, compute maximum address value */
+-	if ((args.tfRegister[IDE_STATUS_OFFSET] & 0x01) == 0) {
+-		u32 high = (args.hobRegister[IDE_HCYL_OFFSET] << 16) |
+-			   (args.hobRegister[IDE_LCYL_OFFSET] <<  8) |
+-			    args.hobRegister[IDE_SECTOR_OFFSET];
+-		u32 low  = ((args.tfRegister[IDE_HCYL_OFFSET])<<16) |
+-			   ((args.tfRegister[IDE_LCYL_OFFSET])<<8) |
+-			    (args.tfRegister[IDE_SECTOR_OFFSET]);
+-		addr = ((__u64)high << 24) | low;
+-		addr++;	/* since the return value is (maxlba - 1), we add 1 */
 -	}
--
--	return t1;
--}
--
--static ulong new_time;
--
--static void ds1374_set_work(struct work_struct *work)
--{
--	ulong t1, t2;
--	int limit = 10;		/* arbitrary retry limit */
--
--	t1 = new_time;
--
--	mutex_lock(&ds1374_mutex);
--
--	/*
--	 * Since the writes are being performed one byte at a time using
--	 * the SMBus vs a 4-byte i2c transfer, there is a chance that a
--	 * carry will occur during the write. To detect this, the write
--	 * value is read back and compared.
--	 */
--	do {
--		ds1374_write_rtc(t1);
--		t2 = ds1374_read_rtc();
--	} while (t1 != t2 && limit--);
--
--	mutex_unlock(&ds1374_mutex);
--
--	if (t1 != t2)
--		dev_warn(&save_client->dev,
--			 "can't confirm time set from rtc chip\n");
--}
--
--static struct workqueue_struct *ds1374_workqueue;
--
--static DECLARE_WORK(ds1374_work, ds1374_set_work);
--
--int ds1374_set_rtc_time(ulong nowtime)
--{
--	new_time = nowtime;
--
--	if (in_interrupt())
--		queue_work(ds1374_workqueue, &ds1374_work);
--	else
--		ds1374_set_work(NULL);
--
--	return 0;
--}
--
--/*
-- *****************************************************************************
-- *
-- *	Driver Interface
-- *
-- *****************************************************************************
-- */
--static int ds1374_probe(struct i2c_adapter *adap, int addr, int kind)
+ 	return addr;
+ }
+ 
+@@ -365,67 +331,37 @@ static unsigned long long idedisk_read_native_max_address_ext(ide_drive_t *drive
+  * Sets maximum virtual LBA address of the drive.
+  * Returns new maximum virtual LBA address (> 0) or 0 on failure.
+  */
+-static unsigned long idedisk_set_max_address(ide_drive_t *drive, unsigned long addr_req)
 -{
--	struct i2c_client *client;
--	int rc;
--
--	client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
--	if (!client)
--		return -ENOMEM;
--
--	strncpy(client->name, DS1374_DRV_NAME, I2C_NAME_SIZE);
--	client->addr = addr;
--	client->adapter = adap;
--	client->driver = &ds1374_driver;
--
--	ds1374_workqueue = create_singlethread_workqueue("ds1374");
--	if (!ds1374_workqueue) {
--		kfree(client);
--		return -ENOMEM;	/* most expected reason */
--	}
--
--	if ((rc = i2c_attach_client(client)) != 0) {
--		kfree(client);
--		return rc;
+-	ide_task_t args;
+-	unsigned long addr_set = 0;
+-	
+-	addr_req--;
+-	/* Create IDE/ATA command request structure */
+-	memset(&args, 0, sizeof(ide_task_t));
+-	args.tfRegister[IDE_SECTOR_OFFSET]	= ((addr_req >>  0) & 0xff);
+-	args.tfRegister[IDE_LCYL_OFFSET]	= ((addr_req >>  8) & 0xff);
+-	args.tfRegister[IDE_HCYL_OFFSET]	= ((addr_req >> 16) & 0xff);
+-	args.tfRegister[IDE_SELECT_OFFSET]	= ((addr_req >> 24) & 0x0f) | 0x40;
+-	args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_SET_MAX;
+-	args.command_type			= IDE_DRIVE_TASK_NO_DATA;
+-	args.handler				= &task_no_data_intr;
+-	/* submit command request */
+-	ide_raw_taskfile(drive, &args, NULL);
+-	/* if OK, read new maximum address value */
+-	if ((args.tfRegister[IDE_STATUS_OFFSET] & 0x01) == 0) {
+-		addr_set = ((args.tfRegister[IDE_SELECT_OFFSET] & 0x0f) << 24)
+-			 | ((args.tfRegister[  IDE_HCYL_OFFSET]       ) << 16)
+-			 | ((args.tfRegister[  IDE_LCYL_OFFSET]       ) <<  8)
+-			 | ((args.tfRegister[IDE_SECTOR_OFFSET]       ));
+-		addr_set++;
 -	}
--
--	save_client = client;
--
--	ds1374_check_rtc_status();
--
--	return 0;
--}
--
--static int ds1374_attach(struct i2c_adapter *adap)
--{
--	return i2c_probe(adap, &addr_data, ds1374_probe);
+-	return addr_set;
 -}
 -
--static int ds1374_detach(struct i2c_client *client)
--{
--	int rc;
--
--	if ((rc = i2c_detach_client(client)) == 0) {
--		kfree(i2c_get_clientdata(client));
--		destroy_workqueue(ds1374_workqueue);
+-static unsigned long long idedisk_set_max_address_ext(ide_drive_t *drive, unsigned long long addr_req)
++static u64 idedisk_set_max_address(ide_drive_t *drive, u64 addr_req, int lba48)
+ {
+ 	ide_task_t args;
+-	unsigned long long addr_set = 0;
++	struct ide_taskfile *tf = &args.tf;
++	u64 addr_set = 0;
+ 
+ 	addr_req--;
+ 	/* Create IDE/ATA command request structure */
+ 	memset(&args, 0, sizeof(ide_task_t));
+-	args.tfRegister[IDE_SECTOR_OFFSET]	= ((addr_req >>  0) & 0xff);
+-	args.tfRegister[IDE_LCYL_OFFSET]	= ((addr_req >>= 8) & 0xff);
+-	args.tfRegister[IDE_HCYL_OFFSET]	= ((addr_req >>= 8) & 0xff);
+-	args.tfRegister[IDE_SELECT_OFFSET]      = 0x40;
+-	args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_SET_MAX_EXT;
+-	args.hobRegister[IDE_SECTOR_OFFSET]	= (addr_req >>= 8) & 0xff;
+-	args.hobRegister[IDE_LCYL_OFFSET]	= (addr_req >>= 8) & 0xff;
+-	args.hobRegister[IDE_HCYL_OFFSET]	= (addr_req >>= 8) & 0xff;
+-	args.hobRegister[IDE_SELECT_OFFSET]	= 0x40;
+-	args.hobRegister[IDE_CONTROL_OFFSET_HOB]= (drive->ctl|0x80);
+-	args.command_type			= IDE_DRIVE_TASK_NO_DATA;
+-	args.handler				= &task_no_data_intr;
++	tf->lbal     = (addr_req >>  0) & 0xff;
++	tf->lbam     = (addr_req >>= 8) & 0xff;
++	tf->lbah     = (addr_req >>= 8) & 0xff;
++	if (lba48) {
++		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;
++	} else {
++		tf->device   = (addr_req >>= 8) & 0x0f;
++		tf->command  = WIN_SET_MAX;
++	}
++	tf->device |= ATA_LBA;
++	args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
++	if (lba48)
++		args.tf_flags |= (IDE_TFLAG_LBA48 | IDE_TFLAG_HOB);
+ 	/* submit command request */
+-	ide_raw_taskfile(drive, &args, NULL);
++	ide_no_data_taskfile(drive, &args);
+ 	/* if OK, compute maximum address value */
+-	if ((args.tfRegister[IDE_STATUS_OFFSET] & 0x01) == 0) {
+-		u32 high = (args.hobRegister[IDE_HCYL_OFFSET] << 16) |
+-			   (args.hobRegister[IDE_LCYL_OFFSET] <<  8) |
+-			    args.hobRegister[IDE_SECTOR_OFFSET];
+-		u32 low  = ((args.tfRegister[IDE_HCYL_OFFSET])<<16) |
+-			   ((args.tfRegister[IDE_LCYL_OFFSET])<<8) |
+-			    (args.tfRegister[IDE_SECTOR_OFFSET]);
+-		addr_set = ((__u64)high << 24) | low;
+-		addr_set++;
 -	}
--	return rc;
--}
--
--static struct i2c_driver ds1374_driver = {
--	.driver = {
--		.name	= DS1374_DRV_NAME,
--	},
--	.id = I2C_DRIVERID_DS1374,
--	.attach_adapter = ds1374_attach,
--	.detach_client = ds1374_detach,
--};
--
--static int __init ds1374_init(void)
--{
--	return i2c_add_driver(&ds1374_driver);
--}
--
--static void __exit ds1374_exit(void)
--{
--	i2c_del_driver(&ds1374_driver);
--}
--
--module_init(ds1374_init);
--module_exit(ds1374_exit);
--
--MODULE_AUTHOR("Randy Vinson <rvinson at mvista.com>");
--MODULE_DESCRIPTION("Maxim/Dallas DS1374 RTC I2C Client Driver");
--MODULE_LICENSE("GPL");
-diff --git a/drivers/i2c/chips/eeprom.c b/drivers/i2c/chips/eeprom.c
-index 1a7eeeb..fde297b 100644
---- a/drivers/i2c/chips/eeprom.c
-+++ b/drivers/i2c/chips/eeprom.c
-@@ -35,7 +35,7 @@
- #include <linux/mutex.h>
++	if ((tf->status & 0x01) == 0)
++		addr_set = ide_get_lba_addr(tf, lba48) + 1;
++
+ 	return addr_set;
+ }
  
- /* Addresses to scan */
--static unsigned short normal_i2c[] = { 0x50, 0x51, 0x52, 0x53, 0x54,
-+static const unsigned short normal_i2c[] = { 0x50, 0x51, 0x52, 0x53, 0x54,
- 					0x55, 0x56, 0x57, I2C_CLIENT_END };
+@@ -471,10 +407,8 @@ static void idedisk_check_hpa(ide_drive_t *drive)
+ 	int lba48 = idedisk_supports_lba48(drive->id);
  
- /* Insmod parameters */
-diff --git a/drivers/i2c/chips/isp1301_omap.c b/drivers/i2c/chips/isp1301_omap.c
-index b767603..2a31601 100644
---- a/drivers/i2c/chips/isp1301_omap.c
-+++ b/drivers/i2c/chips/isp1301_omap.c
-@@ -100,7 +100,7 @@ struct isp1301 {
+ 	capacity = drive->capacity64;
+-	if (lba48)
+-		set_max = idedisk_read_native_max_address_ext(drive);
+-	else
+-		set_max = idedisk_read_native_max_address(drive);
++
++	set_max = idedisk_read_native_max_address(drive, lba48);
  
- #if	defined(CONFIG_TPS65010) || defined(CONFIG_TPS65010_MODULE)
+ 	if (ide_in_drive_list(drive->id, hpa_list)) {
+ 		/*
+@@ -495,10 +429,8 @@ static void idedisk_check_hpa(ide_drive_t *drive)
+ 			 capacity, sectors_to_MB(capacity),
+ 			 set_max, sectors_to_MB(set_max));
  
--#include <asm/arch/tps65010.h>
-+#include <linux/i2c/tps65010.h>
+-	if (lba48)
+-		set_max = idedisk_set_max_address_ext(drive, set_max);
+-	else
+-		set_max = idedisk_set_max_address(drive, set_max);
++	set_max = idedisk_set_max_address(drive, set_max, lba48);
++
+ 	if (set_max) {
+ 		drive->capacity64 = set_max;
+ 		printk(KERN_INFO "%s: Host Protected Area disabled.\n",
+@@ -556,32 +488,32 @@ static sector_t idedisk_capacity (ide_drive_t *drive)
+ static int smart_enable(ide_drive_t *drive)
+ {
+ 	ide_task_t args;
++	struct ide_taskfile *tf = &args.tf;
  
- #else
+ 	memset(&args, 0, sizeof(ide_task_t));
+-	args.tfRegister[IDE_FEATURE_OFFSET]	= SMART_ENABLE;
+-	args.tfRegister[IDE_LCYL_OFFSET]	= SMART_LCYL_PASS;
+-	args.tfRegister[IDE_HCYL_OFFSET]	= SMART_HCYL_PASS;
+-	args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_SMART;
+-	args.command_type			= IDE_DRIVE_TASK_NO_DATA;
+-	args.handler				= &task_no_data_intr;
+-	return ide_raw_taskfile(drive, &args, NULL);
++	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);
+ }
  
-@@ -259,12 +259,6 @@ static inline const char *state_name(struct isp1301 *isp)
- 	return state_string(isp->otg.state);
+ 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));
+-	args.tfRegister[IDE_FEATURE_OFFSET]	= sub_cmd;
+-	args.tfRegister[IDE_NSECTOR_OFFSET]	= 0x01;
+-	args.tfRegister[IDE_LCYL_OFFSET]	= SMART_LCYL_PASS;
+-	args.tfRegister[IDE_HCYL_OFFSET]	= SMART_HCYL_PASS;
+-	args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_SMART;
+-	args.command_type			= IDE_DRIVE_TASK_IN;
+-	args.data_phase				= TASKFILE_IN;
+-	args.handler				= &task_in_intr;
++	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);
++	return ide_raw_taskfile(drive, &args, buf, 1);
  }
  
--#ifdef	VERBOSE
--#define	dev_vdbg			dev_dbg
--#else
--#define	dev_vdbg(dev, fmt, arg...)	do{}while(0)
--#endif
--
- /*-------------------------------------------------------------------------*/
+ static int proc_idedisk_read_cache
+@@ -659,19 +591,20 @@ static ide_proc_entry_t idedisk_proc[] = {
+ static void idedisk_prepare_flush(struct request_queue *q, struct request *rq)
+ {
+ 	ide_drive_t *drive = q->queuedata;
++	ide_task_t task;
  
- /* NOTE:  some of this ISP1301 setup is specific to H2 boards;
-diff --git a/drivers/i2c/chips/m41t00.c b/drivers/i2c/chips/m41t00.c
-deleted file mode 100644
-index 3fcb646..0000000
---- a/drivers/i2c/chips/m41t00.c
-+++ /dev/null
-@@ -1,413 +0,0 @@
--/*
-- * I2C client/driver for the ST M41T00 family of i2c rtc chips.
-- *
-- * Author: Mark A. Greer <mgreer at mvista.com>
-- *
-- * 2005, 2006 (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.
-- */
--/*
-- * This i2c client/driver wedges between the drivers/char/genrtc.c RTC
-- * interface and the SMBus interface of the i2c subsystem.
-- */
--
--#include <linux/kernel.h>
--#include <linux/module.h>
--#include <linux/interrupt.h>
--#include <linux/i2c.h>
--#include <linux/rtc.h>
--#include <linux/bcd.h>
--#include <linux/workqueue.h>
--#include <linux/platform_device.h>
--#include <linux/m41t00.h>
--#include <asm/time.h>
--#include <asm/rtc.h>
--
--static struct i2c_driver m41t00_driver;
--static struct i2c_client *save_client;
--
--static unsigned short ignore[] = { I2C_CLIENT_END };
--static unsigned short normal_addr[] = { I2C_CLIENT_END, I2C_CLIENT_END };
--
--static struct i2c_client_address_data addr_data = {
--	.normal_i2c	= normal_addr,
--	.probe		= ignore,
--	.ignore		= ignore,
--};
--
--struct m41t00_chip_info {
--	u8	type;
--	char	*name;
--	u8	read_limit;
--	u8	sec;		/* Offsets for chip regs */
--	u8	min;
--	u8	hour;
--	u8	day;
--	u8	mon;
--	u8	year;
--	u8	alarm_mon;
--	u8	alarm_hour;
--	u8	sqw;
--	u8	sqw_freq;
--};
--
--static struct m41t00_chip_info m41t00_chip_info_tbl[] = {
--	{
--		.type		= M41T00_TYPE_M41T00,
--		.name		= "m41t00",
--		.read_limit	= 5,
--		.sec		= 0,
--		.min		= 1,
--		.hour		= 2,
--		.day		= 4,
--		.mon		= 5,
--		.year		= 6,
--	},
--	{
--		.type		= M41T00_TYPE_M41T81,
--		.name		= "m41t81",
--		.read_limit	= 1,
--		.sec		= 1,
--		.min		= 2,
--		.hour		= 3,
--		.day		= 5,
--		.mon		= 6,
--		.year		= 7,
--		.alarm_mon	= 0xa,
--		.alarm_hour	= 0xc,
--		.sqw		= 0x13,
--	},
--	{
--		.type		= M41T00_TYPE_M41T85,
--		.name		= "m41t85",
--		.read_limit	= 1,
--		.sec		= 1,
--		.min		= 2,
--		.hour		= 3,
--		.day		= 5,
--		.mon		= 6,
--		.year		= 7,
--		.alarm_mon	= 0xa,
--		.alarm_hour	= 0xc,
--		.sqw		= 0x13,
--	},
--};
--static struct m41t00_chip_info *m41t00_chip;
--
--ulong
--m41t00_get_rtc_time(void)
--{
--	s32 sec, min, hour, day, mon, year;
--	s32 sec1, min1, hour1, day1, mon1, year1;
--	u8 reads = 0;
--	u8 buf[8], msgbuf[1] = { 0 }; /* offset into rtc's regs */
--	struct i2c_msg msgs[] = {
--		{
--			.addr	= save_client->addr,
--			.flags	= 0,
--			.len	= 1,
--			.buf	= msgbuf,
--		},
--		{
--			.addr	= save_client->addr,
--			.flags	= I2C_M_RD,
--			.len	= 8,
--			.buf	= buf,
--		},
--	};
--
--	sec = min = hour = day = mon = year = 0;
--
--	do {
--		if (i2c_transfer(save_client->adapter, msgs, 2) < 0)
--			goto read_err;
--
--		sec1 = sec;
--		min1 = min;
--		hour1 = hour;
--		day1 = day;
--		mon1 = mon;
--		year1 = year;
--
--		sec = buf[m41t00_chip->sec] & 0x7f;
--		min = buf[m41t00_chip->min] & 0x7f;
--		hour = buf[m41t00_chip->hour] & 0x3f;
--		day = buf[m41t00_chip->day] & 0x3f;
--		mon = buf[m41t00_chip->mon] & 0x1f;
--		year = buf[m41t00_chip->year];
--	} while ((++reads < m41t00_chip->read_limit) && ((sec != sec1)
--			|| (min != min1) || (hour != hour1) || (day != day1)
--			|| (mon != mon1) || (year != year1)));
--
--	if ((m41t00_chip->read_limit > 1) && ((sec != sec1) || (min != min1)
--			|| (hour != hour1) || (day != day1) || (mon != mon1)
--			|| (year != year1)))
--		goto read_err;
--
--	sec = BCD2BIN(sec);
--	min = BCD2BIN(min);
--	hour = BCD2BIN(hour);
--	day = BCD2BIN(day);
--	mon = BCD2BIN(mon);
--	year = BCD2BIN(year);
+-	memset(rq->cmd, 0, sizeof(rq->cmd));
 -
--	year += 1900;
--	if (year < 1970)
--		year += 100;
++	memset(&task, 0, sizeof(task));
+ 	if (ide_id_has_flush_cache_ext(drive->id) &&
+ 	    (drive->capacity64 >= (1UL << 28)))
+-		rq->cmd[0] = WIN_FLUSH_CACHE_EXT;
++		task.tf.command = WIN_FLUSH_CACHE_EXT;
+ 	else
+-		rq->cmd[0] = WIN_FLUSH_CACHE;
++		task.tf.command = WIN_FLUSH_CACHE;
++	task.tf_flags	= IDE_TFLAG_OUT_TF | IDE_TFLAG_OUT_DEVICE;
++	task.data_phase	= TASKFILE_NO_DATA;
+ 
 -
--	return mktime(year, mon, day, hour, min, sec);
+-	rq->cmd_type = REQ_TYPE_ATA_TASK;
++	rq->cmd_type = REQ_TYPE_ATA_TASKFILE;
+ 	rq->cmd_flags |= REQ_SOFTBARRIER;
+-	rq->buffer = rq->cmd;
++	rq->special = &task;
+ }
+ 
+ /*
+@@ -687,8 +620,10 @@ static int set_multcount(ide_drive_t *drive, int arg)
+ 
+ 	if (drive->special.b.set_multmode)
+ 		return -EBUSY;
++
+ 	ide_init_drive_cmd (&rq);
+-	rq.cmd_type = REQ_TYPE_ATA_CMD;
++	rq.cmd_type = REQ_TYPE_ATA_TASKFILE;
++
+ 	drive->mult_req = arg;
+ 	drive->special.b.set_multmode = 1;
+ 	(void) ide_do_drive_cmd (drive, &rq, ide_wait);
+@@ -753,12 +688,11 @@ static int write_cache(ide_drive_t *drive, int arg)
+ 
+ 	if (ide_id_has_flush_cache(drive->id)) {
+ 		memset(&args, 0, sizeof(ide_task_t));
+-		args.tfRegister[IDE_FEATURE_OFFSET]	= (arg) ?
++		args.tf.feature = arg ?
+ 			SETFEATURES_EN_WCACHE : SETFEATURES_DIS_WCACHE;
+-		args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_SETFEATURES;
+-		args.command_type		= IDE_DRIVE_TASK_NO_DATA;
+-		args.handler			= &task_no_data_intr;
+-		err = ide_raw_taskfile(drive, &args, NULL);
++		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;
+ 	}
+@@ -774,12 +708,11 @@ static int do_idedisk_flushcache (ide_drive_t *drive)
+ 
+ 	memset(&args, 0, sizeof(ide_task_t));
+ 	if (ide_id_has_flush_cache_ext(drive->id))
+-		args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_FLUSH_CACHE_EXT;
++		args.tf.command = WIN_FLUSH_CACHE_EXT;
+ 	else
+-		args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_FLUSH_CACHE;
+-	args.command_type			= IDE_DRIVE_TASK_NO_DATA;
+-	args.handler				= &task_no_data_intr;
+-	return ide_raw_taskfile(drive, &args, NULL);
++		args.tf.command = WIN_FLUSH_CACHE;
++	args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
++	return ide_no_data_taskfile(drive, &args);
+ }
+ 
+ static int set_acoustic (ide_drive_t *drive, int arg)
+@@ -790,13 +723,11 @@ static int set_acoustic (ide_drive_t *drive, int arg)
+ 		return -EINVAL;
+ 
+ 	memset(&args, 0, sizeof(ide_task_t));
+-	args.tfRegister[IDE_FEATURE_OFFSET]	= (arg) ? SETFEATURES_EN_AAM :
+-							  SETFEATURES_DIS_AAM;
+-	args.tfRegister[IDE_NSECTOR_OFFSET]	= arg;
+-	args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_SETFEATURES;
+-	args.command_type = IDE_DRIVE_TASK_NO_DATA;
+-	args.handler	  = &task_no_data_intr;
+-	ide_raw_taskfile(drive, &args, NULL);
++	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);
+ 	drive->acoustic = arg;
+ 	return 0;
+ }
+@@ -832,7 +763,6 @@ static void idedisk_add_settings(ide_drive_t *drive)
+ 	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,	"bswap",	SETTING_READ,	TYPE_BYTE,	0,	1,			1,	1,	&drive->bswap,		NULL);
+ 	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);
+@@ -1041,6 +971,17 @@ static ide_driver_t idedisk_driver = {
+ #endif
+ };
+ 
++static int idedisk_set_doorlock(ide_drive_t *drive, int on)
++{
++	ide_task_t task;
++
++	memset(&task, 0, sizeof(task));
++	task.tf.command = on ? WIN_DOORLOCK : WIN_DOORUNLOCK;
++	task.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
++
++	return ide_no_data_taskfile(drive, &task);
++}
++
+ static int idedisk_open(struct inode *inode, struct file *filp)
+ {
+ 	struct gendisk *disk = inode->i_bdev->bd_disk;
+@@ -1055,18 +996,13 @@ static int idedisk_open(struct inode *inode, struct file *filp)
+ 	idkp->openers++;
+ 
+ 	if (drive->removable && idkp->openers == 1) {
+-		ide_task_t args;
+-		memset(&args, 0, sizeof(ide_task_t));
+-		args.tfRegister[IDE_COMMAND_OFFSET] = WIN_DOORLOCK;
+-		args.command_type = IDE_DRIVE_TASK_NO_DATA;
+-		args.handler	  = &task_no_data_intr;
+ 		check_disk_change(inode->i_bdev);
+ 		/*
+ 		 * Ignore the return code from door_lock,
+ 		 * since the open() has already succeeded,
+ 		 * and the door_lock is irrelevant at this point.
+ 		 */
+-		if (drive->doorlocking && ide_raw_taskfile(drive, &args, NULL))
++		if (drive->doorlocking && idedisk_set_doorlock(drive, 1))
+ 			drive->doorlocking = 0;
+ 	}
+ 	return 0;
+@@ -1082,12 +1018,7 @@ static int idedisk_release(struct inode *inode, struct file *filp)
+ 		ide_cacheflush_p(drive);
+ 
+ 	if (drive->removable && idkp->openers == 1) {
+-		ide_task_t args;
+-		memset(&args, 0, sizeof(ide_task_t));
+-		args.tfRegister[IDE_COMMAND_OFFSET] = WIN_DOORUNLOCK;
+-		args.command_type = IDE_DRIVE_TASK_NO_DATA;
+-		args.handler	  = &task_no_data_intr;
+-		if (drive->doorlocking && ide_raw_taskfile(drive, &args, NULL))
++		if (drive->doorlocking && idedisk_set_doorlock(drive, 0))
+ 			drive->doorlocking = 0;
+ 	}
+ 
+diff --git a/drivers/ide/ide-dma.c b/drivers/ide/ide-dma.c
+index 4703837..5bf3203 100644
+--- a/drivers/ide/ide-dma.c
++++ b/drivers/ide/ide-dma.c
+@@ -153,13 +153,7 @@ ide_startstop_t ide_dma_intr (ide_drive_t *drive)
+ 		if (!dma_stat) {
+ 			struct request *rq = HWGROUP(drive)->rq;
+ 
+-			if (rq->rq_disk) {
+-				ide_driver_t *drv;
 -
--read_err:
--	dev_err(&save_client->dev, "m41t00_get_rtc_time: Read error\n");
--	return 0;
--}
--EXPORT_SYMBOL_GPL(m41t00_get_rtc_time);
+-				drv = *(ide_driver_t **)rq->rq_disk->private_data;
+-				drv->end_request(drive, 1, rq->nr_sectors);
+-			} else
+-				ide_end_request(drive, 1, rq->nr_sectors);
++			task_end_request(drive, rq, stat);
+ 			return ide_stopped;
+ 		}
+ 		printk(KERN_ERR "%s: dma_intr: bad DMA status (dma_stat=%x)\n", 
+@@ -408,23 +402,29 @@ static int dma_timer_expiry (ide_drive_t *drive)
+ }
+ 
+ /**
+- *	ide_dma_host_off	-	Generic DMA kill
++ *	ide_dma_host_set	-	Enable/disable DMA on a host
+  *	@drive: drive to control
+  *
+- *	Perform the generic IDE controller DMA off operation. This
+- *	works for most IDE bus mastering controllers
++ *	Enable/disable DMA on an IDE controller following generic
++ *	bus-mastering IDE controller behaviour.
+  */
+ 
+-void ide_dma_host_off(ide_drive_t *drive)
++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->INB(hwif->dma_status);
+ 
+-	hwif->OUTB((dma_stat & ~(1<<(5+unit))), hwif->dma_status);
++	if (on)
++		dma_stat |= (1 << (5 + unit));
++	else
++		dma_stat &= ~(1 << (5 + unit));
++
++	hwif->OUTB(dma_stat, hwif->dma_status);
+ }
+ 
+-EXPORT_SYMBOL(ide_dma_host_off);
++EXPORT_SYMBOL_GPL(ide_dma_host_set);
++#endif /* CONFIG_BLK_DEV_IDEDMA_PCI */
+ 
+ /**
+  *	ide_dma_off_quietly	-	Generic DMA kill
+@@ -438,11 +438,10 @@ void ide_dma_off_quietly(ide_drive_t *drive)
+ 	drive->using_dma = 0;
+ 	ide_toggle_bounce(drive, 0);
+ 
+-	drive->hwif->dma_host_off(drive);
++	drive->hwif->dma_host_set(drive, 0);
+ }
+ 
+ EXPORT_SYMBOL(ide_dma_off_quietly);
+-#endif /* CONFIG_BLK_DEV_IDEDMA_PCI */
+ 
+ /**
+  *	ide_dma_off	-	disable DMA on a device
+@@ -455,56 +454,29 @@ EXPORT_SYMBOL(ide_dma_off_quietly);
+ void ide_dma_off(ide_drive_t *drive)
+ {
+ 	printk(KERN_INFO "%s: DMA disabled\n", drive->name);
+-	drive->hwif->dma_off_quietly(drive);
++	ide_dma_off_quietly(drive);
+ }
+ 
+ EXPORT_SYMBOL(ide_dma_off);
+ 
+-#ifdef CONFIG_BLK_DEV_IDEDMA_PCI
+ /**
+- *	ide_dma_host_on	-	Enable DMA on a host
+- *	@drive: drive to enable for DMA
+- *
+- *	Enable DMA on an IDE controller following generic bus mastering
+- *	IDE controller behaviour
+- */
 -
--static void
--m41t00_set(void *arg)
+-void ide_dma_host_on(ide_drive_t *drive)
 -{
--	struct rtc_time	tm;
--	int nowtime = *(int *)arg;
--	s32 sec, min, hour, day, mon, year;
--	u8 wbuf[9], *buf = &wbuf[1], msgbuf[1] = { 0 };
--	struct i2c_msg msgs[] = {
--		{
--			.addr	= save_client->addr,
--			.flags	= 0,
--			.len	= 1,
--			.buf	= msgbuf,
--		},
--		{
--			.addr	= save_client->addr,
--			.flags	= I2C_M_RD,
--			.len	= 8,
--			.buf	= buf,
--		},
--	};
--
--	to_tm(nowtime, &tm);
--	tm.tm_year = (tm.tm_year - 1900) % 100;
--
--	sec = BIN2BCD(tm.tm_sec);
--	min = BIN2BCD(tm.tm_min);
--	hour = BIN2BCD(tm.tm_hour);
--	day = BIN2BCD(tm.tm_mday);
--	mon = BIN2BCD(tm.tm_mon);
--	year = BIN2BCD(tm.tm_year);
+-	if (drive->using_dma) {
+-		ide_hwif_t *hwif	= HWIF(drive);
+-		u8 unit			= (drive->select.b.unit & 0x01);
+-		u8 dma_stat		= hwif->INB(hwif->dma_status);
 -
--	/* Read reg values into buf[0..7]/wbuf[1..8] */
--	if (i2c_transfer(save_client->adapter, msgs, 2) < 0) {
--		dev_err(&save_client->dev, "m41t00_set: Read error\n");
--		return;
+-		hwif->OUTB((dma_stat|(1<<(5+unit))), hwif->dma_status);
 -	}
--
--	wbuf[0] = 0; /* offset into rtc's regs */
--	buf[m41t00_chip->sec] = (buf[m41t00_chip->sec] & ~0x7f) | (sec & 0x7f);
--	buf[m41t00_chip->min] = (buf[m41t00_chip->min] & ~0x7f) | (min & 0x7f);
--	buf[m41t00_chip->hour] = (buf[m41t00_chip->hour] & ~0x3f) | (hour& 0x3f);
--	buf[m41t00_chip->day] = (buf[m41t00_chip->day] & ~0x3f) | (day & 0x3f);
--	buf[m41t00_chip->mon] = (buf[m41t00_chip->mon] & ~0x1f) | (mon & 0x1f);
--	buf[m41t00_chip->year] = year;
--
--	if (i2c_master_send(save_client, wbuf, 9) < 0)
--		dev_err(&save_client->dev, "m41t00_set: Write error\n");
--}
--
--static ulong new_time;
--/* well, isn't this API just _lovely_? */
--static void
--m41t00_barf(struct work_struct *unusable)
--{
--	m41t00_set(&new_time);
 -}
 -
--static struct workqueue_struct *m41t00_wq;
--static DECLARE_WORK(m41t00_work, m41t00_barf);
+-EXPORT_SYMBOL(ide_dma_host_on);
 -
--int
--m41t00_set_rtc_time(ulong nowtime)
+-/**
+- *	__ide_dma_on		-	Enable DMA on a device
++ *	ide_dma_on		-	Enable DMA on a device
+  *	@drive: drive to enable DMA on
+  *
+  *	Enable IDE DMA for a device on this IDE controller.
+  */
+- 
+-int __ide_dma_on (ide_drive_t *drive)
 -{
--	new_time = nowtime;
+-	/* consult the list of known "bad" drives */
+-	if (__ide_dma_bad_drive(drive))
+-		return 1;
+ 
++void ide_dma_on(ide_drive_t *drive)
++{
+ 	drive->using_dma = 1;
+ 	ide_toggle_bounce(drive, 1);
+ 
+-	drive->hwif->dma_host_on(drive);
 -
--	if (in_interrupt())
--		queue_work(m41t00_wq, &m41t00_work);
+-	return 0;
++	drive->hwif->dma_host_set(drive, 1);
+ }
+ 
+-EXPORT_SYMBOL(__ide_dma_on);
++EXPORT_SYMBOL(ide_dma_on);
+ 
++#ifdef CONFIG_BLK_DEV_IDEDMA_PCI
+ /**
+  *	ide_dma_setup	-	begin a DMA phase
+  *	@drive: target device
+@@ -759,6 +731,7 @@ EXPORT_SYMBOL_GPL(ide_find_dma_mode);
+ 
+ static int ide_tune_dma(ide_drive_t *drive)
+ {
++	ide_hwif_t *hwif = drive->hwif;
+ 	u8 speed;
+ 
+ 	if (noautodma || drive->nodma || (drive->id->capability & 1) == 0)
+@@ -771,15 +744,21 @@ static int ide_tune_dma(ide_drive_t *drive)
+ 	if (ide_id_dma_bug(drive))
+ 		return 0;
+ 
+-	if (drive->hwif->host_flags & IDE_HFLAG_TRUST_BIOS_FOR_DMA)
++	if (hwif->host_flags & IDE_HFLAG_TRUST_BIOS_FOR_DMA)
+ 		return config_drive_for_dma(drive);
+ 
+ 	speed = ide_max_dma_mode(drive);
+ 
+-	if (!speed)
+-		return 0;
++	if (!speed) {
++		 /* is this really correct/needed? */
++		if ((hwif->host_flags & IDE_HFLAG_CY82C693) &&
++		    ide_dma_good_drive(drive))
++			return 1;
++		else
++			return 0;
++	}
+ 
+-	if (drive->hwif->host_flags & IDE_HFLAG_NO_SET_MODE)
++	if (hwif->host_flags & IDE_HFLAG_NO_SET_MODE)
+ 		return 0;
+ 
+ 	if (ide_set_dma_mode(drive, speed))
+@@ -824,25 +803,23 @@ err_out:
+ 
+ int ide_set_dma(ide_drive_t *drive)
+ {
+-	ide_hwif_t *hwif = drive->hwif;
+ 	int rc;
+ 
++	/*
++	 * Force DMAing for the beginning of the check.
++	 * Some chipsets appear to do interesting
++	 * things, if not checked and cleared.
++	 *   PARANOIA!!!
++	 */
++	ide_dma_off_quietly(drive);
++
+ 	rc = ide_dma_check(drive);
++	if (rc)
++		return rc;
+ 
+-	switch(rc) {
+-	case -1: /* DMA needs to be disabled */
+-		hwif->dma_off_quietly(drive);
+-		return -1;
+-	case  0: /* DMA needs to be enabled */
+-		return hwif->ide_dma_on(drive);
+-	case  1: /* DMA setting cannot be changed */
+-		break;
+-	default:
+-		BUG();
+-		break;
+-	}
++	ide_dma_on(drive);
+ 
+-	return rc;
++	return 0;
+ }
+ 
+ #ifdef CONFIG_BLK_DEV_IDEDMA_PCI
+@@ -968,11 +945,6 @@ void ide_setup_dma(ide_hwif_t *hwif, unsigned long base, unsigned num_ports)
+ 
+ 	hwif->dma_base = base;
+ 
+-	if (hwif->mate)
+-		hwif->dma_master = hwif->channel ? hwif->mate->dma_base : base;
 -	else
--		m41t00_set(&new_time);
+-		hwif->dma_master = base;
 -
--	return 0;
--}
--EXPORT_SYMBOL_GPL(m41t00_set_rtc_time);
+ 	if (!(hwif->dma_command))
+ 		hwif->dma_command	= hwif->dma_base;
+ 	if (!(hwif->dma_vendor1))
+@@ -984,14 +956,8 @@ void ide_setup_dma(ide_hwif_t *hwif, unsigned long base, unsigned num_ports)
+ 	if (!(hwif->dma_prdtable))
+ 		hwif->dma_prdtable	= (hwif->dma_base + 4);
+ 
+-	if (!hwif->dma_off_quietly)
+-		hwif->dma_off_quietly = &ide_dma_off_quietly;
+-	if (!hwif->dma_host_off)
+-		hwif->dma_host_off = &ide_dma_host_off;
+-	if (!hwif->ide_dma_on)
+-		hwif->ide_dma_on = &__ide_dma_on;
+-	if (!hwif->dma_host_on)
+-		hwif->dma_host_on = &ide_dma_host_on;
++	if (!hwif->dma_host_set)
++		hwif->dma_host_set = &ide_dma_host_set;
+ 	if (!hwif->dma_setup)
+ 		hwif->dma_setup = &ide_dma_setup;
+ 	if (!hwif->dma_exec_cmd)
+@@ -1014,8 +980,6 @@ void ide_setup_dma(ide_hwif_t *hwif, unsigned long base, unsigned num_ports)
+ 		       hwif->drives[1].name, (dma_stat & 0x40) ? "DMA" : "pio");
+ 	}
+ 	printk("\n");
 -
+-	BUG_ON(!hwif->dma_master);
+ }
+ 
+ EXPORT_SYMBOL_GPL(ide_setup_dma);
+diff --git a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c
+index 04a3578..ff8232e 100644
+--- a/drivers/ide/ide-floppy.c
++++ b/drivers/ide/ide-floppy.c
+@@ -369,27 +369,6 @@ typedef struct ide_floppy_obj {
+ #define	IDEFLOPPY_IOCTL_FORMAT_START		0x4602
+ #define IDEFLOPPY_IOCTL_FORMAT_GET_PROGRESS	0x4603
+ 
+-#if 0
 -/*
-- *****************************************************************************
-- *
-- *	platform_data Driver Interface
-- *
-- *****************************************************************************
+- *	Special requests for our block device strategy routine.
 - */
--static int __init
--m41t00_platform_probe(struct platform_device *pdev)
--{
--	struct m41t00_platform_data *pdata;
--	int i;
--
--	if (pdev && (pdata = pdev->dev.platform_data)) {
--		normal_addr[0] = pdata->i2c_addr;
--
--		for (i=0; i<ARRAY_SIZE(m41t00_chip_info_tbl); i++)
--			if (m41t00_chip_info_tbl[i].type == pdata->type) {
--				m41t00_chip = &m41t00_chip_info_tbl[i];
--				m41t00_chip->sqw_freq = pdata->sqw_freq;
--				return 0;
--			}
--	}
--	return -ENODEV;
--}
+-#define	IDEFLOPPY_FIRST_RQ	90
 -
--static int __exit
--m41t00_platform_remove(struct platform_device *pdev)
--{
--	return 0;
--}
+-/*
+- * 	IDEFLOPPY_PC_RQ is used to queue a packet command in the request queue.
+- */
+-#define	IDEFLOPPY_PC_RQ		90
 -
--static struct platform_driver m41t00_platform_driver = {
--	.probe  = m41t00_platform_probe,
--	.remove = m41t00_platform_remove,
--	.driver = {
--		.owner = THIS_MODULE,
--		.name  = M41T00_DRV_NAME,
--	},
--};
+-#define IDEFLOPPY_LAST_RQ	90
 -
 -/*
-- *****************************************************************************
-- *
-- *	Driver Interface
-- *
-- *****************************************************************************
+- *	A macro which can be used to check if a given request command
+- *	originated in the driver or in the buffer cache layer.
 - */
--static int
--m41t00_probe(struct i2c_adapter *adap, int addr, int kind)
--{
--	struct i2c_client *client;
--	int rc;
+-#define IDEFLOPPY_RQ_CMD(cmd) 	((cmd >= IDEFLOPPY_FIRST_RQ) && (cmd <= IDEFLOPPY_LAST_RQ))
 -
--	if (!i2c_check_functionality(adap, I2C_FUNC_I2C
--			| I2C_FUNC_SMBUS_BYTE_DATA))
--		return 0;
+-#endif
 -
--	client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
--	if (!client)
--		return -ENOMEM;
+ /*
+  *	Error codes which are returned in rq->errors to the higher part
+  *	of the driver.
+@@ -793,9 +772,8 @@ static void idefloppy_retry_pc (ide_drive_t *drive)
+ {
+ 	idefloppy_pc_t *pc;
+ 	struct request *rq;
+-	atapi_error_t error;
+ 
+-	error.all = HWIF(drive)->INB(IDE_ERROR_REG);
++	(void)drive->hwif->INB(IDE_ERROR_REG);
+ 	pc = idefloppy_next_pc_storage(drive);
+ 	rq = idefloppy_next_rq_storage(drive);
+ 	idefloppy_create_request_sense_cmd(pc);
+@@ -809,12 +787,12 @@ static void idefloppy_retry_pc (ide_drive_t *drive)
+ static ide_startstop_t idefloppy_pc_intr (ide_drive_t *drive)
+ {
+ 	idefloppy_floppy_t *floppy = drive->driver_data;
+-	atapi_status_t status;
+-	atapi_bcount_t bcount;
+-	atapi_ireason_t ireason;
++	ide_hwif_t *hwif = drive->hwif;
+ 	idefloppy_pc_t *pc = floppy->pc;
+ 	struct request *rq = pc->rq;
+ 	unsigned int temp;
++	u16 bcount;
++	u8 stat, ireason;
+ 
+ 	debug_log(KERN_INFO "ide-floppy: Reached %s interrupt handler\n",
+ 		__FUNCTION__);
+@@ -830,16 +808,16 @@ static ide_startstop_t idefloppy_pc_intr (ide_drive_t *drive)
+ 	}
+ 
+ 	/* Clear the interrupt */
+-	status.all = HWIF(drive)->INB(IDE_STATUS_REG);
++	stat = drive->hwif->INB(IDE_STATUS_REG);
+ 
+-	if (!status.b.drq) {			/* No more interrupts */
++	if ((stat & DRQ_STAT) == 0) {		/* No more interrupts */
+ 		debug_log(KERN_INFO "Packet command completed, %d bytes "
+ 			"transferred\n", pc->actually_transferred);
+ 		clear_bit(PC_DMA_IN_PROGRESS, &pc->flags);
+ 
+ 		local_irq_enable_in_hardirq();
+ 
+-		if (status.b.check || test_bit(PC_DMA_ERROR, &pc->flags)) {
++		if ((stat & ERR_STAT) || test_bit(PC_DMA_ERROR, &pc->flags)) {
+ 			/* Error detected */
+ 			debug_log(KERN_INFO "ide-floppy: %s: I/O error\n",
+ 				drive->name);
+@@ -870,32 +848,32 @@ static ide_startstop_t idefloppy_pc_intr (ide_drive_t *drive)
+ 	}
+ 
+ 	/* Get the number of bytes to transfer */
+-	bcount.b.high = HWIF(drive)->INB(IDE_BCOUNTH_REG);
+-	bcount.b.low = HWIF(drive)->INB(IDE_BCOUNTL_REG);
++	bcount = (hwif->INB(IDE_BCOUNTH_REG) << 8) |
++		  hwif->INB(IDE_BCOUNTL_REG);
+ 	/* on this interrupt */
+-	ireason.all = HWIF(drive)->INB(IDE_IREASON_REG);
++	ireason = hwif->INB(IDE_IREASON_REG);
+ 
+-	if (ireason.b.cod) {
++	if (ireason & CD) {
+ 		printk(KERN_ERR "ide-floppy: CoD != 0 in idefloppy_pc_intr\n");
+ 		return ide_do_reset(drive);
+ 	}
+-	if (ireason.b.io == test_bit(PC_WRITING, &pc->flags)) {
++	if (((ireason & IO) == IO) == test_bit(PC_WRITING, &pc->flags)) {
+ 		/* Hopefully, we will never get here */
+ 		printk(KERN_ERR "ide-floppy: We wanted to %s, ",
+-			ireason.b.io ? "Write":"Read");
++				(ireason & IO) ? "Write" : "Read");
+ 		printk(KERN_ERR "but the floppy wants us to %s !\n",
+-			ireason.b.io ? "Read":"Write");
++				(ireason & IO) ? "Read" : "Write");
+ 		return ide_do_reset(drive);
+ 	}
+ 	if (!test_bit(PC_WRITING, &pc->flags)) {
+ 		/* Reading - Check that we have enough space */
+-		temp = pc->actually_transferred + bcount.all;
++		temp = pc->actually_transferred + bcount;
+ 		if (temp > pc->request_transfer) {
+ 			if (temp > pc->buffer_size) {
+ 				printk(KERN_ERR "ide-floppy: The floppy wants "
+ 					"to send us more data than expected "
+ 					"- discarding data\n");
+-				idefloppy_discard_data(drive,bcount.all);
++				idefloppy_discard_data(drive, bcount);
+ 				BUG_ON(HWGROUP(drive)->handler != NULL);
+ 				ide_set_handler(drive,
+ 						&idefloppy_pc_intr,
+@@ -911,23 +889,21 @@ static ide_startstop_t idefloppy_pc_intr (ide_drive_t *drive)
+ 	if (test_bit(PC_WRITING, &pc->flags)) {
+ 		if (pc->buffer != NULL)
+ 			/* Write the current buffer */
+-			HWIF(drive)->atapi_output_bytes(drive,
+-						pc->current_position,
+-						bcount.all);
++			hwif->atapi_output_bytes(drive, pc->current_position,
++						 bcount);
+ 		else
+-			idefloppy_output_buffers(drive, pc, bcount.all);
++			idefloppy_output_buffers(drive, pc, bcount);
+ 	} else {
+ 		if (pc->buffer != NULL)
+ 			/* Read the current buffer */
+-			HWIF(drive)->atapi_input_bytes(drive,
+-						pc->current_position,
+-						bcount.all);
++			hwif->atapi_input_bytes(drive, pc->current_position,
++						bcount);
+ 		else
+-			idefloppy_input_buffers(drive, pc, bcount.all);
++			idefloppy_input_buffers(drive, pc, bcount);
+ 	}
+ 	/* Update the current position */
+-	pc->actually_transferred += bcount.all;
+-	pc->current_position += bcount.all;
++	pc->actually_transferred += bcount;
++	pc->current_position += bcount;
+ 
+ 	BUG_ON(HWGROUP(drive)->handler != NULL);
+ 	ide_set_handler(drive, &idefloppy_pc_intr, IDEFLOPPY_WAIT_CMD, NULL);		/* And set the interrupt handler again */
+@@ -943,15 +919,15 @@ static ide_startstop_t idefloppy_transfer_pc (ide_drive_t *drive)
+ {
+ 	ide_startstop_t startstop;
+ 	idefloppy_floppy_t *floppy = drive->driver_data;
+-	atapi_ireason_t ireason;
++	u8 ireason;
+ 
+ 	if (ide_wait_stat(&startstop, drive, DRQ_STAT, BUSY_STAT, WAIT_READY)) {
+ 		printk(KERN_ERR "ide-floppy: Strange, packet command "
+ 				"initiated yet DRQ isn't asserted\n");
+ 		return startstop;
+ 	}
+-	ireason.all = HWIF(drive)->INB(IDE_IREASON_REG);
+-	if (!ireason.b.cod || ireason.b.io) {
++	ireason = drive->hwif->INB(IDE_IREASON_REG);
++	if ((ireason & CD) == 0 || (ireason & IO)) {
+ 		printk(KERN_ERR "ide-floppy: (IO,CoD) != (0,1) while "
+ 				"issuing a packet command\n");
+ 		return ide_do_reset(drive);
+@@ -991,15 +967,15 @@ static ide_startstop_t idefloppy_transfer_pc1 (ide_drive_t *drive)
+ {
+ 	idefloppy_floppy_t *floppy = drive->driver_data;
+ 	ide_startstop_t startstop;
+-	atapi_ireason_t ireason;
++	u8 ireason;
+ 
+ 	if (ide_wait_stat(&startstop, drive, DRQ_STAT, BUSY_STAT, WAIT_READY)) {
+ 		printk(KERN_ERR "ide-floppy: Strange, packet command "
+ 				"initiated yet DRQ isn't asserted\n");
+ 		return startstop;
+ 	}
+-	ireason.all = HWIF(drive)->INB(IDE_IREASON_REG);
+-	if (!ireason.b.cod || ireason.b.io) {
++	ireason = drive->hwif->INB(IDE_IREASON_REG);
++	if ((ireason & CD) == 0 || (ireason & IO)) {
+ 		printk(KERN_ERR "ide-floppy: (IO,CoD) != (0,1) "
+ 				"while issuing a packet command\n");
+ 		return ide_do_reset(drive);
+@@ -1041,21 +1017,9 @@ static ide_startstop_t idefloppy_issue_pc (ide_drive_t *drive, idefloppy_pc_t *p
+ {
+ 	idefloppy_floppy_t *floppy = drive->driver_data;
+ 	ide_hwif_t *hwif = drive->hwif;
+-	atapi_feature_t feature;
+-	atapi_bcount_t bcount;
+ 	ide_handler_t *pkt_xfer_routine;
 -
--	strlcpy(client->name, m41t00_chip->name, I2C_NAME_SIZE);
--	client->addr = addr;
--	client->adapter = adap;
--	client->driver = &m41t00_driver;
+-#if 0 /* Accessing floppy->pc is not valid here, the previous pc may be gone
+-         and have lived on another thread's stack; that stack may have become
+-         unmapped meanwhile (CONFIG_DEBUG_PAGEALLOC). */
+-#if IDEFLOPPY_DEBUG_BUGS
+-	if (floppy->pc->c[0] == IDEFLOPPY_REQUEST_SENSE_CMD &&
+-	    pc->c[0] == IDEFLOPPY_REQUEST_SENSE_CMD) {
+-		printk(KERN_ERR "ide-floppy: possible ide-floppy.c bug - "
+-			"Two request sense in serial were issued\n");
+-	}
+-#endif /* IDEFLOPPY_DEBUG_BUGS */
+-#endif
++	u16 bcount;
++	u8 dma;
+ 
+ 	if (floppy->failed_pc == NULL &&
+ 	    pc->c[0] != IDEFLOPPY_REQUEST_SENSE_CMD)
+@@ -1093,25 +1057,20 @@ static ide_startstop_t idefloppy_issue_pc (ide_drive_t *drive, idefloppy_pc_t *p
+ 	/* We haven't transferred any data yet */
+ 	pc->actually_transferred = 0;
+ 	pc->current_position = pc->buffer;
+-	bcount.all = min(pc->request_transfer, 63 * 1024);
++	bcount = min(pc->request_transfer, 63 * 1024);
+ 
+ 	if (test_and_clear_bit(PC_DMA_ERROR, &pc->flags))
+ 		ide_dma_off(drive);
+ 
+-	feature.all = 0;
++	dma = 0;
+ 
+ 	if (test_bit(PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma)
+-		feature.b.dma = !hwif->dma_setup(drive);
++		dma = !hwif->dma_setup(drive);
+ 
+-	if (IDE_CONTROL_REG)
+-		HWIF(drive)->OUTB(drive->ctl, IDE_CONTROL_REG);
+-	/* Use PIO/DMA */
+-	HWIF(drive)->OUTB(feature.all, IDE_FEATURE_REG);
+-	HWIF(drive)->OUTB(bcount.b.high, IDE_BCOUNTH_REG);
+-	HWIF(drive)->OUTB(bcount.b.low, IDE_BCOUNTL_REG);
+-	HWIF(drive)->OUTB(drive->select.all, IDE_SELECT_REG);
++	ide_pktcmd_tf_load(drive, IDE_TFLAG_NO_SELECT_MASK |
++			   IDE_TFLAG_OUT_DEVICE, bcount, dma);
+ 
+-	if (feature.b.dma) {	/* Begin DMA, if necessary */
++	if (dma) {	/* Begin DMA, if necessary */
+ 		set_bit(PC_DMA_IN_PROGRESS, &pc->flags);
+ 		hwif->dma_start(drive);
+ 	}
+@@ -1665,14 +1624,14 @@ static int idefloppy_get_format_progress(ide_drive_t *drive, int __user *arg)
+ 		/* Else assume format_unit has finished, and we're
+ 		** at 0x10000 */
+ 	} else {
+-		atapi_status_t status;
+ 		unsigned long flags;
++		u8 stat;
+ 
+ 		local_irq_save(flags);
+-		status.all = HWIF(drive)->INB(IDE_STATUS_REG);
++		stat = drive->hwif->INB(IDE_STATUS_REG);
+ 		local_irq_restore(flags);
+ 
+-		progress_indication = !status.b.dsc ? 0 : 0x10000;
++		progress_indication = ((stat & SEEK_STAT) == 0) ? 0 : 0x10000;
+ 	}
+ 	if (put_user(progress_indication, arg))
+ 		return (-EFAULT);
+diff --git a/drivers/ide/ide-generic.c b/drivers/ide/ide-generic.c
+index 0f72b98..bb30c29 100644
+--- a/drivers/ide/ide-generic.c
++++ b/drivers/ide/ide-generic.c
+@@ -14,10 +14,16 @@
+ 
+ static int __init ide_generic_init(void)
+ {
++	u8 idx[MAX_HWIFS];
++	int i;
++
+ 	if (ide_hwifs[0].io_ports[IDE_DATA_OFFSET])
+ 		ide_get_lock(NULL, NULL); /* for atari only */
+ 
+-	(void)ideprobe_init();
++	for (i = 0; i < MAX_HWIFS; i++)
++		idx[i] = ide_hwifs[i].present ? 0xff : i;
++
++	ide_device_add_all(idx);
+ 
+ 	if (ide_hwifs[0].io_ports[IDE_DATA_OFFSET])
+ 		ide_release_lock();	/* for atari only */
+diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c
+index bef781f..e6bb9cf 100644
+--- a/drivers/ide/ide-io.c
++++ b/drivers/ide/ide-io.c
+@@ -58,15 +58,19 @@ static int __ide_end_request(ide_drive_t *drive, struct request *rq,
+ 			     int uptodate, unsigned int nr_bytes, int dequeue)
+ {
+ 	int ret = 1;
++	int error = 0;
++
++	if (uptodate <= 0)
++		error = uptodate ? uptodate : -EIO;
+ 
+ 	/*
+ 	 * if failfast is set on a request, override number of sectors and
+ 	 * complete the whole request right now
+ 	 */
+-	if (blk_noretry_request(rq) && end_io_error(uptodate))
++	if (blk_noretry_request(rq) && error)
+ 		nr_bytes = rq->hard_nr_sectors << 9;
+ 
+-	if (!blk_fs_request(rq) && end_io_error(uptodate) && !rq->errors)
++	if (!blk_fs_request(rq) && error && !rq->errors)
+ 		rq->errors = -EIO;
+ 
+ 	/*
+@@ -75,17 +79,12 @@ static int __ide_end_request(ide_drive_t *drive, struct request *rq,
+ 	 */
+ 	if (drive->state == DMA_PIO_RETRY && drive->retry_pio <= 3) {
+ 		drive->state = 0;
+-		HWGROUP(drive)->hwif->ide_dma_on(drive);
++		ide_dma_on(drive);
+ 	}
+ 
+-	if (!end_that_request_chunk(rq, uptodate, nr_bytes)) {
+-		add_disk_randomness(rq->rq_disk);
+-		if (dequeue) {
+-			if (!list_empty(&rq->queuelist))
+-				blkdev_dequeue_request(rq);
++	if (!__blk_end_request(rq, error, nr_bytes)) {
++		if (dequeue)
+ 			HWGROUP(drive)->rq = NULL;
+-		}
+-		end_that_request_last(rq, uptodate);
+ 		ret = 0;
+ 	}
+ 
+@@ -189,18 +188,14 @@ static ide_startstop_t ide_start_power_step(ide_drive_t *drive, struct request *
+ 			return ide_stopped;
+ 		}
+ 		if (ide_id_has_flush_cache_ext(drive->id))
+-			args->tfRegister[IDE_COMMAND_OFFSET] = WIN_FLUSH_CACHE_EXT;
++			args->tf.command = WIN_FLUSH_CACHE_EXT;
+ 		else
+-			args->tfRegister[IDE_COMMAND_OFFSET] = WIN_FLUSH_CACHE;
+-		args->command_type = IDE_DRIVE_TASK_NO_DATA;
+-		args->handler	   = &task_no_data_intr;
+-		return do_rw_taskfile(drive, args);
++			args->tf.command = WIN_FLUSH_CACHE;
++		goto out_do_tf;
+ 
+ 	case idedisk_pm_standby:	/* Suspend step 2 (standby) */
+-		args->tfRegister[IDE_COMMAND_OFFSET] = WIN_STANDBYNOW1;
+-		args->command_type = IDE_DRIVE_TASK_NO_DATA;
+-		args->handler	   = &task_no_data_intr;
+-		return do_rw_taskfile(drive, args);
++		args->tf.command = WIN_STANDBYNOW1;
++		goto out_do_tf;
+ 
+ 	case idedisk_pm_restore_pio:	/* Resume step 1 (restore PIO) */
+ 		ide_set_max_pio(drive);
+@@ -214,10 +209,8 @@ static ide_startstop_t ide_start_power_step(ide_drive_t *drive, struct request *
+ 		return ide_stopped;
+ 
+ 	case idedisk_pm_idle:		/* Resume step 2 (idle) */
+-		args->tfRegister[IDE_COMMAND_OFFSET] = WIN_IDLEIMMEDIATE;
+-		args->command_type = IDE_DRIVE_TASK_NO_DATA;
+-		args->handler = task_no_data_intr;
+-		return do_rw_taskfile(drive, args);
++		args->tf.command = WIN_IDLEIMMEDIATE;
++		goto out_do_tf;
+ 
+ 	case ide_pm_restore_dma:	/* Resume step 3 (restore DMA) */
+ 		/*
+@@ -225,9 +218,8 @@ static ide_startstop_t ide_start_power_step(ide_drive_t *drive, struct request *
+ 		 * we could be smarter and check for current xfer_speed
+ 		 * in struct drive etc...
+ 		 */
+-		if (drive->hwif->ide_dma_on == NULL)
++		if (drive->hwif->dma_host_set == NULL)
+ 			break;
+-		drive->hwif->dma_off_quietly(drive);
+ 		/*
+ 		 * TODO: respect ->using_dma setting
+ 		 */
+@@ -236,6 +228,11 @@ static ide_startstop_t ide_start_power_step(ide_drive_t *drive, struct request *
+ 	}
+ 	pm->pm_step = ide_pm_state_completed;
+ 	return ide_stopped;
++
++out_do_tf:
++	args->tf_flags	 = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
++	args->data_phase = TASKFILE_NO_DATA;
++	return do_rw_taskfile(drive, args);
+ }
+ 
+ /**
+@@ -292,12 +289,54 @@ static void ide_complete_pm_request (ide_drive_t *drive, struct request *rq)
+ 		drive->blocked = 0;
+ 		blk_start_queue(drive->queue);
+ 	}
+-	blkdev_dequeue_request(rq);
+ 	HWGROUP(drive)->rq = NULL;
+-	end_that_request_last(rq, 1);
++	if (__blk_end_request(rq, 0, 0))
++		BUG();
+ 	spin_unlock_irqrestore(&ide_lock, flags);
+ }
+ 
++void ide_tf_read(ide_drive_t *drive, ide_task_t *task)
++{
++	ide_hwif_t *hwif = drive->hwif;
++	struct ide_taskfile *tf = &task->tf;
++
++	if (task->tf_flags & IDE_TFLAG_IN_DATA) {
++		u16 data = hwif->INW(IDE_DATA_REG);
++
++		tf->data = data & 0xff;
++		tf->hob_data = (data >> 8) & 0xff;
++	}
++
++	/* be sure we're looking at the low order bits */
++	hwif->OUTB(drive->ctl & ~0x80, IDE_CONTROL_REG);
++
++	if (task->tf_flags & IDE_TFLAG_IN_NSECT)
++		tf->nsect  = hwif->INB(IDE_NSECTOR_REG);
++	if (task->tf_flags & IDE_TFLAG_IN_LBAL)
++		tf->lbal   = hwif->INB(IDE_SECTOR_REG);
++	if (task->tf_flags & IDE_TFLAG_IN_LBAM)
++		tf->lbam   = hwif->INB(IDE_LCYL_REG);
++	if (task->tf_flags & IDE_TFLAG_IN_LBAH)
++		tf->lbah   = hwif->INB(IDE_HCYL_REG);
++	if (task->tf_flags & IDE_TFLAG_IN_DEVICE)
++		tf->device = hwif->INB(IDE_SELECT_REG);
++
++	if (task->tf_flags & IDE_TFLAG_LBA48) {
++		hwif->OUTB(drive->ctl | 0x80, IDE_CONTROL_REG);
++
++		if (task->tf_flags & IDE_TFLAG_IN_HOB_FEATURE)
++			tf->hob_feature = hwif->INB(IDE_FEATURE_REG);
++		if (task->tf_flags & IDE_TFLAG_IN_HOB_NSECT)
++			tf->hob_nsect   = hwif->INB(IDE_NSECTOR_REG);
++		if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAL)
++			tf->hob_lbal    = hwif->INB(IDE_SECTOR_REG);
++		if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAM)
++			tf->hob_lbam    = hwif->INB(IDE_LCYL_REG);
++		if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAH)
++			tf->hob_lbah    = hwif->INB(IDE_HCYL_REG);
++	}
++}
++
+ /**
+  *	ide_end_drive_cmd	-	end an explicit drive command
+  *	@drive: command 
+@@ -314,7 +353,6 @@ static void ide_complete_pm_request (ide_drive_t *drive, struct request *rq)
+  
+ void ide_end_drive_cmd (ide_drive_t *drive, u8 stat, u8 err)
+ {
+-	ide_hwif_t *hwif = HWIF(drive);
+ 	unsigned long flags;
+ 	struct request *rq;
+ 
+@@ -322,61 +360,18 @@ void ide_end_drive_cmd (ide_drive_t *drive, u8 stat, u8 err)
+ 	rq = HWGROUP(drive)->rq;
+ 	spin_unlock_irqrestore(&ide_lock, flags);
+ 
+-	if (rq->cmd_type == REQ_TYPE_ATA_CMD) {
+-		u8 *args = (u8 *) rq->buffer;
+-		if (rq->errors == 0)
+-			rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT);
 -
--	if ((rc = i2c_attach_client(client)))
--		goto attach_err;
+-		if (args) {
+-			args[0] = stat;
+-			args[1] = err;
+-			args[2] = hwif->INB(IDE_NSECTOR_REG);
+-		}
+-	} else if (rq->cmd_type == REQ_TYPE_ATA_TASK) {
+-		u8 *args = (u8 *) rq->buffer;
+-		if (rq->errors == 0)
+-			rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT);
 -
--	if (m41t00_chip->type != M41T00_TYPE_M41T00) {
--		/* If asked, disable SQW, set SQW frequency & re-enable */
--		if (m41t00_chip->sqw_freq)
--			if (((rc = i2c_smbus_read_byte_data(client,
--					m41t00_chip->alarm_mon)) < 0)
--			 || ((rc = i2c_smbus_write_byte_data(client,
--					m41t00_chip->alarm_mon, rc & ~0x40)) <0)
--			 || ((rc = i2c_smbus_write_byte_data(client,
--					m41t00_chip->sqw,
--					m41t00_chip->sqw_freq)) < 0)
--			 || ((rc = i2c_smbus_write_byte_data(client,
--					m41t00_chip->alarm_mon, rc | 0x40)) <0))
--				goto sqw_err;
+-		if (args) {
+-			args[0] = stat;
+-			args[1] = err;
+-			/* be sure we're looking at the low order bits */
+-			hwif->OUTB(drive->ctl & ~0x80, IDE_CONTROL_REG);
+-			args[2] = hwif->INB(IDE_NSECTOR_REG);
+-			args[3] = hwif->INB(IDE_SECTOR_REG);
+-			args[4] = hwif->INB(IDE_LCYL_REG);
+-			args[5] = hwif->INB(IDE_HCYL_REG);
+-			args[6] = hwif->INB(IDE_SELECT_REG);
+-		}
+-	} else if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) {
++	if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) {
+ 		ide_task_t *args = (ide_task_t *) rq->special;
+ 		if (rq->errors == 0)
+ 			rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT);
+ 			
+ 		if (args) {
+-			if (args->tf_in_flags.b.data) {
+-				u16 data				= hwif->INW(IDE_DATA_REG);
+-				args->tfRegister[IDE_DATA_OFFSET]	= (data) & 0xFF;
+-				args->hobRegister[IDE_DATA_OFFSET]	= (data >> 8) & 0xFF;
+-			}
+-			args->tfRegister[IDE_ERROR_OFFSET]   = err;
+-			/* be sure we're looking at the low order bits */
+-			hwif->OUTB(drive->ctl & ~0x80, IDE_CONTROL_REG);
+-			args->tfRegister[IDE_NSECTOR_OFFSET] = hwif->INB(IDE_NSECTOR_REG);
+-			args->tfRegister[IDE_SECTOR_OFFSET]  = hwif->INB(IDE_SECTOR_REG);
+-			args->tfRegister[IDE_LCYL_OFFSET]    = hwif->INB(IDE_LCYL_REG);
+-			args->tfRegister[IDE_HCYL_OFFSET]    = hwif->INB(IDE_HCYL_REG);
+-			args->tfRegister[IDE_SELECT_OFFSET]  = hwif->INB(IDE_SELECT_REG);
+-			args->tfRegister[IDE_STATUS_OFFSET]  = stat;
 -
--		/* Make sure HT (Halt Update) bit is cleared */
--		if ((rc = i2c_smbus_read_byte_data(client,
--				m41t00_chip->alarm_hour)) < 0)
--			goto ht_err;
+-			if (drive->addressing == 1) {
+-				hwif->OUTB(drive->ctl|0x80, IDE_CONTROL_REG);
+-				args->hobRegister[IDE_FEATURE_OFFSET]	= hwif->INB(IDE_FEATURE_REG);
+-				args->hobRegister[IDE_NSECTOR_OFFSET]	= hwif->INB(IDE_NSECTOR_REG);
+-				args->hobRegister[IDE_SECTOR_OFFSET]	= hwif->INB(IDE_SECTOR_REG);
+-				args->hobRegister[IDE_LCYL_OFFSET]	= hwif->INB(IDE_LCYL_REG);
+-				args->hobRegister[IDE_HCYL_OFFSET]	= hwif->INB(IDE_HCYL_REG);
+-			}
++			struct ide_taskfile *tf = &args->tf;
++
++			tf->error = err;
++			tf->status = stat;
++
++			ide_tf_read(drive, args);
+ 		}
+ 	} else if (blk_pm_request(rq)) {
+ 		struct request_pm_state *pm = rq->data;
+@@ -391,10 +386,10 @@ void ide_end_drive_cmd (ide_drive_t *drive, u8 stat, u8 err)
+ 	}
+ 
+ 	spin_lock_irqsave(&ide_lock, flags);
+-	blkdev_dequeue_request(rq);
+ 	HWGROUP(drive)->rq = NULL;
+ 	rq->errors = err;
+-	end_that_request_last(rq, !rq->errors);
++	if (__blk_end_request(rq, (rq->errors ? -EIO : 0), 0))
++		BUG();
+ 	spin_unlock_irqrestore(&ide_lock, flags);
+ }
+ 
+@@ -615,90 +610,26 @@ ide_startstop_t ide_abort(ide_drive_t *drive, const char *msg)
+ 		return __ide_abort(drive, rq);
+ }
+ 
+-/**
+- *	ide_cmd		-	issue a simple drive command
+- *	@drive: drive the command is for
+- *	@cmd: command byte
+- *	@nsect: sector byte
+- *	@handler: handler for the command completion
+- *
+- *	Issue a simple drive command with interrupts.
+- *	The drive must be selected beforehand.
+- */
 -
--		if (rc & 0x40)
--			if ((rc = i2c_smbus_write_byte_data(client,
--					m41t00_chip->alarm_hour, rc & ~0x40))<0)
--				goto ht_err;
+-static void ide_cmd (ide_drive_t *drive, u8 cmd, u8 nsect,
+-		ide_handler_t *handler)
++static void ide_tf_set_specify_cmd(ide_drive_t *drive, struct ide_taskfile *tf)
+ {
+-	ide_hwif_t *hwif = HWIF(drive);
+-	if (IDE_CONTROL_REG)
+-		hwif->OUTB(drive->ctl,IDE_CONTROL_REG);	/* clear nIEN */
+-	SELECT_MASK(drive,0);
+-	hwif->OUTB(nsect,IDE_NSECTOR_REG);
+-	ide_execute_command(drive, cmd, handler, WAIT_CMD, NULL);
++	tf->nsect   = drive->sect;
++	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;
+ }
+ 
+-/**
+- *	drive_cmd_intr		- 	drive command completion interrupt
+- *	@drive: drive the completion interrupt occurred on
+- *
+- *	drive_cmd_intr() is invoked on completion of a special DRIVE_CMD.
+- *	We do any necessary data reading and then wait for the drive to
+- *	go non busy. At that point we may read the error data and complete
+- *	the request
+- */
+- 
+-static ide_startstop_t drive_cmd_intr (ide_drive_t *drive)
++static void ide_tf_set_restore_cmd(ide_drive_t *drive, struct ide_taskfile *tf)
+ {
+-	struct request *rq = HWGROUP(drive)->rq;
+-	ide_hwif_t *hwif = HWIF(drive);
+-	u8 *args = (u8 *) rq->buffer;
+-	u8 stat = hwif->INB(IDE_STATUS_REG);
+-	int retries = 10;
+-
+-	local_irq_enable_in_hardirq();
+-	if (rq->cmd_type == REQ_TYPE_ATA_CMD &&
+-	    (stat & DRQ_STAT) && args && args[3]) {
+-		u8 io_32bit = drive->io_32bit;
+-		drive->io_32bit = 0;
+-		hwif->ata_input_data(drive, &args[4], args[3] * SECTOR_WORDS);
+-		drive->io_32bit = io_32bit;
+-		while (((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) && retries--)
+-			udelay(100);
 -	}
 -
--	/* Make sure ST (stop) bit is cleared */
--	if ((rc = i2c_smbus_read_byte_data(client, m41t00_chip->sec)) < 0)
--		goto st_err;
+-	if (!OK_STAT(stat, READY_STAT, BAD_STAT))
+-		return ide_error(drive, "drive_cmd", stat);
+-		/* calls ide_end_drive_cmd */
+-	ide_end_drive_cmd(drive, stat, hwif->INB(IDE_ERROR_REG));
+-	return ide_stopped;
++	tf->nsect   = drive->sect;
++	tf->command = WIN_RESTORE;
+ }
+ 
+-static void ide_init_specify_cmd(ide_drive_t *drive, ide_task_t *task)
++static void ide_tf_set_setmult_cmd(ide_drive_t *drive, struct ide_taskfile *tf)
+ {
+-	task->tfRegister[IDE_NSECTOR_OFFSET] = drive->sect;
+-	task->tfRegister[IDE_SECTOR_OFFSET]  = drive->sect;
+-	task->tfRegister[IDE_LCYL_OFFSET]    = drive->cyl;
+-	task->tfRegister[IDE_HCYL_OFFSET]    = drive->cyl>>8;
+-	task->tfRegister[IDE_SELECT_OFFSET]  = ((drive->head-1)|drive->select.all)&0xBF;
+-	task->tfRegister[IDE_COMMAND_OFFSET] = WIN_SPECIFY;
 -
--	if (rc & 0x80)
--		if ((rc = i2c_smbus_write_byte_data(client, m41t00_chip->sec,
--				rc & ~0x80)) < 0)
--			goto st_err;
+-	task->handler = &set_geometry_intr;
+-}
 -
--	m41t00_wq = create_singlethread_workqueue(m41t00_chip->name);
--	save_client = client;
--	return 0;
+-static void ide_init_restore_cmd(ide_drive_t *drive, ide_task_t *task)
+-{
+-	task->tfRegister[IDE_NSECTOR_OFFSET] = drive->sect;
+-	task->tfRegister[IDE_COMMAND_OFFSET] = WIN_RESTORE;
 -
--st_err:
--	dev_err(&client->dev, "m41t00_probe: Can't clear ST bit\n");
--	goto attach_err;
--ht_err:
--	dev_err(&client->dev, "m41t00_probe: Can't clear HT bit\n");
--	goto attach_err;
--sqw_err:
--	dev_err(&client->dev, "m41t00_probe: Can't set SQW Frequency\n");
--attach_err:
--	kfree(client);
--	return rc;
+-	task->handler = &recal_intr;
 -}
 -
--static int
--m41t00_attach(struct i2c_adapter *adap)
+-static void ide_init_setmult_cmd(ide_drive_t *drive, ide_task_t *task)
 -{
--	return i2c_probe(adap, &addr_data, m41t00_probe);
--}
+-	task->tfRegister[IDE_NSECTOR_OFFSET] = drive->mult_req;
+-	task->tfRegister[IDE_COMMAND_OFFSET] = WIN_SETMULT;
+-
+-	task->handler = &set_multmode_intr;
++	tf->nsect   = drive->mult_req;
++	tf->command = WIN_SETMULT;
+ }
+ 
+ static ide_startstop_t ide_disk_special(ide_drive_t *drive)
+@@ -707,19 +638,19 @@ static ide_startstop_t ide_disk_special(ide_drive_t *drive)
+ 	ide_task_t args;
+ 
+ 	memset(&args, 0, sizeof(ide_task_t));
+-	args.command_type = IDE_DRIVE_TASK_NO_DATA;
++	args.data_phase = TASKFILE_NO_DATA;
+ 
+ 	if (s->b.set_geometry) {
+ 		s->b.set_geometry = 0;
+-		ide_init_specify_cmd(drive, &args);
++		ide_tf_set_specify_cmd(drive, &args.tf);
+ 	} else if (s->b.recalibrate) {
+ 		s->b.recalibrate = 0;
+-		ide_init_restore_cmd(drive, &args);
++		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_init_setmult_cmd(drive, &args);
++		ide_tf_set_setmult_cmd(drive, &args.tf);
+ 	} else if (s->all) {
+ 		int special = s->all;
+ 		s->all = 0;
+@@ -727,6 +658,9 @@ static ide_startstop_t ide_disk_special(ide_drive_t *drive)
+ 		return ide_stopped;
+ 	}
+ 
++	args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE |
++			IDE_TFLAG_CUSTOM_HANDLER;
++
+ 	do_rw_taskfile(drive, &args);
+ 
+ 	return ide_started;
+@@ -801,7 +735,7 @@ static ide_startstop_t do_special (ide_drive_t *drive)
+ 
+ 			if (hwif->host_flags & IDE_HFLAG_SET_PIO_MODE_KEEP_DMA) {
+ 				if (keep_dma)
+-					hwif->ide_dma_on(drive);
++					ide_dma_on(drive);
+ 			}
+ 		}
+ 
+@@ -861,13 +795,10 @@ static ide_startstop_t execute_drive_cmd (ide_drive_t *drive,
+ 		struct request *rq)
+ {
+ 	ide_hwif_t *hwif = HWIF(drive);
+-	if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) {
+- 		ide_task_t *args = rq->special;
+- 
+-		if (!args)
+-			goto done;
++	ide_task_t *task = rq->special;
+ 
+-		hwif->data_phase = args->data_phase;
++	if (task) {
++		hwif->data_phase = task->data_phase;
+ 
+ 		switch (hwif->data_phase) {
+ 		case TASKFILE_MULTI_OUT:
+@@ -880,57 +811,9 @@ static ide_startstop_t execute_drive_cmd (ide_drive_t *drive,
+ 			break;
+ 		}
+ 
+-		if (args->tf_out_flags.all != 0) 
+-			return flagged_taskfile(drive, args);
+-		return do_rw_taskfile(drive, args);
+-	} else if (rq->cmd_type == REQ_TYPE_ATA_TASK) {
+-		u8 *args = rq->buffer;
+- 
+-		if (!args)
+-			goto done;
+-#ifdef DEBUG
+- 		printk("%s: DRIVE_TASK_CMD ", drive->name);
+- 		printk("cmd=0x%02x ", args[0]);
+- 		printk("fr=0x%02x ", args[1]);
+- 		printk("ns=0x%02x ", args[2]);
+- 		printk("sc=0x%02x ", args[3]);
+- 		printk("lcyl=0x%02x ", args[4]);
+- 		printk("hcyl=0x%02x ", args[5]);
+- 		printk("sel=0x%02x\n", args[6]);
+-#endif
+- 		hwif->OUTB(args[1], IDE_FEATURE_REG);
+- 		hwif->OUTB(args[3], IDE_SECTOR_REG);
+- 		hwif->OUTB(args[4], IDE_LCYL_REG);
+- 		hwif->OUTB(args[5], IDE_HCYL_REG);
+- 		hwif->OUTB((args[6] & 0xEF)|drive->select.all, IDE_SELECT_REG);
+- 		ide_cmd(drive, args[0], args[2], &drive_cmd_intr);
+- 		return ide_started;
+- 	} else if (rq->cmd_type == REQ_TYPE_ATA_CMD) {
+- 		u8 *args = rq->buffer;
+-
+-		if (!args)
+-			goto done;
+-#ifdef DEBUG
+- 		printk("%s: DRIVE_CMD ", drive->name);
+- 		printk("cmd=0x%02x ", args[0]);
+- 		printk("sc=0x%02x ", args[1]);
+- 		printk("fr=0x%02x ", args[2]);
+- 		printk("xx=0x%02x\n", args[3]);
+-#endif
+- 		if (args[0] == WIN_SMART) {
+- 			hwif->OUTB(0x4f, IDE_LCYL_REG);
+- 			hwif->OUTB(0xc2, IDE_HCYL_REG);
+- 			hwif->OUTB(args[2],IDE_FEATURE_REG);
+- 			hwif->OUTB(args[1],IDE_SECTOR_REG);
+- 			ide_cmd(drive, args[0], args[3], &drive_cmd_intr);
+- 			return ide_started;
+- 		}
+- 		hwif->OUTB(args[2],IDE_FEATURE_REG);
+- 		ide_cmd(drive, args[0], args[1], &drive_cmd_intr);
+- 		return ide_started;
+- 	}
 -
--static int
--m41t00_detach(struct i2c_client *client)
+-done:
++		return do_rw_taskfile(drive, task);
++	}
++
+  	/*
+  	 * NULL is actually a valid way of waiting for
+  	 * all current requests to be flushed from the queue.
+@@ -970,8 +853,7 @@ static void ide_check_pm_state(ide_drive_t *drive, struct request *rq)
+ 		if (rc)
+ 			printk(KERN_WARNING "%s: bus not ready on wakeup\n", drive->name);
+ 		SELECT_DRIVE(drive);
+-		if (IDE_CONTROL_REG)
+-			HWIF(drive)->OUTB(drive->ctl, IDE_CONTROL_REG);
++		ide_set_irq(drive, 1);
+ 		rc = ide_wait_not_busy(HWIF(drive), 100000);
+ 		if (rc)
+ 			printk(KERN_WARNING "%s: drive not ready on wakeup\n", drive->name);
+@@ -1003,6 +885,7 @@ static ide_startstop_t start_request (ide_drive_t *drive, struct request *rq)
+ 
+ 	/* bail early if we've exceeded max_failures */
+ 	if (drive->max_failures && (drive->failures > drive->max_failures)) {
++		rq->cmd_flags |= REQ_FAILED;
+ 		goto kill_rq;
+ 	}
+ 
+@@ -1034,9 +917,7 @@ static ide_startstop_t start_request (ide_drive_t *drive, struct request *rq)
+ 		if (drive->current_speed == 0xff)
+ 			ide_config_drive_speed(drive, drive->desired_speed);
+ 
+-		if (rq->cmd_type == REQ_TYPE_ATA_CMD ||
+-		    rq->cmd_type == REQ_TYPE_ATA_TASK ||
+-		    rq->cmd_type == REQ_TYPE_ATA_TASKFILE)
++		if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE)
+ 			return execute_drive_cmd(drive, rq);
+ 		else if (blk_pm_request(rq)) {
+ 			struct request_pm_state *pm = rq->data;
+@@ -1244,11 +1125,13 @@ static void ide_do_request (ide_hwgroup_t *hwgroup, int masked_irq)
+ 		}
+ 	again:
+ 		hwif = HWIF(drive);
+-		if (hwgroup->hwif->sharing_irq &&
+-		    hwif != hwgroup->hwif &&
+-		    hwif->io_ports[IDE_CONTROL_OFFSET]) {
+-			/* set nIEN for previous hwif */
+-			SELECT_INTERRUPT(drive);
++		if (hwgroup->hwif->sharing_irq && hwif != hwgroup->hwif) {
++			/*
++			 * set nIEN for previous hwif, drives in the
++			 * quirk_list may not like intr setups/cleanups
++			 */
++			if (drive->quirk_list != 1)
++				ide_set_irq(drive, 0);
+ 		}
+ 		hwgroup->hwif = hwif;
+ 		hwgroup->drive = drive;
+@@ -1361,7 +1244,7 @@ static ide_startstop_t ide_dma_timeout_retry(ide_drive_t *drive, int error)
+ 	 */
+ 	drive->retry_pio++;
+ 	drive->state = DMA_PIO_RETRY;
+-	hwif->dma_off_quietly(drive);
++	ide_dma_off_quietly(drive);
+ 
+ 	/*
+ 	 * un-busy drive etc (hwgroup->busy is cleared on return) and
+@@ -1454,12 +1337,8 @@ void ide_timer_expiry (unsigned long data)
+ 			 */
+ 			spin_unlock(&ide_lock);
+ 			hwif  = HWIF(drive);
+-#if DISABLE_IRQ_NOSYNC
+-			disable_irq_nosync(hwif->irq);
+-#else
+ 			/* disable_irq_nosync ?? */
+ 			disable_irq(hwif->irq);
+-#endif /* DISABLE_IRQ_NOSYNC */
+ 			/* local CPU only,
+ 			 * as if we were handling an interrupt */
+ 			local_irq_disable();
+@@ -1710,7 +1589,6 @@ irqreturn_t ide_intr (int irq, void *dev_id)
+ void ide_init_drive_cmd (struct request *rq)
+ {
+ 	memset(rq, 0, sizeof(*rq));
+-	rq->cmd_type = REQ_TYPE_ATA_CMD;
+ 	rq->ref_count = 1;
+ }
+ 
+@@ -1785,3 +1663,19 @@ int ide_do_drive_cmd (ide_drive_t *drive, struct request *rq, ide_action_t actio
+ }
+ 
+ EXPORT_SYMBOL(ide_do_drive_cmd);
++
++void ide_pktcmd_tf_load(ide_drive_t *drive, u32 tf_flags, u16 bcount, u8 dma)
++{
++	ide_task_t task;
++
++	memset(&task, 0, sizeof(task));
++	task.tf_flags = IDE_TFLAG_OUT_LBAH | IDE_TFLAG_OUT_LBAM |
++			IDE_TFLAG_OUT_FEATURE | tf_flags;
++	task.tf.feature = dma;		/* Use PIO/DMA */
++	task.tf.lbam    = bcount & 0xff;
++	task.tf.lbah    = (bcount >> 8) & 0xff;
++
++	ide_tf_load(drive, &task);
++}
++
++EXPORT_SYMBOL_GPL(ide_pktcmd_tf_load);
+diff --git a/drivers/ide/ide-iops.c b/drivers/ide/ide-iops.c
+index bb9693d..e2a7e95 100644
+--- a/drivers/ide/ide-iops.c
++++ b/drivers/ide/ide-iops.c
+@@ -158,14 +158,6 @@ void default_hwif_mmiops (ide_hwif_t *hwif)
+ 
+ EXPORT_SYMBOL(default_hwif_mmiops);
+ 
+-u32 ide_read_24 (ide_drive_t *drive)
 -{
--	int rc;
--
--	if ((rc = i2c_detach_client(client)) == 0) {
--		kfree(client);
--		destroy_workqueue(m41t00_wq);
--	}
--	return rc;
+-	u8 hcyl = HWIF(drive)->INB(IDE_HCYL_REG);
+-	u8 lcyl = HWIF(drive)->INB(IDE_LCYL_REG);
+-	u8 sect = HWIF(drive)->INB(IDE_SECTOR_REG);
+-	return (hcyl<<16)|(lcyl<<8)|sect;
 -}
 -
--static struct i2c_driver m41t00_driver = {
--	.driver = {
--		.name	= M41T00_DRV_NAME,
--	},
--	.id		= I2C_DRIVERID_STM41T00,
--	.attach_adapter	= m41t00_attach,
--	.detach_client	= m41t00_detach,
--};
--
--static int __init
--m41t00_init(void)
+ void SELECT_DRIVE (ide_drive_t *drive)
+ {
+ 	if (HWIF(drive)->selectproc)
+@@ -175,26 +167,12 @@ void SELECT_DRIVE (ide_drive_t *drive)
+ 
+ EXPORT_SYMBOL(SELECT_DRIVE);
+ 
+-void SELECT_INTERRUPT (ide_drive_t *drive)
 -{
--	int rc;
--
--	if (!(rc = platform_driver_register(&m41t00_platform_driver)))
--		rc = i2c_add_driver(&m41t00_driver);
--	return rc;
+-	if (HWIF(drive)->intrproc)
+-		HWIF(drive)->intrproc(drive);
+-	else
+-		HWIF(drive)->OUTB(drive->ctl|2, IDE_CONTROL_REG);
 -}
 -
--static void __exit
--m41t00_exit(void)
+ void SELECT_MASK (ide_drive_t *drive, int mask)
+ {
+ 	if (HWIF(drive)->maskproc)
+ 		HWIF(drive)->maskproc(drive, mask);
+ }
+ 
+-void QUIRK_LIST (ide_drive_t *drive)
 -{
--	i2c_del_driver(&m41t00_driver);
--	platform_driver_unregister(&m41t00_platform_driver);
+-	if (HWIF(drive)->quirkproc)
+-		drive->quirk_list = HWIF(drive)->quirkproc(drive);
 -}
 -
--module_init(m41t00_init);
--module_exit(m41t00_exit);
--
--MODULE_AUTHOR("Mark A. Greer <mgreer at mvista.com>");
--MODULE_DESCRIPTION("ST Microelectronics M41T00 RTC I2C Client Driver");
--MODULE_LICENSE("GPL");
-diff --git a/drivers/i2c/chips/max6875.c b/drivers/i2c/chips/max6875.c
-index 64692f6..fb7ea56 100644
---- a/drivers/i2c/chips/max6875.c
-+++ b/drivers/i2c/chips/max6875.c
-@@ -34,7 +34,7 @@
- #include <linux/mutex.h>
+ /*
+  * Some localbus EIDE interfaces require a special access sequence
+  * when using 32-bit I/O instructions to transfer data.  We call this
+@@ -449,7 +427,6 @@ int drive_is_ready (ide_drive_t *drive)
+ 	udelay(1);
+ #endif
  
- /* Do not scan - the MAX6875 access method will write to some EEPROM chips */
--static unsigned short normal_i2c[] = {I2C_CLIENT_END};
-+static const unsigned short normal_i2c[] = { I2C_CLIENT_END };
+-#ifdef CONFIG_IDEPCI_SHARE_IRQ
+ 	/*
+ 	 * We do a passive status test under shared PCI interrupts on
+ 	 * cards that truly share the ATA side interrupt, but may also share
+@@ -459,7 +436,6 @@ int drive_is_ready (ide_drive_t *drive)
+ 	if (IDE_CONTROL_REG)
+ 		stat = hwif->INB(IDE_ALTSTATUS_REG);
+ 	else
+-#endif /* CONFIG_IDEPCI_SHARE_IRQ */
+ 		/* Note: this may clear a pending IRQ!! */
+ 		stat = hwif->INB(IDE_STATUS_REG);
  
- /* Insmod parameters */
- I2C_CLIENT_INSMOD_1(max6875);
-diff --git a/drivers/i2c/chips/pcf8574.c b/drivers/i2c/chips/pcf8574.c
-index 21c6dd6..b3b830c 100644
---- a/drivers/i2c/chips/pcf8574.c
-+++ b/drivers/i2c/chips/pcf8574.c
-@@ -41,9 +41,11 @@
- #include <linux/i2c.h>
+@@ -642,9 +618,9 @@ no_80w:
  
- /* Addresses to scan */
--static unsigned short normal_i2c[] = { 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
--					0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
--					I2C_CLIENT_END };
-+static const unsigned short normal_i2c[] = {
-+	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
-+	0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
-+	I2C_CLIENT_END
-+};
+ int ide_ata66_check (ide_drive_t *drive, ide_task_t *args)
+ {
+-	if ((args->tfRegister[IDE_COMMAND_OFFSET] == WIN_SETFEATURES) &&
+-	    (args->tfRegister[IDE_SECTOR_OFFSET] > XFER_UDMA_2) &&
+-	    (args->tfRegister[IDE_FEATURE_OFFSET] == SETFEATURES_XFER)) {
++	if (args->tf.command == WIN_SETFEATURES &&
++	    args->tf.nsect > XFER_UDMA_2 &&
++	    args->tf.feature == SETFEATURES_XFER) {
+ 		if (eighty_ninty_three(drive) == 0) {
+ 			printk(KERN_WARNING "%s: UDMA speeds >UDMA33 cannot "
+ 					    "be set\n", drive->name);
+@@ -662,9 +638,9 @@ int ide_ata66_check (ide_drive_t *drive, ide_task_t *args)
+  */
+ int set_transfer (ide_drive_t *drive, ide_task_t *args)
+ {
+-	if ((args->tfRegister[IDE_COMMAND_OFFSET] == WIN_SETFEATURES) &&
+-	    (args->tfRegister[IDE_SECTOR_OFFSET] >= XFER_SW_DMA_0) &&
+-	    (args->tfRegister[IDE_FEATURE_OFFSET] == SETFEATURES_XFER) &&
++	if (args->tf.command == WIN_SETFEATURES &&
++	    args->tf.nsect >= XFER_SW_DMA_0 &&
++	    args->tf.feature == SETFEATURES_XFER &&
+ 	    (drive->id->dma_ultra ||
+ 	     drive->id->dma_mword ||
+ 	     drive->id->dma_1word))
+@@ -712,8 +688,7 @@ int ide_driveid_update(ide_drive_t *drive)
+ 	 */
  
- /* Insmod parameters */
- I2C_CLIENT_INSMOD_2(pcf8574, pcf8574a);
-diff --git a/drivers/i2c/chips/pcf8575.c b/drivers/i2c/chips/pcf8575.c
-new file mode 100644
-index 0000000..3ea08ac
---- /dev/null
-+++ b/drivers/i2c/chips/pcf8575.c
-@@ -0,0 +1,214 @@
-+/*
-+  pcf8575.c
-+
-+  About the PCF8575 chip: the PCF8575 is a 16-bit I/O expander for the I2C bus
-+  produced by a.o. Philips Semiconductors.
-+
-+  Copyright (C) 2006 Michael Hennerich, Analog Devices Inc.
-+  <hennerich at blackfin.uclinux.org>
-+  Based on pcf8574.c.
-+
-+  Copyright (c) 2007 Bart Van Assche <bart.vanassche at gmail.com>.
-+  Ported this driver from ucLinux to the mainstream Linux kernel.
-+
-+  This program is free software; you can redistribute it and/or modify
-+  it under the terms of the GNU General Public License as published by
-+  the Free Software Foundation; either version 2 of the License, or
-+  (at your option) any later version.
-+
-+  This program is distributed in the hope that it will be useful,
-+  but WITHOUT ANY WARRANTY; without even the implied warranty of
-+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+  GNU General Public License for more details.
-+
-+  You should have received a copy of the GNU General Public License
-+  along with this program; if not, write to the Free Software
-+  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-+*/
-+
-+#include <linux/module.h>
-+#include <linux/init.h>
-+#include <linux/i2c.h>
-+#include <linux/slab.h>  /* kzalloc() */
-+#include <linux/sysfs.h> /* sysfs_create_group() */
-+
-+/* Addresses to scan */
-+static const unsigned short normal_i2c[] = {
-+	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
-+	I2C_CLIENT_END
-+};
-+
-+/* Insmod parameters */
-+I2C_CLIENT_INSMOD;
-+
-+
-+/* Each client has this additional data */
-+struct pcf8575_data {
-+	struct i2c_client client;
-+	int write;		/* last written value, or error code */
-+};
-+
-+static int pcf8575_attach_adapter(struct i2c_adapter *adapter);
-+static int pcf8575_detect(struct i2c_adapter *adapter, int address, int kind);
-+static int pcf8575_detach_client(struct i2c_client *client);
-+
-+/* This is the driver that will be inserted */
-+static struct i2c_driver pcf8575_driver = {
-+	.driver = {
-+		.owner	= THIS_MODULE,
-+		.name	= "pcf8575",
-+	},
-+	.attach_adapter	= pcf8575_attach_adapter,
-+	.detach_client	= pcf8575_detach_client,
-+};
-+
-+/* following are the sysfs callback functions */
-+static ssize_t show_read(struct device *dev, struct device_attribute *attr,
-+			 char *buf)
-+{
-+	struct i2c_client *client = to_i2c_client(dev);
-+	u16 val;
-+	u8 iopin_state[2];
-+
-+	i2c_master_recv(client, iopin_state, 2);
-+
-+	val = iopin_state[0];
-+	val |= iopin_state[1] << 8;
+ 	SELECT_MASK(drive, 1);
+-	if (IDE_CONTROL_REG)
+-		hwif->OUTB(drive->ctl,IDE_CONTROL_REG);
++	ide_set_irq(drive, 1);
+ 	msleep(50);
+ 	hwif->OUTB(WIN_IDENTIFY, IDE_COMMAND_REG);
+ 	timeout = jiffies + WAIT_WORSTCASE;
+@@ -766,8 +741,8 @@ int ide_config_drive_speed(ide_drive_t *drive, u8 speed)
+ //		msleep(50);
+ 
+ #ifdef CONFIG_BLK_DEV_IDEDMA
+-	if (hwif->ide_dma_on)	/* check if host supports DMA */
+-		hwif->dma_host_off(drive);
++	if (hwif->dma_host_set)	/* check if host supports DMA */
++		hwif->dma_host_set(drive, 0);
+ #endif
+ 
+ 	/* Skip setting PIO flow-control modes on pre-EIDE drives */
+@@ -796,13 +771,12 @@ int ide_config_drive_speed(ide_drive_t *drive, u8 speed)
+ 	SELECT_DRIVE(drive);
+ 	SELECT_MASK(drive, 0);
+ 	udelay(1);
+-	if (IDE_CONTROL_REG)
+-		hwif->OUTB(drive->ctl | 2, IDE_CONTROL_REG);
++	ide_set_irq(drive, 0);
+ 	hwif->OUTB(speed, IDE_NSECTOR_REG);
+ 	hwif->OUTB(SETFEATURES_XFER, IDE_FEATURE_REG);
+ 	hwif->OUTBSYNC(drive, WIN_SETFEATURES, IDE_COMMAND_REG);
+-	if ((IDE_CONTROL_REG) && (drive->quirk_list == 2))
+-		hwif->OUTB(drive->ctl, IDE_CONTROL_REG);
++	if (drive->quirk_list == 2)
++		ide_set_irq(drive, 1);
+ 
+ 	error = __ide_wait_stat(drive, drive->ready_stat,
+ 				BUSY_STAT|DRQ_STAT|ERR_STAT,
+@@ -823,10 +797,11 @@ int ide_config_drive_speed(ide_drive_t *drive, u8 speed)
+ 
+  skip:
+ #ifdef CONFIG_BLK_DEV_IDEDMA
+-	if (speed >= XFER_SW_DMA_0)
+-		hwif->dma_host_on(drive);
+-	else if (hwif->ide_dma_on)	/* check if host supports DMA */
+-		hwif->dma_off_quietly(drive);
++	if ((speed >= XFER_SW_DMA_0 || (hwif->host_flags & IDE_HFLAG_VDMA)) &&
++	    drive->using_dma)
++		hwif->dma_host_set(drive, 1);
++	else if (hwif->dma_host_set)	/* check if host supports DMA */
++		ide_dma_off_quietly(drive);
+ #endif
+ 
+ 	switch(speed) {
+@@ -902,8 +877,9 @@ EXPORT_SYMBOL(ide_set_handler);
+  *	handler and IRQ setup do not race. All IDE command kick off
+  *	should go via this function or do equivalent locking.
+  */
+- 
+-void ide_execute_command(ide_drive_t *drive, task_ioreg_t cmd, ide_handler_t *handler, unsigned timeout, ide_expiry_t *expiry)
 +
-+	return sprintf(buf, "%u\n", val);
-+}
++void ide_execute_command(ide_drive_t *drive, u8 cmd, ide_handler_t *handler,
++			 unsigned timeout, ide_expiry_t *expiry)
+ {
+ 	unsigned long flags;
+ 	ide_hwgroup_t *hwgroup = HWGROUP(drive);
+@@ -1035,10 +1011,10 @@ static void check_dma_crc(ide_drive_t *drive)
+ {
+ #ifdef CONFIG_BLK_DEV_IDEDMA
+ 	if (drive->crc_count) {
+-		drive->hwif->dma_off_quietly(drive);
++		ide_dma_off_quietly(drive);
+ 		ide_set_xfer_rate(drive, ide_auto_reduce_xfer(drive));
+ 		if (drive->current_speed >= XFER_SW_DMA_0)
+-			(void) HWIF(drive)->ide_dma_on(drive);
++			ide_dma_on(drive);
+ 	} else
+ 		ide_dma_off(drive);
+ #endif
+@@ -1051,8 +1027,7 @@ static void ide_disk_pre_reset(ide_drive_t *drive)
+ 	drive->special.all = 0;
+ 	drive->special.b.set_geometry = legacy;
+ 	drive->special.b.recalibrate  = legacy;
+-	if (OK_TO_RESET_CONTROLLER)
+-		drive->mult_count = 0;
++	drive->mult_count = 0;
+ 	if (!drive->keep_settings && !drive->using_dma)
+ 		drive->mult_req = 0;
+ 	if (drive->mult_req != drive->mult_count)
+@@ -1137,7 +1112,6 @@ static ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi)
+ 	for (unit = 0; unit < MAX_DRIVES; ++unit)
+ 		pre_reset(&hwif->drives[unit]);
+ 
+-#if OK_TO_RESET_CONTROLLER
+ 	if (!IDE_CONTROL_REG) {
+ 		spin_unlock_irqrestore(&ide_lock, flags);
+ 		return ide_stopped;
+@@ -1174,11 +1148,8 @@ static ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi)
+ 	 * state when the disks are reset this way. At least, the Winbond
+ 	 * 553 documentation says that
+ 	 */
+-	if (hwif->resetproc != NULL) {
++	if (hwif->resetproc)
+ 		hwif->resetproc(drive);
+-	}
+-	
+-#endif	/* OK_TO_RESET_CONTROLLER */
+ 
+ 	spin_unlock_irqrestore(&ide_lock, flags);
+ 	return ide_started;
+diff --git a/drivers/ide/ide-lib.c b/drivers/ide/ide-lib.c
+index 062d3bc..9b44fbd 100644
+--- a/drivers/ide/ide-lib.c
++++ b/drivers/ide/ide-lib.c
+@@ -441,6 +441,12 @@ int ide_set_xfer_rate(ide_drive_t *drive, u8 rate)
+ 	 * case could happen iff the transfer mode has already been set on
+ 	 * the device by ide-proc.c::set_xfer_rate()).
+ 	 */
++	if (rate < XFER_PIO_0) {
++		if (hwif->host_flags & IDE_HFLAG_ABUSE_SET_DMA_MODE)
++			return ide_set_dma_mode(drive, rate);
++		else
++			return ide_config_drive_speed(drive, rate);
++	}
+ 
+ 	return ide_set_dma_mode(drive, rate);
+ }
+@@ -448,8 +454,7 @@ int ide_set_xfer_rate(ide_drive_t *drive, u8 rate)
+ static void ide_dump_opcode(ide_drive_t *drive)
+ {
+ 	struct request *rq;
+-	u8 opcode = 0;
+-	int found = 0;
++	ide_task_t *task = NULL;
+ 
+ 	spin_lock(&ide_lock);
+ 	rq = NULL;
+@@ -458,164 +463,129 @@ static void ide_dump_opcode(ide_drive_t *drive)
+ 	spin_unlock(&ide_lock);
+ 	if (!rq)
+ 		return;
+-	if (rq->cmd_type == REQ_TYPE_ATA_CMD ||
+-	    rq->cmd_type == REQ_TYPE_ATA_TASK) {
+-		char *args = rq->buffer;
+-		if (args) {
+-			opcode = args[0];
+-			found = 1;
+-		}
+-	} else if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) {
+-		ide_task_t *args = rq->special;
+-		if (args) {
+-			task_struct_t *tf = (task_struct_t *) args->tfRegister;
+-			opcode = tf->command;
+-			found = 1;
+-		}
+-	}
 +
-+static DEVICE_ATTR(read, S_IRUGO, show_read, NULL);
++	if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE)
++		task = rq->special;
+ 
+ 	printk("ide: failed opcode was: ");
+-	if (!found)
+-		printk("unknown\n");
++	if (task == NULL)
++		printk(KERN_CONT "unknown\n");
+ 	else
+-		printk("0x%02x\n", opcode);
++		printk(KERN_CONT "0x%02x\n", task->tf.command);
+ }
+ 
+-static u8 ide_dump_ata_status(ide_drive_t *drive, const char *msg, u8 stat)
++u64 ide_get_lba_addr(struct ide_taskfile *tf, int lba48)
+ {
+-	ide_hwif_t *hwif = HWIF(drive);
+-	unsigned long flags;
+-	u8 err = 0;
++	u32 high, low;
+ 
+-	local_irq_save(flags);
+-	printk("%s: %s: status=0x%02x { ", drive->name, msg, stat);
+-	if (stat & BUSY_STAT)
+-		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 (lba48)
++		high = (tf->hob_lbah << 16) | (tf->hob_lbam << 8) |
++			tf->hob_lbal;
++	else
++		high = tf->device & 0xf;
++	low  = (tf->lbah << 16) | (tf->lbam << 8) | tf->lbal;
 +
-+static ssize_t show_write(struct device *dev, struct device_attribute *attr,
-+			  char *buf)
-+{
-+	struct pcf8575_data *data = dev_get_drvdata(dev);
-+	if (data->write < 0)
-+		return data->write;
-+	return sprintf(buf, "%d\n", data->write);
++	return ((u64)high << 24) | low;
 +}
++EXPORT_SYMBOL_GPL(ide_get_lba_addr);
 +
-+static ssize_t set_write(struct device *dev, struct device_attribute *attr,
-+			 const char *buf, size_t count)
++static void ide_dump_sector(ide_drive_t *drive)
 +{
-+	struct i2c_client *client = to_i2c_client(dev);
-+	struct pcf8575_data *data = i2c_get_clientdata(client);
-+	unsigned long val = simple_strtoul(buf, NULL, 10);
-+	u8 iopin_state[2];
-+
-+	if (val > 0xffff)
-+		return -EINVAL;
-+
-+	data->write = val;
++	ide_task_t task;
++	struct ide_taskfile *tf = &task.tf;
++	int lba48 = (drive->addressing == 1) ? 1 : 0;
 +
-+	iopin_state[0] = val & 0xFF;
-+	iopin_state[1] = val >> 8;
++	memset(&task, 0, sizeof(task));
++	if (lba48)
++		task.tf_flags = IDE_TFLAG_IN_LBA | IDE_TFLAG_IN_HOB_LBA |
++				IDE_TFLAG_LBA48;
++	else
++		task.tf_flags = IDE_TFLAG_IN_LBA | IDE_TFLAG_IN_DEVICE;
 +
-+	i2c_master_send(client, iopin_state, 2);
++	ide_tf_read(drive, &task);
 +
-+	return count;
++	if (lba48 || (tf->device & ATA_LBA))
++		printk(", LBAsect=%llu",
++			(unsigned long long)ide_get_lba_addr(tf, lba48));
++	else
++		printk(", CHS=%d/%d/%d", (tf->lbah << 8) + tf->lbam,
++					 tf->device & 0xf, tf->lbal);
 +}
 +
-+static DEVICE_ATTR(write, S_IWUSR | S_IRUGO, show_write, set_write);
-+
-+static struct attribute *pcf8575_attributes[] = {
-+	&dev_attr_read.attr,
-+	&dev_attr_write.attr,
-+	NULL
-+};
-+
-+static const struct attribute_group pcf8575_attr_group = {
-+	.attrs = pcf8575_attributes,
-+};
-+
-+/*
-+ * Real code
-+ */
-+
-+static int pcf8575_attach_adapter(struct i2c_adapter *adapter)
++static void ide_dump_ata_error(ide_drive_t *drive, u8 err)
 +{
-+	return i2c_probe(adapter, &addr_data, pcf8575_detect);
++	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 ");
++	printk("}");
++	if ((err & (BBD_ERR | ABRT_ERR)) == BBD_ERR ||
++	    (err & (ECC_ERR|ID_ERR|MARK_ERR))) {
++		ide_dump_sector(drive);
++		if (HWGROUP(drive) && HWGROUP(drive)->rq)
++			printk(", sector=%llu",
++			       (unsigned long long)HWGROUP(drive)->rq->sector);
+ 	}
++	printk("\n");
 +}
 +
-+/* This function is called by i2c_probe */
-+static int pcf8575_detect(struct i2c_adapter *adapter, int address, int kind)
++static void ide_dump_atapi_error(ide_drive_t *drive, u8 err)
 +{
-+	struct i2c_client *client;
-+	struct pcf8575_data *data;
-+	int err = 0;
++	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);
+ 	printk("}\n");
+-	if ((stat & (BUSY_STAT|ERR_STAT)) == ERR_STAT) {
+-		err = hwif->INB(IDE_ERROR_REG);
+-		printk("%s: %s: error=0x%02x { ", drive->name, msg, err);
+-		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 ");
+-		printk("}");
+-		if ((err & (BBD_ERR | ABRT_ERR)) == BBD_ERR ||
+-		    (err & (ECC_ERR|ID_ERR|MARK_ERR))) {
+-			if (drive->addressing == 1) {
+-				__u64 sectors = 0;
+-				u32 low = 0, high = 0;
+-				hwif->OUTB(drive->ctl&~0x80, IDE_CONTROL_REG);
+-				low = ide_read_24(drive);
+-				hwif->OUTB(drive->ctl|0x80, IDE_CONTROL_REG);
+-				high = ide_read_24(drive);
+-				sectors = ((__u64)high << 24) | low;
+-				printk(", LBAsect=%llu, high=%d, low=%d",
+-				       (unsigned long long) sectors,
+-				       high, low);
+-			} else {
+-				u8 cur = hwif->INB(IDE_SELECT_REG);
+-				if (cur & 0x40) {	/* using LBA? */
+-					printk(", LBAsect=%ld", (unsigned long)
+-					 ((cur&0xf)<<24)
+-					 |(hwif->INB(IDE_HCYL_REG)<<16)
+-					 |(hwif->INB(IDE_LCYL_REG)<<8)
+-					 | hwif->INB(IDE_SECTOR_REG));
+-				} else {
+-					printk(", CHS=%d/%d/%d",
+-					 (hwif->INB(IDE_HCYL_REG)<<8) +
+-					  hwif->INB(IDE_LCYL_REG),
+-					  cur & 0xf,
+-					  hwif->INB(IDE_SECTOR_REG));
+-				}
+-			}
+-			if (HWGROUP(drive) && HWGROUP(drive)->rq)
+-				printk(", sector=%llu",
+-					(unsigned long long)HWGROUP(drive)->rq->sector);
+-		}
+-		printk("\n");
+-	}
+-	ide_dump_opcode(drive);
+-	local_irq_restore(flags);
+-	return err;
+ }
+ 
+ /**
+- *	ide_dump_atapi_status       -       print human readable atapi status
++ *	ide_dump_status		-	translate ATA/ATAPI error
+  *	@drive: drive that status applies to
+  *	@msg: text message to print
+  *	@stat: status byte to decode
+  *
+  *	Error reporting, in human readable form (luxurious, but a memory hog).
++ *	Combines the drive name, message and status byte to provide a
++ *	user understandable explanation of the device error.
+  */
+ 
+-static u8 ide_dump_atapi_status(ide_drive_t *drive, const char *msg, u8 stat)
++u8 ide_dump_status(ide_drive_t *drive, const char *msg, u8 stat)
+ {
+ 	unsigned long flags;
++	u8 err = 0;
+ 
+-	atapi_status_t status;
+-	atapi_error_t error;
+-
+-	status.all = stat;
+-	error.all = 0;
+ 	local_irq_save(flags);
+ 	printk("%s: %s: status=0x%02x { ", drive->name, msg, stat);
+-	if (status.b.bsy)
++	if (stat & BUSY_STAT)
+ 		printk("Busy ");
+ 	else {
+-		if (status.b.drdy)	printk("DriveReady ");
+-		if (status.b.df)	printk("DeviceFault ");
+-		if (status.b.dsc)	printk("SeekComplete ");
+-		if (status.b.drq)	printk("DataRequest ");
+-		if (status.b.corr)	printk("CorrectedError ");
+-		if (status.b.idx)	printk("Index ");
+-		if (status.b.check)	printk("Error ");
++		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 ");
+ 	}
+ 	printk("}\n");
+-	if (status.b.check && !status.b.bsy) {
+-		error.all = HWIF(drive)->INB(IDE_ERROR_REG);
+-		printk("%s: %s: error=0x%02x { ", drive->name, msg, error.all);
+-		if (error.b.ili)	printk("IllegalLengthIndication ");
+-		if (error.b.eom)	printk("EndOfMedia ");
+-		if (error.b.abrt)	printk("AbortedCommand ");
+-		if (error.b.mcr)	printk("MediaChangeRequested ");
+-		if (error.b.sense_key)	printk("LastFailedSense=0x%02x ",
+-						error.b.sense_key);
+-		printk("}\n");
++	if ((stat & (BUSY_STAT|ERR_STAT)) == ERR_STAT) {
++		err = drive->hwif->INB(IDE_ERROR_REG);
++		printk("%s: %s: error=0x%02x ", drive->name, msg, err);
++		if (drive->media == ide_disk)
++			ide_dump_ata_error(drive, err);
++		else
++			ide_dump_atapi_error(drive, err);
+ 	}
+ 	ide_dump_opcode(drive);
+ 	local_irq_restore(flags);
+-	return error.all;
+-}
+-
+-/**
+- *	ide_dump_status		-	translate ATA/ATAPI error
+- *	@drive: drive the error occured on
+- *	@msg: information string
+- *	@stat: status byte
+- *
+- *	Error reporting, in human readable form (luxurious, but a memory hog).
+- *	Combines the drive name, message and status byte to provide a
+- *	user understandable explanation of the device error.
+- */
+-
+-u8 ide_dump_status(ide_drive_t *drive, const char *msg, u8 stat)
+-{
+-	if (drive->media == ide_disk)
+-		return ide_dump_ata_status(drive, msg, stat);
+-	return ide_dump_atapi_status(drive, msg, stat);
++	return err;
+ }
+ 
+ EXPORT_SYMBOL(ide_dump_status);
+diff --git a/drivers/ide/ide-pnp.c b/drivers/ide/ide-pnp.c
+index e245521..cbbb0f7 100644
+--- a/drivers/ide/ide-pnp.c
++++ b/drivers/ide/ide-pnp.c
+@@ -31,7 +31,6 @@ static int idepnp_probe(struct pnp_dev * dev, const struct pnp_device_id *dev_id
+ {
+ 	hw_regs_t hw;
+ 	ide_hwif_t *hwif;
+-	int index;
+ 
+ 	if (!(pnp_port_valid(dev, 0) && pnp_port_valid(dev, 1) && pnp_irq_valid(dev, 0)))
+ 		return -1;
+@@ -41,11 +40,19 @@ static int idepnp_probe(struct pnp_dev * dev, const struct pnp_device_id *dev_id
+ 				pnp_port_start(dev, 1));
+ 	hw.irq = pnp_irq(dev, 0);
+ 
+-	index = ide_register_hw(&hw, NULL, 1, &hwif);
++	hwif = ide_find_port(hw.io_ports[IDE_DATA_OFFSET]);
++	if (hwif) {
++		u8 index = hwif->index;
++		u8 idx[4] = { index, 0xff, 0xff, 0xff };
 +
-+	if (!i2c_check_functionality(adapter, I2C_FUNC_I2C))
-+		goto exit;
++		ide_init_port_data(hwif, index);
++		ide_init_port_hw(hwif, &hw);
+ 
+-	if (index != -1) {
+-	    	printk(KERN_INFO "ide%d: generic PnP IDE interface\n", index);
++		printk(KERN_INFO "ide%d: generic PnP IDE interface\n", index);
+ 		pnp_set_drvdata(dev,hwif);
 +
-+	/* OK. For now, we presume we have a valid client. We now create the
-+	   client structure, even though we cannot fill it completely yet. */
-+	data = kzalloc(sizeof(struct pcf8575_data), GFP_KERNEL);
-+	if (!data) {
-+		err = -ENOMEM;
-+		goto exit;
-+	}
++		ide_device_add(idx);
 +
-+	client = &data->client;
-+	i2c_set_clientdata(client, data);
-+	client->addr = address;
-+	client->adapter = adapter;
-+	client->driver = &pcf8575_driver;
-+	strlcpy(client->name, "pcf8575", I2C_NAME_SIZE);
-+	data->write = -EAGAIN;
+ 		return 0;
+ 	}
+ 
+@@ -68,12 +75,15 @@ static struct pnp_driver idepnp_driver = {
+ 	.remove		= idepnp_remove,
+ };
+ 
+-void __init pnpide_init(void)
++static int __init pnpide_init(void)
+ {
+-	pnp_register_driver(&idepnp_driver);
++	return pnp_register_driver(&idepnp_driver);
+ }
+ 
+-void __exit pnpide_exit(void)
++static void __exit pnpide_exit(void)
+ {
+ 	pnp_unregister_driver(&idepnp_driver);
+ }
 +
-+	/* This is the place to detect whether the chip at the specified
-+	   address really is a PCF8575 chip. However, there is no method known
-+	   to detect whether an I2C chip is a PCF8575 or any other I2C chip. */
++module_init(pnpide_init);
++module_exit(pnpide_exit);
+diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c
+index 2994523..edf650b 100644
+--- a/drivers/ide/ide-probe.c
++++ b/drivers/ide/ide-probe.c
+@@ -95,10 +95,10 @@ static void ide_disk_init_mult_count(ide_drive_t *drive)
+ #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 : INITIAL_MULT_COUNT;
++		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 = INITIAL_MULT_COUNT;
++		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))
+@@ -234,7 +234,7 @@ static inline void do_identify (ide_drive_t *drive, u8 cmd)
+ 
+ 	drive->media = ide_disk;
+ 	printk("%s DISK drive\n", (id->config == 0x848a) ? "CFA" : "ATA" );
+-	QUIRK_LIST(drive);
 +
-+	/* Tell the I2C layer a new client has arrived */
-+	err = i2c_attach_client(client);
-+	if (err)
-+		goto exit_free;
+ 	return;
+ 
+ err_misc:
+@@ -350,22 +350,19 @@ static int try_to_identify (ide_drive_t *drive, u8 cmd)
+ 	 * the irq handler isn't expecting.
+ 	 */
+ 	if (IDE_CONTROL_REG) {
+-		u8 ctl = drive->ctl | 2;
+ 		if (!hwif->irq) {
+ 			autoprobe = 1;
+ 			cookie = probe_irq_on();
+-			/* enable device irq */
+-			ctl &= ~2;
+ 		}
+-		hwif->OUTB(ctl, IDE_CONTROL_REG);
++		ide_set_irq(drive, autoprobe);
+ 	}
+ 
+ 	retval = actual_try_to_identify(drive, cmd);
+ 
+ 	if (autoprobe) {
+ 		int irq;
+-		/* mask device irq */
+-		hwif->OUTB(drive->ctl|2, IDE_CONTROL_REG);
 +
-+	/* Register sysfs hooks */
-+	err = sysfs_create_group(&client->dev.kobj, &pcf8575_attr_group);
-+	if (err)
-+		goto exit_detach;
++		ide_set_irq(drive, 0);
+ 		/* clear drive IRQ */
+ 		(void) hwif->INB(IDE_STATUS_REG);
+ 		udelay(5);
+@@ -385,6 +382,20 @@ static int try_to_identify (ide_drive_t *drive, u8 cmd)
+ 	return retval;
+ }
+ 
++static int ide_busy_sleep(ide_hwif_t *hwif)
++{
++	unsigned long timeout = jiffies + WAIT_WORSTCASE;
++	u8 stat;
 +
-+	return 0;
++	do {
++		msleep(50);
++		stat = hwif->INB(hwif->io_ports[IDE_STATUS_OFFSET]);
++		if ((stat & BUSY_STAT) == 0)
++			return 0;
++	} while (time_before(jiffies, timeout));
 +
-+exit_detach:
-+	i2c_detach_client(client);
-+exit_free:
-+	kfree(data);
-+exit:
-+	return err;
++	return 1;
 +}
+ 
+ /**
+  *	do_probe		-	probe an IDE device
+@@ -453,7 +464,6 @@ static int do_probe (ide_drive_t *drive, u8 cmd)
+ 		if ((rc == 1 && cmd == WIN_PIDENTIFY) &&
+ 			((drive->autotune == IDE_TUNE_DEFAULT) ||
+ 			(drive->autotune == IDE_TUNE_AUTO))) {
+-			unsigned long timeout;
+ 			printk("%s: no response (status = 0x%02x), "
+ 				"resetting drive\n", drive->name,
+ 				hwif->INB(IDE_STATUS_REG));
+@@ -461,10 +471,7 @@ static int do_probe (ide_drive_t *drive, u8 cmd)
+ 			hwif->OUTB(drive->select.all, IDE_SELECT_REG);
+ 			msleep(50);
+ 			hwif->OUTB(WIN_SRST, IDE_COMMAND_REG);
+-			timeout = jiffies;
+-			while (((hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) &&
+-			       time_before(jiffies, timeout + WAIT_WORSTCASE))
+-				msleep(50);
++			(void)ide_busy_sleep(hwif);
+ 			rc = try_to_identify(drive, cmd);
+ 		}
+ 		if (rc == 1)
+@@ -492,20 +499,16 @@ static int do_probe (ide_drive_t *drive, u8 cmd)
+ static void enable_nest (ide_drive_t *drive)
+ {
+ 	ide_hwif_t *hwif = HWIF(drive);
+-	unsigned long timeout;
+ 
+ 	printk("%s: enabling %s -- ", hwif->name, drive->id->model);
+ 	SELECT_DRIVE(drive);
+ 	msleep(50);
+ 	hwif->OUTB(EXABYTE_ENABLE_NEST, IDE_COMMAND_REG);
+-	timeout = jiffies + WAIT_WORSTCASE;
+-	do {
+-		if (time_after(jiffies, timeout)) {
+-			printk("failed (timeout)\n");
+-			return;
+-		}
+-		msleep(50);
+-	} while ((hwif->INB(IDE_STATUS_REG)) & BUSY_STAT);
 +
-+static int pcf8575_detach_client(struct i2c_client *client)
-+{
-+	int err;
-+
-+	sysfs_remove_group(&client->dev.kobj, &pcf8575_attr_group);
++	if (ide_busy_sleep(hwif)) {
++		printk(KERN_CONT "failed (timeout)\n");
++		return;
++	}
+ 
+ 	msleep(50);
+ 
+@@ -653,8 +656,7 @@ static int wait_hwif_ready(ide_hwif_t *hwif)
+ 		/* Ignore disks that we will not probe for later. */
+ 		if (!drive->noprobe || drive->present) {
+ 			SELECT_DRIVE(drive);
+-			if (IDE_CONTROL_REG)
+-				hwif->OUTB(drive->ctl, IDE_CONTROL_REG);
++			ide_set_irq(drive, 1);
+ 			mdelay(2);
+ 			rc = ide_wait_not_busy(hwif, 35000);
+ 			if (rc)
+@@ -673,19 +675,18 @@ out:
+ 
+ /**
+  *	ide_undecoded_slave	-	look for bad CF adapters
+- *	@hwif: interface
++ *	@drive1: drive
+  *
+  *	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_hwif_t *hwif)
++void ide_undecoded_slave(ide_drive_t *drive1)
+ {
+-	ide_drive_t *drive0 = &hwif->drives[0];
+-	ide_drive_t *drive1 = &hwif->drives[1];
++	ide_drive_t *drive0 = &drive1->hwif->drives[0];
+ 
+-	if (drive0->present == 0 || drive1->present == 0)
++	if ((drive1->dn & 1) == 0 || drive0->present == 0)
+ 		return;
+ 
+ 	/* If the models don't match they are not the same product */
+@@ -788,18 +789,11 @@ static void probe_hwif(ide_hwif_t *hwif)
+ 		}
+ 	}
+ 	if (hwif->io_ports[IDE_CONTROL_OFFSET] && hwif->reset) {
+-		unsigned long timeout = jiffies + WAIT_WORSTCASE;
+-		u8 stat;
+-
+ 		printk(KERN_WARNING "%s: reset\n", hwif->name);
+ 		hwif->OUTB(12, hwif->io_ports[IDE_CONTROL_OFFSET]);
+ 		udelay(10);
+ 		hwif->OUTB(8, hwif->io_ports[IDE_CONTROL_OFFSET]);
+-		do {
+-			msleep(50);
+-			stat = hwif->INB(hwif->io_ports[IDE_STATUS_OFFSET]);
+-		} while ((stat & BUSY_STAT) && time_after(timeout, jiffies));
+-
++		(void)ide_busy_sleep(hwif);
+ 	}
+ 	local_irq_restore(flags);
+ 	/*
+@@ -814,8 +808,12 @@ static void probe_hwif(ide_hwif_t *hwif)
+ 		return;
+ 	}
+ 
+-	if (hwif->fixup)
+-		hwif->fixup(hwif);
++	for (unit = 0; unit < MAX_DRIVES; unit++) {
++		ide_drive_t *drive = &hwif->drives[unit];
 +
-+	err = i2c_detach_client(client);
-+	if (err)
-+		return err;
++		if (drive->present && hwif->quirkproc)
++			hwif->quirkproc(drive);
++	}
+ 
+ 	for (unit = 0; unit < MAX_DRIVES; ++unit) {
+ 		ide_drive_t *drive = &hwif->drives[unit];
+@@ -830,16 +828,8 @@ static void probe_hwif(ide_hwif_t *hwif)
+ 
+ 			drive->nice1 = 1;
+ 
+-			if (hwif->ide_dma_on) {
+-				/*
+-				 * Force DMAing for the beginning of the check.
+-				 * Some chipsets appear to do interesting
+-				 * things, if not checked and cleared.
+-				 *   PARANOIA!!!
+-				 */
+-				hwif->dma_off_quietly(drive);
++			if (hwif->dma_host_set)
+ 				ide_set_dma(drive);
+-			}
+ 		}
+ 	}
+ 
+@@ -853,25 +843,6 @@ static void probe_hwif(ide_hwif_t *hwif)
+ 	}
+ }
+ 
+-static int hwif_init(ide_hwif_t *hwif);
+-static void hwif_register_devices(ide_hwif_t *hwif);
+-
+-static int probe_hwif_init(ide_hwif_t *hwif)
+-{
+-	probe_hwif(hwif);
+-
+-	if (!hwif_init(hwif)) {
+-		printk(KERN_INFO "%s: failed to initialize IDE interface\n",
+-				 hwif->name);
+-		return -1;
+-	}
+-
+-	if (hwif->present)
+-		hwif_register_devices(hwif);
+-
+-	return 0;
+-}
+-
+ #if MAX_HWIFS > 1
+ /*
+  * save_match() is used to simplify logic in init_irq() below.
+@@ -968,11 +939,6 @@ static int ide_init_queue(ide_drive_t *drive)
+  * Much of the code is for correctly detecting/handling irq sharing
+  * and irq serialization situations.  This is somewhat complex because
+  * it handles static as well as dynamic (PCMCIA) IDE interfaces.
+- *
+- * The IRQF_DISABLED in sa_flags means ide_intr() is always entered with
+- * interrupts completely disabled.  This can be bad for interrupt latency,
+- * but anything else has led to problems on some machines.  We re-enable
+- * interrupts as much as we can safely do in most places.
+  */
+ static int init_irq (ide_hwif_t *hwif)
+ {
+@@ -1055,17 +1021,13 @@ static int init_irq (ide_hwif_t *hwif)
+ 	 * Allocate the irq, if not already obtained for another hwif
+ 	 */
+ 	if (!match || match->irq != hwif->irq) {
+-		int sa = IRQF_DISABLED;
++		int sa = 0;
+ #if defined(__mc68000__) || defined(CONFIG_APUS)
+ 		sa = IRQF_SHARED;
+ #endif /* __mc68000__ || CONFIG_APUS */
+ 
+-		if (IDE_CHIPSET_IS_PCI(hwif->chipset)) {
++		if (IDE_CHIPSET_IS_PCI(hwif->chipset))
+ 			sa = IRQF_SHARED;
+-#ifndef CONFIG_IDEPCI_SHARE_IRQ
+-			sa |= IRQF_DISABLED;
+-#endif /* CONFIG_IDEPCI_SHARE_IRQ */
+-		}
+ 
+ 		if (hwif->io_ports[IDE_CONTROL_OFFSET])
+ 			/* clear nIEN */
+@@ -1173,7 +1135,7 @@ static struct kobject *exact_match(dev_t dev, int *part, void *data)
+ {
+ 	struct gendisk *p = data;
+ 	*part &= (1 << PARTN_BITS) - 1;
+-	return &p->kobj;
++	return &p->dev.kobj;
+ }
+ 
+ static int exact_lock(dev_t dev, void *data)
+@@ -1373,54 +1335,63 @@ static void hwif_register_devices(ide_hwif_t *hwif)
+ 	}
+ }
+ 
+-int ideprobe_init (void)
++int ide_device_add_all(u8 *idx)
+ {
+-	unsigned int index;
+-	int probe[MAX_HWIFS];
+-
+-	memset(probe, 0, MAX_HWIFS * sizeof(int));
+-	for (index = 0; index < MAX_HWIFS; ++index)
+-		probe[index] = !ide_hwifs[index].present;
+-
+-	for (index = 0; index < MAX_HWIFS; ++index)
+-		if (probe[index])
+-			probe_hwif(&ide_hwifs[index]);
+-	for (index = 0; index < MAX_HWIFS; ++index)
+-		if (probe[index])
+-			hwif_init(&ide_hwifs[index]);
+-	for (index = 0; index < MAX_HWIFS; ++index) {
+-		if (probe[index]) {
+-			ide_hwif_t *hwif = &ide_hwifs[index];
+-			if (!hwif->present)
+-				continue;
+-			if (hwif->chipset == ide_unknown || hwif->chipset == ide_forced)
+-				hwif->chipset = ide_generic;
+-			hwif_register_devices(hwif);
++	ide_hwif_t *hwif;
++	int i, rc = 0;
 +
-+	kfree(i2c_get_clientdata(client));
-+	return 0;
-+}
++	for (i = 0; i < MAX_HWIFS; i++) {
++		if (idx[i] == 0xff)
++			continue;
 +
-+static int __init pcf8575_init(void)
-+{
-+	return i2c_add_driver(&pcf8575_driver);
-+}
++		probe_hwif(&ide_hwifs[idx[i]]);
++	}
 +
-+static void __exit pcf8575_exit(void)
-+{
-+	i2c_del_driver(&pcf8575_driver);
-+}
++	for (i = 0; i < MAX_HWIFS; i++) {
++		if (idx[i] == 0xff)
++			continue;
 +
-+MODULE_AUTHOR("Michael Hennerich <hennerich at blackfin.uclinux.org>, "
-+	      "Bart Van Assche <bart.vanassche at gmail.com>");
-+MODULE_DESCRIPTION("pcf8575 driver");
-+MODULE_LICENSE("GPL");
++		hwif = &ide_hwifs[idx[i]];
 +
-+module_init(pcf8575_init);
-+module_exit(pcf8575_exit);
-diff --git a/drivers/i2c/chips/pcf8591.c b/drivers/i2c/chips/pcf8591.c
-index 4dc3637..865f440 100644
---- a/drivers/i2c/chips/pcf8591.c
-+++ b/drivers/i2c/chips/pcf8591.c
-@@ -27,7 +27,7 @@
- #include <linux/mutex.h>
++		if (hwif_init(hwif) == 0) {
++			printk(KERN_INFO "%s: failed to initialize IDE "
++					 "interface\n", hwif->name);
++			rc = -1;
++			continue;
+ 		}
+ 	}
+-	for (index = 0; index < MAX_HWIFS; ++index)
+-		if (probe[index])
+-			ide_proc_register_port(&ide_hwifs[index]);
+-	return 0;
+-}
  
- /* Addresses to scan */
--static unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, 0x4c,
-+static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, 0x4c,
- 					0x4d, 0x4e, 0x4f, I2C_CLIENT_END };
+-EXPORT_SYMBOL_GPL(ideprobe_init);
++	for (i = 0; i < MAX_HWIFS; i++) {
++		if (idx[i] == 0xff)
++			continue;
  
- /* Insmod parameters */
-diff --git a/drivers/i2c/chips/tps65010.c b/drivers/i2c/chips/tps65010.c
-index e320994..4154a91 100644
---- a/drivers/i2c/chips/tps65010.c
-+++ b/drivers/i2c/chips/tps65010.c
-@@ -31,7 +31,7 @@
- #include <linux/seq_file.h>
- #include <linux/mutex.h>
+-int ide_device_add(u8 idx[4])
+-{
+-	int i, rc = 0;
++		hwif = &ide_hwifs[idx[i]];
  
--#include <asm/arch/tps65010.h>
-+#include <linux/i2c/tps65010.h>
+-	for (i = 0; i < 4; i++) {
+-		if (idx[i] != 0xff)
+-			rc |= probe_hwif_init(&ide_hwifs[idx[i]]);
++		if (hwif->present) {
++			if (hwif->chipset == ide_unknown ||
++			    hwif->chipset == ide_forced)
++				hwif->chipset = ide_generic;
++			hwif_register_devices(hwif);
++		}
+ 	}
  
- /*-------------------------------------------------------------------------*/
+-	for (i = 0; i < 4; i++) {
++	for (i = 0; i < MAX_HWIFS; i++) {
+ 		if (idx[i] != 0xff)
+ 			ide_proc_register_port(&ide_hwifs[idx[i]]);
+ 	}
  
-diff --git a/drivers/i2c/chips/tsl2550.c b/drivers/i2c/chips/tsl2550.c
-index 3de4b19..a10fd27 100644
---- a/drivers/i2c/chips/tsl2550.c
-+++ b/drivers/i2c/chips/tsl2550.c
-@@ -432,11 +432,32 @@ static int __devexit tsl2550_remove(struct i2c_client *client)
- 	return 0;
+ 	return rc;
  }
- 
-+#ifdef CONFIG_PM
++EXPORT_SYMBOL_GPL(ide_device_add_all);
 +
-+static int tsl2550_suspend(struct i2c_client *client, pm_message_t mesg)
++int ide_device_add(u8 idx[4])
 +{
-+	return tsl2550_set_power_state(client, 0);
-+}
++	u8 idx_all[MAX_HWIFS];
++	int i;
+ 
++	for (i = 0; i < MAX_HWIFS; i++)
++		idx_all[i] = (i < 4) ? idx[i] : 0xff;
 +
-+static int tsl2550_resume(struct i2c_client *client)
-+{
-+	return tsl2550_set_power_state(client, 1);
++	return ide_device_add_all(idx_all);
 +}
-+
-+#else
-+
-+#define tsl2550_suspend		NULL
-+#define tsl2550_resume		NULL
-+
-+#endif /* CONFIG_PM */
-+
- static struct i2c_driver tsl2550_driver = {
- 	.driver = {
- 		.name	= TSL2550_DRV_NAME,
- 		.owner	= THIS_MODULE,
- 	},
-+	.suspend = tsl2550_suspend,
-+	.resume	= tsl2550_resume,
- 	.probe	= tsl2550_probe,
- 	.remove	= __devexit_p(tsl2550_remove),
- };
-diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
-index b5e13e4..96da22e 100644
---- a/drivers/i2c/i2c-core.c
-+++ b/drivers/i2c/i2c-core.c
-@@ -33,14 +33,15 @@
- #include <linux/platform_device.h>
- #include <linux/mutex.h>
- #include <linux/completion.h>
-+#include <linux/hardirq.h>
-+#include <linux/irqflags.h>
- #include <asm/uaccess.h>
-+#include <asm/semaphore.h>
- 
- #include "i2c-core.h"
+ EXPORT_SYMBOL_GPL(ide_device_add);
+diff --git a/drivers/ide/ide-proc.c b/drivers/ide/ide-proc.c
+index a4007d3..aa663e7 100644
+--- a/drivers/ide/ide-proc.c
++++ b/drivers/ide/ide-proc.c
+@@ -346,14 +346,20 @@ static int ide_write_setting(ide_drive_t *drive, ide_settings_t *setting, int va
  
+ static int set_xfer_rate (ide_drive_t *drive, int arg)
+ {
++	ide_task_t task;
+ 	int err;
  
--static LIST_HEAD(adapters);
--static LIST_HEAD(drivers);
--static DEFINE_MUTEX(core_lists);
-+static DEFINE_MUTEX(core_lock);
- static DEFINE_IDR(i2c_adapter_idr);
+ 	if (arg < 0 || arg > 70)
+ 		return -EINVAL;
  
- #define is_newstyle_driver(d) ((d)->probe || (d)->remove)
-@@ -198,6 +199,25 @@ static struct bus_type i2c_bus_type = {
- 	.resume		= i2c_device_resume,
- };
+-	err = ide_wait_cmd(drive,
+-			WIN_SETFEATURES, (u8) arg,
+-			SETFEATURES_XFER, 0, NULL);
++	memset(&task, 0, sizeof(task));
++	task.tf.command = WIN_SETFEATURES;
++	task.tf.feature = SETFEATURES_XFER;
++	task.tf.nsect   = (u8)arg;
++	task.tf_flags = IDE_TFLAG_OUT_FEATURE | IDE_TFLAG_OUT_NSECT |
++			IDE_TFLAG_IN_NSECT;
++
++	err = ide_no_data_taskfile(drive, &task);
  
+ 	if (!err && arg) {
+ 		ide_set_xfer_rate(drive, (u8) arg);
+diff --git a/drivers/ide/ide-scan-pci.c b/drivers/ide/ide-scan-pci.c
+new file mode 100644
+index 0000000..7ffa332
+--- /dev/null
++++ b/drivers/ide/ide-scan-pci.c
+@@ -0,0 +1,121 @@
++/*
++ * support for probing IDE PCI devices in the PCI bus order
++ *
++ * Copyright (c) 1998-2000  Andre Hedrick <andre at linux-ide.org>
++ * Copyright (c) 1995-1998  Mark Lord
++ *
++ * May be copied or modified under the terms of the GNU General Public License
++ */
 +
-+/**
-+ * i2c_verify_client - return parameter as i2c_client, or NULL
-+ * @dev: device, probably from some driver model iterator
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/ide.h>
++
++/*
++ *	Module interfaces
++ */
++
++static int pre_init = 1;		/* Before first ordered IDE scan */
++static LIST_HEAD(ide_pci_drivers);
++
++/*
++ *	__ide_pci_register_driver	-	attach IDE driver
++ *	@driver: pci driver
++ *	@module: owner module of the driver
 + *
-+ * When traversing the driver model tree, perhaps using driver model
-+ * iterators like @device_for_each_child(), you can't assume very much
-+ * about the nodes you find.  Use this function to avoid oopses caused
-+ * by wrongly treating some non-I2C device as an i2c_client.
++ *	Registers a driver with the IDE layer. The IDE layer arranges that
++ *	boot time setup is done in the expected device order and then
++ *	hands the controllers off to the core PCI code to do the rest of
++ *	the work.
++ *
++ *	Returns are the same as for pci_register_driver
 + */
-+struct i2c_client *i2c_verify_client(struct device *dev)
++
++int __ide_pci_register_driver(struct pci_driver *driver, struct module *module,
++			      const char *mod_name)
 +{
-+	return (dev->bus == &i2c_bus_type)
-+			? to_i2c_client(dev)
-+			: NULL;
++	if (!pre_init)
++		return __pci_register_driver(driver, module, mod_name);
++	driver->driver.owner = module;
++	list_add_tail(&driver->node, &ide_pci_drivers);
++	return 0;
 +}
-+EXPORT_SYMBOL(i2c_verify_client);
++EXPORT_SYMBOL_GPL(__ide_pci_register_driver);
 +
++/**
++ *	ide_scan_pcidev		-	find an IDE driver for a device
++ *	@dev: PCI device to check
++ *
++ *	Look for an IDE driver to handle the device we are considering.
++ *	This is only used during boot up to get the ordering correct. After
++ *	boot up the pci layer takes over the job.
++ */
 +
- /**
-  * i2c_new_device - instantiate an i2c device for use with a new style driver
-  * @adap: the adapter managing the device
-@@ -276,6 +296,50 @@ void i2c_unregister_device(struct i2c_client *client)
- EXPORT_SYMBOL_GPL(i2c_unregister_device);
- 
- 
-+static int dummy_nop(struct i2c_client *client)
++static int __init ide_scan_pcidev(struct pci_dev *dev)
 +{
++	struct list_head *l;
++	struct pci_driver *d;
++
++	list_for_each(l, &ide_pci_drivers) {
++		d = list_entry(l, struct pci_driver, node);
++		if (d->id_table) {
++			const struct pci_device_id *id =
++				pci_match_id(d->id_table, dev);
++
++			if (id != NULL && d->probe(dev, id) >= 0) {
++				dev->driver = d;
++				pci_dev_get(dev);
++				return 1;
++			}
++		}
++	}
 +	return 0;
 +}
 +
-+static struct i2c_driver dummy_driver = {
-+	.driver.name	= "dummy",
-+	.probe		= dummy_nop,
-+	.remove		= dummy_nop,
-+};
-+
 +/**
-+ * i2c_new_dummy - return a new i2c device bound to a dummy driver
-+ * @adapter: the adapter managing the device
-+ * @address: seven bit address to be used
-+ * @type: optional label used for i2c_client.name
-+ * Context: can sleep
-+ *
-+ * This returns an I2C client bound to the "dummy" driver, intended for use
-+ * with devices that consume multiple addresses.  Examples of such chips
-+ * include various EEPROMS (like 24c04 and 24c08 models).
-+ *
-+ * These dummy devices have two main uses.  First, most I2C and SMBus calls
-+ * except i2c_transfer() need a client handle; the dummy will be that handle.
-+ * And second, this prevents the specified address from being bound to a
-+ * different driver.
++ *	ide_scan_pcibus		-	perform the initial IDE driver scan
 + *
-+ * This returns the new i2c client, which should be saved for later use with
-+ * i2c_unregister_device(); or NULL to indicate an error.
++ *	Perform the initial bus rather than driver ordered scan of the
++ *	PCI drivers. After this all IDE pci handling becomes standard
++ *	module ordering not traditionally ordered.
 + */
-+struct i2c_client *
-+i2c_new_dummy(struct i2c_adapter *adapter, u16 address, const char *type)
++
++int __init ide_scan_pcibus(void)
 +{
-+	struct i2c_board_info info = {
-+		.driver_name	= "dummy",
-+		.addr		= address,
-+	};
++	struct pci_dev *dev = NULL;
++	struct pci_driver *d;
++	struct list_head *l, *n;
 +
-+	if (type)
-+		strlcpy(info.type, type, sizeof info.type);
-+	return i2c_new_device(adapter, &info);
-+}
-+EXPORT_SYMBOL_GPL(i2c_new_dummy);
++	pre_init = 0;
++	if (!ide_scan_direction)
++		while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)))
++			ide_scan_pcidev(dev);
++	else
++		while ((dev = pci_get_device_reverse(PCI_ANY_ID, PCI_ANY_ID,
++						     dev)))
++			ide_scan_pcidev(dev);
 +
- /* ------------------------------------------------------------------------- */
- 
- /* I2C bus adapters -- one roots each I2C or SMBUS segment */
-@@ -320,18 +384,27 @@ static void i2c_scan_static_board_info(struct i2c_adapter *adapter)
- 	mutex_unlock(&__i2c_board_lock);
- }
- 
-+static int i2c_do_add_adapter(struct device_driver *d, void *data)
-+{
-+	struct i2c_driver *driver = to_i2c_driver(d);
-+	struct i2c_adapter *adap = data;
++	/*
++	 *	Hand the drivers over to the PCI layer now we
++	 *	are post init.
++	 */
 +
-+	if (driver->attach_adapter) {
-+		/* We ignore the return code; if it fails, too bad */
-+		driver->attach_adapter(adap);
++	list_for_each_safe(l, n, &ide_pci_drivers) {
++		list_del(l);
++		d = list_entry(l, struct pci_driver, node);
++		if (__pci_register_driver(d, d->driver.owner,
++					  d->driver.mod_name))
++			printk(KERN_ERR "%s: failed to register %s driver\n",
++					__FUNCTION__, d->driver.mod_name);
 +	}
++
 +	return 0;
 +}
 +
- static int i2c_register_adapter(struct i2c_adapter *adap)
- {
--	int res = 0;
--	struct list_head   *item;
--	struct i2c_driver  *driver;
-+	int res = 0, dummy;
- 
- 	mutex_init(&adap->bus_lock);
- 	mutex_init(&adap->clist_lock);
- 	INIT_LIST_HEAD(&adap->clients);
- 
--	mutex_lock(&core_lists);
--	list_add_tail(&adap->list, &adapters);
-+	mutex_lock(&core_lock);
- 
- 	/* Add the adapter to the driver core.
- 	 * If the parent pointer is not set up,
-@@ -356,19 +429,14 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
- 		i2c_scan_static_board_info(adap);
- 
- 	/* let legacy drivers scan this bus for matching devices */
--	list_for_each(item,&drivers) {
--		driver = list_entry(item, struct i2c_driver, list);
--		if (driver->attach_adapter)
--			/* We ignore the return code; if it fails, too bad */
--			driver->attach_adapter(adap);
--	}
-+	dummy = bus_for_each_drv(&i2c_bus_type, NULL, adap,
-+				 i2c_do_add_adapter);
- 
- out_unlock:
--	mutex_unlock(&core_lists);
-+	mutex_unlock(&core_lock);
- 	return res;
- 
- out_list:
--	list_del(&adap->list);
- 	idr_remove(&i2c_adapter_idr, adap->nr);
- 	goto out_unlock;
- }
-@@ -394,11 +462,11 @@ retry:
- 	if (idr_pre_get(&i2c_adapter_idr, GFP_KERNEL) == 0)
- 		return -ENOMEM;
- 
--	mutex_lock(&core_lists);
-+	mutex_lock(&core_lock);
- 	/* "above" here means "above or equal to", sigh */
- 	res = idr_get_new_above(&i2c_adapter_idr, adapter,
- 				__i2c_first_dynamic_bus_num, &id);
--	mutex_unlock(&core_lists);
-+	mutex_unlock(&core_lock);
- 
- 	if (res < 0) {
- 		if (res == -EAGAIN)
-@@ -443,7 +511,7 @@ retry:
- 	if (idr_pre_get(&i2c_adapter_idr, GFP_KERNEL) == 0)
- 		return -ENOMEM;
- 
--	mutex_lock(&core_lists);
-+	mutex_lock(&core_lock);
- 	/* "above" here means "above or equal to", sigh;
- 	 * we need the "equal to" result to force the result
- 	 */
-@@ -452,7 +520,7 @@ retry:
- 		status = -EBUSY;
- 		idr_remove(&i2c_adapter_idr, id);
- 	}
--	mutex_unlock(&core_lists);
-+	mutex_unlock(&core_lock);
- 	if (status == -EAGAIN)
- 		goto retry;
- 
-@@ -462,6 +530,21 @@ retry:
- }
- EXPORT_SYMBOL_GPL(i2c_add_numbered_adapter);
- 
-+static int i2c_do_del_adapter(struct device_driver *d, void *data)
++static int __init ide_scan_pci(void)
 +{
-+	struct i2c_driver *driver = to_i2c_driver(d);
-+	struct i2c_adapter *adapter = data;
-+	int res;
-+
-+	if (!driver->detach_adapter)
-+		return 0;
-+	res = driver->detach_adapter(adapter);
-+	if (res)
-+		dev_err(&adapter->dev, "detach_adapter failed (%d) "
-+			"for driver [%s]\n", res, driver->driver.name);
-+	return res;
++	return ide_scan_pcibus();
 +}
 +
- /**
-  * i2c_del_adapter - unregister I2C adapter
-  * @adap: the adapter being unregistered
-@@ -473,35 +556,24 @@ EXPORT_SYMBOL_GPL(i2c_add_numbered_adapter);
- int i2c_del_adapter(struct i2c_adapter *adap)
- {
- 	struct list_head  *item, *_n;
--	struct i2c_adapter *adap_from_list;
--	struct i2c_driver *driver;
- 	struct i2c_client *client;
- 	int res = 0;
++module_init(ide_scan_pci);
+diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c
+index 7b9181b..d71a584 100644
+--- a/drivers/ide/ide-tape.c
++++ b/drivers/ide/ide-tape.c
+@@ -615,16 +615,6 @@ typedef struct os_dat_s {
+ /*************************** End of tunable parameters ***********************/
  
--	mutex_lock(&core_lists);
-+	mutex_lock(&core_lock);
+ /*
+- *	Debugging/Performance analysis
+- *
+- *	I/O trace support
+- */
+-#define USE_IOTRACE	0
+-#if USE_IOTRACE
+-#define IO_IDETAPE_FIFO	500
+-#endif
+-
+-/*
+  *	Read/Write error simulation
+  */
+ #define SIMULATE_ERRORS			0
+@@ -1700,6 +1690,11 @@ static int idetape_end_request(ide_drive_t *drive, int uptodate, int nr_sects)
+ 	if (error)
+ 		tape->failed_pc = NULL;
  
- 	/* First make sure that this adapter was ever added */
--	list_for_each_entry(adap_from_list, &adapters, list) {
--		if (adap_from_list == adap)
--			break;
--	}
--	if (adap_from_list != adap) {
-+	if (idr_find(&i2c_adapter_idr, adap->nr) != adap) {
- 		pr_debug("i2c-core: attempting to delete unregistered "
- 			 "adapter [%s]\n", adap->name);
- 		res = -EINVAL;
- 		goto out_unlock;
- 	}
++	if (!blk_special_request(rq)) {
++		ide_end_request(drive, uptodate, nr_sects);
++		return 0;
++	}
++
+ 	spin_lock_irqsave(&tape->spinlock, flags);
  
--	list_for_each(item,&drivers) {
--		driver = list_entry(item, struct i2c_driver, list);
--		if (driver->detach_adapter)
--			if ((res = driver->detach_adapter(adap))) {
--				dev_err(&adap->dev, "detach_adapter failed "
--					"for driver [%s]\n",
--					driver->driver.name);
--				goto out_unlock;
--			}
--	}
-+	/* Tell drivers about this removal */
-+	res = bus_for_each_drv(&i2c_bus_type, NULL, adap,
-+			       i2c_do_del_adapter);
-+	if (res)
-+		goto out_unlock;
+ 	/* The request was a pipelined data transfer request */
+@@ -1818,9 +1813,8 @@ static ide_startstop_t idetape_retry_pc (ide_drive_t *drive)
+ 	idetape_tape_t *tape = drive->driver_data;
+ 	idetape_pc_t *pc;
+ 	struct request *rq;
+-	atapi_error_t error;
  
- 	/* detach any active clients. This must be done first, because
- 	 * it can fail; in which case we give up. */
-@@ -529,7 +601,6 @@ int i2c_del_adapter(struct i2c_adapter *adap)
- 	/* clean up the sysfs representation */
- 	init_completion(&adap->dev_released);
- 	device_unregister(&adap->dev);
--	list_del(&adap->list);
+-	error.all = HWIF(drive)->INB(IDE_ERROR_REG);
++	(void)drive->hwif->INB(IDE_ERROR_REG);
+ 	pc = idetape_next_pc_storage(drive);
+ 	rq = idetape_next_rq_storage(drive);
+ 	idetape_create_request_sense_cmd(pc);
+@@ -1858,15 +1852,13 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive)
+ {
+ 	ide_hwif_t *hwif = drive->hwif;
+ 	idetape_tape_t *tape = drive->driver_data;
+-	atapi_status_t status;
+-	atapi_bcount_t bcount;
+-	atapi_ireason_t ireason;
+ 	idetape_pc_t *pc = tape->pc;
+-
+ 	unsigned int temp;
+ #if SIMULATE_ERRORS
+ 	static int error_sim_count = 0;
+ #endif
++	u16 bcount;
++	u8 stat, ireason;
  
- 	/* wait for sysfs to drop all references */
- 	wait_for_completion(&adap->dev_released);
-@@ -540,7 +611,7 @@ int i2c_del_adapter(struct i2c_adapter *adap)
- 	dev_dbg(&adap->dev, "adapter [%s] unregistered\n", adap->name);
+ #if IDETAPE_DEBUG_LOG
+ 	if (tape->debug_level >= 4)
+@@ -1875,10 +1867,10 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive)
+ #endif /* IDETAPE_DEBUG_LOG */	
  
-  out_unlock:
--	mutex_unlock(&core_lists);
-+	mutex_unlock(&core_lock);
- 	return res;
- }
- EXPORT_SYMBOL(i2c_del_adapter);
-@@ -583,21 +654,23 @@ int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
- 	if (res)
- 		return res;
+ 	/* Clear the interrupt */
+-	status.all = HWIF(drive)->INB(IDE_STATUS_REG);
++	stat = hwif->INB(IDE_STATUS_REG);
  
--	mutex_lock(&core_lists);
-+	mutex_lock(&core_lock);
+ 	if (test_bit(PC_DMA_IN_PROGRESS, &pc->flags)) {
+-		if (HWIF(drive)->ide_dma_end(drive) || status.b.check) {
++		if (hwif->ide_dma_end(drive) || (stat & ERR_STAT)) {
+ 			/*
+ 			 * A DMA error is sometimes expected. For example,
+ 			 * if the tape is crossing a filemark during a
+@@ -1912,7 +1904,7 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive)
+ 	}
  
--	list_add_tail(&driver->list,&drivers);
- 	pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name);
+ 	/* No more interrupts */
+-	if (!status.b.drq) {
++	if ((stat & DRQ_STAT) == 0) {
+ #if IDETAPE_DEBUG_LOG
+ 		if (tape->debug_level >= 2)
+ 			printk(KERN_INFO "ide-tape: Packet command completed, %d bytes transferred\n", pc->actually_transferred);
+@@ -1927,12 +1919,13 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive)
+ 		    (++error_sim_count % 100) == 0) {
+ 			printk(KERN_INFO "ide-tape: %s: simulating error\n",
+ 				tape->name);
+-			status.b.check = 1;
++			stat |= ERR_STAT;
+ 		}
+ #endif
+-		if (status.b.check && pc->c[0] == IDETAPE_REQUEST_SENSE_CMD)
+-			status.b.check = 0;
+-		if (status.b.check || test_bit(PC_DMA_ERROR, &pc->flags)) {	/* Error detected */
++		if ((stat & ERR_STAT) && pc->c[0] == IDETAPE_REQUEST_SENSE_CMD)
++			stat &= ~ERR_STAT;
++		if ((stat & ERR_STAT) || test_bit(PC_DMA_ERROR, &pc->flags)) {
++			/* Error detected */
+ #if IDETAPE_DEBUG_LOG
+ 			if (tape->debug_level >= 1)
+ 				printk(KERN_INFO "ide-tape: %s: I/O error\n",
+@@ -1951,7 +1944,7 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive)
+ 		}
+ 		pc->error = 0;
+ 		if (test_bit(PC_WAIT_FOR_DSC, &pc->flags) &&
+-		    !status.b.dsc) {
++		    (stat & SEEK_STAT) == 0) {
+ 			/* Media access command */
+ 			tape->dsc_polling_start = jiffies;
+ 			tape->dsc_polling_frequency = IDETAPE_DSC_MA_FAST;
+@@ -1973,30 +1966,30 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive)
+ 		return ide_do_reset(drive);
+ 	}
+ 	/* Get the number of bytes to transfer on this interrupt. */
+-	bcount.b.high = hwif->INB(IDE_BCOUNTH_REG);
+-	bcount.b.low = hwif->INB(IDE_BCOUNTL_REG);
++	bcount = (hwif->INB(IDE_BCOUNTH_REG) << 8) |
++		  hwif->INB(IDE_BCOUNTL_REG);
  
- 	/* legacy drivers scan i2c busses directly */
- 	if (driver->attach_adapter) {
- 		struct i2c_adapter *adapter;
+-	ireason.all = hwif->INB(IDE_IREASON_REG);
++	ireason = hwif->INB(IDE_IREASON_REG);
  
--		list_for_each_entry(adapter, &adapters, list) {
-+		down(&i2c_adapter_class.sem);
-+		list_for_each_entry(adapter, &i2c_adapter_class.devices,
-+				    dev.node) {
- 			driver->attach_adapter(adapter);
+-	if (ireason.b.cod) {
++	if (ireason & CD) {
+ 		printk(KERN_ERR "ide-tape: CoD != 0 in idetape_pc_intr\n");
+ 		return ide_do_reset(drive);
+ 	}
+-	if (ireason.b.io == test_bit(PC_WRITING, &pc->flags)) {
++	if (((ireason & IO) == IO) == test_bit(PC_WRITING, &pc->flags)) {
+ 		/* Hopefully, we will never get here */
+ 		printk(KERN_ERR "ide-tape: We wanted to %s, ",
+-			ireason.b.io ? "Write":"Read");
++				(ireason & IO) ? "Write" : "Read");
+ 		printk(KERN_ERR "ide-tape: but the tape wants us to %s !\n",
+-			ireason.b.io ? "Read":"Write");
++				(ireason & IO) ? "Read" : "Write");
+ 		return ide_do_reset(drive);
+ 	}
+ 	if (!test_bit(PC_WRITING, &pc->flags)) {
+ 		/* Reading - Check that we have enough space */
+-		temp = pc->actually_transferred + bcount.all;
++		temp = pc->actually_transferred + bcount;
+ 		if (temp > pc->request_transfer) {
+ 			if (temp > pc->buffer_size) {
+ 				printk(KERN_ERR "ide-tape: The tape wants to send us more data than expected - discarding data\n");
+-				idetape_discard_data(drive, bcount.all);
++				idetape_discard_data(drive, bcount);
+ 				ide_set_handler(drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL);
+ 				return ide_started;
+ 			}
+@@ -2008,23 +2001,26 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive)
+ 	}
+ 	if (test_bit(PC_WRITING, &pc->flags)) {
+ 		if (pc->bh != NULL)
+-			idetape_output_buffers(drive, pc, bcount.all);
++			idetape_output_buffers(drive, pc, bcount);
+ 		else
+ 			/* Write the current buffer */
+-			HWIF(drive)->atapi_output_bytes(drive, pc->current_position, bcount.all);
++			hwif->atapi_output_bytes(drive, pc->current_position,
++						 bcount);
+ 	} else {
+ 		if (pc->bh != NULL)
+-			idetape_input_buffers(drive, pc, bcount.all);
++			idetape_input_buffers(drive, pc, bcount);
+ 		else
+ 			/* Read the current buffer */
+-			HWIF(drive)->atapi_input_bytes(drive, pc->current_position, bcount.all);
++			hwif->atapi_input_bytes(drive, pc->current_position,
++						bcount);
+ 	}
+ 	/* Update the current position */
+-	pc->actually_transferred += bcount.all;
+-	pc->current_position += bcount.all;
++	pc->actually_transferred += bcount;
++	pc->current_position += bcount;
+ #if IDETAPE_DEBUG_LOG
+ 	if (tape->debug_level >= 2)
+-		printk(KERN_INFO "ide-tape: [cmd %x] transferred %d bytes on that interrupt\n", pc->c[0], bcount.all);
++		printk(KERN_INFO "ide-tape: [cmd %x] transferred %d bytes "
++				 "on that interrupt\n", pc->c[0], bcount);
+ #endif
+ 	/* And set the interrupt handler again */
+ 	ide_set_handler(drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL);
+@@ -2078,28 +2074,28 @@ static ide_startstop_t idetape_transfer_pc(ide_drive_t *drive)
+ 	ide_hwif_t *hwif = drive->hwif;
+ 	idetape_tape_t *tape = drive->driver_data;
+ 	idetape_pc_t *pc = tape->pc;
+-	atapi_ireason_t ireason;
+ 	int retries = 100;
+ 	ide_startstop_t startstop;
++	u8 ireason;
+ 
+ 	if (ide_wait_stat(&startstop,drive,DRQ_STAT,BUSY_STAT,WAIT_READY)) {
+ 		printk(KERN_ERR "ide-tape: Strange, packet command initiated yet DRQ isn't asserted\n");
+ 		return startstop;
+ 	}
+-	ireason.all = hwif->INB(IDE_IREASON_REG);
+-	while (retries-- && (!ireason.b.cod || ireason.b.io)) {
++	ireason = hwif->INB(IDE_IREASON_REG);
++	while (retries-- && ((ireason & CD) == 0 || (ireason & IO))) {
+ 		printk(KERN_ERR "ide-tape: (IO,CoD != (0,1) while issuing "
+ 				"a packet command, retrying\n");
+ 		udelay(100);
+-		ireason.all = hwif->INB(IDE_IREASON_REG);
++		ireason = hwif->INB(IDE_IREASON_REG);
+ 		if (retries == 0) {
+ 			printk(KERN_ERR "ide-tape: (IO,CoD != (0,1) while "
+ 					"issuing a packet command, ignoring\n");
+-			ireason.b.cod = 1;
+-			ireason.b.io = 0;
++			ireason |= CD;
++			ireason &= ~IO;
  		}
-+		up(&i2c_adapter_class.sem);
  	}
+-	if (!ireason.b.cod || ireason.b.io) {
++	if ((ireason & CD) == 0 || (ireason & IO)) {
+ 		printk(KERN_ERR "ide-tape: (IO,CoD) != (0,1) while issuing "
+ 				"a packet command\n");
+ 		return ide_do_reset(drive);
+@@ -2120,8 +2116,8 @@ static ide_startstop_t idetape_issue_packet_command (ide_drive_t *drive, idetape
+ {
+ 	ide_hwif_t *hwif = drive->hwif;
+ 	idetape_tape_t *tape = drive->driver_data;
+-	atapi_bcount_t bcount;
+ 	int dma_ok = 0;
++	u16 bcount;
  
--	mutex_unlock(&core_lists);
-+	mutex_unlock(&core_lock);
- 	return 0;
- }
- EXPORT_SYMBOL(i2c_register_driver);
-@@ -609,11 +682,11 @@ EXPORT_SYMBOL(i2c_register_driver);
-  */
- void i2c_del_driver(struct i2c_driver *driver)
+ #if IDETAPE_DEBUG_BUGS
+ 	if (tape->pc->c[0] == IDETAPE_REQUEST_SENSE_CMD &&
+@@ -2170,7 +2166,7 @@ static ide_startstop_t idetape_issue_packet_command (ide_drive_t *drive, idetape
+ 	pc->actually_transferred = 0;
+ 	pc->current_position = pc->buffer;
+ 	/* Request to transfer the entire buffer at once */
+-	bcount.all = pc->request_transfer;
++	bcount = pc->request_transfer;
+ 
+ 	if (test_and_clear_bit(PC_DMA_ERROR, &pc->flags)) {
+ 		printk(KERN_WARNING "ide-tape: DMA disabled, "
+@@ -2180,12 +2176,9 @@ static ide_startstop_t idetape_issue_packet_command (ide_drive_t *drive, idetape
+ 	if (test_bit(PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma)
+ 		dma_ok = !hwif->dma_setup(drive);
+ 
+-	if (IDE_CONTROL_REG)
+-		hwif->OUTB(drive->ctl, IDE_CONTROL_REG);
+-	hwif->OUTB(dma_ok ? 1 : 0, IDE_FEATURE_REG);	/* Use PIO/DMA */
+-	hwif->OUTB(bcount.b.high, IDE_BCOUNTH_REG);
+-	hwif->OUTB(bcount.b.low, IDE_BCOUNTL_REG);
+-	hwif->OUTB(drive->select.all, IDE_SELECT_REG);
++	ide_pktcmd_tf_load(drive, IDE_TFLAG_NO_SELECT_MASK |
++			   IDE_TFLAG_OUT_DEVICE, bcount, dma_ok);
++
+ 	if (dma_ok)			/* Will begin DMA later */
+ 		set_bit(PC_DMA_IN_PROGRESS, &pc->flags);
+ 	if (test_bit(IDETAPE_DRQ_INTERRUPT, &tape->flags)) {
+@@ -2295,11 +2288,11 @@ static ide_startstop_t idetape_media_access_finished (ide_drive_t *drive)
  {
--	struct list_head   *item1, *item2, *_n;
-+	struct list_head   *item2, *_n;
- 	struct i2c_client  *client;
- 	struct i2c_adapter *adap;
+ 	idetape_tape_t *tape = drive->driver_data;
+ 	idetape_pc_t *pc = tape->pc;
+-	atapi_status_t status;
++	u8 stat;
  
--	mutex_lock(&core_lists);
-+	mutex_lock(&core_lock);
+-	status.all = HWIF(drive)->INB(IDE_STATUS_REG);
+-	if (status.b.dsc) {
+-		if (status.b.check) {
++	stat = drive->hwif->INB(IDE_STATUS_REG);
++	if (stat & SEEK_STAT) {
++		if (stat & ERR_STAT) {
+ 			/* Error detected */
+ 			if (pc->c[0] != IDETAPE_TEST_UNIT_READY_CMD)
+ 				printk(KERN_ERR "ide-tape: %s: I/O error, ",
+@@ -2417,7 +2410,7 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive,
+ 	idetape_tape_t *tape = drive->driver_data;
+ 	idetape_pc_t *pc = NULL;
+ 	struct request *postponed_rq = tape->postponed_rq;
+-	atapi_status_t status;
++	u8 stat;
  
- 	/* new-style driver? */
- 	if (is_newstyle_driver(driver))
-@@ -623,8 +696,8 @@ void i2c_del_driver(struct i2c_driver *driver)
- 	 * attached. If so, detach them to be able to kill the driver
- 	 * afterwards.
+ #if IDETAPE_DEBUG_LOG
+ #if 0
+@@ -2465,7 +2458,7 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive,
+ 	 * If the tape is still busy, postpone our request and service
+ 	 * the other device meanwhile.
  	 */
--	list_for_each(item1,&adapters) {
--		adap = list_entry(item1, struct i2c_adapter, list);
-+	down(&i2c_adapter_class.sem);
-+	list_for_each_entry(adap, &i2c_adapter_class.devices, dev.node) {
- 		if (driver->detach_adapter) {
- 			if (driver->detach_adapter(adap)) {
- 				dev_err(&adap->dev, "detach_adapter failed "
-@@ -648,40 +721,31 @@ void i2c_del_driver(struct i2c_driver *driver)
- 			}
- 		}
+-	status.all = HWIF(drive)->INB(IDE_STATUS_REG);
++	stat = drive->hwif->INB(IDE_STATUS_REG);
+ 
+ 	if (!drive->dsc_overlap && !(rq->cmd[0] & REQ_IDETAPE_PC2))
+ 		set_bit(IDETAPE_IGNORE_DSC, &tape->flags);
+@@ -2481,7 +2474,7 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive,
+ 		tape->insert_speed = tape->insert_size / 1024 * HZ / (jiffies - tape->insert_time);
+ 	calculate_speeds(drive);
+ 	if (!test_and_clear_bit(IDETAPE_IGNORE_DSC, &tape->flags) &&
+-	    !status.b.dsc) {
++	    (stat & SEEK_STAT) == 0) {
+ 		if (postponed_rq == NULL) {
+ 			tape->dsc_polling_start = jiffies;
+ 			tape->dsc_polling_frequency = tape->best_dsc_rw_frequency;
+@@ -2502,9 +2495,6 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive,
  	}
-+	up(&i2c_adapter_class.sem);
+ 	if (rq->cmd[0] & REQ_IDETAPE_READ) {
+ 		tape->buffer_head++;
+-#if USE_IOTRACE
+-		IO_trace(IO_IDETAPE_FIFO, tape->pipeline_head, tape->buffer_head, tape->tape_head, tape->minor);
+-#endif
+ 		tape->postpone_cnt = 0;
+ 		pc = idetape_next_pc_storage(drive);
+ 		idetape_create_read_cmd(tape, pc, rq->current_nr_sectors, (struct idetape_bh *)rq->special);
+@@ -2512,9 +2502,6 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive,
+ 	}
+ 	if (rq->cmd[0] & REQ_IDETAPE_WRITE) {
+ 		tape->buffer_head++;
+-#if USE_IOTRACE
+-		IO_trace(IO_IDETAPE_FIFO, tape->pipeline_head, tape->buffer_head, tape->tape_head, tape->minor);
+-#endif
+ 		tape->postpone_cnt = 0;
+ 		pc = idetape_next_pc_storage(drive);
+ 		idetape_create_write_cmd(tape, pc, rq->current_nr_sectors, (struct idetape_bh *)rq->special);
+@@ -3241,9 +3228,6 @@ static int idetape_add_chrdev_write_request (ide_drive_t *drive, int blocks)
+ 	idetape_switch_buffers(tape, new_stage);
+ 	idetape_add_stage_tail(drive, new_stage);
+ 	tape->pipeline_head++;
+-#if USE_IOTRACE
+-	IO_trace(IO_IDETAPE_FIFO, tape->pipeline_head, tape->buffer_head, tape->tape_head, tape->minor);
+-#endif
+ 	calculate_speeds(drive);
  
-  unregister:
- 	driver_unregister(&driver->driver);
--	list_del(&driver->list);
- 	pr_debug("i2c-core: driver [%s] unregistered\n", driver->driver.name);
+ 	/*
+@@ -3493,9 +3477,6 @@ static int idetape_add_chrdev_read_request (ide_drive_t *drive,int blocks)
+ 		idetape_remove_stage_head(drive);
+ 		spin_unlock_irqrestore(&tape->spinlock, flags);
+ 		tape->pipeline_head++;
+-#if USE_IOTRACE
+-		IO_trace(IO_IDETAPE_FIFO, tape->pipeline_head, tape->buffer_head, tape->tape_head, tape->minor);
+-#endif
+ 		calculate_speeds(drive);
+ 	}
+ #if IDETAPE_DEBUG_BUGS
+@@ -4724,10 +4705,8 @@ static void ide_tape_release(struct kref *kref)
  
--	mutex_unlock(&core_lists);
-+	mutex_unlock(&core_lock);
- }
- EXPORT_SYMBOL(i2c_del_driver);
+ 	drive->dsc_overlap = 0;
+ 	drive->driver_data = NULL;
+-	class_device_destroy(idetape_sysfs_class,
+-			MKDEV(IDETAPE_MAJOR, tape->minor));
+-	class_device_destroy(idetape_sysfs_class,
+-			MKDEV(IDETAPE_MAJOR, tape->minor + 128));
++	device_destroy(idetape_sysfs_class, MKDEV(IDETAPE_MAJOR, tape->minor));
++	device_destroy(idetape_sysfs_class, MKDEV(IDETAPE_MAJOR, tape->minor + 128));
+ 	idetape_devs[tape->minor] = NULL;
+ 	g->private_data = NULL;
+ 	put_disk(g);
+@@ -4884,10 +4863,10 @@ static int ide_tape_probe(ide_drive_t *drive)
  
- /* ------------------------------------------------------------------------- */
+ 	idetape_setup(drive, tape, minor);
  
--static int __i2c_check_addr(struct i2c_adapter *adapter, unsigned int addr)
-+static int __i2c_check_addr(struct device *dev, void *addrp)
- {
--	struct list_head   *item;
--	struct i2c_client  *client;
-+	struct i2c_client	*client = i2c_verify_client(dev);
-+	int			addr = *(int *)addrp;
+-	class_device_create(idetape_sysfs_class, NULL,
+-			MKDEV(IDETAPE_MAJOR, minor), &drive->gendev, "%s", tape->name);
+-	class_device_create(idetape_sysfs_class, NULL,
+-			MKDEV(IDETAPE_MAJOR, minor + 128), &drive->gendev, "n%s", tape->name);
++	device_create(idetape_sysfs_class, &drive->gendev,
++		      MKDEV(IDETAPE_MAJOR, minor), "%s", tape->name);
++	device_create(idetape_sysfs_class, &drive->gendev,
++			MKDEV(IDETAPE_MAJOR, minor + 128), "n%s", tape->name);
  
--	list_for_each(item,&adapter->clients) {
--		client = list_entry(item, struct i2c_client, list);
--		if (client->addr == addr)
--			return -EBUSY;
--	}
-+	if (client && client->addr == addr)
-+		return -EBUSY;
- 	return 0;
- }
+ 	g->fops = &idetape_block_ops;
+ 	ide_register_region(g);
+diff --git a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c
+index 2b60f1b..5eb6fa1 100644
+--- a/drivers/ide/ide-taskfile.c
++++ b/drivers/ide/ide-taskfile.c
+@@ -35,93 +35,81 @@
+ #include <asm/uaccess.h>
+ #include <asm/io.h>
  
- static int i2c_check_addr(struct i2c_adapter *adapter, int addr)
+-static void ata_bswap_data (void *buffer, int wcount)
++void ide_tf_load(ide_drive_t *drive, ide_task_t *task)
  {
--	int rval;
--
--	mutex_lock(&adapter->clist_lock);
--	rval = __i2c_check_addr(adapter, addr);
--	mutex_unlock(&adapter->clist_lock);
+-	u16 *p = buffer;
 -
--	return rval;
-+	return device_for_each_child(&adapter->dev, &addr, __i2c_check_addr);
- }
- 
- int i2c_attach_client(struct i2c_client *client)
-@@ -689,15 +753,6 @@ int i2c_attach_client(struct i2c_client *client)
- 	struct i2c_adapter *adapter = client->adapter;
- 	int res = 0;
- 
--	mutex_lock(&adapter->clist_lock);
--	if (__i2c_check_addr(client->adapter, client->addr)) {
--		res = -EBUSY;
--		goto out_unlock;
+-	while (wcount--) {
+-		*p = *p << 8 | *p >> 8; p++;
+-		*p = *p << 8 | *p >> 8; p++;
 -	}
--	list_add_tail(&client->list,&adapter->clients);
--
--	client->usage_count = 0;
+-}
 -
- 	client->dev.parent = &client->adapter->dev;
- 	client->dev.bus = &i2c_bus_type;
- 
-@@ -712,13 +767,17 @@ int i2c_attach_client(struct i2c_client *client)
- 
- 	snprintf(&client->dev.bus_id[0], sizeof(client->dev.bus_id),
- 		"%d-%04x", i2c_adapter_id(adapter), client->addr);
--	dev_dbg(&adapter->dev, "client [%s] registered with bus id %s\n",
--		client->name, client->dev.bus_id);
- 	res = device_register(&client->dev);
- 	if (res)
--		goto out_list;
-+		goto out_err;
+-static void taskfile_input_data(ide_drive_t *drive, void *buffer, u32 wcount)
+-{
+-	HWIF(drive)->ata_input_data(drive, buffer, wcount);
+-	if (drive->bswap)
+-		ata_bswap_data(buffer, wcount);
+-}
++	ide_hwif_t *hwif = drive->hwif;
++	struct ide_taskfile *tf = &task->tf;
++	u8 HIHI = (task->tf_flags & IDE_TFLAG_LBA48) ? 0xE0 : 0xEF;
 +
-+	mutex_lock(&adapter->clist_lock);
-+	list_add_tail(&client->list, &adapter->clients);
- 	mutex_unlock(&adapter->clist_lock);
- 
-+	dev_dbg(&adapter->dev, "client [%s] registered with bus id %s\n",
-+		client->name, client->dev.bus_id);
++	if (task->tf_flags & IDE_TFLAG_FLAGGED)
++		HIHI = 0xFF;
 +
- 	if (adapter->client_register)  {
- 		if (adapter->client_register(client)) {
- 			dev_dbg(&adapter->dev, "client_register "
-@@ -729,12 +788,9 @@ int i2c_attach_client(struct i2c_client *client)
- 
- 	return 0;
- 
--out_list:
--	list_del(&client->list);
-+out_err:
- 	dev_err(&adapter->dev, "Failed to attach i2c client %s at 0x%02x "
- 		"(%d)\n", client->name, client->addr, res);
--out_unlock:
--	mutex_unlock(&adapter->clist_lock);
- 	return res;
- }
- EXPORT_SYMBOL(i2c_attach_client);
-@@ -744,12 +800,6 @@ int i2c_detach_client(struct i2c_client *client)
- 	struct i2c_adapter *adapter = client->adapter;
- 	int res = 0;
++#ifdef DEBUG
++	printk("%s: tf: feat 0x%02x nsect 0x%02x lbal 0x%02x "
++		"lbam 0x%02x lbah 0x%02x dev 0x%02x cmd 0x%02x\n",
++		drive->name, tf->feature, tf->nsect, tf->lbal,
++		tf->lbam, tf->lbah, tf->device, tf->command);
++	printk("%s: hob: nsect 0x%02x lbal 0x%02x "
++		"lbam 0x%02x lbah 0x%02x\n",
++		drive->name, tf->hob_nsect, tf->hob_lbal,
++		tf->hob_lbam, tf->hob_lbah);
++#endif
  
--	if (client->usage_count > 0) {
--		dev_warn(&client->dev, "Client [%s] still busy, "
--			 "can't detach\n", client->name);
--		return -EBUSY;
+-static void taskfile_output_data(ide_drive_t *drive, void *buffer, u32 wcount)
+-{
+-	if (drive->bswap) {
+-		ata_bswap_data(buffer, wcount);
+-		HWIF(drive)->ata_output_data(drive, buffer, wcount);
+-		ata_bswap_data(buffer, wcount);
+-	} else {
+-		HWIF(drive)->ata_output_data(drive, buffer, wcount);
 -	}
--
- 	if (adapter->client_unregister)  {
- 		res = adapter->client_unregister(client);
- 		if (res) {
-@@ -762,9 +812,10 @@ int i2c_detach_client(struct i2c_client *client)
- 
- 	mutex_lock(&adapter->clist_lock);
- 	list_del(&client->list);
-+	mutex_unlock(&adapter->clist_lock);
++	ide_set_irq(drive, 1);
 +
- 	init_completion(&client->released);
- 	device_unregister(&client->dev);
--	mutex_unlock(&adapter->clist_lock);
- 	wait_for_completion(&client->released);
++	if ((task->tf_flags & IDE_TFLAG_NO_SELECT_MASK) == 0)
++		SELECT_MASK(drive, 0);
++
++	if (task->tf_flags & IDE_TFLAG_OUT_DATA)
++		hwif->OUTW((tf->hob_data << 8) | tf->data, IDE_DATA_REG);
++
++	if (task->tf_flags & IDE_TFLAG_OUT_HOB_FEATURE)
++		hwif->OUTB(tf->hob_feature, IDE_FEATURE_REG);
++	if (task->tf_flags & IDE_TFLAG_OUT_HOB_NSECT)
++		hwif->OUTB(tf->hob_nsect, IDE_NSECTOR_REG);
++	if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAL)
++		hwif->OUTB(tf->hob_lbal, IDE_SECTOR_REG);
++	if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAM)
++		hwif->OUTB(tf->hob_lbam, IDE_LCYL_REG);
++	if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAH)
++		hwif->OUTB(tf->hob_lbah, IDE_HCYL_REG);
++
++	if (task->tf_flags & IDE_TFLAG_OUT_FEATURE)
++		hwif->OUTB(tf->feature, IDE_FEATURE_REG);
++	if (task->tf_flags & IDE_TFLAG_OUT_NSECT)
++		hwif->OUTB(tf->nsect, IDE_NSECTOR_REG);
++	if (task->tf_flags & IDE_TFLAG_OUT_LBAL)
++		hwif->OUTB(tf->lbal, IDE_SECTOR_REG);
++	if (task->tf_flags & IDE_TFLAG_OUT_LBAM)
++		hwif->OUTB(tf->lbam, IDE_LCYL_REG);
++	if (task->tf_flags & IDE_TFLAG_OUT_LBAH)
++		hwif->OUTB(tf->lbah, IDE_HCYL_REG);
++
++	if (task->tf_flags & IDE_TFLAG_OUT_DEVICE)
++		hwif->OUTB((tf->device & HIHI) | drive->select.all, IDE_SELECT_REG);
+ }
  
-  out:
-@@ -772,72 +823,58 @@ int i2c_detach_client(struct i2c_client *client)
+ int taskfile_lib_get_identify (ide_drive_t *drive, u8 *buf)
+ {
+ 	ide_task_t args;
++
+ 	memset(&args, 0, sizeof(ide_task_t));
+-	args.tfRegister[IDE_NSECTOR_OFFSET]	= 0x01;
++	args.tf.nsect = 0x01;
+ 	if (drive->media == ide_disk)
+-		args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_IDENTIFY;
++		args.tf.command = WIN_IDENTIFY;
+ 	else
+-		args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_PIDENTIFY;
+-	args.command_type = IDE_DRIVE_TASK_IN;
+-	args.data_phase   = TASKFILE_IN;
+-	args.handler	  = &task_in_intr;
+-	return ide_raw_taskfile(drive, &args, buf);
++		args.tf.command = WIN_PIDENTIFY;
++	args.tf_flags	= IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
++	args.data_phase	= TASKFILE_IN;
++	return ide_raw_taskfile(drive, &args, buf, 1);
  }
- EXPORT_SYMBOL(i2c_detach_client);
  
--static int i2c_inc_use_client(struct i2c_client *client)
-+/**
-+ * i2c_use_client - increments the reference count of the i2c client structure
-+ * @client: the client being referenced
-+ *
-+ * Each live reference to a client should be refcounted. The driver model does
-+ * that automatically as part of driver binding, so that most drivers don't
-+ * need to do this explicitly: they hold a reference until they're unbound
-+ * from the device.
-+ *
-+ * A pointer to the client with the incremented reference counter is returned.
-+ */
-+struct i2c_client *i2c_use_client(struct i2c_client *client)
+-ide_startstop_t do_rw_taskfile (ide_drive_t *drive, ide_task_t *task)
++static int inline task_dma_ok(ide_task_t *task)
  {
+-	ide_hwif_t *hwif	= HWIF(drive);
+-	task_struct_t *taskfile	= (task_struct_t *) task->tfRegister;
+-	hob_struct_t *hobfile	= (hob_struct_t *) task->hobRegister;
+-	u8 HIHI			= (drive->addressing == 1) ? 0xE0 : 0xEF;
 -
--	if (!try_module_get(client->driver->driver.owner))
--		return -ENODEV;
--	if (!try_module_get(client->adapter->owner)) {
--		module_put(client->driver->driver.owner);
--		return -ENODEV;
+-	/* ALL Command Block Executions SHALL clear nIEN, unless otherwise */
+-	if (IDE_CONTROL_REG) {
+-		/* clear nIEN */
+-		hwif->OUTB(drive->ctl, IDE_CONTROL_REG);
 -	}
+-	SELECT_MASK(drive, 0);
 -
--	return 0;
-+	get_device(&client->dev);
-+	return client;
- }
-+EXPORT_SYMBOL(i2c_use_client);
- 
--static void i2c_dec_use_client(struct i2c_client *client)
-+/**
-+ * i2c_release_client - release a use of the i2c client structure
-+ * @client: the client being no longer referenced
-+ *
-+ * Must be called when a user of a client is finished with it.
-+ */
-+void i2c_release_client(struct i2c_client *client)
- {
--	module_put(client->driver->driver.owner);
--	module_put(client->adapter->owner);
-+	put_device(&client->dev);
- }
-+EXPORT_SYMBOL(i2c_release_client);
- 
--int i2c_use_client(struct i2c_client *client)
--{
--	int ret;
+-	if (drive->addressing == 1) {
+-		hwif->OUTB(hobfile->feature, IDE_FEATURE_REG);
+-		hwif->OUTB(hobfile->sector_count, IDE_NSECTOR_REG);
+-		hwif->OUTB(hobfile->sector_number, IDE_SECTOR_REG);
+-		hwif->OUTB(hobfile->low_cylinder, IDE_LCYL_REG);
+-		hwif->OUTB(hobfile->high_cylinder, IDE_HCYL_REG);
+-	}
 -
--	ret = i2c_inc_use_client(client);
--	if (ret)
--		return ret;
+-	hwif->OUTB(taskfile->feature, IDE_FEATURE_REG);
+-	hwif->OUTB(taskfile->sector_count, IDE_NSECTOR_REG);
+-	hwif->OUTB(taskfile->sector_number, IDE_SECTOR_REG);
+-	hwif->OUTB(taskfile->low_cylinder, IDE_LCYL_REG);
+-	hwif->OUTB(taskfile->high_cylinder, IDE_HCYL_REG);
 -
--	client->usage_count++;
+-	hwif->OUTB((taskfile->device_head & HIHI) | drive->select.all, IDE_SELECT_REG);
 -
--	return 0;
--}
--EXPORT_SYMBOL(i2c_use_client);
-+struct i2c_cmd_arg {
-+	unsigned	cmd;
-+	void		*arg;
-+};
- 
--int i2c_release_client(struct i2c_client *client)
-+static int i2c_cmd(struct device *dev, void *_arg)
- {
--	if (!client->usage_count) {
--		pr_debug("i2c-core: %s used one too many times\n",
--			 __FUNCTION__);
--		return -EPERM;
+-	if (task->handler != NULL) {
+-		if (task->prehandler != NULL) {
+-			hwif->OUTBSYNC(drive, taskfile->command, IDE_COMMAND_REG);
+-			ndelay(400);	/* FIXME */
+-			return task->prehandler(drive, task->rq);
+-		}
+-		ide_execute_command(drive, taskfile->command, task->handler, WAIT_WORSTCASE, NULL);
+-		return ide_started;
 -	}
--
--	client->usage_count--;
--	i2c_dec_use_client(client);
-+	struct i2c_client	*client = i2c_verify_client(dev);
-+	struct i2c_cmd_arg	*arg = _arg;
- 
-+	if (client && client->driver && client->driver->command)
-+		client->driver->command(client, arg->cmd, arg->arg);
- 	return 0;
- }
--EXPORT_SYMBOL(i2c_release_client);
- 
- void i2c_clients_command(struct i2c_adapter *adap, unsigned int cmd, void *arg)
- {
--	struct list_head  *item;
--	struct i2c_client *client;
-+	struct i2c_cmd_arg	cmd_arg;
++	if (blk_fs_request(task->rq) || (task->tf_flags & IDE_TFLAG_FLAGGED))
++		return 1;
  
--	mutex_lock(&adap->clist_lock);
--	list_for_each(item,&adap->clients) {
--		client = list_entry(item, struct i2c_client, list);
--		if (!try_module_get(client->driver->driver.owner))
--			continue;
--		if (NULL != client->driver->command) {
--			mutex_unlock(&adap->clist_lock);
--			client->driver->command(client,cmd,arg);
--			mutex_lock(&adap->clist_lock);
--		}
--		module_put(client->driver->driver.owner);
--       }
--       mutex_unlock(&adap->clist_lock);
-+	cmd_arg.cmd = cmd;
-+	cmd_arg.arg = arg;
-+	device_for_each_child(&adap->dev, &cmd_arg, i2c_cmd);
- }
- EXPORT_SYMBOL(i2c_clients_command);
+-	if (!drive->using_dma)
+-		return ide_stopped;
+-
+-	switch (taskfile->command) {
++	switch (task->tf.command) {
+ 		case WIN_WRITEDMA_ONCE:
+ 		case WIN_WRITEDMA:
+ 		case WIN_WRITEDMA_EXT:
+@@ -129,24 +117,79 @@ ide_startstop_t do_rw_taskfile (ide_drive_t *drive, ide_task_t *task)
+ 		case WIN_READDMA:
+ 		case WIN_READDMA_EXT:
+ 		case WIN_IDENTIFY_DMA:
+-			if (!hwif->dma_setup(drive)) {
+-				hwif->dma_exec_cmd(drive, taskfile->command);
+-				hwif->dma_start(drive);
+-				return ide_started;
+-			}
+-			break;
+-		default:
+-			if (task->handler == NULL)
+-				return ide_stopped;
++			return 1;
+ 	}
  
-@@ -848,11 +885,24 @@ static int __init i2c_init(void)
- 	retval = bus_register(&i2c_bus_type);
- 	if (retval)
- 		return retval;
--	return class_register(&i2c_adapter_class);
-+	retval = class_register(&i2c_adapter_class);
-+	if (retval)
-+		goto bus_err;
-+	retval = i2c_add_driver(&dummy_driver);
-+	if (retval)
-+		goto class_err;
+-	return ide_stopped;
 +	return 0;
-+
-+class_err:
-+	class_unregister(&i2c_adapter_class);
-+bus_err:
-+	bus_unregister(&i2c_bus_type);
-+	return retval;
- }
- 
- static void __exit i2c_exit(void)
- {
-+	i2c_del_driver(&dummy_driver);
- 	class_unregister(&i2c_adapter_class);
- 	bus_unregister(&i2c_bus_type);
  }
-@@ -879,7 +929,15 @@ int i2c_transfer(struct i2c_adapter * adap, struct i2c_msg *msgs, int num)
- 		}
- #endif
  
--		mutex_lock_nested(&adap->bus_lock, adap->level);
-+		if (in_atomic() || irqs_disabled()) {
-+			ret = mutex_trylock(&adap->bus_lock);
-+			if (!ret)
-+				/* I2C activity is ongoing. */
-+				return -EAGAIN;
-+		} else {
-+			mutex_lock_nested(&adap->bus_lock, adap->level);
++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 *);
++
++ide_startstop_t do_rw_taskfile (ide_drive_t *drive, ide_task_t *task)
++{
++	ide_hwif_t *hwif	= HWIF(drive);
++	struct ide_taskfile *tf = &task->tf;
++	ide_handler_t *handler = NULL;
++
++	if (task->data_phase == TASKFILE_MULTI_IN ||
++	    task->data_phase == TASKFILE_MULTI_OUT) {
++		if (!drive->mult_count) {
++			printk(KERN_ERR "%s: multimode not set!\n",
++					drive->name);
++			return ide_stopped;
 +		}
++	}
 +
- 		ret = adap->algo->master_xfer(adap,msgs,num);
- 		mutex_unlock(&adap->bus_lock);
- 
-@@ -978,7 +1036,7 @@ static int i2c_probe_address(struct i2c_adapter *adapter, int addr, int kind,
++	if (task->tf_flags & IDE_TFLAG_FLAGGED)
++		task->tf_flags |= IDE_TFLAG_FLAGGED_SET_IN_FLAGS;
++
++	if ((task->tf_flags & IDE_TFLAG_DMA_PIO_FALLBACK) == 0)
++		ide_tf_load(drive, task);
++
++	switch (task->data_phase) {
++	case TASKFILE_MULTI_OUT:
++	case TASKFILE_OUT:
++		hwif->OUTBSYNC(drive, tf->command, IDE_COMMAND_REG);
++		ndelay(400);	/* FIXME */
++		return pre_task_out_intr(drive, task->rq);
++	case TASKFILE_MULTI_IN:
++	case TASKFILE_IN:
++		handler = task_in_intr;
++		/* fall-through */
++	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 (task_dma_ok(task) == 0 || drive->using_dma == 0 ||
++		    hwif->dma_setup(drive))
++			return ide_stopped;
++		hwif->dma_exec_cmd(drive, tf->command);
++		hwif->dma_start(drive);
++		return ide_started;
++	}
++}
++EXPORT_SYMBOL_GPL(do_rw_taskfile);
++
+ /*
+  * set_multmode_intr() is invoked on completion of a WIN_SETMULT cmd.
+  */
+-ide_startstop_t set_multmode_intr (ide_drive_t *drive)
++static ide_startstop_t set_multmode_intr(ide_drive_t *drive)
+ {
+ 	ide_hwif_t *hwif = HWIF(drive);
+ 	u8 stat;
+@@ -164,7 +207,7 @@ ide_startstop_t set_multmode_intr (ide_drive_t *drive)
+ /*
+  * set_geometry_intr() is invoked on completion of a WIN_SPECIFY cmd.
+  */
+-ide_startstop_t set_geometry_intr (ide_drive_t *drive)
++static ide_startstop_t set_geometry_intr(ide_drive_t *drive)
+ {
+ 	ide_hwif_t *hwif = HWIF(drive);
+ 	int retries = 5;
+@@ -187,7 +230,7 @@ ide_startstop_t set_geometry_intr (ide_drive_t *drive)
+ /*
+  * recal_intr() is invoked on completion of a WIN_RESTORE (recalibrate) cmd.
+  */
+-ide_startstop_t recal_intr (ide_drive_t *drive)
++static ide_startstop_t recal_intr(ide_drive_t *drive)
+ {
+ 	ide_hwif_t *hwif = HWIF(drive);
+ 	u8 stat;
+@@ -200,7 +243,7 @@ ide_startstop_t recal_intr (ide_drive_t *drive)
+ /*
+  * Handler for commands without a data phase
+  */
+-ide_startstop_t task_no_data_intr (ide_drive_t *drive)
++static ide_startstop_t task_no_data_intr(ide_drive_t *drive)
+ {
+ 	ide_task_t *args	= HWGROUP(drive)->rq->special;
+ 	ide_hwif_t *hwif	= HWIF(drive);
+@@ -217,9 +260,7 @@ ide_startstop_t task_no_data_intr (ide_drive_t *drive)
+ 	return ide_stopped;
  }
  
- int i2c_probe(struct i2c_adapter *adapter,
--	      struct i2c_client_address_data *address_data,
-+	      const struct i2c_client_address_data *address_data,
- 	      int (*found_proc) (struct i2c_adapter *, int, int))
+-EXPORT_SYMBOL(task_no_data_intr);
+-
+-static u8 wait_drive_not_busy(ide_drive_t *drive)
++u8 wait_drive_not_busy(ide_drive_t *drive)
  {
- 	int i, err;
-@@ -987,7 +1045,7 @@ int i2c_probe(struct i2c_adapter *adapter,
- 	/* Force entries are done first, and are not affected by ignore
- 	   entries */
- 	if (address_data->forces) {
--		unsigned short **forces = address_data->forces;
-+		const unsigned short * const *forces = address_data->forces;
- 		int kind;
- 
- 		for (kind = 0; forces[kind]; kind++) {
-@@ -1085,7 +1143,6 @@ i2c_new_probed_device(struct i2c_adapter *adap,
- 		return NULL;
- 	}
+ 	ide_hwif_t *hwif = HWIF(drive);
+ 	int retries;
+@@ -227,8 +268,7 @@ static u8 wait_drive_not_busy(ide_drive_t *drive)
  
--	mutex_lock(&adap->clist_lock);
- 	for (i = 0; addr_list[i] != I2C_CLIENT_END; i++) {
- 		/* Check address validity */
- 		if (addr_list[i] < 0x03 || addr_list[i] > 0x77) {
-@@ -1095,7 +1152,7 @@ i2c_new_probed_device(struct i2c_adapter *adap,
- 		}
+ 	/*
+ 	 * Last sector was transfered, wait until drive is ready.
+-	 * This can take up to 10 usec, but we will wait max 1 ms
+-	 * (drive_cmd_intr() waits that long).
++	 * This can take up to 10 usec, but we will wait max 1 ms.
+ 	 */
+ 	for (retries = 0; retries < 100; retries++) {
+ 		if ((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT)
+@@ -283,9 +323,9 @@ static void ide_pio_sector(ide_drive_t *drive, unsigned int write)
  
- 		/* Check address availability */
--		if (__i2c_check_addr(adap, addr_list[i])) {
-+		if (i2c_check_addr(adap, addr_list[i])) {
- 			dev_dbg(&adap->dev, "Address 0x%02x already in "
- 				"use, not probing\n", addr_list[i]);
- 			continue;
-@@ -1123,7 +1180,6 @@ i2c_new_probed_device(struct i2c_adapter *adap,
- 				break;
- 		}
- 	}
--	mutex_unlock(&adap->clist_lock);
+ 	/* do the actual data transfer */
+ 	if (write)
+-		taskfile_output_data(drive, buf, SECTOR_WORDS);
++		hwif->ata_output_data(drive, buf, SECTOR_WORDS);
+ 	else
+-		taskfile_input_data(drive, buf, SECTOR_WORDS);
++		hwif->ata_input_data(drive, buf, SECTOR_WORDS);
  
- 	if (addr_list[i] == I2C_CLIENT_END) {
- 		dev_dbg(&adap->dev, "Probing failed, no device found\n");
-@@ -1139,12 +1195,12 @@ struct i2c_adapter* i2c_get_adapter(int id)
+ 	kunmap_atomic(buf, KM_BIO_SRC_IRQ);
+ #ifdef CONFIG_HIGHMEM
+@@ -305,9 +345,18 @@ static void ide_pio_multi(ide_drive_t *drive, unsigned int write)
+ static void ide_pio_datablock(ide_drive_t *drive, struct request *rq,
+ 				     unsigned int write)
  {
- 	struct i2c_adapter *adapter;
- 
--	mutex_lock(&core_lists);
-+	mutex_lock(&core_lock);
- 	adapter = (struct i2c_adapter *)idr_find(&i2c_adapter_idr, id);
- 	if (adapter && !try_module_get(adapter->owner))
- 		adapter = NULL;
- 
--	mutex_unlock(&core_lists);
-+	mutex_unlock(&core_lock);
- 	return adapter;
- }
- EXPORT_SYMBOL(i2c_get_adapter);
-diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c
-index df540d5..393e679 100644
---- a/drivers/i2c/i2c-dev.c
-+++ b/drivers/i2c/i2c-dev.c
-@@ -182,27 +182,22 @@ static ssize_t i2cdev_write (struct file *file, const char __user *buf, size_t c
- 	return ret;
- }
++	u8 saved_io_32bit = drive->io_32bit;
++
+ 	if (rq->bio)	/* fs request */
+ 		rq->errors = 0;
  
-+static int i2cdev_check(struct device *dev, void *addrp)
-+{
-+	struct i2c_client *client = i2c_verify_client(dev);
++	if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) {
++		ide_task_t *task = rq->special;
 +
-+	if (!client || client->addr != *(unsigned int *)addrp)
-+		return 0;
++		if (task->tf_flags & IDE_TFLAG_IO_16BIT)
++			drive->io_32bit = 0;
++	}
 +
-+	return dev->driver ? -EBUSY : 0;
-+}
+ 	touch_softlockup_watchdog();
+ 
+ 	switch (drive->hwif->data_phase) {
+@@ -319,6 +368,8 @@ static void ide_pio_datablock(ide_drive_t *drive, struct request *rq,
+ 		ide_pio_sector(drive, write);
+ 		break;
+ 	}
 +
- /* This address checking function differs from the one in i2c-core
-    in that it considers an address with a registered device, but no
--   bound driver, as NOT busy. */
-+   driver bound to it, as NOT busy. */
- static int i2cdev_check_addr(struct i2c_adapter *adapter, unsigned int addr)
- {
--	struct list_head *item;
--	struct i2c_client *client;
--	int res = 0;
--
--	mutex_lock(&adapter->clist_lock);
--	list_for_each(item, &adapter->clients) {
--		client = list_entry(item, struct i2c_client, list);
--		if (client->addr == addr) {
--			if (client->driver)
--				res = -EBUSY;
--			break;
--		}
--	}
--	mutex_unlock(&adapter->clist_lock);
--
--	return res;
-+	return device_for_each_child(&adapter->dev, &addr, i2cdev_check);
++	drive->io_32bit = saved_io_32bit;
  }
  
- static int i2cdev_ioctl(struct inode *inode, struct file *file,
-diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig
-index fb06555..64df55e 100644
---- a/drivers/ide/Kconfig
-+++ b/drivers/ide/Kconfig
-@@ -325,7 +325,7 @@ config BLK_DEV_PLATFORM
- 	  If unsure, say N.
- 
- config BLK_DEV_CMD640
--	bool "CMD640 chipset bugfix/support"
-+	tristate "CMD640 chipset bugfix/support"
- 	depends on X86
- 	---help---
- 	  The CMD-Technologies CMD640 IDE chip is used on many common 486 and
-@@ -359,9 +359,8 @@ config BLK_DEV_CMD640_ENHANCED
- 	  Otherwise say N.
- 
- config BLK_DEV_IDEPNP
--	bool "PNP EIDE support"
-+	tristate "PNP EIDE support"
- 	depends on PNP
--	select IDE_GENERIC
- 	help
- 	  If you have a PnP (Plug and Play) compatible EIDE card and
- 	  would like the kernel to automatically detect and activate
-@@ -374,19 +373,20 @@ comment "PCI IDE chipsets support"
- config BLK_DEV_IDEPCI
- 	bool
+ static ide_startstop_t task_error(ide_drive_t *drive, struct request *rq,
+@@ -356,40 +407,35 @@ static ide_startstop_t task_error(ide_drive_t *drive, struct request *rq,
+ 	return ide_error(drive, s, stat);
+ }
  
--config IDEPCI_SHARE_IRQ
--	bool "Sharing PCI IDE interrupts support"
--	depends on BLK_DEV_IDEPCI
-+config IDEPCI_PCIBUS_ORDER
-+	bool "Probe IDE PCI devices in the PCI bus order (DEPRECATED)"
-+	depends on BLK_DEV_IDE=y && BLK_DEV_IDEPCI
-+	default y
- 	help
--	  Some ATA/IDE chipsets have hardware support which allows for
--	  sharing a single IRQ with other cards. To enable support for
--	  this in the ATA/IDE driver, say Y here.
-+	  Probe IDE PCI devices in the order in which they appear on the
-+	  PCI bus (i.e. 00:1f.1 PCI device before 02:01.0 PCI device)
-+	  instead of the order in which IDE PCI host drivers are loaded.
+-static void task_end_request(ide_drive_t *drive, struct request *rq, u8 stat)
++void task_end_request(ide_drive_t *drive, struct request *rq, u8 stat)
+ {
+-	HWIF(drive)->cursg = NULL;
+-
+ 	if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) {
+-		ide_task_t *task = rq->special;
++		u8 err = drive->hwif->INB(IDE_ERROR_REG);
  
--	  It is safe to say Y to this question, in most cases.
--	  If unsure, say N.
-+	  Please note that this method of assuring stable naming of
-+	  IDE devices is unreliable and use other means for achieving
-+	  it (i.e. udev).
+-		if (task->tf_out_flags.all) {
+-			u8 err = drive->hwif->INB(IDE_ERROR_REG);
+-			ide_end_drive_cmd(drive, stat, err);
+-			return;
+-		}
++		ide_end_drive_cmd(drive, stat, err);
++		return;
+ 	}
  
--config IDEPCI_PCIBUS_ORDER
--	def_bool BLK_DEV_IDE=y && BLK_DEV_IDEPCI
-+	  If in doubt, say N.
+ 	if (rq->rq_disk) {
+ 		ide_driver_t *drv;
  
- # TODO: split it on per host driver config options (or module parameters)
- config BLK_DEV_OFFBOARD
-@@ -707,7 +707,6 @@ config BLK_DEV_SVWKS
- config BLK_DEV_SGIIOC4
- 	tristate "Silicon Graphics IOC4 chipset ATA/ATAPI support"
- 	depends on (IA64_SGI_SN2 || IA64_GENERIC) && SGI_IOC4
--	select IDEPCI_SHARE_IRQ
- 	select BLK_DEV_IDEDMA_PCI
- 	help
- 	  This driver adds PIO & MultiMode DMA-2 support for the SGI IOC4
-@@ -801,7 +800,7 @@ config BLK_DEV_CELLEB
- endif
+ 		drv = *(ide_driver_t **)rq->rq_disk->private_data;;
+-		drv->end_request(drive, 1, rq->hard_nr_sectors);
++		drv->end_request(drive, 1, rq->nr_sectors);
+ 	} else
+-		ide_end_request(drive, 1, rq->hard_nr_sectors);
++		ide_end_request(drive, 1, rq->nr_sectors);
+ }
  
- config BLK_DEV_IDE_PMAC
--	bool "Builtin PowerMac IDE support"
-+	tristate "Builtin PowerMac IDE support"
- 	depends on PPC_PMAC && IDE=y && BLK_DEV_IDE=y
- 	help
- 	  This driver provides support for the built-in IDE controller on
-@@ -855,8 +854,9 @@ config BLK_DEV_IDE_AU1XXX_SEQTS_PER_RQ
-        depends on BLK_DEV_IDE_AU1XXX
+ /*
+  * Handler for command with PIO data-in phase (Read/Read Multiple).
+  */
+-ide_startstop_t task_in_intr (ide_drive_t *drive)
++static ide_startstop_t task_in_intr(ide_drive_t *drive)
+ {
+ 	ide_hwif_t *hwif = drive->hwif;
+ 	struct request *rq = HWGROUP(drive)->rq;
+ 	u8 stat = hwif->INB(IDE_STATUS_REG);
  
- config IDE_ARM
--	def_bool ARM && (ARCH_CLPS7500 || ARCH_RPC || ARCH_SHARK)
--	select IDE_GENERIC
-+	tristate "ARM IDE support"
-+	depends on ARM && (ARCH_CLPS7500 || ARCH_RPC || ARCH_SHARK)
-+	default y
+ 	/* new way for dealing with premature shared PCI interrupts */
+-	if (!OK_STAT(stat, DATA_READY, BAD_R_STAT)) {
++	if (!OK_STAT(stat, DRQ_STAT, BAD_R_STAT)) {
+ 		if (stat & (ERR_STAT | DRQ_STAT))
+ 			return task_error(drive, rq, __FUNCTION__, stat);
+ 		/* No data yet, so wait for another IRQ. */
+@@ -402,7 +448,7 @@ ide_startstop_t task_in_intr (ide_drive_t *drive)
+ 	/* If it was the last datablock check status and finish transfer. */
+ 	if (!hwif->nleft) {
+ 		stat = wait_drive_not_busy(drive);
+-		if (!OK_STAT(stat, 0, BAD_R_STAT))
++		if (!OK_STAT(stat, 0, BAD_STAT))
+ 			return task_error(drive, rq, __FUNCTION__, stat);
+ 		task_end_request(drive, rq, stat);
+ 		return ide_stopped;
+@@ -413,7 +459,6 @@ ide_startstop_t task_in_intr (ide_drive_t *drive)
  
- config BLK_DEV_IDE_ICSIDE
- 	tristate "ICS IDE interface support"
-@@ -888,10 +888,9 @@ config BLK_DEV_IDE_BAST
- 	  Simtec BAST or the Thorcom VR1000
+ 	return ide_started;
+ }
+-EXPORT_SYMBOL(task_in_intr);
  
- config ETRAX_IDE
--	bool "ETRAX IDE support"
-+	tristate "ETRAX IDE support"
- 	depends on CRIS && BROKEN
- 	select BLK_DEV_IDEDMA
--	select IDE_GENERIC
- 	help
- 	  Enables the ETRAX IDE driver.
+ /*
+  * Handler for command with PIO data-out phase (Write/Write Multiple).
+@@ -443,11 +488,11 @@ static ide_startstop_t task_out_intr (ide_drive_t *drive)
+ 	return ide_started;
+ }
  
-@@ -923,17 +922,15 @@ config ETRAX_IDE_G27_RESET
- endchoice
+-ide_startstop_t pre_task_out_intr (ide_drive_t *drive, struct request *rq)
++static ide_startstop_t pre_task_out_intr(ide_drive_t *drive, struct request *rq)
+ {
+ 	ide_startstop_t startstop;
  
- config IDE_H8300
--	bool "H8300 IDE support"
-+	tristate "H8300 IDE support"
- 	depends on H8300
--	select IDE_GENERIC
- 	default y
- 	help
- 	  Enables the H8300 IDE driver.
+-	if (ide_wait_stat(&startstop, drive, DATA_READY,
++	if (ide_wait_stat(&startstop, drive, DRQ_STAT,
+ 			  drive->bad_wstat, WAIT_DRQ)) {
+ 		printk(KERN_ERR "%s: no DRQ after issuing %sWRITE%s\n",
+ 				drive->name,
+@@ -464,9 +509,8 @@ ide_startstop_t pre_task_out_intr (ide_drive_t *drive, struct request *rq)
  
- config BLK_DEV_GAYLE
--	bool "Amiga Gayle IDE interface support"
-+	tristate "Amiga Gayle IDE interface support"
- 	depends on AMIGA
--	select IDE_GENERIC
- 	help
- 	  This is the IDE driver for the Amiga Gayle IDE interface. It supports
- 	  both the `A1200 style' and `A4000 style' of the Gayle IDE interface,
-@@ -963,9 +960,8 @@ config BLK_DEV_IDEDOUBLER
- 	  runtime using the "ide=doubler" kernel boot parameter.
+ 	return ide_started;
+ }
+-EXPORT_SYMBOL(pre_task_out_intr);
  
- config BLK_DEV_BUDDHA
--	bool "Buddha/Catweasel/X-Surf IDE interface support (EXPERIMENTAL)"
-+	tristate "Buddha/Catweasel/X-Surf IDE interface support (EXPERIMENTAL)"
- 	depends on ZORRO && EXPERIMENTAL
--	select IDE_GENERIC
- 	help
- 	  This is the IDE driver for the IDE interfaces on the Buddha, 
- 	  Catweasel and X-Surf expansion boards.  It supports up to two interfaces 
-@@ -976,9 +972,8 @@ config BLK_DEV_BUDDHA
- 	  to one of its IDE interfaces.
+-static int ide_diag_taskfile(ide_drive_t *drive, ide_task_t *args, unsigned long data_size, u8 *buf)
++int ide_raw_taskfile(ide_drive_t *drive, ide_task_t *task, u8 *buf, u16 nsect)
+ {
+ 	struct request rq;
  
- config BLK_DEV_FALCON_IDE
--	bool "Falcon IDE interface support"
-+	tristate "Falcon IDE interface support"
- 	depends on ATARI
--	select IDE_GENERIC
- 	help
- 	  This is the IDE driver for the builtin IDE interface on the Atari
- 	  Falcon. Say Y if you have a Falcon and want to use IDE devices (hard
-@@ -986,9 +981,8 @@ config BLK_DEV_FALCON_IDE
- 	  interface.
+@@ -481,36 +525,27 @@ static int ide_diag_taskfile(ide_drive_t *drive, ide_task_t *args, unsigned long
+ 	 * if we would find a solution to transfer any size.
+ 	 * To support special commands like READ LONG.
+ 	 */
+-	if (args->command_type != IDE_DRIVE_TASK_NO_DATA) {
+-		if (data_size == 0)
+-			rq.nr_sectors = (args->hobRegister[IDE_NSECTOR_OFFSET] << 8) | args->tfRegister[IDE_NSECTOR_OFFSET];
+-		else
+-			rq.nr_sectors = data_size / SECTOR_SIZE;
+-
+-		if (!rq.nr_sectors) {
+-			printk(KERN_ERR "%s: in/out command without data\n",
+-					drive->name);
+-			return -EFAULT;
+-		}
++	rq.hard_nr_sectors = rq.nr_sectors = nsect;
++	rq.hard_cur_sectors = rq.current_nr_sectors = nsect;
  
- config BLK_DEV_MAC_IDE
--	bool "Macintosh Quadra/Powerbook IDE interface support"
-+	tristate "Macintosh Quadra/Powerbook IDE interface support"
- 	depends on MAC
--	select IDE_GENERIC
- 	help
- 	  This is the IDE driver for the builtin IDE interface on some m68k
- 	  Macintosh models. It supports both the `Quadra style' (used in
-@@ -1000,18 +994,16 @@ config BLK_DEV_MAC_IDE
- 	  builtin IDE interface.
+-		rq.hard_nr_sectors = rq.nr_sectors;
+-		rq.hard_cur_sectors = rq.current_nr_sectors = rq.nr_sectors;
++	if (task->tf_flags & IDE_TFLAG_WRITE)
++		rq.cmd_flags |= REQ_RW;
  
- config BLK_DEV_Q40IDE
--	bool "Q40/Q60 IDE interface support"
-+	tristate "Q40/Q60 IDE interface support"
- 	depends on Q40
--	select IDE_GENERIC
- 	help
- 	  Enable the on-board IDE controller in the Q40/Q60.  This should
- 	  normally be on; disable it only if you are running a custom hard
- 	  drive subsystem through an expansion card.
+-		if (args->command_type == IDE_DRIVE_TASK_RAW_WRITE)
+-			rq.cmd_flags |= REQ_RW;
+-	}
++	rq.special = task;
++	task->rq = &rq;
  
- config BLK_DEV_MPC8xx_IDE
--	bool "MPC8xx IDE support"
-+	tristate "MPC8xx IDE support"
- 	depends on 8xx && (LWMON || IVMS8 || IVML24 || TQM8xxL) && IDE=y && BLK_DEV_IDE=y && !PPC_MERGE
--	select IDE_GENERIC
- 	help
- 	  This option provides support for IDE on Motorola MPC8xx Systems.
- 	  Please see 'Type of MPC8xx IDE interface' for details.
-diff --git a/drivers/ide/Makefile b/drivers/ide/Makefile
-index b181fc6..0d2da89 100644
---- a/drivers/ide/Makefile
-+++ b/drivers/ide/Makefile
-@@ -7,41 +7,37 @@
- # Note : at this point, these files are compiled on all systems.
- # In the future, some of these should be built conditionally.
- #
--# First come modules that register themselves with the core
-+# link order is important here
+-	rq.special = args;
+-	args->rq = &rq;
+ 	return ide_do_drive_cmd(drive, &rq, ide_wait);
+ }
  
- EXTRA_CFLAGS				+= -Idrivers/ide
+-int ide_raw_taskfile (ide_drive_t *drive, ide_task_t *args, u8 *buf)
++EXPORT_SYMBOL(ide_raw_taskfile);
++
++int ide_no_data_taskfile(ide_drive_t *drive, ide_task_t *task)
+ {
+-	return ide_diag_taskfile(drive, args, 0, buf);
+-}
++	task->data_phase = TASKFILE_NO_DATA;
  
--obj-$(CONFIG_BLK_DEV_IDE)		+= pci/
--
- ide-core-y += ide.o ide-io.o ide-iops.o ide-lib.o ide-probe.o ide-taskfile.o
+-EXPORT_SYMBOL(ide_raw_taskfile);
++	return ide_raw_taskfile(drive, task, NULL, 0);
++}
++EXPORT_SYMBOL_GPL(ide_no_data_taskfile);
  
--ide-core-$(CONFIG_BLK_DEV_CMD640)	+= pci/cmd640.o
--
--# Core IDE code - must come before legacy
-+# core IDE code
- ide-core-$(CONFIG_BLK_DEV_IDEPCI)	+= setup-pci.o
- ide-core-$(CONFIG_BLK_DEV_IDEDMA)	+= ide-dma.o
- ide-core-$(CONFIG_IDE_PROC_FS)		+= ide-proc.o
--ide-core-$(CONFIG_BLK_DEV_IDEPNP)	+= ide-pnp.o
- ide-core-$(CONFIG_BLK_DEV_IDEACPI)	+= ide-acpi.o
+ #ifdef CONFIG_IDE_TASK_IOCTL
+ int ide_taskfile_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg)
+@@ -519,13 +554,12 @@ int ide_taskfile_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg)
+ 	ide_task_t		args;
+ 	u8 *outbuf		= NULL;
+ 	u8 *inbuf		= NULL;
+-	task_ioreg_t *argsptr	= args.tfRegister;
+-	task_ioreg_t *hobsptr	= args.hobRegister;
++	u8 *data_buf		= NULL;
+ 	int err			= 0;
+ 	int tasksize		= sizeof(struct ide_task_request_s);
+ 	unsigned int taskin	= 0;
+ 	unsigned int taskout	= 0;
+-	u8 io_32bit		= drive->io_32bit;
++	u16 nsect		= 0;
+ 	char __user *buf = (char __user *)arg;
  
--# built-in only drivers from arm/
--ide-core-$(CONFIG_IDE_ARM)		+= arm/ide_arm.o
-+obj-$(CONFIG_BLK_DEV_IDE)		+= ide-core.o
+ //	printk("IDE Taskfile ...\n");
+@@ -572,24 +606,52 @@ int ide_taskfile_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg)
+ 	}
  
--# built-in only drivers from legacy/
--ide-core-$(CONFIG_BLK_DEV_BUDDHA)	+= legacy/buddha.o
--ide-core-$(CONFIG_BLK_DEV_FALCON_IDE)	+= legacy/falconide.o
--ide-core-$(CONFIG_BLK_DEV_GAYLE)	+= legacy/gayle.o
--ide-core-$(CONFIG_BLK_DEV_MAC_IDE)	+= legacy/macide.o
--ide-core-$(CONFIG_BLK_DEV_Q40IDE)	+= legacy/q40ide.o
-+ifeq ($(CONFIG_IDE_ARM), y)
-+	ide-arm-core-y += arm/ide_arm.o
-+	obj-y += ide-arm-core.o
-+endif
+ 	memset(&args, 0, sizeof(ide_task_t));
+-	memcpy(argsptr, req_task->io_ports, HDIO_DRIVE_TASK_HDR_SIZE);
+-	memcpy(hobsptr, req_task->hob_ports, HDIO_DRIVE_HOB_HDR_SIZE);
  
--# built-in only drivers from ppc/
--ide-core-$(CONFIG_BLK_DEV_MPC8xx_IDE)	+= ppc/mpc8xx.o
--ide-core-$(CONFIG_BLK_DEV_IDE_PMAC)	+= ppc/pmac.o
-+obj-$(CONFIG_BLK_DEV_IDE)		+= legacy/ pci/
+-	args.tf_in_flags  = req_task->in_flags;
+-	args.tf_out_flags = req_task->out_flags;
+-	args.data_phase   = req_task->data_phase;
+-	args.command_type = req_task->req_cmd;
++	memcpy(&args.tf_array[0], req_task->hob_ports, HDIO_DRIVE_HOB_HDR_SIZE - 2);
++	memcpy(&args.tf_array[6], req_task->io_ports, HDIO_DRIVE_TASK_HDR_SIZE);
++
++	args.data_phase = req_task->data_phase;
++
++	args.tf_flags = IDE_TFLAG_IO_16BIT | IDE_TFLAG_DEVICE |
++			IDE_TFLAG_IN_TF;
++	if (drive->addressing == 1)
++		args.tf_flags |= (IDE_TFLAG_LBA48 | IDE_TFLAG_IN_HOB);
++
++	if (req_task->out_flags.all) {
++		args.tf_flags |= IDE_TFLAG_FLAGGED;
++
++		if (req_task->out_flags.b.data)
++			args.tf_flags |= IDE_TFLAG_OUT_DATA;
++
++		if (req_task->out_flags.b.nsector_hob)
++			args.tf_flags |= IDE_TFLAG_OUT_HOB_NSECT;
++		if (req_task->out_flags.b.sector_hob)
++			args.tf_flags |= IDE_TFLAG_OUT_HOB_LBAL;
++		if (req_task->out_flags.b.lcyl_hob)
++			args.tf_flags |= IDE_TFLAG_OUT_HOB_LBAM;
++		if (req_task->out_flags.b.hcyl_hob)
++			args.tf_flags |= IDE_TFLAG_OUT_HOB_LBAH;
++
++		if (req_task->out_flags.b.error_feature)
++			args.tf_flags |= IDE_TFLAG_OUT_FEATURE;
++		if (req_task->out_flags.b.nsector)
++			args.tf_flags |= IDE_TFLAG_OUT_NSECT;
++		if (req_task->out_flags.b.sector)
++			args.tf_flags |= IDE_TFLAG_OUT_LBAL;
++		if (req_task->out_flags.b.lcyl)
++			args.tf_flags |= IDE_TFLAG_OUT_LBAM;
++		if (req_task->out_flags.b.hcyl)
++			args.tf_flags |= IDE_TFLAG_OUT_LBAH;
++	} else {
++		args.tf_flags |= IDE_TFLAG_OUT_TF;
++		if (args.tf_flags & IDE_TFLAG_LBA48)
++			args.tf_flags |= IDE_TFLAG_OUT_HOB;
++	}
++
++	if (req_task->in_flags.b.data)
++		args.tf_flags |= IDE_TFLAG_IN_DATA;
  
--# built-in only drivers from h8300/
--ide-core-$(CONFIG_IDE_H8300)		+= h8300/ide-h8300.o
-+obj-$(CONFIG_IDEPCI_PCIBUS_ORDER)	+= ide-scan-pci.o
+-	drive->io_32bit = 0;
+ 	switch(req_task->data_phase) {
+-		case TASKFILE_OUT_DMAQ:
+-		case TASKFILE_OUT_DMA:
+-			err = ide_diag_taskfile(drive, &args, taskout, outbuf);
+-			break;
+-		case TASKFILE_IN_DMAQ:
+-		case TASKFILE_IN_DMA:
+-			err = ide_diag_taskfile(drive, &args, taskin, inbuf);
+-			break;
+ 		case TASKFILE_MULTI_OUT:
+ 			if (!drive->mult_count) {
+ 				/* (hs): give up if multcount is not set */
+@@ -601,9 +663,11 @@ int ide_taskfile_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg)
+ 			}
+ 			/* fall through */
+ 		case TASKFILE_OUT:
+-			args.prehandler = &pre_task_out_intr;
+-			args.handler = &task_out_intr;
+-			err = ide_diag_taskfile(drive, &args, taskout, outbuf);
++			/* fall through */
++		case TASKFILE_OUT_DMAQ:
++		case TASKFILE_OUT_DMA:
++			nsect = taskout / SECTOR_SIZE;
++			data_buf = outbuf;
+ 			break;
+ 		case TASKFILE_MULTI_IN:
+ 			if (!drive->mult_count) {
+@@ -616,22 +680,46 @@ int ide_taskfile_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg)
+ 			}
+ 			/* fall through */
+ 		case TASKFILE_IN:
+-			args.handler = &task_in_intr;
+-			err = ide_diag_taskfile(drive, &args, taskin, inbuf);
++			/* fall through */
++		case TASKFILE_IN_DMAQ:
++		case TASKFILE_IN_DMA:
++			nsect = taskin / SECTOR_SIZE;
++			data_buf = inbuf;
+ 			break;
+ 		case TASKFILE_NO_DATA:
+-			args.handler = &task_no_data_intr;
+-			err = ide_diag_taskfile(drive, &args, 0, NULL);
+ 			break;
+ 		default:
+ 			err = -EFAULT;
+ 			goto abort;
+ 	}
  
--obj-$(CONFIG_BLK_DEV_IDE)		+= ide-core.o
-+ifeq ($(CONFIG_BLK_DEV_CMD640), y)
-+	cmd640-core-y += pci/cmd640.o
-+	obj-y += cmd640-core.o
-+endif
+-	memcpy(req_task->io_ports, &(args.tfRegister), HDIO_DRIVE_TASK_HDR_SIZE);
+-	memcpy(req_task->hob_ports, &(args.hobRegister), HDIO_DRIVE_HOB_HDR_SIZE);
+-	req_task->in_flags  = args.tf_in_flags;
+-	req_task->out_flags = args.tf_out_flags;
++	if (req_task->req_cmd == IDE_DRIVE_TASK_NO_DATA)
++		nsect = 0;
++	else if (!nsect) {
++		nsect = (args.tf.hob_nsect << 8) | args.tf.nsect;
 +
-+obj-$(CONFIG_BLK_DEV_IDE)		+= cris/ ppc/
-+obj-$(CONFIG_BLK_DEV_IDEPNP)		+= ide-pnp.o
-+obj-$(CONFIG_IDE_H8300)			+= h8300/
- obj-$(CONFIG_IDE_GENERIC)		+= ide-generic.o
- 
- obj-$(CONFIG_BLK_DEV_IDEDISK)		+= ide-disk.o
-@@ -49,6 +45,20 @@ obj-$(CONFIG_BLK_DEV_IDECD)		+= ide-cd.o
- obj-$(CONFIG_BLK_DEV_IDETAPE)		+= ide-tape.o
- obj-$(CONFIG_BLK_DEV_IDEFLOPPY)		+= ide-floppy.o
- 
--obj-$(CONFIG_BLK_DEV_IDE)		+= legacy/ arm/ mips/
--obj-$(CONFIG_BLK_DEV_HD)		+= legacy/
--obj-$(CONFIG_ETRAX_IDE)		+= cris/
-+ifeq ($(CONFIG_BLK_DEV_IDECS), y)
-+	ide-cs-core-y += legacy/ide-cs.o
-+	obj-y += ide-cs-core.o
-+endif
++		if (!nsect) {
++			printk(KERN_ERR "%s: in/out command without data\n",
++					drive->name);
++			err = -EFAULT;
++			goto abort;
++		}
++	}
 +
-+ifeq ($(CONFIG_BLK_DEV_PLATFORM), y)
-+	ide-platform-core-y += legacy/ide_platform.o
-+	obj-y += ide-platform-core.o
-+endif
++	if (req_task->req_cmd == IDE_DRIVE_TASK_RAW_WRITE)
++		args.tf_flags |= IDE_TFLAG_WRITE;
 +
-+obj-$(CONFIG_BLK_DEV_IDE)		+= arm/ mips/
++	err = ide_raw_taskfile(drive, &args, data_buf, nsect);
 +
-+# old hd driver must be last
-+ifeq ($(CONFIG_BLK_DEV_HD), y)
-+	hd-core-y += legacy/hd.o
-+	obj-y += hd-core.o
-+endif
-diff --git a/drivers/ide/arm/Makefile b/drivers/ide/arm/Makefile
-index 6a78f07..5f63ad2 100644
---- a/drivers/ide/arm/Makefile
-+++ b/drivers/ide/arm/Makefile
-@@ -3,4 +3,8 @@ obj-$(CONFIG_BLK_DEV_IDE_ICSIDE)	+= icside.o
- obj-$(CONFIG_BLK_DEV_IDE_RAPIDE)	+= rapide.o
- obj-$(CONFIG_BLK_DEV_IDE_BAST)		+= bast-ide.o
- 
-+ifeq ($(CONFIG_IDE_ARM), m)
-+	obj-m += ide_arm.o
-+endif
++	memcpy(req_task->hob_ports, &args.tf_array[0], HDIO_DRIVE_HOB_HDR_SIZE - 2);
++	memcpy(req_task->io_ports, &args.tf_array[6], HDIO_DRIVE_TASK_HDR_SIZE);
 +
- EXTRA_CFLAGS	:= -Idrivers/ide
-diff --git a/drivers/ide/arm/bast-ide.c b/drivers/ide/arm/bast-ide.c
-index 48db616..45bf9c8 100644
---- a/drivers/ide/arm/bast-ide.c
-+++ b/drivers/ide/arm/bast-ide.c
-@@ -45,7 +45,7 @@ bastide_register(unsigned int base, unsigned int aux, int irq,
- 	hw.io_ports[IDE_CONTROL_OFFSET] = aux + (6 * 0x20);
- 	hw.irq = irq;
- 
--	ide_register_hw(&hw, NULL, 0, hwif);
-+	ide_register_hw(&hw, NULL, hwif);
++	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)
++			req_task->in_flags.all |= (IDE_HOB_STD_IN_FLAGS << 8);
++	}
  
- 	return 0;
- }
-diff --git a/drivers/ide/arm/icside.c b/drivers/ide/arm/icside.c
-index 93f71fc..8a5c720 100644
---- a/drivers/ide/arm/icside.c
-+++ b/drivers/ide/arm/icside.c
-@@ -272,8 +272,6 @@ static void icside_set_dma_mode(ide_drive_t *drive, const u8 xfer_mode)
- 	case XFER_SW_DMA_0:
- 		cycle_time = 480;
- 		break;
--	default:
--		return;
- 	}
+ 	if (copy_to_user(buf, req_task, tasksize)) {
+ 		err = -EFAULT;
+@@ -658,40 +746,24 @@ abort:
  
- 	/*
-@@ -289,26 +287,10 @@ static void icside_set_dma_mode(ide_drive_t *drive, const u8 xfer_mode)
- 		ide_xfer_verbose(xfer_mode), 2000 / drive->drive_data);
- }
+ //	printk("IDE Taskfile ioctl ended. rc = %i\n", err);
  
--static void icside_dma_host_off(ide_drive_t *drive)
-+static void icside_dma_host_set(ide_drive_t *drive, int on)
- {
+-	drive->io_32bit = io_32bit;
+-
+ 	return err;
  }
+ #endif
  
--static void icside_dma_off_quietly(ide_drive_t *drive)
--{
--	drive->using_dma = 0;
--}
--
--static void icside_dma_host_on(ide_drive_t *drive)
--{
--}
--
--static int icside_dma_on(ide_drive_t *drive)
+-int ide_wait_cmd (ide_drive_t *drive, u8 cmd, u8 nsect, u8 feature, u8 sectors, u8 *buf)
 -{
--	drive->using_dma = 1;
+-	struct request rq;
+-	u8 buffer[4];
 -
--	return 0;
+-	if (!buf)
+-		buf = buffer;
+-	memset(buf, 0, 4 + SECTOR_WORDS * 4 * sectors);
+-	ide_init_drive_cmd(&rq);
+-	rq.buffer = buf;
+-	*buf++ = cmd;
+-	*buf++ = nsect;
+-	*buf++ = feature;
+-	*buf++ = sectors;
+-	return ide_do_drive_cmd(drive, &rq, ide_wait);
 -}
 -
- static int icside_dma_end(ide_drive_t *drive)
- {
- 	ide_hwif_t *hwif = HWIF(drive);
-@@ -424,10 +406,7 @@ static void icside_dma_init(ide_hwif_t *hwif)
- 	hwif->dmatable_dma	= 0;
- 	hwif->set_dma_mode	= icside_set_dma_mode;
- 
--	hwif->dma_host_off	= icside_dma_host_off;
--	hwif->dma_off_quietly	= icside_dma_off_quietly;
--	hwif->dma_host_on	= icside_dma_host_on;
--	hwif->ide_dma_on	= icside_dma_on;
-+	hwif->dma_host_set	= icside_dma_host_set;
- 	hwif->dma_setup		= icside_dma_setup;
- 	hwif->dma_exec_cmd	= icside_dma_exec_cmd;
- 	hwif->dma_start		= icside_dma_start;
-diff --git a/drivers/ide/arm/ide_arm.c b/drivers/ide/arm/ide_arm.c
-index 8957cba..60f2497 100644
---- a/drivers/ide/arm/ide_arm.c
-+++ b/drivers/ide/arm/ide_arm.c
-@@ -24,12 +24,25 @@
- # define IDE_ARM_IRQ	IRQ_HARDDISK
- #endif
- 
--void __init ide_arm_init(void)
-+static int __init ide_arm_init(void)
+ int ide_cmd_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg)
  {
-+	ide_hwif_t *hwif;
- 	hw_regs_t hw;
-+	u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
+-	int err = 0;
+-	u8 args[4], *argbuf = args;
+-	u8 xfer_rate = 0;
+-	int argsize = 4;
++	u8 *buf = NULL;
++	int bufsize = 0, err = 0;
++	u8 args[4], xfer_rate = 0;
+ 	ide_task_t tfargs;
++	struct ide_taskfile *tf = &tfargs.tf;
  
- 	memset(&hw, 0, sizeof(hw));
- 	ide_std_init_ports(&hw, IDE_ARM_IO, IDE_ARM_IO + 0x206);
- 	hw.irq = IDE_ARM_IRQ;
--	ide_register_hw(&hw, NULL, 1, NULL);
+ 	if (NULL == (void *) arg) {
+ 		struct request rq;
 +
-+	hwif = ide_find_port(hw.io_ports[IDE_DATA_OFFSET]);
-+	if (hwif) {
-+		ide_init_port_hw(hwif, &hw);
-+		idx[0] = hwif->index;
+ 		ide_init_drive_cmd(&rq);
++		rq.cmd_type = REQ_TYPE_ATA_TASKFILE;
 +
-+		ide_device_add(idx);
+ 		return ide_do_drive_cmd(drive, &rq, ide_wait);
+ 	}
+ 
+@@ -699,27 +771,40 @@ int ide_cmd_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg)
+ 		return -EFAULT;
+ 
+ 	memset(&tfargs, 0, sizeof(ide_task_t));
+-	tfargs.tfRegister[IDE_FEATURE_OFFSET] = args[2];
+-	tfargs.tfRegister[IDE_NSECTOR_OFFSET] = args[3];
+-	tfargs.tfRegister[IDE_SECTOR_OFFSET]  = args[1];
+-	tfargs.tfRegister[IDE_LCYL_OFFSET]    = 0x00;
+-	tfargs.tfRegister[IDE_HCYL_OFFSET]    = 0x00;
+-	tfargs.tfRegister[IDE_SELECT_OFFSET]  = 0x00;
+-	tfargs.tfRegister[IDE_COMMAND_OFFSET] = args[0];
++	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]) {
+-		argsize = 4 + (SECTOR_WORDS * 4 * args[3]);
+-		argbuf = kzalloc(argsize, GFP_KERNEL);
+-		if (argbuf == NULL)
++		tfargs.tf_flags |= IDE_TFLAG_IO_16BIT;
++		bufsize = SECTOR_WORDS * 4 * args[3];
++		buf = kzalloc(bufsize, GFP_KERNEL);
++		if (buf == NULL)
+ 			return -ENOMEM;
+ 	}
 +
-+	return 0;
- }
+ 	if (set_transfer(drive, &tfargs)) {
+ 		xfer_rate = args[1];
+ 		if (ide_ata66_check(drive, &tfargs))
+ 			goto abort;
+ 	}
+ 
+-	err = ide_wait_cmd(drive, args[0], args[1], args[2], args[3], argbuf);
++	err = ide_raw_taskfile(drive, &tfargs, buf, args[3]);
 +
-+module_init(ide_arm_init);
-diff --git a/drivers/ide/arm/rapide.c b/drivers/ide/arm/rapide.c
-index 0775a3a..e6b56d1 100644
---- a/drivers/ide/arm/rapide.c
-+++ b/drivers/ide/arm/rapide.c
-@@ -13,26 +13,18 @@
++	args[0] = tf->status;
++	args[1] = tf->error;
++	args[2] = tf->nsect;
  
- #include <asm/ecard.h>
+ 	if (!err && xfer_rate) {
+ 		/* active-retuning-calls future */
+@@ -727,142 +812,38 @@ int ide_cmd_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg)
+ 		ide_driveid_update(drive);
+ 	}
+ abort:
+-	if (copy_to_user((void __user *)arg, argbuf, argsize))
++	if (copy_to_user((void __user *)arg, &args, 4))
+ 		err = -EFAULT;
+-	if (argsize > 4)
+-		kfree(argbuf);
++	if (buf) {
++		if (copy_to_user((void __user *)(arg + 4), buf, bufsize))
++			err = -EFAULT;
++		kfree(buf);
++	}
+ 	return err;
+ }
  
--static ide_hwif_t *
--rapide_locate_hwif(void __iomem *base, void __iomem *ctrl, unsigned int sz, int irq)
-+static void rapide_setup_ports(hw_regs_t *hw, void __iomem *base,
-+			       void __iomem *ctrl, unsigned int sz, int irq)
+-static int ide_wait_cmd_task(ide_drive_t *drive, u8 *buf)
+-{
+-	struct request rq;
+-
+-	ide_init_drive_cmd(&rq);
+-	rq.cmd_type = REQ_TYPE_ATA_TASK;
+-	rq.buffer = buf;
+-	return ide_do_drive_cmd(drive, &rq, ide_wait);
+-}
+-
+ int ide_task_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg)
  {
- 	unsigned long port = (unsigned long)base;
--	ide_hwif_t *hwif = ide_find_port(port);
- 	int i;
+ 	void __user *p = (void __user *)arg;
+ 	int err = 0;
+-	u8 args[7], *argbuf = args;
+-	int argsize = 7;
++	u8 args[7];
++	ide_task_t task;
  
--	if (hwif == NULL)
--		goto out;
+ 	if (copy_from_user(args, p, 7))
+ 		return -EFAULT;
+-	err = ide_wait_cmd_task(drive, argbuf);
+-	if (copy_to_user(p, argbuf, argsize))
+-		err = -EFAULT;
+-	return err;
+-}
 -
- 	for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
--		hwif->io_ports[i] = port;
-+		hw->io_ports[i] = port;
- 		port += sz;
- 	}
--	hwif->io_ports[IDE_CONTROL_OFFSET] = (unsigned long)ctrl;
--	hwif->irq = irq;
--	hwif->mmio = 1;
--	default_hwif_mmiops(hwif);
--out:
--	return hwif;
-+	hw->io_ports[IDE_CONTROL_OFFSET] = (unsigned long)ctrl;
-+	hw->irq = irq;
- }
+-/*
+- * NOTICE: This is additions from IBM to provide a discrete interface,
+- * for selective taskregister access operations.  Nice JOB Klaus!!!
+- * Glad to be able to work and co-develop this with you and IBM.
+- */
+-ide_startstop_t flagged_taskfile (ide_drive_t *drive, ide_task_t *task)
+-{
+-	ide_hwif_t *hwif	= HWIF(drive);
+-	task_struct_t *taskfile	= (task_struct_t *) task->tfRegister;
+-	hob_struct_t *hobfile	= (hob_struct_t *) task->hobRegister;
+-
+-	if (task->data_phase == TASKFILE_MULTI_IN ||
+-	    task->data_phase == TASKFILE_MULTI_OUT) {
+-		if (!drive->mult_count) {
+-			printk(KERN_ERR "%s: multimode not set!\n", drive->name);
+-			return ide_stopped;
+-		}
+-	}
  
- static int __devinit
-@@ -42,6 +34,7 @@ rapide_probe(struct expansion_card *ec, const struct ecard_id *id)
- 	void __iomem *base;
- 	int ret;
- 	u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
-+	hw_regs_t hw;
+-	/*
+-	 * (ks) Check taskfile in flags.
+-	 * If set, then execute as it is defined.
+-	 * If not set, then define default settings.
+-	 * The default values are:
+-	 *	read all taskfile registers (except data)
+-	 *	read the hob registers (sector, nsector, lcyl, hcyl)
+-	 */
+-	if (task->tf_in_flags.all == 0) {
+-		task->tf_in_flags.all = IDE_TASKFILE_STD_IN_FLAGS;
+-		if (drive->addressing == 1)
+-			task->tf_in_flags.all |= (IDE_HOB_STD_IN_FLAGS  << 8);
+-        }
+-
+-	/* ALL Command Block Executions SHALL clear nIEN, unless otherwise */
+-	if (IDE_CONTROL_REG)
+-		/* clear nIEN */
+-		hwif->OUTB(drive->ctl, IDE_CONTROL_REG);
+-	SELECT_MASK(drive, 0);
+-
+-	if (task->tf_out_flags.b.data) {
+-		u16 data =  taskfile->data + (hobfile->data << 8);
+-		hwif->OUTW(data, IDE_DATA_REG);
+-	}
+-
+-	/* (ks) send hob registers first */
+-	if (task->tf_out_flags.b.nsector_hob)
+-		hwif->OUTB(hobfile->sector_count, IDE_NSECTOR_REG);
+-	if (task->tf_out_flags.b.sector_hob)
+-		hwif->OUTB(hobfile->sector_number, IDE_SECTOR_REG);
+-	if (task->tf_out_flags.b.lcyl_hob)
+-		hwif->OUTB(hobfile->low_cylinder, IDE_LCYL_REG);
+-	if (task->tf_out_flags.b.hcyl_hob)
+-		hwif->OUTB(hobfile->high_cylinder, IDE_HCYL_REG);
+-
+-	/* (ks) Send now the standard registers */
+-	if (task->tf_out_flags.b.error_feature)
+-		hwif->OUTB(taskfile->feature, IDE_FEATURE_REG);
+-	/* refers to number of sectors to transfer */
+-	if (task->tf_out_flags.b.nsector)
+-		hwif->OUTB(taskfile->sector_count, IDE_NSECTOR_REG);
+-	/* refers to sector offset or start sector */
+-	if (task->tf_out_flags.b.sector)
+-		hwif->OUTB(taskfile->sector_number, IDE_SECTOR_REG);
+-	if (task->tf_out_flags.b.lcyl)
+-		hwif->OUTB(taskfile->low_cylinder, IDE_LCYL_REG);
+-	if (task->tf_out_flags.b.hcyl)
+-		hwif->OUTB(taskfile->high_cylinder, IDE_HCYL_REG);
+-
+-        /*
+-	 * (ks) In the flagged taskfile approch, we will use all specified
+-	 * registers and the register value will not be changed, except the
+-	 * select bit (master/slave) in the drive_head register. We must make
+-	 * sure that the desired drive is selected.
+-	 */
+-	hwif->OUTB(taskfile->device_head | drive->select.all, IDE_SELECT_REG);
+-	switch(task->data_phase) {
++	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;
  
- 	ret = ecard_request_resources(ec);
- 	if (ret)
-@@ -53,11 +46,17 @@ rapide_probe(struct expansion_card *ec, const struct ecard_id *id)
- 		goto release;
- 	}
+-   	        case TASKFILE_OUT_DMAQ:
+-		case TASKFILE_OUT_DMA:
+-		case TASKFILE_IN_DMAQ:
+-		case TASKFILE_IN_DMA:
+-			if (!drive->using_dma)
+-				break;
++	err = ide_no_data_taskfile(drive, &task);
  
--	hwif = rapide_locate_hwif(base, base + 0x818, 1 << 6, ec->irq);
-+	hwif = ide_find_port((unsigned long)base);
- 	if (hwif) {
--		hwif->hwif_data = base;
--		hwif->gendev.parent = &ec->dev;
--		hwif->noprobe = 0;
-+		memset(&hw, 0, sizeof(hw));
-+		rapide_setup_ports(&hw, base, base + 0x818, 1 << 6, ec->irq);
-+		hw.chipset = ide_generic;
-+		hw.dev = &ec->dev;
-+
-+		ide_init_port_hw(hwif, &hw);
-+
-+		hwif->mmio = 1;
-+		default_hwif_mmiops(hwif);
+-			if (!hwif->dma_setup(drive)) {
+-				hwif->dma_exec_cmd(drive, taskfile->command);
+-				hwif->dma_start(drive);
+-				return ide_started;
+-			}
+-			break;
++	args[0] = task.tf.command;
++	memcpy(&args[1], &task.tf_array[7], 6);
  
- 		idx[0] = hwif->index;
+-	        default:
+- 			if (task->handler == NULL)
+-				return ide_stopped;
+-
+-			/* Issue the command */
+-			if (task->prehandler) {
+-				hwif->OUTBSYNC(drive, taskfile->command, IDE_COMMAND_REG);
+-				ndelay(400);	/* FIXME */
+-				return task->prehandler(drive, task->rq);
+-			}
+-			ide_execute_command(drive, taskfile->command, task->handler, WAIT_WORSTCASE, NULL);
+-			return ide_started;
+-	}
++	if (copy_to_user(p, args, 7))
++		err = -EFAULT;
  
-diff --git a/drivers/ide/cris/Makefile b/drivers/ide/cris/Makefile
-index 6176e8d..20b9596 100644
---- a/drivers/ide/cris/Makefile
-+++ b/drivers/ide/cris/Makefile
-@@ -1,3 +1,3 @@
- EXTRA_CFLAGS				+= -Idrivers/ide
+-	return ide_stopped;
++	return err;
+ }
+diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c
+index 54943da..97894ab 100644
+--- a/drivers/ide/ide.c
++++ b/drivers/ide/ide.c
+@@ -95,7 +95,7 @@ DEFINE_MUTEX(ide_cfg_mtx);
+  __cacheline_aligned_in_smp DEFINE_SPINLOCK(ide_lock);
  
--obj-y					+= ide-cris.o
-+obj-$(CONFIG_IDE_ETRAX)			+= ide-cris.o
-diff --git a/drivers/ide/cris/ide-cris.c b/drivers/ide/cris/ide-cris.c
-index 476e0d6..8c3294c 100644
---- a/drivers/ide/cris/ide-cris.c
-+++ b/drivers/ide/cris/ide-cris.c
-@@ -673,9 +673,8 @@ static void cris_ide_input_data (ide_drive_t *drive, void *, unsigned int);
- static void cris_ide_output_data (ide_drive_t *drive, void *, unsigned int);
- static void cris_atapi_input_bytes(ide_drive_t *drive, void *, unsigned int);
- static void cris_atapi_output_bytes(ide_drive_t *drive, void *, unsigned int);
--static int cris_dma_on (ide_drive_t *drive);
+ #ifdef CONFIG_IDEPCI_PCIBUS_ORDER
+-static int ide_scan_direction; /* THIS was formerly 2.2.x pci=reverse */
++int ide_scan_direction; /* THIS was formerly 2.2.x pci=reverse */
+ #endif
  
--static void cris_dma_off(ide_drive_t *drive)
-+static void cris_dma_host_set(ide_drive_t *drive, int on)
+ int noautodma = 0;
+@@ -116,7 +116,7 @@ EXPORT_SYMBOL(ide_hwifs);
+ /*
+  * Do not even *think* about calling this!
+  */
+-static void init_hwif_data(ide_hwif_t *hwif, unsigned int index)
++void ide_init_port_data(ide_hwif_t *hwif, unsigned int index)
  {
- }
+ 	unsigned int unit;
  
-@@ -747,8 +746,6 @@ static void cris_set_dma_mode(ide_drive_t *drive, const u8 speed)
- 			strobe = ATA_DMA2_STROBE;
- 			hold = ATA_DMA2_HOLD;
- 			break;
--		default:
--			return;
+@@ -159,6 +159,7 @@ static void init_hwif_data(ide_hwif_t *hwif, unsigned int index)
+ 		init_completion(&drive->gendev_rel_comp);
  	}
- 
- 	if (speed >= XFER_UDMA_0)
-@@ -757,13 +754,11 @@ static void cris_set_dma_mode(ide_drive_t *drive, const u8 speed)
- 		cris_ide_set_speed(TYPE_DMA, 0, strobe, hold);
  }
++EXPORT_SYMBOL_GPL(ide_init_port_data);
  
--void __init
--init_e100_ide (void)
-+static int __init init_e100_ide(void)
+ static void init_hwif_default(ide_hwif_t *hwif, unsigned int index)
  {
- 	hw_regs_t hw;
--	int ide_offsets[IDE_NR_PORTS];
--	int h;
--	int i;
-+	int ide_offsets[IDE_NR_PORTS], h, i;
-+	u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
- 
- 	printk("ide: ETRAX FS built-in ATA DMA controller\n");
- 
-@@ -780,9 +775,11 @@ init_e100_ide (void)
- 		                ide_offsets,
- 		                0, 0, cris_ide_ack_intr,
- 		                ide_default_irq(0));
--		ide_register_hw(&hw, NULL, 1, &hwif);
-+		hwif = ide_find_port(hw.io_ports[IDE_DATA_OFFSET]);
- 		if (hwif == NULL)
- 			continue;
-+		ide_init_port_data(hwif, hwif->index);
-+		ide_init_port_hw(hwif, &hw);
- 		hwif->mmio = 1;
- 		hwif->chipset = ide_etrax100;
- 		hwif->set_pio_mode = &cris_set_pio_mode;
-@@ -791,6 +788,7 @@ init_e100_ide (void)
- 		hwif->ata_output_data = &cris_ide_output_data;
- 		hwif->atapi_input_bytes = &cris_atapi_input_bytes;
- 		hwif->atapi_output_bytes = &cris_atapi_output_bytes;
-+		hwif->dma_host_set = &cris_dma_host_set;
- 		hwif->ide_dma_end = &cris_dma_end;
- 		hwif->dma_setup = &cris_dma_setup;
- 		hwif->dma_exec_cmd = &cris_dma_exec_cmd;
-@@ -801,9 +799,6 @@ init_e100_ide (void)
- 		hwif->OUTBSYNC = &cris_ide_outbsync;
- 		hwif->INB = &cris_ide_inb;
- 		hwif->INW = &cris_ide_inw;
--		hwif->dma_host_off = &cris_dma_off;
--		hwif->dma_host_on = &cris_dma_on;
--		hwif->dma_off_quietly = &cris_dma_off;
- 		hwif->cbl = ATA_CBL_PATA40;
- 		hwif->host_flags |= IDE_HFLAG_NO_ATAPI_DMA;
- 		hwif->pio_mask = ATA_PIO4,
-@@ -811,6 +806,8 @@ init_e100_ide (void)
- 		hwif->drives[1].autotune = 1;
- 		hwif->ultra_mask = cris_ultra_mask;
- 		hwif->mwdma_mask = 0x07; /* Multiword DMA 0-2 */
-+
-+		idx[h] = hwif->index;
- 	}
- 
- 	/* Reset pulse */
-@@ -823,14 +820,12 @@ init_e100_ide (void)
- 	cris_ide_set_speed(TYPE_PIO, ATA_PIO4_SETUP, ATA_PIO4_STROBE, ATA_PIO4_HOLD);
- 	cris_ide_set_speed(TYPE_DMA, 0, ATA_DMA2_STROBE, ATA_DMA2_HOLD);
- 	cris_ide_set_speed(TYPE_UDMA, ATA_UDMA2_CYC, ATA_UDMA2_DVS, 0);
--}
- 
--static int cris_dma_on (ide_drive_t *drive)
--{
-+	ide_device_add(idx);
-+
- 	return 0;
+@@ -177,8 +178,6 @@ static void init_hwif_default(ide_hwif_t *hwif, unsigned int index)
+ #endif
  }
  
+-extern void ide_arm_init(void);
 -
- static cris_dma_descr_type mydescr __attribute__ ((__aligned__(16)));
- 
  /*
-@@ -1062,3 +1057,5 @@ static void cris_dma_start(ide_drive_t *drive)
- 		LED_DISK_READ(1);
+  * init_ide_data() sets reasonable default values into all fields
+  * of all instances of the hwifs and drives, but only on the first call.
+@@ -210,16 +209,13 @@ static void __init init_ide_data (void)
+ 	/* Initialise all interface structures */
+ 	for (index = 0; index < MAX_HWIFS; ++index) {
+ 		hwif = &ide_hwifs[index];
+-		init_hwif_data(hwif, index);
++		ide_init_port_data(hwif, index);
+ 		init_hwif_default(hwif, index);
+ #if !defined(CONFIG_PPC32) || !defined(CONFIG_PCI)
+ 		hwif->irq =
+ 			ide_init_default_irq(hwif->io_ports[IDE_DATA_OFFSET]);
+ #endif
  	}
+-#ifdef CONFIG_IDE_ARM
+-	ide_arm_init();
+-#endif
  }
-+
-+module_init(init_e100_ide);
-diff --git a/drivers/ide/h8300/Makefile b/drivers/ide/h8300/Makefile
-new file mode 100644
-index 0000000..5eba16f
---- /dev/null
-+++ b/drivers/ide/h8300/Makefile
-@@ -0,0 +1,2 @@
-+
-+obj-$(CONFIG_IDE_H8300)			+= ide-h8300.o
-diff --git a/drivers/ide/h8300/ide-h8300.c b/drivers/ide/h8300/ide-h8300.c
-index 4a49b5c..4f6d019 100644
---- a/drivers/ide/h8300/ide-h8300.c
-+++ b/drivers/ide/h8300/ide-h8300.c
-@@ -84,11 +84,12 @@ static inline void hwif_setup(ide_hwif_t *hwif)
- 	hwif->INSL  = NULL;
- }
- 
--void __init h8300_ide_init(void)
-+static int __init h8300_ide_init(void)
- {
- 	hw_regs_t hw;
- 	ide_hwif_t *hwif;
--	int idx;
-+	int index;
-+	u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
- 
- 	if (!request_region(CONFIG_H8300_IDE_BASE, H8300_IDE_GAP*8, "ide-h8300"))
- 		goto out_busy;
-@@ -100,16 +101,28 @@ void __init h8300_ide_init(void)
- 	hw_setup(&hw);
- 
- 	/* register if */
--	idx = ide_register_hw(&hw, NULL, 1, &hwif);
--	if (idx == -1) {
-+	hwif = ide_find_port(hw.io_ports[IDE_DATA_OFFSET]);
-+	if (hwif == NULL) {
- 		printk(KERN_ERR "ide-h8300: IDE I/F register failed\n");
--		return;
-+		return -ENOENT;
- 	}
- 
-+	index = hwif->index;
-+	ide_init_port_data(hwif, index);
-+	ide_init_port_hw(hwif, &hw);
- 	hwif_setup(hwif);
--	printk(KERN_INFO "ide%d: H8/300 generic IDE interface\n", idx);
--	return;
-+	printk(KERN_INFO "ide%d: H8/300 generic IDE interface\n", index);
-+
-+	idx[0] = index;
-+
-+	ide_device_add(idx);
-+
-+	return 0;
  
- out_busy:
- 	printk(KERN_ERR "ide-h8300: IDE I/F resource already used.\n");
-+
-+	return -EBUSY;
- }
-+
-+module_init(h8300_ide_init);
-diff --git a/drivers/ide/ide-acpi.c b/drivers/ide/ide-acpi.c
-index 899d565..e888fc3 100644
---- a/drivers/ide/ide-acpi.c
-+++ b/drivers/ide/ide-acpi.c
-@@ -383,27 +383,19 @@ static int taskfile_load_raw(ide_drive_t *drive,
- 	       gtf->tfa[3], gtf->tfa[4], gtf->tfa[5], gtf->tfa[6]);
+ /**
+@@ -414,8 +410,6 @@ static void ide_hwif_restore(ide_hwif_t *hwif, ide_hwif_t *tmp_hwif)
+ 	hwif->cds			= tmp_hwif->cds;
+ #endif
  
- 	memset(&args, 0, sizeof(ide_task_t));
--	args.command_type = IDE_DRIVE_TASK_NO_DATA;
--	args.data_phase   = TASKFILE_NO_DATA;
--	args.handler      = &task_no_data_intr;
+-	hwif->fixup			= tmp_hwif->fixup;
+-
+ 	hwif->set_pio_mode		= tmp_hwif->set_pio_mode;
+ 	hwif->set_dma_mode		= tmp_hwif->set_dma_mode;
+ 	hwif->mdma_filter		= tmp_hwif->mdma_filter;
+@@ -424,7 +418,6 @@ static void ide_hwif_restore(ide_hwif_t *hwif, ide_hwif_t *tmp_hwif)
+ 	hwif->reset_poll		= tmp_hwif->reset_poll;
+ 	hwif->pre_reset			= tmp_hwif->pre_reset;
+ 	hwif->resetproc			= tmp_hwif->resetproc;
+-	hwif->intrproc			= tmp_hwif->intrproc;
+ 	hwif->maskproc			= tmp_hwif->maskproc;
+ 	hwif->quirkproc			= tmp_hwif->quirkproc;
+ 	hwif->busproc			= tmp_hwif->busproc;
+@@ -434,16 +427,13 @@ static void ide_hwif_restore(ide_hwif_t *hwif, ide_hwif_t *tmp_hwif)
+ 	hwif->atapi_input_bytes		= tmp_hwif->atapi_input_bytes;
+ 	hwif->atapi_output_bytes	= tmp_hwif->atapi_output_bytes;
  
- 	/* convert gtf to IDE Taskfile */
--	args.tfRegister[1] = gtf->tfa[0];	/* 0x1f1 */
--	args.tfRegister[2] = gtf->tfa[1];	/* 0x1f2 */
--	args.tfRegister[3] = gtf->tfa[2];	/* 0x1f3 */
--	args.tfRegister[4] = gtf->tfa[3];	/* 0x1f4 */
--	args.tfRegister[5] = gtf->tfa[4];	/* 0x1f5 */
--	args.tfRegister[6] = gtf->tfa[5];	/* 0x1f6 */
--	args.tfRegister[7] = gtf->tfa[6];	/* 0x1f7 */
-+	memcpy(&args.tf_array[7], &gtf->tfa, 7);
-+	args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
++	hwif->dma_host_set		= tmp_hwif->dma_host_set;
+ 	hwif->dma_setup			= tmp_hwif->dma_setup;
+ 	hwif->dma_exec_cmd		= tmp_hwif->dma_exec_cmd;
+ 	hwif->dma_start			= tmp_hwif->dma_start;
+ 	hwif->ide_dma_end		= tmp_hwif->ide_dma_end;
+-	hwif->ide_dma_on		= tmp_hwif->ide_dma_on;
+-	hwif->dma_off_quietly		= tmp_hwif->dma_off_quietly;
+ 	hwif->ide_dma_test_irq		= tmp_hwif->ide_dma_test_irq;
+ 	hwif->ide_dma_clear_irq		= tmp_hwif->ide_dma_clear_irq;
+-	hwif->dma_host_on		= tmp_hwif->dma_host_on;
+-	hwif->dma_host_off		= tmp_hwif->dma_host_off;
+ 	hwif->dma_lost_irq		= tmp_hwif->dma_lost_irq;
+ 	hwif->dma_timeout		= tmp_hwif->dma_timeout;
  
- 	if (ide_noacpitfs) {
- 		DEBPRINT("_GTF execution disabled\n");
- 		return err;
- 	}
+@@ -468,7 +458,6 @@ static void ide_hwif_restore(ide_hwif_t *hwif, ide_hwif_t *tmp_hwif)
+ #endif
  
--	err = ide_raw_taskfile(drive, &args, NULL);
-+	err = ide_no_data_taskfile(drive, &args);
- 	if (err)
--		printk(KERN_ERR "%s: ide_raw_taskfile failed: %u\n",
-+		printk(KERN_ERR "%s: ide_no_data_taskfile failed: %u\n",
- 		       __FUNCTION__, err);
+ 	hwif->dma_base			= tmp_hwif->dma_base;
+-	hwif->dma_master		= tmp_hwif->dma_master;
+ 	hwif->dma_command		= tmp_hwif->dma_command;
+ 	hwif->dma_vendor1		= tmp_hwif->dma_vendor1;
+ 	hwif->dma_status		= tmp_hwif->dma_status;
+@@ -602,7 +591,6 @@ void ide_unregister(unsigned int index)
+ 		(void) ide_release_dma(hwif);
  
- 	return err;
-diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c
-index c7d77f0..44b033e 100644
---- a/drivers/ide/ide-cd.c
-+++ b/drivers/ide/ide-cd.c
-@@ -917,19 +917,13 @@ static ide_startstop_t cdrom_start_packet_command(ide_drive_t *drive,
- 	if (ide_wait_stat(&startstop, drive, 0, BUSY_STAT, WAIT_READY))
- 		return startstop;
+ 		hwif->dma_base = 0;
+-		hwif->dma_master = 0;
+ 		hwif->dma_command = 0;
+ 		hwif->dma_vendor1 = 0;
+ 		hwif->dma_status = 0;
+@@ -617,7 +605,7 @@ void ide_unregister(unsigned int index)
+ 	tmp_hwif = *hwif;
  
-+	/* FIXME: for Virtual DMA we must check harder */
- 	if (info->dma)
- 		info->dma = !hwif->dma_setup(drive);
+ 	/* restore hwif data to pristine status */
+-	init_hwif_data(hwif, index);
++	ide_init_port_data(hwif, index);
+ 	init_hwif_default(hwif, index);
  
- 	/* Set up the controller registers. */
--	/* FIXME: for Virtual DMA we must check harder */
--	HWIF(drive)->OUTB(info->dma, IDE_FEATURE_REG);
--	HWIF(drive)->OUTB(0, IDE_IREASON_REG);
--	HWIF(drive)->OUTB(0, IDE_SECTOR_REG);
--
--	HWIF(drive)->OUTB(xferlen & 0xff, IDE_BCOUNTL_REG);
--	HWIF(drive)->OUTB(xferlen >> 8  , IDE_BCOUNTH_REG);
--	if (IDE_CONTROL_REG)
--		HWIF(drive)->OUTB(drive->ctl, IDE_CONTROL_REG);
-+	ide_pktcmd_tf_load(drive, IDE_TFLAG_OUT_NSECT | IDE_TFLAG_OUT_LBAL |
-+			   IDE_TFLAG_NO_SELECT_MASK, xferlen, info->dma);
-  
- 	if (CDROM_CONFIG_FLAGS (drive)->drq_interrupt) {
- 		/* waiting for CDB interrupt, not DMA yet. */
-diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c
-index b178190..717e114 100644
---- a/drivers/ide/ide-disk.c
-+++ b/drivers/ide/ide-disk.c
-@@ -129,6 +129,50 @@ static int lba_capacity_is_ok (struct hd_driveid *id)
- 	return 0;	/* lba_capacity value may be bad */
+ 	ide_hwif_restore(hwif, &tmp_hwif);
+@@ -683,24 +671,34 @@ void ide_setup_ports (	hw_regs_t *hw,
+  */
  }
  
-+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,
-+};
-+
-+static const u8 ide_data_phases[] = {
-+	TASKFILE_MULTI_IN,
-+	TASKFILE_MULTI_OUT,
-+	TASKFILE_IN,
-+	TASKFILE_OUT,
-+	TASKFILE_IN_DMA,
-+	TASKFILE_OUT_DMA,
-+};
-+
-+static void ide_tf_set_cmd(ide_drive_t *drive, ide_task_t *task, u8 dma)
++void ide_init_port_hw(ide_hwif_t *hwif, hw_regs_t *hw)
 +{
-+	u8 index, lba48, write;
-+
-+	lba48 = (task->tf_flags & IDE_TFLAG_LBA48) ? 2 : 0;
-+	write = (task->tf_flags & IDE_TFLAG_WRITE) ? 1 : 0;
-+
-+	if (dma)
-+		index = drive->vdma ? 4 : 8;
-+	else
-+		index = drive->mult_count ? 0 : 4;
-+
-+	task->tf.command = ide_rw_cmds[index + lba48 + write];
-+
-+	if (dma)
-+		index = 8; /* fixup index */
-+
-+	task->data_phase = ide_data_phases[index / 2 + write];
++	memcpy(hwif->io_ports, hw->io_ports, sizeof(hwif->io_ports));
++	hwif->irq = hw->irq;
++	hwif->noprobe = 0;
++	hwif->chipset = hw->chipset;
++	hwif->gendev.parent = hw->dev;
++	hwif->ack_intr = hw->ack_intr;
 +}
++EXPORT_SYMBOL_GPL(ide_init_port_hw);
 +
- /*
-  * __ide_do_rw_disk() issues READ and WRITE commands to a disk,
-  * using LBA if supported, or CHS otherwise, to address sectors.
-@@ -137,11 +181,11 @@ static ide_startstop_t __ide_do_rw_disk(ide_drive_t *drive, struct request *rq,
+ /**
+  *	ide_register_hw		-	register IDE interface
+  *	@hw: hardware registers
+- *	@fixup: fixup function
+- *	@initializing: set while initializing built-in drivers
++ *	@quirkproc: quirkproc function
+  *	@hwifp: pointer to returned hwif
+  *
+  *	Register an IDE interface, specifying exactly the registers etc.
+- *	Set init=1 iff calling before probes have taken place.
+  *
+  *	Returns -1 on error.
+  */
+ 
+-int ide_register_hw(hw_regs_t *hw, void (*fixup)(ide_hwif_t *),
+-		    int initializing, ide_hwif_t **hwifp)
++int ide_register_hw(hw_regs_t *hw, void (*quirkproc)(ide_drive_t *),
++		    ide_hwif_t **hwifp)
  {
- 	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;
--	task_ioreg_t command	= WIN_NOP;
--	ata_nsector_t		nsectors;
--
--	nsectors.all		= (u16) rq->nr_sectors;
-+	ide_task_t		task;
-+	struct ide_taskfile	*tf = &task.tf;
-+	ide_startstop_t		rc;
+ 	int index, retry = 1;
+ 	ide_hwif_t *hwif;
++	u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
  
- 	if ((hwif->host_flags & IDE_HFLAG_NO_LBA48_DMA) && lba48 && dma) {
- 		if (block + rq->nr_sectors > 1ULL << 28)
-@@ -155,121 +199,71 @@ static ide_startstop_t __ide_do_rw_disk(ide_drive_t *drive, struct request *rq,
- 		ide_map_sg(drive, rq);
+ 	do {
+ 		for (index = 0; index < MAX_HWIFS; ++index) {
+@@ -712,8 +710,7 @@ int ide_register_hw(hw_regs_t *hw, void (*fixup)(ide_hwif_t *),
+ 			hwif = &ide_hwifs[index];
+ 			if (hwif->hold)
+ 				continue;
+-			if ((!hwif->present && !hwif->mate && !initializing) ||
+-			    (!hwif->io_ports[IDE_DATA_OFFSET] && initializing))
++			if (!hwif->present && hwif->mate == NULL)
+ 				goto found;
+ 		}
+ 		for (index = 0; index < MAX_HWIFS; index++)
+@@ -724,29 +721,23 @@ found:
+ 	if (hwif->present)
+ 		ide_unregister(index);
+ 	else if (!hwif->hold) {
+-		init_hwif_data(hwif, index);
++		ide_init_port_data(hwif, index);
+ 		init_hwif_default(hwif, index);
  	}
+ 	if (hwif->present)
+ 		return -1;
+-	memcpy(hwif->io_ports, hw->io_ports, sizeof(hwif->io_ports));
+-	hwif->irq = hw->irq;
+-	hwif->noprobe = 0;
+-	hwif->fixup = fixup;
+-	hwif->chipset = hw->chipset;
+-	hwif->gendev.parent = hw->dev;
+-	hwif->ack_intr = hw->ack_intr;
  
--	if (IDE_CONTROL_REG)
--		hwif->OUTB(drive->ctl, IDE_CONTROL_REG);
--
--	/* FIXME: SELECT_MASK(drive, 0) ? */
-+	memset(&task, 0, sizeof(task));
-+	task.tf_flags = IDE_TFLAG_NO_SELECT_MASK;  /* FIXME? */
-+	task.tf_flags |= (IDE_TFLAG_TF | IDE_TFLAG_DEVICE);
- 
- 	if (drive->select.b.lba) {
- 		if (lba48) {
--			task_ioreg_t tasklets[10];
--
- 			pr_debug("%s: LBA=0x%012llx\n", drive->name,
- 					(unsigned long long)block);
+-	if (initializing == 0) {
+-		u8 idx[4] = { index, 0xff, 0xff, 0xff };
++	ide_init_port_hw(hwif, hw);
++	hwif->quirkproc = quirkproc;
  
--			tasklets[0] = 0;
--			tasklets[1] = 0;
--			tasklets[2] = nsectors.b.low;
--			tasklets[3] = nsectors.b.high;
--			tasklets[4] = (task_ioreg_t) block;
--			tasklets[5] = (task_ioreg_t) (block>>8);
--			tasklets[6] = (task_ioreg_t) (block>>16);
--			tasklets[7] = (task_ioreg_t) (block>>24);
--			if (sizeof(block) == 4) {
--				tasklets[8] = (task_ioreg_t) 0;
--				tasklets[9] = (task_ioreg_t) 0;
--			} else {
--				tasklets[8] = (task_ioreg_t)((u64)block >> 32);
--				tasklets[9] = (task_ioreg_t)((u64)block >> 40);
-+			tf->hob_nsect = (nsectors >> 8) & 0xff;
-+			tf->hob_lbal  = (u8)(block >> 24);
-+			if (sizeof(block) != 4) {
-+				tf->hob_lbam = (u8)((u64)block >> 32);
-+				tf->hob_lbah = (u8)((u64)block >> 40);
- 			}
--#ifdef DEBUG
--			printk("%s: 0x%02x%02x 0x%02x%02x%02x%02x%02x%02x\n",
--				drive->name, tasklets[3], tasklets[2],
--				tasklets[9], tasklets[8], tasklets[7],
--				tasklets[6], tasklets[5], tasklets[4]);
--#endif
--			hwif->OUTB(tasklets[1], IDE_FEATURE_REG);
--			hwif->OUTB(tasklets[3], IDE_NSECTOR_REG);
--			hwif->OUTB(tasklets[7], IDE_SECTOR_REG);
--			hwif->OUTB(tasklets[8], IDE_LCYL_REG);
--			hwif->OUTB(tasklets[9], IDE_HCYL_REG);
--
--			hwif->OUTB(tasklets[0], IDE_FEATURE_REG);
--			hwif->OUTB(tasklets[2], IDE_NSECTOR_REG);
--			hwif->OUTB(tasklets[4], IDE_SECTOR_REG);
--			hwif->OUTB(tasklets[5], IDE_LCYL_REG);
--			hwif->OUTB(tasklets[6], IDE_HCYL_REG);
--			hwif->OUTB(0x00|drive->select.all,IDE_SELECT_REG);
-+
-+			tf->nsect  = nsectors & 0xff;
-+			tf->lbal   = (u8) block;
-+			tf->lbam   = (u8)(block >>  8);
-+			tf->lbah   = (u8)(block >> 16);
+-		ide_device_add(idx);
+-	}
++	idx[0] = index;
 +
-+			task.tf_flags |= (IDE_TFLAG_LBA48 | IDE_TFLAG_HOB);
- 		} else {
--			hwif->OUTB(0x00, IDE_FEATURE_REG);
--			hwif->OUTB(nsectors.b.low, IDE_NSECTOR_REG);
--			hwif->OUTB(block, IDE_SECTOR_REG);
--			hwif->OUTB(block>>=8, IDE_LCYL_REG);
--			hwif->OUTB(block>>=8, IDE_HCYL_REG);
--			hwif->OUTB(((block>>8)&0x0f)|drive->select.all,IDE_SELECT_REG);
-+			tf->nsect  = nsectors & 0xff;
-+			tf->lbal   = block;
-+			tf->lbam   = block >>= 8;
-+			tf->lbah   = block >>= 8;
-+			tf->device = (block >> 8) & 0xf;
- 		}
- 	} else {
- 		unsigned int sect,head,cyl,track;
- 		track = (int)block / drive->sect;
- 		sect  = (int)block % drive->sect + 1;
--		hwif->OUTB(sect, IDE_SECTOR_REG);
- 		head  = track % drive->head;
- 		cyl   = track / drive->head;
- 
- 		pr_debug("%s: CHS=%u/%u/%u\n", drive->name, cyl, head, sect);
- 
--		hwif->OUTB(0x00, IDE_FEATURE_REG);
--		hwif->OUTB(nsectors.b.low, IDE_NSECTOR_REG);
--		hwif->OUTB(cyl, IDE_LCYL_REG);
--		hwif->OUTB(cyl>>8, IDE_HCYL_REG);
--		hwif->OUTB(head|drive->select.all,IDE_SELECT_REG);
-+		tf->nsect  = nsectors & 0xff;
-+		tf->lbal   = sect;
-+		tf->lbam   = cyl;
-+		tf->lbah   = cyl >> 8;
-+		tf->device = head;
- 	}
++	ide_device_add(idx);
  
--	if (dma) {
--		if (!hwif->dma_setup(drive)) {
--			if (rq_data_dir(rq)) {
--				command = lba48 ? WIN_WRITEDMA_EXT : WIN_WRITEDMA;
--				if (drive->vdma)
--					command = lba48 ? WIN_WRITE_EXT: WIN_WRITE;
--			} else {
--				command = lba48 ? WIN_READDMA_EXT : WIN_READDMA;
--				if (drive->vdma)
--					command = lba48 ? WIN_READ_EXT: WIN_READ;
--			}
--			hwif->dma_exec_cmd(drive, command);
--			hwif->dma_start(drive);
--			return ide_started;
--		}
--		/* fallback to PIO */
--		ide_init_sg_cmd(drive, rq);
--	}
--
--	if (rq_data_dir(rq) == READ) {
--
--		if (drive->mult_count) {
--			hwif->data_phase = TASKFILE_MULTI_IN;
--			command = lba48 ? WIN_MULTREAD_EXT : WIN_MULTREAD;
--		} else {
--			hwif->data_phase = TASKFILE_IN;
--			command = lba48 ? WIN_READ_EXT : WIN_READ;
--		}
-+	if (rq_data_dir(rq))
-+		task.tf_flags |= IDE_TFLAG_WRITE;
+ 	if (hwifp)
+ 		*hwifp = hwif;
  
--		ide_execute_command(drive, command, &task_in_intr, WAIT_CMD, NULL);
--		return ide_started;
--	} else {
--		if (drive->mult_count) {
--			hwif->data_phase = TASKFILE_MULTI_OUT;
--			command = lba48 ? WIN_MULTWRITE_EXT : WIN_MULTWRITE;
--		} else {
--			hwif->data_phase = TASKFILE_OUT;
--			command = lba48 ? WIN_WRITE_EXT : WIN_WRITE;
--		}
-+	ide_tf_set_cmd(drive, &task, dma);
-+	if (!dma)
-+		hwif->data_phase = task.data_phase;
-+	task.rq = rq;
+-	return (initializing || hwif->present) ? index : -1;
++	return hwif->present ? index : -1;
+ }
  
--		/* FIXME: ->OUTBSYNC ? */
--		hwif->OUTB(command, IDE_COMMAND_REG);
-+	rc = do_rw_taskfile(drive, &task);
+ EXPORT_SYMBOL(ide_register_hw);
+@@ -839,7 +830,7 @@ int set_using_dma(ide_drive_t *drive, int arg)
+ 	if (!drive->id || !(drive->id->capability & 1))
+ 		goto out;
  
--		return pre_task_out_intr(drive, rq);
-+	if (rc == ide_stopped && dma) {
-+		/* fallback to PIO */
-+		task.tf_flags |= IDE_TFLAG_DMA_PIO_FALLBACK;
-+		ide_tf_set_cmd(drive, &task, 0);
-+		hwif->data_phase = task.data_phase;
-+		ide_init_sg_cmd(drive, rq);
-+		rc = do_rw_taskfile(drive, &task);
- 	}
+-	if (hwif->ide_dma_on == NULL)
++	if (hwif->dma_host_set == NULL)
+ 		goto out;
+ 
+ 	err = -EBUSY;
+@@ -854,8 +845,7 @@ int set_using_dma(ide_drive_t *drive, int arg)
+ 	err = 0;
+ 
+ 	if (arg) {
+-		hwif->dma_off_quietly(drive);
+-		if (ide_set_dma(drive) || hwif->ide_dma_on(drive))
++		if (ide_set_dma(drive))
+ 			err = -EIO;
+ 	} else
+ 		ide_dma_off(drive);
+@@ -888,7 +878,10 @@ int set_pio_mode(ide_drive_t *drive, int arg)
+ 
+ 	if (drive->special.b.set_tune)
+ 		return -EBUSY;
 +
-+	return rc;
+ 	ide_init_drive_cmd(&rq);
++	rq.cmd_type = REQ_TYPE_ATA_TASKFILE;
++
+ 	drive->tune_req = (u8) arg;
+ 	drive->special.b.set_tune = 1;
+ 	(void) ide_do_drive_cmd(drive, &rq, ide_wait);
+@@ -1070,7 +1063,7 @@ int generic_ide_ioctl(ide_drive_t *drive, struct file *file, struct block_device
+ 			ide_init_hwif_ports(&hw, (unsigned long) args[0],
+ 					    (unsigned long) args[1], NULL);
+ 			hw.irq = args[2];
+-			if (ide_register_hw(&hw, NULL, 0, NULL) == -1)
++			if (ide_register_hw(&hw, NULL, NULL) == -1)
+ 				return -EIO;
+ 			return 0;
+ 		}
+@@ -1231,26 +1224,12 @@ static int __init match_parm (char *s, const char *keywords[], int vals[], int m
+ 	return 0;	/* zero = nothing matched */
  }
  
- /*
-@@ -307,57 +301,29 @@ static ide_startstop_t ide_do_rw_disk (ide_drive_t *drive, struct request *rq, s
-  * Queries for true maximum capacity of the drive.
-  * Returns maximum LBA address (> 0) of the drive, 0 if failed.
-  */
--static unsigned long idedisk_read_native_max_address(ide_drive_t *drive)
-+static u64 idedisk_read_native_max_address(ide_drive_t *drive, int lba48)
- {
- 	ide_task_t args;
--	unsigned long addr = 0;
-+	struct ide_taskfile *tf = &args.tf;
-+	u64 addr = 0;
+-#ifdef CONFIG_BLK_DEV_ALI14XX
+ extern int probe_ali14xx;
+-extern int ali14xx_init(void);
+-#endif
+-#ifdef CONFIG_BLK_DEV_UMC8672
+ extern int probe_umc8672;
+-extern int umc8672_init(void);
+-#endif
+-#ifdef CONFIG_BLK_DEV_DTC2278
+ extern int probe_dtc2278;
+-extern int dtc2278_init(void);
+-#endif
+-#ifdef CONFIG_BLK_DEV_HT6560B
+ extern int probe_ht6560b;
+-extern int ht6560b_init(void);
+-#endif
+-#ifdef CONFIG_BLK_DEV_QD65XX
+ extern int probe_qd65xx;
+-extern int qd65xx_init(void);
+-#endif
++extern int cmd640_vlb;
  
- 	/* Create IDE/ATA command request structure */
- 	memset(&args, 0, sizeof(ide_task_t));
--	args.tfRegister[IDE_SELECT_OFFSET]	= 0x40;
--	args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_READ_NATIVE_MAX;
--	args.command_type			= IDE_DRIVE_TASK_NO_DATA;
--	args.handler				= &task_no_data_intr;
-+	if (lba48)
-+		tf->command = WIN_READ_NATIVE_MAX_EXT;
-+	else
-+		tf->command = WIN_READ_NATIVE_MAX;
-+	tf->device  = ATA_LBA;
-+	args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
-+	if (lba48)
-+		args.tf_flags |= (IDE_TFLAG_LBA48 | IDE_TFLAG_HOB);
- 	/* submit command request */
--	ide_raw_taskfile(drive, &args, NULL);
-+	ide_no_data_taskfile(drive, &args);
+ static int __initdata is_chipset_set[MAX_HWIFS];
  
- 	/* if OK, compute maximum address value */
--	if ((args.tfRegister[IDE_STATUS_OFFSET] & 0x01) == 0) {
--		addr = ((args.tfRegister[IDE_SELECT_OFFSET] & 0x0f) << 24)
--		     | ((args.tfRegister[  IDE_HCYL_OFFSET]       ) << 16)
--		     | ((args.tfRegister[  IDE_LCYL_OFFSET]       ) <<  8)
--		     | ((args.tfRegister[IDE_SECTOR_OFFSET]       ));
--		addr++;	/* since the return value is (maxlba - 1), we add 1 */
--	}
--	return addr;
--}
-+	if ((tf->status & 0x01) == 0)
-+		addr = ide_get_lba_addr(tf, lba48) + 1;
+@@ -1327,7 +1306,7 @@ static int __init ide_setup(char *s)
+ 	if (s[0] == 'h' && s[1] == 'd' && s[2] >= 'a' && s[2] <= max_drive) {
+ 		const char *hd_words[] = {
+ 			"none", "noprobe", "nowerr", "cdrom", "nodma",
+-			"autotune", "noautotune", "minus8", "swapdata", "bswap",
++			"autotune", "noautotune", "-8", "-9", "-10",
+ 			"noflush", "remap", "remap63", "scsi", NULL };
+ 		unit = s[2] - 'a';
+ 		hw   = unit / MAX_DRIVES;
+@@ -1363,10 +1342,6 @@ static int __init ide_setup(char *s)
+ 			case -7: /* "noautotune" */
+ 				drive->autotune = IDE_TUNE_NOAUTO;
+ 				goto obsolete_option;
+-			case -9: /* "swapdata" */
+-			case -10: /* "bswap" */
+-				drive->bswap = 1;
+-				goto done;
+ 			case -11: /* noflush */
+ 				drive->noflush = 1;
+ 				goto done;
+@@ -1466,11 +1441,8 @@ static int __init ide_setup(char *s)
+ #endif
+ #ifdef CONFIG_BLK_DEV_CMD640
+ 			case -14: /* "cmd640_vlb" */
+-			{
+-				extern int cmd640_vlb; /* flag for cmd640.c */
+ 				cmd640_vlb = 1;
+ 				goto done;
+-			}
+ #endif
+ #ifdef CONFIG_BLK_DEV_HT6560B
+ 			case -13: /* "ht6560b" */
+@@ -1560,79 +1532,6 @@ done:
+ 	return 1;
+ }
  
--static unsigned long long idedisk_read_native_max_address_ext(ide_drive_t *drive)
--{
--	ide_task_t args;
--	unsigned long long addr = 0;
--
--	/* Create IDE/ATA command request structure */
--	memset(&args, 0, sizeof(ide_task_t));
+-extern void __init pnpide_init(void);
+-extern void __exit pnpide_exit(void);
+-extern void __init h8300_ide_init(void);
 -
--	args.tfRegister[IDE_SELECT_OFFSET]	= 0x40;
--	args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_READ_NATIVE_MAX_EXT;
--	args.command_type			= IDE_DRIVE_TASK_NO_DATA;
--	args.handler				= &task_no_data_intr;
--        /* submit command request */
--        ide_raw_taskfile(drive, &args, NULL);
+-/*
+- * probe_for_hwifs() finds/initializes "known" IDE interfaces
+- */
+-static void __init probe_for_hwifs (void)
+-{
+-#ifdef CONFIG_IDEPCI_PCIBUS_ORDER
+-	ide_scan_pcibus(ide_scan_direction);
+-#endif
 -
--	/* if OK, compute maximum address value */
--	if ((args.tfRegister[IDE_STATUS_OFFSET] & 0x01) == 0) {
--		u32 high = (args.hobRegister[IDE_HCYL_OFFSET] << 16) |
--			   (args.hobRegister[IDE_LCYL_OFFSET] <<  8) |
--			    args.hobRegister[IDE_SECTOR_OFFSET];
--		u32 low  = ((args.tfRegister[IDE_HCYL_OFFSET])<<16) |
--			   ((args.tfRegister[IDE_LCYL_OFFSET])<<8) |
--			    (args.tfRegister[IDE_SECTOR_OFFSET]);
--		addr = ((__u64)high << 24) | low;
--		addr++;	/* since the return value is (maxlba - 1), we add 1 */
+-#ifdef CONFIG_ETRAX_IDE
+-	{
+-		extern void init_e100_ide(void);
+-		init_e100_ide();
 -	}
- 	return addr;
- }
- 
-@@ -365,67 +331,37 @@ static unsigned long long idedisk_read_native_max_address_ext(ide_drive_t *drive
-  * Sets maximum virtual LBA address of the drive.
-  * Returns new maximum virtual LBA address (> 0) or 0 on failure.
-  */
--static unsigned long idedisk_set_max_address(ide_drive_t *drive, unsigned long addr_req)
--{
--	ide_task_t args;
--	unsigned long addr_set = 0;
--	
--	addr_req--;
--	/* Create IDE/ATA command request structure */
--	memset(&args, 0, sizeof(ide_task_t));
--	args.tfRegister[IDE_SECTOR_OFFSET]	= ((addr_req >>  0) & 0xff);
--	args.tfRegister[IDE_LCYL_OFFSET]	= ((addr_req >>  8) & 0xff);
--	args.tfRegister[IDE_HCYL_OFFSET]	= ((addr_req >> 16) & 0xff);
--	args.tfRegister[IDE_SELECT_OFFSET]	= ((addr_req >> 24) & 0x0f) | 0x40;
--	args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_SET_MAX;
--	args.command_type			= IDE_DRIVE_TASK_NO_DATA;
--	args.handler				= &task_no_data_intr;
--	/* submit command request */
--	ide_raw_taskfile(drive, &args, NULL);
--	/* if OK, read new maximum address value */
--	if ((args.tfRegister[IDE_STATUS_OFFSET] & 0x01) == 0) {
--		addr_set = ((args.tfRegister[IDE_SELECT_OFFSET] & 0x0f) << 24)
--			 | ((args.tfRegister[  IDE_HCYL_OFFSET]       ) << 16)
--			 | ((args.tfRegister[  IDE_LCYL_OFFSET]       ) <<  8)
--			 | ((args.tfRegister[IDE_SECTOR_OFFSET]       ));
--		addr_set++;
+-#endif /* CONFIG_ETRAX_IDE */
+-#ifdef CONFIG_BLK_DEV_CMD640
+-	{
+-		extern void ide_probe_for_cmd640x(void);
+-		ide_probe_for_cmd640x();
 -	}
--	return addr_set;
+-#endif /* CONFIG_BLK_DEV_CMD640 */
+-#ifdef CONFIG_BLK_DEV_IDE_PMAC
+-	{
+-		extern int pmac_ide_probe(void);
+-		(void)pmac_ide_probe();
+-	}
+-#endif /* CONFIG_BLK_DEV_IDE_PMAC */
+-#ifdef CONFIG_BLK_DEV_GAYLE
+-	{
+-		extern void gayle_init(void);
+-		gayle_init();
+-	}
+-#endif /* CONFIG_BLK_DEV_GAYLE */
+-#ifdef CONFIG_BLK_DEV_FALCON_IDE
+-	{
+-		extern void falconide_init(void);
+-		falconide_init();
+-	}
+-#endif /* CONFIG_BLK_DEV_FALCON_IDE */
+-#ifdef CONFIG_BLK_DEV_MAC_IDE
+-	{
+-		extern void macide_init(void);
+-		macide_init();
+-	}
+-#endif /* CONFIG_BLK_DEV_MAC_IDE */
+-#ifdef CONFIG_BLK_DEV_Q40IDE
+-	{
+-		extern void q40ide_init(void);
+-		q40ide_init();
+-	}
+-#endif /* CONFIG_BLK_DEV_Q40IDE */
+-#ifdef CONFIG_BLK_DEV_BUDDHA
+-	{
+-		extern void buddha_init(void);
+-		buddha_init();
+-	}
+-#endif /* CONFIG_BLK_DEV_BUDDHA */
+-#ifdef CONFIG_BLK_DEV_IDEPNP
+-	pnpide_init();
+-#endif
+-#ifdef CONFIG_H8300
+-	h8300_ide_init();
+-#endif
 -}
 -
--static unsigned long long idedisk_set_max_address_ext(ide_drive_t *drive, unsigned long long addr_req)
-+static u64 idedisk_set_max_address(ide_drive_t *drive, u64 addr_req, int lba48)
- {
- 	ide_task_t args;
--	unsigned long long addr_set = 0;
-+	struct ide_taskfile *tf = &args.tf;
-+	u64 addr_set = 0;
+-/*
+- * Probe module
+- */
+-
+ EXPORT_SYMBOL(ide_lock);
  
- 	addr_req--;
- 	/* Create IDE/ATA command request structure */
- 	memset(&args, 0, sizeof(ide_task_t));
--	args.tfRegister[IDE_SECTOR_OFFSET]	= ((addr_req >>  0) & 0xff);
--	args.tfRegister[IDE_LCYL_OFFSET]	= ((addr_req >>= 8) & 0xff);
--	args.tfRegister[IDE_HCYL_OFFSET]	= ((addr_req >>= 8) & 0xff);
--	args.tfRegister[IDE_SELECT_OFFSET]      = 0x40;
--	args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_SET_MAX_EXT;
--	args.hobRegister[IDE_SECTOR_OFFSET]	= (addr_req >>= 8) & 0xff;
--	args.hobRegister[IDE_LCYL_OFFSET]	= (addr_req >>= 8) & 0xff;
--	args.hobRegister[IDE_HCYL_OFFSET]	= (addr_req >>= 8) & 0xff;
--	args.hobRegister[IDE_SELECT_OFFSET]	= 0x40;
--	args.hobRegister[IDE_CONTROL_OFFSET_HOB]= (drive->ctl|0x80);
--	args.command_type			= IDE_DRIVE_TASK_NO_DATA;
--	args.handler				= &task_no_data_intr;
-+	tf->lbal     = (addr_req >>  0) & 0xff;
-+	tf->lbam     = (addr_req >>= 8) & 0xff;
-+	tf->lbah     = (addr_req >>= 8) & 0xff;
-+	if (lba48) {
-+		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;
-+	} else {
-+		tf->device   = (addr_req >>= 8) & 0x0f;
-+		tf->command  = WIN_SET_MAX;
-+	}
-+	tf->device |= ATA_LBA;
-+	args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
-+	if (lba48)
-+		args.tf_flags |= (IDE_TFLAG_LBA48 | IDE_TFLAG_HOB);
- 	/* submit command request */
--	ide_raw_taskfile(drive, &args, NULL);
-+	ide_no_data_taskfile(drive, &args);
- 	/* if OK, compute maximum address value */
--	if ((args.tfRegister[IDE_STATUS_OFFSET] & 0x01) == 0) {
--		u32 high = (args.hobRegister[IDE_HCYL_OFFSET] << 16) |
--			   (args.hobRegister[IDE_LCYL_OFFSET] <<  8) |
--			    args.hobRegister[IDE_SECTOR_OFFSET];
--		u32 low  = ((args.tfRegister[IDE_HCYL_OFFSET])<<16) |
--			   ((args.tfRegister[IDE_LCYL_OFFSET])<<8) |
--			    (args.tfRegister[IDE_SECTOR_OFFSET]);
--		addr_set = ((__u64)high << 24) | low;
--		addr_set++;
--	}
-+	if ((tf->status & 0x01) == 0)
-+		addr_set = ide_get_lba_addr(tf, lba48) + 1;
-+
- 	return addr_set;
+ static int ide_bus_match(struct device *dev, struct device_driver *drv)
+@@ -1779,30 +1678,6 @@ static int __init ide_init(void)
+ 
+ 	proc_ide_create();
+ 
+-#ifdef CONFIG_BLK_DEV_ALI14XX
+-	if (probe_ali14xx)
+-		(void)ali14xx_init();
+-#endif
+-#ifdef CONFIG_BLK_DEV_UMC8672
+-	if (probe_umc8672)
+-		(void)umc8672_init();
+-#endif
+-#ifdef CONFIG_BLK_DEV_DTC2278
+-	if (probe_dtc2278)
+-		(void)dtc2278_init();
+-#endif
+-#ifdef CONFIG_BLK_DEV_HT6560B
+-	if (probe_ht6560b)
+-		(void)ht6560b_init();
+-#endif
+-#ifdef CONFIG_BLK_DEV_QD65XX
+-	if (probe_qd65xx)
+-		(void)qd65xx_init();
+-#endif
+-
+-	/* Probe for special PCI and other "known" interface chipsets. */
+-	probe_for_hwifs();
+-
+ 	return 0;
  }
  
-@@ -471,10 +407,8 @@ static void idedisk_check_hpa(ide_drive_t *drive)
- 	int lba48 = idedisk_supports_lba48(drive->id);
+@@ -1838,10 +1713,6 @@ void __exit cleanup_module (void)
+ 	for (index = 0; index < MAX_HWIFS; ++index)
+ 		ide_unregister(index);
  
- 	capacity = drive->capacity64;
--	if (lba48)
--		set_max = idedisk_read_native_max_address_ext(drive);
--	else
--		set_max = idedisk_read_native_max_address(drive);
-+
-+	set_max = idedisk_read_native_max_address(drive, lba48);
+-#ifdef CONFIG_BLK_DEV_IDEPNP
+-	pnpide_exit();
+-#endif
+-
+ 	proc_ide_destroy();
  
- 	if (ide_in_drive_list(drive->id, hpa_list)) {
- 		/*
-@@ -495,10 +429,8 @@ static void idedisk_check_hpa(ide_drive_t *drive)
- 			 capacity, sectors_to_MB(capacity),
- 			 set_max, sectors_to_MB(set_max));
+ 	bus_unregister(&ide_bus_type);
+diff --git a/drivers/ide/legacy/Makefile b/drivers/ide/legacy/Makefile
+index 4098223..7043ec7 100644
+--- a/drivers/ide/legacy/Makefile
++++ b/drivers/ide/legacy/Makefile
+@@ -1,15 +1,24 @@
  
--	if (lba48)
--		set_max = idedisk_set_max_address_ext(drive, set_max);
--	else
--		set_max = idedisk_set_max_address(drive, set_max);
-+	set_max = idedisk_set_max_address(drive, set_max, lba48);
++# link order is important here
 +
- 	if (set_max) {
- 		drive->capacity64 = set_max;
- 		printk(KERN_INFO "%s: Host Protected Area disabled.\n",
-@@ -556,32 +488,32 @@ static sector_t idedisk_capacity (ide_drive_t *drive)
- static int smart_enable(ide_drive_t *drive)
- {
- 	ide_task_t args;
-+	struct ide_taskfile *tf = &args.tf;
+ obj-$(CONFIG_BLK_DEV_ALI14XX)		+= ali14xx.o
++obj-$(CONFIG_BLK_DEV_UMC8672)		+= umc8672.o
+ obj-$(CONFIG_BLK_DEV_DTC2278)		+= dtc2278.o
+ obj-$(CONFIG_BLK_DEV_HT6560B)		+= ht6560b.o
+ obj-$(CONFIG_BLK_DEV_QD65XX)		+= qd65xx.o
+-obj-$(CONFIG_BLK_DEV_UMC8672)		+= umc8672.o
  
- 	memset(&args, 0, sizeof(ide_task_t));
--	args.tfRegister[IDE_FEATURE_OFFSET]	= SMART_ENABLE;
--	args.tfRegister[IDE_LCYL_OFFSET]	= SMART_LCYL_PASS;
--	args.tfRegister[IDE_HCYL_OFFSET]	= SMART_HCYL_PASS;
--	args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_SMART;
--	args.command_type			= IDE_DRIVE_TASK_NO_DATA;
--	args.handler				= &task_no_data_intr;
--	return ide_raw_taskfile(drive, &args, NULL);
-+	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);
- }
+-obj-$(CONFIG_BLK_DEV_IDECS)		+= ide-cs.o
++obj-$(CONFIG_BLK_DEV_GAYLE)		+= gayle.o
++obj-$(CONFIG_BLK_DEV_FALCON_IDE)	+= falconide.o
++obj-$(CONFIG_BLK_DEV_MAC_IDE)		+= macide.o
++obj-$(CONFIG_BLK_DEV_Q40IDE)		+= q40ide.o
++obj-$(CONFIG_BLK_DEV_BUDDHA)		+= buddha.o
  
- static int get_smart_data(ide_drive_t *drive, u8 *buf, u8 sub_cmd)
- {
- 	ide_task_t args;
-+	struct ide_taskfile *tf = &args.tf;
+-obj-$(CONFIG_BLK_DEV_PLATFORM)		+= ide_platform.o
++ifeq ($(CONFIG_BLK_DEV_IDECS), m)
++	obj-m += ide-cs.o
++endif
  
- 	memset(&args, 0, sizeof(ide_task_t));
--	args.tfRegister[IDE_FEATURE_OFFSET]	= sub_cmd;
--	args.tfRegister[IDE_NSECTOR_OFFSET]	= 0x01;
--	args.tfRegister[IDE_LCYL_OFFSET]	= SMART_LCYL_PASS;
--	args.tfRegister[IDE_HCYL_OFFSET]	= SMART_HCYL_PASS;
--	args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_SMART;
--	args.command_type			= IDE_DRIVE_TASK_IN;
--	args.data_phase				= TASKFILE_IN;
--	args.handler				= &task_in_intr;
-+	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);
-+	return ide_raw_taskfile(drive, &args, buf, 1);
- }
+-# Last of all
+-obj-$(CONFIG_BLK_DEV_HD)		+= hd.o
++ifeq ($(CONFIG_BLK_DEV_PLATFORM), m)
++	obj-m += ide_platform.o
++endif
  
- static int proc_idedisk_read_cache
-@@ -659,19 +591,20 @@ static ide_proc_entry_t idedisk_proc[] = {
- static void idedisk_prepare_flush(struct request_queue *q, struct request *rq)
+ EXTRA_CFLAGS	:= -Idrivers/ide
+diff --git a/drivers/ide/legacy/ali14xx.c b/drivers/ide/legacy/ali14xx.c
+index 38c3a6d..5ec0be4 100644
+--- a/drivers/ide/legacy/ali14xx.c
++++ b/drivers/ide/legacy/ali14xx.c
+@@ -231,8 +231,7 @@ int probe_ali14xx = 0;
+ module_param_named(probe, probe_ali14xx, bool, 0);
+ MODULE_PARM_DESC(probe, "probe for ALI M14xx chipsets");
+ 
+-/* Can be called directly from ide.c. */
+-int __init ali14xx_init(void)
++static int __init ali14xx_init(void)
  {
- 	ide_drive_t *drive = q->queuedata;
-+	ide_task_t task;
+ 	if (probe_ali14xx == 0)
+ 		goto out;
+@@ -248,9 +247,7 @@ out:
+ 	return -ENODEV;
+ }
  
--	memset(rq->cmd, 0, sizeof(rq->cmd));
--
-+	memset(&task, 0, sizeof(task));
- 	if (ide_id_has_flush_cache_ext(drive->id) &&
- 	    (drive->capacity64 >= (1UL << 28)))
--		rq->cmd[0] = WIN_FLUSH_CACHE_EXT;
-+		task.tf.command = WIN_FLUSH_CACHE_EXT;
- 	else
--		rq->cmd[0] = WIN_FLUSH_CACHE;
-+		task.tf.command = WIN_FLUSH_CACHE;
-+	task.tf_flags	= IDE_TFLAG_OUT_TF | IDE_TFLAG_OUT_DEVICE;
-+	task.data_phase	= TASKFILE_NO_DATA;
+-#ifdef MODULE
+ module_init(ali14xx_init);
+-#endif
  
--
--	rq->cmd_type = REQ_TYPE_ATA_TASK;
-+	rq->cmd_type = REQ_TYPE_ATA_TASKFILE;
- 	rq->cmd_flags |= REQ_SOFTBARRIER;
--	rq->buffer = rq->cmd;
-+	rq->special = &task;
- }
+ MODULE_AUTHOR("see local file");
+ MODULE_DESCRIPTION("support of ALI 14XX IDE chipsets");
+diff --git a/drivers/ide/legacy/buddha.c b/drivers/ide/legacy/buddha.c
+index 4a0be25..74d28e0 100644
+--- a/drivers/ide/legacy/buddha.c
++++ b/drivers/ide/legacy/buddha.c
+@@ -112,6 +112,7 @@ typedef enum BuddhaType_Enum {
+     BOARD_BUDDHA, BOARD_CATWEASEL, BOARD_XSURF
+ } BuddhaType;
  
- /*
-@@ -687,8 +620,10 @@ static int set_multcount(ide_drive_t *drive, int arg)
++static const char *buddha_board_name[] = { "Buddha", "Catweasel", "X-Surf" };
  
- 	if (drive->special.b.set_multmode)
- 		return -EBUSY;
+     /*
+      *  Check and acknowledge the interrupt status
+@@ -143,11 +144,11 @@ static int xsurf_ack_intr(ide_hwif_t *hwif)
+      *  Probe for a Buddha or Catweasel IDE interface
+      */
+ 
+-void __init buddha_init(void)
++static int __init buddha_init(void)
+ {
+ 	hw_regs_t hw;
+ 	ide_hwif_t *hwif;
+-	int i, index;
++	int i;
+ 
+ 	struct zorro_dev *z = NULL;
+ 	u_long buddha_board = 0;
+@@ -156,6 +157,8 @@ void __init buddha_init(void)
+ 
+ 	while ((z = zorro_find_device(ZORRO_WILDCARD, z))) {
+ 		unsigned long board;
++		u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
 +
- 	ide_init_drive_cmd (&rq);
--	rq.cmd_type = REQ_TYPE_ATA_CMD;
-+	rq.cmd_type = REQ_TYPE_ATA_TASKFILE;
+ 		if (z->id == ZORRO_PROD_INDIVIDUAL_COMPUTERS_BUDDHA) {
+ 			buddha_num_hwifs = BUDDHA_NUM_HWIFS;
+ 			type=BOARD_BUDDHA;
+@@ -195,7 +198,10 @@ fail_base2:
+ 		/* X-Surf doesn't have this.  IRQs are always on */
+ 		if (type != BOARD_XSURF)
+ 			z_writeb(0, buddha_board+BUDDHA_IRQ_MR);
+-		
 +
- 	drive->mult_req = arg;
- 	drive->special.b.set_multmode = 1;
- 	(void) ide_do_drive_cmd (drive, &rq, ide_wait);
-@@ -753,12 +688,11 @@ static int write_cache(ide_drive_t *drive, int arg)
++		printk(KERN_INFO "ide: %s IDE controller\n",
++				 buddha_board_name[type]);
++
+ 		for(i=0;i<buddha_num_hwifs;i++) {
+ 			if(type != BOARD_XSURF) {
+ 				ide_setup_ports(&hw, (buddha_board+buddha_bases[i]),
+@@ -213,23 +219,23 @@ fail_base2:
+ 						IRQ_AMIGA_PORTS);
+ 			}	
  
- 	if (ide_id_has_flush_cache(drive->id)) {
- 		memset(&args, 0, sizeof(ide_task_t));
--		args.tfRegister[IDE_FEATURE_OFFSET]	= (arg) ?
-+		args.tf.feature = arg ?
- 			SETFEATURES_EN_WCACHE : SETFEATURES_DIS_WCACHE;
--		args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_SETFEATURES;
--		args.command_type		= IDE_DRIVE_TASK_NO_DATA;
--		args.handler			= &task_no_data_intr;
--		err = ide_raw_taskfile(drive, &args, NULL);
-+		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;
+-			index = ide_register_hw(&hw, NULL, 1, &hwif);
+-			if (index != -1) {
++			hwif = ide_find_port(hw.io_ports[IDE_DATA_OFFSET]);
++			if (hwif) {
++				u8 index = hwif->index;
++
++				ide_init_port_data(hwif, index);
++				ide_init_port_hw(hwif, &hw);
++
+ 				hwif->mmio = 1;
+-				printk("ide%d: ", index);
+-				switch(type) {
+-				case BOARD_BUDDHA:
+-					printk("Buddha");
+-					break;
+-				case BOARD_CATWEASEL:
+-					printk("Catweasel");
+-					break;
+-				case BOARD_XSURF:
+-					printk("X-Surf");
+-					break;
+-				}
+-				printk(" IDE interface\n");	    
+-			}		      
++
++				idx[i] = index;
++			}
+ 		}
++
++		ide_device_add(idx);
  	}
-@@ -774,12 +708,11 @@ static int do_idedisk_flushcache (ide_drive_t *drive)
- 
- 	memset(&args, 0, sizeof(ide_task_t));
- 	if (ide_id_has_flush_cache_ext(drive->id))
--		args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_FLUSH_CACHE_EXT;
-+		args.tf.command = WIN_FLUSH_CACHE_EXT;
- 	else
--		args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_FLUSH_CACHE;
--	args.command_type			= IDE_DRIVE_TASK_NO_DATA;
--	args.handler				= &task_no_data_intr;
--	return ide_raw_taskfile(drive, &args, NULL);
-+		args.tf.command = WIN_FLUSH_CACHE;
-+	args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
-+	return ide_no_data_taskfile(drive, &args);
++
++	return 0;
  }
++
++module_init(buddha_init);
+diff --git a/drivers/ide/legacy/dtc2278.c b/drivers/ide/legacy/dtc2278.c
+index 24a845d..13eee6d 100644
+--- a/drivers/ide/legacy/dtc2278.c
++++ b/drivers/ide/legacy/dtc2278.c
+@@ -150,8 +150,7 @@ int probe_dtc2278 = 0;
+ module_param_named(probe, probe_dtc2278, bool, 0);
+ MODULE_PARM_DESC(probe, "probe for DTC2278xx chipsets");
  
- static int set_acoustic (ide_drive_t *drive, int arg)
-@@ -790,13 +723,11 @@ static int set_acoustic (ide_drive_t *drive, int arg)
- 		return -EINVAL;
- 
- 	memset(&args, 0, sizeof(ide_task_t));
--	args.tfRegister[IDE_FEATURE_OFFSET]	= (arg) ? SETFEATURES_EN_AAM :
--							  SETFEATURES_DIS_AAM;
--	args.tfRegister[IDE_NSECTOR_OFFSET]	= arg;
--	args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_SETFEATURES;
--	args.command_type = IDE_DRIVE_TASK_NO_DATA;
--	args.handler	  = &task_no_data_intr;
--	ide_raw_taskfile(drive, &args, NULL);
-+	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);
- 	drive->acoustic = arg;
+-/* Can be called directly from ide.c. */
+-int __init dtc2278_init(void)
++static int __init dtc2278_init(void)
+ {
+ 	if (probe_dtc2278 == 0)
+ 		return -ENODEV;
+@@ -163,9 +162,7 @@ int __init dtc2278_init(void)
  	return 0;
  }
-@@ -832,7 +763,6 @@ static void idedisk_add_settings(ide_drive_t *drive)
- 	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,	"bswap",	SETTING_READ,	TYPE_BYTE,	0,	1,			1,	1,	&drive->bswap,		NULL);
- 	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);
-@@ -1041,6 +971,17 @@ static ide_driver_t idedisk_driver = {
- #endif
- };
  
-+static int idedisk_set_doorlock(ide_drive_t *drive, int on)
-+{
-+	ide_task_t task;
+-#ifdef MODULE
+ module_init(dtc2278_init);
+-#endif
+ 
+ MODULE_AUTHOR("See Local File");
+ MODULE_DESCRIPTION("support of DTC-2278 VLB IDE chipsets");
+diff --git a/drivers/ide/legacy/falconide.c b/drivers/ide/legacy/falconide.c
+index 7d7936f..2860956 100644
+--- a/drivers/ide/legacy/falconide.c
++++ b/drivers/ide/legacy/falconide.c
+@@ -62,19 +62,31 @@ EXPORT_SYMBOL(falconide_intr_lock);
+      *  Probe for a Falcon IDE interface
+      */
+ 
+-void __init falconide_init(void)
++static int __init falconide_init(void)
+ {
+     if (MACH_IS_ATARI && ATARIHW_PRESENT(IDE)) {
+ 	hw_regs_t hw;
+-	int index;
 +
-+	memset(&task, 0, sizeof(task));
-+	task.tf.command = on ? WIN_DOORLOCK : WIN_DOORUNLOCK;
-+	task.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
++	printk(KERN_INFO "ide: Falcon IDE controller\n");
+ 
+ 	ide_setup_ports(&hw, ATA_HD_BASE, falconide_offsets,
+ 			0, 0, NULL,
+ //			falconide_iops,
+ 			IRQ_MFP_IDE);
+-	index = ide_register_hw(&hw, NULL, 1, NULL);
+ 
+-	if (index != -1)
+-	    printk("ide%d: Falcon IDE interface\n", index);
++	hwif = ide_find_port(hw.io_ports[IDE_DATA_OFFSET]);
++	if (hwif) {
++		u8 index = hwif->index;
++		u8 idx[4] = { index, 0xff, 0xff, 0xff };
 +
-+	return ide_no_data_taskfile(drive, &task);
-+}
++		ide_init_port_data(hwif, index);
++		ide_init_port_hw(hwif, &hw);
 +
- static int idedisk_open(struct inode *inode, struct file *filp)
- {
- 	struct gendisk *disk = inode->i_bdev->bd_disk;
-@@ -1055,18 +996,13 @@ static int idedisk_open(struct inode *inode, struct file *filp)
- 	idkp->openers++;
- 
- 	if (drive->removable && idkp->openers == 1) {
--		ide_task_t args;
--		memset(&args, 0, sizeof(ide_task_t));
--		args.tfRegister[IDE_COMMAND_OFFSET] = WIN_DOORLOCK;
--		args.command_type = IDE_DRIVE_TASK_NO_DATA;
--		args.handler	  = &task_no_data_intr;
- 		check_disk_change(inode->i_bdev);
- 		/*
- 		 * Ignore the return code from door_lock,
- 		 * since the open() has already succeeded,
- 		 * and the door_lock is irrelevant at this point.
- 		 */
--		if (drive->doorlocking && ide_raw_taskfile(drive, &args, NULL))
-+		if (drive->doorlocking && idedisk_set_doorlock(drive, 1))
- 			drive->doorlocking = 0;
- 	}
- 	return 0;
-@@ -1082,12 +1018,7 @@ static int idedisk_release(struct inode *inode, struct file *filp)
- 		ide_cacheflush_p(drive);
++		ide_device_add(idx);
++	}
+     }
++
++    return 0;
+ }
++
++module_init(falconide_init);
+diff --git a/drivers/ide/legacy/gayle.c b/drivers/ide/legacy/gayle.c
+index 53331ee..492fa04 100644
+--- a/drivers/ide/legacy/gayle.c
++++ b/drivers/ide/legacy/gayle.c
+@@ -110,12 +110,13 @@ static int gayle_ack_intr_a1200(ide_hwif_t *hwif)
+      *  Probe for a Gayle IDE interface (and optionally for an IDE doubler)
+      */
  
- 	if (drive->removable && idkp->openers == 1) {
--		ide_task_t args;
--		memset(&args, 0, sizeof(ide_task_t));
--		args.tfRegister[IDE_COMMAND_OFFSET] = WIN_DOORUNLOCK;
--		args.command_type = IDE_DRIVE_TASK_NO_DATA;
--		args.handler	  = &task_no_data_intr;
--		if (drive->doorlocking && ide_raw_taskfile(drive, &args, NULL))
-+		if (drive->doorlocking && idedisk_set_doorlock(drive, 0))
- 			drive->doorlocking = 0;
- 	}
+-void __init gayle_init(void)
++static int __init gayle_init(void)
+ {
+     int a4000, i;
++    u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
  
-diff --git a/drivers/ide/ide-dma.c b/drivers/ide/ide-dma.c
-index 4703837..5bf3203 100644
---- a/drivers/ide/ide-dma.c
-+++ b/drivers/ide/ide-dma.c
-@@ -153,13 +153,7 @@ ide_startstop_t ide_dma_intr (ide_drive_t *drive)
- 		if (!dma_stat) {
- 			struct request *rq = HWGROUP(drive)->rq;
+     if (!MACH_IS_AMIGA)
+-	return;
++	return -ENODEV;
  
--			if (rq->rq_disk) {
--				ide_driver_t *drv;
--
--				drv = *(ide_driver_t **)rq->rq_disk->private_data;
--				drv->end_request(drive, 1, rq->nr_sectors);
--			} else
--				ide_end_request(drive, 1, rq->nr_sectors);
-+			task_end_request(drive, rq, stat);
- 			return ide_stopped;
- 		}
- 		printk(KERN_ERR "%s: dma_intr: bad DMA status (dma_stat=%x)\n", 
-@@ -408,23 +402,29 @@ static int dma_timer_expiry (ide_drive_t *drive)
- }
+     if ((a4000 = AMIGAHW_PRESENT(A4000_IDE)) || AMIGAHW_PRESENT(A1200_IDE))
+ 	goto found;
+@@ -125,15 +126,21 @@ void __init gayle_init(void)
+ 			  NULL))
+ 	goto found;
+ #endif
+-    return;
++    return -ENODEV;
  
- /**
-- *	ide_dma_host_off	-	Generic DMA kill
-+ *	ide_dma_host_set	-	Enable/disable DMA on a host
-  *	@drive: drive to control
-  *
-- *	Perform the generic IDE controller DMA off operation. This
-- *	works for most IDE bus mastering controllers
-+ *	Enable/disable DMA on an IDE controller following generic
-+ *	bus-mastering IDE controller behaviour.
-  */
+ found:
++	printk(KERN_INFO "ide: Gayle IDE controller (A%d style%s)\n",
++			 a4000 ? 4000 : 1200,
++#ifdef CONFIG_BLK_DEV_IDEDOUBLER
++			 ide_doubler ? ", IDE doubler" :
++#endif
++			 "");
++
+     for (i = 0; i < GAYLE_NUM_PROBE_HWIFS; i++) {
+ 	unsigned long base, ctrlport, irqport;
+ 	ide_ack_intr_t *ack_intr;
+ 	hw_regs_t hw;
+ 	ide_hwif_t *hwif;
+-	int index;
+ 	unsigned long phys_base, res_start, res_n;
  
--void ide_dma_host_off(ide_drive_t *drive)
-+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->INB(hwif->dma_status);
+ 	if (a4000) {
+@@ -165,21 +172,23 @@ found:
+ //			&gayle_iops,
+ 			IRQ_AMIGA_PORTS);
  
--	hwif->OUTB((dma_stat & ~(1<<(5+unit))), hwif->dma_status);
-+	if (on)
-+		dma_stat |= (1 << (5 + unit));
-+	else
-+		dma_stat &= ~(1 << (5 + unit));
+-	index = ide_register_hw(&hw, NULL, 1, &hwif);
+-	if (index != -1) {
++	hwif = ide_find_port(base);
++	if (hwif) {
++	    u8 index = hwif->index;
 +
-+	hwif->OUTB(dma_stat, hwif->dma_status);
++	    ide_init_port_data(hwif, index);
++	    ide_init_port_hw(hwif, &hw);
++
+ 	    hwif->mmio = 1;
+-	    switch (i) {
+-		case 0:
+-		    printk("ide%d: Gayle IDE interface (A%d style)\n", index,
+-			   a4000 ? 4000 : 1200);
+-		    break;
+-#ifdef CONFIG_BLK_DEV_IDEDOUBLER
+-		case 1:
+-		    printk("ide%d: IDE doubler\n", index);
+-		    break;
+-#endif /* CONFIG_BLK_DEV_IDEDOUBLER */
+-	    }
++
++	    idx[i] = index;
+ 	} else
+ 	    release_mem_region(res_start, res_n);
+     }
++
++    ide_device_add(idx);
++
++    return 0;
  }
++
++module_init(gayle_init);
+diff --git a/drivers/ide/legacy/ht6560b.c b/drivers/ide/legacy/ht6560b.c
+index a4245d1..8da5031 100644
+--- a/drivers/ide/legacy/ht6560b.c
++++ b/drivers/ide/legacy/ht6560b.c
+@@ -307,8 +307,7 @@ int probe_ht6560b = 0;
+ module_param_named(probe, probe_ht6560b, bool, 0);
+ MODULE_PARM_DESC(probe, "probe for HT6560B chipset");
  
--EXPORT_SYMBOL(ide_dma_host_off);
-+EXPORT_SYMBOL_GPL(ide_dma_host_set);
-+#endif /* CONFIG_BLK_DEV_IDEDMA_PCI */
+-/* Can be called directly from ide.c. */
+-int __init ht6560b_init(void)
++static int __init ht6560b_init(void)
+ {
+ 	ide_hwif_t *hwif, *mate;
+ 	static u8 idx[4] = { 0, 1, 0xff, 0xff };
+@@ -369,9 +368,7 @@ release_region:
+ 	return -ENODEV;
+ }
  
- /**
-  *	ide_dma_off_quietly	-	Generic DMA kill
-@@ -438,11 +438,10 @@ void ide_dma_off_quietly(ide_drive_t *drive)
- 	drive->using_dma = 0;
- 	ide_toggle_bounce(drive, 0);
+-#ifdef MODULE
+ module_init(ht6560b_init);
+-#endif
  
--	drive->hwif->dma_host_off(drive);
-+	drive->hwif->dma_host_set(drive, 0);
+ MODULE_AUTHOR("See Local File");
+ MODULE_DESCRIPTION("HT-6560B EIDE-controller support");
+diff --git a/drivers/ide/legacy/ide-cs.c b/drivers/ide/legacy/ide-cs.c
+index 03715c0..f4ea15b 100644
+--- a/drivers/ide/legacy/ide-cs.c
++++ b/drivers/ide/legacy/ide-cs.c
+@@ -153,7 +153,7 @@ static int idecs_register(unsigned long io, unsigned long ctl, unsigned long irq
+     hw.irq = irq;
+     hw.chipset = ide_pci;
+     hw.dev = &handle->dev;
+-    return ide_register_hw(&hw, &ide_undecoded_slave, 0, NULL);
++    return ide_register_hw(&hw, &ide_undecoded_slave, NULL);
  }
  
- EXPORT_SYMBOL(ide_dma_off_quietly);
--#endif /* CONFIG_BLK_DEV_IDEDMA_PCI */
+ /*======================================================================
+diff --git a/drivers/ide/legacy/ide_platform.c b/drivers/ide/legacy/ide_platform.c
+index 7bb79f5..69a0fb0 100644
+--- a/drivers/ide/legacy/ide_platform.c
++++ b/drivers/ide/legacy/ide_platform.c
+@@ -28,39 +28,27 @@ static struct {
+ 	int index;
+ } hwif_prop;
  
- /**
-  *	ide_dma_off	-	disable DMA on a device
-@@ -455,56 +454,29 @@ EXPORT_SYMBOL(ide_dma_off_quietly);
- void ide_dma_off(ide_drive_t *drive)
+-static ide_hwif_t *__devinit plat_ide_locate_hwif(void __iomem *base,
+-	    void __iomem *ctrl, struct pata_platform_info *pdata, int irq,
+-	    int mmio)
++static void __devinit plat_ide_setup_ports(hw_regs_t *hw,
++					   void __iomem *base,
++					   void __iomem *ctrl,
++					   struct pata_platform_info *pdata,
++					   int irq)
  {
- 	printk(KERN_INFO "%s: DMA disabled\n", drive->name);
--	drive->hwif->dma_off_quietly(drive);
-+	ide_dma_off_quietly(drive);
- }
- 
- EXPORT_SYMBOL(ide_dma_off);
+ 	unsigned long port = (unsigned long)base;
+-	ide_hwif_t *hwif = ide_find_port(port);
+ 	int i;
  
--#ifdef CONFIG_BLK_DEV_IDEDMA_PCI
- /**
-- *	ide_dma_host_on	-	Enable DMA on a host
-- *	@drive: drive to enable for DMA
-- *
-- *	Enable DMA on an IDE controller following generic bus mastering
-- *	IDE controller behaviour
-- */
--
--void ide_dma_host_on(ide_drive_t *drive)
--{
--	if (drive->using_dma) {
--		ide_hwif_t *hwif	= HWIF(drive);
--		u8 unit			= (drive->select.b.unit & 0x01);
--		u8 dma_stat		= hwif->INB(hwif->dma_status);
--
--		hwif->OUTB((dma_stat|(1<<(5+unit))), hwif->dma_status);
--	}
--}
--
--EXPORT_SYMBOL(ide_dma_host_on);
+-	if (hwif == NULL)
+-		goto out;
 -
--/**
-- *	__ide_dma_on		-	Enable DMA on a device
-+ *	ide_dma_on		-	Enable DMA on a device
-  *	@drive: drive to enable DMA on
-  *
-  *	Enable IDE DMA for a device on this IDE controller.
-  */
-- 
--int __ide_dma_on (ide_drive_t *drive)
--{
--	/* consult the list of known "bad" drives */
--	if (__ide_dma_bad_drive(drive))
--		return 1;
- 
-+void ide_dma_on(ide_drive_t *drive)
-+{
- 	drive->using_dma = 1;
- 	ide_toggle_bounce(drive, 1);
+-	hwif->io_ports[IDE_DATA_OFFSET] = port;
++	hw->io_ports[IDE_DATA_OFFSET] = port;
  
--	drive->hwif->dma_host_on(drive);
+ 	port += (1 << pdata->ioport_shift);
+ 	for (i = IDE_ERROR_OFFSET; i <= IDE_STATUS_OFFSET;
+ 	     i++, port += (1 << pdata->ioport_shift))
+-		hwif->io_ports[i] = port;
 -
--	return 0;
-+	drive->hwif->dma_host_set(drive, 1);
- }
- 
--EXPORT_SYMBOL(__ide_dma_on);
-+EXPORT_SYMBOL(ide_dma_on);
+-	hwif->io_ports[IDE_CONTROL_OFFSET] = (unsigned long)ctrl;
++		hw->io_ports[i] = port;
  
-+#ifdef CONFIG_BLK_DEV_IDEDMA_PCI
- /**
-  *	ide_dma_setup	-	begin a DMA phase
-  *	@drive: target device
-@@ -759,6 +731,7 @@ EXPORT_SYMBOL_GPL(ide_find_dma_mode);
+-	hwif->irq = irq;
++	hw->io_ports[IDE_CONTROL_OFFSET] = (unsigned long)ctrl;
  
- static int ide_tune_dma(ide_drive_t *drive)
- {
-+	ide_hwif_t *hwif = drive->hwif;
- 	u8 speed;
+-	hwif->chipset = ide_generic;
++	hw->irq = irq;
  
- 	if (noautodma || drive->nodma || (drive->id->capability & 1) == 0)
-@@ -771,15 +744,21 @@ static int ide_tune_dma(ide_drive_t *drive)
- 	if (ide_id_dma_bug(drive))
- 		return 0;
+-	if (mmio) {
+-		hwif->mmio = 1;
+-		default_hwif_mmiops(hwif);
+-	}
+-
+-	hwif_prop.hwif = hwif;
+-	hwif_prop.index = hwif->index;
+-out:
+-	return hwif;
++	hw->chipset = ide_generic;
+ }
  
--	if (drive->hwif->host_flags & IDE_HFLAG_TRUST_BIOS_FOR_DMA)
-+	if (hwif->host_flags & IDE_HFLAG_TRUST_BIOS_FOR_DMA)
- 		return config_drive_for_dma(drive);
+ static int __devinit plat_ide_probe(struct platform_device *pdev)
+@@ -71,6 +59,7 @@ static int __devinit plat_ide_probe(struct platform_device *pdev)
+ 	u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
+ 	int ret = 0;
+ 	int mmio = 0;
++	hw_regs_t hw;
  
- 	speed = ide_max_dma_mode(drive);
+ 	pdata = pdev->dev.platform_data;
  
--	if (!speed)
--		return 0;
-+	if (!speed) {
-+		 /* is this really correct/needed? */
-+		if ((hwif->host_flags & IDE_HFLAG_CY82C693) &&
-+		    ide_dma_good_drive(drive))
-+			return 1;
-+		else
-+			return 0;
+@@ -106,15 +95,27 @@ static int __devinit plat_ide_probe(struct platform_device *pdev)
+ 			res_alt->start, res_alt->end - res_alt->start + 1);
+ 	}
+ 
+-	hwif = plat_ide_locate_hwif(hwif_prop.plat_ide_mapbase,
+-	         hwif_prop.plat_ide_alt_mapbase, pdata, res_irq->start, mmio);
+-
++	hwif = ide_find_port((unsigned long)hwif_prop.plat_ide_mapbase);
+ 	if (!hwif) {
+ 		ret = -ENODEV;
+ 		goto out;
+ 	}
+-	hwif->gendev.parent = &pdev->dev;
+-	hwif->noprobe = 0;
++
++	memset(&hw, 0, sizeof(hw));
++	plat_ide_setup_ports(&hw, hwif_prop.plat_ide_mapbase,
++			     hwif_prop.plat_ide_alt_mapbase,
++			     pdata, res_irq->start);
++	hw.dev = &pdev->dev;
++
++	ide_init_port_hw(hwif, &hw);
++
++	if (mmio) {
++		hwif->mmio = 1;
++		default_hwif_mmiops(hwif);
 +	}
++
++	hwif_prop.hwif = hwif;
++	hwif_prop.index = hwif->index;
  
--	if (drive->hwif->host_flags & IDE_HFLAG_NO_SET_MODE)
-+	if (hwif->host_flags & IDE_HFLAG_NO_SET_MODE)
- 		return 0;
+ 	idx[0] = hwif->index;
  
- 	if (ide_set_dma_mode(drive, speed))
-@@ -824,25 +803,23 @@ err_out:
+diff --git a/drivers/ide/legacy/macide.c b/drivers/ide/legacy/macide.c
+index 5c6aa77..782d4c7 100644
+--- a/drivers/ide/legacy/macide.c
++++ b/drivers/ide/legacy/macide.c
+@@ -77,15 +77,17 @@ int macide_ack_intr(ide_hwif_t* hwif)
+ 	return 0;
+ }
  
- int ide_set_dma(ide_drive_t *drive)
++static const char *mac_ide_name[] =
++	{ "Quadra", "Powerbook", "Powerbook Baboon" };
++
+ /*
+  * Probe for a Macintosh IDE interface
+  */
+ 
+-void __init macide_init(void)
++static int __init macide_init(void)
  {
--	ide_hwif_t *hwif = drive->hwif;
- 	int rc;
+ 	hw_regs_t hw;
+ 	ide_hwif_t *hwif;
+-	int index = -1;
  
-+	/*
-+	 * Force DMAing for the beginning of the check.
-+	 * Some chipsets appear to do interesting
-+	 * things, if not checked and cleared.
-+	 *   PARANOIA!!!
-+	 */
-+	ide_dma_off_quietly(drive);
+ 	switch (macintosh_config->ide_type) {
+ 	case MAC_IDE_QUADRA:
+@@ -93,48 +95,50 @@ void __init macide_init(void)
+ 				0, 0, macide_ack_intr,
+ //				quadra_ide_iops,
+ 				IRQ_NUBUS_F);
+-		index = ide_register_hw(&hw, NULL, 1, &hwif);
+ 		break;
+ 	case MAC_IDE_PB:
+ 		ide_setup_ports(&hw, IDE_BASE, macide_offsets,
+ 				0, 0, macide_ack_intr,
+ //				macide_pb_iops,
+ 				IRQ_NUBUS_C);
+-		index = ide_register_hw(&hw, NULL, 1, &hwif);
+ 		break;
+ 	case MAC_IDE_BABOON:
+ 		ide_setup_ports(&hw, BABOON_BASE, macide_offsets,
+ 				0, 0, NULL,
+ //				macide_baboon_iops,
+ 				IRQ_BABOON_1);
+-		index = ide_register_hw(&hw, NULL, 1, &hwif);
+-		if (index == -1) break;
+-		if (macintosh_config->ident == MAC_MODEL_PB190) {
++		break;
++	default:
++		return -ENODEV;
++	}
 +
- 	rc = ide_dma_check(drive);
-+	if (rc)
-+		return rc;
++	printk(KERN_INFO "ide: Macintosh %s IDE controller\n",
++			 mac_ide_name[macintosh_config->ide_type - 1]);
  
--	switch(rc) {
--	case -1: /* DMA needs to be disabled */
--		hwif->dma_off_quietly(drive);
--		return -1;
--	case  0: /* DMA needs to be enabled */
--		return hwif->ide_dma_on(drive);
--	case  1: /* DMA setting cannot be changed */
++	hwif = ide_find_port(hw.io_ports[IDE_DATA_OFFSET]);
++	if (hwif) {
++		u8 index = hwif->index;
++		u8 idx[4] = { index, 0xff, 0xff, 0xff };
++
++		ide_init_port_data(hwif, index);
++		ide_init_port_hw(hwif, &hw);
++
++		if (macintosh_config->ide_type == MAC_IDE_BABOON &&
++		    macintosh_config->ident == MAC_MODEL_PB190) {
+ 			/* Fix breakage in ide-disk.c: drive capacity	*/
+ 			/* is not initialized for drives without a 	*/
+ 			/* hardware ID, and we can't get that without	*/
+ 			/* probing the drive which freezes a 190.	*/
+-
+-			ide_drive_t *drive = &ide_hwifs[index].drives[0];
++			ide_drive_t *drive = &hwif->drives[0];
+ 			drive->capacity64 = drive->cyl*drive->head*drive->sect;
+-
+ 		}
 -		break;
+-
 -	default:
--		BUG();
--		break;
+-	    return;
 -	}
-+	ide_dma_on(drive);
  
--	return rc;
+-        if (index != -1) {
+ 		hwif->mmio = 1;
+-		if (macintosh_config->ide_type == MAC_IDE_QUADRA)
+-			printk(KERN_INFO "ide%d: Macintosh Quadra IDE interface\n", index);
+-		else if (macintosh_config->ide_type == MAC_IDE_PB)
+-			printk(KERN_INFO "ide%d: Macintosh Powerbook IDE interface\n", index);
+-		else if (macintosh_config->ide_type == MAC_IDE_BABOON)
+-			printk(KERN_INFO "ide%d: Macintosh Powerbook Baboon IDE interface\n", index);
+-		else
+-			printk(KERN_INFO "ide%d: Unknown Macintosh IDE interface\n", index);
++
++		ide_device_add(idx);
+ 	}
++
 +	return 0;
  }
++
++module_init(macide_init);
+diff --git a/drivers/ide/legacy/q40ide.c b/drivers/ide/legacy/q40ide.c
+index 6ea46a6..f532973 100644
+--- a/drivers/ide/legacy/q40ide.c
++++ b/drivers/ide/legacy/q40ide.c
+@@ -111,15 +111,17 @@ static const char *q40_ide_names[Q40IDE_NUM_HWIFS]={
+  *  Probe for Q40 IDE interfaces
+  */
  
- #ifdef CONFIG_BLK_DEV_IDEDMA_PCI
-@@ -968,11 +945,6 @@ void ide_setup_dma(ide_hwif_t *hwif, unsigned long base, unsigned num_ports)
- 
- 	hwif->dma_base = base;
+-void __init q40ide_init(void)
++static int __init q40ide_init(void)
+ {
+     int i;
+     ide_hwif_t *hwif;
+-    int index;
+     const char *name;
++    u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
  
--	if (hwif->mate)
--		hwif->dma_master = hwif->channel ? hwif->mate->dma_base : base;
--	else
--		hwif->dma_master = base;
--
- 	if (!(hwif->dma_command))
- 		hwif->dma_command	= hwif->dma_base;
- 	if (!(hwif->dma_vendor1))
-@@ -984,14 +956,8 @@ void ide_setup_dma(ide_hwif_t *hwif, unsigned long base, unsigned num_ports)
- 	if (!(hwif->dma_prdtable))
- 		hwif->dma_prdtable	= (hwif->dma_base + 4);
+     if (!MACH_IS_Q40)
+-      return ;
++      return -ENODEV;
++
++    printk(KERN_INFO "ide: Q40 IDE controller\n");
  
--	if (!hwif->dma_off_quietly)
--		hwif->dma_off_quietly = &ide_dma_off_quietly;
--	if (!hwif->dma_host_off)
--		hwif->dma_host_off = &ide_dma_host_off;
--	if (!hwif->ide_dma_on)
--		hwif->ide_dma_on = &__ide_dma_on;
--	if (!hwif->dma_host_on)
--		hwif->dma_host_on = &ide_dma_host_on;
-+	if (!hwif->dma_host_set)
-+		hwif->dma_host_set = &ide_dma_host_set;
- 	if (!hwif->dma_setup)
- 		hwif->dma_setup = &ide_dma_setup;
- 	if (!hwif->dma_exec_cmd)
-@@ -1014,8 +980,6 @@ void ide_setup_dma(ide_hwif_t *hwif, unsigned long base, unsigned num_ports)
- 		       hwif->drives[1].name, (dma_stat & 0x40) ? "DMA" : "pio");
- 	}
- 	printk("\n");
--
--	BUG_ON(!hwif->dma_master);
+     for (i = 0; i < Q40IDE_NUM_HWIFS; i++) {
+ 	hw_regs_t hw;
+@@ -141,10 +143,20 @@ void __init q40ide_init(void)
+ 			0, NULL,
+ //			m68kide_iops,
+ 			q40ide_default_irq(pcide_bases[i]));
+-	index = ide_register_hw(&hw, NULL, 1, &hwif);
+-	// **FIXME**
+-	if (index != -1)
++
++	hwif = ide_find_port(hw.io_ports[IDE_DATA_OFFSET]);
++	if (hwif) {
++		ide_init_port_data(hwif, hwif->index);
++		ide_init_port_hw(hwif, &hw);
+ 		hwif->mmio = 1;
++
++		idx[i] = hwif->index;
++	}
+     }
++
++    ide_device_add(idx);
++
++    return 0;
  }
  
- EXPORT_SYMBOL_GPL(ide_setup_dma);
-diff --git a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c
-index 04a3578..ff8232e 100644
---- a/drivers/ide/ide-floppy.c
-+++ b/drivers/ide/ide-floppy.c
-@@ -369,27 +369,6 @@ typedef struct ide_floppy_obj {
- #define	IDEFLOPPY_IOCTL_FORMAT_START		0x4602
- #define IDEFLOPPY_IOCTL_FORMAT_GET_PROGRESS	0x4603
- 
--#if 0
--/*
-- *	Special requests for our block device strategy routine.
-- */
--#define	IDEFLOPPY_FIRST_RQ	90
--
--/*
-- * 	IDEFLOPPY_PC_RQ is used to queue a packet command in the request queue.
-- */
--#define	IDEFLOPPY_PC_RQ		90
--
--#define IDEFLOPPY_LAST_RQ	90
--
--/*
-- *	A macro which can be used to check if a given request command
-- *	originated in the driver or in the buffer cache layer.
-- */
--#define IDEFLOPPY_RQ_CMD(cmd) 	((cmd >= IDEFLOPPY_FIRST_RQ) && (cmd <= IDEFLOPPY_LAST_RQ))
--
--#endif
--
- /*
-  *	Error codes which are returned in rq->errors to the higher part
-  *	of the driver.
-@@ -793,9 +772,8 @@ static void idefloppy_retry_pc (ide_drive_t *drive)
- {
- 	idefloppy_pc_t *pc;
- 	struct request *rq;
--	atapi_error_t error;
++module_init(q40ide_init);
+diff --git a/drivers/ide/legacy/qd65xx.c b/drivers/ide/legacy/qd65xx.c
+index 912e738..2bac4c1 100644
+--- a/drivers/ide/legacy/qd65xx.c
++++ b/drivers/ide/legacy/qd65xx.c
+@@ -478,8 +478,7 @@ int probe_qd65xx = 0;
+ module_param_named(probe, probe_qd65xx, bool, 0);
+ MODULE_PARM_DESC(probe, "probe for QD65xx chipsets");
  
--	error.all = HWIF(drive)->INB(IDE_ERROR_REG);
-+	(void)drive->hwif->INB(IDE_ERROR_REG);
- 	pc = idefloppy_next_pc_storage(drive);
- 	rq = idefloppy_next_rq_storage(drive);
- 	idefloppy_create_request_sense_cmd(pc);
-@@ -809,12 +787,12 @@ static void idefloppy_retry_pc (ide_drive_t *drive)
- static ide_startstop_t idefloppy_pc_intr (ide_drive_t *drive)
+-/* Can be called directly from ide.c. */
+-int __init qd65xx_init(void)
++static int __init qd65xx_init(void)
  {
- 	idefloppy_floppy_t *floppy = drive->driver_data;
--	atapi_status_t status;
--	atapi_bcount_t bcount;
--	atapi_ireason_t ireason;
-+	ide_hwif_t *hwif = drive->hwif;
- 	idefloppy_pc_t *pc = floppy->pc;
- 	struct request *rq = pc->rq;
- 	unsigned int temp;
-+	u16 bcount;
-+	u8 stat, ireason;
- 
- 	debug_log(KERN_INFO "ide-floppy: Reached %s interrupt handler\n",
- 		__FUNCTION__);
-@@ -830,16 +808,16 @@ static ide_startstop_t idefloppy_pc_intr (ide_drive_t *drive)
- 	}
+ 	if (probe_qd65xx == 0)
+ 		return -ENODEV;
+@@ -492,9 +491,7 @@ int __init qd65xx_init(void)
+ 	return 0;
+ }
  
- 	/* Clear the interrupt */
--	status.all = HWIF(drive)->INB(IDE_STATUS_REG);
-+	stat = drive->hwif->INB(IDE_STATUS_REG);
+-#ifdef MODULE
+ module_init(qd65xx_init);
+-#endif
  
--	if (!status.b.drq) {			/* No more interrupts */
-+	if ((stat & DRQ_STAT) == 0) {		/* No more interrupts */
- 		debug_log(KERN_INFO "Packet command completed, %d bytes "
- 			"transferred\n", pc->actually_transferred);
- 		clear_bit(PC_DMA_IN_PROGRESS, &pc->flags);
+ MODULE_AUTHOR("Samuel Thibault");
+ MODULE_DESCRIPTION("support of qd65xx vlb ide chipset");
+diff --git a/drivers/ide/legacy/umc8672.c b/drivers/ide/legacy/umc8672.c
+index 79577b9..a1ae1ae 100644
+--- a/drivers/ide/legacy/umc8672.c
++++ b/drivers/ide/legacy/umc8672.c
+@@ -169,8 +169,7 @@ int probe_umc8672 = 0;
+ module_param_named(probe, probe_umc8672, bool, 0);
+ MODULE_PARM_DESC(probe, "probe for UMC8672 chipset");
  
- 		local_irq_enable_in_hardirq();
+-/* Can be called directly from ide.c. */
+-int __init umc8672_init(void)
++static int __init umc8672_init(void)
+ {
+ 	if (probe_umc8672 == 0)
+ 		goto out;
+@@ -181,9 +180,7 @@ out:
+ 	return -ENODEV;;
+ }
  
--		if (status.b.check || test_bit(PC_DMA_ERROR, &pc->flags)) {
-+		if ((stat & ERR_STAT) || test_bit(PC_DMA_ERROR, &pc->flags)) {
- 			/* Error detected */
- 			debug_log(KERN_INFO "ide-floppy: %s: I/O error\n",
- 				drive->name);
-@@ -870,32 +848,32 @@ static ide_startstop_t idefloppy_pc_intr (ide_drive_t *drive)
- 	}
+-#ifdef MODULE
+ module_init(umc8672_init);
+-#endif
  
- 	/* Get the number of bytes to transfer */
--	bcount.b.high = HWIF(drive)->INB(IDE_BCOUNTH_REG);
--	bcount.b.low = HWIF(drive)->INB(IDE_BCOUNTL_REG);
-+	bcount = (hwif->INB(IDE_BCOUNTH_REG) << 8) |
-+		  hwif->INB(IDE_BCOUNTL_REG);
- 	/* on this interrupt */
--	ireason.all = HWIF(drive)->INB(IDE_IREASON_REG);
-+	ireason = hwif->INB(IDE_IREASON_REG);
+ MODULE_AUTHOR("Wolfram Podien");
+ MODULE_DESCRIPTION("Support for UMC 8672 IDE chipset");
+diff --git a/drivers/ide/mips/au1xxx-ide.c b/drivers/ide/mips/au1xxx-ide.c
+index a4ce3ba..2d3e511 100644
+--- a/drivers/ide/mips/au1xxx-ide.c
++++ b/drivers/ide/mips/au1xxx-ide.c
+@@ -198,8 +198,6 @@ static void auide_set_dma_mode(ide_drive_t *drive, const u8 speed)
  
--	if (ireason.b.cod) {
-+	if (ireason & CD) {
- 		printk(KERN_ERR "ide-floppy: CoD != 0 in idefloppy_pc_intr\n");
- 		return ide_do_reset(drive);
- 	}
--	if (ireason.b.io == test_bit(PC_WRITING, &pc->flags)) {
-+	if (((ireason & IO) == IO) == test_bit(PC_WRITING, &pc->flags)) {
- 		/* Hopefully, we will never get here */
- 		printk(KERN_ERR "ide-floppy: We wanted to %s, ",
--			ireason.b.io ? "Write":"Read");
-+				(ireason & IO) ? "Write" : "Read");
- 		printk(KERN_ERR "but the floppy wants us to %s !\n",
--			ireason.b.io ? "Read":"Write");
-+				(ireason & IO) ? "Read" : "Write");
- 		return ide_do_reset(drive);
- 	}
- 	if (!test_bit(PC_WRITING, &pc->flags)) {
- 		/* Reading - Check that we have enough space */
--		temp = pc->actually_transferred + bcount.all;
-+		temp = pc->actually_transferred + bcount;
- 		if (temp > pc->request_transfer) {
- 			if (temp > pc->buffer_size) {
- 				printk(KERN_ERR "ide-floppy: The floppy wants "
- 					"to send us more data than expected "
- 					"- discarding data\n");
--				idefloppy_discard_data(drive,bcount.all);
-+				idefloppy_discard_data(drive, bcount);
- 				BUG_ON(HWGROUP(drive)->handler != NULL);
- 				ide_set_handler(drive,
- 						&idefloppy_pc_intr,
-@@ -911,23 +889,21 @@ static ide_startstop_t idefloppy_pc_intr (ide_drive_t *drive)
- 	if (test_bit(PC_WRITING, &pc->flags)) {
- 		if (pc->buffer != NULL)
- 			/* Write the current buffer */
--			HWIF(drive)->atapi_output_bytes(drive,
--						pc->current_position,
--						bcount.all);
-+			hwif->atapi_output_bytes(drive, pc->current_position,
-+						 bcount);
- 		else
--			idefloppy_output_buffers(drive, pc, bcount.all);
-+			idefloppy_output_buffers(drive, pc, bcount);
- 	} else {
- 		if (pc->buffer != NULL)
- 			/* Read the current buffer */
--			HWIF(drive)->atapi_input_bytes(drive,
--						pc->current_position,
--						bcount.all);
-+			hwif->atapi_input_bytes(drive, pc->current_position,
-+						bcount);
- 		else
--			idefloppy_input_buffers(drive, pc, bcount.all);
-+			idefloppy_input_buffers(drive, pc, bcount);
+ 		break;
+ #endif
+-	default:
+-		return;
  	}
- 	/* Update the current position */
--	pc->actually_transferred += bcount.all;
--	pc->current_position += bcount.all;
-+	pc->actually_transferred += bcount;
-+	pc->current_position += bcount;
  
- 	BUG_ON(HWGROUP(drive)->handler != NULL);
- 	ide_set_handler(drive, &idefloppy_pc_intr, IDEFLOPPY_WAIT_CMD, NULL);		/* And set the interrupt handler again */
-@@ -943,15 +919,15 @@ static ide_startstop_t idefloppy_transfer_pc (ide_drive_t *drive)
- {
- 	ide_startstop_t startstop;
- 	idefloppy_floppy_t *floppy = drive->driver_data;
--	atapi_ireason_t ireason;
-+	u8 ireason;
+ 	au_writel(mem_sttime,MEM_STTIME2);
+@@ -397,26 +395,10 @@ static int auide_dma_test_irq(ide_drive_t *drive)
+ 	return 0;
+ }
  
- 	if (ide_wait_stat(&startstop, drive, DRQ_STAT, BUSY_STAT, WAIT_READY)) {
- 		printk(KERN_ERR "ide-floppy: Strange, packet command "
- 				"initiated yet DRQ isn't asserted\n");
- 		return startstop;
- 	}
--	ireason.all = HWIF(drive)->INB(IDE_IREASON_REG);
--	if (!ireason.b.cod || ireason.b.io) {
-+	ireason = drive->hwif->INB(IDE_IREASON_REG);
-+	if ((ireason & CD) == 0 || (ireason & IO)) {
- 		printk(KERN_ERR "ide-floppy: (IO,CoD) != (0,1) while "
- 				"issuing a packet command\n");
- 		return ide_do_reset(drive);
-@@ -991,15 +967,15 @@ static ide_startstop_t idefloppy_transfer_pc1 (ide_drive_t *drive)
+-static void auide_dma_host_on(ide_drive_t *drive)
+-{
+-}
+-
+-static int auide_dma_on(ide_drive_t *drive)
+-{
+-	drive->using_dma = 1;
+-
+-	return 0;
+-}
+-
+-static void auide_dma_host_off(ide_drive_t *drive)
++static void auide_dma_host_set(ide_drive_t *drive, int on)
  {
- 	idefloppy_floppy_t *floppy = drive->driver_data;
- 	ide_startstop_t startstop;
--	atapi_ireason_t ireason;
-+	u8 ireason;
+ }
  
- 	if (ide_wait_stat(&startstop, drive, DRQ_STAT, BUSY_STAT, WAIT_READY)) {
- 		printk(KERN_ERR "ide-floppy: Strange, packet command "
- 				"initiated yet DRQ isn't asserted\n");
- 		return startstop;
- 	}
--	ireason.all = HWIF(drive)->INB(IDE_IREASON_REG);
--	if (!ireason.b.cod || ireason.b.io) {
-+	ireason = drive->hwif->INB(IDE_IREASON_REG);
-+	if ((ireason & CD) == 0 || (ireason & IO)) {
- 		printk(KERN_ERR "ide-floppy: (IO,CoD) != (0,1) "
- 				"while issuing a packet command\n");
- 		return ide_do_reset(drive);
-@@ -1041,21 +1017,9 @@ static ide_startstop_t idefloppy_issue_pc (ide_drive_t *drive, idefloppy_pc_t *p
- {
- 	idefloppy_floppy_t *floppy = drive->driver_data;
- 	ide_hwif_t *hwif = drive->hwif;
--	atapi_feature_t feature;
--	atapi_bcount_t bcount;
- 	ide_handler_t *pkt_xfer_routine;
+-static void auide_dma_off_quietly(ide_drive_t *drive)
+-{
+-	drive->using_dma = 0;
+-}
 -
--#if 0 /* Accessing floppy->pc is not valid here, the previous pc may be gone
--         and have lived on another thread's stack; that stack may have become
--         unmapped meanwhile (CONFIG_DEBUG_PAGEALLOC). */
--#if IDEFLOPPY_DEBUG_BUGS
--	if (floppy->pc->c[0] == IDEFLOPPY_REQUEST_SENSE_CMD &&
--	    pc->c[0] == IDEFLOPPY_REQUEST_SENSE_CMD) {
--		printk(KERN_ERR "ide-floppy: possible ide-floppy.c bug - "
--			"Two request sense in serial were issued\n");
--	}
--#endif /* IDEFLOPPY_DEBUG_BUGS */
--#endif
-+	u16 bcount;
-+	u8 dma;
- 
- 	if (floppy->failed_pc == NULL &&
- 	    pc->c[0] != IDEFLOPPY_REQUEST_SENSE_CMD)
-@@ -1093,25 +1057,20 @@ static ide_startstop_t idefloppy_issue_pc (ide_drive_t *drive, idefloppy_pc_t *p
- 	/* We haven't transferred any data yet */
- 	pc->actually_transferred = 0;
- 	pc->current_position = pc->buffer;
--	bcount.all = min(pc->request_transfer, 63 * 1024);
-+	bcount = min(pc->request_transfer, 63 * 1024);
+ static void auide_dma_lost_irq(ide_drive_t *drive)
+ {
+ 	printk(KERN_ERR "%s: IRQ lost\n", drive->name);
+@@ -643,12 +625,13 @@ static int au_ide_probe(struct device *dev)
+ 	/* FIXME:  This might possibly break PCMCIA IDE devices */
  
- 	if (test_and_clear_bit(PC_DMA_ERROR, &pc->flags))
- 		ide_dma_off(drive);
+ 	hwif                            = &ide_hwifs[pdev->id];
+-	hwif->irq			= ahwif->irq;
+-	hwif->chipset                   = ide_au1xxx;
  
--	feature.all = 0;
-+	dma = 0;
+ 	memset(&hw, 0, sizeof(hw));
+ 	auide_setup_ports(&hw, ahwif);
+-	memcpy(hwif->io_ports, hw.io_ports, sizeof(hwif->io_ports));
++	hw.irq = ahwif->irq;
++	hw.chipset = ide_au1xxx;
++
++	ide_init_port_hw(hwif, &hw);
  
- 	if (test_bit(PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma)
--		feature.b.dma = !hwif->dma_setup(drive);
-+		dma = !hwif->dma_setup(drive);
+ 	hwif->ultra_mask                = 0x0;  /* Disable Ultra DMA */
+ #ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA
+@@ -662,7 +645,6 @@ static int au_ide_probe(struct device *dev)
+ 	hwif->pio_mask = ATA_PIO4;
+ 	hwif->host_flags = IDE_HFLAG_POST_SET_MODE;
  
--	if (IDE_CONTROL_REG)
--		HWIF(drive)->OUTB(drive->ctl, IDE_CONTROL_REG);
--	/* Use PIO/DMA */
--	HWIF(drive)->OUTB(feature.all, IDE_FEATURE_REG);
--	HWIF(drive)->OUTB(bcount.b.high, IDE_BCOUNTH_REG);
--	HWIF(drive)->OUTB(bcount.b.low, IDE_BCOUNTL_REG);
--	HWIF(drive)->OUTB(drive->select.all, IDE_SELECT_REG);
-+	ide_pktcmd_tf_load(drive, IDE_TFLAG_NO_SELECT_MASK |
-+			   IDE_TFLAG_OUT_DEVICE, bcount, dma);
+-	hwif->noprobe = 0;
+ 	hwif->drives[0].unmask          = 1;
+ 	hwif->drives[1].unmask          = 1;
  
--	if (feature.b.dma) {	/* Begin DMA, if necessary */
-+	if (dma) {	/* Begin DMA, if necessary */
- 		set_bit(PC_DMA_IN_PROGRESS, &pc->flags);
- 		hwif->dma_start(drive);
- 	}
-@@ -1665,14 +1624,14 @@ static int idefloppy_get_format_progress(ide_drive_t *drive, int __user *arg)
- 		/* Else assume format_unit has finished, and we're
- 		** at 0x10000 */
- 	} else {
--		atapi_status_t status;
- 		unsigned long flags;
-+		u8 stat;
+@@ -684,29 +666,25 @@ static int au_ide_probe(struct device *dev)
+ 	hwif->set_dma_mode		= &auide_set_dma_mode;
  
- 		local_irq_save(flags);
--		status.all = HWIF(drive)->INB(IDE_STATUS_REG);
-+		stat = drive->hwif->INB(IDE_STATUS_REG);
- 		local_irq_restore(flags);
+ #ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA
+-	hwif->dma_off_quietly		= &auide_dma_off_quietly;
+ 	hwif->dma_timeout		= &auide_dma_timeout;
  
--		progress_indication = !status.b.dsc ? 0 : 0x10000;
-+		progress_indication = ((stat & SEEK_STAT) == 0) ? 0 : 0x10000;
- 	}
- 	if (put_user(progress_indication, arg))
- 		return (-EFAULT);
-diff --git a/drivers/ide/ide-generic.c b/drivers/ide/ide-generic.c
-index 0f72b98..bb30c29 100644
---- a/drivers/ide/ide-generic.c
-+++ b/drivers/ide/ide-generic.c
-@@ -14,10 +14,16 @@
+ 	hwif->mdma_filter		= &auide_mdma_filter;
  
- static int __init ide_generic_init(void)
- {
-+	u8 idx[MAX_HWIFS];
-+	int i;
-+
- 	if (ide_hwifs[0].io_ports[IDE_DATA_OFFSET])
- 		ide_get_lock(NULL, NULL); /* for atari only */
++	hwif->dma_host_set		= &auide_dma_host_set;
+ 	hwif->dma_exec_cmd              = &auide_dma_exec_cmd;
+ 	hwif->dma_start                 = &auide_dma_start;
+ 	hwif->ide_dma_end               = &auide_dma_end;
+ 	hwif->dma_setup                 = &auide_dma_setup;
+ 	hwif->ide_dma_test_irq          = &auide_dma_test_irq;
+-	hwif->dma_host_off		= &auide_dma_host_off;
+-	hwif->dma_host_on		= &auide_dma_host_on;
+ 	hwif->dma_lost_irq		= &auide_dma_lost_irq;
+-	hwif->ide_dma_on                = &auide_dma_on;
+-#else /* !CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA */
++#endif
+ 	hwif->channel                   = 0;
+-	hwif->hold                      = 1;
+ 	hwif->select_data               = 0;    /* no chipset-specific code */
+ 	hwif->config_data               = 0;    /* no chipset-specific code */
  
--	(void)ideprobe_init();
-+	for (i = 0; i < MAX_HWIFS; i++)
-+		idx[i] = ide_hwifs[i].present ? 0xff : i;
+ 	hwif->drives[0].autotune        = 1;    /* 1=autotune, 2=noautotune, 0=default */
+ 	hwif->drives[1].autotune	= 1;
+-#endif
 +
-+	ide_device_add_all(idx);
+ 	hwif->drives[0].no_io_32bit	= 1;
+ 	hwif->drives[1].no_io_32bit	= 1;
  
- 	if (ide_hwifs[0].io_ports[IDE_DATA_OFFSET])
- 		ide_release_lock();	/* for atari only */
-diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c
-index bef781f..6f8f544 100644
---- a/drivers/ide/ide-io.c
-+++ b/drivers/ide/ide-io.c
-@@ -75,7 +75,7 @@ static int __ide_end_request(ide_drive_t *drive, struct request *rq,
- 	 */
- 	if (drive->state == DMA_PIO_RETRY && drive->retry_pio <= 3) {
- 		drive->state = 0;
--		HWGROUP(drive)->hwif->ide_dma_on(drive);
-+		ide_dma_on(drive);
- 	}
+diff --git a/drivers/ide/mips/swarm.c b/drivers/ide/mips/swarm.c
+index 521edd4..8b3959d 100644
+--- a/drivers/ide/mips/swarm.c
++++ b/drivers/ide/mips/swarm.c
+@@ -117,6 +117,7 @@ static int __devinit swarm_ide_probe(struct device *dev)
+ 	default_hwif_mmiops(hwif);
+ 	/* Prevent resource map manipulation.  */
+ 	hwif->mmio = 1;
++	hwif->chipset = ide_generic;
+ 	hwif->noprobe = 0;
  
- 	if (!end_that_request_chunk(rq, uptodate, nr_bytes)) {
-@@ -189,18 +189,14 @@ static ide_startstop_t ide_start_power_step(ide_drive_t *drive, struct request *
- 			return ide_stopped;
- 		}
- 		if (ide_id_has_flush_cache_ext(drive->id))
--			args->tfRegister[IDE_COMMAND_OFFSET] = WIN_FLUSH_CACHE_EXT;
-+			args->tf.command = WIN_FLUSH_CACHE_EXT;
- 		else
--			args->tfRegister[IDE_COMMAND_OFFSET] = WIN_FLUSH_CACHE;
--		args->command_type = IDE_DRIVE_TASK_NO_DATA;
--		args->handler	   = &task_no_data_intr;
--		return do_rw_taskfile(drive, args);
-+			args->tf.command = WIN_FLUSH_CACHE;
-+		goto out_do_tf;
+ 	for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++)
+diff --git a/drivers/ide/pci/Makefile b/drivers/ide/pci/Makefile
+index 95d1ea8..9480325 100644
+--- a/drivers/ide/pci/Makefile
++++ b/drivers/ide/pci/Makefile
+@@ -36,4 +36,8 @@ obj-$(CONFIG_BLK_DEV_VIA82CXXX)		+= via82cxxx.o
+ # Must appear at the end of the block
+ obj-$(CONFIG_BLK_DEV_GENERIC)          += generic.o
  
- 	case idedisk_pm_standby:	/* Suspend step 2 (standby) */
--		args->tfRegister[IDE_COMMAND_OFFSET] = WIN_STANDBYNOW1;
--		args->command_type = IDE_DRIVE_TASK_NO_DATA;
--		args->handler	   = &task_no_data_intr;
--		return do_rw_taskfile(drive, args);
-+		args->tf.command = WIN_STANDBYNOW1;
-+		goto out_do_tf;
++ifeq ($(CONFIG_BLK_DEV_CMD640), m)
++	obj-m += cmd640.o
++endif
++
+ EXTRA_CFLAGS	:= -Idrivers/ide
+diff --git a/drivers/ide/pci/aec62xx.c b/drivers/ide/pci/aec62xx.c
+index 4426850..7f4d185 100644
+--- a/drivers/ide/pci/aec62xx.c
++++ b/drivers/ide/pci/aec62xx.c
+@@ -202,6 +202,7 @@ static const struct ide_port_info aec62xx_chipsets[] __devinitdata = {
+ 		.enablebits	= {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},
+ 		.host_flags	= IDE_HFLAG_SERIALIZE |
+ 				  IDE_HFLAG_NO_ATAPI_DMA |
++				  IDE_HFLAG_ABUSE_SET_DMA_MODE |
+ 				  IDE_HFLAG_OFF_BOARD,
+ 		.pio_mask	= ATA_PIO4,
+ 		.mwdma_mask	= ATA_MWDMA2,
+@@ -211,6 +212,7 @@ static const struct ide_port_info aec62xx_chipsets[] __devinitdata = {
+ 		.init_chipset	= init_chipset_aec62xx,
+ 		.init_hwif	= init_hwif_aec62xx,
+ 		.host_flags	= IDE_HFLAG_NO_ATAPI_DMA | IDE_HFLAG_NO_AUTODMA |
++				  IDE_HFLAG_ABUSE_SET_DMA_MODE |
+ 				  IDE_HFLAG_OFF_BOARD,
+ 		.pio_mask	= ATA_PIO4,
+ 		.mwdma_mask	= ATA_MWDMA2,
+@@ -220,7 +222,8 @@ static const struct ide_port_info aec62xx_chipsets[] __devinitdata = {
+ 		.init_chipset	= init_chipset_aec62xx,
+ 		.init_hwif	= init_hwif_aec62xx,
+ 		.enablebits	= {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},
+-		.host_flags	= IDE_HFLAG_NO_ATAPI_DMA,
++		.host_flags	= IDE_HFLAG_NO_ATAPI_DMA |
++				  IDE_HFLAG_ABUSE_SET_DMA_MODE,
+ 		.pio_mask	= ATA_PIO4,
+ 		.mwdma_mask	= ATA_MWDMA2,
+ 		.udma_mask	= ATA_UDMA4,
+@@ -228,7 +231,9 @@ static const struct ide_port_info aec62xx_chipsets[] __devinitdata = {
+ 		.name		= "AEC6280",
+ 		.init_chipset	= init_chipset_aec62xx,
+ 		.init_hwif	= init_hwif_aec62xx,
+-		.host_flags	= IDE_HFLAG_NO_ATAPI_DMA | IDE_HFLAG_OFF_BOARD,
++		.host_flags	= IDE_HFLAG_NO_ATAPI_DMA |
++				  IDE_HFLAG_ABUSE_SET_DMA_MODE |
++				  IDE_HFLAG_OFF_BOARD,
+ 		.pio_mask	= ATA_PIO4,
+ 		.mwdma_mask	= ATA_MWDMA2,
+ 		.udma_mask	= ATA_UDMA5,
+@@ -237,7 +242,9 @@ static const struct ide_port_info aec62xx_chipsets[] __devinitdata = {
+ 		.init_chipset	= init_chipset_aec62xx,
+ 		.init_hwif	= init_hwif_aec62xx,
+ 		.enablebits	= {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},
+-		.host_flags	= IDE_HFLAG_NO_ATAPI_DMA | IDE_HFLAG_OFF_BOARD,
++		.host_flags	= IDE_HFLAG_NO_ATAPI_DMA |
++				  IDE_HFLAG_ABUSE_SET_DMA_MODE |
++				  IDE_HFLAG_OFF_BOARD,
+ 		.pio_mask	= ATA_PIO4,
+ 		.mwdma_mask	= ATA_MWDMA2,
+ 		.udma_mask	= ATA_UDMA5,
+diff --git a/drivers/ide/pci/alim15x3.c b/drivers/ide/pci/alim15x3.c
+index ce29393..49aa82e 100644
+--- a/drivers/ide/pci/alim15x3.c
++++ b/drivers/ide/pci/alim15x3.c
+@@ -402,9 +402,6 @@ static void ali_set_dma_mode(ide_drive_t *drive, const u8 speed)
+ 	u8 tmpbyte		= 0x00;
+ 	int m5229_udma		= (hwif->channel) ? 0x57 : 0x56;
  
- 	case idedisk_pm_restore_pio:	/* Resume step 1 (restore PIO) */
- 		ide_set_max_pio(drive);
-@@ -214,10 +210,8 @@ static ide_startstop_t ide_start_power_step(ide_drive_t *drive, struct request *
- 		return ide_stopped;
+-	if (speed < XFER_PIO_0)
+-		return;
+-
+ 	if (speed == XFER_UDMA_6)
+ 		speed1 = 0x47;
  
- 	case idedisk_pm_idle:		/* Resume step 2 (idle) */
--		args->tfRegister[IDE_COMMAND_OFFSET] = WIN_IDLEIMMEDIATE;
--		args->command_type = IDE_DRIVE_TASK_NO_DATA;
--		args->handler = task_no_data_intr;
--		return do_rw_taskfile(drive, args);
-+		args->tf.command = WIN_IDLEIMMEDIATE;
-+		goto out_do_tf;
+diff --git a/drivers/ide/pci/amd74xx.c b/drivers/ide/pci/amd74xx.c
+index 8d4125e..cee51fd 100644
+--- a/drivers/ide/pci/amd74xx.c
++++ b/drivers/ide/pci/amd74xx.c
+@@ -266,6 +266,7 @@ static void __devinit init_hwif_amd74xx(ide_hwif_t *hwif)
+ #define IDE_HFLAGS_AMD \
+ 	(IDE_HFLAG_PIO_NO_BLACKLIST | \
+ 	 IDE_HFLAG_PIO_NO_DOWNGRADE | \
++	 IDE_HFLAG_ABUSE_SET_DMA_MODE | \
+ 	 IDE_HFLAG_POST_SET_MODE | \
+ 	 IDE_HFLAG_IO_32BIT | \
+ 	 IDE_HFLAG_UNMASK_IRQS | \
+diff --git a/drivers/ide/pci/atiixp.c b/drivers/ide/pci/atiixp.c
+index ef8e016..4918719 100644
+--- a/drivers/ide/pci/atiixp.c
++++ b/drivers/ide/pci/atiixp.c
+@@ -1,5 +1,5 @@
+ /*
+- *  linux/drivers/ide/pci/atiixp.c	Version 0.03	Aug 3 2007
++ *  linux/drivers/ide/pci/atiixp.c	Version 0.05	Nov 9 2007
+  *
+  *  Copyright (C) 2003 ATI Inc. <hyu at ati.com>
+  *  Copyright (C) 2004,2007 Bartlomiej Zolnierkiewicz
+@@ -43,47 +43,8 @@ static atiixp_ide_timing mdma_timing[] = {
+ 	{ 0x02, 0x00 },
+ };
  
- 	case ide_pm_restore_dma:	/* Resume step 3 (restore DMA) */
- 		/*
-@@ -225,9 +219,8 @@ static ide_startstop_t ide_start_power_step(ide_drive_t *drive, struct request *
- 		 * we could be smarter and check for current xfer_speed
- 		 * in struct drive etc...
- 		 */
--		if (drive->hwif->ide_dma_on == NULL)
-+		if (drive->hwif->dma_host_set == NULL)
- 			break;
--		drive->hwif->dma_off_quietly(drive);
- 		/*
- 		 * TODO: respect ->using_dma setting
- 		 */
-@@ -236,6 +229,11 @@ static ide_startstop_t ide_start_power_step(ide_drive_t *drive, struct request *
- 	}
- 	pm->pm_step = ide_pm_state_completed;
- 	return ide_stopped;
-+
-+out_do_tf:
-+	args->tf_flags	 = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
-+	args->data_phase = TASKFILE_NO_DATA;
-+	return do_rw_taskfile(drive, args);
- }
+-static int save_mdma_mode[4];
+-
+ static DEFINE_SPINLOCK(atiixp_lock);
  
+-static void atiixp_dma_host_on(ide_drive_t *drive)
+-{
+-	struct pci_dev *dev = drive->hwif->pci_dev;
+-	unsigned long flags;
+-	u16 tmp16;
+-
+-	spin_lock_irqsave(&atiixp_lock, flags);
+-
+-	pci_read_config_word(dev, ATIIXP_IDE_UDMA_CONTROL, &tmp16);
+-	if (save_mdma_mode[drive->dn])
+-		tmp16 &= ~(1 << drive->dn);
+-	else
+-		tmp16 |= (1 << drive->dn);
+-	pci_write_config_word(dev, ATIIXP_IDE_UDMA_CONTROL, tmp16);
+-
+-	spin_unlock_irqrestore(&atiixp_lock, flags);
+-
+-	ide_dma_host_on(drive);
+-}
+-
+-static void atiixp_dma_host_off(ide_drive_t *drive)
+-{
+-	struct pci_dev *dev = drive->hwif->pci_dev;
+-	unsigned long flags;
+-	u16 tmp16;
+-
+-	spin_lock_irqsave(&atiixp_lock, flags);
+-
+-	pci_read_config_word(dev, ATIIXP_IDE_UDMA_CONTROL, &tmp16);
+-	tmp16 &= ~(1 << drive->dn);
+-	pci_write_config_word(dev, ATIIXP_IDE_UDMA_CONTROL, tmp16);
+-
+-	spin_unlock_irqrestore(&atiixp_lock, flags);
+-
+-	ide_dma_host_off(drive);
+-}
+-
  /**
-@@ -298,6 +296,48 @@ static void ide_complete_pm_request (ide_drive_t *drive, struct request *rq)
- 	spin_unlock_irqrestore(&ide_lock, flags);
- }
+  *	atiixp_set_pio_mode	-	set host controller for PIO mode
+  *	@drive: drive
+@@ -132,29 +93,33 @@ static void atiixp_set_dma_mode(ide_drive_t *drive, const u8 speed)
+ 	int timing_shift = (drive->dn & 2) ? 16 : 0 + (drive->dn & 1) ? 0 : 8;
+ 	u32 tmp32;
+ 	u16 tmp16;
+-
+-	if (speed < XFER_MW_DMA_0)
+-		return;
++	u16 udma_ctl = 0;
  
-+void ide_tf_read(ide_drive_t *drive, ide_task_t *task)
-+{
-+	ide_hwif_t *hwif = drive->hwif;
-+	struct ide_taskfile *tf = &task->tf;
-+
-+	if (task->tf_flags & IDE_TFLAG_IN_DATA) {
-+		u16 data = hwif->INW(IDE_DATA_REG);
-+
-+		tf->data = data & 0xff;
-+		tf->hob_data = (data >> 8) & 0xff;
-+	}
-+
-+	/* be sure we're looking at the low order bits */
-+	hwif->OUTB(drive->ctl & ~0x80, IDE_CONTROL_REG);
+ 	spin_lock_irqsave(&atiixp_lock, flags);
+ 
+-	save_mdma_mode[drive->dn] = 0;
++	pci_read_config_word(dev, ATIIXP_IDE_UDMA_CONTROL, &udma_ctl);
 +
-+	if (task->tf_flags & IDE_TFLAG_IN_NSECT)
-+		tf->nsect  = hwif->INB(IDE_NSECTOR_REG);
-+	if (task->tf_flags & IDE_TFLAG_IN_LBAL)
-+		tf->lbal   = hwif->INB(IDE_SECTOR_REG);
-+	if (task->tf_flags & IDE_TFLAG_IN_LBAM)
-+		tf->lbam   = hwif->INB(IDE_LCYL_REG);
-+	if (task->tf_flags & IDE_TFLAG_IN_LBAH)
-+		tf->lbah   = hwif->INB(IDE_HCYL_REG);
-+	if (task->tf_flags & IDE_TFLAG_IN_DEVICE)
-+		tf->device = hwif->INB(IDE_SELECT_REG);
+ 	if (speed >= XFER_UDMA_0) {
+ 		pci_read_config_word(dev, ATIIXP_IDE_UDMA_MODE, &tmp16);
+ 		tmp16 &= ~(0x07 << (drive->dn * 4));
+ 		tmp16 |= ((speed & 0x07) << (drive->dn * 4));
+ 		pci_write_config_word(dev, ATIIXP_IDE_UDMA_MODE, tmp16);
+-	} else {
+-		if ((speed >= XFER_MW_DMA_0) && (speed <= XFER_MW_DMA_2)) {
+-			save_mdma_mode[drive->dn] = speed;
+-			pci_read_config_dword(dev, ATIIXP_IDE_MDMA_TIMING, &tmp32);
+-			tmp32 &= ~(0xff << timing_shift);
+-			tmp32 |= (mdma_timing[speed & 0x03].recover_width << timing_shift) |
+-				(mdma_timing[speed & 0x03].command_width << (timing_shift + 4));
+-			pci_write_config_dword(dev, ATIIXP_IDE_MDMA_TIMING, tmp32);
+-		}
 +
-+	if (task->tf_flags & IDE_TFLAG_LBA48) {
-+		hwif->OUTB(drive->ctl | 0x80, IDE_CONTROL_REG);
++		udma_ctl |= (1 << drive->dn);
++	} else if (speed >= XFER_MW_DMA_0) {
++		u8 i = speed & 0x03;
 +
-+		if (task->tf_flags & IDE_TFLAG_IN_HOB_FEATURE)
-+			tf->hob_feature = hwif->INB(IDE_FEATURE_REG);
-+		if (task->tf_flags & IDE_TFLAG_IN_HOB_NSECT)
-+			tf->hob_nsect   = hwif->INB(IDE_NSECTOR_REG);
-+		if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAL)
-+			tf->hob_lbal    = hwif->INB(IDE_SECTOR_REG);
-+		if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAM)
-+			tf->hob_lbam    = hwif->INB(IDE_LCYL_REG);
-+		if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAH)
-+			tf->hob_lbah    = hwif->INB(IDE_HCYL_REG);
-+	}
-+}
++		pci_read_config_dword(dev, ATIIXP_IDE_MDMA_TIMING, &tmp32);
++		tmp32 &= ~(0xff << timing_shift);
++		tmp32 |= (mdma_timing[i].recover_width << timing_shift) |
++			 (mdma_timing[i].command_width << (timing_shift + 4));
++		pci_write_config_dword(dev, ATIIXP_IDE_MDMA_TIMING, tmp32);
 +
- /**
-  *	ide_end_drive_cmd	-	end an explicit drive command
-  *	@drive: command 
-@@ -314,7 +354,6 @@ static void ide_complete_pm_request (ide_drive_t *drive, struct request *rq)
-  
- void ide_end_drive_cmd (ide_drive_t *drive, u8 stat, u8 err)
- {
--	ide_hwif_t *hwif = HWIF(drive);
- 	unsigned long flags;
- 	struct request *rq;
++		udma_ctl &= ~(1 << drive->dn);
+ 	}
  
-@@ -322,61 +361,18 @@ void ide_end_drive_cmd (ide_drive_t *drive, u8 stat, u8 err)
- 	rq = HWGROUP(drive)->rq;
- 	spin_unlock_irqrestore(&ide_lock, flags);
++	pci_write_config_word(dev, ATIIXP_IDE_UDMA_CONTROL, udma_ctl);
++
+ 	spin_unlock_irqrestore(&atiixp_lock, flags);
+ }
  
--	if (rq->cmd_type == REQ_TYPE_ATA_CMD) {
--		u8 *args = (u8 *) rq->buffer;
--		if (rq->errors == 0)
--			rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT);
--
--		if (args) {
--			args[0] = stat;
--			args[1] = err;
--			args[2] = hwif->INB(IDE_NSECTOR_REG);
--		}
--	} else if (rq->cmd_type == REQ_TYPE_ATA_TASK) {
--		u8 *args = (u8 *) rq->buffer;
--		if (rq->errors == 0)
--			rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT);
--
--		if (args) {
--			args[0] = stat;
--			args[1] = err;
--			/* be sure we're looking at the low order bits */
--			hwif->OUTB(drive->ctl & ~0x80, IDE_CONTROL_REG);
--			args[2] = hwif->INB(IDE_NSECTOR_REG);
--			args[3] = hwif->INB(IDE_SECTOR_REG);
--			args[4] = hwif->INB(IDE_LCYL_REG);
--			args[5] = hwif->INB(IDE_HCYL_REG);
--			args[6] = hwif->INB(IDE_SELECT_REG);
--		}
--	} else if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) {
-+	if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) {
- 		ide_task_t *args = (ide_task_t *) rq->special;
- 		if (rq->errors == 0)
- 			rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT);
- 			
- 		if (args) {
--			if (args->tf_in_flags.b.data) {
--				u16 data				= hwif->INW(IDE_DATA_REG);
--				args->tfRegister[IDE_DATA_OFFSET]	= (data) & 0xFF;
--				args->hobRegister[IDE_DATA_OFFSET]	= (data >> 8) & 0xFF;
--			}
--			args->tfRegister[IDE_ERROR_OFFSET]   = err;
--			/* be sure we're looking at the low order bits */
--			hwif->OUTB(drive->ctl & ~0x80, IDE_CONTROL_REG);
--			args->tfRegister[IDE_NSECTOR_OFFSET] = hwif->INB(IDE_NSECTOR_REG);
--			args->tfRegister[IDE_SECTOR_OFFSET]  = hwif->INB(IDE_SECTOR_REG);
--			args->tfRegister[IDE_LCYL_OFFSET]    = hwif->INB(IDE_LCYL_REG);
--			args->tfRegister[IDE_HCYL_OFFSET]    = hwif->INB(IDE_HCYL_REG);
--			args->tfRegister[IDE_SELECT_OFFSET]  = hwif->INB(IDE_SELECT_REG);
--			args->tfRegister[IDE_STATUS_OFFSET]  = stat;
+@@ -184,9 +149,6 @@ static void __devinit init_hwif_atiixp(ide_hwif_t *hwif)
+ 		hwif->cbl = ATA_CBL_PATA80;
+ 	else
+ 		hwif->cbl = ATA_CBL_PATA40;
 -
--			if (drive->addressing == 1) {
--				hwif->OUTB(drive->ctl|0x80, IDE_CONTROL_REG);
--				args->hobRegister[IDE_FEATURE_OFFSET]	= hwif->INB(IDE_FEATURE_REG);
--				args->hobRegister[IDE_NSECTOR_OFFSET]	= hwif->INB(IDE_NSECTOR_REG);
--				args->hobRegister[IDE_SECTOR_OFFSET]	= hwif->INB(IDE_SECTOR_REG);
--				args->hobRegister[IDE_LCYL_OFFSET]	= hwif->INB(IDE_LCYL_REG);
--				args->hobRegister[IDE_HCYL_OFFSET]	= hwif->INB(IDE_HCYL_REG);
--			}
-+			struct ide_taskfile *tf = &args->tf;
+-	hwif->dma_host_on = &atiixp_dma_host_on;
+-	hwif->dma_host_off = &atiixp_dma_host_off;
+ }
+ 
+ static const struct ide_port_info atiixp_pci_info[] __devinitdata = {
+diff --git a/drivers/ide/pci/cmd640.c b/drivers/ide/pci/cmd640.c
+index 4aa4810..da3565e 100644
+--- a/drivers/ide/pci/cmd640.c
++++ b/drivers/ide/pci/cmd640.c
+@@ -706,9 +706,9 @@ static int pci_conf2(void)
+ }
+ 
+ /*
+- * Probe for a cmd640 chipset, and initialize it if found.  Called from ide.c
++ * Probe for a cmd640 chipset, and initialize it if found.
+  */
+-int __init ide_probe_for_cmd640x (void)
++static int __init cmd640x_init(void)
+ {
+ #ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
+ 	int second_port_toggled = 0;
+@@ -717,6 +717,7 @@ int __init ide_probe_for_cmd640x (void)
+ 	const char *bus_type, *port2;
+ 	unsigned int index;
+ 	u8 b, cfr;
++	u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
+ 
+ 	if (cmd640_vlb && probe_for_cmd640_vlb()) {
+ 		bus_type = "VLB";
+@@ -769,6 +770,8 @@ int __init ide_probe_for_cmd640x (void)
+ 	cmd_hwif0->set_pio_mode = &cmd640_set_pio_mode;
+ #endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
+ 
++	idx[0] = cmd_hwif0->index;
 +
-+			tf->error = err;
-+			tf->status = stat;
+ 	/*
+ 	 * Ensure compatibility by always using the slowest timings
+ 	 * for access to the drive's command register block,
+@@ -826,6 +829,8 @@ int __init ide_probe_for_cmd640x (void)
+ 		cmd_hwif1->pio_mask = ATA_PIO5;
+ 		cmd_hwif1->set_pio_mode = &cmd640_set_pio_mode;
+ #endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
 +
-+			ide_tf_read(drive, args);
- 		}
- 	} else if (blk_pm_request(rq)) {
- 		struct request_pm_state *pm = rq->data;
-@@ -615,90 +611,26 @@ ide_startstop_t ide_abort(ide_drive_t *drive, const char *msg)
- 		return __ide_abort(drive, rq);
++		idx[1] = cmd_hwif1->index;
+ 	}
+ 	printk(KERN_INFO "%s: %sserialized, secondary interface %s\n", cmd_hwif1->name,
+ 		cmd_hwif0->serialized ? "" : "not ", port2);
+@@ -872,6 +877,13 @@ int __init ide_probe_for_cmd640x (void)
+ #ifdef CMD640_DUMP_REGS
+ 	cmd640_dump_regs();
+ #endif
++
++	ide_device_add(idx);
++
+ 	return 1;
  }
  
--/**
-- *	ide_cmd		-	issue a simple drive command
-- *	@drive: drive the command is for
-- *	@cmd: command byte
-- *	@nsect: sector byte
-- *	@handler: handler for the command completion
-- *
-- *	Issue a simple drive command with interrupts.
-- *	The drive must be selected beforehand.
-- */
++module_param_named(probe_vlb, cmd640_vlb, bool, 0);
++MODULE_PARM_DESC(probe_vlb, "probe for VLB version of CMD640 chipset");
++
++module_init(cmd640x_init);
+diff --git a/drivers/ide/pci/cmd64x.c b/drivers/ide/pci/cmd64x.c
+index bc55333..cd4eb9d 100644
+--- a/drivers/ide/pci/cmd64x.c
++++ b/drivers/ide/pci/cmd64x.c
+@@ -1,5 +1,5 @@
+ /*
+- * linux/drivers/ide/pci/cmd64x.c		Version 1.52	Dec 24, 2007
++ * linux/drivers/ide/pci/cmd64x.c		Version 1.53	Dec 24, 2007
+  *
+  * cmd64x.c: Enable interrupts at initialization time on Ultra/PCI machines.
+  *           Due to massive hardware bugs, UltraDMA is only supported
+@@ -22,8 +22,6 @@
+ 
+ #include <asm/io.h>
+ 
+-#define DISPLAY_CMD64X_TIMINGS
 -
--static void ide_cmd (ide_drive_t *drive, u8 cmd, u8 nsect,
--		ide_handler_t *handler)
-+static void ide_tf_set_specify_cmd(ide_drive_t *drive, struct ide_taskfile *tf)
- {
--	ide_hwif_t *hwif = HWIF(drive);
--	if (IDE_CONTROL_REG)
--		hwif->OUTB(drive->ctl,IDE_CONTROL_REG);	/* clear nIEN */
--	SELECT_MASK(drive,0);
--	hwif->OUTB(nsect,IDE_NSECTOR_REG);
--	ide_execute_command(drive, cmd, handler, WAIT_CMD, NULL);
-+	tf->nsect   = drive->sect;
-+	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;
- }
+ #define CMD_DEBUG 0
  
--/**
-- *	drive_cmd_intr		- 	drive command completion interrupt
-- *	@drive: drive the completion interrupt occurred on
-- *
-- *	drive_cmd_intr() is invoked on completion of a special DRIVE_CMD.
-- *	We do any necessary data reading and then wait for the drive to
-- *	go non busy. At that point we may read the error data and complete
-- *	the request
-- */
-- 
--static ide_startstop_t drive_cmd_intr (ide_drive_t *drive)
-+static void ide_tf_set_restore_cmd(ide_drive_t *drive, struct ide_taskfile *tf)
- {
--	struct request *rq = HWGROUP(drive)->rq;
--	ide_hwif_t *hwif = HWIF(drive);
--	u8 *args = (u8 *) rq->buffer;
--	u8 stat = hwif->INB(IDE_STATUS_REG);
--	int retries = 10;
+ #if CMD_DEBUG
+@@ -37,11 +35,6 @@
+  */
+ #define CFR		0x50
+ #define   CFR_INTR_CH0		0x04
+-#define CNTRL		0x51
+-#define   CNTRL_ENA_1ST 	0x04
+-#define   CNTRL_ENA_2ND 	0x08
+-#define   CNTRL_DIS_RA0 	0x40
+-#define   CNTRL_DIS_RA1 	0x80
+ 
+ #define	CMDTIM		0x52
+ #define	ARTTIM0		0x53
+@@ -60,108 +53,13 @@
+ #define MRDMODE		0x71
+ #define   MRDMODE_INTR_CH0	0x04
+ #define   MRDMODE_INTR_CH1	0x08
+-#define   MRDMODE_BLK_CH0	0x10
+-#define   MRDMODE_BLK_CH1	0x20
+-#define BMIDESR0	0x72
+ #define UDIDETCR0	0x73
+ #define DTPR0		0x74
+ #define BMIDECR1	0x78
+ #define BMIDECSR	0x79
+-#define BMIDESR1	0x7A
+ #define UDIDETCR1	0x7B
+ #define DTPR1		0x7C
+ 
+-#if defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_IDE_PROC_FS)
+-#include <linux/stat.h>
+-#include <linux/proc_fs.h>
 -
--	local_irq_enable_in_hardirq();
--	if (rq->cmd_type == REQ_TYPE_ATA_CMD &&
--	    (stat & DRQ_STAT) && args && args[3]) {
--		u8 io_32bit = drive->io_32bit;
--		drive->io_32bit = 0;
--		hwif->ata_input_data(drive, &args[4], args[3] * SECTOR_WORDS);
--		drive->io_32bit = io_32bit;
--		while (((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) && retries--)
--			udelay(100);
--	}
+-static u8 cmd64x_proc = 0;
 -
--	if (!OK_STAT(stat, READY_STAT, BAD_STAT))
--		return ide_error(drive, "drive_cmd", stat);
--		/* calls ide_end_drive_cmd */
--	ide_end_drive_cmd(drive, stat, hwif->INB(IDE_ERROR_REG));
--	return ide_stopped;
-+	tf->nsect   = drive->sect;
-+	tf->command = WIN_RESTORE;
- }
- 
--static void ide_init_specify_cmd(ide_drive_t *drive, ide_task_t *task)
-+static void ide_tf_set_setmult_cmd(ide_drive_t *drive, struct ide_taskfile *tf)
- {
--	task->tfRegister[IDE_NSECTOR_OFFSET] = drive->sect;
--	task->tfRegister[IDE_SECTOR_OFFSET]  = drive->sect;
--	task->tfRegister[IDE_LCYL_OFFSET]    = drive->cyl;
--	task->tfRegister[IDE_HCYL_OFFSET]    = drive->cyl>>8;
--	task->tfRegister[IDE_SELECT_OFFSET]  = ((drive->head-1)|drive->select.all)&0xBF;
--	task->tfRegister[IDE_COMMAND_OFFSET] = WIN_SPECIFY;
+-#define CMD_MAX_DEVS		5
 -
--	task->handler = &set_geometry_intr;
--}
+-static struct pci_dev *cmd_devs[CMD_MAX_DEVS];
+-static int n_cmd_devs;
 -
--static void ide_init_restore_cmd(ide_drive_t *drive, ide_task_t *task)
+-static char * print_cmd64x_get_info (char *buf, struct pci_dev *dev, int index)
 -{
--	task->tfRegister[IDE_NSECTOR_OFFSET] = drive->sect;
--	task->tfRegister[IDE_COMMAND_OFFSET] = WIN_RESTORE;
+-	char *p = buf;
+-	u8 reg72 = 0, reg73 = 0;			/* primary */
+-	u8 reg7a = 0, reg7b = 0;			/* secondary */
+-	u8 reg50 = 1, reg51 = 1, reg57 = 0, reg71 = 0;	/* extra */
 -
--	task->handler = &recal_intr;
+-	p += sprintf(p, "\nController: %d\n", index);
+-	p += sprintf(p, "PCI-%x Chipset.\n", dev->device);
+-
+-	(void) pci_read_config_byte(dev, CFR,       &reg50);
+-	(void) pci_read_config_byte(dev, CNTRL,     &reg51);
+-	(void) pci_read_config_byte(dev, ARTTIM23,  &reg57);
+-	(void) pci_read_config_byte(dev, MRDMODE,   &reg71);
+-	(void) pci_read_config_byte(dev, BMIDESR0,  &reg72);
+-	(void) pci_read_config_byte(dev, UDIDETCR0, &reg73);
+-	(void) pci_read_config_byte(dev, BMIDESR1,  &reg7a);
+-	(void) pci_read_config_byte(dev, UDIDETCR1, &reg7b);
+-
+-	/* PCI0643/6 originally didn't have the primary channel enable bit */
+-	if ((dev->device == PCI_DEVICE_ID_CMD_643) ||
+-	    (dev->device == PCI_DEVICE_ID_CMD_646 && dev->revision < 3))
+-		reg51 |= CNTRL_ENA_1ST;
+-
+-	p += sprintf(p, "---------------- Primary Channel "
+-			"---------------- Secondary Channel ------------\n");
+-	p += sprintf(p, "                 %s                         %s\n",
+-		 (reg51 & CNTRL_ENA_1ST) ? "enabled " : "disabled",
+-		 (reg51 & CNTRL_ENA_2ND) ? "enabled " : "disabled");
+-	p += sprintf(p, "---------------- drive0 --------- drive1 "
+-			"-------- drive0 --------- drive1 ------\n");
+-	p += sprintf(p, "DMA enabled:     %s              %s"
+-			"             %s              %s\n",
+-		(reg72 & 0x20) ? "yes" : "no ", (reg72 & 0x40) ? "yes" : "no ",
+-		(reg7a & 0x20) ? "yes" : "no ", (reg7a & 0x40) ? "yes" : "no ");
+-	p += sprintf(p, "UltraDMA mode:   %s (%c)          %s (%c)",
+-		( reg73 & 0x01) ? " on" : "off",
+-		((reg73 & 0x30) == 0x30) ? ((reg73 & 0x04) ? '3' : '0') :
+-		((reg73 & 0x30) == 0x20) ? ((reg73 & 0x04) ? '3' : '1') :
+-		((reg73 & 0x30) == 0x10) ? ((reg73 & 0x04) ? '4' : '2') :
+-		((reg73 & 0x30) == 0x00) ? ((reg73 & 0x04) ? '5' : '2') : '?',
+-		( reg73 & 0x02) ? " on" : "off",
+-		((reg73 & 0xC0) == 0xC0) ? ((reg73 & 0x08) ? '3' : '0') :
+-		((reg73 & 0xC0) == 0x80) ? ((reg73 & 0x08) ? '3' : '1') :
+-		((reg73 & 0xC0) == 0x40) ? ((reg73 & 0x08) ? '4' : '2') :
+-		((reg73 & 0xC0) == 0x00) ? ((reg73 & 0x08) ? '5' : '2') : '?');
+-	p += sprintf(p, "         %s (%c)          %s (%c)\n",
+-		( reg7b & 0x01) ? " on" : "off",
+-		((reg7b & 0x30) == 0x30) ? ((reg7b & 0x04) ? '3' : '0') :
+-		((reg7b & 0x30) == 0x20) ? ((reg7b & 0x04) ? '3' : '1') :
+-		((reg7b & 0x30) == 0x10) ? ((reg7b & 0x04) ? '4' : '2') :
+-		((reg7b & 0x30) == 0x00) ? ((reg7b & 0x04) ? '5' : '2') : '?',
+-		( reg7b & 0x02) ? " on" : "off",
+-		((reg7b & 0xC0) == 0xC0) ? ((reg7b & 0x08) ? '3' : '0') :
+-		((reg7b & 0xC0) == 0x80) ? ((reg7b & 0x08) ? '3' : '1') :
+-		((reg7b & 0xC0) == 0x40) ? ((reg7b & 0x08) ? '4' : '2') :
+-		((reg7b & 0xC0) == 0x00) ? ((reg7b & 0x08) ? '5' : '2') : '?');
+-	p += sprintf(p, "Interrupt:       %s, %s                 %s, %s\n",
+-		(reg71 & MRDMODE_BLK_CH0  ) ? "blocked" : "enabled",
+-		(reg50 & CFR_INTR_CH0	  ) ? "pending" : "clear  ",
+-		(reg71 & MRDMODE_BLK_CH1  ) ? "blocked" : "enabled",
+-		(reg57 & ARTTIM23_INTR_CH1) ? "pending" : "clear  ");
+-
+-	return (char *)p;
 -}
 -
--static void ide_init_setmult_cmd(ide_drive_t *drive, ide_task_t *task)
+-static int cmd64x_get_info (char *buffer, char **addr, off_t offset, int count)
 -{
--	task->tfRegister[IDE_NSECTOR_OFFSET] = drive->mult_req;
--	task->tfRegister[IDE_COMMAND_OFFSET] = WIN_SETMULT;
+-	char *p = buffer;
+-	int i;
 -
--	task->handler = &set_multmode_intr;
-+	tf->nsect   = drive->mult_req;
-+	tf->command = WIN_SETMULT;
- }
- 
- static ide_startstop_t ide_disk_special(ide_drive_t *drive)
-@@ -707,19 +639,19 @@ static ide_startstop_t ide_disk_special(ide_drive_t *drive)
- 	ide_task_t args;
+-	for (i = 0; i < n_cmd_devs; i++) {
+-		struct pci_dev *dev	= cmd_devs[i];
+-		p = print_cmd64x_get_info(p, dev, i);
+-	}
+-	return p-buffer;	/* => must be less than 4k! */
+-}
+-
+-#endif	/* defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_IDE_PROC_FS) */
+-
+ static u8 quantize_timing(int timing, int quant)
+ {
+ 	return (timing + quant - 1) / quant;
+@@ -322,8 +220,6 @@ static void cmd64x_set_dma_mode(ide_drive_t *drive, const u8 speed)
+ 	case XFER_MW_DMA_0:
+ 		program_cycle_times(drive, 480, 215);
+ 		break;
+-	default:
+-		return;
+ 	}
  
- 	memset(&args, 0, sizeof(ide_task_t));
--	args.command_type = IDE_DRIVE_TASK_NO_DATA;
-+	args.data_phase = TASKFILE_NO_DATA;
+ 	if (speed >= XFER_SW_DMA_0)
+@@ -333,14 +229,15 @@ static void cmd64x_set_dma_mode(ide_drive_t *drive, const u8 speed)
+ static int cmd648_ide_dma_end (ide_drive_t *drive)
+ {
+ 	ide_hwif_t *hwif	= HWIF(drive);
++	unsigned long base	= hwif->dma_base - (hwif->channel * 8);
+ 	int err			= __ide_dma_end(drive);
+ 	u8  irq_mask		= hwif->channel ? MRDMODE_INTR_CH1 :
+ 						  MRDMODE_INTR_CH0;
+-	u8  mrdmode		= inb(hwif->dma_master + 0x01);
++	u8  mrdmode		= inb(base + 1);
  
- 	if (s->b.set_geometry) {
- 		s->b.set_geometry = 0;
--		ide_init_specify_cmd(drive, &args);
-+		ide_tf_set_specify_cmd(drive, &args.tf);
- 	} else if (s->b.recalibrate) {
- 		s->b.recalibrate = 0;
--		ide_init_restore_cmd(drive, &args);
-+		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_init_setmult_cmd(drive, &args);
-+		ide_tf_set_setmult_cmd(drive, &args.tf);
- 	} else if (s->all) {
- 		int special = s->all;
- 		s->all = 0;
-@@ -727,6 +659,9 @@ static ide_startstop_t ide_disk_special(ide_drive_t *drive)
- 		return ide_stopped;
- 	}
+ 	/* clear the interrupt bit */
+ 	outb((mrdmode & ~(MRDMODE_INTR_CH0 | MRDMODE_INTR_CH1)) | irq_mask,
+-	     hwif->dma_master + 0x01);
++	     base + 1);
  
-+	args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE |
-+			IDE_TFLAG_CUSTOM_HANDLER;
-+
- 	do_rw_taskfile(drive, &args);
+ 	return err;
+ }
+@@ -365,10 +262,11 @@ static int cmd64x_ide_dma_end (ide_drive_t *drive)
+ static int cmd648_ide_dma_test_irq (ide_drive_t *drive)
+ {
+ 	ide_hwif_t *hwif	= HWIF(drive);
++	unsigned long base	= hwif->dma_base - (hwif->channel * 8);
+ 	u8 irq_mask		= hwif->channel ? MRDMODE_INTR_CH1 :
+ 						  MRDMODE_INTR_CH0;
+ 	u8 dma_stat		= inb(hwif->dma_status);
+-	u8 mrdmode		= inb(hwif->dma_master + 0x01);
++	u8 mrdmode		= inb(base + 1);
  
- 	return ide_started;
-@@ -801,7 +736,7 @@ static ide_startstop_t do_special (ide_drive_t *drive)
+ #ifdef DEBUG
+ 	printk("%s: dma_stat: 0x%02x mrdmode: 0x%02x irq_mask: 0x%02x\n",
+@@ -472,16 +370,6 @@ static unsigned int __devinit init_chipset_cmd64x(struct pci_dev *dev, const cha
+ 	mrdmode &= ~0x30;
+ 	(void) pci_write_config_byte(dev, MRDMODE, (mrdmode | 0x02));
  
- 			if (hwif->host_flags & IDE_HFLAG_SET_PIO_MODE_KEEP_DMA) {
- 				if (keep_dma)
--					hwif->ide_dma_on(drive);
-+					ide_dma_on(drive);
- 			}
- 		}
+-#if defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_IDE_PROC_FS)
+-
+-	cmd_devs[n_cmd_devs++] = dev;
+-
+-	if (!cmd64x_proc) {
+-		cmd64x_proc = 1;
+-		ide_pci_create_host_proc("cmd64x", cmd64x_get_info);
+-	}
+-#endif /* DISPLAY_CMD64X_TIMINGS && CONFIG_IDE_PROC_FS */
+-
+ 	return 0;
+ }
  
-@@ -861,13 +796,10 @@ static ide_startstop_t execute_drive_cmd (ide_drive_t *drive,
- 		struct request *rq)
- {
+diff --git a/drivers/ide/pci/cs5520.c b/drivers/ide/pci/cs5520.c
+index 0466462..6ec00b8 100644
+--- a/drivers/ide/pci/cs5520.c
++++ b/drivers/ide/pci/cs5520.c
+@@ -71,7 +71,6 @@ static void cs5520_set_pio_mode(ide_drive_t *drive, const u8 pio)
  	ide_hwif_t *hwif = HWIF(drive);
--	if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) {
-- 		ide_task_t *args = rq->special;
-- 
--		if (!args)
--			goto done;
-+	ide_task_t *task = rq->special;
+ 	struct pci_dev *pdev = hwif->pci_dev;
+ 	int controller = drive->dn > 1 ? 1 : 0;
+-	u8 reg;
  
--		hwif->data_phase = args->data_phase;
-+	if (task) {
-+		hwif->data_phase = task->data_phase;
+ 	/* FIXME: if DMA = 1 do we need to set the DMA bit here ? */
  
- 		switch (hwif->data_phase) {
- 		case TASKFILE_MULTI_OUT:
-@@ -880,57 +812,9 @@ static ide_startstop_t execute_drive_cmd (ide_drive_t *drive,
- 			break;
- 		}
+@@ -91,11 +90,6 @@ static void cs5520_set_pio_mode(ide_drive_t *drive, const u8 pio)
+ 	pci_write_config_byte(pdev, 0x66 + 4*controller + (drive->dn&1),
+ 		(cs5520_pio_clocks[pio].recovery << 4) |
+ 		(cs5520_pio_clocks[pio].assert));
+-		
+-	/* Set the DMA enable/disable flag */
+-	reg = inb(hwif->dma_base + 0x02 + 8*controller);
+-	reg |= 1<<((drive->dn&1)+5);
+-	outb(reg, hwif->dma_base + 0x02 + 8*controller);
+ }
  
--		if (args->tf_out_flags.all != 0) 
--			return flagged_taskfile(drive, args);
--		return do_rw_taskfile(drive, args);
--	} else if (rq->cmd_type == REQ_TYPE_ATA_TASK) {
--		u8 *args = rq->buffer;
+ static void cs5520_set_dma_mode(ide_drive_t *drive, const u8 speed)
+@@ -109,13 +103,14 @@ static void cs5520_set_dma_mode(ide_drive_t *drive, const u8 speed)
+  *	We wrap the DMA activate to set the vdma flag. This is needed
+  *	so that the IDE DMA layer issues PIO not DMA commands over the
+  *	DMA channel
++ *
++ *	ATAPI is harder so disable it for now using IDE_HFLAG_NO_ATAPI_DMA
+  */
 - 
--		if (!args)
--			goto done;
--#ifdef DEBUG
-- 		printk("%s: DRIVE_TASK_CMD ", drive->name);
-- 		printk("cmd=0x%02x ", args[0]);
-- 		printk("fr=0x%02x ", args[1]);
-- 		printk("ns=0x%02x ", args[2]);
-- 		printk("sc=0x%02x ", args[3]);
-- 		printk("lcyl=0x%02x ", args[4]);
-- 		printk("hcyl=0x%02x ", args[5]);
-- 		printk("sel=0x%02x\n", args[6]);
--#endif
-- 		hwif->OUTB(args[1], IDE_FEATURE_REG);
-- 		hwif->OUTB(args[3], IDE_SECTOR_REG);
-- 		hwif->OUTB(args[4], IDE_LCYL_REG);
-- 		hwif->OUTB(args[5], IDE_HCYL_REG);
-- 		hwif->OUTB((args[6] & 0xEF)|drive->select.all, IDE_SELECT_REG);
-- 		ide_cmd(drive, args[0], args[2], &drive_cmd_intr);
-- 		return ide_started;
-- 	} else if (rq->cmd_type == REQ_TYPE_ATA_CMD) {
-- 		u8 *args = rq->buffer;
--
--		if (!args)
--			goto done;
--#ifdef DEBUG
-- 		printk("%s: DRIVE_CMD ", drive->name);
-- 		printk("cmd=0x%02x ", args[0]);
-- 		printk("sc=0x%02x ", args[1]);
-- 		printk("fr=0x%02x ", args[2]);
-- 		printk("xx=0x%02x\n", args[3]);
--#endif
-- 		if (args[0] == WIN_SMART) {
-- 			hwif->OUTB(0x4f, IDE_LCYL_REG);
-- 			hwif->OUTB(0xc2, IDE_HCYL_REG);
-- 			hwif->OUTB(args[2],IDE_FEATURE_REG);
-- 			hwif->OUTB(args[1],IDE_SECTOR_REG);
-- 			ide_cmd(drive, args[0], args[3], &drive_cmd_intr);
-- 			return ide_started;
-- 		}
-- 		hwif->OUTB(args[2],IDE_FEATURE_REG);
-- 		ide_cmd(drive, args[0], args[1], &drive_cmd_intr);
-- 		return ide_started;
-- 	}
--
--done:
-+		return do_rw_taskfile(drive, task);
-+	}
+-static int cs5520_dma_on(ide_drive_t *drive)
 +
-  	/*
-  	 * NULL is actually a valid way of waiting for
-  	 * all current requests to be flushed from the queue.
-@@ -970,8 +854,7 @@ static void ide_check_pm_state(ide_drive_t *drive, struct request *rq)
- 		if (rc)
- 			printk(KERN_WARNING "%s: bus not ready on wakeup\n", drive->name);
- 		SELECT_DRIVE(drive);
--		if (IDE_CONTROL_REG)
--			HWIF(drive)->OUTB(drive->ctl, IDE_CONTROL_REG);
-+		ide_set_irq(drive, 1);
- 		rc = ide_wait_not_busy(HWIF(drive), 100000);
- 		if (rc)
- 			printk(KERN_WARNING "%s: drive not ready on wakeup\n", drive->name);
-@@ -1003,6 +886,7 @@ static ide_startstop_t start_request (ide_drive_t *drive, struct request *rq)
++static void cs5520_dma_host_set(ide_drive_t *drive, int on)
+ {
+-	/* ATAPI is harder so leave it for now */
+-	drive->vdma = 1;
+-	return 0;
++	drive->vdma = on;
++	ide_dma_host_set(drive, on);
+ }
  
- 	/* bail early if we've exceeded max_failures */
- 	if (drive->max_failures && (drive->failures > drive->max_failures)) {
-+		rq->cmd_flags |= REQ_FAILED;
- 		goto kill_rq;
- 	}
+ static void __devinit init_hwif_cs5520(ide_hwif_t *hwif)
+@@ -126,7 +121,7 @@ static void __devinit init_hwif_cs5520(ide_hwif_t *hwif)
+ 	if (hwif->dma_base == 0)
+ 		return;
  
-@@ -1034,9 +918,7 @@ static ide_startstop_t start_request (ide_drive_t *drive, struct request *rq)
- 		if (drive->current_speed == 0xff)
- 			ide_config_drive_speed(drive, drive->desired_speed);
+-	hwif->ide_dma_on = &cs5520_dma_on;
++	hwif->dma_host_set = &cs5520_dma_host_set;
+ }
  
--		if (rq->cmd_type == REQ_TYPE_ATA_CMD ||
--		    rq->cmd_type == REQ_TYPE_ATA_TASK ||
--		    rq->cmd_type == REQ_TYPE_ATA_TASKFILE)
-+		if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE)
- 			return execute_drive_cmd(drive, rq);
- 		else if (blk_pm_request(rq)) {
- 			struct request_pm_state *pm = rq->data;
-@@ -1244,11 +1126,13 @@ static void ide_do_request (ide_hwgroup_t *hwgroup, int masked_irq)
- 		}
- 	again:
- 		hwif = HWIF(drive);
--		if (hwgroup->hwif->sharing_irq &&
--		    hwif != hwgroup->hwif &&
--		    hwif->io_ports[IDE_CONTROL_OFFSET]) {
--			/* set nIEN for previous hwif */
--			SELECT_INTERRUPT(drive);
-+		if (hwgroup->hwif->sharing_irq && hwif != hwgroup->hwif) {
-+			/*
-+			 * set nIEN for previous hwif, drives in the
-+			 * quirk_list may not like intr setups/cleanups
-+			 */
-+			if (drive->quirk_list != 1)
-+				ide_set_irq(drive, 0);
- 		}
- 		hwgroup->hwif = hwif;
- 		hwgroup->drive = drive;
-@@ -1361,7 +1245,7 @@ static ide_startstop_t ide_dma_timeout_retry(ide_drive_t *drive, int error)
- 	 */
- 	drive->retry_pio++;
- 	drive->state = DMA_PIO_RETRY;
--	hwif->dma_off_quietly(drive);
-+	ide_dma_off_quietly(drive);
+ #define DECLARE_CS_DEV(name_str)				\
+@@ -137,6 +132,7 @@ static void __devinit init_hwif_cs5520(ide_hwif_t *hwif)
+ 				  IDE_HFLAG_CS5520 |		\
+ 				  IDE_HFLAG_VDMA |		\
+ 				  IDE_HFLAG_NO_ATAPI_DMA |	\
++				  IDE_HFLAG_ABUSE_SET_DMA_MODE |\
+ 				  IDE_HFLAG_BOOTABLE,		\
+ 		.pio_mask	= ATA_PIO4,			\
+ 	}
+diff --git a/drivers/ide/pci/cs5530.c b/drivers/ide/pci/cs5530.c
+index 5476903..df5966b 100644
+--- a/drivers/ide/pci/cs5530.c
++++ b/drivers/ide/pci/cs5530.c
+@@ -116,8 +116,6 @@ static void cs5530_set_dma_mode(ide_drive_t *drive, const u8 mode)
+ 		case XFER_MW_DMA_0:	timings = 0x00077771; break;
+ 		case XFER_MW_DMA_1:	timings = 0x00012121; break;
+ 		case XFER_MW_DMA_2:	timings = 0x00002020; break;
+-		default:
+-			return;
+ 	}
+ 	basereg = CS5530_BASEREG(drive->hwif);
+ 	reg = inl(basereg + 4);			/* get drive0 config register */
+diff --git a/drivers/ide/pci/cs5535.c b/drivers/ide/pci/cs5535.c
+index ddcbeba..50b3d77 100644
+--- a/drivers/ide/pci/cs5535.c
++++ b/drivers/ide/pci/cs5535.c
+@@ -190,7 +190,7 @@ static const struct ide_port_info cs5535_chipset __devinitdata = {
+ 	.name		= "CS5535",
+ 	.init_hwif	= init_hwif_cs5535,
+ 	.host_flags	= IDE_HFLAG_SINGLE | IDE_HFLAG_POST_SET_MODE |
+-			  IDE_HFLAG_BOOTABLE,
++			  IDE_HFLAG_ABUSE_SET_DMA_MODE | IDE_HFLAG_BOOTABLE,
+ 	.pio_mask	= ATA_PIO4,
+ 	.mwdma_mask	= ATA_MWDMA2,
+ 	.udma_mask	= ATA_UDMA4,
+diff --git a/drivers/ide/pci/cy82c693.c b/drivers/ide/pci/cy82c693.c
+index 1cd4e9c..3ec4c65 100644
+--- a/drivers/ide/pci/cy82c693.c
++++ b/drivers/ide/pci/cy82c693.c
+@@ -1,5 +1,5 @@
+ /*
+- * linux/drivers/ide/pci/cy82c693.c		Version 0.42	Oct 23, 2007
++ * linux/drivers/ide/pci/cy82c693.c		Version 0.44	Nov 8, 2007
+  *
+  *  Copyright (C) 1998-2000 Andreas S. Krebs (akrebs at altavista.net), Maintainer
+  *  Copyright (C) 1998-2002 Andre Hedrick <andre at linux-ide.org>, Integrator
+@@ -176,17 +176,12 @@ static void compute_clocks (u8 pio, pio_clocks_t *p_pclk)
+  * set DMA mode a specific channel for CY82C693
+  */
  
- 	/*
- 	 * un-busy drive etc (hwgroup->busy is cleared on return) and
-@@ -1454,12 +1338,8 @@ void ide_timer_expiry (unsigned long data)
- 			 */
- 			spin_unlock(&ide_lock);
- 			hwif  = HWIF(drive);
--#if DISABLE_IRQ_NOSYNC
--			disable_irq_nosync(hwif->irq);
--#else
- 			/* disable_irq_nosync ?? */
- 			disable_irq(hwif->irq);
--#endif /* DISABLE_IRQ_NOSYNC */
- 			/* local CPU only,
- 			 * as if we were handling an interrupt */
- 			local_irq_disable();
-@@ -1710,7 +1590,6 @@ irqreturn_t ide_intr (int irq, void *dev_id)
- void ide_init_drive_cmd (struct request *rq)
+-static void cy82c693_dma_enable (ide_drive_t *drive, int mode, int single)
++static void cy82c693_set_dma_mode(ide_drive_t *drive, const u8 mode)
  {
- 	memset(rq, 0, sizeof(*rq));
--	rq->cmd_type = REQ_TYPE_ATA_CMD;
- 	rq->ref_count = 1;
- }
+-	u8 index = 0, data = 0;
++	ide_hwif_t *hwif = drive->hwif;
++	u8 single = (mode & 0x10) >> 4, index = 0, data = 0;
  
-@@ -1785,3 +1664,19 @@ int ide_do_drive_cmd (ide_drive_t *drive, struct request *rq, ide_action_t actio
- }
+-	if (mode>2)	/* make sure we set a valid mode */
+-		mode = 2;
+-			   
+-	if (mode > drive->id->tDMA)  /* to be absolutly sure we have a valid mode */
+-		mode = drive->id->tDMA;
+-	
+-	index = (HWIF(drive)->channel==0) ? CY82_INDEX_CHANNEL0 : CY82_INDEX_CHANNEL1;
++	index = hwif->channel ? CY82_INDEX_CHANNEL1 : CY82_INDEX_CHANNEL0;
  
- EXPORT_SYMBOL(ide_do_drive_cmd);
-+
-+void ide_pktcmd_tf_load(ide_drive_t *drive, u32 tf_flags, u16 bcount, u8 dma)
-+{
-+	ide_task_t task;
-+
-+	memset(&task, 0, sizeof(task));
-+	task.tf_flags = IDE_TFLAG_OUT_LBAH | IDE_TFLAG_OUT_LBAM |
-+			IDE_TFLAG_OUT_FEATURE | tf_flags;
-+	task.tf.feature = dma;		/* Use PIO/DMA */
-+	task.tf.lbam    = bcount & 0xff;
-+	task.tf.lbah    = (bcount >> 8) & 0xff;
-+
-+	ide_tf_load(drive, &task);
-+}
-+
-+EXPORT_SYMBOL_GPL(ide_pktcmd_tf_load);
-diff --git a/drivers/ide/ide-iops.c b/drivers/ide/ide-iops.c
-index bb9693d..e2a7e95 100644
---- a/drivers/ide/ide-iops.c
-+++ b/drivers/ide/ide-iops.c
-@@ -158,14 +158,6 @@ void default_hwif_mmiops (ide_hwif_t *hwif)
+ #if CY82C693_DEBUG_LOGS
+ 	/* for debug let's show the previous values */
+@@ -199,7 +194,7 @@ static void cy82c693_dma_enable (ide_drive_t *drive, int mode, int single)
+ 		(data&0x3), ((data>>2)&1));
+ #endif /* CY82C693_DEBUG_LOGS */
  
- EXPORT_SYMBOL(default_hwif_mmiops);
+-	data = (u8)mode|(u8)(single<<2);
++	data = (mode & 3) | (single << 2);
  
--u32 ide_read_24 (ide_drive_t *drive)
--{
--	u8 hcyl = HWIF(drive)->INB(IDE_HCYL_REG);
--	u8 lcyl = HWIF(drive)->INB(IDE_LCYL_REG);
--	u8 sect = HWIF(drive)->INB(IDE_SECTOR_REG);
--	return (hcyl<<16)|(lcyl<<8)|sect;
--}
--
- void SELECT_DRIVE (ide_drive_t *drive)
- {
- 	if (HWIF(drive)->selectproc)
-@@ -175,26 +167,12 @@ void SELECT_DRIVE (ide_drive_t *drive)
+ 	outb(index, CY82_INDEX_PORT);
+ 	outb(data, CY82_DATA_PORT);
+@@ -207,7 +202,7 @@ static void cy82c693_dma_enable (ide_drive_t *drive, int mode, int single)
+ #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, single);
++		mode & 3, single);
+ #endif /* CY82C693_DEBUG_INFO */
  
- EXPORT_SYMBOL(SELECT_DRIVE);
+ 	/* 
+@@ -230,39 +225,6 @@ static void cy82c693_dma_enable (ide_drive_t *drive, int mode, int single)
+ #endif /* CY82C693_DEBUG_INFO */
+ }
  
--void SELECT_INTERRUPT (ide_drive_t *drive)
+-/* 
+- * used to set DMA mode for CY82C693 (single and multi modes)
+- */
+-static int cy82c693_ide_dma_on (ide_drive_t *drive)
 -{
--	if (HWIF(drive)->intrproc)
--		HWIF(drive)->intrproc(drive);
--	else
--		HWIF(drive)->OUTB(drive->ctl|2, IDE_CONTROL_REG);
+-	struct hd_driveid *id = drive->id;
+-
+-#if CY82C693_DEBUG_INFO
+-	printk (KERN_INFO "dma_on: %s\n", drive->name);
+-#endif /* CY82C693_DEBUG_INFO */
+-
+-	if (id != NULL) {		
+-		/* Enable DMA on any drive that has DMA
+-		 * (multi or single) enabled
+-		 */
+-		if (id->field_valid & 2) {	/* regular DMA */
+-			int mmode, smode;
+-
+-			mmode = id->dma_mword & (id->dma_mword >> 8);
+-			smode = id->dma_1word & (id->dma_1word >> 8);
+-			       		      
+-			if (mmode != 0) {
+-				/* enable multi */
+-				cy82c693_dma_enable(drive, (mmode >> 1), 0);
+-			} else if (smode != 0) {
+-				/* enable single */
+-				cy82c693_dma_enable(drive, (smode >> 1), 1);
+-			}
+-		}
+-	}
+-        return __ide_dma_on(drive);
 -}
 -
- void SELECT_MASK (ide_drive_t *drive, int mask)
+ static void cy82c693_set_pio_mode(ide_drive_t *drive, const u8 pio)
  {
- 	if (HWIF(drive)->maskproc)
- 		HWIF(drive)->maskproc(drive, mask);
+ 	ide_hwif_t *hwif = HWIF(drive);
+@@ -429,11 +391,7 @@ static unsigned int __devinit init_chipset_cy82c693(struct pci_dev *dev, const c
+ static void __devinit init_hwif_cy82c693(ide_hwif_t *hwif)
+ {
+ 	hwif->set_pio_mode = &cy82c693_set_pio_mode;
+-
+-	if (hwif->dma_base == 0)
+-		return;
+-
+-	hwif->ide_dma_on = &cy82c693_ide_dma_on;
++	hwif->set_dma_mode = &cy82c693_set_dma_mode;
  }
  
--void QUIRK_LIST (ide_drive_t *drive)
--{
--	if (HWIF(drive)->quirkproc)
--		drive->quirk_list = HWIF(drive)->quirkproc(drive);
--}
--
- /*
-  * Some localbus EIDE interfaces require a special access sequence
-  * when using 32-bit I/O instructions to transfer data.  We call this
-@@ -449,7 +427,6 @@ int drive_is_ready (ide_drive_t *drive)
- 	udelay(1);
- #endif
+ static void __devinit init_iops_cy82c693(ide_hwif_t *hwif)
+@@ -454,11 +412,11 @@ static const struct ide_port_info cy82c693_chipset __devinitdata = {
+ 	.init_iops	= init_iops_cy82c693,
+ 	.init_hwif	= init_hwif_cy82c693,
+ 	.chipset	= ide_cy82c693,
+-	.host_flags	= IDE_HFLAG_SINGLE | IDE_HFLAG_TRUST_BIOS_FOR_DMA |
++	.host_flags	= IDE_HFLAG_SINGLE | IDE_HFLAG_CY82C693 |
+ 			  IDE_HFLAG_BOOTABLE,
+ 	.pio_mask	= ATA_PIO4,
+-	.swdma_mask	= ATA_SWDMA2_ONLY,
+-	.mwdma_mask	= ATA_MWDMA2_ONLY,
++	.swdma_mask	= ATA_SWDMA2,
++	.mwdma_mask	= ATA_MWDMA2,
+ };
  
--#ifdef CONFIG_IDEPCI_SHARE_IRQ
- 	/*
- 	 * We do a passive status test under shared PCI interrupts on
- 	 * cards that truly share the ATA side interrupt, but may also share
-@@ -459,7 +436,6 @@ int drive_is_ready (ide_drive_t *drive)
- 	if (IDE_CONTROL_REG)
- 		stat = hwif->INB(IDE_ALTSTATUS_REG);
- 	else
--#endif /* CONFIG_IDEPCI_SHARE_IRQ */
- 		/* Note: this may clear a pending IRQ!! */
- 		stat = hwif->INB(IDE_STATUS_REG);
+ static int __devinit cy82c693_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+diff --git a/drivers/ide/pci/delkin_cb.c b/drivers/ide/pci/delkin_cb.c
+index 8382908..26aa492 100644
+--- a/drivers/ide/pci/delkin_cb.c
++++ b/drivers/ide/pci/delkin_cb.c
+@@ -80,7 +80,7 @@ delkin_cb_probe (struct pci_dev *dev, const struct pci_device_id *id)
+ 	hw.irq = dev->irq;
+ 	hw.chipset = ide_pci;		/* this enables IRQ sharing */
  
-@@ -642,9 +618,9 @@ no_80w:
+-	rc = ide_register_hw(&hw, &ide_undecoded_slave, 0, &hwif);
++	rc = ide_register_hw(&hw, &ide_undecoded_slave, &hwif);
+ 	if (rc < 0) {
+ 		printk(KERN_ERR "delkin_cb: ide_register_hw failed (%d)\n", rc);
+ 		pci_disable_device(dev);
+diff --git a/drivers/ide/pci/hpt34x.c b/drivers/ide/pci/hpt34x.c
+index ae6307f..dfba0d1 100644
+--- a/drivers/ide/pci/hpt34x.c
++++ b/drivers/ide/pci/hpt34x.c
+@@ -129,14 +129,18 @@ static void __devinit init_hwif_hpt34x(ide_hwif_t *hwif)
+ 	hwif->set_dma_mode = &hpt34x_set_mode;
+ }
  
- int ide_ata66_check (ide_drive_t *drive, ide_task_t *args)
- {
--	if ((args->tfRegister[IDE_COMMAND_OFFSET] == WIN_SETFEATURES) &&
--	    (args->tfRegister[IDE_SECTOR_OFFSET] > XFER_UDMA_2) &&
--	    (args->tfRegister[IDE_FEATURE_OFFSET] == SETFEATURES_XFER)) {
-+	if (args->tf.command == WIN_SETFEATURES &&
-+	    args->tf.nsect > XFER_UDMA_2 &&
-+	    args->tf.feature == SETFEATURES_XFER) {
- 		if (eighty_ninty_three(drive) == 0) {
- 			printk(KERN_WARNING "%s: UDMA speeds >UDMA33 cannot "
- 					    "be set\n", drive->name);
-@@ -662,9 +638,9 @@ int ide_ata66_check (ide_drive_t *drive, ide_task_t *args)
++#define IDE_HFLAGS_HPT34X \
++	(IDE_HFLAG_NO_ATAPI_DMA | \
++	 IDE_HFLAG_ABUSE_SET_DMA_MODE | \
++	 IDE_HFLAG_NO_AUTODMA)
++
+ static const struct ide_port_info hpt34x_chipsets[] __devinitdata = {
+ 	{ /* 0 */
+ 		.name		= "HPT343",
+ 		.init_chipset	= init_chipset_hpt34x,
+ 		.init_hwif	= init_hwif_hpt34x,
+ 		.extra		= 16,
+-		.host_flags	= IDE_HFLAG_NO_ATAPI_DMA |
+-				  IDE_HFLAG_NO_AUTODMA,
++		.host_flags	= IDE_HFLAGS_HPT34X,
+ 		.pio_mask	= ATA_PIO5,
+ 	},
+ 	{ /* 1 */
+@@ -144,9 +148,7 @@ static const struct ide_port_info hpt34x_chipsets[] __devinitdata = {
+ 		.init_chipset	= init_chipset_hpt34x,
+ 		.init_hwif	= init_hwif_hpt34x,
+ 		.extra		= 16,
+-		.host_flags	= IDE_HFLAG_NO_ATAPI_DMA |
+-				  IDE_HFLAG_NO_AUTODMA |
+-				  IDE_HFLAG_OFF_BOARD,
++		.host_flags	= IDE_HFLAGS_HPT34X | IDE_HFLAG_OFF_BOARD,
+ 		.pio_mask	= ATA_PIO5,
+ #ifdef CONFIG_HPT34X_AUTODMA
+ 		.swdma_mask	= ATA_SWDMA2,
+diff --git a/drivers/ide/pci/hpt366.c b/drivers/ide/pci/hpt366.c
+index 9fce25b..1268593 100644
+--- a/drivers/ide/pci/hpt366.c
++++ b/drivers/ide/pci/hpt366.c
+@@ -1,5 +1,5 @@
+ /*
+- * linux/drivers/ide/pci/hpt366.c		Version 1.22	Dec 4, 2007
++ * linux/drivers/ide/pci/hpt366.c		Version 1.30	Dec 12, 2007
+  *
+  * Copyright (C) 1999-2003		Andre Hedrick <andre at linux-ide.org>
+  * Portions Copyright (C) 2001	        Sun Microsystems, Inc.
+@@ -88,7 +88,7 @@
+  * - rename all the register related variables consistently
+  * - move all the interrupt twiddling code from the speedproc handlers into
+  *   init_hwif_hpt366(), also grouping all the DMA related code together there
+- * - merge two HPT37x speedproc handlers, fix the PIO timing register mask and
++ * - merge HPT36x/HPT37x speedproc handlers, fix PIO timing register mask and
+  *   separate the UltraDMA and MWDMA masks there to avoid changing PIO timings
+  *   when setting an UltraDMA mode
+  * - fix hpt3xx_tune_drive() to set the PIO mode requested, not always select
+@@ -458,6 +458,13 @@ enum ata_clock {
+ 	NUM_ATA_CLOCKS
+ };
+ 
++struct hpt_timings {
++	u32 pio_mask;
++	u32 dma_mask;
++	u32 ultra_mask;
++	u32 *clock_table[NUM_ATA_CLOCKS];
++};
++
+ /*
+  *	Hold all the HighPoint chip information in one place.
   */
- int set_transfer (ide_drive_t *drive, ide_task_t *args)
- {
--	if ((args->tfRegister[IDE_COMMAND_OFFSET] == WIN_SETFEATURES) &&
--	    (args->tfRegister[IDE_SECTOR_OFFSET] >= XFER_SW_DMA_0) &&
--	    (args->tfRegister[IDE_FEATURE_OFFSET] == SETFEATURES_XFER) &&
-+	if (args->tf.command == WIN_SETFEATURES &&
-+	    args->tf.nsect >= XFER_SW_DMA_0 &&
-+	    args->tf.feature == SETFEATURES_XFER &&
- 	    (drive->id->dma_ultra ||
- 	     drive->id->dma_mword ||
- 	     drive->id->dma_1word))
-@@ -712,8 +688,7 @@ int ide_driveid_update(ide_drive_t *drive)
- 	 */
+@@ -468,7 +475,8 @@ struct hpt_info {
+ 	u8 udma_mask;		/* Allowed UltraDMA modes mask. */
+ 	u8 dpll_clk;		/* DPLL clock in MHz */
+ 	u8 pci_clk;		/* PCI  clock in MHz */
+-	u32 **settings; 	/* Chipset settings table */
++	struct hpt_timings *timings; /* Chipset timing data */
++	u8 clock;		/* ATA clock selected */
+ };
  
- 	SELECT_MASK(drive, 1);
--	if (IDE_CONTROL_REG)
--		hwif->OUTB(drive->ctl,IDE_CONTROL_REG);
-+	ide_set_irq(drive, 1);
- 	msleep(50);
- 	hwif->OUTB(WIN_IDENTIFY, IDE_COMMAND_REG);
- 	timeout = jiffies + WAIT_WORSTCASE;
-@@ -766,8 +741,8 @@ int ide_config_drive_speed(ide_drive_t *drive, u8 speed)
- //		msleep(50);
+ /* Supported HighPoint chips */
+@@ -486,20 +494,30 @@ enum {
+ 	HPT371N
+ };
  
- #ifdef CONFIG_BLK_DEV_IDEDMA
--	if (hwif->ide_dma_on)	/* check if host supports DMA */
--		hwif->dma_host_off(drive);
-+	if (hwif->dma_host_set)	/* check if host supports DMA */
-+		hwif->dma_host_set(drive, 0);
- #endif
+-static u32 *hpt36x_settings[NUM_ATA_CLOCKS] = {
+-	twenty_five_base_hpt36x,
+-	thirty_three_base_hpt36x,
+-	forty_base_hpt36x,
+-	NULL,
+-	NULL
++static struct hpt_timings hpt36x_timings = {
++	.pio_mask	= 0xc1f8ffff,
++	.dma_mask	= 0x303800ff,
++	.ultra_mask	= 0x30070000,
++	.clock_table	= {
++		[ATA_CLOCK_25MHZ] = twenty_five_base_hpt36x,
++		[ATA_CLOCK_33MHZ] = thirty_three_base_hpt36x,
++		[ATA_CLOCK_40MHZ] = forty_base_hpt36x,
++		[ATA_CLOCK_50MHZ] = NULL,
++		[ATA_CLOCK_66MHZ] = NULL
++	}
+ };
  
- 	/* Skip setting PIO flow-control modes on pre-EIDE drives */
-@@ -796,13 +771,12 @@ int ide_config_drive_speed(ide_drive_t *drive, u8 speed)
- 	SELECT_DRIVE(drive);
- 	SELECT_MASK(drive, 0);
- 	udelay(1);
--	if (IDE_CONTROL_REG)
--		hwif->OUTB(drive->ctl | 2, IDE_CONTROL_REG);
-+	ide_set_irq(drive, 0);
- 	hwif->OUTB(speed, IDE_NSECTOR_REG);
- 	hwif->OUTB(SETFEATURES_XFER, IDE_FEATURE_REG);
- 	hwif->OUTBSYNC(drive, WIN_SETFEATURES, IDE_COMMAND_REG);
--	if ((IDE_CONTROL_REG) && (drive->quirk_list == 2))
--		hwif->OUTB(drive->ctl, IDE_CONTROL_REG);
-+	if (drive->quirk_list == 2)
-+		ide_set_irq(drive, 1);
+-static u32 *hpt37x_settings[NUM_ATA_CLOCKS] = {
+-	NULL,
+-	thirty_three_base_hpt37x,
+-	NULL,
+-	fifty_base_hpt37x,
+-	sixty_six_base_hpt37x
++static struct hpt_timings hpt37x_timings = {
++	.pio_mask	= 0xcfc3ffff,
++	.dma_mask	= 0x31c001ff,
++	.ultra_mask	= 0x303c0000,
++	.clock_table	= {
++		[ATA_CLOCK_25MHZ] = NULL,
++		[ATA_CLOCK_33MHZ] = thirty_three_base_hpt37x,
++		[ATA_CLOCK_40MHZ] = NULL,
++		[ATA_CLOCK_50MHZ] = fifty_base_hpt37x,
++		[ATA_CLOCK_66MHZ] = sixty_six_base_hpt37x
++	}
+ };
  
- 	error = __ide_wait_stat(drive, drive->ready_stat,
- 				BUSY_STAT|DRQ_STAT|ERR_STAT,
-@@ -823,10 +797,11 @@ int ide_config_drive_speed(ide_drive_t *drive, u8 speed)
+ static const struct hpt_info hpt36x __devinitdata = {
+@@ -507,7 +525,7 @@ static const struct hpt_info hpt36x __devinitdata = {
+ 	.chip_type	= HPT36x,
+ 	.udma_mask	= HPT366_ALLOW_ATA66_3 ? (HPT366_ALLOW_ATA66_4 ? ATA_UDMA4 : ATA_UDMA3) : ATA_UDMA2,
+ 	.dpll_clk	= 0,	/* no DPLL */
+-	.settings	= hpt36x_settings
++	.timings	= &hpt36x_timings
+ };
  
-  skip:
- #ifdef CONFIG_BLK_DEV_IDEDMA
--	if (speed >= XFER_SW_DMA_0)
--		hwif->dma_host_on(drive);
--	else if (hwif->ide_dma_on)	/* check if host supports DMA */
--		hwif->dma_off_quietly(drive);
-+	if ((speed >= XFER_SW_DMA_0 || (hwif->host_flags & IDE_HFLAG_VDMA)) &&
-+	    drive->using_dma)
-+		hwif->dma_host_set(drive, 1);
-+	else if (hwif->dma_host_set)	/* check if host supports DMA */
-+		ide_dma_off_quietly(drive);
- #endif
+ static const struct hpt_info hpt370 __devinitdata = {
+@@ -515,7 +533,7 @@ static const struct hpt_info hpt370 __devinitdata = {
+ 	.chip_type	= HPT370,
+ 	.udma_mask	= HPT370_ALLOW_ATA100_5 ? ATA_UDMA5 : ATA_UDMA4,
+ 	.dpll_clk	= 48,
+-	.settings	= hpt37x_settings
++	.timings	= &hpt37x_timings
+ };
  
- 	switch(speed) {
-@@ -902,8 +877,9 @@ EXPORT_SYMBOL(ide_set_handler);
-  *	handler and IRQ setup do not race. All IDE command kick off
-  *	should go via this function or do equivalent locking.
-  */
-- 
--void ide_execute_command(ide_drive_t *drive, task_ioreg_t cmd, ide_handler_t *handler, unsigned timeout, ide_expiry_t *expiry)
-+
-+void ide_execute_command(ide_drive_t *drive, u8 cmd, ide_handler_t *handler,
-+			 unsigned timeout, ide_expiry_t *expiry)
- {
- 	unsigned long flags;
- 	ide_hwgroup_t *hwgroup = HWGROUP(drive);
-@@ -1035,10 +1011,10 @@ static void check_dma_crc(ide_drive_t *drive)
- {
- #ifdef CONFIG_BLK_DEV_IDEDMA
- 	if (drive->crc_count) {
--		drive->hwif->dma_off_quietly(drive);
-+		ide_dma_off_quietly(drive);
- 		ide_set_xfer_rate(drive, ide_auto_reduce_xfer(drive));
- 		if (drive->current_speed >= XFER_SW_DMA_0)
--			(void) HWIF(drive)->ide_dma_on(drive);
-+			ide_dma_on(drive);
- 	} else
- 		ide_dma_off(drive);
- #endif
-@@ -1051,8 +1027,7 @@ static void ide_disk_pre_reset(ide_drive_t *drive)
- 	drive->special.all = 0;
- 	drive->special.b.set_geometry = legacy;
- 	drive->special.b.recalibrate  = legacy;
--	if (OK_TO_RESET_CONTROLLER)
--		drive->mult_count = 0;
-+	drive->mult_count = 0;
- 	if (!drive->keep_settings && !drive->using_dma)
- 		drive->mult_req = 0;
- 	if (drive->mult_req != drive->mult_count)
-@@ -1137,7 +1112,6 @@ static ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi)
- 	for (unit = 0; unit < MAX_DRIVES; ++unit)
- 		pre_reset(&hwif->drives[unit]);
+ static const struct hpt_info hpt370a __devinitdata = {
+@@ -523,7 +541,7 @@ static const struct hpt_info hpt370a __devinitdata = {
+ 	.chip_type	= HPT370A,
+ 	.udma_mask	= HPT370_ALLOW_ATA100_5 ? ATA_UDMA5 : ATA_UDMA4,
+ 	.dpll_clk	= 48,
+-	.settings	= hpt37x_settings
++	.timings	= &hpt37x_timings
+ };
+ 
+ static const struct hpt_info hpt374 __devinitdata = {
+@@ -531,7 +549,7 @@ static const struct hpt_info hpt374 __devinitdata = {
+ 	.chip_type	= HPT374,
+ 	.udma_mask	= ATA_UDMA5,
+ 	.dpll_clk	= 48,
+-	.settings	= hpt37x_settings
++	.timings	= &hpt37x_timings
+ };
+ 
+ static const struct hpt_info hpt372 __devinitdata = {
+@@ -539,7 +557,7 @@ static const struct hpt_info hpt372 __devinitdata = {
+ 	.chip_type	= HPT372,
+ 	.udma_mask	= HPT372_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5,
+ 	.dpll_clk	= 55,
+-	.settings	= hpt37x_settings
++	.timings	= &hpt37x_timings
+ };
+ 
+ static const struct hpt_info hpt372a __devinitdata = {
+@@ -547,7 +565,7 @@ static const struct hpt_info hpt372a __devinitdata = {
+ 	.chip_type	= HPT372A,
+ 	.udma_mask	= HPT372_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5,
+ 	.dpll_clk	= 66,
+-	.settings	= hpt37x_settings
++	.timings	= &hpt37x_timings
+ };
  
--#if OK_TO_RESET_CONTROLLER
- 	if (!IDE_CONTROL_REG) {
- 		spin_unlock_irqrestore(&ide_lock, flags);
- 		return ide_stopped;
-@@ -1174,11 +1148,8 @@ static ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi)
- 	 * state when the disks are reset this way. At least, the Winbond
- 	 * 553 documentation says that
- 	 */
--	if (hwif->resetproc != NULL) {
-+	if (hwif->resetproc)
- 		hwif->resetproc(drive);
--	}
--	
--#endif	/* OK_TO_RESET_CONTROLLER */
+ static const struct hpt_info hpt302 __devinitdata = {
+@@ -555,7 +573,7 @@ static const struct hpt_info hpt302 __devinitdata = {
+ 	.chip_type	= HPT302,
+ 	.udma_mask	= HPT302_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5,
+ 	.dpll_clk	= 66,
+-	.settings	= hpt37x_settings
++	.timings	= &hpt37x_timings
+ };
  
- 	spin_unlock_irqrestore(&ide_lock, flags);
- 	return ide_started;
-diff --git a/drivers/ide/ide-lib.c b/drivers/ide/ide-lib.c
-index 062d3bc..9b44fbd 100644
---- a/drivers/ide/ide-lib.c
-+++ b/drivers/ide/ide-lib.c
-@@ -441,6 +441,12 @@ int ide_set_xfer_rate(ide_drive_t *drive, u8 rate)
- 	 * case could happen iff the transfer mode has already been set on
- 	 * the device by ide-proc.c::set_xfer_rate()).
- 	 */
-+	if (rate < XFER_PIO_0) {
-+		if (hwif->host_flags & IDE_HFLAG_ABUSE_SET_DMA_MODE)
-+			return ide_set_dma_mode(drive, rate);
-+		else
-+			return ide_config_drive_speed(drive, rate);
-+	}
+ static const struct hpt_info hpt371 __devinitdata = {
+@@ -563,7 +581,7 @@ static const struct hpt_info hpt371 __devinitdata = {
+ 	.chip_type	= HPT371,
+ 	.udma_mask	= HPT371_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5,
+ 	.dpll_clk	= 66,
+-	.settings	= hpt37x_settings
++	.timings	= &hpt37x_timings
+ };
  
- 	return ide_set_dma_mode(drive, rate);
- }
-@@ -448,8 +454,7 @@ int ide_set_xfer_rate(ide_drive_t *drive, u8 rate)
- static void ide_dump_opcode(ide_drive_t *drive)
- {
- 	struct request *rq;
--	u8 opcode = 0;
--	int found = 0;
-+	ide_task_t *task = NULL;
+ static const struct hpt_info hpt372n __devinitdata = {
+@@ -571,7 +589,7 @@ static const struct hpt_info hpt372n __devinitdata = {
+ 	.chip_type	= HPT372N,
+ 	.udma_mask	= HPT372_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5,
+ 	.dpll_clk	= 77,
+-	.settings	= hpt37x_settings
++	.timings	= &hpt37x_timings
+ };
  
- 	spin_lock(&ide_lock);
- 	rq = NULL;
-@@ -458,164 +463,129 @@ static void ide_dump_opcode(ide_drive_t *drive)
- 	spin_unlock(&ide_lock);
- 	if (!rq)
- 		return;
--	if (rq->cmd_type == REQ_TYPE_ATA_CMD ||
--	    rq->cmd_type == REQ_TYPE_ATA_TASK) {
--		char *args = rq->buffer;
--		if (args) {
--			opcode = args[0];
--			found = 1;
--		}
--	} else if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) {
--		ide_task_t *args = rq->special;
--		if (args) {
--			task_struct_t *tf = (task_struct_t *) args->tfRegister;
--			opcode = tf->command;
--			found = 1;
--		}
--	}
-+
-+	if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE)
-+		task = rq->special;
+ static const struct hpt_info hpt302n __devinitdata = {
+@@ -579,7 +597,7 @@ static const struct hpt_info hpt302n __devinitdata = {
+ 	.chip_type	= HPT302N,
+ 	.udma_mask	= HPT302_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5,
+ 	.dpll_clk	= 77,
+-	.settings	= hpt37x_settings
++	.timings	= &hpt37x_timings
+ };
  
- 	printk("ide: failed opcode was: ");
--	if (!found)
--		printk("unknown\n");
-+	if (task == NULL)
-+		printk(KERN_CONT "unknown\n");
- 	else
--		printk("0x%02x\n", opcode);
-+		printk(KERN_CONT "0x%02x\n", task->tf.command);
+ static const struct hpt_info hpt371n __devinitdata = {
+@@ -587,7 +605,7 @@ static const struct hpt_info hpt371n __devinitdata = {
+ 	.chip_type	= HPT371N,
+ 	.udma_mask	= HPT371_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5,
+ 	.dpll_clk	= 77,
+-	.settings	= hpt37x_settings
++	.timings	= &hpt37x_timings
+ };
+ 
+ static int check_in_drive_list(ide_drive_t *drive, const char **list)
+@@ -675,94 +693,50 @@ static u32 get_speed_setting(u8 speed, struct hpt_info *info)
+ 	for (i = 0; i < ARRAY_SIZE(xfer_speeds) - 1; i++)
+ 		if (xfer_speeds[i] == speed)
+ 			break;
+-	/*
+-	 * NOTE: info->settings only points to the pointer
+-	 * to the list of the actual register values
+-	 */
+-	return (*info->settings)[i];
++
++	return info->timings->clock_table[info->clock][i];
  }
  
--static u8 ide_dump_ata_status(ide_drive_t *drive, const char *msg, u8 stat)
-+u64 ide_get_lba_addr(struct ide_taskfile *tf, int lba48)
+-static void hpt36x_set_mode(ide_drive_t *drive, const u8 speed)
++static void hpt3xx_set_mode(ide_drive_t *drive, const u8 speed)
  {
--	ide_hwif_t *hwif = HWIF(drive);
--	unsigned long flags;
--	u8 err = 0;
-+	u32 high, low;
+-	ide_hwif_t *hwif	= HWIF(drive);
+-	struct pci_dev  *dev	= hwif->pci_dev;
++	struct pci_dev  *dev	= HWIF(drive)->pci_dev;
+ 	struct hpt_info	*info	= pci_get_drvdata(dev);
+-	u8  itr_addr		= drive->dn ? 0x44 : 0x40;
++	struct hpt_timings *t	= info->timings;
++	u8  itr_addr		= 0x40 + (drive->dn * 4);
+ 	u32 old_itr		= 0;
+-	u32 itr_mask, new_itr;
+-
+-	itr_mask = speed < XFER_MW_DMA_0 ? 0x30070000 :
+-		  (speed < XFER_UDMA_0   ? 0xc0070000 : 0xc03800ff);
+-
+-	new_itr = get_speed_setting(speed, info);
++	u32 new_itr		= get_speed_setting(speed, info);
++	u32 itr_mask		= speed < XFER_MW_DMA_0 ? t->pio_mask :
++				 (speed < XFER_UDMA_0   ? t->dma_mask :
++							  t->ultra_mask);
  
--	local_irq_save(flags);
--	printk("%s: %s: status=0x%02x { ", drive->name, msg, stat);
--	if (stat & BUSY_STAT)
--		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 (lba48)
-+		high = (tf->hob_lbah << 16) | (tf->hob_lbam << 8) |
-+			tf->hob_lbal;
-+	else
-+		high = tf->device & 0xf;
-+	low  = (tf->lbah << 16) | (tf->lbam << 8) | tf->lbal;
-+
-+	return ((u64)high << 24) | low;
-+}
-+EXPORT_SYMBOL_GPL(ide_get_lba_addr);
-+
-+static void ide_dump_sector(ide_drive_t *drive)
-+{
-+	ide_task_t task;
-+	struct ide_taskfile *tf = &task.tf;
-+	int lba48 = (drive->addressing == 1) ? 1 : 0;
-+
-+	memset(&task, 0, sizeof(task));
-+	if (lba48)
-+		task.tf_flags = IDE_TFLAG_IN_LBA | IDE_TFLAG_IN_HOB_LBA |
-+				IDE_TFLAG_LBA48;
-+	else
-+		task.tf_flags = IDE_TFLAG_IN_LBA | IDE_TFLAG_IN_DEVICE;
-+
-+	ide_tf_read(drive, &task);
-+
-+	if (lba48 || (tf->device & ATA_LBA))
-+		printk(", LBAsect=%llu",
-+			(unsigned long long)ide_get_lba_addr(tf, lba48));
-+	else
-+		printk(", CHS=%d/%d/%d", (tf->lbah << 8) + tf->lbam,
-+					 tf->device & 0xf, tf->lbal);
-+}
-+
-+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 ");
-+	printk("}");
-+	if ((err & (BBD_ERR | ABRT_ERR)) == BBD_ERR ||
-+	    (err & (ECC_ERR|ID_ERR|MARK_ERR))) {
-+		ide_dump_sector(drive);
-+		if (HWGROUP(drive) && HWGROUP(drive)->rq)
-+			printk(", sector=%llu",
-+			       (unsigned long long)HWGROUP(drive)->rq->sector);
- 	}
-+	printk("\n");
-+}
-+
-+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);
- 	printk("}\n");
--	if ((stat & (BUSY_STAT|ERR_STAT)) == ERR_STAT) {
--		err = hwif->INB(IDE_ERROR_REG);
--		printk("%s: %s: error=0x%02x { ", drive->name, msg, err);
--		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 ");
--		printk("}");
--		if ((err & (BBD_ERR | ABRT_ERR)) == BBD_ERR ||
--		    (err & (ECC_ERR|ID_ERR|MARK_ERR))) {
--			if (drive->addressing == 1) {
--				__u64 sectors = 0;
--				u32 low = 0, high = 0;
--				hwif->OUTB(drive->ctl&~0x80, IDE_CONTROL_REG);
--				low = ide_read_24(drive);
--				hwif->OUTB(drive->ctl|0x80, IDE_CONTROL_REG);
--				high = ide_read_24(drive);
--				sectors = ((__u64)high << 24) | low;
--				printk(", LBAsect=%llu, high=%d, low=%d",
--				       (unsigned long long) sectors,
--				       high, low);
--			} else {
--				u8 cur = hwif->INB(IDE_SELECT_REG);
--				if (cur & 0x40) {	/* using LBA? */
--					printk(", LBAsect=%ld", (unsigned long)
--					 ((cur&0xf)<<24)
--					 |(hwif->INB(IDE_HCYL_REG)<<16)
--					 |(hwif->INB(IDE_LCYL_REG)<<8)
--					 | hwif->INB(IDE_SECTOR_REG));
--				} else {
--					printk(", CHS=%d/%d/%d",
--					 (hwif->INB(IDE_HCYL_REG)<<8) +
--					  hwif->INB(IDE_LCYL_REG),
--					  cur & 0xf,
--					  hwif->INB(IDE_SECTOR_REG));
--				}
--			}
--			if (HWGROUP(drive) && HWGROUP(drive)->rq)
--				printk(", sector=%llu",
--					(unsigned long long)HWGROUP(drive)->rq->sector);
--		}
--		printk("\n");
--	}
--	ide_dump_opcode(drive);
--	local_irq_restore(flags);
--	return err;
++	pci_read_config_dword(dev, itr_addr, &old_itr);
++	new_itr = (old_itr & ~itr_mask) | (new_itr & itr_mask);
+ 	/*
+ 	 * Disable on-chip PIO FIFO/buffer (and PIO MST mode as well)
+ 	 * to avoid problems handling I/O errors later
+ 	 */
+-	pci_read_config_dword(dev, itr_addr, &old_itr);
+-	new_itr  = (new_itr & ~itr_mask) | (old_itr & itr_mask);
+ 	new_itr &= ~0xc0000000;
+ 
+ 	pci_write_config_dword(dev, itr_addr, new_itr);
  }
  
- /**
-- *	ide_dump_atapi_status       -       print human readable atapi status
-+ *	ide_dump_status		-	translate ATA/ATAPI error
-  *	@drive: drive that status applies to
-  *	@msg: text message to print
-  *	@stat: status byte to decode
-  *
-  *	Error reporting, in human readable form (luxurious, but a memory hog).
-+ *	Combines the drive name, message and status byte to provide a
-+ *	user understandable explanation of the device error.
-  */
+-static void hpt37x_set_mode(ide_drive_t *drive, const u8 speed)
+-{
+-	ide_hwif_t *hwif	= HWIF(drive);
+-	struct pci_dev  *dev	= hwif->pci_dev;
+-	struct hpt_info	*info	= pci_get_drvdata(dev);
+-	u8  itr_addr		= 0x40 + (drive->dn * 4);
+-	u32 old_itr		= 0;
+-	u32 itr_mask, new_itr;
+-
+-	itr_mask = speed < XFER_MW_DMA_0 ? 0x303c0000 :
+-		  (speed < XFER_UDMA_0   ? 0xc03c0000 : 0xc1c001ff);
+-
+-	new_itr = get_speed_setting(speed, info);
+-
+-	pci_read_config_dword(dev, itr_addr, &old_itr);
+-	new_itr = (new_itr & ~itr_mask) | (old_itr & itr_mask);
+-	
+-	if (speed < XFER_MW_DMA_0)
+-		new_itr &= ~0x80000000; /* Disable on-chip PIO FIFO/buffer */
+-	pci_write_config_dword(dev, itr_addr, new_itr);
+-}
+-
+-static void hpt3xx_set_mode(ide_drive_t *drive, const u8 speed)
+-{
+-	ide_hwif_t *hwif	= HWIF(drive);
+-	struct hpt_info	*info	= pci_get_drvdata(hwif->pci_dev);
+-
+-	if (info->chip_type >= HPT370)
+-		hpt37x_set_mode(drive, speed);
+-	else	/* hpt368: hpt_minimum_revision(dev, 2) */
+-		hpt36x_set_mode(drive, speed);
+-}
+-
+ static void hpt3xx_set_pio_mode(ide_drive_t *drive, const u8 pio)
+ {
+ 	hpt3xx_set_mode(drive, XFER_PIO_0 + pio);
+ }
  
--static u8 ide_dump_atapi_status(ide_drive_t *drive, const char *msg, u8 stat)
-+u8 ide_dump_status(ide_drive_t *drive, const char *msg, u8 stat)
+-static int hpt3xx_quirkproc(ide_drive_t *drive)
++static void hpt3xx_quirkproc(ide_drive_t *drive)
  {
- 	unsigned long flags;
-+	u8 err = 0;
+ 	struct hd_driveid *id	= drive->id;
+ 	const  char **list	= quirk_drives;
  
--	atapi_status_t status;
--	atapi_error_t error;
--
--	status.all = stat;
--	error.all = 0;
- 	local_irq_save(flags);
- 	printk("%s: %s: status=0x%02x { ", drive->name, msg, stat);
--	if (status.b.bsy)
-+	if (stat & BUSY_STAT)
- 		printk("Busy ");
- 	else {
--		if (status.b.drdy)	printk("DriveReady ");
--		if (status.b.df)	printk("DeviceFault ");
--		if (status.b.dsc)	printk("SeekComplete ");
--		if (status.b.drq)	printk("DataRequest ");
--		if (status.b.corr)	printk("CorrectedError ");
--		if (status.b.idx)	printk("Index ");
--		if (status.b.check)	printk("Error ");
-+		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 ");
- 	}
- 	printk("}\n");
--	if (status.b.check && !status.b.bsy) {
--		error.all = HWIF(drive)->INB(IDE_ERROR_REG);
--		printk("%s: %s: error=0x%02x { ", drive->name, msg, error.all);
--		if (error.b.ili)	printk("IllegalLengthIndication ");
--		if (error.b.eom)	printk("EndOfMedia ");
--		if (error.b.abrt)	printk("AbortedCommand ");
--		if (error.b.mcr)	printk("MediaChangeRequested ");
--		if (error.b.sense_key)	printk("LastFailedSense=0x%02x ",
--						error.b.sense_key);
--		printk("}\n");
-+	if ((stat & (BUSY_STAT|ERR_STAT)) == ERR_STAT) {
-+		err = drive->hwif->INB(IDE_ERROR_REG);
-+		printk("%s: %s: error=0x%02x ", drive->name, msg, err);
-+		if (drive->media == ide_disk)
-+			ide_dump_ata_error(drive, err);
-+		else
-+			ide_dump_atapi_error(drive, err);
- 	}
- 	ide_dump_opcode(drive);
- 	local_irq_restore(flags);
--	return error.all;
+ 	while (*list)
+-		if (strstr(id->model, *list++))
+-			return 1;
+-	return 0;
 -}
 -
--/**
-- *	ide_dump_status		-	translate ATA/ATAPI error
-- *	@drive: drive the error occured on
-- *	@msg: information string
-- *	@stat: status byte
-- *
-- *	Error reporting, in human readable form (luxurious, but a memory hog).
-- *	Combines the drive name, message and status byte to provide a
-- *	user understandable explanation of the device error.
-- */
--
--u8 ide_dump_status(ide_drive_t *drive, const char *msg, u8 stat)
+-static void hpt3xx_intrproc(ide_drive_t *drive)
 -{
--	if (drive->media == ide_disk)
--		return ide_dump_ata_status(drive, msg, stat);
--	return ide_dump_atapi_status(drive, msg, stat);
-+	return err;
+-	if (drive->quirk_list)
+-		return;
++		if (strstr(id->model, *list++)) {
++			drive->quirk_list = 1;
++			return;
++		}
+ 
+-	/* drives in the quirk_list may not like intr setups/cleanups */
+-	outb(drive->ctl | 2, IDE_CONTROL_REG);
++	drive->quirk_list = 0;
  }
  
- EXPORT_SYMBOL(ide_dump_status);
-diff --git a/drivers/ide/ide-pnp.c b/drivers/ide/ide-pnp.c
-index e245521..cbbb0f7 100644
---- a/drivers/ide/ide-pnp.c
-+++ b/drivers/ide/ide-pnp.c
-@@ -31,7 +31,6 @@ static int idepnp_probe(struct pnp_dev * dev, const struct pnp_device_id *dev_id
+ static void hpt3xx_maskproc(ide_drive_t *drive, int mask)
+@@ -914,32 +888,33 @@ static int hpt374_ide_dma_end(ide_drive_t *drive)
+ 
+ static void hpt3xxn_set_clock(ide_hwif_t *hwif, u8 mode)
  {
- 	hw_regs_t hw;
- 	ide_hwif_t *hwif;
--	int index;
+-	u8 scr2 = inb(hwif->dma_master + 0x7b);
++	unsigned long base = hwif->extra_base;
++	u8 scr2 = inb(base + 0x6b);
  
- 	if (!(pnp_port_valid(dev, 0) && pnp_port_valid(dev, 1) && pnp_irq_valid(dev, 0)))
- 		return -1;
-@@ -41,11 +40,19 @@ static int idepnp_probe(struct pnp_dev * dev, const struct pnp_device_id *dev_id
- 				pnp_port_start(dev, 1));
- 	hw.irq = pnp_irq(dev, 0);
+ 	if ((scr2 & 0x7f) == mode)
+ 		return;
  
--	index = ide_register_hw(&hw, NULL, 1, &hwif);
-+	hwif = ide_find_port(hw.io_ports[IDE_DATA_OFFSET]);
-+	if (hwif) {
-+		u8 index = hwif->index;
-+		u8 idx[4] = { index, 0xff, 0xff, 0xff };
-+
-+		ide_init_port_data(hwif, index);
-+		ide_init_port_hw(hwif, &hw);
+ 	/* Tristate the bus */
+-	outb(0x80, hwif->dma_master + 0x73);
+-	outb(0x80, hwif->dma_master + 0x77);
++	outb(0x80, base + 0x63);
++	outb(0x80, base + 0x67);
  
--	if (index != -1) {
--	    	printk(KERN_INFO "ide%d: generic PnP IDE interface\n", index);
-+		printk(KERN_INFO "ide%d: generic PnP IDE interface\n", index);
- 		pnp_set_drvdata(dev,hwif);
-+
-+		ide_device_add(idx);
-+
- 		return 0;
- 	}
+ 	/* Switch clock and reset channels */
+-	outb(mode, hwif->dma_master + 0x7b);
+-	outb(0xc0, hwif->dma_master + 0x79);
++	outb(mode, base + 0x6b);
++	outb(0xc0, base + 0x69);
  
-@@ -68,12 +75,15 @@ static struct pnp_driver idepnp_driver = {
- 	.remove		= idepnp_remove,
- };
+ 	/*
+ 	 * Reset the state machines.
+ 	 * NOTE: avoid accidentally enabling the disabled channels.
+ 	 */
+-	outb(inb(hwif->dma_master + 0x70) | 0x32, hwif->dma_master + 0x70);
+-	outb(inb(hwif->dma_master + 0x74) | 0x32, hwif->dma_master + 0x74);
++	outb(inb(base + 0x60) | 0x32, base + 0x60);
++	outb(inb(base + 0x64) | 0x32, base + 0x64);
  
--void __init pnpide_init(void)
-+static int __init pnpide_init(void)
- {
--	pnp_register_driver(&idepnp_driver);
-+	return pnp_register_driver(&idepnp_driver);
- }
+ 	/* Complete reset */
+-	outb(0x00, hwif->dma_master + 0x79);
++	outb(0x00, base + 0x69);
  
--void __exit pnpide_exit(void)
-+static void __exit pnpide_exit(void)
- {
- 	pnp_unregister_driver(&idepnp_driver);
+ 	/* Reconnect channels to bus */
+-	outb(0x00, hwif->dma_master + 0x73);
+-	outb(0x00, hwif->dma_master + 0x77);
++	outb(0x00, base + 0x63);
++	outb(0x00, base + 0x67);
  }
-+
-+module_init(pnpide_init);
-+module_exit(pnpide_exit);
-diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c
-index 2994523..edf650b 100644
---- a/drivers/ide/ide-probe.c
-+++ b/drivers/ide/ide-probe.c
-@@ -95,10 +95,10 @@ static void ide_disk_init_mult_count(ide_drive_t *drive)
- #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 : INITIAL_MULT_COUNT;
-+		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 = INITIAL_MULT_COUNT;
-+		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))
-@@ -234,7 +234,7 @@ static inline void do_identify (ide_drive_t *drive, u8 cmd)
  
- 	drive->media = ide_disk;
- 	printk("%s DISK drive\n", (id->config == 0x848a) ? "CFA" : "ATA" );
--	QUIRK_LIST(drive);
-+
- 	return;
- 
- err_misc:
-@@ -350,22 +350,19 @@ static int try_to_identify (ide_drive_t *drive, u8 cmd)
- 	 * the irq handler isn't expecting.
+ /**
+@@ -1210,7 +1185,7 @@ static unsigned int __devinit init_chipset_hpt366(struct pci_dev *dev, const cha
+ 	 * We also  don't like using  the DPLL because this causes glitches
+ 	 * on PRST-/SRST- when the state engine gets reset...
  	 */
- 	if (IDE_CONTROL_REG) {
--		u8 ctl = drive->ctl | 2;
- 		if (!hwif->irq) {
- 			autoprobe = 1;
- 			cookie = probe_irq_on();
--			/* enable device irq */
--			ctl &= ~2;
+-	if (chip_type >= HPT374 || info->settings[clock] == NULL) {
++	if (chip_type >= HPT374 || info->timings->clock_table[clock] == NULL) {
+ 		u16 f_low, delta = pci_clk < 50 ? 2 : 4;
+ 		int adjust;
+ 
+@@ -1226,7 +1201,7 @@ static unsigned int __devinit init_chipset_hpt366(struct pci_dev *dev, const cha
+ 			clock = ATA_CLOCK_50MHZ;
  		}
--		hwif->OUTB(ctl, IDE_CONTROL_REG);
-+		ide_set_irq(drive, autoprobe);
+ 
+-		if (info->settings[clock] == NULL) {
++		if (info->timings->clock_table[clock] == NULL) {
+ 			printk(KERN_ERR "%s: unknown bus timing!\n", name);
+ 			kfree(info);
+ 			return -EIO;
+@@ -1267,15 +1242,10 @@ static unsigned int __devinit init_chipset_hpt366(struct pci_dev *dev, const cha
+ 		printk("%s: using %d MHz PCI clock\n", name, pci_clk);
  	}
  
- 	retval = actual_try_to_identify(drive, cmd);
+-	/*
+-	 * Advance the table pointer to a slot which points to the list
+-	 * of the register values settings matching the clock being used.
+-	 */
+-	info->settings += clock;
+-
+ 	/* Store the clock frequencies. */
+ 	info->dpll_clk	= dpll_clk;
+ 	info->pci_clk	= pci_clk;
++	info->clock	= clock;
  
- 	if (autoprobe) {
- 		int irq;
--		/* mask device irq */
--		hwif->OUTB(drive->ctl|2, IDE_CONTROL_REG);
+ 	/* Point to this chip's own instance of the hpt_info structure. */
+ 	pci_set_drvdata(dev, info);
+@@ -1320,8 +1290,8 @@ static void __devinit init_hwif_hpt366(ide_hwif_t *hwif)
+ 
+ 	hwif->set_pio_mode	= &hpt3xx_set_pio_mode;
+ 	hwif->set_dma_mode	= &hpt3xx_set_mode;
 +
-+		ide_set_irq(drive, 0);
- 		/* clear drive IRQ */
- 		(void) hwif->INB(IDE_STATUS_REG);
- 		udelay(5);
-@@ -385,6 +382,20 @@ static int try_to_identify (ide_drive_t *drive, u8 cmd)
- 	return retval;
+ 	hwif->quirkproc		= &hpt3xx_quirkproc;
+-	hwif->intrproc		= &hpt3xx_intrproc;
+ 	hwif->maskproc		= &hpt3xx_maskproc;
+ 	hwif->busproc		= &hpt3xx_busproc;
+ 
+@@ -1494,6 +1464,11 @@ static int __devinit hpt36x_init(struct pci_dev *dev, struct pci_dev *dev2)
+ 	return 0;
  }
  
-+static int ide_busy_sleep(ide_hwif_t *hwif)
-+{
-+	unsigned long timeout = jiffies + WAIT_WORSTCASE;
-+	u8 stat;
-+
-+	do {
-+		msleep(50);
-+		stat = hwif->INB(hwif->io_ports[IDE_STATUS_OFFSET]);
-+		if ((stat & BUSY_STAT) == 0)
-+			return 0;
-+	} while (time_before(jiffies, timeout));
++#define IDE_HFLAGS_HPT3XX \
++	(IDE_HFLAG_NO_ATAPI_DMA | \
++	 IDE_HFLAG_ABUSE_SET_DMA_MODE | \
++	 IDE_HFLAG_OFF_BOARD)
 +
-+	return 1;
-+}
- 
- /**
-  *	do_probe		-	probe an IDE device
-@@ -453,7 +464,6 @@ static int do_probe (ide_drive_t *drive, u8 cmd)
- 		if ((rc == 1 && cmd == WIN_PIDENTIFY) &&
- 			((drive->autotune == IDE_TUNE_DEFAULT) ||
- 			(drive->autotune == IDE_TUNE_AUTO))) {
--			unsigned long timeout;
- 			printk("%s: no response (status = 0x%02x), "
- 				"resetting drive\n", drive->name,
- 				hwif->INB(IDE_STATUS_REG));
-@@ -461,10 +471,7 @@ static int do_probe (ide_drive_t *drive, u8 cmd)
- 			hwif->OUTB(drive->select.all, IDE_SELECT_REG);
- 			msleep(50);
- 			hwif->OUTB(WIN_SRST, IDE_COMMAND_REG);
--			timeout = jiffies;
--			while (((hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) &&
--			       time_before(jiffies, timeout + WAIT_WORSTCASE))
--				msleep(50);
-+			(void)ide_busy_sleep(hwif);
- 			rc = try_to_identify(drive, cmd);
- 		}
- 		if (rc == 1)
-@@ -492,20 +499,16 @@ static int do_probe (ide_drive_t *drive, u8 cmd)
- static void enable_nest (ide_drive_t *drive)
- {
- 	ide_hwif_t *hwif = HWIF(drive);
--	unsigned long timeout;
+ static const struct ide_port_info hpt366_chipsets[] __devinitdata = {
+ 	{	/* 0 */
+ 		.name		= "HPT36x",
+@@ -1508,9 +1483,7 @@ static const struct ide_port_info hpt366_chipsets[] __devinitdata = {
+ 		 */
+ 		.enablebits	= {{0x50,0x10,0x10}, {0x54,0x04,0x04}},
+ 		.extra		= 240,
+-		.host_flags	= IDE_HFLAG_SINGLE |
+-				  IDE_HFLAG_NO_ATAPI_DMA |
+-				  IDE_HFLAG_OFF_BOARD,
++		.host_flags	= IDE_HFLAGS_HPT3XX | IDE_HFLAG_SINGLE,
+ 		.pio_mask	= ATA_PIO4,
+ 		.mwdma_mask	= ATA_MWDMA2,
+ 	},{	/* 1 */
+@@ -1520,7 +1493,7 @@ static const struct ide_port_info hpt366_chipsets[] __devinitdata = {
+ 		.init_dma	= init_dma_hpt366,
+ 		.enablebits	= {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
+ 		.extra		= 240,
+-		.host_flags	= IDE_HFLAG_NO_ATAPI_DMA | IDE_HFLAG_OFF_BOARD,
++		.host_flags	= IDE_HFLAGS_HPT3XX,
+ 		.pio_mask	= ATA_PIO4,
+ 		.mwdma_mask	= ATA_MWDMA2,
+ 	},{	/* 2 */
+@@ -1530,7 +1503,7 @@ static const struct ide_port_info hpt366_chipsets[] __devinitdata = {
+ 		.init_dma	= init_dma_hpt366,
+ 		.enablebits	= {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
+ 		.extra		= 240,
+-		.host_flags	= IDE_HFLAG_NO_ATAPI_DMA | IDE_HFLAG_OFF_BOARD,
++		.host_flags	= IDE_HFLAGS_HPT3XX,
+ 		.pio_mask	= ATA_PIO4,
+ 		.mwdma_mask	= ATA_MWDMA2,
+ 	},{	/* 3 */
+@@ -1540,7 +1513,7 @@ static const struct ide_port_info hpt366_chipsets[] __devinitdata = {
+ 		.init_dma	= init_dma_hpt366,
+ 		.enablebits	= {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
+ 		.extra		= 240,
+-		.host_flags	= IDE_HFLAG_NO_ATAPI_DMA | IDE_HFLAG_OFF_BOARD,
++		.host_flags	= IDE_HFLAGS_HPT3XX,
+ 		.pio_mask	= ATA_PIO4,
+ 		.mwdma_mask	= ATA_MWDMA2,
+ 	},{	/* 4 */
+@@ -1551,7 +1524,7 @@ static const struct ide_port_info hpt366_chipsets[] __devinitdata = {
+ 		.enablebits	= {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
+ 		.udma_mask	= ATA_UDMA5,
+ 		.extra		= 240,
+-		.host_flags	= IDE_HFLAG_NO_ATAPI_DMA | IDE_HFLAG_OFF_BOARD,
++		.host_flags	= IDE_HFLAGS_HPT3XX,
+ 		.pio_mask	= ATA_PIO4,
+ 		.mwdma_mask	= ATA_MWDMA2,
+ 	},{	/* 5 */
+@@ -1561,7 +1534,7 @@ static const struct ide_port_info hpt366_chipsets[] __devinitdata = {
+ 		.init_dma	= init_dma_hpt366,
+ 		.enablebits	= {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
+ 		.extra		= 240,
+-		.host_flags	= IDE_HFLAG_NO_ATAPI_DMA | IDE_HFLAG_OFF_BOARD,
++		.host_flags	= IDE_HFLAGS_HPT3XX,
+ 		.pio_mask	= ATA_PIO4,
+ 		.mwdma_mask	= ATA_MWDMA2,
+ 	}
+diff --git a/drivers/ide/pci/it8213.c b/drivers/ide/pci/it8213.c
+index 90b52ed..2a0f45c 100644
+--- a/drivers/ide/pci/it8213.c
++++ b/drivers/ide/pci/it8213.c
+@@ -101,24 +101,11 @@ static void it8213_set_dma_mode(ide_drive_t *drive, const u8 speed)
+ 	pci_read_config_byte(dev, 0x54, &reg54);
+ 	pci_read_config_byte(dev, 0x55, &reg55);
  
- 	printk("%s: enabling %s -- ", hwif->name, drive->id->model);
- 	SELECT_DRIVE(drive);
- 	msleep(50);
- 	hwif->OUTB(EXABYTE_ENABLE_NEST, IDE_COMMAND_REG);
--	timeout = jiffies + WAIT_WORSTCASE;
--	do {
--		if (time_after(jiffies, timeout)) {
--			printk("failed (timeout)\n");
+-	switch(speed) {
+-		case XFER_UDMA_6:
+-		case XFER_UDMA_4:
+-		case XFER_UDMA_2:	u_speed = 2 << (drive->dn * 4); break;
+-		case XFER_UDMA_5:
+-		case XFER_UDMA_3:
+-		case XFER_UDMA_1:	u_speed = 1 << (drive->dn * 4); break;
+-		case XFER_UDMA_0:	u_speed = 0 << (drive->dn * 4); break;
+-			break;
+-		case XFER_MW_DMA_2:
+-		case XFER_MW_DMA_1:
+-		case XFER_SW_DMA_2:
+-			break;
+-		default:
 -			return;
--		}
--		msleep(50);
--	} while ((hwif->INB(IDE_STATUS_REG)) & BUSY_STAT);
+-	}
+-
+ 	if (speed >= XFER_UDMA_0) {
++		u8 udma = speed - XFER_UDMA_0;
 +
-+	if (ide_busy_sleep(hwif)) {
-+		printk(KERN_CONT "failed (timeout)\n");
-+		return;
-+	}
- 
- 	msleep(50);
- 
-@@ -653,8 +656,7 @@ static int wait_hwif_ready(ide_hwif_t *hwif)
- 		/* Ignore disks that we will not probe for later. */
- 		if (!drive->noprobe || drive->present) {
- 			SELECT_DRIVE(drive);
--			if (IDE_CONTROL_REG)
--				hwif->OUTB(drive->ctl, IDE_CONTROL_REG);
-+			ide_set_irq(drive, 1);
- 			mdelay(2);
- 			rc = ide_wait_not_busy(hwif, 35000);
- 			if (rc)
-@@ -673,19 +675,18 @@ out:
++		u_speed = min_t(u8, 2 - (udma & 1), udma) << (drive->dn * 4);
++
+ 		if (!(reg48 & u_flag))
+ 			pci_write_config_byte(dev, 0x48, reg48 | u_flag);
+ 		if (speed >= XFER_UDMA_5) {
+diff --git a/drivers/ide/pci/it821x.c b/drivers/ide/pci/it821x.c
+index 99b7d76..e610a53 100644
+--- a/drivers/ide/pci/it821x.c
++++ b/drivers/ide/pci/it821x.c
+@@ -431,33 +431,29 @@ static u8 __devinit ata66_it821x(ide_hwif_t *hwif)
+ }
  
  /**
-  *	ide_undecoded_slave	-	look for bad CF adapters
+- *	it821x_fixup	-	post init callback
 - *	@hwif: interface
-+ *	@drive1: drive
++ *	it821x_quirkproc	-	post init callback
++ *	@drive: drive
   *
-  *	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.
+- *	This callback is run after the drives have been probed but
++ *	This callback is run after the drive has been probed but
+  *	before anything gets attached. It allows drivers to do any
+  *	final tuning that is needed, or fixups to work around bugs.
   */
  
--void ide_undecoded_slave(ide_hwif_t *hwif)
-+void ide_undecoded_slave(ide_drive_t *drive1)
+-static void __devinit it821x_fixups(ide_hwif_t *hwif)
++static void __devinit it821x_quirkproc(ide_drive_t *drive)
  {
--	ide_drive_t *drive0 = &hwif->drives[0];
--	ide_drive_t *drive1 = &hwif->drives[1];
-+	ide_drive_t *drive0 = &drive1->hwif->drives[0];
+-	struct it821x_dev *itdev = ide_get_hwifdata(hwif);
+-	int i;
++	struct it821x_dev *itdev = ide_get_hwifdata(drive->hwif);
++	struct hd_driveid *id = drive->id;
++	u16 *idbits = (u16 *)drive->id;
  
--	if (drive0->present == 0 || drive1->present == 0)
-+	if ((drive1->dn & 1) == 0 || drive0->present == 0)
- 		return;
+-	if(!itdev->smart) {
++	if (!itdev->smart) {
+ 		/*
+ 		 *	If we are in pass through mode then not much
+ 		 *	needs to be done, but we do bother to clear the
+ 		 *	IRQ mask as we may well be in PIO (eg rev 0x10)
+ 		 *	for now and we know unmasking is safe on this chipset.
+ 		 */
+-		for (i = 0; i < 2; i++) {
+-			ide_drive_t *drive = &hwif->drives[i];
+-			if(drive->present)
+-				drive->unmask = 1;
+-		}
+-		return;
+-	}
++		drive->unmask = 1;
++	} else {
+ 	/*
+ 	 *	Perform fixups on smart mode. We need to "lose" some
+ 	 *	capabilities the firmware lacks but does not filter, and
+@@ -465,16 +461,6 @@ static void __devinit it821x_fixups(ide_hwif_t *hwif)
+ 	 *	in RAID mode.
+ 	 */
  
- 	/* If the models don't match they are not the same product */
-@@ -788,18 +789,11 @@ static void probe_hwif(ide_hwif_t *hwif)
- 		}
- 	}
- 	if (hwif->io_ports[IDE_CONTROL_OFFSET] && hwif->reset) {
--		unsigned long timeout = jiffies + WAIT_WORSTCASE;
--		u8 stat;
+-	for(i = 0; i < 2; i++) {
+-		ide_drive_t *drive = &hwif->drives[i];
+-		struct hd_driveid *id;
+-		u16 *idbits;
 -
- 		printk(KERN_WARNING "%s: reset\n", hwif->name);
- 		hwif->OUTB(12, hwif->io_ports[IDE_CONTROL_OFFSET]);
- 		udelay(10);
- 		hwif->OUTB(8, hwif->io_ports[IDE_CONTROL_OFFSET]);
--		do {
--			msleep(50);
--			stat = hwif->INB(hwif->io_ports[IDE_STATUS_OFFSET]);
--		} while ((stat & BUSY_STAT) && time_after(timeout, jiffies));
+-		if(!drive->present)
+-			continue;
+-		id = drive->id;
+-		idbits = (u16 *)drive->id;
 -
-+		(void)ide_busy_sleep(hwif);
- 	}
- 	local_irq_restore(flags);
- 	/*
-@@ -814,8 +808,12 @@ static void probe_hwif(ide_hwif_t *hwif)
- 		return;
- 	}
+ 		/* Check for RAID v native */
+ 		if(strstr(id->model, "Integrated Technology Express")) {
+ 			/* In raid mode the ident block is slightly buggy
+@@ -537,6 +523,8 @@ static void __devinit init_hwif_it821x(ide_hwif_t *hwif)
+ 	struct it821x_dev *idev = kzalloc(sizeof(struct it821x_dev), GFP_KERNEL);
+ 	u8 conf;
  
--	if (hwif->fixup)
--		hwif->fixup(hwif);
-+	for (unit = 0; unit < MAX_DRIVES; unit++) {
-+		ide_drive_t *drive = &hwif->drives[unit];
++	hwif->quirkproc = &it821x_quirkproc;
 +
-+		if (drive->present && hwif->quirkproc)
-+			hwif->quirkproc(drive);
-+	}
- 
- 	for (unit = 0; unit < MAX_DRIVES; ++unit) {
- 		ide_drive_t *drive = &hwif->drives[unit];
-@@ -830,16 +828,8 @@ static void probe_hwif(ide_hwif_t *hwif)
- 
- 			drive->nice1 = 1;
- 
--			if (hwif->ide_dma_on) {
--				/*
--				 * Force DMAing for the beginning of the check.
--				 * Some chipsets appear to do interesting
--				 * things, if not checked and cleared.
--				 *   PARANOIA!!!
--				 */
--				hwif->dma_off_quietly(drive);
-+			if (hwif->dma_host_set)
- 				ide_set_dma(drive);
--			}
- 		}
- 	}
- 
-@@ -853,25 +843,6 @@ static void probe_hwif(ide_hwif_t *hwif)
+ 	if (idev == NULL) {
+ 		printk(KERN_ERR "it821x: out of memory, falling back to legacy behaviour.\n");
+ 		return;
+@@ -633,7 +621,6 @@ static unsigned int __devinit init_chipset_it821x(struct pci_dev *dev, const cha
+ 		.name		= name_str,		\
+ 		.init_chipset	= init_chipset_it821x,	\
+ 		.init_hwif	= init_hwif_it821x,	\
+-		.fixup	 	= it821x_fixups,	\
+ 		.host_flags	= IDE_HFLAG_BOOTABLE,	\
+ 		.pio_mask	= ATA_PIO4,		\
  	}
- }
+diff --git a/drivers/ide/pci/pdc202xx_new.c b/drivers/ide/pci/pdc202xx_new.c
+index 2b4f44e..89d2363 100644
+--- a/drivers/ide/pci/pdc202xx_new.c
++++ b/drivers/ide/pci/pdc202xx_new.c
+@@ -146,7 +146,7 @@ static struct udma_timing {
+ 	{ 0x1a, 0x01, 0xcb },	/* UDMA mode 6 */
+ };
  
--static int hwif_init(ide_hwif_t *hwif);
--static void hwif_register_devices(ide_hwif_t *hwif);
--
--static int probe_hwif_init(ide_hwif_t *hwif)
--{
--	probe_hwif(hwif);
--
--	if (!hwif_init(hwif)) {
--		printk(KERN_INFO "%s: failed to initialize IDE interface\n",
--				 hwif->name);
--		return -1;
--	}
--
--	if (hwif->present)
--		hwif_register_devices(hwif);
--
--	return 0;
--}
--
- #if MAX_HWIFS > 1
- /*
-  * save_match() is used to simplify logic in init_irq() below.
-@@ -968,11 +939,6 @@ static int ide_init_queue(ide_drive_t *drive)
-  * Much of the code is for correctly detecting/handling irq sharing
-  * and irq serialization situations.  This is somewhat complex because
-  * it handles static as well as dynamic (PCMCIA) IDE interfaces.
-- *
-- * The IRQF_DISABLED in sa_flags means ide_intr() is always entered with
-- * interrupts completely disabled.  This can be bad for interrupt latency,
-- * but anything else has led to problems on some machines.  We re-enable
-- * interrupts as much as we can safely do in most places.
-  */
- static int init_irq (ide_hwif_t *hwif)
+-static void pdcnew_set_mode(ide_drive_t *drive, const u8 speed)
++static void pdcnew_set_dma_mode(ide_drive_t *drive, const u8 speed)
  {
-@@ -1055,17 +1021,13 @@ static int init_irq (ide_hwif_t *hwif)
- 	 * Allocate the irq, if not already obtained for another hwif
- 	 */
- 	if (!match || match->irq != hwif->irq) {
--		int sa = IRQF_DISABLED;
-+		int sa = 0;
- #if defined(__mc68000__) || defined(CONFIG_APUS)
- 		sa = IRQF_SHARED;
- #endif /* __mc68000__ || CONFIG_APUS */
+ 	ide_hwif_t *hwif	= HWIF(drive);
+ 	u8 adj			= (drive->dn & 1) ? 0x08 : 0x00;
+@@ -162,45 +162,18 @@ static void pdcnew_set_mode(ide_drive_t *drive, const u8 speed)
+ 	if (max_dma_rate(hwif->pci_dev) == 4) {
+ 		u8 mode = speed & 0x07;
  
--		if (IDE_CHIPSET_IS_PCI(hwif->chipset)) {
-+		if (IDE_CHIPSET_IS_PCI(hwif->chipset))
- 			sa = IRQF_SHARED;
--#ifndef CONFIG_IDEPCI_SHARE_IRQ
--			sa |= IRQF_DISABLED;
--#endif /* CONFIG_IDEPCI_SHARE_IRQ */
--		}
+-		switch (speed) {
+-			case XFER_UDMA_6:
+-			case XFER_UDMA_5:
+-			case XFER_UDMA_4:
+-			case XFER_UDMA_3:
+-			case XFER_UDMA_2:
+-			case XFER_UDMA_1:
+-			case XFER_UDMA_0:
+-				set_indexed_reg(hwif, 0x10 + adj,
+-						udma_timings[mode].reg10);
+-				set_indexed_reg(hwif, 0x11 + adj,
+-						udma_timings[mode].reg11);
+-				set_indexed_reg(hwif, 0x12 + adj,
+-						udma_timings[mode].reg12);
+-				break;
+-
+-			case XFER_MW_DMA_2:
+-			case XFER_MW_DMA_1:
+-			case XFER_MW_DMA_0:
+-				set_indexed_reg(hwif, 0x0e + adj,
+-						mwdma_timings[mode].reg0e);
+-				set_indexed_reg(hwif, 0x0f + adj,
+-						mwdma_timings[mode].reg0f);
+-				break;
+-			case XFER_PIO_4:
+-			case XFER_PIO_3:
+-			case XFER_PIO_2:
+-			case XFER_PIO_1:
+-			case XFER_PIO_0:
+-				set_indexed_reg(hwif, 0x0c + adj,
+-						pio_timings[mode].reg0c);
+-				set_indexed_reg(hwif, 0x0d + adj,
+-						pio_timings[mode].reg0d);
+-				set_indexed_reg(hwif, 0x13 + adj,
+-						pio_timings[mode].reg13);
+-				break;
+-			default:
+-				printk(KERN_ERR "pdc202xx_new: "
+-				       "Unknown speed %d ignored\n", speed);
++		if (speed >= XFER_UDMA_0) {
++			set_indexed_reg(hwif, 0x10 + adj,
++					udma_timings[mode].reg10);
++			set_indexed_reg(hwif, 0x11 + adj,
++					udma_timings[mode].reg11);
++			set_indexed_reg(hwif, 0x12 + adj,
++					udma_timings[mode].reg12);
++		} else {
++			set_indexed_reg(hwif, 0x0e + adj,
++					mwdma_timings[mode].reg0e);
++			set_indexed_reg(hwif, 0x0f + adj,
++					mwdma_timings[mode].reg0f);
+ 		}
+ 	} else if (speed == XFER_UDMA_2) {
+ 		/* Set tHOLD bit to 0 if using UDMA mode 2 */
+@@ -212,7 +185,14 @@ static void pdcnew_set_mode(ide_drive_t *drive, const u8 speed)
  
- 		if (hwif->io_ports[IDE_CONTROL_OFFSET])
- 			/* clear nIEN */
-@@ -1173,7 +1135,7 @@ static struct kobject *exact_match(dev_t dev, int *part, void *data)
+ static void pdcnew_set_pio_mode(ide_drive_t *drive, const u8 pio)
  {
- 	struct gendisk *p = data;
- 	*part &= (1 << PARTN_BITS) - 1;
--	return &p->kobj;
-+	return &p->dev.kobj;
+-	pdcnew_set_mode(drive, XFER_PIO_0 + pio);
++	ide_hwif_t *hwif = drive->hwif;
++	u8 adj = (drive->dn & 1) ? 0x08 : 0x00;
++
++	if (max_dma_rate(hwif->pci_dev) == 4) {
++		set_indexed_reg(hwif, 0x0c + adj, pio_timings[pio].reg0c);
++		set_indexed_reg(hwif, 0x0d + adj, pio_timings[pio].reg0d);
++		set_indexed_reg(hwif, 0x13 + adj, pio_timings[pio].reg13);
++	}
  }
  
- static int exact_lock(dev_t dev, void *data)
-@@ -1373,54 +1335,63 @@ static void hwif_register_devices(ide_hwif_t *hwif)
- 	}
+ static u8 pdcnew_cable_detect(ide_hwif_t *hwif)
+@@ -223,14 +203,17 @@ static u8 pdcnew_cable_detect(ide_hwif_t *hwif)
+ 		return ATA_CBL_PATA80;
  }
  
--int ideprobe_init (void)
-+int ide_device_add_all(u8 *idx)
+-static int pdcnew_quirkproc(ide_drive_t *drive)
++static void pdcnew_quirkproc(ide_drive_t *drive)
  {
--	unsigned int index;
--	int probe[MAX_HWIFS];
--
--	memset(probe, 0, MAX_HWIFS * sizeof(int));
--	for (index = 0; index < MAX_HWIFS; ++index)
--		probe[index] = !ide_hwifs[index].present;
--
--	for (index = 0; index < MAX_HWIFS; ++index)
--		if (probe[index])
--			probe_hwif(&ide_hwifs[index]);
--	for (index = 0; index < MAX_HWIFS; ++index)
--		if (probe[index])
--			hwif_init(&ide_hwifs[index]);
--	for (index = 0; index < MAX_HWIFS; ++index) {
--		if (probe[index]) {
--			ide_hwif_t *hwif = &ide_hwifs[index];
--			if (!hwif->present)
--				continue;
--			if (hwif->chipset == ide_unknown || hwif->chipset == ide_forced)
--				hwif->chipset = ide_generic;
--			hwif_register_devices(hwif);
-+	ide_hwif_t *hwif;
-+	int i, rc = 0;
-+
-+	for (i = 0; i < MAX_HWIFS; i++) {
-+		if (idx[i] == 0xff)
-+			continue;
-+
-+		probe_hwif(&ide_hwifs[idx[i]]);
-+	}
-+
-+	for (i = 0; i < MAX_HWIFS; i++) {
-+		if (idx[i] == 0xff)
-+			continue;
-+
-+		hwif = &ide_hwifs[idx[i]];
-+
-+		if (hwif_init(hwif) == 0) {
-+			printk(KERN_INFO "%s: failed to initialize IDE "
-+					 "interface\n", hwif->name);
-+			rc = -1;
-+			continue;
- 		}
- 	}
--	for (index = 0; index < MAX_HWIFS; ++index)
--		if (probe[index])
--			ide_proc_register_port(&ide_hwifs[index]);
+ 	const char **list, *model = drive->id->model;
+ 
+ 	for (list = pdc_quirk_drives; *list != NULL; list++)
+-		if (strstr(model, *list) != NULL)
+-			return 2;
 -	return 0;
--}
++		if (strstr(model, *list) != NULL) {
++			drive->quirk_list = 2;
++			return;
++		}
++
++	drive->quirk_list = 0;
+ }
  
--EXPORT_SYMBOL_GPL(ideprobe_init);
-+	for (i = 0; i < MAX_HWIFS; i++) {
-+		if (idx[i] == 0xff)
-+			continue;
+ static void pdcnew_reset(ide_drive_t *drive)
+@@ -466,7 +449,7 @@ static unsigned int __devinit init_chipset_pdcnew(struct pci_dev *dev, const cha
+ static void __devinit init_hwif_pdc202new(ide_hwif_t *hwif)
+ {
+ 	hwif->set_pio_mode = &pdcnew_set_pio_mode;
+-	hwif->set_dma_mode = &pdcnew_set_mode;
++	hwif->set_dma_mode = &pdcnew_set_dma_mode;
  
--int ide_device_add(u8 idx[4])
--{
--	int i, rc = 0;
-+		hwif = &ide_hwifs[idx[i]];
+ 	hwif->quirkproc = &pdcnew_quirkproc;
+ 	hwif->resetproc = &pdcnew_reset;
+diff --git a/drivers/ide/pci/pdc202xx_old.c b/drivers/ide/pci/pdc202xx_old.c
+index e09742e..3a1e081 100644
+--- a/drivers/ide/pci/pdc202xx_old.c
++++ b/drivers/ide/pci/pdc202xx_old.c
+@@ -162,7 +162,7 @@ static u8 pdc202xx_old_cable_detect (ide_hwif_t *hwif)
+  */
+ static void pdc_old_enable_66MHz_clock(ide_hwif_t *hwif)
+ {
+-	unsigned long clock_reg = hwif->dma_master + 0x11;
++	unsigned long clock_reg = hwif->extra_base + 0x01;
+ 	u8 clock = inb(clock_reg);
  
--	for (i = 0; i < 4; i++) {
--		if (idx[i] != 0xff)
--			rc |= probe_hwif_init(&ide_hwifs[idx[i]]);
-+		if (hwif->present) {
-+			if (hwif->chipset == ide_unknown ||
-+			    hwif->chipset == ide_forced)
-+				hwif->chipset = ide_generic;
-+			hwif_register_devices(hwif);
-+		}
- 	}
+ 	outb(clock | (hwif->channel ? 0x08 : 0x02), clock_reg);
+@@ -170,20 +170,23 @@ static void pdc_old_enable_66MHz_clock(ide_hwif_t *hwif)
  
--	for (i = 0; i < 4; i++) {
-+	for (i = 0; i < MAX_HWIFS; i++) {
- 		if (idx[i] != 0xff)
- 			ide_proc_register_port(&ide_hwifs[idx[i]]);
- 	}
+ static void pdc_old_disable_66MHz_clock(ide_hwif_t *hwif)
+ {
+-	unsigned long clock_reg = hwif->dma_master + 0x11;
++	unsigned long clock_reg = hwif->extra_base + 0x01;
+ 	u8 clock = inb(clock_reg);
  
- 	return rc;
+ 	outb(clock & ~(hwif->channel ? 0x08 : 0x02), clock_reg);
  }
-+EXPORT_SYMBOL_GPL(ide_device_add_all);
-+
-+int ide_device_add(u8 idx[4])
-+{
-+	u8 idx_all[MAX_HWIFS];
-+	int i;
  
-+	for (i = 0; i < MAX_HWIFS; i++)
-+		idx_all[i] = (i < 4) ? idx[i] : 0xff;
+-static int pdc202xx_quirkproc (ide_drive_t *drive)
++static void pdc202xx_quirkproc(ide_drive_t *drive)
+ {
+ 	const char **list, *model = drive->id->model;
+ 
+ 	for (list = pdc_quirk_drives; *list != NULL; list++)
+-		if (strstr(model, *list) != NULL)
+-			return 2;
+-	return 0;
++		if (strstr(model, *list) != NULL) {
++			drive->quirk_list = 2;
++			return;
++		}
 +
-+	return ide_device_add_all(idx_all);
-+}
- EXPORT_SYMBOL_GPL(ide_device_add);
-diff --git a/drivers/ide/ide-proc.c b/drivers/ide/ide-proc.c
-index a4007d3..aa663e7 100644
---- a/drivers/ide/ide-proc.c
-+++ b/drivers/ide/ide-proc.c
-@@ -346,14 +346,20 @@ static int ide_write_setting(ide_drive_t *drive, ide_settings_t *setting, int va
++	drive->quirk_list = 0;
+ }
  
- static int set_xfer_rate (ide_drive_t *drive, int arg)
+ static void pdc202xx_old_ide_dma_start(ide_drive_t *drive)
+@@ -193,7 +196,7 @@ static void pdc202xx_old_ide_dma_start(ide_drive_t *drive)
+ 	if (drive->media != ide_disk || drive->addressing == 1) {
+ 		struct request *rq	= HWGROUP(drive)->rq;
+ 		ide_hwif_t *hwif	= HWIF(drive);
+-		unsigned long high_16   = hwif->dma_master;
++		unsigned long high_16	= hwif->extra_base - 16;
+ 		unsigned long atapi_reg	= high_16 + (hwif->channel ? 0x24 : 0x20);
+ 		u32 word_count	= 0;
+ 		u8 clock = inb(high_16 + 0x11);
+@@ -212,7 +215,7 @@ static int pdc202xx_old_ide_dma_end(ide_drive_t *drive)
  {
-+	ide_task_t task;
- 	int err;
+ 	if (drive->media != ide_disk || drive->addressing == 1) {
+ 		ide_hwif_t *hwif	= HWIF(drive);
+-		unsigned long high_16	= hwif->dma_master;
++		unsigned long high_16	= hwif->extra_base - 16;
+ 		unsigned long atapi_reg	= high_16 + (hwif->channel ? 0x24 : 0x20);
+ 		u8 clock		= 0;
  
- 	if (arg < 0 || arg > 70)
- 		return -EINVAL;
+@@ -228,7 +231,7 @@ static int pdc202xx_old_ide_dma_end(ide_drive_t *drive)
+ static int pdc202xx_old_ide_dma_test_irq(ide_drive_t *drive)
+ {
+ 	ide_hwif_t *hwif	= HWIF(drive);
+-	unsigned long high_16	= hwif->dma_master;
++	unsigned long high_16	= hwif->extra_base - 16;
+ 	u8 dma_stat		= inb(hwif->dma_status);
+ 	u8 sc1d			= inb(high_16 + 0x001d);
  
--	err = ide_wait_cmd(drive,
--			WIN_SETFEATURES, (u8) arg,
--			SETFEATURES_XFER, 0, NULL);
-+	memset(&task, 0, sizeof(task));
-+	task.tf.command = WIN_SETFEATURES;
-+	task.tf.feature = SETFEATURES_XFER;
-+	task.tf.nsect   = (u8)arg;
-+	task.tf_flags = IDE_TFLAG_OUT_FEATURE | IDE_TFLAG_OUT_NSECT |
-+			IDE_TFLAG_IN_NSECT;
-+
-+	err = ide_no_data_taskfile(drive, &task);
+@@ -271,7 +274,7 @@ static void pdc202xx_dma_timeout(ide_drive_t *drive)
  
- 	if (!err && arg) {
- 		ide_set_xfer_rate(drive, (u8) arg);
-diff --git a/drivers/ide/ide-scan-pci.c b/drivers/ide/ide-scan-pci.c
-new file mode 100644
-index 0000000..7ffa332
---- /dev/null
-+++ b/drivers/ide/ide-scan-pci.c
-@@ -0,0 +1,121 @@
-+/*
-+ * support for probing IDE PCI devices in the PCI bus order
-+ *
-+ * Copyright (c) 1998-2000  Andre Hedrick <andre at linux-ide.org>
-+ * Copyright (c) 1995-1998  Mark Lord
-+ *
-+ * May be copied or modified under the terms of the GNU General Public License
-+ */
-+
-+#include <linux/kernel.h>
-+#include <linux/init.h>
-+#include <linux/module.h>
-+#include <linux/ide.h>
-+
-+/*
-+ *	Module interfaces
-+ */
-+
-+static int pre_init = 1;		/* Before first ordered IDE scan */
-+static LIST_HEAD(ide_pci_drivers);
-+
-+/*
-+ *	__ide_pci_register_driver	-	attach IDE driver
-+ *	@driver: pci driver
-+ *	@module: owner module of the driver
-+ *
-+ *	Registers a driver with the IDE layer. The IDE layer arranges that
-+ *	boot time setup is done in the expected device order and then
-+ *	hands the controllers off to the core PCI code to do the rest of
-+ *	the work.
-+ *
-+ *	Returns are the same as for pci_register_driver
-+ */
-+
-+int __ide_pci_register_driver(struct pci_driver *driver, struct module *module,
-+			      const char *mod_name)
-+{
-+	if (!pre_init)
-+		return __pci_register_driver(driver, module, mod_name);
-+	driver->driver.owner = module;
-+	list_add_tail(&driver->node, &ide_pci_drivers);
-+	return 0;
-+}
-+EXPORT_SYMBOL_GPL(__ide_pci_register_driver);
-+
-+/**
-+ *	ide_scan_pcidev		-	find an IDE driver for a device
-+ *	@dev: PCI device to check
-+ *
-+ *	Look for an IDE driver to handle the device we are considering.
-+ *	This is only used during boot up to get the ordering correct. After
-+ *	boot up the pci layer takes over the job.
-+ */
+ static void pdc202xx_reset_host (ide_hwif_t *hwif)
+ {
+-	unsigned long high_16	= hwif->dma_master;
++	unsigned long high_16	= hwif->extra_base - 16;
+ 	u8 udma_speed_flag	= inb(high_16 | 0x001f);
+ 
+ 	outb(udma_speed_flag | 0x10, high_16 | 0x001f);
+@@ -375,6 +378,11 @@ static void __devinit pdc202ata4_fixup_irq(struct pci_dev *dev,
+ 	}
+ }
+ 
++#define IDE_HFLAGS_PDC202XX \
++	(IDE_HFLAG_ERROR_STOPS_FIFO | \
++	 IDE_HFLAG_ABUSE_SET_DMA_MODE | \
++	 IDE_HFLAG_OFF_BOARD)
 +
-+static int __init ide_scan_pcidev(struct pci_dev *dev)
-+{
-+	struct list_head *l;
-+	struct pci_driver *d;
+ #define DECLARE_PDC2026X_DEV(name_str, udma, extra_flags) \
+ 	{ \
+ 		.name		= name_str, \
+@@ -382,9 +390,7 @@ static void __devinit pdc202ata4_fixup_irq(struct pci_dev *dev,
+ 		.init_hwif	= init_hwif_pdc202xx, \
+ 		.init_dma	= init_dma_pdc202xx, \
+ 		.extra		= 48, \
+-		.host_flags	= IDE_HFLAG_ERROR_STOPS_FIFO | \
+-				  extra_flags | \
+-				  IDE_HFLAG_OFF_BOARD, \
++		.host_flags	= IDE_HFLAGS_PDC202XX | extra_flags, \
+ 		.pio_mask	= ATA_PIO4, \
+ 		.mwdma_mask	= ATA_MWDMA2, \
+ 		.udma_mask	= udma, \
+@@ -397,8 +403,7 @@ static const struct ide_port_info pdc202xx_chipsets[] __devinitdata = {
+ 		.init_hwif	= init_hwif_pdc202xx,
+ 		.init_dma	= init_dma_pdc202xx,
+ 		.extra		= 16,
+-		.host_flags	= IDE_HFLAG_ERROR_STOPS_FIFO |
+-				  IDE_HFLAG_OFF_BOARD,
++		.host_flags	= IDE_HFLAGS_PDC202XX,
+ 		.pio_mask	= ATA_PIO4,
+ 		.mwdma_mask	= ATA_MWDMA2,
+ 		.udma_mask	= ATA_UDMA2,
+diff --git a/drivers/ide/pci/piix.c b/drivers/ide/pci/piix.c
+index 27781d2..bd6d3f7 100644
+--- a/drivers/ide/pci/piix.c
++++ b/drivers/ide/pci/piix.c
+@@ -203,20 +203,11 @@ static void piix_set_dma_mode(ide_drive_t *drive, const u8 speed)
+ 	pci_read_config_byte(dev, 0x54, &reg54);
+ 	pci_read_config_byte(dev, 0x55, &reg55);
+ 
+-	switch(speed) {
+-		case XFER_UDMA_4:
+-		case XFER_UDMA_2:	u_speed = 2 << (drive->dn * 4); break;
+-		case XFER_UDMA_5:
+-		case XFER_UDMA_3:
+-		case XFER_UDMA_1:	u_speed = 1 << (drive->dn * 4); break;
+-		case XFER_UDMA_0:	u_speed = 0 << (drive->dn * 4); break;
+-		case XFER_MW_DMA_2:
+-		case XFER_MW_DMA_1:
+-		case XFER_SW_DMA_2:	break;
+-		default:		return;
+-	}
+-
+ 	if (speed >= XFER_UDMA_0) {
++		u8 udma = speed - XFER_UDMA_0;
 +
-+	list_for_each(l, &ide_pci_drivers) {
-+		d = list_entry(l, struct pci_driver, node);
-+		if (d->id_table) {
-+			const struct pci_device_id *id =
-+				pci_match_id(d->id_table, dev);
++		u_speed = min_t(u8, 2 - (udma & 1), udma) << (drive->dn * 4);
 +
-+			if (id != NULL && d->probe(dev, id) >= 0) {
-+				dev->driver = d;
-+				pci_dev_get(dev);
-+				return 1;
-+			}
-+		}
-+	}
-+	return 0;
-+}
+ 		if (!(reg48 & u_flag))
+ 			pci_write_config_byte(dev, 0x48, reg48 | u_flag);
+ 		if (speed == XFER_UDMA_5) {
+diff --git a/drivers/ide/pci/sc1200.c b/drivers/ide/pci/sc1200.c
+index 707d5ff..32fdf53 100644
+--- a/drivers/ide/pci/sc1200.c
++++ b/drivers/ide/pci/sc1200.c
+@@ -135,59 +135,29 @@ static void sc1200_set_dma_mode(ide_drive_t *drive, const u8 mode)
+ 	unsigned short		pci_clock;
+ 	unsigned int		basereg = hwif->channel ? 0x50 : 0x40;
+ 
++	static const u32 udma_timing[3][3] = {
++		{ 0x00921250, 0x00911140, 0x00911030 },
++		{ 0x00932470, 0x00922260, 0x00922140 },
++		{ 0x009436a1, 0x00933481, 0x00923261 },
++	};
 +
-+/**
-+ *	ide_scan_pcibus		-	perform the initial IDE driver scan
-+ *
-+ *	Perform the initial bus rather than driver ordered scan of the
-+ *	PCI drivers. After this all IDE pci handling becomes standard
-+ *	module ordering not traditionally ordered.
-+ */
++	static const u32 mwdma_timing[3][3] = {
++		{ 0x00077771, 0x00012121, 0x00002020 },
++		{ 0x000bbbb2, 0x00024241, 0x00013131 },
++		{ 0x000ffff3, 0x00035352, 0x00015151 },
++	};
 +
-+int __init ide_scan_pcibus(void)
-+{
-+	struct pci_dev *dev = NULL;
-+	struct pci_driver *d;
-+	struct list_head *l, *n;
+ 	pci_clock = sc1200_get_pci_clock();
+ 
+ 	/*
+ 	 * Note that each DMA mode has several timings associated with it.
+ 	 * The correct timing depends on the fast PCI clock freq.
+ 	 */
+-	timings = 0;
+-	switch (mode) {
+-		case XFER_UDMA_0:
+-			switch (pci_clock) {
+-				case PCI_CLK_33:	timings = 0x00921250;	break;
+-				case PCI_CLK_48:	timings = 0x00932470;	break;
+-				case PCI_CLK_66:	timings = 0x009436a1;	break;
+-			}
+-			break;
+-		case XFER_UDMA_1:
+-			switch (pci_clock) {
+-				case PCI_CLK_33:	timings = 0x00911140;	break;
+-				case PCI_CLK_48:	timings = 0x00922260;	break;
+-				case PCI_CLK_66:	timings = 0x00933481;	break;
+-			}
+-			break;
+-		case XFER_UDMA_2:
+-			switch (pci_clock) {
+-				case PCI_CLK_33:	timings = 0x00911030;	break;
+-				case PCI_CLK_48:	timings = 0x00922140;	break;
+-				case PCI_CLK_66:	timings = 0x00923261;	break;
+-			}
+-			break;
+-		case XFER_MW_DMA_0:
+-			switch (pci_clock) {
+-				case PCI_CLK_33:	timings = 0x00077771;	break;
+-				case PCI_CLK_48:	timings = 0x000bbbb2;	break;
+-				case PCI_CLK_66:	timings = 0x000ffff3;	break;
+-			}
+-			break;
+-		case XFER_MW_DMA_1:
+-			switch (pci_clock) {
+-				case PCI_CLK_33:	timings = 0x00012121;	break;
+-				case PCI_CLK_48:	timings = 0x00024241;	break;
+-				case PCI_CLK_66:	timings = 0x00035352;	break;
+-			}
+-			break;
+-		case XFER_MW_DMA_2:
+-			switch (pci_clock) {
+-				case PCI_CLK_33:	timings = 0x00002020;	break;
+-				case PCI_CLK_48:	timings = 0x00013131;	break;
+-				case PCI_CLK_66:	timings = 0x00015151;	break;
+-			}
+-			break;
+-		default:
+-			return;
+-	}
 +
-+	pre_init = 0;
-+	if (!ide_scan_direction)
-+		while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)))
-+			ide_scan_pcidev(dev);
++	if (mode >= XFER_UDMA_0)
++		timings =  udma_timing[pci_clock][mode - XFER_UDMA_0];
 +	else
-+		while ((dev = pci_get_device_reverse(PCI_ANY_ID, PCI_ANY_ID,
-+						     dev)))
-+			ide_scan_pcidev(dev);
-+
++		timings = mwdma_timing[pci_clock][mode - XFER_MW_DMA_0];
+ 
+ 	if (unit == 0) {			/* are we configuring drive0? */
+ 		pci_read_config_dword(hwif->pci_dev, basereg+4, &reg);
+@@ -250,9 +220,9 @@ static void sc1200_set_pio_mode(ide_drive_t *drive, const u8 pio)
+ 	}
+ 	if (mode != -1) {
+ 		printk("SC1200: %s: changing (U)DMA mode\n", drive->name);
+-		hwif->dma_off_quietly(drive);
+-		if (ide_set_dma_mode(drive, mode) == 0)
+-			hwif->dma_host_on(drive);
++		ide_dma_off_quietly(drive);
++		if (ide_set_dma_mode(drive, mode) == 0 && drive->using_dma)
++			hwif->dma_host_set(drive, 1);
+ 		return;
+ 	}
+ 
+@@ -260,66 +230,39 @@ static void sc1200_set_pio_mode(ide_drive_t *drive, const u8 pio)
+ }
+ 
+ #ifdef CONFIG_PM
+-static ide_hwif_t *lookup_pci_dev (ide_hwif_t *prev, struct pci_dev *dev)
+-{
+-	int	h;
+-
+-	for (h = 0; h < MAX_HWIFS; h++) {
+-		ide_hwif_t *hwif = &ide_hwifs[h];
+-		if (prev) {
+-			if (hwif == prev)
+-				prev = NULL;	// found previous, now look for next match
+-		} else {
+-			if (hwif && hwif->pci_dev == dev)
+-				return hwif;	// found next match
+-		}
+-	}
+-	return NULL;	// not found
+-}
+-
+-typedef struct sc1200_saved_state_s {
+-	__u32		regs[4];
+-} sc1200_saved_state_t;
+-
++struct sc1200_saved_state {
++	u32 regs[8];
++};
+ 
+ static int sc1200_suspend (struct pci_dev *dev, pm_message_t state)
+ {
+-	ide_hwif_t		*hwif = NULL;
+-
+ 	printk("SC1200: suspend(%u)\n", state.event);
+ 
 +	/*
-+	 *	Hand the drivers over to the PCI layer now we
-+	 *	are post init.
++	 * we only save state when going from full power to less
 +	 */
-+
-+	list_for_each_safe(l, n, &ide_pci_drivers) {
-+		list_del(l);
-+		d = list_entry(l, struct pci_driver, node);
-+		if (__pci_register_driver(d, d->driver.owner,
-+					  d->driver.mod_name))
-+			printk(KERN_ERR "%s: failed to register %s driver\n",
-+					__FUNCTION__, d->driver.mod_name);
-+	}
-+
-+	return 0;
-+}
-+
-+static int __init ide_scan_pci(void)
-+{
-+	return ide_scan_pcibus();
-+}
-+
-+module_init(ide_scan_pci);
-diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c
-index 7b9181b..d71a584 100644
---- a/drivers/ide/ide-tape.c
-+++ b/drivers/ide/ide-tape.c
-@@ -615,16 +615,6 @@ typedef struct os_dat_s {
- /*************************** End of tunable parameters ***********************/
- 
- /*
-- *	Debugging/Performance analysis
-- *
-- *	I/O trace support
-- */
--#define USE_IOTRACE	0
--#if USE_IOTRACE
--#define IO_IDETAPE_FIFO	500
--#endif
+ 	if (state.event == PM_EVENT_ON) {
+-		// we only save state when going from full power to less
 -
--/*
-  *	Read/Write error simulation
-  */
- #define SIMULATE_ERRORS			0
-@@ -1700,6 +1690,11 @@ static int idetape_end_request(ide_drive_t *drive, int uptodate, int nr_sects)
- 	if (error)
- 		tape->failed_pc = NULL;
+-		//
+-		// Loop over all interfaces that are part of this PCI device:
+-		//
+-		while ((hwif = lookup_pci_dev(hwif, dev)) != NULL) {
+-			sc1200_saved_state_t	*ss;
+-			unsigned int		basereg, r;
+-			//
+-			// allocate a permanent save area, if not already allocated
+-			//
+-			ss = (sc1200_saved_state_t *)hwif->config_data;
+-			if (ss == NULL) {
+-				ss = kmalloc(sizeof(sc1200_saved_state_t), GFP_KERNEL);
+-				if (ss == NULL)
+-					return -ENOMEM;
+-				hwif->config_data = (unsigned long)ss;
+-			}
+-			ss = (sc1200_saved_state_t *)hwif->config_data;
+-			//
+-			// Save timing registers:  this may be unnecessary if 
+-			// BIOS also does it
+-			//
+-			basereg = hwif->channel ? 0x50 : 0x40;
+-			for (r = 0; r < 4; ++r) {
+-				pci_read_config_dword (hwif->pci_dev, basereg + (r<<2), &ss->regs[r]);
+-			}
++		struct sc1200_saved_state *ss;
++		unsigned int r;
++
++		/*
++		 * allocate a permanent save area, if not already allocated
++		 */
++		ss = (struct sc1200_saved_state *)pci_get_drvdata(dev);
++		if (ss == NULL) {
++			ss = kmalloc(sizeof(*ss), GFP_KERNEL);
++			if (ss == NULL)
++				return -ENOMEM;
++			pci_set_drvdata(dev, ss);
+ 		}
+-	}
  
-+	if (!blk_special_request(rq)) {
-+		ide_end_request(drive, uptodate, nr_sects);
-+		return 0;
+-	/* You don't need to iterate over disks -- sysfs should have done that for you already */ 
++		/*
++		 * save timing registers
++		 * (this may be unnecessary if BIOS also does it)
++		 */
++		for (r = 0; r < 8; r++)
++			pci_read_config_dword(dev, 0x40 + r * 4, &ss->regs[r]);
 +	}
-+
- 	spin_lock_irqsave(&tape->spinlock, flags);
  
- 	/* The request was a pipelined data transfer request */
-@@ -1818,9 +1813,8 @@ static ide_startstop_t idetape_retry_pc (ide_drive_t *drive)
- 	idetape_tape_t *tape = drive->driver_data;
- 	idetape_pc_t *pc;
- 	struct request *rq;
--	atapi_error_t error;
+ 	pci_disable_device(dev);
+ 	pci_set_power_state(dev, pci_choose_state(dev, state));
+@@ -328,30 +271,25 @@ static int sc1200_suspend (struct pci_dev *dev, pm_message_t state)
  
--	error.all = HWIF(drive)->INB(IDE_ERROR_REG);
-+	(void)drive->hwif->INB(IDE_ERROR_REG);
- 	pc = idetape_next_pc_storage(drive);
- 	rq = idetape_next_rq_storage(drive);
- 	idetape_create_request_sense_cmd(pc);
-@@ -1858,15 +1852,13 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive)
+ static int sc1200_resume (struct pci_dev *dev)
  {
- 	ide_hwif_t *hwif = drive->hwif;
- 	idetape_tape_t *tape = drive->driver_data;
--	atapi_status_t status;
--	atapi_bcount_t bcount;
--	atapi_ireason_t ireason;
- 	idetape_pc_t *pc = tape->pc;
+-	ide_hwif_t	*hwif = NULL;
+-	int		i;
++	struct sc1200_saved_state *ss;
++	unsigned int r;
++	int i;
+ 
+ 	i = pci_enable_device(dev);
+ 	if (i)
+ 		return i;
+ 
+-	//
+-	// loop over all interfaces that are part of this pci device:
+-	//
+-	while ((hwif = lookup_pci_dev(hwif, dev)) != NULL) {
+-		unsigned int		basereg, r;
+-		sc1200_saved_state_t	*ss = (sc1200_saved_state_t *)hwif->config_data;
 -
- 	unsigned int temp;
- #if SIMULATE_ERRORS
- 	static int error_sim_count = 0;
+-		//
+-		// Restore timing registers:  this may be unnecessary if BIOS also does it
+-		//
+-		basereg = hwif->channel ? 0x50 : 0x40;
+-		if (ss != NULL) {
+-			for (r = 0; r < 4; ++r) {
+-				pci_write_config_dword(hwif->pci_dev, basereg + (r<<2), ss->regs[r]);
+-			}
+-		}
++	ss = (struct sc1200_saved_state *)pci_get_drvdata(dev);
++
++	/*
++	 * restore timing registers
++	 * (this may be unnecessary if BIOS also does it)
++	 */
++	if (ss) {
++		for (r = 0; r < 8; r++)
++			pci_write_config_dword(dev, 0x40 + r * 4, ss->regs[r]);
+ 	}
++
+ 	return 0;
+ }
  #endif
-+	u16 bcount;
-+	u8 stat, ireason;
+diff --git a/drivers/ide/pci/scc_pata.c b/drivers/ide/pci/scc_pata.c
+index ebb7132..24a85bb 100644
+--- a/drivers/ide/pci/scc_pata.c
++++ b/drivers/ide/pci/scc_pata.c
+@@ -254,19 +254,7 @@ static void scc_set_dma_mode(ide_drive_t *drive, const u8 speed)
+ 		offset = 0; /* 100MHz */
+ 	}
  
- #if IDETAPE_DEBUG_LOG
- 	if (tape->debug_level >= 4)
-@@ -1875,10 +1867,10 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive)
- #endif /* IDETAPE_DEBUG_LOG */	
+-	switch (speed) {
+-	case XFER_UDMA_6:
+-	case XFER_UDMA_5:
+-	case XFER_UDMA_4:
+-	case XFER_UDMA_3:
+-	case XFER_UDMA_2:
+-	case XFER_UDMA_1:
+-	case XFER_UDMA_0:
+-		idx = speed - XFER_UDMA_0;
+-		break;
+-	default:
+-		return;
+-	}
++	idx = speed - XFER_UDMA_0;
  
- 	/* Clear the interrupt */
--	status.all = HWIF(drive)->INB(IDE_STATUS_REG);
-+	stat = hwif->INB(IDE_STATUS_REG);
+ 	jcactsel = JCACTSELtbl[offset][idx];
+ 	if (is_slave) {
+diff --git a/drivers/ide/pci/serverworks.c b/drivers/ide/pci/serverworks.c
+index a728031..877c09b 100644
+--- a/drivers/ide/pci/serverworks.c
++++ b/drivers/ide/pci/serverworks.c
+@@ -164,25 +164,12 @@ static void svwks_set_dma_mode(ide_drive_t *drive, const u8 speed)
+ 	ultra_timing	&= ~(0x0F << (4*unit));
+ 	ultra_enable	&= ~(0x01 << drive->dn);
  
- 	if (test_bit(PC_DMA_IN_PROGRESS, &pc->flags)) {
--		if (HWIF(drive)->ide_dma_end(drive) || status.b.check) {
-+		if (hwif->ide_dma_end(drive) || (stat & ERR_STAT)) {
- 			/*
- 			 * A DMA error is sometimes expected. For example,
- 			 * if the tape is crossing a filemark during a
-@@ -1912,7 +1904,7 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive)
- 	}
+-	switch(speed) {
+-		case XFER_MW_DMA_2:
+-		case XFER_MW_DMA_1:
+-		case XFER_MW_DMA_0:
+-			dma_timing |= dma_modes[speed - XFER_MW_DMA_0];
+-			break;
+-
+-		case XFER_UDMA_5:
+-		case XFER_UDMA_4:
+-		case XFER_UDMA_3:
+-		case XFER_UDMA_2:
+-		case XFER_UDMA_1:
+-		case XFER_UDMA_0:
+-			dma_timing   |= dma_modes[2];
+-			ultra_timing |= ((udma_modes[speed - XFER_UDMA_0]) << (4*unit));
+-			ultra_enable |= (0x01 << drive->dn);
+-		default:
+-			break;
+-	}
++	if (speed >= XFER_UDMA_0) {
++		dma_timing   |= dma_modes[2];
++		ultra_timing |= (udma_modes[speed - XFER_UDMA_0] << (4 * unit));
++		ultra_enable |= (0x01 << drive->dn);
++	} else if (speed >= XFER_MW_DMA_0)
++		dma_timing   |= dma_modes[speed - XFER_MW_DMA_0];
  
- 	/* No more interrupts */
--	if (!status.b.drq) {
-+	if ((stat & DRQ_STAT) == 0) {
- #if IDETAPE_DEBUG_LOG
- 		if (tape->debug_level >= 2)
- 			printk(KERN_INFO "ide-tape: Packet command completed, %d bytes transferred\n", pc->actually_transferred);
-@@ -1927,12 +1919,13 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive)
- 		    (++error_sim_count % 100) == 0) {
- 			printk(KERN_INFO "ide-tape: %s: simulating error\n",
- 				tape->name);
--			status.b.check = 1;
-+			stat |= ERR_STAT;
- 		}
- #endif
--		if (status.b.check && pc->c[0] == IDETAPE_REQUEST_SENSE_CMD)
--			status.b.check = 0;
--		if (status.b.check || test_bit(PC_DMA_ERROR, &pc->flags)) {	/* Error detected */
-+		if ((stat & ERR_STAT) && pc->c[0] == IDETAPE_REQUEST_SENSE_CMD)
-+			stat &= ~ERR_STAT;
-+		if ((stat & ERR_STAT) || test_bit(PC_DMA_ERROR, &pc->flags)) {
-+			/* Error detected */
- #if IDETAPE_DEBUG_LOG
- 			if (tape->debug_level >= 1)
- 				printk(KERN_INFO "ide-tape: %s: I/O error\n",
-@@ -1951,7 +1944,7 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive)
- 		}
- 		pc->error = 0;
- 		if (test_bit(PC_WAIT_FOR_DSC, &pc->flags) &&
--		    !status.b.dsc) {
-+		    (stat & SEEK_STAT) == 0) {
- 			/* Media access command */
- 			tape->dsc_polling_start = jiffies;
- 			tape->dsc_polling_frequency = IDETAPE_DSC_MA_FAST;
-@@ -1973,30 +1966,30 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive)
- 		return ide_do_reset(drive);
+ 	pci_write_config_byte(dev, drive_pci2[drive->dn], dma_timing);
+ 	pci_write_config_byte(dev, (0x56|hwif->channel), ultra_timing);
+@@ -366,12 +353,17 @@ static void __devinit init_hwif_svwks (ide_hwif_t *hwif)
  	}
- 	/* Get the number of bytes to transfer on this interrupt. */
--	bcount.b.high = hwif->INB(IDE_BCOUNTH_REG);
--	bcount.b.low = hwif->INB(IDE_BCOUNTL_REG);
-+	bcount = (hwif->INB(IDE_BCOUNTH_REG) << 8) |
-+		  hwif->INB(IDE_BCOUNTL_REG);
+ }
  
--	ireason.all = hwif->INB(IDE_IREASON_REG);
-+	ireason = hwif->INB(IDE_IREASON_REG);
++#define IDE_HFLAGS_SVWKS \
++	(IDE_HFLAG_LEGACY_IRQS | \
++	 IDE_HFLAG_ABUSE_SET_DMA_MODE | \
++	 IDE_HFLAG_BOOTABLE)
++
+ static const struct ide_port_info serverworks_chipsets[] __devinitdata = {
+ 	{	/* 0 */
+ 		.name		= "SvrWks OSB4",
+ 		.init_chipset	= init_chipset_svwks,
+ 		.init_hwif	= init_hwif_svwks,
+-		.host_flags	= IDE_HFLAG_LEGACY_IRQS | IDE_HFLAG_BOOTABLE,
++		.host_flags	= IDE_HFLAGS_SVWKS,
+ 		.pio_mask	= ATA_PIO4,
+ 		.mwdma_mask	= ATA_MWDMA2,
+ 		.udma_mask	= 0x00, /* UDMA is problematic on OSB4 */
+@@ -379,7 +371,7 @@ static const struct ide_port_info serverworks_chipsets[] __devinitdata = {
+ 		.name		= "SvrWks CSB5",
+ 		.init_chipset	= init_chipset_svwks,
+ 		.init_hwif	= init_hwif_svwks,
+-		.host_flags	= IDE_HFLAG_LEGACY_IRQS | IDE_HFLAG_BOOTABLE,
++		.host_flags	= IDE_HFLAGS_SVWKS,
+ 		.pio_mask	= ATA_PIO4,
+ 		.mwdma_mask	= ATA_MWDMA2,
+ 		.udma_mask	= ATA_UDMA5,
+@@ -387,7 +379,7 @@ static const struct ide_port_info serverworks_chipsets[] __devinitdata = {
+ 		.name		= "SvrWks CSB6",
+ 		.init_chipset	= init_chipset_svwks,
+ 		.init_hwif	= init_hwif_svwks,
+-		.host_flags	= IDE_HFLAG_LEGACY_IRQS | IDE_HFLAG_BOOTABLE,
++		.host_flags	= IDE_HFLAGS_SVWKS,
+ 		.pio_mask	= ATA_PIO4,
+ 		.mwdma_mask	= ATA_MWDMA2,
+ 		.udma_mask	= ATA_UDMA5,
+@@ -395,8 +387,7 @@ static const struct ide_port_info serverworks_chipsets[] __devinitdata = {
+ 		.name		= "SvrWks CSB6",
+ 		.init_chipset	= init_chipset_svwks,
+ 		.init_hwif	= init_hwif_svwks,
+-		.host_flags	= IDE_HFLAG_LEGACY_IRQS | IDE_HFLAG_SINGLE |
+-				  IDE_HFLAG_BOOTABLE,
++		.host_flags	= IDE_HFLAGS_SVWKS | IDE_HFLAG_SINGLE,
+ 		.pio_mask	= ATA_PIO4,
+ 		.mwdma_mask	= ATA_MWDMA2,
+ 		.udma_mask	= ATA_UDMA5,
+@@ -404,8 +395,7 @@ static const struct ide_port_info serverworks_chipsets[] __devinitdata = {
+ 		.name		= "SvrWks HT1000",
+ 		.init_chipset	= init_chipset_svwks,
+ 		.init_hwif	= init_hwif_svwks,
+-		.host_flags	= IDE_HFLAG_LEGACY_IRQS | IDE_HFLAG_SINGLE |
+-				  IDE_HFLAG_BOOTABLE,
++		.host_flags	= IDE_HFLAGS_SVWKS | IDE_HFLAG_SINGLE,
+ 		.pio_mask	= ATA_PIO4,
+ 		.mwdma_mask	= ATA_MWDMA2,
+ 		.udma_mask	= ATA_UDMA5,
+diff --git a/drivers/ide/pci/sgiioc4.c b/drivers/ide/pci/sgiioc4.c
+index de820aa..9e0be7d 100644
+--- a/drivers/ide/pci/sgiioc4.c
++++ b/drivers/ide/pci/sgiioc4.c
+@@ -277,21 +277,6 @@ sgiioc4_ide_dma_end(ide_drive_t * drive)
+ 	return dma_stat;
+ }
  
--	if (ireason.b.cod) {
-+	if (ireason & CD) {
- 		printk(KERN_ERR "ide-tape: CoD != 0 in idetape_pc_intr\n");
- 		return ide_do_reset(drive);
- 	}
--	if (ireason.b.io == test_bit(PC_WRITING, &pc->flags)) {
-+	if (((ireason & IO) == IO) == test_bit(PC_WRITING, &pc->flags)) {
- 		/* Hopefully, we will never get here */
- 		printk(KERN_ERR "ide-tape: We wanted to %s, ",
--			ireason.b.io ? "Write":"Read");
-+				(ireason & IO) ? "Write" : "Read");
- 		printk(KERN_ERR "ide-tape: but the tape wants us to %s !\n",
--			ireason.b.io ? "Read":"Write");
-+				(ireason & IO) ? "Read" : "Write");
- 		return ide_do_reset(drive);
- 	}
- 	if (!test_bit(PC_WRITING, &pc->flags)) {
- 		/* Reading - Check that we have enough space */
--		temp = pc->actually_transferred + bcount.all;
-+		temp = pc->actually_transferred + bcount;
- 		if (temp > pc->request_transfer) {
- 			if (temp > pc->buffer_size) {
- 				printk(KERN_ERR "ide-tape: The tape wants to send us more data than expected - discarding data\n");
--				idetape_discard_data(drive, bcount.all);
-+				idetape_discard_data(drive, bcount);
- 				ide_set_handler(drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL);
- 				return ide_started;
- 			}
-@@ -2008,23 +2001,26 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive)
- 	}
- 	if (test_bit(PC_WRITING, &pc->flags)) {
- 		if (pc->bh != NULL)
--			idetape_output_buffers(drive, pc, bcount.all);
-+			idetape_output_buffers(drive, pc, bcount);
- 		else
- 			/* Write the current buffer */
--			HWIF(drive)->atapi_output_bytes(drive, pc->current_position, bcount.all);
-+			hwif->atapi_output_bytes(drive, pc->current_position,
-+						 bcount);
- 	} else {
- 		if (pc->bh != NULL)
--			idetape_input_buffers(drive, pc, bcount.all);
-+			idetape_input_buffers(drive, pc, bcount);
- 		else
- 			/* Read the current buffer */
--			HWIF(drive)->atapi_input_bytes(drive, pc->current_position, bcount.all);
-+			hwif->atapi_input_bytes(drive, pc->current_position,
-+						bcount);
- 	}
- 	/* Update the current position */
--	pc->actually_transferred += bcount.all;
--	pc->current_position += bcount.all;
-+	pc->actually_transferred += bcount;
-+	pc->current_position += bcount;
- #if IDETAPE_DEBUG_LOG
- 	if (tape->debug_level >= 2)
--		printk(KERN_INFO "ide-tape: [cmd %x] transferred %d bytes on that interrupt\n", pc->c[0], bcount.all);
-+		printk(KERN_INFO "ide-tape: [cmd %x] transferred %d bytes "
-+				 "on that interrupt\n", pc->c[0], bcount);
- #endif
- 	/* And set the interrupt handler again */
- 	ide_set_handler(drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL);
-@@ -2078,28 +2074,28 @@ static ide_startstop_t idetape_transfer_pc(ide_drive_t *drive)
- 	ide_hwif_t *hwif = drive->hwif;
- 	idetape_tape_t *tape = drive->driver_data;
- 	idetape_pc_t *pc = tape->pc;
--	atapi_ireason_t ireason;
- 	int retries = 100;
- 	ide_startstop_t startstop;
-+	u8 ireason;
+-static int
+-sgiioc4_ide_dma_on(ide_drive_t * drive)
+-{
+-	drive->using_dma = 1;
+-
+-	return 0;
+-}
+-
+-static void sgiioc4_dma_off_quietly(ide_drive_t *drive)
+-{
+-	drive->using_dma = 0;
+-
+-	drive->hwif->dma_host_off(drive);
+-}
+-
+ static void sgiioc4_set_dma_mode(ide_drive_t *drive, const u8 speed)
+ {
+ }
+@@ -303,13 +288,10 @@ sgiioc4_ide_dma_test_irq(ide_drive_t * drive)
+ 	return sgiioc4_checkirq(HWIF(drive));
+ }
  
- 	if (ide_wait_stat(&startstop,drive,DRQ_STAT,BUSY_STAT,WAIT_READY)) {
- 		printk(KERN_ERR "ide-tape: Strange, packet command initiated yet DRQ isn't asserted\n");
- 		return startstop;
- 	}
--	ireason.all = hwif->INB(IDE_IREASON_REG);
--	while (retries-- && (!ireason.b.cod || ireason.b.io)) {
-+	ireason = hwif->INB(IDE_IREASON_REG);
-+	while (retries-- && ((ireason & CD) == 0 || (ireason & IO))) {
- 		printk(KERN_ERR "ide-tape: (IO,CoD != (0,1) while issuing "
- 				"a packet command, retrying\n");
- 		udelay(100);
--		ireason.all = hwif->INB(IDE_IREASON_REG);
-+		ireason = hwif->INB(IDE_IREASON_REG);
- 		if (retries == 0) {
- 			printk(KERN_ERR "ide-tape: (IO,CoD != (0,1) while "
- 					"issuing a packet command, ignoring\n");
--			ireason.b.cod = 1;
--			ireason.b.io = 0;
-+			ireason |= CD;
-+			ireason &= ~IO;
- 		}
- 	}
--	if (!ireason.b.cod || ireason.b.io) {
-+	if ((ireason & CD) == 0 || (ireason & IO)) {
- 		printk(KERN_ERR "ide-tape: (IO,CoD) != (0,1) while issuing "
- 				"a packet command\n");
- 		return ide_do_reset(drive);
-@@ -2120,8 +2116,8 @@ static ide_startstop_t idetape_issue_packet_command (ide_drive_t *drive, idetape
+-static void sgiioc4_dma_host_on(ide_drive_t * drive)
+-{
+-}
+-
+-static void sgiioc4_dma_host_off(ide_drive_t * drive)
++static void sgiioc4_dma_host_set(ide_drive_t *drive, int on)
  {
- 	ide_hwif_t *hwif = drive->hwif;
- 	idetape_tape_t *tape = drive->driver_data;
--	atapi_bcount_t bcount;
- 	int dma_ok = 0;
-+	u16 bcount;
+-	sgiioc4_clearirq(drive);
++	if (!on)
++		sgiioc4_clearirq(drive);
+ }
  
- #if IDETAPE_DEBUG_BUGS
- 	if (tape->pc->c[0] == IDETAPE_REQUEST_SENSE_CMD &&
-@@ -2170,7 +2166,7 @@ static ide_startstop_t idetape_issue_packet_command (ide_drive_t *drive, idetape
- 	pc->actually_transferred = 0;
- 	pc->current_position = pc->buffer;
- 	/* Request to transfer the entire buffer at once */
--	bcount.all = pc->request_transfer;
-+	bcount = pc->request_transfer;
+ static void
+@@ -582,7 +564,6 @@ ide_init_sgiioc4(ide_hwif_t * hwif)
+ 	hwif->pre_reset = NULL;	/* No HBA specific pre_set needed */
+ 	hwif->resetproc = &sgiioc4_resetproc;/* Reset DMA engine,
+ 						clear interrupts */
+-	hwif->intrproc = NULL;	/* Enable or Disable interrupt from drive */
+ 	hwif->maskproc = &sgiioc4_maskproc;	/* Mask on/off NIEN register */
+ 	hwif->quirkproc = NULL;
+ 	hwif->busproc = NULL;
+@@ -594,14 +575,11 @@ ide_init_sgiioc4(ide_hwif_t * hwif)
  
- 	if (test_and_clear_bit(PC_DMA_ERROR, &pc->flags)) {
- 		printk(KERN_WARNING "ide-tape: DMA disabled, "
-@@ -2180,12 +2176,9 @@ static ide_startstop_t idetape_issue_packet_command (ide_drive_t *drive, idetape
- 	if (test_bit(PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma)
- 		dma_ok = !hwif->dma_setup(drive);
+ 	hwif->mwdma_mask = ATA_MWDMA2_ONLY;
+ 
++	hwif->dma_host_set = &sgiioc4_dma_host_set;
+ 	hwif->dma_setup = &sgiioc4_ide_dma_setup;
+ 	hwif->dma_start = &sgiioc4_ide_dma_start;
+ 	hwif->ide_dma_end = &sgiioc4_ide_dma_end;
+-	hwif->ide_dma_on = &sgiioc4_ide_dma_on;
+-	hwif->dma_off_quietly = &sgiioc4_dma_off_quietly;
+ 	hwif->ide_dma_test_irq = &sgiioc4_ide_dma_test_irq;
+-	hwif->dma_host_on = &sgiioc4_dma_host_on;
+-	hwif->dma_host_off = &sgiioc4_dma_host_off;
+ 	hwif->dma_lost_irq = &sgiioc4_dma_lost_irq;
+ 	hwif->dma_timeout = &ide_dma_timeout;
+ }
+@@ -615,6 +593,7 @@ sgiioc4_ide_setup_pci_device(struct pci_dev *dev)
+ 	ide_hwif_t *hwif;
+ 	int h;
+ 	u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
++	hw_regs_t hw;
+ 
+ 	/*
+ 	 * Find an empty HWIF; if none available, return -ENOMEM.
+@@ -654,21 +633,16 @@ sgiioc4_ide_setup_pci_device(struct pci_dev *dev)
+ 		return -ENOMEM;
+ 	}
+ 
+-	if (hwif->io_ports[IDE_DATA_OFFSET] != cmd_base) {
+-		hw_regs_t hw;
+-
+-		/* Initialize the IO registers */
+-		memset(&hw, 0, sizeof(hw));
+-		sgiioc4_init_hwif_ports(&hw, cmd_base, ctl, irqport);
+-		memcpy(hwif->io_ports, hw.io_ports, sizeof(hwif->io_ports));
+-		hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET];
+-	}
++	/* Initialize the IO registers */
++	memset(&hw, 0, sizeof(hw));
++	sgiioc4_init_hwif_ports(&hw, cmd_base, ctl, irqport);
++	hw.irq = dev->irq;
++	hw.chipset = ide_pci;
++	hw.dev = &dev->dev;
++	ide_init_port_hw(hwif, &hw);
  
--	if (IDE_CONTROL_REG)
--		hwif->OUTB(drive->ctl, IDE_CONTROL_REG);
--	hwif->OUTB(dma_ok ? 1 : 0, IDE_FEATURE_REG);	/* Use PIO/DMA */
--	hwif->OUTB(bcount.b.high, IDE_BCOUNTH_REG);
--	hwif->OUTB(bcount.b.low, IDE_BCOUNTL_REG);
--	hwif->OUTB(drive->select.all, IDE_SELECT_REG);
-+	ide_pktcmd_tf_load(drive, IDE_TFLAG_NO_SELECT_MASK |
-+			   IDE_TFLAG_OUT_DEVICE, bcount, dma_ok);
-+
- 	if (dma_ok)			/* Will begin DMA later */
- 		set_bit(PC_DMA_IN_PROGRESS, &pc->flags);
- 	if (test_bit(IDETAPE_DRQ_INTERRUPT, &tape->flags)) {
-@@ -2295,11 +2288,11 @@ static ide_startstop_t idetape_media_access_finished (ide_drive_t *drive)
- {
- 	idetape_tape_t *tape = drive->driver_data;
- 	idetape_pc_t *pc = tape->pc;
--	atapi_status_t status;
-+	u8 stat;
+-	hwif->irq = dev->irq;
+-	hwif->chipset = ide_pci;
+ 	hwif->pci_dev = dev;
+ 	hwif->channel = 0;	/* Single Channel chip */
+-	hwif->gendev.parent = &dev->dev;/* setup proper ancestral information */
  
--	status.all = HWIF(drive)->INB(IDE_STATUS_REG);
--	if (status.b.dsc) {
--		if (status.b.check) {
-+	stat = drive->hwif->INB(IDE_STATUS_REG);
-+	if (stat & SEEK_STAT) {
-+		if (stat & ERR_STAT) {
- 			/* Error detected */
- 			if (pc->c[0] != IDETAPE_TEST_UNIT_READY_CMD)
- 				printk(KERN_ERR "ide-tape: %s: I/O error, ",
-@@ -2417,7 +2410,7 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive,
- 	idetape_tape_t *tape = drive->driver_data;
- 	idetape_pc_t *pc = NULL;
- 	struct request *postponed_rq = tape->postponed_rq;
--	atapi_status_t status;
-+	u8 stat;
+ 	/* The IOC4 uses MMIO rather than Port IO. */
+ 	default_hwif_mmiops(hwif);
+diff --git a/drivers/ide/pci/siimage.c b/drivers/ide/pci/siimage.c
+index 5709c25..908f37b 100644
+--- a/drivers/ide/pci/siimage.c
++++ b/drivers/ide/pci/siimage.c
+@@ -278,27 +278,14 @@ static void sil_set_dma_mode(ide_drive_t *drive, const u8 speed)
  
- #if IDETAPE_DEBUG_LOG
- #if 0
-@@ -2465,7 +2458,7 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive,
- 	 * If the tape is still busy, postpone our request and service
- 	 * the other device meanwhile.
- 	 */
--	status.all = HWIF(drive)->INB(IDE_STATUS_REG);
-+	stat = drive->hwif->INB(IDE_STATUS_REG);
+ 	scsc = is_sata(hwif) ? 1 : scsc;
  
- 	if (!drive->dsc_overlap && !(rq->cmd[0] & REQ_IDETAPE_PC2))
- 		set_bit(IDETAPE_IGNORE_DSC, &tape->flags);
-@@ -2481,7 +2474,7 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive,
- 		tape->insert_speed = tape->insert_size / 1024 * HZ / (jiffies - tape->insert_time);
- 	calculate_speeds(drive);
- 	if (!test_and_clear_bit(IDETAPE_IGNORE_DSC, &tape->flags) &&
--	    !status.b.dsc) {
-+	    (stat & SEEK_STAT) == 0) {
- 		if (postponed_rq == NULL) {
- 			tape->dsc_polling_start = jiffies;
- 			tape->dsc_polling_frequency = tape->best_dsc_rw_frequency;
-@@ -2502,9 +2495,6 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive,
- 	}
- 	if (rq->cmd[0] & REQ_IDETAPE_READ) {
- 		tape->buffer_head++;
--#if USE_IOTRACE
--		IO_trace(IO_IDETAPE_FIFO, tape->pipeline_head, tape->buffer_head, tape->tape_head, tape->minor);
--#endif
- 		tape->postpone_cnt = 0;
- 		pc = idetape_next_pc_storage(drive);
- 		idetape_create_read_cmd(tape, pc, rq->current_nr_sectors, (struct idetape_bh *)rq->special);
-@@ -2512,9 +2502,6 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive,
+-	switch(speed) {
+-		case XFER_MW_DMA_2:
+-		case XFER_MW_DMA_1:
+-		case XFER_MW_DMA_0:
+-			multi = dma[speed - XFER_MW_DMA_0];
+-			mode |= ((unit) ? 0x20 : 0x02);
+-			break;
+-		case XFER_UDMA_6:
+-		case XFER_UDMA_5:
+-		case XFER_UDMA_4:
+-		case XFER_UDMA_3:
+-		case XFER_UDMA_2:
+-		case XFER_UDMA_1:
+-		case XFER_UDMA_0:
+-			multi = dma[2];
+-			ultra |= ((scsc) ? (ultra6[speed - XFER_UDMA_0]) :
+-					   (ultra5[speed - XFER_UDMA_0]));
+-			mode |= ((unit) ? 0x30 : 0x03);
+-			break;
+-		default:
+-			return;
++	if (speed >= XFER_UDMA_0) {
++		multi = dma[2];
++		ultra |= (scsc ? ultra6[speed - XFER_UDMA_0] :
++				 ultra5[speed - XFER_UDMA_0]);
++		mode |= (unit ? 0x30 : 0x03);
++	} else {
++		multi = dma[speed - XFER_MW_DMA_0];
++		mode |= (unit ? 0x20 : 0x02);
  	}
- 	if (rq->cmd[0] & REQ_IDETAPE_WRITE) {
- 		tape->buffer_head++;
--#if USE_IOTRACE
--		IO_trace(IO_IDETAPE_FIFO, tape->pipeline_head, tape->buffer_head, tape->tape_head, tape->minor);
--#endif
- 		tape->postpone_cnt = 0;
- 		pc = idetape_next_pc_storage(drive);
- 		idetape_create_write_cmd(tape, pc, rq->current_nr_sectors, (struct idetape_bh *)rq->special);
-@@ -3241,9 +3228,6 @@ static int idetape_add_chrdev_write_request (ide_drive_t *drive, int blocks)
- 	idetape_switch_buffers(tape, new_stage);
- 	idetape_add_stage_tail(drive, new_stage);
- 	tape->pipeline_head++;
--#if USE_IOTRACE
--	IO_trace(IO_IDETAPE_FIFO, tape->pipeline_head, tape->buffer_head, tape->tape_head, tape->minor);
--#endif
- 	calculate_speeds(drive);
  
- 	/*
-@@ -3493,9 +3477,6 @@ static int idetape_add_chrdev_read_request (ide_drive_t *drive,int blocks)
- 		idetape_remove_stage_head(drive);
- 		spin_unlock_irqrestore(&tape->spinlock, flags);
- 		tape->pipeline_head++;
--#if USE_IOTRACE
--		IO_trace(IO_IDETAPE_FIFO, tape->pipeline_head, tape->buffer_head, tape->tape_head, tape->minor);
--#endif
- 		calculate_speeds(drive);
- 	}
- #if IDETAPE_DEBUG_BUGS
-@@ -4724,10 +4705,8 @@ static void ide_tape_release(struct kref *kref)
+ 	if (hwif->mmio) {
+@@ -726,9 +713,6 @@ static int is_dev_seagate_sata(ide_drive_t *drive)
+ 	const char *s = &drive->id->model[0];
+ 	unsigned len;
  
- 	drive->dsc_overlap = 0;
- 	drive->driver_data = NULL;
--	class_device_destroy(idetape_sysfs_class,
--			MKDEV(IDETAPE_MAJOR, tape->minor));
--	class_device_destroy(idetape_sysfs_class,
--			MKDEV(IDETAPE_MAJOR, tape->minor + 128));
-+	device_destroy(idetape_sysfs_class, MKDEV(IDETAPE_MAJOR, tape->minor));
-+	device_destroy(idetape_sysfs_class, MKDEV(IDETAPE_MAJOR, tape->minor + 128));
- 	idetape_devs[tape->minor] = NULL;
- 	g->private_data = NULL;
- 	put_disk(g);
-@@ -4884,10 +4863,10 @@ static int ide_tape_probe(ide_drive_t *drive)
+-	if (!drive->present)
+-		return 0;
+-
+ 	len = strnlen(s, sizeof(drive->id->model));
  
- 	idetape_setup(drive, tape, minor);
+ 	if ((len > 4) && (!memcmp(s, "ST", 2))) {
+@@ -743,18 +727,20 @@ static int is_dev_seagate_sata(ide_drive_t *drive)
+ }
  
--	class_device_create(idetape_sysfs_class, NULL,
--			MKDEV(IDETAPE_MAJOR, minor), &drive->gendev, "%s", tape->name);
--	class_device_create(idetape_sysfs_class, NULL,
--			MKDEV(IDETAPE_MAJOR, minor + 128), &drive->gendev, "n%s", tape->name);
-+	device_create(idetape_sysfs_class, &drive->gendev,
-+		      MKDEV(IDETAPE_MAJOR, minor), "%s", tape->name);
-+	device_create(idetape_sysfs_class, &drive->gendev,
-+			MKDEV(IDETAPE_MAJOR, minor + 128), "n%s", tape->name);
+ /**
+- *	siimage_fixup		-	post probe fixups
+- *	@hwif: interface to fix up
++ *	sil_quirkproc		-	post probe fixups
++ *	@drive: drive
+  *
+  *	Called after drive probe we use this to decide whether the
+  *	Seagate fixup must be applied. This used to be in init_iops but
+  *	that can occur before we know what drives are present.
+  */
  
- 	g->fops = &idetape_block_ops;
- 	ide_register_region(g);
-diff --git a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c
-index 2b60f1b..5eb6fa1 100644
---- a/drivers/ide/ide-taskfile.c
-+++ b/drivers/ide/ide-taskfile.c
-@@ -35,93 +35,81 @@
- #include <asm/uaccess.h>
- #include <asm/io.h>
+-static void __devinit siimage_fixup(ide_hwif_t *hwif)
++static void __devinit sil_quirkproc(ide_drive_t *drive)
+ {
++	ide_hwif_t *hwif = drive->hwif;
++
+ 	/* Try and raise the rqsize */
+-	if (!is_sata(hwif) || !is_dev_seagate_sata(&hwif->drives[0]))
++	if (!is_sata(hwif) || !is_dev_seagate_sata(drive))
+ 		hwif->rqsize = 128;
+ }
  
--static void ata_bswap_data (void *buffer, int wcount)
-+void ide_tf_load(ide_drive_t *drive, ide_task_t *task)
+@@ -817,6 +803,7 @@ static void __devinit init_hwif_siimage(ide_hwif_t *hwif)
+ 
+ 	hwif->set_pio_mode = &sil_set_pio_mode;
+ 	hwif->set_dma_mode = &sil_set_dma_mode;
++	hwif->quirkproc = &sil_quirkproc;
+ 
+ 	if (sata) {
+ 		static int first = 1;
+@@ -855,7 +842,6 @@ static void __devinit init_hwif_siimage(ide_hwif_t *hwif)
+ 		.init_chipset	= init_chipset_siimage,	\
+ 		.init_iops	= init_iops_siimage,	\
+ 		.init_hwif	= init_hwif_siimage,	\
+-		.fixup		= siimage_fixup,	\
+ 		.host_flags	= IDE_HFLAG_BOOTABLE,	\
+ 		.pio_mask	= ATA_PIO4,		\
+ 		.mwdma_mask	= ATA_MWDMA2,		\
+diff --git a/drivers/ide/pci/sis5513.c b/drivers/ide/pci/sis5513.c
+index d90b429..85d3699 100644
+--- a/drivers/ide/pci/sis5513.c
++++ b/drivers/ide/pci/sis5513.c
+@@ -305,59 +305,56 @@ static void sis_set_pio_mode(ide_drive_t *drive, const u8 pio)
+ 	sis_program_timings(drive, XFER_PIO_0 + pio);
+ }
+ 
+-static void sis_set_dma_mode(ide_drive_t *drive, const u8 speed)
++static void sis_ata133_program_udma_timings(ide_drive_t *drive, const u8 mode)
  {
--	u16 *p = buffer;
+-	ide_hwif_t *hwif	= HWIF(drive);
+-	struct pci_dev *dev	= hwif->pci_dev;
++	struct pci_dev *dev = drive->hwif->pci_dev;
++	u32 regdw = 0;
++	u8 drive_pci = sis_ata133_get_base(drive), clk, idx;
+ 
+-	/* Config chip for mode */
+-	switch(speed) {
+-		case XFER_UDMA_6:
+-		case XFER_UDMA_5:
+-		case XFER_UDMA_4:
+-		case XFER_UDMA_3:
+-		case XFER_UDMA_2:
+-		case XFER_UDMA_1:
+-		case XFER_UDMA_0:
+-			if (chipset_family >= ATA_133) {
+-				u32 regdw = 0;
+-				u8 drive_pci = sis_ata133_get_base(drive);
 -
--	while (wcount--) {
--		*p = *p << 8 | *p >> 8; p++;
--		*p = *p << 8 | *p >> 8; p++;
--	}
--}
+-				pci_read_config_dword(dev, drive_pci, &regdw);
+-				regdw |= 0x04;
+-				regdw &= 0xfffff00f;
+-				/* check if ATA133 enable */
+-				if (regdw & 0x08) {
+-					regdw |= (unsigned long)cycle_time_value[ATA_133][speed-XFER_UDMA_0] << 4;
+-					regdw |= (unsigned long)cvs_time_value[ATA_133][speed-XFER_UDMA_0] << 8;
+-				} else {
+-					regdw |= (unsigned long)cycle_time_value[ATA_100][speed-XFER_UDMA_0] << 4;
+-					regdw |= (unsigned long)cvs_time_value[ATA_100][speed-XFER_UDMA_0] << 8;
+-				}
+-				pci_write_config_dword(dev, (unsigned long)drive_pci, regdw);
+-			} else {
+-				u8 drive_pci = 0x40 + drive->dn * 2, reg = 0;
 -
--static void taskfile_input_data(ide_drive_t *drive, void *buffer, u32 wcount)
--{
--	HWIF(drive)->ata_input_data(drive, buffer, wcount);
--	if (drive->bswap)
--		ata_bswap_data(buffer, wcount);
--}
-+	ide_hwif_t *hwif = drive->hwif;
-+	struct ide_taskfile *tf = &task->tf;
-+	u8 HIHI = (task->tf_flags & IDE_TFLAG_LBA48) ? 0xE0 : 0xEF;
+-				pci_read_config_byte(dev, drive_pci+1, &reg);
+-				/* Force the UDMA bit on if we want to use UDMA */
+-				reg |= 0x80;
+-				/* clean reg cycle time bits */
+-				reg &= ~((0xFF >> (8 - cycle_time_range[chipset_family]))
+-					 << cycle_time_offset[chipset_family]);
+-				/* set reg cycle time bits */
+-				reg |= cycle_time_value[chipset_family][speed-XFER_UDMA_0]
+-					<< cycle_time_offset[chipset_family];
+-				pci_write_config_byte(dev, drive_pci+1, reg);
+-			}
+-			break;
+-		case XFER_MW_DMA_2:
+-		case XFER_MW_DMA_1:
+-		case XFER_MW_DMA_0:
+-			sis_program_timings(drive, speed);
+-			break;
+-		default:
+-			break;
+-	}
++	pci_read_config_dword(dev, drive_pci, &regdw);
 +
-+	if (task->tf_flags & IDE_TFLAG_FLAGGED)
-+		HIHI = 0xFF;
++	regdw |= 0x04;
++	regdw &= 0xfffff00f;
++	/* check if ATA133 enable */
++	clk = (regdw & 0x08) ? ATA_133 : ATA_100;
++	idx = mode - XFER_UDMA_0;
++	regdw |= cycle_time_value[clk][idx] << 4;
++	regdw |= cvs_time_value[clk][idx] << 8;
 +
-+#ifdef DEBUG
-+	printk("%s: tf: feat 0x%02x nsect 0x%02x lbal 0x%02x "
-+		"lbam 0x%02x lbah 0x%02x dev 0x%02x cmd 0x%02x\n",
-+		drive->name, tf->feature, tf->nsect, tf->lbal,
-+		tf->lbam, tf->lbah, tf->device, tf->command);
-+	printk("%s: hob: nsect 0x%02x lbal 0x%02x "
-+		"lbam 0x%02x lbah 0x%02x\n",
-+		drive->name, tf->hob_nsect, tf->hob_lbal,
-+		tf->hob_lbam, tf->hob_lbah);
-+#endif
- 
--static void taskfile_output_data(ide_drive_t *drive, void *buffer, u32 wcount)
--{
--	if (drive->bswap) {
--		ata_bswap_data(buffer, wcount);
--		HWIF(drive)->ata_output_data(drive, buffer, wcount);
--		ata_bswap_data(buffer, wcount);
--	} else {
--		HWIF(drive)->ata_output_data(drive, buffer, wcount);
--	}
-+	ide_set_irq(drive, 1);
++	pci_write_config_dword(dev, drive_pci, regdw);
++}
 +
-+	if ((task->tf_flags & IDE_TFLAG_NO_SELECT_MASK) == 0)
-+		SELECT_MASK(drive, 0);
++static void sis_ata33_program_udma_timings(ide_drive_t *drive, const u8 mode)
++{
++	struct pci_dev *dev = drive->hwif->pci_dev;
++	u8 drive_pci = 0x40 + drive->dn * 2, reg = 0, i = chipset_family;
 +
-+	if (task->tf_flags & IDE_TFLAG_OUT_DATA)
-+		hwif->OUTW((tf->hob_data << 8) | tf->data, IDE_DATA_REG);
++	pci_read_config_byte(dev, drive_pci + 1, &reg);
 +
-+	if (task->tf_flags & IDE_TFLAG_OUT_HOB_FEATURE)
-+		hwif->OUTB(tf->hob_feature, IDE_FEATURE_REG);
-+	if (task->tf_flags & IDE_TFLAG_OUT_HOB_NSECT)
-+		hwif->OUTB(tf->hob_nsect, IDE_NSECTOR_REG);
-+	if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAL)
-+		hwif->OUTB(tf->hob_lbal, IDE_SECTOR_REG);
-+	if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAM)
-+		hwif->OUTB(tf->hob_lbam, IDE_LCYL_REG);
-+	if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAH)
-+		hwif->OUTB(tf->hob_lbah, IDE_HCYL_REG);
++	/* force the UDMA bit on if we want to use UDMA */
++	reg |= 0x80;
++	/* clean reg cycle time bits */
++	reg &= ~((0xff >> (8 - cycle_time_range[i])) << cycle_time_offset[i]);
++	/* set reg cycle time bits */
++	reg |= cycle_time_value[i][mode - XFER_UDMA_0] << cycle_time_offset[i];
 +
-+	if (task->tf_flags & IDE_TFLAG_OUT_FEATURE)
-+		hwif->OUTB(tf->feature, IDE_FEATURE_REG);
-+	if (task->tf_flags & IDE_TFLAG_OUT_NSECT)
-+		hwif->OUTB(tf->nsect, IDE_NSECTOR_REG);
-+	if (task->tf_flags & IDE_TFLAG_OUT_LBAL)
-+		hwif->OUTB(tf->lbal, IDE_SECTOR_REG);
-+	if (task->tf_flags & IDE_TFLAG_OUT_LBAM)
-+		hwif->OUTB(tf->lbam, IDE_LCYL_REG);
-+	if (task->tf_flags & IDE_TFLAG_OUT_LBAH)
-+		hwif->OUTB(tf->lbah, IDE_HCYL_REG);
++	pci_write_config_byte(dev, drive_pci + 1, reg);
++}
 +
-+	if (task->tf_flags & IDE_TFLAG_OUT_DEVICE)
-+		hwif->OUTB((tf->device & HIHI) | drive->select.all, IDE_SELECT_REG);
++static void sis_program_udma_timings(ide_drive_t *drive, const u8 mode)
++{
++	if (chipset_family >= ATA_133)	/* ATA_133 */
++		sis_ata133_program_udma_timings(drive, mode);
++	else				/* ATA_33/66/100a/100/133a */
++		sis_ata33_program_udma_timings(drive, mode);
++}
++
++static void sis_set_dma_mode(ide_drive_t *drive, const u8 speed)
++{
++	if (speed >= XFER_UDMA_0)
++		sis_program_udma_timings(drive, speed);
++	else
++		sis_program_timings(drive, speed);
  }
  
- int taskfile_lib_get_identify (ide_drive_t *drive, u8 *buf)
+ static u8 sis5513_ata133_udma_filter(ide_drive_t *drive)
+diff --git a/drivers/ide/pci/sl82c105.c b/drivers/ide/pci/sl82c105.c
+index 147d783..c7a125b 100644
+--- a/drivers/ide/pci/sl82c105.c
++++ b/drivers/ide/pci/sl82c105.c
+@@ -13,6 +13,7 @@
+  *  -- Benjamin Herrenschmidt (01/11/03) benh at kernel.crashing.org
+  *
+  * Copyright (C) 2006-2007 MontaVista Software, Inc. <source at mvista.com>
++ * Copyright (C)      2007 Bartlomiej Zolnierkiewicz
+  */
+ 
+ #include <linux/types.h>
+@@ -90,14 +91,8 @@ static void sl82c105_set_pio_mode(ide_drive_t *drive, const u8 pio)
+ 	drive->drive_data &= 0xffff0000;
+ 	drive->drive_data |= drv_ctrl;
+ 
+-	if (!drive->using_dma) {
+-		/*
+-		 * If we are actually using MW DMA, then we can not
+-		 * reprogram the interface drive control register.
+-		 */
+-		pci_write_config_word(dev, reg,  drv_ctrl);
+-		pci_read_config_word (dev, reg, &drv_ctrl);
+-	}
++	pci_write_config_word(dev, reg,  drv_ctrl);
++	pci_read_config_word (dev, reg, &drv_ctrl);
+ 
+ 	printk(KERN_DEBUG "%s: selected %s (%dns) (%04X)\n", drive->name,
+ 			  ide_xfer_verbose(pio + XFER_PIO_0),
+@@ -115,33 +110,14 @@ static void sl82c105_set_dma_mode(ide_drive_t *drive, const u8 speed)
+  	DBG(("sl82c105_tune_chipset(drive:%s, speed:%s)\n",
+ 	     drive->name, ide_xfer_verbose(speed)));
+ 
+-	switch (speed) {
+-	case XFER_MW_DMA_2:
+-	case XFER_MW_DMA_1:
+-	case XFER_MW_DMA_0:
+-		drv_ctrl = mwdma_timings[speed - XFER_MW_DMA_0];
++	drv_ctrl = mwdma_timings[speed - XFER_MW_DMA_0];
+ 
+-		/*
+-		 * Store the DMA timings so that we can actually program
+-		 * them when DMA will be turned on...
+-		 */
+-		drive->drive_data &= 0x0000ffff;
+-		drive->drive_data |= (unsigned long)drv_ctrl << 16;
+-
+-		/*
+-		 * If we are already using DMA, we just reprogram
+-		 * the drive control register.
+-		 */
+-		if (drive->using_dma) {
+-			struct pci_dev *dev	= HWIF(drive)->pci_dev;
+-			int reg 		= 0x44 + drive->dn * 4;
+-
+-			pci_write_config_word(dev, reg, drv_ctrl);
+-		}
+-		break;
+-	default:
+-		return;
+-	}
++	/*
++	 * Store the DMA timings so that we can actually program
++	 * them when DMA will be turned on...
++	 */
++	drive->drive_data &= 0x0000ffff;
++	drive->drive_data |= (unsigned long)drv_ctrl << 16;
+ }
+ 
+ /*
+@@ -209,6 +185,11 @@ static void sl82c105_dma_start(ide_drive_t *drive)
  {
- 	ide_task_t args;
+ 	ide_hwif_t *hwif	= HWIF(drive);
+ 	struct pci_dev *dev	= hwif->pci_dev;
++	int reg 		= 0x44 + drive->dn * 4;
 +
- 	memset(&args, 0, sizeof(ide_task_t));
--	args.tfRegister[IDE_NSECTOR_OFFSET]	= 0x01;
-+	args.tf.nsect = 0x01;
- 	if (drive->media == ide_disk)
--		args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_IDENTIFY;
-+		args.tf.command = WIN_IDENTIFY;
- 	else
--		args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_PIDENTIFY;
--	args.command_type = IDE_DRIVE_TASK_IN;
--	args.data_phase   = TASKFILE_IN;
--	args.handler	  = &task_in_intr;
--	return ide_raw_taskfile(drive, &args, buf);
-+		args.tf.command = WIN_PIDENTIFY;
-+	args.tf_flags	= IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
-+	args.data_phase	= TASKFILE_IN;
-+	return ide_raw_taskfile(drive, &args, buf, 1);
++	DBG(("%s(drive:%s)\n", __FUNCTION__, drive->name));
++
++	pci_write_config_word(dev, reg, drive->drive_data >> 16);
+ 
+ 	sl82c105_reset_host(dev);
+ 	ide_dma_start(drive);
+@@ -222,64 +203,24 @@ static void sl82c105_dma_timeout(ide_drive_t *drive)
+ 	ide_dma_timeout(drive);
  }
  
--ide_startstop_t do_rw_taskfile (ide_drive_t *drive, ide_task_t *task)
-+static int inline task_dma_ok(ide_task_t *task)
- {
--	ide_hwif_t *hwif	= HWIF(drive);
--	task_struct_t *taskfile	= (task_struct_t *) task->tfRegister;
--	hob_struct_t *hobfile	= (hob_struct_t *) task->hobRegister;
--	u8 HIHI			= (drive->addressing == 1) ? 0xE0 : 0xEF;
+-static int sl82c105_ide_dma_on(ide_drive_t *drive)
+-{
+-	struct pci_dev *dev	= HWIF(drive)->pci_dev;
+-	int rc, reg 		= 0x44 + drive->dn * 4;
 -
--	/* ALL Command Block Executions SHALL clear nIEN, unless otherwise */
--	if (IDE_CONTROL_REG) {
--		/* clear nIEN */
--		hwif->OUTB(drive->ctl, IDE_CONTROL_REG);
--	}
--	SELECT_MASK(drive, 0);
+-	DBG(("sl82c105_ide_dma_on(drive:%s)\n", drive->name));
 -
--	if (drive->addressing == 1) {
--		hwif->OUTB(hobfile->feature, IDE_FEATURE_REG);
--		hwif->OUTB(hobfile->sector_count, IDE_NSECTOR_REG);
--		hwif->OUTB(hobfile->sector_number, IDE_SECTOR_REG);
--		hwif->OUTB(hobfile->low_cylinder, IDE_LCYL_REG);
--		hwif->OUTB(hobfile->high_cylinder, IDE_HCYL_REG);
+-	rc = __ide_dma_on(drive);
+-	if (rc == 0) {
+-		pci_write_config_word(dev, reg, drive->drive_data >> 16);
+-
+-		printk(KERN_INFO "%s: DMA enabled\n", drive->name);
 -	}
+-	return rc;
+-}
 -
--	hwif->OUTB(taskfile->feature, IDE_FEATURE_REG);
--	hwif->OUTB(taskfile->sector_count, IDE_NSECTOR_REG);
--	hwif->OUTB(taskfile->sector_number, IDE_SECTOR_REG);
--	hwif->OUTB(taskfile->low_cylinder, IDE_LCYL_REG);
--	hwif->OUTB(taskfile->high_cylinder, IDE_HCYL_REG);
+-static void sl82c105_dma_off_quietly(ide_drive_t *drive)
++static int sl82c105_dma_end(ide_drive_t *drive)
+ {
+ 	struct pci_dev *dev	= HWIF(drive)->pci_dev;
+ 	int reg 		= 0x44 + drive->dn * 4;
++	int ret;
+ 
+-	DBG(("sl82c105_dma_off_quietly(drive:%s)\n", drive->name));
++	DBG(("%s(drive:%s)\n", __FUNCTION__, drive->name));
+ 
+-	pci_write_config_word(dev, reg, drive->drive_data);
++	ret = __ide_dma_end(drive);
+ 
+-	ide_dma_off_quietly(drive);
+-}
++	pci_write_config_word(dev, reg, drive->drive_data);
+ 
+-/*
+- * Ok, that is nasty, but we must make sure the DMA timings
+- * won't be used for a PIO access. The solution here is
+- * to make sure the 16 bits mode is diabled on the channel
+- * when DMA is enabled, thus causing the chip to use PIO0
+- * timings for those operations.
+- */
+-static void sl82c105_selectproc(ide_drive_t *drive)
+-{
+-	ide_hwif_t *hwif	= HWIF(drive);
+-	struct pci_dev *dev	= hwif->pci_dev;
+-	u32 val, old, mask;
 -
--	hwif->OUTB((taskfile->device_head & HIHI) | drive->select.all, IDE_SELECT_REG);
+-	//DBG(("sl82c105_selectproc(drive:%s)\n", drive->name));
 -
--	if (task->handler != NULL) {
--		if (task->prehandler != NULL) {
--			hwif->OUTBSYNC(drive, taskfile->command, IDE_COMMAND_REG);
--			ndelay(400);	/* FIXME */
--			return task->prehandler(drive, task->rq);
--		}
--		ide_execute_command(drive, taskfile->command, task->handler, WAIT_WORSTCASE, NULL);
--		return ide_started;
+-	mask = hwif->channel ? CTRL_P1F16 : CTRL_P0F16;
+-	old = val = (u32)pci_get_drvdata(dev);
+-	if (drive->using_dma)
+-		val &= ~mask;
+-	else
+-		val |= mask;
+-	if (old != val) {
+-		pci_write_config_dword(dev, 0x40, val);	
+-		pci_set_drvdata(dev, (void *)val);
 -	}
-+	if (blk_fs_request(task->rq) || (task->tf_flags & IDE_TFLAG_FLAGGED))
-+		return 1;
- 
--	if (!drive->using_dma)
--		return ide_stopped;
--
--	switch (taskfile->command) {
-+	switch (task->tf.command) {
- 		case WIN_WRITEDMA_ONCE:
- 		case WIN_WRITEDMA:
- 		case WIN_WRITEDMA_EXT:
-@@ -129,24 +117,79 @@ ide_startstop_t do_rw_taskfile (ide_drive_t *drive, ide_task_t *task)
- 		case WIN_READDMA:
- 		case WIN_READDMA_EXT:
- 		case WIN_IDENTIFY_DMA:
--			if (!hwif->dma_setup(drive)) {
--				hwif->dma_exec_cmd(drive, taskfile->command);
--				hwif->dma_start(drive);
--				return ide_started;
--			}
--			break;
--		default:
--			if (task->handler == NULL)
--				return ide_stopped;
-+			return 1;
- 	}
- 
--	return ide_stopped;
-+	return 0;
++	return ret;
  }
  
-+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 *);
-+
-+ide_startstop_t do_rw_taskfile (ide_drive_t *drive, ide_task_t *task)
-+{
-+	ide_hwif_t *hwif	= HWIF(drive);
-+	struct ide_taskfile *tf = &task->tf;
-+	ide_handler_t *handler = NULL;
-+
-+	if (task->data_phase == TASKFILE_MULTI_IN ||
-+	    task->data_phase == TASKFILE_MULTI_OUT) {
-+		if (!drive->mult_count) {
-+			printk(KERN_ERR "%s: multimode not set!\n",
-+					drive->name);
-+			return ide_stopped;
-+		}
-+	}
-+
-+	if (task->tf_flags & IDE_TFLAG_FLAGGED)
-+		task->tf_flags |= IDE_TFLAG_FLAGGED_SET_IN_FLAGS;
-+
-+	if ((task->tf_flags & IDE_TFLAG_DMA_PIO_FALLBACK) == 0)
-+		ide_tf_load(drive, task);
-+
-+	switch (task->data_phase) {
-+	case TASKFILE_MULTI_OUT:
-+	case TASKFILE_OUT:
-+		hwif->OUTBSYNC(drive, tf->command, IDE_COMMAND_REG);
-+		ndelay(400);	/* FIXME */
-+		return pre_task_out_intr(drive, task->rq);
-+	case TASKFILE_MULTI_IN:
-+	case TASKFILE_IN:
-+		handler = task_in_intr;
-+		/* fall-through */
-+	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 (task_dma_ok(task) == 0 || drive->using_dma == 0 ||
-+		    hwif->dma_setup(drive))
-+			return ide_stopped;
-+		hwif->dma_exec_cmd(drive, tf->command);
-+		hwif->dma_start(drive);
-+		return ide_started;
-+	}
-+}
-+EXPORT_SYMBOL_GPL(do_rw_taskfile);
-+
- /*
-  * set_multmode_intr() is invoked on completion of a WIN_SETMULT cmd.
-  */
--ide_startstop_t set_multmode_intr (ide_drive_t *drive)
-+static ide_startstop_t set_multmode_intr(ide_drive_t *drive)
- {
- 	ide_hwif_t *hwif = HWIF(drive);
- 	u8 stat;
-@@ -164,7 +207,7 @@ ide_startstop_t set_multmode_intr (ide_drive_t *drive)
- /*
-  * set_geometry_intr() is invoked on completion of a WIN_SPECIFY cmd.
-  */
--ide_startstop_t set_geometry_intr (ide_drive_t *drive)
-+static ide_startstop_t set_geometry_intr(ide_drive_t *drive)
- {
- 	ide_hwif_t *hwif = HWIF(drive);
- 	int retries = 5;
-@@ -187,7 +230,7 @@ ide_startstop_t set_geometry_intr (ide_drive_t *drive)
  /*
-  * recal_intr() is invoked on completion of a WIN_RESTORE (recalibrate) cmd.
+  * ATA reset will clear the 16 bits mode in the control
+- * register, we need to update our cache
++ * register, we need to reprogram it
   */
--ide_startstop_t recal_intr (ide_drive_t *drive)
-+static ide_startstop_t recal_intr(ide_drive_t *drive)
+ static void sl82c105_resetproc(ide_drive_t *drive)
  {
- 	ide_hwif_t *hwif = HWIF(drive);
- 	u8 stat;
-@@ -200,7 +243,7 @@ ide_startstop_t recal_intr (ide_drive_t *drive)
+@@ -289,7 +230,8 @@ static void sl82c105_resetproc(ide_drive_t *drive)
+ 	DBG(("sl82c105_resetproc(drive:%s)\n", drive->name));
+ 
+ 	pci_read_config_dword(dev, 0x40, &val);
+-	pci_set_drvdata(dev, (void *)val);
++	val |= (CTRL_P1F16 | CTRL_P0F16);
++	pci_write_config_dword(dev, 0x40, val);
+ }
+ 
  /*
-  * Handler for commands without a data phase
-  */
--ide_startstop_t task_no_data_intr (ide_drive_t *drive)
-+static ide_startstop_t task_no_data_intr(ide_drive_t *drive)
- {
- 	ide_task_t *args	= HWGROUP(drive)->rq->special;
- 	ide_hwif_t *hwif	= HWIF(drive);
-@@ -217,9 +260,7 @@ ide_startstop_t task_no_data_intr (ide_drive_t *drive)
- 	return ide_stopped;
+@@ -342,7 +284,6 @@ static unsigned int __devinit init_chipset_sl82c105(struct pci_dev *dev, const c
+ 	pci_read_config_dword(dev, 0x40, &val);
+ 	val |= CTRL_P0EN | CTRL_P0F16 | CTRL_P1F16;
+ 	pci_write_config_dword(dev, 0x40, val);
+-	pci_set_drvdata(dev, (void *)val);
+ 
+ 	return dev->irq;
  }
+@@ -358,7 +299,6 @@ static void __devinit init_hwif_sl82c105(ide_hwif_t *hwif)
  
--EXPORT_SYMBOL(task_no_data_intr);
+ 	hwif->set_pio_mode	= &sl82c105_set_pio_mode;
+ 	hwif->set_dma_mode	= &sl82c105_set_dma_mode;
+-	hwif->selectproc	= &sl82c105_selectproc;
+ 	hwif->resetproc 	= &sl82c105_resetproc;
+ 
+ 	if (!hwif->dma_base)
+@@ -377,10 +317,9 @@ static void __devinit init_hwif_sl82c105(ide_hwif_t *hwif)
+ 
+ 	hwif->mwdma_mask = ATA_MWDMA2;
+ 
+-	hwif->ide_dma_on		= &sl82c105_ide_dma_on;
+-	hwif->dma_off_quietly		= &sl82c105_dma_off_quietly;
+ 	hwif->dma_lost_irq		= &sl82c105_dma_lost_irq;
+ 	hwif->dma_start			= &sl82c105_dma_start;
++	hwif->ide_dma_end		= &sl82c105_dma_end;
+ 	hwif->dma_timeout		= &sl82c105_dma_timeout;
+ 
+ 	if (hwif->mate)
+diff --git a/drivers/ide/pci/slc90e66.c b/drivers/ide/pci/slc90e66.c
+index eb4445b..dbbb468 100644
+--- a/drivers/ide/pci/slc90e66.c
++++ b/drivers/ide/pci/slc90e66.c
+@@ -91,19 +91,9 @@ static void slc90e66_set_dma_mode(ide_drive_t *drive, const u8 speed)
+ 	pci_read_config_word(dev, 0x48, &reg48);
+ 	pci_read_config_word(dev, 0x4a, &reg4a);
+ 
+-	switch(speed) {
+-		case XFER_UDMA_4:	u_speed = 4 << (drive->dn * 4); break;
+-		case XFER_UDMA_3:	u_speed = 3 << (drive->dn * 4); break;
+-		case XFER_UDMA_2:	u_speed = 2 << (drive->dn * 4); break;
+-		case XFER_UDMA_1:	u_speed = 1 << (drive->dn * 4); break;
+-		case XFER_UDMA_0:	u_speed = 0 << (drive->dn * 4); break;
+-		case XFER_MW_DMA_2:
+-		case XFER_MW_DMA_1:
+-		case XFER_SW_DMA_2:	break;
+-		default:		return;
+-	}
 -
--static u8 wait_drive_not_busy(ide_drive_t *drive)
-+u8 wait_drive_not_busy(ide_drive_t *drive)
+ 	if (speed >= XFER_UDMA_0) {
++		u_speed = (speed - XFER_UDMA_0) << (drive->dn * 4);
++
+ 		if (!(reg48 & u_flag))
+ 			pci_write_config_word(dev, 0x48, reg48|u_flag);
+ 		/* FIXME: (reg4a & a_speed) ? */
+diff --git a/drivers/ide/pci/tc86c001.c b/drivers/ide/pci/tc86c001.c
+index a66ebd1..e1faf6c 100644
+--- a/drivers/ide/pci/tc86c001.c
++++ b/drivers/ide/pci/tc86c001.c
+@@ -222,7 +222,8 @@ static const struct ide_port_info tc86c001_chipset __devinitdata = {
+ 	.name		= "TC86C001",
+ 	.init_chipset	= init_chipset_tc86c001,
+ 	.init_hwif	= init_hwif_tc86c001,
+-	.host_flags	= IDE_HFLAG_SINGLE | IDE_HFLAG_OFF_BOARD,
++	.host_flags	= IDE_HFLAG_SINGLE | IDE_HFLAG_OFF_BOARD |
++			  IDE_HFLAG_ABUSE_SET_DMA_MODE,
+ 	.pio_mask	= ATA_PIO4,
+ 	.mwdma_mask	= ATA_MWDMA2,
+ 	.udma_mask	= ATA_UDMA4,
+diff --git a/drivers/ide/pci/triflex.c b/drivers/ide/pci/triflex.c
+index a227c41..ae52a96 100644
+--- a/drivers/ide/pci/triflex.c
++++ b/drivers/ide/pci/triflex.c
+@@ -81,8 +81,6 @@ static void triflex_set_mode(ide_drive_t *drive, const u8 speed)
+ 		case XFER_PIO_0:
+ 			timing = 0x0808;
+ 			break;
+-		default:
+-			return;
+ 	}
+ 
+ 	triflex_timings &= ~(0xFFFF << (16 * unit));
+diff --git a/drivers/ide/pci/trm290.c b/drivers/ide/pci/trm290.c
+index 0151d7f..04cd893 100644
+--- a/drivers/ide/pci/trm290.c
++++ b/drivers/ide/pci/trm290.c
+@@ -241,11 +241,7 @@ static int trm290_ide_dma_test_irq (ide_drive_t *drive)
+ 	return (status == 0x00ff);
+ }
+ 
+-static void trm290_dma_host_on(ide_drive_t *drive)
+-{
+-}
+-
+-static void trm290_dma_host_off(ide_drive_t *drive)
++static void trm290_dma_host_set(ide_drive_t *drive, int on)
  {
- 	ide_hwif_t *hwif = HWIF(drive);
- 	int retries;
-@@ -227,8 +268,7 @@ static u8 wait_drive_not_busy(ide_drive_t *drive)
+ }
  
- 	/*
- 	 * Last sector was transfered, wait until drive is ready.
--	 * This can take up to 10 usec, but we will wait max 1 ms
--	 * (drive_cmd_intr() waits that long).
-+	 * This can take up to 10 usec, but we will wait max 1 ms.
- 	 */
- 	for (retries = 0; retries < 100; retries++) {
- 		if ((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT)
-@@ -283,9 +323,9 @@ static void ide_pio_sector(ide_drive_t *drive, unsigned int write)
+@@ -289,8 +285,7 @@ static void __devinit init_hwif_trm290(ide_hwif_t *hwif)
  
- 	/* do the actual data transfer */
- 	if (write)
--		taskfile_output_data(drive, buf, SECTOR_WORDS);
-+		hwif->ata_output_data(drive, buf, SECTOR_WORDS);
- 	else
--		taskfile_input_data(drive, buf, SECTOR_WORDS);
-+		hwif->ata_input_data(drive, buf, SECTOR_WORDS);
+ 	ide_setup_dma(hwif, (hwif->config_data + 4) ^ (hwif->channel ? 0x0080 : 0x0000), 3);
  
- 	kunmap_atomic(buf, KM_BIO_SRC_IRQ);
- #ifdef CONFIG_HIGHMEM
-@@ -305,9 +345,18 @@ static void ide_pio_multi(ide_drive_t *drive, unsigned int write)
- static void ide_pio_datablock(ide_drive_t *drive, struct request *rq,
- 				     unsigned int write)
- {
-+	u8 saved_io_32bit = drive->io_32bit;
+-	hwif->dma_host_off	= &trm290_dma_host_off;
+-	hwif->dma_host_on	= &trm290_dma_host_on;
++	hwif->dma_host_set	= &trm290_dma_host_set;
+ 	hwif->dma_setup 	= &trm290_dma_setup;
+ 	hwif->dma_exec_cmd	= &trm290_dma_exec_cmd;
+ 	hwif->dma_start 	= &trm290_dma_start;
+diff --git a/drivers/ide/pci/via82cxxx.c b/drivers/ide/pci/via82cxxx.c
+index a0d3c16..4b32c90 100644
+--- a/drivers/ide/pci/via82cxxx.c
++++ b/drivers/ide/pci/via82cxxx.c
+@@ -439,6 +439,7 @@ static const struct ide_port_info via82cxxx_chipset __devinitdata = {
+ 	.enablebits	= { { 0x40, 0x02, 0x02 }, { 0x40, 0x01, 0x01 } },
+ 	.host_flags	= IDE_HFLAG_PIO_NO_BLACKLIST |
+ 			  IDE_HFLAG_PIO_NO_DOWNGRADE |
++			  IDE_HFLAG_ABUSE_SET_DMA_MODE |
+ 			  IDE_HFLAG_POST_SET_MODE |
+ 			  IDE_HFLAG_IO_32BIT |
+ 			  IDE_HFLAG_BOOTABLE,
+diff --git a/drivers/ide/ppc/Makefile b/drivers/ide/ppc/Makefile
+new file mode 100644
+index 0000000..65af584
+--- /dev/null
++++ b/drivers/ide/ppc/Makefile
+@@ -0,0 +1,3 @@
 +
- 	if (rq->bio)	/* fs request */
- 		rq->errors = 0;
- 
-+	if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) {
-+		ide_task_t *task = rq->special;
++obj-$(CONFIG_BLK_DEV_IDE_PMAC)		+= pmac.o
++obj-$(CONFIG_BLK_DEV_MPC8xx_IDE)	+= mpc8xx.o
+diff --git a/drivers/ide/ppc/mpc8xx.c b/drivers/ide/ppc/mpc8xx.c
+index 5f0da35..3fd5d45 100644
+--- a/drivers/ide/ppc/mpc8xx.c
++++ b/drivers/ide/ppc/mpc8xx.c
+@@ -838,3 +838,21 @@ void m8xx_ide_init(void)
+ 	ppc_ide_md.default_io_base      = m8xx_ide_default_io_base;
+ 	ppc_ide_md.ide_init_hwif        = m8xx_ide_init_hwif_ports;
+ }
 +
-+		if (task->tf_flags & IDE_TFLAG_IO_16BIT)
-+			drive->io_32bit = 0;
-+	}
++static int __init mpc8xx_ide_probe(void)
++{
++	u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
 +
- 	touch_softlockup_watchdog();
- 
- 	switch (drive->hwif->data_phase) {
-@@ -319,6 +368,8 @@ static void ide_pio_datablock(ide_drive_t *drive, struct request *rq,
- 		ide_pio_sector(drive, write);
- 		break;
- 	}
++#ifdef IDE0_BASE_OFFSET
++	idx[0] = 0;
++#ifdef IDE1_BASE_OFFSET
++	idx[1] = 1;
++#endif
++#endif
 +
-+	drive->io_32bit = saved_io_32bit;
- }
++	ide_device_add(idx);
++
++	return 0;
++}
++
++module_init(mpc8xx_ide_probe);
+diff --git a/drivers/ide/ppc/pmac.c b/drivers/ide/ppc/pmac.c
+index 7f7a598..736d12c 100644
+--- a/drivers/ide/ppc/pmac.c
++++ b/drivers/ide/ppc/pmac.c
+@@ -438,13 +438,8 @@ pmac_ide_init_hwif_ports(hw_regs_t *hw,
+ 		if (data_port == pmac_ide[ix].regbase)
+ 			break;
  
- static ide_startstop_t task_error(ide_drive_t *drive, struct request *rq,
-@@ -356,40 +407,35 @@ static ide_startstop_t task_error(ide_drive_t *drive, struct request *rq,
- 	return ide_error(drive, s, stat);
- }
+-	if (ix >= MAX_HWIFS) {
+-		/* Probably a PCI interface... */
+-		for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; ++i)
+-			hw->io_ports[i] = data_port + i - IDE_DATA_OFFSET;
+-		hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port;
+-		return;
+-	}
++	if (ix >= MAX_HWIFS)
++		return;		/* not an IDE PMAC interface */
  
--static void task_end_request(ide_drive_t *drive, struct request *rq, u8 stat)
-+void task_end_request(ide_drive_t *drive, struct request *rq, u8 stat)
- {
--	HWIF(drive)->cursg = NULL;
--
- 	if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) {
--		ide_task_t *task = rq->special;
-+		u8 err = drive->hwif->INB(IDE_ERROR_REG);
+ 	for (i = 0; i < 8; ++i)
+ 		hw->io_ports[i] = data_port + i * 0x10;
+@@ -833,38 +828,20 @@ static void pmac_ide_set_dma_mode(ide_drive_t *drive, const u8 speed)
+ 	tl[0] = *timings;
+ 	tl[1] = *timings2;
  
--		if (task->tf_out_flags.all) {
--			u8 err = drive->hwif->INB(IDE_ERROR_REG);
--			ide_end_drive_cmd(drive, stat, err);
+-	switch(speed) {
+ #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
+-		case XFER_UDMA_6:
+-		case XFER_UDMA_5:
+-		case XFER_UDMA_4:
+-		case XFER_UDMA_3:
+-		case XFER_UDMA_2:
+-		case XFER_UDMA_1:
+-		case XFER_UDMA_0:
+-			if (pmif->kind == controller_kl_ata4)
+-				ret = set_timings_udma_ata4(&tl[0], speed);
+-			else if (pmif->kind == controller_un_ata6
+-				 || pmif->kind == controller_k2_ata6)
+-				ret = set_timings_udma_ata6(&tl[0], &tl[1], speed);
+-			else if (pmif->kind == controller_sh_ata6)
+-				ret = set_timings_udma_shasta(&tl[0], &tl[1], speed);
+-			else
+-				ret = 1;
+-			break;
+-		case XFER_MW_DMA_2:
+-		case XFER_MW_DMA_1:
+-		case XFER_MW_DMA_0:
+-			set_timings_mdma(drive, pmif->kind, &tl[0], &tl[1], speed);
+-			break;
+-		case XFER_SW_DMA_2:
+-		case XFER_SW_DMA_1:
+-		case XFER_SW_DMA_0:
 -			return;
--		}
-+		ide_end_drive_cmd(drive, stat, err);
-+		return;
- 	}
++	if (speed >= XFER_UDMA_0) {
++		if (pmif->kind == controller_kl_ata4)
++			ret = set_timings_udma_ata4(&tl[0], speed);
++		else if (pmif->kind == controller_un_ata6
++			 || pmif->kind == controller_k2_ata6)
++			ret = set_timings_udma_ata6(&tl[0], &tl[1], speed);
++		else if (pmif->kind == controller_sh_ata6)
++			ret = set_timings_udma_shasta(&tl[0], &tl[1], speed);
++		else
++			ret = -1;
++	} else
++		set_timings_mdma(drive, pmif->kind, &tl[0], &tl[1], speed);
+ #endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
+-		default:
+-			ret = 1;
+-	}
+ 	if (ret)
+ 		return;
  
- 	if (rq->rq_disk) {
- 		ide_driver_t *drv;
+@@ -1035,12 +1012,11 @@ pmac_ide_do_resume(ide_hwif_t *hwif)
+  * rare machines unfortunately, but it's better this way.
+  */
+ static int
+-pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif)
++pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif, hw_regs_t *hw)
+ {
+ 	struct device_node *np = pmif->node;
+ 	const int *bidp;
+ 	u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
+-	hw_regs_t hw;
+ 
+ 	pmif->cable_80 = 0;
+ 	pmif->broken_dma = pmif->broken_dma_warn = 0;
+@@ -1126,11 +1102,9 @@ pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif)
+ 	/* Tell common code _not_ to mess with resources */
+ 	hwif->mmio = 1;
+ 	hwif->hwif_data = pmif;
+-	memset(&hw, 0, sizeof(hw));
+-	pmac_ide_init_hwif_ports(&hw, pmif->regbase, 0, &hwif->irq);
+-	memcpy(hwif->io_ports, hw.io_ports, sizeof(hwif->io_ports));
+-	hwif->chipset = ide_pmac;
+-	hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET] || pmif->mediabay;
++	hw->chipset = ide_pmac;
++	ide_init_port_hw(hwif, hw);
++	hwif->noprobe = pmif->mediabay;
+ 	hwif->hold = pmif->mediabay;
+ 	hwif->cbl = pmif->cable_80 ? ATA_CBL_PATA80 : ATA_CBL_PATA40;
+ 	hwif->drives[0].unmask = 1;
+@@ -1159,8 +1133,6 @@ pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif)
+ 		hwif->noprobe = 0;
+ #endif /* CONFIG_PMAC_MEDIABAY */
+ 
+-	hwif->sg_max_nents = MAX_DCMDS;
+-
+ #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
+ 	/* has a DBDMA controller channel */
+ 	if (pmif->dma_regs)
+@@ -1186,6 +1158,7 @@ pmac_ide_macio_attach(struct macio_dev *mdev, const struct of_device_id *match)
+ 	ide_hwif_t *hwif;
+ 	pmac_ide_hwif_t *pmif;
+ 	int i, rc;
++	hw_regs_t hw;
  
- 		drv = *(ide_driver_t **)rq->rq_disk->private_data;;
--		drv->end_request(drive, 1, rq->hard_nr_sectors);
-+		drv->end_request(drive, 1, rq->nr_sectors);
- 	} else
--		ide_end_request(drive, 1, rq->hard_nr_sectors);
-+		ide_end_request(drive, 1, rq->nr_sectors);
- }
+ 	i = 0;
+ 	while (i < MAX_HWIFS && (ide_hwifs[i].io_ports[IDE_DATA_OFFSET] != 0
+@@ -1228,7 +1201,6 @@ pmac_ide_macio_attach(struct macio_dev *mdev, const struct of_device_id *match)
+ 	regbase = (unsigned long) base;
  
- /*
-  * Handler for command with PIO data-in phase (Read/Read Multiple).
-  */
--ide_startstop_t task_in_intr (ide_drive_t *drive)
-+static ide_startstop_t task_in_intr(ide_drive_t *drive)
- {
- 	ide_hwif_t *hwif = drive->hwif;
- 	struct request *rq = HWGROUP(drive)->rq;
- 	u8 stat = hwif->INB(IDE_STATUS_REG);
+ 	hwif->pci_dev = mdev->bus->pdev;
+-	hwif->gendev.parent = &mdev->ofdev.dev;
  
- 	/* new way for dealing with premature shared PCI interrupts */
--	if (!OK_STAT(stat, DATA_READY, BAD_R_STAT)) {
-+	if (!OK_STAT(stat, DRQ_STAT, BAD_R_STAT)) {
- 		if (stat & (ERR_STAT | DRQ_STAT))
- 			return task_error(drive, rq, __FUNCTION__, stat);
- 		/* No data yet, so wait for another IRQ. */
-@@ -402,7 +448,7 @@ ide_startstop_t task_in_intr (ide_drive_t *drive)
- 	/* If it was the last datablock check status and finish transfer. */
- 	if (!hwif->nleft) {
- 		stat = wait_drive_not_busy(drive);
--		if (!OK_STAT(stat, 0, BAD_R_STAT))
-+		if (!OK_STAT(stat, 0, BAD_STAT))
- 			return task_error(drive, rq, __FUNCTION__, stat);
- 		task_end_request(drive, rq, stat);
- 		return ide_stopped;
-@@ -413,7 +459,6 @@ ide_startstop_t task_in_intr (ide_drive_t *drive)
+ 	pmif->mdev = mdev;
+ 	pmif->node = mdev->ofdev.node;
+@@ -1246,7 +1218,12 @@ pmac_ide_macio_attach(struct macio_dev *mdev, const struct of_device_id *match)
+ #endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
+ 	dev_set_drvdata(&mdev->ofdev.dev, hwif);
  
- 	return ide_started;
- }
--EXPORT_SYMBOL(task_in_intr);
+-	rc = pmac_ide_setup_device(pmif, hwif);
++	memset(&hw, 0, sizeof(hw));
++	pmac_ide_init_hwif_ports(&hw, pmif->regbase, 0, NULL);
++	hw.irq = irq;
++	hw.dev = &mdev->ofdev.dev;
++
++	rc = pmac_ide_setup_device(pmif, hwif, &hw);
+ 	if (rc != 0) {
+ 		/* The inteface is released to the common IDE layer */
+ 		dev_set_drvdata(&mdev->ofdev.dev, NULL);
+@@ -1305,6 +1282,7 @@ pmac_ide_pci_attach(struct pci_dev *pdev, const struct pci_device_id *id)
+ 	void __iomem *base;
+ 	unsigned long rbase, rlen;
+ 	int i, rc;
++	hw_regs_t hw;
  
- /*
-  * Handler for command with PIO data-out phase (Write/Write Multiple).
-@@ -443,11 +488,11 @@ static ide_startstop_t task_out_intr (ide_drive_t *drive)
- 	return ide_started;
- }
+ 	np = pci_device_to_OF_node(pdev);
+ 	if (np == NULL) {
+@@ -1338,7 +1316,6 @@ pmac_ide_pci_attach(struct pci_dev *pdev, const struct pci_device_id *id)
+ 	}
  
--ide_startstop_t pre_task_out_intr (ide_drive_t *drive, struct request *rq)
-+static ide_startstop_t pre_task_out_intr(ide_drive_t *drive, struct request *rq)
- {
- 	ide_startstop_t startstop;
+ 	hwif->pci_dev = pdev;
+-	hwif->gendev.parent = &pdev->dev;
+ 	pmif->mdev = NULL;
+ 	pmif->node = np;
  
--	if (ide_wait_stat(&startstop, drive, DATA_READY,
-+	if (ide_wait_stat(&startstop, drive, DRQ_STAT,
- 			  drive->bad_wstat, WAIT_DRQ)) {
- 		printk(KERN_ERR "%s: no DRQ after issuing %sWRITE%s\n",
- 				drive->name,
-@@ -464,9 +509,8 @@ ide_startstop_t pre_task_out_intr (ide_drive_t *drive, struct request *rq)
+@@ -1355,7 +1332,12 @@ pmac_ide_pci_attach(struct pci_dev *pdev, const struct pci_device_id *id)
  
- 	return ide_started;
- }
--EXPORT_SYMBOL(pre_task_out_intr);
+ 	pci_set_drvdata(pdev, hwif);
  
--static int ide_diag_taskfile(ide_drive_t *drive, ide_task_t *args, unsigned long data_size, u8 *buf)
-+int ide_raw_taskfile(ide_drive_t *drive, ide_task_t *task, u8 *buf, u16 nsect)
- {
- 	struct request rq;
+-	rc = pmac_ide_setup_device(pmif, hwif);
++	memset(&hw, 0, sizeof(hw));
++	pmac_ide_init_hwif_ports(&hw, pmif->regbase, 0, NULL);
++	hw.irq = pdev->irq;
++	hw.dev = &pdev->dev;
++
++	rc = pmac_ide_setup_device(pmif, hwif, &hw);
+ 	if (rc != 0) {
+ 		/* The inteface is released to the common IDE layer */
+ 		pci_set_drvdata(pdev, NULL);
+@@ -1721,11 +1703,7 @@ pmac_ide_dma_test_irq (ide_drive_t *drive)
+ 	return 1;
+ }
  
-@@ -481,36 +525,27 @@ static int ide_diag_taskfile(ide_drive_t *drive, ide_task_t *args, unsigned long
- 	 * if we would find a solution to transfer any size.
- 	 * To support special commands like READ LONG.
- 	 */
--	if (args->command_type != IDE_DRIVE_TASK_NO_DATA) {
--		if (data_size == 0)
--			rq.nr_sectors = (args->hobRegister[IDE_NSECTOR_OFFSET] << 8) | args->tfRegister[IDE_NSECTOR_OFFSET];
--		else
--			rq.nr_sectors = data_size / SECTOR_SIZE;
+-static void pmac_ide_dma_host_off(ide_drive_t *drive)
+-{
+-}
 -
--		if (!rq.nr_sectors) {
--			printk(KERN_ERR "%s: in/out command without data\n",
--					drive->name);
--			return -EFAULT;
--		}
-+	rq.hard_nr_sectors = rq.nr_sectors = nsect;
-+	rq.hard_cur_sectors = rq.current_nr_sectors = nsect;
+-static void pmac_ide_dma_host_on(ide_drive_t *drive)
++static void pmac_ide_dma_host_set(ide_drive_t *drive, int on)
+ {
+ }
  
--		rq.hard_nr_sectors = rq.nr_sectors;
--		rq.hard_cur_sectors = rq.current_nr_sectors = rq.nr_sectors;
-+	if (task->tf_flags & IDE_TFLAG_WRITE)
-+		rq.cmd_flags |= REQ_RW;
+@@ -1771,15 +1749,14 @@ pmac_ide_setup_dma(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif)
+ 		return;
+ 	}
  
--		if (args->command_type == IDE_DRIVE_TASK_RAW_WRITE)
--			rq.cmd_flags |= REQ_RW;
--	}
-+	rq.special = task;
-+	task->rq = &rq;
+-	hwif->dma_off_quietly = &ide_dma_off_quietly;
+-	hwif->ide_dma_on = &__ide_dma_on;
++	hwif->sg_max_nents = MAX_DCMDS;
++
++	hwif->dma_host_set = &pmac_ide_dma_host_set;
+ 	hwif->dma_setup = &pmac_ide_dma_setup;
+ 	hwif->dma_exec_cmd = &pmac_ide_dma_exec_cmd;
+ 	hwif->dma_start = &pmac_ide_dma_start;
+ 	hwif->ide_dma_end = &pmac_ide_dma_end;
+ 	hwif->ide_dma_test_irq = &pmac_ide_dma_test_irq;
+-	hwif->dma_host_off = &pmac_ide_dma_host_off;
+-	hwif->dma_host_on = &pmac_ide_dma_host_on;
+ 	hwif->dma_timeout = &ide_dma_timeout;
+ 	hwif->dma_lost_irq = &pmac_ide_dma_lost_irq;
  
--	rq.special = args;
--	args->rq = &rq;
- 	return ide_do_drive_cmd(drive, &rq, ide_wait);
+@@ -1809,3 +1786,5 @@ pmac_ide_setup_dma(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif)
  }
  
--int ide_raw_taskfile (ide_drive_t *drive, ide_task_t *args, u8 *buf)
-+EXPORT_SYMBOL(ide_raw_taskfile);
+ #endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
 +
-+int ide_no_data_taskfile(ide_drive_t *drive, ide_task_t *task)
- {
--	return ide_diag_taskfile(drive, args, 0, buf);
--}
-+	task->data_phase = TASKFILE_NO_DATA;
- 
--EXPORT_SYMBOL(ide_raw_taskfile);
-+	return ide_raw_taskfile(drive, task, NULL, 0);
-+}
-+EXPORT_SYMBOL_GPL(ide_no_data_taskfile);
++module_init(pmac_ide_probe);
+diff --git a/drivers/ide/setup-pci.c b/drivers/ide/setup-pci.c
+index d2cd5a3..676c66e 100644
+--- a/drivers/ide/setup-pci.c
++++ b/drivers/ide/setup-pci.c
+@@ -165,13 +165,17 @@ static unsigned long ide_get_or_set_dma_base(const struct ide_port_info *d, ide_
  
- #ifdef CONFIG_IDE_TASK_IOCTL
- int ide_taskfile_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg)
-@@ -519,13 +554,12 @@ int ide_taskfile_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg)
- 	ide_task_t		args;
- 	u8 *outbuf		= NULL;
- 	u8 *inbuf		= NULL;
--	task_ioreg_t *argsptr	= args.tfRegister;
--	task_ioreg_t *hobsptr	= args.hobRegister;
-+	u8 *data_buf		= NULL;
- 	int err			= 0;
- 	int tasksize		= sizeof(struct ide_task_request_s);
- 	unsigned int taskin	= 0;
- 	unsigned int taskout	= 0;
--	u8 io_32bit		= drive->io_32bit;
-+	u16 nsect		= 0;
- 	char __user *buf = (char __user *)arg;
+ 		dma_base = pci_resource_start(dev, baridx);
  
- //	printk("IDE Taskfile ...\n");
-@@ -572,24 +606,52 @@ int ide_taskfile_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg)
+-		if (dma_base == 0)
++		if (dma_base == 0) {
+ 			printk(KERN_ERR "%s: DMA base is invalid\n", d->name);
++			return 0;
++		}
  	}
  
- 	memset(&args, 0, sizeof(ide_task_t));
--	memcpy(argsptr, req_task->io_ports, HDIO_DRIVE_TASK_HDR_SIZE);
--	memcpy(hobsptr, req_task->hob_ports, HDIO_DRIVE_HOB_HDR_SIZE);
- 
--	args.tf_in_flags  = req_task->in_flags;
--	args.tf_out_flags = req_task->out_flags;
--	args.data_phase   = req_task->data_phase;
--	args.command_type = req_task->req_cmd;
-+	memcpy(&args.tf_array[0], req_task->hob_ports, HDIO_DRIVE_HOB_HDR_SIZE - 2);
-+	memcpy(&args.tf_array[6], req_task->io_ports, HDIO_DRIVE_TASK_HDR_SIZE);
-+
-+	args.data_phase = req_task->data_phase;
-+
-+	args.tf_flags = IDE_TFLAG_IO_16BIT | IDE_TFLAG_DEVICE |
-+			IDE_TFLAG_IN_TF;
-+	if (drive->addressing == 1)
-+		args.tf_flags |= (IDE_TFLAG_LBA48 | IDE_TFLAG_IN_HOB);
-+
-+	if (req_task->out_flags.all) {
-+		args.tf_flags |= IDE_TFLAG_FLAGGED;
-+
-+		if (req_task->out_flags.b.data)
-+			args.tf_flags |= IDE_TFLAG_OUT_DATA;
-+
-+		if (req_task->out_flags.b.nsector_hob)
-+			args.tf_flags |= IDE_TFLAG_OUT_HOB_NSECT;
-+		if (req_task->out_flags.b.sector_hob)
-+			args.tf_flags |= IDE_TFLAG_OUT_HOB_LBAL;
-+		if (req_task->out_flags.b.lcyl_hob)
-+			args.tf_flags |= IDE_TFLAG_OUT_HOB_LBAM;
-+		if (req_task->out_flags.b.hcyl_hob)
-+			args.tf_flags |= IDE_TFLAG_OUT_HOB_LBAH;
-+
-+		if (req_task->out_flags.b.error_feature)
-+			args.tf_flags |= IDE_TFLAG_OUT_FEATURE;
-+		if (req_task->out_flags.b.nsector)
-+			args.tf_flags |= IDE_TFLAG_OUT_NSECT;
-+		if (req_task->out_flags.b.sector)
-+			args.tf_flags |= IDE_TFLAG_OUT_LBAL;
-+		if (req_task->out_flags.b.lcyl)
-+			args.tf_flags |= IDE_TFLAG_OUT_LBAM;
-+		if (req_task->out_flags.b.hcyl)
-+			args.tf_flags |= IDE_TFLAG_OUT_LBAH;
-+	} else {
-+		args.tf_flags |= IDE_TFLAG_OUT_TF;
-+		if (args.tf_flags & IDE_TFLAG_LBA48)
-+			args.tf_flags |= IDE_TFLAG_OUT_HOB;
-+	}
+-	if ((d->host_flags & IDE_HFLAG_CS5520) == 0 && dma_base) {
++	if (hwif->channel)
++		dma_base += 8;
 +
-+	if (req_task->in_flags.b.data)
-+		args.tf_flags |= IDE_TFLAG_IN_DATA;
++	if ((d->host_flags & IDE_HFLAG_CS5520) == 0) {
+ 		u8 simplex_stat = 0;
+-		dma_base += hwif->channel ? 8 : 0;
  
--	drive->io_32bit = 0;
- 	switch(req_task->data_phase) {
--		case TASKFILE_OUT_DMAQ:
--		case TASKFILE_OUT_DMA:
--			err = ide_diag_taskfile(drive, &args, taskout, outbuf);
--			break;
--		case TASKFILE_IN_DMAQ:
--		case TASKFILE_IN_DMA:
--			err = ide_diag_taskfile(drive, &args, taskin, inbuf);
--			break;
- 		case TASKFILE_MULTI_OUT:
- 			if (!drive->mult_count) {
- 				/* (hs): give up if multcount is not set */
-@@ -601,9 +663,11 @@ int ide_taskfile_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg)
- 			}
- 			/* fall through */
- 		case TASKFILE_OUT:
--			args.prehandler = &pre_task_out_intr;
--			args.handler = &task_out_intr;
--			err = ide_diag_taskfile(drive, &args, taskout, outbuf);
-+			/* fall through */
-+		case TASKFILE_OUT_DMAQ:
-+		case TASKFILE_OUT_DMA:
-+			nsect = taskout / SECTOR_SIZE;
-+			data_buf = outbuf;
- 			break;
- 		case TASKFILE_MULTI_IN:
- 			if (!drive->mult_count) {
-@@ -616,22 +680,46 @@ int ide_taskfile_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg)
- 			}
- 			/* fall through */
- 		case TASKFILE_IN:
--			args.handler = &task_in_intr;
--			err = ide_diag_taskfile(drive, &args, taskin, inbuf);
-+			/* fall through */
-+		case TASKFILE_IN_DMAQ:
-+		case TASKFILE_IN_DMA:
-+			nsect = taskin / SECTOR_SIZE;
-+			data_buf = inbuf;
- 			break;
- 		case TASKFILE_NO_DATA:
--			args.handler = &task_no_data_intr;
--			err = ide_diag_taskfile(drive, &args, 0, NULL);
- 			break;
- 		default:
- 			err = -EFAULT;
- 			goto abort;
- 	}
+ 		switch(dev->device) {
+ 			case PCI_DEVICE_ID_AL_M5219:
+@@ -359,6 +363,8 @@ static ide_hwif_t *ide_hwif_configure(struct pci_dev *dev, const struct ide_port
+ 	unsigned long ctl = 0, base = 0;
+ 	ide_hwif_t *hwif;
+ 	u8 bootable = (d->host_flags & IDE_HFLAG_BOOTABLE) ? 1 : 0;
++	u8 oldnoprobe = 0;
++	struct hw_regs_s hw;
  
--	memcpy(req_task->io_ports, &(args.tfRegister), HDIO_DRIVE_TASK_HDR_SIZE);
--	memcpy(req_task->hob_ports, &(args.hobRegister), HDIO_DRIVE_HOB_HDR_SIZE);
--	req_task->in_flags  = args.tf_in_flags;
--	req_task->out_flags = args.tf_out_flags;
-+	if (req_task->req_cmd == IDE_DRIVE_TASK_NO_DATA)
-+		nsect = 0;
-+	else if (!nsect) {
-+		nsect = (args.tf.hob_nsect << 8) | args.tf.nsect;
+ 	if ((d->host_flags & IDE_HFLAG_ISA_PORTS) == 0) {
+ 		/*  Possibly we should fail if these checks report true */
+@@ -381,26 +387,25 @@ static ide_hwif_t *ide_hwif_configure(struct pci_dev *dev, const struct ide_port
+ 	}
+ 	if ((hwif = ide_match_hwif(base, bootable, d->name)) == NULL)
+ 		return NULL;	/* no room in ide_hwifs[] */
+-	if (hwif->io_ports[IDE_DATA_OFFSET] != base ||
+-	    hwif->io_ports[IDE_CONTROL_OFFSET] != (ctl | 2)) {
+-		hw_regs_t hw;
+-
+-		memset(&hw, 0, sizeof(hw));
+-#ifndef CONFIG_IDE_ARCH_OBSOLETE_INIT
+-		ide_std_init_ports(&hw, base, ctl | 2);
+-#else
+-		ide_init_hwif_ports(&hw, base, ctl | 2, NULL);
+-#endif
+-		memcpy(hwif->io_ports, hw.io_ports, sizeof(hwif->io_ports));
+-		hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET];
+-	}
+-	hwif->chipset = d->chipset ? d->chipset : ide_pci;
 +
-+		if (!nsect) {
-+			printk(KERN_ERR "%s: in/out command without data\n",
-+					drive->name);
-+			err = -EFAULT;
-+			goto abort;
-+		}
-+	}
++	memset(&hw, 0, sizeof(hw));
++	hw.irq = hwif->irq ? hwif->irq : irq;
++	hw.dev = &dev->dev;
++	hw.chipset = d->chipset ? d->chipset : ide_pci;
++	ide_std_init_ports(&hw, base, ctl | 2);
 +
-+	if (req_task->req_cmd == IDE_DRIVE_TASK_RAW_WRITE)
-+		args.tf_flags |= IDE_TFLAG_WRITE;
++	if (hwif->io_ports[IDE_DATA_OFFSET] == base &&
++	    hwif->io_ports[IDE_CONTROL_OFFSET] == (ctl | 2))
++		oldnoprobe = hwif->noprobe;
 +
-+	err = ide_raw_taskfile(drive, &args, data_buf, nsect);
++	ide_init_port_hw(hwif, &hw);
 +
-+	memcpy(req_task->hob_ports, &args.tf_array[0], HDIO_DRIVE_HOB_HDR_SIZE - 2);
-+	memcpy(req_task->io_ports, &args.tf_array[6], HDIO_DRIVE_TASK_HDR_SIZE);
++	hwif->noprobe = oldnoprobe;
 +
-+	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)
-+			req_task->in_flags.all |= (IDE_HOB_STD_IN_FLAGS << 8);
-+	}
- 
- 	if (copy_to_user(buf, req_task, tasksize)) {
- 		err = -EFAULT;
-@@ -658,40 +746,24 @@ abort:
- 
- //	printk("IDE Taskfile ioctl ended. rc = %i\n", err);
+ 	hwif->pci_dev = dev;
+ 	hwif->cds = d;
+ 	hwif->channel = port;
  
--	drive->io_32bit = io_32bit;
--
- 	return err;
- }
- #endif
+-	if (!hwif->irq)
+-		hwif->irq = irq;
+ 	if (mate) {
+ 		hwif->mate = mate;
+ 		mate->mate = hwif;
+@@ -535,12 +540,8 @@ void ide_pci_setup_ports(struct pci_dev *dev, const struct ide_port_info *d, int
+ 		if ((hwif = ide_hwif_configure(dev, d, mate, port, pciirq)) == NULL)
+ 			continue;
  
--int ide_wait_cmd (ide_drive_t *drive, u8 cmd, u8 nsect, u8 feature, u8 sectors, u8 *buf)
--{
--	struct request rq;
--	u8 buffer[4];
--
--	if (!buf)
--		buf = buffer;
--	memset(buf, 0, 4 + SECTOR_WORDS * 4 * sectors);
--	ide_init_drive_cmd(&rq);
--	rq.buffer = buf;
--	*buf++ = cmd;
--	*buf++ = nsect;
--	*buf++ = feature;
--	*buf++ = sectors;
--	return ide_do_drive_cmd(drive, &rq, ide_wait);
--}
+-		/* setup proper ancestral information */
+-		hwif->gendev.parent = &dev->dev;
 -
- int ide_cmd_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg)
- {
--	int err = 0;
--	u8 args[4], *argbuf = args;
--	u8 xfer_rate = 0;
--	int argsize = 4;
-+	u8 *buf = NULL;
-+	int bufsize = 0, err = 0;
-+	u8 args[4], xfer_rate = 0;
- 	ide_task_t tfargs;
-+	struct ide_taskfile *tf = &tfargs.tf;
- 
- 	if (NULL == (void *) arg) {
- 		struct request rq;
-+
- 		ide_init_drive_cmd(&rq);
-+		rq.cmd_type = REQ_TYPE_ATA_TASKFILE;
-+
- 		return ide_do_drive_cmd(drive, &rq, ide_wait);
- 	}
- 
-@@ -699,27 +771,40 @@ int ide_cmd_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg)
- 		return -EFAULT;
+ 		*(idx + port) = hwif->index;
  
- 	memset(&tfargs, 0, sizeof(ide_task_t));
--	tfargs.tfRegister[IDE_FEATURE_OFFSET] = args[2];
--	tfargs.tfRegister[IDE_NSECTOR_OFFSET] = args[3];
--	tfargs.tfRegister[IDE_SECTOR_OFFSET]  = args[1];
--	tfargs.tfRegister[IDE_LCYL_OFFSET]    = 0x00;
--	tfargs.tfRegister[IDE_HCYL_OFFSET]    = 0x00;
--	tfargs.tfRegister[IDE_SELECT_OFFSET]  = 0x00;
--	tfargs.tfRegister[IDE_COMMAND_OFFSET] = args[0];
-+	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 (d->init_iops)
+ 			d->init_iops(hwif);
  
- 	if (args[3]) {
--		argsize = 4 + (SECTOR_WORDS * 4 * args[3]);
--		argbuf = kzalloc(argsize, GFP_KERNEL);
--		if (argbuf == NULL)
-+		tfargs.tf_flags |= IDE_TFLAG_IO_16BIT;
-+		bufsize = SECTOR_WORDS * 4 * args[3];
-+		buf = kzalloc(bufsize, GFP_KERNEL);
-+		if (buf == NULL)
- 			return -ENOMEM;
- 	}
-+
- 	if (set_transfer(drive, &tfargs)) {
- 		xfer_rate = args[1];
- 		if (ide_ata66_check(drive, &tfargs))
- 			goto abort;
- 	}
+@@ -551,8 +552,6 @@ void ide_pci_setup_ports(struct pci_dev *dev, const struct ide_port_info *d, int
+ 		    (d->host_flags & IDE_HFLAG_FORCE_LEGACY_IRQS))
+ 			hwif->irq = port ? 15 : 14;
  
--	err = ide_wait_cmd(drive, args[0], args[1], args[2], args[3], argbuf);
-+	err = ide_raw_taskfile(drive, &tfargs, buf, args[3]);
-+
-+	args[0] = tf->status;
-+	args[1] = tf->error;
-+	args[2] = tf->nsect;
+-		hwif->fixup = d->fixup;
+-
+ 		hwif->host_flags = d->host_flags;
+ 		hwif->pio_mask = d->pio_mask;
  
- 	if (!err && xfer_rate) {
- 		/* active-retuning-calls future */
-@@ -727,142 +812,38 @@ int ide_cmd_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg)
- 		ide_driveid_update(drive);
- 	}
- abort:
--	if (copy_to_user((void __user *)arg, argbuf, argsize))
-+	if (copy_to_user((void __user *)arg, &args, 4))
- 		err = -EFAULT;
--	if (argsize > 4)
--		kfree(argbuf);
-+	if (buf) {
-+		if (copy_to_user((void __user *)(arg + 4), buf, bufsize))
-+			err = -EFAULT;
-+		kfree(buf);
-+	}
- 	return err;
+@@ -699,105 +698,3 @@ out:
  }
  
--static int ide_wait_cmd_task(ide_drive_t *drive, u8 *buf)
--{
--	struct request rq;
+ EXPORT_SYMBOL_GPL(ide_setup_pci_devices);
 -
--	ide_init_drive_cmd(&rq);
--	rq.cmd_type = REQ_TYPE_ATA_TASK;
--	rq.buffer = buf;
--	return ide_do_drive_cmd(drive, &rq, ide_wait);
--}
+-#ifdef CONFIG_IDEPCI_PCIBUS_ORDER
+-/*
+- *	Module interfaces
+- */
 -
- 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], *argbuf = args;
--	int argsize = 7;
-+	u8 args[7];
-+	ide_task_t task;
- 
- 	if (copy_from_user(args, p, 7))
- 		return -EFAULT;
--	err = ide_wait_cmd_task(drive, argbuf);
--	if (copy_to_user(p, argbuf, argsize))
--		err = -EFAULT;
--	return err;
--}
+-static int pre_init = 1;		/* Before first ordered IDE scan */
+-static LIST_HEAD(ide_pci_drivers);
 -
 -/*
-- * NOTICE: This is additions from IBM to provide a discrete interface,
-- * for selective taskregister access operations.  Nice JOB Klaus!!!
-- * Glad to be able to work and co-develop this with you and IBM.
+- *	__ide_pci_register_driver	-	attach IDE driver
+- *	@driver: pci driver
+- *	@module: owner module of the driver
+- *
+- *	Registers a driver with the IDE layer. The IDE layer arranges that
+- *	boot time setup is done in the expected device order and then
+- *	hands the controllers off to the core PCI code to do the rest of
+- *	the work.
+- *
+- *	Returns are the same as for pci_register_driver
 - */
--ide_startstop_t flagged_taskfile (ide_drive_t *drive, ide_task_t *task)
+-
+-int __ide_pci_register_driver(struct pci_driver *driver, struct module *module,
+-			      const char *mod_name)
 -{
--	ide_hwif_t *hwif	= HWIF(drive);
--	task_struct_t *taskfile	= (task_struct_t *) task->tfRegister;
--	hob_struct_t *hobfile	= (hob_struct_t *) task->hobRegister;
+-	if (!pre_init)
+-		return __pci_register_driver(driver, module, mod_name);
+-	driver->driver.owner = module;
+-	list_add_tail(&driver->node, &ide_pci_drivers);
+-	return 0;
+-}
+-EXPORT_SYMBOL_GPL(__ide_pci_register_driver);
 -
--	if (task->data_phase == TASKFILE_MULTI_IN ||
--	    task->data_phase == TASKFILE_MULTI_OUT) {
--		if (!drive->mult_count) {
--			printk(KERN_ERR "%s: multimode not set!\n", drive->name);
--			return ide_stopped;
--		}
--	}
- 
--	/*
--	 * (ks) Check taskfile in flags.
--	 * If set, then execute as it is defined.
--	 * If not set, then define default settings.
--	 * The default values are:
--	 *	read all taskfile registers (except data)
--	 *	read the hob registers (sector, nsector, lcyl, hcyl)
--	 */
--	if (task->tf_in_flags.all == 0) {
--		task->tf_in_flags.all = IDE_TASKFILE_STD_IN_FLAGS;
--		if (drive->addressing == 1)
--			task->tf_in_flags.all |= (IDE_HOB_STD_IN_FLAGS  << 8);
--        }
+-/**
+- *	ide_scan_pcidev		-	find an IDE driver for a device
+- *	@dev: PCI device to check
+- *
+- *	Look for an IDE driver to handle the device we are considering.
+- *	This is only used during boot up to get the ordering correct. After
+- *	boot up the pci layer takes over the job.
+- */
 -
--	/* ALL Command Block Executions SHALL clear nIEN, unless otherwise */
--	if (IDE_CONTROL_REG)
--		/* clear nIEN */
--		hwif->OUTB(drive->ctl, IDE_CONTROL_REG);
--	SELECT_MASK(drive, 0);
+-static int __init ide_scan_pcidev(struct pci_dev *dev)
+-{
+-	struct list_head *l;
+-	struct pci_driver *d;
 -
--	if (task->tf_out_flags.b.data) {
--		u16 data =  taskfile->data + (hobfile->data << 8);
--		hwif->OUTW(data, IDE_DATA_REG);
+-	list_for_each(l, &ide_pci_drivers) {
+-		d = list_entry(l, struct pci_driver, node);
+-		if (d->id_table) {
+-			const struct pci_device_id *id =
+-				pci_match_id(d->id_table, dev);
+-
+-			if (id != NULL && d->probe(dev, id) >= 0) {
+-				dev->driver = d;
+-				pci_dev_get(dev);
+-				return 1;
+-			}
+-		}
 -	}
+-	return 0;
+-}
 -
--	/* (ks) send hob registers first */
--	if (task->tf_out_flags.b.nsector_hob)
--		hwif->OUTB(hobfile->sector_count, IDE_NSECTOR_REG);
--	if (task->tf_out_flags.b.sector_hob)
--		hwif->OUTB(hobfile->sector_number, IDE_SECTOR_REG);
--	if (task->tf_out_flags.b.lcyl_hob)
--		hwif->OUTB(hobfile->low_cylinder, IDE_LCYL_REG);
--	if (task->tf_out_flags.b.hcyl_hob)
--		hwif->OUTB(hobfile->high_cylinder, IDE_HCYL_REG);
+-/**
+- *	ide_scan_pcibus		-	perform the initial IDE driver scan
+- *	@scan_direction: set for reverse order scanning
+- *
+- *	Perform the initial bus rather than driver ordered scan of the
+- *	PCI drivers. After this all IDE pci handling becomes standard
+- *	module ordering not traditionally ordered.
+- */
+- 	
+-void __init ide_scan_pcibus (int scan_direction)
+-{
+-	struct pci_dev *dev = NULL;
+-	struct pci_driver *d;
+-	struct list_head *l, *n;
 -
--	/* (ks) Send now the standard registers */
--	if (task->tf_out_flags.b.error_feature)
--		hwif->OUTB(taskfile->feature, IDE_FEATURE_REG);
--	/* refers to number of sectors to transfer */
--	if (task->tf_out_flags.b.nsector)
--		hwif->OUTB(taskfile->sector_count, IDE_NSECTOR_REG);
--	/* refers to sector offset or start sector */
--	if (task->tf_out_flags.b.sector)
--		hwif->OUTB(taskfile->sector_number, IDE_SECTOR_REG);
--	if (task->tf_out_flags.b.lcyl)
--		hwif->OUTB(taskfile->low_cylinder, IDE_LCYL_REG);
--	if (task->tf_out_flags.b.hcyl)
--		hwif->OUTB(taskfile->high_cylinder, IDE_HCYL_REG);
+-	pre_init = 0;
+-	if (!scan_direction)
+-		while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)))
+-			ide_scan_pcidev(dev);
+-	else
+-		while ((dev = pci_get_device_reverse(PCI_ANY_ID, PCI_ANY_ID,
+-						     dev)))
+-			ide_scan_pcidev(dev);
 -
--        /*
--	 * (ks) In the flagged taskfile approch, we will use all specified
--	 * registers and the register value will not be changed, except the
--	 * select bit (master/slave) in the drive_head register. We must make
--	 * sure that the desired drive is selected.
+-	/*
+-	 *	Hand the drivers over to the PCI layer now we
+-	 *	are post init.
 -	 */
--	hwif->OUTB(taskfile->device_head | drive->select.all, IDE_SELECT_REG);
--	switch(task->data_phase) {
-+	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;
- 
--   	        case TASKFILE_OUT_DMAQ:
--		case TASKFILE_OUT_DMA:
--		case TASKFILE_IN_DMAQ:
--		case TASKFILE_IN_DMA:
--			if (!drive->using_dma)
--				break;
-+	err = ide_no_data_taskfile(drive, &task);
+-
+-	list_for_each_safe(l, n, &ide_pci_drivers) {
+-		list_del(l);
+-		d = list_entry(l, struct pci_driver, node);
+-		if (__pci_register_driver(d, d->driver.owner,
+-					  d->driver.mod_name))
+-			printk(KERN_ERR "%s: failed to register %s driver\n",
+-					__FUNCTION__, d->driver.mod_name);
+-	}
+-}
+-#endif
+diff --git a/drivers/ieee1394/nodemgr.c b/drivers/ieee1394/nodemgr.c
+index 90dc75b..511e432 100644
+--- a/drivers/ieee1394/nodemgr.c
++++ b/drivers/ieee1394/nodemgr.c
+@@ -727,33 +727,31 @@ static int nodemgr_bus_match(struct device * dev, struct device_driver * drv)
  
--			if (!hwif->dma_setup(drive)) {
--				hwif->dma_exec_cmd(drive, taskfile->command);
--				hwif->dma_start(drive);
--				return ide_started;
--			}
--			break;
-+	args[0] = task.tf.command;
-+	memcpy(&args[1], &task.tf_array[7], 6);
+ static DEFINE_MUTEX(nodemgr_serialize_remove_uds);
  
--	        default:
-- 			if (task->handler == NULL)
--				return ide_stopped;
++static int __match_ne(struct device *dev, void *data)
++{
++	struct unit_directory *ud;
++	struct node_entry *ne = (struct node_entry *)data;
++
++	ud = container_of(dev, struct unit_directory, unit_dev);
++	return ud->ne == ne;
++}
++
+ static void nodemgr_remove_uds(struct node_entry *ne)
+ {
+ 	struct device *dev;
+-	struct unit_directory *tmp, *ud;
 -
--			/* Issue the command */
--			if (task->prehandler) {
--				hwif->OUTBSYNC(drive, taskfile->command, IDE_COMMAND_REG);
--				ndelay(400);	/* FIXME */
--				return task->prehandler(drive, task->rq);
+-	/* Iteration over nodemgr_ud_class.devices has to be protected by
+-	 * nodemgr_ud_class.sem, but device_unregister() will eventually
+-	 * take nodemgr_ud_class.sem too. Therefore pick out one ud at a time,
+-	 * release the semaphore, and then unregister the ud. Since this code
+-	 * may be called from other contexts besides the knodemgrds, protect the
+-	 * gap after release of the semaphore by nodemgr_serialize_remove_uds.
++	struct unit_directory *ud;
++
++	/* Use class_find device to iterate the devices. Since this code
++	 * may be called from other contexts besides the knodemgrds,
++	 * protect it by nodemgr_serialize_remove_uds.
+ 	 */
+ 	mutex_lock(&nodemgr_serialize_remove_uds);
+ 	for (;;) {
+-		ud = NULL;
+-		down(&nodemgr_ud_class.sem);
+-		list_for_each_entry(dev, &nodemgr_ud_class.devices, node) {
+-			tmp = container_of(dev, struct unit_directory,
+-					   unit_dev);
+-			if (tmp->ne == ne) {
+-				ud = tmp;
+-				break;
 -			}
--			ide_execute_command(drive, taskfile->command, task->handler, WAIT_WORSTCASE, NULL);
--			return ide_started;
--	}
-+	if (copy_to_user(p, args, 7))
-+		err = -EFAULT;
- 
--	return ide_stopped;
-+	return err;
+-		}
+-		up(&nodemgr_ud_class.sem);
+-		if (ud == NULL)
++		dev = class_find_device(&nodemgr_ud_class, ne, __match_ne);
++		if (!dev)
+ 			break;
++		ud = container_of(dev, struct unit_directory, unit_dev);
++		put_device(dev);
+ 		device_unregister(&ud->unit_dev);
+ 		device_unregister(&ud->device);
+ 	}
+@@ -882,45 +880,66 @@ fail_alloc:
+ 	return NULL;
  }
-diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c
-index 54943da..97894ab 100644
---- a/drivers/ide/ide.c
-+++ b/drivers/ide/ide.c
-@@ -95,7 +95,7 @@ DEFINE_MUTEX(ide_cfg_mtx);
-  __cacheline_aligned_in_smp DEFINE_SPINLOCK(ide_lock);
  
- #ifdef CONFIG_IDEPCI_PCIBUS_ORDER
--static int ide_scan_direction; /* THIS was formerly 2.2.x pci=reverse */
-+int ide_scan_direction; /* THIS was formerly 2.2.x pci=reverse */
- #endif
++static int __match_ne_guid(struct device *dev, void *data)
++{
++	struct node_entry *ne;
++	u64 *guid = (u64 *)data;
++
++	ne = container_of(dev, struct node_entry, node_dev);
++	return ne->guid == *guid;
++}
  
- int noautodma = 0;
-@@ -116,7 +116,7 @@ EXPORT_SYMBOL(ide_hwifs);
- /*
-  * Do not even *think* about calling this!
-  */
--static void init_hwif_data(ide_hwif_t *hwif, unsigned int index)
-+void ide_init_port_data(ide_hwif_t *hwif, unsigned int index)
+ static struct node_entry *find_entry_by_guid(u64 guid)
  {
- 	unsigned int unit;
+ 	struct device *dev;
+-	struct node_entry *ne, *ret_ne = NULL;
+-
+-	down(&nodemgr_ne_class.sem);
+-	list_for_each_entry(dev, &nodemgr_ne_class.devices, node) {
+-		ne = container_of(dev, struct node_entry, node_dev);
++	struct node_entry *ne;
  
-@@ -159,6 +159,7 @@ static void init_hwif_data(ide_hwif_t *hwif, unsigned int index)
- 		init_completion(&drive->gendev_rel_comp);
- 	}
- }
-+EXPORT_SYMBOL_GPL(ide_init_port_data);
+-		if (ne->guid == guid) {
+-			ret_ne = ne;
+-			break;
+-		}
+-	}
+-	up(&nodemgr_ne_class.sem);
++	dev = class_find_device(&nodemgr_ne_class, &guid, __match_ne_guid);
++	if (!dev)
++		return NULL;
++	ne = container_of(dev, struct node_entry, node_dev);
++	put_device(dev);
  
- static void init_hwif_default(ide_hwif_t *hwif, unsigned int index)
- {
-@@ -177,8 +178,6 @@ static void init_hwif_default(ide_hwif_t *hwif, unsigned int index)
- #endif
+-	return ret_ne;
++	return ne;
  }
  
--extern void ide_arm_init(void);
--
- /*
-  * init_ide_data() sets reasonable default values into all fields
-  * of all instances of the hwifs and drives, but only on the first call.
-@@ -210,16 +209,13 @@ static void __init init_ide_data (void)
- 	/* Initialise all interface structures */
- 	for (index = 0; index < MAX_HWIFS; ++index) {
- 		hwif = &ide_hwifs[index];
--		init_hwif_data(hwif, index);
-+		ide_init_port_data(hwif, index);
- 		init_hwif_default(hwif, index);
- #if !defined(CONFIG_PPC32) || !defined(CONFIG_PCI)
- 		hwif->irq =
- 			ide_init_default_irq(hwif->io_ports[IDE_DATA_OFFSET]);
- #endif
- 	}
--#ifdef CONFIG_IDE_ARM
--	ide_arm_init();
--#endif
- }
++struct match_nodeid_param {
++	struct hpsb_host *host;
++	nodeid_t nodeid;
++};
++
++static int __match_ne_nodeid(struct device *dev, void *data)
++{
++	int found = 0;
++	struct node_entry *ne;
++	struct match_nodeid_param *param = (struct match_nodeid_param *)data;
++
++	if (!dev)
++		goto ret;
++	ne = container_of(dev, struct node_entry, node_dev);
++	if (ne->host == param->host && ne->nodeid == param->nodeid)
++		found = 1;
++ret:
++	return found;
++}
  
- /**
-@@ -414,8 +410,6 @@ static void ide_hwif_restore(ide_hwif_t *hwif, ide_hwif_t *tmp_hwif)
- 	hwif->cds			= tmp_hwif->cds;
- #endif
+ static struct node_entry *find_entry_by_nodeid(struct hpsb_host *host,
+ 					       nodeid_t nodeid)
+ {
+ 	struct device *dev;
+-	struct node_entry *ne, *ret_ne = NULL;
++	struct node_entry *ne;
++	struct match_nodeid_param param;
  
--	hwif->fixup			= tmp_hwif->fixup;
--
- 	hwif->set_pio_mode		= tmp_hwif->set_pio_mode;
- 	hwif->set_dma_mode		= tmp_hwif->set_dma_mode;
- 	hwif->mdma_filter		= tmp_hwif->mdma_filter;
-@@ -424,7 +418,6 @@ static void ide_hwif_restore(ide_hwif_t *hwif, ide_hwif_t *tmp_hwif)
- 	hwif->reset_poll		= tmp_hwif->reset_poll;
- 	hwif->pre_reset			= tmp_hwif->pre_reset;
- 	hwif->resetproc			= tmp_hwif->resetproc;
--	hwif->intrproc			= tmp_hwif->intrproc;
- 	hwif->maskproc			= tmp_hwif->maskproc;
- 	hwif->quirkproc			= tmp_hwif->quirkproc;
- 	hwif->busproc			= tmp_hwif->busproc;
-@@ -434,16 +427,13 @@ static void ide_hwif_restore(ide_hwif_t *hwif, ide_hwif_t *tmp_hwif)
- 	hwif->atapi_input_bytes		= tmp_hwif->atapi_input_bytes;
- 	hwif->atapi_output_bytes	= tmp_hwif->atapi_output_bytes;
+-	down(&nodemgr_ne_class.sem);
+-	list_for_each_entry(dev, &nodemgr_ne_class.devices, node) {
+-		ne = container_of(dev, struct node_entry, node_dev);
++	param.host = host;
++	param.nodeid = nodeid;
  
-+	hwif->dma_host_set		= tmp_hwif->dma_host_set;
- 	hwif->dma_setup			= tmp_hwif->dma_setup;
- 	hwif->dma_exec_cmd		= tmp_hwif->dma_exec_cmd;
- 	hwif->dma_start			= tmp_hwif->dma_start;
- 	hwif->ide_dma_end		= tmp_hwif->ide_dma_end;
--	hwif->ide_dma_on		= tmp_hwif->ide_dma_on;
--	hwif->dma_off_quietly		= tmp_hwif->dma_off_quietly;
- 	hwif->ide_dma_test_irq		= tmp_hwif->ide_dma_test_irq;
- 	hwif->ide_dma_clear_irq		= tmp_hwif->ide_dma_clear_irq;
--	hwif->dma_host_on		= tmp_hwif->dma_host_on;
--	hwif->dma_host_off		= tmp_hwif->dma_host_off;
- 	hwif->dma_lost_irq		= tmp_hwif->dma_lost_irq;
- 	hwif->dma_timeout		= tmp_hwif->dma_timeout;
+-		if (ne->host == host && ne->nodeid == nodeid) {
+-			ret_ne = ne;
+-			break;
+-		}
+-	}
+-	up(&nodemgr_ne_class.sem);
++	dev = class_find_device(&nodemgr_ne_class, &param, __match_ne_nodeid);
++	if (!dev)
++		return NULL;
++	ne = container_of(dev, struct node_entry, node_dev);
++	put_device(dev);
  
-@@ -468,7 +458,6 @@ static void ide_hwif_restore(ide_hwif_t *hwif, ide_hwif_t *tmp_hwif)
- #endif
+-	return ret_ne;
++	return ne;
+ }
  
- 	hwif->dma_base			= tmp_hwif->dma_base;
--	hwif->dma_master		= tmp_hwif->dma_master;
- 	hwif->dma_command		= tmp_hwif->dma_command;
- 	hwif->dma_vendor1		= tmp_hwif->dma_vendor1;
- 	hwif->dma_status		= tmp_hwif->dma_status;
-@@ -602,7 +591,6 @@ void ide_unregister(unsigned int index)
- 		(void) ide_release_dma(hwif);
  
- 		hwif->dma_base = 0;
--		hwif->dma_master = 0;
- 		hwif->dma_command = 0;
- 		hwif->dma_vendor1 = 0;
- 		hwif->dma_status = 0;
-@@ -617,7 +605,7 @@ void ide_unregister(unsigned int index)
- 	tmp_hwif = *hwif;
+@@ -1370,107 +1389,109 @@ static void nodemgr_node_scan(struct host_info *hi, int generation)
+ 	}
+ }
  
- 	/* restore hwif data to pristine status */
--	init_hwif_data(hwif, index);
-+	ide_init_port_data(hwif, index);
- 	init_hwif_default(hwif, index);
+-
+-static void nodemgr_suspend_ne(struct node_entry *ne)
++static int __nodemgr_driver_suspend(struct device *dev, void *data)
+ {
+-	struct device *dev;
+ 	struct unit_directory *ud;
+ 	struct device_driver *drv;
++	struct node_entry *ne = (struct node_entry *)data;
+ 	int error;
  
- 	ide_hwif_restore(hwif, &tmp_hwif);
-@@ -683,24 +671,34 @@ void ide_setup_ports (	hw_regs_t *hw,
-  */
- }
+-	HPSB_DEBUG("Node suspended: ID:BUS[" NODE_BUS_FMT "]  GUID[%016Lx]",
+-		   NODE_BUS_ARGS(ne->host, ne->nodeid), (unsigned long long)ne->guid);
++	ud = container_of(dev, struct unit_directory, unit_dev);
++	if (ud->ne == ne) {
++		drv = get_driver(ud->device.driver);
++		if (drv) {
++			error = 1; /* release if suspend is not implemented */
++			if (drv->suspend) {
++				down(&ud->device.sem);
++				error = drv->suspend(&ud->device, PMSG_SUSPEND);
++				up(&ud->device.sem);
++			}
++			if (error)
++				device_release_driver(&ud->device);
++			put_driver(drv);
++		}
++	}
  
-+void ide_init_port_hw(ide_hwif_t *hwif, hw_regs_t *hw)
-+{
-+	memcpy(hwif->io_ports, hw->io_ports, sizeof(hwif->io_ports));
-+	hwif->irq = hw->irq;
-+	hwif->noprobe = 0;
-+	hwif->chipset = hw->chipset;
-+	hwif->gendev.parent = hw->dev;
-+	hwif->ack_intr = hw->ack_intr;
+-	ne->in_limbo = 1;
+-	WARN_ON(device_create_file(&ne->device, &dev_attr_ne_in_limbo));
++	return 0;
 +}
-+EXPORT_SYMBOL_GPL(ide_init_port_hw);
-+
- /**
-  *	ide_register_hw		-	register IDE interface
-  *	@hw: hardware registers
-- *	@fixup: fixup function
-- *	@initializing: set while initializing built-in drivers
-+ *	@quirkproc: quirkproc function
-  *	@hwifp: pointer to returned hwif
-  *
-  *	Register an IDE interface, specifying exactly the registers etc.
-- *	Set init=1 iff calling before probes have taken place.
-  *
-  *	Returns -1 on error.
-  */
  
--int ide_register_hw(hw_regs_t *hw, void (*fixup)(ide_hwif_t *),
--		    int initializing, ide_hwif_t **hwifp)
-+int ide_register_hw(hw_regs_t *hw, void (*quirkproc)(ide_drive_t *),
-+		    ide_hwif_t **hwifp)
- {
- 	int index, retry = 1;
- 	ide_hwif_t *hwif;
-+	u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
+-	down(&nodemgr_ud_class.sem);
+-	list_for_each_entry(dev, &nodemgr_ud_class.devices, node) {
+-		ud = container_of(dev, struct unit_directory, unit_dev);
+-		if (ud->ne != ne)
+-			continue;
++static int __nodemgr_driver_resume(struct device *dev, void *data)
++{
++	struct unit_directory *ud;
++	struct device_driver *drv;
++	struct node_entry *ne = (struct node_entry *)data;
  
- 	do {
- 		for (index = 0; index < MAX_HWIFS; ++index) {
-@@ -712,8 +710,7 @@ int ide_register_hw(hw_regs_t *hw, void (*fixup)(ide_hwif_t *),
- 			hwif = &ide_hwifs[index];
- 			if (hwif->hold)
- 				continue;
--			if ((!hwif->present && !hwif->mate && !initializing) ||
--			    (!hwif->io_ports[IDE_DATA_OFFSET] && initializing))
-+			if (!hwif->present && hwif->mate == NULL)
- 				goto found;
++	ud = container_of(dev, struct unit_directory, unit_dev);
++	if (ud->ne == ne) {
+ 		drv = get_driver(ud->device.driver);
+-		if (!drv)
+-			continue;
+-
+-		error = 1; /* release if suspend is not implemented */
+-		if (drv->suspend) {
+-			down(&ud->device.sem);
+-			error = drv->suspend(&ud->device, PMSG_SUSPEND);
+-			up(&ud->device.sem);
++		if (drv) {
++			if (drv->resume) {
++				down(&ud->device.sem);
++				drv->resume(&ud->device);
++				up(&ud->device.sem);
++			}
++			put_driver(drv);
  		}
- 		for (index = 0; index < MAX_HWIFS; index++)
-@@ -724,29 +721,23 @@ found:
- 	if (hwif->present)
- 		ide_unregister(index);
- 	else if (!hwif->hold) {
--		init_hwif_data(hwif, index);
-+		ide_init_port_data(hwif, index);
- 		init_hwif_default(hwif, index);
+-		if (error)
+-			device_release_driver(&ud->device);
+-		put_driver(drv);
  	}
- 	if (hwif->present)
- 		return -1;
--	memcpy(hwif->io_ports, hw->io_ports, sizeof(hwif->io_ports));
--	hwif->irq = hw->irq;
--	hwif->noprobe = 0;
--	hwif->fixup = fixup;
--	hwif->chipset = hw->chipset;
--	hwif->gendev.parent = hw->dev;
--	hwif->ack_intr = hw->ack_intr;
+-	up(&nodemgr_ud_class.sem);
+-}
  
--	if (initializing == 0) {
--		u8 idx[4] = { index, 0xff, 0xff, 0xff };
-+	ide_init_port_hw(hwif, hw);
-+	hwif->quirkproc = quirkproc;
++	return 0;
++}
  
--		ide_device_add(idx);
--	}
-+	idx[0] = index;
-+
-+	ide_device_add(idx);
+-static void nodemgr_resume_ne(struct node_entry *ne)
++static void nodemgr_suspend_ne(struct node_entry *ne)
+ {
+-	struct device *dev;
+-	struct unit_directory *ud;
+-	struct device_driver *drv;
++	HPSB_DEBUG("Node suspended: ID:BUS[" NODE_BUS_FMT "]  GUID[%016Lx]",
++		   NODE_BUS_ARGS(ne->host, ne->nodeid),
++		   (unsigned long long)ne->guid);
  
- 	if (hwifp)
- 		*hwifp = hwif;
+-	ne->in_limbo = 0;
+-	device_remove_file(&ne->device, &dev_attr_ne_in_limbo);
++	ne->in_limbo = 1;
++	WARN_ON(device_create_file(&ne->device, &dev_attr_ne_in_limbo));
  
--	return (initializing || hwif->present) ? index : -1;
-+	return hwif->present ? index : -1;
- }
+-	down(&nodemgr_ud_class.sem);
+-	list_for_each_entry(dev, &nodemgr_ud_class.devices, node) {
+-		ud = container_of(dev, struct unit_directory, unit_dev);
+-		if (ud->ne != ne)
+-			continue;
++	class_for_each_device(&nodemgr_ud_class, ne, __nodemgr_driver_suspend);
++}
  
- EXPORT_SYMBOL(ide_register_hw);
-@@ -839,7 +830,7 @@ int set_using_dma(ide_drive_t *drive, int arg)
- 	if (!drive->id || !(drive->id->capability & 1))
- 		goto out;
+-		drv = get_driver(ud->device.driver);
+-		if (!drv)
+-			continue;
  
--	if (hwif->ide_dma_on == NULL)
-+	if (hwif->dma_host_set == NULL)
- 		goto out;
+-		if (drv->resume) {
+-			down(&ud->device.sem);
+-			drv->resume(&ud->device);
+-			up(&ud->device.sem);
+-		}
+-		put_driver(drv);
+-	}
+-	up(&nodemgr_ud_class.sem);
++static void nodemgr_resume_ne(struct node_entry *ne)
++{
++	ne->in_limbo = 0;
++	device_remove_file(&ne->device, &dev_attr_ne_in_limbo);
  
- 	err = -EBUSY;
-@@ -854,8 +845,7 @@ int set_using_dma(ide_drive_t *drive, int arg)
- 	err = 0;
++	class_for_each_device(&nodemgr_ud_class, ne, __nodemgr_driver_resume);
+ 	HPSB_DEBUG("Node resumed: ID:BUS[" NODE_BUS_FMT "]  GUID[%016Lx]",
+ 		   NODE_BUS_ARGS(ne->host, ne->nodeid), (unsigned long long)ne->guid);
+ }
  
- 	if (arg) {
--		hwif->dma_off_quietly(drive);
--		if (ide_set_dma(drive) || hwif->ide_dma_on(drive))
-+		if (ide_set_dma(drive))
- 			err = -EIO;
- 	} else
- 		ide_dma_off(drive);
-@@ -888,7 +878,10 @@ int set_pio_mode(ide_drive_t *drive, int arg)
+-
+-static void nodemgr_update_pdrv(struct node_entry *ne)
++static int __nodemgr_update_pdrv(struct device *dev, void *data)
+ {
+-	struct device *dev;
+ 	struct unit_directory *ud;
+ 	struct device_driver *drv;
+ 	struct hpsb_protocol_driver *pdrv;
++	struct node_entry *ne = (struct node_entry *)data;
+ 	int error;
  
- 	if (drive->special.b.set_tune)
- 		return -EBUSY;
+-	down(&nodemgr_ud_class.sem);
+-	list_for_each_entry(dev, &nodemgr_ud_class.devices, node) {
+-		ud = container_of(dev, struct unit_directory, unit_dev);
+-		if (ud->ne != ne)
+-			continue;
+-
++	ud = container_of(dev, struct unit_directory, unit_dev);
++	if (ud->ne == ne) {
+ 		drv = get_driver(ud->device.driver);
+-		if (!drv)
+-			continue;
+-
+-		error = 0;
+-		pdrv = container_of(drv, struct hpsb_protocol_driver, driver);
+-		if (pdrv->update) {
+-			down(&ud->device.sem);
+-			error = pdrv->update(ud);
+-			up(&ud->device.sem);
++		if (drv) {
++			error = 0;
++			pdrv = container_of(drv, struct hpsb_protocol_driver,
++					    driver);
++			if (pdrv->update) {
++				down(&ud->device.sem);
++				error = pdrv->update(ud);
++				up(&ud->device.sem);
++			}
++			if (error)
++				device_release_driver(&ud->device);
++			put_driver(drv);
+ 		}
+-		if (error)
+-			device_release_driver(&ud->device);
+-		put_driver(drv);
+ 	}
+-	up(&nodemgr_ud_class.sem);
 +
- 	ide_init_drive_cmd(&rq);
-+	rq.cmd_type = REQ_TYPE_ATA_TASKFILE;
++	return 0;
++}
 +
- 	drive->tune_req = (u8) arg;
- 	drive->special.b.set_tune = 1;
- 	(void) ide_do_drive_cmd(drive, &rq, ide_wait);
-@@ -1070,7 +1063,7 @@ int generic_ide_ioctl(ide_drive_t *drive, struct file *file, struct block_device
- 			ide_init_hwif_ports(&hw, (unsigned long) args[0],
- 					    (unsigned long) args[1], NULL);
- 			hw.irq = args[2];
--			if (ide_register_hw(&hw, NULL, 0, NULL) == -1)
-+			if (ide_register_hw(&hw, NULL, NULL) == -1)
- 				return -EIO;
- 			return 0;
- 		}
-@@ -1231,26 +1224,12 @@ static int __init match_parm (char *s, const char *keywords[], int vals[], int m
- 	return 0;	/* zero = nothing matched */
++static void nodemgr_update_pdrv(struct node_entry *ne)
++{
++	class_for_each_device(&nodemgr_ud_class, ne, __nodemgr_update_pdrv);
  }
  
--#ifdef CONFIG_BLK_DEV_ALI14XX
- extern int probe_ali14xx;
--extern int ali14xx_init(void);
--#endif
--#ifdef CONFIG_BLK_DEV_UMC8672
- extern int probe_umc8672;
--extern int umc8672_init(void);
--#endif
--#ifdef CONFIG_BLK_DEV_DTC2278
- extern int probe_dtc2278;
--extern int dtc2278_init(void);
--#endif
--#ifdef CONFIG_BLK_DEV_HT6560B
- extern int probe_ht6560b;
--extern int ht6560b_init(void);
--#endif
--#ifdef CONFIG_BLK_DEV_QD65XX
- extern int probe_qd65xx;
--extern int qd65xx_init(void);
--#endif
-+extern int cmd640_vlb;
- 
- static int __initdata is_chipset_set[MAX_HWIFS];
  
-@@ -1327,7 +1306,7 @@ static int __init ide_setup(char *s)
- 	if (s[0] == 'h' && s[1] == 'd' && s[2] >= 'a' && s[2] <= max_drive) {
- 		const char *hd_words[] = {
- 			"none", "noprobe", "nowerr", "cdrom", "nodma",
--			"autotune", "noautotune", "minus8", "swapdata", "bswap",
-+			"autotune", "noautotune", "-8", "-9", "-10",
- 			"noflush", "remap", "remap63", "scsi", NULL };
- 		unit = s[2] - 'a';
- 		hw   = unit / MAX_DRIVES;
-@@ -1363,10 +1342,6 @@ static int __init ide_setup(char *s)
- 			case -7: /* "noautotune" */
- 				drive->autotune = IDE_TUNE_NOAUTO;
- 				goto obsolete_option;
--			case -9: /* "swapdata" */
--			case -10: /* "bswap" */
--				drive->bswap = 1;
--				goto done;
- 			case -11: /* noflush */
- 				drive->noflush = 1;
- 				goto done;
-@@ -1466,11 +1441,8 @@ static int __init ide_setup(char *s)
- #endif
- #ifdef CONFIG_BLK_DEV_CMD640
- 			case -14: /* "cmd640_vlb" */
--			{
--				extern int cmd640_vlb; /* flag for cmd640.c */
- 				cmd640_vlb = 1;
- 				goto done;
--			}
- #endif
- #ifdef CONFIG_BLK_DEV_HT6560B
- 			case -13: /* "ht6560b" */
-@@ -1560,79 +1532,6 @@ done:
- 	return 1;
+@@ -1529,13 +1550,31 @@ static void nodemgr_probe_ne(struct host_info *hi, struct node_entry *ne, int ge
+ 	put_device(dev);
  }
  
--extern void __init pnpide_init(void);
--extern void __exit pnpide_exit(void);
--extern void __init h8300_ide_init(void);
--
--/*
-- * probe_for_hwifs() finds/initializes "known" IDE interfaces
-- */
--static void __init probe_for_hwifs (void)
--{
--#ifdef CONFIG_IDEPCI_PCIBUS_ORDER
--	ide_scan_pcibus(ide_scan_direction);
--#endif
--
--#ifdef CONFIG_ETRAX_IDE
--	{
--		extern void init_e100_ide(void);
--		init_e100_ide();
--	}
--#endif /* CONFIG_ETRAX_IDE */
--#ifdef CONFIG_BLK_DEV_CMD640
--	{
--		extern void ide_probe_for_cmd640x(void);
--		ide_probe_for_cmd640x();
--	}
--#endif /* CONFIG_BLK_DEV_CMD640 */
--#ifdef CONFIG_BLK_DEV_IDE_PMAC
--	{
--		extern int pmac_ide_probe(void);
--		(void)pmac_ide_probe();
--	}
--#endif /* CONFIG_BLK_DEV_IDE_PMAC */
--#ifdef CONFIG_BLK_DEV_GAYLE
--	{
--		extern void gayle_init(void);
--		gayle_init();
--	}
--#endif /* CONFIG_BLK_DEV_GAYLE */
--#ifdef CONFIG_BLK_DEV_FALCON_IDE
--	{
--		extern void falconide_init(void);
--		falconide_init();
--	}
--#endif /* CONFIG_BLK_DEV_FALCON_IDE */
--#ifdef CONFIG_BLK_DEV_MAC_IDE
--	{
--		extern void macide_init(void);
--		macide_init();
--	}
--#endif /* CONFIG_BLK_DEV_MAC_IDE */
--#ifdef CONFIG_BLK_DEV_Q40IDE
--	{
--		extern void q40ide_init(void);
--		q40ide_init();
--	}
--#endif /* CONFIG_BLK_DEV_Q40IDE */
--#ifdef CONFIG_BLK_DEV_BUDDHA
--	{
--		extern void buddha_init(void);
--		buddha_init();
--	}
--#endif /* CONFIG_BLK_DEV_BUDDHA */
--#ifdef CONFIG_BLK_DEV_IDEPNP
--	pnpide_init();
--#endif
--#ifdef CONFIG_H8300
--	h8300_ide_init();
--#endif
--}
--
--/*
-- * Probe module
-- */
--
- EXPORT_SYMBOL(ide_lock);
++struct probe_param {
++	struct host_info *hi;
++	int generation;
++};
++
++static int __nodemgr_node_probe(struct device *dev, void *data)
++{
++	struct probe_param *param = (struct probe_param *)data;
++	struct node_entry *ne;
++
++	ne = container_of(dev, struct node_entry, node_dev);
++	if (!ne->needs_probe)
++		nodemgr_probe_ne(param->hi, ne, param->generation);
++	if (ne->needs_probe)
++		nodemgr_probe_ne(param->hi, ne, param->generation);
++	return 0;
++}
  
- static int ide_bus_match(struct device *dev, struct device_driver *drv)
-@@ -1779,30 +1678,6 @@ static int __init ide_init(void)
+ static void nodemgr_node_probe(struct host_info *hi, int generation)
+ {
+ 	struct hpsb_host *host = hi->host;
+-	struct device *dev;
+-	struct node_entry *ne;
++	struct probe_param param;
  
- 	proc_ide_create();
++	param.hi = hi;
++	param.generation = generation;
+ 	/* Do some processing of the nodes we've probed. This pulls them
+ 	 * into the sysfs layer if needed, and can result in processing of
+ 	 * unit-directories, or just updating the node and it's
+@@ -1545,19 +1584,7 @@ static void nodemgr_node_probe(struct host_info *hi, int generation)
+ 	 * while probes are time-consuming. (Well, those probes need some
+ 	 * improvement...) */
  
--#ifdef CONFIG_BLK_DEV_ALI14XX
--	if (probe_ali14xx)
--		(void)ali14xx_init();
--#endif
--#ifdef CONFIG_BLK_DEV_UMC8672
--	if (probe_umc8672)
--		(void)umc8672_init();
--#endif
--#ifdef CONFIG_BLK_DEV_DTC2278
--	if (probe_dtc2278)
--		(void)dtc2278_init();
--#endif
--#ifdef CONFIG_BLK_DEV_HT6560B
--	if (probe_ht6560b)
--		(void)ht6560b_init();
--#endif
--#ifdef CONFIG_BLK_DEV_QD65XX
--	if (probe_qd65xx)
--		(void)qd65xx_init();
--#endif
--
--	/* Probe for special PCI and other "known" interface chipsets. */
--	probe_for_hwifs();
+-	down(&nodemgr_ne_class.sem);
+-	list_for_each_entry(dev, &nodemgr_ne_class.devices, node) {
+-		ne = container_of(dev, struct node_entry, node_dev);
+-		if (!ne->needs_probe)
+-			nodemgr_probe_ne(hi, ne, generation);
+-	}
+-	list_for_each_entry(dev, &nodemgr_ne_class.devices, node) {
+-		ne = container_of(dev, struct node_entry, node_dev);
+-		if (ne->needs_probe)
+-			nodemgr_probe_ne(hi, ne, generation);
+-	}
+-	up(&nodemgr_ne_class.sem);
 -
++	class_for_each_device(&nodemgr_ne_class, &param, __nodemgr_node_probe);
+ 
+ 	/* If we had a bus reset while we were scanning the bus, it is
+ 	 * possible that we did not probe all nodes.  In that case, we
+@@ -1757,6 +1784,22 @@ exit:
  	return 0;
  }
  
-@@ -1838,10 +1713,6 @@ void __exit cleanup_module (void)
- 	for (index = 0; index < MAX_HWIFS; ++index)
- 		ide_unregister(index);
- 
--#ifdef CONFIG_BLK_DEV_IDEPNP
--	pnpide_exit();
--#endif
++struct host_iter_param {
++	void *data;
++	int (*cb)(struct hpsb_host *, void *);
++};
++
++static int __nodemgr_for_each_host(struct device *dev, void *data)
++{
++	struct hpsb_host *host;
++	struct host_iter_param *hip = (struct host_iter_param *)data;
++	int error = 0;
++
++	host = container_of(dev, struct hpsb_host, host_dev);
++	error = hip->cb(host, hip->data);
++
++	return error;
++}
+ /**
+  * nodemgr_for_each_host - call a function for each IEEE 1394 host
+  * @data: an address to supply to the callback
+@@ -1771,18 +1814,13 @@ exit:
+  */
+ int nodemgr_for_each_host(void *data, int (*cb)(struct hpsb_host *, void *))
+ {
+-	struct device *dev;
+-	struct hpsb_host *host;
+-	int error = 0;
 -
- 	proc_ide_destroy();
+-	down(&hpsb_host_class.sem);
+-	list_for_each_entry(dev, &hpsb_host_class.devices, node) {
+-		host = container_of(dev, struct hpsb_host, host_dev);
++	struct host_iter_param hip;
++	int error;
  
- 	bus_unregister(&ide_bus_type);
-diff --git a/drivers/ide/legacy/Makefile b/drivers/ide/legacy/Makefile
-index 4098223..7043ec7 100644
---- a/drivers/ide/legacy/Makefile
-+++ b/drivers/ide/legacy/Makefile
-@@ -1,15 +1,24 @@
+-		if ((error = cb(host, data)))
+-			break;
+-	}
+-	up(&hpsb_host_class.sem);
++	hip.cb = cb;
++	hip.data = data;
++	error = class_for_each_device(&hpsb_host_class, &hip,
++				      __nodemgr_for_each_host);
  
-+# link order is important here
+ 	return error;
+ }
+diff --git a/drivers/ieee1394/sbp2.c b/drivers/ieee1394/sbp2.c
+index b83d254..1eda11a 100644
+--- a/drivers/ieee1394/sbp2.c
++++ b/drivers/ieee1394/sbp2.c
+@@ -1963,6 +1963,12 @@ static int sbp2scsi_slave_alloc(struct scsi_device *sdev)
+ 	lu->sdev = sdev;
+ 	sdev->allow_restart = 1;
+ 
++	/*
++	 * Update the dma alignment (minimum alignment requirements for
++	 * start and end of DMA transfers) to be a sector
++	 */
++	blk_queue_update_dma_alignment(sdev->request_queue, 511);
 +
- obj-$(CONFIG_BLK_DEV_ALI14XX)		+= ali14xx.o
-+obj-$(CONFIG_BLK_DEV_UMC8672)		+= umc8672.o
- obj-$(CONFIG_BLK_DEV_DTC2278)		+= dtc2278.o
- obj-$(CONFIG_BLK_DEV_HT6560B)		+= ht6560b.o
- obj-$(CONFIG_BLK_DEV_QD65XX)		+= qd65xx.o
--obj-$(CONFIG_BLK_DEV_UMC8672)		+= umc8672.o
+ 	if (lu->workarounds & SBP2_WORKAROUND_INQUIRY_36)
+ 		sdev->inquiry_len = 36;
+ 	return 0;
+diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c
+index 2e39236..c015014 100644
+--- a/drivers/infiniband/core/cm.c
++++ b/drivers/infiniband/core/cm.c
+@@ -1,5 +1,5 @@
+ /*
+- * Copyright (c) 2004-2006 Intel Corporation.  All rights reserved.
++ * Copyright (c) 2004-2007 Intel Corporation.  All rights reserved.
+  * Copyright (c) 2004 Topspin Corporation.  All rights reserved.
+  * Copyright (c) 2004, 2005 Voltaire Corporation.  All rights reserved.
+  * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
+@@ -37,12 +37,14 @@
  
--obj-$(CONFIG_BLK_DEV_IDECS)		+= ide-cs.o
-+obj-$(CONFIG_BLK_DEV_GAYLE)		+= gayle.o
-+obj-$(CONFIG_BLK_DEV_FALCON_IDE)	+= falconide.o
-+obj-$(CONFIG_BLK_DEV_MAC_IDE)		+= macide.o
-+obj-$(CONFIG_BLK_DEV_Q40IDE)		+= q40ide.o
-+obj-$(CONFIG_BLK_DEV_BUDDHA)		+= buddha.o
+ #include <linux/completion.h>
+ #include <linux/dma-mapping.h>
++#include <linux/device.h>
+ #include <linux/err.h>
+ #include <linux/idr.h>
+ #include <linux/interrupt.h>
+ #include <linux/random.h>
+ #include <linux/rbtree.h>
+ #include <linux/spinlock.h>
++#include <linux/sysfs.h>
+ #include <linux/workqueue.h>
  
--obj-$(CONFIG_BLK_DEV_PLATFORM)		+= ide_platform.o
-+ifeq ($(CONFIG_BLK_DEV_IDECS), m)
-+	obj-m += ide-cs.o
-+endif
+ #include <rdma/ib_cache.h>
+@@ -78,17 +80,94 @@ static struct ib_cm {
+ 	struct workqueue_struct *wq;
+ } cm;
  
--# Last of all
--obj-$(CONFIG_BLK_DEV_HD)		+= hd.o
-+ifeq ($(CONFIG_BLK_DEV_PLATFORM), m)
-+	obj-m += ide_platform.o
-+endif
++/* Counter indexes ordered by attribute ID */
++enum {
++	CM_REQ_COUNTER,
++	CM_MRA_COUNTER,
++	CM_REJ_COUNTER,
++	CM_REP_COUNTER,
++	CM_RTU_COUNTER,
++	CM_DREQ_COUNTER,
++	CM_DREP_COUNTER,
++	CM_SIDR_REQ_COUNTER,
++	CM_SIDR_REP_COUNTER,
++	CM_LAP_COUNTER,
++	CM_APR_COUNTER,
++	CM_ATTR_COUNT,
++	CM_ATTR_ID_OFFSET = 0x0010,
++};
++
++enum {
++	CM_XMIT,
++	CM_XMIT_RETRIES,
++	CM_RECV,
++	CM_RECV_DUPLICATES,
++	CM_COUNTER_GROUPS
++};
++
++static char const counter_group_names[CM_COUNTER_GROUPS]
++				     [sizeof("cm_rx_duplicates")] = {
++	"cm_tx_msgs", "cm_tx_retries",
++	"cm_rx_msgs", "cm_rx_duplicates"
++};
++
++struct cm_counter_group {
++	struct kobject obj;
++	atomic_long_t counter[CM_ATTR_COUNT];
++};
++
++struct cm_counter_attribute {
++	struct attribute attr;
++	int index;
++};
++
++#define CM_COUNTER_ATTR(_name, _index) \
++struct cm_counter_attribute cm_##_name##_counter_attr = { \
++	.attr = { .name = __stringify(_name), .mode = 0444, .owner = THIS_MODULE }, \
++	.index = _index \
++}
++
++static CM_COUNTER_ATTR(req, CM_REQ_COUNTER);
++static CM_COUNTER_ATTR(mra, CM_MRA_COUNTER);
++static CM_COUNTER_ATTR(rej, CM_REJ_COUNTER);
++static CM_COUNTER_ATTR(rep, CM_REP_COUNTER);
++static CM_COUNTER_ATTR(rtu, CM_RTU_COUNTER);
++static CM_COUNTER_ATTR(dreq, CM_DREQ_COUNTER);
++static CM_COUNTER_ATTR(drep, CM_DREP_COUNTER);
++static CM_COUNTER_ATTR(sidr_req, CM_SIDR_REQ_COUNTER);
++static CM_COUNTER_ATTR(sidr_rep, CM_SIDR_REP_COUNTER);
++static CM_COUNTER_ATTR(lap, CM_LAP_COUNTER);
++static CM_COUNTER_ATTR(apr, CM_APR_COUNTER);
++
++static struct attribute *cm_counter_default_attrs[] = {
++	&cm_req_counter_attr.attr,
++	&cm_mra_counter_attr.attr,
++	&cm_rej_counter_attr.attr,
++	&cm_rep_counter_attr.attr,
++	&cm_rtu_counter_attr.attr,
++	&cm_dreq_counter_attr.attr,
++	&cm_drep_counter_attr.attr,
++	&cm_sidr_req_counter_attr.attr,
++	&cm_sidr_rep_counter_attr.attr,
++	&cm_lap_counter_attr.attr,
++	&cm_apr_counter_attr.attr,
++	NULL
++};
++
+ struct cm_port {
+ 	struct cm_device *cm_dev;
+ 	struct ib_mad_agent *mad_agent;
++	struct kobject port_obj;
+ 	u8 port_num;
++	struct cm_counter_group counter_group[CM_COUNTER_GROUPS];
+ };
  
- EXTRA_CFLAGS	:= -Idrivers/ide
-diff --git a/drivers/ide/legacy/ali14xx.c b/drivers/ide/legacy/ali14xx.c
-index 38c3a6d..5ec0be4 100644
---- a/drivers/ide/legacy/ali14xx.c
-+++ b/drivers/ide/legacy/ali14xx.c
-@@ -231,8 +231,7 @@ int probe_ali14xx = 0;
- module_param_named(probe, probe_ali14xx, bool, 0);
- MODULE_PARM_DESC(probe, "probe for ALI M14xx chipsets");
+ struct cm_device {
+ 	struct list_head list;
+ 	struct ib_device *device;
++	struct kobject dev_obj;
+ 	u8 ack_delay;
+-	struct cm_port port[0];
++	struct cm_port *port[0];
+ };
  
--/* Can be called directly from ide.c. */
--int __init ali14xx_init(void)
-+static int __init ali14xx_init(void)
- {
- 	if (probe_ali14xx == 0)
- 		goto out;
-@@ -248,9 +247,7 @@ out:
- 	return -ENODEV;
- }
+ struct cm_av {
+@@ -278,7 +357,7 @@ static int cm_init_av_by_path(struct ib_sa_path_rec *path, struct cm_av *av)
+ 	list_for_each_entry(cm_dev, &cm.device_list, list) {
+ 		if (!ib_find_cached_gid(cm_dev->device, &path->sgid,
+ 					&p, NULL)) {
+-			port = &cm_dev->port[p-1];
++			port = cm_dev->port[p-1];
+ 			break;
+ 		}
+ 	}
+@@ -1270,6 +1349,9 @@ static void cm_dup_req_handler(struct cm_work *work,
+ 	struct ib_mad_send_buf *msg = NULL;
+ 	int ret;
  
--#ifdef MODULE
- module_init(ali14xx_init);
--#endif
++	atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES].
++			counter[CM_REQ_COUNTER]);
++
+ 	/* Quick state check to discard duplicate REQs. */
+ 	if (cm_id_priv->id.state == IB_CM_REQ_RCVD)
+ 		return;
+@@ -1616,6 +1698,8 @@ static void cm_dup_rep_handler(struct cm_work *work)
+ 	if (!cm_id_priv)
+ 		return;
  
- MODULE_AUTHOR("see local file");
- MODULE_DESCRIPTION("support of ALI 14XX IDE chipsets");
-diff --git a/drivers/ide/legacy/buddha.c b/drivers/ide/legacy/buddha.c
-index 4a0be25..74d28e0 100644
---- a/drivers/ide/legacy/buddha.c
-+++ b/drivers/ide/legacy/buddha.c
-@@ -112,6 +112,7 @@ typedef enum BuddhaType_Enum {
-     BOARD_BUDDHA, BOARD_CATWEASEL, BOARD_XSURF
- } BuddhaType;
++	atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES].
++			counter[CM_REP_COUNTER]);
+ 	ret = cm_alloc_response_msg(work->port, work->mad_recv_wc, &msg);
+ 	if (ret)
+ 		goto deref;
+@@ -1781,6 +1865,8 @@ static int cm_rtu_handler(struct cm_work *work)
+ 	if (cm_id_priv->id.state != IB_CM_REP_SENT &&
+ 	    cm_id_priv->id.state != IB_CM_MRA_REP_RCVD) {
+ 		spin_unlock_irq(&cm_id_priv->lock);
++		atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES].
++				counter[CM_RTU_COUNTER]);
+ 		goto out;
+ 	}
+ 	cm_id_priv->id.state = IB_CM_ESTABLISHED;
+@@ -1958,6 +2044,8 @@ static int cm_dreq_handler(struct cm_work *work)
+ 	cm_id_priv = cm_acquire_id(dreq_msg->remote_comm_id,
+ 				   dreq_msg->local_comm_id);
+ 	if (!cm_id_priv) {
++		atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES].
++				counter[CM_DREQ_COUNTER]);
+ 		cm_issue_drep(work->port, work->mad_recv_wc);
+ 		return -EINVAL;
+ 	}
+@@ -1977,6 +2065,8 @@ static int cm_dreq_handler(struct cm_work *work)
+ 	case IB_CM_MRA_REP_RCVD:
+ 		break;
+ 	case IB_CM_TIMEWAIT:
++		atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES].
++				counter[CM_DREQ_COUNTER]);
+ 		if (cm_alloc_response_msg(work->port, work->mad_recv_wc, &msg))
+ 			goto unlock;
  
-+static const char *buddha_board_name[] = { "Buddha", "Catweasel", "X-Surf" };
+@@ -1988,6 +2078,10 @@ static int cm_dreq_handler(struct cm_work *work)
+ 		if (ib_post_send_mad(msg, NULL))
+ 			cm_free_msg(msg);
+ 		goto deref;
++	case IB_CM_DREQ_RCVD:
++		atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES].
++				counter[CM_DREQ_COUNTER]);
++		goto unlock;
+ 	default:
+ 		goto unlock;
+ 	}
+@@ -2339,10 +2433,20 @@ static int cm_mra_handler(struct cm_work *work)
+ 		if (cm_mra_get_msg_mraed(mra_msg) != CM_MSG_RESPONSE_OTHER ||
+ 		    cm_id_priv->id.lap_state != IB_CM_LAP_SENT ||
+ 		    ib_modify_mad(cm_id_priv->av.port->mad_agent,
+-				  cm_id_priv->msg, timeout))
++				  cm_id_priv->msg, timeout)) {
++			if (cm_id_priv->id.lap_state == IB_CM_MRA_LAP_RCVD)
++				atomic_long_inc(&work->port->
++						counter_group[CM_RECV_DUPLICATES].
++						counter[CM_MRA_COUNTER]);
+ 			goto out;
++		}
+ 		cm_id_priv->id.lap_state = IB_CM_MRA_LAP_RCVD;
+ 		break;
++	case IB_CM_MRA_REQ_RCVD:
++	case IB_CM_MRA_REP_RCVD:
++		atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES].
++				counter[CM_MRA_COUNTER]);
++		/* fall through */
+ 	default:
+ 		goto out;
+ 	}
+@@ -2502,6 +2606,8 @@ static int cm_lap_handler(struct cm_work *work)
+ 	case IB_CM_LAP_IDLE:
+ 		break;
+ 	case IB_CM_MRA_LAP_SENT:
++		atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES].
++				counter[CM_LAP_COUNTER]);
+ 		if (cm_alloc_response_msg(work->port, work->mad_recv_wc, &msg))
+ 			goto unlock;
  
-     /*
-      *  Check and acknowledge the interrupt status
-@@ -143,11 +144,11 @@ static int xsurf_ack_intr(ide_hwif_t *hwif)
-      *  Probe for a Buddha or Catweasel IDE interface
-      */
+@@ -2515,6 +2621,10 @@ static int cm_lap_handler(struct cm_work *work)
+ 		if (ib_post_send_mad(msg, NULL))
+ 			cm_free_msg(msg);
+ 		goto deref;
++	case IB_CM_LAP_RCVD:
++		atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES].
++				counter[CM_LAP_COUNTER]);
++		goto unlock;
+ 	default:
+ 		goto unlock;
+ 	}
+@@ -2796,6 +2906,8 @@ static int cm_sidr_req_handler(struct cm_work *work)
+ 	cur_cm_id_priv = cm_insert_remote_sidr(cm_id_priv);
+ 	if (cur_cm_id_priv) {
+ 		spin_unlock_irq(&cm.lock);
++		atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES].
++				counter[CM_SIDR_REQ_COUNTER]);
+ 		goto out; /* Duplicate message. */
+ 	}
+ 	cm_id_priv->id.state = IB_CM_SIDR_REQ_RCVD;
+@@ -2990,6 +3102,27 @@ static void cm_send_handler(struct ib_mad_agent *mad_agent,
+ 			    struct ib_mad_send_wc *mad_send_wc)
+ {
+ 	struct ib_mad_send_buf *msg = mad_send_wc->send_buf;
++	struct cm_port *port;
++	u16 attr_index;
++
++	port = mad_agent->context;
++	attr_index = be16_to_cpu(((struct ib_mad_hdr *)
++				  msg->mad)->attr_id) - CM_ATTR_ID_OFFSET;
++
++	/*
++	 * If the send was in response to a received message (context[0] is not
++	 * set to a cm_id), and is not a REJ, then it is a send that was
++	 * manually retried.
++	 */
++	if (!msg->context[0] && (attr_index != CM_REJ_COUNTER))
++		msg->retries = 1;
++
++	atomic_long_add(1 + msg->retries,
++			&port->counter_group[CM_XMIT].counter[attr_index]);
++	if (msg->retries)
++		atomic_long_add(msg->retries,
++				&port->counter_group[CM_XMIT_RETRIES].
++				counter[attr_index]);
  
--void __init buddha_init(void)
-+static int __init buddha_init(void)
+ 	switch (mad_send_wc->status) {
+ 	case IB_WC_SUCCESS:
+@@ -3148,8 +3281,10 @@ EXPORT_SYMBOL(ib_cm_notify);
+ static void cm_recv_handler(struct ib_mad_agent *mad_agent,
+ 			    struct ib_mad_recv_wc *mad_recv_wc)
  {
- 	hw_regs_t hw;
- 	ide_hwif_t *hwif;
--	int i, index;
-+	int i;
++	struct cm_port *port = mad_agent->context;
+ 	struct cm_work *work;
+ 	enum ib_cm_event_type event;
++	u16 attr_id;
+ 	int paths = 0;
  
- 	struct zorro_dev *z = NULL;
- 	u_long buddha_board = 0;
-@@ -156,6 +157,8 @@ void __init buddha_init(void)
+ 	switch (mad_recv_wc->recv_buf.mad->mad_hdr.attr_id) {
+@@ -3194,6 +3329,10 @@ static void cm_recv_handler(struct ib_mad_agent *mad_agent,
+ 		return;
+ 	}
  
- 	while ((z = zorro_find_device(ZORRO_WILDCARD, z))) {
- 		unsigned long board;
-+		u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
++	attr_id = be16_to_cpu(mad_recv_wc->recv_buf.mad->mad_hdr.attr_id);
++	atomic_long_inc(&port->counter_group[CM_RECV].
++			counter[attr_id - CM_ATTR_ID_OFFSET]);
 +
- 		if (z->id == ZORRO_PROD_INDIVIDUAL_COMPUTERS_BUDDHA) {
- 			buddha_num_hwifs = BUDDHA_NUM_HWIFS;
- 			type=BOARD_BUDDHA;
-@@ -195,7 +198,10 @@ fail_base2:
- 		/* X-Surf doesn't have this.  IRQs are always on */
- 		if (type != BOARD_XSURF)
- 			z_writeb(0, buddha_board+BUDDHA_IRQ_MR);
--		
+ 	work = kmalloc(sizeof *work + sizeof(struct ib_sa_path_rec) * paths,
+ 		       GFP_KERNEL);
+ 	if (!work) {
+@@ -3204,7 +3343,7 @@ static void cm_recv_handler(struct ib_mad_agent *mad_agent,
+ 	INIT_DELAYED_WORK(&work->work, cm_work_handler);
+ 	work->cm_event.event = event;
+ 	work->mad_recv_wc = mad_recv_wc;
+-	work->port = (struct cm_port *)mad_agent->context;
++	work->port = port;
+ 	queue_delayed_work(cm.wq, &work->work, 0);
+ }
+ 
+@@ -3379,6 +3518,108 @@ static void cm_get_ack_delay(struct cm_device *cm_dev)
+ 		cm_dev->ack_delay = attr.local_ca_ack_delay;
+ }
+ 
++static ssize_t cm_show_counter(struct kobject *obj, struct attribute *attr,
++			       char *buf)
++{
++	struct cm_counter_group *group;
++	struct cm_counter_attribute *cm_attr;
 +
-+		printk(KERN_INFO "ide: %s IDE controller\n",
-+				 buddha_board_name[type]);
++	group = container_of(obj, struct cm_counter_group, obj);
++	cm_attr = container_of(attr, struct cm_counter_attribute, attr);
 +
- 		for(i=0;i<buddha_num_hwifs;i++) {
- 			if(type != BOARD_XSURF) {
- 				ide_setup_ports(&hw, (buddha_board+buddha_bases[i]),
-@@ -213,23 +219,23 @@ fail_base2:
- 						IRQ_AMIGA_PORTS);
- 			}	
- 
--			index = ide_register_hw(&hw, NULL, 1, &hwif);
--			if (index != -1) {
-+			hwif = ide_find_port(hw.io_ports[IDE_DATA_OFFSET]);
-+			if (hwif) {
-+				u8 index = hwif->index;
++	return sprintf(buf, "%ld\n",
++		       atomic_long_read(&group->counter[cm_attr->index]));
++}
 +
-+				ide_init_port_data(hwif, index);
-+				ide_init_port_hw(hwif, &hw);
++static struct sysfs_ops cm_counter_ops = {
++	.show = cm_show_counter
++};
 +
- 				hwif->mmio = 1;
--				printk("ide%d: ", index);
--				switch(type) {
--				case BOARD_BUDDHA:
--					printk("Buddha");
--					break;
--				case BOARD_CATWEASEL:
--					printk("Catweasel");
--					break;
--				case BOARD_XSURF:
--					printk("X-Surf");
--					break;
--				}
--				printk(" IDE interface\n");	    
--			}		      
++static struct kobj_type cm_counter_obj_type = {
++	.sysfs_ops = &cm_counter_ops,
++	.default_attrs = cm_counter_default_attrs
++};
 +
-+				idx[i] = index;
-+			}
- 		}
++static void cm_release_port_obj(struct kobject *obj)
++{
++	struct cm_port *cm_port;
 +
-+		ide_device_add(idx);
- 	}
++	printk(KERN_ERR "free cm port\n");
 +
-+	return 0;
- }
++	cm_port = container_of(obj, struct cm_port, port_obj);
++	kfree(cm_port);
++}
 +
-+module_init(buddha_init);
-diff --git a/drivers/ide/legacy/dtc2278.c b/drivers/ide/legacy/dtc2278.c
-index 24a845d..13eee6d 100644
---- a/drivers/ide/legacy/dtc2278.c
-+++ b/drivers/ide/legacy/dtc2278.c
-@@ -150,8 +150,7 @@ int probe_dtc2278 = 0;
- module_param_named(probe, probe_dtc2278, bool, 0);
- MODULE_PARM_DESC(probe, "probe for DTC2278xx chipsets");
- 
--/* Can be called directly from ide.c. */
--int __init dtc2278_init(void)
-+static int __init dtc2278_init(void)
- {
- 	if (probe_dtc2278 == 0)
- 		return -ENODEV;
-@@ -163,9 +162,7 @@ int __init dtc2278_init(void)
- 	return 0;
- }
- 
--#ifdef MODULE
- module_init(dtc2278_init);
--#endif
- 
- MODULE_AUTHOR("See Local File");
- MODULE_DESCRIPTION("support of DTC-2278 VLB IDE chipsets");
-diff --git a/drivers/ide/legacy/falconide.c b/drivers/ide/legacy/falconide.c
-index 7d7936f..2860956 100644
---- a/drivers/ide/legacy/falconide.c
-+++ b/drivers/ide/legacy/falconide.c
-@@ -62,19 +62,31 @@ EXPORT_SYMBOL(falconide_intr_lock);
-      *  Probe for a Falcon IDE interface
-      */
- 
--void __init falconide_init(void)
-+static int __init falconide_init(void)
- {
-     if (MACH_IS_ATARI && ATARIHW_PRESENT(IDE)) {
- 	hw_regs_t hw;
--	int index;
++static struct kobj_type cm_port_obj_type = {
++	.release = cm_release_port_obj
++};
 +
-+	printk(KERN_INFO "ide: Falcon IDE controller\n");
- 
- 	ide_setup_ports(&hw, ATA_HD_BASE, falconide_offsets,
- 			0, 0, NULL,
- //			falconide_iops,
- 			IRQ_MFP_IDE);
--	index = ide_register_hw(&hw, NULL, 1, NULL);
- 
--	if (index != -1)
--	    printk("ide%d: Falcon IDE interface\n", index);
-+	hwif = ide_find_port(hw.io_ports[IDE_DATA_OFFSET]);
-+	if (hwif) {
-+		u8 index = hwif->index;
-+		u8 idx[4] = { index, 0xff, 0xff, 0xff };
++static void cm_release_dev_obj(struct kobject *obj)
++{
++	struct cm_device *cm_dev;
 +
-+		ide_init_port_data(hwif, index);
-+		ide_init_port_hw(hwif, &hw);
++	printk(KERN_ERR "free cm dev\n");
 +
-+		ide_device_add(idx);
-+	}
-     }
++	cm_dev = container_of(obj, struct cm_device, dev_obj);
++	kfree(cm_dev);
++}
 +
-+    return 0;
- }
++static struct kobj_type cm_dev_obj_type = {
++	.release = cm_release_dev_obj
++};
 +
-+module_init(falconide_init);
-diff --git a/drivers/ide/legacy/gayle.c b/drivers/ide/legacy/gayle.c
-index 53331ee..492fa04 100644
---- a/drivers/ide/legacy/gayle.c
-+++ b/drivers/ide/legacy/gayle.c
-@@ -110,12 +110,13 @@ static int gayle_ack_intr_a1200(ide_hwif_t *hwif)
-      *  Probe for a Gayle IDE interface (and optionally for an IDE doubler)
-      */
- 
--void __init gayle_init(void)
-+static int __init gayle_init(void)
- {
-     int a4000, i;
-+    u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
- 
-     if (!MACH_IS_AMIGA)
--	return;
-+	return -ENODEV;
- 
-     if ((a4000 = AMIGAHW_PRESENT(A4000_IDE)) || AMIGAHW_PRESENT(A1200_IDE))
- 	goto found;
-@@ -125,15 +126,21 @@ void __init gayle_init(void)
- 			  NULL))
- 	goto found;
- #endif
--    return;
-+    return -ENODEV;
- 
- found:
-+	printk(KERN_INFO "ide: Gayle IDE controller (A%d style%s)\n",
-+			 a4000 ? 4000 : 1200,
-+#ifdef CONFIG_BLK_DEV_IDEDOUBLER
-+			 ide_doubler ? ", IDE doubler" :
-+#endif
-+			 "");
++struct class cm_class = {
++	.name    = "infiniband_cm",
++};
++EXPORT_SYMBOL(cm_class);
++
++static void cm_remove_fs_obj(struct kobject *obj)
++{
++	kobject_put(obj->parent);
++	kobject_put(obj);
++}
++
++static int cm_create_port_fs(struct cm_port *port)
++{
++	int i, ret;
++
++	ret = kobject_init_and_add(&port->port_obj, &cm_port_obj_type,
++				   kobject_get(&port->cm_dev->dev_obj),
++				   "%d", port->port_num);
++	if (ret) {
++		kfree(port);
++		return ret;
++	}
 +
-     for (i = 0; i < GAYLE_NUM_PROBE_HWIFS; i++) {
- 	unsigned long base, ctrlport, irqport;
- 	ide_ack_intr_t *ack_intr;
- 	hw_regs_t hw;
- 	ide_hwif_t *hwif;
--	int index;
- 	unsigned long phys_base, res_start, res_n;
- 
- 	if (a4000) {
-@@ -165,21 +172,23 @@ found:
- //			&gayle_iops,
- 			IRQ_AMIGA_PORTS);
- 
--	index = ide_register_hw(&hw, NULL, 1, &hwif);
--	if (index != -1) {
-+	hwif = ide_find_port(base);
-+	if (hwif) {
-+	    u8 index = hwif->index;
++	for (i = 0; i < CM_COUNTER_GROUPS; i++) {
++		ret = kobject_init_and_add(&port->counter_group[i].obj,
++					   &cm_counter_obj_type,
++					   kobject_get(&port->port_obj),
++					   "%s", counter_group_names[i]);
++		if (ret)
++			goto error;
++	}
 +
-+	    ide_init_port_data(hwif, index);
-+	    ide_init_port_hw(hwif, &hw);
++	return 0;
 +
- 	    hwif->mmio = 1;
--	    switch (i) {
--		case 0:
--		    printk("ide%d: Gayle IDE interface (A%d style)\n", index,
--			   a4000 ? 4000 : 1200);
--		    break;
--#ifdef CONFIG_BLK_DEV_IDEDOUBLER
--		case 1:
--		    printk("ide%d: IDE doubler\n", index);
--		    break;
--#endif /* CONFIG_BLK_DEV_IDEDOUBLER */
--	    }
++error:
++	while (i--)
++		cm_remove_fs_obj(&port->counter_group[i].obj);
++	cm_remove_fs_obj(&port->port_obj);
++	return ret;
 +
-+	    idx[i] = index;
- 	} else
- 	    release_mem_region(res_start, res_n);
-     }
++}
 +
-+    ide_device_add(idx);
++static void cm_remove_port_fs(struct cm_port *port)
++{
++	int i;
 +
-+    return 0;
- }
++	for (i = 0; i < CM_COUNTER_GROUPS; i++)
++		cm_remove_fs_obj(&port->counter_group[i].obj);
 +
-+module_init(gayle_init);
-diff --git a/drivers/ide/legacy/ht6560b.c b/drivers/ide/legacy/ht6560b.c
-index a4245d1..8da5031 100644
---- a/drivers/ide/legacy/ht6560b.c
-+++ b/drivers/ide/legacy/ht6560b.c
-@@ -307,8 +307,7 @@ int probe_ht6560b = 0;
- module_param_named(probe, probe_ht6560b, bool, 0);
- MODULE_PARM_DESC(probe, "probe for HT6560B chipset");
- 
--/* Can be called directly from ide.c. */
--int __init ht6560b_init(void)
-+static int __init ht6560b_init(void)
++	cm_remove_fs_obj(&port->port_obj);
++}
++
+ static void cm_add_one(struct ib_device *device)
  {
- 	ide_hwif_t *hwif, *mate;
- 	static u8 idx[4] = { 0, 1, 0xff, 0xff };
-@@ -369,9 +368,7 @@ release_region:
- 	return -ENODEV;
- }
- 
--#ifdef MODULE
- module_init(ht6560b_init);
--#endif
- 
- MODULE_AUTHOR("See Local File");
- MODULE_DESCRIPTION("HT-6560B EIDE-controller support");
-diff --git a/drivers/ide/legacy/ide-cs.c b/drivers/ide/legacy/ide-cs.c
-index 03715c0..f4ea15b 100644
---- a/drivers/ide/legacy/ide-cs.c
-+++ b/drivers/ide/legacy/ide-cs.c
-@@ -153,7 +153,7 @@ static int idecs_register(unsigned long io, unsigned long ctl, unsigned long irq
-     hw.irq = irq;
-     hw.chipset = ide_pci;
-     hw.dev = &handle->dev;
--    return ide_register_hw(&hw, &ide_undecoded_slave, 0, NULL);
-+    return ide_register_hw(&hw, &ide_undecoded_slave, NULL);
- }
+ 	struct cm_device *cm_dev;
+@@ -3397,7 +3638,7 @@ static void cm_add_one(struct ib_device *device)
+ 	if (rdma_node_get_transport(device->node_type) != RDMA_TRANSPORT_IB)
+ 		return;
  
- /*======================================================================
-diff --git a/drivers/ide/legacy/ide_platform.c b/drivers/ide/legacy/ide_platform.c
-index 7bb79f5..69a0fb0 100644
---- a/drivers/ide/legacy/ide_platform.c
-+++ b/drivers/ide/legacy/ide_platform.c
-@@ -28,39 +28,27 @@ static struct {
- 	int index;
- } hwif_prop;
+-	cm_dev = kmalloc(sizeof(*cm_dev) + sizeof(*port) *
++	cm_dev = kzalloc(sizeof(*cm_dev) + sizeof(*port) *
+ 			 device->phys_port_cnt, GFP_KERNEL);
+ 	if (!cm_dev)
+ 		return;
+@@ -3405,11 +3646,27 @@ static void cm_add_one(struct ib_device *device)
+ 	cm_dev->device = device;
+ 	cm_get_ack_delay(cm_dev);
  
--static ide_hwif_t *__devinit plat_ide_locate_hwif(void __iomem *base,
--	    void __iomem *ctrl, struct pata_platform_info *pdata, int irq,
--	    int mmio)
-+static void __devinit plat_ide_setup_ports(hw_regs_t *hw,
-+					   void __iomem *base,
-+					   void __iomem *ctrl,
-+					   struct pata_platform_info *pdata,
-+					   int irq)
- {
- 	unsigned long port = (unsigned long)base;
--	ide_hwif_t *hwif = ide_find_port(port);
- 	int i;
++	ret = kobject_init_and_add(&cm_dev->dev_obj, &cm_dev_obj_type,
++				   &cm_class.subsys.kobj, "%s", device->name);
++	if (ret) {
++		kfree(cm_dev);
++		return;
++	}
++
+ 	set_bit(IB_MGMT_METHOD_SEND, reg_req.method_mask);
+ 	for (i = 1; i <= device->phys_port_cnt; i++) {
+-		port = &cm_dev->port[i-1];
++		port = kzalloc(sizeof *port, GFP_KERNEL);
++		if (!port)
++			goto error1;
++
++		cm_dev->port[i-1] = port;
+ 		port->cm_dev = cm_dev;
+ 		port->port_num = i;
++
++		ret = cm_create_port_fs(port);
++		if (ret)
++			goto error1;
++
+ 		port->mad_agent = ib_register_mad_agent(device, i,
+ 							IB_QPT_GSI,
+ 							&reg_req,
+@@ -3418,11 +3675,11 @@ static void cm_add_one(struct ib_device *device)
+ 							cm_recv_handler,
+ 							port);
+ 		if (IS_ERR(port->mad_agent))
+-			goto error1;
++			goto error2;
  
--	if (hwif == NULL)
--		goto out;
--
--	hwif->io_ports[IDE_DATA_OFFSET] = port;
-+	hw->io_ports[IDE_DATA_OFFSET] = port;
+ 		ret = ib_modify_port(device, i, 0, &port_modify);
+ 		if (ret)
+-			goto error2;
++			goto error3;
+ 	}
+ 	ib_set_client_data(device, &cm_client, cm_dev);
  
- 	port += (1 << pdata->ioport_shift);
- 	for (i = IDE_ERROR_OFFSET; i <= IDE_STATUS_OFFSET;
- 	     i++, port += (1 << pdata->ioport_shift))
--		hwif->io_ports[i] = port;
--
--	hwif->io_ports[IDE_CONTROL_OFFSET] = (unsigned long)ctrl;
-+		hw->io_ports[i] = port;
+@@ -3431,17 +3688,20 @@ static void cm_add_one(struct ib_device *device)
+ 	write_unlock_irqrestore(&cm.device_lock, flags);
+ 	return;
  
--	hwif->irq = irq;
-+	hw->io_ports[IDE_CONTROL_OFFSET] = (unsigned long)ctrl;
+-error2:
++error3:
+ 	ib_unregister_mad_agent(port->mad_agent);
++error2:
++	cm_remove_port_fs(port);
+ error1:
+ 	port_modify.set_port_cap_mask = 0;
+ 	port_modify.clr_port_cap_mask = IB_PORT_CM_SUP;
+ 	while (--i) {
+-		port = &cm_dev->port[i-1];
++		port = cm_dev->port[i-1];
+ 		ib_modify_port(device, port->port_num, 0, &port_modify);
+ 		ib_unregister_mad_agent(port->mad_agent);
++		cm_remove_port_fs(port);
+ 	}
+-	kfree(cm_dev);
++	cm_remove_fs_obj(&cm_dev->dev_obj);
+ }
  
--	hwif->chipset = ide_generic;
-+	hw->irq = irq;
+ static void cm_remove_one(struct ib_device *device)
+@@ -3463,11 +3723,12 @@ static void cm_remove_one(struct ib_device *device)
+ 	write_unlock_irqrestore(&cm.device_lock, flags);
  
--	if (mmio) {
--		hwif->mmio = 1;
--		default_hwif_mmiops(hwif);
--	}
--
--	hwif_prop.hwif = hwif;
--	hwif_prop.index = hwif->index;
--out:
--	return hwif;
-+	hw->chipset = ide_generic;
+ 	for (i = 1; i <= device->phys_port_cnt; i++) {
+-		port = &cm_dev->port[i-1];
++		port = cm_dev->port[i-1];
+ 		ib_modify_port(device, port->port_num, 0, &port_modify);
+ 		ib_unregister_mad_agent(port->mad_agent);
++		cm_remove_port_fs(port);
+ 	}
+-	kfree(cm_dev);
++	cm_remove_fs_obj(&cm_dev->dev_obj);
  }
  
- static int __devinit plat_ide_probe(struct platform_device *pdev)
-@@ -71,6 +59,7 @@ static int __devinit plat_ide_probe(struct platform_device *pdev)
- 	u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
- 	int ret = 0;
- 	int mmio = 0;
-+	hw_regs_t hw;
- 
- 	pdata = pdev->dev.platform_data;
+ static int __init ib_cm_init(void)
+@@ -3488,17 +3749,25 @@ static int __init ib_cm_init(void)
+ 	idr_pre_get(&cm.local_id_table, GFP_KERNEL);
+ 	INIT_LIST_HEAD(&cm.timewait_list);
  
-@@ -106,15 +95,27 @@ static int __devinit plat_ide_probe(struct platform_device *pdev)
- 			res_alt->start, res_alt->end - res_alt->start + 1);
- 	}
+-	cm.wq = create_workqueue("ib_cm");
+-	if (!cm.wq)
++	ret = class_register(&cm_class);
++	if (ret)
+ 		return -ENOMEM;
  
--	hwif = plat_ide_locate_hwif(hwif_prop.plat_ide_mapbase,
--	         hwif_prop.plat_ide_alt_mapbase, pdata, res_irq->start, mmio);
--
-+	hwif = ide_find_port((unsigned long)hwif_prop.plat_ide_mapbase);
- 	if (!hwif) {
- 		ret = -ENODEV;
- 		goto out;
- 	}
--	hwif->gendev.parent = &pdev->dev;
--	hwif->noprobe = 0;
-+
-+	memset(&hw, 0, sizeof(hw));
-+	plat_ide_setup_ports(&hw, hwif_prop.plat_ide_mapbase,
-+			     hwif_prop.plat_ide_alt_mapbase,
-+			     pdata, res_irq->start);
-+	hw.dev = &pdev->dev;
-+
-+	ide_init_port_hw(hwif, &hw);
-+
-+	if (mmio) {
-+		hwif->mmio = 1;
-+		default_hwif_mmiops(hwif);
++	cm.wq = create_workqueue("ib_cm");
++	if (!cm.wq) {
++		ret = -ENOMEM;
++		goto error1;
 +	}
 +
-+	hwif_prop.hwif = hwif;
-+	hwif_prop.index = hwif->index;
- 
- 	idx[0] = hwif->index;
+ 	ret = ib_register_client(&cm_client);
+ 	if (ret)
+-		goto error;
++		goto error2;
  
-diff --git a/drivers/ide/legacy/macide.c b/drivers/ide/legacy/macide.c
-index 5c6aa77..782d4c7 100644
---- a/drivers/ide/legacy/macide.c
-+++ b/drivers/ide/legacy/macide.c
-@@ -77,15 +77,17 @@ int macide_ack_intr(ide_hwif_t* hwif)
  	return 0;
+-error:
++error2:
+ 	destroy_workqueue(cm.wq);
++error1:
++	class_unregister(&cm_class);
+ 	return ret;
  }
  
-+static const char *mac_ide_name[] =
-+	{ "Quadra", "Powerbook", "Powerbook Baboon" };
-+
- /*
-  * Probe for a Macintosh IDE interface
-  */
+@@ -3519,6 +3788,7 @@ static void __exit ib_cm_cleanup(void)
+ 	}
  
--void __init macide_init(void)
-+static int __init macide_init(void)
- {
- 	hw_regs_t hw;
- 	ide_hwif_t *hwif;
--	int index = -1;
+ 	ib_unregister_client(&cm_client);
++	class_unregister(&cm_class);
+ 	idr_destroy(&cm.local_id_table);
+ }
  
- 	switch (macintosh_config->ide_type) {
- 	case MAC_IDE_QUADRA:
-@@ -93,48 +95,50 @@ void __init macide_init(void)
- 				0, 0, macide_ack_intr,
- //				quadra_ide_iops,
- 				IRQ_NUBUS_F);
--		index = ide_register_hw(&hw, NULL, 1, &hwif);
- 		break;
- 	case MAC_IDE_PB:
- 		ide_setup_ports(&hw, IDE_BASE, macide_offsets,
- 				0, 0, macide_ack_intr,
- //				macide_pb_iops,
- 				IRQ_NUBUS_C);
--		index = ide_register_hw(&hw, NULL, 1, &hwif);
- 		break;
- 	case MAC_IDE_BABOON:
- 		ide_setup_ports(&hw, BABOON_BASE, macide_offsets,
- 				0, 0, NULL,
- //				macide_baboon_iops,
- 				IRQ_BABOON_1);
--		index = ide_register_hw(&hw, NULL, 1, &hwif);
--		if (index == -1) break;
--		if (macintosh_config->ident == MAC_MODEL_PB190) {
-+		break;
-+	default:
-+		return -ENODEV;
-+	}
-+
-+	printk(KERN_INFO "ide: Macintosh %s IDE controller\n",
-+			 mac_ide_name[macintosh_config->ide_type - 1]);
+diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c
+index 0751697..637efea 100644
+--- a/drivers/infiniband/core/cma.c
++++ b/drivers/infiniband/core/cma.c
+@@ -488,7 +488,8 @@ void rdma_destroy_qp(struct rdma_cm_id *id)
+ }
+ EXPORT_SYMBOL(rdma_destroy_qp);
  
-+	hwif = ide_find_port(hw.io_ports[IDE_DATA_OFFSET]);
-+	if (hwif) {
-+		u8 index = hwif->index;
-+		u8 idx[4] = { index, 0xff, 0xff, 0xff };
-+
-+		ide_init_port_data(hwif, index);
-+		ide_init_port_hw(hwif, &hw);
-+
-+		if (macintosh_config->ide_type == MAC_IDE_BABOON &&
-+		    macintosh_config->ident == MAC_MODEL_PB190) {
- 			/* Fix breakage in ide-disk.c: drive capacity	*/
- 			/* is not initialized for drives without a 	*/
- 			/* hardware ID, and we can't get that without	*/
- 			/* probing the drive which freezes a 190.	*/
--
--			ide_drive_t *drive = &ide_hwifs[index].drives[0];
-+			ide_drive_t *drive = &hwif->drives[0];
- 			drive->capacity64 = drive->cyl*drive->head*drive->sect;
--
- 		}
--		break;
--
--	default:
--	    return;
--	}
+-static int cma_modify_qp_rtr(struct rdma_id_private *id_priv)
++static int cma_modify_qp_rtr(struct rdma_id_private *id_priv,
++			     struct rdma_conn_param *conn_param)
+ {
+ 	struct ib_qp_attr qp_attr;
+ 	int qp_attr_mask, ret;
+@@ -514,13 +515,16 @@ static int cma_modify_qp_rtr(struct rdma_id_private *id_priv)
+ 	if (ret)
+ 		goto out;
  
--        if (index != -1) {
- 		hwif->mmio = 1;
--		if (macintosh_config->ide_type == MAC_IDE_QUADRA)
--			printk(KERN_INFO "ide%d: Macintosh Quadra IDE interface\n", index);
--		else if (macintosh_config->ide_type == MAC_IDE_PB)
--			printk(KERN_INFO "ide%d: Macintosh Powerbook IDE interface\n", index);
--		else if (macintosh_config->ide_type == MAC_IDE_BABOON)
--			printk(KERN_INFO "ide%d: Macintosh Powerbook Baboon IDE interface\n", index);
--		else
--			printk(KERN_INFO "ide%d: Unknown Macintosh IDE interface\n", index);
-+
-+		ide_device_add(idx);
- 	}
-+
-+	return 0;
++	if (conn_param)
++		qp_attr.max_dest_rd_atomic = conn_param->responder_resources;
+ 	ret = ib_modify_qp(id_priv->id.qp, &qp_attr, qp_attr_mask);
+ out:
+ 	mutex_unlock(&id_priv->qp_mutex);
+ 	return ret;
  }
-+
-+module_init(macide_init);
-diff --git a/drivers/ide/legacy/q40ide.c b/drivers/ide/legacy/q40ide.c
-index 6ea46a6..f532973 100644
---- a/drivers/ide/legacy/q40ide.c
-+++ b/drivers/ide/legacy/q40ide.c
-@@ -111,15 +111,17 @@ static const char *q40_ide_names[Q40IDE_NUM_HWIFS]={
-  *  Probe for Q40 IDE interfaces
-  */
  
--void __init q40ide_init(void)
-+static int __init q40ide_init(void)
+-static int cma_modify_qp_rts(struct rdma_id_private *id_priv)
++static int cma_modify_qp_rts(struct rdma_id_private *id_priv,
++			     struct rdma_conn_param *conn_param)
  {
-     int i;
-     ide_hwif_t *hwif;
--    int index;
-     const char *name;
-+    u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
+ 	struct ib_qp_attr qp_attr;
+ 	int qp_attr_mask, ret;
+@@ -536,6 +540,8 @@ static int cma_modify_qp_rts(struct rdma_id_private *id_priv)
+ 	if (ret)
+ 		goto out;
  
-     if (!MACH_IS_Q40)
--      return ;
-+      return -ENODEV;
-+
-+    printk(KERN_INFO "ide: Q40 IDE controller\n");
++	if (conn_param)
++		qp_attr.max_rd_atomic = conn_param->initiator_depth;
+ 	ret = ib_modify_qp(id_priv->id.qp, &qp_attr, qp_attr_mask);
+ out:
+ 	mutex_unlock(&id_priv->qp_mutex);
+@@ -866,11 +872,11 @@ static int cma_rep_recv(struct rdma_id_private *id_priv)
+ {
+ 	int ret;
  
-     for (i = 0; i < Q40IDE_NUM_HWIFS; i++) {
- 	hw_regs_t hw;
-@@ -141,10 +143,20 @@ void __init q40ide_init(void)
- 			0, NULL,
- //			m68kide_iops,
- 			q40ide_default_irq(pcide_bases[i]));
--	index = ide_register_hw(&hw, NULL, 1, &hwif);
--	// **FIXME**
--	if (index != -1)
-+
-+	hwif = ide_find_port(hw.io_ports[IDE_DATA_OFFSET]);
-+	if (hwif) {
-+		ide_init_port_data(hwif, hwif->index);
-+		ide_init_port_hw(hwif, &hw);
- 		hwif->mmio = 1;
-+
-+		idx[i] = hwif->index;
+-	ret = cma_modify_qp_rtr(id_priv);
++	ret = cma_modify_qp_rtr(id_priv, NULL);
+ 	if (ret)
+ 		goto reject;
+ 
+-	ret = cma_modify_qp_rts(id_priv);
++	ret = cma_modify_qp_rts(id_priv, NULL);
+ 	if (ret)
+ 		goto reject;
+ 
+@@ -1122,8 +1128,10 @@ static int cma_req_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event)
+ 	cm_id->cm_handler = cma_ib_handler;
+ 
+ 	ret = conn_id->id.event_handler(&conn_id->id, &event);
+-	if (!ret)
++	if (!ret) {
++		cma_enable_remove(conn_id);
+ 		goto out;
 +	}
-     }
-+
-+    ide_device_add(idx);
-+
-+    return 0;
- }
  
-+module_init(q40ide_init);
-diff --git a/drivers/ide/legacy/qd65xx.c b/drivers/ide/legacy/qd65xx.c
-index 912e738..2bac4c1 100644
---- a/drivers/ide/legacy/qd65xx.c
-+++ b/drivers/ide/legacy/qd65xx.c
-@@ -478,8 +478,7 @@ int probe_qd65xx = 0;
- module_param_named(probe, probe_qd65xx, bool, 0);
- MODULE_PARM_DESC(probe, "probe for QD65xx chipsets");
+ 	/* Destroy the CM ID by returning a non-zero value. */
+ 	conn_id->cm_id.ib = NULL;
+@@ -1262,6 +1270,7 @@ static int iw_conn_req_handler(struct iw_cm_id *cm_id,
+ 	struct net_device *dev = NULL;
+ 	struct rdma_cm_event event;
+ 	int ret;
++	struct ib_device_attr attr;
  
--/* Can be called directly from ide.c. */
--int __init qd65xx_init(void)
-+static int __init qd65xx_init(void)
- {
- 	if (probe_qd65xx == 0)
- 		return -ENODEV;
-@@ -492,9 +491,7 @@ int __init qd65xx_init(void)
- 	return 0;
- }
+ 	listen_id = cm_id->context;
+ 	if (cma_disable_remove(listen_id, CMA_LISTEN))
+@@ -1311,10 +1320,19 @@ static int iw_conn_req_handler(struct iw_cm_id *cm_id,
+ 	sin = (struct sockaddr_in *) &new_cm_id->route.addr.dst_addr;
+ 	*sin = iw_event->remote_addr;
  
--#ifdef MODULE
- module_init(qd65xx_init);
--#endif
++	ret = ib_query_device(conn_id->id.device, &attr);
++	if (ret) {
++		cma_enable_remove(conn_id);
++		rdma_destroy_id(new_cm_id);
++		goto out;
++	}
++
+ 	memset(&event, 0, sizeof event);
+ 	event.event = RDMA_CM_EVENT_CONNECT_REQUEST;
+ 	event.param.conn.private_data = iw_event->private_data;
+ 	event.param.conn.private_data_len = iw_event->private_data_len;
++	event.param.conn.initiator_depth = attr.max_qp_init_rd_atom;
++	event.param.conn.responder_resources = attr.max_qp_rd_atom;
+ 	ret = conn_id->id.event_handler(&conn_id->id, &event);
+ 	if (ret) {
+ 		/* User wants to destroy the CM ID */
+@@ -2272,7 +2290,7 @@ static int cma_connect_iw(struct rdma_id_private *id_priv,
+ 	sin = (struct sockaddr_in*) &id_priv->id.route.addr.dst_addr;
+ 	cm_id->remote_addr = *sin;
  
- MODULE_AUTHOR("Samuel Thibault");
- MODULE_DESCRIPTION("support of qd65xx vlb ide chipset");
-diff --git a/drivers/ide/legacy/umc8672.c b/drivers/ide/legacy/umc8672.c
-index 79577b9..a1ae1ae 100644
---- a/drivers/ide/legacy/umc8672.c
-+++ b/drivers/ide/legacy/umc8672.c
-@@ -169,8 +169,7 @@ int probe_umc8672 = 0;
- module_param_named(probe, probe_umc8672, bool, 0);
- MODULE_PARM_DESC(probe, "probe for UMC8672 chipset");
+-	ret = cma_modify_qp_rtr(id_priv);
++	ret = cma_modify_qp_rtr(id_priv, conn_param);
+ 	if (ret)
+ 		goto out;
  
--/* Can be called directly from ide.c. */
--int __init umc8672_init(void)
-+static int __init umc8672_init(void)
+@@ -2335,25 +2353,15 @@ static int cma_accept_ib(struct rdma_id_private *id_priv,
+ 			 struct rdma_conn_param *conn_param)
  {
- 	if (probe_umc8672 == 0)
- 		goto out;
-@@ -181,9 +180,7 @@ out:
- 	return -ENODEV;;
- }
+ 	struct ib_cm_rep_param rep;
+-	struct ib_qp_attr qp_attr;
+-	int qp_attr_mask, ret;
+-
+-	if (id_priv->id.qp) {
+-		ret = cma_modify_qp_rtr(id_priv);
+-		if (ret)
+-			goto out;
++	int ret;
  
--#ifdef MODULE
- module_init(umc8672_init);
--#endif
+-		qp_attr.qp_state = IB_QPS_RTS;
+-		ret = ib_cm_init_qp_attr(id_priv->cm_id.ib, &qp_attr,
+-					 &qp_attr_mask);
+-		if (ret)
+-			goto out;
++	ret = cma_modify_qp_rtr(id_priv, conn_param);
++	if (ret)
++		goto out;
  
- MODULE_AUTHOR("Wolfram Podien");
- MODULE_DESCRIPTION("Support for UMC 8672 IDE chipset");
-diff --git a/drivers/ide/mips/au1xxx-ide.c b/drivers/ide/mips/au1xxx-ide.c
-index a4ce3ba..2d3e511 100644
---- a/drivers/ide/mips/au1xxx-ide.c
-+++ b/drivers/ide/mips/au1xxx-ide.c
-@@ -198,8 +198,6 @@ static void auide_set_dma_mode(ide_drive_t *drive, const u8 speed)
+-		qp_attr.max_rd_atomic = conn_param->initiator_depth;
+-		ret = ib_modify_qp(id_priv->id.qp, &qp_attr, qp_attr_mask);
+-		if (ret)
+-			goto out;
+-	}
++	ret = cma_modify_qp_rts(id_priv, conn_param);
++	if (ret)
++		goto out;
  
- 		break;
- #endif
--	default:
--		return;
- 	}
+ 	memset(&rep, 0, sizeof rep);
+ 	rep.qp_num = id_priv->qp_num;
+@@ -2378,7 +2386,7 @@ static int cma_accept_iw(struct rdma_id_private *id_priv,
+ 	struct iw_cm_conn_param iw_param;
+ 	int ret;
  
- 	au_writel(mem_sttime,MEM_STTIME2);
-@@ -397,26 +395,10 @@ static int auide_dma_test_irq(ide_drive_t *drive)
- 	return 0;
- }
+-	ret = cma_modify_qp_rtr(id_priv);
++	ret = cma_modify_qp_rtr(id_priv, conn_param);
+ 	if (ret)
+ 		return ret;
  
--static void auide_dma_host_on(ide_drive_t *drive)
--{
--}
--
--static int auide_dma_on(ide_drive_t *drive)
--{
--	drive->using_dma = 1;
--
--	return 0;
--}
--
--static void auide_dma_host_off(ide_drive_t *drive)
-+static void auide_dma_host_set(ide_drive_t *drive, int on)
- {
+@@ -2598,11 +2606,9 @@ static void cma_set_mgid(struct rdma_id_private *id_priv,
+ 		/* IPv6 address is an SA assigned MGID. */
+ 		memcpy(mgid, &sin6->sin6_addr, sizeof *mgid);
+ 	} else {
+-		ip_ib_mc_map(sin->sin_addr.s_addr, mc_map);
++		ip_ib_mc_map(sin->sin_addr.s_addr, dev_addr->broadcast, mc_map);
+ 		if (id_priv->id.ps == RDMA_PS_UDP)
+ 			mc_map[7] = 0x01;	/* Use RDMA CM signature */
+-		mc_map[8] = ib_addr_get_pkey(dev_addr) >> 8;
+-		mc_map[9] = (unsigned char) ib_addr_get_pkey(dev_addr);
+ 		*mgid = *(union ib_gid *) (mc_map + 4);
+ 	}
  }
- 
--static void auide_dma_off_quietly(ide_drive_t *drive)
--{
--	drive->using_dma = 0;
--}
--
- static void auide_dma_lost_irq(ide_drive_t *drive)
+diff --git a/drivers/infiniband/core/fmr_pool.c b/drivers/infiniband/core/fmr_pool.c
+index e8d5f6b..6c7aa59 100644
+--- a/drivers/infiniband/core/fmr_pool.c
++++ b/drivers/infiniband/core/fmr_pool.c
+@@ -139,7 +139,7 @@ static inline struct ib_pool_fmr *ib_fmr_cache_lookup(struct ib_fmr_pool *pool,
+ static void ib_fmr_batch_release(struct ib_fmr_pool *pool)
  {
- 	printk(KERN_ERR "%s: IRQ lost\n", drive->name);
-@@ -643,12 +625,13 @@ static int au_ide_probe(struct device *dev)
- 	/* FIXME:  This might possibly break PCMCIA IDE devices */
+ 	int                 ret;
+-	struct ib_pool_fmr *fmr;
++	struct ib_pool_fmr *fmr, *next;
+ 	LIST_HEAD(unmap_list);
+ 	LIST_HEAD(fmr_list);
  
- 	hwif                            = &ide_hwifs[pdev->id];
--	hwif->irq			= ahwif->irq;
--	hwif->chipset                   = ide_au1xxx;
+@@ -158,6 +158,20 @@ static void ib_fmr_batch_release(struct ib_fmr_pool *pool)
+ #endif
+ 	}
  
- 	memset(&hw, 0, sizeof(hw));
- 	auide_setup_ports(&hw, ahwif);
--	memcpy(hwif->io_ports, hw.io_ports, sizeof(hwif->io_ports));
-+	hw.irq = ahwif->irq;
-+	hw.chipset = ide_au1xxx;
++	/*
++	 * The free_list may hold FMRs that have been put there
++	 * because they haven't reached the max_remap count.
++	 * Invalidate their mapping as well.
++	 */
++	list_for_each_entry_safe(fmr, next, &pool->free_list, list) {
++		if (fmr->remap_count == 0)
++			continue;
++		hlist_del_init(&fmr->cache_node);
++		fmr->remap_count = 0;
++		list_add_tail(&fmr->fmr->list, &fmr_list);
++		list_move(&fmr->list, &unmap_list);
++	}
 +
-+	ide_init_port_hw(hwif, &hw);
- 
- 	hwif->ultra_mask                = 0x0;  /* Disable Ultra DMA */
- #ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA
-@@ -662,7 +645,6 @@ static int au_ide_probe(struct device *dev)
- 	hwif->pio_mask = ATA_PIO4;
- 	hwif->host_flags = IDE_HFLAG_POST_SET_MODE;
+ 	list_splice(&pool->dirty_list, &unmap_list);
+ 	INIT_LIST_HEAD(&pool->dirty_list);
+ 	pool->dirty_len = 0;
+@@ -182,8 +196,7 @@ static int ib_fmr_cleanup_thread(void *pool_ptr)
+ 	struct ib_fmr_pool *pool = pool_ptr;
  
--	hwif->noprobe = 0;
- 	hwif->drives[0].unmask          = 1;
- 	hwif->drives[1].unmask          = 1;
+ 	do {
+-		if (pool->dirty_len >= pool->dirty_watermark ||
+-		    atomic_read(&pool->flush_ser) - atomic_read(&pool->req_ser) < 0) {
++		if (atomic_read(&pool->flush_ser) - atomic_read(&pool->req_ser) < 0) {
+ 			ib_fmr_batch_release(pool);
  
-@@ -684,29 +666,25 @@ static int au_ide_probe(struct device *dev)
- 	hwif->set_dma_mode		= &auide_set_dma_mode;
+ 			atomic_inc(&pool->flush_ser);
+@@ -194,8 +207,7 @@ static int ib_fmr_cleanup_thread(void *pool_ptr)
+ 		}
  
- #ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA
--	hwif->dma_off_quietly		= &auide_dma_off_quietly;
- 	hwif->dma_timeout		= &auide_dma_timeout;
+ 		set_current_state(TASK_INTERRUPTIBLE);
+-		if (pool->dirty_len < pool->dirty_watermark &&
+-		    atomic_read(&pool->flush_ser) - atomic_read(&pool->req_ser) >= 0 &&
++		if (atomic_read(&pool->flush_ser) - atomic_read(&pool->req_ser) >= 0 &&
+ 		    !kthread_should_stop())
+ 			schedule();
+ 		__set_current_state(TASK_RUNNING);
+@@ -369,11 +381,6 @@ void ib_destroy_fmr_pool(struct ib_fmr_pool *pool)
  
- 	hwif->mdma_filter		= &auide_mdma_filter;
+ 	i = 0;
+ 	list_for_each_entry_safe(fmr, tmp, &pool->free_list, list) {
+-		if (fmr->remap_count) {
+-			INIT_LIST_HEAD(&fmr_list);
+-			list_add_tail(&fmr->fmr->list, &fmr_list);
+-			ib_unmap_fmr(&fmr_list);
+-		}
+ 		ib_dealloc_fmr(fmr->fmr);
+ 		list_del(&fmr->list);
+ 		kfree(fmr);
+@@ -511,8 +518,10 @@ int ib_fmr_pool_unmap(struct ib_pool_fmr *fmr)
+ 			list_add_tail(&fmr->list, &pool->free_list);
+ 		} else {
+ 			list_add_tail(&fmr->list, &pool->dirty_list);
+-			++pool->dirty_len;
+-			wake_up_process(pool->thread);
++			if (++pool->dirty_len >= pool->dirty_watermark) {
++				atomic_inc(&pool->req_ser);
++				wake_up_process(pool->thread);
++			}
+ 		}
+ 	}
  
-+	hwif->dma_host_set		= &auide_dma_host_set;
- 	hwif->dma_exec_cmd              = &auide_dma_exec_cmd;
- 	hwif->dma_start                 = &auide_dma_start;
- 	hwif->ide_dma_end               = &auide_dma_end;
- 	hwif->dma_setup                 = &auide_dma_setup;
- 	hwif->ide_dma_test_irq          = &auide_dma_test_irq;
--	hwif->dma_host_off		= &auide_dma_host_off;
--	hwif->dma_host_on		= &auide_dma_host_on;
- 	hwif->dma_lost_irq		= &auide_dma_lost_irq;
--	hwif->ide_dma_on                = &auide_dma_on;
--#else /* !CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA */
-+#endif
- 	hwif->channel                   = 0;
--	hwif->hold                      = 1;
- 	hwif->select_data               = 0;    /* no chipset-specific code */
- 	hwif->config_data               = 0;    /* no chipset-specific code */
+diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c
+index 6f42877..fbe16d5 100644
+--- a/drivers/infiniband/core/mad.c
++++ b/drivers/infiniband/core/mad.c
+@@ -701,7 +701,8 @@ static int handle_outgoing_dr_smp(struct ib_mad_agent_private *mad_agent_priv,
+ 	}
  
- 	hwif->drives[0].autotune        = 1;    /* 1=autotune, 2=noautotune, 0=default */
- 	hwif->drives[1].autotune	= 1;
--#endif
-+
- 	hwif->drives[0].no_io_32bit	= 1;
- 	hwif->drives[1].no_io_32bit	= 1;
+ 	/* Check to post send on QP or process locally */
+-	if (smi_check_local_smp(smp, device) == IB_SMI_DISCARD)
++	if (smi_check_local_smp(smp, device) == IB_SMI_DISCARD &&
++	    smi_check_local_returning_smp(smp, device) == IB_SMI_DISCARD)
+ 		goto out;
  
-diff --git a/drivers/ide/mips/swarm.c b/drivers/ide/mips/swarm.c
-index 521edd4..8b3959d 100644
---- a/drivers/ide/mips/swarm.c
-+++ b/drivers/ide/mips/swarm.c
-@@ -117,6 +117,7 @@ static int __devinit swarm_ide_probe(struct device *dev)
- 	default_hwif_mmiops(hwif);
- 	/* Prevent resource map manipulation.  */
- 	hwif->mmio = 1;
-+	hwif->chipset = ide_generic;
- 	hwif->noprobe = 0;
+ 	local = kmalloc(sizeof *local, GFP_ATOMIC);
+@@ -752,8 +753,7 @@ static int handle_outgoing_dr_smp(struct ib_mad_agent_private *mad_agent_priv,
+ 		port_priv = ib_get_mad_port(mad_agent_priv->agent.device,
+ 					    mad_agent_priv->agent.port_num);
+ 		if (port_priv) {
+-			mad_priv->mad.mad.mad_hdr.tid =
+-				((struct ib_mad *)smp)->mad_hdr.tid;
++			memcpy(&mad_priv->mad.mad, smp, sizeof(struct ib_mad));
+ 			recv_mad_agent = find_mad_agent(port_priv,
+ 						        &mad_priv->mad.mad);
+ 		}
+@@ -1100,7 +1100,9 @@ int ib_post_send_mad(struct ib_mad_send_buf *send_buf,
+ 		mad_send_wr->tid = ((struct ib_mad_hdr *) send_buf->mad)->tid;
+ 		/* Timeout will be updated after send completes */
+ 		mad_send_wr->timeout = msecs_to_jiffies(send_buf->timeout_ms);
+-		mad_send_wr->retries = send_buf->retries;
++		mad_send_wr->max_retries = send_buf->retries;
++		mad_send_wr->retries_left = send_buf->retries;
++		send_buf->retries = 0;
+ 		/* Reference for work request to QP + response */
+ 		mad_send_wr->refcount = 1 + (mad_send_wr->timeout > 0);
+ 		mad_send_wr->status = IB_WC_SUCCESS;
+@@ -1931,15 +1933,6 @@ local:
+ 	if (port_priv->device->process_mad) {
+ 		int ret;
  
- 	for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++)
-diff --git a/drivers/ide/pci/Makefile b/drivers/ide/pci/Makefile
-index 95d1ea8..9480325 100644
---- a/drivers/ide/pci/Makefile
-+++ b/drivers/ide/pci/Makefile
-@@ -36,4 +36,8 @@ obj-$(CONFIG_BLK_DEV_VIA82CXXX)		+= via82cxxx.o
- # Must appear at the end of the block
- obj-$(CONFIG_BLK_DEV_GENERIC)          += generic.o
+-		if (!response) {
+-			printk(KERN_ERR PFX "No memory for response MAD\n");
+-			/*
+-			 * Is it better to assume that
+-			 * it wouldn't be processed ?
+-			 */
+-			goto out;
+-		}
+-
+ 		ret = port_priv->device->process_mad(port_priv->device, 0,
+ 						     port_priv->port_num,
+ 						     wc, &recv->grh,
+@@ -2282,8 +2275,6 @@ static void cancel_mads(struct ib_mad_agent_private *mad_agent_priv)
  
-+ifeq ($(CONFIG_BLK_DEV_CMD640), m)
-+	obj-m += cmd640.o
-+endif
-+
- EXTRA_CFLAGS	:= -Idrivers/ide
-diff --git a/drivers/ide/pci/aec62xx.c b/drivers/ide/pci/aec62xx.c
-index 4426850..7f4d185 100644
---- a/drivers/ide/pci/aec62xx.c
-+++ b/drivers/ide/pci/aec62xx.c
-@@ -202,6 +202,7 @@ static const struct ide_port_info aec62xx_chipsets[] __devinitdata = {
- 		.enablebits	= {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},
- 		.host_flags	= IDE_HFLAG_SERIALIZE |
- 				  IDE_HFLAG_NO_ATAPI_DMA |
-+				  IDE_HFLAG_ABUSE_SET_DMA_MODE |
- 				  IDE_HFLAG_OFF_BOARD,
- 		.pio_mask	= ATA_PIO4,
- 		.mwdma_mask	= ATA_MWDMA2,
-@@ -211,6 +212,7 @@ static const struct ide_port_info aec62xx_chipsets[] __devinitdata = {
- 		.init_chipset	= init_chipset_aec62xx,
- 		.init_hwif	= init_hwif_aec62xx,
- 		.host_flags	= IDE_HFLAG_NO_ATAPI_DMA | IDE_HFLAG_NO_AUTODMA |
-+				  IDE_HFLAG_ABUSE_SET_DMA_MODE |
- 				  IDE_HFLAG_OFF_BOARD,
- 		.pio_mask	= ATA_PIO4,
- 		.mwdma_mask	= ATA_MWDMA2,
-@@ -220,7 +222,8 @@ static const struct ide_port_info aec62xx_chipsets[] __devinitdata = {
- 		.init_chipset	= init_chipset_aec62xx,
- 		.init_hwif	= init_hwif_aec62xx,
- 		.enablebits	= {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},
--		.host_flags	= IDE_HFLAG_NO_ATAPI_DMA,
-+		.host_flags	= IDE_HFLAG_NO_ATAPI_DMA |
-+				  IDE_HFLAG_ABUSE_SET_DMA_MODE,
- 		.pio_mask	= ATA_PIO4,
- 		.mwdma_mask	= ATA_MWDMA2,
- 		.udma_mask	= ATA_UDMA4,
-@@ -228,7 +231,9 @@ static const struct ide_port_info aec62xx_chipsets[] __devinitdata = {
- 		.name		= "AEC6280",
- 		.init_chipset	= init_chipset_aec62xx,
- 		.init_hwif	= init_hwif_aec62xx,
--		.host_flags	= IDE_HFLAG_NO_ATAPI_DMA | IDE_HFLAG_OFF_BOARD,
-+		.host_flags	= IDE_HFLAG_NO_ATAPI_DMA |
-+				  IDE_HFLAG_ABUSE_SET_DMA_MODE |
-+				  IDE_HFLAG_OFF_BOARD,
- 		.pio_mask	= ATA_PIO4,
- 		.mwdma_mask	= ATA_MWDMA2,
- 		.udma_mask	= ATA_UDMA5,
-@@ -237,7 +242,9 @@ static const struct ide_port_info aec62xx_chipsets[] __devinitdata = {
- 		.init_chipset	= init_chipset_aec62xx,
- 		.init_hwif	= init_hwif_aec62xx,
- 		.enablebits	= {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},
--		.host_flags	= IDE_HFLAG_NO_ATAPI_DMA | IDE_HFLAG_OFF_BOARD,
-+		.host_flags	= IDE_HFLAG_NO_ATAPI_DMA |
-+				  IDE_HFLAG_ABUSE_SET_DMA_MODE |
-+				  IDE_HFLAG_OFF_BOARD,
- 		.pio_mask	= ATA_PIO4,
- 		.mwdma_mask	= ATA_MWDMA2,
- 		.udma_mask	= ATA_UDMA5,
-diff --git a/drivers/ide/pci/alim15x3.c b/drivers/ide/pci/alim15x3.c
-index ce29393..49aa82e 100644
---- a/drivers/ide/pci/alim15x3.c
-+++ b/drivers/ide/pci/alim15x3.c
-@@ -402,9 +402,6 @@ static void ali_set_dma_mode(ide_drive_t *drive, const u8 speed)
- 	u8 tmpbyte		= 0x00;
- 	int m5229_udma		= (hwif->channel) ? 0x57 : 0x56;
+ 	/* Empty wait list to prevent receives from finding a request */
+ 	list_splice_init(&mad_agent_priv->wait_list, &cancel_list);
+-	/* Empty local completion list as well */
+-	list_splice_init(&mad_agent_priv->local_list, &cancel_list);
+ 	spin_unlock_irqrestore(&mad_agent_priv->lock, flags);
  
--	if (speed < XFER_PIO_0)
--		return;
--
- 	if (speed == XFER_UDMA_6)
- 		speed1 = 0x47;
+ 	/* Report all cancelled requests */
+@@ -2445,9 +2436,12 @@ static int retry_send(struct ib_mad_send_wr_private *mad_send_wr)
+ {
+ 	int ret;
  
-diff --git a/drivers/ide/pci/amd74xx.c b/drivers/ide/pci/amd74xx.c
-index 8d4125e..cee51fd 100644
---- a/drivers/ide/pci/amd74xx.c
-+++ b/drivers/ide/pci/amd74xx.c
-@@ -266,6 +266,7 @@ static void __devinit init_hwif_amd74xx(ide_hwif_t *hwif)
- #define IDE_HFLAGS_AMD \
- 	(IDE_HFLAG_PIO_NO_BLACKLIST | \
- 	 IDE_HFLAG_PIO_NO_DOWNGRADE | \
-+	 IDE_HFLAG_ABUSE_SET_DMA_MODE | \
- 	 IDE_HFLAG_POST_SET_MODE | \
- 	 IDE_HFLAG_IO_32BIT | \
- 	 IDE_HFLAG_UNMASK_IRQS | \
-diff --git a/drivers/ide/pci/atiixp.c b/drivers/ide/pci/atiixp.c
-index ef8e016..4918719 100644
---- a/drivers/ide/pci/atiixp.c
-+++ b/drivers/ide/pci/atiixp.c
-@@ -1,5 +1,5 @@
- /*
-- *  linux/drivers/ide/pci/atiixp.c	Version 0.03	Aug 3 2007
-+ *  linux/drivers/ide/pci/atiixp.c	Version 0.05	Nov 9 2007
-  *
-  *  Copyright (C) 2003 ATI Inc. <hyu at ati.com>
-  *  Copyright (C) 2004,2007 Bartlomiej Zolnierkiewicz
-@@ -43,47 +43,8 @@ static atiixp_ide_timing mdma_timing[] = {
- 	{ 0x02, 0x00 },
- };
+-	if (!mad_send_wr->retries--)
++	if (!mad_send_wr->retries_left)
+ 		return -ETIMEDOUT;
  
--static int save_mdma_mode[4];
--
- static DEFINE_SPINLOCK(atiixp_lock);
++	mad_send_wr->retries_left--;
++	mad_send_wr->send_buf.retries++;
++
+ 	mad_send_wr->timeout = msecs_to_jiffies(mad_send_wr->send_buf.timeout_ms);
  
--static void atiixp_dma_host_on(ide_drive_t *drive)
--{
--	struct pci_dev *dev = drive->hwif->pci_dev;
--	unsigned long flags;
--	u16 tmp16;
--
--	spin_lock_irqsave(&atiixp_lock, flags);
--
--	pci_read_config_word(dev, ATIIXP_IDE_UDMA_CONTROL, &tmp16);
--	if (save_mdma_mode[drive->dn])
--		tmp16 &= ~(1 << drive->dn);
--	else
--		tmp16 |= (1 << drive->dn);
--	pci_write_config_word(dev, ATIIXP_IDE_UDMA_CONTROL, tmp16);
--
--	spin_unlock_irqrestore(&atiixp_lock, flags);
--
--	ide_dma_host_on(drive);
--}
--
--static void atiixp_dma_host_off(ide_drive_t *drive)
--{
--	struct pci_dev *dev = drive->hwif->pci_dev;
--	unsigned long flags;
--	u16 tmp16;
--
--	spin_lock_irqsave(&atiixp_lock, flags);
--
--	pci_read_config_word(dev, ATIIXP_IDE_UDMA_CONTROL, &tmp16);
--	tmp16 &= ~(1 << drive->dn);
--	pci_write_config_word(dev, ATIIXP_IDE_UDMA_CONTROL, tmp16);
--
--	spin_unlock_irqrestore(&atiixp_lock, flags);
--
--	ide_dma_host_off(drive);
--}
--
- /**
-  *	atiixp_set_pio_mode	-	set host controller for PIO mode
-  *	@drive: drive
-@@ -132,29 +93,33 @@ static void atiixp_set_dma_mode(ide_drive_t *drive, const u8 speed)
- 	int timing_shift = (drive->dn & 2) ? 16 : 0 + (drive->dn & 1) ? 0 : 8;
- 	u32 tmp32;
- 	u16 tmp16;
--
--	if (speed < XFER_MW_DMA_0)
--		return;
-+	u16 udma_ctl = 0;
+ 	if (mad_send_wr->mad_agent_priv->agent.rmpp_version) {
+diff --git a/drivers/infiniband/core/mad_priv.h b/drivers/infiniband/core/mad_priv.h
+index 9be5cc0..8b75010 100644
+--- a/drivers/infiniband/core/mad_priv.h
++++ b/drivers/infiniband/core/mad_priv.h
+@@ -131,7 +131,8 @@ struct ib_mad_send_wr_private {
+ 	struct ib_sge sg_list[IB_MAD_SEND_REQ_MAX_SG];
+ 	__be64 tid;
+ 	unsigned long timeout;
+-	int retries;
++	int max_retries;
++	int retries_left;
+ 	int retry;
+ 	int refcount;
+ 	enum ib_wc_status status;
+diff --git a/drivers/infiniband/core/mad_rmpp.c b/drivers/infiniband/core/mad_rmpp.c
+index d43bc62..a5e2a31 100644
+--- a/drivers/infiniband/core/mad_rmpp.c
++++ b/drivers/infiniband/core/mad_rmpp.c
+@@ -684,7 +684,7 @@ static void process_rmpp_ack(struct ib_mad_agent_private *agent,
  
- 	spin_lock_irqsave(&atiixp_lock, flags);
+ 	if (seg_num > mad_send_wr->last_ack) {
+ 		adjust_last_ack(mad_send_wr, seg_num);
+-		mad_send_wr->retries = mad_send_wr->send_buf.retries;
++		mad_send_wr->retries_left = mad_send_wr->max_retries;
+ 	}
+ 	mad_send_wr->newwin = newwin;
+ 	if (mad_send_wr->last_ack == mad_send_wr->send_buf.seg_count) {
+diff --git a/drivers/infiniband/core/multicast.c b/drivers/infiniband/core/multicast.c
+index 1bc1fe6..107f170 100644
+--- a/drivers/infiniband/core/multicast.c
++++ b/drivers/infiniband/core/multicast.c
+@@ -73,11 +73,20 @@ struct mcast_device {
+ };
  
--	save_mdma_mode[drive->dn] = 0;
-+	pci_read_config_word(dev, ATIIXP_IDE_UDMA_CONTROL, &udma_ctl);
+ enum mcast_state {
+-	MCAST_IDLE,
+ 	MCAST_JOINING,
+ 	MCAST_MEMBER,
++	MCAST_ERROR,
++};
 +
- 	if (speed >= XFER_UDMA_0) {
- 		pci_read_config_word(dev, ATIIXP_IDE_UDMA_MODE, &tmp16);
- 		tmp16 &= ~(0x07 << (drive->dn * 4));
- 		tmp16 |= ((speed & 0x07) << (drive->dn * 4));
- 		pci_write_config_word(dev, ATIIXP_IDE_UDMA_MODE, tmp16);
--	} else {
--		if ((speed >= XFER_MW_DMA_0) && (speed <= XFER_MW_DMA_2)) {
--			save_mdma_mode[drive->dn] = speed;
--			pci_read_config_dword(dev, ATIIXP_IDE_MDMA_TIMING, &tmp32);
--			tmp32 &= ~(0xff << timing_shift);
--			tmp32 |= (mdma_timing[speed & 0x03].recover_width << timing_shift) |
--				(mdma_timing[speed & 0x03].command_width << (timing_shift + 4));
--			pci_write_config_dword(dev, ATIIXP_IDE_MDMA_TIMING, tmp32);
--		}
++enum mcast_group_state {
++	MCAST_IDLE,
+ 	MCAST_BUSY,
+-	MCAST_ERROR
++	MCAST_GROUP_ERROR,
++	MCAST_PKEY_EVENT
++};
 +
-+		udma_ctl |= (1 << drive->dn);
-+	} else if (speed >= XFER_MW_DMA_0) {
-+		u8 i = speed & 0x03;
++enum {
++	MCAST_INVALID_PKEY_INDEX = 0xFFFF
+ };
+ 
+ struct mcast_member;
+@@ -93,9 +102,10 @@ struct mcast_group {
+ 	struct mcast_member	*last_join;
+ 	int			members[3];
+ 	atomic_t		refcount;
+-	enum mcast_state	state;
++	enum mcast_group_state	state;
+ 	struct ib_sa_query	*query;
+ 	int			query_id;
++	u16			pkey_index;
+ };
+ 
+ struct mcast_member {
+@@ -378,9 +388,19 @@ static int fail_join(struct mcast_group *group, struct mcast_member *member,
+ static void process_group_error(struct mcast_group *group)
+ {
+ 	struct mcast_member *member;
+-	int ret;
++	int ret = 0;
++	u16 pkey_index;
 +
-+		pci_read_config_dword(dev, ATIIXP_IDE_MDMA_TIMING, &tmp32);
-+		tmp32 &= ~(0xff << timing_shift);
-+		tmp32 |= (mdma_timing[i].recover_width << timing_shift) |
-+			 (mdma_timing[i].command_width << (timing_shift + 4));
-+		pci_write_config_dword(dev, ATIIXP_IDE_MDMA_TIMING, tmp32);
++	if (group->state == MCAST_PKEY_EVENT)
++		ret = ib_find_pkey(group->port->dev->device,
++				   group->port->port_num,
++				   be16_to_cpu(group->rec.pkey), &pkey_index);
+ 
+ 	spin_lock_irq(&group->lock);
++	if (group->state == MCAST_PKEY_EVENT && !ret &&
++	    group->pkey_index == pkey_index)
++		goto out;
 +
-+		udma_ctl &= ~(1 << drive->dn);
+ 	while (!list_empty(&group->active_list)) {
+ 		member = list_entry(group->active_list.next,
+ 				    struct mcast_member, list);
+@@ -399,6 +419,7 @@ static void process_group_error(struct mcast_group *group)
  	}
  
-+	pci_write_config_word(dev, ATIIXP_IDE_UDMA_CONTROL, udma_ctl);
-+
- 	spin_unlock_irqrestore(&atiixp_lock, flags);
+ 	group->rec.join_state = 0;
++out:
+ 	group->state = MCAST_BUSY;
+ 	spin_unlock_irq(&group->lock);
  }
+@@ -415,9 +436,9 @@ static void mcast_work_handler(struct work_struct *work)
+ retest:
+ 	spin_lock_irq(&group->lock);
+ 	while (!list_empty(&group->pending_list) ||
+-	       (group->state == MCAST_ERROR)) {
++	       (group->state != MCAST_BUSY)) {
  
-@@ -184,9 +149,6 @@ static void __devinit init_hwif_atiixp(ide_hwif_t *hwif)
- 		hwif->cbl = ATA_CBL_PATA80;
- 	else
- 		hwif->cbl = ATA_CBL_PATA40;
--
--	hwif->dma_host_on = &atiixp_dma_host_on;
--	hwif->dma_host_off = &atiixp_dma_host_off;
- }
+-		if (group->state == MCAST_ERROR) {
++		if (group->state != MCAST_BUSY) {
+ 			spin_unlock_irq(&group->lock);
+ 			process_group_error(group);
+ 			goto retest;
+@@ -494,12 +515,19 @@ static void join_handler(int status, struct ib_sa_mcmember_rec *rec,
+ 			 void *context)
+ {
+ 	struct mcast_group *group = context;
++	u16 pkey_index = MCAST_INVALID_PKEY_INDEX;
  
- static const struct ide_port_info atiixp_pci_info[] __devinitdata = {
-diff --git a/drivers/ide/pci/cmd640.c b/drivers/ide/pci/cmd640.c
-index 4aa4810..da3565e 100644
---- a/drivers/ide/pci/cmd640.c
-+++ b/drivers/ide/pci/cmd640.c
-@@ -706,9 +706,9 @@ static int pci_conf2(void)
+ 	if (status)
+ 		process_join_error(group, status);
+ 	else {
++		ib_find_pkey(group->port->dev->device, group->port->port_num,
++			     be16_to_cpu(rec->pkey), &pkey_index);
++
+ 		spin_lock_irq(&group->port->lock);
+ 		group->rec = *rec;
++		if (group->state == MCAST_BUSY &&
++		    group->pkey_index == MCAST_INVALID_PKEY_INDEX)
++			group->pkey_index = pkey_index;
+ 		if (!memcmp(&mgid0, &group->rec.mgid, sizeof mgid0)) {
+ 			rb_erase(&group->node, &group->port->table);
+ 			mcast_insert(group->port, group, 1);
+@@ -539,6 +567,7 @@ static struct mcast_group *acquire_group(struct mcast_port *port,
+ 
+ 	group->port = port;
+ 	group->rec.mgid = *mgid;
++	group->pkey_index = MCAST_INVALID_PKEY_INDEX;
+ 	INIT_LIST_HEAD(&group->pending_list);
+ 	INIT_LIST_HEAD(&group->active_list);
+ 	INIT_WORK(&group->work, mcast_work_handler);
+@@ -707,7 +736,8 @@ int ib_init_ah_from_mcmember(struct ib_device *device, u8 port_num,
  }
+ EXPORT_SYMBOL(ib_init_ah_from_mcmember);
  
- /*
-- * Probe for a cmd640 chipset, and initialize it if found.  Called from ide.c
-+ * Probe for a cmd640 chipset, and initialize it if found.
-  */
--int __init ide_probe_for_cmd640x (void)
-+static int __init cmd640x_init(void)
+-static void mcast_groups_lost(struct mcast_port *port)
++static void mcast_groups_event(struct mcast_port *port,
++			       enum mcast_group_state state)
  {
- #ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
- 	int second_port_toggled = 0;
-@@ -717,6 +717,7 @@ int __init ide_probe_for_cmd640x (void)
- 	const char *bus_type, *port2;
- 	unsigned int index;
- 	u8 b, cfr;
-+	u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
+ 	struct mcast_group *group;
+ 	struct rb_node *node;
+@@ -721,7 +751,8 @@ static void mcast_groups_lost(struct mcast_port *port)
+ 			atomic_inc(&group->refcount);
+ 			queue_work(mcast_wq, &group->work);
+ 		}
+-		group->state = MCAST_ERROR;
++		if (group->state != MCAST_GROUP_ERROR)
++			group->state = state;
+ 		spin_unlock(&group->lock);
+ 	}
+ 	spin_unlock_irqrestore(&port->lock, flags);
+@@ -731,16 +762,20 @@ static void mcast_event_handler(struct ib_event_handler *handler,
+ 				struct ib_event *event)
+ {
+ 	struct mcast_device *dev;
++	int index;
  
- 	if (cmd640_vlb && probe_for_cmd640_vlb()) {
- 		bus_type = "VLB";
-@@ -769,6 +770,8 @@ int __init ide_probe_for_cmd640x (void)
- 	cmd_hwif0->set_pio_mode = &cmd640_set_pio_mode;
- #endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
+ 	dev = container_of(handler, struct mcast_device, event_handler);
++	index = event->element.port_num - dev->start_port;
  
-+	idx[0] = cmd_hwif0->index;
-+
- 	/*
- 	 * Ensure compatibility by always using the slowest timings
- 	 * for access to the drive's command register block,
-@@ -826,6 +829,8 @@ int __init ide_probe_for_cmd640x (void)
- 		cmd_hwif1->pio_mask = ATA_PIO5;
- 		cmd_hwif1->set_pio_mode = &cmd640_set_pio_mode;
- #endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
-+
-+		idx[1] = cmd_hwif1->index;
- 	}
- 	printk(KERN_INFO "%s: %sserialized, secondary interface %s\n", cmd_hwif1->name,
- 		cmd_hwif0->serialized ? "" : "not ", port2);
-@@ -872,6 +877,13 @@ int __init ide_probe_for_cmd640x (void)
- #ifdef CMD640_DUMP_REGS
- 	cmd640_dump_regs();
- #endif
-+
-+	ide_device_add(idx);
-+
- 	return 1;
- }
+ 	switch (event->event) {
+ 	case IB_EVENT_PORT_ERR:
+ 	case IB_EVENT_LID_CHANGE:
+ 	case IB_EVENT_SM_CHANGE:
+ 	case IB_EVENT_CLIENT_REREGISTER:
+-		mcast_groups_lost(&dev->port[event->element.port_num -
+-					     dev->start_port]);
++		mcast_groups_event(&dev->port[index], MCAST_GROUP_ERROR);
++		break;
++	case IB_EVENT_PKEY_CHANGE:
++		mcast_groups_event(&dev->port[index], MCAST_PKEY_EVENT);
+ 		break;
+ 	default:
+ 		break;
+diff --git a/drivers/infiniband/core/smi.h b/drivers/infiniband/core/smi.h
+index 1cfc298..aff96ba 100644
+--- a/drivers/infiniband/core/smi.h
++++ b/drivers/infiniband/core/smi.h
+@@ -59,7 +59,8 @@ extern enum smi_action smi_handle_dr_smp_send(struct ib_smp *smp,
+ 					      u8 node_type, int port_num);
  
-+module_param_named(probe_vlb, cmd640_vlb, bool, 0);
-+MODULE_PARM_DESC(probe_vlb, "probe for VLB version of CMD640 chipset");
-+
-+module_init(cmd640x_init);
-diff --git a/drivers/ide/pci/cmd64x.c b/drivers/ide/pci/cmd64x.c
-index bc55333..cd4eb9d 100644
---- a/drivers/ide/pci/cmd64x.c
-+++ b/drivers/ide/pci/cmd64x.c
-@@ -1,5 +1,5 @@
  /*
-- * linux/drivers/ide/pci/cmd64x.c		Version 1.52	Dec 24, 2007
-+ * linux/drivers/ide/pci/cmd64x.c		Version 1.53	Dec 24, 2007
-  *
-  * cmd64x.c: Enable interrupts at initialization time on Ultra/PCI machines.
-  *           Due to massive hardware bugs, UltraDMA is only supported
-@@ -22,8 +22,6 @@
+- * Return 1 if the SMP should be handled by the local SMA/SM via process_mad
++ * Return IB_SMI_HANDLE if the SMP should be handled by the local SMA/SM
++ * via process_mad
+  */
+ static inline enum smi_action smi_check_local_smp(struct ib_smp *smp,
+ 						  struct ib_device *device)
+@@ -71,4 +72,19 @@ static inline enum smi_action smi_check_local_smp(struct ib_smp *smp,
+ 		(smp->hop_ptr == smp->hop_cnt + 1)) ?
+ 		IB_SMI_HANDLE : IB_SMI_DISCARD);
+ }
++
++/*
++ * Return IB_SMI_HANDLE if the SMP should be handled by the local SMA/SM
++ * via process_mad
++ */
++static inline enum smi_action smi_check_local_returning_smp(struct ib_smp *smp,
++						   struct ib_device *device)
++{
++	/* C14-13:3 -- We're at the end of the DR segment of path */
++	/* C14-13:4 -- Hop Pointer == 0 -> give to SM */
++	return ((device->process_mad &&
++		ib_get_smp_direction(smp) &&
++		!smp->hop_ptr) ? IB_SMI_HANDLE : IB_SMI_DISCARD);
++}
++
+ #endif	/* __SMI_H_ */
+diff --git a/drivers/infiniband/core/sysfs.c b/drivers/infiniband/core/sysfs.c
+index 3d40506..c864ef7 100644
+--- a/drivers/infiniband/core/sysfs.c
++++ b/drivers/infiniband/core/sysfs.c
+@@ -508,19 +508,10 @@ static int add_port(struct ib_device *device, int port_num)
  
- #include <asm/io.h>
+ 	p->ibdev      = device;
+ 	p->port_num   = port_num;
+-	p->kobj.ktype = &port_type;
  
--#define DISPLAY_CMD64X_TIMINGS
+-	p->kobj.parent = kobject_get(&device->ports_parent);
+-	if (!p->kobj.parent) {
+-		ret = -EBUSY;
+-		goto err;
+-	}
 -
- #define CMD_DEBUG 0
+-	ret = kobject_set_name(&p->kobj, "%d", port_num);
+-	if (ret)
+-		goto err_put;
+-
+-	ret = kobject_register(&p->kobj);
++	ret = kobject_init_and_add(&p->kobj, &port_type,
++				   kobject_get(device->ports_parent),
++				   "%d", port_num);
+ 	if (ret)
+ 		goto err_put;
  
- #if CMD_DEBUG
-@@ -37,11 +35,6 @@
-  */
- #define CFR		0x50
- #define   CFR_INTR_CH0		0x04
--#define CNTRL		0x51
--#define   CNTRL_ENA_1ST 	0x04
--#define   CNTRL_ENA_2ND 	0x08
--#define   CNTRL_DIS_RA0 	0x40
--#define   CNTRL_DIS_RA1 	0x80
+@@ -549,6 +540,7 @@ static int add_port(struct ib_device *device, int port_num)
  
- #define	CMDTIM		0x52
- #define	ARTTIM0		0x53
-@@ -60,108 +53,13 @@
- #define MRDMODE		0x71
- #define   MRDMODE_INTR_CH0	0x04
- #define   MRDMODE_INTR_CH1	0x08
--#define   MRDMODE_BLK_CH0	0x10
--#define   MRDMODE_BLK_CH1	0x20
--#define BMIDESR0	0x72
- #define UDIDETCR0	0x73
- #define DTPR0		0x74
- #define BMIDECR1	0x78
- #define BMIDECSR	0x79
--#define BMIDESR1	0x7A
- #define UDIDETCR1	0x7B
- #define DTPR1		0x7C
+ 	list_add_tail(&p->kobj.entry, &device->port_list);
  
--#if defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_IDE_PROC_FS)
--#include <linux/stat.h>
--#include <linux/proc_fs.h>
--
--static u8 cmd64x_proc = 0;
--
--#define CMD_MAX_DEVS		5
--
--static struct pci_dev *cmd_devs[CMD_MAX_DEVS];
--static int n_cmd_devs;
--
--static char * print_cmd64x_get_info (char *buf, struct pci_dev *dev, int index)
--{
--	char *p = buf;
--	u8 reg72 = 0, reg73 = 0;			/* primary */
--	u8 reg7a = 0, reg7b = 0;			/* secondary */
--	u8 reg50 = 1, reg51 = 1, reg57 = 0, reg71 = 0;	/* extra */
--
--	p += sprintf(p, "\nController: %d\n", index);
--	p += sprintf(p, "PCI-%x Chipset.\n", dev->device);
--
--	(void) pci_read_config_byte(dev, CFR,       &reg50);
--	(void) pci_read_config_byte(dev, CNTRL,     &reg51);
--	(void) pci_read_config_byte(dev, ARTTIM23,  &reg57);
--	(void) pci_read_config_byte(dev, MRDMODE,   &reg71);
--	(void) pci_read_config_byte(dev, BMIDESR0,  &reg72);
--	(void) pci_read_config_byte(dev, UDIDETCR0, &reg73);
--	(void) pci_read_config_byte(dev, BMIDESR1,  &reg7a);
--	(void) pci_read_config_byte(dev, UDIDETCR1, &reg7b);
--
--	/* PCI0643/6 originally didn't have the primary channel enable bit */
--	if ((dev->device == PCI_DEVICE_ID_CMD_643) ||
--	    (dev->device == PCI_DEVICE_ID_CMD_646 && dev->revision < 3))
--		reg51 |= CNTRL_ENA_1ST;
--
--	p += sprintf(p, "---------------- Primary Channel "
--			"---------------- Secondary Channel ------------\n");
--	p += sprintf(p, "                 %s                         %s\n",
--		 (reg51 & CNTRL_ENA_1ST) ? "enabled " : "disabled",
--		 (reg51 & CNTRL_ENA_2ND) ? "enabled " : "disabled");
--	p += sprintf(p, "---------------- drive0 --------- drive1 "
--			"-------- drive0 --------- drive1 ------\n");
--	p += sprintf(p, "DMA enabled:     %s              %s"
--			"             %s              %s\n",
--		(reg72 & 0x20) ? "yes" : "no ", (reg72 & 0x40) ? "yes" : "no ",
--		(reg7a & 0x20) ? "yes" : "no ", (reg7a & 0x40) ? "yes" : "no ");
--	p += sprintf(p, "UltraDMA mode:   %s (%c)          %s (%c)",
--		( reg73 & 0x01) ? " on" : "off",
--		((reg73 & 0x30) == 0x30) ? ((reg73 & 0x04) ? '3' : '0') :
--		((reg73 & 0x30) == 0x20) ? ((reg73 & 0x04) ? '3' : '1') :
--		((reg73 & 0x30) == 0x10) ? ((reg73 & 0x04) ? '4' : '2') :
--		((reg73 & 0x30) == 0x00) ? ((reg73 & 0x04) ? '5' : '2') : '?',
--		( reg73 & 0x02) ? " on" : "off",
--		((reg73 & 0xC0) == 0xC0) ? ((reg73 & 0x08) ? '3' : '0') :
--		((reg73 & 0xC0) == 0x80) ? ((reg73 & 0x08) ? '3' : '1') :
--		((reg73 & 0xC0) == 0x40) ? ((reg73 & 0x08) ? '4' : '2') :
--		((reg73 & 0xC0) == 0x00) ? ((reg73 & 0x08) ? '5' : '2') : '?');
--	p += sprintf(p, "         %s (%c)          %s (%c)\n",
--		( reg7b & 0x01) ? " on" : "off",
--		((reg7b & 0x30) == 0x30) ? ((reg7b & 0x04) ? '3' : '0') :
--		((reg7b & 0x30) == 0x20) ? ((reg7b & 0x04) ? '3' : '1') :
--		((reg7b & 0x30) == 0x10) ? ((reg7b & 0x04) ? '4' : '2') :
--		((reg7b & 0x30) == 0x00) ? ((reg7b & 0x04) ? '5' : '2') : '?',
--		( reg7b & 0x02) ? " on" : "off",
--		((reg7b & 0xC0) == 0xC0) ? ((reg7b & 0x08) ? '3' : '0') :
--		((reg7b & 0xC0) == 0x80) ? ((reg7b & 0x08) ? '3' : '1') :
--		((reg7b & 0xC0) == 0x40) ? ((reg7b & 0x08) ? '4' : '2') :
--		((reg7b & 0xC0) == 0x00) ? ((reg7b & 0x08) ? '5' : '2') : '?');
--	p += sprintf(p, "Interrupt:       %s, %s                 %s, %s\n",
--		(reg71 & MRDMODE_BLK_CH0  ) ? "blocked" : "enabled",
--		(reg50 & CFR_INTR_CH0	  ) ? "pending" : "clear  ",
--		(reg71 & MRDMODE_BLK_CH1  ) ? "blocked" : "enabled",
--		(reg57 & ARTTIM23_INTR_CH1) ? "pending" : "clear  ");
--
--	return (char *)p;
--}
--
--static int cmd64x_get_info (char *buffer, char **addr, off_t offset, int count)
--{
--	char *p = buffer;
--	int i;
++	kobject_uevent(&p->kobj, KOBJ_ADD);
+ 	return 0;
+ 
+ err_free_pkey:
+@@ -570,9 +562,7 @@ err_remove_pma:
+ 	sysfs_remove_group(&p->kobj, &pma_group);
+ 
+ err_put:
+-	kobject_put(&device->ports_parent);
 -
--	for (i = 0; i < n_cmd_devs; i++) {
--		struct pci_dev *dev	= cmd_devs[i];
--		p = print_cmd64x_get_info(p, dev, i);
+-err:
++	kobject_put(device->ports_parent);
+ 	kfree(p);
+ 	return ret;
+ }
+@@ -694,16 +684,9 @@ int ib_device_register_sysfs(struct ib_device *device)
+ 			goto err_unregister;
+ 	}
+ 
+-	device->ports_parent.parent = kobject_get(&class_dev->kobj);
+-	if (!device->ports_parent.parent) {
+-		ret = -EBUSY;
+-		goto err_unregister;
 -	}
--	return p-buffer;	/* => must be less than 4k! */
--}
--
--#endif	/* defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_IDE_PROC_FS) */
--
- static u8 quantize_timing(int timing, int quant)
- {
- 	return (timing + quant - 1) / quant;
-@@ -322,8 +220,6 @@ static void cmd64x_set_dma_mode(ide_drive_t *drive, const u8 speed)
- 	case XFER_MW_DMA_0:
- 		program_cycle_times(drive, 480, 215);
- 		break;
--	default:
--		return;
+-	ret = kobject_set_name(&device->ports_parent, "ports");
+-	if (ret)
+-		goto err_put;
+-	ret = kobject_register(&device->ports_parent);
+-	if (ret)
++	device->ports_parent = kobject_create_and_add("ports",
++					kobject_get(&class_dev->kobj));
++	if (!device->ports_parent)
+ 		goto err_put;
+ 
+ 	if (device->node_type == RDMA_NODE_IB_SWITCH) {
+@@ -731,7 +714,7 @@ err_put:
+ 			sysfs_remove_group(p, &pma_group);
+ 			sysfs_remove_group(p, &port->pkey_group);
+ 			sysfs_remove_group(p, &port->gid_group);
+-			kobject_unregister(p);
++			kobject_put(p);
+ 		}
  	}
  
- 	if (speed >= XFER_SW_DMA_0)
-@@ -333,14 +229,15 @@ static void cmd64x_set_dma_mode(ide_drive_t *drive, const u8 speed)
- static int cmd648_ide_dma_end (ide_drive_t *drive)
- {
- 	ide_hwif_t *hwif	= HWIF(drive);
-+	unsigned long base	= hwif->dma_base - (hwif->channel * 8);
- 	int err			= __ide_dma_end(drive);
- 	u8  irq_mask		= hwif->channel ? MRDMODE_INTR_CH1 :
- 						  MRDMODE_INTR_CH0;
--	u8  mrdmode		= inb(hwif->dma_master + 0x01);
-+	u8  mrdmode		= inb(base + 1);
+@@ -755,10 +738,10 @@ void ib_device_unregister_sysfs(struct ib_device *device)
+ 		sysfs_remove_group(p, &pma_group);
+ 		sysfs_remove_group(p, &port->pkey_group);
+ 		sysfs_remove_group(p, &port->gid_group);
+-		kobject_unregister(p);
++		kobject_put(p);
+ 	}
  
- 	/* clear the interrupt bit */
- 	outb((mrdmode & ~(MRDMODE_INTR_CH0 | MRDMODE_INTR_CH1)) | irq_mask,
--	     hwif->dma_master + 0x01);
-+	     base + 1);
+-	kobject_unregister(&device->ports_parent);
++	kobject_put(device->ports_parent);
+ 	class_device_unregister(&device->class_dev);
+ }
  
- 	return err;
+diff --git a/drivers/infiniband/core/ucm.c b/drivers/infiniband/core/ucm.c
+index 424983f..4291ab4 100644
+--- a/drivers/infiniband/core/ucm.c
++++ b/drivers/infiniband/core/ucm.c
+@@ -106,6 +106,9 @@ enum {
+ 	IB_UCM_MAX_DEVICES = 32
+ };
+ 
++/* ib_cm and ib_user_cm modules share /sys/class/infiniband_cm */
++extern struct class cm_class;
++
+ #define IB_UCM_BASE_DEV MKDEV(IB_UCM_MAJOR, IB_UCM_BASE_MINOR)
+ 
+ static void ib_ucm_add_one(struct ib_device *device);
+@@ -1199,7 +1202,7 @@ static int ib_ucm_close(struct inode *inode, struct file *filp)
+ 	return 0;
  }
-@@ -365,10 +262,11 @@ static int cmd64x_ide_dma_end (ide_drive_t *drive)
- static int cmd648_ide_dma_test_irq (ide_drive_t *drive)
+ 
+-static void ib_ucm_release_class_dev(struct class_device *class_dev)
++static void ucm_release_class_dev(struct class_device *class_dev)
  {
- 	ide_hwif_t *hwif	= HWIF(drive);
-+	unsigned long base	= hwif->dma_base - (hwif->channel * 8);
- 	u8 irq_mask		= hwif->channel ? MRDMODE_INTR_CH1 :
- 						  MRDMODE_INTR_CH0;
- 	u8 dma_stat		= inb(hwif->dma_status);
--	u8 mrdmode		= inb(hwif->dma_master + 0x01);
-+	u8 mrdmode		= inb(base + 1);
+ 	struct ib_ucm_device *dev;
  
- #ifdef DEBUG
- 	printk("%s: dma_stat: 0x%02x mrdmode: 0x%02x irq_mask: 0x%02x\n",
-@@ -472,16 +370,6 @@ static unsigned int __devinit init_chipset_cmd64x(struct pci_dev *dev, const cha
- 	mrdmode &= ~0x30;
- 	(void) pci_write_config_byte(dev, MRDMODE, (mrdmode | 0x02));
+@@ -1217,11 +1220,6 @@ static const struct file_operations ucm_fops = {
+ 	.poll    = ib_ucm_poll,
+ };
  
--#if defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_IDE_PROC_FS)
--
--	cmd_devs[n_cmd_devs++] = dev;
+-static struct class ucm_class = {
+-	.name    = "infiniband_cm",
+-	.release = ib_ucm_release_class_dev
+-};
 -
--	if (!cmd64x_proc) {
--		cmd64x_proc = 1;
--		ide_pci_create_host_proc("cmd64x", cmd64x_get_info);
+ static ssize_t show_ibdev(struct class_device *class_dev, char *buf)
+ {
+ 	struct ib_ucm_device *dev;
+@@ -1257,9 +1255,10 @@ static void ib_ucm_add_one(struct ib_device *device)
+ 	if (cdev_add(&ucm_dev->dev, IB_UCM_BASE_DEV + ucm_dev->devnum, 1))
+ 		goto err;
+ 
+-	ucm_dev->class_dev.class = &ucm_class;
++	ucm_dev->class_dev.class = &cm_class;
+ 	ucm_dev->class_dev.dev = device->dma_device;
+ 	ucm_dev->class_dev.devt = ucm_dev->dev.dev;
++	ucm_dev->class_dev.release = ucm_release_class_dev;
+ 	snprintf(ucm_dev->class_dev.class_id, BUS_ID_SIZE, "ucm%d",
+ 		 ucm_dev->devnum);
+ 	if (class_device_register(&ucm_dev->class_dev))
+@@ -1306,40 +1305,34 @@ static int __init ib_ucm_init(void)
+ 				     "infiniband_cm");
+ 	if (ret) {
+ 		printk(KERN_ERR "ucm: couldn't register device number\n");
+-		goto err;
++		goto error1;
+ 	}
+ 
+-	ret = class_register(&ucm_class);
+-	if (ret) {
+-		printk(KERN_ERR "ucm: couldn't create class infiniband_cm\n");
+-		goto err_chrdev;
 -	}
--#endif /* DISPLAY_CMD64X_TIMINGS && CONFIG_IDE_PROC_FS */
 -
- 	return 0;
- }
- 
-diff --git a/drivers/ide/pci/cs5520.c b/drivers/ide/pci/cs5520.c
-index 0466462..6ec00b8 100644
---- a/drivers/ide/pci/cs5520.c
-+++ b/drivers/ide/pci/cs5520.c
-@@ -71,7 +71,6 @@ static void cs5520_set_pio_mode(ide_drive_t *drive, const u8 pio)
- 	ide_hwif_t *hwif = HWIF(drive);
- 	struct pci_dev *pdev = hwif->pci_dev;
- 	int controller = drive->dn > 1 ? 1 : 0;
--	u8 reg;
+-	ret = class_create_file(&ucm_class, &class_attr_abi_version);
++	ret = class_create_file(&cm_class, &class_attr_abi_version);
+ 	if (ret) {
+ 		printk(KERN_ERR "ucm: couldn't create abi_version attribute\n");
+-		goto err_class;
++		goto error2;
+ 	}
  
- 	/* FIXME: if DMA = 1 do we need to set the DMA bit here ? */
+ 	ret = ib_register_client(&ucm_client);
+ 	if (ret) {
+ 		printk(KERN_ERR "ucm: couldn't register client\n");
+-		goto err_class;
++		goto error3;
+ 	}
+ 	return 0;
  
-@@ -91,11 +90,6 @@ static void cs5520_set_pio_mode(ide_drive_t *drive, const u8 pio)
- 	pci_write_config_byte(pdev, 0x66 + 4*controller + (drive->dn&1),
- 		(cs5520_pio_clocks[pio].recovery << 4) |
- 		(cs5520_pio_clocks[pio].assert));
--		
--	/* Set the DMA enable/disable flag */
--	reg = inb(hwif->dma_base + 0x02 + 8*controller);
--	reg |= 1<<((drive->dn&1)+5);
--	outb(reg, hwif->dma_base + 0x02 + 8*controller);
+-err_class:
+-	class_unregister(&ucm_class);
+-err_chrdev:
++error3:
++	class_remove_file(&cm_class, &class_attr_abi_version);
++error2:
+ 	unregister_chrdev_region(IB_UCM_BASE_DEV, IB_UCM_MAX_DEVICES);
+-err:
++error1:
+ 	return ret;
  }
  
- static void cs5520_set_dma_mode(ide_drive_t *drive, const u8 speed)
-@@ -109,13 +103,14 @@ static void cs5520_set_dma_mode(ide_drive_t *drive, const u8 speed)
-  *	We wrap the DMA activate to set the vdma flag. This is needed
-  *	so that the IDE DMA layer issues PIO not DMA commands over the
-  *	DMA channel
-+ *
-+ *	ATAPI is harder so disable it for now using IDE_HFLAG_NO_ATAPI_DMA
-  */
-- 
--static int cs5520_dma_on(ide_drive_t *drive)
-+
-+static void cs5520_dma_host_set(ide_drive_t *drive, int on)
+ static void __exit ib_ucm_cleanup(void)
  {
--	/* ATAPI is harder so leave it for now */
--	drive->vdma = 1;
--	return 0;
-+	drive->vdma = on;
-+	ide_dma_host_set(drive, on);
+ 	ib_unregister_client(&ucm_client);
+-	class_unregister(&ucm_class);
++	class_remove_file(&cm_class, &class_attr_abi_version);
+ 	unregister_chrdev_region(IB_UCM_BASE_DEV, IB_UCM_MAX_DEVICES);
+ 	idr_destroy(&ctx_id_table);
  }
+diff --git a/drivers/infiniband/core/ucma.c b/drivers/infiniband/core/ucma.c
+index 90d675a..15937eb 100644
+--- a/drivers/infiniband/core/ucma.c
++++ b/drivers/infiniband/core/ucma.c
+@@ -31,6 +31,7 @@
+  */
  
- static void __devinit init_hwif_cs5520(ide_hwif_t *hwif)
-@@ -126,7 +121,7 @@ static void __devinit init_hwif_cs5520(ide_hwif_t *hwif)
- 	if (hwif->dma_base == 0)
- 		return;
- 
--	hwif->ide_dma_on = &cs5520_dma_on;
-+	hwif->dma_host_set = &cs5520_dma_host_set;
+ #include <linux/completion.h>
++#include <linux/file.h>
+ #include <linux/mutex.h>
+ #include <linux/poll.h>
+ #include <linux/idr.h>
+@@ -991,6 +992,96 @@ out:
+ 	return ret;
  }
  
- #define DECLARE_CS_DEV(name_str)				\
-@@ -137,6 +132,7 @@ static void __devinit init_hwif_cs5520(ide_hwif_t *hwif)
- 				  IDE_HFLAG_CS5520 |		\
- 				  IDE_HFLAG_VDMA |		\
- 				  IDE_HFLAG_NO_ATAPI_DMA |	\
-+				  IDE_HFLAG_ABUSE_SET_DMA_MODE |\
- 				  IDE_HFLAG_BOOTABLE,		\
- 		.pio_mask	= ATA_PIO4,			\
- 	}
-diff --git a/drivers/ide/pci/cs5530.c b/drivers/ide/pci/cs5530.c
-index 5476903..df5966b 100644
---- a/drivers/ide/pci/cs5530.c
-+++ b/drivers/ide/pci/cs5530.c
-@@ -116,8 +116,6 @@ static void cs5530_set_dma_mode(ide_drive_t *drive, const u8 mode)
- 		case XFER_MW_DMA_0:	timings = 0x00077771; break;
- 		case XFER_MW_DMA_1:	timings = 0x00012121; break;
- 		case XFER_MW_DMA_2:	timings = 0x00002020; break;
--		default:
--			return;
- 	}
- 	basereg = CS5530_BASEREG(drive->hwif);
- 	reg = inl(basereg + 4);			/* get drive0 config register */
-diff --git a/drivers/ide/pci/cs5535.c b/drivers/ide/pci/cs5535.c
-index ddcbeba..50b3d77 100644
---- a/drivers/ide/pci/cs5535.c
-+++ b/drivers/ide/pci/cs5535.c
-@@ -190,7 +190,7 @@ static const struct ide_port_info cs5535_chipset __devinitdata = {
- 	.name		= "CS5535",
- 	.init_hwif	= init_hwif_cs5535,
- 	.host_flags	= IDE_HFLAG_SINGLE | IDE_HFLAG_POST_SET_MODE |
--			  IDE_HFLAG_BOOTABLE,
-+			  IDE_HFLAG_ABUSE_SET_DMA_MODE | IDE_HFLAG_BOOTABLE,
- 	.pio_mask	= ATA_PIO4,
- 	.mwdma_mask	= ATA_MWDMA2,
- 	.udma_mask	= ATA_UDMA4,
-diff --git a/drivers/ide/pci/cy82c693.c b/drivers/ide/pci/cy82c693.c
-index 1cd4e9c..3ec4c65 100644
---- a/drivers/ide/pci/cy82c693.c
-+++ b/drivers/ide/pci/cy82c693.c
-@@ -1,5 +1,5 @@
- /*
-- * linux/drivers/ide/pci/cy82c693.c		Version 0.42	Oct 23, 2007
-+ * linux/drivers/ide/pci/cy82c693.c		Version 0.44	Nov 8, 2007
-  *
-  *  Copyright (C) 1998-2000 Andreas S. Krebs (akrebs at altavista.net), Maintainer
-  *  Copyright (C) 1998-2002 Andre Hedrick <andre at linux-ide.org>, Integrator
-@@ -176,17 +176,12 @@ static void compute_clocks (u8 pio, pio_clocks_t *p_pclk)
-  * set DMA mode a specific channel for CY82C693
-  */
- 
--static void cy82c693_dma_enable (ide_drive_t *drive, int mode, int single)
-+static void cy82c693_set_dma_mode(ide_drive_t *drive, const u8 mode)
- {
--	u8 index = 0, data = 0;
-+	ide_hwif_t *hwif = drive->hwif;
-+	u8 single = (mode & 0x10) >> 4, index = 0, data = 0;
++static void ucma_lock_files(struct ucma_file *file1, struct ucma_file *file2)
++{
++	/* Acquire mutex's based on pointer comparison to prevent deadlock. */
++	if (file1 < file2) {
++		mutex_lock(&file1->mut);
++		mutex_lock(&file2->mut);
++	} else {
++		mutex_lock(&file2->mut);
++		mutex_lock(&file1->mut);
++	}
++}
++
++static void ucma_unlock_files(struct ucma_file *file1, struct ucma_file *file2)
++{
++	if (file1 < file2) {
++		mutex_unlock(&file2->mut);
++		mutex_unlock(&file1->mut);
++	} else {
++		mutex_unlock(&file1->mut);
++		mutex_unlock(&file2->mut);
++	}
++}
++
++static void ucma_move_events(struct ucma_context *ctx, struct ucma_file *file)
++{
++	struct ucma_event *uevent, *tmp;
++
++	list_for_each_entry_safe(uevent, tmp, &ctx->file->event_list, list)
++		if (uevent->ctx == ctx)
++			list_move_tail(&uevent->list, &file->event_list);
++}
++
++static ssize_t ucma_migrate_id(struct ucma_file *new_file,
++			       const char __user *inbuf,
++			       int in_len, int out_len)
++{
++	struct rdma_ucm_migrate_id cmd;
++	struct rdma_ucm_migrate_resp resp;
++	struct ucma_context *ctx;
++	struct file *filp;
++	struct ucma_file *cur_file;
++	int ret = 0;
++
++	if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
++		return -EFAULT;
++
++	/* Get current fd to protect against it being closed */
++	filp = fget(cmd.fd);
++	if (!filp)
++		return -ENOENT;
++
++	/* Validate current fd and prevent destruction of id. */
++	ctx = ucma_get_ctx(filp->private_data, cmd.id);
++	if (IS_ERR(ctx)) {
++		ret = PTR_ERR(ctx);
++		goto file_put;
++	}
++
++	cur_file = ctx->file;
++	if (cur_file == new_file) {
++		resp.events_reported = ctx->events_reported;
++		goto response;
++	}
++
++	/*
++	 * Migrate events between fd's, maintaining order, and avoiding new
++	 * events being added before existing events.
++	 */
++	ucma_lock_files(cur_file, new_file);
++	mutex_lock(&mut);
++
++	list_move_tail(&ctx->list, &new_file->ctx_list);
++	ucma_move_events(ctx, new_file);
++	ctx->file = new_file;
++	resp.events_reported = ctx->events_reported;
++
++	mutex_unlock(&mut);
++	ucma_unlock_files(cur_file, new_file);
++
++response:
++	if (copy_to_user((void __user *)(unsigned long)cmd.response,
++			 &resp, sizeof(resp)))
++		ret = -EFAULT;
++
++	ucma_put_ctx(ctx);
++file_put:
++	fput(filp);
++	return ret;
++}
++
+ static ssize_t (*ucma_cmd_table[])(struct ucma_file *file,
+ 				   const char __user *inbuf,
+ 				   int in_len, int out_len) = {
+@@ -1012,6 +1103,7 @@ static ssize_t (*ucma_cmd_table[])(struct ucma_file *file,
+ 	[RDMA_USER_CM_CMD_NOTIFY]	= ucma_notify,
+ 	[RDMA_USER_CM_CMD_JOIN_MCAST]	= ucma_join_multicast,
+ 	[RDMA_USER_CM_CMD_LEAVE_MCAST]	= ucma_leave_multicast,
++	[RDMA_USER_CM_CMD_MIGRATE_ID]	= ucma_migrate_id
+ };
  
--	if (mode>2)	/* make sure we set a valid mode */
--		mode = 2;
--			   
--	if (mode > drive->id->tDMA)  /* to be absolutly sure we have a valid mode */
--		mode = drive->id->tDMA;
--	
--	index = (HWIF(drive)->channel==0) ? CY82_INDEX_CHANNEL0 : CY82_INDEX_CHANNEL1;
-+	index = hwif->channel ? CY82_INDEX_CHANNEL1 : CY82_INDEX_CHANNEL0;
+ static ssize_t ucma_write(struct file *filp, const char __user *buf,
+diff --git a/drivers/infiniband/core/user_mad.c b/drivers/infiniband/core/user_mad.c
+index b53eac4..4e91510 100644
+--- a/drivers/infiniband/core/user_mad.c
++++ b/drivers/infiniband/core/user_mad.c
+@@ -2,6 +2,7 @@
+  * Copyright (c) 2004 Topspin Communications.  All rights reserved.
+  * Copyright (c) 2005 Voltaire, Inc. All rights reserved.
+  * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
++ * Copyright (c) 2008 Cisco. 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
+@@ -42,7 +43,7 @@
+ #include <linux/cdev.h>
+ #include <linux/dma-mapping.h>
+ #include <linux/poll.h>
+-#include <linux/rwsem.h>
++#include <linux/mutex.h>
+ #include <linux/kref.h>
+ #include <linux/compat.h>
  
- #if CY82C693_DEBUG_LOGS
- 	/* for debug let's show the previous values */
-@@ -199,7 +194,7 @@ static void cy82c693_dma_enable (ide_drive_t *drive, int mode, int single)
- 		(data&0x3), ((data>>2)&1));
- #endif /* CY82C693_DEBUG_LOGS */
+@@ -94,7 +95,7 @@ struct ib_umad_port {
+ 	struct class_device   *sm_class_dev;
+ 	struct semaphore       sm_sem;
  
--	data = (u8)mode|(u8)(single<<2);
-+	data = (mode & 3) | (single << 2);
+-	struct rw_semaphore    mutex;
++	struct mutex	       file_mutex;
+ 	struct list_head       file_list;
  
- 	outb(index, CY82_INDEX_PORT);
- 	outb(data, CY82_DATA_PORT);
-@@ -207,7 +202,7 @@ static void cy82c693_dma_enable (ide_drive_t *drive, int mode, int single)
- #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, single);
-+		mode & 3, single);
- #endif /* CY82C693_DEBUG_INFO */
+ 	struct ib_device      *ib_dev;
+@@ -110,11 +111,11 @@ struct ib_umad_device {
+ };
  
- 	/* 
-@@ -230,39 +225,6 @@ static void cy82c693_dma_enable (ide_drive_t *drive, int mode, int single)
- #endif /* CY82C693_DEBUG_INFO */
+ struct ib_umad_file {
++	struct mutex		mutex;
+ 	struct ib_umad_port    *port;
+ 	struct list_head	recv_list;
+ 	struct list_head	send_list;
+ 	struct list_head	port_list;
+-	spinlock_t		recv_lock;
+ 	spinlock_t		send_lock;
+ 	wait_queue_head_t	recv_wait;
+ 	struct ib_mad_agent    *agent[IB_UMAD_MAX_AGENTS];
+@@ -156,7 +157,7 @@ static int hdr_size(struct ib_umad_file *file)
+ 		sizeof (struct ib_user_mad_hdr_old);
  }
  
--/* 
-- * used to set DMA mode for CY82C693 (single and multi modes)
-- */
--static int cy82c693_ide_dma_on (ide_drive_t *drive)
--{
--	struct hd_driveid *id = drive->id;
--
--#if CY82C693_DEBUG_INFO
--	printk (KERN_INFO "dma_on: %s\n", drive->name);
--#endif /* CY82C693_DEBUG_INFO */
--
--	if (id != NULL) {		
--		/* Enable DMA on any drive that has DMA
--		 * (multi or single) enabled
--		 */
--		if (id->field_valid & 2) {	/* regular DMA */
--			int mmode, smode;
--
--			mmode = id->dma_mword & (id->dma_mword >> 8);
--			smode = id->dma_1word & (id->dma_1word >> 8);
--			       		      
--			if (mmode != 0) {
--				/* enable multi */
--				cy82c693_dma_enable(drive, (mmode >> 1), 0);
--			} else if (smode != 0) {
--				/* enable single */
--				cy82c693_dma_enable(drive, (smode >> 1), 1);
--			}
--		}
--	}
--        return __ide_dma_on(drive);
--}
--
- static void cy82c693_set_pio_mode(ide_drive_t *drive, const u8 pio)
+-/* caller must hold port->mutex at least for reading */
++/* caller must hold file->mutex */
+ static struct ib_mad_agent *__get_agent(struct ib_umad_file *file, int id)
  {
- 	ide_hwif_t *hwif = HWIF(drive);
-@@ -429,11 +391,7 @@ static unsigned int __devinit init_chipset_cy82c693(struct pci_dev *dev, const c
- static void __devinit init_hwif_cy82c693(ide_hwif_t *hwif)
+ 	return file->agents_dead ? NULL : file->agent[id];
+@@ -168,32 +169,30 @@ static int queue_packet(struct ib_umad_file *file,
  {
- 	hwif->set_pio_mode = &cy82c693_set_pio_mode;
--
--	if (hwif->dma_base == 0)
--		return;
--
--	hwif->ide_dma_on = &cy82c693_ide_dma_on;
-+	hwif->set_dma_mode = &cy82c693_set_dma_mode;
- }
+ 	int ret = 1;
  
- static void __devinit init_iops_cy82c693(ide_hwif_t *hwif)
-@@ -454,11 +412,11 @@ static const struct ide_port_info cy82c693_chipset __devinitdata = {
- 	.init_iops	= init_iops_cy82c693,
- 	.init_hwif	= init_hwif_cy82c693,
- 	.chipset	= ide_cy82c693,
--	.host_flags	= IDE_HFLAG_SINGLE | IDE_HFLAG_TRUST_BIOS_FOR_DMA |
-+	.host_flags	= IDE_HFLAG_SINGLE | IDE_HFLAG_CY82C693 |
- 			  IDE_HFLAG_BOOTABLE,
- 	.pio_mask	= ATA_PIO4,
--	.swdma_mask	= ATA_SWDMA2_ONLY,
--	.mwdma_mask	= ATA_MWDMA2_ONLY,
-+	.swdma_mask	= ATA_SWDMA2,
-+	.mwdma_mask	= ATA_MWDMA2,
- };
+-	down_read(&file->port->mutex);
++	mutex_lock(&file->mutex);
  
- static int __devinit cy82c693_init_one(struct pci_dev *dev, const struct pci_device_id *id)
-diff --git a/drivers/ide/pci/delkin_cb.c b/drivers/ide/pci/delkin_cb.c
-index 8382908..26aa492 100644
---- a/drivers/ide/pci/delkin_cb.c
-+++ b/drivers/ide/pci/delkin_cb.c
-@@ -80,7 +80,7 @@ delkin_cb_probe (struct pci_dev *dev, const struct pci_device_id *id)
- 	hw.irq = dev->irq;
- 	hw.chipset = ide_pci;		/* this enables IRQ sharing */
+ 	for (packet->mad.hdr.id = 0;
+ 	     packet->mad.hdr.id < IB_UMAD_MAX_AGENTS;
+ 	     packet->mad.hdr.id++)
+ 		if (agent == __get_agent(file, packet->mad.hdr.id)) {
+-			spin_lock_irq(&file->recv_lock);
+ 			list_add_tail(&packet->list, &file->recv_list);
+-			spin_unlock_irq(&file->recv_lock);
+ 			wake_up_interruptible(&file->recv_wait);
+ 			ret = 0;
+ 			break;
+ 		}
  
--	rc = ide_register_hw(&hw, &ide_undecoded_slave, 0, &hwif);
-+	rc = ide_register_hw(&hw, &ide_undecoded_slave, &hwif);
- 	if (rc < 0) {
- 		printk(KERN_ERR "delkin_cb: ide_register_hw failed (%d)\n", rc);
- 		pci_disable_device(dev);
-diff --git a/drivers/ide/pci/hpt34x.c b/drivers/ide/pci/hpt34x.c
-index ae6307f..dfba0d1 100644
---- a/drivers/ide/pci/hpt34x.c
-+++ b/drivers/ide/pci/hpt34x.c
-@@ -129,14 +129,18 @@ static void __devinit init_hwif_hpt34x(ide_hwif_t *hwif)
- 	hwif->set_dma_mode = &hpt34x_set_mode;
+-	up_read(&file->port->mutex);
++	mutex_unlock(&file->mutex);
+ 
+ 	return ret;
  }
  
-+#define IDE_HFLAGS_HPT34X \
-+	(IDE_HFLAG_NO_ATAPI_DMA | \
-+	 IDE_HFLAG_ABUSE_SET_DMA_MODE | \
-+	 IDE_HFLAG_NO_AUTODMA)
-+
- static const struct ide_port_info hpt34x_chipsets[] __devinitdata = {
- 	{ /* 0 */
- 		.name		= "HPT343",
- 		.init_chipset	= init_chipset_hpt34x,
- 		.init_hwif	= init_hwif_hpt34x,
- 		.extra		= 16,
--		.host_flags	= IDE_HFLAG_NO_ATAPI_DMA |
--				  IDE_HFLAG_NO_AUTODMA,
-+		.host_flags	= IDE_HFLAGS_HPT34X,
- 		.pio_mask	= ATA_PIO5,
- 	},
- 	{ /* 1 */
-@@ -144,9 +148,7 @@ static const struct ide_port_info hpt34x_chipsets[] __devinitdata = {
- 		.init_chipset	= init_chipset_hpt34x,
- 		.init_hwif	= init_hwif_hpt34x,
- 		.extra		= 16,
--		.host_flags	= IDE_HFLAG_NO_ATAPI_DMA |
--				  IDE_HFLAG_NO_AUTODMA |
--				  IDE_HFLAG_OFF_BOARD,
-+		.host_flags	= IDE_HFLAGS_HPT34X | IDE_HFLAG_OFF_BOARD,
- 		.pio_mask	= ATA_PIO5,
- #ifdef CONFIG_HPT34X_AUTODMA
- 		.swdma_mask	= ATA_SWDMA2,
-diff --git a/drivers/ide/pci/hpt366.c b/drivers/ide/pci/hpt366.c
-index 9fce25b..1268593 100644
---- a/drivers/ide/pci/hpt366.c
-+++ b/drivers/ide/pci/hpt366.c
-@@ -1,5 +1,5 @@
- /*
-- * linux/drivers/ide/pci/hpt366.c		Version 1.22	Dec 4, 2007
-+ * linux/drivers/ide/pci/hpt366.c		Version 1.30	Dec 12, 2007
-  *
-  * Copyright (C) 1999-2003		Andre Hedrick <andre at linux-ide.org>
-  * Portions Copyright (C) 2001	        Sun Microsystems, Inc.
-@@ -88,7 +88,7 @@
-  * - rename all the register related variables consistently
-  * - move all the interrupt twiddling code from the speedproc handlers into
-  *   init_hwif_hpt366(), also grouping all the DMA related code together there
-- * - merge two HPT37x speedproc handlers, fix the PIO timing register mask and
-+ * - merge HPT36x/HPT37x speedproc handlers, fix PIO timing register mask and
-  *   separate the UltraDMA and MWDMA masks there to avoid changing PIO timings
-  *   when setting an UltraDMA mode
-  * - fix hpt3xx_tune_drive() to set the PIO mode requested, not always select
-@@ -458,6 +458,13 @@ enum ata_clock {
- 	NUM_ATA_CLOCKS
- };
+ static void dequeue_send(struct ib_umad_file *file,
+ 			 struct ib_umad_packet *packet)
+- {
++{
+ 	spin_lock_irq(&file->send_lock);
+ 	list_del(&packet->list);
+ 	spin_unlock_irq(&file->send_lock);
+- }
++}
  
-+struct hpt_timings {
-+	u32 pio_mask;
-+	u32 dma_mask;
-+	u32 ultra_mask;
-+	u32 *clock_table[NUM_ATA_CLOCKS];
-+};
-+
- /*
-  *	Hold all the HighPoint chip information in one place.
-  */
-@@ -468,7 +475,8 @@ struct hpt_info {
- 	u8 udma_mask;		/* Allowed UltraDMA modes mask. */
- 	u8 dpll_clk;		/* DPLL clock in MHz */
- 	u8 pci_clk;		/* PCI  clock in MHz */
--	u32 **settings; 	/* Chipset settings table */
-+	struct hpt_timings *timings; /* Chipset timing data */
-+	u8 clock;		/* ATA clock selected */
- };
+ static void send_handler(struct ib_mad_agent *agent,
+ 			 struct ib_mad_send_wc *send_wc)
+@@ -341,10 +340,10 @@ static ssize_t ib_umad_read(struct file *filp, char __user *buf,
+ 	if (count < hdr_size(file))
+ 		return -EINVAL;
  
- /* Supported HighPoint chips */
-@@ -486,20 +494,30 @@ enum {
- 	HPT371N
- };
+-	spin_lock_irq(&file->recv_lock);
++	mutex_lock(&file->mutex);
  
--static u32 *hpt36x_settings[NUM_ATA_CLOCKS] = {
--	twenty_five_base_hpt36x,
--	thirty_three_base_hpt36x,
--	forty_base_hpt36x,
--	NULL,
--	NULL
-+static struct hpt_timings hpt36x_timings = {
-+	.pio_mask	= 0xc1f8ffff,
-+	.dma_mask	= 0x303800ff,
-+	.ultra_mask	= 0x30070000,
-+	.clock_table	= {
-+		[ATA_CLOCK_25MHZ] = twenty_five_base_hpt36x,
-+		[ATA_CLOCK_33MHZ] = thirty_three_base_hpt36x,
-+		[ATA_CLOCK_40MHZ] = forty_base_hpt36x,
-+		[ATA_CLOCK_50MHZ] = NULL,
-+		[ATA_CLOCK_66MHZ] = NULL
-+	}
- };
+ 	while (list_empty(&file->recv_list)) {
+-		spin_unlock_irq(&file->recv_lock);
++		mutex_unlock(&file->mutex);
  
--static u32 *hpt37x_settings[NUM_ATA_CLOCKS] = {
--	NULL,
--	thirty_three_base_hpt37x,
--	NULL,
--	fifty_base_hpt37x,
--	sixty_six_base_hpt37x
-+static struct hpt_timings hpt37x_timings = {
-+	.pio_mask	= 0xcfc3ffff,
-+	.dma_mask	= 0x31c001ff,
-+	.ultra_mask	= 0x303c0000,
-+	.clock_table	= {
-+		[ATA_CLOCK_25MHZ] = NULL,
-+		[ATA_CLOCK_33MHZ] = thirty_three_base_hpt37x,
-+		[ATA_CLOCK_40MHZ] = NULL,
-+		[ATA_CLOCK_50MHZ] = fifty_base_hpt37x,
-+		[ATA_CLOCK_66MHZ] = sixty_six_base_hpt37x
-+	}
- };
+ 		if (filp->f_flags & O_NONBLOCK)
+ 			return -EAGAIN;
+@@ -353,13 +352,13 @@ static ssize_t ib_umad_read(struct file *filp, char __user *buf,
+ 					     !list_empty(&file->recv_list)))
+ 			return -ERESTARTSYS;
  
- static const struct hpt_info hpt36x __devinitdata = {
-@@ -507,7 +525,7 @@ static const struct hpt_info hpt36x __devinitdata = {
- 	.chip_type	= HPT36x,
- 	.udma_mask	= HPT366_ALLOW_ATA66_3 ? (HPT366_ALLOW_ATA66_4 ? ATA_UDMA4 : ATA_UDMA3) : ATA_UDMA2,
- 	.dpll_clk	= 0,	/* no DPLL */
--	.settings	= hpt36x_settings
-+	.timings	= &hpt36x_timings
- };
+-		spin_lock_irq(&file->recv_lock);
++		mutex_lock(&file->mutex);
+ 	}
  
- static const struct hpt_info hpt370 __devinitdata = {
-@@ -515,7 +533,7 @@ static const struct hpt_info hpt370 __devinitdata = {
- 	.chip_type	= HPT370,
- 	.udma_mask	= HPT370_ALLOW_ATA100_5 ? ATA_UDMA5 : ATA_UDMA4,
- 	.dpll_clk	= 48,
--	.settings	= hpt37x_settings
-+	.timings	= &hpt37x_timings
- };
+ 	packet = list_entry(file->recv_list.next, struct ib_umad_packet, list);
+ 	list_del(&packet->list);
  
- static const struct hpt_info hpt370a __devinitdata = {
-@@ -523,7 +541,7 @@ static const struct hpt_info hpt370a __devinitdata = {
- 	.chip_type	= HPT370A,
- 	.udma_mask	= HPT370_ALLOW_ATA100_5 ? ATA_UDMA5 : ATA_UDMA4,
- 	.dpll_clk	= 48,
--	.settings	= hpt37x_settings
-+	.timings	= &hpt37x_timings
- };
+-	spin_unlock_irq(&file->recv_lock);
++	mutex_unlock(&file->mutex);
  
- static const struct hpt_info hpt374 __devinitdata = {
-@@ -531,7 +549,7 @@ static const struct hpt_info hpt374 __devinitdata = {
- 	.chip_type	= HPT374,
- 	.udma_mask	= ATA_UDMA5,
- 	.dpll_clk	= 48,
--	.settings	= hpt37x_settings
-+	.timings	= &hpt37x_timings
- };
+ 	if (packet->recv_wc)
+ 		ret = copy_recv_mad(file, buf, packet, count);
+@@ -368,9 +367,9 @@ static ssize_t ib_umad_read(struct file *filp, char __user *buf,
  
- static const struct hpt_info hpt372 __devinitdata = {
-@@ -539,7 +557,7 @@ static const struct hpt_info hpt372 __devinitdata = {
- 	.chip_type	= HPT372,
- 	.udma_mask	= HPT372_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5,
- 	.dpll_clk	= 55,
--	.settings	= hpt37x_settings
-+	.timings	= &hpt37x_timings
- };
+ 	if (ret < 0) {
+ 		/* Requeue packet */
+-		spin_lock_irq(&file->recv_lock);
++		mutex_lock(&file->mutex);
+ 		list_add(&packet->list, &file->recv_list);
+-		spin_unlock_irq(&file->recv_lock);
++		mutex_unlock(&file->mutex);
+ 	} else {
+ 		if (packet->recv_wc)
+ 			ib_free_recv_mad(packet->recv_wc);
+@@ -481,7 +480,7 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf,
+ 		goto err;
+ 	}
  
- static const struct hpt_info hpt372a __devinitdata = {
-@@ -547,7 +565,7 @@ static const struct hpt_info hpt372a __devinitdata = {
- 	.chip_type	= HPT372A,
- 	.udma_mask	= HPT372_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5,
- 	.dpll_clk	= 66,
--	.settings	= hpt37x_settings
-+	.timings	= &hpt37x_timings
- };
+-	down_read(&file->port->mutex);
++	mutex_lock(&file->mutex);
  
- static const struct hpt_info hpt302 __devinitdata = {
-@@ -555,7 +573,7 @@ static const struct hpt_info hpt302 __devinitdata = {
- 	.chip_type	= HPT302,
- 	.udma_mask	= HPT302_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5,
- 	.dpll_clk	= 66,
--	.settings	= hpt37x_settings
-+	.timings	= &hpt37x_timings
- };
+ 	agent = __get_agent(file, packet->mad.hdr.id);
+ 	if (!agent) {
+@@ -577,7 +576,7 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf,
+ 	if (ret)
+ 		goto err_send;
  
- static const struct hpt_info hpt371 __devinitdata = {
-@@ -563,7 +581,7 @@ static const struct hpt_info hpt371 __devinitdata = {
- 	.chip_type	= HPT371,
- 	.udma_mask	= HPT371_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5,
- 	.dpll_clk	= 66,
--	.settings	= hpt37x_settings
-+	.timings	= &hpt37x_timings
- };
+-	up_read(&file->port->mutex);
++	mutex_unlock(&file->mutex);
+ 	return count;
  
- static const struct hpt_info hpt372n __devinitdata = {
-@@ -571,7 +589,7 @@ static const struct hpt_info hpt372n __devinitdata = {
- 	.chip_type	= HPT372N,
- 	.udma_mask	= HPT372_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5,
- 	.dpll_clk	= 77,
--	.settings	= hpt37x_settings
-+	.timings	= &hpt37x_timings
- };
+ err_send:
+@@ -587,7 +586,7 @@ err_msg:
+ err_ah:
+ 	ib_destroy_ah(ah);
+ err_up:
+-	up_read(&file->port->mutex);
++	mutex_unlock(&file->mutex);
+ err:
+ 	kfree(packet);
+ 	return ret;
+@@ -613,11 +612,12 @@ static int ib_umad_reg_agent(struct ib_umad_file *file, void __user *arg,
+ {
+ 	struct ib_user_mad_reg_req ureq;
+ 	struct ib_mad_reg_req req;
+-	struct ib_mad_agent *agent;
++	struct ib_mad_agent *agent = NULL;
+ 	int agent_id;
+ 	int ret;
  
- static const struct hpt_info hpt302n __devinitdata = {
-@@ -579,7 +597,7 @@ static const struct hpt_info hpt302n __devinitdata = {
- 	.chip_type	= HPT302N,
- 	.udma_mask	= HPT302_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5,
- 	.dpll_clk	= 77,
--	.settings	= hpt37x_settings
-+	.timings	= &hpt37x_timings
- };
+-	down_write(&file->port->mutex);
++	mutex_lock(&file->port->file_mutex);
++	mutex_lock(&file->mutex);
  
- static const struct hpt_info hpt371n __devinitdata = {
-@@ -587,7 +605,7 @@ static const struct hpt_info hpt371n __devinitdata = {
- 	.chip_type	= HPT371N,
- 	.udma_mask	= HPT371_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5,
- 	.dpll_clk	= 77,
--	.settings	= hpt37x_settings
-+	.timings	= &hpt37x_timings
- };
+ 	if (!file->port->ib_dev) {
+ 		ret = -EPIPE;
+@@ -666,13 +666,13 @@ found:
+ 				      send_handler, recv_handler, file);
+ 	if (IS_ERR(agent)) {
+ 		ret = PTR_ERR(agent);
++		agent = NULL;
+ 		goto out;
+ 	}
  
- static int check_in_drive_list(ide_drive_t *drive, const char **list)
-@@ -675,94 +693,50 @@ static u32 get_speed_setting(u8 speed, struct hpt_info *info)
- 	for (i = 0; i < ARRAY_SIZE(xfer_speeds) - 1; i++)
- 		if (xfer_speeds[i] == speed)
- 			break;
--	/*
--	 * NOTE: info->settings only points to the pointer
--	 * to the list of the actual register values
--	 */
--	return (*info->settings)[i];
+ 	if (put_user(agent_id,
+ 		     (u32 __user *) (arg + offsetof(struct ib_user_mad_reg_req, id)))) {
+ 		ret = -EFAULT;
+-		ib_unregister_mad_agent(agent);
+ 		goto out;
+ 	}
+ 
+@@ -690,7 +690,13 @@ found:
+ 	ret = 0;
+ 
+ out:
+-	up_write(&file->port->mutex);
++	mutex_unlock(&file->mutex);
 +
-+	return info->timings->clock_table[info->clock][i];
++	if (ret && agent)
++		ib_unregister_mad_agent(agent);
++
++	mutex_unlock(&file->port->file_mutex);
++
+ 	return ret;
  }
  
--static void hpt36x_set_mode(ide_drive_t *drive, const u8 speed)
-+static void hpt3xx_set_mode(ide_drive_t *drive, const u8 speed)
- {
--	ide_hwif_t *hwif	= HWIF(drive);
--	struct pci_dev  *dev	= hwif->pci_dev;
-+	struct pci_dev  *dev	= HWIF(drive)->pci_dev;
- 	struct hpt_info	*info	= pci_get_drvdata(dev);
--	u8  itr_addr		= drive->dn ? 0x44 : 0x40;
-+	struct hpt_timings *t	= info->timings;
-+	u8  itr_addr		= 0x40 + (drive->dn * 4);
- 	u32 old_itr		= 0;
--	u32 itr_mask, new_itr;
--
--	itr_mask = speed < XFER_MW_DMA_0 ? 0x30070000 :
--		  (speed < XFER_UDMA_0   ? 0xc0070000 : 0xc03800ff);
--
--	new_itr = get_speed_setting(speed, info);
-+	u32 new_itr		= get_speed_setting(speed, info);
-+	u32 itr_mask		= speed < XFER_MW_DMA_0 ? t->pio_mask :
-+				 (speed < XFER_UDMA_0   ? t->dma_mask :
-+							  t->ultra_mask);
+@@ -703,7 +709,8 @@ static int ib_umad_unreg_agent(struct ib_umad_file *file, u32 __user *arg)
+ 	if (get_user(id, arg))
+ 		return -EFAULT;
  
-+	pci_read_config_dword(dev, itr_addr, &old_itr);
-+	new_itr = (old_itr & ~itr_mask) | (new_itr & itr_mask);
- 	/*
- 	 * Disable on-chip PIO FIFO/buffer (and PIO MST mode as well)
- 	 * to avoid problems handling I/O errors later
- 	 */
--	pci_read_config_dword(dev, itr_addr, &old_itr);
--	new_itr  = (new_itr & ~itr_mask) | (old_itr & itr_mask);
- 	new_itr &= ~0xc0000000;
+-	down_write(&file->port->mutex);
++	mutex_lock(&file->port->file_mutex);
++	mutex_lock(&file->mutex);
  
- 	pci_write_config_dword(dev, itr_addr, new_itr);
+ 	if (id < 0 || id >= IB_UMAD_MAX_AGENTS || !__get_agent(file, id)) {
+ 		ret = -EINVAL;
+@@ -714,11 +721,13 @@ static int ib_umad_unreg_agent(struct ib_umad_file *file, u32 __user *arg)
+ 	file->agent[id] = NULL;
+ 
+ out:
+-	up_write(&file->port->mutex);
++	mutex_unlock(&file->mutex);
+ 
+ 	if (agent)
+ 		ib_unregister_mad_agent(agent);
+ 
++	mutex_unlock(&file->port->file_mutex);
++
+ 	return ret;
  }
  
--static void hpt37x_set_mode(ide_drive_t *drive, const u8 speed)
--{
--	ide_hwif_t *hwif	= HWIF(drive);
--	struct pci_dev  *dev	= hwif->pci_dev;
--	struct hpt_info	*info	= pci_get_drvdata(dev);
--	u8  itr_addr		= 0x40 + (drive->dn * 4);
--	u32 old_itr		= 0;
--	u32 itr_mask, new_itr;
--
--	itr_mask = speed < XFER_MW_DMA_0 ? 0x303c0000 :
--		  (speed < XFER_UDMA_0   ? 0xc03c0000 : 0xc1c001ff);
--
--	new_itr = get_speed_setting(speed, info);
--
--	pci_read_config_dword(dev, itr_addr, &old_itr);
--	new_itr = (new_itr & ~itr_mask) | (old_itr & itr_mask);
--	
--	if (speed < XFER_MW_DMA_0)
--		new_itr &= ~0x80000000; /* Disable on-chip PIO FIFO/buffer */
--	pci_write_config_dword(dev, itr_addr, new_itr);
--}
--
--static void hpt3xx_set_mode(ide_drive_t *drive, const u8 speed)
--{
--	ide_hwif_t *hwif	= HWIF(drive);
--	struct hpt_info	*info	= pci_get_drvdata(hwif->pci_dev);
--
--	if (info->chip_type >= HPT370)
--		hpt37x_set_mode(drive, speed);
--	else	/* hpt368: hpt_minimum_revision(dev, 2) */
--		hpt36x_set_mode(drive, speed);
--}
--
- static void hpt3xx_set_pio_mode(ide_drive_t *drive, const u8 pio)
+@@ -726,12 +735,12 @@ static long ib_umad_enable_pkey(struct ib_umad_file *file)
  {
- 	hpt3xx_set_mode(drive, XFER_PIO_0 + pio);
+ 	int ret = 0;
+ 
+-	down_write(&file->port->mutex);
++	mutex_lock(&file->mutex);
+ 	if (file->already_used)
+ 		ret = -EINVAL;
+ 	else
+ 		file->use_pkey_index = 1;
+-	up_write(&file->port->mutex);
++	mutex_unlock(&file->mutex);
+ 
+ 	return ret;
  }
+@@ -783,7 +792,7 @@ static int ib_umad_open(struct inode *inode, struct file *filp)
+ 	if (!port)
+ 		return -ENXIO;
  
--static int hpt3xx_quirkproc(ide_drive_t *drive)
-+static void hpt3xx_quirkproc(ide_drive_t *drive)
- {
- 	struct hd_driveid *id	= drive->id;
- 	const  char **list	= quirk_drives;
+-	down_write(&port->mutex);
++	mutex_lock(&port->file_mutex);
  
- 	while (*list)
--		if (strstr(id->model, *list++))
--			return 1;
--	return 0;
--}
--
--static void hpt3xx_intrproc(ide_drive_t *drive)
--{
--	if (drive->quirk_list)
--		return;
-+		if (strstr(id->model, *list++)) {
-+			drive->quirk_list = 1;
-+			return;
-+		}
+ 	if (!port->ib_dev) {
+ 		ret = -ENXIO;
+@@ -797,7 +806,7 @@ static int ib_umad_open(struct inode *inode, struct file *filp)
+ 		goto out;
+ 	}
  
--	/* drives in the quirk_list may not like intr setups/cleanups */
--	outb(drive->ctl | 2, IDE_CONTROL_REG);
-+	drive->quirk_list = 0;
+-	spin_lock_init(&file->recv_lock);
++	mutex_init(&file->mutex);
+ 	spin_lock_init(&file->send_lock);
+ 	INIT_LIST_HEAD(&file->recv_list);
+ 	INIT_LIST_HEAD(&file->send_list);
+@@ -809,7 +818,7 @@ static int ib_umad_open(struct inode *inode, struct file *filp)
+ 	list_add_tail(&file->port_list, &port->file_list);
+ 
+ out:
+-	up_write(&port->mutex);
++	mutex_unlock(&port->file_mutex);
+ 	return ret;
  }
  
- static void hpt3xx_maskproc(ide_drive_t *drive, int mask)
-@@ -914,32 +888,33 @@ static int hpt374_ide_dma_end(ide_drive_t *drive)
+@@ -821,7 +830,8 @@ static int ib_umad_close(struct inode *inode, struct file *filp)
+ 	int already_dead;
+ 	int i;
  
- static void hpt3xxn_set_clock(ide_hwif_t *hwif, u8 mode)
- {
--	u8 scr2 = inb(hwif->dma_master + 0x7b);
-+	unsigned long base = hwif->extra_base;
-+	u8 scr2 = inb(base + 0x6b);
+-	down_write(&file->port->mutex);
++	mutex_lock(&file->port->file_mutex);
++	mutex_lock(&file->mutex);
  
- 	if ((scr2 & 0x7f) == mode)
- 		return;
+ 	already_dead = file->agents_dead;
+ 	file->agents_dead = 1;
+@@ -834,14 +844,14 @@ static int ib_umad_close(struct inode *inode, struct file *filp)
  
- 	/* Tristate the bus */
--	outb(0x80, hwif->dma_master + 0x73);
--	outb(0x80, hwif->dma_master + 0x77);
-+	outb(0x80, base + 0x63);
-+	outb(0x80, base + 0x67);
+ 	list_del(&file->port_list);
  
- 	/* Switch clock and reset channels */
--	outb(mode, hwif->dma_master + 0x7b);
--	outb(0xc0, hwif->dma_master + 0x79);
-+	outb(mode, base + 0x6b);
-+	outb(0xc0, base + 0x69);
+-	downgrade_write(&file->port->mutex);
++	mutex_unlock(&file->mutex);
  
- 	/*
- 	 * Reset the state machines.
- 	 * NOTE: avoid accidentally enabling the disabled channels.
- 	 */
--	outb(inb(hwif->dma_master + 0x70) | 0x32, hwif->dma_master + 0x70);
--	outb(inb(hwif->dma_master + 0x74) | 0x32, hwif->dma_master + 0x74);
-+	outb(inb(base + 0x60) | 0x32, base + 0x60);
-+	outb(inb(base + 0x64) | 0x32, base + 0x64);
+ 	if (!already_dead)
+ 		for (i = 0; i < IB_UMAD_MAX_AGENTS; ++i)
+ 			if (file->agent[i])
+ 				ib_unregister_mad_agent(file->agent[i]);
  
- 	/* Complete reset */
--	outb(0x00, hwif->dma_master + 0x79);
-+	outb(0x00, base + 0x69);
+-	up_read(&file->port->mutex);
++	mutex_unlock(&file->port->file_mutex);
  
- 	/* Reconnect channels to bus */
--	outb(0x00, hwif->dma_master + 0x73);
--	outb(0x00, hwif->dma_master + 0x77);
-+	outb(0x00, base + 0x63);
-+	outb(0x00, base + 0x67);
- }
+ 	kfree(file);
+ 	kref_put(&dev->ref, ib_umad_release_dev);
+@@ -914,10 +924,10 @@ static int ib_umad_sm_close(struct inode *inode, struct file *filp)
+ 	};
+ 	int ret = 0;
  
- /**
-@@ -1210,7 +1185,7 @@ static unsigned int __devinit init_chipset_hpt366(struct pci_dev *dev, const cha
- 	 * We also  don't like using  the DPLL because this causes glitches
- 	 * on PRST-/SRST- when the state engine gets reset...
- 	 */
--	if (chip_type >= HPT374 || info->settings[clock] == NULL) {
-+	if (chip_type >= HPT374 || info->timings->clock_table[clock] == NULL) {
- 		u16 f_low, delta = pci_clk < 50 ? 2 : 4;
- 		int adjust;
+-	down_write(&port->mutex);
++	mutex_lock(&port->file_mutex);
+ 	if (port->ib_dev)
+ 		ret = ib_modify_port(port->ib_dev, port->port_num, 0, &props);
+-	up_write(&port->mutex);
++	mutex_unlock(&port->file_mutex);
  
-@@ -1226,7 +1201,7 @@ static unsigned int __devinit init_chipset_hpt366(struct pci_dev *dev, const cha
- 			clock = ATA_CLOCK_50MHZ;
- 		}
+ 	up(&port->sm_sem);
  
--		if (info->settings[clock] == NULL) {
-+		if (info->timings->clock_table[clock] == NULL) {
- 			printk(KERN_ERR "%s: unknown bus timing!\n", name);
- 			kfree(info);
- 			return -EIO;
-@@ -1267,15 +1242,10 @@ static unsigned int __devinit init_chipset_hpt366(struct pci_dev *dev, const cha
- 		printk("%s: using %d MHz PCI clock\n", name, pci_clk);
- 	}
+@@ -981,7 +991,7 @@ static int ib_umad_init_port(struct ib_device *device, int port_num,
+ 	port->ib_dev   = device;
+ 	port->port_num = port_num;
+ 	init_MUTEX(&port->sm_sem);
+-	init_rwsem(&port->mutex);
++	mutex_init(&port->file_mutex);
+ 	INIT_LIST_HEAD(&port->file_list);
+ 
+ 	port->dev = cdev_alloc();
+@@ -1052,6 +1062,7 @@ err_cdev:
+ static void ib_umad_kill_port(struct ib_umad_port *port)
+ {
+ 	struct ib_umad_file *file;
++	int already_dead;
+ 	int id;
+ 
+ 	class_set_devdata(port->class_dev,    NULL);
+@@ -1067,42 +1078,22 @@ static void ib_umad_kill_port(struct ib_umad_port *port)
+ 	umad_port[port->dev_num] = NULL;
+ 	spin_unlock(&port_lock);
+ 
+-	down_write(&port->mutex);
++	mutex_lock(&port->file_mutex);
+ 
+ 	port->ib_dev = NULL;
  
 -	/*
--	 * Advance the table pointer to a slot which points to the list
--	 * of the register values settings matching the clock being used.
+-	 * Now go through the list of files attached to this port and
+-	 * unregister all of their MAD agents.  We need to hold
+-	 * port->mutex while doing this to avoid racing with
+-	 * ib_umad_close(), but we can't hold the mutex for writing
+-	 * while calling ib_unregister_mad_agent(), since that might
+-	 * deadlock by calling back into queue_packet().  So we
+-	 * downgrade our lock to a read lock, and then drop and
+-	 * reacquire the write lock for the next iteration.
+-	 *
+-	 * We do list_del_init() on the file's list_head so that the
+-	 * list_del in ib_umad_close() is still OK, even after the
+-	 * file is removed from the list.
 -	 */
--	info->settings += clock;
+-	while (!list_empty(&port->file_list)) {
+-		file = list_entry(port->file_list.next, struct ib_umad_file,
+-				  port_list);
 -
- 	/* Store the clock frequencies. */
- 	info->dpll_clk	= dpll_clk;
- 	info->pci_clk	= pci_clk;
-+	info->clock	= clock;
++	list_for_each_entry(file, &port->file_list, port_list) {
++		mutex_lock(&file->mutex);
++		already_dead = file->agents_dead;
+ 		file->agents_dead = 1;
+-		list_del_init(&file->port_list);
+-
+-		downgrade_write(&port->mutex);
++		mutex_unlock(&file->mutex);
  
- 	/* Point to this chip's own instance of the hpt_info structure. */
- 	pci_set_drvdata(dev, info);
-@@ -1320,8 +1290,8 @@ static void __devinit init_hwif_hpt366(ide_hwif_t *hwif)
+ 		for (id = 0; id < IB_UMAD_MAX_AGENTS; ++id)
+ 			if (file->agent[id])
+ 				ib_unregister_mad_agent(file->agent[id]);
+-
+-		up_read(&port->mutex);
+-		down_write(&port->mutex);
+ 	}
  
- 	hwif->set_pio_mode	= &hpt3xx_set_pio_mode;
- 	hwif->set_dma_mode	= &hpt3xx_set_mode;
-+
- 	hwif->quirkproc		= &hpt3xx_quirkproc;
--	hwif->intrproc		= &hpt3xx_intrproc;
- 	hwif->maskproc		= &hpt3xx_maskproc;
- 	hwif->busproc		= &hpt3xx_busproc;
+-	up_write(&port->mutex);
++	mutex_unlock(&port->file_mutex);
  
-@@ -1494,6 +1464,11 @@ static int __devinit hpt36x_init(struct pci_dev *dev, struct pci_dev *dev2)
- 	return 0;
+ 	clear_bit(port->dev_num, dev_map);
  }
+diff --git a/drivers/infiniband/hw/cxgb3/cxio_hal.c b/drivers/infiniband/hw/cxgb3/cxio_hal.c
+index eec6a30..03c5ff6 100644
+--- a/drivers/infiniband/hw/cxgb3/cxio_hal.c
++++ b/drivers/infiniband/hw/cxgb3/cxio_hal.c
+@@ -179,7 +179,7 @@ int cxio_create_cq(struct cxio_rdev *rdev_p, struct t3_cq *cq)
+ 	setup.size = 1UL << cq->size_log2;
+ 	setup.credits = 65535;
+ 	setup.credit_thres = 1;
+-	if (rdev_p->t3cdev_p->type == T3B)
++	if (rdev_p->t3cdev_p->type != T3A)
+ 		setup.ovfl_mode = 0;
+ 	else
+ 		setup.ovfl_mode = 1;
+@@ -584,7 +584,7 @@ static int cxio_hal_ctrl_qp_write_mem(struct cxio_rdev *rdev_p, u32 addr,
+ {
+ 	u32 i, nr_wqe, copy_len;
+ 	u8 *copy_data;
+-	u8 wr_len, utx_len;	/* lenght in 8 byte flit */
++	u8 wr_len, utx_len;	/* length in 8 byte flit */
+ 	enum t3_wr_flags flag;
+ 	__be64 *wqe;
+ 	u64 utx_cmd;
+diff --git a/drivers/infiniband/hw/cxgb3/cxio_wr.h b/drivers/infiniband/hw/cxgb3/cxio_wr.h
+index c84d4ac..969d4d9 100644
+--- a/drivers/infiniband/hw/cxgb3/cxio_wr.h
++++ b/drivers/infiniband/hw/cxgb3/cxio_wr.h
+@@ -315,7 +315,7 @@ struct t3_rdma_init_wr {
+ 	__be32 ird;
+ 	__be64 qp_dma_addr;	/* 7 */
+ 	__be32 qp_dma_size;	/* 8 */
+-	u32 irs;
++	__be32 irs;
+ };
  
-+#define IDE_HFLAGS_HPT3XX \
-+	(IDE_HFLAG_NO_ATAPI_DMA | \
-+	 IDE_HFLAG_ABUSE_SET_DMA_MODE | \
-+	 IDE_HFLAG_OFF_BOARD)
-+
- static const struct ide_port_info hpt366_chipsets[] __devinitdata = {
- 	{	/* 0 */
- 		.name		= "HPT36x",
-@@ -1508,9 +1483,7 @@ static const struct ide_port_info hpt366_chipsets[] __devinitdata = {
- 		 */
- 		.enablebits	= {{0x50,0x10,0x10}, {0x54,0x04,0x04}},
- 		.extra		= 240,
--		.host_flags	= IDE_HFLAG_SINGLE |
--				  IDE_HFLAG_NO_ATAPI_DMA |
--				  IDE_HFLAG_OFF_BOARD,
-+		.host_flags	= IDE_HFLAGS_HPT3XX | IDE_HFLAG_SINGLE,
- 		.pio_mask	= ATA_PIO4,
- 		.mwdma_mask	= ATA_MWDMA2,
- 	},{	/* 1 */
-@@ -1520,7 +1493,7 @@ static const struct ide_port_info hpt366_chipsets[] __devinitdata = {
- 		.init_dma	= init_dma_hpt366,
- 		.enablebits	= {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
- 		.extra		= 240,
--		.host_flags	= IDE_HFLAG_NO_ATAPI_DMA | IDE_HFLAG_OFF_BOARD,
-+		.host_flags	= IDE_HFLAGS_HPT3XX,
- 		.pio_mask	= ATA_PIO4,
- 		.mwdma_mask	= ATA_MWDMA2,
- 	},{	/* 2 */
-@@ -1530,7 +1503,7 @@ static const struct ide_port_info hpt366_chipsets[] __devinitdata = {
- 		.init_dma	= init_dma_hpt366,
- 		.enablebits	= {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
- 		.extra		= 240,
--		.host_flags	= IDE_HFLAG_NO_ATAPI_DMA | IDE_HFLAG_OFF_BOARD,
-+		.host_flags	= IDE_HFLAGS_HPT3XX,
- 		.pio_mask	= ATA_PIO4,
- 		.mwdma_mask	= ATA_MWDMA2,
- 	},{	/* 3 */
-@@ -1540,7 +1513,7 @@ static const struct ide_port_info hpt366_chipsets[] __devinitdata = {
- 		.init_dma	= init_dma_hpt366,
- 		.enablebits	= {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
- 		.extra		= 240,
--		.host_flags	= IDE_HFLAG_NO_ATAPI_DMA | IDE_HFLAG_OFF_BOARD,
-+		.host_flags	= IDE_HFLAGS_HPT3XX,
- 		.pio_mask	= ATA_PIO4,
- 		.mwdma_mask	= ATA_MWDMA2,
- 	},{	/* 4 */
-@@ -1551,7 +1524,7 @@ static const struct ide_port_info hpt366_chipsets[] __devinitdata = {
- 		.enablebits	= {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
- 		.udma_mask	= ATA_UDMA5,
- 		.extra		= 240,
--		.host_flags	= IDE_HFLAG_NO_ATAPI_DMA | IDE_HFLAG_OFF_BOARD,
-+		.host_flags	= IDE_HFLAGS_HPT3XX,
- 		.pio_mask	= ATA_PIO4,
- 		.mwdma_mask	= ATA_MWDMA2,
- 	},{	/* 5 */
-@@ -1561,7 +1534,7 @@ static const struct ide_port_info hpt366_chipsets[] __devinitdata = {
- 		.init_dma	= init_dma_hpt366,
- 		.enablebits	= {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
- 		.extra		= 240,
--		.host_flags	= IDE_HFLAG_NO_ATAPI_DMA | IDE_HFLAG_OFF_BOARD,
-+		.host_flags	= IDE_HFLAGS_HPT3XX,
- 		.pio_mask	= ATA_PIO4,
- 		.mwdma_mask	= ATA_MWDMA2,
+ struct t3_genbit {
+@@ -324,7 +324,8 @@ struct t3_genbit {
+ };
+ 
+ enum rdma_init_wr_flags {
+-	RECVS_POSTED = 1,
++	RECVS_POSTED = (1<<0),
++	PRIV_QP = (1<<1),
+ };
+ 
+ union t3_wr {
+diff --git a/drivers/infiniband/hw/cxgb3/iwch_cm.c b/drivers/infiniband/hw/cxgb3/iwch_cm.c
+index 20ba372..f8cb0fe 100644
+--- a/drivers/infiniband/hw/cxgb3/iwch_cm.c
++++ b/drivers/infiniband/hw/cxgb3/iwch_cm.c
+@@ -1118,7 +1118,7 @@ static int act_open_rpl(struct t3cdev *tdev, struct sk_buff *skb, void *ctx)
+ 	     status2errno(rpl->status));
+ 	connect_reply_upcall(ep, status2errno(rpl->status));
+ 	state_set(&ep->com, DEAD);
+-	if (ep->com.tdev->type == T3B && act_open_has_tid(rpl->status))
++	if (ep->com.tdev->type != T3A && act_open_has_tid(rpl->status))
+ 		release_tid(ep->com.tdev, GET_TID(rpl), NULL);
+ 	cxgb3_free_atid(ep->com.tdev, ep->atid);
+ 	dst_release(ep->dst);
+@@ -1249,7 +1249,7 @@ static void reject_cr(struct t3cdev *tdev, u32 hwtid, __be32 peer_ip,
+ 	skb_trim(skb, sizeof(struct cpl_tid_release));
+ 	skb_get(skb);
+ 
+-	if (tdev->type == T3B)
++	if (tdev->type != T3A)
+ 		release_tid(tdev, hwtid, skb);
+ 	else {
+ 		struct cpl_pass_accept_rpl *rpl;
+diff --git a/drivers/infiniband/hw/cxgb3/iwch_mem.c b/drivers/infiniband/hw/cxgb3/iwch_mem.c
+index a6c2c4b..73bfd16 100644
+--- a/drivers/infiniband/hw/cxgb3/iwch_mem.c
++++ b/drivers/infiniband/hw/cxgb3/iwch_mem.c
+@@ -122,6 +122,13 @@ int build_phys_page_list(struct ib_phys_buf *buffer_list,
+ 		*total_size += buffer_list[i].size;
+ 		if (i > 0)
+ 			mask |= buffer_list[i].addr;
++		else
++			mask |= buffer_list[i].addr & PAGE_MASK;
++		if (i != num_phys_buf - 1)
++			mask |= buffer_list[i].addr + buffer_list[i].size;
++		else
++			mask |= (buffer_list[i].addr + buffer_list[i].size +
++				PAGE_SIZE - 1) & PAGE_MASK;
  	}
-diff --git a/drivers/ide/pci/it8213.c b/drivers/ide/pci/it8213.c
-index 90b52ed..2a0f45c 100644
---- a/drivers/ide/pci/it8213.c
-+++ b/drivers/ide/pci/it8213.c
-@@ -101,24 +101,11 @@ static void it8213_set_dma_mode(ide_drive_t *drive, const u8 speed)
- 	pci_read_config_byte(dev, 0x54, &reg54);
- 	pci_read_config_byte(dev, 0x55, &reg55);
  
--	switch(speed) {
--		case XFER_UDMA_6:
--		case XFER_UDMA_4:
--		case XFER_UDMA_2:	u_speed = 2 << (drive->dn * 4); break;
--		case XFER_UDMA_5:
--		case XFER_UDMA_3:
--		case XFER_UDMA_1:	u_speed = 1 << (drive->dn * 4); break;
--		case XFER_UDMA_0:	u_speed = 0 << (drive->dn * 4); break;
--			break;
--		case XFER_MW_DMA_2:
--		case XFER_MW_DMA_1:
--		case XFER_SW_DMA_2:
--			break;
--		default:
--			return;
--	}
--
- 	if (speed >= XFER_UDMA_0) {
-+		u8 udma = speed - XFER_UDMA_0;
-+
-+		u_speed = min_t(u8, 2 - (udma & 1), udma) << (drive->dn * 4);
-+
- 		if (!(reg48 & u_flag))
- 			pci_write_config_byte(dev, 0x48, reg48 | u_flag);
- 		if (speed >= XFER_UDMA_5) {
-diff --git a/drivers/ide/pci/it821x.c b/drivers/ide/pci/it821x.c
-index 99b7d76..e610a53 100644
---- a/drivers/ide/pci/it821x.c
-+++ b/drivers/ide/pci/it821x.c
-@@ -431,33 +431,29 @@ static u8 __devinit ata66_it821x(ide_hwif_t *hwif)
- }
+ 	if (*total_size > 0xFFFFFFFFULL)
+diff --git a/drivers/infiniband/hw/cxgb3/iwch_provider.c b/drivers/infiniband/hw/cxgb3/iwch_provider.c
+index b5436ca..df1838f 100644
+--- a/drivers/infiniband/hw/cxgb3/iwch_provider.c
++++ b/drivers/infiniband/hw/cxgb3/iwch_provider.c
+@@ -39,6 +39,7 @@
+ #include <linux/list.h>
+ #include <linux/spinlock.h>
+ #include <linux/ethtool.h>
++#include <linux/rtnetlink.h>
  
- /**
-- *	it821x_fixup	-	post init callback
-- *	@hwif: interface
-+ *	it821x_quirkproc	-	post init callback
-+ *	@drive: drive
-  *
-- *	This callback is run after the drives have been probed but
-+ *	This callback is run after the drive has been probed but
-  *	before anything gets attached. It allows drivers to do any
-  *	final tuning that is needed, or fixups to work around bugs.
-  */
+ #include <asm/io.h>
+ #include <asm/irq.h>
+@@ -645,7 +646,7 @@ static struct ib_mr *iwch_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
+ 	if (err)
+ 		goto err;
  
--static void __devinit it821x_fixups(ide_hwif_t *hwif)
-+static void __devinit it821x_quirkproc(ide_drive_t *drive)
- {
--	struct it821x_dev *itdev = ide_get_hwifdata(hwif);
--	int i;
-+	struct it821x_dev *itdev = ide_get_hwifdata(drive->hwif);
-+	struct hd_driveid *id = drive->id;
-+	u16 *idbits = (u16 *)drive->id;
+-	if (udata && t3b_device(rhp)) {
++	if (udata && !t3a_device(rhp)) {
+ 		uresp.pbl_addr = (mhp->attr.pbl_addr -
+ 	                         rhp->rdev.rnic_info.pbl_base) >> 3;
+ 		PDBG("%s user resp pbl_addr 0x%x\n", __FUNCTION__,
+@@ -1053,7 +1054,9 @@ static ssize_t show_fw_ver(struct class_device *cdev, char *buf)
+ 	struct net_device *lldev = dev->rdev.t3cdev_p->lldev;
  
--	if(!itdev->smart) {
-+	if (!itdev->smart) {
- 		/*
- 		 *	If we are in pass through mode then not much
- 		 *	needs to be done, but we do bother to clear the
- 		 *	IRQ mask as we may well be in PIO (eg rev 0x10)
- 		 *	for now and we know unmasking is safe on this chipset.
- 		 */
--		for (i = 0; i < 2; i++) {
--			ide_drive_t *drive = &hwif->drives[i];
--			if(drive->present)
--				drive->unmask = 1;
--		}
--		return;
--	}
-+		drive->unmask = 1;
-+	} else {
- 	/*
- 	 *	Perform fixups on smart mode. We need to "lose" some
- 	 *	capabilities the firmware lacks but does not filter, and
-@@ -465,16 +461,6 @@ static void __devinit it821x_fixups(ide_hwif_t *hwif)
- 	 *	in RAID mode.
- 	 */
+ 	PDBG("%s class dev 0x%p\n", __FUNCTION__, cdev);
++	rtnl_lock();
+ 	lldev->ethtool_ops->get_drvinfo(lldev, &info);
++	rtnl_unlock();
+ 	return sprintf(buf, "%s\n", info.fw_version);
+ }
  
--	for(i = 0; i < 2; i++) {
--		ide_drive_t *drive = &hwif->drives[i];
--		struct hd_driveid *id;
--		u16 *idbits;
+@@ -1065,7 +1068,9 @@ static ssize_t show_hca(struct class_device *cdev, char *buf)
+ 	struct net_device *lldev = dev->rdev.t3cdev_p->lldev;
+ 
+ 	PDBG("%s class dev 0x%p\n", __FUNCTION__, cdev);
++	rtnl_lock();
+ 	lldev->ethtool_ops->get_drvinfo(lldev, &info);
++	rtnl_unlock();
+ 	return sprintf(buf, "%s\n", info.driver);
+ }
+ 
+diff --git a/drivers/infiniband/hw/cxgb3/iwch_qp.c b/drivers/infiniband/hw/cxgb3/iwch_qp.c
+index dd89b6b..ea2cdd7 100644
+--- a/drivers/infiniband/hw/cxgb3/iwch_qp.c
++++ b/drivers/infiniband/hw/cxgb3/iwch_qp.c
+@@ -208,36 +208,19 @@ static int iwch_sgl2pbl_map(struct iwch_dev *rhp, struct ib_sge *sg_list,
+ static int iwch_build_rdma_recv(struct iwch_dev *rhp, union t3_wr *wqe,
+ 				struct ib_recv_wr *wr)
+ {
+-	int i, err = 0;
+-	u32 pbl_addr[4];
+-	u8 page_size[4];
++	int i;
+ 	if (wr->num_sge > T3_MAX_SGE)
+ 		return -EINVAL;
+-	err = iwch_sgl2pbl_map(rhp, wr->sg_list, wr->num_sge, pbl_addr,
+-			       page_size);
+-	if (err)
+-		return err;
+-	wqe->recv.pagesz[0] = page_size[0];
+-	wqe->recv.pagesz[1] = page_size[1];
+-	wqe->recv.pagesz[2] = page_size[2];
+-	wqe->recv.pagesz[3] = page_size[3];
+ 	wqe->recv.num_sgle = cpu_to_be32(wr->num_sge);
+ 	for (i = 0; i < wr->num_sge; i++) {
+ 		wqe->recv.sgl[i].stag = cpu_to_be32(wr->sg_list[i].lkey);
+ 		wqe->recv.sgl[i].len = cpu_to_be32(wr->sg_list[i].length);
 -
--		if(!drive->present)
--			continue;
--		id = drive->id;
--		idbits = (u16 *)drive->id;
+-		/* to in the WQE == the offset into the page */
+-		wqe->recv.sgl[i].to = cpu_to_be64(((u32) wr->sg_list[i].addr) %
+-				(1UL << (12 + page_size[i])));
 -
- 		/* Check for RAID v native */
- 		if(strstr(id->model, "Integrated Technology Express")) {
- 			/* In raid mode the ident block is slightly buggy
-@@ -537,6 +523,8 @@ static void __devinit init_hwif_it821x(ide_hwif_t *hwif)
- 	struct it821x_dev *idev = kzalloc(sizeof(struct it821x_dev), GFP_KERNEL);
- 	u8 conf;
- 
-+	hwif->quirkproc = &it821x_quirkproc;
-+
- 	if (idev == NULL) {
- 		printk(KERN_ERR "it821x: out of memory, falling back to legacy behaviour.\n");
- 		return;
-@@ -633,7 +621,6 @@ static unsigned int __devinit init_chipset_it821x(struct pci_dev *dev, const cha
- 		.name		= name_str,		\
- 		.init_chipset	= init_chipset_it821x,	\
- 		.init_hwif	= init_hwif_it821x,	\
--		.fixup	 	= it821x_fixups,	\
- 		.host_flags	= IDE_HFLAG_BOOTABLE,	\
- 		.pio_mask	= ATA_PIO4,		\
+-		/* pbl_addr is the adapters address in the PBL */
+-		wqe->recv.pbl_addr[i] = cpu_to_be32(pbl_addr[i]);
++		wqe->recv.sgl[i].to = cpu_to_be64(wr->sg_list[i].addr);
  	}
-diff --git a/drivers/ide/pci/pdc202xx_new.c b/drivers/ide/pci/pdc202xx_new.c
-index 2b4f44e..89d2363 100644
---- a/drivers/ide/pci/pdc202xx_new.c
-+++ b/drivers/ide/pci/pdc202xx_new.c
-@@ -146,7 +146,7 @@ static struct udma_timing {
- 	{ 0x1a, 0x01, 0xcb },	/* UDMA mode 6 */
- };
+ 	for (; i < T3_MAX_SGE; i++) {
+ 		wqe->recv.sgl[i].stag = 0;
+ 		wqe->recv.sgl[i].len = 0;
+ 		wqe->recv.sgl[i].to = 0;
+-		wqe->recv.pbl_addr[i] = 0;
+ 	}
+ 	return 0;
+ }
+@@ -659,6 +642,7 @@ static void __flush_qp(struct iwch_qp *qhp, unsigned long *flag)
+ 	cxio_flush_rq(&qhp->wq, &rchp->cq, count);
+ 	spin_unlock(&qhp->lock);
+ 	spin_unlock_irqrestore(&rchp->lock, *flag);
++	(*rchp->ibcq.comp_handler)(&rchp->ibcq, rchp->ibcq.cq_context);
  
--static void pdcnew_set_mode(ide_drive_t *drive, const u8 speed)
-+static void pdcnew_set_dma_mode(ide_drive_t *drive, const u8 speed)
- {
- 	ide_hwif_t *hwif	= HWIF(drive);
- 	u8 adj			= (drive->dn & 1) ? 0x08 : 0x00;
-@@ -162,45 +162,18 @@ static void pdcnew_set_mode(ide_drive_t *drive, const u8 speed)
- 	if (max_dma_rate(hwif->pci_dev) == 4) {
- 		u8 mode = speed & 0x07;
+ 	/* locking heirarchy: cq lock first, then qp lock. */
+ 	spin_lock_irqsave(&schp->lock, *flag);
+@@ -668,6 +652,7 @@ static void __flush_qp(struct iwch_qp *qhp, unsigned long *flag)
+ 	cxio_flush_sq(&qhp->wq, &schp->cq, count);
+ 	spin_unlock(&qhp->lock);
+ 	spin_unlock_irqrestore(&schp->lock, *flag);
++	(*schp->ibcq.comp_handler)(&schp->ibcq, schp->ibcq.cq_context);
  
--		switch (speed) {
--			case XFER_UDMA_6:
--			case XFER_UDMA_5:
--			case XFER_UDMA_4:
--			case XFER_UDMA_3:
--			case XFER_UDMA_2:
--			case XFER_UDMA_1:
--			case XFER_UDMA_0:
--				set_indexed_reg(hwif, 0x10 + adj,
--						udma_timings[mode].reg10);
--				set_indexed_reg(hwif, 0x11 + adj,
--						udma_timings[mode].reg11);
--				set_indexed_reg(hwif, 0x12 + adj,
--						udma_timings[mode].reg12);
--				break;
--
--			case XFER_MW_DMA_2:
--			case XFER_MW_DMA_1:
--			case XFER_MW_DMA_0:
--				set_indexed_reg(hwif, 0x0e + adj,
--						mwdma_timings[mode].reg0e);
--				set_indexed_reg(hwif, 0x0f + adj,
--						mwdma_timings[mode].reg0f);
--				break;
--			case XFER_PIO_4:
--			case XFER_PIO_3:
--			case XFER_PIO_2:
--			case XFER_PIO_1:
--			case XFER_PIO_0:
--				set_indexed_reg(hwif, 0x0c + adj,
--						pio_timings[mode].reg0c);
--				set_indexed_reg(hwif, 0x0d + adj,
--						pio_timings[mode].reg0d);
--				set_indexed_reg(hwif, 0x13 + adj,
--						pio_timings[mode].reg13);
--				break;
--			default:
--				printk(KERN_ERR "pdc202xx_new: "
--				       "Unknown speed %d ignored\n", speed);
-+		if (speed >= XFER_UDMA_0) {
-+			set_indexed_reg(hwif, 0x10 + adj,
-+					udma_timings[mode].reg10);
-+			set_indexed_reg(hwif, 0x11 + adj,
-+					udma_timings[mode].reg11);
-+			set_indexed_reg(hwif, 0x12 + adj,
-+					udma_timings[mode].reg12);
-+		} else {
-+			set_indexed_reg(hwif, 0x0e + adj,
-+					mwdma_timings[mode].reg0e);
-+			set_indexed_reg(hwif, 0x0f + adj,
-+					mwdma_timings[mode].reg0f);
- 		}
- 	} else if (speed == XFER_UDMA_2) {
- 		/* Set tHOLD bit to 0 if using UDMA mode 2 */
-@@ -212,7 +185,14 @@ static void pdcnew_set_mode(ide_drive_t *drive, const u8 speed)
+ 	/* deref */
+ 	if (atomic_dec_and_test(&qhp->refcnt))
+@@ -678,7 +663,7 @@ static void __flush_qp(struct iwch_qp *qhp, unsigned long *flag)
+ 
+ static void flush_qp(struct iwch_qp *qhp, unsigned long *flag)
+ {
+-	if (t3b_device(qhp->rhp))
++	if (qhp->ibqp.uobject)
+ 		cxio_set_wq_in_error(&qhp->wq);
+ 	else
+ 		__flush_qp(qhp, flag);
+@@ -732,6 +717,7 @@ static int rdma_init(struct iwch_dev *rhp, struct iwch_qp *qhp,
+ 	init_attr.qp_dma_addr = qhp->wq.dma_addr;
+ 	init_attr.qp_dma_size = (1UL << qhp->wq.size_log2);
+ 	init_attr.flags = rqes_posted(qhp) ? RECVS_POSTED : 0;
++	init_attr.flags |= capable(CAP_NET_BIND_SERVICE) ? PRIV_QP : 0;
+ 	init_attr.irs = qhp->ep->rcv_seq;
+ 	PDBG("%s init_attr.rq_addr 0x%x init_attr.rq_size = %d "
+ 	     "flags 0x%x qpcaps 0x%x\n", __FUNCTION__,
+@@ -847,10 +833,11 @@ int iwch_modify_qp(struct iwch_dev *rhp, struct iwch_qp *qhp,
+ 				disconnect = 1;
+ 				ep = qhp->ep;
+ 			}
++			flush_qp(qhp, &flag);
+ 			break;
+ 		case IWCH_QP_STATE_TERMINATE:
+ 			qhp->attr.state = IWCH_QP_STATE_TERMINATE;
+-			if (t3b_device(qhp->rhp))
++			if (qhp->ibqp.uobject)
+ 				cxio_set_wq_in_error(&qhp->wq);
+ 			if (!internal)
+ 				terminate = 1;
+diff --git a/drivers/infiniband/hw/ehca/ehca_av.c b/drivers/infiniband/hw/ehca/ehca_av.c
+index f7782c8..194c1c3 100644
+--- a/drivers/infiniband/hw/ehca/ehca_av.c
++++ b/drivers/infiniband/hw/ehca/ehca_av.c
+@@ -1,7 +1,7 @@
+ /*
+  *  IBM eServer eHCA Infiniband device driver for Linux on POWER
+  *
+- *  adress vector functions
++ *  address vector functions
+  *
+  *  Authors: Hoang-Nam Nguyen <hnguyen at de.ibm.com>
+  *           Khadija Souissi <souissik at de.ibm.com>
+diff --git a/drivers/infiniband/hw/ehca/ehca_classes.h b/drivers/infiniband/hw/ehca/ehca_classes.h
+index 74d2b72..f281d16 100644
+--- a/drivers/infiniband/hw/ehca/ehca_classes.h
++++ b/drivers/infiniband/hw/ehca/ehca_classes.h
+@@ -94,7 +94,11 @@ struct ehca_sma_attr {
  
- static void pdcnew_set_pio_mode(ide_drive_t *drive, const u8 pio)
- {
--	pdcnew_set_mode(drive, XFER_PIO_0 + pio);
-+	ide_hwif_t *hwif = drive->hwif;
-+	u8 adj = (drive->dn & 1) ? 0x08 : 0x00;
+ struct ehca_sport {
+ 	struct ib_cq *ibcq_aqp1;
+-	struct ib_qp *ibqp_aqp1;
++	struct ib_qp *ibqp_sqp[2];
++	/* lock to serialze modify_qp() calls for sqp in normal
++	 * and irq path (when event PORT_ACTIVE is received first time)
++	 */
++	spinlock_t mod_sqp_lock;
+ 	enum ib_port_state port_state;
+ 	struct ehca_sma_attr saved_attr;
+ };
+@@ -141,6 +145,14 @@ enum ehca_ext_qp_type {
+ 	EQPT_SRQ       = 3,
+ };
+ 
++/* struct to cache modify_qp()'s parms for GSI/SMI qp */
++struct ehca_mod_qp_parm {
++	int mask;
++	struct ib_qp_attr attr;
++};
 +
-+	if (max_dma_rate(hwif->pci_dev) == 4) {
-+		set_indexed_reg(hwif, 0x0c + adj, pio_timings[pio].reg0c);
-+		set_indexed_reg(hwif, 0x0d + adj, pio_timings[pio].reg0d);
-+		set_indexed_reg(hwif, 0x13 + adj, pio_timings[pio].reg13);
-+	}
- }
++#define EHCA_MOD_QP_PARM_MAX 4
++
+ struct ehca_qp {
+ 	union {
+ 		struct ib_qp ib_qp;
+@@ -164,10 +176,18 @@ struct ehca_qp {
+ 	struct ehca_cq *recv_cq;
+ 	unsigned int sqerr_purgeflag;
+ 	struct hlist_node list_entries;
++	/* array to cache modify_qp()'s parms for GSI/SMI qp */
++	struct ehca_mod_qp_parm *mod_qp_parm;
++	int mod_qp_parm_idx;
+ 	/* mmap counter for resources mapped into user space */
+ 	u32 mm_count_squeue;
+ 	u32 mm_count_rqueue;
+ 	u32 mm_count_galpa;
++	/* unsolicited ack circumvention */
++	int unsol_ack_circ;
++	int mtu_shift;
++	u32 message_count;
++	u32 packet_count;
+ };
  
- static u8 pdcnew_cable_detect(ide_hwif_t *hwif)
-@@ -223,14 +203,17 @@ static u8 pdcnew_cable_detect(ide_hwif_t *hwif)
- 		return ATA_CBL_PATA80;
- }
+ #define IS_SRQ(qp) (qp->ext_type == EQPT_SRQ)
+@@ -323,6 +343,7 @@ extern int ehca_port_act_time;
+ extern int ehca_use_hp_mr;
+ extern int ehca_scaling_code;
+ extern int ehca_lock_hcalls;
++extern int ehca_nr_ports;
  
--static int pdcnew_quirkproc(ide_drive_t *drive)
-+static void pdcnew_quirkproc(ide_drive_t *drive)
+ struct ipzu_queue_resp {
+ 	u32 qe_size;      /* queue entry size */
+diff --git a/drivers/infiniband/hw/ehca/ehca_cq.c b/drivers/infiniband/hw/ehca/ehca_cq.c
+index 79c25f5..0467c15 100644
+--- a/drivers/infiniband/hw/ehca/ehca_cq.c
++++ b/drivers/infiniband/hw/ehca/ehca_cq.c
+@@ -246,7 +246,7 @@ struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe, int comp_vector,
+ 		} else {
+ 			if (h_ret != H_PAGE_REGISTERED) {
+ 				ehca_err(device, "Registration of page failed "
+-					 "ehca_cq=%p cq_num=%x h_ret=%li"
++					 "ehca_cq=%p cq_num=%x h_ret=%li "
+ 					 "counter=%i act_pages=%i",
+ 					 my_cq, my_cq->cq_number,
+ 					 h_ret, counter, param.act_pages);
+diff --git a/drivers/infiniband/hw/ehca/ehca_irq.c b/drivers/infiniband/hw/ehca/ehca_irq.c
+index 3f617b2..863b34f 100644
+--- a/drivers/infiniband/hw/ehca/ehca_irq.c
++++ b/drivers/infiniband/hw/ehca/ehca_irq.c
+@@ -62,6 +62,7 @@
+ #define NEQE_PORT_NUMBER       EHCA_BMASK_IBM( 8, 15)
+ #define NEQE_PORT_AVAILABILITY EHCA_BMASK_IBM(16, 16)
+ #define NEQE_DISRUPTIVE        EHCA_BMASK_IBM(16, 16)
++#define NEQE_SPECIFIC_EVENT    EHCA_BMASK_IBM(16, 23)
+ 
+ #define ERROR_DATA_LENGTH      EHCA_BMASK_IBM(52, 63)
+ #define ERROR_DATA_TYPE        EHCA_BMASK_IBM( 0,  7)
+@@ -354,17 +355,34 @@ static void parse_ec(struct ehca_shca *shca, u64 eqe)
  {
- 	const char **list, *model = drive->id->model;
+ 	u8 ec   = EHCA_BMASK_GET(NEQE_EVENT_CODE, eqe);
+ 	u8 port = EHCA_BMASK_GET(NEQE_PORT_NUMBER, eqe);
++	u8 spec_event;
++	struct ehca_sport *sport = &shca->sport[port - 1];
++	unsigned long flags;
  
- 	for (list = pdc_quirk_drives; *list != NULL; list++)
--		if (strstr(model, *list) != NULL)
--			return 2;
--	return 0;
-+		if (strstr(model, *list) != NULL) {
-+			drive->quirk_list = 2;
-+			return;
-+		}
+ 	switch (ec) {
+ 	case 0x30: /* port availability change */
+ 		if (EHCA_BMASK_GET(NEQE_PORT_AVAILABILITY, eqe)) {
+-			shca->sport[port - 1].port_state = IB_PORT_ACTIVE;
++			int suppress_event;
++			/* replay modify_qp for sqps */
++			spin_lock_irqsave(&sport->mod_sqp_lock, flags);
++			suppress_event = !sport->ibqp_sqp[IB_QPT_GSI];
++			if (sport->ibqp_sqp[IB_QPT_SMI])
++				ehca_recover_sqp(sport->ibqp_sqp[IB_QPT_SMI]);
++			if (!suppress_event)
++				ehca_recover_sqp(sport->ibqp_sqp[IB_QPT_GSI]);
++			spin_unlock_irqrestore(&sport->mod_sqp_lock, flags);
 +
-+	drive->quirk_list = 0;
- }
++			/* AQP1 was destroyed, ignore this event */
++			if (suppress_event)
++				break;
++
++			sport->port_state = IB_PORT_ACTIVE;
+ 			dispatch_port_event(shca, port, IB_EVENT_PORT_ACTIVE,
+ 					    "is active");
+ 			ehca_query_sma_attr(shca, port,
+-					    &shca->sport[port - 1].saved_attr);
++					    &sport->saved_attr);
+ 		} else {
+-			shca->sport[port - 1].port_state = IB_PORT_DOWN;
++			sport->port_state = IB_PORT_DOWN;
+ 			dispatch_port_event(shca, port, IB_EVENT_PORT_ERR,
+ 					    "is inactive");
+ 		}
+@@ -378,11 +396,11 @@ static void parse_ec(struct ehca_shca *shca, u64 eqe)
+ 			ehca_warn(&shca->ib_device, "disruptive port "
+ 				  "%d configuration change", port);
  
- static void pdcnew_reset(ide_drive_t *drive)
-@@ -466,7 +449,7 @@ static unsigned int __devinit init_chipset_pdcnew(struct pci_dev *dev, const cha
- static void __devinit init_hwif_pdc202new(ide_hwif_t *hwif)
- {
- 	hwif->set_pio_mode = &pdcnew_set_pio_mode;
--	hwif->set_dma_mode = &pdcnew_set_mode;
-+	hwif->set_dma_mode = &pdcnew_set_dma_mode;
+-			shca->sport[port - 1].port_state = IB_PORT_DOWN;
++			sport->port_state = IB_PORT_DOWN;
+ 			dispatch_port_event(shca, port, IB_EVENT_PORT_ERR,
+ 					    "is inactive");
  
- 	hwif->quirkproc = &pdcnew_quirkproc;
- 	hwif->resetproc = &pdcnew_reset;
-diff --git a/drivers/ide/pci/pdc202xx_old.c b/drivers/ide/pci/pdc202xx_old.c
-index e09742e..3a1e081 100644
---- a/drivers/ide/pci/pdc202xx_old.c
-+++ b/drivers/ide/pci/pdc202xx_old.c
-@@ -162,7 +162,7 @@ static u8 pdc202xx_old_cable_detect (ide_hwif_t *hwif)
-  */
- static void pdc_old_enable_66MHz_clock(ide_hwif_t *hwif)
- {
--	unsigned long clock_reg = hwif->dma_master + 0x11;
-+	unsigned long clock_reg = hwif->extra_base + 0x01;
- 	u8 clock = inb(clock_reg);
+-			shca->sport[port - 1].port_state = IB_PORT_ACTIVE;
++			sport->port_state = IB_PORT_ACTIVE;
+ 			dispatch_port_event(shca, port, IB_EVENT_PORT_ACTIVE,
+ 					    "is active");
+ 		} else
+@@ -394,6 +412,16 @@ static void parse_ec(struct ehca_shca *shca, u64 eqe)
+ 	case 0x33:  /* trace stopped */
+ 		ehca_err(&shca->ib_device, "Traced stopped.");
+ 		break;
++	case 0x34: /* util async event */
++		spec_event = EHCA_BMASK_GET(NEQE_SPECIFIC_EVENT, eqe);
++		if (spec_event == 0x80) /* client reregister required */
++			dispatch_port_event(shca, port,
++					    IB_EVENT_CLIENT_REREGISTER,
++					    "client reregister req.");
++		else
++			ehca_warn(&shca->ib_device, "Unknown util async "
++				  "event %x on port %x", spec_event, port);
++		break;
+ 	default:
+ 		ehca_err(&shca->ib_device, "Unknown event code: %x on %s.",
+ 			 ec, shca->ib_device.name);
+diff --git a/drivers/infiniband/hw/ehca/ehca_iverbs.h b/drivers/infiniband/hw/ehca/ehca_iverbs.h
+index 5485799..c469bfd 100644
+--- a/drivers/infiniband/hw/ehca/ehca_iverbs.h
++++ b/drivers/infiniband/hw/ehca/ehca_iverbs.h
+@@ -200,4 +200,6 @@ void ehca_free_fw_ctrlblock(void *ptr);
+ #define ehca_free_fw_ctrlblock(ptr) free_page((unsigned long)(ptr))
+ #endif
  
- 	outb(clock | (hwif->channel ? 0x08 : 0x02), clock_reg);
-@@ -170,20 +170,23 @@ static void pdc_old_enable_66MHz_clock(ide_hwif_t *hwif)
++void ehca_recover_sqp(struct ib_qp *sqp);
++
+ #endif
+diff --git a/drivers/infiniband/hw/ehca/ehca_main.c b/drivers/infiniband/hw/ehca/ehca_main.c
+index 6a56d86..84c9b7b 100644
+--- a/drivers/infiniband/hw/ehca/ehca_main.c
++++ b/drivers/infiniband/hw/ehca/ehca_main.c
+@@ -90,7 +90,8 @@ MODULE_PARM_DESC(hw_level,
+ 		 "hardware level"
+ 		 " (0: autosensing (default), 1: v. 0.20, 2: v. 0.21)");
+ MODULE_PARM_DESC(nr_ports,
+-		 "number of connected ports (default: 2)");
++		 "number of connected ports (-1: autodetect, 1: port one only, "
++		 "2: two ports (default)");
+ MODULE_PARM_DESC(use_hp_mr,
+ 		 "high performance MRs (0: no (default), 1: yes)");
+ MODULE_PARM_DESC(port_act_time,
+@@ -511,7 +512,7 @@ static int ehca_create_aqp1(struct ehca_shca *shca, u32 port)
+ 	}
+ 	sport->ibcq_aqp1 = ibcq;
  
- static void pdc_old_disable_66MHz_clock(ide_hwif_t *hwif)
- {
--	unsigned long clock_reg = hwif->dma_master + 0x11;
-+	unsigned long clock_reg = hwif->extra_base + 0x01;
- 	u8 clock = inb(clock_reg);
+-	if (sport->ibqp_aqp1) {
++	if (sport->ibqp_sqp[IB_QPT_GSI]) {
+ 		ehca_err(&shca->ib_device, "AQP1 QP is already created.");
+ 		ret = -EPERM;
+ 		goto create_aqp1;
+@@ -537,7 +538,7 @@ static int ehca_create_aqp1(struct ehca_shca *shca, u32 port)
+ 		ret = PTR_ERR(ibqp);
+ 		goto create_aqp1;
+ 	}
+-	sport->ibqp_aqp1 = ibqp;
++	sport->ibqp_sqp[IB_QPT_GSI] = ibqp;
  
- 	outb(clock & ~(hwif->channel ? 0x08 : 0x02), clock_reg);
- }
+ 	return 0;
  
--static int pdc202xx_quirkproc (ide_drive_t *drive)
-+static void pdc202xx_quirkproc(ide_drive_t *drive)
+@@ -550,7 +551,7 @@ static int ehca_destroy_aqp1(struct ehca_sport *sport)
  {
- 	const char **list, *model = drive->id->model;
- 
- 	for (list = pdc_quirk_drives; *list != NULL; list++)
--		if (strstr(model, *list) != NULL)
--			return 2;
--	return 0;
-+		if (strstr(model, *list) != NULL) {
-+			drive->quirk_list = 2;
-+			return;
-+		}
-+
-+	drive->quirk_list = 0;
- }
+ 	int ret;
  
- static void pdc202xx_old_ide_dma_start(ide_drive_t *drive)
-@@ -193,7 +196,7 @@ static void pdc202xx_old_ide_dma_start(ide_drive_t *drive)
- 	if (drive->media != ide_disk || drive->addressing == 1) {
- 		struct request *rq	= HWGROUP(drive)->rq;
- 		ide_hwif_t *hwif	= HWIF(drive);
--		unsigned long high_16   = hwif->dma_master;
-+		unsigned long high_16	= hwif->extra_base - 16;
- 		unsigned long atapi_reg	= high_16 + (hwif->channel ? 0x24 : 0x20);
- 		u32 word_count	= 0;
- 		u8 clock = inb(high_16 + 0x11);
-@@ -212,7 +215,7 @@ static int pdc202xx_old_ide_dma_end(ide_drive_t *drive)
- {
- 	if (drive->media != ide_disk || drive->addressing == 1) {
- 		ide_hwif_t *hwif	= HWIF(drive);
--		unsigned long high_16	= hwif->dma_master;
-+		unsigned long high_16	= hwif->extra_base - 16;
- 		unsigned long atapi_reg	= high_16 + (hwif->channel ? 0x24 : 0x20);
- 		u8 clock		= 0;
+-	ret = ib_destroy_qp(sport->ibqp_aqp1);
++	ret = ib_destroy_qp(sport->ibqp_sqp[IB_QPT_GSI]);
+ 	if (ret) {
+ 		ehca_gen_err("Cannot destroy AQP1 QP. ret=%i", ret);
+ 		return ret;
+@@ -590,6 +591,11 @@ static struct attribute_group ehca_drv_attr_grp = {
+ 	.attrs = ehca_drv_attrs
+ };
  
-@@ -228,7 +231,7 @@ static int pdc202xx_old_ide_dma_end(ide_drive_t *drive)
- static int pdc202xx_old_ide_dma_test_irq(ide_drive_t *drive)
- {
- 	ide_hwif_t *hwif	= HWIF(drive);
--	unsigned long high_16	= hwif->dma_master;
-+	unsigned long high_16	= hwif->extra_base - 16;
- 	u8 dma_stat		= inb(hwif->dma_status);
- 	u8 sc1d			= inb(high_16 + 0x001d);
++static struct attribute_group *ehca_drv_attr_groups[] = {
++	&ehca_drv_attr_grp,
++	NULL,
++};
++
+ #define EHCA_RESOURCE_ATTR(name)                                           \
+ static ssize_t  ehca_show_##name(struct device *dev,                       \
+ 				 struct device_attribute *attr,            \
+@@ -688,7 +694,7 @@ static int __devinit ehca_probe(struct of_device *dev,
+ 	struct ehca_shca *shca;
+ 	const u64 *handle;
+ 	struct ib_pd *ibpd;
+-	int ret;
++	int ret, i;
  
-@@ -271,7 +274,7 @@ static void pdc202xx_dma_timeout(ide_drive_t *drive)
+ 	handle = of_get_property(dev->node, "ibm,hca-handle", NULL);
+ 	if (!handle) {
+@@ -709,6 +715,8 @@ static int __devinit ehca_probe(struct of_device *dev,
+ 		return -ENOMEM;
+ 	}
+ 	mutex_init(&shca->modify_mutex);
++	for (i = 0; i < ARRAY_SIZE(shca->sport); i++)
++		spin_lock_init(&shca->sport[i].mod_sqp_lock);
  
- static void pdc202xx_reset_host (ide_hwif_t *hwif)
- {
--	unsigned long high_16	= hwif->dma_master;
-+	unsigned long high_16	= hwif->extra_base - 16;
- 	u8 udma_speed_flag	= inb(high_16 | 0x001f);
+ 	shca->ofdev = dev;
+ 	shca->ipz_hca_handle.handle = *handle;
+@@ -899,6 +907,9 @@ static struct of_platform_driver ehca_driver = {
+ 	.match_table = ehca_device_table,
+ 	.probe       = ehca_probe,
+ 	.remove      = ehca_remove,
++	.driver	     = {
++		.groups = ehca_drv_attr_groups,
++	},
+ };
  
- 	outb(udma_speed_flag | 0x10, high_16 | 0x001f);
-@@ -375,6 +378,11 @@ static void __devinit pdc202ata4_fixup_irq(struct pci_dev *dev,
+ void ehca_poll_eqs(unsigned long data)
+@@ -926,7 +937,7 @@ void ehca_poll_eqs(unsigned long data)
+ 				ehca_process_eq(shca, 0);
+ 		}
  	}
+-	mod_timer(&poll_eqs_timer, jiffies + HZ);
++	mod_timer(&poll_eqs_timer, round_jiffies(jiffies + HZ));
+ 	spin_unlock(&shca_list_lock);
  }
  
-+#define IDE_HFLAGS_PDC202XX \
-+	(IDE_HFLAG_ERROR_STOPS_FIFO | \
-+	 IDE_HFLAG_ABUSE_SET_DMA_MODE | \
-+	 IDE_HFLAG_OFF_BOARD)
-+
- #define DECLARE_PDC2026X_DEV(name_str, udma, extra_flags) \
- 	{ \
- 		.name		= name_str, \
-@@ -382,9 +390,7 @@ static void __devinit pdc202ata4_fixup_irq(struct pci_dev *dev,
- 		.init_hwif	= init_hwif_pdc202xx, \
- 		.init_dma	= init_dma_pdc202xx, \
- 		.extra		= 48, \
--		.host_flags	= IDE_HFLAG_ERROR_STOPS_FIFO | \
--				  extra_flags | \
--				  IDE_HFLAG_OFF_BOARD, \
-+		.host_flags	= IDE_HFLAGS_PDC202XX | extra_flags, \
- 		.pio_mask	= ATA_PIO4, \
- 		.mwdma_mask	= ATA_MWDMA2, \
- 		.udma_mask	= udma, \
-@@ -397,8 +403,7 @@ static const struct ide_port_info pdc202xx_chipsets[] __devinitdata = {
- 		.init_hwif	= init_hwif_pdc202xx,
- 		.init_dma	= init_dma_pdc202xx,
- 		.extra		= 16,
--		.host_flags	= IDE_HFLAG_ERROR_STOPS_FIFO |
--				  IDE_HFLAG_OFF_BOARD,
-+		.host_flags	= IDE_HFLAGS_PDC202XX,
- 		.pio_mask	= ATA_PIO4,
- 		.mwdma_mask	= ATA_MWDMA2,
- 		.udma_mask	= ATA_UDMA2,
-diff --git a/drivers/ide/pci/piix.c b/drivers/ide/pci/piix.c
-index 27781d2..bd6d3f7 100644
---- a/drivers/ide/pci/piix.c
-+++ b/drivers/ide/pci/piix.c
-@@ -203,20 +203,11 @@ static void piix_set_dma_mode(ide_drive_t *drive, const u8 speed)
- 	pci_read_config_byte(dev, 0x54, &reg54);
- 	pci_read_config_byte(dev, 0x55, &reg55);
+@@ -957,10 +968,6 @@ int __init ehca_module_init(void)
+ 		goto module_init2;
+ 	}
  
--	switch(speed) {
--		case XFER_UDMA_4:
--		case XFER_UDMA_2:	u_speed = 2 << (drive->dn * 4); break;
--		case XFER_UDMA_5:
--		case XFER_UDMA_3:
--		case XFER_UDMA_1:	u_speed = 1 << (drive->dn * 4); break;
--		case XFER_UDMA_0:	u_speed = 0 << (drive->dn * 4); break;
--		case XFER_MW_DMA_2:
--		case XFER_MW_DMA_1:
--		case XFER_SW_DMA_2:	break;
--		default:		return;
--	}
+-	ret = sysfs_create_group(&ehca_driver.driver.kobj, &ehca_drv_attr_grp);
+-	if (ret) /* only complain; we can live without attributes */
+-		ehca_gen_err("Cannot create driver attributes  ret=%d", ret);
 -
- 	if (speed >= XFER_UDMA_0) {
-+		u8 udma = speed - XFER_UDMA_0;
-+
-+		u_speed = min_t(u8, 2 - (udma & 1), udma) << (drive->dn * 4);
-+
- 		if (!(reg48 & u_flag))
- 			pci_write_config_byte(dev, 0x48, reg48 | u_flag);
- 		if (speed == XFER_UDMA_5) {
-diff --git a/drivers/ide/pci/sc1200.c b/drivers/ide/pci/sc1200.c
-index 707d5ff..32fdf53 100644
---- a/drivers/ide/pci/sc1200.c
-+++ b/drivers/ide/pci/sc1200.c
-@@ -135,59 +135,29 @@ static void sc1200_set_dma_mode(ide_drive_t *drive, const u8 mode)
- 	unsigned short		pci_clock;
- 	unsigned int		basereg = hwif->channel ? 0x50 : 0x40;
+ 	if (ehca_poll_all_eqs != 1) {
+ 		ehca_gen_err("WARNING!!!");
+ 		ehca_gen_err("It is possible to lose interrupts.");
+@@ -986,7 +993,6 @@ void __exit ehca_module_exit(void)
+ 	if (ehca_poll_all_eqs == 1)
+ 		del_timer_sync(&poll_eqs_timer);
  
-+	static const u32 udma_timing[3][3] = {
-+		{ 0x00921250, 0x00911140, 0x00911030 },
-+		{ 0x00932470, 0x00922260, 0x00922140 },
-+		{ 0x009436a1, 0x00933481, 0x00923261 },
-+	};
-+
-+	static const u32 mwdma_timing[3][3] = {
-+		{ 0x00077771, 0x00012121, 0x00002020 },
-+		{ 0x000bbbb2, 0x00024241, 0x00013131 },
-+		{ 0x000ffff3, 0x00035352, 0x00015151 },
-+	};
+-	sysfs_remove_group(&ehca_driver.driver.kobj, &ehca_drv_attr_grp);
+ 	ibmebus_unregister_driver(&ehca_driver);
+ 
+ 	ehca_destroy_slab_caches();
+diff --git a/drivers/infiniband/hw/ehca/ehca_qp.c b/drivers/infiniband/hw/ehca/ehca_qp.c
+index eff5fb5..1012f15 100644
+--- a/drivers/infiniband/hw/ehca/ehca_qp.c
++++ b/drivers/infiniband/hw/ehca/ehca_qp.c
+@@ -592,10 +592,8 @@ static struct ehca_qp *internal_create_qp(
+ 		goto create_qp_exit1;
+ 	}
+ 
+-	if (init_attr->sq_sig_type == IB_SIGNAL_ALL_WR)
+-		parms.sigtype = HCALL_SIGT_EVERY;
+-	else
+-		parms.sigtype = HCALL_SIGT_BY_WQE;
++	/* Always signal by WQE so we can hide circ. WQEs */
++	parms.sigtype = HCALL_SIGT_BY_WQE;
+ 
+ 	/* UD_AV CIRCUMVENTION */
+ 	max_send_sge = init_attr->cap.max_send_sge;
+@@ -618,6 +616,10 @@ static struct ehca_qp *internal_create_qp(
+ 	parms.squeue.max_sge = max_send_sge;
+ 	parms.rqueue.max_sge = max_recv_sge;
+ 
++	/* RC QPs need one more SWQE for unsolicited ack circumvention */
++	if (qp_type == IB_QPT_RC)
++		parms.squeue.max_wr++;
 +
- 	pci_clock = sc1200_get_pci_clock();
+ 	if (EHCA_BMASK_GET(HCA_CAP_MINI_QP, shca->hca_cap)) {
+ 		if (HAS_SQ(my_qp))
+ 			ehca_determine_small_queue(
+@@ -650,6 +652,8 @@ static struct ehca_qp *internal_create_qp(
+ 			parms.squeue.act_nr_sges = 1;
+ 			parms.rqueue.act_nr_sges = 1;
+ 		}
++		/* hide the extra WQE */
++		parms.squeue.act_nr_wqes--;
+ 		break;
+ 	case IB_QPT_UD:
+ 	case IB_QPT_GSI:
+@@ -729,12 +733,31 @@ static struct ehca_qp *internal_create_qp(
+ 	init_attr->cap.max_send_wr = parms.squeue.act_nr_wqes;
+ 	my_qp->init_attr = *init_attr;
  
- 	/*
- 	 * Note that each DMA mode has several timings associated with it.
- 	 * The correct timing depends on the fast PCI clock freq.
- 	 */
--	timings = 0;
--	switch (mode) {
--		case XFER_UDMA_0:
--			switch (pci_clock) {
--				case PCI_CLK_33:	timings = 0x00921250;	break;
--				case PCI_CLK_48:	timings = 0x00932470;	break;
--				case PCI_CLK_66:	timings = 0x009436a1;	break;
--			}
--			break;
--		case XFER_UDMA_1:
--			switch (pci_clock) {
--				case PCI_CLK_33:	timings = 0x00911140;	break;
--				case PCI_CLK_48:	timings = 0x00922260;	break;
--				case PCI_CLK_66:	timings = 0x00933481;	break;
--			}
--			break;
--		case XFER_UDMA_2:
--			switch (pci_clock) {
--				case PCI_CLK_33:	timings = 0x00911030;	break;
--				case PCI_CLK_48:	timings = 0x00922140;	break;
--				case PCI_CLK_66:	timings = 0x00923261;	break;
--			}
--			break;
--		case XFER_MW_DMA_0:
--			switch (pci_clock) {
--				case PCI_CLK_33:	timings = 0x00077771;	break;
--				case PCI_CLK_48:	timings = 0x000bbbb2;	break;
--				case PCI_CLK_66:	timings = 0x000ffff3;	break;
--			}
--			break;
--		case XFER_MW_DMA_1:
--			switch (pci_clock) {
--				case PCI_CLK_33:	timings = 0x00012121;	break;
--				case PCI_CLK_48:	timings = 0x00024241;	break;
--				case PCI_CLK_66:	timings = 0x00035352;	break;
--			}
--			break;
--		case XFER_MW_DMA_2:
--			switch (pci_clock) {
--				case PCI_CLK_33:	timings = 0x00002020;	break;
--				case PCI_CLK_48:	timings = 0x00013131;	break;
--				case PCI_CLK_66:	timings = 0x00015151;	break;
--			}
--			break;
--		default:
--			return;
--	}
++	if (qp_type == IB_QPT_SMI || qp_type == IB_QPT_GSI) {
++		shca->sport[init_attr->port_num - 1].ibqp_sqp[qp_type] =
++			&my_qp->ib_qp;
++		if (ehca_nr_ports < 0) {
++			/* alloc array to cache subsequent modify qp parms
++			 * for autodetect mode
++			 */
++			my_qp->mod_qp_parm =
++				kzalloc(EHCA_MOD_QP_PARM_MAX *
++					sizeof(*my_qp->mod_qp_parm),
++					GFP_KERNEL);
++			if (!my_qp->mod_qp_parm) {
++				ehca_err(pd->device,
++					 "Could not alloc mod_qp_parm");
++				goto create_qp_exit4;
++			}
++		}
++	}
 +
-+	if (mode >= XFER_UDMA_0)
-+		timings =  udma_timing[pci_clock][mode - XFER_UDMA_0];
-+	else
-+		timings = mwdma_timing[pci_clock][mode - XFER_MW_DMA_0];
+ 	/* NOTE: define_apq0() not supported yet */
+ 	if (qp_type == IB_QPT_GSI) {
+ 		h_ret = ehca_define_sqp(shca, my_qp, init_attr);
+ 		if (h_ret != H_SUCCESS) {
+ 			ret = ehca2ib_return_code(h_ret);
+-			goto create_qp_exit4;
++			goto create_qp_exit5;
+ 		}
+ 	}
  
- 	if (unit == 0) {			/* are we configuring drive0? */
- 		pci_read_config_dword(hwif->pci_dev, basereg+4, &reg);
-@@ -250,9 +220,9 @@ static void sc1200_set_pio_mode(ide_drive_t *drive, const u8 pio)
+@@ -743,7 +766,7 @@ static struct ehca_qp *internal_create_qp(
+ 		if (ret) {
+ 			ehca_err(pd->device,
+ 				 "Couldn't assign qp to send_cq ret=%i", ret);
+-			goto create_qp_exit4;
++			goto create_qp_exit5;
+ 		}
  	}
- 	if (mode != -1) {
- 		printk("SC1200: %s: changing (U)DMA mode\n", drive->name);
--		hwif->dma_off_quietly(drive);
--		if (ide_set_dma_mode(drive, mode) == 0)
--			hwif->dma_host_on(drive);
-+		ide_dma_off_quietly(drive);
-+		if (ide_set_dma_mode(drive, mode) == 0 && drive->using_dma)
-+			hwif->dma_host_set(drive, 1);
- 		return;
+ 
+@@ -769,12 +792,18 @@ static struct ehca_qp *internal_create_qp(
+ 		if (ib_copy_to_udata(udata, &resp, sizeof resp)) {
+ 			ehca_err(pd->device, "Copy to udata failed");
+ 			ret = -EINVAL;
+-			goto create_qp_exit4;
++			goto create_qp_exit6;
+ 		}
  	}
  
-@@ -260,66 +230,39 @@ static void sc1200_set_pio_mode(ide_drive_t *drive, const u8 pio)
- }
+ 	return my_qp;
  
- #ifdef CONFIG_PM
--static ide_hwif_t *lookup_pci_dev (ide_hwif_t *prev, struct pci_dev *dev)
--{
--	int	h;
--
--	for (h = 0; h < MAX_HWIFS; h++) {
--		ide_hwif_t *hwif = &ide_hwifs[h];
--		if (prev) {
--			if (hwif == prev)
--				prev = NULL;	// found previous, now look for next match
--		} else {
--			if (hwif && hwif->pci_dev == dev)
--				return hwif;	// found next match
--		}
--	}
--	return NULL;	// not found
--}
--
--typedef struct sc1200_saved_state_s {
--	__u32		regs[4];
--} sc1200_saved_state_t;
--
-+struct sc1200_saved_state {
-+	u32 regs[8];
-+};
++create_qp_exit6:
++	ehca_cq_unassign_qp(my_qp->send_cq, my_qp->real_qp_num);
++
++create_qp_exit5:
++	kfree(my_qp->mod_qp_parm);
++
+ create_qp_exit4:
+ 	if (HAS_RQ(my_qp))
+ 		ipz_queue_dtor(my_pd, &my_qp->ipz_rqueue);
+@@ -858,7 +887,7 @@ struct ib_srq *ehca_create_srq(struct ib_pd *pd,
+ 				update_mask,
+ 				mqpcb, my_qp->galpas.kernel);
+ 	if (hret != H_SUCCESS) {
+-		ehca_err(pd->device, "Could not modify SRQ to INIT"
++		ehca_err(pd->device, "Could not modify SRQ to INIT "
+ 			 "ehca_qp=%p qp_num=%x h_ret=%li",
+ 			 my_qp, my_qp->real_qp_num, hret);
+ 		goto create_srq2;
+@@ -872,7 +901,7 @@ struct ib_srq *ehca_create_srq(struct ib_pd *pd,
+ 				update_mask,
+ 				mqpcb, my_qp->galpas.kernel);
+ 	if (hret != H_SUCCESS) {
+-		ehca_err(pd->device, "Could not enable SRQ"
++		ehca_err(pd->device, "Could not enable SRQ "
+ 			 "ehca_qp=%p qp_num=%x h_ret=%li",
+ 			 my_qp, my_qp->real_qp_num, hret);
+ 		goto create_srq2;
+@@ -886,7 +915,7 @@ struct ib_srq *ehca_create_srq(struct ib_pd *pd,
+ 				update_mask,
+ 				mqpcb, my_qp->galpas.kernel);
+ 	if (hret != H_SUCCESS) {
+-		ehca_err(pd->device, "Could not modify SRQ to RTR"
++		ehca_err(pd->device, "Could not modify SRQ to RTR "
+ 			 "ehca_qp=%p qp_num=%x h_ret=%li",
+ 			 my_qp, my_qp->real_qp_num, hret);
+ 		goto create_srq2;
+@@ -992,7 +1021,7 @@ static int internal_modify_qp(struct ib_qp *ibqp,
+ 	unsigned long flags = 0;
  
- static int sc1200_suspend (struct pci_dev *dev, pm_message_t state)
+ 	/* do query_qp to obtain current attr values */
+-	mqpcb = ehca_alloc_fw_ctrlblock(GFP_KERNEL);
++	mqpcb = ehca_alloc_fw_ctrlblock(GFP_ATOMIC);
+ 	if (!mqpcb) {
+ 		ehca_err(ibqp->device, "Could not get zeroed page for mqpcb "
+ 			 "ehca_qp=%p qp_num=%x ", my_qp, ibqp->qp_num);
+@@ -1180,6 +1209,8 @@ static int internal_modify_qp(struct ib_qp *ibqp,
+ 		update_mask |= EHCA_BMASK_SET(MQPCB_MASK_PRIM_P_KEY_IDX, 1);
+ 	}
+ 	if (attr_mask & IB_QP_PORT) {
++		struct ehca_sport *sport;
++		struct ehca_qp *aqp1;
+ 		if (attr->port_num < 1 || attr->port_num > shca->num_ports) {
+ 			ret = -EINVAL;
+ 			ehca_err(ibqp->device, "Invalid port=%x. "
+@@ -1188,6 +1219,29 @@ static int internal_modify_qp(struct ib_qp *ibqp,
+ 				 shca->num_ports);
+ 			goto modify_qp_exit2;
+ 		}
++		sport = &shca->sport[attr->port_num - 1];
++		if (!sport->ibqp_sqp[IB_QPT_GSI]) {
++			/* should not occur */
++			ret = -EFAULT;
++			ehca_err(ibqp->device, "AQP1 was not created for "
++				 "port=%x", attr->port_num);
++			goto modify_qp_exit2;
++		}
++		aqp1 = container_of(sport->ibqp_sqp[IB_QPT_GSI],
++				    struct ehca_qp, ib_qp);
++		if (ibqp->qp_type != IB_QPT_GSI &&
++		    ibqp->qp_type != IB_QPT_SMI &&
++		    aqp1->mod_qp_parm) {
++			/*
++			 * firmware will reject this modify_qp() because
++			 * port is not activated/initialized fully
++			 */
++			ret = -EFAULT;
++			ehca_warn(ibqp->device, "Couldn't modify qp port=%x: "
++				  "either port is being activated (try again) "
++				  "or cabling issue", attr->port_num);
++			goto modify_qp_exit2;
++		}
+ 		mqpcb->prim_phys_port = attr->port_num;
+ 		update_mask |= EHCA_BMASK_SET(MQPCB_MASK_PRIM_PHYS_PORT, 1);
+ 	}
+@@ -1244,6 +1298,8 @@ static int internal_modify_qp(struct ib_qp *ibqp,
+ 	}
+ 
+ 	if (attr_mask & IB_QP_PATH_MTU) {
++		/* store ld(MTU) */
++		my_qp->mtu_shift = attr->path_mtu + 7;
+ 		mqpcb->path_mtu = attr->path_mtu;
+ 		update_mask |= EHCA_BMASK_SET(MQPCB_MASK_PATH_MTU, 1);
+ 	}
+@@ -1467,6 +1523,8 @@ modify_qp_exit1:
+ int ehca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask,
+ 		   struct ib_udata *udata)
  {
--	ide_hwif_t		*hwif = NULL;
--
- 	printk("SC1200: suspend(%u)\n", state.event);
++	struct ehca_shca *shca = container_of(ibqp->device, struct ehca_shca,
++					      ib_device);
+ 	struct ehca_qp *my_qp = container_of(ibqp, struct ehca_qp, ib_qp);
+ 	struct ehca_pd *my_pd = container_of(my_qp->ib_qp.pd, struct ehca_pd,
+ 					     ib_pd);
+@@ -1479,9 +1537,100 @@ int ehca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask,
+ 		return -EINVAL;
+ 	}
  
-+	/*
-+	 * we only save state when going from full power to less
++	/* The if-block below caches qp_attr to be modified for GSI and SMI
++	 * qps during the initialization by ib_mad. When the respective port
++	 * is activated, ie we got an event PORT_ACTIVE, we'll replay the
++	 * cached modify calls sequence, see ehca_recover_sqs() below.
++	 * Why that is required:
++	 * 1) If one port is connected, older code requires that port one
++	 *    to be connected and module option nr_ports=1 to be given by
++	 *    user, which is very inconvenient for end user.
++	 * 2) Firmware accepts modify_qp() only if respective port has become
++	 *    active. Older code had a wait loop of 30sec create_qp()/
++	 *    define_aqp1(), which is not appropriate in practice. This
++	 *    code now removes that wait loop, see define_aqp1(), and always
++	 *    reports all ports to ib_mad resp. users. Only activated ports
++	 *    will then usable for the users.
 +	 */
- 	if (state.event == PM_EVENT_ON) {
--		// we only save state when going from full power to less
--
--		//
--		// Loop over all interfaces that are part of this PCI device:
--		//
--		while ((hwif = lookup_pci_dev(hwif, dev)) != NULL) {
--			sc1200_saved_state_t	*ss;
--			unsigned int		basereg, r;
--			//
--			// allocate a permanent save area, if not already allocated
--			//
--			ss = (sc1200_saved_state_t *)hwif->config_data;
--			if (ss == NULL) {
--				ss = kmalloc(sizeof(sc1200_saved_state_t), GFP_KERNEL);
--				if (ss == NULL)
--					return -ENOMEM;
--				hwif->config_data = (unsigned long)ss;
--			}
--			ss = (sc1200_saved_state_t *)hwif->config_data;
--			//
--			// Save timing registers:  this may be unnecessary if 
--			// BIOS also does it
--			//
--			basereg = hwif->channel ? 0x50 : 0x40;
--			for (r = 0; r < 4; ++r) {
--				pci_read_config_dword (hwif->pci_dev, basereg + (r<<2), &ss->regs[r]);
--			}
-+		struct sc1200_saved_state *ss;
-+		unsigned int r;
++	if (ibqp->qp_type == IB_QPT_GSI || ibqp->qp_type == IB_QPT_SMI) {
++		int port = my_qp->init_attr.port_num;
++		struct ehca_sport *sport = &shca->sport[port - 1];
++		unsigned long flags;
++		spin_lock_irqsave(&sport->mod_sqp_lock, flags);
++		/* cache qp_attr only during init */
++		if (my_qp->mod_qp_parm) {
++			struct ehca_mod_qp_parm *p;
++			if (my_qp->mod_qp_parm_idx >= EHCA_MOD_QP_PARM_MAX) {
++				ehca_err(&shca->ib_device,
++					 "mod_qp_parm overflow state=%x port=%x"
++					 " type=%x", attr->qp_state,
++					 my_qp->init_attr.port_num,
++					 ibqp->qp_type);
++				spin_unlock_irqrestore(&sport->mod_sqp_lock,
++						       flags);
++				return -EINVAL;
++			}
++			p = &my_qp->mod_qp_parm[my_qp->mod_qp_parm_idx];
++			p->mask = attr_mask;
++			p->attr = *attr;
++			my_qp->mod_qp_parm_idx++;
++			ehca_dbg(&shca->ib_device,
++				 "Saved qp_attr for state=%x port=%x type=%x",
++				 attr->qp_state, my_qp->init_attr.port_num,
++				 ibqp->qp_type);
++			spin_unlock_irqrestore(&sport->mod_sqp_lock, flags);
++			return 0;
++		}
++		spin_unlock_irqrestore(&sport->mod_sqp_lock, flags);
++	}
 +
-+		/*
-+		 * allocate a permanent save area, if not already allocated
-+		 */
-+		ss = (struct sc1200_saved_state *)pci_get_drvdata(dev);
-+		if (ss == NULL) {
-+			ss = kmalloc(sizeof(*ss), GFP_KERNEL);
-+			if (ss == NULL)
-+				return -ENOMEM;
-+			pci_set_drvdata(dev, ss);
- 		}
--	}
+ 	return internal_modify_qp(ibqp, attr, attr_mask, 0);
+ }
  
--	/* You don't need to iterate over disks -- sysfs should have done that for you already */ 
-+		/*
-+		 * save timing registers
-+		 * (this may be unnecessary if BIOS also does it)
-+		 */
-+		for (r = 0; r < 8; r++)
-+			pci_read_config_dword(dev, 0x40 + r * 4, &ss->regs[r]);
++void ehca_recover_sqp(struct ib_qp *sqp)
++{
++	struct ehca_qp *my_sqp = container_of(sqp, struct ehca_qp, ib_qp);
++	int port = my_sqp->init_attr.port_num;
++	struct ib_qp_attr attr;
++	struct ehca_mod_qp_parm *qp_parm;
++	int i, qp_parm_idx, ret;
++	unsigned long flags, wr_cnt;
++
++	if (!my_sqp->mod_qp_parm)
++		return;
++	ehca_dbg(sqp->device, "SQP port=%x qp_num=%x", port, sqp->qp_num);
++
++	qp_parm = my_sqp->mod_qp_parm;
++	qp_parm_idx = my_sqp->mod_qp_parm_idx;
++	for (i = 0; i < qp_parm_idx; i++) {
++		attr = qp_parm[i].attr;
++		ret = internal_modify_qp(sqp, &attr, qp_parm[i].mask, 0);
++		if (ret) {
++			ehca_err(sqp->device, "Could not modify SQP port=%x "
++				 "qp_num=%x ret=%x", port, sqp->qp_num, ret);
++			goto free_qp_parm;
++		}
++		ehca_dbg(sqp->device, "SQP port=%x qp_num=%x in state=%x",
++			 port, sqp->qp_num, attr.qp_state);
 +	}
++
++	/* re-trigger posted recv wrs */
++	wr_cnt =  my_sqp->ipz_rqueue.current_q_offset /
++		my_sqp->ipz_rqueue.qe_size;
++	if (wr_cnt) {
++		spin_lock_irqsave(&my_sqp->spinlock_r, flags);
++		hipz_update_rqa(my_sqp, wr_cnt);
++		spin_unlock_irqrestore(&my_sqp->spinlock_r, flags);
++		ehca_dbg(sqp->device, "doorbell port=%x qp_num=%x wr_cnt=%lx",
++			 port, sqp->qp_num, wr_cnt);
++	}
++
++free_qp_parm:
++	kfree(qp_parm);
++	/* this prevents subsequent calls to modify_qp() to cache qp_attr */
++	my_sqp->mod_qp_parm = NULL;
++}
++
+ int ehca_query_qp(struct ib_qp *qp,
+ 		  struct ib_qp_attr *qp_attr,
+ 		  int qp_attr_mask, struct ib_qp_init_attr *qp_init_attr)
+@@ -1769,6 +1918,7 @@ static int internal_destroy_qp(struct ib_device *dev, struct ehca_qp *my_qp,
+ 	struct ehca_shca *shca = container_of(dev, struct ehca_shca, ib_device);
+ 	struct ehca_pd *my_pd = container_of(my_qp->ib_qp.pd, struct ehca_pd,
+ 					     ib_pd);
++	struct ehca_sport *sport = &shca->sport[my_qp->init_attr.port_num - 1];
+ 	u32 cur_pid = current->tgid;
+ 	u32 qp_num = my_qp->real_qp_num;
+ 	int ret;
+@@ -1815,6 +1965,14 @@ static int internal_destroy_qp(struct ib_device *dev, struct ehca_qp *my_qp,
+ 	port_num = my_qp->init_attr.port_num;
+ 	qp_type  = my_qp->init_attr.qp_type;
  
- 	pci_disable_device(dev);
- 	pci_set_power_state(dev, pci_choose_state(dev, state));
-@@ -328,30 +271,25 @@ static int sc1200_suspend (struct pci_dev *dev, pm_message_t state)
- 
- static int sc1200_resume (struct pci_dev *dev)
- {
--	ide_hwif_t	*hwif = NULL;
--	int		i;
-+	struct sc1200_saved_state *ss;
-+	unsigned int r;
-+	int i;
- 
- 	i = pci_enable_device(dev);
- 	if (i)
- 		return i;
++	if (qp_type == IB_QPT_SMI || qp_type == IB_QPT_GSI) {
++		spin_lock_irqsave(&sport->mod_sqp_lock, flags);
++		kfree(my_qp->mod_qp_parm);
++		my_qp->mod_qp_parm = NULL;
++		shca->sport[port_num - 1].ibqp_sqp[qp_type] = NULL;
++		spin_unlock_irqrestore(&sport->mod_sqp_lock, flags);
++	}
++
+ 	/* no support for IB_QPT_SMI yet */
+ 	if (qp_type == IB_QPT_GSI) {
+ 		struct ib_event event;
+diff --git a/drivers/infiniband/hw/ehca/ehca_reqs.c b/drivers/infiniband/hw/ehca/ehca_reqs.c
+index ea91360..3aacc8c 100644
+--- a/drivers/infiniband/hw/ehca/ehca_reqs.c
++++ b/drivers/infiniband/hw/ehca/ehca_reqs.c
+@@ -50,6 +50,9 @@
+ #include "hcp_if.h"
+ #include "hipz_fns.h"
  
--	//
--	// loop over all interfaces that are part of this pci device:
--	//
--	while ((hwif = lookup_pci_dev(hwif, dev)) != NULL) {
--		unsigned int		basereg, r;
--		sc1200_saved_state_t	*ss = (sc1200_saved_state_t *)hwif->config_data;
--
--		//
--		// Restore timing registers:  this may be unnecessary if BIOS also does it
--		//
--		basereg = hwif->channel ? 0x50 : 0x40;
--		if (ss != NULL) {
--			for (r = 0; r < 4; ++r) {
--				pci_write_config_dword(hwif->pci_dev, basereg + (r<<2), ss->regs[r]);
--			}
--		}
-+	ss = (struct sc1200_saved_state *)pci_get_drvdata(dev);
++/* in RC traffic, insert an empty RDMA READ every this many packets */
++#define ACK_CIRC_THRESHOLD 2000000
 +
-+	/*
-+	 * restore timing registers
-+	 * (this may be unnecessary if BIOS also does it)
-+	 */
-+	if (ss) {
-+		for (r = 0; r < 8; r++)
-+			pci_write_config_dword(dev, 0x40 + r * 4, ss->regs[r]);
+ static inline int ehca_write_rwqe(struct ipz_queue *ipz_rqueue,
+ 				  struct ehca_wqe *wqe_p,
+ 				  struct ib_recv_wr *recv_wr)
+@@ -81,7 +84,7 @@ static inline int ehca_write_rwqe(struct ipz_queue *ipz_rqueue,
+ 	if (ehca_debug_level) {
+ 		ehca_gen_dbg("RECEIVE WQE written into ipz_rqueue=%p",
+ 			     ipz_rqueue);
+-		ehca_dmp( wqe_p, 16*(6 + wqe_p->nr_of_data_seg), "recv wqe");
++		ehca_dmp(wqe_p, 16*(6 + wqe_p->nr_of_data_seg), "recv wqe");
  	}
-+
+ 
  	return 0;
- }
- #endif
-diff --git a/drivers/ide/pci/scc_pata.c b/drivers/ide/pci/scc_pata.c
-index ebb7132..24a85bb 100644
---- a/drivers/ide/pci/scc_pata.c
-+++ b/drivers/ide/pci/scc_pata.c
-@@ -254,19 +254,7 @@ static void scc_set_dma_mode(ide_drive_t *drive, const u8 speed)
- 		offset = 0; /* 100MHz */
- 	}
+@@ -135,7 +138,8 @@ static void trace_send_wr_ud(const struct ib_send_wr *send_wr)
  
--	switch (speed) {
--	case XFER_UDMA_6:
--	case XFER_UDMA_5:
--	case XFER_UDMA_4:
--	case XFER_UDMA_3:
--	case XFER_UDMA_2:
--	case XFER_UDMA_1:
--	case XFER_UDMA_0:
--		idx = speed - XFER_UDMA_0;
--		break;
--	default:
--		return;
--	}
-+	idx = speed - XFER_UDMA_0;
+ static inline int ehca_write_swqe(struct ehca_qp *qp,
+ 				  struct ehca_wqe *wqe_p,
+-				  const struct ib_send_wr *send_wr)
++				  const struct ib_send_wr *send_wr,
++				  int hidden)
+ {
+ 	u32 idx;
+ 	u64 dma_length;
+@@ -176,7 +180,9 @@ static inline int ehca_write_swqe(struct ehca_qp *qp,
  
- 	jcactsel = JCACTSELtbl[offset][idx];
- 	if (is_slave) {
-diff --git a/drivers/ide/pci/serverworks.c b/drivers/ide/pci/serverworks.c
-index a728031..877c09b 100644
---- a/drivers/ide/pci/serverworks.c
-+++ b/drivers/ide/pci/serverworks.c
-@@ -164,25 +164,12 @@ static void svwks_set_dma_mode(ide_drive_t *drive, const u8 speed)
- 	ultra_timing	&= ~(0x0F << (4*unit));
- 	ultra_enable	&= ~(0x01 << drive->dn);
+ 	wqe_p->wr_flag = 0;
  
--	switch(speed) {
--		case XFER_MW_DMA_2:
--		case XFER_MW_DMA_1:
--		case XFER_MW_DMA_0:
--			dma_timing |= dma_modes[speed - XFER_MW_DMA_0];
--			break;
--
--		case XFER_UDMA_5:
--		case XFER_UDMA_4:
--		case XFER_UDMA_3:
--		case XFER_UDMA_2:
--		case XFER_UDMA_1:
--		case XFER_UDMA_0:
--			dma_timing   |= dma_modes[2];
--			ultra_timing |= ((udma_modes[speed - XFER_UDMA_0]) << (4*unit));
--			ultra_enable |= (0x01 << drive->dn);
--		default:
--			break;
--	}
-+	if (speed >= XFER_UDMA_0) {
-+		dma_timing   |= dma_modes[2];
-+		ultra_timing |= (udma_modes[speed - XFER_UDMA_0] << (4 * unit));
-+		ultra_enable |= (0x01 << drive->dn);
-+	} else if (speed >= XFER_MW_DMA_0)
-+		dma_timing   |= dma_modes[speed - XFER_MW_DMA_0];
+-	if (send_wr->send_flags & IB_SEND_SIGNALED)
++	if ((send_wr->send_flags & IB_SEND_SIGNALED ||
++	    qp->init_attr.sq_sig_type == IB_SIGNAL_ALL_WR)
++	    && !hidden)
+ 		wqe_p->wr_flag |= WQE_WRFLAG_REQ_SIGNAL_COM;
  
- 	pci_write_config_byte(dev, drive_pci2[drive->dn], dma_timing);
- 	pci_write_config_byte(dev, (0x56|hwif->channel), ultra_timing);
-@@ -366,12 +353,17 @@ static void __devinit init_hwif_svwks (ide_hwif_t *hwif)
- 	}
- }
+ 	if (send_wr->opcode == IB_WR_SEND_WITH_IMM ||
+@@ -199,7 +205,7 @@ static inline int ehca_write_swqe(struct ehca_qp *qp,
+ 
+ 		wqe_p->destination_qp_number = send_wr->wr.ud.remote_qpn << 8;
+ 		wqe_p->local_ee_context_qkey = remote_qkey;
+-		if (!send_wr->wr.ud.ah) {
++		if (unlikely(!send_wr->wr.ud.ah)) {
+ 			ehca_gen_err("wr.ud.ah is NULL. qp=%p", qp);
+ 			return -EINVAL;
+ 		}
+@@ -255,6 +261,15 @@ static inline int ehca_write_swqe(struct ehca_qp *qp,
+ 		} /* eof idx */
+ 		wqe_p->u.nud.atomic_1st_op_dma_len = dma_length;
  
-+#define IDE_HFLAGS_SVWKS \
-+	(IDE_HFLAG_LEGACY_IRQS | \
-+	 IDE_HFLAG_ABUSE_SET_DMA_MODE | \
-+	 IDE_HFLAG_BOOTABLE)
++		/* unsolicited ack circumvention */
++		if (send_wr->opcode == IB_WR_RDMA_READ) {
++			/* on RDMA read, switch on and reset counters */
++			qp->message_count = qp->packet_count = 0;
++			qp->unsol_ack_circ = 1;
++		} else
++			/* else estimate #packets */
++			qp->packet_count += (dma_length >> qp->mtu_shift) + 1;
 +
- static const struct ide_port_info serverworks_chipsets[] __devinitdata = {
- 	{	/* 0 */
- 		.name		= "SvrWks OSB4",
- 		.init_chipset	= init_chipset_svwks,
- 		.init_hwif	= init_hwif_svwks,
--		.host_flags	= IDE_HFLAG_LEGACY_IRQS | IDE_HFLAG_BOOTABLE,
-+		.host_flags	= IDE_HFLAGS_SVWKS,
- 		.pio_mask	= ATA_PIO4,
- 		.mwdma_mask	= ATA_MWDMA2,
- 		.udma_mask	= 0x00, /* UDMA is problematic on OSB4 */
-@@ -379,7 +371,7 @@ static const struct ide_port_info serverworks_chipsets[] __devinitdata = {
- 		.name		= "SvrWks CSB5",
- 		.init_chipset	= init_chipset_svwks,
- 		.init_hwif	= init_hwif_svwks,
--		.host_flags	= IDE_HFLAG_LEGACY_IRQS | IDE_HFLAG_BOOTABLE,
-+		.host_flags	= IDE_HFLAGS_SVWKS,
- 		.pio_mask	= ATA_PIO4,
- 		.mwdma_mask	= ATA_MWDMA2,
- 		.udma_mask	= ATA_UDMA5,
-@@ -387,7 +379,7 @@ static const struct ide_port_info serverworks_chipsets[] __devinitdata = {
- 		.name		= "SvrWks CSB6",
- 		.init_chipset	= init_chipset_svwks,
- 		.init_hwif	= init_hwif_svwks,
--		.host_flags	= IDE_HFLAG_LEGACY_IRQS | IDE_HFLAG_BOOTABLE,
-+		.host_flags	= IDE_HFLAGS_SVWKS,
- 		.pio_mask	= ATA_PIO4,
- 		.mwdma_mask	= ATA_MWDMA2,
- 		.udma_mask	= ATA_UDMA5,
-@@ -395,8 +387,7 @@ static const struct ide_port_info serverworks_chipsets[] __devinitdata = {
- 		.name		= "SvrWks CSB6",
- 		.init_chipset	= init_chipset_svwks,
- 		.init_hwif	= init_hwif_svwks,
--		.host_flags	= IDE_HFLAG_LEGACY_IRQS | IDE_HFLAG_SINGLE |
--				  IDE_HFLAG_BOOTABLE,
-+		.host_flags	= IDE_HFLAGS_SVWKS | IDE_HFLAG_SINGLE,
- 		.pio_mask	= ATA_PIO4,
- 		.mwdma_mask	= ATA_MWDMA2,
- 		.udma_mask	= ATA_UDMA5,
-@@ -404,8 +395,7 @@ static const struct ide_port_info serverworks_chipsets[] __devinitdata = {
- 		.name		= "SvrWks HT1000",
- 		.init_chipset	= init_chipset_svwks,
- 		.init_hwif	= init_hwif_svwks,
--		.host_flags	= IDE_HFLAG_LEGACY_IRQS | IDE_HFLAG_SINGLE |
--				  IDE_HFLAG_BOOTABLE,
-+		.host_flags	= IDE_HFLAGS_SVWKS | IDE_HFLAG_SINGLE,
- 		.pio_mask	= ATA_PIO4,
- 		.mwdma_mask	= ATA_MWDMA2,
- 		.udma_mask	= ATA_UDMA5,
-diff --git a/drivers/ide/pci/sgiioc4.c b/drivers/ide/pci/sgiioc4.c
-index de820aa..9e0be7d 100644
---- a/drivers/ide/pci/sgiioc4.c
-+++ b/drivers/ide/pci/sgiioc4.c
-@@ -277,21 +277,6 @@ sgiioc4_ide_dma_end(ide_drive_t * drive)
- 	return dma_stat;
- }
+ 		break;
  
--static int
--sgiioc4_ide_dma_on(ide_drive_t * drive)
--{
--	drive->using_dma = 1;
--
--	return 0;
--}
--
--static void sgiioc4_dma_off_quietly(ide_drive_t *drive)
--{
--	drive->using_dma = 0;
--
--	drive->hwif->dma_host_off(drive);
--}
--
- static void sgiioc4_set_dma_mode(ide_drive_t *drive, const u8 speed)
- {
- }
-@@ -303,13 +288,10 @@ sgiioc4_ide_dma_test_irq(ide_drive_t * drive)
- 	return sgiioc4_checkirq(HWIF(drive));
+ 	default:
+@@ -355,13 +370,49 @@ static inline void map_ib_wc_status(u32 cqe_status,
+ 		*wc_status = IB_WC_SUCCESS;
  }
  
--static void sgiioc4_dma_host_on(ide_drive_t * drive)
--{
--}
--
--static void sgiioc4_dma_host_off(ide_drive_t * drive)
-+static void sgiioc4_dma_host_set(ide_drive_t *drive, int on)
++static inline int post_one_send(struct ehca_qp *my_qp,
++			 struct ib_send_wr *cur_send_wr,
++			 struct ib_send_wr **bad_send_wr,
++			 int hidden)
++{
++	struct ehca_wqe *wqe_p;
++	int ret;
++	u64 start_offset = my_qp->ipz_squeue.current_q_offset;
++
++	/* get pointer next to free WQE */
++	wqe_p = ipz_qeit_get_inc(&my_qp->ipz_squeue);
++	if (unlikely(!wqe_p)) {
++		/* too many posted work requests: queue overflow */
++		if (bad_send_wr)
++			*bad_send_wr = cur_send_wr;
++		ehca_err(my_qp->ib_qp.device, "Too many posted WQEs "
++			 "qp_num=%x", my_qp->ib_qp.qp_num);
++		return -ENOMEM;
++	}
++	/* write a SEND WQE into the QUEUE */
++	ret = ehca_write_swqe(my_qp, wqe_p, cur_send_wr, hidden);
++	/*
++	 * if something failed,
++	 * reset the free entry pointer to the start value
++	 */
++	if (unlikely(ret)) {
++		my_qp->ipz_squeue.current_q_offset = start_offset;
++		if (bad_send_wr)
++			*bad_send_wr = cur_send_wr;
++		ehca_err(my_qp->ib_qp.device, "Could not write WQE "
++			 "qp_num=%x", my_qp->ib_qp.qp_num);
++		return -EINVAL;
++	}
++
++	return 0;
++}
++
+ int ehca_post_send(struct ib_qp *qp,
+ 		   struct ib_send_wr *send_wr,
+ 		   struct ib_send_wr **bad_send_wr)
  {
--	sgiioc4_clearirq(drive);
-+	if (!on)
-+		sgiioc4_clearirq(drive);
- }
+ 	struct ehca_qp *my_qp = container_of(qp, struct ehca_qp, ib_qp);
+ 	struct ib_send_wr *cur_send_wr;
+-	struct ehca_wqe *wqe_p;
+ 	int wqe_cnt = 0;
+ 	int ret = 0;
+ 	unsigned long flags;
+@@ -369,37 +420,33 @@ int ehca_post_send(struct ib_qp *qp,
+ 	/* LOCK the QUEUE */
+ 	spin_lock_irqsave(&my_qp->spinlock_s, flags);
  
- static void
-@@ -582,7 +564,6 @@ ide_init_sgiioc4(ide_hwif_t * hwif)
- 	hwif->pre_reset = NULL;	/* No HBA specific pre_set needed */
- 	hwif->resetproc = &sgiioc4_resetproc;/* Reset DMA engine,
- 						clear interrupts */
--	hwif->intrproc = NULL;	/* Enable or Disable interrupt from drive */
- 	hwif->maskproc = &sgiioc4_maskproc;	/* Mask on/off NIEN register */
- 	hwif->quirkproc = NULL;
- 	hwif->busproc = NULL;
-@@ -594,14 +575,11 @@ ide_init_sgiioc4(ide_hwif_t * hwif)
++	/* Send an empty extra RDMA read if:
++	 *  1) there has been an RDMA read on this connection before
++	 *  2) no RDMA read occurred for ACK_CIRC_THRESHOLD link packets
++	 *  3) we can be sure that any previous extra RDMA read has been
++	 *     processed so we don't overflow the SQ
++	 */
++	if (unlikely(my_qp->unsol_ack_circ &&
++		     my_qp->packet_count > ACK_CIRC_THRESHOLD &&
++		     my_qp->message_count > my_qp->init_attr.cap.max_send_wr)) {
++		/* insert an empty RDMA READ to fix up the remote QP state */
++		struct ib_send_wr circ_wr;
++		memset(&circ_wr, 0, sizeof(circ_wr));
++		circ_wr.opcode = IB_WR_RDMA_READ;
++		post_one_send(my_qp, &circ_wr, NULL, 1); /* ignore retcode */
++		wqe_cnt++;
++		ehca_dbg(qp->device, "posted circ wr  qp_num=%x", qp->qp_num);
++		my_qp->message_count = my_qp->packet_count = 0;
++	}
++
+ 	/* loop processes list of send reqs */
+ 	for (cur_send_wr = send_wr; cur_send_wr != NULL;
+ 	     cur_send_wr = cur_send_wr->next) {
+-		u64 start_offset = my_qp->ipz_squeue.current_q_offset;
+-		/* get pointer next to free WQE */
+-		wqe_p = ipz_qeit_get_inc(&my_qp->ipz_squeue);
+-		if (unlikely(!wqe_p)) {
+-			/* too many posted work requests: queue overflow */
+-			if (bad_send_wr)
+-				*bad_send_wr = cur_send_wr;
+-			if (wqe_cnt == 0) {
+-				ret = -ENOMEM;
+-				ehca_err(qp->device, "Too many posted WQEs "
+-					 "qp_num=%x", qp->qp_num);
+-			}
+-			goto post_send_exit0;
+-		}
+-		/* write a SEND WQE into the QUEUE */
+-		ret = ehca_write_swqe(my_qp, wqe_p, cur_send_wr);
+-		/*
+-		 * if something failed,
+-		 * reset the free entry pointer to the start value
+-		 */
++		ret = post_one_send(my_qp, cur_send_wr, bad_send_wr, 0);
+ 		if (unlikely(ret)) {
+-			my_qp->ipz_squeue.current_q_offset = start_offset;
+-			*bad_send_wr = cur_send_wr;
+-			if (wqe_cnt == 0) {
+-				ret = -EINVAL;
+-				ehca_err(qp->device, "Could not write WQE "
+-					 "qp_num=%x", qp->qp_num);
+-			}
++			/* if one or more WQEs were successful, don't fail */
++			if (wqe_cnt)
++				ret = 0;
+ 			goto post_send_exit0;
+ 		}
+ 		wqe_cnt++;
+@@ -410,6 +457,7 @@ int ehca_post_send(struct ib_qp *qp,
+ post_send_exit0:
+ 	iosync(); /* serialize GAL register access */
+ 	hipz_update_sqa(my_qp, wqe_cnt);
++	my_qp->message_count += wqe_cnt;
+ 	spin_unlock_irqrestore(&my_qp->spinlock_s, flags);
+ 	return ret;
+ }
+diff --git a/drivers/infiniband/hw/ehca/ehca_sqp.c b/drivers/infiniband/hw/ehca/ehca_sqp.c
+index f0792e5..79e72b2 100644
+--- a/drivers/infiniband/hw/ehca/ehca_sqp.c
++++ b/drivers/infiniband/hw/ehca/ehca_sqp.c
+@@ -40,11 +40,8 @@
+  */
  
- 	hwif->mwdma_mask = ATA_MWDMA2_ONLY;
  
-+	hwif->dma_host_set = &sgiioc4_dma_host_set;
- 	hwif->dma_setup = &sgiioc4_ide_dma_setup;
- 	hwif->dma_start = &sgiioc4_ide_dma_start;
- 	hwif->ide_dma_end = &sgiioc4_ide_dma_end;
--	hwif->ide_dma_on = &sgiioc4_ide_dma_on;
--	hwif->dma_off_quietly = &sgiioc4_dma_off_quietly;
- 	hwif->ide_dma_test_irq = &sgiioc4_ide_dma_test_irq;
--	hwif->dma_host_on = &sgiioc4_dma_host_on;
--	hwif->dma_host_off = &sgiioc4_dma_host_off;
- 	hwif->dma_lost_irq = &sgiioc4_dma_lost_irq;
- 	hwif->dma_timeout = &ide_dma_timeout;
- }
-@@ -615,6 +593,7 @@ sgiioc4_ide_setup_pci_device(struct pci_dev *dev)
- 	ide_hwif_t *hwif;
- 	int h;
- 	u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
-+	hw_regs_t hw;
+-#include <linux/module.h>
+-#include <linux/err.h>
+ #include "ehca_classes.h"
+ #include "ehca_tools.h"
+-#include "ehca_qes.h"
+ #include "ehca_iverbs.h"
+ #include "hcp_if.h"
  
- 	/*
- 	 * Find an empty HWIF; if none available, return -ENOMEM.
-@@ -654,21 +633,16 @@ sgiioc4_ide_setup_pci_device(struct pci_dev *dev)
- 		return -ENOMEM;
+@@ -93,6 +90,9 @@ u64 ehca_define_sqp(struct ehca_shca *shca,
+ 		return H_PARAMETER;
  	}
  
--	if (hwif->io_ports[IDE_DATA_OFFSET] != cmd_base) {
--		hw_regs_t hw;
--
--		/* Initialize the IO registers */
--		memset(&hw, 0, sizeof(hw));
--		sgiioc4_init_hwif_ports(&hw, cmd_base, ctl, irqport);
--		memcpy(hwif->io_ports, hw.io_ports, sizeof(hwif->io_ports));
--		hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET];
--	}
-+	/* Initialize the IO registers */
-+	memset(&hw, 0, sizeof(hw));
-+	sgiioc4_init_hwif_ports(&hw, cmd_base, ctl, irqport);
-+	hw.irq = dev->irq;
-+	hw.chipset = ide_pci;
-+	hw.dev = &dev->dev;
-+	ide_init_port_hw(hwif, &hw);
++	if (ehca_nr_ports < 0) /* autodetect mode */
++		return H_SUCCESS;
++
+ 	for (counter = 0;
+ 	     shca->sport[port - 1].port_state != IB_PORT_ACTIVE &&
+ 		     counter < ehca_port_act_time;
+diff --git a/drivers/infiniband/hw/ipath/ipath_common.h b/drivers/infiniband/hw/ipath/ipath_common.h
+index 851df8a..4146210 100644
+--- a/drivers/infiniband/hw/ipath/ipath_common.h
++++ b/drivers/infiniband/hw/ipath/ipath_common.h
+@@ -82,6 +82,16 @@
+ #define IPATH_IB_LINK_EXTERNAL	7 /* normal, disable local loopback */
  
--	hwif->irq = dev->irq;
--	hwif->chipset = ide_pci;
- 	hwif->pci_dev = dev;
- 	hwif->channel = 0;	/* Single Channel chip */
--	hwif->gendev.parent = &dev->dev;/* setup proper ancestral information */
+ /*
++ * These 3 values (SDR and DDR may be ORed for auto-speed
++ * negotiation) are used for the 3rd argument to path_f_set_ib_cfg
++ * with cmd IPATH_IB_CFG_SPD_ENB, by direct calls or via sysfs.  They
++ * are also the the possible values for ipath_link_speed_enabled and active
++ * The values were chosen to match values used within the IB spec.
++ */
++#define IPATH_IB_SDR 1
++#define IPATH_IB_DDR 2
++
++/*
+  * stats maintained by the driver.  For now, at least, this is global
+  * to all minor devices.
+  */
+@@ -433,8 +443,9 @@ struct ipath_user_info {
+ #define IPATH_CMD_UNUSED_2	26
+ #define IPATH_CMD_PIOAVAILUPD	27	/* force an update of PIOAvail reg */
+ #define IPATH_CMD_POLL_TYPE	28	/* set the kind of polling we want */
++#define IPATH_CMD_ARMLAUNCH_CTRL	29 /* armlaunch detection control */
  
- 	/* The IOC4 uses MMIO rather than Port IO. */
- 	default_hwif_mmiops(hwif);
-diff --git a/drivers/ide/pci/siimage.c b/drivers/ide/pci/siimage.c
-index 5709c25..908f37b 100644
---- a/drivers/ide/pci/siimage.c
-+++ b/drivers/ide/pci/siimage.c
-@@ -278,27 +278,14 @@ static void sil_set_dma_mode(ide_drive_t *drive, const u8 speed)
+-#define IPATH_CMD_MAX		28
++#define IPATH_CMD_MAX		29
  
- 	scsc = is_sata(hwif) ? 1 : scsc;
+ /*
+  * Poll types
+@@ -477,6 +488,8 @@ struct ipath_cmd {
+ 		__u64 port_info;
+ 		/* enable/disable receipt of packets */
+ 		__u32 recv_ctrl;
++		/* enable/disable armlaunch errors (non-zero to enable) */
++		__u32 armlaunch_ctrl;
+ 		/* partition key to set */
+ 		__u16 part_key;
+ 		/* user address of __u32 bitmask of active slaves */
+@@ -579,7 +592,7 @@ struct ipath_flash {
+ struct infinipath_counters {
+ 	__u64 LBIntCnt;
+ 	__u64 LBFlowStallCnt;
+-	__u64 Reserved1;
++	__u64 TxSDmaDescCnt;	/* was Reserved1 */
+ 	__u64 TxUnsupVLErrCnt;
+ 	__u64 TxDataPktCnt;
+ 	__u64 TxFlowPktCnt;
+@@ -615,12 +628,26 @@ struct infinipath_counters {
+ 	__u64 RxP6HdrEgrOvflCnt;
+ 	__u64 RxP7HdrEgrOvflCnt;
+ 	__u64 RxP8HdrEgrOvflCnt;
+-	__u64 Reserved6;
+-	__u64 Reserved7;
++	__u64 RxP9HdrEgrOvflCnt;	/* was Reserved6 */
++	__u64 RxP10HdrEgrOvflCnt;	/* was Reserved7 */
++	__u64 RxP11HdrEgrOvflCnt;	/* new for IBA7220 */
++	__u64 RxP12HdrEgrOvflCnt;	/* new for IBA7220 */
++	__u64 RxP13HdrEgrOvflCnt;	/* new for IBA7220 */
++	__u64 RxP14HdrEgrOvflCnt;	/* new for IBA7220 */
++	__u64 RxP15HdrEgrOvflCnt;	/* new for IBA7220 */
++	__u64 RxP16HdrEgrOvflCnt;	/* new for IBA7220 */
+ 	__u64 IBStatusChangeCnt;
+ 	__u64 IBLinkErrRecoveryCnt;
+ 	__u64 IBLinkDownedCnt;
+ 	__u64 IBSymbolErrCnt;
++	/* The following are new for IBA7220 */
++	__u64 RxVL15DroppedPktCnt;
++	__u64 RxOtherLocalPhyErrCnt;
++	__u64 PcieRetryBufDiagQwordCnt;
++	__u64 ExcessBufferOvflCnt;
++	__u64 LocalLinkIntegrityErrCnt;
++	__u64 RxVlErrCnt;
++	__u64 RxDlidFltrCnt;
+ };
  
--	switch(speed) {
--		case XFER_MW_DMA_2:
--		case XFER_MW_DMA_1:
--		case XFER_MW_DMA_0:
--			multi = dma[speed - XFER_MW_DMA_0];
--			mode |= ((unit) ? 0x20 : 0x02);
--			break;
--		case XFER_UDMA_6:
--		case XFER_UDMA_5:
--		case XFER_UDMA_4:
--		case XFER_UDMA_3:
--		case XFER_UDMA_2:
--		case XFER_UDMA_1:
--		case XFER_UDMA_0:
--			multi = dma[2];
--			ultra |= ((scsc) ? (ultra6[speed - XFER_UDMA_0]) :
--					   (ultra5[speed - XFER_UDMA_0]));
--			mode |= ((unit) ? 0x30 : 0x03);
--			break;
--		default:
--			return;
-+	if (speed >= XFER_UDMA_0) {
-+		multi = dma[2];
-+		ultra |= (scsc ? ultra6[speed - XFER_UDMA_0] :
-+				 ultra5[speed - XFER_UDMA_0]);
-+		mode |= (unit ? 0x30 : 0x03);
-+	} else {
-+		multi = dma[speed - XFER_MW_DMA_0];
-+		mode |= (unit ? 0x20 : 0x02);
+ /*
+diff --git a/drivers/infiniband/hw/ipath/ipath_cq.c b/drivers/infiniband/hw/ipath/ipath_cq.c
+index d1380c7..a03bd28 100644
+--- a/drivers/infiniband/hw/ipath/ipath_cq.c
++++ b/drivers/infiniband/hw/ipath/ipath_cq.c
+@@ -421,7 +421,7 @@ int ipath_resize_cq(struct ib_cq *ibcq, int cqe, struct ib_udata *udata)
+ 	else
+ 		n = head - tail;
+ 	if (unlikely((u32)cqe < n)) {
+-		ret = -EOVERFLOW;
++		ret = -EINVAL;
+ 		goto bail_unlock;
  	}
+ 	for (n = 0; tail != head; n++) {
+diff --git a/drivers/infiniband/hw/ipath/ipath_debug.h b/drivers/infiniband/hw/ipath/ipath_debug.h
+index 19c56e6..d6f6953 100644
+--- a/drivers/infiniband/hw/ipath/ipath_debug.h
++++ b/drivers/infiniband/hw/ipath/ipath_debug.h
+@@ -55,7 +55,7 @@
+ #define __IPATH_PKTDBG      0x80	/* print packet data */
+ /* print process startup (init)/exit messages */
+ #define __IPATH_PROCDBG     0x100
+-/* print mmap/nopage stuff, not using VDBG any more */
++/* print mmap/fault stuff, not using VDBG any more */
+ #define __IPATH_MMDBG       0x200
+ #define __IPATH_ERRPKTDBG   0x400
+ #define __IPATH_USER_SEND   0x1000	/* use user mode send */
+@@ -81,7 +81,7 @@
+ #define __IPATH_VERBDBG   0x0	/* very verbose debug */
+ #define __IPATH_PKTDBG    0x0	/* print packet data */
+ #define __IPATH_PROCDBG   0x0	/* process startup (init)/exit messages */
+-/* print mmap/nopage stuff, not using VDBG any more */
++/* print mmap/fault stuff, not using VDBG any more */
+ #define __IPATH_MMDBG     0x0
+ #define __IPATH_EPKTDBG   0x0	/* print ethernet packet data */
+ #define __IPATH_IPATHDBG  0x0	/* Ethernet (IPATH) table dump on */
+diff --git a/drivers/infiniband/hw/ipath/ipath_driver.c b/drivers/infiniband/hw/ipath/ipath_driver.c
+index 1f152de..d5ff6ca 100644
+--- a/drivers/infiniband/hw/ipath/ipath_driver.c
++++ b/drivers/infiniband/hw/ipath/ipath_driver.c
+@@ -121,6 +121,9 @@ static struct pci_driver ipath_driver = {
+ 	.probe = ipath_init_one,
+ 	.remove = __devexit_p(ipath_remove_one),
+ 	.id_table = ipath_pci_tbl,
++	.driver = {
++		.groups = ipath_driver_attr_groups,
++	},
+ };
  
- 	if (hwif->mmio) {
-@@ -726,9 +713,6 @@ static int is_dev_seagate_sata(ide_drive_t *drive)
- 	const char *s = &drive->id->model[0];
- 	unsigned len;
+ static void ipath_check_status(struct work_struct *work)
+@@ -331,6 +334,8 @@ static void ipath_verify_pioperf(struct ipath_devdata *dd)
+ 		udelay(1);
+ 	}
  
--	if (!drive->present)
--		return 0;
--
- 	len = strnlen(s, sizeof(drive->id->model));
++	ipath_disable_armlaunch(dd);
++
+ 	writeq(0, piobuf); /* length 0, no dwords actually sent */
+ 	ipath_flush_wc();
  
- 	if ((len > 4) && (!memcmp(s, "ST", 2))) {
-@@ -743,18 +727,20 @@ static int is_dev_seagate_sata(ide_drive_t *drive)
+@@ -362,6 +367,7 @@ static void ipath_verify_pioperf(struct ipath_devdata *dd)
+ done:
+ 	/* disarm piobuf, so it's available again */
+ 	ipath_disarm_piobufs(dd, pbnum, 1);
++	ipath_enable_armlaunch(dd);
  }
  
- /**
-- *	siimage_fixup		-	post probe fixups
-- *	@hwif: interface to fix up
-+ *	sil_quirkproc		-	post probe fixups
-+ *	@drive: drive
-  *
-  *	Called after drive probe we use this to decide whether the
-  *	Seagate fixup must be applied. This used to be in init_iops but
-  *	that can occur before we know what drives are present.
-  */
- 
--static void __devinit siimage_fixup(ide_hwif_t *hwif)
-+static void __devinit sil_quirkproc(ide_drive_t *drive)
+ static int __devinit ipath_init_one(struct pci_dev *pdev,
+@@ -800,31 +806,37 @@ void ipath_disarm_piobufs(struct ipath_devdata *dd, unsigned first,
+ 			  unsigned cnt)
  {
-+	ide_hwif_t *hwif = drive->hwif;
-+
- 	/* Try and raise the rqsize */
--	if (!is_sata(hwif) || !is_dev_seagate_sata(&hwif->drives[0]))
-+	if (!is_sata(hwif) || !is_dev_seagate_sata(drive))
- 		hwif->rqsize = 128;
- }
- 
-@@ -817,6 +803,7 @@ static void __devinit init_hwif_siimage(ide_hwif_t *hwif)
+ 	unsigned i, last = first + cnt;
+-	u64 sendctrl, sendorig;
++	unsigned long flags;
  
- 	hwif->set_pio_mode = &sil_set_pio_mode;
- 	hwif->set_dma_mode = &sil_set_dma_mode;
-+	hwif->quirkproc = &sil_quirkproc;
+ 	ipath_cdbg(PKT, "disarm %u PIObufs first=%u\n", cnt, first);
+-	sendorig = dd->ipath_sendctrl;
+ 	for (i = first; i < last; i++) {
+-		sendctrl = sendorig  | INFINIPATH_S_DISARM |
+-			(i << INFINIPATH_S_DISARMPIOBUF_SHIFT);
++		spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags);
++		/*
++		 * The disarm-related bits are write-only, so it
++		 * is ok to OR them in with our copy of sendctrl
++		 * while we hold the lock.
++		 */
+ 		ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
+-				 sendctrl);
++			dd->ipath_sendctrl | INFINIPATH_S_DISARM |
++			(i << INFINIPATH_S_DISARMPIOBUF_SHIFT));
++		/* can't disarm bufs back-to-back per iba7220 spec */
++		ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
++		spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags);
+ 	}
  
- 	if (sata) {
- 		static int first = 1;
-@@ -855,7 +842,6 @@ static void __devinit init_hwif_siimage(ide_hwif_t *hwif)
- 		.init_chipset	= init_chipset_siimage,	\
- 		.init_iops	= init_iops_siimage,	\
- 		.init_hwif	= init_hwif_siimage,	\
--		.fixup		= siimage_fixup,	\
- 		.host_flags	= IDE_HFLAG_BOOTABLE,	\
- 		.pio_mask	= ATA_PIO4,		\
- 		.mwdma_mask	= ATA_MWDMA2,		\
-diff --git a/drivers/ide/pci/sis5513.c b/drivers/ide/pci/sis5513.c
-index d90b429..85d3699 100644
---- a/drivers/ide/pci/sis5513.c
-+++ b/drivers/ide/pci/sis5513.c
-@@ -305,59 +305,56 @@ static void sis_set_pio_mode(ide_drive_t *drive, const u8 pio)
- 	sis_program_timings(drive, XFER_PIO_0 + pio);
+ 	/*
+-	 * Write it again with current value, in case ipath_sendctrl changed
+-	 * while we were looping; no critical bits that would require
+-	 * locking.
+-	 *
+-	 * disable PIOAVAILUPD, then re-enable, reading scratch in
++	 * Disable PIOAVAILUPD, then re-enable, reading scratch in
+ 	 * between.  This seems to avoid a chip timing race that causes
+-	 * pioavail updates to memory to stop.
++	 * pioavail updates to memory to stop.  We xor as we don't
++	 * know the state of the bit when we're called.
+ 	 */
++	spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags);
+ 	ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
+-			 sendorig & ~INFINIPATH_S_PIOBUFAVAILUPD);
+-	sendorig = ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
++		dd->ipath_sendctrl ^ INFINIPATH_S_PIOBUFAVAILUPD);
++	ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
+ 	ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
+ 			 dd->ipath_sendctrl);
++	spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags);
  }
  
--static void sis_set_dma_mode(ide_drive_t *drive, const u8 speed)
-+static void sis_ata133_program_udma_timings(ide_drive_t *drive, const u8 mode)
+ /**
+@@ -1000,12 +1012,10 @@ static void get_rhf_errstring(u32 err, char *msg, size_t len)
+  * ipath_get_egrbuf - get an eager buffer
+  * @dd: the infinipath device
+  * @bufnum: the eager buffer to get
+- * @err: unused
+  *
+  * must only be called if ipath_pd[port] is known to be allocated
+  */
+-static inline void *ipath_get_egrbuf(struct ipath_devdata *dd, u32 bufnum,
+-				     int err)
++static inline void *ipath_get_egrbuf(struct ipath_devdata *dd, u32 bufnum)
  {
--	ide_hwif_t *hwif	= HWIF(drive);
--	struct pci_dev *dev	= hwif->pci_dev;
-+	struct pci_dev *dev = drive->hwif->pci_dev;
-+	u32 regdw = 0;
-+	u8 drive_pci = sis_ata133_get_base(drive), clk, idx;
- 
--	/* Config chip for mode */
--	switch(speed) {
--		case XFER_UDMA_6:
--		case XFER_UDMA_5:
--		case XFER_UDMA_4:
--		case XFER_UDMA_3:
--		case XFER_UDMA_2:
--		case XFER_UDMA_1:
--		case XFER_UDMA_0:
--			if (chipset_family >= ATA_133) {
--				u32 regdw = 0;
--				u8 drive_pci = sis_ata133_get_base(drive);
--
--				pci_read_config_dword(dev, drive_pci, &regdw);
--				regdw |= 0x04;
--				regdw &= 0xfffff00f;
--				/* check if ATA133 enable */
--				if (regdw & 0x08) {
--					regdw |= (unsigned long)cycle_time_value[ATA_133][speed-XFER_UDMA_0] << 4;
--					regdw |= (unsigned long)cvs_time_value[ATA_133][speed-XFER_UDMA_0] << 8;
--				} else {
--					regdw |= (unsigned long)cycle_time_value[ATA_100][speed-XFER_UDMA_0] << 4;
--					regdw |= (unsigned long)cvs_time_value[ATA_100][speed-XFER_UDMA_0] << 8;
--				}
--				pci_write_config_dword(dev, (unsigned long)drive_pci, regdw);
--			} else {
--				u8 drive_pci = 0x40 + drive->dn * 2, reg = 0;
--
--				pci_read_config_byte(dev, drive_pci+1, &reg);
--				/* Force the UDMA bit on if we want to use UDMA */
--				reg |= 0x80;
--				/* clean reg cycle time bits */
--				reg &= ~((0xFF >> (8 - cycle_time_range[chipset_family]))
--					 << cycle_time_offset[chipset_family]);
--				/* set reg cycle time bits */
--				reg |= cycle_time_value[chipset_family][speed-XFER_UDMA_0]
--					<< cycle_time_offset[chipset_family];
--				pci_write_config_byte(dev, drive_pci+1, reg);
--			}
--			break;
--		case XFER_MW_DMA_2:
--		case XFER_MW_DMA_1:
--		case XFER_MW_DMA_0:
--			sis_program_timings(drive, speed);
--			break;
--		default:
--			break;
--	}
-+	pci_read_config_dword(dev, drive_pci, &regdw);
-+
-+	regdw |= 0x04;
-+	regdw &= 0xfffff00f;
-+	/* check if ATA133 enable */
-+	clk = (regdw & 0x08) ? ATA_133 : ATA_100;
-+	idx = mode - XFER_UDMA_0;
-+	regdw |= cycle_time_value[clk][idx] << 4;
-+	regdw |= cvs_time_value[clk][idx] << 8;
-+
-+	pci_write_config_dword(dev, drive_pci, regdw);
-+}
-+
-+static void sis_ata33_program_udma_timings(ide_drive_t *drive, const u8 mode)
-+{
-+	struct pci_dev *dev = drive->hwif->pci_dev;
-+	u8 drive_pci = 0x40 + drive->dn * 2, reg = 0, i = chipset_family;
-+
-+	pci_read_config_byte(dev, drive_pci + 1, &reg);
-+
-+	/* force the UDMA bit on if we want to use UDMA */
-+	reg |= 0x80;
-+	/* clean reg cycle time bits */
-+	reg &= ~((0xff >> (8 - cycle_time_range[i])) << cycle_time_offset[i]);
-+	/* set reg cycle time bits */
-+	reg |= cycle_time_value[i][mode - XFER_UDMA_0] << cycle_time_offset[i];
-+
-+	pci_write_config_byte(dev, drive_pci + 1, reg);
-+}
-+
-+static void sis_program_udma_timings(ide_drive_t *drive, const u8 mode)
-+{
-+	if (chipset_family >= ATA_133)	/* ATA_133 */
-+		sis_ata133_program_udma_timings(drive, mode);
-+	else				/* ATA_33/66/100a/100/133a */
-+		sis_ata33_program_udma_timings(drive, mode);
-+}
-+
-+static void sis_set_dma_mode(ide_drive_t *drive, const u8 speed)
-+{
-+	if (speed >= XFER_UDMA_0)
-+		sis_program_udma_timings(drive, speed);
-+	else
-+		sis_program_timings(drive, speed);
- }
+ 	return dd->ipath_port0_skbinfo ?
+ 		(void *) dd->ipath_port0_skbinfo[bufnum].skb->data : NULL;
+@@ -1097,13 +1107,14 @@ static void ipath_rcv_hdrerr(struct ipath_devdata *dd,
  
- static u8 sis5513_ata133_udma_filter(ide_drive_t *drive)
-diff --git a/drivers/ide/pci/sl82c105.c b/drivers/ide/pci/sl82c105.c
-index 147d783..c7a125b 100644
---- a/drivers/ide/pci/sl82c105.c
-+++ b/drivers/ide/pci/sl82c105.c
-@@ -13,6 +13,7 @@
-  *  -- Benjamin Herrenschmidt (01/11/03) benh at kernel.crashing.org
+ /*
+  * ipath_kreceive - receive a packet
+- * @dd: the infinipath device
++ * @pd: the infinipath port
   *
-  * Copyright (C) 2006-2007 MontaVista Software, Inc. <source at mvista.com>
-+ * Copyright (C)      2007 Bartlomiej Zolnierkiewicz
+  * called from interrupt handler for errors or receive interrupt
   */
+-void ipath_kreceive(struct ipath_devdata *dd)
++void ipath_kreceive(struct ipath_portdata *pd)
+ {
+ 	u64 *rc;
++	struct ipath_devdata *dd = pd->port_dd;
+ 	void *ebuf;
+ 	const u32 rsize = dd->ipath_rcvhdrentsize;	/* words */
+ 	const u32 maxcnt = dd->ipath_rcvhdrcnt * rsize;	/* words */
+@@ -1118,8 +1129,8 @@ void ipath_kreceive(struct ipath_devdata *dd)
+ 		goto bail;
+ 	}
  
- #include <linux/types.h>
-@@ -90,14 +91,8 @@ static void sl82c105_set_pio_mode(ide_drive_t *drive, const u8 pio)
- 	drive->drive_data &= 0xffff0000;
- 	drive->drive_data |= drv_ctrl;
+-	l = dd->ipath_port0head;
+-	hdrqtail = (u32) le64_to_cpu(*dd->ipath_hdrqtailptr);
++	l = pd->port_head;
++	hdrqtail = ipath_get_rcvhdrtail(pd);
+ 	if (l == hdrqtail)
+ 		goto bail;
  
--	if (!drive->using_dma) {
--		/*
--		 * If we are actually using MW DMA, then we can not
--		 * reprogram the interface drive control register.
--		 */
--		pci_write_config_word(dev, reg,  drv_ctrl);
--		pci_read_config_word (dev, reg, &drv_ctrl);
--	}
-+	pci_write_config_word(dev, reg,  drv_ctrl);
-+	pci_read_config_word (dev, reg, &drv_ctrl);
+@@ -1128,7 +1139,7 @@ reloop:
+ 		u32 qp;
+ 		u8 *bthbytes;
  
- 	printk(KERN_DEBUG "%s: selected %s (%dns) (%04X)\n", drive->name,
- 			  ide_xfer_verbose(pio + XFER_PIO_0),
-@@ -115,33 +110,14 @@ static void sl82c105_set_dma_mode(ide_drive_t *drive, const u8 speed)
-  	DBG(("sl82c105_tune_chipset(drive:%s, speed:%s)\n",
- 	     drive->name, ide_xfer_verbose(speed)));
+-		rc = (u64 *) (dd->ipath_pd[0]->port_rcvhdrq + (l << 2));
++		rc = (u64 *) (pd->port_rcvhdrq + (l << 2));
+ 		hdr = (struct ipath_message_header *)&rc[1];
+ 		/*
+ 		 * could make a network order version of IPATH_KD_QP, and
+@@ -1153,7 +1164,7 @@ reloop:
+ 			etail = ipath_hdrget_index((__le32 *) rc);
+ 			if (tlen > sizeof(*hdr) ||
+ 			    etype == RCVHQ_RCV_TYPE_NON_KD)
+-				ebuf = ipath_get_egrbuf(dd, etail, 0);
++				ebuf = ipath_get_egrbuf(dd, etail);
+ 		}
  
--	switch (speed) {
--	case XFER_MW_DMA_2:
--	case XFER_MW_DMA_1:
--	case XFER_MW_DMA_0:
--		drv_ctrl = mwdma_timings[speed - XFER_MW_DMA_0];
-+	drv_ctrl = mwdma_timings[speed - XFER_MW_DMA_0];
+ 		/*
+@@ -1188,7 +1199,7 @@ reloop:
+ 				  be32_to_cpu(hdr->bth[0]) & 0xff);
+ 		else {
+ 			/*
+-			 * error packet, type of error	unknown.
++			 * error packet, type of error unknown.
+ 			 * Probably type 3, but we don't know, so don't
+ 			 * even try to print the opcode, etc.
+ 			 */
+@@ -1238,7 +1249,7 @@ reloop:
+ 		 * earlier packets, we "almost" guarantee we have covered
+ 		 * that case.
+ 		 */
+-		u32 hqtail = (u32)le64_to_cpu(*dd->ipath_hdrqtailptr);
++		u32 hqtail = ipath_get_rcvhdrtail(pd);
+ 		if (hqtail != hdrqtail) {
+ 			hdrqtail = hqtail;
+ 			reloop = 1; /* loop 1 extra time at most */
+@@ -1248,7 +1259,7 @@ reloop:
  
--		/*
--		 * Store the DMA timings so that we can actually program
--		 * them when DMA will be turned on...
--		 */
--		drive->drive_data &= 0x0000ffff;
--		drive->drive_data |= (unsigned long)drv_ctrl << 16;
--
--		/*
--		 * If we are already using DMA, we just reprogram
--		 * the drive control register.
--		 */
--		if (drive->using_dma) {
--			struct pci_dev *dev	= HWIF(drive)->pci_dev;
--			int reg 		= 0x44 + drive->dn * 4;
--
--			pci_write_config_word(dev, reg, drv_ctrl);
--		}
--		break;
--	default:
--		return;
--	}
-+	/*
-+	 * Store the DMA timings so that we can actually program
-+	 * them when DMA will be turned on...
-+	 */
-+	drive->drive_data &= 0x0000ffff;
-+	drive->drive_data |= (unsigned long)drv_ctrl << 16;
- }
+ 	pkttot += i;
  
- /*
-@@ -209,6 +185,11 @@ static void sl82c105_dma_start(ide_drive_t *drive)
- {
- 	ide_hwif_t *hwif	= HWIF(drive);
- 	struct pci_dev *dev	= hwif->pci_dev;
-+	int reg 		= 0x44 + drive->dn * 4;
-+
-+	DBG(("%s(drive:%s)\n", __FUNCTION__, drive->name));
-+
-+	pci_write_config_word(dev, reg, drive->drive_data >> 16);
+-	dd->ipath_port0head = l;
++	pd->port_head = l;
  
- 	sl82c105_reset_host(dev);
- 	ide_dma_start(drive);
-@@ -222,64 +203,24 @@ static void sl82c105_dma_timeout(ide_drive_t *drive)
- 	ide_dma_timeout(drive);
+ 	if (pkttot > ipath_stats.sps_maxpkts_call)
+ 		ipath_stats.sps_maxpkts_call = pkttot;
+@@ -1332,14 +1343,9 @@ static void ipath_update_pio_bufs(struct ipath_devdata *dd)
+ 		/*
+ 		 * Chip Errata: bug 6641; even and odd qwords>3 are swapped
+ 		 */
+-		if (i > 3) {
+-			if (i & 1)
+-				piov = le64_to_cpu(
+-					dd->ipath_pioavailregs_dma[i - 1]);
+-			else
+-				piov = le64_to_cpu(
+-					dd->ipath_pioavailregs_dma[i + 1]);
+-		} else
++		if (i > 3 && (dd->ipath_flags & IPATH_SWAP_PIOBUFS))
++			piov = le64_to_cpu(dd->ipath_pioavailregs_dma[i ^ 1]);
++		else
+ 			piov = le64_to_cpu(dd->ipath_pioavailregs_dma[i]);
+ 		pchg = _IPATH_ALL_CHECKBITS &
+ 			~(dd->ipath_pioavailshadow[i] ^ piov);
+@@ -1598,7 +1604,8 @@ int ipath_create_rcvhdrq(struct ipath_devdata *dd,
+ 
+ 	/* clear for security and sanity on each use */
+ 	memset(pd->port_rcvhdrq, 0, pd->port_rcvhdrq_size);
+-	memset(pd->port_rcvhdrtail_kvaddr, 0, PAGE_SIZE);
++	if (pd->port_rcvhdrtail_kvaddr)
++		memset(pd->port_rcvhdrtail_kvaddr, 0, PAGE_SIZE);
+ 
+ 	/*
+ 	 * tell chip each time we init it, even if we are re-using previous
+@@ -1614,77 +1621,6 @@ bail:
+ 	return ret;
  }
  
--static int sl82c105_ide_dma_on(ide_drive_t *drive)
+-int ipath_waitfor_complete(struct ipath_devdata *dd, ipath_kreg reg_id,
+-			   u64 bits_to_wait_for, u64 * valp)
 -{
--	struct pci_dev *dev	= HWIF(drive)->pci_dev;
--	int rc, reg 		= 0x44 + drive->dn * 4;
--
--	DBG(("sl82c105_ide_dma_on(drive:%s)\n", drive->name));
+-	unsigned long timeout;
+-	u64 lastval, val;
+-	int ret;
 -
--	rc = __ide_dma_on(drive);
--	if (rc == 0) {
--		pci_write_config_word(dev, reg, drive->drive_data >> 16);
+-	lastval = ipath_read_kreg64(dd, reg_id);
+-	/* wait a ridiculously long time */
+-	timeout = jiffies + msecs_to_jiffies(5);
+-	do {
+-		val = ipath_read_kreg64(dd, reg_id);
+-		/* set so they have something, even on failures. */
+-		*valp = val;
+-		if ((val & bits_to_wait_for) == bits_to_wait_for) {
+-			ret = 0;
+-			break;
+-		}
+-		if (val != lastval)
+-			ipath_cdbg(VERBOSE, "Changed from %llx to %llx, "
+-				   "waiting for %llx bits\n",
+-				   (unsigned long long) lastval,
+-				   (unsigned long long) val,
+-				   (unsigned long long) bits_to_wait_for);
+-		cond_resched();
+-		if (time_after(jiffies, timeout)) {
+-			ipath_dbg("Didn't get bits %llx in register 0x%x, "
+-				  "got %llx\n",
+-				  (unsigned long long) bits_to_wait_for,
+-				  reg_id, (unsigned long long) *valp);
+-			ret = -ENODEV;
+-			break;
+-		}
+-	} while (1);
 -
--		printk(KERN_INFO "%s: DMA enabled\n", drive->name);
--	}
--	return rc;
+-	return ret;
 -}
 -
--static void sl82c105_dma_off_quietly(ide_drive_t *drive)
-+static int sl82c105_dma_end(ide_drive_t *drive)
- {
- 	struct pci_dev *dev	= HWIF(drive)->pci_dev;
- 	int reg 		= 0x44 + drive->dn * 4;
-+	int ret;
- 
--	DBG(("sl82c105_dma_off_quietly(drive:%s)\n", drive->name));
-+	DBG(("%s(drive:%s)\n", __FUNCTION__, drive->name));
- 
--	pci_write_config_word(dev, reg, drive->drive_data);
-+	ret = __ide_dma_end(drive);
- 
--	ide_dma_off_quietly(drive);
--}
-+	pci_write_config_word(dev, reg, drive->drive_data);
- 
--/*
-- * Ok, that is nasty, but we must make sure the DMA timings
-- * won't be used for a PIO access. The solution here is
-- * to make sure the 16 bits mode is diabled on the channel
-- * when DMA is enabled, thus causing the chip to use PIO0
-- * timings for those operations.
+-/**
+- * ipath_waitfor_mdio_cmdready - wait for last command to complete
+- * @dd: the infinipath device
+- *
+- * Like ipath_waitfor_complete(), but we wait for the CMDVALID bit to go
+- * away indicating the last command has completed.  It doesn't return data
 - */
--static void sl82c105_selectproc(ide_drive_t *drive)
+-int ipath_waitfor_mdio_cmdready(struct ipath_devdata *dd)
 -{
--	ide_hwif_t *hwif	= HWIF(drive);
--	struct pci_dev *dev	= hwif->pci_dev;
--	u32 val, old, mask;
+-	unsigned long timeout;
+-	u64 val;
+-	int ret;
 -
--	//DBG(("sl82c105_selectproc(drive:%s)\n", drive->name));
+-	/* wait a ridiculously long time */
+-	timeout = jiffies + msecs_to_jiffies(5);
+-	do {
+-		val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_mdio);
+-		if (!(val & IPATH_MDIO_CMDVALID)) {
+-			ret = 0;
+-			break;
+-		}
+-		cond_resched();
+-		if (time_after(jiffies, timeout)) {
+-			ipath_dbg("CMDVALID stuck in mdio reg? (%llx)\n",
+-				  (unsigned long long) val);
+-			ret = -ENODEV;
+-			break;
+-		}
+-	} while (1);
+-
+-	return ret;
+-}
 -
--	mask = hwif->channel ? CTRL_P1F16 : CTRL_P0F16;
--	old = val = (u32)pci_get_drvdata(dev);
--	if (drive->using_dma)
--		val &= ~mask;
--	else
--		val |= mask;
--	if (old != val) {
--		pci_write_config_dword(dev, 0x40, val);	
--		pci_set_drvdata(dev, (void *)val);
--	}
-+	return ret;
- }
  
  /*
-  * ATA reset will clear the 16 bits mode in the control
-- * register, we need to update our cache
-+ * register, we need to reprogram it
+  * Flush all sends that might be in the ready to send state, as well as any
+@@ -2053,6 +1989,8 @@ void ipath_set_led_override(struct ipath_devdata *dd, unsigned int val)
   */
- static void sl82c105_resetproc(ide_drive_t *drive)
+ void ipath_shutdown_device(struct ipath_devdata *dd)
  {
-@@ -289,7 +230,8 @@ static void sl82c105_resetproc(ide_drive_t *drive)
- 	DBG(("sl82c105_resetproc(drive:%s)\n", drive->name));
- 
- 	pci_read_config_dword(dev, 0x40, &val);
--	pci_set_drvdata(dev, (void *)val);
-+	val |= (CTRL_P1F16 | CTRL_P0F16);
-+	pci_write_config_dword(dev, 0x40, val);
- }
- 
- /*
-@@ -342,7 +284,6 @@ static unsigned int __devinit init_chipset_sl82c105(struct pci_dev *dev, const c
- 	pci_read_config_dword(dev, 0x40, &val);
- 	val |= CTRL_P0EN | CTRL_P0F16 | CTRL_P1F16;
- 	pci_write_config_dword(dev, 0x40, val);
--	pci_set_drvdata(dev, (void *)val);
- 
- 	return dev->irq;
- }
-@@ -358,7 +299,6 @@ static void __devinit init_hwif_sl82c105(ide_hwif_t *hwif)
- 
- 	hwif->set_pio_mode	= &sl82c105_set_pio_mode;
- 	hwif->set_dma_mode	= &sl82c105_set_dma_mode;
--	hwif->selectproc	= &sl82c105_selectproc;
- 	hwif->resetproc 	= &sl82c105_resetproc;
- 
- 	if (!hwif->dma_base)
-@@ -377,10 +317,9 @@ static void __devinit init_hwif_sl82c105(ide_hwif_t *hwif)
- 
- 	hwif->mwdma_mask = ATA_MWDMA2;
- 
--	hwif->ide_dma_on		= &sl82c105_ide_dma_on;
--	hwif->dma_off_quietly		= &sl82c105_dma_off_quietly;
- 	hwif->dma_lost_irq		= &sl82c105_dma_lost_irq;
- 	hwif->dma_start			= &sl82c105_dma_start;
-+	hwif->ide_dma_end		= &sl82c105_dma_end;
- 	hwif->dma_timeout		= &sl82c105_dma_timeout;
++	unsigned long flags;
++
+ 	ipath_dbg("Shutting down the device\n");
  
- 	if (hwif->mate)
-diff --git a/drivers/ide/pci/slc90e66.c b/drivers/ide/pci/slc90e66.c
-index eb4445b..dbbb468 100644
---- a/drivers/ide/pci/slc90e66.c
-+++ b/drivers/ide/pci/slc90e66.c
-@@ -91,19 +91,9 @@ static void slc90e66_set_dma_mode(ide_drive_t *drive, const u8 speed)
- 	pci_read_config_word(dev, 0x48, &reg48);
- 	pci_read_config_word(dev, 0x4a, &reg4a);
+ 	dd->ipath_flags |= IPATH_LINKUNK;
+@@ -2073,9 +2011,13 @@ void ipath_shutdown_device(struct ipath_devdata *dd)
+ 	 * gracefully stop all sends allowing any in progress to trickle out
+ 	 * first.
+ 	 */
+-	ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, 0ULL);
++	spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags);
++	dd->ipath_sendctrl = 0;
++	ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, dd->ipath_sendctrl);
+ 	/* flush it */
+ 	ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
++	spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags);
++
+ 	/*
+ 	 * enough for anything that's going to trickle out to have actually
+ 	 * done so.
+@@ -2217,25 +2159,15 @@ static int __init infinipath_init(void)
+ 		goto bail_unit;
+ 	}
  
--	switch(speed) {
--		case XFER_UDMA_4:	u_speed = 4 << (drive->dn * 4); break;
--		case XFER_UDMA_3:	u_speed = 3 << (drive->dn * 4); break;
--		case XFER_UDMA_2:	u_speed = 2 << (drive->dn * 4); break;
--		case XFER_UDMA_1:	u_speed = 1 << (drive->dn * 4); break;
--		case XFER_UDMA_0:	u_speed = 0 << (drive->dn * 4); break;
--		case XFER_MW_DMA_2:
--		case XFER_MW_DMA_1:
--		case XFER_SW_DMA_2:	break;
--		default:		return;
+-	ret = ipath_driver_create_group(&ipath_driver.driver);
+-	if (ret < 0) {
+-		printk(KERN_ERR IPATH_DRV_NAME ": Unable to create driver "
+-		       "sysfs entries: error %d\n", -ret);
+-		goto bail_pci;
 -	}
 -
- 	if (speed >= XFER_UDMA_0) {
-+		u_speed = (speed - XFER_UDMA_0) << (drive->dn * 4);
-+
- 		if (!(reg48 & u_flag))
- 			pci_write_config_word(dev, 0x48, reg48|u_flag);
- 		/* FIXME: (reg4a & a_speed) ? */
-diff --git a/drivers/ide/pci/tc86c001.c b/drivers/ide/pci/tc86c001.c
-index a66ebd1..e1faf6c 100644
---- a/drivers/ide/pci/tc86c001.c
-+++ b/drivers/ide/pci/tc86c001.c
-@@ -222,7 +222,8 @@ static const struct ide_port_info tc86c001_chipset __devinitdata = {
- 	.name		= "TC86C001",
- 	.init_chipset	= init_chipset_tc86c001,
- 	.init_hwif	= init_hwif_tc86c001,
--	.host_flags	= IDE_HFLAG_SINGLE | IDE_HFLAG_OFF_BOARD,
-+	.host_flags	= IDE_HFLAG_SINGLE | IDE_HFLAG_OFF_BOARD |
-+			  IDE_HFLAG_ABUSE_SET_DMA_MODE,
- 	.pio_mask	= ATA_PIO4,
- 	.mwdma_mask	= ATA_MWDMA2,
- 	.udma_mask	= ATA_UDMA4,
-diff --git a/drivers/ide/pci/triflex.c b/drivers/ide/pci/triflex.c
-index a227c41..ae52a96 100644
---- a/drivers/ide/pci/triflex.c
-+++ b/drivers/ide/pci/triflex.c
-@@ -81,8 +81,6 @@ static void triflex_set_mode(ide_drive_t *drive, const u8 speed)
- 		case XFER_PIO_0:
- 			timing = 0x0808;
- 			break;
--		default:
--			return;
+ 	ret = ipath_init_ipathfs();
+ 	if (ret < 0) {
+ 		printk(KERN_ERR IPATH_DRV_NAME ": Unable to create "
+ 		       "ipathfs: error %d\n", -ret);
+-		goto bail_group;
++		goto bail_pci;
  	}
  
- 	triflex_timings &= ~(0xFFFF << (16 * unit));
-diff --git a/drivers/ide/pci/trm290.c b/drivers/ide/pci/trm290.c
-index 0151d7f..04cd893 100644
---- a/drivers/ide/pci/trm290.c
-+++ b/drivers/ide/pci/trm290.c
-@@ -241,11 +241,7 @@ static int trm290_ide_dma_test_irq (ide_drive_t *drive)
- 	return (status == 0x00ff);
- }
+ 	goto bail;
  
--static void trm290_dma_host_on(ide_drive_t *drive)
--{
--}
+-bail_group:
+-	ipath_driver_remove_group(&ipath_driver.driver);
 -
--static void trm290_dma_host_off(ide_drive_t *drive)
-+static void trm290_dma_host_set(ide_drive_t *drive, int on)
- {
- }
+ bail_pci:
+ 	pci_unregister_driver(&ipath_driver);
  
-@@ -289,8 +285,7 @@ static void __devinit init_hwif_trm290(ide_hwif_t *hwif)
+@@ -2250,8 +2182,6 @@ static void __exit infinipath_cleanup(void)
+ {
+ 	ipath_exit_ipathfs();
  
- 	ide_setup_dma(hwif, (hwif->config_data + 4) ^ (hwif->channel ? 0x0080 : 0x0000), 3);
+-	ipath_driver_remove_group(&ipath_driver.driver);
+-
+ 	ipath_cdbg(VERBOSE, "Unregistering pci driver\n");
+ 	pci_unregister_driver(&ipath_driver);
  
--	hwif->dma_host_off	= &trm290_dma_host_off;
--	hwif->dma_host_on	= &trm290_dma_host_on;
-+	hwif->dma_host_set	= &trm290_dma_host_set;
- 	hwif->dma_setup 	= &trm290_dma_setup;
- 	hwif->dma_exec_cmd	= &trm290_dma_exec_cmd;
- 	hwif->dma_start 	= &trm290_dma_start;
-diff --git a/drivers/ide/pci/via82cxxx.c b/drivers/ide/pci/via82cxxx.c
-index a0d3c16..4b32c90 100644
---- a/drivers/ide/pci/via82cxxx.c
-+++ b/drivers/ide/pci/via82cxxx.c
-@@ -439,6 +439,7 @@ static const struct ide_port_info via82cxxx_chipset __devinitdata = {
- 	.enablebits	= { { 0x40, 0x02, 0x02 }, { 0x40, 0x01, 0x01 } },
- 	.host_flags	= IDE_HFLAG_PIO_NO_BLACKLIST |
- 			  IDE_HFLAG_PIO_NO_DOWNGRADE |
-+			  IDE_HFLAG_ABUSE_SET_DMA_MODE |
- 			  IDE_HFLAG_POST_SET_MODE |
- 			  IDE_HFLAG_IO_32BIT |
- 			  IDE_HFLAG_BOOTABLE,
-diff --git a/drivers/ide/ppc/Makefile b/drivers/ide/ppc/Makefile
-new file mode 100644
-index 0000000..65af584
---- /dev/null
-+++ b/drivers/ide/ppc/Makefile
-@@ -0,0 +1,3 @@
-+
-+obj-$(CONFIG_BLK_DEV_IDE_PMAC)		+= pmac.o
-+obj-$(CONFIG_BLK_DEV_MPC8xx_IDE)	+= mpc8xx.o
-diff --git a/drivers/ide/ppc/mpc8xx.c b/drivers/ide/ppc/mpc8xx.c
-index 5f0da35..3fd5d45 100644
---- a/drivers/ide/ppc/mpc8xx.c
-+++ b/drivers/ide/ppc/mpc8xx.c
-@@ -838,3 +838,21 @@ void m8xx_ide_init(void)
- 	ppc_ide_md.default_io_base      = m8xx_ide_default_io_base;
- 	ppc_ide_md.ide_init_hwif        = m8xx_ide_init_hwif_ports;
+@@ -2344,5 +2274,34 @@ int ipath_set_rx_pol_inv(struct ipath_devdata *dd, u8 new_pol_inv)
+ 	}
+ 	return 0;
  }
 +
-+static int __init mpc8xx_ide_probe(void)
++/*
++ * Disable and enable the armlaunch error.  Used for PIO bandwidth testing on
++ * the 7220, which is count-based, rather than trigger-based.  Safe for the
++ * driver check, since it's at init.   Not completely safe when used for
++ * user-mode checking, since some error checking can be lost, but not
++ * particularly risky, and only has problematic side-effects in the face of
++ * very buggy user code.  There is no reference counting, but that's also
++ * fine, given the intended use.
++ */
++void ipath_enable_armlaunch(struct ipath_devdata *dd)
 +{
-+	u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
-+
-+#ifdef IDE0_BASE_OFFSET
-+	idx[0] = 0;
-+#ifdef IDE1_BASE_OFFSET
-+	idx[1] = 1;
-+#endif
-+#endif
-+
-+	ide_device_add(idx);
++	dd->ipath_lasterror &= ~INFINIPATH_E_SPIOARMLAUNCH;
++	ipath_write_kreg(dd, dd->ipath_kregs->kr_errorclear,
++		INFINIPATH_E_SPIOARMLAUNCH);
++	dd->ipath_errormask |= INFINIPATH_E_SPIOARMLAUNCH;
++	ipath_write_kreg(dd, dd->ipath_kregs->kr_errormask,
++		dd->ipath_errormask);
++}
 +
-+	return 0;
++void ipath_disable_armlaunch(struct ipath_devdata *dd)
++{
++	/* so don't re-enable if already set */
++	dd->ipath_maskederrs &= ~INFINIPATH_E_SPIOARMLAUNCH;
++	dd->ipath_errormask &= ~INFINIPATH_E_SPIOARMLAUNCH;
++	ipath_write_kreg(dd, dd->ipath_kregs->kr_errormask,
++		dd->ipath_errormask);
 +}
 +
-+module_init(mpc8xx_ide_probe);
-diff --git a/drivers/ide/ppc/pmac.c b/drivers/ide/ppc/pmac.c
-index 7f7a598..736d12c 100644
---- a/drivers/ide/ppc/pmac.c
-+++ b/drivers/ide/ppc/pmac.c
-@@ -438,13 +438,8 @@ pmac_ide_init_hwif_ports(hw_regs_t *hw,
- 		if (data_port == pmac_ide[ix].regbase)
- 			break;
- 
--	if (ix >= MAX_HWIFS) {
--		/* Probably a PCI interface... */
--		for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; ++i)
--			hw->io_ports[i] = data_port + i - IDE_DATA_OFFSET;
--		hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port;
--		return;
--	}
-+	if (ix >= MAX_HWIFS)
-+		return;		/* not an IDE PMAC interface */
- 
- 	for (i = 0; i < 8; ++i)
- 		hw->io_ports[i] = data_port + i * 0x10;
-@@ -833,38 +828,20 @@ static void pmac_ide_set_dma_mode(ide_drive_t *drive, const u8 speed)
- 	tl[0] = *timings;
- 	tl[1] = *timings2;
+ module_init(infinipath_init);
+ module_exit(infinipath_cleanup);
+diff --git a/drivers/infiniband/hw/ipath/ipath_eeprom.c b/drivers/infiniband/hw/ipath/ipath_eeprom.c
+index e7c25db..e28a42f 100644
+--- a/drivers/infiniband/hw/ipath/ipath_eeprom.c
++++ b/drivers/infiniband/hw/ipath/ipath_eeprom.c
+@@ -510,10 +510,10 @@ int ipath_eeprom_read(struct ipath_devdata *dd, u8 eeprom_offset,
+ {
+ 	int ret;
  
--	switch(speed) {
- #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
--		case XFER_UDMA_6:
--		case XFER_UDMA_5:
--		case XFER_UDMA_4:
--		case XFER_UDMA_3:
--		case XFER_UDMA_2:
--		case XFER_UDMA_1:
--		case XFER_UDMA_0:
--			if (pmif->kind == controller_kl_ata4)
--				ret = set_timings_udma_ata4(&tl[0], speed);
--			else if (pmif->kind == controller_un_ata6
--				 || pmif->kind == controller_k2_ata6)
--				ret = set_timings_udma_ata6(&tl[0], &tl[1], speed);
--			else if (pmif->kind == controller_sh_ata6)
--				ret = set_timings_udma_shasta(&tl[0], &tl[1], speed);
--			else
--				ret = 1;
--			break;
--		case XFER_MW_DMA_2:
--		case XFER_MW_DMA_1:
--		case XFER_MW_DMA_0:
--			set_timings_mdma(drive, pmif->kind, &tl[0], &tl[1], speed);
--			break;
--		case XFER_SW_DMA_2:
--		case XFER_SW_DMA_1:
--		case XFER_SW_DMA_0:
--			return;
-+	if (speed >= XFER_UDMA_0) {
-+		if (pmif->kind == controller_kl_ata4)
-+			ret = set_timings_udma_ata4(&tl[0], speed);
-+		else if (pmif->kind == controller_un_ata6
-+			 || pmif->kind == controller_k2_ata6)
-+			ret = set_timings_udma_ata6(&tl[0], &tl[1], speed);
-+		else if (pmif->kind == controller_sh_ata6)
-+			ret = set_timings_udma_shasta(&tl[0], &tl[1], speed);
-+		else
-+			ret = -1;
-+	} else
-+		set_timings_mdma(drive, pmif->kind, &tl[0], &tl[1], speed);
- #endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
--		default:
--			ret = 1;
--	}
- 	if (ret)
- 		return;
+-	ret = down_interruptible(&dd->ipath_eep_sem);
++	ret = mutex_lock_interruptible(&dd->ipath_eep_lock);
+ 	if (!ret) {
+ 		ret = ipath_eeprom_internal_read(dd, eeprom_offset, buff, len);
+-		up(&dd->ipath_eep_sem);
++		mutex_unlock(&dd->ipath_eep_lock);
+ 	}
  
-@@ -1035,12 +1012,11 @@ pmac_ide_do_resume(ide_hwif_t *hwif)
-  * rare machines unfortunately, but it's better this way.
-  */
- static int
--pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif)
-+pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif, hw_regs_t *hw)
+ 	return ret;
+@@ -524,10 +524,10 @@ int ipath_eeprom_write(struct ipath_devdata *dd, u8 eeprom_offset,
  {
- 	struct device_node *np = pmif->node;
- 	const int *bidp;
- 	u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
--	hw_regs_t hw;
- 
- 	pmif->cable_80 = 0;
- 	pmif->broken_dma = pmif->broken_dma_warn = 0;
-@@ -1126,11 +1102,9 @@ pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif)
- 	/* Tell common code _not_ to mess with resources */
- 	hwif->mmio = 1;
- 	hwif->hwif_data = pmif;
--	memset(&hw, 0, sizeof(hw));
--	pmac_ide_init_hwif_ports(&hw, pmif->regbase, 0, &hwif->irq);
--	memcpy(hwif->io_ports, hw.io_ports, sizeof(hwif->io_ports));
--	hwif->chipset = ide_pmac;
--	hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET] || pmif->mediabay;
-+	hw->chipset = ide_pmac;
-+	ide_init_port_hw(hwif, hw);
-+	hwif->noprobe = pmif->mediabay;
- 	hwif->hold = pmif->mediabay;
- 	hwif->cbl = pmif->cable_80 ? ATA_CBL_PATA80 : ATA_CBL_PATA40;
- 	hwif->drives[0].unmask = 1;
-@@ -1159,8 +1133,6 @@ pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif)
- 		hwif->noprobe = 0;
- #endif /* CONFIG_PMAC_MEDIABAY */
+ 	int ret;
  
--	hwif->sg_max_nents = MAX_DCMDS;
--
- #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
- 	/* has a DBDMA controller channel */
- 	if (pmif->dma_regs)
-@@ -1186,6 +1158,7 @@ pmac_ide_macio_attach(struct macio_dev *mdev, const struct of_device_id *match)
- 	ide_hwif_t *hwif;
- 	pmac_ide_hwif_t *pmif;
- 	int i, rc;
-+	hw_regs_t hw;
+-	ret = down_interruptible(&dd->ipath_eep_sem);
++	ret = mutex_lock_interruptible(&dd->ipath_eep_lock);
+ 	if (!ret) {
+ 		ret = ipath_eeprom_internal_write(dd, eeprom_offset, buff, len);
+-		up(&dd->ipath_eep_sem);
++		mutex_unlock(&dd->ipath_eep_lock);
+ 	}
  
- 	i = 0;
- 	while (i < MAX_HWIFS && (ide_hwifs[i].io_ports[IDE_DATA_OFFSET] != 0
-@@ -1228,7 +1201,6 @@ pmac_ide_macio_attach(struct macio_dev *mdev, const struct of_device_id *match)
- 	regbase = (unsigned long) base;
+ 	return ret;
+@@ -574,7 +574,7 @@ void ipath_get_eeprom_info(struct ipath_devdata *dd)
+ 	struct ipath_devdata *dd0 = ipath_lookup(0);
  
- 	hwif->pci_dev = mdev->bus->pdev;
--	hwif->gendev.parent = &mdev->ofdev.dev;
+ 	if (t && dd0->ipath_nguid > 1 && t <= dd0->ipath_nguid) {
+-		u8 *bguid, oguid;
++		u8 oguid;
+ 		dd->ipath_guid = dd0->ipath_guid;
+ 		bguid = (u8 *) & dd->ipath_guid;
  
- 	pmif->mdev = mdev;
- 	pmif->node = mdev->ofdev.node;
-@@ -1246,7 +1218,12 @@ pmac_ide_macio_attach(struct macio_dev *mdev, const struct of_device_id *match)
- #endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
- 	dev_set_drvdata(&mdev->ofdev.dev, hwif);
+@@ -616,9 +616,9 @@ void ipath_get_eeprom_info(struct ipath_devdata *dd)
+ 		goto bail;
+ 	}
  
--	rc = pmac_ide_setup_device(pmif, hwif);
-+	memset(&hw, 0, sizeof(hw));
-+	pmac_ide_init_hwif_ports(&hw, pmif->regbase, 0, NULL);
-+	hw.irq = irq;
-+	hw.dev = &mdev->ofdev.dev;
-+
-+	rc = pmac_ide_setup_device(pmif, hwif, &hw);
- 	if (rc != 0) {
- 		/* The inteface is released to the common IDE layer */
- 		dev_set_drvdata(&mdev->ofdev.dev, NULL);
-@@ -1305,6 +1282,7 @@ pmac_ide_pci_attach(struct pci_dev *pdev, const struct pci_device_id *id)
- 	void __iomem *base;
- 	unsigned long rbase, rlen;
- 	int i, rc;
-+	hw_regs_t hw;
+-	down(&dd->ipath_eep_sem);
++	mutex_lock(&dd->ipath_eep_lock);
+ 	eep_stat = ipath_eeprom_internal_read(dd, 0, buf, len);
+-	up(&dd->ipath_eep_sem);
++	mutex_unlock(&dd->ipath_eep_lock);
  
- 	np = pci_device_to_OF_node(pdev);
- 	if (np == NULL) {
-@@ -1338,7 +1316,6 @@ pmac_ide_pci_attach(struct pci_dev *pdev, const struct pci_device_id *id)
+ 	if (eep_stat) {
+ 		ipath_dev_err(dd, "Failed reading GUID from eeprom\n");
+@@ -674,7 +674,6 @@ void ipath_get_eeprom_info(struct ipath_devdata *dd)
+ 		 * elsewhere for backward-compatibility.
+ 		 */
+ 		char *snp = dd->ipath_serial;
+-		int len;
+ 		memcpy(snp, ifp->if_sprefix, sizeof ifp->if_sprefix);
+ 		snp[sizeof ifp->if_sprefix] = '\0';
+ 		len = strlen(snp);
+@@ -764,14 +763,14 @@ int ipath_update_eeprom_log(struct ipath_devdata *dd)
+ 	/* Grab semaphore and read current EEPROM. If we get an
+ 	 * error, let go, but if not, keep it until we finish write.
+ 	 */
+-	ret = down_interruptible(&dd->ipath_eep_sem);
++	ret = mutex_lock_interruptible(&dd->ipath_eep_lock);
+ 	if (ret) {
+ 		ipath_dev_err(dd, "Unable to acquire EEPROM for logging\n");
+ 		goto free_bail;
+ 	}
+ 	ret = ipath_eeprom_internal_read(dd, 0, buf, len);
+ 	if (ret) {
+-		up(&dd->ipath_eep_sem);
++		mutex_unlock(&dd->ipath_eep_lock);
+ 		ipath_dev_err(dd, "Unable read EEPROM for logging\n");
+ 		goto free_bail;
  	}
+@@ -779,7 +778,7 @@ int ipath_update_eeprom_log(struct ipath_devdata *dd)
  
- 	hwif->pci_dev = pdev;
--	hwif->gendev.parent = &pdev->dev;
- 	pmif->mdev = NULL;
- 	pmif->node = np;
+ 	csum = flash_csum(ifp, 0);
+ 	if (csum != ifp->if_csum) {
+-		up(&dd->ipath_eep_sem);
++		mutex_unlock(&dd->ipath_eep_lock);
+ 		ipath_dev_err(dd, "EEPROM cks err (0x%02X, S/B 0x%02X)\n",
+ 				csum, ifp->if_csum);
+ 		ret = 1;
+@@ -849,7 +848,7 @@ int ipath_update_eeprom_log(struct ipath_devdata *dd)
+ 		csum = flash_csum(ifp, 1);
+ 		ret = ipath_eeprom_internal_write(dd, 0, buf, hi_water + 1);
+ 	}
+-	up(&dd->ipath_eep_sem);
++	mutex_unlock(&dd->ipath_eep_lock);
+ 	if (ret)
+ 		ipath_dev_err(dd, "Failed updating EEPROM\n");
  
-@@ -1355,7 +1332,12 @@ pmac_ide_pci_attach(struct pci_dev *pdev, const struct pci_device_id *id)
+diff --git a/drivers/infiniband/hw/ipath/ipath_file_ops.c b/drivers/infiniband/hw/ipath/ipath_file_ops.c
+index 5de3243..7e025c8 100644
+--- a/drivers/infiniband/hw/ipath/ipath_file_ops.c
++++ b/drivers/infiniband/hw/ipath/ipath_file_ops.c
+@@ -169,7 +169,7 @@ static int ipath_get_base_info(struct file *fp,
+ 		kinfo->spi_piocnt = dd->ipath_pbufsport;
+ 		kinfo->spi_piobufbase = (u64) pd->port_piobufs;
+ 		kinfo->__spi_uregbase = (u64) dd->ipath_uregbase +
+-			dd->ipath_palign * pd->port_port;
++			dd->ipath_ureg_align * pd->port_port;
+ 	} else if (master) {
+ 		kinfo->spi_piocnt = (dd->ipath_pbufsport / subport_cnt) +
+ 				    (dd->ipath_pbufsport % subport_cnt);
+@@ -186,7 +186,7 @@ static int ipath_get_base_info(struct file *fp,
+ 	}
+ 	if (shared) {
+ 		kinfo->spi_port_uregbase = (u64) dd->ipath_uregbase +
+-			dd->ipath_palign * pd->port_port;
++			dd->ipath_ureg_align * pd->port_port;
+ 		kinfo->spi_port_rcvegrbuf = kinfo->spi_rcv_egrbufs;
+ 		kinfo->spi_port_rcvhdr_base = kinfo->spi_rcvhdr_base;
+ 		kinfo->spi_port_rcvhdr_tailaddr = kinfo->spi_rcvhdr_tailaddr;
+@@ -742,11 +742,12 @@ static int ipath_manage_rcvq(struct ipath_portdata *pd, unsigned subport,
+ 		 * updated and correct itself, even in the face of software
+ 		 * bugs.
+ 		 */
+-		*(volatile u64 *)pd->port_rcvhdrtail_kvaddr = 0;
+-		set_bit(INFINIPATH_R_PORTENABLE_SHIFT + pd->port_port,
++		if (pd->port_rcvhdrtail_kvaddr)
++			ipath_clear_rcvhdrtail(pd);
++		set_bit(dd->ipath_r_portenable_shift + pd->port_port,
+ 			&dd->ipath_rcvctrl);
+ 	} else
+-		clear_bit(INFINIPATH_R_PORTENABLE_SHIFT + pd->port_port,
++		clear_bit(dd->ipath_r_portenable_shift + pd->port_port,
+ 			  &dd->ipath_rcvctrl);
+ 	ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl,
+ 			 dd->ipath_rcvctrl);
+@@ -881,7 +882,7 @@ static int ipath_create_user_egr(struct ipath_portdata *pd)
  
- 	pci_set_drvdata(pdev, hwif);
+ 	egrcnt = dd->ipath_rcvegrcnt;
+ 	/* TID number offset for this port */
+-	egroff = pd->port_port * egrcnt;
++	egroff = (pd->port_port - 1) * egrcnt + dd->ipath_p0_rcvegrcnt;
+ 	egrsize = dd->ipath_rcvegrbufsize;
+ 	ipath_cdbg(VERBOSE, "Allocating %d egr buffers, at egrtid "
+ 		   "offset %x, egrsize %u\n", egrcnt, egroff, egrsize);
+@@ -1049,11 +1050,6 @@ static int mmap_piobufs(struct vm_area_struct *vma,
  
--	rc = pmac_ide_setup_device(pmif, hwif);
-+	memset(&hw, 0, sizeof(hw));
-+	pmac_ide_init_hwif_ports(&hw, pmif->regbase, 0, NULL);
-+	hw.irq = pdev->irq;
-+	hw.dev = &pdev->dev;
-+
-+	rc = pmac_ide_setup_device(pmif, hwif, &hw);
- 	if (rc != 0) {
- 		/* The inteface is released to the common IDE layer */
- 		pci_set_drvdata(pdev, NULL);
-@@ -1721,11 +1703,7 @@ pmac_ide_dma_test_irq (ide_drive_t *drive)
- 	return 1;
- }
+ 	phys = dd->ipath_physaddr + piobufs;
  
--static void pmac_ide_dma_host_off(ide_drive_t *drive)
--{
--}
+-	/*
+-	 * Don't mark this as non-cached, or we don't get the
+-	 * write combining behavior we want on the PIO buffers!
+-	 */
 -
--static void pmac_ide_dma_host_on(ide_drive_t *drive)
-+static void pmac_ide_dma_host_set(ide_drive_t *drive, int on)
- {
+ #if defined(__powerpc__)
+ 	/* There isn't a generic way to specify writethrough mappings */
+ 	pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE;
+@@ -1120,33 +1116,24 @@ bail:
  }
  
-@@ -1771,15 +1749,14 @@ pmac_ide_setup_dma(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif)
- 		return;
- 	}
+ /*
+- * ipath_file_vma_nopage - handle a VMA page fault.
++ * ipath_file_vma_fault - handle a VMA page fault.
+  */
+-static struct page *ipath_file_vma_nopage(struct vm_area_struct *vma,
+-					  unsigned long address, int *type)
++static int ipath_file_vma_fault(struct vm_area_struct *vma,
++					struct vm_fault *vmf)
+ {
+-	unsigned long offset = address - vma->vm_start;
+-	struct page *page = NOPAGE_SIGBUS;
+-	void *pageptr;
++	struct page *page;
  
--	hwif->dma_off_quietly = &ide_dma_off_quietly;
--	hwif->ide_dma_on = &__ide_dma_on;
-+	hwif->sg_max_nents = MAX_DCMDS;
+-	/*
+-	 * Convert the vmalloc address into a struct page.
+-	 */
+-	pageptr = (void *)(offset + (vma->vm_pgoff << PAGE_SHIFT));
+-	page = vmalloc_to_page(pageptr);
++	page = vmalloc_to_page((void *)(vmf->pgoff << PAGE_SHIFT));
+ 	if (!page)
+-		goto out;
+-
+-	/* Increment the reference count. */
++		return VM_FAULT_SIGBUS;
+ 	get_page(page);
+-	if (type)
+-		*type = VM_FAULT_MINOR;
+-out:
+-	return page;
++	vmf->page = page;
 +
-+	hwif->dma_host_set = &pmac_ide_dma_host_set;
- 	hwif->dma_setup = &pmac_ide_dma_setup;
- 	hwif->dma_exec_cmd = &pmac_ide_dma_exec_cmd;
- 	hwif->dma_start = &pmac_ide_dma_start;
- 	hwif->ide_dma_end = &pmac_ide_dma_end;
- 	hwif->ide_dma_test_irq = &pmac_ide_dma_test_irq;
--	hwif->dma_host_off = &pmac_ide_dma_host_off;
--	hwif->dma_host_on = &pmac_ide_dma_host_on;
- 	hwif->dma_timeout = &ide_dma_timeout;
- 	hwif->dma_lost_irq = &pmac_ide_dma_lost_irq;
- 
-@@ -1809,3 +1786,5 @@ pmac_ide_setup_dma(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif)
++	return 0;
  }
  
- #endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
-+
-+module_init(pmac_ide_probe);
-diff --git a/drivers/ide/setup-pci.c b/drivers/ide/setup-pci.c
-index d2cd5a3..676c66e 100644
---- a/drivers/ide/setup-pci.c
-+++ b/drivers/ide/setup-pci.c
-@@ -165,13 +165,17 @@ static unsigned long ide_get_or_set_dma_base(const struct ide_port_info *d, ide_
- 
- 		dma_base = pci_resource_start(dev, baridx);
+ static struct vm_operations_struct ipath_file_vm_ops = {
+-	.nopage = ipath_file_vma_nopage,
++	.fault = ipath_file_vma_fault,
+ };
  
--		if (dma_base == 0)
-+		if (dma_base == 0) {
- 			printk(KERN_ERR "%s: DMA base is invalid\n", d->name);
-+			return 0;
-+		}
+ static int mmap_kvaddr(struct vm_area_struct *vma, u64 pgaddr,
+@@ -1284,7 +1271,7 @@ static int ipath_mmap(struct file *fp, struct vm_area_struct *vma)
+ 		goto bail;
  	}
  
--	if ((d->host_flags & IDE_HFLAG_CS5520) == 0 && dma_base) {
-+	if (hwif->channel)
-+		dma_base += 8;
-+
-+	if ((d->host_flags & IDE_HFLAG_CS5520) == 0) {
- 		u8 simplex_stat = 0;
--		dma_base += hwif->channel ? 8 : 0;
- 
- 		switch(dev->device) {
- 			case PCI_DEVICE_ID_AL_M5219:
-@@ -359,6 +363,8 @@ static ide_hwif_t *ide_hwif_configure(struct pci_dev *dev, const struct ide_port
- 	unsigned long ctl = 0, base = 0;
- 	ide_hwif_t *hwif;
- 	u8 bootable = (d->host_flags & IDE_HFLAG_BOOTABLE) ? 1 : 0;
-+	u8 oldnoprobe = 0;
-+	struct hw_regs_s hw;
+-	ureg = dd->ipath_uregbase + dd->ipath_palign * pd->port_port;
++	ureg = dd->ipath_uregbase + dd->ipath_ureg_align * pd->port_port;
+ 	if (!pd->port_subport_cnt) {
+ 		/* port is not shared */
+ 		piocnt = dd->ipath_pbufsport;
+@@ -1400,7 +1387,10 @@ static unsigned int ipath_poll_next(struct ipath_portdata *pd,
+ 	pollflag = ipath_poll_hdrqfull(pd);
  
- 	if ((d->host_flags & IDE_HFLAG_ISA_PORTS) == 0) {
- 		/*  Possibly we should fail if these checks report true */
-@@ -381,26 +387,25 @@ static ide_hwif_t *ide_hwif_configure(struct pci_dev *dev, const struct ide_port
- 	}
- 	if ((hwif = ide_match_hwif(base, bootable, d->name)) == NULL)
- 		return NULL;	/* no room in ide_hwifs[] */
--	if (hwif->io_ports[IDE_DATA_OFFSET] != base ||
--	    hwif->io_ports[IDE_CONTROL_OFFSET] != (ctl | 2)) {
--		hw_regs_t hw;
--
--		memset(&hw, 0, sizeof(hw));
--#ifndef CONFIG_IDE_ARCH_OBSOLETE_INIT
--		ide_std_init_ports(&hw, base, ctl | 2);
--#else
--		ide_init_hwif_ports(&hw, base, ctl | 2, NULL);
--#endif
--		memcpy(hwif->io_ports, hw.io_ports, sizeof(hwif->io_ports));
--		hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET];
--	}
--	hwif->chipset = d->chipset ? d->chipset : ide_pci;
-+
-+	memset(&hw, 0, sizeof(hw));
-+	hw.irq = hwif->irq ? hwif->irq : irq;
-+	hw.dev = &dev->dev;
-+	hw.chipset = d->chipset ? d->chipset : ide_pci;
-+	ide_std_init_ports(&hw, base, ctl | 2);
-+
-+	if (hwif->io_ports[IDE_DATA_OFFSET] == base &&
-+	    hwif->io_ports[IDE_CONTROL_OFFSET] == (ctl | 2))
-+		oldnoprobe = hwif->noprobe;
-+
-+	ide_init_port_hw(hwif, &hw);
-+
-+	hwif->noprobe = oldnoprobe;
-+
- 	hwif->pci_dev = dev;
- 	hwif->cds = d;
- 	hwif->channel = port;
+ 	head = ipath_read_ureg32(dd, ur_rcvhdrhead, pd->port_port);
+-	tail = *(volatile u64 *)pd->port_rcvhdrtail_kvaddr;
++	if (pd->port_rcvhdrtail_kvaddr)
++		tail = ipath_get_rcvhdrtail(pd);
++	else
++		tail = ipath_read_ureg32(dd, ur_rcvhdrtail, pd->port_port);
  
--	if (!hwif->irq)
--		hwif->irq = irq;
- 	if (mate) {
- 		hwif->mate = mate;
- 		mate->mate = hwif;
-@@ -535,12 +540,8 @@ void ide_pci_setup_ports(struct pci_dev *dev, const struct ide_port_info *d, int
- 		if ((hwif = ide_hwif_configure(dev, d, mate, port, pciirq)) == NULL)
- 			continue;
+ 	if (head != tail)
+ 		pollflag |= POLLIN | POLLRDNORM;
+@@ -1410,7 +1400,7 @@ static unsigned int ipath_poll_next(struct ipath_portdata *pd,
+ 		/* flush waiting flag so we don't miss an event */
+ 		wmb();
  
--		/* setup proper ancestral information */
--		hwif->gendev.parent = &dev->dev;
--
- 		*(idx + port) = hwif->index;
+-		set_bit(pd->port_port + INFINIPATH_R_INTRAVAIL_SHIFT,
++		set_bit(pd->port_port + dd->ipath_r_intravail_shift,
+ 			&dd->ipath_rcvctrl);
  
--		
- 		if (d->init_iops)
- 			d->init_iops(hwif);
+ 		ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl,
+@@ -1790,6 +1780,7 @@ static int find_shared_port(struct file *fp,
+ 			}
+ 			port_fp(fp) = pd;
+ 			subport_fp(fp) = pd->port_cnt++;
++			pd->port_subpid[subport_fp(fp)] = current->pid;
+ 			tidcursor_fp(fp) = 0;
+ 			pd->active_slaves |= 1 << subport_fp(fp);
+ 			ipath_cdbg(PROC,
+@@ -1920,8 +1911,7 @@ static int ipath_do_user_init(struct file *fp,
+ 	 */
+ 	head32 = ipath_read_ureg32(dd, ur_rcvegrindextail, pd->port_port);
+ 	ipath_write_ureg(dd, ur_rcvegrindexhead, head32, pd->port_port);
+-	dd->ipath_lastegrheads[pd->port_port] = -1;
+-	dd->ipath_lastrcvhdrqtails[pd->port_port] = -1;
++	pd->port_lastrcvhdrqtail = -1;
+ 	ipath_cdbg(VERBOSE, "Wrote port%d egrhead %x from tail regs\n",
+ 		pd->port_port, head32);
+ 	pd->port_tidcursor = 0;	/* start at beginning after open */
+@@ -1941,11 +1931,13 @@ static int ipath_do_user_init(struct file *fp,
+ 	 * We explictly set the in-memory copy to 0 beforehand, so we don't
+ 	 * have to wait to be sure the DMA update has happened.
+ 	 */
+-	*(volatile u64 *)pd->port_rcvhdrtail_kvaddr = 0ULL;
+-	set_bit(INFINIPATH_R_PORTENABLE_SHIFT + pd->port_port,
++	if (pd->port_rcvhdrtail_kvaddr)
++		ipath_clear_rcvhdrtail(pd);
++	set_bit(dd->ipath_r_portenable_shift + pd->port_port,
+ 		&dd->ipath_rcvctrl);
+ 	ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl,
+-			 dd->ipath_rcvctrl & ~INFINIPATH_R_TAILUPD);
++			dd->ipath_rcvctrl &
++			~(1ULL << dd->ipath_r_tailupd_shift));
+ 	ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl,
+ 			 dd->ipath_rcvctrl);
+ 	/* Notify any waiting slaves */
+@@ -2022,6 +2014,7 @@ static int ipath_close(struct inode *in, struct file *fp)
+ 		 * the slave(s) don't wait for receive data forever.
+ 		 */
+ 		pd->active_slaves &= ~(1 << fd->subport);
++		pd->port_subpid[fd->subport] = 0;
+ 		mutex_unlock(&ipath_mutex);
+ 		goto bail;
+ 	}
+@@ -2054,9 +2047,9 @@ static int ipath_close(struct inode *in, struct file *fp)
+ 	if (dd->ipath_kregbase) {
+ 		int i;
+ 		/* atomically clear receive enable port and intr avail. */
+-		clear_bit(INFINIPATH_R_PORTENABLE_SHIFT + port,
++		clear_bit(dd->ipath_r_portenable_shift + port,
+ 			  &dd->ipath_rcvctrl);
+-		clear_bit(pd->port_port + INFINIPATH_R_INTRAVAIL_SHIFT,
++		clear_bit(pd->port_port + dd->ipath_r_intravail_shift,
+ 			  &dd->ipath_rcvctrl);
+ 		ipath_write_kreg( dd, dd->ipath_kregs->kr_rcvctrl,
+ 			dd->ipath_rcvctrl);
+@@ -2149,11 +2142,15 @@ static int ipath_get_slave_info(struct ipath_portdata *pd,
  
-@@ -551,8 +552,6 @@ void ide_pci_setup_ports(struct pci_dev *dev, const struct ide_port_info *d, int
- 		    (d->host_flags & IDE_HFLAG_FORCE_LEGACY_IRQS))
- 			hwif->irq = port ? 15 : 14;
+ static int ipath_force_pio_avail_update(struct ipath_devdata *dd)
+ {
+-	u64 reg = dd->ipath_sendctrl;
++	unsigned long flags;
  
--		hwif->fixup = d->fixup;
--
- 		hwif->host_flags = d->host_flags;
- 		hwif->pio_mask = d->pio_mask;
+-	clear_bit(IPATH_S_PIOBUFAVAILUPD, &reg);
+-	ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, reg);
++	spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags);
++	ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
++		dd->ipath_sendctrl & ~INFINIPATH_S_PIOBUFAVAILUPD);
++	ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
+ 	ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, dd->ipath_sendctrl);
++	ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
++	spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags);
  
-@@ -699,105 +698,3 @@ out:
+ 	return 0;
  }
+@@ -2227,6 +2224,11 @@ static ssize_t ipath_write(struct file *fp, const char __user *data,
+ 		dest = &cmd.cmd.poll_type;
+ 		src = &ucmd->cmd.poll_type;
+ 		break;
++	case IPATH_CMD_ARMLAUNCH_CTRL:
++		copy = sizeof(cmd.cmd.armlaunch_ctrl);
++		dest = &cmd.cmd.armlaunch_ctrl;
++		src = &ucmd->cmd.armlaunch_ctrl;
++		break;
+ 	default:
+ 		ret = -EINVAL;
+ 		goto bail;
+@@ -2302,6 +2304,12 @@ static ssize_t ipath_write(struct file *fp, const char __user *data,
+ 	case IPATH_CMD_POLL_TYPE:
+ 		pd->poll_type = cmd.cmd.poll_type;
+ 		break;
++	case IPATH_CMD_ARMLAUNCH_CTRL:
++		if (cmd.cmd.armlaunch_ctrl)
++			ipath_enable_armlaunch(pd->port_dd);
++		else
++			ipath_disable_armlaunch(pd->port_dd);
++		break;
+ 	}
  
- EXPORT_SYMBOL_GPL(ide_setup_pci_devices);
--
--#ifdef CONFIG_IDEPCI_PCIBUS_ORDER
--/*
-- *	Module interfaces
-- */
--
--static int pre_init = 1;		/* Before first ordered IDE scan */
--static LIST_HEAD(ide_pci_drivers);
--
--/*
-- *	__ide_pci_register_driver	-	attach IDE driver
-- *	@driver: pci driver
-- *	@module: owner module of the driver
-- *
-- *	Registers a driver with the IDE layer. The IDE layer arranges that
-- *	boot time setup is done in the expected device order and then
-- *	hands the controllers off to the core PCI code to do the rest of
-- *	the work.
-- *
-- *	Returns are the same as for pci_register_driver
-- */
--
--int __ide_pci_register_driver(struct pci_driver *driver, struct module *module,
--			      const char *mod_name)
--{
--	if (!pre_init)
--		return __pci_register_driver(driver, module, mod_name);
--	driver->driver.owner = module;
--	list_add_tail(&driver->node, &ide_pci_drivers);
--	return 0;
--}
--EXPORT_SYMBOL_GPL(__ide_pci_register_driver);
--
--/**
-- *	ide_scan_pcidev		-	find an IDE driver for a device
-- *	@dev: PCI device to check
-- *
-- *	Look for an IDE driver to handle the device we are considering.
-- *	This is only used during boot up to get the ordering correct. After
-- *	boot up the pci layer takes over the job.
-- */
--
--static int __init ide_scan_pcidev(struct pci_dev *dev)
--{
--	struct list_head *l;
--	struct pci_driver *d;
--
--	list_for_each(l, &ide_pci_drivers) {
--		d = list_entry(l, struct pci_driver, node);
--		if (d->id_table) {
--			const struct pci_device_id *id =
--				pci_match_id(d->id_table, dev);
--
--			if (id != NULL && d->probe(dev, id) >= 0) {
--				dev->driver = d;
--				pci_dev_get(dev);
--				return 1;
--			}
--		}
--	}
--	return 0;
--}
--
--/**
-- *	ide_scan_pcibus		-	perform the initial IDE driver scan
-- *	@scan_direction: set for reverse order scanning
-- *
-- *	Perform the initial bus rather than driver ordered scan of the
-- *	PCI drivers. After this all IDE pci handling becomes standard
-- *	module ordering not traditionally ordered.
-- */
-- 	
--void __init ide_scan_pcibus (int scan_direction)
--{
--	struct pci_dev *dev = NULL;
--	struct pci_driver *d;
--	struct list_head *l, *n;
--
--	pre_init = 0;
--	if (!scan_direction)
--		while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)))
--			ide_scan_pcidev(dev);
--	else
--		while ((dev = pci_get_device_reverse(PCI_ANY_ID, PCI_ANY_ID,
--						     dev)))
--			ide_scan_pcidev(dev);
--
--	/*
--	 *	Hand the drivers over to the PCI layer now we
--	 *	are post init.
--	 */
--
--	list_for_each_safe(l, n, &ide_pci_drivers) {
--		list_del(l);
--		d = list_entry(l, struct pci_driver, node);
--		if (__pci_register_driver(d, d->driver.owner,
--					  d->driver.mod_name))
--			printk(KERN_ERR "%s: failed to register %s driver\n",
--					__FUNCTION__, d->driver.mod_name);
--	}
--}
--#endif
-diff --git a/drivers/ieee1394/nodemgr.c b/drivers/ieee1394/nodemgr.c
-index 90dc75b..511e432 100644
---- a/drivers/ieee1394/nodemgr.c
-+++ b/drivers/ieee1394/nodemgr.c
-@@ -727,33 +727,31 @@ static int nodemgr_bus_match(struct device * dev, struct device_driver * drv)
- 
- static DEFINE_MUTEX(nodemgr_serialize_remove_uds);
+ 	if (ret >= 0)
+diff --git a/drivers/infiniband/hw/ipath/ipath_fs.c b/drivers/infiniband/hw/ipath/ipath_fs.c
+index 262c25d..23faba9 100644
+--- a/drivers/infiniband/hw/ipath/ipath_fs.c
++++ b/drivers/infiniband/hw/ipath/ipath_fs.c
+@@ -108,21 +108,16 @@ static const struct file_operations atomic_stats_ops = {
+ 	.read = atomic_stats_read,
+ };
  
-+static int __match_ne(struct device *dev, void *data)
-+{
-+	struct unit_directory *ud;
-+	struct node_entry *ne = (struct node_entry *)data;
-+
-+	ud = container_of(dev, struct unit_directory, unit_dev);
-+	return ud->ne == ne;
-+}
-+
- static void nodemgr_remove_uds(struct node_entry *ne)
- {
- 	struct device *dev;
--	struct unit_directory *tmp, *ud;
+-#define NUM_COUNTERS sizeof(struct infinipath_counters) / sizeof(u64)
 -
--	/* Iteration over nodemgr_ud_class.devices has to be protected by
--	 * nodemgr_ud_class.sem, but device_unregister() will eventually
--	 * take nodemgr_ud_class.sem too. Therefore pick out one ud at a time,
--	 * release the semaphore, and then unregister the ud. Since this code
--	 * may be called from other contexts besides the knodemgrds, protect the
--	 * gap after release of the semaphore by nodemgr_serialize_remove_uds.
-+	struct unit_directory *ud;
-+
-+	/* Use class_find device to iterate the devices. Since this code
-+	 * may be called from other contexts besides the knodemgrds,
-+	 * protect it by nodemgr_serialize_remove_uds.
- 	 */
- 	mutex_lock(&nodemgr_serialize_remove_uds);
- 	for (;;) {
--		ud = NULL;
--		down(&nodemgr_ud_class.sem);
--		list_for_each_entry(dev, &nodemgr_ud_class.devices, node) {
--			tmp = container_of(dev, struct unit_directory,
--					   unit_dev);
--			if (tmp->ne == ne) {
--				ud = tmp;
--				break;
--			}
--		}
--		up(&nodemgr_ud_class.sem);
--		if (ud == NULL)
-+		dev = class_find_device(&nodemgr_ud_class, ne, __match_ne);
-+		if (!dev)
- 			break;
-+		ud = container_of(dev, struct unit_directory, unit_dev);
-+		put_device(dev);
- 		device_unregister(&ud->unit_dev);
- 		device_unregister(&ud->device);
- 	}
-@@ -882,45 +880,66 @@ fail_alloc:
- 	return NULL;
- }
+ static ssize_t atomic_counters_read(struct file *file, char __user *buf,
+ 				    size_t count, loff_t *ppos)
+ {
+-	u64 counters[NUM_COUNTERS];
+-	u16 i;
++	struct infinipath_counters counters;
+ 	struct ipath_devdata *dd;
  
-+static int __match_ne_guid(struct device *dev, void *data)
-+{
-+	struct node_entry *ne;
-+	u64 *guid = (u64 *)data;
-+
-+	ne = container_of(dev, struct node_entry, node_dev);
-+	return ne->guid == *guid;
-+}
+ 	dd = file->f_path.dentry->d_inode->i_private;
++	dd->ipath_f_read_counters(dd, &counters);
  
- static struct node_entry *find_entry_by_guid(u64 guid)
- {
- 	struct device *dev;
--	struct node_entry *ne, *ret_ne = NULL;
+-	for (i = 0; i < NUM_COUNTERS; i++)
+-		counters[i] = ipath_snap_cntr(dd, i);
 -
--	down(&nodemgr_ne_class.sem);
--	list_for_each_entry(dev, &nodemgr_ne_class.devices, node) {
--		ne = container_of(dev, struct node_entry, node_dev);
-+	struct node_entry *ne;
+-	return simple_read_from_buffer(buf, count, ppos, counters,
++	return simple_read_from_buffer(buf, count, ppos, &counters,
+ 				       sizeof counters);
+ }
  
--		if (ne->guid == guid) {
--			ret_ne = ne;
--			break;
--		}
--	}
--	up(&nodemgr_ne_class.sem);
-+	dev = class_find_device(&nodemgr_ne_class, &guid, __match_ne_guid);
-+	if (!dev)
-+		return NULL;
-+	ne = container_of(dev, struct node_entry, node_dev);
-+	put_device(dev);
+@@ -243,8 +238,7 @@ static int create_device_files(struct super_block *sb,
  
--	return ret_ne;
-+	return ne;
- }
+ 	snprintf(unit, sizeof unit, "%02d", dd->ipath_unit);
+ 	ret = create_file(unit, S_IFDIR|S_IRUGO|S_IXUGO, sb->s_root, &dir,
+-			  (struct file_operations *) &simple_dir_operations,
+-			  dd);
++			  &simple_dir_operations, dd);
+ 	if (ret) {
+ 		printk(KERN_ERR "create_file(%s) failed: %d\n", unit, ret);
+ 		goto bail;
+diff --git a/drivers/infiniband/hw/ipath/ipath_iba6110.c b/drivers/infiniband/hw/ipath/ipath_iba6110.c
+index ddbebe4..9e2ced3 100644
+--- a/drivers/infiniband/hw/ipath/ipath_iba6110.c
++++ b/drivers/infiniband/hw/ipath/ipath_iba6110.c
+@@ -148,10 +148,57 @@ struct _infinipath_do_not_use_kernel_regs {
+ 	unsigned long long ReservedSW2[4];
+ };
  
-+struct match_nodeid_param {
-+	struct hpsb_host *host;
-+	nodeid_t nodeid;
+-#define IPATH_KREG_OFFSET(field) (offsetof(struct \
+-    _infinipath_do_not_use_kernel_regs, field) / sizeof(u64))
++struct _infinipath_do_not_use_counters {
++	__u64 LBIntCnt;
++	__u64 LBFlowStallCnt;
++	__u64 Reserved1;
++	__u64 TxUnsupVLErrCnt;
++	__u64 TxDataPktCnt;
++	__u64 TxFlowPktCnt;
++	__u64 TxDwordCnt;
++	__u64 TxLenErrCnt;
++	__u64 TxMaxMinLenErrCnt;
++	__u64 TxUnderrunCnt;
++	__u64 TxFlowStallCnt;
++	__u64 TxDroppedPktCnt;
++	__u64 RxDroppedPktCnt;
++	__u64 RxDataPktCnt;
++	__u64 RxFlowPktCnt;
++	__u64 RxDwordCnt;
++	__u64 RxLenErrCnt;
++	__u64 RxMaxMinLenErrCnt;
++	__u64 RxICRCErrCnt;
++	__u64 RxVCRCErrCnt;
++	__u64 RxFlowCtrlErrCnt;
++	__u64 RxBadFormatCnt;
++	__u64 RxLinkProblemCnt;
++	__u64 RxEBPCnt;
++	__u64 RxLPCRCErrCnt;
++	__u64 RxBufOvflCnt;
++	__u64 RxTIDFullErrCnt;
++	__u64 RxTIDValidErrCnt;
++	__u64 RxPKeyMismatchCnt;
++	__u64 RxP0HdrEgrOvflCnt;
++	__u64 RxP1HdrEgrOvflCnt;
++	__u64 RxP2HdrEgrOvflCnt;
++	__u64 RxP3HdrEgrOvflCnt;
++	__u64 RxP4HdrEgrOvflCnt;
++	__u64 RxP5HdrEgrOvflCnt;
++	__u64 RxP6HdrEgrOvflCnt;
++	__u64 RxP7HdrEgrOvflCnt;
++	__u64 RxP8HdrEgrOvflCnt;
++	__u64 Reserved6;
++	__u64 Reserved7;
++	__u64 IBStatusChangeCnt;
++	__u64 IBLinkErrRecoveryCnt;
++	__u64 IBLinkDownedCnt;
++	__u64 IBSymbolErrCnt;
 +};
 +
-+static int __match_ne_nodeid(struct device *dev, void *data)
-+{
-+	int found = 0;
-+	struct node_entry *ne;
-+	struct match_nodeid_param *param = (struct match_nodeid_param *)data;
-+
-+	if (!dev)
-+		goto ret;
-+	ne = container_of(dev, struct node_entry, node_dev);
-+	if (ne->host == param->host && ne->nodeid == param->nodeid)
-+		found = 1;
-+ret:
-+	return found;
-+}
++#define IPATH_KREG_OFFSET(field) (offsetof( \
++	struct _infinipath_do_not_use_kernel_regs, field) / sizeof(u64))
+ #define IPATH_CREG_OFFSET(field) (offsetof( \
+-    struct infinipath_counters, field) / sizeof(u64))
++	struct _infinipath_do_not_use_counters, field) / sizeof(u64))
  
- static struct node_entry *find_entry_by_nodeid(struct hpsb_host *host,
- 					       nodeid_t nodeid)
- {
- 	struct device *dev;
--	struct node_entry *ne, *ret_ne = NULL;
-+	struct node_entry *ne;
-+	struct match_nodeid_param param;
+ static const struct ipath_kregs ipath_ht_kregs = {
+ 	.kr_control = IPATH_KREG_OFFSET(Control),
+@@ -282,6 +329,9 @@ static const struct ipath_cregs ipath_ht_cregs = {
+ #define INFINIPATH_HWE_HTAPLL_RFSLIP        0x1000000000000000ULL
+ #define INFINIPATH_HWE_SERDESPLLFAILED      0x2000000000000000ULL
  
--	down(&nodemgr_ne_class.sem);
--	list_for_each_entry(dev, &nodemgr_ne_class.devices, node) {
--		ne = container_of(dev, struct node_entry, node_dev);
-+	param.host = host;
-+	param.nodeid = nodeid;
++#define IBA6110_IBCS_LINKTRAININGSTATE_MASK 0xf
++#define IBA6110_IBCS_LINKSTATE_SHIFT 4
++
+ /* kr_extstatus bits */
+ #define INFINIPATH_EXTS_FREQSEL 0x2
+ #define INFINIPATH_EXTS_SERDESSEL 0x4
+@@ -296,6 +346,12 @@ static const struct ipath_cregs ipath_ht_cregs = {
+ #define INFINIPATH_RT_BUFSIZE_MASK 0x3FFFULL
+ #define INFINIPATH_RT_BUFSIZE_SHIFT 48
  
--		if (ne->host == host && ne->nodeid == nodeid) {
--			ret_ne = ne;
--			break;
--		}
--	}
--	up(&nodemgr_ne_class.sem);
-+	dev = class_find_device(&nodemgr_ne_class, &param, __match_ne_nodeid);
-+	if (!dev)
-+		return NULL;
-+	ne = container_of(dev, struct node_entry, node_dev);
-+	put_device(dev);
++#define INFINIPATH_R_INTRAVAIL_SHIFT 16
++#define INFINIPATH_R_TAILUPD_SHIFT 31
++
++/* kr_xgxsconfig bits */
++#define INFINIPATH_XGXS_RESET          0x7ULL
++
+ /*
+  * masks and bits that are different in different chips, or present only
+  * in one
+@@ -652,7 +708,6 @@ static int ipath_ht_boardname(struct ipath_devdata *dd, char *name,
+ 			      "with ID %u\n", boardrev);
+ 		snprintf(name, namelen, "Unknown_InfiniPath_QHT7xxx_%u",
+ 			 boardrev);
+-		ret = 1;
+ 		break;
+ 	}
+ 	if (n)
+@@ -686,6 +741,13 @@ static int ipath_ht_boardname(struct ipath_devdata *dd, char *name,
+ 			      dd->ipath_htspeed);
+ 	ret = 0;
  
--	return ret_ne;
-+	return ne;
++	/*
++	 * set here, not in ipath_init_*_funcs because we have to do
++	 * it after we can read chip registers.
++	 */
++	dd->ipath_ureg_align =
++		ipath_read_kreg32(dd, dd->ipath_kregs->kr_pagealign);
++
+ bail:
+ 	return ret;
  }
+@@ -969,7 +1031,8 @@ static int ipath_setup_ht_config(struct ipath_devdata *dd,
+ 	do {
+ 		u8 cap_type;
  
+-		/* the HT capability type byte is 3 bytes after the
++		/*
++		 * The HT capability type byte is 3 bytes after the
+ 		 * capability byte.
+ 		 */
+ 		if (pci_read_config_byte(pdev, pos + 3, &cap_type)) {
+@@ -982,6 +1045,8 @@ static int ipath_setup_ht_config(struct ipath_devdata *dd,
+ 	} while ((pos = pci_find_next_capability(pdev, pos,
+ 						 PCI_CAP_ID_HT)));
  
-@@ -1370,107 +1389,109 @@ static void nodemgr_node_scan(struct host_info *hi, int generation)
- 	}
++	dd->ipath_flags |= IPATH_SWAP_PIOBUFS;
++
+ bail:
+ 	return ret;
  }
+@@ -1074,11 +1139,55 @@ static void ipath_setup_ht_setextled(struct ipath_devdata *dd,
  
--
--static void nodemgr_suspend_ne(struct node_entry *ne)
-+static int __nodemgr_driver_suspend(struct device *dev, void *data)
+ static void ipath_init_ht_variables(struct ipath_devdata *dd)
  {
--	struct device *dev;
- 	struct unit_directory *ud;
- 	struct device_driver *drv;
-+	struct node_entry *ne = (struct node_entry *)data;
- 	int error;
- 
--	HPSB_DEBUG("Node suspended: ID:BUS[" NODE_BUS_FMT "]  GUID[%016Lx]",
--		   NODE_BUS_ARGS(ne->host, ne->nodeid), (unsigned long long)ne->guid);
-+	ud = container_of(dev, struct unit_directory, unit_dev);
-+	if (ud->ne == ne) {
-+		drv = get_driver(ud->device.driver);
-+		if (drv) {
-+			error = 1; /* release if suspend is not implemented */
-+			if (drv->suspend) {
-+				down(&ud->device.sem);
-+				error = drv->suspend(&ud->device, PMSG_SUSPEND);
-+				up(&ud->device.sem);
-+			}
-+			if (error)
-+				device_release_driver(&ud->device);
-+			put_driver(drv);
-+		}
-+	}
++	/*
++	 * setup the register offsets, since they are different for each
++	 * chip
++	 */
++	dd->ipath_kregs = &ipath_ht_kregs;
++	dd->ipath_cregs = &ipath_ht_cregs;
++
+ 	dd->ipath_gpio_sda_num = _IPATH_GPIO_SDA_NUM;
+ 	dd->ipath_gpio_scl_num = _IPATH_GPIO_SCL_NUM;
+ 	dd->ipath_gpio_sda = IPATH_GPIO_SDA;
+ 	dd->ipath_gpio_scl = IPATH_GPIO_SCL;
  
--	ne->in_limbo = 1;
--	WARN_ON(device_create_file(&ne->device, &dev_attr_ne_in_limbo));
-+	return 0;
-+}
++	/*
++	 * Fill in data for field-values that change in newer chips.
++	 * We dynamically specify only the mask for LINKTRAININGSTATE
++	 * and only the shift for LINKSTATE, as they are the only ones
++	 * that change.  Also precalculate the 3 link states of interest
++	 * and the combined mask.
++	 */
++	dd->ibcs_ls_shift = IBA6110_IBCS_LINKSTATE_SHIFT;
++	dd->ibcs_lts_mask = IBA6110_IBCS_LINKTRAININGSTATE_MASK;
++	dd->ibcs_mask = (INFINIPATH_IBCS_LINKSTATE_MASK <<
++		dd->ibcs_ls_shift) | dd->ibcs_lts_mask;
++	dd->ib_init = (INFINIPATH_IBCS_LT_STATE_LINKUP <<
++		INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT) |
++		(INFINIPATH_IBCS_L_STATE_INIT << dd->ibcs_ls_shift);
++	dd->ib_arm = (INFINIPATH_IBCS_LT_STATE_LINKUP <<
++		INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT) |
++		(INFINIPATH_IBCS_L_STATE_ARM << dd->ibcs_ls_shift);
++	dd->ib_active = (INFINIPATH_IBCS_LT_STATE_LINKUP <<
++		INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT) |
++		(INFINIPATH_IBCS_L_STATE_ACTIVE << dd->ibcs_ls_shift);
++
++	/*
++	 * Fill in data for ibcc field-values that change in newer chips.
++	 * We dynamically specify only the mask for LINKINITCMD
++	 * and only the shift for LINKCMD and MAXPKTLEN, as they are
++	 * the only ones that change.
++	 */
++	dd->ibcc_lic_mask = INFINIPATH_IBCC_LINKINITCMD_MASK;
++	dd->ibcc_lc_shift = INFINIPATH_IBCC_LINKCMD_SHIFT;
++	dd->ibcc_mpl_shift = INFINIPATH_IBCC_MAXPKTLEN_SHIFT;
++
++	/* Fill in shifts for RcvCtrl. */
++	dd->ipath_r_portenable_shift = INFINIPATH_R_PORTENABLE_SHIFT;
++	dd->ipath_r_intravail_shift = INFINIPATH_R_INTRAVAIL_SHIFT;
++	dd->ipath_r_tailupd_shift = INFINIPATH_R_TAILUPD_SHIFT;
++	dd->ipath_r_portcfg_shift = 0; /* Not on IBA6110 */
++
+ 	dd->ipath_i_bitsextant =
+ 		(INFINIPATH_I_RCVURG_MASK << INFINIPATH_I_RCVURG_SHIFT) |
+ 		(INFINIPATH_I_RCVAVAIL_MASK <<
+@@ -1135,6 +1244,8 @@ static void ipath_init_ht_variables(struct ipath_devdata *dd)
  
--	down(&nodemgr_ud_class.sem);
--	list_for_each_entry(dev, &nodemgr_ud_class.devices, node) {
--		ud = container_of(dev, struct unit_directory, unit_dev);
--		if (ud->ne != ne)
--			continue;
-+static int __nodemgr_driver_resume(struct device *dev, void *data)
-+{
-+	struct unit_directory *ud;
-+	struct device_driver *drv;
-+	struct node_entry *ne = (struct node_entry *)data;
+ 	dd->ipath_i_rcvavail_mask = INFINIPATH_I_RCVAVAIL_MASK;
+ 	dd->ipath_i_rcvurg_mask = INFINIPATH_I_RCVURG_MASK;
++	dd->ipath_i_rcvavail_shift = INFINIPATH_I_RCVAVAIL_SHIFT;
++	dd->ipath_i_rcvurg_shift = INFINIPATH_I_RCVURG_SHIFT;
  
-+	ud = container_of(dev, struct unit_directory, unit_dev);
-+	if (ud->ne == ne) {
- 		drv = get_driver(ud->device.driver);
--		if (!drv)
--			continue;
--
--		error = 1; /* release if suspend is not implemented */
--		if (drv->suspend) {
--			down(&ud->device.sem);
--			error = drv->suspend(&ud->device, PMSG_SUSPEND);
--			up(&ud->device.sem);
-+		if (drv) {
-+			if (drv->resume) {
-+				down(&ud->device.sem);
-+				drv->resume(&ud->device);
-+				up(&ud->device.sem);
-+			}
-+			put_driver(drv);
- 		}
--		if (error)
--			device_release_driver(&ud->device);
--		put_driver(drv);
- 	}
--	up(&nodemgr_ud_class.sem);
--}
+ 	/*
+ 	 * EEPROM error log 0 is TXE Parity errors. 1 is RXE Parity.
+@@ -1148,9 +1259,17 @@ static void ipath_init_ht_variables(struct ipath_devdata *dd)
+ 		INFINIPATH_HWE_RXEMEMPARITYERR_MASK <<
+ 		INFINIPATH_HWE_RXEMEMPARITYERR_SHIFT;
  
-+	return 0;
-+}
+-	dd->ipath_eep_st_masks[2].errs_to_log =
+-		INFINIPATH_E_INVALIDADDR | INFINIPATH_E_RESET;
++	dd->ipath_eep_st_masks[2].errs_to_log = INFINIPATH_E_RESET;
  
--static void nodemgr_resume_ne(struct node_entry *ne)
-+static void nodemgr_suspend_ne(struct node_entry *ne)
- {
--	struct device *dev;
--	struct unit_directory *ud;
--	struct device_driver *drv;
-+	HPSB_DEBUG("Node suspended: ID:BUS[" NODE_BUS_FMT "]  GUID[%016Lx]",
-+		   NODE_BUS_ARGS(ne->host, ne->nodeid),
-+		   (unsigned long long)ne->guid);
++	dd->delay_mult = 2; /* SDR, 4X, can't change */
++
++	dd->ipath_link_width_supported = IB_WIDTH_1X | IB_WIDTH_4X;
++	dd->ipath_link_speed_supported = IPATH_IB_SDR;
++	dd->ipath_link_width_enabled = IB_WIDTH_4X;
++	dd->ipath_link_speed_enabled = dd->ipath_link_speed_supported;
++	/* these can't change for this chip, so set once */
++	dd->ipath_link_width_active = dd->ipath_link_width_enabled;
++	dd->ipath_link_speed_active = dd->ipath_link_speed_enabled;
+ }
  
--	ne->in_limbo = 0;
--	device_remove_file(&ne->device, &dev_attr_ne_in_limbo);
-+	ne->in_limbo = 1;
-+	WARN_ON(device_create_file(&ne->device, &dev_attr_ne_in_limbo));
+ /**
+@@ -1205,14 +1324,16 @@ static void ipath_ht_init_hwerrors(struct ipath_devdata *dd)
+ 	val &= ~INFINIPATH_HWE_HTCMISCERR4;
  
--	down(&nodemgr_ud_class.sem);
--	list_for_each_entry(dev, &nodemgr_ud_class.devices, node) {
--		ud = container_of(dev, struct unit_directory, unit_dev);
--		if (ud->ne != ne)
--			continue;
-+	class_for_each_device(&nodemgr_ud_class, ne, __nodemgr_driver_suspend);
-+}
+ 	/*
+-	 * PLL ignored because MDIO interface has a logic problem
+-	 * for reads, on Comstock and Ponderosa.  BRINGUP
++	 * PLL ignored because unused MDIO interface has a logic problem
+ 	 */
+ 	if (dd->ipath_boardrev == 4 || dd->ipath_boardrev == 9)
+ 		val &= ~INFINIPATH_HWE_SERDESPLLFAILED;
+ 	dd->ipath_hwerrmask = val;
+ }
  
--		drv = get_driver(ud->device.driver);
--		if (!drv)
--			continue;
++
++
++
+ /**
+  * ipath_ht_bringup_serdes - bring up the serdes
+  * @dd: the infinipath device
+@@ -1284,16 +1405,6 @@ static int ipath_ht_bringup_serdes(struct ipath_devdata *dd)
+ 	}
  
--		if (drv->resume) {
--			down(&ud->device.sem);
--			drv->resume(&ud->device);
--			up(&ud->device.sem);
--		}
--		put_driver(drv);
+ 	val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_xgxsconfig);
+-	if (((val >> INFINIPATH_XGXS_MDIOADDR_SHIFT) &
+-	     INFINIPATH_XGXS_MDIOADDR_MASK) != 3) {
+-		val &= ~(INFINIPATH_XGXS_MDIOADDR_MASK <<
+-			 INFINIPATH_XGXS_MDIOADDR_SHIFT);
+-		/*
+-		 * we use address 3
+-		 */
+-		val |= 3ULL << INFINIPATH_XGXS_MDIOADDR_SHIFT;
+-		change = 1;
 -	}
--	up(&nodemgr_ud_class.sem);
-+static void nodemgr_resume_ne(struct node_entry *ne)
-+{
-+	ne->in_limbo = 0;
-+	device_remove_file(&ne->device, &dev_attr_ne_in_limbo);
- 
-+	class_for_each_device(&nodemgr_ud_class, ne, __nodemgr_driver_resume);
- 	HPSB_DEBUG("Node resumed: ID:BUS[" NODE_BUS_FMT "]  GUID[%016Lx]",
- 		   NODE_BUS_ARGS(ne->host, ne->nodeid), (unsigned long long)ne->guid);
- }
+ 	if (val & INFINIPATH_XGXS_RESET) {
+ 		/* normally true after boot */
+ 		val &= ~INFINIPATH_XGXS_RESET;
+@@ -1329,21 +1440,6 @@ static int ipath_ht_bringup_serdes(struct ipath_devdata *dd)
+ 		   (unsigned long long)
+ 		   ipath_read_kreg64(dd, dd->ipath_kregs->kr_xgxsconfig));
  
+-	if (!ipath_waitfor_mdio_cmdready(dd)) {
+-		ipath_write_kreg(dd, dd->ipath_kregs->kr_mdio,
+-				 ipath_mdio_req(IPATH_MDIO_CMD_READ, 31,
+-						IPATH_MDIO_CTRL_XGXS_REG_8,
+-						0));
+-		if (ipath_waitfor_complete(dd, dd->ipath_kregs->kr_mdio,
+-					   IPATH_MDIO_DATAVALID, &val))
+-			ipath_dbg("Never got MDIO data for XGXS status "
+-				  "read\n");
+-		else
+-			ipath_cdbg(VERBOSE, "MDIO Read reg8, "
+-				   "'bank' 31 %x\n", (u32) val);
+-	} else
+-		ipath_dbg("Never got MDIO cmdready for XGXS status read\n");
 -
--static void nodemgr_update_pdrv(struct node_entry *ne)
-+static int __nodemgr_update_pdrv(struct device *dev, void *data)
- {
--	struct device *dev;
- 	struct unit_directory *ud;
- 	struct device_driver *drv;
- 	struct hpsb_protocol_driver *pdrv;
-+	struct node_entry *ne = (struct node_entry *)data;
- 	int error;
+ 	return ret;		/* for now, say we always succeeded */
+ }
  
--	down(&nodemgr_ud_class.sem);
--	list_for_each_entry(dev, &nodemgr_ud_class.devices, node) {
--		ud = container_of(dev, struct unit_directory, unit_dev);
--		if (ud->ne != ne)
--			continue;
--
-+	ud = container_of(dev, struct unit_directory, unit_dev);
-+	if (ud->ne == ne) {
- 		drv = get_driver(ud->device.driver);
--		if (!drv)
--			continue;
--
--		error = 0;
--		pdrv = container_of(drv, struct hpsb_protocol_driver, driver);
--		if (pdrv->update) {
--			down(&ud->device.sem);
--			error = pdrv->update(ud);
--			up(&ud->device.sem);
-+		if (drv) {
-+			error = 0;
-+			pdrv = container_of(drv, struct hpsb_protocol_driver,
-+					    driver);
-+			if (pdrv->update) {
-+				down(&ud->device.sem);
-+				error = pdrv->update(ud);
-+				up(&ud->device.sem);
-+			}
-+			if (error)
-+				device_release_driver(&ud->device);
-+			put_driver(drv);
+@@ -1396,6 +1492,7 @@ static void ipath_ht_put_tid(struct ipath_devdata *dd,
+ 			pa |= lenvalid | INFINIPATH_RT_VALID;
  		}
--		if (error)
--			device_release_driver(&ud->device);
--		put_driver(drv);
  	}
--	up(&nodemgr_ud_class.sem);
-+
-+	return 0;
-+}
 +
-+static void nodemgr_update_pdrv(struct node_entry *ne)
-+{
-+	class_for_each_device(&nodemgr_ud_class, ne, __nodemgr_update_pdrv);
+ 	writeq(pa, tidptr);
  }
  
+@@ -1526,8 +1623,7 @@ static int ipath_ht_early_init(struct ipath_devdata *dd)
+ 	}
  
-@@ -1529,13 +1550,31 @@ static void nodemgr_probe_ne(struct host_info *hi, struct node_entry *ne, int ge
- 	put_device(dev);
+ 	ipath_get_eeprom_info(dd);
+-	if (dd->ipath_boardrev == 5 && dd->ipath_serial[0] == '1' &&
+-		dd->ipath_serial[1] == '2' && dd->ipath_serial[2] == '8') {
++	if (dd->ipath_boardrev == 5) {
+ 		/*
+ 		 * Later production QHT7040 has same changes as QHT7140, so
+ 		 * can use GPIO interrupts.  They have serial #'s starting
+@@ -1602,6 +1698,210 @@ static void ipath_ht_free_irq(struct ipath_devdata *dd)
+ 	dd->ipath_intconfig = 0;
  }
  
-+struct probe_param {
-+	struct host_info *hi;
-+	int generation;
-+};
++static struct ipath_message_header *
++ipath_ht_get_msgheader(struct ipath_devdata *dd, __le32 *rhf_addr)
++{
++	return (struct ipath_message_header *)
++		&rhf_addr[sizeof(u64) / sizeof(u32)];
++}
 +
-+static int __nodemgr_node_probe(struct device *dev, void *data)
++static void ipath_ht_config_ports(struct ipath_devdata *dd, ushort cfgports)
 +{
-+	struct probe_param *param = (struct probe_param *)data;
-+	struct node_entry *ne;
++	dd->ipath_portcnt =
++		ipath_read_kreg32(dd, dd->ipath_kregs->kr_portcnt);
++	dd->ipath_p0_rcvegrcnt =
++		ipath_read_kreg32(dd, dd->ipath_kregs->kr_rcvegrcnt);
++}
 +
-+	ne = container_of(dev, struct node_entry, node_dev);
-+	if (!ne->needs_probe)
-+		nodemgr_probe_ne(param->hi, ne, param->generation);
-+	if (ne->needs_probe)
-+		nodemgr_probe_ne(param->hi, ne, param->generation);
++static void ipath_ht_read_counters(struct ipath_devdata *dd,
++				   struct infinipath_counters *cntrs)
++{
++	cntrs->LBIntCnt =
++		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(LBIntCnt));
++	cntrs->LBFlowStallCnt =
++		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(LBFlowStallCnt));
++	cntrs->TxSDmaDescCnt = 0;
++	cntrs->TxUnsupVLErrCnt =
++		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxUnsupVLErrCnt));
++	cntrs->TxDataPktCnt =
++		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxDataPktCnt));
++	cntrs->TxFlowPktCnt =
++		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxFlowPktCnt));
++	cntrs->TxDwordCnt =
++		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxDwordCnt));
++	cntrs->TxLenErrCnt =
++		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxLenErrCnt));
++	cntrs->TxMaxMinLenErrCnt =
++		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxMaxMinLenErrCnt));
++	cntrs->TxUnderrunCnt =
++		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxUnderrunCnt));
++	cntrs->TxFlowStallCnt =
++		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxFlowStallCnt));
++	cntrs->TxDroppedPktCnt =
++		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxDroppedPktCnt));
++	cntrs->RxDroppedPktCnt =
++		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxDroppedPktCnt));
++	cntrs->RxDataPktCnt =
++		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxDataPktCnt));
++	cntrs->RxFlowPktCnt =
++		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxFlowPktCnt));
++	cntrs->RxDwordCnt =
++		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxDwordCnt));
++	cntrs->RxLenErrCnt =
++		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxLenErrCnt));
++	cntrs->RxMaxMinLenErrCnt =
++		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxMaxMinLenErrCnt));
++	cntrs->RxICRCErrCnt =
++		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxICRCErrCnt));
++	cntrs->RxVCRCErrCnt =
++		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxVCRCErrCnt));
++	cntrs->RxFlowCtrlErrCnt =
++		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxFlowCtrlErrCnt));
++	cntrs->RxBadFormatCnt =
++		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxBadFormatCnt));
++	cntrs->RxLinkProblemCnt =
++		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxLinkProblemCnt));
++	cntrs->RxEBPCnt =
++		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxEBPCnt));
++	cntrs->RxLPCRCErrCnt =
++		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxLPCRCErrCnt));
++	cntrs->RxBufOvflCnt =
++		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxBufOvflCnt));
++	cntrs->RxTIDFullErrCnt =
++		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxTIDFullErrCnt));
++	cntrs->RxTIDValidErrCnt =
++		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxTIDValidErrCnt));
++	cntrs->RxPKeyMismatchCnt =
++		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxPKeyMismatchCnt));
++	cntrs->RxP0HdrEgrOvflCnt =
++		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP0HdrEgrOvflCnt));
++	cntrs->RxP1HdrEgrOvflCnt =
++		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP1HdrEgrOvflCnt));
++	cntrs->RxP2HdrEgrOvflCnt =
++		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP2HdrEgrOvflCnt));
++	cntrs->RxP3HdrEgrOvflCnt =
++		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP3HdrEgrOvflCnt));
++	cntrs->RxP4HdrEgrOvflCnt =
++		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP4HdrEgrOvflCnt));
++	cntrs->RxP5HdrEgrOvflCnt =
++		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP5HdrEgrOvflCnt));
++	cntrs->RxP6HdrEgrOvflCnt =
++		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP6HdrEgrOvflCnt));
++	cntrs->RxP7HdrEgrOvflCnt =
++		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP7HdrEgrOvflCnt));
++	cntrs->RxP8HdrEgrOvflCnt =
++		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP8HdrEgrOvflCnt));
++	cntrs->RxP9HdrEgrOvflCnt = 0;
++	cntrs->RxP10HdrEgrOvflCnt = 0;
++	cntrs->RxP11HdrEgrOvflCnt = 0;
++	cntrs->RxP12HdrEgrOvflCnt = 0;
++	cntrs->RxP13HdrEgrOvflCnt = 0;
++	cntrs->RxP14HdrEgrOvflCnt = 0;
++	cntrs->RxP15HdrEgrOvflCnt = 0;
++	cntrs->RxP16HdrEgrOvflCnt = 0;
++	cntrs->IBStatusChangeCnt =
++		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(IBStatusChangeCnt));
++	cntrs->IBLinkErrRecoveryCnt =
++		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(IBLinkErrRecoveryCnt));
++	cntrs->IBLinkDownedCnt =
++		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(IBLinkDownedCnt));
++	cntrs->IBSymbolErrCnt =
++		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(IBSymbolErrCnt));
++	cntrs->RxVL15DroppedPktCnt = 0;
++	cntrs->RxOtherLocalPhyErrCnt = 0;
++	cntrs->PcieRetryBufDiagQwordCnt = 0;
++	cntrs->ExcessBufferOvflCnt = dd->ipath_overrun_thresh_errs;
++	cntrs->LocalLinkIntegrityErrCnt =
++		(dd->ipath_flags & IPATH_GPIO_ERRINTRS) ?
++		dd->ipath_lli_errs : dd->ipath_lli_errors;
++	cntrs->RxVlErrCnt = 0;
++	cntrs->RxDlidFltrCnt = 0;
++}
++
++
++/* no interrupt fallback for these chips */
++static int ipath_ht_nointr_fallback(struct ipath_devdata *dd)
++{
 +	return 0;
 +}
- 
- static void nodemgr_node_probe(struct host_info *hi, int generation)
- {
- 	struct hpsb_host *host = hi->host;
--	struct device *dev;
--	struct node_entry *ne;
-+	struct probe_param param;
- 
-+	param.hi = hi;
-+	param.generation = generation;
- 	/* Do some processing of the nodes we've probed. This pulls them
- 	 * into the sysfs layer if needed, and can result in processing of
- 	 * unit-directories, or just updating the node and it's
-@@ -1545,19 +1584,7 @@ static void nodemgr_node_probe(struct host_info *hi, int generation)
- 	 * while probes are time-consuming. (Well, those probes need some
- 	 * improvement...) */
- 
--	down(&nodemgr_ne_class.sem);
--	list_for_each_entry(dev, &nodemgr_ne_class.devices, node) {
--		ne = container_of(dev, struct node_entry, node_dev);
--		if (!ne->needs_probe)
--			nodemgr_probe_ne(hi, ne, generation);
--	}
--	list_for_each_entry(dev, &nodemgr_ne_class.devices, node) {
--		ne = container_of(dev, struct node_entry, node_dev);
--		if (ne->needs_probe)
--			nodemgr_probe_ne(hi, ne, generation);
--	}
--	up(&nodemgr_ne_class.sem);
--
-+	class_for_each_device(&nodemgr_ne_class, &param, __nodemgr_node_probe);
- 
- 	/* If we had a bus reset while we were scanning the bus, it is
- 	 * possible that we did not probe all nodes.  In that case, we
-@@ -1757,6 +1784,22 @@ exit:
- 	return 0;
- }
- 
-+struct host_iter_param {
-+	void *data;
-+	int (*cb)(struct hpsb_host *, void *);
-+};
 +
-+static int __nodemgr_for_each_host(struct device *dev, void *data)
++
++/*
++ * reset the XGXS (between serdes and IBC).  Slightly less intrusive
++ * than resetting the IBC or external link state, and useful in some
++ * cases to cause some retraining.  To do this right, we reset IBC
++ * as well.
++ */
++static void ipath_ht_xgxs_reset(struct ipath_devdata *dd)
 +{
-+	struct hpsb_host *host;
-+	struct host_iter_param *hip = (struct host_iter_param *)data;
-+	int error = 0;
++	u64 val, prev_val;
 +
-+	host = container_of(dev, struct hpsb_host, host_dev);
-+	error = hip->cb(host, hip->data);
++	prev_val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_xgxsconfig);
++	val = prev_val | INFINIPATH_XGXS_RESET;
++	prev_val &= ~INFINIPATH_XGXS_RESET; /* be sure */
++	ipath_write_kreg(dd, dd->ipath_kregs->kr_control,
++			 dd->ipath_control & ~INFINIPATH_C_LINKENABLE);
++	ipath_write_kreg(dd, dd->ipath_kregs->kr_xgxsconfig, val);
++	ipath_read_kreg32(dd, dd->ipath_kregs->kr_scratch);
++	ipath_write_kreg(dd, dd->ipath_kregs->kr_xgxsconfig, prev_val);
++	ipath_write_kreg(dd, dd->ipath_kregs->kr_control,
++			 dd->ipath_control);
++}
 +
-+	return error;
++
++static int ipath_ht_get_ib_cfg(struct ipath_devdata *dd, int which)
++{
++	int ret;
++
++	switch (which) {
++	case IPATH_IB_CFG_LWID:
++		ret = dd->ipath_link_width_active;
++		break;
++	case IPATH_IB_CFG_SPD:
++		ret = dd->ipath_link_speed_active;
++		break;
++	case IPATH_IB_CFG_LWID_ENB:
++		ret = dd->ipath_link_width_enabled;
++		break;
++	case IPATH_IB_CFG_SPD_ENB:
++		ret = dd->ipath_link_speed_enabled;
++		break;
++	default:
++		ret =  -ENOTSUPP;
++		break;
++	}
++	return ret;
 +}
- /**
-  * nodemgr_for_each_host - call a function for each IEEE 1394 host
-  * @data: an address to supply to the callback
-@@ -1771,18 +1814,13 @@ exit:
-  */
- int nodemgr_for_each_host(void *data, int (*cb)(struct hpsb_host *, void *))
- {
--	struct device *dev;
--	struct hpsb_host *host;
--	int error = 0;
--
--	down(&hpsb_host_class.sem);
--	list_for_each_entry(dev, &hpsb_host_class.devices, node) {
--		host = container_of(dev, struct hpsb_host, host_dev);
-+	struct host_iter_param hip;
-+	int error;
- 
--		if ((error = cb(host, data)))
--			break;
--	}
--	up(&hpsb_host_class.sem);
-+	hip.cb = cb;
-+	hip.data = data;
-+	error = class_for_each_device(&hpsb_host_class, &hip,
-+				      __nodemgr_for_each_host);
- 
- 	return error;
- }
-diff --git a/drivers/ieee1394/sbp2.c b/drivers/ieee1394/sbp2.c
-index b83d254..1eda11a 100644
---- a/drivers/ieee1394/sbp2.c
-+++ b/drivers/ieee1394/sbp2.c
-@@ -1963,6 +1963,12 @@ static int sbp2scsi_slave_alloc(struct scsi_device *sdev)
- 	lu->sdev = sdev;
- 	sdev->allow_restart = 1;
- 
-+	/*
-+	 * Update the dma alignment (minimum alignment requirements for
-+	 * start and end of DMA transfers) to be a sector
-+	 */
-+	blk_queue_update_dma_alignment(sdev->request_queue, 511);
 +
- 	if (lu->workarounds & SBP2_WORKAROUND_INQUIRY_36)
- 		sdev->inquiry_len = 36;
- 	return 0;
-diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c
-index 2e39236..c015014 100644
---- a/drivers/infiniband/core/cm.c
-+++ b/drivers/infiniband/core/cm.c
-@@ -1,5 +1,5 @@
- /*
-- * Copyright (c) 2004-2006 Intel Corporation.  All rights reserved.
-+ * Copyright (c) 2004-2007 Intel Corporation.  All rights reserved.
-  * Copyright (c) 2004 Topspin Corporation.  All rights reserved.
-  * Copyright (c) 2004, 2005 Voltaire Corporation.  All rights reserved.
-  * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
-@@ -37,12 +37,14 @@
- 
- #include <linux/completion.h>
- #include <linux/dma-mapping.h>
-+#include <linux/device.h>
- #include <linux/err.h>
- #include <linux/idr.h>
- #include <linux/interrupt.h>
- #include <linux/random.h>
- #include <linux/rbtree.h>
- #include <linux/spinlock.h>
-+#include <linux/sysfs.h>
- #include <linux/workqueue.h>
- 
- #include <rdma/ib_cache.h>
-@@ -78,17 +80,94 @@ static struct ib_cm {
- 	struct workqueue_struct *wq;
- } cm;
- 
-+/* Counter indexes ordered by attribute ID */
-+enum {
-+	CM_REQ_COUNTER,
-+	CM_MRA_COUNTER,
-+	CM_REJ_COUNTER,
-+	CM_REP_COUNTER,
-+	CM_RTU_COUNTER,
-+	CM_DREQ_COUNTER,
-+	CM_DREP_COUNTER,
-+	CM_SIDR_REQ_COUNTER,
-+	CM_SIDR_REP_COUNTER,
-+	CM_LAP_COUNTER,
-+	CM_APR_COUNTER,
-+	CM_ATTR_COUNT,
-+	CM_ATTR_ID_OFFSET = 0x0010,
-+};
 +
-+enum {
-+	CM_XMIT,
-+	CM_XMIT_RETRIES,
-+	CM_RECV,
-+	CM_RECV_DUPLICATES,
-+	CM_COUNTER_GROUPS
-+};
++/* we assume range checking is already done, if needed */
++static int ipath_ht_set_ib_cfg(struct ipath_devdata *dd, int which, u32 val)
++{
++	int ret = 0;
 +
-+static char const counter_group_names[CM_COUNTER_GROUPS]
-+				     [sizeof("cm_rx_duplicates")] = {
-+	"cm_tx_msgs", "cm_tx_retries",
-+	"cm_rx_msgs", "cm_rx_duplicates"
-+};
++	if (which == IPATH_IB_CFG_LWID_ENB)
++		dd->ipath_link_width_enabled = val;
++	else if (which == IPATH_IB_CFG_SPD_ENB)
++		dd->ipath_link_speed_enabled = val;
++	else
++		ret = -ENOTSUPP;
++	return ret;
++}
 +
-+struct cm_counter_group {
-+	struct kobject obj;
-+	atomic_long_t counter[CM_ATTR_COUNT];
-+};
 +
-+struct cm_counter_attribute {
-+	struct attribute attr;
-+	int index;
-+};
++static void ipath_ht_config_jint(struct ipath_devdata *dd, u16 a, u16 b)
++{
++}
 +
-+#define CM_COUNTER_ATTR(_name, _index) \
-+struct cm_counter_attribute cm_##_name##_counter_attr = { \
-+	.attr = { .name = __stringify(_name), .mode = 0444, .owner = THIS_MODULE }, \
-+	.index = _index \
++
++static int ipath_ht_ib_updown(struct ipath_devdata *dd, int ibup, u64 ibcs)
++{
++	ipath_setup_ht_setextled(dd, ipath_ib_linkstate(dd, ibcs),
++		ipath_ib_linktrstate(dd, ibcs));
++	return 0;
 +}
 +
-+static CM_COUNTER_ATTR(req, CM_REQ_COUNTER);
-+static CM_COUNTER_ATTR(mra, CM_MRA_COUNTER);
-+static CM_COUNTER_ATTR(rej, CM_REJ_COUNTER);
-+static CM_COUNTER_ATTR(rep, CM_REP_COUNTER);
-+static CM_COUNTER_ATTR(rtu, CM_RTU_COUNTER);
-+static CM_COUNTER_ATTR(dreq, CM_DREQ_COUNTER);
-+static CM_COUNTER_ATTR(drep, CM_DREP_COUNTER);
-+static CM_COUNTER_ATTR(sidr_req, CM_SIDR_REQ_COUNTER);
-+static CM_COUNTER_ATTR(sidr_rep, CM_SIDR_REP_COUNTER);
-+static CM_COUNTER_ATTR(lap, CM_LAP_COUNTER);
-+static CM_COUNTER_ATTR(apr, CM_APR_COUNTER);
 +
-+static struct attribute *cm_counter_default_attrs[] = {
-+	&cm_req_counter_attr.attr,
-+	&cm_mra_counter_attr.attr,
-+	&cm_rej_counter_attr.attr,
-+	&cm_rep_counter_attr.attr,
-+	&cm_rtu_counter_attr.attr,
-+	&cm_dreq_counter_attr.attr,
-+	&cm_drep_counter_attr.attr,
-+	&cm_sidr_req_counter_attr.attr,
-+	&cm_sidr_rep_counter_attr.attr,
-+	&cm_lap_counter_attr.attr,
-+	&cm_apr_counter_attr.attr,
-+	NULL
+ /**
+  * ipath_init_iba6110_funcs - set up the chip-specific function pointers
+  * @dd: the infinipath device
+@@ -1626,22 +1926,19 @@ void ipath_init_iba6110_funcs(struct ipath_devdata *dd)
+ 	dd->ipath_f_setextled = ipath_setup_ht_setextled;
+ 	dd->ipath_f_get_base_info = ipath_ht_get_base_info;
+ 	dd->ipath_f_free_irq = ipath_ht_free_irq;
+-
+-	/*
+-	 * initialize chip-specific variables
+-	 */
+ 	dd->ipath_f_tidtemplate = ipath_ht_tidtemplate;
++	dd->ipath_f_intr_fallback = ipath_ht_nointr_fallback;
++	dd->ipath_f_get_msgheader = ipath_ht_get_msgheader;
++	dd->ipath_f_config_ports = ipath_ht_config_ports;
++	dd->ipath_f_read_counters = ipath_ht_read_counters;
++	dd->ipath_f_xgxs_reset = ipath_ht_xgxs_reset;
++	dd->ipath_f_get_ib_cfg = ipath_ht_get_ib_cfg;
++	dd->ipath_f_set_ib_cfg = ipath_ht_set_ib_cfg;
++	dd->ipath_f_config_jint = ipath_ht_config_jint;
++	dd->ipath_f_ib_updown = ipath_ht_ib_updown;
+ 
+ 	/*
+-	 * setup the register offsets, since they are different for each
+-	 * chip
+-	 */
+-	dd->ipath_kregs = &ipath_ht_kregs;
+-	dd->ipath_cregs = &ipath_ht_cregs;
+-
+-	/*
+-	 * do very early init that is needed before ipath_f_bus is
+-	 * called
++	 * initialize chip-specific variables
+ 	 */
+ 	ipath_init_ht_variables(dd);
+ }
+diff --git a/drivers/infiniband/hw/ipath/ipath_iba6120.c b/drivers/infiniband/hw/ipath/ipath_iba6120.c
+index 0103d6f..c7a2f50 100644
+--- a/drivers/infiniband/hw/ipath/ipath_iba6120.c
++++ b/drivers/infiniband/hw/ipath/ipath_iba6120.c
+@@ -145,10 +145,57 @@ struct _infinipath_do_not_use_kernel_regs {
+ 	unsigned long long Reserved12;
+ };
+ 
+-#define IPATH_KREG_OFFSET(field) (offsetof(struct \
+-    _infinipath_do_not_use_kernel_regs, field) / sizeof(u64))
++struct _infinipath_do_not_use_counters {
++	__u64 LBIntCnt;
++	__u64 LBFlowStallCnt;
++	__u64 Reserved1;
++	__u64 TxUnsupVLErrCnt;
++	__u64 TxDataPktCnt;
++	__u64 TxFlowPktCnt;
++	__u64 TxDwordCnt;
++	__u64 TxLenErrCnt;
++	__u64 TxMaxMinLenErrCnt;
++	__u64 TxUnderrunCnt;
++	__u64 TxFlowStallCnt;
++	__u64 TxDroppedPktCnt;
++	__u64 RxDroppedPktCnt;
++	__u64 RxDataPktCnt;
++	__u64 RxFlowPktCnt;
++	__u64 RxDwordCnt;
++	__u64 RxLenErrCnt;
++	__u64 RxMaxMinLenErrCnt;
++	__u64 RxICRCErrCnt;
++	__u64 RxVCRCErrCnt;
++	__u64 RxFlowCtrlErrCnt;
++	__u64 RxBadFormatCnt;
++	__u64 RxLinkProblemCnt;
++	__u64 RxEBPCnt;
++	__u64 RxLPCRCErrCnt;
++	__u64 RxBufOvflCnt;
++	__u64 RxTIDFullErrCnt;
++	__u64 RxTIDValidErrCnt;
++	__u64 RxPKeyMismatchCnt;
++	__u64 RxP0HdrEgrOvflCnt;
++	__u64 RxP1HdrEgrOvflCnt;
++	__u64 RxP2HdrEgrOvflCnt;
++	__u64 RxP3HdrEgrOvflCnt;
++	__u64 RxP4HdrEgrOvflCnt;
++	__u64 RxP5HdrEgrOvflCnt;
++	__u64 RxP6HdrEgrOvflCnt;
++	__u64 RxP7HdrEgrOvflCnt;
++	__u64 RxP8HdrEgrOvflCnt;
++	__u64 Reserved6;
++	__u64 Reserved7;
++	__u64 IBStatusChangeCnt;
++	__u64 IBLinkErrRecoveryCnt;
++	__u64 IBLinkDownedCnt;
++	__u64 IBSymbolErrCnt;
 +};
 +
- struct cm_port {
- 	struct cm_device *cm_dev;
- 	struct ib_mad_agent *mad_agent;
-+	struct kobject port_obj;
- 	u8 port_num;
-+	struct cm_counter_group counter_group[CM_COUNTER_GROUPS];
- };
++#define IPATH_KREG_OFFSET(field) (offsetof( \
++	struct _infinipath_do_not_use_kernel_regs, field) / sizeof(u64))
+ #define IPATH_CREG_OFFSET(field) (offsetof( \
+-    struct infinipath_counters, field) / sizeof(u64))
++	struct _infinipath_do_not_use_counters, field) / sizeof(u64))
  
- struct cm_device {
- 	struct list_head list;
- 	struct ib_device *device;
-+	struct kobject dev_obj;
- 	u8 ack_delay;
--	struct cm_port port[0];
-+	struct cm_port *port[0];
- };
+ static const struct ipath_kregs ipath_pe_kregs = {
+ 	.kr_control = IPATH_KREG_OFFSET(Control),
+@@ -282,6 +329,9 @@ static const struct ipath_cregs ipath_pe_cregs = {
+ #define INFINIPATH_HWE_PCIE0PLLFAILED       0x0800000000000000ULL
+ #define INFINIPATH_HWE_SERDESPLLFAILED      0x1000000000000000ULL
  
- struct cm_av {
-@@ -278,7 +357,7 @@ static int cm_init_av_by_path(struct ib_sa_path_rec *path, struct cm_av *av)
- 	list_for_each_entry(cm_dev, &cm.device_list, list) {
- 		if (!ib_find_cached_gid(cm_dev->device, &path->sgid,
- 					&p, NULL)) {
--			port = &cm_dev->port[p-1];
-+			port = cm_dev->port[p-1];
- 			break;
- 		}
- 	}
-@@ -1270,6 +1349,9 @@ static void cm_dup_req_handler(struct cm_work *work,
- 	struct ib_mad_send_buf *msg = NULL;
- 	int ret;
++#define IBA6120_IBCS_LINKTRAININGSTATE_MASK 0xf
++#define IBA6120_IBCS_LINKSTATE_SHIFT 4
++
+ /* kr_extstatus bits */
+ #define INFINIPATH_EXTS_FREQSEL 0x2
+ #define INFINIPATH_EXTS_SERDESSEL 0x4
+@@ -296,6 +346,9 @@ static const struct ipath_cregs ipath_pe_cregs = {
+ #define IPATH_GPIO_SCL (1ULL << \
+ 	(_IPATH_GPIO_SCL_NUM+INFINIPATH_EXTC_GPIOOE_SHIFT))
  
-+	atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES].
-+			counter[CM_REQ_COUNTER]);
++#define INFINIPATH_R_INTRAVAIL_SHIFT 16
++#define INFINIPATH_R_TAILUPD_SHIFT 31
 +
- 	/* Quick state check to discard duplicate REQs. */
- 	if (cm_id_priv->id.state == IB_CM_REQ_RCVD)
- 		return;
-@@ -1616,6 +1698,8 @@ static void cm_dup_rep_handler(struct cm_work *work)
- 	if (!cm_id_priv)
- 		return;
+ /* 6120 specific hardware errors... */
+ static const struct ipath_hwerror_msgs ipath_6120_hwerror_msgs[] = {
+ 	INFINIPATH_HWE_MSG(PCIEPOISONEDTLP, "PCIe Poisoned TLP"),
+@@ -320,10 +373,28 @@ static const struct ipath_hwerror_msgs ipath_6120_hwerror_msgs[] = {
+ 		        INFINIPATH_HWE_TXEMEMPARITYERR_PIOPBC) \
+ 		        << INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT)
  
-+	atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES].
-+			counter[CM_REP_COUNTER]);
- 	ret = cm_alloc_response_msg(work->port, work->mad_recv_wc, &msg);
- 	if (ret)
- 		goto deref;
-@@ -1781,6 +1865,8 @@ static int cm_rtu_handler(struct cm_work *work)
- 	if (cm_id_priv->id.state != IB_CM_REP_SENT &&
- 	    cm_id_priv->id.state != IB_CM_MRA_REP_RCVD) {
- 		spin_unlock_irq(&cm_id_priv->lock);
-+		atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES].
-+				counter[CM_RTU_COUNTER]);
- 		goto out;
- 	}
- 	cm_id_priv->id.state = IB_CM_ESTABLISHED;
-@@ -1958,6 +2044,8 @@ static int cm_dreq_handler(struct cm_work *work)
- 	cm_id_priv = cm_acquire_id(dreq_msg->remote_comm_id,
- 				   dreq_msg->local_comm_id);
- 	if (!cm_id_priv) {
-+		atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES].
-+				counter[CM_DREQ_COUNTER]);
- 		cm_issue_drep(work->port, work->mad_recv_wc);
- 		return -EINVAL;
- 	}
-@@ -1977,6 +2065,8 @@ static int cm_dreq_handler(struct cm_work *work)
- 	case IB_CM_MRA_REP_RCVD:
- 		break;
- 	case IB_CM_TIMEWAIT:
-+		atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES].
-+				counter[CM_DREQ_COUNTER]);
- 		if (cm_alloc_response_msg(work->port, work->mad_recv_wc, &msg))
- 			goto unlock;
+-static int ipath_pe_txe_recover(struct ipath_devdata *);
+ static void ipath_pe_put_tid_2(struct ipath_devdata *, u64 __iomem *,
+ 			       u32, unsigned long);
  
-@@ -1988,6 +2078,10 @@ static int cm_dreq_handler(struct cm_work *work)
- 		if (ib_post_send_mad(msg, NULL))
- 			cm_free_msg(msg);
- 		goto deref;
-+	case IB_CM_DREQ_RCVD:
-+		atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES].
-+				counter[CM_DREQ_COUNTER]);
-+		goto unlock;
- 	default:
- 		goto unlock;
- 	}
-@@ -2339,10 +2433,20 @@ static int cm_mra_handler(struct cm_work *work)
- 		if (cm_mra_get_msg_mraed(mra_msg) != CM_MSG_RESPONSE_OTHER ||
- 		    cm_id_priv->id.lap_state != IB_CM_LAP_SENT ||
- 		    ib_modify_mad(cm_id_priv->av.port->mad_agent,
--				  cm_id_priv->msg, timeout))
-+				  cm_id_priv->msg, timeout)) {
-+			if (cm_id_priv->id.lap_state == IB_CM_MRA_LAP_RCVD)
-+				atomic_long_inc(&work->port->
-+						counter_group[CM_RECV_DUPLICATES].
-+						counter[CM_MRA_COUNTER]);
- 			goto out;
++/*
++ * On platforms using this chip, and not having ordered WC stores, we
++ * can get TXE parity errors due to speculative reads to the PIO buffers,
++ * and this, due to a chip bug can result in (many) false parity error
++ * reports.  So it's a debug print on those, and an info print on systems
++ * where the speculative reads don't occur.
++ */
++static void ipath_pe_txe_recover(struct ipath_devdata *dd)
++{
++	if (ipath_unordered_wc())
++		ipath_dbg("Recovering from TXE PIO parity error\n");
++	else {
++		++ipath_stats.sps_txeparity;
++		dev_info(&dd->pcidev->dev,
++			"Recovering from TXE PIO parity error\n");
++	}
++}
++
++
+ /**
+  * ipath_pe_handle_hwerrors - display hardware errors.
+  * @dd: the infinipath device
+@@ -403,35 +474,11 @@ static void ipath_pe_handle_hwerrors(struct ipath_devdata *dd, char *msg,
+ 		 * occur if a processor speculative read is done to the PIO
+ 		 * buffer while we are sending a packet, for example.
+ 		 */
+-		if ((hwerrs & TXE_PIO_PARITY) && ipath_pe_txe_recover(dd))
++		if (hwerrs & TXE_PIO_PARITY) {
++			ipath_pe_txe_recover(dd);
+ 			hwerrs &= ~TXE_PIO_PARITY;
+-		if (hwerrs) {
+-			/*
+-			 * if any set that we aren't ignoring only make the
+-			 * complaint once, in case it's stuck or recurring,
+-			 * and we get here multiple times
+-			 * Force link down, so switch knows, and
+-			 * LEDs are turned off
+-			 */
+-			if (dd->ipath_flags & IPATH_INITTED) {
+-				ipath_set_linkstate(dd, IPATH_IB_LINKDOWN);
+-				ipath_setup_pe_setextled(dd,
+-					INFINIPATH_IBCS_L_STATE_DOWN,
+-					INFINIPATH_IBCS_LT_STATE_DISABLED);
+-				ipath_dev_err(dd, "Fatal Hardware Error (freeze "
+-					      "mode), no longer usable, SN %.16s\n",
+-						  dd->ipath_serial);
+-				isfatal = 1;
+-			}
+-			/*
+-			 * Mark as having had an error for driver, and also
+-			 * for /sys and status word mapped to user programs.
+-			 * This marks unit as not usable, until reset
+-			 */
+-			*dd->ipath_statusp &= ~IPATH_STATUS_IB_READY;
+-			*dd->ipath_statusp |= IPATH_STATUS_HWERROR;
+-			dd->ipath_flags &= ~IPATH_INITTED;
+-		} else {
 +		}
- 		cm_id_priv->id.lap_state = IB_CM_MRA_LAP_RCVD;
- 		break;
-+	case IB_CM_MRA_REQ_RCVD:
-+	case IB_CM_MRA_REP_RCVD:
-+		atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES].
-+				counter[CM_MRA_COUNTER]);
-+		/* fall through */
- 	default:
- 		goto out;
- 	}
-@@ -2502,6 +2606,8 @@ static int cm_lap_handler(struct cm_work *work)
- 	case IB_CM_LAP_IDLE:
- 		break;
- 	case IB_CM_MRA_LAP_SENT:
-+		atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES].
-+				counter[CM_LAP_COUNTER]);
- 		if (cm_alloc_response_msg(work->port, work->mad_recv_wc, &msg))
- 			goto unlock;
++		if (!hwerrs) {
+ 			static u32 freeze_cnt;
  
-@@ -2515,6 +2621,10 @@ static int cm_lap_handler(struct cm_work *work)
- 		if (ib_post_send_mad(msg, NULL))
- 			cm_free_msg(msg);
- 		goto deref;
-+	case IB_CM_LAP_RCVD:
-+		atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES].
-+				counter[CM_LAP_COUNTER]);
-+		goto unlock;
- 	default:
- 		goto unlock;
- 	}
-@@ -2796,6 +2906,8 @@ static int cm_sidr_req_handler(struct cm_work *work)
- 	cur_cm_id_priv = cm_insert_remote_sidr(cm_id_priv);
- 	if (cur_cm_id_priv) {
- 		spin_unlock_irq(&cm.lock);
-+		atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES].
-+				counter[CM_SIDR_REQ_COUNTER]);
- 		goto out; /* Duplicate message. */
+ 			freeze_cnt++;
+@@ -485,7 +532,7 @@ static void ipath_pe_handle_hwerrors(struct ipath_devdata *dd, char *msg,
+ 
+ 	if (hwerrs & INFINIPATH_HWE_SERDESPLLFAILED) {
+ 		/*
+-		 * If it occurs, it is left masked since the eternal
++		 * If it occurs, it is left masked since the external
+ 		 * interface is unused
+ 		 */
+ 		dd->ipath_hwerrmask &= ~INFINIPATH_HWE_SERDESPLLFAILED;
+@@ -563,6 +610,14 @@ static int ipath_pe_boardname(struct ipath_devdata *dd, char *name,
+ 			dd->ipath_f_put_tid = ipath_pe_put_tid_2;
  	}
- 	cm_id_priv->id.state = IB_CM_SIDR_REQ_RCVD;
-@@ -2990,6 +3102,27 @@ static void cm_send_handler(struct ib_mad_agent *mad_agent,
- 			    struct ib_mad_send_wc *mad_send_wc)
- {
- 	struct ib_mad_send_buf *msg = mad_send_wc->send_buf;
-+	struct cm_port *port;
-+	u16 attr_index;
-+
-+	port = mad_agent->context;
-+	attr_index = be16_to_cpu(((struct ib_mad_hdr *)
-+				  msg->mad)->attr_id) - CM_ATTR_ID_OFFSET;
+ 
 +
 +	/*
-+	 * If the send was in response to a received message (context[0] is not
-+	 * set to a cm_id), and is not a REJ, then it is a send that was
-+	 * manually retried.
++	 * set here, not in ipath_init_*_funcs because we have to do
++	 * it after we can read chip registers.
 +	 */
-+	if (!msg->context[0] && (attr_index != CM_REJ_COUNTER))
-+		msg->retries = 1;
++	dd->ipath_ureg_align =
++		ipath_read_kreg32(dd, dd->ipath_kregs->kr_pagealign);
 +
-+	atomic_long_add(1 + msg->retries,
-+			&port->counter_group[CM_XMIT].counter[attr_index]);
-+	if (msg->retries)
-+		atomic_long_add(msg->retries,
-+				&port->counter_group[CM_XMIT_RETRIES].
-+				counter[attr_index]);
+ 	return ret;
+ }
  
- 	switch (mad_send_wc->status) {
- 	case IB_WC_SUCCESS:
-@@ -3148,8 +3281,10 @@ EXPORT_SYMBOL(ib_cm_notify);
- static void cm_recv_handler(struct ib_mad_agent *mad_agent,
- 			    struct ib_mad_recv_wc *mad_recv_wc)
- {
-+	struct cm_port *port = mad_agent->context;
- 	struct cm_work *work;
- 	enum ib_cm_event_type event;
-+	u16 attr_id;
- 	int paths = 0;
+@@ -667,17 +722,8 @@ static int ipath_pe_bringup_serdes(struct ipath_devdata *dd)
  
- 	switch (mad_recv_wc->recv_buf.mad->mad_hdr.attr_id) {
-@@ -3194,6 +3329,10 @@ static void cm_recv_handler(struct ib_mad_agent *mad_agent,
- 		return;
- 	}
+ 	val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_xgxsconfig);
+ 	prev_val = val;
+-	if (((val >> INFINIPATH_XGXS_MDIOADDR_SHIFT) &
+-	     INFINIPATH_XGXS_MDIOADDR_MASK) != 3) {
+-		val &=
+-			~(INFINIPATH_XGXS_MDIOADDR_MASK <<
+-			  INFINIPATH_XGXS_MDIOADDR_SHIFT);
+-		/* MDIO address 3 */
+-		val |= 3ULL << INFINIPATH_XGXS_MDIOADDR_SHIFT;
+-	}
+-	if (val & INFINIPATH_XGXS_RESET) {
++	if (val & INFINIPATH_XGXS_RESET)
+ 		val &= ~INFINIPATH_XGXS_RESET;
+-	}
+ 	if (((val >> INFINIPATH_XGXS_RX_POL_SHIFT) &
+ 	     INFINIPATH_XGXS_RX_POL_MASK) != dd->ipath_rx_pol_inv ) {
+ 		/* need to compensate for Tx inversion in partner */
+@@ -707,21 +753,6 @@ static int ipath_pe_bringup_serdes(struct ipath_devdata *dd)
+ 		   (unsigned long long)
+ 		   ipath_read_kreg64(dd, dd->ipath_kregs->kr_xgxsconfig));
  
-+	attr_id = be16_to_cpu(mad_recv_wc->recv_buf.mad->mad_hdr.attr_id);
-+	atomic_long_inc(&port->counter_group[CM_RECV].
-+			counter[attr_id - CM_ATTR_ID_OFFSET]);
-+
- 	work = kmalloc(sizeof *work + sizeof(struct ib_sa_path_rec) * paths,
- 		       GFP_KERNEL);
- 	if (!work) {
-@@ -3204,7 +3343,7 @@ static void cm_recv_handler(struct ib_mad_agent *mad_agent,
- 	INIT_DELAYED_WORK(&work->work, cm_work_handler);
- 	work->cm_event.event = event;
- 	work->mad_recv_wc = mad_recv_wc;
--	work->port = (struct cm_port *)mad_agent->context;
-+	work->port = port;
- 	queue_delayed_work(cm.wq, &work->work, 0);
+-	if (!ipath_waitfor_mdio_cmdready(dd)) {
+-		ipath_write_kreg(
+-			dd, dd->ipath_kregs->kr_mdio,
+-			ipath_mdio_req(IPATH_MDIO_CMD_READ, 31,
+-				       IPATH_MDIO_CTRL_XGXS_REG_8, 0));
+-		if (ipath_waitfor_complete(dd, dd->ipath_kregs->kr_mdio,
+-					   IPATH_MDIO_DATAVALID, &val))
+-			ipath_dbg("Never got MDIO data for XGXS "
+-				  "status read\n");
+-		else
+-			ipath_cdbg(VERBOSE, "MDIO Read reg8, "
+-				   "'bank' 31 %x\n", (u32) val);
+-	} else
+-		ipath_dbg("Never got MDIO cmdready for XGXS status read\n");
+-
+ 	return ret;
  }
  
-@@ -3379,6 +3518,108 @@ static void cm_get_ack_delay(struct cm_device *cm_dev)
- 		cm_dev->ack_delay = attr.local_ca_ack_delay;
+@@ -902,12 +933,27 @@ static int ipath_setup_pe_config(struct ipath_devdata *dd,
+ 	else
+ 		ipath_dev_err(dd, "Can't find PCI Express "
+ 			      "capability!\n");
++
++	dd->ipath_link_width_supported = IB_WIDTH_1X | IB_WIDTH_4X;
++	dd->ipath_link_speed_supported = IPATH_IB_SDR;
++	dd->ipath_link_width_enabled = IB_WIDTH_4X;
++	dd->ipath_link_speed_enabled = dd->ipath_link_speed_supported;
++	/* these can't change for this chip, so set once */
++	dd->ipath_link_width_active = dd->ipath_link_width_enabled;
++	dd->ipath_link_speed_active = dd->ipath_link_speed_enabled;
+ 	return 0;
  }
  
-+static ssize_t cm_show_counter(struct kobject *obj, struct attribute *attr,
-+			       char *buf)
-+{
-+	struct cm_counter_group *group;
-+	struct cm_counter_attribute *cm_attr;
+ static void ipath_init_pe_variables(struct ipath_devdata *dd)
+ {
+ 	/*
++	 * setup the register offsets, since they are different for each
++	 * chip
++	 */
++	dd->ipath_kregs = &ipath_pe_kregs;
++	dd->ipath_cregs = &ipath_pe_cregs;
 +
-+	group = container_of(obj, struct cm_counter_group, obj);
-+	cm_attr = container_of(attr, struct cm_counter_attribute, attr);
++	/*
+ 	 * bits for selecting i2c direction and values,
+ 	 * used for I2C serial flash
+ 	 */
+@@ -916,6 +962,43 @@ static void ipath_init_pe_variables(struct ipath_devdata *dd)
+ 	dd->ipath_gpio_sda = IPATH_GPIO_SDA;
+ 	dd->ipath_gpio_scl = IPATH_GPIO_SCL;
+ 
++	/*
++	 * Fill in data for field-values that change in newer chips.
++	 * We dynamically specify only the mask for LINKTRAININGSTATE
++	 * and only the shift for LINKSTATE, as they are the only ones
++	 * that change.  Also precalculate the 3 link states of interest
++	 * and the combined mask.
++	 */
++	dd->ibcs_ls_shift = IBA6120_IBCS_LINKSTATE_SHIFT;
++	dd->ibcs_lts_mask = IBA6120_IBCS_LINKTRAININGSTATE_MASK;
++	dd->ibcs_mask = (INFINIPATH_IBCS_LINKSTATE_MASK <<
++		dd->ibcs_ls_shift) | dd->ibcs_lts_mask;
++	dd->ib_init = (INFINIPATH_IBCS_LT_STATE_LINKUP <<
++		INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT) |
++		(INFINIPATH_IBCS_L_STATE_INIT << dd->ibcs_ls_shift);
++	dd->ib_arm = (INFINIPATH_IBCS_LT_STATE_LINKUP <<
++		INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT) |
++		(INFINIPATH_IBCS_L_STATE_ARM << dd->ibcs_ls_shift);
++	dd->ib_active = (INFINIPATH_IBCS_LT_STATE_LINKUP <<
++		INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT) |
++		(INFINIPATH_IBCS_L_STATE_ACTIVE << dd->ibcs_ls_shift);
 +
-+	return sprintf(buf, "%ld\n",
-+		       atomic_long_read(&group->counter[cm_attr->index]));
-+}
++	/*
++	 * Fill in data for ibcc field-values that change in newer chips.
++	 * We dynamically specify only the mask for LINKINITCMD
++	 * and only the shift for LINKCMD and MAXPKTLEN, as they are
++	 * the only ones that change.
++	 */
++	dd->ibcc_lic_mask = INFINIPATH_IBCC_LINKINITCMD_MASK;
++	dd->ibcc_lc_shift = INFINIPATH_IBCC_LINKCMD_SHIFT;
++	dd->ibcc_mpl_shift = INFINIPATH_IBCC_MAXPKTLEN_SHIFT;
 +
-+static struct sysfs_ops cm_counter_ops = {
-+	.show = cm_show_counter
-+};
++	/* Fill in shifts for RcvCtrl. */
++	dd->ipath_r_portenable_shift = INFINIPATH_R_PORTENABLE_SHIFT;
++	dd->ipath_r_intravail_shift = INFINIPATH_R_INTRAVAIL_SHIFT;
++	dd->ipath_r_tailupd_shift = INFINIPATH_R_TAILUPD_SHIFT;
++	dd->ipath_r_portcfg_shift = 0; /* Not on IBA6120 */
 +
-+static struct kobj_type cm_counter_obj_type = {
-+	.sysfs_ops = &cm_counter_ops,
-+	.default_attrs = cm_counter_default_attrs
-+};
+ 	/* variables for sanity checking interrupt and errors */
+ 	dd->ipath_hwe_bitsextant =
+ 		(INFINIPATH_HWE_RXEMEMPARITYERR_MASK <<
+@@ -963,6 +1046,8 @@ static void ipath_init_pe_variables(struct ipath_devdata *dd)
+ 
+ 	dd->ipath_i_rcvavail_mask = INFINIPATH_I_RCVAVAIL_MASK;
+ 	dd->ipath_i_rcvurg_mask = INFINIPATH_I_RCVURG_MASK;
++	dd->ipath_i_rcvavail_shift = INFINIPATH_I_RCVAVAIL_SHIFT;
++	dd->ipath_i_rcvurg_shift = INFINIPATH_I_RCVURG_SHIFT;
+ 
+ 	/*
+ 	 * EEPROM error log 0 is TXE Parity errors. 1 is RXE Parity.
+@@ -984,6 +1069,7 @@ static void ipath_init_pe_variables(struct ipath_devdata *dd)
+ 		INFINIPATH_E_INVALIDADDR | INFINIPATH_E_RESET;
+ 
+ 
++	dd->delay_mult = 2; /* SDR, 4X, can't change */
+ }
+ 
+ /* setup the MSI stuff again after a reset.  I'd like to just call
+@@ -1289,6 +1375,9 @@ static int ipath_pe_early_init(struct ipath_devdata *dd)
+ 	 */
+ 	dd->ipath_rcvhdrentsize = 24;
+ 	dd->ipath_rcvhdrsize = IPATH_DFLT_RCVHDRSIZE;
++	dd->ipath_rhf_offset = 0;
++	dd->ipath_egrtidbase = (u64 __iomem *)
++		((char __iomem *) dd->ipath_kregbase + dd->ipath_rcvegrbase);
+ 
+ 	/*
+ 	 * To truly support a 4KB MTU (for usermode), we need to
+@@ -1359,34 +1448,204 @@ static void ipath_pe_free_irq(struct ipath_devdata *dd)
+ 	dd->ipath_irq = 0;
+ }
+ 
 +
-+static void cm_release_port_obj(struct kobject *obj)
++static struct ipath_message_header *
++ipath_pe_get_msgheader(struct ipath_devdata *dd, __le32 *rhf_addr)
 +{
-+	struct cm_port *cm_port;
-+
-+	printk(KERN_ERR "free cm port\n");
-+
-+	cm_port = container_of(obj, struct cm_port, port_obj);
-+	kfree(cm_port);
++	return (struct ipath_message_header *)
++		&rhf_addr[sizeof(u64) / sizeof(u32)];
 +}
 +
-+static struct kobj_type cm_port_obj_type = {
-+	.release = cm_release_port_obj
-+};
-+
-+static void cm_release_dev_obj(struct kobject *obj)
++static void ipath_pe_config_ports(struct ipath_devdata *dd, ushort cfgports)
 +{
-+	struct cm_device *cm_dev;
-+
-+	printk(KERN_ERR "free cm dev\n");
-+
-+	cm_dev = container_of(obj, struct cm_device, dev_obj);
-+	kfree(cm_dev);
++	dd->ipath_portcnt =
++		ipath_read_kreg32(dd, dd->ipath_kregs->kr_portcnt);
++	dd->ipath_p0_rcvegrcnt =
++		ipath_read_kreg32(dd, dd->ipath_kregs->kr_rcvegrcnt);
 +}
 +
-+static struct kobj_type cm_dev_obj_type = {
-+	.release = cm_release_dev_obj
-+};
++static void ipath_pe_read_counters(struct ipath_devdata *dd,
++				   struct infinipath_counters *cntrs)
++{
++	cntrs->LBIntCnt =
++		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(LBIntCnt));
++	cntrs->LBFlowStallCnt =
++		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(LBFlowStallCnt));
++	cntrs->TxSDmaDescCnt = 0;
++	cntrs->TxUnsupVLErrCnt =
++		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxUnsupVLErrCnt));
++	cntrs->TxDataPktCnt =
++		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxDataPktCnt));
++	cntrs->TxFlowPktCnt =
++		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxFlowPktCnt));
++	cntrs->TxDwordCnt =
++		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxDwordCnt));
++	cntrs->TxLenErrCnt =
++		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxLenErrCnt));
++	cntrs->TxMaxMinLenErrCnt =
++		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxMaxMinLenErrCnt));
++	cntrs->TxUnderrunCnt =
++		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxUnderrunCnt));
++	cntrs->TxFlowStallCnt =
++		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxFlowStallCnt));
++	cntrs->TxDroppedPktCnt =
++		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxDroppedPktCnt));
++	cntrs->RxDroppedPktCnt =
++		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxDroppedPktCnt));
++	cntrs->RxDataPktCnt =
++		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxDataPktCnt));
++	cntrs->RxFlowPktCnt =
++		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxFlowPktCnt));
++	cntrs->RxDwordCnt =
++		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxDwordCnt));
++	cntrs->RxLenErrCnt =
++		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxLenErrCnt));
++	cntrs->RxMaxMinLenErrCnt =
++		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxMaxMinLenErrCnt));
++	cntrs->RxICRCErrCnt =
++		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxICRCErrCnt));
++	cntrs->RxVCRCErrCnt =
++		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxVCRCErrCnt));
++	cntrs->RxFlowCtrlErrCnt =
++		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxFlowCtrlErrCnt));
++	cntrs->RxBadFormatCnt =
++		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxBadFormatCnt));
++	cntrs->RxLinkProblemCnt =
++		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxLinkProblemCnt));
++	cntrs->RxEBPCnt =
++		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxEBPCnt));
++	cntrs->RxLPCRCErrCnt =
++		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxLPCRCErrCnt));
++	cntrs->RxBufOvflCnt =
++		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxBufOvflCnt));
++	cntrs->RxTIDFullErrCnt =
++		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxTIDFullErrCnt));
++	cntrs->RxTIDValidErrCnt =
++		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxTIDValidErrCnt));
++	cntrs->RxPKeyMismatchCnt =
++		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxPKeyMismatchCnt));
++	cntrs->RxP0HdrEgrOvflCnt =
++		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP0HdrEgrOvflCnt));
++	cntrs->RxP1HdrEgrOvflCnt =
++		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP1HdrEgrOvflCnt));
++	cntrs->RxP2HdrEgrOvflCnt =
++		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP2HdrEgrOvflCnt));
++	cntrs->RxP3HdrEgrOvflCnt =
++		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP3HdrEgrOvflCnt));
++	cntrs->RxP4HdrEgrOvflCnt =
++		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP4HdrEgrOvflCnt));
++	cntrs->RxP5HdrEgrOvflCnt = 0;
++	cntrs->RxP6HdrEgrOvflCnt = 0;
++	cntrs->RxP7HdrEgrOvflCnt = 0;
++	cntrs->RxP8HdrEgrOvflCnt = 0;
++	cntrs->RxP9HdrEgrOvflCnt = 0;
++	cntrs->RxP10HdrEgrOvflCnt = 0;
++	cntrs->RxP11HdrEgrOvflCnt = 0;
++	cntrs->RxP12HdrEgrOvflCnt = 0;
++	cntrs->RxP13HdrEgrOvflCnt = 0;
++	cntrs->RxP14HdrEgrOvflCnt = 0;
++	cntrs->RxP15HdrEgrOvflCnt = 0;
++	cntrs->RxP16HdrEgrOvflCnt = 0;
++	cntrs->IBStatusChangeCnt =
++		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(IBStatusChangeCnt));
++	cntrs->IBLinkErrRecoveryCnt =
++		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(IBLinkErrRecoveryCnt));
++	cntrs->IBLinkDownedCnt =
++		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(IBLinkDownedCnt));
++	cntrs->IBSymbolErrCnt =
++		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(IBSymbolErrCnt));
++	cntrs->RxVL15DroppedPktCnt = 0;
++	cntrs->RxOtherLocalPhyErrCnt = 0;
++	cntrs->PcieRetryBufDiagQwordCnt = 0;
++	cntrs->ExcessBufferOvflCnt = dd->ipath_overrun_thresh_errs;
++	cntrs->LocalLinkIntegrityErrCnt = dd->ipath_lli_errs;
++	cntrs->RxVlErrCnt = 0;
++	cntrs->RxDlidFltrCnt = 0;
++}
 +
-+struct class cm_class = {
-+	.name    = "infiniband_cm",
-+};
-+EXPORT_SYMBOL(cm_class);
 +
-+static void cm_remove_fs_obj(struct kobject *obj)
++/* no interrupt fallback for these chips */
++static int ipath_pe_nointr_fallback(struct ipath_devdata *dd)
 +{
-+	kobject_put(obj->parent);
-+	kobject_put(obj);
++	return 0;
 +}
 +
-+static int cm_create_port_fs(struct cm_port *port)
-+{
-+	int i, ret;
 +
-+	ret = kobject_init_and_add(&port->port_obj, &cm_port_obj_type,
-+				   kobject_get(&port->cm_dev->dev_obj),
-+				   "%d", port->port_num);
-+	if (ret) {
-+		kfree(port);
-+		return ret;
-+	}
+ /*
+- * On platforms using this chip, and not having ordered WC stores, we
+- * can get TXE parity errors due to speculative reads to the PIO buffers,
+- * and this, due to a chip bug can result in (many) false parity error
+- * reports.  So it's a debug print on those, and an info print on systems
+- * where the speculative reads don't occur.
+- * Because we can get lots of false errors, we have no upper limit
+- * on recovery attempts on those platforms.
++ * reset the XGXS (between serdes and IBC).  Slightly less intrusive
++ * than resetting the IBC or external link state, and useful in some
++ * cases to cause some retraining.  To do this right, we reset IBC
++ * as well.
+  */
+-static int ipath_pe_txe_recover(struct ipath_devdata *dd)
++static void ipath_pe_xgxs_reset(struct ipath_devdata *dd)
+ {
+-	if (ipath_unordered_wc())
+-		ipath_dbg("Recovering from TXE PIO parity error\n");
+-	else {
+-		int cnt = ++ipath_stats.sps_txeparity;
+-		if (cnt >= IPATH_MAX_PARITY_ATTEMPTS)  {
+-			if (cnt == IPATH_MAX_PARITY_ATTEMPTS)
+-				ipath_dev_err(dd,
+-					"Too many attempts to recover from "
+-					"TXE parity, giving up\n");
+-			return 0;
+-		}
+-		dev_info(&dd->pcidev->dev,
+-			"Recovering from TXE PIO parity error\n");
++	u64 val, prev_val;
 +
-+	for (i = 0; i < CM_COUNTER_GROUPS; i++) {
-+		ret = kobject_init_and_add(&port->counter_group[i].obj,
-+					   &cm_counter_obj_type,
-+					   kobject_get(&port->port_obj),
-+					   "%s", counter_group_names[i]);
-+		if (ret)
-+			goto error;
-+	}
++	prev_val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_xgxsconfig);
++	val = prev_val | INFINIPATH_XGXS_RESET;
++	prev_val &= ~INFINIPATH_XGXS_RESET; /* be sure */
++	ipath_write_kreg(dd, dd->ipath_kregs->kr_control,
++			 dd->ipath_control & ~INFINIPATH_C_LINKENABLE);
++	ipath_write_kreg(dd, dd->ipath_kregs->kr_xgxsconfig, val);
++	ipath_read_kreg32(dd, dd->ipath_kregs->kr_scratch);
++	ipath_write_kreg(dd, dd->ipath_kregs->kr_xgxsconfig, prev_val);
++	ipath_write_kreg(dd, dd->ipath_kregs->kr_control,
++			 dd->ipath_control);
++}
 +
-+	return 0;
 +
-+error:
-+	while (i--)
-+		cm_remove_fs_obj(&port->counter_group[i].obj);
-+	cm_remove_fs_obj(&port->port_obj);
-+	return ret;
++static int ipath_pe_get_ib_cfg(struct ipath_devdata *dd, int which)
++{
++	int ret;
 +
++	switch (which) {
++	case IPATH_IB_CFG_LWID:
++		ret = dd->ipath_link_width_active;
++		break;
++	case IPATH_IB_CFG_SPD:
++		ret = dd->ipath_link_speed_active;
++		break;
++	case IPATH_IB_CFG_LWID_ENB:
++		ret = dd->ipath_link_width_enabled;
++		break;
++	case IPATH_IB_CFG_SPD_ENB:
++		ret = dd->ipath_link_speed_enabled;
++		break;
++	default:
++		ret =  -ENOTSUPP;
++		break;
+ 	}
+-	return 1;
++	return ret;
 +}
 +
-+static void cm_remove_port_fs(struct cm_port *port)
-+{
-+	int i;
-+
-+	for (i = 0; i < CM_COUNTER_GROUPS; i++)
-+		cm_remove_fs_obj(&port->counter_group[i].obj);
 +
-+	cm_remove_fs_obj(&port->port_obj);
-+}
++/* we assume range checking is already done, if needed */
++static int ipath_pe_set_ib_cfg(struct ipath_devdata *dd, int which, u32 val)
++{
++	int ret = 0;
 +
- static void cm_add_one(struct ib_device *device)
- {
- 	struct cm_device *cm_dev;
-@@ -3397,7 +3638,7 @@ static void cm_add_one(struct ib_device *device)
- 	if (rdma_node_get_transport(device->node_type) != RDMA_TRANSPORT_IB)
- 		return;
- 
--	cm_dev = kmalloc(sizeof(*cm_dev) + sizeof(*port) *
-+	cm_dev = kzalloc(sizeof(*cm_dev) + sizeof(*port) *
- 			 device->phys_port_cnt, GFP_KERNEL);
- 	if (!cm_dev)
- 		return;
-@@ -3405,11 +3646,27 @@ static void cm_add_one(struct ib_device *device)
- 	cm_dev->device = device;
- 	cm_get_ack_delay(cm_dev);
++	if (which == IPATH_IB_CFG_LWID_ENB)
++		dd->ipath_link_width_enabled = val;
++	else if (which == IPATH_IB_CFG_SPD_ENB)
++		dd->ipath_link_speed_enabled = val;
++	else
++		ret = -ENOTSUPP;
++	return ret;
+ }
  
-+	ret = kobject_init_and_add(&cm_dev->dev_obj, &cm_dev_obj_type,
-+				   &cm_class.subsys.kobj, "%s", device->name);
-+	if (ret) {
-+		kfree(cm_dev);
-+		return;
-+	}
++static void ipath_pe_config_jint(struct ipath_devdata *dd, u16 a, u16 b)
++{
++}
 +
- 	set_bit(IB_MGMT_METHOD_SEND, reg_req.method_mask);
- 	for (i = 1; i <= device->phys_port_cnt; i++) {
--		port = &cm_dev->port[i-1];
-+		port = kzalloc(sizeof *port, GFP_KERNEL);
-+		if (!port)
-+			goto error1;
 +
-+		cm_dev->port[i-1] = port;
- 		port->cm_dev = cm_dev;
- 		port->port_num = i;
++static int ipath_pe_ib_updown(struct ipath_devdata *dd, int ibup, u64 ibcs)
++{
++	ipath_setup_pe_setextled(dd, ipath_ib_linkstate(dd, ibcs),
++		ipath_ib_linktrstate(dd, ibcs));
++	return 0;
++}
 +
-+		ret = cm_create_port_fs(port);
-+		if (ret)
-+			goto error1;
 +
- 		port->mad_agent = ib_register_mad_agent(device, i,
- 							IB_QPT_GSI,
- 							&reg_req,
-@@ -3418,11 +3675,11 @@ static void cm_add_one(struct ib_device *device)
- 							cm_recv_handler,
- 							port);
- 		if (IS_ERR(port->mad_agent))
--			goto error1;
-+			goto error2;
- 
- 		ret = ib_modify_port(device, i, 0, &port_modify);
- 		if (ret)
--			goto error2;
-+			goto error3;
- 	}
- 	ib_set_client_data(device, &cm_client, cm_dev);
+ /**
+  * ipath_init_iba6120_funcs - set up the chip-specific function pointers
+  * @dd: the infinipath device
+@@ -1407,7 +1666,7 @@ void ipath_init_iba6120_funcs(struct ipath_devdata *dd)
+ 	dd->ipath_f_bringup_serdes = ipath_pe_bringup_serdes;
+ 	dd->ipath_f_clear_tids = ipath_pe_clear_tids;
+ 	/*
+-	 * this may get changed after we read the chip revision,
++	 * _f_put_tid may get changed after we read the chip revision,
+ 	 * but we start with the safe version for all revs
+ 	 */
+ 	dd->ipath_f_put_tid = ipath_pe_put_tid;
+@@ -1415,17 +1674,19 @@ void ipath_init_iba6120_funcs(struct ipath_devdata *dd)
+ 	dd->ipath_f_setextled = ipath_setup_pe_setextled;
+ 	dd->ipath_f_get_base_info = ipath_pe_get_base_info;
+ 	dd->ipath_f_free_irq = ipath_pe_free_irq;
+-
+-	/* initialize chip-specific variables */
+ 	dd->ipath_f_tidtemplate = ipath_pe_tidtemplate;
++	dd->ipath_f_intr_fallback = ipath_pe_nointr_fallback;
++	dd->ipath_f_xgxs_reset = ipath_pe_xgxs_reset;
++	dd->ipath_f_get_msgheader = ipath_pe_get_msgheader;
++	dd->ipath_f_config_ports = ipath_pe_config_ports;
++	dd->ipath_f_read_counters = ipath_pe_read_counters;
++	dd->ipath_f_get_ib_cfg = ipath_pe_get_ib_cfg;
++	dd->ipath_f_set_ib_cfg = ipath_pe_set_ib_cfg;
++	dd->ipath_f_config_jint = ipath_pe_config_jint;
++	dd->ipath_f_ib_updown = ipath_pe_ib_updown;
  
-@@ -3431,17 +3688,20 @@ static void cm_add_one(struct ib_device *device)
- 	write_unlock_irqrestore(&cm.device_lock, flags);
- 	return;
+-	/*
+-	 * setup the register offsets, since they are different for each
+-	 * chip
+-	 */
+-	dd->ipath_kregs = &ipath_pe_kregs;
+-	dd->ipath_cregs = &ipath_pe_cregs;
  
--error2:
-+error3:
- 	ib_unregister_mad_agent(port->mad_agent);
-+error2:
-+	cm_remove_port_fs(port);
- error1:
- 	port_modify.set_port_cap_mask = 0;
- 	port_modify.clr_port_cap_mask = IB_PORT_CM_SUP;
- 	while (--i) {
--		port = &cm_dev->port[i-1];
-+		port = cm_dev->port[i-1];
- 		ib_modify_port(device, port->port_num, 0, &port_modify);
- 		ib_unregister_mad_agent(port->mad_agent);
-+		cm_remove_port_fs(port);
- 	}
--	kfree(cm_dev);
-+	cm_remove_fs_obj(&cm_dev->dev_obj);
++	/* initialize chip-specific variables */
+ 	ipath_init_pe_variables(dd);
  }
  
- static void cm_remove_one(struct ib_device *device)
-@@ -3463,11 +3723,12 @@ static void cm_remove_one(struct ib_device *device)
- 	write_unlock_irqrestore(&cm.device_lock, flags);
+diff --git a/drivers/infiniband/hw/ipath/ipath_init_chip.c b/drivers/infiniband/hw/ipath/ipath_init_chip.c
+index 9dd0bac..4471674 100644
+--- a/drivers/infiniband/hw/ipath/ipath_init_chip.c
++++ b/drivers/infiniband/hw/ipath/ipath_init_chip.c
+@@ -91,7 +91,7 @@ static int create_port0_egr(struct ipath_devdata *dd)
+ 	struct ipath_skbinfo *skbinfo;
+ 	int ret;
  
- 	for (i = 1; i <= device->phys_port_cnt; i++) {
--		port = &cm_dev->port[i-1];
-+		port = cm_dev->port[i-1];
- 		ib_modify_port(device, port->port_num, 0, &port_modify);
- 		ib_unregister_mad_agent(port->mad_agent);
-+		cm_remove_port_fs(port);
- 	}
--	kfree(cm_dev);
-+	cm_remove_fs_obj(&cm_dev->dev_obj);
- }
+-	egrcnt = dd->ipath_rcvegrcnt;
++	egrcnt = dd->ipath_p0_rcvegrcnt;
  
- static int __init ib_cm_init(void)
-@@ -3488,17 +3749,25 @@ static int __init ib_cm_init(void)
- 	idr_pre_get(&cm.local_id_table, GFP_KERNEL);
- 	INIT_LIST_HEAD(&cm.timewait_list);
+ 	skbinfo = vmalloc(sizeof(*dd->ipath_port0_skbinfo) * egrcnt);
+ 	if (skbinfo == NULL) {
+@@ -244,8 +244,7 @@ static int init_chip_first(struct ipath_devdata *dd,
+ 	 * cfgports.  We do still check and report a difference, if
+ 	 * not same (should be impossible).
+ 	 */
+-	dd->ipath_portcnt =
+-		ipath_read_kreg32(dd, dd->ipath_kregs->kr_portcnt);
++	dd->ipath_f_config_ports(dd, ipath_cfgports);
+ 	if (!ipath_cfgports)
+ 		dd->ipath_cfgports = dd->ipath_portcnt;
+ 	else if (ipath_cfgports <= dd->ipath_portcnt) {
+@@ -272,22 +271,7 @@ static int init_chip_first(struct ipath_devdata *dd,
+ 		goto done;
+ 	}
  
--	cm.wq = create_workqueue("ib_cm");
--	if (!cm.wq)
-+	ret = class_register(&cm_class);
-+	if (ret)
- 		return -ENOMEM;
+-	dd->ipath_lastegrheads = kzalloc(sizeof(*dd->ipath_lastegrheads)
+-					 * dd->ipath_cfgports,
+-					 GFP_KERNEL);
+-	dd->ipath_lastrcvhdrqtails =
+-		kzalloc(sizeof(*dd->ipath_lastrcvhdrqtails)
+-			* dd->ipath_cfgports, GFP_KERNEL);
+-
+-	if (!dd->ipath_lastegrheads || !dd->ipath_lastrcvhdrqtails) {
+-		ipath_dev_err(dd, "Unable to allocate head arrays, "
+-			      "failing\n");
+-		ret = -ENOMEM;
+-		goto done;
+-	}
+-
+ 	pd = create_portdata0(dd);
+-
+ 	if (!pd) {
+ 		ipath_dev_err(dd, "Unable to allocate portdata for port "
+ 			      "0, failing\n");
+@@ -345,10 +329,10 @@ static int init_chip_first(struct ipath_devdata *dd,
+ 		       dd->ipath_piobcnt2k, dd->ipath_pio2kbase);
  
-+	cm.wq = create_workqueue("ib_cm");
-+	if (!cm.wq) {
-+		ret = -ENOMEM;
-+		goto error1;
-+	}
-+
- 	ret = ib_register_client(&cm_client);
- 	if (ret)
--		goto error;
-+		goto error2;
+ 	spin_lock_init(&dd->ipath_tid_lock);
+-
++	spin_lock_init(&dd->ipath_sendctrl_lock);
+ 	spin_lock_init(&dd->ipath_gpio_lock);
+ 	spin_lock_init(&dd->ipath_eep_st_lock);
+-	sema_init(&dd->ipath_eep_sem, 1);
++	mutex_init(&dd->ipath_eep_lock);
  
- 	return 0;
--error:
-+error2:
- 	destroy_workqueue(cm.wq);
-+error1:
-+	class_unregister(&cm_class);
- 	return ret;
- }
+ done:
+ 	*pdp = pd;
+@@ -372,9 +356,9 @@ static int init_chip_reset(struct ipath_devdata *dd,
+ 	*pdp = dd->ipath_pd[0];
+ 	/* ensure chip does no sends or receives while we re-initialize */
+ 	dd->ipath_control = dd->ipath_sendctrl = dd->ipath_rcvctrl = 0U;
+-	ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl, 0);
+-	ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, 0);
+-	ipath_write_kreg(dd, dd->ipath_kregs->kr_control, 0);
++	ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl, dd->ipath_rcvctrl);
++	ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, dd->ipath_sendctrl);
++	ipath_write_kreg(dd, dd->ipath_kregs->kr_control, dd->ipath_control);
  
-@@ -3519,6 +3788,7 @@ static void __exit ib_cm_cleanup(void)
- 	}
+ 	rtmp = ipath_read_kreg32(dd, dd->ipath_kregs->kr_portcnt);
+ 	if (dd->ipath_portcnt != rtmp)
+@@ -487,6 +471,7 @@ static void enable_chip(struct ipath_devdata *dd,
+ 			struct ipath_portdata *pd, int reinit)
+ {
+ 	u32 val;
++	unsigned long flags;
+ 	int i;
  
- 	ib_unregister_client(&cm_client);
-+	class_unregister(&cm_class);
- 	idr_destroy(&cm.local_id_table);
- }
+ 	if (!reinit)
+@@ -495,19 +480,21 @@ static void enable_chip(struct ipath_devdata *dd,
+ 	ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl,
+ 			 dd->ipath_rcvctrl);
  
-diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c
-index 0751697..637efea 100644
---- a/drivers/infiniband/core/cma.c
-+++ b/drivers/infiniband/core/cma.c
-@@ -488,7 +488,8 @@ void rdma_destroy_qp(struct rdma_cm_id *id)
- }
- EXPORT_SYMBOL(rdma_destroy_qp);
++	spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags);
+ 	/* Enable PIO send, and update of PIOavail regs to memory. */
+ 	dd->ipath_sendctrl = INFINIPATH_S_PIOENABLE |
+ 		INFINIPATH_S_PIOBUFAVAILUPD;
+-	ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
+-			 dd->ipath_sendctrl);
++	ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, dd->ipath_sendctrl);
++	ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
++	spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags);
  
--static int cma_modify_qp_rtr(struct rdma_id_private *id_priv)
-+static int cma_modify_qp_rtr(struct rdma_id_private *id_priv,
-+			     struct rdma_conn_param *conn_param)
- {
- 	struct ib_qp_attr qp_attr;
- 	int qp_attr_mask, ret;
-@@ -514,13 +515,16 @@ static int cma_modify_qp_rtr(struct rdma_id_private *id_priv)
- 	if (ret)
- 		goto out;
+ 	/*
+ 	 * enable port 0 receive, and receive interrupt.  other ports
+ 	 * done as user opens and inits them.
+ 	 */
+-	dd->ipath_rcvctrl = INFINIPATH_R_TAILUPD |
+-		(1ULL << INFINIPATH_R_PORTENABLE_SHIFT) |
+-		(1ULL << INFINIPATH_R_INTRAVAIL_SHIFT);
++	dd->ipath_rcvctrl = (1ULL << dd->ipath_r_tailupd_shift) |
++		(1ULL << dd->ipath_r_portenable_shift) |
++		(1ULL << dd->ipath_r_intravail_shift);
+ 	ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl,
+ 			 dd->ipath_rcvctrl);
  
-+	if (conn_param)
-+		qp_attr.max_dest_rd_atomic = conn_param->responder_resources;
- 	ret = ib_modify_qp(id_priv->id.qp, &qp_attr, qp_attr_mask);
- out:
- 	mutex_unlock(&id_priv->qp_mutex);
- 	return ret;
- }
+@@ -523,12 +510,11 @@ static void enable_chip(struct ipath_devdata *dd,
+ 	 */
+ 	val = ipath_read_ureg32(dd, ur_rcvegrindextail, 0);
+ 	(void)ipath_write_ureg(dd, ur_rcvegrindexhead, val, 0);
+-	dd->ipath_port0head = ipath_read_ureg32(dd, ur_rcvhdrtail, 0);
  
--static int cma_modify_qp_rts(struct rdma_id_private *id_priv)
-+static int cma_modify_qp_rts(struct rdma_id_private *id_priv,
-+			     struct rdma_conn_param *conn_param)
- {
- 	struct ib_qp_attr qp_attr;
- 	int qp_attr_mask, ret;
-@@ -536,6 +540,8 @@ static int cma_modify_qp_rts(struct rdma_id_private *id_priv)
- 	if (ret)
- 		goto out;
+ 	/* Initialize so we interrupt on next packet received */
+ 	(void)ipath_write_ureg(dd, ur_rcvhdrhead,
+ 			       dd->ipath_rhdrhead_intr_off |
+-			       dd->ipath_port0head, 0);
++			       dd->ipath_pd[0]->port_head, 0);
  
-+	if (conn_param)
-+		qp_attr.max_rd_atomic = conn_param->initiator_depth;
- 	ret = ib_modify_qp(id_priv->id.qp, &qp_attr, qp_attr_mask);
- out:
- 	mutex_unlock(&id_priv->qp_mutex);
-@@ -866,11 +872,11 @@ static int cma_rep_recv(struct rdma_id_private *id_priv)
+ 	/*
+ 	 * by now pioavail updates to memory should have occurred, so
+@@ -542,12 +528,8 @@ static void enable_chip(struct ipath_devdata *dd,
+ 		/*
+ 		 * Chip Errata bug 6641; even and odd qwords>3 are swapped.
+ 		 */
+-		if (i > 3) {
+-			if (i & 1)
+-				val = dd->ipath_pioavailregs_dma[i - 1];
+-			else
+-				val = dd->ipath_pioavailregs_dma[i + 1];
+-		}
++		if (i > 3 && (dd->ipath_flags & IPATH_SWAP_PIOBUFS))
++			val = dd->ipath_pioavailregs_dma[i ^ 1];
+ 		else
+ 			val = dd->ipath_pioavailregs_dma[i];
+ 		dd->ipath_pioavailshadow[i] = le64_to_cpu(val);
+@@ -690,12 +672,13 @@ done:
+  */
+ int ipath_init_chip(struct ipath_devdata *dd, int reinit)
  {
- 	int ret;
+-	int ret = 0, i;
++	int ret = 0;
+ 	u32 val32, kpiobufs;
+ 	u32 piobufs, uports;
+ 	u64 val;
+ 	struct ipath_portdata *pd = NULL; /* keep gcc4 happy */
+ 	gfp_t gfp_flags = GFP_USER | __GFP_COMP;
++	unsigned long flags;
  
--	ret = cma_modify_qp_rtr(id_priv);
-+	ret = cma_modify_qp_rtr(id_priv, NULL);
+ 	ret = init_housekeeping(dd, &pd, reinit);
  	if (ret)
- 		goto reject;
+@@ -746,7 +729,7 @@ int ipath_init_chip(struct ipath_devdata *dd, int reinit)
+ 		kpiobufs = ipath_kpiobufs;
  
--	ret = cma_modify_qp_rts(id_priv);
-+	ret = cma_modify_qp_rts(id_priv, NULL);
- 	if (ret)
- 		goto reject;
+ 	if (kpiobufs + (uports * IPATH_MIN_USER_PORT_BUFCNT) > piobufs) {
+-		i = (int) piobufs -
++		int i = (int) piobufs -
+ 			(int) (uports * IPATH_MIN_USER_PORT_BUFCNT);
+ 		if (i < 0)
+ 			i = 0;
+@@ -827,8 +810,12 @@ int ipath_init_chip(struct ipath_devdata *dd, int reinit)
+ 	ipath_write_kreg(dd, dd->ipath_kregs->kr_hwerrclear,
+ 			 ~0ULL&~INFINIPATH_HWE_MEMBISTFAILED);
+ 	ipath_write_kreg(dd, dd->ipath_kregs->kr_control, 0ULL);
+-	ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
+-			 INFINIPATH_S_PIOENABLE);
++
++	spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags);
++	dd->ipath_sendctrl = INFINIPATH_S_PIOENABLE;
++	ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, dd->ipath_sendctrl);
++	ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
++	spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags);
  
-@@ -1122,8 +1128,10 @@ static int cma_req_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event)
- 	cm_id->cm_handler = cma_ib_handler;
+ 	/*
+ 	 * before error clears, since we expect serdes pll errors during
+diff --git a/drivers/infiniband/hw/ipath/ipath_intr.c b/drivers/infiniband/hw/ipath/ipath_intr.c
+index c61f9da..92e58c9 100644
+--- a/drivers/infiniband/hw/ipath/ipath_intr.c
++++ b/drivers/infiniband/hw/ipath/ipath_intr.c
+@@ -683,7 +683,7 @@ static int handle_errors(struct ipath_devdata *dd, ipath_err_t errs)
+ 		for (i = 0; i < dd->ipath_cfgports; i++) {
+ 			struct ipath_portdata *pd = dd->ipath_pd[i];
+ 			if (i == 0) {
+-				hd = dd->ipath_port0head;
++				hd = pd->port_head;
+ 				tl = (u32) le64_to_cpu(
+ 					*dd->ipath_hdrqtailptr);
+ 			} else if (pd && pd->port_cnt &&
+@@ -693,7 +693,7 @@ static int handle_errors(struct ipath_devdata *dd, ipath_err_t errs)
+ 				 * except kernel
+ 				 */
+ 				tl = *(u64 *) pd->port_rcvhdrtail_kvaddr;
+-				if (tl == dd->ipath_lastrcvhdrqtails[i])
++				if (tl == pd->port_lastrcvhdrqtail)
+ 					continue;
+ 				hd = ipath_read_ureg32(dd, ur_rcvhdrhead,
+ 						       i);
+@@ -703,7 +703,7 @@ static int handle_errors(struct ipath_devdata *dd, ipath_err_t errs)
+ 			    (!hd && tl == dd->ipath_hdrqlast)) {
+ 				if (i == 0)
+ 					chkerrpkts = 1;
+-				dd->ipath_lastrcvhdrqtails[i] = tl;
++				pd->port_lastrcvhdrqtail = tl;
+ 				pd->port_hdrqfull++;
+ 				/* flush hdrqfull so that poll() sees it */
+ 				wmb();
+@@ -712,6 +712,8 @@ static int handle_errors(struct ipath_devdata *dd, ipath_err_t errs)
+ 		}
+ 	}
+ 	if (errs & INFINIPATH_E_RRCVEGRFULL) {
++		struct ipath_portdata *pd = dd->ipath_pd[0];
++
+ 		/*
+ 		 * since this is of less importance and not likely to
+ 		 * happen without also getting hdrfull, only count
+@@ -719,7 +721,7 @@ static int handle_errors(struct ipath_devdata *dd, ipath_err_t errs)
+ 		 * vs user)
+ 		 */
+ 		ipath_stats.sps_etidfull++;
+-		if (dd->ipath_port0head !=
++		if (pd->port_head !=
+ 		    (u32) le64_to_cpu(*dd->ipath_hdrqtailptr))
+ 			chkerrpkts = 1;
+ 	}
+@@ -795,6 +797,7 @@ void ipath_clear_freeze(struct ipath_devdata *dd)
+ {
+ 	int i, im;
+ 	__le64 val;
++	unsigned long flags;
  
- 	ret = conn_id->id.event_handler(&conn_id->id, &event);
--	if (!ret)
-+	if (!ret) {
-+		cma_enable_remove(conn_id);
- 		goto out;
-+	}
+ 	/* disable error interrupts, to avoid confusion */
+ 	ipath_write_kreg(dd, dd->ipath_kregs->kr_errormask, 0ULL);
+@@ -813,11 +816,14 @@ void ipath_clear_freeze(struct ipath_devdata *dd)
+ 			 dd->ipath_control);
  
- 	/* Destroy the CM ID by returning a non-zero value. */
- 	conn_id->cm_id.ib = NULL;
-@@ -1262,6 +1270,7 @@ static int iw_conn_req_handler(struct iw_cm_id *cm_id,
- 	struct net_device *dev = NULL;
- 	struct rdma_cm_event event;
- 	int ret;
-+	struct ib_device_attr attr;
+ 	/* ensure pio avail updates continue */
++	spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags);
+ 	ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
+ 		 dd->ipath_sendctrl & ~INFINIPATH_S_PIOBUFAVAILUPD);
+ 	ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
+ 	ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
+-		 dd->ipath_sendctrl);
++			 dd->ipath_sendctrl);
++	ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
++	spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags);
  
- 	listen_id = cm_id->context;
- 	if (cma_disable_remove(listen_id, CMA_LISTEN))
-@@ -1311,10 +1320,19 @@ static int iw_conn_req_handler(struct iw_cm_id *cm_id,
- 	sin = (struct sockaddr_in *) &new_cm_id->route.addr.dst_addr;
- 	*sin = iw_event->remote_addr;
+ 	/*
+ 	 * We just enabled pioavailupdate, so dma copy is almost certainly
+@@ -825,8 +831,8 @@ void ipath_clear_freeze(struct ipath_devdata *dd)
+ 	 */
+ 	for (i = 0; i < dd->ipath_pioavregs; i++) {
+ 		/* deal with 6110 chip bug */
+-		im = i > 3 ? ((i&1) ? i-1 : i+1) : i;
+-		val = ipath_read_kreg64(dd, (0x1000/sizeof(u64))+im);
++		im = i > 3 ? i ^ 1 : i;
++		val = ipath_read_kreg64(dd, (0x1000 / sizeof(u64)) + im);
+ 		dd->ipath_pioavailregs_dma[i] = dd->ipath_pioavailshadow[i]
+ 			= le64_to_cpu(val);
+ 	}
+@@ -849,7 +855,7 @@ void ipath_clear_freeze(struct ipath_devdata *dd)
  
-+	ret = ib_query_device(conn_id->id.device, &attr);
-+	if (ret) {
-+		cma_enable_remove(conn_id);
-+		rdma_destroy_id(new_cm_id);
-+		goto out;
-+	}
-+
- 	memset(&event, 0, sizeof event);
- 	event.event = RDMA_CM_EVENT_CONNECT_REQUEST;
- 	event.param.conn.private_data = iw_event->private_data;
- 	event.param.conn.private_data_len = iw_event->private_data_len;
-+	event.param.conn.initiator_depth = attr.max_qp_init_rd_atom;
-+	event.param.conn.responder_resources = attr.max_qp_rd_atom;
- 	ret = conn_id->id.event_handler(&conn_id->id, &event);
- 	if (ret) {
- 		/* User wants to destroy the CM ID */
-@@ -2272,7 +2290,7 @@ static int cma_connect_iw(struct rdma_id_private *id_priv,
- 	sin = (struct sockaddr_in*) &id_priv->id.route.addr.dst_addr;
- 	cm_id->remote_addr = *sin;
+ /* this is separate to allow for better optimization of ipath_intr() */
  
--	ret = cma_modify_qp_rtr(id_priv);
-+	ret = cma_modify_qp_rtr(id_priv, conn_param);
- 	if (ret)
- 		goto out;
+-static void ipath_bad_intr(struct ipath_devdata *dd, u32 * unexpectp)
++static noinline void ipath_bad_intr(struct ipath_devdata *dd, u32 *unexpectp)
+ {
+ 	/*
+ 	 * sometimes happen during driver init and unload, don't want
+@@ -877,7 +883,7 @@ static void ipath_bad_intr(struct ipath_devdata *dd, u32 * unexpectp)
+ 				dd->ipath_f_free_irq(dd);
+ 			}
+ 		}
+-		if (ipath_read_kreg32(dd, dd->ipath_kregs->kr_intmask)) {
++		if (ipath_read_ireg(dd, dd->ipath_kregs->kr_intmask)) {
+ 			ipath_dev_err(dd, "%u unexpected interrupts, "
+ 				      "disabling interrupts completely\n",
+ 				      *unexpectp);
+@@ -892,7 +898,7 @@ static void ipath_bad_intr(struct ipath_devdata *dd, u32 * unexpectp)
+ 			  "ignoring\n");
+ }
  
-@@ -2335,25 +2353,15 @@ static int cma_accept_ib(struct rdma_id_private *id_priv,
- 			 struct rdma_conn_param *conn_param)
+-static void ipath_bad_regread(struct ipath_devdata *dd)
++static noinline void ipath_bad_regread(struct ipath_devdata *dd)
  {
- 	struct ib_cm_rep_param rep;
--	struct ib_qp_attr qp_attr;
--	int qp_attr_mask, ret;
--
--	if (id_priv->id.qp) {
--		ret = cma_modify_qp_rtr(id_priv);
--		if (ret)
--			goto out;
-+	int ret;
+ 	static int allbits;
  
--		qp_attr.qp_state = IB_QPS_RTS;
--		ret = ib_cm_init_qp_attr(id_priv->cm_id.ib, &qp_attr,
--					 &qp_attr_mask);
--		if (ret)
--			goto out;
-+	ret = cma_modify_qp_rtr(id_priv, conn_param);
-+	if (ret)
-+		goto out;
+@@ -920,31 +926,9 @@ static void ipath_bad_regread(struct ipath_devdata *dd)
+ 	}
+ }
  
--		qp_attr.max_rd_atomic = conn_param->initiator_depth;
--		ret = ib_modify_qp(id_priv->id.qp, &qp_attr, qp_attr_mask);
--		if (ret)
--			goto out;
+-static void handle_port_pioavail(struct ipath_devdata *dd)
+-{
+-	u32 i;
+-	/*
+-	 * start from port 1, since for now port 0  is never using
+-	 * wait_event for PIO
+-	 */
+-	for (i = 1; dd->ipath_portpiowait && i < dd->ipath_cfgports; i++) {
+-		struct ipath_portdata *pd = dd->ipath_pd[i];
+-
+-		if (pd && pd->port_cnt &&
+-		    dd->ipath_portpiowait & (1U << i)) {
+-			clear_bit(i, &dd->ipath_portpiowait);
+-			if (test_bit(IPATH_PORT_WAITING_PIO,
+-				     &pd->port_flag)) {
+-				clear_bit(IPATH_PORT_WAITING_PIO,
+-					  &pd->port_flag);
+-				wake_up_interruptible(&pd->port_wait);
+-			}
+-		}
 -	}
-+	ret = cma_modify_qp_rts(id_priv, conn_param);
-+	if (ret)
-+		goto out;
- 
- 	memset(&rep, 0, sizeof rep);
- 	rep.qp_num = id_priv->qp_num;
-@@ -2378,7 +2386,7 @@ static int cma_accept_iw(struct rdma_id_private *id_priv,
- 	struct iw_cm_conn_param iw_param;
+-}
+-
+ static void handle_layer_pioavail(struct ipath_devdata *dd)
+ {
++	unsigned long flags;
  	int ret;
  
--	ret = cma_modify_qp_rtr(id_priv);
-+	ret = cma_modify_qp_rtr(id_priv, conn_param);
- 	if (ret)
- 		return ret;
+ 	ret = ipath_ib_piobufavail(dd->verbs_dev);
+@@ -953,9 +937,12 @@ static void handle_layer_pioavail(struct ipath_devdata *dd)
  
-@@ -2598,11 +2606,9 @@ static void cma_set_mgid(struct rdma_id_private *id_priv,
- 		/* IPv6 address is an SA assigned MGID. */
- 		memcpy(mgid, &sin6->sin6_addr, sizeof *mgid);
- 	} else {
--		ip_ib_mc_map(sin->sin_addr.s_addr, mc_map);
-+		ip_ib_mc_map(sin->sin_addr.s_addr, dev_addr->broadcast, mc_map);
- 		if (id_priv->id.ps == RDMA_PS_UDP)
- 			mc_map[7] = 0x01;	/* Use RDMA CM signature */
--		mc_map[8] = ib_addr_get_pkey(dev_addr) >> 8;
--		mc_map[9] = (unsigned char) ib_addr_get_pkey(dev_addr);
- 		*mgid = *(union ib_gid *) (mc_map + 4);
- 	}
+ 	return;
+ set:
+-	set_bit(IPATH_S_PIOINTBUFAVAIL, &dd->ipath_sendctrl);
++	spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags);
++	dd->ipath_sendctrl |= INFINIPATH_S_PIOINTBUFAVAIL;
+ 	ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
+ 			 dd->ipath_sendctrl);
++	ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
++	spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags);
  }
-diff --git a/drivers/infiniband/core/fmr_pool.c b/drivers/infiniband/core/fmr_pool.c
-index e8d5f6b..6c7aa59 100644
---- a/drivers/infiniband/core/fmr_pool.c
-+++ b/drivers/infiniband/core/fmr_pool.c
-@@ -139,7 +139,7 @@ static inline struct ib_pool_fmr *ib_fmr_cache_lookup(struct ib_fmr_pool *pool,
- static void ib_fmr_batch_release(struct ib_fmr_pool *pool)
- {
- 	int                 ret;
--	struct ib_pool_fmr *fmr;
-+	struct ib_pool_fmr *fmr, *next;
- 	LIST_HEAD(unmap_list);
- 	LIST_HEAD(fmr_list);
  
-@@ -158,6 +158,20 @@ static void ib_fmr_batch_release(struct ib_fmr_pool *pool)
- #endif
- 	}
+ /*
+@@ -969,7 +956,15 @@ static void handle_urcv(struct ipath_devdata *dd, u32 istat)
+ 	int i;
+ 	int rcvdint = 0;
  
+-	/* test_bit below needs this... */
 +	/*
-+	 * The free_list may hold FMRs that have been put there
-+	 * because they haven't reached the max_remap count.
-+	 * Invalidate their mapping as well.
++	 * test_and_clear_bit(IPATH_PORT_WAITING_RCV) and
++	 * test_and_clear_bit(IPATH_PORT_WAITING_URG) below
++	 * would both like timely updates of the bits so that
++	 * we don't pass them by unnecessarily.  the rmb()
++	 * here ensures that we see them promptly -- the
++	 * corresponding wmb()'s are in ipath_poll_urgent()
++	 * and ipath_poll_next()...
 +	 */
-+	list_for_each_entry_safe(fmr, next, &pool->free_list, list) {
-+		if (fmr->remap_count == 0)
-+			continue;
-+		hlist_del_init(&fmr->cache_node);
-+		fmr->remap_count = 0;
-+		list_add_tail(&fmr->fmr->list, &fmr_list);
-+		list_move(&fmr->list, &unmap_list);
-+	}
-+
- 	list_splice(&pool->dirty_list, &unmap_list);
- 	INIT_LIST_HEAD(&pool->dirty_list);
- 	pool->dirty_len = 0;
-@@ -182,8 +196,7 @@ static int ib_fmr_cleanup_thread(void *pool_ptr)
- 	struct ib_fmr_pool *pool = pool_ptr;
+ 	rmb();
+ 	portr = ((istat >> INFINIPATH_I_RCVAVAIL_SHIFT) &
+ 		 dd->ipath_i_rcvavail_mask)
+@@ -980,7 +975,7 @@ static void handle_urcv(struct ipath_devdata *dd, u32 istat)
+ 		if (portr & (1 << i) && pd && pd->port_cnt) {
+ 			if (test_and_clear_bit(IPATH_PORT_WAITING_RCV,
+ 					       &pd->port_flag)) {
+-				clear_bit(i + INFINIPATH_R_INTRAVAIL_SHIFT,
++				clear_bit(i + dd->ipath_r_intravail_shift,
+ 					  &dd->ipath_rcvctrl);
+ 				wake_up_interruptible(&pd->port_wait);
+ 				rcvdint = 1;
+@@ -1039,7 +1034,7 @@ irqreturn_t ipath_intr(int irq, void *data)
+ 		goto bail;
+ 	}
  
- 	do {
--		if (pool->dirty_len >= pool->dirty_watermark ||
--		    atomic_read(&pool->flush_ser) - atomic_read(&pool->req_ser) < 0) {
-+		if (atomic_read(&pool->flush_ser) - atomic_read(&pool->req_ser) < 0) {
- 			ib_fmr_batch_release(pool);
+-	istat = ipath_read_kreg32(dd, dd->ipath_kregs->kr_intstatus);
++	istat = ipath_read_ireg(dd, dd->ipath_kregs->kr_intstatus);
  
- 			atomic_inc(&pool->flush_ser);
-@@ -194,8 +207,7 @@ static int ib_fmr_cleanup_thread(void *pool_ptr)
- 		}
+ 	if (unlikely(!istat)) {
+ 		ipath_stats.sps_nullintr++;
+@@ -1180,7 +1175,7 @@ irqreturn_t ipath_intr(int irq, void *data)
+ 	 * for receive are at the bottom.
+ 	 */
+ 	if (chk0rcv) {
+-		ipath_kreceive(dd);
++		ipath_kreceive(dd->ipath_pd[0]);
+ 		istat &= ~port0rbits;
+ 	}
  
- 		set_current_state(TASK_INTERRUPTIBLE);
--		if (pool->dirty_len < pool->dirty_watermark &&
--		    atomic_read(&pool->flush_ser) - atomic_read(&pool->req_ser) >= 0 &&
-+		if (atomic_read(&pool->flush_ser) - atomic_read(&pool->req_ser) >= 0 &&
- 		    !kthread_should_stop())
- 			schedule();
- 		__set_current_state(TASK_RUNNING);
-@@ -369,11 +381,6 @@ void ib_destroy_fmr_pool(struct ib_fmr_pool *pool)
+@@ -1191,12 +1186,14 @@ irqreturn_t ipath_intr(int irq, void *data)
+ 		handle_urcv(dd, istat);
  
- 	i = 0;
- 	list_for_each_entry_safe(fmr, tmp, &pool->free_list, list) {
--		if (fmr->remap_count) {
--			INIT_LIST_HEAD(&fmr_list);
--			list_add_tail(&fmr->fmr->list, &fmr_list);
--			ib_unmap_fmr(&fmr_list);
--		}
- 		ib_dealloc_fmr(fmr->fmr);
- 		list_del(&fmr->list);
- 		kfree(fmr);
-@@ -511,8 +518,10 @@ int ib_fmr_pool_unmap(struct ib_pool_fmr *fmr)
- 			list_add_tail(&fmr->list, &pool->free_list);
- 		} else {
- 			list_add_tail(&fmr->list, &pool->dirty_list);
--			++pool->dirty_len;
--			wake_up_process(pool->thread);
-+			if (++pool->dirty_len >= pool->dirty_watermark) {
-+				atomic_inc(&pool->req_ser);
-+				wake_up_process(pool->thread);
-+			}
- 		}
- 	}
+ 	if (istat & INFINIPATH_I_SPIOBUFAVAIL) {
+-		clear_bit(IPATH_S_PIOINTBUFAVAIL, &dd->ipath_sendctrl);
++		unsigned long flags;
++
++		spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags);
++		dd->ipath_sendctrl &= ~INFINIPATH_S_PIOINTBUFAVAIL;
+ 		ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
+ 				 dd->ipath_sendctrl);
+-
+-		if (dd->ipath_portpiowait)
+-			handle_port_pioavail(dd);
++		ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
++		spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags);
  
-diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c
-index 6f42877..fbe16d5 100644
---- a/drivers/infiniband/core/mad.c
-+++ b/drivers/infiniband/core/mad.c
-@@ -701,7 +701,8 @@ static int handle_outgoing_dr_smp(struct ib_mad_agent_private *mad_agent_priv,
+ 		handle_layer_pioavail(dd);
  	}
+diff --git a/drivers/infiniband/hw/ipath/ipath_kernel.h b/drivers/infiniband/hw/ipath/ipath_kernel.h
+index 8786dd7..4cc0f95 100644
+--- a/drivers/infiniband/hw/ipath/ipath_kernel.h
++++ b/drivers/infiniband/hw/ipath/ipath_kernel.h
+@@ -41,6 +41,7 @@
+ #include <linux/interrupt.h>
+ #include <linux/pci.h>
+ #include <linux/dma-mapping.h>
++#include <linux/mutex.h>
+ #include <asm/io.h>
+ #include <rdma/ib_verbs.h>
  
- 	/* Check to post send on QP or process locally */
--	if (smi_check_local_smp(smp, device) == IB_SMI_DISCARD)
-+	if (smi_check_local_smp(smp, device) == IB_SMI_DISCARD &&
-+	    smi_check_local_returning_smp(smp, device) == IB_SMI_DISCARD)
- 		goto out;
+@@ -140,6 +141,11 @@ struct ipath_portdata {
+ 	u32 port_pionowait;
+ 	/* total number of rcvhdrqfull errors */
+ 	u32 port_hdrqfull;
++	/*
++	 * Used to suppress multiple instances of same
++	 * port staying stuck at same point.
++	 */
++	u32 port_lastrcvhdrqtail;
+ 	/* saved total number of rcvhdrqfull errors for poll edge trigger */
+ 	u32 port_hdrqfull_poll;
+ 	/* total number of polled urgent packets */
+@@ -148,6 +154,7 @@ struct ipath_portdata {
+ 	u32 port_urgent_poll;
+ 	/* pid of process using this port */
+ 	pid_t port_pid;
++	pid_t port_subpid[INFINIPATH_MAX_SUBPORT];
+ 	/* same size as task_struct .comm[] */
+ 	char port_comm[16];
+ 	/* pkeys set by this use of this port */
+@@ -166,6 +173,8 @@ struct ipath_portdata {
+ 	u32 active_slaves;
+ 	/* Type of packets or conditions we want to poll for */
+ 	u16 poll_type;
++	/* port rcvhdrq head offset */
++	u32 port_head;
+ };
  
- 	local = kmalloc(sizeof *local, GFP_ATOMIC);
-@@ -752,8 +753,7 @@ static int handle_outgoing_dr_smp(struct ib_mad_agent_private *mad_agent_priv,
- 		port_priv = ib_get_mad_port(mad_agent_priv->agent.device,
- 					    mad_agent_priv->agent.port_num);
- 		if (port_priv) {
--			mad_priv->mad.mad.mad_hdr.tid =
--				((struct ib_mad *)smp)->mad_hdr.tid;
-+			memcpy(&mad_priv->mad.mad, smp, sizeof(struct ib_mad));
- 			recv_mad_agent = find_mad_agent(port_priv,
- 						        &mad_priv->mad.mad);
- 		}
-@@ -1100,7 +1100,9 @@ int ib_post_send_mad(struct ib_mad_send_buf *send_buf,
- 		mad_send_wr->tid = ((struct ib_mad_hdr *) send_buf->mad)->tid;
- 		/* Timeout will be updated after send completes */
- 		mad_send_wr->timeout = msecs_to_jiffies(send_buf->timeout_ms);
--		mad_send_wr->retries = send_buf->retries;
-+		mad_send_wr->max_retries = send_buf->retries;
-+		mad_send_wr->retries_left = send_buf->retries;
-+		send_buf->retries = 0;
- 		/* Reference for work request to QP + response */
- 		mad_send_wr->refcount = 1 + (mad_send_wr->timeout > 0);
- 		mad_send_wr->status = IB_WC_SUCCESS;
-@@ -1931,15 +1933,6 @@ local:
- 	if (port_priv->device->process_mad) {
- 		int ret;
+ struct sk_buff;
+@@ -182,6 +191,22 @@ struct ipath_skbinfo {
+ 	dma_addr_t phys;
+ };
  
--		if (!response) {
--			printk(KERN_ERR PFX "No memory for response MAD\n");
--			/*
--			 * Is it better to assume that
--			 * it wouldn't be processed ?
--			 */
--			goto out;
--		}
--
- 		ret = port_priv->device->process_mad(port_priv->device, 0,
- 						     port_priv->port_num,
- 						     wc, &recv->grh,
-@@ -2282,8 +2275,6 @@ static void cancel_mads(struct ib_mad_agent_private *mad_agent_priv)
++/*
++ * Possible IB config parameters for ipath_f_get/set_ib_cfg()
++ */
++#define IPATH_IB_CFG_LIDLMC 0 /* Get/set LID (LS16b) and Mask (MS16b) */
++#define IPATH_IB_CFG_HRTBT 1 /* Get/set Heartbeat off/enable/auto */
++#define IPATH_IB_HRTBT_ON 3 /* Heartbeat enabled, sent every 100msec */
++#define IPATH_IB_HRTBT_OFF 0 /* Heartbeat off */
++#define IPATH_IB_CFG_LWID_ENB 2 /* Get/set allowed Link-width */
++#define IPATH_IB_CFG_LWID 3 /* Get currently active Link-width */
++#define IPATH_IB_CFG_SPD_ENB 4 /* Get/set allowed Link speeds */
++#define IPATH_IB_CFG_SPD 5 /* Get current Link spd */
++#define IPATH_IB_CFG_RXPOL_ENB 6 /* Get/set Auto-RX-polarity enable */
++#define IPATH_IB_CFG_LREV_ENB 7 /* Get/set Auto-Lane-reversal enable */
++#define IPATH_IB_CFG_LINKLATENCY 8 /* Get Auto-Lane-reversal enable */
++
++
+ struct ipath_devdata {
+ 	struct list_head ipath_list;
  
- 	/* Empty wait list to prevent receives from finding a request */
- 	list_splice_init(&mad_agent_priv->wait_list, &cancel_list);
--	/* Empty local completion list as well */
--	list_splice_init(&mad_agent_priv->local_list, &cancel_list);
- 	spin_unlock_irqrestore(&mad_agent_priv->lock, flags);
+@@ -222,6 +247,8 @@ struct ipath_devdata {
+ 	struct _ipath_layer ipath_layer;
+ 	/* setup intr */
+ 	int (*ipath_f_intrsetup)(struct ipath_devdata *);
++	/* fallback to alternate interrupt type if possible */
++	int (*ipath_f_intr_fallback)(struct ipath_devdata *);
+ 	/* setup on-chip bus config */
+ 	int (*ipath_f_bus)(struct ipath_devdata *, struct pci_dev *);
+ 	/* hard reset chip */
+@@ -244,6 +271,18 @@ struct ipath_devdata {
+ 	int (*ipath_f_get_base_info)(struct ipath_portdata *, void *);
+ 	/* free irq */
+ 	void (*ipath_f_free_irq)(struct ipath_devdata *);
++	struct ipath_message_header *(*ipath_f_get_msgheader)
++					(struct ipath_devdata *, __le32 *);
++	void (*ipath_f_config_ports)(struct ipath_devdata *, ushort);
++	int (*ipath_f_get_ib_cfg)(struct ipath_devdata *, int);
++	int (*ipath_f_set_ib_cfg)(struct ipath_devdata *, int, u32);
++	void (*ipath_f_config_jint)(struct ipath_devdata *, u16 , u16);
++	void (*ipath_f_read_counters)(struct ipath_devdata *,
++					struct infinipath_counters *);
++	void (*ipath_f_xgxs_reset)(struct ipath_devdata *);
++	/* per chip actions needed for IB Link up/down changes */
++	int (*ipath_f_ib_updown)(struct ipath_devdata *, int, u64);
++
+ 	struct ipath_ibdev *verbs_dev;
+ 	struct timer_list verbs_timer;
+ 	/* total dwords sent (summed from counter) */
+@@ -313,22 +352,12 @@ struct ipath_devdata {
+ 	 * supports, less gives more pio bufs/port, etc.
+ 	 */
+ 	u32 ipath_cfgports;
+-	/* port0 rcvhdrq head offset */
+-	u32 ipath_port0head;
+ 	/* count of port 0 hdrqfull errors */
+ 	u32 ipath_p0_hdrqfull;
++	/* port 0 number of receive eager buffers */
++	u32 ipath_p0_rcvegrcnt;
  
- 	/* Report all cancelled requests */
-@@ -2445,9 +2436,12 @@ static int retry_send(struct ib_mad_send_wr_private *mad_send_wr)
- {
- 	int ret;
+ 	/*
+-	 * (*cfgports) used to suppress multiple instances of same
+-	 * port staying stuck at same point
+-	 */
+-	u32 *ipath_lastrcvhdrqtails;
+-	/*
+-	 * (*cfgports) used to suppress multiple instances of same
+-	 * port staying stuck at same point
+-	 */
+-	u32 *ipath_lastegrheads;
+-	/*
+ 	 * index of last piobuffer we used.  Speeds up searching, by
+ 	 * starting at this point.  Doesn't matter if multiple cpu's use and
+ 	 * update, last updater is only write that matters.  Whenever it
+@@ -367,14 +396,15 @@ struct ipath_devdata {
+ 	unsigned long ipath_wc_len;
+ 	/* ref count for each pkey */
+ 	atomic_t ipath_pkeyrefs[4];
+-	/* shadow copy of all exptids physaddr; used only by funcsim */
+-	u64 *ipath_tidsimshadow;
+ 	/* shadow copy of struct page *'s for exp tid pages */
+ 	struct page **ipath_pageshadow;
+ 	/* shadow copy of dma handles for exp tid pages */
+ 	dma_addr_t *ipath_physshadow;
+-	/* lock to workaround chip bug 9437 */
++	u64 __iomem *ipath_egrtidbase;
++	/* lock to workaround chip bug 9437 and others */
++	spinlock_t ipath_kernel_tid_lock;
+ 	spinlock_t ipath_tid_lock;
++	spinlock_t ipath_sendctrl_lock;
  
--	if (!mad_send_wr->retries--)
-+	if (!mad_send_wr->retries_left)
- 		return -ETIMEDOUT;
+ 	/*
+ 	 * IPATH_STATUS_*,
+@@ -395,6 +425,8 @@ struct ipath_devdata {
+ 	void *ipath_dummy_hdrq;	/* used after port close */
+ 	dma_addr_t ipath_dummy_hdrq_phys;
  
-+	mad_send_wr->retries_left--;
-+	mad_send_wr->send_buf.retries++;
++	unsigned long ipath_ureg_align; /* user register alignment */
 +
- 	mad_send_wr->timeout = msecs_to_jiffies(mad_send_wr->send_buf.timeout_ms);
+ 	/*
+ 	 * Shadow copies of registers; size indicates read access size.
+ 	 * Most of them are readonly, but some are write-only register,
+@@ -456,8 +488,6 @@ struct ipath_devdata {
+ 	unsigned long ipath_rcvctrl;
+ 	/* shadow kr_sendctrl */
+ 	unsigned long ipath_sendctrl;
+-	/* ports waiting for PIOavail intr */
+-	unsigned long ipath_portpiowait;
+ 	unsigned long ipath_lastcancel; /* to not count armlaunch after cancel */
  
- 	if (mad_send_wr->mad_agent_priv->agent.rmpp_version) {
-diff --git a/drivers/infiniband/core/mad_priv.h b/drivers/infiniband/core/mad_priv.h
-index 9be5cc0..8b75010 100644
---- a/drivers/infiniband/core/mad_priv.h
-+++ b/drivers/infiniband/core/mad_priv.h
-@@ -131,7 +131,8 @@ struct ib_mad_send_wr_private {
- 	struct ib_sge sg_list[IB_MAD_SEND_REQ_MAX_SG];
- 	__be64 tid;
- 	unsigned long timeout;
--	int retries;
-+	int max_retries;
-+	int retries_left;
- 	int retry;
- 	int refcount;
- 	enum ib_wc_status status;
-diff --git a/drivers/infiniband/core/mad_rmpp.c b/drivers/infiniband/core/mad_rmpp.c
-index d43bc62..a5e2a31 100644
---- a/drivers/infiniband/core/mad_rmpp.c
-+++ b/drivers/infiniband/core/mad_rmpp.c
-@@ -684,7 +684,7 @@ static void process_rmpp_ack(struct ib_mad_agent_private *agent,
+ 	/* value we put in kr_rcvhdrcnt */
+@@ -550,12 +580,26 @@ struct ipath_devdata {
+ 	u8 ipath_minrev;
+ 	/* board rev, from ipath_revision */
+ 	u8 ipath_boardrev;
++
++	u8 ipath_r_portenable_shift;
++	u8 ipath_r_intravail_shift;
++	u8 ipath_r_tailupd_shift;
++	u8 ipath_r_portcfg_shift;
++
+ 	/* unit # of this chip, if present */
+ 	int ipath_unit;
+ 	/* saved for restore after reset */
+ 	u8 ipath_pci_cacheline;
+ 	/* LID mask control */
+ 	u8 ipath_lmc;
++	/* link width supported */
++	u8 ipath_link_width_supported;
++	/* link speed supported */
++	u8 ipath_link_speed_supported;
++	u8 ipath_link_width_enabled;
++	u8 ipath_link_speed_enabled;
++	u8 ipath_link_width_active;
++	u8 ipath_link_speed_active;
+ 	/* Rx Polarity inversion (compensate for ~tx on partner) */
+ 	u8 ipath_rx_pol_inv;
  
- 	if (seg_num > mad_send_wr->last_ack) {
- 		adjust_last_ack(mad_send_wr, seg_num);
--		mad_send_wr->retries = mad_send_wr->send_buf.retries;
-+		mad_send_wr->retries_left = mad_send_wr->max_retries;
- 	}
- 	mad_send_wr->newwin = newwin;
- 	if (mad_send_wr->last_ack == mad_send_wr->send_buf.seg_count) {
-diff --git a/drivers/infiniband/core/multicast.c b/drivers/infiniband/core/multicast.c
-index 1bc1fe6..107f170 100644
---- a/drivers/infiniband/core/multicast.c
-+++ b/drivers/infiniband/core/multicast.c
-@@ -73,11 +73,20 @@ struct mcast_device {
- };
+@@ -590,6 +634,8 @@ struct ipath_devdata {
+ 	 */
+ 	u32 ipath_i_rcvavail_mask;
+ 	u32 ipath_i_rcvurg_mask;
++	u16 ipath_i_rcvurg_shift;
++	u16 ipath_i_rcvavail_shift;
  
- enum mcast_state {
--	MCAST_IDLE,
- 	MCAST_JOINING,
- 	MCAST_MEMBER,
-+	MCAST_ERROR,
-+};
+ 	/*
+ 	 * Register bits for selecting i2c direction and values, used for
+@@ -603,6 +649,29 @@ struct ipath_devdata {
+ 	/* lock for doing RMW of shadows/regs for ExtCtrl and GPIO */
+ 	spinlock_t ipath_gpio_lock;
+ 
++	/*
++	 * IB link and linktraining states and masks that vary per chip in
++	 * some way.  Set at init, to avoid each IB status change interrupt
++	 */
++	u8 ibcs_ls_shift;
++	u8 ibcs_lts_mask;
++	u32 ibcs_mask;
++	u32 ib_init;
++	u32 ib_arm;
++	u32 ib_active;
 +
-+enum mcast_group_state {
-+	MCAST_IDLE,
- 	MCAST_BUSY,
--	MCAST_ERROR
-+	MCAST_GROUP_ERROR,
-+	MCAST_PKEY_EVENT
-+};
++	u16 ipath_rhf_offset; /* offset of RHF within receive header entry */
 +
-+enum {
-+	MCAST_INVALID_PKEY_INDEX = 0xFFFF
++	/*
++	 * shift/mask for linkcmd, linkinitcmd, maxpktlen in ibccontol
++	 * reg. Changes for IBA7220
++	 */
++	u8 ibcc_lic_mask; /* LinkInitCmd */
++	u8 ibcc_lc_shift; /* LinkCmd */
++	u8 ibcc_mpl_shift; /* Maxpktlen */
++
++	u8 delay_mult;
++
+ 	/* used to override LED behavior */
+ 	u8 ipath_led_override;  /* Substituted for normal value, if non-zero */
+ 	u16 ipath_led_override_timeoff; /* delta to next timer event */
+@@ -616,7 +685,7 @@ struct ipath_devdata {
+ 	/* control access to actual counters, timer */
+ 	spinlock_t ipath_eep_st_lock;
+ 	/* control high-level access to EEPROM */
+-	struct semaphore ipath_eep_sem;
++	struct mutex ipath_eep_lock;
+ 	/* Below inc'd by ipath_snap_cntrs(), locked by ipath_eep_st_lock */
+ 	uint64_t ipath_traffic_wds;
+ 	/* active time is kept in seconds, but logged in hours */
+@@ -630,6 +699,10 @@ struct ipath_devdata {
+ 	 * each of the counters to increment.
+ 	 */
+ 	struct ipath_eep_log_mask ipath_eep_st_masks[IPATH_EEP_LOG_CNT];
++
++	/* interrupt mitigation reload register info */
++	u16 ipath_jint_idle_ticks;	/* idle clock ticks */
++	u16 ipath_jint_max_packets;	/* max packets across all ports */
  };
  
- struct mcast_member;
-@@ -93,9 +102,10 @@ struct mcast_group {
- 	struct mcast_member	*last_join;
- 	int			members[3];
- 	atomic_t		refcount;
--	enum mcast_state	state;
-+	enum mcast_group_state	state;
- 	struct ib_sa_query	*query;
- 	int			query_id;
-+	u16			pkey_index;
- };
+ /* Private data for file operations */
+@@ -690,7 +763,7 @@ void ipath_free_pddata(struct ipath_devdata *, struct ipath_portdata *);
  
- struct mcast_member {
-@@ -378,9 +388,19 @@ static int fail_join(struct mcast_group *group, struct mcast_member *member,
- static void process_group_error(struct mcast_group *group)
- {
- 	struct mcast_member *member;
--	int ret;
-+	int ret = 0;
-+	u16 pkey_index;
-+
-+	if (group->state == MCAST_PKEY_EVENT)
-+		ret = ib_find_pkey(group->port->dev->device,
-+				   group->port->port_num,
-+				   be16_to_cpu(group->rec.pkey), &pkey_index);
+ int ipath_parse_ushort(const char *str, unsigned short *valp);
  
- 	spin_lock_irq(&group->lock);
-+	if (group->state == MCAST_PKEY_EVENT && !ret &&
-+	    group->pkey_index == pkey_index)
-+		goto out;
-+
- 	while (!list_empty(&group->active_list)) {
- 		member = list_entry(group->active_list.next,
- 				    struct mcast_member, list);
-@@ -399,6 +419,7 @@ static void process_group_error(struct mcast_group *group)
- 	}
+-void ipath_kreceive(struct ipath_devdata *);
++void ipath_kreceive(struct ipath_portdata *);
+ int ipath_setrcvhdrsize(struct ipath_devdata *, unsigned);
+ int ipath_reset_device(int);
+ void ipath_get_faststats(unsigned long);
+@@ -698,6 +771,8 @@ int ipath_set_linkstate(struct ipath_devdata *, u8);
+ int ipath_set_mtu(struct ipath_devdata *, u16);
+ int ipath_set_lid(struct ipath_devdata *, u32, u8);
+ int ipath_set_rx_pol_inv(struct ipath_devdata *dd, u8 new_pol_inv);
++void ipath_enable_armlaunch(struct ipath_devdata *);
++void ipath_disable_armlaunch(struct ipath_devdata *);
  
- 	group->rec.join_state = 0;
-+out:
- 	group->state = MCAST_BUSY;
- 	spin_unlock_irq(&group->lock);
- }
-@@ -415,9 +436,9 @@ static void mcast_work_handler(struct work_struct *work)
- retest:
- 	spin_lock_irq(&group->lock);
- 	while (!list_empty(&group->pending_list) ||
--	       (group->state == MCAST_ERROR)) {
-+	       (group->state != MCAST_BUSY)) {
+ /* for use in system calls, where we want to know device type, etc. */
+ #define port_fp(fp) ((struct ipath_filedata *)(fp)->private_data)->pd
+@@ -744,9 +819,15 @@ int ipath_set_rx_pol_inv(struct ipath_devdata *dd, u8 new_pol_inv);
+ 		 * are 64bit */
+ #define IPATH_32BITCOUNTERS 0x20000
+ 		/* can miss port0 rx interrupts */
++		/* Interrupt register is 64 bits */
++#define IPATH_INTREG_64     0x40000
+ #define IPATH_DISABLED      0x80000 /* administratively disabled */
+ 		/* Use GPIO interrupts for new counters */
+ #define IPATH_GPIO_ERRINTRS 0x100000
++#define IPATH_SWAP_PIOBUFS  0x200000
++		/* Suppress heartbeat, even if turning off loopback */
++#define IPATH_NO_HRTBT      0x1000000
++#define IPATH_HAS_MULT_IB_SPEED 0x8000000
  
--		if (group->state == MCAST_ERROR) {
-+		if (group->state != MCAST_BUSY) {
- 			spin_unlock_irq(&group->lock);
- 			process_group_error(group);
- 			goto retest;
-@@ -494,12 +515,19 @@ static void join_handler(int status, struct ib_sa_mcmember_rec *rec,
- 			 void *context)
- {
- 	struct mcast_group *group = context;
-+	u16 pkey_index = MCAST_INVALID_PKEY_INDEX;
+ /* Bits in GPIO for the added interrupts */
+ #define IPATH_GPIO_PORT0_BIT 2
+@@ -758,8 +839,6 @@ int ipath_set_rx_pol_inv(struct ipath_devdata *dd, u8 new_pol_inv);
+ /* portdata flag bit offsets */
+ 		/* waiting for a packet to arrive */
+ #define IPATH_PORT_WAITING_RCV   2
+-		/* waiting for a PIO buffer to be available */
+-#define IPATH_PORT_WAITING_PIO   3
+ 		/* master has not finished initializing */
+ #define IPATH_PORT_MASTER_UNINIT 4
+ 		/* waiting for an urgent packet to arrive */
+@@ -767,8 +846,6 @@ int ipath_set_rx_pol_inv(struct ipath_devdata *dd, u8 new_pol_inv);
  
- 	if (status)
- 		process_join_error(group, status);
- 	else {
-+		ib_find_pkey(group->port->dev->device, group->port->port_num,
-+			     be16_to_cpu(rec->pkey), &pkey_index);
-+
- 		spin_lock_irq(&group->port->lock);
- 		group->rec = *rec;
-+		if (group->state == MCAST_BUSY &&
-+		    group->pkey_index == MCAST_INVALID_PKEY_INDEX)
-+			group->pkey_index = pkey_index;
- 		if (!memcmp(&mgid0, &group->rec.mgid, sizeof mgid0)) {
- 			rb_erase(&group->node, &group->port->table);
- 			mcast_insert(group->port, group, 1);
-@@ -539,6 +567,7 @@ static struct mcast_group *acquire_group(struct mcast_port *port,
+ /* free up any allocated data at closes */
+ void ipath_free_data(struct ipath_portdata *dd);
+-int ipath_waitfor_mdio_cmdready(struct ipath_devdata *);
+-int ipath_waitfor_complete(struct ipath_devdata *, ipath_kreg, u64, u64 *);
+ u32 __iomem *ipath_getpiobuf(struct ipath_devdata *, u32 *);
+ void ipath_init_iba6120_funcs(struct ipath_devdata *);
+ void ipath_init_iba6110_funcs(struct ipath_devdata *);
+@@ -792,33 +869,6 @@ void ipath_set_led_override(struct ipath_devdata *dd, unsigned int val);
+  */
+ #define IPATH_DFLT_RCVHDRSIZE 9
  
- 	group->port = port;
- 	group->rec.mgid = *mgid;
-+	group->pkey_index = MCAST_INVALID_PKEY_INDEX;
- 	INIT_LIST_HEAD(&group->pending_list);
- 	INIT_LIST_HEAD(&group->active_list);
- 	INIT_WORK(&group->work, mcast_work_handler);
-@@ -707,7 +736,8 @@ int ib_init_ah_from_mcmember(struct ib_device *device, u8 port_num,
+-#define IPATH_MDIO_CMD_WRITE   1
+-#define IPATH_MDIO_CMD_READ    2
+-#define IPATH_MDIO_CLD_DIV     25	/* to get 2.5 Mhz mdio clock */
+-#define IPATH_MDIO_CMDVALID    0x40000000	/* bit 30 */
+-#define IPATH_MDIO_DATAVALID   0x80000000	/* bit 31 */
+-#define IPATH_MDIO_CTRL_STD    0x0
+-
+-static inline u64 ipath_mdio_req(int cmd, int dev, int reg, int data)
+-{
+-	return (((u64) IPATH_MDIO_CLD_DIV) << 32) |
+-		(cmd << 26) |
+-		(dev << 21) |
+-		(reg << 16) |
+-		(data & 0xFFFF);
+-}
+-
+-		/* signal and fifo status, in bank 31 */
+-#define IPATH_MDIO_CTRL_XGXS_REG_8  0x8
+-		/* controls loopback, redundancy */
+-#define IPATH_MDIO_CTRL_8355_REG_1  0x10
+-		/* premph, encdec, etc. */
+-#define IPATH_MDIO_CTRL_8355_REG_2  0x11
+-		/* Kchars, etc. */
+-#define IPATH_MDIO_CTRL_8355_REG_6  0x15
+-#define IPATH_MDIO_CTRL_8355_REG_9  0x18
+-#define IPATH_MDIO_CTRL_8355_REG_10 0x1D
+-
+ int ipath_get_user_pages(unsigned long, size_t, struct page **);
+ void ipath_release_user_pages(struct page **, size_t);
+ void ipath_release_user_pages_on_close(struct page **, size_t);
+@@ -863,7 +913,7 @@ static inline u32 ipath_read_ureg32(const struct ipath_devdata *dd,
+ 	return readl(regno + (u64 __iomem *)
+ 		     (dd->ipath_uregbase +
+ 		      (char __iomem *)dd->ipath_kregbase +
+-		      dd->ipath_palign * port));
++		      dd->ipath_ureg_align * port));
  }
- EXPORT_SYMBOL(ib_init_ah_from_mcmember);
  
--static void mcast_groups_lost(struct mcast_port *port)
-+static void mcast_groups_event(struct mcast_port *port,
-+			       enum mcast_group_state state)
- {
- 	struct mcast_group *group;
- 	struct rb_node *node;
-@@ -721,7 +751,8 @@ static void mcast_groups_lost(struct mcast_port *port)
- 			atomic_inc(&group->refcount);
- 			queue_work(mcast_wq, &group->work);
- 		}
--		group->state = MCAST_ERROR;
-+		if (group->state != MCAST_GROUP_ERROR)
-+			group->state = state;
- 		spin_unlock(&group->lock);
- 	}
- 	spin_unlock_irqrestore(&port->lock, flags);
-@@ -731,16 +762,20 @@ static void mcast_event_handler(struct ib_event_handler *handler,
- 				struct ib_event *event)
+ /**
+@@ -880,7 +930,7 @@ static inline void ipath_write_ureg(const struct ipath_devdata *dd,
  {
- 	struct mcast_device *dev;
-+	int index;
- 
- 	dev = container_of(handler, struct mcast_device, event_handler);
-+	index = event->element.port_num - dev->start_port;
- 
- 	switch (event->event) {
- 	case IB_EVENT_PORT_ERR:
- 	case IB_EVENT_LID_CHANGE:
- 	case IB_EVENT_SM_CHANGE:
- 	case IB_EVENT_CLIENT_REREGISTER:
--		mcast_groups_lost(&dev->port[event->element.port_num -
--					     dev->start_port]);
-+		mcast_groups_event(&dev->port[index], MCAST_GROUP_ERROR);
-+		break;
-+	case IB_EVENT_PKEY_CHANGE:
-+		mcast_groups_event(&dev->port[index], MCAST_PKEY_EVENT);
- 		break;
- 	default:
- 		break;
-diff --git a/drivers/infiniband/core/smi.h b/drivers/infiniband/core/smi.h
-index 1cfc298..aff96ba 100644
---- a/drivers/infiniband/core/smi.h
-+++ b/drivers/infiniband/core/smi.h
-@@ -59,7 +59,8 @@ extern enum smi_action smi_handle_dr_smp_send(struct ib_smp *smp,
- 					      u8 node_type, int port_num);
- 
- /*
-- * Return 1 if the SMP should be handled by the local SMA/SM via process_mad
-+ * Return IB_SMI_HANDLE if the SMP should be handled by the local SMA/SM
-+ * via process_mad
-  */
- static inline enum smi_action smi_check_local_smp(struct ib_smp *smp,
- 						  struct ib_device *device)
-@@ -71,4 +72,19 @@ static inline enum smi_action smi_check_local_smp(struct ib_smp *smp,
- 		(smp->hop_ptr == smp->hop_cnt + 1)) ?
- 		IB_SMI_HANDLE : IB_SMI_DISCARD);
+ 	u64 __iomem *ubase = (u64 __iomem *)
+ 		(dd->ipath_uregbase + (char __iomem *) dd->ipath_kregbase +
+-		 dd->ipath_palign * port);
++		 dd->ipath_ureg_align * port);
+ 	if (dd->ipath_kregbase)
+ 		writeq(value, &ubase[regno]);
+ }
+@@ -930,6 +980,53 @@ static inline u32 ipath_read_creg32(const struct ipath_devdata *dd,
+ 		      (char __iomem *)dd->ipath_kregbase));
  }
+ 
++static inline void ipath_write_creg(const struct ipath_devdata *dd,
++				    ipath_creg regno, u64 value)
++{
++	if (dd->ipath_kregbase)
++		writeq(value, regno + (u64 __iomem *)
++		       (dd->ipath_cregbase +
++			(char __iomem *)dd->ipath_kregbase));
++}
++
++static inline void ipath_clear_rcvhdrtail(const struct ipath_portdata *pd)
++{
++	*((u64 *) pd->port_rcvhdrtail_kvaddr) = 0ULL;
++}
++
++static inline u32 ipath_get_rcvhdrtail(const struct ipath_portdata *pd)
++{
++	return (u32) le64_to_cpu(*((volatile __le64 *)
++				pd->port_rcvhdrtail_kvaddr));
++}
++
++static inline u64 ipath_read_ireg(const struct ipath_devdata *dd, ipath_kreg r)
++{
++	return (dd->ipath_flags & IPATH_INTREG_64) ?
++		ipath_read_kreg64(dd, r) : ipath_read_kreg32(dd, r);
++}
 +
 +/*
-+ * Return IB_SMI_HANDLE if the SMP should be handled by the local SMA/SM
-+ * via process_mad
++ * from contents of IBCStatus (or a saved copy), return linkstate
++ * Report ACTIVE_DEFER as ACTIVE, because we treat them the same
++ * everywhere, anyway (and should be, for almost all purposes).
 + */
-+static inline enum smi_action smi_check_local_returning_smp(struct ib_smp *smp,
-+						   struct ib_device *device)
++static inline u32 ipath_ib_linkstate(struct ipath_devdata *dd, u64 ibcs)
 +{
-+	/* C14-13:3 -- We're at the end of the DR segment of path */
-+	/* C14-13:4 -- Hop Pointer == 0 -> give to SM */
-+	return ((device->process_mad &&
-+		ib_get_smp_direction(smp) &&
-+		!smp->hop_ptr) ? IB_SMI_HANDLE : IB_SMI_DISCARD);
++	u32 state = (u32)(ibcs >> dd->ibcs_ls_shift) &
++		INFINIPATH_IBCS_LINKSTATE_MASK;
++	if (state == INFINIPATH_IBCS_L_STATE_ACT_DEFER)
++		state = INFINIPATH_IBCS_L_STATE_ACTIVE;
++	return state;
 +}
 +
- #endif	/* __SMI_H_ */
-diff --git a/drivers/infiniband/core/sysfs.c b/drivers/infiniband/core/sysfs.c
-index 3d40506..c864ef7 100644
---- a/drivers/infiniband/core/sysfs.c
-+++ b/drivers/infiniband/core/sysfs.c
-@@ -508,19 +508,10 @@ static int add_port(struct ib_device *device, int port_num)
++/* from contents of IBCStatus (or a saved copy), return linktrainingstate */
++static inline u32 ipath_ib_linktrstate(struct ipath_devdata *dd, u64 ibcs)
++{
++	return (u32)(ibcs >> INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT) &
++		dd->ibcs_lts_mask;
++}
++
+ /*
+  * sysfs interface.
+  */
+@@ -938,8 +1035,7 @@ struct device_driver;
+ 
+ extern const char ib_ipath_version[];
+ 
+-int ipath_driver_create_group(struct device_driver *);
+-void ipath_driver_remove_group(struct device_driver *);
++extern struct attribute_group *ipath_driver_attr_groups[];
+ 
+ int ipath_device_create_group(struct device *, struct ipath_devdata *);
+ void ipath_device_remove_group(struct device *, struct ipath_devdata *);
+diff --git a/drivers/infiniband/hw/ipath/ipath_keys.c b/drivers/infiniband/hw/ipath/ipath_keys.c
+index 85a4aef..8f32b17 100644
+--- a/drivers/infiniband/hw/ipath/ipath_keys.c
++++ b/drivers/infiniband/hw/ipath/ipath_keys.c
+@@ -128,9 +128,8 @@ int ipath_lkey_ok(struct ipath_qp *qp, struct ipath_sge *isge,
+ 	int ret;
+ 
+ 	/*
+-	 * We use LKEY == zero to mean a physical kmalloc() address.
+-	 * This is a bit of a hack since we rely on dma_map_single()
+-	 * being reversible by calling bus_to_virt().
++	 * We use LKEY == zero for kernel virtual addresses
++	 * (see ipath_get_dma_mr and ipath_dma.c).
+ 	 */
+ 	if (sge->lkey == 0) {
+ 		struct ipath_pd *pd = to_ipd(qp->ibqp.pd);
+diff --git a/drivers/infiniband/hw/ipath/ipath_mad.c b/drivers/infiniband/hw/ipath/ipath_mad.c
+index 3d1432d..d98d5f1 100644
+--- a/drivers/infiniband/hw/ipath/ipath_mad.c
++++ b/drivers/infiniband/hw/ipath/ipath_mad.c
+@@ -934,6 +934,7 @@ static int recv_pma_get_portsamplescontrol(struct ib_perf *pmp,
+ 	struct ib_pma_portsamplescontrol *p =
+ 		(struct ib_pma_portsamplescontrol *)pmp->data;
+ 	struct ipath_ibdev *dev = to_idev(ibdev);
++	struct ipath_cregs const *crp = dev->dd->ipath_cregs;
+ 	unsigned long flags;
+ 	u8 port_select = p->port_select;
+ 
+@@ -955,7 +956,10 @@ static int recv_pma_get_portsamplescontrol(struct ib_perf *pmp,
+ 	p->counter_width = 4;	/* 32 bit counters */
+ 	p->counter_mask0_9 = COUNTER_MASK0_9;
+ 	spin_lock_irqsave(&dev->pending_lock, flags);
+-	p->sample_status = dev->pma_sample_status;
++	if (crp->cr_psstat)
++		p->sample_status = ipath_read_creg32(dev->dd, crp->cr_psstat);
++	else
++		p->sample_status = dev->pma_sample_status;
+ 	p->sample_start = cpu_to_be32(dev->pma_sample_start);
+ 	p->sample_interval = cpu_to_be32(dev->pma_sample_interval);
+ 	p->tag = cpu_to_be16(dev->pma_tag);
+@@ -975,8 +979,9 @@ static int recv_pma_set_portsamplescontrol(struct ib_perf *pmp,
+ 	struct ib_pma_portsamplescontrol *p =
+ 		(struct ib_pma_portsamplescontrol *)pmp->data;
+ 	struct ipath_ibdev *dev = to_idev(ibdev);
++	struct ipath_cregs const *crp = dev->dd->ipath_cregs;
+ 	unsigned long flags;
+-	u32 start;
++	u8 status;
+ 	int ret;
+ 
+ 	if (pmp->attr_mod != 0 ||
+@@ -986,59 +991,67 @@ static int recv_pma_set_portsamplescontrol(struct ib_perf *pmp,
+ 		goto bail;
+ 	}
+ 
+-	start = be32_to_cpu(p->sample_start);
+-	if (start != 0) {
+-		spin_lock_irqsave(&dev->pending_lock, flags);
+-		if (dev->pma_sample_status == IB_PMA_SAMPLE_STATUS_DONE) {
+-			dev->pma_sample_status =
+-				IB_PMA_SAMPLE_STATUS_STARTED;
+-			dev->pma_sample_start = start;
+-			dev->pma_sample_interval =
+-				be32_to_cpu(p->sample_interval);
+-			dev->pma_tag = be16_to_cpu(p->tag);
+-			if (p->counter_select[0])
+-				dev->pma_counter_select[0] =
+-					p->counter_select[0];
+-			if (p->counter_select[1])
+-				dev->pma_counter_select[1] =
+-					p->counter_select[1];
+-			if (p->counter_select[2])
+-				dev->pma_counter_select[2] =
+-					p->counter_select[2];
+-			if (p->counter_select[3])
+-				dev->pma_counter_select[3] =
+-					p->counter_select[3];
+-			if (p->counter_select[4])
+-				dev->pma_counter_select[4] =
+-					p->counter_select[4];
+-		}
+-		spin_unlock_irqrestore(&dev->pending_lock, flags);
++	spin_lock_irqsave(&dev->pending_lock, flags);
++	if (crp->cr_psstat)
++		status = ipath_read_creg32(dev->dd, crp->cr_psstat);
++	else
++		status = dev->pma_sample_status;
++	if (status == IB_PMA_SAMPLE_STATUS_DONE) {
++		dev->pma_sample_start = be32_to_cpu(p->sample_start);
++		dev->pma_sample_interval = be32_to_cpu(p->sample_interval);
++		dev->pma_tag = be16_to_cpu(p->tag);
++		dev->pma_counter_select[0] = p->counter_select[0];
++		dev->pma_counter_select[1] = p->counter_select[1];
++		dev->pma_counter_select[2] = p->counter_select[2];
++		dev->pma_counter_select[3] = p->counter_select[3];
++		dev->pma_counter_select[4] = p->counter_select[4];
++		if (crp->cr_psstat) {
++			ipath_write_creg(dev->dd, crp->cr_psinterval,
++					 dev->pma_sample_interval);
++			ipath_write_creg(dev->dd, crp->cr_psstart,
++					 dev->pma_sample_start);
++		} else
++			dev->pma_sample_status = IB_PMA_SAMPLE_STATUS_STARTED;
+ 	}
++	spin_unlock_irqrestore(&dev->pending_lock, flags);
++
+ 	ret = recv_pma_get_portsamplescontrol(pmp, ibdev, port);
+ 
+ bail:
+ 	return ret;
+ }
+ 
+-static u64 get_counter(struct ipath_ibdev *dev, __be16 sel)
++static u64 get_counter(struct ipath_ibdev *dev,
++		       struct ipath_cregs const *crp,
++		       __be16 sel)
+ {
+ 	u64 ret;
+ 
+ 	switch (sel) {
+ 	case IB_PMA_PORT_XMIT_DATA:
+-		ret = dev->ipath_sword;
++		ret = (crp->cr_psxmitdatacount) ?
++			ipath_read_creg32(dev->dd, crp->cr_psxmitdatacount) :
++			dev->ipath_sword;
+ 		break;
+ 	case IB_PMA_PORT_RCV_DATA:
+-		ret = dev->ipath_rword;
++		ret = (crp->cr_psrcvdatacount) ?
++			ipath_read_creg32(dev->dd, crp->cr_psrcvdatacount) :
++			dev->ipath_rword;
+ 		break;
+ 	case IB_PMA_PORT_XMIT_PKTS:
+-		ret = dev->ipath_spkts;
++		ret = (crp->cr_psxmitpktscount) ?
++			ipath_read_creg32(dev->dd, crp->cr_psxmitpktscount) :
++			dev->ipath_spkts;
+ 		break;
+ 	case IB_PMA_PORT_RCV_PKTS:
+-		ret = dev->ipath_rpkts;
++		ret = (crp->cr_psrcvpktscount) ?
++			ipath_read_creg32(dev->dd, crp->cr_psrcvpktscount) :
++			dev->ipath_rpkts;
+ 		break;
+ 	case IB_PMA_PORT_XMIT_WAIT:
+-		ret = dev->ipath_xmit_wait;
++		ret = (crp->cr_psxmitwaitcount) ?
++			ipath_read_creg32(dev->dd, crp->cr_psxmitwaitcount) :
++			dev->ipath_xmit_wait;
+ 		break;
+ 	default:
+ 		ret = 0;
+@@ -1053,14 +1066,21 @@ static int recv_pma_get_portsamplesresult(struct ib_perf *pmp,
+ 	struct ib_pma_portsamplesresult *p =
+ 		(struct ib_pma_portsamplesresult *)pmp->data;
+ 	struct ipath_ibdev *dev = to_idev(ibdev);
++	struct ipath_cregs const *crp = dev->dd->ipath_cregs;
++	u8 status;
+ 	int i;
+ 
+ 	memset(pmp->data, 0, sizeof(pmp->data));
+ 	p->tag = cpu_to_be16(dev->pma_tag);
+-	p->sample_status = cpu_to_be16(dev->pma_sample_status);
++	if (crp->cr_psstat)
++		status = ipath_read_creg32(dev->dd, crp->cr_psstat);
++	else
++		status = dev->pma_sample_status;
++	p->sample_status = cpu_to_be16(status);
+ 	for (i = 0; i < ARRAY_SIZE(dev->pma_counter_select); i++)
+-		p->counter[i] = cpu_to_be32(
+-			get_counter(dev, dev->pma_counter_select[i]));
++		p->counter[i] = (status != IB_PMA_SAMPLE_STATUS_DONE) ? 0 :
++		    cpu_to_be32(
++			get_counter(dev, crp, dev->pma_counter_select[i]));
  
- 	p->ibdev      = device;
- 	p->port_num   = port_num;
--	p->kobj.ktype = &port_type;
+ 	return reply((struct ib_smp *) pmp);
+ }
+@@ -1071,16 +1091,23 @@ static int recv_pma_get_portsamplesresult_ext(struct ib_perf *pmp,
+ 	struct ib_pma_portsamplesresult_ext *p =
+ 		(struct ib_pma_portsamplesresult_ext *)pmp->data;
+ 	struct ipath_ibdev *dev = to_idev(ibdev);
++	struct ipath_cregs const *crp = dev->dd->ipath_cregs;
++	u8 status;
+ 	int i;
  
--	p->kobj.parent = kobject_get(&device->ports_parent);
--	if (!p->kobj.parent) {
--		ret = -EBUSY;
--		goto err;
--	}
--
--	ret = kobject_set_name(&p->kobj, "%d", port_num);
--	if (ret)
--		goto err_put;
--
--	ret = kobject_register(&p->kobj);
-+	ret = kobject_init_and_add(&p->kobj, &port_type,
-+				   kobject_get(device->ports_parent),
-+				   "%d", port_num);
- 	if (ret)
- 		goto err_put;
+ 	memset(pmp->data, 0, sizeof(pmp->data));
+ 	p->tag = cpu_to_be16(dev->pma_tag);
+-	p->sample_status = cpu_to_be16(dev->pma_sample_status);
++	if (crp->cr_psstat)
++		status = ipath_read_creg32(dev->dd, crp->cr_psstat);
++	else
++		status = dev->pma_sample_status;
++	p->sample_status = cpu_to_be16(status);
+ 	/* 64 bits */
+ 	p->extended_width = __constant_cpu_to_be32(0x80000000);
+ 	for (i = 0; i < ARRAY_SIZE(dev->pma_counter_select); i++)
+-		p->counter[i] = cpu_to_be64(
+-			get_counter(dev, dev->pma_counter_select[i]));
++		p->counter[i] = (status != IB_PMA_SAMPLE_STATUS_DONE) ? 0 :
++		    cpu_to_be64(
++			get_counter(dev, crp, dev->pma_counter_select[i]));
  
-@@ -549,6 +540,7 @@ static int add_port(struct ib_device *device, int port_num)
+ 	return reply((struct ib_smp *) pmp);
+ }
+@@ -1113,6 +1140,8 @@ static int recv_pma_get_portcounters(struct ib_perf *pmp,
+ 		dev->z_local_link_integrity_errors;
+ 	cntrs.excessive_buffer_overrun_errors -=
+ 		dev->z_excessive_buffer_overrun_errors;
++	cntrs.vl15_dropped -= dev->z_vl15_dropped;
++	cntrs.vl15_dropped += dev->n_vl15_dropped;
  
- 	list_add_tail(&p->kobj.entry, &device->port_list);
+ 	memset(pmp->data, 0, sizeof(pmp->data));
  
-+	kobject_uevent(&p->kobj, KOBJ_ADD);
- 	return 0;
+@@ -1156,10 +1185,10 @@ static int recv_pma_get_portcounters(struct ib_perf *pmp,
+ 		cntrs.excessive_buffer_overrun_errors = 0xFUL;
+ 	p->lli_ebor_errors = (cntrs.local_link_integrity_errors << 4) |
+ 		cntrs.excessive_buffer_overrun_errors;
+-	if (dev->n_vl15_dropped > 0xFFFFUL)
++	if (cntrs.vl15_dropped > 0xFFFFUL)
+ 		p->vl15_dropped = __constant_cpu_to_be16(0xFFFF);
+ 	else
+-		p->vl15_dropped = cpu_to_be16((u16)dev->n_vl15_dropped);
++		p->vl15_dropped = cpu_to_be16((u16)cntrs.vl15_dropped);
+ 	if (cntrs.port_xmit_data > 0xFFFFFFFFUL)
+ 		p->port_xmit_data = __constant_cpu_to_be32(0xFFFFFFFF);
+ 	else
+@@ -1262,8 +1291,10 @@ static int recv_pma_set_portcounters(struct ib_perf *pmp,
+ 		dev->z_excessive_buffer_overrun_errors =
+ 			cntrs.excessive_buffer_overrun_errors;
  
- err_free_pkey:
-@@ -570,9 +562,7 @@ err_remove_pma:
- 	sysfs_remove_group(&p->kobj, &pma_group);
+-	if (p->counter_select & IB_PMA_SEL_PORT_VL15_DROPPED)
++	if (p->counter_select & IB_PMA_SEL_PORT_VL15_DROPPED) {
+ 		dev->n_vl15_dropped = 0;
++		dev->z_vl15_dropped = cntrs.vl15_dropped;
++	}
  
- err_put:
--	kobject_put(&device->ports_parent);
+ 	if (p->counter_select & IB_PMA_SEL_PORT_XMIT_DATA)
+ 		dev->z_port_xmit_data = cntrs.port_xmit_data;
+@@ -1434,7 +1465,7 @@ static int process_subn(struct ib_device *ibdev, int mad_flags,
+ 		 * before checking for other consumers.
+ 		 * Just tell the caller to process it normally.
+ 		 */
+-		ret = IB_MAD_RESULT_FAILURE;
++		ret = IB_MAD_RESULT_SUCCESS;
+ 		goto bail;
+ 	default:
+ 		smp->status |= IB_SMP_UNSUP_METHOD;
+@@ -1516,7 +1547,7 @@ static int process_perf(struct ib_device *ibdev, u8 port_num,
+ 		 * before checking for other consumers.
+ 		 * Just tell the caller to process it normally.
+ 		 */
+-		ret = IB_MAD_RESULT_FAILURE;
++		ret = IB_MAD_RESULT_SUCCESS;
+ 		goto bail;
+ 	default:
+ 		pmp->status |= IB_SMP_UNSUP_METHOD;
+diff --git a/drivers/infiniband/hw/ipath/ipath_qp.c b/drivers/infiniband/hw/ipath/ipath_qp.c
+index b997ff8..80dc623 100644
+--- a/drivers/infiniband/hw/ipath/ipath_qp.c
++++ b/drivers/infiniband/hw/ipath/ipath_qp.c
+@@ -387,8 +387,8 @@ int ipath_error_qp(struct ipath_qp *qp, enum ib_wc_status err)
+ 	struct ib_wc wc;
+ 	int ret = 0;
+ 
+-	ipath_dbg("QP%d/%d in error state\n",
+-		  qp->ibqp.qp_num, qp->remote_qpn);
++	ipath_dbg("QP%d/%d in error state (%d)\n",
++		  qp->ibqp.qp_num, qp->remote_qpn, err);
+ 
+ 	spin_lock(&dev->pending_lock);
+ 	/* XXX What if its already removed by the timeout code? */
+@@ -855,8 +855,6 @@ struct ib_qp *ipath_create_qp(struct ib_pd *ibpd,
+ 	 * See ipath_mmap() for details.
+ 	 */
+ 	if (udata && udata->outlen >= sizeof(__u64)) {
+-		int err;
 -
--err:
-+	kobject_put(device->ports_parent);
- 	kfree(p);
- 	return ret;
- }
-@@ -694,16 +684,9 @@ int ib_device_register_sysfs(struct ib_device *device)
- 			goto err_unregister;
- 	}
+ 		if (!qp->r_rq.wq) {
+ 			__u64 offset = 0;
  
--	device->ports_parent.parent = kobject_get(&class_dev->kobj);
--	if (!device->ports_parent.parent) {
--		ret = -EBUSY;
--		goto err_unregister;
--	}
--	ret = kobject_set_name(&device->ports_parent, "ports");
--	if (ret)
--		goto err_put;
--	ret = kobject_register(&device->ports_parent);
--	if (ret)
-+	device->ports_parent = kobject_create_and_add("ports",
-+					kobject_get(&class_dev->kobj));
-+	if (!device->ports_parent)
- 		goto err_put;
+diff --git a/drivers/infiniband/hw/ipath/ipath_rc.c b/drivers/infiniband/hw/ipath/ipath_rc.c
+index 120a61b..459e46e 100644
+--- a/drivers/infiniband/hw/ipath/ipath_rc.c
++++ b/drivers/infiniband/hw/ipath/ipath_rc.c
+@@ -647,6 +647,7 @@ static void send_rc_ack(struct ipath_qp *qp)
  
- 	if (device->node_type == RDMA_NODE_IB_SWITCH) {
-@@ -731,7 +714,7 @@ err_put:
- 			sysfs_remove_group(p, &pma_group);
- 			sysfs_remove_group(p, &port->pkey_group);
- 			sysfs_remove_group(p, &port->gid_group);
--			kobject_unregister(p);
-+			kobject_put(p);
- 		}
- 	}
+ queue_ack:
+ 	spin_lock_irqsave(&qp->s_lock, flags);
++	dev->n_rc_qacks++;
+ 	qp->s_flags |= IPATH_S_ACK_PENDING;
+ 	qp->s_nak_state = qp->r_nak_state;
+ 	qp->s_ack_psn = qp->r_ack_psn;
+@@ -798,11 +799,13 @@ bail:
  
-@@ -755,10 +738,10 @@ void ib_device_unregister_sysfs(struct ib_device *device)
- 		sysfs_remove_group(p, &pma_group);
- 		sysfs_remove_group(p, &port->pkey_group);
- 		sysfs_remove_group(p, &port->gid_group);
--		kobject_unregister(p);
-+		kobject_put(p);
+ static inline void update_last_psn(struct ipath_qp *qp, u32 psn)
+ {
+-	if (qp->s_wait_credit) {
+-		qp->s_wait_credit = 0;
+-		tasklet_hi_schedule(&qp->s_task);
++	if (qp->s_last_psn != psn) {
++		qp->s_last_psn = psn;
++		if (qp->s_wait_credit) {
++			qp->s_wait_credit = 0;
++			tasklet_hi_schedule(&qp->s_task);
++		}
  	}
- 
--	kobject_unregister(&device->ports_parent);
-+	kobject_put(device->ports_parent);
- 	class_device_unregister(&device->class_dev);
+-	qp->s_last_psn = psn;
  }
  
-diff --git a/drivers/infiniband/core/ucm.c b/drivers/infiniband/core/ucm.c
-index 424983f..4291ab4 100644
---- a/drivers/infiniband/core/ucm.c
-+++ b/drivers/infiniband/core/ucm.c
-@@ -106,6 +106,9 @@ enum {
- 	IB_UCM_MAX_DEVICES = 32
- };
+ /**
+@@ -1653,13 +1656,6 @@ void ipath_rc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
+ 	case OP(SEND_FIRST):
+ 		if (!ipath_get_rwqe(qp, 0)) {
+ 		rnr_nak:
+-			/*
+-			 * A RNR NAK will ACK earlier sends and RDMA writes.
+-			 * Don't queue the NAK if a RDMA read or atomic
+-			 * is pending though.
+-			 */
+-			if (qp->r_nak_state)
+-				goto done;
+ 			qp->r_nak_state = IB_RNR_NAK | qp->r_min_rnr_timer;
+ 			qp->r_ack_psn = qp->r_psn;
+ 			goto send_ack;
+diff --git a/drivers/infiniband/hw/ipath/ipath_registers.h b/drivers/infiniband/hw/ipath/ipath_registers.h
+index 708eba3..6d2a17f 100644
+--- a/drivers/infiniband/hw/ipath/ipath_registers.h
++++ b/drivers/infiniband/hw/ipath/ipath_registers.h
+@@ -82,8 +82,7 @@
  
-+/* ib_cm and ib_user_cm modules share /sys/class/infiniband_cm */
-+extern struct class cm_class;
-+
- #define IB_UCM_BASE_DEV MKDEV(IB_UCM_MAJOR, IB_UCM_BASE_MINOR)
+ /* kr_rcvctrl bits */
+ #define INFINIPATH_R_PORTENABLE_SHIFT 0
+-#define INFINIPATH_R_INTRAVAIL_SHIFT 16
+-#define INFINIPATH_R_TAILUPD   0x80000000
++#define INFINIPATH_R_QPMAP_ENABLE (1ULL << 38)
  
- static void ib_ucm_add_one(struct ib_device *device);
-@@ -1199,7 +1202,7 @@ static int ib_ucm_close(struct inode *inode, struct file *filp)
- 	return 0;
- }
+ /* kr_intstatus, kr_intclear, kr_intmask bits */
+ #define INFINIPATH_I_RCVURG_SHIFT 0
+@@ -272,20 +271,6 @@
+ #define INFINIPATH_EXTC_LEDGBLOK_ON          0x00000002ULL
+ #define INFINIPATH_EXTC_LEDGBLERR_OFF        0x00000001ULL
  
--static void ib_ucm_release_class_dev(struct class_device *class_dev)
-+static void ucm_release_class_dev(struct class_device *class_dev)
- {
- 	struct ib_ucm_device *dev;
+-/* kr_mdio bits */
+-#define INFINIPATH_MDIO_CLKDIV_MASK 0x7FULL
+-#define INFINIPATH_MDIO_CLKDIV_SHIFT 32
+-#define INFINIPATH_MDIO_COMMAND_MASK 0x7ULL
+-#define INFINIPATH_MDIO_COMMAND_SHIFT 26
+-#define INFINIPATH_MDIO_DEVADDR_MASK 0x1FULL
+-#define INFINIPATH_MDIO_DEVADDR_SHIFT 21
+-#define INFINIPATH_MDIO_REGADDR_MASK 0x1FULL
+-#define INFINIPATH_MDIO_REGADDR_SHIFT 16
+-#define INFINIPATH_MDIO_DATA_MASK 0xFFFFULL
+-#define INFINIPATH_MDIO_DATA_SHIFT 0
+-#define INFINIPATH_MDIO_CMDVALID    0x0000000040000000ULL
+-#define INFINIPATH_MDIO_RDDATAVALID 0x0000000080000000ULL
+-
+ /* kr_partitionkey bits */
+ #define INFINIPATH_PKEY_SIZE 16
+ #define INFINIPATH_PKEY_MASK 0xFFFF
+@@ -303,8 +288,6 @@
  
-@@ -1217,11 +1220,6 @@ static const struct file_operations ucm_fops = {
- 	.poll    = ib_ucm_poll,
+ /* kr_xgxsconfig bits */
+ #define INFINIPATH_XGXS_RESET          0x7ULL
+-#define INFINIPATH_XGXS_MDIOADDR_MASK  0xfULL
+-#define INFINIPATH_XGXS_MDIOADDR_SHIFT 4
+ #define INFINIPATH_XGXS_RX_POL_SHIFT 19
+ #define INFINIPATH_XGXS_RX_POL_MASK 0xfULL
+ 
+@@ -470,6 +453,20 @@ struct ipath_cregs {
+ 	ipath_creg cr_unsupvlcnt;
+ 	ipath_creg cr_wordrcvcnt;
+ 	ipath_creg cr_wordsendcnt;
++	ipath_creg cr_vl15droppedpktcnt;
++	ipath_creg cr_rxotherlocalphyerrcnt;
++	ipath_creg cr_excessbufferovflcnt;
++	ipath_creg cr_locallinkintegrityerrcnt;
++	ipath_creg cr_rxvlerrcnt;
++	ipath_creg cr_rxdlidfltrcnt;
++	ipath_creg cr_psstat;
++	ipath_creg cr_psstart;
++	ipath_creg cr_psinterval;
++	ipath_creg cr_psrcvdatacount;
++	ipath_creg cr_psrcvpktscount;
++	ipath_creg cr_psxmitdatacount;
++	ipath_creg cr_psxmitpktscount;
++	ipath_creg cr_psxmitwaitcount;
  };
  
--static struct class ucm_class = {
--	.name    = "infiniband_cm",
--	.release = ib_ucm_release_class_dev
--};
--
- static ssize_t show_ibdev(struct class_device *class_dev, char *buf)
+ #endif				/* _IPATH_REGISTERS_H */
+diff --git a/drivers/infiniband/hw/ipath/ipath_ruc.c b/drivers/infiniband/hw/ipath/ipath_ruc.c
+index 54c61a9..a59bdbd 100644
+--- a/drivers/infiniband/hw/ipath/ipath_ruc.c
++++ b/drivers/infiniband/hw/ipath/ipath_ruc.c
+@@ -98,11 +98,15 @@ void ipath_insert_rnr_queue(struct ipath_qp *qp)
+ 		while (qp->s_rnr_timeout >= nqp->s_rnr_timeout) {
+ 			qp->s_rnr_timeout -= nqp->s_rnr_timeout;
+ 			l = l->next;
+-			if (l->next == &dev->rnrwait)
++			if (l->next == &dev->rnrwait) {
++				nqp = NULL;
+ 				break;
++			}
+ 			nqp = list_entry(l->next, struct ipath_qp,
+ 					 timerwait);
+ 		}
++		if (nqp)
++			nqp->s_rnr_timeout -= qp->s_rnr_timeout;
+ 		list_add(&qp->timerwait, l);
+ 	}
+ 	spin_unlock_irqrestore(&dev->pending_lock, flags);
+@@ -479,9 +483,14 @@ done:
+ 
+ static void want_buffer(struct ipath_devdata *dd)
  {
- 	struct ib_ucm_device *dev;
-@@ -1257,9 +1255,10 @@ static void ib_ucm_add_one(struct ib_device *device)
- 	if (cdev_add(&ucm_dev->dev, IB_UCM_BASE_DEV + ucm_dev->devnum, 1))
- 		goto err;
+-	set_bit(IPATH_S_PIOINTBUFAVAIL, &dd->ipath_sendctrl);
++	unsigned long flags;
++
++	spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags);
++	dd->ipath_sendctrl |= INFINIPATH_S_PIOINTBUFAVAIL;
+ 	ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
+ 			 dd->ipath_sendctrl);
++	ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
++	spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags);
+ }
  
--	ucm_dev->class_dev.class = &ucm_class;
-+	ucm_dev->class_dev.class = &cm_class;
- 	ucm_dev->class_dev.dev = device->dma_device;
- 	ucm_dev->class_dev.devt = ucm_dev->dev.dev;
-+	ucm_dev->class_dev.release = ucm_release_class_dev;
- 	snprintf(ucm_dev->class_dev.class_id, BUS_ID_SIZE, "ucm%d",
- 		 ucm_dev->devnum);
- 	if (class_device_register(&ucm_dev->class_dev))
-@@ -1306,40 +1305,34 @@ static int __init ib_ucm_init(void)
- 				     "infiniband_cm");
- 	if (ret) {
- 		printk(KERN_ERR "ucm: couldn't register device number\n");
--		goto err;
-+		goto error1;
- 	}
+ /**
+diff --git a/drivers/infiniband/hw/ipath/ipath_srq.c b/drivers/infiniband/hw/ipath/ipath_srq.c
+index 2fef36f..f772102 100644
+--- a/drivers/infiniband/hw/ipath/ipath_srq.c
++++ b/drivers/infiniband/hw/ipath/ipath_srq.c
+@@ -94,8 +94,8 @@ bail:
+ /**
+  * ipath_create_srq - create a shared receive queue
+  * @ibpd: the protection domain of the SRQ to create
+- * @attr: the attributes of the SRQ
+- * @udata: not used by the InfiniPath verbs driver
++ * @srq_init_attr: the attributes of the SRQ
++ * @udata: data from libipathverbs when creating a user SRQ
+  */
+ struct ib_srq *ipath_create_srq(struct ib_pd *ibpd,
+ 				struct ib_srq_init_attr *srq_init_attr,
+diff --git a/drivers/infiniband/hw/ipath/ipath_stats.c b/drivers/infiniband/hw/ipath/ipath_stats.c
+index f027141..d2725cd 100644
+--- a/drivers/infiniband/hw/ipath/ipath_stats.c
++++ b/drivers/infiniband/hw/ipath/ipath_stats.c
+@@ -133,15 +133,16 @@ bail:
+ static void ipath_qcheck(struct ipath_devdata *dd)
+ {
+ 	static u64 last_tot_hdrqfull;
++	struct ipath_portdata *pd = dd->ipath_pd[0];
+ 	size_t blen = 0;
+ 	char buf[128];
  
--	ret = class_register(&ucm_class);
--	if (ret) {
--		printk(KERN_ERR "ucm: couldn't create class infiniband_cm\n");
--		goto err_chrdev;
--	}
--
--	ret = class_create_file(&ucm_class, &class_attr_abi_version);
-+	ret = class_create_file(&cm_class, &class_attr_abi_version);
- 	if (ret) {
- 		printk(KERN_ERR "ucm: couldn't create abi_version attribute\n");
--		goto err_class;
-+		goto error2;
+ 	*buf = 0;
+-	if (dd->ipath_pd[0]->port_hdrqfull != dd->ipath_p0_hdrqfull) {
++	if (pd->port_hdrqfull != dd->ipath_p0_hdrqfull) {
+ 		blen = snprintf(buf, sizeof buf, "port 0 hdrqfull %u",
+-				dd->ipath_pd[0]->port_hdrqfull -
++				pd->port_hdrqfull -
+ 				dd->ipath_p0_hdrqfull);
+-		dd->ipath_p0_hdrqfull = dd->ipath_pd[0]->port_hdrqfull;
++		dd->ipath_p0_hdrqfull = pd->port_hdrqfull;
  	}
+ 	if (ipath_stats.sps_etidfull != dd->ipath_last_tidfull) {
+ 		blen += snprintf(buf + blen, sizeof buf - blen,
+@@ -173,7 +174,7 @@ static void ipath_qcheck(struct ipath_devdata *dd)
+ 	if (blen)
+ 		ipath_dbg("%s\n", buf);
  
- 	ret = ib_register_client(&ucm_client);
- 	if (ret) {
- 		printk(KERN_ERR "ucm: couldn't register client\n");
--		goto err_class;
-+		goto error3;
- 	}
- 	return 0;
+-	if (dd->ipath_port0head != (u32)
++	if (pd->port_head != (u32)
+ 	    le64_to_cpu(*dd->ipath_hdrqtailptr)) {
+ 		if (dd->ipath_lastport0rcv_cnt ==
+ 		    ipath_stats.sps_port0pkts) {
+@@ -181,7 +182,7 @@ static void ipath_qcheck(struct ipath_devdata *dd)
+ 				   "port0 hd=%llx tl=%x; port0pkts %llx\n",
+ 				   (unsigned long long)
+ 				   le64_to_cpu(*dd->ipath_hdrqtailptr),
+-				   dd->ipath_port0head,
++				   pd->port_head,
+ 				   (unsigned long long)
+ 				   ipath_stats.sps_port0pkts);
+ 		}
+@@ -237,7 +238,7 @@ static void ipath_chk_errormask(struct ipath_devdata *dd)
+ void ipath_get_faststats(unsigned long opaque)
+ {
+ 	struct ipath_devdata *dd = (struct ipath_devdata *) opaque;
+-	u32 val;
++	int i;
+ 	static unsigned cnt;
+ 	unsigned long flags;
+ 	u64 traffic_wds;
+@@ -321,12 +322,11 @@ void ipath_get_faststats(unsigned long opaque)
  
--err_class:
--	class_unregister(&ucm_class);
--err_chrdev:
-+error3:
-+	class_remove_file(&cm_class, &class_attr_abi_version);
-+error2:
- 	unregister_chrdev_region(IB_UCM_BASE_DEV, IB_UCM_MAX_DEVICES);
--err:
-+error1:
- 	return ret;
- }
+ 	/* limit qfull messages to ~one per minute per port */
+ 	if ((++cnt & 0x10)) {
+-		for (val = dd->ipath_cfgports - 1; ((int)val) >= 0;
+-		     val--) {
+-			if (dd->ipath_lastegrheads[val] != -1)
+-				dd->ipath_lastegrheads[val] = -1;
+-			if (dd->ipath_lastrcvhdrqtails[val] != -1)
+-				dd->ipath_lastrcvhdrqtails[val] = -1;
++		for (i = (int) dd->ipath_cfgports; --i >= 0; ) {
++			struct ipath_portdata *pd = dd->ipath_pd[i];
++
++			if (pd && pd->port_lastrcvhdrqtail != -1)
++				pd->port_lastrcvhdrqtail = -1;
+ 		}
+ 	}
  
- static void __exit ib_ucm_cleanup(void)
- {
- 	ib_unregister_client(&ucm_client);
--	class_unregister(&ucm_class);
-+	class_remove_file(&cm_class, &class_attr_abi_version);
- 	unregister_chrdev_region(IB_UCM_BASE_DEV, IB_UCM_MAX_DEVICES);
- 	idr_destroy(&ctx_id_table);
+diff --git a/drivers/infiniband/hw/ipath/ipath_sysfs.c b/drivers/infiniband/hw/ipath/ipath_sysfs.c
+index e1ad7cf..56dfc8a 100644
+--- a/drivers/infiniband/hw/ipath/ipath_sysfs.c
++++ b/drivers/infiniband/hw/ipath/ipath_sysfs.c
+@@ -363,6 +363,60 @@ static ssize_t show_unit(struct device *dev,
+ 	return scnprintf(buf, PAGE_SIZE, "%u\n", dd->ipath_unit);
  }
-diff --git a/drivers/infiniband/core/ucma.c b/drivers/infiniband/core/ucma.c
-index 90d675a..15937eb 100644
---- a/drivers/infiniband/core/ucma.c
-+++ b/drivers/infiniband/core/ucma.c
-@@ -31,6 +31,7 @@
-  */
  
- #include <linux/completion.h>
-+#include <linux/file.h>
- #include <linux/mutex.h>
- #include <linux/poll.h>
- #include <linux/idr.h>
-@@ -991,6 +992,96 @@ out:
- 	return ret;
++static ssize_t show_jint_max_packets(struct device *dev,
++				     struct device_attribute *attr,
++				     char *buf)
++{
++	struct ipath_devdata *dd = dev_get_drvdata(dev);
++
++	return scnprintf(buf, PAGE_SIZE, "%hu\n", dd->ipath_jint_max_packets);
++}
++
++static ssize_t store_jint_max_packets(struct device *dev,
++				      struct device_attribute *attr,
++				      const char *buf,
++				      size_t count)
++{
++	struct ipath_devdata *dd = dev_get_drvdata(dev);
++	u16 v = 0;
++	int ret;
++
++	ret = ipath_parse_ushort(buf, &v);
++	if (ret < 0)
++		ipath_dev_err(dd, "invalid jint_max_packets.\n");
++	else
++		dd->ipath_f_config_jint(dd, dd->ipath_jint_idle_ticks, v);
++
++	return ret;
++}
++
++static ssize_t show_jint_idle_ticks(struct device *dev,
++				    struct device_attribute *attr,
++				    char *buf)
++{
++	struct ipath_devdata *dd = dev_get_drvdata(dev);
++
++	return scnprintf(buf, PAGE_SIZE, "%hu\n", dd->ipath_jint_idle_ticks);
++}
++
++static ssize_t store_jint_idle_ticks(struct device *dev,
++				     struct device_attribute *attr,
++				     const char *buf,
++				     size_t count)
++{
++	struct ipath_devdata *dd = dev_get_drvdata(dev);
++	u16 v = 0;
++	int ret;
++
++	ret = ipath_parse_ushort(buf, &v);
++	if (ret < 0)
++		ipath_dev_err(dd, "invalid jint_idle_ticks.\n");
++	else
++		dd->ipath_f_config_jint(dd, v, dd->ipath_jint_max_packets);
++
++	return ret;
++}
++
+ #define DEVICE_COUNTER(name, attr) \
+ 	static ssize_t show_counter_##name(struct device *dev, \
+ 					   struct device_attribute *attr, \
+@@ -670,6 +724,257 @@ static ssize_t show_logged_errs(struct device *dev,
+ 	return count;
  }
  
-+static void ucma_lock_files(struct ucma_file *file1, struct ucma_file *file2)
++/*
++ * New sysfs entries to control various IB config. These all turn into
++ * accesses via ipath_f_get/set_ib_cfg.
++ *
++ * Get/Set heartbeat enable. Or of 1=enabled, 2=auto
++ */
++static ssize_t show_hrtbt_enb(struct device *dev,
++			 struct device_attribute *attr,
++			 char *buf)
 +{
-+	/* Acquire mutex's based on pointer comparison to prevent deadlock. */
-+	if (file1 < file2) {
-+		mutex_lock(&file1->mut);
-+		mutex_lock(&file2->mut);
-+	} else {
-+		mutex_lock(&file2->mut);
-+		mutex_lock(&file1->mut);
++	struct ipath_devdata *dd = dev_get_drvdata(dev);
++	int ret;
++
++	ret = dd->ipath_f_get_ib_cfg(dd, IPATH_IB_CFG_HRTBT);
++	if (ret >= 0)
++		ret = scnprintf(buf, PAGE_SIZE, "%d\n", ret);
++	return ret;
++}
++
++static ssize_t store_hrtbt_enb(struct device *dev,
++			  struct device_attribute *attr,
++			  const char *buf,
++			  size_t count)
++{
++	struct ipath_devdata *dd = dev_get_drvdata(dev);
++	int ret, r;
++	u16 val;
++
++	ret = ipath_parse_ushort(buf, &val);
++	if (ret >= 0 && val > 3)
++		ret = -EINVAL;
++	if (ret < 0) {
++		ipath_dev_err(dd, "attempt to set invalid Heartbeat enable\n");
++		goto bail;
 +	}
++
++	/*
++	 * Set the "intentional" heartbeat enable per either of
++	 * "Enable" and "Auto", as these are normally set together.
++	 * This bit is consulted when leaving loopback mode,
++	 * because entering loopback mode overrides it and automatically
++	 * disables heartbeat.
++	 */
++	r = dd->ipath_f_set_ib_cfg(dd, IPATH_IB_CFG_HRTBT, val);
++	if (r < 0)
++		ret = r;
++	else if (val == IPATH_IB_HRTBT_OFF)
++		dd->ipath_flags |= IPATH_NO_HRTBT;
++	else
++		dd->ipath_flags &= ~IPATH_NO_HRTBT;
++
++bail:
++	return ret;
 +}
 +
-+static void ucma_unlock_files(struct ucma_file *file1, struct ucma_file *file2)
++/*
++ * Get/Set Link-widths enabled. Or of 1=1x, 2=4x (this is human/IB centric,
++ * _not_ the particular encoding of any given chip)
++ */
++static ssize_t show_lwid_enb(struct device *dev,
++			 struct device_attribute *attr,
++			 char *buf)
 +{
-+	if (file1 < file2) {
-+		mutex_unlock(&file2->mut);
-+		mutex_unlock(&file1->mut);
-+	} else {
-+		mutex_unlock(&file1->mut);
-+		mutex_unlock(&file2->mut);
++	struct ipath_devdata *dd = dev_get_drvdata(dev);
++	int ret;
++
++	ret = dd->ipath_f_get_ib_cfg(dd, IPATH_IB_CFG_LWID_ENB);
++	if (ret >= 0)
++		ret = scnprintf(buf, PAGE_SIZE, "%d\n", ret);
++	return ret;
++}
++
++static ssize_t store_lwid_enb(struct device *dev,
++			  struct device_attribute *attr,
++			  const char *buf,
++			  size_t count)
++{
++	struct ipath_devdata *dd = dev_get_drvdata(dev);
++	int ret, r;
++	u16 val;
++
++	ret = ipath_parse_ushort(buf, &val);
++	if (ret >= 0 && (val == 0 || val > 3))
++		ret = -EINVAL;
++	if (ret < 0) {
++		ipath_dev_err(dd,
++			"attempt to set invalid Link Width (enable)\n");
++		goto bail;
 +	}
++
++	r = dd->ipath_f_set_ib_cfg(dd, IPATH_IB_CFG_LWID_ENB, val);
++	if (r < 0)
++		ret = r;
++
++bail:
++	return ret;
 +}
 +
-+static void ucma_move_events(struct ucma_context *ctx, struct ucma_file *file)
++/* Get current link width */
++static ssize_t show_lwid(struct device *dev,
++			 struct device_attribute *attr,
++			 char *buf)
++
 +{
-+	struct ucma_event *uevent, *tmp;
++	struct ipath_devdata *dd = dev_get_drvdata(dev);
++	int ret;
 +
-+	list_for_each_entry_safe(uevent, tmp, &ctx->file->event_list, list)
-+		if (uevent->ctx == ctx)
-+			list_move_tail(&uevent->list, &file->event_list);
++	ret = dd->ipath_f_get_ib_cfg(dd, IPATH_IB_CFG_LWID);
++	if (ret >= 0)
++		ret = scnprintf(buf, PAGE_SIZE, "%d\n", ret);
++	return ret;
 +}
 +
-+static ssize_t ucma_migrate_id(struct ucma_file *new_file,
-+			       const char __user *inbuf,
-+			       int in_len, int out_len)
++/*
++ * Get/Set Link-speeds enabled. Or of 1=SDR 2=DDR.
++ */
++static ssize_t show_spd_enb(struct device *dev,
++			 struct device_attribute *attr,
++			 char *buf)
 +{
-+	struct rdma_ucm_migrate_id cmd;
-+	struct rdma_ucm_migrate_resp resp;
-+	struct ucma_context *ctx;
-+	struct file *filp;
-+	struct ucma_file *cur_file;
-+	int ret = 0;
++	struct ipath_devdata *dd = dev_get_drvdata(dev);
++	int ret;
 +
-+	if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
-+		return -EFAULT;
++	ret = dd->ipath_f_get_ib_cfg(dd, IPATH_IB_CFG_SPD_ENB);
++	if (ret >= 0)
++		ret = scnprintf(buf, PAGE_SIZE, "%d\n", ret);
++	return ret;
++}
 +
-+	/* Get current fd to protect against it being closed */
-+	filp = fget(cmd.fd);
-+	if (!filp)
-+		return -ENOENT;
++static ssize_t store_spd_enb(struct device *dev,
++			  struct device_attribute *attr,
++			  const char *buf,
++			  size_t count)
++{
++	struct ipath_devdata *dd = dev_get_drvdata(dev);
++	int ret, r;
++	u16 val;
 +
-+	/* Validate current fd and prevent destruction of id. */
-+	ctx = ucma_get_ctx(filp->private_data, cmd.id);
-+	if (IS_ERR(ctx)) {
-+		ret = PTR_ERR(ctx);
-+		goto file_put;
++	ret = ipath_parse_ushort(buf, &val);
++	if (ret >= 0 && (val == 0 || val > (IPATH_IB_SDR | IPATH_IB_DDR)))
++		ret = -EINVAL;
++	if (ret < 0) {
++		ipath_dev_err(dd,
++			"attempt to set invalid Link Speed (enable)\n");
++		goto bail;
 +	}
 +
-+	cur_file = ctx->file;
-+	if (cur_file == new_file) {
-+		resp.events_reported = ctx->events_reported;
-+		goto response;
-+	}
++	r = dd->ipath_f_set_ib_cfg(dd, IPATH_IB_CFG_SPD_ENB, val);
++	if (r < 0)
++		ret = r;
 +
-+	/*
-+	 * Migrate events between fd's, maintaining order, and avoiding new
-+	 * events being added before existing events.
-+	 */
-+	ucma_lock_files(cur_file, new_file);
-+	mutex_lock(&mut);
++bail:
++	return ret;
++}
 +
-+	list_move_tail(&ctx->list, &new_file->ctx_list);
-+	ucma_move_events(ctx, new_file);
-+	ctx->file = new_file;
-+	resp.events_reported = ctx->events_reported;
++/* Get current link speed */
++static ssize_t show_spd(struct device *dev,
++			 struct device_attribute *attr,
++			 char *buf)
++{
++	struct ipath_devdata *dd = dev_get_drvdata(dev);
++	int ret;
 +
-+	mutex_unlock(&mut);
-+	ucma_unlock_files(cur_file, new_file);
++	ret = dd->ipath_f_get_ib_cfg(dd, IPATH_IB_CFG_SPD);
++	if (ret >= 0)
++		ret = scnprintf(buf, PAGE_SIZE, "%d\n", ret);
++	return ret;
++}
 +
-+response:
-+	if (copy_to_user((void __user *)(unsigned long)cmd.response,
-+			 &resp, sizeof(resp)))
-+		ret = -EFAULT;
++/*
++ * Get/Set RX polarity-invert enable. 0=no, 1=yes.
++ */
++static ssize_t show_rx_polinv_enb(struct device *dev,
++			 struct device_attribute *attr,
++			 char *buf)
++{
++	struct ipath_devdata *dd = dev_get_drvdata(dev);
++	int ret;
 +
-+	ucma_put_ctx(ctx);
-+file_put:
-+	fput(filp);
++	ret = dd->ipath_f_get_ib_cfg(dd, IPATH_IB_CFG_RXPOL_ENB);
++	if (ret >= 0)
++		ret = scnprintf(buf, PAGE_SIZE, "%d\n", ret);
 +	return ret;
 +}
 +
- static ssize_t (*ucma_cmd_table[])(struct ucma_file *file,
- 				   const char __user *inbuf,
- 				   int in_len, int out_len) = {
-@@ -1012,6 +1103,7 @@ static ssize_t (*ucma_cmd_table[])(struct ucma_file *file,
- 	[RDMA_USER_CM_CMD_NOTIFY]	= ucma_notify,
- 	[RDMA_USER_CM_CMD_JOIN_MCAST]	= ucma_join_multicast,
- 	[RDMA_USER_CM_CMD_LEAVE_MCAST]	= ucma_leave_multicast,
-+	[RDMA_USER_CM_CMD_MIGRATE_ID]	= ucma_migrate_id
- };
- 
- static ssize_t ucma_write(struct file *filp, const char __user *buf,
-diff --git a/drivers/infiniband/core/user_mad.c b/drivers/infiniband/core/user_mad.c
-index b53eac4..4e91510 100644
---- a/drivers/infiniband/core/user_mad.c
-+++ b/drivers/infiniband/core/user_mad.c
-@@ -2,6 +2,7 @@
-  * Copyright (c) 2004 Topspin Communications.  All rights reserved.
-  * Copyright (c) 2005 Voltaire, Inc. All rights reserved.
-  * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
-+ * Copyright (c) 2008 Cisco. 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
-@@ -42,7 +43,7 @@
- #include <linux/cdev.h>
- #include <linux/dma-mapping.h>
- #include <linux/poll.h>
--#include <linux/rwsem.h>
-+#include <linux/mutex.h>
- #include <linux/kref.h>
- #include <linux/compat.h>
- 
-@@ -94,7 +95,7 @@ struct ib_umad_port {
- 	struct class_device   *sm_class_dev;
- 	struct semaphore       sm_sem;
- 
--	struct rw_semaphore    mutex;
-+	struct mutex	       file_mutex;
- 	struct list_head       file_list;
- 
- 	struct ib_device      *ib_dev;
-@@ -110,11 +111,11 @@ struct ib_umad_device {
- };
- 
- struct ib_umad_file {
-+	struct mutex		mutex;
- 	struct ib_umad_port    *port;
- 	struct list_head	recv_list;
- 	struct list_head	send_list;
- 	struct list_head	port_list;
--	spinlock_t		recv_lock;
- 	spinlock_t		send_lock;
- 	wait_queue_head_t	recv_wait;
- 	struct ib_mad_agent    *agent[IB_UMAD_MAX_AGENTS];
-@@ -156,7 +157,7 @@ static int hdr_size(struct ib_umad_file *file)
- 		sizeof (struct ib_user_mad_hdr_old);
- }
- 
--/* caller must hold port->mutex at least for reading */
-+/* caller must hold file->mutex */
- static struct ib_mad_agent *__get_agent(struct ib_umad_file *file, int id)
- {
- 	return file->agents_dead ? NULL : file->agent[id];
-@@ -168,32 +169,30 @@ static int queue_packet(struct ib_umad_file *file,
- {
- 	int ret = 1;
- 
--	down_read(&file->port->mutex);
-+	mutex_lock(&file->mutex);
- 
- 	for (packet->mad.hdr.id = 0;
- 	     packet->mad.hdr.id < IB_UMAD_MAX_AGENTS;
- 	     packet->mad.hdr.id++)
- 		if (agent == __get_agent(file, packet->mad.hdr.id)) {
--			spin_lock_irq(&file->recv_lock);
- 			list_add_tail(&packet->list, &file->recv_list);
--			spin_unlock_irq(&file->recv_lock);
- 			wake_up_interruptible(&file->recv_wait);
- 			ret = 0;
- 			break;
- 		}
- 
--	up_read(&file->port->mutex);
-+	mutex_unlock(&file->mutex);
- 
- 	return ret;
- }
- 
- static void dequeue_send(struct ib_umad_file *file,
- 			 struct ib_umad_packet *packet)
-- {
++static ssize_t store_rx_polinv_enb(struct device *dev,
++			  struct device_attribute *attr,
++			  const char *buf,
++			  size_t count)
 +{
- 	spin_lock_irq(&file->send_lock);
- 	list_del(&packet->list);
- 	spin_unlock_irq(&file->send_lock);
-- }
++	struct ipath_devdata *dd = dev_get_drvdata(dev);
++	int ret, r;
++	u16 val;
++
++	ret = ipath_parse_ushort(buf, &val);
++	if (ret < 0 || val > 1)
++		goto invalid;
++
++	r = dd->ipath_f_set_ib_cfg(dd, IPATH_IB_CFG_RXPOL_ENB, val);
++	if (r < 0) {
++		ret = r;
++		goto bail;
++	}
++
++	goto bail;
++invalid:
++	ipath_dev_err(dd, "attempt to set invalid Rx Polarity (enable)\n");
++bail:
++	return ret;
 +}
++/*
++ * Get/Set RX lane-reversal enable. 0=no, 1=yes.
++ */
++static ssize_t show_lanerev_enb(struct device *dev,
++			 struct device_attribute *attr,
++			 char *buf)
++{
++	struct ipath_devdata *dd = dev_get_drvdata(dev);
++	int ret;
++
++	ret = dd->ipath_f_get_ib_cfg(dd, IPATH_IB_CFG_LREV_ENB);
++	if (ret >= 0)
++		ret = scnprintf(buf, PAGE_SIZE, "%d\n", ret);
++	return ret;
++}
++
++static ssize_t store_lanerev_enb(struct device *dev,
++			  struct device_attribute *attr,
++			  const char *buf,
++			  size_t count)
++{
++	struct ipath_devdata *dd = dev_get_drvdata(dev);
++	int ret, r;
++	u16 val;
++
++	ret = ipath_parse_ushort(buf, &val);
++	if (ret >= 0 && val > 1) {
++		ret = -EINVAL;
++		ipath_dev_err(dd,
++			"attempt to set invalid Lane reversal (enable)\n");
++		goto bail;
++	}
++
++	r = dd->ipath_f_set_ib_cfg(dd, IPATH_IB_CFG_LREV_ENB, val);
++	if (r < 0)
++		ret = r;
++
++bail:
++	return ret;
++}
++
+ static DRIVER_ATTR(num_units, S_IRUGO, show_num_units, NULL);
+ static DRIVER_ATTR(version, S_IRUGO, show_version, NULL);
  
- static void send_handler(struct ib_mad_agent *agent,
- 			 struct ib_mad_send_wc *send_wc)
-@@ -341,10 +340,10 @@ static ssize_t ib_umad_read(struct file *filp, char __user *buf,
- 	if (count < hdr_size(file))
- 		return -EINVAL;
- 
--	spin_lock_irq(&file->recv_lock);
-+	mutex_lock(&file->mutex);
- 
- 	while (list_empty(&file->recv_list)) {
--		spin_unlock_irq(&file->recv_lock);
-+		mutex_unlock(&file->mutex);
- 
- 		if (filp->f_flags & O_NONBLOCK)
- 			return -EAGAIN;
-@@ -353,13 +352,13 @@ static ssize_t ib_umad_read(struct file *filp, char __user *buf,
- 					     !list_empty(&file->recv_list)))
- 			return -ERESTARTSYS;
- 
--		spin_lock_irq(&file->recv_lock);
-+		mutex_lock(&file->mutex);
- 	}
- 
- 	packet = list_entry(file->recv_list.next, struct ib_umad_packet, list);
- 	list_del(&packet->list);
- 
--	spin_unlock_irq(&file->recv_lock);
-+	mutex_unlock(&file->mutex);
- 
- 	if (packet->recv_wc)
- 		ret = copy_recv_mad(file, buf, packet, count);
-@@ -368,9 +367,9 @@ static ssize_t ib_umad_read(struct file *filp, char __user *buf,
- 
- 	if (ret < 0) {
- 		/* Requeue packet */
--		spin_lock_irq(&file->recv_lock);
-+		mutex_lock(&file->mutex);
- 		list_add(&packet->list, &file->recv_list);
--		spin_unlock_irq(&file->recv_lock);
-+		mutex_unlock(&file->mutex);
- 	} else {
- 		if (packet->recv_wc)
- 			ib_free_recv_mad(packet->recv_wc);
-@@ -481,7 +480,7 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf,
- 		goto err;
- 	}
- 
--	down_read(&file->port->mutex);
-+	mutex_lock(&file->mutex);
- 
- 	agent = __get_agent(file, packet->mad.hdr.id);
- 	if (!agent) {
-@@ -577,7 +576,7 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf,
- 	if (ret)
- 		goto err_send;
- 
--	up_read(&file->port->mutex);
-+	mutex_unlock(&file->mutex);
- 	return count;
- 
- err_send:
-@@ -587,7 +586,7 @@ err_msg:
- err_ah:
- 	ib_destroy_ah(ah);
- err_up:
--	up_read(&file->port->mutex);
-+	mutex_unlock(&file->mutex);
- err:
- 	kfree(packet);
- 	return ret;
-@@ -613,11 +612,12 @@ static int ib_umad_reg_agent(struct ib_umad_file *file, void __user *arg,
- {
- 	struct ib_user_mad_reg_req ureq;
- 	struct ib_mad_reg_req req;
--	struct ib_mad_agent *agent;
-+	struct ib_mad_agent *agent = NULL;
- 	int agent_id;
- 	int ret;
- 
--	down_write(&file->port->mutex);
-+	mutex_lock(&file->port->file_mutex);
-+	mutex_lock(&file->mutex);
- 
- 	if (!file->port->ib_dev) {
- 		ret = -EPIPE;
-@@ -666,13 +666,13 @@ found:
- 				      send_handler, recv_handler, file);
- 	if (IS_ERR(agent)) {
- 		ret = PTR_ERR(agent);
-+		agent = NULL;
- 		goto out;
- 	}
- 
- 	if (put_user(agent_id,
- 		     (u32 __user *) (arg + offsetof(struct ib_user_mad_reg_req, id)))) {
- 		ret = -EFAULT;
--		ib_unregister_mad_agent(agent);
- 		goto out;
- 	}
+@@ -683,6 +988,11 @@ static struct attribute_group driver_attr_group = {
+ 	.attrs = driver_attributes
+ };
  
-@@ -690,7 +690,13 @@ found:
- 	ret = 0;
++struct attribute_group *ipath_driver_attr_groups[] = {
++	&driver_attr_group,
++	NULL,
++};
++
+ static DEVICE_ATTR(guid, S_IWUSR | S_IRUGO, show_guid, store_guid);
+ static DEVICE_ATTR(lmc, S_IWUSR | S_IRUGO, show_lmc, store_lmc);
+ static DEVICE_ATTR(lid, S_IWUSR | S_IRUGO, show_lid, store_lid);
+@@ -701,6 +1011,10 @@ static DEVICE_ATTR(unit, S_IRUGO, show_unit, NULL);
+ static DEVICE_ATTR(rx_pol_inv, S_IWUSR, NULL, store_rx_pol_inv);
+ static DEVICE_ATTR(led_override, S_IWUSR, NULL, store_led_override);
+ static DEVICE_ATTR(logged_errors, S_IRUGO, show_logged_errs, NULL);
++static DEVICE_ATTR(jint_max_packets, S_IWUSR | S_IRUGO,
++		   show_jint_max_packets, store_jint_max_packets);
++static DEVICE_ATTR(jint_idle_ticks, S_IWUSR | S_IRUGO,
++		   show_jint_idle_ticks, store_jint_idle_ticks);
  
- out:
--	up_write(&file->port->mutex);
-+	mutex_unlock(&file->mutex);
+ static struct attribute *dev_attributes[] = {
+ 	&dev_attr_guid.attr,
+@@ -727,6 +1041,34 @@ static struct attribute_group dev_attr_group = {
+ 	.attrs = dev_attributes
+ };
+ 
++static DEVICE_ATTR(hrtbt_enable, S_IWUSR | S_IRUGO, show_hrtbt_enb,
++		   store_hrtbt_enb);
++static DEVICE_ATTR(link_width_enable, S_IWUSR | S_IRUGO, show_lwid_enb,
++		   store_lwid_enb);
++static DEVICE_ATTR(link_width, S_IRUGO, show_lwid, NULL);
++static DEVICE_ATTR(link_speed_enable, S_IWUSR | S_IRUGO, show_spd_enb,
++		   store_spd_enb);
++static DEVICE_ATTR(link_speed, S_IRUGO, show_spd, NULL);
++static DEVICE_ATTR(rx_pol_inv_enable, S_IWUSR | S_IRUGO, show_rx_polinv_enb,
++		   store_rx_polinv_enb);
++static DEVICE_ATTR(rx_lane_rev_enable, S_IWUSR | S_IRUGO, show_lanerev_enb,
++		   store_lanerev_enb);
 +
-+	if (ret && agent)
-+		ib_unregister_mad_agent(agent);
++static struct attribute *dev_ibcfg_attributes[] = {
++	&dev_attr_hrtbt_enable.attr,
++	&dev_attr_link_width_enable.attr,
++	&dev_attr_link_width.attr,
++	&dev_attr_link_speed_enable.attr,
++	&dev_attr_link_speed.attr,
++	&dev_attr_rx_pol_inv_enable.attr,
++	&dev_attr_rx_lane_rev_enable.attr,
++	NULL
++};
 +
-+	mutex_unlock(&file->port->file_mutex);
++static struct attribute_group dev_ibcfg_attr_group = {
++	.attrs = dev_ibcfg_attributes
++};
 +
+ /**
+  * ipath_expose_reset - create a device reset file
+  * @dev: the device structure
+@@ -753,24 +1095,9 @@ int ipath_expose_reset(struct device *dev)
  	return ret;
  }
  
-@@ -703,7 +709,8 @@ static int ib_umad_unreg_agent(struct ib_umad_file *file, u32 __user *arg)
- 	if (get_user(id, arg))
- 		return -EFAULT;
- 
--	down_write(&file->port->mutex);
-+	mutex_lock(&file->port->file_mutex);
-+	mutex_lock(&file->mutex);
- 
- 	if (id < 0 || id >= IB_UMAD_MAX_AGENTS || !__get_agent(file, id)) {
- 		ret = -EINVAL;
-@@ -714,11 +721,13 @@ static int ib_umad_unreg_agent(struct ib_umad_file *file, u32 __user *arg)
- 	file->agent[id] = NULL;
+-int ipath_driver_create_group(struct device_driver *drv)
+-{
+-	int ret;
+-
+-	ret = sysfs_create_group(&drv->kobj, &driver_attr_group);
+-
+-	return ret;
+-}
+-
+-void ipath_driver_remove_group(struct device_driver *drv)
+-{
+-	sysfs_remove_group(&drv->kobj, &driver_attr_group);
+-}
+-
+ int ipath_device_create_group(struct device *dev, struct ipath_devdata *dd)
+ {
+ 	int ret;
+-	char unit[5];
  
- out:
--	up_write(&file->port->mutex);
-+	mutex_unlock(&file->mutex);
+ 	ret = sysfs_create_group(&dev->kobj, &dev_attr_group);
+ 	if (ret)
+@@ -780,11 +1107,26 @@ int ipath_device_create_group(struct device *dev, struct ipath_devdata *dd)
+ 	if (ret)
+ 		goto bail_attrs;
  
- 	if (agent)
- 		ib_unregister_mad_agent(agent);
+-	snprintf(unit, sizeof(unit), "%02d", dd->ipath_unit);
+-	ret = sysfs_create_link(&dev->driver->kobj, &dev->kobj, unit);
+-	if (ret == 0)
+-		goto bail;
++	if (dd->ipath_flags & IPATH_HAS_MULT_IB_SPEED) {
++		ret = device_create_file(dev, &dev_attr_jint_idle_ticks);
++		if (ret)
++			goto bail_counter;
++		ret = device_create_file(dev, &dev_attr_jint_max_packets);
++		if (ret)
++			goto bail_idle;
  
-+	mutex_unlock(&file->port->file_mutex);
++		ret = sysfs_create_group(&dev->kobj, &dev_ibcfg_attr_group);
++		if (ret)
++			goto bail_max;
++	}
 +
- 	return ret;
- }
++	return 0;
++
++bail_max:
++	device_remove_file(dev, &dev_attr_jint_max_packets);
++bail_idle:
++	device_remove_file(dev, &dev_attr_jint_idle_ticks);
++bail_counter:
+ 	sysfs_remove_group(&dev->kobj, &dev_counter_attr_group);
+ bail_attrs:
+ 	sysfs_remove_group(&dev->kobj, &dev_attr_group);
+@@ -794,12 +1136,14 @@ bail:
  
-@@ -726,12 +735,12 @@ static long ib_umad_enable_pkey(struct ib_umad_file *file)
+ void ipath_device_remove_group(struct device *dev, struct ipath_devdata *dd)
  {
- 	int ret = 0;
+-	char unit[5];
++	sysfs_remove_group(&dev->kobj, &dev_counter_attr_group);
  
--	down_write(&file->port->mutex);
-+	mutex_lock(&file->mutex);
- 	if (file->already_used)
- 		ret = -EINVAL;
- 	else
- 		file->use_pkey_index = 1;
--	up_write(&file->port->mutex);
-+	mutex_unlock(&file->mutex);
+-	snprintf(unit, sizeof(unit), "%02d", dd->ipath_unit);
+-	sysfs_remove_link(&dev->driver->kobj, unit);
++	if (dd->ipath_flags & IPATH_HAS_MULT_IB_SPEED) {
++		sysfs_remove_group(&dev->kobj, &dev_ibcfg_attr_group);
++		device_remove_file(dev, &dev_attr_jint_idle_ticks);
++		device_remove_file(dev, &dev_attr_jint_max_packets);
++	}
  
- 	return ret;
- }
-@@ -783,7 +792,7 @@ static int ib_umad_open(struct inode *inode, struct file *filp)
- 	if (!port)
- 		return -ENXIO;
+-	sysfs_remove_group(&dev->kobj, &dev_counter_attr_group);
+ 	sysfs_remove_group(&dev->kobj, &dev_attr_group);
  
--	down_write(&port->mutex);
-+	mutex_lock(&port->file_mutex);
+ 	device_remove_file(dev, &dev_attr_reset);
+diff --git a/drivers/infiniband/hw/ipath/ipath_ud.c b/drivers/infiniband/hw/ipath/ipath_ud.c
+index b3df6f3..de67eed 100644
+--- a/drivers/infiniband/hw/ipath/ipath_ud.c
++++ b/drivers/infiniband/hw/ipath/ipath_ud.c
+@@ -301,8 +301,6 @@ int ipath_make_ud_req(struct ipath_qp *qp)
  
- 	if (!port->ib_dev) {
- 		ret = -ENXIO;
-@@ -797,7 +806,7 @@ static int ib_umad_open(struct inode *inode, struct file *filp)
- 		goto out;
+ 	/* header size in 32-bit words LRH+BTH+DETH = (8+12+8)/4. */
+ 	qp->s_hdrwords = 7;
+-	if (wqe->wr.opcode == IB_WR_SEND_WITH_IMM)
+-		qp->s_hdrwords++;
+ 	qp->s_cur_size = wqe->length;
+ 	qp->s_cur_sge = &qp->s_sge;
+ 	qp->s_wqe = wqe;
+@@ -327,6 +325,7 @@ int ipath_make_ud_req(struct ipath_qp *qp)
+ 		ohdr = &qp->s_hdr.u.oth;
  	}
+ 	if (wqe->wr.opcode == IB_WR_SEND_WITH_IMM) {
++		qp->s_hdrwords++;
+ 		ohdr->u.ud.imm_data = wqe->wr.imm_data;
+ 		bth0 = IB_OPCODE_UD_SEND_ONLY_WITH_IMMEDIATE << 24;
+ 	} else
+diff --git a/drivers/infiniband/hw/ipath/ipath_verbs.c b/drivers/infiniband/hw/ipath/ipath_verbs.c
+index c4c9984..32d8f88 100644
+--- a/drivers/infiniband/hw/ipath/ipath_verbs.c
++++ b/drivers/infiniband/hw/ipath/ipath_verbs.c
+@@ -943,7 +943,7 @@ bail:
+  * ipath_verbs_send - send a packet
+  * @qp: the QP to send on
+  * @hdr: the packet header
+- * @hdrwords: the number of words in the header
++ * @hdrwords: the number of 32-bit words in the header
+  * @ss: the SGE to send
+  * @len: the length of the packet in bytes
+  */
+@@ -955,7 +955,10 @@ int ipath_verbs_send(struct ipath_qp *qp, struct ipath_ib_header *hdr,
+ 	int ret;
+ 	u32 dwords = (len + 3) >> 2;
  
--	spin_lock_init(&file->recv_lock);
-+	mutex_init(&file->mutex);
- 	spin_lock_init(&file->send_lock);
- 	INIT_LIST_HEAD(&file->recv_list);
- 	INIT_LIST_HEAD(&file->send_list);
-@@ -809,7 +818,7 @@ static int ib_umad_open(struct inode *inode, struct file *filp)
- 	list_add_tail(&file->port_list, &port->file_list);
+-	/* +1 is for the qword padding of pbc */
++	/*
++	 * Calculate the send buffer trigger address.
++	 * The +1 counts for the pbc control dword following the pbc length.
++	 */
+ 	plen = hdrwords + dwords + 1;
  
- out:
--	up_write(&port->mutex);
-+	mutex_unlock(&port->file_mutex);
- 	return ret;
+ 	/* Drop non-VL15 packets if we are not in the active state */
+@@ -1130,20 +1133,34 @@ static int ipath_query_device(struct ib_device *ibdev,
+ 	return 0;
  }
  
-@@ -821,7 +830,8 @@ static int ib_umad_close(struct inode *inode, struct file *filp)
- 	int already_dead;
- 	int i;
- 
--	down_write(&file->port->mutex);
-+	mutex_lock(&file->port->file_mutex);
-+	mutex_lock(&file->mutex);
- 
- 	already_dead = file->agents_dead;
- 	file->agents_dead = 1;
-@@ -834,14 +844,14 @@ static int ib_umad_close(struct inode *inode, struct file *filp)
- 
- 	list_del(&file->port_list);
- 
--	downgrade_write(&file->port->mutex);
-+	mutex_unlock(&file->mutex);
- 
- 	if (!already_dead)
- 		for (i = 0; i < IB_UMAD_MAX_AGENTS; ++i)
- 			if (file->agent[i])
- 				ib_unregister_mad_agent(file->agent[i]);
- 
--	up_read(&file->port->mutex);
-+	mutex_unlock(&file->port->file_mutex);
- 
- 	kfree(file);
- 	kref_put(&dev->ref, ib_umad_release_dev);
-@@ -914,10 +924,10 @@ static int ib_umad_sm_close(struct inode *inode, struct file *filp)
- 	};
- 	int ret = 0;
+-const u8 ipath_cvt_physportstate[16] = {
+-	[INFINIPATH_IBCS_LT_STATE_DISABLED] = 3,
+-	[INFINIPATH_IBCS_LT_STATE_LINKUP] = 5,
+-	[INFINIPATH_IBCS_LT_STATE_POLLACTIVE] = 2,
+-	[INFINIPATH_IBCS_LT_STATE_POLLQUIET] = 2,
+-	[INFINIPATH_IBCS_LT_STATE_SLEEPDELAY] = 1,
+-	[INFINIPATH_IBCS_LT_STATE_SLEEPQUIET] = 1,
+-	[INFINIPATH_IBCS_LT_STATE_CFGDEBOUNCE] = 4,
+-	[INFINIPATH_IBCS_LT_STATE_CFGRCVFCFG] = 4,
+-	[INFINIPATH_IBCS_LT_STATE_CFGWAITRMT] = 4,
+-	[INFINIPATH_IBCS_LT_STATE_CFGIDLE] = 4,
+-	[INFINIPATH_IBCS_LT_STATE_RECOVERRETRAIN] = 6,
+-	[INFINIPATH_IBCS_LT_STATE_RECOVERWAITRMT] = 6,
+-	[INFINIPATH_IBCS_LT_STATE_RECOVERIDLE] = 6,
++const u8 ipath_cvt_physportstate[32] = {
++	[INFINIPATH_IBCS_LT_STATE_DISABLED] = IB_PHYSPORTSTATE_DISABLED,
++	[INFINIPATH_IBCS_LT_STATE_LINKUP] = IB_PHYSPORTSTATE_LINKUP,
++	[INFINIPATH_IBCS_LT_STATE_POLLACTIVE] = IB_PHYSPORTSTATE_POLL,
++	[INFINIPATH_IBCS_LT_STATE_POLLQUIET] = IB_PHYSPORTSTATE_POLL,
++	[INFINIPATH_IBCS_LT_STATE_SLEEPDELAY] = IB_PHYSPORTSTATE_SLEEP,
++	[INFINIPATH_IBCS_LT_STATE_SLEEPQUIET] = IB_PHYSPORTSTATE_SLEEP,
++	[INFINIPATH_IBCS_LT_STATE_CFGDEBOUNCE] =
++		IB_PHYSPORTSTATE_CFG_TRAIN,
++	[INFINIPATH_IBCS_LT_STATE_CFGRCVFCFG] =
++		IB_PHYSPORTSTATE_CFG_TRAIN,
++	[INFINIPATH_IBCS_LT_STATE_CFGWAITRMT] =
++		IB_PHYSPORTSTATE_CFG_TRAIN,
++	[INFINIPATH_IBCS_LT_STATE_CFGIDLE] = IB_PHYSPORTSTATE_CFG_TRAIN,
++	[INFINIPATH_IBCS_LT_STATE_RECOVERRETRAIN] =
++		IB_PHYSPORTSTATE_LINK_ERR_RECOVER,
++	[INFINIPATH_IBCS_LT_STATE_RECOVERWAITRMT] =
++		IB_PHYSPORTSTATE_LINK_ERR_RECOVER,
++	[INFINIPATH_IBCS_LT_STATE_RECOVERIDLE] =
++		IB_PHYSPORTSTATE_LINK_ERR_RECOVER,
++	[0x10] = IB_PHYSPORTSTATE_CFG_TRAIN,
++	[0x11] = IB_PHYSPORTSTATE_CFG_TRAIN,
++	[0x12] = IB_PHYSPORTSTATE_CFG_TRAIN,
++	[0x13] = IB_PHYSPORTSTATE_CFG_TRAIN,
++	[0x14] = IB_PHYSPORTSTATE_CFG_TRAIN,
++	[0x15] = IB_PHYSPORTSTATE_CFG_TRAIN,
++	[0x16] = IB_PHYSPORTSTATE_CFG_TRAIN,
++	[0x17] = IB_PHYSPORTSTATE_CFG_TRAIN
+ };
  
--	down_write(&port->mutex);
-+	mutex_lock(&port->file_mutex);
- 	if (port->ib_dev)
- 		ret = ib_modify_port(port->ib_dev, port->port_num, 0, &props);
--	up_write(&port->mutex);
-+	mutex_unlock(&port->file_mutex);
+ u32 ipath_get_cr_errpkey(struct ipath_devdata *dd)
+@@ -1168,8 +1185,9 @@ static int ipath_query_port(struct ib_device *ibdev,
+ 	ibcstat = dd->ipath_lastibcstat;
+ 	props->state = ((ibcstat >> 4) & 0x3) + 1;
+ 	/* See phys_state_show() */
+-	props->phys_state = ipath_cvt_physportstate[
+-		dd->ipath_lastibcstat & 0xf];
++	props->phys_state = /* MEA: assumes shift == 0 */
++		ipath_cvt_physportstate[dd->ipath_lastibcstat &
++		dd->ibcs_lts_mask];
+ 	props->port_cap_flags = dev->port_cap_flags;
+ 	props->gid_tbl_len = 1;
+ 	props->max_msg_sz = 0x80000000;
+@@ -1641,6 +1659,7 @@ int ipath_register_ib_device(struct ipath_devdata *dd)
+ 		cntrs.local_link_integrity_errors;
+ 	idev->z_excessive_buffer_overrun_errors =
+ 		cntrs.excessive_buffer_overrun_errors;
++	idev->z_vl15_dropped = cntrs.vl15_dropped;
  
- 	up(&port->sm_sem);
+ 	/*
+ 	 * The system image GUID is supposed to be the same for all
+diff --git a/drivers/infiniband/hw/ipath/ipath_verbs.h b/drivers/infiniband/hw/ipath/ipath_verbs.h
+index 6ccb54f..3d59736 100644
+--- a/drivers/infiniband/hw/ipath/ipath_verbs.h
++++ b/drivers/infiniband/hw/ipath/ipath_verbs.h
+@@ -554,6 +554,7 @@ struct ipath_ibdev {
+ 	u32 z_pkey_violations;			/* starting count for PMA */
+ 	u32 z_local_link_integrity_errors;	/* starting count for PMA */
+ 	u32 z_excessive_buffer_overrun_errors;	/* starting count for PMA */
++	u32 z_vl15_dropped;			/* starting count for PMA */
+ 	u32 n_rc_resends;
+ 	u32 n_rc_acks;
+ 	u32 n_rc_qacks;
+@@ -598,6 +599,7 @@ struct ipath_verbs_counters {
+ 	u64 port_rcv_packets;
+ 	u32 local_link_integrity_errors;
+ 	u32 excessive_buffer_overrun_errors;
++	u32 vl15_dropped;
+ };
  
-@@ -981,7 +991,7 @@ static int ib_umad_init_port(struct ib_device *device, int port_num,
- 	port->ib_dev   = device;
- 	port->port_num = port_num;
- 	init_MUTEX(&port->sm_sem);
--	init_rwsem(&port->mutex);
-+	mutex_init(&port->file_mutex);
- 	INIT_LIST_HEAD(&port->file_list);
+ static inline struct ipath_mr *to_imr(struct ib_mr *ibmr)
+@@ -830,7 +832,17 @@ unsigned ipath_get_pkey(struct ipath_devdata *, unsigned);
  
- 	port->dev = cdev_alloc();
-@@ -1052,6 +1062,7 @@ err_cdev:
- static void ib_umad_kill_port(struct ib_umad_port *port)
- {
- 	struct ib_umad_file *file;
-+	int already_dead;
- 	int id;
+ extern const enum ib_wc_opcode ib_ipath_wc_opcode[];
  
- 	class_set_devdata(port->class_dev,    NULL);
-@@ -1067,42 +1078,22 @@ static void ib_umad_kill_port(struct ib_umad_port *port)
- 	umad_port[port->dev_num] = NULL;
- 	spin_unlock(&port_lock);
++/*
++ * Below converts HCA-specific LinkTrainingState to IB PhysPortState
++ * values.
++ */
+ extern const u8 ipath_cvt_physportstate[];
++#define IB_PHYSPORTSTATE_SLEEP 1
++#define IB_PHYSPORTSTATE_POLL 2
++#define IB_PHYSPORTSTATE_DISABLED 3
++#define IB_PHYSPORTSTATE_CFG_TRAIN 4
++#define IB_PHYSPORTSTATE_LINKUP 5
++#define IB_PHYSPORTSTATE_LINK_ERR_RECOVER 6
  
--	down_write(&port->mutex);
-+	mutex_lock(&port->file_mutex);
+ extern const int ib_ipath_state_ops[];
  
- 	port->ib_dev = NULL;
+diff --git a/drivers/infiniband/hw/mlx4/cq.c b/drivers/infiniband/hw/mlx4/cq.c
+index 9d32c49..7950aa6 100644
+--- a/drivers/infiniband/hw/mlx4/cq.c
++++ b/drivers/infiniband/hw/mlx4/cq.c
+@@ -313,6 +313,7 @@ static int mlx4_ib_poll_one(struct mlx4_ib_cq *cq,
+ 	struct mlx4_ib_srq *srq;
+ 	int is_send;
+ 	int is_error;
++	u32 g_mlpath_rqpn;
+ 	u16 wqe_ctr;
  
--	/*
--	 * Now go through the list of files attached to this port and
--	 * unregister all of their MAD agents.  We need to hold
--	 * port->mutex while doing this to avoid racing with
--	 * ib_umad_close(), but we can't hold the mutex for writing
--	 * while calling ib_unregister_mad_agent(), since that might
--	 * deadlock by calling back into queue_packet().  So we
--	 * downgrade our lock to a read lock, and then drop and
--	 * reacquire the write lock for the next iteration.
--	 *
--	 * We do list_del_init() on the file's list_head so that the
--	 * list_del in ib_umad_close() is still OK, even after the
--	 * file is removed from the list.
--	 */
--	while (!list_empty(&port->file_list)) {
--		file = list_entry(port->file_list.next, struct ib_umad_file,
--				  port_list);
--
-+	list_for_each_entry(file, &port->file_list, port_list) {
-+		mutex_lock(&file->mutex);
-+		already_dead = file->agents_dead;
- 		file->agents_dead = 1;
--		list_del_init(&file->port_list);
--
--		downgrade_write(&port->mutex);
-+		mutex_unlock(&file->mutex);
+ 	cqe = next_cqe_sw(cq);
+@@ -426,10 +427,10 @@ static int mlx4_ib_poll_one(struct mlx4_ib_cq *cq,
  
- 		for (id = 0; id < IB_UMAD_MAX_AGENTS; ++id)
- 			if (file->agent[id])
- 				ib_unregister_mad_agent(file->agent[id]);
--
--		up_read(&port->mutex);
--		down_write(&port->mutex);
+ 		wc->slid	   = be16_to_cpu(cqe->rlid);
+ 		wc->sl		   = cqe->sl >> 4;
+-		wc->src_qp	   = be32_to_cpu(cqe->g_mlpath_rqpn) & 0xffffff;
+-		wc->dlid_path_bits = (be32_to_cpu(cqe->g_mlpath_rqpn) >> 24) & 0x7f;
+-		wc->wc_flags      |= be32_to_cpu(cqe->g_mlpath_rqpn) & 0x80000000 ?
+-			IB_WC_GRH : 0;
++		g_mlpath_rqpn	   = be32_to_cpu(cqe->g_mlpath_rqpn);
++		wc->src_qp	   = g_mlpath_rqpn & 0xffffff;
++		wc->dlid_path_bits = (g_mlpath_rqpn >> 24) & 0x7f;
++		wc->wc_flags	  |= g_mlpath_rqpn & 0x80000000 ? IB_WC_GRH : 0;
+ 		wc->pkey_index     = be32_to_cpu(cqe->immed_rss_invalid) & 0x7f;
  	}
  
--	up_write(&port->mutex);
-+	mutex_unlock(&port->file_mutex);
- 
- 	clear_bit(port->dev_num, dev_map);
- }
-diff --git a/drivers/infiniband/hw/cxgb3/cxio_hal.c b/drivers/infiniband/hw/cxgb3/cxio_hal.c
-index eec6a30..03c5ff6 100644
---- a/drivers/infiniband/hw/cxgb3/cxio_hal.c
-+++ b/drivers/infiniband/hw/cxgb3/cxio_hal.c
-@@ -179,7 +179,7 @@ int cxio_create_cq(struct cxio_rdev *rdev_p, struct t3_cq *cq)
- 	setup.size = 1UL << cq->size_log2;
- 	setup.credits = 65535;
- 	setup.credit_thres = 1;
--	if (rdev_p->t3cdev_p->type == T3B)
-+	if (rdev_p->t3cdev_p->type != T3A)
- 		setup.ovfl_mode = 0;
- 	else
- 		setup.ovfl_mode = 1;
-@@ -584,7 +584,7 @@ static int cxio_hal_ctrl_qp_write_mem(struct cxio_rdev *rdev_p, u32 addr,
- {
- 	u32 i, nr_wqe, copy_len;
- 	u8 *copy_data;
--	u8 wr_len, utx_len;	/* lenght in 8 byte flit */
-+	u8 wr_len, utx_len;	/* length in 8 byte flit */
- 	enum t3_wr_flags flag;
- 	__be64 *wqe;
- 	u64 utx_cmd;
-diff --git a/drivers/infiniband/hw/cxgb3/cxio_wr.h b/drivers/infiniband/hw/cxgb3/cxio_wr.h
-index c84d4ac..969d4d9 100644
---- a/drivers/infiniband/hw/cxgb3/cxio_wr.h
-+++ b/drivers/infiniband/hw/cxgb3/cxio_wr.h
-@@ -315,7 +315,7 @@ struct t3_rdma_init_wr {
- 	__be32 ird;
- 	__be64 qp_dma_addr;	/* 7 */
- 	__be32 qp_dma_size;	/* 8 */
--	u32 irs;
-+	__be32 irs;
+diff --git a/drivers/infiniband/hw/mthca/mthca_dev.h b/drivers/infiniband/hw/mthca/mthca_dev.h
+index 15aa32e..7bbdd1f 100644
+--- a/drivers/infiniband/hw/mthca/mthca_dev.h
++++ b/drivers/infiniband/hw/mthca/mthca_dev.h
+@@ -60,13 +60,12 @@
+ enum {
+ 	MTHCA_FLAG_DDR_HIDDEN = 1 << 1,
+ 	MTHCA_FLAG_SRQ        = 1 << 2,
+-	MTHCA_FLAG_MSI        = 1 << 3,
+-	MTHCA_FLAG_MSI_X      = 1 << 4,
+-	MTHCA_FLAG_NO_LAM     = 1 << 5,
+-	MTHCA_FLAG_FMR        = 1 << 6,
+-	MTHCA_FLAG_MEMFREE    = 1 << 7,
+-	MTHCA_FLAG_PCIE       = 1 << 8,
+-	MTHCA_FLAG_SINAI_OPT  = 1 << 9
++	MTHCA_FLAG_MSI_X      = 1 << 3,
++	MTHCA_FLAG_NO_LAM     = 1 << 4,
++	MTHCA_FLAG_FMR        = 1 << 5,
++	MTHCA_FLAG_MEMFREE    = 1 << 6,
++	MTHCA_FLAG_PCIE       = 1 << 7,
++	MTHCA_FLAG_SINAI_OPT  = 1 << 8
  };
  
- struct t3_genbit {
-@@ -324,7 +324,8 @@ struct t3_genbit {
- };
+ enum {
+diff --git a/drivers/infiniband/hw/mthca/mthca_eq.c b/drivers/infiniband/hw/mthca/mthca_eq.c
+index b29de51..b60eb5d 100644
+--- a/drivers/infiniband/hw/mthca/mthca_eq.c
++++ b/drivers/infiniband/hw/mthca/mthca_eq.c
+@@ -827,8 +827,7 @@ int mthca_init_eq_table(struct mthca_dev *dev)
+ 	if (err)
+ 		goto err_out_free;
  
- enum rdma_init_wr_flags {
--	RECVS_POSTED = 1,
-+	RECVS_POSTED = (1<<0),
-+	PRIV_QP = (1<<1),
- };
+-	if (dev->mthca_flags & MTHCA_FLAG_MSI ||
+-	    dev->mthca_flags & MTHCA_FLAG_MSI_X) {
++	if (dev->mthca_flags & MTHCA_FLAG_MSI_X) {
+ 		dev->eq_table.clr_mask = 0;
+ 	} else {
+ 		dev->eq_table.clr_mask =
+@@ -839,8 +838,7 @@ int mthca_init_eq_table(struct mthca_dev *dev)
  
- union t3_wr {
-diff --git a/drivers/infiniband/hw/cxgb3/iwch_cm.c b/drivers/infiniband/hw/cxgb3/iwch_cm.c
-index 20ba372..f8cb0fe 100644
---- a/drivers/infiniband/hw/cxgb3/iwch_cm.c
-+++ b/drivers/infiniband/hw/cxgb3/iwch_cm.c
-@@ -1118,7 +1118,7 @@ static int act_open_rpl(struct t3cdev *tdev, struct sk_buff *skb, void *ctx)
- 	     status2errno(rpl->status));
- 	connect_reply_upcall(ep, status2errno(rpl->status));
- 	state_set(&ep->com, DEAD);
--	if (ep->com.tdev->type == T3B && act_open_has_tid(rpl->status))
-+	if (ep->com.tdev->type != T3A && act_open_has_tid(rpl->status))
- 		release_tid(ep->com.tdev, GET_TID(rpl), NULL);
- 	cxgb3_free_atid(ep->com.tdev, ep->atid);
- 	dst_release(ep->dst);
-@@ -1249,7 +1249,7 @@ static void reject_cr(struct t3cdev *tdev, u32 hwtid, __be32 peer_ip,
- 	skb_trim(skb, sizeof(struct cpl_tid_release));
- 	skb_get(skb);
+ 	dev->eq_table.arm_mask = 0;
  
--	if (tdev->type == T3B)
-+	if (tdev->type != T3A)
- 		release_tid(tdev, hwtid, skb);
- 	else {
- 		struct cpl_pass_accept_rpl *rpl;
-diff --git a/drivers/infiniband/hw/cxgb3/iwch_mem.c b/drivers/infiniband/hw/cxgb3/iwch_mem.c
-index a6c2c4b..73bfd16 100644
---- a/drivers/infiniband/hw/cxgb3/iwch_mem.c
-+++ b/drivers/infiniband/hw/cxgb3/iwch_mem.c
-@@ -122,6 +122,13 @@ int build_phys_page_list(struct ib_phys_buf *buffer_list,
- 		*total_size += buffer_list[i].size;
- 		if (i > 0)
- 			mask |= buffer_list[i].addr;
-+		else
-+			mask |= buffer_list[i].addr & PAGE_MASK;
-+		if (i != num_phys_buf - 1)
-+			mask |= buffer_list[i].addr + buffer_list[i].size;
-+		else
-+			mask |= (buffer_list[i].addr + buffer_list[i].size +
-+				PAGE_SIZE - 1) & PAGE_MASK;
- 	}
+-	intr = (dev->mthca_flags & MTHCA_FLAG_MSI) ?
+-		128 : dev->eq_table.inta_pin;
++	intr = dev->eq_table.inta_pin;
  
- 	if (*total_size > 0xFFFFFFFFULL)
-diff --git a/drivers/infiniband/hw/cxgb3/iwch_provider.c b/drivers/infiniband/hw/cxgb3/iwch_provider.c
-index b5436ca..df1838f 100644
---- a/drivers/infiniband/hw/cxgb3/iwch_provider.c
-+++ b/drivers/infiniband/hw/cxgb3/iwch_provider.c
-@@ -39,6 +39,7 @@
- #include <linux/list.h>
- #include <linux/spinlock.h>
- #include <linux/ethtool.h>
-+#include <linux/rtnetlink.h>
+ 	err = mthca_create_eq(dev, dev->limits.num_cqs + MTHCA_NUM_SPARE_EQE,
+ 			      (dev->mthca_flags & MTHCA_FLAG_MSI_X) ? 128 : intr,
+diff --git a/drivers/infiniband/hw/mthca/mthca_main.c b/drivers/infiniband/hw/mthca/mthca_main.c
+index 60de6f9..5cf8250 100644
+--- a/drivers/infiniband/hw/mthca/mthca_main.c
++++ b/drivers/infiniband/hw/mthca/mthca_main.c
+@@ -65,14 +65,9 @@ static int msi_x = 1;
+ module_param(msi_x, int, 0444);
+ MODULE_PARM_DESC(msi_x, "attempt to use MSI-X if nonzero");
  
- #include <asm/io.h>
- #include <asm/irq.h>
-@@ -645,7 +646,7 @@ static struct ib_mr *iwch_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
- 	if (err)
- 		goto err;
+-static int msi = 0;
+-module_param(msi, int, 0444);
+-MODULE_PARM_DESC(msi, "attempt to use MSI if nonzero (deprecated, use MSI-X instead)");
+-
+ #else /* CONFIG_PCI_MSI */
  
--	if (udata && t3b_device(rhp)) {
-+	if (udata && !t3a_device(rhp)) {
- 		uresp.pbl_addr = (mhp->attr.pbl_addr -
- 	                         rhp->rdev.rnic_info.pbl_base) >> 3;
- 		PDBG("%s user resp pbl_addr 0x%x\n", __FUNCTION__,
-@@ -1053,7 +1054,9 @@ static ssize_t show_fw_ver(struct class_device *cdev, char *buf)
- 	struct net_device *lldev = dev->rdev.t3cdev_p->lldev;
+ #define msi_x (0)
+-#define msi   (0)
  
- 	PDBG("%s class dev 0x%p\n", __FUNCTION__, cdev);
-+	rtnl_lock();
- 	lldev->ethtool_ops->get_drvinfo(lldev, &info);
-+	rtnl_unlock();
- 	return sprintf(buf, "%s\n", info.fw_version);
- }
+ #endif /* CONFIG_PCI_MSI */
  
-@@ -1065,7 +1068,9 @@ static ssize_t show_hca(struct class_device *cdev, char *buf)
- 	struct net_device *lldev = dev->rdev.t3cdev_p->lldev;
+@@ -816,13 +811,11 @@ static int mthca_setup_hca(struct mthca_dev *dev)
  
- 	PDBG("%s class dev 0x%p\n", __FUNCTION__, cdev);
-+	rtnl_lock();
- 	lldev->ethtool_ops->get_drvinfo(lldev, &info);
-+	rtnl_unlock();
- 	return sprintf(buf, "%s\n", info.driver);
- }
+ 	err = mthca_NOP(dev, &status);
+ 	if (err || status) {
+-		if (dev->mthca_flags & (MTHCA_FLAG_MSI | MTHCA_FLAG_MSI_X)) {
++		if (dev->mthca_flags & MTHCA_FLAG_MSI_X) {
+ 			mthca_warn(dev, "NOP command failed to generate interrupt "
+ 				   "(IRQ %d).\n",
+-				   dev->mthca_flags & MTHCA_FLAG_MSI_X ?
+-				   dev->eq_table.eq[MTHCA_EQ_CMD].msi_x_vector :
+-				   dev->pdev->irq);
+-			mthca_warn(dev, "Trying again with MSI/MSI-X disabled.\n");
++				   dev->eq_table.eq[MTHCA_EQ_CMD].msi_x_vector);
++			mthca_warn(dev, "Trying again with MSI-X disabled.\n");
+ 		} else {
+ 			mthca_err(dev, "NOP command failed to generate interrupt "
+ 				  "(IRQ %d), aborting.\n",
+@@ -1005,7 +998,7 @@ static struct {
+ 			   .flags     = 0 },
+ 	[ARBEL_COMPAT] = { .latest_fw = MTHCA_FW_VER(4, 8, 200),
+ 			   .flags     = MTHCA_FLAG_PCIE },
+-	[ARBEL_NATIVE] = { .latest_fw = MTHCA_FW_VER(5, 2, 0),
++	[ARBEL_NATIVE] = { .latest_fw = MTHCA_FW_VER(5, 3, 0),
+ 			   .flags     = MTHCA_FLAG_MEMFREE |
+ 					MTHCA_FLAG_PCIE },
+ 	[SINAI]        = { .latest_fw = MTHCA_FW_VER(1, 2, 0),
+@@ -1128,29 +1121,12 @@ static int __mthca_init_one(struct pci_dev *pdev, int hca_type)
  
-diff --git a/drivers/infiniband/hw/cxgb3/iwch_qp.c b/drivers/infiniband/hw/cxgb3/iwch_qp.c
-index dd89b6b..ea2cdd7 100644
---- a/drivers/infiniband/hw/cxgb3/iwch_qp.c
-+++ b/drivers/infiniband/hw/cxgb3/iwch_qp.c
-@@ -208,36 +208,19 @@ static int iwch_sgl2pbl_map(struct iwch_dev *rhp, struct ib_sge *sg_list,
- static int iwch_build_rdma_recv(struct iwch_dev *rhp, union t3_wr *wqe,
- 				struct ib_recv_wr *wr)
- {
--	int i, err = 0;
--	u32 pbl_addr[4];
--	u8 page_size[4];
-+	int i;
- 	if (wr->num_sge > T3_MAX_SGE)
- 		return -EINVAL;
--	err = iwch_sgl2pbl_map(rhp, wr->sg_list, wr->num_sge, pbl_addr,
--			       page_size);
--	if (err)
--		return err;
--	wqe->recv.pagesz[0] = page_size[0];
--	wqe->recv.pagesz[1] = page_size[1];
--	wqe->recv.pagesz[2] = page_size[2];
--	wqe->recv.pagesz[3] = page_size[3];
- 	wqe->recv.num_sgle = cpu_to_be32(wr->num_sge);
- 	for (i = 0; i < wr->num_sge; i++) {
- 		wqe->recv.sgl[i].stag = cpu_to_be32(wr->sg_list[i].lkey);
- 		wqe->recv.sgl[i].len = cpu_to_be32(wr->sg_list[i].length);
+ 	if (msi_x && !mthca_enable_msi_x(mdev))
+ 		mdev->mthca_flags |= MTHCA_FLAG_MSI_X;
+-	else if (msi) {
+-		static int warned;
 -
--		/* to in the WQE == the offset into the page */
--		wqe->recv.sgl[i].to = cpu_to_be64(((u32) wr->sg_list[i].addr) %
--				(1UL << (12 + page_size[i])));
+-		if (!warned) {
+-			printk(KERN_WARNING PFX "WARNING: MSI support will be "
+-			       "removed from the ib_mthca driver in January 2008.\n");
+-			printk(KERN_WARNING "    If you are using MSI and cannot "
+-			       "switch to MSI-X, please tell "
+-			       "<general at lists.openfabrics.org>.\n");
+-			++warned;
+-		}
 -
--		/* pbl_addr is the adapters address in the PBL */
--		wqe->recv.pbl_addr[i] = cpu_to_be32(pbl_addr[i]);
-+		wqe->recv.sgl[i].to = cpu_to_be64(wr->sg_list[i].addr);
- 	}
- 	for (; i < T3_MAX_SGE; i++) {
- 		wqe->recv.sgl[i].stag = 0;
- 		wqe->recv.sgl[i].len = 0;
- 		wqe->recv.sgl[i].to = 0;
--		wqe->recv.pbl_addr[i] = 0;
+-		if (!pci_enable_msi(pdev))
+-			mdev->mthca_flags |= MTHCA_FLAG_MSI;
+-	}
+ 
+ 	err = mthca_setup_hca(mdev);
+-	if (err == -EBUSY && (mdev->mthca_flags & (MTHCA_FLAG_MSI | MTHCA_FLAG_MSI_X))) {
++	if (err == -EBUSY && (mdev->mthca_flags & MTHCA_FLAG_MSI_X)) {
+ 		if (mdev->mthca_flags & MTHCA_FLAG_MSI_X)
+ 			pci_disable_msix(pdev);
+-		if (mdev->mthca_flags & MTHCA_FLAG_MSI)
+-			pci_disable_msi(pdev);
+-		mdev->mthca_flags &= ~(MTHCA_FLAG_MSI_X | MTHCA_FLAG_MSI);
++		mdev->mthca_flags &= ~MTHCA_FLAG_MSI_X;
+ 
+ 		err = mthca_setup_hca(mdev);
  	}
- 	return 0;
- }
-@@ -659,6 +642,7 @@ static void __flush_qp(struct iwch_qp *qhp, unsigned long *flag)
- 	cxio_flush_rq(&qhp->wq, &rchp->cq, count);
- 	spin_unlock(&qhp->lock);
- 	spin_unlock_irqrestore(&rchp->lock, *flag);
-+	(*rchp->ibcq.comp_handler)(&rchp->ibcq, rchp->ibcq.cq_context);
+@@ -1192,8 +1168,6 @@ err_cleanup:
+ err_close:
+ 	if (mdev->mthca_flags & MTHCA_FLAG_MSI_X)
+ 		pci_disable_msix(pdev);
+-	if (mdev->mthca_flags & MTHCA_FLAG_MSI)
+-		pci_disable_msi(pdev);
  
- 	/* locking heirarchy: cq lock first, then qp lock. */
- 	spin_lock_irqsave(&schp->lock, *flag);
-@@ -668,6 +652,7 @@ static void __flush_qp(struct iwch_qp *qhp, unsigned long *flag)
- 	cxio_flush_sq(&qhp->wq, &schp->cq, count);
- 	spin_unlock(&qhp->lock);
- 	spin_unlock_irqrestore(&schp->lock, *flag);
-+	(*schp->ibcq.comp_handler)(&schp->ibcq, schp->ibcq.cq_context);
+ 	mthca_close_hca(mdev);
  
- 	/* deref */
- 	if (atomic_dec_and_test(&qhp->refcnt))
-@@ -678,7 +663,7 @@ static void __flush_qp(struct iwch_qp *qhp, unsigned long *flag)
+@@ -1246,8 +1220,6 @@ static void __mthca_remove_one(struct pci_dev *pdev)
  
- static void flush_qp(struct iwch_qp *qhp, unsigned long *flag)
- {
--	if (t3b_device(qhp->rhp))
-+	if (qhp->ibqp.uobject)
- 		cxio_set_wq_in_error(&qhp->wq);
- 	else
- 		__flush_qp(qhp, flag);
-@@ -732,6 +717,7 @@ static int rdma_init(struct iwch_dev *rhp, struct iwch_qp *qhp,
- 	init_attr.qp_dma_addr = qhp->wq.dma_addr;
- 	init_attr.qp_dma_size = (1UL << qhp->wq.size_log2);
- 	init_attr.flags = rqes_posted(qhp) ? RECVS_POSTED : 0;
-+	init_attr.flags |= capable(CAP_NET_BIND_SERVICE) ? PRIV_QP : 0;
- 	init_attr.irs = qhp->ep->rcv_seq;
- 	PDBG("%s init_attr.rq_addr 0x%x init_attr.rq_size = %d "
- 	     "flags 0x%x qpcaps 0x%x\n", __FUNCTION__,
-@@ -847,10 +833,11 @@ int iwch_modify_qp(struct iwch_dev *rhp, struct iwch_qp *qhp,
- 				disconnect = 1;
- 				ep = qhp->ep;
- 			}
-+			flush_qp(qhp, &flag);
- 			break;
- 		case IWCH_QP_STATE_TERMINATE:
- 			qhp->attr.state = IWCH_QP_STATE_TERMINATE;
--			if (t3b_device(qhp->rhp))
-+			if (qhp->ibqp.uobject)
- 				cxio_set_wq_in_error(&qhp->wq);
- 			if (!internal)
- 				terminate = 1;
-diff --git a/drivers/infiniband/hw/ehca/ehca_av.c b/drivers/infiniband/hw/ehca/ehca_av.c
-index f7782c8..194c1c3 100644
---- a/drivers/infiniband/hw/ehca/ehca_av.c
-+++ b/drivers/infiniband/hw/ehca/ehca_av.c
-@@ -1,7 +1,7 @@
- /*
-  *  IBM eServer eHCA Infiniband device driver for Linux on POWER
-  *
-- *  adress vector functions
-+ *  address vector functions
-  *
-  *  Authors: Hoang-Nam Nguyen <hnguyen at de.ibm.com>
-  *           Khadija Souissi <souissik at de.ibm.com>
-diff --git a/drivers/infiniband/hw/ehca/ehca_classes.h b/drivers/infiniband/hw/ehca/ehca_classes.h
-index 74d2b72..f281d16 100644
---- a/drivers/infiniband/hw/ehca/ehca_classes.h
-+++ b/drivers/infiniband/hw/ehca/ehca_classes.h
-@@ -94,7 +94,11 @@ struct ehca_sma_attr {
+ 		if (mdev->mthca_flags & MTHCA_FLAG_MSI_X)
+ 			pci_disable_msix(pdev);
+-		if (mdev->mthca_flags & MTHCA_FLAG_MSI)
+-			pci_disable_msi(pdev);
  
- struct ehca_sport {
- 	struct ib_cq *ibcq_aqp1;
--	struct ib_qp *ibqp_aqp1;
-+	struct ib_qp *ibqp_sqp[2];
-+	/* lock to serialze modify_qp() calls for sqp in normal
-+	 * and irq path (when event PORT_ACTIVE is received first time)
-+	 */
-+	spinlock_t mod_sqp_lock;
- 	enum ib_port_state port_state;
- 	struct ehca_sma_attr saved_attr;
- };
-@@ -141,6 +145,14 @@ enum ehca_ext_qp_type {
- 	EQPT_SRQ       = 3,
- };
+ 		ib_dealloc_device(&mdev->ib_dev);
+ 		mthca_release_regions(pdev, mdev->mthca_flags &
+diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h b/drivers/infiniband/ulp/ipoib/ipoib.h
+index eb7edab..fe250c6 100644
+--- a/drivers/infiniband/ulp/ipoib/ipoib.h
++++ b/drivers/infiniband/ulp/ipoib/ipoib.h
+@@ -56,42 +56,43 @@
+ /* constants */
  
-+/* struct to cache modify_qp()'s parms for GSI/SMI qp */
-+struct ehca_mod_qp_parm {
-+	int mask;
-+	struct ib_qp_attr attr;
-+};
-+
-+#define EHCA_MOD_QP_PARM_MAX 4
-+
- struct ehca_qp {
- 	union {
- 		struct ib_qp ib_qp;
-@@ -164,10 +176,18 @@ struct ehca_qp {
- 	struct ehca_cq *recv_cq;
- 	unsigned int sqerr_purgeflag;
- 	struct hlist_node list_entries;
-+	/* array to cache modify_qp()'s parms for GSI/SMI qp */
-+	struct ehca_mod_qp_parm *mod_qp_parm;
-+	int mod_qp_parm_idx;
- 	/* mmap counter for resources mapped into user space */
- 	u32 mm_count_squeue;
- 	u32 mm_count_rqueue;
- 	u32 mm_count_galpa;
-+	/* unsolicited ack circumvention */
-+	int unsol_ack_circ;
-+	int mtu_shift;
-+	u32 message_count;
-+	u32 packet_count;
- };
+ enum {
+-	IPOIB_PACKET_SIZE         = 2048,
+-	IPOIB_BUF_SIZE 		  = IPOIB_PACKET_SIZE + IB_GRH_BYTES,
++	IPOIB_PACKET_SIZE	  = 2048,
++	IPOIB_BUF_SIZE		  = IPOIB_PACKET_SIZE + IB_GRH_BYTES,
  
- #define IS_SRQ(qp) (qp->ext_type == EQPT_SRQ)
-@@ -323,6 +343,7 @@ extern int ehca_port_act_time;
- extern int ehca_use_hp_mr;
- extern int ehca_scaling_code;
- extern int ehca_lock_hcalls;
-+extern int ehca_nr_ports;
+-	IPOIB_ENCAP_LEN 	  = 4,
++	IPOIB_ENCAP_LEN		  = 4,
  
- struct ipzu_queue_resp {
- 	u32 qe_size;      /* queue entry size */
-diff --git a/drivers/infiniband/hw/ehca/ehca_cq.c b/drivers/infiniband/hw/ehca/ehca_cq.c
-index 79c25f5..0467c15 100644
---- a/drivers/infiniband/hw/ehca/ehca_cq.c
-+++ b/drivers/infiniband/hw/ehca/ehca_cq.c
-@@ -246,7 +246,7 @@ struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe, int comp_vector,
- 		} else {
- 			if (h_ret != H_PAGE_REGISTERED) {
- 				ehca_err(device, "Registration of page failed "
--					 "ehca_cq=%p cq_num=%x h_ret=%li"
-+					 "ehca_cq=%p cq_num=%x h_ret=%li "
- 					 "counter=%i act_pages=%i",
- 					 my_cq, my_cq->cq_number,
- 					 h_ret, counter, param.act_pages);
-diff --git a/drivers/infiniband/hw/ehca/ehca_irq.c b/drivers/infiniband/hw/ehca/ehca_irq.c
-index 3f617b2..863b34f 100644
---- a/drivers/infiniband/hw/ehca/ehca_irq.c
-+++ b/drivers/infiniband/hw/ehca/ehca_irq.c
-@@ -62,6 +62,7 @@
- #define NEQE_PORT_NUMBER       EHCA_BMASK_IBM( 8, 15)
- #define NEQE_PORT_AVAILABILITY EHCA_BMASK_IBM(16, 16)
- #define NEQE_DISRUPTIVE        EHCA_BMASK_IBM(16, 16)
-+#define NEQE_SPECIFIC_EVENT    EHCA_BMASK_IBM(16, 23)
+-	IPOIB_CM_MTU              = 0x10000 - 0x10, /* padding to align header to 16 */
+-	IPOIB_CM_BUF_SIZE         = IPOIB_CM_MTU  + IPOIB_ENCAP_LEN,
+-	IPOIB_CM_HEAD_SIZE 	  = IPOIB_CM_BUF_SIZE % PAGE_SIZE,
+-	IPOIB_CM_RX_SG            = ALIGN(IPOIB_CM_BUF_SIZE, PAGE_SIZE) / PAGE_SIZE,
+-	IPOIB_RX_RING_SIZE 	  = 128,
+-	IPOIB_TX_RING_SIZE 	  = 64,
++	IPOIB_CM_MTU		  = 0x10000 - 0x10, /* padding to align header to 16 */
++	IPOIB_CM_BUF_SIZE	  = IPOIB_CM_MTU  + IPOIB_ENCAP_LEN,
++	IPOIB_CM_HEAD_SIZE	  = IPOIB_CM_BUF_SIZE % PAGE_SIZE,
++	IPOIB_CM_RX_SG		  = ALIGN(IPOIB_CM_BUF_SIZE, PAGE_SIZE) / PAGE_SIZE,
++	IPOIB_RX_RING_SIZE	  = 128,
++	IPOIB_TX_RING_SIZE	  = 64,
+ 	IPOIB_MAX_QUEUE_SIZE	  = 8192,
+ 	IPOIB_MIN_QUEUE_SIZE	  = 2,
++	IPOIB_CM_MAX_CONN_QP	  = 4096,
  
- #define ERROR_DATA_LENGTH      EHCA_BMASK_IBM(52, 63)
- #define ERROR_DATA_TYPE        EHCA_BMASK_IBM( 0,  7)
-@@ -354,17 +355,34 @@ static void parse_ec(struct ehca_shca *shca, u64 eqe)
- {
- 	u8 ec   = EHCA_BMASK_GET(NEQE_EVENT_CODE, eqe);
- 	u8 port = EHCA_BMASK_GET(NEQE_PORT_NUMBER, eqe);
-+	u8 spec_event;
-+	struct ehca_sport *sport = &shca->sport[port - 1];
-+	unsigned long flags;
+-	IPOIB_NUM_WC 		  = 4,
++	IPOIB_NUM_WC		  = 4,
  
- 	switch (ec) {
- 	case 0x30: /* port availability change */
- 		if (EHCA_BMASK_GET(NEQE_PORT_AVAILABILITY, eqe)) {
--			shca->sport[port - 1].port_state = IB_PORT_ACTIVE;
-+			int suppress_event;
-+			/* replay modify_qp for sqps */
-+			spin_lock_irqsave(&sport->mod_sqp_lock, flags);
-+			suppress_event = !sport->ibqp_sqp[IB_QPT_GSI];
-+			if (sport->ibqp_sqp[IB_QPT_SMI])
-+				ehca_recover_sqp(sport->ibqp_sqp[IB_QPT_SMI]);
-+			if (!suppress_event)
-+				ehca_recover_sqp(sport->ibqp_sqp[IB_QPT_GSI]);
-+			spin_unlock_irqrestore(&sport->mod_sqp_lock, flags);
-+
-+			/* AQP1 was destroyed, ignore this event */
-+			if (suppress_event)
-+				break;
+ 	IPOIB_MAX_PATH_REC_QUEUE  = 3,
+-	IPOIB_MAX_MCAST_QUEUE     = 3,
+-
+-	IPOIB_FLAG_OPER_UP 	  = 0,
+-	IPOIB_FLAG_INITIALIZED    = 1,
+-	IPOIB_FLAG_ADMIN_UP 	  = 2,
+-	IPOIB_PKEY_ASSIGNED 	  = 3,
+-	IPOIB_PKEY_STOP 	  = 4,
+-	IPOIB_FLAG_SUBINTERFACE   = 5,
+-	IPOIB_MCAST_RUN 	  = 6,
+-	IPOIB_STOP_REAPER         = 7,
+-	IPOIB_MCAST_STARTED       = 8,
+-	IPOIB_FLAG_ADMIN_CM 	  = 9,
++	IPOIB_MAX_MCAST_QUEUE	  = 3,
 +
-+			sport->port_state = IB_PORT_ACTIVE;
- 			dispatch_port_event(shca, port, IB_EVENT_PORT_ACTIVE,
- 					    "is active");
- 			ehca_query_sma_attr(shca, port,
--					    &shca->sport[port - 1].saved_attr);
-+					    &sport->saved_attr);
- 		} else {
--			shca->sport[port - 1].port_state = IB_PORT_DOWN;
-+			sport->port_state = IB_PORT_DOWN;
- 			dispatch_port_event(shca, port, IB_EVENT_PORT_ERR,
- 					    "is inactive");
- 		}
-@@ -378,11 +396,11 @@ static void parse_ec(struct ehca_shca *shca, u64 eqe)
- 			ehca_warn(&shca->ib_device, "disruptive port "
- 				  "%d configuration change", port);
++	IPOIB_FLAG_OPER_UP	  = 0,
++	IPOIB_FLAG_INITIALIZED	  = 1,
++	IPOIB_FLAG_ADMIN_UP	  = 2,
++	IPOIB_PKEY_ASSIGNED	  = 3,
++	IPOIB_PKEY_STOP		  = 4,
++	IPOIB_FLAG_SUBINTERFACE	  = 5,
++	IPOIB_MCAST_RUN		  = 6,
++	IPOIB_STOP_REAPER	  = 7,
++	IPOIB_MCAST_STARTED	  = 8,
++	IPOIB_FLAG_ADMIN_CM	  = 9,
+ 	IPOIB_FLAG_UMCAST	  = 10,
  
--			shca->sport[port - 1].port_state = IB_PORT_DOWN;
-+			sport->port_state = IB_PORT_DOWN;
- 			dispatch_port_event(shca, port, IB_EVENT_PORT_ERR,
- 					    "is inactive");
+ 	IPOIB_MAX_BACKOFF_SECONDS = 16,
  
--			shca->sport[port - 1].port_state = IB_PORT_ACTIVE;
-+			sport->port_state = IB_PORT_ACTIVE;
- 			dispatch_port_event(shca, port, IB_EVENT_PORT_ACTIVE,
- 					    "is active");
- 		} else
-@@ -394,6 +412,16 @@ static void parse_ec(struct ehca_shca *shca, u64 eqe)
- 	case 0x33:  /* trace stopped */
- 		ehca_err(&shca->ib_device, "Traced stopped.");
- 		break;
-+	case 0x34: /* util async event */
-+		spec_event = EHCA_BMASK_GET(NEQE_SPECIFIC_EVENT, eqe);
-+		if (spec_event == 0x80) /* client reregister required */
-+			dispatch_port_event(shca, port,
-+					    IB_EVENT_CLIENT_REREGISTER,
-+					    "client reregister req.");
-+		else
-+			ehca_warn(&shca->ib_device, "Unknown util async "
-+				  "event %x on port %x", spec_event, port);
-+		break;
- 	default:
- 		ehca_err(&shca->ib_device, "Unknown event code: %x on %s.",
- 			 ec, shca->ib_device.name);
-diff --git a/drivers/infiniband/hw/ehca/ehca_iverbs.h b/drivers/infiniband/hw/ehca/ehca_iverbs.h
-index 5485799..c469bfd 100644
---- a/drivers/infiniband/hw/ehca/ehca_iverbs.h
-+++ b/drivers/infiniband/hw/ehca/ehca_iverbs.h
-@@ -200,4 +200,6 @@ void ehca_free_fw_ctrlblock(void *ptr);
- #define ehca_free_fw_ctrlblock(ptr) free_page((unsigned long)(ptr))
- #endif
+-	IPOIB_MCAST_FLAG_FOUND 	  = 0,	/* used in set_multicast_list */
++	IPOIB_MCAST_FLAG_FOUND	  = 0,	/* used in set_multicast_list */
+ 	IPOIB_MCAST_FLAG_SENDONLY = 1,
+-	IPOIB_MCAST_FLAG_BUSY 	  = 2,	/* joining or already joined */
++	IPOIB_MCAST_FLAG_BUSY	  = 2,	/* joining or already joined */
+ 	IPOIB_MCAST_FLAG_ATTACHED = 3,
+ };
  
-+void ehca_recover_sqp(struct ib_qp *sqp);
-+
- #endif
-diff --git a/drivers/infiniband/hw/ehca/ehca_main.c b/drivers/infiniband/hw/ehca/ehca_main.c
-index 6a56d86..84c9b7b 100644
---- a/drivers/infiniband/hw/ehca/ehca_main.c
-+++ b/drivers/infiniband/hw/ehca/ehca_main.c
-@@ -90,7 +90,8 @@ MODULE_PARM_DESC(hw_level,
- 		 "hardware level"
- 		 " (0: autosensing (default), 1: v. 0.20, 2: v. 0.21)");
- MODULE_PARM_DESC(nr_ports,
--		 "number of connected ports (default: 2)");
-+		 "number of connected ports (-1: autodetect, 1: port one only, "
-+		 "2: two ports (default)");
- MODULE_PARM_DESC(use_hp_mr,
- 		 "high performance MRs (0: no (default), 1: yes)");
- MODULE_PARM_DESC(port_act_time,
-@@ -511,7 +512,7 @@ static int ehca_create_aqp1(struct ehca_shca *shca, u32 port)
- 	}
- 	sport->ibcq_aqp1 = ibcq;
+@@ -117,7 +118,7 @@ struct ipoib_pseudoheader {
+ struct ipoib_mcast {
+ 	struct ib_sa_mcmember_rec mcmember;
+ 	struct ib_sa_multicast	 *mc;
+-	struct ipoib_ah          *ah;
++	struct ipoib_ah		 *ah;
  
--	if (sport->ibqp_aqp1) {
-+	if (sport->ibqp_sqp[IB_QPT_GSI]) {
- 		ehca_err(&shca->ib_device, "AQP1 QP is already created.");
- 		ret = -EPERM;
- 		goto create_aqp1;
-@@ -537,7 +538,7 @@ static int ehca_create_aqp1(struct ehca_shca *shca, u32 port)
- 		ret = PTR_ERR(ibqp);
- 		goto create_aqp1;
- 	}
--	sport->ibqp_aqp1 = ibqp;
-+	sport->ibqp_sqp[IB_QPT_GSI] = ibqp;
+ 	struct rb_node    rb_node;
+ 	struct list_head  list;
+@@ -186,27 +187,29 @@ enum ipoib_cm_state {
+ };
+ 
+ struct ipoib_cm_rx {
+-	struct ib_cm_id     *id;
+-	struct ib_qp        *qp;
+-	struct list_head     list;
+-	struct net_device   *dev;
+-	unsigned long        jiffies;
+-	enum ipoib_cm_state  state;
++	struct ib_cm_id	       *id;
++	struct ib_qp	       *qp;
++	struct ipoib_cm_rx_buf *rx_ring;
++	struct list_head	list;
++	struct net_device      *dev;
++	unsigned long		jiffies;
++	enum ipoib_cm_state	state;
++	int			recv_count;
+ };
  
- 	return 0;
+ struct ipoib_cm_tx {
+-	struct ib_cm_id     *id;
+-	struct ib_qp        *qp;
++	struct ib_cm_id	    *id;
++	struct ib_qp	    *qp;
+ 	struct list_head     list;
+ 	struct net_device   *dev;
+ 	struct ipoib_neigh  *neigh;
+ 	struct ipoib_path   *path;
+ 	struct ipoib_tx_buf *tx_ring;
+-	unsigned             tx_head;
+-	unsigned             tx_tail;
+-	unsigned long        flags;
+-	u32                  mtu;
+-	struct ib_wc         ibwc[IPOIB_NUM_WC];
++	unsigned	     tx_head;
++	unsigned	     tx_tail;
++	unsigned long	     flags;
++	u32		     mtu;
++	struct ib_wc	     ibwc[IPOIB_NUM_WC];
+ };
  
-@@ -550,7 +551,7 @@ static int ehca_destroy_aqp1(struct ehca_sport *sport)
- {
- 	int ret;
+ struct ipoib_cm_rx_buf {
+@@ -215,25 +218,28 @@ struct ipoib_cm_rx_buf {
+ };
  
--	ret = ib_destroy_qp(sport->ibqp_aqp1);
-+	ret = ib_destroy_qp(sport->ibqp_sqp[IB_QPT_GSI]);
- 	if (ret) {
- 		ehca_gen_err("Cannot destroy AQP1 QP. ret=%i", ret);
- 		return ret;
-@@ -590,6 +591,11 @@ static struct attribute_group ehca_drv_attr_grp = {
- 	.attrs = ehca_drv_attrs
+ struct ipoib_cm_dev_priv {
+-	struct ib_srq  	       *srq;
++	struct ib_srq	       *srq;
+ 	struct ipoib_cm_rx_buf *srq_ring;
+-	struct ib_cm_id        *id;
+-	struct list_head        passive_ids;   /* state: LIVE */
+-	struct list_head        rx_error_list; /* state: ERROR */
+-	struct list_head        rx_flush_list; /* state: FLUSH, drain not started */
+-	struct list_head        rx_drain_list; /* state: FLUSH, drain started */
+-	struct list_head        rx_reap_list;  /* state: FLUSH, drain done */
++	struct ib_cm_id	       *id;
++	struct list_head	passive_ids;   /* state: LIVE */
++	struct list_head	rx_error_list; /* state: ERROR */
++	struct list_head	rx_flush_list; /* state: FLUSH, drain not started */
++	struct list_head	rx_drain_list; /* state: FLUSH, drain started */
++	struct list_head	rx_reap_list;  /* state: FLUSH, drain done */
+ 	struct work_struct      start_task;
+ 	struct work_struct      reap_task;
+ 	struct work_struct      skb_task;
+ 	struct work_struct      rx_reap_task;
+ 	struct delayed_work     stale_task;
+ 	struct sk_buff_head     skb_queue;
+-	struct list_head        start_list;
+-	struct list_head        reap_list;
+-	struct ib_wc            ibwc[IPOIB_NUM_WC];
+-	struct ib_sge           rx_sge[IPOIB_CM_RX_SG];
++	struct list_head	start_list;
++	struct list_head	reap_list;
++	struct ib_wc		ibwc[IPOIB_NUM_WC];
++	struct ib_sge		rx_sge[IPOIB_CM_RX_SG];
+ 	struct ib_recv_wr       rx_wr;
++	int			nonsrq_conn_qp;
++	int			max_cm_mtu;
++	int			num_frags;
  };
  
-+static struct attribute_group *ehca_drv_attr_groups[] = {
-+	&ehca_drv_attr_grp,
-+	NULL,
-+};
-+
- #define EHCA_RESOURCE_ATTR(name)                                           \
- static ssize_t  ehca_show_##name(struct device *dev,                       \
- 				 struct device_attribute *attr,            \
-@@ -688,7 +694,7 @@ static int __devinit ehca_probe(struct of_device *dev,
- 	struct ehca_shca *shca;
- 	const u64 *handle;
- 	struct ib_pd *ibpd;
--	int ret;
-+	int ret, i;
+ /*
+@@ -269,30 +275,30 @@ struct ipoib_dev_priv {
+ 	struct work_struct pkey_event_task;
  
- 	handle = of_get_property(dev->node, "ibm,hca-handle", NULL);
- 	if (!handle) {
-@@ -709,6 +715,8 @@ static int __devinit ehca_probe(struct of_device *dev,
- 		return -ENOMEM;
- 	}
- 	mutex_init(&shca->modify_mutex);
-+	for (i = 0; i < ARRAY_SIZE(shca->sport); i++)
-+		spin_lock_init(&shca->sport[i].mod_sqp_lock);
+ 	struct ib_device *ca;
+-	u8            	  port;
+-	u16           	  pkey;
+-	u16               pkey_index;
+-	struct ib_pd  	 *pd;
+-	struct ib_mr  	 *mr;
+-	struct ib_cq  	 *cq;
+-	struct ib_qp  	 *qp;
+-	u32           	  qkey;
++	u8		  port;
++	u16		  pkey;
++	u16		  pkey_index;
++	struct ib_pd	 *pd;
++	struct ib_mr	 *mr;
++	struct ib_cq	 *cq;
++	struct ib_qp	 *qp;
++	u32		  qkey;
  
- 	shca->ofdev = dev;
- 	shca->ipz_hca_handle.handle = *handle;
-@@ -899,6 +907,9 @@ static struct of_platform_driver ehca_driver = {
- 	.match_table = ehca_device_table,
- 	.probe       = ehca_probe,
- 	.remove      = ehca_remove,
-+	.driver	     = {
-+		.groups = ehca_drv_attr_groups,
-+	},
- };
+ 	union ib_gid local_gid;
+-	u16          local_lid;
++	u16	     local_lid;
  
- void ehca_poll_eqs(unsigned long data)
-@@ -926,7 +937,7 @@ void ehca_poll_eqs(unsigned long data)
- 				ehca_process_eq(shca, 0);
- 		}
- 	}
--	mod_timer(&poll_eqs_timer, jiffies + HZ);
-+	mod_timer(&poll_eqs_timer, round_jiffies(jiffies + HZ));
- 	spin_unlock(&shca_list_lock);
- }
+ 	unsigned int admin_mtu;
+ 	unsigned int mcast_mtu;
  
-@@ -957,10 +968,6 @@ int __init ehca_module_init(void)
- 		goto module_init2;
- 	}
+ 	struct ipoib_rx_buf *rx_ring;
  
--	ret = sysfs_create_group(&ehca_driver.driver.kobj, &ehca_drv_attr_grp);
--	if (ret) /* only complain; we can live without attributes */
--		ehca_gen_err("Cannot create driver attributes  ret=%d", ret);
--
- 	if (ehca_poll_all_eqs != 1) {
- 		ehca_gen_err("WARNING!!!");
- 		ehca_gen_err("It is possible to lose interrupts.");
-@@ -986,7 +993,6 @@ void __exit ehca_module_exit(void)
- 	if (ehca_poll_all_eqs == 1)
- 		del_timer_sync(&poll_eqs_timer);
+-	spinlock_t           tx_lock;
++	spinlock_t	     tx_lock;
+ 	struct ipoib_tx_buf *tx_ring;
+-	unsigned             tx_head;
+-	unsigned             tx_tail;
+-	struct ib_sge        tx_sge;
++	unsigned	     tx_head;
++	unsigned	     tx_tail;
++	struct ib_sge	     tx_sge;
+ 	struct ib_send_wr    tx_wr;
+-	unsigned             tx_outstanding;
++	unsigned	     tx_outstanding;
  
--	sysfs_remove_group(&ehca_driver.driver.kobj, &ehca_drv_attr_grp);
- 	ibmebus_unregister_driver(&ehca_driver);
+ 	struct ib_wc ibwc[IPOIB_NUM_WC];
  
- 	ehca_destroy_slab_caches();
-diff --git a/drivers/infiniband/hw/ehca/ehca_qp.c b/drivers/infiniband/hw/ehca/ehca_qp.c
-index eff5fb5..1012f15 100644
---- a/drivers/infiniband/hw/ehca/ehca_qp.c
-+++ b/drivers/infiniband/hw/ehca/ehca_qp.c
-@@ -592,10 +592,8 @@ static struct ehca_qp *internal_create_qp(
- 		goto create_qp_exit1;
- 	}
+@@ -317,10 +323,10 @@ struct ipoib_dev_priv {
  
--	if (init_attr->sq_sig_type == IB_SIGNAL_ALL_WR)
--		parms.sigtype = HCALL_SIGT_EVERY;
--	else
--		parms.sigtype = HCALL_SIGT_BY_WQE;
-+	/* Always signal by WQE so we can hide circ. WQEs */
-+	parms.sigtype = HCALL_SIGT_BY_WQE;
+ struct ipoib_ah {
+ 	struct net_device *dev;
+-	struct ib_ah      *ah;
++	struct ib_ah	  *ah;
+ 	struct list_head   list;
+-	struct kref        ref;
+-	unsigned           last_send;
++	struct kref	   ref;
++	unsigned	   last_send;
+ };
  
- 	/* UD_AV CIRCUMVENTION */
- 	max_send_sge = init_attr->cap.max_send_sge;
-@@ -618,6 +616,10 @@ static struct ehca_qp *internal_create_qp(
- 	parms.squeue.max_sge = max_send_sge;
- 	parms.rqueue.max_sge = max_recv_sge;
+ struct ipoib_path {
+@@ -331,11 +337,11 @@ struct ipoib_path {
  
-+	/* RC QPs need one more SWQE for unsolicited ack circumvention */
-+	if (qp_type == IB_QPT_RC)
-+		parms.squeue.max_wr++;
-+
- 	if (EHCA_BMASK_GET(HCA_CAP_MINI_QP, shca->hca_cap)) {
- 		if (HAS_SQ(my_qp))
- 			ehca_determine_small_queue(
-@@ -650,6 +652,8 @@ static struct ehca_qp *internal_create_qp(
- 			parms.squeue.act_nr_sges = 1;
- 			parms.rqueue.act_nr_sges = 1;
- 		}
-+		/* hide the extra WQE */
-+		parms.squeue.act_nr_wqes--;
- 		break;
- 	case IB_QPT_UD:
- 	case IB_QPT_GSI:
-@@ -729,12 +733,31 @@ static struct ehca_qp *internal_create_qp(
- 	init_attr->cap.max_send_wr = parms.squeue.act_nr_wqes;
- 	my_qp->init_attr = *init_attr;
+ 	struct list_head      neigh_list;
  
-+	if (qp_type == IB_QPT_SMI || qp_type == IB_QPT_GSI) {
-+		shca->sport[init_attr->port_num - 1].ibqp_sqp[qp_type] =
-+			&my_qp->ib_qp;
-+		if (ehca_nr_ports < 0) {
-+			/* alloc array to cache subsequent modify qp parms
-+			 * for autodetect mode
-+			 */
-+			my_qp->mod_qp_parm =
-+				kzalloc(EHCA_MOD_QP_PARM_MAX *
-+					sizeof(*my_qp->mod_qp_parm),
-+					GFP_KERNEL);
-+			if (!my_qp->mod_qp_parm) {
-+				ehca_err(pd->device,
-+					 "Could not alloc mod_qp_parm");
-+				goto create_qp_exit4;
-+			}
-+		}
-+	}
-+
- 	/* NOTE: define_apq0() not supported yet */
- 	if (qp_type == IB_QPT_GSI) {
- 		h_ret = ehca_define_sqp(shca, my_qp, init_attr);
- 		if (h_ret != H_SUCCESS) {
- 			ret = ehca2ib_return_code(h_ret);
--			goto create_qp_exit4;
-+			goto create_qp_exit5;
- 		}
- 	}
+-	int                   query_id;
++	int		      query_id;
+ 	struct ib_sa_query   *query;
+ 	struct completion     done;
  
-@@ -743,7 +766,7 @@ static struct ehca_qp *internal_create_qp(
- 		if (ret) {
- 			ehca_err(pd->device,
- 				 "Couldn't assign qp to send_cq ret=%i", ret);
--			goto create_qp_exit4;
-+			goto create_qp_exit5;
- 		}
- 	}
+-	struct rb_node        rb_node;
++	struct rb_node	      rb_node;
+ 	struct list_head      list;
+ };
  
-@@ -769,12 +792,18 @@ static struct ehca_qp *internal_create_qp(
- 		if (ib_copy_to_udata(udata, &resp, sizeof resp)) {
- 			ehca_err(pd->device, "Copy to udata failed");
- 			ret = -EINVAL;
--			goto create_qp_exit4;
-+			goto create_qp_exit6;
- 		}
- 	}
+@@ -344,7 +350,7 @@ struct ipoib_neigh {
+ #ifdef CONFIG_INFINIBAND_IPOIB_CM
+ 	struct ipoib_cm_tx *cm;
+ #endif
+-	union ib_gid        dgid;
++	union ib_gid	    dgid;
+ 	struct sk_buff_head queue;
  
- 	return my_qp;
+ 	struct neighbour   *neighbour;
+@@ -455,12 +461,14 @@ void ipoib_drain_cq(struct net_device *dev);
  
-+create_qp_exit6:
-+	ehca_cq_unassign_qp(my_qp->send_cq, my_qp->real_qp_num);
-+
-+create_qp_exit5:
-+	kfree(my_qp->mod_qp_parm);
-+
- create_qp_exit4:
- 	if (HAS_RQ(my_qp))
- 		ipz_queue_dtor(my_pd, &my_qp->ipz_rqueue);
-@@ -858,7 +887,7 @@ struct ib_srq *ehca_create_srq(struct ib_pd *pd,
- 				update_mask,
- 				mqpcb, my_qp->galpas.kernel);
- 	if (hret != H_SUCCESS) {
--		ehca_err(pd->device, "Could not modify SRQ to INIT"
-+		ehca_err(pd->device, "Could not modify SRQ to INIT "
- 			 "ehca_qp=%p qp_num=%x h_ret=%li",
- 			 my_qp, my_qp->real_qp_num, hret);
- 		goto create_srq2;
-@@ -872,7 +901,7 @@ struct ib_srq *ehca_create_srq(struct ib_pd *pd,
- 				update_mask,
- 				mqpcb, my_qp->galpas.kernel);
- 	if (hret != H_SUCCESS) {
--		ehca_err(pd->device, "Could not enable SRQ"
-+		ehca_err(pd->device, "Could not enable SRQ "
- 			 "ehca_qp=%p qp_num=%x h_ret=%li",
- 			 my_qp, my_qp->real_qp_num, hret);
- 		goto create_srq2;
-@@ -886,7 +915,7 @@ struct ib_srq *ehca_create_srq(struct ib_pd *pd,
- 				update_mask,
- 				mqpcb, my_qp->galpas.kernel);
- 	if (hret != H_SUCCESS) {
--		ehca_err(pd->device, "Could not modify SRQ to RTR"
-+		ehca_err(pd->device, "Could not modify SRQ to RTR "
- 			 "ehca_qp=%p qp_num=%x h_ret=%li",
- 			 my_qp, my_qp->real_qp_num, hret);
- 		goto create_srq2;
-@@ -992,7 +1021,7 @@ static int internal_modify_qp(struct ib_qp *ibqp,
- 	unsigned long flags = 0;
+ #ifdef CONFIG_INFINIBAND_IPOIB_CM
  
- 	/* do query_qp to obtain current attr values */
--	mqpcb = ehca_alloc_fw_ctrlblock(GFP_KERNEL);
-+	mqpcb = ehca_alloc_fw_ctrlblock(GFP_ATOMIC);
- 	if (!mqpcb) {
- 		ehca_err(ibqp->device, "Could not get zeroed page for mqpcb "
- 			 "ehca_qp=%p qp_num=%x ", my_qp, ibqp->qp_num);
-@@ -1180,6 +1209,8 @@ static int internal_modify_qp(struct ib_qp *ibqp,
- 		update_mask |= EHCA_BMASK_SET(MQPCB_MASK_PRIM_P_KEY_IDX, 1);
- 	}
- 	if (attr_mask & IB_QP_PORT) {
-+		struct ehca_sport *sport;
-+		struct ehca_qp *aqp1;
- 		if (attr->port_num < 1 || attr->port_num > shca->num_ports) {
- 			ret = -EINVAL;
- 			ehca_err(ibqp->device, "Invalid port=%x. "
-@@ -1188,6 +1219,29 @@ static int internal_modify_qp(struct ib_qp *ibqp,
- 				 shca->num_ports);
- 			goto modify_qp_exit2;
- 		}
-+		sport = &shca->sport[attr->port_num - 1];
-+		if (!sport->ibqp_sqp[IB_QPT_GSI]) {
-+			/* should not occur */
-+			ret = -EFAULT;
-+			ehca_err(ibqp->device, "AQP1 was not created for "
-+				 "port=%x", attr->port_num);
-+			goto modify_qp_exit2;
-+		}
-+		aqp1 = container_of(sport->ibqp_sqp[IB_QPT_GSI],
-+				    struct ehca_qp, ib_qp);
-+		if (ibqp->qp_type != IB_QPT_GSI &&
-+		    ibqp->qp_type != IB_QPT_SMI &&
-+		    aqp1->mod_qp_parm) {
-+			/*
-+			 * firmware will reject this modify_qp() because
-+			 * port is not activated/initialized fully
-+			 */
-+			ret = -EFAULT;
-+			ehca_warn(ibqp->device, "Couldn't modify qp port=%x: "
-+				  "either port is being activated (try again) "
-+				  "or cabling issue", attr->port_num);
-+			goto modify_qp_exit2;
-+		}
- 		mqpcb->prim_phys_port = attr->port_num;
- 		update_mask |= EHCA_BMASK_SET(MQPCB_MASK_PRIM_PHYS_PORT, 1);
- 	}
-@@ -1244,6 +1298,8 @@ static int internal_modify_qp(struct ib_qp *ibqp,
- 	}
+-#define IPOIB_FLAGS_RC          0x80
+-#define IPOIB_FLAGS_UC          0x40
++#define IPOIB_FLAGS_RC		0x80
++#define IPOIB_FLAGS_UC		0x40
  
- 	if (attr_mask & IB_QP_PATH_MTU) {
-+		/* store ld(MTU) */
-+		my_qp->mtu_shift = attr->path_mtu + 7;
- 		mqpcb->path_mtu = attr->path_mtu;
- 		update_mask |= EHCA_BMASK_SET(MQPCB_MASK_PATH_MTU, 1);
- 	}
-@@ -1467,6 +1523,8 @@ modify_qp_exit1:
- int ehca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask,
- 		   struct ib_udata *udata)
- {
-+	struct ehca_shca *shca = container_of(ibqp->device, struct ehca_shca,
-+					      ib_device);
- 	struct ehca_qp *my_qp = container_of(ibqp, struct ehca_qp, ib_qp);
- 	struct ehca_pd *my_pd = container_of(my_qp->ib_qp.pd, struct ehca_pd,
- 					     ib_pd);
-@@ -1479,9 +1537,100 @@ int ehca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask,
- 		return -EINVAL;
- 	}
+ /* We don't support UC connections at the moment */
+ #define IPOIB_CM_SUPPORTED(ha)   (ha[0] & (IPOIB_FLAGS_RC))
  
-+	/* The if-block below caches qp_attr to be modified for GSI and SMI
-+	 * qps during the initialization by ib_mad. When the respective port
-+	 * is activated, ie we got an event PORT_ACTIVE, we'll replay the
-+	 * cached modify calls sequence, see ehca_recover_sqs() below.
-+	 * Why that is required:
-+	 * 1) If one port is connected, older code requires that port one
-+	 *    to be connected and module option nr_ports=1 to be given by
-+	 *    user, which is very inconvenient for end user.
-+	 * 2) Firmware accepts modify_qp() only if respective port has become
-+	 *    active. Older code had a wait loop of 30sec create_qp()/
-+	 *    define_aqp1(), which is not appropriate in practice. This
-+	 *    code now removes that wait loop, see define_aqp1(), and always
-+	 *    reports all ports to ib_mad resp. users. Only activated ports
-+	 *    will then usable for the users.
-+	 */
-+	if (ibqp->qp_type == IB_QPT_GSI || ibqp->qp_type == IB_QPT_SMI) {
-+		int port = my_qp->init_attr.port_num;
-+		struct ehca_sport *sport = &shca->sport[port - 1];
-+		unsigned long flags;
-+		spin_lock_irqsave(&sport->mod_sqp_lock, flags);
-+		/* cache qp_attr only during init */
-+		if (my_qp->mod_qp_parm) {
-+			struct ehca_mod_qp_parm *p;
-+			if (my_qp->mod_qp_parm_idx >= EHCA_MOD_QP_PARM_MAX) {
-+				ehca_err(&shca->ib_device,
-+					 "mod_qp_parm overflow state=%x port=%x"
-+					 " type=%x", attr->qp_state,
-+					 my_qp->init_attr.port_num,
-+					 ibqp->qp_type);
-+				spin_unlock_irqrestore(&sport->mod_sqp_lock,
-+						       flags);
-+				return -EINVAL;
-+			}
-+			p = &my_qp->mod_qp_parm[my_qp->mod_qp_parm_idx];
-+			p->mask = attr_mask;
-+			p->attr = *attr;
-+			my_qp->mod_qp_parm_idx++;
-+			ehca_dbg(&shca->ib_device,
-+				 "Saved qp_attr for state=%x port=%x type=%x",
-+				 attr->qp_state, my_qp->init_attr.port_num,
-+				 ibqp->qp_type);
-+			spin_unlock_irqrestore(&sport->mod_sqp_lock, flags);
-+			return 0;
-+		}
-+		spin_unlock_irqrestore(&sport->mod_sqp_lock, flags);
-+	}
++extern int ipoib_max_conn_qp;
 +
- 	return internal_modify_qp(ibqp, attr, attr_mask, 0);
+ static inline int ipoib_cm_admin_enabled(struct net_device *dev)
+ {
+ 	struct ipoib_dev_priv *priv = netdev_priv(dev);
+@@ -491,6 +499,18 @@ static inline void ipoib_cm_set(struct ipoib_neigh *neigh, struct ipoib_cm_tx *t
+ 	neigh->cm = tx;
  }
  
-+void ehca_recover_sqp(struct ib_qp *sqp)
++static inline int ipoib_cm_has_srq(struct net_device *dev)
 +{
-+	struct ehca_qp *my_sqp = container_of(sqp, struct ehca_qp, ib_qp);
-+	int port = my_sqp->init_attr.port_num;
-+	struct ib_qp_attr attr;
-+	struct ehca_mod_qp_parm *qp_parm;
-+	int i, qp_parm_idx, ret;
-+	unsigned long flags, wr_cnt;
-+
-+	if (!my_sqp->mod_qp_parm)
-+		return;
-+	ehca_dbg(sqp->device, "SQP port=%x qp_num=%x", port, sqp->qp_num);
-+
-+	qp_parm = my_sqp->mod_qp_parm;
-+	qp_parm_idx = my_sqp->mod_qp_parm_idx;
-+	for (i = 0; i < qp_parm_idx; i++) {
-+		attr = qp_parm[i].attr;
-+		ret = internal_modify_qp(sqp, &attr, qp_parm[i].mask, 0);
-+		if (ret) {
-+			ehca_err(sqp->device, "Could not modify SQP port=%x "
-+				 "qp_num=%x ret=%x", port, sqp->qp_num, ret);
-+			goto free_qp_parm;
-+		}
-+		ehca_dbg(sqp->device, "SQP port=%x qp_num=%x in state=%x",
-+			 port, sqp->qp_num, attr.qp_state);
-+	}
-+
-+	/* re-trigger posted recv wrs */
-+	wr_cnt =  my_sqp->ipz_rqueue.current_q_offset /
-+		my_sqp->ipz_rqueue.qe_size;
-+	if (wr_cnt) {
-+		spin_lock_irqsave(&my_sqp->spinlock_r, flags);
-+		hipz_update_rqa(my_sqp, wr_cnt);
-+		spin_unlock_irqrestore(&my_sqp->spinlock_r, flags);
-+		ehca_dbg(sqp->device, "doorbell port=%x qp_num=%x wr_cnt=%lx",
-+			 port, sqp->qp_num, wr_cnt);
-+	}
++	struct ipoib_dev_priv *priv = netdev_priv(dev);
++	return !!priv->cm.srq;
++}
 +
-+free_qp_parm:
-+	kfree(qp_parm);
-+	/* this prevents subsequent calls to modify_qp() to cache qp_attr */
-+	my_sqp->mod_qp_parm = NULL;
++static inline unsigned int ipoib_cm_max_mtu(struct net_device *dev)
++{
++	struct ipoib_dev_priv *priv = netdev_priv(dev);
++	return priv->cm.max_cm_mtu;
 +}
 +
- int ehca_query_qp(struct ib_qp *qp,
- 		  struct ib_qp_attr *qp_attr,
- 		  int qp_attr_mask, struct ib_qp_init_attr *qp_init_attr)
-@@ -1769,6 +1918,7 @@ static int internal_destroy_qp(struct ib_device *dev, struct ehca_qp *my_qp,
- 	struct ehca_shca *shca = container_of(dev, struct ehca_shca, ib_device);
- 	struct ehca_pd *my_pd = container_of(my_qp->ib_qp.pd, struct ehca_pd,
- 					     ib_pd);
-+	struct ehca_sport *sport = &shca->sport[my_qp->init_attr.port_num - 1];
- 	u32 cur_pid = current->tgid;
- 	u32 qp_num = my_qp->real_qp_num;
- 	int ret;
-@@ -1815,6 +1965,14 @@ static int internal_destroy_qp(struct ib_device *dev, struct ehca_qp *my_qp,
- 	port_num = my_qp->init_attr.port_num;
- 	qp_type  = my_qp->init_attr.qp_type;
+ void ipoib_cm_send(struct net_device *dev, struct sk_buff *skb, struct ipoib_cm_tx *tx);
+ int ipoib_cm_dev_open(struct net_device *dev);
+ void ipoib_cm_dev_stop(struct net_device *dev);
+@@ -500,7 +520,7 @@ void ipoib_cm_dev_cleanup(struct net_device *dev);
+ struct ipoib_cm_tx *ipoib_cm_create_tx(struct net_device *dev, struct ipoib_path *path,
+ 				    struct ipoib_neigh *neigh);
+ void ipoib_cm_destroy_tx(struct ipoib_cm_tx *tx);
+-void ipoib_cm_skb_too_long(struct net_device* dev, struct sk_buff *skb,
++void ipoib_cm_skb_too_long(struct net_device *dev, struct sk_buff *skb,
+ 			   unsigned int mtu);
+ void ipoib_cm_handle_rx_wc(struct net_device *dev, struct ib_wc *wc);
+ void ipoib_cm_handle_tx_wc(struct net_device *dev, struct ib_wc *wc);
+@@ -508,6 +528,8 @@ void ipoib_cm_handle_tx_wc(struct net_device *dev, struct ib_wc *wc);
  
-+	if (qp_type == IB_QPT_SMI || qp_type == IB_QPT_GSI) {
-+		spin_lock_irqsave(&sport->mod_sqp_lock, flags);
-+		kfree(my_qp->mod_qp_parm);
-+		my_qp->mod_qp_parm = NULL;
-+		shca->sport[port_num - 1].ibqp_sqp[qp_type] = NULL;
-+		spin_unlock_irqrestore(&sport->mod_sqp_lock, flags);
-+	}
-+
- 	/* no support for IB_QPT_SMI yet */
- 	if (qp_type == IB_QPT_GSI) {
- 		struct ib_event event;
-diff --git a/drivers/infiniband/hw/ehca/ehca_reqs.c b/drivers/infiniband/hw/ehca/ehca_reqs.c
-index ea91360..3aacc8c 100644
---- a/drivers/infiniband/hw/ehca/ehca_reqs.c
-+++ b/drivers/infiniband/hw/ehca/ehca_reqs.c
-@@ -50,6 +50,9 @@
- #include "hcp_if.h"
- #include "hipz_fns.h"
+ struct ipoib_cm_tx;
  
-+/* in RC traffic, insert an empty RDMA READ every this many packets */
-+#define ACK_CIRC_THRESHOLD 2000000
++#define ipoib_max_conn_qp 0
 +
- static inline int ehca_write_rwqe(struct ipz_queue *ipz_rqueue,
- 				  struct ehca_wqe *wqe_p,
- 				  struct ib_recv_wr *recv_wr)
-@@ -81,7 +84,7 @@ static inline int ehca_write_rwqe(struct ipz_queue *ipz_rqueue,
- 	if (ehca_debug_level) {
- 		ehca_gen_dbg("RECEIVE WQE written into ipz_rqueue=%p",
- 			     ipz_rqueue);
--		ehca_dmp( wqe_p, 16*(6 + wqe_p->nr_of_data_seg), "recv wqe");
-+		ehca_dmp(wqe_p, 16*(6 + wqe_p->nr_of_data_seg), "recv wqe");
- 	}
- 
+ static inline int ipoib_cm_admin_enabled(struct net_device *dev)
+ {
  	return 0;
-@@ -135,7 +138,8 @@ static void trace_send_wr_ud(const struct ib_send_wr *send_wr)
- 
- static inline int ehca_write_swqe(struct ehca_qp *qp,
- 				  struct ehca_wqe *wqe_p,
--				  const struct ib_send_wr *send_wr)
-+				  const struct ib_send_wr *send_wr,
-+				  int hidden)
+@@ -533,6 +555,16 @@ static inline void ipoib_cm_set(struct ipoib_neigh *neigh, struct ipoib_cm_tx *t
  {
- 	u32 idx;
- 	u64 dma_length;
-@@ -176,7 +180,9 @@ static inline int ehca_write_swqe(struct ehca_qp *qp,
- 
- 	wqe_p->wr_flag = 0;
- 
--	if (send_wr->send_flags & IB_SEND_SIGNALED)
-+	if ((send_wr->send_flags & IB_SEND_SIGNALED ||
-+	    qp->init_attr.sq_sig_type == IB_SIGNAL_ALL_WR)
-+	    && !hidden)
- 		wqe_p->wr_flag |= WQE_WRFLAG_REQ_SIGNAL_COM;
- 
- 	if (send_wr->opcode == IB_WR_SEND_WITH_IMM ||
-@@ -199,7 +205,7 @@ static inline int ehca_write_swqe(struct ehca_qp *qp,
- 
- 		wqe_p->destination_qp_number = send_wr->wr.ud.remote_qpn << 8;
- 		wqe_p->local_ee_context_qkey = remote_qkey;
--		if (!send_wr->wr.ud.ah) {
-+		if (unlikely(!send_wr->wr.ud.ah)) {
- 			ehca_gen_err("wr.ud.ah is NULL. qp=%p", qp);
- 			return -EINVAL;
- 		}
-@@ -255,6 +261,15 @@ static inline int ehca_write_swqe(struct ehca_qp *qp,
- 		} /* eof idx */
- 		wqe_p->u.nud.atomic_1st_op_dma_len = dma_length;
- 
-+		/* unsolicited ack circumvention */
-+		if (send_wr->opcode == IB_WR_RDMA_READ) {
-+			/* on RDMA read, switch on and reset counters */
-+			qp->message_count = qp->packet_count = 0;
-+			qp->unsol_ack_circ = 1;
-+		} else
-+			/* else estimate #packets */
-+			qp->packet_count += (dma_length >> qp->mtu_shift) + 1;
-+
- 		break;
- 
- 	default:
-@@ -355,13 +370,49 @@ static inline void map_ib_wc_status(u32 cqe_status,
- 		*wc_status = IB_WC_SUCCESS;
  }
  
-+static inline int post_one_send(struct ehca_qp *my_qp,
-+			 struct ib_send_wr *cur_send_wr,
-+			 struct ib_send_wr **bad_send_wr,
-+			 int hidden)
++static inline int ipoib_cm_has_srq(struct net_device *dev)
 +{
-+	struct ehca_wqe *wqe_p;
-+	int ret;
-+	u64 start_offset = my_qp->ipz_squeue.current_q_offset;
-+
-+	/* get pointer next to free WQE */
-+	wqe_p = ipz_qeit_get_inc(&my_qp->ipz_squeue);
-+	if (unlikely(!wqe_p)) {
-+		/* too many posted work requests: queue overflow */
-+		if (bad_send_wr)
-+			*bad_send_wr = cur_send_wr;
-+		ehca_err(my_qp->ib_qp.device, "Too many posted WQEs "
-+			 "qp_num=%x", my_qp->ib_qp.qp_num);
-+		return -ENOMEM;
-+	}
-+	/* write a SEND WQE into the QUEUE */
-+	ret = ehca_write_swqe(my_qp, wqe_p, cur_send_wr, hidden);
-+	/*
-+	 * if something failed,
-+	 * reset the free entry pointer to the start value
-+	 */
-+	if (unlikely(ret)) {
-+		my_qp->ipz_squeue.current_q_offset = start_offset;
-+		if (bad_send_wr)
-+			*bad_send_wr = cur_send_wr;
-+		ehca_err(my_qp->ib_qp.device, "Could not write WQE "
-+			 "qp_num=%x", my_qp->ib_qp.qp_num);
-+		return -EINVAL;
-+	}
++	return 0;
++}
 +
++static inline unsigned int ipoib_cm_max_mtu(struct net_device *dev)
++{
 +	return 0;
 +}
 +
- int ehca_post_send(struct ib_qp *qp,
- 		   struct ib_send_wr *send_wr,
- 		   struct ib_send_wr **bad_send_wr)
+ static inline
+ void ipoib_cm_send(struct net_device *dev, struct sk_buff *skb, struct ipoib_cm_tx *tx)
  {
- 	struct ehca_qp *my_qp = container_of(qp, struct ehca_qp, ib_qp);
- 	struct ib_send_wr *cur_send_wr;
--	struct ehca_wqe *wqe_p;
- 	int wqe_cnt = 0;
- 	int ret = 0;
- 	unsigned long flags;
-@@ -369,37 +420,33 @@ int ehca_post_send(struct ib_qp *qp,
- 	/* LOCK the QUEUE */
- 	spin_lock_irqsave(&my_qp->spinlock_s, flags);
- 
-+	/* Send an empty extra RDMA read if:
-+	 *  1) there has been an RDMA read on this connection before
-+	 *  2) no RDMA read occurred for ACK_CIRC_THRESHOLD link packets
-+	 *  3) we can be sure that any previous extra RDMA read has been
-+	 *     processed so we don't overflow the SQ
-+	 */
-+	if (unlikely(my_qp->unsol_ack_circ &&
-+		     my_qp->packet_count > ACK_CIRC_THRESHOLD &&
-+		     my_qp->message_count > my_qp->init_attr.cap.max_send_wr)) {
-+		/* insert an empty RDMA READ to fix up the remote QP state */
-+		struct ib_send_wr circ_wr;
-+		memset(&circ_wr, 0, sizeof(circ_wr));
-+		circ_wr.opcode = IB_WR_RDMA_READ;
-+		post_one_send(my_qp, &circ_wr, NULL, 1); /* ignore retcode */
-+		wqe_cnt++;
-+		ehca_dbg(qp->device, "posted circ wr  qp_num=%x", qp->qp_num);
-+		my_qp->message_count = my_qp->packet_count = 0;
-+	}
-+
- 	/* loop processes list of send reqs */
- 	for (cur_send_wr = send_wr; cur_send_wr != NULL;
- 	     cur_send_wr = cur_send_wr->next) {
--		u64 start_offset = my_qp->ipz_squeue.current_q_offset;
--		/* get pointer next to free WQE */
--		wqe_p = ipz_qeit_get_inc(&my_qp->ipz_squeue);
--		if (unlikely(!wqe_p)) {
--			/* too many posted work requests: queue overflow */
--			if (bad_send_wr)
--				*bad_send_wr = cur_send_wr;
--			if (wqe_cnt == 0) {
--				ret = -ENOMEM;
--				ehca_err(qp->device, "Too many posted WQEs "
--					 "qp_num=%x", qp->qp_num);
--			}
--			goto post_send_exit0;
--		}
--		/* write a SEND WQE into the QUEUE */
--		ret = ehca_write_swqe(my_qp, wqe_p, cur_send_wr);
--		/*
--		 * if something failed,
--		 * reset the free entry pointer to the start value
--		 */
-+		ret = post_one_send(my_qp, cur_send_wr, bad_send_wr, 0);
- 		if (unlikely(ret)) {
--			my_qp->ipz_squeue.current_q_offset = start_offset;
--			*bad_send_wr = cur_send_wr;
--			if (wqe_cnt == 0) {
--				ret = -EINVAL;
--				ehca_err(qp->device, "Could not write WQE "
--					 "qp_num=%x", qp->qp_num);
--			}
-+			/* if one or more WQEs were successful, don't fail */
-+			if (wqe_cnt)
-+				ret = 0;
- 			goto post_send_exit0;
- 		}
- 		wqe_cnt++;
-@@ -410,6 +457,7 @@ int ehca_post_send(struct ib_qp *qp,
- post_send_exit0:
- 	iosync(); /* serialize GAL register access */
- 	hipz_update_sqa(my_qp, wqe_cnt);
-+	my_qp->message_count += wqe_cnt;
- 	spin_unlock_irqrestore(&my_qp->spinlock_s, flags);
- 	return ret;
+@@ -582,7 +614,7 @@ int ipoib_cm_add_mode_attr(struct net_device *dev)
+ 	return 0;
  }
-diff --git a/drivers/infiniband/hw/ehca/ehca_sqp.c b/drivers/infiniband/hw/ehca/ehca_sqp.c
-index f0792e5..79e72b2 100644
---- a/drivers/infiniband/hw/ehca/ehca_sqp.c
-+++ b/drivers/infiniband/hw/ehca/ehca_sqp.c
-@@ -40,11 +40,8 @@
-  */
  
+-static inline void ipoib_cm_skb_too_long(struct net_device* dev, struct sk_buff *skb,
++static inline void ipoib_cm_skb_too_long(struct net_device *dev, struct sk_buff *skb,
+ 					 unsigned int mtu)
+ {
+ 	dev_kfree_skb_any(skb);
+@@ -624,12 +656,12 @@ extern struct ib_sa_client ipoib_sa_client;
+ extern int ipoib_debug_level;
  
--#include <linux/module.h>
--#include <linux/err.h>
- #include "ehca_classes.h"
- #include "ehca_tools.h"
--#include "ehca_qes.h"
- #include "ehca_iverbs.h"
- #include "hcp_if.h"
+ #define ipoib_dbg(priv, format, arg...)			\
+-	do {					        \
++	do {						\
+ 		if (ipoib_debug_level > 0)			\
+ 			ipoib_printk(KERN_DEBUG, priv, format , ## arg); \
+ 	} while (0)
+ #define ipoib_dbg_mcast(priv, format, arg...)		\
+-	do {					        \
++	do {						\
+ 		if (mcast_debug_level > 0)		\
+ 			ipoib_printk(KERN_DEBUG, priv, format , ## arg); \
+ 	} while (0)
+@@ -642,7 +674,7 @@ extern int ipoib_debug_level;
  
-@@ -93,6 +90,9 @@ u64 ehca_define_sqp(struct ehca_shca *shca,
- 		return H_PARAMETER;
- 	}
+ #ifdef CONFIG_INFINIBAND_IPOIB_DEBUG_DATA
+ #define ipoib_dbg_data(priv, format, arg...)		\
+-	do {					        \
++	do {						\
+ 		if (data_debug_level > 0)		\
+ 			ipoib_printk(KERN_DEBUG, priv, format , ## arg); \
+ 	} while (0)
+diff --git a/drivers/infiniband/ulp/ipoib/ipoib_cm.c b/drivers/infiniband/ulp/ipoib/ipoib_cm.c
+index 059cf92..1818f95 100644
+--- a/drivers/infiniband/ulp/ipoib/ipoib_cm.c
++++ b/drivers/infiniband/ulp/ipoib/ipoib_cm.c
+@@ -39,6 +39,15 @@
+ #include <linux/icmpv6.h>
+ #include <linux/delay.h>
  
-+	if (ehca_nr_ports < 0) /* autodetect mode */
-+		return H_SUCCESS;
++#include "ipoib.h"
 +
- 	for (counter = 0;
- 	     shca->sport[port - 1].port_state != IB_PORT_ACTIVE &&
- 		     counter < ehca_port_act_time;
-diff --git a/drivers/infiniband/hw/ipath/ipath_common.h b/drivers/infiniband/hw/ipath/ipath_common.h
-index 851df8a..4146210 100644
---- a/drivers/infiniband/hw/ipath/ipath_common.h
-+++ b/drivers/infiniband/hw/ipath/ipath_common.h
-@@ -82,6 +82,16 @@
- #define IPATH_IB_LINK_EXTERNAL	7 /* normal, disable local loopback */
- 
- /*
-+ * These 3 values (SDR and DDR may be ORed for auto-speed
-+ * negotiation) are used for the 3rd argument to path_f_set_ib_cfg
-+ * with cmd IPATH_IB_CFG_SPD_ENB, by direct calls or via sysfs.  They
-+ * are also the the possible values for ipath_link_speed_enabled and active
-+ * The values were chosen to match values used within the IB spec.
-+ */
-+#define IPATH_IB_SDR 1
-+#define IPATH_IB_DDR 2
++int ipoib_max_conn_qp = 128;
 +
-+/*
-  * stats maintained by the driver.  For now, at least, this is global
-  * to all minor devices.
-  */
-@@ -433,8 +443,9 @@ struct ipath_user_info {
- #define IPATH_CMD_UNUSED_2	26
- #define IPATH_CMD_PIOAVAILUPD	27	/* force an update of PIOAvail reg */
- #define IPATH_CMD_POLL_TYPE	28	/* set the kind of polling we want */
-+#define IPATH_CMD_ARMLAUNCH_CTRL	29 /* armlaunch detection control */
- 
--#define IPATH_CMD_MAX		28
-+#define IPATH_CMD_MAX		29
- 
- /*
-  * Poll types
-@@ -477,6 +488,8 @@ struct ipath_cmd {
- 		__u64 port_info;
- 		/* enable/disable receipt of packets */
- 		__u32 recv_ctrl;
-+		/* enable/disable armlaunch errors (non-zero to enable) */
-+		__u32 armlaunch_ctrl;
- 		/* partition key to set */
- 		__u16 part_key;
- 		/* user address of __u32 bitmask of active slaves */
-@@ -579,7 +592,7 @@ struct ipath_flash {
- struct infinipath_counters {
- 	__u64 LBIntCnt;
- 	__u64 LBFlowStallCnt;
--	__u64 Reserved1;
-+	__u64 TxSDmaDescCnt;	/* was Reserved1 */
- 	__u64 TxUnsupVLErrCnt;
- 	__u64 TxDataPktCnt;
- 	__u64 TxFlowPktCnt;
-@@ -615,12 +628,26 @@ struct infinipath_counters {
- 	__u64 RxP6HdrEgrOvflCnt;
- 	__u64 RxP7HdrEgrOvflCnt;
- 	__u64 RxP8HdrEgrOvflCnt;
--	__u64 Reserved6;
--	__u64 Reserved7;
-+	__u64 RxP9HdrEgrOvflCnt;	/* was Reserved6 */
-+	__u64 RxP10HdrEgrOvflCnt;	/* was Reserved7 */
-+	__u64 RxP11HdrEgrOvflCnt;	/* new for IBA7220 */
-+	__u64 RxP12HdrEgrOvflCnt;	/* new for IBA7220 */
-+	__u64 RxP13HdrEgrOvflCnt;	/* new for IBA7220 */
-+	__u64 RxP14HdrEgrOvflCnt;	/* new for IBA7220 */
-+	__u64 RxP15HdrEgrOvflCnt;	/* new for IBA7220 */
-+	__u64 RxP16HdrEgrOvflCnt;	/* new for IBA7220 */
- 	__u64 IBStatusChangeCnt;
- 	__u64 IBLinkErrRecoveryCnt;
- 	__u64 IBLinkDownedCnt;
- 	__u64 IBSymbolErrCnt;
-+	/* The following are new for IBA7220 */
-+	__u64 RxVL15DroppedPktCnt;
-+	__u64 RxOtherLocalPhyErrCnt;
-+	__u64 PcieRetryBufDiagQwordCnt;
-+	__u64 ExcessBufferOvflCnt;
-+	__u64 LocalLinkIntegrityErrCnt;
-+	__u64 RxVlErrCnt;
-+	__u64 RxDlidFltrCnt;
- };
- 
- /*
-diff --git a/drivers/infiniband/hw/ipath/ipath_cq.c b/drivers/infiniband/hw/ipath/ipath_cq.c
-index d1380c7..a03bd28 100644
---- a/drivers/infiniband/hw/ipath/ipath_cq.c
-+++ b/drivers/infiniband/hw/ipath/ipath_cq.c
-@@ -421,7 +421,7 @@ int ipath_resize_cq(struct ib_cq *ibcq, int cqe, struct ib_udata *udata)
- 	else
- 		n = head - tail;
- 	if (unlikely((u32)cqe < n)) {
--		ret = -EOVERFLOW;
-+		ret = -EINVAL;
- 		goto bail_unlock;
- 	}
- 	for (n = 0; tail != head; n++) {
-diff --git a/drivers/infiniband/hw/ipath/ipath_debug.h b/drivers/infiniband/hw/ipath/ipath_debug.h
-index 19c56e6..d6f6953 100644
---- a/drivers/infiniband/hw/ipath/ipath_debug.h
-+++ b/drivers/infiniband/hw/ipath/ipath_debug.h
-@@ -55,7 +55,7 @@
- #define __IPATH_PKTDBG      0x80	/* print packet data */
- /* print process startup (init)/exit messages */
- #define __IPATH_PROCDBG     0x100
--/* print mmap/nopage stuff, not using VDBG any more */
-+/* print mmap/fault stuff, not using VDBG any more */
- #define __IPATH_MMDBG       0x200
- #define __IPATH_ERRPKTDBG   0x400
- #define __IPATH_USER_SEND   0x1000	/* use user mode send */
-@@ -81,7 +81,7 @@
- #define __IPATH_VERBDBG   0x0	/* very verbose debug */
- #define __IPATH_PKTDBG    0x0	/* print packet data */
- #define __IPATH_PROCDBG   0x0	/* process startup (init)/exit messages */
--/* print mmap/nopage stuff, not using VDBG any more */
-+/* print mmap/fault stuff, not using VDBG any more */
- #define __IPATH_MMDBG     0x0
- #define __IPATH_EPKTDBG   0x0	/* print ethernet packet data */
- #define __IPATH_IPATHDBG  0x0	/* Ethernet (IPATH) table dump on */
-diff --git a/drivers/infiniband/hw/ipath/ipath_driver.c b/drivers/infiniband/hw/ipath/ipath_driver.c
-index 1f152de..d5ff6ca 100644
---- a/drivers/infiniband/hw/ipath/ipath_driver.c
-+++ b/drivers/infiniband/hw/ipath/ipath_driver.c
-@@ -121,6 +121,9 @@ static struct pci_driver ipath_driver = {
- 	.probe = ipath_init_one,
- 	.remove = __devexit_p(ipath_remove_one),
- 	.id_table = ipath_pci_tbl,
-+	.driver = {
-+		.groups = ipath_driver_attr_groups,
-+	},
- };
- 
- static void ipath_check_status(struct work_struct *work)
-@@ -331,6 +334,8 @@ static void ipath_verify_pioperf(struct ipath_devdata *dd)
- 		udelay(1);
- 	}
- 
-+	ipath_disable_armlaunch(dd);
++module_param_named(max_nonsrq_conn_qp, ipoib_max_conn_qp, int, 0444);
++MODULE_PARM_DESC(max_nonsrq_conn_qp,
++		 "Max number of connected-mode QPs per interface "
++		 "(applied only if shared receive queue is not available)");
 +
- 	writeq(0, piobuf); /* length 0, no dwords actually sent */
- 	ipath_flush_wc();
- 
-@@ -362,6 +367,7 @@ static void ipath_verify_pioperf(struct ipath_devdata *dd)
- done:
- 	/* disarm piobuf, so it's available again */
- 	ipath_disarm_piobufs(dd, pbnum, 1);
-+	ipath_enable_armlaunch(dd);
- }
- 
- static int __devinit ipath_init_one(struct pci_dev *pdev,
-@@ -800,31 +806,37 @@ void ipath_disarm_piobufs(struct ipath_devdata *dd, unsigned first,
- 			  unsigned cnt)
- {
- 	unsigned i, last = first + cnt;
--	u64 sendctrl, sendorig;
-+	unsigned long flags;
- 
- 	ipath_cdbg(PKT, "disarm %u PIObufs first=%u\n", cnt, first);
--	sendorig = dd->ipath_sendctrl;
- 	for (i = first; i < last; i++) {
--		sendctrl = sendorig  | INFINIPATH_S_DISARM |
--			(i << INFINIPATH_S_DISARMPIOBUF_SHIFT);
-+		spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags);
-+		/*
-+		 * The disarm-related bits are write-only, so it
-+		 * is ok to OR them in with our copy of sendctrl
-+		 * while we hold the lock.
-+		 */
- 		ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
--				 sendctrl);
-+			dd->ipath_sendctrl | INFINIPATH_S_DISARM |
-+			(i << INFINIPATH_S_DISARMPIOBUF_SHIFT));
-+		/* can't disarm bufs back-to-back per iba7220 spec */
-+		ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
-+		spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags);
- 	}
- 
- 	/*
--	 * Write it again with current value, in case ipath_sendctrl changed
--	 * while we were looping; no critical bits that would require
--	 * locking.
--	 *
--	 * disable PIOAVAILUPD, then re-enable, reading scratch in
-+	 * Disable PIOAVAILUPD, then re-enable, reading scratch in
- 	 * between.  This seems to avoid a chip timing race that causes
--	 * pioavail updates to memory to stop.
-+	 * pioavail updates to memory to stop.  We xor as we don't
-+	 * know the state of the bit when we're called.
- 	 */
-+	spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags);
- 	ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
--			 sendorig & ~INFINIPATH_S_PIOBUFAVAILUPD);
--	sendorig = ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
-+		dd->ipath_sendctrl ^ INFINIPATH_S_PIOBUFAVAILUPD);
-+	ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
- 	ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
- 			 dd->ipath_sendctrl);
-+	spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags);
- }
- 
- /**
-@@ -1000,12 +1012,10 @@ static void get_rhf_errstring(u32 err, char *msg, size_t len)
-  * ipath_get_egrbuf - get an eager buffer
-  * @dd: the infinipath device
-  * @bufnum: the eager buffer to get
-- * @err: unused
-  *
-  * must only be called if ipath_pd[port] is known to be allocated
-  */
--static inline void *ipath_get_egrbuf(struct ipath_devdata *dd, u32 bufnum,
--				     int err)
-+static inline void *ipath_get_egrbuf(struct ipath_devdata *dd, u32 bufnum)
- {
- 	return dd->ipath_port0_skbinfo ?
- 		(void *) dd->ipath_port0_skbinfo[bufnum].skb->data : NULL;
-@@ -1097,13 +1107,14 @@ static void ipath_rcv_hdrerr(struct ipath_devdata *dd,
+ #ifdef CONFIG_INFINIBAND_IPOIB_DEBUG_DATA
+ static int data_debug_level;
  
- /*
-  * ipath_kreceive - receive a packet
-- * @dd: the infinipath device
-+ * @pd: the infinipath port
-  *
-  * called from interrupt handler for errors or receive interrupt
-  */
--void ipath_kreceive(struct ipath_devdata *dd)
-+void ipath_kreceive(struct ipath_portdata *pd)
- {
- 	u64 *rc;
-+	struct ipath_devdata *dd = pd->port_dd;
- 	void *ebuf;
- 	const u32 rsize = dd->ipath_rcvhdrentsize;	/* words */
- 	const u32 maxcnt = dd->ipath_rcvhdrcnt * rsize;	/* words */
-@@ -1118,8 +1129,8 @@ void ipath_kreceive(struct ipath_devdata *dd)
- 		goto bail;
- 	}
+@@ -47,8 +56,6 @@ MODULE_PARM_DESC(cm_data_debug_level,
+ 		 "Enable data path debug tracing for connected mode if > 0");
+ #endif
  
--	l = dd->ipath_port0head;
--	hdrqtail = (u32) le64_to_cpu(*dd->ipath_hdrqtailptr);
-+	l = pd->port_head;
-+	hdrqtail = ipath_get_rcvhdrtail(pd);
- 	if (l == hdrqtail)
- 		goto bail;
+-#include "ipoib.h"
+-
+ #define IPOIB_CM_IETF_ID 0x1000000000000000ULL
  
-@@ -1128,7 +1139,7 @@ reloop:
- 		u32 qp;
- 		u8 *bthbytes;
+ #define IPOIB_CM_RX_UPDATE_TIME (256 * HZ)
+@@ -81,7 +88,7 @@ static void ipoib_cm_dma_unmap_rx(struct ipoib_dev_priv *priv, int frags,
+ 		ib_dma_unmap_single(priv->ca, mapping[i + 1], PAGE_SIZE, DMA_FROM_DEVICE);
+ }
  
--		rc = (u64 *) (dd->ipath_pd[0]->port_rcvhdrq + (l << 2));
-+		rc = (u64 *) (pd->port_rcvhdrq + (l << 2));
- 		hdr = (struct ipath_message_header *)&rc[1];
- 		/*
- 		 * could make a network order version of IPATH_KD_QP, and
-@@ -1153,7 +1164,7 @@ reloop:
- 			etail = ipath_hdrget_index((__le32 *) rc);
- 			if (tlen > sizeof(*hdr) ||
- 			    etype == RCVHQ_RCV_TYPE_NON_KD)
--				ebuf = ipath_get_egrbuf(dd, etail, 0);
-+				ebuf = ipath_get_egrbuf(dd, etail);
- 		}
+-static int ipoib_cm_post_receive(struct net_device *dev, int id)
++static int ipoib_cm_post_receive_srq(struct net_device *dev, int id)
+ {
+ 	struct ipoib_dev_priv *priv = netdev_priv(dev);
+ 	struct ib_recv_wr *bad_wr;
+@@ -89,13 +96,13 @@ static int ipoib_cm_post_receive(struct net_device *dev, int id)
  
- 		/*
-@@ -1188,7 +1199,7 @@ reloop:
- 				  be32_to_cpu(hdr->bth[0]) & 0xff);
- 		else {
- 			/*
--			 * error packet, type of error	unknown.
-+			 * error packet, type of error unknown.
- 			 * Probably type 3, but we don't know, so don't
- 			 * even try to print the opcode, etc.
- 			 */
-@@ -1238,7 +1249,7 @@ reloop:
- 		 * earlier packets, we "almost" guarantee we have covered
- 		 * that case.
- 		 */
--		u32 hqtail = (u32)le64_to_cpu(*dd->ipath_hdrqtailptr);
-+		u32 hqtail = ipath_get_rcvhdrtail(pd);
- 		if (hqtail != hdrqtail) {
- 			hdrqtail = hqtail;
- 			reloop = 1; /* loop 1 extra time at most */
-@@ -1248,7 +1259,7 @@ reloop:
+ 	priv->cm.rx_wr.wr_id = id | IPOIB_OP_CM | IPOIB_OP_RECV;
  
- 	pkttot += i;
+-	for (i = 0; i < IPOIB_CM_RX_SG; ++i)
++	for (i = 0; i < priv->cm.num_frags; ++i)
+ 		priv->cm.rx_sge[i].addr = priv->cm.srq_ring[id].mapping[i];
  
--	dd->ipath_port0head = l;
-+	pd->port_head = l;
+ 	ret = ib_post_srq_recv(priv->cm.srq, &priv->cm.rx_wr, &bad_wr);
+ 	if (unlikely(ret)) {
+ 		ipoib_warn(priv, "post srq failed for buf %d (%d)\n", id, ret);
+-		ipoib_cm_dma_unmap_rx(priv, IPOIB_CM_RX_SG - 1,
++		ipoib_cm_dma_unmap_rx(priv, priv->cm.num_frags - 1,
+ 				      priv->cm.srq_ring[id].mapping);
+ 		dev_kfree_skb_any(priv->cm.srq_ring[id].skb);
+ 		priv->cm.srq_ring[id].skb = NULL;
+@@ -104,7 +111,33 @@ static int ipoib_cm_post_receive(struct net_device *dev, int id)
+ 	return ret;
+ }
  
- 	if (pkttot > ipath_stats.sps_maxpkts_call)
- 		ipath_stats.sps_maxpkts_call = pkttot;
-@@ -1332,14 +1343,9 @@ static void ipath_update_pio_bufs(struct ipath_devdata *dd)
- 		/*
- 		 * Chip Errata: bug 6641; even and odd qwords>3 are swapped
- 		 */
--		if (i > 3) {
--			if (i & 1)
--				piov = le64_to_cpu(
--					dd->ipath_pioavailregs_dma[i - 1]);
--			else
--				piov = le64_to_cpu(
--					dd->ipath_pioavailregs_dma[i + 1]);
--		} else
-+		if (i > 3 && (dd->ipath_flags & IPATH_SWAP_PIOBUFS))
-+			piov = le64_to_cpu(dd->ipath_pioavailregs_dma[i ^ 1]);
-+		else
- 			piov = le64_to_cpu(dd->ipath_pioavailregs_dma[i]);
- 		pchg = _IPATH_ALL_CHECKBITS &
- 			~(dd->ipath_pioavailshadow[i] ^ piov);
-@@ -1598,7 +1604,8 @@ int ipath_create_rcvhdrq(struct ipath_devdata *dd,
+-static struct sk_buff *ipoib_cm_alloc_rx_skb(struct net_device *dev, int id, int frags,
++static int ipoib_cm_post_receive_nonsrq(struct net_device *dev,
++					struct ipoib_cm_rx *rx, int id)
++{
++	struct ipoib_dev_priv *priv = netdev_priv(dev);
++	struct ib_recv_wr *bad_wr;
++	int i, ret;
++
++	priv->cm.rx_wr.wr_id = id | IPOIB_OP_CM | IPOIB_OP_RECV;
++
++	for (i = 0; i < IPOIB_CM_RX_SG; ++i)
++		priv->cm.rx_sge[i].addr = rx->rx_ring[id].mapping[i];
++
++	ret = ib_post_recv(rx->qp, &priv->cm.rx_wr, &bad_wr);
++	if (unlikely(ret)) {
++		ipoib_warn(priv, "post recv failed for buf %d (%d)\n", id, ret);
++		ipoib_cm_dma_unmap_rx(priv, IPOIB_CM_RX_SG - 1,
++				      rx->rx_ring[id].mapping);
++		dev_kfree_skb_any(rx->rx_ring[id].skb);
++		rx->rx_ring[id].skb = NULL;
++	}
++
++	return ret;
++}
++
++static struct sk_buff *ipoib_cm_alloc_rx_skb(struct net_device *dev,
++					     struct ipoib_cm_rx_buf *rx_ring,
++					     int id, int frags,
+ 					     u64 mapping[IPOIB_CM_RX_SG])
+ {
+ 	struct ipoib_dev_priv *priv = netdev_priv(dev);
+@@ -141,7 +174,7 @@ static struct sk_buff *ipoib_cm_alloc_rx_skb(struct net_device *dev, int id, int
+ 			goto partial_error;
+ 	}
  
- 	/* clear for security and sanity on each use */
- 	memset(pd->port_rcvhdrq, 0, pd->port_rcvhdrq_size);
--	memset(pd->port_rcvhdrtail_kvaddr, 0, PAGE_SIZE);
-+	if (pd->port_rcvhdrtail_kvaddr)
-+		memset(pd->port_rcvhdrtail_kvaddr, 0, PAGE_SIZE);
+-	priv->cm.srq_ring[id].skb = skb;
++	rx_ring[id].skb = skb;
+ 	return skb;
  
- 	/*
- 	 * tell chip each time we init it, even if we are re-using previous
-@@ -1614,77 +1621,6 @@ bail:
- 	return ret;
+ partial_error:
+@@ -155,7 +188,23 @@ partial_error:
+ 	return NULL;
  }
  
--int ipath_waitfor_complete(struct ipath_devdata *dd, ipath_kreg reg_id,
--			   u64 bits_to_wait_for, u64 * valp)
--{
--	unsigned long timeout;
--	u64 lastval, val;
--	int ret;
--
--	lastval = ipath_read_kreg64(dd, reg_id);
--	/* wait a ridiculously long time */
--	timeout = jiffies + msecs_to_jiffies(5);
--	do {
--		val = ipath_read_kreg64(dd, reg_id);
--		/* set so they have something, even on failures. */
--		*valp = val;
--		if ((val & bits_to_wait_for) == bits_to_wait_for) {
--			ret = 0;
--			break;
--		}
--		if (val != lastval)
--			ipath_cdbg(VERBOSE, "Changed from %llx to %llx, "
--				   "waiting for %llx bits\n",
--				   (unsigned long long) lastval,
--				   (unsigned long long) val,
--				   (unsigned long long) bits_to_wait_for);
--		cond_resched();
--		if (time_after(jiffies, timeout)) {
--			ipath_dbg("Didn't get bits %llx in register 0x%x, "
--				  "got %llx\n",
--				  (unsigned long long) bits_to_wait_for,
--				  reg_id, (unsigned long long) *valp);
--			ret = -ENODEV;
--			break;
--		}
--	} while (1);
--
--	return ret;
--}
--
--/**
-- * ipath_waitfor_mdio_cmdready - wait for last command to complete
-- * @dd: the infinipath device
-- *
-- * Like ipath_waitfor_complete(), but we wait for the CMDVALID bit to go
-- * away indicating the last command has completed.  It doesn't return data
-- */
--int ipath_waitfor_mdio_cmdready(struct ipath_devdata *dd)
--{
--	unsigned long timeout;
--	u64 val;
--	int ret;
--
--	/* wait a ridiculously long time */
--	timeout = jiffies + msecs_to_jiffies(5);
--	do {
--		val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_mdio);
--		if (!(val & IPATH_MDIO_CMDVALID)) {
--			ret = 0;
--			break;
--		}
--		cond_resched();
--		if (time_after(jiffies, timeout)) {
--			ipath_dbg("CMDVALID stuck in mdio reg? (%llx)\n",
--				  (unsigned long long) val);
--			ret = -ENODEV;
--			break;
--		}
--	} while (1);
--
--	return ret;
--}
--
+-static void ipoib_cm_start_rx_drain(struct ipoib_dev_priv* priv)
++static void ipoib_cm_free_rx_ring(struct net_device *dev,
++				  struct ipoib_cm_rx_buf *rx_ring)
++{
++	struct ipoib_dev_priv *priv = netdev_priv(dev);
++	int i;
++
++	for (i = 0; i < ipoib_recvq_size; ++i)
++		if (rx_ring[i].skb) {
++			ipoib_cm_dma_unmap_rx(priv, IPOIB_CM_RX_SG - 1,
++					      rx_ring[i].mapping);
++			dev_kfree_skb_any(rx_ring[i].skb);
++		}
++
++	kfree(rx_ring);
++}
++
++static void ipoib_cm_start_rx_drain(struct ipoib_dev_priv *priv)
+ {
+ 	struct ib_send_wr *bad_wr;
+ 	struct ipoib_cm_rx *p;
+@@ -208,12 +257,18 @@ static struct ib_qp *ipoib_cm_create_rx_qp(struct net_device *dev,
+ 		.qp_type = IB_QPT_RC,
+ 		.qp_context = p,
+ 	};
++
++	if (!ipoib_cm_has_srq(dev)) {
++		attr.cap.max_recv_wr  = ipoib_recvq_size;
++		attr.cap.max_recv_sge = IPOIB_CM_RX_SG;
++	}
++
+ 	return ib_create_qp(priv->pd, &attr);
+ }
  
- /*
-  * Flush all sends that might be in the ready to send state, as well as any
-@@ -2053,6 +1989,8 @@ void ipath_set_led_override(struct ipath_devdata *dd, unsigned int val)
-  */
- void ipath_shutdown_device(struct ipath_devdata *dd)
+ static int ipoib_cm_modify_rx_qp(struct net_device *dev,
+-				  struct ib_cm_id *cm_id, struct ib_qp *qp,
+-				  unsigned psn)
++				 struct ib_cm_id *cm_id, struct ib_qp *qp,
++				 unsigned psn)
  {
-+	unsigned long flags;
+ 	struct ipoib_dev_priv *priv = netdev_priv(dev);
+ 	struct ib_qp_attr qp_attr;
+@@ -266,6 +321,60 @@ static int ipoib_cm_modify_rx_qp(struct net_device *dev,
+ 	return 0;
+ }
+ 
++static int ipoib_cm_nonsrq_init_rx(struct net_device *dev, struct ib_cm_id *cm_id,
++				   struct ipoib_cm_rx *rx)
++{
++	struct ipoib_dev_priv *priv = netdev_priv(dev);
++	int ret;
++	int i;
 +
- 	ipath_dbg("Shutting down the device\n");
++	rx->rx_ring = kcalloc(ipoib_recvq_size, sizeof *rx->rx_ring, GFP_KERNEL);
++	if (!rx->rx_ring)
++		return -ENOMEM;
++
++	spin_lock_irq(&priv->lock);
++
++	if (priv->cm.nonsrq_conn_qp >= ipoib_max_conn_qp) {
++		spin_unlock_irq(&priv->lock);
++		ib_send_cm_rej(cm_id, IB_CM_REJ_NO_QP, NULL, 0, NULL, 0);
++		ret = -EINVAL;
++		goto err_free;
++	} else
++		++priv->cm.nonsrq_conn_qp;
++
++	spin_unlock_irq(&priv->lock);
++
++	for (i = 0; i < ipoib_recvq_size; ++i) {
++		if (!ipoib_cm_alloc_rx_skb(dev, rx->rx_ring, i, IPOIB_CM_RX_SG - 1,
++					   rx->rx_ring[i].mapping)) {
++			ipoib_warn(priv, "failed to allocate receive buffer %d\n", i);
++				ret = -ENOMEM;
++				goto err_count;
++			}
++		ret = ipoib_cm_post_receive_nonsrq(dev, rx, i);
++		if (ret) {
++			ipoib_warn(priv, "ipoib_cm_post_receive_nonsrq "
++				   "failed for buf %d\n", i);
++			ret = -EIO;
++			goto err_count;
++		}
++	}
++
++	rx->recv_count = ipoib_recvq_size;
++
++	return 0;
++
++err_count:
++	spin_lock_irq(&priv->lock);
++	--priv->cm.nonsrq_conn_qp;
++	spin_unlock_irq(&priv->lock);
++
++err_free:
++	ipoib_cm_free_rx_ring(dev, rx->rx_ring);
++
++	return ret;
++}
++
+ static int ipoib_cm_send_rep(struct net_device *dev, struct ib_cm_id *cm_id,
+ 			     struct ib_qp *qp, struct ib_cm_req_event_param *req,
+ 			     unsigned psn)
+@@ -281,7 +390,7 @@ static int ipoib_cm_send_rep(struct net_device *dev, struct ib_cm_id *cm_id,
+ 	rep.private_data_len = sizeof data;
+ 	rep.flow_control = 0;
+ 	rep.rnr_retry_count = req->rnr_retry_count;
+-	rep.srq = 1;
++	rep.srq = ipoib_cm_has_srq(dev);
+ 	rep.qp_num = qp->qp_num;
+ 	rep.starting_psn = psn;
+ 	return ib_send_cm_rep(cm_id, &rep);
+@@ -317,6 +426,12 @@ static int ipoib_cm_req_handler(struct ib_cm_id *cm_id, struct ib_cm_event *even
+ 	if (ret)
+ 		goto err_modify;
  
- 	dd->ipath_flags |= IPATH_LINKUNK;
-@@ -2073,9 +2011,13 @@ void ipath_shutdown_device(struct ipath_devdata *dd)
- 	 * gracefully stop all sends allowing any in progress to trickle out
- 	 * first.
- 	 */
--	ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, 0ULL);
-+	spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags);
-+	dd->ipath_sendctrl = 0;
-+	ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, dd->ipath_sendctrl);
- 	/* flush it */
- 	ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
-+	spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags);
++	if (!ipoib_cm_has_srq(dev)) {
++		ret = ipoib_cm_nonsrq_init_rx(dev, cm_id, p);
++		if (ret)
++			goto err_modify;
++	}
 +
- 	/*
- 	 * enough for anything that's going to trickle out to have actually
- 	 * done so.
-@@ -2217,25 +2159,15 @@ static int __init infinipath_init(void)
- 		goto bail_unit;
+ 	spin_lock_irq(&priv->lock);
+ 	queue_delayed_work(ipoib_workqueue,
+ 			   &priv->cm.stale_task, IPOIB_CM_RX_DELAY);
+@@ -401,12 +516,14 @@ static void skb_put_frags(struct sk_buff *skb, unsigned int hdr_space,
+ void ipoib_cm_handle_rx_wc(struct net_device *dev, struct ib_wc *wc)
+ {
+ 	struct ipoib_dev_priv *priv = netdev_priv(dev);
++	struct ipoib_cm_rx_buf *rx_ring;
+ 	unsigned int wr_id = wc->wr_id & ~(IPOIB_OP_CM | IPOIB_OP_RECV);
+ 	struct sk_buff *skb, *newskb;
+ 	struct ipoib_cm_rx *p;
+ 	unsigned long flags;
+ 	u64 mapping[IPOIB_CM_RX_SG];
+ 	int frags;
++	int has_srq;
+ 
+ 	ipoib_dbg_data(priv, "cm recv completion: id %d, status: %d\n",
+ 		       wr_id, wc->status);
+@@ -424,18 +541,32 @@ void ipoib_cm_handle_rx_wc(struct net_device *dev, struct ib_wc *wc)
+ 		return;
  	}
  
--	ret = ipath_driver_create_group(&ipath_driver.driver);
--	if (ret < 0) {
--		printk(KERN_ERR IPATH_DRV_NAME ": Unable to create driver "
--		       "sysfs entries: error %d\n", -ret);
--		goto bail_pci;
--	}
--
- 	ret = ipath_init_ipathfs();
- 	if (ret < 0) {
- 		printk(KERN_ERR IPATH_DRV_NAME ": Unable to create "
- 		       "ipathfs: error %d\n", -ret);
--		goto bail_group;
-+		goto bail_pci;
+-	skb  = priv->cm.srq_ring[wr_id].skb;
++	p = wc->qp->qp_context;
++
++	has_srq = ipoib_cm_has_srq(dev);
++	rx_ring = has_srq ? priv->cm.srq_ring : p->rx_ring;
++
++	skb = rx_ring[wr_id].skb;
+ 
+ 	if (unlikely(wc->status != IB_WC_SUCCESS)) {
+ 		ipoib_dbg(priv, "cm recv error "
+ 			   "(status=%d, wrid=%d vend_err %x)\n",
+ 			   wc->status, wr_id, wc->vendor_err);
+ 		++dev->stats.rx_dropped;
+-		goto repost;
++		if (has_srq)
++			goto repost;
++		else {
++			if (!--p->recv_count) {
++				spin_lock_irqsave(&priv->lock, flags);
++				list_move(&p->list, &priv->cm.rx_reap_list);
++				spin_unlock_irqrestore(&priv->lock, flags);
++				queue_work(ipoib_workqueue, &priv->cm.rx_reap_task);
++			}
++			return;
++		}
  	}
  
- 	goto bail;
+ 	if (unlikely(!(wr_id & IPOIB_CM_RX_UPDATE_MASK))) {
+-		p = wc->qp->qp_context;
+ 		if (p && time_after_eq(jiffies, p->jiffies + IPOIB_CM_RX_UPDATE_TIME)) {
+ 			spin_lock_irqsave(&priv->lock, flags);
+ 			p->jiffies = jiffies;
+@@ -450,7 +581,7 @@ void ipoib_cm_handle_rx_wc(struct net_device *dev, struct ib_wc *wc)
+ 	frags = PAGE_ALIGN(wc->byte_len - min(wc->byte_len,
+ 					      (unsigned)IPOIB_CM_HEAD_SIZE)) / PAGE_SIZE;
  
--bail_group:
--	ipath_driver_remove_group(&ipath_driver.driver);
--
- bail_pci:
- 	pci_unregister_driver(&ipath_driver);
+-	newskb = ipoib_cm_alloc_rx_skb(dev, wr_id, frags, mapping);
++	newskb = ipoib_cm_alloc_rx_skb(dev, rx_ring, wr_id, frags, mapping);
+ 	if (unlikely(!newskb)) {
+ 		/*
+ 		 * If we can't allocate a new RX buffer, dump
+@@ -461,8 +592,8 @@ void ipoib_cm_handle_rx_wc(struct net_device *dev, struct ib_wc *wc)
+ 		goto repost;
+ 	}
  
-@@ -2250,8 +2182,6 @@ static void __exit infinipath_cleanup(void)
+-	ipoib_cm_dma_unmap_rx(priv, frags, priv->cm.srq_ring[wr_id].mapping);
+-	memcpy(priv->cm.srq_ring[wr_id].mapping, mapping, (frags + 1) * sizeof *mapping);
++	ipoib_cm_dma_unmap_rx(priv, frags, rx_ring[wr_id].mapping);
++	memcpy(rx_ring[wr_id].mapping, mapping, (frags + 1) * sizeof *mapping);
+ 
+ 	ipoib_dbg_data(priv, "received %d bytes, SLID 0x%04x\n",
+ 		       wc->byte_len, wc->slid);
+@@ -483,9 +614,17 @@ void ipoib_cm_handle_rx_wc(struct net_device *dev, struct ib_wc *wc)
+ 	netif_receive_skb(skb);
+ 
+ repost:
+-	if (unlikely(ipoib_cm_post_receive(dev, wr_id)))
+-		ipoib_warn(priv, "ipoib_cm_post_receive failed "
+-			   "for buf %d\n", wr_id);
++	if (has_srq) {
++		if (unlikely(ipoib_cm_post_receive_srq(dev, wr_id)))
++			ipoib_warn(priv, "ipoib_cm_post_receive_srq failed "
++				   "for buf %d\n", wr_id);
++	} else {
++		if (unlikely(ipoib_cm_post_receive_nonsrq(dev, p, wr_id))) {
++			--p->recv_count;
++			ipoib_warn(priv, "ipoib_cm_post_receive_nonsrq failed "
++				   "for buf %d\n", wr_id);
++		}
++	}
+ }
+ 
+ static inline int post_send(struct ipoib_dev_priv *priv,
+@@ -495,10 +634,10 @@ static inline int post_send(struct ipoib_dev_priv *priv,
  {
- 	ipath_exit_ipathfs();
+ 	struct ib_send_wr *bad_wr;
  
--	ipath_driver_remove_group(&ipath_driver.driver);
--
- 	ipath_cdbg(VERBOSE, "Unregistering pci driver\n");
- 	pci_unregister_driver(&ipath_driver);
+-	priv->tx_sge.addr             = addr;
+-	priv->tx_sge.length           = len;
++	priv->tx_sge.addr	= addr;
++	priv->tx_sge.length	= len;
  
-@@ -2344,5 +2274,34 @@ int ipath_set_rx_pol_inv(struct ipath_devdata *dd, u8 new_pol_inv)
- 	}
- 	return 0;
+-	priv->tx_wr.wr_id 	      = wr_id | IPOIB_OP_CM;
++	priv->tx_wr.wr_id	= wr_id | IPOIB_OP_CM;
+ 
+ 	return ib_post_send(tx->qp, &priv->tx_wr, &bad_wr);
  }
-+
-+/*
-+ * Disable and enable the armlaunch error.  Used for PIO bandwidth testing on
-+ * the 7220, which is count-based, rather than trigger-based.  Safe for the
-+ * driver check, since it's at init.   Not completely safe when used for
-+ * user-mode checking, since some error checking can be lost, but not
-+ * particularly risky, and only has problematic side-effects in the face of
-+ * very buggy user code.  There is no reference counting, but that's also
-+ * fine, given the intended use.
-+ */
-+void ipath_enable_armlaunch(struct ipath_devdata *dd)
+@@ -540,7 +679,7 @@ void ipoib_cm_send(struct net_device *dev, struct sk_buff *skb, struct ipoib_cm_
+ 	tx_req->mapping = addr;
+ 
+ 	if (unlikely(post_send(priv, tx, tx->tx_head & (ipoib_sendq_size - 1),
+-			        addr, skb->len))) {
++			       addr, skb->len))) {
+ 		ipoib_warn(priv, "post_send failed\n");
+ 		++dev->stats.tx_errors;
+ 		ib_dma_unmap_single(priv->ca, addr, skb->len, DMA_TO_DEVICE);
+@@ -657,10 +796,33 @@ err_cm:
+ 	return ret;
+ }
+ 
++static void ipoib_cm_free_rx_reap_list(struct net_device *dev)
 +{
-+	dd->ipath_lasterror &= ~INFINIPATH_E_SPIOARMLAUNCH;
-+	ipath_write_kreg(dd, dd->ipath_kregs->kr_errorclear,
-+		INFINIPATH_E_SPIOARMLAUNCH);
-+	dd->ipath_errormask |= INFINIPATH_E_SPIOARMLAUNCH;
-+	ipath_write_kreg(dd, dd->ipath_kregs->kr_errormask,
-+		dd->ipath_errormask);
-+}
++	struct ipoib_dev_priv *priv = netdev_priv(dev);
++	struct ipoib_cm_rx *rx, *n;
++	LIST_HEAD(list);
 +
-+void ipath_disable_armlaunch(struct ipath_devdata *dd)
-+{
-+	/* so don't re-enable if already set */
-+	dd->ipath_maskederrs &= ~INFINIPATH_E_SPIOARMLAUNCH;
-+	dd->ipath_errormask &= ~INFINIPATH_E_SPIOARMLAUNCH;
-+	ipath_write_kreg(dd, dd->ipath_kregs->kr_errormask,
-+		dd->ipath_errormask);
++	spin_lock_irq(&priv->lock);
++	list_splice_init(&priv->cm.rx_reap_list, &list);
++	spin_unlock_irq(&priv->lock);
++
++	list_for_each_entry_safe(rx, n, &list, list) {
++		ib_destroy_cm_id(rx->id);
++		ib_destroy_qp(rx->qp);
++		if (!ipoib_cm_has_srq(dev)) {
++			ipoib_cm_free_rx_ring(priv->dev, rx->rx_ring);
++			spin_lock_irq(&priv->lock);
++			--priv->cm.nonsrq_conn_qp;
++			spin_unlock_irq(&priv->lock);
++		}
++		kfree(rx);
++	}
 +}
 +
- module_init(infinipath_init);
- module_exit(infinipath_cleanup);
-diff --git a/drivers/infiniband/hw/ipath/ipath_eeprom.c b/drivers/infiniband/hw/ipath/ipath_eeprom.c
-index e7c25db..e28a42f 100644
---- a/drivers/infiniband/hw/ipath/ipath_eeprom.c
-+++ b/drivers/infiniband/hw/ipath/ipath_eeprom.c
-@@ -510,10 +510,10 @@ int ipath_eeprom_read(struct ipath_devdata *dd, u8 eeprom_offset,
+ void ipoib_cm_dev_stop(struct net_device *dev)
  {
+ 	struct ipoib_dev_priv *priv = netdev_priv(dev);
+-	struct ipoib_cm_rx *p, *n;
++	struct ipoib_cm_rx *p;
+ 	unsigned long begin;
+ 	LIST_HEAD(list);
  	int ret;
- 
--	ret = down_interruptible(&dd->ipath_eep_sem);
-+	ret = mutex_lock_interruptible(&dd->ipath_eep_lock);
- 	if (!ret) {
- 		ret = ipath_eeprom_internal_read(dd, eeprom_offset, buff, len);
--		up(&dd->ipath_eep_sem);
-+		mutex_unlock(&dd->ipath_eep_lock);
+@@ -706,15 +868,9 @@ void ipoib_cm_dev_stop(struct net_device *dev)
+ 		spin_lock_irq(&priv->lock);
  	}
  
- 	return ret;
-@@ -524,10 +524,10 @@ int ipath_eeprom_write(struct ipath_devdata *dd, u8 eeprom_offset,
- {
- 	int ret;
+-	list_splice_init(&priv->cm.rx_reap_list, &list);
+-
+ 	spin_unlock_irq(&priv->lock);
  
--	ret = down_interruptible(&dd->ipath_eep_sem);
-+	ret = mutex_lock_interruptible(&dd->ipath_eep_lock);
- 	if (!ret) {
- 		ret = ipath_eeprom_internal_write(dd, eeprom_offset, buff, len);
--		up(&dd->ipath_eep_sem);
-+		mutex_unlock(&dd->ipath_eep_lock);
- 	}
+-	list_for_each_entry_safe(p, n, &list, list) {
+-		ib_destroy_cm_id(p->id);
+-		ib_destroy_qp(p->qp);
+-		kfree(p);
+-	}
++	ipoib_cm_free_rx_reap_list(dev);
  
- 	return ret;
-@@ -574,7 +574,7 @@ void ipath_get_eeprom_info(struct ipath_devdata *dd)
- 	struct ipath_devdata *dd0 = ipath_lookup(0);
+ 	cancel_delayed_work(&priv->cm.stale_task);
+ }
+@@ -799,7 +955,7 @@ static struct ib_qp *ipoib_cm_create_tx_qp(struct net_device *dev, struct ipoib_
+ 		.sq_sig_type		= IB_SIGNAL_ALL_WR,
+ 		.qp_type		= IB_QPT_RC,
+ 		.qp_context		= tx
+-        };
++	};
  
- 	if (t && dd0->ipath_nguid > 1 && t <= dd0->ipath_nguid) {
--		u8 *bguid, oguid;
-+		u8 oguid;
- 		dd->ipath_guid = dd0->ipath_guid;
- 		bguid = (u8 *) & dd->ipath_guid;
+ 	return ib_create_qp(priv->pd, &attr);
+ }
+@@ -816,28 +972,28 @@ static int ipoib_cm_send_req(struct net_device *dev,
+ 	data.qpn = cpu_to_be32(priv->qp->qp_num);
+ 	data.mtu = cpu_to_be32(IPOIB_CM_BUF_SIZE);
  
-@@ -616,9 +616,9 @@ void ipath_get_eeprom_info(struct ipath_devdata *dd)
- 		goto bail;
- 	}
+-	req.primary_path 	      = pathrec;
+-	req.alternate_path 	      = NULL;
+-	req.service_id                = cpu_to_be64(IPOIB_CM_IETF_ID | qpn);
+-	req.qp_num 		      = qp->qp_num;
+-	req.qp_type 		      = qp->qp_type;
+-	req.private_data 	      = &data;
+-	req.private_data_len 	      = sizeof data;
+-	req.flow_control 	      = 0;
++	req.primary_path		= pathrec;
++	req.alternate_path		= NULL;
++	req.service_id			= cpu_to_be64(IPOIB_CM_IETF_ID | qpn);
++	req.qp_num			= qp->qp_num;
++	req.qp_type			= qp->qp_type;
++	req.private_data		= &data;
++	req.private_data_len		= sizeof data;
++	req.flow_control		= 0;
  
--	down(&dd->ipath_eep_sem);
-+	mutex_lock(&dd->ipath_eep_lock);
- 	eep_stat = ipath_eeprom_internal_read(dd, 0, buf, len);
--	up(&dd->ipath_eep_sem);
-+	mutex_unlock(&dd->ipath_eep_lock);
+-	req.starting_psn              = 0; /* FIXME */
++	req.starting_psn		= 0; /* FIXME */
  
- 	if (eep_stat) {
- 		ipath_dev_err(dd, "Failed reading GUID from eeprom\n");
-@@ -674,7 +674,6 @@ void ipath_get_eeprom_info(struct ipath_devdata *dd)
- 		 * elsewhere for backward-compatibility.
- 		 */
- 		char *snp = dd->ipath_serial;
--		int len;
- 		memcpy(snp, ifp->if_sprefix, sizeof ifp->if_sprefix);
- 		snp[sizeof ifp->if_sprefix] = '\0';
- 		len = strlen(snp);
-@@ -764,14 +763,14 @@ int ipath_update_eeprom_log(struct ipath_devdata *dd)
- 	/* Grab semaphore and read current EEPROM. If we get an
- 	 * error, let go, but if not, keep it until we finish write.
+ 	/*
+ 	 * Pick some arbitrary defaults here; we could make these
+ 	 * module parameters if anyone cared about setting them.
  	 */
--	ret = down_interruptible(&dd->ipath_eep_sem);
-+	ret = mutex_lock_interruptible(&dd->ipath_eep_lock);
- 	if (ret) {
- 		ipath_dev_err(dd, "Unable to acquire EEPROM for logging\n");
- 		goto free_bail;
- 	}
- 	ret = ipath_eeprom_internal_read(dd, 0, buf, len);
- 	if (ret) {
--		up(&dd->ipath_eep_sem);
-+		mutex_unlock(&dd->ipath_eep_lock);
- 		ipath_dev_err(dd, "Unable read EEPROM for logging\n");
- 		goto free_bail;
- 	}
-@@ -779,7 +778,7 @@ int ipath_update_eeprom_log(struct ipath_devdata *dd)
- 
- 	csum = flash_csum(ifp, 0);
- 	if (csum != ifp->if_csum) {
--		up(&dd->ipath_eep_sem);
-+		mutex_unlock(&dd->ipath_eep_lock);
- 		ipath_dev_err(dd, "EEPROM cks err (0x%02X, S/B 0x%02X)\n",
- 				csum, ifp->if_csum);
- 		ret = 1;
-@@ -849,7 +848,7 @@ int ipath_update_eeprom_log(struct ipath_devdata *dd)
- 		csum = flash_csum(ifp, 1);
- 		ret = ipath_eeprom_internal_write(dd, 0, buf, hi_water + 1);
- 	}
--	up(&dd->ipath_eep_sem);
-+	mutex_unlock(&dd->ipath_eep_lock);
- 	if (ret)
- 		ipath_dev_err(dd, "Failed updating EEPROM\n");
- 
-diff --git a/drivers/infiniband/hw/ipath/ipath_file_ops.c b/drivers/infiniband/hw/ipath/ipath_file_ops.c
-index 5de3243..7e025c8 100644
---- a/drivers/infiniband/hw/ipath/ipath_file_ops.c
-+++ b/drivers/infiniband/hw/ipath/ipath_file_ops.c
-@@ -169,7 +169,7 @@ static int ipath_get_base_info(struct file *fp,
- 		kinfo->spi_piocnt = dd->ipath_pbufsport;
- 		kinfo->spi_piobufbase = (u64) pd->port_piobufs;
- 		kinfo->__spi_uregbase = (u64) dd->ipath_uregbase +
--			dd->ipath_palign * pd->port_port;
-+			dd->ipath_ureg_align * pd->port_port;
- 	} else if (master) {
- 		kinfo->spi_piocnt = (dd->ipath_pbufsport / subport_cnt) +
- 				    (dd->ipath_pbufsport % subport_cnt);
-@@ -186,7 +186,7 @@ static int ipath_get_base_info(struct file *fp,
- 	}
- 	if (shared) {
- 		kinfo->spi_port_uregbase = (u64) dd->ipath_uregbase +
--			dd->ipath_palign * pd->port_port;
-+			dd->ipath_ureg_align * pd->port_port;
- 		kinfo->spi_port_rcvegrbuf = kinfo->spi_rcv_egrbufs;
- 		kinfo->spi_port_rcvhdr_base = kinfo->spi_rcvhdr_base;
- 		kinfo->spi_port_rcvhdr_tailaddr = kinfo->spi_rcvhdr_tailaddr;
-@@ -742,11 +742,12 @@ static int ipath_manage_rcvq(struct ipath_portdata *pd, unsigned subport,
- 		 * updated and correct itself, even in the face of software
- 		 * bugs.
- 		 */
--		*(volatile u64 *)pd->port_rcvhdrtail_kvaddr = 0;
--		set_bit(INFINIPATH_R_PORTENABLE_SHIFT + pd->port_port,
-+		if (pd->port_rcvhdrtail_kvaddr)
-+			ipath_clear_rcvhdrtail(pd);
-+		set_bit(dd->ipath_r_portenable_shift + pd->port_port,
- 			&dd->ipath_rcvctrl);
- 	} else
--		clear_bit(INFINIPATH_R_PORTENABLE_SHIFT + pd->port_port,
-+		clear_bit(dd->ipath_r_portenable_shift + pd->port_port,
- 			  &dd->ipath_rcvctrl);
- 	ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl,
- 			 dd->ipath_rcvctrl);
-@@ -881,7 +882,7 @@ static int ipath_create_user_egr(struct ipath_portdata *pd)
+-	req.responder_resources	      = 4;
+-	req.remote_cm_response_timeout = 20;
+-	req.local_cm_response_timeout  = 20;
+-	req.retry_count 	      = 0; /* RFC draft warns against retries */
+-	req.rnr_retry_count 	      = 0; /* RFC draft warns against retries */
+-	req.max_cm_retries 	      = 15;
+-	req.srq 	              = 1;
++	req.responder_resources		= 4;
++	req.remote_cm_response_timeout	= 20;
++	req.local_cm_response_timeout	= 20;
++	req.retry_count			= 0; /* RFC draft warns against retries */
++	req.rnr_retry_count		= 0; /* RFC draft warns against retries */
++	req.max_cm_retries		= 15;
++	req.srq				= ipoib_cm_has_srq(dev);
+ 	return ib_send_cm_req(id, &req);
+ }
  
- 	egrcnt = dd->ipath_rcvegrcnt;
- 	/* TID number offset for this port */
--	egroff = pd->port_port * egrcnt;
-+	egroff = (pd->port_port - 1) * egrcnt + dd->ipath_p0_rcvegrcnt;
- 	egrsize = dd->ipath_rcvegrbufsize;
- 	ipath_cdbg(VERBOSE, "Allocating %d egr buffers, at egrtid "
- 		   "offset %x, egrsize %u\n", egrcnt, egroff, egrsize);
-@@ -1049,11 +1050,6 @@ static int mmap_piobufs(struct vm_area_struct *vma,
+@@ -1150,7 +1306,7 @@ static void ipoib_cm_skb_reap(struct work_struct *work)
+ 	spin_unlock_irq(&priv->tx_lock);
+ }
  
- 	phys = dd->ipath_physaddr + piobufs;
+-void ipoib_cm_skb_too_long(struct net_device* dev, struct sk_buff *skb,
++void ipoib_cm_skb_too_long(struct net_device *dev, struct sk_buff *skb,
+ 			   unsigned int mtu)
+ {
+ 	struct ipoib_dev_priv *priv = netdev_priv(dev);
+@@ -1166,20 +1322,8 @@ void ipoib_cm_skb_too_long(struct net_device* dev, struct sk_buff *skb,
  
--	/*
--	 * Don't mark this as non-cached, or we don't get the
--	 * write combining behavior we want on the PIO buffers!
--	 */
+ static void ipoib_cm_rx_reap(struct work_struct *work)
+ {
+-	struct ipoib_dev_priv *priv = container_of(work, struct ipoib_dev_priv,
+-						   cm.rx_reap_task);
+-	struct ipoib_cm_rx *p, *n;
+-	LIST_HEAD(list);
 -
- #if defined(__powerpc__)
- 	/* There isn't a generic way to specify writethrough mappings */
- 	pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE;
-@@ -1120,33 +1116,24 @@ bail:
+-	spin_lock_irq(&priv->lock);
+-	list_splice_init(&priv->cm.rx_reap_list, &list);
+-	spin_unlock_irq(&priv->lock);
+-
+-	list_for_each_entry_safe(p, n, &list, list) {
+-		ib_destroy_cm_id(p->id);
+-		ib_destroy_qp(p->qp);
+-		kfree(p);
+-	}
++	ipoib_cm_free_rx_reap_list(container_of(work, struct ipoib_dev_priv,
++						cm.rx_reap_task)->dev);
  }
  
- /*
-- * ipath_file_vma_nopage - handle a VMA page fault.
-+ * ipath_file_vma_fault - handle a VMA page fault.
-  */
--static struct page *ipath_file_vma_nopage(struct vm_area_struct *vma,
--					  unsigned long address, int *type)
-+static int ipath_file_vma_fault(struct vm_area_struct *vma,
-+					struct vm_fault *vmf)
+ static void ipoib_cm_stale_task(struct work_struct *work)
+@@ -1212,7 +1356,7 @@ static void ipoib_cm_stale_task(struct work_struct *work)
+ }
+ 
+ 
+-static ssize_t show_mode(struct device *d, struct device_attribute *attr, 
++static ssize_t show_mode(struct device *d, struct device_attribute *attr,
+ 			 char *buf)
  {
--	unsigned long offset = address - vma->vm_start;
--	struct page *page = NOPAGE_SIGBUS;
--	void *pageptr;
-+	struct page *page;
+ 	struct ipoib_dev_priv *priv = netdev_priv(to_net_dev(d));
+@@ -1255,16 +1399,40 @@ int ipoib_cm_add_mode_attr(struct net_device *dev)
+ 	return device_create_file(&dev->dev, &dev_attr_mode);
+ }
  
--	/*
--	 * Convert the vmalloc address into a struct page.
--	 */
--	pageptr = (void *)(offset + (vma->vm_pgoff << PAGE_SHIFT));
--	page = vmalloc_to_page(pageptr);
-+	page = vmalloc_to_page((void *)(vmf->pgoff << PAGE_SHIFT));
- 	if (!page)
--		goto out;
--
--	/* Increment the reference count. */
-+		return VM_FAULT_SIGBUS;
- 	get_page(page);
--	if (type)
--		*type = VM_FAULT_MINOR;
--out:
--	return page;
-+	vmf->page = page;
+-int ipoib_cm_dev_init(struct net_device *dev)
++static void ipoib_cm_create_srq(struct net_device *dev, int max_sge)
+ {
+ 	struct ipoib_dev_priv *priv = netdev_priv(dev);
+ 	struct ib_srq_init_attr srq_init_attr = {
+ 		.attr = {
+ 			.max_wr  = ipoib_recvq_size,
+-			.max_sge = IPOIB_CM_RX_SG
++			.max_sge = max_sge
+ 		}
+ 	};
+-	int ret, i;
 +
-+	return 0;
- }
++	priv->cm.srq = ib_create_srq(priv->pd, &srq_init_attr);
++	if (IS_ERR(priv->cm.srq)) {
++		if (PTR_ERR(priv->cm.srq) != -ENOSYS)
++			printk(KERN_WARNING "%s: failed to allocate SRQ, error %ld\n",
++			       priv->ca->name, PTR_ERR(priv->cm.srq));
++		priv->cm.srq = NULL;
++		return;
++	}
++
++	priv->cm.srq_ring = kzalloc(ipoib_recvq_size * sizeof *priv->cm.srq_ring,
++				    GFP_KERNEL);
++	if (!priv->cm.srq_ring) {
++		printk(KERN_WARNING "%s: failed to allocate CM SRQ ring (%d entries)\n",
++		       priv->ca->name, ipoib_recvq_size);
++		ib_destroy_srq(priv->cm.srq);
++		priv->cm.srq = NULL;
++	}
++}
++
++int ipoib_cm_dev_init(struct net_device *dev)
++{
++	struct ipoib_dev_priv *priv = netdev_priv(dev);
++	int i, ret;
++	struct ib_device_attr attr;
  
- static struct vm_operations_struct ipath_file_vm_ops = {
--	.nopage = ipath_file_vma_nopage,
-+	.fault = ipath_file_vma_fault,
- };
+ 	INIT_LIST_HEAD(&priv->cm.passive_ids);
+ 	INIT_LIST_HEAD(&priv->cm.reap_list);
+@@ -1281,43 +1449,53 @@ int ipoib_cm_dev_init(struct net_device *dev)
  
- static int mmap_kvaddr(struct vm_area_struct *vma, u64 pgaddr,
-@@ -1284,7 +1271,7 @@ static int ipath_mmap(struct file *fp, struct vm_area_struct *vma)
- 		goto bail;
- 	}
+ 	skb_queue_head_init(&priv->cm.skb_queue);
  
--	ureg = dd->ipath_uregbase + dd->ipath_palign * pd->port_port;
-+	ureg = dd->ipath_uregbase + dd->ipath_ureg_align * pd->port_port;
- 	if (!pd->port_subport_cnt) {
- 		/* port is not shared */
- 		piocnt = dd->ipath_pbufsport;
-@@ -1400,7 +1387,10 @@ static unsigned int ipath_poll_next(struct ipath_portdata *pd,
- 	pollflag = ipath_poll_hdrqfull(pd);
+-	priv->cm.srq = ib_create_srq(priv->pd, &srq_init_attr);
+-	if (IS_ERR(priv->cm.srq)) {
+-		ret = PTR_ERR(priv->cm.srq);
+-		priv->cm.srq = NULL;
++	ret = ib_query_device(priv->ca, &attr);
++	if (ret) {
++		printk(KERN_WARNING "ib_query_device() failed with %d\n", ret);
+ 		return ret;
+ 	}
  
- 	head = ipath_read_ureg32(dd, ur_rcvhdrhead, pd->port_port);
--	tail = *(volatile u64 *)pd->port_rcvhdrtail_kvaddr;
-+	if (pd->port_rcvhdrtail_kvaddr)
-+		tail = ipath_get_rcvhdrtail(pd);
-+	else
-+		tail = ipath_read_ureg32(dd, ur_rcvhdrtail, pd->port_port);
+-	priv->cm.srq_ring = kzalloc(ipoib_recvq_size * sizeof *priv->cm.srq_ring,
+-				    GFP_KERNEL);
+-	if (!priv->cm.srq_ring) {
+-		printk(KERN_WARNING "%s: failed to allocate CM ring (%d entries)\n",
+-		       priv->ca->name, ipoib_recvq_size);
+-		ipoib_cm_dev_cleanup(dev);
+-		return -ENOMEM;
++	ipoib_dbg(priv, "max_srq_sge=%d\n", attr.max_srq_sge);
++
++	attr.max_srq_sge = min_t(int, IPOIB_CM_RX_SG, attr.max_srq_sge);
++	ipoib_cm_create_srq(dev, attr.max_srq_sge);
++	if (ipoib_cm_has_srq(dev)) {
++		priv->cm.max_cm_mtu = attr.max_srq_sge * PAGE_SIZE - 0x10;
++		priv->cm.num_frags  = attr.max_srq_sge;
++		ipoib_dbg(priv, "max_cm_mtu = 0x%x, num_frags=%d\n",
++			  priv->cm.max_cm_mtu, priv->cm.num_frags);
++	} else {
++		priv->cm.max_cm_mtu = IPOIB_CM_MTU;
++		priv->cm.num_frags  = IPOIB_CM_RX_SG;
+ 	}
  
- 	if (head != tail)
- 		pollflag |= POLLIN | POLLRDNORM;
-@@ -1410,7 +1400,7 @@ static unsigned int ipath_poll_next(struct ipath_portdata *pd,
- 		/* flush waiting flag so we don't miss an event */
- 		wmb();
+-	for (i = 0; i < IPOIB_CM_RX_SG; ++i)
++	for (i = 0; i < priv->cm.num_frags; ++i)
+ 		priv->cm.rx_sge[i].lkey	= priv->mr->lkey;
  
--		set_bit(pd->port_port + INFINIPATH_R_INTRAVAIL_SHIFT,
-+		set_bit(pd->port_port + dd->ipath_r_intravail_shift,
- 			&dd->ipath_rcvctrl);
+ 	priv->cm.rx_sge[0].length = IPOIB_CM_HEAD_SIZE;
+-	for (i = 1; i < IPOIB_CM_RX_SG; ++i)
++	for (i = 1; i < priv->cm.num_frags; ++i)
+ 		priv->cm.rx_sge[i].length = PAGE_SIZE;
+ 	priv->cm.rx_wr.next = NULL;
+ 	priv->cm.rx_wr.sg_list = priv->cm.rx_sge;
+-	priv->cm.rx_wr.num_sge = IPOIB_CM_RX_SG;
++	priv->cm.rx_wr.num_sge = priv->cm.num_frags;
++
++	if (ipoib_cm_has_srq(dev)) {
++		for (i = 0; i < ipoib_recvq_size; ++i) {
++			if (!ipoib_cm_alloc_rx_skb(dev, priv->cm.srq_ring, i,
++						   priv->cm.num_frags - 1,
++						   priv->cm.srq_ring[i].mapping)) {
++				ipoib_warn(priv, "failed to allocate "
++					   "receive buffer %d\n", i);
++				ipoib_cm_dev_cleanup(dev);
++				return -ENOMEM;
++			}
  
- 		ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl,
-@@ -1790,6 +1780,7 @@ static int find_shared_port(struct file *fp,
- 			}
- 			port_fp(fp) = pd;
- 			subport_fp(fp) = pd->port_cnt++;
-+			pd->port_subpid[subport_fp(fp)] = current->pid;
- 			tidcursor_fp(fp) = 0;
- 			pd->active_slaves |= 1 << subport_fp(fp);
- 			ipath_cdbg(PROC,
-@@ -1920,8 +1911,7 @@ static int ipath_do_user_init(struct file *fp,
- 	 */
- 	head32 = ipath_read_ureg32(dd, ur_rcvegrindextail, pd->port_port);
- 	ipath_write_ureg(dd, ur_rcvegrindexhead, head32, pd->port_port);
--	dd->ipath_lastegrheads[pd->port_port] = -1;
--	dd->ipath_lastrcvhdrqtails[pd->port_port] = -1;
-+	pd->port_lastrcvhdrqtail = -1;
- 	ipath_cdbg(VERBOSE, "Wrote port%d egrhead %x from tail regs\n",
- 		pd->port_port, head32);
- 	pd->port_tidcursor = 0;	/* start at beginning after open */
-@@ -1941,11 +1931,13 @@ static int ipath_do_user_init(struct file *fp,
- 	 * We explictly set the in-memory copy to 0 beforehand, so we don't
- 	 * have to wait to be sure the DMA update has happened.
- 	 */
--	*(volatile u64 *)pd->port_rcvhdrtail_kvaddr = 0ULL;
--	set_bit(INFINIPATH_R_PORTENABLE_SHIFT + pd->port_port,
-+	if (pd->port_rcvhdrtail_kvaddr)
-+		ipath_clear_rcvhdrtail(pd);
-+	set_bit(dd->ipath_r_portenable_shift + pd->port_port,
- 		&dd->ipath_rcvctrl);
- 	ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl,
--			 dd->ipath_rcvctrl & ~INFINIPATH_R_TAILUPD);
-+			dd->ipath_rcvctrl &
-+			~(1ULL << dd->ipath_r_tailupd_shift));
- 	ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl,
- 			 dd->ipath_rcvctrl);
- 	/* Notify any waiting slaves */
-@@ -2022,6 +2014,7 @@ static int ipath_close(struct inode *in, struct file *fp)
- 		 * the slave(s) don't wait for receive data forever.
- 		 */
- 		pd->active_slaves &= ~(1 << fd->subport);
-+		pd->port_subpid[fd->subport] = 0;
- 		mutex_unlock(&ipath_mutex);
- 		goto bail;
+-	for (i = 0; i < ipoib_recvq_size; ++i) {
+-		if (!ipoib_cm_alloc_rx_skb(dev, i, IPOIB_CM_RX_SG - 1,
+-					   priv->cm.srq_ring[i].mapping)) {
+-			ipoib_warn(priv, "failed to allocate receive buffer %d\n", i);
+-			ipoib_cm_dev_cleanup(dev);
+-			return -ENOMEM;
+-		}
+-		if (ipoib_cm_post_receive(dev, i)) {
+-			ipoib_warn(priv, "ipoib_ib_post_receive failed for buf %d\n", i);
+-			ipoib_cm_dev_cleanup(dev);
+-			return -EIO;
++			if (ipoib_cm_post_receive_srq(dev, i)) {
++				ipoib_warn(priv, "ipoib_cm_post_receive_srq "
++					   "failed for buf %d\n", i);
++				ipoib_cm_dev_cleanup(dev);
++				return -EIO;
++			}
+ 		}
  	}
-@@ -2054,9 +2047,9 @@ static int ipath_close(struct inode *in, struct file *fp)
- 	if (dd->ipath_kregbase) {
- 		int i;
- 		/* atomically clear receive enable port and intr avail. */
--		clear_bit(INFINIPATH_R_PORTENABLE_SHIFT + port,
-+		clear_bit(dd->ipath_r_portenable_shift + port,
- 			  &dd->ipath_rcvctrl);
--		clear_bit(pd->port_port + INFINIPATH_R_INTRAVAIL_SHIFT,
-+		clear_bit(pd->port_port + dd->ipath_r_intravail_shift,
- 			  &dd->ipath_rcvctrl);
- 		ipath_write_kreg( dd, dd->ipath_kregs->kr_rcvctrl,
- 			dd->ipath_rcvctrl);
-@@ -2149,11 +2142,15 @@ static int ipath_get_slave_info(struct ipath_portdata *pd,
  
- static int ipath_force_pio_avail_update(struct ipath_devdata *dd)
+@@ -1328,7 +1506,7 @@ int ipoib_cm_dev_init(struct net_device *dev)
+ void ipoib_cm_dev_cleanup(struct net_device *dev)
+ {
+ 	struct ipoib_dev_priv *priv = netdev_priv(dev);
+-	int i, ret;
++	int ret;
+ 
+ 	if (!priv->cm.srq)
+ 		return;
+@@ -1342,13 +1520,7 @@ void ipoib_cm_dev_cleanup(struct net_device *dev)
+ 	priv->cm.srq = NULL;
+ 	if (!priv->cm.srq_ring)
+ 		return;
+-	for (i = 0; i < ipoib_recvq_size; ++i)
+-		if (priv->cm.srq_ring[i].skb) {
+-			ipoib_cm_dma_unmap_rx(priv, IPOIB_CM_RX_SG - 1,
+-					      priv->cm.srq_ring[i].mapping);
+-			dev_kfree_skb_any(priv->cm.srq_ring[i].skb);
+-			priv->cm.srq_ring[i].skb = NULL;
+-		}
+-	kfree(priv->cm.srq_ring);
++
++	ipoib_cm_free_rx_ring(dev, priv->cm.srq_ring);
+ 	priv->cm.srq_ring = NULL;
+ }
+diff --git a/drivers/infiniband/ulp/ipoib/ipoib_fs.c b/drivers/infiniband/ulp/ipoib/ipoib_fs.c
+index 44c1741..8b882bb 100644
+--- a/drivers/infiniband/ulp/ipoib/ipoib_fs.c
++++ b/drivers/infiniband/ulp/ipoib/ipoib_fs.c
+@@ -124,7 +124,7 @@ static int ipoib_mcg_seq_show(struct seq_file *file, void *iter_ptr)
+ 	return 0;
+ }
+ 
+-static struct seq_operations ipoib_mcg_seq_ops = {
++static const struct seq_operations ipoib_mcg_seq_ops = {
+ 	.start = ipoib_mcg_seq_start,
+ 	.next  = ipoib_mcg_seq_next,
+ 	.stop  = ipoib_mcg_seq_stop,
+@@ -230,7 +230,7 @@ static int ipoib_path_seq_show(struct seq_file *file, void *iter_ptr)
+ 	return 0;
+ }
+ 
+-static struct seq_operations ipoib_path_seq_ops = {
++static const struct seq_operations ipoib_path_seq_ops = {
+ 	.start = ipoib_path_seq_start,
+ 	.next  = ipoib_path_seq_next,
+ 	.stop  = ipoib_path_seq_stop,
+diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/drivers/infiniband/ulp/ipoib/ipoib_ib.c
+index 5063dd5..52bc2bd 100644
+--- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c
++++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c
+@@ -345,12 +345,12 @@ static inline int post_send(struct ipoib_dev_priv *priv,
  {
--	u64 reg = dd->ipath_sendctrl;
-+	unsigned long flags;
+ 	struct ib_send_wr *bad_wr;
  
--	clear_bit(IPATH_S_PIOBUFAVAILUPD, &reg);
--	ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, reg);
-+	spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags);
-+	ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
-+		dd->ipath_sendctrl & ~INFINIPATH_S_PIOBUFAVAILUPD);
-+	ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
- 	ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, dd->ipath_sendctrl);
-+	ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
-+	spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags);
+-	priv->tx_sge.addr             = addr;
+-	priv->tx_sge.length           = len;
++	priv->tx_sge.addr	      = addr;
++	priv->tx_sge.length	      = len;
  
- 	return 0;
+-	priv->tx_wr.wr_id 	      = wr_id;
++	priv->tx_wr.wr_id	      = wr_id;
+ 	priv->tx_wr.wr.ud.remote_qpn  = qpn;
+-	priv->tx_wr.wr.ud.ah 	      = address;
++	priv->tx_wr.wr.ud.ah	      = address;
+ 
+ 	return ib_post_send(priv->qp, &priv->tx_wr, &bad_wr);
  }
-@@ -2227,6 +2224,11 @@ static ssize_t ipath_write(struct file *fp, const char __user *data,
- 		dest = &cmd.cmd.poll_type;
- 		src = &ucmd->cmd.poll_type;
- 		break;
-+	case IPATH_CMD_ARMLAUNCH_CTRL:
-+		copy = sizeof(cmd.cmd.armlaunch_ctrl);
-+		dest = &cmd.cmd.armlaunch_ctrl;
-+		src = &ucmd->cmd.armlaunch_ctrl;
-+		break;
- 	default:
- 		ret = -EINVAL;
- 		goto bail;
-@@ -2302,6 +2304,12 @@ static ssize_t ipath_write(struct file *fp, const char __user *data,
- 	case IPATH_CMD_POLL_TYPE:
- 		pd->poll_type = cmd.cmd.poll_type;
- 		break;
-+	case IPATH_CMD_ARMLAUNCH_CTRL:
-+		if (cmd.cmd.armlaunch_ctrl)
-+			ipath_enable_armlaunch(pd->port_dd);
-+		else
-+			ipath_disable_armlaunch(pd->port_dd);
-+		break;
+diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c
+index c9f6077..a082466 100644
+--- a/drivers/infiniband/ulp/ipoib/ipoib_main.c
++++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c
+@@ -182,17 +182,20 @@ static int ipoib_change_mtu(struct net_device *dev, int new_mtu)
+ 	struct ipoib_dev_priv *priv = netdev_priv(dev);
+ 
+ 	/* dev->mtu > 2K ==> connected mode */
+-	if (ipoib_cm_admin_enabled(dev) && new_mtu <= IPOIB_CM_MTU) {
++	if (ipoib_cm_admin_enabled(dev)) {
++		if (new_mtu > ipoib_cm_max_mtu(dev))
++			return -EINVAL;
++
+ 		if (new_mtu > priv->mcast_mtu)
+ 			ipoib_warn(priv, "mtu > %d will cause multicast packet drops.\n",
+ 				   priv->mcast_mtu);
++
+ 		dev->mtu = new_mtu;
+ 		return 0;
  	}
  
- 	if (ret >= 0)
-diff --git a/drivers/infiniband/hw/ipath/ipath_fs.c b/drivers/infiniband/hw/ipath/ipath_fs.c
-index 262c25d..23faba9 100644
---- a/drivers/infiniband/hw/ipath/ipath_fs.c
-+++ b/drivers/infiniband/hw/ipath/ipath_fs.c
-@@ -108,21 +108,16 @@ static const struct file_operations atomic_stats_ops = {
- 	.read = atomic_stats_read,
- };
+-	if (new_mtu > IPOIB_PACKET_SIZE - IPOIB_ENCAP_LEN) {
++	if (new_mtu > IPOIB_PACKET_SIZE - IPOIB_ENCAP_LEN)
+ 		return -EINVAL;
+-	}
  
--#define NUM_COUNTERS sizeof(struct infinipath_counters) / sizeof(u64)
+ 	priv->admin_mtu = new_mtu;
+ 
+@@ -474,8 +477,8 @@ static struct ipoib_path *path_rec_create(struct net_device *dev, void *gid)
+ 	INIT_LIST_HEAD(&path->neigh_list);
+ 
+ 	memcpy(path->pathrec.dgid.raw, gid, sizeof (union ib_gid));
+-	path->pathrec.sgid          = priv->local_gid;
+-	path->pathrec.pkey          = cpu_to_be16(priv->pkey);
++	path->pathrec.sgid	    = priv->local_gid;
++	path->pathrec.pkey	    = cpu_to_be16(priv->pkey);
+ 	path->pathrec.numb_path     = 1;
+ 	path->pathrec.traffic_class = priv->broadcast->mcmember.traffic_class;
+ 
+@@ -669,16 +672,6 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev)
+ 	if (unlikely(!spin_trylock_irqsave(&priv->tx_lock, flags)))
+ 		return NETDEV_TX_LOCKED;
+ 
+-	/*
+-	 * Check if our queue is stopped.  Since we have the LLTX bit
+-	 * set, we can't rely on netif_stop_queue() preventing our
+-	 * xmit function from being called with a full queue.
+-	 */
+-	if (unlikely(netif_queue_stopped(dev))) {
+-		spin_unlock_irqrestore(&priv->tx_lock, flags);
+-		return NETDEV_TX_BUSY;
+-	}
 -
- static ssize_t atomic_counters_read(struct file *file, char __user *buf,
- 				    size_t count, loff_t *ppos)
+ 	if (likely(skb->dst && skb->dst->neighbour)) {
+ 		if (unlikely(!*to_ipoib_neigh(skb->dst->neighbour))) {
+ 			ipoib_path_lookup(skb, dev);
+@@ -950,34 +943,34 @@ static void ipoib_setup(struct net_device *dev)
  {
--	u64 counters[NUM_COUNTERS];
--	u16 i;
-+	struct infinipath_counters counters;
- 	struct ipath_devdata *dd;
+ 	struct ipoib_dev_priv *priv = netdev_priv(dev);
  
- 	dd = file->f_path.dentry->d_inode->i_private;
-+	dd->ipath_f_read_counters(dd, &counters);
+-	dev->open 		 = ipoib_open;
+-	dev->stop 		 = ipoib_stop;
+-	dev->change_mtu 	 = ipoib_change_mtu;
+-	dev->hard_start_xmit 	 = ipoib_start_xmit;
+-	dev->tx_timeout 	 = ipoib_timeout;
+-	dev->header_ops 	 = &ipoib_header_ops;
+-	dev->set_multicast_list  = ipoib_set_mcast_list;
+-	dev->neigh_setup         = ipoib_neigh_setup_dev;
++	dev->open		 = ipoib_open;
++	dev->stop		 = ipoib_stop;
++	dev->change_mtu		 = ipoib_change_mtu;
++	dev->hard_start_xmit	 = ipoib_start_xmit;
++	dev->tx_timeout		 = ipoib_timeout;
++	dev->header_ops		 = &ipoib_header_ops;
++	dev->set_multicast_list	 = ipoib_set_mcast_list;
++	dev->neigh_setup	 = ipoib_neigh_setup_dev;
  
--	for (i = 0; i < NUM_COUNTERS; i++)
--		counters[i] = ipath_snap_cntr(dd, i);
--
--	return simple_read_from_buffer(buf, count, ppos, counters,
-+	return simple_read_from_buffer(buf, count, ppos, &counters,
- 				       sizeof counters);
- }
+ 	netif_napi_add(dev, &priv->napi, ipoib_poll, 100);
  
-@@ -243,8 +238,7 @@ static int create_device_files(struct super_block *sb,
+-	dev->watchdog_timeo 	 = HZ;
++	dev->watchdog_timeo	 = HZ;
  
- 	snprintf(unit, sizeof unit, "%02d", dd->ipath_unit);
- 	ret = create_file(unit, S_IFDIR|S_IRUGO|S_IXUGO, sb->s_root, &dir,
--			  (struct file_operations *) &simple_dir_operations,
--			  dd);
-+			  &simple_dir_operations, dd);
- 	if (ret) {
- 		printk(KERN_ERR "create_file(%s) failed: %d\n", unit, ret);
- 		goto bail;
-diff --git a/drivers/infiniband/hw/ipath/ipath_iba6110.c b/drivers/infiniband/hw/ipath/ipath_iba6110.c
-index ddbebe4..9e2ced3 100644
---- a/drivers/infiniband/hw/ipath/ipath_iba6110.c
-+++ b/drivers/infiniband/hw/ipath/ipath_iba6110.c
-@@ -148,10 +148,57 @@ struct _infinipath_do_not_use_kernel_regs {
- 	unsigned long long ReservedSW2[4];
- };
+-	dev->flags              |= IFF_BROADCAST | IFF_MULTICAST;
++	dev->flags		|= IFF_BROADCAST | IFF_MULTICAST;
  
--#define IPATH_KREG_OFFSET(field) (offsetof(struct \
--    _infinipath_do_not_use_kernel_regs, field) / sizeof(u64))
-+struct _infinipath_do_not_use_counters {
-+	__u64 LBIntCnt;
-+	__u64 LBFlowStallCnt;
-+	__u64 Reserved1;
-+	__u64 TxUnsupVLErrCnt;
-+	__u64 TxDataPktCnt;
-+	__u64 TxFlowPktCnt;
-+	__u64 TxDwordCnt;
-+	__u64 TxLenErrCnt;
-+	__u64 TxMaxMinLenErrCnt;
-+	__u64 TxUnderrunCnt;
-+	__u64 TxFlowStallCnt;
-+	__u64 TxDroppedPktCnt;
-+	__u64 RxDroppedPktCnt;
-+	__u64 RxDataPktCnt;
-+	__u64 RxFlowPktCnt;
-+	__u64 RxDwordCnt;
-+	__u64 RxLenErrCnt;
-+	__u64 RxMaxMinLenErrCnt;
-+	__u64 RxICRCErrCnt;
-+	__u64 RxVCRCErrCnt;
-+	__u64 RxFlowCtrlErrCnt;
-+	__u64 RxBadFormatCnt;
-+	__u64 RxLinkProblemCnt;
-+	__u64 RxEBPCnt;
-+	__u64 RxLPCRCErrCnt;
-+	__u64 RxBufOvflCnt;
-+	__u64 RxTIDFullErrCnt;
-+	__u64 RxTIDValidErrCnt;
-+	__u64 RxPKeyMismatchCnt;
-+	__u64 RxP0HdrEgrOvflCnt;
-+	__u64 RxP1HdrEgrOvflCnt;
-+	__u64 RxP2HdrEgrOvflCnt;
-+	__u64 RxP3HdrEgrOvflCnt;
-+	__u64 RxP4HdrEgrOvflCnt;
-+	__u64 RxP5HdrEgrOvflCnt;
-+	__u64 RxP6HdrEgrOvflCnt;
-+	__u64 RxP7HdrEgrOvflCnt;
-+	__u64 RxP8HdrEgrOvflCnt;
-+	__u64 Reserved6;
-+	__u64 Reserved7;
-+	__u64 IBStatusChangeCnt;
-+	__u64 IBLinkErrRecoveryCnt;
-+	__u64 IBLinkDownedCnt;
-+	__u64 IBSymbolErrCnt;
-+};
-+
-+#define IPATH_KREG_OFFSET(field) (offsetof( \
-+	struct _infinipath_do_not_use_kernel_regs, field) / sizeof(u64))
- #define IPATH_CREG_OFFSET(field) (offsetof( \
--    struct infinipath_counters, field) / sizeof(u64))
-+	struct _infinipath_do_not_use_counters, field) / sizeof(u64))
+ 	/*
+ 	 * We add in INFINIBAND_ALEN to allow for the destination
+ 	 * address "pseudoheader" for skbs without neighbour struct.
+ 	 */
+-	dev->hard_header_len 	 = IPOIB_ENCAP_LEN + INFINIBAND_ALEN;
+-	dev->addr_len 		 = INFINIBAND_ALEN;
+-	dev->type 		 = ARPHRD_INFINIBAND;
+-	dev->tx_queue_len 	 = ipoib_sendq_size * 2;
+-	dev->features            = NETIF_F_VLAN_CHALLENGED | NETIF_F_LLTX;
++	dev->hard_header_len	 = IPOIB_ENCAP_LEN + INFINIBAND_ALEN;
++	dev->addr_len		 = INFINIBAND_ALEN;
++	dev->type		 = ARPHRD_INFINIBAND;
++	dev->tx_queue_len	 = ipoib_sendq_size * 2;
++	dev->features		 = NETIF_F_VLAN_CHALLENGED | NETIF_F_LLTX;
  
- static const struct ipath_kregs ipath_ht_kregs = {
- 	.kr_control = IPATH_KREG_OFFSET(Control),
-@@ -282,6 +329,9 @@ static const struct ipath_cregs ipath_ht_cregs = {
- #define INFINIPATH_HWE_HTAPLL_RFSLIP        0x1000000000000000ULL
- #define INFINIPATH_HWE_SERDESPLLFAILED      0x2000000000000000ULL
+ 	/* MTU will be reset when mcast join happens */
+-	dev->mtu 		 = IPOIB_PACKET_SIZE - IPOIB_ENCAP_LEN;
+-	priv->mcast_mtu 	 = priv->admin_mtu = dev->mtu;
++	dev->mtu		 = IPOIB_PACKET_SIZE - IPOIB_ENCAP_LEN;
++	priv->mcast_mtu		 = priv->admin_mtu = dev->mtu;
  
-+#define IBA6110_IBCS_LINKTRAININGSTATE_MASK 0xf
-+#define IBA6110_IBCS_LINKSTATE_SHIFT 4
-+
- /* kr_extstatus bits */
- #define INFINIPATH_EXTS_FREQSEL 0x2
- #define INFINIPATH_EXTS_SERDESSEL 0x4
-@@ -296,6 +346,12 @@ static const struct ipath_cregs ipath_ht_cregs = {
- #define INFINIPATH_RT_BUFSIZE_MASK 0x3FFFULL
- #define INFINIPATH_RT_BUFSIZE_SHIFT 48
+ 	memcpy(dev->broadcast, ipv4_bcast_addr, INFINIBAND_ALEN);
  
-+#define INFINIPATH_R_INTRAVAIL_SHIFT 16
-+#define INFINIPATH_R_TAILUPD_SHIFT 31
-+
-+/* kr_xgxsconfig bits */
-+#define INFINIPATH_XGXS_RESET          0x7ULL
-+
- /*
-  * masks and bits that are different in different chips, or present only
-  * in one
-@@ -652,7 +708,6 @@ static int ipath_ht_boardname(struct ipath_devdata *dd, char *name,
- 			      "with ID %u\n", boardrev);
- 		snprintf(name, namelen, "Unknown_InfiniPath_QHT7xxx_%u",
- 			 boardrev);
--		ret = 1;
- 		break;
- 	}
- 	if (n)
-@@ -686,6 +741,13 @@ static int ipath_ht_boardname(struct ipath_devdata *dd, char *name,
- 			      dd->ipath_htspeed);
- 	ret = 0;
+@@ -1268,6 +1261,9 @@ static int __init ipoib_init_module(void)
+ 	ipoib_sendq_size = roundup_pow_of_two(ipoib_sendq_size);
+ 	ipoib_sendq_size = min(ipoib_sendq_size, IPOIB_MAX_QUEUE_SIZE);
+ 	ipoib_sendq_size = max(ipoib_sendq_size, IPOIB_MIN_QUEUE_SIZE);
++#ifdef CONFIG_INFINIBAND_IPOIB_CM
++	ipoib_max_conn_qp = min(ipoib_max_conn_qp, IPOIB_CM_MAX_CONN_QP);
++#endif
  
-+	/*
-+	 * set here, not in ipath_init_*_funcs because we have to do
-+	 * it after we can read chip registers.
-+	 */
-+	dd->ipath_ureg_align =
-+		ipath_read_kreg32(dd, dd->ipath_kregs->kr_pagealign);
-+
- bail:
- 	return ret;
- }
-@@ -969,7 +1031,8 @@ static int ipath_setup_ht_config(struct ipath_devdata *dd,
- 	do {
- 		u8 cap_type;
+ 	ret = ipoib_register_debugfs();
+ 	if (ret)
+diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
+index 9bcfc7a..2628339 100644
+--- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
++++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
+@@ -702,7 +702,7 @@ void ipoib_mcast_send(struct net_device *dev, void *mgid, struct sk_buff *skb)
  
--		/* the HT capability type byte is 3 bytes after the
-+		/*
-+		 * The HT capability type byte is 3 bytes after the
- 		 * capability byte.
- 		 */
- 		if (pci_read_config_byte(pdev, pos + 3, &cap_type)) {
-@@ -982,6 +1045,8 @@ static int ipath_setup_ht_config(struct ipath_devdata *dd,
- 	} while ((pos = pci_find_next_capability(pdev, pos,
- 						 PCI_CAP_ID_HT)));
+ out:
+ 	if (mcast && mcast->ah) {
+-		if (skb->dst            &&
++		if (skb->dst		&&
+ 		    skb->dst->neighbour &&
+ 		    !*to_ipoib_neigh(skb->dst->neighbour)) {
+ 			struct ipoib_neigh *neigh = ipoib_neigh_alloc(skb->dst->neighbour,
+@@ -710,7 +710,7 @@ out:
  
-+	dd->ipath_flags |= IPATH_SWAP_PIOBUFS;
-+
- bail:
- 	return ret;
- }
-@@ -1074,11 +1139,55 @@ static void ipath_setup_ht_setextled(struct ipath_devdata *dd,
+ 			if (neigh) {
+ 				kref_get(&mcast->ah->ref);
+-				neigh->ah  	= mcast->ah;
++				neigh->ah	= mcast->ah;
+ 				list_add_tail(&neigh->list, &mcast->neigh_list);
+ 			}
+ 		}
+@@ -788,10 +788,6 @@ void ipoib_mcast_restart_task(struct work_struct *work)
  
- static void ipath_init_ht_variables(struct ipath_devdata *dd)
- {
-+	/*
-+	 * setup the register offsets, since they are different for each
-+	 * chip
-+	 */
-+	dd->ipath_kregs = &ipath_ht_kregs;
-+	dd->ipath_cregs = &ipath_ht_cregs;
-+
- 	dd->ipath_gpio_sda_num = _IPATH_GPIO_SDA_NUM;
- 	dd->ipath_gpio_scl_num = _IPATH_GPIO_SCL_NUM;
- 	dd->ipath_gpio_sda = IPATH_GPIO_SDA;
- 	dd->ipath_gpio_scl = IPATH_GPIO_SCL;
+ 		memcpy(mgid.raw, mclist->dmi_addr + 4, sizeof mgid);
  
-+	/*
-+	 * Fill in data for field-values that change in newer chips.
-+	 * We dynamically specify only the mask for LINKTRAININGSTATE
-+	 * and only the shift for LINKSTATE, as they are the only ones
-+	 * that change.  Also precalculate the 3 link states of interest
-+	 * and the combined mask.
-+	 */
-+	dd->ibcs_ls_shift = IBA6110_IBCS_LINKSTATE_SHIFT;
-+	dd->ibcs_lts_mask = IBA6110_IBCS_LINKTRAININGSTATE_MASK;
-+	dd->ibcs_mask = (INFINIPATH_IBCS_LINKSTATE_MASK <<
-+		dd->ibcs_ls_shift) | dd->ibcs_lts_mask;
-+	dd->ib_init = (INFINIPATH_IBCS_LT_STATE_LINKUP <<
-+		INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT) |
-+		(INFINIPATH_IBCS_L_STATE_INIT << dd->ibcs_ls_shift);
-+	dd->ib_arm = (INFINIPATH_IBCS_LT_STATE_LINKUP <<
-+		INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT) |
-+		(INFINIPATH_IBCS_L_STATE_ARM << dd->ibcs_ls_shift);
-+	dd->ib_active = (INFINIPATH_IBCS_LT_STATE_LINKUP <<
-+		INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT) |
-+		(INFINIPATH_IBCS_L_STATE_ACTIVE << dd->ibcs_ls_shift);
-+
-+	/*
-+	 * Fill in data for ibcc field-values that change in newer chips.
-+	 * We dynamically specify only the mask for LINKINITCMD
-+	 * and only the shift for LINKCMD and MAXPKTLEN, as they are
-+	 * the only ones that change.
-+	 */
-+	dd->ibcc_lic_mask = INFINIPATH_IBCC_LINKINITCMD_MASK;
-+	dd->ibcc_lc_shift = INFINIPATH_IBCC_LINKCMD_SHIFT;
-+	dd->ibcc_mpl_shift = INFINIPATH_IBCC_MAXPKTLEN_SHIFT;
-+
-+	/* Fill in shifts for RcvCtrl. */
-+	dd->ipath_r_portenable_shift = INFINIPATH_R_PORTENABLE_SHIFT;
-+	dd->ipath_r_intravail_shift = INFINIPATH_R_INTRAVAIL_SHIFT;
-+	dd->ipath_r_tailupd_shift = INFINIPATH_R_TAILUPD_SHIFT;
-+	dd->ipath_r_portcfg_shift = 0; /* Not on IBA6110 */
-+
- 	dd->ipath_i_bitsextant =
- 		(INFINIPATH_I_RCVURG_MASK << INFINIPATH_I_RCVURG_SHIFT) |
- 		(INFINIPATH_I_RCVAVAIL_MASK <<
-@@ -1135,6 +1244,8 @@ static void ipath_init_ht_variables(struct ipath_devdata *dd)
+-		/* Add in the P_Key */
+-		mgid.raw[4] = (priv->pkey >> 8) & 0xff;
+-		mgid.raw[5] = priv->pkey & 0xff;
+-
+ 		mcast = __ipoib_mcast_find(dev, &mgid);
+ 		if (!mcast || test_bit(IPOIB_MCAST_FLAG_SENDONLY, &mcast->flags)) {
+ 			struct ipoib_mcast *nmcast;
+diff --git a/drivers/infiniband/ulp/ipoib/ipoib_verbs.c b/drivers/infiniband/ulp/ipoib/ipoib_verbs.c
+index 3c6e45d..433e99a 100644
+--- a/drivers/infiniband/ulp/ipoib/ipoib_verbs.c
++++ b/drivers/infiniband/ulp/ipoib/ipoib_verbs.c
+@@ -172,8 +172,12 @@ int ipoib_transport_dev_init(struct net_device *dev, struct ib_device *ca)
  
- 	dd->ipath_i_rcvavail_mask = INFINIPATH_I_RCVAVAIL_MASK;
- 	dd->ipath_i_rcvurg_mask = INFINIPATH_I_RCVURG_MASK;
-+	dd->ipath_i_rcvavail_shift = INFINIPATH_I_RCVAVAIL_SHIFT;
-+	dd->ipath_i_rcvurg_shift = INFINIPATH_I_RCVURG_SHIFT;
+ 	size = ipoib_sendq_size + ipoib_recvq_size + 1;
+ 	ret = ipoib_cm_dev_init(dev);
+-	if (!ret)
+-		size += ipoib_recvq_size + 1 /* 1 extra for rx_drain_qp */;
++	if (!ret) {
++		if (ipoib_cm_has_srq(dev))
++			size += ipoib_recvq_size + 1; /* 1 extra for rx_drain_qp */
++		else
++			size += ipoib_recvq_size * ipoib_max_conn_qp;
++	}
  
- 	/*
- 	 * EEPROM error log 0 is TXE Parity errors. 1 is RXE Parity.
-@@ -1148,9 +1259,17 @@ static void ipath_init_ht_variables(struct ipath_devdata *dd)
- 		INFINIPATH_HWE_RXEMEMPARITYERR_MASK <<
- 		INFINIPATH_HWE_RXEMEMPARITYERR_SHIFT;
+ 	priv->cq = ib_create_cq(priv->ca, ipoib_ib_completion, NULL, dev, size, 0);
+ 	if (IS_ERR(priv->cq)) {
+@@ -197,12 +201,12 @@ int ipoib_transport_dev_init(struct net_device *dev, struct ib_device *ca)
+ 	priv->dev->dev_addr[2] = (priv->qp->qp_num >>  8) & 0xff;
+ 	priv->dev->dev_addr[3] = (priv->qp->qp_num      ) & 0xff;
  
--	dd->ipath_eep_st_masks[2].errs_to_log =
--		INFINIPATH_E_INVALIDADDR | INFINIPATH_E_RESET;
-+	dd->ipath_eep_st_masks[2].errs_to_log = INFINIPATH_E_RESET;
+-	priv->tx_sge.lkey 	= priv->mr->lkey;
++	priv->tx_sge.lkey	= priv->mr->lkey;
  
-+	dd->delay_mult = 2; /* SDR, 4X, can't change */
-+
-+	dd->ipath_link_width_supported = IB_WIDTH_1X | IB_WIDTH_4X;
-+	dd->ipath_link_speed_supported = IPATH_IB_SDR;
-+	dd->ipath_link_width_enabled = IB_WIDTH_4X;
-+	dd->ipath_link_speed_enabled = dd->ipath_link_speed_supported;
-+	/* these can't change for this chip, so set once */
-+	dd->ipath_link_width_active = dd->ipath_link_width_enabled;
-+	dd->ipath_link_speed_active = dd->ipath_link_speed_enabled;
+-	priv->tx_wr.opcode 	= IB_WR_SEND;
+-	priv->tx_wr.sg_list 	= &priv->tx_sge;
+-	priv->tx_wr.num_sge 	= 1;
+-	priv->tx_wr.send_flags 	= IB_SEND_SIGNALED;
++	priv->tx_wr.opcode	= IB_WR_SEND;
++	priv->tx_wr.sg_list	= &priv->tx_sge;
++	priv->tx_wr.num_sge	= 1;
++	priv->tx_wr.send_flags	= IB_SEND_SIGNALED;
+ 
+ 	return 0;
+ 
+diff --git a/drivers/infiniband/ulp/iser/Kconfig b/drivers/infiniband/ulp/iser/Kconfig
+index fe604c8..77dedba 100644
+--- a/drivers/infiniband/ulp/iser/Kconfig
++++ b/drivers/infiniband/ulp/iser/Kconfig
+@@ -8,5 +8,5 @@ config INFINIBAND_ISER
+           that speak iSCSI over iSER over InfiniBand.
+ 
+ 	  The iSER protocol is defined by IETF.
+-	  See <http://www.ietf.org/internet-drafts/draft-ietf-ips-iser-05.txt>
+-	  and <http://www.infinibandta.org/members/spec/iser_annex_060418.pdf>
++	  See <http://www.ietf.org/rfc/rfc5046.txt>
++	  and <http://www.infinibandta.org/members/spec/Annex_iSER.PDF>
+diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c
+index bad8dac..be1b9fb 100644
+--- a/drivers/infiniband/ulp/iser/iscsi_iser.c
++++ b/drivers/infiniband/ulp/iser/iscsi_iser.c
+@@ -129,7 +129,7 @@ error:
+  * iscsi_iser_cmd_init - Initialize iSCSI SCSI_READ or SCSI_WRITE commands
+  *
+  **/
+-static void
++static int
+ iscsi_iser_cmd_init(struct iscsi_cmd_task *ctask)
+ {
+ 	struct iscsi_iser_conn     *iser_conn  = ctask->conn->dd_data;
+@@ -138,6 +138,7 @@ iscsi_iser_cmd_init(struct iscsi_cmd_task *ctask)
+ 	iser_ctask->command_sent = 0;
+ 	iser_ctask->iser_conn    = iser_conn;
+ 	iser_ctask_rdma_init(iser_ctask);
++	return 0;
  }
  
  /**
-@@ -1205,14 +1324,16 @@ static void ipath_ht_init_hwerrors(struct ipath_devdata *dd)
- 	val &= ~INFINIPATH_HWE_HTCMISCERR4;
+@@ -220,12 +221,6 @@ iscsi_iser_ctask_xmit(struct iscsi_conn *conn,
+ 	debug_scsi("ctask deq [cid %d itt 0x%x]\n",
+ 		   conn->id, ctask->itt);
  
- 	/*
--	 * PLL ignored because MDIO interface has a logic problem
--	 * for reads, on Comstock and Ponderosa.  BRINGUP
-+	 * PLL ignored because unused MDIO interface has a logic problem
- 	 */
- 	if (dd->ipath_boardrev == 4 || dd->ipath_boardrev == 9)
- 		val &= ~INFINIPATH_HWE_SERDESPLLFAILED;
- 	dd->ipath_hwerrmask = val;
+-	/*
+-	 * serialize with TMF AbortTask
+-	 */
+-	if (ctask->mtask)
+-		return error;
+-
+ 	/* Send the cmd PDU */
+ 	if (!iser_ctask->command_sent) {
+ 		error = iser_send_command(conn, ctask);
+@@ -406,6 +401,7 @@ iscsi_iser_session_create(struct iscsi_transport *iscsit,
+ 		ctask      = session->cmds[i];
+ 		iser_ctask = ctask->dd_data;
+ 		ctask->hdr = (struct iscsi_cmd *)&iser_ctask->desc.iscsi_header;
++		ctask->hdr_max = sizeof(iser_ctask->desc.iscsi_header);
+ 	}
+ 
+ 	for (i = 0; i < session->mgmtpool_max; i++) {
+@@ -551,11 +547,13 @@ static struct scsi_host_template iscsi_iser_sht = {
+ 	.module                 = THIS_MODULE,
+ 	.name                   = "iSCSI Initiator over iSER, v." DRV_VER,
+ 	.queuecommand           = iscsi_queuecommand,
++	.change_queue_depth	= iscsi_change_queue_depth,
+ 	.can_queue		= ISCSI_DEF_XMIT_CMDS_MAX - 1,
+ 	.sg_tablesize           = ISCSI_ISER_SG_TABLESIZE,
+ 	.max_sectors		= 1024,
+ 	.cmd_per_lun            = ISCSI_MAX_CMD_PER_LUN,
+ 	.eh_abort_handler       = iscsi_eh_abort,
++	.eh_device_reset_handler= iscsi_eh_device_reset,
+ 	.eh_host_reset_handler	= iscsi_eh_host_reset,
+ 	.use_clustering         = DISABLE_CLUSTERING,
+ 	.proc_name              = "iscsi_iser",
+@@ -582,7 +580,9 @@ static struct iscsi_transport iscsi_iser_transport = {
+ 				  ISCSI_PERSISTENT_ADDRESS |
+ 				  ISCSI_TARGET_NAME | ISCSI_TPGT |
+ 				  ISCSI_USERNAME | ISCSI_PASSWORD |
+-				  ISCSI_USERNAME_IN | ISCSI_PASSWORD_IN,
++				  ISCSI_USERNAME_IN | ISCSI_PASSWORD_IN |
++				  ISCSI_FAST_ABORT | ISCSI_ABORT_TMO |
++				  ISCSI_PING_TMO | ISCSI_RECV_TMO,
+ 	.host_param_mask	= ISCSI_HOST_HWADDRESS |
+ 				  ISCSI_HOST_NETDEV_NAME |
+ 				  ISCSI_HOST_INITIATOR_NAME,
+diff --git a/drivers/infiniband/ulp/iser/iser_initiator.c b/drivers/infiniband/ulp/iser/iser_initiator.c
+index a6f2303..83247f1 100644
+--- a/drivers/infiniband/ulp/iser/iser_initiator.c
++++ b/drivers/infiniband/ulp/iser/iser_initiator.c
+@@ -561,7 +561,7 @@ void iser_rcv_completion(struct iser_desc *rx_desc,
+ 	if (opcode == ISCSI_OP_SCSI_CMD_RSP) {
+ 	        itt = get_itt(hdr->itt); /* mask out cid and age bits */
+ 		if (!(itt < session->cmds_max))
+-			iser_err("itt can't be matched to task!!!"
++			iser_err("itt can't be matched to task!!! "
+ 				 "conn %p opcode %d cmds_max %d itt %d\n",
+ 				 conn->iscsi_conn,opcode,session->cmds_max,itt);
+ 		/* use the mapping given with the cmds array indexed by itt */
+@@ -621,9 +621,7 @@ void iser_snd_completion(struct iser_desc *tx_desc)
+ 			struct iscsi_session *session = conn->session;
+ 
+ 			spin_lock(&conn->session->lock);
+-			list_del(&mtask->running);
+-			__kfifo_put(session->mgmtpool.queue, (void*)&mtask,
+-				    sizeof(void*));
++			iscsi_free_mgmt_task(conn, mtask);
+ 			spin_unlock(&session->lock);
+ 		}
+ 	}
+diff --git a/drivers/infiniband/ulp/iser/iser_verbs.c b/drivers/infiniband/ulp/iser/iser_verbs.c
+index 654a4dc..714b8db 100644
+--- a/drivers/infiniband/ulp/iser/iser_verbs.c
++++ b/drivers/infiniband/ulp/iser/iser_verbs.c
+@@ -105,7 +105,7 @@ pd_err:
  }
  
-+
-+
-+
  /**
-  * ipath_ht_bringup_serdes - bring up the serdes
-  * @dd: the infinipath device
-@@ -1284,16 +1405,6 @@ static int ipath_ht_bringup_serdes(struct ipath_devdata *dd)
+- * iser_free_device_ib_res - destory/dealloc/dereg the DMA MR,
++ * iser_free_device_ib_res - destroy/dealloc/dereg the DMA MR,
+  * CQ and PD created with the device associated with the adapator.
+  */
+ static void iser_free_device_ib_res(struct iser_device *device)
+@@ -475,13 +475,11 @@ static int iser_cma_handler(struct rdma_cm_id *cma_id, struct rdma_cm_event *eve
+ 		iser_disconnected_handler(cma_id);
+ 		break;
+ 	case RDMA_CM_EVENT_DEVICE_REMOVAL:
++		iser_err("Device removal is currently unsupported\n");
+ 		BUG();
+ 		break;
+-	case RDMA_CM_EVENT_CONNECT_RESPONSE:
+-		BUG();
+-		break;
+-	case RDMA_CM_EVENT_CONNECT_REQUEST:
+ 	default:
++		iser_err("Unexpected RDMA CM event (%d)\n", event->event);
+ 		break;
  	}
+ 	return ret;
+diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c
+index bdb6f85..f2d2c7e 100644
+--- a/drivers/infiniband/ulp/srp/ib_srp.c
++++ b/drivers/infiniband/ulp/srp/ib_srp.c
+@@ -272,7 +272,8 @@ static void srp_path_rec_completion(int status,
  
- 	val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_xgxsconfig);
--	if (((val >> INFINIPATH_XGXS_MDIOADDR_SHIFT) &
--	     INFINIPATH_XGXS_MDIOADDR_MASK) != 3) {
--		val &= ~(INFINIPATH_XGXS_MDIOADDR_MASK <<
--			 INFINIPATH_XGXS_MDIOADDR_SHIFT);
--		/*
--		 * we use address 3
--		 */
--		val |= 3ULL << INFINIPATH_XGXS_MDIOADDR_SHIFT;
--		change = 1;
--	}
- 	if (val & INFINIPATH_XGXS_RESET) {
- 		/* normally true after boot */
- 		val &= ~INFINIPATH_XGXS_RESET;
-@@ -1329,21 +1440,6 @@ static int ipath_ht_bringup_serdes(struct ipath_devdata *dd)
- 		   (unsigned long long)
- 		   ipath_read_kreg64(dd, dd->ipath_kregs->kr_xgxsconfig));
+ 	target->status = status;
+ 	if (status)
+-		printk(KERN_ERR PFX "Got failed path rec status %d\n", status);
++		shost_printk(KERN_ERR, target->scsi_host,
++			     PFX "Got failed path rec status %d\n", status);
+ 	else
+ 		target->path = *pathrec;
+ 	complete(&target->done);
+@@ -303,7 +304,8 @@ static int srp_lookup_path(struct srp_target_port *target)
+ 	wait_for_completion(&target->done);
  
--	if (!ipath_waitfor_mdio_cmdready(dd)) {
--		ipath_write_kreg(dd, dd->ipath_kregs->kr_mdio,
--				 ipath_mdio_req(IPATH_MDIO_CMD_READ, 31,
--						IPATH_MDIO_CTRL_XGXS_REG_8,
--						0));
--		if (ipath_waitfor_complete(dd, dd->ipath_kregs->kr_mdio,
--					   IPATH_MDIO_DATAVALID, &val))
--			ipath_dbg("Never got MDIO data for XGXS status "
--				  "read\n");
--		else
--			ipath_cdbg(VERBOSE, "MDIO Read reg8, "
--				   "'bank' 31 %x\n", (u32) val);
--	} else
--		ipath_dbg("Never got MDIO cmdready for XGXS status read\n");
--
- 	return ret;		/* for now, say we always succeeded */
+ 	if (target->status < 0)
+-		printk(KERN_WARNING PFX "Path record query failed\n");
++		shost_printk(KERN_WARNING, target->scsi_host,
++			     PFX "Path record query failed\n");
+ 
+ 	return target->status;
  }
+@@ -379,9 +381,10 @@ static int srp_send_req(struct srp_target_port *target)
+ 	 * the second 8 bytes to the local node GUID.
+ 	 */
+ 	if (srp_target_is_topspin(target)) {
+-		printk(KERN_DEBUG PFX "Topspin/Cisco initiator port ID workaround "
+-		       "activated for target GUID %016llx\n",
+-		       (unsigned long long) be64_to_cpu(target->ioc_guid));
++		shost_printk(KERN_DEBUG, target->scsi_host,
++			     PFX "Topspin/Cisco initiator port ID workaround "
++			     "activated for target GUID %016llx\n",
++			     (unsigned long long) be64_to_cpu(target->ioc_guid));
+ 		memset(req->priv.initiator_port_id, 0, 8);
+ 		memcpy(req->priv.initiator_port_id + 8,
+ 		       &target->srp_host->dev->dev->node_guid, 8);
+@@ -400,7 +403,8 @@ static void srp_disconnect_target(struct srp_target_port *target)
  
-@@ -1396,6 +1492,7 @@ static void ipath_ht_put_tid(struct ipath_devdata *dd,
- 			pa |= lenvalid | INFINIPATH_RT_VALID;
- 		}
+ 	init_completion(&target->done);
+ 	if (ib_send_cm_dreq(target->cm_id, NULL, 0)) {
+-		printk(KERN_DEBUG PFX "Sending CM DREQ failed\n");
++		shost_printk(KERN_DEBUG, target->scsi_host,
++			     PFX "Sending CM DREQ failed\n");
+ 		return;
  	}
-+
- 	writeq(pa, tidptr);
- }
+ 	wait_for_completion(&target->done);
+@@ -568,7 +572,8 @@ static int srp_reconnect_target(struct srp_target_port *target)
+ 	return ret;
  
-@@ -1526,8 +1623,7 @@ static int ipath_ht_early_init(struct ipath_devdata *dd)
+ err:
+-	printk(KERN_ERR PFX "reconnect failed (%d), removing target port.\n", ret);
++	shost_printk(KERN_ERR, target->scsi_host,
++		     PFX "reconnect failed (%d), removing target port.\n", ret);
+ 
+ 	/*
+ 	 * We couldn't reconnect, so kill our target port off.
+@@ -683,8 +688,9 @@ static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_target_port *target,
+ 
+ 	if (scmnd->sc_data_direction != DMA_FROM_DEVICE &&
+ 	    scmnd->sc_data_direction != DMA_TO_DEVICE) {
+-		printk(KERN_WARNING PFX "Unhandled data direction %d\n",
+-		       scmnd->sc_data_direction);
++		shost_printk(KERN_WARNING, target->scsi_host,
++			     PFX "Unhandled data direction %d\n",
++			     scmnd->sc_data_direction);
+ 		return -EINVAL;
  	}
  
- 	ipath_get_eeprom_info(dd);
--	if (dd->ipath_boardrev == 5 && dd->ipath_serial[0] == '1' &&
--		dd->ipath_serial[1] == '2' && dd->ipath_serial[2] == '8') {
-+	if (dd->ipath_boardrev == 5) {
- 		/*
- 		 * Later production QHT7040 has same changes as QHT7140, so
- 		 * can use GPIO interrupts.  They have serial #'s starting
-@@ -1602,6 +1698,210 @@ static void ipath_ht_free_irq(struct ipath_devdata *dd)
- 	dd->ipath_intconfig = 0;
- }
+@@ -786,8 +792,9 @@ static void srp_process_rsp(struct srp_target_port *target, struct srp_rsp *rsp)
+ 	} else {
+ 		scmnd = req->scmnd;
+ 		if (!scmnd)
+-			printk(KERN_ERR "Null scmnd for RSP w/tag %016llx\n",
+-			       (unsigned long long) rsp->tag);
++			shost_printk(KERN_ERR, target->scsi_host,
++				     "Null scmnd for RSP w/tag %016llx\n",
++				     (unsigned long long) rsp->tag);
+ 		scmnd->result = rsp->status;
  
-+static struct ipath_message_header *
-+ipath_ht_get_msgheader(struct ipath_devdata *dd, __le32 *rhf_addr)
-+{
-+	return (struct ipath_message_header *)
-+		&rhf_addr[sizeof(u64) / sizeof(u32)];
-+}
-+
-+static void ipath_ht_config_ports(struct ipath_devdata *dd, ushort cfgports)
-+{
-+	dd->ipath_portcnt =
-+		ipath_read_kreg32(dd, dd->ipath_kregs->kr_portcnt);
-+	dd->ipath_p0_rcvegrcnt =
-+		ipath_read_kreg32(dd, dd->ipath_kregs->kr_rcvegrcnt);
-+}
-+
-+static void ipath_ht_read_counters(struct ipath_devdata *dd,
-+				   struct infinipath_counters *cntrs)
-+{
-+	cntrs->LBIntCnt =
-+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(LBIntCnt));
-+	cntrs->LBFlowStallCnt =
-+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(LBFlowStallCnt));
-+	cntrs->TxSDmaDescCnt = 0;
-+	cntrs->TxUnsupVLErrCnt =
-+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxUnsupVLErrCnt));
-+	cntrs->TxDataPktCnt =
-+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxDataPktCnt));
-+	cntrs->TxFlowPktCnt =
-+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxFlowPktCnt));
-+	cntrs->TxDwordCnt =
-+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxDwordCnt));
-+	cntrs->TxLenErrCnt =
-+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxLenErrCnt));
-+	cntrs->TxMaxMinLenErrCnt =
-+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxMaxMinLenErrCnt));
-+	cntrs->TxUnderrunCnt =
-+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxUnderrunCnt));
-+	cntrs->TxFlowStallCnt =
-+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxFlowStallCnt));
-+	cntrs->TxDroppedPktCnt =
-+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxDroppedPktCnt));
-+	cntrs->RxDroppedPktCnt =
-+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxDroppedPktCnt));
-+	cntrs->RxDataPktCnt =
-+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxDataPktCnt));
-+	cntrs->RxFlowPktCnt =
-+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxFlowPktCnt));
-+	cntrs->RxDwordCnt =
-+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxDwordCnt));
-+	cntrs->RxLenErrCnt =
-+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxLenErrCnt));
-+	cntrs->RxMaxMinLenErrCnt =
-+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxMaxMinLenErrCnt));
-+	cntrs->RxICRCErrCnt =
-+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxICRCErrCnt));
-+	cntrs->RxVCRCErrCnt =
-+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxVCRCErrCnt));
-+	cntrs->RxFlowCtrlErrCnt =
-+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxFlowCtrlErrCnt));
-+	cntrs->RxBadFormatCnt =
-+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxBadFormatCnt));
-+	cntrs->RxLinkProblemCnt =
-+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxLinkProblemCnt));
-+	cntrs->RxEBPCnt =
-+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxEBPCnt));
-+	cntrs->RxLPCRCErrCnt =
-+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxLPCRCErrCnt));
-+	cntrs->RxBufOvflCnt =
-+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxBufOvflCnt));
-+	cntrs->RxTIDFullErrCnt =
-+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxTIDFullErrCnt));
-+	cntrs->RxTIDValidErrCnt =
-+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxTIDValidErrCnt));
-+	cntrs->RxPKeyMismatchCnt =
-+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxPKeyMismatchCnt));
-+	cntrs->RxP0HdrEgrOvflCnt =
-+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP0HdrEgrOvflCnt));
-+	cntrs->RxP1HdrEgrOvflCnt =
-+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP1HdrEgrOvflCnt));
-+	cntrs->RxP2HdrEgrOvflCnt =
-+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP2HdrEgrOvflCnt));
-+	cntrs->RxP3HdrEgrOvflCnt =
-+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP3HdrEgrOvflCnt));
-+	cntrs->RxP4HdrEgrOvflCnt =
-+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP4HdrEgrOvflCnt));
-+	cntrs->RxP5HdrEgrOvflCnt =
-+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP5HdrEgrOvflCnt));
-+	cntrs->RxP6HdrEgrOvflCnt =
-+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP6HdrEgrOvflCnt));
-+	cntrs->RxP7HdrEgrOvflCnt =
-+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP7HdrEgrOvflCnt));
-+	cntrs->RxP8HdrEgrOvflCnt =
-+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP8HdrEgrOvflCnt));
-+	cntrs->RxP9HdrEgrOvflCnt = 0;
-+	cntrs->RxP10HdrEgrOvflCnt = 0;
-+	cntrs->RxP11HdrEgrOvflCnt = 0;
-+	cntrs->RxP12HdrEgrOvflCnt = 0;
-+	cntrs->RxP13HdrEgrOvflCnt = 0;
-+	cntrs->RxP14HdrEgrOvflCnt = 0;
-+	cntrs->RxP15HdrEgrOvflCnt = 0;
-+	cntrs->RxP16HdrEgrOvflCnt = 0;
-+	cntrs->IBStatusChangeCnt =
-+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(IBStatusChangeCnt));
-+	cntrs->IBLinkErrRecoveryCnt =
-+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(IBLinkErrRecoveryCnt));
-+	cntrs->IBLinkDownedCnt =
-+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(IBLinkDownedCnt));
-+	cntrs->IBSymbolErrCnt =
-+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(IBSymbolErrCnt));
-+	cntrs->RxVL15DroppedPktCnt = 0;
-+	cntrs->RxOtherLocalPhyErrCnt = 0;
-+	cntrs->PcieRetryBufDiagQwordCnt = 0;
-+	cntrs->ExcessBufferOvflCnt = dd->ipath_overrun_thresh_errs;
-+	cntrs->LocalLinkIntegrityErrCnt =
-+		(dd->ipath_flags & IPATH_GPIO_ERRINTRS) ?
-+		dd->ipath_lli_errs : dd->ipath_lli_errors;
-+	cntrs->RxVlErrCnt = 0;
-+	cntrs->RxDlidFltrCnt = 0;
-+}
-+
-+
-+/* no interrupt fallback for these chips */
-+static int ipath_ht_nointr_fallback(struct ipath_devdata *dd)
-+{
-+	return 0;
-+}
-+
-+
-+/*
-+ * reset the XGXS (between serdes and IBC).  Slightly less intrusive
-+ * than resetting the IBC or external link state, and useful in some
-+ * cases to cause some retraining.  To do this right, we reset IBC
-+ * as well.
-+ */
-+static void ipath_ht_xgxs_reset(struct ipath_devdata *dd)
-+{
-+	u64 val, prev_val;
-+
-+	prev_val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_xgxsconfig);
-+	val = prev_val | INFINIPATH_XGXS_RESET;
-+	prev_val &= ~INFINIPATH_XGXS_RESET; /* be sure */
-+	ipath_write_kreg(dd, dd->ipath_kregs->kr_control,
-+			 dd->ipath_control & ~INFINIPATH_C_LINKENABLE);
-+	ipath_write_kreg(dd, dd->ipath_kregs->kr_xgxsconfig, val);
-+	ipath_read_kreg32(dd, dd->ipath_kregs->kr_scratch);
-+	ipath_write_kreg(dd, dd->ipath_kregs->kr_xgxsconfig, prev_val);
-+	ipath_write_kreg(dd, dd->ipath_kregs->kr_control,
-+			 dd->ipath_control);
-+}
-+
-+
-+static int ipath_ht_get_ib_cfg(struct ipath_devdata *dd, int which)
-+{
-+	int ret;
-+
-+	switch (which) {
-+	case IPATH_IB_CFG_LWID:
-+		ret = dd->ipath_link_width_active;
-+		break;
-+	case IPATH_IB_CFG_SPD:
-+		ret = dd->ipath_link_speed_active;
-+		break;
-+	case IPATH_IB_CFG_LWID_ENB:
-+		ret = dd->ipath_link_width_enabled;
-+		break;
-+	case IPATH_IB_CFG_SPD_ENB:
-+		ret = dd->ipath_link_speed_enabled;
-+		break;
-+	default:
-+		ret =  -ENOTSUPP;
-+		break;
-+	}
-+	return ret;
-+}
-+
-+
-+/* we assume range checking is already done, if needed */
-+static int ipath_ht_set_ib_cfg(struct ipath_devdata *dd, int which, u32 val)
-+{
-+	int ret = 0;
-+
-+	if (which == IPATH_IB_CFG_LWID_ENB)
-+		dd->ipath_link_width_enabled = val;
-+	else if (which == IPATH_IB_CFG_SPD_ENB)
-+		dd->ipath_link_speed_enabled = val;
-+	else
-+		ret = -ENOTSUPP;
-+	return ret;
-+}
-+
-+
-+static void ipath_ht_config_jint(struct ipath_devdata *dd, u16 a, u16 b)
-+{
-+}
-+
-+
-+static int ipath_ht_ib_updown(struct ipath_devdata *dd, int ibup, u64 ibcs)
-+{
-+	ipath_setup_ht_setextled(dd, ipath_ib_linkstate(dd, ibcs),
-+		ipath_ib_linktrstate(dd, ibcs));
-+	return 0;
-+}
-+
+ 		if (rsp->flags & SRP_RSP_FLAG_SNSVALID) {
+@@ -831,7 +838,8 @@ static void srp_handle_recv(struct srp_target_port *target, struct ib_wc *wc)
+ 	if (0) {
+ 		int i;
+ 
+-		printk(KERN_ERR PFX "recv completion, opcode 0x%02x\n", opcode);
++		shost_printk(KERN_ERR, target->scsi_host,
++			     PFX "recv completion, opcode 0x%02x\n", opcode);
+ 
+ 		for (i = 0; i < wc->byte_len; ++i) {
+ 			if (i % 8 == 0)
+@@ -852,11 +860,13 @@ static void srp_handle_recv(struct srp_target_port *target, struct ib_wc *wc)
+ 
+ 	case SRP_T_LOGOUT:
+ 		/* XXX Handle target logout */
+-		printk(KERN_WARNING PFX "Got target logout request\n");
++		shost_printk(KERN_WARNING, target->scsi_host,
++			     PFX "Got target logout request\n");
+ 		break;
+ 
+ 	default:
+-		printk(KERN_WARNING PFX "Unhandled SRP opcode 0x%02x\n", opcode);
++		shost_printk(KERN_WARNING, target->scsi_host,
++			     PFX "Unhandled SRP opcode 0x%02x\n", opcode);
+ 		break;
+ 	}
+ 
+@@ -872,9 +882,10 @@ static void srp_completion(struct ib_cq *cq, void *target_ptr)
+ 	ib_req_notify_cq(cq, IB_CQ_NEXT_COMP);
+ 	while (ib_poll_cq(cq, 1, &wc) > 0) {
+ 		if (wc.status) {
+-			printk(KERN_ERR PFX "failed %s status %d\n",
+-			       wc.wr_id & SRP_OP_RECV ? "receive" : "send",
+-			       wc.status);
++			shost_printk(KERN_ERR, target->scsi_host,
++				     PFX "failed %s status %d\n",
++				     wc.wr_id & SRP_OP_RECV ? "receive" : "send",
++				     wc.status);
+ 			target->qp_in_error = 1;
+ 			break;
+ 		}
+@@ -930,13 +941,18 @@ static int srp_post_recv(struct srp_target_port *target)
+  * req_lim and tx_head.  Lock cannot be dropped between call here and
+  * call to __srp_post_send().
+  */
+-static struct srp_iu *__srp_get_tx_iu(struct srp_target_port *target)
++static struct srp_iu *__srp_get_tx_iu(struct srp_target_port *target,
++					enum srp_request_type req_type)
+ {
++	s32 min = (req_type == SRP_REQ_TASK_MGMT) ? 1 : 2;
 +
- /**
-  * ipath_init_iba6110_funcs - set up the chip-specific function pointers
-  * @dd: the infinipath device
-@@ -1626,22 +1926,19 @@ void ipath_init_iba6110_funcs(struct ipath_devdata *dd)
- 	dd->ipath_f_setextled = ipath_setup_ht_setextled;
- 	dd->ipath_f_get_base_info = ipath_ht_get_base_info;
- 	dd->ipath_f_free_irq = ipath_ht_free_irq;
--
--	/*
--	 * initialize chip-specific variables
--	 */
- 	dd->ipath_f_tidtemplate = ipath_ht_tidtemplate;
-+	dd->ipath_f_intr_fallback = ipath_ht_nointr_fallback;
-+	dd->ipath_f_get_msgheader = ipath_ht_get_msgheader;
-+	dd->ipath_f_config_ports = ipath_ht_config_ports;
-+	dd->ipath_f_read_counters = ipath_ht_read_counters;
-+	dd->ipath_f_xgxs_reset = ipath_ht_xgxs_reset;
-+	dd->ipath_f_get_ib_cfg = ipath_ht_get_ib_cfg;
-+	dd->ipath_f_set_ib_cfg = ipath_ht_set_ib_cfg;
-+	dd->ipath_f_config_jint = ipath_ht_config_jint;
-+	dd->ipath_f_ib_updown = ipath_ht_ib_updown;
+ 	if (target->tx_head - target->tx_tail >= SRP_SQ_SIZE)
+ 		return NULL;
+ 
+-	if (unlikely(target->req_lim < 1))
++	if (target->req_lim < min) {
+ 		++target->zero_req_lim;
++		return NULL;
++	}
  
- 	/*
--	 * setup the register offsets, since they are different for each
--	 * chip
--	 */
--	dd->ipath_kregs = &ipath_ht_kregs;
--	dd->ipath_cregs = &ipath_ht_cregs;
--
--	/*
--	 * do very early init that is needed before ipath_f_bus is
--	 * called
-+	 * initialize chip-specific variables
- 	 */
- 	ipath_init_ht_variables(dd);
+ 	return target->tx_ring[target->tx_head & SRP_SQ_SIZE];
  }
-diff --git a/drivers/infiniband/hw/ipath/ipath_iba6120.c b/drivers/infiniband/hw/ipath/ipath_iba6120.c
-index 0103d6f..c7a2f50 100644
---- a/drivers/infiniband/hw/ipath/ipath_iba6120.c
-+++ b/drivers/infiniband/hw/ipath/ipath_iba6120.c
-@@ -145,10 +145,57 @@ struct _infinipath_do_not_use_kernel_regs {
- 	unsigned long long Reserved12;
- };
+@@ -993,7 +1009,7 @@ static int srp_queuecommand(struct scsi_cmnd *scmnd,
+ 		return 0;
+ 	}
  
--#define IPATH_KREG_OFFSET(field) (offsetof(struct \
--    _infinipath_do_not_use_kernel_regs, field) / sizeof(u64))
-+struct _infinipath_do_not_use_counters {
-+	__u64 LBIntCnt;
-+	__u64 LBFlowStallCnt;
-+	__u64 Reserved1;
-+	__u64 TxUnsupVLErrCnt;
-+	__u64 TxDataPktCnt;
-+	__u64 TxFlowPktCnt;
-+	__u64 TxDwordCnt;
-+	__u64 TxLenErrCnt;
-+	__u64 TxMaxMinLenErrCnt;
-+	__u64 TxUnderrunCnt;
-+	__u64 TxFlowStallCnt;
-+	__u64 TxDroppedPktCnt;
-+	__u64 RxDroppedPktCnt;
-+	__u64 RxDataPktCnt;
-+	__u64 RxFlowPktCnt;
-+	__u64 RxDwordCnt;
-+	__u64 RxLenErrCnt;
-+	__u64 RxMaxMinLenErrCnt;
-+	__u64 RxICRCErrCnt;
-+	__u64 RxVCRCErrCnt;
-+	__u64 RxFlowCtrlErrCnt;
-+	__u64 RxBadFormatCnt;
-+	__u64 RxLinkProblemCnt;
-+	__u64 RxEBPCnt;
-+	__u64 RxLPCRCErrCnt;
-+	__u64 RxBufOvflCnt;
-+	__u64 RxTIDFullErrCnt;
-+	__u64 RxTIDValidErrCnt;
-+	__u64 RxPKeyMismatchCnt;
-+	__u64 RxP0HdrEgrOvflCnt;
-+	__u64 RxP1HdrEgrOvflCnt;
-+	__u64 RxP2HdrEgrOvflCnt;
-+	__u64 RxP3HdrEgrOvflCnt;
-+	__u64 RxP4HdrEgrOvflCnt;
-+	__u64 RxP5HdrEgrOvflCnt;
-+	__u64 RxP6HdrEgrOvflCnt;
-+	__u64 RxP7HdrEgrOvflCnt;
-+	__u64 RxP8HdrEgrOvflCnt;
-+	__u64 Reserved6;
-+	__u64 Reserved7;
-+	__u64 IBStatusChangeCnt;
-+	__u64 IBLinkErrRecoveryCnt;
-+	__u64 IBLinkDownedCnt;
-+	__u64 IBSymbolErrCnt;
-+};
-+
-+#define IPATH_KREG_OFFSET(field) (offsetof( \
-+	struct _infinipath_do_not_use_kernel_regs, field) / sizeof(u64))
- #define IPATH_CREG_OFFSET(field) (offsetof( \
--    struct infinipath_counters, field) / sizeof(u64))
-+	struct _infinipath_do_not_use_counters, field) / sizeof(u64))
+-	iu = __srp_get_tx_iu(target);
++	iu = __srp_get_tx_iu(target, SRP_REQ_NORMAL);
+ 	if (!iu)
+ 		goto err;
  
- static const struct ipath_kregs ipath_pe_kregs = {
- 	.kr_control = IPATH_KREG_OFFSET(Control),
-@@ -282,6 +329,9 @@ static const struct ipath_cregs ipath_pe_cregs = {
- #define INFINIPATH_HWE_PCIE0PLLFAILED       0x0800000000000000ULL
- #define INFINIPATH_HWE_SERDESPLLFAILED      0x1000000000000000ULL
+@@ -1022,12 +1038,13 @@ static int srp_queuecommand(struct scsi_cmnd *scmnd,
  
-+#define IBA6120_IBCS_LINKTRAININGSTATE_MASK 0xf
-+#define IBA6120_IBCS_LINKSTATE_SHIFT 4
-+
- /* kr_extstatus bits */
- #define INFINIPATH_EXTS_FREQSEL 0x2
- #define INFINIPATH_EXTS_SERDESSEL 0x4
-@@ -296,6 +346,9 @@ static const struct ipath_cregs ipath_pe_cregs = {
- #define IPATH_GPIO_SCL (1ULL << \
- 	(_IPATH_GPIO_SCL_NUM+INFINIPATH_EXTC_GPIOOE_SHIFT))
+ 	len = srp_map_data(scmnd, target, req);
+ 	if (len < 0) {
+-		printk(KERN_ERR PFX "Failed to map data\n");
++		shost_printk(KERN_ERR, target->scsi_host,
++			     PFX "Failed to map data\n");
+ 		goto err;
+ 	}
  
-+#define INFINIPATH_R_INTRAVAIL_SHIFT 16
-+#define INFINIPATH_R_TAILUPD_SHIFT 31
-+
- /* 6120 specific hardware errors... */
- static const struct ipath_hwerror_msgs ipath_6120_hwerror_msgs[] = {
- 	INFINIPATH_HWE_MSG(PCIEPOISONEDTLP, "PCIe Poisoned TLP"),
-@@ -320,10 +373,28 @@ static const struct ipath_hwerror_msgs ipath_6120_hwerror_msgs[] = {
- 		        INFINIPATH_HWE_TXEMEMPARITYERR_PIOPBC) \
- 		        << INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT)
+ 	if (__srp_post_recv(target)) {
+-		printk(KERN_ERR PFX "Recv failed\n");
++		shost_printk(KERN_ERR, target->scsi_host, PFX "Recv failed\n");
+ 		goto err_unmap;
+ 	}
  
--static int ipath_pe_txe_recover(struct ipath_devdata *);
- static void ipath_pe_put_tid_2(struct ipath_devdata *, u64 __iomem *,
- 			       u32, unsigned long);
+@@ -1035,7 +1052,7 @@ static int srp_queuecommand(struct scsi_cmnd *scmnd,
+ 				      DMA_TO_DEVICE);
  
-+/*
-+ * On platforms using this chip, and not having ordered WC stores, we
-+ * can get TXE parity errors due to speculative reads to the PIO buffers,
-+ * and this, due to a chip bug can result in (many) false parity error
-+ * reports.  So it's a debug print on those, and an info print on systems
-+ * where the speculative reads don't occur.
-+ */
-+static void ipath_pe_txe_recover(struct ipath_devdata *dd)
-+{
-+	if (ipath_unordered_wc())
-+		ipath_dbg("Recovering from TXE PIO parity error\n");
-+	else {
-+		++ipath_stats.sps_txeparity;
-+		dev_info(&dd->pcidev->dev,
-+			"Recovering from TXE PIO parity error\n");
-+	}
-+}
-+
-+
- /**
-  * ipath_pe_handle_hwerrors - display hardware errors.
-  * @dd: the infinipath device
-@@ -403,35 +474,11 @@ static void ipath_pe_handle_hwerrors(struct ipath_devdata *dd, char *msg,
- 		 * occur if a processor speculative read is done to the PIO
- 		 * buffer while we are sending a packet, for example.
- 		 */
--		if ((hwerrs & TXE_PIO_PARITY) && ipath_pe_txe_recover(dd))
-+		if (hwerrs & TXE_PIO_PARITY) {
-+			ipath_pe_txe_recover(dd);
- 			hwerrs &= ~TXE_PIO_PARITY;
--		if (hwerrs) {
--			/*
--			 * if any set that we aren't ignoring only make the
--			 * complaint once, in case it's stuck or recurring,
--			 * and we get here multiple times
--			 * Force link down, so switch knows, and
--			 * LEDs are turned off
--			 */
--			if (dd->ipath_flags & IPATH_INITTED) {
--				ipath_set_linkstate(dd, IPATH_IB_LINKDOWN);
--				ipath_setup_pe_setextled(dd,
--					INFINIPATH_IBCS_L_STATE_DOWN,
--					INFINIPATH_IBCS_LT_STATE_DISABLED);
--				ipath_dev_err(dd, "Fatal Hardware Error (freeze "
--					      "mode), no longer usable, SN %.16s\n",
--						  dd->ipath_serial);
--				isfatal = 1;
--			}
--			/*
--			 * Mark as having had an error for driver, and also
--			 * for /sys and status word mapped to user programs.
--			 * This marks unit as not usable, until reset
--			 */
--			*dd->ipath_statusp &= ~IPATH_STATUS_IB_READY;
--			*dd->ipath_statusp |= IPATH_STATUS_HWERROR;
--			dd->ipath_flags &= ~IPATH_INITTED;
--		} else {
-+		}
-+		if (!hwerrs) {
- 			static u32 freeze_cnt;
+ 	if (__srp_post_send(target, iu, len)) {
+-		printk(KERN_ERR PFX "Send failed\n");
++		shost_printk(KERN_ERR, target->scsi_host, PFX "Send failed\n");
+ 		goto err_unmap;
+ 	}
  
- 			freeze_cnt++;
-@@ -485,7 +532,7 @@ static void ipath_pe_handle_hwerrors(struct ipath_devdata *dd, char *msg,
+@@ -1090,6 +1107,7 @@ static void srp_cm_rej_handler(struct ib_cm_id *cm_id,
+ 			       struct ib_cm_event *event,
+ 			       struct srp_target_port *target)
+ {
++	struct Scsi_Host *shost = target->scsi_host;
+ 	struct ib_class_port_info *cpi;
+ 	int opcode;
  
- 	if (hwerrs & INFINIPATH_HWE_SERDESPLLFAILED) {
- 		/*
--		 * If it occurs, it is left masked since the eternal
-+		 * If it occurs, it is left masked since the external
- 		 * interface is unused
- 		 */
- 		dd->ipath_hwerrmask &= ~INFINIPATH_HWE_SERDESPLLFAILED;
-@@ -563,6 +610,14 @@ static int ipath_pe_boardname(struct ipath_devdata *dd, char *name,
- 			dd->ipath_f_put_tid = ipath_pe_put_tid_2;
- 	}
+@@ -1115,19 +1133,22 @@ static void srp_cm_rej_handler(struct ib_cm_id *cm_id,
+ 			memcpy(target->path.dgid.raw,
+ 			       event->param.rej_rcvd.ari, 16);
  
-+
-+	/*
-+	 * set here, not in ipath_init_*_funcs because we have to do
-+	 * it after we can read chip registers.
-+	 */
-+	dd->ipath_ureg_align =
-+		ipath_read_kreg32(dd, dd->ipath_kregs->kr_pagealign);
-+
- 	return ret;
- }
+-			printk(KERN_DEBUG PFX "Topspin/Cisco redirect to target port GID %016llx%016llx\n",
+-			       (unsigned long long) be64_to_cpu(target->path.dgid.global.subnet_prefix),
+-			       (unsigned long long) be64_to_cpu(target->path.dgid.global.interface_id));
++			shost_printk(KERN_DEBUG, shost,
++				     PFX "Topspin/Cisco redirect to target port GID %016llx%016llx\n",
++				     (unsigned long long) be64_to_cpu(target->path.dgid.global.subnet_prefix),
++				     (unsigned long long) be64_to_cpu(target->path.dgid.global.interface_id));
  
-@@ -667,17 +722,8 @@ static int ipath_pe_bringup_serdes(struct ipath_devdata *dd)
+ 			target->status = SRP_PORT_REDIRECT;
+ 		} else {
+-			printk(KERN_WARNING "  REJ reason: IB_CM_REJ_PORT_REDIRECT\n");
++			shost_printk(KERN_WARNING, shost,
++				     "  REJ reason: IB_CM_REJ_PORT_REDIRECT\n");
+ 			target->status = -ECONNRESET;
+ 		}
+ 		break;
  
- 	val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_xgxsconfig);
- 	prev_val = val;
--	if (((val >> INFINIPATH_XGXS_MDIOADDR_SHIFT) &
--	     INFINIPATH_XGXS_MDIOADDR_MASK) != 3) {
--		val &=
--			~(INFINIPATH_XGXS_MDIOADDR_MASK <<
--			  INFINIPATH_XGXS_MDIOADDR_SHIFT);
--		/* MDIO address 3 */
--		val |= 3ULL << INFINIPATH_XGXS_MDIOADDR_SHIFT;
--	}
--	if (val & INFINIPATH_XGXS_RESET) {
-+	if (val & INFINIPATH_XGXS_RESET)
- 		val &= ~INFINIPATH_XGXS_RESET;
--	}
- 	if (((val >> INFINIPATH_XGXS_RX_POL_SHIFT) &
- 	     INFINIPATH_XGXS_RX_POL_MASK) != dd->ipath_rx_pol_inv ) {
- 		/* need to compensate for Tx inversion in partner */
-@@ -707,21 +753,6 @@ static int ipath_pe_bringup_serdes(struct ipath_devdata *dd)
- 		   (unsigned long long)
- 		   ipath_read_kreg64(dd, dd->ipath_kregs->kr_xgxsconfig));
+ 	case IB_CM_REJ_DUPLICATE_LOCAL_COMM_ID:
+-		printk(KERN_WARNING "  REJ reason: IB_CM_REJ_DUPLICATE_LOCAL_COMM_ID\n");
++		shost_printk(KERN_WARNING, shost,
++			    "  REJ reason: IB_CM_REJ_DUPLICATE_LOCAL_COMM_ID\n");
+ 		target->status = -ECONNRESET;
+ 		break;
  
--	if (!ipath_waitfor_mdio_cmdready(dd)) {
--		ipath_write_kreg(
--			dd, dd->ipath_kregs->kr_mdio,
--			ipath_mdio_req(IPATH_MDIO_CMD_READ, 31,
--				       IPATH_MDIO_CTRL_XGXS_REG_8, 0));
--		if (ipath_waitfor_complete(dd, dd->ipath_kregs->kr_mdio,
--					   IPATH_MDIO_DATAVALID, &val))
--			ipath_dbg("Never got MDIO data for XGXS "
--				  "status read\n");
--		else
--			ipath_cdbg(VERBOSE, "MDIO Read reg8, "
--				   "'bank' 31 %x\n", (u32) val);
--	} else
--		ipath_dbg("Never got MDIO cmdready for XGXS status read\n");
--
- 	return ret;
+@@ -1138,20 +1159,21 @@ static void srp_cm_rej_handler(struct ib_cm_id *cm_id,
+ 			u32 reason = be32_to_cpu(rej->reason);
+ 
+ 			if (reason == SRP_LOGIN_REJ_REQ_IT_IU_LENGTH_TOO_LARGE)
+-				printk(KERN_WARNING PFX
+-				       "SRP_LOGIN_REJ: requested max_it_iu_len too large\n");
++				shost_printk(KERN_WARNING, shost,
++					     PFX "SRP_LOGIN_REJ: requested max_it_iu_len too large\n");
+ 			else
+-				printk(KERN_WARNING PFX
+-				       "SRP LOGIN REJECTED, reason 0x%08x\n", reason);
++				shost_printk(KERN_WARNING, shost,
++					    PFX "SRP LOGIN REJECTED, reason 0x%08x\n", reason);
+ 		} else
+-			printk(KERN_WARNING "  REJ reason: IB_CM_REJ_CONSUMER_DEFINED,"
+-			       " opcode 0x%02x\n", opcode);
++			shost_printk(KERN_WARNING, shost,
++				     "  REJ reason: IB_CM_REJ_CONSUMER_DEFINED,"
++				     " opcode 0x%02x\n", opcode);
+ 		target->status = -ECONNRESET;
+ 		break;
+ 
+ 	default:
+-		printk(KERN_WARNING "  REJ reason 0x%x\n",
+-		       event->param.rej_rcvd.reason);
++		shost_printk(KERN_WARNING, shost, "  REJ reason 0x%x\n",
++			     event->param.rej_rcvd.reason);
+ 		target->status = -ECONNRESET;
+ 	}
  }
+@@ -1166,7 +1188,8 @@ static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event)
  
-@@ -902,12 +933,27 @@ static int ipath_setup_pe_config(struct ipath_devdata *dd,
- 	else
- 		ipath_dev_err(dd, "Can't find PCI Express "
- 			      "capability!\n");
+ 	switch (event->event) {
+ 	case IB_CM_REQ_ERROR:
+-		printk(KERN_DEBUG PFX "Sending CM REQ failed\n");
++		shost_printk(KERN_DEBUG, target->scsi_host,
++			     PFX "Sending CM REQ failed\n");
+ 		comp = 1;
+ 		target->status = -ECONNRESET;
+ 		break;
+@@ -1184,7 +1207,8 @@ static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event)
+ 			target->scsi_host->can_queue = min(target->req_lim,
+ 							   target->scsi_host->can_queue);
+ 		} else {
+-			printk(KERN_WARNING PFX "Unhandled RSP opcode %#x\n", opcode);
++			shost_printk(KERN_WARNING, target->scsi_host,
++				    PFX "Unhandled RSP opcode %#x\n", opcode);
+ 			target->status = -ECONNRESET;
+ 			break;
+ 		}
+@@ -1230,20 +1254,23 @@ static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event)
+ 		break;
+ 
+ 	case IB_CM_REJ_RECEIVED:
+-		printk(KERN_DEBUG PFX "REJ received\n");
++		shost_printk(KERN_DEBUG, target->scsi_host, PFX "REJ received\n");
+ 		comp = 1;
+ 
+ 		srp_cm_rej_handler(cm_id, event, target);
+ 		break;
+ 
+ 	case IB_CM_DREQ_RECEIVED:
+-		printk(KERN_WARNING PFX "DREQ received - connection closed\n");
++		shost_printk(KERN_WARNING, target->scsi_host,
++			     PFX "DREQ received - connection closed\n");
+ 		if (ib_send_cm_drep(cm_id, NULL, 0))
+-			printk(KERN_ERR PFX "Sending CM DREP failed\n");
++			shost_printk(KERN_ERR, target->scsi_host,
++				     PFX "Sending CM DREP failed\n");
+ 		break;
+ 
+ 	case IB_CM_TIMEWAIT_EXIT:
+-		printk(KERN_ERR PFX "connection closed\n");
++		shost_printk(KERN_ERR, target->scsi_host,
++			     PFX "connection closed\n");
+ 
+ 		comp = 1;
+ 		target->status = 0;
+@@ -1255,7 +1282,8 @@ static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event)
+ 		break;
+ 
+ 	default:
+-		printk(KERN_WARNING PFX "Unhandled CM event %d\n", event->event);
++		shost_printk(KERN_WARNING, target->scsi_host,
++			     PFX "Unhandled CM event %d\n", event->event);
+ 		break;
+ 	}
+ 
+@@ -1283,7 +1311,7 @@ static int srp_send_tsk_mgmt(struct srp_target_port *target,
+ 
+ 	init_completion(&req->done);
+ 
+-	iu = __srp_get_tx_iu(target);
++	iu = __srp_get_tx_iu(target, SRP_REQ_TASK_MGMT);
+ 	if (!iu)
+ 		goto out;
+ 
+@@ -1332,7 +1360,7 @@ static int srp_abort(struct scsi_cmnd *scmnd)
+ 	struct srp_request *req;
+ 	int ret = SUCCESS;
+ 
+-	printk(KERN_ERR "SRP abort called\n");
++	shost_printk(KERN_ERR, target->scsi_host, "SRP abort called\n");
+ 
+ 	if (target->qp_in_error)
+ 		return FAILED;
+@@ -1362,7 +1390,7 @@ static int srp_reset_device(struct scsi_cmnd *scmnd)
+ 	struct srp_target_port *target = host_to_target(scmnd->device->host);
+ 	struct srp_request *req, *tmp;
+ 
+-	printk(KERN_ERR "SRP reset_device called\n");
++	shost_printk(KERN_ERR, target->scsi_host, "SRP reset_device called\n");
+ 
+ 	if (target->qp_in_error)
+ 		return FAILED;
+@@ -1389,7 +1417,7 @@ static int srp_reset_host(struct scsi_cmnd *scmnd)
+ 	struct srp_target_port *target = host_to_target(scmnd->device->host);
+ 	int ret = FAILED;
+ 
+-	printk(KERN_ERR PFX "SRP reset_host called\n");
++	shost_printk(KERN_ERR, target->scsi_host, PFX "SRP reset_host called\n");
+ 
+ 	if (!srp_reconnect_target(target))
+ 		ret = SUCCESS;
+@@ -1543,6 +1571,7 @@ static struct scsi_host_template srp_template = {
+ 	.this_id			= -1,
+ 	.cmd_per_lun			= SRP_SQ_SIZE,
+ 	.use_clustering			= ENABLE_CLUSTERING,
++	.use_sg_chaining		= ENABLE_SG_CHAINING,
+ 	.shost_attrs			= srp_host_attrs
+ };
+ 
+@@ -1814,8 +1843,9 @@ static ssize_t srp_create_target(struct class_device *class_dev,
+ 
+ 	ib_get_cached_gid(host->dev->dev, host->port, 0, &target->path.sgid);
+ 
+-	printk(KERN_DEBUG PFX "new target: id_ext %016llx ioc_guid %016llx pkey %04x "
+-	       "service_id %016llx dgid %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
++	shost_printk(KERN_DEBUG, target->scsi_host, PFX
++		     "new target: id_ext %016llx ioc_guid %016llx pkey %04x "
++		     "service_id %016llx dgid %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
+ 	       (unsigned long long) be64_to_cpu(target->id_ext),
+ 	       (unsigned long long) be64_to_cpu(target->ioc_guid),
+ 	       be16_to_cpu(target->path.pkey),
+@@ -1842,7 +1872,8 @@ static ssize_t srp_create_target(struct class_device *class_dev,
+ 	target->qp_in_error = 0;
+ 	ret = srp_connect_target(target);
+ 	if (ret) {
+-		printk(KERN_ERR PFX "Connection failed\n");
++		shost_printk(KERN_ERR, target->scsi_host,
++			     PFX "Connection failed\n");
+ 		goto err_cm_id;
+ 	}
+ 
+diff --git a/drivers/infiniband/ulp/srp/ib_srp.h b/drivers/infiniband/ulp/srp/ib_srp.h
+index e3573e7..4a3c1f3 100644
+--- a/drivers/infiniband/ulp/srp/ib_srp.h
++++ b/drivers/infiniband/ulp/srp/ib_srp.h
+@@ -79,6 +79,11 @@ enum srp_target_state {
+ 	SRP_TARGET_REMOVED
+ };
+ 
++enum srp_request_type {
++	SRP_REQ_NORMAL,
++	SRP_REQ_TASK_MGMT,
++};
 +
-+	dd->ipath_link_width_supported = IB_WIDTH_1X | IB_WIDTH_4X;
-+	dd->ipath_link_speed_supported = IPATH_IB_SDR;
-+	dd->ipath_link_width_enabled = IB_WIDTH_4X;
-+	dd->ipath_link_speed_enabled = dd->ipath_link_speed_supported;
-+	/* these can't change for this chip, so set once */
-+	dd->ipath_link_width_active = dd->ipath_link_width_enabled;
-+	dd->ipath_link_speed_active = dd->ipath_link_speed_enabled;
- 	return 0;
+ struct srp_device {
+ 	struct list_head	dev_list;
+ 	struct ib_device       *dev;
+diff --git a/drivers/input/touchscreen/corgi_ts.c b/drivers/input/touchscreen/corgi_ts.c
+index b1b2e07..99d92f5 100644
+--- a/drivers/input/touchscreen/corgi_ts.c
++++ b/drivers/input/touchscreen/corgi_ts.c
+@@ -74,10 +74,10 @@ extern unsigned int get_clk_frequency_khz(int info);
+ 
+ static unsigned long calc_waittime(struct corgi_ts *corgi_ts)
+ {
+-	unsigned long hsync_len = corgi_ts->machinfo->get_hsync_len();
++	unsigned long hsync_invperiod = corgi_ts->machinfo->get_hsync_invperiod();
+ 
+-	if (hsync_len)
+-		return get_clk_frequency_khz(0)*1000/hsync_len;
++	if (hsync_invperiod)
++		return get_clk_frequency_khz(0)*1000/hsync_invperiod;
+ 	else
+ 		return 0;
  }
+@@ -114,7 +114,7 @@ static int sync_receive_data_send_cmd(struct corgi_ts *corgi_ts, int doRecive, i
+ 			if (timer2-timer1 > wait_time) {
+ 				/* too slow - timeout, try again */
+ 				corgi_ts->machinfo->wait_hsync();
+-				/* get OSCR */
++				/* get CCNT */
+ 				CCNT(timer1);
+ 				/* Wait after HSync */
+ 				CCNT(timer2);
+diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c
+index f449dae..23ae66c 100644
+--- a/drivers/isdn/capi/capi.c
++++ b/drivers/isdn/capi/capi.c
+@@ -1544,11 +1544,11 @@ static int __init capi_init(void)
+ 		return PTR_ERR(capi_class);
+ 	}
  
- static void ipath_init_pe_variables(struct ipath_devdata *dd)
+-	class_device_create(capi_class, NULL, MKDEV(capi_major, 0), NULL, "capi");
++	device_create(capi_class, NULL, MKDEV(capi_major, 0), "capi");
+ 
+ #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
+ 	if (capinc_tty_init() < 0) {
+-		class_device_destroy(capi_class, MKDEV(capi_major, 0));
++		device_destroy(capi_class, MKDEV(capi_major, 0));
+ 		class_destroy(capi_class);
+ 		unregister_chrdev(capi_major, "capi20");
+ 		return -ENOMEM;
+@@ -1576,7 +1576,7 @@ static void __exit capi_exit(void)
  {
- 	/*
-+	 * setup the register offsets, since they are different for each
-+	 * chip
-+	 */
-+	dd->ipath_kregs = &ipath_pe_kregs;
-+	dd->ipath_cregs = &ipath_pe_cregs;
-+
-+	/*
- 	 * bits for selecting i2c direction and values,
- 	 * used for I2C serial flash
- 	 */
-@@ -916,6 +962,43 @@ static void ipath_init_pe_variables(struct ipath_devdata *dd)
- 	dd->ipath_gpio_sda = IPATH_GPIO_SDA;
- 	dd->ipath_gpio_scl = IPATH_GPIO_SCL;
+ 	proc_exit();
  
-+	/*
-+	 * Fill in data for field-values that change in newer chips.
-+	 * We dynamically specify only the mask for LINKTRAININGSTATE
-+	 * and only the shift for LINKSTATE, as they are the only ones
-+	 * that change.  Also precalculate the 3 link states of interest
-+	 * and the combined mask.
-+	 */
-+	dd->ibcs_ls_shift = IBA6120_IBCS_LINKSTATE_SHIFT;
-+	dd->ibcs_lts_mask = IBA6120_IBCS_LINKTRAININGSTATE_MASK;
-+	dd->ibcs_mask = (INFINIPATH_IBCS_LINKSTATE_MASK <<
-+		dd->ibcs_ls_shift) | dd->ibcs_lts_mask;
-+	dd->ib_init = (INFINIPATH_IBCS_LT_STATE_LINKUP <<
-+		INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT) |
-+		(INFINIPATH_IBCS_L_STATE_INIT << dd->ibcs_ls_shift);
-+	dd->ib_arm = (INFINIPATH_IBCS_LT_STATE_LINKUP <<
-+		INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT) |
-+		(INFINIPATH_IBCS_L_STATE_ARM << dd->ibcs_ls_shift);
-+	dd->ib_active = (INFINIPATH_IBCS_LT_STATE_LINKUP <<
-+		INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT) |
-+		(INFINIPATH_IBCS_L_STATE_ACTIVE << dd->ibcs_ls_shift);
-+
-+	/*
-+	 * Fill in data for ibcc field-values that change in newer chips.
-+	 * We dynamically specify only the mask for LINKINITCMD
-+	 * and only the shift for LINKCMD and MAXPKTLEN, as they are
-+	 * the only ones that change.
-+	 */
-+	dd->ibcc_lic_mask = INFINIPATH_IBCC_LINKINITCMD_MASK;
-+	dd->ibcc_lc_shift = INFINIPATH_IBCC_LINKCMD_SHIFT;
-+	dd->ibcc_mpl_shift = INFINIPATH_IBCC_MAXPKTLEN_SHIFT;
-+
-+	/* Fill in shifts for RcvCtrl. */
-+	dd->ipath_r_portenable_shift = INFINIPATH_R_PORTENABLE_SHIFT;
-+	dd->ipath_r_intravail_shift = INFINIPATH_R_INTRAVAIL_SHIFT;
-+	dd->ipath_r_tailupd_shift = INFINIPATH_R_TAILUPD_SHIFT;
-+	dd->ipath_r_portcfg_shift = 0; /* Not on IBA6120 */
-+
- 	/* variables for sanity checking interrupt and errors */
- 	dd->ipath_hwe_bitsextant =
- 		(INFINIPATH_HWE_RXEMEMPARITYERR_MASK <<
-@@ -963,6 +1046,8 @@ static void ipath_init_pe_variables(struct ipath_devdata *dd)
+-	class_device_destroy(capi_class, MKDEV(capi_major, 0));
++	device_destroy(capi_class, MKDEV(capi_major, 0));
+ 	class_destroy(capi_class);
+ 	unregister_chrdev(capi_major, "capi20");
  
- 	dd->ipath_i_rcvavail_mask = INFINIPATH_I_RCVAVAIL_MASK;
- 	dd->ipath_i_rcvurg_mask = INFINIPATH_I_RCVURG_MASK;
-+	dd->ipath_i_rcvavail_shift = INFINIPATH_I_RCVAVAIL_SHIFT;
-+	dd->ipath_i_rcvurg_shift = INFINIPATH_I_RCVURG_SHIFT;
+diff --git a/drivers/isdn/capi/capidrv.c b/drivers/isdn/capi/capidrv.c
+index 48c1775..cb42b69 100644
+--- a/drivers/isdn/capi/capidrv.c
++++ b/drivers/isdn/capi/capidrv.c
+@@ -2332,13 +2332,14 @@ static int __init capidrv_init(void)
  
- 	/*
- 	 * EEPROM error log 0 is TXE Parity errors. 1 is RXE Parity.
-@@ -984,6 +1069,7 @@ static void ipath_init_pe_variables(struct ipath_devdata *dd)
- 		INFINIPATH_E_INVALIDADDR | INFINIPATH_E_RESET;
+ static void __exit capidrv_exit(void)
+ {
+-	char rev[10];
++	char rev[32];
+ 	char *p;
  
+ 	if ((p = strchr(revision, ':')) != 0) {
+-		strcpy(rev, p + 1);
+-		p = strchr(rev, '$');
+-		*p = 0;
++		strncpy(rev, p + 1, sizeof(rev));
++		rev[sizeof(rev)-1] = 0;
++		if ((p = strchr(rev, '$')) != 0)
++			*p = 0;
+ 	} else {
+ 		strcpy(rev, " ??? ");
+ 	}
+diff --git a/drivers/isdn/gigaset/gigaset.h b/drivers/isdn/gigaset/gigaset.h
+index a0317ab..02bdaf2 100644
+--- a/drivers/isdn/gigaset/gigaset.h
++++ b/drivers/isdn/gigaset/gigaset.h
+@@ -106,12 +106,6 @@ enum debuglevel {
+ 					 activated */
+ };
  
-+	dd->delay_mult = 2; /* SDR, 4X, can't change */
+-/* missing from linux/device.h ... */
+-#ifndef dev_notice
+-#define dev_notice(dev, format, arg...)		\
+-	dev_printk(KERN_NOTICE , dev , format , ## arg)
+-#endif
+-
+ /* Kernel message macros for situations where dev_printk and friends cannot be
+  * used for lack of reliable access to a device structure.
+  * linux/usb.h already contains these but in an obsolete form which clutters
+diff --git a/drivers/kvm/kvm_main.c b/drivers/kvm/kvm_main.c
+index 47c10b8..c0f372f 100644
+--- a/drivers/kvm/kvm_main.c
++++ b/drivers/kvm/kvm_main.c
+@@ -3451,7 +3451,7 @@ static int kvm_resume(struct sys_device *dev)
  }
  
- /* setup the MSI stuff again after a reset.  I'd like to just call
-@@ -1289,6 +1375,9 @@ static int ipath_pe_early_init(struct ipath_devdata *dd)
- 	 */
- 	dd->ipath_rcvhdrentsize = 24;
- 	dd->ipath_rcvhdrsize = IPATH_DFLT_RCVHDRSIZE;
-+	dd->ipath_rhf_offset = 0;
-+	dd->ipath_egrtidbase = (u64 __iomem *)
-+		((char __iomem *) dd->ipath_kregbase + dd->ipath_rcvegrbase);
+ static struct sysdev_class kvm_sysdev_class = {
+-	set_kset_name("kvm"),
++	.name = "kvm",
+ 	.suspend = kvm_suspend,
+ 	.resume = kvm_resume,
+ };
+diff --git a/drivers/lguest/x86/core.c b/drivers/lguest/x86/core.c
+index 482aec2..96d0fd0 100644
+--- a/drivers/lguest/x86/core.c
++++ b/drivers/lguest/x86/core.c
+@@ -459,7 +459,7 @@ void __init lguest_arch_host_init(void)
  
- 	/*
- 	 * To truly support a 4KB MTU (for usermode), we need to
-@@ -1359,34 +1448,204 @@ static void ipath_pe_free_irq(struct ipath_devdata *dd)
- 	dd->ipath_irq = 0;
- }
+ 	/* We don't need the complexity of CPUs coming and going while we're
+ 	 * doing this. */
+-	lock_cpu_hotplug();
++	get_online_cpus();
+ 	if (cpu_has_pge) { /* We have a broader idea of "global". */
+ 		/* Remember that this was originally set (for cleanup). */
+ 		cpu_had_pge = 1;
+@@ -469,20 +469,20 @@ void __init lguest_arch_host_init(void)
+ 		/* Turn off the feature in the global feature set. */
+ 		clear_bit(X86_FEATURE_PGE, boot_cpu_data.x86_capability);
+ 	}
+-	unlock_cpu_hotplug();
++	put_online_cpus();
+ };
+ /*:*/
  
-+
-+static struct ipath_message_header *
-+ipath_pe_get_msgheader(struct ipath_devdata *dd, __le32 *rhf_addr)
-+{
-+	return (struct ipath_message_header *)
-+		&rhf_addr[sizeof(u64) / sizeof(u32)];
-+}
-+
-+static void ipath_pe_config_ports(struct ipath_devdata *dd, ushort cfgports)
-+{
-+	dd->ipath_portcnt =
-+		ipath_read_kreg32(dd, dd->ipath_kregs->kr_portcnt);
-+	dd->ipath_p0_rcvegrcnt =
-+		ipath_read_kreg32(dd, dd->ipath_kregs->kr_rcvegrcnt);
-+}
-+
-+static void ipath_pe_read_counters(struct ipath_devdata *dd,
-+				   struct infinipath_counters *cntrs)
-+{
-+	cntrs->LBIntCnt =
-+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(LBIntCnt));
-+	cntrs->LBFlowStallCnt =
-+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(LBFlowStallCnt));
-+	cntrs->TxSDmaDescCnt = 0;
-+	cntrs->TxUnsupVLErrCnt =
-+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxUnsupVLErrCnt));
-+	cntrs->TxDataPktCnt =
-+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxDataPktCnt));
-+	cntrs->TxFlowPktCnt =
-+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxFlowPktCnt));
-+	cntrs->TxDwordCnt =
-+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxDwordCnt));
-+	cntrs->TxLenErrCnt =
-+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxLenErrCnt));
-+	cntrs->TxMaxMinLenErrCnt =
-+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxMaxMinLenErrCnt));
-+	cntrs->TxUnderrunCnt =
-+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxUnderrunCnt));
-+	cntrs->TxFlowStallCnt =
-+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxFlowStallCnt));
-+	cntrs->TxDroppedPktCnt =
-+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxDroppedPktCnt));
-+	cntrs->RxDroppedPktCnt =
-+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxDroppedPktCnt));
-+	cntrs->RxDataPktCnt =
-+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxDataPktCnt));
-+	cntrs->RxFlowPktCnt =
-+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxFlowPktCnt));
-+	cntrs->RxDwordCnt =
-+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxDwordCnt));
-+	cntrs->RxLenErrCnt =
-+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxLenErrCnt));
-+	cntrs->RxMaxMinLenErrCnt =
-+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxMaxMinLenErrCnt));
-+	cntrs->RxICRCErrCnt =
-+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxICRCErrCnt));
-+	cntrs->RxVCRCErrCnt =
-+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxVCRCErrCnt));
-+	cntrs->RxFlowCtrlErrCnt =
-+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxFlowCtrlErrCnt));
-+	cntrs->RxBadFormatCnt =
-+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxBadFormatCnt));
-+	cntrs->RxLinkProblemCnt =
-+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxLinkProblemCnt));
-+	cntrs->RxEBPCnt =
-+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxEBPCnt));
-+	cntrs->RxLPCRCErrCnt =
-+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxLPCRCErrCnt));
-+	cntrs->RxBufOvflCnt =
-+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxBufOvflCnt));
-+	cntrs->RxTIDFullErrCnt =
-+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxTIDFullErrCnt));
-+	cntrs->RxTIDValidErrCnt =
-+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxTIDValidErrCnt));
-+	cntrs->RxPKeyMismatchCnt =
-+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxPKeyMismatchCnt));
-+	cntrs->RxP0HdrEgrOvflCnt =
-+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP0HdrEgrOvflCnt));
-+	cntrs->RxP1HdrEgrOvflCnt =
-+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP1HdrEgrOvflCnt));
-+	cntrs->RxP2HdrEgrOvflCnt =
-+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP2HdrEgrOvflCnt));
-+	cntrs->RxP3HdrEgrOvflCnt =
-+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP3HdrEgrOvflCnt));
-+	cntrs->RxP4HdrEgrOvflCnt =
-+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP4HdrEgrOvflCnt));
-+	cntrs->RxP5HdrEgrOvflCnt = 0;
-+	cntrs->RxP6HdrEgrOvflCnt = 0;
-+	cntrs->RxP7HdrEgrOvflCnt = 0;
-+	cntrs->RxP8HdrEgrOvflCnt = 0;
-+	cntrs->RxP9HdrEgrOvflCnt = 0;
-+	cntrs->RxP10HdrEgrOvflCnt = 0;
-+	cntrs->RxP11HdrEgrOvflCnt = 0;
-+	cntrs->RxP12HdrEgrOvflCnt = 0;
-+	cntrs->RxP13HdrEgrOvflCnt = 0;
-+	cntrs->RxP14HdrEgrOvflCnt = 0;
-+	cntrs->RxP15HdrEgrOvflCnt = 0;
-+	cntrs->RxP16HdrEgrOvflCnt = 0;
-+	cntrs->IBStatusChangeCnt =
-+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(IBStatusChangeCnt));
-+	cntrs->IBLinkErrRecoveryCnt =
-+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(IBLinkErrRecoveryCnt));
-+	cntrs->IBLinkDownedCnt =
-+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(IBLinkDownedCnt));
-+	cntrs->IBSymbolErrCnt =
-+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(IBSymbolErrCnt));
-+	cntrs->RxVL15DroppedPktCnt = 0;
-+	cntrs->RxOtherLocalPhyErrCnt = 0;
-+	cntrs->PcieRetryBufDiagQwordCnt = 0;
-+	cntrs->ExcessBufferOvflCnt = dd->ipath_overrun_thresh_errs;
-+	cntrs->LocalLinkIntegrityErrCnt = dd->ipath_lli_errs;
-+	cntrs->RxVlErrCnt = 0;
-+	cntrs->RxDlidFltrCnt = 0;
-+}
-+
-+
-+/* no interrupt fallback for these chips */
-+static int ipath_pe_nointr_fallback(struct ipath_devdata *dd)
-+{
-+	return 0;
-+}
-+
-+
- /*
-- * On platforms using this chip, and not having ordered WC stores, we
-- * can get TXE parity errors due to speculative reads to the PIO buffers,
-- * and this, due to a chip bug can result in (many) false parity error
-- * reports.  So it's a debug print on those, and an info print on systems
-- * where the speculative reads don't occur.
-- * Because we can get lots of false errors, we have no upper limit
-- * on recovery attempts on those platforms.
-+ * reset the XGXS (between serdes and IBC).  Slightly less intrusive
-+ * than resetting the IBC or external link state, and useful in some
-+ * cases to cause some retraining.  To do this right, we reset IBC
-+ * as well.
-  */
--static int ipath_pe_txe_recover(struct ipath_devdata *dd)
-+static void ipath_pe_xgxs_reset(struct ipath_devdata *dd)
+ void __exit lguest_arch_host_fini(void)
  {
--	if (ipath_unordered_wc())
--		ipath_dbg("Recovering from TXE PIO parity error\n");
--	else {
--		int cnt = ++ipath_stats.sps_txeparity;
--		if (cnt >= IPATH_MAX_PARITY_ATTEMPTS)  {
--			if (cnt == IPATH_MAX_PARITY_ATTEMPTS)
--				ipath_dev_err(dd,
--					"Too many attempts to recover from "
--					"TXE parity, giving up\n");
--			return 0;
--		}
--		dev_info(&dd->pcidev->dev,
--			"Recovering from TXE PIO parity error\n");
-+	u64 val, prev_val;
-+
-+	prev_val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_xgxsconfig);
-+	val = prev_val | INFINIPATH_XGXS_RESET;
-+	prev_val &= ~INFINIPATH_XGXS_RESET; /* be sure */
-+	ipath_write_kreg(dd, dd->ipath_kregs->kr_control,
-+			 dd->ipath_control & ~INFINIPATH_C_LINKENABLE);
-+	ipath_write_kreg(dd, dd->ipath_kregs->kr_xgxsconfig, val);
-+	ipath_read_kreg32(dd, dd->ipath_kregs->kr_scratch);
-+	ipath_write_kreg(dd, dd->ipath_kregs->kr_xgxsconfig, prev_val);
-+	ipath_write_kreg(dd, dd->ipath_kregs->kr_control,
-+			 dd->ipath_control);
-+}
-+
-+
-+static int ipath_pe_get_ib_cfg(struct ipath_devdata *dd, int which)
-+{
-+	int ret;
-+
-+	switch (which) {
-+	case IPATH_IB_CFG_LWID:
-+		ret = dd->ipath_link_width_active;
-+		break;
-+	case IPATH_IB_CFG_SPD:
-+		ret = dd->ipath_link_speed_active;
-+		break;
-+	case IPATH_IB_CFG_LWID_ENB:
-+		ret = dd->ipath_link_width_enabled;
-+		break;
-+	case IPATH_IB_CFG_SPD_ENB:
-+		ret = dd->ipath_link_speed_enabled;
-+		break;
-+	default:
-+		ret =  -ENOTSUPP;
-+		break;
+ 	/* If we had PGE before we started, turn it back on now. */
+-	lock_cpu_hotplug();
++	get_online_cpus();
+ 	if (cpu_had_pge) {
+ 		set_bit(X86_FEATURE_PGE, boot_cpu_data.x86_capability);
+ 		/* adjust_pge's argument "1" means set PGE. */
+ 		on_each_cpu(adjust_pge, (void *)1, 0, 1);
  	}
--	return 1;
-+	return ret;
-+}
-+
-+
-+/* we assume range checking is already done, if needed */
-+static int ipath_pe_set_ib_cfg(struct ipath_devdata *dd, int which, u32 val)
-+{
-+	int ret = 0;
-+
-+	if (which == IPATH_IB_CFG_LWID_ENB)
-+		dd->ipath_link_width_enabled = val;
-+	else if (which == IPATH_IB_CFG_SPD_ENB)
-+		dd->ipath_link_speed_enabled = val;
-+	else
-+		ret = -ENOTSUPP;
-+	return ret;
+-	unlock_cpu_hotplug();
++	put_online_cpus();
  }
  
-+static void ipath_pe_config_jint(struct ipath_devdata *dd, u16 a, u16 b)
-+{
-+}
-+
-+
-+static int ipath_pe_ib_updown(struct ipath_devdata *dd, int ibup, u64 ibcs)
-+{
-+	ipath_setup_pe_setextled(dd, ipath_ib_linkstate(dd, ibcs),
-+		ipath_ib_linktrstate(dd, ibcs));
-+	return 0;
-+}
-+
-+
- /**
-  * ipath_init_iba6120_funcs - set up the chip-specific function pointers
-  * @dd: the infinipath device
-@@ -1407,7 +1666,7 @@ void ipath_init_iba6120_funcs(struct ipath_devdata *dd)
- 	dd->ipath_f_bringup_serdes = ipath_pe_bringup_serdes;
- 	dd->ipath_f_clear_tids = ipath_pe_clear_tids;
- 	/*
--	 * this may get changed after we read the chip revision,
-+	 * _f_put_tid may get changed after we read the chip revision,
- 	 * but we start with the safe version for all revs
- 	 */
- 	dd->ipath_f_put_tid = ipath_pe_put_tid;
-@@ -1415,17 +1674,19 @@ void ipath_init_iba6120_funcs(struct ipath_devdata *dd)
- 	dd->ipath_f_setextled = ipath_setup_pe_setextled;
- 	dd->ipath_f_get_base_info = ipath_pe_get_base_info;
- 	dd->ipath_f_free_irq = ipath_pe_free_irq;
+ 
+diff --git a/drivers/macintosh/adb.c b/drivers/macintosh/adb.c
+index 5c742a5..b7adde4 100644
+--- a/drivers/macintosh/adb.c
++++ b/drivers/macintosh/adb.c
+@@ -875,5 +875,5 @@ adbdev_init(void)
+ 	adb_dev_class = class_create(THIS_MODULE, "adb");
+ 	if (IS_ERR(adb_dev_class))
+ 		return;
+-	class_device_create(adb_dev_class, NULL, MKDEV(ADB_MAJOR, 0), NULL, "adb");
++	device_create(adb_dev_class, NULL, MKDEV(ADB_MAJOR, 0), "adb");
+ }
+diff --git a/drivers/macintosh/mediabay.c b/drivers/macintosh/mediabay.c
+index 48d647a..eaba4a9 100644
+--- a/drivers/macintosh/mediabay.c
++++ b/drivers/macintosh/mediabay.c
+@@ -563,7 +563,8 @@ static void media_bay_step(int i)
+ 				ide_init_hwif_ports(&hw, (unsigned long) bay->cd_base, (unsigned long) 0, NULL);
+ 				hw.irq = bay->cd_irq;
+ 				hw.chipset = ide_pmac;
+-				bay->cd_index = ide_register_hw(&hw, NULL, 0, NULL);
++				bay->cd_index =
++					ide_register_hw(&hw, NULL, NULL);
+ 				pmu_resume();
+ 			}
+ 			if (bay->cd_index == -1) {
+diff --git a/drivers/macintosh/therm_windtunnel.c b/drivers/macintosh/therm_windtunnel.c
+index 5452da1..b66da74 100644
+--- a/drivers/macintosh/therm_windtunnel.c
++++ b/drivers/macintosh/therm_windtunnel.c
+@@ -47,12 +47,10 @@
+ 
+ #define LOG_TEMP		0			/* continously log temperature */
+ 
+-#define I2C_DRIVERID_G4FAN	0x9001			/* fixme */
 -
--	/* initialize chip-specific variables */
- 	dd->ipath_f_tidtemplate = ipath_pe_tidtemplate;
-+	dd->ipath_f_intr_fallback = ipath_pe_nointr_fallback;
-+	dd->ipath_f_xgxs_reset = ipath_pe_xgxs_reset;
-+	dd->ipath_f_get_msgheader = ipath_pe_get_msgheader;
-+	dd->ipath_f_config_ports = ipath_pe_config_ports;
-+	dd->ipath_f_read_counters = ipath_pe_read_counters;
-+	dd->ipath_f_get_ib_cfg = ipath_pe_get_ib_cfg;
-+	dd->ipath_f_set_ib_cfg = ipath_pe_set_ib_cfg;
-+	dd->ipath_f_config_jint = ipath_pe_config_jint;
-+	dd->ipath_f_ib_updown = ipath_pe_ib_updown;
+ static int 			do_probe( struct i2c_adapter *adapter, int addr, int kind);
  
--	/*
--	 * setup the register offsets, since they are different for each
--	 * chip
--	 */
--	dd->ipath_kregs = &ipath_pe_kregs;
--	dd->ipath_cregs = &ipath_pe_cregs;
+ /* scan 0x48-0x4f (DS1775) and 0x2c-2x2f (ADM1030) */
+-static unsigned short		normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b,
++static const unsigned short	normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b,
+ 						 0x4c, 0x4d, 0x4e, 0x4f,
+ 						 0x2c, 0x2d, 0x2e, 0x2f,
+ 						 I2C_CLIENT_END };
+@@ -357,7 +355,6 @@ static struct i2c_driver g4fan_driver = {
+ 	.driver = {
+ 		.name	= "therm_windtunnel",
+ 	},
+-	.id		= I2C_DRIVERID_G4FAN,
+ 	.attach_adapter = do_attach,
+ 	.detach_client	= do_detach,
+ };
+diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c
+index 6123c70..ac420b1 100644
+--- a/drivers/macintosh/via-pmu.c
++++ b/drivers/macintosh/via-pmu.c
+@@ -2796,7 +2796,7 @@ static int pmu_sys_resume(struct sys_device *sysdev)
+ #endif /* CONFIG_PM_SLEEP && CONFIG_PPC32 */
  
-+	/* initialize chip-specific variables */
- 	ipath_init_pe_variables(dd);
+ static struct sysdev_class pmu_sysclass = {
+-	set_kset_name("pmu"),
++	.name = "pmu",
+ };
+ 
+ static struct sys_device device_pmu = {
+diff --git a/drivers/md/dm.c b/drivers/md/dm.c
+index 88c0fd6..f2d24eb 100644
+--- a/drivers/md/dm.c
++++ b/drivers/md/dm.c
+@@ -1109,7 +1109,7 @@ static void event_callback(void *context)
+ 	list_splice_init(&md->uevent_list, &uevents);
+ 	spin_unlock_irqrestore(&md->uevent_lock, flags);
+ 
+-	dm_send_uevents(&uevents, &md->disk->kobj);
++	dm_send_uevents(&uevents, &md->disk->dev.kobj);
+ 
+ 	atomic_inc(&md->event_nr);
+ 	wake_up(&md->eventq);
+@@ -1530,7 +1530,7 @@ out:
+  *---------------------------------------------------------------*/
+ void dm_kobject_uevent(struct mapped_device *md)
+ {
+-	kobject_uevent(&md->disk->kobj, KOBJ_CHANGE);
++	kobject_uevent(&md->disk->dev.kobj, KOBJ_CHANGE);
+ }
+ 
+ uint32_t dm_next_uevent_seq(struct mapped_device *md)
+diff --git a/drivers/md/md.c b/drivers/md/md.c
+index cef9ebd..c28a120 100644
+--- a/drivers/md/md.c
++++ b/drivers/md/md.c
+@@ -231,7 +231,7 @@ static void mddev_put(mddev_t *mddev)
+ 		list_del(&mddev->all_mddevs);
+ 		spin_unlock(&all_mddevs_lock);
+ 		blk_cleanup_queue(mddev->queue);
+-		kobject_unregister(&mddev->kobj);
++		kobject_put(&mddev->kobj);
+ 	} else
+ 		spin_unlock(&all_mddevs_lock);
  }
+@@ -1383,22 +1383,19 @@ static int bind_rdev_to_array(mdk_rdev_t * rdev, mddev_t * mddev)
+ 			return -EBUSY;
+ 	}
+ 	bdevname(rdev->bdev,b);
+-	if (kobject_set_name(&rdev->kobj, "dev-%s", b) < 0)
+-		return -ENOMEM;
+-	while ( (s=strchr(rdev->kobj.k_name, '/')) != NULL)
++	while ( (s=strchr(b, '/')) != NULL)
+ 		*s = '!';
+-			
++
+ 	rdev->mddev = mddev;
+ 	printk(KERN_INFO "md: bind<%s>\n", b);
+ 
+-	rdev->kobj.parent = &mddev->kobj;
+-	if ((err = kobject_add(&rdev->kobj)))
++	if ((err = kobject_add(&rdev->kobj, &mddev->kobj, "dev-%s", b)))
+ 		goto fail;
+ 
+ 	if (rdev->bdev->bd_part)
+-		ko = &rdev->bdev->bd_part->kobj;
++		ko = &rdev->bdev->bd_part->dev.kobj;
+ 	else
+-		ko = &rdev->bdev->bd_disk->kobj;
++		ko = &rdev->bdev->bd_disk->dev.kobj;
+ 	if ((err = sysfs_create_link(&rdev->kobj, ko, "block"))) {
+ 		kobject_del(&rdev->kobj);
+ 		goto fail;
+@@ -2036,9 +2033,7 @@ static mdk_rdev_t *md_import_device(dev_t newdev, int super_format, int super_mi
+ 	if (err)
+ 		goto abort_free;
+ 
+-	rdev->kobj.parent = NULL;
+-	rdev->kobj.ktype = &rdev_ktype;
+-	kobject_init(&rdev->kobj);
++	kobject_init(&rdev->kobj, &rdev_ktype);
  
-diff --git a/drivers/infiniband/hw/ipath/ipath_init_chip.c b/drivers/infiniband/hw/ipath/ipath_init_chip.c
-index 9dd0bac..4471674 100644
---- a/drivers/infiniband/hw/ipath/ipath_init_chip.c
-+++ b/drivers/infiniband/hw/ipath/ipath_init_chip.c
-@@ -91,7 +91,7 @@ static int create_port0_egr(struct ipath_devdata *dd)
- 	struct ipath_skbinfo *skbinfo;
- 	int ret;
+ 	rdev->desc_nr = -1;
+ 	rdev->saved_raid_disk = -1;
+@@ -3054,6 +3049,7 @@ static struct kobject *md_probe(dev_t dev, int *part, void *data)
+ 	int partitioned = (MAJOR(dev) != MD_MAJOR);
+ 	int shift = partitioned ? MdpMinorShift : 0;
+ 	int unit = MINOR(dev) >> shift;
++	int error;
  
--	egrcnt = dd->ipath_rcvegrcnt;
-+	egrcnt = dd->ipath_p0_rcvegrcnt;
+ 	if (!mddev)
+ 		return NULL;
+@@ -3082,12 +3078,13 @@ static struct kobject *md_probe(dev_t dev, int *part, void *data)
+ 	add_disk(disk);
+ 	mddev->gendisk = disk;
+ 	mutex_unlock(&disks_mutex);
+-	mddev->kobj.parent = &disk->kobj;
+-	kobject_set_name(&mddev->kobj, "%s", "md");
+-	mddev->kobj.ktype = &md_ktype;
+-	if (kobject_register(&mddev->kobj))
++	error = kobject_init_and_add(&mddev->kobj, &md_ktype, &disk->dev.kobj,
++				     "%s", "md");
++	if (error)
+ 		printk(KERN_WARNING "md: cannot register %s/md - name in use\n",
+ 		       disk->disk_name);
++	else
++		kobject_uevent(&mddev->kobj, KOBJ_ADD);
+ 	return NULL;
+ }
  
- 	skbinfo = vmalloc(sizeof(*dd->ipath_port0_skbinfo) * egrcnt);
- 	if (skbinfo == NULL) {
-@@ -244,8 +244,7 @@ static int init_chip_first(struct ipath_devdata *dd,
- 	 * cfgports.  We do still check and report a difference, if
- 	 * not same (should be impossible).
- 	 */
--	dd->ipath_portcnt =
--		ipath_read_kreg32(dd, dd->ipath_kregs->kr_portcnt);
-+	dd->ipath_f_config_ports(dd, ipath_cfgports);
- 	if (!ipath_cfgports)
- 		dd->ipath_cfgports = dd->ipath_portcnt;
- 	else if (ipath_cfgports <= dd->ipath_portcnt) {
-@@ -272,22 +271,7 @@ static int init_chip_first(struct ipath_devdata *dd,
- 		goto done;
- 	}
+@@ -3359,7 +3356,7 @@ static int do_md_run(mddev_t * mddev)
  
--	dd->ipath_lastegrheads = kzalloc(sizeof(*dd->ipath_lastegrheads)
--					 * dd->ipath_cfgports,
--					 GFP_KERNEL);
--	dd->ipath_lastrcvhdrqtails =
--		kzalloc(sizeof(*dd->ipath_lastrcvhdrqtails)
--			* dd->ipath_cfgports, GFP_KERNEL);
--
--	if (!dd->ipath_lastegrheads || !dd->ipath_lastrcvhdrqtails) {
--		ipath_dev_err(dd, "Unable to allocate head arrays, "
--			      "failing\n");
--		ret = -ENOMEM;
--		goto done;
--	}
--
- 	pd = create_portdata0(dd);
--
- 	if (!pd) {
- 		ipath_dev_err(dd, "Unable to allocate portdata for port "
- 			      "0, failing\n");
-@@ -345,10 +329,10 @@ static int init_chip_first(struct ipath_devdata *dd,
- 		       dd->ipath_piobcnt2k, dd->ipath_pio2kbase);
+ 	mddev->changed = 1;
+ 	md_new_event(mddev);
+-	kobject_uevent(&mddev->gendisk->kobj, KOBJ_CHANGE);
++	kobject_uevent(&mddev->gendisk->dev.kobj, KOBJ_CHANGE);
+ 	return 0;
+ }
  
- 	spin_lock_init(&dd->ipath_tid_lock);
--
-+	spin_lock_init(&dd->ipath_sendctrl_lock);
- 	spin_lock_init(&dd->ipath_gpio_lock);
- 	spin_lock_init(&dd->ipath_eep_st_lock);
--	sema_init(&dd->ipath_eep_sem, 1);
-+	mutex_init(&dd->ipath_eep_lock);
+diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig
+index 1604f04..8f4a453 100644
+--- a/drivers/media/Kconfig
++++ b/drivers/media/Kconfig
+@@ -69,11 +69,13 @@ source "drivers/media/common/Kconfig"
+ config VIDEO_TUNER
+ 	tristate
+ 	depends on I2C
++	select TUNER_XC2028 if !VIDEO_TUNER_CUSTOMIZE
+ 	select TUNER_MT20XX if !VIDEO_TUNER_CUSTOMIZE
+ 	select TUNER_TDA8290 if !VIDEO_TUNER_CUSTOMIZE
+ 	select TUNER_TEA5761 if !VIDEO_TUNER_CUSTOMIZE
+ 	select TUNER_TEA5767 if !VIDEO_TUNER_CUSTOMIZE
+ 	select TUNER_SIMPLE if !VIDEO_TUNER_CUSTOMIZE
++	select TUNER_TDA9887 if !VIDEO_TUNER_CUSTOMIZE
  
- done:
- 	*pdp = pd;
-@@ -372,9 +356,9 @@ static int init_chip_reset(struct ipath_devdata *dd,
- 	*pdp = dd->ipath_pd[0];
- 	/* ensure chip does no sends or receives while we re-initialize */
- 	dd->ipath_control = dd->ipath_sendctrl = dd->ipath_rcvctrl = 0U;
--	ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl, 0);
--	ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, 0);
--	ipath_write_kreg(dd, dd->ipath_kregs->kr_control, 0);
-+	ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl, dd->ipath_rcvctrl);
-+	ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, dd->ipath_sendctrl);
-+	ipath_write_kreg(dd, dd->ipath_kregs->kr_control, dd->ipath_control);
+ menuconfig VIDEO_TUNER_CUSTOMIZE
+ 	bool "Customize analog tuner modules to build"
+@@ -89,6 +91,13 @@ menuconfig VIDEO_TUNER_CUSTOMIZE
  
- 	rtmp = ipath_read_kreg32(dd, dd->ipath_kregs->kr_portcnt);
- 	if (dd->ipath_portcnt != rtmp)
-@@ -487,6 +471,7 @@ static void enable_chip(struct ipath_devdata *dd,
- 			struct ipath_portdata *pd, int reinit)
- {
- 	u32 val;
-+	unsigned long flags;
- 	int i;
+ if VIDEO_TUNER_CUSTOMIZE
  
- 	if (!reinit)
-@@ -495,19 +480,21 @@ static void enable_chip(struct ipath_devdata *dd,
- 	ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl,
- 			 dd->ipath_rcvctrl);
++config TUNER_XC2028
++	tristate "XCeive xc2028/xc3028 tuners"
++	depends on I2C
++	default m if VIDEO_TUNER_CUSTOMIZE
++	help
++	  Say Y here to include support for the xc2028/xc3028 tuners.
++
+ config TUNER_MT20XX
+ 	tristate "Microtune 2032 / 2050 tuners"
+ 	depends on I2C
+@@ -97,8 +106,10 @@ config TUNER_MT20XX
+ 	  Say Y here to include support for the MT2032 / MT2050 tuner.
  
-+	spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags);
- 	/* Enable PIO send, and update of PIOavail regs to memory. */
- 	dd->ipath_sendctrl = INFINIPATH_S_PIOENABLE |
- 		INFINIPATH_S_PIOBUFAVAILUPD;
--	ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
--			 dd->ipath_sendctrl);
-+	ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, dd->ipath_sendctrl);
-+	ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
-+	spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags);
+ config TUNER_TDA8290
+-	tristate "TDA 8290+8275(a) tuner combo"
++	tristate "TDA 8290/8295 + 8275(a)/18271 tuner combo"
+ 	depends on I2C
++	select DVB_TDA827X
++	select DVB_TDA18271
+ 	default m if VIDEO_TUNER_CUSTOMIZE
+ 	help
+ 	  Say Y here to include support for Philips TDA8290+8275(a) tuner.
+@@ -120,10 +131,19 @@ config TUNER_TEA5767
+ config TUNER_SIMPLE
+ 	tristate "Simple tuner support"
+ 	depends on I2C
++	select TUNER_TDA9887
+ 	default m if VIDEO_TUNER_CUSTOMIZE
+ 	help
+ 	  Say Y here to include support for various simple tuners.
  
- 	/*
- 	 * enable port 0 receive, and receive interrupt.  other ports
- 	 * done as user opens and inits them.
- 	 */
--	dd->ipath_rcvctrl = INFINIPATH_R_TAILUPD |
--		(1ULL << INFINIPATH_R_PORTENABLE_SHIFT) |
--		(1ULL << INFINIPATH_R_INTRAVAIL_SHIFT);
-+	dd->ipath_rcvctrl = (1ULL << dd->ipath_r_tailupd_shift) |
-+		(1ULL << dd->ipath_r_portenable_shift) |
-+		(1ULL << dd->ipath_r_intravail_shift);
- 	ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl,
- 			 dd->ipath_rcvctrl);
++config TUNER_TDA9887
++	tristate "TDA 9885/6/7 analog IF demodulator"
++	depends on I2C
++	default m if VIDEO_TUNER_CUSTOMIZE
++	help
++	  Say Y here to include support for Philips TDA9885/6/7
++	  analog IF demodulator.
++
+ endif # VIDEO_TUNER_CUSTOMIZE
  
-@@ -523,12 +510,11 @@ static void enable_chip(struct ipath_devdata *dd,
- 	 */
- 	val = ipath_read_ureg32(dd, ur_rcvegrindextail, 0);
- 	(void)ipath_write_ureg(dd, ur_rcvegrindexhead, val, 0);
--	dd->ipath_port0head = ipath_read_ureg32(dd, ur_rcvhdrtail, 0);
+ config VIDEOBUF_GEN
+diff --git a/drivers/media/common/Kconfig b/drivers/media/common/Kconfig
+index c5092ef..06ca759 100644
+--- a/drivers/media/common/Kconfig
++++ b/drivers/media/common/Kconfig
+@@ -1,6 +1,6 @@
+ config VIDEO_SAA7146
+ 	tristate
+-	depends on I2C
++	depends on I2C && PCI
  
- 	/* Initialize so we interrupt on next packet received */
- 	(void)ipath_write_ureg(dd, ur_rcvhdrhead,
- 			       dd->ipath_rhdrhead_intr_off |
--			       dd->ipath_port0head, 0);
-+			       dd->ipath_pd[0]->port_head, 0);
+ config VIDEO_SAA7146_VV
+ 	tristate
+diff --git a/drivers/media/common/ir-functions.c b/drivers/media/common/ir-functions.c
+index e7c3ab9..bb2a027 100644
+--- a/drivers/media/common/ir-functions.c
++++ b/drivers/media/common/ir-functions.c
+@@ -258,7 +258,7 @@ int ir_decode_biphase(u32 *samples, int count, int low, int high)
+  * saa7134 */
  
- 	/*
- 	 * by now pioavail updates to memory should have occurred, so
-@@ -542,12 +528,8 @@ static void enable_chip(struct ipath_devdata *dd,
- 		/*
- 		 * Chip Errata bug 6641; even and odd qwords>3 are swapped.
- 		 */
--		if (i > 3) {
--			if (i & 1)
--				val = dd->ipath_pioavailregs_dma[i - 1];
--			else
--				val = dd->ipath_pioavailregs_dma[i + 1];
--		}
-+		if (i > 3 && (dd->ipath_flags & IPATH_SWAP_PIOBUFS))
-+			val = dd->ipath_pioavailregs_dma[i ^ 1];
- 		else
- 			val = dd->ipath_pioavailregs_dma[i];
- 		dd->ipath_pioavailshadow[i] = le64_to_cpu(val);
-@@ -690,12 +672,13 @@ done:
-  */
- int ipath_init_chip(struct ipath_devdata *dd, int reinit)
+ /* decode raw bit pattern to RC5 code */
+-u32 ir_rc5_decode(unsigned int code)
++static u32 ir_rc5_decode(unsigned int code)
  {
--	int ret = 0, i;
-+	int ret = 0;
- 	u32 val32, kpiobufs;
- 	u32 piobufs, uports;
- 	u64 val;
- 	struct ipath_portdata *pd = NULL; /* keep gcc4 happy */
- 	gfp_t gfp_flags = GFP_USER | __GFP_COMP;
-+	unsigned long flags;
+ 	unsigned int org_code = code;
+ 	unsigned int pair;
+@@ -371,7 +371,6 @@ EXPORT_SYMBOL_GPL(ir_dump_samples);
+ EXPORT_SYMBOL_GPL(ir_decode_biphase);
+ EXPORT_SYMBOL_GPL(ir_decode_pulsedistance);
  
- 	ret = init_housekeeping(dd, &pd, reinit);
- 	if (ret)
-@@ -746,7 +729,7 @@ int ipath_init_chip(struct ipath_devdata *dd, int reinit)
- 		kpiobufs = ipath_kpiobufs;
+-EXPORT_SYMBOL_GPL(ir_rc5_decode);
+ EXPORT_SYMBOL_GPL(ir_rc5_timer_end);
+ EXPORT_SYMBOL_GPL(ir_rc5_timer_keyup);
  
- 	if (kpiobufs + (uports * IPATH_MIN_USER_PORT_BUFCNT) > piobufs) {
--		i = (int) piobufs -
-+		int i = (int) piobufs -
- 			(int) (uports * IPATH_MIN_USER_PORT_BUFCNT);
- 		if (i < 0)
- 			i = 0;
-@@ -827,8 +810,12 @@ int ipath_init_chip(struct ipath_devdata *dd, int reinit)
- 	ipath_write_kreg(dd, dd->ipath_kregs->kr_hwerrclear,
- 			 ~0ULL&~INFINIPATH_HWE_MEMBISTFAILED);
- 	ipath_write_kreg(dd, dd->ipath_kregs->kr_control, 0ULL);
--	ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
--			 INFINIPATH_S_PIOENABLE);
+diff --git a/drivers/media/common/ir-keymaps.c b/drivers/media/common/ir-keymaps.c
+index 185e8a8..a4a937c 100644
+--- a/drivers/media/common/ir-keymaps.c
++++ b/drivers/media/common/ir-keymaps.c
+@@ -1331,7 +1331,12 @@ IR_KEYTAB_TYPE ir_codes_winfast[IR_KEYTAB_SIZE] = {
+ 	[ 0x35 ] = KEY_FASTFORWARD,
+ 	[ 0x36 ] = KEY_TV,
+ 	[ 0x37 ] = KEY_RADIO,         /* FM */
+-	[ 0x38 ] = KEY_DVD
++	[ 0x38 ] = KEY_DVD,
 +
-+	spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags);
-+	dd->ipath_sendctrl = INFINIPATH_S_PIOENABLE;
-+	ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, dd->ipath_sendctrl);
-+	ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
-+	spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags);
++	[ 0x3e ] = KEY_F21,           /* MCE +VOL, on Y04G0033 */
++	[ 0x3a ] = KEY_F22,           /* MCE -VOL, on Y04G0033 */
++	[ 0x3b ] = KEY_F23,           /* MCE +CH,  on Y04G0033 */
++	[ 0x3f ] = KEY_F24            /* MCE -CH,  on Y04G0033 */
+ };
  
- 	/*
- 	 * before error clears, since we expect serdes pll errors during
-diff --git a/drivers/infiniband/hw/ipath/ipath_intr.c b/drivers/infiniband/hw/ipath/ipath_intr.c
-index c61f9da..92e58c9 100644
---- a/drivers/infiniband/hw/ipath/ipath_intr.c
-+++ b/drivers/infiniband/hw/ipath/ipath_intr.c
-@@ -683,7 +683,7 @@ static int handle_errors(struct ipath_devdata *dd, ipath_err_t errs)
- 		for (i = 0; i < dd->ipath_cfgports; i++) {
- 			struct ipath_portdata *pd = dd->ipath_pd[i];
- 			if (i == 0) {
--				hd = dd->ipath_port0head;
-+				hd = pd->port_head;
- 				tl = (u32) le64_to_cpu(
- 					*dd->ipath_hdrqtailptr);
- 			} else if (pd && pd->port_cnt &&
-@@ -693,7 +693,7 @@ static int handle_errors(struct ipath_devdata *dd, ipath_err_t errs)
- 				 * except kernel
- 				 */
- 				tl = *(u64 *) pd->port_rcvhdrtail_kvaddr;
--				if (tl == dd->ipath_lastrcvhdrqtails[i])
-+				if (tl == pd->port_lastrcvhdrqtail)
- 					continue;
- 				hd = ipath_read_ureg32(dd, ur_rcvhdrhead,
- 						       i);
-@@ -703,7 +703,7 @@ static int handle_errors(struct ipath_devdata *dd, ipath_err_t errs)
- 			    (!hd && tl == dd->ipath_hdrqlast)) {
- 				if (i == 0)
- 					chkerrpkts = 1;
--				dd->ipath_lastrcvhdrqtails[i] = tl;
-+				pd->port_lastrcvhdrqtail = tl;
- 				pd->port_hdrqfull++;
- 				/* flush hdrqfull so that poll() sees it */
- 				wmb();
-@@ -712,6 +712,8 @@ static int handle_errors(struct ipath_devdata *dd, ipath_err_t errs)
- 		}
- 	}
- 	if (errs & INFINIPATH_E_RRCVEGRFULL) {
-+		struct ipath_portdata *pd = dd->ipath_pd[0];
-+
- 		/*
- 		 * since this is of less importance and not likely to
- 		 * happen without also getting hdrfull, only count
-@@ -719,7 +721,7 @@ static int handle_errors(struct ipath_devdata *dd, ipath_err_t errs)
- 		 * vs user)
- 		 */
- 		ipath_stats.sps_etidfull++;
--		if (dd->ipath_port0head !=
-+		if (pd->port_head !=
- 		    (u32) le64_to_cpu(*dd->ipath_hdrqtailptr))
- 			chkerrpkts = 1;
- 	}
-@@ -795,6 +797,7 @@ void ipath_clear_freeze(struct ipath_devdata *dd)
- {
- 	int i, im;
- 	__le64 val;
-+	unsigned long flags;
+ EXPORT_SYMBOL_GPL(ir_codes_winfast);
+@@ -1843,3 +1848,142 @@ IR_KEYTAB_TYPE ir_codes_fusionhdtv_mce[IR_KEYTAB_SIZE] = {
+ };
  
- 	/* disable error interrupts, to avoid confusion */
- 	ipath_write_kreg(dd, dd->ipath_kregs->kr_errormask, 0ULL);
-@@ -813,11 +816,14 @@ void ipath_clear_freeze(struct ipath_devdata *dd)
- 			 dd->ipath_control);
+ EXPORT_SYMBOL_GPL(ir_codes_fusionhdtv_mce);
++
++/* Pinnacle PCTV HD 800i mini remote */
++IR_KEYTAB_TYPE ir_codes_pinnacle_pctv_hd[IR_KEYTAB_SIZE] = {
++
++	[0x0f] = KEY_1,
++	[0x15] = KEY_2,
++	[0x10] = KEY_3,
++	[0x18] = KEY_4,
++	[0x1b] = KEY_5,
++	[0x1e] = KEY_6,
++	[0x11] = KEY_7,
++	[0x21] = KEY_8,
++	[0x12] = KEY_9,
++	[0x27] = KEY_0,
++
++	[0x24] = KEY_ZOOM,
++	[0x2a] = KEY_SUBTITLE,
++
++	[0x00] = KEY_MUTE,
++	[0x01] = KEY_ENTER,	/* Pinnacle Logo */
++	[0x39] = KEY_POWER,
++
++	[0x03] = KEY_VOLUMEUP,
++	[0x09] = KEY_VOLUMEDOWN,
++	[0x06] = KEY_CHANNELUP,
++	[0x0c] = KEY_CHANNELDOWN,
++
++	[0x2d] = KEY_REWIND,
++	[0x30] = KEY_PLAYPAUSE,
++	[0x33] = KEY_FASTFORWARD,
++	[0x3c] = KEY_STOP,
++	[0x36] = KEY_RECORD,
++	[0x3f] = KEY_EPG,	/* Labeled "?" */
++};
++EXPORT_SYMBOL_GPL(ir_codes_pinnacle_pctv_hd);
++
++/*
++ * Igor Kuznetsov <igk72 at ya.ru>
++ * Andrey J. Melnikov <temnota at kmv.ru>
++ *
++ * Keytable is used by BeholdTV 60x series, M6 series at
++ * least, and probably other cards too.
++ * The "ascii-art picture" below (in comments, first row
++ * is the keycode in hex, and subsequent row(s) shows
++ * the button labels (several variants when appropriate)
++ * helps to descide which keycodes to assign to the buttons.
++ */
++IR_KEYTAB_TYPE ir_codes_behold[IR_KEYTAB_SIZE] = {
++
++	/*  0x1c            0x12  *
++	 *  TV/FM          POWER  *
++	 *                        */
++	[ 0x1c ] = KEY_TUNER,	/*XXX KEY_TV KEY_RADIO */
++	[ 0x12 ] = KEY_POWER,
++
++	/*  0x01    0x02    0x03  *
++	 *   1       2       3    *
++	 *                        *
++	 *  0x04    0x05    0x06  *
++	 *   4       5       6    *
++	 *                        *
++	 *  0x07    0x08    0x09  *
++	 *   7       8       9    *
++	 *                        */
++	[ 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,
++
++	/*  0x0a    0x00    0x17  *
++	 * RECALL    0      MODE  *
++	 *                        */
++	[ 0x0a ] = KEY_AGAIN,
++	[ 0x00 ] = KEY_0,
++	[ 0x17 ] = KEY_MODE,
++
++	/*  0x14          0x10    *
++	 * ASPECT      FULLSCREEN *
++	 *                        */
++	[ 0x14 ] = KEY_SCREEN,
++	[ 0x10 ] = KEY_ZOOM,
++
++	/*          0x0b          *
++	 *           Up           *
++	 *                        *
++	 *  0x18    0x16    0x0c  *
++	 *  Left     Ok     Right *
++	 *                        *
++	 *         0x015          *
++	 *         Down           *
++	 *                        */
++	[ 0x0b ] = KEY_CHANNELUP,	/*XXX KEY_UP */
++	[ 0x18 ] = KEY_VOLUMEDOWN,	/*XXX KEY_LEFT */
++	[ 0x16 ] = KEY_OK,		/*XXX KEY_ENTER */
++	[ 0x0c ] = KEY_VOLUMEUP,	/*XXX KEY_RIGHT */
++	[ 0x15 ] = KEY_CHANNELDOWN,	/*XXX KEY_DOWN */
++
++	/*  0x11            0x0d  *
++	 *  MUTE            INFO  *
++	 *                        */
++	[ 0x11 ] = KEY_MUTE,
++	[ 0x0d ] = KEY_INFO,
++
++	/*  0x0f    0x1b    0x1a  *
++	 * RECORD PLAY/PAUSE STOP *
++	 *                        *
++	 *  0x0e    0x1f    0x1e  *
++	 *TELETEXT  AUDIO  SOURCE *
++	 *           RED   YELLOW *
++	 *                        */
++	[ 0x0f ] = KEY_RECORD,
++	[ 0x1b ] = KEY_PLAYPAUSE,
++	[ 0x1a ] = KEY_STOP,
++	[ 0x0e ] = KEY_TEXT,
++	[ 0x1f ] = KEY_RED,	/*XXX KEY_AUDIO */
++	[ 0x1e ] = KEY_YELLOW,	/*XXX KEY_SOURCE */
++
++	/*  0x1d   0x13     0x19  *
++	 * SLEEP  PREVIEW   DVB   *
++	 *         GREEN    BLUE  *
++	 *                        */
++	[ 0x1d ] = KEY_SLEEP,
++	[ 0x13 ] = KEY_GREEN,
++	[ 0x19 ] = KEY_BLUE,	/*XXX KEY_SAT */
++
++	/*  0x58           0x5c   *
++	 * FREEZE        SNAPSHOT *
++	 *                        */
++	[ 0x58 ] = KEY_SLOW,
++	[ 0x5c ] = KEY_SAVE,
++
++};
++
++EXPORT_SYMBOL_GPL(ir_codes_behold);
+diff --git a/drivers/media/common/saa7146_fops.c b/drivers/media/common/saa7146_fops.c
+index 67d1b1b..f0703d8 100644
+--- a/drivers/media/common/saa7146_fops.c
++++ b/drivers/media/common/saa7146_fops.c
+@@ -61,7 +61,7 @@ void saa7146_dma_free(struct saa7146_dev *dev,struct videobuf_queue *q,
+ 	videobuf_waiton(&buf->vb,0,0);
+ 	videobuf_dma_unmap(q, dma);
+ 	videobuf_dma_free(dma);
+-	buf->vb.state = STATE_NEEDS_INIT;
++	buf->vb.state = VIDEOBUF_NEEDS_INIT;
+ }
  
- 	/* ensure pio avail updates continue */
-+	spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags);
- 	ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
- 		 dd->ipath_sendctrl & ~INFINIPATH_S_PIOBUFAVAILUPD);
- 	ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
- 	ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
--		 dd->ipath_sendctrl);
-+			 dd->ipath_sendctrl);
-+	ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
-+	spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags);
  
- 	/*
- 	 * We just enabled pioavailupdate, so dma copy is almost certainly
-@@ -825,8 +831,8 @@ void ipath_clear_freeze(struct ipath_devdata *dd)
- 	 */
- 	for (i = 0; i < dd->ipath_pioavregs; i++) {
- 		/* deal with 6110 chip bug */
--		im = i > 3 ? ((i&1) ? i-1 : i+1) : i;
--		val = ipath_read_kreg64(dd, (0x1000/sizeof(u64))+im);
-+		im = i > 3 ? i ^ 1 : i;
-+		val = ipath_read_kreg64(dd, (0x1000 / sizeof(u64)) + im);
- 		dd->ipath_pioavailregs_dma[i] = dd->ipath_pioavailshadow[i]
- 			= le64_to_cpu(val);
+@@ -83,7 +83,7 @@ int saa7146_buffer_queue(struct saa7146_dev *dev,
+ 		buf->activate(dev,buf,NULL);
+ 	} else {
+ 		list_add_tail(&buf->vb.queue,&q->queue);
+-		buf->vb.state = STATE_QUEUED;
++		buf->vb.state = VIDEOBUF_QUEUED;
+ 		DEB_D(("adding buffer %p to queue. (active buffer present)\n", buf));
+ 	}
+ 	return 0;
+@@ -174,7 +174,7 @@ void saa7146_buffer_timeout(unsigned long data)
+ 	spin_lock_irqsave(&dev->slock,flags);
+ 	if (q->curr) {
+ 		DEB_D(("timeout on %p\n", q->curr));
+-		saa7146_buffer_finish(dev,q,STATE_ERROR);
++		saa7146_buffer_finish(dev,q,VIDEOBUF_ERROR);
  	}
-@@ -849,7 +855,7 @@ void ipath_clear_freeze(struct ipath_devdata *dd)
- 
- /* this is separate to allow for better optimization of ipath_intr() */
- 
--static void ipath_bad_intr(struct ipath_devdata *dd, u32 * unexpectp)
-+static noinline void ipath_bad_intr(struct ipath_devdata *dd, u32 *unexpectp)
- {
- 	/*
- 	 * sometimes happen during driver init and unload, don't want
-@@ -877,7 +883,7 @@ static void ipath_bad_intr(struct ipath_devdata *dd, u32 * unexpectp)
- 				dd->ipath_f_free_irq(dd);
- 			}
- 		}
--		if (ipath_read_kreg32(dd, dd->ipath_kregs->kr_intmask)) {
-+		if (ipath_read_ireg(dd, dd->ipath_kregs->kr_intmask)) {
- 			ipath_dev_err(dd, "%u unexpected interrupts, "
- 				      "disabling interrupts completely\n",
- 				      *unexpectp);
-@@ -892,7 +898,7 @@ static void ipath_bad_intr(struct ipath_devdata *dd, u32 * unexpectp)
- 			  "ignoring\n");
- }
  
--static void ipath_bad_regread(struct ipath_devdata *dd)
-+static noinline void ipath_bad_regread(struct ipath_devdata *dd)
- {
- 	static int allbits;
+ 	/* we don't restart the transfer here like other drivers do. when
+@@ -366,7 +366,7 @@ static unsigned int fops_poll(struct file *file, struct poll_table_struct *wait)
+ 	}
  
-@@ -920,31 +926,9 @@ static void ipath_bad_regread(struct ipath_devdata *dd)
+ 	poll_wait(file, &buf->done, wait);
+-	if (buf->state == STATE_DONE || buf->state == STATE_ERROR) {
++	if (buf->state == VIDEOBUF_DONE || buf->state == VIDEOBUF_ERROR) {
+ 		DEB_D(("poll succeeded!\n"));
+ 		return POLLIN|POLLRDNORM;
+ 	}
+@@ -538,6 +538,7 @@ int saa7146_register_device(struct video_device **vid, struct saa7146_dev* dev,
+ 	// fixme: -1 should be an insmod parameter *for the extension* (like "video_nr");
+ 	if (video_register_device(vfd, type, -1) < 0) {
+ 		ERR(("cannot register v4l2 device. skipping.\n"));
++		video_device_release(vfd);
+ 		return -1;
  	}
- }
  
--static void handle_port_pioavail(struct ipath_devdata *dd)
--{
--	u32 i;
--	/*
--	 * start from port 1, since for now port 0  is never using
--	 * wait_event for PIO
--	 */
--	for (i = 1; dd->ipath_portpiowait && i < dd->ipath_cfgports; i++) {
--		struct ipath_portdata *pd = dd->ipath_pd[i];
--
--		if (pd && pd->port_cnt &&
--		    dd->ipath_portpiowait & (1U << i)) {
--			clear_bit(i, &dd->ipath_portpiowait);
--			if (test_bit(IPATH_PORT_WAITING_PIO,
--				     &pd->port_flag)) {
--				clear_bit(IPATH_PORT_WAITING_PIO,
--					  &pd->port_flag);
--				wake_up_interruptible(&pd->port_wait);
--			}
--		}
--	}
--}
--
- static void handle_layer_pioavail(struct ipath_devdata *dd)
+diff --git a/drivers/media/common/saa7146_vbi.c b/drivers/media/common/saa7146_vbi.c
+index 6103484..c32dda9 100644
+--- a/drivers/media/common/saa7146_vbi.c
++++ b/drivers/media/common/saa7146_vbi.c
+@@ -205,7 +205,7 @@ static int buffer_activate(struct saa7146_dev *dev,
+ 			   struct saa7146_buf *next)
  {
-+	unsigned long flags;
- 	int ret;
- 
- 	ret = ipath_ib_piobufavail(dd->verbs_dev);
-@@ -953,9 +937,12 @@ static void handle_layer_pioavail(struct ipath_devdata *dd)
+ 	struct saa7146_vv *vv = dev->vv_data;
+-	buf->vb.state = STATE_ACTIVE;
++	buf->vb.state = VIDEOBUF_ACTIVE;
  
- 	return;
- set:
--	set_bit(IPATH_S_PIOINTBUFAVAIL, &dd->ipath_sendctrl);
-+	spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags);
-+	dd->ipath_sendctrl |= INFINIPATH_S_PIOINTBUFAVAIL;
- 	ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
- 			 dd->ipath_sendctrl);
-+	ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
-+	spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags);
- }
+ 	DEB_VBI(("dev:%p, buf:%p, next:%p\n",dev,buf,next));
+ 	saa7146_set_vbi_capture(dev,buf,next);
+@@ -238,7 +238,7 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,e
+ 	if (buf->vb.size != size)
+ 		saa7146_dma_free(dev,q,buf);
  
- /*
-@@ -969,7 +956,15 @@ static void handle_urcv(struct ipath_devdata *dd, u32 istat)
- 	int i;
- 	int rcvdint = 0;
+-	if (STATE_NEEDS_INIT == buf->vb.state) {
++	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
+ 		struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
  
--	/* test_bit below needs this... */
-+	/*
-+	 * test_and_clear_bit(IPATH_PORT_WAITING_RCV) and
-+	 * test_and_clear_bit(IPATH_PORT_WAITING_URG) below
-+	 * would both like timely updates of the bits so that
-+	 * we don't pass them by unnecessarily.  the rmb()
-+	 * here ensures that we see them promptly -- the
-+	 * corresponding wmb()'s are in ipath_poll_urgent()
-+	 * and ipath_poll_next()...
-+	 */
- 	rmb();
- 	portr = ((istat >> INFINIPATH_I_RCVAVAIL_SHIFT) &
- 		 dd->ipath_i_rcvavail_mask)
-@@ -980,7 +975,7 @@ static void handle_urcv(struct ipath_devdata *dd, u32 istat)
- 		if (portr & (1 << i) && pd && pd->port_cnt) {
- 			if (test_and_clear_bit(IPATH_PORT_WAITING_RCV,
- 					       &pd->port_flag)) {
--				clear_bit(i + INFINIPATH_R_INTRAVAIL_SHIFT,
-+				clear_bit(i + dd->ipath_r_intravail_shift,
- 					  &dd->ipath_rcvctrl);
- 				wake_up_interruptible(&pd->port_wait);
- 				rcvdint = 1;
-@@ -1039,7 +1034,7 @@ irqreturn_t ipath_intr(int irq, void *data)
- 		goto bail;
+ 		buf->vb.width  = llength;
+@@ -257,7 +257,7 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,e
+ 		if (0 != err)
+ 			return err;
  	}
+-	buf->vb.state = STATE_PREPARED;
++	buf->vb.state = VIDEOBUF_PREPARED;
+ 	buf->activate = buffer_activate;
  
--	istat = ipath_read_kreg32(dd, dd->ipath_kregs->kr_intstatus);
-+	istat = ipath_read_ireg(dd, dd->ipath_kregs->kr_intstatus);
+ 	return 0;
+@@ -335,7 +335,7 @@ static void vbi_stop(struct saa7146_fh *fh, struct file *file)
+ 	saa7146_write(dev, MC1, MASK_20);
  
- 	if (unlikely(!istat)) {
- 		ipath_stats.sps_nullintr++;
-@@ -1180,7 +1175,7 @@ irqreturn_t ipath_intr(int irq, void *data)
- 	 * for receive are at the bottom.
- 	 */
- 	if (chk0rcv) {
--		ipath_kreceive(dd);
-+		ipath_kreceive(dd->ipath_pd[0]);
- 		istat &= ~port0rbits;
+ 	if (vv->vbi_q.curr) {
+-		saa7146_buffer_finish(dev,&vv->vbi_q,STATE_DONE);
++		saa7146_buffer_finish(dev,&vv->vbi_q,VIDEOBUF_DONE);
  	}
  
-@@ -1191,12 +1186,14 @@ irqreturn_t ipath_intr(int irq, void *data)
- 		handle_urcv(dd, istat);
+ 	videobuf_queue_cancel(&fh->vbi_q);
+@@ -458,7 +458,7 @@ static void vbi_irq_done(struct saa7146_dev *dev, unsigned long status)
+ 		/* this must be += 2, one count for each field */
+ 		vv->vbi_fieldcount+=2;
+ 		vv->vbi_q.curr->vb.field_count = vv->vbi_fieldcount;
+-		saa7146_buffer_finish(dev,&vv->vbi_q,STATE_DONE);
++		saa7146_buffer_finish(dev,&vv->vbi_q,VIDEOBUF_DONE);
+ 	} else {
+ 		DEB_VBI(("dev:%p\n",dev));
+ 	}
+diff --git a/drivers/media/common/saa7146_video.c b/drivers/media/common/saa7146_video.c
+index ae36d10..c31ab48 100644
+--- a/drivers/media/common/saa7146_video.c
++++ b/drivers/media/common/saa7146_video.c
+@@ -1235,7 +1235,7 @@ static int buffer_activate (struct saa7146_dev *dev,
+ {
+ 	struct saa7146_vv *vv = dev->vv_data;
  
- 	if (istat & INFINIPATH_I_SPIOBUFAVAIL) {
--		clear_bit(IPATH_S_PIOINTBUFAVAIL, &dd->ipath_sendctrl);
-+		unsigned long flags;
-+
-+		spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags);
-+		dd->ipath_sendctrl &= ~INFINIPATH_S_PIOINTBUFAVAIL;
- 		ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
- 				 dd->ipath_sendctrl);
--
--		if (dd->ipath_portpiowait)
--			handle_port_pioavail(dd);
-+		ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
-+		spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags);
+-	buf->vb.state = STATE_ACTIVE;
++	buf->vb.state = VIDEOBUF_ACTIVE;
+ 	saa7146_set_capture(dev,buf,next);
  
- 		handle_layer_pioavail(dd);
+ 	mod_timer(&vv->video_q.timeout, jiffies+BUFFER_TIMEOUT);
+@@ -1281,7 +1281,7 @@ static int buffer_prepare(struct videobuf_queue *q,
+ 		saa7146_dma_free(dev,q,buf);
  	}
-diff --git a/drivers/infiniband/hw/ipath/ipath_kernel.h b/drivers/infiniband/hw/ipath/ipath_kernel.h
-index 8786dd7..4cc0f95 100644
---- a/drivers/infiniband/hw/ipath/ipath_kernel.h
-+++ b/drivers/infiniband/hw/ipath/ipath_kernel.h
-@@ -41,6 +41,7 @@
- #include <linux/interrupt.h>
- #include <linux/pci.h>
- #include <linux/dma-mapping.h>
-+#include <linux/mutex.h>
- #include <asm/io.h>
- #include <rdma/ib_verbs.h>
- 
-@@ -140,6 +141,11 @@ struct ipath_portdata {
- 	u32 port_pionowait;
- 	/* total number of rcvhdrqfull errors */
- 	u32 port_hdrqfull;
-+	/*
-+	 * Used to suppress multiple instances of same
-+	 * port staying stuck at same point.
-+	 */
-+	u32 port_lastrcvhdrqtail;
- 	/* saved total number of rcvhdrqfull errors for poll edge trigger */
- 	u32 port_hdrqfull_poll;
- 	/* total number of polled urgent packets */
-@@ -148,6 +154,7 @@ struct ipath_portdata {
- 	u32 port_urgent_poll;
- 	/* pid of process using this port */
- 	pid_t port_pid;
-+	pid_t port_subpid[INFINIPATH_MAX_SUBPORT];
- 	/* same size as task_struct .comm[] */
- 	char port_comm[16];
- 	/* pkeys set by this use of this port */
-@@ -166,6 +173,8 @@ struct ipath_portdata {
- 	u32 active_slaves;
- 	/* Type of packets or conditions we want to poll for */
- 	u16 poll_type;
-+	/* port rcvhdrq head offset */
-+	u32 port_head;
- };
  
- struct sk_buff;
-@@ -182,6 +191,22 @@ struct ipath_skbinfo {
- 	dma_addr_t phys;
- };
+-	if (STATE_NEEDS_INIT == buf->vb.state) {
++	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
+ 		struct saa7146_format *sfmt;
  
-+/*
-+ * Possible IB config parameters for ipath_f_get/set_ib_cfg()
-+ */
-+#define IPATH_IB_CFG_LIDLMC 0 /* Get/set LID (LS16b) and Mask (MS16b) */
-+#define IPATH_IB_CFG_HRTBT 1 /* Get/set Heartbeat off/enable/auto */
-+#define IPATH_IB_HRTBT_ON 3 /* Heartbeat enabled, sent every 100msec */
-+#define IPATH_IB_HRTBT_OFF 0 /* Heartbeat off */
-+#define IPATH_IB_CFG_LWID_ENB 2 /* Get/set allowed Link-width */
-+#define IPATH_IB_CFG_LWID 3 /* Get currently active Link-width */
-+#define IPATH_IB_CFG_SPD_ENB 4 /* Get/set allowed Link speeds */
-+#define IPATH_IB_CFG_SPD 5 /* Get current Link spd */
-+#define IPATH_IB_CFG_RXPOL_ENB 6 /* Get/set Auto-RX-polarity enable */
-+#define IPATH_IB_CFG_LREV_ENB 7 /* Get/set Auto-Lane-reversal enable */
-+#define IPATH_IB_CFG_LINKLATENCY 8 /* Get Auto-Lane-reversal enable */
-+
-+
- struct ipath_devdata {
- 	struct list_head ipath_list;
+ 		buf->vb.bytesperline  = fh->video_fmt.bytesperline;
+@@ -1314,7 +1314,7 @@ static int buffer_prepare(struct videobuf_queue *q,
+ 		if (err)
+ 			goto oops;
+ 	}
+-	buf->vb.state = STATE_PREPARED;
++	buf->vb.state = VIDEOBUF_PREPARED;
+ 	buf->activate = buffer_activate;
  
-@@ -222,6 +247,8 @@ struct ipath_devdata {
- 	struct _ipath_layer ipath_layer;
- 	/* setup intr */
- 	int (*ipath_f_intrsetup)(struct ipath_devdata *);
-+	/* fallback to alternate interrupt type if possible */
-+	int (*ipath_f_intr_fallback)(struct ipath_devdata *);
- 	/* setup on-chip bus config */
- 	int (*ipath_f_bus)(struct ipath_devdata *, struct pci_dev *);
- 	/* hard reset chip */
-@@ -244,6 +271,18 @@ struct ipath_devdata {
- 	int (*ipath_f_get_base_info)(struct ipath_portdata *, void *);
- 	/* free irq */
- 	void (*ipath_f_free_irq)(struct ipath_devdata *);
-+	struct ipath_message_header *(*ipath_f_get_msgheader)
-+					(struct ipath_devdata *, __le32 *);
-+	void (*ipath_f_config_ports)(struct ipath_devdata *, ushort);
-+	int (*ipath_f_get_ib_cfg)(struct ipath_devdata *, int);
-+	int (*ipath_f_set_ib_cfg)(struct ipath_devdata *, int, u32);
-+	void (*ipath_f_config_jint)(struct ipath_devdata *, u16 , u16);
-+	void (*ipath_f_read_counters)(struct ipath_devdata *,
-+					struct infinipath_counters *);
-+	void (*ipath_f_xgxs_reset)(struct ipath_devdata *);
-+	/* per chip actions needed for IB Link up/down changes */
-+	int (*ipath_f_ib_updown)(struct ipath_devdata *, int, u64);
-+
- 	struct ipath_ibdev *verbs_dev;
- 	struct timer_list verbs_timer;
- 	/* total dwords sent (summed from counter) */
-@@ -313,22 +352,12 @@ struct ipath_devdata {
- 	 * supports, less gives more pio bufs/port, etc.
- 	 */
- 	u32 ipath_cfgports;
--	/* port0 rcvhdrq head offset */
--	u32 ipath_port0head;
- 	/* count of port 0 hdrqfull errors */
- 	u32 ipath_p0_hdrqfull;
-+	/* port 0 number of receive eager buffers */
-+	u32 ipath_p0_rcvegrcnt;
+ 	return 0;
+@@ -1453,7 +1453,7 @@ static void video_irq_done(struct saa7146_dev *dev, unsigned long st)
  
- 	/*
--	 * (*cfgports) used to suppress multiple instances of same
--	 * port staying stuck at same point
--	 */
--	u32 *ipath_lastrcvhdrqtails;
--	/*
--	 * (*cfgports) used to suppress multiple instances of same
--	 * port staying stuck at same point
--	 */
--	u32 *ipath_lastegrheads;
--	/*
- 	 * index of last piobuffer we used.  Speeds up searching, by
- 	 * starting at this point.  Doesn't matter if multiple cpu's use and
- 	 * update, last updater is only write that matters.  Whenever it
-@@ -367,14 +396,15 @@ struct ipath_devdata {
- 	unsigned long ipath_wc_len;
- 	/* ref count for each pkey */
- 	atomic_t ipath_pkeyrefs[4];
--	/* shadow copy of all exptids physaddr; used only by funcsim */
--	u64 *ipath_tidsimshadow;
- 	/* shadow copy of struct page *'s for exp tid pages */
- 	struct page **ipath_pageshadow;
- 	/* shadow copy of dma handles for exp tid pages */
- 	dma_addr_t *ipath_physshadow;
--	/* lock to workaround chip bug 9437 */
-+	u64 __iomem *ipath_egrtidbase;
-+	/* lock to workaround chip bug 9437 and others */
-+	spinlock_t ipath_kernel_tid_lock;
- 	spinlock_t ipath_tid_lock;
-+	spinlock_t ipath_sendctrl_lock;
+ 	/* only finish the buffer if we have one... */
+ 	if( NULL != q->curr ) {
+-		saa7146_buffer_finish(dev,q,STATE_DONE);
++		saa7146_buffer_finish(dev,q,VIDEOBUF_DONE);
+ 	}
+ 	saa7146_buffer_next(dev,q,0);
  
- 	/*
- 	 * IPATH_STATUS_*,
-@@ -395,6 +425,8 @@ struct ipath_devdata {
- 	void *ipath_dummy_hdrq;	/* used after port close */
- 	dma_addr_t ipath_dummy_hdrq_phys;
+diff --git a/drivers/media/dvb/b2c2/flexcop.c b/drivers/media/dvb/b2c2/flexcop.c
+index 29ec418..2ddafd0 100644
+--- a/drivers/media/dvb/b2c2/flexcop.c
++++ b/drivers/media/dvb/b2c2/flexcop.c
+@@ -212,7 +212,6 @@ void flexcop_reset_block_300(struct flexcop_device *fc)
  
-+	unsigned long ipath_ureg_align; /* user register alignment */
-+
- 	/*
- 	 * Shadow copies of registers; size indicates read access size.
- 	 * Most of them are readonly, but some are write-only register,
-@@ -456,8 +488,6 @@ struct ipath_devdata {
- 	unsigned long ipath_rcvctrl;
- 	/* shadow kr_sendctrl */
- 	unsigned long ipath_sendctrl;
--	/* ports waiting for PIOavail intr */
--	unsigned long ipath_portpiowait;
- 	unsigned long ipath_lastcancel; /* to not count armlaunch after cancel */
+ 	fc->write_ibi_reg(fc,ctrl_208,v208_save);
+ }
+-EXPORT_SYMBOL(flexcop_reset_block_300);
  
- 	/* value we put in kr_rcvhdrcnt */
-@@ -550,12 +580,26 @@ struct ipath_devdata {
- 	u8 ipath_minrev;
- 	/* board rev, from ipath_revision */
- 	u8 ipath_boardrev;
-+
-+	u8 ipath_r_portenable_shift;
-+	u8 ipath_r_intravail_shift;
-+	u8 ipath_r_tailupd_shift;
-+	u8 ipath_r_portcfg_shift;
-+
- 	/* unit # of this chip, if present */
- 	int ipath_unit;
- 	/* saved for restore after reset */
- 	u8 ipath_pci_cacheline;
- 	/* LID mask control */
- 	u8 ipath_lmc;
-+	/* link width supported */
-+	u8 ipath_link_width_supported;
-+	/* link speed supported */
-+	u8 ipath_link_speed_supported;
-+	u8 ipath_link_width_enabled;
-+	u8 ipath_link_speed_enabled;
-+	u8 ipath_link_width_active;
-+	u8 ipath_link_speed_active;
- 	/* Rx Polarity inversion (compensate for ~tx on partner) */
- 	u8 ipath_rx_pol_inv;
+ struct flexcop_device *flexcop_device_kmalloc(size_t bus_specific_len)
+ {
+diff --git a/drivers/media/dvb/bt8xx/bt878.c b/drivers/media/dvb/bt8xx/bt878.c
+index 85e36a1..c7bbb40 100644
+--- a/drivers/media/dvb/bt8xx/bt878.c
++++ b/drivers/media/dvb/bt8xx/bt878.c
+@@ -378,23 +378,37 @@ bt878_device_control(struct bt878 *bt, unsigned int cmd, union dst_gpio_packet *
  
-@@ -590,6 +634,8 @@ struct ipath_devdata {
- 	 */
- 	u32 ipath_i_rcvavail_mask;
- 	u32 ipath_i_rcvurg_mask;
-+	u16 ipath_i_rcvurg_shift;
-+	u16 ipath_i_rcvavail_shift;
+ EXPORT_SYMBOL(bt878_device_control);
  
- 	/*
- 	 * Register bits for selecting i2c direction and values, used for
-@@ -603,6 +649,29 @@ struct ipath_devdata {
- 	/* lock for doing RMW of shadows/regs for ExtCtrl and GPIO */
- 	spinlock_t ipath_gpio_lock;
++#define BROOKTREE_878_DEVICE(vend, dev, name) \
++	{ \
++		.vendor = PCI_VENDOR_ID_BROOKTREE, \
++		.device = PCI_DEVICE_ID_BROOKTREE_878, \
++		.subvendor = (vend), .subdevice = (dev), \
++		.driver_data = (unsigned long) name \
++	}
  
-+	/*
-+	 * IB link and linktraining states and masks that vary per chip in
-+	 * some way.  Set at init, to avoid each IB status change interrupt
-+	 */
-+	u8 ibcs_ls_shift;
-+	u8 ibcs_lts_mask;
-+	u32 ibcs_mask;
-+	u32 ib_init;
-+	u32 ib_arm;
-+	u32 ib_active;
-+
-+	u16 ipath_rhf_offset; /* offset of RHF within receive header entry */
-+
-+	/*
-+	 * shift/mask for linkcmd, linkinitcmd, maxpktlen in ibccontol
-+	 * reg. Changes for IBA7220
-+	 */
-+	u8 ibcc_lic_mask; /* LinkInitCmd */
-+	u8 ibcc_lc_shift; /* LinkCmd */
-+	u8 ibcc_mpl_shift; /* Maxpktlen */
-+
-+	u8 delay_mult;
-+
- 	/* used to override LED behavior */
- 	u8 ipath_led_override;  /* Substituted for normal value, if non-zero */
- 	u16 ipath_led_override_timeoff; /* delta to next timer event */
-@@ -616,7 +685,7 @@ struct ipath_devdata {
- 	/* control access to actual counters, timer */
- 	spinlock_t ipath_eep_st_lock;
- 	/* control high-level access to EEPROM */
--	struct semaphore ipath_eep_sem;
-+	struct mutex ipath_eep_lock;
- 	/* Below inc'd by ipath_snap_cntrs(), locked by ipath_eep_st_lock */
- 	uint64_t ipath_traffic_wds;
- 	/* active time is kept in seconds, but logged in hours */
-@@ -630,6 +699,10 @@ struct ipath_devdata {
- 	 * each of the counters to increment.
- 	 */
- 	struct ipath_eep_log_mask ipath_eep_st_masks[IPATH_EEP_LOG_CNT];
-+
-+	/* interrupt mitigation reload register info */
-+	u16 ipath_jint_idle_ticks;	/* idle clock ticks */
-+	u16 ipath_jint_max_packets;	/* max packets across all ports */
+-static struct cards card_list[] __devinitdata = {
+-
+-	{ 0x01010071, BTTV_BOARD_NEBULA_DIGITV,			"Nebula Electronics DigiTV" },
+-	{ 0x07611461, BTTV_BOARD_AVDVBT_761,			"AverMedia AverTV DVB-T 761" },
+-	{ 0x001c11bd, BTTV_BOARD_PINNACLESAT,			"Pinnacle PCTV Sat" },
+-	{ 0x002611bd, BTTV_BOARD_TWINHAN_DST,			"Pinnacle PCTV SAT CI" },
+-	{ 0x00011822, BTTV_BOARD_TWINHAN_DST,			"Twinhan VisionPlus DVB" },
+-	{ 0xfc00270f, BTTV_BOARD_TWINHAN_DST,			"ChainTech digitop DST-1000 DVB-S" },
+-	{ 0x07711461, BTTV_BOARD_AVDVBT_771,			"AVermedia AverTV DVB-T 771" },
+-	{ 0xdb1018ac, BTTV_BOARD_DVICO_DVBT_LITE,		"DViCO FusionHDTV DVB-T Lite" },
+-	{ 0xdb1118ac, BTTV_BOARD_DVICO_DVBT_LITE,		"Ultraview DVB-T Lite" },
+-	{ 0xd50018ac, BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE,	"DViCO FusionHDTV 5 Lite" },
+-	{ 0x20007063, BTTV_BOARD_PC_HDTV,			"pcHDTV HD-2000 TV" },
+-	{ 0x00261822, BTTV_BOARD_TWINHAN_DST,			"DNTV Live! Mini" }
++static struct pci_device_id bt878_pci_tbl[] __devinitdata = {
++	BROOKTREE_878_DEVICE(0x0071, 0x0101, "Nebula Electronics DigiTV"),
++	BROOKTREE_878_DEVICE(0x1461, 0x0761, "AverMedia AverTV DVB-T 761"),
++	BROOKTREE_878_DEVICE(0x11bd, 0x001c, "Pinnacle PCTV Sat"),
++	BROOKTREE_878_DEVICE(0x11bd, 0x0026, "Pinnacle PCTV SAT CI"),
++	BROOKTREE_878_DEVICE(0x1822, 0x0001, "Twinhan VisionPlus DVB"),
++	BROOKTREE_878_DEVICE(0x270f, 0xfc00,
++				"ChainTech digitop DST-1000 DVB-S"),
++	BROOKTREE_878_DEVICE(0x1461, 0x0771, "AVermedia AverTV DVB-T 771"),
++	BROOKTREE_878_DEVICE(0x18ac, 0xdb10, "DViCO FusionHDTV DVB-T Lite"),
++	BROOKTREE_878_DEVICE(0x18ac, 0xdb11, "Ultraview DVB-T Lite"),
++	BROOKTREE_878_DEVICE(0x18ac, 0xd500, "DViCO FusionHDTV 5 Lite"),
++	BROOKTREE_878_DEVICE(0x7063, 0x2000, "pcHDTV HD-2000 TV"),
++	BROOKTREE_878_DEVICE(0x1822, 0x0026, "DNTV Live! Mini"),
++	{ }
  };
  
- /* Private data for file operations */
-@@ -690,7 +763,7 @@ void ipath_free_pddata(struct ipath_devdata *, struct ipath_portdata *);
++MODULE_DEVICE_TABLE(pci, bt878_pci_tbl);
++
++static const char * __devinit card_name(const struct pci_device_id *id)
++{
++	return id->driver_data ? (const char *)id->driver_data : "Unknown";
++}
  
- int ipath_parse_ushort(const char *str, unsigned short *valp);
+ /***********************/
+ /* PCI device handling */
+@@ -403,15 +417,13 @@ static struct cards card_list[] __devinitdata = {
+ static int __devinit bt878_probe(struct pci_dev *dev,
+ 				 const struct pci_device_id *pci_id)
+ {
+-	int result = 0, has_dvb = 0, i;
++	int result = 0;
+ 	unsigned char lat;
+ 	struct bt878 *bt;
+ #if defined(__powerpc__)
+ 	unsigned int cmd;
+ #endif
+ 	unsigned int cardid;
+-	unsigned short id;
+-	struct cards *dvb_cards;
  
--void ipath_kreceive(struct ipath_devdata *);
-+void ipath_kreceive(struct ipath_portdata *);
- int ipath_setrcvhdrsize(struct ipath_devdata *, unsigned);
- int ipath_reset_device(int);
- void ipath_get_faststats(unsigned long);
-@@ -698,6 +771,8 @@ int ipath_set_linkstate(struct ipath_devdata *, u8);
- int ipath_set_mtu(struct ipath_devdata *, u16);
- int ipath_set_lid(struct ipath_devdata *, u32, u8);
- int ipath_set_rx_pol_inv(struct ipath_devdata *dd, u8 new_pol_inv);
-+void ipath_enable_armlaunch(struct ipath_devdata *);
-+void ipath_disable_armlaunch(struct ipath_devdata *);
+ 	printk(KERN_INFO "bt878: Bt878 AUDIO function found (%d).\n",
+ 	       bt878_num);
+@@ -423,25 +435,11 @@ static int __devinit bt878_probe(struct pci_dev *dev,
+ 	if (pci_enable_device(dev))
+ 		return -EIO;
  
- /* for use in system calls, where we want to know device type, etc. */
- #define port_fp(fp) ((struct ipath_filedata *)(fp)->private_data)->pd
-@@ -744,9 +819,15 @@ int ipath_set_rx_pol_inv(struct ipath_devdata *dd, u8 new_pol_inv);
- 		 * are 64bit */
- #define IPATH_32BITCOUNTERS 0x20000
- 		/* can miss port0 rx interrupts */
-+		/* Interrupt register is 64 bits */
-+#define IPATH_INTREG_64     0x40000
- #define IPATH_DISABLED      0x80000 /* administratively disabled */
- 		/* Use GPIO interrupts for new counters */
- #define IPATH_GPIO_ERRINTRS 0x100000
-+#define IPATH_SWAP_PIOBUFS  0x200000
-+		/* Suppress heartbeat, even if turning off loopback */
-+#define IPATH_NO_HRTBT      0x1000000
-+#define IPATH_HAS_MULT_IB_SPEED 0x8000000
+-	pci_read_config_word(dev, PCI_SUBSYSTEM_ID, &id);
+-	cardid = id << 16;
+-	pci_read_config_word(dev, PCI_SUBSYSTEM_VENDOR_ID, &id);
+-	cardid |= id;
+-
+-	for (i = 0, dvb_cards = card_list; i < ARRAY_SIZE(card_list); i++, dvb_cards++) {
+-		if (cardid == dvb_cards->pci_id) {
+-			printk("%s: card id=[0x%x],[ %s ] has DVB functions.\n",
+-				__func__, cardid, dvb_cards->name);
+-			has_dvb = 1;
+-		}
+-	}
++	cardid = dev->subsystem_device << 16;
++	cardid |= dev->subsystem_vendor;
  
- /* Bits in GPIO for the added interrupts */
- #define IPATH_GPIO_PORT0_BIT 2
-@@ -758,8 +839,6 @@ int ipath_set_rx_pol_inv(struct ipath_devdata *dd, u8 new_pol_inv);
- /* portdata flag bit offsets */
- 		/* waiting for a packet to arrive */
- #define IPATH_PORT_WAITING_RCV   2
--		/* waiting for a PIO buffer to be available */
--#define IPATH_PORT_WAITING_PIO   3
- 		/* master has not finished initializing */
- #define IPATH_PORT_MASTER_UNINIT 4
- 		/* waiting for an urgent packet to arrive */
-@@ -767,8 +846,6 @@ int ipath_set_rx_pol_inv(struct ipath_devdata *dd, u8 new_pol_inv);
+-	if (!has_dvb) {
+-		printk("%s: card id=[0x%x], Unknown card.\nExiting..\n", __func__, cardid);
+-		result = -EINVAL;
+-
+-		goto fail0;
+-	}
++	printk(KERN_INFO "%s: card id=[0x%x],[ %s ] has DVB functions.\n",
++				__func__, cardid, card_name(pci_id));
  
- /* free up any allocated data at closes */
- void ipath_free_data(struct ipath_portdata *dd);
--int ipath_waitfor_mdio_cmdready(struct ipath_devdata *);
--int ipath_waitfor_complete(struct ipath_devdata *, ipath_kreg, u64, u64 *);
- u32 __iomem *ipath_getpiobuf(struct ipath_devdata *, u32 *);
- void ipath_init_iba6120_funcs(struct ipath_devdata *);
- void ipath_init_iba6110_funcs(struct ipath_devdata *);
-@@ -792,33 +869,6 @@ void ipath_set_led_override(struct ipath_devdata *dd, unsigned int val);
-  */
- #define IPATH_DFLT_RCVHDRSIZE 9
+ 	bt = &bt878[bt878_num];
+ 	bt->dev = dev;
+@@ -572,14 +570,6 @@ static void __devexit bt878_remove(struct pci_dev *pci_dev)
+ 	return;
+ }
  
--#define IPATH_MDIO_CMD_WRITE   1
--#define IPATH_MDIO_CMD_READ    2
--#define IPATH_MDIO_CLD_DIV     25	/* to get 2.5 Mhz mdio clock */
--#define IPATH_MDIO_CMDVALID    0x40000000	/* bit 30 */
--#define IPATH_MDIO_DATAVALID   0x80000000	/* bit 31 */
--#define IPATH_MDIO_CTRL_STD    0x0
--
--static inline u64 ipath_mdio_req(int cmd, int dev, int reg, int data)
--{
--	return (((u64) IPATH_MDIO_CLD_DIV) << 32) |
--		(cmd << 26) |
--		(dev << 21) |
--		(reg << 16) |
--		(data & 0xFFFF);
--}
+-static struct pci_device_id bt878_pci_tbl[] __devinitdata = {
+-	{PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BROOKTREE_878,
+-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+-	{0,}
+-};
 -
--		/* signal and fifo status, in bank 31 */
--#define IPATH_MDIO_CTRL_XGXS_REG_8  0x8
--		/* controls loopback, redundancy */
--#define IPATH_MDIO_CTRL_8355_REG_1  0x10
--		/* premph, encdec, etc. */
--#define IPATH_MDIO_CTRL_8355_REG_2  0x11
--		/* Kchars, etc. */
--#define IPATH_MDIO_CTRL_8355_REG_6  0x15
--#define IPATH_MDIO_CTRL_8355_REG_9  0x18
--#define IPATH_MDIO_CTRL_8355_REG_10 0x1D
+-MODULE_DEVICE_TABLE(pci, bt878_pci_tbl);
 -
- int ipath_get_user_pages(unsigned long, size_t, struct page **);
- void ipath_release_user_pages(struct page **, size_t);
- void ipath_release_user_pages_on_close(struct page **, size_t);
-@@ -863,7 +913,7 @@ static inline u32 ipath_read_ureg32(const struct ipath_devdata *dd,
- 	return readl(regno + (u64 __iomem *)
- 		     (dd->ipath_uregbase +
- 		      (char __iomem *)dd->ipath_kregbase +
--		      dd->ipath_palign * port));
-+		      dd->ipath_ureg_align * port));
- }
- 
- /**
-@@ -880,7 +930,7 @@ static inline void ipath_write_ureg(const struct ipath_devdata *dd,
- {
- 	u64 __iomem *ubase = (u64 __iomem *)
- 		(dd->ipath_uregbase + (char __iomem *) dd->ipath_kregbase +
--		 dd->ipath_palign * port);
-+		 dd->ipath_ureg_align * port);
- 	if (dd->ipath_kregbase)
- 		writeq(value, &ubase[regno]);
- }
-@@ -930,6 +980,53 @@ static inline u32 ipath_read_creg32(const struct ipath_devdata *dd,
- 		      (char __iomem *)dd->ipath_kregbase));
- }
+ static struct pci_driver bt878_pci_driver = {
+       .name	= "bt878",
+       .id_table = bt878_pci_tbl,
+diff --git a/drivers/media/dvb/bt8xx/bt878.h b/drivers/media/dvb/bt8xx/bt878.h
+index d593bc1..375fd28 100644
+--- a/drivers/media/dvb/bt8xx/bt878.h
++++ b/drivers/media/dvb/bt8xx/bt878.h
+@@ -101,12 +101,6 @@
+ #define BTTV_BOARD_DVICO_DVBT_LITE         0x80
+ #define BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE 0x87
  
-+static inline void ipath_write_creg(const struct ipath_devdata *dd,
-+				    ipath_creg regno, u64 value)
-+{
-+	if (dd->ipath_kregbase)
-+		writeq(value, regno + (u64 __iomem *)
-+		       (dd->ipath_cregbase +
-+			(char __iomem *)dd->ipath_kregbase));
-+}
-+
-+static inline void ipath_clear_rcvhdrtail(const struct ipath_portdata *pd)
-+{
-+	*((u64 *) pd->port_rcvhdrtail_kvaddr) = 0ULL;
-+}
-+
-+static inline u32 ipath_get_rcvhdrtail(const struct ipath_portdata *pd)
-+{
-+	return (u32) le64_to_cpu(*((volatile __le64 *)
-+				pd->port_rcvhdrtail_kvaddr));
-+}
-+
-+static inline u64 ipath_read_ireg(const struct ipath_devdata *dd, ipath_kreg r)
-+{
-+	return (dd->ipath_flags & IPATH_INTREG_64) ?
-+		ipath_read_kreg64(dd, r) : ipath_read_kreg32(dd, r);
-+}
-+
-+/*
-+ * from contents of IBCStatus (or a saved copy), return linkstate
-+ * Report ACTIVE_DEFER as ACTIVE, because we treat them the same
-+ * everywhere, anyway (and should be, for almost all purposes).
-+ */
-+static inline u32 ipath_ib_linkstate(struct ipath_devdata *dd, u64 ibcs)
-+{
-+	u32 state = (u32)(ibcs >> dd->ibcs_ls_shift) &
-+		INFINIPATH_IBCS_LINKSTATE_MASK;
-+	if (state == INFINIPATH_IBCS_L_STATE_ACT_DEFER)
-+		state = INFINIPATH_IBCS_L_STATE_ACTIVE;
-+	return state;
-+}
-+
-+/* from contents of IBCStatus (or a saved copy), return linktrainingstate */
-+static inline u32 ipath_ib_linktrstate(struct ipath_devdata *dd, u64 ibcs)
-+{
-+	return (u32)(ibcs >> INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT) &
-+		dd->ibcs_lts_mask;
-+}
-+
- /*
-  * sysfs interface.
-  */
-@@ -938,8 +1035,7 @@ struct device_driver;
+-struct cards {
+-	__u32 pci_id;
+-	__u16 card_id;
+-	char  *name;
+-};
+-
+ extern int bt878_num;
  
- extern const char ib_ipath_version[];
+ struct bt878 {
+diff --git a/drivers/media/dvb/bt8xx/dst.c b/drivers/media/dvb/bt8xx/dst.c
+index b7a17e6..307ff35 100644
+--- a/drivers/media/dvb/bt8xx/dst.c
++++ b/drivers/media/dvb/bt8xx/dst.c
+@@ -71,6 +71,7 @@ MODULE_PARM_DESC(dst_algo, "tuning algo: default is 0=(SW), 1=(HW)");
+ 	}								\
+ } while(0)
  
--int ipath_driver_create_group(struct device_driver *);
--void ipath_driver_remove_group(struct device_driver *);
-+extern struct attribute_group *ipath_driver_attr_groups[];
++static int dst_command(struct dst_state *state, u8 *data, u8 len);
  
- int ipath_device_create_group(struct device *, struct ipath_devdata *);
- void ipath_device_remove_group(struct device *, struct ipath_devdata *);
-diff --git a/drivers/infiniband/hw/ipath/ipath_keys.c b/drivers/infiniband/hw/ipath/ipath_keys.c
-index 85a4aef..8f32b17 100644
---- a/drivers/infiniband/hw/ipath/ipath_keys.c
-+++ b/drivers/infiniband/hw/ipath/ipath_keys.c
-@@ -128,9 +128,8 @@ int ipath_lkey_ok(struct ipath_qp *qp, struct ipath_sge *isge,
- 	int ret;
+ static void dst_packsize(struct dst_state *state, int psize)
+ {
+@@ -80,7 +81,8 @@ static void dst_packsize(struct dst_state *state, int psize)
+ 	bt878_device_control(state->bt, DST_IG_TS, &bits);
+ }
  
- 	/*
--	 * We use LKEY == zero to mean a physical kmalloc() address.
--	 * This is a bit of a hack since we rely on dma_map_single()
--	 * being reversible by calling bus_to_virt().
-+	 * We use LKEY == zero for kernel virtual addresses
-+	 * (see ipath_get_dma_mr and ipath_dma.c).
- 	 */
- 	if (sge->lkey == 0) {
- 		struct ipath_pd *pd = to_ipd(qp->ibqp.pd);
-diff --git a/drivers/infiniband/hw/ipath/ipath_mad.c b/drivers/infiniband/hw/ipath/ipath_mad.c
-index 3d1432d..d98d5f1 100644
---- a/drivers/infiniband/hw/ipath/ipath_mad.c
-+++ b/drivers/infiniband/hw/ipath/ipath_mad.c
-@@ -934,6 +934,7 @@ static int recv_pma_get_portsamplescontrol(struct ib_perf *pmp,
- 	struct ib_pma_portsamplescontrol *p =
- 		(struct ib_pma_portsamplescontrol *)pmp->data;
- 	struct ipath_ibdev *dev = to_idev(ibdev);
-+	struct ipath_cregs const *crp = dev->dd->ipath_cregs;
- 	unsigned long flags;
- 	u8 port_select = p->port_select;
+-int dst_gpio_outb(struct dst_state *state, u32 mask, u32 enbb, u32 outhigh, int delay)
++static int dst_gpio_outb(struct dst_state *state, u32 mask, u32 enbb,
++			 u32 outhigh, int delay)
+ {
+ 	union dst_gpio_packet enb;
+ 	union dst_gpio_packet bits;
+@@ -109,9 +111,8 @@ int dst_gpio_outb(struct dst_state *state, u32 mask, u32 enbb, u32 outhigh, int
  
-@@ -955,7 +956,10 @@ static int recv_pma_get_portsamplescontrol(struct ib_perf *pmp,
- 	p->counter_width = 4;	/* 32 bit counters */
- 	p->counter_mask0_9 = COUNTER_MASK0_9;
- 	spin_lock_irqsave(&dev->pending_lock, flags);
--	p->sample_status = dev->pma_sample_status;
-+	if (crp->cr_psstat)
-+		p->sample_status = ipath_read_creg32(dev->dd, crp->cr_psstat);
-+	else
-+		p->sample_status = dev->pma_sample_status;
- 	p->sample_start = cpu_to_be32(dev->pma_sample_start);
- 	p->sample_interval = cpu_to_be32(dev->pma_sample_interval);
- 	p->tag = cpu_to_be16(dev->pma_tag);
-@@ -975,8 +979,9 @@ static int recv_pma_set_portsamplescontrol(struct ib_perf *pmp,
- 	struct ib_pma_portsamplescontrol *p =
- 		(struct ib_pma_portsamplescontrol *)pmp->data;
- 	struct ipath_ibdev *dev = to_idev(ibdev);
-+	struct ipath_cregs const *crp = dev->dd->ipath_cregs;
- 	unsigned long flags;
--	u32 start;
-+	u8 status;
- 	int ret;
+ 	return 0;
+ }
+-EXPORT_SYMBOL(dst_gpio_outb);
  
- 	if (pmp->attr_mod != 0 ||
-@@ -986,59 +991,67 @@ static int recv_pma_set_portsamplescontrol(struct ib_perf *pmp,
- 		goto bail;
- 	}
+-int dst_gpio_inb(struct dst_state *state, u8 *result)
++static int dst_gpio_inb(struct dst_state *state, u8 *result)
+ {
+ 	union dst_gpio_packet rd_packet;
+ 	int err;
+@@ -125,7 +126,6 @@ int dst_gpio_inb(struct dst_state *state, u8 *result)
  
--	start = be32_to_cpu(p->sample_start);
--	if (start != 0) {
--		spin_lock_irqsave(&dev->pending_lock, flags);
--		if (dev->pma_sample_status == IB_PMA_SAMPLE_STATUS_DONE) {
--			dev->pma_sample_status =
--				IB_PMA_SAMPLE_STATUS_STARTED;
--			dev->pma_sample_start = start;
--			dev->pma_sample_interval =
--				be32_to_cpu(p->sample_interval);
--			dev->pma_tag = be16_to_cpu(p->tag);
--			if (p->counter_select[0])
--				dev->pma_counter_select[0] =
--					p->counter_select[0];
--			if (p->counter_select[1])
--				dev->pma_counter_select[1] =
--					p->counter_select[1];
--			if (p->counter_select[2])
--				dev->pma_counter_select[2] =
--					p->counter_select[2];
--			if (p->counter_select[3])
--				dev->pma_counter_select[3] =
--					p->counter_select[3];
--			if (p->counter_select[4])
--				dev->pma_counter_select[4] =
--					p->counter_select[4];
--		}
--		spin_unlock_irqrestore(&dev->pending_lock, flags);
-+	spin_lock_irqsave(&dev->pending_lock, flags);
-+	if (crp->cr_psstat)
-+		status = ipath_read_creg32(dev->dd, crp->cr_psstat);
-+	else
-+		status = dev->pma_sample_status;
-+	if (status == IB_PMA_SAMPLE_STATUS_DONE) {
-+		dev->pma_sample_start = be32_to_cpu(p->sample_start);
-+		dev->pma_sample_interval = be32_to_cpu(p->sample_interval);
-+		dev->pma_tag = be16_to_cpu(p->tag);
-+		dev->pma_counter_select[0] = p->counter_select[0];
-+		dev->pma_counter_select[1] = p->counter_select[1];
-+		dev->pma_counter_select[2] = p->counter_select[2];
-+		dev->pma_counter_select[3] = p->counter_select[3];
-+		dev->pma_counter_select[4] = p->counter_select[4];
-+		if (crp->cr_psstat) {
-+			ipath_write_creg(dev->dd, crp->cr_psinterval,
-+					 dev->pma_sample_interval);
-+			ipath_write_creg(dev->dd, crp->cr_psstart,
-+					 dev->pma_sample_start);
-+		} else
-+			dev->pma_sample_status = IB_PMA_SAMPLE_STATUS_STARTED;
- 	}
-+	spin_unlock_irqrestore(&dev->pending_lock, flags);
-+
- 	ret = recv_pma_get_portsamplescontrol(pmp, ibdev, port);
+ 	return 0;
+ }
+-EXPORT_SYMBOL(dst_gpio_inb);
  
- bail:
- 	return ret;
+ int rdc_reset_state(struct dst_state *state)
+ {
+@@ -145,7 +145,7 @@ int rdc_reset_state(struct dst_state *state)
  }
+ EXPORT_SYMBOL(rdc_reset_state);
  
--static u64 get_counter(struct ipath_ibdev *dev, __be16 sel)
-+static u64 get_counter(struct ipath_ibdev *dev,
-+		       struct ipath_cregs const *crp,
-+		       __be16 sel)
+-int rdc_8820_reset(struct dst_state *state)
++static int rdc_8820_reset(struct dst_state *state)
  {
- 	u64 ret;
+ 	dprintk(verbose, DST_DEBUG, 1, "Resetting DST");
+ 	if (dst_gpio_outb(state, RDC_8820_RESET, RDC_8820_RESET, 0, NO_DELAY) < 0) {
+@@ -160,9 +160,8 @@ int rdc_8820_reset(struct dst_state *state)
  
- 	switch (sel) {
- 	case IB_PMA_PORT_XMIT_DATA:
--		ret = dev->ipath_sword;
-+		ret = (crp->cr_psxmitdatacount) ?
-+			ipath_read_creg32(dev->dd, crp->cr_psxmitdatacount) :
-+			dev->ipath_sword;
- 		break;
- 	case IB_PMA_PORT_RCV_DATA:
--		ret = dev->ipath_rword;
-+		ret = (crp->cr_psrcvdatacount) ?
-+			ipath_read_creg32(dev->dd, crp->cr_psrcvdatacount) :
-+			dev->ipath_rword;
- 		break;
- 	case IB_PMA_PORT_XMIT_PKTS:
--		ret = dev->ipath_spkts;
-+		ret = (crp->cr_psxmitpktscount) ?
-+			ipath_read_creg32(dev->dd, crp->cr_psxmitpktscount) :
-+			dev->ipath_spkts;
- 		break;
- 	case IB_PMA_PORT_RCV_PKTS:
--		ret = dev->ipath_rpkts;
-+		ret = (crp->cr_psrcvpktscount) ?
-+			ipath_read_creg32(dev->dd, crp->cr_psrcvpktscount) :
-+			dev->ipath_rpkts;
- 		break;
- 	case IB_PMA_PORT_XMIT_WAIT:
--		ret = dev->ipath_xmit_wait;
-+		ret = (crp->cr_psxmitwaitcount) ?
-+			ipath_read_creg32(dev->dd, crp->cr_psxmitwaitcount) :
-+			dev->ipath_xmit_wait;
- 		break;
- 	default:
- 		ret = 0;
-@@ -1053,14 +1066,21 @@ static int recv_pma_get_portsamplesresult(struct ib_perf *pmp,
- 	struct ib_pma_portsamplesresult *p =
- 		(struct ib_pma_portsamplesresult *)pmp->data;
- 	struct ipath_ibdev *dev = to_idev(ibdev);
-+	struct ipath_cregs const *crp = dev->dd->ipath_cregs;
-+	u8 status;
- 	int i;
+ 	return 0;
+ }
+-EXPORT_SYMBOL(rdc_8820_reset);
  
- 	memset(pmp->data, 0, sizeof(pmp->data));
- 	p->tag = cpu_to_be16(dev->pma_tag);
--	p->sample_status = cpu_to_be16(dev->pma_sample_status);
-+	if (crp->cr_psstat)
-+		status = ipath_read_creg32(dev->dd, crp->cr_psstat);
-+	else
-+		status = dev->pma_sample_status;
-+	p->sample_status = cpu_to_be16(status);
- 	for (i = 0; i < ARRAY_SIZE(dev->pma_counter_select); i++)
--		p->counter[i] = cpu_to_be32(
--			get_counter(dev, dev->pma_counter_select[i]));
-+		p->counter[i] = (status != IB_PMA_SAMPLE_STATUS_DONE) ? 0 :
-+		    cpu_to_be32(
-+			get_counter(dev, crp, dev->pma_counter_select[i]));
+-int dst_pio_enable(struct dst_state *state)
++static int dst_pio_enable(struct dst_state *state)
+ {
+ 	if (dst_gpio_outb(state, ~0, RDC_8820_PIO_0_ENABLE, 0, NO_DELAY) < 0) {
+ 		dprintk(verbose, DST_ERROR, 1, "dst_gpio_outb ERROR !");
+@@ -172,7 +171,6 @@ int dst_pio_enable(struct dst_state *state)
  
- 	return reply((struct ib_smp *) pmp);
+ 	return 0;
  }
-@@ -1071,16 +1091,23 @@ static int recv_pma_get_portsamplesresult_ext(struct ib_perf *pmp,
- 	struct ib_pma_portsamplesresult_ext *p =
- 		(struct ib_pma_portsamplesresult_ext *)pmp->data;
- 	struct ipath_ibdev *dev = to_idev(ibdev);
-+	struct ipath_cregs const *crp = dev->dd->ipath_cregs;
-+	u8 status;
- 	int i;
+-EXPORT_SYMBOL(dst_pio_enable);
  
- 	memset(pmp->data, 0, sizeof(pmp->data));
- 	p->tag = cpu_to_be16(dev->pma_tag);
--	p->sample_status = cpu_to_be16(dev->pma_sample_status);
-+	if (crp->cr_psstat)
-+		status = ipath_read_creg32(dev->dd, crp->cr_psstat);
-+	else
-+		status = dev->pma_sample_status;
-+	p->sample_status = cpu_to_be16(status);
- 	/* 64 bits */
- 	p->extended_width = __constant_cpu_to_be32(0x80000000);
- 	for (i = 0; i < ARRAY_SIZE(dev->pma_counter_select); i++)
--		p->counter[i] = cpu_to_be64(
--			get_counter(dev, dev->pma_counter_select[i]));
-+		p->counter[i] = (status != IB_PMA_SAMPLE_STATUS_DONE) ? 0 :
-+		    cpu_to_be64(
-+			get_counter(dev, crp, dev->pma_counter_select[i]));
+ int dst_pio_disable(struct dst_state *state)
+ {
+@@ -611,7 +609,7 @@ static int dst_type_print(struct dst_state *state, u8 type)
+ 	return 0;
+ }
  
- 	return reply((struct ib_smp *) pmp);
+-struct tuner_types tuner_list[] = {
++static struct tuner_types tuner_list[] = {
+ 	{
+ 		.tuner_type = TUNER_TYPE_L64724,
+ 		.tuner_name = "L 64724",
+@@ -1224,7 +1222,7 @@ static int dst_probe(struct dst_state *state)
+ 	return 0;
  }
-@@ -1113,6 +1140,8 @@ static int recv_pma_get_portcounters(struct ib_perf *pmp,
- 		dev->z_local_link_integrity_errors;
- 	cntrs.excessive_buffer_overrun_errors -=
- 		dev->z_excessive_buffer_overrun_errors;
-+	cntrs.vl15_dropped -= dev->z_vl15_dropped;
-+	cntrs.vl15_dropped += dev->n_vl15_dropped;
  
- 	memset(pmp->data, 0, sizeof(pmp->data));
+-int dst_command(struct dst_state *state, u8 *data, u8 len)
++static int dst_command(struct dst_state *state, u8 *data, u8 len)
+ {
+ 	u8 reply;
  
-@@ -1156,10 +1185,10 @@ static int recv_pma_get_portcounters(struct ib_perf *pmp,
- 		cntrs.excessive_buffer_overrun_errors = 0xFUL;
- 	p->lli_ebor_errors = (cntrs.local_link_integrity_errors << 4) |
- 		cntrs.excessive_buffer_overrun_errors;
--	if (dev->n_vl15_dropped > 0xFFFFUL)
-+	if (cntrs.vl15_dropped > 0xFFFFUL)
- 		p->vl15_dropped = __constant_cpu_to_be16(0xFFFF);
- 	else
--		p->vl15_dropped = cpu_to_be16((u16)dev->n_vl15_dropped);
-+		p->vl15_dropped = cpu_to_be16((u16)cntrs.vl15_dropped);
- 	if (cntrs.port_xmit_data > 0xFFFFFFFFUL)
- 		p->port_xmit_data = __constant_cpu_to_be32(0xFFFFFFFF);
- 	else
-@@ -1262,8 +1291,10 @@ static int recv_pma_set_portcounters(struct ib_perf *pmp,
- 		dev->z_excessive_buffer_overrun_errors =
- 			cntrs.excessive_buffer_overrun_errors;
+@@ -1287,7 +1285,6 @@ error:
+ 	return -EIO;
  
--	if (p->counter_select & IB_PMA_SEL_PORT_VL15_DROPPED)
-+	if (p->counter_select & IB_PMA_SEL_PORT_VL15_DROPPED) {
- 		dev->n_vl15_dropped = 0;
-+		dev->z_vl15_dropped = cntrs.vl15_dropped;
-+	}
+ }
+-EXPORT_SYMBOL(dst_command);
  
- 	if (p->counter_select & IB_PMA_SEL_PORT_XMIT_DATA)
- 		dev->z_port_xmit_data = cntrs.port_xmit_data;
-@@ -1434,7 +1465,7 @@ static int process_subn(struct ib_device *ibdev, int mad_flags,
- 		 * before checking for other consumers.
- 		 * Just tell the caller to process it normally.
- 		 */
--		ret = IB_MAD_RESULT_FAILURE;
-+		ret = IB_MAD_RESULT_SUCCESS;
- 		goto bail;
- 	default:
- 		smp->status |= IB_SMP_UNSUP_METHOD;
-@@ -1516,7 +1547,7 @@ static int process_perf(struct ib_device *ibdev, u8 port_num,
- 		 * before checking for other consumers.
- 		 * Just tell the caller to process it normally.
- 		 */
--		ret = IB_MAD_RESULT_FAILURE;
-+		ret = IB_MAD_RESULT_SUCCESS;
- 		goto bail;
- 	default:
- 		pmp->status |= IB_SMP_UNSUP_METHOD;
-diff --git a/drivers/infiniband/hw/ipath/ipath_qp.c b/drivers/infiniband/hw/ipath/ipath_qp.c
-index b997ff8..80dc623 100644
---- a/drivers/infiniband/hw/ipath/ipath_qp.c
-+++ b/drivers/infiniband/hw/ipath/ipath_qp.c
-@@ -387,8 +387,8 @@ int ipath_error_qp(struct ipath_qp *qp, enum ib_wc_status err)
- 	struct ib_wc wc;
- 	int ret = 0;
+ static int dst_get_signal(struct dst_state *state)
+ {
+diff --git a/drivers/media/dvb/bt8xx/dst_common.h b/drivers/media/dvb/bt8xx/dst_common.h
+index 87623d2..d88cf2a 100644
+--- a/drivers/media/dvb/bt8xx/dst_common.h
++++ b/drivers/media/dvb/bt8xx/dst_common.h
+@@ -165,10 +165,8 @@ struct dst_config
+ };
  
--	ipath_dbg("QP%d/%d in error state\n",
--		  qp->ibqp.qp_num, qp->remote_qpn);
-+	ipath_dbg("QP%d/%d in error state (%d)\n",
-+		  qp->ibqp.qp_num, qp->remote_qpn, err);
+ int rdc_reset_state(struct dst_state *state);
+-int rdc_8820_reset(struct dst_state *state);
  
- 	spin_lock(&dev->pending_lock);
- 	/* XXX What if its already removed by the timeout code? */
-@@ -855,8 +855,6 @@ struct ib_qp *ipath_create_qp(struct ib_pd *ibpd,
- 	 * See ipath_mmap() for details.
- 	 */
- 	if (udata && udata->outlen >= sizeof(__u64)) {
--		int err;
+ int dst_wait_dst_ready(struct dst_state *state, u8 delay_mode);
+-int dst_pio_enable(struct dst_state *state);
+ int dst_pio_disable(struct dst_state *state);
+ int dst_error_recovery(struct dst_state* state);
+ int dst_error_bailout(struct dst_state *state);
+@@ -179,9 +177,6 @@ int read_dst(struct dst_state *state, u8 * ret, u8 len);
+ u8 dst_check_sum(u8 * buf, u32 len);
+ struct dst_state* dst_attach(struct dst_state* state, struct dvb_adapter *dvb_adapter);
+ struct dvb_device *dst_ca_attach(struct dst_state *state, struct dvb_adapter *dvb_adapter);
+-int dst_gpio_outb(struct dst_state* state, u32 mask, u32 enbb, u32 outhigh, int delay);
 -
- 		if (!qp->r_rq.wq) {
- 			__u64 offset = 0;
- 
-diff --git a/drivers/infiniband/hw/ipath/ipath_rc.c b/drivers/infiniband/hw/ipath/ipath_rc.c
-index 120a61b..459e46e 100644
---- a/drivers/infiniband/hw/ipath/ipath_rc.c
-+++ b/drivers/infiniband/hw/ipath/ipath_rc.c
-@@ -647,6 +647,7 @@ static void send_rc_ack(struct ipath_qp *qp)
+-int dst_command(struct dst_state* state, u8 * data, u8 len);
  
- queue_ack:
- 	spin_lock_irqsave(&qp->s_lock, flags);
-+	dev->n_rc_qacks++;
- 	qp->s_flags |= IPATH_S_ACK_PENDING;
- 	qp->s_nak_state = qp->r_nak_state;
- 	qp->s_ack_psn = qp->r_ack_psn;
-@@ -798,11 +799,13 @@ bail:
  
- static inline void update_last_psn(struct ipath_qp *qp, u32 psn)
- {
--	if (qp->s_wait_credit) {
--		qp->s_wait_credit = 0;
--		tasklet_hi_schedule(&qp->s_task);
-+	if (qp->s_last_psn != psn) {
-+		qp->s_last_psn = psn;
-+		if (qp->s_wait_credit) {
-+			qp->s_wait_credit = 0;
-+			tasklet_hi_schedule(&qp->s_task);
-+		}
+ #endif // DST_COMMON_H
+diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c
+index 445f026..925cfa6 100644
+--- a/drivers/media/dvb/dvb-core/dvb_frontend.c
++++ b/drivers/media/dvb/dvb-core/dvb_frontend.c
+@@ -1202,6 +1202,10 @@ void dvb_frontend_detach(struct dvb_frontend* fe)
+ 		fe->ops.tuner_ops.release(fe);
+ 		symbol_put_addr(fe->ops.tuner_ops.release);
  	}
--	qp->s_last_psn = psn;
++	if (fe->ops.analog_ops.release) {
++		fe->ops.analog_ops.release(fe);
++		symbol_put_addr(fe->ops.analog_ops.release);
++	}
+ 	ptr = (void*)fe->ops.release;
+ 	if (ptr) {
+ 		fe->ops.release(fe);
+@@ -1215,6 +1219,8 @@ void dvb_frontend_detach(struct dvb_frontend* fe)
+ 		fe->ops.release_sec(fe);
+ 	if (fe->ops.tuner_ops.release)
+ 		fe->ops.tuner_ops.release(fe);
++	if (fe->ops.analog_ops.release)
++		fe->ops.analog_ops.release(fe);
+ 	if (fe->ops.release)
+ 		fe->ops.release(fe);
  }
+diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.h b/drivers/media/dvb/dvb-core/dvb_frontend.h
+index a5262e8..aa4133f 100644
+--- a/drivers/media/dvb/dvb-core/dvb_frontend.h
++++ b/drivers/media/dvb/dvb-core/dvb_frontend.h
+@@ -84,6 +84,9 @@ struct dvb_tuner_ops {
+ 	/** This is support for demods like the mt352 - fills out the supplied buffer with what to write. */
+ 	int (*calc_regs)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p, u8 *buf, int buf_len);
  
- /**
-@@ -1653,13 +1656,6 @@ void ipath_rc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
- 	case OP(SEND_FIRST):
- 		if (!ipath_get_rwqe(qp, 0)) {
- 		rnr_nak:
--			/*
--			 * A RNR NAK will ACK earlier sends and RDMA writes.
--			 * Don't queue the NAK if a RDMA read or atomic
--			 * is pending though.
--			 */
--			if (qp->r_nak_state)
--				goto done;
- 			qp->r_nak_state = IB_RNR_NAK | qp->r_min_rnr_timer;
- 			qp->r_ack_psn = qp->r_psn;
- 			goto send_ack;
-diff --git a/drivers/infiniband/hw/ipath/ipath_registers.h b/drivers/infiniband/hw/ipath/ipath_registers.h
-index 708eba3..6d2a17f 100644
---- a/drivers/infiniband/hw/ipath/ipath_registers.h
-+++ b/drivers/infiniband/hw/ipath/ipath_registers.h
-@@ -82,8 +82,7 @@
++	/** This is to allow setting tuner-specific configs */
++	int (*set_config)(struct dvb_frontend *fe, void *priv_cfg);
++
+ 	int (*get_frequency)(struct dvb_frontend *fe, u32 *frequency);
+ 	int (*get_bandwidth)(struct dvb_frontend *fe, u32 *bandwidth);
  
- /* kr_rcvctrl bits */
- #define INFINIPATH_R_PORTENABLE_SHIFT 0
--#define INFINIPATH_R_INTRAVAIL_SHIFT 16
--#define INFINIPATH_R_TAILUPD   0x80000000
-+#define INFINIPATH_R_QPMAP_ENABLE (1ULL << 38)
+@@ -98,6 +101,28 @@ struct dvb_tuner_ops {
+ 	int (*set_bandwidth)(struct dvb_frontend *fe, u32 bandwidth);
+ };
  
- /* kr_intstatus, kr_intclear, kr_intmask bits */
- #define INFINIPATH_I_RCVURG_SHIFT 0
-@@ -272,20 +271,6 @@
- #define INFINIPATH_EXTC_LEDGBLOK_ON          0x00000002ULL
- #define INFINIPATH_EXTC_LEDGBLERR_OFF        0x00000001ULL
++struct analog_demod_info {
++	char *name;
++};
++
++struct analog_demod_ops {
++
++	struct analog_demod_info info;
++
++	void (*set_params)(struct dvb_frontend *fe,
++			   struct analog_parameters *params);
++	int  (*has_signal)(struct dvb_frontend *fe);
++	int  (*is_stereo)(struct dvb_frontend *fe);
++	int  (*get_afc)(struct dvb_frontend *fe);
++	void (*tuner_status)(struct dvb_frontend *fe);
++	void (*standby)(struct dvb_frontend *fe);
++	void (*release)(struct dvb_frontend *fe);
++	int  (*i2c_gate_ctrl)(struct dvb_frontend *fe, int enable);
++
++	/** This is to allow setting tuner-specific configuration */
++	int (*set_config)(struct dvb_frontend *fe, void *priv_cfg);
++};
++
+ struct dvb_frontend_ops {
  
--/* kr_mdio bits */
--#define INFINIPATH_MDIO_CLKDIV_MASK 0x7FULL
--#define INFINIPATH_MDIO_CLKDIV_SHIFT 32
--#define INFINIPATH_MDIO_COMMAND_MASK 0x7ULL
--#define INFINIPATH_MDIO_COMMAND_SHIFT 26
--#define INFINIPATH_MDIO_DEVADDR_MASK 0x1FULL
--#define INFINIPATH_MDIO_DEVADDR_SHIFT 21
--#define INFINIPATH_MDIO_REGADDR_MASK 0x1FULL
--#define INFINIPATH_MDIO_REGADDR_SHIFT 16
--#define INFINIPATH_MDIO_DATA_MASK 0xFFFFULL
--#define INFINIPATH_MDIO_DATA_SHIFT 0
--#define INFINIPATH_MDIO_CMDVALID    0x0000000040000000ULL
--#define INFINIPATH_MDIO_RDDATAVALID 0x0000000080000000ULL
--
- /* kr_partitionkey bits */
- #define INFINIPATH_PKEY_SIZE 16
- #define INFINIPATH_PKEY_MASK 0xFFFF
-@@ -303,8 +288,6 @@
+ 	struct dvb_frontend_info info;
+@@ -143,6 +168,7 @@ struct dvb_frontend_ops {
+ 	int (*ts_bus_ctrl)(struct dvb_frontend* fe, int acquire);
  
- /* kr_xgxsconfig bits */
- #define INFINIPATH_XGXS_RESET          0x7ULL
--#define INFINIPATH_XGXS_MDIOADDR_MASK  0xfULL
--#define INFINIPATH_XGXS_MDIOADDR_SHIFT 4
- #define INFINIPATH_XGXS_RX_POL_SHIFT 19
- #define INFINIPATH_XGXS_RX_POL_MASK 0xfULL
+ 	struct dvb_tuner_ops tuner_ops;
++	struct analog_demod_ops analog_ops;
+ };
  
-@@ -470,6 +453,20 @@ struct ipath_cregs {
- 	ipath_creg cr_unsupvlcnt;
- 	ipath_creg cr_wordrcvcnt;
- 	ipath_creg cr_wordsendcnt;
-+	ipath_creg cr_vl15droppedpktcnt;
-+	ipath_creg cr_rxotherlocalphyerrcnt;
-+	ipath_creg cr_excessbufferovflcnt;
-+	ipath_creg cr_locallinkintegrityerrcnt;
-+	ipath_creg cr_rxvlerrcnt;
-+	ipath_creg cr_rxdlidfltrcnt;
-+	ipath_creg cr_psstat;
-+	ipath_creg cr_psstart;
-+	ipath_creg cr_psinterval;
-+	ipath_creg cr_psrcvdatacount;
-+	ipath_creg cr_psrcvpktscount;
-+	ipath_creg cr_psxmitdatacount;
-+	ipath_creg cr_psxmitpktscount;
-+	ipath_creg cr_psxmitwaitcount;
+ #define MAX_EVENT 8
+@@ -159,18 +185,19 @@ struct dvb_fe_events {
+ struct dvb_frontend {
+ 	struct dvb_frontend_ops ops;
+ 	struct dvb_adapter *dvb;
+-	void* demodulator_priv;
+-	void* tuner_priv;
+-	void* frontend_priv;
+-	void* sec_priv;
++	void *demodulator_priv;
++	void *tuner_priv;
++	void *frontend_priv;
++	void *sec_priv;
++	void *analog_demod_priv;
  };
  
- #endif				/* _IPATH_REGISTERS_H */
-diff --git a/drivers/infiniband/hw/ipath/ipath_ruc.c b/drivers/infiniband/hw/ipath/ipath_ruc.c
-index 54c61a9..a59bdbd 100644
---- a/drivers/infiniband/hw/ipath/ipath_ruc.c
-+++ b/drivers/infiniband/hw/ipath/ipath_ruc.c
-@@ -98,11 +98,15 @@ void ipath_insert_rnr_queue(struct ipath_qp *qp)
- 		while (qp->s_rnr_timeout >= nqp->s_rnr_timeout) {
- 			qp->s_rnr_timeout -= nqp->s_rnr_timeout;
- 			l = l->next;
--			if (l->next == &dev->rnrwait)
-+			if (l->next == &dev->rnrwait) {
-+				nqp = NULL;
- 				break;
-+			}
- 			nqp = list_entry(l->next, struct ipath_qp,
- 					 timerwait);
- 		}
-+		if (nqp)
-+			nqp->s_rnr_timeout -= qp->s_rnr_timeout;
- 		list_add(&qp->timerwait, l);
- 	}
- 	spin_unlock_irqrestore(&dev->pending_lock, flags);
-@@ -479,9 +483,14 @@ done:
+-extern int dvb_register_frontend(struct dvb_adapter* dvb,
+-				 struct dvb_frontend* fe);
++extern int dvb_register_frontend(struct dvb_adapter *dvb,
++				 struct dvb_frontend *fe);
  
- static void want_buffer(struct ipath_devdata *dd)
- {
--	set_bit(IPATH_S_PIOINTBUFAVAIL, &dd->ipath_sendctrl);
-+	unsigned long flags;
-+
-+	spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags);
-+	dd->ipath_sendctrl |= INFINIPATH_S_PIOINTBUFAVAIL;
- 	ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
- 			 dd->ipath_sendctrl);
-+	ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
-+	spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags);
- }
+-extern int dvb_unregister_frontend(struct dvb_frontend* fe);
++extern int dvb_unregister_frontend(struct dvb_frontend *fe);
  
- /**
-diff --git a/drivers/infiniband/hw/ipath/ipath_srq.c b/drivers/infiniband/hw/ipath/ipath_srq.c
-index 2fef36f..f772102 100644
---- a/drivers/infiniband/hw/ipath/ipath_srq.c
-+++ b/drivers/infiniband/hw/ipath/ipath_srq.c
-@@ -94,8 +94,8 @@ bail:
- /**
-  * ipath_create_srq - create a shared receive queue
-  * @ibpd: the protection domain of the SRQ to create
-- * @attr: the attributes of the SRQ
-- * @udata: not used by the InfiniPath verbs driver
-+ * @srq_init_attr: the attributes of the SRQ
-+ * @udata: data from libipathverbs when creating a user SRQ
-  */
- struct ib_srq *ipath_create_srq(struct ib_pd *ibpd,
- 				struct ib_srq_init_attr *srq_init_attr,
-diff --git a/drivers/infiniband/hw/ipath/ipath_stats.c b/drivers/infiniband/hw/ipath/ipath_stats.c
-index f027141..d2725cd 100644
---- a/drivers/infiniband/hw/ipath/ipath_stats.c
-+++ b/drivers/infiniband/hw/ipath/ipath_stats.c
-@@ -133,15 +133,16 @@ bail:
- static void ipath_qcheck(struct ipath_devdata *dd)
- {
- 	static u64 last_tot_hdrqfull;
-+	struct ipath_portdata *pd = dd->ipath_pd[0];
- 	size_t blen = 0;
- 	char buf[128];
+-extern void dvb_frontend_detach(struct dvb_frontend* fe);
++extern void dvb_frontend_detach(struct dvb_frontend *fe);
  
- 	*buf = 0;
--	if (dd->ipath_pd[0]->port_hdrqfull != dd->ipath_p0_hdrqfull) {
-+	if (pd->port_hdrqfull != dd->ipath_p0_hdrqfull) {
- 		blen = snprintf(buf, sizeof buf, "port 0 hdrqfull %u",
--				dd->ipath_pd[0]->port_hdrqfull -
-+				pd->port_hdrqfull -
- 				dd->ipath_p0_hdrqfull);
--		dd->ipath_p0_hdrqfull = dd->ipath_pd[0]->port_hdrqfull;
-+		dd->ipath_p0_hdrqfull = pd->port_hdrqfull;
- 	}
- 	if (ipath_stats.sps_etidfull != dd->ipath_last_tidfull) {
- 		blen += snprintf(buf + blen, sizeof buf - blen,
-@@ -173,7 +174,7 @@ static void ipath_qcheck(struct ipath_devdata *dd)
- 	if (blen)
- 		ipath_dbg("%s\n", buf);
+ extern void dvb_frontend_reinitialise(struct dvb_frontend *fe);
  
--	if (dd->ipath_port0head != (u32)
-+	if (pd->port_head != (u32)
- 	    le64_to_cpu(*dd->ipath_hdrqtailptr)) {
- 		if (dd->ipath_lastport0rcv_cnt ==
- 		    ipath_stats.sps_port0pkts) {
-@@ -181,7 +182,7 @@ static void ipath_qcheck(struct ipath_devdata *dd)
- 				   "port0 hd=%llx tl=%x; port0pkts %llx\n",
- 				   (unsigned long long)
- 				   le64_to_cpu(*dd->ipath_hdrqtailptr),
--				   dd->ipath_port0head,
-+				   pd->port_head,
- 				   (unsigned long long)
- 				   ipath_stats.sps_port0pkts);
- 		}
-@@ -237,7 +238,7 @@ static void ipath_chk_errormask(struct ipath_devdata *dd)
- void ipath_get_faststats(unsigned long opaque)
- {
- 	struct ipath_devdata *dd = (struct ipath_devdata *) opaque;
--	u32 val;
-+	int i;
- 	static unsigned cnt;
- 	unsigned long flags;
- 	u64 traffic_wds;
-@@ -321,12 +322,11 @@ void ipath_get_faststats(unsigned long opaque)
+diff --git a/drivers/media/dvb/dvb-core/dvb_ringbuffer.c b/drivers/media/dvb/dvb-core/dvb_ringbuffer.c
+index 9878183..ac9d93c 100644
+--- a/drivers/media/dvb/dvb-core/dvb_ringbuffer.c
++++ b/drivers/media/dvb/dvb-core/dvb_ringbuffer.c
+@@ -261,11 +261,6 @@ EXPORT_SYMBOL(dvb_ringbuffer_init);
+ EXPORT_SYMBOL(dvb_ringbuffer_empty);
+ EXPORT_SYMBOL(dvb_ringbuffer_free);
+ EXPORT_SYMBOL(dvb_ringbuffer_avail);
+-EXPORT_SYMBOL(dvb_ringbuffer_flush);
+ EXPORT_SYMBOL(dvb_ringbuffer_flush_spinlock_wakeup);
+ EXPORT_SYMBOL(dvb_ringbuffer_read);
+ EXPORT_SYMBOL(dvb_ringbuffer_write);
+-EXPORT_SYMBOL(dvb_ringbuffer_pkt_write);
+-EXPORT_SYMBOL(dvb_ringbuffer_pkt_read);
+-EXPORT_SYMBOL(dvb_ringbuffer_pkt_dispose);
+-EXPORT_SYMBOL(dvb_ringbuffer_pkt_next);
+diff --git a/drivers/media/dvb/dvb-usb/af9005.c b/drivers/media/dvb/dvb-usb/af9005.c
+index 7db6eee..e7f76f5 100644
+--- a/drivers/media/dvb/dvb-usb/af9005.c
++++ b/drivers/media/dvb/dvb-usb/af9005.c
+@@ -1026,6 +1026,7 @@ static int af9005_usb_probe(struct usb_interface *intf,
+ static struct usb_device_id af9005_usb_table[] = {
+ 	{USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9005)},
+ 	{USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_USB_XE)},
++	{USB_DEVICE(USB_VID_ANSONIC, USB_PID_ANSONIC_DVBT_USB)},
+ 	{0},
+ };
  
- 	/* limit qfull messages to ~one per minute per port */
- 	if ((++cnt & 0x10)) {
--		for (val = dd->ipath_cfgports - 1; ((int)val) >= 0;
--		     val--) {
--			if (dd->ipath_lastegrheads[val] != -1)
--				dd->ipath_lastegrheads[val] = -1;
--			if (dd->ipath_lastrcvhdrqtails[val] != -1)
--				dd->ipath_lastrcvhdrqtails[val] = -1;
-+		for (i = (int) dd->ipath_cfgports; --i >= 0; ) {
-+			struct ipath_portdata *pd = dd->ipath_pd[i];
+@@ -1075,7 +1076,7 @@ static struct dvb_usb_device_properties af9005_properties = {
+ 	.rc_key_map_size = 0,
+ 	.rc_query = af9005_rc_query,
+ 
+-	.num_device_descs = 2,
++	.num_device_descs = 3,
+ 	.devices = {
+ 		    {.name = "Afatech DVB-T USB1.1 stick",
+ 		     .cold_ids = {&af9005_usb_table[0], NULL},
+@@ -1085,6 +1086,10 @@ static struct dvb_usb_device_properties af9005_properties = {
+ 		     .cold_ids = {&af9005_usb_table[1], NULL},
+ 		     .warm_ids = {NULL},
+ 		     },
++		    {.name = "Ansonic DVB-T USB1.1 stick",
++		     .cold_ids = {&af9005_usb_table[2], NULL},
++		     .warm_ids = {NULL},
++		     },
+ 		    {NULL},
+ 		    }
+ };
+diff --git a/drivers/media/dvb/dvb-usb/au6610.c b/drivers/media/dvb/dvb-usb/au6610.c
+index 18e0b16..f3ff813 100644
+--- a/drivers/media/dvb/dvb-usb/au6610.c
++++ b/drivers/media/dvb/dvb-usb/au6610.c
+@@ -79,12 +79,12 @@ static int au6610_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
+ 	struct dvb_usb_device *d = i2c_get_adapdata(adap);
+ 	int i;
+ 
+-	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+-		return -EAGAIN;
+-
+ 	if (num > 2)
+ 		return -EINVAL;
+ 
++	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
++		return -EAGAIN;
 +
-+			if (pd && pd->port_lastrcvhdrqtail != -1)
-+				pd->port_lastrcvhdrqtail = -1;
- 		}
- 	}
+ 	for (i = 0; i < num; i++) {
+ 		/* write/read request */
+ 		if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) {
+diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/dvb/dvb-usb/cxusb.c
+index 04e31cf..c583650 100644
+--- a/drivers/media/dvb/dvb-usb/cxusb.c
++++ b/drivers/media/dvb/dvb-usb/cxusb.c
+@@ -15,7 +15,7 @@
+  *
+  * Copyright (C) 2005 Patrick Boettcher (patrick.boettcher at desy.de)
+  * Copyright (C) 2006 Michael Krufky (mkrufky at linuxtv.org)
+- * Copyright (C) 2006 Chris Pascoe (c.pascoe at itee.uq.edu.au)
++ * Copyright (C) 2006, 2007 Chris Pascoe (c.pascoe at itee.uq.edu.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
+@@ -30,11 +30,16 @@
+ #include "mt352.h"
+ #include "mt352_priv.h"
+ #include "zl10353.h"
++#include "tuner-xc2028.h"
++#include "tuner-xc2028-types.h"
  
-diff --git a/drivers/infiniband/hw/ipath/ipath_sysfs.c b/drivers/infiniband/hw/ipath/ipath_sysfs.c
-index e1ad7cf..56dfc8a 100644
---- a/drivers/infiniband/hw/ipath/ipath_sysfs.c
-+++ b/drivers/infiniband/hw/ipath/ipath_sysfs.c
-@@ -363,6 +363,60 @@ static ssize_t show_unit(struct device *dev,
- 	return scnprintf(buf, PAGE_SIZE, "%u\n", dd->ipath_unit);
+ /* debug */
+-int dvb_usb_cxusb_debug;
++static int dvb_usb_cxusb_debug;
+ module_param_named(debug, dvb_usb_cxusb_debug, int, 0644);
+ MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS);
++#define deb_info(args...)   dprintk(dvb_usb_cxusb_debug,0x01,args)
++#define deb_i2c(args...)    if (d->udev->descriptor.idVendor == USB_VID_MEDION) \
++				dprintk(dvb_usb_cxusb_debug,0x01,args)
+ 
+ static int cxusb_ctrl_msg(struct dvb_usb_device *d,
+ 			  u8 cmd, u8 *wbuf, int wlen, u8 *rbuf, int rlen)
+@@ -46,11 +51,9 @@ static int cxusb_ctrl_msg(struct dvb_usb_device *d,
+ 	sndbuf[0] = cmd;
+ 	memcpy(&sndbuf[1], wbuf, wlen);
+ 	if (wo)
+-		dvb_usb_generic_write(d, sndbuf, 1+wlen);
++		return dvb_usb_generic_write(d, sndbuf, 1+wlen);
+ 	else
+-		dvb_usb_generic_rw(d, sndbuf, 1+wlen, rbuf, rlen, 0);
+-
+-	return 0;
++		return dvb_usb_generic_rw(d, sndbuf, 1+wlen, rbuf, rlen, 0);
  }
  
-+static ssize_t show_jint_max_packets(struct device *dev,
-+				     struct device_attribute *attr,
-+				     char *buf)
-+{
-+	struct ipath_devdata *dd = dev_get_drvdata(dev);
-+
-+	return scnprintf(buf, PAGE_SIZE, "%hu\n", dd->ipath_jint_max_packets);
-+}
-+
-+static ssize_t store_jint_max_packets(struct device *dev,
-+				      struct device_attribute *attr,
-+				      const char *buf,
-+				      size_t count)
+ /* GPIO */
+@@ -72,6 +75,34 @@ static void cxusb_gpio_tuner(struct dvb_usb_device *d, int onoff)
+ 	st->gpio_write_state[GPIO_TUNER] = onoff;
+ }
+ 
++static int cxusb_bluebird_gpio_rw(struct dvb_usb_device *d, u8 changemask,
++				 u8 newval)
 +{
-+	struct ipath_devdata *dd = dev_get_drvdata(dev);
-+	u16 v = 0;
-+	int ret;
++	u8 o[2], gpio_state;
++	int rc;
 +
-+	ret = ipath_parse_ushort(buf, &v);
-+	if (ret < 0)
-+		ipath_dev_err(dd, "invalid jint_max_packets.\n");
-+	else
-+		dd->ipath_f_config_jint(dd, dd->ipath_jint_idle_ticks, v);
++	o[0] = 0xff & ~changemask;	/* mask of bits to keep */
++	o[1] = newval & changemask;	/* new values for bits  */
 +
-+	return ret;
++	rc = cxusb_ctrl_msg(d, CMD_BLUEBIRD_GPIO_RW, o, 2, &gpio_state, 1);
++	if (rc < 0 || (gpio_state & changemask) != (newval & changemask))
++		deb_info("bluebird_gpio_write failed.\n");
++
++	return rc < 0 ? rc : gpio_state;
 +}
 +
-+static ssize_t show_jint_idle_ticks(struct device *dev,
-+				    struct device_attribute *attr,
-+				    char *buf)
++static void cxusb_bluebird_gpio_pulse(struct dvb_usb_device *d, u8 pin, int low)
 +{
-+	struct ipath_devdata *dd = dev_get_drvdata(dev);
++	cxusb_bluebird_gpio_rw(d, pin, low ? 0 : pin);
++	msleep(5);
++	cxusb_bluebird_gpio_rw(d, pin, low ? pin : 0);
++}
 +
-+	return scnprintf(buf, PAGE_SIZE, "%hu\n", dd->ipath_jint_idle_ticks);
++static void cxusb_nano2_led(struct dvb_usb_device *d, int onoff)
++{
++	cxusb_bluebird_gpio_rw(d, 0x40, onoff ? 0 : 0x40);
 +}
 +
-+static ssize_t store_jint_idle_ticks(struct device *dev,
-+				     struct device_attribute *attr,
-+				     const char *buf,
-+				     size_t count)
+ /* I2C */
+ static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
+ 			  int num)
+@@ -82,9 +113,6 @@ static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
+ 	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+ 		return -EAGAIN;
+ 
+-	if (num > 2)
+-		warn("more than two i2c messages at a time is not handled yet. TODO.");
+-
+ 	for (i = 0; i < num; i++) {
+ 
+ 		if (d->udev->descriptor.idVendor == USB_VID_MEDION)
+@@ -97,8 +125,22 @@ static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
+ 				break;
+ 			}
+ 
+-		/* read request */
+-		if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) {
++		if (msg[i].flags & I2C_M_RD) {
++			/* read only */
++			u8 obuf[3], ibuf[1+msg[i].len];
++			obuf[0] = 0;
++			obuf[1] = msg[i].len;
++			obuf[2] = msg[i].addr;
++			if (cxusb_ctrl_msg(d, CMD_I2C_READ,
++					   obuf, 3,
++					   ibuf, 1+msg[i].len) < 0) {
++				warn("i2c read failed");
++				break;
++			}
++			memcpy(msg[i].buf, &ibuf[1], msg[i].len);
++		} else if (i+1 < num && (msg[i+1].flags & I2C_M_RD) &&
++			   msg[i].addr == msg[i+1].addr) {
++			/* write to then read from same address */
+ 			u8 obuf[3+msg[i].len], ibuf[1+msg[i+1].len];
+ 			obuf[0] = msg[i].len;
+ 			obuf[1] = msg[i+1].len;
+@@ -116,7 +158,8 @@ static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
+ 			memcpy(msg[i+1].buf, &ibuf[1], msg[i+1].len);
+ 
+ 			i++;
+-		} else { /* write */
++		} else {
++			/* write only */
+ 			u8 obuf[2+msg[i].len], ibuf;
+ 			obuf[0] = msg[i].addr;
+ 			obuf[1] = msg[i].len;
+@@ -131,7 +174,7 @@ static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
+ 	}
+ 
+ 	mutex_unlock(&d->i2c_mutex);
+-	return i;
++	return i == num ? num : -EREMOTEIO;
+ }
+ 
+ static u32 cxusb_i2c_func(struct i2c_adapter *adapter)
+@@ -162,6 +205,17 @@ static int cxusb_bluebird_power_ctrl(struct dvb_usb_device *d, int onoff)
+ 		return 0;
+ }
+ 
++static int cxusb_nano2_power_ctrl(struct dvb_usb_device *d, int onoff)
 +{
-+	struct ipath_devdata *dd = dev_get_drvdata(dev);
-+	u16 v = 0;
-+	int ret;
++	int rc = 0;
 +
-+	ret = ipath_parse_ushort(buf, &v);
-+	if (ret < 0)
-+		ipath_dev_err(dd, "invalid jint_idle_ticks.\n");
-+	else
-+		dd->ipath_f_config_jint(dd, v, dd->ipath_jint_max_packets);
++	rc = cxusb_power_ctrl(d, onoff);
++	if (!onoff)
++		cxusb_nano2_led(d, 0);
 +
-+	return ret;
++	return rc;
 +}
 +
- #define DEVICE_COUNTER(name, attr) \
- 	static ssize_t show_counter_##name(struct device *dev, \
- 					   struct device_attribute *attr, \
-@@ -670,6 +724,257 @@ static ssize_t show_logged_errs(struct device *dev,
- 	return count;
+ static int cxusb_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
+ {
+ 	u8 buf[2] = { 0x03, 0x00 };
+@@ -197,6 +251,34 @@ static int cxusb_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
+ 	return 0;
  }
  
-+/*
-+ * New sysfs entries to control various IB config. These all turn into
-+ * accesses via ipath_f_get/set_ib_cfg.
-+ *
-+ * Get/Set heartbeat enable. Or of 1=enabled, 2=auto
-+ */
-+static ssize_t show_hrtbt_enb(struct device *dev,
-+			 struct device_attribute *attr,
-+			 char *buf)
++static int cxusb_bluebird2_rc_query(struct dvb_usb_device *d, u32 *event,
++				    int *state)
 +{
-+	struct ipath_devdata *dd = dev_get_drvdata(dev);
-+	int ret;
++	struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
++	u8 ircode[4];
++	int i;
++	struct i2c_msg msg = { .addr = 0x6b, .flags = I2C_M_RD,
++			       .buf = ircode, .len = 4 };
 +
-+	ret = dd->ipath_f_get_ib_cfg(dd, IPATH_IB_CFG_HRTBT);
-+	if (ret >= 0)
-+		ret = scnprintf(buf, PAGE_SIZE, "%d\n", ret);
-+	return ret;
-+}
++	*event = 0;
++	*state = REMOTE_NO_KEY_PRESSED;
 +
-+static ssize_t store_hrtbt_enb(struct device *dev,
-+			  struct device_attribute *attr,
-+			  const char *buf,
-+			  size_t count)
-+{
-+	struct ipath_devdata *dd = dev_get_drvdata(dev);
-+	int ret, r;
-+	u16 val;
++	if (cxusb_i2c_xfer(&d->i2c_adap, &msg, 1) != 1)
++		return 0;
 +
-+	ret = ipath_parse_ushort(buf, &val);
-+	if (ret >= 0 && val > 3)
-+		ret = -EINVAL;
-+	if (ret < 0) {
-+		ipath_dev_err(dd, "attempt to set invalid Heartbeat enable\n");
-+		goto bail;
-+	}
++	for (i = 0; i < d->props.rc_key_map_size; i++) {
++		if (keymap[i].custom == ircode[1] &&
++		    keymap[i].data == ircode[2]) {
++			*event = keymap[i].event;
++			*state = REMOTE_KEY_PRESSED;
 +
-+	/*
-+	 * Set the "intentional" heartbeat enable per either of
-+	 * "Enable" and "Auto", as these are normally set together.
-+	 * This bit is consulted when leaving loopback mode,
-+	 * because entering loopback mode overrides it and automatically
-+	 * disables heartbeat.
-+	 */
-+	r = dd->ipath_f_set_ib_cfg(dd, IPATH_IB_CFG_HRTBT, val);
-+	if (r < 0)
-+		ret = r;
-+	else if (val == IPATH_IB_HRTBT_OFF)
-+		dd->ipath_flags |= IPATH_NO_HRTBT;
-+	else
-+		dd->ipath_flags &= ~IPATH_NO_HRTBT;
++			return 0;
++		}
++	}
 +
-+bail:
-+	return ret;
++	return 0;
 +}
 +
-+/*
-+ * Get/Set Link-widths enabled. Or of 1=1x, 2=4x (this is human/IB centric,
-+ * _not_ the particular encoding of any given chip)
-+ */
-+static ssize_t show_lwid_enb(struct device *dev,
-+			 struct device_attribute *attr,
-+			 char *buf)
-+{
-+	struct ipath_devdata *dd = dev_get_drvdata(dev);
-+	int ret;
+ static struct dvb_usb_rc_key dvico_mce_rc_keys[] = {
+ 	{ 0xfe, 0x02, KEY_TV },
+ 	{ 0xfe, 0x0e, KEY_MP3 },
+@@ -351,6 +433,20 @@ static struct mt352_config cxusb_mt352_config = {
+ 	.demod_init    = cxusb_mt352_demod_init,
+ };
+ 
++static struct zl10353_config cxusb_zl10353_xc3028_config = {
++	.demod_address = 0x0f,
++	.if2 = 45600,
++	.no_tuner = 1,
++	.parallel_ts = 1,
++};
 +
-+	ret = dd->ipath_f_get_ib_cfg(dd, IPATH_IB_CFG_LWID_ENB);
-+	if (ret >= 0)
-+		ret = scnprintf(buf, PAGE_SIZE, "%d\n", ret);
-+	return ret;
-+}
++static struct mt352_config cxusb_mt352_xc3028_config = {
++	.demod_address = 0x0f,
++	.if2 = 4560,
++	.no_tuner = 1,
++	.demod_init = cxusb_mt352_demod_init,
++};
 +
-+static ssize_t store_lwid_enb(struct device *dev,
-+			  struct device_attribute *attr,
-+			  const char *buf,
-+			  size_t count)
+ /* Callbacks for DVB USB */
+ static int cxusb_fmd1216me_tuner_attach(struct dvb_usb_adapter *adap)
+ {
+@@ -386,6 +482,51 @@ static int cxusb_lgh064f_tuner_attach(struct dvb_usb_adapter *adap)
+ 	return 0;
+ }
+ 
++static int dvico_bluebird_xc2028_callback(void *ptr, int command, int arg)
 +{
-+	struct ipath_devdata *dd = dev_get_drvdata(dev);
-+	int ret, r;
-+	u16 val;
++	struct dvb_usb_device *d = ptr;
 +
-+	ret = ipath_parse_ushort(buf, &val);
-+	if (ret >= 0 && (val == 0 || val > 3))
-+		ret = -EINVAL;
-+	if (ret < 0) {
-+		ipath_dev_err(dd,
-+			"attempt to set invalid Link Width (enable)\n");
-+		goto bail;
++	switch (command) {
++	case XC2028_TUNER_RESET:
++		deb_info("%s: XC2028_TUNER_RESET %d\n", __FUNCTION__, arg);
++		cxusb_bluebird_gpio_pulse(d, 0x01, 1);
++		break;
++	case XC2028_RESET_CLK:
++		deb_info("%s: XC2028_RESET_CLK %d\n", __FUNCTION__, arg);
++		break;
++	default:
++		deb_info("%s: unknown command %d, arg %d\n", __FUNCTION__,
++			 command, arg);
++		return -EINVAL;
 +	}
 +
-+	r = dd->ipath_f_set_ib_cfg(dd, IPATH_IB_CFG_LWID_ENB, val);
-+	if (r < 0)
-+		ret = r;
-+
-+bail:
-+	return ret;
++	return 0;
 +}
 +
-+/* Get current link width */
-+static ssize_t show_lwid(struct device *dev,
-+			 struct device_attribute *attr,
-+			 char *buf)
-+
++static int cxusb_dvico_xc3028_tuner_attach(struct dvb_usb_adapter *adap)
 +{
-+	struct ipath_devdata *dd = dev_get_drvdata(dev);
-+	int ret;
++	struct dvb_frontend	 *fe;
++	struct xc2028_config	  cfg = {
++		.i2c_adap  = &adap->dev->i2c_adap,
++		.i2c_addr  = 0x61,
++		.video_dev = adap->dev,
++		.callback  = dvico_bluebird_xc2028_callback,
++	};
++	static struct xc2028_ctrl ctl = {
++		.fname       = "xc3028-dvico-au-01.fw",
++		.max_len     = 64,
++		.scode_table = ZARLINK456,
++	};
 +
-+	ret = dd->ipath_f_get_ib_cfg(dd, IPATH_IB_CFG_LWID);
-+	if (ret >= 0)
-+		ret = scnprintf(buf, PAGE_SIZE, "%d\n", ret);
-+	return ret;
-+}
++	fe = dvb_attach(xc2028_attach, adap->fe, &cfg);
++	if (fe == NULL || fe->ops.tuner_ops.set_config == NULL)
++		return -EIO;
 +
-+/*
-+ * Get/Set Link-speeds enabled. Or of 1=SDR 2=DDR.
-+ */
-+static ssize_t show_spd_enb(struct device *dev,
-+			 struct device_attribute *attr,
-+			 char *buf)
-+{
-+	struct ipath_devdata *dd = dev_get_drvdata(dev);
-+	int ret;
++	fe->ops.tuner_ops.set_config(fe, &ctl);
 +
-+	ret = dd->ipath_f_get_ib_cfg(dd, IPATH_IB_CFG_SPD_ENB);
-+	if (ret >= 0)
-+		ret = scnprintf(buf, PAGE_SIZE, "%d\n", ret);
-+	return ret;
++	return 0;
 +}
 +
-+static ssize_t store_spd_enb(struct device *dev,
-+			  struct device_attribute *attr,
-+			  const char *buf,
-+			  size_t count)
+ static int cxusb_cx22702_frontend_attach(struct dvb_usb_adapter *adap)
+ {
+ 	u8 b;
+@@ -447,27 +588,120 @@ static int cxusb_dee1601_frontend_attach(struct dvb_usb_adapter *adap)
+ 	return -EIO;
+ }
+ 
++static int cxusb_dualdig4_frontend_attach(struct dvb_usb_adapter *adap)
 +{
-+	struct ipath_devdata *dd = dev_get_drvdata(dev);
-+	int ret, r;
-+	u16 val;
++	u8 ircode[4];
++	int i;
++	struct i2c_msg msg = { .addr = 0x6b, .flags = I2C_M_RD,
++			       .buf = ircode, .len = 4 };
 +
-+	ret = ipath_parse_ushort(buf, &val);
-+	if (ret >= 0 && (val == 0 || val > (IPATH_IB_SDR | IPATH_IB_DDR)))
-+		ret = -EINVAL;
-+	if (ret < 0) {
-+		ipath_dev_err(dd,
-+			"attempt to set invalid Link Speed (enable)\n");
-+		goto bail;
-+	}
++	if (usb_set_interface(adap->dev->udev, 0, 1) < 0)
++		err("set interface failed");
 +
-+	r = dd->ipath_f_set_ib_cfg(dd, IPATH_IB_CFG_SPD_ENB, val);
-+	if (r < 0)
-+		ret = r;
++	cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0);
 +
-+bail:
-+	return ret;
-+}
++	/* reset the tuner and demodulator */
++	cxusb_bluebird_gpio_rw(adap->dev, 0x04, 0);
++	cxusb_bluebird_gpio_pulse(adap->dev, 0x01, 1);
++	cxusb_bluebird_gpio_pulse(adap->dev, 0x02, 1);
 +
-+/* Get current link speed */
-+static ssize_t show_spd(struct device *dev,
-+			 struct device_attribute *attr,
-+			 char *buf)
-+{
-+	struct ipath_devdata *dd = dev_get_drvdata(dev);
-+	int ret;
++	if ((adap->fe = dvb_attach(zl10353_attach,
++				   &cxusb_zl10353_xc3028_config,
++				   &adap->dev->i2c_adap)) == NULL)
++		return -EIO;
 +
-+	ret = dd->ipath_f_get_ib_cfg(dd, IPATH_IB_CFG_SPD);
-+	if (ret >= 0)
-+		ret = scnprintf(buf, PAGE_SIZE, "%d\n", ret);
-+	return ret;
++	/* try to determine if there is no IR decoder on the I2C bus */
++	for (i = 0; adap->dev->props.rc_key_map != NULL && i < 5; i++) {
++		msleep(20);
++		if (cxusb_i2c_xfer(&adap->dev->i2c_adap, &msg, 1) != 1)
++			goto no_IR;
++		if (ircode[0] == 0 && ircode[1] == 0)
++			continue;
++		if (ircode[2] + ircode[3] != 0xff) {
++no_IR:
++			adap->dev->props.rc_key_map = NULL;
++			info("No IR receiver detected on this device.");
++			break;
++		}
++	}
++
++	return 0;
 +}
 +
-+/*
-+ * Get/Set RX polarity-invert enable. 0=no, 1=yes.
-+ */
-+static ssize_t show_rx_polinv_enb(struct device *dev,
-+			 struct device_attribute *attr,
-+			 char *buf)
++static int cxusb_nano2_frontend_attach(struct dvb_usb_adapter *adap)
 +{
-+	struct ipath_devdata *dd = dev_get_drvdata(dev);
-+	int ret;
++	if (usb_set_interface(adap->dev->udev, 0, 1) < 0)
++		err("set interface failed");
 +
-+	ret = dd->ipath_f_get_ib_cfg(dd, IPATH_IB_CFG_RXPOL_ENB);
-+	if (ret >= 0)
-+		ret = scnprintf(buf, PAGE_SIZE, "%d\n", ret);
-+	return ret;
-+}
++	cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0);
 +
-+static ssize_t store_rx_polinv_enb(struct device *dev,
-+			  struct device_attribute *attr,
-+			  const char *buf,
-+			  size_t count)
-+{
-+	struct ipath_devdata *dd = dev_get_drvdata(dev);
-+	int ret, r;
-+	u16 val;
++	/* reset the tuner and demodulator */
++	cxusb_bluebird_gpio_rw(adap->dev, 0x04, 0);
++	cxusb_bluebird_gpio_pulse(adap->dev, 0x01, 1);
++	cxusb_bluebird_gpio_pulse(adap->dev, 0x02, 1);
 +
-+	ret = ipath_parse_ushort(buf, &val);
-+	if (ret < 0 || val > 1)
-+		goto invalid;
++	if ((adap->fe = dvb_attach(zl10353_attach,
++				   &cxusb_zl10353_xc3028_config,
++				   &adap->dev->i2c_adap)) != NULL)
++		return 0;
 +
-+	r = dd->ipath_f_set_ib_cfg(dd, IPATH_IB_CFG_RXPOL_ENB, val);
-+	if (r < 0) {
-+		ret = r;
-+		goto bail;
-+	}
++	if ((adap->fe = dvb_attach(mt352_attach,
++				   &cxusb_mt352_xc3028_config,
++				   &adap->dev->i2c_adap)) != NULL)
++		return 0;
 +
-+	goto bail;
-+invalid:
-+	ipath_dev_err(dd, "attempt to set invalid Rx Polarity (enable)\n");
-+bail:
-+	return ret;
++	return -EIO;
 +}
++
 +/*
-+ * Get/Set RX lane-reversal enable. 0=no, 1=yes.
++ * 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
++ * have non-default values to decide whether the device is actually cold or
++ * not, and forget a match if it turns out we selected the wrong device.
 + */
-+static ssize_t show_lanerev_enb(struct device *dev,
-+			 struct device_attribute *attr,
-+			 char *buf)
-+{
-+	struct ipath_devdata *dd = dev_get_drvdata(dev);
-+	int ret;
-+
-+	ret = dd->ipath_f_get_ib_cfg(dd, IPATH_IB_CFG_LREV_ENB);
-+	if (ret >= 0)
-+		ret = scnprintf(buf, PAGE_SIZE, "%d\n", ret);
-+	return ret;
-+}
-+
-+static ssize_t store_lanerev_enb(struct device *dev,
-+			  struct device_attribute *attr,
-+			  const char *buf,
-+			  size_t count)
++static int bluebird_fx2_identify_state(struct usb_device *udev,
++				       struct dvb_usb_device_properties *props,
++				       struct dvb_usb_device_description **desc,
++				       int *cold)
 +{
-+	struct ipath_devdata *dd = dev_get_drvdata(dev);
-+	int ret, r;
-+	u16 val;
++	int wascold = *cold;
 +
-+	ret = ipath_parse_ushort(buf, &val);
-+	if (ret >= 0 && val > 1) {
-+		ret = -EINVAL;
-+		ipath_dev_err(dd,
-+			"attempt to set invalid Lane reversal (enable)\n");
-+		goto bail;
-+	}
++	*cold = udev->descriptor.bDeviceClass == 0xff &&
++		udev->descriptor.bDeviceSubClass == 0xff &&
++		udev->descriptor.bDeviceProtocol == 0xff;
 +
-+	r = dd->ipath_f_set_ib_cfg(dd, IPATH_IB_CFG_LREV_ENB, val);
-+	if (r < 0)
-+		ret = r;
++	if (*cold && !wascold)
++		*desc = NULL;
 +
-+bail:
-+	return ret;
++	return 0;
 +}
 +
- static DRIVER_ATTR(num_units, S_IRUGO, show_num_units, NULL);
- static DRIVER_ATTR(version, S_IRUGO, show_version, NULL);
- 
-@@ -683,6 +988,11 @@ static struct attribute_group driver_attr_group = {
- 	.attrs = driver_attributes
- };
- 
-+struct attribute_group *ipath_driver_attr_groups[] = {
-+	&driver_attr_group,
-+	NULL,
-+};
-+
- static DEVICE_ATTR(guid, S_IWUSR | S_IRUGO, show_guid, store_guid);
- static DEVICE_ATTR(lmc, S_IWUSR | S_IRUGO, show_lmc, store_lmc);
- static DEVICE_ATTR(lid, S_IWUSR | S_IRUGO, show_lid, store_lid);
-@@ -701,6 +1011,10 @@ static DEVICE_ATTR(unit, S_IRUGO, show_unit, NULL);
- static DEVICE_ATTR(rx_pol_inv, S_IWUSR, NULL, store_rx_pol_inv);
- static DEVICE_ATTR(led_override, S_IWUSR, NULL, store_led_override);
- static DEVICE_ATTR(logged_errors, S_IRUGO, show_logged_errs, NULL);
-+static DEVICE_ATTR(jint_max_packets, S_IWUSR | S_IRUGO,
-+		   show_jint_max_packets, store_jint_max_packets);
-+static DEVICE_ATTR(jint_idle_ticks, S_IWUSR | S_IRUGO,
-+		   show_jint_idle_ticks, store_jint_idle_ticks);
- 
- static struct attribute *dev_attributes[] = {
- 	&dev_attr_guid.attr,
-@@ -727,6 +1041,34 @@ static struct attribute_group dev_attr_group = {
- 	.attrs = dev_attributes
- };
- 
-+static DEVICE_ATTR(hrtbt_enable, S_IWUSR | S_IRUGO, show_hrtbt_enb,
-+		   store_hrtbt_enb);
-+static DEVICE_ATTR(link_width_enable, S_IWUSR | S_IRUGO, show_lwid_enb,
-+		   store_lwid_enb);
-+static DEVICE_ATTR(link_width, S_IRUGO, show_lwid, NULL);
-+static DEVICE_ATTR(link_speed_enable, S_IWUSR | S_IRUGO, show_spd_enb,
-+		   store_spd_enb);
-+static DEVICE_ATTR(link_speed, S_IRUGO, show_spd, NULL);
-+static DEVICE_ATTR(rx_pol_inv_enable, S_IWUSR | S_IRUGO, show_rx_polinv_enb,
-+		   store_rx_polinv_enb);
-+static DEVICE_ATTR(rx_lane_rev_enable, S_IWUSR | S_IRUGO, show_lanerev_enb,
-+		   store_lanerev_enb);
-+
-+static struct attribute *dev_ibcfg_attributes[] = {
-+	&dev_attr_hrtbt_enable.attr,
-+	&dev_attr_link_width_enable.attr,
-+	&dev_attr_link_width.attr,
-+	&dev_attr_link_speed_enable.attr,
-+	&dev_attr_link_speed.attr,
-+	&dev_attr_rx_pol_inv_enable.attr,
-+	&dev_attr_rx_lane_rev_enable.attr,
-+	NULL
-+};
-+
-+static struct attribute_group dev_ibcfg_attr_group = {
-+	.attrs = dev_ibcfg_attributes
-+};
-+
- /**
-  * ipath_expose_reset - create a device reset file
-  * @dev: the device structure
-@@ -753,24 +1095,9 @@ int ipath_expose_reset(struct device *dev)
- 	return ret;
- }
+ /*
+  * DViCO bluebird firmware needs the "warm" product ID to be patched into the
+  * firmware file before download.
+  */
  
--int ipath_driver_create_group(struct device_driver *drv)
--{
--	int ret;
--
--	ret = sysfs_create_group(&drv->kobj, &driver_attr_group);
--
--	return ret;
--}
--
--void ipath_driver_remove_group(struct device_driver *drv)
--{
--	sysfs_remove_group(&drv->kobj, &driver_attr_group);
--}
--
- int ipath_device_create_group(struct device *dev, struct ipath_devdata *dd)
+-#define BLUEBIRD_01_ID_OFFSET 6638
++static const int dvico_firmware_id_offsets[] = { 6638, 3204 };
+ static int bluebird_patch_dvico_firmware_download(struct usb_device *udev,
+ 						  const struct firmware *fw)
  {
- 	int ret;
--	char unit[5];
- 
- 	ret = sysfs_create_group(&dev->kobj, &dev_attr_group);
- 	if (ret)
-@@ -780,11 +1107,26 @@ int ipath_device_create_group(struct device *dev, struct ipath_devdata *dd)
- 	if (ret)
- 		goto bail_attrs;
- 
--	snprintf(unit, sizeof(unit), "%02d", dd->ipath_unit);
--	ret = sysfs_create_link(&dev->driver->kobj, &dev->kobj, unit);
--	if (ret == 0)
--		goto bail;
-+	if (dd->ipath_flags & IPATH_HAS_MULT_IB_SPEED) {
-+		ret = device_create_file(dev, &dev_attr_jint_idle_ticks);
-+		if (ret)
-+			goto bail_counter;
-+		ret = device_create_file(dev, &dev_attr_jint_max_packets);
-+		if (ret)
-+			goto bail_idle;
- 
-+		ret = sysfs_create_group(&dev->kobj, &dev_ibcfg_attr_group);
-+		if (ret)
-+			goto bail_max;
-+	}
-+
-+	return 0;
+-	if (fw->size < BLUEBIRD_01_ID_OFFSET + 4)
+-		return -EINVAL;
++	int pos;
 +
-+bail_max:
-+	device_remove_file(dev, &dev_attr_jint_max_packets);
-+bail_idle:
-+	device_remove_file(dev, &dev_attr_jint_idle_ticks);
-+bail_counter:
- 	sysfs_remove_group(&dev->kobj, &dev_counter_attr_group);
- bail_attrs:
- 	sysfs_remove_group(&dev->kobj, &dev_attr_group);
-@@ -794,12 +1136,14 @@ bail:
- 
- void ipath_device_remove_group(struct device *dev, struct ipath_devdata *dd)
- {
--	char unit[5];
-+	sysfs_remove_group(&dev->kobj, &dev_counter_attr_group);
- 
--	snprintf(unit, sizeof(unit), "%02d", dd->ipath_unit);
--	sysfs_remove_link(&dev->driver->kobj, unit);
-+	if (dd->ipath_flags & IPATH_HAS_MULT_IB_SPEED) {
-+		sysfs_remove_group(&dev->kobj, &dev_ibcfg_attr_group);
-+		device_remove_file(dev, &dev_attr_jint_idle_ticks);
-+		device_remove_file(dev, &dev_attr_jint_max_packets);
-+	}
++	for (pos = 0; pos < ARRAY_SIZE(dvico_firmware_id_offsets); pos++) {
++		int idoff = dvico_firmware_id_offsets[pos];
  
--	sysfs_remove_group(&dev->kobj, &dev_counter_attr_group);
- 	sysfs_remove_group(&dev->kobj, &dev_attr_group);
+-	if (fw->data[BLUEBIRD_01_ID_OFFSET] == (USB_VID_DVICO & 0xff) &&
+-	    fw->data[BLUEBIRD_01_ID_OFFSET + 1] == USB_VID_DVICO >> 8) {
++		if (fw->size < idoff + 4)
++			continue;
  
- 	device_remove_file(dev, &dev_attr_reset);
-diff --git a/drivers/infiniband/hw/ipath/ipath_ud.c b/drivers/infiniband/hw/ipath/ipath_ud.c
-index b3df6f3..de67eed 100644
---- a/drivers/infiniband/hw/ipath/ipath_ud.c
-+++ b/drivers/infiniband/hw/ipath/ipath_ud.c
-@@ -301,8 +301,6 @@ int ipath_make_ud_req(struct ipath_qp *qp)
+-		fw->data[BLUEBIRD_01_ID_OFFSET + 2] =
+-			le16_to_cpu(udev->descriptor.idProduct) + 1;
+-		fw->data[BLUEBIRD_01_ID_OFFSET + 3] =
+-			le16_to_cpu(udev->descriptor.idProduct) >> 8;
++		if (fw->data[idoff] == (USB_VID_DVICO & 0xff) &&
++		    fw->data[idoff + 1] == USB_VID_DVICO >> 8) {
++			fw->data[idoff + 2] =
++				le16_to_cpu(udev->descriptor.idProduct) + 1;
++			fw->data[idoff + 3] =
++				le16_to_cpu(udev->descriptor.idProduct) >> 8;
  
- 	/* header size in 32-bit words LRH+BTH+DETH = (8+12+8)/4. */
- 	qp->s_hdrwords = 7;
--	if (wqe->wr.opcode == IB_WR_SEND_WITH_IMM)
--		qp->s_hdrwords++;
- 	qp->s_cur_size = wqe->length;
- 	qp->s_cur_sge = &qp->s_sge;
- 	qp->s_wqe = wqe;
-@@ -327,6 +325,7 @@ int ipath_make_ud_req(struct ipath_qp *qp)
- 		ohdr = &qp->s_hdr.u.oth;
+-		return usb_cypress_load_firmware(udev, fw, CYPRESS_FX2);
++			return usb_cypress_load_firmware(udev, fw, CYPRESS_FX2);
++		}
  	}
- 	if (wqe->wr.opcode == IB_WR_SEND_WITH_IMM) {
-+		qp->s_hdrwords++;
- 		ohdr->u.ud.imm_data = wqe->wr.imm_data;
- 		bth0 = IB_OPCODE_UD_SEND_ONLY_WITH_IMMEDIATE << 24;
- 	} else
-diff --git a/drivers/infiniband/hw/ipath/ipath_verbs.c b/drivers/infiniband/hw/ipath/ipath_verbs.c
-index c4c9984..32d8f88 100644
---- a/drivers/infiniband/hw/ipath/ipath_verbs.c
-+++ b/drivers/infiniband/hw/ipath/ipath_verbs.c
-@@ -943,7 +943,7 @@ bail:
-  * ipath_verbs_send - send a packet
-  * @qp: the QP to send on
-  * @hdr: the packet header
-- * @hdrwords: the number of words in the header
-+ * @hdrwords: the number of 32-bit words in the header
-  * @ss: the SGE to send
-  * @len: the length of the packet in bytes
-  */
-@@ -955,7 +955,10 @@ int ipath_verbs_send(struct ipath_qp *qp, struct ipath_ib_header *hdr,
- 	int ret;
- 	u32 dwords = (len + 3) >> 2;
- 
--	/* +1 is for the qword padding of pbc */
-+	/*
-+	 * Calculate the send buffer trigger address.
-+	 * The +1 counts for the pbc control dword following the pbc length.
-+	 */
- 	plen = hdrwords + dwords + 1;
- 
- 	/* Drop non-VL15 packets if we are not in the active state */
-@@ -1130,20 +1133,34 @@ static int ipath_query_device(struct ib_device *ibdev,
- 	return 0;
- }
  
--const u8 ipath_cvt_physportstate[16] = {
--	[INFINIPATH_IBCS_LT_STATE_DISABLED] = 3,
--	[INFINIPATH_IBCS_LT_STATE_LINKUP] = 5,
--	[INFINIPATH_IBCS_LT_STATE_POLLACTIVE] = 2,
--	[INFINIPATH_IBCS_LT_STATE_POLLQUIET] = 2,
--	[INFINIPATH_IBCS_LT_STATE_SLEEPDELAY] = 1,
--	[INFINIPATH_IBCS_LT_STATE_SLEEPQUIET] = 1,
--	[INFINIPATH_IBCS_LT_STATE_CFGDEBOUNCE] = 4,
--	[INFINIPATH_IBCS_LT_STATE_CFGRCVFCFG] = 4,
--	[INFINIPATH_IBCS_LT_STATE_CFGWAITRMT] = 4,
--	[INFINIPATH_IBCS_LT_STATE_CFGIDLE] = 4,
--	[INFINIPATH_IBCS_LT_STATE_RECOVERRETRAIN] = 6,
--	[INFINIPATH_IBCS_LT_STATE_RECOVERWAITRMT] = 6,
--	[INFINIPATH_IBCS_LT_STATE_RECOVERIDLE] = 6,
-+const u8 ipath_cvt_physportstate[32] = {
-+	[INFINIPATH_IBCS_LT_STATE_DISABLED] = IB_PHYSPORTSTATE_DISABLED,
-+	[INFINIPATH_IBCS_LT_STATE_LINKUP] = IB_PHYSPORTSTATE_LINKUP,
-+	[INFINIPATH_IBCS_LT_STATE_POLLACTIVE] = IB_PHYSPORTSTATE_POLL,
-+	[INFINIPATH_IBCS_LT_STATE_POLLQUIET] = IB_PHYSPORTSTATE_POLL,
-+	[INFINIPATH_IBCS_LT_STATE_SLEEPDELAY] = IB_PHYSPORTSTATE_SLEEP,
-+	[INFINIPATH_IBCS_LT_STATE_SLEEPQUIET] = IB_PHYSPORTSTATE_SLEEP,
-+	[INFINIPATH_IBCS_LT_STATE_CFGDEBOUNCE] =
-+		IB_PHYSPORTSTATE_CFG_TRAIN,
-+	[INFINIPATH_IBCS_LT_STATE_CFGRCVFCFG] =
-+		IB_PHYSPORTSTATE_CFG_TRAIN,
-+	[INFINIPATH_IBCS_LT_STATE_CFGWAITRMT] =
-+		IB_PHYSPORTSTATE_CFG_TRAIN,
-+	[INFINIPATH_IBCS_LT_STATE_CFGIDLE] = IB_PHYSPORTSTATE_CFG_TRAIN,
-+	[INFINIPATH_IBCS_LT_STATE_RECOVERRETRAIN] =
-+		IB_PHYSPORTSTATE_LINK_ERR_RECOVER,
-+	[INFINIPATH_IBCS_LT_STATE_RECOVERWAITRMT] =
-+		IB_PHYSPORTSTATE_LINK_ERR_RECOVER,
-+	[INFINIPATH_IBCS_LT_STATE_RECOVERIDLE] =
-+		IB_PHYSPORTSTATE_LINK_ERR_RECOVER,
-+	[0x10] = IB_PHYSPORTSTATE_CFG_TRAIN,
-+	[0x11] = IB_PHYSPORTSTATE_CFG_TRAIN,
-+	[0x12] = IB_PHYSPORTSTATE_CFG_TRAIN,
-+	[0x13] = IB_PHYSPORTSTATE_CFG_TRAIN,
-+	[0x14] = IB_PHYSPORTSTATE_CFG_TRAIN,
-+	[0x15] = IB_PHYSPORTSTATE_CFG_TRAIN,
-+	[0x16] = IB_PHYSPORTSTATE_CFG_TRAIN,
-+	[0x17] = IB_PHYSPORTSTATE_CFG_TRAIN
- };
+ 	return -EINVAL;
+@@ -479,6 +713,9 @@ static struct dvb_usb_device_properties cxusb_bluebird_lgh064f_properties;
+ static struct dvb_usb_device_properties cxusb_bluebird_dee1601_properties;
+ 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_nano2_properties;
++static struct dvb_usb_device_properties cxusb_bluebird_nano2_needsfirmware_properties;
  
- u32 ipath_get_cr_errpkey(struct ipath_devdata *dd)
-@@ -1168,8 +1185,9 @@ static int ipath_query_port(struct ib_device *ibdev,
- 	ibcstat = dd->ipath_lastibcstat;
- 	props->state = ((ibcstat >> 4) & 0x3) + 1;
- 	/* See phys_state_show() */
--	props->phys_state = ipath_cvt_physportstate[
--		dd->ipath_lastibcstat & 0xf];
-+	props->phys_state = /* MEA: assumes shift == 0 */
-+		ipath_cvt_physportstate[dd->ipath_lastibcstat &
-+		dd->ibcs_lts_mask];
- 	props->port_cap_flags = dev->port_cap_flags;
- 	props->gid_tbl_len = 1;
- 	props->max_msg_sz = 0x80000000;
-@@ -1641,6 +1659,7 @@ int ipath_register_ib_device(struct ipath_devdata *dd)
- 		cntrs.local_link_integrity_errors;
- 	idev->z_excessive_buffer_overrun_errors =
- 		cntrs.excessive_buffer_overrun_errors;
-+	idev->z_vl15_dropped = cntrs.vl15_dropped;
+ static int cxusb_probe(struct usb_interface *intf,
+ 		       const struct usb_device_id *id)
+@@ -487,7 +724,10 @@ static int cxusb_probe(struct usb_interface *intf,
+ 		dvb_usb_device_init(intf,&cxusb_bluebird_lgh064f_properties,THIS_MODULE,NULL) == 0 ||
+ 		dvb_usb_device_init(intf,&cxusb_bluebird_dee1601_properties,THIS_MODULE,NULL) == 0 ||
+ 		dvb_usb_device_init(intf,&cxusb_bluebird_lgz201_properties,THIS_MODULE,NULL) == 0 ||
+-		dvb_usb_device_init(intf,&cxusb_bluebird_dtt7579_properties,THIS_MODULE,NULL) == 0) {
++		dvb_usb_device_init(intf,&cxusb_bluebird_dtt7579_properties,THIS_MODULE,NULL) == 0 ||
++		dvb_usb_device_init(intf,&cxusb_bluebird_dualdig4_properties,THIS_MODULE,NULL) == 0 ||
++		dvb_usb_device_init(intf,&cxusb_bluebird_nano2_properties,THIS_MODULE,NULL) == 0 ||
++		dvb_usb_device_init(intf,&cxusb_bluebird_nano2_needsfirmware_properties,THIS_MODULE,NULL) == 0) {
+ 		return 0;
+ 	}
  
- 	/*
- 	 * The system image GUID is supposed to be the same for all
-diff --git a/drivers/infiniband/hw/ipath/ipath_verbs.h b/drivers/infiniband/hw/ipath/ipath_verbs.h
-index 6ccb54f..3d59736 100644
---- a/drivers/infiniband/hw/ipath/ipath_verbs.h
-+++ b/drivers/infiniband/hw/ipath/ipath_verbs.h
-@@ -554,6 +554,7 @@ struct ipath_ibdev {
- 	u32 z_pkey_violations;			/* starting count for PMA */
- 	u32 z_local_link_integrity_errors;	/* starting count for PMA */
- 	u32 z_excessive_buffer_overrun_errors;	/* starting count for PMA */
-+	u32 z_vl15_dropped;			/* starting count for PMA */
- 	u32 n_rc_resends;
- 	u32 n_rc_acks;
- 	u32 n_rc_qacks;
-@@ -598,6 +599,7 @@ struct ipath_verbs_counters {
- 	u64 port_rcv_packets;
- 	u32 local_link_integrity_errors;
- 	u32 excessive_buffer_overrun_errors;
-+	u32 vl15_dropped;
+@@ -508,6 +748,9 @@ static struct usb_device_id cxusb_table [] = {
+ 	{ USB_DEVICE(USB_VID_DVICO, USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_WARM) },
+ 	{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_2_COLD) },
+ 	{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_2_WARM) },
++	{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_4) },
++	{ 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) },
+ 	{}		/* Terminating entry */
  };
- 
- static inline struct ipath_mr *to_imr(struct ib_mr *ibmr)
-@@ -830,7 +832,17 @@ unsigned ipath_get_pkey(struct ipath_devdata *, unsigned);
- 
- extern const enum ib_wc_opcode ib_ipath_wc_opcode[];
- 
-+/*
-+ * Below converts HCA-specific LinkTrainingState to IB PhysPortState
-+ * values.
-+ */
- extern const u8 ipath_cvt_physportstate[];
-+#define IB_PHYSPORTSTATE_SLEEP 1
-+#define IB_PHYSPORTSTATE_POLL 2
-+#define IB_PHYSPORTSTATE_DISABLED 3
-+#define IB_PHYSPORTSTATE_CFG_TRAIN 4
-+#define IB_PHYSPORTSTATE_LINKUP 5
-+#define IB_PHYSPORTSTATE_LINK_ERR_RECOVER 6
- 
- extern const int ib_ipath_state_ops[];
- 
-diff --git a/drivers/infiniband/hw/mlx4/cq.c b/drivers/infiniband/hw/mlx4/cq.c
-index 9d32c49..7950aa6 100644
---- a/drivers/infiniband/hw/mlx4/cq.c
-+++ b/drivers/infiniband/hw/mlx4/cq.c
-@@ -313,6 +313,7 @@ static int mlx4_ib_poll_one(struct mlx4_ib_cq *cq,
- 	struct mlx4_ib_srq *srq;
- 	int is_send;
- 	int is_error;
-+	u32 g_mlpath_rqpn;
- 	u16 wqe_ctr;
- 
- 	cqe = next_cqe_sw(cq);
-@@ -426,10 +427,10 @@ static int mlx4_ib_poll_one(struct mlx4_ib_cq *cq,
- 
- 		wc->slid	   = be16_to_cpu(cqe->rlid);
- 		wc->sl		   = cqe->sl >> 4;
--		wc->src_qp	   = be32_to_cpu(cqe->g_mlpath_rqpn) & 0xffffff;
--		wc->dlid_path_bits = (be32_to_cpu(cqe->g_mlpath_rqpn) >> 24) & 0x7f;
--		wc->wc_flags      |= be32_to_cpu(cqe->g_mlpath_rqpn) & 0x80000000 ?
--			IB_WC_GRH : 0;
-+		g_mlpath_rqpn	   = be32_to_cpu(cqe->g_mlpath_rqpn);
-+		wc->src_qp	   = g_mlpath_rqpn & 0xffffff;
-+		wc->dlid_path_bits = (g_mlpath_rqpn >> 24) & 0x7f;
-+		wc->wc_flags	  |= g_mlpath_rqpn & 0x80000000 ? IB_WC_GRH : 0;
- 		wc->pkey_index     = be32_to_cpu(cqe->immed_rss_invalid) & 0x7f;
+ MODULE_DEVICE_TABLE (usb, cxusb_table);
+@@ -766,6 +1009,151 @@ static struct dvb_usb_device_properties cxusb_bluebird_dtt7579_properties = {
  	}
- 
-diff --git a/drivers/infiniband/hw/mthca/mthca_dev.h b/drivers/infiniband/hw/mthca/mthca_dev.h
-index 15aa32e..7bbdd1f 100644
---- a/drivers/infiniband/hw/mthca/mthca_dev.h
-+++ b/drivers/infiniband/hw/mthca/mthca_dev.h
-@@ -60,13 +60,12 @@
- enum {
- 	MTHCA_FLAG_DDR_HIDDEN = 1 << 1,
- 	MTHCA_FLAG_SRQ        = 1 << 2,
--	MTHCA_FLAG_MSI        = 1 << 3,
--	MTHCA_FLAG_MSI_X      = 1 << 4,
--	MTHCA_FLAG_NO_LAM     = 1 << 5,
--	MTHCA_FLAG_FMR        = 1 << 6,
--	MTHCA_FLAG_MEMFREE    = 1 << 7,
--	MTHCA_FLAG_PCIE       = 1 << 8,
--	MTHCA_FLAG_SINAI_OPT  = 1 << 9
-+	MTHCA_FLAG_MSI_X      = 1 << 3,
-+	MTHCA_FLAG_NO_LAM     = 1 << 4,
-+	MTHCA_FLAG_FMR        = 1 << 5,
-+	MTHCA_FLAG_MEMFREE    = 1 << 6,
-+	MTHCA_FLAG_PCIE       = 1 << 7,
-+	MTHCA_FLAG_SINAI_OPT  = 1 << 8
  };
  
- enum {
-diff --git a/drivers/infiniband/hw/mthca/mthca_eq.c b/drivers/infiniband/hw/mthca/mthca_eq.c
-index b29de51..b60eb5d 100644
---- a/drivers/infiniband/hw/mthca/mthca_eq.c
-+++ b/drivers/infiniband/hw/mthca/mthca_eq.c
-@@ -827,8 +827,7 @@ int mthca_init_eq_table(struct mthca_dev *dev)
- 	if (err)
- 		goto err_out_free;
- 
--	if (dev->mthca_flags & MTHCA_FLAG_MSI ||
--	    dev->mthca_flags & MTHCA_FLAG_MSI_X) {
-+	if (dev->mthca_flags & MTHCA_FLAG_MSI_X) {
- 		dev->eq_table.clr_mask = 0;
- 	} else {
- 		dev->eq_table.clr_mask =
-@@ -839,8 +838,7 @@ int mthca_init_eq_table(struct mthca_dev *dev)
- 
- 	dev->eq_table.arm_mask = 0;
- 
--	intr = (dev->mthca_flags & MTHCA_FLAG_MSI) ?
--		128 : dev->eq_table.inta_pin;
-+	intr = dev->eq_table.inta_pin;
- 
- 	err = mthca_create_eq(dev, dev->limits.num_cqs + MTHCA_NUM_SPARE_EQE,
- 			      (dev->mthca_flags & MTHCA_FLAG_MSI_X) ? 128 : intr,
-diff --git a/drivers/infiniband/hw/mthca/mthca_main.c b/drivers/infiniband/hw/mthca/mthca_main.c
-index 60de6f9..5cf8250 100644
---- a/drivers/infiniband/hw/mthca/mthca_main.c
-+++ b/drivers/infiniband/hw/mthca/mthca_main.c
-@@ -65,14 +65,9 @@ static int msi_x = 1;
- module_param(msi_x, int, 0444);
- MODULE_PARM_DESC(msi_x, "attempt to use MSI-X if nonzero");
++static struct dvb_usb_device_properties cxusb_bluebird_dualdig4_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_frontend_attach,
++			.tuner_attach     = cxusb_dvico_xc3028_tuner_attach,
++			/* parameter for the MPEG2-data transfer */
++			.stream = {
++				.type = USB_BULK,
++				.count = 5,
++				.endpoint = 0x02,
++				.u = {
++					.bulk = {
++						.buffersize = 8192,
++					}
++				}
++			},
++		},
++	},
++
++	.power_ctrl       = cxusb_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_bluebird2_rc_query,
++
++	.num_device_descs = 1,
++	.devices = {
++		{   "DViCO FusionHDTV DVB-T Dual Digital 4",
++			{ NULL },
++			{ &cxusb_table[13], NULL },
++		},
++	}
++};
++
++static struct dvb_usb_device_properties cxusb_bluebird_nano2_properties = {
++	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
++
++	.usb_ctrl         = CYPRESS_FX2,
++	.identify_state   = bluebird_fx2_identify_state,
++
++	.size_of_priv     = sizeof(struct cxusb_state),
++
++	.num_adapters = 1,
++	.adapter = {
++		{
++			.streaming_ctrl   = cxusb_streaming_ctrl,
++			.frontend_attach  = cxusb_nano2_frontend_attach,
++			.tuner_attach     = cxusb_dvico_xc3028_tuner_attach,
++			/* parameter for the MPEG2-data transfer */
++			.stream = {
++				.type = USB_BULK,
++				.count = 5,
++				.endpoint = 0x02,
++				.u = {
++					.bulk = {
++						.buffersize = 8192,
++					}
++				}
++			},
++		},
++	},
++
++	.power_ctrl       = cxusb_nano2_power_ctrl,
++
++	.i2c_algo         = &cxusb_i2c_algo,
++
++	.generic_bulk_ctrl_endpoint = 0x01,
++
++	.rc_interval      = 100,
++	.rc_key_map       = dvico_portable_rc_keys,
++	.rc_key_map_size  = ARRAY_SIZE(dvico_portable_rc_keys),
++	.rc_query         = cxusb_bluebird2_rc_query,
++
++	.num_device_descs = 1,
++	.devices = {
++		{   "DViCO FusionHDTV DVB-T NANO2",
++			{ NULL },
++			{ &cxusb_table[14], NULL },
++		},
++	}
++};
++
++static struct dvb_usb_device_properties cxusb_bluebird_nano2_needsfirmware_properties = {
++	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
++
++	.usb_ctrl          = DEVICE_SPECIFIC,
++	.firmware          = "dvb-usb-bluebird-02.fw",
++	.download_firmware = bluebird_patch_dvico_firmware_download,
++	.identify_state    = bluebird_fx2_identify_state,
++
++	.size_of_priv      = sizeof(struct cxusb_state),
++
++	.num_adapters = 1,
++	.adapter = {
++		{
++			.streaming_ctrl   = cxusb_streaming_ctrl,
++			.frontend_attach  = cxusb_nano2_frontend_attach,
++			.tuner_attach     = cxusb_dvico_xc3028_tuner_attach,
++			/* parameter for the MPEG2-data transfer */
++			.stream = {
++				.type = USB_BULK,
++				.count = 5,
++				.endpoint = 0x02,
++				.u = {
++					.bulk = {
++						.buffersize = 8192,
++					}
++				}
++			},
++		},
++	},
++
++	.power_ctrl       = cxusb_nano2_power_ctrl,
++
++	.i2c_algo         = &cxusb_i2c_algo,
++
++	.generic_bulk_ctrl_endpoint = 0x01,
++
++	.rc_interval      = 100,
++	.rc_key_map       = dvico_portable_rc_keys,
++	.rc_key_map_size  = ARRAY_SIZE(dvico_portable_rc_keys),
++	.rc_query         = cxusb_rc_query,
++
++	.num_device_descs = 1,
++	.devices = {
++		{   "DViCO FusionHDTV DVB-T NANO2 w/o firmware",
++			{ &cxusb_table[14], NULL },
++			{ &cxusb_table[15], NULL },
++		},
++	}
++};
++
+ static struct usb_driver cxusb_driver = {
+ 	.name		= "dvb_usb_cxusb",
+ 	.probe		= cxusb_probe,
+diff --git a/drivers/media/dvb/dvb-usb/cxusb.h b/drivers/media/dvb/dvb-usb/cxusb.h
+index c8ef775..4768a2c 100644
+--- a/drivers/media/dvb/dvb-usb/cxusb.h
++++ b/drivers/media/dvb/dvb-usb/cxusb.h
+@@ -4,12 +4,9 @@
+ #define DVB_USB_LOG_PREFIX "cxusb"
+ #include "dvb-usb.h"
  
--static int msi = 0;
--module_param(msi, int, 0444);
--MODULE_PARM_DESC(msi, "attempt to use MSI if nonzero (deprecated, use MSI-X instead)");
+-extern int dvb_usb_cxusb_debug;
+-#define deb_info(args...)   dprintk(dvb_usb_cxusb_debug,0x01,args)
+-#define deb_i2c(args...)    if (d->udev->descriptor.idVendor == USB_VID_MEDION) \
+-				dprintk(dvb_usb_cxusb_debug,0x01,args)
 -
- #else /* CONFIG_PCI_MSI */
+ /* usb commands - some of it are guesses, don't have a reference yet */
++#define CMD_BLUEBIRD_GPIO_RW 0x05
++
+ #define CMD_I2C_WRITE     0x08
+ #define CMD_I2C_READ      0x09
  
- #define msi_x (0)
--#define msi   (0)
+diff --git a/drivers/media/dvb/dvb-usb/dib0700_core.c b/drivers/media/dvb/dvb-usb/dib0700_core.c
+index 3ea294e..c9857d5 100644
+--- a/drivers/media/dvb/dvb-usb/dib0700_core.c
++++ b/drivers/media/dvb/dvb-usb/dib0700_core.c
+@@ -243,7 +243,7 @@ int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
+ 	u8 b[4];
  
- #endif /* CONFIG_PCI_MSI */
+ 	b[0] = REQUEST_ENABLE_VIDEO;
+-	b[1] = 0x00;
++	b[1] = (onoff << 4) | 0x00; /* this bit gives a kind of command, rather than enabling something or not */
+ 	b[2] = (0x01 << 4); /* Master mode */
+ 	b[3] = 0x00;
  
-@@ -816,13 +811,11 @@ static int mthca_setup_hca(struct mthca_dev *dev)
+@@ -256,9 +256,6 @@ int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
  
- 	err = mthca_NOP(dev, &status);
- 	if (err || status) {
--		if (dev->mthca_flags & (MTHCA_FLAG_MSI | MTHCA_FLAG_MSI_X)) {
-+		if (dev->mthca_flags & MTHCA_FLAG_MSI_X) {
- 			mthca_warn(dev, "NOP command failed to generate interrupt "
- 				   "(IRQ %d).\n",
--				   dev->mthca_flags & MTHCA_FLAG_MSI_X ?
--				   dev->eq_table.eq[MTHCA_EQ_CMD].msi_x_vector :
--				   dev->pdev->irq);
--			mthca_warn(dev, "Trying again with MSI/MSI-X disabled.\n");
-+				   dev->eq_table.eq[MTHCA_EQ_CMD].msi_x_vector);
-+			mthca_warn(dev, "Trying again with MSI-X disabled.\n");
- 		} else {
- 			mthca_err(dev, "NOP command failed to generate interrupt "
- 				  "(IRQ %d), aborting.\n",
-@@ -1005,7 +998,7 @@ static struct {
- 			   .flags     = 0 },
- 	[ARBEL_COMPAT] = { .latest_fw = MTHCA_FW_VER(4, 8, 200),
- 			   .flags     = MTHCA_FLAG_PCIE },
--	[ARBEL_NATIVE] = { .latest_fw = MTHCA_FW_VER(5, 2, 0),
-+	[ARBEL_NATIVE] = { .latest_fw = MTHCA_FW_VER(5, 3, 0),
- 			   .flags     = MTHCA_FLAG_MEMFREE |
- 					MTHCA_FLAG_PCIE },
- 	[SINAI]        = { .latest_fw = MTHCA_FW_VER(1, 2, 0),
-@@ -1128,29 +1121,12 @@ static int __mthca_init_one(struct pci_dev *pdev, int hca_type)
+ 	b[2] |= st->channel_state;
  
- 	if (msi_x && !mthca_enable_msi_x(mdev))
- 		mdev->mthca_flags |= MTHCA_FLAG_MSI_X;
--	else if (msi) {
--		static int warned;
--
--		if (!warned) {
--			printk(KERN_WARNING PFX "WARNING: MSI support will be "
--			       "removed from the ib_mthca driver in January 2008.\n");
--			printk(KERN_WARNING "    If you are using MSI and cannot "
--			       "switch to MSI-X, please tell "
--			       "<general at lists.openfabrics.org>.\n");
--			++warned;
--		}
+-	if (st->channel_state) /* if at least one channel is active */
+-		b[1] = (0x01 << 4) | 0x00;
 -
--		if (!pci_enable_msi(pdev))
--			mdev->mthca_flags |= MTHCA_FLAG_MSI;
--	}
- 
- 	err = mthca_setup_hca(mdev);
--	if (err == -EBUSY && (mdev->mthca_flags & (MTHCA_FLAG_MSI | MTHCA_FLAG_MSI_X))) {
-+	if (err == -EBUSY && (mdev->mthca_flags & MTHCA_FLAG_MSI_X)) {
- 		if (mdev->mthca_flags & MTHCA_FLAG_MSI_X)
- 			pci_disable_msix(pdev);
--		if (mdev->mthca_flags & MTHCA_FLAG_MSI)
--			pci_disable_msi(pdev);
--		mdev->mthca_flags &= ~(MTHCA_FLAG_MSI_X | MTHCA_FLAG_MSI);
-+		mdev->mthca_flags &= ~MTHCA_FLAG_MSI_X;
- 
- 		err = mthca_setup_hca(mdev);
- 	}
-@@ -1192,8 +1168,6 @@ err_cleanup:
- err_close:
- 	if (mdev->mthca_flags & MTHCA_FLAG_MSI_X)
- 		pci_disable_msix(pdev);
--	if (mdev->mthca_flags & MTHCA_FLAG_MSI)
--		pci_disable_msi(pdev);
- 
- 	mthca_close_hca(mdev);
- 
-@@ -1246,8 +1220,6 @@ static void __mthca_remove_one(struct pci_dev *pdev)
- 
- 		if (mdev->mthca_flags & MTHCA_FLAG_MSI_X)
- 			pci_disable_msix(pdev);
--		if (mdev->mthca_flags & MTHCA_FLAG_MSI)
--			pci_disable_msi(pdev);
- 
- 		ib_dealloc_device(&mdev->ib_dev);
- 		mthca_release_regions(pdev, mdev->mthca_flags &
-diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h b/drivers/infiniband/ulp/ipoib/ipoib.h
-index eb7edab..fe250c6 100644
---- a/drivers/infiniband/ulp/ipoib/ipoib.h
-+++ b/drivers/infiniband/ulp/ipoib/ipoib.h
-@@ -56,42 +56,43 @@
- /* constants */
- 
- enum {
--	IPOIB_PACKET_SIZE         = 2048,
--	IPOIB_BUF_SIZE 		  = IPOIB_PACKET_SIZE + IB_GRH_BYTES,
-+	IPOIB_PACKET_SIZE	  = 2048,
-+	IPOIB_BUF_SIZE		  = IPOIB_PACKET_SIZE + IB_GRH_BYTES,
- 
--	IPOIB_ENCAP_LEN 	  = 4,
-+	IPOIB_ENCAP_LEN		  = 4,
- 
--	IPOIB_CM_MTU              = 0x10000 - 0x10, /* padding to align header to 16 */
--	IPOIB_CM_BUF_SIZE         = IPOIB_CM_MTU  + IPOIB_ENCAP_LEN,
--	IPOIB_CM_HEAD_SIZE 	  = IPOIB_CM_BUF_SIZE % PAGE_SIZE,
--	IPOIB_CM_RX_SG            = ALIGN(IPOIB_CM_BUF_SIZE, PAGE_SIZE) / PAGE_SIZE,
--	IPOIB_RX_RING_SIZE 	  = 128,
--	IPOIB_TX_RING_SIZE 	  = 64,
-+	IPOIB_CM_MTU		  = 0x10000 - 0x10, /* padding to align header to 16 */
-+	IPOIB_CM_BUF_SIZE	  = IPOIB_CM_MTU  + IPOIB_ENCAP_LEN,
-+	IPOIB_CM_HEAD_SIZE	  = IPOIB_CM_BUF_SIZE % PAGE_SIZE,
-+	IPOIB_CM_RX_SG		  = ALIGN(IPOIB_CM_BUF_SIZE, PAGE_SIZE) / PAGE_SIZE,
-+	IPOIB_RX_RING_SIZE	  = 128,
-+	IPOIB_TX_RING_SIZE	  = 64,
- 	IPOIB_MAX_QUEUE_SIZE	  = 8192,
- 	IPOIB_MIN_QUEUE_SIZE	  = 2,
-+	IPOIB_CM_MAX_CONN_QP	  = 4096,
+ 	deb_info("data for streaming: %x %x\n",b[1],b[2]);
  
--	IPOIB_NUM_WC 		  = 4,
-+	IPOIB_NUM_WC		  = 4,
+ 	return dib0700_ctrl_wr(adap->dev, b, 4);
+diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c
+index 58452b5..e709382 100644
+--- a/drivers/media/dvb/dvb-usb/dib0700_devices.c
++++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c
+@@ -94,12 +94,28 @@ static int bristol_frontend_attach(struct dvb_usb_adapter *adap)
+ 		(10 + adap->id) << 1, &bristol_dib3000mc_config[adap->id])) == NULL ? -ENODEV : 0;
+ }
  
- 	IPOIB_MAX_PATH_REC_QUEUE  = 3,
--	IPOIB_MAX_MCAST_QUEUE     = 3,
--
--	IPOIB_FLAG_OPER_UP 	  = 0,
--	IPOIB_FLAG_INITIALIZED    = 1,
--	IPOIB_FLAG_ADMIN_UP 	  = 2,
--	IPOIB_PKEY_ASSIGNED 	  = 3,
--	IPOIB_PKEY_STOP 	  = 4,
--	IPOIB_FLAG_SUBINTERFACE   = 5,
--	IPOIB_MCAST_RUN 	  = 6,
--	IPOIB_STOP_REAPER         = 7,
--	IPOIB_MCAST_STARTED       = 8,
--	IPOIB_FLAG_ADMIN_CM 	  = 9,
-+	IPOIB_MAX_MCAST_QUEUE	  = 3,
++static int eeprom_read(struct i2c_adapter *adap,u8 adrs,u8 *pval)
++{
++	struct i2c_msg msg[2] = {
++		{ .addr = 0x50, .flags = 0,        .buf = &adrs, .len = 1 },
++		{ .addr = 0x50, .flags = I2C_M_RD, .buf = pval,  .len = 1 },
++	};
++	if (i2c_transfer(adap, msg, 2) != 2) return -EREMOTEIO;
++	return 0;
++}
 +
-+	IPOIB_FLAG_OPER_UP	  = 0,
-+	IPOIB_FLAG_INITIALIZED	  = 1,
-+	IPOIB_FLAG_ADMIN_UP	  = 2,
-+	IPOIB_PKEY_ASSIGNED	  = 3,
-+	IPOIB_PKEY_STOP		  = 4,
-+	IPOIB_FLAG_SUBINTERFACE	  = 5,
-+	IPOIB_MCAST_RUN		  = 6,
-+	IPOIB_STOP_REAPER	  = 7,
-+	IPOIB_MCAST_STARTED	  = 8,
-+	IPOIB_FLAG_ADMIN_CM	  = 9,
- 	IPOIB_FLAG_UMCAST	  = 10,
- 
- 	IPOIB_MAX_BACKOFF_SECONDS = 16,
+ static int bristol_tuner_attach(struct dvb_usb_adapter *adap)
+ {
+-	struct dib0700_state *st = adap->dev->priv;
++	struct i2c_adapter *prim_i2c = &adap->dev->i2c_adap;
+ 	struct i2c_adapter *tun_i2c = dib3000mc_get_tuner_i2c_master(adap->fe, 1);
+-	return dvb_attach(mt2060_attach,adap->fe, tun_i2c, &bristol_mt2060_config[adap->id],
+-		st->mt2060_if1[adap->id]) == NULL ? -ENODEV : 0;
++	s8 a;
++	int if1=1220;
++	if (adap->dev->udev->descriptor.idVendor  == USB_VID_HAUPPAUGE &&
++		adap->dev->udev->descriptor.idProduct == USB_PID_HAUPPAUGE_NOVA_T_500_2) {
++		if (!eeprom_read(prim_i2c,0x59 + adap->id,&a)) if1=1220+a;
++	}
++	return dvb_attach(mt2060_attach,adap->fe, tun_i2c,&bristol_mt2060_config[adap->id],
++		if1) == NULL ? -ENODEV : 0;
+ }
  
--	IPOIB_MCAST_FLAG_FOUND 	  = 0,	/* used in set_multicast_list */
-+	IPOIB_MCAST_FLAG_FOUND	  = 0,	/* used in set_multicast_list */
- 	IPOIB_MCAST_FLAG_SENDONLY = 1,
--	IPOIB_MCAST_FLAG_BUSY 	  = 2,	/* joining or already joined */
-+	IPOIB_MCAST_FLAG_BUSY	  = 2,	/* joining or already joined */
- 	IPOIB_MCAST_FLAG_ATTACHED = 3,
+ /* STK7700D: Pinnacle/Terratec/Hauppauge Dual DVB-T Diversity */
+@@ -230,6 +246,27 @@ static struct mt2266_config stk7700d_mt2266_config[2] = {
+ 	}
  };
  
-@@ -117,7 +118,7 @@ struct ipoib_pseudoheader {
- struct ipoib_mcast {
- 	struct ib_sa_mcmember_rec mcmember;
- 	struct ib_sa_multicast	 *mc;
--	struct ipoib_ah          *ah;
-+	struct ipoib_ah		 *ah;
- 
- 	struct rb_node    rb_node;
- 	struct list_head  list;
-@@ -186,27 +187,29 @@ enum ipoib_cm_state {
++static int stk7700P2_frontend_attach(struct dvb_usb_adapter *adap)
++{
++	if (adap->id == 0) {
++		dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
++		msleep(10);
++		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, GPIO10, GPIO_OUT, 0);
++		msleep(10);
++		dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
++		msleep(10);
++		dib7000p_i2c_enumeration(&adap->dev->i2c_adap,1,18,stk7700d_dib7000p_mt2266_config);
++	}
++
++	adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap,0x80+(adap->id << 1),
++				&stk7700d_dib7000p_mt2266_config[adap->id]);
++
++	return adap->fe == NULL ? -ENODEV : 0;
++}
++
+ static int stk7700d_frontend_attach(struct dvb_usb_adapter *adap)
+ {
+ 	if (adap->id == 0) {
+@@ -415,6 +452,35 @@ static struct dvb_usb_rc_key dib0700_rc_keys[] = {
+ 	{ 0x1e, 0x38, KEY_YELLOW },
+ 	{ 0x1e, 0x3b, KEY_GOTO },
+ 	{ 0x1e, 0x3d, KEY_POWER },
++
++	/* Key codes for the Leadtek Winfast DTV Dongle */
++	{ 0x00, 0x42, KEY_POWER },
++	{ 0x07, 0x7c, KEY_TUNER },
++	{ 0x0f, 0x4e, KEY_PRINT }, /* PREVIEW */
++	{ 0x08, 0x40, KEY_SCREEN }, /* full screen toggle*/
++	{ 0x0f, 0x71, KEY_DOT }, /* frequency */
++	{ 0x07, 0x43, KEY_0 },
++	{ 0x0c, 0x41, KEY_1 },
++	{ 0x04, 0x43, KEY_2 },
++	{ 0x0b, 0x7f, KEY_3 },
++	{ 0x0e, 0x41, KEY_4 },
++	{ 0x06, 0x43, KEY_5 },
++	{ 0x09, 0x7f, KEY_6 },
++	{ 0x0d, 0x7e, KEY_7 },
++	{ 0x05, 0x7c, KEY_8 },
++	{ 0x0a, 0x40, KEY_9 },
++	{ 0x0e, 0x4e, KEY_CLEAR },
++	{ 0x04, 0x7c, KEY_CHANNEL }, /* show channel number */
++	{ 0x0f, 0x41, KEY_LAST }, /* recall */
++	{ 0x03, 0x42, KEY_MUTE },
++	{ 0x06, 0x4c, KEY_RESERVED }, /* PIP button*/
++	{ 0x01, 0x72, KEY_SHUFFLE }, /* SNAPSHOT */
++	{ 0x0c, 0x4e, KEY_PLAYPAUSE }, /* TIMESHIFT */
++	{ 0x0b, 0x70, KEY_RECORD },
++	{ 0x03, 0x7d, KEY_VOLUMEUP },
++	{ 0x01, 0x7d, KEY_VOLUMEDOWN },
++	{ 0x02, 0x42, KEY_CHANNELUP },
++	{ 0x00, 0x7d, KEY_CHANNELDOWN },
  };
  
- struct ipoib_cm_rx {
--	struct ib_cm_id     *id;
--	struct ib_qp        *qp;
--	struct list_head     list;
--	struct net_device   *dev;
--	unsigned long        jiffies;
--	enum ipoib_cm_state  state;
-+	struct ib_cm_id	       *id;
-+	struct ib_qp	       *qp;
-+	struct ipoib_cm_rx_buf *rx_ring;
-+	struct list_head	list;
-+	struct net_device      *dev;
-+	unsigned long		jiffies;
-+	enum ipoib_cm_state	state;
-+	int			recv_count;
- };
+ /* STK7700P: Hauppauge Nova-T Stick, AVerMedia Volar */
+@@ -578,16 +644,22 @@ static struct mt2060_config stk7700p_mt2060_config = {
  
- struct ipoib_cm_tx {
--	struct ib_cm_id     *id;
--	struct ib_qp        *qp;
-+	struct ib_cm_id	    *id;
-+	struct ib_qp	    *qp;
- 	struct list_head     list;
- 	struct net_device   *dev;
- 	struct ipoib_neigh  *neigh;
- 	struct ipoib_path   *path;
- 	struct ipoib_tx_buf *tx_ring;
--	unsigned             tx_head;
--	unsigned             tx_tail;
--	unsigned long        flags;
--	u32                  mtu;
--	struct ib_wc         ibwc[IPOIB_NUM_WC];
-+	unsigned	     tx_head;
-+	unsigned	     tx_tail;
-+	unsigned long	     flags;
-+	u32		     mtu;
-+	struct ib_wc	     ibwc[IPOIB_NUM_WC];
- };
+ static int stk7700p_tuner_attach(struct dvb_usb_adapter *adap)
+ {
++	struct i2c_adapter *prim_i2c = &adap->dev->i2c_adap;
+ 	struct dib0700_state *st = adap->dev->priv;
+ 	struct i2c_adapter *tun_i2c;
+-
++	s8 a;
++	int if1=1220;
++	if (adap->dev->udev->descriptor.idVendor  == USB_VID_HAUPPAUGE &&
++		adap->dev->udev->descriptor.idProduct == USB_PID_HAUPPAUGE_NOVA_T_STICK) {
++		if (!eeprom_read(prim_i2c,0x58,&a)) if1=1220+a;
++	}
+ 	if (st->is_dib7000pc)
+ 		tun_i2c = dib7000p_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_TUNER, 1);
+ 	else
+ 		tun_i2c = dib7000m_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_TUNER, 1);
  
- struct ipoib_cm_rx_buf {
-@@ -215,25 +218,28 @@ struct ipoib_cm_rx_buf {
- };
+ 	return dvb_attach(mt2060_attach, adap->fe, tun_i2c, &stk7700p_mt2060_config,
+-		st->mt2060_if1[0]) == NULL ? -ENODEV : 0;
++		if1) == NULL ? -ENODEV : 0;
+ }
  
- struct ipoib_cm_dev_priv {
--	struct ib_srq  	       *srq;
-+	struct ib_srq	       *srq;
- 	struct ipoib_cm_rx_buf *srq_ring;
--	struct ib_cm_id        *id;
--	struct list_head        passive_ids;   /* state: LIVE */
--	struct list_head        rx_error_list; /* state: ERROR */
--	struct list_head        rx_flush_list; /* state: FLUSH, drain not started */
--	struct list_head        rx_drain_list; /* state: FLUSH, drain started */
--	struct list_head        rx_reap_list;  /* state: FLUSH, drain done */
-+	struct ib_cm_id	       *id;
-+	struct list_head	passive_ids;   /* state: LIVE */
-+	struct list_head	rx_error_list; /* state: ERROR */
-+	struct list_head	rx_flush_list; /* state: FLUSH, drain not started */
-+	struct list_head	rx_drain_list; /* state: FLUSH, drain started */
-+	struct list_head	rx_reap_list;  /* state: FLUSH, drain done */
- 	struct work_struct      start_task;
- 	struct work_struct      reap_task;
- 	struct work_struct      skb_task;
- 	struct work_struct      rx_reap_task;
- 	struct delayed_work     stale_task;
- 	struct sk_buff_head     skb_queue;
--	struct list_head        start_list;
--	struct list_head        reap_list;
--	struct ib_wc            ibwc[IPOIB_NUM_WC];
--	struct ib_sge           rx_sge[IPOIB_CM_RX_SG];
-+	struct list_head	start_list;
-+	struct list_head	reap_list;
-+	struct ib_wc		ibwc[IPOIB_NUM_WC];
-+	struct ib_sge		rx_sge[IPOIB_CM_RX_SG];
- 	struct ib_recv_wr       rx_wr;
-+	int			nonsrq_conn_qp;
-+	int			max_cm_mtu;
-+	int			num_frags;
- };
+ /* DIB7070 generic */
+@@ -709,6 +781,8 @@ static struct dib7000p_config dib7070p_dib7000p_config = {
+ 	.agc_config_count = 1,
+ 	.agc = &dib7070_agc_config,
+ 	.bw  = &dib7070_bw_config_12_mhz,
++	.tuner_is_baseband = 1,
++	.spur_protect = 1,
  
- /*
-@@ -269,30 +275,30 @@ struct ipoib_dev_priv {
- 	struct work_struct pkey_event_task;
+ 	.gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS,
+ 	.gpio_val = DIB7000P_GPIO_DEFAULT_VALUES,
+@@ -748,6 +822,8 @@ static struct dib7000p_config stk7070pd_dib7000p_config[2] = {
+ 		.agc_config_count = 1,
+ 		.agc = &dib7070_agc_config,
+ 		.bw  = &dib7070_bw_config_12_mhz,
++		.tuner_is_baseband = 1,
++		.spur_protect = 1,
  
- 	struct ib_device *ca;
--	u8            	  port;
--	u16           	  pkey;
--	u16               pkey_index;
--	struct ib_pd  	 *pd;
--	struct ib_mr  	 *mr;
--	struct ib_cq  	 *cq;
--	struct ib_qp  	 *qp;
--	u32           	  qkey;
-+	u8		  port;
-+	u16		  pkey;
-+	u16		  pkey_index;
-+	struct ib_pd	 *pd;
-+	struct ib_mr	 *mr;
-+	struct ib_cq	 *cq;
-+	struct ib_qp	 *qp;
-+	u32		  qkey;
+ 		.gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS,
+ 		.gpio_val = DIB7000P_GPIO_DEFAULT_VALUES,
+@@ -760,6 +836,8 @@ static struct dib7000p_config stk7070pd_dib7000p_config[2] = {
+ 		.agc_config_count = 1,
+ 		.agc = &dib7070_agc_config,
+ 		.bw  = &dib7070_bw_config_12_mhz,
++		.tuner_is_baseband = 1,
++		.spur_protect = 1,
  
- 	union ib_gid local_gid;
--	u16          local_lid;
-+	u16	     local_lid;
+ 		.gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS,
+ 		.gpio_val = DIB7000P_GPIO_DEFAULT_VALUES,
+@@ -821,6 +899,12 @@ struct usb_device_id dib0700_usb_id_table[] = {
+ 		{ USB_DEVICE(USB_VID_PINNACLE,  USB_PID_PINNACLE_PCTV_DUAL_DIVERSITY_DVB_T) },
+ 		{ USB_DEVICE(USB_VID_COMPRO,    USB_PID_COMPRO_VIDEOMATE_U500_PC) },
+ /* 20 */{ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_EXPRESS) },
++		{ USB_DEVICE(USB_VID_GIGABYTE,  USB_PID_GIGABYTE_U7000) },
++		{ USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ARTEC_T14BR) },
++		{ USB_DEVICE(USB_VID_ASUS,      USB_PID_ASUS_U3000) },
++		{ USB_DEVICE(USB_VID_ASUS,      USB_PID_ASUS_U3100) },
++/* 25 */	{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_STICK_3) },
++		{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_MYTV_T) },
+ 		{ 0 }		/* Terminating entry */
+ };
+ MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table);
+@@ -862,7 +946,7 @@ struct dvb_usb_device_properties dib0700_devices[] = {
+ 			},
+ 		},
  
- 	unsigned int admin_mtu;
- 	unsigned int mcast_mtu;
+-		.num_device_descs = 7,
++		.num_device_descs = 8,
+ 		.devices = {
+ 			{   "DiBcom STK7700P reference design",
+ 				{ &dib0700_usb_id_table[0], &dib0700_usb_id_table[1] },
+@@ -891,6 +975,10 @@ struct dvb_usb_device_properties dib0700_devices[] = {
+ 			{   "AVerMedia AVerTV DVB-T Express",
+ 				{ &dib0700_usb_id_table[20] },
+ 				{ NULL },
++			},
++			{   "Gigabyte U7000",
++				{ &dib0700_usb_id_table[21], NULL },
++				{ NULL },
+ 			}
+ 		},
  
- 	struct ipoib_rx_buf *rx_ring;
+@@ -961,7 +1049,7 @@ struct dvb_usb_device_properties dib0700_devices[] = {
+ 			{   "DiBcom STK7700D reference design",
+ 				{ &dib0700_usb_id_table[14], NULL },
+ 				{ NULL },
+-			},
++			}
+ 		},
  
--	spinlock_t           tx_lock;
-+	spinlock_t	     tx_lock;
- 	struct ipoib_tx_buf *tx_ring;
--	unsigned             tx_head;
--	unsigned             tx_tail;
--	struct ib_sge        tx_sge;
-+	unsigned	     tx_head;
-+	unsigned	     tx_tail;
-+	struct ib_sge	     tx_sge;
- 	struct ib_send_wr    tx_wr;
--	unsigned             tx_outstanding;
-+	unsigned	     tx_outstanding;
+ 		.rc_interval      = DEFAULT_RC_INTERVAL,
+@@ -974,6 +1062,25 @@ struct dvb_usb_device_properties dib0700_devices[] = {
+ 		.num_adapters = 1,
+ 		.adapter = {
+ 			{
++				.frontend_attach  = stk7700P2_frontend_attach,
++				.tuner_attach     = stk7700d_tuner_attach,
++
++				DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
++			},
++		},
++
++		.num_device_descs = 1,
++		.devices = {
++			{   "ASUS My Cinema U3000 Mini DVBT Tuner",
++				{ &dib0700_usb_id_table[23], NULL },
++				{ NULL },
++			},
++		}
++	}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
++
++		.num_adapters = 1,
++		.adapter = {
++			{
+ 				.frontend_attach  = stk7070p_frontend_attach,
+ 				.tuner_attach     = dib7070p_tuner_attach,
  
- 	struct ib_wc ibwc[IPOIB_NUM_WC];
+@@ -983,7 +1090,7 @@ struct dvb_usb_device_properties dib0700_devices[] = {
+ 			},
+ 		},
  
-@@ -317,10 +323,10 @@ struct ipoib_dev_priv {
+-		.num_device_descs = 2,
++		.num_device_descs = 6,
+ 		.devices = {
+ 			{   "DiBcom STK7070P reference design",
+ 				{ &dib0700_usb_id_table[15], NULL },
+@@ -993,7 +1100,29 @@ struct dvb_usb_device_properties dib0700_devices[] = {
+ 				{ &dib0700_usb_id_table[16], NULL },
+ 				{ NULL },
+ 			},
+-		}
++			{   "Artec T14BR DVB-T",
++				{ &dib0700_usb_id_table[22], NULL },
++				{ NULL },
++			},
++			{   "ASUS My Cinema U3100 Mini DVBT Tuner",
++				{ &dib0700_usb_id_table[24], NULL },
++				{ NULL },
++			},
++			{   "Hauppauge Nova-T Stick",
++				{ &dib0700_usb_id_table[25], NULL },
++				{ NULL },
++			},
++			{   "Hauppauge Nova-T MyTV.t",
++				{ &dib0700_usb_id_table[26], 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,
  
- struct ipoib_ah {
- 	struct net_device *dev;
--	struct ib_ah      *ah;
-+	struct ib_ah	  *ah;
- 	struct list_head   list;
--	struct kref        ref;
--	unsigned           last_send;
-+	struct kref	   ref;
-+	unsigned	   last_send;
+ 		.num_adapters = 2,
+@@ -1024,7 +1153,7 @@ struct dvb_usb_device_properties dib0700_devices[] = {
+ 			{   "Pinnacle PCTV Dual DVB-T Diversity Stick",
+ 				{ &dib0700_usb_id_table[18], NULL },
+ 				{ NULL },
+-			},
++			}
+ 		}
+ 	},
  };
+diff --git a/drivers/media/dvb/dvb-usb/digitv.c b/drivers/media/dvb/dvb-usb/digitv.c
+index bca1e09..3acbda4 100644
+--- a/drivers/media/dvb/dvb-usb/digitv.c
++++ b/drivers/media/dvb/dvb-usb/digitv.c
+@@ -17,9 +17,10 @@
+ #include "nxt6000.h"
  
- struct ipoib_path {
-@@ -331,11 +337,11 @@ struct ipoib_path {
+ /* debug */
+-int dvb_usb_digitv_debug;
++static int dvb_usb_digitv_debug;
+ module_param_named(debug,dvb_usb_digitv_debug, int, 0644);
+ MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS);
++#define deb_rc(args...)   dprintk(dvb_usb_digitv_debug,0x01,args)
  
- 	struct list_head      neigh_list;
+ static int digitv_ctrl_msg(struct dvb_usb_device *d,
+ 		u8 cmd, u8 vv, u8 *wbuf, int wlen, u8 *rbuf, int rlen)
+diff --git a/drivers/media/dvb/dvb-usb/digitv.h b/drivers/media/dvb/dvb-usb/digitv.h
+index 8b43e3d..908c09f 100644
+--- a/drivers/media/dvb/dvb-usb/digitv.h
++++ b/drivers/media/dvb/dvb-usb/digitv.h
+@@ -8,9 +8,6 @@ struct digitv_state {
+     int is_nxt6000;
+ };
  
--	int                   query_id;
-+	int		      query_id;
- 	struct ib_sa_query   *query;
- 	struct completion     done;
+-extern int dvb_usb_digitv_debug;
+-#define deb_rc(args...)   dprintk(dvb_usb_digitv_debug,0x01,args)
+-
+ /* protocol (from usblogging and the SDK:
+  *
+  * Always 7 bytes bulk message(s) for controlling
+diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
+index 4fa3e89..aa4844e 100644
+--- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
++++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
+@@ -15,7 +15,9 @@
+ #define USB_VID_ALCOR_MICRO			0x058f
+ #define USB_VID_ALINK				0x05e3
+ #define USB_VID_ANCHOR				0x0547
++#define USB_VID_ANSONIC				0x10b9
+ #define USB_VID_ANUBIS_ELECTRONIC		0x10fd
++#define USB_VID_ASUS				0x0b05
+ #define USB_VID_AVERMEDIA			0x07ca
+ #define USB_VID_COMPRO				0x185b
+ #define USB_VID_COMPRO_UNK			0x145f
+@@ -44,12 +46,16 @@
+ #define USB_VID_ULTIMA_ELECTRONIC		0x05d8
+ #define USB_VID_UNIWILL				0x1584
+ #define USB_VID_WIDEVIEW			0x14aa
++/* dom : pour gigabyte u7000 */
++#define USB_VID_GIGABYTE			0x1044
++
  
--	struct rb_node        rb_node;
-+	struct rb_node	      rb_node;
- 	struct list_head      list;
- };
+ /* Product IDs */
+ #define USB_PID_ADSTECH_USB2_COLD			0xa333
+ #define USB_PID_ADSTECH_USB2_WARM			0xa334
+ #define USB_PID_AFATECH_AF9005				0x9020
+ #define USB_VID_ALINK_DTU				0xf170
++#define USB_PID_ANSONIC_DVBT_USB			0x6000
+ #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 +75,7 @@
+ #define USB_PID_DIBCOM_STK7700P				0x1e14
+ #define USB_PID_DIBCOM_STK7700P_PC			0x1e78
+ #define USB_PID_DIBCOM_STK7700D				0x1ef0
++#define USB_PID_DIBCOM_STK7700_U7000			0x7001
+ #define USB_PID_DIBCOM_STK7070P				0x1ebc
+ #define USB_PID_DIBCOM_STK7070PD			0x1ebe
+ #define USB_PID_DIBCOM_ANCHOR_2135_COLD			0x2131
+@@ -99,6 +106,7 @@
+ #define USB_PID_ULTIMA_TVBOX_USB2_WARM			0x810a
+ #define USB_PID_ARTEC_T14_COLD				0x810b
+ #define USB_PID_ARTEC_T14_WARM				0x810c
++#define USB_PID_ARTEC_T14BR				0x810f
+ #define USB_PID_ULTIMA_TVBOX_USB2_FX_COLD		0x8613
+ #define USB_PID_ULTIMA_TVBOX_USB2_FX_WARM		0x1002
+ #define USB_PID_UNK_HYPER_PALTEK_COLD			0x005e
+@@ -120,6 +128,8 @@
+ #define USB_PID_HAUPPAUGE_NOVA_T_500_2			0x9950
+ #define USB_PID_HAUPPAUGE_NOVA_T_STICK			0x7050
+ #define USB_PID_HAUPPAUGE_NOVA_T_STICK_2		0x7060
++#define USB_PID_HAUPPAUGE_NOVA_T_STICK_3		0x7070
++#define USB_PID_HAUPPAUGE_MYTV_T			0x7080
+ #define USB_PID_HAUPPAUGE_NOVA_TD_STICK			0x9580
+ #define USB_PID_AVERMEDIA_EXPRESS			0xb568
+ #define USB_PID_AVERMEDIA_VOLAR				0xa807
+@@ -143,6 +153,9 @@
+ #define USB_PID_DVICO_BLUEBIRD_DUAL_1_WARM		0xdb51
+ #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_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
+ #define USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_WARM		0xdb55
+ #define USB_PID_MEDION_MD95700				0x0932
+@@ -170,6 +183,9 @@
+ #define USB_PID_OPERA1_WARM				0x3829
+ #define USB_PID_LIFEVIEW_TV_WALKER_TWIN_COLD		0x0514
+ #define USB_PID_LIFEVIEW_TV_WALKER_TWIN_WARM		0x0513
+-
++/* dom pour gigabyte u7000 */
++#define USB_PID_GIGABYTE_U7000				0x7001
++#define USB_PID_ASUS_U3000				0x171f
++#define USB_PID_ASUS_U3100				0x173f
  
-@@ -344,7 +350,7 @@ struct ipoib_neigh {
- #ifdef CONFIG_INFINIBAND_IPOIB_CM
- 	struct ipoib_cm_tx *cm;
  #endif
--	union ib_gid        dgid;
-+	union ib_gid	    dgid;
- 	struct sk_buff_head queue;
- 
- 	struct neighbour   *neighbour;
-@@ -455,12 +461,14 @@ void ipoib_drain_cq(struct net_device *dev);
+diff --git a/drivers/media/dvb/dvb-usb/gl861.c b/drivers/media/dvb/dvb-usb/gl861.c
+index f01d99c..6b99d9f 100644
+--- a/drivers/media/dvb/dvb-usb/gl861.c
++++ b/drivers/media/dvb/dvb-usb/gl861.c
+@@ -56,12 +56,12 @@ static int gl861_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
+ 	struct dvb_usb_device *d = i2c_get_adapdata(adap);
+ 	int i;
  
- #ifdef CONFIG_INFINIBAND_IPOIB_CM
+-	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+-		return -EAGAIN;
+-
+ 	if (num > 2)
+ 		return -EINVAL;
  
--#define IPOIB_FLAGS_RC          0x80
--#define IPOIB_FLAGS_UC          0x40
-+#define IPOIB_FLAGS_RC		0x80
-+#define IPOIB_FLAGS_UC		0x40
++	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)) {
+diff --git a/drivers/media/dvb/dvb-usb/gp8psk.c b/drivers/media/dvb/dvb-usb/gp8psk.c
+index 92147ee..83e8535 100644
+--- a/drivers/media/dvb/dvb-usb/gp8psk.c
++++ b/drivers/media/dvb/dvb-usb/gp8psk.c
+@@ -171,22 +171,6 @@ static int gp8psk_power_ctrl(struct dvb_usb_device *d, int onoff)
+ 	return 0;
+ }
  
- /* We don't support UC connections at the moment */
- #define IPOIB_CM_SUPPORTED(ha)   (ha[0] & (IPOIB_FLAGS_RC))
+-int gp8psk_bcm4500_reload(struct dvb_usb_device *d)
+-{
+-	u8 buf;
+-	int gp_product_id = le16_to_cpu(d->udev->descriptor.idProduct);
+-	/* Turn off 8psk power */
+-	if (gp8psk_usb_in_op(d, BOOT_8PSK, 0, 0, &buf, 1))
+-		return -EINVAL;
+-	/* Turn On 8psk power */
+-	if (gp8psk_usb_in_op(d, BOOT_8PSK, 1, 0, &buf, 1))
+-		return -EINVAL;
+-	/* load BCM4500 firmware */
+-	if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM)
+-		if (gp8psk_load_bcm4500fw(d))
+-			return EINVAL;
+-	return 0;
+-}
  
-+extern int ipoib_max_conn_qp;
-+
- static inline int ipoib_cm_admin_enabled(struct net_device *dev)
+ static int gp8psk_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
  {
- 	struct ipoib_dev_priv *priv = netdev_priv(dev);
-@@ -491,6 +499,18 @@ static inline void ipoib_cm_set(struct ipoib_neigh *neigh, struct ipoib_cm_tx *t
- 	neigh->cm = tx;
- }
+diff --git a/drivers/media/dvb/dvb-usb/gp8psk.h b/drivers/media/dvb/dvb-usb/gp8psk.h
+index e83a575..e5cd814 100644
+--- a/drivers/media/dvb/dvb-usb/gp8psk.h
++++ b/drivers/media/dvb/dvb-usb/gp8psk.h
+@@ -92,6 +92,5 @@ extern struct dvb_frontend * gp8psk_fe_attach(struct dvb_usb_device *d);
+ extern int gp8psk_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen);
+ extern int gp8psk_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value,
+ 			     u16 index, u8 *b, int blen);
+-extern int gp8psk_bcm4500_reload(struct dvb_usb_device *d);
  
-+static inline int ipoib_cm_has_srq(struct net_device *dev)
-+{
-+	struct ipoib_dev_priv *priv = netdev_priv(dev);
-+	return !!priv->cm.srq;
-+}
-+
-+static inline unsigned int ipoib_cm_max_mtu(struct net_device *dev)
-+{
-+	struct ipoib_dev_priv *priv = netdev_priv(dev);
-+	return priv->cm.max_cm_mtu;
-+}
+ #endif
+diff --git a/drivers/media/dvb/dvb-usb/opera1.c b/drivers/media/dvb/dvb-usb/opera1.c
+index d7c0495..21935bf 100644
+--- a/drivers/media/dvb/dvb-usb/opera1.c
++++ b/drivers/media/dvb/dvb-usb/opera1.c
+@@ -10,7 +10,9 @@
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+ 
+-#include "opera1.h"
++#define DVB_USB_LOG_PREFIX "opera"
 +
- void ipoib_cm_send(struct net_device *dev, struct sk_buff *skb, struct ipoib_cm_tx *tx);
- int ipoib_cm_dev_open(struct net_device *dev);
- void ipoib_cm_dev_stop(struct net_device *dev);
-@@ -500,7 +520,7 @@ void ipoib_cm_dev_cleanup(struct net_device *dev);
- struct ipoib_cm_tx *ipoib_cm_create_tx(struct net_device *dev, struct ipoib_path *path,
- 				    struct ipoib_neigh *neigh);
- void ipoib_cm_destroy_tx(struct ipoib_cm_tx *tx);
--void ipoib_cm_skb_too_long(struct net_device* dev, struct sk_buff *skb,
-+void ipoib_cm_skb_too_long(struct net_device *dev, struct sk_buff *skb,
- 			   unsigned int mtu);
- void ipoib_cm_handle_rx_wc(struct net_device *dev, struct ib_wc *wc);
- void ipoib_cm_handle_tx_wc(struct net_device *dev, struct ib_wc *wc);
-@@ -508,6 +528,8 @@ void ipoib_cm_handle_tx_wc(struct net_device *dev, struct ib_wc *wc);
++#include "dvb-usb.h"
+ #include "stv0299.h"
  
- struct ipoib_cm_tx;
+ #define OPERA_READ_MSG 0
+@@ -38,7 +40,7 @@ struct opera_rc_keys {
+ 	u32 event;
+ };
  
-+#define ipoib_max_conn_qp 0
-+
- static inline int ipoib_cm_admin_enabled(struct net_device *dev)
- {
- 	return 0;
-@@ -533,6 +555,16 @@ static inline void ipoib_cm_set(struct ipoib_neigh *neigh, struct ipoib_cm_tx *t
- {
+-int dvb_usb_opera1_debug;
++static int dvb_usb_opera1_debug;
+ module_param_named(debug, dvb_usb_opera1_debug, int, 0644);
+ MODULE_PARM_DESC(debug,
+ 		 "set debugging level (1=info,xfer=2,pll=4,ts=8,err=16,rc=32,fw=64 (or-able))."
+diff --git a/drivers/media/dvb/dvb-usb/opera1.h b/drivers/media/dvb/dvb-usb/opera1.h
+deleted file mode 100644
+index 5317442..0000000
+--- a/drivers/media/dvb/dvb-usb/opera1.h
++++ /dev/null
+@@ -1,9 +0,0 @@
+-#ifndef _OPERA1_H_
+-#define _OPERA1_H_
+-
+-#define DVB_USB_LOG_PREFIX "opera"
+-#include "dvb-usb.h"
+-
+-extern int dvb_usb_opera1_debug;
+-#define deb_xfer(args...) dprintk(dvb_usb_opera1_debug,0x02,args)
+-#endif
+diff --git a/drivers/media/dvb/dvb-usb/vp702x.c b/drivers/media/dvb/dvb-usb/vp702x.c
+index 16533b3..e553c13 100644
+--- a/drivers/media/dvb/dvb-usb/vp702x.c
++++ b/drivers/media/dvb/dvb-usb/vp702x.c
+@@ -56,7 +56,7 @@ int vp702x_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8
+ 	return ret;
  }
  
-+static inline int ipoib_cm_has_srq(struct net_device *dev)
-+{
-+	return 0;
-+}
-+
-+static inline unsigned int ipoib_cm_max_mtu(struct net_device *dev)
-+{
-+	return 0;
-+}
-+
- static inline
- void ipoib_cm_send(struct net_device *dev, struct sk_buff *skb, struct ipoib_cm_tx *tx)
+-int vp702x_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value,
++static int vp702x_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value,
+ 			     u16 index, u8 *b, int blen)
  {
-@@ -582,7 +614,7 @@ int ipoib_cm_add_mode_attr(struct net_device *dev)
+ 	int ret;
+@@ -204,19 +204,6 @@ static int vp702x_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
  	return 0;
  }
  
--static inline void ipoib_cm_skb_too_long(struct net_device* dev, struct sk_buff *skb,
-+static inline void ipoib_cm_skb_too_long(struct net_device *dev, struct sk_buff *skb,
- 					 unsigned int mtu)
- {
- 	dev_kfree_skb_any(skb);
-@@ -624,12 +656,12 @@ extern struct ib_sa_client ipoib_sa_client;
- extern int ipoib_debug_level;
- 
- #define ipoib_dbg(priv, format, arg...)			\
--	do {					        \
-+	do {						\
- 		if (ipoib_debug_level > 0)			\
- 			ipoib_printk(KERN_DEBUG, priv, format , ## arg); \
- 	} while (0)
- #define ipoib_dbg_mcast(priv, format, arg...)		\
--	do {					        \
-+	do {						\
- 		if (mcast_debug_level > 0)		\
- 			ipoib_printk(KERN_DEBUG, priv, format , ## arg); \
- 	} while (0)
-@@ -642,7 +674,7 @@ extern int ipoib_debug_level;
+-int vp702x_power_ctrl(struct dvb_usb_device *d, int onoff)
+-{
+-	struct vp702x_device_state *st = d->priv;
+-
+-	if (st->power_state == 0 && onoff)
+-		vp702x_usb_out_op(d, SET_TUNER_POWER_REQ, 1, 7, NULL, 0);
+-	else if (st->power_state == 1 && onoff == 0)
+-		vp702x_usb_out_op(d, SET_TUNER_POWER_REQ, 0, 7, NULL, 0);
+-
+-	st->power_state = onoff;
+-
+-	return 0;
+-}
  
- #ifdef CONFIG_INFINIBAND_IPOIB_DEBUG_DATA
- #define ipoib_dbg_data(priv, format, arg...)		\
--	do {					        \
-+	do {						\
- 		if (data_debug_level > 0)		\
- 			ipoib_printk(KERN_DEBUG, priv, format , ## arg); \
- 	} while (0)
-diff --git a/drivers/infiniband/ulp/ipoib/ipoib_cm.c b/drivers/infiniband/ulp/ipoib/ipoib_cm.c
-index 059cf92..1818f95 100644
---- a/drivers/infiniband/ulp/ipoib/ipoib_cm.c
-+++ b/drivers/infiniband/ulp/ipoib/ipoib_cm.c
-@@ -39,6 +39,15 @@
- #include <linux/icmpv6.h>
- #include <linux/delay.h>
+ static int vp702x_read_mac_addr(struct dvb_usb_device *d,u8 mac[6])
+ {
+diff --git a/drivers/media/dvb/dvb-usb/vp702x.h b/drivers/media/dvb/dvb-usb/vp702x.h
+index 25a9dee..c2f97f9 100644
+--- a/drivers/media/dvb/dvb-usb/vp702x.h
++++ b/drivers/media/dvb/dvb-usb/vp702x.h
+@@ -102,7 +102,5 @@ extern struct dvb_frontend * vp702x_fe_attach(struct dvb_usb_device *d);
  
-+#include "ipoib.h"
-+
-+int ipoib_max_conn_qp = 128;
-+
-+module_param_named(max_nonsrq_conn_qp, ipoib_max_conn_qp, int, 0444);
-+MODULE_PARM_DESC(max_nonsrq_conn_qp,
-+		 "Max number of connected-mode QPs per interface "
-+		 "(applied only if shared receive queue is not available)");
-+
- #ifdef CONFIG_INFINIBAND_IPOIB_DEBUG_DATA
- static int data_debug_level;
+ extern int vp702x_usb_inout_op(struct dvb_usb_device *d, u8 *o, int olen, u8 *i, int ilen, int msec);
+ extern int vp702x_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen);
+-extern int vp702x_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen);
+-extern int vp702x_power_ctrl(struct dvb_usb_device *d, int onoff);
  
-@@ -47,8 +56,6 @@ MODULE_PARM_DESC(cm_data_debug_level,
- 		 "Enable data path debug tracing for connected mode if > 0");
  #endif
+diff --git a/drivers/media/dvb/dvb-usb/vp7045.c b/drivers/media/dvb/dvb-usb/vp7045.c
+index 5bbd2d5..c172bab 100644
+--- a/drivers/media/dvb/dvb-usb/vp7045.c
++++ b/drivers/media/dvb/dvb-usb/vp7045.c
+@@ -15,9 +15,12 @@
+ #include "vp7045.h"
  
--#include "ipoib.h"
--
- #define IPOIB_CM_IETF_ID 0x1000000000000000ULL
- 
- #define IPOIB_CM_RX_UPDATE_TIME (256 * HZ)
-@@ -81,7 +88,7 @@ static void ipoib_cm_dma_unmap_rx(struct ipoib_dev_priv *priv, int frags,
- 		ib_dma_unmap_single(priv->ca, mapping[i + 1], PAGE_SIZE, DMA_FROM_DEVICE);
- }
+ /* debug */
+-int dvb_usb_vp7045_debug;
++static int dvb_usb_vp7045_debug;
+ module_param_named(debug,dvb_usb_vp7045_debug, int, 0644);
+ MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,rc=4 (or-able))." DVB_USB_DEBUG_STATUS);
++#define deb_info(args...) dprintk(dvb_usb_vp7045_debug,0x01,args)
++#define deb_xfer(args...) dprintk(dvb_usb_vp7045_debug,0x02,args)
++#define deb_rc(args...)   dprintk(dvb_usb_vp7045_debug,0x04,args)
  
--static int ipoib_cm_post_receive(struct net_device *dev, int id)
-+static int ipoib_cm_post_receive_srq(struct net_device *dev, int id)
+ int vp7045_usb_op(struct dvb_usb_device *d, u8 cmd, u8 *out, int outlen, u8 *in, int inlen, int msec)
  {
- 	struct ipoib_dev_priv *priv = netdev_priv(dev);
- 	struct ib_recv_wr *bad_wr;
-@@ -89,13 +96,13 @@ static int ipoib_cm_post_receive(struct net_device *dev, int id)
- 
- 	priv->cm.rx_wr.wr_id = id | IPOIB_OP_CM | IPOIB_OP_RECV;
+diff --git a/drivers/media/dvb/dvb-usb/vp7045.h b/drivers/media/dvb/dvb-usb/vp7045.h
+index 9ce21a2..969688f 100644
+--- a/drivers/media/dvb/dvb-usb/vp7045.h
++++ b/drivers/media/dvb/dvb-usb/vp7045.h
+@@ -17,11 +17,6 @@
+ #define DVB_USB_LOG_PREFIX "vp7045"
+ #include "dvb-usb.h"
  
--	for (i = 0; i < IPOIB_CM_RX_SG; ++i)
-+	for (i = 0; i < priv->cm.num_frags; ++i)
- 		priv->cm.rx_sge[i].addr = priv->cm.srq_ring[id].mapping[i];
+-extern int dvb_usb_vp7045_debug;
+-#define deb_info(args...) dprintk(dvb_usb_vp7045_debug,0x01,args)
+-#define deb_xfer(args...) dprintk(dvb_usb_vp7045_debug,0x02,args)
+-#define deb_rc(args...)   dprintk(dvb_usb_vp7045_debug,0x04,args)
+-
+ /* vp7045 commands */
  
- 	ret = ib_post_srq_recv(priv->cm.srq, &priv->cm.rx_wr, &bad_wr);
- 	if (unlikely(ret)) {
- 		ipoib_warn(priv, "post srq failed for buf %d (%d)\n", id, ret);
--		ipoib_cm_dma_unmap_rx(priv, IPOIB_CM_RX_SG - 1,
-+		ipoib_cm_dma_unmap_rx(priv, priv->cm.num_frags - 1,
- 				      priv->cm.srq_ring[id].mapping);
- 		dev_kfree_skb_any(priv->cm.srq_ring[id].skb);
- 		priv->cm.srq_ring[id].skb = NULL;
-@@ -104,7 +111,33 @@ static int ipoib_cm_post_receive(struct net_device *dev, int id)
- 	return ret;
- }
+ /* Twinhan Vendor requests */
+diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig
+index 59b9ed1..9ad86ce 100644
+--- a/drivers/media/dvb/frontends/Kconfig
++++ b/drivers/media/dvb/frontends/Kconfig
+@@ -316,6 +316,13 @@ config DVB_TDA827X
+ 	help
+ 	  A DVB-T silicon tuner module. Say Y when you want to support this tuner.
  
--static struct sk_buff *ipoib_cm_alloc_rx_skb(struct net_device *dev, int id, int frags,
-+static int ipoib_cm_post_receive_nonsrq(struct net_device *dev,
-+					struct ipoib_cm_rx *rx, int id)
-+{
-+	struct ipoib_dev_priv *priv = netdev_priv(dev);
-+	struct ib_recv_wr *bad_wr;
-+	int i, ret;
-+
-+	priv->cm.rx_wr.wr_id = id | IPOIB_OP_CM | IPOIB_OP_RECV;
-+
-+	for (i = 0; i < IPOIB_CM_RX_SG; ++i)
-+		priv->cm.rx_sge[i].addr = rx->rx_ring[id].mapping[i];
-+
-+	ret = ib_post_recv(rx->qp, &priv->cm.rx_wr, &bad_wr);
-+	if (unlikely(ret)) {
-+		ipoib_warn(priv, "post recv failed for buf %d (%d)\n", id, ret);
-+		ipoib_cm_dma_unmap_rx(priv, IPOIB_CM_RX_SG - 1,
-+				      rx->rx_ring[id].mapping);
-+		dev_kfree_skb_any(rx->rx_ring[id].skb);
-+		rx->rx_ring[id].skb = NULL;
-+	}
-+
-+	return ret;
-+}
++config DVB_TDA18271
++	tristate "NXP TDA18271 silicon tuner"
++	depends on I2C
++	default m if DVB_FE_CUSTOMISE
++	help
++	  A silicon tuner module. Say Y when you want to support this tuner.
 +
-+static struct sk_buff *ipoib_cm_alloc_rx_skb(struct net_device *dev,
-+					     struct ipoib_cm_rx_buf *rx_ring,
-+					     int id, int frags,
- 					     u64 mapping[IPOIB_CM_RX_SG])
- {
- 	struct ipoib_dev_priv *priv = netdev_priv(dev);
-@@ -141,7 +174,7 @@ static struct sk_buff *ipoib_cm_alloc_rx_skb(struct net_device *dev, int id, int
- 			goto partial_error;
- 	}
+ config DVB_TUNER_QT1010
+ 	tristate "Quantek QT1010 silicon tuner"
+ 	depends on DVB_CORE && I2C
+@@ -353,6 +360,15 @@ config DVB_TUNER_DIB0070
+ 	  This device is only used inside a SiP called togther with a
+ 	  demodulator for now.
  
--	priv->cm.srq_ring[id].skb = skb;
-+	rx_ring[id].skb = skb;
- 	return skb;
++config DVB_TUNER_XC5000
++	tristate "Xceive XC5000 silicon tuner"
++	depends on I2C
++	default m if DVB_FE_CUSTOMISE
++	help
++	  A driver for the silicon tuner XC5000 from Xceive.
++	  This device is only used inside a SiP called togther with a
++	  demodulator for now.
++
+ comment "Miscellaneous devices"
+ 	depends on DVB_CORE
  
- partial_error:
-@@ -155,7 +188,23 @@ partial_error:
- 	return NULL;
- }
+diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile
+index 4b8ad1f..16bd107 100644
+--- a/drivers/media/dvb/frontends/Makefile
++++ b/drivers/media/dvb/frontends/Makefile
+@@ -3,6 +3,9 @@
+ #
  
--static void ipoib_cm_start_rx_drain(struct ipoib_dev_priv* priv)
-+static void ipoib_cm_free_rx_ring(struct net_device *dev,
-+				  struct ipoib_cm_rx_buf *rx_ring)
-+{
-+	struct ipoib_dev_priv *priv = netdev_priv(dev);
-+	int i;
+ EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/
++EXTRA_CFLAGS += -Idrivers/media/video/
 +
-+	for (i = 0; i < ipoib_recvq_size; ++i)
-+		if (rx_ring[i].skb) {
-+			ipoib_cm_dma_unmap_rx(priv, IPOIB_CM_RX_SG - 1,
-+					      rx_ring[i].mapping);
-+			dev_kfree_skb_any(rx_ring[i].skb);
-+		}
++tda18271-objs := tda18271-tables.o tda18271-common.o tda18271-fe.o
+ 
+ obj-$(CONFIG_DVB_PLL) += dvb-pll.o
+ obj-$(CONFIG_DVB_STV0299) += stv0299.o
+@@ -39,6 +42,7 @@ obj-$(CONFIG_DVB_ISL6421) += isl6421.o
+ obj-$(CONFIG_DVB_TDA10086) += tda10086.o
+ obj-$(CONFIG_DVB_TDA826X) += tda826x.o
+ obj-$(CONFIG_DVB_TDA827X) += tda827x.o
++obj-$(CONFIG_DVB_TDA18271) += tda18271.o
+ obj-$(CONFIG_DVB_TUNER_MT2060) += mt2060.o
+ obj-$(CONFIG_DVB_TUNER_MT2266) += mt2266.o
+ obj-$(CONFIG_DVB_TUNER_DIB0070) += dib0070.o
+@@ -46,3 +50,4 @@ obj-$(CONFIG_DVB_TUNER_QT1010) += qt1010.o
+ obj-$(CONFIG_DVB_TUA6100) += tua6100.o
+ obj-$(CONFIG_DVB_TUNER_MT2131) += mt2131.o
+ obj-$(CONFIG_DVB_S5H1409) += s5h1409.o
++obj-$(CONFIG_DVB_TUNER_XC5000) += xc5000.o
+diff --git a/drivers/media/dvb/frontends/dib0070.c b/drivers/media/dvb/frontends/dib0070.c
+index 481eaa6..fe895bf 100644
+--- a/drivers/media/dvb/frontends/dib0070.c
++++ b/drivers/media/dvb/frontends/dib0070.c
+@@ -434,9 +434,14 @@ static u16 dib0070_p1f_defaults[] =
+ 	0,
+ };
+ 
+-static void dib0070_wbd_calibration(struct dib0070_state *state)
++static void dib0070_wbd_calibration(struct dvb_frontend *fe)
+ {
+ 	u16 wbd_offs;
++	struct dib0070_state *state = fe->tuner_priv;
 +
-+	kfree(rx_ring);
-+}
++	if (state->cfg->sleep)
++		state->cfg->sleep(fe, 0);
 +
-+static void ipoib_cm_start_rx_drain(struct ipoib_dev_priv *priv)
- {
- 	struct ib_send_wr *bad_wr;
- 	struct ipoib_cm_rx *p;
-@@ -208,12 +257,18 @@ static struct ib_qp *ipoib_cm_create_rx_qp(struct net_device *dev,
- 		.qp_type = IB_QPT_RC,
- 		.qp_context = p,
- 	};
+ 	dib0070_write_reg(state, 0x0f, 0x6d81);
+ 	dib0070_write_reg(state, 0x20, 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001);
+ 	msleep(9);
+@@ -444,6 +449,10 @@ static void dib0070_wbd_calibration(struct dib0070_state *state)
+ 	dib0070_write_reg(state, 0x20, 0);
+ 	state->wbd_ff_offset = ((wbd_offs * 8 * 18 / 33 + 1) / 2);
+ 	dprintk( "WBDStart = %d (Vargen) - FF = %hd", (u32) wbd_offs * 1800/1024, state->wbd_ff_offset);
 +
-+	if (!ipoib_cm_has_srq(dev)) {
-+		attr.cap.max_recv_wr  = ipoib_recvq_size;
-+		attr.cap.max_recv_sge = IPOIB_CM_RX_SG;
-+	}
++	if (state->cfg->sleep)
++		state->cfg->sleep(fe, 1);
 +
- 	return ib_create_qp(priv->pd, &attr);
  }
  
- static int ipoib_cm_modify_rx_qp(struct net_device *dev,
--				  struct ib_cm_id *cm_id, struct ib_qp *qp,
--				  unsigned psn)
-+				 struct ib_cm_id *cm_id, struct ib_qp *qp,
-+				 unsigned psn)
- {
- 	struct ipoib_dev_priv *priv = netdev_priv(dev);
- 	struct ib_qp_attr qp_attr;
-@@ -266,6 +321,60 @@ static int ipoib_cm_modify_rx_qp(struct net_device *dev,
- 	return 0;
- }
+ u16 dib0070_wbd_offset(struct dvb_frontend *fe)
+@@ -560,7 +569,7 @@ struct dvb_frontend * dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter
+ 	if (dib0070_reset(state) != 0)
+ 		goto free_mem;
  
-+static int ipoib_cm_nonsrq_init_rx(struct net_device *dev, struct ib_cm_id *cm_id,
-+				   struct ipoib_cm_rx *rx)
-+{
-+	struct ipoib_dev_priv *priv = netdev_priv(dev);
-+	int ret;
-+	int i;
-+
-+	rx->rx_ring = kcalloc(ipoib_recvq_size, sizeof *rx->rx_ring, GFP_KERNEL);
-+	if (!rx->rx_ring)
-+		return -ENOMEM;
-+
-+	spin_lock_irq(&priv->lock);
-+
-+	if (priv->cm.nonsrq_conn_qp >= ipoib_max_conn_qp) {
-+		spin_unlock_irq(&priv->lock);
-+		ib_send_cm_rej(cm_id, IB_CM_REJ_NO_QP, NULL, 0, NULL, 0);
-+		ret = -EINVAL;
-+		goto err_free;
-+	} else
-+		++priv->cm.nonsrq_conn_qp;
-+
-+	spin_unlock_irq(&priv->lock);
-+
-+	for (i = 0; i < ipoib_recvq_size; ++i) {
-+		if (!ipoib_cm_alloc_rx_skb(dev, rx->rx_ring, i, IPOIB_CM_RX_SG - 1,
-+					   rx->rx_ring[i].mapping)) {
-+			ipoib_warn(priv, "failed to allocate receive buffer %d\n", i);
-+				ret = -ENOMEM;
-+				goto err_count;
-+			}
-+		ret = ipoib_cm_post_receive_nonsrq(dev, rx, i);
-+		if (ret) {
-+			ipoib_warn(priv, "ipoib_cm_post_receive_nonsrq "
-+				   "failed for buf %d\n", i);
-+			ret = -EIO;
-+			goto err_count;
-+		}
-+	}
-+
-+	rx->recv_count = ipoib_recvq_size;
-+
-+	return 0;
-+
-+err_count:
-+	spin_lock_irq(&priv->lock);
-+	--priv->cm.nonsrq_conn_qp;
-+	spin_unlock_irq(&priv->lock);
-+
-+err_free:
-+	ipoib_cm_free_rx_ring(dev, rx->rx_ring);
-+
-+	return ret;
-+}
-+
- static int ipoib_cm_send_rep(struct net_device *dev, struct ib_cm_id *cm_id,
- 			     struct ib_qp *qp, struct ib_cm_req_event_param *req,
- 			     unsigned psn)
-@@ -281,7 +390,7 @@ static int ipoib_cm_send_rep(struct net_device *dev, struct ib_cm_id *cm_id,
- 	rep.private_data_len = sizeof data;
- 	rep.flow_control = 0;
- 	rep.rnr_retry_count = req->rnr_retry_count;
--	rep.srq = 1;
-+	rep.srq = ipoib_cm_has_srq(dev);
- 	rep.qp_num = qp->qp_num;
- 	rep.starting_psn = psn;
- 	return ib_send_cm_rep(cm_id, &rep);
-@@ -317,6 +426,12 @@ static int ipoib_cm_req_handler(struct ib_cm_id *cm_id, struct ib_cm_event *even
- 	if (ret)
- 		goto err_modify;
+-	dib0070_wbd_calibration(state);
++	dib0070_wbd_calibration(fe);
  
-+	if (!ipoib_cm_has_srq(dev)) {
-+		ret = ipoib_cm_nonsrq_init_rx(dev, cm_id, p);
-+		if (ret)
-+			goto err_modify;
-+	}
-+
- 	spin_lock_irq(&priv->lock);
- 	queue_delayed_work(ipoib_workqueue,
- 			   &priv->cm.stale_task, IPOIB_CM_RX_DELAY);
-@@ -401,12 +516,14 @@ static void skb_put_frags(struct sk_buff *skb, unsigned int hdr_space,
- void ipoib_cm_handle_rx_wc(struct net_device *dev, struct ib_wc *wc)
+ 	printk(KERN_INFO "DiB0070: successfully identified\n");
+ 	memcpy(&fe->ops.tuner_ops, &dib0070_ops, sizeof(struct dvb_tuner_ops));
+diff --git a/drivers/media/dvb/frontends/dib3000mc.c b/drivers/media/dvb/frontends/dib3000mc.c
+index edae0be..fa85160 100644
+--- a/drivers/media/dvb/frontends/dib3000mc.c
++++ b/drivers/media/dvb/frontends/dib3000mc.c
+@@ -684,6 +684,9 @@ static int dib3000mc_set_frontend(struct dvb_frontend* fe,
+ 				struct dvb_frontend_parameters *fep)
  {
- 	struct ipoib_dev_priv *priv = netdev_priv(dev);
-+	struct ipoib_cm_rx_buf *rx_ring;
- 	unsigned int wr_id = wc->wr_id & ~(IPOIB_OP_CM | IPOIB_OP_RECV);
- 	struct sk_buff *skb, *newskb;
- 	struct ipoib_cm_rx *p;
- 	unsigned long flags;
- 	u64 mapping[IPOIB_CM_RX_SG];
- 	int frags;
-+	int has_srq;
+ 	struct dib3000mc_state *state = fe->demodulator_priv;
++    int ret;
++
++	dib3000mc_set_output_mode(state, OUTMODE_HIGH_Z);
  
- 	ipoib_dbg_data(priv, "cm recv completion: id %d, status: %d\n",
- 		       wr_id, wc->status);
-@@ -424,18 +541,32 @@ void ipoib_cm_handle_rx_wc(struct net_device *dev, struct ib_wc *wc)
- 		return;
+ 	state->current_bandwidth = fep->u.ofdm.bandwidth;
+ 	dib3000mc_set_bandwidth(state, BANDWIDTH_TO_KHZ(fep->u.ofdm.bandwidth));
+@@ -700,7 +703,7 @@ static int dib3000mc_set_frontend(struct dvb_frontend* fe,
+ 		fep->u.ofdm.guard_interval    == GUARD_INTERVAL_AUTO ||
+ 		fep->u.ofdm.constellation     == QAM_AUTO ||
+ 		fep->u.ofdm.code_rate_HP      == FEC_AUTO) {
+-		int i = 100, found;
++		int i = 1000, found;
+ 
+ 		dib3000mc_autosearch_start(fe, fep);
+ 		do {
+@@ -715,10 +718,11 @@ static int dib3000mc_set_frontend(struct dvb_frontend* fe,
+ 		dib3000mc_get_frontend(fe, fep);
  	}
  
--	skb  = priv->cm.srq_ring[wr_id].skb;
-+	p = wc->qp->qp_context;
++    ret = dib3000mc_tune(fe, fep);
 +
-+	has_srq = ipoib_cm_has_srq(dev);
-+	rx_ring = has_srq ? priv->cm.srq_ring : p->rx_ring;
+ 	/* make this a config parameter */
+ 	dib3000mc_set_output_mode(state, OUTMODE_MPEG2_FIFO);
+-
+-	return dib3000mc_tune(fe, fep);
++    return ret;
+ }
+ 
+ static int dib3000mc_read_status(struct dvb_frontend *fe, fe_status_t *stat)
+diff --git a/drivers/media/dvb/frontends/dib7000m.c b/drivers/media/dvb/frontends/dib7000m.c
+index fb18441..5f1375e 100644
+--- a/drivers/media/dvb/frontends/dib7000m.c
++++ b/drivers/media/dvb/frontends/dib7000m.c
+@@ -1171,7 +1171,9 @@ static int dib7000m_set_frontend(struct dvb_frontend* fe,
+ 				struct dvb_frontend_parameters *fep)
+ {
+ 	struct dib7000m_state *state = fe->demodulator_priv;
+-	int time;
++	int time, ret;
 +
-+	skb = rx_ring[wr_id].skb;
++    dib7000m_set_output_mode(state, OUTMODE_HIGH_Z);
  
- 	if (unlikely(wc->status != IB_WC_SUCCESS)) {
- 		ipoib_dbg(priv, "cm recv error "
- 			   "(status=%d, wrid=%d vend_err %x)\n",
- 			   wc->status, wr_id, wc->vendor_err);
- 		++dev->stats.rx_dropped;
--		goto repost;
-+		if (has_srq)
-+			goto repost;
-+		else {
-+			if (!--p->recv_count) {
-+				spin_lock_irqsave(&priv->lock, flags);
-+				list_move(&p->list, &priv->cm.rx_reap_list);
-+				spin_unlock_irqrestore(&priv->lock, flags);
-+				queue_work(ipoib_workqueue, &priv->cm.rx_reap_task);
-+			}
-+			return;
-+		}
+ 	state->current_bandwidth = fep->u.ofdm.bandwidth;
+ 	dib7000m_set_bandwidth(state, BANDWIDTH_TO_KHZ(fep->u.ofdm.bandwidth));
+@@ -1206,10 +1208,11 @@ static int dib7000m_set_frontend(struct dvb_frontend* fe,
+ 		dib7000m_get_frontend(fe, fep);
  	}
  
- 	if (unlikely(!(wr_id & IPOIB_CM_RX_UPDATE_MASK))) {
--		p = wc->qp->qp_context;
- 		if (p && time_after_eq(jiffies, p->jiffies + IPOIB_CM_RX_UPDATE_TIME)) {
- 			spin_lock_irqsave(&priv->lock, flags);
- 			p->jiffies = jiffies;
-@@ -450,7 +581,7 @@ void ipoib_cm_handle_rx_wc(struct net_device *dev, struct ib_wc *wc)
- 	frags = PAGE_ALIGN(wc->byte_len - min(wc->byte_len,
- 					      (unsigned)IPOIB_CM_HEAD_SIZE)) / PAGE_SIZE;
++	ret = dib7000m_tune(fe, fep);
++
+ 	/* make this a config parameter */
+ 	dib7000m_set_output_mode(state, OUTMODE_MPEG2_FIFO);
+-
+-	return dib7000m_tune(fe, fep);
++	return ret;
+ }
  
--	newskb = ipoib_cm_alloc_rx_skb(dev, wr_id, frags, mapping);
-+	newskb = ipoib_cm_alloc_rx_skb(dev, rx_ring, wr_id, frags, mapping);
- 	if (unlikely(!newskb)) {
- 		/*
- 		 * If we can't allocate a new RX buffer, dump
-@@ -461,8 +592,8 @@ void ipoib_cm_handle_rx_wc(struct net_device *dev, struct ib_wc *wc)
- 		goto repost;
- 	}
+ static int dib7000m_read_status(struct dvb_frontend *fe, fe_status_t *stat)
+diff --git a/drivers/media/dvb/frontends/dib7000p.c b/drivers/media/dvb/frontends/dib7000p.c
+index f45bcfc..47c23e2 100644
+--- a/drivers/media/dvb/frontends/dib7000p.c
++++ b/drivers/media/dvb/frontends/dib7000p.c
+@@ -35,8 +35,8 @@ struct dib7000p_state {
  
--	ipoib_cm_dma_unmap_rx(priv, frags, priv->cm.srq_ring[wr_id].mapping);
--	memcpy(priv->cm.srq_ring[wr_id].mapping, mapping, (frags + 1) * sizeof *mapping);
-+	ipoib_cm_dma_unmap_rx(priv, frags, rx_ring[wr_id].mapping);
-+	memcpy(rx_ring[wr_id].mapping, mapping, (frags + 1) * sizeof *mapping);
+ 	u16 wbd_ref;
  
- 	ipoib_dbg_data(priv, "received %d bytes, SLID 0x%04x\n",
- 		       wc->byte_len, wc->slid);
-@@ -483,9 +614,17 @@ void ipoib_cm_handle_rx_wc(struct net_device *dev, struct ib_wc *wc)
- 	netif_receive_skb(skb);
+-	u8 current_band;
+-	fe_bandwidth_t current_bandwidth;
++	u8  current_band;
++	u32 current_bandwidth;
+ 	struct dibx000_agc_config *current_agc;
+ 	u32 timf;
  
- repost:
--	if (unlikely(ipoib_cm_post_receive(dev, wr_id)))
--		ipoib_warn(priv, "ipoib_cm_post_receive failed "
--			   "for buf %d\n", wr_id);
-+	if (has_srq) {
-+		if (unlikely(ipoib_cm_post_receive_srq(dev, wr_id)))
-+			ipoib_warn(priv, "ipoib_cm_post_receive_srq failed "
-+				   "for buf %d\n", wr_id);
-+	} else {
-+		if (unlikely(ipoib_cm_post_receive_nonsrq(dev, p, wr_id))) {
-+			--p->recv_count;
-+			ipoib_warn(priv, "ipoib_cm_post_receive_nonsrq failed "
-+				   "for buf %d\n", wr_id);
-+		}
-+	}
- }
+@@ -1074,7 +1074,7 @@ static int dib7000p_get_frontend(struct dvb_frontend* fe,
  
- static inline int post_send(struct ipoib_dev_priv *priv,
-@@ -495,10 +634,10 @@ static inline int post_send(struct ipoib_dev_priv *priv,
+ 	fep->inversion = INVERSION_AUTO;
+ 
+-	fep->u.ofdm.bandwidth = state->current_bandwidth;
++	fep->u.ofdm.bandwidth = BANDWIDTH_TO_INDEX(state->current_bandwidth);
+ 
+ 	switch ((tps >> 8) & 0x3) {
+ 		case 0: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K; break;
+@@ -1128,12 +1128,11 @@ static int dib7000p_set_frontend(struct dvb_frontend* fe,
+ 				struct dvb_frontend_parameters *fep)
  {
- 	struct ib_send_wr *bad_wr;
+ 	struct dib7000p_state *state = fe->demodulator_priv;
+-	int time;
++	int time, ret;
  
--	priv->tx_sge.addr             = addr;
--	priv->tx_sge.length           = len;
-+	priv->tx_sge.addr	= addr;
-+	priv->tx_sge.length	= len;
+-	state->current_bandwidth = fep->u.ofdm.bandwidth;
+-	dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(fep->u.ofdm.bandwidth));
++	dib7000p_set_output_mode(state, OUTMODE_HIGH_Z);
  
--	priv->tx_wr.wr_id 	      = wr_id | IPOIB_OP_CM;
-+	priv->tx_wr.wr_id	= wr_id | IPOIB_OP_CM;
+-	/* maybe the parameter has been changed */
++    /* maybe the parameter has been changed */
+ 	state->sfn_workaround_active = buggy_sfn_workaround;
  
- 	return ib_post_send(tx->qp, &priv->tx_wr, &bad_wr);
- }
-@@ -540,7 +679,7 @@ void ipoib_cm_send(struct net_device *dev, struct sk_buff *skb, struct ipoib_cm_
- 	tx_req->mapping = addr;
+ 	if (fe->ops.tuner_ops.set_params)
+@@ -1166,10 +1165,11 @@ static int dib7000p_set_frontend(struct dvb_frontend* fe,
+ 		dib7000p_get_frontend(fe, fep);
+ 	}
  
- 	if (unlikely(post_send(priv, tx, tx->tx_head & (ipoib_sendq_size - 1),
--			        addr, skb->len))) {
-+			       addr, skb->len))) {
- 		ipoib_warn(priv, "post_send failed\n");
- 		++dev->stats.tx_errors;
- 		ib_dma_unmap_single(priv->ca, addr, skb->len, DMA_TO_DEVICE);
-@@ -657,10 +796,33 @@ err_cm:
- 	return ret;
++	ret = dib7000p_tune(fe, fep);
++
+ 	/* make this a config parameter */
+ 	dib7000p_set_output_mode(state, OUTMODE_MPEG2_FIFO);
+-
+-	return dib7000p_tune(fe, fep);
++    return ret;
  }
  
-+static void ipoib_cm_free_rx_reap_list(struct net_device *dev)
-+{
-+	struct ipoib_dev_priv *priv = netdev_priv(dev);
-+	struct ipoib_cm_rx *rx, *n;
-+	LIST_HEAD(list);
-+
-+	spin_lock_irq(&priv->lock);
-+	list_splice_init(&priv->cm.rx_reap_list, &list);
-+	spin_unlock_irq(&priv->lock);
-+
-+	list_for_each_entry_safe(rx, n, &list, list) {
-+		ib_destroy_cm_id(rx->id);
-+		ib_destroy_qp(rx->qp);
-+		if (!ipoib_cm_has_srq(dev)) {
-+			ipoib_cm_free_rx_ring(priv->dev, rx->rx_ring);
-+			spin_lock_irq(&priv->lock);
-+			--priv->cm.nonsrq_conn_qp;
-+			spin_unlock_irq(&priv->lock);
-+		}
-+		kfree(rx);
-+	}
-+}
+ static int dib7000p_read_status(struct dvb_frontend *fe, fe_status_t *stat)
+diff --git a/drivers/media/dvb/frontends/dibx000_common.h b/drivers/media/dvb/frontends/dibx000_common.h
+index 5e17275..84e4d53 100644
+--- a/drivers/media/dvb/frontends/dibx000_common.h
++++ b/drivers/media/dvb/frontends/dibx000_common.h
+@@ -128,6 +128,11 @@ enum dibx000_adc_states {
+ 			     (v) == BANDWIDTH_7_MHZ  ? 7000 : \
+ 			     (v) == BANDWIDTH_6_MHZ  ? 6000 : 8000 )
+ 
++#define BANDWIDTH_TO_INDEX(v) ( \
++	(v) == 8000 ? BANDWIDTH_8_MHZ : \
++		(v) == 7000 ? BANDWIDTH_7_MHZ : \
++		(v) == 6000 ? BANDWIDTH_6_MHZ : BANDWIDTH_8_MHZ )
 +
- void ipoib_cm_dev_stop(struct net_device *dev)
- {
- 	struct ipoib_dev_priv *priv = netdev_priv(dev);
--	struct ipoib_cm_rx *p, *n;
-+	struct ipoib_cm_rx *p;
- 	unsigned long begin;
- 	LIST_HEAD(list);
- 	int ret;
-@@ -706,15 +868,9 @@ void ipoib_cm_dev_stop(struct net_device *dev)
- 		spin_lock_irq(&priv->lock);
- 	}
+ /* Chip output mode. */
+ #define OUTMODE_HIGH_Z              0
+ #define OUTMODE_MPEG2_PAR_GATED_CLK 1
+diff --git a/drivers/media/dvb/frontends/mt2266.c b/drivers/media/dvb/frontends/mt2266.c
+index 03fe826..54b18f9 100644
+--- a/drivers/media/dvb/frontends/mt2266.c
++++ b/drivers/media/dvb/frontends/mt2266.c
+@@ -38,8 +38,12 @@ struct mt2266_priv {
  
--	list_splice_init(&priv->cm.rx_reap_list, &list);
--
- 	spin_unlock_irq(&priv->lock);
+ 	u32 frequency;
+ 	u32 bandwidth;
++	u8 band;
+ };
  
--	list_for_each_entry_safe(p, n, &list, list) {
--		ib_destroy_cm_id(p->id);
--		ib_destroy_qp(p->qp);
--		kfree(p);
--	}
-+	ipoib_cm_free_rx_reap_list(dev);
++#define MT2266_VHF 1
++#define MT2266_UHF 0
++
+ /* Here, frequencies are expressed in kiloHertz to avoid 32 bits overflows */
  
- 	cancel_delayed_work(&priv->cm.stale_task);
+ static int debug;
+@@ -90,26 +94,30 @@ static int mt2266_writeregs(struct mt2266_priv *priv,u8 *buf, u8 len)
  }
-@@ -799,7 +955,7 @@ static struct ib_qp *ipoib_cm_create_tx_qp(struct net_device *dev, struct ipoib_
- 		.sq_sig_type		= IB_SIGNAL_ALL_WR,
- 		.qp_type		= IB_QPT_RC,
- 		.qp_context		= tx
--        };
-+	};
  
- 	return ib_create_qp(priv->pd, &attr);
- }
-@@ -816,28 +972,28 @@ static int ipoib_cm_send_req(struct net_device *dev,
- 	data.qpn = cpu_to_be32(priv->qp->qp_num);
- 	data.mtu = cpu_to_be32(IPOIB_CM_BUF_SIZE);
+ // Initialisation sequences
+-static u8 mt2266_init1[] = {
+-	REG_TUNE,
+-	0x00, 0x00, 0x28, 0x00, 0x52, 0x99, 0x3f };
++static u8 mt2266_init1[] = { REG_TUNE, 0x00, 0x00, 0x28,
++				 0x00, 0x52, 0x99, 0x3f };
  
--	req.primary_path 	      = pathrec;
--	req.alternate_path 	      = NULL;
--	req.service_id                = cpu_to_be64(IPOIB_CM_IETF_ID | qpn);
--	req.qp_num 		      = qp->qp_num;
--	req.qp_type 		      = qp->qp_type;
--	req.private_data 	      = &data;
--	req.private_data_len 	      = sizeof data;
--	req.flow_control 	      = 0;
-+	req.primary_path		= pathrec;
-+	req.alternate_path		= NULL;
-+	req.service_id			= cpu_to_be64(IPOIB_CM_IETF_ID | qpn);
-+	req.qp_num			= qp->qp_num;
-+	req.qp_type			= qp->qp_type;
-+	req.private_data		= &data;
-+	req.private_data_len		= sizeof data;
-+	req.flow_control		= 0;
+ static u8 mt2266_init2[] = {
+-	0x17,                                     0x6d, 0x71, 0x61, 0xc0, 0xbf, 0xff, 0xdc, 0x00, 0x0a,
+-	0xd4, 0x03, 0x64, 0x64, 0x64, 0x64, 0x22, 0xaa, 0xf2, 0x1e, 0x80, 0x14, 0x01, 0x01, 0x01, 0x01,
+-	0x01, 0x01, 0x7f, 0x5e, 0x3f, 0xff, 0xff, 0xff, 0x00, 0x77, 0x0f, 0x2d };
++    0x17, 0x6d, 0x71, 0x61, 0xc0, 0xbf, 0xff, 0xdc, 0x00, 0x0a, 0xd4,
++    0x03, 0x64, 0x64, 0x64, 0x64, 0x22, 0xaa, 0xf2, 0x1e, 0x80, 0x14,
++    0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x7f, 0x5e, 0x3f, 0xff, 0xff,
++    0xff, 0x00, 0x77, 0x0f, 0x2d
++};
++
++static u8 mt2266_init_8mhz[] = { REG_BANDWIDTH, 0x22, 0x22, 0x22, 0x22,
++						0x22, 0x22, 0x22, 0x22 };
  
--	req.starting_psn              = 0; /* FIXME */
-+	req.starting_psn		= 0; /* FIXME */
+-static u8 mt2266_init_8mhz[] = {
+-	REG_BANDWIDTH,
+-	0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22 };
++static u8 mt2266_init_7mhz[] = { REG_BANDWIDTH, 0x32, 0x32, 0x32, 0x32,
++						0x32, 0x32, 0x32, 0x32 };
  
- 	/*
- 	 * Pick some arbitrary defaults here; we could make these
- 	 * module parameters if anyone cared about setting them.
- 	 */
--	req.responder_resources	      = 4;
--	req.remote_cm_response_timeout = 20;
--	req.local_cm_response_timeout  = 20;
--	req.retry_count 	      = 0; /* RFC draft warns against retries */
--	req.rnr_retry_count 	      = 0; /* RFC draft warns against retries */
--	req.max_cm_retries 	      = 15;
--	req.srq 	              = 1;
-+	req.responder_resources		= 4;
-+	req.remote_cm_response_timeout	= 20;
-+	req.local_cm_response_timeout	= 20;
-+	req.retry_count			= 0; /* RFC draft warns against retries */
-+	req.rnr_retry_count		= 0; /* RFC draft warns against retries */
-+	req.max_cm_retries		= 15;
-+	req.srq				= ipoib_cm_has_srq(dev);
- 	return ib_send_cm_req(id, &req);
- }
+-static u8 mt2266_init_7mhz[] = {
+-	REG_BANDWIDTH,
+-	0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32 };
++static u8 mt2266_init_6mhz[] = { REG_BANDWIDTH, 0xa7, 0xa7, 0xa7, 0xa7,
++						0xa7, 0xa7, 0xa7, 0xa7 };
  
-@@ -1150,7 +1306,7 @@ static void ipoib_cm_skb_reap(struct work_struct *work)
- 	spin_unlock_irq(&priv->tx_lock);
- }
+-static u8 mt2266_init_6mhz[] = {
+-	REG_BANDWIDTH,
+-	0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7 };
++static u8 mt2266_uhf[] = { 0x1d, 0xdc, 0x00, 0x0a, 0xd4, 0x03, 0x64, 0x64,
++			   0x64, 0x64, 0x22, 0xaa, 0xf2, 0x1e, 0x80, 0x14 };
++
++static u8 mt2266_vhf[] = { 0x1d, 0xfe, 0x00, 0x00, 0xb4, 0x03, 0xa5, 0xa5,
++			   0xa5, 0xa5, 0x82, 0xaa, 0xf1, 0x17, 0x80, 0x1f };
  
--void ipoib_cm_skb_too_long(struct net_device* dev, struct sk_buff *skb,
-+void ipoib_cm_skb_too_long(struct net_device *dev, struct sk_buff *skb,
- 			   unsigned int mtu)
- {
- 	struct ipoib_dev_priv *priv = netdev_priv(dev);
-@@ -1166,20 +1322,8 @@ void ipoib_cm_skb_too_long(struct net_device* dev, struct sk_buff *skb,
+ #define FREF 30000       // Quartz oscillator 30 MHz
  
- static void ipoib_cm_rx_reap(struct work_struct *work)
- {
--	struct ipoib_dev_priv *priv = container_of(work, struct ipoib_dev_priv,
--						   cm.rx_reap_task);
--	struct ipoib_cm_rx *p, *n;
--	LIST_HEAD(list);
+@@ -122,35 +130,78 @@ static int mt2266_set_params(struct dvb_frontend *fe, struct dvb_frontend_parame
+ 	u8  lnaband;
+ 	u8  b[10];
+ 	int i;
++	u8 band;
+ 
+ 	priv = fe->tuner_priv;
+ 
+-	mt2266_writereg(priv,0x17,0x6d);
+-	mt2266_writereg(priv,0x1c,0xff);
 -
--	spin_lock_irq(&priv->lock);
--	list_splice_init(&priv->cm.rx_reap_list, &list);
--	spin_unlock_irq(&priv->lock);
+ 	freq = params->frequency / 1000; // Hz -> kHz
++	if (freq < 470000 && freq > 230000)
++		return -EINVAL; /* Gap between VHF and UHF bands */
+ 	priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0;
+ 	priv->frequency = freq * 1000;
+-	tune=2 * freq * (8192/16) / (FREF/16);
 -
--	list_for_each_entry_safe(p, n, &list, list) {
--		ib_destroy_cm_id(p->id);
--		ib_destroy_qp(p->qp);
--		kfree(p);
--	}
-+	ipoib_cm_free_rx_reap_list(container_of(work, struct ipoib_dev_priv,
-+						cm.rx_reap_task)->dev);
+-	if (freq <= 495000) lnaband = 0xEE; else
+-	if (freq <= 525000) lnaband = 0xDD; else
+-	if (freq <= 550000) lnaband = 0xCC; else
+-	if (freq <= 580000) lnaband = 0xBB; else
+-	if (freq <= 605000) lnaband = 0xAA; else
+-	if (freq <= 630000) lnaband = 0x99; else
+-	if (freq <= 655000) lnaband = 0x88; else
+-	if (freq <= 685000) lnaband = 0x77; else
+-	if (freq <= 710000) lnaband = 0x66; else
+-	if (freq <= 735000) lnaband = 0x55; else
+-	if (freq <= 765000) lnaband = 0x44; else
+-	if (freq <= 802000) lnaband = 0x33; else
+-	if (freq <= 840000) lnaband = 0x22; else lnaband = 0x11;
+-
+-	msleep(100);
+-	mt2266_writeregs(priv,(params->u.ofdm.bandwidth==BANDWIDTH_6_MHZ)?mt2266_init_6mhz:
+-				(params->u.ofdm.bandwidth==BANDWIDTH_7_MHZ)?mt2266_init_7mhz:
+-				mt2266_init_8mhz,sizeof(mt2266_init_8mhz));
++
++	tune = 2 * freq * (8192/16) / (FREF/16);
++	band = (freq < 300000) ? MT2266_VHF : MT2266_UHF;
++	if (band == MT2266_VHF)
++		tune *= 2;
++
++	switch (params->u.ofdm.bandwidth) {
++	case BANDWIDTH_6_MHZ:
++		mt2266_writeregs(priv, mt2266_init_6mhz,
++				 sizeof(mt2266_init_6mhz));
++		break;
++	case BANDWIDTH_7_MHZ:
++		mt2266_writeregs(priv, mt2266_init_7mhz,
++				 sizeof(mt2266_init_7mhz));
++		break;
++	case BANDWIDTH_8_MHZ:
++	default:
++		mt2266_writeregs(priv, mt2266_init_8mhz,
++				 sizeof(mt2266_init_8mhz));
++		break;
++	}
++
++	if (band == MT2266_VHF && priv->band == MT2266_UHF) {
++		dprintk("Switch from UHF to VHF");
++		mt2266_writereg(priv, 0x05, 0x04);
++		mt2266_writereg(priv, 0x19, 0x61);
++		mt2266_writeregs(priv, mt2266_vhf, sizeof(mt2266_vhf));
++	} else if (band == MT2266_UHF && priv->band == MT2266_VHF) {
++		dprintk("Switch from VHF to UHF");
++		mt2266_writereg(priv, 0x05, 0x52);
++		mt2266_writereg(priv, 0x19, 0x61);
++		mt2266_writeregs(priv, mt2266_uhf, sizeof(mt2266_uhf));
++	}
++	msleep(10);
++
++	if (freq <= 495000)
++		lnaband = 0xEE;
++	else if (freq <= 525000)
++		lnaband = 0xDD;
++	else if (freq <= 550000)
++		lnaband = 0xCC;
++	else if (freq <= 580000)
++		lnaband = 0xBB;
++	else if (freq <= 605000)
++		lnaband = 0xAA;
++	else if (freq <= 630000)
++		lnaband = 0x99;
++	else if (freq <= 655000)
++		lnaband = 0x88;
++	else if (freq <= 685000)
++		lnaband = 0x77;
++	else if (freq <= 710000)
++		lnaband = 0x66;
++	else if (freq <= 735000)
++		lnaband = 0x55;
++	else if (freq <= 765000)
++		lnaband = 0x44;
++	else if (freq <= 802000)
++		lnaband = 0x33;
++	else if (freq <= 840000)
++		lnaband = 0x22;
++	else
++		lnaband = 0x11;
+ 
+ 	b[0] = REG_TUNE;
+ 	b[1] = (tune >> 8) & 0x1F;
+@@ -158,47 +209,54 @@ static int mt2266_set_params(struct dvb_frontend *fe, struct dvb_frontend_parame
+ 	b[3] = tune >> 13;
+ 	mt2266_writeregs(priv,b,4);
+ 
+-	dprintk("set_parms: tune=%d band=%d",(int)tune,(int)lnaband);
+-	dprintk("set_parms: [1..3]: %2x %2x %2x",(int)b[1],(int)b[2],(int)b[3]);
+-
+-	b[0] = 0x05;
+-	b[1] = 0x62;
+-	b[2] = lnaband;
+-	mt2266_writeregs(priv,b,3);
++	dprintk("set_parms: tune=%d band=%d %s",
++		(int) tune, (int) lnaband,
++		(band == MT2266_UHF) ? "UHF" : "VHF");
++	dprintk("set_parms: [1..3]: %2x %2x %2x",
++		(int) b[1], (int) b[2], (int)b[3]);
++
++	if (band == MT2266_UHF) {
++		b[0] = 0x05;
++		b[1] = (priv->band == MT2266_VHF) ? 0x52 : 0x62;
++		b[2] = lnaband;
++		mt2266_writeregs(priv, b, 3);
++	}
+ 
+-	//Waits for pll lock or timeout
++	/* Wait for pll lock or timeout */
+ 	i = 0;
+ 	do {
+ 		mt2266_readreg(priv,REG_LOCK,b);
+-		if ((b[0] & 0x40)==0x40)
++		if (b[0] & 0x40)
+ 			break;
+ 		msleep(10);
+ 		i++;
+ 	} while (i<10);
+ 	dprintk("Lock when i=%i",(int)i);
++
++	if (band == MT2266_UHF && priv->band == MT2266_VHF)
++		mt2266_writereg(priv, 0x05, 0x62);
++
++	priv->band = band;
++
+ 	return ret;
  }
  
- static void ipoib_cm_stale_task(struct work_struct *work)
-@@ -1212,7 +1356,7 @@ static void ipoib_cm_stale_task(struct work_struct *work)
+ static void mt2266_calibrate(struct mt2266_priv *priv)
+ {
+-	mt2266_writereg(priv,0x11,0x03);
+-	mt2266_writereg(priv,0x11,0x01);
+-
+-	mt2266_writeregs(priv,mt2266_init1,sizeof(mt2266_init1));
+-	mt2266_writeregs(priv,mt2266_init2,sizeof(mt2266_init2));
+-
+-	mt2266_writereg(priv,0x33,0x5e);
+-	mt2266_writereg(priv,0x10,0x10);
+-	mt2266_writereg(priv,0x10,0x00);
+-
+-	mt2266_writeregs(priv,mt2266_init_8mhz,sizeof(mt2266_init_8mhz));
+-
++	mt2266_writereg(priv, 0x11, 0x03);
++	mt2266_writereg(priv, 0x11, 0x01);
++	mt2266_writeregs(priv, mt2266_init1, sizeof(mt2266_init1));
++	mt2266_writeregs(priv, mt2266_init2, sizeof(mt2266_init2));
++	mt2266_writereg(priv, 0x33, 0x5e);
++	mt2266_writereg(priv, 0x10, 0x10);
++	mt2266_writereg(priv, 0x10, 0x00);
++	mt2266_writeregs(priv, mt2266_init_8mhz, sizeof(mt2266_init_8mhz));
+ 	msleep(25);
+-	mt2266_writereg(priv,0x17,0x6d);
+-	mt2266_writereg(priv,0x1c,0x00);
++	mt2266_writereg(priv, 0x17, 0x6d);
++	mt2266_writereg(priv, 0x1c, 0x00);
+ 	msleep(75);
+-	mt2266_writereg(priv,0x17,0x6d);
+-	mt2266_writereg(priv,0x1c,0xff);
++	mt2266_writereg(priv, 0x17, 0x6d);
++	mt2266_writereg(priv, 0x1c, 0xff);
  }
  
+ static int mt2266_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+@@ -217,17 +275,22 @@ static int mt2266_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
  
--static ssize_t show_mode(struct device *d, struct device_attribute *attr, 
-+static ssize_t show_mode(struct device *d, struct device_attribute *attr,
- 			 char *buf)
+ static int mt2266_init(struct dvb_frontend *fe)
  {
- 	struct ipoib_dev_priv *priv = netdev_priv(to_net_dev(d));
-@@ -1255,16 +1399,40 @@ int ipoib_cm_add_mode_attr(struct net_device *dev)
- 	return device_create_file(&dev->dev, &dev_attr_mode);
++	int ret;
+ 	struct mt2266_priv *priv = fe->tuner_priv;
+-	mt2266_writereg(priv,0x17,0x6d);
+-	mt2266_writereg(priv,0x1c,0xff);
++	ret = mt2266_writereg(priv, 0x17, 0x6d);
++	if (ret < 0)
++		return ret;
++	ret = mt2266_writereg(priv, 0x1c, 0xff);
++	if (ret < 0)
++		return ret;
+ 	return 0;
  }
  
--int ipoib_cm_dev_init(struct net_device *dev)
-+static void ipoib_cm_create_srq(struct net_device *dev, int max_sge)
+ static int mt2266_sleep(struct dvb_frontend *fe)
  {
- 	struct ipoib_dev_priv *priv = netdev_priv(dev);
- 	struct ib_srq_init_attr srq_init_attr = {
- 		.attr = {
- 			.max_wr  = ipoib_recvq_size,
--			.max_sge = IPOIB_CM_RX_SG
-+			.max_sge = max_sge
- 		}
- 	};
--	int ret, i;
-+
-+	priv->cm.srq = ib_create_srq(priv->pd, &srq_init_attr);
-+	if (IS_ERR(priv->cm.srq)) {
-+		if (PTR_ERR(priv->cm.srq) != -ENOSYS)
-+			printk(KERN_WARNING "%s: failed to allocate SRQ, error %ld\n",
-+			       priv->ca->name, PTR_ERR(priv->cm.srq));
-+		priv->cm.srq = NULL;
-+		return;
-+	}
-+
-+	priv->cm.srq_ring = kzalloc(ipoib_recvq_size * sizeof *priv->cm.srq_ring,
-+				    GFP_KERNEL);
-+	if (!priv->cm.srq_ring) {
-+		printk(KERN_WARNING "%s: failed to allocate CM SRQ ring (%d entries)\n",
-+		       priv->ca->name, ipoib_recvq_size);
-+		ib_destroy_srq(priv->cm.srq);
-+		priv->cm.srq = NULL;
-+	}
-+}
-+
-+int ipoib_cm_dev_init(struct net_device *dev)
-+{
-+	struct ipoib_dev_priv *priv = netdev_priv(dev);
-+	int i, ret;
-+	struct ib_device_attr attr;
+ 	struct mt2266_priv *priv = fe->tuner_priv;
+-	mt2266_writereg(priv,0x17,0x6d);
+-	mt2266_writereg(priv,0x1c,0x00);
++	mt2266_writereg(priv, 0x17, 0x6d);
++	mt2266_writereg(priv, 0x1c, 0x00);
+ 	return 0;
+ }
  
- 	INIT_LIST_HEAD(&priv->cm.passive_ids);
- 	INIT_LIST_HEAD(&priv->cm.reap_list);
-@@ -1281,43 +1449,53 @@ int ipoib_cm_dev_init(struct net_device *dev)
+@@ -241,8 +304,8 @@ static int mt2266_release(struct dvb_frontend *fe)
+ static const struct dvb_tuner_ops mt2266_tuner_ops = {
+ 	.info = {
+ 		.name           = "Microtune MT2266",
+-		.frequency_min  = 470000000,
+-		.frequency_max  = 860000000,
++		.frequency_min  = 174000000,
++		.frequency_max  = 862000000,
+ 		.frequency_step =     50000,
+ 	},
+ 	.release       = mt2266_release,
+@@ -264,8 +327,9 @@ struct dvb_frontend * mt2266_attach(struct dvb_frontend *fe, struct i2c_adapter
  
- 	skb_queue_head_init(&priv->cm.skb_queue);
+ 	priv->cfg      = cfg;
+ 	priv->i2c      = i2c;
++	priv->band     = MT2266_UHF;
  
--	priv->cm.srq = ib_create_srq(priv->pd, &srq_init_attr);
--	if (IS_ERR(priv->cm.srq)) {
--		ret = PTR_ERR(priv->cm.srq);
--		priv->cm.srq = NULL;
-+	ret = ib_query_device(priv->ca, &attr);
-+	if (ret) {
-+		printk(KERN_WARNING "ib_query_device() failed with %d\n", ret);
- 		return ret;
+-	if (mt2266_readreg(priv,0,&id) != 0) {
++	if (mt2266_readreg(priv, 0, &id)) {
+ 		kfree(priv);
+ 		return NULL;
  	}
+diff --git a/drivers/media/dvb/frontends/mt312.c b/drivers/media/dvb/frontends/mt312.c
+index 0606b9a..1638301 100644
+--- a/drivers/media/dvb/frontends/mt312.c
++++ b/drivers/media/dvb/frontends/mt312.c
+@@ -37,9 +37,9 @@
  
--	priv->cm.srq_ring = kzalloc(ipoib_recvq_size * sizeof *priv->cm.srq_ring,
--				    GFP_KERNEL);
--	if (!priv->cm.srq_ring) {
--		printk(KERN_WARNING "%s: failed to allocate CM ring (%d entries)\n",
--		       priv->ca->name, ipoib_recvq_size);
--		ipoib_cm_dev_cleanup(dev);
--		return -ENOMEM;
-+	ipoib_dbg(priv, "max_srq_sge=%d\n", attr.max_srq_sge);
-+
-+	attr.max_srq_sge = min_t(int, IPOIB_CM_RX_SG, attr.max_srq_sge);
-+	ipoib_cm_create_srq(dev, attr.max_srq_sge);
-+	if (ipoib_cm_has_srq(dev)) {
-+		priv->cm.max_cm_mtu = attr.max_srq_sge * PAGE_SIZE - 0x10;
-+		priv->cm.num_frags  = attr.max_srq_sge;
-+		ipoib_dbg(priv, "max_cm_mtu = 0x%x, num_frags=%d\n",
-+			  priv->cm.max_cm_mtu, priv->cm.num_frags);
-+	} else {
-+		priv->cm.max_cm_mtu = IPOIB_CM_MTU;
-+		priv->cm.num_frags  = IPOIB_CM_RX_SG;
- 	}
  
--	for (i = 0; i < IPOIB_CM_RX_SG; ++i)
-+	for (i = 0; i < priv->cm.num_frags; ++i)
- 		priv->cm.rx_sge[i].lkey	= priv->mr->lkey;
+ struct mt312_state {
+-	struct i2c_adapter* i2c;
++	struct i2c_adapter *i2c;
+ 	/* configuration settings */
+-	const struct mt312_config* config;
++	const struct mt312_config *config;
+ 	struct dvb_frontend frontend;
  
- 	priv->cm.rx_sge[0].length = IPOIB_CM_HEAD_SIZE;
--	for (i = 1; i < IPOIB_CM_RX_SG; ++i)
-+	for (i = 1; i < priv->cm.num_frags; ++i)
- 		priv->cm.rx_sge[i].length = PAGE_SIZE;
- 	priv->cm.rx_wr.next = NULL;
- 	priv->cm.rx_wr.sg_list = priv->cm.rx_sge;
--	priv->cm.rx_wr.num_sge = IPOIB_CM_RX_SG;
-+	priv->cm.rx_wr.num_sge = priv->cm.num_frags;
-+
-+	if (ipoib_cm_has_srq(dev)) {
-+		for (i = 0; i < ipoib_recvq_size; ++i) {
-+			if (!ipoib_cm_alloc_rx_skb(dev, priv->cm.srq_ring, i,
-+						   priv->cm.num_frags - 1,
-+						   priv->cm.srq_ring[i].mapping)) {
-+				ipoib_warn(priv, "failed to allocate "
-+					   "receive buffer %d\n", i);
-+				ipoib_cm_dev_cleanup(dev);
-+				return -ENOMEM;
-+			}
+ 	u8 id;
+@@ -49,14 +49,15 @@ struct mt312_state {
+ static int debug;
+ #define dprintk(args...) \
+ 	do { \
+-		if (debug) printk(KERN_DEBUG "mt312: " args); \
++		if (debug) \
++			printk(KERN_DEBUG "mt312: " args); \
+ 	} while (0)
  
--	for (i = 0; i < ipoib_recvq_size; ++i) {
--		if (!ipoib_cm_alloc_rx_skb(dev, i, IPOIB_CM_RX_SG - 1,
--					   priv->cm.srq_ring[i].mapping)) {
--			ipoib_warn(priv, "failed to allocate receive buffer %d\n", i);
--			ipoib_cm_dev_cleanup(dev);
--			return -ENOMEM;
--		}
--		if (ipoib_cm_post_receive(dev, i)) {
--			ipoib_warn(priv, "ipoib_ib_post_receive failed for buf %d\n", i);
--			ipoib_cm_dev_cleanup(dev);
--			return -EIO;
-+			if (ipoib_cm_post_receive_srq(dev, i)) {
-+				ipoib_warn(priv, "ipoib_cm_post_receive_srq "
-+					   "failed for buf %d\n", i);
-+				ipoib_cm_dev_cleanup(dev);
-+				return -EIO;
-+			}
- 		}
- 	}
+ #define MT312_SYS_CLK		90000000UL	/* 90 MHz */
+ #define MT312_LPOWER_SYS_CLK	60000000UL	/* 60 MHz */
+ #define MT312_PLL_CLK		10000000UL	/* 10 MHz */
  
-@@ -1328,7 +1506,7 @@ int ipoib_cm_dev_init(struct net_device *dev)
- void ipoib_cm_dev_cleanup(struct net_device *dev)
+-static int mt312_read(struct mt312_state* state, const enum mt312_reg_addr reg,
++static int mt312_read(struct mt312_state *state, const enum mt312_reg_addr reg,
+ 		      void *buf, const size_t count)
  {
- 	struct ipoib_dev_priv *priv = netdev_priv(dev);
--	int i, ret;
-+	int ret;
+ 	int ret;
+@@ -79,7 +80,7 @@ static int mt312_read(struct mt312_state* state, const enum mt312_reg_addr reg,
+ 		return -EREMOTEIO;
+ 	}
  
- 	if (!priv->cm.srq)
- 		return;
-@@ -1342,13 +1520,7 @@ void ipoib_cm_dev_cleanup(struct net_device *dev)
- 	priv->cm.srq = NULL;
- 	if (!priv->cm.srq_ring)
- 		return;
--	for (i = 0; i < ipoib_recvq_size; ++i)
--		if (priv->cm.srq_ring[i].skb) {
--			ipoib_cm_dma_unmap_rx(priv, IPOIB_CM_RX_SG - 1,
--					      priv->cm.srq_ring[i].mapping);
--			dev_kfree_skb_any(priv->cm.srq_ring[i].skb);
--			priv->cm.srq_ring[i].skb = NULL;
--		}
--	kfree(priv->cm.srq_ring);
-+
-+	ipoib_cm_free_rx_ring(dev, priv->cm.srq_ring);
- 	priv->cm.srq_ring = NULL;
+-	if(debug) {
++	if (debug) {
+ 		int i;
+ 		dprintk("R(%d):", reg & 0x7f);
+ 		for (i = 0; i < count; i++)
+@@ -90,14 +91,14 @@ static int mt312_read(struct mt312_state* state, const enum mt312_reg_addr reg,
+ 	return 0;
  }
-diff --git a/drivers/infiniband/ulp/ipoib/ipoib_fs.c b/drivers/infiniband/ulp/ipoib/ipoib_fs.c
-index 44c1741..8b882bb 100644
---- a/drivers/infiniband/ulp/ipoib/ipoib_fs.c
-+++ b/drivers/infiniband/ulp/ipoib/ipoib_fs.c
-@@ -124,7 +124,7 @@ static int ipoib_mcg_seq_show(struct seq_file *file, void *iter_ptr)
+ 
+-static int mt312_write(struct mt312_state* state, const enum mt312_reg_addr reg,
++static int mt312_write(struct mt312_state *state, const enum mt312_reg_addr reg,
+ 		       const void *src, const size_t count)
+ {
+ 	int ret;
+ 	u8 buf[count + 1];
+ 	struct i2c_msg msg;
+ 
+-	if(debug) {
++	if (debug) {
+ 		int i;
+ 		dprintk("W(%d):", reg & 0x7f);
+ 		for (i = 0; i < count; i++)
+@@ -123,13 +124,13 @@ static int mt312_write(struct mt312_state* state, const enum mt312_reg_addr reg,
  	return 0;
  }
  
--static struct seq_operations ipoib_mcg_seq_ops = {
-+static const struct seq_operations ipoib_mcg_seq_ops = {
- 	.start = ipoib_mcg_seq_start,
- 	.next  = ipoib_mcg_seq_next,
- 	.stop  = ipoib_mcg_seq_stop,
-@@ -230,7 +230,7 @@ static int ipoib_path_seq_show(struct seq_file *file, void *iter_ptr)
+-static inline int mt312_readreg(struct mt312_state* state,
++static inline int mt312_readreg(struct mt312_state *state,
+ 				const enum mt312_reg_addr reg, u8 *val)
+ {
+ 	return mt312_read(state, reg, val, 1);
+ }
+ 
+-static inline int mt312_writereg(struct mt312_state* state,
++static inline int mt312_writereg(struct mt312_state *state,
+ 				 const enum mt312_reg_addr reg, const u8 val)
+ {
+ 	return mt312_write(state, reg, &val, 1);
+@@ -140,18 +141,19 @@ static inline u32 mt312_div(u32 a, u32 b)
+ 	return (a + (b / 2)) / b;
+ }
+ 
+-static int mt312_reset(struct mt312_state* state, const u8 full)
++static int mt312_reset(struct mt312_state *state, const u8 full)
+ {
+ 	return mt312_writereg(state, RESET, full ? 0x80 : 0x40);
+ }
+ 
+-static int mt312_get_inversion(struct mt312_state* state,
++static int mt312_get_inversion(struct mt312_state *state,
+ 			       fe_spectral_inversion_t *i)
+ {
+ 	int ret;
+ 	u8 vit_mode;
+ 
+-	if ((ret = mt312_readreg(state, VIT_MODE, &vit_mode)) < 0)
++	ret = mt312_readreg(state, VIT_MODE, &vit_mode);
++	if (ret < 0)
+ 		return ret;
+ 
+ 	if (vit_mode & 0x80)	/* auto inversion was used */
+@@ -160,7 +162,7 @@ static int mt312_get_inversion(struct mt312_state* state,
  	return 0;
  }
  
--static struct seq_operations ipoib_path_seq_ops = {
-+static const struct seq_operations ipoib_path_seq_ops = {
- 	.start = ipoib_path_seq_start,
- 	.next  = ipoib_path_seq_next,
- 	.stop  = ipoib_path_seq_stop,
-diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/drivers/infiniband/ulp/ipoib/ipoib_ib.c
-index 5063dd5..52bc2bd 100644
---- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c
-+++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c
-@@ -345,12 +345,12 @@ static inline int post_send(struct ipoib_dev_priv *priv,
+-static int mt312_get_symbol_rate(struct mt312_state* state, u32 *sr)
++static int mt312_get_symbol_rate(struct mt312_state *state, u32 *sr)
  {
- 	struct ib_send_wr *bad_wr;
+ 	int ret;
+ 	u8 sym_rate_h;
+@@ -169,37 +171,44 @@ static int mt312_get_symbol_rate(struct mt312_state* state, u32 *sr)
+ 	u16 monitor;
+ 	u8 buf[2];
  
--	priv->tx_sge.addr             = addr;
--	priv->tx_sge.length           = len;
-+	priv->tx_sge.addr	      = addr;
-+	priv->tx_sge.length	      = len;
+-	if ((ret = mt312_readreg(state, SYM_RATE_H, &sym_rate_h)) < 0)
++	ret = mt312_readreg(state, SYM_RATE_H, &sym_rate_h);
++	if (ret < 0)
+ 		return ret;
  
--	priv->tx_wr.wr_id 	      = wr_id;
-+	priv->tx_wr.wr_id	      = wr_id;
- 	priv->tx_wr.wr.ud.remote_qpn  = qpn;
--	priv->tx_wr.wr.ud.ah 	      = address;
-+	priv->tx_wr.wr.ud.ah	      = address;
+-	if (sym_rate_h & 0x80) {	/* symbol rate search was used */
+-		if ((ret = mt312_writereg(state, MON_CTRL, 0x03)) < 0)
++	if (sym_rate_h & 0x80) {
++		/* symbol rate search was used */
++		ret = mt312_writereg(state, MON_CTRL, 0x03);
++		if (ret < 0)
+ 			return ret;
  
- 	return ib_post_send(priv->qp, &priv->tx_wr, &bad_wr);
- }
-diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c
-index c9f6077..a082466 100644
---- a/drivers/infiniband/ulp/ipoib/ipoib_main.c
-+++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c
-@@ -182,17 +182,20 @@ static int ipoib_change_mtu(struct net_device *dev, int new_mtu)
- 	struct ipoib_dev_priv *priv = netdev_priv(dev);
+-		if ((ret = mt312_read(state, MONITOR_H, buf, sizeof(buf))) < 0)
++		ret = mt312_read(state, MONITOR_H, buf, sizeof(buf));
++		if (ret < 0)
+ 			return ret;
  
- 	/* dev->mtu > 2K ==> connected mode */
--	if (ipoib_cm_admin_enabled(dev) && new_mtu <= IPOIB_CM_MTU) {
-+	if (ipoib_cm_admin_enabled(dev)) {
-+		if (new_mtu > ipoib_cm_max_mtu(dev))
-+			return -EINVAL;
-+
- 		if (new_mtu > priv->mcast_mtu)
- 			ipoib_warn(priv, "mtu > %d will cause multicast packet drops.\n",
- 				   priv->mcast_mtu);
-+
- 		dev->mtu = new_mtu;
- 		return 0;
- 	}
+ 		monitor = (buf[0] << 8) | buf[1];
  
--	if (new_mtu > IPOIB_PACKET_SIZE - IPOIB_ENCAP_LEN) {
-+	if (new_mtu > IPOIB_PACKET_SIZE - IPOIB_ENCAP_LEN)
- 		return -EINVAL;
--	}
+-		dprintk(KERN_DEBUG "sr(auto) = %u\n",
++		dprintk("sr(auto) = %u\n",
+ 		       mt312_div(monitor * 15625, 4));
+ 	} else {
+-		if ((ret = mt312_writereg(state, MON_CTRL, 0x05)) < 0)
++		ret = mt312_writereg(state, MON_CTRL, 0x05);
++		if (ret < 0)
+ 			return ret;
  
- 	priv->admin_mtu = new_mtu;
+-		if ((ret = mt312_read(state, MONITOR_H, buf, sizeof(buf))) < 0)
++		ret = mt312_read(state, MONITOR_H, buf, sizeof(buf));
++		if (ret < 0)
+ 			return ret;
  
-@@ -474,8 +477,8 @@ static struct ipoib_path *path_rec_create(struct net_device *dev, void *gid)
- 	INIT_LIST_HEAD(&path->neigh_list);
+ 		dec_ratio = ((buf[0] >> 5) & 0x07) * 32;
  
- 	memcpy(path->pathrec.dgid.raw, gid, sizeof (union ib_gid));
--	path->pathrec.sgid          = priv->local_gid;
--	path->pathrec.pkey          = cpu_to_be16(priv->pkey);
-+	path->pathrec.sgid	    = priv->local_gid;
-+	path->pathrec.pkey	    = cpu_to_be16(priv->pkey);
- 	path->pathrec.numb_path     = 1;
- 	path->pathrec.traffic_class = priv->broadcast->mcmember.traffic_class;
+-		if ((ret = mt312_read(state, SYM_RAT_OP_H, buf, sizeof(buf))) < 0)
++		ret = mt312_read(state, SYM_RAT_OP_H, buf, sizeof(buf));
++		if (ret < 0)
+ 			return ret;
  
-@@ -669,16 +672,6 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev)
- 	if (unlikely(!spin_trylock_irqsave(&priv->tx_lock, flags)))
- 		return NETDEV_TX_LOCKED;
+ 		sym_rat_op = (buf[0] << 8) | buf[1];
  
--	/*
--	 * Check if our queue is stopped.  Since we have the LLTX bit
--	 * set, we can't rely on netif_stop_queue() preventing our
--	 * xmit function from being called with a full queue.
--	 */
--	if (unlikely(netif_queue_stopped(dev))) {
--		spin_unlock_irqrestore(&priv->tx_lock, flags);
--		return NETDEV_TX_BUSY;
--	}
--
- 	if (likely(skb->dst && skb->dst->neighbour)) {
- 		if (unlikely(!*to_ipoib_neigh(skb->dst->neighbour))) {
- 			ipoib_path_lookup(skb, dev);
-@@ -950,34 +943,34 @@ static void ipoib_setup(struct net_device *dev)
- {
- 	struct ipoib_dev_priv *priv = netdev_priv(dev);
+-		dprintk(KERN_DEBUG "sym_rat_op=%d dec_ratio=%d\n",
++		dprintk("sym_rat_op=%d dec_ratio=%d\n",
+ 		       sym_rat_op, dec_ratio);
+-		dprintk(KERN_DEBUG "*sr(manual) = %lu\n",
++		dprintk("*sr(manual) = %lu\n",
+ 		       (((MT312_PLL_CLK * 8192) / (sym_rat_op + 8192)) *
+ 			2) - dec_ratio);
+ 	}
+@@ -207,7 +216,7 @@ static int mt312_get_symbol_rate(struct mt312_state* state, u32 *sr)
+ 	return 0;
+ }
  
--	dev->open 		 = ipoib_open;
--	dev->stop 		 = ipoib_stop;
--	dev->change_mtu 	 = ipoib_change_mtu;
--	dev->hard_start_xmit 	 = ipoib_start_xmit;
--	dev->tx_timeout 	 = ipoib_timeout;
--	dev->header_ops 	 = &ipoib_header_ops;
--	dev->set_multicast_list  = ipoib_set_mcast_list;
--	dev->neigh_setup         = ipoib_neigh_setup_dev;
-+	dev->open		 = ipoib_open;
-+	dev->stop		 = ipoib_stop;
-+	dev->change_mtu		 = ipoib_change_mtu;
-+	dev->hard_start_xmit	 = ipoib_start_xmit;
-+	dev->tx_timeout		 = ipoib_timeout;
-+	dev->header_ops		 = &ipoib_header_ops;
-+	dev->set_multicast_list	 = ipoib_set_mcast_list;
-+	dev->neigh_setup	 = ipoib_neigh_setup_dev;
+-static int mt312_get_code_rate(struct mt312_state* state, fe_code_rate_t *cr)
++static int mt312_get_code_rate(struct mt312_state *state, fe_code_rate_t *cr)
+ {
+ 	const fe_code_rate_t fec_tab[8] =
+ 	    { FEC_1_2, FEC_2_3, FEC_3_4, FEC_5_6, FEC_6_7, FEC_7_8,
+@@ -216,7 +225,8 @@ static int mt312_get_code_rate(struct mt312_state* state, fe_code_rate_t *cr)
+ 	int ret;
+ 	u8 fec_status;
  
- 	netif_napi_add(dev, &priv->napi, ipoib_poll, 100);
+-	if ((ret = mt312_readreg(state, FEC_STATUS, &fec_status)) < 0)
++	ret = mt312_readreg(state, FEC_STATUS, &fec_status);
++	if (ret < 0)
+ 		return ret;
  
--	dev->watchdog_timeo 	 = HZ;
-+	dev->watchdog_timeo	 = HZ;
+ 	*cr = fec_tab[(fec_status >> 4) & 0x07];
+@@ -224,61 +234,72 @@ static int mt312_get_code_rate(struct mt312_state* state, fe_code_rate_t *cr)
+ 	return 0;
+ }
  
--	dev->flags              |= IFF_BROADCAST | IFF_MULTICAST;
-+	dev->flags		|= IFF_BROADCAST | IFF_MULTICAST;
+-static int mt312_initfe(struct dvb_frontend* fe)
++static int mt312_initfe(struct dvb_frontend *fe)
+ {
+ 	struct mt312_state *state = fe->demodulator_priv;
+ 	int ret;
+ 	u8 buf[2];
  
- 	/*
- 	 * We add in INFINIBAND_ALEN to allow for the destination
- 	 * address "pseudoheader" for skbs without neighbour struct.
- 	 */
--	dev->hard_header_len 	 = IPOIB_ENCAP_LEN + INFINIBAND_ALEN;
--	dev->addr_len 		 = INFINIBAND_ALEN;
--	dev->type 		 = ARPHRD_INFINIBAND;
--	dev->tx_queue_len 	 = ipoib_sendq_size * 2;
--	dev->features            = NETIF_F_VLAN_CHALLENGED | NETIF_F_LLTX;
-+	dev->hard_header_len	 = IPOIB_ENCAP_LEN + INFINIBAND_ALEN;
-+	dev->addr_len		 = INFINIBAND_ALEN;
-+	dev->type		 = ARPHRD_INFINIBAND;
-+	dev->tx_queue_len	 = ipoib_sendq_size * 2;
-+	dev->features		 = NETIF_F_VLAN_CHALLENGED | NETIF_F_LLTX;
+ 	/* wake up */
+-	if ((ret = mt312_writereg(state, CONFIG, (state->frequency == 60 ? 0x88 : 0x8c))) < 0)
++	ret = mt312_writereg(state, CONFIG,
++			(state->frequency == 60 ? 0x88 : 0x8c));
++	if (ret < 0)
+ 		return ret;
  
- 	/* MTU will be reset when mcast join happens */
--	dev->mtu 		 = IPOIB_PACKET_SIZE - IPOIB_ENCAP_LEN;
--	priv->mcast_mtu 	 = priv->admin_mtu = dev->mtu;
-+	dev->mtu		 = IPOIB_PACKET_SIZE - IPOIB_ENCAP_LEN;
-+	priv->mcast_mtu		 = priv->admin_mtu = dev->mtu;
+ 	/* wait at least 150 usec */
+ 	udelay(150);
  
- 	memcpy(dev->broadcast, ipv4_bcast_addr, INFINIBAND_ALEN);
+ 	/* full reset */
+-	if ((ret = mt312_reset(state, 1)) < 0)
++	ret = mt312_reset(state, 1);
++	if (ret < 0)
+ 		return ret;
  
-@@ -1268,6 +1261,9 @@ static int __init ipoib_init_module(void)
- 	ipoib_sendq_size = roundup_pow_of_two(ipoib_sendq_size);
- 	ipoib_sendq_size = min(ipoib_sendq_size, IPOIB_MAX_QUEUE_SIZE);
- 	ipoib_sendq_size = max(ipoib_sendq_size, IPOIB_MIN_QUEUE_SIZE);
-+#ifdef CONFIG_INFINIBAND_IPOIB_CM
-+	ipoib_max_conn_qp = min(ipoib_max_conn_qp, IPOIB_CM_MAX_CONN_QP);
-+#endif
+-// Per datasheet, write correct values. 09/28/03 ACCJr.
+-// If we don't do this, we won't get FE_HAS_VITERBI in the VP310.
++/* Per datasheet, write correct values. 09/28/03 ACCJr.
++ * If we don't do this, we won't get FE_HAS_VITERBI in the VP310. */
+ 	{
+-		u8 buf_def[8]={0x14, 0x12, 0x03, 0x02, 0x01, 0x00, 0x00, 0x00};
++		u8 buf_def[8] = { 0x14, 0x12, 0x03, 0x02,
++				  0x01, 0x00, 0x00, 0x00 };
  
- 	ret = ipoib_register_debugfs();
- 	if (ret)
-diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
-index 9bcfc7a..2628339 100644
---- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
-+++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
-@@ -702,7 +702,7 @@ void ipoib_mcast_send(struct net_device *dev, void *mgid, struct sk_buff *skb)
+-		if ((ret = mt312_write(state, VIT_SETUP, buf_def, sizeof(buf_def))) < 0)
++		ret = mt312_write(state, VIT_SETUP, buf_def, sizeof(buf_def));
++		if (ret < 0)
+ 			return ret;
+ 	}
  
- out:
- 	if (mcast && mcast->ah) {
--		if (skb->dst            &&
-+		if (skb->dst		&&
- 		    skb->dst->neighbour &&
- 		    !*to_ipoib_neigh(skb->dst->neighbour)) {
- 			struct ipoib_neigh *neigh = ipoib_neigh_alloc(skb->dst->neighbour,
-@@ -710,7 +710,7 @@ out:
+ 	/* SYS_CLK */
+-	buf[0] = mt312_div((state->frequency == 60 ? MT312_LPOWER_SYS_CLK : MT312_SYS_CLK) * 2, 1000000);
++	buf[0] = mt312_div((state->frequency == 60 ? MT312_LPOWER_SYS_CLK :
++				MT312_SYS_CLK) * 2, 1000000);
  
- 			if (neigh) {
- 				kref_get(&mcast->ah->ref);
--				neigh->ah  	= mcast->ah;
-+				neigh->ah	= mcast->ah;
- 				list_add_tail(&neigh->list, &mcast->neigh_list);
- 			}
- 		}
-@@ -788,10 +788,6 @@ void ipoib_mcast_restart_task(struct work_struct *work)
+ 	/* DISEQC_RATIO */
+ 	buf[1] = mt312_div(MT312_PLL_CLK, 15000 * 4);
  
- 		memcpy(mgid.raw, mclist->dmi_addr + 4, sizeof mgid);
+-	if ((ret = mt312_write(state, SYS_CLK, buf, sizeof(buf))) < 0)
++	ret = mt312_write(state, SYS_CLK, buf, sizeof(buf));
++	if (ret < 0)
+ 		return ret;
  
--		/* Add in the P_Key */
--		mgid.raw[4] = (priv->pkey >> 8) & 0xff;
--		mgid.raw[5] = priv->pkey & 0xff;
--
- 		mcast = __ipoib_mcast_find(dev, &mgid);
- 		if (!mcast || test_bit(IPOIB_MCAST_FLAG_SENDONLY, &mcast->flags)) {
- 			struct ipoib_mcast *nmcast;
-diff --git a/drivers/infiniband/ulp/ipoib/ipoib_verbs.c b/drivers/infiniband/ulp/ipoib/ipoib_verbs.c
-index 3c6e45d..433e99a 100644
---- a/drivers/infiniband/ulp/ipoib/ipoib_verbs.c
-+++ b/drivers/infiniband/ulp/ipoib/ipoib_verbs.c
-@@ -172,8 +172,12 @@ int ipoib_transport_dev_init(struct net_device *dev, struct ib_device *ca)
+-	if ((ret = mt312_writereg(state, SNR_THS_HIGH, 0x32)) < 0)
++	ret = mt312_writereg(state, SNR_THS_HIGH, 0x32);
++	if (ret < 0)
+ 		return ret;
  
- 	size = ipoib_sendq_size + ipoib_recvq_size + 1;
- 	ret = ipoib_cm_dev_init(dev);
--	if (!ret)
--		size += ipoib_recvq_size + 1 /* 1 extra for rx_drain_qp */;
-+	if (!ret) {
-+		if (ipoib_cm_has_srq(dev))
-+			size += ipoib_recvq_size + 1; /* 1 extra for rx_drain_qp */
-+		else
-+			size += ipoib_recvq_size * ipoib_max_conn_qp;
-+	}
+-	if ((ret = mt312_writereg(state, OP_CTRL, 0x53)) < 0)
++	ret = mt312_writereg(state, OP_CTRL, 0x53);
++	if (ret < 0)
+ 		return ret;
  
- 	priv->cq = ib_create_cq(priv->ca, ipoib_ib_completion, NULL, dev, size, 0);
- 	if (IS_ERR(priv->cq)) {
-@@ -197,12 +201,12 @@ int ipoib_transport_dev_init(struct net_device *dev, struct ib_device *ca)
- 	priv->dev->dev_addr[2] = (priv->qp->qp_num >>  8) & 0xff;
- 	priv->dev->dev_addr[3] = (priv->qp->qp_num      ) & 0xff;
+ 	/* TS_SW_LIM */
+ 	buf[0] = 0x8c;
+ 	buf[1] = 0x98;
  
--	priv->tx_sge.lkey 	= priv->mr->lkey;
-+	priv->tx_sge.lkey	= priv->mr->lkey;
+-	if ((ret = mt312_write(state, TS_SW_LIM_L, buf, sizeof(buf))) < 0)
++	ret = mt312_write(state, TS_SW_LIM_L, buf, sizeof(buf));
++	if (ret < 0)
+ 		return ret;
  
--	priv->tx_wr.opcode 	= IB_WR_SEND;
--	priv->tx_wr.sg_list 	= &priv->tx_sge;
--	priv->tx_wr.num_sge 	= 1;
--	priv->tx_wr.send_flags 	= IB_SEND_SIGNALED;
-+	priv->tx_wr.opcode	= IB_WR_SEND;
-+	priv->tx_wr.sg_list	= &priv->tx_sge;
-+	priv->tx_wr.num_sge	= 1;
-+	priv->tx_wr.send_flags	= IB_SEND_SIGNALED;
+-	if ((ret = mt312_writereg(state, CS_SW_LIM, 0x69)) < 0)
++	ret = mt312_writereg(state, CS_SW_LIM, 0x69);
++	if (ret < 0)
+ 		return ret;
  
  	return 0;
+ }
  
-diff --git a/drivers/infiniband/ulp/iser/Kconfig b/drivers/infiniband/ulp/iser/Kconfig
-index fe604c8..77dedba 100644
---- a/drivers/infiniband/ulp/iser/Kconfig
-+++ b/drivers/infiniband/ulp/iser/Kconfig
-@@ -8,5 +8,5 @@ config INFINIBAND_ISER
-           that speak iSCSI over iSER over InfiniBand.
- 
- 	  The iSER protocol is defined by IETF.
--	  See <http://www.ietf.org/internet-drafts/draft-ietf-ips-iser-05.txt>
--	  and <http://www.infinibandta.org/members/spec/iser_annex_060418.pdf>
-+	  See <http://www.ietf.org/rfc/rfc5046.txt>
-+	  and <http://www.infinibandta.org/members/spec/Annex_iSER.PDF>
-diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c
-index bad8dac..be1b9fb 100644
---- a/drivers/infiniband/ulp/iser/iscsi_iser.c
-+++ b/drivers/infiniband/ulp/iser/iscsi_iser.c
-@@ -129,7 +129,7 @@ error:
-  * iscsi_iser_cmd_init - Initialize iSCSI SCSI_READ or SCSI_WRITE commands
-  *
-  **/
--static void
-+static int
- iscsi_iser_cmd_init(struct iscsi_cmd_task *ctask)
+-static int mt312_send_master_cmd(struct dvb_frontend* fe,
++static int mt312_send_master_cmd(struct dvb_frontend *fe,
+ 				 struct dvb_diseqc_master_cmd *c)
  {
- 	struct iscsi_iser_conn     *iser_conn  = ctask->conn->dd_data;
-@@ -138,6 +138,7 @@ iscsi_iser_cmd_init(struct iscsi_cmd_task *ctask)
- 	iser_ctask->command_sent = 0;
- 	iser_ctask->iser_conn    = iser_conn;
- 	iser_ctask_rdma_init(iser_ctask);
-+	return 0;
- }
+ 	struct mt312_state *state = fe->demodulator_priv;
+@@ -288,29 +309,31 @@ static int mt312_send_master_cmd(struct dvb_frontend* fe,
+ 	if ((c->msg_len == 0) || (c->msg_len > sizeof(c->msg)))
+ 		return -EINVAL;
  
- /**
-@@ -220,12 +221,6 @@ iscsi_iser_ctask_xmit(struct iscsi_conn *conn,
- 	debug_scsi("ctask deq [cid %d itt 0x%x]\n",
- 		   conn->id, ctask->itt);
+-	if ((ret = mt312_readreg(state, DISEQC_MODE, &diseqc_mode)) < 0)
++	ret = mt312_readreg(state, DISEQC_MODE, &diseqc_mode);
++	if (ret < 0)
+ 		return ret;
  
--	/*
--	 * serialize with TMF AbortTask
--	 */
--	if (ctask->mtask)
--		return error;
--
- 	/* Send the cmd PDU */
- 	if (!iser_ctask->command_sent) {
- 		error = iser_send_command(conn, ctask);
-@@ -406,6 +401,7 @@ iscsi_iser_session_create(struct iscsi_transport *iscsit,
- 		ctask      = session->cmds[i];
- 		iser_ctask = ctask->dd_data;
- 		ctask->hdr = (struct iscsi_cmd *)&iser_ctask->desc.iscsi_header;
-+		ctask->hdr_max = sizeof(iser_ctask->desc.iscsi_header);
- 	}
+-	if ((ret =
+-	     mt312_write(state, (0x80 | DISEQC_INSTR), c->msg, c->msg_len)) < 0)
++	ret = mt312_write(state, (0x80 | DISEQC_INSTR), c->msg, c->msg_len);
++	if (ret < 0)
+ 		return ret;
  
- 	for (i = 0; i < session->mgmtpool_max; i++) {
-@@ -551,11 +547,13 @@ static struct scsi_host_template iscsi_iser_sht = {
- 	.module                 = THIS_MODULE,
- 	.name                   = "iSCSI Initiator over iSER, v." DRV_VER,
- 	.queuecommand           = iscsi_queuecommand,
-+	.change_queue_depth	= iscsi_change_queue_depth,
- 	.can_queue		= ISCSI_DEF_XMIT_CMDS_MAX - 1,
- 	.sg_tablesize           = ISCSI_ISER_SG_TABLESIZE,
- 	.max_sectors		= 1024,
- 	.cmd_per_lun            = ISCSI_MAX_CMD_PER_LUN,
- 	.eh_abort_handler       = iscsi_eh_abort,
-+	.eh_device_reset_handler= iscsi_eh_device_reset,
- 	.eh_host_reset_handler	= iscsi_eh_host_reset,
- 	.use_clustering         = DISABLE_CLUSTERING,
- 	.proc_name              = "iscsi_iser",
-@@ -582,7 +580,9 @@ static struct iscsi_transport iscsi_iser_transport = {
- 				  ISCSI_PERSISTENT_ADDRESS |
- 				  ISCSI_TARGET_NAME | ISCSI_TPGT |
- 				  ISCSI_USERNAME | ISCSI_PASSWORD |
--				  ISCSI_USERNAME_IN | ISCSI_PASSWORD_IN,
-+				  ISCSI_USERNAME_IN | ISCSI_PASSWORD_IN |
-+				  ISCSI_FAST_ABORT | ISCSI_ABORT_TMO |
-+				  ISCSI_PING_TMO | ISCSI_RECV_TMO,
- 	.host_param_mask	= ISCSI_HOST_HWADDRESS |
- 				  ISCSI_HOST_NETDEV_NAME |
- 				  ISCSI_HOST_INITIATOR_NAME,
-diff --git a/drivers/infiniband/ulp/iser/iser_initiator.c b/drivers/infiniband/ulp/iser/iser_initiator.c
-index a6f2303..83247f1 100644
---- a/drivers/infiniband/ulp/iser/iser_initiator.c
-+++ b/drivers/infiniband/ulp/iser/iser_initiator.c
-@@ -561,7 +561,7 @@ void iser_rcv_completion(struct iser_desc *rx_desc,
- 	if (opcode == ISCSI_OP_SCSI_CMD_RSP) {
- 	        itt = get_itt(hdr->itt); /* mask out cid and age bits */
- 		if (!(itt < session->cmds_max))
--			iser_err("itt can't be matched to task!!!"
-+			iser_err("itt can't be matched to task!!! "
- 				 "conn %p opcode %d cmds_max %d itt %d\n",
- 				 conn->iscsi_conn,opcode,session->cmds_max,itt);
- 		/* use the mapping given with the cmds array indexed by itt */
-@@ -621,9 +621,7 @@ void iser_snd_completion(struct iser_desc *tx_desc)
- 			struct iscsi_session *session = conn->session;
+-	if ((ret =
+-	     mt312_writereg(state, DISEQC_MODE,
+-			    (diseqc_mode & 0x40) | ((c->msg_len - 1) << 3)
+-			    | 0x04)) < 0)
++	ret = mt312_writereg(state, DISEQC_MODE,
++			     (diseqc_mode & 0x40) | ((c->msg_len - 1) << 3)
++			     | 0x04);
++	if (ret < 0)
+ 		return ret;
  
- 			spin_lock(&conn->session->lock);
--			list_del(&mtask->running);
--			__kfifo_put(session->mgmtpool.queue, (void*)&mtask,
--				    sizeof(void*));
-+			iscsi_free_mgmt_task(conn, mtask);
- 			spin_unlock(&session->lock);
- 		}
- 	}
-diff --git a/drivers/infiniband/ulp/iser/iser_verbs.c b/drivers/infiniband/ulp/iser/iser_verbs.c
-index 654a4dc..714b8db 100644
---- a/drivers/infiniband/ulp/iser/iser_verbs.c
-+++ b/drivers/infiniband/ulp/iser/iser_verbs.c
-@@ -105,7 +105,7 @@ pd_err:
+ 	/* set DISEQC_MODE[2:0] to zero if a return message is expected */
+-	if (c->msg[0] & 0x02)
+-		if ((ret =
+-		     mt312_writereg(state, DISEQC_MODE, (diseqc_mode & 0x40))) < 0)
++	if (c->msg[0] & 0x02) {
++		ret = mt312_writereg(state, DISEQC_MODE, (diseqc_mode & 0x40));
++		if (ret < 0)
+ 			return ret;
++	}
+ 
+ 	return 0;
  }
  
- /**
-- * iser_free_device_ib_res - destory/dealloc/dereg the DMA MR,
-+ * iser_free_device_ib_res - destroy/dealloc/dereg the DMA MR,
-  * CQ and PD created with the device associated with the adapator.
-  */
- static void iser_free_device_ib_res(struct iser_device *device)
-@@ -475,13 +475,11 @@ static int iser_cma_handler(struct rdma_cm_id *cma_id, struct rdma_cm_event *eve
- 		iser_disconnected_handler(cma_id);
- 		break;
- 	case RDMA_CM_EVENT_DEVICE_REMOVAL:
-+		iser_err("Device removal is currently unsupported\n");
- 		BUG();
- 		break;
--	case RDMA_CM_EVENT_CONNECT_RESPONSE:
--		BUG();
--		break;
--	case RDMA_CM_EVENT_CONNECT_REQUEST:
- 	default:
-+		iser_err("Unexpected RDMA CM event (%d)\n", event->event);
- 		break;
- 	}
- 	return ret;
-diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c
-index bdb6f85..f2d2c7e 100644
---- a/drivers/infiniband/ulp/srp/ib_srp.c
-+++ b/drivers/infiniband/ulp/srp/ib_srp.c
-@@ -272,7 +272,8 @@ static void srp_path_rec_completion(int status,
+-static int mt312_send_burst(struct dvb_frontend* fe, const fe_sec_mini_cmd_t c)
++static int mt312_send_burst(struct dvb_frontend *fe, const fe_sec_mini_cmd_t c)
+ {
+ 	struct mt312_state *state = fe->demodulator_priv;
+ 	const u8 mini_tab[2] = { 0x02, 0x03 };
+@@ -321,18 +344,19 @@ static int mt312_send_burst(struct dvb_frontend* fe, const fe_sec_mini_cmd_t c)
+ 	if (c > SEC_MINI_B)
+ 		return -EINVAL;
  
- 	target->status = status;
- 	if (status)
--		printk(KERN_ERR PFX "Got failed path rec status %d\n", status);
-+		shost_printk(KERN_ERR, target->scsi_host,
-+			     PFX "Got failed path rec status %d\n", status);
- 	else
- 		target->path = *pathrec;
- 	complete(&target->done);
-@@ -303,7 +304,8 @@ static int srp_lookup_path(struct srp_target_port *target)
- 	wait_for_completion(&target->done);
+-	if ((ret = mt312_readreg(state, DISEQC_MODE, &diseqc_mode)) < 0)
++	ret = mt312_readreg(state, DISEQC_MODE, &diseqc_mode);
++	if (ret < 0)
+ 		return ret;
  
- 	if (target->status < 0)
--		printk(KERN_WARNING PFX "Path record query failed\n");
-+		shost_printk(KERN_WARNING, target->scsi_host,
-+			     PFX "Path record query failed\n");
+-	if ((ret =
+-	     mt312_writereg(state, DISEQC_MODE,
+-			    (diseqc_mode & 0x40) | mini_tab[c])) < 0)
++	ret = mt312_writereg(state, DISEQC_MODE,
++			     (diseqc_mode & 0x40) | mini_tab[c]);
++	if (ret < 0)
+ 		return ret;
  
- 	return target->status;
+ 	return 0;
  }
-@@ -379,9 +381,10 @@ static int srp_send_req(struct srp_target_port *target)
- 	 * the second 8 bytes to the local node GUID.
- 	 */
- 	if (srp_target_is_topspin(target)) {
--		printk(KERN_DEBUG PFX "Topspin/Cisco initiator port ID workaround "
--		       "activated for target GUID %016llx\n",
--		       (unsigned long long) be64_to_cpu(target->ioc_guid));
-+		shost_printk(KERN_DEBUG, target->scsi_host,
-+			     PFX "Topspin/Cisco initiator port ID workaround "
-+			     "activated for target GUID %016llx\n",
-+			     (unsigned long long) be64_to_cpu(target->ioc_guid));
- 		memset(req->priv.initiator_port_id, 0, 8);
- 		memcpy(req->priv.initiator_port_id + 8,
- 		       &target->srp_host->dev->dev->node_guid, 8);
-@@ -400,7 +403,8 @@ static void srp_disconnect_target(struct srp_target_port *target)
  
- 	init_completion(&target->done);
- 	if (ib_send_cm_dreq(target->cm_id, NULL, 0)) {
--		printk(KERN_DEBUG PFX "Sending CM DREQ failed\n");
-+		shost_printk(KERN_DEBUG, target->scsi_host,
-+			     PFX "Sending CM DREQ failed\n");
- 		return;
- 	}
- 	wait_for_completion(&target->done);
-@@ -568,7 +572,8 @@ static int srp_reconnect_target(struct srp_target_port *target)
- 	return ret;
+-static int mt312_set_tone(struct dvb_frontend* fe, const fe_sec_tone_mode_t t)
++static int mt312_set_tone(struct dvb_frontend *fe, const fe_sec_tone_mode_t t)
+ {
+ 	struct mt312_state *state = fe->demodulator_priv;
+ 	const u8 tone_tab[2] = { 0x01, 0x00 };
+@@ -343,18 +367,19 @@ static int mt312_set_tone(struct dvb_frontend* fe, const fe_sec_tone_mode_t t)
+ 	if (t > SEC_TONE_OFF)
+ 		return -EINVAL;
  
- err:
--	printk(KERN_ERR PFX "reconnect failed (%d), removing target port.\n", ret);
-+	shost_printk(KERN_ERR, target->scsi_host,
-+		     PFX "reconnect failed (%d), removing target port.\n", ret);
+-	if ((ret = mt312_readreg(state, DISEQC_MODE, &diseqc_mode)) < 0)
++	ret = mt312_readreg(state, DISEQC_MODE, &diseqc_mode);
++	if (ret < 0)
+ 		return ret;
  
- 	/*
- 	 * We couldn't reconnect, so kill our target port off.
-@@ -683,8 +688,9 @@ static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_target_port *target,
+-	if ((ret =
+-	     mt312_writereg(state, DISEQC_MODE,
+-			    (diseqc_mode & 0x40) | tone_tab[t])) < 0)
++	ret = mt312_writereg(state, DISEQC_MODE,
++			     (diseqc_mode & 0x40) | tone_tab[t]);
++	if (ret < 0)
+ 		return ret;
  
- 	if (scmnd->sc_data_direction != DMA_FROM_DEVICE &&
- 	    scmnd->sc_data_direction != DMA_TO_DEVICE) {
--		printk(KERN_WARNING PFX "Unhandled data direction %d\n",
--		       scmnd->sc_data_direction);
-+		shost_printk(KERN_WARNING, target->scsi_host,
-+			     PFX "Unhandled data direction %d\n",
-+			     scmnd->sc_data_direction);
- 		return -EINVAL;
- 	}
+ 	return 0;
+ }
  
-@@ -786,8 +792,9 @@ static void srp_process_rsp(struct srp_target_port *target, struct srp_rsp *rsp)
- 	} else {
- 		scmnd = req->scmnd;
- 		if (!scmnd)
--			printk(KERN_ERR "Null scmnd for RSP w/tag %016llx\n",
--			       (unsigned long long) rsp->tag);
-+			shost_printk(KERN_ERR, target->scsi_host,
-+				     "Null scmnd for RSP w/tag %016llx\n",
-+				     (unsigned long long) rsp->tag);
- 		scmnd->result = rsp->status;
+-static int mt312_set_voltage(struct dvb_frontend* fe, const fe_sec_voltage_t v)
++static int mt312_set_voltage(struct dvb_frontend *fe, const fe_sec_voltage_t v)
+ {
+ 	struct mt312_state *state = fe->demodulator_priv;
+ 	const u8 volt_tab[3] = { 0x00, 0x40, 0x00 };
+@@ -365,7 +390,7 @@ static int mt312_set_voltage(struct dvb_frontend* fe, const fe_sec_voltage_t v)
+ 	return mt312_writereg(state, DISEQC_MODE, volt_tab[v]);
+ }
  
- 		if (rsp->flags & SRP_RSP_FLAG_SNSVALID) {
-@@ -831,7 +838,8 @@ static void srp_handle_recv(struct srp_target_port *target, struct ib_wc *wc)
- 	if (0) {
- 		int i;
+-static int mt312_read_status(struct dvb_frontend* fe, fe_status_t *s)
++static int mt312_read_status(struct dvb_frontend *fe, fe_status_t *s)
+ {
+ 	struct mt312_state *state = fe->demodulator_priv;
+ 	int ret;
+@@ -373,10 +398,12 @@ static int mt312_read_status(struct dvb_frontend* fe, fe_status_t *s)
  
--		printk(KERN_ERR PFX "recv completion, opcode 0x%02x\n", opcode);
-+		shost_printk(KERN_ERR, target->scsi_host,
-+			     PFX "recv completion, opcode 0x%02x\n", opcode);
+ 	*s = 0;
  
- 		for (i = 0; i < wc->byte_len; ++i) {
- 			if (i % 8 == 0)
-@@ -852,11 +860,13 @@ static void srp_handle_recv(struct srp_target_port *target, struct ib_wc *wc)
+-	if ((ret = mt312_read(state, QPSK_STAT_H, status, sizeof(status))) < 0)
++	ret = mt312_read(state, QPSK_STAT_H, status, sizeof(status));
++	if (ret < 0)
+ 		return ret;
  
- 	case SRP_T_LOGOUT:
- 		/* XXX Handle target logout */
--		printk(KERN_WARNING PFX "Got target logout request\n");
-+		shost_printk(KERN_WARNING, target->scsi_host,
-+			     PFX "Got target logout request\n");
- 		break;
+-	dprintk(KERN_DEBUG "QPSK_STAT_H: 0x%02x, QPSK_STAT_L: 0x%02x, FEC_STATUS: 0x%02x\n", status[0], status[1], status[2]);
++	dprintk("QPSK_STAT_H: 0x%02x, QPSK_STAT_L: 0x%02x,"
++		" FEC_STATUS: 0x%02x\n", status[0], status[1], status[2]);
  
- 	default:
--		printk(KERN_WARNING PFX "Unhandled SRP opcode 0x%02x\n", opcode);
-+		shost_printk(KERN_WARNING, target->scsi_host,
-+			     PFX "Unhandled SRP opcode 0x%02x\n", opcode);
- 		break;
- 	}
+ 	if (status[0] & 0xc0)
+ 		*s |= FE_HAS_SIGNAL;	/* signal noise ratio */
+@@ -392,13 +419,14 @@ static int mt312_read_status(struct dvb_frontend* fe, fe_status_t *s)
+ 	return 0;
+ }
  
-@@ -872,9 +882,10 @@ static void srp_completion(struct ib_cq *cq, void *target_ptr)
- 	ib_req_notify_cq(cq, IB_CQ_NEXT_COMP);
- 	while (ib_poll_cq(cq, 1, &wc) > 0) {
- 		if (wc.status) {
--			printk(KERN_ERR PFX "failed %s status %d\n",
--			       wc.wr_id & SRP_OP_RECV ? "receive" : "send",
--			       wc.status);
-+			shost_printk(KERN_ERR, target->scsi_host,
-+				     PFX "failed %s status %d\n",
-+				     wc.wr_id & SRP_OP_RECV ? "receive" : "send",
-+				     wc.status);
- 			target->qp_in_error = 1;
- 			break;
- 		}
-@@ -930,13 +941,18 @@ static int srp_post_recv(struct srp_target_port *target)
-  * req_lim and tx_head.  Lock cannot be dropped between call here and
-  * call to __srp_post_send().
-  */
--static struct srp_iu *__srp_get_tx_iu(struct srp_target_port *target)
-+static struct srp_iu *__srp_get_tx_iu(struct srp_target_port *target,
-+					enum srp_request_type req_type)
+-static int mt312_read_ber(struct dvb_frontend* fe, u32 *ber)
++static int mt312_read_ber(struct dvb_frontend *fe, u32 *ber)
  {
-+	s32 min = (req_type == SRP_REQ_TASK_MGMT) ? 1 : 2;
-+
- 	if (target->tx_head - target->tx_tail >= SRP_SQ_SIZE)
- 		return NULL;
+ 	struct mt312_state *state = fe->demodulator_priv;
+ 	int ret;
+ 	u8 buf[3];
  
--	if (unlikely(target->req_lim < 1))
-+	if (target->req_lim < min) {
- 		++target->zero_req_lim;
-+		return NULL;
-+	}
+-	if ((ret = mt312_read(state, RS_BERCNT_H, buf, 3)) < 0)
++	ret = mt312_read(state, RS_BERCNT_H, buf, 3);
++	if (ret < 0)
+ 		return ret;
  
- 	return target->tx_ring[target->tx_head & SRP_SQ_SIZE];
+ 	*ber = ((buf[0] << 16) | (buf[1] << 8) | buf[2]) * 64;
+@@ -406,7 +434,8 @@ static int mt312_read_ber(struct dvb_frontend* fe, u32 *ber)
+ 	return 0;
  }
-@@ -993,7 +1009,7 @@ static int srp_queuecommand(struct scsi_cmnd *scmnd,
- 		return 0;
- 	}
  
--	iu = __srp_get_tx_iu(target);
-+	iu = __srp_get_tx_iu(target, SRP_REQ_NORMAL);
- 	if (!iu)
- 		goto err;
+-static int mt312_read_signal_strength(struct dvb_frontend* fe, u16 *signal_strength)
++static int mt312_read_signal_strength(struct dvb_frontend *fe,
++				      u16 *signal_strength)
+ {
+ 	struct mt312_state *state = fe->demodulator_priv;
+ 	int ret;
+@@ -414,7 +443,8 @@ static int mt312_read_signal_strength(struct dvb_frontend* fe, u16 *signal_stren
+ 	u16 agc;
+ 	s16 err_db;
  
-@@ -1022,12 +1038,13 @@ static int srp_queuecommand(struct scsi_cmnd *scmnd,
+-	if ((ret = mt312_read(state, AGC_H, buf, sizeof(buf))) < 0)
++	ret = mt312_read(state, AGC_H, buf, sizeof(buf));
++	if (ret < 0)
+ 		return ret;
  
- 	len = srp_map_data(scmnd, target, req);
- 	if (len < 0) {
--		printk(KERN_ERR PFX "Failed to map data\n");
-+		shost_printk(KERN_ERR, target->scsi_host,
-+			     PFX "Failed to map data\n");
- 		goto err;
- 	}
+ 	agc = (buf[0] << 6) | (buf[1] >> 2);
+@@ -422,18 +452,19 @@ static int mt312_read_signal_strength(struct dvb_frontend* fe, u16 *signal_stren
  
- 	if (__srp_post_recv(target)) {
--		printk(KERN_ERR PFX "Recv failed\n");
-+		shost_printk(KERN_ERR, target->scsi_host, PFX "Recv failed\n");
- 		goto err_unmap;
- 	}
+ 	*signal_strength = agc;
  
-@@ -1035,7 +1052,7 @@ static int srp_queuecommand(struct scsi_cmnd *scmnd,
- 				      DMA_TO_DEVICE);
+-	dprintk(KERN_DEBUG "agc=%08x err_db=%hd\n", agc, err_db);
++	dprintk("agc=%08x err_db=%hd\n", agc, err_db);
  
- 	if (__srp_post_send(target, iu, len)) {
--		printk(KERN_ERR PFX "Send failed\n");
-+		shost_printk(KERN_ERR, target->scsi_host, PFX "Send failed\n");
- 		goto err_unmap;
- 	}
+ 	return 0;
+ }
  
-@@ -1090,6 +1107,7 @@ static void srp_cm_rej_handler(struct ib_cm_id *cm_id,
- 			       struct ib_cm_event *event,
- 			       struct srp_target_port *target)
+-static int mt312_read_snr(struct dvb_frontend* fe, u16 *snr)
++static int mt312_read_snr(struct dvb_frontend *fe, u16 *snr)
  {
-+	struct Scsi_Host *shost = target->scsi_host;
- 	struct ib_class_port_info *cpi;
- 	int opcode;
- 
-@@ -1115,19 +1133,22 @@ static void srp_cm_rej_handler(struct ib_cm_id *cm_id,
- 			memcpy(target->path.dgid.raw,
- 			       event->param.rej_rcvd.ari, 16);
- 
--			printk(KERN_DEBUG PFX "Topspin/Cisco redirect to target port GID %016llx%016llx\n",
--			       (unsigned long long) be64_to_cpu(target->path.dgid.global.subnet_prefix),
--			       (unsigned long long) be64_to_cpu(target->path.dgid.global.interface_id));
-+			shost_printk(KERN_DEBUG, shost,
-+				     PFX "Topspin/Cisco redirect to target port GID %016llx%016llx\n",
-+				     (unsigned long long) be64_to_cpu(target->path.dgid.global.subnet_prefix),
-+				     (unsigned long long) be64_to_cpu(target->path.dgid.global.interface_id));
- 
- 			target->status = SRP_PORT_REDIRECT;
- 		} else {
--			printk(KERN_WARNING "  REJ reason: IB_CM_REJ_PORT_REDIRECT\n");
-+			shost_printk(KERN_WARNING, shost,
-+				     "  REJ reason: IB_CM_REJ_PORT_REDIRECT\n");
- 			target->status = -ECONNRESET;
- 		}
- 		break;
- 
- 	case IB_CM_REJ_DUPLICATE_LOCAL_COMM_ID:
--		printk(KERN_WARNING "  REJ reason: IB_CM_REJ_DUPLICATE_LOCAL_COMM_ID\n");
-+		shost_printk(KERN_WARNING, shost,
-+			    "  REJ reason: IB_CM_REJ_DUPLICATE_LOCAL_COMM_ID\n");
- 		target->status = -ECONNRESET;
- 		break;
- 
-@@ -1138,20 +1159,21 @@ static void srp_cm_rej_handler(struct ib_cm_id *cm_id,
- 			u32 reason = be32_to_cpu(rej->reason);
+ 	struct mt312_state *state = fe->demodulator_priv;
+ 	int ret;
+ 	u8 buf[2];
  
- 			if (reason == SRP_LOGIN_REJ_REQ_IT_IU_LENGTH_TOO_LARGE)
--				printk(KERN_WARNING PFX
--				       "SRP_LOGIN_REJ: requested max_it_iu_len too large\n");
-+				shost_printk(KERN_WARNING, shost,
-+					     PFX "SRP_LOGIN_REJ: requested max_it_iu_len too large\n");
- 			else
--				printk(KERN_WARNING PFX
--				       "SRP LOGIN REJECTED, reason 0x%08x\n", reason);
-+				shost_printk(KERN_WARNING, shost,
-+					    PFX "SRP LOGIN REJECTED, reason 0x%08x\n", reason);
- 		} else
--			printk(KERN_WARNING "  REJ reason: IB_CM_REJ_CONSUMER_DEFINED,"
--			       " opcode 0x%02x\n", opcode);
-+			shost_printk(KERN_WARNING, shost,
-+				     "  REJ reason: IB_CM_REJ_CONSUMER_DEFINED,"
-+				     " opcode 0x%02x\n", opcode);
- 		target->status = -ECONNRESET;
- 		break;
+-	if ((ret = mt312_read(state, M_SNR_H, &buf, sizeof(buf))) < 0)
++	ret = mt312_read(state, M_SNR_H, &buf, sizeof(buf));
++	if (ret < 0)
+ 		return ret;
  
- 	default:
--		printk(KERN_WARNING "  REJ reason 0x%x\n",
--		       event->param.rej_rcvd.reason);
-+		shost_printk(KERN_WARNING, shost, "  REJ reason 0x%x\n",
-+			     event->param.rej_rcvd.reason);
- 		target->status = -ECONNRESET;
- 	}
+ 	*snr = 0xFFFF - ((((buf[0] & 0x7f) << 8) | buf[1]) << 1);
+@@ -441,13 +472,14 @@ static int mt312_read_snr(struct dvb_frontend* fe, u16 *snr)
+ 	return 0;
  }
-@@ -1166,7 +1188,8 @@ static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event)
- 
- 	switch (event->event) {
- 	case IB_CM_REQ_ERROR:
--		printk(KERN_DEBUG PFX "Sending CM REQ failed\n");
-+		shost_printk(KERN_DEBUG, target->scsi_host,
-+			     PFX "Sending CM REQ failed\n");
- 		comp = 1;
- 		target->status = -ECONNRESET;
- 		break;
-@@ -1184,7 +1207,8 @@ static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event)
- 			target->scsi_host->can_queue = min(target->req_lim,
- 							   target->scsi_host->can_queue);
- 		} else {
--			printk(KERN_WARNING PFX "Unhandled RSP opcode %#x\n", opcode);
-+			shost_printk(KERN_WARNING, target->scsi_host,
-+				    PFX "Unhandled RSP opcode %#x\n", opcode);
- 			target->status = -ECONNRESET;
- 			break;
- 		}
-@@ -1230,20 +1254,23 @@ static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event)
- 		break;
  
- 	case IB_CM_REJ_RECEIVED:
--		printk(KERN_DEBUG PFX "REJ received\n");
-+		shost_printk(KERN_DEBUG, target->scsi_host, PFX "REJ received\n");
- 		comp = 1;
+-static int mt312_read_ucblocks(struct dvb_frontend* fe, u32 *ubc)
++static int mt312_read_ucblocks(struct dvb_frontend *fe, u32 *ubc)
+ {
+ 	struct mt312_state *state = fe->demodulator_priv;
+ 	int ret;
+ 	u8 buf[2];
  
- 		srp_cm_rej_handler(cm_id, event, target);
- 		break;
+-	if ((ret = mt312_read(state, RS_UBC_H, &buf, sizeof(buf))) < 0)
++	ret = mt312_read(state, RS_UBC_H, &buf, sizeof(buf));
++	if (ret < 0)
+ 		return ret;
  
- 	case IB_CM_DREQ_RECEIVED:
--		printk(KERN_WARNING PFX "DREQ received - connection closed\n");
-+		shost_printk(KERN_WARNING, target->scsi_host,
-+			     PFX "DREQ received - connection closed\n");
- 		if (ib_send_cm_drep(cm_id, NULL, 0))
--			printk(KERN_ERR PFX "Sending CM DREP failed\n");
-+			shost_printk(KERN_ERR, target->scsi_host,
-+				     PFX "Sending CM DREP failed\n");
- 		break;
+ 	*ubc = (buf[0] << 8) | buf[1];
+@@ -455,7 +487,7 @@ static int mt312_read_ucblocks(struct dvb_frontend* fe, u32 *ubc)
+ 	return 0;
+ }
  
- 	case IB_CM_TIMEWAIT_EXIT:
--		printk(KERN_ERR PFX "connection closed\n");
-+		shost_printk(KERN_ERR, target->scsi_host,
-+			     PFX "connection closed\n");
+-static int mt312_set_frontend(struct dvb_frontend* fe,
++static int mt312_set_frontend(struct dvb_frontend *fe,
+ 			      struct dvb_frontend_parameters *p)
+ {
+ 	struct mt312_state *state = fe->demodulator_priv;
+@@ -491,24 +523,28 @@ static int mt312_set_frontend(struct dvb_frontend* fe,
  
- 		comp = 1;
- 		target->status = 0;
-@@ -1255,7 +1282,8 @@ static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event)
- 		break;
+ 	switch (state->id) {
+ 	case ID_VP310:
+-	// For now we will do this only for the VP310.
+-	// It should be better for the mt312 as well, but tunning will be slower. ACCJr 09/29/03
++	/* For now we will do this only for the VP310.
++	 * It should be better for the mt312 as well,
++	 * but tuning will be slower. ACCJr 09/29/03
++	 */
+ 		ret = mt312_readreg(state, CONFIG, &config_val);
+ 		if (ret < 0)
+ 			return ret;
+-		if (p->u.qpsk.symbol_rate >= 30000000) //Note that 30MS/s should use 90MHz
+-		{
+-			if ((config_val & 0x0c) == 0x08) { //We are running 60MHz
++		if (p->u.qpsk.symbol_rate >= 30000000) {
++			/* Note that 30MS/s should use 90MHz */
++			if ((config_val & 0x0c) == 0x08) {
++				/* We are running 60MHz */
+ 				state->frequency = 90;
+-				if ((ret = mt312_initfe(fe)) < 0)
++				ret = mt312_initfe(fe);
++				if (ret < 0)
+ 					return ret;
+ 			}
+-		}
+-		else
+-		{
+-			if ((config_val & 0x0c) == 0x0C) { //We are running 90MHz
++		} else {
++			if ((config_val & 0x0c) == 0x0C) {
++				/* We are running 90MHz */
+ 				state->frequency = 60;
+-				if ((ret = mt312_initfe(fe)) < 0)
++				ret = mt312_initfe(fe);
++				if (ret < 0)
+ 					return ret;
+ 			}
+ 		}
+@@ -523,7 +559,8 @@ static int mt312_set_frontend(struct dvb_frontend* fe,
  
- 	default:
--		printk(KERN_WARNING PFX "Unhandled CM event %d\n", event->event);
-+		shost_printk(KERN_WARNING, target->scsi_host,
-+			     PFX "Unhandled CM event %d\n", event->event);
- 		break;
+ 	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.i2c_gate_ctrl)
++			fe->ops.i2c_gate_ctrl(fe, 0);
  	}
  
-@@ -1283,7 +1311,7 @@ static int srp_send_tsk_mgmt(struct srp_target_port *target,
- 
- 	init_completion(&req->done);
- 
--	iu = __srp_get_tx_iu(target);
-+	iu = __srp_get_tx_iu(target, SRP_REQ_TASK_MGMT);
- 	if (!iu)
- 		goto out;
- 
-@@ -1332,7 +1360,7 @@ static int srp_abort(struct scsi_cmnd *scmnd)
- 	struct srp_request *req;
- 	int ret = SUCCESS;
- 
--	printk(KERN_ERR "SRP abort called\n");
-+	shost_printk(KERN_ERR, target->scsi_host, "SRP abort called\n");
+ 	/* sr = (u16)(sr * 256.0 / 1000000.0) */
+@@ -545,7 +582,8 @@ static int mt312_set_frontend(struct dvb_frontend* fe,
+ 	/* GO */
+ 	buf[4] = 0x01;
  
- 	if (target->qp_in_error)
- 		return FAILED;
-@@ -1362,7 +1390,7 @@ static int srp_reset_device(struct scsi_cmnd *scmnd)
- 	struct srp_target_port *target = host_to_target(scmnd->device->host);
- 	struct srp_request *req, *tmp;
+-	if ((ret = mt312_write(state, SYM_RATE_H, buf, sizeof(buf))) < 0)
++	ret = mt312_write(state, SYM_RATE_H, buf, sizeof(buf));
++	if (ret < 0)
+ 		return ret;
  
--	printk(KERN_ERR "SRP reset_device called\n");
-+	shost_printk(KERN_ERR, target->scsi_host, "SRP reset_device called\n");
+ 	mt312_reset(state, 0);
+@@ -553,27 +591,30 @@ static int mt312_set_frontend(struct dvb_frontend* fe,
+ 	return 0;
+ }
  
- 	if (target->qp_in_error)
- 		return FAILED;
-@@ -1389,7 +1417,7 @@ static int srp_reset_host(struct scsi_cmnd *scmnd)
- 	struct srp_target_port *target = host_to_target(scmnd->device->host);
- 	int ret = FAILED;
+-static int mt312_get_frontend(struct dvb_frontend* fe,
++static int mt312_get_frontend(struct dvb_frontend *fe,
+ 			      struct dvb_frontend_parameters *p)
+ {
+ 	struct mt312_state *state = fe->demodulator_priv;
+ 	int ret;
  
--	printk(KERN_ERR PFX "SRP reset_host called\n");
-+	shost_printk(KERN_ERR, target->scsi_host, PFX "SRP reset_host called\n");
+-	if ((ret = mt312_get_inversion(state, &p->inversion)) < 0)
++	ret = mt312_get_inversion(state, &p->inversion);
++	if (ret < 0)
+ 		return ret;
  
- 	if (!srp_reconnect_target(target))
- 		ret = SUCCESS;
-@@ -1543,6 +1571,7 @@ static struct scsi_host_template srp_template = {
- 	.this_id			= -1,
- 	.cmd_per_lun			= SRP_SQ_SIZE,
- 	.use_clustering			= ENABLE_CLUSTERING,
-+	.use_sg_chaining		= ENABLE_SG_CHAINING,
- 	.shost_attrs			= srp_host_attrs
- };
+-	if ((ret = mt312_get_symbol_rate(state, &p->u.qpsk.symbol_rate)) < 0)
++	ret = mt312_get_symbol_rate(state, &p->u.qpsk.symbol_rate);
++	if (ret < 0)
+ 		return ret;
  
-@@ -1814,8 +1843,9 @@ static ssize_t srp_create_target(struct class_device *class_dev,
+-	if ((ret = mt312_get_code_rate(state, &p->u.qpsk.fec_inner)) < 0)
++	ret = mt312_get_code_rate(state, &p->u.qpsk.fec_inner);
++	if (ret < 0)
+ 		return ret;
  
- 	ib_get_cached_gid(host->dev->dev, host->port, 0, &target->path.sgid);
+ 	return 0;
+ }
  
--	printk(KERN_DEBUG PFX "new target: id_ext %016llx ioc_guid %016llx pkey %04x "
--	       "service_id %016llx dgid %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
-+	shost_printk(KERN_DEBUG, target->scsi_host, PFX
-+		     "new target: id_ext %016llx ioc_guid %016llx pkey %04x "
-+		     "service_id %016llx dgid %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
- 	       (unsigned long long) be64_to_cpu(target->id_ext),
- 	       (unsigned long long) be64_to_cpu(target->ioc_guid),
- 	       be16_to_cpu(target->path.pkey),
-@@ -1842,7 +1872,8 @@ static ssize_t srp_create_target(struct class_device *class_dev,
- 	target->qp_in_error = 0;
- 	ret = srp_connect_target(target);
- 	if (ret) {
--		printk(KERN_ERR PFX "Connection failed\n");
-+		shost_printk(KERN_ERR, target->scsi_host,
-+			     PFX "Connection failed\n");
- 		goto err_cm_id;
+-static int mt312_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
++static int mt312_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
+ {
+-	struct mt312_state* state = fe->demodulator_priv;
++	struct mt312_state *state = fe->demodulator_priv;
+ 
+ 	if (enable) {
+ 		return mt312_writereg(state, GPP_CTRL, 0x40);
+@@ -582,27 +623,31 @@ static int mt312_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
  	}
+ }
  
-diff --git a/drivers/infiniband/ulp/srp/ib_srp.h b/drivers/infiniband/ulp/srp/ib_srp.h
-index e3573e7..4a3c1f3 100644
---- a/drivers/infiniband/ulp/srp/ib_srp.h
-+++ b/drivers/infiniband/ulp/srp/ib_srp.h
-@@ -79,6 +79,11 @@ enum srp_target_state {
- 	SRP_TARGET_REMOVED
- };
+-static int mt312_sleep(struct dvb_frontend* fe)
++static int mt312_sleep(struct dvb_frontend *fe)
+ {
+ 	struct mt312_state *state = fe->demodulator_priv;
+ 	int ret;
+ 	u8 config;
  
-+enum srp_request_type {
-+	SRP_REQ_NORMAL,
-+	SRP_REQ_TASK_MGMT,
-+};
-+
- struct srp_device {
- 	struct list_head	dev_list;
- 	struct ib_device       *dev;
-diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c
-index f449dae..23ae66c 100644
---- a/drivers/isdn/capi/capi.c
-+++ b/drivers/isdn/capi/capi.c
-@@ -1544,11 +1544,11 @@ static int __init capi_init(void)
- 		return PTR_ERR(capi_class);
- 	}
+ 	/* reset all registers to defaults */
+-	if ((ret = mt312_reset(state, 1)) < 0)
++	ret = mt312_reset(state, 1);
++	if (ret < 0)
+ 		return ret;
  
--	class_device_create(capi_class, NULL, MKDEV(capi_major, 0), NULL, "capi");
-+	device_create(capi_class, NULL, MKDEV(capi_major, 0), "capi");
+-	if ((ret = mt312_readreg(state, CONFIG, &config)) < 0)
++	ret = mt312_readreg(state, CONFIG, &config);
++	if (ret < 0)
+ 		return ret;
  
- #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
- 	if (capinc_tty_init() < 0) {
--		class_device_destroy(capi_class, MKDEV(capi_major, 0));
-+		device_destroy(capi_class, MKDEV(capi_major, 0));
- 		class_destroy(capi_class);
- 		unregister_chrdev(capi_major, "capi20");
- 		return -ENOMEM;
-@@ -1576,7 +1576,7 @@ static void __exit capi_exit(void)
+ 	/* enter standby */
+-	if ((ret = mt312_writereg(state, CONFIG, config & 0x7f)) < 0)
++	ret = mt312_writereg(state, CONFIG, config & 0x7f);
++	if (ret < 0)
+ 		return ret;
+ 
+ 	return 0;
+ }
+ 
+-static int mt312_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
++static int mt312_get_tune_settings(struct dvb_frontend *fe,
++		struct dvb_frontend_tune_settings *fesettings)
  {
- 	proc_exit();
+ 	fesettings->min_delay_ms = 50;
+ 	fesettings->step_size = 0;
+@@ -610,9 +655,9 @@ static int mt312_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_
+ 	return 0;
+ }
  
--	class_device_destroy(capi_class, MKDEV(capi_major, 0));
-+	device_destroy(capi_class, MKDEV(capi_major, 0));
- 	class_destroy(capi_class);
- 	unregister_chrdev(capi_major, "capi20");
+-static void mt312_release(struct dvb_frontend* fe)
++static void mt312_release(struct dvb_frontend *fe)
+ {
+-	struct mt312_state* state = fe->demodulator_priv;
++	struct mt312_state *state = fe->demodulator_priv;
+ 	kfree(state);
+ }
  
-diff --git a/drivers/isdn/capi/capidrv.c b/drivers/isdn/capi/capidrv.c
-index 48c1775..cb42b69 100644
---- a/drivers/isdn/capi/capidrv.c
-+++ b/drivers/isdn/capi/capidrv.c
-@@ -2332,13 +2332,14 @@ static int __init capidrv_init(void)
+@@ -655,10 +700,10 @@ static struct dvb_frontend_ops vp310_mt312_ops = {
+ 	.set_voltage = mt312_set_voltage,
+ };
  
- static void __exit capidrv_exit(void)
+-struct dvb_frontend* vp310_mt312_attach(const struct mt312_config* config,
+-					struct i2c_adapter* i2c)
++struct dvb_frontend *vp310_mt312_attach(const struct mt312_config *config,
++					struct i2c_adapter *i2c)
  {
--	char rev[10];
-+	char rev[32];
- 	char *p;
+-	struct mt312_state* state = NULL;
++	struct mt312_state *state = NULL;
  
- 	if ((p = strchr(revision, ':')) != 0) {
--		strcpy(rev, p + 1);
--		p = strchr(rev, '$');
--		*p = 0;
-+		strncpy(rev, p + 1, sizeof(rev));
-+		rev[sizeof(rev)-1] = 0;
-+		if ((p = strchr(rev, '$')) != 0)
-+			*p = 0;
- 	} else {
- 		strcpy(rev, " ??? ");
+ 	/* allocate memory for the internal state */
+ 	state = kmalloc(sizeof(struct mt312_state), GFP_KERNEL);
+@@ -674,7 +719,8 @@ struct dvb_frontend* vp310_mt312_attach(const struct mt312_config* config,
+ 		goto error;
+ 
+ 	/* create dvb_frontend */
+-	memcpy(&state->frontend.ops, &vp310_mt312_ops, sizeof(struct dvb_frontend_ops));
++	memcpy(&state->frontend.ops, &vp310_mt312_ops,
++		sizeof(struct dvb_frontend_ops));
+ 	state->frontend.demodulator_priv = state;
+ 
+ 	switch (state->id) {
+@@ -687,7 +733,8 @@ struct dvb_frontend* vp310_mt312_attach(const struct mt312_config* config,
+ 		state->frequency = 60;
+ 		break;
+ 	default:
+-		printk (KERN_WARNING "Only Zarlink VP310/MT312 are supported chips.\n");
++		printk(KERN_WARNING "Only Zarlink VP310/MT312"
++			" are supported chips.\n");
+ 		goto error;
  	}
-diff --git a/drivers/isdn/gigaset/gigaset.h b/drivers/isdn/gigaset/gigaset.h
-index a0317ab..02bdaf2 100644
---- a/drivers/isdn/gigaset/gigaset.h
-+++ b/drivers/isdn/gigaset/gigaset.h
-@@ -106,12 +106,6 @@ enum debuglevel {
- 					 activated */
- };
  
--/* missing from linux/device.h ... */
--#ifndef dev_notice
--#define dev_notice(dev, format, arg...)		\
--	dev_printk(KERN_NOTICE , dev , format , ## arg)
--#endif
--
- /* Kernel message macros for situations where dev_printk and friends cannot be
-  * used for lack of reliable access to a device structure.
-  * linux/usb.h already contains these but in an obsolete form which clutters
-diff --git a/drivers/kvm/kvm_main.c b/drivers/kvm/kvm_main.c
-index 47c10b8..c0f372f 100644
---- a/drivers/kvm/kvm_main.c
-+++ b/drivers/kvm/kvm_main.c
-@@ -3451,7 +3451,7 @@ static int kvm_resume(struct sys_device *dev)
+@@ -697,6 +744,7 @@ error:
+ 	kfree(state);
+ 	return NULL;
  }
++EXPORT_SYMBOL(vp310_mt312_attach);
  
- static struct sysdev_class kvm_sysdev_class = {
--	set_kset_name("kvm"),
-+	.name = "kvm",
- 	.suspend = kvm_suspend,
- 	.resume = kvm_resume,
- };
-diff --git a/drivers/lguest/x86/core.c b/drivers/lguest/x86/core.c
-index 482aec2..96d0fd0 100644
---- a/drivers/lguest/x86/core.c
-+++ b/drivers/lguest/x86/core.c
-@@ -459,7 +459,7 @@ void __init lguest_arch_host_init(void)
+ module_param(debug, int, 0644);
+ MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+@@ -705,4 +753,3 @@ MODULE_DESCRIPTION("Zarlink VP310/MT312 DVB-S Demodulator driver");
+ MODULE_AUTHOR("Andreas Oberritter <obi at linuxtv.org>");
+ MODULE_LICENSE("GPL");
  
- 	/* We don't need the complexity of CPUs coming and going while we're
- 	 * doing this. */
--	lock_cpu_hotplug();
-+	get_online_cpus();
- 	if (cpu_has_pge) { /* We have a broader idea of "global". */
- 		/* Remember that this was originally set (for cleanup). */
- 		cpu_had_pge = 1;
-@@ -469,20 +469,20 @@ void __init lguest_arch_host_init(void)
- 		/* Turn off the feature in the global feature set. */
- 		clear_bit(X86_FEATURE_PGE, boot_cpu_data.x86_capability);
- 	}
--	unlock_cpu_hotplug();
-+	put_online_cpus();
+-EXPORT_SYMBOL(vp310_mt312_attach);
+diff --git a/drivers/media/dvb/frontends/mt312.h b/drivers/media/dvb/frontends/mt312.h
+index cf9a150..f17cb93 100644
+--- a/drivers/media/dvb/frontends/mt312.h
++++ b/drivers/media/dvb/frontends/mt312.h
+@@ -28,22 +28,21 @@
+ 
+ #include <linux/dvb/frontend.h>
+ 
+-struct mt312_config
+-{
++struct mt312_config {
+ 	/* the demodulator's i2c address */
+ 	u8 demod_address;
  };
- /*:*/
  
- void __exit lguest_arch_host_fini(void)
+ #if defined(CONFIG_DVB_MT312) || (defined(CONFIG_DVB_MT312_MODULE) && defined(MODULE))
+-struct dvb_frontend* vp310_mt312_attach(const struct mt312_config* config,
+-					struct i2c_adapter* i2c);
++struct dvb_frontend *vp310_mt312_attach(const struct mt312_config *config,
++					struct i2c_adapter *i2c);
+ #else
+-static inline struct dvb_frontend* vp310_mt312_attach(const struct mt312_config* config,
+-					struct i2c_adapter* i2c)
++static inline struct dvb_frontend *vp310_mt312_attach(
++	const struct mt312_config *config, struct i2c_adapter *i2c)
  {
- 	/* If we had PGE before we started, turn it back on now. */
--	lock_cpu_hotplug();
-+	get_online_cpus();
- 	if (cpu_had_pge) {
- 		set_bit(X86_FEATURE_PGE, boot_cpu_data.x86_capability);
- 		/* adjust_pge's argument "1" means set PGE. */
- 		on_each_cpu(adjust_pge, (void *)1, 0, 1);
- 	}
--	unlock_cpu_hotplug();
-+	put_online_cpus();
+ 	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+ 	return NULL;
  }
+-#endif // CONFIG_DVB_MT312
++#endif /* CONFIG_DVB_MT312 */
  
+-#endif // MT312_H
++#endif /* MT312_H */
+diff --git a/drivers/media/dvb/frontends/mt352.c b/drivers/media/dvb/frontends/mt352.c
+index 5dd9b73..7cd190b 100644
+--- a/drivers/media/dvb/frontends/mt352.c
++++ b/drivers/media/dvb/frontends/mt352.c
+@@ -152,7 +152,13 @@ static void mt352_calc_input_freq(struct mt352_state* state,
+ 	if (state->config.if2)
+ 		if2 = state->config.if2;
  
-diff --git a/drivers/macintosh/adb.c b/drivers/macintosh/adb.c
-index 5c742a5..b7adde4 100644
---- a/drivers/macintosh/adb.c
-+++ b/drivers/macintosh/adb.c
-@@ -875,5 +875,5 @@ adbdev_init(void)
- 	adb_dev_class = class_create(THIS_MODULE, "adb");
- 	if (IS_ERR(adb_dev_class))
- 		return;
--	class_device_create(adb_dev_class, NULL, MKDEV(ADB_MAJOR, 0), NULL, "adb");
-+	device_create(adb_dev_class, NULL, MKDEV(ADB_MAJOR, 0), "adb");
+-	ife = (2*adc_clock - if2);
++	if (adc_clock >= if2 * 2)
++		ife = if2;
++	else {
++		ife = adc_clock - (if2 % adc_clock);
++		if (ife > adc_clock / 2)
++			ife = adc_clock - ife;
++	}
+ 	value = -16374 * ife / adc_clock;
+ 	dprintk("%s: if2 %d, ife %d, adc_clock %d => %d / 0x%x\n",
+ 		__FUNCTION__, if2, ife, adc_clock, value, value & 0x3fff);
+diff --git a/drivers/media/dvb/frontends/or51132.c b/drivers/media/dvb/frontends/or51132.c
+index b314a1f..1d2d28c 100644
+--- a/drivers/media/dvb/frontends/or51132.c
++++ b/drivers/media/dvb/frontends/or51132.c
+@@ -564,7 +564,7 @@ struct dvb_frontend* or51132_attach(const struct or51132_config* config,
+ 	/* Allocate memory for the internal state */
+ 	state = kmalloc(sizeof(struct or51132_state), GFP_KERNEL);
+ 	if (state == NULL)
+-		goto error;
++		return NULL;
+ 
+ 	/* Setup the state */
+ 	state->config = config;
+@@ -576,10 +576,6 @@ struct dvb_frontend* or51132_attach(const struct or51132_config* config,
+ 	memcpy(&state->frontend.ops, &or51132_ops, sizeof(struct dvb_frontend_ops));
+ 	state->frontend.demodulator_priv = state;
+ 	return &state->frontend;
+-
+-error:
+-	kfree(state);
+-	return NULL;
  }
-diff --git a/drivers/macintosh/mediabay.c b/drivers/macintosh/mediabay.c
-index 48d647a..eaba4a9 100644
---- a/drivers/macintosh/mediabay.c
-+++ b/drivers/macintosh/mediabay.c
-@@ -563,7 +563,8 @@ static void media_bay_step(int i)
- 				ide_init_hwif_ports(&hw, (unsigned long) bay->cd_base, (unsigned long) 0, NULL);
- 				hw.irq = bay->cd_irq;
- 				hw.chipset = ide_pmac;
--				bay->cd_index = ide_register_hw(&hw, NULL, 0, NULL);
-+				bay->cd_index =
-+					ide_register_hw(&hw, NULL, NULL);
- 				pmu_resume();
- 			}
- 			if (bay->cd_index == -1) {
-diff --git a/drivers/macintosh/therm_windtunnel.c b/drivers/macintosh/therm_windtunnel.c
-index 5452da1..b66da74 100644
---- a/drivers/macintosh/therm_windtunnel.c
-+++ b/drivers/macintosh/therm_windtunnel.c
-@@ -47,12 +47,10 @@
  
- #define LOG_TEMP		0			/* continously log temperature */
+ static struct dvb_frontend_ops or51132_ops = {
+diff --git a/drivers/media/dvb/frontends/or51211.c b/drivers/media/dvb/frontends/or51211.c
+index f02bd94..6a6b0d7 100644
+--- a/drivers/media/dvb/frontends/or51211.c
++++ b/drivers/media/dvb/frontends/or51211.c
+@@ -529,7 +529,7 @@ struct dvb_frontend* or51211_attach(const struct or51211_config* config,
+ 	/* Allocate memory for the internal state */
+ 	state = kmalloc(sizeof(struct or51211_state), GFP_KERNEL);
+ 	if (state == NULL)
+-		goto error;
++		return NULL;
  
--#define I2C_DRIVERID_G4FAN	0x9001			/* fixme */
+ 	/* Setup the state */
+ 	state->config = config;
+@@ -541,10 +541,6 @@ struct dvb_frontend* or51211_attach(const struct or51211_config* config,
+ 	memcpy(&state->frontend.ops, &or51211_ops, sizeof(struct dvb_frontend_ops));
+ 	state->frontend.demodulator_priv = state;
+ 	return &state->frontend;
 -
- static int 			do_probe( struct i2c_adapter *adapter, int addr, int kind);
+-error:
+-	kfree(state);
+-	return NULL;
+ }
  
- /* scan 0x48-0x4f (DS1775) and 0x2c-2x2f (ADM1030) */
--static unsigned short		normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b,
-+static const unsigned short	normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b,
- 						 0x4c, 0x4d, 0x4e, 0x4f,
- 						 0x2c, 0x2d, 0x2e, 0x2f,
- 						 I2C_CLIENT_END };
-@@ -357,7 +355,6 @@ static struct i2c_driver g4fan_driver = {
- 	.driver = {
- 		.name	= "therm_windtunnel",
- 	},
--	.id		= I2C_DRIVERID_G4FAN,
- 	.attach_adapter = do_attach,
- 	.detach_client	= do_detach,
- };
-diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c
-index 6123c70..ac420b1 100644
---- a/drivers/macintosh/via-pmu.c
-+++ b/drivers/macintosh/via-pmu.c
-@@ -2796,7 +2796,7 @@ static int pmu_sys_resume(struct sys_device *sysdev)
- #endif /* CONFIG_PM_SLEEP && CONFIG_PPC32 */
+ static struct dvb_frontend_ops or51211_ops = {
+diff --git a/drivers/media/dvb/frontends/s5h1409.c b/drivers/media/dvb/frontends/s5h1409.c
+index 562d920..8194334 100644
+--- a/drivers/media/dvb/frontends/s5h1409.c
++++ b/drivers/media/dvb/frontends/s5h1409.c
+@@ -42,6 +42,7 @@ struct s5h1409_state {
+ 	fe_modulation_t current_modulation;
  
- static struct sysdev_class pmu_sysclass = {
--	set_kset_name("pmu"),
-+	.name = "pmu",
+ 	u32 current_frequency;
++	int if_freq;
+ 
+ 	u32 is_qam_locked;
+ 	u32 qam_state;
+@@ -97,7 +98,7 @@ static struct init_tab {
+ 	{ 0xac, 0x1003, },
+ 	{ 0xad, 0x103f, },
+ 	{ 0xe2, 0x0100, },
+-	{ 0xe3, 0x0000, },
++	{ 0xe3, 0x1000, },
+ 	{ 0x28, 0x1010, },
+ 	{ 0xb1, 0x000e, },
  };
+@@ -348,28 +349,32 @@ static int s5h1409_softreset(struct dvb_frontend* fe)
+ 	return 0;
+ }
  
- static struct sys_device device_pmu = {
-diff --git a/drivers/md/dm.c b/drivers/md/dm.c
-index 88c0fd6..f2d24eb 100644
---- a/drivers/md/dm.c
-+++ b/drivers/md/dm.c
-@@ -1109,7 +1109,7 @@ static void event_callback(void *context)
- 	list_splice_init(&md->uevent_list, &uevents);
- 	spin_unlock_irqrestore(&md->uevent_lock, flags);
++#define S5H1409_VSB_IF_FREQ 5380
++#define S5H1409_QAM_IF_FREQ state->config->qam_if
++
+ static int s5h1409_set_if_freq(struct dvb_frontend* fe, int KHz)
+ {
+ 	struct s5h1409_state* state = fe->demodulator_priv;
+-	int ret = 0;
  
--	dm_send_uevents(&uevents, &md->disk->kobj);
-+	dm_send_uevents(&uevents, &md->disk->dev.kobj);
+ 	dprintk("%s(%d KHz)\n", __FUNCTION__, KHz);
  
- 	atomic_inc(&md->event_nr);
- 	wake_up(&md->eventq);
-@@ -1530,7 +1530,7 @@ out:
-  *---------------------------------------------------------------*/
- void dm_kobject_uevent(struct mapped_device *md)
- {
--	kobject_uevent(&md->disk->kobj, KOBJ_CHANGE);
-+	kobject_uevent(&md->disk->dev.kobj, KOBJ_CHANGE);
+-	if( (KHz == 44000) || (KHz == 5380) ) {
+-		s5h1409_writereg(state, 0x87, 0x01be);
+-		s5h1409_writereg(state, 0x88, 0x0436);
+-		s5h1409_writereg(state, 0x89, 0x054d);
+-	} else
+-	if (KHz == 4000) {
++	switch (KHz) {
++	case 4000:
+ 		s5h1409_writereg(state, 0x87, 0x014b);
+ 		s5h1409_writereg(state, 0x88, 0x0cb5);
+ 		s5h1409_writereg(state, 0x89, 0x03e2);
+-	} else {
+-		printk("%s() Invalid arg = %d KHz\n", __FUNCTION__, KHz);
+-		ret = -1;
++		break;
++	case 5380:
++	case 44000:
++	default:
++		s5h1409_writereg(state, 0x87, 0x01be);
++		s5h1409_writereg(state, 0x88, 0x0436);
++		s5h1409_writereg(state, 0x89, 0x054d);
++		break;
+ 	}
++	state->if_freq = KHz;
+ 
+-	return ret;
++	return 0;
  }
  
- uint32_t dm_next_uevent_seq(struct mapped_device *md)
-diff --git a/drivers/md/md.c b/drivers/md/md.c
-index cef9ebd..c28a120 100644
---- a/drivers/md/md.c
-+++ b/drivers/md/md.c
-@@ -231,7 +231,7 @@ static void mddev_put(mddev_t *mddev)
- 		list_del(&mddev->all_mddevs);
- 		spin_unlock(&all_mddevs_lock);
- 		blk_cleanup_queue(mddev->queue);
--		kobject_unregister(&mddev->kobj);
-+		kobject_put(&mddev->kobj);
- 	} else
- 		spin_unlock(&all_mddevs_lock);
+ static int s5h1409_set_spectralinversion(struct dvb_frontend* fe, int inverted)
+@@ -394,11 +399,15 @@ static int s5h1409_enable_modulation(struct dvb_frontend* fe,
+ 	switch(m) {
+ 	case VSB_8:
+ 		dprintk("%s() VSB_8\n", __FUNCTION__);
++		if (state->if_freq != S5H1409_VSB_IF_FREQ)
++			s5h1409_set_if_freq(fe, S5H1409_VSB_IF_FREQ);
+ 		s5h1409_writereg(state, 0xf4, 0);
+ 		break;
+ 	case QAM_64:
+ 	case QAM_256:
+ 		dprintk("%s() QAM_AUTO (64/256)\n", __FUNCTION__);
++		if (state->if_freq != S5H1409_QAM_IF_FREQ)
++			s5h1409_set_if_freq(fe, S5H1409_QAM_IF_FREQ);
+ 		s5h1409_writereg(state, 0xf4, 1);
+ 		s5h1409_writereg(state, 0x85, 0x110);
+ 		break;
+@@ -432,9 +441,11 @@ static int s5h1409_set_gpio(struct dvb_frontend* fe, int enable)
+ 	dprintk("%s(%d)\n", __FUNCTION__, enable);
+ 
+ 	if (enable)
+-		return s5h1409_writereg(state, 0xe3, 0x1100);
++		return s5h1409_writereg(state, 0xe3,
++			s5h1409_readreg(state, 0xe3) | 0x1100);
+ 	else
+-		return s5h1409_writereg(state, 0xe3, 0x1000);
++		return s5h1409_writereg(state, 0xe3,
++			s5h1409_readreg(state, 0xe3) & 0xeeff);
  }
-@@ -1383,22 +1383,19 @@ static int bind_rdev_to_array(mdk_rdev_t * rdev, mddev_t * mddev)
- 			return -EBUSY;
+ 
+ static int s5h1409_sleep(struct dvb_frontend* fe, int enable)
+@@ -504,13 +515,15 @@ static void s5h1409_set_qam_interleave_mode(struct dvb_frontend *fe)
+ 			s5h1409_writereg(state, 0x96, 0x20);
+ 			s5h1409_writereg(state, 0xad,
+ 				( ((reg1 & 0xf000) >> 4) | (reg2 & 0xf0ff)) );
+-			s5h1409_writereg(state, 0xab, 0x1100);
++			s5h1409_writereg(state, 0xab,
++				s5h1409_readreg(state, 0xab) & 0xeffe);
+ 		}
+ 	} else {
+ 		if (state->qam_state != 1) {
+ 			state->qam_state = 1;
+ 			s5h1409_writereg(state, 0x96, 0x08);
+-			s5h1409_writereg(state, 0xab, 0x1101);
++			s5h1409_writereg(state, 0xab,
++				s5h1409_readreg(state, 0xab) | 0x1001);
+ 		}
  	}
- 	bdevname(rdev->bdev,b);
--	if (kobject_set_name(&rdev->kobj, "dev-%s", b) < 0)
--		return -ENOMEM;
--	while ( (s=strchr(rdev->kobj.k_name, '/')) != NULL)
-+	while ( (s=strchr(b, '/')) != NULL)
- 		*s = '!';
--			
-+
- 	rdev->mddev = mddev;
- 	printk(KERN_INFO "md: bind<%s>\n", b);
+ }
+@@ -547,6 +560,36 @@ static int s5h1409_set_frontend (struct dvb_frontend* fe,
+ 	return 0;
+ }
  
--	rdev->kobj.parent = &mddev->kobj;
--	if ((err = kobject_add(&rdev->kobj)))
-+	if ((err = kobject_add(&rdev->kobj, &mddev->kobj, "dev-%s", b)))
- 		goto fail;
++static int s5h1409_set_mpeg_timing(struct dvb_frontend *fe, int mode)
++{
++	struct s5h1409_state *state = fe->demodulator_priv;
++	u16 val;
++
++	dprintk("%s(%d)\n", __FUNCTION__, mode);
++
++	val = s5h1409_readreg(state, 0xac) & 0xcfff;
++	switch (mode) {
++	case S5H1409_MPEGTIMING_CONTINOUS_INVERTING_CLOCK:
++		val |= 0x0000;
++		break;
++	case S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK:
++		dprintk("%s(%d) Mode1 or Defaulting\n", __FUNCTION__, mode);
++		val |= 0x1000;
++		break;
++	case S5H1409_MPEGTIMING_NONCONTINOUS_INVERTING_CLOCK:
++		val |= 0x2000;
++		break;
++	case S5H1409_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK:
++		val |= 0x3000;
++		break;
++	default:
++		return -EINVAL;
++	}
++
++	/* Configure MPEG Signal Timing charactistics */
++	return s5h1409_writereg(state, 0xac, val);
++}
++
+ /* Reset the demod hardware and reset all of the configuration registers
+    to a default state. */
+ static int s5h1409_init (struct dvb_frontend* fe)
+@@ -566,13 +609,16 @@ static int s5h1409_init (struct dvb_frontend* fe)
+ 	state->current_modulation = VSB_8;
  
- 	if (rdev->bdev->bd_part)
--		ko = &rdev->bdev->bd_part->kobj;
-+		ko = &rdev->bdev->bd_part->dev.kobj;
+ 	if (state->config->output_mode == S5H1409_SERIAL_OUTPUT)
+-		s5h1409_writereg(state, 0xab, 0x100); /* Serial */
++		s5h1409_writereg(state, 0xab,
++			s5h1409_readreg(state, 0xab) | 0x100); /* Serial */
  	else
--		ko = &rdev->bdev->bd_disk->kobj;
-+		ko = &rdev->bdev->bd_disk->dev.kobj;
- 	if ((err = sysfs_create_link(&rdev->kobj, ko, "block"))) {
- 		kobject_del(&rdev->kobj);
- 		goto fail;
-@@ -2036,9 +2033,7 @@ static mdk_rdev_t *md_import_device(dev_t newdev, int super_format, int super_mi
- 	if (err)
- 		goto abort_free;
+-		s5h1409_writereg(state, 0xab, 0x0); /* Parallel */
++		s5h1409_writereg(state, 0xab,
++			s5h1409_readreg(state, 0xab) & 0xfeff); /* Parallel */
  
--	rdev->kobj.parent = NULL;
--	rdev->kobj.ktype = &rdev_ktype;
--	kobject_init(&rdev->kobj);
-+	kobject_init(&rdev->kobj, &rdev_ktype);
+ 	s5h1409_set_spectralinversion(fe, state->config->inversion);
+-	s5h1409_set_if_freq(fe, state->config->if_freq);
++	s5h1409_set_if_freq(fe, state->if_freq);
+ 	s5h1409_set_gpio(fe, state->config->gpio);
++	s5h1409_set_mpeg_timing(fe, state->config->mpeg_timing);
+ 	s5h1409_softreset(fe);
  
- 	rdev->desc_nr = -1;
- 	rdev->saved_raid_disk = -1;
-@@ -3054,6 +3049,7 @@ static struct kobject *md_probe(dev_t dev, int *part, void *data)
- 	int partitioned = (MAJOR(dev) != MD_MAJOR);
- 	int shift = partitioned ? MdpMinorShift : 0;
- 	int unit = MINOR(dev) >> shift;
-+	int error;
+ 	/* Note: Leaving the I2C gate closed. */
+@@ -741,6 +787,7 @@ struct dvb_frontend* s5h1409_attach(const struct s5h1409_config* config,
+ 				    struct i2c_adapter* i2c)
+ {
+ 	struct s5h1409_state* state = NULL;
++	u16 reg;
  
- 	if (!mddev)
- 		return NULL;
-@@ -3082,12 +3078,13 @@ static struct kobject *md_probe(dev_t dev, int *part, void *data)
- 	add_disk(disk);
- 	mddev->gendisk = disk;
- 	mutex_unlock(&disks_mutex);
--	mddev->kobj.parent = &disk->kobj;
--	kobject_set_name(&mddev->kobj, "%s", "md");
--	mddev->kobj.ktype = &md_ktype;
--	if (kobject_register(&mddev->kobj))
-+	error = kobject_init_and_add(&mddev->kobj, &md_ktype, &disk->dev.kobj,
-+				     "%s", "md");
-+	if (error)
- 		printk(KERN_WARNING "md: cannot register %s/md - name in use\n",
- 		       disk->disk_name);
-+	else
-+		kobject_uevent(&mddev->kobj, KOBJ_ADD);
- 	return NULL;
- }
+ 	/* allocate memory for the internal state */
+ 	state = kmalloc(sizeof(struct s5h1409_state), GFP_KERNEL);
+@@ -751,9 +798,11 @@ struct dvb_frontend* s5h1409_attach(const struct s5h1409_config* config,
+ 	state->config = config;
+ 	state->i2c = i2c;
+ 	state->current_modulation = 0;
++	state->if_freq = S5H1409_VSB_IF_FREQ;
  
-@@ -3359,7 +3356,7 @@ static int do_md_run(mddev_t * mddev)
+ 	/* check if the demod exists */
+-	if (s5h1409_readreg(state, 0x04) != 0x0066)
++	reg = s5h1409_readreg(state, 0x04);
++	if ((reg != 0x0066) && (reg != 0x007f))
+ 		goto error;
  
- 	mddev->changed = 1;
- 	md_new_event(mddev);
--	kobject_uevent(&mddev->gendisk->kobj, KOBJ_CHANGE);
-+	kobject_uevent(&mddev->gendisk->dev.kobj, KOBJ_CHANGE);
- 	return 0;
- }
+ 	/* create dvb_frontend */
+@@ -761,8 +810,14 @@ struct dvb_frontend* s5h1409_attach(const struct s5h1409_config* config,
+ 	       sizeof(struct dvb_frontend_ops));
+ 	state->frontend.demodulator_priv = state;
  
-diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig
-index 1604f04..8f4a453 100644
---- a/drivers/media/Kconfig
-+++ b/drivers/media/Kconfig
-@@ -69,11 +69,13 @@ source "drivers/media/common/Kconfig"
- config VIDEO_TUNER
- 	tristate
- 	depends on I2C
-+	select TUNER_XC2028 if !VIDEO_TUNER_CUSTOMIZE
- 	select TUNER_MT20XX if !VIDEO_TUNER_CUSTOMIZE
- 	select TUNER_TDA8290 if !VIDEO_TUNER_CUSTOMIZE
- 	select TUNER_TEA5761 if !VIDEO_TUNER_CUSTOMIZE
- 	select TUNER_TEA5767 if !VIDEO_TUNER_CUSTOMIZE
- 	select TUNER_SIMPLE if !VIDEO_TUNER_CUSTOMIZE
-+	select TUNER_TDA9887 if !VIDEO_TUNER_CUSTOMIZE
++	if (s5h1409_init(&state->frontend) != 0) {
++		printk(KERN_ERR "%s: Failed to initialize correctly\n",
++			__FUNCTION__);
++		goto error;
++	}
++
+ 	/* Note: Leaving the I2C gate open here. */
+-	s5h1409_writereg(state, 0xf3, 1);
++	s5h1409_i2c_gate_ctrl(&state->frontend, 1);
  
- menuconfig VIDEO_TUNER_CUSTOMIZE
- 	bool "Customize analog tuner modules to build"
-@@ -89,6 +91,13 @@ menuconfig VIDEO_TUNER_CUSTOMIZE
+ 	return &state->frontend;
  
- if VIDEO_TUNER_CUSTOMIZE
+diff --git a/drivers/media/dvb/frontends/s5h1409.h b/drivers/media/dvb/frontends/s5h1409.h
+index 20f9af1..f0bb13f 100644
+--- a/drivers/media/dvb/frontends/s5h1409.h
++++ b/drivers/media/dvb/frontends/s5h1409.h
+@@ -39,8 +39,8 @@ struct s5h1409_config
+ #define S5H1409_GPIO_ON  1
+ 	u8 gpio;
  
-+config TUNER_XC2028
-+	tristate "XCeive xc2028/xc3028 tuners"
-+	depends on I2C
-+	default m if VIDEO_TUNER_CUSTOMIZE
-+	help
-+	  Say Y here to include support for the xc2028/xc3028 tuners.
+-	/* IF Freq in KHz */
+-	u16 if_freq;
++	/* IF Freq for QAM in KHz, VSB is hardcoded to 5380 */
++	u16 qam_if;
+ 
+ 	/* Spectral Inversion */
+ #define S5H1409_INVERSION_OFF 0
+@@ -51,6 +51,13 @@ struct s5h1409_config
+ #define S5H1409_TUNERLOCKING 0
+ #define S5H1409_DEMODLOCKING 1
+ 	u8 status_mode;
++
++	/* MPEG signal timing */
++#define S5H1409_MPEGTIMING_CONTINOUS_INVERTING_CLOCK       0
++#define S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK    1
++#define S5H1409_MPEGTIMING_NONCONTINOUS_INVERTING_CLOCK    2
++#define S5H1409_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK 3
++	u16 mpeg_timing;
+ };
+ 
+ #if defined(CONFIG_DVB_S5H1409) || (defined(CONFIG_DVB_S5H1409_MODULE) && defined(MODULE))
+diff --git a/drivers/media/dvb/frontends/tda18271-common.c b/drivers/media/dvb/frontends/tda18271-common.c
+new file mode 100644
+index 0000000..cebb6b9
+--- /dev/null
++++ b/drivers/media/dvb/frontends/tda18271-common.c
+@@ -0,0 +1,653 @@
++/*
++    tda18271-common.c - driver for the Philips / NXP TDA18271 silicon tuner
++
++    Copyright (C) 2007, 2008 Michael Krufky <mkrufky at 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.
++*/
++
++#include "tda18271-priv.h"
++
++static int tda18271_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
++{
++	struct tda18271_priv *priv = fe->tuner_priv;
++	enum tda18271_i2c_gate gate;
++	int ret = 0;
++
++	switch (priv->gate) {
++	case TDA18271_GATE_DIGITAL:
++	case TDA18271_GATE_ANALOG:
++		gate = priv->gate;
++		break;
++	case TDA18271_GATE_AUTO:
++	default:
++		switch (priv->mode) {
++		case TDA18271_DIGITAL:
++			gate = TDA18271_GATE_DIGITAL;
++			break;
++		case TDA18271_ANALOG:
++		default:
++			gate = TDA18271_GATE_ANALOG;
++			break;
++		}
++	}
++
++	switch (gate) {
++	case TDA18271_GATE_ANALOG:
++		if (fe->ops.analog_ops.i2c_gate_ctrl)
++			ret = fe->ops.analog_ops.i2c_gate_ctrl(fe, enable);
++		break;
++	case TDA18271_GATE_DIGITAL:
++		if (fe->ops.i2c_gate_ctrl)
++			ret = fe->ops.i2c_gate_ctrl(fe, enable);
++		break;
++	default:
++		ret = -EINVAL;
++		break;
++	}
++
++	return ret;
++};
++
++/*---------------------------------------------------------------------*/
++
++static void tda18271_dump_regs(struct dvb_frontend *fe, int extended)
++{
++	struct tda18271_priv *priv = fe->tuner_priv;
++	unsigned char *regs = priv->tda18271_regs;
++
++	tda_reg("=== TDA18271 REG DUMP ===\n");
++	tda_reg("ID_BYTE            = 0x%02x\n", 0xff & regs[R_ID]);
++	tda_reg("THERMO_BYTE        = 0x%02x\n", 0xff & regs[R_TM]);
++	tda_reg("POWER_LEVEL_BYTE   = 0x%02x\n", 0xff & regs[R_PL]);
++	tda_reg("EASY_PROG_BYTE_1   = 0x%02x\n", 0xff & regs[R_EP1]);
++	tda_reg("EASY_PROG_BYTE_2   = 0x%02x\n", 0xff & regs[R_EP2]);
++	tda_reg("EASY_PROG_BYTE_3   = 0x%02x\n", 0xff & regs[R_EP3]);
++	tda_reg("EASY_PROG_BYTE_4   = 0x%02x\n", 0xff & regs[R_EP4]);
++	tda_reg("EASY_PROG_BYTE_5   = 0x%02x\n", 0xff & regs[R_EP5]);
++	tda_reg("CAL_POST_DIV_BYTE  = 0x%02x\n", 0xff & regs[R_CPD]);
++	tda_reg("CAL_DIV_BYTE_1     = 0x%02x\n", 0xff & regs[R_CD1]);
++	tda_reg("CAL_DIV_BYTE_2     = 0x%02x\n", 0xff & regs[R_CD2]);
++	tda_reg("CAL_DIV_BYTE_3     = 0x%02x\n", 0xff & regs[R_CD3]);
++	tda_reg("MAIN_POST_DIV_BYTE = 0x%02x\n", 0xff & regs[R_MPD]);
++	tda_reg("MAIN_DIV_BYTE_1    = 0x%02x\n", 0xff & regs[R_MD1]);
++	tda_reg("MAIN_DIV_BYTE_2    = 0x%02x\n", 0xff & regs[R_MD2]);
++	tda_reg("MAIN_DIV_BYTE_3    = 0x%02x\n", 0xff & regs[R_MD3]);
++
++	/* only dump extended regs if DBG_ADV is set */
++	if (!(tda18271_debug & DBG_ADV))
++		return;
++
++	/* W indicates write-only registers.
++	 * Register dump for write-only registers shows last value written. */
++
++	tda_reg("EXTENDED_BYTE_1    = 0x%02x\n", 0xff & regs[R_EB1]);
++	tda_reg("EXTENDED_BYTE_2    = 0x%02x\n", 0xff & regs[R_EB2]);
++	tda_reg("EXTENDED_BYTE_3    = 0x%02x\n", 0xff & regs[R_EB3]);
++	tda_reg("EXTENDED_BYTE_4    = 0x%02x\n", 0xff & regs[R_EB4]);
++	tda_reg("EXTENDED_BYTE_5    = 0x%02x\n", 0xff & regs[R_EB5]);
++	tda_reg("EXTENDED_BYTE_6    = 0x%02x\n", 0xff & regs[R_EB6]);
++	tda_reg("EXTENDED_BYTE_7    = 0x%02x\n", 0xff & regs[R_EB7]);
++	tda_reg("EXTENDED_BYTE_8    = 0x%02x\n", 0xff & regs[R_EB8]);
++	tda_reg("EXTENDED_BYTE_9  W = 0x%02x\n", 0xff & regs[R_EB9]);
++	tda_reg("EXTENDED_BYTE_10   = 0x%02x\n", 0xff & regs[R_EB10]);
++	tda_reg("EXTENDED_BYTE_11   = 0x%02x\n", 0xff & regs[R_EB11]);
++	tda_reg("EXTENDED_BYTE_12   = 0x%02x\n", 0xff & regs[R_EB12]);
++	tda_reg("EXTENDED_BYTE_13   = 0x%02x\n", 0xff & regs[R_EB13]);
++	tda_reg("EXTENDED_BYTE_14   = 0x%02x\n", 0xff & regs[R_EB14]);
++	tda_reg("EXTENDED_BYTE_15   = 0x%02x\n", 0xff & regs[R_EB15]);
++	tda_reg("EXTENDED_BYTE_16 W = 0x%02x\n", 0xff & regs[R_EB16]);
++	tda_reg("EXTENDED_BYTE_17 W = 0x%02x\n", 0xff & regs[R_EB17]);
++	tda_reg("EXTENDED_BYTE_18   = 0x%02x\n", 0xff & regs[R_EB18]);
++	tda_reg("EXTENDED_BYTE_19 W = 0x%02x\n", 0xff & regs[R_EB19]);
++	tda_reg("EXTENDED_BYTE_20 W = 0x%02x\n", 0xff & regs[R_EB20]);
++	tda_reg("EXTENDED_BYTE_21   = 0x%02x\n", 0xff & regs[R_EB21]);
++	tda_reg("EXTENDED_BYTE_22   = 0x%02x\n", 0xff & regs[R_EB22]);
++	tda_reg("EXTENDED_BYTE_23   = 0x%02x\n", 0xff & regs[R_EB23]);
++}
++
++int tda18271_read_regs(struct dvb_frontend *fe)
++{
++	struct tda18271_priv *priv = fe->tuner_priv;
++	unsigned char *regs = priv->tda18271_regs;
++	unsigned char buf = 0x00;
++	int ret;
++	struct i2c_msg msg[] = {
++		{ .addr = priv->i2c_addr, .flags = 0,
++		  .buf = &buf, .len = 1 },
++		{ .addr = priv->i2c_addr, .flags = I2C_M_RD,
++		  .buf = regs, .len = 16 }
++	};
++
++	tda18271_i2c_gate_ctrl(fe, 1);
++
++	/* read all registers */
++	ret = i2c_transfer(priv->i2c_adap, msg, 2);
++
++	tda18271_i2c_gate_ctrl(fe, 0);
++
++	if (ret != 2)
++		tda_err("ERROR: i2c_transfer returned: %d\n", ret);
++
++	if (tda18271_debug & DBG_REG)
++		tda18271_dump_regs(fe, 0);
++
++	return (ret == 2 ? 0 : ret);
++}
++
++int tda18271_read_extended(struct dvb_frontend *fe)
++{
++	struct tda18271_priv *priv = fe->tuner_priv;
++	unsigned char *regs = priv->tda18271_regs;
++	unsigned char regdump[TDA18271_NUM_REGS];
++	unsigned char buf = 0x00;
++	int ret, i;
++	struct i2c_msg msg[] = {
++		{ .addr = priv->i2c_addr, .flags = 0,
++		  .buf = &buf, .len = 1 },
++		{ .addr = priv->i2c_addr, .flags = I2C_M_RD,
++		  .buf = regdump, .len = TDA18271_NUM_REGS }
++	};
++
++	tda18271_i2c_gate_ctrl(fe, 1);
++
++	/* read all registers */
++	ret = i2c_transfer(priv->i2c_adap, msg, 2);
++
++	tda18271_i2c_gate_ctrl(fe, 0);
++
++	if (ret != 2)
++		tda_err("ERROR: i2c_transfer returned: %d\n", ret);
++
++	for (i = 0; i <= TDA18271_NUM_REGS; i++) {
++		/* don't update write-only registers */
++		if ((i != R_EB9)  &&
++		    (i != R_EB16) &&
++		    (i != R_EB17) &&
++		    (i != R_EB19) &&
++		    (i != R_EB20))
++		regs[i] = regdump[i];
++	}
++
++	if (tda18271_debug & DBG_REG)
++		tda18271_dump_regs(fe, 1);
++
++	return (ret == 2 ? 0 : ret);
++}
++
++int tda18271_write_regs(struct dvb_frontend *fe, int idx, int len)
++{
++	struct tda18271_priv *priv = fe->tuner_priv;
++	unsigned char *regs = priv->tda18271_regs;
++	unsigned char buf[TDA18271_NUM_REGS + 1];
++	struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0,
++			       .buf = buf, .len = len + 1 };
++	int i, ret;
++
++	BUG_ON((len == 0) || (idx + len > sizeof(buf)));
++
++	buf[0] = idx;
++	for (i = 1; i <= len; i++)
++		buf[i] = regs[idx - 1 + i];
++
++	tda18271_i2c_gate_ctrl(fe, 1);
++
++	/* write registers */
++	ret = i2c_transfer(priv->i2c_adap, &msg, 1);
++
++	tda18271_i2c_gate_ctrl(fe, 0);
++
++	if (ret != 1)
++		tda_err("ERROR: i2c_transfer returned: %d\n", ret);
++
++	return (ret == 1 ? 0 : ret);
++}
++
++/*---------------------------------------------------------------------*/
++
++int tda18271_init_regs(struct dvb_frontend *fe)
++{
++	struct tda18271_priv *priv = fe->tuner_priv;
++	unsigned char *regs = priv->tda18271_regs;
++
++	tda_dbg("initializing registers for device @ %d-%04x\n",
++		i2c_adapter_id(priv->i2c_adap), priv->i2c_addr);
++
++	/* initialize registers */
++	switch (priv->id) {
++	case TDA18271HDC1:
++		regs[R_ID]   = 0x83;
++		break;
++	case TDA18271HDC2:
++		regs[R_ID]   = 0x84;
++		break;
++	};
++
++	regs[R_TM]   = 0x08;
++	regs[R_PL]   = 0x80;
++	regs[R_EP1]  = 0xc6;
++	regs[R_EP2]  = 0xdf;
++	regs[R_EP3]  = 0x16;
++	regs[R_EP4]  = 0x60;
++	regs[R_EP5]  = 0x80;
++	regs[R_CPD]  = 0x80;
++	regs[R_CD1]  = 0x00;
++	regs[R_CD2]  = 0x00;
++	regs[R_CD3]  = 0x00;
++	regs[R_MPD]  = 0x00;
++	regs[R_MD1]  = 0x00;
++	regs[R_MD2]  = 0x00;
++	regs[R_MD3]  = 0x00;
++
++	switch (priv->id) {
++	case TDA18271HDC1:
++		regs[R_EB1]  = 0xff;
++		break;
++	case TDA18271HDC2:
++		regs[R_EB1]  = 0xfc;
++		break;
++	};
++
++	regs[R_EB2]  = 0x01;
++	regs[R_EB3]  = 0x84;
++	regs[R_EB4]  = 0x41;
++	regs[R_EB5]  = 0x01;
++	regs[R_EB6]  = 0x84;
++	regs[R_EB7]  = 0x40;
++	regs[R_EB8]  = 0x07;
++	regs[R_EB9]  = 0x00;
++	regs[R_EB10] = 0x00;
++	regs[R_EB11] = 0x96;
++
++	switch (priv->id) {
++	case TDA18271HDC1:
++		regs[R_EB12] = 0x0f;
++		break;
++	case TDA18271HDC2:
++		regs[R_EB12] = 0x33;
++		break;
++	};
++
++	regs[R_EB13] = 0xc1;
++	regs[R_EB14] = 0x00;
++	regs[R_EB15] = 0x8f;
++	regs[R_EB16] = 0x00;
++	regs[R_EB17] = 0x00;
++
++	switch (priv->id) {
++	case TDA18271HDC1:
++		regs[R_EB18] = 0x00;
++		break;
++	case TDA18271HDC2:
++		regs[R_EB18] = 0x8c;
++		break;
++	};
++
++	regs[R_EB19] = 0x00;
++	regs[R_EB20] = 0x20;
++
++	switch (priv->id) {
++	case TDA18271HDC1:
++		regs[R_EB21] = 0x33;
++		break;
++	case TDA18271HDC2:
++		regs[R_EB21] = 0xb3;
++		break;
++	};
++
++	regs[R_EB22] = 0x48;
++	regs[R_EB23] = 0xb0;
++
++	tda18271_write_regs(fe, 0x00, TDA18271_NUM_REGS);
++
++	/* setup agc1 gain */
++	regs[R_EB17] = 0x00;
++	tda18271_write_regs(fe, R_EB17, 1);
++	regs[R_EB17] = 0x03;
++	tda18271_write_regs(fe, R_EB17, 1);
++	regs[R_EB17] = 0x43;
++	tda18271_write_regs(fe, R_EB17, 1);
++	regs[R_EB17] = 0x4c;
++	tda18271_write_regs(fe, R_EB17, 1);
++
++	/* setup agc2 gain */
++	if ((priv->id) == TDA18271HDC1) {
++		regs[R_EB20] = 0xa0;
++		tda18271_write_regs(fe, R_EB20, 1);
++		regs[R_EB20] = 0xa7;
++		tda18271_write_regs(fe, R_EB20, 1);
++		regs[R_EB20] = 0xe7;
++		tda18271_write_regs(fe, R_EB20, 1);
++		regs[R_EB20] = 0xec;
++		tda18271_write_regs(fe, R_EB20, 1);
++	}
++
++	/* image rejection calibration */
++
++	/* low-band */
++	regs[R_EP3] = 0x1f;
++	regs[R_EP4] = 0x66;
++	regs[R_EP5] = 0x81;
++	regs[R_CPD] = 0xcc;
++	regs[R_CD1] = 0x6c;
++	regs[R_CD2] = 0x00;
++	regs[R_CD3] = 0x00;
++	regs[R_MPD] = 0xcd;
++	regs[R_MD1] = 0x77;
++	regs[R_MD2] = 0x08;
++	regs[R_MD3] = 0x00;
 +
- config TUNER_MT20XX
- 	tristate "Microtune 2032 / 2050 tuners"
- 	depends on I2C
-@@ -97,8 +106,10 @@ config TUNER_MT20XX
- 	  Say Y here to include support for the MT2032 / MT2050 tuner.
- 
- config TUNER_TDA8290
--	tristate "TDA 8290+8275(a) tuner combo"
-+	tristate "TDA 8290/8295 + 8275(a)/18271 tuner combo"
- 	depends on I2C
-+	select DVB_TDA827X
-+	select DVB_TDA18271
- 	default m if VIDEO_TUNER_CUSTOMIZE
- 	help
- 	  Say Y here to include support for Philips TDA8290+8275(a) tuner.
-@@ -120,10 +131,19 @@ config TUNER_TEA5767
- config TUNER_SIMPLE
- 	tristate "Simple tuner support"
- 	depends on I2C
-+	select TUNER_TDA9887
- 	default m if VIDEO_TUNER_CUSTOMIZE
- 	help
- 	  Say Y here to include support for various simple tuners.
- 
-+config TUNER_TDA9887
-+	tristate "TDA 9885/6/7 analog IF demodulator"
-+	depends on I2C
-+	default m if VIDEO_TUNER_CUSTOMIZE
-+	help
-+	  Say Y here to include support for Philips TDA9885/6/7
-+	  analog IF demodulator.
++	switch (priv->id) {
++	case TDA18271HDC1:
++		tda18271_write_regs(fe, R_EP3, 11);
++		break;
++	case TDA18271HDC2:
++		tda18271_write_regs(fe, R_EP3, 12);
++		break;
++	};
 +
- endif # VIDEO_TUNER_CUSTOMIZE
- 
- config VIDEOBUF_GEN
-diff --git a/drivers/media/common/Kconfig b/drivers/media/common/Kconfig
-index c5092ef..06ca759 100644
---- a/drivers/media/common/Kconfig
-+++ b/drivers/media/common/Kconfig
-@@ -1,6 +1,6 @@
- config VIDEO_SAA7146
- 	tristate
--	depends on I2C
-+	depends on I2C && PCI
- 
- config VIDEO_SAA7146_VV
- 	tristate
-diff --git a/drivers/media/common/ir-functions.c b/drivers/media/common/ir-functions.c
-index e7c3ab9..bb2a027 100644
---- a/drivers/media/common/ir-functions.c
-+++ b/drivers/media/common/ir-functions.c
-@@ -258,7 +258,7 @@ int ir_decode_biphase(u32 *samples, int count, int low, int high)
-  * saa7134 */
- 
- /* decode raw bit pattern to RC5 code */
--u32 ir_rc5_decode(unsigned int code)
-+static u32 ir_rc5_decode(unsigned int code)
- {
- 	unsigned int org_code = code;
- 	unsigned int pair;
-@@ -371,7 +371,6 @@ EXPORT_SYMBOL_GPL(ir_dump_samples);
- EXPORT_SYMBOL_GPL(ir_decode_biphase);
- EXPORT_SYMBOL_GPL(ir_decode_pulsedistance);
- 
--EXPORT_SYMBOL_GPL(ir_rc5_decode);
- EXPORT_SYMBOL_GPL(ir_rc5_timer_end);
- EXPORT_SYMBOL_GPL(ir_rc5_timer_keyup);
- 
-diff --git a/drivers/media/common/ir-keymaps.c b/drivers/media/common/ir-keymaps.c
-index 185e8a8..a4a937c 100644
---- a/drivers/media/common/ir-keymaps.c
-+++ b/drivers/media/common/ir-keymaps.c
-@@ -1331,7 +1331,12 @@ IR_KEYTAB_TYPE ir_codes_winfast[IR_KEYTAB_SIZE] = {
- 	[ 0x35 ] = KEY_FASTFORWARD,
- 	[ 0x36 ] = KEY_TV,
- 	[ 0x37 ] = KEY_RADIO,         /* FM */
--	[ 0x38 ] = KEY_DVD
-+	[ 0x38 ] = KEY_DVD,
++	if ((priv->id) == TDA18271HDC2) {
++		/* main pll cp source on */
++		regs[R_EB4] = 0x61;
++		tda18271_write_regs(fe, R_EB4, 1);
++		msleep(1);
 +
-+	[ 0x3e ] = KEY_F21,           /* MCE +VOL, on Y04G0033 */
-+	[ 0x3a ] = KEY_F22,           /* MCE -VOL, on Y04G0033 */
-+	[ 0x3b ] = KEY_F23,           /* MCE +CH,  on Y04G0033 */
-+	[ 0x3f ] = KEY_F24            /* MCE -CH,  on Y04G0033 */
- };
- 
- EXPORT_SYMBOL_GPL(ir_codes_winfast);
-@@ -1843,3 +1848,142 @@ IR_KEYTAB_TYPE ir_codes_fusionhdtv_mce[IR_KEYTAB_SIZE] = {
- };
- 
- EXPORT_SYMBOL_GPL(ir_codes_fusionhdtv_mce);
++		/* main pll cp source off */
++		regs[R_EB4] = 0x41;
++		tda18271_write_regs(fe, R_EB4, 1);
++	}
 +
-+/* Pinnacle PCTV HD 800i mini remote */
-+IR_KEYTAB_TYPE ir_codes_pinnacle_pctv_hd[IR_KEYTAB_SIZE] = {
++	msleep(5); /* pll locking */
 +
-+	[0x0f] = KEY_1,
-+	[0x15] = KEY_2,
-+	[0x10] = KEY_3,
-+	[0x18] = KEY_4,
-+	[0x1b] = KEY_5,
-+	[0x1e] = KEY_6,
-+	[0x11] = KEY_7,
-+	[0x21] = KEY_8,
-+	[0x12] = KEY_9,
-+	[0x27] = KEY_0,
++	/* launch detector */
++	tda18271_write_regs(fe, R_EP1, 1);
++	msleep(5); /* wanted low measurement */
 +
-+	[0x24] = KEY_ZOOM,
-+	[0x2a] = KEY_SUBTITLE,
++	regs[R_EP5] = 0x85;
++	regs[R_CPD] = 0xcb;
++	regs[R_CD1] = 0x66;
++	regs[R_CD2] = 0x70;
 +
-+	[0x00] = KEY_MUTE,
-+	[0x01] = KEY_ENTER,	/* Pinnacle Logo */
-+	[0x39] = KEY_POWER,
++	tda18271_write_regs(fe, R_EP3, 7);
++	msleep(5); /* pll locking */
 +
-+	[0x03] = KEY_VOLUMEUP,
-+	[0x09] = KEY_VOLUMEDOWN,
-+	[0x06] = KEY_CHANNELUP,
-+	[0x0c] = KEY_CHANNELDOWN,
++	/* launch optimization algorithm */
++	tda18271_write_regs(fe, R_EP2, 1);
++	msleep(30); /* image low optimization completion */
 +
-+	[0x2d] = KEY_REWIND,
-+	[0x30] = KEY_PLAYPAUSE,
-+	[0x33] = KEY_FASTFORWARD,
-+	[0x3c] = KEY_STOP,
-+	[0x36] = KEY_RECORD,
-+	[0x3f] = KEY_EPG,	/* Labeled "?" */
-+};
-+EXPORT_SYMBOL_GPL(ir_codes_pinnacle_pctv_hd);
++	/* mid-band */
++	regs[R_EP5] = 0x82;
++	regs[R_CPD] = 0xa8;
++	regs[R_CD2] = 0x00;
++	regs[R_MPD] = 0xa9;
++	regs[R_MD1] = 0x73;
++	regs[R_MD2] = 0x1a;
++
++	tda18271_write_regs(fe, R_EP3, 11);
++	msleep(5); /* pll locking */
++
++	tda18271_write_regs(fe, R_EP1, 1);
++	msleep(5); /* wanted mid measurement */
++
++	regs[R_EP5] = 0x86;
++	regs[R_CPD] = 0xa8;
++	regs[R_CD1] = 0x66;
++	regs[R_CD2] = 0xa0;
++
++	tda18271_write_regs(fe, R_EP3, 7);
++	msleep(5); /* pll locking */
++
++	/* launch optimization algorithm */
++	tda18271_write_regs(fe, R_EP2, 1);
++	msleep(30); /* image mid optimization completion */
++
++	/* high-band */
++	regs[R_EP5] = 0x83;
++	regs[R_CPD] = 0x98;
++	regs[R_CD1] = 0x65;
++	regs[R_CD2] = 0x00;
++	regs[R_MPD] = 0x99;
++	regs[R_MD1] = 0x71;
++	regs[R_MD2] = 0xcd;
++
++	tda18271_write_regs(fe, R_EP3, 11);
++	msleep(5); /* pll locking */
++
++	/* launch detector */
++	tda18271_write_regs(fe, R_EP1, 1);
++	msleep(5); /* wanted high measurement */
++
++	regs[R_EP5] = 0x87;
++	regs[R_CD1] = 0x65;
++	regs[R_CD2] = 0x50;
++
++	tda18271_write_regs(fe, R_EP3, 7);
++	msleep(5); /* pll locking */
++
++	/* launch optimization algorithm */
++	tda18271_write_regs(fe, R_EP2, 1);
++	msleep(30); /* image high optimization completion */
++
++	/* return to normal mode */
++	regs[R_EP4] = 0x64;
++	tda18271_write_regs(fe, R_EP4, 1);
++
++	/* synchronize */
++	tda18271_write_regs(fe, R_EP1, 1);
++
++	return 0;
++}
++
++/*---------------------------------------------------------------------*/
 +
 +/*
-+ * Igor Kuznetsov <igk72 at ya.ru>
-+ * Andrey J. Melnikov <temnota at kmv.ru>
++ *  Standby modes, EP3 [7:5]
++ *
++ *  | SM  || SM_LT || SM_XT || mode description
++ *  |=====\\=======\\=======\\===================================
++ *  |  0  ||   0   ||   0   || normal mode
++ *  |-----||-------||-------||-----------------------------------
++ *  |     ||       ||       || standby mode w/ slave tuner output
++ *  |  1  ||   0   ||   0   || & loop thru & xtal oscillator on
++ *  |-----||-------||-------||-----------------------------------
++ *  |  1  ||   1   ||   0   || standby mode w/ xtal oscillator on
++ *  |-----||-------||-------||-----------------------------------
++ *  |  1  ||   1   ||   1   || power off
 + *
-+ * Keytable is used by BeholdTV 60x series, M6 series at
-+ * least, and probably other cards too.
-+ * The "ascii-art picture" below (in comments, first row
-+ * is the keycode in hex, and subsequent row(s) shows
-+ * the button labels (several variants when appropriate)
-+ * helps to descide which keycodes to assign to the buttons.
 + */
-+IR_KEYTAB_TYPE ir_codes_behold[IR_KEYTAB_SIZE] = {
-+
-+	/*  0x1c            0x12  *
-+	 *  TV/FM          POWER  *
-+	 *                        */
-+	[ 0x1c ] = KEY_TUNER,	/*XXX KEY_TV KEY_RADIO */
-+	[ 0x12 ] = KEY_POWER,
 +
-+	/*  0x01    0x02    0x03  *
-+	 *   1       2       3    *
-+	 *                        *
-+	 *  0x04    0x05    0x06  *
-+	 *   4       5       6    *
-+	 *                        *
-+	 *  0x07    0x08    0x09  *
-+	 *   7       8       9    *
-+	 *                        */
-+	[ 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,
++int tda18271_set_standby_mode(struct dvb_frontend *fe,
++			      int sm, int sm_lt, int sm_xt)
++{
++	struct tda18271_priv *priv = fe->tuner_priv;
++	unsigned char *regs = priv->tda18271_regs;
 +
-+	/*  0x0a    0x00    0x17  *
-+	 * RECALL    0      MODE  *
-+	 *                        */
-+	[ 0x0a ] = KEY_AGAIN,
-+	[ 0x00 ] = KEY_0,
-+	[ 0x17 ] = KEY_MODE,
++	tda_dbg("sm = %d, sm_lt = %d, sm_xt = %d\n", sm, sm_lt, sm_xt);
 +
-+	/*  0x14          0x10    *
-+	 * ASPECT      FULLSCREEN *
-+	 *                        */
-+	[ 0x14 ] = KEY_SCREEN,
-+	[ 0x10 ] = KEY_ZOOM,
++	regs[R_EP3]  &= ~0xe0; /* clear sm, sm_lt, sm_xt */
++	regs[R_EP3]  |= sm    ? (1 << 7) : 0 |
++			sm_lt ? (1 << 6) : 0 |
++			sm_xt ? (1 << 5) : 0;
 +
-+	/*          0x0b          *
-+	 *           Up           *
-+	 *                        *
-+	 *  0x18    0x16    0x0c  *
-+	 *  Left     Ok     Right *
-+	 *                        *
-+	 *         0x015          *
-+	 *         Down           *
-+	 *                        */
-+	[ 0x0b ] = KEY_CHANNELUP,	/*XXX KEY_UP */
-+	[ 0x18 ] = KEY_VOLUMEDOWN,	/*XXX KEY_LEFT */
-+	[ 0x16 ] = KEY_OK,		/*XXX KEY_ENTER */
-+	[ 0x0c ] = KEY_VOLUMEUP,	/*XXX KEY_RIGHT */
-+	[ 0x15 ] = KEY_CHANNELDOWN,	/*XXX KEY_DOWN */
++	tda18271_write_regs(fe, R_EP3, 1);
 +
-+	/*  0x11            0x0d  *
-+	 *  MUTE            INFO  *
-+	 *                        */
-+	[ 0x11 ] = KEY_MUTE,
-+	[ 0x0d ] = KEY_INFO,
++	return 0;
++}
 +
-+	/*  0x0f    0x1b    0x1a  *
-+	 * RECORD PLAY/PAUSE STOP *
-+	 *                        *
-+	 *  0x0e    0x1f    0x1e  *
-+	 *TELETEXT  AUDIO  SOURCE *
-+	 *           RED   YELLOW *
-+	 *                        */
-+	[ 0x0f ] = KEY_RECORD,
-+	[ 0x1b ] = KEY_PLAYPAUSE,
-+	[ 0x1a ] = KEY_STOP,
-+	[ 0x0e ] = KEY_TEXT,
-+	[ 0x1f ] = KEY_RED,	/*XXX KEY_AUDIO */
-+	[ 0x1e ] = KEY_YELLOW,	/*XXX KEY_SOURCE */
++/*---------------------------------------------------------------------*/
 +
-+	/*  0x1d   0x13     0x19  *
-+	 * SLEEP  PREVIEW   DVB   *
-+	 *         GREEN    BLUE  *
-+	 *                        */
-+	[ 0x1d ] = KEY_SLEEP,
-+	[ 0x13 ] = KEY_GREEN,
-+	[ 0x19 ] = KEY_BLUE,	/*XXX KEY_SAT */
++int tda18271_calc_main_pll(struct dvb_frontend *fe, u32 freq)
++{
++	/* sets main post divider & divider bytes, but does not write them */
++	struct tda18271_priv *priv = fe->tuner_priv;
++	unsigned char *regs = priv->tda18271_regs;
++	u8 d, pd;
++	u32 div;
 +
-+	/*  0x58           0x5c   *
-+	 * FREEZE        SNAPSHOT *
-+	 *                        */
-+	[ 0x58 ] = KEY_SLOW,
-+	[ 0x5c ] = KEY_SAVE,
++	int ret = tda18271_lookup_pll_map(fe, MAIN_PLL, &freq, &pd, &d);
++	if (ret < 0)
++		goto fail;
 +
-+};
++	regs[R_MPD]   = (0x77 & pd);
 +
-+EXPORT_SYMBOL_GPL(ir_codes_behold);
-diff --git a/drivers/media/common/saa7146_fops.c b/drivers/media/common/saa7146_fops.c
-index 67d1b1b..f0703d8 100644
---- a/drivers/media/common/saa7146_fops.c
-+++ b/drivers/media/common/saa7146_fops.c
-@@ -61,7 +61,7 @@ void saa7146_dma_free(struct saa7146_dev *dev,struct videobuf_queue *q,
- 	videobuf_waiton(&buf->vb,0,0);
- 	videobuf_dma_unmap(q, dma);
- 	videobuf_dma_free(dma);
--	buf->vb.state = STATE_NEEDS_INIT;
-+	buf->vb.state = VIDEOBUF_NEEDS_INIT;
- }
- 
- 
-@@ -83,7 +83,7 @@ int saa7146_buffer_queue(struct saa7146_dev *dev,
- 		buf->activate(dev,buf,NULL);
- 	} else {
- 		list_add_tail(&buf->vb.queue,&q->queue);
--		buf->vb.state = STATE_QUEUED;
-+		buf->vb.state = VIDEOBUF_QUEUED;
- 		DEB_D(("adding buffer %p to queue. (active buffer present)\n", buf));
- 	}
- 	return 0;
-@@ -174,7 +174,7 @@ void saa7146_buffer_timeout(unsigned long data)
- 	spin_lock_irqsave(&dev->slock,flags);
- 	if (q->curr) {
- 		DEB_D(("timeout on %p\n", q->curr));
--		saa7146_buffer_finish(dev,q,STATE_ERROR);
-+		saa7146_buffer_finish(dev,q,VIDEOBUF_ERROR);
- 	}
- 
- 	/* we don't restart the transfer here like other drivers do. when
-@@ -366,7 +366,7 @@ static unsigned int fops_poll(struct file *file, struct poll_table_struct *wait)
- 	}
- 
- 	poll_wait(file, &buf->done, wait);
--	if (buf->state == STATE_DONE || buf->state == STATE_ERROR) {
-+	if (buf->state == VIDEOBUF_DONE || buf->state == VIDEOBUF_ERROR) {
- 		DEB_D(("poll succeeded!\n"));
- 		return POLLIN|POLLRDNORM;
- 	}
-@@ -538,6 +538,7 @@ int saa7146_register_device(struct video_device **vid, struct saa7146_dev* dev,
- 	// fixme: -1 should be an insmod parameter *for the extension* (like "video_nr");
- 	if (video_register_device(vfd, type, -1) < 0) {
- 		ERR(("cannot register v4l2 device. skipping.\n"));
-+		video_device_release(vfd);
- 		return -1;
- 	}
- 
-diff --git a/drivers/media/common/saa7146_vbi.c b/drivers/media/common/saa7146_vbi.c
-index 6103484..c32dda9 100644
---- a/drivers/media/common/saa7146_vbi.c
-+++ b/drivers/media/common/saa7146_vbi.c
-@@ -205,7 +205,7 @@ static int buffer_activate(struct saa7146_dev *dev,
- 			   struct saa7146_buf *next)
- {
- 	struct saa7146_vv *vv = dev->vv_data;
--	buf->vb.state = STATE_ACTIVE;
-+	buf->vb.state = VIDEOBUF_ACTIVE;
- 
- 	DEB_VBI(("dev:%p, buf:%p, next:%p\n",dev,buf,next));
- 	saa7146_set_vbi_capture(dev,buf,next);
-@@ -238,7 +238,7 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,e
- 	if (buf->vb.size != size)
- 		saa7146_dma_free(dev,q,buf);
- 
--	if (STATE_NEEDS_INIT == buf->vb.state) {
-+	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
- 		struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
- 
- 		buf->vb.width  = llength;
-@@ -257,7 +257,7 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,e
- 		if (0 != err)
- 			return err;
- 	}
--	buf->vb.state = STATE_PREPARED;
-+	buf->vb.state = VIDEOBUF_PREPARED;
- 	buf->activate = buffer_activate;
- 
- 	return 0;
-@@ -335,7 +335,7 @@ static void vbi_stop(struct saa7146_fh *fh, struct file *file)
- 	saa7146_write(dev, MC1, MASK_20);
- 
- 	if (vv->vbi_q.curr) {
--		saa7146_buffer_finish(dev,&vv->vbi_q,STATE_DONE);
-+		saa7146_buffer_finish(dev,&vv->vbi_q,VIDEOBUF_DONE);
- 	}
- 
- 	videobuf_queue_cancel(&fh->vbi_q);
-@@ -458,7 +458,7 @@ static void vbi_irq_done(struct saa7146_dev *dev, unsigned long status)
- 		/* this must be += 2, one count for each field */
- 		vv->vbi_fieldcount+=2;
- 		vv->vbi_q.curr->vb.field_count = vv->vbi_fieldcount;
--		saa7146_buffer_finish(dev,&vv->vbi_q,STATE_DONE);
-+		saa7146_buffer_finish(dev,&vv->vbi_q,VIDEOBUF_DONE);
- 	} else {
- 		DEB_VBI(("dev:%p\n",dev));
- 	}
-diff --git a/drivers/media/common/saa7146_video.c b/drivers/media/common/saa7146_video.c
-index ae36d10..c31ab48 100644
---- a/drivers/media/common/saa7146_video.c
-+++ b/drivers/media/common/saa7146_video.c
-@@ -1235,7 +1235,7 @@ static int buffer_activate (struct saa7146_dev *dev,
- {
- 	struct saa7146_vv *vv = dev->vv_data;
- 
--	buf->vb.state = STATE_ACTIVE;
-+	buf->vb.state = VIDEOBUF_ACTIVE;
- 	saa7146_set_capture(dev,buf,next);
- 
- 	mod_timer(&vv->video_q.timeout, jiffies+BUFFER_TIMEOUT);
-@@ -1281,7 +1281,7 @@ static int buffer_prepare(struct videobuf_queue *q,
- 		saa7146_dma_free(dev,q,buf);
- 	}
- 
--	if (STATE_NEEDS_INIT == buf->vb.state) {
-+	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
- 		struct saa7146_format *sfmt;
- 
- 		buf->vb.bytesperline  = fh->video_fmt.bytesperline;
-@@ -1314,7 +1314,7 @@ static int buffer_prepare(struct videobuf_queue *q,
- 		if (err)
- 			goto oops;
- 	}
--	buf->vb.state = STATE_PREPARED;
-+	buf->vb.state = VIDEOBUF_PREPARED;
- 	buf->activate = buffer_activate;
- 
- 	return 0;
-@@ -1453,7 +1453,7 @@ static void video_irq_done(struct saa7146_dev *dev, unsigned long st)
- 
- 	/* only finish the buffer if we have one... */
- 	if( NULL != q->curr ) {
--		saa7146_buffer_finish(dev,q,STATE_DONE);
-+		saa7146_buffer_finish(dev,q,VIDEOBUF_DONE);
- 	}
- 	saa7146_buffer_next(dev,q,0);
- 
-diff --git a/drivers/media/dvb/b2c2/flexcop.c b/drivers/media/dvb/b2c2/flexcop.c
-index 29ec418..2ddafd0 100644
---- a/drivers/media/dvb/b2c2/flexcop.c
-+++ b/drivers/media/dvb/b2c2/flexcop.c
-@@ -212,7 +212,6 @@ void flexcop_reset_block_300(struct flexcop_device *fc)
- 
- 	fc->write_ibi_reg(fc,ctrl_208,v208_save);
- }
--EXPORT_SYMBOL(flexcop_reset_block_300);
- 
- struct flexcop_device *flexcop_device_kmalloc(size_t bus_specific_len)
- {
-diff --git a/drivers/media/dvb/bt8xx/bt878.c b/drivers/media/dvb/bt8xx/bt878.c
-index 85e36a1..c7bbb40 100644
---- a/drivers/media/dvb/bt8xx/bt878.c
-+++ b/drivers/media/dvb/bt8xx/bt878.c
-@@ -378,23 +378,37 @@ bt878_device_control(struct bt878 *bt, unsigned int cmd, union dst_gpio_packet *
- 
- EXPORT_SYMBOL(bt878_device_control);
- 
-+#define BROOKTREE_878_DEVICE(vend, dev, name) \
-+	{ \
-+		.vendor = PCI_VENDOR_ID_BROOKTREE, \
-+		.device = PCI_DEVICE_ID_BROOKTREE_878, \
-+		.subvendor = (vend), .subdevice = (dev), \
-+		.driver_data = (unsigned long) name \
++	switch (priv->mode) {
++	case TDA18271_ANALOG:
++		regs[R_MPD]  &= ~0x08;
++		break;
++	case TDA18271_DIGITAL:
++		regs[R_MPD]  |=  0x08;
++		break;
 +	}
- 
--static struct cards card_list[] __devinitdata = {
--
--	{ 0x01010071, BTTV_BOARD_NEBULA_DIGITV,			"Nebula Electronics DigiTV" },
--	{ 0x07611461, BTTV_BOARD_AVDVBT_761,			"AverMedia AverTV DVB-T 761" },
--	{ 0x001c11bd, BTTV_BOARD_PINNACLESAT,			"Pinnacle PCTV Sat" },
--	{ 0x002611bd, BTTV_BOARD_TWINHAN_DST,			"Pinnacle PCTV SAT CI" },
--	{ 0x00011822, BTTV_BOARD_TWINHAN_DST,			"Twinhan VisionPlus DVB" },
--	{ 0xfc00270f, BTTV_BOARD_TWINHAN_DST,			"ChainTech digitop DST-1000 DVB-S" },
--	{ 0x07711461, BTTV_BOARD_AVDVBT_771,			"AVermedia AverTV DVB-T 771" },
--	{ 0xdb1018ac, BTTV_BOARD_DVICO_DVBT_LITE,		"DViCO FusionHDTV DVB-T Lite" },
--	{ 0xdb1118ac, BTTV_BOARD_DVICO_DVBT_LITE,		"Ultraview DVB-T Lite" },
--	{ 0xd50018ac, BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE,	"DViCO FusionHDTV 5 Lite" },
--	{ 0x20007063, BTTV_BOARD_PC_HDTV,			"pcHDTV HD-2000 TV" },
--	{ 0x00261822, BTTV_BOARD_TWINHAN_DST,			"DNTV Live! Mini" }
-+static struct pci_device_id bt878_pci_tbl[] __devinitdata = {
-+	BROOKTREE_878_DEVICE(0x0071, 0x0101, "Nebula Electronics DigiTV"),
-+	BROOKTREE_878_DEVICE(0x1461, 0x0761, "AverMedia AverTV DVB-T 761"),
-+	BROOKTREE_878_DEVICE(0x11bd, 0x001c, "Pinnacle PCTV Sat"),
-+	BROOKTREE_878_DEVICE(0x11bd, 0x0026, "Pinnacle PCTV SAT CI"),
-+	BROOKTREE_878_DEVICE(0x1822, 0x0001, "Twinhan VisionPlus DVB"),
-+	BROOKTREE_878_DEVICE(0x270f, 0xfc00,
-+				"ChainTech digitop DST-1000 DVB-S"),
-+	BROOKTREE_878_DEVICE(0x1461, 0x0771, "AVermedia AverTV DVB-T 771"),
-+	BROOKTREE_878_DEVICE(0x18ac, 0xdb10, "DViCO FusionHDTV DVB-T Lite"),
-+	BROOKTREE_878_DEVICE(0x18ac, 0xdb11, "Ultraview DVB-T Lite"),
-+	BROOKTREE_878_DEVICE(0x18ac, 0xd500, "DViCO FusionHDTV 5 Lite"),
-+	BROOKTREE_878_DEVICE(0x7063, 0x2000, "pcHDTV HD-2000 TV"),
-+	BROOKTREE_878_DEVICE(0x1822, 0x0026, "DNTV Live! Mini"),
-+	{ }
- };
- 
-+MODULE_DEVICE_TABLE(pci, bt878_pci_tbl);
 +
-+static const char * __devinit card_name(const struct pci_device_id *id)
-+{
-+	return id->driver_data ? (const char *)id->driver_data : "Unknown";
++	div =  ((d * (freq / 1000)) << 7) / 125;
++
++	regs[R_MD1]   = 0x7f & (div >> 16);
++	regs[R_MD2]   = 0xff & (div >> 8);
++	regs[R_MD3]   = 0xff & div;
++fail:
++	return ret;
 +}
- 
- /***********************/
- /* PCI device handling */
-@@ -403,15 +417,13 @@ static struct cards card_list[] __devinitdata = {
- static int __devinit bt878_probe(struct pci_dev *dev,
- 				 const struct pci_device_id *pci_id)
- {
--	int result = 0, has_dvb = 0, i;
-+	int result = 0;
- 	unsigned char lat;
- 	struct bt878 *bt;
- #if defined(__powerpc__)
- 	unsigned int cmd;
- #endif
- 	unsigned int cardid;
--	unsigned short id;
--	struct cards *dvb_cards;
- 
- 	printk(KERN_INFO "bt878: Bt878 AUDIO function found (%d).\n",
- 	       bt878_num);
-@@ -423,25 +435,11 @@ static int __devinit bt878_probe(struct pci_dev *dev,
- 	if (pci_enable_device(dev))
- 		return -EIO;
- 
--	pci_read_config_word(dev, PCI_SUBSYSTEM_ID, &id);
--	cardid = id << 16;
--	pci_read_config_word(dev, PCI_SUBSYSTEM_VENDOR_ID, &id);
--	cardid |= id;
--
--	for (i = 0, dvb_cards = card_list; i < ARRAY_SIZE(card_list); i++, dvb_cards++) {
--		if (cardid == dvb_cards->pci_id) {
--			printk("%s: card id=[0x%x],[ %s ] has DVB functions.\n",
--				__func__, cardid, dvb_cards->name);
--			has_dvb = 1;
--		}
--	}
-+	cardid = dev->subsystem_device << 16;
-+	cardid |= dev->subsystem_vendor;
- 
--	if (!has_dvb) {
--		printk("%s: card id=[0x%x], Unknown card.\nExiting..\n", __func__, cardid);
--		result = -EINVAL;
--
--		goto fail0;
--	}
-+	printk(KERN_INFO "%s: card id=[0x%x],[ %s ] has DVB functions.\n",
-+				__func__, cardid, card_name(pci_id));
- 
- 	bt = &bt878[bt878_num];
- 	bt->dev = dev;
-@@ -572,14 +570,6 @@ static void __devexit bt878_remove(struct pci_dev *pci_dev)
- 	return;
- }
- 
--static struct pci_device_id bt878_pci_tbl[] __devinitdata = {
--	{PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BROOKTREE_878,
--	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
--	{0,}
--};
--
--MODULE_DEVICE_TABLE(pci, bt878_pci_tbl);
--
- static struct pci_driver bt878_pci_driver = {
-       .name	= "bt878",
-       .id_table = bt878_pci_tbl,
-diff --git a/drivers/media/dvb/bt8xx/bt878.h b/drivers/media/dvb/bt8xx/bt878.h
-index d593bc1..375fd28 100644
---- a/drivers/media/dvb/bt8xx/bt878.h
-+++ b/drivers/media/dvb/bt8xx/bt878.h
-@@ -101,12 +101,6 @@
- #define BTTV_BOARD_DVICO_DVBT_LITE         0x80
- #define BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE 0x87
- 
--struct cards {
--	__u32 pci_id;
--	__u16 card_id;
--	char  *name;
--};
--
- extern int bt878_num;
- 
- struct bt878 {
-diff --git a/drivers/media/dvb/bt8xx/dst.c b/drivers/media/dvb/bt8xx/dst.c
-index b7a17e6..307ff35 100644
---- a/drivers/media/dvb/bt8xx/dst.c
-+++ b/drivers/media/dvb/bt8xx/dst.c
-@@ -71,6 +71,7 @@ MODULE_PARM_DESC(dst_algo, "tuning algo: default is 0=(SW), 1=(HW)");
- 	}								\
- } while(0)
- 
-+static int dst_command(struct dst_state *state, u8 *data, u8 len);
- 
- static void dst_packsize(struct dst_state *state, int psize)
- {
-@@ -80,7 +81,8 @@ static void dst_packsize(struct dst_state *state, int psize)
- 	bt878_device_control(state->bt, DST_IG_TS, &bits);
- }
- 
--int dst_gpio_outb(struct dst_state *state, u32 mask, u32 enbb, u32 outhigh, int delay)
-+static int dst_gpio_outb(struct dst_state *state, u32 mask, u32 enbb,
-+			 u32 outhigh, int delay)
- {
- 	union dst_gpio_packet enb;
- 	union dst_gpio_packet bits;
-@@ -109,9 +111,8 @@ int dst_gpio_outb(struct dst_state *state, u32 mask, u32 enbb, u32 outhigh, int
- 
- 	return 0;
- }
--EXPORT_SYMBOL(dst_gpio_outb);
- 
--int dst_gpio_inb(struct dst_state *state, u8 *result)
-+static int dst_gpio_inb(struct dst_state *state, u8 *result)
- {
- 	union dst_gpio_packet rd_packet;
- 	int err;
-@@ -125,7 +126,6 @@ int dst_gpio_inb(struct dst_state *state, u8 *result)
- 
- 	return 0;
- }
--EXPORT_SYMBOL(dst_gpio_inb);
- 
- int rdc_reset_state(struct dst_state *state)
- {
-@@ -145,7 +145,7 @@ int rdc_reset_state(struct dst_state *state)
- }
- EXPORT_SYMBOL(rdc_reset_state);
- 
--int rdc_8820_reset(struct dst_state *state)
-+static int rdc_8820_reset(struct dst_state *state)
- {
- 	dprintk(verbose, DST_DEBUG, 1, "Resetting DST");
- 	if (dst_gpio_outb(state, RDC_8820_RESET, RDC_8820_RESET, 0, NO_DELAY) < 0) {
-@@ -160,9 +160,8 @@ int rdc_8820_reset(struct dst_state *state)
- 
- 	return 0;
- }
--EXPORT_SYMBOL(rdc_8820_reset);
- 
--int dst_pio_enable(struct dst_state *state)
-+static int dst_pio_enable(struct dst_state *state)
- {
- 	if (dst_gpio_outb(state, ~0, RDC_8820_PIO_0_ENABLE, 0, NO_DELAY) < 0) {
- 		dprintk(verbose, DST_ERROR, 1, "dst_gpio_outb ERROR !");
-@@ -172,7 +171,6 @@ int dst_pio_enable(struct dst_state *state)
- 
- 	return 0;
- }
--EXPORT_SYMBOL(dst_pio_enable);
- 
- int dst_pio_disable(struct dst_state *state)
- {
-@@ -611,7 +609,7 @@ static int dst_type_print(struct dst_state *state, u8 type)
- 	return 0;
- }
- 
--struct tuner_types tuner_list[] = {
-+static struct tuner_types tuner_list[] = {
- 	{
- 		.tuner_type = TUNER_TYPE_L64724,
- 		.tuner_name = "L 64724",
-@@ -1224,7 +1222,7 @@ static int dst_probe(struct dst_state *state)
- 	return 0;
- }
- 
--int dst_command(struct dst_state *state, u8 *data, u8 len)
-+static int dst_command(struct dst_state *state, u8 *data, u8 len)
- {
- 	u8 reply;
- 
-@@ -1287,7 +1285,6 @@ error:
- 	return -EIO;
- 
- }
--EXPORT_SYMBOL(dst_command);
- 
- static int dst_get_signal(struct dst_state *state)
- {
-diff --git a/drivers/media/dvb/bt8xx/dst_common.h b/drivers/media/dvb/bt8xx/dst_common.h
-index 87623d2..d88cf2a 100644
---- a/drivers/media/dvb/bt8xx/dst_common.h
-+++ b/drivers/media/dvb/bt8xx/dst_common.h
-@@ -165,10 +165,8 @@ struct dst_config
- };
- 
- int rdc_reset_state(struct dst_state *state);
--int rdc_8820_reset(struct dst_state *state);
- 
- int dst_wait_dst_ready(struct dst_state *state, u8 delay_mode);
--int dst_pio_enable(struct dst_state *state);
- int dst_pio_disable(struct dst_state *state);
- int dst_error_recovery(struct dst_state* state);
- int dst_error_bailout(struct dst_state *state);
-@@ -179,9 +177,6 @@ int read_dst(struct dst_state *state, u8 * ret, u8 len);
- u8 dst_check_sum(u8 * buf, u32 len);
- struct dst_state* dst_attach(struct dst_state* state, struct dvb_adapter *dvb_adapter);
- struct dvb_device *dst_ca_attach(struct dst_state *state, struct dvb_adapter *dvb_adapter);
--int dst_gpio_outb(struct dst_state* state, u32 mask, u32 enbb, u32 outhigh, int delay);
--
--int dst_command(struct dst_state* state, u8 * data, u8 len);
- 
- 
- #endif // DST_COMMON_H
-diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c
-index 445f026..925cfa6 100644
---- a/drivers/media/dvb/dvb-core/dvb_frontend.c
-+++ b/drivers/media/dvb/dvb-core/dvb_frontend.c
-@@ -1202,6 +1202,10 @@ void dvb_frontend_detach(struct dvb_frontend* fe)
- 		fe->ops.tuner_ops.release(fe);
- 		symbol_put_addr(fe->ops.tuner_ops.release);
- 	}
-+	if (fe->ops.analog_ops.release) {
-+		fe->ops.analog_ops.release(fe);
-+		symbol_put_addr(fe->ops.analog_ops.release);
-+	}
- 	ptr = (void*)fe->ops.release;
- 	if (ptr) {
- 		fe->ops.release(fe);
-@@ -1215,6 +1219,8 @@ void dvb_frontend_detach(struct dvb_frontend* fe)
- 		fe->ops.release_sec(fe);
- 	if (fe->ops.tuner_ops.release)
- 		fe->ops.tuner_ops.release(fe);
-+	if (fe->ops.analog_ops.release)
-+		fe->ops.analog_ops.release(fe);
- 	if (fe->ops.release)
- 		fe->ops.release(fe);
- }
-diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.h b/drivers/media/dvb/dvb-core/dvb_frontend.h
-index a5262e8..aa4133f 100644
---- a/drivers/media/dvb/dvb-core/dvb_frontend.h
-+++ b/drivers/media/dvb/dvb-core/dvb_frontend.h
-@@ -84,6 +84,9 @@ struct dvb_tuner_ops {
- 	/** This is support for demods like the mt352 - fills out the supplied buffer with what to write. */
- 	int (*calc_regs)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p, u8 *buf, int buf_len);
- 
-+	/** This is to allow setting tuner-specific configs */
-+	int (*set_config)(struct dvb_frontend *fe, void *priv_cfg);
 +
- 	int (*get_frequency)(struct dvb_frontend *fe, u32 *frequency);
- 	int (*get_bandwidth)(struct dvb_frontend *fe, u32 *bandwidth);
- 
-@@ -98,6 +101,28 @@ struct dvb_tuner_ops {
- 	int (*set_bandwidth)(struct dvb_frontend *fe, u32 bandwidth);
- };
- 
-+struct analog_demod_info {
-+	char *name;
-+};
++int tda18271_calc_cal_pll(struct dvb_frontend *fe, u32 freq)
++{
++	/* sets cal post divider & divider bytes, but does not write them */
++	struct tda18271_priv *priv = fe->tuner_priv;
++	unsigned char *regs = priv->tda18271_regs;
++	u8 d, pd;
++	u32 div;
 +
-+struct analog_demod_ops {
++	int ret = tda18271_lookup_pll_map(fe, CAL_PLL, &freq, &pd, &d);
++	if (ret < 0)
++		goto fail;
 +
-+	struct analog_demod_info info;
++	regs[R_CPD]   = pd;
 +
-+	void (*set_params)(struct dvb_frontend *fe,
-+			   struct analog_parameters *params);
-+	int  (*has_signal)(struct dvb_frontend *fe);
-+	int  (*is_stereo)(struct dvb_frontend *fe);
-+	int  (*get_afc)(struct dvb_frontend *fe);
-+	void (*tuner_status)(struct dvb_frontend *fe);
-+	void (*standby)(struct dvb_frontend *fe);
-+	void (*release)(struct dvb_frontend *fe);
-+	int  (*i2c_gate_ctrl)(struct dvb_frontend *fe, int enable);
++	div =  ((d * (freq / 1000)) << 7) / 125;
 +
-+	/** This is to allow setting tuner-specific configuration */
-+	int (*set_config)(struct dvb_frontend *fe, void *priv_cfg);
-+};
++	regs[R_CD1]   = 0x7f & (div >> 16);
++	regs[R_CD2]   = 0xff & (div >> 8);
++	regs[R_CD3]   = 0xff & div;
++fail:
++	return ret;
++}
 +
- struct dvb_frontend_ops {
- 
- 	struct dvb_frontend_info info;
-@@ -143,6 +168,7 @@ struct dvb_frontend_ops {
- 	int (*ts_bus_ctrl)(struct dvb_frontend* fe, int acquire);
- 
- 	struct dvb_tuner_ops tuner_ops;
-+	struct analog_demod_ops analog_ops;
- };
- 
- #define MAX_EVENT 8
-@@ -159,18 +185,19 @@ struct dvb_fe_events {
- struct dvb_frontend {
- 	struct dvb_frontend_ops ops;
- 	struct dvb_adapter *dvb;
--	void* demodulator_priv;
--	void* tuner_priv;
--	void* frontend_priv;
--	void* sec_priv;
-+	void *demodulator_priv;
-+	void *tuner_priv;
-+	void *frontend_priv;
-+	void *sec_priv;
-+	void *analog_demod_priv;
- };
- 
--extern int dvb_register_frontend(struct dvb_adapter* dvb,
--				 struct dvb_frontend* fe);
-+extern int dvb_register_frontend(struct dvb_adapter *dvb,
-+				 struct dvb_frontend *fe);
- 
--extern int dvb_unregister_frontend(struct dvb_frontend* fe);
-+extern int dvb_unregister_frontend(struct dvb_frontend *fe);
- 
--extern void dvb_frontend_detach(struct dvb_frontend* fe);
-+extern void dvb_frontend_detach(struct dvb_frontend *fe);
- 
- extern void dvb_frontend_reinitialise(struct dvb_frontend *fe);
- 
-diff --git a/drivers/media/dvb/dvb-core/dvb_ringbuffer.c b/drivers/media/dvb/dvb-core/dvb_ringbuffer.c
-index 9878183..ac9d93c 100644
---- a/drivers/media/dvb/dvb-core/dvb_ringbuffer.c
-+++ b/drivers/media/dvb/dvb-core/dvb_ringbuffer.c
-@@ -261,11 +261,6 @@ EXPORT_SYMBOL(dvb_ringbuffer_init);
- EXPORT_SYMBOL(dvb_ringbuffer_empty);
- EXPORT_SYMBOL(dvb_ringbuffer_free);
- EXPORT_SYMBOL(dvb_ringbuffer_avail);
--EXPORT_SYMBOL(dvb_ringbuffer_flush);
- EXPORT_SYMBOL(dvb_ringbuffer_flush_spinlock_wakeup);
- EXPORT_SYMBOL(dvb_ringbuffer_read);
- EXPORT_SYMBOL(dvb_ringbuffer_write);
--EXPORT_SYMBOL(dvb_ringbuffer_pkt_write);
--EXPORT_SYMBOL(dvb_ringbuffer_pkt_read);
--EXPORT_SYMBOL(dvb_ringbuffer_pkt_dispose);
--EXPORT_SYMBOL(dvb_ringbuffer_pkt_next);
-diff --git a/drivers/media/dvb/dvb-usb/af9005.c b/drivers/media/dvb/dvb-usb/af9005.c
-index 7db6eee..e7f76f5 100644
---- a/drivers/media/dvb/dvb-usb/af9005.c
-+++ b/drivers/media/dvb/dvb-usb/af9005.c
-@@ -1026,6 +1026,7 @@ static int af9005_usb_probe(struct usb_interface *intf,
- static struct usb_device_id af9005_usb_table[] = {
- 	{USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9005)},
- 	{USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_USB_XE)},
-+	{USB_DEVICE(USB_VID_ANSONIC, USB_PID_ANSONIC_DVBT_USB)},
- 	{0},
- };
- 
-@@ -1075,7 +1076,7 @@ static struct dvb_usb_device_properties af9005_properties = {
- 	.rc_key_map_size = 0,
- 	.rc_query = af9005_rc_query,
- 
--	.num_device_descs = 2,
-+	.num_device_descs = 3,
- 	.devices = {
- 		    {.name = "Afatech DVB-T USB1.1 stick",
- 		     .cold_ids = {&af9005_usb_table[0], NULL},
-@@ -1085,6 +1086,10 @@ static struct dvb_usb_device_properties af9005_properties = {
- 		     .cold_ids = {&af9005_usb_table[1], NULL},
- 		     .warm_ids = {NULL},
- 		     },
-+		    {.name = "Ansonic DVB-T USB1.1 stick",
-+		     .cold_ids = {&af9005_usb_table[2], NULL},
-+		     .warm_ids = {NULL},
-+		     },
- 		    {NULL},
- 		    }
- };
-diff --git a/drivers/media/dvb/dvb-usb/au6610.c b/drivers/media/dvb/dvb-usb/au6610.c
-index 18e0b16..f3ff813 100644
---- a/drivers/media/dvb/dvb-usb/au6610.c
-+++ b/drivers/media/dvb/dvb-usb/au6610.c
-@@ -79,12 +79,12 @@ static int au6610_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
- 	struct dvb_usb_device *d = i2c_get_adapdata(adap);
- 	int i;
- 
--	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
--		return -EAGAIN;
--
- 	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)) {
-diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/dvb/dvb-usb/cxusb.c
-index 04e31cf..c583650 100644
---- a/drivers/media/dvb/dvb-usb/cxusb.c
-+++ b/drivers/media/dvb/dvb-usb/cxusb.c
-@@ -15,7 +15,7 @@
-  *
-  * Copyright (C) 2005 Patrick Boettcher (patrick.boettcher at desy.de)
-  * Copyright (C) 2006 Michael Krufky (mkrufky at linuxtv.org)
-- * Copyright (C) 2006 Chris Pascoe (c.pascoe at itee.uq.edu.au)
-+ * Copyright (C) 2006, 2007 Chris Pascoe (c.pascoe at itee.uq.edu.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
-@@ -30,11 +30,16 @@
- #include "mt352.h"
- #include "mt352_priv.h"
- #include "zl10353.h"
-+#include "tuner-xc2028.h"
-+#include "tuner-xc2028-types.h"
- 
- /* debug */
--int dvb_usb_cxusb_debug;
-+static int dvb_usb_cxusb_debug;
- module_param_named(debug, dvb_usb_cxusb_debug, int, 0644);
- MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS);
-+#define deb_info(args...)   dprintk(dvb_usb_cxusb_debug,0x01,args)
-+#define deb_i2c(args...)    if (d->udev->descriptor.idVendor == USB_VID_MEDION) \
-+				dprintk(dvb_usb_cxusb_debug,0x01,args)
- 
- static int cxusb_ctrl_msg(struct dvb_usb_device *d,
- 			  u8 cmd, u8 *wbuf, int wlen, u8 *rbuf, int rlen)
-@@ -46,11 +51,9 @@ static int cxusb_ctrl_msg(struct dvb_usb_device *d,
- 	sndbuf[0] = cmd;
- 	memcpy(&sndbuf[1], wbuf, wlen);
- 	if (wo)
--		dvb_usb_generic_write(d, sndbuf, 1+wlen);
-+		return dvb_usb_generic_write(d, sndbuf, 1+wlen);
- 	else
--		dvb_usb_generic_rw(d, sndbuf, 1+wlen, rbuf, rlen, 0);
--
--	return 0;
-+		return dvb_usb_generic_rw(d, sndbuf, 1+wlen, rbuf, rlen, 0);
- }
- 
- /* GPIO */
-@@ -72,6 +75,34 @@ static void cxusb_gpio_tuner(struct dvb_usb_device *d, int onoff)
- 	st->gpio_write_state[GPIO_TUNER] = onoff;
- }
- 
-+static int cxusb_bluebird_gpio_rw(struct dvb_usb_device *d, u8 changemask,
-+				 u8 newval)
++int tda18271_calc_bp_filter(struct dvb_frontend *fe, u32 *freq)
 +{
-+	u8 o[2], gpio_state;
-+	int rc;
++	/* sets bp filter bits, but does not write them */
++	struct tda18271_priv *priv = fe->tuner_priv;
++	unsigned char *regs = priv->tda18271_regs;
++	u8 val;
 +
-+	o[0] = 0xff & ~changemask;	/* mask of bits to keep */
-+	o[1] = newval & changemask;	/* new values for bits  */
++	int ret = tda18271_lookup_map(fe, BP_FILTER, freq, &val);
++	if (ret < 0)
++		goto fail;
++
++	regs[R_EP1]  &= ~0x07; /* clear bp filter bits */
++	regs[R_EP1]  |= (0x07 & val);
++fail:
++	return ret;
++}
++
++int tda18271_calc_km(struct dvb_frontend *fe, u32 *freq)
++{
++	/* sets K & M bits, but does not write them */
++	struct tda18271_priv *priv = fe->tuner_priv;
++	unsigned char *regs = priv->tda18271_regs;
++	u8 val;
 +
-+	rc = cxusb_ctrl_msg(d, CMD_BLUEBIRD_GPIO_RW, o, 2, &gpio_state, 1);
-+	if (rc < 0 || (gpio_state & changemask) != (newval & changemask))
-+		deb_info("bluebird_gpio_write failed.\n");
++	int ret = tda18271_lookup_map(fe, RF_CAL_KMCO, freq, &val);
++	if (ret < 0)
++		goto fail;
 +
-+	return rc < 0 ? rc : gpio_state;
++	regs[R_EB13] &= ~0x7c; /* clear k & m bits */
++	regs[R_EB13] |= (0x7c & val);
++fail:
++	return ret;
 +}
 +
-+static void cxusb_bluebird_gpio_pulse(struct dvb_usb_device *d, u8 pin, int low)
++int tda18271_calc_rf_band(struct dvb_frontend *fe, u32 *freq)
 +{
-+	cxusb_bluebird_gpio_rw(d, pin, low ? 0 : pin);
-+	msleep(5);
-+	cxusb_bluebird_gpio_rw(d, pin, low ? pin : 0);
++	/* sets rf band bits, but does not write them */
++	struct tda18271_priv *priv = fe->tuner_priv;
++	unsigned char *regs = priv->tda18271_regs;
++	u8 val;
++
++	int ret = tda18271_lookup_map(fe, RF_BAND, freq, &val);
++	if (ret < 0)
++		goto fail;
++
++	regs[R_EP2]  &= ~0xe0; /* clear rf band bits */
++	regs[R_EP2]  |= (0xe0 & (val << 5));
++fail:
++	return ret;
 +}
 +
-+static void cxusb_nano2_led(struct dvb_usb_device *d, int onoff)
++int tda18271_calc_gain_taper(struct dvb_frontend *fe, u32 *freq)
 +{
-+	cxusb_bluebird_gpio_rw(d, 0x40, onoff ? 0 : 0x40);
++	/* sets gain taper bits, but does not write them */
++	struct tda18271_priv *priv = fe->tuner_priv;
++	unsigned char *regs = priv->tda18271_regs;
++	u8 val;
++
++	int ret = tda18271_lookup_map(fe, GAIN_TAPER, freq, &val);
++	if (ret < 0)
++		goto fail;
++
++	regs[R_EP2]  &= ~0x1f; /* clear gain taper bits */
++	regs[R_EP2]  |= (0x1f & val);
++fail:
++	return ret;
 +}
 +
- /* I2C */
- static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
- 			  int num)
-@@ -82,9 +113,6 @@ static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
- 	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
- 		return -EAGAIN;
- 
--	if (num > 2)
--		warn("more than two i2c messages at a time is not handled yet. TODO.");
--
- 	for (i = 0; i < num; i++) {
- 
- 		if (d->udev->descriptor.idVendor == USB_VID_MEDION)
-@@ -97,8 +125,22 @@ static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
- 				break;
- 			}
- 
--		/* read request */
--		if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) {
-+		if (msg[i].flags & I2C_M_RD) {
-+			/* read only */
-+			u8 obuf[3], ibuf[1+msg[i].len];
-+			obuf[0] = 0;
-+			obuf[1] = msg[i].len;
-+			obuf[2] = msg[i].addr;
-+			if (cxusb_ctrl_msg(d, CMD_I2C_READ,
-+					   obuf, 3,
-+					   ibuf, 1+msg[i].len) < 0) {
-+				warn("i2c read failed");
-+				break;
-+			}
-+			memcpy(msg[i].buf, &ibuf[1], msg[i].len);
-+		} else if (i+1 < num && (msg[i+1].flags & I2C_M_RD) &&
-+			   msg[i].addr == msg[i+1].addr) {
-+			/* write to then read from same address */
- 			u8 obuf[3+msg[i].len], ibuf[1+msg[i+1].len];
- 			obuf[0] = msg[i].len;
- 			obuf[1] = msg[i+1].len;
-@@ -116,7 +158,8 @@ static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
- 			memcpy(msg[i+1].buf, &ibuf[1], msg[i+1].len);
- 
- 			i++;
--		} else { /* write */
-+		} else {
-+			/* write only */
- 			u8 obuf[2+msg[i].len], ibuf;
- 			obuf[0] = msg[i].addr;
- 			obuf[1] = msg[i].len;
-@@ -131,7 +174,7 @@ static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
- 	}
- 
- 	mutex_unlock(&d->i2c_mutex);
--	return i;
-+	return i == num ? num : -EREMOTEIO;
- }
- 
- static u32 cxusb_i2c_func(struct i2c_adapter *adapter)
-@@ -162,6 +205,17 @@ static int cxusb_bluebird_power_ctrl(struct dvb_usb_device *d, int onoff)
- 		return 0;
- }
- 
-+static int cxusb_nano2_power_ctrl(struct dvb_usb_device *d, int onoff)
++int tda18271_calc_ir_measure(struct dvb_frontend *fe, u32 *freq)
 +{
-+	int rc = 0;
++	/* sets IR Meas bits, but does not write them */
++	struct tda18271_priv *priv = fe->tuner_priv;
++	unsigned char *regs = priv->tda18271_regs;
++	u8 val;
 +
-+	rc = cxusb_power_ctrl(d, onoff);
-+	if (!onoff)
-+		cxusb_nano2_led(d, 0);
++	int ret = tda18271_lookup_map(fe, IR_MEASURE, freq, &val);
++	if (ret < 0)
++		goto fail;
 +
-+	return rc;
++	regs[R_EP5] &= ~0x07;
++	regs[R_EP5] |= (0x07 & val);
++fail:
++	return ret;
 +}
 +
- static int cxusb_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
- {
- 	u8 buf[2] = { 0x03, 0x00 };
-@@ -197,6 +251,34 @@ static int cxusb_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
- 	return 0;
- }
- 
-+static int cxusb_bluebird2_rc_query(struct dvb_usb_device *d, u32 *event,
-+				    int *state)
++int tda18271_calc_rf_cal(struct dvb_frontend *fe, u32 *freq)
 +{
-+	struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
-+	u8 ircode[4];
-+	int i;
-+	struct i2c_msg msg = { .addr = 0x6b, .flags = I2C_M_RD,
-+			       .buf = ircode, .len = 4 };
++	/* sets rf cal byte (RFC_Cprog), but does not write it */
++	struct tda18271_priv *priv = fe->tuner_priv;
++	unsigned char *regs = priv->tda18271_regs;
++	u8 val;
 +
-+	*event = 0;
-+	*state = REMOTE_NO_KEY_PRESSED;
++	tda18271_lookup_map(fe, RF_CAL, freq, &val);
 +
-+	if (cxusb_i2c_xfer(&d->i2c_adap, &msg, 1) != 1)
-+		return 0;
++	regs[R_EB14] = val;
 +
-+	for (i = 0; i < d->props.rc_key_map_size; i++) {
-+		if (keymap[i].custom == ircode[1] &&
-+		    keymap[i].data == ircode[2]) {
-+			*event = keymap[i].event;
-+			*state = REMOTE_KEY_PRESSED;
++	return 0;
++}
 +
-+			return 0;
-+		}
-+	}
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-basic-offset: 8
++ * End:
++ */
+diff --git a/drivers/media/dvb/frontends/tda18271-fe.c b/drivers/media/dvb/frontends/tda18271-fe.c
+new file mode 100644
+index 0000000..dfe72aa
+--- /dev/null
++++ b/drivers/media/dvb/frontends/tda18271-fe.c
+@@ -0,0 +1,1225 @@
++/*
++    tda18271-fe.c - driver for the Philips / NXP TDA18271 silicon tuner
++
++    Copyright (C) 2007, 2008 Michael Krufky <mkrufky at 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.
++*/
++
++#include <linux/delay.h>
++#include <linux/videodev2.h>
++#include "tda18271-priv.h"
++
++int tda18271_debug;
++module_param_named(debug, tda18271_debug, int, 0644);
++MODULE_PARM_DESC(debug, "set debug level "
++		 "(info=1, map=2, reg=4, adv=8, cal=16 (or-able))");
++
++static int tda18271_cal_on_startup;
++module_param_named(cal, tda18271_cal_on_startup, int, 0644);
++MODULE_PARM_DESC(cal, "perform RF tracking filter calibration on startup");
++
++static LIST_HEAD(tda18271_list);
++static DEFINE_MUTEX(tda18271_list_mutex);
++
++/*---------------------------------------------------------------------*/
++
++static int tda18271_ir_cal_init(struct dvb_frontend *fe)
++{
++	struct tda18271_priv *priv = fe->tuner_priv;
++	unsigned char *regs = priv->tda18271_regs;
++
++	tda18271_read_regs(fe);
++
++	/* test IR_CAL_OK to see if we need init */
++	if ((regs[R_EP1] & 0x08) == 0)
++		tda18271_init_regs(fe);
 +
 +	return 0;
 +}
 +
- static struct dvb_usb_rc_key dvico_mce_rc_keys[] = {
- 	{ 0xfe, 0x02, KEY_TV },
- 	{ 0xfe, 0x0e, KEY_MP3 },
-@@ -351,6 +433,20 @@ static struct mt352_config cxusb_mt352_config = {
- 	.demod_init    = cxusb_mt352_demod_init,
- };
- 
-+static struct zl10353_config cxusb_zl10353_xc3028_config = {
-+	.demod_address = 0x0f,
-+	.if2 = 45600,
-+	.no_tuner = 1,
-+	.parallel_ts = 1,
-+};
-+
-+static struct mt352_config cxusb_mt352_xc3028_config = {
-+	.demod_address = 0x0f,
-+	.if2 = 4560,
-+	.no_tuner = 1,
-+	.demod_init = cxusb_mt352_demod_init,
-+};
++/* ------------------------------------------------------------------ */
 +
- /* Callbacks for DVB USB */
- static int cxusb_fmd1216me_tuner_attach(struct dvb_usb_adapter *adap)
- {
-@@ -386,6 +482,51 @@ static int cxusb_lgh064f_tuner_attach(struct dvb_usb_adapter *adap)
- 	return 0;
- }
- 
-+static int dvico_bluebird_xc2028_callback(void *ptr, int command, int arg)
++static int tda18271_channel_configuration(struct dvb_frontend *fe,
++					  u32 ifc, u32 freq, u32 bw, u8 std,
++					  int radio)
 +{
-+	struct dvb_usb_device *d = ptr;
++	struct tda18271_priv *priv = fe->tuner_priv;
++	unsigned char *regs = priv->tda18271_regs;
++	u32 N;
 +
-+	switch (command) {
-+	case XC2028_TUNER_RESET:
-+		deb_info("%s: XC2028_TUNER_RESET %d\n", __FUNCTION__, arg);
-+		cxusb_bluebird_gpio_pulse(d, 0x01, 1);
++	/* update TV broadcast parameters */
++
++	/* set standard */
++	regs[R_EP3]  &= ~0x1f; /* clear std bits */
++	regs[R_EP3]  |= std;
++
++	/* set cal mode to normal */
++	regs[R_EP4]  &= ~0x03;
++
++	/* update IF output level & IF notch frequency */
++	regs[R_EP4]  &= ~0x1c; /* clear if level bits */
++
++	switch (priv->mode) {
++	case TDA18271_ANALOG:
++		regs[R_MPD]  &= ~0x80; /* IF notch = 0 */
 +		break;
-+	case XC2028_RESET_CLK:
-+		deb_info("%s: XC2028_RESET_CLK %d\n", __FUNCTION__, arg);
++	case TDA18271_DIGITAL:
++		regs[R_EP4]  |= 0x04; /* IF level = 1 */
++		regs[R_MPD]  |= 0x80; /* IF notch = 1 */
++		break;
++	}
++
++	if (radio)
++		regs[R_EP4]  |=  0x80;
++	else
++		regs[R_EP4]  &= ~0x80;
++
++	/* update RF_TOP / IF_TOP */
++	switch (priv->mode) {
++	case TDA18271_ANALOG:
++		regs[R_EB22]  = 0x2c;
++		break;
++	case TDA18271_DIGITAL:
++		regs[R_EB22]  = 0x37;
 +		break;
-+	default:
-+		deb_info("%s: unknown command %d, arg %d\n", __FUNCTION__,
-+			 command, arg);
-+		return -EINVAL;
 +	}
++	tda18271_write_regs(fe, R_EB22, 1);
++
++	/* --------------------------------------------------------------- */
++
++	/* disable Power Level Indicator */
++	regs[R_EP1]  |= 0x40;
++
++	/* frequency dependent parameters */
++
++	tda18271_calc_ir_measure(fe, &freq);
++
++	tda18271_calc_bp_filter(fe, &freq);
++
++	tda18271_calc_rf_band(fe, &freq);
++
++	tda18271_calc_gain_taper(fe, &freq);
++
++	/* --------------------------------------------------------------- */
++
++	/* dual tuner and agc1 extra configuration */
++
++	/* main vco when Master, cal vco when slave */
++	regs[R_EB1]  |= 0x04; /* FIXME: assumes master */
++
++	/* agc1 always active */
++	regs[R_EB1]  &= ~0x02;
++
++	/* agc1 has priority on agc2 */
++	regs[R_EB1]  &= ~0x01;
++
++	tda18271_write_regs(fe, R_EB1, 1);
++
++	/* --------------------------------------------------------------- */
++
++	N = freq + ifc;
++
++	/* FIXME: assumes master */
++	tda18271_calc_main_pll(fe, N);
++	tda18271_write_regs(fe, R_MPD, 4);
++
++	tda18271_write_regs(fe, R_TM, 7);
++
++	/* main pll charge pump source */
++	regs[R_EB4] |= 0x20;
++	tda18271_write_regs(fe, R_EB4, 1);
++
++	msleep(1);
++
++	/* normal operation for the main pll */
++	regs[R_EB4] &= ~0x20;
++	tda18271_write_regs(fe, R_EB4, 1);
++
++	msleep(5);
 +
 +	return 0;
 +}
 +
-+static int cxusb_dvico_xc3028_tuner_attach(struct dvb_usb_adapter *adap)
++static int tda18271_read_thermometer(struct dvb_frontend *fe)
 +{
-+	struct dvb_frontend	 *fe;
-+	struct xc2028_config	  cfg = {
-+		.i2c_adap  = &adap->dev->i2c_adap,
-+		.i2c_addr  = 0x61,
-+		.video_dev = adap->dev,
-+		.callback  = dvico_bluebird_xc2028_callback,
-+	};
-+	static struct xc2028_ctrl ctl = {
-+		.fname       = "xc3028-dvico-au-01.fw",
-+		.max_len     = 64,
-+		.scode_table = ZARLINK456,
-+	};
++	struct tda18271_priv *priv = fe->tuner_priv;
++	unsigned char *regs = priv->tda18271_regs;
++	int tm;
 +
-+	fe = dvb_attach(xc2028_attach, adap->fe, &cfg);
-+	if (fe == NULL || fe->ops.tuner_ops.set_config == NULL)
-+		return -EIO;
++	/* switch thermometer on */
++	regs[R_TM]   |= 0x10;
++	tda18271_write_regs(fe, R_TM, 1);
 +
-+	fe->ops.tuner_ops.set_config(fe, &ctl);
++	/* read thermometer info */
++	tda18271_read_regs(fe);
 +
-+	return 0;
++	if ((((regs[R_TM] & 0x0f) == 0x00) && ((regs[R_TM] & 0x20) == 0x20)) ||
++	    (((regs[R_TM] & 0x0f) == 0x08) && ((regs[R_TM] & 0x20) == 0x00))) {
++
++		if ((regs[R_TM] & 0x20) == 0x20)
++			regs[R_TM] &= ~0x20;
++		else
++			regs[R_TM] |= 0x20;
++
++		tda18271_write_regs(fe, R_TM, 1);
++
++		msleep(10); /* temperature sensing */
++
++		/* read thermometer info */
++		tda18271_read_regs(fe);
++	}
++
++	tm = tda18271_lookup_thermometer(fe);
++
++	/* switch thermometer off */
++	regs[R_TM]   &= ~0x10;
++	tda18271_write_regs(fe, R_TM, 1);
++
++	/* set CAL mode to normal */
++	regs[R_EP4]  &= ~0x03;
++	tda18271_write_regs(fe, R_EP4, 1);
++
++	return tm;
 +}
 +
- static int cxusb_cx22702_frontend_attach(struct dvb_usb_adapter *adap)
- {
- 	u8 b;
-@@ -447,27 +588,120 @@ static int cxusb_dee1601_frontend_attach(struct dvb_usb_adapter *adap)
- 	return -EIO;
- }
- 
-+static int cxusb_dualdig4_frontend_attach(struct dvb_usb_adapter *adap)
++static int tda18271_rf_tracking_filters_correction(struct dvb_frontend *fe,
++						   u32 freq)
 +{
-+	u8 ircode[4];
-+	int i;
-+	struct i2c_msg msg = { .addr = 0x6b, .flags = I2C_M_RD,
-+			       .buf = ircode, .len = 4 };
++	struct tda18271_priv *priv = fe->tuner_priv;
++	struct tda18271_rf_tracking_filter_cal *map = priv->rf_cal_state;
++	unsigned char *regs = priv->tda18271_regs;
++	int tm_current, rfcal_comp, approx, i;
++	u8 dc_over_dt, rf_tab;
 +
-+	if (usb_set_interface(adap->dev->udev, 0, 1) < 0)
-+		err("set interface failed");
++	/* power up */
++	tda18271_set_standby_mode(fe, 0, 0, 0);
 +
-+	cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0);
++	/* read die current temperature */
++	tm_current = tda18271_read_thermometer(fe);
 +
-+	/* reset the tuner and demodulator */
-+	cxusb_bluebird_gpio_rw(adap->dev, 0x04, 0);
-+	cxusb_bluebird_gpio_pulse(adap->dev, 0x01, 1);
-+	cxusb_bluebird_gpio_pulse(adap->dev, 0x02, 1);
++	/* frequency dependent parameters */
 +
-+	if ((adap->fe = dvb_attach(zl10353_attach,
-+				   &cxusb_zl10353_xc3028_config,
-+				   &adap->dev->i2c_adap)) == NULL)
-+		return -EIO;
++	tda18271_calc_rf_cal(fe, &freq);
++	rf_tab = regs[R_EB14];
 +
-+	/* try to determine if there is no IR decoder on the I2C bus */
-+	for (i = 0; adap->dev->props.rc_key_map != NULL && i < 5; i++) {
-+		msleep(20);
-+		if (cxusb_i2c_xfer(&adap->dev->i2c_adap, &msg, 1) != 1)
-+			goto no_IR;
-+		if (ircode[0] == 0 && ircode[1] == 0)
-+			continue;
-+		if (ircode[2] + ircode[3] != 0xff) {
-+no_IR:
-+			adap->dev->props.rc_key_map = NULL;
-+			info("No IR receiver detected on this device.");
-+			break;
-+		}
++	i = tda18271_lookup_rf_band(fe, &freq, NULL);
++	if (i < 0)
++		return -EINVAL;
++
++	if ((0 == map[i].rf3) || (freq / 1000 < map[i].rf2)) {
++		approx = map[i].rf_a1 *
++			(freq / 1000 - map[i].rf1) + map[i].rf_b1 + rf_tab;
++	} else {
++		approx = map[i].rf_a2 *
++			(freq / 1000 - map[i].rf2) + map[i].rf_b2 + rf_tab;
 +	}
 +
++	if (approx < 0)
++		approx = 0;
++	if (approx > 255)
++		approx = 255;
++
++	tda18271_lookup_map(fe, RF_CAL_DC_OVER_DT, &freq, &dc_over_dt);
++
++	/* calculate temperature compensation */
++	rfcal_comp = dc_over_dt * (tm_current - priv->tm_rfcal);
++
++	regs[R_EB14] = approx + rfcal_comp;
++	tda18271_write_regs(fe, R_EB14, 1);
++
 +	return 0;
 +}
 +
-+static int cxusb_nano2_frontend_attach(struct dvb_usb_adapter *adap)
++static int tda18271_por(struct dvb_frontend *fe)
 +{
-+	if (usb_set_interface(adap->dev->udev, 0, 1) < 0)
-+		err("set interface failed");
++	struct tda18271_priv *priv = fe->tuner_priv;
++	unsigned char *regs = priv->tda18271_regs;
 +
-+	cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0);
++	/* power up detector 1 */
++	regs[R_EB12] &= ~0x20;
++	tda18271_write_regs(fe, R_EB12, 1);
 +
-+	/* reset the tuner and demodulator */
-+	cxusb_bluebird_gpio_rw(adap->dev, 0x04, 0);
-+	cxusb_bluebird_gpio_pulse(adap->dev, 0x01, 1);
-+	cxusb_bluebird_gpio_pulse(adap->dev, 0x02, 1);
++	regs[R_EB18] &= ~0x80; /* turn agc1 loop on */
++	regs[R_EB18] &= ~0x03; /* set agc1_gain to  6 dB */
++	tda18271_write_regs(fe, R_EB18, 1);
 +
-+	if ((adap->fe = dvb_attach(zl10353_attach,
-+				   &cxusb_zl10353_xc3028_config,
-+				   &adap->dev->i2c_adap)) != NULL)
-+		return 0;
++	regs[R_EB21] |= 0x03; /* set agc2_gain to -6 dB */
 +
-+	if ((adap->fe = dvb_attach(mt352_attach,
-+				   &cxusb_mt352_xc3028_config,
-+				   &adap->dev->i2c_adap)) != NULL)
-+		return 0;
++	/* POR mode */
++	tda18271_set_standby_mode(fe, 1, 0, 0);
 +
-+	return -EIO;
++	/* disable 1.5 MHz low pass filter */
++	regs[R_EB23] &= ~0x04; /* forcelp_fc2_en = 0 */
++	regs[R_EB23] &= ~0x02; /* XXX: lp_fc[2] = 0 */
++	tda18271_write_regs(fe, R_EB21, 3);
++
++	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
-+ * have non-default values to decide whether the device is actually cold or
-+ * not, and forget a match if it turns out we selected the wrong device.
-+ */
-+static int bluebird_fx2_identify_state(struct usb_device *udev,
-+				       struct dvb_usb_device_properties *props,
-+				       struct dvb_usb_device_description **desc,
-+				       int *cold)
++static int tda18271_calibrate_rf(struct dvb_frontend *fe, u32 freq)
 +{
-+	int wascold = *cold;
++	struct tda18271_priv *priv = fe->tuner_priv;
++	unsigned char *regs = priv->tda18271_regs;
++	u32 N;
 +
-+	*cold = udev->descriptor.bDeviceClass == 0xff &&
-+		udev->descriptor.bDeviceSubClass == 0xff &&
-+		udev->descriptor.bDeviceProtocol == 0xff;
++	/* set CAL mode to normal */
++	regs[R_EP4]  &= ~0x03;
++	tda18271_write_regs(fe, R_EP4, 1);
 +
-+	if (*cold && !wascold)
-+		*desc = NULL;
++	/* switch off agc1 */
++	regs[R_EP3]  |= 0x40; /* sm_lt = 1 */
 +
-+	return 0;
++	regs[R_EB18] |= 0x03; /* set agc1_gain to 15 dB */
++	tda18271_write_regs(fe, R_EB18, 1);
++
++	/* frequency dependent parameters */
++
++	tda18271_calc_bp_filter(fe, &freq);
++	tda18271_calc_gain_taper(fe, &freq);
++	tda18271_calc_rf_band(fe, &freq);
++	tda18271_calc_km(fe, &freq);
++
++	tda18271_write_regs(fe, R_EP1, 3);
++	tda18271_write_regs(fe, R_EB13, 1);
++
++	/* main pll charge pump source */
++	regs[R_EB4]  |= 0x20;
++	tda18271_write_regs(fe, R_EB4, 1);
++
++	/* cal pll charge pump source */
++	regs[R_EB7]  |= 0x20;
++	tda18271_write_regs(fe, R_EB7, 1);
++
++	/* force dcdc converter to 0 V */
++	regs[R_EB14] = 0x00;
++	tda18271_write_regs(fe, R_EB14, 1);
++
++	/* disable plls lock */
++	regs[R_EB20] &= ~0x20;
++	tda18271_write_regs(fe, R_EB20, 1);
++
++	/* set CAL mode to RF tracking filter calibration */
++	regs[R_EP4]  |= 0x03;
++	tda18271_write_regs(fe, R_EP4, 2);
++
++	/* --------------------------------------------------------------- */
++
++	/* set the internal calibration signal */
++	N = freq;
++
++	tda18271_calc_main_pll(fe, N);
++	tda18271_write_regs(fe, R_MPD, 4);
++
++	/* downconvert internal calibration */
++	N += 1000000;
++
++	tda18271_calc_main_pll(fe, N);
++	tda18271_write_regs(fe, R_MPD, 4);
++
++	msleep(5);
++
++	tda18271_write_regs(fe, R_EP2, 1);
++	tda18271_write_regs(fe, R_EP1, 1);
++	tda18271_write_regs(fe, R_EP2, 1);
++	tda18271_write_regs(fe, R_EP1, 1);
++
++	/* --------------------------------------------------------------- */
++
++	/* normal operation for the main pll */
++	regs[R_EB4] &= ~0x20;
++	tda18271_write_regs(fe, R_EB4, 1);
++
++	/* normal operation for the cal pll  */
++	regs[R_EB7] &= ~0x20;
++	tda18271_write_regs(fe, R_EB7, 1);
++
++	msleep(5); /* plls locking */
++
++	/* launch the rf tracking filters calibration */
++	regs[R_EB20]  |= 0x20;
++	tda18271_write_regs(fe, R_EB20, 1);
++
++	msleep(60); /* calibration */
++
++	/* --------------------------------------------------------------- */
++
++	/* set CAL mode to normal */
++	regs[R_EP4]  &= ~0x03;
++
++	/* switch on agc1 */
++	regs[R_EP3]  &= ~0x40; /* sm_lt = 0 */
++
++	regs[R_EB18] &= ~0x03; /* set agc1_gain to  6 dB */
++	tda18271_write_regs(fe, R_EB18, 1);
++
++	tda18271_write_regs(fe, R_EP3, 2);
++
++	/* synchronization */
++	tda18271_write_regs(fe, R_EP1, 1);
++
++	/* get calibration result */
++	tda18271_read_extended(fe);
++
++	return regs[R_EB14];
 +}
 +
- /*
-  * DViCO bluebird firmware needs the "warm" product ID to be patched into the
-  * firmware file before download.
-  */
- 
--#define BLUEBIRD_01_ID_OFFSET 6638
-+static const int dvico_firmware_id_offsets[] = { 6638, 3204 };
- static int bluebird_patch_dvico_firmware_download(struct usb_device *udev,
- 						  const struct firmware *fw)
- {
--	if (fw->size < BLUEBIRD_01_ID_OFFSET + 4)
--		return -EINVAL;
-+	int pos;
++static int tda18271_powerscan(struct dvb_frontend *fe,
++			      u32 *freq_in, u32 *freq_out)
++{
++	struct tda18271_priv *priv = fe->tuner_priv;
++	unsigned char *regs = priv->tda18271_regs;
++	int sgn, bcal, count, wait;
++	u8 cid_target;
++	u16 count_limit;
++	u32 freq;
 +
-+	for (pos = 0; pos < ARRAY_SIZE(dvico_firmware_id_offsets); pos++) {
-+		int idoff = dvico_firmware_id_offsets[pos];
- 
--	if (fw->data[BLUEBIRD_01_ID_OFFSET] == (USB_VID_DVICO & 0xff) &&
--	    fw->data[BLUEBIRD_01_ID_OFFSET + 1] == USB_VID_DVICO >> 8) {
-+		if (fw->size < idoff + 4)
-+			continue;
- 
--		fw->data[BLUEBIRD_01_ID_OFFSET + 2] =
--			le16_to_cpu(udev->descriptor.idProduct) + 1;
--		fw->data[BLUEBIRD_01_ID_OFFSET + 3] =
--			le16_to_cpu(udev->descriptor.idProduct) >> 8;
-+		if (fw->data[idoff] == (USB_VID_DVICO & 0xff) &&
-+		    fw->data[idoff + 1] == USB_VID_DVICO >> 8) {
-+			fw->data[idoff + 2] =
-+				le16_to_cpu(udev->descriptor.idProduct) + 1;
-+			fw->data[idoff + 3] =
-+				le16_to_cpu(udev->descriptor.idProduct) >> 8;
- 
--		return usb_cypress_load_firmware(udev, fw, CYPRESS_FX2);
-+			return usb_cypress_load_firmware(udev, fw, CYPRESS_FX2);
-+		}
- 	}
- 
- 	return -EINVAL;
-@@ -479,6 +713,9 @@ static struct dvb_usb_device_properties cxusb_bluebird_lgh064f_properties;
- static struct dvb_usb_device_properties cxusb_bluebird_dee1601_properties;
- 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_nano2_properties;
-+static struct dvb_usb_device_properties cxusb_bluebird_nano2_needsfirmware_properties;
- 
- static int cxusb_probe(struct usb_interface *intf,
- 		       const struct usb_device_id *id)
-@@ -487,7 +724,10 @@ static int cxusb_probe(struct usb_interface *intf,
- 		dvb_usb_device_init(intf,&cxusb_bluebird_lgh064f_properties,THIS_MODULE,NULL) == 0 ||
- 		dvb_usb_device_init(intf,&cxusb_bluebird_dee1601_properties,THIS_MODULE,NULL) == 0 ||
- 		dvb_usb_device_init(intf,&cxusb_bluebird_lgz201_properties,THIS_MODULE,NULL) == 0 ||
--		dvb_usb_device_init(intf,&cxusb_bluebird_dtt7579_properties,THIS_MODULE,NULL) == 0) {
-+		dvb_usb_device_init(intf,&cxusb_bluebird_dtt7579_properties,THIS_MODULE,NULL) == 0 ||
-+		dvb_usb_device_init(intf,&cxusb_bluebird_dualdig4_properties,THIS_MODULE,NULL) == 0 ||
-+		dvb_usb_device_init(intf,&cxusb_bluebird_nano2_properties,THIS_MODULE,NULL) == 0 ||
-+		dvb_usb_device_init(intf,&cxusb_bluebird_nano2_needsfirmware_properties,THIS_MODULE,NULL) == 0) {
- 		return 0;
- 	}
- 
-@@ -508,6 +748,9 @@ static struct usb_device_id cxusb_table [] = {
- 	{ USB_DEVICE(USB_VID_DVICO, USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_WARM) },
- 	{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_2_COLD) },
- 	{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_2_WARM) },
-+	{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_4) },
-+	{ 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) },
- 	{}		/* Terminating entry */
- };
- MODULE_DEVICE_TABLE (usb, cxusb_table);
-@@ -766,6 +1009,151 @@ static struct dvb_usb_device_properties cxusb_bluebird_dtt7579_properties = {
- 	}
- };
- 
-+static struct dvb_usb_device_properties cxusb_bluebird_dualdig4_properties = {
-+	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
++	freq = *freq_in;
 +
-+	.usb_ctrl         = CYPRESS_FX2,
++	tda18271_calc_rf_band(fe, &freq);
++	tda18271_calc_rf_cal(fe, &freq);
++	tda18271_calc_gain_taper(fe, &freq);
++	tda18271_lookup_cid_target(fe, &freq, &cid_target, &count_limit);
 +
-+	.size_of_priv     = sizeof(struct cxusb_state),
++	tda18271_write_regs(fe, R_EP2, 1);
++	tda18271_write_regs(fe, R_EB14, 1);
 +
-+	.num_adapters = 1,
-+	.adapter = {
-+		{
-+			.streaming_ctrl   = cxusb_streaming_ctrl,
-+			.frontend_attach  = cxusb_dualdig4_frontend_attach,
-+			.tuner_attach     = cxusb_dvico_xc3028_tuner_attach,
-+			/* parameter for the MPEG2-data transfer */
-+			.stream = {
-+				.type = USB_BULK,
-+				.count = 5,
-+				.endpoint = 0x02,
-+				.u = {
-+					.bulk = {
-+						.buffersize = 8192,
-+					}
-+				}
-+			},
-+		},
-+	},
++	/* downconvert frequency */
++	freq += 1000000;
 +
-+	.power_ctrl       = cxusb_power_ctrl,
++	tda18271_calc_main_pll(fe, freq);
++	tda18271_write_regs(fe, R_MPD, 4);
 +
-+	.i2c_algo         = &cxusb_i2c_algo,
++	msleep(5); /* pll locking */
 +
-+	.generic_bulk_ctrl_endpoint = 0x01,
++	/* detection mode */
++	regs[R_EP4]  &= ~0x03;
++	regs[R_EP4]  |= 0x01;
++	tda18271_write_regs(fe, R_EP4, 1);
 +
-+	.rc_interval      = 100,
-+	.rc_key_map       = dvico_mce_rc_keys,
-+	.rc_key_map_size  = ARRAY_SIZE(dvico_mce_rc_keys),
-+	.rc_query         = cxusb_bluebird2_rc_query,
++	/* launch power detection measurement */
++	tda18271_write_regs(fe, R_EP2, 1);
 +
-+	.num_device_descs = 1,
-+	.devices = {
-+		{   "DViCO FusionHDTV DVB-T Dual Digital 4",
-+			{ NULL },
-+			{ &cxusb_table[13], NULL },
-+		},
-+	}
-+};
++	/* read power detection info, stored in EB10 */
++	tda18271_read_extended(fe);
 +
-+static struct dvb_usb_device_properties cxusb_bluebird_nano2_properties = {
-+	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
++	/* algorithm initialization */
++	sgn = 1;
++	*freq_out = *freq_in;
++	bcal = 0;
++	count = 0;
++	wait = false;
 +
-+	.usb_ctrl         = CYPRESS_FX2,
-+	.identify_state   = bluebird_fx2_identify_state,
++	while ((regs[R_EB10] & 0x3f) < cid_target) {
++		/* downconvert updated freq to 1 MHz */
++		freq = *freq_in + (sgn * count) + 1000000;
 +
-+	.size_of_priv     = sizeof(struct cxusb_state),
++		tda18271_calc_main_pll(fe, freq);
++		tda18271_write_regs(fe, R_MPD, 4);
 +
-+	.num_adapters = 1,
-+	.adapter = {
-+		{
-+			.streaming_ctrl   = cxusb_streaming_ctrl,
-+			.frontend_attach  = cxusb_nano2_frontend_attach,
-+			.tuner_attach     = cxusb_dvico_xc3028_tuner_attach,
-+			/* parameter for the MPEG2-data transfer */
-+			.stream = {
-+				.type = USB_BULK,
-+				.count = 5,
-+				.endpoint = 0x02,
-+				.u = {
-+					.bulk = {
-+						.buffersize = 8192,
-+					}
-+				}
-+			},
-+		},
-+	},
++		if (wait) {
++			msleep(5); /* pll locking */
++			wait = false;
++		} else
++			udelay(100); /* pll locking */
 +
-+	.power_ctrl       = cxusb_nano2_power_ctrl,
++		/* launch power detection measurement */
++		tda18271_write_regs(fe, R_EP2, 1);
 +
-+	.i2c_algo         = &cxusb_i2c_algo,
++		/* read power detection info, stored in EB10 */
++		tda18271_read_extended(fe);
 +
-+	.generic_bulk_ctrl_endpoint = 0x01,
++		count += 200;
 +
-+	.rc_interval      = 100,
-+	.rc_key_map       = dvico_portable_rc_keys,
-+	.rc_key_map_size  = ARRAY_SIZE(dvico_portable_rc_keys),
-+	.rc_query         = cxusb_bluebird2_rc_query,
++		if (count < count_limit)
++			continue;
 +
-+	.num_device_descs = 1,
-+	.devices = {
-+		{   "DViCO FusionHDTV DVB-T NANO2",
-+			{ NULL },
-+			{ &cxusb_table[14], NULL },
-+		},
++		if (sgn <= 0)
++			break;
++
++		sgn = -1 * sgn;
++		count = 200;
++		wait = true;
 +	}
-+};
 +
-+static struct dvb_usb_device_properties cxusb_bluebird_nano2_needsfirmware_properties = {
-+	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
++	if ((regs[R_EB10] & 0x3f) >= cid_target) {
++		bcal = 1;
++		*freq_out = freq - 1000000;
++	} else
++		bcal = 0;
 +
-+	.usb_ctrl          = DEVICE_SPECIFIC,
-+	.firmware          = "dvb-usb-bluebird-02.fw",
-+	.download_firmware = bluebird_patch_dvico_firmware_download,
-+	.identify_state    = bluebird_fx2_identify_state,
++	tda_cal("bcal = %d, freq_in = %d, freq_out = %d (freq = %d)\n",
++		bcal, *freq_in, *freq_out, freq);
 +
-+	.size_of_priv      = sizeof(struct cxusb_state),
++	return bcal;
++}
 +
-+	.num_adapters = 1,
-+	.adapter = {
-+		{
-+			.streaming_ctrl   = cxusb_streaming_ctrl,
-+			.frontend_attach  = cxusb_nano2_frontend_attach,
-+			.tuner_attach     = cxusb_dvico_xc3028_tuner_attach,
-+			/* parameter for the MPEG2-data transfer */
-+			.stream = {
-+				.type = USB_BULK,
-+				.count = 5,
-+				.endpoint = 0x02,
-+				.u = {
-+					.bulk = {
-+						.buffersize = 8192,
-+					}
-+				}
-+			},
-+		},
-+	},
++static int tda18271_powerscan_init(struct dvb_frontend *fe)
++{
++	struct tda18271_priv *priv = fe->tuner_priv;
++	unsigned char *regs = priv->tda18271_regs;
 +
-+	.power_ctrl       = cxusb_nano2_power_ctrl,
++	/* set standard to digital */
++	regs[R_EP3]  &= ~0x1f; /* clear std bits */
++	regs[R_EP3]  |= 0x12;
 +
-+	.i2c_algo         = &cxusb_i2c_algo,
++	/* set cal mode to normal */
++	regs[R_EP4]  &= ~0x03;
 +
-+	.generic_bulk_ctrl_endpoint = 0x01,
++	/* update IF output level & IF notch frequency */
++	regs[R_EP4]  &= ~0x1c; /* clear if level bits */
 +
-+	.rc_interval      = 100,
-+	.rc_key_map       = dvico_portable_rc_keys,
-+	.rc_key_map_size  = ARRAY_SIZE(dvico_portable_rc_keys),
-+	.rc_query         = cxusb_rc_query,
++	tda18271_write_regs(fe, R_EP3, 2);
 +
-+	.num_device_descs = 1,
-+	.devices = {
-+		{   "DViCO FusionHDTV DVB-T NANO2 w/o firmware",
-+			{ &cxusb_table[14], NULL },
-+			{ &cxusb_table[15], NULL },
-+		},
-+	}
-+};
++	regs[R_EB18] &= ~0x03; /* set agc1_gain to   6 dB */
++	tda18271_write_regs(fe, R_EB18, 1);
 +
- static struct usb_driver cxusb_driver = {
- 	.name		= "dvb_usb_cxusb",
- 	.probe		= cxusb_probe,
-diff --git a/drivers/media/dvb/dvb-usb/cxusb.h b/drivers/media/dvb/dvb-usb/cxusb.h
-index c8ef775..4768a2c 100644
---- a/drivers/media/dvb/dvb-usb/cxusb.h
-+++ b/drivers/media/dvb/dvb-usb/cxusb.h
-@@ -4,12 +4,9 @@
- #define DVB_USB_LOG_PREFIX "cxusb"
- #include "dvb-usb.h"
- 
--extern int dvb_usb_cxusb_debug;
--#define deb_info(args...)   dprintk(dvb_usb_cxusb_debug,0x01,args)
--#define deb_i2c(args...)    if (d->udev->descriptor.idVendor == USB_VID_MEDION) \
--				dprintk(dvb_usb_cxusb_debug,0x01,args)
--
- /* usb commands - some of it are guesses, don't have a reference yet */
-+#define CMD_BLUEBIRD_GPIO_RW 0x05
++	regs[R_EB21] &= ~0x03; /* set agc2_gain to -15 dB */
 +
- #define CMD_I2C_WRITE     0x08
- #define CMD_I2C_READ      0x09
- 
-diff --git a/drivers/media/dvb/dvb-usb/dib0700_core.c b/drivers/media/dvb/dvb-usb/dib0700_core.c
-index 3ea294e..c9857d5 100644
---- a/drivers/media/dvb/dvb-usb/dib0700_core.c
-+++ b/drivers/media/dvb/dvb-usb/dib0700_core.c
-@@ -243,7 +243,7 @@ int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
- 	u8 b[4];
- 
- 	b[0] = REQUEST_ENABLE_VIDEO;
--	b[1] = 0x00;
-+	b[1] = (onoff << 4) | 0x00; /* this bit gives a kind of command, rather than enabling something or not */
- 	b[2] = (0x01 << 4); /* Master mode */
- 	b[3] = 0x00;
- 
-@@ -256,9 +256,6 @@ int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
- 
- 	b[2] |= st->channel_state;
- 
--	if (st->channel_state) /* if at least one channel is active */
--		b[1] = (0x01 << 4) | 0x00;
--
- 	deb_info("data for streaming: %x %x\n",b[1],b[2]);
- 
- 	return dib0700_ctrl_wr(adap->dev, b, 4);
-diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c
-index 58452b5..e709382 100644
---- a/drivers/media/dvb/dvb-usb/dib0700_devices.c
-+++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c
-@@ -94,12 +94,28 @@ static int bristol_frontend_attach(struct dvb_usb_adapter *adap)
- 		(10 + adap->id) << 1, &bristol_dib3000mc_config[adap->id])) == NULL ? -ENODEV : 0;
- }
- 
-+static int eeprom_read(struct i2c_adapter *adap,u8 adrs,u8 *pval)
++	/* 1.5 MHz low pass filter */
++	regs[R_EB23] |= 0x04; /* forcelp_fc2_en = 1 */
++	regs[R_EB23] |= 0x02; /* lp_fc[2] = 1 */
++
++	tda18271_write_regs(fe, R_EB21, 3);
++
++	return 0;
++}
++
++static int tda18271_rf_tracking_filters_init(struct dvb_frontend *fe, u32 freq)
 +{
-+	struct i2c_msg msg[2] = {
-+		{ .addr = 0x50, .flags = 0,        .buf = &adrs, .len = 1 },
-+		{ .addr = 0x50, .flags = I2C_M_RD, .buf = pval,  .len = 1 },
-+	};
-+	if (i2c_transfer(adap, msg, 2) != 2) return -EREMOTEIO;
++	struct tda18271_priv *priv = fe->tuner_priv;
++	struct tda18271_rf_tracking_filter_cal *map = priv->rf_cal_state;
++	unsigned char *regs = priv->tda18271_regs;
++	int bcal, rf, i;
++#define RF1 0
++#define RF2 1
++#define RF3 2
++	u32 rf_default[3];
++	u32 rf_freq[3];
++	u8 prog_cal[3];
++	u8 prog_tab[3];
++
++	i = tda18271_lookup_rf_band(fe, &freq, NULL);
++
++	if (i < 0)
++		return i;
++
++	rf_default[RF1] = 1000 * map[i].rf1_def;
++	rf_default[RF2] = 1000 * map[i].rf2_def;
++	rf_default[RF3] = 1000 * map[i].rf3_def;
++
++	for (rf = RF1; rf <= RF3; rf++) {
++		if (0 == rf_default[rf])
++			return 0;
++		tda_cal("freq = %d, rf = %d\n", freq, rf);
++
++		/* look for optimized calibration frequency */
++		bcal = tda18271_powerscan(fe, &rf_default[rf], &rf_freq[rf]);
++
++		tda18271_calc_rf_cal(fe, &rf_freq[rf]);
++		prog_tab[rf] = regs[R_EB14];
++
++		if (1 == bcal)
++			prog_cal[rf] = tda18271_calibrate_rf(fe, rf_freq[rf]);
++		else
++			prog_cal[rf] = prog_tab[rf];
++
++		switch (rf) {
++		case RF1:
++			map[i].rf_a1 = 0;
++			map[i].rf_b1 = prog_cal[RF1] - prog_tab[RF1];
++			map[i].rf1   = rf_freq[RF1] / 1000;
++			break;
++		case RF2:
++			map[i].rf_a1 = (prog_cal[RF2] - prog_tab[RF2] -
++					prog_cal[RF1] + prog_tab[RF1]) /
++				((rf_freq[RF2] - rf_freq[RF1]) / 1000);
++			map[i].rf2   = rf_freq[RF2] / 1000;
++			break;
++		case RF3:
++			map[i].rf_a2 = (prog_cal[RF3] - prog_tab[RF3] -
++					prog_cal[RF2] + prog_tab[RF2]) /
++				((rf_freq[RF3] - rf_freq[RF2]) / 1000);
++			map[i].rf_b2 = prog_cal[RF2] - prog_tab[RF2];
++			map[i].rf3   = rf_freq[RF3] / 1000;
++			break;
++		default:
++			BUG();
++		}
++	}
++
 +	return 0;
 +}
 +
- static int bristol_tuner_attach(struct dvb_usb_adapter *adap)
- {
--	struct dib0700_state *st = adap->dev->priv;
-+	struct i2c_adapter *prim_i2c = &adap->dev->i2c_adap;
- 	struct i2c_adapter *tun_i2c = dib3000mc_get_tuner_i2c_master(adap->fe, 1);
--	return dvb_attach(mt2060_attach,adap->fe, tun_i2c, &bristol_mt2060_config[adap->id],
--		st->mt2060_if1[adap->id]) == NULL ? -ENODEV : 0;
-+	s8 a;
-+	int if1=1220;
-+	if (adap->dev->udev->descriptor.idVendor  == USB_VID_HAUPPAUGE &&
-+		adap->dev->udev->descriptor.idProduct == USB_PID_HAUPPAUGE_NOVA_T_500_2) {
-+		if (!eeprom_read(prim_i2c,0x59 + adap->id,&a)) if1=1220+a;
-+	}
-+	return dvb_attach(mt2060_attach,adap->fe, tun_i2c,&bristol_mt2060_config[adap->id],
-+		if1) == NULL ? -ENODEV : 0;
- }
- 
- /* STK7700D: Pinnacle/Terratec/Hauppauge Dual DVB-T Diversity */
-@@ -230,6 +246,27 @@ static struct mt2266_config stk7700d_mt2266_config[2] = {
- 	}
- };
- 
-+static int stk7700P2_frontend_attach(struct dvb_usb_adapter *adap)
++static int tda18271_calc_rf_filter_curve(struct dvb_frontend *fe)
 +{
-+	if (adap->id == 0) {
-+		dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
-+		msleep(10);
-+		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, GPIO10, GPIO_OUT, 0);
-+		msleep(10);
-+		dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
-+		msleep(10);
-+		dib7000p_i2c_enumeration(&adap->dev->i2c_adap,1,18,stk7700d_dib7000p_mt2266_config);
-+	}
++	struct tda18271_priv *priv = fe->tuner_priv;
++	unsigned int i;
 +
-+	adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap,0x80+(adap->id << 1),
-+				&stk7700d_dib7000p_mt2266_config[adap->id]);
++	tda_info("tda18271: performing RF tracking filter calibration\n");
 +
-+	return adap->fe == NULL ? -ENODEV : 0;
++	/* wait for die temperature stabilization */
++	msleep(200);
++
++	tda18271_powerscan_init(fe);
++
++	/* rf band calibration */
++	for (i = 0; priv->rf_cal_state[i].rfmax != 0; i++)
++		tda18271_rf_tracking_filters_init(fe, 1000 *
++						  priv->rf_cal_state[i].rfmax);
++
++	priv->tm_rfcal = tda18271_read_thermometer(fe);
++
++	return 0;
 +}
 +
- static int stk7700d_frontend_attach(struct dvb_usb_adapter *adap)
- {
- 	if (adap->id == 0) {
-@@ -415,6 +452,35 @@ static struct dvb_usb_rc_key dib0700_rc_keys[] = {
- 	{ 0x1e, 0x38, KEY_YELLOW },
- 	{ 0x1e, 0x3b, KEY_GOTO },
- 	{ 0x1e, 0x3d, KEY_POWER },
++/* ------------------------------------------------------------------ */
 +
-+	/* Key codes for the Leadtek Winfast DTV Dongle */
-+	{ 0x00, 0x42, KEY_POWER },
-+	{ 0x07, 0x7c, KEY_TUNER },
-+	{ 0x0f, 0x4e, KEY_PRINT }, /* PREVIEW */
-+	{ 0x08, 0x40, KEY_SCREEN }, /* full screen toggle*/
-+	{ 0x0f, 0x71, KEY_DOT }, /* frequency */
-+	{ 0x07, 0x43, KEY_0 },
-+	{ 0x0c, 0x41, KEY_1 },
-+	{ 0x04, 0x43, KEY_2 },
-+	{ 0x0b, 0x7f, KEY_3 },
-+	{ 0x0e, 0x41, KEY_4 },
-+	{ 0x06, 0x43, KEY_5 },
-+	{ 0x09, 0x7f, KEY_6 },
-+	{ 0x0d, 0x7e, KEY_7 },
-+	{ 0x05, 0x7c, KEY_8 },
-+	{ 0x0a, 0x40, KEY_9 },
-+	{ 0x0e, 0x4e, KEY_CLEAR },
-+	{ 0x04, 0x7c, KEY_CHANNEL }, /* show channel number */
-+	{ 0x0f, 0x41, KEY_LAST }, /* recall */
-+	{ 0x03, 0x42, KEY_MUTE },
-+	{ 0x06, 0x4c, KEY_RESERVED }, /* PIP button*/
-+	{ 0x01, 0x72, KEY_SHUFFLE }, /* SNAPSHOT */
-+	{ 0x0c, 0x4e, KEY_PLAYPAUSE }, /* TIMESHIFT */
-+	{ 0x0b, 0x70, KEY_RECORD },
-+	{ 0x03, 0x7d, KEY_VOLUMEUP },
-+	{ 0x01, 0x7d, KEY_VOLUMEDOWN },
-+	{ 0x02, 0x42, KEY_CHANNELUP },
-+	{ 0x00, 0x7d, KEY_CHANNELDOWN },
- };
- 
- /* STK7700P: Hauppauge Nova-T Stick, AVerMedia Volar */
-@@ -578,16 +644,22 @@ static struct mt2060_config stk7700p_mt2060_config = {
- 
- static int stk7700p_tuner_attach(struct dvb_usb_adapter *adap)
- {
-+	struct i2c_adapter *prim_i2c = &adap->dev->i2c_adap;
- 	struct dib0700_state *st = adap->dev->priv;
- 	struct i2c_adapter *tun_i2c;
--
-+	s8 a;
-+	int if1=1220;
-+	if (adap->dev->udev->descriptor.idVendor  == USB_VID_HAUPPAUGE &&
-+		adap->dev->udev->descriptor.idProduct == USB_PID_HAUPPAUGE_NOVA_T_STICK) {
-+		if (!eeprom_read(prim_i2c,0x58,&a)) if1=1220+a;
-+	}
- 	if (st->is_dib7000pc)
- 		tun_i2c = dib7000p_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_TUNER, 1);
- 	else
- 		tun_i2c = dib7000m_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_TUNER, 1);
- 
- 	return dvb_attach(mt2060_attach, adap->fe, tun_i2c, &stk7700p_mt2060_config,
--		st->mt2060_if1[0]) == NULL ? -ENODEV : 0;
-+		if1) == NULL ? -ENODEV : 0;
- }
- 
- /* DIB7070 generic */
-@@ -709,6 +781,8 @@ static struct dib7000p_config dib7070p_dib7000p_config = {
- 	.agc_config_count = 1,
- 	.agc = &dib7070_agc_config,
- 	.bw  = &dib7070_bw_config_12_mhz,
-+	.tuner_is_baseband = 1,
-+	.spur_protect = 1,
- 
- 	.gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS,
- 	.gpio_val = DIB7000P_GPIO_DEFAULT_VALUES,
-@@ -748,6 +822,8 @@ static struct dib7000p_config stk7070pd_dib7000p_config[2] = {
- 		.agc_config_count = 1,
- 		.agc = &dib7070_agc_config,
- 		.bw  = &dib7070_bw_config_12_mhz,
-+		.tuner_is_baseband = 1,
-+		.spur_protect = 1,
- 
- 		.gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS,
- 		.gpio_val = DIB7000P_GPIO_DEFAULT_VALUES,
-@@ -760,6 +836,8 @@ static struct dib7000p_config stk7070pd_dib7000p_config[2] = {
- 		.agc_config_count = 1,
- 		.agc = &dib7070_agc_config,
- 		.bw  = &dib7070_bw_config_12_mhz,
-+		.tuner_is_baseband = 1,
-+		.spur_protect = 1,
- 
- 		.gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS,
- 		.gpio_val = DIB7000P_GPIO_DEFAULT_VALUES,
-@@ -821,6 +899,12 @@ struct usb_device_id dib0700_usb_id_table[] = {
- 		{ USB_DEVICE(USB_VID_PINNACLE,  USB_PID_PINNACLE_PCTV_DUAL_DIVERSITY_DVB_T) },
- 		{ USB_DEVICE(USB_VID_COMPRO,    USB_PID_COMPRO_VIDEOMATE_U500_PC) },
- /* 20 */{ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_EXPRESS) },
-+		{ USB_DEVICE(USB_VID_GIGABYTE,  USB_PID_GIGABYTE_U7000) },
-+		{ USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ARTEC_T14BR) },
-+		{ USB_DEVICE(USB_VID_ASUS,      USB_PID_ASUS_U3000) },
-+		{ USB_DEVICE(USB_VID_ASUS,      USB_PID_ASUS_U3100) },
-+/* 25 */	{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_STICK_3) },
-+		{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_MYTV_T) },
- 		{ 0 }		/* Terminating entry */
- };
- MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table);
-@@ -862,7 +946,7 @@ struct dvb_usb_device_properties dib0700_devices[] = {
- 			},
- 		},
- 
--		.num_device_descs = 7,
-+		.num_device_descs = 8,
- 		.devices = {
- 			{   "DiBcom STK7700P reference design",
- 				{ &dib0700_usb_id_table[0], &dib0700_usb_id_table[1] },
-@@ -891,6 +975,10 @@ struct dvb_usb_device_properties dib0700_devices[] = {
- 			{   "AVerMedia AVerTV DVB-T Express",
- 				{ &dib0700_usb_id_table[20] },
- 				{ NULL },
-+			},
-+			{   "Gigabyte U7000",
-+				{ &dib0700_usb_id_table[21], NULL },
-+				{ NULL },
- 			}
- 		},
- 
-@@ -961,7 +1049,7 @@ struct dvb_usb_device_properties dib0700_devices[] = {
- 			{   "DiBcom STK7700D reference design",
- 				{ &dib0700_usb_id_table[14], NULL },
- 				{ NULL },
--			},
-+			}
- 		},
- 
- 		.rc_interval      = DEFAULT_RC_INTERVAL,
-@@ -974,6 +1062,25 @@ struct dvb_usb_device_properties dib0700_devices[] = {
- 		.num_adapters = 1,
- 		.adapter = {
- 			{
-+				.frontend_attach  = stk7700P2_frontend_attach,
-+				.tuner_attach     = stk7700d_tuner_attach,
++static int tda18271_rf_cal_init(struct dvb_frontend *fe)
++{
++	struct tda18271_priv *priv = fe->tuner_priv;
++	unsigned char *regs = priv->tda18271_regs;
 +
-+				DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
-+			},
-+		},
++	/* test RF_CAL_OK to see if we need init */
++	if ((regs[R_EP1] & 0x10) == 0)
++		priv->cal_initialized = false;
 +
-+		.num_device_descs = 1,
-+		.devices = {
-+			{   "ASUS My Cinema U3000 Mini DVBT Tuner",
-+				{ &dib0700_usb_id_table[23], NULL },
-+				{ NULL },
-+			},
-+		}
-+	}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
++	if (priv->cal_initialized)
++		return 0;
 +
-+		.num_adapters = 1,
-+		.adapter = {
-+			{
- 				.frontend_attach  = stk7070p_frontend_attach,
- 				.tuner_attach     = dib7070p_tuner_attach,
- 
-@@ -983,7 +1090,7 @@ struct dvb_usb_device_properties dib0700_devices[] = {
- 			},
- 		},
- 
--		.num_device_descs = 2,
-+		.num_device_descs = 6,
- 		.devices = {
- 			{   "DiBcom STK7070P reference design",
- 				{ &dib0700_usb_id_table[15], NULL },
-@@ -993,7 +1100,29 @@ struct dvb_usb_device_properties dib0700_devices[] = {
- 				{ &dib0700_usb_id_table[16], NULL },
- 				{ NULL },
- 			},
--		}
-+			{   "Artec T14BR DVB-T",
-+				{ &dib0700_usb_id_table[22], NULL },
-+				{ NULL },
-+			},
-+			{   "ASUS My Cinema U3100 Mini DVBT Tuner",
-+				{ &dib0700_usb_id_table[24], NULL },
-+				{ NULL },
-+			},
-+			{   "Hauppauge Nova-T Stick",
-+				{ &dib0700_usb_id_table[25], NULL },
-+				{ NULL },
-+			},
-+			{   "Hauppauge Nova-T MyTV.t",
-+				{ &dib0700_usb_id_table[26], NULL },
-+				{ NULL },
-+			},
-+		},
++	tda18271_calc_rf_filter_curve(fe);
 +
-+		.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
++	tda18271_por(fe);
 +
- 	}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
- 
- 		.num_adapters = 2,
-@@ -1024,7 +1153,7 @@ struct dvb_usb_device_properties dib0700_devices[] = {
- 			{   "Pinnacle PCTV Dual DVB-T Diversity Stick",
- 				{ &dib0700_usb_id_table[18], NULL },
- 				{ NULL },
--			},
-+			}
- 		}
- 	},
- };
-diff --git a/drivers/media/dvb/dvb-usb/digitv.c b/drivers/media/dvb/dvb-usb/digitv.c
-index bca1e09..3acbda4 100644
---- a/drivers/media/dvb/dvb-usb/digitv.c
-+++ b/drivers/media/dvb/dvb-usb/digitv.c
-@@ -17,9 +17,10 @@
- #include "nxt6000.h"
- 
- /* debug */
--int dvb_usb_digitv_debug;
-+static int dvb_usb_digitv_debug;
- module_param_named(debug,dvb_usb_digitv_debug, int, 0644);
- MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS);
-+#define deb_rc(args...)   dprintk(dvb_usb_digitv_debug,0x01,args)
- 
- static int digitv_ctrl_msg(struct dvb_usb_device *d,
- 		u8 cmd, u8 vv, u8 *wbuf, int wlen, u8 *rbuf, int rlen)
-diff --git a/drivers/media/dvb/dvb-usb/digitv.h b/drivers/media/dvb/dvb-usb/digitv.h
-index 8b43e3d..908c09f 100644
---- a/drivers/media/dvb/dvb-usb/digitv.h
-+++ b/drivers/media/dvb/dvb-usb/digitv.h
-@@ -8,9 +8,6 @@ struct digitv_state {
-     int is_nxt6000;
- };
- 
--extern int dvb_usb_digitv_debug;
--#define deb_rc(args...)   dprintk(dvb_usb_digitv_debug,0x01,args)
--
- /* protocol (from usblogging and the SDK:
-  *
-  * Always 7 bytes bulk message(s) for controlling
-diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
-index 4fa3e89..aa4844e 100644
---- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
-+++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
-@@ -15,7 +15,9 @@
- #define USB_VID_ALCOR_MICRO			0x058f
- #define USB_VID_ALINK				0x05e3
- #define USB_VID_ANCHOR				0x0547
-+#define USB_VID_ANSONIC				0x10b9
- #define USB_VID_ANUBIS_ELECTRONIC		0x10fd
-+#define USB_VID_ASUS				0x0b05
- #define USB_VID_AVERMEDIA			0x07ca
- #define USB_VID_COMPRO				0x185b
- #define USB_VID_COMPRO_UNK			0x145f
-@@ -44,12 +46,16 @@
- #define USB_VID_ULTIMA_ELECTRONIC		0x05d8
- #define USB_VID_UNIWILL				0x1584
- #define USB_VID_WIDEVIEW			0x14aa
-+/* dom : pour gigabyte u7000 */
-+#define USB_VID_GIGABYTE			0x1044
++	tda_info("tda18271: RF tracking filter calibration complete\n");
 +
- 
- /* Product IDs */
- #define USB_PID_ADSTECH_USB2_COLD			0xa333
- #define USB_PID_ADSTECH_USB2_WARM			0xa334
- #define USB_PID_AFATECH_AF9005				0x9020
- #define USB_VID_ALINK_DTU				0xf170
-+#define USB_PID_ANSONIC_DVBT_USB			0x6000
- #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 +75,7 @@
- #define USB_PID_DIBCOM_STK7700P				0x1e14
- #define USB_PID_DIBCOM_STK7700P_PC			0x1e78
- #define USB_PID_DIBCOM_STK7700D				0x1ef0
-+#define USB_PID_DIBCOM_STK7700_U7000			0x7001
- #define USB_PID_DIBCOM_STK7070P				0x1ebc
- #define USB_PID_DIBCOM_STK7070PD			0x1ebe
- #define USB_PID_DIBCOM_ANCHOR_2135_COLD			0x2131
-@@ -99,6 +106,7 @@
- #define USB_PID_ULTIMA_TVBOX_USB2_WARM			0x810a
- #define USB_PID_ARTEC_T14_COLD				0x810b
- #define USB_PID_ARTEC_T14_WARM				0x810c
-+#define USB_PID_ARTEC_T14BR				0x810f
- #define USB_PID_ULTIMA_TVBOX_USB2_FX_COLD		0x8613
- #define USB_PID_ULTIMA_TVBOX_USB2_FX_WARM		0x1002
- #define USB_PID_UNK_HYPER_PALTEK_COLD			0x005e
-@@ -120,6 +128,8 @@
- #define USB_PID_HAUPPAUGE_NOVA_T_500_2			0x9950
- #define USB_PID_HAUPPAUGE_NOVA_T_STICK			0x7050
- #define USB_PID_HAUPPAUGE_NOVA_T_STICK_2		0x7060
-+#define USB_PID_HAUPPAUGE_NOVA_T_STICK_3		0x7070
-+#define USB_PID_HAUPPAUGE_MYTV_T			0x7080
- #define USB_PID_HAUPPAUGE_NOVA_TD_STICK			0x9580
- #define USB_PID_AVERMEDIA_EXPRESS			0xb568
- #define USB_PID_AVERMEDIA_VOLAR				0xa807
-@@ -143,6 +153,9 @@
- #define USB_PID_DVICO_BLUEBIRD_DUAL_1_WARM		0xdb51
- #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_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
- #define USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_WARM		0xdb55
- #define USB_PID_MEDION_MD95700				0x0932
-@@ -170,6 +183,9 @@
- #define USB_PID_OPERA1_WARM				0x3829
- #define USB_PID_LIFEVIEW_TV_WALKER_TWIN_COLD		0x0514
- #define USB_PID_LIFEVIEW_TV_WALKER_TWIN_WARM		0x0513
--
-+/* dom pour gigabyte u7000 */
-+#define USB_PID_GIGABYTE_U7000				0x7001
-+#define USB_PID_ASUS_U3000				0x171f
-+#define USB_PID_ASUS_U3100				0x173f
- 
- #endif
-diff --git a/drivers/media/dvb/dvb-usb/gl861.c b/drivers/media/dvb/dvb-usb/gl861.c
-index f01d99c..6b99d9f 100644
---- a/drivers/media/dvb/dvb-usb/gl861.c
-+++ b/drivers/media/dvb/dvb-usb/gl861.c
-@@ -56,12 +56,12 @@ static int gl861_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
- 	struct dvb_usb_device *d = i2c_get_adapdata(adap);
- 	int i;
- 
--	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
--		return -EAGAIN;
--
- 	if (num > 2)
- 		return -EINVAL;
- 
-+	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
-+		return -EAGAIN;
++	priv->cal_initialized = true;
 +
- 	for (i = 0; i < num; i++) {
- 		/* write/read request */
- 		if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) {
-diff --git a/drivers/media/dvb/dvb-usb/gp8psk.c b/drivers/media/dvb/dvb-usb/gp8psk.c
-index 92147ee..83e8535 100644
---- a/drivers/media/dvb/dvb-usb/gp8psk.c
-+++ b/drivers/media/dvb/dvb-usb/gp8psk.c
-@@ -171,22 +171,6 @@ static int gp8psk_power_ctrl(struct dvb_usb_device *d, int onoff)
- 	return 0;
- }
- 
--int gp8psk_bcm4500_reload(struct dvb_usb_device *d)
--{
--	u8 buf;
--	int gp_product_id = le16_to_cpu(d->udev->descriptor.idProduct);
--	/* Turn off 8psk power */
--	if (gp8psk_usb_in_op(d, BOOT_8PSK, 0, 0, &buf, 1))
--		return -EINVAL;
--	/* Turn On 8psk power */
--	if (gp8psk_usb_in_op(d, BOOT_8PSK, 1, 0, &buf, 1))
--		return -EINVAL;
--	/* load BCM4500 firmware */
--	if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM)
--		if (gp8psk_load_bcm4500fw(d))
--			return EINVAL;
--	return 0;
--}
- 
- static int gp8psk_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
- {
-diff --git a/drivers/media/dvb/dvb-usb/gp8psk.h b/drivers/media/dvb/dvb-usb/gp8psk.h
-index e83a575..e5cd814 100644
---- a/drivers/media/dvb/dvb-usb/gp8psk.h
-+++ b/drivers/media/dvb/dvb-usb/gp8psk.h
-@@ -92,6 +92,5 @@ extern struct dvb_frontend * gp8psk_fe_attach(struct dvb_usb_device *d);
- extern int gp8psk_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen);
- extern int gp8psk_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value,
- 			     u16 index, u8 *b, int blen);
--extern int gp8psk_bcm4500_reload(struct dvb_usb_device *d);
- 
- #endif
-diff --git a/drivers/media/dvb/dvb-usb/opera1.c b/drivers/media/dvb/dvb-usb/opera1.c
-index d7c0495..21935bf 100644
---- a/drivers/media/dvb/dvb-usb/opera1.c
-+++ b/drivers/media/dvb/dvb-usb/opera1.c
-@@ -10,7 +10,9 @@
- * see Documentation/dvb/README.dvb-usb for more information
- */
- 
--#include "opera1.h"
-+#define DVB_USB_LOG_PREFIX "opera"
++	return 0;
++}
 +
-+#include "dvb-usb.h"
- #include "stv0299.h"
- 
- #define OPERA_READ_MSG 0
-@@ -38,7 +40,7 @@ struct opera_rc_keys {
- 	u32 event;
- };
- 
--int dvb_usb_opera1_debug;
-+static int dvb_usb_opera1_debug;
- module_param_named(debug, dvb_usb_opera1_debug, int, 0644);
- MODULE_PARM_DESC(debug,
- 		 "set debugging level (1=info,xfer=2,pll=4,ts=8,err=16,rc=32,fw=64 (or-able))."
-diff --git a/drivers/media/dvb/dvb-usb/opera1.h b/drivers/media/dvb/dvb-usb/opera1.h
-deleted file mode 100644
-index 5317442..0000000
---- a/drivers/media/dvb/dvb-usb/opera1.h
-+++ /dev/null
-@@ -1,9 +0,0 @@
--#ifndef _OPERA1_H_
--#define _OPERA1_H_
--
--#define DVB_USB_LOG_PREFIX "opera"
--#include "dvb-usb.h"
--
--extern int dvb_usb_opera1_debug;
--#define deb_xfer(args...) dprintk(dvb_usb_opera1_debug,0x02,args)
--#endif
-diff --git a/drivers/media/dvb/dvb-usb/vp702x.c b/drivers/media/dvb/dvb-usb/vp702x.c
-index 16533b3..e553c13 100644
---- a/drivers/media/dvb/dvb-usb/vp702x.c
-+++ b/drivers/media/dvb/dvb-usb/vp702x.c
-@@ -56,7 +56,7 @@ int vp702x_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8
- 	return ret;
- }
- 
--int vp702x_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value,
-+static int vp702x_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value,
- 			     u16 index, u8 *b, int blen)
- {
- 	int ret;
-@@ -204,19 +204,6 @@ static int vp702x_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
- 	return 0;
- }
- 
--int vp702x_power_ctrl(struct dvb_usb_device *d, int onoff)
--{
--	struct vp702x_device_state *st = d->priv;
--
--	if (st->power_state == 0 && onoff)
--		vp702x_usb_out_op(d, SET_TUNER_POWER_REQ, 1, 7, NULL, 0);
--	else if (st->power_state == 1 && onoff == 0)
--		vp702x_usb_out_op(d, SET_TUNER_POWER_REQ, 0, 7, NULL, 0);
--
--	st->power_state = onoff;
--
--	return 0;
--}
- 
- static int vp702x_read_mac_addr(struct dvb_usb_device *d,u8 mac[6])
- {
-diff --git a/drivers/media/dvb/dvb-usb/vp702x.h b/drivers/media/dvb/dvb-usb/vp702x.h
-index 25a9dee..c2f97f9 100644
---- a/drivers/media/dvb/dvb-usb/vp702x.h
-+++ b/drivers/media/dvb/dvb-usb/vp702x.h
-@@ -102,7 +102,5 @@ extern struct dvb_frontend * vp702x_fe_attach(struct dvb_usb_device *d);
- 
- extern int vp702x_usb_inout_op(struct dvb_usb_device *d, u8 *o, int olen, u8 *i, int ilen, int msec);
- extern int vp702x_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen);
--extern int vp702x_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen);
--extern int vp702x_power_ctrl(struct dvb_usb_device *d, int onoff);
- 
- #endif
-diff --git a/drivers/media/dvb/dvb-usb/vp7045.c b/drivers/media/dvb/dvb-usb/vp7045.c
-index 5bbd2d5..c172bab 100644
---- a/drivers/media/dvb/dvb-usb/vp7045.c
-+++ b/drivers/media/dvb/dvb-usb/vp7045.c
-@@ -15,9 +15,12 @@
- #include "vp7045.h"
- 
- /* debug */
--int dvb_usb_vp7045_debug;
-+static int dvb_usb_vp7045_debug;
- module_param_named(debug,dvb_usb_vp7045_debug, int, 0644);
- MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,rc=4 (or-able))." DVB_USB_DEBUG_STATUS);
-+#define deb_info(args...) dprintk(dvb_usb_vp7045_debug,0x01,args)
-+#define deb_xfer(args...) dprintk(dvb_usb_vp7045_debug,0x02,args)
-+#define deb_rc(args...)   dprintk(dvb_usb_vp7045_debug,0x04,args)
- 
- int vp7045_usb_op(struct dvb_usb_device *d, u8 cmd, u8 *out, int outlen, u8 *in, int inlen, int msec)
- {
-diff --git a/drivers/media/dvb/dvb-usb/vp7045.h b/drivers/media/dvb/dvb-usb/vp7045.h
-index 9ce21a2..969688f 100644
---- a/drivers/media/dvb/dvb-usb/vp7045.h
-+++ b/drivers/media/dvb/dvb-usb/vp7045.h
-@@ -17,11 +17,6 @@
- #define DVB_USB_LOG_PREFIX "vp7045"
- #include "dvb-usb.h"
- 
--extern int dvb_usb_vp7045_debug;
--#define deb_info(args...) dprintk(dvb_usb_vp7045_debug,0x01,args)
--#define deb_xfer(args...) dprintk(dvb_usb_vp7045_debug,0x02,args)
--#define deb_rc(args...)   dprintk(dvb_usb_vp7045_debug,0x04,args)
--
- /* vp7045 commands */
- 
- /* Twinhan Vendor requests */
-diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig
-index 59b9ed1..9ad86ce 100644
---- a/drivers/media/dvb/frontends/Kconfig
-+++ b/drivers/media/dvb/frontends/Kconfig
-@@ -316,6 +316,13 @@ config DVB_TDA827X
- 	help
- 	  A DVB-T silicon tuner module. Say Y when you want to support this tuner.
- 
-+config DVB_TDA18271
-+	tristate "NXP TDA18271 silicon tuner"
-+	depends on I2C
-+	default m if DVB_FE_CUSTOMISE
-+	help
-+	  A silicon tuner module. Say Y when you want to support this tuner.
++static int tda18271_init(struct dvb_frontend *fe)
++{
++	struct tda18271_priv *priv = fe->tuner_priv;
 +
- config DVB_TUNER_QT1010
- 	tristate "Quantek QT1010 silicon tuner"
- 	depends on DVB_CORE && I2C
-@@ -353,6 +360,15 @@ config DVB_TUNER_DIB0070
- 	  This device is only used inside a SiP called togther with a
- 	  demodulator for now.
- 
-+config DVB_TUNER_XC5000
-+	tristate "Xceive XC5000 silicon tuner"
-+	depends on I2C
-+	default m if DVB_FE_CUSTOMISE
-+	help
-+	  A driver for the silicon tuner XC5000 from Xceive.
-+	  This device is only used inside a SiP called togther with a
-+	  demodulator for now.
++	mutex_lock(&priv->lock);
 +
- comment "Miscellaneous devices"
- 	depends on DVB_CORE
- 
-diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile
-index 4b8ad1f..16bd107 100644
---- a/drivers/media/dvb/frontends/Makefile
-+++ b/drivers/media/dvb/frontends/Makefile
-@@ -3,6 +3,9 @@
- #
- 
- EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/
-+EXTRA_CFLAGS += -Idrivers/media/video/
++	/* power up */
++	tda18271_set_standby_mode(fe, 0, 0, 0);
 +
-+tda18271-objs := tda18271-tables.o tda18271-common.o tda18271-fe.o
- 
- obj-$(CONFIG_DVB_PLL) += dvb-pll.o
- obj-$(CONFIG_DVB_STV0299) += stv0299.o
-@@ -39,6 +42,7 @@ obj-$(CONFIG_DVB_ISL6421) += isl6421.o
- obj-$(CONFIG_DVB_TDA10086) += tda10086.o
- obj-$(CONFIG_DVB_TDA826X) += tda826x.o
- obj-$(CONFIG_DVB_TDA827X) += tda827x.o
-+obj-$(CONFIG_DVB_TDA18271) += tda18271.o
- obj-$(CONFIG_DVB_TUNER_MT2060) += mt2060.o
- obj-$(CONFIG_DVB_TUNER_MT2266) += mt2266.o
- obj-$(CONFIG_DVB_TUNER_DIB0070) += dib0070.o
-@@ -46,3 +50,4 @@ obj-$(CONFIG_DVB_TUNER_QT1010) += qt1010.o
- obj-$(CONFIG_DVB_TUA6100) += tua6100.o
- obj-$(CONFIG_DVB_TUNER_MT2131) += mt2131.o
- obj-$(CONFIG_DVB_S5H1409) += s5h1409.o
-+obj-$(CONFIG_DVB_TUNER_XC5000) += xc5000.o
-diff --git a/drivers/media/dvb/frontends/dib0070.c b/drivers/media/dvb/frontends/dib0070.c
-index 481eaa6..fe895bf 100644
---- a/drivers/media/dvb/frontends/dib0070.c
-+++ b/drivers/media/dvb/frontends/dib0070.c
-@@ -434,9 +434,14 @@ static u16 dib0070_p1f_defaults[] =
- 	0,
- };
- 
--static void dib0070_wbd_calibration(struct dib0070_state *state)
-+static void dib0070_wbd_calibration(struct dvb_frontend *fe)
- {
- 	u16 wbd_offs;
-+	struct dib0070_state *state = fe->tuner_priv;
++	/* initialization */
++	tda18271_ir_cal_init(fe);
 +
-+	if (state->cfg->sleep)
-+		state->cfg->sleep(fe, 0);
++	if (priv->id == TDA18271HDC2)
++		tda18271_rf_cal_init(fe);
 +
- 	dib0070_write_reg(state, 0x0f, 0x6d81);
- 	dib0070_write_reg(state, 0x20, 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001);
- 	msleep(9);
-@@ -444,6 +449,10 @@ static void dib0070_wbd_calibration(struct dib0070_state *state)
- 	dib0070_write_reg(state, 0x20, 0);
- 	state->wbd_ff_offset = ((wbd_offs * 8 * 18 / 33 + 1) / 2);
- 	dprintk( "WBDStart = %d (Vargen) - FF = %hd", (u32) wbd_offs * 1800/1024, state->wbd_ff_offset);
++	mutex_unlock(&priv->lock);
 +
-+	if (state->cfg->sleep)
-+		state->cfg->sleep(fe, 1);
++	return 0;
++}
 +
- }
- 
- u16 dib0070_wbd_offset(struct dvb_frontend *fe)
-@@ -560,7 +569,7 @@ struct dvb_frontend * dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter
- 	if (dib0070_reset(state) != 0)
- 		goto free_mem;
- 
--	dib0070_wbd_calibration(state);
-+	dib0070_wbd_calibration(fe);
- 
- 	printk(KERN_INFO "DiB0070: successfully identified\n");
- 	memcpy(&fe->ops.tuner_ops, &dib0070_ops, sizeof(struct dvb_tuner_ops));
-diff --git a/drivers/media/dvb/frontends/dib3000mc.c b/drivers/media/dvb/frontends/dib3000mc.c
-index edae0be..fa85160 100644
---- a/drivers/media/dvb/frontends/dib3000mc.c
-+++ b/drivers/media/dvb/frontends/dib3000mc.c
-@@ -684,6 +684,9 @@ static int dib3000mc_set_frontend(struct dvb_frontend* fe,
- 				struct dvb_frontend_parameters *fep)
- {
- 	struct dib3000mc_state *state = fe->demodulator_priv;
-+    int ret;
++static int tda18271c2_tune(struct dvb_frontend *fe,
++			   u32 ifc, u32 freq, u32 bw, u8 std, int radio)
++{
++	struct tda18271_priv *priv = fe->tuner_priv;
 +
-+	dib3000mc_set_output_mode(state, OUTMODE_HIGH_Z);
- 
- 	state->current_bandwidth = fep->u.ofdm.bandwidth;
- 	dib3000mc_set_bandwidth(state, BANDWIDTH_TO_KHZ(fep->u.ofdm.bandwidth));
-@@ -700,7 +703,7 @@ static int dib3000mc_set_frontend(struct dvb_frontend* fe,
- 		fep->u.ofdm.guard_interval    == GUARD_INTERVAL_AUTO ||
- 		fep->u.ofdm.constellation     == QAM_AUTO ||
- 		fep->u.ofdm.code_rate_HP      == FEC_AUTO) {
--		int i = 100, found;
-+		int i = 1000, found;
- 
- 		dib3000mc_autosearch_start(fe, fep);
- 		do {
-@@ -715,10 +718,11 @@ static int dib3000mc_set_frontend(struct dvb_frontend* fe,
- 		dib3000mc_get_frontend(fe, fep);
- 	}
- 
-+    ret = dib3000mc_tune(fe, fep);
++	tda_dbg("freq = %d, ifc = %d\n", freq, ifc);
 +
- 	/* make this a config parameter */
- 	dib3000mc_set_output_mode(state, OUTMODE_MPEG2_FIFO);
--
--	return dib3000mc_tune(fe, fep);
-+    return ret;
- }
- 
- static int dib3000mc_read_status(struct dvb_frontend *fe, fe_status_t *stat)
-diff --git a/drivers/media/dvb/frontends/dib7000m.c b/drivers/media/dvb/frontends/dib7000m.c
-index fb18441..5f1375e 100644
---- a/drivers/media/dvb/frontends/dib7000m.c
-+++ b/drivers/media/dvb/frontends/dib7000m.c
-@@ -1171,7 +1171,9 @@ static int dib7000m_set_frontend(struct dvb_frontend* fe,
- 				struct dvb_frontend_parameters *fep)
- {
- 	struct dib7000m_state *state = fe->demodulator_priv;
--	int time;
-+	int time, ret;
++	tda18271_init(fe);
 +
-+    dib7000m_set_output_mode(state, OUTMODE_HIGH_Z);
- 
- 	state->current_bandwidth = fep->u.ofdm.bandwidth;
- 	dib7000m_set_bandwidth(state, BANDWIDTH_TO_KHZ(fep->u.ofdm.bandwidth));
-@@ -1206,10 +1208,11 @@ static int dib7000m_set_frontend(struct dvb_frontend* fe,
- 		dib7000m_get_frontend(fe, fep);
- 	}
- 
-+	ret = dib7000m_tune(fe, fep);
++	mutex_lock(&priv->lock);
 +
- 	/* make this a config parameter */
- 	dib7000m_set_output_mode(state, OUTMODE_MPEG2_FIFO);
--
--	return dib7000m_tune(fe, fep);
-+	return ret;
- }
- 
- static int dib7000m_read_status(struct dvb_frontend *fe, fe_status_t *stat)
-diff --git a/drivers/media/dvb/frontends/dib7000p.c b/drivers/media/dvb/frontends/dib7000p.c
-index f45bcfc..47c23e2 100644
---- a/drivers/media/dvb/frontends/dib7000p.c
-+++ b/drivers/media/dvb/frontends/dib7000p.c
-@@ -35,8 +35,8 @@ struct dib7000p_state {
- 
- 	u16 wbd_ref;
- 
--	u8 current_band;
--	fe_bandwidth_t current_bandwidth;
-+	u8  current_band;
-+	u32 current_bandwidth;
- 	struct dibx000_agc_config *current_agc;
- 	u32 timf;
- 
-@@ -1074,7 +1074,7 @@ static int dib7000p_get_frontend(struct dvb_frontend* fe,
- 
- 	fep->inversion = INVERSION_AUTO;
- 
--	fep->u.ofdm.bandwidth = state->current_bandwidth;
-+	fep->u.ofdm.bandwidth = BANDWIDTH_TO_INDEX(state->current_bandwidth);
- 
- 	switch ((tps >> 8) & 0x3) {
- 		case 0: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K; break;
-@@ -1128,12 +1128,11 @@ static int dib7000p_set_frontend(struct dvb_frontend* fe,
- 				struct dvb_frontend_parameters *fep)
- {
- 	struct dib7000p_state *state = fe->demodulator_priv;
--	int time;
-+	int time, ret;
- 
--	state->current_bandwidth = fep->u.ofdm.bandwidth;
--	dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(fep->u.ofdm.bandwidth));
-+	dib7000p_set_output_mode(state, OUTMODE_HIGH_Z);
- 
--	/* maybe the parameter has been changed */
-+    /* maybe the parameter has been changed */
- 	state->sfn_workaround_active = buggy_sfn_workaround;
- 
- 	if (fe->ops.tuner_ops.set_params)
-@@ -1166,10 +1165,11 @@ static int dib7000p_set_frontend(struct dvb_frontend* fe,
- 		dib7000p_get_frontend(fe, fep);
- 	}
- 
-+	ret = dib7000p_tune(fe, fep);
++	tda18271_rf_tracking_filters_correction(fe, freq);
 +
- 	/* make this a config parameter */
- 	dib7000p_set_output_mode(state, OUTMODE_MPEG2_FIFO);
--
--	return dib7000p_tune(fe, fep);
-+    return ret;
- }
- 
- static int dib7000p_read_status(struct dvb_frontend *fe, fe_status_t *stat)
-diff --git a/drivers/media/dvb/frontends/dibx000_common.h b/drivers/media/dvb/frontends/dibx000_common.h
-index 5e17275..84e4d53 100644
---- a/drivers/media/dvb/frontends/dibx000_common.h
-+++ b/drivers/media/dvb/frontends/dibx000_common.h
-@@ -128,6 +128,11 @@ enum dibx000_adc_states {
- 			     (v) == BANDWIDTH_7_MHZ  ? 7000 : \
- 			     (v) == BANDWIDTH_6_MHZ  ? 6000 : 8000 )
- 
-+#define BANDWIDTH_TO_INDEX(v) ( \
-+	(v) == 8000 ? BANDWIDTH_8_MHZ : \
-+		(v) == 7000 ? BANDWIDTH_7_MHZ : \
-+		(v) == 6000 ? BANDWIDTH_6_MHZ : BANDWIDTH_8_MHZ )
++	tda18271_channel_configuration(fe, ifc, freq, bw, std, radio);
 +
- /* Chip output mode. */
- #define OUTMODE_HIGH_Z              0
- #define OUTMODE_MPEG2_PAR_GATED_CLK 1
-diff --git a/drivers/media/dvb/frontends/mt2266.c b/drivers/media/dvb/frontends/mt2266.c
-index 03fe826..54b18f9 100644
---- a/drivers/media/dvb/frontends/mt2266.c
-+++ b/drivers/media/dvb/frontends/mt2266.c
-@@ -38,8 +38,12 @@ struct mt2266_priv {
- 
- 	u32 frequency;
- 	u32 bandwidth;
-+	u8 band;
- };
- 
-+#define MT2266_VHF 1
-+#define MT2266_UHF 0
++	mutex_unlock(&priv->lock);
 +
- /* Here, frequencies are expressed in kiloHertz to avoid 32 bits overflows */
- 
- static int debug;
-@@ -90,26 +94,30 @@ static int mt2266_writeregs(struct mt2266_priv *priv,u8 *buf, u8 len)
- }
- 
- // Initialisation sequences
--static u8 mt2266_init1[] = {
--	REG_TUNE,
--	0x00, 0x00, 0x28, 0x00, 0x52, 0x99, 0x3f };
-+static u8 mt2266_init1[] = { REG_TUNE, 0x00, 0x00, 0x28,
-+				 0x00, 0x52, 0x99, 0x3f };
- 
- static u8 mt2266_init2[] = {
--	0x17,                                     0x6d, 0x71, 0x61, 0xc0, 0xbf, 0xff, 0xdc, 0x00, 0x0a,
--	0xd4, 0x03, 0x64, 0x64, 0x64, 0x64, 0x22, 0xaa, 0xf2, 0x1e, 0x80, 0x14, 0x01, 0x01, 0x01, 0x01,
--	0x01, 0x01, 0x7f, 0x5e, 0x3f, 0xff, 0xff, 0xff, 0x00, 0x77, 0x0f, 0x2d };
-+    0x17, 0x6d, 0x71, 0x61, 0xc0, 0xbf, 0xff, 0xdc, 0x00, 0x0a, 0xd4,
-+    0x03, 0x64, 0x64, 0x64, 0x64, 0x22, 0xaa, 0xf2, 0x1e, 0x80, 0x14,
-+    0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x7f, 0x5e, 0x3f, 0xff, 0xff,
-+    0xff, 0x00, 0x77, 0x0f, 0x2d
-+};
++	return 0;
++}
 +
-+static u8 mt2266_init_8mhz[] = { REG_BANDWIDTH, 0x22, 0x22, 0x22, 0x22,
-+						0x22, 0x22, 0x22, 0x22 };
- 
--static u8 mt2266_init_8mhz[] = {
--	REG_BANDWIDTH,
--	0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22 };
-+static u8 mt2266_init_7mhz[] = { REG_BANDWIDTH, 0x32, 0x32, 0x32, 0x32,
-+						0x32, 0x32, 0x32, 0x32 };
- 
--static u8 mt2266_init_7mhz[] = {
--	REG_BANDWIDTH,
--	0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32 };
-+static u8 mt2266_init_6mhz[] = { REG_BANDWIDTH, 0xa7, 0xa7, 0xa7, 0xa7,
-+						0xa7, 0xa7, 0xa7, 0xa7 };
- 
--static u8 mt2266_init_6mhz[] = {
--	REG_BANDWIDTH,
--	0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7 };
-+static u8 mt2266_uhf[] = { 0x1d, 0xdc, 0x00, 0x0a, 0xd4, 0x03, 0x64, 0x64,
-+			   0x64, 0x64, 0x22, 0xaa, 0xf2, 0x1e, 0x80, 0x14 };
++/* ------------------------------------------------------------------ */
 +
-+static u8 mt2266_vhf[] = { 0x1d, 0xfe, 0x00, 0x00, 0xb4, 0x03, 0xa5, 0xa5,
-+			   0xa5, 0xa5, 0x82, 0xaa, 0xf1, 0x17, 0x80, 0x1f };
- 
- #define FREF 30000       // Quartz oscillator 30 MHz
- 
-@@ -122,35 +130,78 @@ static int mt2266_set_params(struct dvb_frontend *fe, struct dvb_frontend_parame
- 	u8  lnaband;
- 	u8  b[10];
- 	int i;
-+	u8 band;
- 
- 	priv = fe->tuner_priv;
- 
--	mt2266_writereg(priv,0x17,0x6d);
--	mt2266_writereg(priv,0x1c,0xff);
--
- 	freq = params->frequency / 1000; // Hz -> kHz
-+	if (freq < 470000 && freq > 230000)
-+		return -EINVAL; /* Gap between VHF and UHF bands */
- 	priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0;
- 	priv->frequency = freq * 1000;
--	tune=2 * freq * (8192/16) / (FREF/16);
--
--	if (freq <= 495000) lnaband = 0xEE; else
--	if (freq <= 525000) lnaband = 0xDD; else
--	if (freq <= 550000) lnaband = 0xCC; else
--	if (freq <= 580000) lnaband = 0xBB; else
--	if (freq <= 605000) lnaband = 0xAA; else
--	if (freq <= 630000) lnaband = 0x99; else
--	if (freq <= 655000) lnaband = 0x88; else
--	if (freq <= 685000) lnaband = 0x77; else
--	if (freq <= 710000) lnaband = 0x66; else
--	if (freq <= 735000) lnaband = 0x55; else
--	if (freq <= 765000) lnaband = 0x44; else
--	if (freq <= 802000) lnaband = 0x33; else
--	if (freq <= 840000) lnaband = 0x22; else lnaband = 0x11;
--
--	msleep(100);
--	mt2266_writeregs(priv,(params->u.ofdm.bandwidth==BANDWIDTH_6_MHZ)?mt2266_init_6mhz:
--				(params->u.ofdm.bandwidth==BANDWIDTH_7_MHZ)?mt2266_init_7mhz:
--				mt2266_init_8mhz,sizeof(mt2266_init_8mhz));
++static int tda18271c1_tune(struct dvb_frontend *fe,
++			   u32 ifc, u32 freq, u32 bw, u8 std, int radio)
++{
++	struct tda18271_priv *priv = fe->tuner_priv;
++	unsigned char *regs = priv->tda18271_regs;
++	u32 N = 0;
 +
-+	tune = 2 * freq * (8192/16) / (FREF/16);
-+	band = (freq < 300000) ? MT2266_VHF : MT2266_UHF;
-+	if (band == MT2266_VHF)
-+		tune *= 2;
++	tda18271_init(fe);
 +
-+	switch (params->u.ofdm.bandwidth) {
-+	case BANDWIDTH_6_MHZ:
-+		mt2266_writeregs(priv, mt2266_init_6mhz,
-+				 sizeof(mt2266_init_6mhz));
-+		break;
-+	case BANDWIDTH_7_MHZ:
-+		mt2266_writeregs(priv, mt2266_init_7mhz,
-+				 sizeof(mt2266_init_7mhz));
-+		break;
-+	case BANDWIDTH_8_MHZ:
-+	default:
-+		mt2266_writeregs(priv, mt2266_init_8mhz,
-+				 sizeof(mt2266_init_8mhz));
-+		break;
-+	}
++	mutex_lock(&priv->lock);
 +
-+	if (band == MT2266_VHF && priv->band == MT2266_UHF) {
-+		dprintk("Switch from UHF to VHF");
-+		mt2266_writereg(priv, 0x05, 0x04);
-+		mt2266_writereg(priv, 0x19, 0x61);
-+		mt2266_writeregs(priv, mt2266_vhf, sizeof(mt2266_vhf));
-+	} else if (band == MT2266_UHF && priv->band == MT2266_VHF) {
-+		dprintk("Switch from VHF to UHF");
-+		mt2266_writereg(priv, 0x05, 0x52);
-+		mt2266_writereg(priv, 0x19, 0x61);
-+		mt2266_writeregs(priv, mt2266_uhf, sizeof(mt2266_uhf));
-+	}
-+	msleep(10);
++	tda_dbg("freq = %d, ifc = %d\n", freq, ifc);
 +
-+	if (freq <= 495000)
-+		lnaband = 0xEE;
-+	else if (freq <= 525000)
-+		lnaband = 0xDD;
-+	else if (freq <= 550000)
-+		lnaband = 0xCC;
-+	else if (freq <= 580000)
-+		lnaband = 0xBB;
-+	else if (freq <= 605000)
-+		lnaband = 0xAA;
-+	else if (freq <= 630000)
-+		lnaband = 0x99;
-+	else if (freq <= 655000)
-+		lnaband = 0x88;
-+	else if (freq <= 685000)
-+		lnaband = 0x77;
-+	else if (freq <= 710000)
-+		lnaband = 0x66;
-+	else if (freq <= 735000)
-+		lnaband = 0x55;
-+	else if (freq <= 765000)
-+		lnaband = 0x44;
-+	else if (freq <= 802000)
-+		lnaband = 0x33;
-+	else if (freq <= 840000)
-+		lnaband = 0x22;
-+	else
-+		lnaband = 0x11;
- 
- 	b[0] = REG_TUNE;
- 	b[1] = (tune >> 8) & 0x1F;
-@@ -158,47 +209,54 @@ static int mt2266_set_params(struct dvb_frontend *fe, struct dvb_frontend_parame
- 	b[3] = tune >> 13;
- 	mt2266_writeregs(priv,b,4);
- 
--	dprintk("set_parms: tune=%d band=%d",(int)tune,(int)lnaband);
--	dprintk("set_parms: [1..3]: %2x %2x %2x",(int)b[1],(int)b[2],(int)b[3]);
--
--	b[0] = 0x05;
--	b[1] = 0x62;
--	b[2] = lnaband;
--	mt2266_writeregs(priv,b,3);
-+	dprintk("set_parms: tune=%d band=%d %s",
-+		(int) tune, (int) lnaband,
-+		(band == MT2266_UHF) ? "UHF" : "VHF");
-+	dprintk("set_parms: [1..3]: %2x %2x %2x",
-+		(int) b[1], (int) b[2], (int)b[3]);
++	/* RF tracking filter calibration */
 +
-+	if (band == MT2266_UHF) {
-+		b[0] = 0x05;
-+		b[1] = (priv->band == MT2266_VHF) ? 0x52 : 0x62;
-+		b[2] = lnaband;
-+		mt2266_writeregs(priv, b, 3);
-+	}
- 
--	//Waits for pll lock or timeout
-+	/* Wait for pll lock or timeout */
- 	i = 0;
- 	do {
- 		mt2266_readreg(priv,REG_LOCK,b);
--		if ((b[0] & 0x40)==0x40)
-+		if (b[0] & 0x40)
- 			break;
- 		msleep(10);
- 		i++;
- 	} while (i<10);
- 	dprintk("Lock when i=%i",(int)i);
++	/* calculate bp filter */
++	tda18271_calc_bp_filter(fe, &freq);
++	tda18271_write_regs(fe, R_EP1, 1);
++
++	regs[R_EB4]  &= 0x07;
++	regs[R_EB4]  |= 0x60;
++	tda18271_write_regs(fe, R_EB4, 1);
++
++	regs[R_EB7]   = 0x60;
++	tda18271_write_regs(fe, R_EB7, 1);
 +
-+	if (band == MT2266_UHF && priv->band == MT2266_VHF)
-+		mt2266_writereg(priv, 0x05, 0x62);
++	regs[R_EB14]  = 0x00;
++	tda18271_write_regs(fe, R_EB14, 1);
 +
-+	priv->band = band;
++	regs[R_EB20]  = 0xcc;
++	tda18271_write_regs(fe, R_EB20, 1);
 +
- 	return ret;
- }
- 
- static void mt2266_calibrate(struct mt2266_priv *priv)
- {
--	mt2266_writereg(priv,0x11,0x03);
--	mt2266_writereg(priv,0x11,0x01);
--
--	mt2266_writeregs(priv,mt2266_init1,sizeof(mt2266_init1));
--	mt2266_writeregs(priv,mt2266_init2,sizeof(mt2266_init2));
--
--	mt2266_writereg(priv,0x33,0x5e);
--	mt2266_writereg(priv,0x10,0x10);
--	mt2266_writereg(priv,0x10,0x00);
--
--	mt2266_writeregs(priv,mt2266_init_8mhz,sizeof(mt2266_init_8mhz));
--
-+	mt2266_writereg(priv, 0x11, 0x03);
-+	mt2266_writereg(priv, 0x11, 0x01);
-+	mt2266_writeregs(priv, mt2266_init1, sizeof(mt2266_init1));
-+	mt2266_writeregs(priv, mt2266_init2, sizeof(mt2266_init2));
-+	mt2266_writereg(priv, 0x33, 0x5e);
-+	mt2266_writereg(priv, 0x10, 0x10);
-+	mt2266_writereg(priv, 0x10, 0x00);
-+	mt2266_writeregs(priv, mt2266_init_8mhz, sizeof(mt2266_init_8mhz));
- 	msleep(25);
--	mt2266_writereg(priv,0x17,0x6d);
--	mt2266_writereg(priv,0x1c,0x00);
-+	mt2266_writereg(priv, 0x17, 0x6d);
-+	mt2266_writereg(priv, 0x1c, 0x00);
- 	msleep(75);
--	mt2266_writereg(priv,0x17,0x6d);
--	mt2266_writereg(priv,0x1c,0xff);
-+	mt2266_writereg(priv, 0x17, 0x6d);
-+	mt2266_writereg(priv, 0x1c, 0xff);
- }
- 
- static int mt2266_get_frequency(struct dvb_frontend *fe, u32 *frequency)
-@@ -217,17 +275,22 @@ static int mt2266_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
- 
- static int mt2266_init(struct dvb_frontend *fe)
- {
-+	int ret;
- 	struct mt2266_priv *priv = fe->tuner_priv;
--	mt2266_writereg(priv,0x17,0x6d);
--	mt2266_writereg(priv,0x1c,0xff);
-+	ret = mt2266_writereg(priv, 0x17, 0x6d);
-+	if (ret < 0)
-+		return ret;
-+	ret = mt2266_writereg(priv, 0x1c, 0xff);
-+	if (ret < 0)
-+		return ret;
- 	return 0;
- }
- 
- static int mt2266_sleep(struct dvb_frontend *fe)
- {
- 	struct mt2266_priv *priv = fe->tuner_priv;
--	mt2266_writereg(priv,0x17,0x6d);
--	mt2266_writereg(priv,0x1c,0x00);
-+	mt2266_writereg(priv, 0x17, 0x6d);
-+	mt2266_writereg(priv, 0x1c, 0x00);
- 	return 0;
- }
- 
-@@ -241,8 +304,8 @@ static int mt2266_release(struct dvb_frontend *fe)
- static const struct dvb_tuner_ops mt2266_tuner_ops = {
- 	.info = {
- 		.name           = "Microtune MT2266",
--		.frequency_min  = 470000000,
--		.frequency_max  = 860000000,
-+		.frequency_min  = 174000000,
-+		.frequency_max  = 862000000,
- 		.frequency_step =     50000,
- 	},
- 	.release       = mt2266_release,
-@@ -264,8 +327,9 @@ struct dvb_frontend * mt2266_attach(struct dvb_frontend *fe, struct i2c_adapter
- 
- 	priv->cfg      = cfg;
- 	priv->i2c      = i2c;
-+	priv->band     = MT2266_UHF;
- 
--	if (mt2266_readreg(priv,0,&id) != 0) {
-+	if (mt2266_readreg(priv, 0, &id)) {
- 		kfree(priv);
- 		return NULL;
- 	}
-diff --git a/drivers/media/dvb/frontends/mt312.c b/drivers/media/dvb/frontends/mt312.c
-index 0606b9a..1638301 100644
---- a/drivers/media/dvb/frontends/mt312.c
-+++ b/drivers/media/dvb/frontends/mt312.c
-@@ -37,9 +37,9 @@
- 
- 
- struct mt312_state {
--	struct i2c_adapter* i2c;
-+	struct i2c_adapter *i2c;
- 	/* configuration settings */
--	const struct mt312_config* config;
-+	const struct mt312_config *config;
- 	struct dvb_frontend frontend;
- 
- 	u8 id;
-@@ -49,14 +49,15 @@ struct mt312_state {
- static int debug;
- #define dprintk(args...) \
- 	do { \
--		if (debug) printk(KERN_DEBUG "mt312: " args); \
-+		if (debug) \
-+			printk(KERN_DEBUG "mt312: " args); \
- 	} while (0)
- 
- #define MT312_SYS_CLK		90000000UL	/* 90 MHz */
- #define MT312_LPOWER_SYS_CLK	60000000UL	/* 60 MHz */
- #define MT312_PLL_CLK		10000000UL	/* 10 MHz */
- 
--static int mt312_read(struct mt312_state* state, const enum mt312_reg_addr reg,
-+static int mt312_read(struct mt312_state *state, const enum mt312_reg_addr reg,
- 		      void *buf, const size_t count)
- {
- 	int ret;
-@@ -79,7 +80,7 @@ static int mt312_read(struct mt312_state* state, const enum mt312_reg_addr reg,
- 		return -EREMOTEIO;
- 	}
- 
--	if(debug) {
-+	if (debug) {
- 		int i;
- 		dprintk("R(%d):", reg & 0x7f);
- 		for (i = 0; i < count; i++)
-@@ -90,14 +91,14 @@ static int mt312_read(struct mt312_state* state, const enum mt312_reg_addr reg,
- 	return 0;
- }
- 
--static int mt312_write(struct mt312_state* state, const enum mt312_reg_addr reg,
-+static int mt312_write(struct mt312_state *state, const enum mt312_reg_addr reg,
- 		       const void *src, const size_t count)
- {
- 	int ret;
- 	u8 buf[count + 1];
- 	struct i2c_msg msg;
- 
--	if(debug) {
-+	if (debug) {
- 		int i;
- 		dprintk("W(%d):", reg & 0x7f);
- 		for (i = 0; i < count; i++)
-@@ -123,13 +124,13 @@ static int mt312_write(struct mt312_state* state, const enum mt312_reg_addr reg,
- 	return 0;
- }
- 
--static inline int mt312_readreg(struct mt312_state* state,
-+static inline int mt312_readreg(struct mt312_state *state,
- 				const enum mt312_reg_addr reg, u8 *val)
- {
- 	return mt312_read(state, reg, val, 1);
- }
- 
--static inline int mt312_writereg(struct mt312_state* state,
-+static inline int mt312_writereg(struct mt312_state *state,
- 				 const enum mt312_reg_addr reg, const u8 val)
- {
- 	return mt312_write(state, reg, &val, 1);
-@@ -140,18 +141,19 @@ static inline u32 mt312_div(u32 a, u32 b)
- 	return (a + (b / 2)) / b;
- }
- 
--static int mt312_reset(struct mt312_state* state, const u8 full)
-+static int mt312_reset(struct mt312_state *state, const u8 full)
- {
- 	return mt312_writereg(state, RESET, full ? 0x80 : 0x40);
- }
- 
--static int mt312_get_inversion(struct mt312_state* state,
-+static int mt312_get_inversion(struct mt312_state *state,
- 			       fe_spectral_inversion_t *i)
- {
- 	int ret;
- 	u8 vit_mode;
- 
--	if ((ret = mt312_readreg(state, VIT_MODE, &vit_mode)) < 0)
-+	ret = mt312_readreg(state, VIT_MODE, &vit_mode);
-+	if (ret < 0)
- 		return ret;
- 
- 	if (vit_mode & 0x80)	/* auto inversion was used */
-@@ -160,7 +162,7 @@ static int mt312_get_inversion(struct mt312_state* state,
- 	return 0;
- }
- 
--static int mt312_get_symbol_rate(struct mt312_state* state, u32 *sr)
-+static int mt312_get_symbol_rate(struct mt312_state *state, u32 *sr)
- {
- 	int ret;
- 	u8 sym_rate_h;
-@@ -169,37 +171,44 @@ static int mt312_get_symbol_rate(struct mt312_state* state, u32 *sr)
- 	u16 monitor;
- 	u8 buf[2];
- 
--	if ((ret = mt312_readreg(state, SYM_RATE_H, &sym_rate_h)) < 0)
-+	ret = mt312_readreg(state, SYM_RATE_H, &sym_rate_h);
-+	if (ret < 0)
- 		return ret;
- 
--	if (sym_rate_h & 0x80) {	/* symbol rate search was used */
--		if ((ret = mt312_writereg(state, MON_CTRL, 0x03)) < 0)
-+	if (sym_rate_h & 0x80) {
-+		/* symbol rate search was used */
-+		ret = mt312_writereg(state, MON_CTRL, 0x03);
-+		if (ret < 0)
- 			return ret;
- 
--		if ((ret = mt312_read(state, MONITOR_H, buf, sizeof(buf))) < 0)
-+		ret = mt312_read(state, MONITOR_H, buf, sizeof(buf));
-+		if (ret < 0)
- 			return ret;
- 
- 		monitor = (buf[0] << 8) | buf[1];
- 
--		dprintk(KERN_DEBUG "sr(auto) = %u\n",
-+		dprintk("sr(auto) = %u\n",
- 		       mt312_div(monitor * 15625, 4));
- 	} else {
--		if ((ret = mt312_writereg(state, MON_CTRL, 0x05)) < 0)
-+		ret = mt312_writereg(state, MON_CTRL, 0x05);
-+		if (ret < 0)
- 			return ret;
- 
--		if ((ret = mt312_read(state, MONITOR_H, buf, sizeof(buf))) < 0)
-+		ret = mt312_read(state, MONITOR_H, buf, sizeof(buf));
-+		if (ret < 0)
- 			return ret;
- 
- 		dec_ratio = ((buf[0] >> 5) & 0x07) * 32;
- 
--		if ((ret = mt312_read(state, SYM_RAT_OP_H, buf, sizeof(buf))) < 0)
-+		ret = mt312_read(state, SYM_RAT_OP_H, buf, sizeof(buf));
-+		if (ret < 0)
- 			return ret;
- 
- 		sym_rat_op = (buf[0] << 8) | buf[1];
- 
--		dprintk(KERN_DEBUG "sym_rat_op=%d dec_ratio=%d\n",
-+		dprintk("sym_rat_op=%d dec_ratio=%d\n",
- 		       sym_rat_op, dec_ratio);
--		dprintk(KERN_DEBUG "*sr(manual) = %lu\n",
-+		dprintk("*sr(manual) = %lu\n",
- 		       (((MT312_PLL_CLK * 8192) / (sym_rat_op + 8192)) *
- 			2) - dec_ratio);
- 	}
-@@ -207,7 +216,7 @@ static int mt312_get_symbol_rate(struct mt312_state* state, u32 *sr)
- 	return 0;
- }
- 
--static int mt312_get_code_rate(struct mt312_state* state, fe_code_rate_t *cr)
-+static int mt312_get_code_rate(struct mt312_state *state, fe_code_rate_t *cr)
- {
- 	const fe_code_rate_t fec_tab[8] =
- 	    { FEC_1_2, FEC_2_3, FEC_3_4, FEC_5_6, FEC_6_7, FEC_7_8,
-@@ -216,7 +225,8 @@ static int mt312_get_code_rate(struct mt312_state* state, fe_code_rate_t *cr)
- 	int ret;
- 	u8 fec_status;
- 
--	if ((ret = mt312_readreg(state, FEC_STATUS, &fec_status)) < 0)
-+	ret = mt312_readreg(state, FEC_STATUS, &fec_status);
-+	if (ret < 0)
- 		return ret;
- 
- 	*cr = fec_tab[(fec_status >> 4) & 0x07];
-@@ -224,61 +234,72 @@ static int mt312_get_code_rate(struct mt312_state* state, fe_code_rate_t *cr)
- 	return 0;
- }
- 
--static int mt312_initfe(struct dvb_frontend* fe)
-+static int mt312_initfe(struct dvb_frontend *fe)
- {
- 	struct mt312_state *state = fe->demodulator_priv;
- 	int ret;
- 	u8 buf[2];
- 
- 	/* wake up */
--	if ((ret = mt312_writereg(state, CONFIG, (state->frequency == 60 ? 0x88 : 0x8c))) < 0)
-+	ret = mt312_writereg(state, CONFIG,
-+			(state->frequency == 60 ? 0x88 : 0x8c));
-+	if (ret < 0)
- 		return ret;
- 
- 	/* wait at least 150 usec */
- 	udelay(150);
- 
- 	/* full reset */
--	if ((ret = mt312_reset(state, 1)) < 0)
-+	ret = mt312_reset(state, 1);
-+	if (ret < 0)
- 		return ret;
- 
--// Per datasheet, write correct values. 09/28/03 ACCJr.
--// If we don't do this, we won't get FE_HAS_VITERBI in the VP310.
-+/* Per datasheet, write correct values. 09/28/03 ACCJr.
-+ * If we don't do this, we won't get FE_HAS_VITERBI in the VP310. */
- 	{
--		u8 buf_def[8]={0x14, 0x12, 0x03, 0x02, 0x01, 0x00, 0x00, 0x00};
-+		u8 buf_def[8] = { 0x14, 0x12, 0x03, 0x02,
-+				  0x01, 0x00, 0x00, 0x00 };
- 
--		if ((ret = mt312_write(state, VIT_SETUP, buf_def, sizeof(buf_def))) < 0)
-+		ret = mt312_write(state, VIT_SETUP, buf_def, sizeof(buf_def));
-+		if (ret < 0)
- 			return ret;
- 	}
- 
- 	/* SYS_CLK */
--	buf[0] = mt312_div((state->frequency == 60 ? MT312_LPOWER_SYS_CLK : MT312_SYS_CLK) * 2, 1000000);
-+	buf[0] = mt312_div((state->frequency == 60 ? MT312_LPOWER_SYS_CLK :
-+				MT312_SYS_CLK) * 2, 1000000);
- 
- 	/* DISEQC_RATIO */
- 	buf[1] = mt312_div(MT312_PLL_CLK, 15000 * 4);
- 
--	if ((ret = mt312_write(state, SYS_CLK, buf, sizeof(buf))) < 0)
-+	ret = mt312_write(state, SYS_CLK, buf, sizeof(buf));
-+	if (ret < 0)
- 		return ret;
- 
--	if ((ret = mt312_writereg(state, SNR_THS_HIGH, 0x32)) < 0)
-+	ret = mt312_writereg(state, SNR_THS_HIGH, 0x32);
-+	if (ret < 0)
- 		return ret;
- 
--	if ((ret = mt312_writereg(state, OP_CTRL, 0x53)) < 0)
-+	ret = mt312_writereg(state, OP_CTRL, 0x53);
-+	if (ret < 0)
- 		return ret;
- 
- 	/* TS_SW_LIM */
- 	buf[0] = 0x8c;
- 	buf[1] = 0x98;
- 
--	if ((ret = mt312_write(state, TS_SW_LIM_L, buf, sizeof(buf))) < 0)
-+	ret = mt312_write(state, TS_SW_LIM_L, buf, sizeof(buf));
-+	if (ret < 0)
- 		return ret;
- 
--	if ((ret = mt312_writereg(state, CS_SW_LIM, 0x69)) < 0)
-+	ret = mt312_writereg(state, CS_SW_LIM, 0x69);
-+	if (ret < 0)
- 		return ret;
- 
- 	return 0;
- }
- 
--static int mt312_send_master_cmd(struct dvb_frontend* fe,
-+static int mt312_send_master_cmd(struct dvb_frontend *fe,
- 				 struct dvb_diseqc_master_cmd *c)
- {
- 	struct mt312_state *state = fe->demodulator_priv;
-@@ -288,29 +309,31 @@ static int mt312_send_master_cmd(struct dvb_frontend* fe,
- 	if ((c->msg_len == 0) || (c->msg_len > sizeof(c->msg)))
- 		return -EINVAL;
- 
--	if ((ret = mt312_readreg(state, DISEQC_MODE, &diseqc_mode)) < 0)
-+	ret = mt312_readreg(state, DISEQC_MODE, &diseqc_mode);
-+	if (ret < 0)
- 		return ret;
- 
--	if ((ret =
--	     mt312_write(state, (0x80 | DISEQC_INSTR), c->msg, c->msg_len)) < 0)
-+	ret = mt312_write(state, (0x80 | DISEQC_INSTR), c->msg, c->msg_len);
-+	if (ret < 0)
- 		return ret;
- 
--	if ((ret =
--	     mt312_writereg(state, DISEQC_MODE,
--			    (diseqc_mode & 0x40) | ((c->msg_len - 1) << 3)
--			    | 0x04)) < 0)
-+	ret = mt312_writereg(state, DISEQC_MODE,
-+			     (diseqc_mode & 0x40) | ((c->msg_len - 1) << 3)
-+			     | 0x04);
-+	if (ret < 0)
- 		return ret;
- 
- 	/* set DISEQC_MODE[2:0] to zero if a return message is expected */
--	if (c->msg[0] & 0x02)
--		if ((ret =
--		     mt312_writereg(state, DISEQC_MODE, (diseqc_mode & 0x40))) < 0)
-+	if (c->msg[0] & 0x02) {
-+		ret = mt312_writereg(state, DISEQC_MODE, (diseqc_mode & 0x40));
-+		if (ret < 0)
- 			return ret;
-+	}
- 
- 	return 0;
- }
- 
--static int mt312_send_burst(struct dvb_frontend* fe, const fe_sec_mini_cmd_t c)
-+static int mt312_send_burst(struct dvb_frontend *fe, const fe_sec_mini_cmd_t c)
- {
- 	struct mt312_state *state = fe->demodulator_priv;
- 	const u8 mini_tab[2] = { 0x02, 0x03 };
-@@ -321,18 +344,19 @@ static int mt312_send_burst(struct dvb_frontend* fe, const fe_sec_mini_cmd_t c)
- 	if (c > SEC_MINI_B)
- 		return -EINVAL;
- 
--	if ((ret = mt312_readreg(state, DISEQC_MODE, &diseqc_mode)) < 0)
-+	ret = mt312_readreg(state, DISEQC_MODE, &diseqc_mode);
-+	if (ret < 0)
- 		return ret;
- 
--	if ((ret =
--	     mt312_writereg(state, DISEQC_MODE,
--			    (diseqc_mode & 0x40) | mini_tab[c])) < 0)
-+	ret = mt312_writereg(state, DISEQC_MODE,
-+			     (diseqc_mode & 0x40) | mini_tab[c]);
-+	if (ret < 0)
- 		return ret;
- 
- 	return 0;
- }
- 
--static int mt312_set_tone(struct dvb_frontend* fe, const fe_sec_tone_mode_t t)
-+static int mt312_set_tone(struct dvb_frontend *fe, const fe_sec_tone_mode_t t)
- {
- 	struct mt312_state *state = fe->demodulator_priv;
- 	const u8 tone_tab[2] = { 0x01, 0x00 };
-@@ -343,18 +367,19 @@ static int mt312_set_tone(struct dvb_frontend* fe, const fe_sec_tone_mode_t t)
- 	if (t > SEC_TONE_OFF)
- 		return -EINVAL;
- 
--	if ((ret = mt312_readreg(state, DISEQC_MODE, &diseqc_mode)) < 0)
-+	ret = mt312_readreg(state, DISEQC_MODE, &diseqc_mode);
-+	if (ret < 0)
- 		return ret;
- 
--	if ((ret =
--	     mt312_writereg(state, DISEQC_MODE,
--			    (diseqc_mode & 0x40) | tone_tab[t])) < 0)
-+	ret = mt312_writereg(state, DISEQC_MODE,
-+			     (diseqc_mode & 0x40) | tone_tab[t]);
-+	if (ret < 0)
- 		return ret;
- 
- 	return 0;
- }
- 
--static int mt312_set_voltage(struct dvb_frontend* fe, const fe_sec_voltage_t v)
-+static int mt312_set_voltage(struct dvb_frontend *fe, const fe_sec_voltage_t v)
- {
- 	struct mt312_state *state = fe->demodulator_priv;
- 	const u8 volt_tab[3] = { 0x00, 0x40, 0x00 };
-@@ -365,7 +390,7 @@ static int mt312_set_voltage(struct dvb_frontend* fe, const fe_sec_voltage_t v)
- 	return mt312_writereg(state, DISEQC_MODE, volt_tab[v]);
- }
- 
--static int mt312_read_status(struct dvb_frontend* fe, fe_status_t *s)
-+static int mt312_read_status(struct dvb_frontend *fe, fe_status_t *s)
- {
- 	struct mt312_state *state = fe->demodulator_priv;
- 	int ret;
-@@ -373,10 +398,12 @@ static int mt312_read_status(struct dvb_frontend* fe, fe_status_t *s)
- 
- 	*s = 0;
- 
--	if ((ret = mt312_read(state, QPSK_STAT_H, status, sizeof(status))) < 0)
-+	ret = mt312_read(state, QPSK_STAT_H, status, sizeof(status));
-+	if (ret < 0)
- 		return ret;
- 
--	dprintk(KERN_DEBUG "QPSK_STAT_H: 0x%02x, QPSK_STAT_L: 0x%02x, FEC_STATUS: 0x%02x\n", status[0], status[1], status[2]);
-+	dprintk("QPSK_STAT_H: 0x%02x, QPSK_STAT_L: 0x%02x,"
-+		" FEC_STATUS: 0x%02x\n", status[0], status[1], status[2]);
- 
- 	if (status[0] & 0xc0)
- 		*s |= FE_HAS_SIGNAL;	/* signal noise ratio */
-@@ -392,13 +419,14 @@ static int mt312_read_status(struct dvb_frontend* fe, fe_status_t *s)
- 	return 0;
- }
- 
--static int mt312_read_ber(struct dvb_frontend* fe, u32 *ber)
-+static int mt312_read_ber(struct dvb_frontend *fe, u32 *ber)
- {
- 	struct mt312_state *state = fe->demodulator_priv;
- 	int ret;
- 	u8 buf[3];
- 
--	if ((ret = mt312_read(state, RS_BERCNT_H, buf, 3)) < 0)
-+	ret = mt312_read(state, RS_BERCNT_H, buf, 3);
-+	if (ret < 0)
- 		return ret;
- 
- 	*ber = ((buf[0] << 16) | (buf[1] << 8) | buf[2]) * 64;
-@@ -406,7 +434,8 @@ static int mt312_read_ber(struct dvb_frontend* fe, u32 *ber)
- 	return 0;
- }
- 
--static int mt312_read_signal_strength(struct dvb_frontend* fe, u16 *signal_strength)
-+static int mt312_read_signal_strength(struct dvb_frontend *fe,
-+				      u16 *signal_strength)
- {
- 	struct mt312_state *state = fe->demodulator_priv;
- 	int ret;
-@@ -414,7 +443,8 @@ static int mt312_read_signal_strength(struct dvb_frontend* fe, u16 *signal_stren
- 	u16 agc;
- 	s16 err_db;
- 
--	if ((ret = mt312_read(state, AGC_H, buf, sizeof(buf))) < 0)
-+	ret = mt312_read(state, AGC_H, buf, sizeof(buf));
-+	if (ret < 0)
- 		return ret;
- 
- 	agc = (buf[0] << 6) | (buf[1] >> 2);
-@@ -422,18 +452,19 @@ static int mt312_read_signal_strength(struct dvb_frontend* fe, u16 *signal_stren
- 
- 	*signal_strength = agc;
- 
--	dprintk(KERN_DEBUG "agc=%08x err_db=%hd\n", agc, err_db);
-+	dprintk("agc=%08x err_db=%hd\n", agc, err_db);
- 
- 	return 0;
- }
- 
--static int mt312_read_snr(struct dvb_frontend* fe, u16 *snr)
-+static int mt312_read_snr(struct dvb_frontend *fe, u16 *snr)
- {
- 	struct mt312_state *state = fe->demodulator_priv;
- 	int ret;
- 	u8 buf[2];
- 
--	if ((ret = mt312_read(state, M_SNR_H, &buf, sizeof(buf))) < 0)
-+	ret = mt312_read(state, M_SNR_H, &buf, sizeof(buf));
-+	if (ret < 0)
- 		return ret;
- 
- 	*snr = 0xFFFF - ((((buf[0] & 0x7f) << 8) | buf[1]) << 1);
-@@ -441,13 +472,14 @@ static int mt312_read_snr(struct dvb_frontend* fe, u16 *snr)
- 	return 0;
- }
- 
--static int mt312_read_ucblocks(struct dvb_frontend* fe, u32 *ubc)
-+static int mt312_read_ucblocks(struct dvb_frontend *fe, u32 *ubc)
- {
- 	struct mt312_state *state = fe->demodulator_priv;
- 	int ret;
- 	u8 buf[2];
- 
--	if ((ret = mt312_read(state, RS_UBC_H, &buf, sizeof(buf))) < 0)
-+	ret = mt312_read(state, RS_UBC_H, &buf, sizeof(buf));
-+	if (ret < 0)
- 		return ret;
- 
- 	*ubc = (buf[0] << 8) | buf[1];
-@@ -455,7 +487,7 @@ static int mt312_read_ucblocks(struct dvb_frontend* fe, u32 *ubc)
- 	return 0;
- }
- 
--static int mt312_set_frontend(struct dvb_frontend* fe,
-+static int mt312_set_frontend(struct dvb_frontend *fe,
- 			      struct dvb_frontend_parameters *p)
- {
- 	struct mt312_state *state = fe->demodulator_priv;
-@@ -491,24 +523,28 @@ static int mt312_set_frontend(struct dvb_frontend* fe,
- 
- 	switch (state->id) {
- 	case ID_VP310:
--	// For now we will do this only for the VP310.
--	// It should be better for the mt312 as well, but tunning will be slower. ACCJr 09/29/03
-+	/* For now we will do this only for the VP310.
-+	 * It should be better for the mt312 as well,
-+	 * but tuning will be slower. ACCJr 09/29/03
-+	 */
- 		ret = mt312_readreg(state, CONFIG, &config_val);
- 		if (ret < 0)
- 			return ret;
--		if (p->u.qpsk.symbol_rate >= 30000000) //Note that 30MS/s should use 90MHz
--		{
--			if ((config_val & 0x0c) == 0x08) { //We are running 60MHz
-+		if (p->u.qpsk.symbol_rate >= 30000000) {
-+			/* Note that 30MS/s should use 90MHz */
-+			if ((config_val & 0x0c) == 0x08) {
-+				/* We are running 60MHz */
- 				state->frequency = 90;
--				if ((ret = mt312_initfe(fe)) < 0)
-+				ret = mt312_initfe(fe);
-+				if (ret < 0)
- 					return ret;
- 			}
--		}
--		else
--		{
--			if ((config_val & 0x0c) == 0x0C) { //We are running 90MHz
-+		} else {
-+			if ((config_val & 0x0c) == 0x0C) {
-+				/* We are running 90MHz */
- 				state->frequency = 60;
--				if ((ret = mt312_initfe(fe)) < 0)
-+				ret = mt312_initfe(fe);
-+				if (ret < 0)
- 					return ret;
- 			}
- 		}
-@@ -523,7 +559,8 @@ static int mt312_set_frontend(struct dvb_frontend* fe,
- 
- 	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.i2c_gate_ctrl)
-+			fe->ops.i2c_gate_ctrl(fe, 0);
- 	}
- 
- 	/* sr = (u16)(sr * 256.0 / 1000000.0) */
-@@ -545,7 +582,8 @@ static int mt312_set_frontend(struct dvb_frontend* fe,
- 	/* GO */
- 	buf[4] = 0x01;
- 
--	if ((ret = mt312_write(state, SYM_RATE_H, buf, sizeof(buf))) < 0)
-+	ret = mt312_write(state, SYM_RATE_H, buf, sizeof(buf));
-+	if (ret < 0)
- 		return ret;
- 
- 	mt312_reset(state, 0);
-@@ -553,27 +591,30 @@ static int mt312_set_frontend(struct dvb_frontend* fe,
- 	return 0;
- }
- 
--static int mt312_get_frontend(struct dvb_frontend* fe,
-+static int mt312_get_frontend(struct dvb_frontend *fe,
- 			      struct dvb_frontend_parameters *p)
- {
- 	struct mt312_state *state = fe->demodulator_priv;
- 	int ret;
- 
--	if ((ret = mt312_get_inversion(state, &p->inversion)) < 0)
-+	ret = mt312_get_inversion(state, &p->inversion);
-+	if (ret < 0)
- 		return ret;
- 
--	if ((ret = mt312_get_symbol_rate(state, &p->u.qpsk.symbol_rate)) < 0)
-+	ret = mt312_get_symbol_rate(state, &p->u.qpsk.symbol_rate);
-+	if (ret < 0)
- 		return ret;
- 
--	if ((ret = mt312_get_code_rate(state, &p->u.qpsk.fec_inner)) < 0)
-+	ret = mt312_get_code_rate(state, &p->u.qpsk.fec_inner);
-+	if (ret < 0)
- 		return ret;
- 
- 	return 0;
- }
- 
--static int mt312_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
-+static int mt312_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
- {
--	struct mt312_state* state = fe->demodulator_priv;
-+	struct mt312_state *state = fe->demodulator_priv;
- 
- 	if (enable) {
- 		return mt312_writereg(state, GPP_CTRL, 0x40);
-@@ -582,27 +623,31 @@ static int mt312_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
- 	}
- }
- 
--static int mt312_sleep(struct dvb_frontend* fe)
-+static int mt312_sleep(struct dvb_frontend *fe)
- {
- 	struct mt312_state *state = fe->demodulator_priv;
- 	int ret;
- 	u8 config;
- 
- 	/* reset all registers to defaults */
--	if ((ret = mt312_reset(state, 1)) < 0)
-+	ret = mt312_reset(state, 1);
-+	if (ret < 0)
- 		return ret;
- 
--	if ((ret = mt312_readreg(state, CONFIG, &config)) < 0)
-+	ret = mt312_readreg(state, CONFIG, &config);
-+	if (ret < 0)
- 		return ret;
- 
- 	/* enter standby */
--	if ((ret = mt312_writereg(state, CONFIG, config & 0x7f)) < 0)
-+	ret = mt312_writereg(state, CONFIG, config & 0x7f);
-+	if (ret < 0)
- 		return ret;
- 
- 	return 0;
- }
- 
--static int mt312_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
-+static int mt312_get_tune_settings(struct dvb_frontend *fe,
-+		struct dvb_frontend_tune_settings *fesettings)
- {
- 	fesettings->min_delay_ms = 50;
- 	fesettings->step_size = 0;
-@@ -610,9 +655,9 @@ static int mt312_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_
- 	return 0;
- }
- 
--static void mt312_release(struct dvb_frontend* fe)
-+static void mt312_release(struct dvb_frontend *fe)
- {
--	struct mt312_state* state = fe->demodulator_priv;
-+	struct mt312_state *state = fe->demodulator_priv;
- 	kfree(state);
- }
- 
-@@ -655,10 +700,10 @@ static struct dvb_frontend_ops vp310_mt312_ops = {
- 	.set_voltage = mt312_set_voltage,
- };
- 
--struct dvb_frontend* vp310_mt312_attach(const struct mt312_config* config,
--					struct i2c_adapter* i2c)
-+struct dvb_frontend *vp310_mt312_attach(const struct mt312_config *config,
-+					struct i2c_adapter *i2c)
- {
--	struct mt312_state* state = NULL;
-+	struct mt312_state *state = NULL;
- 
- 	/* allocate memory for the internal state */
- 	state = kmalloc(sizeof(struct mt312_state), GFP_KERNEL);
-@@ -674,7 +719,8 @@ struct dvb_frontend* vp310_mt312_attach(const struct mt312_config* config,
- 		goto error;
- 
- 	/* create dvb_frontend */
--	memcpy(&state->frontend.ops, &vp310_mt312_ops, sizeof(struct dvb_frontend_ops));
-+	memcpy(&state->frontend.ops, &vp310_mt312_ops,
-+		sizeof(struct dvb_frontend_ops));
- 	state->frontend.demodulator_priv = state;
- 
- 	switch (state->id) {
-@@ -687,7 +733,8 @@ struct dvb_frontend* vp310_mt312_attach(const struct mt312_config* config,
- 		state->frequency = 60;
- 		break;
- 	default:
--		printk (KERN_WARNING "Only Zarlink VP310/MT312 are supported chips.\n");
-+		printk(KERN_WARNING "Only Zarlink VP310/MT312"
-+			" are supported chips.\n");
- 		goto error;
- 	}
- 
-@@ -697,6 +744,7 @@ error:
- 	kfree(state);
- 	return NULL;
- }
-+EXPORT_SYMBOL(vp310_mt312_attach);
- 
- module_param(debug, int, 0644);
- MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
-@@ -705,4 +753,3 @@ MODULE_DESCRIPTION("Zarlink VP310/MT312 DVB-S Demodulator driver");
- MODULE_AUTHOR("Andreas Oberritter <obi at linuxtv.org>");
- MODULE_LICENSE("GPL");
- 
--EXPORT_SYMBOL(vp310_mt312_attach);
-diff --git a/drivers/media/dvb/frontends/mt312.h b/drivers/media/dvb/frontends/mt312.h
-index cf9a150..f17cb93 100644
---- a/drivers/media/dvb/frontends/mt312.h
-+++ b/drivers/media/dvb/frontends/mt312.h
-@@ -28,22 +28,21 @@
- 
- #include <linux/dvb/frontend.h>
- 
--struct mt312_config
--{
-+struct mt312_config {
- 	/* the demodulator's i2c address */
- 	u8 demod_address;
- };
- 
- #if defined(CONFIG_DVB_MT312) || (defined(CONFIG_DVB_MT312_MODULE) && defined(MODULE))
--struct dvb_frontend* vp310_mt312_attach(const struct mt312_config* config,
--					struct i2c_adapter* i2c);
-+struct dvb_frontend *vp310_mt312_attach(const struct mt312_config *config,
-+					struct i2c_adapter *i2c);
- #else
--static inline struct dvb_frontend* vp310_mt312_attach(const struct mt312_config* config,
--					struct i2c_adapter* i2c)
-+static inline struct dvb_frontend *vp310_mt312_attach(
-+	const struct mt312_config *config, struct i2c_adapter *i2c)
- {
- 	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
- 	return NULL;
- }
--#endif // CONFIG_DVB_MT312
-+#endif /* CONFIG_DVB_MT312 */
- 
--#endif // MT312_H
-+#endif /* MT312_H */
-diff --git a/drivers/media/dvb/frontends/mt352.c b/drivers/media/dvb/frontends/mt352.c
-index 5dd9b73..7cd190b 100644
---- a/drivers/media/dvb/frontends/mt352.c
-+++ b/drivers/media/dvb/frontends/mt352.c
-@@ -152,7 +152,13 @@ static void mt352_calc_input_freq(struct mt352_state* state,
- 	if (state->config.if2)
- 		if2 = state->config.if2;
- 
--	ife = (2*adc_clock - if2);
-+	if (adc_clock >= if2 * 2)
-+		ife = if2;
-+	else {
-+		ife = adc_clock - (if2 % adc_clock);
-+		if (ife > adc_clock / 2)
-+			ife = adc_clock - ife;
++	/* set cal mode to RF tracking filter calibration */
++	regs[R_EP4]  |= 0x03;
++
++	/* calculate cal pll */
++
++	switch (priv->mode) {
++	case TDA18271_ANALOG:
++		N = freq - 1250000;
++		break;
++	case TDA18271_DIGITAL:
++		N = freq + bw / 2;
++		break;
 +	}
- 	value = -16374 * ife / adc_clock;
- 	dprintk("%s: if2 %d, ife %d, adc_clock %d => %d / 0x%x\n",
- 		__FUNCTION__, if2, ife, adc_clock, value, value & 0x3fff);
-diff --git a/drivers/media/dvb/frontends/or51132.c b/drivers/media/dvb/frontends/or51132.c
-index b314a1f..1d2d28c 100644
---- a/drivers/media/dvb/frontends/or51132.c
-+++ b/drivers/media/dvb/frontends/or51132.c
-@@ -564,7 +564,7 @@ struct dvb_frontend* or51132_attach(const struct or51132_config* config,
- 	/* Allocate memory for the internal state */
- 	state = kmalloc(sizeof(struct or51132_state), GFP_KERNEL);
- 	if (state == NULL)
--		goto error;
-+		return NULL;
- 
- 	/* Setup the state */
- 	state->config = config;
-@@ -576,10 +576,6 @@ struct dvb_frontend* or51132_attach(const struct or51132_config* config,
- 	memcpy(&state->frontend.ops, &or51132_ops, sizeof(struct dvb_frontend_ops));
- 	state->frontend.demodulator_priv = state;
- 	return &state->frontend;
--
--error:
--	kfree(state);
--	return NULL;
- }
- 
- static struct dvb_frontend_ops or51132_ops = {
-diff --git a/drivers/media/dvb/frontends/or51211.c b/drivers/media/dvb/frontends/or51211.c
-index f02bd94..6a6b0d7 100644
---- a/drivers/media/dvb/frontends/or51211.c
-+++ b/drivers/media/dvb/frontends/or51211.c
-@@ -529,7 +529,7 @@ struct dvb_frontend* or51211_attach(const struct or51211_config* config,
- 	/* Allocate memory for the internal state */
- 	state = kmalloc(sizeof(struct or51211_state), GFP_KERNEL);
- 	if (state == NULL)
--		goto error;
-+		return NULL;
- 
- 	/* Setup the state */
- 	state->config = config;
-@@ -541,10 +541,6 @@ struct dvb_frontend* or51211_attach(const struct or51211_config* config,
- 	memcpy(&state->frontend.ops, &or51211_ops, sizeof(struct dvb_frontend_ops));
- 	state->frontend.demodulator_priv = state;
- 	return &state->frontend;
--
--error:
--	kfree(state);
--	return NULL;
- }
- 
- static struct dvb_frontend_ops or51211_ops = {
-diff --git a/drivers/media/dvb/frontends/s5h1409.c b/drivers/media/dvb/frontends/s5h1409.c
-index 562d920..8194334 100644
---- a/drivers/media/dvb/frontends/s5h1409.c
-+++ b/drivers/media/dvb/frontends/s5h1409.c
-@@ -42,6 +42,7 @@ struct s5h1409_state {
- 	fe_modulation_t current_modulation;
- 
- 	u32 current_frequency;
-+	int if_freq;
- 
- 	u32 is_qam_locked;
- 	u32 qam_state;
-@@ -97,7 +98,7 @@ static struct init_tab {
- 	{ 0xac, 0x1003, },
- 	{ 0xad, 0x103f, },
- 	{ 0xe2, 0x0100, },
--	{ 0xe3, 0x0000, },
-+	{ 0xe3, 0x1000, },
- 	{ 0x28, 0x1010, },
- 	{ 0xb1, 0x000e, },
- };
-@@ -348,28 +349,32 @@ static int s5h1409_softreset(struct dvb_frontend* fe)
- 	return 0;
- }
- 
-+#define S5H1409_VSB_IF_FREQ 5380
-+#define S5H1409_QAM_IF_FREQ state->config->qam_if
 +
- static int s5h1409_set_if_freq(struct dvb_frontend* fe, int KHz)
- {
- 	struct s5h1409_state* state = fe->demodulator_priv;
--	int ret = 0;
- 
- 	dprintk("%s(%d KHz)\n", __FUNCTION__, KHz);
- 
--	if( (KHz == 44000) || (KHz == 5380) ) {
--		s5h1409_writereg(state, 0x87, 0x01be);
--		s5h1409_writereg(state, 0x88, 0x0436);
--		s5h1409_writereg(state, 0x89, 0x054d);
--	} else
--	if (KHz == 4000) {
-+	switch (KHz) {
-+	case 4000:
- 		s5h1409_writereg(state, 0x87, 0x014b);
- 		s5h1409_writereg(state, 0x88, 0x0cb5);
- 		s5h1409_writereg(state, 0x89, 0x03e2);
--	} else {
--		printk("%s() Invalid arg = %d KHz\n", __FUNCTION__, KHz);
--		ret = -1;
++	tda18271_calc_cal_pll(fe, N);
++
++	/* calculate main pll */
++
++	switch (priv->mode) {
++	case TDA18271_ANALOG:
++		N = freq - 250000;
 +		break;
-+	case 5380:
-+	case 44000:
-+	default:
-+		s5h1409_writereg(state, 0x87, 0x01be);
-+		s5h1409_writereg(state, 0x88, 0x0436);
-+		s5h1409_writereg(state, 0x89, 0x054d);
++	case TDA18271_DIGITAL:
++		N = freq + bw / 2 + 1000000;
 +		break;
- 	}
-+	state->if_freq = KHz;
- 
--	return ret;
-+	return 0;
- }
- 
- static int s5h1409_set_spectralinversion(struct dvb_frontend* fe, int inverted)
-@@ -394,11 +399,15 @@ static int s5h1409_enable_modulation(struct dvb_frontend* fe,
- 	switch(m) {
- 	case VSB_8:
- 		dprintk("%s() VSB_8\n", __FUNCTION__);
-+		if (state->if_freq != S5H1409_VSB_IF_FREQ)
-+			s5h1409_set_if_freq(fe, S5H1409_VSB_IF_FREQ);
- 		s5h1409_writereg(state, 0xf4, 0);
- 		break;
- 	case QAM_64:
- 	case QAM_256:
- 		dprintk("%s() QAM_AUTO (64/256)\n", __FUNCTION__);
-+		if (state->if_freq != S5H1409_QAM_IF_FREQ)
-+			s5h1409_set_if_freq(fe, S5H1409_QAM_IF_FREQ);
- 		s5h1409_writereg(state, 0xf4, 1);
- 		s5h1409_writereg(state, 0x85, 0x110);
- 		break;
-@@ -432,9 +441,11 @@ static int s5h1409_set_gpio(struct dvb_frontend* fe, int enable)
- 	dprintk("%s(%d)\n", __FUNCTION__, enable);
- 
- 	if (enable)
--		return s5h1409_writereg(state, 0xe3, 0x1100);
-+		return s5h1409_writereg(state, 0xe3,
-+			s5h1409_readreg(state, 0xe3) | 0x1100);
- 	else
--		return s5h1409_writereg(state, 0xe3, 0x1000);
-+		return s5h1409_writereg(state, 0xe3,
-+			s5h1409_readreg(state, 0xe3) & 0xeeff);
- }
- 
- static int s5h1409_sleep(struct dvb_frontend* fe, int enable)
-@@ -504,13 +515,15 @@ static void s5h1409_set_qam_interleave_mode(struct dvb_frontend *fe)
- 			s5h1409_writereg(state, 0x96, 0x20);
- 			s5h1409_writereg(state, 0xad,
- 				( ((reg1 & 0xf000) >> 4) | (reg2 & 0xf0ff)) );
--			s5h1409_writereg(state, 0xab, 0x1100);
-+			s5h1409_writereg(state, 0xab,
-+				s5h1409_readreg(state, 0xab) & 0xeffe);
- 		}
- 	} else {
- 		if (state->qam_state != 1) {
- 			state->qam_state = 1;
- 			s5h1409_writereg(state, 0x96, 0x08);
--			s5h1409_writereg(state, 0xab, 0x1101);
-+			s5h1409_writereg(state, 0xab,
-+				s5h1409_readreg(state, 0xab) | 0x1001);
- 		}
- 	}
- }
-@@ -547,6 +560,36 @@ static int s5h1409_set_frontend (struct dvb_frontend* fe,
- 	return 0;
- }
- 
-+static int s5h1409_set_mpeg_timing(struct dvb_frontend *fe, int mode)
-+{
-+	struct s5h1409_state *state = fe->demodulator_priv;
-+	u16 val;
++	}
++
++	tda18271_calc_main_pll(fe, N);
++
++	tda18271_write_regs(fe, R_EP3, 11);
++	msleep(5); /* RF tracking filter calibration initialization */
++
++	/* search for K,M,CO for RF calibration */
++	tda18271_calc_km(fe, &freq);
++	tda18271_write_regs(fe, R_EB13, 1);
++
++	/* search for rf band */
++	tda18271_calc_rf_band(fe, &freq);
++
++	/* search for gain taper */
++	tda18271_calc_gain_taper(fe, &freq);
++
++	tda18271_write_regs(fe, R_EP2, 1);
++	tda18271_write_regs(fe, R_EP1, 1);
++	tda18271_write_regs(fe, R_EP2, 1);
++	tda18271_write_regs(fe, R_EP1, 1);
++
++	regs[R_EB4]  &= 0x07;
++	regs[R_EB4]  |= 0x40;
++	tda18271_write_regs(fe, R_EB4, 1);
 +
-+	dprintk("%s(%d)\n", __FUNCTION__, mode);
++	regs[R_EB7]   = 0x40;
++	tda18271_write_regs(fe, R_EB7, 1);
++	msleep(10);
 +
-+	val = s5h1409_readreg(state, 0xac) & 0xcfff;
-+	switch (mode) {
-+	case S5H1409_MPEGTIMING_CONTINOUS_INVERTING_CLOCK:
-+		val |= 0x0000;
++	regs[R_EB20]  = 0xec;
++	tda18271_write_regs(fe, R_EB20, 1);
++	msleep(60); /* RF tracking filter calibration completion */
++
++	regs[R_EP4]  &= ~0x03; /* set cal mode to normal */
++	tda18271_write_regs(fe, R_EP4, 1);
++
++	tda18271_write_regs(fe, R_EP1, 1);
++
++	/* RF tracking filter correction for VHF_Low band */
++	if (0 == tda18271_calc_rf_cal(fe, &freq))
++		tda18271_write_regs(fe, R_EB14, 1);
++
++	/* Channel Configuration */
++
++	switch (priv->mode) {
++	case TDA18271_ANALOG:
++		regs[R_EB22]  = 0x2c;
 +		break;
-+	case S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK:
-+		dprintk("%s(%d) Mode1 or Defaulting\n", __FUNCTION__, mode);
-+		val |= 0x1000;
++	case TDA18271_DIGITAL:
++		regs[R_EB22]  = 0x37;
 +		break;
-+	case S5H1409_MPEGTIMING_NONCONTINOUS_INVERTING_CLOCK:
-+		val |= 0x2000;
++	}
++	tda18271_write_regs(fe, R_EB22, 1);
++
++	regs[R_EP1]  |= 0x40; /* set dis power level on */
++
++	/* set standard */
++	regs[R_EP3]  &= ~0x1f; /* clear std bits */
++
++	/* see table 22 */
++	regs[R_EP3]  |= std;
++
++	regs[R_EP4]  &= ~0x03; /* set cal mode to normal */
++
++	regs[R_EP4]  &= ~0x1c; /* clear if level bits */
++	switch (priv->mode) {
++	case TDA18271_ANALOG:
++		regs[R_MPD]  &= ~0x80; /* IF notch = 0 */
 +		break;
-+	case S5H1409_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK:
-+		val |= 0x3000;
++	case TDA18271_DIGITAL:
++		regs[R_EP4]  |= 0x04;
++		regs[R_MPD]  |= 0x80;
 +		break;
-+	default:
-+		return -EINVAL;
 +	}
 +
-+	/* Configure MPEG Signal Timing charactistics */
-+	return s5h1409_writereg(state, 0xac, val);
-+}
++	if (radio)
++		regs[R_EP4]  |=  0x80;
++	else
++		regs[R_EP4]  &= ~0x80;
 +
- /* Reset the demod hardware and reset all of the configuration registers
-    to a default state. */
- static int s5h1409_init (struct dvb_frontend* fe)
-@@ -566,13 +609,16 @@ static int s5h1409_init (struct dvb_frontend* fe)
- 	state->current_modulation = VSB_8;
- 
- 	if (state->config->output_mode == S5H1409_SERIAL_OUTPUT)
--		s5h1409_writereg(state, 0xab, 0x100); /* Serial */
-+		s5h1409_writereg(state, 0xab,
-+			s5h1409_readreg(state, 0xab) | 0x100); /* Serial */
- 	else
--		s5h1409_writereg(state, 0xab, 0x0); /* Parallel */
-+		s5h1409_writereg(state, 0xab,
-+			s5h1409_readreg(state, 0xab) & 0xfeff); /* Parallel */
- 
- 	s5h1409_set_spectralinversion(fe, state->config->inversion);
--	s5h1409_set_if_freq(fe, state->config->if_freq);
-+	s5h1409_set_if_freq(fe, state->if_freq);
- 	s5h1409_set_gpio(fe, state->config->gpio);
-+	s5h1409_set_mpeg_timing(fe, state->config->mpeg_timing);
- 	s5h1409_softreset(fe);
- 
- 	/* Note: Leaving the I2C gate closed. */
-@@ -741,6 +787,7 @@ struct dvb_frontend* s5h1409_attach(const struct s5h1409_config* config,
- 				    struct i2c_adapter* i2c)
- {
- 	struct s5h1409_state* state = NULL;
-+	u16 reg;
- 
- 	/* allocate memory for the internal state */
- 	state = kmalloc(sizeof(struct s5h1409_state), GFP_KERNEL);
-@@ -751,9 +798,11 @@ struct dvb_frontend* s5h1409_attach(const struct s5h1409_config* config,
- 	state->config = config;
- 	state->i2c = i2c;
- 	state->current_modulation = 0;
-+	state->if_freq = S5H1409_VSB_IF_FREQ;
- 
- 	/* check if the demod exists */
--	if (s5h1409_readreg(state, 0x04) != 0x0066)
-+	reg = s5h1409_readreg(state, 0x04);
-+	if ((reg != 0x0066) && (reg != 0x007f))
- 		goto error;
- 
- 	/* create dvb_frontend */
-@@ -761,8 +810,14 @@ struct dvb_frontend* s5h1409_attach(const struct s5h1409_config* config,
- 	       sizeof(struct dvb_frontend_ops));
- 	state->frontend.demodulator_priv = state;
- 
-+	if (s5h1409_init(&state->frontend) != 0) {
-+		printk(KERN_ERR "%s: Failed to initialize correctly\n",
-+			__FUNCTION__);
-+		goto error;
-+	}
++	/* image rejection validity */
++	tda18271_calc_ir_measure(fe, &freq);
 +
- 	/* Note: Leaving the I2C gate open here. */
--	s5h1409_writereg(state, 0xf3, 1);
-+	s5h1409_i2c_gate_ctrl(&state->frontend, 1);
- 
- 	return &state->frontend;
- 
-diff --git a/drivers/media/dvb/frontends/s5h1409.h b/drivers/media/dvb/frontends/s5h1409.h
-index 20f9af1..f0bb13f 100644
---- a/drivers/media/dvb/frontends/s5h1409.h
-+++ b/drivers/media/dvb/frontends/s5h1409.h
-@@ -39,8 +39,8 @@ struct s5h1409_config
- #define S5H1409_GPIO_ON  1
- 	u8 gpio;
- 
--	/* IF Freq in KHz */
--	u16 if_freq;
-+	/* IF Freq for QAM in KHz, VSB is hardcoded to 5380 */
-+	u16 qam_if;
- 
- 	/* Spectral Inversion */
- #define S5H1409_INVERSION_OFF 0
-@@ -51,6 +51,13 @@ struct s5h1409_config
- #define S5H1409_TUNERLOCKING 0
- #define S5H1409_DEMODLOCKING 1
- 	u8 status_mode;
++	/* calculate MAIN PLL */
++	N = freq + ifc;
 +
-+	/* MPEG signal timing */
-+#define S5H1409_MPEGTIMING_CONTINOUS_INVERTING_CLOCK       0
-+#define S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK    1
-+#define S5H1409_MPEGTIMING_NONCONTINOUS_INVERTING_CLOCK    2
-+#define S5H1409_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK 3
-+	u16 mpeg_timing;
- };
- 
- #if defined(CONFIG_DVB_S5H1409) || (defined(CONFIG_DVB_S5H1409_MODULE) && defined(MODULE))
-diff --git a/drivers/media/dvb/frontends/tda18271-common.c b/drivers/media/dvb/frontends/tda18271-common.c
-new file mode 100644
-index 0000000..cebb6b9
---- /dev/null
-+++ b/drivers/media/dvb/frontends/tda18271-common.c
-@@ -0,0 +1,653 @@
-+/*
-+    tda18271-common.c - driver for the Philips / NXP TDA18271 silicon tuner
++	tda18271_calc_main_pll(fe, N);
 +
-+    Copyright (C) 2007, 2008 Michael Krufky <mkrufky at linuxtv.org>
++	tda18271_write_regs(fe, R_TM, 15);
++	msleep(5);
++	mutex_unlock(&priv->lock);
 +
-+    This program is free software; you can redistribute it and/or modify
-+    it under the terms of the GNU General Public License as published by
-+    the Free Software Foundation; either version 2 of the License, or
-+    (at your option) any later version.
++	return 0;
++}
 +
-+    This program is distributed in the hope that it will be useful,
-+    but WITHOUT ANY WARRANTY; without even the implied warranty of
-+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+    GNU General Public License for more details.
++static inline int tda18271_tune(struct dvb_frontend *fe,
++				u32 ifc, u32 freq, u32 bw, u8 std, int radio)
++{
++	struct tda18271_priv *priv = fe->tuner_priv;
++	int ret = -EINVAL;
 +
-+    You 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.
-+*/
++	switch (priv->id) {
++	case TDA18271HDC1:
++		ret = tda18271c1_tune(fe, ifc, freq, bw, std, radio);
++		break;
++	case TDA18271HDC2:
++		ret = tda18271c2_tune(fe, ifc, freq, bw, std, radio);
++		break;
++	}
++	return ret;
++}
 +
-+#include "tda18271-priv.h"
++/* ------------------------------------------------------------------ */
 +
-+static int tda18271_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
++static int tda18271_set_params(struct dvb_frontend *fe,
++			       struct dvb_frontend_parameters *params)
 +{
 +	struct tda18271_priv *priv = fe->tuner_priv;
-+	enum tda18271_i2c_gate gate;
-+	int ret = 0;
++	struct tda18271_std_map *std_map = &priv->std;
++	int ret;
++	u8 std;
++	u16 sgIF;
++	u32 bw, freq = params->frequency;
 +
-+	switch (priv->gate) {
-+	case TDA18271_GATE_DIGITAL:
-+	case TDA18271_GATE_ANALOG:
-+		gate = priv->gate;
-+		break;
-+	case TDA18271_GATE_AUTO:
-+	default:
-+		switch (priv->mode) {
-+		case TDA18271_DIGITAL:
-+			gate = TDA18271_GATE_DIGITAL;
++	priv->mode = TDA18271_DIGITAL;
++
++	if (fe->ops.info.type == FE_ATSC) {
++		switch (params->u.vsb.modulation) {
++		case VSB_8:
++		case VSB_16:
++			std  = std_map->atsc_6.std_bits;
++			sgIF = std_map->atsc_6.if_freq;
++			break;
++		case QAM_64:
++		case QAM_256:
++			std  = std_map->qam_6.std_bits;
++			sgIF = std_map->qam_6.if_freq;
 +			break;
-+		case TDA18271_ANALOG:
 +		default:
-+			gate = TDA18271_GATE_ANALOG;
++			tda_warn("modulation not set!\n");
++			return -EINVAL;
++		}
++#if 0
++		/* userspace request is already center adjusted */
++		freq += 1750000; /* Adjust to center (+1.75MHZ) */
++#endif
++		bw = 6000000;
++	} else if (fe->ops.info.type == FE_OFDM) {
++		switch (params->u.ofdm.bandwidth) {
++		case BANDWIDTH_6_MHZ:
++			bw = 6000000;
++			std  = std_map->dvbt_6.std_bits;
++			sgIF = std_map->dvbt_6.if_freq;
++			break;
++		case BANDWIDTH_7_MHZ:
++			bw = 7000000;
++			std  = std_map->dvbt_7.std_bits;
++			sgIF = std_map->dvbt_7.if_freq;
++			break;
++		case BANDWIDTH_8_MHZ:
++			bw = 8000000;
++			std  = std_map->dvbt_8.std_bits;
++			sgIF = std_map->dvbt_8.if_freq;
 +			break;
++		default:
++			tda_warn("bandwidth not set!\n");
++			return -EINVAL;
 +		}
++	} else {
++		tda_warn("modulation type not supported!\n");
++		return -EINVAL;
 +	}
 +
-+	switch (gate) {
-+	case TDA18271_GATE_ANALOG:
-+		if (fe->ops.analog_ops.i2c_gate_ctrl)
-+			ret = fe->ops.analog_ops.i2c_gate_ctrl(fe, enable);
-+		break;
-+	case TDA18271_GATE_DIGITAL:
-+		if (fe->ops.i2c_gate_ctrl)
-+			ret = fe->ops.i2c_gate_ctrl(fe, enable);
-+		break;
-+	default:
-+		ret = -EINVAL;
-+		break;
-+	}
++	/* When tuning digital, the analog demod must be tri-stated */
++	if (fe->ops.analog_ops.standby)
++		fe->ops.analog_ops.standby(fe);
 +
-+	return ret;
-+};
++	ret = tda18271_tune(fe, sgIF * 1000, freq, bw, std, 0);
 +
-+/*---------------------------------------------------------------------*/
++	if (ret < 0)
++		goto fail;
 +
-+static void tda18271_dump_regs(struct dvb_frontend *fe, int extended)
++	priv->frequency = freq;
++	priv->bandwidth = (fe->ops.info.type == FE_OFDM) ?
++		params->u.ofdm.bandwidth : 0;
++fail:
++	return ret;
++}
++
++static int tda18271_set_analog_params(struct dvb_frontend *fe,
++				      struct analog_parameters *params)
 +{
 +	struct tda18271_priv *priv = fe->tuner_priv;
-+	unsigned char *regs = priv->tda18271_regs;
++	struct tda18271_std_map *std_map = &priv->std;
++	char *mode;
++	int ret, radio = 0;
++	u8 std;
++	u16 sgIF;
++	u32 freq = params->frequency * 62500;
 +
-+	tda_reg("=== TDA18271 REG DUMP ===\n");
-+	tda_reg("ID_BYTE            = 0x%02x\n", 0xff & regs[R_ID]);
-+	tda_reg("THERMO_BYTE        = 0x%02x\n", 0xff & regs[R_TM]);
-+	tda_reg("POWER_LEVEL_BYTE   = 0x%02x\n", 0xff & regs[R_PL]);
-+	tda_reg("EASY_PROG_BYTE_1   = 0x%02x\n", 0xff & regs[R_EP1]);
-+	tda_reg("EASY_PROG_BYTE_2   = 0x%02x\n", 0xff & regs[R_EP2]);
-+	tda_reg("EASY_PROG_BYTE_3   = 0x%02x\n", 0xff & regs[R_EP3]);
-+	tda_reg("EASY_PROG_BYTE_4   = 0x%02x\n", 0xff & regs[R_EP4]);
-+	tda_reg("EASY_PROG_BYTE_5   = 0x%02x\n", 0xff & regs[R_EP5]);
-+	tda_reg("CAL_POST_DIV_BYTE  = 0x%02x\n", 0xff & regs[R_CPD]);
-+	tda_reg("CAL_DIV_BYTE_1     = 0x%02x\n", 0xff & regs[R_CD1]);
-+	tda_reg("CAL_DIV_BYTE_2     = 0x%02x\n", 0xff & regs[R_CD2]);
-+	tda_reg("CAL_DIV_BYTE_3     = 0x%02x\n", 0xff & regs[R_CD3]);
-+	tda_reg("MAIN_POST_DIV_BYTE = 0x%02x\n", 0xff & regs[R_MPD]);
-+	tda_reg("MAIN_DIV_BYTE_1    = 0x%02x\n", 0xff & regs[R_MD1]);
-+	tda_reg("MAIN_DIV_BYTE_2    = 0x%02x\n", 0xff & regs[R_MD2]);
-+	tda_reg("MAIN_DIV_BYTE_3    = 0x%02x\n", 0xff & regs[R_MD3]);
++	priv->mode = TDA18271_ANALOG;
 +
-+	/* only dump extended regs if DBG_ADV is set */
-+	if (!(tda18271_debug & DBG_ADV))
-+		return;
++	if (params->mode == V4L2_TUNER_RADIO) {
++		radio = 1;
++		freq = freq / 1000;
++		std  = std_map->fm_radio.std_bits;
++		sgIF = std_map->fm_radio.if_freq;
++		mode = "fm";
++	} else if (params->std & V4L2_STD_MN) {
++		std  = std_map->atv_mn.std_bits;
++		sgIF = std_map->atv_mn.if_freq;
++		mode = "MN";
++	} else if (params->std & V4L2_STD_B) {
++		std  = std_map->atv_b.std_bits;
++		sgIF = std_map->atv_b.if_freq;
++		mode = "B";
++	} else if (params->std & V4L2_STD_GH) {
++		std  = std_map->atv_gh.std_bits;
++		sgIF = std_map->atv_gh.if_freq;
++		mode = "GH";
++	} else if (params->std & V4L2_STD_PAL_I) {
++		std  = std_map->atv_i.std_bits;
++		sgIF = std_map->atv_i.if_freq;
++		mode = "I";
++	} else if (params->std & V4L2_STD_DK) {
++		std  = std_map->atv_dk.std_bits;
++		sgIF = std_map->atv_dk.if_freq;
++		mode = "DK";
++	} else if (params->std & V4L2_STD_SECAM_L) {
++		std  = std_map->atv_l.std_bits;
++		sgIF = std_map->atv_l.if_freq;
++		mode = "L";
++	} else if (params->std & V4L2_STD_SECAM_LC) {
++		std  = std_map->atv_lc.std_bits;
++		sgIF = std_map->atv_lc.if_freq;
++		mode = "L'";
++	} else {
++		std  = std_map->atv_i.std_bits;
++		sgIF = std_map->atv_i.if_freq;
++		mode = "xx";
++	}
 +
-+	/* W indicates write-only registers.
-+	 * Register dump for write-only registers shows last value written. */
++	tda_dbg("setting tda18271 to system %s\n", mode);
 +
-+	tda_reg("EXTENDED_BYTE_1    = 0x%02x\n", 0xff & regs[R_EB1]);
-+	tda_reg("EXTENDED_BYTE_2    = 0x%02x\n", 0xff & regs[R_EB2]);
-+	tda_reg("EXTENDED_BYTE_3    = 0x%02x\n", 0xff & regs[R_EB3]);
-+	tda_reg("EXTENDED_BYTE_4    = 0x%02x\n", 0xff & regs[R_EB4]);
-+	tda_reg("EXTENDED_BYTE_5    = 0x%02x\n", 0xff & regs[R_EB5]);
-+	tda_reg("EXTENDED_BYTE_6    = 0x%02x\n", 0xff & regs[R_EB6]);
-+	tda_reg("EXTENDED_BYTE_7    = 0x%02x\n", 0xff & regs[R_EB7]);
-+	tda_reg("EXTENDED_BYTE_8    = 0x%02x\n", 0xff & regs[R_EB8]);
-+	tda_reg("EXTENDED_BYTE_9  W = 0x%02x\n", 0xff & regs[R_EB9]);
-+	tda_reg("EXTENDED_BYTE_10   = 0x%02x\n", 0xff & regs[R_EB10]);
-+	tda_reg("EXTENDED_BYTE_11   = 0x%02x\n", 0xff & regs[R_EB11]);
-+	tda_reg("EXTENDED_BYTE_12   = 0x%02x\n", 0xff & regs[R_EB12]);
-+	tda_reg("EXTENDED_BYTE_13   = 0x%02x\n", 0xff & regs[R_EB13]);
-+	tda_reg("EXTENDED_BYTE_14   = 0x%02x\n", 0xff & regs[R_EB14]);
-+	tda_reg("EXTENDED_BYTE_15   = 0x%02x\n", 0xff & regs[R_EB15]);
-+	tda_reg("EXTENDED_BYTE_16 W = 0x%02x\n", 0xff & regs[R_EB16]);
-+	tda_reg("EXTENDED_BYTE_17 W = 0x%02x\n", 0xff & regs[R_EB17]);
-+	tda_reg("EXTENDED_BYTE_18   = 0x%02x\n", 0xff & regs[R_EB18]);
-+	tda_reg("EXTENDED_BYTE_19 W = 0x%02x\n", 0xff & regs[R_EB19]);
-+	tda_reg("EXTENDED_BYTE_20 W = 0x%02x\n", 0xff & regs[R_EB20]);
-+	tda_reg("EXTENDED_BYTE_21   = 0x%02x\n", 0xff & regs[R_EB21]);
-+	tda_reg("EXTENDED_BYTE_22   = 0x%02x\n", 0xff & regs[R_EB22]);
-+	tda_reg("EXTENDED_BYTE_23   = 0x%02x\n", 0xff & regs[R_EB23]);
++	ret = tda18271_tune(fe, sgIF * 1000, freq, 0, std, radio);
++
++	if (ret < 0)
++		goto fail;
++
++	priv->frequency = freq;
++	priv->bandwidth = 0;
++fail:
++	return ret;
 +}
 +
-+int tda18271_read_regs(struct dvb_frontend *fe)
++static int tda18271_sleep(struct dvb_frontend *fe)
 +{
 +	struct tda18271_priv *priv = fe->tuner_priv;
-+	unsigned char *regs = priv->tda18271_regs;
-+	unsigned char buf = 0x00;
-+	int ret;
-+	struct i2c_msg msg[] = {
-+		{ .addr = priv->i2c_addr, .flags = 0,
-+		  .buf = &buf, .len = 1 },
-+		{ .addr = priv->i2c_addr, .flags = I2C_M_RD,
-+		  .buf = regs, .len = 16 }
-+	};
-+
-+	tda18271_i2c_gate_ctrl(fe, 1);
 +
-+	/* read all registers */
-+	ret = i2c_transfer(priv->i2c_adap, msg, 2);
-+
-+	tda18271_i2c_gate_ctrl(fe, 0);
++	mutex_lock(&priv->lock);
 +
-+	if (ret != 2)
-+		tda_err("ERROR: i2c_transfer returned: %d\n", ret);
++	/* standby mode w/ slave tuner output
++	 * & loop thru & xtal oscillator on */
++	tda18271_set_standby_mode(fe, 1, 0, 0);
 +
-+	if (tda18271_debug & DBG_REG)
-+		tda18271_dump_regs(fe, 0);
++	mutex_unlock(&priv->lock);
 +
-+	return (ret == 2 ? 0 : ret);
++	return 0;
 +}
 +
-+int tda18271_read_extended(struct dvb_frontend *fe)
++static int tda18271_release(struct dvb_frontend *fe)
 +{
 +	struct tda18271_priv *priv = fe->tuner_priv;
-+	unsigned char *regs = priv->tda18271_regs;
-+	unsigned char regdump[TDA18271_NUM_REGS];
-+	unsigned char buf = 0x00;
-+	int ret, i;
-+	struct i2c_msg msg[] = {
-+		{ .addr = priv->i2c_addr, .flags = 0,
-+		  .buf = &buf, .len = 1 },
-+		{ .addr = priv->i2c_addr, .flags = I2C_M_RD,
-+		  .buf = regdump, .len = TDA18271_NUM_REGS }
-+	};
-+
-+	tda18271_i2c_gate_ctrl(fe, 1);
 +
-+	/* read all registers */
-+	ret = i2c_transfer(priv->i2c_adap, msg, 2);
++	mutex_lock(&tda18271_list_mutex);
 +
-+	tda18271_i2c_gate_ctrl(fe, 0);
++	priv->count--;
 +
-+	if (ret != 2)
-+		tda_err("ERROR: i2c_transfer returned: %d\n", ret);
++	if (!priv->count) {
++		tda_dbg("destroying instance @ %d-%04x\n",
++			i2c_adapter_id(priv->i2c_adap),
++			priv->i2c_addr);
++		list_del(&priv->tda18271_list);
 +
-+	for (i = 0; i <= TDA18271_NUM_REGS; i++) {
-+		/* don't update write-only registers */
-+		if ((i != R_EB9)  &&
-+		    (i != R_EB16) &&
-+		    (i != R_EB17) &&
-+		    (i != R_EB19) &&
-+		    (i != R_EB20))
-+		regs[i] = regdump[i];
++		kfree(priv);
 +	}
++	mutex_unlock(&tda18271_list_mutex);
 +
-+	if (tda18271_debug & DBG_REG)
-+		tda18271_dump_regs(fe, 1);
++	fe->tuner_priv = NULL;
 +
-+	return (ret == 2 ? 0 : ret);
++	return 0;
 +}
 +
-+int tda18271_write_regs(struct dvb_frontend *fe, int idx, int len)
++static int tda18271_get_frequency(struct dvb_frontend *fe, u32 *frequency)
 +{
 +	struct tda18271_priv *priv = fe->tuner_priv;
-+	unsigned char *regs = priv->tda18271_regs;
-+	unsigned char buf[TDA18271_NUM_REGS + 1];
-+	struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0,
-+			       .buf = buf, .len = len + 1 };
-+	int i, ret;
++	*frequency = priv->frequency;
++	return 0;
++}
 +
-+	BUG_ON((len == 0) || (idx + len > sizeof(buf)));
++static int tda18271_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
++{
++	struct tda18271_priv *priv = fe->tuner_priv;
++	*bandwidth = priv->bandwidth;
++	return 0;
++}
 +
-+	buf[0] = idx;
-+	for (i = 1; i <= len; i++)
-+		buf[i] = regs[idx - 1 + i];
++/* ------------------------------------------------------------------ */
 +
-+	tda18271_i2c_gate_ctrl(fe, 1);
++#define tda18271_update_std(std_cfg, name) do {				\
++	if (map->std_cfg.if_freq + map->std_cfg.std_bits > 0) {		\
++		tda_dbg("Using custom std config for %s\n", name);	\
++		memcpy(&std->std_cfg, &map->std_cfg,			\
++			sizeof(struct tda18271_std_map_item));		\
++	} } while (0)
 +
-+	/* write registers */
-+	ret = i2c_transfer(priv->i2c_adap, &msg, 1);
++#define tda18271_dump_std_item(std_cfg, name) do {			\
++	tda_dbg("(%s) if freq = %d, std bits = 0x%02x\n",		\
++		name, std->std_cfg.if_freq, std->std_cfg.std_bits);	\
++	} while (0)
 +
-+	tda18271_i2c_gate_ctrl(fe, 0);
++static int tda18271_dump_std_map(struct dvb_frontend *fe)
++{
++	struct tda18271_priv *priv = fe->tuner_priv;
++	struct tda18271_std_map *std = &priv->std;
 +
-+	if (ret != 1)
-+		tda_err("ERROR: i2c_transfer returned: %d\n", ret);
++	tda_dbg("========== STANDARD MAP SETTINGS ==========\n");
++	tda18271_dump_std_item(fm_radio, "fm");
++	tda18271_dump_std_item(atv_b,  "pal b");
++	tda18271_dump_std_item(atv_dk, "pal dk");
++	tda18271_dump_std_item(atv_gh, "pal gh");
++	tda18271_dump_std_item(atv_i,  "pal i");
++	tda18271_dump_std_item(atv_l,  "pal l");
++	tda18271_dump_std_item(atv_lc, "pal l'");
++	tda18271_dump_std_item(atv_mn, "atv mn");
++	tda18271_dump_std_item(atsc_6, "atsc 6");
++	tda18271_dump_std_item(dvbt_6, "dvbt 6");
++	tda18271_dump_std_item(dvbt_7, "dvbt 7");
++	tda18271_dump_std_item(dvbt_8, "dvbt 8");
++	tda18271_dump_std_item(qam_6,  "qam 6");
++	tda18271_dump_std_item(qam_8,  "qam 8");
 +
-+	return (ret == 1 ? 0 : ret);
++	return 0;
 +}
 +
-+/*---------------------------------------------------------------------*/
++static int tda18271_update_std_map(struct dvb_frontend *fe,
++				   struct tda18271_std_map *map)
++{
++	struct tda18271_priv *priv = fe->tuner_priv;
++	struct tda18271_std_map *std = &priv->std;
 +
-+int tda18271_init_regs(struct dvb_frontend *fe)
++	if (!map)
++		return -EINVAL;
++
++	tda18271_update_std(fm_radio, "fm");
++	tda18271_update_std(atv_b,  "atv b");
++	tda18271_update_std(atv_dk, "atv dk");
++	tda18271_update_std(atv_gh, "atv gh");
++	tda18271_update_std(atv_i,  "atv i");
++	tda18271_update_std(atv_l,  "atv l");
++	tda18271_update_std(atv_lc, "atv l'");
++	tda18271_update_std(atv_mn, "atv mn");
++	tda18271_update_std(atsc_6, "atsc 6");
++	tda18271_update_std(dvbt_6, "dvbt 6");
++	tda18271_update_std(dvbt_7, "dvbt 7");
++	tda18271_update_std(dvbt_8, "dvbt 8");
++	tda18271_update_std(qam_6,  "qam 6");
++	tda18271_update_std(qam_8,  "qam 8");
++
++	return 0;
++}
++
++static int tda18271_get_id(struct dvb_frontend *fe)
 +{
 +	struct tda18271_priv *priv = fe->tuner_priv;
 +	unsigned char *regs = priv->tda18271_regs;
++	char *name;
++	int ret = 0;
 +
-+	tda_dbg("initializing registers for device @ %d-%04x\n",
-+		i2c_adapter_id(priv->i2c_adap), priv->i2c_addr);
++	mutex_lock(&priv->lock);
++	tda18271_read_regs(fe);
++	mutex_unlock(&priv->lock);
 +
-+	/* initialize registers */
-+	switch (priv->id) {
-+	case TDA18271HDC1:
-+		regs[R_ID]   = 0x83;
++	switch (regs[R_ID] & 0x7f) {
++	case 3:
++		name = "TDA18271HD/C1";
++		priv->id = TDA18271HDC1;
 +		break;
-+	case TDA18271HDC2:
-+		regs[R_ID]   = 0x84;
++	case 4:
++		name = "TDA18271HD/C2";
++		priv->id = TDA18271HDC2;
 +		break;
-+	};
++	default:
++		name = "Unknown device";
++		ret = -EINVAL;
++		break;
++	}
 +
-+	regs[R_TM]   = 0x08;
-+	regs[R_PL]   = 0x80;
-+	regs[R_EP1]  = 0xc6;
-+	regs[R_EP2]  = 0xdf;
-+	regs[R_EP3]  = 0x16;
-+	regs[R_EP4]  = 0x60;
-+	regs[R_EP5]  = 0x80;
-+	regs[R_CPD]  = 0x80;
-+	regs[R_CD1]  = 0x00;
-+	regs[R_CD2]  = 0x00;
-+	regs[R_CD3]  = 0x00;
-+	regs[R_MPD]  = 0x00;
-+	regs[R_MD1]  = 0x00;
-+	regs[R_MD2]  = 0x00;
-+	regs[R_MD3]  = 0x00;
++	tda_info("%s detected @ %d-%04x%s\n", name,
++		 i2c_adapter_id(priv->i2c_adap), priv->i2c_addr,
++		 (0 == ret) ? "" : ", device not supported.");
 +
-+	switch (priv->id) {
-+	case TDA18271HDC1:
-+		regs[R_EB1]  = 0xff;
-+		break;
-+	case TDA18271HDC2:
-+		regs[R_EB1]  = 0xfc;
-+		break;
-+	};
++	return ret;
++}
 +
-+	regs[R_EB2]  = 0x01;
-+	regs[R_EB3]  = 0x84;
-+	regs[R_EB4]  = 0x41;
-+	regs[R_EB5]  = 0x01;
-+	regs[R_EB6]  = 0x84;
-+	regs[R_EB7]  = 0x40;
-+	regs[R_EB8]  = 0x07;
-+	regs[R_EB9]  = 0x00;
-+	regs[R_EB10] = 0x00;
-+	regs[R_EB11] = 0x96;
++static struct dvb_tuner_ops tda18271_tuner_ops = {
++	.info = {
++		.name = "NXP TDA18271HD",
++		.frequency_min  =  45000000,
++		.frequency_max  = 864000000,
++		.frequency_step =     62500
++	},
++	.init              = tda18271_init,
++	.sleep             = tda18271_sleep,
++	.set_params        = tda18271_set_params,
++	.set_analog_params = tda18271_set_analog_params,
++	.release           = tda18271_release,
++	.get_frequency     = tda18271_get_frequency,
++	.get_bandwidth     = tda18271_get_bandwidth,
++};
 +
-+	switch (priv->id) {
-+	case TDA18271HDC1:
-+		regs[R_EB12] = 0x0f;
-+		break;
-+	case TDA18271HDC2:
-+		regs[R_EB12] = 0x33;
-+		break;
-+	};
++struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr,
++				     struct i2c_adapter *i2c,
++				     struct tda18271_config *cfg)
++{
++	struct tda18271_priv *priv = NULL;
++	int state_found = 0;
 +
-+	regs[R_EB13] = 0xc1;
-+	regs[R_EB14] = 0x00;
-+	regs[R_EB15] = 0x8f;
-+	regs[R_EB16] = 0x00;
-+	regs[R_EB17] = 0x00;
++	mutex_lock(&tda18271_list_mutex);
 +
-+	switch (priv->id) {
-+	case TDA18271HDC1:
-+		regs[R_EB18] = 0x00;
-+		break;
-+	case TDA18271HDC2:
-+		regs[R_EB18] = 0x8c;
-+		break;
-+	};
++	list_for_each_entry(priv, &tda18271_list, tda18271_list) {
++		if ((i2c_adapter_id(priv->i2c_adap) == i2c_adapter_id(i2c)) &&
++		    (priv->i2c_addr == addr)) {
++			tda_dbg("attaching existing tuner @ %d-%04x\n",
++				i2c_adapter_id(priv->i2c_adap),
++				priv->i2c_addr);
++			priv->count++;
++			fe->tuner_priv = priv;
++			state_found = 1;
++			/* allow dvb driver to override i2c gate setting */
++			if ((cfg) && (cfg->gate != TDA18271_GATE_ANALOG))
++				priv->gate = cfg->gate;
++			break;
++		}
++	}
++	if (state_found == 0) {
++		tda_dbg("creating new tuner instance @ %d-%04x\n",
++			i2c_adapter_id(i2c), addr);
 +
-+	regs[R_EB19] = 0x00;
-+	regs[R_EB20] = 0x20;
++		priv = kzalloc(sizeof(struct tda18271_priv), GFP_KERNEL);
++		if (priv == NULL) {
++			mutex_unlock(&tda18271_list_mutex);
++			return NULL;
++		}
 +
-+	switch (priv->id) {
-+	case TDA18271HDC1:
-+		regs[R_EB21] = 0x33;
-+		break;
-+	case TDA18271HDC2:
-+		regs[R_EB21] = 0xb3;
-+		break;
-+	};
++		priv->i2c_addr = addr;
++		priv->i2c_adap = i2c;
++		priv->gate = (cfg) ? cfg->gate : TDA18271_GATE_AUTO;
++		priv->cal_initialized = false;
++		mutex_init(&priv->lock);
++		priv->count++;
 +
-+	regs[R_EB22] = 0x48;
-+	regs[R_EB23] = 0xb0;
++		fe->tuner_priv = priv;
 +
-+	tda18271_write_regs(fe, 0x00, TDA18271_NUM_REGS);
++		list_add_tail(&priv->tda18271_list, &tda18271_list);
 +
-+	/* setup agc1 gain */
-+	regs[R_EB17] = 0x00;
-+	tda18271_write_regs(fe, R_EB17, 1);
-+	regs[R_EB17] = 0x03;
-+	tda18271_write_regs(fe, R_EB17, 1);
-+	regs[R_EB17] = 0x43;
-+	tda18271_write_regs(fe, R_EB17, 1);
-+	regs[R_EB17] = 0x4c;
-+	tda18271_write_regs(fe, R_EB17, 1);
++		if (tda18271_get_id(fe) < 0)
++			goto fail;
 +
-+	/* setup agc2 gain */
-+	if ((priv->id) == TDA18271HDC1) {
-+		regs[R_EB20] = 0xa0;
-+		tda18271_write_regs(fe, R_EB20, 1);
-+		regs[R_EB20] = 0xa7;
-+		tda18271_write_regs(fe, R_EB20, 1);
-+		regs[R_EB20] = 0xe7;
-+		tda18271_write_regs(fe, R_EB20, 1);
-+		regs[R_EB20] = 0xec;
-+		tda18271_write_regs(fe, R_EB20, 1);
++		if (tda18271_assign_map_layout(fe) < 0)
++			goto fail;
++
++		mutex_lock(&priv->lock);
++		tda18271_init_regs(fe);
++
++		if ((tda18271_cal_on_startup) && (priv->id == TDA18271HDC2))
++			tda18271_rf_cal_init(fe);
++
++		mutex_unlock(&priv->lock);
 +	}
 +
-+	/* image rejection calibration */
++	/* override default std map with values in config struct */
++	if ((cfg) && (cfg->std_map))
++		tda18271_update_std_map(fe, cfg->std_map);
 +
-+	/* low-band */
-+	regs[R_EP3] = 0x1f;
-+	regs[R_EP4] = 0x66;
-+	regs[R_EP5] = 0x81;
-+	regs[R_CPD] = 0xcc;
-+	regs[R_CD1] = 0x6c;
-+	regs[R_CD2] = 0x00;
-+	regs[R_CD3] = 0x00;
-+	regs[R_MPD] = 0xcd;
-+	regs[R_MD1] = 0x77;
-+	regs[R_MD2] = 0x08;
-+	regs[R_MD3] = 0x00;
++	mutex_unlock(&tda18271_list_mutex);
++
++	memcpy(&fe->ops.tuner_ops, &tda18271_tuner_ops,
++	       sizeof(struct dvb_tuner_ops));
++
++	if (tda18271_debug & DBG_MAP)
++		tda18271_dump_std_map(fe);
++
++	return fe;
++fail:
++	mutex_unlock(&tda18271_list_mutex);
++
++	tda18271_release(fe);
++	return NULL;
++}
++EXPORT_SYMBOL_GPL(tda18271_attach);
++MODULE_DESCRIPTION("NXP TDA18271HD analog / digital tuner driver");
++MODULE_AUTHOR("Michael Krufky <mkrufky at linuxtv.org>");
++MODULE_LICENSE("GPL");
++MODULE_VERSION("0.2");
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-basic-offset: 8
++ * End:
++ */
+diff --git a/drivers/media/dvb/frontends/tda18271-priv.h b/drivers/media/dvb/frontends/tda18271-priv.h
+new file mode 100644
+index 0000000..7b939a5
+--- /dev/null
++++ b/drivers/media/dvb/frontends/tda18271-priv.h
+@@ -0,0 +1,212 @@
++/*
++    tda18271-priv.h - private header for the NXP TDA18271 silicon tuner
++
++    Copyright (C) 2007, 2008 Michael Krufky <mkrufky at 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 __TDA18271_PRIV_H__
++#define __TDA18271_PRIV_H__
++
++#include <linux/kernel.h>
++#include <linux/types.h>
++#include <linux/mutex.h>
++#include "tda18271.h"
++
++#define R_ID     0x00	/* ID byte                */
++#define R_TM     0x01	/* Thermo byte            */
++#define R_PL     0x02	/* Power level byte       */
++#define R_EP1    0x03	/* Easy Prog byte 1       */
++#define R_EP2    0x04	/* Easy Prog byte 2       */
++#define R_EP3    0x05	/* Easy Prog byte 3       */
++#define R_EP4    0x06	/* Easy Prog byte 4       */
++#define R_EP5    0x07	/* Easy Prog byte 5       */
++#define R_CPD    0x08	/* Cal Post-Divider byte  */
++#define R_CD1    0x09	/* Cal Divider byte 1     */
++#define R_CD2    0x0a	/* Cal Divider byte 2     */
++#define R_CD3    0x0b	/* Cal Divider byte 3     */
++#define R_MPD    0x0c	/* Main Post-Divider byte */
++#define R_MD1    0x0d	/* Main Divider byte 1    */
++#define R_MD2    0x0e	/* Main Divider byte 2    */
++#define R_MD3    0x0f	/* Main Divider byte 3    */
++#define R_EB1    0x10	/* Extended byte 1        */
++#define R_EB2    0x11	/* Extended byte 2        */
++#define R_EB3    0x12	/* Extended byte 3        */
++#define R_EB4    0x13	/* Extended byte 4        */
++#define R_EB5    0x14	/* Extended byte 5        */
++#define R_EB6    0x15	/* Extended byte 6        */
++#define R_EB7    0x16	/* Extended byte 7        */
++#define R_EB8    0x17	/* Extended byte 8        */
++#define R_EB9    0x18	/* Extended byte 9        */
++#define R_EB10   0x19	/* Extended byte 10       */
++#define R_EB11   0x1a	/* Extended byte 11       */
++#define R_EB12   0x1b	/* Extended byte 12       */
++#define R_EB13   0x1c	/* Extended byte 13       */
++#define R_EB14   0x1d	/* Extended byte 14       */
++#define R_EB15   0x1e	/* Extended byte 15       */
++#define R_EB16   0x1f	/* Extended byte 16       */
++#define R_EB17   0x20	/* Extended byte 17       */
++#define R_EB18   0x21	/* Extended byte 18       */
++#define R_EB19   0x22	/* Extended byte 19       */
++#define R_EB20   0x23	/* Extended byte 20       */
++#define R_EB21   0x24	/* Extended byte 21       */
++#define R_EB22   0x25	/* Extended byte 22       */
++#define R_EB23   0x26	/* Extended byte 23       */
++
++#define TDA18271_NUM_REGS 39
++
++/*---------------------------------------------------------------------*/
++
++struct tda18271_rf_tracking_filter_cal {
++	u32 rfmax;
++	u8  rfband;
++	u32 rf1_def;
++	u32 rf2_def;
++	u32 rf3_def;
++	u32 rf1;
++	u32 rf2;
++	u32 rf3;
++	int rf_a1;
++	int rf_b1;
++	int rf_a2;
++	int rf_b2;
++};
++
++enum tda18271_mode {
++	TDA18271_ANALOG,
++	TDA18271_DIGITAL,
++};
++
++struct tda18271_map_layout;
++
++enum tda18271_ver {
++	TDA18271HDC1,
++	TDA18271HDC2,
++};
++
++struct tda18271_priv {
++	u8 i2c_addr;
++	struct i2c_adapter *i2c_adap;
++	unsigned char tda18271_regs[TDA18271_NUM_REGS];
++
++	struct list_head tda18271_list;
++
++	enum tda18271_mode mode;
++	enum tda18271_i2c_gate gate;
++	enum tda18271_ver id;
++
++	unsigned int count;
++	unsigned int tm_rfcal;
++	unsigned int cal_initialized:1;
++
++	struct tda18271_map_layout *maps;
++	struct tda18271_std_map std;
++	struct tda18271_rf_tracking_filter_cal rf_cal_state[8];
++
++	struct mutex lock;
++
++	u32 frequency;
++	u32 bandwidth;
++};
++
++/*---------------------------------------------------------------------*/
++
++extern int tda18271_debug;
++
++#define DBG_INFO 1
++#define DBG_MAP  2
++#define DBG_REG  4
++#define DBG_ADV  8
++#define DBG_CAL  16
++
++#define tda_printk(kern, fmt, arg...) \
++	printk(kern "%s: " fmt, __FUNCTION__, ##arg)
++
++#define dprintk(kern, lvl, fmt, arg...) do {\
++	if (tda18271_debug & lvl) \
++		tda_printk(kern, fmt, ##arg); } while (0)
++
++#define tda_info(fmt, arg...) printk(KERN_INFO              fmt, ##arg)
++#define tda_warn(fmt, arg...) tda_printk(KERN_WARNING,      fmt, ##arg)
++#define tda_err(fmt, arg...)  tda_printk(KERN_ERR,          fmt, ##arg)
++#define tda_dbg(fmt, arg...)  dprintk(KERN_DEBUG, DBG_INFO, fmt, ##arg)
++#define tda_map(fmt, arg...)  dprintk(KERN_DEBUG, DBG_MAP,  fmt, ##arg)
++#define tda_reg(fmt, arg...)  dprintk(KERN_DEBUG, DBG_REG,  fmt, ##arg)
++#define tda_cal(fmt, arg...)  dprintk(KERN_DEBUG, DBG_CAL,  fmt, ##arg)
++
++/*---------------------------------------------------------------------*/
++
++enum tda18271_map_type {
++	/* tda18271_pll_map */
++	MAIN_PLL,
++	CAL_PLL,
++	/* tda18271_map */
++	RF_CAL,
++	RF_CAL_KMCO,
++	RF_CAL_DC_OVER_DT,
++	BP_FILTER,
++	RF_BAND,
++	GAIN_TAPER,
++	IR_MEASURE,
++};
++
++extern int tda18271_lookup_pll_map(struct dvb_frontend *fe,
++				   enum tda18271_map_type map_type,
++				   u32 *freq, u8 *post_div, u8 *div);
++extern int tda18271_lookup_map(struct dvb_frontend *fe,
++			       enum tda18271_map_type map_type,
++			       u32 *freq, u8 *val);
++
++extern int tda18271_lookup_thermometer(struct dvb_frontend *fe);
++
++extern int tda18271_lookup_rf_band(struct dvb_frontend *fe,
++				   u32 *freq, u8 *rf_band);
++
++extern int tda18271_lookup_cid_target(struct dvb_frontend *fe,
++				      u32 *freq, u8 *cid_target,
++				      u16 *count_limit);
++
++extern int tda18271_assign_map_layout(struct dvb_frontend *fe);
++
++/*---------------------------------------------------------------------*/
++
++extern int tda18271_read_regs(struct dvb_frontend *fe);
++extern int tda18271_read_extended(struct dvb_frontend *fe);
++extern int tda18271_write_regs(struct dvb_frontend *fe, int idx, int len);
++extern int tda18271_init_regs(struct dvb_frontend *fe);
++
++extern int tda18271_set_standby_mode(struct dvb_frontend *fe,
++				     int sm, int sm_lt, int sm_xt);
++
++extern int tda18271_calc_main_pll(struct dvb_frontend *fe, u32 freq);
++extern int tda18271_calc_cal_pll(struct dvb_frontend *fe, u32 freq);
++
++extern int tda18271_calc_bp_filter(struct dvb_frontend *fe, u32 *freq);
++extern int tda18271_calc_km(struct dvb_frontend *fe, u32 *freq);
++extern int tda18271_calc_rf_band(struct dvb_frontend *fe, u32 *freq);
++extern int tda18271_calc_gain_taper(struct dvb_frontend *fe, u32 *freq);
++extern int tda18271_calc_ir_measure(struct dvb_frontend *fe, u32 *freq);
++extern int tda18271_calc_rf_cal(struct dvb_frontend *fe, u32 *freq);
++
++#endif /* __TDA18271_PRIV_H__ */
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-basic-offset: 8
++ * End:
++ */
+diff --git a/drivers/media/dvb/frontends/tda18271-tables.c b/drivers/media/dvb/frontends/tda18271-tables.c
+new file mode 100644
+index 0000000..e94afcf
+--- /dev/null
++++ b/drivers/media/dvb/frontends/tda18271-tables.c
+@@ -0,0 +1,1285 @@
++/*
++    tda18271-tables.c - driver for the Philips / NXP TDA18271 silicon tuner
++
++    Copyright (C) 2007, 2008 Michael Krufky <mkrufky at 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.
++*/
 +
-+	switch (priv->id) {
-+	case TDA18271HDC1:
-+		tda18271_write_regs(fe, R_EP3, 11);
-+		break;
-+	case TDA18271HDC2:
-+		tda18271_write_regs(fe, R_EP3, 12);
-+		break;
-+	};
++#include "tda18271-priv.h"
 +
-+	if ((priv->id) == TDA18271HDC2) {
-+		/* main pll cp source on */
-+		regs[R_EB4] = 0x61;
-+		tda18271_write_regs(fe, R_EB4, 1);
-+		msleep(1);
++struct tda18271_pll_map {
++	u32 lomax;
++	u8 pd; /* post div */
++	u8 d;  /*      div */
++};
 +
-+		/* main pll cp source off */
-+		regs[R_EB4] = 0x41;
-+		tda18271_write_regs(fe, R_EB4, 1);
-+	}
++struct tda18271_map {
++	u32 rfmax;
++	u8  val;
++};
 +
-+	msleep(5); /* pll locking */
++/*---------------------------------------------------------------------*/
 +
-+	/* launch detector */
-+	tda18271_write_regs(fe, R_EP1, 1);
-+	msleep(5); /* wanted low measurement */
++static struct tda18271_pll_map tda18271c1_main_pll[] = {
++	{ .lomax =  32000, .pd = 0x5f, .d = 0xf0 },
++	{ .lomax =  35000, .pd = 0x5e, .d = 0xe0 },
++	{ .lomax =  37000, .pd = 0x5d, .d = 0xd0 },
++	{ .lomax =  41000, .pd = 0x5c, .d = 0xc0 },
++	{ .lomax =  44000, .pd = 0x5b, .d = 0xb0 },
++	{ .lomax =  49000, .pd = 0x5a, .d = 0xa0 },
++	{ .lomax =  54000, .pd = 0x59, .d = 0x90 },
++	{ .lomax =  61000, .pd = 0x58, .d = 0x80 },
++	{ .lomax =  65000, .pd = 0x4f, .d = 0x78 },
++	{ .lomax =  70000, .pd = 0x4e, .d = 0x70 },
++	{ .lomax =  75000, .pd = 0x4d, .d = 0x68 },
++	{ .lomax =  82000, .pd = 0x4c, .d = 0x60 },
++	{ .lomax =  89000, .pd = 0x4b, .d = 0x58 },
++	{ .lomax =  98000, .pd = 0x4a, .d = 0x50 },
++	{ .lomax = 109000, .pd = 0x49, .d = 0x48 },
++	{ .lomax = 123000, .pd = 0x48, .d = 0x40 },
++	{ .lomax = 131000, .pd = 0x3f, .d = 0x3c },
++	{ .lomax = 141000, .pd = 0x3e, .d = 0x38 },
++	{ .lomax = 151000, .pd = 0x3d, .d = 0x34 },
++	{ .lomax = 164000, .pd = 0x3c, .d = 0x30 },
++	{ .lomax = 179000, .pd = 0x3b, .d = 0x2c },
++	{ .lomax = 197000, .pd = 0x3a, .d = 0x28 },
++	{ .lomax = 219000, .pd = 0x39, .d = 0x24 },
++	{ .lomax = 246000, .pd = 0x38, .d = 0x20 },
++	{ .lomax = 263000, .pd = 0x2f, .d = 0x1e },
++	{ .lomax = 282000, .pd = 0x2e, .d = 0x1c },
++	{ .lomax = 303000, .pd = 0x2d, .d = 0x1a },
++	{ .lomax = 329000, .pd = 0x2c, .d = 0x18 },
++	{ .lomax = 359000, .pd = 0x2b, .d = 0x16 },
++	{ .lomax = 395000, .pd = 0x2a, .d = 0x14 },
++	{ .lomax = 438000, .pd = 0x29, .d = 0x12 },
++	{ .lomax = 493000, .pd = 0x28, .d = 0x10 },
++	{ .lomax = 526000, .pd = 0x1f, .d = 0x0f },
++	{ .lomax = 564000, .pd = 0x1e, .d = 0x0e },
++	{ .lomax = 607000, .pd = 0x1d, .d = 0x0d },
++	{ .lomax = 658000, .pd = 0x1c, .d = 0x0c },
++	{ .lomax = 718000, .pd = 0x1b, .d = 0x0b },
++	{ .lomax = 790000, .pd = 0x1a, .d = 0x0a },
++	{ .lomax = 877000, .pd = 0x19, .d = 0x09 },
++	{ .lomax = 987000, .pd = 0x18, .d = 0x08 },
++	{ .lomax =      0, .pd = 0x00, .d = 0x00 }, /* end */
++};
 +
-+	regs[R_EP5] = 0x85;
-+	regs[R_CPD] = 0xcb;
-+	regs[R_CD1] = 0x66;
-+	regs[R_CD2] = 0x70;
++static struct tda18271_pll_map tda18271c2_main_pll[] = {
++	{ .lomax =  33125, .pd = 0x57, .d = 0xf0 },
++	{ .lomax =  35500, .pd = 0x56, .d = 0xe0 },
++	{ .lomax =  38188, .pd = 0x55, .d = 0xd0 },
++	{ .lomax =  41375, .pd = 0x54, .d = 0xc0 },
++	{ .lomax =  45125, .pd = 0x53, .d = 0xb0 },
++	{ .lomax =  49688, .pd = 0x52, .d = 0xa0 },
++	{ .lomax =  55188, .pd = 0x51, .d = 0x90 },
++	{ .lomax =  62125, .pd = 0x50, .d = 0x80 },
++	{ .lomax =  66250, .pd = 0x47, .d = 0x78 },
++	{ .lomax =  71000, .pd = 0x46, .d = 0x70 },
++	{ .lomax =  76375, .pd = 0x45, .d = 0x68 },
++	{ .lomax =  82750, .pd = 0x44, .d = 0x60 },
++	{ .lomax =  90250, .pd = 0x43, .d = 0x58 },
++	{ .lomax =  99375, .pd = 0x42, .d = 0x50 },
++	{ .lomax = 110375, .pd = 0x41, .d = 0x48 },
++	{ .lomax = 124250, .pd = 0x40, .d = 0x40 },
++	{ .lomax = 132500, .pd = 0x37, .d = 0x3c },
++	{ .lomax = 142000, .pd = 0x36, .d = 0x38 },
++	{ .lomax = 152750, .pd = 0x35, .d = 0x34 },
++	{ .lomax = 165500, .pd = 0x34, .d = 0x30 },
++	{ .lomax = 180500, .pd = 0x33, .d = 0x2c },
++	{ .lomax = 198750, .pd = 0x32, .d = 0x28 },
++	{ .lomax = 220750, .pd = 0x31, .d = 0x24 },
++	{ .lomax = 248500, .pd = 0x30, .d = 0x20 },
++	{ .lomax = 265000, .pd = 0x27, .d = 0x1e },
++	{ .lomax = 284000, .pd = 0x26, .d = 0x1c },
++	{ .lomax = 305500, .pd = 0x25, .d = 0x1a },
++	{ .lomax = 331000, .pd = 0x24, .d = 0x18 },
++	{ .lomax = 361000, .pd = 0x23, .d = 0x16 },
++	{ .lomax = 397500, .pd = 0x22, .d = 0x14 },
++	{ .lomax = 441500, .pd = 0x21, .d = 0x12 },
++	{ .lomax = 497000, .pd = 0x20, .d = 0x10 },
++	{ .lomax = 530000, .pd = 0x17, .d = 0x0f },
++	{ .lomax = 568000, .pd = 0x16, .d = 0x0e },
++	{ .lomax = 611000, .pd = 0x15, .d = 0x0d },
++	{ .lomax = 662000, .pd = 0x14, .d = 0x0c },
++	{ .lomax = 722000, .pd = 0x13, .d = 0x0b },
++	{ .lomax = 795000, .pd = 0x12, .d = 0x0a },
++	{ .lomax = 883000, .pd = 0x11, .d = 0x09 },
++	{ .lomax = 994000, .pd = 0x10, .d = 0x08 },
++	{ .lomax =      0, .pd = 0x00, .d = 0x00 }, /* end */
++};
 +
-+	tda18271_write_regs(fe, R_EP3, 7);
-+	msleep(5); /* pll locking */
++static struct tda18271_pll_map tda18271c1_cal_pll[] = {
++	{ .lomax =   33000, .pd = 0xdd, .d = 0xd0 },
++	{ .lomax =   36000, .pd = 0xdc, .d = 0xc0 },
++	{ .lomax =   40000, .pd = 0xdb, .d = 0xb0 },
++	{ .lomax =   44000, .pd = 0xda, .d = 0xa0 },
++	{ .lomax =   49000, .pd = 0xd9, .d = 0x90 },
++	{ .lomax =   55000, .pd = 0xd8, .d = 0x80 },
++	{ .lomax =   63000, .pd = 0xd3, .d = 0x70 },
++	{ .lomax =   67000, .pd = 0xcd, .d = 0x68 },
++	{ .lomax =   73000, .pd = 0xcc, .d = 0x60 },
++	{ .lomax =   80000, .pd = 0xcb, .d = 0x58 },
++	{ .lomax =   88000, .pd = 0xca, .d = 0x50 },
++	{ .lomax =   98000, .pd = 0xc9, .d = 0x48 },
++	{ .lomax =  110000, .pd = 0xc8, .d = 0x40 },
++	{ .lomax =  126000, .pd = 0xc3, .d = 0x38 },
++	{ .lomax =  135000, .pd = 0xbd, .d = 0x34 },
++	{ .lomax =  147000, .pd = 0xbc, .d = 0x30 },
++	{ .lomax =  160000, .pd = 0xbb, .d = 0x2c },
++	{ .lomax =  176000, .pd = 0xba, .d = 0x28 },
++	{ .lomax =  196000, .pd = 0xb9, .d = 0x24 },
++	{ .lomax =  220000, .pd = 0xb8, .d = 0x20 },
++	{ .lomax =  252000, .pd = 0xb3, .d = 0x1c },
++	{ .lomax =  271000, .pd = 0xad, .d = 0x1a },
++	{ .lomax =  294000, .pd = 0xac, .d = 0x18 },
++	{ .lomax =  321000, .pd = 0xab, .d = 0x16 },
++	{ .lomax =  353000, .pd = 0xaa, .d = 0x14 },
++	{ .lomax =  392000, .pd = 0xa9, .d = 0x12 },
++	{ .lomax =  441000, .pd = 0xa8, .d = 0x10 },
++	{ .lomax =  505000, .pd = 0xa3, .d = 0x0e },
++	{ .lomax =  543000, .pd = 0x9d, .d = 0x0d },
++	{ .lomax =  589000, .pd = 0x9c, .d = 0x0c },
++	{ .lomax =  642000, .pd = 0x9b, .d = 0x0b },
++	{ .lomax =  707000, .pd = 0x9a, .d = 0x0a },
++	{ .lomax =  785000, .pd = 0x99, .d = 0x09 },
++	{ .lomax =  883000, .pd = 0x98, .d = 0x08 },
++	{ .lomax = 1010000, .pd = 0x93, .d = 0x07 },
++	{ .lomax =       0, .pd = 0x00, .d = 0x00 }, /* end */
++};
 +
-+	/* launch optimization algorithm */
-+	tda18271_write_regs(fe, R_EP2, 1);
-+	msleep(30); /* image low optimization completion */
++static struct tda18271_pll_map tda18271c2_cal_pll[] = {
++	{ .lomax =   33813, .pd = 0xdd, .d = 0xd0 },
++	{ .lomax =   36625, .pd = 0xdc, .d = 0xc0 },
++	{ .lomax =   39938, .pd = 0xdb, .d = 0xb0 },
++	{ .lomax =   43938, .pd = 0xda, .d = 0xa0 },
++	{ .lomax =   48813, .pd = 0xd9, .d = 0x90 },
++	{ .lomax =   54938, .pd = 0xd8, .d = 0x80 },
++	{ .lomax =   62813, .pd = 0xd3, .d = 0x70 },
++	{ .lomax =   67625, .pd = 0xcd, .d = 0x68 },
++	{ .lomax =   73250, .pd = 0xcc, .d = 0x60 },
++	{ .lomax =   79875, .pd = 0xcb, .d = 0x58 },
++	{ .lomax =   87875, .pd = 0xca, .d = 0x50 },
++	{ .lomax =   97625, .pd = 0xc9, .d = 0x48 },
++	{ .lomax =  109875, .pd = 0xc8, .d = 0x40 },
++	{ .lomax =  125625, .pd = 0xc3, .d = 0x38 },
++	{ .lomax =  135250, .pd = 0xbd, .d = 0x34 },
++	{ .lomax =  146500, .pd = 0xbc, .d = 0x30 },
++	{ .lomax =  159750, .pd = 0xbb, .d = 0x2c },
++	{ .lomax =  175750, .pd = 0xba, .d = 0x28 },
++	{ .lomax =  195250, .pd = 0xb9, .d = 0x24 },
++	{ .lomax =  219750, .pd = 0xb8, .d = 0x20 },
++	{ .lomax =  251250, .pd = 0xb3, .d = 0x1c },
++	{ .lomax =  270500, .pd = 0xad, .d = 0x1a },
++	{ .lomax =  293000, .pd = 0xac, .d = 0x18 },
++	{ .lomax =  319500, .pd = 0xab, .d = 0x16 },
++	{ .lomax =  351500, .pd = 0xaa, .d = 0x14 },
++	{ .lomax =  390500, .pd = 0xa9, .d = 0x12 },
++	{ .lomax =  439500, .pd = 0xa8, .d = 0x10 },
++	{ .lomax =  502500, .pd = 0xa3, .d = 0x0e },
++	{ .lomax =  541000, .pd = 0x9d, .d = 0x0d },
++	{ .lomax =  586000, .pd = 0x9c, .d = 0x0c },
++	{ .lomax =  639000, .pd = 0x9b, .d = 0x0b },
++	{ .lomax =  703000, .pd = 0x9a, .d = 0x0a },
++	{ .lomax =  781000, .pd = 0x99, .d = 0x09 },
++	{ .lomax =  879000, .pd = 0x98, .d = 0x08 },
++	{ .lomax =       0, .pd = 0x00, .d = 0x00 }, /* end */
++};
 +
-+	/* mid-band */
-+	regs[R_EP5] = 0x82;
-+	regs[R_CPD] = 0xa8;
-+	regs[R_CD2] = 0x00;
-+	regs[R_MPD] = 0xa9;
-+	regs[R_MD1] = 0x73;
-+	regs[R_MD2] = 0x1a;
++static struct tda18271_map tda18271_bp_filter[] = {
++	{ .rfmax =  62000, .val = 0x00 },
++	{ .rfmax =  84000, .val = 0x01 },
++	{ .rfmax = 100000, .val = 0x02 },
++	{ .rfmax = 140000, .val = 0x03 },
++	{ .rfmax = 170000, .val = 0x04 },
++	{ .rfmax = 180000, .val = 0x05 },
++	{ .rfmax = 865000, .val = 0x06 },
++	{ .rfmax =      0, .val = 0x00 }, /* end */
++};
 +
-+	tda18271_write_regs(fe, R_EP3, 11);
-+	msleep(5); /* pll locking */
++static struct tda18271_map tda18271c1_km[] = {
++	{ .rfmax =  61100, .val = 0x74 },
++	{ .rfmax = 350000, .val = 0x40 },
++	{ .rfmax = 720000, .val = 0x30 },
++	{ .rfmax = 865000, .val = 0x40 },
++	{ .rfmax =      0, .val = 0x00 }, /* end */
++};
 +
-+	tda18271_write_regs(fe, R_EP1, 1);
-+	msleep(5); /* wanted mid measurement */
++static struct tda18271_map tda18271c2_km[] = {
++	{ .rfmax =  47900, .val = 0x38 },
++	{ .rfmax =  61100, .val = 0x44 },
++	{ .rfmax = 350000, .val = 0x30 },
++	{ .rfmax = 720000, .val = 0x24 },
++	{ .rfmax = 865000, .val = 0x3c },
++	{ .rfmax =      0, .val = 0x00 }, /* end */
++};
 +
-+	regs[R_EP5] = 0x86;
-+	regs[R_CPD] = 0xa8;
-+	regs[R_CD1] = 0x66;
-+	regs[R_CD2] = 0xa0;
++static struct tda18271_map tda18271_rf_band[] = {
++	{ .rfmax =  47900, .val = 0x00 },
++	{ .rfmax =  61100, .val = 0x01 },
++/*	{ .rfmax = 152600, .val = 0x02 }, */
++	{ .rfmax = 121200, .val = 0x02 },
++	{ .rfmax = 164700, .val = 0x03 },
++	{ .rfmax = 203500, .val = 0x04 },
++	{ .rfmax = 457800, .val = 0x05 },
++	{ .rfmax = 865000, .val = 0x06 },
++	{ .rfmax =      0, .val = 0x00 }, /* end */
++};
 +
-+	tda18271_write_regs(fe, R_EP3, 7);
-+	msleep(5); /* pll locking */
++static struct tda18271_map tda18271_gain_taper[] = {
++	{ .rfmax =  45400, .val = 0x1f },
++	{ .rfmax =  45800, .val = 0x1e },
++	{ .rfmax =  46200, .val = 0x1d },
++	{ .rfmax =  46700, .val = 0x1c },
++	{ .rfmax =  47100, .val = 0x1b },
++	{ .rfmax =  47500, .val = 0x1a },
++	{ .rfmax =  47900, .val = 0x19 },
++	{ .rfmax =  49600, .val = 0x17 },
++	{ .rfmax =  51200, .val = 0x16 },
++	{ .rfmax =  52900, .val = 0x15 },
++	{ .rfmax =  54500, .val = 0x14 },
++	{ .rfmax =  56200, .val = 0x13 },
++	{ .rfmax =  57800, .val = 0x12 },
++	{ .rfmax =  59500, .val = 0x11 },
++	{ .rfmax =  61100, .val = 0x10 },
++	{ .rfmax =  67600, .val = 0x0d },
++	{ .rfmax =  74200, .val = 0x0c },
++	{ .rfmax =  80700, .val = 0x0b },
++	{ .rfmax =  87200, .val = 0x0a },
++	{ .rfmax =  93800, .val = 0x09 },
++	{ .rfmax = 100300, .val = 0x08 },
++	{ .rfmax = 106900, .val = 0x07 },
++	{ .rfmax = 113400, .val = 0x06 },
++	{ .rfmax = 119900, .val = 0x05 },
++	{ .rfmax = 126500, .val = 0x04 },
++	{ .rfmax = 133000, .val = 0x03 },
++	{ .rfmax = 139500, .val = 0x02 },
++	{ .rfmax = 146100, .val = 0x01 },
++	{ .rfmax = 152600, .val = 0x00 },
++	{ .rfmax = 154300, .val = 0x1f },
++	{ .rfmax = 156100, .val = 0x1e },
++	{ .rfmax = 157800, .val = 0x1d },
++	{ .rfmax = 159500, .val = 0x1c },
++	{ .rfmax = 161200, .val = 0x1b },
++	{ .rfmax = 163000, .val = 0x1a },
++	{ .rfmax = 164700, .val = 0x19 },
++	{ .rfmax = 170200, .val = 0x17 },
++	{ .rfmax = 175800, .val = 0x16 },
++	{ .rfmax = 181300, .val = 0x15 },
++	{ .rfmax = 186900, .val = 0x14 },
++	{ .rfmax = 192400, .val = 0x13 },
++	{ .rfmax = 198000, .val = 0x12 },
++	{ .rfmax = 203500, .val = 0x11 },
++	{ .rfmax = 216200, .val = 0x14 },
++	{ .rfmax = 228900, .val = 0x13 },
++	{ .rfmax = 241600, .val = 0x12 },
++	{ .rfmax = 254400, .val = 0x11 },
++	{ .rfmax = 267100, .val = 0x10 },
++	{ .rfmax = 279800, .val = 0x0f },
++	{ .rfmax = 292500, .val = 0x0e },
++	{ .rfmax = 305200, .val = 0x0d },
++	{ .rfmax = 317900, .val = 0x0c },
++	{ .rfmax = 330700, .val = 0x0b },
++	{ .rfmax = 343400, .val = 0x0a },
++	{ .rfmax = 356100, .val = 0x09 },
++	{ .rfmax = 368800, .val = 0x08 },
++	{ .rfmax = 381500, .val = 0x07 },
++	{ .rfmax = 394200, .val = 0x06 },
++	{ .rfmax = 406900, .val = 0x05 },
++	{ .rfmax = 419700, .val = 0x04 },
++	{ .rfmax = 432400, .val = 0x03 },
++	{ .rfmax = 445100, .val = 0x02 },
++	{ .rfmax = 457800, .val = 0x01 },
++	{ .rfmax = 476300, .val = 0x19 },
++	{ .rfmax = 494800, .val = 0x18 },
++	{ .rfmax = 513300, .val = 0x17 },
++	{ .rfmax = 531800, .val = 0x16 },
++	{ .rfmax = 550300, .val = 0x15 },
++	{ .rfmax = 568900, .val = 0x14 },
++	{ .rfmax = 587400, .val = 0x13 },
++	{ .rfmax = 605900, .val = 0x12 },
++	{ .rfmax = 624400, .val = 0x11 },
++	{ .rfmax = 642900, .val = 0x10 },
++	{ .rfmax = 661400, .val = 0x0f },
++	{ .rfmax = 679900, .val = 0x0e },
++	{ .rfmax = 698400, .val = 0x0d },
++	{ .rfmax = 716900, .val = 0x0c },
++	{ .rfmax = 735400, .val = 0x0b },
++	{ .rfmax = 753900, .val = 0x0a },
++	{ .rfmax = 772500, .val = 0x09 },
++	{ .rfmax = 791000, .val = 0x08 },
++	{ .rfmax = 809500, .val = 0x07 },
++	{ .rfmax = 828000, .val = 0x06 },
++	{ .rfmax = 846500, .val = 0x05 },
++	{ .rfmax = 865000, .val = 0x04 },
++	{ .rfmax =      0, .val = 0x00 }, /* end */
++};
 +
-+	/* launch optimization algorithm */
-+	tda18271_write_regs(fe, R_EP2, 1);
-+	msleep(30); /* image mid optimization completion */
++static struct tda18271_map tda18271c1_rf_cal[] = {
++	{ .rfmax = 41000, .val = 0x1e },
++	{ .rfmax = 43000, .val = 0x30 },
++	{ .rfmax = 45000, .val = 0x43 },
++	{ .rfmax = 46000, .val = 0x4d },
++	{ .rfmax = 47000, .val = 0x54 },
++	{ .rfmax = 47900, .val = 0x64 },
++	{ .rfmax = 49100, .val = 0x20 },
++	{ .rfmax = 50000, .val = 0x22 },
++	{ .rfmax = 51000, .val = 0x2a },
++	{ .rfmax = 53000, .val = 0x32 },
++	{ .rfmax = 55000, .val = 0x35 },
++	{ .rfmax = 56000, .val = 0x3c },
++	{ .rfmax = 57000, .val = 0x3f },
++	{ .rfmax = 58000, .val = 0x48 },
++	{ .rfmax = 59000, .val = 0x4d },
++	{ .rfmax = 60000, .val = 0x58 },
++	{ .rfmax = 61100, .val = 0x5f },
++	{ .rfmax =     0, .val = 0x00 }, /* end */
++};
 +
-+	/* high-band */
-+	regs[R_EP5] = 0x83;
-+	regs[R_CPD] = 0x98;
-+	regs[R_CD1] = 0x65;
-+	regs[R_CD2] = 0x00;
-+	regs[R_MPD] = 0x99;
-+	regs[R_MD1] = 0x71;
-+	regs[R_MD2] = 0xcd;
++static struct tda18271_map tda18271c2_rf_cal[] = {
++	{ .rfmax =  41000, .val = 0x0f },
++	{ .rfmax =  43000, .val = 0x1c },
++	{ .rfmax =  45000, .val = 0x2f },
++	{ .rfmax =  46000, .val = 0x39 },
++	{ .rfmax =  47000, .val = 0x40 },
++	{ .rfmax =  47900, .val = 0x50 },
++	{ .rfmax =  49100, .val = 0x16 },
++	{ .rfmax =  50000, .val = 0x18 },
++	{ .rfmax =  51000, .val = 0x20 },
++	{ .rfmax =  53000, .val = 0x28 },
++	{ .rfmax =  55000, .val = 0x2b },
++	{ .rfmax =  56000, .val = 0x32 },
++	{ .rfmax =  57000, .val = 0x35 },
++	{ .rfmax =  58000, .val = 0x3e },
++	{ .rfmax =  59000, .val = 0x43 },
++	{ .rfmax =  60000, .val = 0x4e },
++	{ .rfmax =  61100, .val = 0x55 },
++	{ .rfmax =  63000, .val = 0x0f },
++	{ .rfmax =  64000, .val = 0x11 },
++	{ .rfmax =  65000, .val = 0x12 },
++	{ .rfmax =  66000, .val = 0x15 },
++	{ .rfmax =  67000, .val = 0x16 },
++	{ .rfmax =  68000, .val = 0x17 },
++	{ .rfmax =  70000, .val = 0x19 },
++	{ .rfmax =  71000, .val = 0x1c },
++	{ .rfmax =  72000, .val = 0x1d },
++	{ .rfmax =  73000, .val = 0x1f },
++	{ .rfmax =  74000, .val = 0x20 },
++	{ .rfmax =  75000, .val = 0x21 },
++	{ .rfmax =  76000, .val = 0x24 },
++	{ .rfmax =  77000, .val = 0x25 },
++	{ .rfmax =  78000, .val = 0x27 },
++	{ .rfmax =  80000, .val = 0x28 },
++	{ .rfmax =  81000, .val = 0x29 },
++	{ .rfmax =  82000, .val = 0x2d },
++	{ .rfmax =  83000, .val = 0x2e },
++	{ .rfmax =  84000, .val = 0x2f },
++	{ .rfmax =  85000, .val = 0x31 },
++	{ .rfmax =  86000, .val = 0x33 },
++	{ .rfmax =  87000, .val = 0x34 },
++	{ .rfmax =  88000, .val = 0x35 },
++	{ .rfmax =  89000, .val = 0x37 },
++	{ .rfmax =  90000, .val = 0x38 },
++	{ .rfmax =  91000, .val = 0x39 },
++	{ .rfmax =  93000, .val = 0x3c },
++	{ .rfmax =  94000, .val = 0x3e },
++	{ .rfmax =  95000, .val = 0x3f },
++	{ .rfmax =  96000, .val = 0x40 },
++	{ .rfmax =  97000, .val = 0x42 },
++	{ .rfmax =  99000, .val = 0x45 },
++	{ .rfmax = 100000, .val = 0x46 },
++	{ .rfmax = 102000, .val = 0x48 },
++	{ .rfmax = 103000, .val = 0x4a },
++	{ .rfmax = 105000, .val = 0x4d },
++	{ .rfmax = 106000, .val = 0x4e },
++	{ .rfmax = 107000, .val = 0x50 },
++	{ .rfmax = 108000, .val = 0x51 },
++	{ .rfmax = 110000, .val = 0x54 },
++	{ .rfmax = 111000, .val = 0x56 },
++	{ .rfmax = 112000, .val = 0x57 },
++	{ .rfmax = 113000, .val = 0x58 },
++	{ .rfmax = 114000, .val = 0x59 },
++	{ .rfmax = 115000, .val = 0x5c },
++	{ .rfmax = 116000, .val = 0x5d },
++	{ .rfmax = 117000, .val = 0x5f },
++	{ .rfmax = 119000, .val = 0x60 },
++	{ .rfmax = 120000, .val = 0x64 },
++	{ .rfmax = 121000, .val = 0x65 },
++	{ .rfmax = 122000, .val = 0x66 },
++	{ .rfmax = 123000, .val = 0x68 },
++	{ .rfmax = 124000, .val = 0x69 },
++	{ .rfmax = 125000, .val = 0x6c },
++	{ .rfmax = 126000, .val = 0x6d },
++	{ .rfmax = 127000, .val = 0x6e },
++	{ .rfmax = 128000, .val = 0x70 },
++	{ .rfmax = 129000, .val = 0x71 },
++	{ .rfmax = 130000, .val = 0x75 },
++	{ .rfmax = 131000, .val = 0x77 },
++	{ .rfmax = 132000, .val = 0x78 },
++	{ .rfmax = 133000, .val = 0x7b },
++	{ .rfmax = 134000, .val = 0x7e },
++	{ .rfmax = 135000, .val = 0x81 },
++	{ .rfmax = 136000, .val = 0x82 },
++	{ .rfmax = 137000, .val = 0x87 },
++	{ .rfmax = 138000, .val = 0x88 },
++	{ .rfmax = 139000, .val = 0x8d },
++	{ .rfmax = 140000, .val = 0x8e },
++	{ .rfmax = 141000, .val = 0x91 },
++	{ .rfmax = 142000, .val = 0x95 },
++	{ .rfmax = 143000, .val = 0x9a },
++	{ .rfmax = 144000, .val = 0x9d },
++	{ .rfmax = 145000, .val = 0xa1 },
++	{ .rfmax = 146000, .val = 0xa2 },
++	{ .rfmax = 147000, .val = 0xa4 },
++	{ .rfmax = 148000, .val = 0xa9 },
++	{ .rfmax = 149000, .val = 0xae },
++	{ .rfmax = 150000, .val = 0xb0 },
++	{ .rfmax = 151000, .val = 0xb1 },
++	{ .rfmax = 152000, .val = 0xb7 },
++	{ .rfmax = 153000, .val = 0xbd },
++	{ .rfmax = 154000, .val = 0x20 },
++	{ .rfmax = 155000, .val = 0x22 },
++	{ .rfmax = 156000, .val = 0x24 },
++	{ .rfmax = 157000, .val = 0x25 },
++	{ .rfmax = 158000, .val = 0x27 },
++	{ .rfmax = 159000, .val = 0x29 },
++	{ .rfmax = 160000, .val = 0x2c },
++	{ .rfmax = 161000, .val = 0x2d },
++	{ .rfmax = 163000, .val = 0x2e },
++	{ .rfmax = 164000, .val = 0x2f },
++	{ .rfmax = 165000, .val = 0x30 },
++	{ .rfmax = 166000, .val = 0x11 },
++	{ .rfmax = 167000, .val = 0x12 },
++	{ .rfmax = 168000, .val = 0x13 },
++	{ .rfmax = 169000, .val = 0x14 },
++	{ .rfmax = 170000, .val = 0x15 },
++	{ .rfmax = 172000, .val = 0x16 },
++	{ .rfmax = 173000, .val = 0x17 },
++	{ .rfmax = 174000, .val = 0x18 },
++	{ .rfmax = 175000, .val = 0x1a },
++	{ .rfmax = 176000, .val = 0x1b },
++	{ .rfmax = 178000, .val = 0x1d },
++	{ .rfmax = 179000, .val = 0x1e },
++	{ .rfmax = 180000, .val = 0x1f },
++	{ .rfmax = 181000, .val = 0x20 },
++	{ .rfmax = 182000, .val = 0x21 },
++	{ .rfmax = 183000, .val = 0x22 },
++	{ .rfmax = 184000, .val = 0x24 },
++	{ .rfmax = 185000, .val = 0x25 },
++	{ .rfmax = 186000, .val = 0x26 },
++	{ .rfmax = 187000, .val = 0x27 },
++	{ .rfmax = 188000, .val = 0x29 },
++	{ .rfmax = 189000, .val = 0x2a },
++	{ .rfmax = 190000, .val = 0x2c },
++	{ .rfmax = 191000, .val = 0x2d },
++	{ .rfmax = 192000, .val = 0x2e },
++	{ .rfmax = 193000, .val = 0x2f },
++	{ .rfmax = 194000, .val = 0x30 },
++	{ .rfmax = 195000, .val = 0x33 },
++	{ .rfmax = 196000, .val = 0x35 },
++	{ .rfmax = 198000, .val = 0x36 },
++	{ .rfmax = 200000, .val = 0x38 },
++	{ .rfmax = 201000, .val = 0x3c },
++	{ .rfmax = 202000, .val = 0x3d },
++	{ .rfmax = 203500, .val = 0x3e },
++	{ .rfmax = 206000, .val = 0x0e },
++	{ .rfmax = 208000, .val = 0x0f },
++	{ .rfmax = 212000, .val = 0x10 },
++	{ .rfmax = 216000, .val = 0x11 },
++	{ .rfmax = 217000, .val = 0x12 },
++	{ .rfmax = 218000, .val = 0x13 },
++	{ .rfmax = 220000, .val = 0x14 },
++	{ .rfmax = 222000, .val = 0x15 },
++	{ .rfmax = 225000, .val = 0x16 },
++	{ .rfmax = 228000, .val = 0x17 },
++	{ .rfmax = 231000, .val = 0x18 },
++	{ .rfmax = 234000, .val = 0x19 },
++	{ .rfmax = 235000, .val = 0x1a },
++	{ .rfmax = 236000, .val = 0x1b },
++	{ .rfmax = 237000, .val = 0x1c },
++	{ .rfmax = 240000, .val = 0x1d },
++	{ .rfmax = 242000, .val = 0x1f },
++	{ .rfmax = 247000, .val = 0x20 },
++	{ .rfmax = 249000, .val = 0x21 },
++	{ .rfmax = 252000, .val = 0x22 },
++	{ .rfmax = 253000, .val = 0x23 },
++	{ .rfmax = 254000, .val = 0x24 },
++	{ .rfmax = 256000, .val = 0x25 },
++	{ .rfmax = 259000, .val = 0x26 },
++	{ .rfmax = 262000, .val = 0x27 },
++	{ .rfmax = 264000, .val = 0x28 },
++	{ .rfmax = 267000, .val = 0x29 },
++	{ .rfmax = 269000, .val = 0x2a },
++	{ .rfmax = 271000, .val = 0x2b },
++	{ .rfmax = 273000, .val = 0x2c },
++	{ .rfmax = 275000, .val = 0x2d },
++	{ .rfmax = 277000, .val = 0x2e },
++	{ .rfmax = 279000, .val = 0x2f },
++	{ .rfmax = 282000, .val = 0x30 },
++	{ .rfmax = 284000, .val = 0x31 },
++	{ .rfmax = 286000, .val = 0x32 },
++	{ .rfmax = 287000, .val = 0x33 },
++	{ .rfmax = 290000, .val = 0x34 },
++	{ .rfmax = 293000, .val = 0x35 },
++	{ .rfmax = 295000, .val = 0x36 },
++	{ .rfmax = 297000, .val = 0x37 },
++	{ .rfmax = 300000, .val = 0x38 },
++	{ .rfmax = 303000, .val = 0x39 },
++	{ .rfmax = 305000, .val = 0x3a },
++	{ .rfmax = 306000, .val = 0x3b },
++	{ .rfmax = 307000, .val = 0x3c },
++	{ .rfmax = 310000, .val = 0x3d },
++	{ .rfmax = 312000, .val = 0x3e },
++	{ .rfmax = 315000, .val = 0x3f },
++	{ .rfmax = 318000, .val = 0x40 },
++	{ .rfmax = 320000, .val = 0x41 },
++	{ .rfmax = 323000, .val = 0x42 },
++	{ .rfmax = 324000, .val = 0x43 },
++	{ .rfmax = 325000, .val = 0x44 },
++	{ .rfmax = 327000, .val = 0x45 },
++	{ .rfmax = 331000, .val = 0x46 },
++	{ .rfmax = 334000, .val = 0x47 },
++	{ .rfmax = 337000, .val = 0x48 },
++	{ .rfmax = 339000, .val = 0x49 },
++	{ .rfmax = 340000, .val = 0x4a },
++	{ .rfmax = 341000, .val = 0x4b },
++	{ .rfmax = 343000, .val = 0x4c },
++	{ .rfmax = 345000, .val = 0x4d },
++	{ .rfmax = 349000, .val = 0x4e },
++	{ .rfmax = 352000, .val = 0x4f },
++	{ .rfmax = 353000, .val = 0x50 },
++	{ .rfmax = 355000, .val = 0x51 },
++	{ .rfmax = 357000, .val = 0x52 },
++	{ .rfmax = 359000, .val = 0x53 },
++	{ .rfmax = 361000, .val = 0x54 },
++	{ .rfmax = 362000, .val = 0x55 },
++	{ .rfmax = 364000, .val = 0x56 },
++	{ .rfmax = 368000, .val = 0x57 },
++	{ .rfmax = 370000, .val = 0x58 },
++	{ .rfmax = 372000, .val = 0x59 },
++	{ .rfmax = 375000, .val = 0x5a },
++	{ .rfmax = 376000, .val = 0x5b },
++	{ .rfmax = 377000, .val = 0x5c },
++	{ .rfmax = 379000, .val = 0x5d },
++	{ .rfmax = 382000, .val = 0x5e },
++	{ .rfmax = 384000, .val = 0x5f },
++	{ .rfmax = 385000, .val = 0x60 },
++	{ .rfmax = 386000, .val = 0x61 },
++	{ .rfmax = 388000, .val = 0x62 },
++	{ .rfmax = 390000, .val = 0x63 },
++	{ .rfmax = 393000, .val = 0x64 },
++	{ .rfmax = 394000, .val = 0x65 },
++	{ .rfmax = 396000, .val = 0x66 },
++	{ .rfmax = 397000, .val = 0x67 },
++	{ .rfmax = 398000, .val = 0x68 },
++	{ .rfmax = 400000, .val = 0x69 },
++	{ .rfmax = 402000, .val = 0x6a },
++	{ .rfmax = 403000, .val = 0x6b },
++	{ .rfmax = 407000, .val = 0x6c },
++	{ .rfmax = 408000, .val = 0x6d },
++	{ .rfmax = 409000, .val = 0x6e },
++	{ .rfmax = 410000, .val = 0x6f },
++	{ .rfmax = 411000, .val = 0x70 },
++	{ .rfmax = 412000, .val = 0x71 },
++	{ .rfmax = 413000, .val = 0x72 },
++	{ .rfmax = 414000, .val = 0x73 },
++	{ .rfmax = 417000, .val = 0x74 },
++	{ .rfmax = 418000, .val = 0x75 },
++	{ .rfmax = 420000, .val = 0x76 },
++	{ .rfmax = 422000, .val = 0x77 },
++	{ .rfmax = 423000, .val = 0x78 },
++	{ .rfmax = 424000, .val = 0x79 },
++	{ .rfmax = 427000, .val = 0x7a },
++	{ .rfmax = 428000, .val = 0x7b },
++	{ .rfmax = 429000, .val = 0x7d },
++	{ .rfmax = 432000, .val = 0x7f },
++	{ .rfmax = 434000, .val = 0x80 },
++	{ .rfmax = 435000, .val = 0x81 },
++	{ .rfmax = 436000, .val = 0x83 },
++	{ .rfmax = 437000, .val = 0x84 },
++	{ .rfmax = 438000, .val = 0x85 },
++	{ .rfmax = 439000, .val = 0x86 },
++	{ .rfmax = 440000, .val = 0x87 },
++	{ .rfmax = 441000, .val = 0x88 },
++	{ .rfmax = 442000, .val = 0x89 },
++	{ .rfmax = 445000, .val = 0x8a },
++	{ .rfmax = 446000, .val = 0x8b },
++	{ .rfmax = 447000, .val = 0x8c },
++	{ .rfmax = 448000, .val = 0x8e },
++	{ .rfmax = 449000, .val = 0x8f },
++	{ .rfmax = 450000, .val = 0x90 },
++	{ .rfmax = 452000, .val = 0x91 },
++	{ .rfmax = 453000, .val = 0x93 },
++	{ .rfmax = 454000, .val = 0x94 },
++	{ .rfmax = 456000, .val = 0x96 },
++	{ .rfmax = 457000, .val = 0x98 },
++	{ .rfmax = 461000, .val = 0x11 },
++	{ .rfmax = 468000, .val = 0x12 },
++	{ .rfmax = 472000, .val = 0x13 },
++	{ .rfmax = 473000, .val = 0x14 },
++	{ .rfmax = 474000, .val = 0x15 },
++	{ .rfmax = 481000, .val = 0x16 },
++	{ .rfmax = 486000, .val = 0x17 },
++	{ .rfmax = 491000, .val = 0x18 },
++	{ .rfmax = 498000, .val = 0x19 },
++	{ .rfmax = 499000, .val = 0x1a },
++	{ .rfmax = 501000, .val = 0x1b },
++	{ .rfmax = 506000, .val = 0x1c },
++	{ .rfmax = 511000, .val = 0x1d },
++	{ .rfmax = 516000, .val = 0x1e },
++	{ .rfmax = 520000, .val = 0x1f },
++	{ .rfmax = 521000, .val = 0x20 },
++	{ .rfmax = 525000, .val = 0x21 },
++	{ .rfmax = 529000, .val = 0x22 },
++	{ .rfmax = 533000, .val = 0x23 },
++	{ .rfmax = 539000, .val = 0x24 },
++	{ .rfmax = 541000, .val = 0x25 },
++	{ .rfmax = 547000, .val = 0x26 },
++	{ .rfmax = 549000, .val = 0x27 },
++	{ .rfmax = 551000, .val = 0x28 },
++	{ .rfmax = 556000, .val = 0x29 },
++	{ .rfmax = 561000, .val = 0x2a },
++	{ .rfmax = 563000, .val = 0x2b },
++	{ .rfmax = 565000, .val = 0x2c },
++	{ .rfmax = 569000, .val = 0x2d },
++	{ .rfmax = 571000, .val = 0x2e },
++	{ .rfmax = 577000, .val = 0x2f },
++	{ .rfmax = 580000, .val = 0x30 },
++	{ .rfmax = 582000, .val = 0x31 },
++	{ .rfmax = 584000, .val = 0x32 },
++	{ .rfmax = 588000, .val = 0x33 },
++	{ .rfmax = 591000, .val = 0x34 },
++	{ .rfmax = 596000, .val = 0x35 },
++	{ .rfmax = 598000, .val = 0x36 },
++	{ .rfmax = 603000, .val = 0x37 },
++	{ .rfmax = 604000, .val = 0x38 },
++	{ .rfmax = 606000, .val = 0x39 },
++	{ .rfmax = 612000, .val = 0x3a },
++	{ .rfmax = 615000, .val = 0x3b },
++	{ .rfmax = 617000, .val = 0x3c },
++	{ .rfmax = 621000, .val = 0x3d },
++	{ .rfmax = 622000, .val = 0x3e },
++	{ .rfmax = 625000, .val = 0x3f },
++	{ .rfmax = 632000, .val = 0x40 },
++	{ .rfmax = 633000, .val = 0x41 },
++	{ .rfmax = 634000, .val = 0x42 },
++	{ .rfmax = 642000, .val = 0x43 },
++	{ .rfmax = 643000, .val = 0x44 },
++	{ .rfmax = 647000, .val = 0x45 },
++	{ .rfmax = 650000, .val = 0x46 },
++	{ .rfmax = 652000, .val = 0x47 },
++	{ .rfmax = 657000, .val = 0x48 },
++	{ .rfmax = 661000, .val = 0x49 },
++	{ .rfmax = 662000, .val = 0x4a },
++	{ .rfmax = 665000, .val = 0x4b },
++	{ .rfmax = 667000, .val = 0x4c },
++	{ .rfmax = 670000, .val = 0x4d },
++	{ .rfmax = 673000, .val = 0x4e },
++	{ .rfmax = 676000, .val = 0x4f },
++	{ .rfmax = 677000, .val = 0x50 },
++	{ .rfmax = 681000, .val = 0x51 },
++	{ .rfmax = 683000, .val = 0x52 },
++	{ .rfmax = 686000, .val = 0x53 },
++	{ .rfmax = 688000, .val = 0x54 },
++	{ .rfmax = 689000, .val = 0x55 },
++	{ .rfmax = 691000, .val = 0x56 },
++	{ .rfmax = 695000, .val = 0x57 },
++	{ .rfmax = 698000, .val = 0x58 },
++	{ .rfmax = 703000, .val = 0x59 },
++	{ .rfmax = 704000, .val = 0x5a },
++	{ .rfmax = 705000, .val = 0x5b },
++	{ .rfmax = 707000, .val = 0x5c },
++	{ .rfmax = 710000, .val = 0x5d },
++	{ .rfmax = 712000, .val = 0x5e },
++	{ .rfmax = 717000, .val = 0x5f },
++	{ .rfmax = 718000, .val = 0x60 },
++	{ .rfmax = 721000, .val = 0x61 },
++	{ .rfmax = 722000, .val = 0x62 },
++	{ .rfmax = 723000, .val = 0x63 },
++	{ .rfmax = 725000, .val = 0x64 },
++	{ .rfmax = 727000, .val = 0x65 },
++	{ .rfmax = 730000, .val = 0x66 },
++	{ .rfmax = 732000, .val = 0x67 },
++	{ .rfmax = 735000, .val = 0x68 },
++	{ .rfmax = 740000, .val = 0x69 },
++	{ .rfmax = 741000, .val = 0x6a },
++	{ .rfmax = 742000, .val = 0x6b },
++	{ .rfmax = 743000, .val = 0x6c },
++	{ .rfmax = 745000, .val = 0x6d },
++	{ .rfmax = 747000, .val = 0x6e },
++	{ .rfmax = 748000, .val = 0x6f },
++	{ .rfmax = 750000, .val = 0x70 },
++	{ .rfmax = 752000, .val = 0x71 },
++	{ .rfmax = 754000, .val = 0x72 },
++	{ .rfmax = 757000, .val = 0x73 },
++	{ .rfmax = 758000, .val = 0x74 },
++	{ .rfmax = 760000, .val = 0x75 },
++	{ .rfmax = 763000, .val = 0x76 },
++	{ .rfmax = 764000, .val = 0x77 },
++	{ .rfmax = 766000, .val = 0x78 },
++	{ .rfmax = 767000, .val = 0x79 },
++	{ .rfmax = 768000, .val = 0x7a },
++	{ .rfmax = 773000, .val = 0x7b },
++	{ .rfmax = 774000, .val = 0x7c },
++	{ .rfmax = 776000, .val = 0x7d },
++	{ .rfmax = 777000, .val = 0x7e },
++	{ .rfmax = 778000, .val = 0x7f },
++	{ .rfmax = 779000, .val = 0x80 },
++	{ .rfmax = 781000, .val = 0x81 },
++	{ .rfmax = 783000, .val = 0x82 },
++	{ .rfmax = 784000, .val = 0x83 },
++	{ .rfmax = 785000, .val = 0x84 },
++	{ .rfmax = 786000, .val = 0x85 },
++	{ .rfmax = 793000, .val = 0x86 },
++	{ .rfmax = 794000, .val = 0x87 },
++	{ .rfmax = 795000, .val = 0x88 },
++	{ .rfmax = 797000, .val = 0x89 },
++	{ .rfmax = 799000, .val = 0x8a },
++	{ .rfmax = 801000, .val = 0x8b },
++	{ .rfmax = 802000, .val = 0x8c },
++	{ .rfmax = 803000, .val = 0x8d },
++	{ .rfmax = 804000, .val = 0x8e },
++	{ .rfmax = 810000, .val = 0x90 },
++	{ .rfmax = 811000, .val = 0x91 },
++	{ .rfmax = 812000, .val = 0x92 },
++	{ .rfmax = 814000, .val = 0x93 },
++	{ .rfmax = 816000, .val = 0x94 },
++	{ .rfmax = 817000, .val = 0x96 },
++	{ .rfmax = 818000, .val = 0x97 },
++	{ .rfmax = 820000, .val = 0x98 },
++	{ .rfmax = 821000, .val = 0x99 },
++	{ .rfmax = 822000, .val = 0x9a },
++	{ .rfmax = 828000, .val = 0x9b },
++	{ .rfmax = 829000, .val = 0x9d },
++	{ .rfmax = 830000, .val = 0x9f },
++	{ .rfmax = 831000, .val = 0xa0 },
++	{ .rfmax = 833000, .val = 0xa1 },
++	{ .rfmax = 835000, .val = 0xa2 },
++	{ .rfmax = 836000, .val = 0xa3 },
++	{ .rfmax = 837000, .val = 0xa4 },
++	{ .rfmax = 838000, .val = 0xa6 },
++	{ .rfmax = 840000, .val = 0xa8 },
++	{ .rfmax = 842000, .val = 0xa9 },
++	{ .rfmax = 845000, .val = 0xaa },
++	{ .rfmax = 846000, .val = 0xab },
++	{ .rfmax = 847000, .val = 0xad },
++	{ .rfmax = 848000, .val = 0xae },
++	{ .rfmax = 852000, .val = 0xaf },
++	{ .rfmax = 853000, .val = 0xb0 },
++	{ .rfmax = 858000, .val = 0xb1 },
++	{ .rfmax = 860000, .val = 0xb2 },
++	{ .rfmax = 861000, .val = 0xb3 },
++	{ .rfmax = 862000, .val = 0xb4 },
++	{ .rfmax = 863000, .val = 0xb6 },
++	{ .rfmax = 864000, .val = 0xb8 },
++	{ .rfmax = 865000, .val = 0xb9 },
++	{ .rfmax =      0, .val = 0x00 }, /* end */
++};
 +
-+	tda18271_write_regs(fe, R_EP3, 11);
-+	msleep(5); /* pll locking */
++static struct tda18271_map tda18271_ir_measure[] = {
++	{ .rfmax =  30000, .val = 4 },
++	{ .rfmax = 200000, .val = 5 },
++	{ .rfmax = 600000, .val = 6 },
++	{ .rfmax = 865000, .val = 7 },
++	{ .rfmax =      0, .val = 0 }, /* end */
++};
 +
-+	/* launch detector */
-+	tda18271_write_regs(fe, R_EP1, 1);
-+	msleep(5); /* wanted high measurement */
++static struct tda18271_map tda18271_rf_cal_dc_over_dt[] = {
++	{ .rfmax =  47900, .val = 0x00 },
++	{ .rfmax =  55000, .val = 0x00 },
++	{ .rfmax =  61100, .val = 0x0a },
++	{ .rfmax =  64000, .val = 0x0a },
++	{ .rfmax =  82000, .val = 0x14 },
++	{ .rfmax =  84000, .val = 0x19 },
++	{ .rfmax = 119000, .val = 0x1c },
++	{ .rfmax = 124000, .val = 0x20 },
++	{ .rfmax = 129000, .val = 0x2a },
++	{ .rfmax = 134000, .val = 0x32 },
++	{ .rfmax = 139000, .val = 0x39 },
++	{ .rfmax = 144000, .val = 0x3e },
++	{ .rfmax = 149000, .val = 0x3f },
++	{ .rfmax = 152600, .val = 0x40 },
++	{ .rfmax = 154000, .val = 0x40 },
++	{ .rfmax = 164700, .val = 0x41 },
++	{ .rfmax = 203500, .val = 0x32 },
++	{ .rfmax = 353000, .val = 0x19 },
++	{ .rfmax = 356000, .val = 0x1a },
++	{ .rfmax = 359000, .val = 0x1b },
++	{ .rfmax = 363000, .val = 0x1c },
++	{ .rfmax = 366000, .val = 0x1d },
++	{ .rfmax = 369000, .val = 0x1e },
++	{ .rfmax = 373000, .val = 0x1f },
++	{ .rfmax = 376000, .val = 0x20 },
++	{ .rfmax = 379000, .val = 0x21 },
++	{ .rfmax = 383000, .val = 0x22 },
++	{ .rfmax = 386000, .val = 0x23 },
++	{ .rfmax = 389000, .val = 0x24 },
++	{ .rfmax = 393000, .val = 0x25 },
++	{ .rfmax = 396000, .val = 0x26 },
++	{ .rfmax = 399000, .val = 0x27 },
++	{ .rfmax = 402000, .val = 0x28 },
++	{ .rfmax = 404000, .val = 0x29 },
++	{ .rfmax = 407000, .val = 0x2a },
++	{ .rfmax = 409000, .val = 0x2b },
++	{ .rfmax = 412000, .val = 0x2c },
++	{ .rfmax = 414000, .val = 0x2d },
++	{ .rfmax = 417000, .val = 0x2e },
++	{ .rfmax = 419000, .val = 0x2f },
++	{ .rfmax = 422000, .val = 0x30 },
++	{ .rfmax = 424000, .val = 0x31 },
++	{ .rfmax = 427000, .val = 0x32 },
++	{ .rfmax = 429000, .val = 0x33 },
++	{ .rfmax = 432000, .val = 0x34 },
++	{ .rfmax = 434000, .val = 0x35 },
++	{ .rfmax = 437000, .val = 0x36 },
++	{ .rfmax = 439000, .val = 0x37 },
++	{ .rfmax = 442000, .val = 0x38 },
++	{ .rfmax = 444000, .val = 0x39 },
++	{ .rfmax = 447000, .val = 0x3a },
++	{ .rfmax = 449000, .val = 0x3b },
++	{ .rfmax = 457800, .val = 0x3c },
++	{ .rfmax = 465000, .val = 0x0f },
++	{ .rfmax = 477000, .val = 0x12 },
++	{ .rfmax = 483000, .val = 0x14 },
++	{ .rfmax = 502000, .val = 0x19 },
++	{ .rfmax = 508000, .val = 0x1b },
++	{ .rfmax = 519000, .val = 0x1c },
++	{ .rfmax = 522000, .val = 0x1d },
++	{ .rfmax = 524000, .val = 0x1e },
++	{ .rfmax = 534000, .val = 0x1f },
++	{ .rfmax = 549000, .val = 0x20 },
++	{ .rfmax = 554000, .val = 0x22 },
++	{ .rfmax = 584000, .val = 0x24 },
++	{ .rfmax = 589000, .val = 0x26 },
++	{ .rfmax = 658000, .val = 0x27 },
++	{ .rfmax = 664000, .val = 0x2c },
++	{ .rfmax = 669000, .val = 0x2d },
++	{ .rfmax = 699000, .val = 0x2e },
++	{ .rfmax = 704000, .val = 0x30 },
++	{ .rfmax = 709000, .val = 0x31 },
++	{ .rfmax = 714000, .val = 0x32 },
++	{ .rfmax = 724000, .val = 0x33 },
++	{ .rfmax = 729000, .val = 0x36 },
++	{ .rfmax = 739000, .val = 0x38 },
++	{ .rfmax = 744000, .val = 0x39 },
++	{ .rfmax = 749000, .val = 0x3b },
++	{ .rfmax = 754000, .val = 0x3c },
++	{ .rfmax = 759000, .val = 0x3d },
++	{ .rfmax = 764000, .val = 0x3e },
++	{ .rfmax = 769000, .val = 0x3f },
++	{ .rfmax = 774000, .val = 0x40 },
++	{ .rfmax = 779000, .val = 0x41 },
++	{ .rfmax = 784000, .val = 0x43 },
++	{ .rfmax = 789000, .val = 0x46 },
++	{ .rfmax = 794000, .val = 0x48 },
++	{ .rfmax = 799000, .val = 0x4b },
++	{ .rfmax = 804000, .val = 0x4f },
++	{ .rfmax = 809000, .val = 0x54 },
++	{ .rfmax = 814000, .val = 0x59 },
++	{ .rfmax = 819000, .val = 0x5d },
++	{ .rfmax = 824000, .val = 0x61 },
++	{ .rfmax = 829000, .val = 0x68 },
++	{ .rfmax = 834000, .val = 0x6e },
++	{ .rfmax = 839000, .val = 0x75 },
++	{ .rfmax = 844000, .val = 0x7e },
++	{ .rfmax = 849000, .val = 0x82 },
++	{ .rfmax = 854000, .val = 0x84 },
++	{ .rfmax = 859000, .val = 0x8f },
++	{ .rfmax = 865000, .val = 0x9a },
++	{ .rfmax =      0, .val = 0x00 }, /* end */
++};
 +
-+	regs[R_EP5] = 0x87;
-+	regs[R_CD1] = 0x65;
-+	regs[R_CD2] = 0x50;
++/*---------------------------------------------------------------------*/
 +
-+	tda18271_write_regs(fe, R_EP3, 7);
-+	msleep(5); /* pll locking */
++struct tda18271_thermo_map {
++	u8 d;
++	u8 r0;
++	u8 r1;
++};
 +
-+	/* launch optimization algorithm */
-+	tda18271_write_regs(fe, R_EP2, 1);
-+	msleep(30); /* image high optimization completion */
++static struct tda18271_thermo_map tda18271_thermometer[] = {
++	{ .d = 0x00, .r0 = 60, .r1 =  92 },
++	{ .d = 0x01, .r0 = 62, .r1 =  94 },
++	{ .d = 0x02, .r0 = 66, .r1 =  98 },
++	{ .d = 0x03, .r0 = 64, .r1 =  96 },
++	{ .d = 0x04, .r0 = 74, .r1 = 106 },
++	{ .d = 0x05, .r0 = 72, .r1 = 104 },
++	{ .d = 0x06, .r0 = 68, .r1 = 100 },
++	{ .d = 0x07, .r0 = 70, .r1 = 102 },
++	{ .d = 0x08, .r0 = 90, .r1 = 122 },
++	{ .d = 0x09, .r0 = 88, .r1 = 120 },
++	{ .d = 0x0a, .r0 = 84, .r1 = 116 },
++	{ .d = 0x0b, .r0 = 86, .r1 = 118 },
++	{ .d = 0x0c, .r0 = 76, .r1 = 108 },
++	{ .d = 0x0d, .r0 = 78, .r1 = 110 },
++	{ .d = 0x0e, .r0 = 82, .r1 = 114 },
++	{ .d = 0x0f, .r0 = 80, .r1 = 112 },
++	{ .d = 0x00, .r0 =  0, .r1 =   0 }, /* end */
++};
 +
-+	/* return to normal mode */
-+	regs[R_EP4] = 0x64;
-+	tda18271_write_regs(fe, R_EP4, 1);
++int tda18271_lookup_thermometer(struct dvb_frontend *fe)
++{
++	struct tda18271_priv *priv = fe->tuner_priv;
++	unsigned char *regs = priv->tda18271_regs;
++	int val, i = 0;
 +
-+	/* synchronize */
-+	tda18271_write_regs(fe, R_EP1, 1);
++	while (tda18271_thermometer[i].d < (regs[R_TM] & 0x0f)) {
++		if (tda18271_thermometer[i + 1].d == 0)
++			break;
++		i++;
++	}
 +
-+	return 0;
++	if ((regs[R_TM] & 0x20) == 0x20)
++		val = tda18271_thermometer[i].r1;
++	else
++		val = tda18271_thermometer[i].r0;
++
++	tda_map("(%d) tm = %d\n", i, val);
++
++	return val;
 +}
 +
 +/*---------------------------------------------------------------------*/
 +
-+/*
-+ *  Standby modes, EP3 [7:5]
-+ *
-+ *  | SM  || SM_LT || SM_XT || mode description
-+ *  |=====\\=======\\=======\\===================================
-+ *  |  0  ||   0   ||   0   || normal mode
-+ *  |-----||-------||-------||-----------------------------------
-+ *  |     ||       ||       || standby mode w/ slave tuner output
-+ *  |  1  ||   0   ||   0   || & loop thru & xtal oscillator on
-+ *  |-----||-------||-------||-----------------------------------
-+ *  |  1  ||   1   ||   0   || standby mode w/ xtal oscillator on
-+ *  |-----||-------||-------||-----------------------------------
-+ *  |  1  ||   1   ||   1   || power off
-+ *
-+ */
++struct tda18271_cid_target_map {
++	u32 rfmax;
++	u8  target;
++	u16 limit;
++};
 +
-+int tda18271_set_standby_mode(struct dvb_frontend *fe,
-+			      int sm, int sm_lt, int sm_xt)
-+{
-+	struct tda18271_priv *priv = fe->tuner_priv;
-+	unsigned char *regs = priv->tda18271_regs;
++static struct tda18271_cid_target_map tda18271_cid_target[] = {
++	{ .rfmax =  46000, .target = 0x04, .limit =  1800 },
++	{ .rfmax =  52200, .target = 0x0a, .limit =  1500 },
++	{ .rfmax =  79100, .target = 0x01, .limit =  4000 },
++	{ .rfmax = 136800, .target = 0x18, .limit =  4000 },
++	{ .rfmax = 156700, .target = 0x18, .limit =  4000 },
++	{ .rfmax = 156700, .target = 0x18, .limit =  4000 },
++	{ .rfmax = 186250, .target = 0x0a, .limit =  4000 },
++	{ .rfmax = 230000, .target = 0x0a, .limit =  4000 },
++	{ .rfmax = 345000, .target = 0x18, .limit =  4000 },
++	{ .rfmax = 426000, .target = 0x0e, .limit =  4000 },
++	{ .rfmax = 489500, .target = 0x1e, .limit =  4000 },
++	{ .rfmax = 697500, .target = 0x32, .limit =  4000 },
++	{ .rfmax = 842000, .target = 0x3a, .limit =  4000 },
++	{ .rfmax =      0, .target = 0x00, .limit =     0 }, /* end */
++};
 +
-+	tda_dbg("sm = %d, sm_lt = %d, sm_xt = %d\n", sm, sm_lt, sm_xt);
++int tda18271_lookup_cid_target(struct dvb_frontend *fe,
++			       u32 *freq, u8 *cid_target, u16 *count_limit)
++{
++	int i = 0;
 +
-+	regs[R_EP3]  &= ~0xe0; /* clear sm, sm_lt, sm_xt */
-+	regs[R_EP3]  |= sm    ? (1 << 7) : 0 |
-+			sm_lt ? (1 << 6) : 0 |
-+			sm_xt ? (1 << 5) : 0;
++	while ((tda18271_cid_target[i].rfmax * 1000) < *freq) {
++		if (tda18271_cid_target[i + 1].rfmax == 0)
++			break;
++		i++;
++	}
++	*cid_target  = tda18271_cid_target[i].target;
++	*count_limit = tda18271_cid_target[i].limit;
 +
-+	tda18271_write_regs(fe, R_EP3, 1);
++	tda_map("(%d) cid_target = %02x, count_limit = %d\n", i,
++		tda18271_cid_target[i].target, tda18271_cid_target[i].limit);
 +
 +	return 0;
 +}
 +
 +/*---------------------------------------------------------------------*/
 +
-+int tda18271_calc_main_pll(struct dvb_frontend *fe, u32 freq)
++static struct tda18271_rf_tracking_filter_cal tda18271_rf_band_template[] = {
++	{ .rfmax =  47900, .rfband = 0x00,
++	  .rf1_def =  46000, .rf2_def =      0, .rf3_def =      0 },
++	{ .rfmax =  61100, .rfband = 0x01,
++	  .rf1_def =  52200, .rf2_def =      0, .rf3_def =      0 },
++	{ .rfmax = 152600, .rfband = 0x02,
++	  .rf1_def =  70100, .rf2_def = 136800, .rf3_def =      0 },
++	{ .rfmax = 164700, .rfband = 0x03,
++	  .rf1_def = 156700, .rf2_def =      0, .rf3_def =      0 },
++	{ .rfmax = 203500, .rfband = 0x04,
++	  .rf1_def = 186250, .rf2_def =      0, .rf3_def =      0 },
++	{ .rfmax = 457800, .rfband = 0x05,
++	  .rf1_def = 230000, .rf2_def = 345000, .rf3_def = 426000 },
++	{ .rfmax = 865000, .rfband = 0x06,
++	  .rf1_def = 489500, .rf2_def = 697500, .rf3_def = 842000 },
++	{ .rfmax =      0, .rfband = 0x00,
++	  .rf1_def =      0, .rf2_def =      0, .rf3_def =      0 }, /* end */
++};
++
++int tda18271_lookup_rf_band(struct dvb_frontend *fe, u32 *freq, u8 *rf_band)
 +{
-+	/* sets main post divider & divider bytes, but does not write them */
 +	struct tda18271_priv *priv = fe->tuner_priv;
-+	unsigned char *regs = priv->tda18271_regs;
-+	u8 d, pd;
-+	u32 div;
-+
-+	int ret = tda18271_lookup_pll_map(fe, MAIN_PLL, &freq, &pd, &d);
-+	if (ret < 0)
-+		goto fail;
-+
-+	regs[R_MPD]   = (0x77 & pd);
++	struct tda18271_rf_tracking_filter_cal *map = priv->rf_cal_state;
++	int i = 0;
 +
-+	switch (priv->mode) {
-+	case TDA18271_ANALOG:
-+		regs[R_MPD]  &= ~0x08;
-+		break;
-+	case TDA18271_DIGITAL:
-+		regs[R_MPD]  |=  0x08;
-+		break;
++	while ((map[i].rfmax * 1000) < *freq) {
++		if (tda18271_debug & DBG_ADV)
++			tda_map("(%d) rfmax = %d < freq = %d, "
++				"rf1_def = %d, rf2_def = %d, rf3_def = %d, "
++				"rf1 = %d, rf2 = %d, rf3 = %d, "
++				"rf_a1 = %d, rf_a2 = %d, "
++				"rf_b1 = %d, rf_b2 = %d\n",
++				i, map[i].rfmax * 1000, *freq,
++				map[i].rf1_def, map[i].rf2_def, map[i].rf3_def,
++				map[i].rf1, map[i].rf2, map[i].rf3,
++				map[i].rf_a1, map[i].rf_a2,
++				map[i].rf_b1, map[i].rf_b2);
++		if (map[i].rfmax == 0)
++			return -EINVAL;
++		i++;
 +	}
++	if (rf_band)
++		*rf_band = map[i].rfband;
 +
-+	div =  ((d * (freq / 1000)) << 7) / 125;
++	tda_map("(%d) rf_band = %02x\n", i, map[i].rfband);
 +
-+	regs[R_MD1]   = 0x7f & (div >> 16);
-+	regs[R_MD2]   = 0xff & (div >> 8);
-+	regs[R_MD3]   = 0xff & div;
-+fail:
-+	return ret;
++	return i;
 +}
 +
-+int tda18271_calc_cal_pll(struct dvb_frontend *fe, u32 freq)
-+{
-+	/* sets cal post divider & divider bytes, but does not write them */
-+	struct tda18271_priv *priv = fe->tuner_priv;
-+	unsigned char *regs = priv->tda18271_regs;
-+	u8 d, pd;
-+	u32 div;
-+
-+	int ret = tda18271_lookup_pll_map(fe, CAL_PLL, &freq, &pd, &d);
-+	if (ret < 0)
-+		goto fail;
++/*---------------------------------------------------------------------*/
 +
-+	regs[R_CPD]   = pd;
++struct tda18271_map_layout {
++	struct tda18271_pll_map *main_pll;
++	struct tda18271_pll_map *cal_pll;
 +
-+	div =  ((d * (freq / 1000)) << 7) / 125;
++	struct tda18271_map *rf_cal;
++	struct tda18271_map *rf_cal_kmco;
++	struct tda18271_map *rf_cal_dc_over_dt;
 +
-+	regs[R_CD1]   = 0x7f & (div >> 16);
-+	regs[R_CD2]   = 0xff & (div >> 8);
-+	regs[R_CD3]   = 0xff & div;
-+fail:
-+	return ret;
-+}
++	struct tda18271_map *bp_filter;
++	struct tda18271_map *rf_band;
++	struct tda18271_map *gain_taper;
++	struct tda18271_map *ir_measure;
++};
 +
 +/*---------------------------------------------------------------------*/
 +
-+int tda18271_calc_bp_filter(struct dvb_frontend *fe, u32 *freq)
++int tda18271_lookup_pll_map(struct dvb_frontend *fe,
++			    enum tda18271_map_type map_type,
++			    u32 *freq, u8 *post_div, u8 *div)
 +{
-+	/* sets bp filter bits, but does not write them */
 +	struct tda18271_priv *priv = fe->tuner_priv;
-+	unsigned char *regs = priv->tda18271_regs;
-+	u8 val;
++	struct tda18271_pll_map *map = NULL;
++	unsigned int i = 0;
++	char *map_name;
++	int ret = 0;
 +
-+	int ret = tda18271_lookup_map(fe, BP_FILTER, freq, &val);
-+	if (ret < 0)
++	BUG_ON(!priv->maps);
++
++	switch (map_type) {
++	case MAIN_PLL:
++		map = priv->maps->main_pll;
++		map_name = "main_pll";
++		break;
++	case CAL_PLL:
++		map = priv->maps->cal_pll;
++		map_name = "cal_pll";
++		break;
++	default:
++		/* we should never get here */
++		map_name = "undefined";
++		break;
++	}
++
++	if (!map) {
++		tda_warn("%s map is not set!\n", map_name);
++		ret = -EINVAL;
 +		goto fail;
++	}
 +
-+	regs[R_EP1]  &= ~0x07; /* clear bp filter bits */
-+	regs[R_EP1]  |= (0x07 & val);
++	while ((map[i].lomax * 1000) < *freq) {
++		if (map[i + 1].lomax == 0) {
++			tda_map("%s: frequency (%d) out of range\n",
++				map_name, *freq);
++			ret = -ERANGE;
++			break;
++		}
++		i++;
++	}
++	*post_div = map[i].pd;
++	*div      = map[i].d;
++
++	tda_map("(%d) %s: post div = 0x%02x, div = 0x%02x\n",
++		i, map_name, *post_div, *div);
 +fail:
 +	return ret;
 +}
 +
-+int tda18271_calc_km(struct dvb_frontend *fe, u32 *freq)
++int tda18271_lookup_map(struct dvb_frontend *fe,
++			enum tda18271_map_type map_type,
++			u32 *freq, u8 *val)
 +{
-+	/* sets K & M bits, but does not write them */
 +	struct tda18271_priv *priv = fe->tuner_priv;
-+	unsigned char *regs = priv->tda18271_regs;
-+	u8 val;
++	struct tda18271_map *map = NULL;
++	unsigned int i = 0;
++	char *map_name;
++	int ret = 0;
 +
-+	int ret = tda18271_lookup_map(fe, RF_CAL_KMCO, freq, &val);
-+	if (ret < 0)
++	BUG_ON(!priv->maps);
++
++	switch (map_type) {
++	case BP_FILTER:
++		map = priv->maps->bp_filter;
++		map_name = "bp_filter";
++		break;
++	case RF_CAL_KMCO:
++		map = priv->maps->rf_cal_kmco;
++		map_name = "km";
++		break;
++	case RF_BAND:
++		map = priv->maps->rf_band;
++		map_name = "rf_band";
++		break;
++	case GAIN_TAPER:
++		map = priv->maps->gain_taper;
++		map_name = "gain_taper";
++		break;
++	case RF_CAL:
++		map = priv->maps->rf_cal;
++		map_name = "rf_cal";
++		break;
++	case IR_MEASURE:
++		map = priv->maps->ir_measure;
++		map_name = "ir_measure";
++		break;
++	case RF_CAL_DC_OVER_DT:
++		map = priv->maps->rf_cal_dc_over_dt;
++		map_name = "rf_cal_dc_over_dt";
++		break;
++	default:
++		/* we should never get here */
++		map_name = "undefined";
++		break;
++	}
++
++	if (!map) {
++		tda_warn("%s map is not set!\n", map_name);
++		ret = -EINVAL;
 +		goto fail;
++	}
 +
-+	regs[R_EB13] &= ~0x7c; /* clear k & m bits */
-+	regs[R_EB13] |= (0x7c & val);
++	while ((map[i].rfmax * 1000) < *freq) {
++		if (map[i + 1].rfmax == 0) {
++			tda_map("%s: frequency (%d) out of range\n",
++				map_name, *freq);
++			ret = -ERANGE;
++			break;
++		}
++		i++;
++	}
++	*val = map[i].val;
++
++	tda_map("(%d) %s: 0x%02x\n", i, map_name, *val);
 +fail:
 +	return ret;
 +}
 +
-+int tda18271_calc_rf_band(struct dvb_frontend *fe, u32 *freq)
-+{
-+	/* sets rf band bits, but does not write them */
-+	struct tda18271_priv *priv = fe->tuner_priv;
-+	unsigned char *regs = priv->tda18271_regs;
-+	u8 val;
++/*---------------------------------------------------------------------*/
 +
-+	int ret = tda18271_lookup_map(fe, RF_BAND, freq, &val);
-+	if (ret < 0)
-+		goto fail;
++static struct tda18271_std_map tda18271c1_std_map = {
++	.fm_radio = { .if_freq = 1250, .std_bits = 0x18 },
++	.atv_b    = { .if_freq = 6750, .std_bits = 0x0e },
++	.atv_dk   = { .if_freq = 7750, .std_bits = 0x0f },
++	.atv_gh   = { .if_freq = 7750, .std_bits = 0x0f },
++	.atv_i    = { .if_freq = 7750, .std_bits = 0x0f },
++	.atv_l    = { .if_freq = 7750, .std_bits = 0x0f },
++	.atv_lc   = { .if_freq = 1250, .std_bits = 0x0f },
++	.atv_mn   = { .if_freq = 5750, .std_bits = 0x0d },
++	.atsc_6   = { .if_freq = 3250, .std_bits = 0x1c },
++	.dvbt_6   = { .if_freq = 3300, .std_bits = 0x1c },
++	.dvbt_7   = { .if_freq = 3800, .std_bits = 0x1d },
++	.dvbt_8   = { .if_freq = 4300, .std_bits = 0x1e },
++	.qam_6    = { .if_freq = 4000, .std_bits = 0x1d },
++	.qam_8    = { .if_freq = 5000, .std_bits = 0x1f },
++};
 +
-+	regs[R_EP2]  &= ~0xe0; /* clear rf band bits */
-+	regs[R_EP2]  |= (0xe0 & (val << 5));
-+fail:
-+	return ret;
-+}
++static struct tda18271_std_map tda18271c2_std_map = {
++	.fm_radio = { .if_freq = 1250, .std_bits = 0x18 },
++	.atv_b    = { .if_freq = 6000, .std_bits = 0x0d },
++	.atv_dk   = { .if_freq = 6900, .std_bits = 0x0e },
++	.atv_gh   = { .if_freq = 7100, .std_bits = 0x0e },
++	.atv_i    = { .if_freq = 7250, .std_bits = 0x0e },
++	.atv_l    = { .if_freq = 6900, .std_bits = 0x0e },
++	.atv_lc   = { .if_freq = 1250, .std_bits = 0x0e },
++	.atv_mn   = { .if_freq = 5400, .std_bits = 0x0c },
++	.atsc_6   = { .if_freq = 3250, .std_bits = 0x1c },
++	.dvbt_6   = { .if_freq = 3300, .std_bits = 0x1c },
++	.dvbt_7   = { .if_freq = 3500, .std_bits = 0x1c },
++	.dvbt_8   = { .if_freq = 4000, .std_bits = 0x1d },
++	.qam_6    = { .if_freq = 4000, .std_bits = 0x1d },
++	.qam_8    = { .if_freq = 5000, .std_bits = 0x1f },
++};
 +
-+int tda18271_calc_gain_taper(struct dvb_frontend *fe, u32 *freq)
-+{
-+	/* sets gain taper bits, but does not write them */
-+	struct tda18271_priv *priv = fe->tuner_priv;
-+	unsigned char *regs = priv->tda18271_regs;
-+	u8 val;
++/*---------------------------------------------------------------------*/
 +
-+	int ret = tda18271_lookup_map(fe, GAIN_TAPER, freq, &val);
-+	if (ret < 0)
-+		goto fail;
++static struct tda18271_map_layout tda18271c1_map_layout = {
++	.main_pll          = tda18271c1_main_pll,
++	.cal_pll           = tda18271c1_cal_pll,
 +
-+	regs[R_EP2]  &= ~0x1f; /* clear gain taper bits */
-+	regs[R_EP2]  |= (0x1f & val);
-+fail:
-+	return ret;
-+}
++	.rf_cal            = tda18271c1_rf_cal,
++	.rf_cal_kmco       = tda18271c1_km,
 +
-+int tda18271_calc_ir_measure(struct dvb_frontend *fe, u32 *freq)
-+{
-+	/* sets IR Meas bits, but does not write them */
-+	struct tda18271_priv *priv = fe->tuner_priv;
-+	unsigned char *regs = priv->tda18271_regs;
-+	u8 val;
++	.bp_filter         = tda18271_bp_filter,
++	.rf_band           = tda18271_rf_band,
++	.gain_taper        = tda18271_gain_taper,
++	.ir_measure        = tda18271_ir_measure,
++};
 +
-+	int ret = tda18271_lookup_map(fe, IR_MEASURE, freq, &val);
-+	if (ret < 0)
-+		goto fail;
++static struct tda18271_map_layout tda18271c2_map_layout = {
++	.main_pll          = tda18271c2_main_pll,
++	.cal_pll           = tda18271c2_cal_pll,
 +
-+	regs[R_EP5] &= ~0x07;
-+	regs[R_EP5] |= (0x07 & val);
-+fail:
-+	return ret;
-+}
++	.rf_cal            = tda18271c2_rf_cal,
++	.rf_cal_kmco       = tda18271c2_km,
 +
-+int tda18271_calc_rf_cal(struct dvb_frontend *fe, u32 *freq)
++	.rf_cal_dc_over_dt = tda18271_rf_cal_dc_over_dt,
++
++	.bp_filter         = tda18271_bp_filter,
++	.rf_band           = tda18271_rf_band,
++	.gain_taper        = tda18271_gain_taper,
++	.ir_measure        = tda18271_ir_measure,
++};
++
++int tda18271_assign_map_layout(struct dvb_frontend *fe)
 +{
-+	/* sets rf cal byte (RFC_Cprog), but does not write it */
 +	struct tda18271_priv *priv = fe->tuner_priv;
-+	unsigned char *regs = priv->tda18271_regs;
-+	u8 val;
-+
-+	tda18271_lookup_map(fe, RF_CAL, freq, &val);
++	int ret = 0;
 +
-+	regs[R_EB14] = val;
++	switch (priv->id) {
++	case TDA18271HDC1:
++		priv->maps = &tda18271c1_map_layout;
++		memcpy(&priv->std, &tda18271c1_std_map,
++		       sizeof(struct tda18271_std_map));
++		break;
++	case TDA18271HDC2:
++		priv->maps = &tda18271c2_map_layout;
++		memcpy(&priv->std, &tda18271c2_std_map,
++		       sizeof(struct tda18271_std_map));
++		break;
++	default:
++		ret = -EINVAL;
++		break;
++	}
++	memcpy(priv->rf_cal_state, &tda18271_rf_band_template,
++	       sizeof(tda18271_rf_band_template));
 +
-+	return 0;
++	return ret;
 +}
 +
 +/*
@@ -92611,14 +190199,14 @@
 + * c-basic-offset: 8
 + * End:
 + */
-diff --git a/drivers/media/dvb/frontends/tda18271-fe.c b/drivers/media/dvb/frontends/tda18271-fe.c
+diff --git a/drivers/media/dvb/frontends/tda18271.h b/drivers/media/dvb/frontends/tda18271.h
 new file mode 100644
-index 0000000..dfe72aa
+index 0000000..24b0e35
 --- /dev/null
-+++ b/drivers/media/dvb/frontends/tda18271-fe.c
-@@ -0,0 +1,1225 @@
++++ b/drivers/media/dvb/frontends/tda18271.h
+@@ -0,0 +1,78 @@
 +/*
-+    tda18271-fe.c - driver for the Philips / NXP TDA18271 silicon tuner
++    tda18271.h - header for the Philips / NXP TDA18271 silicon tuner
 +
 +    Copyright (C) 2007, 2008 Michael Krufky <mkrufky at linuxtv.org>
 +
@@ -92637,13627 +190225,15211 @@
 +    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 +*/
 +
-+#include <linux/delay.h>
-+#include <linux/videodev2.h>
-+#include "tda18271-priv.h"
-+
-+int tda18271_debug;
-+module_param_named(debug, tda18271_debug, int, 0644);
-+MODULE_PARM_DESC(debug, "set debug level "
-+		 "(info=1, map=2, reg=4, adv=8, cal=16 (or-able))");
-+
-+static int tda18271_cal_on_startup;
-+module_param_named(cal, tda18271_cal_on_startup, int, 0644);
-+MODULE_PARM_DESC(cal, "perform RF tracking filter calibration on startup");
-+
-+static LIST_HEAD(tda18271_list);
-+static DEFINE_MUTEX(tda18271_list_mutex);
++#ifndef __TDA18271_H__
++#define __TDA18271_H__
 +
-+/*---------------------------------------------------------------------*/
++#include <linux/i2c.h>
++#include "dvb_frontend.h"
 +
-+static int tda18271_ir_cal_init(struct dvb_frontend *fe)
-+{
-+	struct tda18271_priv *priv = fe->tuner_priv;
-+	unsigned char *regs = priv->tda18271_regs;
++struct tda18271_std_map_item {
++	u16 if_freq;
++	u8 std_bits;
++};
 +
-+	tda18271_read_regs(fe);
++struct tda18271_std_map {
++	struct tda18271_std_map_item fm_radio;
++	struct tda18271_std_map_item atv_b;
++	struct tda18271_std_map_item atv_dk;
++	struct tda18271_std_map_item atv_gh;
++	struct tda18271_std_map_item atv_i;
++	struct tda18271_std_map_item atv_l;
++	struct tda18271_std_map_item atv_lc;
++	struct tda18271_std_map_item atv_mn;
++	struct tda18271_std_map_item atsc_6;
++	struct tda18271_std_map_item dvbt_6;
++	struct tda18271_std_map_item dvbt_7;
++	struct tda18271_std_map_item dvbt_8;
++	struct tda18271_std_map_item qam_6;
++	struct tda18271_std_map_item qam_8;
++};
 +
-+	/* test IR_CAL_OK to see if we need init */
-+	if ((regs[R_EP1] & 0x08) == 0)
-+		tda18271_init_regs(fe);
++enum tda18271_i2c_gate {
++	TDA18271_GATE_AUTO = 0,
++	TDA18271_GATE_ANALOG,
++	TDA18271_GATE_DIGITAL,
++};
 +
-+	return 0;
-+}
++struct tda18271_config {
++	/* override default if freq / std settings (optional) */
++	struct tda18271_std_map *std_map;
 +
-+/* ------------------------------------------------------------------ */
++	/* use i2c gate provided by analog or digital demod */
++	enum tda18271_i2c_gate gate;
++};
 +
-+static int tda18271_channel_configuration(struct dvb_frontend *fe,
-+					  u32 ifc, u32 freq, u32 bw, u8 std,
-+					  int radio)
++#if defined(CONFIG_DVB_TDA18271) || (defined(CONFIG_DVB_TDA18271_MODULE) && defined(MODULE))
++extern struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr,
++					    struct i2c_adapter *i2c,
++					    struct tda18271_config *cfg);
++#else
++static inline struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe,
++						   u8 addr,
++						   struct i2c_adapter *i2c,
++						   struct tda18271_config *cfg)
 +{
-+	struct tda18271_priv *priv = fe->tuner_priv;
-+	unsigned char *regs = priv->tda18271_regs;
-+	u32 N;
-+
-+	/* update TV broadcast parameters */
-+
-+	/* set standard */
-+	regs[R_EP3]  &= ~0x1f; /* clear std bits */
-+	regs[R_EP3]  |= std;
++	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
++	return NULL;
++}
++#endif
 +
-+	/* set cal mode to normal */
-+	regs[R_EP4]  &= ~0x03;
++#endif /* __TDA18271_H__ */
+diff --git a/drivers/media/dvb/frontends/tda827x.c b/drivers/media/dvb/frontends/tda827x.c
+index 256fc4b..229b119 100644
+--- a/drivers/media/dvb/frontends/tda827x.c
++++ b/drivers/media/dvb/frontends/tda827x.c
+@@ -19,12 +19,16 @@
+  */
+ 
+ #include <linux/module.h>
+-#include <linux/dvb/frontend.h>
+ #include <asm/types.h>
++#include <linux/dvb/frontend.h>
++#include <linux/videodev2.h>
+ 
+ #include "tda827x.h"
+ 
+ static int debug = 0;
++module_param(debug, int, 0644);
++MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
 +
-+	/* update IF output level & IF notch frequency */
-+	regs[R_EP4]  &= ~0x1c; /* clear if level bits */
+ #define dprintk(args...) \
+ 	do {					    \
+ 		if (debug) printk(KERN_DEBUG "tda827x: " args); \
+@@ -34,10 +38,57 @@ struct tda827x_priv {
+ 	int i2c_addr;
+ 	struct i2c_adapter *i2c_adap;
+ 	struct tda827x_config *cfg;
 +
-+	switch (priv->mode) {
-+	case TDA18271_ANALOG:
-+		regs[R_MPD]  &= ~0x80; /* IF notch = 0 */
-+		break;
-+	case TDA18271_DIGITAL:
-+		regs[R_EP4]  |= 0x04; /* IF level = 1 */
-+		regs[R_MPD]  |= 0x80; /* IF notch = 1 */
-+		break;
-+	}
++	unsigned int sgIF;
++	unsigned char lpsel;
 +
-+	if (radio)
-+		regs[R_EP4]  |=  0x80;
-+	else
-+		regs[R_EP4]  &= ~0x80;
+ 	u32 frequency;
+ 	u32 bandwidth;
+ };
+ 
++static void tda827x_set_std(struct dvb_frontend *fe,
++			    struct analog_parameters *params)
++{
++	struct tda827x_priv *priv = fe->tuner_priv;
++	char *mode;
 +
-+	/* update RF_TOP / IF_TOP */
-+	switch (priv->mode) {
-+	case TDA18271_ANALOG:
-+		regs[R_EB22]  = 0x2c;
-+		break;
-+	case TDA18271_DIGITAL:
-+		regs[R_EB22]  = 0x37;
-+		break;
++	priv->lpsel = 0;
++	if (params->std & V4L2_STD_MN) {
++		priv->sgIF = 92;
++		priv->lpsel = 1;
++		mode = "MN";
++	} else if (params->std & V4L2_STD_B) {
++		priv->sgIF = 108;
++		mode = "B";
++	} else if (params->std & V4L2_STD_GH) {
++		priv->sgIF = 124;
++		mode = "GH";
++	} else if (params->std & V4L2_STD_PAL_I) {
++		priv->sgIF = 124;
++		mode = "I";
++	} else if (params->std & V4L2_STD_DK) {
++		priv->sgIF = 124;
++		mode = "DK";
++	} else if (params->std & V4L2_STD_SECAM_L) {
++		priv->sgIF = 124;
++		mode = "L";
++	} else if (params->std & V4L2_STD_SECAM_LC) {
++		priv->sgIF = 20;
++		mode = "LC";
++	} else {
++		priv->sgIF = 124;
++		mode = "xx";
 +	}
-+	tda18271_write_regs(fe, R_EB22, 1);
 +
-+	/* --------------------------------------------------------------- */
++	if (params->mode == V4L2_TUNER_RADIO)
++		priv->sgIF = 88; /* if frequency is 5.5 MHz */
 +
-+	/* disable Power Level Indicator */
-+	regs[R_EP1]  |= 0x40;
++	dprintk("setting tda827x to system %s\n", mode);
++}
 +
-+	/* frequency dependent parameters */
 +
-+	tda18271_calc_ir_measure(fe, &freq);
++/* ------------------------------------------------------------------ */
 +
-+	tda18271_calc_bp_filter(fe, &freq);
+ struct tda827x_data {
+ 	u32 lomax;
+ 	u8  spd;
+@@ -48,7 +99,7 @@ struct tda827x_data {
+ 	u8 div1p5;
+ };
+ 
+-static const struct tda827x_data tda827x_dvbt[] = {
++static const struct tda827x_data tda827x_table[] = {
+ 	{ .lomax =  62000000, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 1},
+ 	{ .lomax =  66000000, .spd = 3, .bs = 3, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 1},
+ 	{ .lomax =  76000000, .spd = 3, .bs = 1, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 0},
+@@ -106,21 +157,22 @@ static int tda827xo_set_params(struct dvb_frontend *fe,
+ 	tuner_freq = params->frequency + if_freq;
+ 
+ 	i = 0;
+-	while (tda827x_dvbt[i].lomax < tuner_freq) {
+-		if(tda827x_dvbt[i + 1].lomax == 0)
++	while (tda827x_table[i].lomax < tuner_freq) {
++		if (tda827x_table[i + 1].lomax == 0)
+ 			break;
+ 		i++;
+ 	}
+ 
+-	N = ((tuner_freq + 125000) / 250000) << (tda827x_dvbt[i].spd + 2);
++	N = ((tuner_freq + 125000) / 250000) << (tda827x_table[i].spd + 2);
+ 	buf[0] = 0;
+ 	buf[1] = (N>>8) | 0x40;
+ 	buf[2] = N & 0xff;
+ 	buf[3] = 0;
+ 	buf[4] = 0x52;
+-	buf[5] = (tda827x_dvbt[i].spd << 6) + (tda827x_dvbt[i].div1p5 << 5) +
+-				(tda827x_dvbt[i].bs << 3) + tda827x_dvbt[i].bp;
+-	buf[6] = (tda827x_dvbt[i].gc3 << 4) + 0x8f;
++	buf[5] = (tda827x_table[i].spd << 6) + (tda827x_table[i].div1p5 << 5) +
++				(tda827x_table[i].bs << 3) +
++				tda827x_table[i].bp;
++	buf[6] = (tda827x_table[i].gc3 << 4) + 0x8f;
+ 	buf[7] = 0xbf;
+ 	buf[8] = 0x2a;
+ 	buf[9] = 0x05;
+@@ -140,7 +192,7 @@ static int tda827xo_set_params(struct dvb_frontend *fe,
+ 	msleep(500);
+ 	/* correct CP value */
+ 	buf[0] = 0x30;
+-	buf[1] = 0x50 + tda827x_dvbt[i].cp;
++	buf[1] = 0x50 + tda827x_table[i].cp;
+ 	msg.len = 2;
+ 
+ 	if (fe->ops.i2c_gate_ctrl)
+@@ -173,6 +225,102 @@ static int tda827xo_sleep(struct dvb_frontend *fe)
+ 
+ /* ------------------------------------------------------------------ */
+ 
++static int tda827xo_set_analog_params(struct dvb_frontend *fe,
++				      struct analog_parameters *params)
++{
++	unsigned char tuner_reg[8];
++	unsigned char reg2[2];
++	u32 N;
++	int i;
++	struct tda827x_priv *priv = fe->tuner_priv;
++	struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0 };
++	unsigned int freq = params->frequency;
 +
-+	tda18271_calc_rf_band(fe, &freq);
++	tda827x_set_std(fe, params);
 +
-+	tda18271_calc_gain_taper(fe, &freq);
++	if (params->mode == V4L2_TUNER_RADIO)
++		freq = freq / 1000;
 +
-+	/* --------------------------------------------------------------- */
++	N = freq + priv->sgIF;
 +
-+	/* dual tuner and agc1 extra configuration */
++	i = 0;
++	while (tda827x_table[i].lomax < N * 62500) {
++		if (tda827x_table[i + 1].lomax == 0)
++			break;
++		i++;
++	}
 +
-+	/* main vco when Master, cal vco when slave */
-+	regs[R_EB1]  |= 0x04; /* FIXME: assumes master */
++	N = N << tda827x_table[i].spd;
 +
-+	/* agc1 always active */
-+	regs[R_EB1]  &= ~0x02;
++	tuner_reg[0] = 0;
++	tuner_reg[1] = (unsigned char)(N>>8);
++	tuner_reg[2] = (unsigned char) N;
++	tuner_reg[3] = 0x40;
++	tuner_reg[4] = 0x52 + (priv->lpsel << 5);
++	tuner_reg[5] = (tda827x_table[i].spd    << 6) +
++		       (tda827x_table[i].div1p5 << 5) +
++		       (tda827x_table[i].bs     << 3) + tda827x_table[i].bp;
++	tuner_reg[6] = 0x8f + (tda827x_table[i].gc3 << 4);
++	tuner_reg[7] = 0x8f;
 +
-+	/* agc1 has priority on agc2 */
-+	regs[R_EB1]  &= ~0x01;
++	msg.buf = tuner_reg;
++	msg.len = 8;
++	i2c_transfer(priv->i2c_adap, &msg, 1);
 +
-+	tda18271_write_regs(fe, R_EB1, 1);
++	msg.buf = reg2;
++	msg.len = 2;
++	reg2[0] = 0x80;
++	reg2[1] = 0;
++	i2c_transfer(priv->i2c_adap, &msg, 1);
 +
-+	/* --------------------------------------------------------------- */
++	reg2[0] = 0x60;
++	reg2[1] = 0xbf;
++	i2c_transfer(priv->i2c_adap, &msg, 1);
 +
-+	N = freq + ifc;
++	reg2[0] = 0x30;
++	reg2[1] = tuner_reg[4] + 0x80;
++	i2c_transfer(priv->i2c_adap, &msg, 1);
 +
-+	/* FIXME: assumes master */
-+	tda18271_calc_main_pll(fe, N);
-+	tda18271_write_regs(fe, R_MPD, 4);
++	msleep(1);
++	reg2[0] = 0x30;
++	reg2[1] = tuner_reg[4] + 4;
++	i2c_transfer(priv->i2c_adap, &msg, 1);
 +
-+	tda18271_write_regs(fe, R_TM, 7);
++	msleep(1);
++	reg2[0] = 0x30;
++	reg2[1] = tuner_reg[4];
++	i2c_transfer(priv->i2c_adap, &msg, 1);
 +
-+	/* main pll charge pump source */
-+	regs[R_EB4] |= 0x20;
-+	tda18271_write_regs(fe, R_EB4, 1);
++	msleep(550);
++	reg2[0] = 0x30;
++	reg2[1] = (tuner_reg[4] & 0xfc) + tda827x_table[i].cp;
++	i2c_transfer(priv->i2c_adap, &msg, 1);
 +
-+	msleep(1);
++	reg2[0] = 0x60;
++	reg2[1] = 0x3f;
++	i2c_transfer(priv->i2c_adap, &msg, 1);
 +
-+	/* normal operation for the main pll */
-+	regs[R_EB4] &= ~0x20;
-+	tda18271_write_regs(fe, R_EB4, 1);
++	reg2[0] = 0x80;
++	reg2[1] = 0x08;   /* Vsync en */
++	i2c_transfer(priv->i2c_adap, &msg, 1);
 +
-+	msleep(5);
++	priv->frequency = freq * 62500;
 +
 +	return 0;
 +}
 +
-+static int tda18271_read_thermometer(struct dvb_frontend *fe)
++static void tda827xo_agcf(struct dvb_frontend *fe)
 +{
-+	struct tda18271_priv *priv = fe->tuner_priv;
-+	unsigned char *regs = priv->tda18271_regs;
-+	int tm;
-+
-+	/* switch thermometer on */
-+	regs[R_TM]   |= 0x10;
-+	tda18271_write_regs(fe, R_TM, 1);
-+
-+	/* read thermometer info */
-+	tda18271_read_regs(fe);
-+
-+	if ((((regs[R_TM] & 0x0f) == 0x00) && ((regs[R_TM] & 0x20) == 0x20)) ||
-+	    (((regs[R_TM] & 0x0f) == 0x08) && ((regs[R_TM] & 0x20) == 0x00))) {
-+
-+		if ((regs[R_TM] & 0x20) == 0x20)
-+			regs[R_TM] &= ~0x20;
-+		else
-+			regs[R_TM] |= 0x20;
-+
-+		tda18271_write_regs(fe, R_TM, 1);
-+
-+		msleep(10); /* temperature sensing */
-+
-+		/* read thermometer info */
-+		tda18271_read_regs(fe);
-+	}
-+
-+	tm = tda18271_lookup_thermometer(fe);
-+
-+	/* switch thermometer off */
-+	regs[R_TM]   &= ~0x10;
-+	tda18271_write_regs(fe, R_TM, 1);
-+
-+	/* set CAL mode to normal */
-+	regs[R_EP4]  &= ~0x03;
-+	tda18271_write_regs(fe, R_EP4, 1);
++	struct tda827x_priv *priv = fe->tuner_priv;
++	unsigned char data[] = { 0x80, 0x0c };
++	struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0,
++			       .buf = data, .len = 2};
 +
-+	return tm;
++	i2c_transfer(priv->i2c_adap, &msg, 1);
 +}
 +
-+static int tda18271_rf_tracking_filters_correction(struct dvb_frontend *fe,
-+						   u32 freq)
-+{
-+	struct tda18271_priv *priv = fe->tuner_priv;
-+	struct tda18271_rf_tracking_filter_cal *map = priv->rf_cal_state;
-+	unsigned char *regs = priv->tda18271_regs;
-+	int tm_current, rfcal_comp, approx, i;
-+	u8 dc_over_dt, rf_tab;
-+
-+	/* power up */
-+	tda18271_set_standby_mode(fe, 0, 0, 0);
-+
-+	/* read die current temperature */
-+	tm_current = tda18271_read_thermometer(fe);
-+
-+	/* frequency dependent parameters */
-+
-+	tda18271_calc_rf_cal(fe, &freq);
-+	rf_tab = regs[R_EB14];
-+
-+	i = tda18271_lookup_rf_band(fe, &freq, NULL);
-+	if (i < 0)
-+		return -EINVAL;
-+
-+	if ((0 == map[i].rf3) || (freq / 1000 < map[i].rf2)) {
-+		approx = map[i].rf_a1 *
-+			(freq / 1000 - map[i].rf1) + map[i].rf_b1 + rf_tab;
-+	} else {
-+		approx = map[i].rf_a2 *
-+			(freq / 1000 - map[i].rf2) + map[i].rf_b2 + rf_tab;
-+	}
-+
-+	if (approx < 0)
-+		approx = 0;
-+	if (approx > 255)
-+		approx = 255;
-+
-+	tda18271_lookup_map(fe, RF_CAL_DC_OVER_DT, &freq, &dc_over_dt);
-+
-+	/* calculate temperature compensation */
-+	rfcal_comp = dc_over_dt * (tm_current - priv->tm_rfcal);
++/* ------------------------------------------------------------------ */
 +
-+	regs[R_EB14] = approx + rfcal_comp;
-+	tda18271_write_regs(fe, R_EB14, 1);
+ struct tda827xa_data {
+ 	u32 lomax;
+ 	u8  svco;
+@@ -212,6 +360,35 @@ static const struct tda827xa_data tda827xa_dvbt[] = {
+ 	{ .lomax =         0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0}
+ };
+ 
++static struct tda827xa_data tda827xa_analog[] = {
++	{ .lomax =  56875000, .svco = 3, .spd = 4, .scr = 0, .sbs = 0, .gc3 = 3},
++	{ .lomax =  67250000, .svco = 0, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3},
++	{ .lomax =  81250000, .svco = 1, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3},
++	{ .lomax =  97500000, .svco = 2, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3},
++	{ .lomax = 113750000, .svco = 3, .spd = 3, .scr = 0, .sbs = 1, .gc3 = 1},
++	{ .lomax = 134500000, .svco = 0, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},
++	{ .lomax = 154000000, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},
++	{ .lomax = 162500000, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},
++	{ .lomax = 183000000, .svco = 2, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},
++	{ .lomax = 195000000, .svco = 2, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 1},
++	{ .lomax = 227500000, .svco = 3, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 3},
++	{ .lomax = 269000000, .svco = 0, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 3},
++	{ .lomax = 325000000, .svco = 1, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 1},
++	{ .lomax = 390000000, .svco = 2, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 3},
++	{ .lomax = 455000000, .svco = 3, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 3},
++	{ .lomax = 520000000, .svco = 0, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1},
++	{ .lomax = 538000000, .svco = 0, .spd = 0, .scr = 1, .sbs = 3, .gc3 = 1},
++	{ .lomax = 554000000, .svco = 1, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1},
++	{ .lomax = 620000000, .svco = 1, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0},
++	{ .lomax = 650000000, .svco = 1, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0},
++	{ .lomax = 700000000, .svco = 2, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0},
++	{ .lomax = 780000000, .svco = 2, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0},
++	{ .lomax = 820000000, .svco = 3, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0},
++	{ .lomax = 870000000, .svco = 3, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0},
++	{ .lomax = 911000000, .svco = 3, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 0},
++	{ .lomax =         0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0}
++};
 +
-+	return 0;
-+}
+ static int tda827xa_set_params(struct dvb_frontend *fe,
+ 			       struct dvb_frontend_parameters *params)
+ {
+@@ -368,6 +545,163 @@ static int tda827xa_sleep(struct dvb_frontend *fe)
+ 	return 0;
+ }
+ 
++/* ------------------------------------------------------------------ */
 +
-+static int tda18271_por(struct dvb_frontend *fe)
++static void tda827xa_lna_gain(struct dvb_frontend *fe, int high,
++			      struct analog_parameters *params)
 +{
-+	struct tda18271_priv *priv = fe->tuner_priv;
-+	unsigned char *regs = priv->tda18271_regs;
-+
-+	/* power up detector 1 */
-+	regs[R_EB12] &= ~0x20;
-+	tda18271_write_regs(fe, R_EB12, 1);
-+
-+	regs[R_EB18] &= ~0x80; /* turn agc1 loop on */
-+	regs[R_EB18] &= ~0x03; /* set agc1_gain to  6 dB */
-+	tda18271_write_regs(fe, R_EB18, 1);
-+
-+	regs[R_EB21] |= 0x03; /* set agc2_gain to -6 dB */
-+
-+	/* POR mode */
-+	tda18271_set_standby_mode(fe, 1, 0, 0);
++	struct tda827x_priv *priv = fe->tuner_priv;
++	unsigned char buf[] = {0x22, 0x01};
++	int arg;
++	struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0,
++			       .buf = buf, .len = sizeof(buf) };
 +
-+	/* disable 1.5 MHz low pass filter */
-+	regs[R_EB23] &= ~0x04; /* forcelp_fc2_en = 0 */
-+	regs[R_EB23] &= ~0x02; /* XXX: lp_fc[2] = 0 */
-+	tda18271_write_regs(fe, R_EB21, 3);
++	if (NULL == priv->cfg) {
++		dprintk("tda827x_config not defined, cannot set LNA gain!\n");
++		return;
++	}
 +
-+	return 0;
++	if (priv->cfg->config) {
++		if (high)
++			dprintk("setting LNA to high gain\n");
++		else
++			dprintk("setting LNA to low gain\n");
++	}
++	switch (*priv->cfg->config) {
++	case 0: /* no LNA */
++		break;
++	case 1: /* switch is GPIO 0 of tda8290 */
++	case 2:
++		/* turn Vsync on */
++		if (params->std & V4L2_STD_MN)
++			arg = 1;
++		else
++			arg = 0;
++		if (priv->cfg->tuner_callback)
++			priv->cfg->tuner_callback(priv->i2c_adap->algo_data,
++						  1, 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);
++		break;
++	}
 +}
 +
-+static int tda18271_calibrate_rf(struct dvb_frontend *fe, u32 freq)
++static int tda827xa_set_analog_params(struct dvb_frontend *fe,
++				      struct analog_parameters *params)
 +{
-+	struct tda18271_priv *priv = fe->tuner_priv;
-+	unsigned char *regs = priv->tda18271_regs;
++	unsigned char tuner_reg[11];
 +	u32 N;
++	int i;
++	struct tda827x_priv *priv = fe->tuner_priv;
++	struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0,
++			       .buf = tuner_reg, .len = sizeof(tuner_reg) };
++	unsigned int freq = params->frequency;
 +
-+	/* set CAL mode to normal */
-+	regs[R_EP4]  &= ~0x03;
-+	tda18271_write_regs(fe, R_EP4, 1);
-+
-+	/* switch off agc1 */
-+	regs[R_EP3]  |= 0x40; /* sm_lt = 1 */
-+
-+	regs[R_EB18] |= 0x03; /* set agc1_gain to 15 dB */
-+	tda18271_write_regs(fe, R_EB18, 1);
-+
-+	/* frequency dependent parameters */
-+
-+	tda18271_calc_bp_filter(fe, &freq);
-+	tda18271_calc_gain_taper(fe, &freq);
-+	tda18271_calc_rf_band(fe, &freq);
-+	tda18271_calc_km(fe, &freq);
-+
-+	tda18271_write_regs(fe, R_EP1, 3);
-+	tda18271_write_regs(fe, R_EB13, 1);
-+
-+	/* main pll charge pump source */
-+	regs[R_EB4]  |= 0x20;
-+	tda18271_write_regs(fe, R_EB4, 1);
-+
-+	/* cal pll charge pump source */
-+	regs[R_EB7]  |= 0x20;
-+	tda18271_write_regs(fe, R_EB7, 1);
-+
-+	/* force dcdc converter to 0 V */
-+	regs[R_EB14] = 0x00;
-+	tda18271_write_regs(fe, R_EB14, 1);
-+
-+	/* disable plls lock */
-+	regs[R_EB20] &= ~0x20;
-+	tda18271_write_regs(fe, R_EB20, 1);
-+
-+	/* set CAL mode to RF tracking filter calibration */
-+	regs[R_EP4]  |= 0x03;
-+	tda18271_write_regs(fe, R_EP4, 2);
-+
-+	/* --------------------------------------------------------------- */
-+
-+	/* set the internal calibration signal */
-+	N = freq;
-+
-+	tda18271_calc_main_pll(fe, N);
-+	tda18271_write_regs(fe, R_MPD, 4);
-+
-+	/* downconvert internal calibration */
-+	N += 1000000;
++	tda827x_set_std(fe, params);
 +
-+	tda18271_calc_main_pll(fe, N);
-+	tda18271_write_regs(fe, R_MPD, 4);
++	tda827xa_lna_gain(fe, 1, params);
++	msleep(10);
 +
-+	msleep(5);
++	if (params->mode == V4L2_TUNER_RADIO)
++		freq = freq / 1000;
 +
-+	tda18271_write_regs(fe, R_EP2, 1);
-+	tda18271_write_regs(fe, R_EP1, 1);
-+	tda18271_write_regs(fe, R_EP2, 1);
-+	tda18271_write_regs(fe, R_EP1, 1);
++	N = freq + priv->sgIF;
 +
-+	/* --------------------------------------------------------------- */
++	i = 0;
++	while (tda827xa_analog[i].lomax < N * 62500) {
++		if (tda827xa_analog[i + 1].lomax == 0)
++			break;
++		i++;
++	}
 +
-+	/* normal operation for the main pll */
-+	regs[R_EB4] &= ~0x20;
-+	tda18271_write_regs(fe, R_EB4, 1);
++	N = N << tda827xa_analog[i].spd;
 +
-+	/* normal operation for the cal pll  */
-+	regs[R_EB7] &= ~0x20;
-+	tda18271_write_regs(fe, R_EB7, 1);
++	tuner_reg[0] = 0;
++	tuner_reg[1] = (unsigned char)(N>>8);
++	tuner_reg[2] = (unsigned char) N;
++	tuner_reg[3] = 0;
++	tuner_reg[4] = 0x16;
++	tuner_reg[5] = (tda827xa_analog[i].spd << 5) +
++		       (tda827xa_analog[i].svco << 3) +
++			tda827xa_analog[i].sbs;
++	tuner_reg[6] = 0x8b + (tda827xa_analog[i].gc3 << 4);
++	tuner_reg[7] = 0x1c;
++	tuner_reg[8] = 4;
++	tuner_reg[9] = 0x20;
++	tuner_reg[10] = 0x00;
++	msg.len = 11;
++	i2c_transfer(priv->i2c_adap, &msg, 1);
 +
-+	msleep(5); /* plls locking */
++	tuner_reg[0] = 0x90;
++	tuner_reg[1] = 0xff;
++	tuner_reg[2] = 0xe0;
++	tuner_reg[3] = 0;
++	tuner_reg[4] = 0x99 + (priv->lpsel << 1);
++	msg.len = 5;
++	i2c_transfer(priv->i2c_adap, &msg, 1);
 +
-+	/* launch the rf tracking filters calibration */
-+	regs[R_EB20]  |= 0x20;
-+	tda18271_write_regs(fe, R_EB20, 1);
++	tuner_reg[0] = 0xa0;
++	tuner_reg[1] = 0xc0;
++	msg.len = 2;
++	i2c_transfer(priv->i2c_adap, &msg, 1);
 +
-+	msleep(60); /* calibration */
++	tuner_reg[0] = 0x30;
++	tuner_reg[1] = 0x10 + tda827xa_analog[i].scr;
++	i2c_transfer(priv->i2c_adap, &msg, 1);
 +
-+	/* --------------------------------------------------------------- */
++	msg.flags = I2C_M_RD;
++	i2c_transfer(priv->i2c_adap, &msg, 1);
++	msg.flags = 0;
++	tuner_reg[1] >>= 4;
++	dprintk("AGC2 gain is: %d\n", tuner_reg[1]);
++	if (tuner_reg[1] < 1)
++		tda827xa_lna_gain(fe, 0, params);
 +
-+	/* set CAL mode to normal */
-+	regs[R_EP4]  &= ~0x03;
++	msleep(100);
++	tuner_reg[0] = 0x60;
++	tuner_reg[1] = 0x3c;
++	i2c_transfer(priv->i2c_adap, &msg, 1);
 +
-+	/* switch on agc1 */
-+	regs[R_EP3]  &= ~0x40; /* sm_lt = 0 */
++	msleep(163);
++	tuner_reg[0] = 0x50;
++	tuner_reg[1] = 0x8f + (tda827xa_analog[i].gc3 << 4);
++	i2c_transfer(priv->i2c_adap, &msg, 1);
 +
-+	regs[R_EB18] &= ~0x03; /* set agc1_gain to  6 dB */
-+	tda18271_write_regs(fe, R_EB18, 1);
++	tuner_reg[0] = 0x80;
++	tuner_reg[1] = 0x28;
++	i2c_transfer(priv->i2c_adap, &msg, 1);
 +
-+	tda18271_write_regs(fe, R_EP3, 2);
++	tuner_reg[0] = 0xb0;
++	tuner_reg[1] = 0x01;
++	i2c_transfer(priv->i2c_adap, &msg, 1);
 +
-+	/* synchronization */
-+	tda18271_write_regs(fe, R_EP1, 1);
++	tuner_reg[0] = 0xc0;
++	tuner_reg[1] = 0x19 + (priv->lpsel << 1);
++	i2c_transfer(priv->i2c_adap, &msg, 1);
 +
-+	/* get calibration result */
-+	tda18271_read_extended(fe);
++	priv->frequency = freq * 62500;
 +
-+	return regs[R_EB14];
++	return 0;
 +}
 +
-+static int tda18271_powerscan(struct dvb_frontend *fe,
-+			      u32 *freq_in, u32 *freq_out)
++static void tda827xa_agcf(struct dvb_frontend *fe)
 +{
-+	struct tda18271_priv *priv = fe->tuner_priv;
-+	unsigned char *regs = priv->tda18271_regs;
-+	int sgn, bcal, count, wait;
-+	u8 cid_target;
-+	u16 count_limit;
-+	u32 freq;
-+
-+	freq = *freq_in;
-+
-+	tda18271_calc_rf_band(fe, &freq);
-+	tda18271_calc_rf_cal(fe, &freq);
-+	tda18271_calc_gain_taper(fe, &freq);
-+	tda18271_lookup_cid_target(fe, &freq, &cid_target, &count_limit);
-+
-+	tda18271_write_regs(fe, R_EP2, 1);
-+	tda18271_write_regs(fe, R_EB14, 1);
-+
-+	/* downconvert frequency */
-+	freq += 1000000;
++	struct tda827x_priv *priv = fe->tuner_priv;
++	unsigned char data[] = {0x80, 0x2c};
++	struct i2c_msg msg = {.addr = priv->i2c_addr, .flags = 0,
++			      .buf = data, .len = 2};
++	i2c_transfer(priv->i2c_adap, &msg, 1);
++}
 +
-+	tda18271_calc_main_pll(fe, freq);
-+	tda18271_write_regs(fe, R_MPD, 4);
++/* ------------------------------------------------------------------ */
 +
-+	msleep(5); /* pll locking */
+ static int tda827x_release(struct dvb_frontend *fe)
+ {
+ 	kfree(fe->tuner_priv);
+@@ -430,6 +764,7 @@ static struct dvb_tuner_ops tda827xo_tuner_ops = {
+ 	.init = tda827x_initial_init,
+ 	.sleep = tda827x_initial_sleep,
+ 	.set_params = tda827xo_set_params,
++	.set_analog_params = tda827xo_set_analog_params,
+ 	.get_frequency = tda827x_get_frequency,
+ 	.get_bandwidth = tda827x_get_bandwidth,
+ };
+@@ -445,6 +780,7 @@ static struct dvb_tuner_ops tda827xa_tuner_ops = {
+ 	.init = tda827x_init,
+ 	.sleep = tda827xa_sleep,
+ 	.set_params = tda827xa_set_params,
++	.set_analog_params = tda827xa_set_analog_params,
+ 	.get_frequency = tda827x_get_frequency,
+ 	.get_bandwidth = tda827x_get_bandwidth,
+ };
+@@ -465,9 +801,13 @@ static int tda827x_probe_version(struct dvb_frontend *fe)
+ 		dprintk("tda827x tuner found\n");
+ 		fe->ops.tuner_ops.init  = tda827x_init;
+ 		fe->ops.tuner_ops.sleep = tda827xo_sleep;
++		if (priv->cfg)
++			priv->cfg->agcf = tda827xo_agcf;
+ 	} else {
+ 		dprintk("tda827xa tuner found\n");
+ 		memcpy(&fe->ops.tuner_ops, &tda827xa_tuner_ops, sizeof(struct dvb_tuner_ops));
++		if (priv->cfg)
++			priv->cfg->agcf = tda827xa_agcf;
+ 	}
+ 	return 0;
+ }
+@@ -487,16 +827,13 @@ struct dvb_frontend *tda827x_attach(struct dvb_frontend *fe, int addr,
+ 	priv->i2c_adap = i2c;
+ 	priv->cfg = cfg;
+ 	memcpy(&fe->ops.tuner_ops, &tda827xo_tuner_ops, sizeof(struct dvb_tuner_ops));
+-
+ 	fe->tuner_priv = priv;
+ 
++	dprintk("type set to %s\n", fe->ops.tuner_ops.info.name);
 +
-+	/* detection mode */
-+	regs[R_EP4]  &= ~0x03;
-+	regs[R_EP4]  |= 0x01;
-+	tda18271_write_regs(fe, R_EP4, 1);
+ 	return fe;
+ }
+-
+-EXPORT_SYMBOL(tda827x_attach);
+-
+-module_param(debug, int, 0644);
+-MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
++EXPORT_SYMBOL_GPL(tda827x_attach);
+ 
+ MODULE_DESCRIPTION("DVB TDA827x driver");
+ MODULE_AUTHOR("Hartmut Hackmann <hartmut.hackmann at t-online.de>");
+diff --git a/drivers/media/dvb/frontends/tda827x.h b/drivers/media/dvb/frontends/tda827x.h
+index 69e8263..92eb65b 100644
+--- a/drivers/media/dvb/frontends/tda827x.h
++++ b/drivers/media/dvb/frontends/tda827x.h
+@@ -29,9 +29,16 @@
+ 
+ struct tda827x_config
+ {
++	/* saa7134 - provided callbacks */
+ 	void (*lna_gain) (struct dvb_frontend *fe, int high);
+ 	int (*init) (struct dvb_frontend *fe);
+ 	int (*sleep) (struct dvb_frontend *fe);
 +
-+	/* launch power detection measurement */
-+	tda18271_write_regs(fe, R_EP2, 1);
++	/* interface to tda829x driver */
++	unsigned int *config;
++	int (*tuner_callback) (void *dev, int command, int arg);
 +
-+	/* read power detection info, stored in EB10 */
-+	tda18271_read_extended(fe);
++	void (*agcf)(struct dvb_frontend *fe);
+ };
+ 
+ 
+diff --git a/drivers/media/dvb/frontends/ves1820.c b/drivers/media/dvb/frontends/ves1820.c
+index 60433b5..8791701 100644
+--- a/drivers/media/dvb/frontends/ves1820.c
++++ b/drivers/media/dvb/frontends/ves1820.c
+@@ -65,7 +65,7 @@ static int ves1820_writereg(struct ves1820_state *state, u8 reg, u8 data)
+ 	ret = i2c_transfer(state->i2c, &msg, 1);
+ 
+ 	if (ret != 1)
+-		printk("ves1820: %s(): writereg error (reg == 0x%02x,"
++		printk("ves1820: %s(): writereg error (reg == 0x%02x, "
+ 			"val == 0x%02x, ret == %i)\n", __FUNCTION__, reg, data, ret);
+ 
+ 	return (ret != 1) ? -EREMOTEIO : 0;
+@@ -84,7 +84,7 @@ static u8 ves1820_readreg(struct ves1820_state *state, u8 reg)
+ 	ret = i2c_transfer(state->i2c, msg, 2);
+ 
+ 	if (ret != 2)
+-		printk("ves1820: %s(): readreg error (reg == 0x%02x,"
++		printk("ves1820: %s(): readreg error (reg == 0x%02x, "
+ 		"ret == %i)\n", __FUNCTION__, reg, ret);
+ 
+ 	return b1[0];
+diff --git a/drivers/media/dvb/frontends/xc5000.c b/drivers/media/dvb/frontends/xc5000.c
+new file mode 100644
+index 0000000..f642ca2
+--- /dev/null
++++ b/drivers/media/dvb/frontends/xc5000.c
+@@ -0,0 +1,964 @@
++/*
++ *  Driver for Xceive XC5000 "QAM/8VSB single chip tuner"
++ *
++ *  Copyright (c) 2007 Xceive Corporation
++ *  Copyright (c) 2007 Steven Toth <stoth at hauppauge.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.
++ */
 +
-+	/* algorithm initialization */
-+	sgn = 1;
-+	*freq_out = *freq_in;
-+	bcal = 0;
-+	count = 0;
-+	wait = false;
++#include <linux/module.h>
++#include <linux/moduleparam.h>
++#include <linux/videodev2.h>
++#include <linux/delay.h>
++#include <linux/dvb/frontend.h>
++#include <linux/i2c.h>
 +
-+	while ((regs[R_EB10] & 0x3f) < cid_target) {
-+		/* downconvert updated freq to 1 MHz */
-+		freq = *freq_in + (sgn * count) + 1000000;
++#include "dvb_frontend.h"
 +
-+		tda18271_calc_main_pll(fe, freq);
-+		tda18271_write_regs(fe, R_MPD, 4);
++#include "xc5000.h"
++#include "xc5000_priv.h"
 +
-+		if (wait) {
-+			msleep(5); /* pll locking */
-+			wait = false;
-+		} else
-+			udelay(100); /* pll locking */
++static int debug;
++module_param(debug, int, 0644);
++MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
 +
-+		/* launch power detection measurement */
-+		tda18271_write_regs(fe, R_EP2, 1);
++#define dprintk(level,fmt, arg...) if (debug >= level) \
++	printk(KERN_INFO "%s: " fmt, "xc5000", ## arg)
 +
-+		/* read power detection info, stored in EB10 */
-+		tda18271_read_extended(fe);
++#define XC5000_DEFAULT_FIRMWARE "dvb-fe-xc5000-1.1.fw"
++#define XC5000_DEFAULT_FIRMWARE_SIZE 12332
 +
-+		count += 200;
++/* Misc Defines */
++#define MAX_TV_STANDARD			23
++#define XC_MAX_I2C_WRITE_LENGTH		64
 +
-+		if (count < count_limit)
-+			continue;
++/* Signal Types */
++#define XC_RF_MODE_AIR			0
++#define XC_RF_MODE_CABLE		1
 +
-+		if (sgn <= 0)
-+			break;
++/* Result codes */
++#define XC_RESULT_SUCCESS		0
++#define XC_RESULT_RESET_FAILURE		1
++#define XC_RESULT_I2C_WRITE_FAILURE	2
++#define XC_RESULT_I2C_READ_FAILURE	3
++#define XC_RESULT_OUT_OF_RANGE		5
 +
-+		sgn = -1 * sgn;
-+		count = 200;
-+		wait = true;
-+	}
++/* Product id */
++#define XC_PRODUCT_ID_FW_NOT_LOADED	0x2000
++#define XC_PRODUCT_ID_FW_LOADED 	0x1388
 +
-+	if ((regs[R_EB10] & 0x3f) >= cid_target) {
-+		bcal = 1;
-+		*freq_out = freq - 1000000;
-+	} else
-+		bcal = 0;
++/* Registers */
++#define XREG_INIT         0x00
++#define XREG_VIDEO_MODE   0x01
++#define XREG_AUDIO_MODE   0x02
++#define XREG_RF_FREQ      0x03
++#define XREG_D_CODE       0x04
++#define XREG_IF_OUT       0x05
++#define XREG_SEEK_MODE    0x07
++#define XREG_POWER_DOWN   0x0A
++#define XREG_SIGNALSOURCE 0x0D /* 0=Air, 1=Cable */
++#define XREG_SMOOTHEDCVBS 0x0E
++#define XREG_XTALFREQ     0x0F
++#define XREG_FINERFFREQ   0x10
++#define XREG_DDIMODE      0x11
 +
-+	tda_cal("bcal = %d, freq_in = %d, freq_out = %d (freq = %d)\n",
-+		bcal, *freq_in, *freq_out, freq);
++#define XREG_ADC_ENV      0x00
++#define XREG_QUALITY      0x01
++#define XREG_FRAME_LINES  0x02
++#define XREG_HSYNC_FREQ   0x03
++#define XREG_LOCK         0x04
++#define XREG_FREQ_ERROR   0x05
++#define XREG_SNR          0x06
++#define XREG_VERSION      0x07
++#define XREG_PRODUCT_ID   0x08
++#define XREG_BUSY         0x09
 +
-+	return bcal;
-+}
++/*
++   Basic firmware description. This will remain with
++   the driver for documentation purposes.
 +
-+static int tda18271_powerscan_init(struct dvb_frontend *fe)
-+{
-+	struct tda18271_priv *priv = fe->tuner_priv;
-+	unsigned char *regs = priv->tda18271_regs;
++   This represents an I2C firmware file encoded as a
++   string of unsigned char. Format is as follows:
 +
-+	/* set standard to digital */
-+	regs[R_EP3]  &= ~0x1f; /* clear std bits */
-+	regs[R_EP3]  |= 0x12;
++   char[0  ]=len0_MSB  -> len = len_MSB * 256 + len_LSB
++   char[1  ]=len0_LSB  -> length of first write transaction
++   char[2  ]=data0 -> first byte to be sent
++   char[3  ]=data1
++   char[4  ]=data2
++   char[   ]=...
++   char[M  ]=dataN  -> last byte to be sent
++   char[M+1]=len1_MSB  -> len = len_MSB * 256 + len_LSB
++   char[M+2]=len1_LSB  -> length of second write transaction
++   char[M+3]=data0
++   char[M+4]=data1
++   ...
++   etc.
 +
-+	/* set cal mode to normal */
-+	regs[R_EP4]  &= ~0x03;
++   The [len] value should be interpreted as follows:
 +
-+	/* update IF output level & IF notch frequency */
-+	regs[R_EP4]  &= ~0x1c; /* clear if level bits */
++   len= len_MSB _ len_LSB
++   len=1111_1111_1111_1111   : End of I2C_SEQUENCE
++   len=0000_0000_0000_0000   : Reset command: Do hardware reset
++   len=0NNN_NNNN_NNNN_NNNN   : Normal transaction: number of bytes = {1:32767)
++   len=1WWW_WWWW_WWWW_WWWW   : Wait command: wait for {1:32767} ms
 +
-+	tda18271_write_regs(fe, R_EP3, 2);
++   For the RESET and WAIT commands, the two following bytes will contain
++   immediately the length of the following transaction.
 +
-+	regs[R_EB18] &= ~0x03; /* set agc1_gain to   6 dB */
-+	tda18271_write_regs(fe, R_EB18, 1);
++*/
++typedef struct {
++	char *Name;
++	u16 AudioMode;
++	u16 VideoMode;
++} XC_TV_STANDARD;
 +
-+	regs[R_EB21] &= ~0x03; /* set agc2_gain to -15 dB */
++/* Tuner standards */
++#define MN_NTSC_PAL_BTSC	0
++#define MN_NTSC_PAL_A2		1
++#define MN_NTSC_PAL_EIAJ	2
++#define MN_NTSC_PAL_Mono	3
++#define BG_PAL_A2		4
++#define BG_PAL_NICAM		5
++#define BG_PAL_MONO		6
++#define I_PAL_NICAM		7
++#define I_PAL_NICAM_MONO	8
++#define DK_PAL_A2		9
++#define DK_PAL_NICAM		10
++#define DK_PAL_MONO		11
++#define DK_SECAM_A2DK1		12
++#define DK_SECAM_A2LDK3 	13
++#define DK_SECAM_A2MONO 	14
++#define L_SECAM_NICAM		15
++#define LC_SECAM_NICAM		16
++#define DTV6			17
++#define DTV8			18
++#define DTV7_8			19
++#define DTV7			20
++#define FM_Radio_INPUT2 	21
++#define FM_Radio_INPUT1 	22
 +
-+	/* 1.5 MHz low pass filter */
-+	regs[R_EB23] |= 0x04; /* forcelp_fc2_en = 1 */
-+	regs[R_EB23] |= 0x02; /* lp_fc[2] = 1 */
++XC_TV_STANDARD XC5000_Standard[MAX_TV_STANDARD] = {
++	{"M/N-NTSC/PAL-BTSC", 0x0400, 0x8020},
++	{"M/N-NTSC/PAL-A2",   0x0600, 0x8020},
++	{"M/N-NTSC/PAL-EIAJ", 0x0440, 0x8020},
++	{"M/N-NTSC/PAL-Mono", 0x0478, 0x8020},
++	{"B/G-PAL-A2",        0x0A00, 0x8049},
++	{"B/G-PAL-NICAM",     0x0C04, 0x8049},
++	{"B/G-PAL-MONO",      0x0878, 0x8059},
++	{"I-PAL-NICAM",       0x1080, 0x8009},
++	{"I-PAL-NICAM-MONO",  0x0E78, 0x8009},
++	{"D/K-PAL-A2",        0x1600, 0x8009},
++	{"D/K-PAL-NICAM",     0x0E80, 0x8009},
++	{"D/K-PAL-MONO",      0x1478, 0x8009},
++	{"D/K-SECAM-A2 DK1",  0x1200, 0x8009},
++	{"D/K-SECAM-A2 L/DK3",0x0E00, 0x8009},
++	{"D/K-SECAM-A2 MONO", 0x1478, 0x8009},
++	{"L-SECAM-NICAM",     0x8E82, 0x0009},
++	{"L'-SECAM-NICAM",    0x8E82, 0x4009},
++	{"DTV6",              0x00C0, 0x8002},
++	{"DTV8",              0x00C0, 0x800B},
++	{"DTV7/8",            0x00C0, 0x801B},
++	{"DTV7",              0x00C0, 0x8007},
++	{"FM Radio-INPUT2",   0x9802, 0x9002},
++	{"FM Radio-INPUT1",   0x0208, 0x9002}
++};
 +
-+	tda18271_write_regs(fe, R_EB21, 3);
++static int  xc5000_writeregs(struct xc5000_priv *priv, u8 *buf, u8 len);
++static int  xc5000_readregs(struct xc5000_priv *priv, u8 *buf, u8 len);
++static void xc5000_TunerReset(struct dvb_frontend *fe);
 +
-+	return 0;
++static int xc_send_i2c_data(struct xc5000_priv *priv, u8 *buf, int len)
++{
++	return xc5000_writeregs(priv, buf, len)
++		? XC_RESULT_I2C_WRITE_FAILURE : XC_RESULT_SUCCESS;
 +}
 +
-+static int tda18271_rf_tracking_filters_init(struct dvb_frontend *fe, u32 freq)
++static int xc_read_i2c_data(struct xc5000_priv *priv, u8 *buf, int len)
 +{
-+	struct tda18271_priv *priv = fe->tuner_priv;
-+	struct tda18271_rf_tracking_filter_cal *map = priv->rf_cal_state;
-+	unsigned char *regs = priv->tda18271_regs;
-+	int bcal, rf, i;
-+#define RF1 0
-+#define RF2 1
-+#define RF3 2
-+	u32 rf_default[3];
-+	u32 rf_freq[3];
-+	u8 prog_cal[3];
-+	u8 prog_tab[3];
++	return xc5000_readregs(priv, buf, len)
++		? XC_RESULT_I2C_READ_FAILURE : XC_RESULT_SUCCESS;
++}
 +
-+	i = tda18271_lookup_rf_band(fe, &freq, NULL);
++static int xc_reset(struct dvb_frontend *fe)
++{
++	xc5000_TunerReset(fe);
++	return XC_RESULT_SUCCESS;
++}
 +
-+	if (i < 0)
-+		return i;
++static void xc_wait(int wait_ms)
++{
++	msleep(wait_ms);
++}
 +
-+	rf_default[RF1] = 1000 * map[i].rf1_def;
-+	rf_default[RF2] = 1000 * map[i].rf2_def;
-+	rf_default[RF3] = 1000 * map[i].rf3_def;
++static void xc5000_TunerReset(struct dvb_frontend *fe)
++{
++	struct xc5000_priv *priv = fe->tuner_priv;
++	int ret;
 +
-+	for (rf = RF1; rf <= RF3; rf++) {
-+		if (0 == rf_default[rf])
-+			return 0;
-+		tda_cal("freq = %d, rf = %d\n", freq, rf);
++	dprintk(1, "%s()\n", __FUNCTION__);
 +
-+		/* look for optimized calibration frequency */
-+		bcal = tda18271_powerscan(fe, &rf_default[rf], &rf_freq[rf]);
++	if (priv->cfg->tuner_callback) {
++		ret = priv->cfg->tuner_callback(priv->cfg->priv,
++						XC5000_TUNER_RESET, 0);
++		if (ret)
++			printk(KERN_ERR "xc5000: reset failed\n");
++	} else
++		printk(KERN_ERR "xc5000: no tuner reset callback function, fatal\n");
++}
 +
-+		tda18271_calc_rf_cal(fe, &rf_freq[rf]);
-+		prog_tab[rf] = regs[R_EB14];
++static int xc_write_reg(struct xc5000_priv *priv, u16 regAddr, u16 i2cData)
++{
++	u8 buf[4];
++	int WatchDogTimer = 5;
++	int result;
 +
-+		if (1 == bcal)
-+			prog_cal[rf] = tda18271_calibrate_rf(fe, rf_freq[rf]);
-+		else
-+			prog_cal[rf] = prog_tab[rf];
++	buf[0] = (regAddr >> 8) & 0xFF;
++	buf[1] = regAddr & 0xFF;
++	buf[2] = (i2cData >> 8) & 0xFF;
++	buf[3] = i2cData & 0xFF;
++	result = xc_send_i2c_data(priv, buf, 4);
++	if (result == XC_RESULT_SUCCESS) {
++		/* wait for busy flag to clear */
++		while ((WatchDogTimer > 0) && (result == XC_RESULT_SUCCESS)) {
++			buf[0] = 0;
++			buf[1] = XREG_BUSY;
 +
-+		switch (rf) {
-+		case RF1:
-+			map[i].rf_a1 = 0;
-+			map[i].rf_b1 = prog_cal[RF1] - prog_tab[RF1];
-+			map[i].rf1   = rf_freq[RF1] / 1000;
-+			break;
-+		case RF2:
-+			map[i].rf_a1 = (prog_cal[RF2] - prog_tab[RF2] -
-+					prog_cal[RF1] + prog_tab[RF1]) /
-+				((rf_freq[RF2] - rf_freq[RF1]) / 1000);
-+			map[i].rf2   = rf_freq[RF2] / 1000;
-+			break;
-+		case RF3:
-+			map[i].rf_a2 = (prog_cal[RF3] - prog_tab[RF3] -
-+					prog_cal[RF2] + prog_tab[RF2]) /
-+				((rf_freq[RF3] - rf_freq[RF2]) / 1000);
-+			map[i].rf_b2 = prog_cal[RF2] - prog_tab[RF2];
-+			map[i].rf3   = rf_freq[RF3] / 1000;
-+			break;
-+		default:
-+			BUG();
++			result = xc_send_i2c_data(priv, buf, 2);
++			if (result == XC_RESULT_SUCCESS) {
++				result = xc_read_i2c_data(priv, buf, 2);
++				if (result == XC_RESULT_SUCCESS) {
++					if ((buf[0] == 0) && (buf[1] == 0)) {
++						/* busy flag cleared */
++					break;
++					} else {
++						xc_wait(100); /* wait 5 ms */
++						WatchDogTimer--;
++					}
++				}
++			}
 +		}
 +	}
++	if (WatchDogTimer < 0)
++		result = XC_RESULT_I2C_WRITE_FAILURE;
 +
-+	return 0;
++	return result;
 +}
 +
-+static int tda18271_calc_rf_filter_curve(struct dvb_frontend *fe)
++static int xc_read_reg(struct xc5000_priv *priv, u16 regAddr, u16 *i2cData)
 +{
-+	struct tda18271_priv *priv = fe->tuner_priv;
-+	unsigned int i;
-+
-+	tda_info("tda18271: performing RF tracking filter calibration\n");
-+
-+	/* wait for die temperature stabilization */
-+	msleep(200);
-+
-+	tda18271_powerscan_init(fe);
++	u8 buf[2];
++	int result;
 +
-+	/* rf band calibration */
-+	for (i = 0; priv->rf_cal_state[i].rfmax != 0; i++)
-+		tda18271_rf_tracking_filters_init(fe, 1000 *
-+						  priv->rf_cal_state[i].rfmax);
++	buf[0] = (regAddr >> 8) & 0xFF;
++	buf[1] = regAddr & 0xFF;
++	result = xc_send_i2c_data(priv, buf, 2);
++	if (result != XC_RESULT_SUCCESS)
++		return result;
 +
-+	priv->tm_rfcal = tda18271_read_thermometer(fe);
++	result = xc_read_i2c_data(priv, buf, 2);
++	if (result != XC_RESULT_SUCCESS)
++		return result;
 +
-+	return 0;
++	*i2cData = buf[0] * 256 + buf[1];
++	return result;
 +}
 +
-+/* ------------------------------------------------------------------ */
-+
-+static int tda18271_rf_cal_init(struct dvb_frontend *fe)
++static int xc_load_i2c_sequence(struct dvb_frontend *fe, u8 i2c_sequence[])
 +{
-+	struct tda18271_priv *priv = fe->tuner_priv;
-+	unsigned char *regs = priv->tda18271_regs;
-+
-+	/* test RF_CAL_OK to see if we need init */
-+	if ((regs[R_EP1] & 0x10) == 0)
-+		priv->cal_initialized = false;
-+
-+	if (priv->cal_initialized)
-+		return 0;
-+
-+	tda18271_calc_rf_filter_curve(fe);
++	struct xc5000_priv *priv = fe->tuner_priv;
 +
-+	tda18271_por(fe);
++	int i, nbytes_to_send, result;
++	unsigned int len, pos, index;
++	u8 buf[XC_MAX_I2C_WRITE_LENGTH];
 +
-+	tda_info("tda18271: RF tracking filter calibration complete\n");
++	index=0;
++	while ((i2c_sequence[index]!=0xFF) || (i2c_sequence[index+1]!=0xFF)) {
++		len = i2c_sequence[index]* 256 + i2c_sequence[index+1];
++		if (len == 0x0000) {
++			/* RESET command */
++			result = xc_reset(fe);
++			index += 2;
++			if (result != XC_RESULT_SUCCESS)
++				return result;
++		} else if (len & 0x8000) {
++			/* WAIT command */
++			xc_wait(len & 0x7FFF);
++			index += 2;
++		} else {
++			/* Send i2c data whilst ensuring individual transactions
++			 * do not exceed XC_MAX_I2C_WRITE_LENGTH bytes.
++			 */
++			index += 2;
++			buf[0] = i2c_sequence[index];
++			buf[1] = i2c_sequence[index + 1];
++			pos = 2;
++			while (pos < len) {
++				if ((len - pos) > XC_MAX_I2C_WRITE_LENGTH - 2) {
++					nbytes_to_send = XC_MAX_I2C_WRITE_LENGTH;
++				} else {
++					nbytes_to_send = (len - pos + 2);
++				}
++				for (i=2; i<nbytes_to_send; i++) {
++					buf[i] = i2c_sequence[index + pos + i - 2];
++				}
++				result = xc_send_i2c_data(priv, buf, nbytes_to_send);
 +
-+	priv->cal_initialized = true;
++				if (result != XC_RESULT_SUCCESS)
++					return result;
 +
-+	return 0;
++				pos += nbytes_to_send - 2;
++			}
++			index += len;
++		}
++	}
++	return XC_RESULT_SUCCESS;
 +}
 +
-+static int tda18271_init(struct dvb_frontend *fe)
++static int xc_initialize(struct xc5000_priv *priv)
 +{
-+	struct tda18271_priv *priv = fe->tuner_priv;
-+
-+	mutex_lock(&priv->lock);
-+
-+	/* power up */
-+	tda18271_set_standby_mode(fe, 0, 0, 0);
++	dprintk(1, "%s()\n", __FUNCTION__);
++	return xc_write_reg(priv, XREG_INIT, 0);
++}
 +
-+	/* initialization */
-+	tda18271_ir_cal_init(fe);
++static int xc_SetTVStandard(struct xc5000_priv *priv,
++	u16 VideoMode, u16 AudioMode)
++{
++	int ret;
++	dprintk(1, "%s(0x%04x,0x%04x)\n", __FUNCTION__, VideoMode, AudioMode);
++	dprintk(1, "%s() Standard = %s\n",
++		__FUNCTION__,
++		XC5000_Standard[priv->video_standard].Name);
 +
-+	if (priv->id == TDA18271HDC2)
-+		tda18271_rf_cal_init(fe);
++	ret = xc_write_reg(priv, XREG_VIDEO_MODE, VideoMode);
++	if (ret == XC_RESULT_SUCCESS)
++		ret = xc_write_reg(priv, XREG_AUDIO_MODE, AudioMode);
 +
-+	mutex_unlock(&priv->lock);
++	return ret;
++}
 +
++static int xc_shutdown(struct xc5000_priv *priv)
++{
 +	return 0;
++	/* Fixme: cannot bring tuner back alive once shutdown
++	 *        without reloading the driver modules.
++	 *    return xc_write_reg(priv, XREG_POWER_DOWN, 0);
++	 */
 +}
 +
-+static int tda18271c2_tune(struct dvb_frontend *fe,
-+			   u32 ifc, u32 freq, u32 bw, u8 std, int radio)
++static int xc_SetSignalSource(struct xc5000_priv *priv, u16 rf_mode)
 +{
-+	struct tda18271_priv *priv = fe->tuner_priv;
++	dprintk(1, "%s(%d) Source = %s\n", __FUNCTION__, rf_mode,
++		rf_mode == XC_RF_MODE_AIR ? "ANTENNA" : "CABLE");
 +
-+	tda_dbg("freq = %d, ifc = %d\n", freq, ifc);
++	if ((rf_mode != XC_RF_MODE_AIR) && (rf_mode != XC_RF_MODE_CABLE))
++	{
++		rf_mode = XC_RF_MODE_CABLE;
++		printk(KERN_ERR
++			"%s(), Invalid mode, defaulting to CABLE",
++			__FUNCTION__);
++	}
++	return xc_write_reg(priv, XREG_SIGNALSOURCE, rf_mode);
++}
 +
-+	tda18271_init(fe);
++static const struct dvb_tuner_ops xc5000_tuner_ops;
 +
-+	mutex_lock(&priv->lock);
++static int xc_set_RF_frequency(struct xc5000_priv *priv, u32 freq_hz)
++{
++	u16 freq_code;
 +
-+	tda18271_rf_tracking_filters_correction(fe, freq);
++	dprintk(1, "%s(%u)\n", __FUNCTION__, freq_hz);
 +
-+	tda18271_channel_configuration(fe, ifc, freq, bw, std, radio);
++	if ((freq_hz > xc5000_tuner_ops.info.frequency_max) ||
++		(freq_hz < xc5000_tuner_ops.info.frequency_min))
++		return XC_RESULT_OUT_OF_RANGE;
 +
-+	mutex_unlock(&priv->lock);
++	freq_code = (u16)(freq_hz / 15625);
 +
-+	return 0;
++	return xc_write_reg(priv, XREG_RF_FREQ, freq_code);
 +}
 +
-+/* ------------------------------------------------------------------ */
 +
-+static int tda18271c1_tune(struct dvb_frontend *fe,
-+			   u32 ifc, u32 freq, u32 bw, u8 std, int radio)
++static int xc_set_IF_frequency(struct xc5000_priv *priv, u32 freq_khz)
 +{
-+	struct tda18271_priv *priv = fe->tuner_priv;
-+	unsigned char *regs = priv->tda18271_regs;
-+	u32 N = 0;
-+
-+	tda18271_init(fe);
-+
-+	mutex_lock(&priv->lock);
-+
-+	tda_dbg("freq = %d, ifc = %d\n", freq, ifc);
-+
-+	/* RF tracking filter calibration */
++	u32 freq_code = (freq_khz * 1024)/1000;
++	dprintk(1, "%s(freq_khz = %d) freq_code = 0x%x\n",
++		__FUNCTION__, freq_khz, freq_code);
 +
-+	/* calculate bp filter */
-+	tda18271_calc_bp_filter(fe, &freq);
-+	tda18271_write_regs(fe, R_EP1, 1);
++	return xc_write_reg(priv, XREG_IF_OUT, freq_code);
++}
 +
-+	regs[R_EB4]  &= 0x07;
-+	regs[R_EB4]  |= 0x60;
-+	tda18271_write_regs(fe, R_EB4, 1);
 +
-+	regs[R_EB7]   = 0x60;
-+	tda18271_write_regs(fe, R_EB7, 1);
++static int xc_get_ADC_Envelope(struct xc5000_priv *priv, u16 *adc_envelope)
++{
++	return xc_read_reg(priv, XREG_ADC_ENV, adc_envelope);
++}
 +
-+	regs[R_EB14]  = 0x00;
-+	tda18271_write_regs(fe, R_EB14, 1);
++static int xc_get_frequency_error(struct xc5000_priv *priv, u32 *freq_error_hz)
++{
++	int result;
++	u16 regData;
++	u32 tmp;
 +
-+	regs[R_EB20]  = 0xcc;
-+	tda18271_write_regs(fe, R_EB20, 1);
++	result = xc_read_reg(priv, XREG_FREQ_ERROR, &regData);
++	if (result)
++		return result;
 +
-+	/* set cal mode to RF tracking filter calibration */
-+	regs[R_EP4]  |= 0x03;
++	tmp = (u32)regData;
++	(*freq_error_hz) = (tmp * 15625) / 1000;
++	return result;
++}
 +
-+	/* calculate cal pll */
++static int xc_get_lock_status(struct xc5000_priv *priv, u16 *lock_status)
++{
++	return xc_read_reg(priv, XREG_LOCK, lock_status);
++}
 +
-+	switch (priv->mode) {
-+	case TDA18271_ANALOG:
-+		N = freq - 1250000;
-+		break;
-+	case TDA18271_DIGITAL:
-+		N = freq + bw / 2;
-+		break;
-+	}
++static int xc_get_version(struct xc5000_priv *priv,
++	u8 *hw_majorversion, u8 *hw_minorversion,
++	u8 *fw_majorversion, u8 *fw_minorversion)
++{
++	u16 data;
++	int result;
 +
-+	tda18271_calc_cal_pll(fe, N);
++	result = xc_read_reg(priv, XREG_VERSION, &data);
++	if (result)
++		return result;
 +
-+	/* calculate main pll */
++	(*hw_majorversion) = (data >> 12) & 0x0F;
++	(*hw_minorversion) = (data >>  8) & 0x0F;
++	(*fw_majorversion) = (data >>  4) & 0x0F;
++	(*fw_minorversion) = data & 0x0F;
 +
-+	switch (priv->mode) {
-+	case TDA18271_ANALOG:
-+		N = freq - 250000;
-+		break;
-+	case TDA18271_DIGITAL:
-+		N = freq + bw / 2 + 1000000;
-+		break;
-+	}
++	return 0;
++}
 +
-+	tda18271_calc_main_pll(fe, N);
++static int xc_get_hsync_freq(struct xc5000_priv *priv, u32 *hsync_freq_hz)
++{
++	u16 regData;
++	int result;
 +
-+	tda18271_write_regs(fe, R_EP3, 11);
-+	msleep(5); /* RF tracking filter calibration initialization */
++	result = xc_read_reg(priv, XREG_HSYNC_FREQ, &regData);
++	if (result)
++		return result;
 +
-+	/* search for K,M,CO for RF calibration */
-+	tda18271_calc_km(fe, &freq);
-+	tda18271_write_regs(fe, R_EB13, 1);
++	(*hsync_freq_hz) = ((regData & 0x0fff) * 763)/100;
++	return result;
++}
 +
-+	/* search for rf band */
-+	tda18271_calc_rf_band(fe, &freq);
++static int xc_get_frame_lines(struct xc5000_priv *priv, u16 *frame_lines)
++{
++	return xc_read_reg(priv, XREG_FRAME_LINES, frame_lines);
++}
 +
-+	/* search for gain taper */
-+	tda18271_calc_gain_taper(fe, &freq);
++static int xc_get_quality(struct xc5000_priv *priv, u16 *quality)
++{
++	return xc_read_reg(priv, XREG_QUALITY, quality);
++}
 +
-+	tda18271_write_regs(fe, R_EP2, 1);
-+	tda18271_write_regs(fe, R_EP1, 1);
-+	tda18271_write_regs(fe, R_EP2, 1);
-+	tda18271_write_regs(fe, R_EP1, 1);
++static u16 WaitForLock(struct xc5000_priv *priv)
++{
++	u16 lockState = 0;
++	int watchDogCount = 40;
 +
-+	regs[R_EB4]  &= 0x07;
-+	regs[R_EB4]  |= 0x40;
-+	tda18271_write_regs(fe, R_EB4, 1);
++	while ((lockState == 0) && (watchDogCount > 0)) {
++		xc_get_lock_status(priv, &lockState);
++		if (lockState != 1) {
++			xc_wait(5);
++			watchDogCount--;
++		}
++	}
++	return lockState;
++}
 +
-+	regs[R_EB7]   = 0x40;
-+	tda18271_write_regs(fe, R_EB7, 1);
-+	msleep(10);
++static int xc_tune_channel(struct xc5000_priv *priv, u32 freq_hz)
++{
++	int found = 0;
 +
-+	regs[R_EB20]  = 0xec;
-+	tda18271_write_regs(fe, R_EB20, 1);
-+	msleep(60); /* RF tracking filter calibration completion */
++	dprintk(1, "%s(%u)\n", __FUNCTION__, freq_hz);
 +
-+	regs[R_EP4]  &= ~0x03; /* set cal mode to normal */
-+	tda18271_write_regs(fe, R_EP4, 1);
++	if (xc_set_RF_frequency(priv, freq_hz) != XC_RESULT_SUCCESS)
++		return 0;
 +
-+	tda18271_write_regs(fe, R_EP1, 1);
++	if (WaitForLock(priv) == 1)
++		found = 1;
 +
-+	/* RF tracking filter correction for VHF_Low band */
-+	if (0 == tda18271_calc_rf_cal(fe, &freq))
-+		tda18271_write_regs(fe, R_EB14, 1);
++	return found;
++}
 +
-+	/* Channel Configuration */
++static int xc5000_readreg(struct xc5000_priv *priv, u16 reg, u16 *val)
++{
++	u8 buf[2] = { reg >> 8, reg & 0xff };
++	u8 bval[2] = { 0, 0 };
++	struct i2c_msg msg[2] = {
++		{ .addr = priv->cfg->i2c_address,
++			.flags = 0, .buf = &buf[0], .len = 2 },
++		{ .addr = priv->cfg->i2c_address,
++			.flags = I2C_M_RD, .buf = &bval[0], .len = 2 },
++	};
 +
-+	switch (priv->mode) {
-+	case TDA18271_ANALOG:
-+		regs[R_EB22]  = 0x2c;
-+		break;
-+	case TDA18271_DIGITAL:
-+		regs[R_EB22]  = 0x37;
-+		break;
++	if (i2c_transfer(priv->i2c, msg, 2) != 2) {
++		printk(KERN_WARNING "xc5000: I2C read failed\n");
++		return -EREMOTEIO;
 +	}
-+	tda18271_write_regs(fe, R_EB22, 1);
-+
-+	regs[R_EP1]  |= 0x40; /* set dis power level on */
-+
-+	/* set standard */
-+	regs[R_EP3]  &= ~0x1f; /* clear std bits */
 +
-+	/* see table 22 */
-+	regs[R_EP3]  |= std;
++	*val = (bval[0] << 8) | bval[1];
++	return 0;
++}
 +
-+	regs[R_EP4]  &= ~0x03; /* set cal mode to normal */
++static int xc5000_writeregs(struct xc5000_priv *priv, u8 *buf, u8 len)
++{
++	struct i2c_msg msg = { .addr = priv->cfg->i2c_address,
++		.flags = 0, .buf = buf, .len = len };
 +
-+	regs[R_EP4]  &= ~0x1c; /* clear if level bits */
-+	switch (priv->mode) {
-+	case TDA18271_ANALOG:
-+		regs[R_MPD]  &= ~0x80; /* IF notch = 0 */
-+		break;
-+	case TDA18271_DIGITAL:
-+		regs[R_EP4]  |= 0x04;
-+		regs[R_MPD]  |= 0x80;
-+		break;
++	if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
++		printk(KERN_ERR "xc5000: I2C write failed (len=%i)\n",
++			(int)len);
++		return -EREMOTEIO;
 +	}
-+
-+	if (radio)
-+		regs[R_EP4]  |=  0x80;
-+	else
-+		regs[R_EP4]  &= ~0x80;
-+
-+	/* image rejection validity */
-+	tda18271_calc_ir_measure(fe, &freq);
-+
-+	/* calculate MAIN PLL */
-+	N = freq + ifc;
-+
-+	tda18271_calc_main_pll(fe, N);
-+
-+	tda18271_write_regs(fe, R_TM, 15);
-+	msleep(5);
-+	mutex_unlock(&priv->lock);
-+
 +	return 0;
 +}
 +
-+static inline int tda18271_tune(struct dvb_frontend *fe,
-+				u32 ifc, u32 freq, u32 bw, u8 std, int radio)
++static int xc5000_readregs(struct xc5000_priv *priv, u8 *buf, u8 len)
 +{
-+	struct tda18271_priv *priv = fe->tuner_priv;
-+	int ret = -EINVAL;
++	struct i2c_msg msg = { .addr = priv->cfg->i2c_address,
++		.flags = I2C_M_RD, .buf = buf, .len = len };
 +
-+	switch (priv->id) {
-+	case TDA18271HDC1:
-+		ret = tda18271c1_tune(fe, ifc, freq, bw, std, radio);
-+		break;
-+	case TDA18271HDC2:
-+		ret = tda18271c2_tune(fe, ifc, freq, bw, std, radio);
-+		break;
++	if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
++		printk(KERN_ERR "xc5000 I2C read failed (len=%i)\n",(int)len);
++		return -EREMOTEIO;
 +	}
-+	return ret;
++	return 0;
 +}
 +
-+/* ------------------------------------------------------------------ */
-+
-+static int tda18271_set_params(struct dvb_frontend *fe,
-+			       struct dvb_frontend_parameters *params)
++static int xc5000_fwupload(struct dvb_frontend* fe)
 +{
-+	struct tda18271_priv *priv = fe->tuner_priv;
-+	struct tda18271_std_map *std_map = &priv->std;
++	struct xc5000_priv *priv = fe->tuner_priv;
++	const struct firmware *fw;
 +	int ret;
-+	u8 std;
-+	u16 sgIF;
-+	u32 bw, freq = params->frequency;
 +
-+	priv->mode = TDA18271_DIGITAL;
++	/* request the firmware, this will block and timeout */
++	printk(KERN_INFO "xc5000: waiting for firmware upload (%s)...\n",
++		XC5000_DEFAULT_FIRMWARE);
 +
-+	if (fe->ops.info.type == FE_ATSC) {
-+		switch (params->u.vsb.modulation) {
-+		case VSB_8:
-+		case VSB_16:
-+			std  = std_map->atsc_6.std_bits;
-+			sgIF = std_map->atsc_6.if_freq;
-+			break;
-+		case QAM_64:
-+		case QAM_256:
-+			std  = std_map->qam_6.std_bits;
-+			sgIF = std_map->qam_6.if_freq;
-+			break;
-+		default:
-+			tda_warn("modulation not set!\n");
-+			return -EINVAL;
-+		}
-+#if 0
-+		/* userspace request is already center adjusted */
-+		freq += 1750000; /* Adjust to center (+1.75MHZ) */
-+#endif
-+		bw = 6000000;
-+	} else if (fe->ops.info.type == FE_OFDM) {
-+		switch (params->u.ofdm.bandwidth) {
-+		case BANDWIDTH_6_MHZ:
-+			bw = 6000000;
-+			std  = std_map->dvbt_6.std_bits;
-+			sgIF = std_map->dvbt_6.if_freq;
-+			break;
-+		case BANDWIDTH_7_MHZ:
-+			bw = 7000000;
-+			std  = std_map->dvbt_7.std_bits;
-+			sgIF = std_map->dvbt_7.if_freq;
-+			break;
-+		case BANDWIDTH_8_MHZ:
-+			bw = 8000000;
-+			std  = std_map->dvbt_8.std_bits;
-+			sgIF = std_map->dvbt_8.if_freq;
-+			break;
-+		default:
-+			tda_warn("bandwidth not set!\n");
-+			return -EINVAL;
-+		}
++	ret = request_firmware(&fw, XC5000_DEFAULT_FIRMWARE, &priv->i2c->dev);
++	if (ret) {
++		printk(KERN_ERR "xc5000: Upload failed. (file not found?)\n");
++		ret = XC_RESULT_RESET_FAILURE;
++		goto out;
 +	} else {
-+		tda_warn("modulation type not supported!\n");
-+		return -EINVAL;
++		printk(KERN_INFO "xc5000: firmware read %Zu bytes.\n",
++		       fw->size);
++		ret = XC_RESULT_SUCCESS;
 +	}
 +
-+	/* When tuning digital, the analog demod must be tri-stated */
-+	if (fe->ops.analog_ops.standby)
-+		fe->ops.analog_ops.standby(fe);
++	if (fw->size != XC5000_DEFAULT_FIRMWARE_SIZE) {
++		printk(KERN_ERR "xc5000: firmware incorrect size\n");
++		ret = XC_RESULT_RESET_FAILURE;
++	} else {
++		printk(KERN_INFO "xc5000: firmware upload\n");
++		ret = xc_load_i2c_sequence(fe,  fw->data );
++	}
++
++out:
++	release_firmware(fw);
++	return ret;
++}
++
++static void xc_debug_dump(struct xc5000_priv *priv)
++{
++	u16 adc_envelope;
++	u32 freq_error_hz = 0;
++	u16 lock_status;
++	u32 hsync_freq_hz = 0;
++	u16 frame_lines;
++	u16 quality;
++	u8 hw_majorversion = 0, hw_minorversion = 0;
++	u8 fw_majorversion = 0, fw_minorversion = 0;
++
++	/* Wait for stats to stabilize.
++	 * Frame Lines needs two frame times after initial lock
++	 * before it is valid.
++	 */
++	xc_wait(100);
++
++	xc_get_ADC_Envelope(priv,  &adc_envelope);
++	dprintk(1, "*** ADC envelope (0-1023) = %d\n", adc_envelope);
++
++	xc_get_frequency_error(priv, &freq_error_hz);
++	dprintk(1, "*** Frequency error = %d Hz\n", freq_error_hz);
++
++	xc_get_lock_status(priv,  &lock_status);
++	dprintk(1, "*** Lock status (0-Wait, 1-Locked, 2-No-signal) = %d\n",
++		lock_status);
++
++	xc_get_version(priv,  &hw_majorversion, &hw_minorversion,
++		&fw_majorversion, &fw_minorversion);
++	dprintk(1, "*** HW: V%02x.%02x, FW: V%02x.%02x\n",
++		hw_majorversion, hw_minorversion,
++		fw_majorversion, fw_minorversion);
 +
-+	ret = tda18271_tune(fe, sgIF * 1000, freq, bw, std, 0);
++	xc_get_hsync_freq(priv,  &hsync_freq_hz);
++	dprintk(1, "*** Horizontal sync frequency = %d Hz\n", hsync_freq_hz);
 +
-+	if (ret < 0)
-+		goto fail;
++	xc_get_frame_lines(priv,  &frame_lines);
++	dprintk(1, "*** Frame lines = %d\n", frame_lines);
 +
-+	priv->frequency = freq;
-+	priv->bandwidth = (fe->ops.info.type == FE_OFDM) ?
-+		params->u.ofdm.bandwidth : 0;
-+fail:
-+	return ret;
++	xc_get_quality(priv,  &quality);
++	dprintk(1, "*** Quality (0:<8dB, 7:>56dB) = %d\n", quality);
 +}
 +
-+static int tda18271_set_analog_params(struct dvb_frontend *fe,
-+				      struct analog_parameters *params)
++static int xc5000_set_params(struct dvb_frontend *fe,
++	struct dvb_frontend_parameters *params)
 +{
-+	struct tda18271_priv *priv = fe->tuner_priv;
-+	struct tda18271_std_map *std_map = &priv->std;
-+	char *mode;
-+	int ret, radio = 0;
-+	u8 std;
-+	u16 sgIF;
-+	u32 freq = params->frequency * 62500;
++	struct xc5000_priv *priv = fe->tuner_priv;
++	int ret;
 +
-+	priv->mode = TDA18271_ANALOG;
++	dprintk(1, "%s() frequency=%d (Hz)\n", __FUNCTION__, params->frequency);
 +
-+	if (params->mode == V4L2_TUNER_RADIO) {
-+		radio = 1;
-+		freq = freq / 1000;
-+		std  = std_map->fm_radio.std_bits;
-+		sgIF = std_map->fm_radio.if_freq;
-+		mode = "fm";
-+	} else if (params->std & V4L2_STD_MN) {
-+		std  = std_map->atv_mn.std_bits;
-+		sgIF = std_map->atv_mn.if_freq;
-+		mode = "MN";
-+	} else if (params->std & V4L2_STD_B) {
-+		std  = std_map->atv_b.std_bits;
-+		sgIF = std_map->atv_b.if_freq;
-+		mode = "B";
-+	} else if (params->std & V4L2_STD_GH) {
-+		std  = std_map->atv_gh.std_bits;
-+		sgIF = std_map->atv_gh.if_freq;
-+		mode = "GH";
-+	} else if (params->std & V4L2_STD_PAL_I) {
-+		std  = std_map->atv_i.std_bits;
-+		sgIF = std_map->atv_i.if_freq;
-+		mode = "I";
-+	} else if (params->std & V4L2_STD_DK) {
-+		std  = std_map->atv_dk.std_bits;
-+		sgIF = std_map->atv_dk.if_freq;
-+		mode = "DK";
-+	} else if (params->std & V4L2_STD_SECAM_L) {
-+		std  = std_map->atv_l.std_bits;
-+		sgIF = std_map->atv_l.if_freq;
-+		mode = "L";
-+	} else if (params->std & V4L2_STD_SECAM_LC) {
-+		std  = std_map->atv_lc.std_bits;
-+		sgIF = std_map->atv_lc.if_freq;
-+		mode = "L'";
-+	} else {
-+		std  = std_map->atv_i.std_bits;
-+		sgIF = std_map->atv_i.if_freq;
-+		mode = "xx";
++	switch(params->u.vsb.modulation) {
++	case VSB_8:
++	case VSB_16:
++		dprintk(1, "%s() VSB modulation\n", __FUNCTION__);
++		priv->rf_mode = XC_RF_MODE_AIR;
++		priv->freq_hz = params->frequency - 1750000;
++		priv->bandwidth = BANDWIDTH_6_MHZ;
++		priv->video_standard = DTV6;
++		break;
++	case QAM_64:
++	case QAM_256:
++	case QAM_AUTO:
++		dprintk(1, "%s() QAM modulation\n", __FUNCTION__);
++		priv->rf_mode = XC_RF_MODE_CABLE;
++		priv->freq_hz = params->frequency - 1750000;
++		priv->bandwidth = BANDWIDTH_6_MHZ;
++		priv->video_standard = DTV6;
++		break;
++	default:
++		return -EINVAL;
 +	}
 +
-+	tda_dbg("setting tda18271 to system %s\n", mode);
++	dprintk(1, "%s() frequency=%d (compensated)\n",
++		__FUNCTION__, priv->freq_hz);
 +
-+	ret = tda18271_tune(fe, sgIF * 1000, freq, 0, std, radio);
++	ret = xc_SetSignalSource(priv, priv->rf_mode);
++	if (ret != XC_RESULT_SUCCESS) {
++		printk(KERN_ERR
++			"xc5000: xc_SetSignalSource(%d) failed\n",
++			priv->rf_mode);
++		return -EREMOTEIO;
++	}
 +
-+	if (ret < 0)
-+		goto fail;
++	ret = xc_SetTVStandard(priv,
++		XC5000_Standard[priv->video_standard].VideoMode,
++		XC5000_Standard[priv->video_standard].AudioMode);
++	if (ret != XC_RESULT_SUCCESS) {
++		printk(KERN_ERR "xc5000: xc_SetTVStandard failed\n");
++		return -EREMOTEIO;
++	}
 +
-+	priv->frequency = freq;
-+	priv->bandwidth = 0;
-+fail:
-+	return ret;
++	ret = xc_set_IF_frequency(priv, priv->cfg->if_khz);
++	if (ret != XC_RESULT_SUCCESS) {
++		printk(KERN_ERR "xc5000: xc_Set_IF_frequency(%d) failed\n",
++			priv->cfg->if_khz);
++		return -EIO;
++	}
++
++	xc_tune_channel(priv, priv->freq_hz);
++
++	if (debug)
++		xc_debug_dump(priv);
++
++	return 0;
 +}
 +
-+static int tda18271_sleep(struct dvb_frontend *fe)
++static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe);
++
++static int xc5000_set_analog_params(struct dvb_frontend *fe,
++	struct analog_parameters *params)
 +{
-+	struct tda18271_priv *priv = fe->tuner_priv;
++	struct xc5000_priv *priv = fe->tuner_priv;
++	int ret;
 +
-+	mutex_lock(&priv->lock);
++	if(priv->fwloaded == 0)
++		xc_load_fw_and_init_tuner(fe);
 +
-+	/* standby mode w/ slave tuner output
-+	 * & loop thru & xtal oscillator on */
-+	tda18271_set_standby_mode(fe, 1, 0, 0);
++	dprintk(1, "%s() frequency=%d (in units of 62.5khz)\n",
++		__FUNCTION__, params->frequency);
 +
-+	mutex_unlock(&priv->lock);
++	priv->rf_mode = XC_RF_MODE_CABLE; /* Fix me: it could be air. */
 +
-+	return 0;
-+}
++	/* params->frequency is in units of 62.5khz */
++	priv->freq_hz = params->frequency * 62500;
 +
-+static int tda18271_release(struct dvb_frontend *fe)
-+{
-+	struct tda18271_priv *priv = fe->tuner_priv;
++	/* FIX ME: Some video standards may have several possible audio
++		   standards. We simply default to one of them here.
++	 */
++	if(params->std & V4L2_STD_MN) {
++		/* default to BTSC audio standard */
++		priv->video_standard = MN_NTSC_PAL_BTSC;
++		goto tune_channel;
++	}
 +
-+	mutex_lock(&tda18271_list_mutex);
++	if(params->std & V4L2_STD_PAL_BG) {
++		/* default to NICAM audio standard */
++		priv->video_standard = BG_PAL_NICAM;
++		goto tune_channel;
++	}
 +
-+	priv->count--;
++	if(params->std & V4L2_STD_PAL_I) {
++		/* default to NICAM audio standard */
++		priv->video_standard = I_PAL_NICAM;
++		goto tune_channel;
++	}
 +
-+	if (!priv->count) {
-+		tda_dbg("destroying instance @ %d-%04x\n",
-+			i2c_adapter_id(priv->i2c_adap),
-+			priv->i2c_addr);
-+		list_del(&priv->tda18271_list);
++	if(params->std & V4L2_STD_PAL_DK) {
++		/* default to NICAM audio standard */
++		priv->video_standard = DK_PAL_NICAM;
++		goto tune_channel;
++	}
 +
-+		kfree(priv);
++	if(params->std & V4L2_STD_SECAM_DK) {
++		/* default to A2 DK1 audio standard */
++		priv->video_standard = DK_SECAM_A2DK1;
++		goto tune_channel;
 +	}
-+	mutex_unlock(&tda18271_list_mutex);
 +
-+	fe->tuner_priv = NULL;
++	if(params->std & V4L2_STD_SECAM_L) {
++		priv->video_standard = L_SECAM_NICAM;
++		goto tune_channel;
++	}
++
++	if(params->std & V4L2_STD_SECAM_LC) {
++		priv->video_standard = LC_SECAM_NICAM;
++		goto tune_channel;
++	}
++
++tune_channel:
++	ret = xc_SetSignalSource(priv, priv->rf_mode);
++	if (ret != XC_RESULT_SUCCESS) {
++	printk(KERN_ERR
++			"xc5000: xc_SetSignalSource(%d) failed\n",
++			priv->rf_mode);
++		return -EREMOTEIO;
++	}
++
++	ret = xc_SetTVStandard(priv,
++		XC5000_Standard[priv->video_standard].VideoMode,
++		XC5000_Standard[priv->video_standard].AudioMode);
++	if (ret != XC_RESULT_SUCCESS) {
++		printk(KERN_ERR "xc5000: xc_SetTVStandard failed\n");
++		return -EREMOTEIO;
++	}
++
++	xc_tune_channel(priv, priv->freq_hz);
++
++	if (debug)
++		xc_debug_dump(priv);
 +
 +	return 0;
 +}
 +
-+static int tda18271_get_frequency(struct dvb_frontend *fe, u32 *frequency)
++static int xc5000_get_frequency(struct dvb_frontend *fe, u32 *freq)
 +{
-+	struct tda18271_priv *priv = fe->tuner_priv;
-+	*frequency = priv->frequency;
++	struct xc5000_priv *priv = fe->tuner_priv;
++	dprintk(1, "%s()\n", __FUNCTION__);
++	*freq = priv->freq_hz;
 +	return 0;
 +}
 +
-+static int tda18271_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
++static int xc5000_get_bandwidth(struct dvb_frontend *fe, u32 *bw)
 +{
-+	struct tda18271_priv *priv = fe->tuner_priv;
-+	*bandwidth = priv->bandwidth;
++	struct xc5000_priv *priv = fe->tuner_priv;
++	dprintk(1, "%s()\n", __FUNCTION__);
++
++	*bw = priv->bandwidth;
 +	return 0;
 +}
 +
-+/* ------------------------------------------------------------------ */
-+
-+#define tda18271_update_std(std_cfg, name) do {				\
-+	if (map->std_cfg.if_freq + map->std_cfg.std_bits > 0) {		\
-+		tda_dbg("Using custom std config for %s\n", name);	\
-+		memcpy(&std->std_cfg, &map->std_cfg,			\
-+			sizeof(struct tda18271_std_map_item));		\
-+	} } while (0)
++static int xc5000_get_status(struct dvb_frontend *fe, u32 *status)
++{
++	struct xc5000_priv *priv = fe->tuner_priv;
++	u16 lock_status = 0;
 +
-+#define tda18271_dump_std_item(std_cfg, name) do {			\
-+	tda_dbg("(%s) if freq = %d, std bits = 0x%02x\n",		\
-+		name, std->std_cfg.if_freq, std->std_cfg.std_bits);	\
-+	} while (0)
++	xc_get_lock_status(priv, &lock_status);
 +
-+static int tda18271_dump_std_map(struct dvb_frontend *fe)
-+{
-+	struct tda18271_priv *priv = fe->tuner_priv;
-+	struct tda18271_std_map *std = &priv->std;
++	dprintk(1, "%s() lock_status = 0x%08x\n", __FUNCTION__, lock_status);
 +
-+	tda_dbg("========== STANDARD MAP SETTINGS ==========\n");
-+	tda18271_dump_std_item(fm_radio, "fm");
-+	tda18271_dump_std_item(atv_b,  "pal b");
-+	tda18271_dump_std_item(atv_dk, "pal dk");
-+	tda18271_dump_std_item(atv_gh, "pal gh");
-+	tda18271_dump_std_item(atv_i,  "pal i");
-+	tda18271_dump_std_item(atv_l,  "pal l");
-+	tda18271_dump_std_item(atv_lc, "pal l'");
-+	tda18271_dump_std_item(atv_mn, "atv mn");
-+	tda18271_dump_std_item(atsc_6, "atsc 6");
-+	tda18271_dump_std_item(dvbt_6, "dvbt 6");
-+	tda18271_dump_std_item(dvbt_7, "dvbt 7");
-+	tda18271_dump_std_item(dvbt_8, "dvbt 8");
-+	tda18271_dump_std_item(qam_6,  "qam 6");
-+	tda18271_dump_std_item(qam_8,  "qam 8");
++	*status = lock_status;
 +
 +	return 0;
 +}
 +
-+static int tda18271_update_std_map(struct dvb_frontend *fe,
-+				   struct tda18271_std_map *map)
++static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe)
 +{
-+	struct tda18271_priv *priv = fe->tuner_priv;
-+	struct tda18271_std_map *std = &priv->std;
++	struct xc5000_priv *priv = fe->tuner_priv;
++	int ret = 0;
 +
-+	if (!map)
-+		return -EINVAL;
++	if (priv->fwloaded == 0) {
++		ret = xc5000_fwupload(fe);
++		if (ret != XC_RESULT_SUCCESS)
++			return ret;
++		priv->fwloaded = 1;
++	}
 +
-+	tda18271_update_std(fm_radio, "fm");
-+	tda18271_update_std(atv_b,  "atv b");
-+	tda18271_update_std(atv_dk, "atv dk");
-+	tda18271_update_std(atv_gh, "atv gh");
-+	tda18271_update_std(atv_i,  "atv i");
-+	tda18271_update_std(atv_l,  "atv l");
-+	tda18271_update_std(atv_lc, "atv l'");
-+	tda18271_update_std(atv_mn, "atv mn");
-+	tda18271_update_std(atsc_6, "atsc 6");
-+	tda18271_update_std(dvbt_6, "dvbt 6");
-+	tda18271_update_std(dvbt_7, "dvbt 7");
-+	tda18271_update_std(dvbt_8, "dvbt 8");
-+	tda18271_update_std(qam_6,  "qam 6");
-+	tda18271_update_std(qam_8,  "qam 8");
++	/* Start the tuner self-calibration process */
++	ret |= xc_initialize(priv);
 +
-+	return 0;
++	/* Wait for calibration to complete.
++	 * We could continue but XC5000 will clock stretch subsequent
++	 * I2C transactions until calibration is complete.  This way we
++	 * don't have to rely on clock stretching working.
++	 */
++	xc_wait( 100 );
++
++	/* Default to "CABLE" mode */
++	ret |= xc_write_reg(priv, XREG_SIGNALSOURCE, XC_RF_MODE_CABLE);
++
++	return ret;
 +}
 +
-+static int tda18271_get_id(struct dvb_frontend *fe)
++static int xc5000_sleep(struct dvb_frontend *fe)
 +{
-+	struct tda18271_priv *priv = fe->tuner_priv;
-+	unsigned char *regs = priv->tda18271_regs;
-+	char *name;
-+	int ret = 0;
++	struct xc5000_priv *priv = fe->tuner_priv;
++	int ret;
 +
-+	mutex_lock(&priv->lock);
-+	tda18271_read_regs(fe);
-+	mutex_unlock(&priv->lock);
++	dprintk(1, "%s()\n", __FUNCTION__);
 +
-+	switch (regs[R_ID] & 0x7f) {
-+	case 3:
-+		name = "TDA18271HD/C1";
-+		priv->id = TDA18271HDC1;
-+		break;
-+	case 4:
-+		name = "TDA18271HD/C2";
-+		priv->id = TDA18271HDC2;
-+		break;
-+	default:
-+		name = "Unknown device";
-+		ret = -EINVAL;
-+		break;
++	/* On Pinnacle PCTV HD 800i, the tuner cannot be reinitialized
++	 * once shutdown without reloading the driver. Maybe I am not
++	 * doing something right.
++	 *
++	 */
++
++	ret = xc_shutdown(priv);
++	if(ret != XC_RESULT_SUCCESS) {
++		printk(KERN_ERR
++			"xc5000: %s() unable to shutdown tuner\n",
++			__FUNCTION__);
++		return -EREMOTEIO;
++	}
++	else {
++		/* priv->fwloaded = 0; */
++		return XC_RESULT_SUCCESS;
 +	}
++}
 +
-+	tda_info("%s detected @ %d-%04x%s\n", name,
-+		 i2c_adapter_id(priv->i2c_adap), priv->i2c_addr,
-+		 (0 == ret) ? "" : ", device not supported.");
++static int xc5000_init(struct dvb_frontend *fe)
++{
++	struct xc5000_priv *priv = fe->tuner_priv;
++	dprintk(1, "%s()\n", __FUNCTION__);
 +
-+	return ret;
++	if (xc_load_fw_and_init_tuner(fe) != XC_RESULT_SUCCESS) {
++		printk(KERN_ERR "xc5000: Unable to initialise tuner\n");
++		return -EREMOTEIO;
++	}
++
++	if (debug)
++		xc_debug_dump(priv);
++
++	return 0;
 +}
 +
-+static struct dvb_tuner_ops tda18271_tuner_ops = {
++static int xc5000_release(struct dvb_frontend *fe)
++{
++	dprintk(1, "%s()\n", __FUNCTION__);
++	kfree(fe->tuner_priv);
++	fe->tuner_priv = NULL;
++	return 0;
++}
++
++static const struct dvb_tuner_ops xc5000_tuner_ops = {
 +	.info = {
-+		.name = "NXP TDA18271HD",
-+		.frequency_min  =  45000000,
-+		.frequency_max  = 864000000,
-+		.frequency_step =     62500
++		.name           = "Xceive XC5000",
++		.frequency_min  =    1000000,
++		.frequency_max  = 1023000000,
++		.frequency_step =      50000,
 +	},
-+	.init              = tda18271_init,
-+	.sleep             = tda18271_sleep,
-+	.set_params        = tda18271_set_params,
-+	.set_analog_params = tda18271_set_analog_params,
-+	.release           = tda18271_release,
-+	.get_frequency     = tda18271_get_frequency,
-+	.get_bandwidth     = tda18271_get_bandwidth,
++
++	.release	   = xc5000_release,
++	.init		   = xc5000_init,
++	.sleep		   = xc5000_sleep,
++
++	.set_params	   = xc5000_set_params,
++	.set_analog_params = xc5000_set_analog_params,
++	.get_frequency	   = xc5000_get_frequency,
++	.get_bandwidth	   = xc5000_get_bandwidth,
++	.get_status	   = xc5000_get_status
 +};
 +
-+struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr,
-+				     struct i2c_adapter *i2c,
-+				     struct tda18271_config *cfg)
++struct dvb_frontend * xc5000_attach(struct dvb_frontend *fe,
++	struct i2c_adapter *i2c,
++	struct xc5000_config *cfg)
 +{
-+	struct tda18271_priv *priv = NULL;
-+	int state_found = 0;
-+
-+	mutex_lock(&tda18271_list_mutex);
++	struct xc5000_priv *priv = NULL;
++	u16 id = 0;
 +
-+	list_for_each_entry(priv, &tda18271_list, tda18271_list) {
-+		if ((i2c_adapter_id(priv->i2c_adap) == i2c_adapter_id(i2c)) &&
-+		    (priv->i2c_addr == addr)) {
-+			tda_dbg("attaching existing tuner @ %d-%04x\n",
-+				i2c_adapter_id(priv->i2c_adap),
-+				priv->i2c_addr);
-+			priv->count++;
-+			fe->tuner_priv = priv;
-+			state_found = 1;
-+			/* allow dvb driver to override i2c gate setting */
-+			if ((cfg) && (cfg->gate != TDA18271_GATE_ANALOG))
-+				priv->gate = cfg->gate;
-+			break;
-+		}
-+	}
-+	if (state_found == 0) {
-+		tda_dbg("creating new tuner instance @ %d-%04x\n",
-+			i2c_adapter_id(i2c), addr);
++	dprintk(1, "%s()\n", __FUNCTION__);
 +
-+		priv = kzalloc(sizeof(struct tda18271_priv), GFP_KERNEL);
-+		if (priv == NULL) {
-+			mutex_unlock(&tda18271_list_mutex);
-+			return NULL;
-+		}
++	priv = kzalloc(sizeof(struct xc5000_priv), GFP_KERNEL);
++	if (priv == NULL)
++		return NULL;
 +
-+		priv->i2c_addr = addr;
-+		priv->i2c_adap = i2c;
-+		priv->gate = (cfg) ? cfg->gate : TDA18271_GATE_AUTO;
-+		priv->cal_initialized = false;
-+		mutex_init(&priv->lock);
-+		priv->count++;
++	priv->cfg = cfg;
++	priv->bandwidth = BANDWIDTH_6_MHZ;
++	priv->i2c = i2c;
 +
-+		fe->tuner_priv = priv;
++	/* 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;
++	}
 +
-+		list_add_tail(&priv->tda18271_list, &tda18271_list);
++	switch(id) {
++	case XC_PRODUCT_ID_FW_LOADED:
++		printk(KERN_INFO
++			"xc5000: Successfully identified at address 0x%02x\n",
++			cfg->i2c_address);
++		printk(KERN_INFO
++			"xc5000: Firmware has been loaded previously\n");
++		priv->fwloaded = 1;
++		break;
++	case XC_PRODUCT_ID_FW_NOT_LOADED:
++		printk(KERN_INFO
++			"xc5000: Successfully identified at address 0x%02x\n",
++			cfg->i2c_address);
++		printk(KERN_INFO
++			"xc5000: Firmware has not been loaded previously\n");
++		priv->fwloaded = 0;
++		break;
++	default:
++		printk(KERN_ERR
++			"xc5000: Device not found at addr 0x%02x (0x%x)\n",
++			cfg->i2c_address, id);
++		kfree(priv);
++		return NULL;
++	}
 +
-+		if (tda18271_get_id(fe) < 0)
-+			goto fail;
++	memcpy(&fe->ops.tuner_ops, &xc5000_tuner_ops,
++		sizeof(struct dvb_tuner_ops));
 +
-+		if (tda18271_assign_map_layout(fe) < 0)
-+			goto fail;
++	fe->tuner_priv = priv;
 +
-+		mutex_lock(&priv->lock);
-+		tda18271_init_regs(fe);
++	return fe;
++}
++EXPORT_SYMBOL(xc5000_attach);
 +
-+		if ((tda18271_cal_on_startup) && (priv->id == TDA18271HDC2))
-+			tda18271_rf_cal_init(fe);
++MODULE_AUTHOR("Steven Toth");
++MODULE_DESCRIPTION("Xceive xc5000 silicon tuner driver");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/media/dvb/frontends/xc5000.h b/drivers/media/dvb/frontends/xc5000.h
+new file mode 100644
+index 0000000..e0e8456
+--- /dev/null
++++ b/drivers/media/dvb/frontends/xc5000.h
+@@ -0,0 +1,62 @@
++/*
++ *  Driver for Xceive XC5000 "QAM/8VSB single chip tuner"
++ *
++ *  Copyright (c) 2007 Steven Toth <stoth at hauppauge.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.
++ */
 +
-+		mutex_unlock(&priv->lock);
-+	}
++#ifndef __XC5000_H__
++#define __XC5000_H__
 +
-+	/* override default std map with values in config struct */
-+	if ((cfg) && (cfg->std_map))
-+		tda18271_update_std_map(fe, cfg->std_map);
++#include <linux/firmware.h>
 +
-+	mutex_unlock(&tda18271_list_mutex);
++struct dvb_frontend;
++struct i2c_adapter;
 +
-+	memcpy(&fe->ops.tuner_ops, &tda18271_tuner_ops,
-+	       sizeof(struct dvb_tuner_ops));
++struct xc5000_config {
++	u8   i2c_address;
++	u32  if_khz;
 +
-+	if (tda18271_debug & DBG_MAP)
-+		tda18271_dump_std_map(fe);
++	/* For each bridge framework, when it attaches either analog or digital,
++	 * it has to store a reference back to its _core equivalent structure,
++	 * so that it can service the hardware by steering gpio's etc.
++	 * Each bridge implementation is different so cast priv accordingly.
++	 * The xc5000 driver cares not for this value, other than ensuring
++	 * it's passed back to a bridge during tuner_callback().
++	 */
++	void *priv;
++	int  (*tuner_callback) (void *priv, int command, int arg);
++};
 +
-+	return fe;
-+fail:
-+	mutex_unlock(&tda18271_list_mutex);
++/* xc5000 callback command */
++#define XC5000_TUNER_RESET		0
 +
-+	tda18271_release(fe);
++#if defined(CONFIG_DVB_TUNER_XC5000) || defined(CONFIG_DVB_TUNER_XC5000_MODULE)
++extern struct dvb_frontend* xc5000_attach(struct dvb_frontend *fe,
++					  struct i2c_adapter *i2c,
++					  struct xc5000_config *cfg);
++#else
++static inline struct dvb_frontend* xc5000_attach(struct dvb_frontend *fe,
++						 struct i2c_adapter *i2c,
++						 struct xc5000_config *cfg)
++{
++	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
 +	return NULL;
 +}
-+EXPORT_SYMBOL_GPL(tda18271_attach);
-+MODULE_DESCRIPTION("NXP TDA18271HD analog / digital tuner driver");
-+MODULE_AUTHOR("Michael Krufky <mkrufky at linuxtv.org>");
-+MODULE_LICENSE("GPL");
-+MODULE_VERSION("0.2");
++#endif // CONFIG_DVB_TUNER_XC5000
 +
-+/*
-+ * Overrides for Emacs so that we follow Linus's tabbing style.
-+ * ---------------------------------------------------------------------------
-+ * Local variables:
-+ * c-basic-offset: 8
-+ * End:
-+ */
-diff --git a/drivers/media/dvb/frontends/tda18271-priv.h b/drivers/media/dvb/frontends/tda18271-priv.h
++#endif // __XC5000_H__
+diff --git a/drivers/media/dvb/frontends/xc5000_priv.h b/drivers/media/dvb/frontends/xc5000_priv.h
 new file mode 100644
-index 0000000..7b939a5
+index 0000000..13b2d19
 --- /dev/null
-+++ b/drivers/media/dvb/frontends/tda18271-priv.h
-@@ -0,0 +1,212 @@
++++ b/drivers/media/dvb/frontends/xc5000_priv.h
+@@ -0,0 +1,36 @@
 +/*
-+    tda18271-priv.h - private header for the NXP TDA18271 silicon tuner
++ *  Driver for Xceive XC5000 "QAM/8VSB single chip tuner"
++ *
++ *  Copyright (c) 2007 Steven Toth <stoth at hauppauge.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.
++ */
 +
-+    Copyright (C) 2007, 2008 Michael Krufky <mkrufky at linuxtv.org>
++#ifndef XC5000_PRIV_H
++#define XC5000_PRIV_H
 +
-+    This program is free software; you can redistribute it and/or modify
-+    it under the terms of the GNU General Public License as published by
-+    the Free Software Foundation; either version 2 of the License, or
-+    (at your option) any later version.
++struct xc5000_priv {
++	struct xc5000_config *cfg;
++	struct i2c_adapter   *i2c;
 +
-+    This program is distributed in the hope that it will be useful,
-+    but WITHOUT ANY WARRANTY; without even the implied warranty of
-+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+    GNU General Public License for more details.
++	u32 freq_hz;
++	u32 bandwidth;
++	u8  video_standard;
++	u8  rf_mode;
++	u8  fwloaded;
++};
 +
-+    You 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.
-+*/
++#endif
+diff --git a/drivers/media/dvb/frontends/zl10353.c b/drivers/media/dvb/frontends/zl10353.c
+index 0106df4..276e3b6 100644
+--- a/drivers/media/dvb/frontends/zl10353.c
++++ b/drivers/media/dvb/frontends/zl10353.c
+@@ -1,7 +1,7 @@
+ /*
+  * Driver for Zarlink DVB-T ZL10353 demodulator
+  *
+- * Copyright (C) 2006 Christopher Pascoe <c.pascoe at itee.uq.edu.au>
++ * Copyright (C) 2006, 2007 Christopher Pascoe <c.pascoe at itee.uq.edu.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
+@@ -16,7 +16,7 @@
+  *
+  * You 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.=
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+  */
+ 
+ #include <linux/kernel.h>
+@@ -25,6 +25,7 @@
+ #include <linux/delay.h>
+ #include <linux/string.h>
+ #include <linux/slab.h>
++#include <asm/div64.h>
+ 
+ #include "dvb_frontend.h"
+ #include "zl10353_priv.h"
+@@ -35,6 +36,8 @@ struct zl10353_state {
+ 	struct dvb_frontend frontend;
+ 
+ 	struct zl10353_config config;
 +
-+#ifndef __TDA18271_PRIV_H__
-+#define __TDA18271_PRIV_H__
++	enum fe_bandwidth bandwidth;
+ };
+ 
+ static int debug;
+@@ -122,9 +125,10 @@ static void zl10353_calc_nominal_rate(struct dvb_frontend *fe,
+ 				      enum fe_bandwidth bandwidth,
+ 				      u16 *nominal_rate)
+ {
+-	u32 adc_clock = 45056; /* 45.056 MHz */
+-	u8 bw;
+ 	struct zl10353_state *state = fe->demodulator_priv;
++	u32 adc_clock = 450560; /* 45.056 MHz */
++	u64 value;
++	u8 bw;
+ 
+ 	if (state->config.adc_clock)
+ 		adc_clock = state->config.adc_clock;
+@@ -142,12 +146,44 @@ static void zl10353_calc_nominal_rate(struct dvb_frontend *fe,
+ 		break;
+ 	}
+ 
+-	*nominal_rate = (bw * (1 << 23) / 7 * 125 + adc_clock / 2) / adc_clock;
++	value = (u64)10 * (1 << 23) / 7 * 125;
++	value = (bw * value) + adc_clock / 2;
++	do_div(value, adc_clock);
++	*nominal_rate = value;
+ 
+ 	dprintk("%s: bw %d, adc_clock %d => 0x%x\n",
+ 		__FUNCTION__, bw, adc_clock, *nominal_rate);
+ }
+ 
++static void zl10353_calc_input_freq(struct dvb_frontend *fe,
++				    u16 *input_freq)
++{
++	struct zl10353_state *state = fe->demodulator_priv;
++	u32 adc_clock = 450560;	/* 45.056  MHz */
++	int if2 = 361667;	/* 36.1667 MHz */
++	int ife;
++	u64 value;
 +
-+#include <linux/kernel.h>
-+#include <linux/types.h>
-+#include <linux/mutex.h>
-+#include "tda18271.h"
++	if (state->config.adc_clock)
++		adc_clock = state->config.adc_clock;
++	if (state->config.if2)
++		if2 = state->config.if2;
 +
-+#define R_ID     0x00	/* ID byte                */
-+#define R_TM     0x01	/* Thermo byte            */
-+#define R_PL     0x02	/* Power level byte       */
-+#define R_EP1    0x03	/* Easy Prog byte 1       */
-+#define R_EP2    0x04	/* Easy Prog byte 2       */
-+#define R_EP3    0x05	/* Easy Prog byte 3       */
-+#define R_EP4    0x06	/* Easy Prog byte 4       */
-+#define R_EP5    0x07	/* Easy Prog byte 5       */
-+#define R_CPD    0x08	/* Cal Post-Divider byte  */
-+#define R_CD1    0x09	/* Cal Divider byte 1     */
-+#define R_CD2    0x0a	/* Cal Divider byte 2     */
-+#define R_CD3    0x0b	/* Cal Divider byte 3     */
-+#define R_MPD    0x0c	/* Main Post-Divider byte */
-+#define R_MD1    0x0d	/* Main Divider byte 1    */
-+#define R_MD2    0x0e	/* Main Divider byte 2    */
-+#define R_MD3    0x0f	/* Main Divider byte 3    */
-+#define R_EB1    0x10	/* Extended byte 1        */
-+#define R_EB2    0x11	/* Extended byte 2        */
-+#define R_EB3    0x12	/* Extended byte 3        */
-+#define R_EB4    0x13	/* Extended byte 4        */
-+#define R_EB5    0x14	/* Extended byte 5        */
-+#define R_EB6    0x15	/* Extended byte 6        */
-+#define R_EB7    0x16	/* Extended byte 7        */
-+#define R_EB8    0x17	/* Extended byte 8        */
-+#define R_EB9    0x18	/* Extended byte 9        */
-+#define R_EB10   0x19	/* Extended byte 10       */
-+#define R_EB11   0x1a	/* Extended byte 11       */
-+#define R_EB12   0x1b	/* Extended byte 12       */
-+#define R_EB13   0x1c	/* Extended byte 13       */
-+#define R_EB14   0x1d	/* Extended byte 14       */
-+#define R_EB15   0x1e	/* Extended byte 15       */
-+#define R_EB16   0x1f	/* Extended byte 16       */
-+#define R_EB17   0x20	/* Extended byte 17       */
-+#define R_EB18   0x21	/* Extended byte 18       */
-+#define R_EB19   0x22	/* Extended byte 19       */
-+#define R_EB20   0x23	/* Extended byte 20       */
-+#define R_EB21   0x24	/* Extended byte 21       */
-+#define R_EB22   0x25	/* Extended byte 22       */
-+#define R_EB23   0x26	/* Extended byte 23       */
++	if (adc_clock >= if2 * 2)
++		ife = if2;
++	else {
++		ife = adc_clock - (if2 % adc_clock);
++		if (ife > adc_clock / 2)
++			ife = adc_clock - ife;
++	}
++	value = (u64)65536 * ife + adc_clock / 2;
++	do_div(value, adc_clock);
++	*input_freq = -value;
 +
-+#define TDA18271_NUM_REGS 39
++	dprintk("%s: if2 %d, ife %d, adc_clock %d => %d / 0x%x\n",
++		__FUNCTION__, if2, ife, adc_clock, -(int)value, *input_freq);
++}
 +
-+/*---------------------------------------------------------------------*/
+ static int zl10353_sleep(struct dvb_frontend *fe)
+ {
+ 	static u8 zl10353_softdown[] = { 0x50, 0x0C, 0x44 };
+@@ -160,64 +196,276 @@ static int zl10353_set_parameters(struct dvb_frontend *fe,
+ 				  struct dvb_frontend_parameters *param)
+ {
+ 	struct zl10353_state *state = fe->demodulator_priv;
+-	u16 nominal_rate;
+-	u8 pllbuf[6] = { 0x67 };
++	u16 nominal_rate, input_freq;
++	u8 pllbuf[6] = { 0x67 }, acq_ctl = 0;
++	u16 tps = 0;
++	struct dvb_ofdm_parameters *op = &param->u.ofdm;
+ 
+-	/* These settings set "auto-everything" and start the FSM. */
+-	zl10353_single_write(fe, 0x55, 0x80);
++	zl10353_single_write(fe, RESET, 0x80);
+ 	udelay(200);
+ 	zl10353_single_write(fe, 0xEA, 0x01);
+ 	udelay(200);
+ 	zl10353_single_write(fe, 0xEA, 0x00);
+ 
+-	zl10353_single_write(fe, 0x56, 0x28);
+-	zl10353_single_write(fe, 0x89, 0x20);
+-	zl10353_single_write(fe, 0x5E, 0x00);
++	zl10353_single_write(fe, AGC_TARGET, 0x28);
 +
-+struct tda18271_rf_tracking_filter_cal {
-+	u32 rfmax;
-+	u8  rfband;
-+	u32 rf1_def;
-+	u32 rf2_def;
-+	u32 rf3_def;
-+	u32 rf1;
-+	u32 rf2;
-+	u32 rf3;
-+	int rf_a1;
-+	int rf_b1;
-+	int rf_a2;
-+	int rf_b2;
-+};
++	if (op->transmission_mode != TRANSMISSION_MODE_AUTO)
++		acq_ctl |= (1 << 0);
++	if (op->guard_interval != GUARD_INTERVAL_AUTO)
++		acq_ctl |= (1 << 1);
++	zl10353_single_write(fe, ACQ_CTL, acq_ctl);
+ 
+-	zl10353_calc_nominal_rate(fe, param->u.ofdm.bandwidth, &nominal_rate);
++	switch (op->bandwidth) {
++	case BANDWIDTH_6_MHZ:
++		/* These are extrapolated from the 7 and 8MHz values */
++		zl10353_single_write(fe, MCLK_RATIO, 0x97);
++		zl10353_single_write(fe, 0x64, 0x34);
++		break;
++	case BANDWIDTH_7_MHZ:
++		zl10353_single_write(fe, MCLK_RATIO, 0x86);
++		zl10353_single_write(fe, 0x64, 0x35);
++		break;
++	case BANDWIDTH_8_MHZ:
++	default:
++		zl10353_single_write(fe, MCLK_RATIO, 0x75);
++		zl10353_single_write(fe, 0x64, 0x36);
++	}
 +
-+enum tda18271_mode {
-+	TDA18271_ANALOG,
-+	TDA18271_DIGITAL,
-+};
++	zl10353_calc_nominal_rate(fe, op->bandwidth, &nominal_rate);
+ 	zl10353_single_write(fe, TRL_NOMINAL_RATE_1, msb(nominal_rate));
+ 	zl10353_single_write(fe, TRL_NOMINAL_RATE_0, lsb(nominal_rate));
++	state->bandwidth = op->bandwidth;
 +
-+struct tda18271_map_layout;
++	zl10353_calc_input_freq(fe, &input_freq);
++	zl10353_single_write(fe, INPUT_FREQ_1, msb(input_freq));
++	zl10353_single_write(fe, INPUT_FREQ_0, lsb(input_freq));
 +
-+enum tda18271_ver {
-+	TDA18271HDC1,
-+	TDA18271HDC2,
-+};
++	/* Hint at TPS settings */
++	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:
++		break;
++	default:
++		return -EINVAL;
++	}
 +
-+struct tda18271_priv {
-+	u8 i2c_addr;
-+	struct i2c_adapter *i2c_adap;
-+	unsigned char tda18271_regs[TDA18271_NUM_REGS];
++	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:
++		break;
++	case FEC_NONE:
++		if (op->hierarchy_information == HIERARCHY_AUTO ||
++		    op->hierarchy_information == HIERARCHY_NONE)
++			break;
++	default:
++		return -EINVAL;
++	}
 +
-+	struct list_head tda18271_list;
++	switch (op->constellation) {
++	case QPSK:
++		break;
++	case QAM_AUTO:
++	case QAM_16:
++		tps |= (1 << 13);
++		break;
++	case QAM_64:
++		tps |= (2 << 13);
++		break;
++	default:
++		return -EINVAL;
++	}
 +
-+	enum tda18271_mode mode;
-+	enum tda18271_i2c_gate gate;
-+	enum tda18271_ver id;
++	switch (op->transmission_mode) {
++	case TRANSMISSION_MODE_2K:
++	case TRANSMISSION_MODE_AUTO:
++		break;
++	case TRANSMISSION_MODE_8K:
++		tps |= (1 << 0);
++		break;
++	default:
++		return -EINVAL;
++	}
 +
-+	unsigned int count;
-+	unsigned int tm_rfcal;
-+	unsigned int cal_initialized:1;
++	switch (op->guard_interval) {
++	case GUARD_INTERVAL_1_32:
++	case GUARD_INTERVAL_AUTO:
++		break;
++	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;
++	default:
++		return -EINVAL;
++	}
++
++	switch (op->hierarchy_information) {
++	case HIERARCHY_AUTO:
++	case HIERARCHY_NONE:
++		break;
++	case HIERARCHY_1:
++		tps |= (1 << 10);
++		break;
++	case HIERARCHY_2:
++		tps |= (2 << 10);
++		break;
++	case HIERARCHY_4:
++		tps |= (3 << 10);
++		break;
++	default:
++		return -EINVAL;
++	}
++
++	zl10353_single_write(fe, TPS_GIVEN_1, msb(tps));
++	zl10353_single_write(fe, TPS_GIVEN_0, lsb(tps));
+ 
+-	zl10353_single_write(fe, 0x6C, 0xCD);
+-	zl10353_single_write(fe, 0x6D, 0x7E);
+ 	if (fe->ops.i2c_gate_ctrl)
+ 		fe->ops.i2c_gate_ctrl(fe, 0);
+ 
+-	// if there is no attached secondary tuner, we call set_params to program
+-	// a potential tuner attached somewhere else
++	/*
++	 * If there is no tuner attached to the secondary I2C bus, we call
++	 * set_params to program a potential tuner attached somewhere else.
++	 * Otherwise, we update the PLL registers via calc_regs.
++	 */
+ 	if (state->config.no_tuner) {
+ 		if (fe->ops.tuner_ops.set_params) {
+ 			fe->ops.tuner_ops.set_params(fe, param);
+ 			if (fe->ops.i2c_gate_ctrl)
+ 				fe->ops.i2c_gate_ctrl(fe, 0);
+ 		}
++	} else if (fe->ops.tuner_ops.calc_regs) {
++		fe->ops.tuner_ops.calc_regs(fe, param, pllbuf + 1, 5);
++		pllbuf[1] <<= 1;
++		zl10353_write(fe, pllbuf, sizeof(pllbuf));
+ 	}
+ 
+-	// if pllbuf is defined, retrieve the settings
+-	if (fe->ops.tuner_ops.calc_regs) {
+-		fe->ops.tuner_ops.calc_regs(fe, param, pllbuf+1, 5);
+-		pllbuf[1] <<= 1;
+-	} else {
+-		// fake pllbuf settings
+-		pllbuf[1] = 0x61 << 1;
+-		pllbuf[2] = 0;
+-		pllbuf[3] = 0;
+-		pllbuf[3] = 0;
+-		pllbuf[4] = 0;
++	zl10353_single_write(fe, 0x5F, 0x13);
++
++	/* If no attached tuner or invalid PLL registers, just start the FSM. */
++	if (state->config.no_tuner || fe->ops.tuner_ops.calc_regs == NULL)
++		zl10353_single_write(fe, FSM_GO, 0x01);
++	else
++		zl10353_single_write(fe, TUNER_GO, 0x01);
++
++	return 0;
++}
++
++static int zl10353_get_parameters(struct dvb_frontend *fe,
++				  struct dvb_frontend_parameters *param)
++{
++	struct zl10353_state *state = fe->demodulator_priv;
++	struct dvb_ofdm_parameters *op = &param->u.ofdm;
++	int s6, s9;
++	u16 tps;
++	static const u8 tps_fec_to_api[8] = {
++		FEC_1_2,
++		FEC_2_3,
++		FEC_3_4,
++		FEC_5_6,
++		FEC_7_8,
++		FEC_AUTO,
++		FEC_AUTO,
++		FEC_AUTO
++	};
 +
-+	struct tda18271_map_layout *maps;
-+	struct tda18271_std_map std;
-+	struct tda18271_rf_tracking_filter_cal rf_cal_state[8];
++	s6 = zl10353_read_register(state, STATUS_6);
++	s9 = zl10353_read_register(state, STATUS_9);
++	if (s6 < 0 || s9 < 0)
++		return -EREMOTEIO;
++	if ((s6 & (1 << 5)) == 0 || (s9 & (1 << 4)) == 0)
++		return -EINVAL;	/* no FE or TPS lock */
 +
-+	struct mutex lock;
++	tps = zl10353_read_register(state, TPS_RECEIVED_1) << 8 |
++	      zl10353_read_register(state, TPS_RECEIVED_0);
 +
-+	u32 frequency;
-+	u32 bandwidth;
-+};
++	op->code_rate_HP = tps_fec_to_api[(tps >> 7) & 7];
++	op->code_rate_LP = tps_fec_to_api[(tps >> 4) & 7];
 +
-+/*---------------------------------------------------------------------*/
++	switch ((tps >> 13) & 3) {
++	case 0:
++		op->constellation = QPSK;
++		break;
++	case 1:
++		op->constellation = QAM_16;
++		break;
++	case 2:
++		op->constellation = QAM_64;
++		break;
++	default:
++		op->constellation = QAM_AUTO;
++		break;
+ 	}
+ 
+-	// there is no call to _just_ start decoding, so we send the pllbuf anyway
+-	// even if there isn't a PLL attached to the secondary bus
+-	zl10353_write(fe, pllbuf, sizeof(pllbuf));
++	op->transmission_mode = (tps & 0x01) ? TRANSMISSION_MODE_8K :
++					       TRANSMISSION_MODE_2K;
+ 
+-	zl10353_single_write(fe, 0x5F, 0x13);
+-	zl10353_single_write(fe, 0x70, 0x01);
+-	udelay(250);
+-	zl10353_single_write(fe, 0xE4, 0x00);
+-	zl10353_single_write(fe, 0xE5, 0x2A);
+-	zl10353_single_write(fe, 0xE9, 0x02);
+-	zl10353_single_write(fe, 0xE7, 0x40);
+-	zl10353_single_write(fe, 0xE8, 0x10);
++	switch ((tps >> 2) & 3) {
++	case 0:
++		op->guard_interval = GUARD_INTERVAL_1_32;
++		break;
++	case 1:
++		op->guard_interval = GUARD_INTERVAL_1_16;
++		break;
++	case 2:
++		op->guard_interval = GUARD_INTERVAL_1_8;
++		break;
++	case 3:
++		op->guard_interval = GUARD_INTERVAL_1_4;
++		break;
++	default:
++		op->guard_interval = GUARD_INTERVAL_AUTO;
++		break;
++	}
 +
-+extern int tda18271_debug;
++	switch ((tps >> 10) & 7) {
++	case 0:
++		op->hierarchy_information = HIERARCHY_NONE;
++		break;
++	case 1:
++		op->hierarchy_information = HIERARCHY_1;
++		break;
++	case 2:
++		op->hierarchy_information = HIERARCHY_2;
++		break;
++	case 3:
++		op->hierarchy_information = HIERARCHY_4;
++		break;
++	default:
++		op->hierarchy_information = HIERARCHY_AUTO;
++		break;
++	}
 +
-+#define DBG_INFO 1
-+#define DBG_MAP  2
-+#define DBG_REG  4
-+#define DBG_ADV  8
-+#define DBG_CAL  16
++	param->frequency = 0;
++	op->bandwidth = state->bandwidth;
++	param->inversion = INVERSION_AUTO;
+ 
+ 	return 0;
+ }
+@@ -406,6 +654,7 @@ static struct dvb_frontend_ops zl10353_ops = {
+ 	.write = zl10353_write,
+ 
+ 	.set_frontend = zl10353_set_parameters,
++	.get_frontend = zl10353_get_parameters,
+ 	.get_tune_settings = zl10353_get_tune_settings,
+ 
+ 	.read_status = zl10353_read_status,
+diff --git a/drivers/media/dvb/frontends/zl10353.h b/drivers/media/dvb/frontends/zl10353.h
+index 1c3d494..fc734c2 100644
+--- a/drivers/media/dvb/frontends/zl10353.h
++++ b/drivers/media/dvb/frontends/zl10353.h
+@@ -1,7 +1,7 @@
+ /*
+  *  Driver for Zarlink DVB-T ZL10353 demodulator
+  *
+- *  Copyright (C) 2006 Christopher Pascoe <c.pascoe at itee.uq.edu.au>
++ *  Copyright (C) 2006, 2007 Christopher Pascoe <c.pascoe at itee.uq.edu.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
+@@ -29,8 +29,9 @@ struct zl10353_config
+ 	/* demodulator's I2C address */
+ 	u8 demod_address;
+ 
+-	/* frequencies in kHz */
+-	int adc_clock;	/* default: 45056 */
++	/* frequencies in units of 0.1kHz */
++	int adc_clock;	/* default: 450560 (45.056  MHz) */
++	int if2;	/* default: 361667 (36.1667 MHz) */
+ 
+ 	/* set if no pll is connected to the secondary i2c bus */
+ 	int no_tuner;
+@@ -49,6 +50,6 @@ static inline struct dvb_frontend* zl10353_attach(const struct zl10353_config *c
+ 	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+ 	return NULL;
+ }
+-#endif // CONFIG_DVB_ZL10353
++#endif /* CONFIG_DVB_ZL10353 */
+ 
+ #endif /* ZL10353_H */
+diff --git a/drivers/media/dvb/frontends/zl10353_priv.h b/drivers/media/dvb/frontends/zl10353_priv.h
+index 4962434..055ff1f 100644
+--- a/drivers/media/dvb/frontends/zl10353_priv.h
++++ b/drivers/media/dvb/frontends/zl10353_priv.h
+@@ -1,7 +1,7 @@
+ /*
+  *  Driver for Zarlink DVB-T ZL10353 demodulator
+  *
+- *  Copyright (C) 2006 Christopher Pascoe <c.pascoe at itee.uq.edu.au>
++ *  Copyright (C) 2006, 2007 Christopher Pascoe <c.pascoe at itee.uq.edu.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
+@@ -16,7 +16,7 @@
+  *
+  *  You 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.=
++ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+  */
+ 
+ #ifndef _ZL10353_PRIV_
+@@ -46,9 +46,28 @@ enum zl10353_reg_addr {
+ 	RS_ERR_CNT_0       = 0x13,
+ 	RS_UBC_1           = 0x14,
+ 	RS_UBC_0           = 0x15,
++	TPS_RECEIVED_1     = 0x1D,
++	TPS_RECEIVED_0     = 0x1E,
++	TPS_CURRENT_1      = 0x1F,
++	TPS_CURRENT_0      = 0x20,
++	RESET              = 0x55,
++	AGC_TARGET         = 0x56,
++	MCLK_RATIO         = 0x5C,
++	ACQ_CTL            = 0x5E,
+ 	TRL_NOMINAL_RATE_1 = 0x65,
+ 	TRL_NOMINAL_RATE_0 = 0x66,
++	INPUT_FREQ_1       = 0x6C,
++	INPUT_FREQ_0       = 0x6D,
++	TPS_GIVEN_1        = 0x6E,
++	TPS_GIVEN_0        = 0x6F,
++	TUNER_GO           = 0x70,
++	FSM_GO             = 0x71,
+ 	CHIP_ID            = 0x7F,
++	CHAN_STEP_1        = 0xE4,
++	CHAN_STEP_0        = 0xE5,
++	OFDM_LOCK_TIME     = 0xE7,
++	FEC_LOCK_TIME      = 0xE8,
++	ACQ_DELAY          = 0xE9,
+ };
+ 
+ #endif                          /* _ZL10353_PRIV_ */
+diff --git a/drivers/media/dvb/ttpci/Kconfig b/drivers/media/dvb/ttpci/Kconfig
+index 54b91f2..ae88243 100644
+--- a/drivers/media/dvb/ttpci/Kconfig
++++ b/drivers/media/dvb/ttpci/Kconfig
+@@ -1,8 +1,14 @@
++config TTPCI_EEPROM
++	tristate
++	default n
 +
-+#define tda_printk(kern, fmt, arg...) \
-+	printk(kern "%s: " fmt, __FUNCTION__, ##arg)
+ config DVB_AV7110
+ 	tristate "AV7110 cards"
+-	depends on DVB_CORE && PCI && I2C && VIDEO_V4L1
++	depends on DVB_CORE && PCI && I2C
+ 	select FW_LOADER if !DVB_AV7110_FIRMWARE
++	select TTPCI_EEPROM
+ 	select VIDEO_SAA7146_VV
++	depends on VIDEO_DEV	# dependencies of VIDEO_SAA7146_VV
+ 	select DVB_VES1820 if !DVB_FE_CUSTOMISE
+ 	select DVB_VES1X93 if !DVB_FE_CUSTOMISE
+ 	select DVB_STV0299 if !DVB_FE_CUSTOMISE
+@@ -57,10 +63,19 @@ config DVB_AV7110_OSD
+ 
+ 	  All other people say N.
+ 
++config DVB_BUDGET_CORE
++	tristate "SAA7146 DVB cards (aka Budget, Nova-PCI)"
++	depends on DVB_CORE && PCI && I2C
++	select VIDEO_SAA7146
++	select TTPCI_EEPROM
++	help
++	  Support for simple SAA7146 based DVB cards
++	  (so called Budget- or Nova-PCI cards) without onboard
++	  MPEG2 decoder.
 +
-+#define dprintk(kern, lvl, fmt, arg...) do {\
-+	if (tda18271_debug & lvl) \
-+		tda_printk(kern, fmt, ##arg); } while (0)
+ config DVB_BUDGET
+ 	tristate "Budget cards"
+-	depends on DVB_CORE && PCI && I2C && VIDEO_V4L1
+-	select VIDEO_SAA7146
++	depends on DVB_BUDGET_CORE && I2C
+ 	select DVB_STV0299 if !DVB_FE_CUSTOMISE
+ 	select DVB_VES1X93 if !DVB_FE_CUSTOMISE
+ 	select DVB_VES1820 if !DVB_FE_CUSTOMISE
+@@ -73,9 +88,9 @@ config DVB_BUDGET
+ 	select DVB_TDA826X if !DVB_FE_CUSTOMISE
+ 	select DVB_LNBP21 if !DVB_FE_CUSTOMISE
+ 	help
+-	  Support for simple SAA7146 based DVB cards
+-	  (so called Budget- or Nova-PCI cards) without onboard
+-	  MPEG2 decoder.
++	  Support for simple SAA7146 based DVB cards (so called Budget-
++	  or Nova-PCI cards) without onboard MPEG2 decoder, and without
++	  analog inputs or an onboard Common Interface connector.
+ 
+ 	  Say Y if you own such a card and want to use it.
+ 
+@@ -84,8 +99,7 @@ config DVB_BUDGET
+ 
+ config DVB_BUDGET_CI
+ 	tristate "Budget cards with onboard CI connector"
+-	depends on DVB_CORE && PCI && I2C && VIDEO_V4L1 && INPUT
+-	select VIDEO_SAA7146
++	depends on DVB_BUDGET_CORE && I2C
+ 	select DVB_STV0297 if !DVB_FE_CUSTOMISE
+ 	select DVB_STV0299 if !DVB_FE_CUSTOMISE
+ 	select DVB_TDA1004X if !DVB_FE_CUSTOMISE
+@@ -106,8 +120,9 @@ config DVB_BUDGET_CI
+ 
+ config DVB_BUDGET_AV
+ 	tristate "Budget cards with analog video inputs"
+-	depends on DVB_CORE && PCI && I2C && VIDEO_V4L1
++	depends on DVB_BUDGET_CORE && I2C
+ 	select VIDEO_SAA7146_VV
++	depends on VIDEO_DEV	# dependencies of VIDEO_SAA7146_VV
+ 	select DVB_PLL if !DVB_FE_CUSTOMISE
+ 	select DVB_STV0299 if !DVB_FE_CUSTOMISE
+ 	select DVB_TDA1004X if !DVB_FE_CUSTOMISE
+@@ -127,8 +142,8 @@ config DVB_BUDGET_AV
+ 
+ config DVB_BUDGET_PATCH
+ 	tristate "AV7110 cards with Budget Patch"
+-	depends on DVB_CORE && DVB_BUDGET && VIDEO_V4L1
+-	select DVB_AV7110
++	depends on DVB_BUDGET_CORE && I2C
++	depends on DVB_AV7110
+ 	select DVB_STV0299 if !DVB_FE_CUSTOMISE
+ 	select DVB_VES1X93 if !DVB_FE_CUSTOMISE
+ 	select DVB_TDA8083 if !DVB_FE_CUSTOMISE
+diff --git a/drivers/media/dvb/ttpci/Makefile b/drivers/media/dvb/ttpci/Makefile
+index 2c11452..d7483f1 100644
+--- a/drivers/media/dvb/ttpci/Makefile
++++ b/drivers/media/dvb/ttpci/Makefile
+@@ -5,11 +5,13 @@
+ 
+ dvb-ttpci-objs := av7110_hw.o av7110_v4l.o av7110_av.o av7110_ca.o av7110.o av7110_ipack.o av7110_ir.o
+ 
+-obj-$(CONFIG_DVB_BUDGET) += budget-core.o budget.o ttpci-eeprom.o
+-obj-$(CONFIG_DVB_BUDGET_AV) += budget-core.o budget-av.o ttpci-eeprom.o
+-obj-$(CONFIG_DVB_BUDGET_CI) += budget-core.o budget-ci.o ttpci-eeprom.o
+-obj-$(CONFIG_DVB_BUDGET_PATCH) += budget-core.o budget-patch.o ttpci-eeprom.o
+-obj-$(CONFIG_DVB_AV7110) += dvb-ttpci.o ttpci-eeprom.o
++obj-$(CONFIG_TTPCI_EEPROM) += ttpci-eeprom.o
++obj-$(CONFIG_DVB_BUDGET_CORE) += budget-core.o
++obj-$(CONFIG_DVB_BUDGET) += budget.o
++obj-$(CONFIG_DVB_BUDGET_AV) += budget-av.o
++obj-$(CONFIG_DVB_BUDGET_CI) += budget-ci.o
++obj-$(CONFIG_DVB_BUDGET_PATCH) += budget-patch.o
++obj-$(CONFIG_DVB_AV7110) += dvb-ttpci.o
+ 
+ EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
+ 
+diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c
+index 0d36c15..0e5701b 100644
+--- a/drivers/media/dvb/ttpci/av7110.c
++++ b/drivers/media/dvb/ttpci/av7110.c
+@@ -2595,7 +2595,8 @@ static int __devinit av7110_attach(struct saa7146_dev* dev,
+ 	mutex_init(&av7110->osd_mutex);
+ 
+ 	/* TV standard */
+-	av7110->vidmode = tv_standard == 1 ? VIDEO_MODE_NTSC : VIDEO_MODE_PAL;
++	av7110->vidmode = tv_standard == 1 ? AV7110_VIDEO_MODE_NTSC
++					   : AV7110_VIDEO_MODE_PAL;
+ 
+ 	/* ARM "watchdog" */
+ 	init_waitqueue_head(&av7110->arm_wait);
+diff --git a/drivers/media/dvb/ttpci/av7110.h b/drivers/media/dvb/ttpci/av7110.h
+index 0cb4395..39fbf7d 100644
+--- a/drivers/media/dvb/ttpci/av7110.h
++++ b/drivers/media/dvb/ttpci/av7110.h
+@@ -46,6 +46,11 @@ extern int av7110_debug;
+ 
+ enum {AV_PES_STREAM, PS_STREAM, TS_STREAM, PES_STREAM};
+ 
++enum av7110_video_mode {
++	AV7110_VIDEO_MODE_PAL 	= 0,
++	AV7110_VIDEO_MODE_NTSC	= 1
++};
 +
-+#define tda_info(fmt, arg...) printk(KERN_INFO              fmt, ##arg)
-+#define tda_warn(fmt, arg...) tda_printk(KERN_WARNING,      fmt, ##arg)
-+#define tda_err(fmt, arg...)  tda_printk(KERN_ERR,          fmt, ##arg)
-+#define tda_dbg(fmt, arg...)  dprintk(KERN_DEBUG, DBG_INFO, fmt, ##arg)
-+#define tda_map(fmt, arg...)  dprintk(KERN_DEBUG, DBG_MAP,  fmt, ##arg)
-+#define tda_reg(fmt, arg...)  dprintk(KERN_DEBUG, DBG_REG,  fmt, ##arg)
-+#define tda_cal(fmt, arg...)  dprintk(KERN_DEBUG, DBG_CAL,  fmt, ##arg)
+ struct av7110_p2t {
+ 	u8		  pes[TS_SIZE];
+ 	u8		  counter;
+@@ -170,7 +175,7 @@ struct av7110 {
+ 
+ 	ca_slot_info_t		ci_slot[2];
+ 
+-	int			vidmode;
++	enum av7110_video_mode	vidmode;
+ 	struct dmxdev		dmxdev;
+ 	struct dvb_demux	demux;
+ 
+diff --git a/drivers/media/dvb/ttpci/av7110_av.c b/drivers/media/dvb/ttpci/av7110_av.c
+index d75e7e4..aef6e36 100644
+--- a/drivers/media/dvb/ttpci/av7110_av.c
++++ b/drivers/media/dvb/ttpci/av7110_av.c
+@@ -329,7 +329,7 @@ int av7110_set_volume(struct av7110 *av7110, int volleft, int volright)
+ 	return 0;
+ }
+ 
+-int av7110_set_vidmode(struct av7110 *av7110, int mode)
++int av7110_set_vidmode(struct av7110 *av7110, enum av7110_video_mode mode)
+ {
+ 	int ret;
+ 	dprintk(2, "av7110:%p, \n", av7110);
+@@ -348,11 +348,15 @@ int av7110_set_vidmode(struct av7110 *av7110, int mode)
+ }
+ 
+ 
+-static int sw2mode[16] = {
+-	VIDEO_MODE_PAL, VIDEO_MODE_NTSC, VIDEO_MODE_NTSC, VIDEO_MODE_PAL,
+-	VIDEO_MODE_NTSC, VIDEO_MODE_NTSC, VIDEO_MODE_PAL, VIDEO_MODE_NTSC,
+-	VIDEO_MODE_PAL, VIDEO_MODE_PAL, VIDEO_MODE_PAL, VIDEO_MODE_PAL,
+-	VIDEO_MODE_PAL, VIDEO_MODE_PAL, VIDEO_MODE_PAL, VIDEO_MODE_PAL,
++static enum av7110_video_mode sw2mode[16] = {
++	AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_NTSC,
++	AV7110_VIDEO_MODE_NTSC, AV7110_VIDEO_MODE_PAL,
++	AV7110_VIDEO_MODE_NTSC, AV7110_VIDEO_MODE_NTSC,
++	AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_NTSC,
++	AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_PAL,
++	AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_PAL,
++	AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_PAL,
++	AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_PAL,
+ };
+ 
+ static int get_video_format(struct av7110 *av7110, u8 *buf, int count)
+diff --git a/drivers/media/dvb/ttpci/av7110_av.h b/drivers/media/dvb/ttpci/av7110_av.h
+index 45dc144..5f02ef8 100644
+--- a/drivers/media/dvb/ttpci/av7110_av.h
++++ b/drivers/media/dvb/ttpci/av7110_av.h
+@@ -3,7 +3,8 @@
+ 
+ struct av7110;
+ 
+-extern int av7110_set_vidmode(struct av7110 *av7110, int mode);
++extern int av7110_set_vidmode(struct av7110 *av7110,
++			      enum av7110_video_mode mode);
+ 
+ extern int av7110_record_cb(struct dvb_filter_pes2ts *p2t, u8 *buf, size_t len);
+ extern int av7110_pes_play(void *dest, struct dvb_ringbuffer *buf, int dlen);
+diff --git a/drivers/media/dvb/ttpci/av7110_v4l.c b/drivers/media/dvb/ttpci/av7110_v4l.c
+index 76cca00..e2f066f 100644
+--- a/drivers/media/dvb/ttpci/av7110_v4l.c
++++ b/drivers/media/dvb/ttpci/av7110_v4l.c
+@@ -876,11 +876,11 @@ static int std_callback(struct saa7146_dev* dev, struct saa7146_standard *std)
+ 	struct av7110 *av7110 = (struct av7110*) dev->ext_priv;
+ 
+ 	if (std->id & V4L2_STD_PAL) {
+-		av7110->vidmode = VIDEO_MODE_PAL;
++		av7110->vidmode = AV7110_VIDEO_MODE_PAL;
+ 		av7110_set_vidmode(av7110, av7110->vidmode);
+ 	}
+ 	else if (std->id & V4L2_STD_NTSC) {
+-		av7110->vidmode = VIDEO_MODE_NTSC;
++		av7110->vidmode = AV7110_VIDEO_MODE_NTSC;
+ 		av7110_set_vidmode(av7110, av7110->vidmode);
+ 	}
+ 	else
+diff --git a/drivers/media/radio/Kconfig b/drivers/media/radio/Kconfig
+index 11e962f..8d5214f 100644
+--- a/drivers/media/radio/Kconfig
++++ b/drivers/media/radio/Kconfig
+@@ -351,4 +351,14 @@ config USB_DSBR
+ 	  To compile this driver as a module, choose M here: the
+ 	  module will be called dsbr100.
+ 
++config USB_SI470X
++	tristate "Silicon Labs Si470x FM Radio Receiver 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.
 +
-+/*---------------------------------------------------------------------*/
++	  To compile this driver as a module, choose M here: the
++	  module will be called radio-silabs.
 +
-+enum tda18271_map_type {
-+	/* tda18271_pll_map */
-+	MAIN_PLL,
-+	CAL_PLL,
-+	/* tda18271_map */
-+	RF_CAL,
-+	RF_CAL_KMCO,
-+	RF_CAL_DC_OVER_DT,
-+	BP_FILTER,
-+	RF_BAND,
-+	GAIN_TAPER,
-+	IR_MEASURE,
-+};
+ endif # RADIO_ADAPTERS
+diff --git a/drivers/media/radio/Makefile b/drivers/media/radio/Makefile
+index cf55a18..a30159f 100644
+--- a/drivers/media/radio/Makefile
++++ b/drivers/media/radio/Makefile
+@@ -21,5 +21,6 @@ obj-$(CONFIG_RADIO_GEMTEK_PCI) += radio-gemtek-pci.o
+ obj-$(CONFIG_RADIO_TRUST) += radio-trust.o
+ obj-$(CONFIG_RADIO_MAESTRO) += radio-maestro.o
+ obj-$(CONFIG_USB_DSBR) += dsbr100.o
++obj-$(CONFIG_USB_SI470X) += radio-si470x.o
+ 
+ EXTRA_CFLAGS += -Isound
+diff --git a/drivers/media/radio/dsbr100.c b/drivers/media/radio/dsbr100.c
+index 3bd07f7..36c0e36 100644
+--- a/drivers/media/radio/dsbr100.c
++++ b/drivers/media/radio/dsbr100.c
+@@ -33,6 +33,9 @@
+ 
+  History:
+ 
++ Version 0.43:
++	Oliver Neukum: avoided DMA coherency issue
 +
-+extern int tda18271_lookup_pll_map(struct dvb_frontend *fe,
-+				   enum tda18271_map_type map_type,
-+				   u32 *freq, u8 *post_div, u8 *div);
-+extern int tda18271_lookup_map(struct dvb_frontend *fe,
-+			       enum tda18271_map_type map_type,
-+			       u32 *freq, u8 *val);
+  Version 0.42:
+ 	Converted dsbr100 to use video_ioctl2
+ 	by Douglas Landgraf <dougsland at gmail.com>
+@@ -135,7 +138,7 @@ module_param(radio_nr, int, 0);
+ struct dsbr100_device {
+ 	struct usb_device *usbdev;
+ 	struct video_device *videodev;
+-	unsigned char transfer_buffer[TB_LEN];
++	u8 *transfer_buffer;
+ 	int curfreq;
+ 	int stereo;
+ 	int users;
+@@ -237,10 +240,7 @@ static void dsbr100_getstat(struct dsbr100_device *radio)
+ /* 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.  stv680.c does not relase its private
+-data, so I don't do this here either.  Checking out the
+-code I'd expect I better did that, but if there's a memory
+-leak here it's tiny (~50 bytes per disconnect) */
++of releasing it. */
+ static void usb_dsbr100_disconnect(struct usb_interface *intf)
+ {
+ 	struct dsbr100_device *radio = usb_get_intfdata(intf);
+@@ -250,6 +250,7 @@ static void usb_dsbr100_disconnect(struct usb_interface *intf)
+ 		video_unregister_device(radio->videodev);
+ 		radio->videodev = NULL;
+ 		if (radio->users) {
++			kfree(radio->transfer_buffer);
+ 			kfree(radio);
+ 		} else {
+ 			radio->removed = 1;
+@@ -425,6 +426,7 @@ static int usb_dsbr100_close(struct inode *inode, struct file *file)
+ 		return -ENODEV;
+ 	radio->users = 0;
+ 	if (radio->removed) {
++		kfree(radio->transfer_buffer);
+ 		kfree(radio);
+ 	}
+ 	return 0;
+@@ -471,7 +473,12 @@ static int usb_dsbr100_probe(struct usb_interface *intf,
+ 
+ 	if (!(radio = kmalloc(sizeof(struct dsbr100_device), GFP_KERNEL)))
+ 		return -ENOMEM;
++	if (!(radio->transfer_buffer = kmalloc(TB_LEN, GFP_KERNEL))) {
++		kfree(radio);
++		return -ENOMEM;
++	}
+ 	if (!(radio->videodev = video_device_alloc())) {
++		kfree(radio->transfer_buffer);
+ 		kfree(radio);
+ 		return -ENOMEM;
+ 	}
+@@ -485,6 +492,7 @@ static int usb_dsbr100_probe(struct usb_interface *intf,
+ 	if (video_register_device(radio->videodev, VFL_TYPE_RADIO,radio_nr)) {
+ 		warn("Could not register video device");
+ 		video_device_release(radio->videodev);
++		kfree(radio->transfer_buffer);
+ 		kfree(radio);
+ 		return -EIO;
+ 	}
+diff --git a/drivers/media/radio/radio-gemtek.c b/drivers/media/radio/radio-gemtek.c
+index 5e4b9dd..246422b 100644
+--- a/drivers/media/radio/radio-gemtek.c
++++ b/drivers/media/radio/radio-gemtek.c
+@@ -58,10 +58,10 @@ static int initmute	= 1;
+ static int radio_nr	= -1;
+ 
+ module_param(io, int, 0444);
+-MODULE_PARM_DESC(io, "Force I/O port for the GemTek Radio card if automatic"
++MODULE_PARM_DESC(io, "Force I/O port for the GemTek Radio card if automatic "
+ 	 "probing is disabled or fails. The most common I/O ports are: 0x20c "
+ 	 "0x30c, 0x24c or 0x34c (0x20c, 0x248 and 0x28c have been reported to "
+-	 " work for the combined sound/radiocard).");
++	 "work for the combined sound/radiocard).");
+ 
+ module_param(probe, bool, 0444);
+ MODULE_PARM_DESC(probe, "Enable automatic device probing. Note: only the most "
+@@ -392,7 +392,7 @@ static struct v4l2_queryctrl radio_qctrl[] = {
+ 	}
+ };
+ 
+-static struct file_operations gemtek_fops = {
++static const struct file_operations gemtek_fops = {
+ 	.owner		= THIS_MODULE,
+ 	.open		= video_exclusive_open,
+ 	.release	= video_exclusive_release,
+diff --git a/drivers/media/radio/radio-maestro.c b/drivers/media/radio/radio-maestro.c
+index 8e33a19..bc51f4d 100644
+--- a/drivers/media/radio/radio-maestro.c
++++ b/drivers/media/radio/radio-maestro.c
+@@ -423,7 +423,7 @@ static int __devinit maestro_probe(struct pci_dev *pdev,
+ errunr:
+ 	video_unregister_device(maestro_radio_inst);
+ errfr1:
+-	kfree(maestro_radio_inst);
++	video_device_release(maestro_radio_inst);
+ errfr:
+ 	kfree(radio_unit);
+ err:
+diff --git a/drivers/media/radio/radio-sf16fmi.c b/drivers/media/radio/radio-sf16fmi.c
+index 3951653..3118bda 100644
+--- a/drivers/media/radio/radio-sf16fmi.c
++++ b/drivers/media/radio/radio-sf16fmi.c
+@@ -321,7 +321,7 @@ static struct isapnp_device_id id_table[] __devinitdata = {
+ 
+ MODULE_DEVICE_TABLE(isapnp, id_table);
+ 
+-static int isapnp_fmi_probe(void)
++static int __init isapnp_fmi_probe(void)
+ {
+ 	int i = 0;
+ 
+diff --git a/drivers/media/radio/radio-sf16fmr2.c b/drivers/media/radio/radio-sf16fmr2.c
+index c432c44..f7c8b00 100644
+--- a/drivers/media/radio/radio-sf16fmr2.c
++++ b/drivers/media/radio/radio-sf16fmr2.c
+@@ -476,8 +476,7 @@ static int __init fmr2_init(void)
+ 		return -EBUSY;
+ 	}
+ 
+-	if(video_register_device(&fmr2_radio, VFL_TYPE_RADIO, radio_nr)==-1)
+-	{
++	if (video_register_device(&fmr2_radio, VFL_TYPE_RADIO, radio_nr) < 0) {
+ 		release_region(io, 2);
+ 		return -EINVAL;
+ 	}
+diff --git a/drivers/media/radio/radio-si470x.c b/drivers/media/radio/radio-si470x.c
+new file mode 100644
+index 0000000..8e4bd47
+--- /dev/null
++++ b/drivers/media/radio/radio-si470x.c
+@@ -0,0 +1,1432 @@
++/*
++ *  drivers/media/radio/radio-si470x.c
++ *
++ *  Driver for USB radios for the Silicon Labs Si470x FM Radio Receivers:
++ *   - Silicon Labs USB FM Radio Reference Design
++ *   - ADS/Tech FM Radio Receiver (formerly Instant FM Music) (RDX-155-EF)
++ *
++ *  Copyright (c) 2008 Tobias Lorenz <tobias.lorenz at gmx.net>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You 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
++ */
 +
-+extern int tda18271_lookup_thermometer(struct dvb_frontend *fe);
 +
-+extern int tda18271_lookup_rf_band(struct dvb_frontend *fe,
-+				   u32 *freq, u8 *rf_band);
++/*
++ * History:
++ * 2008-01-12	Tobias Lorenz <tobias.lorenz at gmx.net>
++ *		Version 1.0.0
++ *		- First working version
++ * 2008-01-13   Tobias Lorenz <tobias.lorenz at gmx.net>
++ *		Version 1.0.1
++ *		- Improved error handling, every function now returns errno
++ *		- Improved multi user access (start/mute/stop)
++ *		- Channel doesn't get lost anymore after start/mute/stop
++ *		- RDS support added (polling mode via interrupt EP 1)
++ *		- marked default module parameters with *value*
++ *		- switched from bit structs to bit masks
++ *		- header file cleaned and integrated
++ * 2008-01-14	Tobias Lorenz <tobias.lorenz at gmx.net>
++ * 		Version 1.0.2
++ * 		- hex values are now lower case
++ * 		- commented USB ID for ADS/Tech moved on todo list
++ * 		- blacklisted si470x in hid-quirks.c
++ * 		- rds buffer handling functions integrated into *_work, *_read
++ * 		- rds_command in si470x_poll exchanged against simple retval
++ * 		- check for firmware version 15
++ * 		- code order and prototypes still remain the same
++ * 		- spacing and bottom of band codes remain the same
++ * 2008-01-16	Tobias Lorenz <tobias.lorenz at gmx.net>
++ *		Version 1.0.3
++ * 		- code reordered to avoid function prototypes
++ *		- switch/case defaults are now more user-friendly
++ *		- unified comment style
++ *		- applied all checkpatch.pl v1.12 suggestions
++ *		  except the warning about the too long lines with bit comments
++ *		- renamed FMRADIO to RADIO to cut line length (checkpatch.pl)
++ * 2008-01-22	Tobias Lorenz <tobias.lorenz at gmx.net>
++ *		Version 1.0.4
++ *		- avoid poss. locking when doing copy_to_user which may sleep
++ *		- RDS is automatically activated on read now
++ *		- code cleaned of unnecessary rds_commands
++ *		- USB Vendor/Product ID for ADS/Tech FM Radio Receiver verified
++ *		  (thanks to Guillaume RAMOUSSE)
++ *
++ * ToDo:
++ * - add seeking support
++ * - add firmware download/update support
++ * - RDS support: interrupt mode, instead of polling
++ * - add LED status output (check if that's not already done in firmware)
++ */
 +
-+extern int tda18271_lookup_cid_target(struct dvb_frontend *fe,
-+				      u32 *freq, u8 *cid_target,
-+				      u16 *count_limit);
 +
-+extern int tda18271_assign_map_layout(struct dvb_frontend *fe);
++/* driver definitions */
++#define DRIVER_AUTHOR "Tobias Lorenz <tobias.lorenz at gmx.net>"
++#define DRIVER_NAME "radio-si470x"
++#define DRIVER_VERSION KERNEL_VERSION(1, 0, 4)
++#define DRIVER_CARD "Silicon Labs Si470x FM Radio Receiver"
++#define DRIVER_DESC "USB radio driver for Si470x FM Radio Receivers"
 +
-+/*---------------------------------------------------------------------*/
 +
-+extern int tda18271_read_regs(struct dvb_frontend *fe);
-+extern int tda18271_read_extended(struct dvb_frontend *fe);
-+extern int tda18271_write_regs(struct dvb_frontend *fe, int idx, int len);
-+extern int tda18271_init_regs(struct dvb_frontend *fe);
++/* kernel includes */
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/slab.h>
++#include <linux/input.h>
++#include <linux/usb.h>
++#include <linux/hid.h>
++#include <linux/version.h>
++#include <linux/videodev2.h>
++#include <media/v4l2-common.h>
++#include <media/rds.h>
 +
-+extern int tda18271_set_standby_mode(struct dvb_frontend *fe,
-+				     int sm, int sm_lt, int sm_xt);
 +
-+extern int tda18271_calc_main_pll(struct dvb_frontend *fe, u32 freq);
-+extern int tda18271_calc_cal_pll(struct dvb_frontend *fe, u32 freq);
++/* USB Device ID List */
++static struct usb_device_id si470x_usb_driver_id_table[] = {
++	/* Silicon Labs USB FM Radio Reference Design */
++	{ USB_DEVICE_AND_INTERFACE_INFO(0x10c4, 0x818a,	USB_CLASS_HID, 0, 0) },
++	/* ADS/Tech FM Radio Receiver (formerly Instant FM Music) */
++	{ USB_DEVICE_AND_INTERFACE_INFO(0x06e1, 0xa155,	USB_CLASS_HID, 0, 0) },
++	/* Terminating entry */
++	{ }
++};
++MODULE_DEVICE_TABLE(usb, si470x_usb_driver_id_table);
 +
-+extern int tda18271_calc_bp_filter(struct dvb_frontend *fe, u32 *freq);
-+extern int tda18271_calc_km(struct dvb_frontend *fe, u32 *freq);
-+extern int tda18271_calc_rf_band(struct dvb_frontend *fe, u32 *freq);
-+extern int tda18271_calc_gain_taper(struct dvb_frontend *fe, u32 *freq);
-+extern int tda18271_calc_ir_measure(struct dvb_frontend *fe, u32 *freq);
-+extern int tda18271_calc_rf_cal(struct dvb_frontend *fe, u32 *freq);
 +
-+#endif /* __TDA18271_PRIV_H__ */
 +
-+/*
-+ * Overrides for Emacs so that we follow Linus's tabbing style.
-+ * ---------------------------------------------------------------------------
-+ * Local variables:
-+ * c-basic-offset: 8
-+ * End:
-+ */
-diff --git a/drivers/media/dvb/frontends/tda18271-tables.c b/drivers/media/dvb/frontends/tda18271-tables.c
-new file mode 100644
-index 0000000..e94afcf
---- /dev/null
-+++ b/drivers/media/dvb/frontends/tda18271-tables.c
-@@ -0,0 +1,1285 @@
-+/*
-+    tda18271-tables.c - driver for the Philips / NXP TDA18271 silicon tuner
++/**************************************************************************
++ * Module Parameters
++ **************************************************************************/
 +
-+    Copyright (C) 2007, 2008 Michael Krufky <mkrufky at linuxtv.org>
++/* Radio Nr */
++static int radio_nr = -1;
++module_param(radio_nr, int, 0);
++MODULE_PARM_DESC(radio_nr, "Radio Nr");
 +
-+    This program is free software; you can redistribute it and/or modify
-+    it under the terms of the GNU General Public License as published by
-+    the Free Software Foundation; either version 2 of the License, or
-+    (at your option) any later version.
++/* Spacing (kHz) */
++/* 0: 200 kHz (USA, Australia) */
++/* 1: 100 kHz (Europe, Japan) */
++/* 2:  50 kHz */
++static int space = 2;
++module_param(space, int, 0);
++MODULE_PARM_DESC(radio_nr, "Spacing: 0=200kHz 1=100kHz *2=50kHz*");
 +
-+    This program is distributed in the hope that it will be useful,
-+    but WITHOUT ANY WARRANTY; without even the implied warranty of
-+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+    GNU General Public License for more details.
++/* Bottom of Band (MHz) */
++/* 0: 87.5 - 108 MHz (USA, Europe)*/
++/* 1: 76   - 108 MHz (Japan wide band) */
++/* 2: 76   -  90 MHz (Japan) */
++static int band = 1;
++module_param(band, int, 0);
++MODULE_PARM_DESC(radio_nr, "Band: 0=87.5..108MHz *1=76..108MHz* 2=76..90MHz");
 +
-+    You 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.
-+*/
++/* De-emphasis */
++/* 0: 75 us (USA) */
++/* 1: 50 us (Europe, Australia, Japan) */
++static int de = 1;
++module_param(de, int, 0);
++MODULE_PARM_DESC(radio_nr, "De-emphasis: 0=75us *1=50us*");
 +
-+#include "tda18271-priv.h"
++/* USB timeout */
++static int usb_timeout = 500;
++module_param(usb_timeout, int, 0);
++MODULE_PARM_DESC(usb_timeout, "USB timeout (ms): *500*");
 +
-+struct tda18271_pll_map {
-+	u32 lomax;
-+	u8 pd; /* post div */
-+	u8 d;  /*      div */
-+};
++/* Seek retries */
++static int seek_retries = 100;
++module_param(seek_retries, int, 0);
++MODULE_PARM_DESC(seek_retries, "Seek retries: *100*");
 +
-+struct tda18271_map {
-+	u32 rfmax;
-+	u8  val;
-+};
++/* RDS buffer blocks */
++static int rds_buf = 100;
++module_param(rds_buf, int, 0);
++MODULE_PARM_DESC(rds_buf, "RDS buffer entries: *100*");
 +
-+/*---------------------------------------------------------------------*/
++/* RDS maximum block errors */
++static int max_rds_errors = 1;
++/* 0 means   0  errors requiring correction */
++/* 1 means 1-2  errors requiring correction (used by original USBRadio.exe) */
++/* 2 means 3-5  errors requiring correction */
++/* 3 means   6+ errors or errors in checkword, correction not possible */
++module_param(max_rds_errors, int, 0);
++MODULE_PARM_DESC(max_rds_errors, "RDS maximum block errors: *1*");
 +
-+static struct tda18271_pll_map tda18271c1_main_pll[] = {
-+	{ .lomax =  32000, .pd = 0x5f, .d = 0xf0 },
-+	{ .lomax =  35000, .pd = 0x5e, .d = 0xe0 },
-+	{ .lomax =  37000, .pd = 0x5d, .d = 0xd0 },
-+	{ .lomax =  41000, .pd = 0x5c, .d = 0xc0 },
-+	{ .lomax =  44000, .pd = 0x5b, .d = 0xb0 },
-+	{ .lomax =  49000, .pd = 0x5a, .d = 0xa0 },
-+	{ .lomax =  54000, .pd = 0x59, .d = 0x90 },
-+	{ .lomax =  61000, .pd = 0x58, .d = 0x80 },
-+	{ .lomax =  65000, .pd = 0x4f, .d = 0x78 },
-+	{ .lomax =  70000, .pd = 0x4e, .d = 0x70 },
-+	{ .lomax =  75000, .pd = 0x4d, .d = 0x68 },
-+	{ .lomax =  82000, .pd = 0x4c, .d = 0x60 },
-+	{ .lomax =  89000, .pd = 0x4b, .d = 0x58 },
-+	{ .lomax =  98000, .pd = 0x4a, .d = 0x50 },
-+	{ .lomax = 109000, .pd = 0x49, .d = 0x48 },
-+	{ .lomax = 123000, .pd = 0x48, .d = 0x40 },
-+	{ .lomax = 131000, .pd = 0x3f, .d = 0x3c },
-+	{ .lomax = 141000, .pd = 0x3e, .d = 0x38 },
-+	{ .lomax = 151000, .pd = 0x3d, .d = 0x34 },
-+	{ .lomax = 164000, .pd = 0x3c, .d = 0x30 },
-+	{ .lomax = 179000, .pd = 0x3b, .d = 0x2c },
-+	{ .lomax = 197000, .pd = 0x3a, .d = 0x28 },
-+	{ .lomax = 219000, .pd = 0x39, .d = 0x24 },
-+	{ .lomax = 246000, .pd = 0x38, .d = 0x20 },
-+	{ .lomax = 263000, .pd = 0x2f, .d = 0x1e },
-+	{ .lomax = 282000, .pd = 0x2e, .d = 0x1c },
-+	{ .lomax = 303000, .pd = 0x2d, .d = 0x1a },
-+	{ .lomax = 329000, .pd = 0x2c, .d = 0x18 },
-+	{ .lomax = 359000, .pd = 0x2b, .d = 0x16 },
-+	{ .lomax = 395000, .pd = 0x2a, .d = 0x14 },
-+	{ .lomax = 438000, .pd = 0x29, .d = 0x12 },
-+	{ .lomax = 493000, .pd = 0x28, .d = 0x10 },
-+	{ .lomax = 526000, .pd = 0x1f, .d = 0x0f },
-+	{ .lomax = 564000, .pd = 0x1e, .d = 0x0e },
-+	{ .lomax = 607000, .pd = 0x1d, .d = 0x0d },
-+	{ .lomax = 658000, .pd = 0x1c, .d = 0x0c },
-+	{ .lomax = 718000, .pd = 0x1b, .d = 0x0b },
-+	{ .lomax = 790000, .pd = 0x1a, .d = 0x0a },
-+	{ .lomax = 877000, .pd = 0x19, .d = 0x09 },
-+	{ .lomax = 987000, .pd = 0x18, .d = 0x08 },
-+	{ .lomax =      0, .pd = 0x00, .d = 0x00 }, /* end */
-+};
++/* RDS poll frequency */
++static int rds_poll_time = 40;
++/* 40 is used by the original USBRadio.exe */
++/* 50 is used by radio-cadet */
++/* 75 should be okay */
++/* 80 is the usual RDS receive interval */
++module_param(rds_poll_time, int, 0);
++MODULE_PARM_DESC(rds_poll_time, "RDS poll time (ms): *40*");
 +
-+static struct tda18271_pll_map tda18271c2_main_pll[] = {
-+	{ .lomax =  33125, .pd = 0x57, .d = 0xf0 },
-+	{ .lomax =  35500, .pd = 0x56, .d = 0xe0 },
-+	{ .lomax =  38188, .pd = 0x55, .d = 0xd0 },
-+	{ .lomax =  41375, .pd = 0x54, .d = 0xc0 },
-+	{ .lomax =  45125, .pd = 0x53, .d = 0xb0 },
-+	{ .lomax =  49688, .pd = 0x52, .d = 0xa0 },
-+	{ .lomax =  55188, .pd = 0x51, .d = 0x90 },
-+	{ .lomax =  62125, .pd = 0x50, .d = 0x80 },
-+	{ .lomax =  66250, .pd = 0x47, .d = 0x78 },
-+	{ .lomax =  71000, .pd = 0x46, .d = 0x70 },
-+	{ .lomax =  76375, .pd = 0x45, .d = 0x68 },
-+	{ .lomax =  82750, .pd = 0x44, .d = 0x60 },
-+	{ .lomax =  90250, .pd = 0x43, .d = 0x58 },
-+	{ .lomax =  99375, .pd = 0x42, .d = 0x50 },
-+	{ .lomax = 110375, .pd = 0x41, .d = 0x48 },
-+	{ .lomax = 124250, .pd = 0x40, .d = 0x40 },
-+	{ .lomax = 132500, .pd = 0x37, .d = 0x3c },
-+	{ .lomax = 142000, .pd = 0x36, .d = 0x38 },
-+	{ .lomax = 152750, .pd = 0x35, .d = 0x34 },
-+	{ .lomax = 165500, .pd = 0x34, .d = 0x30 },
-+	{ .lomax = 180500, .pd = 0x33, .d = 0x2c },
-+	{ .lomax = 198750, .pd = 0x32, .d = 0x28 },
-+	{ .lomax = 220750, .pd = 0x31, .d = 0x24 },
-+	{ .lomax = 248500, .pd = 0x30, .d = 0x20 },
-+	{ .lomax = 265000, .pd = 0x27, .d = 0x1e },
-+	{ .lomax = 284000, .pd = 0x26, .d = 0x1c },
-+	{ .lomax = 305500, .pd = 0x25, .d = 0x1a },
-+	{ .lomax = 331000, .pd = 0x24, .d = 0x18 },
-+	{ .lomax = 361000, .pd = 0x23, .d = 0x16 },
-+	{ .lomax = 397500, .pd = 0x22, .d = 0x14 },
-+	{ .lomax = 441500, .pd = 0x21, .d = 0x12 },
-+	{ .lomax = 497000, .pd = 0x20, .d = 0x10 },
-+	{ .lomax = 530000, .pd = 0x17, .d = 0x0f },
-+	{ .lomax = 568000, .pd = 0x16, .d = 0x0e },
-+	{ .lomax = 611000, .pd = 0x15, .d = 0x0d },
-+	{ .lomax = 662000, .pd = 0x14, .d = 0x0c },
-+	{ .lomax = 722000, .pd = 0x13, .d = 0x0b },
-+	{ .lomax = 795000, .pd = 0x12, .d = 0x0a },
-+	{ .lomax = 883000, .pd = 0x11, .d = 0x09 },
-+	{ .lomax = 994000, .pd = 0x10, .d = 0x08 },
-+	{ .lomax =      0, .pd = 0x00, .d = 0x00 }, /* end */
-+};
 +
-+static struct tda18271_pll_map tda18271c1_cal_pll[] = {
-+	{ .lomax =   33000, .pd = 0xdd, .d = 0xd0 },
-+	{ .lomax =   36000, .pd = 0xdc, .d = 0xc0 },
-+	{ .lomax =   40000, .pd = 0xdb, .d = 0xb0 },
-+	{ .lomax =   44000, .pd = 0xda, .d = 0xa0 },
-+	{ .lomax =   49000, .pd = 0xd9, .d = 0x90 },
-+	{ .lomax =   55000, .pd = 0xd8, .d = 0x80 },
-+	{ .lomax =   63000, .pd = 0xd3, .d = 0x70 },
-+	{ .lomax =   67000, .pd = 0xcd, .d = 0x68 },
-+	{ .lomax =   73000, .pd = 0xcc, .d = 0x60 },
-+	{ .lomax =   80000, .pd = 0xcb, .d = 0x58 },
-+	{ .lomax =   88000, .pd = 0xca, .d = 0x50 },
-+	{ .lomax =   98000, .pd = 0xc9, .d = 0x48 },
-+	{ .lomax =  110000, .pd = 0xc8, .d = 0x40 },
-+	{ .lomax =  126000, .pd = 0xc3, .d = 0x38 },
-+	{ .lomax =  135000, .pd = 0xbd, .d = 0x34 },
-+	{ .lomax =  147000, .pd = 0xbc, .d = 0x30 },
-+	{ .lomax =  160000, .pd = 0xbb, .d = 0x2c },
-+	{ .lomax =  176000, .pd = 0xba, .d = 0x28 },
-+	{ .lomax =  196000, .pd = 0xb9, .d = 0x24 },
-+	{ .lomax =  220000, .pd = 0xb8, .d = 0x20 },
-+	{ .lomax =  252000, .pd = 0xb3, .d = 0x1c },
-+	{ .lomax =  271000, .pd = 0xad, .d = 0x1a },
-+	{ .lomax =  294000, .pd = 0xac, .d = 0x18 },
-+	{ .lomax =  321000, .pd = 0xab, .d = 0x16 },
-+	{ .lomax =  353000, .pd = 0xaa, .d = 0x14 },
-+	{ .lomax =  392000, .pd = 0xa9, .d = 0x12 },
-+	{ .lomax =  441000, .pd = 0xa8, .d = 0x10 },
-+	{ .lomax =  505000, .pd = 0xa3, .d = 0x0e },
-+	{ .lomax =  543000, .pd = 0x9d, .d = 0x0d },
-+	{ .lomax =  589000, .pd = 0x9c, .d = 0x0c },
-+	{ .lomax =  642000, .pd = 0x9b, .d = 0x0b },
-+	{ .lomax =  707000, .pd = 0x9a, .d = 0x0a },
-+	{ .lomax =  785000, .pd = 0x99, .d = 0x09 },
-+	{ .lomax =  883000, .pd = 0x98, .d = 0x08 },
-+	{ .lomax = 1010000, .pd = 0x93, .d = 0x07 },
-+	{ .lomax =       0, .pd = 0x00, .d = 0x00 }, /* end */
-+};
 +
-+static struct tda18271_pll_map tda18271c2_cal_pll[] = {
-+	{ .lomax =   33813, .pd = 0xdd, .d = 0xd0 },
-+	{ .lomax =   36625, .pd = 0xdc, .d = 0xc0 },
-+	{ .lomax =   39938, .pd = 0xdb, .d = 0xb0 },
-+	{ .lomax =   43938, .pd = 0xda, .d = 0xa0 },
-+	{ .lomax =   48813, .pd = 0xd9, .d = 0x90 },
-+	{ .lomax =   54938, .pd = 0xd8, .d = 0x80 },
-+	{ .lomax =   62813, .pd = 0xd3, .d = 0x70 },
-+	{ .lomax =   67625, .pd = 0xcd, .d = 0x68 },
-+	{ .lomax =   73250, .pd = 0xcc, .d = 0x60 },
-+	{ .lomax =   79875, .pd = 0xcb, .d = 0x58 },
-+	{ .lomax =   87875, .pd = 0xca, .d = 0x50 },
-+	{ .lomax =   97625, .pd = 0xc9, .d = 0x48 },
-+	{ .lomax =  109875, .pd = 0xc8, .d = 0x40 },
-+	{ .lomax =  125625, .pd = 0xc3, .d = 0x38 },
-+	{ .lomax =  135250, .pd = 0xbd, .d = 0x34 },
-+	{ .lomax =  146500, .pd = 0xbc, .d = 0x30 },
-+	{ .lomax =  159750, .pd = 0xbb, .d = 0x2c },
-+	{ .lomax =  175750, .pd = 0xba, .d = 0x28 },
-+	{ .lomax =  195250, .pd = 0xb9, .d = 0x24 },
-+	{ .lomax =  219750, .pd = 0xb8, .d = 0x20 },
-+	{ .lomax =  251250, .pd = 0xb3, .d = 0x1c },
-+	{ .lomax =  270500, .pd = 0xad, .d = 0x1a },
-+	{ .lomax =  293000, .pd = 0xac, .d = 0x18 },
-+	{ .lomax =  319500, .pd = 0xab, .d = 0x16 },
-+	{ .lomax =  351500, .pd = 0xaa, .d = 0x14 },
-+	{ .lomax =  390500, .pd = 0xa9, .d = 0x12 },
-+	{ .lomax =  439500, .pd = 0xa8, .d = 0x10 },
-+	{ .lomax =  502500, .pd = 0xa3, .d = 0x0e },
-+	{ .lomax =  541000, .pd = 0x9d, .d = 0x0d },
-+	{ .lomax =  586000, .pd = 0x9c, .d = 0x0c },
-+	{ .lomax =  639000, .pd = 0x9b, .d = 0x0b },
-+	{ .lomax =  703000, .pd = 0x9a, .d = 0x0a },
-+	{ .lomax =  781000, .pd = 0x99, .d = 0x09 },
-+	{ .lomax =  879000, .pd = 0x98, .d = 0x08 },
-+	{ .lomax =       0, .pd = 0x00, .d = 0x00 }, /* end */
-+};
++/**************************************************************************
++ * Register Definitions
++ **************************************************************************/
++#define RADIO_REGISTER_SIZE	2	/* 16 register bit width */
++#define RADIO_REGISTER_NUM	16	/* DEVICEID   ... RDSD */
++#define RDS_REGISTER_NUM	6	/* STATUSRSSI ... RDSD */
 +
-+static struct tda18271_map tda18271_bp_filter[] = {
-+	{ .rfmax =  62000, .val = 0x00 },
-+	{ .rfmax =  84000, .val = 0x01 },
-+	{ .rfmax = 100000, .val = 0x02 },
-+	{ .rfmax = 140000, .val = 0x03 },
-+	{ .rfmax = 170000, .val = 0x04 },
-+	{ .rfmax = 180000, .val = 0x05 },
-+	{ .rfmax = 865000, .val = 0x06 },
-+	{ .rfmax =      0, .val = 0x00 }, /* end */
-+};
++#define DEVICEID		0	/* Device ID */
++#define DEVICEID_PN		0xf000	/* bits 15..12: Part Number */
++#define DEVICEID_MFGID		0x0fff	/* bits 11..00: Manufacturer ID */
 +
-+static struct tda18271_map tda18271c1_km[] = {
-+	{ .rfmax =  61100, .val = 0x74 },
-+	{ .rfmax = 350000, .val = 0x40 },
-+	{ .rfmax = 720000, .val = 0x30 },
-+	{ .rfmax = 865000, .val = 0x40 },
-+	{ .rfmax =      0, .val = 0x00 }, /* end */
-+};
++#define CHIPID			1	/* Chip ID */
++#define CHIPID_REV		0xfc00	/* bits 15..10: Chip Version */
++#define CHIPID_DEV		0x0200	/* bits 09..09: Device */
++#define CHIPID_FIRMWARE		0x01ff	/* bits 08..00: Firmware Version */
 +
-+static struct tda18271_map tda18271c2_km[] = {
-+	{ .rfmax =  47900, .val = 0x38 },
-+	{ .rfmax =  61100, .val = 0x44 },
-+	{ .rfmax = 350000, .val = 0x30 },
-+	{ .rfmax = 720000, .val = 0x24 },
-+	{ .rfmax = 865000, .val = 0x3c },
-+	{ .rfmax =      0, .val = 0x00 }, /* end */
-+};
++#define POWERCFG		2	/* Power Configuration */
++#define POWERCFG_DSMUTE		0x8000	/* bits 15..15: Softmute Disable */
++#define POWERCFG_DMUTE		0x4000	/* bits 14..14: Mute Disable */
++#define POWERCFG_MONO		0x2000	/* bits 13..13: Mono Select */
++#define POWERCFG_RDSM		0x0800	/* bits 11..11: RDS Mode (Si4701 only) */
++#define POWERCFG_SKMODE		0x0400	/* bits 10..10: Seek Mode */
++#define POWERCFG_SEEKUP		0x0200	/* bits 09..09: Seek Direction */
++#define POWERCFG_SEEK		0x0100	/* bits 08..08: Seek */
++#define POWERCFG_DISABLE	0x0040	/* bits 06..06: Powerup Disable */
++#define POWERCFG_ENABLE		0x0001	/* bits 00..00: Powerup Enable */
 +
-+static struct tda18271_map tda18271_rf_band[] = {
-+	{ .rfmax =  47900, .val = 0x00 },
-+	{ .rfmax =  61100, .val = 0x01 },
-+/*	{ .rfmax = 152600, .val = 0x02 }, */
-+	{ .rfmax = 121200, .val = 0x02 },
-+	{ .rfmax = 164700, .val = 0x03 },
-+	{ .rfmax = 203500, .val = 0x04 },
-+	{ .rfmax = 457800, .val = 0x05 },
-+	{ .rfmax = 865000, .val = 0x06 },
-+	{ .rfmax =      0, .val = 0x00 }, /* end */
-+};
++#define CHANNEL			3	/* Channel */
++#define CHANNEL_TUNE		0x8000	/* bits 15..15: Tune */
++#define CHANNEL_CHAN		0x03ff	/* bits 09..00: Channel Select */
 +
-+static struct tda18271_map tda18271_gain_taper[] = {
-+	{ .rfmax =  45400, .val = 0x1f },
-+	{ .rfmax =  45800, .val = 0x1e },
-+	{ .rfmax =  46200, .val = 0x1d },
-+	{ .rfmax =  46700, .val = 0x1c },
-+	{ .rfmax =  47100, .val = 0x1b },
-+	{ .rfmax =  47500, .val = 0x1a },
-+	{ .rfmax =  47900, .val = 0x19 },
-+	{ .rfmax =  49600, .val = 0x17 },
-+	{ .rfmax =  51200, .val = 0x16 },
-+	{ .rfmax =  52900, .val = 0x15 },
-+	{ .rfmax =  54500, .val = 0x14 },
-+	{ .rfmax =  56200, .val = 0x13 },
-+	{ .rfmax =  57800, .val = 0x12 },
-+	{ .rfmax =  59500, .val = 0x11 },
-+	{ .rfmax =  61100, .val = 0x10 },
-+	{ .rfmax =  67600, .val = 0x0d },
-+	{ .rfmax =  74200, .val = 0x0c },
-+	{ .rfmax =  80700, .val = 0x0b },
-+	{ .rfmax =  87200, .val = 0x0a },
-+	{ .rfmax =  93800, .val = 0x09 },
-+	{ .rfmax = 100300, .val = 0x08 },
-+	{ .rfmax = 106900, .val = 0x07 },
-+	{ .rfmax = 113400, .val = 0x06 },
-+	{ .rfmax = 119900, .val = 0x05 },
-+	{ .rfmax = 126500, .val = 0x04 },
-+	{ .rfmax = 133000, .val = 0x03 },
-+	{ .rfmax = 139500, .val = 0x02 },
-+	{ .rfmax = 146100, .val = 0x01 },
-+	{ .rfmax = 152600, .val = 0x00 },
-+	{ .rfmax = 154300, .val = 0x1f },
-+	{ .rfmax = 156100, .val = 0x1e },
-+	{ .rfmax = 157800, .val = 0x1d },
-+	{ .rfmax = 159500, .val = 0x1c },
-+	{ .rfmax = 161200, .val = 0x1b },
-+	{ .rfmax = 163000, .val = 0x1a },
-+	{ .rfmax = 164700, .val = 0x19 },
-+	{ .rfmax = 170200, .val = 0x17 },
-+	{ .rfmax = 175800, .val = 0x16 },
-+	{ .rfmax = 181300, .val = 0x15 },
-+	{ .rfmax = 186900, .val = 0x14 },
-+	{ .rfmax = 192400, .val = 0x13 },
-+	{ .rfmax = 198000, .val = 0x12 },
-+	{ .rfmax = 203500, .val = 0x11 },
-+	{ .rfmax = 216200, .val = 0x14 },
-+	{ .rfmax = 228900, .val = 0x13 },
-+	{ .rfmax = 241600, .val = 0x12 },
-+	{ .rfmax = 254400, .val = 0x11 },
-+	{ .rfmax = 267100, .val = 0x10 },
-+	{ .rfmax = 279800, .val = 0x0f },
-+	{ .rfmax = 292500, .val = 0x0e },
-+	{ .rfmax = 305200, .val = 0x0d },
-+	{ .rfmax = 317900, .val = 0x0c },
-+	{ .rfmax = 330700, .val = 0x0b },
-+	{ .rfmax = 343400, .val = 0x0a },
-+	{ .rfmax = 356100, .val = 0x09 },
-+	{ .rfmax = 368800, .val = 0x08 },
-+	{ .rfmax = 381500, .val = 0x07 },
-+	{ .rfmax = 394200, .val = 0x06 },
-+	{ .rfmax = 406900, .val = 0x05 },
-+	{ .rfmax = 419700, .val = 0x04 },
-+	{ .rfmax = 432400, .val = 0x03 },
-+	{ .rfmax = 445100, .val = 0x02 },
-+	{ .rfmax = 457800, .val = 0x01 },
-+	{ .rfmax = 476300, .val = 0x19 },
-+	{ .rfmax = 494800, .val = 0x18 },
-+	{ .rfmax = 513300, .val = 0x17 },
-+	{ .rfmax = 531800, .val = 0x16 },
-+	{ .rfmax = 550300, .val = 0x15 },
-+	{ .rfmax = 568900, .val = 0x14 },
-+	{ .rfmax = 587400, .val = 0x13 },
-+	{ .rfmax = 605900, .val = 0x12 },
-+	{ .rfmax = 624400, .val = 0x11 },
-+	{ .rfmax = 642900, .val = 0x10 },
-+	{ .rfmax = 661400, .val = 0x0f },
-+	{ .rfmax = 679900, .val = 0x0e },
-+	{ .rfmax = 698400, .val = 0x0d },
-+	{ .rfmax = 716900, .val = 0x0c },
-+	{ .rfmax = 735400, .val = 0x0b },
-+	{ .rfmax = 753900, .val = 0x0a },
-+	{ .rfmax = 772500, .val = 0x09 },
-+	{ .rfmax = 791000, .val = 0x08 },
-+	{ .rfmax = 809500, .val = 0x07 },
-+	{ .rfmax = 828000, .val = 0x06 },
-+	{ .rfmax = 846500, .val = 0x05 },
-+	{ .rfmax = 865000, .val = 0x04 },
-+	{ .rfmax =      0, .val = 0x00 }, /* end */
-+};
++#define SYSCONFIG1		4	/* System Configuration 1 */
++#define SYSCONFIG1_RDSIEN	0x8000	/* bits 15..15: RDS Interrupt Enable (Si4701 only) */
++#define SYSCONFIG1_STCIEN	0x4000	/* bits 14..14: Seek/Tune Complete Interrupt Enable */
++#define SYSCONFIG1_RDS		0x1000	/* bits 12..12: RDS Enable (Si4701 only) */
++#define SYSCONFIG1_DE		0x0800	/* bits 11..11: De-emphasis (0=75us 1=50us) */
++#define SYSCONFIG1_AGCD		0x0400	/* bits 10..10: AGC Disable */
++#define SYSCONFIG1_BLNDADJ	0x00c0	/* bits 07..06: Stereo/Mono Blend Level Adjustment */
++#define SYSCONFIG1_GPIO3	0x0030	/* bits 05..04: General Purpose I/O 3 */
++#define SYSCONFIG1_GPIO2	0x000c	/* bits 03..02: General Purpose I/O 2 */
++#define SYSCONFIG1_GPIO1	0x0003	/* bits 01..00: General Purpose I/O 1 */
 +
-+static struct tda18271_map tda18271c1_rf_cal[] = {
-+	{ .rfmax = 41000, .val = 0x1e },
-+	{ .rfmax = 43000, .val = 0x30 },
-+	{ .rfmax = 45000, .val = 0x43 },
-+	{ .rfmax = 46000, .val = 0x4d },
-+	{ .rfmax = 47000, .val = 0x54 },
-+	{ .rfmax = 47900, .val = 0x64 },
-+	{ .rfmax = 49100, .val = 0x20 },
-+	{ .rfmax = 50000, .val = 0x22 },
-+	{ .rfmax = 51000, .val = 0x2a },
-+	{ .rfmax = 53000, .val = 0x32 },
-+	{ .rfmax = 55000, .val = 0x35 },
-+	{ .rfmax = 56000, .val = 0x3c },
-+	{ .rfmax = 57000, .val = 0x3f },
-+	{ .rfmax = 58000, .val = 0x48 },
-+	{ .rfmax = 59000, .val = 0x4d },
-+	{ .rfmax = 60000, .val = 0x58 },
-+	{ .rfmax = 61100, .val = 0x5f },
-+	{ .rfmax =     0, .val = 0x00 }, /* end */
-+};
++#define SYSCONFIG2		5	/* System Configuration 2 */
++#define SYSCONFIG2_SEEKTH	0xff00	/* bits 15..08: RSSI Seek Threshold */
++#define SYSCONFIG2_BAND		0x0080	/* bits 07..06: Band Select */
++#define SYSCONFIG2_SPACE	0x0030	/* bits 05..04: Channel Spacing */
++#define SYSCONFIG2_VOLUME	0x000f	/* bits 03..00: Volume */
 +
-+static struct tda18271_map tda18271c2_rf_cal[] = {
-+	{ .rfmax =  41000, .val = 0x0f },
-+	{ .rfmax =  43000, .val = 0x1c },
-+	{ .rfmax =  45000, .val = 0x2f },
-+	{ .rfmax =  46000, .val = 0x39 },
-+	{ .rfmax =  47000, .val = 0x40 },
-+	{ .rfmax =  47900, .val = 0x50 },
-+	{ .rfmax =  49100, .val = 0x16 },
-+	{ .rfmax =  50000, .val = 0x18 },
-+	{ .rfmax =  51000, .val = 0x20 },
-+	{ .rfmax =  53000, .val = 0x28 },
-+	{ .rfmax =  55000, .val = 0x2b },
-+	{ .rfmax =  56000, .val = 0x32 },
-+	{ .rfmax =  57000, .val = 0x35 },
-+	{ .rfmax =  58000, .val = 0x3e },
-+	{ .rfmax =  59000, .val = 0x43 },
-+	{ .rfmax =  60000, .val = 0x4e },
-+	{ .rfmax =  61100, .val = 0x55 },
-+	{ .rfmax =  63000, .val = 0x0f },
-+	{ .rfmax =  64000, .val = 0x11 },
-+	{ .rfmax =  65000, .val = 0x12 },
-+	{ .rfmax =  66000, .val = 0x15 },
-+	{ .rfmax =  67000, .val = 0x16 },
-+	{ .rfmax =  68000, .val = 0x17 },
-+	{ .rfmax =  70000, .val = 0x19 },
-+	{ .rfmax =  71000, .val = 0x1c },
-+	{ .rfmax =  72000, .val = 0x1d },
-+	{ .rfmax =  73000, .val = 0x1f },
-+	{ .rfmax =  74000, .val = 0x20 },
-+	{ .rfmax =  75000, .val = 0x21 },
-+	{ .rfmax =  76000, .val = 0x24 },
-+	{ .rfmax =  77000, .val = 0x25 },
-+	{ .rfmax =  78000, .val = 0x27 },
-+	{ .rfmax =  80000, .val = 0x28 },
-+	{ .rfmax =  81000, .val = 0x29 },
-+	{ .rfmax =  82000, .val = 0x2d },
-+	{ .rfmax =  83000, .val = 0x2e },
-+	{ .rfmax =  84000, .val = 0x2f },
-+	{ .rfmax =  85000, .val = 0x31 },
-+	{ .rfmax =  86000, .val = 0x33 },
-+	{ .rfmax =  87000, .val = 0x34 },
-+	{ .rfmax =  88000, .val = 0x35 },
-+	{ .rfmax =  89000, .val = 0x37 },
-+	{ .rfmax =  90000, .val = 0x38 },
-+	{ .rfmax =  91000, .val = 0x39 },
-+	{ .rfmax =  93000, .val = 0x3c },
-+	{ .rfmax =  94000, .val = 0x3e },
-+	{ .rfmax =  95000, .val = 0x3f },
-+	{ .rfmax =  96000, .val = 0x40 },
-+	{ .rfmax =  97000, .val = 0x42 },
-+	{ .rfmax =  99000, .val = 0x45 },
-+	{ .rfmax = 100000, .val = 0x46 },
-+	{ .rfmax = 102000, .val = 0x48 },
-+	{ .rfmax = 103000, .val = 0x4a },
-+	{ .rfmax = 105000, .val = 0x4d },
-+	{ .rfmax = 106000, .val = 0x4e },
-+	{ .rfmax = 107000, .val = 0x50 },
-+	{ .rfmax = 108000, .val = 0x51 },
-+	{ .rfmax = 110000, .val = 0x54 },
-+	{ .rfmax = 111000, .val = 0x56 },
-+	{ .rfmax = 112000, .val = 0x57 },
-+	{ .rfmax = 113000, .val = 0x58 },
-+	{ .rfmax = 114000, .val = 0x59 },
-+	{ .rfmax = 115000, .val = 0x5c },
-+	{ .rfmax = 116000, .val = 0x5d },
-+	{ .rfmax = 117000, .val = 0x5f },
-+	{ .rfmax = 119000, .val = 0x60 },
-+	{ .rfmax = 120000, .val = 0x64 },
-+	{ .rfmax = 121000, .val = 0x65 },
-+	{ .rfmax = 122000, .val = 0x66 },
-+	{ .rfmax = 123000, .val = 0x68 },
-+	{ .rfmax = 124000, .val = 0x69 },
-+	{ .rfmax = 125000, .val = 0x6c },
-+	{ .rfmax = 126000, .val = 0x6d },
-+	{ .rfmax = 127000, .val = 0x6e },
-+	{ .rfmax = 128000, .val = 0x70 },
-+	{ .rfmax = 129000, .val = 0x71 },
-+	{ .rfmax = 130000, .val = 0x75 },
-+	{ .rfmax = 131000, .val = 0x77 },
-+	{ .rfmax = 132000, .val = 0x78 },
-+	{ .rfmax = 133000, .val = 0x7b },
-+	{ .rfmax = 134000, .val = 0x7e },
-+	{ .rfmax = 135000, .val = 0x81 },
-+	{ .rfmax = 136000, .val = 0x82 },
-+	{ .rfmax = 137000, .val = 0x87 },
-+	{ .rfmax = 138000, .val = 0x88 },
-+	{ .rfmax = 139000, .val = 0x8d },
-+	{ .rfmax = 140000, .val = 0x8e },
-+	{ .rfmax = 141000, .val = 0x91 },
-+	{ .rfmax = 142000, .val = 0x95 },
-+	{ .rfmax = 143000, .val = 0x9a },
-+	{ .rfmax = 144000, .val = 0x9d },
-+	{ .rfmax = 145000, .val = 0xa1 },
-+	{ .rfmax = 146000, .val = 0xa2 },
-+	{ .rfmax = 147000, .val = 0xa4 },
-+	{ .rfmax = 148000, .val = 0xa9 },
-+	{ .rfmax = 149000, .val = 0xae },
-+	{ .rfmax = 150000, .val = 0xb0 },
-+	{ .rfmax = 151000, .val = 0xb1 },
-+	{ .rfmax = 152000, .val = 0xb7 },
-+	{ .rfmax = 153000, .val = 0xbd },
-+	{ .rfmax = 154000, .val = 0x20 },
-+	{ .rfmax = 155000, .val = 0x22 },
-+	{ .rfmax = 156000, .val = 0x24 },
-+	{ .rfmax = 157000, .val = 0x25 },
-+	{ .rfmax = 158000, .val = 0x27 },
-+	{ .rfmax = 159000, .val = 0x29 },
-+	{ .rfmax = 160000, .val = 0x2c },
-+	{ .rfmax = 161000, .val = 0x2d },
-+	{ .rfmax = 163000, .val = 0x2e },
-+	{ .rfmax = 164000, .val = 0x2f },
-+	{ .rfmax = 165000, .val = 0x30 },
-+	{ .rfmax = 166000, .val = 0x11 },
-+	{ .rfmax = 167000, .val = 0x12 },
-+	{ .rfmax = 168000, .val = 0x13 },
-+	{ .rfmax = 169000, .val = 0x14 },
-+	{ .rfmax = 170000, .val = 0x15 },
-+	{ .rfmax = 172000, .val = 0x16 },
-+	{ .rfmax = 173000, .val = 0x17 },
-+	{ .rfmax = 174000, .val = 0x18 },
-+	{ .rfmax = 175000, .val = 0x1a },
-+	{ .rfmax = 176000, .val = 0x1b },
-+	{ .rfmax = 178000, .val = 0x1d },
-+	{ .rfmax = 179000, .val = 0x1e },
-+	{ .rfmax = 180000, .val = 0x1f },
-+	{ .rfmax = 181000, .val = 0x20 },
-+	{ .rfmax = 182000, .val = 0x21 },
-+	{ .rfmax = 183000, .val = 0x22 },
-+	{ .rfmax = 184000, .val = 0x24 },
-+	{ .rfmax = 185000, .val = 0x25 },
-+	{ .rfmax = 186000, .val = 0x26 },
-+	{ .rfmax = 187000, .val = 0x27 },
-+	{ .rfmax = 188000, .val = 0x29 },
-+	{ .rfmax = 189000, .val = 0x2a },
-+	{ .rfmax = 190000, .val = 0x2c },
-+	{ .rfmax = 191000, .val = 0x2d },
-+	{ .rfmax = 192000, .val = 0x2e },
-+	{ .rfmax = 193000, .val = 0x2f },
-+	{ .rfmax = 194000, .val = 0x30 },
-+	{ .rfmax = 195000, .val = 0x33 },
-+	{ .rfmax = 196000, .val = 0x35 },
-+	{ .rfmax = 198000, .val = 0x36 },
-+	{ .rfmax = 200000, .val = 0x38 },
-+	{ .rfmax = 201000, .val = 0x3c },
-+	{ .rfmax = 202000, .val = 0x3d },
-+	{ .rfmax = 203500, .val = 0x3e },
-+	{ .rfmax = 206000, .val = 0x0e },
-+	{ .rfmax = 208000, .val = 0x0f },
-+	{ .rfmax = 212000, .val = 0x10 },
-+	{ .rfmax = 216000, .val = 0x11 },
-+	{ .rfmax = 217000, .val = 0x12 },
-+	{ .rfmax = 218000, .val = 0x13 },
-+	{ .rfmax = 220000, .val = 0x14 },
-+	{ .rfmax = 222000, .val = 0x15 },
-+	{ .rfmax = 225000, .val = 0x16 },
-+	{ .rfmax = 228000, .val = 0x17 },
-+	{ .rfmax = 231000, .val = 0x18 },
-+	{ .rfmax = 234000, .val = 0x19 },
-+	{ .rfmax = 235000, .val = 0x1a },
-+	{ .rfmax = 236000, .val = 0x1b },
-+	{ .rfmax = 237000, .val = 0x1c },
-+	{ .rfmax = 240000, .val = 0x1d },
-+	{ .rfmax = 242000, .val = 0x1f },
-+	{ .rfmax = 247000, .val = 0x20 },
-+	{ .rfmax = 249000, .val = 0x21 },
-+	{ .rfmax = 252000, .val = 0x22 },
-+	{ .rfmax = 253000, .val = 0x23 },
-+	{ .rfmax = 254000, .val = 0x24 },
-+	{ .rfmax = 256000, .val = 0x25 },
-+	{ .rfmax = 259000, .val = 0x26 },
-+	{ .rfmax = 262000, .val = 0x27 },
-+	{ .rfmax = 264000, .val = 0x28 },
-+	{ .rfmax = 267000, .val = 0x29 },
-+	{ .rfmax = 269000, .val = 0x2a },
-+	{ .rfmax = 271000, .val = 0x2b },
-+	{ .rfmax = 273000, .val = 0x2c },
-+	{ .rfmax = 275000, .val = 0x2d },
-+	{ .rfmax = 277000, .val = 0x2e },
-+	{ .rfmax = 279000, .val = 0x2f },
-+	{ .rfmax = 282000, .val = 0x30 },
-+	{ .rfmax = 284000, .val = 0x31 },
-+	{ .rfmax = 286000, .val = 0x32 },
-+	{ .rfmax = 287000, .val = 0x33 },
-+	{ .rfmax = 290000, .val = 0x34 },
-+	{ .rfmax = 293000, .val = 0x35 },
-+	{ .rfmax = 295000, .val = 0x36 },
-+	{ .rfmax = 297000, .val = 0x37 },
-+	{ .rfmax = 300000, .val = 0x38 },
-+	{ .rfmax = 303000, .val = 0x39 },
-+	{ .rfmax = 305000, .val = 0x3a },
-+	{ .rfmax = 306000, .val = 0x3b },
-+	{ .rfmax = 307000, .val = 0x3c },
-+	{ .rfmax = 310000, .val = 0x3d },
-+	{ .rfmax = 312000, .val = 0x3e },
-+	{ .rfmax = 315000, .val = 0x3f },
-+	{ .rfmax = 318000, .val = 0x40 },
-+	{ .rfmax = 320000, .val = 0x41 },
-+	{ .rfmax = 323000, .val = 0x42 },
-+	{ .rfmax = 324000, .val = 0x43 },
-+	{ .rfmax = 325000, .val = 0x44 },
-+	{ .rfmax = 327000, .val = 0x45 },
-+	{ .rfmax = 331000, .val = 0x46 },
-+	{ .rfmax = 334000, .val = 0x47 },
-+	{ .rfmax = 337000, .val = 0x48 },
-+	{ .rfmax = 339000, .val = 0x49 },
-+	{ .rfmax = 340000, .val = 0x4a },
-+	{ .rfmax = 341000, .val = 0x4b },
-+	{ .rfmax = 343000, .val = 0x4c },
-+	{ .rfmax = 345000, .val = 0x4d },
-+	{ .rfmax = 349000, .val = 0x4e },
-+	{ .rfmax = 352000, .val = 0x4f },
-+	{ .rfmax = 353000, .val = 0x50 },
-+	{ .rfmax = 355000, .val = 0x51 },
-+	{ .rfmax = 357000, .val = 0x52 },
-+	{ .rfmax = 359000, .val = 0x53 },
-+	{ .rfmax = 361000, .val = 0x54 },
-+	{ .rfmax = 362000, .val = 0x55 },
-+	{ .rfmax = 364000, .val = 0x56 },
-+	{ .rfmax = 368000, .val = 0x57 },
-+	{ .rfmax = 370000, .val = 0x58 },
-+	{ .rfmax = 372000, .val = 0x59 },
-+	{ .rfmax = 375000, .val = 0x5a },
-+	{ .rfmax = 376000, .val = 0x5b },
-+	{ .rfmax = 377000, .val = 0x5c },
-+	{ .rfmax = 379000, .val = 0x5d },
-+	{ .rfmax = 382000, .val = 0x5e },
-+	{ .rfmax = 384000, .val = 0x5f },
-+	{ .rfmax = 385000, .val = 0x60 },
-+	{ .rfmax = 386000, .val = 0x61 },
-+	{ .rfmax = 388000, .val = 0x62 },
-+	{ .rfmax = 390000, .val = 0x63 },
-+	{ .rfmax = 393000, .val = 0x64 },
-+	{ .rfmax = 394000, .val = 0x65 },
-+	{ .rfmax = 396000, .val = 0x66 },
-+	{ .rfmax = 397000, .val = 0x67 },
-+	{ .rfmax = 398000, .val = 0x68 },
-+	{ .rfmax = 400000, .val = 0x69 },
-+	{ .rfmax = 402000, .val = 0x6a },
-+	{ .rfmax = 403000, .val = 0x6b },
-+	{ .rfmax = 407000, .val = 0x6c },
-+	{ .rfmax = 408000, .val = 0x6d },
-+	{ .rfmax = 409000, .val = 0x6e },
-+	{ .rfmax = 410000, .val = 0x6f },
-+	{ .rfmax = 411000, .val = 0x70 },
-+	{ .rfmax = 412000, .val = 0x71 },
-+	{ .rfmax = 413000, .val = 0x72 },
-+	{ .rfmax = 414000, .val = 0x73 },
-+	{ .rfmax = 417000, .val = 0x74 },
-+	{ .rfmax = 418000, .val = 0x75 },
-+	{ .rfmax = 420000, .val = 0x76 },
-+	{ .rfmax = 422000, .val = 0x77 },
-+	{ .rfmax = 423000, .val = 0x78 },
-+	{ .rfmax = 424000, .val = 0x79 },
-+	{ .rfmax = 427000, .val = 0x7a },
-+	{ .rfmax = 428000, .val = 0x7b },
-+	{ .rfmax = 429000, .val = 0x7d },
-+	{ .rfmax = 432000, .val = 0x7f },
-+	{ .rfmax = 434000, .val = 0x80 },
-+	{ .rfmax = 435000, .val = 0x81 },
-+	{ .rfmax = 436000, .val = 0x83 },
-+	{ .rfmax = 437000, .val = 0x84 },
-+	{ .rfmax = 438000, .val = 0x85 },
-+	{ .rfmax = 439000, .val = 0x86 },
-+	{ .rfmax = 440000, .val = 0x87 },
-+	{ .rfmax = 441000, .val = 0x88 },
-+	{ .rfmax = 442000, .val = 0x89 },
-+	{ .rfmax = 445000, .val = 0x8a },
-+	{ .rfmax = 446000, .val = 0x8b },
-+	{ .rfmax = 447000, .val = 0x8c },
-+	{ .rfmax = 448000, .val = 0x8e },
-+	{ .rfmax = 449000, .val = 0x8f },
-+	{ .rfmax = 450000, .val = 0x90 },
-+	{ .rfmax = 452000, .val = 0x91 },
-+	{ .rfmax = 453000, .val = 0x93 },
-+	{ .rfmax = 454000, .val = 0x94 },
-+	{ .rfmax = 456000, .val = 0x96 },
-+	{ .rfmax = 457000, .val = 0x98 },
-+	{ .rfmax = 461000, .val = 0x11 },
-+	{ .rfmax = 468000, .val = 0x12 },
-+	{ .rfmax = 472000, .val = 0x13 },
-+	{ .rfmax = 473000, .val = 0x14 },
-+	{ .rfmax = 474000, .val = 0x15 },
-+	{ .rfmax = 481000, .val = 0x16 },
-+	{ .rfmax = 486000, .val = 0x17 },
-+	{ .rfmax = 491000, .val = 0x18 },
-+	{ .rfmax = 498000, .val = 0x19 },
-+	{ .rfmax = 499000, .val = 0x1a },
-+	{ .rfmax = 501000, .val = 0x1b },
-+	{ .rfmax = 506000, .val = 0x1c },
-+	{ .rfmax = 511000, .val = 0x1d },
-+	{ .rfmax = 516000, .val = 0x1e },
-+	{ .rfmax = 520000, .val = 0x1f },
-+	{ .rfmax = 521000, .val = 0x20 },
-+	{ .rfmax = 525000, .val = 0x21 },
-+	{ .rfmax = 529000, .val = 0x22 },
-+	{ .rfmax = 533000, .val = 0x23 },
-+	{ .rfmax = 539000, .val = 0x24 },
-+	{ .rfmax = 541000, .val = 0x25 },
-+	{ .rfmax = 547000, .val = 0x26 },
-+	{ .rfmax = 549000, .val = 0x27 },
-+	{ .rfmax = 551000, .val = 0x28 },
-+	{ .rfmax = 556000, .val = 0x29 },
-+	{ .rfmax = 561000, .val = 0x2a },
-+	{ .rfmax = 563000, .val = 0x2b },
-+	{ .rfmax = 565000, .val = 0x2c },
-+	{ .rfmax = 569000, .val = 0x2d },
-+	{ .rfmax = 571000, .val = 0x2e },
-+	{ .rfmax = 577000, .val = 0x2f },
-+	{ .rfmax = 580000, .val = 0x30 },
-+	{ .rfmax = 582000, .val = 0x31 },
-+	{ .rfmax = 584000, .val = 0x32 },
-+	{ .rfmax = 588000, .val = 0x33 },
-+	{ .rfmax = 591000, .val = 0x34 },
-+	{ .rfmax = 596000, .val = 0x35 },
-+	{ .rfmax = 598000, .val = 0x36 },
-+	{ .rfmax = 603000, .val = 0x37 },
-+	{ .rfmax = 604000, .val = 0x38 },
-+	{ .rfmax = 606000, .val = 0x39 },
-+	{ .rfmax = 612000, .val = 0x3a },
-+	{ .rfmax = 615000, .val = 0x3b },
-+	{ .rfmax = 617000, .val = 0x3c },
-+	{ .rfmax = 621000, .val = 0x3d },
-+	{ .rfmax = 622000, .val = 0x3e },
-+	{ .rfmax = 625000, .val = 0x3f },
-+	{ .rfmax = 632000, .val = 0x40 },
-+	{ .rfmax = 633000, .val = 0x41 },
-+	{ .rfmax = 634000, .val = 0x42 },
-+	{ .rfmax = 642000, .val = 0x43 },
-+	{ .rfmax = 643000, .val = 0x44 },
-+	{ .rfmax = 647000, .val = 0x45 },
-+	{ .rfmax = 650000, .val = 0x46 },
-+	{ .rfmax = 652000, .val = 0x47 },
-+	{ .rfmax = 657000, .val = 0x48 },
-+	{ .rfmax = 661000, .val = 0x49 },
-+	{ .rfmax = 662000, .val = 0x4a },
-+	{ .rfmax = 665000, .val = 0x4b },
-+	{ .rfmax = 667000, .val = 0x4c },
-+	{ .rfmax = 670000, .val = 0x4d },
-+	{ .rfmax = 673000, .val = 0x4e },
-+	{ .rfmax = 676000, .val = 0x4f },
-+	{ .rfmax = 677000, .val = 0x50 },
-+	{ .rfmax = 681000, .val = 0x51 },
-+	{ .rfmax = 683000, .val = 0x52 },
-+	{ .rfmax = 686000, .val = 0x53 },
-+	{ .rfmax = 688000, .val = 0x54 },
-+	{ .rfmax = 689000, .val = 0x55 },
-+	{ .rfmax = 691000, .val = 0x56 },
-+	{ .rfmax = 695000, .val = 0x57 },
-+	{ .rfmax = 698000, .val = 0x58 },
-+	{ .rfmax = 703000, .val = 0x59 },
-+	{ .rfmax = 704000, .val = 0x5a },
-+	{ .rfmax = 705000, .val = 0x5b },
-+	{ .rfmax = 707000, .val = 0x5c },
-+	{ .rfmax = 710000, .val = 0x5d },
-+	{ .rfmax = 712000, .val = 0x5e },
-+	{ .rfmax = 717000, .val = 0x5f },
-+	{ .rfmax = 718000, .val = 0x60 },
-+	{ .rfmax = 721000, .val = 0x61 },
-+	{ .rfmax = 722000, .val = 0x62 },
-+	{ .rfmax = 723000, .val = 0x63 },
-+	{ .rfmax = 725000, .val = 0x64 },
-+	{ .rfmax = 727000, .val = 0x65 },
-+	{ .rfmax = 730000, .val = 0x66 },
-+	{ .rfmax = 732000, .val = 0x67 },
-+	{ .rfmax = 735000, .val = 0x68 },
-+	{ .rfmax = 740000, .val = 0x69 },
-+	{ .rfmax = 741000, .val = 0x6a },
-+	{ .rfmax = 742000, .val = 0x6b },
-+	{ .rfmax = 743000, .val = 0x6c },
-+	{ .rfmax = 745000, .val = 0x6d },
-+	{ .rfmax = 747000, .val = 0x6e },
-+	{ .rfmax = 748000, .val = 0x6f },
-+	{ .rfmax = 750000, .val = 0x70 },
-+	{ .rfmax = 752000, .val = 0x71 },
-+	{ .rfmax = 754000, .val = 0x72 },
-+	{ .rfmax = 757000, .val = 0x73 },
-+	{ .rfmax = 758000, .val = 0x74 },
-+	{ .rfmax = 760000, .val = 0x75 },
-+	{ .rfmax = 763000, .val = 0x76 },
-+	{ .rfmax = 764000, .val = 0x77 },
-+	{ .rfmax = 766000, .val = 0x78 },
-+	{ .rfmax = 767000, .val = 0x79 },
-+	{ .rfmax = 768000, .val = 0x7a },
-+	{ .rfmax = 773000, .val = 0x7b },
-+	{ .rfmax = 774000, .val = 0x7c },
-+	{ .rfmax = 776000, .val = 0x7d },
-+	{ .rfmax = 777000, .val = 0x7e },
-+	{ .rfmax = 778000, .val = 0x7f },
-+	{ .rfmax = 779000, .val = 0x80 },
-+	{ .rfmax = 781000, .val = 0x81 },
-+	{ .rfmax = 783000, .val = 0x82 },
-+	{ .rfmax = 784000, .val = 0x83 },
-+	{ .rfmax = 785000, .val = 0x84 },
-+	{ .rfmax = 786000, .val = 0x85 },
-+	{ .rfmax = 793000, .val = 0x86 },
-+	{ .rfmax = 794000, .val = 0x87 },
-+	{ .rfmax = 795000, .val = 0x88 },
-+	{ .rfmax = 797000, .val = 0x89 },
-+	{ .rfmax = 799000, .val = 0x8a },
-+	{ .rfmax = 801000, .val = 0x8b },
-+	{ .rfmax = 802000, .val = 0x8c },
-+	{ .rfmax = 803000, .val = 0x8d },
-+	{ .rfmax = 804000, .val = 0x8e },
-+	{ .rfmax = 810000, .val = 0x90 },
-+	{ .rfmax = 811000, .val = 0x91 },
-+	{ .rfmax = 812000, .val = 0x92 },
-+	{ .rfmax = 814000, .val = 0x93 },
-+	{ .rfmax = 816000, .val = 0x94 },
-+	{ .rfmax = 817000, .val = 0x96 },
-+	{ .rfmax = 818000, .val = 0x97 },
-+	{ .rfmax = 820000, .val = 0x98 },
-+	{ .rfmax = 821000, .val = 0x99 },
-+	{ .rfmax = 822000, .val = 0x9a },
-+	{ .rfmax = 828000, .val = 0x9b },
-+	{ .rfmax = 829000, .val = 0x9d },
-+	{ .rfmax = 830000, .val = 0x9f },
-+	{ .rfmax = 831000, .val = 0xa0 },
-+	{ .rfmax = 833000, .val = 0xa1 },
-+	{ .rfmax = 835000, .val = 0xa2 },
-+	{ .rfmax = 836000, .val = 0xa3 },
-+	{ .rfmax = 837000, .val = 0xa4 },
-+	{ .rfmax = 838000, .val = 0xa6 },
-+	{ .rfmax = 840000, .val = 0xa8 },
-+	{ .rfmax = 842000, .val = 0xa9 },
-+	{ .rfmax = 845000, .val = 0xaa },
-+	{ .rfmax = 846000, .val = 0xab },
-+	{ .rfmax = 847000, .val = 0xad },
-+	{ .rfmax = 848000, .val = 0xae },
-+	{ .rfmax = 852000, .val = 0xaf },
-+	{ .rfmax = 853000, .val = 0xb0 },
-+	{ .rfmax = 858000, .val = 0xb1 },
-+	{ .rfmax = 860000, .val = 0xb2 },
-+	{ .rfmax = 861000, .val = 0xb3 },
-+	{ .rfmax = 862000, .val = 0xb4 },
-+	{ .rfmax = 863000, .val = 0xb6 },
-+	{ .rfmax = 864000, .val = 0xb8 },
-+	{ .rfmax = 865000, .val = 0xb9 },
-+	{ .rfmax =      0, .val = 0x00 }, /* end */
-+};
++#define SYSCONFIG3		6	/* System Configuration 3 */
++#define SYSCONFIG3_SMUTER	0xc000	/* bits 15..14: Softmute Attack/Recover Rate */
++#define SYSCONFIG3_SMUTEA	0x3000	/* bits 13..12: Softmute Attenuation */
++#define SYSCONFIG3_SKSNR	0x00f0	/* bits 07..04: Seek SNR Threshold */
++#define SYSCONFIG3_SKCNT	0x000f	/* bits 03..00: Seek FM Impulse Detection Threshold */
 +
-+static struct tda18271_map tda18271_ir_measure[] = {
-+	{ .rfmax =  30000, .val = 4 },
-+	{ .rfmax = 200000, .val = 5 },
-+	{ .rfmax = 600000, .val = 6 },
-+	{ .rfmax = 865000, .val = 7 },
-+	{ .rfmax =      0, .val = 0 }, /* end */
-+};
++#define TEST1			7	/* Test 1 */
++#define TEST1_AHIZEN		0x4000	/* bits 14..14: Audio High-Z Enable */
 +
-+static struct tda18271_map tda18271_rf_cal_dc_over_dt[] = {
-+	{ .rfmax =  47900, .val = 0x00 },
-+	{ .rfmax =  55000, .val = 0x00 },
-+	{ .rfmax =  61100, .val = 0x0a },
-+	{ .rfmax =  64000, .val = 0x0a },
-+	{ .rfmax =  82000, .val = 0x14 },
-+	{ .rfmax =  84000, .val = 0x19 },
-+	{ .rfmax = 119000, .val = 0x1c },
-+	{ .rfmax = 124000, .val = 0x20 },
-+	{ .rfmax = 129000, .val = 0x2a },
-+	{ .rfmax = 134000, .val = 0x32 },
-+	{ .rfmax = 139000, .val = 0x39 },
-+	{ .rfmax = 144000, .val = 0x3e },
-+	{ .rfmax = 149000, .val = 0x3f },
-+	{ .rfmax = 152600, .val = 0x40 },
-+	{ .rfmax = 154000, .val = 0x40 },
-+	{ .rfmax = 164700, .val = 0x41 },
-+	{ .rfmax = 203500, .val = 0x32 },
-+	{ .rfmax = 353000, .val = 0x19 },
-+	{ .rfmax = 356000, .val = 0x1a },
-+	{ .rfmax = 359000, .val = 0x1b },
-+	{ .rfmax = 363000, .val = 0x1c },
-+	{ .rfmax = 366000, .val = 0x1d },
-+	{ .rfmax = 369000, .val = 0x1e },
-+	{ .rfmax = 373000, .val = 0x1f },
-+	{ .rfmax = 376000, .val = 0x20 },
-+	{ .rfmax = 379000, .val = 0x21 },
-+	{ .rfmax = 383000, .val = 0x22 },
-+	{ .rfmax = 386000, .val = 0x23 },
-+	{ .rfmax = 389000, .val = 0x24 },
-+	{ .rfmax = 393000, .val = 0x25 },
-+	{ .rfmax = 396000, .val = 0x26 },
-+	{ .rfmax = 399000, .val = 0x27 },
-+	{ .rfmax = 402000, .val = 0x28 },
-+	{ .rfmax = 404000, .val = 0x29 },
-+	{ .rfmax = 407000, .val = 0x2a },
-+	{ .rfmax = 409000, .val = 0x2b },
-+	{ .rfmax = 412000, .val = 0x2c },
-+	{ .rfmax = 414000, .val = 0x2d },
-+	{ .rfmax = 417000, .val = 0x2e },
-+	{ .rfmax = 419000, .val = 0x2f },
-+	{ .rfmax = 422000, .val = 0x30 },
-+	{ .rfmax = 424000, .val = 0x31 },
-+	{ .rfmax = 427000, .val = 0x32 },
-+	{ .rfmax = 429000, .val = 0x33 },
-+	{ .rfmax = 432000, .val = 0x34 },
-+	{ .rfmax = 434000, .val = 0x35 },
-+	{ .rfmax = 437000, .val = 0x36 },
-+	{ .rfmax = 439000, .val = 0x37 },
-+	{ .rfmax = 442000, .val = 0x38 },
-+	{ .rfmax = 444000, .val = 0x39 },
-+	{ .rfmax = 447000, .val = 0x3a },
-+	{ .rfmax = 449000, .val = 0x3b },
-+	{ .rfmax = 457800, .val = 0x3c },
-+	{ .rfmax = 465000, .val = 0x0f },
-+	{ .rfmax = 477000, .val = 0x12 },
-+	{ .rfmax = 483000, .val = 0x14 },
-+	{ .rfmax = 502000, .val = 0x19 },
-+	{ .rfmax = 508000, .val = 0x1b },
-+	{ .rfmax = 519000, .val = 0x1c },
-+	{ .rfmax = 522000, .val = 0x1d },
-+	{ .rfmax = 524000, .val = 0x1e },
-+	{ .rfmax = 534000, .val = 0x1f },
-+	{ .rfmax = 549000, .val = 0x20 },
-+	{ .rfmax = 554000, .val = 0x22 },
-+	{ .rfmax = 584000, .val = 0x24 },
-+	{ .rfmax = 589000, .val = 0x26 },
-+	{ .rfmax = 658000, .val = 0x27 },
-+	{ .rfmax = 664000, .val = 0x2c },
-+	{ .rfmax = 669000, .val = 0x2d },
-+	{ .rfmax = 699000, .val = 0x2e },
-+	{ .rfmax = 704000, .val = 0x30 },
-+	{ .rfmax = 709000, .val = 0x31 },
-+	{ .rfmax = 714000, .val = 0x32 },
-+	{ .rfmax = 724000, .val = 0x33 },
-+	{ .rfmax = 729000, .val = 0x36 },
-+	{ .rfmax = 739000, .val = 0x38 },
-+	{ .rfmax = 744000, .val = 0x39 },
-+	{ .rfmax = 749000, .val = 0x3b },
-+	{ .rfmax = 754000, .val = 0x3c },
-+	{ .rfmax = 759000, .val = 0x3d },
-+	{ .rfmax = 764000, .val = 0x3e },
-+	{ .rfmax = 769000, .val = 0x3f },
-+	{ .rfmax = 774000, .val = 0x40 },
-+	{ .rfmax = 779000, .val = 0x41 },
-+	{ .rfmax = 784000, .val = 0x43 },
-+	{ .rfmax = 789000, .val = 0x46 },
-+	{ .rfmax = 794000, .val = 0x48 },
-+	{ .rfmax = 799000, .val = 0x4b },
-+	{ .rfmax = 804000, .val = 0x4f },
-+	{ .rfmax = 809000, .val = 0x54 },
-+	{ .rfmax = 814000, .val = 0x59 },
-+	{ .rfmax = 819000, .val = 0x5d },
-+	{ .rfmax = 824000, .val = 0x61 },
-+	{ .rfmax = 829000, .val = 0x68 },
-+	{ .rfmax = 834000, .val = 0x6e },
-+	{ .rfmax = 839000, .val = 0x75 },
-+	{ .rfmax = 844000, .val = 0x7e },
-+	{ .rfmax = 849000, .val = 0x82 },
-+	{ .rfmax = 854000, .val = 0x84 },
-+	{ .rfmax = 859000, .val = 0x8f },
-+	{ .rfmax = 865000, .val = 0x9a },
-+	{ .rfmax =      0, .val = 0x00 }, /* end */
-+};
++#define TEST2			8	/* Test 2 */
++/* TEST2 only contains reserved bits */
 +
-+/*---------------------------------------------------------------------*/
++#define BOOTCONFIG		9	/* Boot Configuration */
++/* BOOTCONFIG only contains reserved bits */
 +
-+struct tda18271_thermo_map {
-+	u8 d;
-+	u8 r0;
-+	u8 r1;
-+};
++#define STATUSRSSI		10	/* Status RSSI */
++#define STATUSRSSI_RDSR		0x8000	/* bits 15..15: RDS Ready (Si4701 only) */
++#define STATUSRSSI_STC		0x4000	/* bits 14..14: Seek/Tune Complete */
++#define STATUSRSSI_SF		0x2000	/* bits 13..13: Seek Fail/Band Limit */
++#define STATUSRSSI_AFCRL	0x1000	/* bits 12..12: AFC Rail */
++#define STATUSRSSI_RDSS		0x0800	/* bits 11..11: RDS Synchronized (Si4701 only) */
++#define STATUSRSSI_BLERA	0x0600	/* bits 10..09: RDS Block A Errors (Si4701 only) */
++#define STATUSRSSI_ST		0x0100	/* bits 08..08: Stereo Indicator */
++#define STATUSRSSI_RSSI		0x00ff	/* bits 07..00: RSSI (Received Signal Strength Indicator) */
 +
-+static struct tda18271_thermo_map tda18271_thermometer[] = {
-+	{ .d = 0x00, .r0 = 60, .r1 =  92 },
-+	{ .d = 0x01, .r0 = 62, .r1 =  94 },
-+	{ .d = 0x02, .r0 = 66, .r1 =  98 },
-+	{ .d = 0x03, .r0 = 64, .r1 =  96 },
-+	{ .d = 0x04, .r0 = 74, .r1 = 106 },
-+	{ .d = 0x05, .r0 = 72, .r1 = 104 },
-+	{ .d = 0x06, .r0 = 68, .r1 = 100 },
-+	{ .d = 0x07, .r0 = 70, .r1 = 102 },
-+	{ .d = 0x08, .r0 = 90, .r1 = 122 },
-+	{ .d = 0x09, .r0 = 88, .r1 = 120 },
-+	{ .d = 0x0a, .r0 = 84, .r1 = 116 },
-+	{ .d = 0x0b, .r0 = 86, .r1 = 118 },
-+	{ .d = 0x0c, .r0 = 76, .r1 = 108 },
-+	{ .d = 0x0d, .r0 = 78, .r1 = 110 },
-+	{ .d = 0x0e, .r0 = 82, .r1 = 114 },
-+	{ .d = 0x0f, .r0 = 80, .r1 = 112 },
-+	{ .d = 0x00, .r0 =  0, .r1 =   0 }, /* end */
-+};
++#define READCHAN		11	/* Read Channel */
++#define READCHAN_BLERB		0xc000	/* bits 15..14: RDS Block D Errors (Si4701 only) */
++#define READCHAN_BLERC		0x3000	/* bits 13..12: RDS Block C Errors (Si4701 only) */
++#define READCHAN_BLERD		0x0c00	/* bits 11..10: RDS Block B Errors (Si4701 only) */
++#define READCHAN_READCHAN	0x03ff	/* bits 09..00: Read Channel */
 +
-+int tda18271_lookup_thermometer(struct dvb_frontend *fe)
-+{
-+	struct tda18271_priv *priv = fe->tuner_priv;
-+	unsigned char *regs = priv->tda18271_regs;
-+	int val, i = 0;
++#define RDSA			12	/* RDSA */
++#define RDSA_RDSA		0xffff	/* bits 15..00: RDS Block A Data (Si4701 only) */
 +
-+	while (tda18271_thermometer[i].d < (regs[R_TM] & 0x0f)) {
-+		if (tda18271_thermometer[i + 1].d == 0)
-+			break;
-+		i++;
-+	}
++#define RDSB			13	/* RDSB */
++#define RDSB_RDSB		0xffff	/* bits 15..00: RDS Block B Data (Si4701 only) */
 +
-+	if ((regs[R_TM] & 0x20) == 0x20)
-+		val = tda18271_thermometer[i].r1;
-+	else
-+		val = tda18271_thermometer[i].r0;
++#define RDSC			14	/* RDSC */
++#define RDSC_RDSC		0xffff	/* bits 15..00: RDS Block C Data (Si4701 only) */
 +
-+	tda_map("(%d) tm = %d\n", i, val);
++#define RDSD			15	/* RDSD */
++#define RDSD_RDSD		0xffff	/* bits 15..00: RDS Block D Data (Si4701 only) */
 +
-+	return val;
-+}
 +
-+/*---------------------------------------------------------------------*/
 +
-+struct tda18271_cid_target_map {
-+	u32 rfmax;
-+	u8  target;
-+	u16 limit;
-+};
++/**************************************************************************
++ * USB HID Reports
++ **************************************************************************/
 +
-+static struct tda18271_cid_target_map tda18271_cid_target[] = {
-+	{ .rfmax =  46000, .target = 0x04, .limit =  1800 },
-+	{ .rfmax =  52200, .target = 0x0a, .limit =  1500 },
-+	{ .rfmax =  79100, .target = 0x01, .limit =  4000 },
-+	{ .rfmax = 136800, .target = 0x18, .limit =  4000 },
-+	{ .rfmax = 156700, .target = 0x18, .limit =  4000 },
-+	{ .rfmax = 156700, .target = 0x18, .limit =  4000 },
-+	{ .rfmax = 186250, .target = 0x0a, .limit =  4000 },
-+	{ .rfmax = 230000, .target = 0x0a, .limit =  4000 },
-+	{ .rfmax = 345000, .target = 0x18, .limit =  4000 },
-+	{ .rfmax = 426000, .target = 0x0e, .limit =  4000 },
-+	{ .rfmax = 489500, .target = 0x1e, .limit =  4000 },
-+	{ .rfmax = 697500, .target = 0x32, .limit =  4000 },
-+	{ .rfmax = 842000, .target = 0x3a, .limit =  4000 },
-+	{ .rfmax =      0, .target = 0x00, .limit =     0 }, /* end */
-+};
++/* Reports 1-16 give direct read/write access to the 16 Si470x registers */
++/* with the (REPORT_ID - 1) corresponding to the register address across USB */
++/* endpoint 0 using GET_REPORT and SET_REPORT */
++#define REGISTER_REPORT_SIZE	(RADIO_REGISTER_SIZE + 1)
++#define REGISTER_REPORT(reg)	((reg) + 1)
 +
-+int tda18271_lookup_cid_target(struct dvb_frontend *fe,
-+			       u32 *freq, u8 *cid_target, u16 *count_limit)
-+{
-+	int i = 0;
++/* Report 17 gives direct read/write access to the entire Si470x register */
++/* map across endpoint 0 using GET_REPORT and SET_REPORT */
++#define ENTIRE_REPORT_SIZE	(RADIO_REGISTER_NUM * RADIO_REGISTER_SIZE + 1)
++#define ENTIRE_REPORT		17
 +
-+	while ((tda18271_cid_target[i].rfmax * 1000) < *freq) {
-+		if (tda18271_cid_target[i + 1].rfmax == 0)
-+			break;
-+		i++;
-+	}
-+	*cid_target  = tda18271_cid_target[i].target;
-+	*count_limit = tda18271_cid_target[i].limit;
++/* Report 18 is used to send the lowest 6 Si470x registers up the HID */
++/* interrupt endpoint 1 to Windows every 20 milliseconds for status */
++#define RDS_REPORT_SIZE		(RDS_REGISTER_NUM * RADIO_REGISTER_SIZE + 1)
++#define RDS_REPORT		18
 +
-+	tda_map("(%d) cid_target = %02x, count_limit = %d\n", i,
-+		tda18271_cid_target[i].target, tda18271_cid_target[i].limit);
++/* Report 19: LED state */
++#define LED_REPORT_SIZE		3
++#define LED_REPORT		19
 +
-+	return 0;
-+}
++/* Report 19: stream */
++#define STREAM_REPORT_SIZE	3
++#define	STREAM_REPORT		19
 +
-+/*---------------------------------------------------------------------*/
++/* Report 20: scratch */
++#define SCRATCH_PAGE_SIZE	63
++#define SCRATCH_REPORT_SIZE	(SCRATCH_PAGE_SIZE + 1)
++#define SCRATCH_REPORT		20
 +
-+static struct tda18271_rf_tracking_filter_cal tda18271_rf_band_template[] = {
-+	{ .rfmax =  47900, .rfband = 0x00,
-+	  .rf1_def =  46000, .rf2_def =      0, .rf3_def =      0 },
-+	{ .rfmax =  61100, .rfband = 0x01,
-+	  .rf1_def =  52200, .rf2_def =      0, .rf3_def =      0 },
-+	{ .rfmax = 152600, .rfband = 0x02,
-+	  .rf1_def =  70100, .rf2_def = 136800, .rf3_def =      0 },
-+	{ .rfmax = 164700, .rfband = 0x03,
-+	  .rf1_def = 156700, .rf2_def =      0, .rf3_def =      0 },
-+	{ .rfmax = 203500, .rfband = 0x04,
-+	  .rf1_def = 186250, .rf2_def =      0, .rf3_def =      0 },
-+	{ .rfmax = 457800, .rfband = 0x05,
-+	  .rf1_def = 230000, .rf2_def = 345000, .rf3_def = 426000 },
-+	{ .rfmax = 865000, .rfband = 0x06,
-+	  .rf1_def = 489500, .rf2_def = 697500, .rf3_def = 842000 },
-+	{ .rfmax =      0, .rfband = 0x00,
-+	  .rf1_def =      0, .rf2_def =      0, .rf3_def =      0 }, /* end */
-+};
++/* Reports 19-22: flash upgrade of the C8051F321 */
++#define WRITE_REPORT		19
++#define FLASH_REPORT		20
++#define CRC_REPORT		21
++#define RESPONSE_REPORT		22
 +
-+int tda18271_lookup_rf_band(struct dvb_frontend *fe, u32 *freq, u8 *rf_band)
-+{
-+	struct tda18271_priv *priv = fe->tuner_priv;
-+	struct tda18271_rf_tracking_filter_cal *map = priv->rf_cal_state;
-+	int i = 0;
++/* Report 23: currently unused, but can accept 60 byte reports on the HID */
++/* interrupt out endpoint 2 every 1 millisecond */
++#define UNUSED_REPORT		23
 +
-+	while ((map[i].rfmax * 1000) < *freq) {
-+		if (tda18271_debug & DBG_ADV)
-+			tda_map("(%d) rfmax = %d < freq = %d, "
-+				"rf1_def = %d, rf2_def = %d, rf3_def = %d, "
-+				"rf1 = %d, rf2 = %d, rf3 = %d, "
-+				"rf_a1 = %d, rf_a2 = %d, "
-+				"rf_b1 = %d, rf_b2 = %d\n",
-+				i, map[i].rfmax * 1000, *freq,
-+				map[i].rf1_def, map[i].rf2_def, map[i].rf3_def,
-+				map[i].rf1, map[i].rf2, map[i].rf3,
-+				map[i].rf_a1, map[i].rf_a2,
-+				map[i].rf_b1, map[i].rf_b2);
-+		if (map[i].rfmax == 0)
-+			return -EINVAL;
-+		i++;
-+	}
-+	if (rf_band)
-+		*rf_band = map[i].rfband;
 +
-+	tda_map("(%d) rf_band = %02x\n", i, map[i].rfband);
 +
-+	return i;
-+}
++/**************************************************************************
++ * Software/Hardware Versions
++ **************************************************************************/
++#define RADIO_SW_VERSION_NOT_BOOTLOADABLE	6
++#define RADIO_SW_VERSION			7
++#define RADIO_SW_VERSION_CURRENT		15
++#define RADIO_HW_VERSION			1
 +
-+/*---------------------------------------------------------------------*/
++#define SCRATCH_PAGE_SW_VERSION	1
++#define SCRATCH_PAGE_HW_VERSION	2
 +
-+struct tda18271_map_layout {
-+	struct tda18271_pll_map *main_pll;
-+	struct tda18271_pll_map *cal_pll;
 +
-+	struct tda18271_map *rf_cal;
-+	struct tda18271_map *rf_cal_kmco;
-+	struct tda18271_map *rf_cal_dc_over_dt;
 +
-+	struct tda18271_map *bp_filter;
-+	struct tda18271_map *rf_band;
-+	struct tda18271_map *gain_taper;
-+	struct tda18271_map *ir_measure;
-+};
++/**************************************************************************
++ * LED State Definitions
++ **************************************************************************/
++#define LED_COMMAND		0x35
 +
-+/*---------------------------------------------------------------------*/
++#define NO_CHANGE_LED		0x00
++#define ALL_COLOR_LED		0x01	/* streaming state */
++#define BLINK_GREEN_LED		0x02	/* connect state */
++#define BLINK_RED_LED		0x04
++#define BLINK_ORANGE_LED	0x10	/* disconnect state */
++#define SOLID_GREEN_LED		0x20	/* tuning/seeking state */
++#define SOLID_RED_LED		0x40	/* bootload state */
++#define SOLID_ORANGE_LED	0x80
 +
-+int tda18271_lookup_pll_map(struct dvb_frontend *fe,
-+			    enum tda18271_map_type map_type,
-+			    u32 *freq, u8 *post_div, u8 *div)
-+{
-+	struct tda18271_priv *priv = fe->tuner_priv;
-+	struct tda18271_pll_map *map = NULL;
-+	unsigned int i = 0;
-+	char *map_name;
-+	int ret = 0;
 +
-+	BUG_ON(!priv->maps);
 +
-+	switch (map_type) {
-+	case MAIN_PLL:
-+		map = priv->maps->main_pll;
-+		map_name = "main_pll";
-+		break;
-+	case CAL_PLL:
-+		map = priv->maps->cal_pll;
-+		map_name = "cal_pll";
-+		break;
-+	default:
-+		/* we should never get here */
-+		map_name = "undefined";
-+		break;
-+	}
++/**************************************************************************
++ * Stream State Definitions
++ **************************************************************************/
++#define STREAM_COMMAND	0x36
++#define STREAM_VIDPID	0x00
++#define STREAM_AUDIO	0xff
 +
-+	if (!map) {
-+		tda_warn("%s map is not set!\n", map_name);
-+		ret = -EINVAL;
-+		goto fail;
-+	}
 +
-+	while ((map[i].lomax * 1000) < *freq) {
-+		if (map[i + 1].lomax == 0) {
-+			tda_map("%s: frequency (%d) out of range\n",
-+				map_name, *freq);
-+			ret = -ERANGE;
-+			break;
-+		}
-+		i++;
-+	}
-+	*post_div = map[i].pd;
-+	*div      = map[i].d;
 +
-+	tda_map("(%d) %s: post div = 0x%02x, div = 0x%02x\n",
-+		i, map_name, *post_div, *div);
-+fail:
-+	return ret;
-+}
++/**************************************************************************
++ * Bootloader / Flash Commands
++ **************************************************************************/
 +
-+int tda18271_lookup_map(struct dvb_frontend *fe,
-+			enum tda18271_map_type map_type,
-+			u32 *freq, u8 *val)
-+{
-+	struct tda18271_priv *priv = fe->tuner_priv;
-+	struct tda18271_map *map = NULL;
-+	unsigned int i = 0;
-+	char *map_name;
-+	int ret = 0;
++/* unique id sent to bootloader and required to put into a bootload state */
++#define UNIQUE_BL_ID		0x34
 +
-+	BUG_ON(!priv->maps);
++/* mask for the flash data */
++#define FLASH_DATA_MASK		0x55
 +
-+	switch (map_type) {
-+	case BP_FILTER:
-+		map = priv->maps->bp_filter;
-+		map_name = "bp_filter";
-+		break;
-+	case RF_CAL_KMCO:
-+		map = priv->maps->rf_cal_kmco;
-+		map_name = "km";
-+		break;
-+	case RF_BAND:
-+		map = priv->maps->rf_band;
-+		map_name = "rf_band";
-+		break;
-+	case GAIN_TAPER:
-+		map = priv->maps->gain_taper;
-+		map_name = "gain_taper";
-+		break;
-+	case RF_CAL:
-+		map = priv->maps->rf_cal;
-+		map_name = "rf_cal";
-+		break;
-+	case IR_MEASURE:
-+		map = priv->maps->ir_measure;
-+		map_name = "ir_measure";
-+		break;
-+	case RF_CAL_DC_OVER_DT:
-+		map = priv->maps->rf_cal_dc_over_dt;
-+		map_name = "rf_cal_dc_over_dt";
-+		break;
-+	default:
-+		/* we should never get here */
-+		map_name = "undefined";
-+		break;
-+	}
++/* bootloader commands */
++#define GET_SW_VERSION_COMMAND	0x00
++#define	SET_PAGE_COMMAND	0x01
++#define ERASE_PAGE_COMMAND	0x02
++#define WRITE_PAGE_COMMAND	0x03
++#define CRC_ON_PAGE_COMMAND	0x04
++#define READ_FLASH_BYTE_COMMAND	0x05
++#define RESET_DEVICE_COMMAND	0x06
++#define GET_HW_VERSION_COMMAND	0x07
++#define BLANK			0xff
 +
-+	if (!map) {
-+		tda_warn("%s map is not set!\n", map_name);
-+		ret = -EINVAL;
-+		goto fail;
-+	}
++/* bootloader command responses */
++#define COMMAND_OK		0x01
++#define COMMAND_FAILED		0x02
++#define COMMAND_PENDING		0x03
 +
-+	while ((map[i].rfmax * 1000) < *freq) {
-+		if (map[i + 1].rfmax == 0) {
-+			tda_map("%s: frequency (%d) out of range\n",
-+				map_name, *freq);
-+			ret = -ERANGE;
-+			break;
-+		}
-+		i++;
-+	}
-+	*val = map[i].val;
++/* buffer sizes */
++#define COMMAND_BUFFER_SIZE	4
++#define RESPONSE_BUFFER_SIZE	2
++#define FLASH_BUFFER_SIZE	64
++#define CRC_BUFFER_SIZE		3
 +
-+	tda_map("(%d) %s: 0x%02x\n", i, map_name, *val);
-+fail:
-+	return ret;
-+}
 +
-+/*---------------------------------------------------------------------*/
 +
-+static struct tda18271_std_map tda18271c1_std_map = {
-+	.fm_radio = { .if_freq = 1250, .std_bits = 0x18 },
-+	.atv_b    = { .if_freq = 6750, .std_bits = 0x0e },
-+	.atv_dk   = { .if_freq = 7750, .std_bits = 0x0f },
-+	.atv_gh   = { .if_freq = 7750, .std_bits = 0x0f },
-+	.atv_i    = { .if_freq = 7750, .std_bits = 0x0f },
-+	.atv_l    = { .if_freq = 7750, .std_bits = 0x0f },
-+	.atv_lc   = { .if_freq = 1250, .std_bits = 0x0f },
-+	.atv_mn   = { .if_freq = 5750, .std_bits = 0x0d },
-+	.atsc_6   = { .if_freq = 3250, .std_bits = 0x1c },
-+	.dvbt_6   = { .if_freq = 3300, .std_bits = 0x1c },
-+	.dvbt_7   = { .if_freq = 3800, .std_bits = 0x1d },
-+	.dvbt_8   = { .if_freq = 4300, .std_bits = 0x1e },
-+	.qam_6    = { .if_freq = 4000, .std_bits = 0x1d },
-+	.qam_8    = { .if_freq = 5000, .std_bits = 0x1f },
-+};
++/**************************************************************************
++ * General Driver Definitions
++ **************************************************************************/
 +
-+static struct tda18271_std_map tda18271c2_std_map = {
-+	.fm_radio = { .if_freq = 1250, .std_bits = 0x18 },
-+	.atv_b    = { .if_freq = 6000, .std_bits = 0x0d },
-+	.atv_dk   = { .if_freq = 6900, .std_bits = 0x0e },
-+	.atv_gh   = { .if_freq = 7100, .std_bits = 0x0e },
-+	.atv_i    = { .if_freq = 7250, .std_bits = 0x0e },
-+	.atv_l    = { .if_freq = 6900, .std_bits = 0x0e },
-+	.atv_lc   = { .if_freq = 1250, .std_bits = 0x0e },
-+	.atv_mn   = { .if_freq = 5400, .std_bits = 0x0c },
-+	.atsc_6   = { .if_freq = 3250, .std_bits = 0x1c },
-+	.dvbt_6   = { .if_freq = 3300, .std_bits = 0x1c },
-+	.dvbt_7   = { .if_freq = 3500, .std_bits = 0x1c },
-+	.dvbt_8   = { .if_freq = 4000, .std_bits = 0x1d },
-+	.qam_6    = { .if_freq = 4000, .std_bits = 0x1d },
-+	.qam_8    = { .if_freq = 5000, .std_bits = 0x1f },
-+};
++/*
++ * si470x_device - private data
++ */
++struct si470x_device {
++	/* reference to USB and video device */
++	struct usb_device *usbdev;
++	struct video_device *videodev;
 +
-+/*---------------------------------------------------------------------*/
++	/* are these really necessary ? */
++	int users;
 +
-+static struct tda18271_map_layout tda18271c1_map_layout = {
-+	.main_pll          = tda18271c1_main_pll,
-+	.cal_pll           = tda18271c1_cal_pll,
++	/* report buffer (maximum 64 bytes) */
++	unsigned char buf[64];
 +
-+	.rf_cal            = tda18271c1_rf_cal,
-+	.rf_cal_kmco       = tda18271c1_km,
++	/* Silabs internal registers (0..15) */
++	unsigned short registers[RADIO_REGISTER_NUM];
 +
-+	.bp_filter         = tda18271_bp_filter,
-+	.rf_band           = tda18271_rf_band,
-+	.gain_taper        = tda18271_gain_taper,
-+	.ir_measure        = tda18271_ir_measure,
++	/* RDS receive buffer */
++	struct work_struct work;
++	wait_queue_head_t read_queue;
++	struct timer_list timer;
++	spinlock_t lock;		/* buffer locking */
++	unsigned char *buffer;		/* size is always multiple of three */
++	unsigned int buf_size;
++	unsigned int rd_index;
++	unsigned int wr_index;
 +};
 +
-+static struct tda18271_map_layout tda18271c2_map_layout = {
-+	.main_pll          = tda18271c2_main_pll,
-+	.cal_pll           = tda18271c2_cal_pll,
 +
-+	.rf_cal            = tda18271c2_rf_cal,
-+	.rf_cal_kmco       = tda18271c2_km,
++/*
++ * The frequency is set in units of 62.5 Hz when using V4L2_TUNER_CAP_LOW,
++ * 62.5 kHz otherwise.
++ * The tuner is able to have a channel spacing of 50, 100 or 200 kHz.
++ * tuner->capability is therefore set to V4L2_TUNER_CAP_LOW
++ * The FREQ_MUL is then: 1 MHz / 62.5 Hz = 16000
++ */
++#define FREQ_MUL (1000000 / 62.5)
 +
-+	.rf_cal_dc_over_dt = tda18271_rf_cal_dc_over_dt,
 +
-+	.bp_filter         = tda18271_bp_filter,
-+	.rf_band           = tda18271_rf_band,
-+	.gain_taper        = tda18271_gain_taper,
-+	.ir_measure        = tda18271_ir_measure,
-+};
 +
-+int tda18271_assign_map_layout(struct dvb_frontend *fe)
++/**************************************************************************
++ * General Driver Functions
++ **************************************************************************/
++
++/*
++ * si470x_get_report - receive a HID report
++ */
++static int si470x_get_report(struct si470x_device *radio, int size)
 +{
-+	struct tda18271_priv *priv = fe->tuner_priv;
-+	int ret = 0;
++	return usb_control_msg(radio->usbdev,
++		usb_rcvctrlpipe(radio->usbdev, 0),
++		HID_REQ_GET_REPORT,
++		USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
++		radio->buf[0], 2,
++		radio->buf, size, usb_timeout);
++}
 +
-+	switch (priv->id) {
-+	case TDA18271HDC1:
-+		priv->maps = &tda18271c1_map_layout;
-+		memcpy(&priv->std, &tda18271c1_std_map,
-+		       sizeof(struct tda18271_std_map));
-+		break;
-+	case TDA18271HDC2:
-+		priv->maps = &tda18271c2_map_layout;
-+		memcpy(&priv->std, &tda18271c2_std_map,
-+		       sizeof(struct tda18271_std_map));
-+		break;
-+	default:
-+		ret = -EINVAL;
-+		break;
-+	}
-+	memcpy(priv->rf_cal_state, &tda18271_rf_band_template,
-+	       sizeof(tda18271_rf_band_template));
 +
-+	return ret;
++/*
++ * si470x_set_report - send a HID report
++ */
++static int si470x_set_report(struct si470x_device *radio, int size)
++{
++	return usb_control_msg(radio->usbdev,
++		usb_sndctrlpipe(radio->usbdev, 0),
++		HID_REQ_SET_REPORT,
++		USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,
++		radio->buf[0], 2,
++		radio->buf, size, usb_timeout);
 +}
 +
++
 +/*
-+ * Overrides for Emacs so that we follow Linus's tabbing style.
-+ * ---------------------------------------------------------------------------
-+ * Local variables:
-+ * c-basic-offset: 8
-+ * End:
++ * si470x_get_register - read register
 + */
-diff --git a/drivers/media/dvb/frontends/tda18271.h b/drivers/media/dvb/frontends/tda18271.h
-new file mode 100644
-index 0000000..24b0e35
---- /dev/null
-+++ b/drivers/media/dvb/frontends/tda18271.h
-@@ -0,0 +1,78 @@
-+/*
-+    tda18271.h - header for the Philips / NXP TDA18271 silicon tuner
++static int si470x_get_register(struct si470x_device *radio, int regnr)
++{
++	int retval;
 +
-+    Copyright (C) 2007, 2008 Michael Krufky <mkrufky at linuxtv.org>
++	radio->buf[0] = REGISTER_REPORT(regnr);
 +
-+    This program is free software; you can redistribute it and/or modify
-+    it under the terms of the GNU General Public License as published by
-+    the Free Software Foundation; either version 2 of the License, or
-+    (at your option) any later version.
++	retval = si470x_get_report(radio, REGISTER_REPORT_SIZE);
++	if (retval >= 0)
++		radio->registers[regnr] = (radio->buf[1] << 8) | radio->buf[2];
 +
-+    This program is distributed in the hope that it will be useful,
-+    but WITHOUT ANY WARRANTY; without even the implied warranty of
-+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+    GNU General Public License for more details.
++	return (retval < 0) ? -EINVAL : 0;
++}
 +
-+    You 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 __TDA18271_H__
-+#define __TDA18271_H__
++/*
++ * si470x_set_register - write register
++ */
++static int si470x_set_register(struct si470x_device *radio, int regnr)
++{
++	int retval;
 +
-+#include <linux/i2c.h>
-+#include "dvb_frontend.h"
++	radio->buf[0] = REGISTER_REPORT(regnr);
++	radio->buf[1] = (radio->registers[regnr] & 0xff00) >> 8;
++	radio->buf[2] = (radio->registers[regnr] & 0x00ff);
 +
-+struct tda18271_std_map_item {
-+	u16 if_freq;
-+	u8 std_bits;
-+};
++	retval = si470x_set_report(radio, REGISTER_REPORT_SIZE);
 +
-+struct tda18271_std_map {
-+	struct tda18271_std_map_item fm_radio;
-+	struct tda18271_std_map_item atv_b;
-+	struct tda18271_std_map_item atv_dk;
-+	struct tda18271_std_map_item atv_gh;
-+	struct tda18271_std_map_item atv_i;
-+	struct tda18271_std_map_item atv_l;
-+	struct tda18271_std_map_item atv_lc;
-+	struct tda18271_std_map_item atv_mn;
-+	struct tda18271_std_map_item atsc_6;
-+	struct tda18271_std_map_item dvbt_6;
-+	struct tda18271_std_map_item dvbt_7;
-+	struct tda18271_std_map_item dvbt_8;
-+	struct tda18271_std_map_item qam_6;
-+	struct tda18271_std_map_item qam_8;
-+};
++	return (retval < 0) ? -EINVAL : 0;
++}
 +
-+enum tda18271_i2c_gate {
-+	TDA18271_GATE_AUTO = 0,
-+	TDA18271_GATE_ANALOG,
-+	TDA18271_GATE_DIGITAL,
-+};
 +
-+struct tda18271_config {
-+	/* override default if freq / std settings (optional) */
-+	struct tda18271_std_map *std_map;
++/*
++ * si470x_get_all_registers - read entire registers
++ */
++static int si470x_get_all_registers(struct si470x_device *radio)
++{
++	int retval;
++	int regnr;
 +
-+	/* use i2c gate provided by analog or digital demod */
-+	enum tda18271_i2c_gate gate;
-+};
++	radio->buf[0] = ENTIRE_REPORT;
 +
-+#if defined(CONFIG_DVB_TDA18271) || (defined(CONFIG_DVB_TDA18271_MODULE) && defined(MODULE))
-+extern struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr,
-+					    struct i2c_adapter *i2c,
-+					    struct tda18271_config *cfg);
-+#else
-+static inline struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe,
-+						   u8 addr,
-+						   struct i2c_adapter *i2c,
-+						   struct tda18271_config *cfg)
-+{
-+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
-+	return NULL;
-+}
-+#endif
++	retval = si470x_get_report(radio, ENTIRE_REPORT_SIZE);
 +
-+#endif /* __TDA18271_H__ */
-diff --git a/drivers/media/dvb/frontends/tda827x.c b/drivers/media/dvb/frontends/tda827x.c
-index 256fc4b..229b119 100644
---- a/drivers/media/dvb/frontends/tda827x.c
-+++ b/drivers/media/dvb/frontends/tda827x.c
-@@ -19,12 +19,16 @@
-  */
- 
- #include <linux/module.h>
--#include <linux/dvb/frontend.h>
- #include <asm/types.h>
-+#include <linux/dvb/frontend.h>
-+#include <linux/videodev2.h>
- 
- #include "tda827x.h"
- 
- static int debug = 0;
-+module_param(debug, int, 0644);
-+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
++	if (retval >= 0)
++		for (regnr = 0; regnr < RADIO_REGISTER_NUM; regnr++)
++			radio->registers[regnr] =
++			(radio->buf[regnr * RADIO_REGISTER_SIZE + 1] << 8) |
++			 radio->buf[regnr * RADIO_REGISTER_SIZE + 2];
 +
- #define dprintk(args...) \
- 	do {					    \
- 		if (debug) printk(KERN_DEBUG "tda827x: " args); \
-@@ -34,10 +38,57 @@ struct tda827x_priv {
- 	int i2c_addr;
- 	struct i2c_adapter *i2c_adap;
- 	struct tda827x_config *cfg;
++	return (retval < 0) ? -EINVAL : 0;
++}
 +
-+	unsigned int sgIF;
-+	unsigned char lpsel;
 +
- 	u32 frequency;
- 	u32 bandwidth;
- };
- 
-+static void tda827x_set_std(struct dvb_frontend *fe,
-+			    struct analog_parameters *params)
++/*
++ * si470x_get_rds_registers - read rds registers
++ */
++static int si470x_get_rds_registers(struct si470x_device *radio)
 +{
-+	struct tda827x_priv *priv = fe->tuner_priv;
-+	char *mode;
++	int retval;
++	int regnr;
++	int size;
 +
-+	priv->lpsel = 0;
-+	if (params->std & V4L2_STD_MN) {
-+		priv->sgIF = 92;
-+		priv->lpsel = 1;
-+		mode = "MN";
-+	} else if (params->std & V4L2_STD_B) {
-+		priv->sgIF = 108;
-+		mode = "B";
-+	} else if (params->std & V4L2_STD_GH) {
-+		priv->sgIF = 124;
-+		mode = "GH";
-+	} else if (params->std & V4L2_STD_PAL_I) {
-+		priv->sgIF = 124;
-+		mode = "I";
-+	} else if (params->std & V4L2_STD_DK) {
-+		priv->sgIF = 124;
-+		mode = "DK";
-+	} else if (params->std & V4L2_STD_SECAM_L) {
-+		priv->sgIF = 124;
-+		mode = "L";
-+	} else if (params->std & V4L2_STD_SECAM_LC) {
-+		priv->sgIF = 20;
-+		mode = "LC";
-+	} else {
-+		priv->sgIF = 124;
-+		mode = "xx";
-+	}
++	radio->buf[0] = RDS_REPORT;
 +
-+	if (params->mode == V4L2_TUNER_RADIO)
-+		priv->sgIF = 88; /* if frequency is 5.5 MHz */
++	retval = usb_interrupt_msg(radio->usbdev,
++		usb_rcvctrlpipe(radio->usbdev, 1),
++		radio->buf, RDS_REPORT_SIZE, &size, usb_timeout);
 +
-+	dprintk("setting tda827x to system %s\n", mode);
-+}
++	if (retval >= 0)
++		for (regnr = 0; regnr < RDS_REGISTER_NUM; regnr++)
++			radio->registers[STATUSRSSI + regnr] =
++			(radio->buf[regnr * RADIO_REGISTER_SIZE + 1] << 8) |
++			 radio->buf[regnr * RADIO_REGISTER_SIZE + 2];
 +
++	return (retval < 0) ? -EINVAL : 0;
++}
 +
-+/* ------------------------------------------------------------------ */
 +
- struct tda827x_data {
- 	u32 lomax;
- 	u8  spd;
-@@ -48,7 +99,7 @@ struct tda827x_data {
- 	u8 div1p5;
- };
- 
--static const struct tda827x_data tda827x_dvbt[] = {
-+static const struct tda827x_data tda827x_table[] = {
- 	{ .lomax =  62000000, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 1},
- 	{ .lomax =  66000000, .spd = 3, .bs = 3, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 1},
- 	{ .lomax =  76000000, .spd = 3, .bs = 1, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 0},
-@@ -106,21 +157,22 @@ static int tda827xo_set_params(struct dvb_frontend *fe,
- 	tuner_freq = params->frequency + if_freq;
- 
- 	i = 0;
--	while (tda827x_dvbt[i].lomax < tuner_freq) {
--		if(tda827x_dvbt[i + 1].lomax == 0)
-+	while (tda827x_table[i].lomax < tuner_freq) {
-+		if (tda827x_table[i + 1].lomax == 0)
- 			break;
- 		i++;
- 	}
- 
--	N = ((tuner_freq + 125000) / 250000) << (tda827x_dvbt[i].spd + 2);
-+	N = ((tuner_freq + 125000) / 250000) << (tda827x_table[i].spd + 2);
- 	buf[0] = 0;
- 	buf[1] = (N>>8) | 0x40;
- 	buf[2] = N & 0xff;
- 	buf[3] = 0;
- 	buf[4] = 0x52;
--	buf[5] = (tda827x_dvbt[i].spd << 6) + (tda827x_dvbt[i].div1p5 << 5) +
--				(tda827x_dvbt[i].bs << 3) + tda827x_dvbt[i].bp;
--	buf[6] = (tda827x_dvbt[i].gc3 << 4) + 0x8f;
-+	buf[5] = (tda827x_table[i].spd << 6) + (tda827x_table[i].div1p5 << 5) +
-+				(tda827x_table[i].bs << 3) +
-+				tda827x_table[i].bp;
-+	buf[6] = (tda827x_table[i].gc3 << 4) + 0x8f;
- 	buf[7] = 0xbf;
- 	buf[8] = 0x2a;
- 	buf[9] = 0x05;
-@@ -140,7 +192,7 @@ static int tda827xo_set_params(struct dvb_frontend *fe,
- 	msleep(500);
- 	/* correct CP value */
- 	buf[0] = 0x30;
--	buf[1] = 0x50 + tda827x_dvbt[i].cp;
-+	buf[1] = 0x50 + tda827x_table[i].cp;
- 	msg.len = 2;
- 
- 	if (fe->ops.i2c_gate_ctrl)
-@@ -173,6 +225,102 @@ static int tda827xo_sleep(struct dvb_frontend *fe)
- 
- /* ------------------------------------------------------------------ */
- 
-+static int tda827xo_set_analog_params(struct dvb_frontend *fe,
-+				      struct analog_parameters *params)
++/*
++ * si470x_set_chan - set the channel
++ */
++static int si470x_set_chan(struct si470x_device *radio, int chan)
 +{
-+	unsigned char tuner_reg[8];
-+	unsigned char reg2[2];
-+	u32 N;
-+	int i;
-+	struct tda827x_priv *priv = fe->tuner_priv;
-+	struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0 };
-+	unsigned int freq = params->frequency;
-+
-+	tda827x_set_std(fe, params);
-+
-+	if (params->mode == V4L2_TUNER_RADIO)
-+		freq = freq / 1000;
++	int retval, i;
 +
-+	N = freq + priv->sgIF;
++	/* start tuning */
++	radio->registers[CHANNEL] &= ~CHANNEL_CHAN;
++	radio->registers[CHANNEL] |= CHANNEL_TUNE | chan;
++	retval = si470x_set_register(radio, CHANNEL);
++	if (retval < 0)
++		return retval;
 +
++	/* wait till seek operation has completed */
 +	i = 0;
-+	while (tda827x_table[i].lomax < N * 62500) {
-+		if (tda827x_table[i + 1].lomax == 0)
-+			break;
-+		i++;
-+	}
++	do {
++		retval = si470x_get_register(radio, STATUSRSSI);
++		if (retval < 0)
++			return retval;
++	} while ((radio->registers[STATUSRSSI] & STATUSRSSI_STC) &&
++		(++i < seek_retries));
++	if (i >= seek_retries)
++		printk(KERN_WARNING DRIVER_NAME
++			": seek does not finish after %d tries\n", i);
 +
-+	N = N << tda827x_table[i].spd;
++	/* stop tuning */
++	radio->registers[CHANNEL] &= ~CHANNEL_TUNE;
++	return si470x_set_register(radio, CHANNEL);
++}
 +
-+	tuner_reg[0] = 0;
-+	tuner_reg[1] = (unsigned char)(N>>8);
-+	tuner_reg[2] = (unsigned char) N;
-+	tuner_reg[3] = 0x40;
-+	tuner_reg[4] = 0x52 + (priv->lpsel << 5);
-+	tuner_reg[5] = (tda827x_table[i].spd    << 6) +
-+		       (tda827x_table[i].div1p5 << 5) +
-+		       (tda827x_table[i].bs     << 3) + tda827x_table[i].bp;
-+	tuner_reg[6] = 0x8f + (tda827x_table[i].gc3 << 4);
-+	tuner_reg[7] = 0x8f;
 +
-+	msg.buf = tuner_reg;
-+	msg.len = 8;
-+	i2c_transfer(priv->i2c_adap, &msg, 1);
++/*
++ * si470x_get_freq - get the frequency
++ */
++static int si470x_get_freq(struct si470x_device *radio)
++{
++	int spacing, band_bottom, chan, freq;
++	int retval;
 +
-+	msg.buf = reg2;
-+	msg.len = 2;
-+	reg2[0] = 0x80;
-+	reg2[1] = 0;
-+	i2c_transfer(priv->i2c_adap, &msg, 1);
++	/* Spacing (kHz) */
++	switch (space) {
++	/* 0: 200 kHz (USA, Australia) */
++	case 0 : spacing = 0.200 * FREQ_MUL; break;
++	/* 1: 100 kHz (Europe, Japan) */
++	case 1 : spacing = 0.100 * FREQ_MUL; break;
++	/* 2:  50 kHz */
++	default: spacing = 0.050 * FREQ_MUL; break;
++	};
 +
-+	reg2[0] = 0x60;
-+	reg2[1] = 0xbf;
-+	i2c_transfer(priv->i2c_adap, &msg, 1);
++	/* Bottom of Band (MHz) */
++	switch (band) {
++	/* 0: 87.5 - 108 MHz (USA, Europe) */
++	case 0 : band_bottom = 87.5 * FREQ_MUL; break;
++	/* 1: 76   - 108 MHz (Japan wide band) */
++	default: band_bottom = 76   * FREQ_MUL; break;
++	/* 2: 76   -  90 MHz (Japan) */
++	case 2 : band_bottom = 76   * FREQ_MUL; break;
++	};
 +
-+	reg2[0] = 0x30;
-+	reg2[1] = tuner_reg[4] + 0x80;
-+	i2c_transfer(priv->i2c_adap, &msg, 1);
++	/* read channel */
++	retval = si470x_get_register(radio, READCHAN);
++	if (retval < 0)
++		return retval;
++	chan = radio->registers[READCHAN] & READCHAN_READCHAN;
 +
-+	msleep(1);
-+	reg2[0] = 0x30;
-+	reg2[1] = tuner_reg[4] + 4;
-+	i2c_transfer(priv->i2c_adap, &msg, 1);
++	/* Frequency (MHz) = Spacing (kHz) x Channel + Bottom of Band (MHz) */
++	freq = chan * spacing + band_bottom;
 +
-+	msleep(1);
-+	reg2[0] = 0x30;
-+	reg2[1] = tuner_reg[4];
-+	i2c_transfer(priv->i2c_adap, &msg, 1);
++	return freq;
++}
 +
-+	msleep(550);
-+	reg2[0] = 0x30;
-+	reg2[1] = (tuner_reg[4] & 0xfc) + tda827x_table[i].cp;
-+	i2c_transfer(priv->i2c_adap, &msg, 1);
 +
-+	reg2[0] = 0x60;
-+	reg2[1] = 0x3f;
-+	i2c_transfer(priv->i2c_adap, &msg, 1);
++/*
++ * si470x_set_freq - set the frequency
++ */
++static int si470x_set_freq(struct si470x_device *radio, int freq)
++{
++	int spacing, band_bottom, chan;
 +
-+	reg2[0] = 0x80;
-+	reg2[1] = 0x08;   /* Vsync en */
-+	i2c_transfer(priv->i2c_adap, &msg, 1);
++	/* Spacing (kHz) */
++	switch (space) {
++	/* 0: 200 kHz (USA, Australia) */
++	case 0 : spacing = 0.200 * FREQ_MUL; break;
++	/* 1: 100 kHz (Europe, Japan) */
++	case 1 : spacing = 0.100 * FREQ_MUL; break;
++	/* 2:  50 kHz */
++	default: spacing = 0.050 * FREQ_MUL; break;
++	};
 +
-+	priv->frequency = freq * 62500;
++	/* Bottom of Band (MHz) */
++	switch (band) {
++	/* 0: 87.5 - 108 MHz (USA, Europe) */
++	case 0 : band_bottom = 87.5 * FREQ_MUL; break;
++	/* 1: 76   - 108 MHz (Japan wide band) */
++	default: band_bottom = 76   * FREQ_MUL; break;
++	/* 2: 76   -  90 MHz (Japan) */
++	case 2 : band_bottom = 76   * FREQ_MUL; break;
++	};
 +
-+	return 0;
++	/* Chan = [ Freq (Mhz) - Bottom of Band (MHz) ] / Spacing (kHz) */
++	chan = (freq - band_bottom) / spacing;
++
++	return si470x_set_chan(radio, chan);
 +}
 +
-+static void tda827xo_agcf(struct dvb_frontend *fe)
++
++/*
++ * si470x_start - switch on radio
++ */
++static int si470x_start(struct si470x_device *radio)
 +{
-+	struct tda827x_priv *priv = fe->tuner_priv;
-+	unsigned char data[] = { 0x80, 0x0c };
-+	struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0,
-+			       .buf = data, .len = 2};
++	int retval;
 +
-+	i2c_transfer(priv->i2c_adap, &msg, 1);
-+}
++	/* powercfg */
++	radio->registers[POWERCFG] =
++		POWERCFG_DMUTE | POWERCFG_ENABLE | POWERCFG_RDSM;
++	retval = si470x_set_register(radio, POWERCFG);
++	if (retval < 0)
++		return retval;
 +
-+/* ------------------------------------------------------------------ */
++	/* sysconfig 1 */
++	radio->registers[SYSCONFIG1] = SYSCONFIG1_DE;
++	retval = si470x_set_register(radio, SYSCONFIG1);
++	if (retval < 0)
++		return retval;
 +
- struct tda827xa_data {
- 	u32 lomax;
- 	u8  svco;
-@@ -212,6 +360,35 @@ static const struct tda827xa_data tda827xa_dvbt[] = {
- 	{ .lomax =         0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0}
- };
- 
-+static struct tda827xa_data tda827xa_analog[] = {
-+	{ .lomax =  56875000, .svco = 3, .spd = 4, .scr = 0, .sbs = 0, .gc3 = 3},
-+	{ .lomax =  67250000, .svco = 0, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3},
-+	{ .lomax =  81250000, .svco = 1, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3},
-+	{ .lomax =  97500000, .svco = 2, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3},
-+	{ .lomax = 113750000, .svco = 3, .spd = 3, .scr = 0, .sbs = 1, .gc3 = 1},
-+	{ .lomax = 134500000, .svco = 0, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},
-+	{ .lomax = 154000000, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},
-+	{ .lomax = 162500000, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},
-+	{ .lomax = 183000000, .svco = 2, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},
-+	{ .lomax = 195000000, .svco = 2, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 1},
-+	{ .lomax = 227500000, .svco = 3, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 3},
-+	{ .lomax = 269000000, .svco = 0, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 3},
-+	{ .lomax = 325000000, .svco = 1, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 1},
-+	{ .lomax = 390000000, .svco = 2, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 3},
-+	{ .lomax = 455000000, .svco = 3, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 3},
-+	{ .lomax = 520000000, .svco = 0, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1},
-+	{ .lomax = 538000000, .svco = 0, .spd = 0, .scr = 1, .sbs = 3, .gc3 = 1},
-+	{ .lomax = 554000000, .svco = 1, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1},
-+	{ .lomax = 620000000, .svco = 1, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0},
-+	{ .lomax = 650000000, .svco = 1, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0},
-+	{ .lomax = 700000000, .svco = 2, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0},
-+	{ .lomax = 780000000, .svco = 2, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0},
-+	{ .lomax = 820000000, .svco = 3, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0},
-+	{ .lomax = 870000000, .svco = 3, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0},
-+	{ .lomax = 911000000, .svco = 3, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 0},
-+	{ .lomax =         0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0}
-+};
++	/* sysconfig 2 */
++	radio->registers[SYSCONFIG2] =
++		(0x3f  << 8) |	/* SEEKTH */
++		(band  << 6) |	/* BAND */
++		(space << 4) |	/* SPACE */
++		15;		/* VOLUME (max) */
++	retval = si470x_set_register(radio, SYSCONFIG2);
++	if (retval < 0)
++		return retval;
 +
- static int tda827xa_set_params(struct dvb_frontend *fe,
- 			       struct dvb_frontend_parameters *params)
- {
-@@ -368,6 +545,163 @@ static int tda827xa_sleep(struct dvb_frontend *fe)
- 	return 0;
- }
- 
-+/* ------------------------------------------------------------------ */
++	/* reset last channel */
++	return si470x_set_chan(radio,
++		radio->registers[CHANNEL] & CHANNEL_CHAN);
++}
 +
-+static void tda827xa_lna_gain(struct dvb_frontend *fe, int high,
-+			      struct analog_parameters *params)
++
++/*
++ * si470x_stop - switch off radio
++ */
++static int si470x_stop(struct si470x_device *radio)
 +{
-+	struct tda827x_priv *priv = fe->tuner_priv;
-+	unsigned char buf[] = {0x22, 0x01};
-+	int arg;
-+	struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0,
-+			       .buf = buf, .len = sizeof(buf) };
++	int retval;
 +
-+	if (NULL == priv->cfg) {
-+		dprintk("tda827x_config not defined, cannot set LNA gain!\n");
-+		return;
-+	}
++	/* sysconfig 1 */
++	radio->registers[SYSCONFIG1] &= ~SYSCONFIG1_RDS;
++	retval = si470x_set_register(radio, SYSCONFIG1);
++	if (retval < 0)
++		return retval;
 +
-+	if (priv->cfg->config) {
-+		if (high)
-+			dprintk("setting LNA to high gain\n");
-+		else
-+			dprintk("setting LNA to low gain\n");
-+	}
-+	switch (*priv->cfg->config) {
-+	case 0: /* no LNA */
-+		break;
-+	case 1: /* switch is GPIO 0 of tda8290 */
-+	case 2:
-+		/* turn Vsync on */
-+		if (params->std & V4L2_STD_MN)
-+			arg = 1;
-+		else
-+			arg = 0;
-+		if (priv->cfg->tuner_callback)
-+			priv->cfg->tuner_callback(priv->i2c_adap->algo_data,
-+						  1, 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);
-+		break;
-+	}
++	/* powercfg */
++	radio->registers[POWERCFG] &= ~POWERCFG_DMUTE;
++	/* POWERCFG_ENABLE has to automatically go low */
++	radio->registers[POWERCFG] |= POWERCFG_ENABLE |	POWERCFG_DISABLE;
++	return si470x_set_register(radio, POWERCFG);
 +}
 +
-+static int tda827xa_set_analog_params(struct dvb_frontend *fe,
-+				      struct analog_parameters *params)
++
++/*
++ * si470x_rds_on - switch on rds reception
++ */
++static int si470x_rds_on(struct si470x_device *radio)
 +{
-+	unsigned char tuner_reg[11];
-+	u32 N;
-+	int i;
-+	struct tda827x_priv *priv = fe->tuner_priv;
-+	struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0,
-+			       .buf = tuner_reg, .len = sizeof(tuner_reg) };
-+	unsigned int freq = params->frequency;
++	/* sysconfig 1 */
++	radio->registers[SYSCONFIG1] |= SYSCONFIG1_RDS;
++	return si470x_set_register(radio, SYSCONFIG1);
++}
 +
-+	tda827x_set_std(fe, params);
 +
-+	tda827xa_lna_gain(fe, 1, params);
-+	msleep(10);
 +
-+	if (params->mode == V4L2_TUNER_RADIO)
-+		freq = freq / 1000;
++/**************************************************************************
++ * RDS Driver Functions
++ **************************************************************************/
 +
-+	N = freq + priv->sgIF;
++/*
++ * si470x_rds - rds processing function
++ */
++static void si470x_rds(struct si470x_device *radio)
++{
++	unsigned char tmpbuf[3];
++	unsigned char blocknum;
++	unsigned char bler; /* rds block errors */
++	unsigned short rds;
++	unsigned int i;
 +
-+	i = 0;
-+	while (tda827xa_analog[i].lomax < N * 62500) {
-+		if (tda827xa_analog[i + 1].lomax == 0)
-+			break;
-+		i++;
++	/* get rds blocks */
++	if (si470x_get_rds_registers(radio) < 0)
++		return;
++	if ((radio->registers[STATUSRSSI] & STATUSRSSI_RDSR) == 0) {
++		/* No RDS group ready */
++		return;
++	}
++	if ((radio->registers[STATUSRSSI] & STATUSRSSI_RDSS) == 0) {
++		/* RDS decoder not synchronized */
++		return;
 +	}
 +
-+	N = N << tda827xa_analog[i].spd;
++	/* copy four RDS blocks to internal buffer */
++	if (spin_trylock(&radio->lock)) {
++		/* process each rds block */
++		for (blocknum = 0; blocknum < 4; blocknum++) {
++			switch (blocknum) {
++			default:
++				bler = (radio->registers[STATUSRSSI] &
++						STATUSRSSI_BLERA) >> 9;
++				rds = radio->registers[RDSA];
++				break;
++			case 1:
++				bler = (radio->registers[READCHAN] &
++						READCHAN_BLERB) >> 14;
++				rds = radio->registers[RDSB];
++				break;
++			case 2:
++				bler = (radio->registers[READCHAN] &
++						READCHAN_BLERC) >> 12;
++				rds = radio->registers[RDSC];
++				break;
++			case 3:
++				bler = (radio->registers[READCHAN] &
++						READCHAN_BLERD) >> 10;
++				rds = radio->registers[RDSD];
++				break;
++			};
 +
-+	tuner_reg[0] = 0;
-+	tuner_reg[1] = (unsigned char)(N>>8);
-+	tuner_reg[2] = (unsigned char) N;
-+	tuner_reg[3] = 0;
-+	tuner_reg[4] = 0x16;
-+	tuner_reg[5] = (tda827xa_analog[i].spd << 5) +
-+		       (tda827xa_analog[i].svco << 3) +
-+			tda827xa_analog[i].sbs;
-+	tuner_reg[6] = 0x8b + (tda827xa_analog[i].gc3 << 4);
-+	tuner_reg[7] = 0x1c;
-+	tuner_reg[8] = 4;
-+	tuner_reg[9] = 0x20;
-+	tuner_reg[10] = 0x00;
-+	msg.len = 11;
-+	i2c_transfer(priv->i2c_adap, &msg, 1);
++			/* Fill the V4L2 RDS buffer */
++			tmpbuf[0] = rds & 0x00ff;	/* LSB */
++			tmpbuf[1] = (rds & 0xff00) >> 8;/* MSB */
++			tmpbuf[2] = blocknum;		/* offset name */
++			tmpbuf[2] |= blocknum << 3;	/* received offset */
++			if (bler > max_rds_errors)
++				tmpbuf[2] |= 0x80; /* uncorrectable errors */
++			else if (bler > 0)
++				tmpbuf[2] |= 0x40; /* corrected error(s) */
 +
-+	tuner_reg[0] = 0x90;
-+	tuner_reg[1] = 0xff;
-+	tuner_reg[2] = 0xe0;
-+	tuner_reg[3] = 0;
-+	tuner_reg[4] = 0x99 + (priv->lpsel << 1);
-+	msg.len = 5;
-+	i2c_transfer(priv->i2c_adap, &msg, 1);
++			/* copy RDS block to internal buffer */
++			for (i = 0; i < 3; i++) {
++				radio->buffer[radio->wr_index] = tmpbuf[i];
++				radio->wr_index++;
++			}
 +
-+	tuner_reg[0] = 0xa0;
-+	tuner_reg[1] = 0xc0;
-+	msg.len = 2;
-+	i2c_transfer(priv->i2c_adap, &msg, 1);
++			/* wrap write pointer */
++			if (radio->wr_index >= radio->buf_size)
++				radio->wr_index = 0;
 +
-+	tuner_reg[0] = 0x30;
-+	tuner_reg[1] = 0x10 + tda827xa_analog[i].scr;
-+	i2c_transfer(priv->i2c_adap, &msg, 1);
++			/* check for overflow */
++			if (radio->wr_index == radio->rd_index) {
++				/* increment and wrap read pointer */
++				radio->rd_index += 3;
++				if (radio->rd_index >= radio->buf_size)
++					radio->rd_index = 0;
++			}
++		}
++		spin_unlock(&radio->lock);
++	}
 +
-+	msg.flags = I2C_M_RD;
-+	i2c_transfer(priv->i2c_adap, &msg, 1);
-+	msg.flags = 0;
-+	tuner_reg[1] >>= 4;
-+	dprintk("AGC2 gain is: %d\n", tuner_reg[1]);
-+	if (tuner_reg[1] < 1)
-+		tda827xa_lna_gain(fe, 0, params);
++	/* wake up read queue */
++	if (radio->wr_index != radio->rd_index)
++		wake_up_interruptible(&radio->read_queue);
++}
 +
-+	msleep(100);
-+	tuner_reg[0] = 0x60;
-+	tuner_reg[1] = 0x3c;
-+	i2c_transfer(priv->i2c_adap, &msg, 1);
 +
-+	msleep(163);
-+	tuner_reg[0] = 0x50;
-+	tuner_reg[1] = 0x8f + (tda827xa_analog[i].gc3 << 4);
-+	i2c_transfer(priv->i2c_adap, &msg, 1);
++/*
++ * si470x_timer - rds timer function
++ */
++static void si470x_timer(unsigned long data)
++{
++	struct si470x_device *radio = (struct si470x_device *) data;
 +
-+	tuner_reg[0] = 0x80;
-+	tuner_reg[1] = 0x28;
-+	i2c_transfer(priv->i2c_adap, &msg, 1);
++	schedule_work(&radio->work);
++}
 +
-+	tuner_reg[0] = 0xb0;
-+	tuner_reg[1] = 0x01;
-+	i2c_transfer(priv->i2c_adap, &msg, 1);
 +
-+	tuner_reg[0] = 0xc0;
-+	tuner_reg[1] = 0x19 + (priv->lpsel << 1);
-+	i2c_transfer(priv->i2c_adap, &msg, 1);
++/*
++ * si470x_work - rds work function
++ */
++static void si470x_work(struct work_struct *work)
++{
++	struct si470x_device *radio = container_of(work, struct si470x_device,
++		work);
 +
-+	priv->frequency = freq * 62500;
++	if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0)
++		return;
 +
-+	return 0;
++	si470x_rds(radio);
++	mod_timer(&radio->timer, jiffies + msecs_to_jiffies(rds_poll_time));
 +}
 +
-+static void tda827xa_agcf(struct dvb_frontend *fe)
++
++
++/**************************************************************************
++ * File Operations Interface
++ **************************************************************************/
++
++/*
++ * si470x_fops_read - read RDS data
++ */
++static ssize_t si470x_fops_read(struct file *file, char __user *buf,
++		size_t count, loff_t *ppos)
 +{
-+	struct tda827x_priv *priv = fe->tuner_priv;
-+	unsigned char data[] = {0x80, 0x2c};
-+	struct i2c_msg msg = {.addr = priv->i2c_addr, .flags = 0,
-+			      .buf = data, .len = 2};
-+	i2c_transfer(priv->i2c_adap, &msg, 1);
-+}
++	struct si470x_device *radio = video_get_drvdata(video_devdata(file));
++	int retval = 0;
++	unsigned int block_count = 0;
 +
-+/* ------------------------------------------------------------------ */
++	/* switch on rds reception */
++	if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0) {
++		si470x_rds_on(radio);
++		schedule_work(&radio->work);
++	}
 +
- static int tda827x_release(struct dvb_frontend *fe)
- {
- 	kfree(fe->tuner_priv);
-@@ -430,6 +764,7 @@ static struct dvb_tuner_ops tda827xo_tuner_ops = {
- 	.init = tda827x_initial_init,
- 	.sleep = tda827x_initial_sleep,
- 	.set_params = tda827xo_set_params,
-+	.set_analog_params = tda827xo_set_analog_params,
- 	.get_frequency = tda827x_get_frequency,
- 	.get_bandwidth = tda827x_get_bandwidth,
- };
-@@ -445,6 +780,7 @@ static struct dvb_tuner_ops tda827xa_tuner_ops = {
- 	.init = tda827x_init,
- 	.sleep = tda827xa_sleep,
- 	.set_params = tda827xa_set_params,
-+	.set_analog_params = tda827xa_set_analog_params,
- 	.get_frequency = tda827x_get_frequency,
- 	.get_bandwidth = tda827x_get_bandwidth,
- };
-@@ -465,9 +801,13 @@ static int tda827x_probe_version(struct dvb_frontend *fe)
- 		dprintk("tda827x tuner found\n");
- 		fe->ops.tuner_ops.init  = tda827x_init;
- 		fe->ops.tuner_ops.sleep = tda827xo_sleep;
-+		if (priv->cfg)
-+			priv->cfg->agcf = tda827xo_agcf;
- 	} else {
- 		dprintk("tda827xa tuner found\n");
- 		memcpy(&fe->ops.tuner_ops, &tda827xa_tuner_ops, sizeof(struct dvb_tuner_ops));
-+		if (priv->cfg)
-+			priv->cfg->agcf = tda827xa_agcf;
- 	}
- 	return 0;
- }
-@@ -487,16 +827,13 @@ struct dvb_frontend *tda827x_attach(struct dvb_frontend *fe, int addr,
- 	priv->i2c_adap = i2c;
- 	priv->cfg = cfg;
- 	memcpy(&fe->ops.tuner_ops, &tda827xo_tuner_ops, sizeof(struct dvb_tuner_ops));
--
- 	fe->tuner_priv = priv;
- 
-+	dprintk("type set to %s\n", fe->ops.tuner_ops.info.name);
++	/* block if no new data available */
++	while (radio->wr_index == radio->rd_index) {
++		if (file->f_flags & O_NONBLOCK)
++			return -EWOULDBLOCK;
++		interruptible_sleep_on(&radio->read_queue);
++	}
 +
- 	return fe;
- }
--
--EXPORT_SYMBOL(tda827x_attach);
--
--module_param(debug, int, 0644);
--MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
-+EXPORT_SYMBOL_GPL(tda827x_attach);
- 
- MODULE_DESCRIPTION("DVB TDA827x driver");
- MODULE_AUTHOR("Hartmut Hackmann <hartmut.hackmann at t-online.de>");
-diff --git a/drivers/media/dvb/frontends/tda827x.h b/drivers/media/dvb/frontends/tda827x.h
-index 69e8263..92eb65b 100644
---- a/drivers/media/dvb/frontends/tda827x.h
-+++ b/drivers/media/dvb/frontends/tda827x.h
-@@ -29,9 +29,16 @@
- 
- struct tda827x_config
- {
-+	/* saa7134 - provided callbacks */
- 	void (*lna_gain) (struct dvb_frontend *fe, int high);
- 	int (*init) (struct dvb_frontend *fe);
- 	int (*sleep) (struct dvb_frontend *fe);
++	/* calculate block count from byte count */
++	count /= 3;
++
++	/* copy RDS block out of internal buffer and to user buffer */
++	if (spin_trylock(&radio->lock)) {
++		while (block_count < count) {
++			if (radio->rd_index == radio->wr_index)
++				break;
++
++			/* always transfer rds complete blocks */
++			if (copy_to_user(buf,
++					&radio->buffer[radio->rd_index], 3))
++				/* retval = -EFAULT; */
++				break;
++
++			/* increment and wrap read pointer */
++			radio->rd_index += 3;
++			if (radio->rd_index >= radio->buf_size)
++				radio->rd_index = 0;
++
++			/* increment counters */
++			block_count++;
++			buf += 3;
++			retval += 3;
++		}
++
++		spin_unlock(&radio->lock);
++	}
++
++	return retval;
++}
 +
-+	/* interface to tda829x driver */
-+	unsigned int *config;
-+	int (*tuner_callback) (void *dev, int command, int arg);
 +
-+	void (*agcf)(struct dvb_frontend *fe);
- };
- 
- 
-diff --git a/drivers/media/dvb/frontends/ves1820.c b/drivers/media/dvb/frontends/ves1820.c
-index 60433b5..8791701 100644
---- a/drivers/media/dvb/frontends/ves1820.c
-+++ b/drivers/media/dvb/frontends/ves1820.c
-@@ -65,7 +65,7 @@ static int ves1820_writereg(struct ves1820_state *state, u8 reg, u8 data)
- 	ret = i2c_transfer(state->i2c, &msg, 1);
- 
- 	if (ret != 1)
--		printk("ves1820: %s(): writereg error (reg == 0x%02x,"
-+		printk("ves1820: %s(): writereg error (reg == 0x%02x, "
- 			"val == 0x%02x, ret == %i)\n", __FUNCTION__, reg, data, ret);
- 
- 	return (ret != 1) ? -EREMOTEIO : 0;
-@@ -84,7 +84,7 @@ static u8 ves1820_readreg(struct ves1820_state *state, u8 reg)
- 	ret = i2c_transfer(state->i2c, msg, 2);
- 
- 	if (ret != 2)
--		printk("ves1820: %s(): readreg error (reg == 0x%02x,"
-+		printk("ves1820: %s(): readreg error (reg == 0x%02x, "
- 		"ret == %i)\n", __FUNCTION__, reg, ret);
- 
- 	return b1[0];
-diff --git a/drivers/media/dvb/frontends/xc5000.c b/drivers/media/dvb/frontends/xc5000.c
-new file mode 100644
-index 0000000..f642ca2
---- /dev/null
-+++ b/drivers/media/dvb/frontends/xc5000.c
-@@ -0,0 +1,964 @@
 +/*
-+ *  Driver for Xceive XC5000 "QAM/8VSB single chip tuner"
-+ *
-+ *  Copyright (c) 2007 Xceive Corporation
-+ *  Copyright (c) 2007 Steven Toth <stoth at hauppauge.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.
++ * si470x_fops_poll - poll RDS data
 + */
++static unsigned int si470x_fops_poll(struct file *file,
++		struct poll_table_struct *pts)
++{
++	struct si470x_device *radio = video_get_drvdata(video_devdata(file));
 +
-+#include <linux/module.h>
-+#include <linux/moduleparam.h>
-+#include <linux/videodev2.h>
-+#include <linux/delay.h>
-+#include <linux/dvb/frontend.h>
-+#include <linux/i2c.h>
++	/* switch on rds reception */
++	if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0) {
++		si470x_rds_on(radio);
++		schedule_work(&radio->work);
++	}
 +
-+#include "dvb_frontend.h"
++	poll_wait(file, &radio->read_queue, pts);
 +
-+#include "xc5000.h"
-+#include "xc5000_priv.h"
++	if (radio->rd_index != radio->wr_index)
++		return POLLIN | POLLRDNORM;
 +
-+static int debug;
-+module_param(debug, int, 0644);
-+MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
++	return 0;
++}
 +
-+#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
++/*
++ * si470x_fops_open - file open
++ */
++static int si470x_fops_open(struct inode *inode, struct file *file)
++{
++	struct si470x_device *radio = video_get_drvdata(video_devdata(file));
 +
-+/* Misc Defines */
-+#define MAX_TV_STANDARD			23
-+#define XC_MAX_I2C_WRITE_LENGTH		64
++	radio->users++;
++	if (radio->users == 1)
++		return si470x_start(radio);
 +
-+/* Signal Types */
-+#define XC_RF_MODE_AIR			0
-+#define XC_RF_MODE_CABLE		1
++	return 0;
++}
 +
-+/* Result codes */
-+#define XC_RESULT_SUCCESS		0
-+#define XC_RESULT_RESET_FAILURE		1
-+#define XC_RESULT_I2C_WRITE_FAILURE	2
-+#define XC_RESULT_I2C_READ_FAILURE	3
-+#define XC_RESULT_OUT_OF_RANGE		5
 +
-+/* Product id */
-+#define XC_PRODUCT_ID_FW_NOT_LOADED	0x2000
-+#define XC_PRODUCT_ID_FW_LOADED 	0x1388
++/*
++ * si470x_fops_release - file release
++ */
++static int si470x_fops_release(struct inode *inode, struct file *file)
++{
++	struct si470x_device *radio = video_get_drvdata(video_devdata(file));
 +
-+/* Registers */
-+#define XREG_INIT         0x00
-+#define XREG_VIDEO_MODE   0x01
-+#define XREG_AUDIO_MODE   0x02
-+#define XREG_RF_FREQ      0x03
-+#define XREG_D_CODE       0x04
-+#define XREG_IF_OUT       0x05
-+#define XREG_SEEK_MODE    0x07
-+#define XREG_POWER_DOWN   0x0A
-+#define XREG_SIGNALSOURCE 0x0D /* 0=Air, 1=Cable */
-+#define XREG_SMOOTHEDCVBS 0x0E
-+#define XREG_XTALFREQ     0x0F
-+#define XREG_FINERFFREQ   0x10
-+#define XREG_DDIMODE      0x11
++	if (!radio)
++		return -ENODEV;
 +
-+#define XREG_ADC_ENV      0x00
-+#define XREG_QUALITY      0x01
-+#define XREG_FRAME_LINES  0x02
-+#define XREG_HSYNC_FREQ   0x03
-+#define XREG_LOCK         0x04
-+#define XREG_FREQ_ERROR   0x05
-+#define XREG_SNR          0x06
-+#define XREG_VERSION      0x07
-+#define XREG_PRODUCT_ID   0x08
-+#define XREG_BUSY         0x09
++	radio->users--;
++	if (radio->users == 0) {
++		/* stop rds reception */
++		del_timer_sync(&radio->timer);
++		flush_scheduled_work();
 +
-+/*
-+   Basic firmware description. This will remain with
-+   the driver for documentation purposes.
++		/* cancel read processes */
++		wake_up_interruptible(&radio->read_queue);
 +
-+   This represents an I2C firmware file encoded as a
-+   string of unsigned char. Format is as follows:
++		return si470x_stop(radio);
++	}
 +
-+   char[0  ]=len0_MSB  -> len = len_MSB * 256 + len_LSB
-+   char[1  ]=len0_LSB  -> length of first write transaction
-+   char[2  ]=data0 -> first byte to be sent
-+   char[3  ]=data1
-+   char[4  ]=data2
-+   char[   ]=...
-+   char[M  ]=dataN  -> last byte to be sent
-+   char[M+1]=len1_MSB  -> len = len_MSB * 256 + len_LSB
-+   char[M+2]=len1_LSB  -> length of second write transaction
-+   char[M+3]=data0
-+   char[M+4]=data1
-+   ...
-+   etc.
++	return 0;
++}
 +
-+   The [len] value should be interpreted as follows:
 +
-+   len= len_MSB _ len_LSB
-+   len=1111_1111_1111_1111   : End of I2C_SEQUENCE
-+   len=0000_0000_0000_0000   : Reset command: Do hardware reset
-+   len=0NNN_NNNN_NNNN_NNNN   : Normal transaction: number of bytes = {1:32767)
-+   len=1WWW_WWWW_WWWW_WWWW   : Wait command: wait for {1:32767} ms
++/*
++ * si470x_fops - file operations interface
++ */
++static const struct file_operations si470x_fops = {
++	.owner		= THIS_MODULE,
++	.llseek		= no_llseek,
++	.read		= si470x_fops_read,
++	.poll		= si470x_fops_poll,
++	.ioctl		= video_ioctl2,
++	.compat_ioctl	= v4l_compat_ioctl32,
++	.open		= si470x_fops_open,
++	.release	= si470x_fops_release,
++};
 +
-+   For the RESET and WAIT commands, the two following bytes will contain
-+   immediately the length of the following transaction.
 +
-+*/
-+typedef struct {
-+	char *Name;
-+	u16 AudioMode;
-+	u16 VideoMode;
-+} XC_TV_STANDARD;
 +
-+/* Tuner standards */
-+#define MN_NTSC_PAL_BTSC	0
-+#define MN_NTSC_PAL_A2		1
-+#define MN_NTSC_PAL_EIAJ	2
-+#define MN_NTSC_PAL_Mono	3
-+#define BG_PAL_A2		4
-+#define BG_PAL_NICAM		5
-+#define BG_PAL_MONO		6
-+#define I_PAL_NICAM		7
-+#define I_PAL_NICAM_MONO	8
-+#define DK_PAL_A2		9
-+#define DK_PAL_NICAM		10
-+#define DK_PAL_MONO		11
-+#define DK_SECAM_A2DK1		12
-+#define DK_SECAM_A2LDK3 	13
-+#define DK_SECAM_A2MONO 	14
-+#define L_SECAM_NICAM		15
-+#define LC_SECAM_NICAM		16
-+#define DTV6			17
-+#define DTV8			18
-+#define DTV7_8			19
-+#define DTV7			20
-+#define FM_Radio_INPUT2 	21
-+#define FM_Radio_INPUT1 	22
++/**************************************************************************
++ * Video4Linux Interface
++ **************************************************************************/
 +
-+XC_TV_STANDARD XC5000_Standard[MAX_TV_STANDARD] = {
-+	{"M/N-NTSC/PAL-BTSC", 0x0400, 0x8020},
-+	{"M/N-NTSC/PAL-A2",   0x0600, 0x8020},
-+	{"M/N-NTSC/PAL-EIAJ", 0x0440, 0x8020},
-+	{"M/N-NTSC/PAL-Mono", 0x0478, 0x8020},
-+	{"B/G-PAL-A2",        0x0A00, 0x8049},
-+	{"B/G-PAL-NICAM",     0x0C04, 0x8049},
-+	{"B/G-PAL-MONO",      0x0878, 0x8059},
-+	{"I-PAL-NICAM",       0x1080, 0x8009},
-+	{"I-PAL-NICAM-MONO",  0x0E78, 0x8009},
-+	{"D/K-PAL-A2",        0x1600, 0x8009},
-+	{"D/K-PAL-NICAM",     0x0E80, 0x8009},
-+	{"D/K-PAL-MONO",      0x1478, 0x8009},
-+	{"D/K-SECAM-A2 DK1",  0x1200, 0x8009},
-+	{"D/K-SECAM-A2 L/DK3",0x0E00, 0x8009},
-+	{"D/K-SECAM-A2 MONO", 0x1478, 0x8009},
-+	{"L-SECAM-NICAM",     0x8E82, 0x0009},
-+	{"L'-SECAM-NICAM",    0x8E82, 0x4009},
-+	{"DTV6",              0x00C0, 0x8002},
-+	{"DTV8",              0x00C0, 0x800B},
-+	{"DTV7/8",            0x00C0, 0x801B},
-+	{"DTV7",              0x00C0, 0x8007},
-+	{"FM Radio-INPUT2",   0x9802, 0x9002},
-+	{"FM Radio-INPUT1",   0x0208, 0x9002}
++/*
++ * si470x_v4l2_queryctrl - query control
++ */
++static struct v4l2_queryctrl si470x_v4l2_queryctrl[] = {
++/* HINT: the disabled controls are only here to satify kradio and such apps */
++	{
++		.id		= V4L2_CID_AUDIO_VOLUME,
++		.type		= V4L2_CTRL_TYPE_INTEGER,
++		.name		= "Volume",
++		.minimum	= 0,
++		.maximum	= 15,
++		.step		= 1,
++		.default_value	= 15,
++	},
++	{
++		.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_MUTE,
++		.type		= V4L2_CTRL_TYPE_BOOLEAN,
++		.name		= "Mute",
++		.minimum	= 0,
++		.maximum	= 1,
++		.step		= 1,
++		.default_value	= 1,
++	},
++	{
++		.id		= V4L2_CID_AUDIO_LOUDNESS,
++		.flags		= V4L2_CTRL_FLAG_DISABLED,
++	},
 +};
 +
-+static int  xc5000_writeregs(struct xc5000_priv *priv, u8 *buf, u8 len);
-+static int  xc5000_readregs(struct xc5000_priv *priv, u8 *buf, u8 len);
-+static void xc5000_TunerReset(struct dvb_frontend *fe);
 +
-+static int xc_send_i2c_data(struct xc5000_priv *priv, u8 *buf, int len)
++/*
++ * si470x_vidioc_querycap - query device capabilities
++ */
++static int si470x_vidioc_querycap(struct file *file, void *priv,
++		struct v4l2_capability *capability)
 +{
-+	return xc5000_writeregs(priv, buf, len)
-+		? XC_RESULT_I2C_WRITE_FAILURE : XC_RESULT_SUCCESS;
++	strlcpy(capability->driver, DRIVER_NAME, sizeof(capability->driver));
++	strlcpy(capability->card, DRIVER_CARD, sizeof(capability->card));
++	sprintf(capability->bus_info, "USB");
++	capability->version = DRIVER_VERSION;
++	capability->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
++
++	return 0;
 +}
 +
-+static int xc_read_i2c_data(struct xc5000_priv *priv, u8 *buf, int len)
++
++/*
++ * si470x_vidioc_g_input - get input
++ */
++static int si470x_vidioc_g_input(struct file *filp, void *priv,
++		unsigned int *i)
 +{
-+	return xc5000_readregs(priv, buf, len)
-+		? XC_RESULT_I2C_READ_FAILURE : XC_RESULT_SUCCESS;
++	*i = 0;
++
++	return 0;
 +}
 +
-+static int xc_reset(struct dvb_frontend *fe)
++
++/*
++ * si470x_vidioc_s_input - set input
++ */
++static int si470x_vidioc_s_input(struct file *filp, void *priv, unsigned int i)
 +{
-+	xc5000_TunerReset(fe);
-+	return XC_RESULT_SUCCESS;
++	if (i != 0)
++		return -EINVAL;
++
++	return 0;
 +}
 +
-+static void xc_wait(int wait_ms)
++
++/*
++ * si470x_vidioc_queryctrl - enumerate control items
++ */
++static int si470x_vidioc_queryctrl(struct file *file, void *priv,
++		struct v4l2_queryctrl *qc)
 +{
-+	msleep(wait_ms);
++	int i;
++
++	for (i = 0; i < ARRAY_SIZE(si470x_v4l2_queryctrl); i++) {
++		if (qc->id && qc->id == si470x_v4l2_queryctrl[i].id) {
++			memcpy(qc, &(si470x_v4l2_queryctrl[i]), sizeof(*qc));
++			return 0;
++		}
++	}
++
++	return -EINVAL;
 +}
 +
-+static void xc5000_TunerReset(struct dvb_frontend *fe)
++
++/*
++ * si470x_vidioc_g_ctrl - get the value of a control
++ */
++static int si470x_vidioc_g_ctrl(struct file *file, void *priv,
++		struct v4l2_control *ctrl)
 +{
-+	struct xc5000_priv *priv = fe->tuner_priv;
-+	int ret;
++	struct si470x_device *radio = video_get_drvdata(video_devdata(file));
 +
-+	dprintk(1, "%s()\n", __FUNCTION__);
++	switch (ctrl->id) {
++	case V4L2_CID_AUDIO_VOLUME:
++		ctrl->value = radio->registers[SYSCONFIG2] &
++				SYSCONFIG2_VOLUME;
++		break;
++	case V4L2_CID_AUDIO_MUTE:
++		ctrl->value = ((radio->registers[POWERCFG] &
++				POWERCFG_DMUTE) == 0) ? 1 : 0;
++		break;
++	}
 +
-+	if (priv->cfg->tuner_callback) {
-+		ret = priv->cfg->tuner_callback(priv->cfg->priv,
-+						XC5000_TUNER_RESET, 0);
-+		if (ret)
-+			printk(KERN_ERR "xc5000: reset failed\n");
-+	} else
-+		printk(KERN_ERR "xc5000: no tuner reset callback function, fatal\n");
++	return 0;
 +}
 +
-+static int xc_write_reg(struct xc5000_priv *priv, u16 regAddr, u16 i2cData)
-+{
-+	u8 buf[4];
-+	int WatchDogTimer = 5;
-+	int result;
 +
-+	buf[0] = (regAddr >> 8) & 0xFF;
-+	buf[1] = regAddr & 0xFF;
-+	buf[2] = (i2cData >> 8) & 0xFF;
-+	buf[3] = i2cData & 0xFF;
-+	result = xc_send_i2c_data(priv, buf, 4);
-+	if (result == XC_RESULT_SUCCESS) {
-+		/* wait for busy flag to clear */
-+		while ((WatchDogTimer > 0) && (result == XC_RESULT_SUCCESS)) {
-+			buf[0] = 0;
-+			buf[1] = XREG_BUSY;
++/*
++ * si470x_vidioc_s_ctrl - set the value of a control
++ */
++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));
 +
-+			result = xc_send_i2c_data(priv, buf, 2);
-+			if (result == XC_RESULT_SUCCESS) {
-+				result = xc_read_i2c_data(priv, buf, 2);
-+				if (result == XC_RESULT_SUCCESS) {
-+					if ((buf[0] == 0) && (buf[1] == 0)) {
-+						/* busy flag cleared */
-+					break;
-+					} else {
-+						xc_wait(100); /* wait 5 ms */
-+						WatchDogTimer--;
-+					}
-+				}
-+			}
-+		}
++	switch (ctrl->id) {
++	case V4L2_CID_AUDIO_VOLUME:
++		radio->registers[SYSCONFIG2] &= ~SYSCONFIG2_VOLUME;
++		radio->registers[SYSCONFIG2] |= ctrl->value;
++		return si470x_set_register(radio, SYSCONFIG2);
++	case V4L2_CID_AUDIO_MUTE:
++		if (ctrl->value == 1)
++			radio->registers[POWERCFG] &= ~POWERCFG_DMUTE;
++		else
++			radio->registers[POWERCFG] |= POWERCFG_DMUTE;
++		return si470x_set_register(radio, POWERCFG);
 +	}
-+	if (WatchDogTimer < 0)
-+		result = XC_RESULT_I2C_WRITE_FAILURE;
 +
-+	return result;
++	return -EINVAL;
 +}
 +
-+static int xc_read_reg(struct xc5000_priv *priv, u16 regAddr, u16 *i2cData)
++
++/*
++ * si470x_vidioc_g_audio - get audio attributes
++ */
++static int si470x_vidioc_g_audio(struct file *file, void *priv,
++		struct v4l2_audio *audio)
 +{
-+	u8 buf[2];
-+	int result;
++	if (audio->index > 1)
++		return -EINVAL;
 +
-+	buf[0] = (regAddr >> 8) & 0xFF;
-+	buf[1] = regAddr & 0xFF;
-+	result = xc_send_i2c_data(priv, buf, 2);
-+	if (result != XC_RESULT_SUCCESS)
-+		return result;
++	strcpy(audio->name, "Radio");
++	audio->capability = V4L2_AUDCAP_STEREO;
 +
-+	result = xc_read_i2c_data(priv, buf, 2);
-+	if (result != XC_RESULT_SUCCESS)
-+		return result;
++	return 0;
++}
 +
-+	*i2cData = buf[0] * 256 + buf[1];
-+	return result;
++
++/*
++ * si470x_vidioc_s_audio - set audio attributes
++ */
++static int si470x_vidioc_s_audio(struct file *file, void *priv,
++		struct v4l2_audio *audio)
++{
++	if (audio->index != 0)
++		return -EINVAL;
++
++	return 0;
 +}
 +
-+static int xc_load_i2c_sequence(struct dvb_frontend *fe, u8 i2c_sequence[])
++
++/*
++ * si470x_vidioc_g_tuner - get tuner attributes
++ */
++static int si470x_vidioc_g_tuner(struct file *file, void *priv,
++		struct v4l2_tuner *tuner)
 +{
-+	struct xc5000_priv *priv = fe->tuner_priv;
++	int retval;
++	struct si470x_device *radio = video_get_drvdata(video_devdata(file));
 +
-+	int i, nbytes_to_send, result;
-+	unsigned int len, pos, index;
-+	u8 buf[XC_MAX_I2C_WRITE_LENGTH];
++	if (tuner->index > 0)
++		return -EINVAL;
 +
-+	index=0;
-+	while ((i2c_sequence[index]!=0xFF) || (i2c_sequence[index+1]!=0xFF)) {
-+		len = i2c_sequence[index]* 256 + i2c_sequence[index+1];
-+		if (len == 0x0000) {
-+			/* RESET command */
-+			result = xc_reset(fe);
-+			index += 2;
-+			if (result != XC_RESULT_SUCCESS)
-+				return result;
-+		} else if (len & 0x8000) {
-+			/* WAIT command */
-+			xc_wait(len & 0x7FFF);
-+			index += 2;
-+		} else {
-+			/* Send i2c data whilst ensuring individual transactions
-+			 * do not exceed XC_MAX_I2C_WRITE_LENGTH bytes.
-+			 */
-+			index += 2;
-+			buf[0] = i2c_sequence[index];
-+			buf[1] = i2c_sequence[index + 1];
-+			pos = 2;
-+			while (pos < len) {
-+				if ((len - pos) > XC_MAX_I2C_WRITE_LENGTH - 2) {
-+					nbytes_to_send = XC_MAX_I2C_WRITE_LENGTH;
-+				} else {
-+					nbytes_to_send = (len - pos + 2);
-+				}
-+				for (i=2; i<nbytes_to_send; i++) {
-+					buf[i] = i2c_sequence[index + pos + i - 2];
-+				}
-+				result = xc_send_i2c_data(priv, buf, nbytes_to_send);
++	/* read status rssi */
++	retval = si470x_get_register(radio, STATUSRSSI);
++	if (retval < 0)
++		return retval;
 +
-+				if (result != XC_RESULT_SUCCESS)
-+					return result;
++	strcpy(tuner->name, "FM");
++	tuner->type = V4L2_TUNER_RADIO;
++	switch (band) {
++	/* 0: 87.5 - 108 MHz (USA, Europe, default) */
++	default:
++		tuner->rangelow  =  87.5 * FREQ_MUL;
++		tuner->rangehigh = 108   * FREQ_MUL;
++		break;
++	/* 1: 76   - 108 MHz (Japan wide band) */
++	case 1 :
++		tuner->rangelow  =  76   * FREQ_MUL;
++		tuner->rangehigh = 108   * FREQ_MUL;
++		break;
++	/* 2: 76   -  90 MHz (Japan) */
++	case 2 :
++		tuner->rangelow  =  76   * FREQ_MUL;
++		tuner->rangehigh =  90   * FREQ_MUL;
++		break;
++	};
++	tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
++	tuner->capability = V4L2_TUNER_CAP_LOW;
 +
-+				pos += nbytes_to_send - 2;
-+			}
-+			index += len;
-+		}
-+	}
-+	return XC_RESULT_SUCCESS;
++	/* Stereo indicator == Stereo (instead of Mono) */
++	if ((radio->registers[STATUSRSSI] & STATUSRSSI_ST) == 1)
++		tuner->audmode = V4L2_TUNER_MODE_STEREO;
++	else
++		tuner->audmode = V4L2_TUNER_MODE_MONO;
++
++	/* min is worst, max is best; signal:0..0xffff; rssi: 0..0xff */
++	tuner->signal = (radio->registers[STATUSRSSI] & STATUSRSSI_RSSI)
++				* 0x0101;
++
++	/* automatic frequency control: -1: freq to low, 1 freq to high */
++	tuner->afc = 0;
++
++	return 0;
 +}
 +
-+static int xc_initialize(struct xc5000_priv *priv)
++
++/*
++ * si470x_vidioc_s_tuner - set tuner attributes
++ */
++static int si470x_vidioc_s_tuner(struct file *file, void *priv,
++		struct v4l2_tuner *tuner)
 +{
-+	dprintk(1, "%s()\n", __FUNCTION__);
-+	return xc_write_reg(priv, XREG_INIT, 0);
++	struct si470x_device *radio = video_get_drvdata(video_devdata(file));
++
++	if (tuner->index > 0)
++		return -EINVAL;
++
++	if (tuner->audmode == V4L2_TUNER_MODE_MONO)
++		radio->registers[POWERCFG] |= POWERCFG_MONO;  /* force mono */
++	else
++		radio->registers[POWERCFG] &= ~POWERCFG_MONO; /* try stereo */
++
++	return si470x_set_register(radio, POWERCFG);
 +}
 +
-+static int xc_SetTVStandard(struct xc5000_priv *priv,
-+	u16 VideoMode, u16 AudioMode)
++
++/*
++ * si470x_vidioc_g_frequency - get tuner or modulator radio frequency
++ */
++static int si470x_vidioc_g_frequency(struct file *file, void *priv,
++		struct v4l2_frequency *freq)
 +{
-+	int ret;
-+	dprintk(1, "%s(0x%04x,0x%04x)\n", __FUNCTION__, VideoMode, AudioMode);
-+	dprintk(1, "%s() Standard = %s\n",
-+		__FUNCTION__,
-+		XC5000_Standard[priv->video_standard].Name);
++	struct si470x_device *radio = video_get_drvdata(video_devdata(file));
 +
-+	ret = xc_write_reg(priv, XREG_VIDEO_MODE, VideoMode);
-+	if (ret == XC_RESULT_SUCCESS)
-+		ret = xc_write_reg(priv, XREG_AUDIO_MODE, AudioMode);
++	freq->type = V4L2_TUNER_RADIO;
++	freq->frequency = si470x_get_freq(radio);
 +
-+	return ret;
++	return 0;
 +}
 +
-+static int xc_shutdown(struct xc5000_priv *priv)
++
++/*
++ * si470x_vidioc_s_frequency - set tuner or modulator radio frequency
++ */
++static int si470x_vidioc_s_frequency(struct file *file, void *priv,
++		struct v4l2_frequency *freq)
 +{
-+	return 0;
-+	/* Fixme: cannot bring tuner back alive once shutdown
-+	 *        without reloading the driver modules.
-+	 *    return xc_write_reg(priv, XREG_POWER_DOWN, 0);
-+	 */
++	struct si470x_device *radio = video_get_drvdata(video_devdata(file));
++
++	if (freq->type != V4L2_TUNER_RADIO)
++		return -EINVAL;
++
++	return si470x_set_freq(radio, freq->frequency);
 +}
 +
-+static int xc_SetSignalSource(struct xc5000_priv *priv, u16 rf_mode)
++
++/*
++ * si470x_viddev_tamples - video device interface
++ */
++static struct video_device si470x_viddev_template = {
++	.fops			= &si470x_fops,
++	.name			= DRIVER_NAME,
++	.type			= VID_TYPE_TUNER,
++	.release		= video_device_release,
++	.vidioc_querycap	= si470x_vidioc_querycap,
++	.vidioc_g_input		= si470x_vidioc_g_input,
++	.vidioc_s_input		= si470x_vidioc_s_input,
++	.vidioc_queryctrl	= si470x_vidioc_queryctrl,
++	.vidioc_g_ctrl		= si470x_vidioc_g_ctrl,
++	.vidioc_s_ctrl		= si470x_vidioc_s_ctrl,
++	.vidioc_g_audio		= si470x_vidioc_g_audio,
++	.vidioc_s_audio		= si470x_vidioc_s_audio,
++	.vidioc_g_tuner		= si470x_vidioc_g_tuner,
++	.vidioc_s_tuner		= si470x_vidioc_s_tuner,
++	.vidioc_g_frequency	= si470x_vidioc_g_frequency,
++	.vidioc_s_frequency	= si470x_vidioc_s_frequency,
++	.owner			= THIS_MODULE,
++};
++
++
++
++/**************************************************************************
++ * USB Interface
++ **************************************************************************/
++
++/*
++ * si470x_usb_driver_probe - probe for the device
++ */
++static int si470x_usb_driver_probe(struct usb_interface *intf,
++		const struct usb_device_id *id)
 +{
-+	dprintk(1, "%s(%d) Source = %s\n", __FUNCTION__, rf_mode,
-+		rf_mode == XC_RF_MODE_AIR ? "ANTENNA" : "CABLE");
++	struct si470x_device *radio;
 +
-+	if ((rf_mode != XC_RF_MODE_AIR) && (rf_mode != XC_RF_MODE_CABLE))
-+	{
-+		rf_mode = XC_RF_MODE_CABLE;
-+		printk(KERN_ERR
-+			"%s(), Invalid mode, defaulting to CABLE",
-+			__FUNCTION__);
++	/* memory and interface allocations */
++	radio = kmalloc(sizeof(struct si470x_device), GFP_KERNEL);
++	if (!radio)
++		return -ENOMEM;
++	radio->videodev = video_device_alloc();
++	if (!radio->videodev) {
++		kfree(radio);
++		return -ENOMEM;
 +	}
-+	return xc_write_reg(priv, XREG_SIGNALSOURCE, rf_mode);
++	memcpy(radio->videodev, &si470x_viddev_template,
++			sizeof(si470x_viddev_template));
++	radio->users = 0;
++	radio->usbdev = interface_to_usbdev(intf);
++	video_set_drvdata(radio->videodev, radio);
++	if (video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr)) {
++		printk(KERN_WARNING DRIVER_NAME
++				": Could not register video device\n");
++		video_device_release(radio->videodev);
++		kfree(radio);
++		return -EIO;
++	}
++	usb_set_intfdata(intf, radio);
++
++	/* show some infos about the specific device */
++	if (si470x_get_all_registers(radio) < 0) {
++		video_device_release(radio->videodev);
++		kfree(radio);
++		return -EIO;
++	}
++	printk(KERN_INFO DRIVER_NAME ": DeviceID=0x%4.4x ChipID=0x%4.4x\n",
++			radio->registers[DEVICEID], radio->registers[CHIPID]);
++
++	/* check if firmware is current */
++	if ((radio->registers[CHIPID] & CHIPID_FIRMWARE)
++			< RADIO_SW_VERSION_CURRENT)
++		printk(KERN_WARNING DRIVER_NAME
++			": This driver is known to work with chip version %d, "
++			"but the device has firmware %d.\n"
++			DRIVER_NAME
++			"If you have some trouble using this driver, please "
++			"report to V4L ML at video4linux-list at redhat.com\n",
++			radio->registers[CHIPID] & CHIPID_FIRMWARE,
++			RADIO_SW_VERSION_CURRENT);
++
++	/* set initial frequency */
++	si470x_set_freq(radio, 87.5 * FREQ_MUL); /* available in all regions */
++
++	/* rds initialization */
++	radio->buf_size = rds_buf * 3;
++	radio->buffer = kmalloc(radio->buf_size, GFP_KERNEL);
++	if (!radio->buffer) {
++		video_device_release(radio->videodev);
++		kfree(radio);
++		return -ENOMEM;
++	}
++	radio->wr_index = 0;
++	radio->rd_index = 0;
++	init_waitqueue_head(&radio->read_queue);
++
++	/* prepare polling via eventd */
++	INIT_WORK(&radio->work, si470x_work);
++	init_timer(&radio->timer);
++	radio->timer.function = si470x_timer;
++	radio->timer.data = (unsigned long) radio;
++
++	return 0;
 +}
 +
-+static const struct dvb_tuner_ops xc5000_tuner_ops;
 +
-+static int xc_set_RF_frequency(struct xc5000_priv *priv, u32 freq_hz)
++/*
++ * si470x_usb_driver_disconnect - disconnect the device
++ */
++static void si470x_usb_driver_disconnect(struct usb_interface *intf)
 +{
-+	u16 freq_code;
++	struct si470x_device *radio = usb_get_intfdata(intf);
 +
-+	dprintk(1, "%s(%u)\n", __FUNCTION__, freq_hz);
++	del_timer_sync(&radio->timer);
++	flush_scheduled_work();
 +
-+	if ((freq_hz > xc5000_tuner_ops.info.frequency_max) ||
-+		(freq_hz < xc5000_tuner_ops.info.frequency_min))
-+		return XC_RESULT_OUT_OF_RANGE;
++	usb_set_intfdata(intf, NULL);
++	if (radio) {
++		video_unregister_device(radio->videodev);
++		kfree(radio->buffer);
++		kfree(radio);
++	}
++}
 +
-+	freq_code = (u16)(freq_hz / 15625);
 +
-+	return xc_write_reg(priv, XREG_RF_FREQ, freq_code);
++/*
++ * si470x_usb_driver - usb driver interface
++ */
++static struct usb_driver si470x_usb_driver = {
++	.name		= DRIVER_NAME,
++	.probe		= si470x_usb_driver_probe,
++	.disconnect	= si470x_usb_driver_disconnect,
++	.id_table	= si470x_usb_driver_id_table,
++};
++
++
++
++/**************************************************************************
++ * Module Interface
++ **************************************************************************/
++
++/*
++ * si470x_module_init - module init
++ */
++static int __init si470x_module_init(void)
++{
++	printk(KERN_INFO DRIVER_DESC "\n");
++	return usb_register(&si470x_usb_driver);
 +}
 +
 +
-+static int xc_set_IF_frequency(struct xc5000_priv *priv, u32 freq_khz)
++/*
++ * si470x_module_exit - module exit
++ */
++static void __exit si470x_module_exit(void)
 +{
-+	u32 freq_code = (freq_khz * 1024)/1000;
-+	dprintk(1, "%s(freq_khz = %d) freq_code = 0x%x\n",
-+		__FUNCTION__, freq_khz, freq_code);
++	usb_deregister(&si470x_usb_driver);
++}
++
++
++module_init(si470x_module_init);
++module_exit(si470x_module_exit);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR(DRIVER_AUTHOR);
++MODULE_DESCRIPTION(DRIVER_DESC);
++MODULE_VERSION("1.0.4");
+diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
+index c9f14bf..a2e8987 100644
+--- a/drivers/media/video/Kconfig
++++ b/drivers/media/video/Kconfig
+@@ -45,7 +45,7 @@ comment "Audio decoders"
+ 
+ config VIDEO_TVAUDIO
+ 	tristate "Simple audio decoder chips"
+-	depends on VIDEO_V4L1 && I2C
++	depends on VIDEO_V4L2 && I2C
+ 	---help---
+ 	  Support for several audio decoder chips found on some bt8xx boards:
+ 	  Philips: tda9840, tda9873h, tda9874h/a, tda9850, tda985x, tea6300,
+@@ -57,7 +57,7 @@ config VIDEO_TVAUDIO
+ 
+ config VIDEO_TDA7432
+ 	tristate "Philips TDA7432 audio processor"
+-	depends on VIDEO_V4L1 && I2C
++	depends on VIDEO_V4L2 && I2C
+ 	---help---
+ 	  Support for tda7432 audio decoder chip found on some bt8xx boards.
+ 
+@@ -75,7 +75,7 @@ config VIDEO_TDA9840
+ 
+ config VIDEO_TDA9875
+ 	tristate "Philips TDA9875 audio processor"
+-	depends on VIDEO_V4L1 && I2C
++	depends on VIDEO_V4L2 && I2C
+ 	---help---
+ 	  Support for tda9875 audio decoder chip found on some bt8xx boards.
+ 
+@@ -109,9 +109,19 @@ config VIDEO_MSP3400
+ 	  To compile this driver as a module, choose M here: the
+ 	  module will be called msp3400.
+ 
++config VIDEO_CS5345
++	tristate "Cirrus Logic CS5345 audio ADC"
++	depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
++	---help---
++	  Support for the Cirrus Logic CS5345 24-bit, 192 kHz
++	  stereo A/D converter.
++
++	  To compile this driver as a module, choose M here: the
++	  module will be called cs5345.
++
+ config VIDEO_CS53L32A
+ 	tristate "Cirrus Logic CS53L32A audio ADC"
+-	depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
++	depends on VIDEO_V4L2 && I2C
+ 	---help---
+ 	  Support for the Cirrus Logic CS53L32A low voltage
+ 	  stereo A/D converter.
+@@ -119,6 +129,15 @@ config VIDEO_CS53L32A
+ 	  To compile this driver as a module, choose M here: the
+ 	  module will be called cs53l32a.
+ 
++config VIDEO_M52790
++       tristate "Mitsubishi M52790 A/V switch"
++       depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
++       ---help---
++	 Support for the Mitsubishi M52790 A/V switch.
++
++	 To compile this driver as a module, choose M here: the
++	 module will be called m52790.
++
+ config VIDEO_TLV320AIC23B
+ 	tristate "Texas Instruments TLV320AIC23B audio codec"
+ 	depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
+@@ -130,7 +149,7 @@ config VIDEO_TLV320AIC23B
+ 
+ config VIDEO_WM8775
+ 	tristate "Wolfson Microelectronics WM8775 audio ADC with input mixer"
+-	depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
++	depends on VIDEO_V4L2 && I2C
+ 	---help---
+ 	  Support for the Wolfson Microelectronics WM8775 high
+ 	  performance stereo A/D Converter with a 4 channel input mixer.
+@@ -140,7 +159,7 @@ config VIDEO_WM8775
+ 
+ config VIDEO_WM8739
+ 	tristate "Wolfson Microelectronics WM8739 stereo audio ADC"
+-	depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
++	depends on VIDEO_V4L2 && I2C
+ 	---help---
+ 	  Support for the Wolfson Microelectronics WM8739
+ 	  stereo A/D Converter.
+@@ -244,7 +263,7 @@ config VIDEO_SAA7114
+ 
+ config VIDEO_SAA711X
+ 	tristate "Philips SAA7113/4/5 video decoders"
+-	depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
++	depends on VIDEO_V4L2 && I2C
+ 	---help---
+ 	  Support for the Philips SAA7113/4/5 video decoders.
+ 
+@@ -300,7 +319,7 @@ comment "Video encoders"
+ 
+ config VIDEO_SAA7127
+ 	tristate "Philips SAA7127/9 digital video encoders"
+-	depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
++	depends on VIDEO_V4L2 && I2C
+ 	---help---
+ 	  Support for the Philips SAA7127/9 digital video encoders.
+ 
+@@ -338,7 +357,7 @@ comment "Video improvement chips"
+ 
+ config VIDEO_UPD64031A
+ 	tristate "NEC Electronics uPD64031A Ghost Reduction"
+-	depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
++	depends on VIDEO_V4L2 && I2C
+ 	---help---
+ 	  Support for the NEC Electronics uPD64031A Ghost Reduction
+ 	  video chip. It is most often found in NTSC TV cards made for
+@@ -350,7 +369,7 @@ config VIDEO_UPD64031A
+ 
+ config VIDEO_UPD64083
+ 	tristate "NEC Electronics uPD64083 3-Dimensional Y/C separation"
+-	depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
++	depends on VIDEO_V4L2 && I2C
+ 	---help---
+ 	  Support for the NEC Electronics uPD64083 3-Dimensional Y/C
+ 	  separation video chip. It is used to improve the quality of
+@@ -802,6 +821,19 @@ config USB_ZR364XX
+ 	  To compile this driver as a module, choose M here: the
+ 	  module will be called zr364xx.
+ 
++config USB_STKWEBCAM
++	tristate "USB Syntek DC1125 Camera support"
++	depends on VIDEO_V4L2 && EXPERIMENTAL
++	---help---
++	  Say Y here if you want to use this type of camera.
++	  Supported devices are typically found in some Asus laptops,
++	  with USB id 174f:a311 and 05e1:0501. Other Syntek cameras
++	  may be supported by the stk11xx driver, from which this is
++	  derived, see http://stk11xx.sourceforge.net
++
++	  To compile this driver as a module, choose M here: the
++	  module will be called stkwebcam.
++
+ endif # V4L_USB_DRIVERS
+ 
+ endif # VIDEO_CAPTURE_DRIVERS
+diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
+index b5a0641..28ddd14 100644
+--- a/drivers/media/video/Makefile
++++ b/drivers/media/video/Makefile
+@@ -4,10 +4,12 @@
+ 
+ zr36067-objs	:=	zoran_procfs.o zoran_device.o \
+ 			zoran_driver.o zoran_card.o
+-tuner-objs	:=	tuner-core.o tuner-types.o tda9887.o
++tuner-objs	:=	tuner-core.o tuner-types.o
+ 
+ msp3400-objs	:=	msp3400-driver.o msp3400-kthreads.o
+ 
++stkwebcam-objs	:=	stk-webcam.o stk-sensor.o
++
+ obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-common.o compat_ioctl32.o \
+ 			   v4l2-int-device.o
+ 
+@@ -66,7 +68,9 @@ obj-$(CONFIG_VIDEO_USBVISION) += usbvision/
+ obj-$(CONFIG_VIDEO_TVP5150) += tvp5150.o
+ obj-$(CONFIG_VIDEO_PVRUSB2) += pvrusb2/
+ obj-$(CONFIG_VIDEO_MSP3400) += msp3400.o
++obj-$(CONFIG_VIDEO_CS5345) += cs5345.o
+ obj-$(CONFIG_VIDEO_CS53L32A) += cs53l32a.o
++obj-$(CONFIG_VIDEO_M52790) += m52790.o
+ obj-$(CONFIG_VIDEO_TLV320AIC23B) += tlv320aic23b.o
+ obj-$(CONFIG_VIDEO_WM8775) += wm8775.o
+ obj-$(CONFIG_VIDEO_WM8739) += wm8739.o
+@@ -81,11 +85,13 @@ obj-$(CONFIG_TUNER_3036) += tuner-3036.o
+ 
+ obj-$(CONFIG_VIDEO_TUNER) += tuner.o
+ 
++obj-$(CONFIG_TUNER_XC2028) += tuner-xc2028.o
+ obj-$(CONFIG_TUNER_SIMPLE) += tuner-simple.o
+ obj-$(CONFIG_TUNER_MT20XX) += mt20xx.o
+ obj-$(CONFIG_TUNER_TDA8290) += tda8290.o
+ obj-$(CONFIG_TUNER_TEA5767) += tea5767.o
+ obj-$(CONFIG_TUNER_TEA5761) += tea5761.o
++obj-$(CONFIG_TUNER_TDA9887) += tda9887.o
+ 
+ obj-$(CONFIG_VIDEOBUF_GEN) += videobuf-core.o
+ obj-$(CONFIG_VIDEOBUF_DMA_SG) += videobuf-dma-sg.o
+@@ -112,6 +118,7 @@ obj-$(CONFIG_USB_SE401)         += se401.o
+ obj-$(CONFIG_USB_STV680)        += stv680.o
+ obj-$(CONFIG_USB_W9968CF)       += w9968cf.o
+ obj-$(CONFIG_USB_ZR364XX)       += zr364xx.o
++obj-$(CONFIG_USB_STKWEBCAM)     += stkwebcam.o
+ 
+ obj-$(CONFIG_USB_SN9C102)       += sn9c102/
+ obj-$(CONFIG_USB_ET61X251)      += et61x251/
+@@ -129,3 +136,4 @@ obj-$(CONFIG_VIDEO_VIVI) += vivi.o
+ obj-$(CONFIG_VIDEO_CX23885) += cx23885/
+ 
+ EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
++EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
+diff --git a/drivers/media/video/bt8xx/Kconfig b/drivers/media/video/bt8xx/Kconfig
+index 2ca162b..cfc822b 100644
+--- a/drivers/media/video/bt8xx/Kconfig
++++ b/drivers/media/video/bt8xx/Kconfig
+@@ -1,6 +1,6 @@
+ config VIDEO_BT848
+ 	tristate "BT848 Video For Linux"
+-	depends on VIDEO_DEV && PCI && I2C && VIDEO_V4L1
++	depends on VIDEO_DEV && PCI && I2C && VIDEO_V4L2 && INPUT
+ 	select I2C_ALGOBIT
+ 	select FW_LOADER
+ 	select VIDEO_BTCX
+diff --git a/drivers/media/video/bt8xx/Makefile b/drivers/media/video/bt8xx/Makefile
+index a096a03..924d216 100644
+--- a/drivers/media/video/bt8xx/Makefile
++++ b/drivers/media/video/bt8xx/Makefile
+@@ -4,7 +4,7 @@
+ 
+ bttv-objs      :=      bttv-driver.o bttv-cards.o bttv-if.o \
+ 		       bttv-risc.o bttv-vbi.o bttv-i2c.o bttv-gpio.o \
+-		       bttv-input.o
++		       bttv-input.o bttv-audio-hook.o
+ 
+ obj-$(CONFIG_VIDEO_BT848) += bttv.o
+ 
+diff --git a/drivers/media/video/bt8xx/bttv-audio-hook.c b/drivers/media/video/bt8xx/bttv-audio-hook.c
+new file mode 100644
+index 0000000..2364d16
+--- /dev/null
++++ b/drivers/media/video/bt8xx/bttv-audio-hook.c
+@@ -0,0 +1,382 @@
++/*
++ * Handlers for board audio hooks, splitted from bttv-cards
++ *
++ * Copyright (c) 2006 Mauro Carvalho Chehab (mchehab at infradead.org)
++ * This code is placed under the terms of the GNU General Public License
++ */
 +
-+	return xc_write_reg(priv, XREG_IF_OUT, freq_code);
-+}
++#include "bttv-audio-hook.h"
 +
++#include <linux/delay.h>
 +
-+static int xc_get_ADC_Envelope(struct xc5000_priv *priv, u16 *adc_envelope)
-+{
-+	return xc_read_reg(priv, XREG_ADC_ENV, adc_envelope);
-+}
++/* ----------------------------------------------------------------------- */
++/* winview                                                                 */
 +
-+static int xc_get_frequency_error(struct xc5000_priv *priv, u32 *freq_error_hz)
++void winview_volume(struct bttv *btv, __u16 volume)
 +{
-+	int result;
-+	u16 regData;
-+	u32 tmp;
-+
-+	result = xc_read_reg(priv, XREG_FREQ_ERROR, &regData);
-+	if (result)
-+		return result;
-+
-+	tmp = (u32)regData;
-+	(*freq_error_hz) = (tmp * 15625) / 1000;
-+	return result;
-+}
++	/* PT2254A programming Jon Tombs, jon at gte.esi.us.es */
++	int bits_out, loops, vol, data;
 +
-+static int xc_get_lock_status(struct xc5000_priv *priv, u16 *lock_status)
-+{
-+	return xc_read_reg(priv, XREG_LOCK, lock_status);
++	/* 32 levels logarithmic */
++	vol = 32 - ((volume>>11));
++	/* units */
++	bits_out = (PT2254_DBS_IN_2>>(vol%5));
++	/* tens */
++	bits_out |= (PT2254_DBS_IN_10>>(vol/5));
++	bits_out |= PT2254_L_CHANNEL | PT2254_R_CHANNEL;
++	data = gpio_read();
++	data &= ~(WINVIEW_PT2254_CLK| WINVIEW_PT2254_DATA|
++		  WINVIEW_PT2254_STROBE);
++	for (loops = 17; loops >= 0 ; loops--) {
++		if (bits_out & (1<<loops))
++			data |=  WINVIEW_PT2254_DATA;
++		else
++			data &= ~WINVIEW_PT2254_DATA;
++		gpio_write(data);
++		udelay(5);
++		data |= WINVIEW_PT2254_CLK;
++		gpio_write(data);
++		udelay(5);
++		data &= ~WINVIEW_PT2254_CLK;
++		gpio_write(data);
++	}
++	data |=  WINVIEW_PT2254_STROBE;
++	data &= ~WINVIEW_PT2254_DATA;
++	gpio_write(data);
++	udelay(10);
++	data &= ~WINVIEW_PT2254_STROBE;
++	gpio_write(data);
 +}
 +
-+static int xc_get_version(struct xc5000_priv *priv,
-+	u8 *hw_majorversion, u8 *hw_minorversion,
-+	u8 *fw_majorversion, u8 *fw_minorversion)
-+{
-+	u16 data;
-+	int result;
-+
-+	result = xc_read_reg(priv, XREG_VERSION, &data);
-+	if (result)
-+		return result;
-+
-+	(*hw_majorversion) = (data >> 12) & 0x0F;
-+	(*hw_minorversion) = (data >>  8) & 0x0F;
-+	(*fw_majorversion) = (data >>  4) & 0x0F;
-+	(*fw_minorversion) = data & 0x0F;
-+
-+	return 0;
-+}
++/* ----------------------------------------------------------------------- */
++/* mono/stereo control for various cards (which don't use i2c chips but    */
++/* connect something to the GPIO pins                                      */
 +
-+static int xc_get_hsync_freq(struct xc5000_priv *priv, u32 *hsync_freq_hz)
++void gvbctv3pci_audio(struct bttv *btv, struct v4l2_tuner *t, int set)
 +{
-+	u16 regData;
-+	int result;
-+
-+	result = xc_read_reg(priv, XREG_HSYNC_FREQ, &regData);
-+	if (result)
-+		return result;
-+
-+	(*hsync_freq_hz) = ((regData & 0x0fff) * 763)/100;
-+	return result;
-+}
++	unsigned int con = 0;
 +
-+static int xc_get_frame_lines(struct xc5000_priv *priv, u16 *frame_lines)
-+{
-+	return xc_read_reg(priv, XREG_FRAME_LINES, frame_lines);
++	if (set) {
++		gpio_inout(0x300, 0x300);
++		if (t->audmode & V4L2_TUNER_MODE_LANG1)
++			con = 0x000;
++		if (t->audmode & V4L2_TUNER_MODE_LANG2)
++			con = 0x300;
++		if (t->audmode & V4L2_TUNER_MODE_STEREO)
++			con = 0x200;
++/*		if (t->audmode & V4L2_TUNER_MODE_MONO)
++ *			con = 0x100; */
++		gpio_bits(0x300, con);
++	} else {
++		t->audmode = V4L2_TUNER_MODE_STEREO |
++			  V4L2_TUNER_MODE_LANG1  | V4L2_TUNER_MODE_LANG2;
++	}
 +}
 +
-+static int xc_get_quality(struct xc5000_priv *priv, u16 *quality)
++void gvbctv5pci_audio(struct bttv *btv, struct v4l2_tuner *t, int set)
 +{
-+	return xc_read_reg(priv, XREG_QUALITY, quality);
-+}
++	unsigned int val, con;
 +
-+static u16 WaitForLock(struct xc5000_priv *priv)
-+{
-+	u16 lockState = 0;
-+	int watchDogCount = 40;
++	if (btv->radio_user)
++		return;
 +
-+	while ((lockState == 0) && (watchDogCount > 0)) {
-+		xc_get_lock_status(priv, &lockState);
-+		if (lockState != 1) {
-+			xc_wait(5);
-+			watchDogCount--;
++	val = gpio_read();
++	if (set) {
++		con = 0x000;
++		if (t->audmode & V4L2_TUNER_MODE_LANG2) {
++			if (t->audmode & V4L2_TUNER_MODE_LANG1) {
++				/* LANG1 + LANG2 */
++				con = 0x100;
++			}
++			else {
++				/* LANG2 */
++				con = 0x300;
++			}
++		}
++		if (con != (val & 0x300)) {
++			gpio_bits(0x300, con);
++			if (bttv_gpio)
++				bttv_gpio_tracking(btv,"gvbctv5pci");
++		}
++	} else {
++		switch (val & 0x70) {
++		  case 0x10:
++			t->rxsubchans = V4L2_TUNER_SUB_LANG1 |  V4L2_TUNER_SUB_LANG2;
++			break;
++		  case 0x30:
++			t->rxsubchans = V4L2_TUNER_SUB_LANG2;
++			break;
++		  case 0x50:
++			t->rxsubchans = V4L2_TUNER_SUB_LANG1;
++			break;
++		  case 0x60:
++			t->rxsubchans = V4L2_TUNER_SUB_STEREO;
++			break;
++		  case 0x70:
++			t->rxsubchans = V4L2_TUNER_SUB_MONO;
++			break;
++		  default:
++			t->rxsubchans = V4L2_TUNER_SUB_MONO |
++					 V4L2_TUNER_SUB_STEREO |
++					 V4L2_TUNER_SUB_LANG1 |
++					 V4L2_TUNER_SUB_LANG2;
 +		}
++		t->audmode = V4L2_TUNER_MODE_STEREO |
++			  V4L2_TUNER_MODE_LANG1  | V4L2_TUNER_MODE_LANG2;
 +	}
-+	return lockState;
-+}
-+
-+static int xc_tune_channel(struct xc5000_priv *priv, u32 freq_hz)
-+{
-+	int found = 0;
-+
-+	dprintk(1, "%s(%u)\n", __FUNCTION__, freq_hz);
-+
-+	if (xc_set_RF_frequency(priv, freq_hz) != XC_RESULT_SUCCESS)
-+		return 0;
-+
-+	if (WaitForLock(priv) == 1)
-+		found = 1;
-+
-+	return found;
 +}
 +
-+static int xc5000_readreg(struct xc5000_priv *priv, u16 reg, u16 *val)
-+{
-+	u8 buf[2] = { reg >> 8, reg & 0xff };
-+	u8 bval[2] = { 0, 0 };
-+	struct i2c_msg msg[2] = {
-+		{ .addr = priv->cfg->i2c_address,
-+			.flags = 0, .buf = &buf[0], .len = 2 },
-+		{ .addr = priv->cfg->i2c_address,
-+			.flags = I2C_M_RD, .buf = &bval[0], .len = 2 },
-+	};
-+
-+	if (i2c_transfer(priv->i2c, msg, 2) != 2) {
-+		printk(KERN_WARNING "xc5000: I2C read failed\n");
-+		return -EREMOTEIO;
-+	}
-+
-+	*val = (bval[0] << 8) | bval[1];
-+	return 0;
-+}
++/*
++ * Mario Medina Nussbaum <medisoft at alohabbs.org.mx>
++ *  I discover that on BT848_GPIO_DATA address a byte 0xcce enable stereo,
++ *  0xdde enables mono and 0xccd enables sap
++ *
++ * Petr Vandrovec <VANDROVE at vc.cvut.cz>
++ *  P.S.: At least mask in line above is wrong - GPIO pins 3,2 select
++ *  input/output sound connection, so both must be set for output mode.
++ *
++ * Looks like it's needed only for the "tvphone", the "tvphone 98"
++ * handles this with a tda9840
++ *
++ */
 +
-+static int xc5000_writeregs(struct xc5000_priv *priv, u8 *buf, u8 len)
++void avermedia_tvphone_audio(struct bttv *btv, struct v4l2_tuner *t, int set)
 +{
-+	struct i2c_msg msg = { .addr = priv->cfg->i2c_address,
-+		.flags = 0, .buf = buf, .len = len };
++	int val = 0;
 +
-+	if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
-+		printk(KERN_ERR "xc5000: I2C write failed (len=%i)\n",
-+			(int)len);
-+		return -EREMOTEIO;
++	if (set) {
++		if (t->audmode & V4L2_TUNER_MODE_LANG2)   /* SAP */
++			val = 0x02;
++		if (t->audmode & V4L2_TUNER_MODE_STEREO)
++			val = 0x01;
++		if (val) {
++			gpio_bits(0x03,val);
++			if (bttv_gpio)
++				bttv_gpio_tracking(btv,"avermedia");
++		}
++	} else {
++		t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO |
++			V4L2_TUNER_MODE_LANG1;
++		return;
 +	}
-+	return 0;
 +}
 +
-+static int xc5000_readregs(struct xc5000_priv *priv, u8 *buf, u8 len)
-+{
-+	struct i2c_msg msg = { .addr = priv->cfg->i2c_address,
-+		.flags = I2C_M_RD, .buf = buf, .len = len };
-+
-+	if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
-+		printk(KERN_ERR "xc5000 I2C read failed (len=%i)\n",(int)len);
-+		return -EREMOTEIO;
-+	}
-+	return 0;
-+}
 +
-+static int xc5000_fwupload(struct dvb_frontend* fe)
++void avermedia_tv_stereo_audio(struct bttv *btv, struct v4l2_tuner *t, int set)
 +{
-+	struct xc5000_priv *priv = fe->tuner_priv;
-+	const struct firmware *fw;
-+	int ret;
-+
-+	/* request the firmware, this will block and timeout */
-+	printk(KERN_INFO "xc5000: waiting for firmware upload (%s)...\n",
-+		XC5000_DEFAULT_FIRMWARE);
-+
-+	ret = request_firmware(&fw, XC5000_DEFAULT_FIRMWARE, &priv->i2c->dev);
-+	if (ret) {
-+		printk(KERN_ERR "xc5000: Upload failed. (file not found?)\n");
-+		ret = XC_RESULT_RESET_FAILURE;
-+		goto out;
-+	} else {
-+		printk(KERN_INFO "xc5000: firmware read %Zu bytes.\n",
-+		       fw->size);
-+		ret = XC_RESULT_SUCCESS;
-+	}
++	int val = 0;
 +
-+	if (fw->size != XC5000_DEFAULT_FIRMWARE_SIZE) {
-+		printk(KERN_ERR "xc5000: firmware incorrect size\n");
-+		ret = XC_RESULT_RESET_FAILURE;
++	if (set) {
++		if (t->audmode & V4L2_TUNER_MODE_LANG2)   /* SAP */
++			val = 0x01;
++		if (t->audmode & V4L2_TUNER_MODE_STEREO)  /* STEREO */
++			val = 0x02;
++		btaor(val, ~0x03, BT848_GPIO_DATA);
++		if (bttv_gpio)
++			bttv_gpio_tracking(btv,"avermedia");
 +	} else {
-+		printk(KERN_INFO "xc5000: firmware upload\n");
-+		ret = xc_load_i2c_sequence(fe,  fw->data );
++		t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO |
++			V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2;
++		return;
 +	}
-+
-+out:
-+	release_firmware(fw);
-+	return ret;
 +}
 +
-+static void xc_debug_dump(struct xc5000_priv *priv)
-+{
-+	u16 adc_envelope;
-+	u32 freq_error_hz = 0;
-+	u16 lock_status;
-+	u32 hsync_freq_hz = 0;
-+	u16 frame_lines;
-+	u16 quality;
-+	u8 hw_majorversion = 0, hw_minorversion = 0;
-+	u8 fw_majorversion = 0, fw_minorversion = 0;
-+
-+	/* Wait for stats to stabilize.
-+	 * Frame Lines needs two frame times after initial lock
-+	 * before it is valid.
-+	 */
-+	xc_wait(100);
-+
-+	xc_get_ADC_Envelope(priv,  &adc_envelope);
-+	dprintk(1, "*** ADC envelope (0-1023) = %d\n", adc_envelope);
-+
-+	xc_get_frequency_error(priv, &freq_error_hz);
-+	dprintk(1, "*** Frequency error = %d Hz\n", freq_error_hz);
-+
-+	xc_get_lock_status(priv,  &lock_status);
-+	dprintk(1, "*** Lock status (0-Wait, 1-Locked, 2-No-signal) = %d\n",
-+		lock_status);
-+
-+	xc_get_version(priv,  &hw_majorversion, &hw_minorversion,
-+		&fw_majorversion, &fw_minorversion);
-+	dprintk(1, "*** HW: V%02x.%02x, FW: V%02x.%02x\n",
-+		hw_majorversion, hw_minorversion,
-+		fw_majorversion, fw_minorversion);
-+
-+	xc_get_hsync_freq(priv,  &hsync_freq_hz);
-+	dprintk(1, "*** Horizontal sync frequency = %d Hz\n", hsync_freq_hz);
-+
-+	xc_get_frame_lines(priv,  &frame_lines);
-+	dprintk(1, "*** Frame lines = %d\n", frame_lines);
-+
-+	xc_get_quality(priv,  &quality);
-+	dprintk(1, "*** Quality (0:<8dB, 7:>56dB) = %d\n", quality);
-+}
++/* Lifetec 9415 handling */
 +
-+static int xc5000_set_params(struct dvb_frontend *fe,
-+	struct dvb_frontend_parameters *params)
++void lt9415_audio(struct bttv *btv, struct v4l2_tuner *t, int set)
 +{
-+	struct xc5000_priv *priv = fe->tuner_priv;
-+	int ret;
-+
-+	dprintk(1, "%s() frequency=%d (Hz)\n", __FUNCTION__, params->frequency);
-+
-+	switch(params->u.vsb.modulation) {
-+	case VSB_8:
-+	case VSB_16:
-+		dprintk(1, "%s() VSB modulation\n", __FUNCTION__);
-+		priv->rf_mode = XC_RF_MODE_AIR;
-+		priv->freq_hz = params->frequency - 1750000;
-+		priv->bandwidth = BANDWIDTH_6_MHZ;
-+		priv->video_standard = DTV6;
-+		break;
-+	case QAM_64:
-+	case QAM_256:
-+	case QAM_AUTO:
-+		dprintk(1, "%s() QAM modulation\n", __FUNCTION__);
-+		priv->rf_mode = XC_RF_MODE_CABLE;
-+		priv->freq_hz = params->frequency - 1750000;
-+		priv->bandwidth = BANDWIDTH_6_MHZ;
-+		priv->video_standard = DTV6;
-+		break;
-+	default:
-+		return -EINVAL;
-+	}
-+
-+	dprintk(1, "%s() frequency=%d (compensated)\n",
-+		__FUNCTION__, priv->freq_hz);
-+
-+	ret = xc_SetSignalSource(priv, priv->rf_mode);
-+	if (ret != XC_RESULT_SUCCESS) {
-+		printk(KERN_ERR
-+			"xc5000: xc_SetSignalSource(%d) failed\n",
-+			priv->rf_mode);
-+		return -EREMOTEIO;
-+	}
++	int val = 0;
 +
-+	ret = xc_SetTVStandard(priv,
-+		XC5000_Standard[priv->video_standard].VideoMode,
-+		XC5000_Standard[priv->video_standard].AudioMode);
-+	if (ret != XC_RESULT_SUCCESS) {
-+		printk(KERN_ERR "xc5000: xc_SetTVStandard failed\n");
-+		return -EREMOTEIO;
++	if (gpio_read() & 0x4000) {
++		t->audmode = V4L2_TUNER_MODE_MONO;
++		return;
 +	}
 +
-+	ret = xc_set_IF_frequency(priv, priv->cfg->if_khz);
-+	if (ret != XC_RESULT_SUCCESS) {
-+		printk(KERN_ERR "xc5000: xc_Set_IF_frequency(%d) failed\n",
-+			priv->cfg->if_khz);
-+		return -EIO;
++	if (set) {
++		if (t->audmode & V4L2_TUNER_MODE_LANG2)  /* A2 SAP */
++			val = 0x0080;
++		if (t->audmode & V4L2_TUNER_MODE_STEREO) /* A2 stereo */
++			val = 0x0880;
++		if ((t->audmode & V4L2_TUNER_MODE_LANG1) ||
++		    (t->audmode & V4L2_TUNER_MODE_MONO))
++			val = 0;
++		gpio_bits(0x0880, val);
++		if (bttv_gpio)
++			bttv_gpio_tracking(btv,"lt9415");
++	} else {
++		/* autodetect doesn't work with this card :-( */
++		t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO |
++			V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2;
++		return;
 +	}
-+
-+	xc_tune_channel(priv, priv->freq_hz);
-+
-+	if (debug)
-+		xc_debug_dump(priv);
-+
-+	return 0;
 +}
 +
-+static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe);
-+
-+static int xc5000_set_analog_params(struct dvb_frontend *fe,
-+	struct analog_parameters *params)
++/* TDA9821 on TerraTV+ Bt848, Bt878 */
++void terratv_audio(struct bttv *btv,  struct v4l2_tuner *t, int set)
 +{
-+	struct xc5000_priv *priv = fe->tuner_priv;
-+	int ret;
-+
-+	if(priv->fwloaded == 0)
-+		xc_load_fw_and_init_tuner(fe);
-+
-+	dprintk(1, "%s() frequency=%d (in units of 62.5khz)\n",
-+		__FUNCTION__, params->frequency);
-+
-+	priv->rf_mode = XC_RF_MODE_CABLE; /* Fix me: it could be air. */
-+
-+	/* params->frequency is in units of 62.5khz */
-+	priv->freq_hz = params->frequency * 62500;
-+
-+	/* FIX ME: Some video standards may have several possible audio
-+		   standards. We simply default to one of them here.
-+	 */
-+	if(params->std & V4L2_STD_MN) {
-+		/* default to BTSC audio standard */
-+		priv->video_standard = MN_NTSC_PAL_BTSC;
-+		goto tune_channel;
-+	}
-+
-+	if(params->std & V4L2_STD_PAL_BG) {
-+		/* default to NICAM audio standard */
-+		priv->video_standard = BG_PAL_NICAM;
-+		goto tune_channel;
-+	}
-+
-+	if(params->std & V4L2_STD_PAL_I) {
-+		/* default to NICAM audio standard */
-+		priv->video_standard = I_PAL_NICAM;
-+		goto tune_channel;
-+	}
-+
-+	if(params->std & V4L2_STD_PAL_DK) {
-+		/* default to NICAM audio standard */
-+		priv->video_standard = DK_PAL_NICAM;
-+		goto tune_channel;
-+	}
-+
-+	if(params->std & V4L2_STD_SECAM_DK) {
-+		/* default to A2 DK1 audio standard */
-+		priv->video_standard = DK_SECAM_A2DK1;
-+		goto tune_channel;
-+	}
-+
-+	if(params->std & V4L2_STD_SECAM_L) {
-+		priv->video_standard = L_SECAM_NICAM;
-+		goto tune_channel;
-+	}
-+
-+	if(params->std & V4L2_STD_SECAM_LC) {
-+		priv->video_standard = LC_SECAM_NICAM;
-+		goto tune_channel;
-+	}
-+
-+tune_channel:
-+	ret = xc_SetSignalSource(priv, priv->rf_mode);
-+	if (ret != XC_RESULT_SUCCESS) {
-+	printk(KERN_ERR
-+			"xc5000: xc_SetSignalSource(%d) failed\n",
-+			priv->rf_mode);
-+		return -EREMOTEIO;
-+	}
++	unsigned int con = 0;
 +
-+	ret = xc_SetTVStandard(priv,
-+		XC5000_Standard[priv->video_standard].VideoMode,
-+		XC5000_Standard[priv->video_standard].AudioMode);
-+	if (ret != XC_RESULT_SUCCESS) {
-+		printk(KERN_ERR "xc5000: xc_SetTVStandard failed\n");
-+		return -EREMOTEIO;
++	if (set) {
++		gpio_inout(0x180000,0x180000);
++		if (t->audmode & V4L2_TUNER_MODE_LANG2)
++			con = 0x080000;
++		if (t->audmode & V4L2_TUNER_MODE_STEREO)
++			con = 0x180000;
++		gpio_bits(0x180000, con);
++		if (bttv_gpio)
++			bttv_gpio_tracking(btv,"terratv");
++	} else {
++		t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO |
++			V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2;
 +	}
-+
-+	xc_tune_channel(priv, priv->freq_hz);
-+
-+	if (debug)
-+		xc_debug_dump(priv);
-+
-+	return 0;
 +}
 +
-+static int xc5000_get_frequency(struct dvb_frontend *fe, u32 *freq)
-+{
-+	struct xc5000_priv *priv = fe->tuner_priv;
-+	dprintk(1, "%s()\n", __FUNCTION__);
-+	*freq = priv->freq_hz;
-+	return 0;
-+}
 +
-+static int xc5000_get_bandwidth(struct dvb_frontend *fe, u32 *bw)
++void winfast2000_audio(struct bttv *btv, struct v4l2_tuner *t, int set)
 +{
-+	struct xc5000_priv *priv = fe->tuner_priv;
-+	dprintk(1, "%s()\n", __FUNCTION__);
++	unsigned long val = 0;
 +
-+	*bw = priv->bandwidth;
-+	return 0;
++	if (set) {
++		/*btor (0xc32000, BT848_GPIO_OUT_EN);*/
++		if (t->audmode & V4L2_TUNER_MODE_MONO)		/* Mono */
++			val = 0x420000;
++		if (t->audmode & V4L2_TUNER_MODE_LANG1)	/* Mono */
++			val = 0x420000;
++		if (t->audmode & V4L2_TUNER_MODE_LANG2)	/* SAP */
++			val = 0x410000;
++		if (t->audmode & V4L2_TUNER_MODE_STEREO)	/* Stereo */
++			val = 0x020000;
++		if (val) {
++			gpio_bits(0x430000, val);
++			if (bttv_gpio)
++				bttv_gpio_tracking(btv,"winfast2000");
++		}
++	} else {
++		t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO |
++			  V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2;
++	}
 +}
 +
-+static int xc5000_get_status(struct dvb_frontend *fe, u32 *status)
++/*
++ * Dariusz Kowalewski <darekk at automex.pl>
++ * sound control for Prolink PV-BT878P+9B (PixelView PlayTV Pro FM+NICAM
++ * revision 9B has on-board TDA9874A sound decoder).
++ *
++ * Note: There are card variants without tda9874a. Forcing the "stereo sound route"
++ *       will mute this cards.
++ */
++void pvbt878p9b_audio(struct bttv *btv, struct v4l2_tuner *t, int set)
 +{
-+	struct xc5000_priv *priv = fe->tuner_priv;
-+	u16 lock_status = 0;
-+
-+	xc_get_lock_status(priv, &lock_status);
-+
-+	dprintk(1, "%s() lock_status = 0x%08x\n", __FUNCTION__, lock_status);
-+
-+	*status = lock_status;
-+
-+	return 0;
-+}
++	unsigned int val = 0;
 +
-+static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe)
-+{
-+	struct xc5000_priv *priv = fe->tuner_priv;
-+	int ret = 0;
++	if (btv->radio_user)
++		return;
 +
-+	if (priv->fwloaded == 0) {
-+		ret = xc5000_fwupload(fe);
-+		if (ret != XC_RESULT_SUCCESS)
-+			return ret;
-+		priv->fwloaded = 1;
++	if (set) {
++		if (t->audmode & V4L2_TUNER_MODE_MONO)	{
++			val = 0x01;
++		}
++		if ((t->audmode & (V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2))
++		    || (t->audmode & V4L2_TUNER_MODE_STEREO)) {
++			val = 0x02;
++		}
++		if (val) {
++			gpio_bits(0x03,val);
++			if (bttv_gpio)
++				bttv_gpio_tracking(btv,"pvbt878p9b");
++		}
++	} else {
++		t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO |
++			V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2;
 +	}
-+
-+	/* Start the tuner self-calibration process */
-+	ret |= xc_initialize(priv);
-+
-+	/* Wait for calibration to complete.
-+	 * We could continue but XC5000 will clock stretch subsequent
-+	 * I2C transactions until calibration is complete.  This way we
-+	 * don't have to rely on clock stretching working.
-+	 */
-+	xc_wait( 100 );
-+
-+	/* Default to "CABLE" mode */
-+	ret |= xc_write_reg(priv, XREG_SIGNALSOURCE, XC_RF_MODE_CABLE);
-+
-+	return ret;
 +}
 +
-+static int xc5000_sleep(struct dvb_frontend *fe)
++/*
++ * Dariusz Kowalewski <darekk at automex.pl>
++ * sound control for FlyVideo 2000S (with tda9874 decoder)
++ * based on pvbt878p9b_audio() - this is not tested, please fix!!!
++ */
++void fv2000s_audio(struct bttv *btv, struct v4l2_tuner *t, int set)
 +{
-+	struct xc5000_priv *priv = fe->tuner_priv;
-+	int ret;
-+
-+	dprintk(1, "%s()\n", __FUNCTION__);
++	unsigned int val = 0xffff;
 +
-+	/* On Pinnacle PCTV HD 800i, the tuner cannot be reinitialized
-+	 * once shutdown without reloading the driver. Maybe I am not
-+	 * doing something right.
-+	 *
-+	 */
++	if (btv->radio_user)
++		return;
 +
-+	ret = xc_shutdown(priv);
-+	if(ret != XC_RESULT_SUCCESS) {
-+		printk(KERN_ERR
-+			"xc5000: %s() unable to shutdown tuner\n",
-+			__FUNCTION__);
-+		return -EREMOTEIO;
-+	}
-+	else {
-+		/* priv->fwloaded = 0; */
-+		return XC_RESULT_SUCCESS;
++	if (set) {
++		if (t->audmode & V4L2_TUNER_MODE_MONO)	{
++			val = 0x0000;
++		}
++		if ((t->audmode & (V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2))
++		    || (t->audmode & V4L2_TUNER_MODE_STEREO)) {
++			val = 0x1080; /*-dk-???: 0x0880, 0x0080, 0x1800 ... */
++		}
++		if (val != 0xffff) {
++			gpio_bits(0x1800, val);
++			if (bttv_gpio)
++				bttv_gpio_tracking(btv,"fv2000s");
++		}
++	} else {
++		t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO |
++			V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2;
 +	}
 +}
 +
-+static int xc5000_init(struct dvb_frontend *fe)
++/*
++ * sound control for Canopus WinDVR PCI
++ * Masaki Suzuki <masaki at btree.org>
++ */
++void windvr_audio(struct bttv *btv, struct v4l2_tuner *t, int set)
 +{
-+	struct xc5000_priv *priv = fe->tuner_priv;
-+	dprintk(1, "%s()\n", __FUNCTION__);
++	unsigned long val = 0;
 +
-+	if (xc_load_fw_and_init_tuner(fe) != XC_RESULT_SUCCESS) {
-+		printk(KERN_ERR "xc5000: Unable to initialise tuner\n");
-+		return -EREMOTEIO;
++	if (set) {
++		if (t->audmode & V4L2_TUNER_MODE_MONO)
++			val = 0x040000;
++		if (t->audmode & V4L2_TUNER_MODE_LANG1)
++			val = 0;
++		if (t->audmode & V4L2_TUNER_MODE_LANG2)
++			val = 0x100000;
++		if (t->audmode & V4L2_TUNER_MODE_STEREO)
++			val = 0;
++		if (val) {
++			gpio_bits(0x140000, val);
++			if (bttv_gpio)
++				bttv_gpio_tracking(btv,"windvr");
++		}
++	} else {
++		t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO |
++			  V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2;
 +	}
-+
-+	if (debug)
-+		xc_debug_dump(priv);
-+
-+	return 0;
-+}
-+
-+static int xc5000_release(struct dvb_frontend *fe)
-+{
-+	dprintk(1, "%s()\n", __FUNCTION__);
-+	kfree(fe->tuner_priv);
-+	fe->tuner_priv = NULL;
-+	return 0;
 +}
 +
-+static const struct dvb_tuner_ops xc5000_tuner_ops = {
-+	.info = {
-+		.name           = "Xceive XC5000",
-+		.frequency_min  =    1000000,
-+		.frequency_max  = 1023000000,
-+		.frequency_step =      50000,
-+	},
-+
-+	.release	   = xc5000_release,
-+	.init		   = xc5000_init,
-+	.sleep		   = xc5000_sleep,
-+
-+	.set_params	   = xc5000_set_params,
-+	.set_analog_params = xc5000_set_analog_params,
-+	.get_frequency	   = xc5000_get_frequency,
-+	.get_bandwidth	   = xc5000_get_bandwidth,
-+	.get_status	   = xc5000_get_status
-+};
-+
-+struct dvb_frontend * xc5000_attach(struct dvb_frontend *fe,
-+	struct i2c_adapter *i2c,
-+	struct xc5000_config *cfg)
++/*
++ * sound control for AD-TVK503
++ * Hiroshi Takekawa <sian at big.or.jp>
++ */
++void adtvk503_audio(struct bttv *btv, struct v4l2_tuner *t, int set)
 +{
-+	struct xc5000_priv *priv = NULL;
-+	u16 id = 0;
-+
-+	dprintk(1, "%s()\n", __FUNCTION__);
-+
-+	priv = kzalloc(sizeof(struct xc5000_priv), GFP_KERNEL);
-+	if (priv == NULL)
-+		return NULL;
-+
-+	priv->cfg = cfg;
-+	priv->bandwidth = BANDWIDTH_6_MHZ;
-+	priv->i2c = i2c;
++	unsigned int con = 0xffffff;
 +
-+	/* 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;
-+	}
++	/* btaor(0x1e0000, ~0x1e0000, BT848_GPIO_OUT_EN); */
 +
-+	switch(id) {
-+	case XC_PRODUCT_ID_FW_LOADED:
-+		printk(KERN_INFO
-+			"xc5000: Successfully identified at address 0x%02x\n",
-+			cfg->i2c_address);
-+		printk(KERN_INFO
-+			"xc5000: Firmware has been loaded previously\n");
-+		priv->fwloaded = 1;
-+		break;
-+	case XC_PRODUCT_ID_FW_NOT_LOADED:
-+		printk(KERN_INFO
-+			"xc5000: Successfully identified at address 0x%02x\n",
-+			cfg->i2c_address);
-+		printk(KERN_INFO
-+			"xc5000: Firmware has not been loaded previously\n");
-+		priv->fwloaded = 0;
-+		break;
-+	default:
-+		printk(KERN_ERR
-+			"xc5000: Device not found at addr 0x%02x (0x%x)\n",
-+			cfg->i2c_address, id);
-+		kfree(priv);
-+		return NULL;
++	if (set) {
++		/* btor(***, BT848_GPIO_OUT_EN); */
++		if (t->audmode & V4L2_TUNER_MODE_LANG1)
++			con = 0x00000000;
++		if (t->audmode & V4L2_TUNER_MODE_LANG2)
++			con = 0x00180000;
++		if (t->audmode & V4L2_TUNER_MODE_STEREO)
++			con = 0x00000000;
++		if (t->audmode & V4L2_TUNER_MODE_MONO)
++			con = 0x00060000;
++		if (con != 0xffffff) {
++			gpio_bits(0x1e0000,con);
++			if (bttv_gpio)
++				bttv_gpio_tracking(btv, "adtvk503");
++		}
++	} else {
++		t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO |
++			  V4L2_TUNER_MODE_LANG1  | V4L2_TUNER_MODE_LANG2;
 +	}
-+
-+	memcpy(&fe->ops.tuner_ops, &xc5000_tuner_ops,
-+		sizeof(struct dvb_tuner_ops));
-+
-+	fe->tuner_priv = priv;
-+
-+	return fe;
 +}
-+EXPORT_SYMBOL(xc5000_attach);
-+
-+MODULE_AUTHOR("Steven Toth");
-+MODULE_DESCRIPTION("Xceive xc5000 silicon tuner driver");
-+MODULE_LICENSE("GPL");
-diff --git a/drivers/media/dvb/frontends/xc5000.h b/drivers/media/dvb/frontends/xc5000.h
+diff --git a/drivers/media/video/bt8xx/bttv-audio-hook.h b/drivers/media/video/bt8xx/bttv-audio-hook.h
 new file mode 100644
-index 0000000..e0e8456
+index 0000000..159d07a
 --- /dev/null
-+++ b/drivers/media/dvb/frontends/xc5000.h
-@@ -0,0 +1,62 @@
++++ b/drivers/media/video/bt8xx/bttv-audio-hook.h
+@@ -0,0 +1,23 @@
 +/*
-+ *  Driver for Xceive XC5000 "QAM/8VSB single chip tuner"
-+ *
-+ *  Copyright (c) 2007 Steven Toth <stoth at hauppauge.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.
++ * Handlers for board audio hooks, splitted from bttv-cards
 + *
-+ *  You 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.
++ * Copyright (c) 2006 Mauro Carvalho Chehab (mchehab at infradead.org)
++ * This code is placed under the terms of the GNU General Public License
 + */
 +
-+#ifndef __XC5000_H__
-+#define __XC5000_H__
++#include "bttvp.h"
 +
-+#include <linux/firmware.h>
++void winview_volume (struct bttv *btv, __u16 volume);
++
++void lt9415_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set);
++void avermedia_tvphone_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set);
++void avermedia_tv_stereo_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set);
++void terratv_audio(struct bttv *btv,  struct v4l2_tuner *tuner, int set);
++void gvbctv3pci_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set);
++void gvbctv5pci_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set);
++void winfast2000_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set);
++void pvbt878p9b_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set);
++void fv2000s_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set);
++void windvr_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set);
++void adtvk503_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set);
++
+diff --git a/drivers/media/video/bt8xx/bttv-cards.c b/drivers/media/video/bt8xx/bttv-cards.c
+index 585d1ef..63a47cd 100644
+--- a/drivers/media/video/bt8xx/bttv-cards.c
++++ b/drivers/media/video/bt8xx/bttv-cards.c
+@@ -39,6 +39,7 @@
+ #include "bttvp.h"
+ #include <media/v4l2-common.h>
+ #include <media/tvaudio.h>
++#include "bttv-audio-hook.h"
+ 
+ /* fwd decl */
+ static void boot_msp34xx(struct bttv *btv, int pin);
+@@ -50,20 +51,6 @@ static void modtec_eeprom(struct bttv *btv);
+ static void init_PXC200(struct bttv *btv);
+ static void init_RTV24(struct bttv *btv);
+ 
+-static void winview_audio(struct bttv *btv, struct video_audio *v, int set);
+-static void lt9415_audio(struct bttv *btv, struct video_audio *v, int set);
+-static void avermedia_tvphone_audio(struct bttv *btv, struct video_audio *v,
+-				    int set);
+-static void avermedia_tv_stereo_audio(struct bttv *btv, struct video_audio *v,
+-				      int set);
+-static void terratv_audio(struct bttv *btv, struct video_audio *v, int set);
+-static void gvbctv3pci_audio(struct bttv *btv, struct video_audio *v, int set);
+-static void gvbctv5pci_audio(struct bttv *btv, struct video_audio *v, int set);
+-static void winfast2000_audio(struct bttv *btv, struct video_audio *v, int set);
+-static void pvbt878p9b_audio(struct bttv *btv, struct video_audio *v, int set);
+-static void fv2000s_audio(struct bttv *btv, struct video_audio *v, int set);
+-static void windvr_audio(struct bttv *btv, struct video_audio *v, int set);
+-static void adtvk503_audio(struct bttv *btv, struct video_audio *v, int set);
+ static void rv605_muxsel(struct bttv *btv, unsigned int input);
+ static void eagle_muxsel(struct bttv *btv, unsigned int input);
+ static void xguard_muxsel(struct bttv *btv, unsigned int input);
+@@ -427,7 +414,7 @@ struct tvcard bttv_tvcards[] = {
+ 		.tuner_type	= UNSET,
+ 		.tuner_addr	= ADDR_UNSET,
+ 		.radio_addr     = ADDR_UNSET,
+-		.audio_hook	= avermedia_tvphone_audio,
++		.audio_mode_gpio= avermedia_tvphone_audio,
+ 		.has_remote     = 1,
+ 	},
+ 	[BTTV_BOARD_MATRIX_VISION] = {
+@@ -539,7 +526,7 @@ struct tvcard bttv_tvcards[] = {
+ 		.tuner_type	= TUNER_PHILIPS_PAL,
+ 		.tuner_addr	= ADDR_UNSET,
+ 		.radio_addr     = ADDR_UNSET,
+-		.audio_hook     = avermedia_tv_stereo_audio,
++		.audio_mode_gpio= avermedia_tv_stereo_audio,
+ 		.no_gpioirq     = 1,
+ 	},
+ 	[BTTV_BOARD_VHX] = {
+@@ -604,7 +591,7 @@ struct tvcard bttv_tvcards[] = {
+ 		.tuner_type	= UNSET,
+ 		.tuner_addr	= ADDR_UNSET,
+ 		.radio_addr     = ADDR_UNSET,
+-		.audio_hook	= winview_audio,
++		.volume_gpio	= winview_volume,
+ 		.has_radio	= 1,
+ 	},
+ 	[BTTV_BOARD_AVEC_INTERCAP] = {
+@@ -728,7 +715,7 @@ struct tvcard bttv_tvcards[] = {
+ 		.tuner_type	= TUNER_PHILIPS_PAL,
+ 		.tuner_addr	= ADDR_UNSET,
+ 		.radio_addr     = ADDR_UNSET,
+-		.audio_hook     = terratv_audio,
++		.audio_mode_gpio= terratv_audio,
+ 	},
+ 	[BTTV_BOARD_HAUPPAUG_WCAM] = {
+ 		.name		= "Hauppauge WinCam newer (bt878)",
+@@ -776,7 +763,7 @@ struct tvcard bttv_tvcards[] = {
+ 		.tuner_type	= TUNER_PHILIPS_PAL,
+ 		.tuner_addr	= ADDR_UNSET,
+ 		.radio_addr     = ADDR_UNSET,
+-		.audio_hook	= terratv_audio,
++		.audio_mode_gpio= terratv_audio,
+ 		/* GPIO wiring:
+ 		External 20 pin connector (for Active Radio Upgrade board)
+ 		gpio00: i2c-sda
+@@ -915,7 +902,7 @@ struct tvcard bttv_tvcards[] = {
+ 		.tuner_type	= TUNER_PHILIPS_PAL, /* default for now, gpio reads BFFF06 for Pal bg+dk */
+ 		.tuner_addr	= ADDR_UNSET,
+ 		.radio_addr     = ADDR_UNSET,
+-		.audio_hook	= winfast2000_audio,
++		.audio_mode_gpio= winfast2000_audio,
+ 		.has_remote     = 1,
+ 	},
+ 	[BTTV_BOARD_CHRONOS_VS2] = {
+@@ -1035,7 +1022,7 @@ struct tvcard bttv_tvcards[] = {
+ 		.tuner_addr	= ADDR_UNSET,
+ 		.radio_addr     = ADDR_UNSET,
+ 		.has_radio	= 1,
+-		.audio_hook	= avermedia_tvphone_audio,
++		.audio_mode_gpio= avermedia_tvphone_audio,
+ 	},
+ 	[BTTV_BOARD_PV951] = {
+ 		.name		= "ProVideo PV951", /* pic16c54 */
+@@ -1167,7 +1154,7 @@ struct tvcard bttv_tvcards[] = {
+ 		.tuner_type	= TUNER_ALPS_TSHC6_NTSC,
+ 		.tuner_addr	= ADDR_UNSET,
+ 		.radio_addr     = ADDR_UNSET,
+-		.audio_hook	= gvbctv3pci_audio,
++		.audio_mode_gpio= gvbctv3pci_audio,
+ 	},
+ 	[BTTV_BOARD_PXELVWPLTVPAK] = {
+ 		.name		= "Prolink PV-BT878P+4E / PixelView PlayTV PAK / Lenco MXTV-9578 CP",
+@@ -1472,7 +1459,7 @@ struct tvcard bttv_tvcards[] = {
+ 				/* -dk-???: set mute=0x1800 for tda9874h daughterboard */
+ 		.gpiomux 	= { 0x0000,0x0800,0x1000,0x1000 },
+ 		.gpiomute 	= 0x1800,
+-		.audio_hook	= fv2000s_audio,
++		.audio_mode_gpio= fv2000s_audio,
+ 		.no_msp34xx	= 1,
+ 		.no_tda9875	= 1,
+ 		.needs_tvaudio  = 1,
+@@ -1513,7 +1500,7 @@ struct tvcard bttv_tvcards[] = {
+ 		.tuner_type     = TUNER_SHARP_2U5JF5540_NTSC,
+ 		.tuner_addr	= ADDR_UNSET,
+ 		.radio_addr     = ADDR_UNSET,
+-		.audio_hook     = gvbctv3pci_audio,
++		.audio_mode_gpio= gvbctv3pci_audio,
+ 	},
+ 
+ 	/* ---- card 0x44 ---------------------------------- */
+@@ -1632,7 +1619,7 @@ struct tvcard bttv_tvcards[] = {
+ 		.tuner_type	= TUNER_PHILIPS_PAL,
+ 		.tuner_addr	= ADDR_UNSET,
+ 		.radio_addr     = ADDR_UNSET,
+-		.audio_hook	= pvbt878p9b_audio, /* Note: not all cards have stereo */
++		.audio_mode_gpio= pvbt878p9b_audio, /* Note: not all cards have stereo */
+ 		.has_radio	= 1,  /* Note: not all cards have radio */
+ 		.has_remote     = 1,
+ 		/* GPIO wiring:
+@@ -1710,7 +1697,7 @@ struct tvcard bttv_tvcards[] = {
+ 		.tuner_type     = TUNER_PHILIPS_NTSC,
+ 		.tuner_addr	= ADDR_UNSET,
+ 		.radio_addr     = ADDR_UNSET,
+-		.audio_hook     = windvr_audio,
++		.audio_mode_gpio= windvr_audio,
+ 	},
+ 	[BTTV_BOARD_GRANDTEC_MULTI] = {
+ 		.name           = "GrandTec Multi Capture Card (Bt878)",
+@@ -1807,7 +1794,7 @@ struct tvcard bttv_tvcards[] = {
+ 		.tuner_type     = TUNER_PHILIPS_NTSC_M,
+ 		.tuner_addr	= ADDR_UNSET,
+ 		.radio_addr     = ADDR_UNSET,
+-		.audio_hook     = gvbctv5pci_audio,
++		.audio_mode_gpio= gvbctv5pci_audio,
+ 		.has_radio      = 1,
+ 	},
+ 	[BTTV_BOARD_OSPREY1x0] = {
+@@ -2106,7 +2093,7 @@ struct tvcard bttv_tvcards[] = {
+ 		.tuner_type     = TUNER_PHILIPS_NTSC,
+ 		.tuner_addr	= ADDR_UNSET,
+ 		.radio_addr     = ADDR_UNSET,
+-		.audio_hook	= adtvk503_audio,
++		.audio_mode_gpio= adtvk503_audio,
+ 	},
+ 
+ 		/* ---- card 0x64 ---------------------------------- */
+@@ -3173,8 +3160,8 @@ static void flyvideo_gpio(struct bttv *btv)
+ 	/* LR90 Audio Routing is done by 2 hef4052, so Audio_Mask has 4 bits: 0x001c80
+ 	 * LR26/LR50 only has 1 hef4052, Audio_Mask 0x000c00
+ 	 * Audio options: from tuner, from tda9821/tda9821(mono,stereo,sap), from tda9874, ext., mute */
+-	if(has_tda9820_tda9821) btv->audio_hook = lt9415_audio;
+-	/* todo: if(has_tda9874) btv->audio_hook = fv2000s_audio; */
++	if(has_tda9820_tda9821) btv->audio_mode_gpio = lt9415_audio;
++	/* todo: if(has_tda9874) btv->audio_mode_gpio = fv2000s_audio; */
+ }
+ 
+ static int miro_tunermap[] = { 0,6,2,3,   4,5,6,0,  3,0,4,5,  5,2,16,1,
+@@ -3574,8 +3561,12 @@ void __devinit bttv_init_card2(struct bttv *btv)
+ 	}
+ 
+ 	if (btv->tda9887_conf) {
+-		bttv_call_i2c_clients(btv, TDA9887_SET_CONFIG,
+-							&btv->tda9887_conf);
++		struct v4l2_priv_tun_config tda9887_cfg;
 +
-+struct dvb_frontend;
-+struct i2c_adapter;
++		tda9887_cfg.tuner = TUNER_TDA9887;
++		tda9887_cfg.priv = &btv->tda9887_conf;
 +
-+struct xc5000_config {
-+	u8   i2c_address;
-+	u32  if_khz;
++		bttv_call_i2c_clients(btv, TUNER_SET_CONFIG, &tda9887_cfg);
+ 	}
+ 
+ 	btv->svhs = bttv_tvcards[btv->c.type].svhs;
+@@ -3590,8 +3581,10 @@ void __devinit bttv_init_card2(struct bttv *btv)
+ 		btv->has_remote=1;
+ 	if (!bttv_tvcards[btv->c.type].no_gpioirq)
+ 		btv->gpioirq=1;
+-	if (bttv_tvcards[btv->c.type].audio_hook)
+-		btv->audio_hook=bttv_tvcards[btv->c.type].audio_hook;
++	if (bttv_tvcards[btv->c.type].volume_gpio)
++		btv->volume_gpio=bttv_tvcards[btv->c.type].volume_gpio;
++	if (bttv_tvcards[btv->c.type].audio_mode_gpio)
++		btv->audio_mode_gpio=bttv_tvcards[btv->c.type].audio_mode_gpio;
+ 
+ 	if (bttv_tvcards[btv->c.type].digital_mode == DIGITAL_MODE_CAMERA) {
+ 		/* detect Bt832 chip for quartzsight digital camera */
+@@ -3950,7 +3943,7 @@ static void __devinit avermedia_eeprom(struct bttv *btv)
+ void bttv_tda9880_setnorm(struct bttv *btv, int norm)
+ {
+ 	/* fix up our card entry */
+-	if(norm==VIDEO_MODE_NTSC) {
++	if(norm==V4L2_STD_NTSC) {
+ 		bttv_tvcards[BTTV_BOARD_VOODOOTV_FM].gpiomux[TVAUDIO_INPUT_TUNER]=0x957fff;
+ 		bttv_tvcards[BTTV_BOARD_VOODOOTV_FM].gpiomute=0x957fff;
+ 		bttv_tvcards[BTTV_BOARD_VOODOOTV_200].gpiomux[TVAUDIO_INPUT_TUNER]=0x957fff;
+@@ -4319,387 +4312,6 @@ void tea5757_set_freq(struct bttv *btv, unsigned short freq)
+ 	tea5757_write(btv, 5 * freq + 0x358); /* add 10.7MHz (see docs) */
+ }
+ 
+-
+-/* ----------------------------------------------------------------------- */
+-/* winview                                                                 */
+-
+-static void winview_audio(struct bttv *btv, struct video_audio *v, int set)
+-{
+-	/* PT2254A programming Jon Tombs, jon at gte.esi.us.es */
+-	int bits_out, loops, vol, data;
+-
+-	if (!set) {
+-		/* Fixed by Leandro Lucarella <luca at linuxmendoza.org.ar (07/31/01) */
+-		v->flags |= VIDEO_AUDIO_VOLUME;
+-		return;
+-	}
+-
+-	/* 32 levels logarithmic */
+-	vol = 32 - ((v->volume>>11));
+-	/* units */
+-	bits_out = (PT2254_DBS_IN_2>>(vol%5));
+-	/* tens */
+-	bits_out |= (PT2254_DBS_IN_10>>(vol/5));
+-	bits_out |= PT2254_L_CHANNEL | PT2254_R_CHANNEL;
+-	data = gpio_read();
+-	data &= ~(WINVIEW_PT2254_CLK| WINVIEW_PT2254_DATA|
+-		  WINVIEW_PT2254_STROBE);
+-	for (loops = 17; loops >= 0 ; loops--) {
+-		if (bits_out & (1<<loops))
+-			data |=  WINVIEW_PT2254_DATA;
+-		else
+-			data &= ~WINVIEW_PT2254_DATA;
+-		gpio_write(data);
+-		udelay(5);
+-		data |= WINVIEW_PT2254_CLK;
+-		gpio_write(data);
+-		udelay(5);
+-		data &= ~WINVIEW_PT2254_CLK;
+-		gpio_write(data);
+-	}
+-	data |=  WINVIEW_PT2254_STROBE;
+-	data &= ~WINVIEW_PT2254_DATA;
+-	gpio_write(data);
+-	udelay(10);
+-	data &= ~WINVIEW_PT2254_STROBE;
+-	gpio_write(data);
+-}
+-
+-/* ----------------------------------------------------------------------- */
+-/* mono/stereo control for various cards (which don't use i2c chips but    */
+-/* connect something to the GPIO pins                                      */
+-
+-static void
+-gvbctv3pci_audio(struct bttv *btv, struct video_audio *v, int set)
+-{
+-	unsigned int con = 0;
+-
+-	if (set) {
+-		gpio_inout(0x300, 0x300);
+-		if (v->mode & VIDEO_SOUND_LANG1)
+-			con = 0x000;
+-		if (v->mode & VIDEO_SOUND_LANG2)
+-			con = 0x300;
+-		if (v->mode & VIDEO_SOUND_STEREO)
+-			con = 0x200;
+-/*		if (v->mode & VIDEO_SOUND_MONO)
+- *			con = 0x100; */
+-		gpio_bits(0x300, con);
+-	} else {
+-		v->mode = VIDEO_SOUND_STEREO |
+-			  VIDEO_SOUND_LANG1  | VIDEO_SOUND_LANG2;
+-	}
+-}
+-
+-static void
+-gvbctv5pci_audio(struct bttv *btv, struct video_audio *v, int set)
+-{
+-	unsigned int val, con;
+-
+-	if (btv->radio_user)
+-		return;
+-
+-	val = gpio_read();
+-	if (set) {
+-		con = 0x000;
+-		if (v->mode & VIDEO_SOUND_LANG2) {
+-			if (v->mode & VIDEO_SOUND_LANG1) {
+-				/* LANG1 + LANG2 */
+-				con = 0x100;
+-			}
+-			else {
+-				/* LANG2 */
+-				con = 0x300;
+-			}
+-		}
+-		if (con != (val & 0x300)) {
+-			gpio_bits(0x300, con);
+-			if (bttv_gpio)
+-				bttv_gpio_tracking(btv,"gvbctv5pci");
+-		}
+-	} else {
+-		switch (val & 0x70) {
+-		  case 0x10:
+-			v->mode = VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
+-			break;
+-		  case 0x30:
+-			v->mode = VIDEO_SOUND_LANG2;
+-			break;
+-		  case 0x50:
+-			v->mode = VIDEO_SOUND_LANG1;
+-			break;
+-		  case 0x60:
+-			v->mode = VIDEO_SOUND_STEREO;
+-			break;
+-		  case 0x70:
+-			v->mode = VIDEO_SOUND_MONO;
+-			break;
+-		  default:
+-			v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
+-				  VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
+-		}
+-	}
+-}
+-
+-/*
+- * Mario Medina Nussbaum <medisoft at alohabbs.org.mx>
+- *  I discover that on BT848_GPIO_DATA address a byte 0xcce enable stereo,
+- *  0xdde enables mono and 0xccd enables sap
+- *
+- * Petr Vandrovec <VANDROVE at vc.cvut.cz>
+- *  P.S.: At least mask in line above is wrong - GPIO pins 3,2 select
+- *  input/output sound connection, so both must be set for output mode.
+- *
+- * Looks like it's needed only for the "tvphone", the "tvphone 98"
+- * handles this with a tda9840
+- *
+- */
+-static void
+-avermedia_tvphone_audio(struct bttv *btv, struct video_audio *v, int set)
+-{
+-	int val = 0;
+-
+-	if (set) {
+-		if (v->mode & VIDEO_SOUND_LANG2)   /* SAP */
+-			val = 0x02;
+-		if (v->mode & VIDEO_SOUND_STEREO)
+-			val = 0x01;
+-		if (val) {
+-			gpio_bits(0x03,val);
+-			if (bttv_gpio)
+-				bttv_gpio_tracking(btv,"avermedia");
+-		}
+-	} else {
+-		v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
+-			VIDEO_SOUND_LANG1;
+-		return;
+-	}
+-}
+-
+-static void
+-avermedia_tv_stereo_audio(struct bttv *btv, struct video_audio *v, int set)
+-{
+-	int val = 0;
+-
+-	if (set) {
+-		if (v->mode & VIDEO_SOUND_LANG2)   /* SAP */
+-			val = 0x01;
+-		if (v->mode & VIDEO_SOUND_STEREO)  /* STEREO */
+-			val = 0x02;
+-		btaor(val, ~0x03, BT848_GPIO_DATA);
+-		if (bttv_gpio)
+-			bttv_gpio_tracking(btv,"avermedia");
+-	} else {
+-		v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
+-			VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
+-		return;
+-	}
+-}
+-
+-/* Lifetec 9415 handling */
+-static void
+-lt9415_audio(struct bttv *btv, struct video_audio *v, int set)
+-{
+-	int val = 0;
+-
+-	if (gpio_read() & 0x4000) {
+-		v->mode = VIDEO_SOUND_MONO;
+-		return;
+-	}
+-
+-	if (set) {
+-		if (v->mode & VIDEO_SOUND_LANG2)  /* A2 SAP */
+-			val = 0x0080;
+-		if (v->mode & VIDEO_SOUND_STEREO) /* A2 stereo */
+-			val = 0x0880;
+-		if ((v->mode & VIDEO_SOUND_LANG1) ||
+-		    (v->mode & VIDEO_SOUND_MONO))
+-			val = 0;
+-		gpio_bits(0x0880, val);
+-		if (bttv_gpio)
+-			bttv_gpio_tracking(btv,"lt9415");
+-	} else {
+-		/* autodetect doesn't work with this card :-( */
+-		v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
+-			VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
+-		return;
+-	}
+-}
+-
+-/* TDA9821 on TerraTV+ Bt848, Bt878 */
+-static void
+-terratv_audio(struct bttv *btv, struct video_audio *v, int set)
+-{
+-	unsigned int con = 0;
+-
+-	if (set) {
+-		gpio_inout(0x180000,0x180000);
+-		if (v->mode & VIDEO_SOUND_LANG2)
+-			con = 0x080000;
+-		if (v->mode & VIDEO_SOUND_STEREO)
+-			con = 0x180000;
+-		gpio_bits(0x180000, con);
+-		if (bttv_gpio)
+-			bttv_gpio_tracking(btv,"terratv");
+-	} else {
+-		v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
+-			VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
+-	}
+-}
+-
+-static void
+-winfast2000_audio(struct bttv *btv, struct video_audio *v, int set)
+-{
+-	unsigned long val = 0;
+-
+-	if (set) {
+-		/*btor (0xc32000, BT848_GPIO_OUT_EN);*/
+-		if (v->mode & VIDEO_SOUND_MONO)		/* Mono */
+-			val = 0x420000;
+-		if (v->mode & VIDEO_SOUND_LANG1)	/* Mono */
+-			val = 0x420000;
+-		if (v->mode & VIDEO_SOUND_LANG2)	/* SAP */
+-			val = 0x410000;
+-		if (v->mode & VIDEO_SOUND_STEREO)	/* Stereo */
+-			val = 0x020000;
+-		if (val) {
+-			gpio_bits(0x430000, val);
+-			if (bttv_gpio)
+-				bttv_gpio_tracking(btv,"winfast2000");
+-		}
+-	} else {
+-		v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
+-			  VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
+-	}
+-}
+-
+-/*
+- * Dariusz Kowalewski <darekk at automex.pl>
+- * sound control for Prolink PV-BT878P+9B (PixelView PlayTV Pro FM+NICAM
+- * revision 9B has on-board TDA9874A sound decoder).
+- *
+- * Note: There are card variants without tda9874a. Forcing the "stereo sound route"
+- *       will mute this cards.
+- */
+-static void
+-pvbt878p9b_audio(struct bttv *btv, struct video_audio *v, int set)
+-{
+-	unsigned int val = 0;
+-
+-	if (btv->radio_user)
+-		return;
+-
+-	if (set) {
+-		if (v->mode & VIDEO_SOUND_MONO)	{
+-			val = 0x01;
+-		}
+-		if ((v->mode & (VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2))
+-		    || (v->mode & VIDEO_SOUND_STEREO)) {
+-			val = 0x02;
+-		}
+-		if (val) {
+-			gpio_bits(0x03,val);
+-			if (bttv_gpio)
+-				bttv_gpio_tracking(btv,"pvbt878p9b");
+-		}
+-	} else {
+-		v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
+-			VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
+-	}
+-}
+-
+-/*
+- * Dariusz Kowalewski <darekk at automex.pl>
+- * sound control for FlyVideo 2000S (with tda9874 decoder)
+- * based on pvbt878p9b_audio() - this is not tested, please fix!!!
+- */
+-static void
+-fv2000s_audio(struct bttv *btv, struct video_audio *v, int set)
+-{
+-	unsigned int val = 0xffff;
+-
+-	if (btv->radio_user)
+-		return;
+-	if (set) {
+-		if (v->mode & VIDEO_SOUND_MONO)	{
+-			val = 0x0000;
+-		}
+-		if ((v->mode & (VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2))
+-		    || (v->mode & VIDEO_SOUND_STEREO)) {
+-			val = 0x1080; /*-dk-???: 0x0880, 0x0080, 0x1800 ... */
+-		}
+-		if (val != 0xffff) {
+-			gpio_bits(0x1800, val);
+-			if (bttv_gpio)
+-				bttv_gpio_tracking(btv,"fv2000s");
+-		}
+-	} else {
+-		v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
+-			VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
+-	}
+-}
+-
+-/*
+- * sound control for Canopus WinDVR PCI
+- * Masaki Suzuki <masaki at btree.org>
+- */
+-static void
+-windvr_audio(struct bttv *btv, struct video_audio *v, int set)
+-{
+-	unsigned long val = 0;
+-
+-	if (set) {
+-		if (v->mode & VIDEO_SOUND_MONO)
+-			val = 0x040000;
+-		if (v->mode & VIDEO_SOUND_LANG1)
+-			val = 0;
+-		if (v->mode & VIDEO_SOUND_LANG2)
+-			val = 0x100000;
+-		if (v->mode & VIDEO_SOUND_STEREO)
+-			val = 0;
+-		if (val) {
+-			gpio_bits(0x140000, val);
+-			if (bttv_gpio)
+-				bttv_gpio_tracking(btv,"windvr");
+-		}
+-	} else {
+-		v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
+-			  VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
+-	}
+-}
+-
+-/*
+- * sound control for AD-TVK503
+- * Hiroshi Takekawa <sian at big.or.jp>
+- */
+-static void
+-adtvk503_audio(struct bttv *btv, struct video_audio *v, int set)
+-{
+-	unsigned int con = 0xffffff;
+-
+-	/* btaor(0x1e0000, ~0x1e0000, BT848_GPIO_OUT_EN); */
+-
+-	if (set) {
+-		/* btor(***, BT848_GPIO_OUT_EN); */
+-		if (v->mode & VIDEO_SOUND_LANG1)
+-			con = 0x00000000;
+-		if (v->mode & VIDEO_SOUND_LANG2)
+-			con = 0x00180000;
+-		if (v->mode & VIDEO_SOUND_STEREO)
+-			con = 0x00000000;
+-		if (v->mode & VIDEO_SOUND_MONO)
+-			con = 0x00060000;
+-		if (con != 0xffffff) {
+-			gpio_bits(0x1e0000,con);
+-			if (bttv_gpio)
+-				bttv_gpio_tracking(btv, "adtvk503");
+-		}
+-	} else {
+-		v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
+-			  VIDEO_SOUND_LANG1  | VIDEO_SOUND_LANG2;
+-	}
+-}
+-
+ /* RemoteVision MX (rv605) muxsel helper [Miguel Freitas]
+  *
+  * This is needed because rv605 don't use a normal multiplex, but a crosspoint
+diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c
+index 581a3c9..907dc62 100644
+--- a/drivers/media/video/bt8xx/bttv-driver.c
++++ b/drivers/media/video/bt8xx/bttv-driver.c
+@@ -9,6 +9,12 @@
+     some v4l2 code lines are taken from Justin's bttv2 driver which is
+     (c) 2000 Justin Schoeman <justin at suntiger.ee.up.ac.za>
+ 
++    V4L1 removal from:
++    (c) 2005-2006 Nickolay V. Shmyrev <nshmyrev at yandex.ru>
 +
-+	/* For each bridge framework, when it attaches either analog or digital,
-+	 * it has to store a reference back to its _core equivalent structure,
-+	 * so that it can service the hardware by steering gpio's etc.
-+	 * Each bridge implementation is different so cast priv accordingly.
-+	 * The xc5000 driver cares not for this value, other than ensuring
-+	 * it's passed back to a bridge during tuner_callback().
-+	 */
-+	void *priv;
-+	int  (*tuner_callback) (void *priv, int command, int arg);
-+};
++    Fixes to be fully V4L2 compliant by
++    (c) 2006 Mauro Carvalho Chehab <mchehab at infradead.org>
 +
-+/* xc5000 callback command */
-+#define XC5000_TUNER_RESET		0
+     Cropping and overscan support
+     Copyright (C) 2005, 2006 Michael H. Schimek <mschimek at gmx.at>
+     Sponsored by OPQ Systems AB
+@@ -157,7 +163,7 @@ MODULE_LICENSE("GPL");
+ static ssize_t show_card(struct device *cd,
+ 			 struct device_attribute *attr, char *buf)
+ {
+-	struct video_device *vfd = to_video_device(cd);
++	struct video_device *vfd = container_of(cd, struct video_device, class_dev);
+ 	struct bttv *btv = dev_get_drvdata(vfd->dev);
+ 	return sprintf(buf, "%d\n", btv ? btv->c.type : UNSET);
+ }
+@@ -470,31 +476,27 @@ static const unsigned int BTTV_TVNORMS = ARRAY_SIZE(bttv_tvnorms);
+ /* ----------------------------------------------------------------------- */
+ /* bttv format list
+    packed pixel formats must come first */
+-static const struct bttv_format bttv_formats[] = {
++static const struct bttv_format formats[] = {
+ 	{
+ 		.name     = "8 bpp, gray",
+-		.palette  = VIDEO_PALETTE_GREY,
+ 		.fourcc   = V4L2_PIX_FMT_GREY,
+ 		.btformat = BT848_COLOR_FMT_Y8,
+ 		.depth    = 8,
+ 		.flags    = FORMAT_FLAGS_PACKED,
+ 	},{
+ 		.name     = "8 bpp, dithered color",
+-		.palette  = VIDEO_PALETTE_HI240,
+ 		.fourcc   = V4L2_PIX_FMT_HI240,
+ 		.btformat = BT848_COLOR_FMT_RGB8,
+ 		.depth    = 8,
+ 		.flags    = FORMAT_FLAGS_PACKED | FORMAT_FLAGS_DITHER,
+ 	},{
+ 		.name     = "15 bpp RGB, le",
+-		.palette  = VIDEO_PALETTE_RGB555,
+ 		.fourcc   = V4L2_PIX_FMT_RGB555,
+ 		.btformat = BT848_COLOR_FMT_RGB15,
+ 		.depth    = 16,
+ 		.flags    = FORMAT_FLAGS_PACKED,
+ 	},{
+ 		.name     = "15 bpp RGB, be",
+-		.palette  = -1,
+ 		.fourcc   = V4L2_PIX_FMT_RGB555X,
+ 		.btformat = BT848_COLOR_FMT_RGB15,
+ 		.btswap   = 0x03, /* byteswap */
+@@ -502,14 +504,12 @@ static const struct bttv_format bttv_formats[] = {
+ 		.flags    = FORMAT_FLAGS_PACKED,
+ 	},{
+ 		.name     = "16 bpp RGB, le",
+-		.palette  = VIDEO_PALETTE_RGB565,
+ 		.fourcc   = V4L2_PIX_FMT_RGB565,
+ 		.btformat = BT848_COLOR_FMT_RGB16,
+ 		.depth    = 16,
+ 		.flags    = FORMAT_FLAGS_PACKED,
+ 	},{
+ 		.name     = "16 bpp RGB, be",
+-		.palette  = -1,
+ 		.fourcc   = V4L2_PIX_FMT_RGB565X,
+ 		.btformat = BT848_COLOR_FMT_RGB16,
+ 		.btswap   = 0x03, /* byteswap */
+@@ -517,21 +517,18 @@ static const struct bttv_format bttv_formats[] = {
+ 		.flags    = FORMAT_FLAGS_PACKED,
+ 	},{
+ 		.name     = "24 bpp RGB, le",
+-		.palette  = VIDEO_PALETTE_RGB24,
+ 		.fourcc   = V4L2_PIX_FMT_BGR24,
+ 		.btformat = BT848_COLOR_FMT_RGB24,
+ 		.depth    = 24,
+ 		.flags    = FORMAT_FLAGS_PACKED,
+ 	},{
+ 		.name     = "32 bpp RGB, le",
+-		.palette  = VIDEO_PALETTE_RGB32,
+ 		.fourcc   = V4L2_PIX_FMT_BGR32,
+ 		.btformat = BT848_COLOR_FMT_RGB32,
+ 		.depth    = 32,
+ 		.flags    = FORMAT_FLAGS_PACKED,
+ 	},{
+ 		.name     = "32 bpp RGB, be",
+-		.palette  = -1,
+ 		.fourcc   = V4L2_PIX_FMT_RGB32,
+ 		.btformat = BT848_COLOR_FMT_RGB32,
+ 		.btswap   = 0x0f, /* byte+word swap */
+@@ -539,21 +536,18 @@ static const struct bttv_format bttv_formats[] = {
+ 		.flags    = FORMAT_FLAGS_PACKED,
+ 	},{
+ 		.name     = "4:2:2, packed, YUYV",
+-		.palette  = VIDEO_PALETTE_YUV422,
+ 		.fourcc   = V4L2_PIX_FMT_YUYV,
+ 		.btformat = BT848_COLOR_FMT_YUY2,
+ 		.depth    = 16,
+ 		.flags    = FORMAT_FLAGS_PACKED,
+ 	},{
+ 		.name     = "4:2:2, packed, YUYV",
+-		.palette  = VIDEO_PALETTE_YUYV,
+ 		.fourcc   = V4L2_PIX_FMT_YUYV,
+ 		.btformat = BT848_COLOR_FMT_YUY2,
+ 		.depth    = 16,
+ 		.flags    = FORMAT_FLAGS_PACKED,
+ 	},{
+ 		.name     = "4:2:2, packed, UYVY",
+-		.palette  = VIDEO_PALETTE_UYVY,
+ 		.fourcc   = V4L2_PIX_FMT_UYVY,
+ 		.btformat = BT848_COLOR_FMT_YUY2,
+ 		.btswap   = 0x03, /* byteswap */
+@@ -561,7 +555,6 @@ static const struct bttv_format bttv_formats[] = {
+ 		.flags    = FORMAT_FLAGS_PACKED,
+ 	},{
+ 		.name     = "4:2:2, planar, Y-Cb-Cr",
+-		.palette  = VIDEO_PALETTE_YUV422P,
+ 		.fourcc   = V4L2_PIX_FMT_YUV422P,
+ 		.btformat = BT848_COLOR_FMT_YCrCb422,
+ 		.depth    = 16,
+@@ -570,7 +563,6 @@ static const struct bttv_format bttv_formats[] = {
+ 		.vshift   = 0,
+ 	},{
+ 		.name     = "4:2:0, planar, Y-Cb-Cr",
+-		.palette  = VIDEO_PALETTE_YUV420P,
+ 		.fourcc   = V4L2_PIX_FMT_YUV420,
+ 		.btformat = BT848_COLOR_FMT_YCrCb422,
+ 		.depth    = 12,
+@@ -579,7 +571,6 @@ static const struct bttv_format bttv_formats[] = {
+ 		.vshift   = 1,
+ 	},{
+ 		.name     = "4:2:0, planar, Y-Cr-Cb",
+-		.palette  = -1,
+ 		.fourcc   = V4L2_PIX_FMT_YVU420,
+ 		.btformat = BT848_COLOR_FMT_YCrCb422,
+ 		.depth    = 12,
+@@ -588,7 +579,6 @@ static const struct bttv_format bttv_formats[] = {
+ 		.vshift   = 1,
+ 	},{
+ 		.name     = "4:1:1, planar, Y-Cb-Cr",
+-		.palette  = VIDEO_PALETTE_YUV411P,
+ 		.fourcc   = V4L2_PIX_FMT_YUV411P,
+ 		.btformat = BT848_COLOR_FMT_YCrCb411,
+ 		.depth    = 12,
+@@ -597,7 +587,6 @@ static const struct bttv_format bttv_formats[] = {
+ 		.vshift   = 0,
+ 	},{
+ 		.name     = "4:1:0, planar, Y-Cb-Cr",
+-		.palette  = VIDEO_PALETTE_YUV410P,
+ 		.fourcc   = V4L2_PIX_FMT_YUV410,
+ 		.btformat = BT848_COLOR_FMT_YCrCb411,
+ 		.depth    = 9,
+@@ -606,7 +595,6 @@ static const struct bttv_format bttv_formats[] = {
+ 		.vshift   = 2,
+ 	},{
+ 		.name     = "4:1:0, planar, Y-Cr-Cb",
+-		.palette  = -1,
+ 		.fourcc   = V4L2_PIX_FMT_YVU410,
+ 		.btformat = BT848_COLOR_FMT_YCrCb411,
+ 		.depth    = 9,
+@@ -615,14 +603,13 @@ static const struct bttv_format bttv_formats[] = {
+ 		.vshift   = 2,
+ 	},{
+ 		.name     = "raw scanlines",
+-		.palette  = VIDEO_PALETTE_RAW,
+ 		.fourcc   = -1,
+ 		.btformat = BT848_COLOR_FMT_RAW,
+ 		.depth    = 8,
+ 		.flags    = FORMAT_FLAGS_RAW,
+ 	}
+ };
+-static const unsigned int BTTV_FORMATS = ARRAY_SIZE(bttv_formats);
++static const unsigned int FORMATS = ARRAY_SIZE(formats);
+ 
+ /* ----------------------------------------------------------------------- */
+ 
+@@ -798,7 +785,17 @@ static const struct v4l2_queryctrl bttv_ctls[] = {
+ 
+ 
+ };
+-static const int BTTV_CTLS = ARRAY_SIZE(bttv_ctls);
 +
-+#if defined(CONFIG_DVB_TUNER_XC5000) || defined(CONFIG_DVB_TUNER_XC5000_MODULE)
-+extern struct dvb_frontend* xc5000_attach(struct dvb_frontend *fe,
-+					  struct i2c_adapter *i2c,
-+					  struct xc5000_config *cfg);
-+#else
-+static inline struct dvb_frontend* xc5000_attach(struct dvb_frontend *fe,
-+						 struct i2c_adapter *i2c,
-+						 struct xc5000_config *cfg)
++static const struct v4l2_queryctrl *ctrl_by_id(int id)
 +{
-+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
-+	return NULL;
-+}
-+#endif // CONFIG_DVB_TUNER_XC5000
-+
-+#endif // __XC5000_H__
-diff --git a/drivers/media/dvb/frontends/xc5000_priv.h b/drivers/media/dvb/frontends/xc5000_priv.h
-new file mode 100644
-index 0000000..13b2d19
---- /dev/null
-+++ b/drivers/media/dvb/frontends/xc5000_priv.h
-@@ -0,0 +1,36 @@
-+/*
-+ *  Driver for Xceive XC5000 "QAM/8VSB single chip tuner"
-+ *
-+ *  Copyright (c) 2007 Steven Toth <stoth at hauppauge.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 XC5000_PRIV_H
-+#define XC5000_PRIV_H
-+
-+struct xc5000_priv {
-+	struct xc5000_config *cfg;
-+	struct i2c_adapter   *i2c;
++	int i;
 +
-+	u32 freq_hz;
-+	u32 bandwidth;
-+	u8  video_standard;
-+	u8  rf_mode;
-+	u8  fwloaded;
-+};
++	for (i = 0; i < ARRAY_SIZE(bttv_ctls); i++)
++		if (bttv_ctls[i].id == id)
++			return bttv_ctls+i;
 +
-+#endif
-diff --git a/drivers/media/dvb/frontends/zl10353.c b/drivers/media/dvb/frontends/zl10353.c
-index 0106df4..276e3b6 100644
---- a/drivers/media/dvb/frontends/zl10353.c
-+++ b/drivers/media/dvb/frontends/zl10353.c
-@@ -1,7 +1,7 @@
- /*
-  * Driver for Zarlink DVB-T ZL10353 demodulator
-  *
-- * Copyright (C) 2006 Christopher Pascoe <c.pascoe at itee.uq.edu.au>
-+ * Copyright (C) 2006, 2007 Christopher Pascoe <c.pascoe at itee.uq.edu.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
-@@ -16,7 +16,7 @@
-  *
-  * You 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.=
-+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-  */
++	return NULL;
++}
  
- #include <linux/kernel.h>
-@@ -25,6 +25,7 @@
- #include <linux/delay.h>
- #include <linux/string.h>
- #include <linux/slab.h>
-+#include <asm/div64.h>
+ /* ----------------------------------------------------------------------- */
+ /* resource management                                                     */
+@@ -1255,16 +1252,6 @@ audio_input(struct bttv *btv, int input)
+ }
  
- #include "dvb_frontend.h"
- #include "zl10353_priv.h"
-@@ -35,6 +36,8 @@ struct zl10353_state {
- 	struct dvb_frontend frontend;
+ static void
+-i2c_vidiocschan(struct bttv *btv)
+-{
+-	v4l2_std_id std = bttv_tvnorms[btv->tvnorm].v4l2_id;
+-
+-	bttv_call_i2c_clients(btv, VIDIOC_S_STD, &std);
+-	if (btv->c.type == BTTV_BOARD_VOODOOTV_FM || btv->c.type == BTTV_BOARD_VOODOOTV_200)
+-		bttv_tda9880_setnorm(btv,btv->tvnorm);
+-}
+-
+-static void
+ bttv_crop_calc_limits(struct bttv_crop *c)
+ {
+ 	/* Scale factor min. 1:1, max. 16:1. Min. image size
+@@ -1298,6 +1285,7 @@ static int
+ set_tvnorm(struct bttv *btv, unsigned int norm)
+ {
+ 	const struct bttv_tvnorm *tvnorm;
++	v4l2_std_id id;
  
- 	struct zl10353_config config;
+ 	if (norm < 0 || norm >= BTTV_TVNORMS)
+ 		return -EINVAL;
+@@ -1334,6 +1322,9 @@ set_tvnorm(struct bttv *btv, unsigned int norm)
+ 		bttv_tda9880_setnorm(btv,norm);
+ 		break;
+ 	}
++	id = tvnorm->v4l2_id;
++	bttv_call_i2c_clients(btv, VIDIOC_S_STD, &id);
 +
-+	enum fe_bandwidth bandwidth;
- };
+ 	return 0;
+ }
  
- static int debug;
-@@ -122,9 +125,10 @@ static void zl10353_calc_nominal_rate(struct dvb_frontend *fe,
- 				      enum fe_bandwidth bandwidth,
- 				      u16 *nominal_rate)
+@@ -1359,7 +1350,6 @@ set_input(struct bttv *btv, unsigned int input, unsigned int norm)
+ 	audio_input(btv,(input == bttv_tvcards[btv->c.type].tuner ?
+ 		       TVAUDIO_INPUT_TUNER : TVAUDIO_INPUT_EXTERN));
+ 	set_tvnorm(btv, norm);
+-	i2c_vidiocschan(btv);
+ }
+ 
+ static void init_irqreg(struct bttv *btv)
+@@ -1452,38 +1442,12 @@ static void bttv_reinit_bt848(struct bttv *btv)
+ 	set_input(btv, btv->input, btv->tvnorm);
+ }
+ 
+-static int get_control(struct bttv *btv, struct v4l2_control *c)
++static int bttv_g_ctrl(struct file *file, void *priv,
++					struct v4l2_control *c)
  {
--	u32 adc_clock = 45056; /* 45.056 MHz */
--	u8 bw;
- 	struct zl10353_state *state = fe->demodulator_priv;
-+	u32 adc_clock = 450560; /* 45.056 MHz */
-+	u64 value;
-+	u8 bw;
+-	struct video_audio va;
+-	int i;
++	struct bttv_fh *fh = priv;
++	struct bttv *btv = fh->btv;
  
- 	if (state->config.adc_clock)
- 		adc_clock = state->config.adc_clock;
-@@ -142,12 +146,44 @@ static void zl10353_calc_nominal_rate(struct dvb_frontend *fe,
+-	for (i = 0; i < BTTV_CTLS; i++)
+-		if (bttv_ctls[i].id == c->id)
+-			break;
+-	if (i == BTTV_CTLS)
+-		return -EINVAL;
+-	if (btv->audio_hook && i >= 4 && i <= 8) {
+-		memset(&va,0,sizeof(va));
+-		btv->audio_hook(btv,&va,0);
+-		switch (c->id) {
+-		case V4L2_CID_AUDIO_MUTE:
+-			c->value = (VIDEO_AUDIO_MUTE & va.flags) ? 1 : 0;
+-			break;
+-		case V4L2_CID_AUDIO_VOLUME:
+-			c->value = va.volume;
+-			break;
+-		case V4L2_CID_AUDIO_BALANCE:
+-			c->value = va.balance;
+-			break;
+-		case V4L2_CID_AUDIO_BASS:
+-			c->value = va.bass;
+-			break;
+-		case V4L2_CID_AUDIO_TREBLE:
+-			c->value = va.treble;
+-			break;
+-		}
+-		return 0;
+-	}
+ 	switch (c->id) {
+ 	case V4L2_CID_BRIGHTNESS:
+ 		c->value = btv->bright;
+@@ -1503,7 +1467,7 @@ static int get_control(struct bttv *btv, struct v4l2_control *c)
+ 	case V4L2_CID_AUDIO_BALANCE:
+ 	case V4L2_CID_AUDIO_BASS:
+ 	case V4L2_CID_AUDIO_TREBLE:
+-		bttv_call_i2c_clients(btv,VIDIOC_G_CTRL,c);
++		bttv_call_i2c_clients(btv, VIDIOC_G_CTRL, c);
  		break;
- 	}
- 
--	*nominal_rate = (bw * (1 << 23) / 7 * 125 + adc_clock / 2) / adc_clock;
-+	value = (u64)10 * (1 << 23) / 7 * 125;
-+	value = (bw * value) + adc_clock / 2;
-+	do_div(value, adc_clock);
-+	*nominal_rate = value;
  
- 	dprintk("%s: bw %d, adc_clock %d => 0x%x\n",
- 		__FUNCTION__, bw, adc_clock, *nominal_rate);
+ 	case V4L2_CID_PRIVATE_CHROMA_AGC:
+@@ -1545,67 +1509,44 @@ static int get_control(struct bttv *btv, struct v4l2_control *c)
+ 	return 0;
  }
  
-+static void zl10353_calc_input_freq(struct dvb_frontend *fe,
-+				    u16 *input_freq)
-+{
-+	struct zl10353_state *state = fe->demodulator_priv;
-+	u32 adc_clock = 450560;	/* 45.056  MHz */
-+	int if2 = 361667;	/* 36.1667 MHz */
-+	int ife;
-+	u64 value;
-+
-+	if (state->config.adc_clock)
-+		adc_clock = state->config.adc_clock;
-+	if (state->config.if2)
-+		if2 = state->config.if2;
-+
-+	if (adc_clock >= if2 * 2)
-+		ife = if2;
-+	else {
-+		ife = adc_clock - (if2 % adc_clock);
-+		if (ife > adc_clock / 2)
-+			ife = adc_clock - ife;
-+	}
-+	value = (u64)65536 * ife + adc_clock / 2;
-+	do_div(value, adc_clock);
-+	*input_freq = -value;
-+
-+	dprintk("%s: if2 %d, ife %d, adc_clock %d => %d / 0x%x\n",
-+		__FUNCTION__, if2, ife, adc_clock, -(int)value, *input_freq);
-+}
-+
- static int zl10353_sleep(struct dvb_frontend *fe)
+-static int set_control(struct bttv *btv, struct v4l2_control *c)
++static int bttv_s_ctrl(struct file *file, void *f,
++					struct v4l2_control *c)
  {
- 	static u8 zl10353_softdown[] = { 0x50, 0x0C, 0x44 };
-@@ -160,64 +196,276 @@ static int zl10353_set_parameters(struct dvb_frontend *fe,
- 				  struct dvb_frontend_parameters *param)
+-	struct video_audio va;
+-	int i,val;
++	int err;
++	int val;
++	struct bttv_fh *fh = f;
++	struct bttv *btv = fh->btv;
+ 
+-	for (i = 0; i < BTTV_CTLS; i++)
+-		if (bttv_ctls[i].id == c->id)
+-			break;
+-	if (i == BTTV_CTLS)
+-		return -EINVAL;
+-	if (btv->audio_hook && i >= 4 && i <= 8) {
+-		memset(&va,0,sizeof(va));
+-		btv->audio_hook(btv,&va,0);
+-		switch (c->id) {
+-		case V4L2_CID_AUDIO_MUTE:
+-			if (c->value) {
+-				va.flags |= VIDEO_AUDIO_MUTE;
+-				audio_mute(btv, 1);
+-			} else {
+-				va.flags &= ~VIDEO_AUDIO_MUTE;
+-				audio_mute(btv, 0);
+-			}
+-			break;
++	err = v4l2_prio_check(&btv->prio, &fh->prio);
++	if (0 != err)
++		return err;
+ 
+-		case V4L2_CID_AUDIO_VOLUME:
+-			va.volume = c->value;
+-			break;
+-		case V4L2_CID_AUDIO_BALANCE:
+-			va.balance = c->value;
+-			break;
+-		case V4L2_CID_AUDIO_BASS:
+-			va.bass = c->value;
+-			break;
+-		case V4L2_CID_AUDIO_TREBLE:
+-			va.treble = c->value;
+-			break;
+-		}
+-		btv->audio_hook(btv,&va,1);
+-		return 0;
+-	}
+ 	switch (c->id) {
+ 	case V4L2_CID_BRIGHTNESS:
+-		bt848_bright(btv,c->value);
++		bt848_bright(btv, c->value);
+ 		break;
+ 	case V4L2_CID_HUE:
+-		bt848_hue(btv,c->value);
++		bt848_hue(btv, c->value);
+ 		break;
+ 	case V4L2_CID_CONTRAST:
+-		bt848_contrast(btv,c->value);
++		bt848_contrast(btv, c->value);
+ 		break;
+ 	case V4L2_CID_SATURATION:
+-		bt848_sat(btv,c->value);
++		bt848_sat(btv, c->value);
+ 		break;
+ 	case V4L2_CID_AUDIO_MUTE:
+ 		audio_mute(btv, c->value);
+ 		/* fall through */
+ 	case V4L2_CID_AUDIO_VOLUME:
++		if (btv->volume_gpio)
++			btv->volume_gpio(btv, c->value);
++
++		bttv_call_i2c_clients(btv, VIDIOC_S_CTRL, c);
++		break;
+ 	case V4L2_CID_AUDIO_BALANCE:
+ 	case V4L2_CID_AUDIO_BASS:
+ 	case V4L2_CID_AUDIO_TREBLE:
+-		bttv_call_i2c_clients(btv,VIDIOC_S_CTRL,c);
++		bttv_call_i2c_clients(btv, VIDIOC_S_CTRL, c);
+ 		break;
+ 
+ 	case V4L2_CID_PRIVATE_CHROMA_AGC:
+@@ -1632,8 +1573,9 @@ static int set_control(struct bttv *btv, struct v4l2_control *c)
+ 		break;
+ 	case V4L2_CID_PRIVATE_AGC_CRUSH:
+ 		btv->opt_adc_crush = c->value;
+-		btwrite(BT848_ADC_RESERVED | (btv->opt_adc_crush ? BT848_ADC_CRUSH : 0),
+-			BT848_ADC);
++		btwrite(BT848_ADC_RESERVED |
++				(btv->opt_adc_crush ? BT848_ADC_CRUSH : 0),
++				BT848_ADC);
+ 		break;
+ 	case V4L2_CID_PRIVATE_VCR_HACK:
+ 		btv->opt_vcr_hack = c->value;
+@@ -1693,29 +1635,15 @@ static void bttv_field_count(struct bttv *btv)
+ }
+ 
+ static const struct bttv_format*
+-format_by_palette(int palette)
+-{
+-	unsigned int i;
+-
+-	for (i = 0; i < BTTV_FORMATS; i++) {
+-		if (-1 == bttv_formats[i].palette)
+-			continue;
+-		if (bttv_formats[i].palette == palette)
+-			return bttv_formats+i;
+-	}
+-	return NULL;
+-}
+-
+-static const struct bttv_format*
+ format_by_fourcc(int fourcc)
  {
- 	struct zl10353_state *state = fe->demodulator_priv;
--	u16 nominal_rate;
--	u8 pllbuf[6] = { 0x67 };
-+	u16 nominal_rate, input_freq;
-+	u8 pllbuf[6] = { 0x67 }, acq_ctl = 0;
-+	u16 tps = 0;
-+	struct dvb_ofdm_parameters *op = &param->u.ofdm;
+ 	unsigned int i;
+ 
+-	for (i = 0; i < BTTV_FORMATS; i++) {
+-		if (-1 == bttv_formats[i].fourcc)
++	for (i = 0; i < FORMATS; i++) {
++		if (-1 == formats[i].fourcc)
+ 			continue;
+-		if (bttv_formats[i].fourcc == fourcc)
+-			return bttv_formats+i;
++		if (formats[i].fourcc == fourcc)
++			return formats+i;
+ 	}
+ 	return NULL;
+ }
+@@ -1733,7 +1661,7 @@ bttv_switch_overlay(struct bttv *btv, struct bttv_fh *fh,
+ 
+ 	dprintk("switch_overlay: enter [new=%p]\n",new);
+ 	if (new)
+-		new->vb.state = STATE_DONE;
++		new->vb.state = VIDEOBUF_DONE;
+ 	spin_lock_irqsave(&btv->s_lock,flags);
+ 	old = btv->screen;
+ 	btv->screen = new;
+@@ -1844,7 +1772,7 @@ static int bttv_prepare_buffer(struct videobuf_queue *q,struct bttv *btv,
+ 	}
+ 
+ 	/* alloc risc memory */
+-	if (STATE_NEEDS_INIT == buf->vb.state) {
++	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
+ 		redo_dma_risc = 1;
+ 		if (0 != (rc = videobuf_iolock(q,&buf->vb,&btv->fbuf)))
+ 			goto fail;
+@@ -1854,7 +1782,7 @@ static int bttv_prepare_buffer(struct videobuf_queue *q,struct bttv *btv,
+ 		if (0 != (rc = bttv_buffer_risc(btv,buf)))
+ 			goto fail;
+ 
+-	buf->vb.state = STATE_PREPARED;
++	buf->vb.state = VIDEOBUF_PREPARED;
+ 	return 0;
+ 
+  fail:
+@@ -1893,7 +1821,7 @@ buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
+ 	struct bttv_fh *fh = q->priv_data;
+ 	struct bttv    *btv = fh->btv;
+ 
+-	buf->vb.state = STATE_QUEUED;
++	buf->vb.state = VIDEOBUF_QUEUED;
+ 	list_add_tail(&buf->vb.queue,&btv->capture);
+ 	if (!btv->curr.frame_irq) {
+ 		btv->loop_irq |= 1;
+@@ -1916,374 +1844,234 @@ static struct videobuf_queue_ops bttv_video_qops = {
+ 	.buf_release  = buffer_release,
+ };
  
--	/* These settings set "auto-everything" and start the FSM. */
--	zl10353_single_write(fe, 0x55, 0x80);
-+	zl10353_single_write(fe, RESET, 0x80);
- 	udelay(200);
- 	zl10353_single_write(fe, 0xEA, 0x01);
- 	udelay(200);
- 	zl10353_single_write(fe, 0xEA, 0x00);
+-static int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg)
++static int bttv_s_std(struct file *file, void *priv, v4l2_std_id *id)
+ {
+-	switch (cmd) {
+-	case BTTV_VERSION:
+-		return BTTV_VERSION_CODE;
++	struct bttv_fh *fh  = priv;
++	struct bttv *btv = fh->btv;
++	unsigned int i;
++	int err;
  
--	zl10353_single_write(fe, 0x56, 0x28);
--	zl10353_single_write(fe, 0x89, 0x20);
--	zl10353_single_write(fe, 0x5E, 0x00);
-+	zl10353_single_write(fe, AGC_TARGET, 0x28);
-+
-+	if (op->transmission_mode != TRANSMISSION_MODE_AUTO)
-+		acq_ctl |= (1 << 0);
-+	if (op->guard_interval != GUARD_INTERVAL_AUTO)
-+		acq_ctl |= (1 << 1);
-+	zl10353_single_write(fe, ACQ_CTL, acq_ctl);
+-	/* ***  v4l1  *** ************************************************ */
+-	case VIDIOCGFREQ:
+-	{
+-		unsigned long *freq = arg;
+-		*freq = btv->freq;
+-		return 0;
+-	}
+-	case VIDIOCSFREQ:
+-	{
+-		struct v4l2_frequency freq;
++	err = v4l2_prio_check(&btv->prio, &fh->prio);
++	if (0 != err)
++		return err;
  
--	zl10353_calc_nominal_rate(fe, param->u.ofdm.bandwidth, &nominal_rate);
-+	switch (op->bandwidth) {
-+	case BANDWIDTH_6_MHZ:
-+		/* These are extrapolated from the 7 and 8MHz values */
-+		zl10353_single_write(fe, MCLK_RATIO, 0x97);
-+		zl10353_single_write(fe, 0x64, 0x34);
-+		break;
-+	case BANDWIDTH_7_MHZ:
-+		zl10353_single_write(fe, MCLK_RATIO, 0x86);
-+		zl10353_single_write(fe, 0x64, 0x35);
-+		break;
-+	case BANDWIDTH_8_MHZ:
-+	default:
-+		zl10353_single_write(fe, MCLK_RATIO, 0x75);
-+		zl10353_single_write(fe, 0x64, 0x36);
-+	}
-+
-+	zl10353_calc_nominal_rate(fe, op->bandwidth, &nominal_rate);
- 	zl10353_single_write(fe, TRL_NOMINAL_RATE_1, msb(nominal_rate));
- 	zl10353_single_write(fe, TRL_NOMINAL_RATE_0, lsb(nominal_rate));
-+	state->bandwidth = op->bandwidth;
-+
-+	zl10353_calc_input_freq(fe, &input_freq);
-+	zl10353_single_write(fe, INPUT_FREQ_1, msb(input_freq));
-+	zl10353_single_write(fe, INPUT_FREQ_0, lsb(input_freq));
-+
-+	/* Hint at TPS settings */
-+	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:
-+		break;
-+	default:
-+		return -EINVAL;
-+	}
-+
-+	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:
-+		break;
-+	case FEC_NONE:
-+		if (op->hierarchy_information == HIERARCHY_AUTO ||
-+		    op->hierarchy_information == HIERARCHY_NONE)
+-		memset(&freq, 0, sizeof(freq));
+-		freq.frequency = *(unsigned long *)arg;
+-		mutex_lock(&btv->lock);
+-		freq.type = btv->radio_user ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
+-		btv->freq = *(unsigned long *)arg;
+-		bttv_call_i2c_clients(btv,VIDIOC_S_FREQUENCY,&freq);
+-		if (btv->has_matchbox && btv->radio_user)
+-			tea5757_set_freq(btv,*(unsigned long *)arg);
+-		mutex_unlock(&btv->lock);
+-		return 0;
+-	}
++	for (i = 0; i < BTTV_TVNORMS; i++)
++		if (*id & bttv_tvnorms[i].v4l2_id)
 +			break;
-+	default:
-+		return -EINVAL;
-+	}
-+
-+	switch (op->constellation) {
-+	case QPSK:
-+		break;
-+	case QAM_AUTO:
-+	case QAM_16:
-+		tps |= (1 << 13);
-+		break;
-+	case QAM_64:
-+		tps |= (2 << 13);
-+		break;
-+	default:
-+		return -EINVAL;
-+	}
-+
-+	switch (op->transmission_mode) {
-+	case TRANSMISSION_MODE_2K:
-+	case TRANSMISSION_MODE_AUTO:
-+		break;
-+	case TRANSMISSION_MODE_8K:
-+		tps |= (1 << 0);
-+		break;
-+	default:
-+		return -EINVAL;
-+	}
-+
-+	switch (op->guard_interval) {
-+	case GUARD_INTERVAL_1_32:
-+	case GUARD_INTERVAL_AUTO:
-+		break;
-+	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;
-+	default:
-+		return -EINVAL;
-+	}
-+
-+	switch (op->hierarchy_information) {
-+	case HIERARCHY_AUTO:
-+	case HIERARCHY_NONE:
-+		break;
-+	case HIERARCHY_1:
-+		tps |= (1 << 10);
-+		break;
-+	case HIERARCHY_2:
-+		tps |= (2 << 10);
-+		break;
-+	case HIERARCHY_4:
-+		tps |= (3 << 10);
-+		break;
-+	default:
++	if (i == BTTV_TVNORMS)
 +		return -EINVAL;
-+	}
-+
-+	zl10353_single_write(fe, TPS_GIVEN_1, msb(tps));
-+	zl10353_single_write(fe, TPS_GIVEN_0, lsb(tps));
  
--	zl10353_single_write(fe, 0x6C, 0xCD);
--	zl10353_single_write(fe, 0x6D, 0x7E);
- 	if (fe->ops.i2c_gate_ctrl)
- 		fe->ops.i2c_gate_ctrl(fe, 0);
+-	case VIDIOCGTUNER:
+-	{
+-		struct video_tuner *v = arg;
++	mutex_lock(&btv->lock);
++	set_tvnorm(btv, i);
++	mutex_unlock(&btv->lock);
  
--	// if there is no attached secondary tuner, we call set_params to program
--	// a potential tuner attached somewhere else
-+	/*
-+	 * If there is no tuner attached to the secondary I2C bus, we call
-+	 * set_params to program a potential tuner attached somewhere else.
-+	 * Otherwise, we update the PLL registers via calc_regs.
-+	 */
- 	if (state->config.no_tuner) {
- 		if (fe->ops.tuner_ops.set_params) {
- 			fe->ops.tuner_ops.set_params(fe, param);
- 			if (fe->ops.i2c_gate_ctrl)
- 				fe->ops.i2c_gate_ctrl(fe, 0);
- 		}
-+	} else if (fe->ops.tuner_ops.calc_regs) {
-+		fe->ops.tuner_ops.calc_regs(fe, param, pllbuf + 1, 5);
-+		pllbuf[1] <<= 1;
-+		zl10353_write(fe, pllbuf, sizeof(pllbuf));
- 	}
+-		if (UNSET == bttv_tvcards[btv->c.type].tuner)
+-			return -EINVAL;
+-		if (v->tuner) /* Only tuner 0 */
+-			return -EINVAL;
+-		strcpy(v->name, "Television");
+-		v->rangelow  = 0;
+-		v->rangehigh = 0x7FFFFFFF;
+-		v->flags     = VIDEO_TUNER_PAL|VIDEO_TUNER_NTSC|VIDEO_TUNER_SECAM;
+-		v->mode      = btv->tvnorm;
+-		v->signal    = (btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC) ? 0xFFFF : 0;
+-		bttv_call_i2c_clients(btv,cmd,v);
+-		return 0;
+-	}
+-	case VIDIOCSTUNER:
+-	{
+-		struct video_tuner *v = arg;
++	return 0;
++}
  
--	// if pllbuf is defined, retrieve the settings
--	if (fe->ops.tuner_ops.calc_regs) {
--		fe->ops.tuner_ops.calc_regs(fe, param, pllbuf+1, 5);
--		pllbuf[1] <<= 1;
--	} else {
--		// fake pllbuf settings
--		pllbuf[1] = 0x61 << 1;
--		pllbuf[2] = 0;
--		pllbuf[3] = 0;
--		pllbuf[3] = 0;
--		pllbuf[4] = 0;
-+	zl10353_single_write(fe, 0x5F, 0x13);
-+
-+	/* If no attached tuner or invalid PLL registers, just start the FSM. */
-+	if (state->config.no_tuner || fe->ops.tuner_ops.calc_regs == NULL)
-+		zl10353_single_write(fe, FSM_GO, 0x01);
+-		if (v->tuner) /* Only tuner 0 */
+-			return -EINVAL;
+-		if (v->mode >= BTTV_TVNORMS)
+-			return -EINVAL;
++static int bttv_querystd(struct file *file, void *f, v4l2_std_id *id)
++{
++	struct bttv_fh *fh = f;
++	struct bttv *btv = fh->btv;
+ 
+-		mutex_lock(&btv->lock);
+-		set_tvnorm(btv,v->mode);
+-		bttv_call_i2c_clients(btv,cmd,v);
+-		mutex_unlock(&btv->lock);
+-		return 0;
+-	}
++	if (btread(BT848_DSTATUS) & BT848_DSTATUS_NUML)
++		*id = V4L2_STD_625_50;
 +	else
-+		zl10353_single_write(fe, TUNER_GO, 0x01);
-+
++		*id = V4L2_STD_525_60;
 +	return 0;
 +}
-+
-+static int zl10353_get_parameters(struct dvb_frontend *fe,
-+				  struct dvb_frontend_parameters *param)
+ 
+-	case VIDIOCGCHAN:
+-	{
+-		struct video_channel *v = arg;
+-		unsigned int channel = v->channel;
++static int bttv_enum_input(struct file *file, void *priv,
++					struct v4l2_input *i)
 +{
-+	struct zl10353_state *state = fe->demodulator_priv;
-+	struct dvb_ofdm_parameters *op = &param->u.ofdm;
-+	int s6, s9;
-+	u16 tps;
-+	static const u8 tps_fec_to_api[8] = {
-+		FEC_1_2,
-+		FEC_2_3,
-+		FEC_3_4,
-+		FEC_5_6,
-+		FEC_7_8,
-+		FEC_AUTO,
-+		FEC_AUTO,
-+		FEC_AUTO
-+	};
-+
-+	s6 = zl10353_read_register(state, STATUS_6);
-+	s9 = zl10353_read_register(state, STATUS_9);
-+	if (s6 < 0 || s9 < 0)
-+		return -EREMOTEIO;
-+	if ((s6 & (1 << 5)) == 0 || (s9 & (1 << 4)) == 0)
-+		return -EINVAL;	/* no FE or TPS lock */
-+
-+	tps = zl10353_read_register(state, TPS_RECEIVED_1) << 8 |
-+	      zl10353_read_register(state, TPS_RECEIVED_0);
-+
-+	op->code_rate_HP = tps_fec_to_api[(tps >> 7) & 7];
-+	op->code_rate_LP = tps_fec_to_api[(tps >> 4) & 7];
-+
-+	switch ((tps >> 13) & 3) {
-+	case 0:
-+		op->constellation = QPSK;
-+		break;
-+	case 1:
-+		op->constellation = QAM_16;
-+		break;
-+	case 2:
-+		op->constellation = QAM_64;
-+		break;
-+	default:
-+		op->constellation = QAM_AUTO;
-+		break;
- 	}
++	struct bttv_fh *fh = priv;
++	struct bttv *btv = fh->btv;
++	unsigned int n;
  
--	// there is no call to _just_ start decoding, so we send the pllbuf anyway
--	// even if there isn't a PLL attached to the secondary bus
--	zl10353_write(fe, pllbuf, sizeof(pllbuf));
-+	op->transmission_mode = (tps & 0x01) ? TRANSMISSION_MODE_8K :
-+					       TRANSMISSION_MODE_2K;
+-		if (channel >= bttv_tvcards[btv->c.type].video_inputs)
+-			return -EINVAL;
+-		v->tuners=0;
+-		v->flags = VIDEO_VC_AUDIO;
+-		v->type = VIDEO_TYPE_CAMERA;
+-		v->norm = btv->tvnorm;
+-		if (channel == bttv_tvcards[btv->c.type].tuner)  {
+-			strcpy(v->name,"Television");
+-			v->flags|=VIDEO_VC_TUNER;
+-			v->type=VIDEO_TYPE_TV;
+-			v->tuners=1;
+-		} else if (channel == btv->svhs) {
+-			strcpy(v->name,"S-Video");
+-		} else {
+-			sprintf(v->name,"Composite%d",channel);
+-		}
+-		return 0;
+-	}
+-	case VIDIOCSCHAN:
+-	{
+-		struct video_channel *v = arg;
+-		unsigned int channel = v->channel;
++	n = i->index;
  
--	zl10353_single_write(fe, 0x5F, 0x13);
--	zl10353_single_write(fe, 0x70, 0x01);
--	udelay(250);
--	zl10353_single_write(fe, 0xE4, 0x00);
--	zl10353_single_write(fe, 0xE5, 0x2A);
--	zl10353_single_write(fe, 0xE9, 0x02);
--	zl10353_single_write(fe, 0xE7, 0x40);
--	zl10353_single_write(fe, 0xE8, 0x10);
-+	switch ((tps >> 2) & 3) {
-+	case 0:
-+		op->guard_interval = GUARD_INTERVAL_1_32;
-+		break;
-+	case 1:
-+		op->guard_interval = GUARD_INTERVAL_1_16;
-+		break;
-+	case 2:
-+		op->guard_interval = GUARD_INTERVAL_1_8;
-+		break;
-+	case 3:
-+		op->guard_interval = GUARD_INTERVAL_1_4;
-+		break;
-+	default:
-+		op->guard_interval = GUARD_INTERVAL_AUTO;
-+		break;
-+	}
-+
-+	switch ((tps >> 10) & 7) {
-+	case 0:
-+		op->hierarchy_information = HIERARCHY_NONE;
-+		break;
-+	case 1:
-+		op->hierarchy_information = HIERARCHY_1;
-+		break;
-+	case 2:
-+		op->hierarchy_information = HIERARCHY_2;
-+		break;
-+	case 3:
-+		op->hierarchy_information = HIERARCHY_4;
-+		break;
-+	default:
-+		op->hierarchy_information = HIERARCHY_AUTO;
-+		break;
-+	}
-+
-+	param->frequency = 0;
-+	op->bandwidth = state->bandwidth;
-+	param->inversion = INVERSION_AUTO;
+-		if (channel >= bttv_tvcards[btv->c.type].video_inputs)
+-			return -EINVAL;
+-		if (v->norm >= BTTV_TVNORMS)
+-			return -EINVAL;
++	if (n >= bttv_tvcards[btv->c.type].video_inputs)
++		return -EINVAL;
  
- 	return 0;
- }
-@@ -406,6 +654,7 @@ static struct dvb_frontend_ops zl10353_ops = {
- 	.write = zl10353_write,
+-		mutex_lock(&btv->lock);
+-		if (channel == btv->input &&
+-		    v->norm == btv->tvnorm) {
+-			/* nothing to do */
+-			mutex_unlock(&btv->lock);
+-			return 0;
+-		}
++	memset(i, 0, sizeof(*i));
  
- 	.set_frontend = zl10353_set_parameters,
-+	.get_frontend = zl10353_get_parameters,
- 	.get_tune_settings = zl10353_get_tune_settings,
+-		set_input(btv, v->channel, v->norm);
+-		mutex_unlock(&btv->lock);
+-		return 0;
++	i->index    = n;
++	i->type     = V4L2_INPUT_TYPE_CAMERA;
++	i->audioset = 1;
++
++	if (i->index == bttv_tvcards[btv->c.type].tuner) {
++		sprintf(i->name, "Television");
++		i->type  = V4L2_INPUT_TYPE_TUNER;
++		i->tuner = 0;
++	} else if (i->index == btv->svhs) {
++		sprintf(i->name, "S-Video");
++	} else {
++		sprintf(i->name, "Composite%d", i->index);
+ 	}
  
- 	.read_status = zl10353_read_status,
-diff --git a/drivers/media/dvb/frontends/zl10353.h b/drivers/media/dvb/frontends/zl10353.h
-index 1c3d494..fc734c2 100644
---- a/drivers/media/dvb/frontends/zl10353.h
-+++ b/drivers/media/dvb/frontends/zl10353.h
-@@ -1,7 +1,7 @@
- /*
-  *  Driver for Zarlink DVB-T ZL10353 demodulator
-  *
-- *  Copyright (C) 2006 Christopher Pascoe <c.pascoe at itee.uq.edu.au>
-+ *  Copyright (C) 2006, 2007 Christopher Pascoe <c.pascoe at itee.uq.edu.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
-@@ -29,8 +29,9 @@ struct zl10353_config
- 	/* demodulator's I2C address */
- 	u8 demod_address;
+-	case VIDIOCGAUDIO:
+-	{
+-		struct video_audio *v = arg;
++	if (i->index == btv->input) {
++		__u32 dstatus = btread(BT848_DSTATUS);
++		if (0 == (dstatus & BT848_DSTATUS_PRES))
++			i->status |= V4L2_IN_ST_NO_SIGNAL;
++		if (0 == (dstatus & BT848_DSTATUS_HLOC))
++			i->status |= V4L2_IN_ST_NO_H_LOCK;
++	}
  
--	/* frequencies in kHz */
--	int adc_clock;	/* default: 45056 */
-+	/* frequencies in units of 0.1kHz */
-+	int adc_clock;	/* default: 450560 (45.056  MHz) */
-+	int if2;	/* default: 361667 (36.1667 MHz) */
+-		memset(v,0,sizeof(*v));
+-		strcpy(v->name,"Television");
+-		v->flags |= VIDEO_AUDIO_MUTABLE;
+-		v->mode  = VIDEO_SOUND_MONO;
++	for (n = 0; n < BTTV_TVNORMS; n++)
++		i->std |= bttv_tvnorms[n].v4l2_id;
  
- 	/* set if no pll is connected to the secondary i2c bus */
- 	int no_tuner;
-@@ -49,6 +50,6 @@ static inline struct dvb_frontend* zl10353_attach(const struct zl10353_config *c
- 	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
- 	return NULL;
- }
--#endif // CONFIG_DVB_ZL10353
-+#endif /* CONFIG_DVB_ZL10353 */
+-		mutex_lock(&btv->lock);
+-		bttv_call_i2c_clients(btv,cmd,v);
++	return 0;
++}
  
- #endif /* ZL10353_H */
-diff --git a/drivers/media/dvb/frontends/zl10353_priv.h b/drivers/media/dvb/frontends/zl10353_priv.h
-index 4962434..055ff1f 100644
---- a/drivers/media/dvb/frontends/zl10353_priv.h
-+++ b/drivers/media/dvb/frontends/zl10353_priv.h
-@@ -1,7 +1,7 @@
- /*
-  *  Driver for Zarlink DVB-T ZL10353 demodulator
-  *
-- *  Copyright (C) 2006 Christopher Pascoe <c.pascoe at itee.uq.edu.au>
-+ *  Copyright (C) 2006, 2007 Christopher Pascoe <c.pascoe at itee.uq.edu.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
-@@ -16,7 +16,7 @@
-  *
-  *  You 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.=
-+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-  */
+-		/* card specific hooks */
+-		if (btv->audio_hook)
+-			btv->audio_hook(btv,v,0);
++static int bttv_g_input(struct file *file, void *priv, unsigned int *i)
++{
++	struct bttv_fh *fh = priv;
++	struct bttv *btv = fh->btv;
  
- #ifndef _ZL10353_PRIV_
-@@ -46,9 +46,28 @@ enum zl10353_reg_addr {
- 	RS_ERR_CNT_0       = 0x13,
- 	RS_UBC_1           = 0x14,
- 	RS_UBC_0           = 0x15,
-+	TPS_RECEIVED_1     = 0x1D,
-+	TPS_RECEIVED_0     = 0x1E,
-+	TPS_CURRENT_1      = 0x1F,
-+	TPS_CURRENT_0      = 0x20,
-+	RESET              = 0x55,
-+	AGC_TARGET         = 0x56,
-+	MCLK_RATIO         = 0x5C,
-+	ACQ_CTL            = 0x5E,
- 	TRL_NOMINAL_RATE_1 = 0x65,
- 	TRL_NOMINAL_RATE_0 = 0x66,
-+	INPUT_FREQ_1       = 0x6C,
-+	INPUT_FREQ_0       = 0x6D,
-+	TPS_GIVEN_1        = 0x6E,
-+	TPS_GIVEN_0        = 0x6F,
-+	TUNER_GO           = 0x70,
-+	FSM_GO             = 0x71,
- 	CHIP_ID            = 0x7F,
-+	CHAN_STEP_1        = 0xE4,
-+	CHAN_STEP_0        = 0xE5,
-+	OFDM_LOCK_TIME     = 0xE7,
-+	FEC_LOCK_TIME      = 0xE8,
-+	ACQ_DELAY          = 0xE9,
- };
+-		mutex_unlock(&btv->lock);
+-		return 0;
+-	}
+-	case VIDIOCSAUDIO:
+-	{
+-		struct video_audio *v = arg;
+-		unsigned int audio = v->audio;
++	*i = btv->input;
++	return 0;
++}
  
- #endif                          /* _ZL10353_PRIV_ */
-diff --git a/drivers/media/dvb/ttpci/Kconfig b/drivers/media/dvb/ttpci/Kconfig
-index 54b91f2..ae88243 100644
---- a/drivers/media/dvb/ttpci/Kconfig
-+++ b/drivers/media/dvb/ttpci/Kconfig
-@@ -1,8 +1,14 @@
-+config TTPCI_EEPROM
-+	tristate
-+	default n
-+
- config DVB_AV7110
- 	tristate "AV7110 cards"
--	depends on DVB_CORE && PCI && I2C && VIDEO_V4L1
-+	depends on DVB_CORE && PCI && I2C
- 	select FW_LOADER if !DVB_AV7110_FIRMWARE
-+	select TTPCI_EEPROM
- 	select VIDEO_SAA7146_VV
-+	depends on VIDEO_DEV	# dependencies of VIDEO_SAA7146_VV
- 	select DVB_VES1820 if !DVB_FE_CUSTOMISE
- 	select DVB_VES1X93 if !DVB_FE_CUSTOMISE
- 	select DVB_STV0299 if !DVB_FE_CUSTOMISE
-@@ -57,10 +63,19 @@ config DVB_AV7110_OSD
+-		if (audio >= bttv_tvcards[btv->c.type].audio_inputs)
+-			return -EINVAL;
++static int bttv_s_input(struct file *file, void *priv, unsigned int i)
++{
++	struct bttv_fh *fh  = priv;
++	struct bttv *btv = fh->btv;
  
- 	  All other people say N.
+-		mutex_lock(&btv->lock);
+-		audio_mute(btv, (v->flags&VIDEO_AUDIO_MUTE) ? 1 : 0);
+-		bttv_call_i2c_clients(btv,cmd,v);
++	int err;
  
-+config DVB_BUDGET_CORE
-+	tristate "SAA7146 DVB cards (aka Budget, Nova-PCI)"
-+	depends on DVB_CORE && PCI && I2C
-+	select VIDEO_SAA7146
-+	select TTPCI_EEPROM
-+	help
-+	  Support for simple SAA7146 based DVB cards
-+	  (so called Budget- or Nova-PCI cards) without onboard
-+	  MPEG2 decoder.
-+
- config DVB_BUDGET
- 	tristate "Budget cards"
--	depends on DVB_CORE && PCI && I2C && VIDEO_V4L1
--	select VIDEO_SAA7146
-+	depends on DVB_BUDGET_CORE && I2C
- 	select DVB_STV0299 if !DVB_FE_CUSTOMISE
- 	select DVB_VES1X93 if !DVB_FE_CUSTOMISE
- 	select DVB_VES1820 if !DVB_FE_CUSTOMISE
-@@ -73,9 +88,9 @@ config DVB_BUDGET
- 	select DVB_TDA826X if !DVB_FE_CUSTOMISE
- 	select DVB_LNBP21 if !DVB_FE_CUSTOMISE
- 	help
--	  Support for simple SAA7146 based DVB cards
--	  (so called Budget- or Nova-PCI cards) without onboard
--	  MPEG2 decoder.
-+	  Support for simple SAA7146 based DVB cards (so called Budget-
-+	  or Nova-PCI cards) without onboard MPEG2 decoder, and without
-+	  analog inputs or an onboard Common Interface connector.
+-		/* card specific hooks */
+-		if (btv->audio_hook)
+-			btv->audio_hook(btv,v,1);
++	err = v4l2_prio_check(&btv->prio, &fh->prio);
++	if (0 != err)
++		return err;
  
- 	  Say Y if you own such a card and want to use it.
+-		mutex_unlock(&btv->lock);
+-		return 0;
+-	}
++	if (i > bttv_tvcards[btv->c.type].video_inputs)
++		return -EINVAL;
  
-@@ -84,8 +99,7 @@ config DVB_BUDGET
+-	/* ***  v4l2  *** ************************************************ */
+-	case VIDIOC_ENUMSTD:
+-	{
+-		struct v4l2_standard *e = arg;
+-		unsigned int index = e->index;
++	mutex_lock(&btv->lock);
++	set_input(btv, i, btv->tvnorm);
++	mutex_unlock(&btv->lock);
++	return 0;
++}
  
- config DVB_BUDGET_CI
- 	tristate "Budget cards with onboard CI connector"
--	depends on DVB_CORE && PCI && I2C && VIDEO_V4L1 && INPUT
--	select VIDEO_SAA7146
-+	depends on DVB_BUDGET_CORE && I2C
- 	select DVB_STV0297 if !DVB_FE_CUSTOMISE
- 	select DVB_STV0299 if !DVB_FE_CUSTOMISE
- 	select DVB_TDA1004X if !DVB_FE_CUSTOMISE
-@@ -106,8 +120,9 @@ config DVB_BUDGET_CI
+-		if (index >= BTTV_TVNORMS)
+-			return -EINVAL;
+-		v4l2_video_std_construct(e, bttv_tvnorms[e->index].v4l2_id,
+-					 bttv_tvnorms[e->index].name);
+-		e->index = index;
+-		return 0;
+-	}
+-	case VIDIOC_G_STD:
+-	{
+-		v4l2_std_id *id = arg;
+-		*id = bttv_tvnorms[btv->tvnorm].v4l2_id;
+-		return 0;
+-	}
+-	case VIDIOC_S_STD:
+-	{
+-		v4l2_std_id *id = arg;
+-		unsigned int i;
++static int bttv_s_tuner(struct file *file, void *priv,
++					struct v4l2_tuner *t)
++{
++	struct bttv_fh *fh  = priv;
++	struct bttv *btv = fh->btv;
++	int err;
  
- config DVB_BUDGET_AV
- 	tristate "Budget cards with analog video inputs"
--	depends on DVB_CORE && PCI && I2C && VIDEO_V4L1
-+	depends on DVB_BUDGET_CORE && I2C
- 	select VIDEO_SAA7146_VV
-+	depends on VIDEO_DEV	# dependencies of VIDEO_SAA7146_VV
- 	select DVB_PLL if !DVB_FE_CUSTOMISE
- 	select DVB_STV0299 if !DVB_FE_CUSTOMISE
- 	select DVB_TDA1004X if !DVB_FE_CUSTOMISE
-@@ -127,8 +142,8 @@ config DVB_BUDGET_AV
+-		for (i = 0; i < BTTV_TVNORMS; i++)
+-			if (*id & bttv_tvnorms[i].v4l2_id)
+-				break;
+-		if (i == BTTV_TVNORMS)
+-			return -EINVAL;
++	err = v4l2_prio_check(&btv->prio, &fh->prio);
++	if (0 != err)
++		return err;
  
- config DVB_BUDGET_PATCH
- 	tristate "AV7110 cards with Budget Patch"
--	depends on DVB_CORE && DVB_BUDGET && VIDEO_V4L1
--	select DVB_AV7110
-+	depends on DVB_BUDGET_CORE && I2C
-+	depends on DVB_AV7110
- 	select DVB_STV0299 if !DVB_FE_CUSTOMISE
- 	select DVB_VES1X93 if !DVB_FE_CUSTOMISE
- 	select DVB_TDA8083 if !DVB_FE_CUSTOMISE
-diff --git a/drivers/media/dvb/ttpci/Makefile b/drivers/media/dvb/ttpci/Makefile
-index 2c11452..d7483f1 100644
---- a/drivers/media/dvb/ttpci/Makefile
-+++ b/drivers/media/dvb/ttpci/Makefile
-@@ -5,11 +5,13 @@
+-		mutex_lock(&btv->lock);
+-		set_tvnorm(btv,i);
+-		i2c_vidiocschan(btv);
+-		mutex_unlock(&btv->lock);
+-		return 0;
+-	}
+-	case VIDIOC_QUERYSTD:
+-	{
+-		v4l2_std_id *id = arg;
++	if (UNSET == bttv_tvcards[btv->c.type].tuner)
++		return -EINVAL;
  
- dvb-ttpci-objs := av7110_hw.o av7110_v4l.o av7110_av.o av7110_ca.o av7110.o av7110_ipack.o av7110_ir.o
+-		if (btread(BT848_DSTATUS) & BT848_DSTATUS_NUML)
+-			*id = V4L2_STD_625_50;
+-		else
+-			*id = V4L2_STD_525_60;
+-		return 0;
+-	}
++	if (0 != t->index)
++		return -EINVAL;
  
--obj-$(CONFIG_DVB_BUDGET) += budget-core.o budget.o ttpci-eeprom.o
--obj-$(CONFIG_DVB_BUDGET_AV) += budget-core.o budget-av.o ttpci-eeprom.o
--obj-$(CONFIG_DVB_BUDGET_CI) += budget-core.o budget-ci.o ttpci-eeprom.o
--obj-$(CONFIG_DVB_BUDGET_PATCH) += budget-core.o budget-patch.o ttpci-eeprom.o
--obj-$(CONFIG_DVB_AV7110) += dvb-ttpci.o ttpci-eeprom.o
-+obj-$(CONFIG_TTPCI_EEPROM) += ttpci-eeprom.o
-+obj-$(CONFIG_DVB_BUDGET_CORE) += budget-core.o
-+obj-$(CONFIG_DVB_BUDGET) += budget.o
-+obj-$(CONFIG_DVB_BUDGET_AV) += budget-av.o
-+obj-$(CONFIG_DVB_BUDGET_CI) += budget-ci.o
-+obj-$(CONFIG_DVB_BUDGET_PATCH) += budget-patch.o
-+obj-$(CONFIG_DVB_AV7110) += dvb-ttpci.o
+-	case VIDIOC_ENUMINPUT:
+-	{
+-		struct v4l2_input *i = arg;
+-		unsigned int n;
++	mutex_lock(&btv->lock);
++	bttv_call_i2c_clients(btv, VIDIOC_S_TUNER, t);
  
- EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
+-		n = i->index;
+-		if (n >= bttv_tvcards[btv->c.type].video_inputs)
+-			return -EINVAL;
+-		memset(i,0,sizeof(*i));
+-		i->index    = n;
+-		i->type     = V4L2_INPUT_TYPE_CAMERA;
+-		i->audioset = 1;
+-		if (i->index == bttv_tvcards[btv->c.type].tuner) {
+-			sprintf(i->name, "Television");
+-			i->type  = V4L2_INPUT_TYPE_TUNER;
+-			i->tuner = 0;
+-		} else if (i->index == btv->svhs) {
+-			sprintf(i->name, "S-Video");
+-		} else {
+-			sprintf(i->name,"Composite%d",i->index);
+-		}
+-		if (i->index == btv->input) {
+-			__u32 dstatus = btread(BT848_DSTATUS);
+-			if (0 == (dstatus & BT848_DSTATUS_PRES))
+-				i->status |= V4L2_IN_ST_NO_SIGNAL;
+-			if (0 == (dstatus & BT848_DSTATUS_HLOC))
+-				i->status |= V4L2_IN_ST_NO_H_LOCK;
+-		}
+-		for (n = 0; n < BTTV_TVNORMS; n++)
+-			i->std |= bttv_tvnorms[n].v4l2_id;
+-		return 0;
+-	}
+-	case VIDIOC_G_INPUT:
+-	{
+-		int *i = arg;
+-		*i = btv->input;
+-		return 0;
+-	}
+-	case VIDIOC_S_INPUT:
+-	{
+-		unsigned int *i = arg;
++	if (btv->audio_mode_gpio)
++		btv->audio_mode_gpio(btv, t, 1);
  
-diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c
-index 0d36c15..0e5701b 100644
---- a/drivers/media/dvb/ttpci/av7110.c
-+++ b/drivers/media/dvb/ttpci/av7110.c
-@@ -2595,7 +2595,8 @@ static int __devinit av7110_attach(struct saa7146_dev* dev,
- 	mutex_init(&av7110->osd_mutex);
+-		if (*i > bttv_tvcards[btv->c.type].video_inputs)
+-			return -EINVAL;
+-		mutex_lock(&btv->lock);
+-		set_input(btv, *i, btv->tvnorm);
+-		mutex_unlock(&btv->lock);
+-		return 0;
+-	}
++	mutex_unlock(&btv->lock);
  
- 	/* TV standard */
--	av7110->vidmode = tv_standard == 1 ? VIDEO_MODE_NTSC : VIDEO_MODE_PAL;
-+	av7110->vidmode = tv_standard == 1 ? AV7110_VIDEO_MODE_NTSC
-+					   : AV7110_VIDEO_MODE_PAL;
+-	case VIDIOC_G_TUNER:
+-	{
+-		struct v4l2_tuner *t = arg;
++	return 0;
++}
  
- 	/* ARM "watchdog" */
- 	init_waitqueue_head(&av7110->arm_wait);
-diff --git a/drivers/media/dvb/ttpci/av7110.h b/drivers/media/dvb/ttpci/av7110.h
-index 0cb4395..39fbf7d 100644
---- a/drivers/media/dvb/ttpci/av7110.h
-+++ b/drivers/media/dvb/ttpci/av7110.h
-@@ -46,6 +46,11 @@ extern int av7110_debug;
+-		if (UNSET == bttv_tvcards[btv->c.type].tuner)
+-			return -EINVAL;
+-		if (0 != t->index)
+-			return -EINVAL;
+-		mutex_lock(&btv->lock);
+-		memset(t,0,sizeof(*t));
+-		t->rxsubchans = V4L2_TUNER_SUB_MONO;
+-		bttv_call_i2c_clients(btv, VIDIOC_G_TUNER, t);
+-		strcpy(t->name, "Television");
+-		t->capability = V4L2_TUNER_CAP_NORM;
+-		t->type       = V4L2_TUNER_ANALOG_TV;
+-		if (btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC)
+-			t->signal = 0xffff;
+-
+-		if (btv->audio_hook) {
+-			/* Hmmm ... */
+-			struct video_audio va;
+-			memset(&va, 0, sizeof(struct video_audio));
+-			btv->audio_hook(btv,&va,0);
+-			t->audmode    = V4L2_TUNER_MODE_MONO;
+-			t->rxsubchans = V4L2_TUNER_SUB_MONO;
+-			if(va.mode & VIDEO_SOUND_STEREO) {
+-				t->audmode    = V4L2_TUNER_MODE_STEREO;
+-				t->rxsubchans = V4L2_TUNER_SUB_STEREO;
+-			}
+-			if(va.mode & VIDEO_SOUND_LANG2) {
+-				t->audmode    = V4L2_TUNER_MODE_LANG1;
+-				t->rxsubchans = V4L2_TUNER_SUB_LANG1
+-					| V4L2_TUNER_SUB_LANG2;
+-			}
+-		}
+-		/* FIXME: fill capability+audmode */
+-		mutex_unlock(&btv->lock);
+-		return 0;
+-	}
+-	case VIDIOC_S_TUNER:
+-	{
+-		struct v4l2_tuner *t = arg;
++static int bttv_g_frequency(struct file *file, void *priv,
++					struct v4l2_frequency *f)
++{
++	struct bttv_fh *fh  = priv;
++	struct bttv *btv = fh->btv;
++	int err;
  
- enum {AV_PES_STREAM, PS_STREAM, TS_STREAM, PES_STREAM};
+-		if (UNSET == bttv_tvcards[btv->c.type].tuner)
+-			return -EINVAL;
+-		if (0 != t->index)
+-			return -EINVAL;
+-		mutex_lock(&btv->lock);
+-		bttv_call_i2c_clients(btv, VIDIOC_S_TUNER, t);
+-		if (btv->audio_hook) {
+-			struct video_audio va;
+-			memset(&va, 0, sizeof(struct video_audio));
+-			if (t->audmode == V4L2_TUNER_MODE_MONO)
+-				va.mode = VIDEO_SOUND_MONO;
+-			else if (t->audmode == V4L2_TUNER_MODE_STEREO ||
+-				 t->audmode == V4L2_TUNER_MODE_LANG1_LANG2)
+-				va.mode = VIDEO_SOUND_STEREO;
+-			else if (t->audmode == V4L2_TUNER_MODE_LANG1)
+-				va.mode = VIDEO_SOUND_LANG1;
+-			else if (t->audmode == V4L2_TUNER_MODE_LANG2)
+-				va.mode = VIDEO_SOUND_LANG2;
+-			btv->audio_hook(btv,&va,1);
+-		}
+-		mutex_unlock(&btv->lock);
+-		return 0;
+-	}
++	err = v4l2_prio_check(&btv->prio, &fh->prio);
++	if (0 != err)
++		return err;
  
-+enum av7110_video_mode {
-+	AV7110_VIDEO_MODE_PAL 	= 0,
-+	AV7110_VIDEO_MODE_NTSC	= 1
-+};
-+
- struct av7110_p2t {
- 	u8		  pes[TS_SIZE];
- 	u8		  counter;
-@@ -170,7 +175,7 @@ struct av7110 {
+-	case VIDIOC_G_FREQUENCY:
+-	{
+-		struct v4l2_frequency *f = arg;
++	f->type = V4L2_TUNER_ANALOG_TV;
++	f->frequency = btv->freq;
  
- 	ca_slot_info_t		ci_slot[2];
+-		memset(f,0,sizeof(*f));
+-		f->type = V4L2_TUNER_ANALOG_TV;
+-		f->frequency = btv->freq;
+-		return 0;
+-	}
+-	case VIDIOC_S_FREQUENCY:
+-	{
+-		struct v4l2_frequency *f = arg;
++	return 0;
++}
++
++static int bttv_s_frequency(struct file *file, void *priv,
++					struct v4l2_frequency *f)
++{
++	struct bttv_fh *fh  = priv;
++	struct bttv *btv = fh->btv;
++	int err;
++
++	err = v4l2_prio_check(&btv->prio, &fh->prio);
++	if (0 != err)
++		return err;
++
++	if (unlikely(f->tuner != 0))
++		return -EINVAL;
++	if (unlikely(f->type != V4L2_TUNER_ANALOG_TV))
++		return -EINVAL;
++	mutex_lock(&btv->lock);
++	btv->freq = f->frequency;
++	bttv_call_i2c_clients(btv, VIDIOC_S_FREQUENCY, f);
++	if (btv->has_matchbox && btv->radio_user)
++		tea5757_set_freq(btv, btv->freq);
++	mutex_unlock(&btv->lock);
++	return 0;
++}
++
++static int bttv_log_status(struct file *file, void *f)
++{
++	struct bttv_fh *fh  = f;
++	struct bttv *btv = fh->btv;
++
++	printk(KERN_INFO "bttv%d: ========  START STATUS CARD #%d  ========\n",
++			btv->c.nr, btv->c.nr);
++	bttv_call_i2c_clients(btv, VIDIOC_LOG_STATUS, NULL);
++	printk(KERN_INFO "bttv%d: ========  END STATUS CARD   #%d  ========\n",
++			btv->c.nr, btv->c.nr);
++	return 0;
++}
  
--	int			vidmode;
-+	enum av7110_video_mode	vidmode;
- 	struct dmxdev		dmxdev;
- 	struct dvb_demux	demux;
+-		if (unlikely(f->tuner != 0))
+-			return -EINVAL;
+-		if (unlikely (f->type != V4L2_TUNER_ANALOG_TV))
+-			return -EINVAL;
+-		mutex_lock(&btv->lock);
+-		btv->freq = f->frequency;
+-		bttv_call_i2c_clients(btv,VIDIOC_S_FREQUENCY,f);
+-		if (btv->has_matchbox && btv->radio_user)
+-			tea5757_set_freq(btv,btv->freq);
+-		mutex_unlock(&btv->lock);
+-		return 0;
+-	}
+-	case VIDIOC_LOG_STATUS:
+-	{
+-		printk(KERN_INFO "bttv%d: =================  START STATUS CARD #%d  =================\n", btv->c.nr, btv->c.nr);
+-		bttv_call_i2c_clients(btv, VIDIOC_LOG_STATUS, NULL);
+-		printk(KERN_INFO "bttv%d: ==================  END STATUS CARD #%d  ==================\n", btv->c.nr, btv->c.nr);
+-		return 0;
+-	}
+ #ifdef CONFIG_VIDEO_ADV_DEBUG
+-	case VIDIOC_DBG_G_REGISTER:
+-	case VIDIOC_DBG_S_REGISTER:
+-	{
+-		struct v4l2_register *reg = arg;
+-		if (!capable(CAP_SYS_ADMIN))
+-			return -EPERM;
+-		if (!v4l2_chip_match_host(reg->match_type, reg->match_chip))
+-			return -EINVAL;
+-		/* bt848 has a 12-bit register space */
+-		reg->reg &= 0xfff;
+-		if (cmd == VIDIOC_DBG_G_REGISTER)
+-			reg->val = btread(reg->reg);
+-		else
+-			btwrite(reg->val, reg->reg);
+-		return 0;
+-	}
+-#endif
++static int bttv_g_register(struct file *file, void *f,
++					struct v4l2_register *reg)
++{
++	struct bttv_fh *fh = f;
++	struct bttv *btv = fh->btv;
  
-diff --git a/drivers/media/dvb/ttpci/av7110_av.c b/drivers/media/dvb/ttpci/av7110_av.c
-index d75e7e4..aef6e36 100644
---- a/drivers/media/dvb/ttpci/av7110_av.c
-+++ b/drivers/media/dvb/ttpci/av7110_av.c
-@@ -329,7 +329,7 @@ int av7110_set_volume(struct av7110 *av7110, int volleft, int volright)
+-	default:
+-		return -ENOIOCTLCMD;
++	if (!capable(CAP_SYS_ADMIN))
++		return -EPERM;
++
++	if (!v4l2_chip_match_host(reg->match_type, reg->match_chip))
++		return -EINVAL;
++
++	/* bt848 has a 12-bit register space */
++	reg->reg &= 0xfff;
++	reg->val = btread(reg->reg);
++
++	return 0;
++}
++
++static int bttv_s_register(struct file *file, void *f,
++					struct v4l2_register *reg)
++{
++	struct bttv_fh *fh = f;
++	struct bttv *btv = fh->btv;
++
++	if (!capable(CAP_SYS_ADMIN))
++		return -EPERM;
++
++	if (!v4l2_chip_match_host(reg->match_type, reg->match_chip))
++		return -EINVAL;
++
++	/* bt848 has a 12-bit register space */
++	reg->reg &= 0xfff;
++	btwrite(reg->val, reg->reg);
+ 
+-	}
  	return 0;
  }
++#endif
  
--int av7110_set_vidmode(struct av7110 *av7110, int mode)
-+int av7110_set_vidmode(struct av7110 *av7110, enum av7110_video_mode mode)
+ /* Given cropping boundaries b and the scaled width and height of a
+    single field or frame, which must not exceed hardware limits, this
+@@ -2659,983 +2447,681 @@ pix_format_set_size     (struct v4l2_pix_format *       f,
+ 	}
+ }
+ 
+-static int bttv_g_fmt(struct bttv_fh *fh, struct v4l2_format *f)
++static int bttv_g_fmt_cap(struct file *file, void *priv,
++					struct v4l2_format *f)
  {
- 	int ret;
- 	dprintk(2, "av7110:%p, \n", av7110);
-@@ -348,11 +348,15 @@ int av7110_set_vidmode(struct av7110 *av7110, int mode)
+-	switch (f->type) {
+-	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+-		memset(&f->fmt.pix,0,sizeof(struct v4l2_pix_format));
+-		pix_format_set_size (&f->fmt.pix, fh->fmt,
+-				     fh->width, fh->height);
+-		f->fmt.pix.field        = fh->cap.field;
+-		f->fmt.pix.pixelformat  = fh->fmt->fourcc;
+-		return 0;
+-	case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+-		memset(&f->fmt.win,0,sizeof(struct v4l2_window));
+-		f->fmt.win.w     = fh->ov.w;
+-		f->fmt.win.field = fh->ov.field;
+-		return 0;
+-	case V4L2_BUF_TYPE_VBI_CAPTURE:
+-		bttv_vbi_get_fmt(fh, &f->fmt.vbi);
+-		return 0;
+-	default:
+-		return -EINVAL;
+-	}
++	struct bttv_fh *fh  = priv;
++
++	pix_format_set_size(&f->fmt.pix, fh->fmt,
++				fh->width, fh->height);
++	f->fmt.pix.field        = fh->cap.field;
++	f->fmt.pix.pixelformat  = fh->fmt->fourcc;
++
++	return 0;
  }
  
+-static int bttv_try_fmt(struct bttv_fh *fh, struct bttv *btv,
+-			struct v4l2_format *f, int adjust_crop)
++static int bttv_g_fmt_overlay(struct file *file, void *priv,
++					struct v4l2_format *f)
+ {
+-	switch (f->type) {
+-	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+-	{
+-		const struct bttv_format *fmt;
+-		enum v4l2_field field;
+-		__s32 width, height;
+-		int rc;
++	struct bttv_fh *fh  = priv;
  
--static int sw2mode[16] = {
--	VIDEO_MODE_PAL, VIDEO_MODE_NTSC, VIDEO_MODE_NTSC, VIDEO_MODE_PAL,
--	VIDEO_MODE_NTSC, VIDEO_MODE_NTSC, VIDEO_MODE_PAL, VIDEO_MODE_NTSC,
--	VIDEO_MODE_PAL, VIDEO_MODE_PAL, VIDEO_MODE_PAL, VIDEO_MODE_PAL,
--	VIDEO_MODE_PAL, VIDEO_MODE_PAL, VIDEO_MODE_PAL, VIDEO_MODE_PAL,
-+static enum av7110_video_mode sw2mode[16] = {
-+	AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_NTSC,
-+	AV7110_VIDEO_MODE_NTSC, AV7110_VIDEO_MODE_PAL,
-+	AV7110_VIDEO_MODE_NTSC, AV7110_VIDEO_MODE_NTSC,
-+	AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_NTSC,
-+	AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_PAL,
-+	AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_PAL,
-+	AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_PAL,
-+	AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_PAL,
- };
+-		fmt = format_by_fourcc(f->fmt.pix.pixelformat);
+-		if (NULL == fmt)
+-			return -EINVAL;
++	f->fmt.win.w     = fh->ov.w;
++	f->fmt.win.field = fh->ov.field;
  
- static int get_video_format(struct av7110 *av7110, u8 *buf, int count)
-diff --git a/drivers/media/dvb/ttpci/av7110_av.h b/drivers/media/dvb/ttpci/av7110_av.h
-index 45dc144..5f02ef8 100644
---- a/drivers/media/dvb/ttpci/av7110_av.h
-+++ b/drivers/media/dvb/ttpci/av7110_av.h
-@@ -3,7 +3,8 @@
+-		field = f->fmt.pix.field;
+-		if (V4L2_FIELD_ANY == field) {
+-			__s32 height2;
++	return 0;
++}
  
- struct av7110;
+-			height2 = btv->crop[!!fh->do_crop].rect.height >> 1;
+-			field = (f->fmt.pix.height > height2)
+-				? V4L2_FIELD_INTERLACED
+-				: V4L2_FIELD_BOTTOM;
+-		}
+-		if (V4L2_FIELD_SEQ_BT == field)
+-			field = V4L2_FIELD_SEQ_TB;
+-		switch (field) {
+-		case V4L2_FIELD_TOP:
+-		case V4L2_FIELD_BOTTOM:
+-		case V4L2_FIELD_ALTERNATE:
+-		case V4L2_FIELD_INTERLACED:
+-			break;
+-		case V4L2_FIELD_SEQ_TB:
+-			if (fmt->flags & FORMAT_FLAGS_PLANAR)
+-				return -EINVAL;
+-			break;
+-		default:
+-			return -EINVAL;
+-		}
++static int bttv_try_fmt_cap(struct file *file, void *priv,
++						struct v4l2_format *f)
++{
++	const struct bttv_format *fmt;
++	struct bttv_fh *fh = priv;
++	struct bttv *btv = fh->btv;
++	enum v4l2_field field;
++	__s32 width, height;
++	int rc;
  
--extern int av7110_set_vidmode(struct av7110 *av7110, int mode);
-+extern int av7110_set_vidmode(struct av7110 *av7110,
-+			      enum av7110_video_mode mode);
+-		width = f->fmt.pix.width;
+-		height = f->fmt.pix.height;
++	fmt = format_by_fourcc(f->fmt.pix.pixelformat);
++	if (NULL == fmt)
++		return -EINVAL;
  
- extern int av7110_record_cb(struct dvb_filter_pes2ts *p2t, u8 *buf, size_t len);
- extern int av7110_pes_play(void *dest, struct dvb_ringbuffer *buf, int dlen);
-diff --git a/drivers/media/dvb/ttpci/av7110_v4l.c b/drivers/media/dvb/ttpci/av7110_v4l.c
-index 76cca00..e2f066f 100644
---- a/drivers/media/dvb/ttpci/av7110_v4l.c
-+++ b/drivers/media/dvb/ttpci/av7110_v4l.c
-@@ -876,11 +876,11 @@ static int std_callback(struct saa7146_dev* dev, struct saa7146_standard *std)
- 	struct av7110 *av7110 = (struct av7110*) dev->ext_priv;
+-		rc = limit_scaled_size(fh, &width, &height, field,
+-				       /* width_mask: 4 pixels */ ~3,
+-				       /* width_bias: nearest */ 2,
+-				       /* adjust_size */ 1,
+-				       adjust_crop);
+-		if (0 != rc)
+-			return rc;
++	field = f->fmt.pix.field;
  
- 	if (std->id & V4L2_STD_PAL) {
--		av7110->vidmode = VIDEO_MODE_PAL;
-+		av7110->vidmode = AV7110_VIDEO_MODE_PAL;
- 		av7110_set_vidmode(av7110, av7110->vidmode);
+-		/* update data for the application */
+-		f->fmt.pix.field = field;
+-		pix_format_set_size(&f->fmt.pix, fmt, width, height);
++	if (V4L2_FIELD_ANY == field) {
++		__s32 height2;
+ 
+-		return 0;
++		height2 = btv->crop[!!fh->do_crop].rect.height >> 1;
++		field = (f->fmt.pix.height > height2)
++			? V4L2_FIELD_INTERLACED
++			: V4L2_FIELD_BOTTOM;
  	}
- 	else if (std->id & V4L2_STD_NTSC) {
--		av7110->vidmode = VIDEO_MODE_NTSC;
-+		av7110->vidmode = AV7110_VIDEO_MODE_NTSC;
- 		av7110_set_vidmode(av7110, av7110->vidmode);
+-	case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+-		return verify_window(fh, &f->fmt.win,
+-				     /* adjust_size */ 1,
+-				     /* adjust_crop */ 0);
+-	case V4L2_BUF_TYPE_VBI_CAPTURE:
+-		return bttv_vbi_try_fmt(fh, &f->fmt.vbi);
++
++	if (V4L2_FIELD_SEQ_BT == field)
++		field = V4L2_FIELD_SEQ_TB;
++
++	switch (field) {
++	case V4L2_FIELD_TOP:
++	case V4L2_FIELD_BOTTOM:
++	case V4L2_FIELD_ALTERNATE:
++	case V4L2_FIELD_INTERLACED:
++		break;
++	case V4L2_FIELD_SEQ_TB:
++		if (fmt->flags & FORMAT_FLAGS_PLANAR)
++			return -EINVAL;
++		break;
+ 	default:
+ 		return -EINVAL;
  	}
- 	else
-diff --git a/drivers/media/radio/Kconfig b/drivers/media/radio/Kconfig
-index 11e962f..8d5214f 100644
---- a/drivers/media/radio/Kconfig
-+++ b/drivers/media/radio/Kconfig
-@@ -351,4 +351,14 @@ config USB_DSBR
- 	  To compile this driver as a module, choose M here: the
- 	  module will be called dsbr100.
- 
-+config USB_SI470X
-+	tristate "Silicon Labs Si470x FM Radio Receiver 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.
 +
-+	  To compile this driver as a module, choose M here: the
-+	  module will be called radio-silabs.
++	width = f->fmt.pix.width;
++	height = f->fmt.pix.height;
 +
- endif # RADIO_ADAPTERS
-diff --git a/drivers/media/radio/Makefile b/drivers/media/radio/Makefile
-index cf55a18..a30159f 100644
---- a/drivers/media/radio/Makefile
-+++ b/drivers/media/radio/Makefile
-@@ -21,5 +21,6 @@ obj-$(CONFIG_RADIO_GEMTEK_PCI) += radio-gemtek-pci.o
- obj-$(CONFIG_RADIO_TRUST) += radio-trust.o
- obj-$(CONFIG_RADIO_MAESTRO) += radio-maestro.o
- obj-$(CONFIG_USB_DSBR) += dsbr100.o
-+obj-$(CONFIG_USB_SI470X) += radio-si470x.o
- 
- EXTRA_CFLAGS += -Isound
-diff --git a/drivers/media/radio/dsbr100.c b/drivers/media/radio/dsbr100.c
-index 3bd07f7..36c0e36 100644
---- a/drivers/media/radio/dsbr100.c
-+++ b/drivers/media/radio/dsbr100.c
-@@ -33,6 +33,9 @@
- 
-  History:
++	rc = limit_scaled_size(fh, &width, &height, field,
++			       /* width_mask: 4 pixels */ ~3,
++			       /* width_bias: nearest */ 2,
++			       /* adjust_size */ 1,
++			       /* adjust_crop */ 0);
++	if (0 != rc)
++		return rc;
++
++	/* update data for the application */
++	f->fmt.pix.field = field;
++	pix_format_set_size(&f->fmt.pix, fmt, width, height);
++
++	return 0;
+ }
  
-+ Version 0.43:
-+	Oliver Neukum: avoided DMA coherency issue
+-static int bttv_s_fmt(struct bttv_fh *fh, struct bttv *btv,
+-		      struct v4l2_format *f)
++static int bttv_try_fmt_overlay(struct file *file, void *priv,
++						struct v4l2_format *f)
++{
++	struct bttv_fh *fh = priv;
 +
-  Version 0.42:
- 	Converted dsbr100 to use video_ioctl2
- 	by Douglas Landgraf <dougsland at gmail.com>
-@@ -135,7 +138,7 @@ module_param(radio_nr, int, 0);
- struct dsbr100_device {
- 	struct usb_device *usbdev;
- 	struct video_device *videodev;
--	unsigned char transfer_buffer[TB_LEN];
-+	u8 *transfer_buffer;
- 	int curfreq;
- 	int stereo;
- 	int users;
-@@ -237,10 +240,7 @@ static void dsbr100_getstat(struct dsbr100_device *radio)
- /* 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.  stv680.c does not relase its private
--data, so I don't do this here either.  Checking out the
--code I'd expect I better did that, but if there's a memory
--leak here it's tiny (~50 bytes per disconnect) */
-+of releasing it. */
- static void usb_dsbr100_disconnect(struct usb_interface *intf)
++	return verify_window(fh, &f->fmt.win,
++			/* adjust_size */ 1,
++			/* adjust_crop */ 0);
++}
++
++static int bttv_s_fmt_cap(struct file *file, void *priv,
++				struct v4l2_format *f)
  {
- 	struct dsbr100_device *radio = usb_get_intfdata(intf);
-@@ -250,6 +250,7 @@ static void usb_dsbr100_disconnect(struct usb_interface *intf)
- 		video_unregister_device(radio->videodev);
- 		radio->videodev = NULL;
- 		if (radio->users) {
-+			kfree(radio->transfer_buffer);
- 			kfree(radio);
- 		} else {
- 			radio->removed = 1;
-@@ -425,6 +426,7 @@ static int usb_dsbr100_close(struct inode *inode, struct file *file)
- 		return -ENODEV;
- 	radio->users = 0;
- 	if (radio->removed) {
-+		kfree(radio->transfer_buffer);
- 		kfree(radio);
- 	}
- 	return 0;
-@@ -471,7 +473,12 @@ static int usb_dsbr100_probe(struct usb_interface *intf,
+ 	int retval;
++	const struct bttv_format *fmt;
++	struct bttv_fh *fh = priv;
++	struct bttv *btv = fh->btv;
++	__s32 width, height;
++	enum v4l2_field field;
  
- 	if (!(radio = kmalloc(sizeof(struct dsbr100_device), GFP_KERNEL)))
- 		return -ENOMEM;
-+	if (!(radio->transfer_buffer = kmalloc(TB_LEN, GFP_KERNEL))) {
-+		kfree(radio);
-+		return -ENOMEM;
-+	}
- 	if (!(radio->videodev = video_device_alloc())) {
-+		kfree(radio->transfer_buffer);
- 		kfree(radio);
- 		return -ENOMEM;
- 	}
-@@ -485,6 +492,7 @@ static int usb_dsbr100_probe(struct usb_interface *intf,
- 	if (video_register_device(radio->videodev, VFL_TYPE_RADIO,radio_nr)) {
- 		warn("Could not register video device");
- 		video_device_release(radio->videodev);
-+		kfree(radio->transfer_buffer);
- 		kfree(radio);
- 		return -EIO;
- 	}
-diff --git a/drivers/media/radio/radio-gemtek.c b/drivers/media/radio/radio-gemtek.c
-index 5e4b9dd..246422b 100644
---- a/drivers/media/radio/radio-gemtek.c
-+++ b/drivers/media/radio/radio-gemtek.c
-@@ -58,10 +58,10 @@ static int initmute	= 1;
- static int radio_nr	= -1;
+-	switch (f->type) {
+-	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+-	{
+-		const struct bttv_format *fmt;
++	retval = bttv_switch_type(fh, f->type);
++	if (0 != retval)
++		return retval;
  
- module_param(io, int, 0444);
--MODULE_PARM_DESC(io, "Force I/O port for the GemTek Radio card if automatic"
-+MODULE_PARM_DESC(io, "Force I/O port for the GemTek Radio card if automatic "
- 	 "probing is disabled or fails. The most common I/O ports are: 0x20c "
- 	 "0x30c, 0x24c or 0x34c (0x20c, 0x248 and 0x28c have been reported to "
--	 " work for the combined sound/radiocard).");
-+	 "work for the combined sound/radiocard).");
+-		retval = bttv_switch_type(fh,f->type);
+-		if (0 != retval)
+-			return retval;
+-		retval = bttv_try_fmt(fh,btv,f, /* adjust_crop */ 1);
+-		if (0 != retval)
+-			return retval;
+-		fmt = format_by_fourcc(f->fmt.pix.pixelformat);
++	retval = bttv_try_fmt_cap(file, priv, f);
++	if (0 != retval)
++		return retval;
  
- module_param(probe, bool, 0444);
- MODULE_PARM_DESC(probe, "Enable automatic device probing. Note: only the most "
-@@ -392,7 +392,7 @@ static struct v4l2_queryctrl radio_qctrl[] = {
- 	}
- };
+-		/* update our state informations */
+-		mutex_lock(&fh->cap.lock);
+-		fh->fmt              = fmt;
+-		fh->cap.field        = f->fmt.pix.field;
+-		fh->cap.last         = V4L2_FIELD_NONE;
+-		fh->width            = f->fmt.pix.width;
+-		fh->height           = f->fmt.pix.height;
+-		btv->init.fmt        = fmt;
+-		btv->init.width      = f->fmt.pix.width;
+-		btv->init.height     = f->fmt.pix.height;
+-		mutex_unlock(&fh->cap.lock);
++	width = f->fmt.pix.width;
++	height = f->fmt.pix.height;
++	field = f->fmt.pix.field;
  
--static struct file_operations gemtek_fops = {
-+static const struct file_operations gemtek_fops = {
- 	.owner		= THIS_MODULE,
- 	.open		= video_exclusive_open,
- 	.release	= video_exclusive_release,
-diff --git a/drivers/media/radio/radio-maestro.c b/drivers/media/radio/radio-maestro.c
-index 8e33a19..bc51f4d 100644
---- a/drivers/media/radio/radio-maestro.c
-+++ b/drivers/media/radio/radio-maestro.c
-@@ -423,7 +423,7 @@ static int __devinit maestro_probe(struct pci_dev *pdev,
- errunr:
- 	video_unregister_device(maestro_radio_inst);
- errfr1:
--	kfree(maestro_radio_inst);
-+	video_device_release(maestro_radio_inst);
- errfr:
- 	kfree(radio_unit);
- err:
-diff --git a/drivers/media/radio/radio-sf16fmi.c b/drivers/media/radio/radio-sf16fmi.c
-index 3951653..3118bda 100644
---- a/drivers/media/radio/radio-sf16fmi.c
-+++ b/drivers/media/radio/radio-sf16fmi.c
-@@ -321,7 +321,7 @@ static struct isapnp_device_id id_table[] __devinitdata = {
+-		return 0;
+-	}
+-	case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+-		if (no_overlay > 0) {
+-			printk ("V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
+-			return -EINVAL;
+-		}
+-		return setup_window(fh, btv, &f->fmt.win, 1);
+-	case V4L2_BUF_TYPE_VBI_CAPTURE:
+-		retval = bttv_switch_type(fh,f->type);
+-		if (0 != retval)
+-			return retval;
+-		return bttv_vbi_set_fmt(fh, &f->fmt.vbi);
+-	default:
+-		return -EINVAL;
+-	}
+-}
++	retval = limit_scaled_size(fh, &width, &height, f->fmt.pix.field,
++			       /* width_mask: 4 pixels */ ~3,
++			       /* width_bias: nearest */ 2,
++			       /* adjust_size */ 1,
++			       /* adjust_crop */ 1);
++	if (0 != retval)
++		return retval;
  
- MODULE_DEVICE_TABLE(isapnp, id_table);
+-static int bttv_do_ioctl(struct inode *inode, struct file *file,
+-			 unsigned int cmd, void *arg)
+-{
+-	struct bttv_fh *fh  = file->private_data;
+-	struct bttv    *btv = fh->btv;
+-	unsigned long flags;
+-	int retval = 0;
++	f->fmt.pix.field = field;
  
--static int isapnp_fmi_probe(void)
-+static int __init isapnp_fmi_probe(void)
- {
- 	int i = 0;
+-	if (bttv_debug > 1)
+-		v4l_print_ioctl(btv->c.name, cmd);
+-
+-	if (btv->errors)
+-		bttv_reinit_bt848(btv);
+-
+-	switch (cmd) {
+-	case VIDIOCSFREQ:
+-	case VIDIOCSTUNER:
+-	case VIDIOCSCHAN:
+-	case VIDIOC_S_CTRL:
+-	case VIDIOC_S_STD:
+-	case VIDIOC_S_INPUT:
+-	case VIDIOC_S_TUNER:
+-	case VIDIOC_S_FREQUENCY:
+-		retval = v4l2_prio_check(&btv->prio,&fh->prio);
+-		if (0 != retval)
+-			return retval;
+-	};
++	fmt = format_by_fourcc(f->fmt.pix.pixelformat);
  
-diff --git a/drivers/media/radio/radio-sf16fmr2.c b/drivers/media/radio/radio-sf16fmr2.c
-index c432c44..f7c8b00 100644
---- a/drivers/media/radio/radio-sf16fmr2.c
-+++ b/drivers/media/radio/radio-sf16fmr2.c
-@@ -476,8 +476,7 @@ static int __init fmr2_init(void)
- 		return -EBUSY;
- 	}
+-	switch (cmd) {
++	/* update our state informations */
++	mutex_lock(&fh->cap.lock);
++	fh->fmt              = fmt;
++	fh->cap.field        = f->fmt.pix.field;
++	fh->cap.last         = V4L2_FIELD_NONE;
++	fh->width            = f->fmt.pix.width;
++	fh->height           = f->fmt.pix.height;
++	btv->init.fmt        = fmt;
++	btv->init.width      = f->fmt.pix.width;
++	btv->init.height     = f->fmt.pix.height;
++	mutex_unlock(&fh->cap.lock);
  
--	if(video_register_device(&fmr2_radio, VFL_TYPE_RADIO, radio_nr)==-1)
+-	/* ***  v4l1  *** ************************************************ */
+-	case VIDIOCGCAP:
 -	{
-+	if (video_register_device(&fmr2_radio, VFL_TYPE_RADIO, radio_nr) < 0) {
- 		release_region(io, 2);
- 		return -EINVAL;
+-		struct video_capability *cap = arg;
++	return 0;
++}
+ 
+-		memset(cap,0,sizeof(*cap));
+-		strcpy(cap->name,btv->video_dev->name);
+-		if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) {
+-			/* vbi */
+-			cap->type = VID_TYPE_TUNER|VID_TYPE_TELETEXT;
+-		} else {
+-			/* others */
+-			cap->type = VID_TYPE_CAPTURE|
+-				VID_TYPE_TUNER|
+-				VID_TYPE_CLIPPING|
+-				VID_TYPE_SCALES;
+-			if (no_overlay <= 0)
+-				cap->type |= VID_TYPE_OVERLAY;
+-
+-			cap->maxwidth  = bttv_tvnorms[btv->tvnorm].swidth;
+-			cap->maxheight = bttv_tvnorms[btv->tvnorm].sheight;
+-			cap->minwidth  = 48;
+-			cap->minheight = 32;
+-		}
+-		cap->channels  = bttv_tvcards[btv->c.type].video_inputs;
+-		cap->audios    = bttv_tvcards[btv->c.type].audio_inputs;
+-		return 0;
+-	}
++static int bttv_s_fmt_overlay(struct file *file, void *priv,
++				struct v4l2_format *f)
++{
++	struct bttv_fh *fh = priv;
++	struct bttv *btv = fh->btv;
+ 
+-	case VIDIOCGPICT:
+-	{
+-		struct video_picture *pic = arg;
+-
+-		memset(pic,0,sizeof(*pic));
+-		pic->brightness = btv->bright;
+-		pic->contrast   = btv->contrast;
+-		pic->hue        = btv->hue;
+-		pic->colour     = btv->saturation;
+-		if (fh->fmt) {
+-			pic->depth   = fh->fmt->depth;
+-			pic->palette = fh->fmt->palette;
+-		}
+-		return 0;
++	if (no_overlay > 0) {
++		printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
++		return -EINVAL;
  	}
-diff --git a/drivers/media/radio/radio-si470x.c b/drivers/media/radio/radio-si470x.c
-new file mode 100644
-index 0000000..8e4bd47
---- /dev/null
-+++ b/drivers/media/radio/radio-si470x.c
-@@ -0,0 +1,1432 @@
-+/*
-+ *  drivers/media/radio/radio-si470x.c
-+ *
-+ *  Driver for USB radios for the Silicon Labs Si470x FM Radio Receivers:
-+ *   - Silicon Labs USB FM Radio Reference Design
-+ *   - ADS/Tech FM Radio Receiver (formerly Instant FM Music) (RDX-155-EF)
-+ *
-+ *  Copyright (c) 2008 Tobias Lorenz <tobias.lorenz at gmx.net>
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+ * GNU General Public License for more details.
-+ *
-+ * You 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:
-+ * 2008-01-12	Tobias Lorenz <tobias.lorenz at gmx.net>
-+ *		Version 1.0.0
-+ *		- First working version
-+ * 2008-01-13   Tobias Lorenz <tobias.lorenz at gmx.net>
-+ *		Version 1.0.1
-+ *		- Improved error handling, every function now returns errno
-+ *		- Improved multi user access (start/mute/stop)
-+ *		- Channel doesn't get lost anymore after start/mute/stop
-+ *		- RDS support added (polling mode via interrupt EP 1)
-+ *		- marked default module parameters with *value*
-+ *		- switched from bit structs to bit masks
-+ *		- header file cleaned and integrated
-+ * 2008-01-14	Tobias Lorenz <tobias.lorenz at gmx.net>
-+ * 		Version 1.0.2
-+ * 		- hex values are now lower case
-+ * 		- commented USB ID for ADS/Tech moved on todo list
-+ * 		- blacklisted si470x in hid-quirks.c
-+ * 		- rds buffer handling functions integrated into *_work, *_read
-+ * 		- rds_command in si470x_poll exchanged against simple retval
-+ * 		- check for firmware version 15
-+ * 		- code order and prototypes still remain the same
-+ * 		- spacing and bottom of band codes remain the same
-+ * 2008-01-16	Tobias Lorenz <tobias.lorenz at gmx.net>
-+ *		Version 1.0.3
-+ * 		- code reordered to avoid function prototypes
-+ *		- switch/case defaults are now more user-friendly
-+ *		- unified comment style
-+ *		- applied all checkpatch.pl v1.12 suggestions
-+ *		  except the warning about the too long lines with bit comments
-+ *		- renamed FMRADIO to RADIO to cut line length (checkpatch.pl)
-+ * 2008-01-22	Tobias Lorenz <tobias.lorenz at gmx.net>
-+ *		Version 1.0.4
-+ *		- avoid poss. locking when doing copy_to_user which may sleep
-+ *		- RDS is automatically activated on read now
-+ *		- code cleaned of unnecessary rds_commands
-+ *		- USB Vendor/Product ID for ADS/Tech FM Radio Receiver verified
-+ *		  (thanks to Guillaume RAMOUSSE)
-+ *
-+ * ToDo:
-+ * - add seeking support
-+ * - add firmware download/update support
-+ * - RDS support: interrupt mode, instead of polling
-+ * - add LED status output (check if that's not already done in firmware)
-+ */
-+
-+
-+/* driver definitions */
-+#define DRIVER_AUTHOR "Tobias Lorenz <tobias.lorenz at gmx.net>"
-+#define DRIVER_NAME "radio-si470x"
-+#define DRIVER_VERSION KERNEL_VERSION(1, 0, 4)
-+#define DRIVER_CARD "Silicon Labs Si470x FM Radio Receiver"
-+#define DRIVER_DESC "USB radio driver for Si470x FM Radio Receivers"
-+
-+
-+/* kernel includes */
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/init.h>
-+#include <linux/slab.h>
-+#include <linux/input.h>
-+#include <linux/usb.h>
-+#include <linux/hid.h>
-+#include <linux/version.h>
-+#include <linux/videodev2.h>
-+#include <media/v4l2-common.h>
-+#include <media/rds.h>
-+
-+
-+/* USB Device ID List */
-+static struct usb_device_id si470x_usb_driver_id_table[] = {
-+	/* Silicon Labs USB FM Radio Reference Design */
-+	{ USB_DEVICE_AND_INTERFACE_INFO(0x10c4, 0x818a,	USB_CLASS_HID, 0, 0) },
-+	/* ADS/Tech FM Radio Receiver (formerly Instant FM Music) */
-+	{ USB_DEVICE_AND_INTERFACE_INFO(0x06e1, 0xa155,	USB_CLASS_HID, 0, 0) },
-+	/* Terminating entry */
-+	{ }
-+};
-+MODULE_DEVICE_TABLE(usb, si470x_usb_driver_id_table);
-+
-+
-+
-+/**************************************************************************
-+ * Module Parameters
-+ **************************************************************************/
-+
-+/* Radio Nr */
-+static int radio_nr = -1;
-+module_param(radio_nr, int, 0);
-+MODULE_PARM_DESC(radio_nr, "Radio Nr");
-+
-+/* Spacing (kHz) */
-+/* 0: 200 kHz (USA, Australia) */
-+/* 1: 100 kHz (Europe, Japan) */
-+/* 2:  50 kHz */
-+static int space = 2;
-+module_param(space, int, 0);
-+MODULE_PARM_DESC(radio_nr, "Spacing: 0=200kHz 1=100kHz *2=50kHz*");
-+
-+/* Bottom of Band (MHz) */
-+/* 0: 87.5 - 108 MHz (USA, Europe)*/
-+/* 1: 76   - 108 MHz (Japan wide band) */
-+/* 2: 76   -  90 MHz (Japan) */
-+static int band = 1;
-+module_param(band, int, 0);
-+MODULE_PARM_DESC(radio_nr, "Band: 0=87.5..108MHz *1=76..108MHz* 2=76..90MHz");
-+
-+/* De-emphasis */
-+/* 0: 75 us (USA) */
-+/* 1: 50 us (Europe, Australia, Japan) */
-+static int de = 1;
-+module_param(de, int, 0);
-+MODULE_PARM_DESC(radio_nr, "De-emphasis: 0=75us *1=50us*");
-+
-+/* USB timeout */
-+static int usb_timeout = 500;
-+module_param(usb_timeout, int, 0);
-+MODULE_PARM_DESC(usb_timeout, "USB timeout (ms): *500*");
-+
-+/* Seek retries */
-+static int seek_retries = 100;
-+module_param(seek_retries, int, 0);
-+MODULE_PARM_DESC(seek_retries, "Seek retries: *100*");
-+
-+/* RDS buffer blocks */
-+static int rds_buf = 100;
-+module_param(rds_buf, int, 0);
-+MODULE_PARM_DESC(rds_buf, "RDS buffer entries: *100*");
-+
-+/* RDS maximum block errors */
-+static int max_rds_errors = 1;
-+/* 0 means   0  errors requiring correction */
-+/* 1 means 1-2  errors requiring correction (used by original USBRadio.exe) */
-+/* 2 means 3-5  errors requiring correction */
-+/* 3 means   6+ errors or errors in checkword, correction not possible */
-+module_param(max_rds_errors, int, 0);
-+MODULE_PARM_DESC(max_rds_errors, "RDS maximum block errors: *1*");
-+
-+/* RDS poll frequency */
-+static int rds_poll_time = 40;
-+/* 40 is used by the original USBRadio.exe */
-+/* 50 is used by radio-cadet */
-+/* 75 should be okay */
-+/* 80 is the usual RDS receive interval */
-+module_param(rds_poll_time, int, 0);
-+MODULE_PARM_DESC(rds_poll_time, "RDS poll time (ms): *40*");
-+
-+
-+
-+/**************************************************************************
-+ * Register Definitions
-+ **************************************************************************/
-+#define RADIO_REGISTER_SIZE	2	/* 16 register bit width */
-+#define RADIO_REGISTER_NUM	16	/* DEVICEID   ... RDSD */
-+#define RDS_REGISTER_NUM	6	/* STATUSRSSI ... RDSD */
-+
-+#define DEVICEID		0	/* Device ID */
-+#define DEVICEID_PN		0xf000	/* bits 15..12: Part Number */
-+#define DEVICEID_MFGID		0x0fff	/* bits 11..00: Manufacturer ID */
-+
-+#define CHIPID			1	/* Chip ID */
-+#define CHIPID_REV		0xfc00	/* bits 15..10: Chip Version */
-+#define CHIPID_DEV		0x0200	/* bits 09..09: Device */
-+#define CHIPID_FIRMWARE		0x01ff	/* bits 08..00: Firmware Version */
-+
-+#define POWERCFG		2	/* Power Configuration */
-+#define POWERCFG_DSMUTE		0x8000	/* bits 15..15: Softmute Disable */
-+#define POWERCFG_DMUTE		0x4000	/* bits 14..14: Mute Disable */
-+#define POWERCFG_MONO		0x2000	/* bits 13..13: Mono Select */
-+#define POWERCFG_RDSM		0x0800	/* bits 11..11: RDS Mode (Si4701 only) */
-+#define POWERCFG_SKMODE		0x0400	/* bits 10..10: Seek Mode */
-+#define POWERCFG_SEEKUP		0x0200	/* bits 09..09: Seek Direction */
-+#define POWERCFG_SEEK		0x0100	/* bits 08..08: Seek */
-+#define POWERCFG_DISABLE	0x0040	/* bits 06..06: Powerup Disable */
-+#define POWERCFG_ENABLE		0x0001	/* bits 00..00: Powerup Enable */
-+
-+#define CHANNEL			3	/* Channel */
-+#define CHANNEL_TUNE		0x8000	/* bits 15..15: Tune */
-+#define CHANNEL_CHAN		0x03ff	/* bits 09..00: Channel Select */
-+
-+#define SYSCONFIG1		4	/* System Configuration 1 */
-+#define SYSCONFIG1_RDSIEN	0x8000	/* bits 15..15: RDS Interrupt Enable (Si4701 only) */
-+#define SYSCONFIG1_STCIEN	0x4000	/* bits 14..14: Seek/Tune Complete Interrupt Enable */
-+#define SYSCONFIG1_RDS		0x1000	/* bits 12..12: RDS Enable (Si4701 only) */
-+#define SYSCONFIG1_DE		0x0800	/* bits 11..11: De-emphasis (0=75us 1=50us) */
-+#define SYSCONFIG1_AGCD		0x0400	/* bits 10..10: AGC Disable */
-+#define SYSCONFIG1_BLNDADJ	0x00c0	/* bits 07..06: Stereo/Mono Blend Level Adjustment */
-+#define SYSCONFIG1_GPIO3	0x0030	/* bits 05..04: General Purpose I/O 3 */
-+#define SYSCONFIG1_GPIO2	0x000c	/* bits 03..02: General Purpose I/O 2 */
-+#define SYSCONFIG1_GPIO1	0x0003	/* bits 01..00: General Purpose I/O 1 */
-+
-+#define SYSCONFIG2		5	/* System Configuration 2 */
-+#define SYSCONFIG2_SEEKTH	0xff00	/* bits 15..08: RSSI Seek Threshold */
-+#define SYSCONFIG2_BAND		0x0080	/* bits 07..06: Band Select */
-+#define SYSCONFIG2_SPACE	0x0030	/* bits 05..04: Channel Spacing */
-+#define SYSCONFIG2_VOLUME	0x000f	/* bits 03..00: Volume */
-+
-+#define SYSCONFIG3		6	/* System Configuration 3 */
-+#define SYSCONFIG3_SMUTER	0xc000	/* bits 15..14: Softmute Attack/Recover Rate */
-+#define SYSCONFIG3_SMUTEA	0x3000	/* bits 13..12: Softmute Attenuation */
-+#define SYSCONFIG3_SKSNR	0x00f0	/* bits 07..04: Seek SNR Threshold */
-+#define SYSCONFIG3_SKCNT	0x000f	/* bits 03..00: Seek FM Impulse Detection Threshold */
-+
-+#define TEST1			7	/* Test 1 */
-+#define TEST1_AHIZEN		0x4000	/* bits 14..14: Audio High-Z Enable */
-+
-+#define TEST2			8	/* Test 2 */
-+/* TEST2 only contains reserved bits */
-+
-+#define BOOTCONFIG		9	/* Boot Configuration */
-+/* BOOTCONFIG only contains reserved bits */
-+
-+#define STATUSRSSI		10	/* Status RSSI */
-+#define STATUSRSSI_RDSR		0x8000	/* bits 15..15: RDS Ready (Si4701 only) */
-+#define STATUSRSSI_STC		0x4000	/* bits 14..14: Seek/Tune Complete */
-+#define STATUSRSSI_SF		0x2000	/* bits 13..13: Seek Fail/Band Limit */
-+#define STATUSRSSI_AFCRL	0x1000	/* bits 12..12: AFC Rail */
-+#define STATUSRSSI_RDSS		0x0800	/* bits 11..11: RDS Synchronized (Si4701 only) */
-+#define STATUSRSSI_BLERA	0x0600	/* bits 10..09: RDS Block A Errors (Si4701 only) */
-+#define STATUSRSSI_ST		0x0100	/* bits 08..08: Stereo Indicator */
-+#define STATUSRSSI_RSSI		0x00ff	/* bits 07..00: RSSI (Received Signal Strength Indicator) */
-+
-+#define READCHAN		11	/* Read Channel */
-+#define READCHAN_BLERB		0xc000	/* bits 15..14: RDS Block D Errors (Si4701 only) */
-+#define READCHAN_BLERC		0x3000	/* bits 13..12: RDS Block C Errors (Si4701 only) */
-+#define READCHAN_BLERD		0x0c00	/* bits 11..10: RDS Block B Errors (Si4701 only) */
-+#define READCHAN_READCHAN	0x03ff	/* bits 09..00: Read Channel */
-+
-+#define RDSA			12	/* RDSA */
-+#define RDSA_RDSA		0xffff	/* bits 15..00: RDS Block A Data (Si4701 only) */
-+
-+#define RDSB			13	/* RDSB */
-+#define RDSB_RDSB		0xffff	/* bits 15..00: RDS Block B Data (Si4701 only) */
-+
-+#define RDSC			14	/* RDSC */
-+#define RDSC_RDSC		0xffff	/* bits 15..00: RDS Block C Data (Si4701 only) */
-+
-+#define RDSD			15	/* RDSD */
-+#define RDSD_RDSD		0xffff	/* bits 15..00: RDS Block D Data (Si4701 only) */
-+
-+
-+
-+/**************************************************************************
-+ * USB HID Reports
-+ **************************************************************************/
-+
-+/* Reports 1-16 give direct read/write access to the 16 Si470x registers */
-+/* with the (REPORT_ID - 1) corresponding to the register address across USB */
-+/* endpoint 0 using GET_REPORT and SET_REPORT */
-+#define REGISTER_REPORT_SIZE	(RADIO_REGISTER_SIZE + 1)
-+#define REGISTER_REPORT(reg)	((reg) + 1)
-+
-+/* Report 17 gives direct read/write access to the entire Si470x register */
-+/* map across endpoint 0 using GET_REPORT and SET_REPORT */
-+#define ENTIRE_REPORT_SIZE	(RADIO_REGISTER_NUM * RADIO_REGISTER_SIZE + 1)
-+#define ENTIRE_REPORT		17
-+
-+/* Report 18 is used to send the lowest 6 Si470x registers up the HID */
-+/* interrupt endpoint 1 to Windows every 20 milliseconds for status */
-+#define RDS_REPORT_SIZE		(RDS_REGISTER_NUM * RADIO_REGISTER_SIZE + 1)
-+#define RDS_REPORT		18
-+
-+/* Report 19: LED state */
-+#define LED_REPORT_SIZE		3
-+#define LED_REPORT		19
-+
-+/* Report 19: stream */
-+#define STREAM_REPORT_SIZE	3
-+#define	STREAM_REPORT		19
-+
-+/* Report 20: scratch */
-+#define SCRATCH_PAGE_SIZE	63
-+#define SCRATCH_REPORT_SIZE	(SCRATCH_PAGE_SIZE + 1)
-+#define SCRATCH_REPORT		20
-+
-+/* Reports 19-22: flash upgrade of the C8051F321 */
-+#define WRITE_REPORT		19
-+#define FLASH_REPORT		20
-+#define CRC_REPORT		21
-+#define RESPONSE_REPORT		22
-+
-+/* Report 23: currently unused, but can accept 60 byte reports on the HID */
-+/* interrupt out endpoint 2 every 1 millisecond */
-+#define UNUSED_REPORT		23
-+
-+
-+
-+/**************************************************************************
-+ * Software/Hardware Versions
-+ **************************************************************************/
-+#define RADIO_SW_VERSION_NOT_BOOTLOADABLE	6
-+#define RADIO_SW_VERSION			7
-+#define RADIO_SW_VERSION_CURRENT		15
-+#define RADIO_HW_VERSION			1
-+
-+#define SCRATCH_PAGE_SW_VERSION	1
-+#define SCRATCH_PAGE_HW_VERSION	2
-+
-+
-+
-+/**************************************************************************
-+ * LED State Definitions
-+ **************************************************************************/
-+#define LED_COMMAND		0x35
-+
-+#define NO_CHANGE_LED		0x00
-+#define ALL_COLOR_LED		0x01	/* streaming state */
-+#define BLINK_GREEN_LED		0x02	/* connect state */
-+#define BLINK_RED_LED		0x04
-+#define BLINK_ORANGE_LED	0x10	/* disconnect state */
-+#define SOLID_GREEN_LED		0x20	/* tuning/seeking state */
-+#define SOLID_RED_LED		0x40	/* bootload state */
-+#define SOLID_ORANGE_LED	0x80
-+
-+
-+
-+/**************************************************************************
-+ * Stream State Definitions
-+ **************************************************************************/
-+#define STREAM_COMMAND	0x36
-+#define STREAM_VIDPID	0x00
-+#define STREAM_AUDIO	0xff
-+
-+
-+
-+/**************************************************************************
-+ * Bootloader / Flash Commands
-+ **************************************************************************/
-+
-+/* unique id sent to bootloader and required to put into a bootload state */
-+#define UNIQUE_BL_ID		0x34
-+
-+/* mask for the flash data */
-+#define FLASH_DATA_MASK		0x55
-+
-+/* bootloader commands */
-+#define GET_SW_VERSION_COMMAND	0x00
-+#define	SET_PAGE_COMMAND	0x01
-+#define ERASE_PAGE_COMMAND	0x02
-+#define WRITE_PAGE_COMMAND	0x03
-+#define CRC_ON_PAGE_COMMAND	0x04
-+#define READ_FLASH_BYTE_COMMAND	0x05
-+#define RESET_DEVICE_COMMAND	0x06
-+#define GET_HW_VERSION_COMMAND	0x07
-+#define BLANK			0xff
-+
-+/* bootloader command responses */
-+#define COMMAND_OK		0x01
-+#define COMMAND_FAILED		0x02
-+#define COMMAND_PENDING		0x03
-+
-+/* buffer sizes */
-+#define COMMAND_BUFFER_SIZE	4
-+#define RESPONSE_BUFFER_SIZE	2
-+#define FLASH_BUFFER_SIZE	64
-+#define CRC_BUFFER_SIZE		3
-+
-+
-+
-+/**************************************************************************
-+ * General Driver Definitions
-+ **************************************************************************/
-+
-+/*
-+ * si470x_device - private data
-+ */
-+struct si470x_device {
-+	/* reference to USB and video device */
-+	struct usb_device *usbdev;
-+	struct video_device *videodev;
-+
-+	/* are these really necessary ? */
-+	int users;
-+
-+	/* report buffer (maximum 64 bytes) */
-+	unsigned char buf[64];
-+
-+	/* Silabs internal registers (0..15) */
-+	unsigned short registers[RADIO_REGISTER_NUM];
-+
-+	/* RDS receive buffer */
-+	struct work_struct work;
-+	wait_queue_head_t read_queue;
-+	struct timer_list timer;
-+	spinlock_t lock;		/* buffer locking */
-+	unsigned char *buffer;		/* size is always multiple of three */
-+	unsigned int buf_size;
-+	unsigned int rd_index;
-+	unsigned int wr_index;
-+};
-+
-+
-+/*
-+ * The frequency is set in units of 62.5 Hz when using V4L2_TUNER_CAP_LOW,
-+ * 62.5 kHz otherwise.
-+ * The tuner is able to have a channel spacing of 50, 100 or 200 kHz.
-+ * tuner->capability is therefore set to V4L2_TUNER_CAP_LOW
-+ * The FREQ_MUL is then: 1 MHz / 62.5 Hz = 16000
-+ */
-+#define FREQ_MUL (1000000 / 62.5)
-+
+-	case VIDIOCSPICT:
+-	{
+-		struct video_picture *pic = arg;
+-		const struct bttv_format *fmt;
+ 
+-		fmt = format_by_palette(pic->palette);
+-		if (NULL == fmt)
+-			return -EINVAL;
+-		mutex_lock(&fh->cap.lock);
+-		if (fmt->flags & FORMAT_FLAGS_RAW) {
+-			/* VIDIOCMCAPTURE uses gbufsize, not RAW_BPL *
+-			   RAW_LINES * 2. F1 is stored at offset 0, F2
+-			   at buffer size / 2. */
+-			fh->width = RAW_BPL;
+-			fh->height = gbufsize / RAW_BPL;
+-			btv->init.width  = RAW_BPL;
+-			btv->init.height = gbufsize / RAW_BPL;
+-		}
+-		fh->ovfmt   = fmt;
+-		fh->fmt     = fmt;
+-		btv->init.ovfmt   = fmt;
+-		btv->init.fmt     = fmt;
+-		if (bigendian) {
+-			/* dirty hack time:  swap bytes for overlay if the
+-			   display adaptor is big endian (insmod option) */
+-			if (fmt->palette == VIDEO_PALETTE_RGB555 ||
+-			    fmt->palette == VIDEO_PALETTE_RGB565 ||
+-			    fmt->palette == VIDEO_PALETTE_RGB32) {
+-				fh->ovfmt = fmt+1;
+-			}
+-		}
+-		bt848_bright(btv,pic->brightness);
+-		bt848_contrast(btv,pic->contrast);
+-		bt848_hue(btv,pic->hue);
+-		bt848_sat(btv,pic->colour);
++	return setup_window(fh, btv, &f->fmt.win, 1);
++}
 +
++#ifdef CONFIG_VIDEO_V4L1_COMPAT
++static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf)
++{
++	int retval;
++	unsigned int i;
++	struct bttv_fh *fh = priv;
 +
-+/**************************************************************************
-+ * General Driver Functions
-+ **************************************************************************/
++	mutex_lock(&fh->cap.lock);
++	retval = videobuf_mmap_setup(&fh->cap, gbuffers, gbufsize,
++				     V4L2_MEMORY_MMAP);
++	if (retval < 0) {
+ 		mutex_unlock(&fh->cap.lock);
+-		return 0;
++		return retval;
+ 	}
+ 
+-	case VIDIOCGWIN:
+-	{
+-		struct video_window *win = arg;
++	gbuffers = retval;
++	memset(mbuf, 0, sizeof(*mbuf));
++	mbuf->frames = gbuffers;
++	mbuf->size   = gbuffers * gbufsize;
+ 
+-		memset(win,0,sizeof(*win));
+-		win->x      = fh->ov.w.left;
+-		win->y      = fh->ov.w.top;
+-		win->width  = fh->ov.w.width;
+-		win->height = fh->ov.w.height;
+-		return 0;
+-	}
+-	case VIDIOCSWIN:
+-	{
+-		struct video_window *win = arg;
+-		struct v4l2_window w2;
++	for (i = 0; i < gbuffers; i++)
++		mbuf->offsets[i] = i * gbufsize;
+ 
+-		if (no_overlay > 0) {
+-			printk ("VIDIOCSWIN: no_overlay\n");
+-			return -EINVAL;
+-		}
++	mutex_unlock(&fh->cap.lock);
++	return 0;
++}
++#endif
+ 
+-		w2.field = V4L2_FIELD_ANY;
+-		w2.w.left    = win->x;
+-		w2.w.top     = win->y;
+-		w2.w.width   = win->width;
+-		w2.w.height  = win->height;
+-		w2.clipcount = win->clipcount;
+-		w2.clips     = (struct v4l2_clip __user *)win->clips;
+-		retval = setup_window(fh, btv, &w2, 0);
+-		if (0 == retval) {
+-			/* on v4l1 this ioctl affects the read() size too */
+-			fh->width  = fh->ov.w.width;
+-			fh->height = fh->ov.w.height;
+-			btv->init.width  = fh->ov.w.width;
+-			btv->init.height = fh->ov.w.height;
+-		}
+-		return retval;
+-	}
++static int bttv_querycap(struct file *file, void  *priv,
++				struct v4l2_capability *cap)
++{
++	struct bttv_fh *fh = priv;
++	struct bttv *btv = fh->btv;
+ 
+-	case VIDIOCGFBUF:
+-	{
+-		struct video_buffer *fbuf = arg;
+-
+-		fbuf->base          = btv->fbuf.base;
+-		fbuf->width         = btv->fbuf.fmt.width;
+-		fbuf->height        = btv->fbuf.fmt.height;
+-		fbuf->bytesperline  = btv->fbuf.fmt.bytesperline;
+-		if (fh->ovfmt)
+-			fbuf->depth = fh->ovfmt->depth;
+-		else {
+-			if (fbuf->width)
+-				fbuf->depth   = ((fbuf->bytesperline<<3)
+-						  + (fbuf->width-1) )
+-						  /fbuf->width;
+-			else
+-				fbuf->depth = 0;
+-		}
+-		return 0;
+-	}
+-	case VIDIOCSFBUF:
+-	{
+-		struct video_buffer *fbuf = arg;
+-		const struct bttv_format *fmt;
+-		unsigned long end;
+-
+-		if(!capable(CAP_SYS_ADMIN) &&
+-		   !capable(CAP_SYS_RAWIO))
+-			return -EPERM;
+-		end = (unsigned long)fbuf->base +
+-			fbuf->height * fbuf->bytesperline;
+-		mutex_lock(&fh->cap.lock);
+-		retval = -EINVAL;
++	if (0 == v4l2)
++		return -EINVAL;
+ 
+-		switch (fbuf->depth) {
+-		case 8:
+-			fmt = format_by_palette(VIDEO_PALETTE_HI240);
+-			break;
+-		case 16:
+-			fmt = format_by_palette(VIDEO_PALETTE_RGB565);
+-			break;
+-		case 24:
+-			fmt = format_by_palette(VIDEO_PALETTE_RGB24);
+-			break;
+-		case 32:
+-			fmt = format_by_palette(VIDEO_PALETTE_RGB32);
+-			break;
+-		case 15:
+-			fbuf->depth = 16;
+-			fmt = format_by_palette(VIDEO_PALETTE_RGB555);
+-			break;
+-		default:
+-			fmt = NULL;
+-			break;
+-		}
+-		if (NULL == fmt)
+-			goto fh_unlock_and_return;
+-
+-		fh->ovfmt = fmt;
+-		fh->fmt   = fmt;
+-		btv->init.ovfmt = fmt;
+-		btv->init.fmt   = fmt;
+-		btv->fbuf.base             = fbuf->base;
+-		btv->fbuf.fmt.width        = fbuf->width;
+-		btv->fbuf.fmt.height       = fbuf->height;
+-		if (fbuf->bytesperline)
+-			btv->fbuf.fmt.bytesperline = fbuf->bytesperline;
+-		else
+-			btv->fbuf.fmt.bytesperline = btv->fbuf.fmt.width*fbuf->depth/8;
+-		mutex_unlock(&fh->cap.lock);
+-		return 0;
+-	}
++	strlcpy(cap->driver, "bttv", sizeof(cap->driver));
++	strlcpy(cap->card, btv->video_dev->name, sizeof(cap->card));
++	snprintf(cap->bus_info, sizeof(cap->bus_info),
++		 "PCI:%s", pci_name(btv->c.pci));
++	cap->version = BTTV_VERSION_CODE;
++	cap->capabilities =
++		V4L2_CAP_VIDEO_CAPTURE |
++		V4L2_CAP_VBI_CAPTURE |
++		V4L2_CAP_READWRITE |
++		V4L2_CAP_STREAMING;
++	if (no_overlay <= 0)
++		cap->capabilities |= V4L2_CAP_VIDEO_OVERLAY;
 +
-+/*
-+ * si470x_get_report - receive a HID report
-+ */
-+static int si470x_get_report(struct si470x_device *radio, int size)
++	if (bttv_tvcards[btv->c.type].tuner != UNSET &&
++	    bttv_tvcards[btv->c.type].tuner != TUNER_ABSENT)
++		cap->capabilities |= V4L2_CAP_TUNER;
++	return 0;
++}
+ 
+-	case VIDIOCCAPTURE:
+-	case VIDIOC_OVERLAY:
+-	{
+-		struct bttv_buffer *new;
+-		int *on = arg;
++static int bttv_enum_fmt_vbi(struct file *file, void  *priv,
++				struct v4l2_fmtdesc *f)
 +{
-+	return usb_control_msg(radio->usbdev,
-+		usb_rcvctrlpipe(radio->usbdev, 0),
-+		HID_REQ_GET_REPORT,
-+		USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
-+		radio->buf[0], 2,
-+		radio->buf, size, usb_timeout);
++	if (0 != f->index)
++		return -EINVAL;
+ 
+-		if (*on) {
+-			/* verify args */
+-			if (NULL == btv->fbuf.base)
+-				return -EINVAL;
+-			if (!fh->ov.setup_ok) {
+-				dprintk("bttv%d: overlay: !setup_ok\n",btv->c.nr);
+-				return -EINVAL;
+-			}
+-		}
++	f->pixelformat = V4L2_PIX_FMT_GREY;
++	strcpy(f->description, "vbi data");
+ 
+-		if (!check_alloc_btres(btv,fh,RESOURCE_OVERLAY))
+-			return -EBUSY;
++	return 0;
 +}
-+
-+
-+/*
-+ * si470x_set_report - send a HID report
-+ */
-+static int si470x_set_report(struct si470x_device *radio, int size)
+ 
+-		mutex_lock(&fh->cap.lock);
+-		if (*on) {
+-			fh->ov.tvnorm = btv->tvnorm;
+-			new = videobuf_pci_alloc(sizeof(*new));
+-			new->crop = btv->crop[!!fh->do_crop].rect;
+-			bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new);
+-		} else {
+-			new = NULL;
+-		}
++static int bttv_enum_fmt_cap_ovr(struct v4l2_fmtdesc *f)
 +{
-+	return usb_control_msg(radio->usbdev,
-+		usb_sndctrlpipe(radio->usbdev, 0),
-+		HID_REQ_SET_REPORT,
-+		USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,
-+		radio->buf[0], 2,
-+		radio->buf, size, usb_timeout);
++	int index = -1, i;
+ 
+-		/* switch over */
+-		retval = bttv_switch_overlay(btv,fh,new);
+-		mutex_unlock(&fh->cap.lock);
+-		return retval;
++	for (i = 0; i < FORMATS; i++) {
++		if (formats[i].fourcc != -1)
++			index++;
++		if ((unsigned int)index == f->index)
++			break;
+ 	}
++	if (FORMATS == i)
++		return -EINVAL;
+ 
+-	case VIDIOCGMBUF:
+-	{
+-		struct video_mbuf *mbuf = arg;
+-		unsigned int i;
++	f->pixelformat = formats[i].fourcc;
++	strlcpy(f->description, formats[i].name, sizeof(f->description));
+ 
+-		retval = videobuf_mmap_setup(&fh->cap,gbuffers,gbufsize,
+-					     V4L2_MEMORY_MMAP);
+-		if (retval < 0)
+-			return retval;
++	return i;
 +}
-+
-+
-+/*
-+ * si470x_get_register - read register
-+ */
-+static int si470x_get_register(struct si470x_device *radio, int regnr)
+ 
+-		gbuffers = retval;
+-		memset(mbuf,0,sizeof(*mbuf));
+-		mbuf->frames = gbuffers;
+-		mbuf->size   = gbuffers * gbufsize;
+-		for (i = 0; i < gbuffers; i++)
+-			mbuf->offsets[i] = i * gbufsize;
+-		return 0;
+-	}
+-	case VIDIOCMCAPTURE:
+-	{
+-		struct video_mmap *vm = arg;
+-		struct bttv_buffer *buf;
+-		enum v4l2_field field;
+-		__s32 height2;
+-		int res;
++static int bttv_enum_fmt_cap(struct file *file, void  *priv,
++				struct v4l2_fmtdesc *f)
 +{
-+	int retval;
-+
-+	radio->buf[0] = REGISTER_REPORT(regnr);
-+
-+	retval = si470x_get_report(radio, REGISTER_REPORT_SIZE);
-+	if (retval >= 0)
-+		radio->registers[regnr] = (radio->buf[1] << 8) | radio->buf[2];
-+
-+	return (retval < 0) ? -EINVAL : 0;
++	int rc = bttv_enum_fmt_cap_ovr(f);
+ 
+-		if (vm->frame >= VIDEO_MAX_FRAME)
+-			return -EINVAL;
++	if (rc < 0)
++		return rc;
+ 
+-		res = bttv_resource(fh);
+-		if (!check_alloc_btres(btv, fh, res))
+-			return -EBUSY;
++	return 0;
 +}
-+
-+
-+/*
-+ * si470x_set_register - write register
-+ */
-+static int si470x_set_register(struct si470x_device *radio, int regnr)
+ 
+-		mutex_lock(&fh->cap.lock);
+-		retval = -EINVAL;
+-		buf = (struct bttv_buffer *)fh->cap.bufs[vm->frame];
+-		if (NULL == buf)
+-			goto fh_unlock_and_return;
+-		if (0 == buf->vb.baddr)
+-			goto fh_unlock_and_return;
+-		if (buf->vb.state == STATE_QUEUED ||
+-		    buf->vb.state == STATE_ACTIVE)
+-			goto fh_unlock_and_return;
++static int bttv_enum_fmt_overlay(struct file *file, void  *priv,
++					struct v4l2_fmtdesc *f)
 +{
-+	int retval;
-+
-+	radio->buf[0] = REGISTER_REPORT(regnr);
-+	radio->buf[1] = (radio->registers[regnr] & 0xff00) >> 8;
-+	radio->buf[2] = (radio->registers[regnr] & 0x00ff);
-+
-+	retval = si470x_set_report(radio, REGISTER_REPORT_SIZE);
-+
-+	return (retval < 0) ? -EINVAL : 0;
++	int rc;
+ 
+-		height2 = btv->crop[!!fh->do_crop].rect.height >> 1;
+-		field = (vm->height > height2)
+-			? V4L2_FIELD_INTERLACED
+-			: V4L2_FIELD_BOTTOM;
+-		retval = bttv_prepare_buffer(&fh->cap,btv,buf,
+-					     format_by_palette(vm->format),
+-					     vm->width,vm->height,field);
+-		if (0 != retval)
+-			goto fh_unlock_and_return;
+-		btv->init.width = vm->width;
+-		btv->init.height = vm->height;
+-		spin_lock_irqsave(&btv->s_lock,flags);
+-		buffer_queue(&fh->cap,&buf->vb);
+-		spin_unlock_irqrestore(&btv->s_lock,flags);
+-		mutex_unlock(&fh->cap.lock);
+-		return 0;
++	if (no_overlay > 0) {
++		printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
++		return -EINVAL;
+ 	}
+-	case VIDIOCSYNC:
+-	{
+-		int *frame = arg;
+-		struct bttv_buffer *buf;
+ 
+-		if (*frame >= VIDEO_MAX_FRAME)
+-			return -EINVAL;
++	rc = bttv_enum_fmt_cap_ovr(f);
+ 
+-		mutex_lock(&fh->cap.lock);
+-		retval = -EINVAL;
+-		buf = (struct bttv_buffer *)fh->cap.bufs[*frame];
+-		if (NULL == buf)
+-			goto fh_unlock_and_return;
+-		retval = videobuf_waiton(&buf->vb,0,1);
+-		if (0 != retval)
+-			goto fh_unlock_and_return;
+-		switch (buf->vb.state) {
+-		case STATE_ERROR:
+-			retval = -EIO;
+-			/* fall through */
+-		case STATE_DONE:
+-		{
+-			struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
+-			videobuf_dma_sync(&fh->cap,dma);
+-			bttv_dma_free(&fh->cap,btv,buf);
+-			break;
+-		}
+-		default:
+-			retval = -EINVAL;
+-			break;
+-		}
+-		mutex_unlock(&fh->cap.lock);
+-		return retval;
+-	}
++	if (rc < 0)
++		return rc;
+ 
+-	case VIDIOCGVBIFMT:
+-		if (fh->type != V4L2_BUF_TYPE_VBI_CAPTURE) {
+-			retval = bttv_switch_type(fh,V4L2_BUF_TYPE_VBI_CAPTURE);
+-			if (0 != retval)
+-				return retval;
+-		}
++	if (!(formats[rc].flags & FORMAT_FLAGS_PACKED))
++		return -EINVAL;
+ 
+-		/* fall through */
++	return 0;
 +}
-+
-+
-+/*
-+ * si470x_get_all_registers - read entire registers
-+ */
-+static int si470x_get_all_registers(struct si470x_device *radio)
+ 
+-	case VIDIOCSVBIFMT:
+-		return v4l_compat_translate_ioctl(inode, file, cmd,
+-						  arg, bttv_do_ioctl);
+-
+-	case BTTV_VERSION:
+-	case VIDIOCGFREQ:
+-	case VIDIOCSFREQ:
+-	case VIDIOCGTUNER:
+-	case VIDIOCSTUNER:
+-	case VIDIOCGCHAN:
+-	case VIDIOCSCHAN:
+-	case VIDIOCGAUDIO:
+-	case VIDIOCSAUDIO:
+-		return bttv_common_ioctls(btv,cmd,arg);
+-
+-	/* ***  v4l2  *** ************************************************ */
+-	case VIDIOC_QUERYCAP:
+-	{
+-		struct v4l2_capability *cap = arg;
++static int bttv_g_fbuf(struct file *file, void *f,
++				struct v4l2_framebuffer *fb)
++{
++	struct bttv_fh *fh = f;
++	struct bttv *btv = fh->btv;
+ 
+-		if (0 == v4l2)
+-			return -EINVAL;
+-		memset(cap, 0, sizeof (*cap));
+-		strlcpy(cap->driver, "bttv", sizeof (cap->driver));
+-		strlcpy(cap->card, btv->video_dev->name, sizeof (cap->card));
+-		snprintf(cap->bus_info, sizeof (cap->bus_info),
+-			 "PCI:%s", pci_name(btv->c.pci));
+-		cap->version = BTTV_VERSION_CODE;
+-		cap->capabilities =
+-			V4L2_CAP_VIDEO_CAPTURE |
+-			V4L2_CAP_VBI_CAPTURE |
+-			V4L2_CAP_READWRITE |
+-			V4L2_CAP_STREAMING;
+-		if (no_overlay <= 0)
+-			cap->capabilities |= V4L2_CAP_VIDEO_OVERLAY;
+-
+-		if (bttv_tvcards[btv->c.type].tuner != UNSET &&
+-		    bttv_tvcards[btv->c.type].tuner != TUNER_ABSENT)
+-			cap->capabilities |= V4L2_CAP_TUNER;
+-		return 0;
+-	}
++	*fb = btv->fbuf;
++	fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING;
++	if (fh->ovfmt)
++		fb->fmt.pixelformat  = fh->ovfmt->fourcc;
++	return 0;
++}
+ 
+-	case VIDIOC_ENUM_FMT:
+-	{
+-		struct v4l2_fmtdesc *f = arg;
+-		enum v4l2_buf_type type;
+-		unsigned int i;
+-		int index;
+-
+-		type  = f->type;
+-		if (V4L2_BUF_TYPE_VBI_CAPTURE == type) {
+-			/* vbi */
+-			index = f->index;
+-			if (0 != index)
+-				return -EINVAL;
+-			memset(f,0,sizeof(*f));
+-			f->index       = index;
+-			f->type        = type;
+-			f->pixelformat = V4L2_PIX_FMT_GREY;
+-			strcpy(f->description,"vbi data");
+-			return 0;
+-		}
++static int bttv_overlay(struct file *file, void *f, unsigned int on)
 +{
++	struct bttv_fh *fh = f;
++	struct bttv *btv = fh->btv;
++	struct bttv_buffer *new;
 +	int retval;
-+	int regnr;
-+
-+	radio->buf[0] = ENTIRE_REPORT;
-+
-+	retval = si470x_get_report(radio, ENTIRE_REPORT_SIZE);
-+
-+	if (retval >= 0)
-+		for (regnr = 0; regnr < RADIO_REGISTER_NUM; regnr++)
-+			radio->registers[regnr] =
-+			(radio->buf[regnr * RADIO_REGISTER_SIZE + 1] << 8) |
-+			 radio->buf[regnr * RADIO_REGISTER_SIZE + 2];
+ 
+-		/* video capture + overlay */
+-		index = -1;
+-		for (i = 0; i < BTTV_FORMATS; i++) {
+-			if (bttv_formats[i].fourcc != -1)
+-				index++;
+-			if ((unsigned int)index == f->index)
+-				break;
+-		}
+-		if (BTTV_FORMATS == i)
++	if (on) {
++		/* verify args */
++		if (NULL == btv->fbuf.base)
+ 			return -EINVAL;
+-
+-		switch (f->type) {
+-		case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+-			break;
+-		case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+-			if (!(bttv_formats[i].flags & FORMAT_FLAGS_PACKED))
+-				return -EINVAL;
+-			break;
+-		default:
++		if (!fh->ov.setup_ok) {
++			dprintk("bttv%d: overlay: !setup_ok\n", btv->c.nr);
+ 			return -EINVAL;
+ 		}
+-		memset(f,0,sizeof(*f));
+-		f->index       = index;
+-		f->type        = type;
+-		f->pixelformat = bttv_formats[i].fourcc;
+-		strlcpy(f->description,bttv_formats[i].name,sizeof(f->description));
+-		return 0;
+ 	}
+ 
+-	case VIDIOC_TRY_FMT:
+-	{
+-		struct v4l2_format *f = arg;
+-		return bttv_try_fmt(fh,btv,f, /* adjust_crop */ 0);
+-	}
+-	case VIDIOC_G_FMT:
+-	{
+-		struct v4l2_format *f = arg;
+-		return bttv_g_fmt(fh,f);
+-	}
+-	case VIDIOC_S_FMT:
+-	{
+-		struct v4l2_format *f = arg;
+-		return bttv_s_fmt(fh,btv,f);
++	if (!check_alloc_btres(btv, fh, RESOURCE_OVERLAY))
++		return -EBUSY;
 +
-+	return (retval < 0) ? -EINVAL : 0;
++	mutex_lock(&fh->cap.lock);
++	if (on) {
++		fh->ov.tvnorm = btv->tvnorm;
++		new = videobuf_pci_alloc(sizeof(*new));
++		bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new);
++	} else {
++		new = NULL;
+ 	}
+ 
+-	case VIDIOC_G_FBUF:
+-	{
+-		struct v4l2_framebuffer *fb = arg;
++	/* switch over */
++	retval = bttv_switch_overlay(btv, fh, new);
++	mutex_unlock(&fh->cap.lock);
++	return retval;
 +}
-+
-+
-+/*
-+ * si470x_get_rds_registers - read rds registers
-+ */
-+static int si470x_get_rds_registers(struct si470x_device *radio)
+ 
+-		*fb = btv->fbuf;
+-		fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING;
+-		if (fh->ovfmt)
+-			fb->fmt.pixelformat  = fh->ovfmt->fourcc;
+-		return 0;
+-	}
+-	case VIDIOC_S_FBUF:
+-	{
+-		struct v4l2_framebuffer *fb = arg;
+-		const struct bttv_format *fmt;
++static int bttv_s_fbuf(struct file *file, void *f,
++				struct v4l2_framebuffer *fb)
 +{
++	struct bttv_fh *fh = f;
++	struct bttv *btv = fh->btv;
++	const struct bttv_format *fmt;
 +	int retval;
-+	int regnr;
-+	int size;
+ 
+-		if(!capable(CAP_SYS_ADMIN) &&
+-		   !capable(CAP_SYS_RAWIO))
+-			return -EPERM;
++	if (!capable(CAP_SYS_ADMIN) &&
++		!capable(CAP_SYS_RAWIO))
++		return -EPERM;
+ 
+-		/* check args */
+-		fmt = format_by_fourcc(fb->fmt.pixelformat);
+-		if (NULL == fmt)
+-			return -EINVAL;
+-		if (0 == (fmt->flags & FORMAT_FLAGS_PACKED))
+-			return -EINVAL;
++	/* check args */
++	fmt = format_by_fourcc(fb->fmt.pixelformat);
++	if (NULL == fmt)
++		return -EINVAL;
++	if (0 == (fmt->flags & FORMAT_FLAGS_PACKED))
++		return -EINVAL;
+ 
+-		retval = -EINVAL;
+-		if (fb->flags & V4L2_FBUF_FLAG_OVERLAY) {
+-			__s32 width = fb->fmt.width;
+-			__s32 height = fb->fmt.height;
+-
+-			retval = limit_scaled_size(fh, &width, &height,
+-						   V4L2_FIELD_INTERLACED,
+-						   /* width_mask */ ~3,
+-						   /* width_bias */ 2,
+-						   /* adjust_size */ 0,
+-						   /* adjust_crop */ 0);
+-			if (0 != retval)
+-				return retval;
+-		}
++	retval = -EINVAL;
++	if (fb->flags & V4L2_FBUF_FLAG_OVERLAY) {
++		__s32 width = fb->fmt.width;
++		__s32 height = fb->fmt.height;
 +
-+	radio->buf[0] = RDS_REPORT;
++		retval = limit_scaled_size(fh, &width, &height,
++					   V4L2_FIELD_INTERLACED,
++					   /* width_mask */ ~3,
++					   /* width_bias */ 2,
++					   /* adjust_size */ 0,
++					   /* adjust_crop */ 0);
++		if (0 != retval)
++			return retval;
++	}
+ 
+-		/* ok, accept it */
+-		mutex_lock(&fh->cap.lock);
+-		btv->fbuf.base       = fb->base;
+-		btv->fbuf.fmt.width  = fb->fmt.width;
+-		btv->fbuf.fmt.height = fb->fmt.height;
+-		if (0 != fb->fmt.bytesperline)
+-			btv->fbuf.fmt.bytesperline = fb->fmt.bytesperline;
+-		else
+-			btv->fbuf.fmt.bytesperline = btv->fbuf.fmt.width*fmt->depth/8;
+-
+-		retval = 0;
+-		fh->ovfmt = fmt;
+-		btv->init.ovfmt = fmt;
+-		if (fb->flags & V4L2_FBUF_FLAG_OVERLAY) {
+-			fh->ov.w.left   = 0;
+-			fh->ov.w.top    = 0;
+-			fh->ov.w.width  = fb->fmt.width;
+-			fh->ov.w.height = fb->fmt.height;
+-			btv->init.ov.w.width  = fb->fmt.width;
+-			btv->init.ov.w.height = fb->fmt.height;
+-				kfree(fh->ov.clips);
+-			fh->ov.clips = NULL;
+-			fh->ov.nclips = 0;
+-
+-			if (check_btres(fh, RESOURCE_OVERLAY)) {
+-				struct bttv_buffer *new;
+-
+-				new = videobuf_pci_alloc(sizeof(*new));
+-				new->crop = btv->crop[!!fh->do_crop].rect;
+-				bttv_overlay_risc(btv,&fh->ov,fh->ovfmt,new);
+-				retval = bttv_switch_overlay(btv,fh,new);
+-			}
++	/* ok, accept it */
++	mutex_lock(&fh->cap.lock);
++	btv->fbuf.base       = fb->base;
++	btv->fbuf.fmt.width  = fb->fmt.width;
++	btv->fbuf.fmt.height = fb->fmt.height;
++	if (0 != fb->fmt.bytesperline)
++		btv->fbuf.fmt.bytesperline = fb->fmt.bytesperline;
++	else
++		btv->fbuf.fmt.bytesperline = btv->fbuf.fmt.width*fmt->depth/8;
 +
-+	retval = usb_interrupt_msg(radio->usbdev,
-+		usb_rcvctrlpipe(radio->usbdev, 1),
-+		radio->buf, RDS_REPORT_SIZE, &size, usb_timeout);
++	retval = 0;
++	fh->ovfmt = fmt;
++	btv->init.ovfmt = fmt;
++	if (fb->flags & V4L2_FBUF_FLAG_OVERLAY) {
++		fh->ov.w.left   = 0;
++		fh->ov.w.top    = 0;
++		fh->ov.w.width  = fb->fmt.width;
++		fh->ov.w.height = fb->fmt.height;
++		btv->init.ov.w.width  = fb->fmt.width;
++		btv->init.ov.w.height = fb->fmt.height;
++			kfree(fh->ov.clips);
++		fh->ov.clips = NULL;
++		fh->ov.nclips = 0;
 +
-+	if (retval >= 0)
-+		for (regnr = 0; regnr < RDS_REGISTER_NUM; regnr++)
-+			radio->registers[STATUSRSSI + regnr] =
-+			(radio->buf[regnr * RADIO_REGISTER_SIZE + 1] << 8) |
-+			 radio->buf[regnr * RADIO_REGISTER_SIZE + 2];
++		if (check_btres(fh, RESOURCE_OVERLAY)) {
++			struct bttv_buffer *new;
 +
-+	return (retval < 0) ? -EINVAL : 0;
++			new = videobuf_pci_alloc(sizeof(*new));
++			new->crop = btv->crop[!!fh->do_crop].rect;
++			bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new);
++			retval = bttv_switch_overlay(btv, fh, new);
+ 		}
+-		mutex_unlock(&fh->cap.lock);
+-		return retval;
+ 	}
++	mutex_unlock(&fh->cap.lock);
++	return retval;
 +}
-+
-+
-+/*
-+ * si470x_set_chan - set the channel
-+ */
-+static int si470x_set_chan(struct si470x_device *radio, int chan)
+ 
+-	case VIDIOC_REQBUFS:
+-		return videobuf_reqbufs(bttv_queue(fh),arg);
++static int bttv_reqbufs(struct file *file, void *priv,
++				struct v4l2_requestbuffers *p)
 +{
-+	int retval, i;
-+
-+	/* start tuning */
-+	radio->registers[CHANNEL] &= ~CHANNEL_CHAN;
-+	radio->registers[CHANNEL] |= CHANNEL_TUNE | chan;
-+	retval = si470x_set_register(radio, CHANNEL);
-+	if (retval < 0)
-+		return retval;
-+
-+	/* wait till seek operation has completed */
-+	i = 0;
-+	do {
-+		retval = si470x_get_register(radio, STATUSRSSI);
-+		if (retval < 0)
-+			return retval;
-+	} while ((radio->registers[STATUSRSSI] & STATUSRSSI_STC) &&
-+		(++i < seek_retries));
-+	if (i >= seek_retries)
-+		printk(KERN_WARNING DRIVER_NAME
-+			": seek does not finish after %d tries\n", i);
-+
-+	/* stop tuning */
-+	radio->registers[CHANNEL] &= ~CHANNEL_TUNE;
-+	return si470x_set_register(radio, CHANNEL);
++	struct bttv_fh *fh = priv;
++	return videobuf_reqbufs(bttv_queue(fh), p);
 +}
-+
-+
-+/*
-+ * si470x_get_freq - get the frequency
-+ */
-+static int si470x_get_freq(struct si470x_device *radio)
+ 
+-	case VIDIOC_QUERYBUF:
+-		return videobuf_querybuf(bttv_queue(fh),arg);
++static int bttv_querybuf(struct file *file, void *priv,
++				struct v4l2_buffer *b)
 +{
-+	int spacing, band_bottom, chan, freq;
++	struct bttv_fh *fh = priv;
++	return videobuf_querybuf(bttv_queue(fh), b);
++}
+ 
+-	case VIDIOC_QBUF:
+-	{
+-		int res = bttv_resource(fh);
++static int bttv_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
++{
++	struct bttv_fh *fh = priv;
++	struct bttv *btv = fh->btv;
++	int res = bttv_resource(fh);
+ 
+-		if (!check_alloc_btres(btv, fh, res))
+-			return -EBUSY;
+-		return videobuf_qbuf(bttv_queue(fh),arg);
+-	}
++	if (!check_alloc_btres(btv, fh, res))
++		return -EBUSY;
+ 
+-	case VIDIOC_DQBUF:
+-		return videobuf_dqbuf(bttv_queue(fh),arg,
+-				      file->f_flags & O_NONBLOCK);
++	return videobuf_qbuf(bttv_queue(fh), b);
++}
+ 
+-	case VIDIOC_STREAMON:
+-	{
+-		int res = bttv_resource(fh);
++static int bttv_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
++{
++	struct bttv_fh *fh = priv;
++	return videobuf_dqbuf(bttv_queue(fh), b,
++			file->f_flags & O_NONBLOCK);
++}
+ 
+-		if (!check_alloc_btres(btv,fh,res))
+-			return -EBUSY;
+-		return videobuf_streamon(bttv_queue(fh));
+-	}
+-	case VIDIOC_STREAMOFF:
+-	{
+-		int res = bttv_resource(fh);
++static int bttv_streamon(struct file *file, void *priv,
++					enum v4l2_buf_type type)
++{
++	struct bttv_fh *fh = priv;
++	struct bttv *btv = fh->btv;
++	int res = bttv_resource(fh);
+ 
+-		retval = videobuf_streamoff(bttv_queue(fh));
+-		if (retval < 0)
+-			return retval;
+-		free_btres(btv,fh,res);
+-		return 0;
+-	}
++	if (!check_alloc_btres(btv, fh, res))
++		return -EBUSY;
++	return videobuf_streamon(bttv_queue(fh));
++}
+ 
+-	case VIDIOC_QUERYCTRL:
+-	{
+-		struct v4l2_queryctrl *c = arg;
+-		int i;
+ 
+-		if ((c->id <  V4L2_CID_BASE ||
+-		     c->id >= V4L2_CID_LASTP1) &&
+-		    (c->id <  V4L2_CID_PRIVATE_BASE ||
+-		     c->id >= V4L2_CID_PRIVATE_LASTP1))
+-			return -EINVAL;
+-		for (i = 0; i < BTTV_CTLS; i++)
+-			if (bttv_ctls[i].id == c->id)
+-				break;
+-		if (i == BTTV_CTLS) {
+-			*c = no_ctl;
+-			return 0;
+-		}
+-		*c = bttv_ctls[i];
+-		if (btv->audio_hook && i >= 4 && i <= 8) {
+-			struct video_audio va;
+-			memset(&va,0,sizeof(va));
+-			btv->audio_hook(btv,&va,0);
+-			switch (bttv_ctls[i].id) {
+-			case V4L2_CID_AUDIO_VOLUME:
+-				if (!(va.flags & VIDEO_AUDIO_VOLUME))
+-					*c = no_ctl;
+-				break;
+-			case V4L2_CID_AUDIO_BALANCE:
+-				if (!(va.flags & VIDEO_AUDIO_BALANCE))
+-					*c = no_ctl;
+-				break;
+-			case V4L2_CID_AUDIO_BASS:
+-				if (!(va.flags & VIDEO_AUDIO_BASS))
+-					*c = no_ctl;
+-				break;
+-			case V4L2_CID_AUDIO_TREBLE:
+-				if (!(va.flags & VIDEO_AUDIO_TREBLE))
+-					*c = no_ctl;
+-				break;
+-			}
+-		}
+-		return 0;
+-	}
+-	case VIDIOC_G_CTRL:
+-		return get_control(btv,arg);
+-	case VIDIOC_S_CTRL:
+-		return set_control(btv,arg);
+-	case VIDIOC_G_PARM:
+-	{
+-		struct v4l2_streamparm *parm = arg;
+-		struct v4l2_standard s;
+-		if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+-			return -EINVAL;
+-		memset(parm,0,sizeof(*parm));
+-		v4l2_video_std_construct(&s, bttv_tvnorms[btv->tvnorm].v4l2_id,
+-					 bttv_tvnorms[btv->tvnorm].name);
+-		parm->parm.capture.timeperframe = s.frameperiod;
+-		return 0;
+-	}
++static int bttv_streamoff(struct file *file, void *priv,
++					enum v4l2_buf_type type)
++{
++	struct bttv_fh *fh = priv;
++	struct bttv *btv = fh->btv;
 +	int retval;
-+
-+	/* Spacing (kHz) */
-+	switch (space) {
-+	/* 0: 200 kHz (USA, Australia) */
-+	case 0 : spacing = 0.200 * FREQ_MUL; break;
-+	/* 1: 100 kHz (Europe, Japan) */
-+	case 1 : spacing = 0.100 * FREQ_MUL; break;
-+	/* 2:  50 kHz */
-+	default: spacing = 0.050 * FREQ_MUL; break;
-+	};
-+
-+	/* Bottom of Band (MHz) */
-+	switch (band) {
-+	/* 0: 87.5 - 108 MHz (USA, Europe) */
-+	case 0 : band_bottom = 87.5 * FREQ_MUL; break;
-+	/* 1: 76   - 108 MHz (Japan wide band) */
-+	default: band_bottom = 76   * FREQ_MUL; break;
-+	/* 2: 76   -  90 MHz (Japan) */
-+	case 2 : band_bottom = 76   * FREQ_MUL; break;
-+	};
-+
-+	/* read channel */
-+	retval = si470x_get_register(radio, READCHAN);
++	int res = bttv_resource(fh);
+ 
+-	case VIDIOC_G_PRIORITY:
+-	{
+-		enum v4l2_priority *p = arg;
+ 
+-		*p = v4l2_prio_max(&btv->prio);
+-		return 0;
+-	}
+-	case VIDIOC_S_PRIORITY:
+-	{
+-		enum v4l2_priority *prio = arg;
++	retval = videobuf_streamoff(bttv_queue(fh));
 +	if (retval < 0)
 +		return retval;
-+	chan = radio->registers[READCHAN] & READCHAN_READCHAN;
-+
-+	/* Frequency (MHz) = Spacing (kHz) x Channel + Bottom of Band (MHz) */
-+	freq = chan * spacing + band_bottom;
++	free_btres(btv, fh, res);
++	return 0;
++}
+ 
+-		return v4l2_prio_change(&btv->prio, &fh->prio, *prio);
+-	}
++static int bttv_queryctrl(struct file *file, void *priv,
++					struct v4l2_queryctrl *c)
++{
++	struct bttv_fh *fh = priv;
++	struct bttv *btv = fh->btv;
++	const struct v4l2_queryctrl *ctrl;
+ 
+-	case VIDIOC_CROPCAP:
+-	{
+-		struct v4l2_cropcap *cap = arg;
+-		enum v4l2_buf_type type;
++	if ((c->id <  V4L2_CID_BASE ||
++	     c->id >= V4L2_CID_LASTP1) &&
++	    (c->id <  V4L2_CID_PRIVATE_BASE ||
++	     c->id >= V4L2_CID_PRIVATE_LASTP1))
++		return -EINVAL;
+ 
+-		type = cap->type;
++	if (!btv->volume_gpio && (c->id == V4L2_CID_AUDIO_VOLUME))
++		*c = no_ctl;
++	else {
++		ctrl = ctrl_by_id(c->id);
+ 
+-		if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+-		    type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
+-			return -EINVAL;
++		*c = (NULL != ctrl) ? *ctrl : no_ctl;
++	}
+ 
+-		*cap = bttv_tvnorms[btv->tvnorm].cropcap;
+-		cap->type = type;
++	return 0;
++}
+ 
+-		return 0;
+-	}
+-	case VIDIOC_G_CROP:
+-	{
+-		struct v4l2_crop * crop = arg;
++static int bttv_g_parm(struct file *file, void *f,
++				struct v4l2_streamparm *parm)
++{
++	struct bttv_fh *fh = f;
++	struct bttv *btv = fh->btv;
++	struct v4l2_standard s;
+ 
+-		if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+-		    crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
+-			return -EINVAL;
++	if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
++		return -EINVAL;
++	v4l2_video_std_construct(&s, bttv_tvnorms[btv->tvnorm].v4l2_id,
++				 bttv_tvnorms[btv->tvnorm].name);
++	parm->parm.capture.timeperframe = s.frameperiod;
++	return 0;
++}
+ 
+-		/* No fh->do_crop = 1; because btv->crop[1] may be
+-		   inconsistent with fh->width or fh->height and apps
+-		   do not expect a change here. */
++static int bttv_g_tuner(struct file *file, void *priv,
++				struct v4l2_tuner *t)
++{
++	struct bttv_fh *fh = priv;
++	struct bttv *btv = fh->btv;
+ 
+-		crop->c = btv->crop[!!fh->do_crop].rect;
++	if (UNSET == bttv_tvcards[btv->c.type].tuner)
++		return -EINVAL;
++	if (0 != t->index)
++		return -EINVAL;
+ 
+-		return 0;
+-	}
+-	case VIDIOC_S_CROP:
+-	{
+-		struct v4l2_crop *crop = arg;
+-		const struct v4l2_rect *b;
+-		struct bttv_crop c;
+-		__s32 b_left;
+-		__s32 b_top;
+-		__s32 b_right;
+-		__s32 b_bottom;
+-
+-		if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+-		    crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
+-			return -EINVAL;
++	mutex_lock(&btv->lock);
++	memset(t, 0, sizeof(*t));
++	t->rxsubchans = V4L2_TUNER_SUB_MONO;
++	bttv_call_i2c_clients(btv, VIDIOC_G_TUNER, t);
++	strcpy(t->name, "Television");
++	t->capability = V4L2_TUNER_CAP_NORM;
++	t->type       = V4L2_TUNER_ANALOG_TV;
++	if (btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC)
++		t->signal = 0xffff;
 +
-+	return freq;
++	if (btv->audio_mode_gpio)
++		btv->audio_mode_gpio(btv, t, 0);
+ 
+-		retval = v4l2_prio_check(&btv->prio,&fh->prio);
+-		if (0 != retval)
+-			return retval;
++	mutex_unlock(&btv->lock);
++	return 0;
++}
+ 
+-		/* Make sure tvnorm, vbi_end and the current cropping
+-		   parameters remain consistent until we're done. Note
+-		   read() may change vbi_end in check_alloc_btres(). */
+-		mutex_lock(&btv->lock);
++static int bttv_g_priority(struct file *file, void *f, enum v4l2_priority *p)
++{
++	struct bttv_fh *fh = f;
++	struct bttv *btv = fh->btv;
+ 
+-		retval = -EBUSY;
++	*p = v4l2_prio_max(&btv->prio);
+ 
+-		if (locked_btres(fh->btv, VIDEO_RESOURCES))
+-			goto btv_unlock_and_return;
++	return 0;
++}
+ 
+-		b = &bttv_tvnorms[btv->tvnorm].cropcap.bounds;
++static int bttv_s_priority(struct file *file, void *f,
++					enum v4l2_priority prio)
++{
++	struct bttv_fh *fh = f;
++	struct bttv *btv = fh->btv;
+ 
+-		b_left = b->left;
+-		b_right = b_left + b->width;
+-		b_bottom = b->top + b->height;
++	return v4l2_prio_change(&btv->prio, &fh->prio, prio);
 +}
-+
-+
-+/*
-+ * si470x_set_freq - set the frequency
-+ */
-+static int si470x_set_freq(struct si470x_device *radio, int freq)
+ 
+-		b_top = max(b->top, btv->vbi_end);
+-		if (b_top + 32 >= b_bottom)
+-			goto btv_unlock_and_return;
++static int bttv_cropcap(struct file *file, void *priv,
++				struct v4l2_cropcap *cap)
 +{
-+	int spacing, band_bottom, chan;
-+
-+	/* Spacing (kHz) */
-+	switch (space) {
-+	/* 0: 200 kHz (USA, Australia) */
-+	case 0 : spacing = 0.200 * FREQ_MUL; break;
-+	/* 1: 100 kHz (Europe, Japan) */
-+	case 1 : spacing = 0.100 * FREQ_MUL; break;
-+	/* 2:  50 kHz */
-+	default: spacing = 0.050 * FREQ_MUL; break;
-+	};
-+
-+	/* Bottom of Band (MHz) */
-+	switch (band) {
-+	/* 0: 87.5 - 108 MHz (USA, Europe) */
-+	case 0 : band_bottom = 87.5 * FREQ_MUL; break;
-+	/* 1: 76   - 108 MHz (Japan wide band) */
-+	default: band_bottom = 76   * FREQ_MUL; break;
-+	/* 2: 76   -  90 MHz (Japan) */
-+	case 2 : band_bottom = 76   * FREQ_MUL; break;
-+	};
-+
-+	/* Chan = [ Freq (Mhz) - Bottom of Band (MHz) ] / Spacing (kHz) */
-+	chan = (freq - band_bottom) / spacing;
-+
-+	return si470x_set_chan(radio, chan);
++	struct bttv_fh *fh = priv;
++	struct bttv *btv = fh->btv;
+ 
+-		/* Min. scaled size 48 x 32. */
+-		c.rect.left = clamp(crop->c.left, b_left, b_right - 48);
+-		c.rect.left = min(c.rect.left, (__s32) MAX_HDELAY);
++	if (cap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
++	    cap->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
++		return -EINVAL;
+ 
+-		c.rect.width = clamp(crop->c.width,
+-				     48, b_right - c.rect.left);
++	*cap = bttv_tvnorms[btv->tvnorm].cropcap;
+ 
+-		c.rect.top = clamp(crop->c.top, b_top, b_bottom - 32);
+-		/* Top and height must be a multiple of two. */
+-		c.rect.top = (c.rect.top + 1) & ~1;
++	return 0;
 +}
-+
-+
-+/*
-+ * si470x_start - switch on radio
-+ */
-+static int si470x_start(struct si470x_device *radio)
+ 
+-		c.rect.height = clamp(crop->c.height,
+-				      32, b_bottom - c.rect.top);
+-		c.rect.height = (c.rect.height + 1) & ~1;
++static int bttv_g_crop(struct file *file, void *f, struct v4l2_crop *crop)
++{
++	struct bttv_fh *fh = f;
++	struct bttv *btv = fh->btv;
+ 
+-		bttv_crop_calc_limits(&c);
++	if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
++	    crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
++		return -EINVAL;
+ 
+-		btv->crop[1] = c;
++	/* No fh->do_crop = 1; because btv->crop[1] may be
++	   inconsistent with fh->width or fh->height and apps
++	   do not expect a change here. */
+ 
+-		mutex_unlock(&btv->lock);
++	crop->c = btv->crop[!!fh->do_crop].rect;
+ 
+-		fh->do_crop = 1;
++	return 0;
++}
+ 
+-		mutex_lock(&fh->cap.lock);
++static int bttv_s_crop(struct file *file, void *f, struct v4l2_crop *crop)
 +{
++	struct bttv_fh *fh = f;
++	struct bttv *btv = fh->btv;
++	const struct v4l2_rect *b;
 +	int retval;
-+
-+	/* powercfg */
-+	radio->registers[POWERCFG] =
-+		POWERCFG_DMUTE | POWERCFG_ENABLE | POWERCFG_RDSM;
-+	retval = si470x_set_register(radio, POWERCFG);
-+	if (retval < 0)
++	struct bttv_crop c;
++	__s32 b_left;
++	__s32 b_top;
++	__s32 b_right;
++	__s32 b_bottom;
+ 
+-		if (fh->width < c.min_scaled_width) {
+-			fh->width = c.min_scaled_width;
+-			btv->init.width = c.min_scaled_width;
+-		} else if (fh->width > c.max_scaled_width) {
+-			fh->width = c.max_scaled_width;
+-			btv->init.width = c.max_scaled_width;
+-		}
++	if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
++	    crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
++		return -EINVAL;
+ 
+-		if (fh->height < c.min_scaled_height) {
+-			fh->height = c.min_scaled_height;
+-			btv->init.height = c.min_scaled_height;
+-		} else if (fh->height > c.max_scaled_height) {
+-			fh->height = c.max_scaled_height;
+-			btv->init.height = c.max_scaled_height;
+-		}
++	retval = v4l2_prio_check(&btv->prio, &fh->prio);
++	if (0 != retval)
 +		return retval;
+ 
+-		mutex_unlock(&fh->cap.lock);
++	/* Make sure tvnorm, vbi_end and the current cropping
++	   parameters remain consistent until we're done. Note
++	   read() may change vbi_end in check_alloc_btres(). */
++	mutex_lock(&btv->lock);
+ 
+-		return 0;
++	retval = -EBUSY;
 +
-+	/* sysconfig 1 */
-+	radio->registers[SYSCONFIG1] = SYSCONFIG1_DE;
-+	retval = si470x_set_register(radio, SYSCONFIG1);
-+	if (retval < 0)
++	if (locked_btres(fh->btv, VIDEO_RESOURCES)) {
++		mutex_unlock(&btv->lock);
 +		return retval;
+ 	}
+ 
+-	case VIDIOC_ENUMSTD:
+-	case VIDIOC_G_STD:
+-	case VIDIOC_S_STD:
+-	case VIDIOC_ENUMINPUT:
+-	case VIDIOC_G_INPUT:
+-	case VIDIOC_S_INPUT:
+-	case VIDIOC_G_TUNER:
+-	case VIDIOC_S_TUNER:
+-	case VIDIOC_G_FREQUENCY:
+-	case VIDIOC_S_FREQUENCY:
+-	case VIDIOC_LOG_STATUS:
+-	case VIDIOC_DBG_G_REGISTER:
+-	case VIDIOC_DBG_S_REGISTER:
+-		return bttv_common_ioctls(btv,cmd,arg);
++	b = &bttv_tvnorms[btv->tvnorm].cropcap.bounds;
+ 
+-	default:
+-		return -ENOIOCTLCMD;
++	b_left = b->left;
++	b_right = b_left + b->width;
++	b_bottom = b->top + b->height;
 +
-+	/* sysconfig 2 */
-+	radio->registers[SYSCONFIG2] =
-+		(0x3f  << 8) |	/* SEEKTH */
-+		(band  << 6) |	/* BAND */
-+		(space << 4) |	/* SPACE */
-+		15;		/* VOLUME (max) */
-+	retval = si470x_set_register(radio, SYSCONFIG2);
-+	if (retval < 0)
++	b_top = max(b->top, btv->vbi_end);
++	if (b_top + 32 >= b_bottom) {
++		mutex_unlock(&btv->lock);
 +		return retval;
+ 	}
+-	return 0;
+ 
+- fh_unlock_and_return:
+-	mutex_unlock(&fh->cap.lock);
+-	return retval;
++	/* Min. scaled size 48 x 32. */
++	c.rect.left = clamp(crop->c.left, b_left, b_right - 48);
++	c.rect.left = min(c.rect.left, (__s32) MAX_HDELAY);
+ 
+- btv_unlock_and_return:
+-	mutex_unlock(&btv->lock);
+-	return retval;
+-}
++	c.rect.width = clamp(crop->c.width,
++			     48, b_right - c.rect.left);
+ 
+-static int bttv_ioctl(struct inode *inode, struct file *file,
+-		      unsigned int cmd, unsigned long arg)
+-{
+-	struct bttv_fh *fh  = file->private_data;
++	c.rect.top = clamp(crop->c.top, b_top, b_bottom - 32);
++	/* Top and height must be a multiple of two. */
++	c.rect.top = (c.rect.top + 1) & ~1;
+ 
+-	switch (cmd) {
+-	case BTTV_VBISIZE:
+-	{
+-		const struct bttv_tvnorm *tvnorm;
++	c.rect.height = clamp(crop->c.height,
++			      32, b_bottom - c.rect.top);
++	c.rect.height = (c.rect.height + 1) & ~1;
+ 
+-		tvnorm = fh->vbi_fmt.tvnorm;
++	bttv_crop_calc_limits(&c);
+ 
+-		if (fh->vbi_fmt.fmt.start[0] != tvnorm->vbistart[0] ||
+-		    fh->vbi_fmt.fmt.start[1] != tvnorm->vbistart[1] ||
+-		    fh->vbi_fmt.fmt.count[0] != fh->vbi_fmt.fmt.count[1]) {
+-			/* BTTV_VBISIZE cannot express these parameters,
+-			   however open() resets the paramters to defaults
+-			   and apps shouldn't call BTTV_VBISIZE after
+-			   VIDIOC_S_FMT. */
+-			return -EINVAL;
+-		}
++	btv->crop[1] = c;
 +
-+	/* reset last channel */
-+	return si470x_set_chan(radio,
-+		radio->registers[CHANNEL] & CHANNEL_CHAN);
-+}
++	mutex_unlock(&btv->lock);
 +
++	fh->do_crop = 1;
+ 
+-		bttv_switch_type(fh,V4L2_BUF_TYPE_VBI_CAPTURE);
+-		return (fh->vbi_fmt.fmt.count[0] * 2
+-			* fh->vbi_fmt.fmt.samples_per_line);
++	mutex_lock(&fh->cap.lock);
 +
-+/*
-+ * si470x_stop - switch off radio
-+ */
-+static int si470x_stop(struct si470x_device *radio)
-+{
-+	int retval;
++	if (fh->width < c.min_scaled_width) {
++		fh->width = c.min_scaled_width;
++		btv->init.width = c.min_scaled_width;
++	} else if (fh->width > c.max_scaled_width) {
++		fh->width = c.max_scaled_width;
++		btv->init.width = c.max_scaled_width;
+ 	}
+ 
+-	default:
+-		return video_usercopy(inode, file, cmd, arg, bttv_do_ioctl);
++	if (fh->height < c.min_scaled_height) {
++		fh->height = c.min_scaled_height;
++		btv->init.height = c.min_scaled_height;
++	} else if (fh->height > c.max_scaled_height) {
++		fh->height = c.max_scaled_height;
++		btv->init.height = c.max_scaled_height;
+ 	}
 +
-+	/* sysconfig 1 */
-+	radio->registers[SYSCONFIG1] &= ~SYSCONFIG1_RDS;
-+	retval = si470x_set_register(radio, SYSCONFIG1);
-+	if (retval < 0)
-+		return retval;
++	mutex_unlock(&fh->cap.lock);
 +
-+	/* powercfg */
-+	radio->registers[POWERCFG] &= ~POWERCFG_DMUTE;
-+	/* POWERCFG_ENABLE has to automatically go low */
-+	radio->registers[POWERCFG] |= POWERCFG_ENABLE |	POWERCFG_DISABLE;
-+	return si470x_set_register(radio, POWERCFG);
++	return 0;
 +}
 +
-+
-+/*
-+ * si470x_rds_on - switch on rds reception
-+ */
-+static int si470x_rds_on(struct si470x_device *radio)
++static int bttv_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
 +{
-+	/* sysconfig 1 */
-+	radio->registers[SYSCONFIG1] |= SYSCONFIG1_RDS;
-+	return si470x_set_register(radio, SYSCONFIG1);
++	strcpy(a->name, "audio");
++	return 0;
 +}
 +
-+
-+
-+/**************************************************************************
-+ * RDS Driver Functions
-+ **************************************************************************/
-+
-+/*
-+ * si470x_rds - rds processing function
-+ */
-+static void si470x_rds(struct si470x_device *radio)
++static int bttv_s_audio(struct file *file, void *priv, struct v4l2_audio *a)
 +{
-+	unsigned char tmpbuf[3];
-+	unsigned char blocknum;
-+	unsigned char bler; /* rds block errors */
-+	unsigned short rds;
-+	unsigned int i;
-+
-+	/* get rds blocks */
-+	if (si470x_get_rds_registers(radio) < 0)
-+		return;
-+	if ((radio->registers[STATUSRSSI] & STATUSRSSI_RDSR) == 0) {
-+		/* No RDS group ready */
-+		return;
-+	}
-+	if ((radio->registers[STATUSRSSI] & STATUSRSSI_RDSS) == 0) {
-+		/* RDS decoder not synchronized */
-+		return;
-+	}
++	return 0;
+ }
+ 
+ static ssize_t bttv_read(struct file *file, char __user *data,
+@@ -3719,8 +3205,8 @@ static unsigned int bttv_poll(struct file *file, poll_table *wait)
+ 	}
+ 
+ 	poll_wait(file, &buf->vb.done, wait);
+-	if (buf->vb.state == STATE_DONE ||
+-	    buf->vb.state == STATE_ERROR)
++	if (buf->vb.state == VIDEOBUF_DONE ||
++	    buf->vb.state == VIDEOBUF_ERROR)
+ 		return POLLIN|POLLRDNORM;
+ 	return 0;
+ }
+@@ -3777,7 +3263,7 @@ static int bttv_open(struct inode *inode, struct file *file)
+ 			    V4L2_FIELD_SEQ_TB,
+ 			    sizeof(struct bttv_buffer),
+ 			    fh);
+-	i2c_vidiocschan(btv);
++	set_tvnorm(btv,btv->tvnorm);
+ 
+ 	btv->users++;
+ 
+@@ -3857,7 +3343,7 @@ static const struct file_operations bttv_fops =
+ 	.owner	  = THIS_MODULE,
+ 	.open	  = bttv_open,
+ 	.release  = bttv_release,
+-	.ioctl	  = bttv_ioctl,
++	.ioctl	  = video_ioctl2,
+ 	.compat_ioctl	= v4l_compat_ioctl32,
+ 	.llseek	  = no_llseek,
+ 	.read	  = bttv_read,
+@@ -3867,19 +3353,61 @@ static const struct file_operations bttv_fops =
+ 
+ static struct video_device bttv_video_template =
+ {
+-	.name     = "UNSET",
+-	.type     = VID_TYPE_CAPTURE|VID_TYPE_TUNER|
+-		    VID_TYPE_CLIPPING|VID_TYPE_SCALES,
+-	.fops     = &bttv_fops,
+-	.minor    = -1,
+-};
+-
+-static struct video_device bttv_vbi_template =
+-{
+-	.name     = "bt848/878 vbi",
+-	.type     = VID_TYPE_TUNER|VID_TYPE_TELETEXT,
+ 	.fops     = &bttv_fops,
+ 	.minor    = -1,
++	.vidioc_querycap                = bttv_querycap,
++	.vidioc_enum_fmt_cap            = bttv_enum_fmt_cap,
++	.vidioc_g_fmt_cap               = bttv_g_fmt_cap,
++	.vidioc_try_fmt_cap             = bttv_try_fmt_cap,
++	.vidioc_s_fmt_cap               = bttv_s_fmt_cap,
++	.vidioc_enum_fmt_overlay        = bttv_enum_fmt_overlay,
++	.vidioc_g_fmt_overlay           = bttv_g_fmt_overlay,
++	.vidioc_try_fmt_overlay         = bttv_try_fmt_overlay,
++	.vidioc_s_fmt_overlay           = bttv_s_fmt_overlay,
++	.vidioc_enum_fmt_vbi            = bttv_enum_fmt_vbi,
++	.vidioc_g_fmt_vbi               = bttv_g_fmt_vbi,
++	.vidioc_try_fmt_vbi             = bttv_try_fmt_vbi,
++	.vidioc_s_fmt_vbi               = bttv_s_fmt_vbi,
++	.vidioc_g_audio                 = bttv_g_audio,
++	.vidioc_s_audio                 = bttv_s_audio,
++	.vidioc_cropcap                 = bttv_cropcap,
++	.vidioc_reqbufs                 = bttv_reqbufs,
++	.vidioc_querybuf                = bttv_querybuf,
++	.vidioc_qbuf                    = bttv_qbuf,
++	.vidioc_dqbuf                   = bttv_dqbuf,
++	.vidioc_s_std                   = bttv_s_std,
++	.vidioc_enum_input              = bttv_enum_input,
++	.vidioc_g_input                 = bttv_g_input,
++	.vidioc_s_input                 = bttv_s_input,
++	.vidioc_queryctrl               = bttv_queryctrl,
++	.vidioc_g_ctrl                  = bttv_g_ctrl,
++	.vidioc_s_ctrl                  = bttv_s_ctrl,
++	.vidioc_streamon                = bttv_streamon,
++	.vidioc_streamoff               = bttv_streamoff,
++	.vidioc_g_tuner                 = bttv_g_tuner,
++	.vidioc_s_tuner                 = bttv_s_tuner,
++#ifdef CONFIG_VIDEO_V4L1_COMPAT
++	.vidiocgmbuf                    = vidiocgmbuf,
++#endif
++	.vidioc_g_crop                  = bttv_g_crop,
++	.vidioc_g_crop                  = bttv_g_crop,
++	.vidioc_s_crop                  = bttv_s_crop,
++	.vidioc_g_fbuf                  = bttv_g_fbuf,
++	.vidioc_s_fbuf                  = bttv_s_fbuf,
++	.vidioc_overlay                 = bttv_overlay,
++	.vidioc_g_priority              = bttv_g_priority,
++	.vidioc_s_priority              = bttv_s_priority,
++	.vidioc_g_parm                  = bttv_g_parm,
++	.vidioc_g_frequency             = bttv_g_frequency,
++	.vidioc_s_frequency             = bttv_s_frequency,
++	.vidioc_log_status		= bttv_log_status,
++	.vidioc_querystd		= bttv_querystd,
++#ifdef CONFIG_VIDEO_ADV_DEBUG
++	.vidioc_g_register		= bttv_g_register,
++	.vidioc_s_register		= bttv_s_register,
++#endif
++	.tvnorms                        = BTTV_NORMS,
++	.current_norm                   = V4L2_STD_PAL,
+ };
+ 
+ /* ----------------------------------------------------------------------- */
+@@ -3918,7 +3446,7 @@ static int radio_open(struct inode *inode, struct file *file)
+ 
+ static int radio_release(struct inode *inode, struct file *file)
+ {
+-	struct bttv        *btv = file->private_data;
++	struct bttv *btv = file->private_data;
+ 	struct rds_command cmd;
+ 
+ 	btv->radio_user--;
+@@ -3928,59 +3456,116 @@ static int radio_release(struct inode *inode, struct file *file)
+ 	return 0;
+ }
+ 
+-static int radio_do_ioctl(struct inode *inode, struct file *file,
+-			  unsigned int cmd, void *arg)
++static int radio_querycap(struct file *file, void *priv,
++					struct v4l2_capability *cap)
+ {
+-	struct bttv    *btv = file->private_data;
++	struct bttv_fh *fh = priv;
++	struct bttv *btv = fh->btv;
+ 
+-	switch (cmd) {
+-	case VIDIOCGCAP:
+-	{
+-		struct video_capability *cap = arg;
++	strcpy(cap->driver, "bttv");
++	strlcpy(cap->card, btv->radio_dev->name, sizeof(cap->card));
++	sprintf(cap->bus_info, "PCI:%s", pci_name(btv->c.pci));
++	cap->version = BTTV_VERSION_CODE;
++	cap->capabilities = V4L2_CAP_TUNER;
+ 
+-		memset(cap,0,sizeof(*cap));
+-		strcpy(cap->name,btv->radio_dev->name);
+-		cap->type = VID_TYPE_TUNER;
+-		cap->channels = 1;
+-		cap->audios = 1;
+-		return 0;
+-	}
++	return 0;
++}
+ 
+-	case VIDIOCGTUNER:
+-	{
+-		struct video_tuner *v = arg;
++static int radio_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
++{
++	struct bttv_fh *fh = priv;
++	struct bttv *btv = fh->btv;
+ 
+-		if(v->tuner)
+-			return -EINVAL;
+-		memset(v,0,sizeof(*v));
+-		strcpy(v->name, "Radio");
+-		bttv_call_i2c_clients(btv,cmd,v);
+-		return 0;
+-	}
+-	case VIDIOCSTUNER:
+-		/* nothing to do */
+-		return 0;
++	if (UNSET == bttv_tvcards[btv->c.type].tuner)
++		return -EINVAL;
++	if (0 != t->index)
++		return -EINVAL;
++	mutex_lock(&btv->lock);
++	memset(t, 0, sizeof(*t));
++	strcpy(t->name, "Radio");
++	t->type = V4L2_TUNER_RADIO;
+ 
+-	case BTTV_VERSION:
+-	case VIDIOCGFREQ:
+-	case VIDIOCSFREQ:
+-	case VIDIOCGAUDIO:
+-	case VIDIOCSAUDIO:
+-	case VIDIOC_LOG_STATUS:
+-	case VIDIOC_DBG_G_REGISTER:
+-	case VIDIOC_DBG_S_REGISTER:
+-		return bttv_common_ioctls(btv,cmd,arg);
++	bttv_call_i2c_clients(btv, VIDIOC_G_TUNER, t);
 +
-+	/* copy four RDS blocks to internal buffer */
-+	if (spin_trylock(&radio->lock)) {
-+		/* process each rds block */
-+		for (blocknum = 0; blocknum < 4; blocknum++) {
-+			switch (blocknum) {
-+			default:
-+				bler = (radio->registers[STATUSRSSI] &
-+						STATUSRSSI_BLERA) >> 9;
-+				rds = radio->registers[RDSA];
-+				break;
-+			case 1:
-+				bler = (radio->registers[READCHAN] &
-+						READCHAN_BLERB) >> 14;
-+				rds = radio->registers[RDSB];
-+				break;
-+			case 2:
-+				bler = (radio->registers[READCHAN] &
-+						READCHAN_BLERC) >> 12;
-+				rds = radio->registers[RDSC];
-+				break;
-+			case 3:
-+				bler = (radio->registers[READCHAN] &
-+						READCHAN_BLERD) >> 10;
-+				rds = radio->registers[RDSD];
-+				break;
-+			};
++	if (btv->audio_mode_gpio)
++		btv->audio_mode_gpio(btv, t, 0);
 +
-+			/* Fill the V4L2 RDS buffer */
-+			tmpbuf[0] = rds & 0x00ff;	/* LSB */
-+			tmpbuf[1] = (rds & 0xff00) >> 8;/* MSB */
-+			tmpbuf[2] = blocknum;		/* offset name */
-+			tmpbuf[2] |= blocknum << 3;	/* received offset */
-+			if (bler > max_rds_errors)
-+				tmpbuf[2] |= 0x80; /* uncorrectable errors */
-+			else if (bler > 0)
-+				tmpbuf[2] |= 0x40; /* corrected error(s) */
++	mutex_unlock(&btv->lock);
 +
-+			/* copy RDS block to internal buffer */
-+			for (i = 0; i < 3; i++) {
-+				radio->buffer[radio->wr_index] = tmpbuf[i];
-+				radio->wr_index++;
-+			}
++	return 0;
++}
 +
-+			/* wrap write pointer */
-+			if (radio->wr_index >= radio->buf_size)
-+				radio->wr_index = 0;
++static int radio_enum_input(struct file *file, void *priv,
++				struct v4l2_input *i)
++{
++	if (i->index != 0)
++		return -EINVAL;
 +
-+			/* check for overflow */
-+			if (radio->wr_index == radio->rd_index) {
-+				/* increment and wrap read pointer */
-+				radio->rd_index += 3;
-+				if (radio->rd_index >= radio->buf_size)
-+					radio->rd_index = 0;
-+			}
-+		}
-+		spin_unlock(&radio->lock);
-+	}
++	strcpy(i->name, "Radio");
++	 i->type = V4L2_INPUT_TYPE_TUNER;
 +
-+	/* wake up read queue */
-+	if (radio->wr_index != radio->rd_index)
-+		wake_up_interruptible(&radio->read_queue);
++	return 0;
 +}
 +
-+
-+/*
-+ * si470x_timer - rds timer function
-+ */
-+static void si470x_timer(unsigned long data)
++static int radio_g_audio(struct file *file, void *priv,
++					struct v4l2_audio *a)
 +{
-+	struct si470x_device *radio = (struct si470x_device *) data;
-+
-+	schedule_work(&radio->work);
++	memset(a, 0, sizeof(*a));
++	strcpy(a->name, "Radio");
++	return 0;
 +}
 +
-+
-+/*
-+ * si470x_work - rds work function
-+ */
-+static void si470x_work(struct work_struct *work)
++static int radio_s_tuner(struct file *file, void *priv,
++					struct v4l2_tuner *t)
 +{
-+	struct si470x_device *radio = container_of(work, struct si470x_device,
-+		work);
++	struct bttv_fh *fh = priv;
++	struct bttv *btv = fh->btv;
 +
-+	if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0)
-+		return;
++	if (0 != t->index)
++		return -EINVAL;
 +
-+	si470x_rds(radio);
-+	mod_timer(&radio->timer, jiffies + msecs_to_jiffies(rds_poll_time));
++	bttv_call_i2c_clients(btv, VIDIOC_G_TUNER, t);
++	return 0;
 +}
 +
-+
-+
-+/**************************************************************************
-+ * File Operations Interface
-+ **************************************************************************/
-+
-+/*
-+ * si470x_fops_read - read RDS data
-+ */
-+static ssize_t si470x_fops_read(struct file *file, char __user *buf,
-+		size_t count, loff_t *ppos)
++static int radio_s_audio(struct file *file, void *priv,
++					struct v4l2_audio *a)
 +{
-+	struct si470x_device *radio = video_get_drvdata(video_devdata(file));
-+	int retval = 0;
-+	unsigned int block_count = 0;
-+
-+	/* switch on rds reception */
-+	if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0) {
-+		si470x_rds_on(radio);
-+		schedule_work(&radio->work);
-+	}
-+
-+	/* block if no new data available */
-+	while (radio->wr_index == radio->rd_index) {
-+		if (file->f_flags & O_NONBLOCK)
-+			return -EWOULDBLOCK;
-+		interruptible_sleep_on(&radio->read_queue);
-+	}
-+
-+	/* calculate block count from byte count */
-+	count /= 3;
-+
-+	/* copy RDS block out of internal buffer and to user buffer */
-+	if (spin_trylock(&radio->lock)) {
-+		while (block_count < count) {
-+			if (radio->rd_index == radio->wr_index)
-+				break;
-+
-+			/* always transfer rds complete blocks */
-+			if (copy_to_user(buf,
-+					&radio->buffer[radio->rd_index], 3))
-+				/* retval = -EFAULT; */
-+				break;
-+
-+			/* increment and wrap read pointer */
-+			radio->rd_index += 3;
-+			if (radio->rd_index >= radio->buf_size)
-+				radio->rd_index = 0;
-+
-+			/* increment counters */
-+			block_count++;
-+			buf += 3;
-+			retval += 3;
-+		}
-+
-+		spin_unlock(&radio->lock);
-+	}
++	return 0;
++}
 +
-+	return retval;
++static int radio_s_input(struct file *filp, void *priv, unsigned int i)
++{
++	return 0;
 +}
 +
++static int radio_s_std(struct file *file, void *fh, v4l2_std_id *norm)
++{
++	return 0;
++}
 +
-+/*
-+ * si470x_fops_poll - poll RDS data
-+ */
-+static unsigned int si470x_fops_poll(struct file *file,
-+		struct poll_table_struct *pts)
++static int radio_queryctrl(struct file *file, void *priv,
++					struct v4l2_queryctrl *c)
 +{
-+	struct si470x_device *radio = video_get_drvdata(video_devdata(file));
++	const struct v4l2_queryctrl *ctrl;
 +
-+	/* switch on rds reception */
-+	if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0) {
-+		si470x_rds_on(radio);
-+		schedule_work(&radio->work);
-+	}
++	if (c->id <  V4L2_CID_BASE ||
++			c->id >= V4L2_CID_LASTP1)
++		return -EINVAL;
 +
-+	poll_wait(file, &radio->read_queue, pts);
++	if (c->id == V4L2_CID_AUDIO_MUTE) {
++		ctrl = ctrl_by_id(c->id);
++		*c = *ctrl;
++	} else
++		*c = no_ctl;
+ 
+-	default:
+-		return -ENOIOCTLCMD;
+-	}
+ 	return 0;
+ }
+ 
+-static int radio_ioctl(struct inode *inode, struct file *file,
+-		       unsigned int cmd, unsigned long arg)
++static int radio_g_input(struct file *filp, void *priv, unsigned int *i)
+ {
+-	return video_usercopy(inode, file, cmd, arg, radio_do_ioctl);
++	*i = 0;
++	return 0;
+ }
+ 
+ static ssize_t radio_read(struct file *file, char __user *data,
+@@ -4016,17 +3601,29 @@ static const struct file_operations radio_fops =
+ 	.open	  = radio_open,
+ 	.read     = radio_read,
+ 	.release  = radio_release,
+-	.ioctl	  = radio_ioctl,
++	.ioctl	  = video_ioctl2,
+ 	.llseek	  = no_llseek,
+ 	.poll     = radio_poll,
+ };
+ 
+ static struct video_device radio_template =
+ {
+-	.name     = "bt848/878 radio",
+-	.type     = VID_TYPE_TUNER,
+ 	.fops     = &radio_fops,
+ 	.minor    = -1,
++	.vidioc_querycap        = radio_querycap,
++	.vidioc_g_tuner         = radio_g_tuner,
++	.vidioc_enum_input      = radio_enum_input,
++	.vidioc_g_audio         = radio_g_audio,
++	.vidioc_s_tuner         = radio_s_tuner,
++	.vidioc_s_audio         = radio_s_audio,
++	.vidioc_s_input         = radio_s_input,
++	.vidioc_s_std           = radio_s_std,
++	.vidioc_queryctrl       = radio_queryctrl,
++	.vidioc_g_input         = radio_g_input,
++	.vidioc_g_ctrl          = bttv_g_ctrl,
++	.vidioc_s_ctrl          = bttv_s_ctrl,
++	.vidioc_g_frequency     = bttv_g_frequency,
++	.vidioc_s_frequency     = bttv_s_frequency,
+ };
+ 
+ /* ----------------------------------------------------------------------- */
+@@ -4308,20 +3905,20 @@ static void bttv_irq_timeout(unsigned long data)
+ 	bttv_set_dma(btv, 0);
+ 
+ 	/* wake up */
+-	bttv_irq_wakeup_video(btv, &old, &new, STATE_ERROR);
+-	bttv_irq_wakeup_vbi(btv, ovbi, STATE_ERROR);
++	bttv_irq_wakeup_video(btv, &old, &new, VIDEOBUF_ERROR);
++	bttv_irq_wakeup_vbi(btv, ovbi, VIDEOBUF_ERROR);
+ 
+ 	/* cancel all outstanding capture / vbi requests */
+ 	while (!list_empty(&btv->capture)) {
+ 		item = list_entry(btv->capture.next, struct bttv_buffer, vb.queue);
+ 		list_del(&item->vb.queue);
+-		item->vb.state = STATE_ERROR;
++		item->vb.state = VIDEOBUF_ERROR;
+ 		wake_up(&item->vb.done);
+ 	}
+ 	while (!list_empty(&btv->vcapture)) {
+ 		item = list_entry(btv->vcapture.next, struct bttv_buffer, vb.queue);
+ 		list_del(&item->vb.queue);
+-		item->vb.state = STATE_ERROR;
++		item->vb.state = VIDEOBUF_ERROR;
+ 		wake_up(&item->vb.done);
+ 	}
+ 
+@@ -4344,7 +3941,7 @@ bttv_irq_wakeup_top(struct bttv *btv)
+ 
+ 	do_gettimeofday(&wakeup->vb.ts);
+ 	wakeup->vb.field_count = btv->field_count;
+-	wakeup->vb.state = STATE_DONE;
++	wakeup->vb.state = VIDEOBUF_DONE;
+ 	wake_up(&wakeup->vb.done);
+ 	spin_unlock(&btv->s_lock);
+ }
+@@ -4393,7 +3990,7 @@ bttv_irq_switch_video(struct bttv *btv)
+ 	}
+ 
+ 	/* wake up finished buffers */
+-	bttv_irq_wakeup_video(btv, &old, &new, STATE_DONE);
++	bttv_irq_wakeup_video(btv, &old, &new, VIDEOBUF_DONE);
+ 	spin_unlock(&btv->s_lock);
+ }
+ 
+@@ -4426,7 +4023,7 @@ bttv_irq_switch_vbi(struct bttv *btv)
+ 	bttv_buffer_activate_vbi(btv, new);
+ 	bttv_set_dma(btv, 0);
+ 
+-	bttv_irq_wakeup_vbi(btv, old, STATE_DONE);
++	bttv_irq_wakeup_vbi(btv, old, VIDEOBUF_DONE);
+ 	spin_unlock(&btv->s_lock);
+ }
+ 
+@@ -4548,8 +4145,9 @@ static irqreturn_t bttv_irq(int irq, void *dev_id)
+ /* initialitation                                                          */
+ 
+ static struct video_device *vdev_init(struct bttv *btv,
+-				      struct video_device *template,
+-				      char *type)
++				      const struct video_device *template,
++				      const char *type_name,
++				      const int type)
+ {
+ 	struct video_device *vfd;
+ 
+@@ -4560,9 +4158,10 @@ static struct video_device *vdev_init(struct bttv *btv,
+ 	vfd->minor   = -1;
+ 	vfd->dev     = &btv->c.pci->dev;
+ 	vfd->release = video_device_release;
++	vfd->type    = type;
+ 	snprintf(vfd->name, sizeof(vfd->name), "BT%d%s %s (%s)",
+ 		 btv->id, (btv->id==848 && btv->revision==0x12) ? "A" : "",
+-		 type, bttv_tvcards[btv->c.type].name);
++		 type_name, bttv_tvcards[btv->c.type].name);
+ 	return vfd;
+ }
+ 
+@@ -4594,6 +4193,11 @@ static void bttv_unregister_video(struct bttv *btv)
+ /* register video4linux devices */
+ static int __devinit bttv_register_video(struct bttv *btv)
+ {
++	int video_type = VID_TYPE_CAPTURE |
++			 VID_TYPE_TUNER   |
++			 VID_TYPE_CLIPPING|
++			 VID_TYPE_SCALES;
 +
-+	if (radio->rd_index != radio->wr_index)
-+		return POLLIN | POLLRDNORM;
+ 	if (no_overlay <= 0) {
+ 		bttv_video_template.type |= VID_TYPE_OVERLAY;
+ 	} else {
+@@ -4601,7 +4205,9 @@ static int __devinit bttv_register_video(struct bttv *btv)
+ 	}
+ 
+ 	/* video */
+-	btv->video_dev = vdev_init(btv, &bttv_video_template, "video");
++	btv->video_dev = vdev_init(btv, &bttv_video_template,
++				   "video", video_type);
 +
-+	return 0;
-+}
+ 	if (NULL == btv->video_dev)
+ 		goto err;
+ 	if (video_register_device(btv->video_dev,VFL_TYPE_GRABBER,video_nr)<0)
+@@ -4616,7 +4222,9 @@ static int __devinit bttv_register_video(struct bttv *btv)
+ 	}
+ 
+ 	/* vbi */
+-	btv->vbi_dev = vdev_init(btv, &bttv_vbi_template, "vbi");
++	btv->vbi_dev = vdev_init(btv, &bttv_video_template,
++				 "vbi", VID_TYPE_TUNER | VID_TYPE_TELETEXT);
 +
+ 	if (NULL == btv->vbi_dev)
+ 		goto err;
+ 	if (video_register_device(btv->vbi_dev,VFL_TYPE_VBI,vbi_nr)<0)
+@@ -4627,7 +4235,8 @@ static int __devinit bttv_register_video(struct bttv *btv)
+ 	if (!btv->has_radio)
+ 		return 0;
+ 	/* radio */
+-	btv->radio_dev = vdev_init(btv, &radio_template, "radio");
++	btv->radio_dev = vdev_init(btv, &radio_template,
++				   "radio", VID_TYPE_TUNER);
+ 	if (NULL == btv->radio_dev)
+ 		goto err;
+ 	if (video_register_device(btv->radio_dev, VFL_TYPE_RADIO,radio_nr)<0)
+@@ -4768,7 +4377,7 @@ static int __devinit bttv_probe(struct pci_dev *dev,
+ 	btv->init.btv         = btv;
+ 	btv->init.ov.w.width  = 320;
+ 	btv->init.ov.w.height = 240;
+-	btv->init.fmt         = format_by_palette(VIDEO_PALETTE_RGB24);
++	btv->init.fmt         = format_by_fourcc(V4L2_PIX_FMT_BGR24);
+ 	btv->init.width       = 320;
+ 	btv->init.height      = 240;
+ 	btv->input = 0;
+@@ -5013,14 +4622,17 @@ static int __init bttv_init_module(void)
+ 		printk(KERN_WARNING "bttv: bus_register error: %d\n", ret);
+ 		return ret;
+ 	}
+-	return pci_register_driver(&bttv_pci_driver);
++	ret = pci_register_driver(&bttv_pci_driver);
++	if (ret < 0)
++		bus_unregister(&bttv_sub_bus_type);
 +
-+/*
-+ * si470x_fops_open - file open
-+ */
-+static int si470x_fops_open(struct inode *inode, struct file *file)
-+{
-+	struct si470x_device *radio = video_get_drvdata(video_devdata(file));
++	return ret;
+ }
+ 
+ static void __exit bttv_cleanup_module(void)
+ {
+ 	pci_unregister_driver(&bttv_pci_driver);
+ 	bus_unregister(&bttv_sub_bus_type);
+-	return;
+ }
+ 
+ module_init(bttv_init_module);
+diff --git a/drivers/media/video/bt8xx/bttv-input.c b/drivers/media/video/bt8xx/bttv-input.c
+index e7c521b..fc9ecb2 100644
+--- a/drivers/media/video/bt8xx/bttv-input.c
++++ b/drivers/media/video/bt8xx/bttv-input.c
+@@ -69,6 +69,11 @@ static void ir_handle_key(struct bttv *btv)
+ 	    (ir->mask_keyup    &&  (0 == (gpio & ir->mask_keyup)))) {
+ 		ir_input_keydown(ir->dev,&ir->ir,data,data);
+ 	} else {
++		/* HACK: Probably, ir->mask_keydown is missing
++		   for this board */
++		if (btv->c.type == BTTV_BOARD_WINFAST2000)
++			ir_input_keydown(ir->dev, &ir->ir, data, data);
++
+ 		ir_input_nokey(ir->dev,&ir->ir);
+ 	}
+ 
+diff --git a/drivers/media/video/bt8xx/bttv-risc.c b/drivers/media/video/bt8xx/bttv-risc.c
+index 58986f1..e5979f7 100644
+--- a/drivers/media/video/bt8xx/bttv-risc.c
++++ b/drivers/media/video/bt8xx/bttv-risc.c
+@@ -582,7 +582,7 @@ bttv_dma_free(struct videobuf_queue *q,struct bttv *btv, struct bttv_buffer *buf
+ 	videobuf_dma_free(dma);
+ 	btcx_riscmem_free(btv->c.pci,&buf->bottom);
+ 	btcx_riscmem_free(btv->c.pci,&buf->top);
+-	buf->vb.state = STATE_NEEDS_INIT;
++	buf->vb.state = VIDEOBUF_NEEDS_INIT;
+ }
+ 
+ int
+@@ -602,7 +602,7 @@ bttv_buffer_activate_vbi(struct bttv *btv,
+ 	if (vbi) {
+ 		unsigned int crop, vdelay;
+ 
+-		vbi->vb.state = STATE_ACTIVE;
++		vbi->vb.state = VIDEOBUF_ACTIVE;
+ 		list_del(&vbi->vb.queue);
+ 
+ 		/* VDELAY is start of video, end of VBI capturing. */
+@@ -644,12 +644,12 @@ bttv_buffer_activate_video(struct bttv *btv,
+ 	/* video capture */
+ 	if (NULL != set->top  &&  NULL != set->bottom) {
+ 		if (set->top == set->bottom) {
+-			set->top->vb.state    = STATE_ACTIVE;
++			set->top->vb.state    = VIDEOBUF_ACTIVE;
+ 			if (set->top->vb.queue.next)
+ 				list_del(&set->top->vb.queue);
+ 		} else {
+-			set->top->vb.state    = STATE_ACTIVE;
+-			set->bottom->vb.state = STATE_ACTIVE;
++			set->top->vb.state    = VIDEOBUF_ACTIVE;
++			set->bottom->vb.state = VIDEOBUF_ACTIVE;
+ 			if (set->top->vb.queue.next)
+ 				list_del(&set->top->vb.queue);
+ 			if (set->bottom->vb.queue.next)
+@@ -666,7 +666,7 @@ bttv_buffer_activate_video(struct bttv *btv,
+ 		btaor((set->top->btswap & 0x0a) | (set->bottom->btswap & 0x05),
+ 		      ~0x0f, BT848_COLOR_CTL);
+ 	} else if (NULL != set->top) {
+-		set->top->vb.state  = STATE_ACTIVE;
++		set->top->vb.state  = VIDEOBUF_ACTIVE;
+ 		if (set->top->vb.queue.next)
+ 			list_del(&set->top->vb.queue);
+ 		bttv_apply_geo(btv, &set->top->geo,1);
+@@ -677,7 +677,7 @@ bttv_buffer_activate_video(struct bttv *btv,
+ 		btaor(set->top->btformat & 0xff, ~0xff, BT848_COLOR_FMT);
+ 		btaor(set->top->btswap & 0x0f,   ~0x0f, BT848_COLOR_CTL);
+ 	} else if (NULL != set->bottom) {
+-		set->bottom->vb.state = STATE_ACTIVE;
++		set->bottom->vb.state = VIDEOBUF_ACTIVE;
+ 		if (set->bottom->vb.queue.next)
+ 			list_del(&set->bottom->vb.queue);
+ 		bttv_apply_geo(btv, &set->bottom->geo,1);
+diff --git a/drivers/media/video/bt8xx/bttv-vbi.c b/drivers/media/video/bt8xx/bttv-vbi.c
+index 346ce01..1f0cc79 100644
+--- a/drivers/media/video/bt8xx/bttv-vbi.c
++++ b/drivers/media/video/bt8xx/bttv-vbi.c
+@@ -142,7 +142,7 @@ static int vbi_buffer_prepare(struct videobuf_queue *q,
+ 		redo_dma_risc = 1;
+ 	}
+ 
+-	if (STATE_NEEDS_INIT == buf->vb.state) {
++	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
+ 		redo_dma_risc = 1;
+ 		if (0 != (rc = videobuf_iolock(q, &buf->vb, NULL)))
+ 			goto fail;
+@@ -189,7 +189,7 @@ static int vbi_buffer_prepare(struct videobuf_queue *q,
+ 	/* For bttv_buffer_activate_vbi(). */
+ 	buf->geo.vdelay = min_vdelay;
+ 
+-	buf->vb.state = STATE_PREPARED;
++	buf->vb.state = VIDEOBUF_PREPARED;
+ 	buf->vb.field = field;
+ 	dprintk("buf prepare %p: top=%p bottom=%p field=%s\n",
+ 		vb, &buf->top, &buf->bottom,
+@@ -209,7 +209,7 @@ vbi_buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
+ 	struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb);
+ 
+ 	dprintk("queue %p\n",vb);
+-	buf->vb.state = STATE_QUEUED;
++	buf->vb.state = VIDEOBUF_QUEUED;
+ 	list_add_tail(&buf->vb.queue,&btv->vcapture);
+ 	if (NULL == btv->cvbi) {
+ 		fh->btv->loop_irq |= 4;
+@@ -236,10 +236,8 @@ struct videobuf_queue_ops bttv_vbi_qops = {
+ 
+ /* ----------------------------------------------------------------------- */
+ 
+-static int
+-try_fmt			(struct v4l2_vbi_format *	f,
+-			 const struct bttv_tvnorm *	tvnorm,
+-			 __s32				crop_start)
++static int try_fmt(struct v4l2_vbi_format *f, const struct bttv_tvnorm *tvnorm,
++			__s32 crop_start)
+ {
+ 	__s32 min_start, max_start, max_end, f2_offset;
+ 	unsigned int i;
+@@ -305,10 +303,9 @@ try_fmt			(struct v4l2_vbi_format *	f,
+ 	return 0;
+ }
+ 
+-int
+-bttv_vbi_try_fmt	(struct bttv_fh *		fh,
+-			 struct v4l2_vbi_format *	f)
++int bttv_try_fmt_vbi(struct file *file, void *f, struct v4l2_format *frt)
+ {
++	struct bttv_fh *fh = f;
+ 	struct bttv *btv = fh->btv;
+ 	const struct bttv_tvnorm *tvnorm;
+ 	__s32 crop_start;
+@@ -320,13 +317,13 @@ bttv_vbi_try_fmt	(struct bttv_fh *		fh,
+ 
+ 	mutex_unlock(&btv->lock);
+ 
+-	return try_fmt(f, tvnorm, crop_start);
++	return try_fmt(&frt->fmt.vbi, tvnorm, crop_start);
+ }
+ 
+-int
+-bttv_vbi_set_fmt	(struct bttv_fh *		fh,
+-			 struct v4l2_vbi_format *	f)
 +
-+	radio->users++;
-+	if (radio->users == 1)
-+		return si470x_start(radio);
++int bttv_s_fmt_vbi(struct file *file, void *f, struct v4l2_format *frt)
+ {
++	struct bttv_fh *fh = f;
+ 	struct bttv *btv = fh->btv;
+ 	const struct bttv_tvnorm *tvnorm;
+ 	__s32 start1, end;
+@@ -340,11 +337,12 @@ bttv_vbi_set_fmt	(struct bttv_fh *		fh,
+ 
+ 	tvnorm = &bttv_tvnorms[btv->tvnorm];
+ 
+-	rc = try_fmt(f, tvnorm, btv->crop_start);
++	rc = try_fmt(&frt->fmt.vbi, tvnorm, btv->crop_start);
+ 	if (0 != rc)
+ 		goto fail;
+ 
+-	start1 = f->start[1] - tvnorm->vbistart[1] + tvnorm->vbistart[0];
++	start1 = frt->fmt.vbi.start[1] - tvnorm->vbistart[1] +
++		tvnorm->vbistart[0];
+ 
+ 	/* First possible line of video capturing. Should be
+ 	   max(f->start[0] + f->count[0], start1 + f->count[1]) * 2
+@@ -352,11 +350,11 @@ bttv_vbi_set_fmt	(struct bttv_fh *		fh,
+ 	   pretend the VBI and video capture window may overlap,
+ 	   so end = start + 1, the lowest possible value, times two
+ 	   because vbi_fmt.end counts field lines times two. */
+-	end = max(f->start[0], start1) * 2 + 2;
++	end = max(frt->fmt.vbi.start[0], start1) * 2 + 2;
+ 
+ 	mutex_lock(&fh->vbi.lock);
+ 
+-	fh->vbi_fmt.fmt    = *f;
++	fh->vbi_fmt.fmt    = frt->fmt.vbi;
+ 	fh->vbi_fmt.tvnorm = tvnorm;
+ 	fh->vbi_fmt.end    = end;
+ 
+@@ -370,13 +368,13 @@ bttv_vbi_set_fmt	(struct bttv_fh *		fh,
+ 	return rc;
+ }
+ 
+-void
+-bttv_vbi_get_fmt	(struct bttv_fh *		fh,
+-			 struct v4l2_vbi_format *	f)
 +
++int bttv_g_fmt_vbi(struct file *file, void *f, struct v4l2_format *frt)
+ {
++	struct bttv_fh *fh = f;
+ 	const struct bttv_tvnorm *tvnorm;
+ 
+-	*f = fh->vbi_fmt.fmt;
++	frt->fmt.vbi = fh->vbi_fmt.fmt;
+ 
+ 	tvnorm = &bttv_tvnorms[fh->btv->tvnorm];
+ 
+@@ -391,28 +389,28 @@ bttv_vbi_get_fmt	(struct bttv_fh *		fh,
+ 		max_end = (tvnorm->cropcap.bounds.top
+ 			   + tvnorm->cropcap.bounds.height) >> 1;
+ 
+-		f->sampling_rate = tvnorm->Fsc;
++		frt->fmt.vbi.sampling_rate = tvnorm->Fsc;
+ 
+ 		for (i = 0; i < 2; ++i) {
+ 			__s32 new_start;
+ 
+-			new_start = f->start[i]
++			new_start = frt->fmt.vbi.start[i]
+ 				+ tvnorm->vbistart[i]
+ 				- fh->vbi_fmt.tvnorm->vbistart[i];
+ 
+-			f->start[i] = min(new_start, max_end - 1);
+-			f->count[i] = min((__s32) f->count[i],
+-					  max_end - f->start[i]);
++			frt->fmt.vbi.start[i] = min(new_start, max_end - 1);
++			frt->fmt.vbi.count[i] =
++				min((__s32) frt->fmt.vbi.count[i],
++					  max_end - frt->fmt.vbi.start[i]);
+ 
+ 			max_end += tvnorm->vbistart[1]
+ 				- tvnorm->vbistart[0];
+ 		}
+ 	}
 +	return 0;
-+}
-+
-+
-+/*
-+ * si470x_fops_release - file release
-+ */
-+static int si470x_fops_release(struct inode *inode, struct file *file)
-+{
-+	struct si470x_device *radio = video_get_drvdata(video_devdata(file));
-+
-+	if (!radio)
-+		return -ENODEV;
-+
-+	radio->users--;
-+	if (radio->users == 0) {
-+		/* stop rds reception */
-+		del_timer_sync(&radio->timer);
-+		flush_scheduled_work();
+ }
+ 
+-void
+-bttv_vbi_fmt_reset	(struct bttv_vbi_fmt *		f,
+-			 int				norm)
++void bttv_vbi_fmt_reset(struct bttv_vbi_fmt *f, int norm)
+ {
+ 	const struct bttv_tvnorm *tvnorm;
+ 	unsigned int real_samples_per_line;
+diff --git a/drivers/media/video/bt8xx/bttv.h b/drivers/media/video/bt8xx/bttv.h
+index 19e75d5..bf4c339 100644
+--- a/drivers/media/video/bt8xx/bttv.h
++++ b/drivers/media/video/bt8xx/bttv.h
+@@ -241,7 +241,10 @@ struct tvcard
+ 	unsigned int radio_addr;
+ 
+ 	unsigned int has_radio;
+-	void (*audio_hook)(struct bttv *btv, struct video_audio *v, int set);
 +
-+		/* cancel read processes */
-+		wake_up_interruptible(&radio->read_queue);
++	void (*volume_gpio)(struct bttv *btv, __u16 volume);
++	void (*audio_mode_gpio)(struct bttv *btv, struct v4l2_tuner *tuner, int set);
 +
-+		return si470x_stop(radio);
-+	}
+ 	void (*muxsel_hook)(struct bttv *btv, unsigned int input);
+ };
+ 
+diff --git a/drivers/media/video/bt8xx/bttvp.h b/drivers/media/video/bt8xx/bttvp.h
+index d4ac4c4..1305d31 100644
+--- a/drivers/media/video/bt8xx/bttvp.h
++++ b/drivers/media/video/bt8xx/bttvp.h
+@@ -84,6 +84,11 @@
+ 
+ #define clamp(x, low, high) min (max (low, x), high)
+ 
++#define BTTV_NORMS    (\
++		V4L2_STD_PAL    | V4L2_STD_PAL_N | \
++		V4L2_STD_PAL_Nc | V4L2_STD_SECAM | \
++		V4L2_STD_NTSC   | V4L2_STD_PAL_M | \
++		V4L2_STD_PAL_60)
+ /* ---------------------------------------------------------- */
+ 
+ struct bttv_tvnorm {
+@@ -112,7 +117,6 @@ extern const struct bttv_tvnorm bttv_tvnorms[];
+ 
+ struct bttv_format {
+ 	char *name;
+-	int  palette;         /* video4linux 1      */
+ 	int  fourcc;          /* video4linux 2      */
+ 	int  btformat;        /* BT848_COLOR_FMT_*  */
+ 	int  btswap;          /* BT848_COLOR_CTL_*  */
+@@ -253,9 +257,9 @@ int bttv_overlay_risc(struct bttv *btv, struct bttv_overlay *ov,
+ /* ---------------------------------------------------------- */
+ /* bttv-vbi.c                                                 */
+ 
+-int bttv_vbi_try_fmt(struct bttv_fh *fh, struct v4l2_vbi_format *f);
+-void bttv_vbi_get_fmt(struct bttv_fh *fh, struct v4l2_vbi_format *f);
+-int bttv_vbi_set_fmt(struct bttv_fh *fh, struct v4l2_vbi_format *f);
++int bttv_try_fmt_vbi(struct file *file, void *fh, struct v4l2_format *f);
++int bttv_g_fmt_vbi(struct file *file, void *fh, struct v4l2_format *f);
++int bttv_s_fmt_vbi(struct file *file, void *fh, struct v4l2_format *f);
+ 
+ extern struct videobuf_queue_ops bttv_vbi_qops;
+ 
+@@ -337,7 +341,9 @@ struct bttv {
+ 	/* old gpio interface */
+ 	wait_queue_head_t gpioq;
+ 	int shutdown;
+-	void (*audio_hook)(struct bttv *btv, struct video_audio *v, int set);
 +
-+	return 0;
-+}
++	void (*volume_gpio)(struct bttv *btv, __u16 volume);
++	void (*audio_mode_gpio)(struct bttv *btv, struct v4l2_tuner *tuner, int set);
+ 
+ 	/* new gpio interface */
+ 	spinlock_t gpio_lock;
+@@ -458,10 +464,6 @@ struct bttv {
+ extern unsigned int bttv_num;
+ extern struct bttv bttvs[BTTV_MAX];
+ 
+-/* private ioctls */
+-#define BTTV_VERSION            _IOR('v' , BASE_VIDIOCPRIVATE+6, int)
+-#define BTTV_VBISIZE            _IOR('v' , BASE_VIDIOCPRIVATE+8, int)
+-
+ #endif
+ 
+ #define btwrite(dat,adr)    writel((dat), btv->bt848_mmio+(adr))
+diff --git a/drivers/media/video/bw-qcam.c b/drivers/media/video/bw-qcam.c
+index 5842352..0322653 100644
+--- a/drivers/media/video/bw-qcam.c
++++ b/drivers/media/video/bw-qcam.c
+@@ -82,11 +82,16 @@ OTHER DEALINGS IN THE SOFTWARE.
+ static unsigned int maxpoll=250;   /* Maximum busy-loop count for qcam I/O */
+ static unsigned int yieldlines=4;  /* Yield after this many during capture */
+ static int video_nr = -1;
++static unsigned int force_init;		/* Whether to probe aggressively */
+ 
+ module_param(maxpoll, int, 0);
+ module_param(yieldlines, int, 0);
+ module_param(video_nr, int, 0);
+ 
++/* Set force_init=1 to avoid detection by polling status register and
++ * immediately attempt to initialize qcam */
++module_param(force_init, int, 0);
 +
+ static inline int read_lpstatus(struct qcam_device *q)
+ {
+ 	return parport_read_status(q->pport);
+@@ -331,6 +336,9 @@ static int qc_detect(struct qcam_device *q)
+ 	int count = 0;
+ 	int i;
+ 
++	if (force_init)
++		return 1;
 +
+ 	lastreg = reg = read_lpstatus(q) & 0xf0;
+ 
+ 	for (i = 0; i < 500; i++)
+@@ -354,12 +362,12 @@ static int qc_detect(struct qcam_device *q)
+ 
+ 	/* Be (even more) liberal in what you accept...  */
+ 
+-/*	if (count > 30 && count < 200) */
+ 	if (count > 20 && count < 400) {
+ 		return 1;	/* found */
+ 	} else {
+ 		printk(KERN_ERR "No Quickcam found on port %s\n",
+ 			q->pport->name);
++		printk(KERN_DEBUG "Quickcam detection counter: %u\n", count);
+ 		return 0;	/* not found */
+ 	}
+ }
+diff --git a/drivers/media/video/cs5345.c b/drivers/media/video/cs5345.c
+new file mode 100644
+index 0000000..fae469c
+--- /dev/null
++++ b/drivers/media/video/cs5345.c
+@@ -0,0 +1,168 @@
 +/*
-+ * si470x_fops - file operations interface
++ * cs5345 Cirrus Logic 24-bit, 192 kHz Stereo Audio ADC
++ * Copyright (C) 2007 Hans Verkuil
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You 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.
 + */
-+static const struct file_operations si470x_fops = {
-+	.owner		= THIS_MODULE,
-+	.llseek		= no_llseek,
-+	.read		= si470x_fops_read,
-+	.poll		= si470x_fops_poll,
-+	.ioctl		= video_ioctl2,
-+	.compat_ioctl	= v4l_compat_ioctl32,
-+	.open		= si470x_fops_open,
-+	.release	= si470x_fops_release,
-+};
 +
 +
++#include <linux/version.h>
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/i2c.h>
++#include <linux/videodev2.h>
++#include <media/v4l2-i2c-drv.h>
++#include <media/v4l2-common.h>
++#include <media/v4l2-chip-ident.h>
 +
-+/**************************************************************************
-+ * Video4Linux Interface
-+ **************************************************************************/
++MODULE_DESCRIPTION("i2c device driver for cs5345 Audio ADC");
++MODULE_AUTHOR("Hans Verkuil");
++MODULE_LICENSE("GPL");
 +
-+/*
-+ * si470x_v4l2_queryctrl - query control
-+ */
-+static struct v4l2_queryctrl si470x_v4l2_queryctrl[] = {
-+/* HINT: the disabled controls are only here to satify kradio and such apps */
-+	{
-+		.id		= V4L2_CID_AUDIO_VOLUME,
-+		.type		= V4L2_CTRL_TYPE_INTEGER,
-+		.name		= "Volume",
-+		.minimum	= 0,
-+		.maximum	= 15,
-+		.step		= 1,
-+		.default_value	= 15,
-+	},
-+	{
-+		.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_MUTE,
-+		.type		= V4L2_CTRL_TYPE_BOOLEAN,
-+		.name		= "Mute",
-+		.minimum	= 0,
-+		.maximum	= 1,
-+		.step		= 1,
-+		.default_value	= 1,
-+	},
-+	{
-+		.id		= V4L2_CID_AUDIO_LOUDNESS,
-+		.flags		= V4L2_CTRL_FLAG_DISABLED,
-+	},
-+};
++static int debug;
 +
++module_param(debug, bool, 0644);
 +
-+/*
-+ * si470x_vidioc_querycap - query device capabilities
-+ */
-+static int si470x_vidioc_querycap(struct file *file, void *priv,
-+		struct v4l2_capability *capability)
-+{
-+	strlcpy(capability->driver, DRIVER_NAME, sizeof(capability->driver));
-+	strlcpy(capability->card, DRIVER_CARD, sizeof(capability->card));
-+	sprintf(capability->bus_info, "USB");
-+	capability->version = DRIVER_VERSION;
-+	capability->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
++MODULE_PARM_DESC(debug, "Debugging messages\n\t\t\t0=Off (default), 1=On");
 +
-+	return 0;
-+}
 +
++/* ----------------------------------------------------------------------- */
 +
-+/*
-+ * si470x_vidioc_g_input - get input
-+ */
-+static int si470x_vidioc_g_input(struct file *filp, void *priv,
-+		unsigned int *i)
++static inline int cs5345_write(struct i2c_client *client, u8 reg, u8 value)
 +{
-+	*i = 0;
-+
-+	return 0;
++	return i2c_smbus_write_byte_data(client, reg, value);
 +}
 +
-+
-+/*
-+ * si470x_vidioc_s_input - set input
-+ */
-+static int si470x_vidioc_s_input(struct file *filp, void *priv, unsigned int i)
++static inline int cs5345_read(struct i2c_client *client, u8 reg)
 +{
-+	if (i != 0)
-+		return -EINVAL;
-+
-+	return 0;
++	return i2c_smbus_read_byte_data(client, reg);
 +}
 +
-+
-+/*
-+ * si470x_vidioc_queryctrl - enumerate control items
-+ */
-+static int si470x_vidioc_queryctrl(struct file *file, void *priv,
-+		struct v4l2_queryctrl *qc)
++static int cs5345_command(struct i2c_client *client, unsigned cmd, void *arg)
 +{
-+	int i;
-+
-+	for (i = 0; i < ARRAY_SIZE(si470x_v4l2_queryctrl); i++) {
-+		if (qc->id && qc->id == si470x_v4l2_queryctrl[i].id) {
-+			memcpy(qc, &(si470x_v4l2_queryctrl[i]), sizeof(*qc));
-+			return 0;
-+		}
-+	}
++	struct v4l2_routing *route = arg;
++	struct v4l2_control *ctrl = arg;
 +
-+	return -EINVAL;
-+}
++	switch (cmd) {
++	case VIDIOC_INT_G_AUDIO_ROUTING:
++		route->input = cs5345_read(client, 0x09) & 7;
++		route->input |= cs5345_read(client, 0x05) & 0x70;
++		route->output = 0;
++		break;
 +
++	case VIDIOC_INT_S_AUDIO_ROUTING:
++		if ((route->input & 0xf) > 6) {
++			v4l_err(client, "Invalid input %d.\n", route->input);
++			return -EINVAL;
++		}
++		cs5345_write(client, 0x09, route->input & 0xf);
++		cs5345_write(client, 0x05, route->input & 0xf0);
++		break;
 +
-+/*
-+ * si470x_vidioc_g_ctrl - get the value of a control
-+ */
-+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));
++	case VIDIOC_G_CTRL:
++		if (ctrl->id == V4L2_CID_AUDIO_MUTE) {
++			ctrl->value = (cs5345_read(client, 0x04) & 0x08) != 0;
++			break;
++		}
++		if (ctrl->id != V4L2_CID_AUDIO_VOLUME)
++			return -EINVAL;
++		ctrl->value = cs5345_read(client, 0x07) & 0x3f;
++		if (ctrl->value >= 32)
++			ctrl->value = ctrl->value - 64;
++		break;
 +
-+	switch (ctrl->id) {
-+	case V4L2_CID_AUDIO_VOLUME:
-+		ctrl->value = radio->registers[SYSCONFIG2] &
-+				SYSCONFIG2_VOLUME;
++	case VIDIOC_S_CTRL:
 +		break;
-+	case V4L2_CID_AUDIO_MUTE:
-+		ctrl->value = ((radio->registers[POWERCFG] &
-+				POWERCFG_DMUTE) == 0) ? 1 : 0;
++		if (ctrl->id == V4L2_CID_AUDIO_MUTE) {
++			cs5345_write(client, 0x04, ctrl->value ? 0x80 : 0);
++			break;
++		}
++		if (ctrl->id != V4L2_CID_AUDIO_VOLUME)
++			return -EINVAL;
++		if (ctrl->value > 24 || ctrl->value < -24)
++			return -EINVAL;
++		cs5345_write(client, 0x07, ((u8)ctrl->value) & 0x3f);
++		cs5345_write(client, 0x08, ((u8)ctrl->value) & 0x3f);
 +		break;
-+	}
-+
-+	return 0;
-+}
 +
++#ifdef CONFIG_VIDEO_ADV_DEBUG
++	case VIDIOC_DBG_G_REGISTER:
++	case VIDIOC_DBG_S_REGISTER:
++	{
++		struct v4l2_register *reg = arg;
 +
-+/*
-+ * si470x_vidioc_s_ctrl - set the value of a control
-+ */
-+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));
-+
-+	switch (ctrl->id) {
-+	case V4L2_CID_AUDIO_VOLUME:
-+		radio->registers[SYSCONFIG2] &= ~SYSCONFIG2_VOLUME;
-+		radio->registers[SYSCONFIG2] |= ctrl->value;
-+		return si470x_set_register(radio, SYSCONFIG2);
-+	case V4L2_CID_AUDIO_MUTE:
-+		if (ctrl->value == 1)
-+			radio->registers[POWERCFG] &= ~POWERCFG_DMUTE;
++		if (!v4l2_chip_match_i2c_client(client,
++					reg->match_type, reg->match_chip))
++			return -EINVAL;
++		if (!capable(CAP_SYS_ADMIN))
++			return -EPERM;
++		if (cmd == VIDIOC_DBG_G_REGISTER)
++			reg->val = cs5345_read(client, reg->reg & 0x1f);
 +		else
-+			radio->registers[POWERCFG] |= POWERCFG_DMUTE;
-+		return si470x_set_register(radio, POWERCFG);
++			cs5345_write(client, reg->reg & 0x1f, reg->val & 0x1f);
++		break;
 +	}
++#endif
 +
-+	return -EINVAL;
-+}
-+
-+
-+/*
-+ * si470x_vidioc_g_audio - get audio attributes
-+ */
-+static int si470x_vidioc_g_audio(struct file *file, void *priv,
-+		struct v4l2_audio *audio)
-+{
-+	if (audio->index > 1)
-+		return -EINVAL;
-+
-+	strcpy(audio->name, "Radio");
-+	audio->capability = V4L2_AUDCAP_STEREO;
-+
-+	return 0;
-+}
-+
-+
-+/*
-+ * si470x_vidioc_s_audio - set audio attributes
-+ */
-+static int si470x_vidioc_s_audio(struct file *file, void *priv,
-+		struct v4l2_audio *audio)
-+{
-+	if (audio->index != 0)
-+		return -EINVAL;
-+
-+	return 0;
-+}
-+
-+
-+/*
-+ * si470x_vidioc_g_tuner - get tuner attributes
-+ */
-+static int si470x_vidioc_g_tuner(struct file *file, void *priv,
-+		struct v4l2_tuner *tuner)
-+{
-+	int retval;
-+	struct si470x_device *radio = video_get_drvdata(video_devdata(file));
++	case VIDIOC_G_CHIP_IDENT:
++		return v4l2_chip_ident_i2c_client(client,
++				arg, V4L2_IDENT_CS5345, 0);
 +
-+	if (tuner->index > 0)
-+		return -EINVAL;
++	case VIDIOC_LOG_STATUS:
++		{
++			u8 v = cs5345_read(client, 0x09) & 7;
++			u8 m = cs5345_read(client, 0x04);
++			int vol = cs5345_read(client, 0x08) & 0x3f;
 +
-+	/* read status rssi */
-+	retval = si470x_get_register(radio, STATUSRSSI);
-+	if (retval < 0)
-+		return retval;
++			v4l_info(client, "Input:  %d%s\n", v,
++				      (m & 0x80) ? " (muted)" : "");
++			if (vol >= 32)
++				vol = vol - 64;
++			v4l_info(client, "Volume: %d dB\n", vol);
++			break;
++		}
 +
-+	strcpy(tuner->name, "FM");
-+	tuner->type = V4L2_TUNER_RADIO;
-+	switch (band) {
-+	/* 0: 87.5 - 108 MHz (USA, Europe, default) */
 +	default:
-+		tuner->rangelow  =  87.5 * FREQ_MUL;
-+		tuner->rangehigh = 108   * FREQ_MUL;
-+		break;
-+	/* 1: 76   - 108 MHz (Japan wide band) */
-+	case 1 :
-+		tuner->rangelow  =  76   * FREQ_MUL;
-+		tuner->rangehigh = 108   * FREQ_MUL;
-+		break;
-+	/* 2: 76   -  90 MHz (Japan) */
-+	case 2 :
-+		tuner->rangelow  =  76   * FREQ_MUL;
-+		tuner->rangehigh =  90   * FREQ_MUL;
-+		break;
-+	};
-+	tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
-+	tuner->capability = V4L2_TUNER_CAP_LOW;
-+
-+	/* Stereo indicator == Stereo (instead of Mono) */
-+	if ((radio->registers[STATUSRSSI] & STATUSRSSI_ST) == 1)
-+		tuner->audmode = V4L2_TUNER_MODE_STEREO;
-+	else
-+		tuner->audmode = V4L2_TUNER_MODE_MONO;
-+
-+	/* min is worst, max is best; signal:0..0xffff; rssi: 0..0xff */
-+	tuner->signal = (radio->registers[STATUSRSSI] & STATUSRSSI_RSSI)
-+				* 0x0101;
-+
-+	/* automatic frequency control: -1: freq to low, 1 freq to high */
-+	tuner->afc = 0;
-+
-+	return 0;
-+}
-+
-+
-+/*
-+ * si470x_vidioc_s_tuner - set tuner attributes
-+ */
-+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));
-+
-+	if (tuner->index > 0)
 +		return -EINVAL;
-+
-+	if (tuner->audmode == V4L2_TUNER_MODE_MONO)
-+		radio->registers[POWERCFG] |= POWERCFG_MONO;  /* force mono */
-+	else
-+		radio->registers[POWERCFG] &= ~POWERCFG_MONO; /* try stereo */
-+
-+	return si470x_set_register(radio, POWERCFG);
-+}
-+
-+
-+/*
-+ * si470x_vidioc_g_frequency - get tuner or modulator radio frequency
-+ */
-+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));
-+
-+	freq->type = V4L2_TUNER_RADIO;
-+	freq->frequency = si470x_get_freq(radio);
-+
++	}
 +	return 0;
 +}
 +
++/* ----------------------------------------------------------------------- */
 +
-+/*
-+ * si470x_vidioc_s_frequency - set tuner or modulator radio frequency
-+ */
-+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));
-+
-+	if (freq->type != V4L2_TUNER_RADIO)
-+		return -EINVAL;
-+
-+	return si470x_set_freq(radio, freq->frequency);
-+}
-+
-+
-+/*
-+ * si470x_viddev_tamples - video device interface
-+ */
-+static struct video_device si470x_viddev_template = {
-+	.fops			= &si470x_fops,
-+	.name			= DRIVER_NAME,
-+	.type			= VID_TYPE_TUNER,
-+	.release		= video_device_release,
-+	.vidioc_querycap	= si470x_vidioc_querycap,
-+	.vidioc_g_input		= si470x_vidioc_g_input,
-+	.vidioc_s_input		= si470x_vidioc_s_input,
-+	.vidioc_queryctrl	= si470x_vidioc_queryctrl,
-+	.vidioc_g_ctrl		= si470x_vidioc_g_ctrl,
-+	.vidioc_s_ctrl		= si470x_vidioc_s_ctrl,
-+	.vidioc_g_audio		= si470x_vidioc_g_audio,
-+	.vidioc_s_audio		= si470x_vidioc_s_audio,
-+	.vidioc_g_tuner		= si470x_vidioc_g_tuner,
-+	.vidioc_s_tuner		= si470x_vidioc_s_tuner,
-+	.vidioc_g_frequency	= si470x_vidioc_g_frequency,
-+	.vidioc_s_frequency	= si470x_vidioc_s_frequency,
-+	.owner			= THIS_MODULE,
-+};
-+
-+
-+
-+/**************************************************************************
-+ * USB Interface
-+ **************************************************************************/
-+
-+/*
-+ * si470x_usb_driver_probe - probe for the device
-+ */
-+static int si470x_usb_driver_probe(struct usb_interface *intf,
-+		const struct usb_device_id *id)
++static int cs5345_probe(struct i2c_client *client)
 +{
-+	struct si470x_device *radio;
-+
-+	/* memory and interface allocations */
-+	radio = kmalloc(sizeof(struct si470x_device), GFP_KERNEL);
-+	if (!radio)
-+		return -ENOMEM;
-+	radio->videodev = video_device_alloc();
-+	if (!radio->videodev) {
-+		kfree(radio);
-+		return -ENOMEM;
-+	}
-+	memcpy(radio->videodev, &si470x_viddev_template,
-+			sizeof(si470x_viddev_template));
-+	radio->users = 0;
-+	radio->usbdev = interface_to_usbdev(intf);
-+	video_set_drvdata(radio->videodev, radio);
-+	if (video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr)) {
-+		printk(KERN_WARNING DRIVER_NAME
-+				": Could not register video device\n");
-+		video_device_release(radio->videodev);
-+		kfree(radio);
-+		return -EIO;
-+	}
-+	usb_set_intfdata(intf, radio);
-+
-+	/* show some infos about the specific device */
-+	if (si470x_get_all_registers(radio) < 0) {
-+		video_device_release(radio->videodev);
-+		kfree(radio);
++	/* Check if the adapter supports the needed features */
++	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
 +		return -EIO;
-+	}
-+	printk(KERN_INFO DRIVER_NAME ": DeviceID=0x%4.4x ChipID=0x%4.4x\n",
-+			radio->registers[DEVICEID], radio->registers[CHIPID]);
-+
-+	/* check if firmware is current */
-+	if ((radio->registers[CHIPID] & CHIPID_FIRMWARE)
-+			< RADIO_SW_VERSION_CURRENT)
-+		printk(KERN_WARNING DRIVER_NAME
-+			": This driver is known to work with chip version %d, "
-+			"but the device has firmware %d.\n"
-+			DRIVER_NAME
-+			"If you have some trouble using this driver, please "
-+			"report to V4L ML at video4linux-list at redhat.com\n",
-+			radio->registers[CHIPID] & CHIPID_FIRMWARE,
-+			RADIO_SW_VERSION_CURRENT);
-+
-+	/* set initial frequency */
-+	si470x_set_freq(radio, 87.5 * FREQ_MUL); /* available in all regions */
-+
-+	/* rds initialization */
-+	radio->buf_size = rds_buf * 3;
-+	radio->buffer = kmalloc(radio->buf_size, GFP_KERNEL);
-+	if (!radio->buffer) {
-+		video_device_release(radio->videodev);
-+		kfree(radio);
-+		return -ENOMEM;
-+	}
-+	radio->wr_index = 0;
-+	radio->rd_index = 0;
-+	init_waitqueue_head(&radio->read_queue);
 +
-+	/* prepare polling via eventd */
-+	INIT_WORK(&radio->work, si470x_work);
-+	init_timer(&radio->timer);
-+	radio->timer.function = si470x_timer;
-+	radio->timer.data = (unsigned long) radio;
++	v4l_info(client, "chip found @ 0x%x (%s)\n",
++			client->addr << 1, client->adapter->name);
 +
++	cs5345_write(client, 0x02, 0x00);
++	cs5345_write(client, 0x04, 0x01);
++	cs5345_write(client, 0x09, 0x01);
 +	return 0;
 +}
 +
++/* ----------------------------------------------------------------------- */
 +
-+/*
-+ * si470x_usb_driver_disconnect - disconnect the device
-+ */
-+static void si470x_usb_driver_disconnect(struct usb_interface *intf)
-+{
-+	struct si470x_device *radio = usb_get_intfdata(intf);
-+
-+	del_timer_sync(&radio->timer);
-+	flush_scheduled_work();
-+
-+	usb_set_intfdata(intf, NULL);
-+	if (radio) {
-+		video_unregister_device(radio->videodev);
-+		kfree(radio->buffer);
-+		kfree(radio);
-+	}
-+}
-+
-+
-+/*
-+ * si470x_usb_driver - usb driver interface
-+ */
-+static struct usb_driver si470x_usb_driver = {
-+	.name		= DRIVER_NAME,
-+	.probe		= si470x_usb_driver_probe,
-+	.disconnect	= si470x_usb_driver_disconnect,
-+	.id_table	= si470x_usb_driver_id_table,
++static struct v4l2_i2c_driver_data v4l2_i2c_data = {
++	.name = "cs5345",
++	.driverid = I2C_DRIVERID_CS5345,
++	.command = cs5345_command,
++	.probe = cs5345_probe,
 +};
 +
-+
-+
-+/**************************************************************************
-+ * Module Interface
-+ **************************************************************************/
-+
-+/*
-+ * si470x_module_init - module init
-+ */
-+static int __init si470x_module_init(void)
-+{
-+	printk(KERN_INFO DRIVER_DESC "\n");
-+	return usb_register(&si470x_usb_driver);
-+}
-+
-+
-+/*
-+ * si470x_module_exit - module exit
-+ */
-+static void __exit si470x_module_exit(void)
-+{
-+	usb_deregister(&si470x_usb_driver);
-+}
-+
-+
-+module_init(si470x_module_init);
-+module_exit(si470x_module_exit);
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR(DRIVER_AUTHOR);
-+MODULE_DESCRIPTION(DRIVER_DESC);
-+MODULE_VERSION("1.0.4");
-diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
-index c9f14bf..a2e8987 100644
---- a/drivers/media/video/Kconfig
-+++ b/drivers/media/video/Kconfig
-@@ -45,7 +45,7 @@ comment "Audio decoders"
+diff --git a/drivers/media/video/cs53l32a.c b/drivers/media/video/cs53l32a.c
+index a73e285..f41bfde 100644
+--- a/drivers/media/video/cs53l32a.c
++++ b/drivers/media/video/cs53l32a.c
+@@ -29,12 +29,13 @@
+ #include <linux/videodev.h>
+ #include <media/v4l2-common.h>
+ #include <media/v4l2-chip-ident.h>
++#include <media/v4l2-i2c-drv-legacy.h>
+ 
+ MODULE_DESCRIPTION("i2c device driver for cs53l32a Audio ADC");
+ MODULE_AUTHOR("Martin Vaughan");
+ MODULE_LICENSE("GPL");
+ 
+-static int debug = 0;
++static int debug;
+ 
+ module_param(debug, bool, 0644);
+ 
+@@ -57,8 +58,7 @@ static int cs53l32a_read(struct i2c_client *client, u8 reg)
+ 	return i2c_smbus_read_byte_data(client, reg);
+ }
+ 
+-static int cs53l32a_command(struct i2c_client *client, unsigned int cmd,
+-			    void *arg)
++static int cs53l32a_command(struct i2c_client *client, unsigned cmd, void *arg)
+ {
+ 	struct v4l2_routing *route = arg;
+ 	struct v4l2_control *ctrl = arg;
+@@ -105,7 +105,8 @@ static int cs53l32a_command(struct i2c_client *client, unsigned int cmd,
+ 		break;
+ 
+ 	case VIDIOC_G_CHIP_IDENT:
+-		return v4l2_chip_ident_i2c_client(client, arg, V4L2_IDENT_CS53l32A, 0);
++		return v4l2_chip_ident_i2c_client(client,
++				arg, V4L2_IDENT_CS53l32A, 0);
+ 
+ 	case VIDIOC_LOG_STATUS:
+ 		{
+@@ -134,27 +135,18 @@ static int cs53l32a_command(struct i2c_client *client, unsigned int cmd,
+  * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
+  */
+ 
+-static struct i2c_driver i2c_driver;
+-
+-static int cs53l32a_attach(struct i2c_adapter *adapter, int address, int kind)
++static int cs53l32a_probe(struct i2c_client *client)
+ {
+-	struct i2c_client *client;
+ 	int i;
+ 
+ 	/* Check if the adapter supports the needed features */
+-	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+-		return 0;
+-
+-	client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
+-	if (client == 0)
+-		return -ENOMEM;
++	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
++		return -EIO;
+ 
+-	client->addr = address;
+-	client->adapter = adapter;
+-	client->driver = &i2c_driver;
+ 	snprintf(client->name, sizeof(client->name) - 1, "cs53l32a");
+ 
+-	v4l_info(client, "chip found @ 0x%x (%s)\n", address << 1, adapter->name);
++	v4l_info(client, "chip found @ 0x%x (%s)\n",
++			client->addr << 1, client->adapter->name);
+ 
+ 	for (i = 1; i <= 7; i++) {
+ 		u8 v = cs53l32a_read(client, i);
+@@ -179,55 +171,13 @@ static int cs53l32a_attach(struct i2c_adapter *adapter, int address, int kind)
+ 
+ 		v4l_dbg(1, debug, client, "Read Reg %d %02x\n", i, v);
+ 	}
+-
+-	i2c_attach_client(client);
+-
+ 	return 0;
+ }
+ 
+-static int cs53l32a_probe(struct i2c_adapter *adapter)
+-{
+-	if (adapter->class & I2C_CLASS_TV_ANALOG)
+-		return i2c_probe(adapter, &addr_data, cs53l32a_attach);
+-	return 0;
+-}
+-
+-static int cs53l32a_detach(struct i2c_client *client)
+-{
+-	int err;
+-
+-	err = i2c_detach_client(client);
+-	if (err) {
+-		return err;
+-	}
+-	kfree(client);
+-
+-	return 0;
+-}
+-
+-/* ----------------------------------------------------------------------- */
+-
+-/* i2c implementation */
+-static struct i2c_driver i2c_driver = {
+-	.driver = {
+-		.name = "cs53l32a",
+-	},
+-	.id = I2C_DRIVERID_CS53L32A,
+-	.attach_adapter = cs53l32a_probe,
+-	.detach_client = cs53l32a_detach,
++static struct v4l2_i2c_driver_data v4l2_i2c_data = {
++	.name = "cs53l32a",
++	.driverid = I2C_DRIVERID_CS53L32A,
+ 	.command = cs53l32a_command,
++	.probe = cs53l32a_probe,
+ };
+ 
+-
+-static int __init cs53l32a_init_module(void)
+-{
+-	return i2c_add_driver(&i2c_driver);
+-}
+-
+-static void __exit cs53l32a_cleanup_module(void)
+-{
+-	i2c_del_driver(&i2c_driver);
+-}
+-
+-module_init(cs53l32a_init_module);
+-module_exit(cs53l32a_cleanup_module);
+diff --git a/drivers/media/video/cx2341x.c b/drivers/media/video/cx2341x.c
+index 6230425..c592899 100644
+--- a/drivers/media/video/cx2341x.c
++++ b/drivers/media/video/cx2341x.c
+@@ -34,7 +34,7 @@ MODULE_DESCRIPTION("cx23415/6 driver");
+ MODULE_AUTHOR("Hans Verkuil");
+ MODULE_LICENSE("GPL");
+ 
+-static int debug = 0;
++static int debug;
+ module_param(debug, int, 0644);
+ MODULE_PARM_DESC(debug, "Debug level (0-1)");
+ 
+@@ -75,6 +75,7 @@ const u32 cx2341x_mpeg_ctrls[] = {
+ 	V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS,
+ 	0
+ };
++EXPORT_SYMBOL(cx2341x_mpeg_ctrls);
+ 
+ 
+ /* Map the control ID to the correct field in the cx2341x_mpeg_params
+@@ -281,13 +282,14 @@ static int cx2341x_set_ctrl(struct cx2341x_mpeg_params *params, int busy,
+ 			return -EBUSY;
+ 		params->stream_type = ctrl->value;
+ 		params->video_encoding =
+-			(params->stream_type == V4L2_MPEG_STREAM_TYPE_MPEG1_SS ||
+-			 params->stream_type == V4L2_MPEG_STREAM_TYPE_MPEG1_VCD) ?
+-			V4L2_MPEG_VIDEO_ENCODING_MPEG_1 : V4L2_MPEG_VIDEO_ENCODING_MPEG_2;
+-		if (params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1) {
++		    (params->stream_type == V4L2_MPEG_STREAM_TYPE_MPEG1_SS ||
++		     params->stream_type == V4L2_MPEG_STREAM_TYPE_MPEG1_VCD) ?
++			V4L2_MPEG_VIDEO_ENCODING_MPEG_1 :
++			V4L2_MPEG_VIDEO_ENCODING_MPEG_2;
++		if (params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1)
+ 			/* MPEG-1 implies CBR */
+-			params->video_bitrate_mode = V4L2_MPEG_VIDEO_BITRATE_MODE_CBR;
+-		}
++			params->video_bitrate_mode =
++				V4L2_MPEG_VIDEO_BITRATE_MODE_CBR;
+ 		break;
+ 	case V4L2_CID_MPEG_STREAM_VBI_FMT:
+ 		params->stream_vbi_fmt = ctrl->value;
+@@ -334,7 +336,8 @@ static int cx2341x_set_ctrl(struct cx2341x_mpeg_params *params, int busy,
+ 	return 0;
+ }
+ 
+-static int cx2341x_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 step, s32 def)
++static int cx2341x_ctrl_query_fill(struct v4l2_queryctrl *qctrl,
++				   s32 min, s32 max, s32 step, s32 def)
+ {
+ 	const char *name;
+ 
+@@ -417,7 +420,8 @@ static int cx2341x_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 ma
+ 	return 0;
+ }
+ 
+-int cx2341x_ctrl_query(struct cx2341x_mpeg_params *params, struct v4l2_queryctrl *qctrl)
++int cx2341x_ctrl_query(struct cx2341x_mpeg_params *params,
++		       struct v4l2_queryctrl *qctrl)
+ {
+ 	int err;
+ 
+@@ -440,7 +444,8 @@ int cx2341x_ctrl_query(struct cx2341x_mpeg_params *params, struct v4l2_queryctrl
+ 
+ 	case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
+ 		err = v4l2_ctrl_query_fill_std(qctrl);
+-		if (err == 0 && params->audio_mode != V4L2_MPEG_AUDIO_MODE_JOINT_STEREO)
++		if (err == 0 &&
++		    params->audio_mode != V4L2_MPEG_AUDIO_MODE_JOINT_STEREO)
+ 			qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+ 		return err;
+ 
+@@ -455,13 +460,16 @@ int cx2341x_ctrl_query(struct cx2341x_mpeg_params *params, struct v4l2_queryctrl
+ 
+ 	case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+ 		err = v4l2_ctrl_query_fill_std(qctrl);
+-		if (err == 0 && params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1)
++		if (err == 0 &&
++		    params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1)
+ 			qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+ 		return err;
+ 
+ 	case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
+ 		err = v4l2_ctrl_query_fill_std(qctrl);
+-		if (err == 0 && params->video_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR)
++		if (err == 0 &&
++		    params->video_bitrate_mode ==
++				V4L2_MPEG_VIDEO_BITRATE_MODE_CBR)
+ 			qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+ 		return err;
+ 
+@@ -476,80 +484,90 @@ int cx2341x_ctrl_query(struct cx2341x_mpeg_params *params, struct v4l2_queryctrl
+ 	/* CX23415/6 specific */
+ 	case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
+ 		return cx2341x_ctrl_query_fill(qctrl,
+-				V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL,
+-				V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO, 1,
+-				V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL);
++			V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL,
++			V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO, 1,
++			V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL);
+ 
+ 	case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER:
+ 		cx2341x_ctrl_query_fill(qctrl, 0, 15, 1, 0);
+ 		qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
+-		if (params->video_spatial_filter_mode == V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO)
+-		       qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
++		if (params->video_spatial_filter_mode ==
++			    V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO)
++			qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+ 		return 0;
  
- config VIDEO_TVAUDIO
- 	tristate "Simple audio decoder chips"
--	depends on VIDEO_V4L1 && I2C
-+	depends on VIDEO_V4L2 && I2C
- 	---help---
- 	  Support for several audio decoder chips found on some bt8xx boards:
- 	  Philips: tda9840, tda9873h, tda9874h/a, tda9850, tda985x, tea6300,
-@@ -57,7 +57,7 @@ config VIDEO_TVAUDIO
+ 	case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
+ 		cx2341x_ctrl_query_fill(qctrl,
+-				V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_OFF,
+-				V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_2D_SYM_NON_SEPARABLE, 1,
+-				V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_OFF);
+-		if (params->video_spatial_filter_mode == V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO)
+-		       qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
++			V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_OFF,
++			V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_2D_SYM_NON_SEPARABLE,
++			1,
++			V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_OFF);
++		if (params->video_spatial_filter_mode ==
++			    V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO)
++			qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+ 		return 0;
  
- config VIDEO_TDA7432
- 	tristate "Philips TDA7432 audio processor"
--	depends on VIDEO_V4L1 && I2C
-+	depends on VIDEO_V4L2 && I2C
- 	---help---
- 	  Support for tda7432 audio decoder chip found on some bt8xx boards.
+ 	case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
+ 		cx2341x_ctrl_query_fill(qctrl,
+-				V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_OFF,
+-				V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR, 1,
+-				V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_OFF);
+-		if (params->video_spatial_filter_mode == V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO)
+-		       qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
++		    V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_OFF,
++		    V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR,
++		    1,
++		    V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_OFF);
++		if (params->video_spatial_filter_mode ==
++			V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO)
++			qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+ 		return 0;
  
-@@ -75,7 +75,7 @@ config VIDEO_TDA9840
+ 	case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
+ 		return cx2341x_ctrl_query_fill(qctrl,
+-				V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL,
+-				V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO, 1,
+-				V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL);
++			V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL,
++			V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO, 1,
++			V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL);
  
- config VIDEO_TDA9875
- 	tristate "Philips TDA9875 audio processor"
--	depends on VIDEO_V4L1 && I2C
-+	depends on VIDEO_V4L2 && I2C
- 	---help---
- 	  Support for tda9875 audio decoder chip found on some bt8xx boards.
+ 	case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER:
+ 		cx2341x_ctrl_query_fill(qctrl, 0, 31, 1, 0);
+ 		qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
+-		if (params->video_temporal_filter_mode == V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO)
+-		       qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
++		if (params->video_temporal_filter_mode ==
++			V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO)
++			qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+ 		return 0;
  
-@@ -109,9 +109,19 @@ config VIDEO_MSP3400
- 	  To compile this driver as a module, choose M here: the
- 	  module will be called msp3400.
+ 	case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
+ 		return cx2341x_ctrl_query_fill(qctrl,
+-				V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF,
+-				V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_DIAG, 1,
+-				V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF);
++			V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF,
++			V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_DIAG, 1,
++			V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF);
  
-+config VIDEO_CS5345
-+	tristate "Cirrus Logic CS5345 audio ADC"
-+	depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
-+	---help---
-+	  Support for the Cirrus Logic CS5345 24-bit, 192 kHz
-+	  stereo A/D converter.
-+
-+	  To compile this driver as a module, choose M here: the
-+	  module will be called cs5345.
-+
- config VIDEO_CS53L32A
- 	tristate "Cirrus Logic CS53L32A audio ADC"
--	depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
-+	depends on VIDEO_V4L2 && I2C
- 	---help---
- 	  Support for the Cirrus Logic CS53L32A low voltage
- 	  stereo A/D converter.
-@@ -119,6 +129,15 @@ config VIDEO_CS53L32A
- 	  To compile this driver as a module, choose M here: the
- 	  module will be called cs53l32a.
+ 	case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP:
+ 		cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, 255);
+ 		qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
+-		if (params->video_median_filter_type == V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF)
+-		       qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
++		if (params->video_median_filter_type ==
++				V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF)
++			qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+ 		return 0;
  
-+config VIDEO_M52790
-+       tristate "Mitsubishi M52790 A/V switch"
-+       depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
-+       ---help---
-+	 Support for the Mitsubishi M52790 A/V switch.
-+
-+	 To compile this driver as a module, choose M here: the
-+	 module will be called m52790.
-+
- config VIDEO_TLV320AIC23B
- 	tristate "Texas Instruments TLV320AIC23B audio codec"
- 	depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
-@@ -130,7 +149,7 @@ config VIDEO_TLV320AIC23B
+ 	case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM:
+ 		cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, 0);
+ 		qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
+-		if (params->video_median_filter_type == V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF)
+-		       qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
++		if (params->video_median_filter_type ==
++				V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF)
++			qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+ 		return 0;
  
- config VIDEO_WM8775
- 	tristate "Wolfson Microelectronics WM8775 audio ADC with input mixer"
--	depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
-+	depends on VIDEO_V4L2 && I2C
- 	---help---
- 	  Support for the Wolfson Microelectronics WM8775 high
- 	  performance stereo A/D Converter with a 4 channel input mixer.
-@@ -140,7 +159,7 @@ config VIDEO_WM8775
+ 	case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP:
+ 		cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, 255);
+ 		qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
+-		if (params->video_median_filter_type == V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF)
+-		       qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
++		if (params->video_median_filter_type ==
++				V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF)
++			qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+ 		return 0;
  
- config VIDEO_WM8739
- 	tristate "Wolfson Microelectronics WM8739 stereo audio ADC"
--	depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
-+	depends on VIDEO_V4L2 && I2C
- 	---help---
- 	  Support for the Wolfson Microelectronics WM8739
- 	  stereo A/D Converter.
-@@ -244,7 +263,7 @@ config VIDEO_SAA7114
+ 	case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM:
+ 		cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, 0);
+ 		qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
+-		if (params->video_median_filter_type == V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF)
+-		       qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
++		if (params->video_median_filter_type ==
++				V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF)
++			qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+ 		return 0;
  
- config VIDEO_SAA711X
- 	tristate "Philips SAA7113/4/5 video decoders"
--	depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
-+	depends on VIDEO_V4L2 && I2C
- 	---help---
- 	  Support for the Philips SAA7113/4/5 video decoders.
+ 	case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS:
+@@ -560,6 +578,7 @@ int cx2341x_ctrl_query(struct cx2341x_mpeg_params *params, struct v4l2_queryctrl
  
-@@ -300,7 +319,7 @@ comment "Video encoders"
+ 	}
+ }
++EXPORT_SYMBOL(cx2341x_ctrl_query);
  
- config VIDEO_SAA7127
- 	tristate "Philips SAA7127/9 digital video encoders"
--	depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
-+	depends on VIDEO_V4L2 && I2C
- 	---help---
- 	  Support for the Philips SAA7127/9 digital video encoders.
+ const char **cx2341x_ctrl_get_menu(u32 id)
+ {
+@@ -629,6 +648,7 @@ const char **cx2341x_ctrl_get_menu(u32 id)
+ 		return v4l2_ctrl_get_menu(id);
+ 	}
+ }
++EXPORT_SYMBOL(cx2341x_ctrl_get_menu);
  
-@@ -338,7 +357,7 @@ comment "Video improvement chips"
+ static void cx2341x_calc_audio_properties(struct cx2341x_mpeg_params *params)
+ {
+@@ -637,9 +657,8 @@ static void cx2341x_calc_audio_properties(struct cx2341x_mpeg_params *params)
+ 		((1 + params->audio_l2_bitrate) << 4) |
+ 		(params->audio_mode << 8) |
+ 		(params->audio_mode_extension << 10) |
+-		(((params->audio_emphasis == V4L2_MPEG_AUDIO_EMPHASIS_CCITT_J17) ?
+-		  3 :
+-		  params->audio_emphasis) << 12) |
++		(((params->audio_emphasis == V4L2_MPEG_AUDIO_EMPHASIS_CCITT_J17)
++		  ? 3 : params->audio_emphasis) << 12) |
+ 		(params->audio_crc << 14);
+ }
  
- config VIDEO_UPD64031A
- 	tristate "NEC Electronics uPD64031A Ghost Reduction"
--	depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
-+	depends on VIDEO_V4L2 && I2C
- 	---help---
- 	  Support for the NEC Electronics uPD64031A Ghost Reduction
- 	  video chip. It is most often found in NTSC TV cards made for
-@@ -350,7 +369,7 @@ config VIDEO_UPD64031A
+@@ -679,19 +698,19 @@ int cx2341x_ext_ctrls(struct cx2341x_mpeg_params *params, int busy,
+ 		if (err)
+ 			break;
+ 	}
+-	if (err == 0 && params->video_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR &&
+-			params->video_bitrate_peak < params->video_bitrate) {
++	if (err == 0 &&
++	    params->video_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR &&
++	    params->video_bitrate_peak < params->video_bitrate) {
+ 		err = -ERANGE;
+ 		ctrls->error_idx = ctrls->count;
+ 	}
+-	if (err) {
++	if (err)
+ 		ctrls->error_idx = i;
+-	}
+-	else {
++	else
+ 		cx2341x_calc_audio_properties(params);
+-	}
+ 	return err;
+ }
++EXPORT_SYMBOL(cx2341x_ext_ctrls);
  
- config VIDEO_UPD64083
- 	tristate "NEC Electronics uPD64083 3-Dimensional Y/C separation"
--	depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
-+	depends on VIDEO_V4L2 && I2C
- 	---help---
- 	  Support for the NEC Electronics uPD64083 3-Dimensional Y/C
- 	  separation video chip. It is used to improve the quality of
-@@ -802,6 +821,19 @@ config USB_ZR364XX
- 	  To compile this driver as a module, choose M here: the
- 	  module will be called zr364xx.
+ void cx2341x_fill_defaults(struct cx2341x_mpeg_params *p)
+ {
+@@ -732,13 +751,18 @@ void cx2341x_fill_defaults(struct cx2341x_mpeg_params *p)
+ 	.video_mute_yuv = 0x008080,  /* YCbCr value for black */
  
-+config USB_STKWEBCAM
-+	tristate "USB Syntek DC1125 Camera support"
-+	depends on VIDEO_V4L2 && EXPERIMENTAL
-+	---help---
-+	  Say Y here if you want to use this type of camera.
-+	  Supported devices are typically found in some Asus laptops,
-+	  with USB id 174f:a311 and 05e1:0501. Other Syntek cameras
-+	  may be supported by the stk11xx driver, from which this is
-+	  derived, see http://stk11xx.sourceforge.net
-+
-+	  To compile this driver as a module, choose M here: the
-+	  module will be called stkwebcam.
-+
- endif # V4L_USB_DRIVERS
+ 	/* encoding filters */
+-	.video_spatial_filter_mode = V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL,
++	.video_spatial_filter_mode =
++		V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL,
+ 	.video_spatial_filter = 0,
+-	.video_luma_spatial_filter_type = V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_HOR,
+-	.video_chroma_spatial_filter_type = V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR,
+-	.video_temporal_filter_mode = V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL,
++	.video_luma_spatial_filter_type =
++		V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_HOR,
++	.video_chroma_spatial_filter_type =
++		V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR,
++	.video_temporal_filter_mode =
++		V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL,
+ 	.video_temporal_filter = 8,
+-	.video_median_filter_type = V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF,
++	.video_median_filter_type =
++		V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF,
+ 	.video_luma_median_filter_top = 255,
+ 	.video_luma_median_filter_bottom = 0,
+ 	.video_chroma_median_filter_top = 255,
+@@ -748,8 +772,10 @@ void cx2341x_fill_defaults(struct cx2341x_mpeg_params *p)
+ 	*p = default_params;
+ 	cx2341x_calc_audio_properties(p);
+ }
++EXPORT_SYMBOL(cx2341x_fill_defaults);
  
- endif # VIDEO_CAPTURE_DRIVERS
-diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
-index b5a0641..28ddd14 100644
---- a/drivers/media/video/Makefile
-+++ b/drivers/media/video/Makefile
-@@ -4,10 +4,12 @@
+-static int cx2341x_api(void *priv, cx2341x_mbox_func func, int cmd, int args, ...)
++static int cx2341x_api(void *priv, cx2341x_mbox_func func,
++		       u32 cmd, int args, ...)
+ {
+ 	u32 data[CX2341X_MBOX_MAX_DATA];
+ 	va_list vargs;
+@@ -757,15 +783,17 @@ static int cx2341x_api(void *priv, cx2341x_mbox_func func, int cmd, int args, ..
  
- zr36067-objs	:=	zoran_procfs.o zoran_device.o \
- 			zoran_driver.o zoran_card.o
--tuner-objs	:=	tuner-core.o tuner-types.o tda9887.o
-+tuner-objs	:=	tuner-core.o tuner-types.o
+ 	va_start(vargs, args);
  
- msp3400-objs	:=	msp3400-driver.o msp3400-kthreads.o
+-	for (i = 0; i < args; i++) {
++	for (i = 0; i < args; i++)
+ 		data[i] = va_arg(vargs, int);
+-	}
+ 	va_end(vargs);
+ 	return func(priv, cmd, args, 0, data);
+ }
  
-+stkwebcam-objs	:=	stk-webcam.o stk-sensor.o
++#define NEQ(field) (old->field != new->field)
 +
- obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-common.o compat_ioctl32.o \
- 			   v4l2-int-device.o
+ int cx2341x_update(void *priv, cx2341x_mbox_func func,
+-		const struct cx2341x_mpeg_params *old, const struct cx2341x_mpeg_params *new)
++		   const struct cx2341x_mpeg_params *old,
++		   const struct cx2341x_mpeg_params *new)
+ {
+ 	static int mpeg_stream_type[] = {
+ 		0,	/* MPEG-2 PS */
+@@ -777,17 +805,18 @@ int cx2341x_update(void *priv, cx2341x_mbox_func func,
+ 	};
  
-@@ -66,7 +68,9 @@ obj-$(CONFIG_VIDEO_USBVISION) += usbvision/
- obj-$(CONFIG_VIDEO_TVP5150) += tvp5150.o
- obj-$(CONFIG_VIDEO_PVRUSB2) += pvrusb2/
- obj-$(CONFIG_VIDEO_MSP3400) += msp3400.o
-+obj-$(CONFIG_VIDEO_CS5345) += cs5345.o
- obj-$(CONFIG_VIDEO_CS53L32A) += cs53l32a.o
-+obj-$(CONFIG_VIDEO_M52790) += m52790.o
- obj-$(CONFIG_VIDEO_TLV320AIC23B) += tlv320aic23b.o
- obj-$(CONFIG_VIDEO_WM8775) += wm8775.o
- obj-$(CONFIG_VIDEO_WM8739) += wm8739.o
-@@ -81,11 +85,13 @@ obj-$(CONFIG_TUNER_3036) += tuner-3036.o
+ 	int err = 0;
++	int force = (old == NULL);
+ 	u16 temporal = new->video_temporal_filter;
  
- obj-$(CONFIG_VIDEO_TUNER) += tuner.o
+ 	cx2341x_api(priv, func, CX2341X_ENC_SET_OUTPUT_PORT, 2, new->port, 0);
  
-+obj-$(CONFIG_TUNER_XC2028) += tuner-xc2028.o
- obj-$(CONFIG_TUNER_SIMPLE) += tuner-simple.o
- obj-$(CONFIG_TUNER_MT20XX) += mt20xx.o
- obj-$(CONFIG_TUNER_TDA8290) += tda8290.o
- obj-$(CONFIG_TUNER_TEA5767) += tea5767.o
- obj-$(CONFIG_TUNER_TEA5761) += tea5761.o
-+obj-$(CONFIG_TUNER_TDA9887) += tda9887.o
+-	if (old == NULL || old->is_50hz != new->is_50hz) {
+-		err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_RATE, 1, new->is_50hz);
++	if (force || NEQ(is_50hz)) {
++		err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_RATE, 1,
++				  new->is_50hz);
+ 		if (err) return err;
+ 	}
  
- obj-$(CONFIG_VIDEOBUF_GEN) += videobuf-core.o
- obj-$(CONFIG_VIDEOBUF_DMA_SG) += videobuf-dma-sg.o
-@@ -112,6 +118,7 @@ obj-$(CONFIG_USB_SE401)         += se401.o
- obj-$(CONFIG_USB_STV680)        += stv680.o
- obj-$(CONFIG_USB_W9968CF)       += w9968cf.o
- obj-$(CONFIG_USB_ZR364XX)       += zr364xx.o
-+obj-$(CONFIG_USB_STKWEBCAM)     += stkwebcam.o
+-	if (old == NULL || old->width != new->width || old->height != new->height ||
+-			old->video_encoding != new->video_encoding) {
++	if (force || NEQ(width) || NEQ(height) || NEQ(video_encoding)) {
+ 		u16 w = new->width;
+ 		u16 h = new->height;
  
- obj-$(CONFIG_USB_SN9C102)       += sn9c102/
- obj-$(CONFIG_USB_ET61X251)      += et61x251/
-@@ -129,3 +136,4 @@ obj-$(CONFIG_VIDEO_VIVI) += vivi.o
- obj-$(CONFIG_VIDEO_CX23885) += cx23885/
+@@ -795,69 +824,74 @@ int cx2341x_update(void *priv, cx2341x_mbox_func func,
+ 			w /= 2;
+ 			h /= 2;
+ 		}
+-		err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_SIZE, 2, h, w);
++		err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_SIZE, 2,
++				  h, w);
+ 		if (err) return err;
+ 	}
  
- EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
-+EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
-diff --git a/drivers/media/video/bt8xx/Kconfig b/drivers/media/video/bt8xx/Kconfig
-index 2ca162b..cfc822b 100644
---- a/drivers/media/video/bt8xx/Kconfig
-+++ b/drivers/media/video/bt8xx/Kconfig
-@@ -1,6 +1,6 @@
- config VIDEO_BT848
- 	tristate "BT848 Video For Linux"
--	depends on VIDEO_DEV && PCI && I2C && VIDEO_V4L1
-+	depends on VIDEO_DEV && PCI && I2C && VIDEO_V4L2 && INPUT
- 	select I2C_ALGOBIT
- 	select FW_LOADER
- 	select VIDEO_BTCX
-diff --git a/drivers/media/video/bt8xx/Makefile b/drivers/media/video/bt8xx/Makefile
-index a096a03..924d216 100644
---- a/drivers/media/video/bt8xx/Makefile
-+++ b/drivers/media/video/bt8xx/Makefile
-@@ -4,7 +4,7 @@
+ 	if (new->width != 720 || new->height != (new->is_50hz ? 576 : 480)) {
+-		/* Adjust temporal filter if necessary. The problem with the temporal
+-		   filter is that it works well with full resolution capturing, but
+-		   not when the capture window is scaled (the filter introduces
+-		   a ghosting effect). So if the capture window is scaled, then
+-		   force the filter to 0.
++		/* Adjust temporal filter if necessary. The problem with the
++		   temporal filter is that it works well with full resolution
++		   capturing, but not when the capture window is scaled (the
++		   filter introduces a ghosting effect). So if the capture
++		   window is scaled, then force the filter to 0.
  
- bttv-objs      :=      bttv-driver.o bttv-cards.o bttv-if.o \
- 		       bttv-risc.o bttv-vbi.o bttv-i2c.o bttv-gpio.o \
--		       bttv-input.o
-+		       bttv-input.o bttv-audio-hook.o
+ 		   For full resolution the filter really improves the video
+-		   quality, especially if the original video quality is suboptimal. */
++		   quality, especially if the original video quality is
++		   suboptimal. */
+ 		temporal = 0;
+ 	}
  
- obj-$(CONFIG_VIDEO_BT848) += bttv.o
+-	if (old == NULL || old->stream_type != new->stream_type) {
+-		err = cx2341x_api(priv, func, CX2341X_ENC_SET_STREAM_TYPE, 1, mpeg_stream_type[new->stream_type]);
++	if (force || NEQ(stream_type)) {
++		err = cx2341x_api(priv, func, CX2341X_ENC_SET_STREAM_TYPE, 1,
++				  mpeg_stream_type[new->stream_type]);
+ 		if (err) return err;
+ 	}
+-	if (old == NULL || old->video_aspect != new->video_aspect) {
+-		err = cx2341x_api(priv, func, CX2341X_ENC_SET_ASPECT_RATIO, 1, 1 + new->video_aspect);
++	if (force || NEQ(video_aspect)) {
++		err = cx2341x_api(priv, func, CX2341X_ENC_SET_ASPECT_RATIO, 1,
++				  1 + new->video_aspect);
+ 		if (err) return err;
+ 	}
+-	if (old == NULL || old->video_b_frames != new->video_b_frames ||
+-		old->video_gop_size != new->video_gop_size) {
++	if (force || NEQ(video_b_frames) || NEQ(video_gop_size)) {
+ 		err = cx2341x_api(priv, func, CX2341X_ENC_SET_GOP_PROPERTIES, 2,
+ 				new->video_gop_size, new->video_b_frames + 1);
+ 		if (err) return err;
+ 	}
+-	if (old == NULL || old->video_gop_closure != new->video_gop_closure) {
+-		err = cx2341x_api(priv, func, CX2341X_ENC_SET_GOP_CLOSURE, 1, new->video_gop_closure);
++	if (force || NEQ(video_gop_closure)) {
++		err = cx2341x_api(priv, func, CX2341X_ENC_SET_GOP_CLOSURE, 1,
++				  new->video_gop_closure);
+ 		if (err) return err;
+ 	}
+-	if (old == NULL || old->audio_properties != new->audio_properties) {
+-		err = cx2341x_api(priv, func, CX2341X_ENC_SET_AUDIO_PROPERTIES, 1, new->audio_properties);
++	if (force || NEQ(audio_properties)) {
++		err = cx2341x_api(priv, func, CX2341X_ENC_SET_AUDIO_PROPERTIES,
++				  1, new->audio_properties);
+ 		if (err) return err;
+ 	}
+-	if (old == NULL || old->audio_mute != new->audio_mute) {
+-		err = cx2341x_api(priv, func, CX2341X_ENC_MUTE_AUDIO, 1, new->audio_mute);
++	if (force || NEQ(audio_mute)) {
++		err = cx2341x_api(priv, func, CX2341X_ENC_MUTE_AUDIO, 1,
++				  new->audio_mute);
+ 		if (err) return err;
+ 	}
+-	if (old == NULL || old->video_bitrate_mode != new->video_bitrate_mode ||
+-		old->video_bitrate != new->video_bitrate ||
+-		old->video_bitrate_peak != new->video_bitrate_peak) {
++	if (force || NEQ(video_bitrate_mode) || NEQ(video_bitrate) ||
++						NEQ(video_bitrate_peak)) {
+ 		err = cx2341x_api(priv, func, CX2341X_ENC_SET_BIT_RATE, 5,
+ 				new->video_bitrate_mode, new->video_bitrate,
+ 				new->video_bitrate_peak / 400, 0, 0);
+ 		if (err) return err;
+ 	}
+-	if (old == NULL || old->video_spatial_filter_mode != new->video_spatial_filter_mode ||
+-		old->video_temporal_filter_mode != new->video_temporal_filter_mode ||
+-		old->video_median_filter_type != new->video_median_filter_type) {
+-		err = cx2341x_api(priv, func, CX2341X_ENC_SET_DNR_FILTER_MODE, 2,
+-				new->video_spatial_filter_mode | (new->video_temporal_filter_mode << 1),
++	if (force || NEQ(video_spatial_filter_mode) ||
++		     NEQ(video_temporal_filter_mode) ||
++		     NEQ(video_median_filter_type)) {
++		err = cx2341x_api(priv, func, CX2341X_ENC_SET_DNR_FILTER_MODE,
++				  2, new->video_spatial_filter_mode |
++					(new->video_temporal_filter_mode << 1),
+ 				new->video_median_filter_type);
+ 		if (err) return err;
+ 	}
+-	if (old == NULL ||
+-		old->video_luma_median_filter_bottom != new->video_luma_median_filter_bottom ||
+-		old->video_luma_median_filter_top != new->video_luma_median_filter_top ||
+-		old->video_chroma_median_filter_bottom != new->video_chroma_median_filter_bottom ||
+-		old->video_chroma_median_filter_top != new->video_chroma_median_filter_top) {
++	if (force || NEQ(video_luma_median_filter_bottom) ||
++		     NEQ(video_luma_median_filter_top) ||
++		     NEQ(video_chroma_median_filter_bottom) ||
++		     NEQ(video_chroma_median_filter_top)) {
+ 		err = cx2341x_api(priv, func, CX2341X_ENC_SET_CORING_LEVELS, 4,
+ 				new->video_luma_median_filter_bottom,
+ 				new->video_luma_median_filter_top,
+@@ -865,36 +899,39 @@ int cx2341x_update(void *priv, cx2341x_mbox_func func,
+ 				new->video_chroma_median_filter_top);
+ 		if (err) return err;
+ 	}
+-	if (old == NULL ||
+-		old->video_luma_spatial_filter_type != new->video_luma_spatial_filter_type ||
+-		old->video_chroma_spatial_filter_type != new->video_chroma_spatial_filter_type) {
+-		err = cx2341x_api(priv, func, CX2341X_ENC_SET_SPATIAL_FILTER_TYPE, 2,
+-			new->video_luma_spatial_filter_type, new->video_chroma_spatial_filter_type);
++	if (force || NEQ(video_luma_spatial_filter_type) ||
++		     NEQ(video_chroma_spatial_filter_type)) {
++		err = cx2341x_api(priv, func,
++				  CX2341X_ENC_SET_SPATIAL_FILTER_TYPE,
++				  2, new->video_luma_spatial_filter_type,
++				  new->video_chroma_spatial_filter_type);
+ 		if (err) return err;
+ 	}
+-	if (old == NULL ||
+-		old->video_spatial_filter != new->video_spatial_filter ||
+-		old->video_temporal_filter != temporal) {
+-		err = cx2341x_api(priv, func, CX2341X_ENC_SET_DNR_FILTER_PROPS, 2,
+-			new->video_spatial_filter, temporal);
++	if (force || NEQ(video_spatial_filter) ||
++		     old->video_temporal_filter != temporal) {
++		err = cx2341x_api(priv, func, CX2341X_ENC_SET_DNR_FILTER_PROPS,
++				  2, new->video_spatial_filter, temporal);
+ 		if (err) return err;
+ 	}
+-	if (old == NULL || old->video_temporal_decimation != new->video_temporal_decimation) {
+-		err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_DROP_RATE, 1,
+-			new->video_temporal_decimation);
++	if (force || NEQ(video_temporal_decimation)) {
++		err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_DROP_RATE,
++				  1, new->video_temporal_decimation);
+ 		if (err) return err;
+ 	}
+-	if (old == NULL || old->video_mute != new->video_mute ||
+-			(new->video_mute && old->video_mute_yuv != new->video_mute_yuv)) {
+-		err = cx2341x_api(priv, func, CX2341X_ENC_MUTE_VIDEO, 1, new->video_mute | (new->video_mute_yuv << 8));
++	if (force || NEQ(video_mute) ||
++		(new->video_mute && NEQ(video_mute_yuv))) {
++		err = cx2341x_api(priv, func, CX2341X_ENC_MUTE_VIDEO, 1,
++				new->video_mute | (new->video_mute_yuv << 8));
+ 		if (err) return err;
+ 	}
+-	if (old == NULL || old->stream_insert_nav_packets != new->stream_insert_nav_packets) {
+-		err = cx2341x_api(priv, func, CX2341X_ENC_MISC, 2, 7, new->stream_insert_nav_packets);
++	if (force || NEQ(stream_insert_nav_packets)) {
++		err = cx2341x_api(priv, func, CX2341X_ENC_MISC, 2,
++				7, new->stream_insert_nav_packets);
+ 		if (err) return err;
+ 	}
+ 	return 0;
+ }
++EXPORT_SYMBOL(cx2341x_update);
  
-diff --git a/drivers/media/video/bt8xx/bttv-audio-hook.c b/drivers/media/video/bt8xx/bttv-audio-hook.c
-new file mode 100644
-index 0000000..2364d16
---- /dev/null
-+++ b/drivers/media/video/bt8xx/bttv-audio-hook.c
-@@ -0,0 +1,382 @@
-+/*
-+ * Handlers for board audio hooks, splitted from bttv-cards
-+ *
-+ * Copyright (c) 2006 Mauro Carvalho Chehab (mchehab at infradead.org)
-+ * This code is placed under the terms of the GNU General Public License
-+ */
-+
-+#include "bttv-audio-hook.h"
-+
-+#include <linux/delay.h>
-+
-+/* ----------------------------------------------------------------------- */
-+/* winview                                                                 */
-+
-+void winview_volume(struct bttv *btv, __u16 volume)
-+{
-+	/* PT2254A programming Jon Tombs, jon at gte.esi.us.es */
-+	int bits_out, loops, vol, data;
-+
-+	/* 32 levels logarithmic */
-+	vol = 32 - ((volume>>11));
-+	/* units */
-+	bits_out = (PT2254_DBS_IN_2>>(vol%5));
-+	/* tens */
-+	bits_out |= (PT2254_DBS_IN_10>>(vol/5));
-+	bits_out |= PT2254_L_CHANNEL | PT2254_R_CHANNEL;
-+	data = gpio_read();
-+	data &= ~(WINVIEW_PT2254_CLK| WINVIEW_PT2254_DATA|
-+		  WINVIEW_PT2254_STROBE);
-+	for (loops = 17; loops >= 0 ; loops--) {
-+		if (bits_out & (1<<loops))
-+			data |=  WINVIEW_PT2254_DATA;
-+		else
-+			data &= ~WINVIEW_PT2254_DATA;
-+		gpio_write(data);
-+		udelay(5);
-+		data |= WINVIEW_PT2254_CLK;
-+		gpio_write(data);
-+		udelay(5);
-+		data &= ~WINVIEW_PT2254_CLK;
-+		gpio_write(data);
-+	}
-+	data |=  WINVIEW_PT2254_STROBE;
-+	data &= ~WINVIEW_PT2254_DATA;
-+	gpio_write(data);
-+	udelay(10);
-+	data &= ~WINVIEW_PT2254_STROBE;
-+	gpio_write(data);
-+}
-+
-+/* ----------------------------------------------------------------------- */
-+/* mono/stereo control for various cards (which don't use i2c chips but    */
-+/* connect something to the GPIO pins                                      */
-+
-+void gvbctv3pci_audio(struct bttv *btv, struct v4l2_tuner *t, int set)
-+{
-+	unsigned int con = 0;
-+
-+	if (set) {
-+		gpio_inout(0x300, 0x300);
-+		if (t->audmode & V4L2_TUNER_MODE_LANG1)
-+			con = 0x000;
-+		if (t->audmode & V4L2_TUNER_MODE_LANG2)
-+			con = 0x300;
-+		if (t->audmode & V4L2_TUNER_MODE_STEREO)
-+			con = 0x200;
-+/*		if (t->audmode & V4L2_TUNER_MODE_MONO)
-+ *			con = 0x100; */
-+		gpio_bits(0x300, con);
-+	} else {
-+		t->audmode = V4L2_TUNER_MODE_STEREO |
-+			  V4L2_TUNER_MODE_LANG1  | V4L2_TUNER_MODE_LANG2;
-+	}
-+}
-+
-+void gvbctv5pci_audio(struct bttv *btv, struct v4l2_tuner *t, int set)
-+{
-+	unsigned int val, con;
-+
-+	if (btv->radio_user)
-+		return;
-+
-+	val = gpio_read();
-+	if (set) {
-+		con = 0x000;
-+		if (t->audmode & V4L2_TUNER_MODE_LANG2) {
-+			if (t->audmode & V4L2_TUNER_MODE_LANG1) {
-+				/* LANG1 + LANG2 */
-+				con = 0x100;
-+			}
-+			else {
-+				/* LANG2 */
-+				con = 0x300;
-+			}
-+		}
-+		if (con != (val & 0x300)) {
-+			gpio_bits(0x300, con);
-+			if (bttv_gpio)
-+				bttv_gpio_tracking(btv,"gvbctv5pci");
-+		}
-+	} else {
-+		switch (val & 0x70) {
-+		  case 0x10:
-+			t->rxsubchans = V4L2_TUNER_SUB_LANG1 |  V4L2_TUNER_SUB_LANG2;
-+			break;
-+		  case 0x30:
-+			t->rxsubchans = V4L2_TUNER_SUB_LANG2;
-+			break;
-+		  case 0x50:
-+			t->rxsubchans = V4L2_TUNER_SUB_LANG1;
-+			break;
-+		  case 0x60:
-+			t->rxsubchans = V4L2_TUNER_SUB_STEREO;
-+			break;
-+		  case 0x70:
-+			t->rxsubchans = V4L2_TUNER_SUB_MONO;
-+			break;
-+		  default:
-+			t->rxsubchans = V4L2_TUNER_SUB_MONO |
-+					 V4L2_TUNER_SUB_STEREO |
-+					 V4L2_TUNER_SUB_LANG1 |
-+					 V4L2_TUNER_SUB_LANG2;
-+		}
-+		t->audmode = V4L2_TUNER_MODE_STEREO |
-+			  V4L2_TUNER_MODE_LANG1  | V4L2_TUNER_MODE_LANG2;
-+	}
-+}
-+
-+/*
-+ * Mario Medina Nussbaum <medisoft at alohabbs.org.mx>
-+ *  I discover that on BT848_GPIO_DATA address a byte 0xcce enable stereo,
-+ *  0xdde enables mono and 0xccd enables sap
-+ *
-+ * Petr Vandrovec <VANDROVE at vc.cvut.cz>
-+ *  P.S.: At least mask in line above is wrong - GPIO pins 3,2 select
-+ *  input/output sound connection, so both must be set for output mode.
-+ *
-+ * Looks like it's needed only for the "tvphone", the "tvphone 98"
-+ * handles this with a tda9840
-+ *
-+ */
-+
-+void avermedia_tvphone_audio(struct bttv *btv, struct v4l2_tuner *t, int set)
-+{
-+	int val = 0;
-+
-+	if (set) {
-+		if (t->audmode & V4L2_TUNER_MODE_LANG2)   /* SAP */
-+			val = 0x02;
-+		if (t->audmode & V4L2_TUNER_MODE_STEREO)
-+			val = 0x01;
-+		if (val) {
-+			gpio_bits(0x03,val);
-+			if (bttv_gpio)
-+				bttv_gpio_tracking(btv,"avermedia");
-+		}
-+	} else {
-+		t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO |
-+			V4L2_TUNER_MODE_LANG1;
-+		return;
-+	}
-+}
-+
-+
-+void avermedia_tv_stereo_audio(struct bttv *btv, struct v4l2_tuner *t, int set)
-+{
-+	int val = 0;
-+
-+	if (set) {
-+		if (t->audmode & V4L2_TUNER_MODE_LANG2)   /* SAP */
-+			val = 0x01;
-+		if (t->audmode & V4L2_TUNER_MODE_STEREO)  /* STEREO */
-+			val = 0x02;
-+		btaor(val, ~0x03, BT848_GPIO_DATA);
-+		if (bttv_gpio)
-+			bttv_gpio_tracking(btv,"avermedia");
-+	} else {
-+		t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO |
-+			V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2;
-+		return;
-+	}
-+}
-+
-+/* Lifetec 9415 handling */
-+
-+void lt9415_audio(struct bttv *btv, struct v4l2_tuner *t, int set)
-+{
-+	int val = 0;
-+
-+	if (gpio_read() & 0x4000) {
-+		t->audmode = V4L2_TUNER_MODE_MONO;
-+		return;
-+	}
-+
-+	if (set) {
-+		if (t->audmode & V4L2_TUNER_MODE_LANG2)  /* A2 SAP */
-+			val = 0x0080;
-+		if (t->audmode & V4L2_TUNER_MODE_STEREO) /* A2 stereo */
-+			val = 0x0880;
-+		if ((t->audmode & V4L2_TUNER_MODE_LANG1) ||
-+		    (t->audmode & V4L2_TUNER_MODE_MONO))
-+			val = 0;
-+		gpio_bits(0x0880, val);
-+		if (bttv_gpio)
-+			bttv_gpio_tracking(btv,"lt9415");
-+	} else {
-+		/* autodetect doesn't work with this card :-( */
-+		t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO |
-+			V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2;
-+		return;
-+	}
-+}
-+
-+/* TDA9821 on TerraTV+ Bt848, Bt878 */
-+void terratv_audio(struct bttv *btv,  struct v4l2_tuner *t, int set)
-+{
-+	unsigned int con = 0;
-+
-+	if (set) {
-+		gpio_inout(0x180000,0x180000);
-+		if (t->audmode & V4L2_TUNER_MODE_LANG2)
-+			con = 0x080000;
-+		if (t->audmode & V4L2_TUNER_MODE_STEREO)
-+			con = 0x180000;
-+		gpio_bits(0x180000, con);
-+		if (bttv_gpio)
-+			bttv_gpio_tracking(btv,"terratv");
-+	} else {
-+		t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO |
-+			V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2;
-+	}
-+}
-+
-+
-+void winfast2000_audio(struct bttv *btv, struct v4l2_tuner *t, int set)
-+{
-+	unsigned long val = 0;
-+
-+	if (set) {
-+		/*btor (0xc32000, BT848_GPIO_OUT_EN);*/
-+		if (t->audmode & V4L2_TUNER_MODE_MONO)		/* Mono */
-+			val = 0x420000;
-+		if (t->audmode & V4L2_TUNER_MODE_LANG1)	/* Mono */
-+			val = 0x420000;
-+		if (t->audmode & V4L2_TUNER_MODE_LANG2)	/* SAP */
-+			val = 0x410000;
-+		if (t->audmode & V4L2_TUNER_MODE_STEREO)	/* Stereo */
-+			val = 0x020000;
-+		if (val) {
-+			gpio_bits(0x430000, val);
-+			if (bttv_gpio)
-+				bttv_gpio_tracking(btv,"winfast2000");
-+		}
-+	} else {
-+		t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO |
-+			  V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2;
-+	}
-+}
-+
-+/*
-+ * Dariusz Kowalewski <darekk at automex.pl>
-+ * sound control for Prolink PV-BT878P+9B (PixelView PlayTV Pro FM+NICAM
-+ * revision 9B has on-board TDA9874A sound decoder).
-+ *
-+ * Note: There are card variants without tda9874a. Forcing the "stereo sound route"
-+ *       will mute this cards.
-+ */
-+void pvbt878p9b_audio(struct bttv *btv, struct v4l2_tuner *t, int set)
-+{
-+	unsigned int val = 0;
-+
-+	if (btv->radio_user)
-+		return;
+ static const char *cx2341x_menu_item(struct cx2341x_mpeg_params *p, u32 id)
+ {
+@@ -943,18 +980,17 @@ void cx2341x_log_status(struct cx2341x_mpeg_params *p, const char *prefix)
+ 		cx2341x_menu_item(p, V4L2_CID_MPEG_VIDEO_ASPECT),
+ 		cx2341x_menu_item(p, V4L2_CID_MPEG_VIDEO_BITRATE_MODE),
+ 		p->video_bitrate);
+-	if (p->video_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) {
++	if (p->video_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR)
+ 		printk(", Peak %d", p->video_bitrate_peak);
+-	}
+ 	printk("\n");
+-	printk(KERN_INFO "%s: Video:  GOP Size %d, %d B-Frames, %sGOP Closure\n",
++	printk(KERN_INFO
++		"%s: Video:  GOP Size %d, %d B-Frames, %sGOP Closure\n",
+ 		prefix,
+ 		p->video_gop_size, p->video_b_frames,
+ 		p->video_gop_closure ? "" : "No ");
+-	if (p->video_temporal_decimation) {
++	if (p->video_temporal_decimation)
+ 		printk(KERN_INFO "%s: Video: Temporal Decimation %d\n",
+ 			prefix, p->video_temporal_decimation);
+-	}
+ 
+ 	/* Audio */
+ 	printk(KERN_INFO "%s: Audio:  %s, %s, %s, %s%s",
+@@ -964,10 +1000,9 @@ void cx2341x_log_status(struct cx2341x_mpeg_params *p, const char *prefix)
+ 		cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_L2_BITRATE),
+ 		cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_MODE),
+ 		p->audio_mute ? " (muted)" : "");
+-	if (p->audio_mode == V4L2_MPEG_AUDIO_MODE_JOINT_STEREO) {
+-		printk(", %s",
+-			cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_MODE_EXTENSION));
+-	}
++	if (p->audio_mode == V4L2_MPEG_AUDIO_MODE_JOINT_STEREO)
++		printk(", %s", cx2341x_menu_item(p,
++				V4L2_CID_MPEG_AUDIO_MODE_EXTENSION));
+ 	printk(", %s, %s\n",
+ 		cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_EMPHASIS),
+ 		cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_CRC));
+@@ -975,33 +1010,33 @@ void cx2341x_log_status(struct cx2341x_mpeg_params *p, const char *prefix)
+ 	/* Encoding filters */
+ 	printk(KERN_INFO "%s: Spatial Filter:  %s, Luma %s, Chroma %s, %d\n",
+ 		prefix,
+-		cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE),
+-		cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE),
+-		cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE),
++		cx2341x_menu_item(p,
++		    V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE),
++		cx2341x_menu_item(p,
++		    V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE),
++		cx2341x_menu_item(p,
++		    V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE),
+ 		p->video_spatial_filter);
+-	if (p->width != 720 || p->height != (p->is_50hz ? 576 : 480)) {
 +
-+	if (set) {
-+		if (t->audmode & V4L2_TUNER_MODE_MONO)	{
-+			val = 0x01;
-+		}
-+		if ((t->audmode & (V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2))
-+		    || (t->audmode & V4L2_TUNER_MODE_STEREO)) {
-+			val = 0x02;
-+		}
-+		if (val) {
-+			gpio_bits(0x03,val);
-+			if (bttv_gpio)
-+				bttv_gpio_tracking(btv,"pvbt878p9b");
-+		}
-+	} else {
-+		t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO |
-+			V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2;
-+	}
-+}
++	if (p->width != 720 || p->height != (p->is_50hz ? 576 : 480))
+ 		temporal = 0;
+-	}
 +
-+/*
-+ * Dariusz Kowalewski <darekk at automex.pl>
-+ * sound control for FlyVideo 2000S (with tda9874 decoder)
-+ * based on pvbt878p9b_audio() - this is not tested, please fix!!!
+ 	printk(KERN_INFO "%s: Temporal Filter: %s, %d\n",
+ 		prefix,
+-		cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE),
++		cx2341x_menu_item(p,
++			V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE),
+ 		temporal);
+-	printk(KERN_INFO "%s: Median Filter:   %s, Luma [%d, %d], Chroma [%d, %d]\n",
++	printk(KERN_INFO
++		"%s: Median Filter:   %s, Luma [%d, %d], Chroma [%d, %d]\n",
+ 		prefix,
+-		cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE),
++		cx2341x_menu_item(p,
++			V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE),
+ 		p->video_luma_median_filter_bottom,
+ 		p->video_luma_median_filter_top,
+ 		p->video_chroma_median_filter_bottom,
+ 		p->video_chroma_median_filter_top);
+ }
+-
+-EXPORT_SYMBOL(cx2341x_fill_defaults);
+-EXPORT_SYMBOL(cx2341x_ctrl_query);
+-EXPORT_SYMBOL(cx2341x_ctrl_get_menu);
+-EXPORT_SYMBOL(cx2341x_ext_ctrls);
+-EXPORT_SYMBOL(cx2341x_update);
+ EXPORT_SYMBOL(cx2341x_log_status);
+-EXPORT_SYMBOL(cx2341x_mpeg_ctrls);
+ 
+ /*
+  * Local variables:
+diff --git a/drivers/media/video/cx23885/Kconfig b/drivers/media/video/cx23885/Kconfig
+index 081ee6e..1fd326f 100644
+--- a/drivers/media/video/cx23885/Kconfig
++++ b/drivers/media/video/cx23885/Kconfig
+@@ -12,6 +12,10 @@ config VIDEO_CX23885
+ 	select DVB_S5H1409 if !DVB_FE_CUSTOMISE
+ 	select DVB_LGDT330X if !DVB_FE_CUSTOMISE
+ 	select DVB_PLL if !DVB_FE_CUSTOMISE
++	select TUNER_XC2028 if !DVB_FE_CUSTOMIZE
++	select TUNER_TDA8290 if !DVB_FE_CUSTOMIZE
++	select DVB_TDA18271 if !DVB_FE_CUSTOMIZE
++	select DVB_TUNER_XC5000 if !DVB_FE_CUSTOMIZE
+ 	---help---
+ 	  This is a video4linux driver for Conexant 23885 based
+ 	  TV cards.
+diff --git a/drivers/media/video/cx23885/Makefile b/drivers/media/video/cx23885/Makefile
+index 6650670..32c90be 100644
+--- a/drivers/media/video/cx23885/Makefile
++++ b/drivers/media/video/cx23885/Makefile
+@@ -1,4 +1,4 @@
+-cx23885-objs	:= cx23885-cards.o cx23885-core.o cx23885-i2c.o cx23885-dvb.o
++cx23885-objs	:= cx23885-cards.o cx23885-video.o cx23885-vbi.o cx23885-core.o cx23885-i2c.o cx23885-dvb.o
+ 
+ obj-$(CONFIG_VIDEO_CX23885) += cx23885.o
+ 
+diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c
+index b9012ac..2d414da 100644
+--- a/drivers/media/video/cx23885/cx23885-cards.c
++++ b/drivers/media/video/cx23885/cx23885-cards.c
+@@ -23,6 +23,7 @@
+ #include <linux/module.h>
+ #include <linux/pci.h>
+ #include <linux/delay.h>
++#include <media/cx25840.h>
+ 
+ #include "cx23885.h"
+ 
+@@ -32,6 +33,8 @@
+ struct cx23885_board cx23885_boards[] = {
+ 	[CX23885_BOARD_UNKNOWN] = {
+ 		.name		= "UNKNOWN/GENERIC",
++		/* Ensure safe default for unknown boards */
++		.clk_freq       = 0,
+ 		.input          = {{
+ 			.type   = CX23885_VMUX_COMPOSITE1,
+ 			.vmux   = 0,
+@@ -69,23 +72,29 @@ struct cx23885_board cx23885_boards[] = {
+ 	},
+ 	[CX23885_BOARD_HAUPPAUGE_HVR1800] = {
+ 		.name		= "Hauppauge WinTV-HVR1800",
++		.porta		= CX23885_ANALOG_VIDEO,
+ 		.portc		= CX23885_MPEG_DVB,
++		.tuner_type	= TUNER_PHILIPS_TDA8290,
++		.tuner_addr	= 0x42, /* 0x84 >> 1 */
+ 		.input          = {{
+ 			.type   = CX23885_VMUX_TELEVISION,
+-			.vmux   = 0,
+-			.gpio0  = 0xff00,
+-		},{
+-			.type   = CX23885_VMUX_DEBUG,
+-			.vmux   = 0,
+-			.gpio0  = 0xff01,
++			.vmux   =	CX25840_VIN7_CH3 |
++					CX25840_VIN5_CH2 |
++					CX25840_VIN2_CH1,
++			.gpio0  = 0,
+ 		},{
+ 			.type   = CX23885_VMUX_COMPOSITE1,
+-			.vmux   = 1,
+-			.gpio0  = 0xff02,
++			.vmux   =	CX25840_VIN7_CH3 |
++					CX25840_VIN4_CH2 |
++					CX25840_VIN6_CH1,
++			.gpio0  = 0,
+ 		},{
+ 			.type   = CX23885_VMUX_SVIDEO,
+-			.vmux   = 2,
+-			.gpio0  = 0xff02,
++			.vmux   =	CX25840_VIN7_CH3 |
++					CX25840_VIN4_CH2 |
++					CX25840_VIN8_CH1 |
++					CX25840_SVIDEO_ON,
++			.gpio0  = 0,
+ 		}},
+ 	},
+ 	[CX23885_BOARD_HAUPPAUGE_HVR1250] = {
+@@ -113,6 +122,14 @@ struct cx23885_board cx23885_boards[] = {
+ 		.name		= "DViCO FusionHDTV5 Express",
+ 		.portb		= CX23885_MPEG_DVB,
+ 	},
++	[CX23885_BOARD_HAUPPAUGE_HVR1500Q] = {
++		.name		= "Hauppauge WinTV-HVR1500Q",
++		.portc		= CX23885_MPEG_DVB,
++	},
++	[CX23885_BOARD_HAUPPAUGE_HVR1500] = {
++		.name		= "Hauppauge WinTV-HVR1500",
++		.portc		= CX23885_MPEG_DVB,
++	},
+ };
+ const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards);
+ 
+@@ -138,12 +155,32 @@ struct cx23885_subid cx23885_subids[] = {
+ 		.card      = CX23885_BOARD_HAUPPAUGE_HVR1800,
+ 	},{
+ 		.subvendor = 0x0070,
++		.subdevice = 0x7809,
++		.card      = CX23885_BOARD_HAUPPAUGE_HVR1800,
++	},{
++		.subvendor = 0x0070,
+ 		.subdevice = 0x7911,
+ 		.card      = CX23885_BOARD_HAUPPAUGE_HVR1250,
+ 	},{
+ 		.subvendor = 0x18ac,
+ 		.subdevice = 0xd500,
+ 		.card      = CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP,
++	},{
++		.subvendor = 0x0070,
++		.subdevice = 0x7790,
++		.card      = CX23885_BOARD_HAUPPAUGE_HVR1500Q,
++	},{
++		.subvendor = 0x0070,
++		.subdevice = 0x7797,
++		.card      = CX23885_BOARD_HAUPPAUGE_HVR1500Q,
++	},{
++		.subvendor = 0x0070,
++		.subdevice = 0x7710,
++		.card      = CX23885_BOARD_HAUPPAUGE_HVR1500,
++	},{
++		.subvendor = 0x0070,
++		.subdevice = 0x7717,
++		.card      = CX23885_BOARD_HAUPPAUGE_HVR1500,
+ 	},
+ };
+ const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids);
+@@ -184,9 +221,19 @@ static void hauppauge_eeprom(struct cx23885_dev *dev, u8 *eeprom_data)
+ 	switch (tv.model)
+ 	{
+ 	case 76601: /* WinTV-HVR1800lp (PCIe, Retail, No IR, Dual channel ATSC and MPEG2 HW Encoder */
+-	case 77001: /* WinTV-HVR1500 (Express Card, Retail, No IR, ATSC and Basic analog */
+-	case 78501: /* WinTV-HVR1800 (PCIe, Retail, IR, Dual channel ATSC and MPEG2 HW Encoder */
+-	case 78521: /* WinTV-HVR1800 (PCIe, Retail, IR, Dual channel ATSC and MPEG2 HW Encoder */
++	case 77001: /* WinTV-HVR1500 (Express Card, OEM, No IR, ATSC and Basic analog */
++	case 77011: /* WinTV-HVR1500 (Express Card, Retail, No IR, ATSC and Basic analog */
++	case 77041: /* WinTV-HVR1500Q (Express Card, OEM, No IR, ATSC/QAM and Basic analog */
++	case 77051: /* WinTV-HVR1500Q (Express Card, Retail, No IR, ATSC/QAM and Basic analog */
++	case 78011: /* WinTV-HVR1800 (PCIe, Retail, 3.5mm in, IR, No FM, Dual channel ATSC and MPEG2 HW Encoder */
++	case 78501: /* WinTV-HVR1800 (PCIe, OEM, RCA in, No IR, FM, Dual channel ATSC and MPEG2 HW Encoder */
++	case 78521: /* WinTV-HVR1800 (PCIe, OEM, RCA in, No IR, FM, Dual channel ATSC and MPEG2 HW Encoder */
++	case 78531: /* WinTV-HVR1800 (PCIe, OEM, RCA in, No IR, No FM, Dual channel ATSC and MPEG2 HW Encoder */
++	case 78631: /* WinTV-HVR1800 (PCIe, OEM, No IR, No FM, Dual channel ATSC and MPEG2 HW Encoder */
++	case 79001: /* WinTV-HVR1250 (PCIe, Retail, IR, full height, ATSC and Basic analog */
++	case 79101: /* WinTV-HVR1250 (PCIe, Retail, IR, half height, ATSC and Basic analog */
++	case 79571: /* WinTV-HVR1250 (PCIe, OEM, No IR, full height, ATSC and Basic analog */
++	case 79671: /* WinTV-HVR1250 (PCIe, OEM, No IR, half height, ATSC and Basic analog */
+ 		break;
+ 	default:
+ 		printk("%s: warning: unknown hauppauge model #%d\n", dev->name, tv.model);
+@@ -197,6 +244,34 @@ static void hauppauge_eeprom(struct cx23885_dev *dev, u8 *eeprom_data)
+ 			dev->name, tv.model);
+ }
+ 
++/* Tuner callback function for cx23885 boards. Currently only needed
++ * for HVR1500Q, which has an xc5000 tuner.
 + */
-+void fv2000s_audio(struct bttv *btv, struct v4l2_tuner *t, int set)
++int cx23885_tuner_callback(void *priv, int command, int arg)
 +{
-+	unsigned int val = 0xffff;
-+
-+	if (btv->radio_user)
-+		return;
++	struct cx23885_i2c *bus = priv;
++	struct cx23885_dev *dev = bus->dev;
 +
-+	if (set) {
-+		if (t->audmode & V4L2_TUNER_MODE_MONO)	{
-+			val = 0x0000;
-+		}
-+		if ((t->audmode & (V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2))
-+		    || (t->audmode & V4L2_TUNER_MODE_STEREO)) {
-+			val = 0x1080; /*-dk-???: 0x0880, 0x0080, 0x1800 ... */
-+		}
-+		if (val != 0xffff) {
-+			gpio_bits(0x1800, val);
-+			if (bttv_gpio)
-+				bttv_gpio_tracking(btv,"fv2000s");
++	switch(dev->board) {
++	case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
++		if(command == 0) {	/* Tuner Reset Command from xc5000 */
++			/* Drive the tuner into reset and out */
++			cx_clear(GP0_IO, 0x00000004);
++			mdelay(200);
++			cx_set(GP0_IO, 0x00000004);
++			return 0;
 +		}
-+	} else {
-+		t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO |
-+			V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2;
-+	}
-+}
-+
-+/*
-+ * sound control for Canopus WinDVR PCI
-+ * Masaki Suzuki <masaki at btree.org>
-+ */
-+void windvr_audio(struct bttv *btv, struct v4l2_tuner *t, int set)
-+{
-+	unsigned long val = 0;
-+
-+	if (set) {
-+		if (t->audmode & V4L2_TUNER_MODE_MONO)
-+			val = 0x040000;
-+		if (t->audmode & V4L2_TUNER_MODE_LANG1)
-+			val = 0;
-+		if (t->audmode & V4L2_TUNER_MODE_LANG2)
-+			val = 0x100000;
-+		if (t->audmode & V4L2_TUNER_MODE_STEREO)
-+			val = 0;
-+		if (val) {
-+			gpio_bits(0x140000, val);
-+			if (bttv_gpio)
-+				bttv_gpio_tracking(btv,"windvr");
++		else {
++			printk(KERN_ERR
++				"%s(): Unknow command.\n", __FUNCTION__);
++			return -EINVAL;
 +		}
-+	} else {
-+		t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO |
-+			  V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2;
++		break;
 +	}
-+}
-+
-+/*
-+ * sound control for AD-TVK503
-+ * Hiroshi Takekawa <sian at big.or.jp>
-+ */
-+void adtvk503_audio(struct bttv *btv, struct v4l2_tuner *t, int set)
-+{
-+	unsigned int con = 0xffffff;
-+
-+	/* btaor(0x1e0000, ~0x1e0000, BT848_GPIO_OUT_EN); */
 +
-+	if (set) {
-+		/* btor(***, BT848_GPIO_OUT_EN); */
-+		if (t->audmode & V4L2_TUNER_MODE_LANG1)
-+			con = 0x00000000;
-+		if (t->audmode & V4L2_TUNER_MODE_LANG2)
-+			con = 0x00180000;
-+		if (t->audmode & V4L2_TUNER_MODE_STEREO)
-+			con = 0x00000000;
-+		if (t->audmode & V4L2_TUNER_MODE_MONO)
-+			con = 0x00060000;
-+		if (con != 0xffffff) {
-+			gpio_bits(0x1e0000,con);
-+			if (bttv_gpio)
-+				bttv_gpio_tracking(btv, "adtvk503");
-+		}
-+	} else {
-+		t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO |
-+			  V4L2_TUNER_MODE_LANG1  | V4L2_TUNER_MODE_LANG2;
-+	}
++	return 0; /* Should never be here */
 +}
-diff --git a/drivers/media/video/bt8xx/bttv-audio-hook.h b/drivers/media/video/bt8xx/bttv-audio-hook.h
-new file mode 100644
-index 0000000..159d07a
---- /dev/null
-+++ b/drivers/media/video/bt8xx/bttv-audio-hook.h
-@@ -0,0 +1,23 @@
-+/*
-+ * Handlers for board audio hooks, splitted from bttv-cards
-+ *
-+ * Copyright (c) 2006 Mauro Carvalho Chehab (mchehab at infradead.org)
-+ * This code is placed under the terms of the GNU General Public License
-+ */
 +
-+#include "bttvp.h"
+ void cx23885_gpio_setup(struct cx23885_dev *dev)
+ {
+ 	switch(dev->board) {
+@@ -204,6 +279,23 @@ void cx23885_gpio_setup(struct cx23885_dev *dev)
+ 		/* GPIO-0 cx24227 demodulator reset */
+ 		cx_set(GP0_IO, 0x00010001); /* Bring the part out of reset */
+ 		break;
++	case CX23885_BOARD_HAUPPAUGE_HVR1500:
++		/* GPIO-0 cx24227 demodulator */
++		/* GPIO-2 xc3028 tuner */
 +
-+void winview_volume (struct bttv *btv, __u16 volume);
++		/* Put the parts into reset */
++		cx_set(GP0_IO, 0x00050000);
++		cx_clear(GP0_IO, 0x00000005);
++		msleep(5);
 +
-+void lt9415_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set);
-+void avermedia_tvphone_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set);
-+void avermedia_tv_stereo_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set);
-+void terratv_audio(struct bttv *btv,  struct v4l2_tuner *tuner, int set);
-+void gvbctv3pci_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set);
-+void gvbctv5pci_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set);
-+void winfast2000_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set);
-+void pvbt878p9b_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set);
-+void fv2000s_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set);
-+void windvr_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set);
-+void adtvk503_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set);
++		/* Bring the parts out of reset */
++		cx_set(GP0_IO, 0x00050005);
++		break;
++	case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
++		/* GPIO-0 cx24227 demodulator reset */
++		/* GPIO-2 xc5000 tuner reset */
++		cx_set(GP0_IO, 0x00050005); /* Bring the part out of reset */
++		break;
+ 	case CX23885_BOARD_HAUPPAUGE_HVR1800:
+ 		/* GPIO-0 656_CLK */
+ 		/* GPIO-1 656_D0 */
+@@ -212,7 +304,14 @@ void cx23885_gpio_setup(struct cx23885_dev *dev)
+ 		/* GPIO-11-14 cx23417 addr0-3 */
+ 		/* GPIO-15-18 cx23417 READY, CS, RD, WR */
+ 		/* GPIO-19 IR_RX */
+-		// FIXME: Analog requires the tuner is brought out of reset
 +
-diff --git a/drivers/media/video/bt8xx/bttv-cards.c b/drivers/media/video/bt8xx/bttv-cards.c
-index 585d1ef..63a47cd 100644
---- a/drivers/media/video/bt8xx/bttv-cards.c
-+++ b/drivers/media/video/bt8xx/bttv-cards.c
-@@ -39,6 +39,7 @@
- #include "bttvp.h"
- #include <media/v4l2-common.h>
- #include <media/tvaudio.h>
-+#include "bttv-audio-hook.h"
++		/* Force the TDA8295A into reset and back */
++		cx_set(GP0_IO, 0x00040004);
++		mdelay(20);
++		cx_clear(GP0_IO, 0x00000004);
++		mdelay(20);
++		cx_set(GP0_IO, 0x00040004);
++		mdelay(20);
+ 		break;
+ 	}
+ }
+@@ -221,6 +320,8 @@ int cx23885_ir_init(struct cx23885_dev *dev)
+ {
+ 	switch (dev->board) {
+ 	case CX23885_BOARD_HAUPPAUGE_HVR1250:
++	case CX23885_BOARD_HAUPPAUGE_HVR1500:
++	case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
+ 	case CX23885_BOARD_HAUPPAUGE_HVR1800:
+ 		/* FIXME: Implement me */
+ 		break;
+@@ -244,6 +345,8 @@ void cx23885_card_setup(struct cx23885_dev *dev)
  
- /* fwd decl */
- static void boot_msp34xx(struct bttv *btv, int pin);
-@@ -50,20 +51,6 @@ static void modtec_eeprom(struct bttv *btv);
- static void init_PXC200(struct bttv *btv);
- static void init_RTV24(struct bttv *btv);
+ 	switch (dev->board) {
+ 	case CX23885_BOARD_HAUPPAUGE_HVR1250:
++	case CX23885_BOARD_HAUPPAUGE_HVR1500:
++	case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
+ 	case CX23885_BOARD_HAUPPAUGE_HVR1800:
+ 	case CX23885_BOARD_HAUPPAUGE_HVR1800lp:
+ 		if (dev->i2c_bus[0].i2c_rc == 0)
+@@ -258,6 +361,8 @@ void cx23885_card_setup(struct cx23885_dev *dev)
+ 		ts1->src_sel_val   = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
+ 		break;
+ 	case CX23885_BOARD_HAUPPAUGE_HVR1250:
++	case CX23885_BOARD_HAUPPAUGE_HVR1500:
++	case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
+ 	case CX23885_BOARD_HAUPPAUGE_HVR1800:
+ 	case CX23885_BOARD_HAUPPAUGE_HVR1800lp:
+ 	default:
+@@ -270,8 +375,6 @@ void cx23885_card_setup(struct cx23885_dev *dev)
  
--static void winview_audio(struct bttv *btv, struct video_audio *v, int set);
--static void lt9415_audio(struct bttv *btv, struct video_audio *v, int set);
--static void avermedia_tvphone_audio(struct bttv *btv, struct video_audio *v,
--				    int set);
--static void avermedia_tv_stereo_audio(struct bttv *btv, struct video_audio *v,
--				      int set);
--static void terratv_audio(struct bttv *btv, struct video_audio *v, int set);
--static void gvbctv3pci_audio(struct bttv *btv, struct video_audio *v, int set);
--static void gvbctv5pci_audio(struct bttv *btv, struct video_audio *v, int set);
--static void winfast2000_audio(struct bttv *btv, struct video_audio *v, int set);
--static void pvbt878p9b_audio(struct bttv *btv, struct video_audio *v, int set);
--static void fv2000s_audio(struct bttv *btv, struct video_audio *v, int set);
--static void windvr_audio(struct bttv *btv, struct video_audio *v, int set);
--static void adtvk503_audio(struct bttv *btv, struct video_audio *v, int set);
- static void rv605_muxsel(struct bttv *btv, unsigned int input);
- static void eagle_muxsel(struct bttv *btv, unsigned int input);
- static void xguard_muxsel(struct bttv *btv, unsigned int input);
-@@ -427,7 +414,7 @@ struct tvcard bttv_tvcards[] = {
- 		.tuner_type	= UNSET,
- 		.tuner_addr	= ADDR_UNSET,
- 		.radio_addr     = ADDR_UNSET,
--		.audio_hook	= avermedia_tvphone_audio,
-+		.audio_mode_gpio= avermedia_tvphone_audio,
- 		.has_remote     = 1,
- 	},
- 	[BTTV_BOARD_MATRIX_VISION] = {
-@@ -539,7 +526,7 @@ struct tvcard bttv_tvcards[] = {
- 		.tuner_type	= TUNER_PHILIPS_PAL,
- 		.tuner_addr	= ADDR_UNSET,
- 		.radio_addr     = ADDR_UNSET,
--		.audio_hook     = avermedia_tv_stereo_audio,
-+		.audio_mode_gpio= avermedia_tv_stereo_audio,
- 		.no_gpioirq     = 1,
- 	},
- 	[BTTV_BOARD_VHX] = {
-@@ -604,7 +591,7 @@ struct tvcard bttv_tvcards[] = {
- 		.tuner_type	= UNSET,
- 		.tuner_addr	= ADDR_UNSET,
- 		.radio_addr     = ADDR_UNSET,
--		.audio_hook	= winview_audio,
-+		.volume_gpio	= winview_volume,
- 		.has_radio	= 1,
- 	},
- 	[BTTV_BOARD_AVEC_INTERCAP] = {
-@@ -728,7 +715,7 @@ struct tvcard bttv_tvcards[] = {
- 		.tuner_type	= TUNER_PHILIPS_PAL,
- 		.tuner_addr	= ADDR_UNSET,
- 		.radio_addr     = ADDR_UNSET,
--		.audio_hook     = terratv_audio,
-+		.audio_mode_gpio= terratv_audio,
- 	},
- 	[BTTV_BOARD_HAUPPAUG_WCAM] = {
- 		.name		= "Hauppauge WinCam newer (bt878)",
-@@ -776,7 +763,7 @@ struct tvcard bttv_tvcards[] = {
- 		.tuner_type	= TUNER_PHILIPS_PAL,
- 		.tuner_addr	= ADDR_UNSET,
- 		.radio_addr     = ADDR_UNSET,
--		.audio_hook	= terratv_audio,
-+		.audio_mode_gpio= terratv_audio,
- 		/* GPIO wiring:
- 		External 20 pin connector (for Active Radio Upgrade board)
- 		gpio00: i2c-sda
-@@ -915,7 +902,7 @@ struct tvcard bttv_tvcards[] = {
- 		.tuner_type	= TUNER_PHILIPS_PAL, /* default for now, gpio reads BFFF06 for Pal bg+dk */
- 		.tuner_addr	= ADDR_UNSET,
- 		.radio_addr     = ADDR_UNSET,
--		.audio_hook	= winfast2000_audio,
-+		.audio_mode_gpio= winfast2000_audio,
- 		.has_remote     = 1,
- 	},
- 	[BTTV_BOARD_CHRONOS_VS2] = {
-@@ -1035,7 +1022,7 @@ struct tvcard bttv_tvcards[] = {
- 		.tuner_addr	= ADDR_UNSET,
- 		.radio_addr     = ADDR_UNSET,
- 		.has_radio	= 1,
--		.audio_hook	= avermedia_tvphone_audio,
-+		.audio_mode_gpio= avermedia_tvphone_audio,
- 	},
- 	[BTTV_BOARD_PV951] = {
- 		.name		= "ProVideo PV951", /* pic16c54 */
-@@ -1167,7 +1154,7 @@ struct tvcard bttv_tvcards[] = {
- 		.tuner_type	= TUNER_ALPS_TSHC6_NTSC,
- 		.tuner_addr	= ADDR_UNSET,
- 		.radio_addr     = ADDR_UNSET,
--		.audio_hook	= gvbctv3pci_audio,
-+		.audio_mode_gpio= gvbctv3pci_audio,
- 	},
- 	[BTTV_BOARD_PXELVWPLTVPAK] = {
- 		.name		= "Prolink PV-BT878P+4E / PixelView PlayTV PAK / Lenco MXTV-9578 CP",
-@@ -1472,7 +1459,7 @@ struct tvcard bttv_tvcards[] = {
- 				/* -dk-???: set mute=0x1800 for tda9874h daughterboard */
- 		.gpiomux 	= { 0x0000,0x0800,0x1000,0x1000 },
- 		.gpiomute 	= 0x1800,
--		.audio_hook	= fv2000s_audio,
-+		.audio_mode_gpio= fv2000s_audio,
- 		.no_msp34xx	= 1,
- 		.no_tda9875	= 1,
- 		.needs_tvaudio  = 1,
-@@ -1513,7 +1500,7 @@ struct tvcard bttv_tvcards[] = {
- 		.tuner_type     = TUNER_SHARP_2U5JF5540_NTSC,
- 		.tuner_addr	= ADDR_UNSET,
- 		.radio_addr     = ADDR_UNSET,
--		.audio_hook     = gvbctv3pci_audio,
-+		.audio_mode_gpio= gvbctv3pci_audio,
- 	},
+ /* ------------------------------------------------------------------ */
  
- 	/* ---- card 0x44 ---------------------------------- */
-@@ -1632,7 +1619,7 @@ struct tvcard bttv_tvcards[] = {
- 		.tuner_type	= TUNER_PHILIPS_PAL,
- 		.tuner_addr	= ADDR_UNSET,
- 		.radio_addr     = ADDR_UNSET,
--		.audio_hook	= pvbt878p9b_audio, /* Note: not all cards have stereo */
-+		.audio_mode_gpio= pvbt878p9b_audio, /* Note: not all cards have stereo */
- 		.has_radio	= 1,  /* Note: not all cards have radio */
- 		.has_remote     = 1,
- 		/* GPIO wiring:
-@@ -1710,7 +1697,7 @@ struct tvcard bttv_tvcards[] = {
- 		.tuner_type     = TUNER_PHILIPS_NTSC,
- 		.tuner_addr	= ADDR_UNSET,
- 		.radio_addr     = ADDR_UNSET,
--		.audio_hook     = windvr_audio,
-+		.audio_mode_gpio= windvr_audio,
- 	},
- 	[BTTV_BOARD_GRANDTEC_MULTI] = {
- 		.name           = "GrandTec Multi Capture Card (Bt878)",
-@@ -1807,7 +1794,7 @@ struct tvcard bttv_tvcards[] = {
- 		.tuner_type     = TUNER_PHILIPS_NTSC_M,
- 		.tuner_addr	= ADDR_UNSET,
- 		.radio_addr     = ADDR_UNSET,
--		.audio_hook     = gvbctv5pci_audio,
-+		.audio_mode_gpio= gvbctv5pci_audio,
- 		.has_radio      = 1,
- 	},
- 	[BTTV_BOARD_OSPREY1x0] = {
-@@ -2106,7 +2093,7 @@ struct tvcard bttv_tvcards[] = {
- 		.tuner_type     = TUNER_PHILIPS_NTSC,
- 		.tuner_addr	= ADDR_UNSET,
- 		.radio_addr     = ADDR_UNSET,
--		.audio_hook	= adtvk503_audio,
-+		.audio_mode_gpio= adtvk503_audio,
- 	},
+-EXPORT_SYMBOL(cx23885_boards);
+-
+ /*
+  * Local variables:
+  * c-basic-offset: 8
+diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c
+index 3cdd136..8e40c7b 100644
+--- a/drivers/media/video/cx23885/cx23885-core.c
++++ b/drivers/media/video/cx23885/cx23885-core.c
+@@ -36,7 +36,7 @@ MODULE_DESCRIPTION("Driver for cx23885 based TV cards");
+ MODULE_AUTHOR("Steven Toth <stoth at hauppauge.com>");
+ MODULE_LICENSE("GPL");
  
- 		/* ---- card 0x64 ---------------------------------- */
-@@ -3173,8 +3160,8 @@ static void flyvideo_gpio(struct bttv *btv)
- 	/* LR90 Audio Routing is done by 2 hef4052, so Audio_Mask has 4 bits: 0x001c80
- 	 * LR26/LR50 only has 1 hef4052, Audio_Mask 0x000c00
- 	 * Audio options: from tuner, from tda9821/tda9821(mono,stereo,sap), from tda9874, ext., mute */
--	if(has_tda9820_tda9821) btv->audio_hook = lt9415_audio;
--	/* todo: if(has_tda9874) btv->audio_hook = fv2000s_audio; */
-+	if(has_tda9820_tda9821) btv->audio_mode_gpio = lt9415_audio;
-+	/* todo: if(has_tda9874) btv->audio_mode_gpio = fv2000s_audio; */
- }
+-static unsigned int debug = 0;
++static unsigned int debug;
+ module_param(debug,int,0644);
+ MODULE_PARM_DESC(debug,"enable debug messages");
  
- static int miro_tunermap[] = { 0,6,2,3,   4,5,6,0,  3,0,4,5,  5,2,16,1,
-@@ -3574,8 +3561,12 @@ void __devinit bttv_init_card2(struct bttv *btv)
- 	}
+@@ -44,13 +44,15 @@ static unsigned int card[]  = {[0 ... (CX23885_MAXBOARDS - 1)] = UNSET };
+ module_param_array(card,  int, NULL, 0444);
+ MODULE_PARM_DESC(card,"card type");
  
- 	if (btv->tda9887_conf) {
--		bttv_call_i2c_clients(btv, TDA9887_SET_CONFIG,
--							&btv->tda9887_conf);
-+		struct v4l2_priv_tun_config tda9887_cfg;
-+
-+		tda9887_cfg.tuner = TUNER_TDA9887;
-+		tda9887_cfg.priv = &btv->tda9887_conf;
-+
-+		bttv_call_i2c_clients(btv, TUNER_SET_CONFIG, &tda9887_cfg);
- 	}
+-#define dprintk(level,fmt, arg...)	if (debug >= level) \
+-	printk(KERN_DEBUG "%s/0: " fmt, dev->name , ## arg)
++#define dprintk(level, fmt, arg...)\
++	do { if (debug >= level)\
++		printk(KERN_DEBUG "%s/0: " fmt, dev->name, ## arg);\
++	} while (0)
  
- 	btv->svhs = bttv_tvcards[btv->c.type].svhs;
-@@ -3590,8 +3581,10 @@ void __devinit bttv_init_card2(struct bttv *btv)
- 		btv->has_remote=1;
- 	if (!bttv_tvcards[btv->c.type].no_gpioirq)
- 		btv->gpioirq=1;
--	if (bttv_tvcards[btv->c.type].audio_hook)
--		btv->audio_hook=bttv_tvcards[btv->c.type].audio_hook;
-+	if (bttv_tvcards[btv->c.type].volume_gpio)
-+		btv->volume_gpio=bttv_tvcards[btv->c.type].volume_gpio;
-+	if (bttv_tvcards[btv->c.type].audio_mode_gpio)
-+		btv->audio_mode_gpio=bttv_tvcards[btv->c.type].audio_mode_gpio;
+ static unsigned int cx23885_devcount;
  
- 	if (bttv_tvcards[btv->c.type].digital_mode == DIGITAL_MODE_CAMERA) {
- 		/* detect Bt832 chip for quartzsight digital camera */
-@@ -3950,7 +3943,7 @@ static void __devinit avermedia_eeprom(struct bttv *btv)
- void bttv_tda9880_setnorm(struct bttv *btv, int norm)
- {
- 	/* fix up our card entry */
--	if(norm==VIDEO_MODE_NTSC) {
-+	if(norm==V4L2_STD_NTSC) {
- 		bttv_tvcards[BTTV_BOARD_VOODOOTV_FM].gpiomux[TVAUDIO_INPUT_TUNER]=0x957fff;
- 		bttv_tvcards[BTTV_BOARD_VOODOOTV_FM].gpiomute=0x957fff;
- 		bttv_tvcards[BTTV_BOARD_VOODOOTV_200].gpiomux[TVAUDIO_INPUT_TUNER]=0x957fff;
-@@ -4319,387 +4312,6 @@ void tea5757_set_freq(struct bttv *btv, unsigned short freq)
- 	tea5757_write(btv, 5 * freq + 0x358); /* add 10.7MHz (see docs) */
+ static DEFINE_MUTEX(devlist);
+-static LIST_HEAD(cx23885_devlist);
++LIST_HEAD(cx23885_devlist);
+ 
+ #define NO_SYNC_LINE (-1U)
+ 
+@@ -73,14 +75,14 @@ static LIST_HEAD(cx23885_devlist);
+  * 0x00010ea0 0x00010xxx Free
+  */
+ 
+-struct sram_channel cx23885_sram_channels[] = {
++static struct sram_channel cx23885_sram_channels[] = {
+ 	[SRAM_CH01] = {
+-		.name		= "test ch1",
++		.name		= "VID A",
+ 		.cmds_start	= 0x10000,
+-		.ctrl_start	= 0x10500,
+-		.cdt		= 0x10900,
+-		.fifo_start	= 0x3000,
+-		.fifo_size	= 0x1000,
++		.ctrl_start	= 0x105b0,
++		.cdt		= 0x107b0,
++		.fifo_start	= 0x40,
++		.fifo_size	= 0x2800,
+ 		.ptr1_reg	= DMA1_PTR1,
+ 		.ptr2_reg	= DMA1_PTR2,
+ 		.cnt1_reg	= DMA1_CNT1,
+@@ -102,8 +104,8 @@ struct sram_channel cx23885_sram_channels[] = {
+ 	[SRAM_CH03] = {
+ 		.name		= "TS1 B",
+ 		.cmds_start	= 0x100A0,
+-		.ctrl_start	= 0x10780,
+-		.cdt		= 0x10400,
++		.ctrl_start	= 0x10630,
++		.cdt		= 0x10870,
+ 		.fifo_start	= 0x5000,
+ 		.fifo_size	= 0x1000,
+ 		.ptr1_reg	= DMA3_PTR1,
+@@ -139,7 +141,7 @@ struct sram_channel cx23885_sram_channels[] = {
+ 		.name		= "TS2 C",
+ 		.cmds_start	= 0x10140,
+ 		.ctrl_start	= 0x10680,
+-		.cdt		= 0x10480,
++		.cdt		= 0x108d0,
+ 		.fifo_start	= 0x6000,
+ 		.fifo_size	= 0x1000,
+ 		.ptr1_reg	= DMA5_PTR1,
+@@ -205,14 +207,14 @@ struct sram_channel cx23885_sram_channels[] = {
+  * 0x00010ea0 0x00010xxx Free
+  */
+ 
+-struct sram_channel cx23887_sram_channels[] = {
++static struct sram_channel cx23887_sram_channels[] = {
+ 	[SRAM_CH01] = {
+-		.name		= "test ch1",
+-		.cmds_start	= 0x0,
+-		.ctrl_start	= 0x0,
+-		.cdt		= 0x0,
+-		.fifo_start	= 0x0,
+-		.fifo_size	= 0x0,
++		.name		= "VID A",
++		.cmds_start	= 0x10000,
++		.ctrl_start	= 0x105b0,
++		.cdt		= 0x107b0,
++		.fifo_start	= 0x40,
++		.fifo_size	= 0x2800,
+ 		.ptr1_reg	= DMA1_PTR1,
+ 		.ptr2_reg	= DMA1_PTR2,
+ 		.cnt1_reg	= DMA1_CNT1,
+@@ -231,12 +233,12 @@ struct sram_channel cx23887_sram_channels[] = {
+ 		.cnt2_reg	= DMA2_CNT2,
+ 	},
+ 	[SRAM_CH03] = {
+-		.name		= "ch3",
+-		.cmds_start	= 0x0,
+-		.ctrl_start	= 0x0,
+-		.cdt		= 0x0,
+-		.fifo_start	= 0x0,
+-		.fifo_size	= 0x0,
++		.name		= "TS1 B",
++		.cmds_start	= 0x100A0,
++		.ctrl_start	= 0x10780,
++		.cdt		= 0x10400,
++		.fifo_start	= 0x5000,
++		.fifo_size	= 0x1000,
+ 		.ptr1_reg	= DMA3_PTR1,
+ 		.ptr2_reg	= DMA3_PTR2,
+ 		.cnt1_reg	= DMA3_CNT1,
+@@ -357,7 +359,7 @@ static int cx23885_risc_decode(u32 risc)
  }
  
--
--/* ----------------------------------------------------------------------- */
--/* winview                                                                 */
--
--static void winview_audio(struct bttv *btv, struct video_audio *v, int set)
--{
--	/* PT2254A programming Jon Tombs, jon at gte.esi.us.es */
--	int bits_out, loops, vol, data;
--
--	if (!set) {
--		/* Fixed by Leandro Lucarella <luca at linuxmendoza.org.ar (07/31/01) */
--		v->flags |= VIDEO_AUDIO_VOLUME;
--		return;
--	}
--
--	/* 32 levels logarithmic */
--	vol = 32 - ((v->volume>>11));
--	/* units */
--	bits_out = (PT2254_DBS_IN_2>>(vol%5));
--	/* tens */
--	bits_out |= (PT2254_DBS_IN_10>>(vol/5));
--	bits_out |= PT2254_L_CHANNEL | PT2254_R_CHANNEL;
--	data = gpio_read();
--	data &= ~(WINVIEW_PT2254_CLK| WINVIEW_PT2254_DATA|
--		  WINVIEW_PT2254_STROBE);
--	for (loops = 17; loops >= 0 ; loops--) {
--		if (bits_out & (1<<loops))
--			data |=  WINVIEW_PT2254_DATA;
--		else
--			data &= ~WINVIEW_PT2254_DATA;
--		gpio_write(data);
--		udelay(5);
--		data |= WINVIEW_PT2254_CLK;
--		gpio_write(data);
--		udelay(5);
--		data &= ~WINVIEW_PT2254_CLK;
--		gpio_write(data);
--	}
--	data |=  WINVIEW_PT2254_STROBE;
--	data &= ~WINVIEW_PT2254_DATA;
--	gpio_write(data);
--	udelay(10);
--	data &= ~WINVIEW_PT2254_STROBE;
--	gpio_write(data);
--}
--
--/* ----------------------------------------------------------------------- */
--/* mono/stereo control for various cards (which don't use i2c chips but    */
--/* connect something to the GPIO pins                                      */
--
--static void
--gvbctv3pci_audio(struct bttv *btv, struct video_audio *v, int set)
--{
--	unsigned int con = 0;
--
--	if (set) {
--		gpio_inout(0x300, 0x300);
--		if (v->mode & VIDEO_SOUND_LANG1)
--			con = 0x000;
--		if (v->mode & VIDEO_SOUND_LANG2)
--			con = 0x300;
--		if (v->mode & VIDEO_SOUND_STEREO)
--			con = 0x200;
--/*		if (v->mode & VIDEO_SOUND_MONO)
-- *			con = 0x100; */
--		gpio_bits(0x300, con);
--	} else {
--		v->mode = VIDEO_SOUND_STEREO |
--			  VIDEO_SOUND_LANG1  | VIDEO_SOUND_LANG2;
--	}
--}
--
--static void
--gvbctv5pci_audio(struct bttv *btv, struct video_audio *v, int set)
--{
--	unsigned int val, con;
--
--	if (btv->radio_user)
--		return;
--
--	val = gpio_read();
--	if (set) {
--		con = 0x000;
--		if (v->mode & VIDEO_SOUND_LANG2) {
--			if (v->mode & VIDEO_SOUND_LANG1) {
--				/* LANG1 + LANG2 */
--				con = 0x100;
--			}
--			else {
--				/* LANG2 */
--				con = 0x300;
--			}
--		}
--		if (con != (val & 0x300)) {
--			gpio_bits(0x300, con);
--			if (bttv_gpio)
--				bttv_gpio_tracking(btv,"gvbctv5pci");
--		}
--	} else {
--		switch (val & 0x70) {
--		  case 0x10:
--			v->mode = VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
--			break;
--		  case 0x30:
--			v->mode = VIDEO_SOUND_LANG2;
--			break;
--		  case 0x50:
--			v->mode = VIDEO_SOUND_LANG1;
--			break;
--		  case 0x60:
--			v->mode = VIDEO_SOUND_STEREO;
--			break;
--		  case 0x70:
--			v->mode = VIDEO_SOUND_MONO;
--			break;
--		  default:
--			v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
--				  VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
--		}
--	}
--}
--
--/*
-- * Mario Medina Nussbaum <medisoft at alohabbs.org.mx>
-- *  I discover that on BT848_GPIO_DATA address a byte 0xcce enable stereo,
-- *  0xdde enables mono and 0xccd enables sap
-- *
-- * Petr Vandrovec <VANDROVE at vc.cvut.cz>
-- *  P.S.: At least mask in line above is wrong - GPIO pins 3,2 select
-- *  input/output sound connection, so both must be set for output mode.
-- *
-- * Looks like it's needed only for the "tvphone", the "tvphone 98"
-- * handles this with a tda9840
-- *
-- */
--static void
--avermedia_tvphone_audio(struct bttv *btv, struct video_audio *v, int set)
--{
--	int val = 0;
--
--	if (set) {
--		if (v->mode & VIDEO_SOUND_LANG2)   /* SAP */
--			val = 0x02;
--		if (v->mode & VIDEO_SOUND_STEREO)
--			val = 0x01;
--		if (val) {
--			gpio_bits(0x03,val);
--			if (bttv_gpio)
--				bttv_gpio_tracking(btv,"avermedia");
--		}
--	} else {
--		v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
--			VIDEO_SOUND_LANG1;
--		return;
--	}
--}
--
--static void
--avermedia_tv_stereo_audio(struct bttv *btv, struct video_audio *v, int set)
--{
--	int val = 0;
--
--	if (set) {
--		if (v->mode & VIDEO_SOUND_LANG2)   /* SAP */
--			val = 0x01;
--		if (v->mode & VIDEO_SOUND_STEREO)  /* STEREO */
--			val = 0x02;
--		btaor(val, ~0x03, BT848_GPIO_DATA);
--		if (bttv_gpio)
--			bttv_gpio_tracking(btv,"avermedia");
--	} else {
--		v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
--			VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
--		return;
--	}
--}
--
--/* Lifetec 9415 handling */
--static void
--lt9415_audio(struct bttv *btv, struct video_audio *v, int set)
--{
--	int val = 0;
--
--	if (gpio_read() & 0x4000) {
--		v->mode = VIDEO_SOUND_MONO;
--		return;
--	}
--
--	if (set) {
--		if (v->mode & VIDEO_SOUND_LANG2)  /* A2 SAP */
--			val = 0x0080;
--		if (v->mode & VIDEO_SOUND_STEREO) /* A2 stereo */
--			val = 0x0880;
--		if ((v->mode & VIDEO_SOUND_LANG1) ||
--		    (v->mode & VIDEO_SOUND_MONO))
--			val = 0;
--		gpio_bits(0x0880, val);
--		if (bttv_gpio)
--			bttv_gpio_tracking(btv,"lt9415");
--	} else {
--		/* autodetect doesn't work with this card :-( */
--		v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
--			VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
--		return;
--	}
--}
--
--/* TDA9821 on TerraTV+ Bt848, Bt878 */
--static void
--terratv_audio(struct bttv *btv, struct video_audio *v, int set)
--{
--	unsigned int con = 0;
--
--	if (set) {
--		gpio_inout(0x180000,0x180000);
--		if (v->mode & VIDEO_SOUND_LANG2)
--			con = 0x080000;
--		if (v->mode & VIDEO_SOUND_STEREO)
--			con = 0x180000;
--		gpio_bits(0x180000, con);
--		if (bttv_gpio)
--			bttv_gpio_tracking(btv,"terratv");
--	} else {
--		v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
--			VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
--	}
--}
--
--static void
--winfast2000_audio(struct bttv *btv, struct video_audio *v, int set)
--{
--	unsigned long val = 0;
--
--	if (set) {
--		/*btor (0xc32000, BT848_GPIO_OUT_EN);*/
--		if (v->mode & VIDEO_SOUND_MONO)		/* Mono */
--			val = 0x420000;
--		if (v->mode & VIDEO_SOUND_LANG1)	/* Mono */
--			val = 0x420000;
--		if (v->mode & VIDEO_SOUND_LANG2)	/* SAP */
--			val = 0x410000;
--		if (v->mode & VIDEO_SOUND_STEREO)	/* Stereo */
--			val = 0x020000;
--		if (val) {
--			gpio_bits(0x430000, val);
--			if (bttv_gpio)
--				bttv_gpio_tracking(btv,"winfast2000");
--		}
--	} else {
--		v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
--			  VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
--	}
--}
--
--/*
-- * Dariusz Kowalewski <darekk at automex.pl>
-- * sound control for Prolink PV-BT878P+9B (PixelView PlayTV Pro FM+NICAM
-- * revision 9B has on-board TDA9874A sound decoder).
-- *
-- * Note: There are card variants without tda9874a. Forcing the "stereo sound route"
-- *       will mute this cards.
-- */
--static void
--pvbt878p9b_audio(struct bttv *btv, struct video_audio *v, int set)
--{
--	unsigned int val = 0;
--
--	if (btv->radio_user)
--		return;
--
--	if (set) {
--		if (v->mode & VIDEO_SOUND_MONO)	{
--			val = 0x01;
--		}
--		if ((v->mode & (VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2))
--		    || (v->mode & VIDEO_SOUND_STEREO)) {
--			val = 0x02;
--		}
--		if (val) {
--			gpio_bits(0x03,val);
--			if (bttv_gpio)
--				bttv_gpio_tracking(btv,"pvbt878p9b");
--		}
--	} else {
--		v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
--			VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
--	}
--}
--
--/*
-- * Dariusz Kowalewski <darekk at automex.pl>
-- * sound control for FlyVideo 2000S (with tda9874 decoder)
-- * based on pvbt878p9b_audio() - this is not tested, please fix!!!
-- */
--static void
--fv2000s_audio(struct bttv *btv, struct video_audio *v, int set)
--{
--	unsigned int val = 0xffff;
--
--	if (btv->radio_user)
--		return;
--	if (set) {
--		if (v->mode & VIDEO_SOUND_MONO)	{
--			val = 0x0000;
--		}
--		if ((v->mode & (VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2))
--		    || (v->mode & VIDEO_SOUND_STEREO)) {
--			val = 0x1080; /*-dk-???: 0x0880, 0x0080, 0x1800 ... */
--		}
--		if (val != 0xffff) {
--			gpio_bits(0x1800, val);
--			if (bttv_gpio)
--				bttv_gpio_tracking(btv,"fv2000s");
--		}
--	} else {
--		v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
--			VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
--	}
--}
--
--/*
-- * sound control for Canopus WinDVR PCI
-- * Masaki Suzuki <masaki at btree.org>
-- */
--static void
--windvr_audio(struct bttv *btv, struct video_audio *v, int set)
--{
--	unsigned long val = 0;
--
--	if (set) {
--		if (v->mode & VIDEO_SOUND_MONO)
--			val = 0x040000;
--		if (v->mode & VIDEO_SOUND_LANG1)
--			val = 0;
--		if (v->mode & VIDEO_SOUND_LANG2)
--			val = 0x100000;
--		if (v->mode & VIDEO_SOUND_STEREO)
--			val = 0;
--		if (val) {
--			gpio_bits(0x140000, val);
--			if (bttv_gpio)
--				bttv_gpio_tracking(btv,"windvr");
--		}
--	} else {
--		v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
--			  VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
--	}
--}
--
--/*
-- * sound control for AD-TVK503
-- * Hiroshi Takekawa <sian at big.or.jp>
-- */
--static void
--adtvk503_audio(struct bttv *btv, struct video_audio *v, int set)
--{
--	unsigned int con = 0xffffff;
--
--	/* btaor(0x1e0000, ~0x1e0000, BT848_GPIO_OUT_EN); */
--
--	if (set) {
--		/* btor(***, BT848_GPIO_OUT_EN); */
--		if (v->mode & VIDEO_SOUND_LANG1)
--			con = 0x00000000;
--		if (v->mode & VIDEO_SOUND_LANG2)
--			con = 0x00180000;
--		if (v->mode & VIDEO_SOUND_STEREO)
--			con = 0x00000000;
--		if (v->mode & VIDEO_SOUND_MONO)
--			con = 0x00060000;
--		if (con != 0xffffff) {
--			gpio_bits(0x1e0000,con);
--			if (bttv_gpio)
--				bttv_gpio_tracking(btv, "adtvk503");
--		}
--	} else {
--		v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
--			  VIDEO_SOUND_LANG1  | VIDEO_SOUND_LANG2;
--	}
--}
--
- /* RemoteVision MX (rv605) muxsel helper [Miguel Freitas]
-  *
-  * This is needed because rv605 don't use a normal multiplex, but a crosspoint
-diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c
-index 581a3c9..907dc62 100644
---- a/drivers/media/video/bt8xx/bttv-driver.c
-+++ b/drivers/media/video/bt8xx/bttv-driver.c
-@@ -9,6 +9,12 @@
-     some v4l2 code lines are taken from Justin's bttv2 driver which is
-     (c) 2000 Justin Schoeman <justin at suntiger.ee.up.ac.za>
+ void cx23885_wakeup(struct cx23885_tsport *port,
+-		    struct cx23885_dmaqueue *q, u32 count)
++			   struct cx23885_dmaqueue *q, u32 count)
+ {
+ 	struct cx23885_dev *dev = port->dev;
+ 	struct cx23885_buffer *buf;
+@@ -378,7 +380,7 @@ void cx23885_wakeup(struct cx23885_tsport *port,
+ 		do_gettimeofday(&buf->vb.ts);
+ 		dprintk(2, "[%p/%d] wakeup reg=%d buf=%d\n", buf, buf->vb.i,
+ 			count, buf->count);
+-		buf->vb.state = STATE_DONE;
++		buf->vb.state = VIDEOBUF_DONE;
+ 		list_del(&buf->vb.queue);
+ 		wake_up(&buf->vb.done);
+ 	}
+@@ -391,12 +393,10 @@ void cx23885_wakeup(struct cx23885_tsport *port,
+ 		printk("%s: %d buffers handled (should be 1)\n",
+ 		       __FUNCTION__, bc);
+ }
+-void cx23885_sram_channel_dump(struct cx23885_dev *dev,
+-			       struct sram_channel *ch);
  
-+    V4L1 removal from:
-+    (c) 2005-2006 Nickolay V. Shmyrev <nshmyrev at yandex.ru>
-+
-+    Fixes to be fully V4L2 compliant by
-+    (c) 2006 Mauro Carvalho Chehab <mchehab at infradead.org>
-+
-     Cropping and overscan support
-     Copyright (C) 2005, 2006 Michael H. Schimek <mschimek at gmx.at>
-     Sponsored by OPQ Systems AB
-@@ -157,7 +163,7 @@ MODULE_LICENSE("GPL");
- static ssize_t show_card(struct device *cd,
- 			 struct device_attribute *attr, char *buf)
+ int cx23885_sram_channel_setup(struct cx23885_dev *dev,
+-			       struct sram_channel *ch,
+-			       unsigned int bpl, u32 risc)
++				      struct sram_channel *ch,
++				      unsigned int bpl, u32 risc)
+ {
+ 	unsigned int i, lines;
+ 	u32 cdt;
+@@ -468,7 +468,7 @@ int cx23885_sram_channel_setup(struct cx23885_dev *dev,
+ }
+ 
+ void cx23885_sram_channel_dump(struct cx23885_dev *dev,
+-			       struct sram_channel *ch)
++				      struct sram_channel *ch)
  {
--	struct video_device *vfd = to_video_device(cd);
-+	struct video_device *vfd = container_of(cd, struct video_device, class_dev);
- 	struct bttv *btv = dev_get_drvdata(vfd->dev);
- 	return sprintf(buf, "%d\n", btv ? btv->c.type : UNSET);
+ 	static char *name[] = {
+ 		"init risc lo",
+@@ -529,8 +529,8 @@ void cx23885_sram_channel_dump(struct cx23885_dev *dev,
+ 	       dev->name, cx_read(ch->cnt2_reg));
  }
-@@ -470,31 +476,27 @@ static const unsigned int BTTV_TVNORMS = ARRAY_SIZE(bttv_tvnorms);
- /* ----------------------------------------------------------------------- */
- /* bttv format list
-    packed pixel formats must come first */
--static const struct bttv_format bttv_formats[] = {
-+static const struct bttv_format formats[] = {
- 	{
- 		.name     = "8 bpp, gray",
--		.palette  = VIDEO_PALETTE_GREY,
- 		.fourcc   = V4L2_PIX_FMT_GREY,
- 		.btformat = BT848_COLOR_FMT_Y8,
- 		.depth    = 8,
- 		.flags    = FORMAT_FLAGS_PACKED,
- 	},{
- 		.name     = "8 bpp, dithered color",
--		.palette  = VIDEO_PALETTE_HI240,
- 		.fourcc   = V4L2_PIX_FMT_HI240,
- 		.btformat = BT848_COLOR_FMT_RGB8,
- 		.depth    = 8,
- 		.flags    = FORMAT_FLAGS_PACKED | FORMAT_FLAGS_DITHER,
- 	},{
- 		.name     = "15 bpp RGB, le",
--		.palette  = VIDEO_PALETTE_RGB555,
- 		.fourcc   = V4L2_PIX_FMT_RGB555,
- 		.btformat = BT848_COLOR_FMT_RGB15,
- 		.depth    = 16,
- 		.flags    = FORMAT_FLAGS_PACKED,
- 	},{
- 		.name     = "15 bpp RGB, be",
--		.palette  = -1,
- 		.fourcc   = V4L2_PIX_FMT_RGB555X,
- 		.btformat = BT848_COLOR_FMT_RGB15,
- 		.btswap   = 0x03, /* byteswap */
-@@ -502,14 +504,12 @@ static const struct bttv_format bttv_formats[] = {
- 		.flags    = FORMAT_FLAGS_PACKED,
- 	},{
- 		.name     = "16 bpp RGB, le",
--		.palette  = VIDEO_PALETTE_RGB565,
- 		.fourcc   = V4L2_PIX_FMT_RGB565,
- 		.btformat = BT848_COLOR_FMT_RGB16,
- 		.depth    = 16,
- 		.flags    = FORMAT_FLAGS_PACKED,
- 	},{
- 		.name     = "16 bpp RGB, be",
--		.palette  = -1,
- 		.fourcc   = V4L2_PIX_FMT_RGB565X,
- 		.btformat = BT848_COLOR_FMT_RGB16,
- 		.btswap   = 0x03, /* byteswap */
-@@ -517,21 +517,18 @@ static const struct bttv_format bttv_formats[] = {
- 		.flags    = FORMAT_FLAGS_PACKED,
- 	},{
- 		.name     = "24 bpp RGB, le",
--		.palette  = VIDEO_PALETTE_RGB24,
- 		.fourcc   = V4L2_PIX_FMT_BGR24,
- 		.btformat = BT848_COLOR_FMT_RGB24,
- 		.depth    = 24,
- 		.flags    = FORMAT_FLAGS_PACKED,
- 	},{
- 		.name     = "32 bpp RGB, le",
--		.palette  = VIDEO_PALETTE_RGB32,
- 		.fourcc   = V4L2_PIX_FMT_BGR32,
- 		.btformat = BT848_COLOR_FMT_RGB32,
- 		.depth    = 32,
- 		.flags    = FORMAT_FLAGS_PACKED,
- 	},{
- 		.name     = "32 bpp RGB, be",
--		.palette  = -1,
- 		.fourcc   = V4L2_PIX_FMT_RGB32,
- 		.btformat = BT848_COLOR_FMT_RGB32,
- 		.btswap   = 0x0f, /* byte+word swap */
-@@ -539,21 +536,18 @@ static const struct bttv_format bttv_formats[] = {
- 		.flags    = FORMAT_FLAGS_PACKED,
- 	},{
- 		.name     = "4:2:2, packed, YUYV",
--		.palette  = VIDEO_PALETTE_YUV422,
- 		.fourcc   = V4L2_PIX_FMT_YUYV,
- 		.btformat = BT848_COLOR_FMT_YUY2,
- 		.depth    = 16,
- 		.flags    = FORMAT_FLAGS_PACKED,
- 	},{
- 		.name     = "4:2:2, packed, YUYV",
--		.palette  = VIDEO_PALETTE_YUYV,
- 		.fourcc   = V4L2_PIX_FMT_YUYV,
- 		.btformat = BT848_COLOR_FMT_YUY2,
- 		.depth    = 16,
- 		.flags    = FORMAT_FLAGS_PACKED,
- 	},{
- 		.name     = "4:2:2, packed, UYVY",
--		.palette  = VIDEO_PALETTE_UYVY,
- 		.fourcc   = V4L2_PIX_FMT_UYVY,
- 		.btformat = BT848_COLOR_FMT_YUY2,
- 		.btswap   = 0x03, /* byteswap */
-@@ -561,7 +555,6 @@ static const struct bttv_format bttv_formats[] = {
- 		.flags    = FORMAT_FLAGS_PACKED,
- 	},{
- 		.name     = "4:2:2, planar, Y-Cb-Cr",
--		.palette  = VIDEO_PALETTE_YUV422P,
- 		.fourcc   = V4L2_PIX_FMT_YUV422P,
- 		.btformat = BT848_COLOR_FMT_YCrCb422,
- 		.depth    = 16,
-@@ -570,7 +563,6 @@ static const struct bttv_format bttv_formats[] = {
- 		.vshift   = 0,
- 	},{
- 		.name     = "4:2:0, planar, Y-Cb-Cr",
--		.palette  = VIDEO_PALETTE_YUV420P,
- 		.fourcc   = V4L2_PIX_FMT_YUV420,
- 		.btformat = BT848_COLOR_FMT_YCrCb422,
- 		.depth    = 12,
-@@ -579,7 +571,6 @@ static const struct bttv_format bttv_formats[] = {
- 		.vshift   = 1,
- 	},{
- 		.name     = "4:2:0, planar, Y-Cr-Cb",
--		.palette  = -1,
- 		.fourcc   = V4L2_PIX_FMT_YVU420,
- 		.btformat = BT848_COLOR_FMT_YCrCb422,
- 		.depth    = 12,
-@@ -588,7 +579,6 @@ static const struct bttv_format bttv_formats[] = {
- 		.vshift   = 1,
- 	},{
- 		.name     = "4:1:1, planar, Y-Cb-Cr",
--		.palette  = VIDEO_PALETTE_YUV411P,
- 		.fourcc   = V4L2_PIX_FMT_YUV411P,
- 		.btformat = BT848_COLOR_FMT_YCrCb411,
- 		.depth    = 12,
-@@ -597,7 +587,6 @@ static const struct bttv_format bttv_formats[] = {
- 		.vshift   = 0,
- 	},{
- 		.name     = "4:1:0, planar, Y-Cb-Cr",
--		.palette  = VIDEO_PALETTE_YUV410P,
- 		.fourcc   = V4L2_PIX_FMT_YUV410,
- 		.btformat = BT848_COLOR_FMT_YCrCb411,
- 		.depth    = 9,
-@@ -606,7 +595,6 @@ static const struct bttv_format bttv_formats[] = {
- 		.vshift   = 2,
- 	},{
- 		.name     = "4:1:0, planar, Y-Cr-Cb",
--		.palette  = -1,
- 		.fourcc   = V4L2_PIX_FMT_YVU410,
- 		.btformat = BT848_COLOR_FMT_YCrCb411,
- 		.depth    = 9,
-@@ -615,14 +603,13 @@ static const struct bttv_format bttv_formats[] = {
- 		.vshift   = 2,
- 	},{
- 		.name     = "raw scanlines",
--		.palette  = VIDEO_PALETTE_RAW,
- 		.fourcc   = -1,
- 		.btformat = BT848_COLOR_FMT_RAW,
- 		.depth    = 8,
- 		.flags    = FORMAT_FLAGS_RAW,
+ 
+-void cx23885_risc_disasm(struct cx23885_tsport *port,
+-			 struct btcx_riscmem *risc)
++static void cx23885_risc_disasm(struct cx23885_tsport *port,
++				struct btcx_riscmem *risc)
+ {
+ 	struct cx23885_dev *dev = port->dev;
+ 	unsigned int i, j, n;
+@@ -548,7 +548,7 @@ void cx23885_risc_disasm(struct cx23885_tsport *port,
  	}
- };
--static const unsigned int BTTV_FORMATS = ARRAY_SIZE(bttv_formats);
-+static const unsigned int FORMATS = ARRAY_SIZE(formats);
+ }
  
- /* ----------------------------------------------------------------------- */
+-void cx23885_shutdown(struct cx23885_dev *dev)
++static void cx23885_shutdown(struct cx23885_dev *dev)
+ {
+ 	/* disable RISC controller */
+ 	cx_write(DEV_CNTRL2, 0);
+@@ -578,7 +578,7 @@ void cx23885_shutdown(struct cx23885_dev *dev)
  
-@@ -798,7 +785,17 @@ static const struct v4l2_queryctrl bttv_ctls[] = {
+ }
  
+-void cx23885_reset(struct cx23885_dev *dev)
++static void cx23885_reset(struct cx23885_dev *dev)
+ {
+ 	dprintk(1, "%s()\n", __FUNCTION__);
  
- };
--static const int BTTV_CTLS = ARRAY_SIZE(bttv_ctls);
-+
-+static const struct v4l2_queryctrl *ctrl_by_id(int id)
-+{
-+	int i;
-+
-+	for (i = 0; i < ARRAY_SIZE(bttv_ctls); i++)
-+		if (bttv_ctls[i].id == id)
-+			return bttv_ctls+i;
-+
-+	return NULL;
-+}
+@@ -594,15 +594,18 @@ void cx23885_reset(struct cx23885_dev *dev)
  
- /* ----------------------------------------------------------------------- */
- /* resource management                                                     */
-@@ -1255,16 +1252,6 @@ audio_input(struct bttv *btv, int input)
+ 	mdelay(100);
+ 
+-	cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH01 ], 188*4, 0);
+-	cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH02 ], 128, 0);
+-	cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH03 ], 188*4, 0);
+-	cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH04 ], 128, 0);
+-	cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH05 ], 128, 0);
+-	cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH06 ], 188*4, 0);
+-	cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH07 ], 128, 0);
+-	cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH08 ], 128, 0);
+-	cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH09 ], 128, 0);
++	cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH01],
++		720*4, 0);
++	cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH02], 128, 0);
++	cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH03],
++		188*4, 0);
++	cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH04], 128, 0);
++	cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH05], 128, 0);
++	cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH06],
++		188*4, 0);
++	cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH07], 128, 0);
++	cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH08], 128, 0);
++	cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH09], 128, 0);
+ 
+ 	cx23885_gpio_setup(dev);
  }
+@@ -637,7 +640,7 @@ static int get_resources(struct cx23885_dev *dev)
  
- static void
--i2c_vidiocschan(struct bttv *btv)
--{
--	v4l2_std_id std = bttv_tvnorms[btv->tvnorm].v4l2_id;
--
--	bttv_call_i2c_clients(btv, VIDIOC_S_STD, &std);
--	if (btv->c.type == BTTV_BOARD_VOODOOTV_FM || btv->c.type == BTTV_BOARD_VOODOOTV_200)
--		bttv_tda9880_setnorm(btv,btv->tvnorm);
--}
--
--static void
- bttv_crop_calc_limits(struct bttv_crop *c)
+ static void cx23885_timeout(unsigned long data);
+ int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc,
+-			 u32 reg, u32 mask, u32 value);
++				u32 reg, u32 mask, u32 value);
+ 
+ static int cx23885_init_tsport(struct cx23885_dev *dev, struct cx23885_tsport *port, int portno)
  {
- 	/* Scale factor min. 1:1, max. 16:1. Min. image size
-@@ -1298,6 +1285,7 @@ static int
- set_tvnorm(struct bttv *btv, unsigned int norm)
+@@ -704,6 +707,44 @@ static int cx23885_init_tsport(struct cx23885_dev *dev, struct cx23885_tsport *p
+ 	return 0;
+ }
+ 
++static void cx23885_dev_checkrevision(struct cx23885_dev *dev)
++{
++	switch (cx_read(RDR_CFG2) & 0xff) {
++	case 0x00:
++		/* cx23885 */
++		dev->hwrevision = 0xa0;
++		break;
++	case 0x01:
++		/* CX23885-12Z */
++		dev->hwrevision = 0xa1;
++		break;
++	case 0x02:
++		/* CX23885-13Z */
++		dev->hwrevision = 0xb0;
++		break;
++	case 0x03:
++		/* CX23888-22Z */
++		dev->hwrevision = 0xc0;
++		break;
++	case 0x0e:
++		/* CX23887-15Z */
++		dev->hwrevision = 0xc0;
++	case 0x0f:
++		/* CX23887-14Z */
++		dev->hwrevision = 0xb1;
++		break;
++	default:
++		printk(KERN_ERR "%s() New hardware revision found 0x%x\n",
++			__FUNCTION__, dev->hwrevision);
++	}
++	if (dev->hwrevision)
++		printk(KERN_INFO "%s() Hardware revision = 0x%02x\n",
++			__FUNCTION__, dev->hwrevision);
++	else
++		printk(KERN_ERR "%s() Hardware revision unknown 0x%x\n",
++			__FUNCTION__, dev->hwrevision);
++}
++
+ static int cx23885_dev_setup(struct cx23885_dev *dev)
  {
- 	const struct bttv_tvnorm *tvnorm;
-+	v4l2_std_id id;
+ 	int i;
+@@ -723,10 +764,14 @@ static int cx23885_dev_setup(struct cx23885_dev *dev)
+ 	if(dev->pci->device == 0x8880) {
+ 		dev->bridge = CX23885_BRIDGE_887;
+ 		dev->sram_channels = cx23887_sram_channels;
++		/* Apply a sensible clock frequency for the PCIe bridge */
++		dev->clk_freq = 25000000;
+ 	} else
+ 	if(dev->pci->device == 0x8852) {
+ 		dev->bridge = CX23885_BRIDGE_885;
+ 		dev->sram_channels = cx23885_sram_channels;
++		/* Apply a sensible clock frequency for the PCIe bridge */
++		dev->clk_freq = 28000000;
+ 	} else
+ 		BUG();
  
- 	if (norm < 0 || norm >= BTTV_TVNORMS)
- 		return -EINVAL;
-@@ -1334,6 +1322,9 @@ set_tvnorm(struct bttv *btv, unsigned int norm)
- 		bttv_tda9880_setnorm(btv,norm);
- 		break;
+@@ -746,6 +791,10 @@ static int cx23885_dev_setup(struct cx23885_dev *dev)
+ 		cx23885_card_list(dev);
  	}
-+	id = tvnorm->v4l2_id;
-+	bttv_call_i2c_clients(btv, VIDIOC_S_STD, &id);
+ 
++	/* If the user specific a clk freq override, apply it */
++	if (cx23885_boards[dev->board].clk_freq > 0)
++		dev->clk_freq = cx23885_boards[dev->board].clk_freq;
++
+ 	dev->pci_bus  = dev->pci->bus->number;
+ 	dev->pci_slot = PCI_SLOT(dev->pci->devfn);
+ 	dev->pci_irqmask = 0x001f00;
+@@ -810,6 +859,17 @@ static int cx23885_dev_setup(struct cx23885_dev *dev)
+ 
+ 	cx23885_pci_quirks(dev);
+ 
++	/* Assume some sensible defaults */
++	dev->tuner_type = cx23885_boards[dev->board].tuner_type;
++	dev->tuner_addr = cx23885_boards[dev->board].tuner_addr;
++	dev->radio_type = cx23885_boards[dev->board].radio_type;
++	dev->radio_addr = cx23885_boards[dev->board].radio_addr;
++
++	dprintk(1, "%s() tuner_type = 0x%x tuner_addr = 0x%x\n",
++		__FUNCTION__, dev->tuner_type, dev->tuner_addr);
++	dprintk(1, "%s() radio_type = 0x%x radio_addr = 0x%x\n",
++		__FUNCTION__, dev->radio_type, dev->radio_addr);
++
+ 	/* init hardware */
+ 	cx23885_reset(dev);
+ 
+@@ -820,24 +880,33 @@ static int cx23885_dev_setup(struct cx23885_dev *dev)
+ 	cx23885_card_setup(dev);
+ 	cx23885_ir_init(dev);
+ 
+-	if(cx23885_boards[dev->board].portb == CX23885_MPEG_DVB) {
++	if (cx23885_boards[dev->board].porta == CX23885_ANALOG_VIDEO) {
++		if (cx23885_video_register(dev) < 0) {
++			printk(KERN_ERR "%s() Failed to register analog "
++				"video adapters on VID_A\n", __FUNCTION__);
++		}
++	}
++
++	if (cx23885_boards[dev->board].portb == CX23885_MPEG_DVB) {
+ 		if (cx23885_dvb_register(&dev->ts1) < 0) {
+ 			printk(KERN_ERR "%s() Failed to register dvb adapters on VID_B\n",
+ 			       __FUNCTION__);
+ 		}
+ 	}
+ 
+-	if(cx23885_boards[dev->board].portc == CX23885_MPEG_DVB) {
++	if (cx23885_boards[dev->board].portc == CX23885_MPEG_DVB) {
+ 		if (cx23885_dvb_register(&dev->ts2) < 0) {
+ 			printk(KERN_ERR "%s() Failed to register dvb adapters on VID_C\n",
+ 			       __FUNCTION__);
+ 		}
+ 	}
+ 
++	cx23885_dev_checkrevision(dev);
 +
  	return 0;
  }
  
-@@ -1359,7 +1350,6 @@ set_input(struct bttv *btv, unsigned int input, unsigned int norm)
- 	audio_input(btv,(input == bttv_tvcards[btv->c.type].tuner ?
- 		       TVAUDIO_INPUT_TUNER : TVAUDIO_INPUT_EXTERN));
- 	set_tvnorm(btv, norm);
--	i2c_vidiocschan(btv);
+-void cx23885_dev_unregister(struct cx23885_dev *dev)
++static void cx23885_dev_unregister(struct cx23885_dev *dev)
+ {
+ 	release_mem_region(pci_resource_start(dev->pci,0),
+ 			   pci_resource_len(dev->pci,0));
+@@ -845,6 +914,9 @@ void cx23885_dev_unregister(struct cx23885_dev *dev)
+ 	if (!atomic_dec_and_test(&dev->refcount))
+ 		return;
+ 
++	if (cx23885_boards[dev->board].porta == CX23885_ANALOG_VIDEO)
++		cx23885_video_unregister(dev);
++
+ 	if(cx23885_boards[dev->board].portb == CX23885_MPEG_DVB)
+ 		cx23885_dvb_unregister(&dev->ts1);
+ 
+@@ -952,9 +1024,11 @@ int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc,
+ 	return 0;
  }
  
- static void init_irqreg(struct bttv *btv)
-@@ -1452,38 +1442,12 @@ static void bttv_reinit_bt848(struct bttv *btv)
- 	set_input(btv, btv->input, btv->tvnorm);
+-int cx23885_risc_databuffer(struct pci_dev *pci, struct btcx_riscmem *risc,
+-			    struct scatterlist *sglist, unsigned int bpl,
+-			    unsigned int lines)
++static int cx23885_risc_databuffer(struct pci_dev *pci,
++				   struct btcx_riscmem *risc,
++				   struct scatterlist *sglist,
++				   unsigned int bpl,
++				   unsigned int lines)
+ {
+ 	u32 instructions;
+ 	u32 *rp;
+@@ -982,7 +1056,7 @@ int cx23885_risc_databuffer(struct pci_dev *pci, struct btcx_riscmem *risc,
  }
  
--static int get_control(struct bttv *btv, struct v4l2_control *c)
-+static int bttv_g_ctrl(struct file *file, void *priv,
-+					struct v4l2_control *c)
+ int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc,
+-			 u32 reg, u32 mask, u32 value)
++				u32 reg, u32 mask, u32 value)
  {
--	struct video_audio va;
--	int i;
-+	struct bttv_fh *fh = priv;
-+	struct bttv *btv = fh->btv;
+ 	u32 *rp;
+ 	int rc;
+@@ -1011,7 +1085,58 @@ void cx23885_free_buffer(struct videobuf_queue *q, struct cx23885_buffer *buf)
+ 	videobuf_dma_unmap(q, dma);
+ 	videobuf_dma_free(dma);
+ 	btcx_riscmem_free((struct pci_dev *)q->dev, &buf->risc);
+-	buf->vb.state = STATE_NEEDS_INIT;
++	buf->vb.state = VIDEOBUF_NEEDS_INIT;
++}
++
++static void cx23885_tsport_reg_dump(struct cx23885_tsport *port)
++{
++	struct cx23885_dev *dev = port->dev;
++
++	dprintk(1, "%s() Register Dump\n", __FUNCTION__);
++	dprintk(1, "%s() DEV_CNTRL2               0x%08X\n", __FUNCTION__,
++		cx_read(DEV_CNTRL2));
++	dprintk(1, "%s() PCI_INT_MSK              0x%08X\n", __FUNCTION__,
++		cx_read(PCI_INT_MSK));
++	dprintk(1, "%s() AUD_INT_INT_MSK          0x%08X\n", __FUNCTION__,
++		cx_read(AUDIO_INT_INT_MSK));
++	dprintk(1, "%s() AUD_INT_DMA_CTL          0x%08X\n", __FUNCTION__,
++		cx_read(AUD_INT_DMA_CTL));
++	dprintk(1, "%s() AUD_EXT_INT_MSK          0x%08X\n", __FUNCTION__,
++		cx_read(AUDIO_EXT_INT_MSK));
++	dprintk(1, "%s() AUD_EXT_DMA_CTL          0x%08X\n", __FUNCTION__,
++		cx_read(AUD_EXT_DMA_CTL));
++	dprintk(1, "%s() PAD_CTRL                 0x%08X\n", __FUNCTION__,
++		cx_read(PAD_CTRL));
++	dprintk(1, "%s() ALT_PIN_OUT_SEL          0x%08X\n", __FUNCTION__,
++		cx_read(ALT_PIN_OUT_SEL));
++	dprintk(1, "%s() GPIO2                    0x%08X\n", __FUNCTION__,
++		cx_read(GPIO2));
++	dprintk(1, "%s() gpcnt(0x%08X)          0x%08X\n", __FUNCTION__,
++		port->reg_gpcnt, cx_read(port->reg_gpcnt));
++	dprintk(1, "%s() gpcnt_ctl(0x%08X)      0x%08x\n", __FUNCTION__,
++		port->reg_gpcnt_ctl, cx_read(port->reg_gpcnt_ctl));
++	dprintk(1, "%s() dma_ctl(0x%08X)        0x%08x\n", __FUNCTION__,
++		port->reg_dma_ctl, cx_read(port->reg_dma_ctl));
++	dprintk(1, "%s() src_sel(0x%08X)        0x%08x\n", __FUNCTION__,
++		port->reg_src_sel, cx_read(port->reg_src_sel));
++	dprintk(1, "%s() lngth(0x%08X)          0x%08x\n", __FUNCTION__,
++		port->reg_lngth, cx_read(port->reg_lngth));
++	dprintk(1, "%s() hw_sop_ctrl(0x%08X)    0x%08x\n", __FUNCTION__,
++		port->reg_hw_sop_ctrl, cx_read(port->reg_hw_sop_ctrl));
++	dprintk(1, "%s() gen_ctrl(0x%08X)       0x%08x\n", __FUNCTION__,
++		port->reg_gen_ctrl, cx_read(port->reg_gen_ctrl));
++	dprintk(1, "%s() bd_pkt_status(0x%08X)  0x%08x\n", __FUNCTION__,
++		port->reg_bd_pkt_status, cx_read(port->reg_bd_pkt_status));
++	dprintk(1, "%s() sop_status(0x%08X)     0x%08x\n", __FUNCTION__,
++		port->reg_sop_status, cx_read(port->reg_sop_status));
++	dprintk(1, "%s() fifo_ovfl_stat(0x%08X) 0x%08x\n", __FUNCTION__,
++		port->reg_fifo_ovfl_stat, cx_read(port->reg_fifo_ovfl_stat));
++	dprintk(1, "%s() vld_misc(0x%08X)       0x%08x\n", __FUNCTION__,
++		port->reg_vld_misc, cx_read(port->reg_vld_misc));
++	dprintk(1, "%s() ts_clk_en(0x%08X)      0x%08x\n", __FUNCTION__,
++		port->reg_ts_clk_en, cx_read(port->reg_ts_clk_en));
++	dprintk(1, "%s() ts_int_msk(0x%08X)     0x%08x\n", __FUNCTION__,
++		port->reg_ts_int_msk, cx_read(port->reg_ts_int_msk));
+ }
  
--	for (i = 0; i < BTTV_CTLS; i++)
--		if (bttv_ctls[i].id == c->id)
--			break;
--	if (i == BTTV_CTLS)
--		return -EINVAL;
--	if (btv->audio_hook && i >= 4 && i <= 8) {
--		memset(&va,0,sizeof(va));
--		btv->audio_hook(btv,&va,0);
--		switch (c->id) {
--		case V4L2_CID_AUDIO_MUTE:
--			c->value = (VIDEO_AUDIO_MUTE & va.flags) ? 1 : 0;
--			break;
--		case V4L2_CID_AUDIO_VOLUME:
--			c->value = va.volume;
--			break;
--		case V4L2_CID_AUDIO_BALANCE:
--			c->value = va.balance;
--			break;
--		case V4L2_CID_AUDIO_BASS:
--			c->value = va.bass;
--			break;
--		case V4L2_CID_AUDIO_TREBLE:
--			c->value = va.treble;
--			break;
--		}
--		return 0;
--	}
- 	switch (c->id) {
- 	case V4L2_CID_BRIGHTNESS:
- 		c->value = btv->bright;
-@@ -1503,7 +1467,7 @@ static int get_control(struct bttv *btv, struct v4l2_control *c)
- 	case V4L2_CID_AUDIO_BALANCE:
- 	case V4L2_CID_AUDIO_BASS:
- 	case V4L2_CID_AUDIO_TREBLE:
--		bttv_call_i2c_clients(btv,VIDIOC_G_CTRL,c);
-+		bttv_call_i2c_clients(btv, VIDIOC_G_CTRL, c);
- 		break;
+ static int cx23885_start_dma(struct cx23885_tsport *port,
+@@ -1076,6 +1201,9 @@ static int cx23885_start_dma(struct cx23885_tsport *port,
  
- 	case V4L2_CID_PRIVATE_CHROMA_AGC:
-@@ -1545,67 +1509,44 @@ static int get_control(struct bttv *btv, struct v4l2_control *c)
+ 	cx_set(DEV_CNTRL2, (1<<5)); /* Enable RISC controller */
+ 
++	if (debug > 4)
++		cx23885_tsport_reg_dump(port);
++
  	return 0;
  }
  
--static int set_control(struct bttv *btv, struct v4l2_control *c)
-+static int bttv_s_ctrl(struct file *file, void *f,
-+					struct v4l2_control *c)
+@@ -1091,7 +1219,7 @@ static int cx23885_stop_dma(struct cx23885_tsport *port)
+ 	return 0;
+ }
+ 
+-static int cx23885_restart_queue(struct cx23885_tsport *port,
++int cx23885_restart_queue(struct cx23885_tsport *port,
+ 				struct cx23885_dmaqueue *q)
  {
--	struct video_audio va;
--	int i,val;
-+	int err;
-+	int val;
-+	struct bttv_fh *fh = f;
-+	struct bttv *btv = fh->btv;
+ 	struct cx23885_dev *dev = port->dev;
+@@ -1114,7 +1242,7 @@ static int cx23885_restart_queue(struct cx23885_tsport *port,
+ 				list_del(&buf->vb.queue);
+ 				list_add_tail(&buf->vb.queue, &q->active);
+ 				cx23885_start_dma(port, q, buf);
+-				buf->vb.state = STATE_ACTIVE;
++				buf->vb.state = VIDEOBUF_ACTIVE;
+ 				buf->count    = q->count++;
+ 				mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
+ 				dprintk(5, "[%p/%d] restart_queue - first active\n",
+@@ -1125,7 +1253,7 @@ static int cx23885_restart_queue(struct cx23885_tsport *port,
+ 				   prev->fmt       == buf->fmt) {
+ 				list_del(&buf->vb.queue);
+ 				list_add_tail(&buf->vb.queue, &q->active);
+-				buf->vb.state = STATE_ACTIVE;
++				buf->vb.state = VIDEOBUF_ACTIVE;
+ 				buf->count    = q->count++;
+ 				prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
+ 				prev->risc.jmp[2] = cpu_to_le32(0); /* 64 bit bits 63-32 */
+@@ -1162,7 +1290,7 @@ int cx23885_buf_prepare(struct videobuf_queue *q, struct cx23885_tsport *port,
+ 	if (0 != buf->vb.baddr  &&  buf->vb.bsize < size)
+ 		return -EINVAL;
  
--	for (i = 0; i < BTTV_CTLS; i++)
--		if (bttv_ctls[i].id == c->id)
--			break;
--	if (i == BTTV_CTLS)
--		return -EINVAL;
--	if (btv->audio_hook && i >= 4 && i <= 8) {
--		memset(&va,0,sizeof(va));
--		btv->audio_hook(btv,&va,0);
--		switch (c->id) {
--		case V4L2_CID_AUDIO_MUTE:
--			if (c->value) {
--				va.flags |= VIDEO_AUDIO_MUTE;
--				audio_mute(btv, 1);
--			} else {
--				va.flags &= ~VIDEO_AUDIO_MUTE;
--				audio_mute(btv, 0);
--			}
--			break;
-+	err = v4l2_prio_check(&btv->prio, &fh->prio);
-+	if (0 != err)
-+		return err;
+-	if (STATE_NEEDS_INIT == buf->vb.state) {
++	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
+ 		buf->vb.width  = port->ts_packet_size;
+ 		buf->vb.height = port->ts_packet_count;
+ 		buf->vb.size   = size;
+@@ -1174,7 +1302,7 @@ int cx23885_buf_prepare(struct videobuf_queue *q, struct cx23885_tsport *port,
+ 					videobuf_to_dma(&buf->vb)->sglist,
+ 					buf->vb.width, buf->vb.height);
+ 	}
+-	buf->vb.state = STATE_PREPARED;
++	buf->vb.state = VIDEOBUF_PREPARED;
+ 	return 0;
  
--		case V4L2_CID_AUDIO_VOLUME:
--			va.volume = c->value;
--			break;
--		case V4L2_CID_AUDIO_BALANCE:
--			va.balance = c->value;
--			break;
--		case V4L2_CID_AUDIO_BASS:
--			va.bass = c->value;
--			break;
--		case V4L2_CID_AUDIO_TREBLE:
--			va.treble = c->value;
--			break;
--		}
--		btv->audio_hook(btv,&va,1);
--		return 0;
--	}
- 	switch (c->id) {
- 	case V4L2_CID_BRIGHTNESS:
--		bt848_bright(btv,c->value);
-+		bt848_bright(btv, c->value);
- 		break;
- 	case V4L2_CID_HUE:
--		bt848_hue(btv,c->value);
-+		bt848_hue(btv, c->value);
- 		break;
- 	case V4L2_CID_CONTRAST:
--		bt848_contrast(btv,c->value);
-+		bt848_contrast(btv, c->value);
+  fail:
+@@ -1197,7 +1325,7 @@ void cx23885_buf_queue(struct cx23885_tsport *port, struct cx23885_buffer *buf)
+ 		dprintk( 1, "queue is empty - first active\n" );
+ 		list_add_tail(&buf->vb.queue, &cx88q->active);
+ 		cx23885_start_dma(port, cx88q, buf);
+-		buf->vb.state = STATE_ACTIVE;
++		buf->vb.state = VIDEOBUF_ACTIVE;
+ 		buf->count    = cx88q->count++;
+ 		mod_timer(&cx88q->timeout, jiffies + BUFFER_TIMEOUT);
+ 		dprintk(1, "[%p/%d] %s - first active\n",
+@@ -1207,7 +1335,7 @@ void cx23885_buf_queue(struct cx23885_tsport *port, struct cx23885_buffer *buf)
+ 		prev = list_entry(cx88q->active.prev, struct cx23885_buffer,
+ 				  vb.queue);
+ 		list_add_tail(&buf->vb.queue, &cx88q->active);
+-		buf->vb.state = STATE_ACTIVE;
++		buf->vb.state = VIDEOBUF_ACTIVE;
+ 		buf->count    = cx88q->count++;
+ 		prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
+ 		prev->risc.jmp[2] = cpu_to_le32(0); /* 64 bit bits 63-32 */
+@@ -1231,7 +1359,7 @@ static void do_cancel_buffers(struct cx23885_tsport *port, char *reason,
+ 		buf = list_entry(q->active.next, struct cx23885_buffer,
+ 				 vb.queue);
+ 		list_del(&buf->vb.queue);
+-		buf->vb.state = STATE_ERROR;
++		buf->vb.state = VIDEOBUF_ERROR;
+ 		wake_up(&buf->vb.done);
+ 		dprintk(1, "[%p/%d] %s - dma=0x%08lx\n",
+ 			buf, buf->vb.i, reason, (unsigned long)buf->risc.dma);
+@@ -1243,16 +1371,6 @@ static void do_cancel_buffers(struct cx23885_tsport *port, char *reason,
+ 	spin_unlock_irqrestore(&port->slock, flags);
+ }
+ 
+-void cx23885_cancel_buffers(struct cx23885_tsport *port)
+-{
+-	struct cx23885_dev *dev = port->dev;
+-	struct cx23885_dmaqueue *q = &port->mpegq;
+-
+-	dprintk(1, "%s()\n", __FUNCTION__);
+-	del_timer_sync(&q->timeout);
+-	cx23885_stop_dma(port);
+-	do_cancel_buffers(port, "cancel", 0);
+-}
+ 
+ static void cx23885_timeout(unsigned long data)
+ {
+@@ -1325,12 +1443,15 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id)
+ 	struct cx23885_tsport *ts1 = &dev->ts1;
+ 	struct cx23885_tsport *ts2 = &dev->ts2;
+ 	u32 pci_status, pci_mask;
++	u32 vida_status, vida_mask;
+ 	u32 ts1_status, ts1_mask;
+ 	u32 ts2_status, ts2_mask;
+-	int ts1_count = 0, ts2_count = 0, handled = 0;
++	int vida_count = 0, ts1_count = 0, ts2_count = 0, handled = 0;
+ 
+ 	pci_status = cx_read(PCI_INT_STAT);
+ 	pci_mask = cx_read(PCI_INT_MSK);
++	vida_status = cx_read(VID_A_INT_STAT);
++	vida_mask = cx_read(VID_A_INT_MSK);
+ 	ts1_status = cx_read(VID_B_INT_STAT);
+ 	ts1_mask = cx_read(VID_B_INT_MSK);
+ 	ts2_status = cx_read(VID_C_INT_STAT);
+@@ -1339,11 +1460,17 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id)
+ 	if ( (pci_status == 0) && (ts2_status == 0) && (ts1_status == 0) )
+ 		goto out;
+ 
++	vida_count = cx_read(VID_A_GPCNT);
+ 	ts1_count = cx_read(ts1->reg_gpcnt);
+ 	ts2_count = cx_read(ts2->reg_gpcnt);
+-	dprintk(7, "pci_status: 0x%08x  pci_mask: 0x%08x\n", pci_status, pci_mask );
+-	dprintk(7, "ts1_status: 0x%08x  ts1_mask: 0x%08x count: 0x%x\n", ts1_status, ts1_mask, ts1_count );
+-	dprintk(7, "ts2_status: 0x%08x  ts2_mask: 0x%08x count: 0x%x\n", ts2_status, ts2_mask, ts2_count );
++	dprintk(7, "pci_status: 0x%08x  pci_mask: 0x%08x\n",
++		pci_status, pci_mask);
++	dprintk(7, "vida_status: 0x%08x vida_mask: 0x%08x count: 0x%x\n",
++		vida_status, vida_mask, vida_count);
++	dprintk(7, "ts1_status: 0x%08x  ts1_mask: 0x%08x count: 0x%x\n",
++		ts1_status, ts1_mask, ts1_count);
++	dprintk(7, "ts2_status: 0x%08x  ts2_mask: 0x%08x count: 0x%x\n",
++		ts2_status, ts2_mask, ts2_count);
+ 
+ 	if ( (pci_status & PCI_MSK_RISC_RD) ||
+ 	     (pci_status & PCI_MSK_RISC_WR) ||
+@@ -1380,11 +1507,18 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id)
+ 
+ 	}
+ 
+-	if (ts1_status)
+-		handled += cx23885_irq_ts(ts1, ts1_status);
++	if (ts1_status) {
++		if (cx23885_boards[dev->board].portb == CX23885_MPEG_DVB)
++			handled += cx23885_irq_ts(ts1, ts1_status);
++	}
++
++	if (ts2_status) {
++		if (cx23885_boards[dev->board].portc == CX23885_MPEG_DVB)
++			handled += cx23885_irq_ts(ts2, ts2_status);
++	}
+ 
+-	if (ts2_status)
+-		handled += cx23885_irq_ts(ts2, ts2_status);
++	if (vida_status)
++		handled += cx23885_video_irq(dev, vida_status);
+ 
+ 	if (handled)
+ 		cx_write(PCI_INT_STAT, pci_status);
+diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c
+index eda8c05..ed465c0 100644
+--- a/drivers/media/video/cx23885/cx23885-dvb.c
++++ b/drivers/media/video/cx23885/cx23885-dvb.c
+@@ -32,13 +32,26 @@
+ 
+ #include "s5h1409.h"
+ #include "mt2131.h"
++#include "tda8290.h"
++#include "tda18271.h"
+ #include "lgdt330x.h"
++#include "xc5000.h"
+ #include "dvb-pll.h"
++#include "tuner-xc2028.h"
++#include "tuner-xc2028-types.h"
+ 
+-static unsigned int debug = 0;
++static unsigned int debug;
+ 
+-#define dprintk(level,fmt, arg...)	if (debug >= level) \
+-	printk(KERN_DEBUG "%s: " fmt, dev->name, ## arg)
++#define dprintk(level, fmt, arg...)\
++	do { if (debug >= level)\
++		printk(KERN_DEBUG "%s/0: " fmt, dev->name, ## arg);\
++	} while (0)
++
++/* ------------------------------------------------------------------ */
++
++static unsigned int alt_tuner;
++module_param(alt_tuner, int, 0644);
++MODULE_PARM_DESC(alt_tuner, "Enable alternate tuner configuration");
+ 
+ /* ------------------------------------------------------------------ */
+ 
+@@ -85,18 +98,39 @@ static struct s5h1409_config hauppauge_generic_config = {
+ 	.demod_address = 0x32 >> 1,
+ 	.output_mode   = S5H1409_SERIAL_OUTPUT,
+ 	.gpio          = S5H1409_GPIO_ON,
+-	.if_freq       = 44000,
++	.qam_if        = 44000,
+ 	.inversion     = S5H1409_INVERSION_OFF,
+-	.status_mode   = S5H1409_DEMODLOCKING
++	.status_mode   = S5H1409_DEMODLOCKING,
++	.mpeg_timing   = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
++};
++
++static struct s5h1409_config hauppauge_ezqam_config = {
++	.demod_address = 0x32 >> 1,
++	.output_mode   = S5H1409_SERIAL_OUTPUT,
++	.gpio          = S5H1409_GPIO_OFF,
++	.qam_if        = 4000,
++	.inversion     = S5H1409_INVERSION_ON,
++	.status_mode   = S5H1409_DEMODLOCKING,
++	.mpeg_timing   = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
+ };
+ 
+ static struct s5h1409_config hauppauge_hvr1800lp_config = {
+ 	.demod_address = 0x32 >> 1,
+ 	.output_mode   = S5H1409_SERIAL_OUTPUT,
+ 	.gpio          = S5H1409_GPIO_OFF,
+-	.if_freq       = 44000,
++	.qam_if        = 44000,
++	.inversion     = S5H1409_INVERSION_OFF,
++	.status_mode   = S5H1409_DEMODLOCKING,
++	.mpeg_timing   = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
++};
++
++static struct s5h1409_config hauppauge_hvr1500_config = {
++	.demod_address = 0x32 >> 1,
++	.output_mode   = S5H1409_SERIAL_OUTPUT,
++	.gpio          = S5H1409_GPIO_OFF,
+ 	.inversion     = S5H1409_INVERSION_OFF,
+-	.status_mode   = S5H1409_DEMODLOCKING
++	.status_mode   = S5H1409_DEMODLOCKING,
++	.mpeg_timing   = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
+ };
+ 
+ static struct mt2131_config hauppauge_generic_tunerconfig = {
+@@ -109,6 +143,66 @@ static struct lgdt330x_config fusionhdtv_5_express = {
+ 	.serial_mpeg = 0x40,
+ };
+ 
++static struct s5h1409_config hauppauge_hvr1500q_config = {
++	.demod_address = 0x32 >> 1,
++	.output_mode   = S5H1409_SERIAL_OUTPUT,
++	.gpio          = S5H1409_GPIO_ON,
++	.qam_if        = 44000,
++	.inversion     = S5H1409_INVERSION_OFF,
++	.status_mode   = S5H1409_DEMODLOCKING,
++	.mpeg_timing   = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
++};
++
++static struct xc5000_config hauppauge_hvr1500q_tunerconfig = {
++	.i2c_address      = 0x61,
++	.if_khz           = 5380,
++	.tuner_callback   = cx23885_tuner_callback
++};
++
++static struct tda829x_config tda829x_no_probe = {
++	.probe_tuner = TDA829X_DONT_PROBE,
++};
++
++static struct tda18271_std_map hauppauge_tda18271_std_map = {
++	.atsc_6   = { .if_freq = 5380, .std_bits = 0x1b },
++	.qam_6    = { .if_freq = 4000, .std_bits = 0x18 },
++};
++
++static struct tda18271_config hauppauge_tda18271_config = {
++	.std_map = &hauppauge_tda18271_std_map,
++	.gate    = TDA18271_GATE_ANALOG,
++};
++
++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", __FUNCTION__, 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", __FUNCTION__, arg);
++		break;
++	default:
++		dprintk(1, "%s: unknown command %d, arg %d\n", __FUNCTION__,
++			command, arg);
++		return -EINVAL;
++	}
++
++	return 0;
++}
++
+ static int dvb_register(struct cx23885_tsport *port)
+ {
+ 	struct cx23885_dev *dev = port->dev;
+@@ -120,7 +214,6 @@ static int dvb_register(struct cx23885_tsport *port)
+ 	/* init frontend */
+ 	switch (dev->board) {
+ 	case CX23885_BOARD_HAUPPAUGE_HVR1250:
+-	case CX23885_BOARD_HAUPPAUGE_HVR1800:
+ 		i2c_bus = &dev->i2c_bus[0];
+ 		port->dvb.frontend = dvb_attach(s5h1409_attach,
+ 						&hauppauge_generic_config,
+@@ -131,6 +224,36 @@ static int dvb_register(struct cx23885_tsport *port)
+ 				   &hauppauge_generic_tunerconfig, 0);
+ 		}
  		break;
- 	case V4L2_CID_SATURATION:
--		bt848_sat(btv,c->value);
-+		bt848_sat(btv, c->value);
++	case CX23885_BOARD_HAUPPAUGE_HVR1800:
++		i2c_bus = &dev->i2c_bus[0];
++		switch (alt_tuner) {
++		case 1:
++			port->dvb.frontend =
++				dvb_attach(s5h1409_attach,
++					   &hauppauge_ezqam_config,
++					   &i2c_bus->i2c_adap);
++			if (port->dvb.frontend != NULL) {
++				dvb_attach(tda829x_attach, port->dvb.frontend,
++					   &dev->i2c_bus[1].i2c_adap, 0x42,
++					   &tda829x_no_probe);
++				dvb_attach(tda18271_attach, port->dvb.frontend,
++					   0x60, &dev->i2c_bus[1].i2c_adap,
++					   &hauppauge_tda18271_config);
++			}
++			break;
++		case 0:
++		default:
++			port->dvb.frontend =
++				dvb_attach(s5h1409_attach,
++					   &hauppauge_generic_config,
++					   &i2c_bus->i2c_adap);
++			if (port->dvb.frontend != NULL)
++				dvb_attach(mt2131_attach, port->dvb.frontend,
++					   &i2c_bus->i2c_adap,
++					   &hauppauge_generic_tunerconfig, 0);
++			break;
++		}
++		break;
+ 	case CX23885_BOARD_HAUPPAUGE_HVR1800lp:
+ 		i2c_bus = &dev->i2c_bus[0];
+ 		port->dvb.frontend = dvb_attach(s5h1409_attach,
+@@ -152,6 +275,43 @@ static int dvb_register(struct cx23885_tsport *port)
+ 				   &i2c_bus->i2c_adap, DVB_PLL_LG_TDVS_H06XF);
+ 		}
  		break;
- 	case V4L2_CID_AUDIO_MUTE:
- 		audio_mute(btv, c->value);
- 		/* fall through */
- 	case V4L2_CID_AUDIO_VOLUME:
-+		if (btv->volume_gpio)
-+			btv->volume_gpio(btv, c->value);
++	case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
++		i2c_bus = &dev->i2c_bus[1];
++		port->dvb.frontend = dvb_attach(s5h1409_attach,
++						&hauppauge_hvr1500q_config,
++						&dev->i2c_bus[0].i2c_adap);
++		if (port->dvb.frontend != NULL) {
++			hauppauge_hvr1500q_tunerconfig.priv = i2c_bus;
++			dvb_attach(xc5000_attach, port->dvb.frontend,
++				&i2c_bus->i2c_adap,
++				&hauppauge_hvr1500q_tunerconfig);
++		}
++		break;
++	case CX23885_BOARD_HAUPPAUGE_HVR1500:
++		i2c_bus = &dev->i2c_bus[1];
++		port->dvb.frontend = dvb_attach(s5h1409_attach,
++						&hauppauge_hvr1500_config,
++						&dev->i2c_bus[0].i2c_adap);
++		if (port->dvb.frontend != NULL) {
++			struct dvb_frontend *fe;
++			struct xc2028_config cfg = {
++				.i2c_adap  = &i2c_bus->i2c_adap,
++				.i2c_addr  = 0x61,
++				.video_dev = port,
++				.callback  = cx23885_hvr1500_xc3028_callback,
++			};
++			static struct xc2028_ctrl ctl = {
++				.fname       = "xc3028-v27.fw",
++				.max_len     = 64,
++				.scode_table = OREN538,
++			};
++
++			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",
+ 		       dev->name);
+@@ -165,6 +325,9 @@ static int dvb_register(struct cx23885_tsport *port)
+ 	/* Put the analog decoder in standby to keep it quiet */
+ 	cx23885_call_i2c_clients(i2c_bus, TUNER_SET_STANDBY, NULL);
+ 
++	if (port->dvb.frontend->ops.analog_ops.standby)
++		port->dvb.frontend->ops.analog_ops.standby(port->dvb.frontend);
++
+ 	/* register everything */
+ 	return videobuf_dvb_register(&port->dvb, THIS_MODULE, port,
+ 				     &dev->pci->dev);
+diff --git a/drivers/media/video/cx23885/cx23885-i2c.c b/drivers/media/video/cx23885/cx23885-i2c.c
+index 71da528..92fe0bd 100644
+--- a/drivers/media/video/cx23885/cx23885-i2c.c
++++ b/drivers/media/video/cx23885/cx23885-i2c.c
+@@ -29,7 +29,7 @@
+ 
+ #include <media/v4l2-common.h>
+ 
+-static unsigned int i2c_debug = 0;
++static unsigned int i2c_debug;
+ module_param(i2c_debug, int, 0644);
+ MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]");
+ 
+@@ -37,8 +37,10 @@ static unsigned int i2c_scan = 0;
+ module_param(i2c_scan, int, 0444);
+ MODULE_PARM_DESC(i2c_scan, "scan i2c bus at insmod time");
+ 
+-#define dprintk(level,fmt, arg...)	if (i2c_debug >= level) \
+-	printk(KERN_DEBUG "%s: " fmt, dev->name , ## arg)
++#define dprintk(level, fmt, arg...)\
++	do { if (i2c_debug >= level)\
++		printk(KERN_DEBUG "%s/0: " fmt, dev->name, ## arg);\
++	} while (0)
+ 
+ #define I2C_WAIT_DELAY 32
+ #define I2C_WAIT_RETRY 64
+@@ -77,14 +79,19 @@ static int i2c_wait_done(struct i2c_adapter *i2c_adap)
+ }
+ 
+ static int i2c_sendbytes(struct i2c_adapter *i2c_adap,
+-			 const struct i2c_msg *msg, int last)
++			 const struct i2c_msg *msg, int joined_rlen)
+ {
+ 	struct cx23885_i2c *bus = i2c_adap->algo_data;
+ 	struct cx23885_dev *dev = bus->dev;
+ 	u32 wdata, addr, ctrl;
+ 	int retval, cnt;
+ 
+-	dprintk(1, "%s()\n", __FUNCTION__);
++	if (joined_rlen)
++		dprintk(1, "%s(msg->wlen=%d, nextmsg->rlen=%d)\n", __FUNCTION__,
++			msg->len, joined_rlen);
++	else
++		dprintk(1, "%s(msg->len=%d)\n", __FUNCTION__, msg->len);
 +
-+		bttv_call_i2c_clients(btv, VIDIOC_S_CTRL, c);
-+		break;
- 	case V4L2_CID_AUDIO_BALANCE:
- 	case V4L2_CID_AUDIO_BASS:
- 	case V4L2_CID_AUDIO_TREBLE:
--		bttv_call_i2c_clients(btv,VIDIOC_S_CTRL,c);
-+		bttv_call_i2c_clients(btv, VIDIOC_S_CTRL, c);
- 		break;
+ 	/* Deal with i2c probe functions with zero payload */
+ 	if (msg->len == 0) {
+ 		cx_write(bus->reg_addr, msg->addr << 25);
+@@ -106,6 +113,8 @@ static int i2c_sendbytes(struct i2c_adapter *i2c_adap,
  
- 	case V4L2_CID_PRIVATE_CHROMA_AGC:
-@@ -1632,8 +1573,9 @@ static int set_control(struct bttv *btv, struct v4l2_control *c)
- 		break;
- 	case V4L2_CID_PRIVATE_AGC_CRUSH:
- 		btv->opt_adc_crush = c->value;
--		btwrite(BT848_ADC_RESERVED | (btv->opt_adc_crush ? BT848_ADC_CRUSH : 0),
--			BT848_ADC);
-+		btwrite(BT848_ADC_RESERVED |
-+				(btv->opt_adc_crush ? BT848_ADC_CRUSH : 0),
-+				BT848_ADC);
- 		break;
- 	case V4L2_CID_PRIVATE_VCR_HACK:
- 		btv->opt_vcr_hack = c->value;
-@@ -1693,29 +1635,15 @@ static void bttv_field_count(struct bttv *btv)
+ 	if (msg->len > 1)
+ 		ctrl |= I2C_NOSTOP | I2C_EXTEND;
++	else if (joined_rlen)
++		ctrl |= I2C_NOSTOP;
+ 
+ 	cx_write(bus->reg_addr, addr);
+ 	cx_write(bus->reg_wdata, wdata);
+@@ -127,8 +136,10 @@ static int i2c_sendbytes(struct i2c_adapter *i2c_adap,
+ 		wdata = msg->buf[cnt];
+ 		ctrl = bus->i2c_period | (1 << 12) | (1 << 2);
+ 
+-		if (cnt < msg->len-1 || !last)
++		if (cnt < msg->len - 1)
+ 			ctrl |= I2C_NOSTOP | I2C_EXTEND;
++		else if (joined_rlen)
++			ctrl |= I2C_NOSTOP;
+ 
+ 		cx_write(bus->reg_addr, addr);
+ 		cx_write(bus->reg_wdata, wdata);
+@@ -150,19 +161,22 @@ static int i2c_sendbytes(struct i2c_adapter *i2c_adap,
+  eio:
+ 	retval = -EIO;
+  err:
+-	printk(" ERR: %d\n", retval);
++	if (i2c_debug)
++		printk(" ERR: %d\n", retval);
+ 	return retval;
  }
  
- static const struct bttv_format*
--format_by_palette(int palette)
--{
--	unsigned int i;
--
--	for (i = 0; i < BTTV_FORMATS; i++) {
--		if (-1 == bttv_formats[i].palette)
--			continue;
--		if (bttv_formats[i].palette == palette)
--			return bttv_formats+i;
--	}
--	return NULL;
--}
--
--static const struct bttv_format*
- format_by_fourcc(int fourcc)
+ static int i2c_readbytes(struct i2c_adapter *i2c_adap,
+-			 const struct i2c_msg *msg, int last)
++			 const struct i2c_msg *msg, int joined)
  {
- 	unsigned int i;
+ 	struct cx23885_i2c *bus = i2c_adap->algo_data;
+ 	struct cx23885_dev *dev = bus->dev;
+ 	u32 ctrl, cnt;
+ 	int retval;
  
--	for (i = 0; i < BTTV_FORMATS; i++) {
--		if (-1 == bttv_formats[i].fourcc)
-+	for (i = 0; i < FORMATS; i++) {
-+		if (-1 == formats[i].fourcc)
- 			continue;
--		if (bttv_formats[i].fourcc == fourcc)
--			return bttv_formats+i;
-+		if (formats[i].fourcc == fourcc)
-+			return formats+i;
- 	}
- 	return NULL;
- }
-@@ -1733,7 +1661,7 @@ bttv_switch_overlay(struct bttv *btv, struct bttv_fh *fh,
+-	dprintk(1, "%s()\n", __FUNCTION__);
++
++	if (i2c_debug && !joined)
++		dprintk(1, "%s(msg->len=%d)\n", __FUNCTION__, msg->len);
  
- 	dprintk("switch_overlay: enter [new=%p]\n",new);
- 	if (new)
--		new->vb.state = STATE_DONE;
-+		new->vb.state = VIDEOBUF_DONE;
- 	spin_lock_irqsave(&btv->s_lock,flags);
- 	old = btv->screen;
- 	btv->screen = new;
-@@ -1844,7 +1772,7 @@ static int bttv_prepare_buffer(struct videobuf_queue *q,struct bttv *btv,
+ 	/* Deal with i2c probe functions with zero payload */
+ 	if (msg->len == 0) {
+@@ -178,11 +192,18 @@ static int i2c_readbytes(struct i2c_adapter *i2c_adap,
+ 		return 0;
  	}
  
- 	/* alloc risc memory */
--	if (STATE_NEEDS_INIT == buf->vb.state) {
-+	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
- 		redo_dma_risc = 1;
- 		if (0 != (rc = videobuf_iolock(q,&buf->vb,&btv->fbuf)))
- 			goto fail;
-@@ -1854,7 +1782,7 @@ static int bttv_prepare_buffer(struct videobuf_queue *q,struct bttv *btv,
- 		if (0 != (rc = bttv_buffer_risc(btv,buf)))
- 			goto fail;
++	if (i2c_debug) {
++		if (joined)
++			printk(" R");
++		else
++			printk(" <R %02x", (msg->addr << 1) + 1);
++	}
++
+ 	for(cnt = 0; cnt < msg->len; cnt++) {
  
--	buf->vb.state = STATE_PREPARED;
-+	buf->vb.state = VIDEOBUF_PREPARED;
- 	return 0;
+ 		ctrl = bus->i2c_period | (1 << 12) | (1 << 2) | 1;
  
-  fail:
-@@ -1893,7 +1821,7 @@ buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
- 	struct bttv_fh *fh = q->priv_data;
- 	struct bttv    *btv = fh->btv;
+-		if (cnt < msg->len-1 || !last)
++		if (cnt < msg->len - 1)
+ 			ctrl |= I2C_NOSTOP | I2C_EXTEND;
  
--	buf->vb.state = STATE_QUEUED;
-+	buf->vb.state = VIDEOBUF_QUEUED;
- 	list_add_tail(&buf->vb.queue,&btv->capture);
- 	if (!btv->curr.frame_irq) {
- 		btv->loop_irq |= 1;
-@@ -1916,374 +1844,234 @@ static struct videobuf_queue_ops bttv_video_qops = {
- 	.buf_release  = buffer_release,
- };
+ 		cx_write(bus->reg_addr, msg->addr << 25);
+@@ -195,9 +216,7 @@ static int i2c_readbytes(struct i2c_adapter *i2c_adap,
+ 			goto eio;
+ 		msg->buf[cnt] = cx_read(bus->reg_rdata) & 0xff;
+ 		if (i2c_debug) {
+-			if (!(ctrl & I2C_NOSTOP))
+-				printk(" <R %02x", (msg->addr << 1) +1);
+-			printk(" =%02x", msg->buf[cnt]);
++			printk(" %02x", msg->buf[cnt]);
+ 			if (!(ctrl & I2C_NOSTOP))
+ 				printk(" >\n");
+ 		}
+@@ -207,7 +226,8 @@ static int i2c_readbytes(struct i2c_adapter *i2c_adap,
+  eio:
+ 	retval = -EIO;
+  err:
+-	printk(" ERR: %d\n", retval);
++	if (i2c_debug)
++		printk(" ERR: %d\n", retval);
+ 	return retval;
+ }
  
--static int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg)
-+static int bttv_s_std(struct file *file, void *priv, v4l2_std_id *id)
- {
--	switch (cmd) {
--	case BTTV_VERSION:
--		return BTTV_VERSION_CODE;
-+	struct bttv_fh *fh  = priv;
-+	struct bttv *btv = fh->btv;
-+	unsigned int i;
-+	int err;
+@@ -225,15 +245,22 @@ static int i2c_xfer(struct i2c_adapter *i2c_adap,
+ 			__FUNCTION__, num, msgs[i].addr, msgs[i].len);
+ 		if (msgs[i].flags & I2C_M_RD) {
+ 			/* read */
+-			retval = i2c_readbytes(i2c_adap, &msgs[i], i+1 == num);
++			retval = i2c_readbytes(i2c_adap, &msgs[i], 0);
++		} else if (i + 1 < num && (msgs[i + 1].flags & I2C_M_RD) &&
++			   msgs[i].addr == msgs[i + 1].addr) {
++			/* write then read from same address */
++			retval = i2c_sendbytes(i2c_adap, &msgs[i],
++					       msgs[i + 1].len);
+ 			if (retval < 0)
+ 				goto err;
++			i++;
++			retval = i2c_readbytes(i2c_adap, &msgs[i], 1);
+ 		} else {
+ 			/* write */
+-			retval = i2c_sendbytes(i2c_adap, &msgs[i], i+1 == num);
+-			if (retval < 0)
+-				goto err;
++			retval = i2c_sendbytes(i2c_adap, &msgs[i], 0);
+ 		}
++		if (retval < 0)
++			goto err;
+ 	}
+ 	return num;
  
--	/* ***  v4l1  *** ************************************************ */
--	case VIDIOCGFREQ:
--	{
--		unsigned long *freq = arg;
--		*freq = btv->freq;
--		return 0;
--	}
--	case VIDIOCSFREQ:
--	{
--		struct v4l2_frequency freq;
-+	err = v4l2_prio_check(&btv->prio, &fh->prio);
-+	if (0 != err)
-+		return err;
+@@ -243,7 +270,9 @@ static int i2c_xfer(struct i2c_adapter *i2c_adap,
  
--		memset(&freq, 0, sizeof(freq));
--		freq.frequency = *(unsigned long *)arg;
--		mutex_lock(&btv->lock);
--		freq.type = btv->radio_user ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
--		btv->freq = *(unsigned long *)arg;
--		bttv_call_i2c_clients(btv,VIDIOC_S_FREQUENCY,&freq);
--		if (btv->has_matchbox && btv->radio_user)
--			tea5757_set_freq(btv,*(unsigned long *)arg);
--		mutex_unlock(&btv->lock);
--		return 0;
--	}
-+	for (i = 0; i < BTTV_TVNORMS; i++)
-+		if (*id & bttv_tvnorms[i].v4l2_id)
-+			break;
-+	if (i == BTTV_TVNORMS)
-+		return -EINVAL;
+ static int attach_inform(struct i2c_client *client)
+ {
+-	struct cx23885_dev *dev = i2c_get_adapdata(client->adapter);
++	struct cx23885_i2c *bus = i2c_get_adapdata(client->adapter);
++	struct cx23885_dev *dev = bus->dev;
++	struct tuner_setup tun_setup;
  
--	case VIDIOCGTUNER:
--	{
--		struct video_tuner *v = arg;
-+	mutex_lock(&btv->lock);
-+	set_tvnorm(btv, i);
-+	mutex_unlock(&btv->lock);
+ 	dprintk(1, "%s i2c attach [addr=0x%x,client=%s]\n",
+ 		client->driver->driver.name, client->addr, client->name);
+@@ -251,6 +280,31 @@ static int attach_inform(struct i2c_client *client)
+ 	if (!client->driver->command)
+ 		return 0;
  
--		if (UNSET == bttv_tvcards[btv->c.type].tuner)
--			return -EINVAL;
--		if (v->tuner) /* Only tuner 0 */
--			return -EINVAL;
--		strcpy(v->name, "Television");
--		v->rangelow  = 0;
--		v->rangehigh = 0x7FFFFFFF;
--		v->flags     = VIDEO_TUNER_PAL|VIDEO_TUNER_NTSC|VIDEO_TUNER_SECAM;
--		v->mode      = btv->tvnorm;
--		v->signal    = (btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC) ? 0xFFFF : 0;
--		bttv_call_i2c_clients(btv,cmd,v);
--		return 0;
--	}
--	case VIDIOCSTUNER:
--	{
--		struct video_tuner *v = arg;
-+	return 0;
-+}
++	if (dev->tuner_type != UNSET) {
++
++		dprintk(1, "%s  (tuner) i2c attach [addr=0x%x,client=%s]\n",
++			client->driver->driver.name, client->addr,
++			client->name);
++
++		if ((dev->tuner_addr == ADDR_UNSET) ||
++			(dev->tuner_addr == client->addr)) {
++
++			dprintk(1, "%s (tuner || addr UNSET)\n",
++				client->driver->driver.name);
++
++			dprintk(1, "%s i2c attach [addr=0x%x,client=%s]\n",
++				client->driver->driver.name,
++				client->addr, client->name);
++
++			tun_setup.mode_mask = T_ANALOG_TV;
++			tun_setup.type = dev->tuner_type;
++			tun_setup.addr = dev->tuner_addr;
++
++			client->driver->command(client, TUNER_SET_TYPE_ADDR,
++				&tun_setup);
++		}
++	}
++
+ 	return 0;
+ }
  
--		if (v->tuner) /* Only tuner 0 */
--			return -EINVAL;
--		if (v->mode >= BTTV_TVNORMS)
--			return -EINVAL;
-+static int bttv_querystd(struct file *file, void *f, v4l2_std_id *id)
-+{
-+	struct bttv_fh *fh = f;
-+	struct bttv *btv = fh->btv;
+@@ -289,6 +343,7 @@ static struct i2c_adapter cx23885_i2c_adap_template = {
+ 	.owner             = THIS_MODULE,
+ 	.id                = I2C_HW_B_CX23885,
+ 	.algo              = &cx23885_i2c_algo_template,
++	.class             = I2C_CLASS_TV_ANALOG,
+ 	.client_register   = attach_inform,
+ 	.client_unregister = detach_inform,
+ };
+@@ -305,7 +360,7 @@ static char *i2c_devs[128] = {
+ 	[ 0x84 >> 1 ] = "tda8295",
+ 	[ 0xa0 >> 1 ] = "eeprom",
+ 	[ 0xc0 >> 1 ] = "tuner/mt2131/tda8275",
+-	[ 0xc2 >> 1 ] = "tuner/mt2131/tda8275",
++	[ 0xc2 >> 1 ] = "tuner/mt2131/tda8275/xc5000",
+ };
  
--		mutex_lock(&btv->lock);
--		set_tvnorm(btv,v->mode);
--		bttv_call_i2c_clients(btv,cmd,v);
--		mutex_unlock(&btv->lock);
--		return 0;
--	}
-+	if (btread(BT848_DSTATUS) & BT848_DSTATUS_NUML)
-+		*id = V4L2_STD_625_50;
-+	else
-+		*id = V4L2_STD_525_60;
-+	return 0;
-+}
+ static void do_i2c_scan(char *name, struct i2c_client *c)
+@@ -344,6 +399,7 @@ int cx23885_i2c_register(struct cx23885_i2c *bus)
  
--	case VIDIOCGCHAN:
--	{
--		struct video_channel *v = arg;
--		unsigned int channel = v->channel;
-+static int bttv_enum_input(struct file *file, void *priv,
-+					struct v4l2_input *i)
-+{
-+	struct bttv_fh *fh = priv;
-+	struct bttv *btv = fh->btv;
-+	unsigned int n;
+ 	bus->i2c_algo.data = bus;
+ 	bus->i2c_adap.algo_data = bus;
++	i2c_set_adapdata(&bus->i2c_adap, bus);
+ 	i2c_add_adapter(&bus->i2c_adap);
  
--		if (channel >= bttv_tvcards[btv->c.type].video_inputs)
--			return -EINVAL;
--		v->tuners=0;
--		v->flags = VIDEO_VC_AUDIO;
--		v->type = VIDEO_TYPE_CAMERA;
--		v->norm = btv->tvnorm;
--		if (channel == bttv_tvcards[btv->c.type].tuner)  {
--			strcpy(v->name,"Television");
--			v->flags|=VIDEO_VC_TUNER;
--			v->type=VIDEO_TYPE_TV;
--			v->tuners=1;
--		} else if (channel == btv->svhs) {
--			strcpy(v->name,"S-Video");
--		} else {
--			sprintf(v->name,"Composite%d",channel);
--		}
--		return 0;
--	}
--	case VIDIOCSCHAN:
--	{
--		struct video_channel *v = arg;
--		unsigned int channel = v->channel;
-+	n = i->index;
+ 	bus->i2c_client.adapter = &bus->i2c_adap;
+@@ -366,8 +422,6 @@ int cx23885_i2c_unregister(struct cx23885_i2c *bus)
  
--		if (channel >= bttv_tvcards[btv->c.type].video_inputs)
--			return -EINVAL;
--		if (v->norm >= BTTV_TVNORMS)
--			return -EINVAL;
-+	if (n >= bttv_tvcards[btv->c.type].video_inputs)
-+		return -EINVAL;
+ /* ----------------------------------------------------------------------- */
  
--		mutex_lock(&btv->lock);
--		if (channel == btv->input &&
--		    v->norm == btv->tvnorm) {
--			/* nothing to do */
--			mutex_unlock(&btv->lock);
--			return 0;
--		}
-+	memset(i, 0, sizeof(*i));
+-EXPORT_SYMBOL(cx23885_call_i2c_clients);
+-
+ /*
+  * Local variables:
+  * c-basic-offset: 8
+diff --git a/drivers/media/video/cx23885/cx23885-reg.h b/drivers/media/video/cx23885/cx23885-reg.h
+index 162169f..bdd11bc 100644
+--- a/drivers/media/video/cx23885/cx23885-reg.h
++++ b/drivers/media/video/cx23885/cx23885-reg.h
+@@ -233,6 +233,17 @@ Channel manager Data Structure entry = 20 DWORD
+ #define VID_A_INT_SSTAT	0x0004002C
  
--		set_input(btv, v->channel, v->norm);
--		mutex_unlock(&btv->lock);
--		return 0;
-+	i->index    = n;
-+	i->type     = V4L2_INPUT_TYPE_CAMERA;
-+	i->audioset = 1;
-+
-+	if (i->index == bttv_tvcards[btv->c.type].tuner) {
-+		sprintf(i->name, "Television");
-+		i->type  = V4L2_INPUT_TYPE_TUNER;
-+		i->tuner = 0;
-+	} else if (i->index == btv->svhs) {
-+		sprintf(i->name, "S-Video");
-+	} else {
-+		sprintf(i->name, "Composite%d", i->index);
- 	}
+ #define VID_B_INT_MSK	0x00040030
++#define VID_B_MSK_BAD_PKT     (1 << 20)
++#define VID_B_MSK_VBI_OPC_ERR (1 << 17)
++#define VID_B_MSK_OPC_ERR     (1 << 16)
++#define VID_B_MSK_VBI_SYNC    (1 << 13)
++#define VID_B_MSK_SYNC        (1 << 12)
++#define VID_B_MSK_VBI_OF      (1 <<  9)
++#define VID_B_MSK_OF          (1 <<  8)
++#define VID_B_MSK_VBI_RISCI2  (1 <<  5)
++#define VID_B_MSK_RISCI2      (1 <<  4)
++#define VID_B_MSK_VBI_RISCI1  (1 <<  1)
++#define VID_B_MSK_RISCI1       1
+ #define VID_B_INT_STAT	0x00040034
+ #define VID_B_INT_MSTAT	0x00040038
+ #define VID_B_INT_SSTAT	0x0004003C
+@@ -276,6 +287,7 @@ Channel manager Data Structure entry = 20 DWORD
  
--	case VIDIOCGAUDIO:
--	{
--		struct video_audio *v = arg;
-+	if (i->index == btv->input) {
-+		__u32 dstatus = btread(BT848_DSTATUS);
-+		if (0 == (dstatus & BT848_DSTATUS_PRES))
-+			i->status |= V4L2_IN_ST_NO_SIGNAL;
-+		if (0 == (dstatus & BT848_DSTATUS_HLOC))
-+			i->status |= V4L2_IN_ST_NO_H_LOCK;
-+	}
+ #define RDR_CFG0	0x00050000
+ #define RDR_CFG1	0x00050004
++#define RDR_CFG2	0x00050008
+ #define RDR_TLCTL0	0x00050318
  
--		memset(v,0,sizeof(*v));
--		strcpy(v->name,"Television");
--		v->flags |= VIDEO_AUDIO_MUTABLE;
--		v->mode  = VIDEO_SOUND_MONO;
-+	for (n = 0; n < BTTV_TVNORMS; n++)
-+		i->std |= bttv_tvnorms[n].v4l2_id;
+ /* APB DMAC Current Buffer Pointer */
+@@ -335,6 +347,7 @@ Channel manager Data Structure entry = 20 DWORD
+ /* GPIO (417 Microsoftcontroller) Output Enable, Low Active */
+ #define MC417_OEN	0x00110024
+ #define MC417_CTL	0x00110028
++#define ALT_PIN_OUT_SEL 0x0011002C
+ #define CLK_DELAY	0x00110048
+ #define PAD_CTRL	0x0011004C
  
--		mutex_lock(&btv->lock);
--		bttv_call_i2c_clients(btv,cmd,v);
+diff --git a/drivers/media/video/cx23885/cx23885-vbi.c b/drivers/media/video/cx23885/cx23885-vbi.c
+new file mode 100644
+index 0000000..e36e3fc
+--- /dev/null
++++ b/drivers/media/video/cx23885/cx23885-vbi.c
+@@ -0,0 +1,258 @@
++/*
++ *  Driver for the Conexant CX23885 PCIe bridge
++ *
++ *  Copyright (c) 2007 Steven Toth <stoth at hauppauge.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/module.h>
++#include <linux/moduleparam.h>
++#include <linux/init.h>
++#include <linux/slab.h>
++
++#include "cx23885.h"
++
++static unsigned int vbibufs = 4;
++module_param(vbibufs, int, 0644);
++MODULE_PARM_DESC(vbibufs, "number of vbi buffers, range 2-32");
++
++static unsigned int vbi_debug;
++module_param(vbi_debug, int, 0644);
++MODULE_PARM_DESC(vbi_debug, "enable debug messages [vbi]");
++
++#define dprintk(level, fmt, arg...)\
++	do { if (vbi_debug >= level)\
++		printk(KERN_DEBUG "%s/0: " fmt, dev->name, ## arg);\
++	} while (0)
++
++/* ------------------------------------------------------------------ */
++
++int cx23885_vbi_fmt(struct file *file, void *priv,
++	struct v4l2_format *f)
++{
++	struct cx23885_fh *fh = priv;
++	struct cx23885_dev *dev = fh->dev;
++
++	if (dev->tvnorm & V4L2_STD_525_60) {
++		/* ntsc */
++		f->fmt.vbi.sampling_rate = 28636363;
++		f->fmt.vbi.start[0] = 10;
++		f->fmt.vbi.start[1] = 273;
++
++	} else if (dev->tvnorm & V4L2_STD_625_50) {
++		/* pal */
++		f->fmt.vbi.sampling_rate = 35468950;
++		f->fmt.vbi.start[0] = 7 - 1;
++		f->fmt.vbi.start[1] = 319 - 1;
++	}
 +	return 0;
 +}
- 
--		/* card specific hooks */
--		if (btv->audio_hook)
--			btv->audio_hook(btv,v,0);
-+static int bttv_g_input(struct file *file, void *priv, unsigned int *i)
++
++static int cx23885_start_vbi_dma(struct cx23885_dev    *dev,
++			 struct cx23885_dmaqueue *q,
++			 struct cx23885_buffer   *buf)
 +{
-+	struct bttv_fh *fh = priv;
-+	struct bttv *btv = fh->btv;
- 
--		mutex_unlock(&btv->lock);
--		return 0;
--	}
--	case VIDIOCSAUDIO:
--	{
--		struct video_audio *v = arg;
--		unsigned int audio = v->audio;
-+	*i = btv->input;
++	/* setup fifo + format */
++	cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH02],
++				buf->vb.width, buf->risc.dma);
++
++	/* reset counter */
++	q->count = 1;
++
++	/* enable irqs */
++	cx_set(PCI_INT_MSK, cx_read(PCI_INT_MSK) | 0x01);
++	cx_set(VID_A_INT_MSK, 0x000022);
++
++	/* start dma */
++	cx_set(DEV_CNTRL2, (1<<5));
++	cx_set(VID_A_DMA_CTL, 0x00000022);
++
 +	return 0;
 +}
- 
--		if (audio >= bttv_tvcards[btv->c.type].audio_inputs)
--			return -EINVAL;
-+static int bttv_s_input(struct file *file, void *priv, unsigned int i)
++
++int cx23885_stop_vbi_dma(struct cx23885_dev *dev)
 +{
-+	struct bttv_fh *fh  = priv;
-+	struct bttv *btv = fh->btv;
- 
--		mutex_lock(&btv->lock);
--		audio_mute(btv, (v->flags&VIDEO_AUDIO_MUTE) ? 1 : 0);
--		bttv_call_i2c_clients(btv,cmd,v);
-+	int err;
- 
--		/* card specific hooks */
--		if (btv->audio_hook)
--			btv->audio_hook(btv,v,1);
-+	err = v4l2_prio_check(&btv->prio, &fh->prio);
-+	if (0 != err)
-+		return err;
- 
--		mutex_unlock(&btv->lock);
--		return 0;
--	}
-+	if (i > bttv_tvcards[btv->c.type].video_inputs)
-+		return -EINVAL;
- 
--	/* ***  v4l2  *** ************************************************ */
--	case VIDIOC_ENUMSTD:
--	{
--		struct v4l2_standard *e = arg;
--		unsigned int index = e->index;
-+	mutex_lock(&btv->lock);
-+	set_input(btv, i, btv->tvnorm);
-+	mutex_unlock(&btv->lock);
++	/* 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;
 +}
- 
--		if (index >= BTTV_TVNORMS)
--			return -EINVAL;
--		v4l2_video_std_construct(e, bttv_tvnorms[e->index].v4l2_id,
--					 bttv_tvnorms[e->index].name);
--		e->index = index;
--		return 0;
--	}
--	case VIDIOC_G_STD:
--	{
--		v4l2_std_id *id = arg;
--		*id = bttv_tvnorms[btv->tvnorm].v4l2_id;
--		return 0;
--	}
--	case VIDIOC_S_STD:
--	{
--		v4l2_std_id *id = arg;
--		unsigned int i;
-+static int bttv_s_tuner(struct file *file, void *priv,
-+					struct v4l2_tuner *t)
++
++int cx23885_restart_vbi_queue(struct cx23885_dev    *dev,
++			     struct cx23885_dmaqueue *q)
 +{
-+	struct bttv_fh *fh  = priv;
-+	struct bttv *btv = fh->btv;
-+	int err;
- 
--		for (i = 0; i < BTTV_TVNORMS; i++)
--			if (*id & bttv_tvnorms[i].v4l2_id)
--				break;
--		if (i == BTTV_TVNORMS)
--			return -EINVAL;
-+	err = v4l2_prio_check(&btv->prio, &fh->prio);
-+	if (0 != err)
-+		return err;
- 
--		mutex_lock(&btv->lock);
--		set_tvnorm(btv,i);
--		i2c_vidiocschan(btv);
--		mutex_unlock(&btv->lock);
--		return 0;
--	}
--	case VIDIOC_QUERYSTD:
--	{
--		v4l2_std_id *id = arg;
-+	if (UNSET == bttv_tvcards[btv->c.type].tuner)
-+		return -EINVAL;
- 
--		if (btread(BT848_DSTATUS) & BT848_DSTATUS_NUML)
--			*id = V4L2_STD_625_50;
--		else
--			*id = V4L2_STD_525_60;
--		return 0;
--	}
-+	if (0 != t->index)
-+		return -EINVAL;
- 
--	case VIDIOC_ENUMINPUT:
--	{
--		struct v4l2_input *i = arg;
--		unsigned int n;
-+	mutex_lock(&btv->lock);
-+	bttv_call_i2c_clients(btv, VIDIOC_S_TUNER, t);
- 
--		n = i->index;
--		if (n >= bttv_tvcards[btv->c.type].video_inputs)
--			return -EINVAL;
--		memset(i,0,sizeof(*i));
--		i->index    = n;
--		i->type     = V4L2_INPUT_TYPE_CAMERA;
--		i->audioset = 1;
--		if (i->index == bttv_tvcards[btv->c.type].tuner) {
--			sprintf(i->name, "Television");
--			i->type  = V4L2_INPUT_TYPE_TUNER;
--			i->tuner = 0;
--		} else if (i->index == btv->svhs) {
--			sprintf(i->name, "S-Video");
--		} else {
--			sprintf(i->name,"Composite%d",i->index);
--		}
--		if (i->index == btv->input) {
--			__u32 dstatus = btread(BT848_DSTATUS);
--			if (0 == (dstatus & BT848_DSTATUS_PRES))
--				i->status |= V4L2_IN_ST_NO_SIGNAL;
--			if (0 == (dstatus & BT848_DSTATUS_HLOC))
--				i->status |= V4L2_IN_ST_NO_H_LOCK;
--		}
--		for (n = 0; n < BTTV_TVNORMS; n++)
--			i->std |= bttv_tvnorms[n].v4l2_id;
--		return 0;
--	}
--	case VIDIOC_G_INPUT:
--	{
--		int *i = arg;
--		*i = btv->input;
--		return 0;
--	}
--	case VIDIOC_S_INPUT:
--	{
--		unsigned int *i = arg;
-+	if (btv->audio_mode_gpio)
-+		btv->audio_mode_gpio(btv, t, 1);
- 
--		if (*i > bttv_tvcards[btv->c.type].video_inputs)
--			return -EINVAL;
--		mutex_lock(&btv->lock);
--		set_input(btv, *i, btv->tvnorm);
--		mutex_unlock(&btv->lock);
--		return 0;
--	}
-+	mutex_unlock(&btv->lock);
- 
--	case VIDIOC_G_TUNER:
--	{
--		struct v4l2_tuner *t = arg;
++	struct cx23885_buffer *buf;
++	struct list_head *item;
++
++	if (list_empty(&q->active))
++		return 0;
++
++	buf = list_entry(q->active.next, struct cx23885_buffer, vb.queue);
++	dprintk(2, "restart_queue [%p/%d]: restart dma\n",
++		buf, buf->vb.i);
++	cx23885_start_vbi_dma(dev, q, buf);
++	list_for_each(item, &q->active) {
++		buf = list_entry(item, struct cx23885_buffer, vb.queue);
++		buf->count = q->count++;
++	}
++	mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
 +	return 0;
 +}
- 
--		if (UNSET == bttv_tvcards[btv->c.type].tuner)
--			return -EINVAL;
--		if (0 != t->index)
--			return -EINVAL;
--		mutex_lock(&btv->lock);
--		memset(t,0,sizeof(*t));
--		t->rxsubchans = V4L2_TUNER_SUB_MONO;
--		bttv_call_i2c_clients(btv, VIDIOC_G_TUNER, t);
--		strcpy(t->name, "Television");
--		t->capability = V4L2_TUNER_CAP_NORM;
--		t->type       = V4L2_TUNER_ANALOG_TV;
--		if (btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC)
--			t->signal = 0xffff;
--
--		if (btv->audio_hook) {
--			/* Hmmm ... */
--			struct video_audio va;
--			memset(&va, 0, sizeof(struct video_audio));
--			btv->audio_hook(btv,&va,0);
--			t->audmode    = V4L2_TUNER_MODE_MONO;
--			t->rxsubchans = V4L2_TUNER_SUB_MONO;
--			if(va.mode & VIDEO_SOUND_STEREO) {
--				t->audmode    = V4L2_TUNER_MODE_STEREO;
--				t->rxsubchans = V4L2_TUNER_SUB_STEREO;
--			}
--			if(va.mode & VIDEO_SOUND_LANG2) {
--				t->audmode    = V4L2_TUNER_MODE_LANG1;
--				t->rxsubchans = V4L2_TUNER_SUB_LANG1
--					| V4L2_TUNER_SUB_LANG2;
--			}
--		}
--		/* FIXME: fill capability+audmode */
--		mutex_unlock(&btv->lock);
--		return 0;
--	}
--	case VIDIOC_S_TUNER:
--	{
--		struct v4l2_tuner *t = arg;
-+static int bttv_g_frequency(struct file *file, void *priv,
-+					struct v4l2_frequency *f)
++
++void cx23885_vbi_timeout(unsigned long data)
 +{
-+	struct bttv_fh *fh  = priv;
-+	struct bttv *btv = fh->btv;
-+	int err;
- 
--		if (UNSET == bttv_tvcards[btv->c.type].tuner)
--			return -EINVAL;
--		if (0 != t->index)
--			return -EINVAL;
--		mutex_lock(&btv->lock);
--		bttv_call_i2c_clients(btv, VIDIOC_S_TUNER, t);
--		if (btv->audio_hook) {
--			struct video_audio va;
--			memset(&va, 0, sizeof(struct video_audio));
--			if (t->audmode == V4L2_TUNER_MODE_MONO)
--				va.mode = VIDEO_SOUND_MONO;
--			else if (t->audmode == V4L2_TUNER_MODE_STEREO ||
--				 t->audmode == V4L2_TUNER_MODE_LANG1_LANG2)
--				va.mode = VIDEO_SOUND_STEREO;
--			else if (t->audmode == V4L2_TUNER_MODE_LANG1)
--				va.mode = VIDEO_SOUND_LANG1;
--			else if (t->audmode == V4L2_TUNER_MODE_LANG2)
--				va.mode = VIDEO_SOUND_LANG2;
--			btv->audio_hook(btv,&va,1);
--		}
--		mutex_unlock(&btv->lock);
--		return 0;
--	}
-+	err = v4l2_prio_check(&btv->prio, &fh->prio);
-+	if (0 != err)
-+		return err;
- 
--	case VIDIOC_G_FREQUENCY:
--	{
--		struct v4l2_frequency *f = arg;
-+	f->type = V4L2_TUNER_ANALOG_TV;
-+	f->frequency = btv->freq;
- 
--		memset(f,0,sizeof(*f));
--		f->type = V4L2_TUNER_ANALOG_TV;
--		f->frequency = btv->freq;
--		return 0;
--	}
--	case VIDIOC_S_FREQUENCY:
--	{
--		struct v4l2_frequency *f = arg;
++	struct cx23885_dev *dev = (struct cx23885_dev *)data;
++	struct cx23885_dmaqueue *q = &dev->vbiq;
++	struct cx23885_buffer *buf;
++	unsigned long flags;
++
++	cx23885_sram_channel_dump(dev, &dev->sram_channels[SRAM_CH02]);
++
++	cx_clear(VID_A_DMA_CTL, 0x22);
++
++	spin_lock_irqsave(&dev->slock, flags);
++	while (!list_empty(&q->active)) {
++		buf = list_entry(q->active.next, struct cx23885_buffer,
++			vb.queue);
++		list_del(&buf->vb.queue);
++		buf->vb.state = VIDEOBUF_ERROR;
++		wake_up(&buf->vb.done);
++		printk("%s/0: [%p/%d] timeout - dma=0x%08lx\n", dev->name,
++		       buf, buf->vb.i, (unsigned long)buf->risc.dma);
++	}
++	cx23885_restart_vbi_queue(dev, q);
++	spin_unlock_irqrestore(&dev->slock, flags);
++}
++
++/* ------------------------------------------------------------------ */
++#define VBI_LINE_LENGTH 2048
++#define VBI_LINE_COUNT 17
++
++static int
++vbi_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size)
++{
++	*size = VBI_LINE_COUNT * VBI_LINE_LENGTH * 2;
++	if (0 == *count)
++		*count = vbibufs;
++	if (*count < 2)
++		*count = 2;
++	if (*count > 32)
++		*count = 32;
++	return 0;
++}
++
++static int
++vbi_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
++	    enum v4l2_field field)
++{
++	struct cx23885_fh *fh  = q->priv_data;
++	struct cx23885_dev *dev = fh->dev;
++	struct cx23885_buffer *buf = container_of(vb,
++		struct cx23885_buffer, vb);
++	struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb);
++	unsigned int size;
++	int rc;
++
++	size = VBI_LINE_COUNT * VBI_LINE_LENGTH * 2;
++	if (0 != buf->vb.baddr  &&  buf->vb.bsize < size)
++		return -EINVAL;
++
++	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
++		buf->vb.width  = VBI_LINE_LENGTH;
++		buf->vb.height = VBI_LINE_COUNT;
++		buf->vb.size   = size;
++		buf->vb.field  = V4L2_FIELD_SEQ_TB;
++
++		rc = videobuf_iolock(q, &buf->vb, NULL);
++		if (0 != rc)
++			goto fail;
++		cx23885_risc_buffer(dev->pci, &buf->risc,
++				 dma->sglist,
++				 0, buf->vb.width * buf->vb.height,
++				 buf->vb.width, 0,
++				 buf->vb.height);
++	}
++	buf->vb.state = VIDEOBUF_PREPARED;
 +	return 0;
++
++ fail:
++	cx23885_free_buffer(q, buf);
++	return rc;
++}
++
++static void
++vbi_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
++{
++	struct cx23885_buffer   *buf =
++		container_of(vb, struct cx23885_buffer, vb);
++	struct cx23885_buffer   *prev;
++	struct cx23885_fh       *fh   = vq->priv_data;
++	struct cx23885_dev      *dev  = fh->dev;
++	struct cx23885_dmaqueue *q    = &dev->vbiq;
++
++	/* add jump to stopper */
++	buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
++	buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma);
++	buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */
++
++	if (list_empty(&q->active)) {
++		list_add_tail(&buf->vb.queue, &q->active);
++		cx23885_start_vbi_dma(dev, q, buf);
++		buf->vb.state = VIDEOBUF_ACTIVE;
++		buf->count    = q->count++;
++		mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
++		dprintk(2, "[%p/%d] vbi_queue - first active\n",
++			buf, buf->vb.i);
++
++	} else {
++		prev = list_entry(q->active.prev, struct cx23885_buffer,
++			vb.queue);
++		list_add_tail(&buf->vb.queue, &q->active);
++		buf->vb.state = VIDEOBUF_ACTIVE;
++		buf->count    = q->count++;
++		prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
++		prev->risc.jmp[2] = cpu_to_le32(0); /* Bits 63-32 */
++		dprintk(2, "[%p/%d] buffer_queue - append to active\n",
++			buf, buf->vb.i);
++	}
++}
++
++static void vbi_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
++{
++	struct cx23885_buffer *buf =
++		container_of(vb, struct cx23885_buffer, vb);
++
++	cx23885_free_buffer(q, buf);
 +}
 +
-+static int bttv_s_frequency(struct file *file, void *priv,
-+					struct v4l2_frequency *f)
-+{
-+	struct bttv_fh *fh  = priv;
-+	struct bttv *btv = fh->btv;
-+	int err;
++struct videobuf_queue_ops cx23885_vbi_qops = {
++	.buf_setup    = vbi_setup,
++	.buf_prepare  = vbi_prepare,
++	.buf_queue    = vbi_queue,
++	.buf_release  = vbi_release,
++};
++
++/* ------------------------------------------------------------------ */
++/*
++ * Local variables:
++ * c-basic-offset: 8
++ * End:
++ */
+diff --git a/drivers/media/video/cx23885/cx23885-video.c b/drivers/media/video/cx23885/cx23885-video.c
+new file mode 100644
+index 0000000..d3c4d2c
+--- /dev/null
++++ b/drivers/media/video/cx23885/cx23885-video.c
+@@ -0,0 +1,1557 @@
++/*
++ *  Driver for the Conexant CX23885 PCIe bridge
++ *
++ *  Copyright (c) 2007 Steven Toth <stoth at hauppauge.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/init.h>
++#include <linux/list.h>
++#include <linux/module.h>
++#include <linux/moduleparam.h>
++#include <linux/kmod.h>
++#include <linux/kernel.h>
++#include <linux/slab.h>
++#include <linux/interrupt.h>
++#include <linux/delay.h>
++#include <linux/kthread.h>
++#include <asm/div64.h>
++
++#include "cx23885.h"
++#include <media/v4l2-common.h>
++
++#ifdef CONFIG_VIDEO_V4L1_COMPAT
++/* Include V4L1 specific functions. Should be removed soon */
++#include <linux/videodev.h>
++#endif
++
++MODULE_DESCRIPTION("v4l2 driver module for cx23885 based TV cards");
++MODULE_AUTHOR("Steven Toth <stoth at hauppauge.com>");
++MODULE_LICENSE("GPL");
++
++/* ------------------------------------------------------------------ */
++
++static unsigned int video_nr[] = {[0 ... (CX23885_MAXBOARDS - 1)] = UNSET };
++static unsigned int vbi_nr[]   = {[0 ... (CX23885_MAXBOARDS - 1)] = UNSET };
++static unsigned int radio_nr[] = {[0 ... (CX23885_MAXBOARDS - 1)] = UNSET };
++
++module_param_array(video_nr, int, NULL, 0444);
++module_param_array(vbi_nr,   int, NULL, 0444);
++module_param_array(radio_nr, int, NULL, 0444);
++
++MODULE_PARM_DESC(video_nr, "video device numbers");
++MODULE_PARM_DESC(vbi_nr, "vbi device numbers");
++MODULE_PARM_DESC(radio_nr, "radio device numbers");
++
++static unsigned int video_debug;
++module_param(video_debug, int, 0644);
++MODULE_PARM_DESC(video_debug, "enable debug messages [video]");
++
++static unsigned int irq_debug;
++module_param(irq_debug, int, 0644);
++MODULE_PARM_DESC(irq_debug, "enable debug messages [IRQ handler]");
 +
-+	err = v4l2_prio_check(&btv->prio, &fh->prio);
-+	if (0 != err)
-+		return err;
++static unsigned int vid_limit = 16;
++module_param(vid_limit, int, 0644);
++MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes");
 +
-+	if (unlikely(f->tuner != 0))
-+		return -EINVAL;
-+	if (unlikely(f->type != V4L2_TUNER_ANALOG_TV))
-+		return -EINVAL;
-+	mutex_lock(&btv->lock);
-+	btv->freq = f->frequency;
-+	bttv_call_i2c_clients(btv, VIDIOC_S_FREQUENCY, f);
-+	if (btv->has_matchbox && btv->radio_user)
-+		tea5757_set_freq(btv, btv->freq);
-+	mutex_unlock(&btv->lock);
-+	return 0;
-+}
++#define dprintk(level, fmt, arg...)\
++	do { if (video_debug >= level)\
++		printk(KERN_DEBUG "%s/0: " fmt, dev->name, ## arg);\
++	} while (0)
 +
-+static int bttv_log_status(struct file *file, void *f)
-+{
-+	struct bttv_fh *fh  = f;
-+	struct bttv *btv = fh->btv;
++/* ------------------------------------------------------------------- */
++/* static data                                                         */
 +
-+	printk(KERN_INFO "bttv%d: ========  START STATUS CARD #%d  ========\n",
-+			btv->c.nr, btv->c.nr);
-+	bttv_call_i2c_clients(btv, VIDIOC_LOG_STATUS, NULL);
-+	printk(KERN_INFO "bttv%d: ========  END STATUS CARD   #%d  ========\n",
-+			btv->c.nr, btv->c.nr);
-+	return 0;
-+}
- 
--		if (unlikely(f->tuner != 0))
--			return -EINVAL;
--		if (unlikely (f->type != V4L2_TUNER_ANALOG_TV))
--			return -EINVAL;
--		mutex_lock(&btv->lock);
--		btv->freq = f->frequency;
--		bttv_call_i2c_clients(btv,VIDIOC_S_FREQUENCY,f);
--		if (btv->has_matchbox && btv->radio_user)
--			tea5757_set_freq(btv,btv->freq);
--		mutex_unlock(&btv->lock);
--		return 0;
--	}
--	case VIDIOC_LOG_STATUS:
--	{
--		printk(KERN_INFO "bttv%d: =================  START STATUS CARD #%d  =================\n", btv->c.nr, btv->c.nr);
--		bttv_call_i2c_clients(btv, VIDIOC_LOG_STATUS, NULL);
--		printk(KERN_INFO "bttv%d: ==================  END STATUS CARD #%d  ==================\n", btv->c.nr, btv->c.nr);
--		return 0;
--	}
- #ifdef CONFIG_VIDEO_ADV_DEBUG
--	case VIDIOC_DBG_G_REGISTER:
--	case VIDIOC_DBG_S_REGISTER:
--	{
--		struct v4l2_register *reg = arg;
--		if (!capable(CAP_SYS_ADMIN))
--			return -EPERM;
--		if (!v4l2_chip_match_host(reg->match_type, reg->match_chip))
--			return -EINVAL;
--		/* bt848 has a 12-bit register space */
--		reg->reg &= 0xfff;
--		if (cmd == VIDIOC_DBG_G_REGISTER)
--			reg->val = btread(reg->reg);
--		else
--			btwrite(reg->val, reg->reg);
--		return 0;
--	}
--#endif
-+static int bttv_g_register(struct file *file, void *f,
-+					struct v4l2_register *reg)
-+{
-+	struct bttv_fh *fh = f;
-+	struct bttv *btv = fh->btv;
- 
--	default:
--		return -ENOIOCTLCMD;
-+	if (!capable(CAP_SYS_ADMIN))
-+		return -EPERM;
++#define FORMAT_FLAGS_PACKED       0x01
 +
-+	if (!v4l2_chip_match_host(reg->match_type, reg->match_chip))
-+		return -EINVAL;
++static struct cx23885_fmt formats[] = {
++	{
++		.name     = "8 bpp, gray",
++		.fourcc   = V4L2_PIX_FMT_GREY,
++		.depth    = 8,
++		.flags    = FORMAT_FLAGS_PACKED,
++	}, {
++		.name     = "15 bpp RGB, le",
++		.fourcc   = V4L2_PIX_FMT_RGB555,
++		.depth    = 16,
++		.flags    = FORMAT_FLAGS_PACKED,
++	}, {
++		.name     = "15 bpp RGB, be",
++		.fourcc   = V4L2_PIX_FMT_RGB555X,
++		.depth    = 16,
++		.flags    = FORMAT_FLAGS_PACKED,
++	}, {
++		.name     = "16 bpp RGB, le",
++		.fourcc   = V4L2_PIX_FMT_RGB565,
++		.depth    = 16,
++		.flags    = FORMAT_FLAGS_PACKED,
++	}, {
++		.name     = "16 bpp RGB, be",
++		.fourcc   = V4L2_PIX_FMT_RGB565X,
++		.depth    = 16,
++		.flags    = FORMAT_FLAGS_PACKED,
++	}, {
++		.name     = "24 bpp RGB, le",
++		.fourcc   = V4L2_PIX_FMT_BGR24,
++		.depth    = 24,
++		.flags    = FORMAT_FLAGS_PACKED,
++	}, {
++		.name     = "32 bpp RGB, le",
++		.fourcc   = V4L2_PIX_FMT_BGR32,
++		.depth    = 32,
++		.flags    = FORMAT_FLAGS_PACKED,
++	}, {
++		.name     = "32 bpp RGB, be",
++		.fourcc   = V4L2_PIX_FMT_RGB32,
++		.depth    = 32,
++		.flags    = FORMAT_FLAGS_PACKED,
++	}, {
++		.name     = "4:2:2, packed, YUYV",
++		.fourcc   = V4L2_PIX_FMT_YUYV,
++		.depth    = 16,
++		.flags    = FORMAT_FLAGS_PACKED,
++	}, {
++		.name     = "4:2:2, packed, UYVY",
++		.fourcc   = V4L2_PIX_FMT_UYVY,
++		.depth    = 16,
++		.flags    = FORMAT_FLAGS_PACKED,
++	},
++};
 +
-+	/* bt848 has a 12-bit register space */
-+	reg->reg &= 0xfff;
-+	reg->val = btread(reg->reg);
++static struct cx23885_fmt *format_by_fourcc(unsigned int fourcc)
++{
++	unsigned int i;
 +
-+	return 0;
++	for (i = 0; i < ARRAY_SIZE(formats); i++)
++		if (formats[i].fourcc == fourcc)
++			return formats+i;
++
++	printk(KERN_ERR "%s(0x%08x) NOT FOUND\n", __FUNCTION__, fourcc);
++	return NULL;
 +}
 +
-+static int bttv_s_register(struct file *file, void *f,
-+					struct v4l2_register *reg)
-+{
-+	struct bttv_fh *fh = f;
-+	struct bttv *btv = fh->btv;
++/* ------------------------------------------------------------------- */
 +
-+	if (!capable(CAP_SYS_ADMIN))
-+		return -EPERM;
++static const struct v4l2_queryctrl no_ctl = {
++	.name  = "42",
++	.flags = V4L2_CTRL_FLAG_DISABLED,
++};
 +
-+	if (!v4l2_chip_match_host(reg->match_type, reg->match_chip))
-+		return -EINVAL;
++static struct cx23885_ctrl cx23885_ctls[] = {
++	/* --- video --- */
++	{
++		.v = {
++			.id            = V4L2_CID_BRIGHTNESS,
++			.name          = "Brightness",
++			.minimum       = 0x00,
++			.maximum       = 0xff,
++			.step          = 1,
++			.default_value = 0x7f,
++			.type          = V4L2_CTRL_TYPE_INTEGER,
++		},
++		.off                   = 128,
++		.reg                   = LUMA_CTRL,
++		.mask                  = 0x00ff,
++		.shift                 = 0,
++	}, {
++		.v = {
++			.id            = V4L2_CID_CONTRAST,
++			.name          = "Contrast",
++			.minimum       = 0,
++			.maximum       = 0xff,
++			.step          = 1,
++			.default_value = 0x3f,
++			.type          = V4L2_CTRL_TYPE_INTEGER,
++		},
++		.off                   = 0,
++		.reg                   = LUMA_CTRL,
++		.mask                  = 0xff00,
++		.shift                 = 8,
++	}, {
++		.v = {
++			.id            = V4L2_CID_HUE,
++			.name          = "Hue",
++			.minimum       = 0,
++			.maximum       = 0xff,
++			.step          = 1,
++			.default_value = 0x7f,
++			.type          = V4L2_CTRL_TYPE_INTEGER,
++		},
++		.off                   = 128,
++		.reg                   = CHROMA_CTRL,
++		.mask                  = 0xff0000,
++		.shift                 = 16,
++	}, {
++		/* strictly, this only describes only U saturation.
++		 * V saturation is handled specially through code.
++		 */
++		.v = {
++			.id            = V4L2_CID_SATURATION,
++			.name          = "Saturation",
++			.minimum       = 0,
++			.maximum       = 0xff,
++			.step          = 1,
++			.default_value = 0x7f,
++			.type          = V4L2_CTRL_TYPE_INTEGER,
++		},
++		.off                   = 0,
++		.reg                   = CHROMA_CTRL,
++		.mask                  = 0x00ff,
++		.shift                 = 0,
++	}, {
++	/* --- audio --- */
++		.v = {
++			.id            = V4L2_CID_AUDIO_MUTE,
++			.name          = "Mute",
++			.minimum       = 0,
++			.maximum       = 1,
++			.default_value = 1,
++			.type          = V4L2_CTRL_TYPE_BOOLEAN,
++		},
++		.reg                   = PATH1_CTL1,
++		.mask                  = (0x1f << 24),
++		.shift                 = 24,
++	}, {
++		.v = {
++			.id            = V4L2_CID_AUDIO_VOLUME,
++			.name          = "Volume",
++			.minimum       = 0,
++			.maximum       = 0x3f,
++			.step          = 1,
++			.default_value = 0x3f,
++			.type          = V4L2_CTRL_TYPE_INTEGER,
++		},
++		.reg                   = PATH1_VOL_CTL,
++		.mask                  = 0xff,
++		.shift                 = 0,
++	}
++};
++static const int CX23885_CTLS = ARRAY_SIZE(cx23885_ctls);
 +
-+	/* bt848 has a 12-bit register space */
-+	reg->reg &= 0xfff;
-+	btwrite(reg->val, reg->reg);
- 
--	}
- 	return 0;
- }
-+#endif
- 
- /* Given cropping boundaries b and the scaled width and height of a
-    single field or frame, which must not exceed hardware limits, this
-@@ -2659,983 +2447,681 @@ pix_format_set_size     (struct v4l2_pix_format *       f,
- 	}
- }
- 
--static int bttv_g_fmt(struct bttv_fh *fh, struct v4l2_format *f)
-+static int bttv_g_fmt_cap(struct file *file, void *priv,
-+					struct v4l2_format *f)
- {
--	switch (f->type) {
--	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
--		memset(&f->fmt.pix,0,sizeof(struct v4l2_pix_format));
--		pix_format_set_size (&f->fmt.pix, fh->fmt,
--				     fh->width, fh->height);
--		f->fmt.pix.field        = fh->cap.field;
--		f->fmt.pix.pixelformat  = fh->fmt->fourcc;
--		return 0;
--	case V4L2_BUF_TYPE_VIDEO_OVERLAY:
--		memset(&f->fmt.win,0,sizeof(struct v4l2_window));
--		f->fmt.win.w     = fh->ov.w;
--		f->fmt.win.field = fh->ov.field;
--		return 0;
--	case V4L2_BUF_TYPE_VBI_CAPTURE:
--		bttv_vbi_get_fmt(fh, &f->fmt.vbi);
--		return 0;
--	default:
--		return -EINVAL;
--	}
-+	struct bttv_fh *fh  = priv;
++const u32 cx23885_user_ctrls[] = {
++	V4L2_CID_USER_CLASS,
++	V4L2_CID_BRIGHTNESS,
++	V4L2_CID_CONTRAST,
++	V4L2_CID_SATURATION,
++	V4L2_CID_HUE,
++	V4L2_CID_AUDIO_VOLUME,
++	V4L2_CID_AUDIO_MUTE,
++	0
++};
++EXPORT_SYMBOL(cx23885_user_ctrls);
 +
-+	pix_format_set_size(&f->fmt.pix, fh->fmt,
-+				fh->width, fh->height);
-+	f->fmt.pix.field        = fh->cap.field;
-+	f->fmt.pix.pixelformat  = fh->fmt->fourcc;
++static const u32 *ctrl_classes[] = {
++	cx23885_user_ctrls,
++	NULL
++};
 +
-+	return 0;
- }
- 
--static int bttv_try_fmt(struct bttv_fh *fh, struct bttv *btv,
--			struct v4l2_format *f, int adjust_crop)
-+static int bttv_g_fmt_overlay(struct file *file, void *priv,
-+					struct v4l2_format *f)
- {
--	switch (f->type) {
--	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
--	{
--		const struct bttv_format *fmt;
--		enum v4l2_field field;
--		__s32 width, height;
--		int rc;
-+	struct bttv_fh *fh  = priv;
- 
--		fmt = format_by_fourcc(f->fmt.pix.pixelformat);
--		if (NULL == fmt)
--			return -EINVAL;
-+	f->fmt.win.w     = fh->ov.w;
-+	f->fmt.win.field = fh->ov.field;
- 
--		field = f->fmt.pix.field;
--		if (V4L2_FIELD_ANY == field) {
--			__s32 height2;
-+	return 0;
-+}
- 
--			height2 = btv->crop[!!fh->do_crop].rect.height >> 1;
--			field = (f->fmt.pix.height > height2)
--				? V4L2_FIELD_INTERLACED
--				: V4L2_FIELD_BOTTOM;
--		}
--		if (V4L2_FIELD_SEQ_BT == field)
--			field = V4L2_FIELD_SEQ_TB;
--		switch (field) {
--		case V4L2_FIELD_TOP:
--		case V4L2_FIELD_BOTTOM:
--		case V4L2_FIELD_ALTERNATE:
--		case V4L2_FIELD_INTERLACED:
--			break;
--		case V4L2_FIELD_SEQ_TB:
--			if (fmt->flags & FORMAT_FLAGS_PLANAR)
--				return -EINVAL;
--			break;
--		default:
--			return -EINVAL;
--		}
-+static int bttv_try_fmt_cap(struct file *file, void *priv,
-+						struct v4l2_format *f)
++void cx23885_video_wakeup(struct cx23885_dev *dev,
++		 struct cx23885_dmaqueue *q, u32 count)
 +{
-+	const struct bttv_format *fmt;
-+	struct bttv_fh *fh = priv;
-+	struct bttv *btv = fh->btv;
-+	enum v4l2_field field;
-+	__s32 width, height;
-+	int rc;
- 
--		width = f->fmt.pix.width;
--		height = f->fmt.pix.height;
-+	fmt = format_by_fourcc(f->fmt.pix.pixelformat);
-+	if (NULL == fmt)
-+		return -EINVAL;
- 
--		rc = limit_scaled_size(fh, &width, &height, field,
--				       /* width_mask: 4 pixels */ ~3,
--				       /* width_bias: nearest */ 2,
--				       /* adjust_size */ 1,
--				       adjust_crop);
--		if (0 != rc)
--			return rc;
-+	field = f->fmt.pix.field;
- 
--		/* update data for the application */
--		f->fmt.pix.field = field;
--		pix_format_set_size(&f->fmt.pix, fmt, width, height);
-+	if (V4L2_FIELD_ANY == field) {
-+		__s32 height2;
- 
--		return 0;
-+		height2 = btv->crop[!!fh->do_crop].rect.height >> 1;
-+		field = (f->fmt.pix.height > height2)
-+			? V4L2_FIELD_INTERLACED
-+			: V4L2_FIELD_BOTTOM;
- 	}
--	case V4L2_BUF_TYPE_VIDEO_OVERLAY:
--		return verify_window(fh, &f->fmt.win,
--				     /* adjust_size */ 1,
--				     /* adjust_crop */ 0);
--	case V4L2_BUF_TYPE_VBI_CAPTURE:
--		return bttv_vbi_try_fmt(fh, &f->fmt.vbi);
++	struct cx23885_buffer *buf;
++	int bc;
 +
-+	if (V4L2_FIELD_SEQ_BT == field)
-+		field = V4L2_FIELD_SEQ_TB;
++	for (bc = 0;; bc++) {
++		if (list_empty(&q->active))
++			break;
++		buf = list_entry(q->active.next,
++				 struct cx23885_buffer, vb.queue);
 +
-+	switch (field) {
-+	case V4L2_FIELD_TOP:
-+	case V4L2_FIELD_BOTTOM:
-+	case V4L2_FIELD_ALTERNATE:
-+	case V4L2_FIELD_INTERLACED:
-+		break;
-+	case V4L2_FIELD_SEQ_TB:
-+		if (fmt->flags & FORMAT_FLAGS_PLANAR)
-+			return -EINVAL;
-+		break;
- 	default:
- 		return -EINVAL;
- 	}
++		/* count comes from the hw and is is 16bit wide --
++		 * this trick handles wrap-arounds correctly for
++		 * up to 32767 buffers in flight... */
++		if ((s16) (count - buf->count) < 0)
++			break;
 +
-+	width = f->fmt.pix.width;
-+	height = f->fmt.pix.height;
++		do_gettimeofday(&buf->vb.ts);
++		dprintk(2, "[%p/%d] wakeup reg=%d buf=%d\n", buf, buf->vb.i,
++			count, buf->count);
++		buf->vb.state = VIDEOBUF_DONE;
++		list_del(&buf->vb.queue);
++		wake_up(&buf->vb.done);
++	}
++	if (list_empty(&q->active)) {
++		del_timer(&q->timeout);
++	} else {
++		mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
++	}
++	if (bc != 1)
++		printk(KERN_ERR "%s: %d buffers handled (should be 1)\n",
++			__FUNCTION__, bc);
++}
 +
-+	rc = limit_scaled_size(fh, &width, &height, field,
-+			       /* width_mask: 4 pixels */ ~3,
-+			       /* width_bias: nearest */ 2,
-+			       /* adjust_size */ 1,
-+			       /* adjust_crop */ 0);
-+	if (0 != rc)
-+		return rc;
++int cx23885_set_tvnorm(struct cx23885_dev *dev, v4l2_std_id norm)
++{
++	dprintk(1, "%s(norm = 0x%08x) name: [%s]\n",
++		__FUNCTION__,
++		(unsigned int)norm,
++		v4l2_norm_to_name(norm));
 +
-+	/* update data for the application */
-+	f->fmt.pix.field = field;
-+	pix_format_set_size(&f->fmt.pix, fmt, width, height);
++	dev->tvnorm = norm;
 +
-+	return 0;
- }
- 
--static int bttv_s_fmt(struct bttv_fh *fh, struct bttv *btv,
--		      struct v4l2_format *f)
-+static int bttv_try_fmt_overlay(struct file *file, void *priv,
-+						struct v4l2_format *f)
-+{
-+	struct bttv_fh *fh = priv;
++	/* Tell the analog tuner/demods */
++	cx23885_call_i2c_clients(&dev->i2c_bus[1], VIDIOC_S_STD, &norm);
 +
-+	return verify_window(fh, &f->fmt.win,
-+			/* adjust_size */ 1,
-+			/* adjust_crop */ 0);
-+}
++	/* Tell the internal A/V decoder */
++	cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_S_STD, &norm);
 +
-+static int bttv_s_fmt_cap(struct file *file, void *priv,
-+				struct v4l2_format *f)
- {
- 	int retval;
-+	const struct bttv_format *fmt;
-+	struct bttv_fh *fh = priv;
-+	struct bttv *btv = fh->btv;
-+	__s32 width, height;
-+	enum v4l2_field field;
- 
--	switch (f->type) {
--	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
--	{
--		const struct bttv_format *fmt;
-+	retval = bttv_switch_type(fh, f->type);
-+	if (0 != retval)
-+		return retval;
- 
--		retval = bttv_switch_type(fh,f->type);
--		if (0 != retval)
--			return retval;
--		retval = bttv_try_fmt(fh,btv,f, /* adjust_crop */ 1);
--		if (0 != retval)
--			return retval;
--		fmt = format_by_fourcc(f->fmt.pix.pixelformat);
-+	retval = bttv_try_fmt_cap(file, priv, f);
-+	if (0 != retval)
-+		return retval;
- 
--		/* update our state informations */
--		mutex_lock(&fh->cap.lock);
--		fh->fmt              = fmt;
--		fh->cap.field        = f->fmt.pix.field;
--		fh->cap.last         = V4L2_FIELD_NONE;
--		fh->width            = f->fmt.pix.width;
--		fh->height           = f->fmt.pix.height;
--		btv->init.fmt        = fmt;
--		btv->init.width      = f->fmt.pix.width;
--		btv->init.height     = f->fmt.pix.height;
--		mutex_unlock(&fh->cap.lock);
-+	width = f->fmt.pix.width;
-+	height = f->fmt.pix.height;
-+	field = f->fmt.pix.field;
- 
--		return 0;
--	}
--	case V4L2_BUF_TYPE_VIDEO_OVERLAY:
--		if (no_overlay > 0) {
--			printk ("V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
--			return -EINVAL;
--		}
--		return setup_window(fh, btv, &f->fmt.win, 1);
--	case V4L2_BUF_TYPE_VBI_CAPTURE:
--		retval = bttv_switch_type(fh,f->type);
--		if (0 != retval)
--			return retval;
--		return bttv_vbi_set_fmt(fh, &f->fmt.vbi);
--	default:
--		return -EINVAL;
--	}
--}
-+	retval = limit_scaled_size(fh, &width, &height, f->fmt.pix.field,
-+			       /* width_mask: 4 pixels */ ~3,
-+			       /* width_bias: nearest */ 2,
-+			       /* adjust_size */ 1,
-+			       /* adjust_crop */ 1);
-+	if (0 != retval)
-+		return retval;
- 
--static int bttv_do_ioctl(struct inode *inode, struct file *file,
--			 unsigned int cmd, void *arg)
--{
--	struct bttv_fh *fh  = file->private_data;
--	struct bttv    *btv = fh->btv;
--	unsigned long flags;
--	int retval = 0;
-+	f->fmt.pix.field = field;
- 
--	if (bttv_debug > 1)
--		v4l_print_ioctl(btv->c.name, cmd);
--
--	if (btv->errors)
--		bttv_reinit_bt848(btv);
--
--	switch (cmd) {
--	case VIDIOCSFREQ:
--	case VIDIOCSTUNER:
--	case VIDIOCSCHAN:
--	case VIDIOC_S_CTRL:
--	case VIDIOC_S_STD:
--	case VIDIOC_S_INPUT:
--	case VIDIOC_S_TUNER:
--	case VIDIOC_S_FREQUENCY:
--		retval = v4l2_prio_check(&btv->prio,&fh->prio);
--		if (0 != retval)
--			return retval;
--	};
-+	fmt = format_by_fourcc(f->fmt.pix.pixelformat);
- 
--	switch (cmd) {
-+	/* update our state informations */
-+	mutex_lock(&fh->cap.lock);
-+	fh->fmt              = fmt;
-+	fh->cap.field        = f->fmt.pix.field;
-+	fh->cap.last         = V4L2_FIELD_NONE;
-+	fh->width            = f->fmt.pix.width;
-+	fh->height           = f->fmt.pix.height;
-+	btv->init.fmt        = fmt;
-+	btv->init.width      = f->fmt.pix.width;
-+	btv->init.height     = f->fmt.pix.height;
-+	mutex_unlock(&fh->cap.lock);
- 
--	/* ***  v4l1  *** ************************************************ */
--	case VIDIOCGCAP:
--	{
--		struct video_capability *cap = arg;
 +	return 0;
 +}
- 
--		memset(cap,0,sizeof(*cap));
--		strcpy(cap->name,btv->video_dev->name);
--		if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) {
--			/* vbi */
--			cap->type = VID_TYPE_TUNER|VID_TYPE_TELETEXT;
--		} else {
--			/* others */
--			cap->type = VID_TYPE_CAPTURE|
--				VID_TYPE_TUNER|
--				VID_TYPE_CLIPPING|
--				VID_TYPE_SCALES;
--			if (no_overlay <= 0)
--				cap->type |= VID_TYPE_OVERLAY;
--
--			cap->maxwidth  = bttv_tvnorms[btv->tvnorm].swidth;
--			cap->maxheight = bttv_tvnorms[btv->tvnorm].sheight;
--			cap->minwidth  = 48;
--			cap->minheight = 32;
--		}
--		cap->channels  = bttv_tvcards[btv->c.type].video_inputs;
--		cap->audios    = bttv_tvcards[btv->c.type].audio_inputs;
--		return 0;
--	}
-+static int bttv_s_fmt_overlay(struct file *file, void *priv,
-+				struct v4l2_format *f)
++
++struct video_device *cx23885_vdev_init(struct cx23885_dev *dev,
++				    struct pci_dev *pci,
++				    struct video_device *template,
++				    char *type)
 +{
-+	struct bttv_fh *fh = priv;
-+	struct bttv *btv = fh->btv;
- 
--	case VIDIOCGPICT:
--	{
--		struct video_picture *pic = arg;
--
--		memset(pic,0,sizeof(*pic));
--		pic->brightness = btv->bright;
--		pic->contrast   = btv->contrast;
--		pic->hue        = btv->hue;
--		pic->colour     = btv->saturation;
--		if (fh->fmt) {
--			pic->depth   = fh->fmt->depth;
--			pic->palette = fh->fmt->palette;
--		}
--		return 0;
-+	if (no_overlay > 0) {
-+		printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
-+		return -EINVAL;
- 	}
--	case VIDIOCSPICT:
--	{
--		struct video_picture *pic = arg;
--		const struct bttv_format *fmt;
- 
--		fmt = format_by_palette(pic->palette);
--		if (NULL == fmt)
--			return -EINVAL;
--		mutex_lock(&fh->cap.lock);
--		if (fmt->flags & FORMAT_FLAGS_RAW) {
--			/* VIDIOCMCAPTURE uses gbufsize, not RAW_BPL *
--			   RAW_LINES * 2. F1 is stored at offset 0, F2
--			   at buffer size / 2. */
--			fh->width = RAW_BPL;
--			fh->height = gbufsize / RAW_BPL;
--			btv->init.width  = RAW_BPL;
--			btv->init.height = gbufsize / RAW_BPL;
--		}
--		fh->ovfmt   = fmt;
--		fh->fmt     = fmt;
--		btv->init.ovfmt   = fmt;
--		btv->init.fmt     = fmt;
--		if (bigendian) {
--			/* dirty hack time:  swap bytes for overlay if the
--			   display adaptor is big endian (insmod option) */
--			if (fmt->palette == VIDEO_PALETTE_RGB555 ||
--			    fmt->palette == VIDEO_PALETTE_RGB565 ||
--			    fmt->palette == VIDEO_PALETTE_RGB32) {
--				fh->ovfmt = fmt+1;
--			}
--		}
--		bt848_bright(btv,pic->brightness);
--		bt848_contrast(btv,pic->contrast);
--		bt848_hue(btv,pic->hue);
--		bt848_sat(btv,pic->colour);
-+	return setup_window(fh, btv, &f->fmt.win, 1);
++	struct video_device *vfd;
++	dprintk(1, "%s()\n", __FUNCTION__);
++
++	vfd = video_device_alloc();
++	if (NULL == vfd)
++		return NULL;
++	*vfd = *template;
++	vfd->minor   = -1;
++	vfd->dev     = &pci->dev;
++	vfd->release = video_device_release;
++	snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)",
++		 dev->name, type, cx23885_boards[dev->board].name);
++	return vfd;
 +}
 +
-+#ifdef CONFIG_VIDEO_V4L1_COMPAT
-+static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf)
++int cx23885_ctrl_query(struct v4l2_queryctrl *qctrl)
 +{
-+	int retval;
-+	unsigned int i;
-+	struct bttv_fh *fh = priv;
++	int i;
 +
-+	mutex_lock(&fh->cap.lock);
-+	retval = videobuf_mmap_setup(&fh->cap, gbuffers, gbufsize,
-+				     V4L2_MEMORY_MMAP);
-+	if (retval < 0) {
- 		mutex_unlock(&fh->cap.lock);
--		return 0;
-+		return retval;
- 	}
- 
--	case VIDIOCGWIN:
--	{
--		struct video_window *win = arg;
-+	gbuffers = retval;
-+	memset(mbuf, 0, sizeof(*mbuf));
-+	mbuf->frames = gbuffers;
-+	mbuf->size   = gbuffers * gbufsize;
- 
--		memset(win,0,sizeof(*win));
--		win->x      = fh->ov.w.left;
--		win->y      = fh->ov.w.top;
--		win->width  = fh->ov.w.width;
--		win->height = fh->ov.w.height;
--		return 0;
--	}
--	case VIDIOCSWIN:
--	{
--		struct video_window *win = arg;
--		struct v4l2_window w2;
-+	for (i = 0; i < gbuffers; i++)
-+		mbuf->offsets[i] = i * gbufsize;
- 
--		if (no_overlay > 0) {
--			printk ("VIDIOCSWIN: no_overlay\n");
--			return -EINVAL;
--		}
-+	mutex_unlock(&fh->cap.lock);
++	if (qctrl->id < V4L2_CID_BASE ||
++	    qctrl->id >= V4L2_CID_LASTP1)
++		return -EINVAL;
++	for (i = 0; i < CX23885_CTLS; i++)
++		if (cx23885_ctls[i].v.id == qctrl->id)
++			break;
++	if (i == CX23885_CTLS) {
++		*qctrl = no_ctl;
++		return 0;
++	}
++	*qctrl = cx23885_ctls[i].v;
 +	return 0;
 +}
-+#endif
- 
--		w2.field = V4L2_FIELD_ANY;
--		w2.w.left    = win->x;
--		w2.w.top     = win->y;
--		w2.w.width   = win->width;
--		w2.w.height  = win->height;
--		w2.clipcount = win->clipcount;
--		w2.clips     = (struct v4l2_clip __user *)win->clips;
--		retval = setup_window(fh, btv, &w2, 0);
--		if (0 == retval) {
--			/* on v4l1 this ioctl affects the read() size too */
--			fh->width  = fh->ov.w.width;
--			fh->height = fh->ov.w.height;
--			btv->init.width  = fh->ov.w.width;
--			btv->init.height = fh->ov.w.height;
--		}
--		return retval;
--	}
-+static int bttv_querycap(struct file *file, void  *priv,
-+				struct v4l2_capability *cap)
++EXPORT_SYMBOL(cx23885_ctrl_query);
++
++/* ------------------------------------------------------------------- */
++/* resource management                                                 */
++
++static int res_get(struct cx23885_dev *dev, struct cx23885_fh *fh,
++	unsigned int bit)
 +{
-+	struct bttv_fh *fh = priv;
-+	struct bttv *btv = fh->btv;
- 
--	case VIDIOCGFBUF:
--	{
--		struct video_buffer *fbuf = arg;
--
--		fbuf->base          = btv->fbuf.base;
--		fbuf->width         = btv->fbuf.fmt.width;
--		fbuf->height        = btv->fbuf.fmt.height;
--		fbuf->bytesperline  = btv->fbuf.fmt.bytesperline;
--		if (fh->ovfmt)
--			fbuf->depth = fh->ovfmt->depth;
--		else {
--			if (fbuf->width)
--				fbuf->depth   = ((fbuf->bytesperline<<3)
--						  + (fbuf->width-1) )
--						  /fbuf->width;
--			else
--				fbuf->depth = 0;
--		}
--		return 0;
--	}
--	case VIDIOCSFBUF:
--	{
--		struct video_buffer *fbuf = arg;
--		const struct bttv_format *fmt;
--		unsigned long end;
--
--		if(!capable(CAP_SYS_ADMIN) &&
--		   !capable(CAP_SYS_RAWIO))
--			return -EPERM;
--		end = (unsigned long)fbuf->base +
--			fbuf->height * fbuf->bytesperline;
--		mutex_lock(&fh->cap.lock);
--		retval = -EINVAL;
-+	if (0 == v4l2)
-+		return -EINVAL;
- 
--		switch (fbuf->depth) {
--		case 8:
--			fmt = format_by_palette(VIDEO_PALETTE_HI240);
--			break;
--		case 16:
--			fmt = format_by_palette(VIDEO_PALETTE_RGB565);
--			break;
--		case 24:
--			fmt = format_by_palette(VIDEO_PALETTE_RGB24);
--			break;
--		case 32:
--			fmt = format_by_palette(VIDEO_PALETTE_RGB32);
--			break;
--		case 15:
--			fbuf->depth = 16;
--			fmt = format_by_palette(VIDEO_PALETTE_RGB555);
--			break;
--		default:
--			fmt = NULL;
--			break;
--		}
--		if (NULL == fmt)
--			goto fh_unlock_and_return;
--
--		fh->ovfmt = fmt;
--		fh->fmt   = fmt;
--		btv->init.ovfmt = fmt;
--		btv->init.fmt   = fmt;
--		btv->fbuf.base             = fbuf->base;
--		btv->fbuf.fmt.width        = fbuf->width;
--		btv->fbuf.fmt.height       = fbuf->height;
--		if (fbuf->bytesperline)
--			btv->fbuf.fmt.bytesperline = fbuf->bytesperline;
--		else
--			btv->fbuf.fmt.bytesperline = btv->fbuf.fmt.width*fbuf->depth/8;
--		mutex_unlock(&fh->cap.lock);
--		return 0;
--	}
-+	strlcpy(cap->driver, "bttv", sizeof(cap->driver));
-+	strlcpy(cap->card, btv->video_dev->name, sizeof(cap->card));
-+	snprintf(cap->bus_info, sizeof(cap->bus_info),
-+		 "PCI:%s", pci_name(btv->c.pci));
-+	cap->version = BTTV_VERSION_CODE;
-+	cap->capabilities =
-+		V4L2_CAP_VIDEO_CAPTURE |
-+		V4L2_CAP_VBI_CAPTURE |
-+		V4L2_CAP_READWRITE |
-+		V4L2_CAP_STREAMING;
-+	if (no_overlay <= 0)
-+		cap->capabilities |= V4L2_CAP_VIDEO_OVERLAY;
++	dprintk(1, "%s()\n", __FUNCTION__);
++	if (fh->resources & bit)
++		/* have it already allocated */
++		return 1;
 +
-+	if (bttv_tvcards[btv->c.type].tuner != UNSET &&
-+	    bttv_tvcards[btv->c.type].tuner != TUNER_ABSENT)
-+		cap->capabilities |= V4L2_CAP_TUNER;
-+	return 0;
++	/* is it free? */
++	mutex_lock(&dev->lock);
++	if (dev->resources & bit) {
++		/* no, someone else uses it */
++		mutex_unlock(&dev->lock);
++		return 0;
++	}
++	/* it's free, grab it */
++	fh->resources  |= bit;
++	dev->resources |= bit;
++	dprintk(1, "res: get %d\n", bit);
++	mutex_unlock(&dev->lock);
++	return 1;
 +}
- 
--	case VIDIOCCAPTURE:
--	case VIDIOC_OVERLAY:
--	{
--		struct bttv_buffer *new;
--		int *on = arg;
-+static int bttv_enum_fmt_vbi(struct file *file, void  *priv,
-+				struct v4l2_fmtdesc *f)
++
++static int res_check(struct cx23885_fh *fh, unsigned int bit)
 +{
-+	if (0 != f->index)
-+		return -EINVAL;
- 
--		if (*on) {
--			/* verify args */
--			if (NULL == btv->fbuf.base)
--				return -EINVAL;
--			if (!fh->ov.setup_ok) {
--				dprintk("bttv%d: overlay: !setup_ok\n",btv->c.nr);
--				return -EINVAL;
--			}
--		}
-+	f->pixelformat = V4L2_PIX_FMT_GREY;
-+	strcpy(f->description, "vbi data");
- 
--		if (!check_alloc_btres(btv,fh,RESOURCE_OVERLAY))
--			return -EBUSY;
-+	return 0;
++	return (fh->resources & bit);
 +}
- 
--		mutex_lock(&fh->cap.lock);
--		if (*on) {
--			fh->ov.tvnorm = btv->tvnorm;
--			new = videobuf_pci_alloc(sizeof(*new));
--			new->crop = btv->crop[!!fh->do_crop].rect;
--			bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new);
--		} else {
--			new = NULL;
--		}
-+static int bttv_enum_fmt_cap_ovr(struct v4l2_fmtdesc *f)
++
++static int res_locked(struct cx23885_dev *dev, unsigned int bit)
 +{
-+	int index = -1, i;
- 
--		/* switch over */
--		retval = bttv_switch_overlay(btv,fh,new);
--		mutex_unlock(&fh->cap.lock);
--		return retval;
-+	for (i = 0; i < FORMATS; i++) {
-+		if (formats[i].fourcc != -1)
-+			index++;
-+		if ((unsigned int)index == f->index)
-+			break;
- 	}
-+	if (FORMATS == i)
-+		return -EINVAL;
- 
--	case VIDIOCGMBUF:
--	{
--		struct video_mbuf *mbuf = arg;
--		unsigned int i;
-+	f->pixelformat = formats[i].fourcc;
-+	strlcpy(f->description, formats[i].name, sizeof(f->description));
- 
--		retval = videobuf_mmap_setup(&fh->cap,gbuffers,gbufsize,
--					     V4L2_MEMORY_MMAP);
--		if (retval < 0)
--			return retval;
-+	return i;
++	return (dev->resources & bit);
 +}
- 
--		gbuffers = retval;
--		memset(mbuf,0,sizeof(*mbuf));
--		mbuf->frames = gbuffers;
--		mbuf->size   = gbuffers * gbufsize;
--		for (i = 0; i < gbuffers; i++)
--			mbuf->offsets[i] = i * gbufsize;
--		return 0;
--	}
--	case VIDIOCMCAPTURE:
--	{
--		struct video_mmap *vm = arg;
--		struct bttv_buffer *buf;
--		enum v4l2_field field;
--		__s32 height2;
--		int res;
-+static int bttv_enum_fmt_cap(struct file *file, void  *priv,
-+				struct v4l2_fmtdesc *f)
++
++static void res_free(struct cx23885_dev *dev, struct cx23885_fh *fh,
++	unsigned int bits)
 +{
-+	int rc = bttv_enum_fmt_cap_ovr(f);
- 
--		if (vm->frame >= VIDEO_MAX_FRAME)
--			return -EINVAL;
-+	if (rc < 0)
-+		return rc;
- 
--		res = bttv_resource(fh);
--		if (!check_alloc_btres(btv, fh, res))
--			return -EBUSY;
++	BUG_ON((fh->resources & bits) != bits);
++	dprintk(1, "%s()\n", __FUNCTION__);
++
++	mutex_lock(&dev->lock);
++	fh->resources  &= ~bits;
++	dev->resources &= ~bits;
++	dprintk(1, "res: put %d\n", bits);
++	mutex_unlock(&dev->lock);
++}
++
++int cx23885_video_mux(struct cx23885_dev *dev, unsigned int input)
++{
++	struct v4l2_routing route;
++	memset(&route, 0, sizeof(route));
++
++	dprintk(1, "%s() video_mux: %d [vmux=%d, gpio=0x%x,0x%x,0x%x,0x%x]\n",
++		__FUNCTION__,
++		input, INPUT(input)->vmux,
++		INPUT(input)->gpio0, INPUT(input)->gpio1,
++		INPUT(input)->gpio2, INPUT(input)->gpio3);
++	dev->input = input;
++
++	route.input = INPUT(input)->vmux;
++
++	/* Tell the internal A/V decoder */
++	cx23885_call_i2c_clients(&dev->i2c_bus[2],
++		VIDIOC_INT_S_VIDEO_ROUTING, &route);
++
 +	return 0;
 +}
- 
--		mutex_lock(&fh->cap.lock);
--		retval = -EINVAL;
--		buf = (struct bttv_buffer *)fh->cap.bufs[vm->frame];
--		if (NULL == buf)
--			goto fh_unlock_and_return;
--		if (0 == buf->vb.baddr)
--			goto fh_unlock_and_return;
--		if (buf->vb.state == STATE_QUEUED ||
--		    buf->vb.state == STATE_ACTIVE)
--			goto fh_unlock_and_return;
-+static int bttv_enum_fmt_overlay(struct file *file, void  *priv,
-+					struct v4l2_fmtdesc *f)
++EXPORT_SYMBOL(cx23885_video_mux);
++
++/* ------------------------------------------------------------------ */
++int cx23885_set_scale(struct cx23885_dev *dev, unsigned int width,
++	unsigned int height, enum v4l2_field field)
 +{
-+	int rc;
- 
--		height2 = btv->crop[!!fh->do_crop].rect.height >> 1;
--		field = (vm->height > height2)
--			? V4L2_FIELD_INTERLACED
--			: V4L2_FIELD_BOTTOM;
--		retval = bttv_prepare_buffer(&fh->cap,btv,buf,
--					     format_by_palette(vm->format),
--					     vm->width,vm->height,field);
--		if (0 != retval)
--			goto fh_unlock_and_return;
--		btv->init.width = vm->width;
--		btv->init.height = vm->height;
--		spin_lock_irqsave(&btv->s_lock,flags);
--		buffer_queue(&fh->cap,&buf->vb);
--		spin_unlock_irqrestore(&btv->s_lock,flags);
--		mutex_unlock(&fh->cap.lock);
--		return 0;
-+	if (no_overlay > 0) {
-+		printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
-+		return -EINVAL;
- 	}
--	case VIDIOCSYNC:
--	{
--		int *frame = arg;
--		struct bttv_buffer *buf;
- 
--		if (*frame >= VIDEO_MAX_FRAME)
--			return -EINVAL;
-+	rc = bttv_enum_fmt_cap_ovr(f);
- 
--		mutex_lock(&fh->cap.lock);
--		retval = -EINVAL;
--		buf = (struct bttv_buffer *)fh->cap.bufs[*frame];
--		if (NULL == buf)
--			goto fh_unlock_and_return;
--		retval = videobuf_waiton(&buf->vb,0,1);
--		if (0 != retval)
--			goto fh_unlock_and_return;
--		switch (buf->vb.state) {
--		case STATE_ERROR:
--			retval = -EIO;
--			/* fall through */
--		case STATE_DONE:
--		{
--			struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
--			videobuf_dma_sync(&fh->cap,dma);
--			bttv_dma_free(&fh->cap,btv,buf);
--			break;
--		}
--		default:
--			retval = -EINVAL;
--			break;
--		}
--		mutex_unlock(&fh->cap.lock);
--		return retval;
--	}
-+	if (rc < 0)
-+		return rc;
- 
--	case VIDIOCGVBIFMT:
--		if (fh->type != V4L2_BUF_TYPE_VBI_CAPTURE) {
--			retval = bttv_switch_type(fh,V4L2_BUF_TYPE_VBI_CAPTURE);
--			if (0 != retval)
--				return retval;
--		}
-+	if (!(formats[rc].flags & FORMAT_FLAGS_PACKED))
-+		return -EINVAL;
- 
--		/* fall through */
++	dprintk(1, "%s()\n", __FUNCTION__);
 +	return 0;
 +}
- 
--	case VIDIOCSVBIFMT:
--		return v4l_compat_translate_ioctl(inode, file, cmd,
--						  arg, bttv_do_ioctl);
--
--	case BTTV_VERSION:
--	case VIDIOCGFREQ:
--	case VIDIOCSFREQ:
--	case VIDIOCGTUNER:
--	case VIDIOCSTUNER:
--	case VIDIOCGCHAN:
--	case VIDIOCSCHAN:
--	case VIDIOCGAUDIO:
--	case VIDIOCSAUDIO:
--		return bttv_common_ioctls(btv,cmd,arg);
--
--	/* ***  v4l2  *** ************************************************ */
--	case VIDIOC_QUERYCAP:
--	{
--		struct v4l2_capability *cap = arg;
-+static int bttv_g_fbuf(struct file *file, void *f,
-+				struct v4l2_framebuffer *fb)
++
++static int cx23885_start_video_dma(struct cx23885_dev *dev,
++			   struct cx23885_dmaqueue *q,
++			   struct cx23885_buffer *buf)
 +{
-+	struct bttv_fh *fh = f;
-+	struct bttv *btv = fh->btv;
- 
--		if (0 == v4l2)
--			return -EINVAL;
--		memset(cap, 0, sizeof (*cap));
--		strlcpy(cap->driver, "bttv", sizeof (cap->driver));
--		strlcpy(cap->card, btv->video_dev->name, sizeof (cap->card));
--		snprintf(cap->bus_info, sizeof (cap->bus_info),
--			 "PCI:%s", pci_name(btv->c.pci));
--		cap->version = BTTV_VERSION_CODE;
--		cap->capabilities =
--			V4L2_CAP_VIDEO_CAPTURE |
--			V4L2_CAP_VBI_CAPTURE |
--			V4L2_CAP_READWRITE |
--			V4L2_CAP_STREAMING;
--		if (no_overlay <= 0)
--			cap->capabilities |= V4L2_CAP_VIDEO_OVERLAY;
--
--		if (bttv_tvcards[btv->c.type].tuner != UNSET &&
--		    bttv_tvcards[btv->c.type].tuner != TUNER_ABSENT)
--			cap->capabilities |= V4L2_CAP_TUNER;
--		return 0;
--	}
-+	*fb = btv->fbuf;
-+	fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING;
-+	if (fh->ovfmt)
-+		fb->fmt.pixelformat  = fh->ovfmt->fourcc;
++	dprintk(1, "%s()\n", __FUNCTION__);
++
++	/* setup fifo + format */
++	cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH01],
++				buf->bpl, buf->risc.dma);
++	cx23885_set_scale(dev, buf->vb.width, buf->vb.height, buf->vb.field);
++
++	/* reset counter */
++	cx_write(VID_A_GPCNT_CTL, 3);
++	q->count = 1;
++
++	/* enable irq */
++	cx_set(PCI_INT_MSK, cx_read(PCI_INT_MSK) | 0x01);
++	cx_set(VID_A_INT_MSK, 0x000011);
++
++	/* start dma */
++	cx_set(DEV_CNTRL2, (1<<5));
++	cx_set(VID_A_DMA_CTL, 0x11); /* FIFO and RISC enable */
++
 +	return 0;
 +}
- 
--	case VIDIOC_ENUM_FMT:
--	{
--		struct v4l2_fmtdesc *f = arg;
--		enum v4l2_buf_type type;
--		unsigned int i;
--		int index;
--
--		type  = f->type;
--		if (V4L2_BUF_TYPE_VBI_CAPTURE == type) {
--			/* vbi */
--			index = f->index;
--			if (0 != index)
--				return -EINVAL;
--			memset(f,0,sizeof(*f));
--			f->index       = index;
--			f->type        = type;
--			f->pixelformat = V4L2_PIX_FMT_GREY;
--			strcpy(f->description,"vbi data");
--			return 0;
--		}
-+static int bttv_overlay(struct file *file, void *f, unsigned int on)
++
++
++static int cx23885_restart_video_queue(struct cx23885_dev *dev,
++			       struct cx23885_dmaqueue *q)
 +{
-+	struct bttv_fh *fh = f;
-+	struct bttv *btv = fh->btv;
-+	struct bttv_buffer *new;
-+	int retval;
- 
--		/* video capture + overlay */
--		index = -1;
--		for (i = 0; i < BTTV_FORMATS; i++) {
--			if (bttv_formats[i].fourcc != -1)
--				index++;
--			if ((unsigned int)index == f->index)
--				break;
--		}
--		if (BTTV_FORMATS == i)
-+	if (on) {
-+		/* verify args */
-+		if (NULL == btv->fbuf.base)
- 			return -EINVAL;
--
--		switch (f->type) {
--		case V4L2_BUF_TYPE_VIDEO_CAPTURE:
--			break;
--		case V4L2_BUF_TYPE_VIDEO_OVERLAY:
--			if (!(bttv_formats[i].flags & FORMAT_FLAGS_PACKED))
--				return -EINVAL;
--			break;
--		default:
-+		if (!fh->ov.setup_ok) {
-+			dprintk("bttv%d: overlay: !setup_ok\n", btv->c.nr);
- 			return -EINVAL;
- 		}
--		memset(f,0,sizeof(*f));
--		f->index       = index;
--		f->type        = type;
--		f->pixelformat = bttv_formats[i].fourcc;
--		strlcpy(f->description,bttv_formats[i].name,sizeof(f->description));
--		return 0;
- 	}
- 
--	case VIDIOC_TRY_FMT:
--	{
--		struct v4l2_format *f = arg;
--		return bttv_try_fmt(fh,btv,f, /* adjust_crop */ 0);
--	}
--	case VIDIOC_G_FMT:
--	{
--		struct v4l2_format *f = arg;
--		return bttv_g_fmt(fh,f);
--	}
--	case VIDIOC_S_FMT:
--	{
--		struct v4l2_format *f = arg;
--		return bttv_s_fmt(fh,btv,f);
-+	if (!check_alloc_btres(btv, fh, RESOURCE_OVERLAY))
-+		return -EBUSY;
++	struct cx23885_buffer *buf, *prev;
++	struct list_head *item;
++	dprintk(1, "%s()\n", __FUNCTION__);
 +
-+	mutex_lock(&fh->cap.lock);
-+	if (on) {
-+		fh->ov.tvnorm = btv->tvnorm;
-+		new = videobuf_pci_alloc(sizeof(*new));
-+		bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new);
-+	} else {
-+		new = NULL;
- 	}
- 
--	case VIDIOC_G_FBUF:
--	{
--		struct v4l2_framebuffer *fb = arg;
-+	/* switch over */
-+	retval = bttv_switch_overlay(btv, fh, new);
-+	mutex_unlock(&fh->cap.lock);
-+	return retval;
++	if (!list_empty(&q->active)) {
++		buf = list_entry(q->active.next, struct cx23885_buffer,
++			vb.queue);
++		dprintk(2, "restart_queue [%p/%d]: restart dma\n",
++			buf, buf->vb.i);
++		cx23885_start_video_dma(dev, q, buf);
++		list_for_each(item, &q->active) {
++			buf = list_entry(item, struct cx23885_buffer,
++				vb.queue);
++			buf->count    = q->count++;
++		}
++		mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
++		return 0;
++	}
++
++	prev = NULL;
++	for (;;) {
++		if (list_empty(&q->queued))
++			return 0;
++		buf = list_entry(q->queued.next, struct cx23885_buffer,
++			vb.queue);
++		if (NULL == prev) {
++			list_move_tail(&buf->vb.queue, &q->active);
++			cx23885_start_video_dma(dev, q, buf);
++			buf->vb.state = VIDEOBUF_ACTIVE;
++			buf->count    = q->count++;
++			mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
++			dprintk(2, "[%p/%d] restart_queue - first active\n",
++				buf, buf->vb.i);
++
++		} else if (prev->vb.width  == buf->vb.width  &&
++			   prev->vb.height == buf->vb.height &&
++			   prev->fmt       == buf->fmt) {
++			list_move_tail(&buf->vb.queue, &q->active);
++			buf->vb.state = VIDEOBUF_ACTIVE;
++			buf->count    = q->count++;
++			prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
++			prev->risc.jmp[2] = cpu_to_le32(0); /* Bits 63 - 32 */
++			dprintk(2, "[%p/%d] restart_queue - move to active\n",
++				buf, buf->vb.i);
++		} else {
++			return 0;
++		}
++		prev = buf;
++	}
 +}
- 
--		*fb = btv->fbuf;
--		fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING;
--		if (fh->ovfmt)
--			fb->fmt.pixelformat  = fh->ovfmt->fourcc;
--		return 0;
--	}
--	case VIDIOC_S_FBUF:
--	{
--		struct v4l2_framebuffer *fb = arg;
--		const struct bttv_format *fmt;
-+static int bttv_s_fbuf(struct file *file, void *f,
-+				struct v4l2_framebuffer *fb)
++
++static int buffer_setup(struct videobuf_queue *q, unsigned int *count,
++	unsigned int *size)
 +{
-+	struct bttv_fh *fh = f;
-+	struct bttv *btv = fh->btv;
-+	const struct bttv_format *fmt;
-+	int retval;
- 
--		if(!capable(CAP_SYS_ADMIN) &&
--		   !capable(CAP_SYS_RAWIO))
--			return -EPERM;
-+	if (!capable(CAP_SYS_ADMIN) &&
-+		!capable(CAP_SYS_RAWIO))
-+		return -EPERM;
- 
--		/* check args */
--		fmt = format_by_fourcc(fb->fmt.pixelformat);
--		if (NULL == fmt)
--			return -EINVAL;
--		if (0 == (fmt->flags & FORMAT_FLAGS_PACKED))
--			return -EINVAL;
-+	/* check args */
-+	fmt = format_by_fourcc(fb->fmt.pixelformat);
-+	if (NULL == fmt)
++	struct cx23885_fh *fh = q->priv_data;
++
++	*size = fh->fmt->depth*fh->width*fh->height >> 3;
++	if (0 == *count)
++		*count = 32;
++	while (*size * *count > vid_limit * 1024 * 1024)
++		(*count)--;
++	return 0;
++}
++
++static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
++	       enum v4l2_field field)
++{
++	struct cx23885_fh *fh  = q->priv_data;
++	struct cx23885_dev *dev = fh->dev;
++	struct cx23885_buffer *buf =
++		container_of(vb, struct cx23885_buffer, vb);
++	int rc, init_buffer = 0;
++	u32 line0_offset, line1_offset;
++	struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb);
++
++	BUG_ON(NULL == fh->fmt);
++	if (fh->width  < 48 || fh->width  > norm_maxw(dev->tvnorm) ||
++	    fh->height < 32 || fh->height > norm_maxh(dev->tvnorm))
 +		return -EINVAL;
-+	if (0 == (fmt->flags & FORMAT_FLAGS_PACKED))
++	buf->vb.size = (fh->width * fh->height * fh->fmt->depth) >> 3;
++	if (0 != buf->vb.baddr  &&  buf->vb.bsize < buf->vb.size)
 +		return -EINVAL;
- 
--		retval = -EINVAL;
--		if (fb->flags & V4L2_FBUF_FLAG_OVERLAY) {
--			__s32 width = fb->fmt.width;
--			__s32 height = fb->fmt.height;
--
--			retval = limit_scaled_size(fh, &width, &height,
--						   V4L2_FIELD_INTERLACED,
--						   /* width_mask */ ~3,
--						   /* width_bias */ 2,
--						   /* adjust_size */ 0,
--						   /* adjust_crop */ 0);
--			if (0 != retval)
--				return retval;
--		}
-+	retval = -EINVAL;
-+	if (fb->flags & V4L2_FBUF_FLAG_OVERLAY) {
-+		__s32 width = fb->fmt.width;
-+		__s32 height = fb->fmt.height;
 +
-+		retval = limit_scaled_size(fh, &width, &height,
-+					   V4L2_FIELD_INTERLACED,
-+					   /* width_mask */ ~3,
-+					   /* width_bias */ 2,
-+					   /* adjust_size */ 0,
-+					   /* adjust_crop */ 0);
-+		if (0 != retval)
-+			return retval;
++	if (buf->fmt       != fh->fmt    ||
++	    buf->vb.width  != fh->width  ||
++	    buf->vb.height != fh->height ||
++	    buf->vb.field  != field) {
++		buf->fmt       = fh->fmt;
++		buf->vb.width  = fh->width;
++		buf->vb.height = fh->height;
++		buf->vb.field  = field;
++		init_buffer = 1;
 +	}
- 
--		/* ok, accept it */
--		mutex_lock(&fh->cap.lock);
--		btv->fbuf.base       = fb->base;
--		btv->fbuf.fmt.width  = fb->fmt.width;
--		btv->fbuf.fmt.height = fb->fmt.height;
--		if (0 != fb->fmt.bytesperline)
--			btv->fbuf.fmt.bytesperline = fb->fmt.bytesperline;
--		else
--			btv->fbuf.fmt.bytesperline = btv->fbuf.fmt.width*fmt->depth/8;
--
--		retval = 0;
--		fh->ovfmt = fmt;
--		btv->init.ovfmt = fmt;
--		if (fb->flags & V4L2_FBUF_FLAG_OVERLAY) {
--			fh->ov.w.left   = 0;
--			fh->ov.w.top    = 0;
--			fh->ov.w.width  = fb->fmt.width;
--			fh->ov.w.height = fb->fmt.height;
--			btv->init.ov.w.width  = fb->fmt.width;
--			btv->init.ov.w.height = fb->fmt.height;
--				kfree(fh->ov.clips);
--			fh->ov.clips = NULL;
--			fh->ov.nclips = 0;
--
--			if (check_btres(fh, RESOURCE_OVERLAY)) {
--				struct bttv_buffer *new;
--
--				new = videobuf_pci_alloc(sizeof(*new));
--				new->crop = btv->crop[!!fh->do_crop].rect;
--				bttv_overlay_risc(btv,&fh->ov,fh->ovfmt,new);
--				retval = bttv_switch_overlay(btv,fh,new);
--			}
-+	/* ok, accept it */
-+	mutex_lock(&fh->cap.lock);
-+	btv->fbuf.base       = fb->base;
-+	btv->fbuf.fmt.width  = fb->fmt.width;
-+	btv->fbuf.fmt.height = fb->fmt.height;
-+	if (0 != fb->fmt.bytesperline)
-+		btv->fbuf.fmt.bytesperline = fb->fmt.bytesperline;
-+	else
-+		btv->fbuf.fmt.bytesperline = btv->fbuf.fmt.width*fmt->depth/8;
 +
-+	retval = 0;
-+	fh->ovfmt = fmt;
-+	btv->init.ovfmt = fmt;
-+	if (fb->flags & V4L2_FBUF_FLAG_OVERLAY) {
-+		fh->ov.w.left   = 0;
-+		fh->ov.w.top    = 0;
-+		fh->ov.w.width  = fb->fmt.width;
-+		fh->ov.w.height = fb->fmt.height;
-+		btv->init.ov.w.width  = fb->fmt.width;
-+		btv->init.ov.w.height = fb->fmt.height;
-+			kfree(fh->ov.clips);
-+		fh->ov.clips = NULL;
-+		fh->ov.nclips = 0;
++	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
++		init_buffer = 1;
++		rc = videobuf_iolock(q, &buf->vb, NULL);
++		if (0 != rc)
++			goto fail;
++	}
 +
-+		if (check_btres(fh, RESOURCE_OVERLAY)) {
-+			struct bttv_buffer *new;
++	if (init_buffer) {
++		buf->bpl = buf->vb.width * buf->fmt->depth >> 3;
++		switch (buf->vb.field) {
++		case V4L2_FIELD_TOP:
++			cx23885_risc_buffer(dev->pci, &buf->risc,
++					 dma->sglist, 0, UNSET,
++					 buf->bpl, 0, buf->vb.height);
++			break;
++		case V4L2_FIELD_BOTTOM:
++			cx23885_risc_buffer(dev->pci, &buf->risc,
++					 dma->sglist, UNSET, 0,
++					 buf->bpl, 0, buf->vb.height);
++			break;
++		case V4L2_FIELD_INTERLACED:
++			if (dev->tvnorm & V4L2_STD_NTSC) {
++				/* cx25840 transmits NTSC bottom field first */
++				dprintk(1, "%s() Creating NTSC risc\n",
++					__FUNCTION__);
++				line0_offset = buf->bpl;
++				line1_offset = 0;
++			} else {
++				/* All other formats are top field first */
++				dprintk(1, "%s() Creating PAL/SECAM risc\n",
++					__FUNCTION__);
++				line0_offset = 0;
++				line1_offset = buf->bpl;
++			}
++			cx23885_risc_buffer(dev->pci, &buf->risc,
++					dma->sglist, line0_offset,
++					line1_offset,
++					buf->bpl, buf->bpl,
++					buf->vb.height >> 1);
++			break;
++		case V4L2_FIELD_SEQ_TB:
++			cx23885_risc_buffer(dev->pci, &buf->risc,
++					 dma->sglist,
++					 0, buf->bpl * (buf->vb.height >> 1),
++					 buf->bpl, 0,
++					 buf->vb.height >> 1);
++			break;
++		case V4L2_FIELD_SEQ_BT:
++			cx23885_risc_buffer(dev->pci, &buf->risc,
++					 dma->sglist,
++					 buf->bpl * (buf->vb.height >> 1), 0,
++					 buf->bpl, 0,
++					 buf->vb.height >> 1);
++			break;
++		default:
++			BUG();
++		}
++	}
++	dprintk(2, "[%p/%d] buffer_prep - %dx%d %dbpp \"%s\" - dma=0x%08lx\n",
++		buf, buf->vb.i,
++		fh->width, fh->height, fh->fmt->depth, fh->fmt->name,
++		(unsigned long)buf->risc.dma);
 +
-+			new = videobuf_pci_alloc(sizeof(*new));
-+			new->crop = btv->crop[!!fh->do_crop].rect;
-+			bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new);
-+			retval = bttv_switch_overlay(btv, fh, new);
- 		}
--		mutex_unlock(&fh->cap.lock);
--		return retval;
- 	}
-+	mutex_unlock(&fh->cap.lock);
-+	return retval;
-+}
- 
--	case VIDIOC_REQBUFS:
--		return videobuf_reqbufs(bttv_queue(fh),arg);
-+static int bttv_reqbufs(struct file *file, void *priv,
-+				struct v4l2_requestbuffers *p)
-+{
-+	struct bttv_fh *fh = priv;
-+	return videobuf_reqbufs(bttv_queue(fh), p);
-+}
- 
--	case VIDIOC_QUERYBUF:
--		return videobuf_querybuf(bttv_queue(fh),arg);
-+static int bttv_querybuf(struct file *file, void *priv,
-+				struct v4l2_buffer *b)
-+{
-+	struct bttv_fh *fh = priv;
-+	return videobuf_querybuf(bttv_queue(fh), b);
++	buf->vb.state = VIDEOBUF_PREPARED;
++	return 0;
++
++ fail:
++	cx23885_free_buffer(q, buf);
++	return rc;
 +}
- 
--	case VIDIOC_QBUF:
--	{
--		int res = bttv_resource(fh);
-+static int bttv_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
++
++static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
 +{
-+	struct bttv_fh *fh = priv;
-+	struct bttv *btv = fh->btv;
-+	int res = bttv_resource(fh);
- 
--		if (!check_alloc_btres(btv, fh, res))
--			return -EBUSY;
--		return videobuf_qbuf(bttv_queue(fh),arg);
--	}
-+	if (!check_alloc_btres(btv, fh, res))
-+		return -EBUSY;
- 
--	case VIDIOC_DQBUF:
--		return videobuf_dqbuf(bttv_queue(fh),arg,
--				      file->f_flags & O_NONBLOCK);
-+	return videobuf_qbuf(bttv_queue(fh), b);
++	struct cx23885_buffer   *buf = container_of(vb,
++		struct cx23885_buffer, vb);
++	struct cx23885_buffer   *prev;
++	struct cx23885_fh       *fh   = vq->priv_data;
++	struct cx23885_dev      *dev  = fh->dev;
++	struct cx23885_dmaqueue *q    = &dev->vidq;
++
++	/* add jump to stopper */
++	buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
++	buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma);
++	buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */
++
++	if (!list_empty(&q->queued)) {
++		list_add_tail(&buf->vb.queue, &q->queued);
++		buf->vb.state = VIDEOBUF_QUEUED;
++		dprintk(2, "[%p/%d] buffer_queue - append to queued\n",
++			buf, buf->vb.i);
++
++	} else if (list_empty(&q->active)) {
++		list_add_tail(&buf->vb.queue, &q->active);
++		cx23885_start_video_dma(dev, q, buf);
++		buf->vb.state = VIDEOBUF_ACTIVE;
++		buf->count    = q->count++;
++		mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
++		dprintk(2, "[%p/%d] buffer_queue - first active\n",
++			buf, buf->vb.i);
++
++	} else {
++		prev = list_entry(q->active.prev, struct cx23885_buffer,
++			vb.queue);
++		if (prev->vb.width  == buf->vb.width  &&
++		    prev->vb.height == buf->vb.height &&
++		    prev->fmt       == buf->fmt) {
++			list_add_tail(&buf->vb.queue, &q->active);
++			buf->vb.state = VIDEOBUF_ACTIVE;
++			buf->count    = q->count++;
++			prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
++			/* 64 bit bits 63-32 */
++			prev->risc.jmp[2] = cpu_to_le32(0);
++			dprintk(2, "[%p/%d] buffer_queue - append to active\n",
++				buf, buf->vb.i);
++
++		} else {
++			list_add_tail(&buf->vb.queue, &q->queued);
++			buf->vb.state = VIDEOBUF_QUEUED;
++			dprintk(2, "[%p/%d] buffer_queue - first queued\n",
++				buf, buf->vb.i);
++		}
++	}
 +}
- 
--	case VIDIOC_STREAMON:
--	{
--		int res = bttv_resource(fh);
-+static int bttv_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
++
++static void buffer_release(struct videobuf_queue *q,
++	struct videobuf_buffer *vb)
 +{
-+	struct bttv_fh *fh = priv;
-+	return videobuf_dqbuf(bttv_queue(fh), b,
-+			file->f_flags & O_NONBLOCK);
++	struct cx23885_buffer *buf = container_of(vb,
++		struct cx23885_buffer, vb);
++
++	cx23885_free_buffer(q, buf);
 +}
- 
--		if (!check_alloc_btres(btv,fh,res))
--			return -EBUSY;
--		return videobuf_streamon(bttv_queue(fh));
--	}
--	case VIDIOC_STREAMOFF:
--	{
--		int res = bttv_resource(fh);
-+static int bttv_streamon(struct file *file, void *priv,
-+					enum v4l2_buf_type type)
++
++static struct videobuf_queue_ops cx23885_video_qops = {
++	.buf_setup    = buffer_setup,
++	.buf_prepare  = buffer_prepare,
++	.buf_queue    = buffer_queue,
++	.buf_release  = buffer_release,
++};
++
++static struct videobuf_queue *get_queue(struct cx23885_fh *fh)
 +{
-+	struct bttv_fh *fh = priv;
-+	struct bttv *btv = fh->btv;
-+	int res = bttv_resource(fh);
- 
--		retval = videobuf_streamoff(bttv_queue(fh));
--		if (retval < 0)
--			return retval;
--		free_btres(btv,fh,res);
--		return 0;
--	}
-+	if (!check_alloc_btres(btv, fh, res))
-+		return -EBUSY;
-+	return videobuf_streamon(bttv_queue(fh));
++	switch (fh->type) {
++	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
++		return &fh->vidq;
++	case V4L2_BUF_TYPE_VBI_CAPTURE:
++		return &fh->vbiq;
++	default:
++		BUG();
++		return NULL;
++	}
 +}
- 
--	case VIDIOC_QUERYCTRL:
--	{
--		struct v4l2_queryctrl *c = arg;
--		int i;
- 
--		if ((c->id <  V4L2_CID_BASE ||
--		     c->id >= V4L2_CID_LASTP1) &&
--		    (c->id <  V4L2_CID_PRIVATE_BASE ||
--		     c->id >= V4L2_CID_PRIVATE_LASTP1))
--			return -EINVAL;
--		for (i = 0; i < BTTV_CTLS; i++)
--			if (bttv_ctls[i].id == c->id)
--				break;
--		if (i == BTTV_CTLS) {
--			*c = no_ctl;
--			return 0;
--		}
--		*c = bttv_ctls[i];
--		if (btv->audio_hook && i >= 4 && i <= 8) {
--			struct video_audio va;
--			memset(&va,0,sizeof(va));
--			btv->audio_hook(btv,&va,0);
--			switch (bttv_ctls[i].id) {
--			case V4L2_CID_AUDIO_VOLUME:
--				if (!(va.flags & VIDEO_AUDIO_VOLUME))
--					*c = no_ctl;
--				break;
--			case V4L2_CID_AUDIO_BALANCE:
--				if (!(va.flags & VIDEO_AUDIO_BALANCE))
--					*c = no_ctl;
--				break;
--			case V4L2_CID_AUDIO_BASS:
--				if (!(va.flags & VIDEO_AUDIO_BASS))
--					*c = no_ctl;
--				break;
--			case V4L2_CID_AUDIO_TREBLE:
--				if (!(va.flags & VIDEO_AUDIO_TREBLE))
--					*c = no_ctl;
--				break;
--			}
--		}
--		return 0;
--	}
--	case VIDIOC_G_CTRL:
--		return get_control(btv,arg);
--	case VIDIOC_S_CTRL:
--		return set_control(btv,arg);
--	case VIDIOC_G_PARM:
--	{
--		struct v4l2_streamparm *parm = arg;
--		struct v4l2_standard s;
--		if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
--			return -EINVAL;
--		memset(parm,0,sizeof(*parm));
--		v4l2_video_std_construct(&s, bttv_tvnorms[btv->tvnorm].v4l2_id,
--					 bttv_tvnorms[btv->tvnorm].name);
--		parm->parm.capture.timeperframe = s.frameperiod;
--		return 0;
--	}
-+static int bttv_streamoff(struct file *file, void *priv,
-+					enum v4l2_buf_type type)
++
++static int get_resource(struct cx23885_fh *fh)
 +{
-+	struct bttv_fh *fh = priv;
-+	struct bttv *btv = fh->btv;
-+	int retval;
-+	int res = bttv_resource(fh);
- 
--	case VIDIOC_G_PRIORITY:
--	{
--		enum v4l2_priority *p = arg;
- 
--		*p = v4l2_prio_max(&btv->prio);
--		return 0;
--	}
--	case VIDIOC_S_PRIORITY:
--	{
--		enum v4l2_priority *prio = arg;
-+	retval = videobuf_streamoff(bttv_queue(fh));
-+	if (retval < 0)
-+		return retval;
-+	free_btres(btv, fh, res);
-+	return 0;
++	switch (fh->type) {
++	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
++		return RESOURCE_VIDEO;
++	case V4L2_BUF_TYPE_VBI_CAPTURE:
++		return RESOURCE_VBI;
++	default:
++		BUG();
++		return 0;
++	}
 +}
- 
--		return v4l2_prio_change(&btv->prio, &fh->prio, *prio);
--	}
-+static int bttv_queryctrl(struct file *file, void *priv,
-+					struct v4l2_queryctrl *c)
++
++static int video_open(struct inode *inode, struct file *file)
 +{
-+	struct bttv_fh *fh = priv;
-+	struct bttv *btv = fh->btv;
-+	const struct v4l2_queryctrl *ctrl;
- 
--	case VIDIOC_CROPCAP:
--	{
--		struct v4l2_cropcap *cap = arg;
--		enum v4l2_buf_type type;
-+	if ((c->id <  V4L2_CID_BASE ||
-+	     c->id >= V4L2_CID_LASTP1) &&
-+	    (c->id <  V4L2_CID_PRIVATE_BASE ||
-+	     c->id >= V4L2_CID_PRIVATE_LASTP1))
-+		return -EINVAL;
- 
--		type = cap->type;
-+	if (!btv->volume_gpio && (c->id == V4L2_CID_AUDIO_VOLUME))
-+		*c = no_ctl;
-+	else {
-+		ctrl = ctrl_by_id(c->id);
- 
--		if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
--		    type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
--			return -EINVAL;
-+		*c = (NULL != ctrl) ? *ctrl : no_ctl;
++	int minor = iminor(inode);
++	struct cx23885_dev *h, *dev = NULL;
++	struct cx23885_fh *fh;
++	struct list_head *list;
++	enum v4l2_buf_type type = 0;
++	int radio = 0;
++
++	list_for_each(list, &cx23885_devlist) {
++		h = list_entry(list, struct cx23885_dev, devlist);
++		if (h->video_dev->minor == minor) {
++			dev  = h;
++			type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
++		}
++		if (h->vbi_dev &&
++		   h->vbi_dev->minor == minor) {
++			dev  = h;
++			type = V4L2_BUF_TYPE_VBI_CAPTURE;
++		}
++		if (h->radio_dev &&
++		    h->radio_dev->minor == minor) {
++			radio = 1;
++			dev   = h;
++		}
 +	}
- 
--		*cap = bttv_tvnorms[btv->tvnorm].cropcap;
--		cap->type = type;
++	if (NULL == dev)
++		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)
++		return -ENOMEM;
++	file->private_data = fh;
++	fh->dev      = dev;
++	fh->radio    = radio;
++	fh->type     = type;
++	fh->width    = 320;
++	fh->height   = 240;
++	fh->fmt      = format_by_fourcc(V4L2_PIX_FMT_BGR24);
++
++	videobuf_queue_pci_init(&fh->vidq, &cx23885_video_qops,
++			    dev->pci, &dev->slock,
++			    V4L2_BUF_TYPE_VIDEO_CAPTURE,
++			    V4L2_FIELD_INTERLACED,
++			    sizeof(struct cx23885_buffer),
++			    fh);
++
++	dprintk(1, "post videobuf_queue_init()\n");
++
++
 +	return 0;
 +}
- 
--		return 0;
--	}
--	case VIDIOC_G_CROP:
--	{
--		struct v4l2_crop * crop = arg;
-+static int bttv_g_parm(struct file *file, void *f,
-+				struct v4l2_streamparm *parm)
++
++static ssize_t video_read(struct file *file, char __user *data,
++	size_t count, loff_t *ppos)
 +{
-+	struct bttv_fh *fh = f;
-+	struct bttv *btv = fh->btv;
-+	struct v4l2_standard s;
- 
--		if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
--		    crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
--			return -EINVAL;
-+	if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-+		return -EINVAL;
-+	v4l2_video_std_construct(&s, bttv_tvnorms[btv->tvnorm].v4l2_id,
-+				 bttv_tvnorms[btv->tvnorm].name);
-+	parm->parm.capture.timeperframe = s.frameperiod;
-+	return 0;
++	struct cx23885_fh *fh = file->private_data;
++
++	switch (fh->type) {
++	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
++		if (res_locked(fh->dev, RESOURCE_VIDEO))
++			return -EBUSY;
++		return videobuf_read_one(&fh->vidq, data, count, ppos,
++					 file->f_flags & O_NONBLOCK);
++	case V4L2_BUF_TYPE_VBI_CAPTURE:
++		if (!res_get(fh->dev, fh, RESOURCE_VBI))
++			return -EBUSY;
++		return videobuf_read_stream(&fh->vbiq, data, count, ppos, 1,
++					    file->f_flags & O_NONBLOCK);
++	default:
++		BUG();
++		return 0;
++	}
 +}
- 
--		/* No fh->do_crop = 1; because btv->crop[1] may be
--		   inconsistent with fh->width or fh->height and apps
--		   do not expect a change here. */
-+static int bttv_g_tuner(struct file *file, void *priv,
-+				struct v4l2_tuner *t)
++
++static unsigned int video_poll(struct file *file,
++	struct poll_table_struct *wait)
 +{
-+	struct bttv_fh *fh = priv;
-+	struct bttv *btv = fh->btv;
- 
--		crop->c = btv->crop[!!fh->do_crop].rect;
-+	if (UNSET == bttv_tvcards[btv->c.type].tuner)
-+		return -EINVAL;
-+	if (0 != t->index)
-+		return -EINVAL;
- 
--		return 0;
--	}
--	case VIDIOC_S_CROP:
--	{
--		struct v4l2_crop *crop = arg;
--		const struct v4l2_rect *b;
--		struct bttv_crop c;
--		__s32 b_left;
--		__s32 b_top;
--		__s32 b_right;
--		__s32 b_bottom;
--
--		if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
--		    crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
--			return -EINVAL;
-+	mutex_lock(&btv->lock);
-+	memset(t, 0, sizeof(*t));
-+	t->rxsubchans = V4L2_TUNER_SUB_MONO;
-+	bttv_call_i2c_clients(btv, VIDIOC_G_TUNER, t);
-+	strcpy(t->name, "Television");
-+	t->capability = V4L2_TUNER_CAP_NORM;
-+	t->type       = V4L2_TUNER_ANALOG_TV;
-+	if (btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC)
-+		t->signal = 0xffff;
++	struct cx23885_fh *fh = file->private_data;
++	struct cx23885_buffer *buf;
 +
-+	if (btv->audio_mode_gpio)
-+		btv->audio_mode_gpio(btv, t, 0);
- 
--		retval = v4l2_prio_check(&btv->prio,&fh->prio);
--		if (0 != retval)
--			return retval;
-+	mutex_unlock(&btv->lock);
++	if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) {
++		if (!res_get(fh->dev, fh, RESOURCE_VBI))
++			return POLLERR;
++		return videobuf_poll_stream(file, &fh->vbiq, wait);
++	}
++
++	if (res_check(fh, RESOURCE_VIDEO)) {
++		/* streaming capture */
++		if (list_empty(&fh->vidq.stream))
++			return POLLERR;
++		buf = list_entry(fh->vidq.stream.next,
++			struct cx23885_buffer, vb.stream);
++	} else {
++		/* read() capture */
++		buf = (struct cx23885_buffer *)fh->vidq.read_buf;
++		if (NULL == buf)
++			return POLLERR;
++	}
++	poll_wait(file, &buf->vb.done, wait);
++	if (buf->vb.state == VIDEOBUF_DONE ||
++	    buf->vb.state == VIDEOBUF_ERROR)
++		return POLLIN|POLLRDNORM;
 +	return 0;
 +}
- 
--		/* Make sure tvnorm, vbi_end and the current cropping
--		   parameters remain consistent until we're done. Note
--		   read() may change vbi_end in check_alloc_btres(). */
--		mutex_lock(&btv->lock);
-+static int bttv_g_priority(struct file *file, void *f, enum v4l2_priority *p)
++
++static int video_release(struct inode *inode, struct file *file)
 +{
-+	struct bttv_fh *fh = f;
-+	struct bttv *btv = fh->btv;
- 
--		retval = -EBUSY;
-+	*p = v4l2_prio_max(&btv->prio);
- 
--		if (locked_btres(fh->btv, VIDEO_RESOURCES))
--			goto btv_unlock_and_return;
++	struct cx23885_fh *fh = file->private_data;
++	struct cx23885_dev *dev = fh->dev;
++
++	/* turn off overlay */
++	if (res_check(fh, RESOURCE_OVERLAY)) {
++		/* FIXME */
++		res_free(dev, fh, RESOURCE_OVERLAY);
++	}
++
++	/* stop video capture */
++	if (res_check(fh, RESOURCE_VIDEO)) {
++		videobuf_queue_cancel(&fh->vidq);
++		res_free(dev, fh, RESOURCE_VIDEO);
++	}
++	if (fh->vidq.read_buf) {
++		buffer_release(&fh->vidq, fh->vidq.read_buf);
++		kfree(fh->vidq.read_buf);
++	}
++
++	/* stop vbi capture */
++	if (res_check(fh, RESOURCE_VBI)) {
++		if (fh->vbiq.streaming)
++			videobuf_streamoff(&fh->vbiq);
++		if (fh->vbiq.reading)
++			videobuf_read_stop(&fh->vbiq);
++		res_free(dev, fh, RESOURCE_VBI);
++	}
++
++	videobuf_mmap_free(&fh->vidq);
++	file->private_data = NULL;
++	kfree(fh);
++
++	/* We are not putting the tuner to sleep here on exit, because
++	 * we want to use the mpeg encoder in another session to capture
++	 * tuner video. Closing this will result in no video to the encoder.
++	 */
++
 +	return 0;
 +}
- 
--		b = &bttv_tvnorms[btv->tvnorm].cropcap.bounds;
-+static int bttv_s_priority(struct file *file, void *f,
-+					enum v4l2_priority prio)
++
++static int video_mmap(struct file *file, struct vm_area_struct *vma)
 +{
-+	struct bttv_fh *fh = f;
-+	struct bttv *btv = fh->btv;
- 
--		b_left = b->left;
--		b_right = b_left + b->width;
--		b_bottom = b->top + b->height;
-+	return v4l2_prio_change(&btv->prio, &fh->prio, prio);
++	struct cx23885_fh *fh = file->private_data;
++
++	return videobuf_mmap_mapper(get_queue(fh), vma);
 +}
- 
--		b_top = max(b->top, btv->vbi_end);
--		if (b_top + 32 >= b_bottom)
--			goto btv_unlock_and_return;
-+static int bttv_cropcap(struct file *file, void *priv,
-+				struct v4l2_cropcap *cap)
++
++/* ------------------------------------------------------------------ */
++/* VIDEO CTRL IOCTLS                                                  */
++
++int cx23885_get_control(struct cx23885_dev *dev, struct v4l2_control *ctl)
 +{
-+	struct bttv_fh *fh = priv;
-+	struct bttv *btv = fh->btv;
- 
--		/* Min. scaled size 48 x 32. */
--		c.rect.left = clamp(crop->c.left, b_left, b_right - 48);
--		c.rect.left = min(c.rect.left, (__s32) MAX_HDELAY);
-+	if (cap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
-+	    cap->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
-+		return -EINVAL;
- 
--		c.rect.width = clamp(crop->c.width,
--				     48, b_right - c.rect.left);
-+	*cap = bttv_tvnorms[btv->tvnorm].cropcap;
- 
--		c.rect.top = clamp(crop->c.top, b_top, b_bottom - 32);
--		/* Top and height must be a multiple of two. */
--		c.rect.top = (c.rect.top + 1) & ~1;
++	dprintk(1, "%s() calling cx25840(VIDIOC_G_CTRL)\n", __FUNCTION__);
++	cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_G_CTRL, ctl);
 +	return 0;
 +}
- 
--		c.rect.height = clamp(crop->c.height,
--				      32, b_bottom - c.rect.top);
--		c.rect.height = (c.rect.height + 1) & ~1;
-+static int bttv_g_crop(struct file *file, void *f, struct v4l2_crop *crop)
++EXPORT_SYMBOL(cx23885_get_control);
++
++int cx23885_set_control(struct cx23885_dev *dev, struct v4l2_control *ctl)
 +{
-+	struct bttv_fh *fh = f;
-+	struct bttv *btv = fh->btv;
- 
--		bttv_crop_calc_limits(&c);
-+	if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
-+	    crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
-+		return -EINVAL;
- 
--		btv->crop[1] = c;
-+	/* No fh->do_crop = 1; because btv->crop[1] may be
-+	   inconsistent with fh->width or fh->height and apps
-+	   do not expect a change here. */
- 
--		mutex_unlock(&btv->lock);
-+	crop->c = btv->crop[!!fh->do_crop].rect;
- 
--		fh->do_crop = 1;
++	dprintk(1, "%s() calling cx25840(VIDIOC_S_CTRL)"
++		" (disabled - no action)\n", __FUNCTION__);
 +	return 0;
 +}
- 
--		mutex_lock(&fh->cap.lock);
-+static int bttv_s_crop(struct file *file, void *f, struct v4l2_crop *crop)
-+{
-+	struct bttv_fh *fh = f;
-+	struct bttv *btv = fh->btv;
-+	const struct v4l2_rect *b;
-+	int retval;
-+	struct bttv_crop c;
-+	__s32 b_left;
-+	__s32 b_top;
-+	__s32 b_right;
-+	__s32 b_bottom;
- 
--		if (fh->width < c.min_scaled_width) {
--			fh->width = c.min_scaled_width;
--			btv->init.width = c.min_scaled_width;
--		} else if (fh->width > c.max_scaled_width) {
--			fh->width = c.max_scaled_width;
--			btv->init.width = c.max_scaled_width;
--		}
-+	if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
-+	    crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
-+		return -EINVAL;
- 
--		if (fh->height < c.min_scaled_height) {
--			fh->height = c.min_scaled_height;
--			btv->init.height = c.min_scaled_height;
--		} else if (fh->height > c.max_scaled_height) {
--			fh->height = c.max_scaled_height;
--			btv->init.height = c.max_scaled_height;
--		}
-+	retval = v4l2_prio_check(&btv->prio, &fh->prio);
-+	if (0 != retval)
-+		return retval;
- 
--		mutex_unlock(&fh->cap.lock);
-+	/* Make sure tvnorm, vbi_end and the current cropping
-+	   parameters remain consistent until we're done. Note
-+	   read() may change vbi_end in check_alloc_btres(). */
-+	mutex_lock(&btv->lock);
- 
--		return 0;
-+	retval = -EBUSY;
++EXPORT_SYMBOL(cx23885_set_control);
 +
-+	if (locked_btres(fh->btv, VIDEO_RESOURCES)) {
-+		mutex_unlock(&btv->lock);
-+		return retval;
- 	}
- 
--	case VIDIOC_ENUMSTD:
--	case VIDIOC_G_STD:
--	case VIDIOC_S_STD:
--	case VIDIOC_ENUMINPUT:
--	case VIDIOC_G_INPUT:
--	case VIDIOC_S_INPUT:
--	case VIDIOC_G_TUNER:
--	case VIDIOC_S_TUNER:
--	case VIDIOC_G_FREQUENCY:
--	case VIDIOC_S_FREQUENCY:
--	case VIDIOC_LOG_STATUS:
--	case VIDIOC_DBG_G_REGISTER:
--	case VIDIOC_DBG_S_REGISTER:
--		return bttv_common_ioctls(btv,cmd,arg);
-+	b = &bttv_tvnorms[btv->tvnorm].cropcap.bounds;
- 
--	default:
--		return -ENOIOCTLCMD;
-+	b_left = b->left;
-+	b_right = b_left + b->width;
-+	b_bottom = b->top + b->height;
++static void init_controls(struct cx23885_dev *dev)
++{
++	struct v4l2_control ctrl;
++	int i;
 +
-+	b_top = max(b->top, btv->vbi_end);
-+	if (b_top + 32 >= b_bottom) {
-+		mutex_unlock(&btv->lock);
-+		return retval;
- 	}
--	return 0;
- 
-- fh_unlock_and_return:
--	mutex_unlock(&fh->cap.lock);
--	return retval;
-+	/* Min. scaled size 48 x 32. */
-+	c.rect.left = clamp(crop->c.left, b_left, b_right - 48);
-+	c.rect.left = min(c.rect.left, (__s32) MAX_HDELAY);
- 
-- btv_unlock_and_return:
--	mutex_unlock(&btv->lock);
--	return retval;
--}
-+	c.rect.width = clamp(crop->c.width,
-+			     48, b_right - c.rect.left);
- 
--static int bttv_ioctl(struct inode *inode, struct file *file,
--		      unsigned int cmd, unsigned long arg)
--{
--	struct bttv_fh *fh  = file->private_data;
-+	c.rect.top = clamp(crop->c.top, b_top, b_bottom - 32);
-+	/* Top and height must be a multiple of two. */
-+	c.rect.top = (c.rect.top + 1) & ~1;
- 
--	switch (cmd) {
--	case BTTV_VBISIZE:
--	{
--		const struct bttv_tvnorm *tvnorm;
-+	c.rect.height = clamp(crop->c.height,
-+			      32, b_bottom - c.rect.top);
-+	c.rect.height = (c.rect.height + 1) & ~1;
- 
--		tvnorm = fh->vbi_fmt.tvnorm;
-+	bttv_crop_calc_limits(&c);
- 
--		if (fh->vbi_fmt.fmt.start[0] != tvnorm->vbistart[0] ||
--		    fh->vbi_fmt.fmt.start[1] != tvnorm->vbistart[1] ||
--		    fh->vbi_fmt.fmt.count[0] != fh->vbi_fmt.fmt.count[1]) {
--			/* BTTV_VBISIZE cannot express these parameters,
--			   however open() resets the paramters to defaults
--			   and apps shouldn't call BTTV_VBISIZE after
--			   VIDIOC_S_FMT. */
--			return -EINVAL;
--		}
-+	btv->crop[1] = c;
++	for (i = 0; i < CX23885_CTLS; i++) {
++		ctrl.id = cx23885_ctls[i].v.id;
++		ctrl.value = cx23885_ctls[i].v.default_value;
 +
-+	mutex_unlock(&btv->lock);
++		cx23885_set_control(dev, &ctrl);
++	}
++}
 +
-+	fh->do_crop = 1;
- 
--		bttv_switch_type(fh,V4L2_BUF_TYPE_VBI_CAPTURE);
--		return (fh->vbi_fmt.fmt.count[0] * 2
--			* fh->vbi_fmt.fmt.samples_per_line);
-+	mutex_lock(&fh->cap.lock);
++/* ------------------------------------------------------------------ */
++/* VIDEO IOCTLS                                                       */
 +
-+	if (fh->width < c.min_scaled_width) {
-+		fh->width = c.min_scaled_width;
-+		btv->init.width = c.min_scaled_width;
-+	} else if (fh->width > c.max_scaled_width) {
-+		fh->width = c.max_scaled_width;
-+		btv->init.width = c.max_scaled_width;
- 	}
- 
--	default:
--		return video_usercopy(inode, file, cmd, arg, bttv_do_ioctl);
-+	if (fh->height < c.min_scaled_height) {
-+		fh->height = c.min_scaled_height;
-+		btv->init.height = c.min_scaled_height;
-+	} else if (fh->height > c.max_scaled_height) {
-+		fh->height = c.max_scaled_height;
-+		btv->init.height = c.max_scaled_height;
- 	}
++static int vidioc_g_fmt_cap(struct file *file, void *priv,
++	struct v4l2_format *f)
++{
++	struct cx23885_fh *fh   = priv;
 +
-+	mutex_unlock(&fh->cap.lock);
++	f->fmt.pix.width        = fh->width;
++	f->fmt.pix.height       = fh->height;
++	f->fmt.pix.field        = fh->vidq.field;
++	f->fmt.pix.pixelformat  = fh->fmt->fourcc;
++	f->fmt.pix.bytesperline =
++		(f->fmt.pix.width * fh->fmt->depth) >> 3;
++	f->fmt.pix.sizeimage =
++		f->fmt.pix.height * f->fmt.pix.bytesperline;
 +
 +	return 0;
 +}
 +
-+static int bttv_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
++static int vidioc_try_fmt_cap(struct file *file, void *priv,
++	struct v4l2_format *f)
 +{
-+	strcpy(a->name, "audio");
-+	return 0;
-+}
++	struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
++	struct cx23885_fmt *fmt;
++	enum v4l2_field   field;
++	unsigned int      maxw, maxh;
 +
-+static int bttv_s_audio(struct file *file, void *priv, struct v4l2_audio *a)
-+{
-+	return 0;
- }
- 
- static ssize_t bttv_read(struct file *file, char __user *data,
-@@ -3719,8 +3205,8 @@ static unsigned int bttv_poll(struct file *file, poll_table *wait)
- 	}
- 
- 	poll_wait(file, &buf->vb.done, wait);
--	if (buf->vb.state == STATE_DONE ||
--	    buf->vb.state == STATE_ERROR)
-+	if (buf->vb.state == VIDEOBUF_DONE ||
-+	    buf->vb.state == VIDEOBUF_ERROR)
- 		return POLLIN|POLLRDNORM;
- 	return 0;
- }
-@@ -3777,7 +3263,7 @@ static int bttv_open(struct inode *inode, struct file *file)
- 			    V4L2_FIELD_SEQ_TB,
- 			    sizeof(struct bttv_buffer),
- 			    fh);
--	i2c_vidiocschan(btv);
-+	set_tvnorm(btv,btv->tvnorm);
- 
- 	btv->users++;
- 
-@@ -3857,7 +3343,7 @@ static const struct file_operations bttv_fops =
- 	.owner	  = THIS_MODULE,
- 	.open	  = bttv_open,
- 	.release  = bttv_release,
--	.ioctl	  = bttv_ioctl,
-+	.ioctl	  = video_ioctl2,
- 	.compat_ioctl	= v4l_compat_ioctl32,
- 	.llseek	  = no_llseek,
- 	.read	  = bttv_read,
-@@ -3867,19 +3353,61 @@ static const struct file_operations bttv_fops =
- 
- static struct video_device bttv_video_template =
- {
--	.name     = "UNSET",
--	.type     = VID_TYPE_CAPTURE|VID_TYPE_TUNER|
--		    VID_TYPE_CLIPPING|VID_TYPE_SCALES,
--	.fops     = &bttv_fops,
--	.minor    = -1,
--};
--
--static struct video_device bttv_vbi_template =
--{
--	.name     = "bt848/878 vbi",
--	.type     = VID_TYPE_TUNER|VID_TYPE_TELETEXT,
- 	.fops     = &bttv_fops,
- 	.minor    = -1,
-+	.vidioc_querycap                = bttv_querycap,
-+	.vidioc_enum_fmt_cap            = bttv_enum_fmt_cap,
-+	.vidioc_g_fmt_cap               = bttv_g_fmt_cap,
-+	.vidioc_try_fmt_cap             = bttv_try_fmt_cap,
-+	.vidioc_s_fmt_cap               = bttv_s_fmt_cap,
-+	.vidioc_enum_fmt_overlay        = bttv_enum_fmt_overlay,
-+	.vidioc_g_fmt_overlay           = bttv_g_fmt_overlay,
-+	.vidioc_try_fmt_overlay         = bttv_try_fmt_overlay,
-+	.vidioc_s_fmt_overlay           = bttv_s_fmt_overlay,
-+	.vidioc_enum_fmt_vbi            = bttv_enum_fmt_vbi,
-+	.vidioc_g_fmt_vbi               = bttv_g_fmt_vbi,
-+	.vidioc_try_fmt_vbi             = bttv_try_fmt_vbi,
-+	.vidioc_s_fmt_vbi               = bttv_s_fmt_vbi,
-+	.vidioc_g_audio                 = bttv_g_audio,
-+	.vidioc_s_audio                 = bttv_s_audio,
-+	.vidioc_cropcap                 = bttv_cropcap,
-+	.vidioc_reqbufs                 = bttv_reqbufs,
-+	.vidioc_querybuf                = bttv_querybuf,
-+	.vidioc_qbuf                    = bttv_qbuf,
-+	.vidioc_dqbuf                   = bttv_dqbuf,
-+	.vidioc_s_std                   = bttv_s_std,
-+	.vidioc_enum_input              = bttv_enum_input,
-+	.vidioc_g_input                 = bttv_g_input,
-+	.vidioc_s_input                 = bttv_s_input,
-+	.vidioc_queryctrl               = bttv_queryctrl,
-+	.vidioc_g_ctrl                  = bttv_g_ctrl,
-+	.vidioc_s_ctrl                  = bttv_s_ctrl,
-+	.vidioc_streamon                = bttv_streamon,
-+	.vidioc_streamoff               = bttv_streamoff,
-+	.vidioc_g_tuner                 = bttv_g_tuner,
-+	.vidioc_s_tuner                 = bttv_s_tuner,
-+#ifdef CONFIG_VIDEO_V4L1_COMPAT
-+	.vidiocgmbuf                    = vidiocgmbuf,
-+#endif
-+	.vidioc_g_crop                  = bttv_g_crop,
-+	.vidioc_g_crop                  = bttv_g_crop,
-+	.vidioc_s_crop                  = bttv_s_crop,
-+	.vidioc_g_fbuf                  = bttv_g_fbuf,
-+	.vidioc_s_fbuf                  = bttv_s_fbuf,
-+	.vidioc_overlay                 = bttv_overlay,
-+	.vidioc_g_priority              = bttv_g_priority,
-+	.vidioc_s_priority              = bttv_s_priority,
-+	.vidioc_g_parm                  = bttv_g_parm,
-+	.vidioc_g_frequency             = bttv_g_frequency,
-+	.vidioc_s_frequency             = bttv_s_frequency,
-+	.vidioc_log_status		= bttv_log_status,
-+	.vidioc_querystd		= bttv_querystd,
-+#ifdef CONFIG_VIDEO_ADV_DEBUG
-+	.vidioc_g_register		= bttv_g_register,
-+	.vidioc_s_register		= bttv_s_register,
-+#endif
-+	.tvnorms                        = BTTV_NORMS,
-+	.current_norm                   = V4L2_STD_PAL,
- };
- 
- /* ----------------------------------------------------------------------- */
-@@ -3918,7 +3446,7 @@ static int radio_open(struct inode *inode, struct file *file)
- 
- static int radio_release(struct inode *inode, struct file *file)
- {
--	struct bttv        *btv = file->private_data;
-+	struct bttv *btv = file->private_data;
- 	struct rds_command cmd;
- 
- 	btv->radio_user--;
-@@ -3928,59 +3456,116 @@ static int radio_release(struct inode *inode, struct file *file)
- 	return 0;
- }
- 
--static int radio_do_ioctl(struct inode *inode, struct file *file,
--			  unsigned int cmd, void *arg)
-+static int radio_querycap(struct file *file, void *priv,
-+					struct v4l2_capability *cap)
- {
--	struct bttv    *btv = file->private_data;
-+	struct bttv_fh *fh = priv;
-+	struct bttv *btv = fh->btv;
- 
--	switch (cmd) {
--	case VIDIOCGCAP:
--	{
--		struct video_capability *cap = arg;
-+	strcpy(cap->driver, "bttv");
-+	strlcpy(cap->card, btv->radio_dev->name, sizeof(cap->card));
-+	sprintf(cap->bus_info, "PCI:%s", pci_name(btv->c.pci));
-+	cap->version = BTTV_VERSION_CODE;
-+	cap->capabilities = V4L2_CAP_TUNER;
- 
--		memset(cap,0,sizeof(*cap));
--		strcpy(cap->name,btv->radio_dev->name);
--		cap->type = VID_TYPE_TUNER;
--		cap->channels = 1;
--		cap->audios = 1;
--		return 0;
--	}
-+	return 0;
-+}
- 
--	case VIDIOCGTUNER:
--	{
--		struct video_tuner *v = arg;
-+static int radio_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
-+{
-+	struct bttv_fh *fh = priv;
-+	struct bttv *btv = fh->btv;
- 
--		if(v->tuner)
--			return -EINVAL;
--		memset(v,0,sizeof(*v));
--		strcpy(v->name, "Radio");
--		bttv_call_i2c_clients(btv,cmd,v);
--		return 0;
--	}
--	case VIDIOCSTUNER:
--		/* nothing to do */
--		return 0;
-+	if (UNSET == bttv_tvcards[btv->c.type].tuner)
-+		return -EINVAL;
-+	if (0 != t->index)
++	fmt = format_by_fourcc(f->fmt.pix.pixelformat);
++	if (NULL == fmt)
 +		return -EINVAL;
-+	mutex_lock(&btv->lock);
-+	memset(t, 0, sizeof(*t));
-+	strcpy(t->name, "Radio");
-+	t->type = V4L2_TUNER_RADIO;
- 
--	case BTTV_VERSION:
--	case VIDIOCGFREQ:
--	case VIDIOCSFREQ:
--	case VIDIOCGAUDIO:
--	case VIDIOCSAUDIO:
--	case VIDIOC_LOG_STATUS:
--	case VIDIOC_DBG_G_REGISTER:
--	case VIDIOC_DBG_S_REGISTER:
--		return bttv_common_ioctls(btv,cmd,arg);
-+	bttv_call_i2c_clients(btv, VIDIOC_G_TUNER, t);
 +
-+	if (btv->audio_mode_gpio)
-+		btv->audio_mode_gpio(btv, t, 0);
++	field = f->fmt.pix.field;
++	maxw  = norm_maxw(dev->tvnorm);
++	maxh  = norm_maxh(dev->tvnorm);
 +
-+	mutex_unlock(&btv->lock);
++	if (V4L2_FIELD_ANY == field) {
++		field = (f->fmt.pix.height > maxh/2)
++			? V4L2_FIELD_INTERLACED
++			: V4L2_FIELD_BOTTOM;
++	}
++
++	switch (field) {
++	case V4L2_FIELD_TOP:
++	case V4L2_FIELD_BOTTOM:
++		maxh = maxh / 2;
++		break;
++	case V4L2_FIELD_INTERLACED:
++		break;
++	default:
++		return -EINVAL;
++	}
++
++	f->fmt.pix.field = field;
++	if (f->fmt.pix.height < 32)
++		f->fmt.pix.height = 32;
++	if (f->fmt.pix.height > maxh)
++		f->fmt.pix.height = maxh;
++	if (f->fmt.pix.width < 48)
++		f->fmt.pix.width = 48;
++	if (f->fmt.pix.width > maxw)
++		f->fmt.pix.width = maxw;
++	f->fmt.pix.width &= ~0x03;
++	f->fmt.pix.bytesperline =
++		(f->fmt.pix.width * fmt->depth) >> 3;
++	f->fmt.pix.sizeimage =
++		f->fmt.pix.height * f->fmt.pix.bytesperline;
 +
 +	return 0;
 +}
 +
-+static int radio_enum_input(struct file *file, void *priv,
-+				struct v4l2_input *i)
++static int vidioc_s_fmt_cap(struct file *file, void *priv,
++	struct v4l2_format *f)
 +{
-+	if (i->index != 0)
-+		return -EINVAL;
++	struct cx23885_fh *fh = priv;
++	struct cx23885_dev *dev  = ((struct cx23885_fh *)priv)->dev;
++	int err;
 +
-+	strcpy(i->name, "Radio");
-+	 i->type = V4L2_INPUT_TYPE_TUNER;
++	dprintk(2, "%s()\n", __FUNCTION__);
++	err = vidioc_try_fmt_cap(file, priv, f);
 +
++	if (0 != err)
++		return err;
++	fh->fmt        = format_by_fourcc(f->fmt.pix.pixelformat);
++	fh->width      = f->fmt.pix.width;
++	fh->height     = f->fmt.pix.height;
++	fh->vidq.field = f->fmt.pix.field;
++	dprintk(2, "%s() width=%d height=%d field=%d\n", __FUNCTION__,
++		fh->width, fh->height, fh->vidq.field);
++	cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_S_FMT, f);
 +	return 0;
 +}
 +
-+static int radio_g_audio(struct file *file, void *priv,
-+					struct v4l2_audio *a)
++static int vidioc_querycap(struct file *file, void  *priv,
++	struct v4l2_capability *cap)
 +{
-+	memset(a, 0, sizeof(*a));
-+	strcpy(a->name, "Radio");
++	struct cx23885_dev *dev  = ((struct cx23885_fh *)priv)->dev;
++
++	strcpy(cap->driver, "cx23885");
++	strlcpy(cap->card, cx23885_boards[dev->board].name,
++		sizeof(cap->card));
++	sprintf(cap->bus_info, "PCIe:%s", pci_name(dev->pci));
++	cap->version = CX23885_VERSION_CODE;
++	cap->capabilities =
++		V4L2_CAP_VIDEO_CAPTURE |
++		V4L2_CAP_READWRITE     |
++		V4L2_CAP_STREAMING     |
++		V4L2_CAP_VBI_CAPTURE;
++	if (UNSET != dev->tuner_type)
++		cap->capabilities |= V4L2_CAP_TUNER;
 +	return 0;
 +}
 +
-+static int radio_s_tuner(struct file *file, void *priv,
-+					struct v4l2_tuner *t)
++static int vidioc_enum_fmt_cap(struct file *file, void  *priv,
++	struct v4l2_fmtdesc *f)
 +{
-+	struct bttv_fh *fh = priv;
-+	struct bttv *btv = fh->btv;
-+
-+	if (0 != t->index)
++	if (unlikely(f->index >= ARRAY_SIZE(formats)))
 +		return -EINVAL;
 +
-+	bttv_call_i2c_clients(btv, VIDIOC_G_TUNER, t);
++	strlcpy(f->description, formats[f->index].name,
++		sizeof(f->description));
++	f->pixelformat = formats[f->index].fourcc;
++
 +	return 0;
 +}
 +
-+static int radio_s_audio(struct file *file, void *priv,
-+					struct v4l2_audio *a)
++#ifdef CONFIG_VIDEO_V4L1_COMPAT
++static int vidiocgmbuf(struct file *file, void *priv,
++	struct video_mbuf *mbuf)
 +{
++	struct cx23885_fh *fh = priv;
++	struct videobuf_queue *q;
++	struct v4l2_requestbuffers req;
++	unsigned int i;
++	int err;
++
++	q = get_queue(fh);
++	memset(&req, 0, sizeof(req));
++	req.type   = q->type;
++	req.count  = 8;
++	req.memory = V4L2_MEMORY_MMAP;
++	err = videobuf_reqbufs(q, &req);
++	if (err < 0)
++		return err;
++
++	mbuf->frames = req.count;
++	mbuf->size   = 0;
++	for (i = 0; i < mbuf->frames; i++) {
++		mbuf->offsets[i]  = q->bufs[i]->boff;
++		mbuf->size       += q->bufs[i]->bsize;
++	}
 +	return 0;
 +}
++#endif
 +
-+static int radio_s_input(struct file *filp, void *priv, unsigned int i)
++static int vidioc_reqbufs(struct file *file, void *priv,
++	struct v4l2_requestbuffers *p)
 +{
-+	return 0;
++	struct cx23885_fh *fh = priv;
++	return (videobuf_reqbufs(get_queue(fh), p));
 +}
 +
-+static int radio_s_std(struct file *file, void *fh, v4l2_std_id *norm)
++static int vidioc_querybuf(struct file *file, void *priv,
++	struct v4l2_buffer *p)
 +{
-+	return 0;
++	struct cx23885_fh *fh = priv;
++	return (videobuf_querybuf(get_queue(fh), p));
 +}
 +
-+static int radio_queryctrl(struct file *file, void *priv,
-+					struct v4l2_queryctrl *c)
++static int vidioc_qbuf(struct file *file, void *priv,
++	struct v4l2_buffer *p)
 +{
-+	const struct v4l2_queryctrl *ctrl;
++	struct cx23885_fh *fh = priv;
++	return (videobuf_qbuf(get_queue(fh), p));
++}
 +
-+	if (c->id <  V4L2_CID_BASE ||
-+			c->id >= V4L2_CID_LASTP1)
-+		return -EINVAL;
++static int vidioc_dqbuf(struct file *file, void *priv,
++	struct v4l2_buffer *p)
++{
++	struct cx23885_fh *fh = priv;
++	return (videobuf_dqbuf(get_queue(fh), p,
++				file->f_flags & O_NONBLOCK));
++}
 +
-+	if (c->id == V4L2_CID_AUDIO_MUTE) {
-+		ctrl = ctrl_by_id(c->id);
-+		*c = *ctrl;
-+	} else
-+		*c = no_ctl;
- 
--	default:
--		return -ENOIOCTLCMD;
--	}
- 	return 0;
- }
- 
--static int radio_ioctl(struct inode *inode, struct file *file,
--		       unsigned int cmd, unsigned long arg)
-+static int radio_g_input(struct file *filp, void *priv, unsigned int *i)
- {
--	return video_usercopy(inode, file, cmd, arg, radio_do_ioctl);
-+	*i = 0;
-+	return 0;
- }
- 
- static ssize_t radio_read(struct file *file, char __user *data,
-@@ -4016,17 +3601,29 @@ static const struct file_operations radio_fops =
- 	.open	  = radio_open,
- 	.read     = radio_read,
- 	.release  = radio_release,
--	.ioctl	  = radio_ioctl,
-+	.ioctl	  = video_ioctl2,
- 	.llseek	  = no_llseek,
- 	.poll     = radio_poll,
- };
- 
- static struct video_device radio_template =
- {
--	.name     = "bt848/878 radio",
--	.type     = VID_TYPE_TUNER,
- 	.fops     = &radio_fops,
- 	.minor    = -1,
-+	.vidioc_querycap        = radio_querycap,
-+	.vidioc_g_tuner         = radio_g_tuner,
-+	.vidioc_enum_input      = radio_enum_input,
-+	.vidioc_g_audio         = radio_g_audio,
-+	.vidioc_s_tuner         = radio_s_tuner,
-+	.vidioc_s_audio         = radio_s_audio,
-+	.vidioc_s_input         = radio_s_input,
-+	.vidioc_s_std           = radio_s_std,
-+	.vidioc_queryctrl       = radio_queryctrl,
-+	.vidioc_g_input         = radio_g_input,
-+	.vidioc_g_ctrl          = bttv_g_ctrl,
-+	.vidioc_s_ctrl          = bttv_s_ctrl,
-+	.vidioc_g_frequency     = bttv_g_frequency,
-+	.vidioc_s_frequency     = bttv_s_frequency,
- };
- 
- /* ----------------------------------------------------------------------- */
-@@ -4308,20 +3905,20 @@ static void bttv_irq_timeout(unsigned long data)
- 	bttv_set_dma(btv, 0);
- 
- 	/* wake up */
--	bttv_irq_wakeup_video(btv, &old, &new, STATE_ERROR);
--	bttv_irq_wakeup_vbi(btv, ovbi, STATE_ERROR);
-+	bttv_irq_wakeup_video(btv, &old, &new, VIDEOBUF_ERROR);
-+	bttv_irq_wakeup_vbi(btv, ovbi, VIDEOBUF_ERROR);
- 
- 	/* cancel all outstanding capture / vbi requests */
- 	while (!list_empty(&btv->capture)) {
- 		item = list_entry(btv->capture.next, struct bttv_buffer, vb.queue);
- 		list_del(&item->vb.queue);
--		item->vb.state = STATE_ERROR;
-+		item->vb.state = VIDEOBUF_ERROR;
- 		wake_up(&item->vb.done);
- 	}
- 	while (!list_empty(&btv->vcapture)) {
- 		item = list_entry(btv->vcapture.next, struct bttv_buffer, vb.queue);
- 		list_del(&item->vb.queue);
--		item->vb.state = STATE_ERROR;
-+		item->vb.state = VIDEOBUF_ERROR;
- 		wake_up(&item->vb.done);
- 	}
- 
-@@ -4344,7 +3941,7 @@ bttv_irq_wakeup_top(struct bttv *btv)
- 
- 	do_gettimeofday(&wakeup->vb.ts);
- 	wakeup->vb.field_count = btv->field_count;
--	wakeup->vb.state = STATE_DONE;
-+	wakeup->vb.state = VIDEOBUF_DONE;
- 	wake_up(&wakeup->vb.done);
- 	spin_unlock(&btv->s_lock);
- }
-@@ -4393,7 +3990,7 @@ bttv_irq_switch_video(struct bttv *btv)
- 	}
- 
- 	/* wake up finished buffers */
--	bttv_irq_wakeup_video(btv, &old, &new, STATE_DONE);
-+	bttv_irq_wakeup_video(btv, &old, &new, VIDEOBUF_DONE);
- 	spin_unlock(&btv->s_lock);
- }
- 
-@@ -4426,7 +4023,7 @@ bttv_irq_switch_vbi(struct bttv *btv)
- 	bttv_buffer_activate_vbi(btv, new);
- 	bttv_set_dma(btv, 0);
- 
--	bttv_irq_wakeup_vbi(btv, old, STATE_DONE);
-+	bttv_irq_wakeup_vbi(btv, old, VIDEOBUF_DONE);
- 	spin_unlock(&btv->s_lock);
- }
- 
-@@ -4548,8 +4145,9 @@ static irqreturn_t bttv_irq(int irq, void *dev_id)
- /* initialitation                                                          */
- 
- static struct video_device *vdev_init(struct bttv *btv,
--				      struct video_device *template,
--				      char *type)
-+				      const struct video_device *template,
-+				      const char *type_name,
-+				      const int type)
- {
- 	struct video_device *vfd;
- 
-@@ -4560,9 +4158,10 @@ static struct video_device *vdev_init(struct bttv *btv,
- 	vfd->minor   = -1;
- 	vfd->dev     = &btv->c.pci->dev;
- 	vfd->release = video_device_release;
-+	vfd->type    = type;
- 	snprintf(vfd->name, sizeof(vfd->name), "BT%d%s %s (%s)",
- 		 btv->id, (btv->id==848 && btv->revision==0x12) ? "A" : "",
--		 type, bttv_tvcards[btv->c.type].name);
-+		 type_name, bttv_tvcards[btv->c.type].name);
- 	return vfd;
- }
- 
-@@ -4594,6 +4193,11 @@ static void bttv_unregister_video(struct bttv *btv)
- /* register video4linux devices */
- static int __devinit bttv_register_video(struct bttv *btv)
- {
-+	int video_type = VID_TYPE_CAPTURE |
-+			 VID_TYPE_TUNER   |
-+			 VID_TYPE_CLIPPING|
-+			 VID_TYPE_SCALES;
++static int vidioc_streamon(struct file *file, void *priv,
++	enum v4l2_buf_type i)
++{
++	struct cx23885_fh *fh = priv;
++	struct cx23885_dev *dev = fh->dev;
++	dprintk(1, "%s()\n", __FUNCTION__);
 +
- 	if (no_overlay <= 0) {
- 		bttv_video_template.type |= VID_TYPE_OVERLAY;
- 	} else {
-@@ -4601,7 +4205,9 @@ static int __devinit bttv_register_video(struct bttv *btv)
- 	}
- 
- 	/* video */
--	btv->video_dev = vdev_init(btv, &bttv_video_template, "video");
-+	btv->video_dev = vdev_init(btv, &bttv_video_template,
-+				   "video", video_type);
++	if (unlikely(fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE))
++		return -EINVAL;
++	if (unlikely(i != fh->type))
++		return -EINVAL;
 +
- 	if (NULL == btv->video_dev)
- 		goto err;
- 	if (video_register_device(btv->video_dev,VFL_TYPE_GRABBER,video_nr)<0)
-@@ -4616,7 +4222,9 @@ static int __devinit bttv_register_video(struct bttv *btv)
- 	}
- 
- 	/* vbi */
--	btv->vbi_dev = vdev_init(btv, &bttv_vbi_template, "vbi");
-+	btv->vbi_dev = vdev_init(btv, &bttv_video_template,
-+				 "vbi", VID_TYPE_TUNER | VID_TYPE_TELETEXT);
++	if (unlikely(!res_get(dev, fh, get_resource(fh))))
++		return -EBUSY;
++	return videobuf_streamon(get_queue(fh));
++}
 +
- 	if (NULL == btv->vbi_dev)
- 		goto err;
- 	if (video_register_device(btv->vbi_dev,VFL_TYPE_VBI,vbi_nr)<0)
-@@ -4627,7 +4235,8 @@ static int __devinit bttv_register_video(struct bttv *btv)
- 	if (!btv->has_radio)
- 		return 0;
- 	/* radio */
--	btv->radio_dev = vdev_init(btv, &radio_template, "radio");
-+	btv->radio_dev = vdev_init(btv, &radio_template,
-+				   "radio", VID_TYPE_TUNER);
- 	if (NULL == btv->radio_dev)
- 		goto err;
- 	if (video_register_device(btv->radio_dev, VFL_TYPE_RADIO,radio_nr)<0)
-@@ -4768,7 +4377,7 @@ static int __devinit bttv_probe(struct pci_dev *dev,
- 	btv->init.btv         = btv;
- 	btv->init.ov.w.width  = 320;
- 	btv->init.ov.w.height = 240;
--	btv->init.fmt         = format_by_palette(VIDEO_PALETTE_RGB24);
-+	btv->init.fmt         = format_by_fourcc(V4L2_PIX_FMT_BGR24);
- 	btv->init.width       = 320;
- 	btv->init.height      = 240;
- 	btv->input = 0;
-@@ -5013,14 +4622,17 @@ static int __init bttv_init_module(void)
- 		printk(KERN_WARNING "bttv: bus_register error: %d\n", ret);
- 		return ret;
- 	}
--	return pci_register_driver(&bttv_pci_driver);
-+	ret = pci_register_driver(&bttv_pci_driver);
-+	if (ret < 0)
-+		bus_unregister(&bttv_sub_bus_type);
++static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
++{
++	struct cx23885_fh *fh = priv;
++	struct cx23885_dev *dev = fh->dev;
++	int err, res;
++	dprintk(1, "%s()\n", __FUNCTION__);
 +
-+	return ret;
- }
- 
- static void __exit bttv_cleanup_module(void)
- {
- 	pci_unregister_driver(&bttv_pci_driver);
- 	bus_unregister(&bttv_sub_bus_type);
--	return;
- }
- 
- module_init(bttv_init_module);
-diff --git a/drivers/media/video/bt8xx/bttv-input.c b/drivers/media/video/bt8xx/bttv-input.c
-index e7c521b..fc9ecb2 100644
---- a/drivers/media/video/bt8xx/bttv-input.c
-+++ b/drivers/media/video/bt8xx/bttv-input.c
-@@ -69,6 +69,11 @@ static void ir_handle_key(struct bttv *btv)
- 	    (ir->mask_keyup    &&  (0 == (gpio & ir->mask_keyup)))) {
- 		ir_input_keydown(ir->dev,&ir->ir,data,data);
- 	} else {
-+		/* HACK: Probably, ir->mask_keydown is missing
-+		   for this board */
-+		if (btv->c.type == BTTV_BOARD_WINFAST2000)
-+			ir_input_keydown(ir->dev, &ir->ir, data, data);
++	if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
++		return -EINVAL;
++	if (i != fh->type)
++		return -EINVAL;
 +
- 		ir_input_nokey(ir->dev,&ir->ir);
- 	}
- 
-diff --git a/drivers/media/video/bt8xx/bttv-risc.c b/drivers/media/video/bt8xx/bttv-risc.c
-index 58986f1..e5979f7 100644
---- a/drivers/media/video/bt8xx/bttv-risc.c
-+++ b/drivers/media/video/bt8xx/bttv-risc.c
-@@ -582,7 +582,7 @@ bttv_dma_free(struct videobuf_queue *q,struct bttv *btv, struct bttv_buffer *buf
- 	videobuf_dma_free(dma);
- 	btcx_riscmem_free(btv->c.pci,&buf->bottom);
- 	btcx_riscmem_free(btv->c.pci,&buf->top);
--	buf->vb.state = STATE_NEEDS_INIT;
-+	buf->vb.state = VIDEOBUF_NEEDS_INIT;
- }
- 
- int
-@@ -602,7 +602,7 @@ bttv_buffer_activate_vbi(struct bttv *btv,
- 	if (vbi) {
- 		unsigned int crop, vdelay;
- 
--		vbi->vb.state = STATE_ACTIVE;
-+		vbi->vb.state = VIDEOBUF_ACTIVE;
- 		list_del(&vbi->vb.queue);
- 
- 		/* VDELAY is start of video, end of VBI capturing. */
-@@ -644,12 +644,12 @@ bttv_buffer_activate_video(struct bttv *btv,
- 	/* video capture */
- 	if (NULL != set->top  &&  NULL != set->bottom) {
- 		if (set->top == set->bottom) {
--			set->top->vb.state    = STATE_ACTIVE;
-+			set->top->vb.state    = VIDEOBUF_ACTIVE;
- 			if (set->top->vb.queue.next)
- 				list_del(&set->top->vb.queue);
- 		} else {
--			set->top->vb.state    = STATE_ACTIVE;
--			set->bottom->vb.state = STATE_ACTIVE;
-+			set->top->vb.state    = VIDEOBUF_ACTIVE;
-+			set->bottom->vb.state = VIDEOBUF_ACTIVE;
- 			if (set->top->vb.queue.next)
- 				list_del(&set->top->vb.queue);
- 			if (set->bottom->vb.queue.next)
-@@ -666,7 +666,7 @@ bttv_buffer_activate_video(struct bttv *btv,
- 		btaor((set->top->btswap & 0x0a) | (set->bottom->btswap & 0x05),
- 		      ~0x0f, BT848_COLOR_CTL);
- 	} else if (NULL != set->top) {
--		set->top->vb.state  = STATE_ACTIVE;
-+		set->top->vb.state  = VIDEOBUF_ACTIVE;
- 		if (set->top->vb.queue.next)
- 			list_del(&set->top->vb.queue);
- 		bttv_apply_geo(btv, &set->top->geo,1);
-@@ -677,7 +677,7 @@ bttv_buffer_activate_video(struct bttv *btv,
- 		btaor(set->top->btformat & 0xff, ~0xff, BT848_COLOR_FMT);
- 		btaor(set->top->btswap & 0x0f,   ~0x0f, BT848_COLOR_CTL);
- 	} else if (NULL != set->bottom) {
--		set->bottom->vb.state = STATE_ACTIVE;
-+		set->bottom->vb.state = VIDEOBUF_ACTIVE;
- 		if (set->bottom->vb.queue.next)
- 			list_del(&set->bottom->vb.queue);
- 		bttv_apply_geo(btv, &set->bottom->geo,1);
-diff --git a/drivers/media/video/bt8xx/bttv-vbi.c b/drivers/media/video/bt8xx/bttv-vbi.c
-index 346ce01..1f0cc79 100644
---- a/drivers/media/video/bt8xx/bttv-vbi.c
-+++ b/drivers/media/video/bt8xx/bttv-vbi.c
-@@ -142,7 +142,7 @@ static int vbi_buffer_prepare(struct videobuf_queue *q,
- 		redo_dma_risc = 1;
- 	}
- 
--	if (STATE_NEEDS_INIT == buf->vb.state) {
-+	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
- 		redo_dma_risc = 1;
- 		if (0 != (rc = videobuf_iolock(q, &buf->vb, NULL)))
- 			goto fail;
-@@ -189,7 +189,7 @@ static int vbi_buffer_prepare(struct videobuf_queue *q,
- 	/* For bttv_buffer_activate_vbi(). */
- 	buf->geo.vdelay = min_vdelay;
- 
--	buf->vb.state = STATE_PREPARED;
-+	buf->vb.state = VIDEOBUF_PREPARED;
- 	buf->vb.field = field;
- 	dprintk("buf prepare %p: top=%p bottom=%p field=%s\n",
- 		vb, &buf->top, &buf->bottom,
-@@ -209,7 +209,7 @@ vbi_buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
- 	struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb);
- 
- 	dprintk("queue %p\n",vb);
--	buf->vb.state = STATE_QUEUED;
-+	buf->vb.state = VIDEOBUF_QUEUED;
- 	list_add_tail(&buf->vb.queue,&btv->vcapture);
- 	if (NULL == btv->cvbi) {
- 		fh->btv->loop_irq |= 4;
-@@ -236,10 +236,8 @@ struct videobuf_queue_ops bttv_vbi_qops = {
- 
- /* ----------------------------------------------------------------------- */
- 
--static int
--try_fmt			(struct v4l2_vbi_format *	f,
--			 const struct bttv_tvnorm *	tvnorm,
--			 __s32				crop_start)
-+static int try_fmt(struct v4l2_vbi_format *f, const struct bttv_tvnorm *tvnorm,
-+			__s32 crop_start)
- {
- 	__s32 min_start, max_start, max_end, f2_offset;
- 	unsigned int i;
-@@ -305,10 +303,9 @@ try_fmt			(struct v4l2_vbi_format *	f,
- 	return 0;
- }
- 
--int
--bttv_vbi_try_fmt	(struct bttv_fh *		fh,
--			 struct v4l2_vbi_format *	f)
-+int bttv_try_fmt_vbi(struct file *file, void *f, struct v4l2_format *frt)
- {
-+	struct bttv_fh *fh = f;
- 	struct bttv *btv = fh->btv;
- 	const struct bttv_tvnorm *tvnorm;
- 	__s32 crop_start;
-@@ -320,13 +317,13 @@ bttv_vbi_try_fmt	(struct bttv_fh *		fh,
- 
- 	mutex_unlock(&btv->lock);
- 
--	return try_fmt(f, tvnorm, crop_start);
-+	return try_fmt(&frt->fmt.vbi, tvnorm, crop_start);
- }
- 
--int
--bttv_vbi_set_fmt	(struct bttv_fh *		fh,
--			 struct v4l2_vbi_format *	f)
++	res = get_resource(fh);
++	err = videobuf_streamoff(get_queue(fh));
++	if (err < 0)
++		return err;
++	res_free(dev, fh, res);
++	return 0;
++}
 +
-+int bttv_s_fmt_vbi(struct file *file, void *f, struct v4l2_format *frt)
- {
-+	struct bttv_fh *fh = f;
- 	struct bttv *btv = fh->btv;
- 	const struct bttv_tvnorm *tvnorm;
- 	__s32 start1, end;
-@@ -340,11 +337,12 @@ bttv_vbi_set_fmt	(struct bttv_fh *		fh,
- 
- 	tvnorm = &bttv_tvnorms[btv->tvnorm];
- 
--	rc = try_fmt(f, tvnorm, btv->crop_start);
-+	rc = try_fmt(&frt->fmt.vbi, tvnorm, btv->crop_start);
- 	if (0 != rc)
- 		goto fail;
- 
--	start1 = f->start[1] - tvnorm->vbistart[1] + tvnorm->vbistart[0];
-+	start1 = frt->fmt.vbi.start[1] - tvnorm->vbistart[1] +
-+		tvnorm->vbistart[0];
- 
- 	/* First possible line of video capturing. Should be
- 	   max(f->start[0] + f->count[0], start1 + f->count[1]) * 2
-@@ -352,11 +350,11 @@ bttv_vbi_set_fmt	(struct bttv_fh *		fh,
- 	   pretend the VBI and video capture window may overlap,
- 	   so end = start + 1, the lowest possible value, times two
- 	   because vbi_fmt.end counts field lines times two. */
--	end = max(f->start[0], start1) * 2 + 2;
-+	end = max(frt->fmt.vbi.start[0], start1) * 2 + 2;
- 
- 	mutex_lock(&fh->vbi.lock);
- 
--	fh->vbi_fmt.fmt    = *f;
-+	fh->vbi_fmt.fmt    = frt->fmt.vbi;
- 	fh->vbi_fmt.tvnorm = tvnorm;
- 	fh->vbi_fmt.end    = end;
- 
-@@ -370,13 +368,13 @@ bttv_vbi_set_fmt	(struct bttv_fh *		fh,
- 	return rc;
- }
- 
--void
--bttv_vbi_get_fmt	(struct bttv_fh *		fh,
--			 struct v4l2_vbi_format *	f)
++static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *tvnorms)
++{
++	struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
++	dprintk(1, "%s()\n", __FUNCTION__);
++
++	mutex_lock(&dev->lock);
++	cx23885_set_tvnorm(dev, *tvnorms);
++	mutex_unlock(&dev->lock);
 +
-+int bttv_g_fmt_vbi(struct file *file, void *f, struct v4l2_format *frt)
- {
-+	struct bttv_fh *fh = f;
- 	const struct bttv_tvnorm *tvnorm;
- 
--	*f = fh->vbi_fmt.fmt;
-+	frt->fmt.vbi = fh->vbi_fmt.fmt;
- 
- 	tvnorm = &bttv_tvnorms[fh->btv->tvnorm];
- 
-@@ -391,28 +389,28 @@ bttv_vbi_get_fmt	(struct bttv_fh *		fh,
- 		max_end = (tvnorm->cropcap.bounds.top
- 			   + tvnorm->cropcap.bounds.height) >> 1;
- 
--		f->sampling_rate = tvnorm->Fsc;
-+		frt->fmt.vbi.sampling_rate = tvnorm->Fsc;
- 
- 		for (i = 0; i < 2; ++i) {
- 			__s32 new_start;
- 
--			new_start = f->start[i]
-+			new_start = frt->fmt.vbi.start[i]
- 				+ tvnorm->vbistart[i]
- 				- fh->vbi_fmt.tvnorm->vbistart[i];
- 
--			f->start[i] = min(new_start, max_end - 1);
--			f->count[i] = min((__s32) f->count[i],
--					  max_end - f->start[i]);
-+			frt->fmt.vbi.start[i] = min(new_start, max_end - 1);
-+			frt->fmt.vbi.count[i] =
-+				min((__s32) frt->fmt.vbi.count[i],
-+					  max_end - frt->fmt.vbi.start[i]);
- 
- 			max_end += tvnorm->vbistart[1]
- 				- tvnorm->vbistart[0];
- 		}
- 	}
 +	return 0;
- }
- 
--void
--bttv_vbi_fmt_reset	(struct bttv_vbi_fmt *		f,
--			 int				norm)
-+void bttv_vbi_fmt_reset(struct bttv_vbi_fmt *f, int norm)
- {
- 	const struct bttv_tvnorm *tvnorm;
- 	unsigned int real_samples_per_line;
-diff --git a/drivers/media/video/bt8xx/bttv.h b/drivers/media/video/bt8xx/bttv.h
-index 19e75d5..bf4c339 100644
---- a/drivers/media/video/bt8xx/bttv.h
-+++ b/drivers/media/video/bt8xx/bttv.h
-@@ -241,7 +241,10 @@ struct tvcard
- 	unsigned int radio_addr;
- 
- 	unsigned int has_radio;
--	void (*audio_hook)(struct bttv *btv, struct video_audio *v, int set);
++}
 +
-+	void (*volume_gpio)(struct bttv *btv, __u16 volume);
-+	void (*audio_mode_gpio)(struct bttv *btv, struct v4l2_tuner *tuner, int set);
++int cx23885_enum_input(struct cx23885_dev *dev, struct v4l2_input *i)
++{
++	static const char *iname[] = {
++		[CX23885_VMUX_COMPOSITE1] = "Composite1",
++		[CX23885_VMUX_COMPOSITE2] = "Composite2",
++		[CX23885_VMUX_COMPOSITE3] = "Composite3",
++		[CX23885_VMUX_COMPOSITE4] = "Composite4",
++		[CX23885_VMUX_SVIDEO]     = "S-Video",
++		[CX23885_VMUX_TELEVISION] = "Television",
++		[CX23885_VMUX_CABLE]      = "Cable TV",
++		[CX23885_VMUX_DVB]        = "DVB",
++		[CX23885_VMUX_DEBUG]      = "for debug only",
++	};
++	unsigned int n;
++	dprintk(1, "%s()\n", __FUNCTION__);
 +
- 	void (*muxsel_hook)(struct bttv *btv, unsigned int input);
- };
- 
-diff --git a/drivers/media/video/bt8xx/bttvp.h b/drivers/media/video/bt8xx/bttvp.h
-index d4ac4c4..1305d31 100644
---- a/drivers/media/video/bt8xx/bttvp.h
-+++ b/drivers/media/video/bt8xx/bttvp.h
-@@ -84,6 +84,11 @@
- 
- #define clamp(x, low, high) min (max (low, x), high)
- 
-+#define BTTV_NORMS    (\
-+		V4L2_STD_PAL    | V4L2_STD_PAL_N | \
-+		V4L2_STD_PAL_Nc | V4L2_STD_SECAM | \
-+		V4L2_STD_NTSC   | V4L2_STD_PAL_M | \
-+		V4L2_STD_PAL_60)
- /* ---------------------------------------------------------- */
- 
- struct bttv_tvnorm {
-@@ -112,7 +117,6 @@ extern const struct bttv_tvnorm bttv_tvnorms[];
- 
- struct bttv_format {
- 	char *name;
--	int  palette;         /* video4linux 1      */
- 	int  fourcc;          /* video4linux 2      */
- 	int  btformat;        /* BT848_COLOR_FMT_*  */
- 	int  btswap;          /* BT848_COLOR_CTL_*  */
-@@ -253,9 +257,9 @@ int bttv_overlay_risc(struct bttv *btv, struct bttv_overlay *ov,
- /* ---------------------------------------------------------- */
- /* bttv-vbi.c                                                 */
- 
--int bttv_vbi_try_fmt(struct bttv_fh *fh, struct v4l2_vbi_format *f);
--void bttv_vbi_get_fmt(struct bttv_fh *fh, struct v4l2_vbi_format *f);
--int bttv_vbi_set_fmt(struct bttv_fh *fh, struct v4l2_vbi_format *f);
-+int bttv_try_fmt_vbi(struct file *file, void *fh, struct v4l2_format *f);
-+int bttv_g_fmt_vbi(struct file *file, void *fh, struct v4l2_format *f);
-+int bttv_s_fmt_vbi(struct file *file, void *fh, struct v4l2_format *f);
- 
- extern struct videobuf_queue_ops bttv_vbi_qops;
- 
-@@ -337,7 +341,9 @@ struct bttv {
- 	/* old gpio interface */
- 	wait_queue_head_t gpioq;
- 	int shutdown;
--	void (*audio_hook)(struct bttv *btv, struct video_audio *v, int set);
++	n = i->index;
++	if (n >= 4)
++		return -EINVAL;
 +
-+	void (*volume_gpio)(struct bttv *btv, __u16 volume);
-+	void (*audio_mode_gpio)(struct bttv *btv, struct v4l2_tuner *tuner, int set);
- 
- 	/* new gpio interface */
- 	spinlock_t gpio_lock;
-@@ -458,10 +464,6 @@ struct bttv {
- extern unsigned int bttv_num;
- extern struct bttv bttvs[BTTV_MAX];
- 
--/* private ioctls */
--#define BTTV_VERSION            _IOR('v' , BASE_VIDIOCPRIVATE+6, int)
--#define BTTV_VBISIZE            _IOR('v' , BASE_VIDIOCPRIVATE+8, int)
--
- #endif
- 
- #define btwrite(dat,adr)    writel((dat), btv->bt848_mmio+(adr))
-diff --git a/drivers/media/video/bw-qcam.c b/drivers/media/video/bw-qcam.c
-index 5842352..0322653 100644
---- a/drivers/media/video/bw-qcam.c
-+++ b/drivers/media/video/bw-qcam.c
-@@ -82,11 +82,16 @@ OTHER DEALINGS IN THE SOFTWARE.
- static unsigned int maxpoll=250;   /* Maximum busy-loop count for qcam I/O */
- static unsigned int yieldlines=4;  /* Yield after this many during capture */
- static int video_nr = -1;
-+static unsigned int force_init;		/* Whether to probe aggressively */
- 
- module_param(maxpoll, int, 0);
- module_param(yieldlines, int, 0);
- module_param(video_nr, int, 0);
- 
-+/* Set force_init=1 to avoid detection by polling status register and
-+ * immediately attempt to initialize qcam */
-+module_param(force_init, int, 0);
++	if (0 == INPUT(n)->type)
++		return -EINVAL;
 +
- static inline int read_lpstatus(struct qcam_device *q)
- {
- 	return parport_read_status(q->pport);
-@@ -331,6 +336,9 @@ static int qc_detect(struct qcam_device *q)
- 	int count = 0;
- 	int i;
- 
-+	if (force_init)
-+		return 1;
++	memset(i, 0, sizeof(*i));
++	i->index = n;
++	i->type  = V4L2_INPUT_TYPE_CAMERA;
++	strcpy(i->name, iname[INPUT(n)->type]);
++	if ((CX23885_VMUX_TELEVISION == INPUT(n)->type) ||
++		(CX23885_VMUX_CABLE == INPUT(n)->type))
++		i->type = V4L2_INPUT_TYPE_TUNER;
++		i->std = CX23885_NORMS;
++	return 0;
++}
++EXPORT_SYMBOL(cx23885_enum_input);
 +
- 	lastreg = reg = read_lpstatus(q) & 0xf0;
- 
- 	for (i = 0; i < 500; i++)
-@@ -354,12 +362,12 @@ static int qc_detect(struct qcam_device *q)
- 
- 	/* Be (even more) liberal in what you accept...  */
- 
--/*	if (count > 30 && count < 200) */
- 	if (count > 20 && count < 400) {
- 		return 1;	/* found */
- 	} else {
- 		printk(KERN_ERR "No Quickcam found on port %s\n",
- 			q->pport->name);
-+		printk(KERN_DEBUG "Quickcam detection counter: %u\n", count);
- 		return 0;	/* not found */
- 	}
- }
-diff --git a/drivers/media/video/cs5345.c b/drivers/media/video/cs5345.c
-new file mode 100644
-index 0000000..fae469c
---- /dev/null
-+++ b/drivers/media/video/cs5345.c
-@@ -0,0 +1,168 @@
-+/*
-+ * cs5345 Cirrus Logic 24-bit, 192 kHz Stereo Audio ADC
-+ * Copyright (C) 2007 Hans Verkuil
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+ * GNU General Public License for more details.
-+ *
-+ * You 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.
-+ */
++static int vidioc_enum_input(struct file *file, void *priv,
++				struct v4l2_input *i)
++{
++	struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
++	dprintk(1, "%s()\n", __FUNCTION__);
++	return cx23885_enum_input(dev, i);
++}
 +
++static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
++{
++	struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
 +
-+#include <linux/version.h>
-+#include <linux/module.h>
-+#include <linux/kernel.h>
-+#include <linux/i2c.h>
-+#include <linux/videodev2.h>
-+#include <media/v4l2-i2c-drv.h>
-+#include <media/v4l2-common.h>
-+#include <media/v4l2-chip-ident.h>
++	*i = dev->input;
++	dprintk(1, "%s() returns %d\n", __FUNCTION__, *i);
++	return 0;
++}
 +
-+MODULE_DESCRIPTION("i2c device driver for cs5345 Audio ADC");
-+MODULE_AUTHOR("Hans Verkuil");
-+MODULE_LICENSE("GPL");
++static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
++{
++	struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
 +
-+static int debug;
++	dprintk(1, "%s(%d)\n", __FUNCTION__, i);
 +
-+module_param(debug, bool, 0644);
++	if (i >= 4) {
++		dprintk(1, "%s() -EINVAL\n", __FUNCTION__);
++		return -EINVAL;
++	}
 +
-+MODULE_PARM_DESC(debug, "Debugging messages\n\t\t\t0=Off (default), 1=On");
++	mutex_lock(&dev->lock);
++	cx23885_video_mux(dev, i);
++	mutex_unlock(&dev->lock);
++	return 0;
++}
 +
++static int vidioc_queryctrl(struct file *file, void *priv,
++				struct v4l2_queryctrl *qctrl)
++{
++	qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id);
++	if (unlikely(qctrl->id == 0))
++		return -EINVAL;
++	return cx23885_ctrl_query(qctrl);
++}
 +
-+/* ----------------------------------------------------------------------- */
++static int vidioc_g_ctrl(struct file *file, void *priv,
++				struct v4l2_control *ctl)
++{
++	struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
 +
-+static inline int cs5345_write(struct i2c_client *client, u8 reg, u8 value)
++	return cx23885_get_control(dev, ctl);
++}
++
++static int vidioc_s_ctrl(struct file *file, void *priv,
++				struct v4l2_control *ctl)
 +{
-+	return i2c_smbus_write_byte_data(client, reg, value);
++	struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
++
++	return cx23885_set_control(dev, ctl);
 +}
 +
-+static inline int cs5345_read(struct i2c_client *client, u8 reg)
++static int vidioc_g_tuner(struct file *file, void *priv,
++				struct v4l2_tuner *t)
 +{
-+	return i2c_smbus_read_byte_data(client, reg);
++	struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
++
++	if (unlikely(UNSET == dev->tuner_type))
++		return -EINVAL;
++	if (0 != t->index)
++		return -EINVAL;
++
++	strcpy(t->name, "Television");
++	t->type       = V4L2_TUNER_ANALOG_TV;
++	t->capability = V4L2_TUNER_CAP_NORM;
++	t->rangehigh  = 0xffffffffUL;
++	t->signal = 0xffff ; /* LOCKED */
++	return 0;
 +}
 +
-+static int cs5345_command(struct i2c_client *client, unsigned cmd, void *arg)
++static int vidioc_s_tuner(struct file *file, void *priv,
++				struct v4l2_tuner *t)
 +{
-+	struct v4l2_routing *route = arg;
-+	struct v4l2_control *ctrl = arg;
++	struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
 +
-+	switch (cmd) {
-+	case VIDIOC_INT_G_AUDIO_ROUTING:
-+		route->input = cs5345_read(client, 0x09) & 7;
-+		route->input |= cs5345_read(client, 0x05) & 0x70;
-+		route->output = 0;
-+		break;
++	if (UNSET == dev->tuner_type)
++		return -EINVAL;
++	if (0 != t->index)
++		return -EINVAL;
++	return 0;
++}
 +
-+	case VIDIOC_INT_S_AUDIO_ROUTING:
-+		if ((route->input & 0xf) > 6) {
-+			v4l_err(client, "Invalid input %d.\n", route->input);
-+			return -EINVAL;
-+		}
-+		cs5345_write(client, 0x09, route->input & 0xf);
-+		cs5345_write(client, 0x05, route->input & 0xf0);
-+		break;
++static int vidioc_g_frequency(struct file *file, void *priv,
++				struct v4l2_frequency *f)
++{
++	struct cx23885_fh *fh = priv;
++	struct cx23885_dev *dev = fh->dev;
 +
-+	case VIDIOC_G_CTRL:
-+		if (ctrl->id == V4L2_CID_AUDIO_MUTE) {
-+			ctrl->value = (cs5345_read(client, 0x04) & 0x08) != 0;
-+			break;
-+		}
-+		if (ctrl->id != V4L2_CID_AUDIO_VOLUME)
-+			return -EINVAL;
-+		ctrl->value = cs5345_read(client, 0x07) & 0x3f;
-+		if (ctrl->value >= 32)
-+			ctrl->value = ctrl->value - 64;
-+		break;
++	if (unlikely(UNSET == dev->tuner_type))
++		return -EINVAL;
 +
-+	case VIDIOC_S_CTRL:
-+		break;
-+		if (ctrl->id == V4L2_CID_AUDIO_MUTE) {
-+			cs5345_write(client, 0x04, ctrl->value ? 0x80 : 0);
-+			break;
-+		}
-+		if (ctrl->id != V4L2_CID_AUDIO_VOLUME)
-+			return -EINVAL;
-+		if (ctrl->value > 24 || ctrl->value < -24)
-+			return -EINVAL;
-+		cs5345_write(client, 0x07, ((u8)ctrl->value) & 0x3f);
-+		cs5345_write(client, 0x08, ((u8)ctrl->value) & 0x3f);
-+		break;
++	/* f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; */
++	f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
++	f->frequency = dev->freq;
++
++	cx23885_call_i2c_clients(&dev->i2c_bus[1], VIDIOC_G_FREQUENCY, f);
++
++	return 0;
++}
++
++int cx23885_set_freq(struct cx23885_dev *dev, struct v4l2_frequency *f)
++{
++	if (unlikely(UNSET == dev->tuner_type))
++		return -EINVAL;
++	if (unlikely(f->tuner != 0))
++		return -EINVAL;
++
++	mutex_lock(&dev->lock);
++	dev->freq = f->frequency;
++
++	cx23885_call_i2c_clients(&dev->i2c_bus[1], VIDIOC_S_FREQUENCY, f);
++
++	/* When changing channels it is required to reset TVAUDIO */
++	msleep(10);
++
++	mutex_unlock(&dev->lock);
++
++	return 0;
++}
++EXPORT_SYMBOL(cx23885_set_freq);
++
++static int vidioc_s_frequency(struct file *file, void *priv,
++				struct v4l2_frequency *f)
++{
++	struct cx23885_fh *fh = priv;
++	struct cx23885_dev *dev = fh->dev;
++
++	if (unlikely(0 == fh->radio && f->type != V4L2_TUNER_ANALOG_TV))
++		return -EINVAL;
++	if (unlikely(1 == fh->radio && f->type != V4L2_TUNER_RADIO))
++		return -EINVAL;
++
++	return
++		cx23885_set_freq(dev, f);
++}
 +
 +#ifdef CONFIG_VIDEO_ADV_DEBUG
-+	case VIDIOC_DBG_G_REGISTER:
-+	case VIDIOC_DBG_S_REGISTER:
-+	{
-+		struct v4l2_register *reg = arg;
++static int vidioc_g_register(struct file *file, void *fh,
++				struct v4l2_register *reg)
++{
++	struct cx23885_dev *dev = ((struct cx23885_fh *)fh)->dev;
 +
-+		if (!v4l2_chip_match_i2c_client(client,
-+					reg->match_type, reg->match_chip))
-+			return -EINVAL;
-+		if (!capable(CAP_SYS_ADMIN))
-+			return -EPERM;
-+		if (cmd == VIDIOC_DBG_G_REGISTER)
-+			reg->val = cs5345_read(client, reg->reg & 0x1f);
-+		else
-+			cs5345_write(client, reg->reg & 0x1f, reg->val & 0x1f);
-+		break;
-+	}
-+#endif
++	if (!v4l2_chip_match_host(reg->match_type, reg->match_chip))
++		return -EINVAL;
 +
-+	case VIDIOC_G_CHIP_IDENT:
-+		return v4l2_chip_ident_i2c_client(client,
-+				arg, V4L2_IDENT_CS5345, 0);
++	cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_DBG_G_REGISTER, reg);
 +
-+	case VIDIOC_LOG_STATUS:
-+		{
-+			u8 v = cs5345_read(client, 0x09) & 7;
-+			u8 m = cs5345_read(client, 0x04);
-+			int vol = cs5345_read(client, 0x08) & 0x3f;
++	return 0;
++}
 +
-+			v4l_info(client, "Input:  %d%s\n", v,
-+				      (m & 0x80) ? " (muted)" : "");
-+			if (vol >= 32)
-+				vol = vol - 64;
-+			v4l_info(client, "Volume: %d dB\n", vol);
-+			break;
-+		}
++static int vidioc_s_register(struct file *file, void *fh,
++				struct v4l2_register *reg)
++{
++	struct cx23885_dev *dev = ((struct cx23885_fh *)fh)->dev;
 +
-+	default:
++	if (!v4l2_chip_match_host(reg->match_type, reg->match_chip))
 +		return -EINVAL;
-+	}
++
++	cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_DBG_S_REGISTER, reg);
++
 +	return 0;
 +}
++#endif
 +
-+/* ----------------------------------------------------------------------- */
++/* ----------------------------------------------------------- */
 +
-+static int cs5345_probe(struct i2c_client *client)
++static void cx23885_vid_timeout(unsigned long data)
 +{
-+	/* Check if the adapter supports the needed features */
-+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
-+		return -EIO;
++	struct cx23885_dev *dev = (struct cx23885_dev *)data;
++	struct cx23885_dmaqueue *q = &dev->vidq;
++	struct cx23885_buffer *buf;
++	unsigned long flags;
 +
-+	v4l_info(client, "chip found @ 0x%x (%s)\n",
-+			client->addr << 1, client->adapter->name);
++	cx23885_sram_channel_dump(dev, &dev->sram_channels[SRAM_CH01]);
 +
-+	cs5345_write(client, 0x02, 0x00);
-+	cs5345_write(client, 0x04, 0x01);
-+	cs5345_write(client, 0x09, 0x01);
-+	return 0;
++	cx_clear(VID_A_DMA_CTL, 0x11);
++
++	spin_lock_irqsave(&dev->slock, flags);
++	while (!list_empty(&q->active)) {
++		buf = list_entry(q->active.next,
++			struct cx23885_buffer, vb.queue);
++		list_del(&buf->vb.queue);
++		buf->vb.state = VIDEOBUF_ERROR;
++		wake_up(&buf->vb.done);
++		printk(KERN_ERR "%s/0: [%p/%d] timeout - dma=0x%08lx\n",
++			dev->name, buf, buf->vb.i,
++			(unsigned long)buf->risc.dma);
++	}
++	cx23885_restart_video_queue(dev, q);
++	spin_unlock_irqrestore(&dev->slock, flags);
 +}
 +
-+/* ----------------------------------------------------------------------- */
++int cx23885_video_irq(struct cx23885_dev *dev, u32 status)
++{
++	u32 mask, count;
++	int handled = 0;
 +
-+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
-+	.name = "cs5345",
-+	.driverid = I2C_DRIVERID_CS5345,
-+	.command = cs5345_command,
-+	.probe = cs5345_probe,
++	mask   = cx_read(VID_A_INT_MSK);
++	if (0 == (status & mask))
++		return handled;
++	cx_write(VID_A_INT_STAT, status);
++
++	dprintk(2, "%s() status = 0x%08x\n", __FUNCTION__, status);
++	/* risc op code error */
++	if (status & (1 << 16)) {
++		printk(KERN_WARNING "%s/0: video risc op code error\n",
++			dev->name);
++		cx_clear(VID_A_DMA_CTL, 0x11);
++		cx23885_sram_channel_dump(dev, &dev->sram_channels[SRAM_CH01]);
++	}
++
++	/* risc1 y */
++	if (status & 0x01) {
++		spin_lock(&dev->slock);
++		count = cx_read(VID_A_GPCNT);
++		cx23885_video_wakeup(dev, &dev->vidq, count);
++		spin_unlock(&dev->slock);
++		handled++;
++	}
++	/* risc2 y */
++	if (status & 0x10) {
++		dprintk(2, "stopper video\n");
++		spin_lock(&dev->slock);
++		cx23885_restart_video_queue(dev, &dev->vidq);
++		spin_unlock(&dev->slock);
++		handled++;
++	}
++
++	return handled;
++}
++
++/* ----------------------------------------------------------- */
++/* exported stuff                                              */
++
++static const struct file_operations video_fops = {
++	.owner	       = THIS_MODULE,
++	.open	       = video_open,
++	.release       = video_release,
++	.read	       = video_read,
++	.poll          = video_poll,
++	.mmap	       = video_mmap,
++	.ioctl	       = video_ioctl2,
++	.compat_ioctl  = v4l_compat_ioctl32,
++	.llseek        = no_llseek,
 +};
 +
-diff --git a/drivers/media/video/cs53l32a.c b/drivers/media/video/cs53l32a.c
-index a73e285..f41bfde 100644
---- a/drivers/media/video/cs53l32a.c
-+++ b/drivers/media/video/cs53l32a.c
-@@ -29,12 +29,13 @@
- #include <linux/videodev.h>
- #include <media/v4l2-common.h>
- #include <media/v4l2-chip-ident.h>
-+#include <media/v4l2-i2c-drv-legacy.h>
++static struct video_device cx23885_vbi_template;
++static struct video_device cx23885_video_template = {
++	.name                 = "cx23885-video",
++	.type                 = VID_TYPE_CAPTURE|VID_TYPE_TUNER|VID_TYPE_SCALES,
++	.fops                 = &video_fops,
++	.minor                = -1,
++	.vidioc_querycap      = vidioc_querycap,
++	.vidioc_enum_fmt_cap  = vidioc_enum_fmt_cap,
++	.vidioc_g_fmt_cap     = vidioc_g_fmt_cap,
++	.vidioc_try_fmt_cap   = vidioc_try_fmt_cap,
++	.vidioc_s_fmt_cap     = vidioc_s_fmt_cap,
++	.vidioc_g_fmt_vbi     = cx23885_vbi_fmt,
++	.vidioc_try_fmt_vbi   = cx23885_vbi_fmt,
++	.vidioc_s_fmt_vbi     = cx23885_vbi_fmt,
++	.vidioc_reqbufs       = vidioc_reqbufs,
++	.vidioc_querybuf      = vidioc_querybuf,
++	.vidioc_qbuf          = vidioc_qbuf,
++	.vidioc_dqbuf         = vidioc_dqbuf,
++	.vidioc_s_std         = vidioc_s_std,
++	.vidioc_enum_input    = vidioc_enum_input,
++	.vidioc_g_input       = vidioc_g_input,
++	.vidioc_s_input       = vidioc_s_input,
++	.vidioc_queryctrl     = vidioc_queryctrl,
++	.vidioc_g_ctrl        = vidioc_g_ctrl,
++	.vidioc_s_ctrl        = vidioc_s_ctrl,
++	.vidioc_streamon      = vidioc_streamon,
++	.vidioc_streamoff     = vidioc_streamoff,
++#ifdef CONFIG_VIDEO_V4L1_COMPAT
++	.vidiocgmbuf          = vidiocgmbuf,
++#endif
++	.vidioc_g_tuner       = vidioc_g_tuner,
++	.vidioc_s_tuner       = vidioc_s_tuner,
++	.vidioc_g_frequency   = vidioc_g_frequency,
++	.vidioc_s_frequency   = vidioc_s_frequency,
++#ifdef CONFIG_VIDEO_ADV_DEBUG
++	.vidioc_g_register    = vidioc_g_register,
++	.vidioc_s_register    = vidioc_s_register,
++#endif
++	.tvnorms              = CX23885_NORMS,
++	.current_norm         = V4L2_STD_NTSC_M,
++};
++
++static const struct file_operations radio_fops = {
++	.owner         = THIS_MODULE,
++	.open          = video_open,
++	.release       = video_release,
++	.ioctl         = video_ioctl2,
++	.compat_ioctl  = v4l_compat_ioctl32,
++	.llseek        = no_llseek,
++};
++
++
++void cx23885_video_unregister(struct cx23885_dev *dev)
++{
++	dprintk(1, "%s()\n", __FUNCTION__);
++	cx_clear(PCI_INT_MSK, 1);
++
++	if (dev->video_dev) {
++		if (-1 != dev->video_dev->minor)
++			video_unregister_device(dev->video_dev);
++		else
++			video_device_release(dev->video_dev);
++		dev->video_dev = NULL;
++
++		btcx_riscmem_free(dev->pci, &dev->vidq.stopper);
++	}
++}
++
++int cx23885_video_register(struct cx23885_dev *dev)
++{
++	int err;
++
++	dprintk(1, "%s()\n", __FUNCTION__);
++	spin_lock_init(&dev->slock);
++
++	/* Initialize VBI template */
++	memcpy(&cx23885_vbi_template, &cx23885_video_template,
++		sizeof(cx23885_vbi_template));
++	strcpy(cx23885_vbi_template.name, "cx23885-vbi");
++	cx23885_vbi_template.type = VID_TYPE_TELETEXT|VID_TYPE_TUNER;
++
++	dev->tvnorm = cx23885_video_template.current_norm;
++
++	/* init video dma queues */
++	INIT_LIST_HEAD(&dev->vidq.active);
++	INIT_LIST_HEAD(&dev->vidq.queued);
++	dev->vidq.timeout.function = cx23885_vid_timeout;
++	dev->vidq.timeout.data = (unsigned long)dev;
++	init_timer(&dev->vidq.timeout);
++	cx23885_risc_stopper(dev->pci, &dev->vidq.stopper,
++		VID_A_DMA_CTL, 0x11, 0x00);
++
++	/* Don't enable VBI yet */
++	cx_set(PCI_INT_MSK, 1);
++
++
++	/* register v4l devices */
++	dev->video_dev = cx23885_vdev_init(dev, dev->pci,
++		&cx23885_video_template, "video");
++	err = video_register_device(dev->video_dev, VFL_TYPE_GRABBER,
++				    video_nr[dev->nr]);
++	if (err < 0) {
++		printk(KERN_INFO "%s: can't register video device\n",
++			dev->name);
++		goto fail_unreg;
++	}
++	printk(KERN_INFO "%s/0: registered device video%d [v4l2]\n",
++	       dev->name, dev->video_dev->minor & 0x1f);
++	/* initial device configuration */
++	mutex_lock(&dev->lock);
++	cx23885_set_tvnorm(dev, dev->tvnorm);
++	init_controls(dev);
++	cx23885_video_mux(dev, 0);
++	mutex_unlock(&dev->lock);
++
++	return 0;
++
++fail_unreg:
++	cx23885_video_unregister(dev);
++	return err;
++}
++
+diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h
+index dec4dc2..7cb2179 100644
+--- a/drivers/media/video/cx23885/cx23885.h
++++ b/drivers/media/video/cx23885/cx23885.h
+@@ -44,6 +44,10 @@
  
- MODULE_DESCRIPTION("i2c device driver for cs53l32a Audio ADC");
- MODULE_AUTHOR("Martin Vaughan");
- MODULE_LICENSE("GPL");
+ /* Max number of inputs by card */
+ #define MAX_CX23885_INPUT 8
++#define INPUT(nr) (&cx23885_boards[dev->board].input[nr])
++#define RESOURCE_OVERLAY       1
++#define RESOURCE_VIDEO         2
++#define RESOURCE_VBI           4
  
--static int debug = 0;
-+static int debug;
+ #define BUFFER_TIMEOUT     (HZ)  /* 0.5 seconds */
  
- module_param(debug, bool, 0644);
+@@ -53,6 +57,62 @@
+ #define CX23885_BOARD_HAUPPAUGE_HVR1800        2
+ #define CX23885_BOARD_HAUPPAUGE_HVR1250        3
+ #define CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP   4
++#define CX23885_BOARD_HAUPPAUGE_HVR1500Q       5
++#define CX23885_BOARD_HAUPPAUGE_HVR1500        6
++
++/* Currently unsupported by the driver: PAL/H, NTSC/Kr, SECAM B/G/H/LC */
++#define CX23885_NORMS (\
++	V4L2_STD_NTSC_M |  V4L2_STD_NTSC_M_JP |  V4L2_STD_NTSC_443 | \
++	V4L2_STD_PAL_BG |  V4L2_STD_PAL_DK    |  V4L2_STD_PAL_I    | \
++	V4L2_STD_PAL_M  |  V4L2_STD_PAL_N     |  V4L2_STD_PAL_Nc   | \
++	V4L2_STD_PAL_60 |  V4L2_STD_SECAM_L   |  V4L2_STD_SECAM_DK)
++
++struct cx23885_fmt {
++	char  *name;
++	u32   fourcc;          /* v4l2 format id */
++	int   depth;
++	int   flags;
++	u32   cxformat;
++};
++
++struct cx23885_ctrl {
++	struct v4l2_queryctrl v;
++	u32                   off;
++	u32                   reg;
++	u32                   mask;
++	u32                   shift;
++};
++
++struct cx23885_tvnorm {
++	char		*name;
++	v4l2_std_id	id;
++	u32		cxiformat;
++	u32		cxoformat;
++};
++
++struct cx23885_fh {
++	struct cx23885_dev         *dev;
++	enum v4l2_buf_type         type;
++	int                        radio;
++	u32                        resources;
++
++	/* video overlay */
++	struct v4l2_window         win;
++	struct v4l2_clip           *clips;
++	unsigned int               nclips;
++
++	/* video capture */
++	struct cx23885_fmt         *fmt;
++	unsigned int               width, height;
++
++	/* vbi capture */
++	struct videobuf_queue      vidq;
++	struct videobuf_queue      vbiq;
++
++	/* MPEG Encoder specifics ONLY */
++	struct videobuf_queue      mpegq;
++	atomic_t                   v4l_reading;
++};
  
-@@ -57,8 +58,7 @@ static int cs53l32a_read(struct i2c_client *client, u8 reg)
- 	return i2c_smbus_read_byte_data(client, reg);
- }
+ enum cx23885_itype {
+ 	CX23885_VMUX_COMPOSITE1 = 1,
+@@ -92,12 +152,28 @@ struct cx23885_input {
  
--static int cs53l32a_command(struct i2c_client *client, unsigned int cmd,
--			    void *arg)
-+static int cs53l32a_command(struct i2c_client *client, unsigned cmd, void *arg)
- {
- 	struct v4l2_routing *route = arg;
- 	struct v4l2_control *ctrl = arg;
-@@ -105,7 +105,8 @@ static int cs53l32a_command(struct i2c_client *client, unsigned int cmd,
- 		break;
+ typedef enum {
+ 	CX23885_MPEG_UNDEFINED = 0,
+-	CX23885_MPEG_DVB
++	CX23885_MPEG_DVB,
++	CX23885_ANALOG_VIDEO,
+ } port_t;
  
- 	case VIDIOC_G_CHIP_IDENT:
--		return v4l2_chip_ident_i2c_client(client, arg, V4L2_IDENT_CS53l32A, 0);
-+		return v4l2_chip_ident_i2c_client(client,
-+				arg, V4L2_IDENT_CS53l32A, 0);
+ struct cx23885_board {
+ 	char                    *name;
+-	port_t			portb, portc;
++	port_t			porta, portb, portc;
++	unsigned int		tuner_type;
++	unsigned int		radio_type;
++	unsigned char		tuner_addr;
++	unsigned char		radio_addr;
++
++	/* Vendors can and do run the PCIe bridge at different
++	 * clock rates, driven physically by crystals on the PCBs.
++	 * The core has to accomodate this. This allows the user
++	 * to add new boards with new frequencys. The value is
++	 * expressed in Hz.
++	 *
++	 * The core framework will default this value based on
++	 * current designs, but it can vary.
++	 */
++	u32			clk_freq;
+ 	struct cx23885_input    input[MAX_CX23885_INPUT];
+ };
  
- 	case VIDIOC_LOG_STATUS:
- 		{
-@@ -134,27 +135,18 @@ static int cs53l32a_command(struct i2c_client *client, unsigned int cmd,
-  * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
-  */
+@@ -189,6 +265,11 @@ struct cx23885_dev {
+ 	u32                        __iomem *lmmio;
+ 	u8                         __iomem *bmmio;
+ 	int                        pci_irqmask;
++	int                        hwrevision;
++
++	/* This valud is board specific and is used to configure the
++	 * AV core so we see nice clean and stable video and audio. */
++	u32                        clk_freq;
  
--static struct i2c_driver i2c_driver;
--
--static int cs53l32a_attach(struct i2c_adapter *adapter, int address, int kind)
-+static int cs53l32a_probe(struct i2c_client *client)
- {
--	struct i2c_client *client;
- 	int i;
+ 	/* I2C adapters: Master 1 & 2 (External) & Master 3 (Internal only) */
+ 	struct cx23885_i2c         i2c_bus[3];
+@@ -210,8 +291,31 @@ struct cx23885_dev {
+ 		CX23885_BRIDGE_885 = 885,
+ 		CX23885_BRIDGE_887 = 887,
+ 	} bridge;
++
++	/* Analog video */
++	u32                        resources;
++	unsigned int               input;
++	u32                        tvaudio;
++	v4l2_std_id                tvnorm;
++	unsigned int               tuner_type;
++	unsigned char              tuner_addr;
++	unsigned int               radio_type;
++	unsigned char              radio_addr;
++	unsigned int               has_radio;
++
++	/* V4l */
++	u32                        freq;
++	struct video_device        *video_dev;
++	struct video_device        *vbi_dev;
++	struct video_device        *radio_dev;
++
++	struct cx23885_dmaqueue    vidq;
++	struct cx23885_dmaqueue    vbiq;
++	spinlock_t                 slock;
+ };
  
- 	/* Check if the adapter supports the needed features */
--	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
--		return 0;
--
--	client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
--	if (client == 0)
--		return -ENOMEM;
-+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
-+		return -EIO;
++extern struct list_head cx23885_devlist;
++
+ #define SRAM_CH01  0 /* Video A */
+ #define SRAM_CH02  1 /* VBI A */
+ #define SRAM_CH03  2 /* Video B */
+@@ -254,19 +358,42 @@ struct sram_channel {
+ #define cx_set(reg,bit)          cx_andor((reg),(bit),(bit))
+ #define cx_clear(reg,bit)        cx_andor((reg),(bit),0)
  
--	client->addr = address;
--	client->adapter = adapter;
--	client->driver = &i2c_driver;
- 	snprintf(client->name, sizeof(client->name) - 1, "cs53l32a");
++/* ----------------------------------------------------------- */
++/* cx23885-core.c                                              */
++
+ extern int cx23885_sram_channel_setup(struct cx23885_dev *dev,
+ 	struct sram_channel *ch,
+ 	unsigned int bpl, u32 risc);
  
--	v4l_info(client, "chip found @ 0x%x (%s)\n", address << 1, adapter->name);
-+	v4l_info(client, "chip found @ 0x%x (%s)\n",
-+			client->addr << 1, client->adapter->name);
+-/* ----------------------------------------------------------- */
+-/* cx23885-cards.c                                                */
++extern void cx23885_sram_channel_dump(struct cx23885_dev *dev,
++	struct sram_channel *ch);
  
- 	for (i = 1; i <= 7; i++) {
- 		u8 v = cs53l32a_read(client, i);
-@@ -179,55 +171,13 @@ static int cs53l32a_attach(struct i2c_adapter *adapter, int address, int kind)
++extern int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc,
++	u32 reg, u32 mask, u32 value);
++
++extern int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc,
++	struct scatterlist *sglist,
++	unsigned int top_offset, unsigned int bottom_offset,
++	unsigned int bpl, unsigned int padding, unsigned int lines);
++
++void cx23885_cancel_buffers(struct cx23885_tsport *port);
++
++extern int cx23885_restart_queue(struct cx23885_tsport *port,
++				struct cx23885_dmaqueue *q);
++
++extern void cx23885_wakeup(struct cx23885_tsport *port,
++			   struct cx23885_dmaqueue *q, u32 count);
++
++
++/* ----------------------------------------------------------- */
++/* cx23885-cards.c                                             */
+ extern struct cx23885_board cx23885_boards[];
+ extern const unsigned int cx23885_bcount;
  
- 		v4l_dbg(1, debug, client, "Read Reg %d %02x\n", i, v);
- 	}
--
--	i2c_attach_client(client);
--
- 	return 0;
- }
+ extern struct cx23885_subid cx23885_subids[];
+ extern const unsigned int cx23885_idcount;
  
--static int cs53l32a_probe(struct i2c_adapter *adapter)
--{
--	if (adapter->class & I2C_CLASS_TV_ANALOG)
--		return i2c_probe(adapter, &addr_data, cs53l32a_attach);
--	return 0;
--}
--
--static int cs53l32a_detach(struct i2c_client *client)
--{
--	int err;
--
--	err = i2c_detach_client(client);
--	if (err) {
--		return err;
--	}
--	kfree(client);
--
--	return 0;
--}
--
--/* ----------------------------------------------------------------------- */
++extern int cx23885_tuner_callback(void *priv, 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);
+@@ -280,19 +407,50 @@ extern int cx23885_buf_prepare(struct videobuf_queue *q,
+ 			       struct cx23885_tsport *port,
+ 			       struct cx23885_buffer *buf,
+ 			       enum v4l2_field field);
 -
--/* i2c implementation */
--static struct i2c_driver i2c_driver = {
--	.driver = {
--		.name = "cs53l32a",
--	},
--	.id = I2C_DRIVERID_CS53L32A,
--	.attach_adapter = cs53l32a_probe,
--	.detach_client = cs53l32a_detach,
-+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
-+	.name = "cs53l32a",
-+	.driverid = I2C_DRIVERID_CS53L32A,
- 	.command = cs53l32a_command,
-+	.probe = cs53l32a_probe,
- };
+ extern void cx23885_buf_queue(struct cx23885_tsport *port,
+ 			      struct cx23885_buffer *buf);
+ extern void cx23885_free_buffer(struct videobuf_queue *q,
+ 				struct cx23885_buffer *buf);
  
--
--static int __init cs53l32a_init_module(void)
--{
--	return i2c_add_driver(&i2c_driver);
--}
--
--static void __exit cs53l32a_cleanup_module(void)
--{
--	i2c_del_driver(&i2c_driver);
--}
--
--module_init(cs53l32a_init_module);
--module_exit(cs53l32a_cleanup_module);
-diff --git a/drivers/media/video/cx2341x.c b/drivers/media/video/cx2341x.c
-index 6230425..c592899 100644
---- a/drivers/media/video/cx2341x.c
-+++ b/drivers/media/video/cx2341x.c
-@@ -34,7 +34,7 @@ MODULE_DESCRIPTION("cx23415/6 driver");
- MODULE_AUTHOR("Hans Verkuil");
- MODULE_LICENSE("GPL");
+ /* ----------------------------------------------------------- */
++/* cx23885-video.c                                             */
++/* Video */
++extern int cx23885_video_register(struct cx23885_dev *dev);
++extern void cx23885_video_unregister(struct cx23885_dev *dev);
++extern int cx23885_video_irq(struct cx23885_dev *dev, u32 status);
++
++/* ----------------------------------------------------------- */
++/* cx23885-vbi.c                                               */
++extern int cx23885_vbi_fmt(struct file *file, void *priv,
++	struct v4l2_format *f);
++extern void cx23885_vbi_timeout(unsigned long data);
++extern struct videobuf_queue_ops cx23885_vbi_qops;
++
+ /* cx23885-i2c.c                                                */
+ extern int cx23885_i2c_register(struct cx23885_i2c *bus);
+ extern int cx23885_i2c_unregister(struct cx23885_i2c *bus);
+ extern void cx23885_call_i2c_clients(struct cx23885_i2c *bus, unsigned int cmd,
+ 				     void *arg);
+ 
++/* ----------------------------------------------------------- */
++/* tv norms                                                    */
++
++static inline unsigned int norm_maxw(v4l2_std_id norm)
++{
++	return (norm & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 720 : 768;
++}
++
++static inline unsigned int norm_maxh(v4l2_std_id norm)
++{
++	return (norm & V4L2_STD_625_50) ? 576 : 480;
++}
++
++static inline unsigned int norm_swidth(v4l2_std_id norm)
++{
++	return (norm & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 754 : 922;
++}
++
++
+ /*
+  * Local variables:
+  * c-basic-offset: 8
+diff --git a/drivers/media/video/cx25840/cx25840-audio.c b/drivers/media/video/cx25840/cx25840-audio.c
+index 3d46a77..d6421e1 100644
+--- a/drivers/media/video/cx25840/cx25840-audio.c
++++ b/drivers/media/video/cx25840/cx25840-audio.c
+@@ -32,118 +32,156 @@ static int set_audclk_freq(struct i2c_client *client, u32 freq)
  
--static int debug = 0;
-+static int debug;
- module_param(debug, int, 0644);
- MODULE_PARM_DESC(debug, "Debug level (0-1)");
+ 	/* common for all inputs and rates */
+ 	/* SA_MCLK_SEL=1, SA_MCLK_DIV=0x10 */
+-	cx25840_write(client, 0x127, 0x50);
++	if (!state->is_cx23885)
++		cx25840_write(client, 0x127, 0x50);
  
-@@ -75,6 +75,7 @@ const u32 cx2341x_mpeg_ctrls[] = {
- 	V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS,
- 	0
- };
-+EXPORT_SYMBOL(cx2341x_mpeg_ctrls);
+ 	if (state->aud_input != CX25840_AUDIO_SERIAL) {
+ 		switch (freq) {
+ 		case 32000:
++			if (state->is_cx23885) {
++				/* We don't have register values
++				 * so avoid destroying registers. */
++				break;
++			}
+ 			/* VID_PLL and AUX_PLL */
+-			cx25840_write4(client, 0x108, 0x0f040610);
++			cx25840_write4(client, 0x108, 0x1006040f);
  
+ 			/* AUX_PLL_FRAC */
+-			cx25840_write4(client, 0x110, 0xee39bb01);
++			cx25840_write4(client, 0x110, 0x01bb39ee);
  
- /* Map the control ID to the correct field in the cx2341x_mpeg_params
-@@ -281,13 +282,14 @@ static int cx2341x_set_ctrl(struct cx2341x_mpeg_params *params, int busy,
- 			return -EBUSY;
- 		params->stream_type = ctrl->value;
- 		params->video_encoding =
--			(params->stream_type == V4L2_MPEG_STREAM_TYPE_MPEG1_SS ||
--			 params->stream_type == V4L2_MPEG_STREAM_TYPE_MPEG1_VCD) ?
--			V4L2_MPEG_VIDEO_ENCODING_MPEG_1 : V4L2_MPEG_VIDEO_ENCODING_MPEG_2;
--		if (params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1) {
-+		    (params->stream_type == V4L2_MPEG_STREAM_TYPE_MPEG1_SS ||
-+		     params->stream_type == V4L2_MPEG_STREAM_TYPE_MPEG1_VCD) ?
-+			V4L2_MPEG_VIDEO_ENCODING_MPEG_1 :
-+			V4L2_MPEG_VIDEO_ENCODING_MPEG_2;
-+		if (params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1)
- 			/* MPEG-1 implies CBR */
--			params->video_bitrate_mode = V4L2_MPEG_VIDEO_BITRATE_MODE_CBR;
--		}
-+			params->video_bitrate_mode =
-+				V4L2_MPEG_VIDEO_BITRATE_MODE_CBR;
- 		break;
- 	case V4L2_CID_MPEG_STREAM_VBI_FMT:
- 		params->stream_vbi_fmt = ctrl->value;
-@@ -334,7 +336,8 @@ static int cx2341x_set_ctrl(struct cx2341x_mpeg_params *params, int busy,
- 	return 0;
- }
+ 			if (state->is_cx25836)
+ 				break;
  
--static int cx2341x_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 step, s32 def)
-+static int cx2341x_ctrl_query_fill(struct v4l2_queryctrl *qctrl,
-+				   s32 min, s32 max, s32 step, s32 def)
- {
- 	const char *name;
+ 			/* src3/4/6_ctl = 0x0801f77f */
+-			cx25840_write4(client, 0x900, 0x7ff70108);
+-			cx25840_write4(client, 0x904, 0x7ff70108);
+-			cx25840_write4(client, 0x90c, 0x7ff70108);
++			cx25840_write4(client, 0x900, 0x0801f77f);
++			cx25840_write4(client, 0x904, 0x0801f77f);
++			cx25840_write4(client, 0x90c, 0x0801f77f);
+ 			break;
  
-@@ -417,7 +420,8 @@ static int cx2341x_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 ma
- 	return 0;
- }
+ 		case 44100:
++			if (state->is_cx23885) {
++				/* We don't have register values
++				 * so avoid destroying registers. */
++				break;
++			}
+ 			/* VID_PLL and AUX_PLL */
+-			cx25840_write4(client, 0x108, 0x0f040910);
++			cx25840_write4(client, 0x108, 0x1009040f);
  
--int cx2341x_ctrl_query(struct cx2341x_mpeg_params *params, struct v4l2_queryctrl *qctrl)
-+int cx2341x_ctrl_query(struct cx2341x_mpeg_params *params,
-+		       struct v4l2_queryctrl *qctrl)
- {
- 	int err;
+ 			/* AUX_PLL_FRAC */
+-			cx25840_write4(client, 0x110, 0xd66bec00);
++			cx25840_write4(client, 0x110, 0x00ec6bd6);
  
-@@ -440,7 +444,8 @@ int cx2341x_ctrl_query(struct cx2341x_mpeg_params *params, struct v4l2_queryctrl
+ 			if (state->is_cx25836)
+ 				break;
  
- 	case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
- 		err = v4l2_ctrl_query_fill_std(qctrl);
--		if (err == 0 && params->audio_mode != V4L2_MPEG_AUDIO_MODE_JOINT_STEREO)
-+		if (err == 0 &&
-+		    params->audio_mode != V4L2_MPEG_AUDIO_MODE_JOINT_STEREO)
- 			qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
- 		return err;
+ 			/* src3/4/6_ctl = 0x08016d59 */
+-			cx25840_write4(client, 0x900, 0x596d0108);
+-			cx25840_write4(client, 0x904, 0x596d0108);
+-			cx25840_write4(client, 0x90c, 0x596d0108);
++			cx25840_write4(client, 0x900, 0x08016d59);
++			cx25840_write4(client, 0x904, 0x08016d59);
++			cx25840_write4(client, 0x90c, 0x08016d59);
+ 			break;
  
-@@ -455,13 +460,16 @@ int cx2341x_ctrl_query(struct cx2341x_mpeg_params *params, struct v4l2_queryctrl
+ 		case 48000:
++			if (state->is_cx23885) {
++				/* We don't have register values
++				 * so avoid destroying registers. */
++				break;
++			}
+ 			/* VID_PLL and AUX_PLL */
+-			cx25840_write4(client, 0x108, 0x0f040a10);
++			cx25840_write4(client, 0x108, 0x100a040f);
  
- 	case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
- 		err = v4l2_ctrl_query_fill_std(qctrl);
--		if (err == 0 && params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1)
-+		if (err == 0 &&
-+		    params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1)
- 			qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
- 		return err;
+ 			/* AUX_PLL_FRAC */
+-			cx25840_write4(client, 0x110, 0xe5d69800);
++			cx25840_write4(client, 0x110, 0x0098d6e5);
  
- 	case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
- 		err = v4l2_ctrl_query_fill_std(qctrl);
--		if (err == 0 && params->video_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR)
-+		if (err == 0 &&
-+		    params->video_bitrate_mode ==
-+				V4L2_MPEG_VIDEO_BITRATE_MODE_CBR)
- 			qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
- 		return err;
+ 			if (state->is_cx25836)
+ 				break;
  
-@@ -476,80 +484,90 @@ int cx2341x_ctrl_query(struct cx2341x_mpeg_params *params, struct v4l2_queryctrl
- 	/* CX23415/6 specific */
- 	case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
- 		return cx2341x_ctrl_query_fill(qctrl,
--				V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL,
--				V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO, 1,
--				V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL);
-+			V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL,
-+			V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO, 1,
-+			V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL);
+ 			/* src3/4/6_ctl = 0x08014faa */
+-			cx25840_write4(client, 0x900, 0xaa4f0108);
+-			cx25840_write4(client, 0x904, 0xaa4f0108);
+-			cx25840_write4(client, 0x90c, 0xaa4f0108);
++			cx25840_write4(client, 0x900, 0x08014faa);
++			cx25840_write4(client, 0x904, 0x08014faa);
++			cx25840_write4(client, 0x90c, 0x08014faa);
+ 			break;
+ 		}
+ 	} else {
+ 		switch (freq) {
+ 		case 32000:
++			if (state->is_cx23885) {
++				/* We don't have register values
++				 * so avoid destroying registers. */
++				break;
++			}
+ 			/* VID_PLL and AUX_PLL */
+-			cx25840_write4(client, 0x108, 0x0f04081e);
++			cx25840_write4(client, 0x108, 0x1e08040f);
  
- 	case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER:
- 		cx2341x_ctrl_query_fill(qctrl, 0, 15, 1, 0);
- 		qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
--		if (params->video_spatial_filter_mode == V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO)
--		       qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
-+		if (params->video_spatial_filter_mode ==
-+			    V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO)
-+			qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
- 		return 0;
+ 			/* AUX_PLL_FRAC */
+-			cx25840_write4(client, 0x110, 0x69082a01);
++			cx25840_write4(client, 0x110, 0x012a0869);
  
- 	case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
- 		cx2341x_ctrl_query_fill(qctrl,
--				V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_OFF,
--				V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_2D_SYM_NON_SEPARABLE, 1,
--				V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_OFF);
--		if (params->video_spatial_filter_mode == V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO)
--		       qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
-+			V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_OFF,
-+			V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_2D_SYM_NON_SEPARABLE,
-+			1,
-+			V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_OFF);
-+		if (params->video_spatial_filter_mode ==
-+			    V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO)
-+			qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
- 		return 0;
+ 			if (state->is_cx25836)
+ 				break;
  
- 	case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
- 		cx2341x_ctrl_query_fill(qctrl,
--				V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_OFF,
--				V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR, 1,
--				V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_OFF);
--		if (params->video_spatial_filter_mode == V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO)
--		       qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
-+		    V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_OFF,
-+		    V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR,
-+		    1,
-+		    V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_OFF);
-+		if (params->video_spatial_filter_mode ==
-+			V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO)
-+			qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
- 		return 0;
+ 			/* src1_ctl = 0x08010000 */
+-			cx25840_write4(client, 0x8f8, 0x00000108);
++			cx25840_write4(client, 0x8f8, 0x08010000);
  
- 	case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
- 		return cx2341x_ctrl_query_fill(qctrl,
--				V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL,
--				V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO, 1,
--				V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL);
-+			V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL,
-+			V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO, 1,
-+			V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL);
+ 			/* src3/4/6_ctl = 0x08020000 */
+-			cx25840_write4(client, 0x900, 0x00000208);
+-			cx25840_write4(client, 0x904, 0x00000208);
+-			cx25840_write4(client, 0x90c, 0x00000208);
++			cx25840_write4(client, 0x900, 0x08020000);
++			cx25840_write4(client, 0x904, 0x08020000);
++			cx25840_write4(client, 0x90c, 0x08020000);
  
- 	case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER:
- 		cx2341x_ctrl_query_fill(qctrl, 0, 31, 1, 0);
- 		qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
--		if (params->video_temporal_filter_mode == V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO)
--		       qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
-+		if (params->video_temporal_filter_mode ==
-+			V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO)
-+			qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
- 		return 0;
+ 			/* SA_MCLK_SEL=1, SA_MCLK_DIV=0x14 */
+ 			cx25840_write(client, 0x127, 0x54);
+ 			break;
  
- 	case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
- 		return cx2341x_ctrl_query_fill(qctrl,
--				V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF,
--				V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_DIAG, 1,
--				V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF);
-+			V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF,
-+			V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_DIAG, 1,
-+			V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF);
+ 		case 44100:
++			if (state->is_cx23885) {
++				/* We don't have register values
++				 * so avoid destroying registers. */
++				break;
++			}
++
+ 			/* VID_PLL and AUX_PLL */
+-			cx25840_write4(client, 0x108, 0x0f040918);
++			cx25840_write4(client, 0x108, 0x1809040f);
  
- 	case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP:
- 		cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, 255);
- 		qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
--		if (params->video_median_filter_type == V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF)
--		       qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
-+		if (params->video_median_filter_type ==
-+				V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF)
-+			qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
- 		return 0;
+ 			/* AUX_PLL_FRAC */
+-			cx25840_write4(client, 0x110, 0xd66bec00);
++			cx25840_write4(client, 0x110, 0x00ec6bd6);
  
- 	case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM:
- 		cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, 0);
- 		qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
--		if (params->video_median_filter_type == V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF)
--		       qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
-+		if (params->video_median_filter_type ==
-+				V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF)
-+			qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
- 		return 0;
+ 			if (state->is_cx25836)
+ 				break;
  
- 	case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP:
- 		cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, 255);
- 		qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
--		if (params->video_median_filter_type == V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF)
--		       qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
-+		if (params->video_median_filter_type ==
-+				V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF)
-+			qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
- 		return 0;
+ 			/* src1_ctl = 0x08010000 */
+-			cx25840_write4(client, 0x8f8, 0xcd600108);
++			cx25840_write4(client, 0x8f8, 0x080160cd);
  
- 	case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM:
- 		cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, 0);
- 		qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
--		if (params->video_median_filter_type == V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF)
--		       qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
-+		if (params->video_median_filter_type ==
-+				V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF)
-+			qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
- 		return 0;
+ 			/* src3/4/6_ctl = 0x08020000 */
+-			cx25840_write4(client, 0x900, 0x85730108);
+-			cx25840_write4(client, 0x904, 0x85730108);
+-			cx25840_write4(client, 0x90c, 0x85730108);
++			cx25840_write4(client, 0x900, 0x08017385);
++			cx25840_write4(client, 0x904, 0x08017385);
++			cx25840_write4(client, 0x90c, 0x08017385);
+ 			break;
  
- 	case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS:
-@@ -560,6 +578,7 @@ int cx2341x_ctrl_query(struct cx2341x_mpeg_params *params, struct v4l2_queryctrl
+ 		case 48000:
+-			/* VID_PLL and AUX_PLL */
+-			cx25840_write4(client, 0x108, 0x0f040a18);
++			if (!state->is_cx23885) {
++				/* VID_PLL and AUX_PLL */
++				cx25840_write4(client, 0x108, 0x180a040f);
  
- 	}
- }
-+EXPORT_SYMBOL(cx2341x_ctrl_query);
+-			/* AUX_PLL_FRAC */
+-			cx25840_write4(client, 0x110, 0xe5d69800);
++				/* AUX_PLL_FRAC */
++				cx25840_write4(client, 0x110, 0x0098d6e5);
++			}
  
- const char **cx2341x_ctrl_get_menu(u32 id)
- {
-@@ -629,6 +648,7 @@ const char **cx2341x_ctrl_get_menu(u32 id)
- 		return v4l2_ctrl_get_menu(id);
- 	}
- }
-+EXPORT_SYMBOL(cx2341x_ctrl_get_menu);
+ 			if (state->is_cx25836)
+ 				break;
  
- static void cx2341x_calc_audio_properties(struct cx2341x_mpeg_params *params)
- {
-@@ -637,9 +657,8 @@ static void cx2341x_calc_audio_properties(struct cx2341x_mpeg_params *params)
- 		((1 + params->audio_l2_bitrate) << 4) |
- 		(params->audio_mode << 8) |
- 		(params->audio_mode_extension << 10) |
--		(((params->audio_emphasis == V4L2_MPEG_AUDIO_EMPHASIS_CCITT_J17) ?
--		  3 :
--		  params->audio_emphasis) << 12) |
-+		(((params->audio_emphasis == V4L2_MPEG_AUDIO_EMPHASIS_CCITT_J17)
-+		  ? 3 : params->audio_emphasis) << 12) |
- 		(params->audio_crc << 14);
- }
+-			/* src1_ctl = 0x08010000 */
+-			cx25840_write4(client, 0x8f8, 0x00800108);
++			if (!state->is_cx23885) {
++				/* src1_ctl */
++				cx25840_write4(client, 0x8f8, 0x08018000);
  
-@@ -679,19 +698,19 @@ int cx2341x_ext_ctrls(struct cx2341x_mpeg_params *params, int busy,
- 		if (err)
+-			/* src3/4/6_ctl = 0x08020000 */
+-			cx25840_write4(client, 0x900, 0x55550108);
+-			cx25840_write4(client, 0x904, 0x55550108);
+-			cx25840_write4(client, 0x90c, 0x55550108);
++				/* src3/4/6_ctl */
++				cx25840_write4(client, 0x900, 0x08015555);
++				cx25840_write4(client, 0x904, 0x08015555);
++				cx25840_write4(client, 0x90c, 0x08015555);
++			} else {
++
++				cx25840_write4(client, 0x8f8, 0x0801867c);
++
++				cx25840_write4(client, 0x900, 0x08014faa);
++				cx25840_write4(client, 0x904, 0x08014faa);
++				cx25840_write4(client, 0x90c, 0x08014faa);
++			}
  			break;
+ 		}
  	}
--	if (err == 0 && params->video_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR &&
--			params->video_bitrate_peak < params->video_bitrate) {
-+	if (err == 0 &&
-+	    params->video_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR &&
-+	    params->video_bitrate_peak < params->video_bitrate) {
- 		err = -ERANGE;
- 		ctrls->error_idx = ctrls->count;
- 	}
--	if (err) {
-+	if (err)
- 		ctrls->error_idx = i;
--	}
--	else {
-+	else
- 		cx2341x_calc_audio_properties(params);
--	}
- 	return err;
- }
-+EXPORT_SYMBOL(cx2341x_ext_ctrls);
- 
- void cx2341x_fill_defaults(struct cx2341x_mpeg_params *p)
- {
-@@ -732,13 +751,18 @@ void cx2341x_fill_defaults(struct cx2341x_mpeg_params *p)
- 	.video_mute_yuv = 0x008080,  /* YCbCr value for black */
- 
- 	/* encoding filters */
--	.video_spatial_filter_mode = V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL,
-+	.video_spatial_filter_mode =
-+		V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL,
- 	.video_spatial_filter = 0,
--	.video_luma_spatial_filter_type = V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_HOR,
--	.video_chroma_spatial_filter_type = V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR,
--	.video_temporal_filter_mode = V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL,
-+	.video_luma_spatial_filter_type =
-+		V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_HOR,
-+	.video_chroma_spatial_filter_type =
-+		V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR,
-+	.video_temporal_filter_mode =
-+		V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL,
- 	.video_temporal_filter = 8,
--	.video_median_filter_type = V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF,
-+	.video_median_filter_type =
-+		V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF,
- 	.video_luma_median_filter_top = 255,
- 	.video_luma_median_filter_bottom = 0,
- 	.video_chroma_median_filter_top = 255,
-@@ -748,8 +772,10 @@ void cx2341x_fill_defaults(struct cx2341x_mpeg_params *p)
- 	*p = default_params;
- 	cx2341x_calc_audio_properties(p);
- }
-+EXPORT_SYMBOL(cx2341x_fill_defaults);
+@@ -168,14 +206,14 @@ void cx25840_audio_set_path(struct i2c_client *client)
  
--static int cx2341x_api(void *priv, cx2341x_mbox_func func, int cmd, int args, ...)
-+static int cx2341x_api(void *priv, cx2341x_mbox_func func,
-+		       u32 cmd, int args, ...)
- {
- 	u32 data[CX2341X_MBOX_MAX_DATA];
- 	va_list vargs;
-@@ -757,15 +783,17 @@ static int cx2341x_api(void *priv, cx2341x_mbox_func func, int cmd, int args, ..
+ 	if (state->aud_input == CX25840_AUDIO_SERIAL) {
+ 		/* Set Path1 to Serial Audio Input */
+-		cx25840_write4(client, 0x8d0, 0x12100101);
++		cx25840_write4(client, 0x8d0, 0x01011012);
  
- 	va_start(vargs, args);
+ 		/* The microcontroller should not be started for the
+ 		 * non-tuner inputs: autodetection is specific for
+ 		 * TV audio. */
+ 	} else {
+ 		/* Set Path1 to Analog Demod Main Channel */
+-		cx25840_write4(client, 0x8d0, 0x7038061f);
++		cx25840_write4(client, 0x8d0, 0x1f063870);
+ 	}
  
--	for (i = 0; i < args; i++) {
-+	for (i = 0; i < args; i++)
- 		data[i] = va_arg(vargs, int);
--	}
- 	va_end(vargs);
- 	return func(priv, cmd, args, 0, data);
- }
+ 	set_audclk_freq(client, state->audclk_freq);
+@@ -188,6 +226,11 @@ void cx25840_audio_set_path(struct i2c_client *client)
  
-+#define NEQ(field) (old->field != new->field)
+ 	/* deassert soft reset */
+ 	cx25840_and_or(client, 0x810, ~0x1, 0x00);
 +
- int cx2341x_update(void *priv, cx2341x_mbox_func func,
--		const struct cx2341x_mpeg_params *old, const struct cx2341x_mpeg_params *new)
-+		   const struct cx2341x_mpeg_params *old,
-+		   const struct cx2341x_mpeg_params *new)
- {
- 	static int mpeg_stream_type[] = {
- 		0,	/* MPEG-2 PS */
-@@ -777,17 +805,18 @@ int cx2341x_update(void *priv, cx2341x_mbox_func func,
- 	};
- 
- 	int err = 0;
-+	int force = (old == NULL);
- 	u16 temporal = new->video_temporal_filter;
- 
- 	cx2341x_api(priv, func, CX2341X_ENC_SET_OUTPUT_PORT, 2, new->port, 0);
++	if (state->is_cx23885) {
++		/* Ensure the controller is running when we exit */
++		cx25840_and_or(client, 0x803, ~0x10, 0x10);
++	}
+ }
  
--	if (old == NULL || old->is_50hz != new->is_50hz) {
--		err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_RATE, 1, new->is_50hz);
-+	if (force || NEQ(is_50hz)) {
-+		err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_RATE, 1,
-+				  new->is_50hz);
- 		if (err) return err;
- 	}
+ static int get_volume(struct i2c_client *client)
+diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c
+index 15f191e..756a1ee 100644
+--- a/drivers/media/video/cx25840/cx25840-core.c
++++ b/drivers/media/video/cx25840/cx25840-core.c
+@@ -13,6 +13,8 @@
+  * NTSC sliced VBI support by Christopher Neufeld <television at cneufeld.ca>
+  * with additional fixes by Hans Verkuil <hverkuil at xs4all.nl>.
+  *
++ * CX23885 support by Steven Toth <stoth at hauppauge.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
+@@ -37,6 +39,7 @@
+ #include <linux/delay.h>
+ #include <media/v4l2-common.h>
+ #include <media/v4l2-chip-ident.h>
++#include <media/v4l2-i2c-drv-legacy.h>
+ #include <media/cx25840.h>
  
--	if (old == NULL || old->width != new->width || old->height != new->height ||
--			old->video_encoding != new->video_encoding) {
-+	if (force || NEQ(width) || NEQ(height) || NEQ(video_encoding)) {
- 		u16 w = new->width;
- 		u16 h = new->height;
+ #include "cx25840-core.h"
+@@ -72,10 +75,10 @@ int cx25840_write4(struct i2c_client *client, u16 addr, u32 value)
+ 	u8 buffer[6];
+ 	buffer[0] = addr >> 8;
+ 	buffer[1] = addr & 0xff;
+-	buffer[2] = value >> 24;
+-	buffer[3] = (value >> 16) & 0xff;
+-	buffer[4] = (value >> 8) & 0xff;
+-	buffer[5] = value & 0xff;
++	buffer[2] = value & 0xff;
++	buffer[3] = (value >> 8) & 0xff;
++	buffer[4] = (value >> 16) & 0xff;
++	buffer[5] = value >> 24;
+ 	return i2c_master_send(client, buffer, 6);
+ }
  
-@@ -795,69 +824,74 @@ int cx2341x_update(void *priv, cx2341x_mbox_func func,
- 			w /= 2;
- 			h /= 2;
- 		}
--		err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_SIZE, 2, h, w);
-+		err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_SIZE, 2,
-+				  h, w);
- 		if (err) return err;
- 	}
+@@ -122,8 +125,6 @@ int cx25840_and_or(struct i2c_client *client, u16 addr, unsigned and_mask,
  
- 	if (new->width != 720 || new->height != (new->is_50hz ? 576 : 480)) {
--		/* Adjust temporal filter if necessary. The problem with the temporal
--		   filter is that it works well with full resolution capturing, but
--		   not when the capture window is scaled (the filter introduces
--		   a ghosting effect). So if the capture window is scaled, then
--		   force the filter to 0.
-+		/* Adjust temporal filter if necessary. The problem with the
-+		   temporal filter is that it works well with full resolution
-+		   capturing, but not when the capture window is scaled (the
-+		   filter introduces a ghosting effect). So if the capture
-+		   window is scaled, then force the filter to 0.
+ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_input,
+ 						enum cx25840_audio_input aud_input);
+-static void log_audio_status(struct i2c_client *client);
+-static void log_video_status(struct i2c_client *client);
  
- 		   For full resolution the filter really improves the video
--		   quality, especially if the original video quality is suboptimal. */
-+		   quality, especially if the original video quality is
-+		   suboptimal. */
- 		temporal = 0;
- 	}
+ /* ----------------------------------------------------------------------- */
  
--	if (old == NULL || old->stream_type != new->stream_type) {
--		err = cx2341x_api(priv, func, CX2341X_ENC_SET_STREAM_TYPE, 1, mpeg_stream_type[new->stream_type]);
-+	if (force || NEQ(stream_type)) {
-+		err = cx2341x_api(priv, func, CX2341X_ENC_SET_STREAM_TYPE, 1,
-+				  mpeg_stream_type[new->stream_type]);
- 		if (err) return err;
- 	}
--	if (old == NULL || old->video_aspect != new->video_aspect) {
--		err = cx2341x_api(priv, func, CX2341X_ENC_SET_ASPECT_RATIO, 1, 1 + new->video_aspect);
-+	if (force || NEQ(video_aspect)) {
-+		err = cx2341x_api(priv, func, CX2341X_ENC_SET_ASPECT_RATIO, 1,
-+				  1 + new->video_aspect);
- 		if (err) return err;
- 	}
--	if (old == NULL || old->video_b_frames != new->video_b_frames ||
--		old->video_gop_size != new->video_gop_size) {
-+	if (force || NEQ(video_b_frames) || NEQ(video_gop_size)) {
- 		err = cx2341x_api(priv, func, CX2341X_ENC_SET_GOP_PROPERTIES, 2,
- 				new->video_gop_size, new->video_b_frames + 1);
- 		if (err) return err;
- 	}
--	if (old == NULL || old->video_gop_closure != new->video_gop_closure) {
--		err = cx2341x_api(priv, func, CX2341X_ENC_SET_GOP_CLOSURE, 1, new->video_gop_closure);
-+	if (force || NEQ(video_gop_closure)) {
-+		err = cx2341x_api(priv, func, CX2341X_ENC_SET_GOP_CLOSURE, 1,
-+				  new->video_gop_closure);
- 		if (err) return err;
- 	}
--	if (old == NULL || old->audio_properties != new->audio_properties) {
--		err = cx2341x_api(priv, func, CX2341X_ENC_SET_AUDIO_PROPERTIES, 1, new->audio_properties);
-+	if (force || NEQ(audio_properties)) {
-+		err = cx2341x_api(priv, func, CX2341X_ENC_SET_AUDIO_PROPERTIES,
-+				  1, new->audio_properties);
- 		if (err) return err;
- 	}
--	if (old == NULL || old->audio_mute != new->audio_mute) {
--		err = cx2341x_api(priv, func, CX2341X_ENC_MUTE_AUDIO, 1, new->audio_mute);
-+	if (force || NEQ(audio_mute)) {
-+		err = cx2341x_api(priv, func, CX2341X_ENC_MUTE_AUDIO, 1,
-+				  new->audio_mute);
- 		if (err) return err;
- 	}
--	if (old == NULL || old->video_bitrate_mode != new->video_bitrate_mode ||
--		old->video_bitrate != new->video_bitrate ||
--		old->video_bitrate_peak != new->video_bitrate_peak) {
-+	if (force || NEQ(video_bitrate_mode) || NEQ(video_bitrate) ||
-+						NEQ(video_bitrate_peak)) {
- 		err = cx2341x_api(priv, func, CX2341X_ENC_SET_BIT_RATE, 5,
- 				new->video_bitrate_mode, new->video_bitrate,
- 				new->video_bitrate_peak / 400, 0, 0);
- 		if (err) return err;
- 	}
--	if (old == NULL || old->video_spatial_filter_mode != new->video_spatial_filter_mode ||
--		old->video_temporal_filter_mode != new->video_temporal_filter_mode ||
--		old->video_median_filter_type != new->video_median_filter_type) {
--		err = cx2341x_api(priv, func, CX2341X_ENC_SET_DNR_FILTER_MODE, 2,
--				new->video_spatial_filter_mode | (new->video_temporal_filter_mode << 1),
-+	if (force || NEQ(video_spatial_filter_mode) ||
-+		     NEQ(video_temporal_filter_mode) ||
-+		     NEQ(video_median_filter_type)) {
-+		err = cx2341x_api(priv, func, CX2341X_ENC_SET_DNR_FILTER_MODE,
-+				  2, new->video_spatial_filter_mode |
-+					(new->video_temporal_filter_mode << 1),
- 				new->video_median_filter_type);
- 		if (err) return err;
- 	}
--	if (old == NULL ||
--		old->video_luma_median_filter_bottom != new->video_luma_median_filter_bottom ||
--		old->video_luma_median_filter_top != new->video_luma_median_filter_top ||
--		old->video_chroma_median_filter_bottom != new->video_chroma_median_filter_bottom ||
--		old->video_chroma_median_filter_top != new->video_chroma_median_filter_top) {
-+	if (force || NEQ(video_luma_median_filter_bottom) ||
-+		     NEQ(video_luma_median_filter_top) ||
-+		     NEQ(video_chroma_median_filter_bottom) ||
-+		     NEQ(video_chroma_median_filter_top)) {
- 		err = cx2341x_api(priv, func, CX2341X_ENC_SET_CORING_LEVELS, 4,
- 				new->video_luma_median_filter_bottom,
- 				new->video_luma_median_filter_top,
-@@ -865,36 +899,39 @@ int cx2341x_update(void *priv, cx2341x_mbox_func func,
- 				new->video_chroma_median_filter_top);
- 		if (err) return err;
- 	}
--	if (old == NULL ||
--		old->video_luma_spatial_filter_type != new->video_luma_spatial_filter_type ||
--		old->video_chroma_spatial_filter_type != new->video_chroma_spatial_filter_type) {
--		err = cx2341x_api(priv, func, CX2341X_ENC_SET_SPATIAL_FILTER_TYPE, 2,
--			new->video_luma_spatial_filter_type, new->video_chroma_spatial_filter_type);
-+	if (force || NEQ(video_luma_spatial_filter_type) ||
-+		     NEQ(video_chroma_spatial_filter_type)) {
-+		err = cx2341x_api(priv, func,
-+				  CX2341X_ENC_SET_SPATIAL_FILTER_TYPE,
-+				  2, new->video_luma_spatial_filter_type,
-+				  new->video_chroma_spatial_filter_type);
- 		if (err) return err;
- 	}
--	if (old == NULL ||
--		old->video_spatial_filter != new->video_spatial_filter ||
--		old->video_temporal_filter != temporal) {
--		err = cx2341x_api(priv, func, CX2341X_ENC_SET_DNR_FILTER_PROPS, 2,
--			new->video_spatial_filter, temporal);
-+	if (force || NEQ(video_spatial_filter) ||
-+		     old->video_temporal_filter != temporal) {
-+		err = cx2341x_api(priv, func, CX2341X_ENC_SET_DNR_FILTER_PROPS,
-+				  2, new->video_spatial_filter, temporal);
- 		if (err) return err;
- 	}
--	if (old == NULL || old->video_temporal_decimation != new->video_temporal_decimation) {
--		err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_DROP_RATE, 1,
--			new->video_temporal_decimation);
-+	if (force || NEQ(video_temporal_decimation)) {
-+		err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_DROP_RATE,
-+				  1, new->video_temporal_decimation);
- 		if (err) return err;
- 	}
--	if (old == NULL || old->video_mute != new->video_mute ||
--			(new->video_mute && old->video_mute_yuv != new->video_mute_yuv)) {
--		err = cx2341x_api(priv, func, CX2341X_ENC_MUTE_VIDEO, 1, new->video_mute | (new->video_mute_yuv << 8));
-+	if (force || NEQ(video_mute) ||
-+		(new->video_mute && NEQ(video_mute_yuv))) {
-+		err = cx2341x_api(priv, func, CX2341X_ENC_MUTE_VIDEO, 1,
-+				new->video_mute | (new->video_mute_yuv << 8));
- 		if (err) return err;
- 	}
--	if (old == NULL || old->stream_insert_nav_packets != new->stream_insert_nav_packets) {
--		err = cx2341x_api(priv, func, CX2341X_ENC_MISC, 2, 7, new->stream_insert_nav_packets);
-+	if (force || NEQ(stream_insert_nav_packets)) {
-+		err = cx2341x_api(priv, func, CX2341X_ENC_MISC, 2,
-+				7, new->stream_insert_nav_packets);
- 		if (err) return err;
- 	}
- 	return 0;
+@@ -256,6 +257,96 @@ static void cx25840_initialize(struct i2c_client *client)
+ 	cx25840_and_or(client, 0x803, ~0x10, 0x10);
  }
-+EXPORT_SYMBOL(cx2341x_update);
- 
- static const char *cx2341x_menu_item(struct cx2341x_mpeg_params *p, u32 id)
- {
-@@ -943,18 +980,17 @@ void cx2341x_log_status(struct cx2341x_mpeg_params *p, const char *prefix)
- 		cx2341x_menu_item(p, V4L2_CID_MPEG_VIDEO_ASPECT),
- 		cx2341x_menu_item(p, V4L2_CID_MPEG_VIDEO_BITRATE_MODE),
- 		p->video_bitrate);
--	if (p->video_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) {
-+	if (p->video_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR)
- 		printk(", Peak %d", p->video_bitrate_peak);
--	}
- 	printk("\n");
--	printk(KERN_INFO "%s: Video:  GOP Size %d, %d B-Frames, %sGOP Closure\n",
-+	printk(KERN_INFO
-+		"%s: Video:  GOP Size %d, %d B-Frames, %sGOP Closure\n",
- 		prefix,
- 		p->video_gop_size, p->video_b_frames,
- 		p->video_gop_closure ? "" : "No ");
--	if (p->video_temporal_decimation) {
-+	if (p->video_temporal_decimation)
- 		printk(KERN_INFO "%s: Video: Temporal Decimation %d\n",
- 			prefix, p->video_temporal_decimation);
--	}
  
- 	/* Audio */
- 	printk(KERN_INFO "%s: Audio:  %s, %s, %s, %s%s",
-@@ -964,10 +1000,9 @@ void cx2341x_log_status(struct cx2341x_mpeg_params *p, const char *prefix)
- 		cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_L2_BITRATE),
- 		cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_MODE),
- 		p->audio_mute ? " (muted)" : "");
--	if (p->audio_mode == V4L2_MPEG_AUDIO_MODE_JOINT_STEREO) {
--		printk(", %s",
--			cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_MODE_EXTENSION));
--	}
-+	if (p->audio_mode == V4L2_MPEG_AUDIO_MODE_JOINT_STEREO)
-+		printk(", %s", cx2341x_menu_item(p,
-+				V4L2_CID_MPEG_AUDIO_MODE_EXTENSION));
- 	printk(", %s, %s\n",
- 		cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_EMPHASIS),
- 		cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_CRC));
-@@ -975,33 +1010,33 @@ void cx2341x_log_status(struct cx2341x_mpeg_params *p, const char *prefix)
- 	/* Encoding filters */
- 	printk(KERN_INFO "%s: Spatial Filter:  %s, Luma %s, Chroma %s, %d\n",
- 		prefix,
--		cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE),
--		cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE),
--		cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE),
-+		cx2341x_menu_item(p,
-+		    V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE),
-+		cx2341x_menu_item(p,
-+		    V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE),
-+		cx2341x_menu_item(p,
-+		    V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE),
- 		p->video_spatial_filter);
--	if (p->width != 720 || p->height != (p->is_50hz ? 576 : 480)) {
++static void cx23885_initialize(struct i2c_client *client)
++{
++	DEFINE_WAIT(wait);
++	struct cx25840_state *state = i2c_get_clientdata(client);
++	struct workqueue_struct *q;
 +
-+	if (p->width != 720 || p->height != (p->is_50hz ? 576 : 480))
- 		temporal = 0;
--	}
++	/* Internal Reset */
++	cx25840_and_or(client, 0x102, ~0x01, 0x01);
++	cx25840_and_or(client, 0x102, ~0x01, 0x00);
 +
- 	printk(KERN_INFO "%s: Temporal Filter: %s, %d\n",
- 		prefix,
--		cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE),
-+		cx2341x_menu_item(p,
-+			V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE),
- 		temporal);
--	printk(KERN_INFO "%s: Median Filter:   %s, Luma [%d, %d], Chroma [%d, %d]\n",
-+	printk(KERN_INFO
-+		"%s: Median Filter:   %s, Luma [%d, %d], Chroma [%d, %d]\n",
- 		prefix,
--		cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE),
-+		cx2341x_menu_item(p,
-+			V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE),
- 		p->video_luma_median_filter_bottom,
- 		p->video_luma_median_filter_top,
- 		p->video_chroma_median_filter_bottom,
- 		p->video_chroma_median_filter_top);
- }
--
--EXPORT_SYMBOL(cx2341x_fill_defaults);
--EXPORT_SYMBOL(cx2341x_ctrl_query);
--EXPORT_SYMBOL(cx2341x_ctrl_get_menu);
--EXPORT_SYMBOL(cx2341x_ext_ctrls);
--EXPORT_SYMBOL(cx2341x_update);
- EXPORT_SYMBOL(cx2341x_log_status);
--EXPORT_SYMBOL(cx2341x_mpeg_ctrls);
- 
- /*
-  * Local variables:
-diff --git a/drivers/media/video/cx23885/Kconfig b/drivers/media/video/cx23885/Kconfig
-index 081ee6e..1fd326f 100644
---- a/drivers/media/video/cx23885/Kconfig
-+++ b/drivers/media/video/cx23885/Kconfig
-@@ -12,6 +12,10 @@ config VIDEO_CX23885
- 	select DVB_S5H1409 if !DVB_FE_CUSTOMISE
- 	select DVB_LGDT330X if !DVB_FE_CUSTOMISE
- 	select DVB_PLL if !DVB_FE_CUSTOMISE
-+	select TUNER_XC2028 if !DVB_FE_CUSTOMIZE
-+	select TUNER_TDA8290 if !DVB_FE_CUSTOMIZE
-+	select DVB_TDA18271 if !DVB_FE_CUSTOMIZE
-+	select DVB_TUNER_XC5000 if !DVB_FE_CUSTOMIZE
- 	---help---
- 	  This is a video4linux driver for Conexant 23885 based
- 	  TV cards.
-diff --git a/drivers/media/video/cx23885/Makefile b/drivers/media/video/cx23885/Makefile
-index 6650670..32c90be 100644
---- a/drivers/media/video/cx23885/Makefile
-+++ b/drivers/media/video/cx23885/Makefile
-@@ -1,4 +1,4 @@
--cx23885-objs	:= cx23885-cards.o cx23885-core.o cx23885-i2c.o cx23885-dvb.o
-+cx23885-objs	:= cx23885-cards.o cx23885-video.o cx23885-vbi.o cx23885-core.o cx23885-i2c.o cx23885-dvb.o
++	/* Stop microcontroller */
++	cx25840_and_or(client, 0x803, ~0x10, 0x00);
++
++	/* DIF in reset? */
++	cx25840_write(client, 0x398, 0);
++
++	/* Trust the default xtal, no division */
++	/* This changes for the cx23888 products */
++	cx25840_write(client, 0x2, 0x76);
++
++	/* Bring down the regulator for AUX clk */
++	cx25840_write(client, 0x1, 0x40);
++
++	/* Sys PLL frac */
++	cx25840_write4(client, 0x11c, 0x01d1744c);
++
++	/* Sys PLL int */
++	cx25840_write4(client, 0x118, 0x00000416);
++
++	/* Disable DIF bypass */
++	cx25840_write4(client, 0x33c, 0x00000001);
++
++	/* DIF Src phase inc */
++	cx25840_write4(client, 0x340, 0x0df7df83);
++
++	/* Vid PLL frac */
++	cx25840_write4(client, 0x10c, 0x01b6db7b);
++
++	/* Vid PLL int */
++	cx25840_write4(client, 0x108, 0x00000512);
++
++	/* Luma */
++	cx25840_write4(client, 0x414, 0x00107d12);
++
++	/* Chroma */
++	cx25840_write4(client, 0x420, 0x3d008282);
++
++	/* Aux PLL frac */
++	cx25840_write4(client, 0x114, 0x017dbf48);
++
++	/* Aux PLL int */
++	cx25840_write4(client, 0x110, 0x000a030e);
++
++	/* ADC2 input select */
++	cx25840_write(client, 0x102, 0x10);
++
++	/* VIN1 & VIN5 */
++	cx25840_write(client, 0x103, 0x11);
++
++	/* Enable format auto detect */
++	cx25840_write(client, 0x400, 0);
++	/* Fast subchroma lock */
++	/* White crush, Chroma AGC & Chroma Killer enabled */
++	cx25840_write(client, 0x401, 0xe8);
++
++	/* Select AFE clock pad output source */
++	cx25840_write(client, 0x144, 0x05);
++
++	/* Do the firmware load in a work handler to prevent.
++	   Otherwise the kernel is blocked waiting for the
++	   bit-banging i2c interface to finish uploading the
++	   firmware. */
++	INIT_WORK(&state->fw_work, cx25840_work_handler);
++	init_waitqueue_head(&state->fw_wait);
++	q = create_singlethread_workqueue("cx25840_fw");
++	prepare_to_wait(&state->fw_wait, &wait, TASK_UNINTERRUPTIBLE);
++	queue_work(q, &state->fw_work);
++	schedule();
++	finish_wait(&state->fw_wait, &wait);
++	destroy_workqueue(q);
++
++	cx25840_vbi_setup(client);
++
++	/* (re)set input */
++	set_input(client, state->vid_input, state->aud_input);
++
++	/* start microcontroller */
++	cx25840_and_or(client, 0x803, ~0x10, 0x10);
++}
++
+ /* ----------------------------------------------------------------------- */
  
- obj-$(CONFIG_VIDEO_CX23885) += cx23885.o
+ static void input_change(struct i2c_client *client)
+@@ -319,9 +410,22 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp
+ 			   vid_input <= CX25840_COMPOSITE8);
+ 	u8 reg;
  
-diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c
-index b9012ac..2d414da 100644
---- a/drivers/media/video/cx23885/cx23885-cards.c
-+++ b/drivers/media/video/cx23885/cx23885-cards.c
-@@ -23,6 +23,7 @@
- #include <linux/module.h>
- #include <linux/pci.h>
- #include <linux/delay.h>
-+#include <media/cx25840.h>
+-	v4l_dbg(1, cx25840_debug, client, "decoder set video input %d, audio input %d\n",
+-			vid_input, aud_input);
++	v4l_dbg(1, cx25840_debug, client,
++		"decoder set video input %d, audio input %d\n",
++		vid_input, aud_input);
++
++	if (vid_input >= CX25840_VIN1_CH1) {
++		v4l_dbg(1, cx25840_debug, client, "vid_input 0x%x\n",
++			vid_input);
++		reg = vid_input & 0xff;
++		if ((vid_input & CX25840_SVIDEO_ON) == CX25840_SVIDEO_ON)
++			is_composite = 0;
++		else
++			is_composite = 1;
  
- #include "cx23885.h"
++		v4l_dbg(1, cx25840_debug, client, "mux cfg 0x%x comp=%d\n",
++			reg, is_composite);
++	} else
+ 	if (is_composite) {
+ 		reg = 0xf0 + (vid_input - CX25840_COMPOSITE1);
+ 	} else {
+@@ -331,7 +435,8 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp
+ 		if ((vid_input & ~0xff0) ||
+ 		    luma < CX25840_SVIDEO_LUMA1 || luma > CX25840_SVIDEO_LUMA4 ||
+ 		    chroma < CX25840_SVIDEO_CHROMA4 || chroma > CX25840_SVIDEO_CHROMA8) {
+-			v4l_err(client, "0x%04x is not a valid video input!\n", vid_input);
++			v4l_err(client, "0x%04x is not a valid video input!\n",
++				vid_input);
+ 			return -EINVAL;
+ 		}
+ 		reg = 0xf0 + ((luma - CX25840_SVIDEO_LUMA1) >> 4);
+@@ -344,31 +449,49 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp
+ 		}
+ 	}
  
-@@ -32,6 +33,8 @@
- struct cx23885_board cx23885_boards[] = {
- 	[CX23885_BOARD_UNKNOWN] = {
- 		.name		= "UNKNOWN/GENERIC",
-+		/* Ensure safe default for unknown boards */
-+		.clk_freq       = 0,
- 		.input          = {{
- 			.type   = CX23885_VMUX_COMPOSITE1,
- 			.vmux   = 0,
-@@ -69,23 +72,29 @@ struct cx23885_board cx23885_boards[] = {
- 	},
- 	[CX23885_BOARD_HAUPPAUGE_HVR1800] = {
- 		.name		= "Hauppauge WinTV-HVR1800",
-+		.porta		= CX23885_ANALOG_VIDEO,
- 		.portc		= CX23885_MPEG_DVB,
-+		.tuner_type	= TUNER_PHILIPS_TDA8290,
-+		.tuner_addr	= 0x42, /* 0x84 >> 1 */
- 		.input          = {{
- 			.type   = CX23885_VMUX_TELEVISION,
--			.vmux   = 0,
--			.gpio0  = 0xff00,
--		},{
--			.type   = CX23885_VMUX_DEBUG,
--			.vmux   = 0,
--			.gpio0  = 0xff01,
-+			.vmux   =	CX25840_VIN7_CH3 |
-+					CX25840_VIN5_CH2 |
-+					CX25840_VIN2_CH1,
-+			.gpio0  = 0,
- 		},{
- 			.type   = CX23885_VMUX_COMPOSITE1,
--			.vmux   = 1,
--			.gpio0  = 0xff02,
-+			.vmux   =	CX25840_VIN7_CH3 |
-+					CX25840_VIN4_CH2 |
-+					CX25840_VIN6_CH1,
-+			.gpio0  = 0,
- 		},{
- 			.type   = CX23885_VMUX_SVIDEO,
--			.vmux   = 2,
--			.gpio0  = 0xff02,
-+			.vmux   =	CX25840_VIN7_CH3 |
-+					CX25840_VIN4_CH2 |
-+					CX25840_VIN8_CH1 |
-+					CX25840_SVIDEO_ON,
-+			.gpio0  = 0,
- 		}},
- 	},
- 	[CX23885_BOARD_HAUPPAUGE_HVR1250] = {
-@@ -113,6 +122,14 @@ struct cx23885_board cx23885_boards[] = {
- 		.name		= "DViCO FusionHDTV5 Express",
- 		.portb		= CX23885_MPEG_DVB,
- 	},
-+	[CX23885_BOARD_HAUPPAUGE_HVR1500Q] = {
-+		.name		= "Hauppauge WinTV-HVR1500Q",
-+		.portc		= CX23885_MPEG_DVB,
-+	},
-+	[CX23885_BOARD_HAUPPAUGE_HVR1500] = {
-+		.name		= "Hauppauge WinTV-HVR1500",
-+		.portc		= CX23885_MPEG_DVB,
-+	},
- };
- const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards);
+-	switch (aud_input) {
+-	case CX25840_AUDIO_SERIAL:
+-		/* do nothing, use serial audio input */
+-		break;
+-	case CX25840_AUDIO4: reg &= ~0x30; break;
+-	case CX25840_AUDIO5: reg &= ~0x30; reg |= 0x10; break;
+-	case CX25840_AUDIO6: reg &= ~0x30; reg |= 0x20; break;
+-	case CX25840_AUDIO7: reg &= ~0xc0; break;
+-	case CX25840_AUDIO8: reg &= ~0xc0; reg |= 0x40; break;
++	/* The caller has previously prepared the correct routing
++	 * configuration in reg (for the cx23885) so we have no
++	 * need to attempt to flip bits for earlier av decoders.
++	 */
++	if (!state->is_cx23885) {
++		switch (aud_input) {
++		case CX25840_AUDIO_SERIAL:
++			/* do nothing, use serial audio input */
++			break;
++		case CX25840_AUDIO4: reg &= ~0x30; break;
++		case CX25840_AUDIO5: reg &= ~0x30; reg |= 0x10; break;
++		case CX25840_AUDIO6: reg &= ~0x30; reg |= 0x20; break;
++		case CX25840_AUDIO7: reg &= ~0xc0; break;
++		case CX25840_AUDIO8: reg &= ~0xc0; reg |= 0x40; break;
  
-@@ -138,12 +155,32 @@ struct cx23885_subid cx23885_subids[] = {
- 		.card      = CX23885_BOARD_HAUPPAUGE_HVR1800,
- 	},{
- 		.subvendor = 0x0070,
-+		.subdevice = 0x7809,
-+		.card      = CX23885_BOARD_HAUPPAUGE_HVR1800,
-+	},{
-+		.subvendor = 0x0070,
- 		.subdevice = 0x7911,
- 		.card      = CX23885_BOARD_HAUPPAUGE_HVR1250,
- 	},{
- 		.subvendor = 0x18ac,
- 		.subdevice = 0xd500,
- 		.card      = CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP,
-+	},{
-+		.subvendor = 0x0070,
-+		.subdevice = 0x7790,
-+		.card      = CX23885_BOARD_HAUPPAUGE_HVR1500Q,
-+	},{
-+		.subvendor = 0x0070,
-+		.subdevice = 0x7797,
-+		.card      = CX23885_BOARD_HAUPPAUGE_HVR1500Q,
-+	},{
-+		.subvendor = 0x0070,
-+		.subdevice = 0x7710,
-+		.card      = CX23885_BOARD_HAUPPAUGE_HVR1500,
-+	},{
-+		.subvendor = 0x0070,
-+		.subdevice = 0x7717,
-+		.card      = CX23885_BOARD_HAUPPAUGE_HVR1500,
- 	},
- };
- const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids);
-@@ -184,9 +221,19 @@ static void hauppauge_eeprom(struct cx23885_dev *dev, u8 *eeprom_data)
- 	switch (tv.model)
- 	{
- 	case 76601: /* WinTV-HVR1800lp (PCIe, Retail, No IR, Dual channel ATSC and MPEG2 HW Encoder */
--	case 77001: /* WinTV-HVR1500 (Express Card, Retail, No IR, ATSC and Basic analog */
--	case 78501: /* WinTV-HVR1800 (PCIe, Retail, IR, Dual channel ATSC and MPEG2 HW Encoder */
--	case 78521: /* WinTV-HVR1800 (PCIe, Retail, IR, Dual channel ATSC and MPEG2 HW Encoder */
-+	case 77001: /* WinTV-HVR1500 (Express Card, OEM, No IR, ATSC and Basic analog */
-+	case 77011: /* WinTV-HVR1500 (Express Card, Retail, No IR, ATSC and Basic analog */
-+	case 77041: /* WinTV-HVR1500Q (Express Card, OEM, No IR, ATSC/QAM and Basic analog */
-+	case 77051: /* WinTV-HVR1500Q (Express Card, Retail, No IR, ATSC/QAM and Basic analog */
-+	case 78011: /* WinTV-HVR1800 (PCIe, Retail, 3.5mm in, IR, No FM, Dual channel ATSC and MPEG2 HW Encoder */
-+	case 78501: /* WinTV-HVR1800 (PCIe, OEM, RCA in, No IR, FM, Dual channel ATSC and MPEG2 HW Encoder */
-+	case 78521: /* WinTV-HVR1800 (PCIe, OEM, RCA in, No IR, FM, Dual channel ATSC and MPEG2 HW Encoder */
-+	case 78531: /* WinTV-HVR1800 (PCIe, OEM, RCA in, No IR, No FM, Dual channel ATSC and MPEG2 HW Encoder */
-+	case 78631: /* WinTV-HVR1800 (PCIe, OEM, No IR, No FM, Dual channel ATSC and MPEG2 HW Encoder */
-+	case 79001: /* WinTV-HVR1250 (PCIe, Retail, IR, full height, ATSC and Basic analog */
-+	case 79101: /* WinTV-HVR1250 (PCIe, Retail, IR, half height, ATSC and Basic analog */
-+	case 79571: /* WinTV-HVR1250 (PCIe, OEM, No IR, full height, ATSC and Basic analog */
-+	case 79671: /* WinTV-HVR1250 (PCIe, OEM, No IR, half height, ATSC and Basic analog */
- 		break;
- 	default:
- 		printk("%s: warning: unknown hauppauge model #%d\n", dev->name, tv.model);
-@@ -197,6 +244,34 @@ static void hauppauge_eeprom(struct cx23885_dev *dev, u8 *eeprom_data)
- 			dev->name, tv.model);
+-	default:
+-		v4l_err(client, "0x%04x is not a valid audio input!\n", aud_input);
+-		return -EINVAL;
++		default:
++			v4l_err(client, "0x%04x is not a valid audio input!\n",
++				aud_input);
++			return -EINVAL;
++		}
+ 	}
+ 
+ 	cx25840_write(client, 0x103, reg);
++
+ 	/* Set INPUT_MODE to Composite (0) or S-Video (1) */
+ 	cx25840_and_or(client, 0x401, ~0x6, is_composite ? 0 : 0x02);
+-	/* Set CH_SEL_ADC2 to 1 if input comes from CH3 */
+-	cx25840_and_or(client, 0x102, ~0x2, (reg & 0x80) == 0 ? 2 : 0);
+-	/* Set DUAL_MODE_ADC2 to 1 if input comes from both CH2 and CH3 */
+-	if ((reg & 0xc0) != 0xc0 && (reg & 0x30) != 0x30)
+-		cx25840_and_or(client, 0x102, ~0x4, 4);
+-	else
+-		cx25840_and_or(client, 0x102, ~0x4, 0);
++
++	if (!state->is_cx23885) {
++		/* Set CH_SEL_ADC2 to 1 if input comes from CH3 */
++		cx25840_and_or(client, 0x102, ~0x2, (reg & 0x80) == 0 ? 2 : 0);
++		/* Set DUAL_MODE_ADC2 to 1 if input comes from both CH2&CH3 */
++		if ((reg & 0xc0) != 0xc0 && (reg & 0x30) != 0x30)
++			cx25840_and_or(client, 0x102, ~0x4, 4);
++		else
++			cx25840_and_or(client, 0x102, ~0x4, 0);
++	} else {
++		if (is_composite)
++			/* ADC2 input select channel 2 */
++			cx25840_and_or(client, 0x102, ~0x2, 0);
++		else
++			/* ADC2 input select channel 3 */
++			cx25840_and_or(client, 0x102, ~0x2, 2);
++	}
+ 
+ 	state->vid_input = vid_input;
+ 	state->aud_input = aud_input;
+@@ -376,6 +499,25 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp
+ 		cx25840_audio_set_path(client);
+ 		input_change(client);
+ 	}
++
++	if (state->is_cx23885) {
++		/* Audio channel 1 src : Parallel 1 */
++		cx25840_write(client, 0x124, 0x03);
++
++		/* Select AFE clock pad output source */
++		cx25840_write(client, 0x144, 0x05);
++
++		/* I2S_IN_CTL: I2S_IN_SONY_MODE, LEFT SAMPLE on WS=1 */
++		cx25840_write(client, 0x914, 0xa0);
++
++		/* I2S_OUT_CTL:
++		 * I2S_IN_SONY_MODE, LEFT SAMPLE on WS=1
++		 * I2S_OUT_MASTER_MODE = Master
++		 */
++		cx25840_write(client, 0x918, 0xa0);
++		cx25840_write(client, 0x919, 0x01);
++	}
++
+ 	return 0;
  }
  
-+/* 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)
+@@ -641,6 +783,200 @@ static int set_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt)
+ 
+ /* ----------------------------------------------------------------------- */
+ 
++static void log_video_status(struct i2c_client *client)
 +{
-+	struct cx23885_i2c *bus = priv;
-+	struct cx23885_dev *dev = bus->dev;
++	static const char *const fmt_strs[] = {
++		"0x0",
++		"NTSC-M", "NTSC-J", "NTSC-4.43",
++		"PAL-BDGHI", "PAL-M", "PAL-N", "PAL-Nc", "PAL-60",
++		"0x9", "0xA", "0xB",
++		"SECAM",
++		"0xD", "0xE", "0xF"
++	};
 +
-+	switch(dev->board) {
-+	case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
-+		if(command == 0) {	/* Tuner Reset Command from xc5000 */
-+			/* Drive the tuner into reset and out */
-+			cx_clear(GP0_IO, 0x00000004);
-+			mdelay(200);
-+			cx_set(GP0_IO, 0x00000004);
-+			return 0;
++	struct cx25840_state *state = i2c_get_clientdata(client);
++	u8 vidfmt_sel = cx25840_read(client, 0x400) & 0xf;
++	u8 gen_stat1 = cx25840_read(client, 0x40d);
++	u8 gen_stat2 = cx25840_read(client, 0x40e);
++	int vid_input = state->vid_input;
++
++	v4l_info(client, "Video signal:              %spresent\n",
++		    (gen_stat2 & 0x20) ? "" : "not ");
++	v4l_info(client, "Detected format:           %s\n",
++		    fmt_strs[gen_stat1 & 0xf]);
++
++	v4l_info(client, "Specified standard:        %s\n",
++		    vidfmt_sel ? fmt_strs[vidfmt_sel] : "automatic detection");
++
++	if (vid_input >= CX25840_COMPOSITE1 &&
++	    vid_input <= CX25840_COMPOSITE8) {
++		v4l_info(client, "Specified video input:     Composite %d\n",
++			vid_input - CX25840_COMPOSITE1 + 1);
++	} else {
++		v4l_info(client, "Specified video input:     S-Video (Luma In%d, Chroma In%d)\n",
++			(vid_input & 0xf0) >> 4, (vid_input & 0xf00) >> 8);
++	}
++
++	v4l_info(client, "Specified audioclock freq: %d Hz\n", state->audclk_freq);
++}
++
++/* ----------------------------------------------------------------------- */
++
++static void log_audio_status(struct i2c_client *client)
++{
++	struct cx25840_state *state = i2c_get_clientdata(client);
++	u8 download_ctl = cx25840_read(client, 0x803);
++	u8 mod_det_stat0 = cx25840_read(client, 0x804);
++	u8 mod_det_stat1 = cx25840_read(client, 0x805);
++	u8 audio_config = cx25840_read(client, 0x808);
++	u8 pref_mode = cx25840_read(client, 0x809);
++	u8 afc0 = cx25840_read(client, 0x80b);
++	u8 mute_ctl = cx25840_read(client, 0x8d3);
++	int aud_input = state->aud_input;
++	char *p;
++
++	switch (mod_det_stat0) {
++	case 0x00: p = "mono"; break;
++	case 0x01: p = "stereo"; break;
++	case 0x02: p = "dual"; break;
++	case 0x04: p = "tri"; break;
++	case 0x10: p = "mono with SAP"; break;
++	case 0x11: p = "stereo with SAP"; break;
++	case 0x12: p = "dual with SAP"; break;
++	case 0x14: p = "tri with SAP"; break;
++	case 0xfe: p = "forced mode"; break;
++	default: p = "not defined";
++	}
++	v4l_info(client, "Detected audio mode:       %s\n", p);
++
++	switch (mod_det_stat1) {
++	case 0x00: p = "not defined"; break;
++	case 0x01: p = "EIAJ"; break;
++	case 0x02: p = "A2-M"; break;
++	case 0x03: p = "A2-BG"; break;
++	case 0x04: p = "A2-DK1"; break;
++	case 0x05: p = "A2-DK2"; break;
++	case 0x06: p = "A2-DK3"; break;
++	case 0x07: p = "A1 (6.0 MHz FM Mono)"; break;
++	case 0x08: p = "AM-L"; break;
++	case 0x09: p = "NICAM-BG"; break;
++	case 0x0a: p = "NICAM-DK"; break;
++	case 0x0b: p = "NICAM-I"; break;
++	case 0x0c: p = "NICAM-L"; break;
++	case 0x0d: p = "BTSC/EIAJ/A2-M Mono (4.5 MHz FMMono)"; break;
++	case 0x0e: p = "IF FM Radio"; break;
++	case 0x0f: p = "BTSC"; break;
++	case 0x10: p = "high-deviation FM"; break;
++	case 0x11: p = "very high-deviation FM"; break;
++	case 0xfd: p = "unknown audio standard"; break;
++	case 0xfe: p = "forced audio standard"; break;
++	case 0xff: p = "no detected audio standard"; break;
++	default: p = "not defined";
++	}
++	v4l_info(client, "Detected audio standard:   %s\n", p);
++	v4l_info(client, "Audio muted:               %s\n",
++		    (state->unmute_volume >= 0) ? "yes" : "no");
++	v4l_info(client, "Audio microcontroller:     %s\n",
++		    (download_ctl & 0x10) ?
++				((mute_ctl & 0x2) ? "detecting" : "running") : "stopped");
++
++	switch (audio_config >> 4) {
++	case 0x00: p = "undefined"; break;
++	case 0x01: p = "BTSC"; break;
++	case 0x02: p = "EIAJ"; break;
++	case 0x03: p = "A2-M"; break;
++	case 0x04: p = "A2-BG"; break;
++	case 0x05: p = "A2-DK1"; break;
++	case 0x06: p = "A2-DK2"; break;
++	case 0x07: p = "A2-DK3"; break;
++	case 0x08: p = "A1 (6.0 MHz FM Mono)"; break;
++	case 0x09: p = "AM-L"; break;
++	case 0x0a: p = "NICAM-BG"; break;
++	case 0x0b: p = "NICAM-DK"; break;
++	case 0x0c: p = "NICAM-I"; break;
++	case 0x0d: p = "NICAM-L"; break;
++	case 0x0e: p = "FM radio"; break;
++	case 0x0f: p = "automatic detection"; break;
++	default: p = "undefined";
++	}
++	v4l_info(client, "Configured audio standard: %s\n", p);
++
++	if ((audio_config >> 4) < 0xF) {
++		switch (audio_config & 0xF) {
++		case 0x00: p = "MONO1 (LANGUAGE A/Mono L+R channel for BTSC, EIAJ, A2)"; break;
++		case 0x01: p = "MONO2 (LANGUAGE B)"; break;
++		case 0x02: p = "MONO3 (STEREO forced MONO)"; break;
++		case 0x03: p = "MONO4 (NICAM ANALOG-Language C/Analog Fallback)"; break;
++		case 0x04: p = "STEREO"; break;
++		case 0x05: p = "DUAL1 (AB)"; break;
++		case 0x06: p = "DUAL2 (AC) (FM)"; break;
++		case 0x07: p = "DUAL3 (BC) (FM)"; break;
++		case 0x08: p = "DUAL4 (AC) (AM)"; break;
++		case 0x09: p = "DUAL5 (BC) (AM)"; break;
++		case 0x0a: p = "SAP"; break;
++		default: p = "undefined";
 +		}
-+		else {
-+			printk(KERN_ERR
-+				"%s(): Unknow command.\n", __FUNCTION__);
-+			return -EINVAL;
++		v4l_info(client, "Configured audio mode:     %s\n", p);
++	} else {
++		switch (audio_config & 0xF) {
++		case 0x00: p = "BG"; break;
++		case 0x01: p = "DK1"; break;
++		case 0x02: p = "DK2"; break;
++		case 0x03: p = "DK3"; break;
++		case 0x04: p = "I"; break;
++		case 0x05: p = "L"; break;
++		case 0x06: p = "BTSC"; break;
++		case 0x07: p = "EIAJ"; break;
++		case 0x08: p = "A2-M"; break;
++		case 0x09: p = "FM Radio"; break;
++		case 0x0f: p = "automatic standard and mode detection"; break;
++		default: p = "undefined";
 +		}
-+		break;
++		v4l_info(client, "Configured audio system:   %s\n", p);
 +	}
 +
-+	return 0; /* Should never be here */
-+}
++	if (aud_input) {
++		v4l_info(client, "Specified audio input:     Tuner (In%d)\n", aud_input);
++	} else {
++		v4l_info(client, "Specified audio input:     External\n");
++	}
 +
- void cx23885_gpio_setup(struct cx23885_dev *dev)
- {
- 	switch(dev->board) {
-@@ -204,6 +279,23 @@ void cx23885_gpio_setup(struct cx23885_dev *dev)
- 		/* GPIO-0 cx24227 demodulator reset */
- 		cx_set(GP0_IO, 0x00010001); /* Bring the part out of reset */
- 		break;
-+	case CX23885_BOARD_HAUPPAUGE_HVR1500:
-+		/* GPIO-0 cx24227 demodulator */
-+		/* GPIO-2 xc3028 tuner */
++	switch (pref_mode & 0xf) {
++	case 0: p = "mono/language A"; break;
++	case 1: p = "language B"; break;
++	case 2: p = "language C"; break;
++	case 3: p = "analog fallback"; break;
++	case 4: p = "stereo"; break;
++	case 5: p = "language AC"; break;
++	case 6: p = "language BC"; break;
++	case 7: p = "language AB"; break;
++	default: p = "undefined";
++	}
++	v4l_info(client, "Preferred audio mode:      %s\n", p);
 +
-+		/* Put the parts into reset */
-+		cx_set(GP0_IO, 0x00050000);
-+		cx_clear(GP0_IO, 0x00000005);
-+		msleep(5);
++	if ((audio_config & 0xf) == 0xf) {
++		switch ((afc0 >> 3) & 0x3) {
++		case 0: p = "system DK"; break;
++		case 1: p = "system L"; break;
++		case 2: p = "autodetect"; break;
++		default: p = "undefined";
++		}
++		v4l_info(client, "Selected 65 MHz format:    %s\n", p);
 +
-+		/* Bring the parts out of reset */
-+		cx_set(GP0_IO, 0x00050005);
-+		break;
-+	case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
-+		/* GPIO-0 cx24227 demodulator reset */
-+		/* GPIO-2 xc5000 tuner reset */
-+		cx_set(GP0_IO, 0x00050005); /* Bring the part out of reset */
-+		break;
- 	case CX23885_BOARD_HAUPPAUGE_HVR1800:
- 		/* GPIO-0 656_CLK */
- 		/* GPIO-1 656_D0 */
-@@ -212,7 +304,14 @@ void cx23885_gpio_setup(struct cx23885_dev *dev)
- 		/* GPIO-11-14 cx23417 addr0-3 */
- 		/* GPIO-15-18 cx23417 READY, CS, RD, WR */
- 		/* GPIO-19 IR_RX */
--		// FIXME: Analog requires the tuner is brought out of reset
++		switch (afc0 & 0x7) {
++		case 0: p = "chroma"; break;
++		case 1: p = "BTSC"; break;
++		case 2: p = "EIAJ"; break;
++		case 3: p = "A2-M"; break;
++		case 4: p = "autodetect"; break;
++		default: p = "undefined";
++		}
++		v4l_info(client, "Selected 45 MHz format:    %s\n", p);
++	}
++}
 +
-+		/* Force the TDA8295A into reset and back */
-+		cx_set(GP0_IO, 0x00040004);
-+		mdelay(20);
-+		cx_clear(GP0_IO, 0x00000004);
-+		mdelay(20);
-+		cx_set(GP0_IO, 0x00040004);
-+		mdelay(20);
- 		break;
- 	}
- }
-@@ -221,6 +320,8 @@ int cx23885_ir_init(struct cx23885_dev *dev)
++/* ----------------------------------------------------------------------- */
++
+ static int cx25840_command(struct i2c_client *client, unsigned int cmd,
+ 			   void *arg)
  {
- 	switch (dev->board) {
- 	case CX23885_BOARD_HAUPPAUGE_HVR1250:
-+	case CX23885_BOARD_HAUPPAUGE_HVR1500:
-+	case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
- 	case CX23885_BOARD_HAUPPAUGE_HVR1800:
- 		/* FIXME: Implement me */
- 		break;
-@@ -244,6 +345,8 @@ void cx23885_card_setup(struct cx23885_dev *dev)
+@@ -660,6 +996,8 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd,
+ 		state->is_initialized = 1;
+ 		if (state->is_cx25836)
+ 			cx25836_initialize(client);
++		else if (state->is_cx23885)
++			cx23885_initialize(client);
+ 		else
+ 			cx25840_initialize(client);
+ 	}
+@@ -677,6 +1015,7 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd,
+ 			return -EINVAL;
+ 		if (!capable(CAP_SYS_ADMIN))
+ 			return -EPERM;
++
+ 		if (cmd == VIDIOC_DBG_G_REGISTER)
+ 			reg->val = cx25840_read(client, reg->reg & 0x0fff);
+ 		else
+@@ -693,14 +1032,26 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd,
  
- 	switch (dev->board) {
- 	case CX23885_BOARD_HAUPPAUGE_HVR1250:
-+	case CX23885_BOARD_HAUPPAUGE_HVR1500:
-+	case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
- 	case CX23885_BOARD_HAUPPAUGE_HVR1800:
- 	case CX23885_BOARD_HAUPPAUGE_HVR1800lp:
- 		if (dev->i2c_bus[0].i2c_rc == 0)
-@@ -258,6 +361,8 @@ void cx23885_card_setup(struct cx23885_dev *dev)
- 		ts1->src_sel_val   = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
+ 	case VIDIOC_STREAMON:
+ 		v4l_dbg(1, cx25840_debug, client, "enable output\n");
+-		cx25840_write(client, 0x115, state->is_cx25836 ? 0x0c : 0x8c);
+-		cx25840_write(client, 0x116, state->is_cx25836 ? 0x04 : 0x07);
++		if (state->is_cx23885) {
++			u8 v = (cx25840_read(client, 0x421) | 0x0b);
++			cx25840_write(client, 0x421, v);
++		} else {
++			cx25840_write(client, 0x115,
++				state->is_cx25836 ? 0x0c : 0x8c);
++			cx25840_write(client, 0x116,
++				state->is_cx25836 ? 0x04 : 0x07);
++		}
  		break;
- 	case CX23885_BOARD_HAUPPAUGE_HVR1250:
-+	case CX23885_BOARD_HAUPPAUGE_HVR1500:
-+	case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
- 	case CX23885_BOARD_HAUPPAUGE_HVR1800:
- 	case CX23885_BOARD_HAUPPAUGE_HVR1800lp:
- 	default:
-@@ -270,8 +375,6 @@ void cx23885_card_setup(struct cx23885_dev *dev)
- 
- /* ------------------------------------------------------------------ */
- 
--EXPORT_SYMBOL(cx23885_boards);
--
- /*
-  * Local variables:
-  * c-basic-offset: 8
-diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c
-index 3cdd136..8e40c7b 100644
---- a/drivers/media/video/cx23885/cx23885-core.c
-+++ b/drivers/media/video/cx23885/cx23885-core.c
-@@ -36,7 +36,7 @@ MODULE_DESCRIPTION("Driver for cx23885 based TV cards");
- MODULE_AUTHOR("Steven Toth <stoth at hauppauge.com>");
- MODULE_LICENSE("GPL");
- 
--static unsigned int debug = 0;
-+static unsigned int debug;
- module_param(debug,int,0644);
- MODULE_PARM_DESC(debug,"enable debug messages");
  
-@@ -44,13 +44,15 @@ static unsigned int card[]  = {[0 ... (CX23885_MAXBOARDS - 1)] = UNSET };
- module_param_array(card,  int, NULL, 0444);
- MODULE_PARM_DESC(card,"card type");
+ 	case VIDIOC_STREAMOFF:
+ 		v4l_dbg(1, cx25840_debug, client, "disable output\n");
+-		cx25840_write(client, 0x115, 0x00);
+-		cx25840_write(client, 0x116, 0x00);
++		if (state->is_cx23885) {
++			u8 v = cx25840_read(client, 0x421) & ~(0x0b);
++			cx25840_write(client, 0x421, v);
++		} else {
++			cx25840_write(client, 0x115, 0x00);
++			cx25840_write(client, 0x116, 0x00);
++		}
+ 		break;
  
--#define dprintk(level,fmt, arg...)	if (debug >= level) \
--	printk(KERN_DEBUG "%s/0: " fmt, dev->name , ## arg)
-+#define dprintk(level, fmt, arg...)\
-+	do { if (debug >= level)\
-+		printk(KERN_DEBUG "%s/0: " fmt, dev->name, ## arg);\
-+	} while (0)
+ 	case VIDIOC_LOG_STATUS:
+@@ -863,6 +1214,8 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd,
+ 	case VIDIOC_INT_RESET:
+ 		if (state->is_cx25836)
+ 			cx25836_initialize(client);
++		else if (state->is_cx23885)
++			cx23885_initialize(client);
+ 		else
+ 			cx25840_initialize(client);
+ 		break;
+@@ -879,35 +1232,21 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd,
  
- static unsigned int cx23885_devcount;
+ /* ----------------------------------------------------------------------- */
  
- static DEFINE_MUTEX(devlist);
--static LIST_HEAD(cx23885_devlist);
-+LIST_HEAD(cx23885_devlist);
+-static struct i2c_driver i2c_driver_cx25840;
+-
+-static int cx25840_detect_client(struct i2c_adapter *adapter, int address,
+-				 int kind)
++static int cx25840_probe(struct i2c_client *client)
+ {
+-	struct i2c_client *client;
+ 	struct cx25840_state *state;
+ 	u32 id;
+ 	u16 device_id;
  
- #define NO_SYNC_LINE (-1U)
+-	/* Check if the adapter supports the needed features
+-	 * Not until kernel version 2.6.11 did the bit-algo
+-	 * correctly report that it would do an I2C-level xfer */
+-	if (!i2c_check_functionality(adapter, I2C_FUNC_I2C))
+-		return 0;
+-
+-	client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
+-	if (client == 0)
+-		return -ENOMEM;
+-
+-	client->addr = address;
+-	client->adapter = adapter;
+-	client->driver = &i2c_driver_cx25840;
+-	snprintf(client->name, sizeof(client->name) - 1, "cx25840");
++	/* Check if the adapter supports the needed features */
++	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
++		return -EIO;
  
-@@ -73,14 +75,14 @@ static LIST_HEAD(cx23885_devlist);
-  * 0x00010ea0 0x00010xxx Free
-  */
+ 	v4l_dbg(1, cx25840_debug, client, "detecting cx25840 client on address 0x%x\n", client->addr << 1);
  
--struct sram_channel cx23885_sram_channels[] = {
-+static struct sram_channel cx23885_sram_channels[] = {
- 	[SRAM_CH01] = {
--		.name		= "test ch1",
-+		.name		= "VID A",
- 		.cmds_start	= 0x10000,
--		.ctrl_start	= 0x10500,
--		.cdt		= 0x10900,
--		.fifo_start	= 0x3000,
--		.fifo_size	= 0x1000,
-+		.ctrl_start	= 0x105b0,
-+		.cdt		= 0x107b0,
-+		.fifo_start	= 0x40,
-+		.fifo_size	= 0x2800,
- 		.ptr1_reg	= DMA1_PTR1,
- 		.ptr2_reg	= DMA1_PTR2,
- 		.cnt1_reg	= DMA1_CNT1,
-@@ -102,8 +104,8 @@ struct sram_channel cx23885_sram_channels[] = {
- 	[SRAM_CH03] = {
- 		.name		= "TS1 B",
- 		.cmds_start	= 0x100A0,
--		.ctrl_start	= 0x10780,
--		.cdt		= 0x10400,
-+		.ctrl_start	= 0x10630,
-+		.cdt		= 0x10870,
- 		.fifo_start	= 0x5000,
- 		.fifo_size	= 0x1000,
- 		.ptr1_reg	= DMA3_PTR1,
-@@ -139,7 +141,7 @@ struct sram_channel cx23885_sram_channels[] = {
- 		.name		= "TS2 C",
- 		.cmds_start	= 0x10140,
- 		.ctrl_start	= 0x10680,
--		.cdt		= 0x10480,
-+		.cdt		= 0x108d0,
- 		.fifo_start	= 0x6000,
- 		.fifo_size	= 0x1000,
- 		.ptr1_reg	= DMA5_PTR1,
-@@ -205,14 +207,14 @@ struct sram_channel cx23885_sram_channels[] = {
-  * 0x00010ea0 0x00010xxx Free
-  */
+ 	device_id = cx25840_read(client, 0x101) << 8;
+ 	device_id |= cx25840_read(client, 0x100);
++	v4l_dbg(1, cx25840_debug, client, "device_id = 0x%04x\n", device_id);
  
--struct sram_channel cx23887_sram_channels[] = {
-+static struct sram_channel cx23887_sram_channels[] = {
- 	[SRAM_CH01] = {
--		.name		= "test ch1",
--		.cmds_start	= 0x0,
--		.ctrl_start	= 0x0,
--		.cdt		= 0x0,
--		.fifo_start	= 0x0,
--		.fifo_size	= 0x0,
-+		.name		= "VID A",
-+		.cmds_start	= 0x10000,
-+		.ctrl_start	= 0x105b0,
-+		.cdt		= 0x107b0,
-+		.fifo_start	= 0x40,
-+		.fifo_size	= 0x2800,
- 		.ptr1_reg	= DMA1_PTR1,
- 		.ptr2_reg	= DMA1_PTR2,
- 		.cnt1_reg	= DMA1_CNT1,
-@@ -231,12 +233,12 @@ struct sram_channel cx23887_sram_channels[] = {
- 		.cnt2_reg	= DMA2_CNT2,
- 	},
- 	[SRAM_CH03] = {
--		.name		= "ch3",
--		.cmds_start	= 0x0,
--		.ctrl_start	= 0x0,
--		.cdt		= 0x0,
--		.fifo_start	= 0x0,
--		.fifo_size	= 0x0,
-+		.name		= "TS1 B",
-+		.cmds_start	= 0x100A0,
-+		.ctrl_start	= 0x10780,
-+		.cdt		= 0x10400,
-+		.fifo_start	= 0x5000,
-+		.fifo_size	= 0x1000,
- 		.ptr1_reg	= DMA3_PTR1,
- 		.ptr2_reg	= DMA3_PTR2,
- 		.cnt1_reg	= DMA3_CNT1,
-@@ -357,7 +359,7 @@ static int cx23885_risc_decode(u32 risc)
- }
+ 	/* The high byte of the device ID should be
+ 	 * 0x83 for the cx2583x and 0x84 for the cx2584x */
+@@ -916,16 +1255,18 @@ static int cx25840_detect_client(struct i2c_adapter *adapter, int address,
+ 	}
+ 	else if ((device_id & 0xff00) == 0x8400) {
+ 		id = V4L2_IDENT_CX25840 + ((device_id >> 4) & 0xf);
++	} else if (device_id == 0x0000) {
++		id = V4L2_IDENT_CX25836 + ((device_id >> 4) & 0xf) - 6;
++	} else if (device_id == 0x1313) {
++		id = V4L2_IDENT_CX25836 + ((device_id >> 4) & 0xf) - 6;
+ 	}
+ 	else {
+ 		v4l_dbg(1, cx25840_debug, client, "cx25840 not found\n");
+-		kfree(client);
+-		return 0;
++		return -ENODEV;
+ 	}
  
- void cx23885_wakeup(struct cx23885_tsport *port,
--		    struct cx23885_dmaqueue *q, u32 count)
-+			   struct cx23885_dmaqueue *q, u32 count)
- {
- 	struct cx23885_dev *dev = port->dev;
- 	struct cx23885_buffer *buf;
-@@ -378,7 +380,7 @@ void cx23885_wakeup(struct cx23885_tsport *port,
- 		do_gettimeofday(&buf->vb.ts);
- 		dprintk(2, "[%p/%d] wakeup reg=%d buf=%d\n", buf, buf->vb.i,
- 			count, buf->count);
--		buf->vb.state = STATE_DONE;
-+		buf->vb.state = VIDEOBUF_DONE;
- 		list_del(&buf->vb.queue);
- 		wake_up(&buf->vb.done);
+ 	state = kzalloc(sizeof(struct cx25840_state), GFP_KERNEL);
+ 	if (state == NULL) {
+-		kfree(client);
+ 		return -ENOMEM;
  	}
-@@ -391,12 +393,10 @@ void cx23885_wakeup(struct cx23885_tsport *port,
- 		printk("%s: %d buffers handled (should be 1)\n",
- 		       __FUNCTION__, bc);
- }
--void cx23885_sram_channel_dump(struct cx23885_dev *dev,
--			       struct sram_channel *ch);
  
- int cx23885_sram_channel_setup(struct cx23885_dev *dev,
--			       struct sram_channel *ch,
--			       unsigned int bpl, u32 risc)
-+				      struct sram_channel *ch,
-+				      unsigned int bpl, u32 risc)
- {
- 	unsigned int i, lines;
- 	u32 cdt;
-@@ -468,7 +468,7 @@ int cx23885_sram_channel_setup(struct cx23885_dev *dev,
- }
+@@ -939,6 +1280,7 @@ static int cx25840_detect_client(struct i2c_adapter *adapter, int address,
+ 	i2c_set_clientdata(client, state);
+ 	state->c = client;
+ 	state->is_cx25836 = ((device_id & 0xff00) == 0x8300);
++	state->is_cx23885 = (device_id == 0x0000) || (device_id == 0x1313);
+ 	state->vid_input = CX25840_COMPOSITE7;
+ 	state->aud_input = CX25840_AUDIO8;
+ 	state->audclk_freq = 48000;
+@@ -949,250 +1291,19 @@ static int cx25840_detect_client(struct i2c_adapter *adapter, int address,
+ 	state->id = id;
+ 	state->rev = device_id;
  
- void cx23885_sram_channel_dump(struct cx23885_dev *dev,
--			       struct sram_channel *ch)
-+				      struct sram_channel *ch)
- {
- 	static char *name[] = {
- 		"init risc lo",
-@@ -529,8 +529,8 @@ void cx23885_sram_channel_dump(struct cx23885_dev *dev,
- 	       dev->name, cx_read(ch->cnt2_reg));
+-	i2c_attach_client(client);
+-
+-	return 0;
+-}
+-
+-static int cx25840_attach_adapter(struct i2c_adapter *adapter)
+-{
+-	if (adapter->class & I2C_CLASS_TV_ANALOG)
+-		return i2c_probe(adapter, &addr_data, &cx25840_detect_client);
+ 	return 0;
  }
  
--void cx23885_risc_disasm(struct cx23885_tsport *port,
--			 struct btcx_riscmem *risc)
-+static void cx23885_risc_disasm(struct cx23885_tsport *port,
-+				struct btcx_riscmem *risc)
+-static int cx25840_detach_client(struct i2c_client *client)
++static int cx25840_remove(struct i2c_client *client)
  {
- 	struct cx23885_dev *dev = port->dev;
- 	unsigned int i, j, n;
-@@ -548,7 +548,7 @@ void cx23885_risc_disasm(struct cx23885_tsport *port,
- 	}
+-	struct cx25840_state *state = i2c_get_clientdata(client);
+-	int err;
+-
+-	err = i2c_detach_client(client);
+-	if (err) {
+-		return err;
+-	}
+-
+-	kfree(state);
+-	kfree(client);
+-
++	kfree(i2c_get_clientdata(client));
+ 	return 0;
  }
  
--void cx23885_shutdown(struct cx23885_dev *dev)
-+static void cx23885_shutdown(struct cx23885_dev *dev)
- {
- 	/* disable RISC controller */
- 	cx_write(DEV_CNTRL2, 0);
-@@ -578,7 +578,7 @@ void cx23885_shutdown(struct cx23885_dev *dev)
+-/* ----------------------------------------------------------------------- */
+-
+-static struct i2c_driver i2c_driver_cx25840 = {
+-	.driver = {
+-		.name = "cx25840",
+-	},
+-	.id = I2C_DRIVERID_CX25840,
+-	.attach_adapter = cx25840_attach_adapter,
+-	.detach_client = cx25840_detach_client,
++static struct v4l2_i2c_driver_data v4l2_i2c_data = {
++	.name = "cx25840",
++	.driverid = I2C_DRIVERID_CX25840,
+ 	.command = cx25840_command,
++	.probe = cx25840_probe,
++	.remove = cx25840_remove,
+ };
+-
+-
+-static int __init m__init(void)
+-{
+-	return i2c_add_driver(&i2c_driver_cx25840);
+-}
+-
+-static void __exit m__exit(void)
+-{
+-	i2c_del_driver(&i2c_driver_cx25840);
+-}
+-
+-module_init(m__init);
+-module_exit(m__exit);
+-
+-/* ----------------------------------------------------------------------- */
+-
+-static void log_video_status(struct i2c_client *client)
+-{
+-	static const char *const fmt_strs[] = {
+-		"0x0",
+-		"NTSC-M", "NTSC-J", "NTSC-4.43",
+-		"PAL-BDGHI", "PAL-M", "PAL-N", "PAL-Nc", "PAL-60",
+-		"0x9", "0xA", "0xB",
+-		"SECAM",
+-		"0xD", "0xE", "0xF"
+-	};
+-
+-	struct cx25840_state *state = i2c_get_clientdata(client);
+-	u8 vidfmt_sel = cx25840_read(client, 0x400) & 0xf;
+-	u8 gen_stat1 = cx25840_read(client, 0x40d);
+-	u8 gen_stat2 = cx25840_read(client, 0x40e);
+-	int vid_input = state->vid_input;
+-
+-	v4l_info(client, "Video signal:              %spresent\n",
+-		    (gen_stat2 & 0x20) ? "" : "not ");
+-	v4l_info(client, "Detected format:           %s\n",
+-		    fmt_strs[gen_stat1 & 0xf]);
+-
+-	v4l_info(client, "Specified standard:        %s\n",
+-		    vidfmt_sel ? fmt_strs[vidfmt_sel] : "automatic detection");
+-
+-	if (vid_input >= CX25840_COMPOSITE1 &&
+-	    vid_input <= CX25840_COMPOSITE8) {
+-		v4l_info(client, "Specified video input:     Composite %d\n",
+-			vid_input - CX25840_COMPOSITE1 + 1);
+-	} else {
+-		v4l_info(client, "Specified video input:     S-Video (Luma In%d, Chroma In%d)\n",
+-			(vid_input & 0xf0) >> 4, (vid_input & 0xf00) >> 8);
+-	}
+-
+-	v4l_info(client, "Specified audioclock freq: %d Hz\n", state->audclk_freq);
+-}
+-
+-/* ----------------------------------------------------------------------- */
+-
+-static void log_audio_status(struct i2c_client *client)
+-{
+-	struct cx25840_state *state = i2c_get_clientdata(client);
+-	u8 download_ctl = cx25840_read(client, 0x803);
+-	u8 mod_det_stat0 = cx25840_read(client, 0x804);
+-	u8 mod_det_stat1 = cx25840_read(client, 0x805);
+-	u8 audio_config = cx25840_read(client, 0x808);
+-	u8 pref_mode = cx25840_read(client, 0x809);
+-	u8 afc0 = cx25840_read(client, 0x80b);
+-	u8 mute_ctl = cx25840_read(client, 0x8d3);
+-	int aud_input = state->aud_input;
+-	char *p;
+-
+-	switch (mod_det_stat0) {
+-	case 0x00: p = "mono"; break;
+-	case 0x01: p = "stereo"; break;
+-	case 0x02: p = "dual"; break;
+-	case 0x04: p = "tri"; break;
+-	case 0x10: p = "mono with SAP"; break;
+-	case 0x11: p = "stereo with SAP"; break;
+-	case 0x12: p = "dual with SAP"; break;
+-	case 0x14: p = "tri with SAP"; break;
+-	case 0xfe: p = "forced mode"; break;
+-	default: p = "not defined";
+-	}
+-	v4l_info(client, "Detected audio mode:       %s\n", p);
+-
+-	switch (mod_det_stat1) {
+-	case 0x00: p = "not defined"; break;
+-	case 0x01: p = "EIAJ"; break;
+-	case 0x02: p = "A2-M"; break;
+-	case 0x03: p = "A2-BG"; break;
+-	case 0x04: p = "A2-DK1"; break;
+-	case 0x05: p = "A2-DK2"; break;
+-	case 0x06: p = "A2-DK3"; break;
+-	case 0x07: p = "A1 (6.0 MHz FM Mono)"; break;
+-	case 0x08: p = "AM-L"; break;
+-	case 0x09: p = "NICAM-BG"; break;
+-	case 0x0a: p = "NICAM-DK"; break;
+-	case 0x0b: p = "NICAM-I"; break;
+-	case 0x0c: p = "NICAM-L"; break;
+-	case 0x0d: p = "BTSC/EIAJ/A2-M Mono (4.5 MHz FMMono)"; break;
+-	case 0x0e: p = "IF FM Radio"; break;
+-	case 0x0f: p = "BTSC"; break;
+-	case 0x10: p = "high-deviation FM"; break;
+-	case 0x11: p = "very high-deviation FM"; break;
+-	case 0xfd: p = "unknown audio standard"; break;
+-	case 0xfe: p = "forced audio standard"; break;
+-	case 0xff: p = "no detected audio standard"; break;
+-	default: p = "not defined";
+-	}
+-	v4l_info(client, "Detected audio standard:   %s\n", p);
+-	v4l_info(client, "Audio muted:               %s\n",
+-		    (state->unmute_volume >= 0) ? "yes" : "no");
+-	v4l_info(client, "Audio microcontroller:     %s\n",
+-		    (download_ctl & 0x10) ?
+-				((mute_ctl & 0x2) ? "detecting" : "running") : "stopped");
+-
+-	switch (audio_config >> 4) {
+-	case 0x00: p = "undefined"; break;
+-	case 0x01: p = "BTSC"; break;
+-	case 0x02: p = "EIAJ"; break;
+-	case 0x03: p = "A2-M"; break;
+-	case 0x04: p = "A2-BG"; break;
+-	case 0x05: p = "A2-DK1"; break;
+-	case 0x06: p = "A2-DK2"; break;
+-	case 0x07: p = "A2-DK3"; break;
+-	case 0x08: p = "A1 (6.0 MHz FM Mono)"; break;
+-	case 0x09: p = "AM-L"; break;
+-	case 0x0a: p = "NICAM-BG"; break;
+-	case 0x0b: p = "NICAM-DK"; break;
+-	case 0x0c: p = "NICAM-I"; break;
+-	case 0x0d: p = "NICAM-L"; break;
+-	case 0x0e: p = "FM radio"; break;
+-	case 0x0f: p = "automatic detection"; break;
+-	default: p = "undefined";
+-	}
+-	v4l_info(client, "Configured audio standard: %s\n", p);
+-
+-	if ((audio_config >> 4) < 0xF) {
+-		switch (audio_config & 0xF) {
+-		case 0x00: p = "MONO1 (LANGUAGE A/Mono L+R channel for BTSC, EIAJ, A2)"; break;
+-		case 0x01: p = "MONO2 (LANGUAGE B)"; break;
+-		case 0x02: p = "MONO3 (STEREO forced MONO)"; break;
+-		case 0x03: p = "MONO4 (NICAM ANALOG-Language C/Analog Fallback)"; break;
+-		case 0x04: p = "STEREO"; break;
+-		case 0x05: p = "DUAL1 (AB)"; break;
+-		case 0x06: p = "DUAL2 (AC) (FM)"; break;
+-		case 0x07: p = "DUAL3 (BC) (FM)"; break;
+-		case 0x08: p = "DUAL4 (AC) (AM)"; break;
+-		case 0x09: p = "DUAL5 (BC) (AM)"; break;
+-		case 0x0a: p = "SAP"; break;
+-		default: p = "undefined";
+-		}
+-		v4l_info(client, "Configured audio mode:     %s\n", p);
+-	} else {
+-		switch (audio_config & 0xF) {
+-		case 0x00: p = "BG"; break;
+-		case 0x01: p = "DK1"; break;
+-		case 0x02: p = "DK2"; break;
+-		case 0x03: p = "DK3"; break;
+-		case 0x04: p = "I"; break;
+-		case 0x05: p = "L"; break;
+-		case 0x06: p = "BTSC"; break;
+-		case 0x07: p = "EIAJ"; break;
+-		case 0x08: p = "A2-M"; break;
+-		case 0x09: p = "FM Radio"; break;
+-		case 0x0f: p = "automatic standard and mode detection"; break;
+-		default: p = "undefined";
+-		}
+-		v4l_info(client, "Configured audio system:   %s\n", p);
+-	}
+-
+-	if (aud_input) {
+-		v4l_info(client, "Specified audio input:     Tuner (In%d)\n", aud_input);
+-	} else {
+-		v4l_info(client, "Specified audio input:     External\n");
+-	}
+-
+-	switch (pref_mode & 0xf) {
+-	case 0: p = "mono/language A"; break;
+-	case 1: p = "language B"; break;
+-	case 2: p = "language C"; break;
+-	case 3: p = "analog fallback"; break;
+-	case 4: p = "stereo"; break;
+-	case 5: p = "language AC"; break;
+-	case 6: p = "language BC"; break;
+-	case 7: p = "language AB"; break;
+-	default: p = "undefined";
+-	}
+-	v4l_info(client, "Preferred audio mode:      %s\n", p);
+-
+-	if ((audio_config & 0xf) == 0xf) {
+-		switch ((afc0 >> 3) & 0x3) {
+-		case 0: p = "system DK"; break;
+-		case 1: p = "system L"; break;
+-		case 2: p = "autodetect"; break;
+-		default: p = "undefined";
+-		}
+-		v4l_info(client, "Selected 65 MHz format:    %s\n", p);
+-
+-		switch (afc0 & 0x7) {
+-		case 0: p = "chroma"; break;
+-		case 1: p = "BTSC"; break;
+-		case 2: p = "EIAJ"; break;
+-		case 3: p = "A2-M"; break;
+-		case 4: p = "autodetect"; break;
+-		default: p = "undefined";
+-		}
+-		v4l_info(client, "Selected 45 MHz format:    %s\n", p);
+-	}
+-}
+diff --git a/drivers/media/video/cx25840/cx25840-core.h b/drivers/media/video/cx25840/cx25840-core.h
+index ea669b1..95093ed 100644
+--- a/drivers/media/video/cx25840/cx25840-core.h
++++ b/drivers/media/video/cx25840/cx25840-core.h
+@@ -47,6 +47,7 @@ struct cx25840_state {
+ 	u32 id;
+ 	u32 rev;
+ 	int is_cx25836;
++	int is_cx23885;
+ 	int is_initialized;
+ 	wait_queue_head_t fw_wait;    /* wake up when the fw load is finished */
+ 	struct work_struct fw_work;   /* work entry for fw load */
+diff --git a/drivers/media/video/cx25840/cx25840-firmware.c b/drivers/media/video/cx25840/cx25840-firmware.c
+index e852024..1ddf724 100644
+--- a/drivers/media/video/cx25840/cx25840-firmware.c
++++ b/drivers/media/video/cx25840/cx25840-firmware.c
+@@ -24,6 +24,7 @@
+ #include "cx25840-core.h"
  
- }
+ #define FWFILE "v4l-cx25840.fw"
++#define FWFILE_CX23885 "v4l-cx23885-avcore-01.fw"
  
--void cx23885_reset(struct cx23885_dev *dev)
-+static void cx23885_reset(struct cx23885_dev *dev)
- {
- 	dprintk(1, "%s()\n", __FUNCTION__);
+ /*
+  * Mike Isely <isely at pobox.com> - The FWSEND parameter controls the
+@@ -92,10 +93,14 @@ static int fw_write(struct i2c_client *client, u8 * data, int size)
  
-@@ -594,15 +594,18 @@ void cx23885_reset(struct cx23885_dev *dev)
+ int cx25840_loadfw(struct i2c_client *client)
+ {
++	struct cx25840_state *state = i2c_get_clientdata(client);
+ 	const struct firmware *fw = NULL;
+ 	u8 buffer[4], *ptr;
+ 	int size, send, retval;
  
- 	mdelay(100);
++	if (state->is_cx23885)
++		firmware = FWFILE_CX23885;
++
+ 	if (request_firmware(&fw, firmware, FWDEV(client)) != 0) {
+ 		v4l_err(client, "unable to open firmware %s\n", firmware);
+ 		return -EINVAL;
+diff --git a/drivers/media/video/cx25840/cx25840-vbi.c b/drivers/media/video/cx25840/cx25840-vbi.c
+index ced13fe..6828f59 100644
+--- a/drivers/media/video/cx25840/cx25840-vbi.c
++++ b/drivers/media/video/cx25840/cx25840-vbi.c
+@@ -180,7 +180,7 @@ void cx25840_vbi_setup(struct i2c_client *client)
+ 						fsc/1000000,fsc%1000000);
  
--	cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH01 ], 188*4, 0);
--	cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH02 ], 128, 0);
--	cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH03 ], 188*4, 0);
--	cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH04 ], 128, 0);
--	cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH05 ], 128, 0);
--	cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH06 ], 188*4, 0);
--	cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH07 ], 128, 0);
--	cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH08 ], 128, 0);
--	cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH09 ], 128, 0);
-+	cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH01],
-+		720*4, 0);
-+	cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH02], 128, 0);
-+	cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH03],
-+		188*4, 0);
-+	cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH04], 128, 0);
-+	cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH05], 128, 0);
-+	cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH06],
-+		188*4, 0);
-+	cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH07], 128, 0);
-+	cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH08], 128, 0);
-+	cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH09], 128, 0);
+ 		v4l_dbg(1, cx25840_debug, client, "hblank %i, hactive %i, "
+-			"vblank %i , vactive %i, vblank656 %i, src_dec %i,"
++			"vblank %i, vactive %i, vblank656 %i, src_dec %i, "
+ 			"burst 0x%02x, luma_lpf %i, uv_lpf %i, comb 0x%02x,"
+ 			" sc 0x%06x\n",
+ 			hblank, hactive, vblank, vactive, vblank656,
+diff --git a/drivers/media/video/cx88/Kconfig b/drivers/media/video/cx88/Kconfig
+index ceb31d4..49d3813 100644
+--- a/drivers/media/video/cx88/Kconfig
++++ b/drivers/media/video/cx88/Kconfig
+@@ -8,6 +8,7 @@ config VIDEO_CX88
+ 	select VIDEO_TUNER
+ 	select VIDEO_TVEEPROM
+ 	select VIDEO_IR
++	select VIDEO_WM8775 if VIDEO_HELPER_CHIPS_AUTO
+ 	---help---
+ 	  This is a video4linux driver for Conexant 2388x based
+ 	  TV cards.
+diff --git a/drivers/media/video/cx88/cx88-alsa.c b/drivers/media/video/cx88/cx88-alsa.c
+index 40ffd7a..8735227 100644
+--- a/drivers/media/video/cx88/cx88-alsa.c
++++ b/drivers/media/video/cx88/cx88-alsa.c
+@@ -417,7 +417,7 @@ static int snd_cx88_hw_params(struct snd_pcm_substream * substream,
+ 	buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP|RISC_IRQ1|RISC_CNT_INC);
+ 	buf->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
  
- 	cx23885_gpio_setup(dev);
- }
-@@ -637,7 +640,7 @@ static int get_resources(struct cx23885_dev *dev)
+-	buf->vb.state = STATE_PREPARED;
++	buf->vb.state = VIDEOBUF_PREPARED;
  
- static void cx23885_timeout(unsigned long data);
- int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc,
--			 u32 reg, u32 mask, u32 value);
-+				u32 reg, u32 mask, u32 value);
+ 	chip->buf = buf;
+ 	chip->dma_risc = dma;
+diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c
+index f802b56..a99e9d5 100644
+--- a/drivers/media/video/cx88/cx88-blackbird.c
++++ b/drivers/media/video/cx88/cx88-blackbird.c
+@@ -307,7 +307,7 @@ static int register_read(struct cx88_core *core, u32 address, u32 *value)
  
- static int cx23885_init_tsport(struct cx23885_dev *dev, struct cx23885_tsport *port, int portno)
- {
-@@ -704,6 +707,44 @@ static int cx23885_init_tsport(struct cx23885_dev *dev, struct cx23885_tsport *p
- 	return 0;
- }
+ /* ------------------------------------------------------------------ */
  
-+static void cx23885_dev_checkrevision(struct cx23885_dev *dev)
-+{
-+	switch (cx_read(RDR_CFG2) & 0xff) {
-+	case 0x00:
-+		/* cx23885 */
-+		dev->hwrevision = 0xa0;
-+		break;
-+	case 0x01:
-+		/* CX23885-12Z */
-+		dev->hwrevision = 0xa1;
-+		break;
-+	case 0x02:
-+		/* CX23885-13Z */
-+		dev->hwrevision = 0xb0;
-+		break;
-+	case 0x03:
-+		/* CX23888-22Z */
-+		dev->hwrevision = 0xc0;
-+		break;
-+	case 0x0e:
-+		/* CX23887-15Z */
-+		dev->hwrevision = 0xc0;
-+	case 0x0f:
-+		/* CX23887-14Z */
-+		dev->hwrevision = 0xb1;
-+		break;
-+	default:
-+		printk(KERN_ERR "%s() New hardware revision found 0x%x\n",
-+			__FUNCTION__, dev->hwrevision);
-+	}
-+	if (dev->hwrevision)
-+		printk(KERN_INFO "%s() Hardware revision = 0x%02x\n",
-+			__FUNCTION__, dev->hwrevision);
-+	else
-+		printk(KERN_ERR "%s() Hardware revision unknown 0x%x\n",
-+			__FUNCTION__, dev->hwrevision);
-+}
-+
- static int cx23885_dev_setup(struct cx23885_dev *dev)
+-static int blackbird_mbox_func(void *priv, int command, int in, int out, u32 data[CX2341X_MBOX_MAX_DATA])
++static int blackbird_mbox_func(void *priv, u32 command, int in, int out, u32 data[CX2341X_MBOX_MAX_DATA])
  {
- 	int i;
-@@ -723,10 +764,14 @@ static int cx23885_dev_setup(struct cx23885_dev *dev)
- 	if(dev->pci->device == 0x8880) {
- 		dev->bridge = CX23885_BRIDGE_887;
- 		dev->sram_channels = cx23887_sram_channels;
-+		/* Apply a sensible clock frequency for the PCIe bridge */
-+		dev->clk_freq = 25000000;
- 	} else
- 	if(dev->pci->device == 0x8852) {
- 		dev->bridge = CX23885_BRIDGE_885;
- 		dev->sram_channels = cx23885_sram_channels;
-+		/* Apply a sensible clock frequency for the PCIe bridge */
-+		dev->clk_freq = 28000000;
- 	} else
- 		BUG();
- 
-@@ -746,6 +791,10 @@ static int cx23885_dev_setup(struct cx23885_dev *dev)
- 		cx23885_card_list(dev);
+ 	struct cx8802_dev *dev = priv;
+ 	unsigned long timeout;
+@@ -536,11 +536,12 @@ static int blackbird_initialize_codec(struct cx8802_dev *dev)
+ 	dprintk(1,"Initialize codec\n");
+ 	retval = blackbird_api_cmd(dev, CX2341X_ENC_PING_FW, 0, 0); /* ping */
+ 	if (retval < 0) {
++
++		dev->mpeg_active = 0;
++
+ 		/* ping was not successful, reset and upload firmware */
+ 		cx_write(MO_SRST_IO, 0); /* SYS_RSTO=0 */
+-		msleep(1);
+ 		cx_write(MO_SRST_IO, 1); /* SYS_RSTO=1 */
+-		msleep(1);
+ 		retval = blackbird_load_firmware(dev);
+ 		if (retval < 0)
+ 			return retval;
+@@ -562,7 +563,6 @@ static int blackbird_initialize_codec(struct cx8802_dev *dev)
+ 		}
+ 		dprintk(0, "Firmware version is 0x%08x\n", version);
  	}
+-	msleep(1);
  
-+	/* If the user specific a clk freq override, apply it */
-+	if (cx23885_boards[dev->board].clk_freq > 0)
-+		dev->clk_freq = cx23885_boards[dev->board].clk_freq;
-+
- 	dev->pci_bus  = dev->pci->bus->number;
- 	dev->pci_slot = PCI_SLOT(dev->pci->devfn);
- 	dev->pci_irqmask = 0x001f00;
-@@ -810,6 +859,17 @@ static int cx23885_dev_setup(struct cx23885_dev *dev)
+ 	cx_write(MO_PINMUX_IO, 0x88); /* 656-8bit IO and enable MPEG parallel IO */
+ 	cx_clear(MO_INPUT_FORMAT, 0x100); /* chroma subcarrier lock to normal? */
+@@ -570,40 +570,68 @@ static int blackbird_initialize_codec(struct cx8802_dev *dev)
+ 	cx_clear(MO_OUTPUT_FORMAT, 0x0008); /* Normal Y-limits to let the mpeg encoder sync */
  
- 	cx23885_pci_quirks(dev);
+ 	blackbird_codec_settings(dev);
+-	msleep(1);
  
-+	/* Assume some sensible defaults */
-+	dev->tuner_type = cx23885_boards[dev->board].tuner_type;
-+	dev->tuner_addr = cx23885_boards[dev->board].tuner_addr;
-+	dev->radio_type = cx23885_boards[dev->board].radio_type;
-+	dev->radio_addr = cx23885_boards[dev->board].radio_addr;
-+
-+	dprintk(1, "%s() tuner_type = 0x%x tuner_addr = 0x%x\n",
-+		__FUNCTION__, dev->tuner_type, dev->tuner_addr);
-+	dprintk(1, "%s() radio_type = 0x%x radio_addr = 0x%x\n",
-+		__FUNCTION__, dev->radio_type, dev->radio_addr);
-+
- 	/* init hardware */
- 	cx23885_reset(dev);
+-	/* blackbird_api_cmd(dev, IVTV_API_ASSIGN_NUM_VSYNC_LINES, 4, 0, 0xef, 0xef);
+-	   blackbird_api_cmd(dev, IVTV_API_ASSIGN_NUM_VSYNC_LINES, 4, 0, 0xf0, 0xf0);
+-	   blackbird_api_cmd(dev, IVTV_API_ASSIGN_NUM_VSYNC_LINES, 4, 0, 0x180, 0x180); */
+ 	blackbird_api_cmd(dev, CX2341X_ENC_SET_NUM_VSYNC_LINES, 2, 0,
+ 			BLACKBIRD_FIELD1_SAA7115,
+ 			BLACKBIRD_FIELD2_SAA7115
+ 		);
  
-@@ -820,24 +880,33 @@ static int cx23885_dev_setup(struct cx23885_dev *dev)
- 	cx23885_card_setup(dev);
- 	cx23885_ir_init(dev);
+-	/* blackbird_api_cmd(dev, IVTV_API_ASSIGN_PLACEHOLDER, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); */
+ 	blackbird_api_cmd(dev, CX2341X_ENC_SET_PLACEHOLDER, 12, 0,
+ 			BLACKBIRD_CUSTOM_EXTENSION_USR_DATA,
+ 			0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
  
--	if(cx23885_boards[dev->board].portb == CX23885_MPEG_DVB) {
-+	if (cx23885_boards[dev->board].porta == CX23885_ANALOG_VIDEO) {
-+		if (cx23885_video_register(dev) < 0) {
-+			printk(KERN_ERR "%s() Failed to register analog "
-+				"video adapters on VID_A\n", __FUNCTION__);
+-	/* initialize the video input */
+-	blackbird_api_cmd(dev, CX2341X_ENC_INITIALIZE_INPUT, 0, 0);
++	return 0;
++}
+ 
+-	msleep(1);
++static int blackbird_start_codec(struct file *file, void *priv)
++{
++	struct cx8802_dev *dev  = ((struct cx8802_fh *)priv)->dev;
++	struct cx88_core *core = dev->core;
++	/* start capturing to the host interface */
++	u32 reg;
+ 
+-	blackbird_api_cmd(dev, CX2341X_ENC_MUTE_VIDEO, 1, 0, BLACKBIRD_UNMUTE);
+-	msleep(1);
+-	blackbird_api_cmd(dev, CX2341X_ENC_MUTE_AUDIO, 1, 0, BLACKBIRD_UNMUTE);
+-	msleep(1);
++	int i;
++	int lastchange = -1;
++	int lastval = 0;
++
++	for (i = 0; (i < 10) && (i < (lastchange + 4)); i++) {
++		reg = cx_read(AUD_STATUS);
++
++		dprintk(1, "AUD_STATUS:%dL: 0x%x\n", i, reg);
++		if ((reg & 0x0F) != lastval) {
++			lastval = reg & 0x0F;
++			lastchange = i;
 +		}
++		msleep(100);
 +	}
 +
-+	if (cx23885_boards[dev->board].portb == CX23885_MPEG_DVB) {
- 		if (cx23885_dvb_register(&dev->ts1) < 0) {
- 			printk(KERN_ERR "%s() Failed to register dvb adapters on VID_B\n",
- 			       __FUNCTION__);
- 		}
- 	}
- 
--	if(cx23885_boards[dev->board].portc == CX23885_MPEG_DVB) {
-+	if (cx23885_boards[dev->board].portc == CX23885_MPEG_DVB) {
- 		if (cx23885_dvb_register(&dev->ts2) < 0) {
- 			printk(KERN_ERR "%s() Failed to register dvb adapters on VID_C\n",
- 			       __FUNCTION__);
- 		}
- 	}
- 
-+	cx23885_dev_checkrevision(dev);
++	/* unmute audio source */
++	cx_clear(AUD_VOL_CTL, (1 << 6));
 +
- 	return 0;
- }
- 
--void cx23885_dev_unregister(struct cx23885_dev *dev)
-+static void cx23885_dev_unregister(struct cx23885_dev *dev)
- {
- 	release_mem_region(pci_resource_start(dev->pci,0),
- 			   pci_resource_len(dev->pci,0));
-@@ -845,6 +914,9 @@ void cx23885_dev_unregister(struct cx23885_dev *dev)
- 	if (!atomic_dec_and_test(&dev->refcount))
- 		return;
- 
-+	if (cx23885_boards[dev->board].porta == CX23885_ANALOG_VIDEO)
-+		cx23885_video_unregister(dev);
++	blackbird_api_cmd(dev, CX2341X_ENC_REFRESH_INPUT, 0, 0);
 +
- 	if(cx23885_boards[dev->board].portb == CX23885_MPEG_DVB)
- 		cx23885_dvb_unregister(&dev->ts1);
- 
-@@ -952,9 +1024,11 @@ int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc,
- 	return 0;
- }
++	/* initialize the video input */
++	blackbird_api_cmd(dev, CX2341X_ENC_INITIALIZE_INPUT, 0, 0);
  
--int cx23885_risc_databuffer(struct pci_dev *pci, struct btcx_riscmem *risc,
--			    struct scatterlist *sglist, unsigned int bpl,
--			    unsigned int lines)
-+static int cx23885_risc_databuffer(struct pci_dev *pci,
-+				   struct btcx_riscmem *risc,
-+				   struct scatterlist *sglist,
-+				   unsigned int bpl,
-+				   unsigned int lines)
- {
- 	u32 instructions;
- 	u32 *rp;
-@@ -982,7 +1056,7 @@ int cx23885_risc_databuffer(struct pci_dev *pci, struct btcx_riscmem *risc,
- }
+ 	/* start capturing to the host interface */
+-	/* blackbird_api_cmd(dev, CX2341X_ENC_START_CAPTURE, 2, 0, 0, 0x13); */
+ 	blackbird_api_cmd(dev, CX2341X_ENC_START_CAPTURE, 2, 0,
+ 			BLACKBIRD_MPEG_CAPTURE,
+ 			BLACKBIRD_RAW_BITS_NONE
+ 		);
+-	msleep(10);
  
- int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc,
--			 u32 reg, u32 mask, u32 value)
-+				u32 reg, u32 mask, u32 value)
- {
- 	u32 *rp;
- 	int rc;
-@@ -1011,7 +1085,58 @@ void cx23885_free_buffer(struct videobuf_queue *q, struct cx23885_buffer *buf)
- 	videobuf_dma_unmap(q, dma);
- 	videobuf_dma_free(dma);
- 	btcx_riscmem_free((struct pci_dev *)q->dev, &buf->risc);
--	buf->vb.state = STATE_NEEDS_INIT;
-+	buf->vb.state = VIDEOBUF_NEEDS_INIT;
+-	blackbird_api_cmd(dev, CX2341X_ENC_REFRESH_INPUT, 0,0);
++	dev->mpeg_active = 1;
++	return 0;
 +}
 +
-+static void cx23885_tsport_reg_dump(struct cx23885_tsport *port)
++static int blackbird_stop_codec(struct cx8802_dev *dev)
 +{
-+	struct cx23885_dev *dev = port->dev;
++	blackbird_api_cmd(dev, CX2341X_ENC_STOP_CAPTURE, 3, 0,
++			BLACKBIRD_END_NOW,
++			BLACKBIRD_MPEG_CAPTURE,
++			BLACKBIRD_RAW_BITS_NONE
++		);
 +
-+	dprintk(1, "%s() Register Dump\n", __FUNCTION__);
-+	dprintk(1, "%s() DEV_CNTRL2               0x%08X\n", __FUNCTION__,
-+		cx_read(DEV_CNTRL2));
-+	dprintk(1, "%s() PCI_INT_MSK              0x%08X\n", __FUNCTION__,
-+		cx_read(PCI_INT_MSK));
-+	dprintk(1, "%s() AUD_INT_INT_MSK          0x%08X\n", __FUNCTION__,
-+		cx_read(AUDIO_INT_INT_MSK));
-+	dprintk(1, "%s() AUD_INT_DMA_CTL          0x%08X\n", __FUNCTION__,
-+		cx_read(AUD_INT_DMA_CTL));
-+	dprintk(1, "%s() AUD_EXT_INT_MSK          0x%08X\n", __FUNCTION__,
-+		cx_read(AUDIO_EXT_INT_MSK));
-+	dprintk(1, "%s() AUD_EXT_DMA_CTL          0x%08X\n", __FUNCTION__,
-+		cx_read(AUD_EXT_DMA_CTL));
-+	dprintk(1, "%s() PAD_CTRL                 0x%08X\n", __FUNCTION__,
-+		cx_read(PAD_CTRL));
-+	dprintk(1, "%s() ALT_PIN_OUT_SEL          0x%08X\n", __FUNCTION__,
-+		cx_read(ALT_PIN_OUT_SEL));
-+	dprintk(1, "%s() GPIO2                    0x%08X\n", __FUNCTION__,
-+		cx_read(GPIO2));
-+	dprintk(1, "%s() gpcnt(0x%08X)          0x%08X\n", __FUNCTION__,
-+		port->reg_gpcnt, cx_read(port->reg_gpcnt));
-+	dprintk(1, "%s() gpcnt_ctl(0x%08X)      0x%08x\n", __FUNCTION__,
-+		port->reg_gpcnt_ctl, cx_read(port->reg_gpcnt_ctl));
-+	dprintk(1, "%s() dma_ctl(0x%08X)        0x%08x\n", __FUNCTION__,
-+		port->reg_dma_ctl, cx_read(port->reg_dma_ctl));
-+	dprintk(1, "%s() src_sel(0x%08X)        0x%08x\n", __FUNCTION__,
-+		port->reg_src_sel, cx_read(port->reg_src_sel));
-+	dprintk(1, "%s() lngth(0x%08X)          0x%08x\n", __FUNCTION__,
-+		port->reg_lngth, cx_read(port->reg_lngth));
-+	dprintk(1, "%s() hw_sop_ctrl(0x%08X)    0x%08x\n", __FUNCTION__,
-+		port->reg_hw_sop_ctrl, cx_read(port->reg_hw_sop_ctrl));
-+	dprintk(1, "%s() gen_ctrl(0x%08X)       0x%08x\n", __FUNCTION__,
-+		port->reg_gen_ctrl, cx_read(port->reg_gen_ctrl));
-+	dprintk(1, "%s() bd_pkt_status(0x%08X)  0x%08x\n", __FUNCTION__,
-+		port->reg_bd_pkt_status, cx_read(port->reg_bd_pkt_status));
-+	dprintk(1, "%s() sop_status(0x%08X)     0x%08x\n", __FUNCTION__,
-+		port->reg_sop_status, cx_read(port->reg_sop_status));
-+	dprintk(1, "%s() fifo_ovfl_stat(0x%08X) 0x%08x\n", __FUNCTION__,
-+		port->reg_fifo_ovfl_stat, cx_read(port->reg_fifo_ovfl_stat));
-+	dprintk(1, "%s() vld_misc(0x%08X)       0x%08x\n", __FUNCTION__,
-+		port->reg_vld_misc, cx_read(port->reg_vld_misc));
-+	dprintk(1, "%s() ts_clk_en(0x%08X)      0x%08x\n", __FUNCTION__,
-+		port->reg_ts_clk_en, cx_read(port->reg_ts_clk_en));
-+	dprintk(1, "%s() ts_int_msk(0x%08X)     0x%08x\n", __FUNCTION__,
-+		port->reg_ts_int_msk, cx_read(port->reg_ts_int_msk));
++	dev->mpeg_active = 0;
+ 	return 0;
  }
  
- static int cx23885_start_dma(struct cx23885_tsport *port,
-@@ -1076,6 +1201,9 @@ static int cx23885_start_dma(struct cx23885_tsport *port,
+@@ -833,6 +861,10 @@ static int vidioc_s_ext_ctrls (struct file *file, void *priv,
  
- 	cx_set(DEV_CNTRL2, (1<<5)); /* Enable RISC controller */
+ 	if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
+ 		return -EINVAL;
++
++	if (dev->mpeg_active)
++		blackbird_stop_codec(dev);
++
+ 	p = dev->params;
+ 	err = cx2341x_ext_ctrls(&p, 0, f, VIDIOC_S_EXT_CTRLS);
+ 	if (!err) {
+@@ -864,10 +896,9 @@ static int vidioc_s_frequency (struct file *file, void *priv,
+ 	struct cx8802_dev *dev  = fh->dev;
+ 	struct cx88_core  *core = dev->core;
  
-+	if (debug > 4)
-+		cx23885_tsport_reg_dump(port);
+-	blackbird_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0,
+-				BLACKBIRD_END_NOW,
+-				BLACKBIRD_MPEG_CAPTURE,
+-				BLACKBIRD_RAW_BITS_NONE);
++	if (dev->mpeg_active)
++		blackbird_stop_codec(dev);
 +
- 	return 0;
- }
+ 	cx88_set_freq (core,f);
+ 	blackbird_initialize_codec(dev);
+ 	cx88_set_scale(dev->core, dev->width, dev->height,
+@@ -1073,15 +1104,11 @@ static int mpeg_open(struct inode *inode, struct file *file)
+ static int mpeg_release(struct inode *inode, struct file *file)
+ {
+ 	struct cx8802_fh  *fh  = file->private_data;
+-	struct cx8802_dev *dev = NULL;
++	struct cx8802_dev *dev = fh->dev;
+ 	struct cx8802_driver *drv = NULL;
  
-@@ -1091,7 +1219,7 @@ static int cx23885_stop_dma(struct cx23885_tsport *port)
- 	return 0;
- }
+-	/* blackbird_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0, BLACKBIRD_END_NOW, 0, 0x13); */
+-	blackbird_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0,
+-			BLACKBIRD_END_NOW,
+-			BLACKBIRD_MPEG_CAPTURE,
+-			BLACKBIRD_RAW_BITS_NONE
+-		);
++	if (dev->mpeg_active)
++		blackbird_stop_codec(dev);
  
--static int cx23885_restart_queue(struct cx23885_tsport *port,
-+int cx23885_restart_queue(struct cx23885_tsport *port,
- 				struct cx23885_dmaqueue *q)
+ 	cx8802_cancel_buffers(fh->dev);
+ 	/* stop mpeg capture */
+@@ -1107,6 +1134,10 @@ static ssize_t
+ mpeg_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
  {
- 	struct cx23885_dev *dev = port->dev;
-@@ -1114,7 +1242,7 @@ static int cx23885_restart_queue(struct cx23885_tsport *port,
- 				list_del(&buf->vb.queue);
- 				list_add_tail(&buf->vb.queue, &q->active);
- 				cx23885_start_dma(port, q, buf);
--				buf->vb.state = STATE_ACTIVE;
-+				buf->vb.state = VIDEOBUF_ACTIVE;
- 				buf->count    = q->count++;
- 				mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
- 				dprintk(5, "[%p/%d] restart_queue - first active\n",
-@@ -1125,7 +1253,7 @@ static int cx23885_restart_queue(struct cx23885_tsport *port,
- 				   prev->fmt       == buf->fmt) {
- 				list_del(&buf->vb.queue);
- 				list_add_tail(&buf->vb.queue, &q->active);
--				buf->vb.state = STATE_ACTIVE;
-+				buf->vb.state = VIDEOBUF_ACTIVE;
- 				buf->count    = q->count++;
- 				prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
- 				prev->risc.jmp[2] = cpu_to_le32(0); /* 64 bit bits 63-32 */
-@@ -1162,7 +1290,7 @@ int cx23885_buf_prepare(struct videobuf_queue *q, struct cx23885_tsport *port,
- 	if (0 != buf->vb.baddr  &&  buf->vb.bsize < size)
- 		return -EINVAL;
- 
--	if (STATE_NEEDS_INIT == buf->vb.state) {
-+	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
- 		buf->vb.width  = port->ts_packet_size;
- 		buf->vb.height = port->ts_packet_count;
- 		buf->vb.size   = size;
-@@ -1174,7 +1302,7 @@ int cx23885_buf_prepare(struct videobuf_queue *q, struct cx23885_tsport *port,
- 					videobuf_to_dma(&buf->vb)->sglist,
- 					buf->vb.width, buf->vb.height);
- 	}
--	buf->vb.state = STATE_PREPARED;
-+	buf->vb.state = VIDEOBUF_PREPARED;
- 	return 0;
+ 	struct cx8802_fh *fh = file->private_data;
++	struct cx8802_dev *dev = fh->dev;
++
++	if (!dev->mpeg_active)
++		blackbird_start_codec(file, fh);
  
-  fail:
-@@ -1197,7 +1325,7 @@ void cx23885_buf_queue(struct cx23885_tsport *port, struct cx23885_buffer *buf)
- 		dprintk( 1, "queue is empty - first active\n" );
- 		list_add_tail(&buf->vb.queue, &cx88q->active);
- 		cx23885_start_dma(port, cx88q, buf);
--		buf->vb.state = STATE_ACTIVE;
-+		buf->vb.state = VIDEOBUF_ACTIVE;
- 		buf->count    = cx88q->count++;
- 		mod_timer(&cx88q->timeout, jiffies + BUFFER_TIMEOUT);
- 		dprintk(1, "[%p/%d] %s - first active\n",
-@@ -1207,7 +1335,7 @@ void cx23885_buf_queue(struct cx23885_tsport *port, struct cx23885_buffer *buf)
- 		prev = list_entry(cx88q->active.prev, struct cx23885_buffer,
- 				  vb.queue);
- 		list_add_tail(&buf->vb.queue, &cx88q->active);
--		buf->vb.state = STATE_ACTIVE;
-+		buf->vb.state = VIDEOBUF_ACTIVE;
- 		buf->count    = cx88q->count++;
- 		prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
- 		prev->risc.jmp[2] = cpu_to_le32(0); /* 64 bit bits 63-32 */
-@@ -1231,7 +1359,7 @@ static void do_cancel_buffers(struct cx23885_tsport *port, char *reason,
- 		buf = list_entry(q->active.next, struct cx23885_buffer,
- 				 vb.queue);
- 		list_del(&buf->vb.queue);
--		buf->vb.state = STATE_ERROR;
-+		buf->vb.state = VIDEOBUF_ERROR;
- 		wake_up(&buf->vb.done);
- 		dprintk(1, "[%p/%d] %s - dma=0x%08lx\n",
- 			buf, buf->vb.i, reason, (unsigned long)buf->risc.dma);
-@@ -1243,16 +1371,6 @@ static void do_cancel_buffers(struct cx23885_tsport *port, char *reason,
- 	spin_unlock_irqrestore(&port->slock, flags);
- }
+ 	return videobuf_read_stream(&fh->mpegq, data, count, ppos, 0,
+ 				    file->f_flags & O_NONBLOCK);
+@@ -1282,6 +1313,7 @@ static int cx8802_blackbird_probe(struct cx8802_driver *drv)
+ 	       core->name);
+ 	host_setup(dev->core);
  
--void cx23885_cancel_buffers(struct cx23885_tsport *port)
--{
--	struct cx23885_dev *dev = port->dev;
--	struct cx23885_dmaqueue *q = &port->mpegq;
--
--	dprintk(1, "%s()\n", __FUNCTION__);
--	del_timer_sync(&q->timeout);
--	cx23885_stop_dma(port);
--	do_cancel_buffers(port, "cancel", 0);
--}
++	blackbird_initialize_codec(dev);
+ 	blackbird_register_video(dev);
  
- static void cx23885_timeout(unsigned long data)
- {
-@@ -1325,12 +1443,15 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id)
- 	struct cx23885_tsport *ts1 = &dev->ts1;
- 	struct cx23885_tsport *ts2 = &dev->ts2;
- 	u32 pci_status, pci_mask;
-+	u32 vida_status, vida_mask;
- 	u32 ts1_status, ts1_mask;
- 	u32 ts2_status, ts2_mask;
--	int ts1_count = 0, ts2_count = 0, handled = 0;
-+	int vida_count = 0, ts1_count = 0, ts2_count = 0, handled = 0;
+ 	/* initial device configuration: needed ? */
+diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c
+index a4eb6a8..e6b7f51 100644
+--- a/drivers/media/video/cx88/cx88-cards.c
++++ b/drivers/media/video/cx88/cx88-cards.c
+@@ -26,6 +26,7 @@
+ #include <linux/delay.h>
  
- 	pci_status = cx_read(PCI_INT_STAT);
- 	pci_mask = cx_read(PCI_INT_MSK);
-+	vida_status = cx_read(VID_A_INT_STAT);
-+	vida_mask = cx_read(VID_A_INT_MSK);
- 	ts1_status = cx_read(VID_B_INT_STAT);
- 	ts1_mask = cx_read(VID_B_INT_MSK);
- 	ts2_status = cx_read(VID_C_INT_STAT);
-@@ -1339,11 +1460,17 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id)
- 	if ( (pci_status == 0) && (ts2_status == 0) && (ts1_status == 0) )
- 		goto out;
+ #include "cx88.h"
++#include "tea5767.h"
  
-+	vida_count = cx_read(VID_A_GPCNT);
- 	ts1_count = cx_read(ts1->reg_gpcnt);
- 	ts2_count = cx_read(ts2->reg_gpcnt);
--	dprintk(7, "pci_status: 0x%08x  pci_mask: 0x%08x\n", pci_status, pci_mask );
--	dprintk(7, "ts1_status: 0x%08x  ts1_mask: 0x%08x count: 0x%x\n", ts1_status, ts1_mask, ts1_count );
--	dprintk(7, "ts2_status: 0x%08x  ts2_mask: 0x%08x count: 0x%x\n", ts2_status, ts2_mask, ts2_count );
-+	dprintk(7, "pci_status: 0x%08x  pci_mask: 0x%08x\n",
-+		pci_status, pci_mask);
-+	dprintk(7, "vida_status: 0x%08x vida_mask: 0x%08x count: 0x%x\n",
-+		vida_status, vida_mask, vida_count);
-+	dprintk(7, "ts1_status: 0x%08x  ts1_mask: 0x%08x count: 0x%x\n",
-+		ts1_status, ts1_mask, ts1_count);
-+	dprintk(7, "ts2_status: 0x%08x  ts2_mask: 0x%08x count: 0x%x\n",
-+		ts2_status, ts2_mask, ts2_count);
+ static unsigned int tuner[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET };
+ static unsigned int radio[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET };
+@@ -245,6 +246,10 @@ static const struct cx88_board cx88_boards[] = {
+ 		}},
+ 		.radio = {
+ 			 .type   = CX88_RADIO,
++			 .vmux   = 3,
++			 .gpio0  = 0x000040bf,
++			 .gpio1  = 0x000080c0,
++			 .gpio2  = 0x0000ff20,
+ 		},
+ 	},
+ 	[CX88_BOARD_WINFAST_DV2000] = {
+@@ -297,22 +302,22 @@ static const struct cx88_board cx88_boards[] = {
+ 			.type   = CX88_VMUX_TELEVISION,
+ 			.vmux   = 0,
+ 			.gpio0  = 0x0000bde2,
+-			.extadc = 1,
++			.audioroute = 1,
+ 		},{
+ 			.type   = CX88_VMUX_COMPOSITE1,
+ 			.vmux   = 1,
+ 			.gpio0  = 0x0000bde6,
+-			.extadc = 1,
++			.audioroute = 1,
+ 		},{
+ 			.type   = CX88_VMUX_SVIDEO,
+ 			.vmux   = 2,
+ 			.gpio0  = 0x0000bde6,
+-			.extadc = 1,
++			.audioroute = 1,
+ 		}},
+ 		.radio = {
+ 			.type   = CX88_RADIO,
+ 			.gpio0  = 0x0000bd62,
+-			.extadc = 1,
++			.audioroute = 1,
+ 		},
+ 		.mpeg           = CX88_MPEG_BLACKBIRD,
+ 	},
+@@ -373,7 +378,7 @@ static const struct cx88_board cx88_boards[] = {
+ 			.type   = CX88_VMUX_SVIDEO,
+ 			.vmux   = 2,
+ 			.gpio0  = 0x0000fde6, // 0x0000fda6 L,R RCA audio in?
+-			.extadc = 1,
++			.audioroute = 1,
+ 		}},
+ 		.radio = {
+ 			.type   = CX88_RADIO,
+@@ -544,7 +549,7 @@ static const struct cx88_board cx88_boards[] = {
+ 		.input          = {{
+ 			.type   = CX88_VMUX_TELEVISION,
+ 			.vmux   = 0,
+-			.extadc = 1,
++			.audioroute = 1,
+ 		}},
+ 		.mpeg           = CX88_MPEG_BLACKBIRD,
+ 	},
+@@ -667,22 +672,22 @@ static const struct cx88_board cx88_boards[] = {
+ 			.type   = CX88_VMUX_TELEVISION,
+ 			.vmux   = 0,
+ 			.gpio0  = 0x00009d80,
+-			.extadc = 1,
++			.audioroute = 1,
+ 		},{
+ 			.type   = CX88_VMUX_COMPOSITE1,
+ 			.vmux   = 1,
+ 			.gpio0  = 0x00009d76,
+-			.extadc = 1,
++			.audioroute = 1,
+ 		},{
+ 			.type   = CX88_VMUX_SVIDEO,
+ 			.vmux   = 2,
+ 			.gpio0  = 0x00009d76,
+-			.extadc = 1,
++			.audioroute = 1,
+ 		}},
+ 		.radio = {
+ 			.type   = CX88_RADIO,
+ 			.gpio0  = 0x00009d00,
+-			.extadc = 1,
++			.audioroute = 1,
+ 		},
+ 		.mpeg           = CX88_MPEG_BLACKBIRD,
+ 	},
+@@ -821,23 +826,23 @@ static const struct cx88_board cx88_boards[] = {
+ 			.type   = CX88_VMUX_COMPOSITE1,
+ 			.vmux   = 0,
+ 			.gpio0  = 0x0000cd73,
+-			.extadc = 1,
++			.audioroute = 1,
+ 		},{
+ 			.type   = CX88_VMUX_SVIDEO,
+ 			.vmux   = 1,
+ 			.gpio0  = 0x0000cd73,
+-			.extadc = 1,
++			.audioroute = 1,
+ 		},{
+ 			.type   = CX88_VMUX_TELEVISION,
+ 			.vmux   = 3,
+ 			.gpio0  = 0x0000cdb3,
+-			.extadc = 1,
++			.audioroute = 1,
+ 		}},
+ 		.radio = {
+ 			.type   = CX88_RADIO,
+ 			.vmux   = 2,
+ 			.gpio0  = 0x0000cdf3,
+-			.extadc = 1,
++			.audioroute = 1,
+ 		},
+ 		.mpeg           = CX88_MPEG_BLACKBIRD,
+ 	},
+@@ -1105,12 +1110,12 @@ static const struct cx88_board cx88_boards[] = {
+ 			.type   = CX88_VMUX_COMPOSITE1,
+ 			.vmux   = 1,
+ 			.gpio0  = 0x3de6,
+-			.extadc = 1,
++			.audioroute = 1,
+ 		},{
+ 			.type   = CX88_VMUX_SVIDEO,
+ 			.vmux   = 2,
+ 			.gpio0  = 0x3de6,
+-			.extadc = 1,
++			.audioroute = 1,
+ 		}},
+ 		.radio = {
+ 			.type   = CX88_RADIO,
+@@ -1335,17 +1340,17 @@ static const struct cx88_board cx88_boards[] = {
+ 			.type   = CX88_VMUX_TELEVISION,
+ 			.vmux   = 0,
+ 			.gpio0	= 0xe780,
+-			.extadc = 1,
++			.audioroute = 1,
+ 		},{
+ 			.type	= CX88_VMUX_COMPOSITE1,
+ 			.vmux	= 1,
+ 			.gpio0	= 0xe780,
+-			.extadc = 1,
++			.audioroute = 2,
+ 		},{
+ 			.type	= CX88_VMUX_SVIDEO,
+ 			.vmux	= 2,
+ 			.gpio0	= 0xe780,
+-			.extadc = 1,
++			.audioroute = 2,
+ 		}},
+ 		/* fixme: Add radio support */
+ 		.mpeg           = CX88_MPEG_DVB | CX88_MPEG_BLACKBIRD,
+@@ -1370,6 +1375,32 @@ static const struct cx88_board cx88_boards[] = {
+ 			.gpio0  = 0x07fa,
+ 		}},
+ 	},
++	[CX88_BOARD_PINNACLE_PCTV_HD_800i] = {
++		.name           = "Pinnacle PCTV HD 800i",
++		.tuner_type     = TUNER_XC5000,
++		.radio_type     = UNSET,
++		.tuner_addr	= ADDR_UNSET,
++		.radio_addr	= ADDR_UNSET,
++		.input          = {{
++			.type   = CX88_VMUX_TELEVISION,
++			.vmux   = 0,
++			.gpio0  = 0x04fb,
++			.gpio1  = 0x10ff,
++		},{
++			.type   = CX88_VMUX_COMPOSITE1,
++			.vmux   = 1,
++			.gpio0  = 0x04fb,
++			.gpio1  = 0x10ef,
++			.audioroute = 1,
++		},{
++			.type   = CX88_VMUX_SVIDEO,
++			.vmux   = 2,
++			.gpio0  = 0x04fb,
++			.gpio1  = 0x10ef,
++			.audioroute = 1,
++		}},
++		.mpeg           = CX88_MPEG_DVB,
++	},
+ };
  
- 	if ( (pci_status & PCI_MSK_RISC_RD) ||
- 	     (pci_status & PCI_MSK_RISC_WR) ||
-@@ -1380,11 +1507,18 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id)
+ /* ------------------------------------------------------------------ */
+@@ -1679,6 +1710,10 @@ static const struct cx88_subid cx88_subids[] = {
+ 		.subvendor = 0x1421,
+ 		.subdevice = 0x0390,
+ 		.card      = CX88_BOARD_ADSTECH_PTV_390,
++	},{
++		.subvendor = 0x11bd,
++		.subdevice = 0x0051,
++		.card      = CX88_BOARD_PINNACLE_PCTV_HD_800i,
+ 	},
+ };
  
- 	}
+@@ -1846,6 +1881,36 @@ static void dvico_fusionhdtv_hybrid_init(struct cx88_core *core)
+ }
  
--	if (ts1_status)
--		handled += cx23885_irq_ts(ts1, ts1_status);
-+	if (ts1_status) {
-+		if (cx23885_boards[dev->board].portb == CX23885_MPEG_DVB)
-+			handled += cx23885_irq_ts(ts1, ts1_status);
-+	}
+ /* ----------------------------------------------------------------------- */
++/* Tuner callback function. Currently only needed for the Pinnacle 	   *
++ * PCTV HD 800i with an xc5000 sillicon tuner. This is used for both	   *
++ * analog tuner attach (tuner-core.c) and dvb tuner attach (cx88-dvb.c)    */
 +
-+	if (ts2_status) {
-+		if (cx23885_boards[dev->board].portc == CX23885_MPEG_DVB)
-+			handled += cx23885_irq_ts(ts2, ts2_status);
++int cx88_tuner_callback(void *priv, int command, int arg)
++{
++	struct i2c_algo_bit_data *i2c_algo = priv;
++	struct cx88_core *core = i2c_algo->data;
++
++	switch(core->boardnr) {
++	case CX88_BOARD_PINNACLE_PCTV_HD_800i:
++		if(command == 0) { /* This is the reset command from xc5000 */
++			/* Reset XC5000 tuner via SYS_RSTO_pin */
++			cx_write(MO_SRST_IO, 0);
++			msleep(10);
++			cx_write(MO_SRST_IO, 1);
++			return 0;
++		}
++		else {
++			printk(KERN_ERR
++				"xc5000: unknown tuner callback command.\n");
++			return -EINVAL;
++		}
++		break;
 +	}
++	return 0; /* Should never be here */
++}
++EXPORT_SYMBOL(cx88_tuner_callback);
++
++/* ----------------------------------------------------------------------- */
  
--	if (ts2_status)
--		handled += cx23885_irq_ts(ts2, ts2_status);
-+	if (vida_status)
-+		handled += cx23885_video_irq(dev, vida_status);
- 
- 	if (handled)
- 		cx_write(PCI_INT_STAT, pci_status);
-diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c
-index eda8c05..ed465c0 100644
---- a/drivers/media/video/cx23885/cx23885-dvb.c
-+++ b/drivers/media/video/cx23885/cx23885-dvb.c
-@@ -32,13 +32,26 @@
- 
- #include "s5h1409.h"
- #include "mt2131.h"
-+#include "tda8290.h"
-+#include "tda18271.h"
- #include "lgdt330x.h"
-+#include "xc5000.h"
- #include "dvb-pll.h"
-+#include "tuner-xc2028.h"
-+#include "tuner-xc2028-types.h"
- 
--static unsigned int debug = 0;
-+static unsigned int debug;
- 
--#define dprintk(level,fmt, arg...)	if (debug >= level) \
--	printk(KERN_DEBUG "%s: " fmt, dev->name, ## arg)
-+#define dprintk(level, fmt, arg...)\
-+	do { if (debug >= level)\
-+		printk(KERN_DEBUG "%s/0: " fmt, dev->name, ## arg);\
-+	} while (0)
+ static void cx88_card_list(struct cx88_core *core, struct pci_dev *pci)
+ {
+@@ -1979,6 +2044,23 @@ static void cx88_card_setup(struct cx88_core *core)
+ 						core->name, i);
+ 		}
+ 		break;
++	case CX88_BOARD_MSI_TVANYWHERE_MASTER:
++	{
++		struct v4l2_priv_tun_config tea5767_cfg;
++		struct tea5767_ctrl ctl;
 +
-+/* ------------------------------------------------------------------ */
++		memset(&ctl, 0, sizeof(ctl));
 +
-+static unsigned int alt_tuner;
-+module_param(alt_tuner, int, 0644);
-+MODULE_PARM_DESC(alt_tuner, "Enable alternate tuner configuration");
- 
- /* ------------------------------------------------------------------ */
- 
-@@ -85,18 +98,39 @@ static struct s5h1409_config hauppauge_generic_config = {
- 	.demod_address = 0x32 >> 1,
- 	.output_mode   = S5H1409_SERIAL_OUTPUT,
- 	.gpio          = S5H1409_GPIO_ON,
--	.if_freq       = 44000,
-+	.qam_if        = 44000,
- 	.inversion     = S5H1409_INVERSION_OFF,
--	.status_mode   = S5H1409_DEMODLOCKING
-+	.status_mode   = S5H1409_DEMODLOCKING,
-+	.mpeg_timing   = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
-+};
++		ctl.high_cut  = 1;
++		ctl.st_noise  = 1;
++		ctl.deemph_75 = 1;
++		ctl.xtal_freq = TEA5767_HIGH_LO_13MHz;
 +
-+static struct s5h1409_config hauppauge_ezqam_config = {
-+	.demod_address = 0x32 >> 1,
-+	.output_mode   = S5H1409_SERIAL_OUTPUT,
-+	.gpio          = S5H1409_GPIO_OFF,
-+	.qam_if        = 4000,
-+	.inversion     = S5H1409_INVERSION_ON,
-+	.status_mode   = S5H1409_DEMODLOCKING,
-+	.mpeg_timing   = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
- };
- 
- static struct s5h1409_config hauppauge_hvr1800lp_config = {
- 	.demod_address = 0x32 >> 1,
- 	.output_mode   = S5H1409_SERIAL_OUTPUT,
- 	.gpio          = S5H1409_GPIO_OFF,
--	.if_freq       = 44000,
-+	.qam_if        = 44000,
-+	.inversion     = S5H1409_INVERSION_OFF,
-+	.status_mode   = S5H1409_DEMODLOCKING,
-+	.mpeg_timing   = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
-+};
++		tea5767_cfg.tuner = TUNER_TEA5767;
++		tea5767_cfg.priv  = &ctl;
 +
-+static struct s5h1409_config hauppauge_hvr1500_config = {
-+	.demod_address = 0x32 >> 1,
-+	.output_mode   = S5H1409_SERIAL_OUTPUT,
-+	.gpio          = S5H1409_GPIO_OFF,
- 	.inversion     = S5H1409_INVERSION_OFF,
--	.status_mode   = S5H1409_DEMODLOCKING
-+	.status_mode   = S5H1409_DEMODLOCKING,
-+	.mpeg_timing   = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
- };
++		cx88_call_i2c_clients(core, TUNER_SET_CONFIG, &tea5767_cfg);
++	}
+ 	}
+ }
  
- static struct mt2131_config hauppauge_generic_tunerconfig = {
-@@ -109,6 +143,66 @@ static struct lgdt330x_config fusionhdtv_5_express = {
- 	.serial_mpeg = 0x40,
+diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c
+index 62e8dd2..01e2ac9 100644
+--- a/drivers/media/video/cx88/cx88-core.c
++++ b/drivers/media/video/cx88/cx88-core.c
+@@ -220,7 +220,7 @@ cx88_free_buffer(struct videobuf_queue *q, struct cx88_buffer *buf)
+ 	videobuf_dma_unmap(q, dma);
+ 	videobuf_dma_free(dma);
+ 	btcx_riscmem_free((struct pci_dev *)q->dev, &buf->risc);
+-	buf->vb.state = STATE_NEEDS_INIT;
++	buf->vb.state = VIDEOBUF_NEEDS_INIT;
+ }
+ 
+ /* ------------------------------------------------------------------ */
+@@ -538,7 +538,7 @@ void cx88_wakeup(struct cx88_core *core,
+ 		do_gettimeofday(&buf->vb.ts);
+ 		dprintk(2,"[%p/%d] wakeup reg=%d buf=%d\n",buf,buf->vb.i,
+ 			count, buf->count);
+-		buf->vb.state = STATE_DONE;
++		buf->vb.state = VIDEOBUF_DONE;
+ 		list_del(&buf->vb.queue);
+ 		wake_up(&buf->vb.done);
+ 	}
+diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c
+index fce19ca..f7b41eb 100644
+--- a/drivers/media/video/cx88/cx88-dvb.c
++++ b/drivers/media/video/cx88/cx88-dvb.c
+@@ -40,6 +40,8 @@
+ #include "cx22702.h"
+ #include "or51132.h"
+ #include "lgdt330x.h"
++#include "s5h1409.h"
++#include "xc5000.h"
+ #include "nxt200x.h"
+ #include "cx24123.h"
+ #include "isl6421.h"
+@@ -371,6 +373,22 @@ static struct cx24123_config kworld_dvbs_100_config = {
+ 	.lnb_polarity  = 1,
  };
  
-+static struct s5h1409_config hauppauge_hvr1500q_config = {
++static struct s5h1409_config pinnacle_pctv_hd_800i_config = {
 +	.demod_address = 0x32 >> 1,
-+	.output_mode   = S5H1409_SERIAL_OUTPUT,
-+	.gpio          = S5H1409_GPIO_ON,
-+	.qam_if        = 44000,
++	.output_mode   = S5H1409_PARALLEL_OUTPUT,
++	.gpio	       = S5H1409_GPIO_ON,
++	.qam_if	       = 44000,
 +	.inversion     = S5H1409_INVERSION_OFF,
 +	.status_mode   = S5H1409_DEMODLOCKING,
-+	.mpeg_timing   = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
-+};
-+
-+static struct xc5000_config hauppauge_hvr1500q_tunerconfig = {
-+	.i2c_address      = 0x61,
-+	.if_khz           = 5380,
-+	.tuner_callback   = cx23885_tuner_callback
-+};
-+
-+static struct tda829x_config tda829x_no_probe = {
-+	.probe_tuner = TDA829X_DONT_PROBE,
-+};
-+
-+static struct tda18271_std_map hauppauge_tda18271_std_map = {
-+	.atsc_6   = { .if_freq = 5380, .std_bits = 0x1b },
-+	.qam_6    = { .if_freq = 4000, .std_bits = 0x18 },
++	.mpeg_timing   = S5H1409_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK,
 +};
 +
-+static struct tda18271_config hauppauge_tda18271_config = {
-+	.std_map = &hauppauge_tda18271_std_map,
-+	.gate    = TDA18271_GATE_ANALOG,
++static struct xc5000_config pinnacle_pctv_hd_800i_tuner_config = {
++	.i2c_address	= 0x64,
++	.if_khz		= 5380,
++	.tuner_callback	= cx88_tuner_callback,
 +};
 +
-+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", __FUNCTION__, 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", __FUNCTION__, arg);
-+		break;
-+	default:
-+		dprintk(1, "%s: unknown command %d, arg %d\n", __FUNCTION__,
-+			command, arg);
-+		return -EINVAL;
-+	}
-+
-+	return 0;
-+}
-+
- static int dvb_register(struct cx23885_tsport *port)
+ static int dvb_register(struct cx8802_dev *dev)
  {
- 	struct cx23885_dev *dev = port->dev;
-@@ -120,7 +214,6 @@ static int dvb_register(struct cx23885_tsport *port)
- 	/* init frontend */
- 	switch (dev->board) {
- 	case CX23885_BOARD_HAUPPAUGE_HVR1250:
--	case CX23885_BOARD_HAUPPAUGE_HVR1800:
- 		i2c_bus = &dev->i2c_bus[0];
- 		port->dvb.frontend = dvb_attach(s5h1409_attach,
- 						&hauppauge_generic_config,
-@@ -131,6 +224,36 @@ static int dvb_register(struct cx23885_tsport *port)
- 				   &hauppauge_generic_tunerconfig, 0);
- 		}
- 		break;
-+	case CX23885_BOARD_HAUPPAUGE_HVR1800:
-+		i2c_bus = &dev->i2c_bus[0];
-+		switch (alt_tuner) {
-+		case 1:
-+			port->dvb.frontend =
-+				dvb_attach(s5h1409_attach,
-+					   &hauppauge_ezqam_config,
-+					   &i2c_bus->i2c_adap);
-+			if (port->dvb.frontend != NULL) {
-+				dvb_attach(tda829x_attach, port->dvb.frontend,
-+					   &dev->i2c_bus[1].i2c_adap, 0x42,
-+					   &tda829x_no_probe);
-+				dvb_attach(tda18271_attach, port->dvb.frontend,
-+					   0x60, &dev->i2c_bus[1].i2c_adap,
-+					   &hauppauge_tda18271_config);
-+			}
-+			break;
-+		case 0:
-+		default:
-+			port->dvb.frontend =
-+				dvb_attach(s5h1409_attach,
-+					   &hauppauge_generic_config,
-+					   &i2c_bus->i2c_adap);
-+			if (port->dvb.frontend != NULL)
-+				dvb_attach(mt2131_attach, port->dvb.frontend,
-+					   &i2c_bus->i2c_adap,
-+					   &hauppauge_generic_tunerconfig, 0);
-+			break;
-+		}
-+		break;
- 	case CX23885_BOARD_HAUPPAUGE_HVR1800lp:
- 		i2c_bus = &dev->i2c_bus[0];
- 		port->dvb.frontend = dvb_attach(s5h1409_attach,
-@@ -152,6 +275,43 @@ static int dvb_register(struct cx23885_tsport *port)
- 				   &i2c_bus->i2c_adap, DVB_PLL_LG_TDVS_H06XF);
- 		}
- 		break;
-+	case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
-+		i2c_bus = &dev->i2c_bus[1];
-+		port->dvb.frontend = dvb_attach(s5h1409_attach,
-+						&hauppauge_hvr1500q_config,
-+						&dev->i2c_bus[0].i2c_adap);
-+		if (port->dvb.frontend != NULL) {
-+			hauppauge_hvr1500q_tunerconfig.priv = i2c_bus;
-+			dvb_attach(xc5000_attach, port->dvb.frontend,
-+				&i2c_bus->i2c_adap,
-+				&hauppauge_hvr1500q_tunerconfig);
-+		}
-+		break;
-+	case CX23885_BOARD_HAUPPAUGE_HVR1500:
-+		i2c_bus = &dev->i2c_bus[1];
-+		port->dvb.frontend = dvb_attach(s5h1409_attach,
-+						&hauppauge_hvr1500_config,
-+						&dev->i2c_bus[0].i2c_adap);
-+		if (port->dvb.frontend != NULL) {
-+			struct dvb_frontend *fe;
-+			struct xc2028_config cfg = {
-+				.i2c_adap  = &i2c_bus->i2c_adap,
-+				.i2c_addr  = 0x61,
-+				.video_dev = port,
-+				.callback  = cx23885_hvr1500_xc3028_callback,
-+			};
-+			static struct xc2028_ctrl ctl = {
-+				.fname       = "xc3028-v27.fw",
-+				.max_len     = 64,
-+				.scode_table = OREN538,
-+			};
-+
-+			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);
+ 	/* init struct videobuf_dvb */
+@@ -625,6 +643,21 @@ static int dvb_register(struct cx8802_dev *dev)
+ 			dev->dvb.frontend->ops.set_voltage = geniatech_dvbs_set_voltage;
+ 		}
+ 		break;
++	case CX88_BOARD_PINNACLE_PCTV_HD_800i:
++		dev->dvb.frontend = dvb_attach(s5h1409_attach,
++					       &pinnacle_pctv_hd_800i_config,
++					       &dev->core->i2c_adap);
++		if (dev->dvb.frontend != NULL) {
++			/* tuner_config.video_dev must point to
++			 * i2c_adap.algo_data
++			 */
++			pinnacle_pctv_hd_800i_tuner_config.priv =
++						dev->core->i2c_adap.algo_data;
++			dvb_attach(xc5000_attach, dev->dvb.frontend,
++				   &dev->core->i2c_adap,
++				   &pinnacle_pctv_hd_800i_tuner_config);
 +		}
 +		break;
  	default:
- 		printk("%s: The frontend of your DVB/ATSC card isn't supported yet\n",
- 		       dev->name);
-@@ -165,6 +325,9 @@ static int dvb_register(struct cx23885_tsport *port)
- 	/* Put the analog decoder in standby to keep it quiet */
- 	cx23885_call_i2c_clients(i2c_bus, TUNER_SET_STANDBY, NULL);
+ 		printk(KERN_ERR "%s/2: The frontend of your DVB/ATSC card isn't supported yet\n",
+ 		       dev->core->name);
+diff --git a/drivers/media/video/cx88/cx88-i2c.c b/drivers/media/video/cx88/cx88-i2c.c
+index c8b1c50..566b26a 100644
+--- a/drivers/media/video/cx88/cx88-i2c.c
++++ b/drivers/media/video/cx88/cx88-i2c.c
+@@ -109,26 +109,32 @@ static int attach_inform(struct i2c_client *client)
  
-+	if (port->dvb.frontend->ops.analog_ops.standby)
-+		port->dvb.frontend->ops.analog_ops.standby(port->dvb.frontend);
+ 	if (core->board.radio_type != UNSET) {
+ 		if ((core->board.radio_addr==ADDR_UNSET)||(core->board.radio_addr==client->addr)) {
+-			tun_setup.mode_mask = T_RADIO;
+-			tun_setup.type = core->board.radio_type;
+-			tun_setup.addr = core->board.radio_addr;
+-
++			tun_setup.mode_mask	 = T_RADIO;
++			tun_setup.type		 = core->board.radio_type;
++			tun_setup.addr		 = core->board.radio_addr;
++			tun_setup.tuner_callback = cx88_tuner_callback;
+ 			client->driver->command (client, TUNER_SET_TYPE_ADDR, &tun_setup);
+ 		}
+ 	}
+ 	if (core->board.tuner_type != UNSET) {
+ 		if ((core->board.tuner_addr==ADDR_UNSET)||(core->board.tuner_addr==client->addr)) {
+ 
+-			tun_setup.mode_mask = T_ANALOG_TV;
+-			tun_setup.type = core->board.tuner_type;
+-			tun_setup.addr = core->board.tuner_addr;
+-
++			tun_setup.mode_mask	 = T_ANALOG_TV;
++			tun_setup.type		 = core->board.tuner_type;
++			tun_setup.addr		 = core->board.tuner_addr;
++			tun_setup.tuner_callback = cx88_tuner_callback;
+ 			client->driver->command (client,TUNER_SET_TYPE_ADDR, &tun_setup);
+ 		}
+ 	}
+ 
+-	if (core->board.tda9887_conf)
+-		client->driver->command(client, TDA9887_SET_CONFIG, &core->board.tda9887_conf);
++	if (core->board.tda9887_conf) {
++		struct v4l2_priv_tun_config tda9887_cfg;
 +
- 	/* register everything */
- 	return videobuf_dvb_register(&port->dvb, THIS_MODULE, port,
- 				     &dev->pci->dev);
-diff --git a/drivers/media/video/cx23885/cx23885-i2c.c b/drivers/media/video/cx23885/cx23885-i2c.c
-index 71da528..92fe0bd 100644
---- a/drivers/media/video/cx23885/cx23885-i2c.c
-+++ b/drivers/media/video/cx23885/cx23885-i2c.c
-@@ -29,7 +29,7 @@
++		tda9887_cfg.tuner = TUNER_TDA9887;
++		tda9887_cfg.priv  = &core->board.tda9887_conf;
++
++		client->driver->command(client, TUNER_SET_CONFIG, &tda9887_cfg);
++	}
+ 	return 0;
+ }
  
- #include <media/v4l2-common.h>
+@@ -176,6 +182,7 @@ static char *i2c_devs[128] = {
+ 	[ 0xa0 >> 1 ] = "eeprom",
+ 	[ 0xc0 >> 1 ] = "tuner (analog)",
+ 	[ 0xc2 >> 1 ] = "tuner (analog/dvb)",
++	[ 0xc8 >> 1 ] = "xc5000",
+ };
  
--static unsigned int i2c_debug = 0;
-+static unsigned int i2c_debug;
- module_param(i2c_debug, int, 0644);
- MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]");
+ static void do_i2c_scan(char *name, struct i2c_client *c)
+diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c
+index e52de39..bb0911b 100644
+--- a/drivers/media/video/cx88/cx88-input.c
++++ b/drivers/media/video/cx88/cx88-input.c
+@@ -305,6 +305,11 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
+ 		ir->mask_keycode = 0xfa;
+ 		ir->polling = 50; /* ms */
+ 		break;
++	case CX88_BOARD_PINNACLE_PCTV_HD_800i:
++		ir_codes = ir_codes_pinnacle_pctv_hd;
++		ir_type = IR_TYPE_RC5;
++		ir->sampling = 1;
++		break;
+ 	}
  
-@@ -37,8 +37,10 @@ static unsigned int i2c_scan = 0;
- module_param(i2c_scan, int, 0444);
- MODULE_PARM_DESC(i2c_scan, "scan i2c bus at insmod time");
+ 	if (NULL == ir_codes) {
+@@ -443,6 +448,7 @@ void cx88_ir_irq(struct cx88_core *core)
+ 	case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1:
+ 	case CX88_BOARD_HAUPPAUGE_HVR1100:
+ 	case CX88_BOARD_HAUPPAUGE_HVR3000:
++	case CX88_BOARD_PINNACLE_PCTV_HD_800i:
+ 		ircode = ir_decode_biphase(ir->samples, ir->scount, 5, 7);
+ 		ir_dprintk("biphase decoded: %x\n", ircode);
+ 		if ((ircode & 0xfffff000) != 0x3000)
+diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c
+index 448c673..0aedbea 100644
+--- a/drivers/media/video/cx88/cx88-mpeg.c
++++ b/drivers/media/video/cx88/cx88-mpeg.c
+@@ -102,7 +102,7 @@ static int cx8802_start_dma(struct cx8802_dev    *dev,
+ 		cx_write(TS_GEN_CNTRL, 0x0040 | dev->ts_gen_cntrl);
+ 		udelay(100);
+ 		cx_write(MO_PINMUX_IO, 0x00);
+-		cx_write(TS_HW_SOP_CNTRL,0x47<<16|188<<4|0x01);
++		cx_write(TS_HW_SOP_CNTRL, 0x47<<16|188<<4|0x01);
+ 		switch (core->boardnr) {
+ 		case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q:
+ 		case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T:
+@@ -117,6 +117,15 @@ static int cx8802_start_dma(struct cx8802_dev    *dev,
+ 			break;
+ 		case CX88_BOARD_HAUPPAUGE_HVR1300:
+ 			break;
++		case CX88_BOARD_PINNACLE_PCTV_HD_800i:
++			/* Enable MPEG parallel IO and video signal pins */
++			cx_write(MO_PINMUX_IO, 0x88);
++			cx_write(TS_HW_SOP_CNTRL, (0x47 << 16) | (188 << 4));
++			dev->ts_gen_cntrl = 5;
++			cx_write(TS_SOP_STAT, 0);
++			cx_write(TS_VALERR_CNTRL, 0);
++			udelay(100);
++			break;
+ 		default:
+ 			cx_write(TS_SOP_STAT, 0x00);
+ 			break;
+@@ -195,7 +204,7 @@ static int cx8802_restart_queue(struct cx8802_dev    *dev,
+ 				list_del(&buf->vb.queue);
+ 				list_add_tail(&buf->vb.queue,&q->active);
+ 				cx8802_start_dma(dev, q, buf);
+-				buf->vb.state = STATE_ACTIVE;
++				buf->vb.state = VIDEOBUF_ACTIVE;
+ 				buf->count    = q->count++;
+ 				mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
+ 				dprintk(1,"[%p/%d] restart_queue - first active\n",
+@@ -206,7 +215,7 @@ static int cx8802_restart_queue(struct cx8802_dev    *dev,
+ 				   prev->fmt       == buf->fmt) {
+ 				list_del(&buf->vb.queue);
+ 				list_add_tail(&buf->vb.queue,&q->active);
+-				buf->vb.state = STATE_ACTIVE;
++				buf->vb.state = VIDEOBUF_ACTIVE;
+ 				buf->count    = q->count++;
+ 				prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
+ 				dprintk(1,"[%p/%d] restart_queue - move to active\n",
+@@ -242,7 +251,7 @@ int cx8802_buf_prepare(struct videobuf_queue *q, struct cx8802_dev *dev,
+ 	if (0 != buf->vb.baddr  &&  buf->vb.bsize < size)
+ 		return -EINVAL;
  
--#define dprintk(level,fmt, arg...)	if (i2c_debug >= level) \
--	printk(KERN_DEBUG "%s: " fmt, dev->name , ## arg)
-+#define dprintk(level, fmt, arg...)\
-+	do { if (i2c_debug >= level)\
-+		printk(KERN_DEBUG "%s/0: " fmt, dev->name, ## arg);\
-+	} while (0)
+-	if (STATE_NEEDS_INIT == buf->vb.state) {
++	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
+ 		buf->vb.width  = dev->ts_packet_size;
+ 		buf->vb.height = dev->ts_packet_count;
+ 		buf->vb.size   = size;
+@@ -254,7 +263,7 @@ int cx8802_buf_prepare(struct videobuf_queue *q, struct cx8802_dev *dev,
+ 				     dma->sglist,
+ 				     buf->vb.width, buf->vb.height, 0);
+ 	}
+-	buf->vb.state = STATE_PREPARED;
++	buf->vb.state = VIDEOBUF_PREPARED;
+ 	return 0;
  
- #define I2C_WAIT_DELAY 32
- #define I2C_WAIT_RETRY 64
-@@ -77,14 +79,19 @@ static int i2c_wait_done(struct i2c_adapter *i2c_adap)
+  fail:
+@@ -276,7 +285,7 @@ void cx8802_buf_queue(struct cx8802_dev *dev, struct cx88_buffer *buf)
+ 		dprintk( 1, "queue is empty - first active\n" );
+ 		list_add_tail(&buf->vb.queue,&cx88q->active);
+ 		cx8802_start_dma(dev, cx88q, buf);
+-		buf->vb.state = STATE_ACTIVE;
++		buf->vb.state = VIDEOBUF_ACTIVE;
+ 		buf->count    = cx88q->count++;
+ 		mod_timer(&cx88q->timeout, jiffies+BUFFER_TIMEOUT);
+ 		dprintk(1,"[%p/%d] %s - first active\n",
+@@ -286,7 +295,7 @@ void cx8802_buf_queue(struct cx8802_dev *dev, struct cx88_buffer *buf)
+ 		dprintk( 1, "queue is not empty - append to active\n" );
+ 		prev = list_entry(cx88q->active.prev, struct cx88_buffer, vb.queue);
+ 		list_add_tail(&buf->vb.queue,&cx88q->active);
+-		buf->vb.state = STATE_ACTIVE;
++		buf->vb.state = VIDEOBUF_ACTIVE;
+ 		buf->count    = cx88q->count++;
+ 		prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
+ 		dprintk( 1, "[%p/%d] %s - append to active\n",
+@@ -306,7 +315,7 @@ static void do_cancel_buffers(struct cx8802_dev *dev, char *reason, int restart)
+ 	while (!list_empty(&q->active)) {
+ 		buf = list_entry(q->active.next, struct cx88_buffer, vb.queue);
+ 		list_del(&buf->vb.queue);
+-		buf->vb.state = STATE_ERROR;
++		buf->vb.state = VIDEOBUF_ERROR;
+ 		wake_up(&buf->vb.done);
+ 		dprintk(1,"[%p/%d] %s - dma=0x%08lx\n",
+ 			buf, buf->vb.i, reason, (unsigned long)buf->risc.dma);
+@@ -437,10 +446,7 @@ static irqreturn_t cx8802_irq(int irq, void *dev_id)
+ 	return IRQ_RETVAL(handled);
  }
  
- static int i2c_sendbytes(struct i2c_adapter *i2c_adap,
--			 const struct i2c_msg *msg, int last)
-+			 const struct i2c_msg *msg, int joined_rlen)
+-/* ----------------------------------------------------------- */
+-/* exported stuff                                              */
+-
+-int cx8802_init_common(struct cx8802_dev *dev)
++static int cx8802_init_common(struct cx8802_dev *dev)
  {
- 	struct cx23885_i2c *bus = i2c_adap->algo_data;
- 	struct cx23885_dev *dev = bus->dev;
- 	u32 wdata, addr, ctrl;
- 	int retval, cnt;
- 
--	dprintk(1, "%s()\n", __FUNCTION__);
-+	if (joined_rlen)
-+		dprintk(1, "%s(msg->wlen=%d, nextmsg->rlen=%d)\n", __FUNCTION__,
-+			msg->len, joined_rlen);
-+	else
-+		dprintk(1, "%s(msg->len=%d)\n", __FUNCTION__, msg->len);
-+
- 	/* Deal with i2c probe functions with zero payload */
- 	if (msg->len == 0) {
- 		cx_write(bus->reg_addr, msg->addr << 25);
-@@ -106,6 +113,8 @@ static int i2c_sendbytes(struct i2c_adapter *i2c_adap,
- 
- 	if (msg->len > 1)
- 		ctrl |= I2C_NOSTOP | I2C_EXTEND;
-+	else if (joined_rlen)
-+		ctrl |= I2C_NOSTOP;
+ 	struct cx88_core *core = dev->core;
+ 	int err;
+@@ -488,7 +494,7 @@ int cx8802_init_common(struct cx8802_dev *dev)
+ 	return 0;
+ }
  
- 	cx_write(bus->reg_addr, addr);
- 	cx_write(bus->reg_wdata, wdata);
-@@ -127,8 +136,10 @@ static int i2c_sendbytes(struct i2c_adapter *i2c_adap,
- 		wdata = msg->buf[cnt];
- 		ctrl = bus->i2c_period | (1 << 12) | (1 << 2);
+-void cx8802_fini_common(struct cx8802_dev *dev)
++static void cx8802_fini_common(struct cx8802_dev *dev)
+ {
+ 	dprintk( 2, "cx8802_fini_common\n" );
+ 	cx8802_stop_dma(dev);
+@@ -504,7 +510,7 @@ void cx8802_fini_common(struct cx8802_dev *dev)
  
--		if (cnt < msg->len-1 || !last)
-+		if (cnt < msg->len - 1)
- 			ctrl |= I2C_NOSTOP | I2C_EXTEND;
-+		else if (joined_rlen)
-+			ctrl |= I2C_NOSTOP;
+ /* ----------------------------------------------------------- */
  
- 		cx_write(bus->reg_addr, addr);
- 		cx_write(bus->reg_wdata, wdata);
-@@ -150,19 +161,22 @@ static int i2c_sendbytes(struct i2c_adapter *i2c_adap,
-  eio:
- 	retval = -EIO;
-  err:
--	printk(" ERR: %d\n", retval);
-+	if (i2c_debug)
-+		printk(" ERR: %d\n", retval);
- 	return retval;
+-int cx8802_suspend_common(struct pci_dev *pci_dev, pm_message_t state)
++static int cx8802_suspend_common(struct pci_dev *pci_dev, pm_message_t state)
+ {
+ 	struct cx8802_dev *dev = pci_get_drvdata(pci_dev);
+ 	struct cx88_core *core = dev->core;
+@@ -530,7 +536,7 @@ int cx8802_suspend_common(struct pci_dev *pci_dev, pm_message_t state)
+ 	return 0;
  }
  
- static int i2c_readbytes(struct i2c_adapter *i2c_adap,
--			 const struct i2c_msg *msg, int last)
-+			 const struct i2c_msg *msg, int joined)
+-int cx8802_resume_common(struct pci_dev *pci_dev)
++static int cx8802_resume_common(struct pci_dev *pci_dev)
  {
- 	struct cx23885_i2c *bus = i2c_adap->algo_data;
- 	struct cx23885_dev *dev = bus->dev;
- 	u32 ctrl, cnt;
- 	int retval;
+ 	struct cx8802_dev *dev = pci_get_drvdata(pci_dev);
+ 	struct cx88_core *core = dev->core;
+@@ -874,9 +880,6 @@ EXPORT_SYMBOL(cx8802_buf_prepare);
+ EXPORT_SYMBOL(cx8802_buf_queue);
+ EXPORT_SYMBOL(cx8802_cancel_buffers);
  
--	dprintk(1, "%s()\n", __FUNCTION__);
-+
-+	if (i2c_debug && !joined)
-+		dprintk(1, "%s(msg->len=%d)\n", __FUNCTION__, msg->len);
+-EXPORT_SYMBOL(cx8802_init_common);
+-EXPORT_SYMBOL(cx8802_fini_common);
+-
+ EXPORT_SYMBOL(cx8802_register_driver);
+ EXPORT_SYMBOL(cx8802_unregister_driver);
+ EXPORT_SYMBOL(cx8802_get_driver);
+diff --git a/drivers/media/video/cx88/cx88-vbi.c b/drivers/media/video/cx88/cx88-vbi.c
+index babb085..d96ecfc 100644
+--- a/drivers/media/video/cx88/cx88-vbi.c
++++ b/drivers/media/video/cx88/cx88-vbi.c
+@@ -130,7 +130,7 @@ void cx8800_vbi_timeout(unsigned long data)
+ 	while (!list_empty(&q->active)) {
+ 		buf = list_entry(q->active.next, struct cx88_buffer, vb.queue);
+ 		list_del(&buf->vb.queue);
+-		buf->vb.state = STATE_ERROR;
++		buf->vb.state = VIDEOBUF_ERROR;
+ 		wake_up(&buf->vb.done);
+ 		printk("%s/0: [%p/%d] timeout - dma=0x%08lx\n", dev->core->name,
+ 		       buf, buf->vb.i, (unsigned long)buf->risc.dma);
+@@ -168,7 +168,7 @@ vbi_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
+ 	if (0 != buf->vb.baddr  &&  buf->vb.bsize < size)
+ 		return -EINVAL;
  
- 	/* Deal with i2c probe functions with zero payload */
- 	if (msg->len == 0) {
-@@ -178,11 +192,18 @@ static int i2c_readbytes(struct i2c_adapter *i2c_adap,
- 		return 0;
+-	if (STATE_NEEDS_INIT == buf->vb.state) {
++	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
+ 		struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
+ 		buf->vb.width  = VBI_LINE_LENGTH;
+ 		buf->vb.height = VBI_LINE_COUNT;
+@@ -183,7 +183,7 @@ vbi_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
+ 				 buf->vb.width, 0,
+ 				 buf->vb.height);
  	}
+-	buf->vb.state = STATE_PREPARED;
++	buf->vb.state = VIDEOBUF_PREPARED;
+ 	return 0;
  
-+	if (i2c_debug) {
-+		if (joined)
-+			printk(" R");
-+		else
-+			printk(" <R %02x", (msg->addr << 1) + 1);
-+	}
-+
- 	for(cnt = 0; cnt < msg->len; cnt++) {
- 
- 		ctrl = bus->i2c_period | (1 << 12) | (1 << 2) | 1;
- 
--		if (cnt < msg->len-1 || !last)
-+		if (cnt < msg->len - 1)
- 			ctrl |= I2C_NOSTOP | I2C_EXTEND;
- 
- 		cx_write(bus->reg_addr, msg->addr << 25);
-@@ -195,9 +216,7 @@ static int i2c_readbytes(struct i2c_adapter *i2c_adap,
- 			goto eio;
- 		msg->buf[cnt] = cx_read(bus->reg_rdata) & 0xff;
- 		if (i2c_debug) {
--			if (!(ctrl & I2C_NOSTOP))
--				printk(" <R %02x", (msg->addr << 1) +1);
--			printk(" =%02x", msg->buf[cnt]);
-+			printk(" %02x", msg->buf[cnt]);
- 			if (!(ctrl & I2C_NOSTOP))
- 				printk(" >\n");
- 		}
-@@ -207,7 +226,8 @@ static int i2c_readbytes(struct i2c_adapter *i2c_adap,
-  eio:
- 	retval = -EIO;
-  err:
--	printk(" ERR: %d\n", retval);
-+	if (i2c_debug)
-+		printk(" ERR: %d\n", retval);
- 	return retval;
- }
- 
-@@ -225,15 +245,22 @@ static int i2c_xfer(struct i2c_adapter *i2c_adap,
- 			__FUNCTION__, num, msgs[i].addr, msgs[i].len);
- 		if (msgs[i].flags & I2C_M_RD) {
- 			/* read */
--			retval = i2c_readbytes(i2c_adap, &msgs[i], i+1 == num);
-+			retval = i2c_readbytes(i2c_adap, &msgs[i], 0);
-+		} else if (i + 1 < num && (msgs[i + 1].flags & I2C_M_RD) &&
-+			   msgs[i].addr == msgs[i + 1].addr) {
-+			/* write then read from same address */
-+			retval = i2c_sendbytes(i2c_adap, &msgs[i],
-+					       msgs[i + 1].len);
- 			if (retval < 0)
- 				goto err;
-+			i++;
-+			retval = i2c_readbytes(i2c_adap, &msgs[i], 1);
- 		} else {
- 			/* write */
--			retval = i2c_sendbytes(i2c_adap, &msgs[i], i+1 == num);
--			if (retval < 0)
--				goto err;
-+			retval = i2c_sendbytes(i2c_adap, &msgs[i], 0);
- 		}
-+		if (retval < 0)
-+			goto err;
+  fail:
+@@ -207,7 +207,7 @@ vbi_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+ 	if (list_empty(&q->active)) {
+ 		list_add_tail(&buf->vb.queue,&q->active);
+ 		cx8800_start_vbi_dma(dev, q, buf);
+-		buf->vb.state = STATE_ACTIVE;
++		buf->vb.state = VIDEOBUF_ACTIVE;
+ 		buf->count    = q->count++;
+ 		mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
+ 		dprintk(2,"[%p/%d] vbi_queue - first active\n",
+@@ -216,7 +216,7 @@ vbi_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+ 	} else {
+ 		prev = list_entry(q->active.prev, struct cx88_buffer, vb.queue);
+ 		list_add_tail(&buf->vb.queue,&q->active);
+-		buf->vb.state = STATE_ACTIVE;
++		buf->vb.state = VIDEOBUF_ACTIVE;
+ 		buf->count    = q->count++;
+ 		prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
+ 		dprintk(2,"[%p/%d] buffer_queue - append to active\n",
+diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c
+index c84dafb..7f1931a 100644
+--- a/drivers/media/video/cx88/cx88-video.c
++++ b/drivers/media/video/cx88/cx88-video.c
+@@ -392,13 +392,41 @@ int cx88_video_mux(struct cx88_core *core, unsigned int input)
+ 		break;
  	}
- 	return num;
- 
-@@ -243,7 +270,9 @@ static int i2c_xfer(struct i2c_adapter *i2c_adap,
- 
- static int attach_inform(struct i2c_client *client)
- {
--	struct cx23885_dev *dev = i2c_get_adapdata(client->adapter);
-+	struct cx23885_i2c *bus = i2c_get_adapdata(client->adapter);
-+	struct cx23885_dev *dev = bus->dev;
-+	struct tuner_setup tun_setup;
- 
- 	dprintk(1, "%s i2c attach [addr=0x%x,client=%s]\n",
- 		client->driver->driver.name, client->addr, client->name);
-@@ -251,6 +280,31 @@ static int attach_inform(struct i2c_client *client)
- 	if (!client->driver->command)
- 		return 0;
  
-+	if (dev->tuner_type != UNSET) {
+-	if (core->board.mpeg & CX88_MPEG_BLACKBIRD) {
+-		/* sets sound input from external adc */
+-		if (INPUT(input).extadc)
++	/* if there are audioroutes defined, we have an external
++	   ADC to deal with audio */
 +
-+		dprintk(1, "%s  (tuner) i2c attach [addr=0x%x,client=%s]\n",
-+			client->driver->driver.name, client->addr,
-+			client->name);
++	if (INPUT(input).audioroute) {
 +
-+		if ((dev->tuner_addr == ADDR_UNSET) ||
-+			(dev->tuner_addr == client->addr)) {
++		/* cx2388's C-ADC is connected to the tuner only.
++		   When used with S-Video, that ADC is busy dealing with
++		   chroma, so an external must be used for baseband audio */
 +
-+			dprintk(1, "%s (tuner || addr UNSET)\n",
-+				client->driver->driver.name);
++		if (INPUT(input).type != CX88_VMUX_TELEVISION &&
++			INPUT(input).type != CX88_RADIO) {
++			/* "ADC mode" */
++			cx_write(AUD_I2SCNTL, 0x1);
+ 			cx_set(AUD_CTL, EN_I2SIN_ENABLE);
+-		else
++		} else {
++			/* Normal mode */
++			cx_write(AUD_I2SCNTL, 0x0);
+ 			cx_clear(AUD_CTL, EN_I2SIN_ENABLE);
++		}
 +
-+			dprintk(1, "%s i2c attach [addr=0x%x,client=%s]\n",
-+				client->driver->driver.name,
-+				client->addr, client->name);
++		/* The wm8775 module has the "2" route hardwired into
++		   the initialization. Some boards may use different
++		   routes for different inputs. HVR-1300 surely does */
++		if (core->board.audio_chip &&
++		    core->board.audio_chip == AUDIO_CHIP_WM8775) {
++			struct v4l2_routing route;
 +
-+			tun_setup.mode_mask = T_ANALOG_TV;
-+			tun_setup.type = dev->tuner_type;
-+			tun_setup.addr = dev->tuner_addr;
++			route.input = INPUT(input).audioroute;
++			cx88_call_i2c_clients(core,
++				VIDIOC_INT_S_AUDIO_ROUTING, &route);
 +
-+			client->driver->command(client, TUNER_SET_TYPE_ADDR,
-+				&tun_setup);
 +		}
-+	}
 +
+ 	}
++
+ 	return 0;
+ }
+ EXPORT_SYMBOL(cx88_video_mux);
+@@ -486,7 +514,7 @@ static int restart_video_queue(struct cx8800_dev    *dev,
+ 		if (NULL == prev) {
+ 			list_move_tail(&buf->vb.queue, &q->active);
+ 			start_video_dma(dev, q, buf);
+-			buf->vb.state = STATE_ACTIVE;
++			buf->vb.state = VIDEOBUF_ACTIVE;
+ 			buf->count    = q->count++;
+ 			mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
+ 			dprintk(2,"[%p/%d] restart_queue - first active\n",
+@@ -496,7 +524,7 @@ static int restart_video_queue(struct cx8800_dev    *dev,
+ 			   prev->vb.height == buf->vb.height &&
+ 			   prev->fmt       == buf->fmt) {
+ 			list_move_tail(&buf->vb.queue, &q->active);
+-			buf->vb.state = STATE_ACTIVE;
++			buf->vb.state = VIDEOBUF_ACTIVE;
+ 			buf->count    = q->count++;
+ 			prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
+ 			dprintk(2,"[%p/%d] restart_queue - move to active\n",
+@@ -553,7 +581,7 @@ buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
+ 		init_buffer = 1;
+ 	}
+ 
+-	if (STATE_NEEDS_INIT == buf->vb.state) {
++	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
+ 		init_buffer = 1;
+ 		if (0 != (rc = videobuf_iolock(q,&buf->vb,NULL)))
+ 			goto fail;
+@@ -601,7 +629,7 @@ buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
+ 		fh->width, fh->height, fh->fmt->depth, fh->fmt->name,
+ 		(unsigned long)buf->risc.dma);
+ 
+-	buf->vb.state = STATE_PREPARED;
++	buf->vb.state = VIDEOBUF_PREPARED;
+ 	return 0;
+ 
+  fail:
+@@ -625,14 +653,14 @@ buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+ 
+ 	if (!list_empty(&q->queued)) {
+ 		list_add_tail(&buf->vb.queue,&q->queued);
+-		buf->vb.state = STATE_QUEUED;
++		buf->vb.state = VIDEOBUF_QUEUED;
+ 		dprintk(2,"[%p/%d] buffer_queue - append to queued\n",
+ 			buf, buf->vb.i);
+ 
+ 	} else if (list_empty(&q->active)) {
+ 		list_add_tail(&buf->vb.queue,&q->active);
+ 		start_video_dma(dev, q, buf);
+-		buf->vb.state = STATE_ACTIVE;
++		buf->vb.state = VIDEOBUF_ACTIVE;
+ 		buf->count    = q->count++;
+ 		mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
+ 		dprintk(2,"[%p/%d] buffer_queue - first active\n",
+@@ -644,7 +672,7 @@ buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+ 		    prev->vb.height == buf->vb.height &&
+ 		    prev->fmt       == buf->fmt) {
+ 			list_add_tail(&buf->vb.queue,&q->active);
+-			buf->vb.state = STATE_ACTIVE;
++			buf->vb.state = VIDEOBUF_ACTIVE;
+ 			buf->count    = q->count++;
+ 			prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
+ 			dprintk(2,"[%p/%d] buffer_queue - append to active\n",
+@@ -652,7 +680,7 @@ buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+ 
+ 		} else {
+ 			list_add_tail(&buf->vb.queue,&q->queued);
+-			buf->vb.state = STATE_QUEUED;
++			buf->vb.state = VIDEOBUF_QUEUED;
+ 			dprintk(2,"[%p/%d] buffer_queue - first queued\n",
+ 				buf, buf->vb.i);
+ 		}
+@@ -822,8 +850,8 @@ video_poll(struct file *file, struct poll_table_struct *wait)
+ 			return POLLERR;
+ 	}
+ 	poll_wait(file, &buf->vb.done, wait);
+-	if (buf->vb.state == STATE_DONE ||
+-	    buf->vb.state == STATE_ERROR)
++	if (buf->vb.state == VIDEOBUF_DONE ||
++	    buf->vb.state == VIDEOBUF_ERROR)
+ 		return POLLIN|POLLRDNORM;
  	return 0;
  }
+@@ -1496,7 +1524,7 @@ static void cx8800_vid_timeout(unsigned long data)
+ 	while (!list_empty(&q->active)) {
+ 		buf = list_entry(q->active.next, struct cx88_buffer, vb.queue);
+ 		list_del(&buf->vb.queue);
+-		buf->vb.state = STATE_ERROR;
++		buf->vb.state = VIDEOBUF_ERROR;
+ 		wake_up(&buf->vb.done);
+ 		printk("%s/0: [%p/%d] timeout - dma=0x%08lx\n", core->name,
+ 		       buf, buf->vb.i, (unsigned long)buf->risc.dma);
+diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h
+index eb296bd..4e823f2 100644
+--- a/drivers/media/video/cx88/cx88.h
++++ b/drivers/media/video/cx88/cx88.h
+@@ -210,6 +210,7 @@ extern struct sram_channel cx88_sram_channels[];
+ #define CX88_BOARD_TE_DTV_250_OEM_SWANN    55
+ #define CX88_BOARD_HAUPPAUGE_HVR1300       56
+ #define CX88_BOARD_ADSTECH_PTV_390         57
++#define CX88_BOARD_PINNACLE_PCTV_HD_800i   58
  
-@@ -289,6 +343,7 @@ static struct i2c_adapter cx23885_i2c_adap_template = {
- 	.owner             = THIS_MODULE,
- 	.id                = I2C_HW_B_CX23885,
- 	.algo              = &cx23885_i2c_algo_template,
-+	.class             = I2C_CLASS_TV_ANALOG,
- 	.client_register   = attach_inform,
- 	.client_unregister = detach_inform,
- };
-@@ -305,7 +360,7 @@ static char *i2c_devs[128] = {
- 	[ 0x84 >> 1 ] = "tda8295",
- 	[ 0xa0 >> 1 ] = "eeprom",
- 	[ 0xc0 >> 1 ] = "tuner/mt2131/tda8275",
--	[ 0xc2 >> 1 ] = "tuner/mt2131/tda8275",
-+	[ 0xc2 >> 1 ] = "tuner/mt2131/tda8275/xc5000",
+ enum cx88_itype {
+ 	CX88_VMUX_COMPOSITE1 = 1,
+@@ -228,7 +229,7 @@ struct cx88_input {
+ 	enum cx88_itype type;
+ 	u32             gpio0, gpio1, gpio2, gpio3;
+ 	unsigned int    vmux:2;
+-	unsigned int    extadc:1;
++	unsigned int    audioroute:2;
  };
  
- static void do_i2c_scan(char *name, struct i2c_client *c)
-@@ -344,6 +399,7 @@ int cx23885_i2c_register(struct cx23885_i2c *bus)
- 
- 	bus->i2c_algo.data = bus;
- 	bus->i2c_adap.algo_data = bus;
-+	i2c_set_adapdata(&bus->i2c_adap, bus);
- 	i2c_add_adapter(&bus->i2c_adap);
+ struct cx88_board {
+@@ -461,6 +462,7 @@ struct cx8802_dev {
+ 	u32                        mailbox;
+ 	int                        width;
+ 	int                        height;
++	unsigned char              mpeg_active; /* nonzero if mpeg encoder is active */
  
- 	bus->i2c_client.adapter = &bus->i2c_adap;
-@@ -366,8 +422,6 @@ int cx23885_i2c_unregister(struct cx23885_i2c *bus)
+ 	/* mpeg params */
+ 	struct cx2341x_mpeg_params params;
+@@ -588,6 +590,7 @@ extern void cx88_call_i2c_clients(struct cx88_core *core,
+ /* ----------------------------------------------------------- */
+ /* cx88-cards.c                                                */
  
- /* ----------------------------------------------------------------------- */
++extern int cx88_tuner_callback(void *dev, 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);
+@@ -633,12 +636,6 @@ int cx8802_buf_prepare(struct videobuf_queue *q,struct cx8802_dev *dev,
+ void cx8802_buf_queue(struct cx8802_dev *dev, struct cx88_buffer *buf);
+ void cx8802_cancel_buffers(struct cx8802_dev *dev);
  
--EXPORT_SYMBOL(cx23885_call_i2c_clients);
+-int cx8802_init_common(struct cx8802_dev *dev);
+-void cx8802_fini_common(struct cx8802_dev *dev);
 -
- /*
-  * Local variables:
-  * c-basic-offset: 8
-diff --git a/drivers/media/video/cx23885/cx23885-reg.h b/drivers/media/video/cx23885/cx23885-reg.h
-index 162169f..bdd11bc 100644
---- a/drivers/media/video/cx23885/cx23885-reg.h
-+++ b/drivers/media/video/cx23885/cx23885-reg.h
-@@ -233,6 +233,17 @@ Channel manager Data Structure entry = 20 DWORD
- #define VID_A_INT_SSTAT	0x0004002C
+-int cx8802_suspend_common(struct pci_dev *pci_dev, pm_message_t state);
+-int cx8802_resume_common(struct pci_dev *pci_dev);
+-
+ /* ----------------------------------------------------------- */
+ /* cx88-video.c*/
+ extern const u32 cx88_user_ctrls[];
+diff --git a/drivers/media/video/dpc7146.c b/drivers/media/video/dpc7146.c
+index 255dae3..566e479 100644
+--- a/drivers/media/video/dpc7146.c
++++ b/drivers/media/video/dpc7146.c
+@@ -87,11 +87,24 @@ struct dpc
+ 	int cur_input;	/* current input */
+ };
  
- #define VID_B_INT_MSK	0x00040030
-+#define VID_B_MSK_BAD_PKT     (1 << 20)
-+#define VID_B_MSK_VBI_OPC_ERR (1 << 17)
-+#define VID_B_MSK_OPC_ERR     (1 << 16)
-+#define VID_B_MSK_VBI_SYNC    (1 << 13)
-+#define VID_B_MSK_SYNC        (1 << 12)
-+#define VID_B_MSK_VBI_OF      (1 <<  9)
-+#define VID_B_MSK_OF          (1 <<  8)
-+#define VID_B_MSK_VBI_RISCI2  (1 <<  5)
-+#define VID_B_MSK_RISCI2      (1 <<  4)
-+#define VID_B_MSK_VBI_RISCI1  (1 <<  1)
-+#define VID_B_MSK_RISCI1       1
- #define VID_B_INT_STAT	0x00040034
- #define VID_B_INT_MSTAT	0x00040038
- #define VID_B_INT_SSTAT	0x0004003C
-@@ -276,6 +287,7 @@ Channel manager Data Structure entry = 20 DWORD
++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;
+-	struct i2c_client *client;
  
- #define RDR_CFG0	0x00050000
- #define RDR_CFG1	0x00050004
-+#define RDR_CFG2	0x00050008
- #define RDR_TLCTL0	0x00050318
+ 	dpc = kzalloc(sizeof(struct dpc), GFP_KERNEL);
+ 	if( NULL == dpc ) {
+@@ -115,9 +128,7 @@ static int dpc_probe(struct saa7146_dev* dev)
+ 	}
  
- /* APB DMAC Current Buffer Pointer */
-@@ -335,6 +347,7 @@ Channel manager Data Structure entry = 20 DWORD
- /* GPIO (417 Microsoftcontroller) Output Enable, Low Active */
- #define MC417_OEN	0x00110024
- #define MC417_CTL	0x00110028
-+#define ALT_PIN_OUT_SEL 0x0011002C
- #define CLK_DELAY	0x00110048
- #define PAD_CTRL	0x0011004C
+ 	/* loop through all i2c-devices on the bus and look who is there */
+-	list_for_each_entry(client, &dpc->i2c_adapter.clients, list)
+-		if( I2C_SAA7111A == client->addr )
+-			dpc->saa7111a = client;
++	device_for_each_child(&dpc->i2c_adapter.dev, dpc, dpc_check_clients);
  
-diff --git a/drivers/media/video/cx23885/cx23885-vbi.c b/drivers/media/video/cx23885/cx23885-vbi.c
+ 	/* check if all devices are present */
+ 	if( 0 == dpc->saa7111a ) {
+diff --git a/drivers/media/video/em28xx/Kconfig b/drivers/media/video/em28xx/Kconfig
+index c112780..abbd38c 100644
+--- a/drivers/media/video/em28xx/Kconfig
++++ b/drivers/media/video/em28xx/Kconfig
+@@ -1,6 +1,6 @@
+ config VIDEO_EM28XX
+ 	tristate "Empia EM2800/2820/2840 USB video capture support"
+-	depends on VIDEO_V4L1 && I2C && INPUT
++	depends on VIDEO_DEV && I2C && INPUT
+ 	select VIDEO_TUNER
+ 	select VIDEO_TVEEPROM
+ 	select VIDEO_IR
+@@ -11,3 +11,18 @@ config VIDEO_EM28XX
+ 
+ 	  To compile this driver as a module, choose M here: the
+ 	  module will be called em28xx
++
++config VIDEO_EM28XX_ALSA
++	depends on VIDEO_EM28XX
++	tristate "Empia EM28xx ALSA audio module"
++	---help---
++	  This is an ALSA driver for some Empia 28xx based TV cards.
++
++	  This is not required for em2800/em2820/em2821 boards. However,
++	  newer em28xx devices uses Vendor Class for audio, instead of
++	  implementing the USB Audio Class. For those chips, this module
++	  will enable digital audio.
++
++	  To compile this driver as a module, choose M here: the
++	  module will be called em28xx-alsa
++
+diff --git a/drivers/media/video/em28xx/Makefile b/drivers/media/video/em28xx/Makefile
+index 826d0e3..0924550 100644
+--- a/drivers/media/video/em28xx/Makefile
++++ b/drivers/media/video/em28xx/Makefile
+@@ -1,6 +1,12 @@
+ em28xx-objs     := em28xx-video.o em28xx-i2c.o em28xx-cards.o em28xx-core.o \
+ 		   em28xx-input.o
+ 
++em28xx-alsa-objs := em28xx-audio.o
++
+ obj-$(CONFIG_VIDEO_EM28XX) += em28xx.o
++obj-$(CONFIG_VIDEO_EM28XX_ALSA) += em28xx-alsa.o
+ 
+ EXTRA_CFLAGS += -Idrivers/media/video
++EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
++EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
++
+diff --git a/drivers/media/video/em28xx/em28xx-audio.c b/drivers/media/video/em28xx/em28xx-audio.c
 new file mode 100644
-index 0000000..e36e3fc
+index 0000000..941357c
 --- /dev/null
-+++ b/drivers/media/video/cx23885/cx23885-vbi.c
-@@ -0,0 +1,258 @@
++++ b/drivers/media/video/em28xx/em28xx-audio.c
+@@ -0,0 +1,489 @@
 +/*
-+ *  Driver for the Conexant CX23885 PCIe bridge
++ *  Empiatech em28x1 audio extension
 + *
-+ *  Copyright (c) 2007 Steven Toth <stoth at hauppauge.com>
++ *  Copyright (C) 2006 Markus Rechberger <mrechberger at gmail.com>
++ *
++ *  Copyright (C) 2007 Mauro Carvalho Chehab <mchehab at infradead.org>
++ *	- Port to work with the in-kernel driver
++ *	- Several cleanups
++ *
++ *  This driver is based on my previous au600 usb pstn audio driver
++ *  and inherits all the copyrights
 + *
 + *  This program is free software; you can redistribute it and/or modify
 + *  it under the terms of the GNU General Public License as published by
@@ -106267,7 +205439,6 @@
 + *  This program is distributed in the hope that it will be useful,
 + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+ *
 + *  GNU General Public License for more details.
 + *
 + *  You should have received a copy of the GNU General Public License
@@ -106276,100956 +205447,121445 @@
 + */
 +
 +#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/moduleparam.h>
++#include <linux/usb.h>
 +#include <linux/init.h>
++#include <linux/sound.h>
++#include <linux/spinlock.h>
++#include <linux/soundcard.h>
 +#include <linux/slab.h>
++#include <linux/vmalloc.h>
++#include <linux/proc_fs.h>
++#include <linux/module.h>
++#include <sound/driver.h>
++#include <sound/core.h>
++#include <sound/pcm.h>
++#include <sound/pcm_params.h>
++#include <sound/info.h>
++#include <sound/initval.h>
++#include <sound/control.h>
++#include <media/v4l2-common.h>
++#include "em28xx.h"
 +
-+#include "cx23885.h"
++static int debug;
++module_param(debug, int, 0644);
++MODULE_PARM_DESC(debug, "activates debug info");
++
++#define dprintk(fmt, arg...) do {					\
++	    if (debug)							\
++		printk(KERN_INFO "em28xx-audio %s: " fmt,		\
++				  __FUNCTION__, ##arg); 		\
++	} while (0)
++
++static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
++
++static int em28xx_isoc_audio_deinit(struct em28xx *dev)
++{
++	int i;
++
++	dprintk("Stopping isoc\n");
++	for (i = 0; i < EM28XX_AUDIO_BUFS; i++) {
++		usb_kill_urb(dev->adev->urb[i]);
++		usb_free_urb(dev->adev->urb[i]);
++		dev->adev->urb[i] = NULL;
++	}
++
++	return 0;
++}
++
++static void em28xx_audio_isocirq(struct urb *urb)
++{
++	struct em28xx            *dev = urb->context;
++	int                      i;
++	unsigned int             oldptr;
++	unsigned long            flags;
++	int                      period_elapsed = 0;
++	int                      status;
++	unsigned char            *cp;
++	unsigned int             stride;
++	struct snd_pcm_substream *substream;
++	struct snd_pcm_runtime   *runtime;
++	if (dev->adev->capture_pcm_substream) {
++		substream = dev->adev->capture_pcm_substream;
++		runtime = substream->runtime;
++		stride = runtime->frame_bits >> 3;
++
++		for (i = 0; i < urb->number_of_packets; i++) {
++			int length =
++			    urb->iso_frame_desc[i].actual_length / stride;
++			cp = (unsigned char *)urb->transfer_buffer +
++			    urb->iso_frame_desc[i].offset;
++
++			if (!length)
++				continue;
++
++			spin_lock_irqsave(&dev->adev->slock, flags);
++
++			oldptr = dev->adev->hwptr_done_capture;
++			dev->adev->hwptr_done_capture += length;
++			if (dev->adev->hwptr_done_capture >=
++			    runtime->buffer_size)
++				dev->adev->hwptr_done_capture -=
++				    runtime->buffer_size;
++
++			dev->adev->capture_transfer_done += length;
++			if (dev->adev->capture_transfer_done >=
++			    runtime->period_size) {
++				dev->adev->capture_transfer_done -=
++				    runtime->period_size;
++				period_elapsed = 1;
++			}
++
++			spin_unlock_irqrestore(&dev->adev->slock, flags);
++
++			if (oldptr + length >= runtime->buffer_size) {
++				unsigned int cnt =
++				    runtime->buffer_size - oldptr - 1;
++				memcpy(runtime->dma_area + oldptr * stride, cp,
++				       cnt * stride);
++				memcpy(runtime->dma_area, cp + cnt,
++				       length * stride - cnt * stride);
++			} else {
++				memcpy(runtime->dma_area + oldptr * stride, cp,
++				       length * stride);
++			}
++		}
++		if (period_elapsed)
++			snd_pcm_period_elapsed(substream);
++	}
++	urb->status = 0;
++
++	if (dev->adev->shutdown)
++		return;
++
++	status = usb_submit_urb(urb, GFP_ATOMIC);
++	if (status < 0) {
++		em28xx_errdev("resubmit of audio urb failed (error=%i)\n",
++			      status);
++	}
++	return;
++}
++
++static int em28xx_init_audio_isoc(struct em28xx *dev)
++{
++	int       i, errCode;
++	const int sb_size = EM28XX_NUM_AUDIO_PACKETS *
++			    EM28XX_AUDIO_MAX_PACKET_SIZE;
++
++	dprintk("Starting isoc transfers\n");
++
++	for (i = 0; i < EM28XX_AUDIO_BUFS; i++) {
++		struct urb *urb;
++		int j, k;
++
++		dev->adev->transfer_buffer[i] = kmalloc(sb_size, GFP_ATOMIC);
++		if (!dev->adev->transfer_buffer[i])
++			return -ENOMEM;
++
++		memset(dev->adev->transfer_buffer[i], 0x80, sb_size);
++		urb = usb_alloc_urb(EM28XX_NUM_AUDIO_PACKETS, GFP_ATOMIC);
++		if (!urb)
++			return -ENOMEM;
++
++		urb->dev = dev->udev;
++		urb->context = dev;
++		urb->pipe = usb_rcvisocpipe(dev->udev, 0x83);
++		urb->transfer_flags = URB_ISO_ASAP;
++		urb->transfer_buffer = dev->adev->transfer_buffer[i];
++		urb->interval = 1;
++		urb->complete = em28xx_audio_isocirq;
++		urb->number_of_packets = EM28XX_NUM_AUDIO_PACKETS;
++		urb->transfer_buffer_length = sb_size;
++
++		for (j = k = 0; j < EM28XX_NUM_AUDIO_PACKETS;
++			     j++, k += EM28XX_AUDIO_MAX_PACKET_SIZE) {
++			urb->iso_frame_desc[j].offset = k;
++			urb->iso_frame_desc[j].length =
++			    EM28XX_AUDIO_MAX_PACKET_SIZE;
++		}
++		dev->adev->urb[i] = urb;
++	}
++
++	for (i = 0; i < EM28XX_AUDIO_BUFS; i++) {
++		errCode = usb_submit_urb(dev->adev->urb[i], GFP_ATOMIC);
++		if (errCode) {
++			em28xx_isoc_audio_deinit(dev);
++
++			return errCode;
++		}
++	}
++
++	return 0;
++}
++
++static int em28xx_cmd(struct em28xx *dev, int cmd, int arg)
++{
++	dprintk("%s transfer\n", (dev->adev->capture_stream == STREAM_ON)?
++				 "stop" : "start");
++
++	switch (cmd) {
++	case EM28XX_CAPTURE_STREAM_EN:
++		if (dev->adev->capture_stream == STREAM_OFF && arg == 1) {
++			dev->adev->capture_stream = STREAM_ON;
++			em28xx_init_audio_isoc(dev);
++		} else if (dev->adev->capture_stream == STREAM_ON && arg == 0) {
++			dev->adev->capture_stream = STREAM_OFF;
++			em28xx_isoc_audio_deinit(dev);
++		} else {
++			printk(KERN_ERR "An underrun very likely occurred. "
++					"Ignoring it.\n");
++		}
++		return 0;
++	default:
++		return -EINVAL;
++	}
++}
++
++static int snd_pcm_alloc_vmalloc_buffer(struct snd_pcm_substream *subs,
++					size_t size)
++{
++	struct snd_pcm_runtime *runtime = subs->runtime;
++
++	dprintk("Alocating vbuffer\n");
++	if (runtime->dma_area) {
++		if (runtime->dma_bytes > size)
++			return 0;
++
++		vfree(runtime->dma_area);
++	}
++	runtime->dma_area = vmalloc(size);
++	if (!runtime->dma_area)
++		return -ENOMEM;
++
++	runtime->dma_bytes = size;
++
++	return 0;
++}
++
++static struct snd_pcm_hardware snd_em28xx_hw_capture = {
++	.info = SNDRV_PCM_INFO_BLOCK_TRANSFER |
++		SNDRV_PCM_INFO_MMAP           |
++		SNDRV_PCM_INFO_INTERLEAVED    |
++		SNDRV_PCM_INFO_MMAP_VALID,
++
++	.formats = SNDRV_PCM_FMTBIT_S16_LE,
++
++	.rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_KNOT,
++
++	.rate_min = 48000,
++	.rate_max = 48000,
++	.channels_min = 2,
++	.channels_max = 2,
++	.buffer_bytes_max = 62720 * 8,	/* just about the value in usbaudio.c */
++	.period_bytes_min = 64,		/* 12544/2, */
++	.period_bytes_max = 12544,
++	.periods_min = 2,
++	.periods_max = 98,		/* 12544, */
++};
 +
-+static unsigned int vbibufs = 4;
-+module_param(vbibufs, int, 0644);
-+MODULE_PARM_DESC(vbibufs, "number of vbi buffers, range 2-32");
++static int snd_em28xx_capture_open(struct snd_pcm_substream *substream)
++{
++	struct em28xx *dev = snd_pcm_substream_chip(substream);
++	struct snd_pcm_runtime *runtime = substream->runtime;
++	int ret = 0;
 +
-+static unsigned int vbi_debug;
-+module_param(vbi_debug, int, 0644);
-+MODULE_PARM_DESC(vbi_debug, "enable debug messages [vbi]");
++	dprintk("opening device and trying to acquire exclusive lock\n");
 +
-+#define dprintk(level, fmt, arg...)\
-+	do { if (vbi_debug >= level)\
-+		printk(KERN_DEBUG "%s/0: " fmt, dev->name, ## arg);\
-+	} while (0)
++	/* Sets volume, mute, etc */
++	dev->mute = 0;
++	ret = em28xx_audio_analog_set(dev);
++	if (ret < 0)
++		goto err;
 +
-+/* ------------------------------------------------------------------ */
++	runtime->hw = snd_em28xx_hw_capture;
++	if (dev->alt == 0 && dev->adev->users == 0) {
++		int errCode;
++		dev->alt = 7;
++		errCode = usb_set_interface(dev->udev, 0, 7);
++		dprintk("changing alternate number to 7\n");
++	}
 +
-+int cx23885_vbi_fmt(struct file *file, void *priv,
-+	struct v4l2_format *f)
-+{
-+	struct cx23885_fh *fh = priv;
-+	struct cx23885_dev *dev = fh->dev;
++	dev->adev->users++;
 +
-+	if (dev->tvnorm & V4L2_STD_525_60) {
-+		/* ntsc */
-+		f->fmt.vbi.sampling_rate = 28636363;
-+		f->fmt.vbi.start[0] = 10;
-+		f->fmt.vbi.start[1] = 273;
++	snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
++	dev->adev->capture_pcm_substream = substream;
++	runtime->private_data = dev;
 +
-+	} else if (dev->tvnorm & V4L2_STD_625_50) {
-+		/* pal */
-+		f->fmt.vbi.sampling_rate = 35468950;
-+		f->fmt.vbi.start[0] = 7 - 1;
-+		f->fmt.vbi.start[1] = 319 - 1;
-+	}
 +	return 0;
++err:
++	printk(KERN_ERR "Error while configuring em28xx mixer\n");
++	return ret;
 +}
 +
-+static int cx23885_start_vbi_dma(struct cx23885_dev    *dev,
-+			 struct cx23885_dmaqueue *q,
-+			 struct cx23885_buffer   *buf)
++static int snd_em28xx_pcm_close(struct snd_pcm_substream *substream)
 +{
-+	/* setup fifo + format */
-+	cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH02],
-+				buf->vb.width, buf->risc.dma);
-+
-+	/* reset counter */
-+	q->count = 1;
++	struct em28xx *dev = snd_pcm_substream_chip(substream);
++	dev->adev->users--;
 +
-+	/* enable irqs */
-+	cx_set(PCI_INT_MSK, cx_read(PCI_INT_MSK) | 0x01);
-+	cx_set(VID_A_INT_MSK, 0x000022);
++	dprintk("closing device\n");
 +
-+	/* start dma */
-+	cx_set(DEV_CNTRL2, (1<<5));
-+	cx_set(VID_A_DMA_CTL, 0x00000022);
++	dev->mute = 1;
++	em28xx_audio_analog_set(dev);
 +
++	if (dev->adev->users == 0 && dev->adev->shutdown == 1) {
++		dprintk("audio users: %d\n", dev->adev->users);
++		dprintk("disabling audio stream!\n");
++		dev->adev->shutdown = 0;
++		dprintk("released lock\n");
++		em28xx_cmd(dev, EM28XX_CAPTURE_STREAM_EN, 0);
++	}
 +	return 0;
 +}
 +
-+int cx23885_stop_vbi_dma(struct cx23885_dev *dev)
++static int snd_em28xx_hw_capture_params(struct snd_pcm_substream *substream,
++					struct snd_pcm_hw_params *hw_params)
 +{
-+	/* 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;
-+}
++	unsigned int channels, rate, format;
++	int ret;
 +
-+int cx23885_restart_vbi_queue(struct cx23885_dev    *dev,
-+			     struct cx23885_dmaqueue *q)
-+{
-+	struct cx23885_buffer *buf;
-+	struct list_head *item;
++	dprintk("Setting capture parameters\n");
 +
-+	if (list_empty(&q->active))
-+		return 0;
++	ret = snd_pcm_alloc_vmalloc_buffer(substream,
++				params_buffer_bytes(hw_params));
++	format = params_format(hw_params);
++	rate = params_rate(hw_params);
++	channels = params_channels(hw_params);
 +
-+	buf = list_entry(q->active.next, struct cx23885_buffer, vb.queue);
-+	dprintk(2, "restart_queue [%p/%d]: restart dma\n",
-+		buf, buf->vb.i);
-+	cx23885_start_vbi_dma(dev, q, buf);
-+	list_for_each(item, &q->active) {
-+		buf = list_entry(item, struct cx23885_buffer, vb.queue);
-+		buf->count = q->count++;
-+	}
-+	mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
++	/* TODO: set up em28xx audio chip to deliver the correct audio format,
++	   current default is 48000hz multiplexed => 96000hz mono
++	   which shouldn't matter since analogue TV only supports mono */
 +	return 0;
 +}
 +
-+void cx23885_vbi_timeout(unsigned long data)
++static int snd_em28xx_hw_capture_free(struct snd_pcm_substream *substream)
 +{
-+	struct cx23885_dev *dev = (struct cx23885_dev *)data;
-+	struct cx23885_dmaqueue *q = &dev->vbiq;
-+	struct cx23885_buffer *buf;
-+	unsigned long flags;
++	struct em28xx *dev = snd_pcm_substream_chip(substream);
 +
-+	cx23885_sram_channel_dump(dev, &dev->sram_channels[SRAM_CH02]);
++	dprintk("Stop capture, if needed\n");
 +
-+	cx_clear(VID_A_DMA_CTL, 0x22);
++	if (dev->adev->capture_stream == STREAM_ON)
++		em28xx_cmd(dev, EM28XX_CAPTURE_STREAM_EN, 0);
 +
-+	spin_lock_irqsave(&dev->slock, flags);
-+	while (!list_empty(&q->active)) {
-+		buf = list_entry(q->active.next, struct cx23885_buffer,
-+			vb.queue);
-+		list_del(&buf->vb.queue);
-+		buf->vb.state = VIDEOBUF_ERROR;
-+		wake_up(&buf->vb.done);
-+		printk("%s/0: [%p/%d] timeout - dma=0x%08lx\n", dev->name,
-+		       buf, buf->vb.i, (unsigned long)buf->risc.dma);
-+	}
-+	cx23885_restart_vbi_queue(dev, q);
-+	spin_unlock_irqrestore(&dev->slock, flags);
++	return 0;
 +}
 +
-+/* ------------------------------------------------------------------ */
-+#define VBI_LINE_LENGTH 2048
-+#define VBI_LINE_COUNT 17
-+
-+static int
-+vbi_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size)
++static int snd_em28xx_prepare(struct snd_pcm_substream *substream)
 +{
-+	*size = VBI_LINE_COUNT * VBI_LINE_LENGTH * 2;
-+	if (0 == *count)
-+		*count = vbibufs;
-+	if (*count < 2)
-+		*count = 2;
-+	if (*count > 32)
-+		*count = 32;
 +	return 0;
 +}
 +
-+static int
-+vbi_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
-+	    enum v4l2_field field)
++static int snd_em28xx_capture_trigger(struct snd_pcm_substream *substream,
++				      int cmd)
 +{
-+	struct cx23885_fh *fh  = q->priv_data;
-+	struct cx23885_dev *dev = fh->dev;
-+	struct cx23885_buffer *buf = container_of(vb,
-+		struct cx23885_buffer, vb);
-+	struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb);
-+	unsigned int size;
-+	int rc;
++	struct em28xx *dev = snd_pcm_substream_chip(substream);
 +
-+	size = VBI_LINE_COUNT * VBI_LINE_LENGTH * 2;
-+	if (0 != buf->vb.baddr  &&  buf->vb.bsize < size)
++	dprintk("Should %s capture\n", (cmd == SNDRV_PCM_TRIGGER_START)?
++				       "start": "stop");
++	switch (cmd) {
++	case SNDRV_PCM_TRIGGER_START:
++		em28xx_cmd(dev, EM28XX_CAPTURE_STREAM_EN, 1);
++		return 0;
++	case SNDRV_PCM_TRIGGER_STOP:
++		dev->adev->shutdown = 1;
++		return 0;
++	default:
 +		return -EINVAL;
-+
-+	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
-+		buf->vb.width  = VBI_LINE_LENGTH;
-+		buf->vb.height = VBI_LINE_COUNT;
-+		buf->vb.size   = size;
-+		buf->vb.field  = V4L2_FIELD_SEQ_TB;
-+
-+		rc = videobuf_iolock(q, &buf->vb, NULL);
-+		if (0 != rc)
-+			goto fail;
-+		cx23885_risc_buffer(dev->pci, &buf->risc,
-+				 dma->sglist,
-+				 0, buf->vb.width * buf->vb.height,
-+				 buf->vb.width, 0,
-+				 buf->vb.height);
 +	}
-+	buf->vb.state = VIDEOBUF_PREPARED;
-+	return 0;
-+
-+ fail:
-+	cx23885_free_buffer(q, buf);
-+	return rc;
 +}
 +
-+static void
-+vbi_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
++static snd_pcm_uframes_t snd_em28xx_capture_pointer(struct snd_pcm_substream
++						    *substream)
 +{
-+	struct cx23885_buffer   *buf =
-+		container_of(vb, struct cx23885_buffer, vb);
-+	struct cx23885_buffer   *prev;
-+	struct cx23885_fh       *fh   = vq->priv_data;
-+	struct cx23885_dev      *dev  = fh->dev;
-+	struct cx23885_dmaqueue *q    = &dev->vbiq;
-+
-+	/* add jump to stopper */
-+	buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
-+	buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma);
-+	buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */
++	struct em28xx *dev;
 +
-+	if (list_empty(&q->active)) {
-+		list_add_tail(&buf->vb.queue, &q->active);
-+		cx23885_start_vbi_dma(dev, q, buf);
-+		buf->vb.state = VIDEOBUF_ACTIVE;
-+		buf->count    = q->count++;
-+		mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
-+		dprintk(2, "[%p/%d] vbi_queue - first active\n",
-+			buf, buf->vb.i);
++	snd_pcm_uframes_t hwptr_done;
++	dev = snd_pcm_substream_chip(substream);
++	hwptr_done = dev->adev->hwptr_done_capture;
 +
-+	} else {
-+		prev = list_entry(q->active.prev, struct cx23885_buffer,
-+			vb.queue);
-+		list_add_tail(&buf->vb.queue, &q->active);
-+		buf->vb.state = VIDEOBUF_ACTIVE;
-+		buf->count    = q->count++;
-+		prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
-+		prev->risc.jmp[2] = cpu_to_le32(0); /* Bits 63-32 */
-+		dprintk(2, "[%p/%d] buffer_queue - append to active\n",
-+			buf, buf->vb.i);
-+	}
++	return hwptr_done;
 +}
 +
-+static void vbi_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
++static struct page *snd_pcm_get_vmalloc_page(struct snd_pcm_substream *subs,
++					     unsigned long offset)
 +{
-+	struct cx23885_buffer *buf =
-+		container_of(vb, struct cx23885_buffer, vb);
++	void *pageptr = subs->runtime->dma_area + offset;
 +
-+	cx23885_free_buffer(q, buf);
++	return vmalloc_to_page(pageptr);
 +}
 +
-+struct videobuf_queue_ops cx23885_vbi_qops = {
-+	.buf_setup    = vbi_setup,
-+	.buf_prepare  = vbi_prepare,
-+	.buf_queue    = vbi_queue,
-+	.buf_release  = vbi_release,
++static struct snd_pcm_ops snd_em28xx_pcm_capture = {
++	.open      = snd_em28xx_capture_open,
++	.close     = snd_em28xx_pcm_close,
++	.ioctl     = snd_pcm_lib_ioctl,
++	.hw_params = snd_em28xx_hw_capture_params,
++	.hw_free   = snd_em28xx_hw_capture_free,
++	.prepare   = snd_em28xx_prepare,
++	.trigger   = snd_em28xx_capture_trigger,
++	.pointer   = snd_em28xx_capture_pointer,
++	.page      = snd_pcm_get_vmalloc_page,
 +};
 +
-+/* ------------------------------------------------------------------ */
-+/*
-+ * Local variables:
-+ * c-basic-offset: 8
-+ * End:
-+ */
-diff --git a/drivers/media/video/cx23885/cx23885-video.c b/drivers/media/video/cx23885/cx23885-video.c
-new file mode 100644
-index 0000000..d3c4d2c
---- /dev/null
-+++ b/drivers/media/video/cx23885/cx23885-video.c
-@@ -0,0 +1,1557 @@
-+/*
-+ *  Driver for the Conexant CX23885 PCIe bridge
-+ *
-+ *  Copyright (c) 2007 Steven Toth <stoth at hauppauge.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.
-+ */
++static int em28xx_audio_init(struct em28xx *dev)
++{
++	struct em28xx_audio *adev;
++	struct snd_pcm      *pcm;
++	struct snd_card     *card;
++	static int          devnr;
++	int                 ret, err;
 +
-+#include <linux/init.h>
-+#include <linux/list.h>
-+#include <linux/module.h>
-+#include <linux/moduleparam.h>
-+#include <linux/kmod.h>
-+#include <linux/kernel.h>
-+#include <linux/slab.h>
-+#include <linux/interrupt.h>
-+#include <linux/delay.h>
-+#include <linux/kthread.h>
-+#include <asm/div64.h>
++	printk(KERN_INFO "em28xx-audio.c: probing for em28x1 "
++			 "non standard usbaudio\n");
++	printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2006 Markus "
++			 "Rechberger\n");
 +
-+#include "cx23885.h"
-+#include <media/v4l2-common.h>
++	adev = kzalloc(sizeof(*adev), GFP_KERNEL);
++	if (!adev) {
++		printk(KERN_ERR "em28xx-audio.c: out of memory\n");
++		return -1;
++	}
++	card = snd_card_new(index[devnr], "Em28xx Audio", THIS_MODULE, 0);
++	if (card == NULL) {
++		kfree(adev);
++		return -ENOMEM;
++	}
 +
-+#ifdef CONFIG_VIDEO_V4L1_COMPAT
-+/* Include V4L1 specific functions. Should be removed soon */
-+#include <linux/videodev.h>
-+#endif
++	spin_lock_init(&adev->slock);
++	ret = snd_pcm_new(card, "Em28xx Audio", 0, 0, 1, &pcm);
++	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_em28xx_pcm_capture);
++	pcm->info_flags = 0;
++	pcm->private_data = dev;
++	strcpy(pcm->name, "Empia 28xx Capture");
++	strcpy(card->driver, "Empia Em28xx Audio");
++	strcpy(card->shortname, "Em28xx Audio");
++	strcpy(card->longname, "Empia Em28xx Audio");
 +
-+MODULE_DESCRIPTION("v4l2 driver module for cx23885 based TV cards");
-+MODULE_AUTHOR("Steven Toth <stoth at hauppauge.com>");
-+MODULE_LICENSE("GPL");
++	err = snd_card_register(card);
++	if (err < 0) {
++		snd_card_free(card);
++		return -ENOMEM;
++	}
++	adev->sndcard = card;
++	adev->udev = dev->udev;
++	dev->adev = adev;
 +
-+/* ------------------------------------------------------------------ */
++	return 0;
++}
 +
-+static unsigned int video_nr[] = {[0 ... (CX23885_MAXBOARDS - 1)] = UNSET };
-+static unsigned int vbi_nr[]   = {[0 ... (CX23885_MAXBOARDS - 1)] = UNSET };
-+static unsigned int radio_nr[] = {[0 ... (CX23885_MAXBOARDS - 1)] = UNSET };
++static int em28xx_audio_fini(struct em28xx *dev)
++{
++	if (dev == NULL)
++		return 0;
 +
-+module_param_array(video_nr, int, NULL, 0444);
-+module_param_array(vbi_nr,   int, NULL, 0444);
-+module_param_array(radio_nr, int, NULL, 0444);
++	if (dev->adev) {
++		snd_card_free(dev->adev->sndcard);
++		kfree(dev->adev);
++		dev->adev = NULL;
++	}
 +
-+MODULE_PARM_DESC(video_nr, "video device numbers");
-+MODULE_PARM_DESC(vbi_nr, "vbi device numbers");
-+MODULE_PARM_DESC(radio_nr, "radio device numbers");
++	return 0;
++}
 +
-+static unsigned int video_debug;
-+module_param(video_debug, int, 0644);
-+MODULE_PARM_DESC(video_debug, "enable debug messages [video]");
++static struct em28xx_ops audio_ops = {
++	.id   = EM28XX_AUDIO,
++	.name = "Em28xx Audio Extension",
++	.init = em28xx_audio_init,
++	.fini = em28xx_audio_fini,
++};
 +
-+static unsigned int irq_debug;
-+module_param(irq_debug, int, 0644);
-+MODULE_PARM_DESC(irq_debug, "enable debug messages [IRQ handler]");
++static int __init em28xx_alsa_register(void)
++{
++	return em28xx_register_extension(&audio_ops);
++}
 +
-+static unsigned int vid_limit = 16;
-+module_param(vid_limit, int, 0644);
-+MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes");
++static void __exit em28xx_alsa_unregister(void)
++{
++	em28xx_unregister_extension(&audio_ops);
++}
 +
-+#define dprintk(level, fmt, arg...)\
-+	do { if (video_debug >= level)\
-+		printk(KERN_DEBUG "%s/0: " fmt, dev->name, ## arg);\
-+	} while (0)
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Markus Rechberger <mrechberger at gmail.com>");
++MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab at infradead.org>");
++MODULE_DESCRIPTION("Em28xx Audio driver");
 +
-+/* ------------------------------------------------------------------- */
-+/* static data                                                         */
++module_init(em28xx_alsa_register);
++module_exit(em28xx_alsa_unregister);
+diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c
+index 418ea8b..2159d01 100644
+--- a/drivers/media/video/em28xx/em28xx-cards.c
++++ b/drivers/media/video/em28xx/em28xx-cards.c
+@@ -1,5 +1,6 @@
+ /*
+-   em28xx-cards.c - driver for Empia EM2800/EM2820/2840 USB video capture devices
++   em28xx-cards.c - driver for Empia EM2800/EM2820/2840 USB
++		    video capture devices
+ 
+    Copyright (C) 2005 Ludovico Cavedon <cavedon at sssup.it>
+ 		      Markus Rechberger <mrechberger at gmail.com>
+@@ -35,294 +36,735 @@
+ #include <media/v4l2-common.h>
+ 
+ #include "em28xx.h"
++#include "tuner-xc2028.h"
 +
-+#define FORMAT_FLAGS_PACKED       0x01
++static int tuner = -1;
++module_param(tuner, int, 0444);
++MODULE_PARM_DESC(tuner, "tuner type");
 +
-+static struct cx23885_fmt formats[] = {
-+	{
-+		.name     = "8 bpp, gray",
-+		.fourcc   = V4L2_PIX_FMT_GREY,
-+		.depth    = 8,
-+		.flags    = FORMAT_FLAGS_PACKED,
-+	}, {
-+		.name     = "15 bpp RGB, le",
-+		.fourcc   = V4L2_PIX_FMT_RGB555,
-+		.depth    = 16,
-+		.flags    = FORMAT_FLAGS_PACKED,
-+	}, {
-+		.name     = "15 bpp RGB, be",
-+		.fourcc   = V4L2_PIX_FMT_RGB555X,
-+		.depth    = 16,
-+		.flags    = FORMAT_FLAGS_PACKED,
-+	}, {
-+		.name     = "16 bpp RGB, le",
-+		.fourcc   = V4L2_PIX_FMT_RGB565,
-+		.depth    = 16,
-+		.flags    = FORMAT_FLAGS_PACKED,
-+	}, {
-+		.name     = "16 bpp RGB, be",
-+		.fourcc   = V4L2_PIX_FMT_RGB565X,
-+		.depth    = 16,
-+		.flags    = FORMAT_FLAGS_PACKED,
-+	}, {
-+		.name     = "24 bpp RGB, le",
-+		.fourcc   = V4L2_PIX_FMT_BGR24,
-+		.depth    = 24,
-+		.flags    = FORMAT_FLAGS_PACKED,
-+	}, {
-+		.name     = "32 bpp RGB, le",
-+		.fourcc   = V4L2_PIX_FMT_BGR32,
-+		.depth    = 32,
-+		.flags    = FORMAT_FLAGS_PACKED,
-+	}, {
-+		.name     = "32 bpp RGB, be",
-+		.fourcc   = V4L2_PIX_FMT_RGB32,
-+		.depth    = 32,
-+		.flags    = FORMAT_FLAGS_PACKED,
-+	}, {
-+		.name     = "4:2:2, packed, YUYV",
-+		.fourcc   = V4L2_PIX_FMT_YUYV,
-+		.depth    = 16,
-+		.flags    = FORMAT_FLAGS_PACKED,
-+	}, {
-+		.name     = "4:2:2, packed, UYVY",
-+		.fourcc   = V4L2_PIX_FMT_UYVY,
-+		.depth    = 16,
-+		.flags    = FORMAT_FLAGS_PACKED,
-+	},
++static unsigned int disable_ir;
++module_param(disable_ir, int, 0444);
++MODULE_PARM_DESC(disable_ir, "disable infrared remote support");
++
++struct em28xx_hash_table {
++	unsigned long hash;
++	unsigned int  model;
++	unsigned int  tuner;
 +};
 +
-+static struct cx23885_fmt *format_by_fourcc(unsigned int fourcc)
-+{
-+	unsigned int i;
++/* Boards supported by driver */
 +
-+	for (i = 0; i < ARRAY_SIZE(formats); i++)
-+		if (formats[i].fourcc == fourcc)
-+			return formats+i;
++#define EM2800_BOARD_UNKNOWN			0
++#define EM2820_BOARD_UNKNOWN			1
++#define EM2820_BOARD_TERRATEC_CINERGY_250	2
++#define EM2820_BOARD_PINNACLE_USB_2		3
++#define EM2820_BOARD_HAUPPAUGE_WINTV_USB_2      4
++#define EM2820_BOARD_MSI_VOX_USB_2              5
++#define EM2800_BOARD_TERRATEC_CINERGY_200       6
++#define EM2800_BOARD_LEADTEK_WINFAST_USBII      7
++#define EM2800_BOARD_KWORLD_USB2800             8
++#define EM2820_BOARD_PINNACLE_DVC_90		9
++#define EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900	10
++#define EM2880_BOARD_TERRATEC_HYBRID_XS		11
++#define EM2820_BOARD_KWORLD_PVRTV2800RF		12
++#define EM2880_BOARD_TERRATEC_PRODIGY_XS	13
++#define EM2820_BOARD_PROLINK_PLAYTV_USB2	14
++#define EM2800_BOARD_VGEAR_POCKETTV             15
++#define EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950	16
+ 
+ struct em28xx_board em28xx_boards[] = {
+ 	[EM2800_BOARD_UNKNOWN] = {
+ 		.name         = "Unknown EM2800 video grabber",
+ 		.is_em2800    = 1,
+ 		.vchannels    = 2,
+-		.norm         = VIDEO_MODE_PAL,
+ 		.tda9887_conf = TDA9887_PRESENT,
+-		.has_tuner    = 1,
+ 		.decoder      = EM28XX_SAA7113,
+-		.input           = {{
++		.input           = { {
+ 			.type     = EM28XX_VMUX_COMPOSITE1,
+ 			.vmux     = SAA7115_COMPOSITE0,
+ 			.amux     = 1,
+-		},{
++		}, {
+ 			.type     = EM28XX_VMUX_SVIDEO,
+ 			.vmux     = SAA7115_SVIDEO3,
+ 			.amux     = 1,
+-		}},
++		} },
+ 	},
+ 	[EM2820_BOARD_UNKNOWN] = {
+-		.name         = "Unknown EM2820/2840 video grabber",
++		.name         = "Unknown EM2750/28xx video grabber",
+ 		.is_em2800    = 0,
+-		.vchannels    = 2,
+-		.norm         = VIDEO_MODE_PAL,
+-		.tda9887_conf = TDA9887_PRESENT,
+-		.has_tuner    = 1,
+-		.decoder      = EM28XX_SAA7113,
+-		.input           = {{
+-			.type     = EM28XX_VMUX_COMPOSITE1,
+-			.vmux     = SAA7115_COMPOSITE0,
+-			.amux     = 1,
+-		},{
+-			.type     = EM28XX_VMUX_SVIDEO,
+-			.vmux     = SAA7115_SVIDEO3,
+-			.amux     = 1,
+-		}},
++		.tuner_type   = TUNER_ABSENT,
+ 	},
+ 	[EM2820_BOARD_KWORLD_PVRTV2800RF] = {
+ 		.name         = "Kworld PVR TV 2800 RF",
+ 		.is_em2800    = 0,
+ 		.vchannels    = 2,
+-		.norm         = VIDEO_MODE_PAL,
++		.tuner_type   = TUNER_TEMIC_PAL,
+ 		.tda9887_conf = TDA9887_PRESENT,
+-		.has_tuner    = 1,
+ 		.decoder      = EM28XX_SAA7113,
+-		.input           = {{
++		.input           = { {
+ 			.type     = EM28XX_VMUX_COMPOSITE1,
+ 			.vmux     = SAA7115_COMPOSITE0,
+ 			.amux     = 1,
+-		},{
++		}, {
+ 			.type     = EM28XX_VMUX_SVIDEO,
+ 			.vmux     = SAA7115_SVIDEO3,
+ 			.amux     = 1,
+-		}},
++		} },
+ 	},
+ 	[EM2820_BOARD_TERRATEC_CINERGY_250] = {
+ 		.name         = "Terratec Cinergy 250 USB",
+ 		.vchannels    = 3,
+-		.norm         = VIDEO_MODE_PAL,
+ 		.tuner_type   = TUNER_LG_PAL_NEW_TAPC,
+ 		.tda9887_conf = TDA9887_PRESENT,
+-		.has_tuner    = 1,
+ 		.decoder      = EM28XX_SAA7113,
+-		.input          = {{
++		.input          = { {
+ 			.type     = EM28XX_VMUX_TELEVISION,
+ 			.vmux     = SAA7115_COMPOSITE2,
+ 			.amux     = 1,
+-		},{
++		}, {
+ 			.type     = EM28XX_VMUX_COMPOSITE1,
+ 			.vmux     = SAA7115_COMPOSITE0,
+ 			.amux     = 1,
+-		},{
++		}, {
+ 			.type     = EM28XX_VMUX_SVIDEO,
+ 			.vmux     = SAA7115_SVIDEO3,
+ 			.amux     = 1,
+-		}},
++		} },
+ 	},
+ 	[EM2820_BOARD_PINNACLE_USB_2] = {
+ 		.name         = "Pinnacle PCTV USB 2",
+ 		.vchannels    = 3,
+-		.norm         = VIDEO_MODE_PAL,
+ 		.tuner_type   = TUNER_LG_PAL_NEW_TAPC,
+ 		.tda9887_conf = TDA9887_PRESENT,
+-		.has_tuner    = 1,
+ 		.decoder      = EM28XX_SAA7113,
+-		.input          = {{
++		.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_HAUPPAUGE_WINTV_USB_2] = {
+ 		.name         = "Hauppauge WinTV USB 2",
+ 		.vchannels    = 3,
+-		.norm         = VIDEO_MODE_NTSC,
+ 		.tuner_type   = TUNER_PHILIPS_FM1236_MK3,
+-		.tda9887_conf = TDA9887_PRESENT|TDA9887_PORT1_ACTIVE|TDA9887_PORT2_ACTIVE,
+-		.has_tuner    = 1,
++		.tda9887_conf = TDA9887_PRESENT |
++				TDA9887_PORT1_ACTIVE|
++				TDA9887_PORT2_ACTIVE,
+ 		.decoder      = EM28XX_TVP5150,
+ 		.has_msp34xx  = 1,
+ 		/*FIXME: S-Video not tested */
+-		.input          = {{
++		.input          = { {
+ 			.type     = EM28XX_VMUX_TELEVISION,
+ 			.vmux     = TVP5150_COMPOSITE0,
+ 			.amux     = MSP_INPUT_DEFAULT,
+-		},{
++		}, {
+ 			.type     = EM28XX_VMUX_SVIDEO,
+ 			.vmux     = TVP5150_SVIDEO,
+ 			.amux     = MSP_INPUT(MSP_IN_SCART1, MSP_IN_TUNER1,
+ 					MSP_DSP_IN_SCART, MSP_DSP_IN_SCART),
+-		}},
++		} },
+ 	},
+-	[EM2820_BOARD_MSI_VOX_USB_2] = {
+-		.name		= "MSI VOX USB 2.0",
+-		.vchannels	= 3,
+-		.norm		= VIDEO_MODE_PAL,
+-		.tuner_type	= TUNER_LG_PAL_NEW_TAPC,
+-		.tda9887_conf	= TDA9887_PRESENT|TDA9887_PORT1_ACTIVE|TDA9887_PORT2_ACTIVE,
+-		.has_tuner	= 1,
+-		.decoder        = EM28XX_SAA7114,
+-		.input          = {{
++	[EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900] = {
++		.name         = "Hauppauge WinTV HVR 900",
++		.vchannels    = 3,
++		.tda9887_conf = TDA9887_PRESENT,
++		.tuner_type   = TUNER_XC2028,
++		.mts_firmware = 1,
++		.decoder      = EM28XX_TVP5150,
++		.input          = { {
++			.type     = EM28XX_VMUX_TELEVISION,
++			.vmux     = TVP5150_COMPOSITE0,
++			.amux     = 0,
++		}, {
++			.type     = EM28XX_VMUX_COMPOSITE1,
++			.vmux     = TVP5150_COMPOSITE1,
++			.amux     = 1,
++		}, {
++			.type     = EM28XX_VMUX_SVIDEO,
++			.vmux     = TVP5150_SVIDEO,
++			.amux     = 1,
++		} },
++	},
++	[EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950] = {
++		.name           = "Hauppauge WinTV HVR 950",
++		.vchannels      = 3,
++		.tda9887_conf   = TDA9887_PRESENT,
++		.tuner_type     = TUNER_XC2028,
++		.mts_firmware   = 1,
++		.has_12mhz_i2s  = 1,
++		.decoder        = EM28XX_TVP5150,
++		.input          = { {
+ 			.type     = EM28XX_VMUX_TELEVISION,
+-			.vmux     = SAA7115_COMPOSITE4,
++			.vmux     = TVP5150_COMPOSITE0,
+ 			.amux     = 0,
+-		},{
++		}, {
+ 			.type     = EM28XX_VMUX_COMPOSITE1,
+-			.vmux     = SAA7115_COMPOSITE0,
++			.vmux     = TVP5150_COMPOSITE1,
+ 			.amux     = 1,
+-		},{
++		}, {
+ 			.type     = EM28XX_VMUX_SVIDEO,
+-			.vmux     = SAA7115_SVIDEO3,
++			.vmux     = TVP5150_SVIDEO,
+ 			.amux     = 1,
+-		}},
++		} },
 +
-+	printk(KERN_ERR "%s(0x%08x) NOT FOUND\n", __FUNCTION__, fourcc);
-+	return NULL;
++		/* gpio's 4, 1, 0 */
++		.analog_gpio = 0x003d2d,
++	},
++	[EM2880_BOARD_TERRATEC_HYBRID_XS] = {
++		.name         = "Terratec Hybrid XS",
++		.vchannels    = 3,
++		.tda9887_conf = TDA9887_PRESENT,
++		.tuner_type   = TUNER_XC2028,
++		.decoder      = EM28XX_TVP5150,
++		.input          = { {
++			.type     = EM28XX_VMUX_TELEVISION,
++			.vmux     = TVP5150_COMPOSITE0,
++			.amux     = 0,
++		}, {
++			.type     = EM28XX_VMUX_COMPOSITE1,
++			.vmux     = TVP5150_COMPOSITE1,
++			.amux     = 1,
++		}, {
++			.type     = EM28XX_VMUX_SVIDEO,
++			.vmux     = TVP5150_SVIDEO,
++			.amux     = 1,
++		} },
++	},
++	/* maybe there's a reason behind it why Terratec sells the Hybrid XS
++	   as Prodigy XS with a different PID, let's keep it separated for now
++	   maybe we'll need it lateron */
++	[EM2880_BOARD_TERRATEC_PRODIGY_XS] = {
++		.name         = "Terratec Prodigy XS",
++		.vchannels    = 3,
++		.tda9887_conf = TDA9887_PRESENT,
++		.tuner_type   = TUNER_XC2028,
++		.decoder      = EM28XX_TVP5150,
++		.input          = { {
++			.type     = EM28XX_VMUX_TELEVISION,
++			.vmux     = TVP5150_COMPOSITE0,
++			.amux     = 0,
++		}, {
++			.type     = EM28XX_VMUX_COMPOSITE1,
++			.vmux     = TVP5150_COMPOSITE1,
++			.amux     = 1,
++		}, {
++			.type     = EM28XX_VMUX_SVIDEO,
++			.vmux     = TVP5150_SVIDEO,
++			.amux     = 1,
++		} },
++	},
++	[EM2820_BOARD_MSI_VOX_USB_2] = {
++		.name		   = "MSI VOX USB 2.0",
++		.vchannels	   = 3,
++		.tuner_type	   = TUNER_LG_PAL_NEW_TAPC,
++		.tda9887_conf	   = TDA9887_PRESENT      |
++				     TDA9887_PORT1_ACTIVE |
++				     TDA9887_PORT2_ACTIVE,
++		.max_range_640_480 = 1,
++
++		.decoder           = EM28XX_SAA7114,
++		.input             = { {
++			.type      = EM28XX_VMUX_TELEVISION,
++			.vmux      = SAA7115_COMPOSITE4,
++			.amux      = 0,
++		}, {
++			.type      = EM28XX_VMUX_COMPOSITE1,
++			.vmux      = SAA7115_COMPOSITE0,
++			.amux      = 1,
++		}, {
++			.type      = EM28XX_VMUX_SVIDEO,
++			.vmux      = SAA7115_SVIDEO3,
++			.amux      = 1,
++		} },
+ 	},
+ 	[EM2800_BOARD_TERRATEC_CINERGY_200] = {
+ 		.name         = "Terratec Cinergy 200 USB",
+ 		.is_em2800    = 1,
+ 		.vchannels    = 3,
+-		.norm         = VIDEO_MODE_PAL,
+ 		.tuner_type   = TUNER_LG_PAL_NEW_TAPC,
+ 		.tda9887_conf = TDA9887_PRESENT,
+-		.has_tuner    = 1,
+ 		.decoder      = EM28XX_SAA7113,
+-		.input          = {{
++		.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,
+-		}},
++		} },
+ 	},
+ 	[EM2800_BOARD_LEADTEK_WINFAST_USBII] = {
+ 		.name         = "Leadtek Winfast USB II",
+ 		.is_em2800    = 1,
+ 		.vchannels    = 3,
+-		.norm         = VIDEO_MODE_PAL,
+ 		.tuner_type   = TUNER_LG_PAL_NEW_TAPC,
+ 		.tda9887_conf = TDA9887_PRESENT,
+-		.has_tuner    = 1,
+ 		.decoder      = EM28XX_SAA7113,
+-		.input          = {{
++		.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,
+-		}},
++		} },
+ 	},
+ 	[EM2800_BOARD_KWORLD_USB2800] = {
+ 		.name         = "Kworld USB2800",
+ 		.is_em2800    = 1,
+ 		.vchannels    = 3,
+-		.norm         = VIDEO_MODE_PAL,
+ 		.tuner_type   = TUNER_PHILIPS_ATSC,
+ 		.tda9887_conf = TDA9887_PRESENT,
+-		.has_tuner    = 1,
+ 		.decoder      = EM28XX_SAA7113,
+-		.input          = {{
++		.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_PINNACLE_DVC_90] = {
+-		.name         = "Pinnacle Dazzle DVC 90",
++		.name         = "Pinnacle Dazzle DVC 90/DVC 100",
++		.vchannels    = 3,
++		.tuner_type   = TUNER_ABSENT,
++		.decoder      = EM28XX_SAA7113,
++		.input          = { {
++			.type     = EM28XX_VMUX_COMPOSITE1,
++			.vmux     = SAA7115_COMPOSITE0,
++			.amux     = 1,
++		}, {
++			.type     = EM28XX_VMUX_SVIDEO,
++			.vmux     = SAA7115_SVIDEO3,
++			.amux     = 1,
++		} },
++	},
++	[EM2800_BOARD_VGEAR_POCKETTV] = {
++		.name         = "V-Gear PocketTV",
++		.is_em2800    = 1,
++		.vchannels    = 3,
++		.tuner_type   = TUNER_LG_PAL_NEW_TAPC,
++		.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_PROLINK_PLAYTV_USB2] = {
++		.name         = "Pixelview Prolink PlayTV USB 2.0",
+ 		.vchannels    = 3,
+-		.norm         = VIDEO_MODE_PAL,
+-		.has_tuner    = 0,
++		.tda9887_conf = TDA9887_PRESENT,
++		.tuner_type   = TUNER_YMEC_TVF_5533MF,
+ 		.decoder      = EM28XX_SAA7113,
+-		.input          = {{
++		.input          = { {
++			.type     = EM28XX_VMUX_TELEVISION,
++			.vmux     = SAA7115_COMPOSITE2,
++			.amux     = 1,
++		}, {
+ 			.type     = EM28XX_VMUX_COMPOSITE1,
+ 			.vmux     = SAA7115_COMPOSITE0,
+ 			.amux     = 1,
+-		},{
++		}, {
+ 			.type     = EM28XX_VMUX_SVIDEO,
+ 			.vmux     = SAA7115_SVIDEO3,
+ 			.amux     = 1,
+-		}},
++		} },
+ 	},
+ };
+ const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards);
+ 
+ /* table of devices that work with this driver */
+ struct usb_device_id em28xx_id_table [] = {
+-	{ USB_DEVICE(0xeb1a, 0x2800), .driver_info = EM2800_BOARD_UNKNOWN },
+-	{ USB_DEVICE(0xeb1a, 0x2820), .driver_info = EM2820_BOARD_MSI_VOX_USB_2 },
+-	{ USB_DEVICE(0x0ccd, 0x0036), .driver_info = EM2820_BOARD_TERRATEC_CINERGY_250 },
+-	{ USB_DEVICE(0x2304, 0x0208), .driver_info = EM2820_BOARD_PINNACLE_USB_2 },
+-	{ USB_DEVICE(0x2040, 0x4200), .driver_info = EM2820_BOARD_HAUPPAUGE_WINTV_USB_2 },
+-	{ USB_DEVICE(0x2304, 0x0207), .driver_info = EM2820_BOARD_PINNACLE_DVC_90 },
++	{ USB_DEVICE(0xeb1a, 0x2750),
++			.driver_info = EM2820_BOARD_UNKNOWN },
++	{ USB_DEVICE(0xeb1a, 0x2800),
++			.driver_info = EM2800_BOARD_UNKNOWN },
++	{ USB_DEVICE(0xeb1a, 0x2820),
++			.driver_info = EM2820_BOARD_UNKNOWN },
++	{ USB_DEVICE(0xeb1a, 0x2821),
++			.driver_info = EM2820_BOARD_UNKNOWN },
++	{ USB_DEVICE(0xeb1a, 0x2860),
++			.driver_info = EM2820_BOARD_UNKNOWN },
++	{ USB_DEVICE(0xeb1a, 0x2861),
++			.driver_info = EM2820_BOARD_UNKNOWN },
++	{ USB_DEVICE(0xeb1a, 0x2870),
++			.driver_info = EM2820_BOARD_UNKNOWN },
++	{ USB_DEVICE(0xeb1a, 0x2881),
++			.driver_info = EM2820_BOARD_UNKNOWN },
++	{ USB_DEVICE(0xeb1a, 0x2883),
++			.driver_info = EM2820_BOARD_UNKNOWN },
++	{ USB_DEVICE(0x0ccd, 0x0036),
++			.driver_info = EM2820_BOARD_TERRATEC_CINERGY_250 },
++	{ USB_DEVICE(0x2304, 0x0208),
++			.driver_info = EM2820_BOARD_PINNACLE_USB_2 },
++	{ USB_DEVICE(0x2040, 0x4200),
++			.driver_info = EM2820_BOARD_HAUPPAUGE_WINTV_USB_2 },
++	{ USB_DEVICE(0x2040, 0x4201),
++			.driver_info = EM2820_BOARD_HAUPPAUGE_WINTV_USB_2 },
++	{ USB_DEVICE(0x2304, 0x0207),
++			.driver_info = EM2820_BOARD_PINNACLE_DVC_90 },
++	{ USB_DEVICE(0x2304, 0x021a),
++			.driver_info = EM2820_BOARD_PINNACLE_DVC_90 },
++	{ USB_DEVICE(0x2040, 0x6500),
++			.driver_info = EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900 },
++	{ USB_DEVICE(0x2040, 0x6513),
++			.driver_info = EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950 },
++	{ USB_DEVICE(0x0ccd, 0x0042),
++			.driver_info = EM2880_BOARD_TERRATEC_HYBRID_XS },
++	{ USB_DEVICE(0x0ccd, 0x0047),
++			.driver_info = EM2880_BOARD_TERRATEC_PRODIGY_XS },
+ 	{ },
+ };
++MODULE_DEVICE_TABLE(usb, em28xx_id_table);
++
++/* EEPROM hash table for devices with generic USB IDs */
++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},
++};
++
++/* I2C devicelist hash table for devices with generic USB IDs */
++static struct em28xx_hash_table em28xx_i2c_hash[] = {
++	{0xb06a32c3, EM2800_BOARD_TERRATEC_CINERGY_200, TUNER_LG_PAL_NEW_TAPC},
++	{0xf51200e3, EM2800_BOARD_VGEAR_POCKETTV, TUNER_LG_PAL_NEW_TAPC},
++};
+ 
++/* Since em28xx_pre_card_setup() requires a proper dev->model,
++ * this won't work for boards with generic PCI IDs
++ */
+ void em28xx_pre_card_setup(struct em28xx *dev)
+ {
+ 	/* request some modules */
+-	switch(dev->model){
+-		case EM2880_BOARD_TERRATEC_PRODIGY_XS:
+-		case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900:
+-		case EM2880_BOARD_TERRATEC_HYBRID_XS:
+-			{
+-				em28xx_write_regs_req(dev, 0x00, 0x08, "\x7d", 1); // reset through GPIO?
+-				break;
++	switch (dev->model) {
++	case EM2880_BOARD_TERRATEC_PRODIGY_XS:
++	case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900:
++	case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950:
++	case EM2880_BOARD_TERRATEC_HYBRID_XS:
++		em28xx_write_regs(dev, XCLK_REG, "\x27", 1);
++		em28xx_write_regs(dev, I2C_CLK_REG, "\x40", 1);
++		em28xx_write_regs(dev, 0x08, "\xff", 1);
++		em28xx_write_regs(dev, 0x04, "\x00", 1);
++		msleep(100);
++		em28xx_write_regs(dev, 0x04, "\x08", 1);
++		msleep(100);
++		em28xx_write_regs(dev, 0x08, "\xff", 1);
++		msleep(50);
++		em28xx_write_regs(dev, 0x08, "\x2d", 1);
++		msleep(50);
++		em28xx_write_regs(dev, 0x08, "\x3d", 1);
++		break;
++	}
 +}
 +
-+/* ------------------------------------------------------------------- */
++static int em28xx_tuner_callback(void *ptr, int command, int arg)
++{
++	int rc = 0;
++	struct em28xx *dev = ptr;
 +
-+static const struct v4l2_queryctrl no_ctl = {
-+	.name  = "42",
-+	.flags = V4L2_CTRL_FLAG_DISABLED,
-+};
++	if (dev->tuner_type != TUNER_XC2028)
++		return 0;
 +
-+static struct cx23885_ctrl cx23885_ctls[] = {
-+	/* --- video --- */
++	switch (command) {
++	case XC2028_TUNER_RESET:
 +	{
-+		.v = {
-+			.id            = V4L2_CID_BRIGHTNESS,
-+			.name          = "Brightness",
-+			.minimum       = 0x00,
-+			.maximum       = 0xff,
-+			.step          = 1,
-+			.default_value = 0x7f,
-+			.type          = V4L2_CTRL_TYPE_INTEGER,
-+		},
-+		.off                   = 128,
-+		.reg                   = LUMA_CTRL,
-+		.mask                  = 0x00ff,
-+		.shift                 = 0,
-+	}, {
-+		.v = {
-+			.id            = V4L2_CID_CONTRAST,
-+			.name          = "Contrast",
-+			.minimum       = 0,
-+			.maximum       = 0xff,
-+			.step          = 1,
-+			.default_value = 0x3f,
-+			.type          = V4L2_CTRL_TYPE_INTEGER,
-+		},
-+		.off                   = 0,
-+		.reg                   = LUMA_CTRL,
-+		.mask                  = 0xff00,
-+		.shift                 = 8,
-+	}, {
-+		.v = {
-+			.id            = V4L2_CID_HUE,
-+			.name          = "Hue",
-+			.minimum       = 0,
-+			.maximum       = 0xff,
-+			.step          = 1,
-+			.default_value = 0x7f,
-+			.type          = V4L2_CTRL_TYPE_INTEGER,
-+		},
-+		.off                   = 128,
-+		.reg                   = CHROMA_CTRL,
-+		.mask                  = 0xff0000,
-+		.shift                 = 16,
-+	}, {
-+		/* strictly, this only describes only U saturation.
-+		 * V saturation is handled specially through code.
++		/* GPIO and initialization codes for analog TV and radio
++		   This code should be complemented for DTV, since reset
++		   codes are different.
 +		 */
-+		.v = {
-+			.id            = V4L2_CID_SATURATION,
-+			.name          = "Saturation",
-+			.minimum       = 0,
-+			.maximum       = 0xff,
-+			.step          = 1,
-+			.default_value = 0x7f,
-+			.type          = V4L2_CTRL_TYPE_INTEGER,
-+		},
-+		.off                   = 0,
-+		.reg                   = CHROMA_CTRL,
-+		.mask                  = 0x00ff,
-+		.shift                 = 0,
-+	}, {
-+	/* --- audio --- */
-+		.v = {
-+			.id            = V4L2_CID_AUDIO_MUTE,
-+			.name          = "Mute",
-+			.minimum       = 0,
-+			.maximum       = 1,
-+			.default_value = 1,
-+			.type          = V4L2_CTRL_TYPE_BOOLEAN,
-+		},
-+		.reg                   = PATH1_CTL1,
-+		.mask                  = (0x1f << 24),
-+		.shift                 = 24,
-+	}, {
-+		.v = {
-+			.id            = V4L2_CID_AUDIO_VOLUME,
-+			.name          = "Volume",
-+			.minimum       = 0,
-+			.maximum       = 0x3f,
-+			.step          = 1,
-+			.default_value = 0x3f,
-+			.type          = V4L2_CTRL_TYPE_INTEGER,
-+		},
-+		.reg                   = PATH1_VOL_CTL,
-+		.mask                  = 0xff,
-+		.shift                 = 0,
-+	}
-+};
-+static const int CX23885_CTLS = ARRAY_SIZE(cx23885_ctls);
-+
-+const u32 cx23885_user_ctrls[] = {
-+	V4L2_CID_USER_CLASS,
-+	V4L2_CID_BRIGHTNESS,
-+	V4L2_CID_CONTRAST,
-+	V4L2_CID_SATURATION,
-+	V4L2_CID_HUE,
-+	V4L2_CID_AUDIO_VOLUME,
-+	V4L2_CID_AUDIO_MUTE,
-+	0
-+};
-+EXPORT_SYMBOL(cx23885_user_ctrls);
 +
-+static const u32 *ctrl_classes[] = {
-+	cx23885_user_ctrls,
-+	NULL
-+};
++		dev->em28xx_write_regs_req(dev, 0x00, 0x48, "\x00", 1);
++		dev->em28xx_write_regs_req(dev, 0x00, 0x12, "\x67", 1);
 +
-+void cx23885_video_wakeup(struct cx23885_dev *dev,
-+		 struct cx23885_dmaqueue *q, u32 count)
-+{
-+	struct cx23885_buffer *buf;
-+	int bc;
++		if (dev->analog_gpio) {
++			char gpio0 = dev->analog_gpio & 0xff;
++			char gpio1 = (dev->analog_gpio >> 8) & 0xff;
++			char gpio4 = dev->analog_gpio >> 24;
 +
-+	for (bc = 0;; bc++) {
-+		if (list_empty(&q->active))
-+			break;
-+		buf = list_entry(q->active.next,
-+				 struct cx23885_buffer, vb.queue);
++			if (gpio4) {
++				dev->em28xx_write_regs(dev, 0x04, &gpio4, 1);
++				msleep(140);
+ 			}
 +
-+		/* count comes from the hw and is is 16bit wide --
-+		 * this trick handles wrap-arounds correctly for
-+		 * up to 32767 buffers in flight... */
-+		if ((s16) (count - buf->count) < 0)
-+			break;
++			msleep(6);
++			dev->em28xx_write_regs(dev, 0x08, &gpio0, 1);
++			msleep(10);
++			dev->em28xx_write_regs(dev, 0x08, &gpio1, 1);
++			msleep(5);
++		}
 +
-+		do_gettimeofday(&buf->vb.ts);
-+		dprintk(2, "[%p/%d] wakeup reg=%d buf=%d\n", buf, buf->vb.i,
-+			count, buf->count);
-+		buf->vb.state = VIDEOBUF_DONE;
-+		list_del(&buf->vb.queue);
-+		wake_up(&buf->vb.done);
++		break;
 +	}
-+	if (list_empty(&q->active)) {
-+		del_timer(&q->timeout);
-+	} else {
-+		mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
 +	}
-+	if (bc != 1)
-+		printk(KERN_ERR "%s: %d buffers handled (should be 1)\n",
-+			__FUNCTION__, bc);
++	return rc;
 +}
 +
-+int cx23885_set_tvnorm(struct cx23885_dev *dev, v4l2_std_id norm)
++static void em28xx_config_tuner(struct em28xx *dev)
 +{
-+	dprintk(1, "%s(norm = 0x%08x) name: [%s]\n",
-+		__FUNCTION__,
-+		(unsigned int)norm,
-+		v4l2_norm_to_name(norm));
++	struct v4l2_priv_tun_config  xc2028_cfg;
++	struct xc2028_ctrl           ctl;
++	struct tuner_setup           tun_setup;
++	struct v4l2_frequency        f;
 +
-+	dev->tvnorm = norm;
++	if (dev->tuner_type == TUNER_ABSENT)
++		return;
 +
-+	/* Tell the analog tuner/demods */
-+	cx23885_call_i2c_clients(&dev->i2c_bus[1], VIDIOC_S_STD, &norm);
++	tun_setup.mode_mask = T_ANALOG_TV | T_RADIO;
++	tun_setup.type = dev->tuner_type;
++	tun_setup.addr = dev->tuner_addr;
++	tun_setup.tuner_callback = em28xx_tuner_callback;
 +
-+	/* Tell the internal A/V decoder */
-+	cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_S_STD, &norm);
++	em28xx_i2c_call_clients(dev, TUNER_SET_TYPE_ADDR, &tun_setup);
 +
-+	return 0;
-+}
++	if (dev->tuner_type == TUNER_XC2028) {
++		memset(&ctl, 0, sizeof(ctl));
 +
-+struct video_device *cx23885_vdev_init(struct cx23885_dev *dev,
-+				    struct pci_dev *pci,
-+				    struct video_device *template,
-+				    char *type)
-+{
-+	struct video_device *vfd;
-+	dprintk(1, "%s()\n", __FUNCTION__);
++		ctl.fname   = XC2028_DEFAULT_FIRMWARE;
++		ctl.max_len = 64;
++		ctl.mts = em28xx_boards[dev->model].mts_firmware;
 +
-+	vfd = video_device_alloc();
-+	if (NULL == vfd)
-+		return NULL;
-+	*vfd = *template;
-+	vfd->minor   = -1;
-+	vfd->dev     = &pci->dev;
-+	vfd->release = video_device_release;
-+	snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)",
-+		 dev->name, type, cx23885_boards[dev->board].name);
-+	return vfd;
++		xc2028_cfg.tuner = TUNER_XC2028;
++		xc2028_cfg.priv  = &ctl;
++
++		em28xx_i2c_call_clients(dev, TUNER_SET_CONFIG, &xc2028_cfg);
++	}
++
++	/* configure tuner */
++	f.tuner = 0;
++	f.type = V4L2_TUNER_ANALOG_TV;
++	f.frequency = 9076;     /* just a magic number */
++	dev->ctl_freq = f.frequency;
++	em28xx_i2c_call_clients(dev, VIDIOC_S_FREQUENCY, &f);
 +}
 +
-+int cx23885_ctrl_query(struct v4l2_queryctrl *qctrl)
++static int em28xx_hint_board(struct em28xx *dev)
 +{
 +	int i;
 +
-+	if (qctrl->id < V4L2_CID_BASE ||
-+	    qctrl->id >= V4L2_CID_LASTP1)
-+		return -EINVAL;
-+	for (i = 0; i < CX23885_CTLS; i++)
-+		if (cx23885_ctls[i].v.id == qctrl->id)
-+			break;
-+	if (i == CX23885_CTLS) {
-+		*qctrl = no_ctl;
-+		return 0;
++	/* HINT method: EEPROM
++	 *
++	 * This method works only for boards with eeprom.
++	 * Uses a hash of all eeprom bytes. The hash should be
++	 * unique for a vendor/tuner pair.
++	 * There are a high chance that tuners for different
++	 * video standards produce different hashes.
++	 */
++	for (i = 0; i < ARRAY_SIZE(em28xx_eeprom_hash); i++) {
++		if (dev->hash == em28xx_eeprom_hash[i].hash) {
++			dev->model = em28xx_eeprom_hash[i].model;
++			dev->tuner_type = em28xx_eeprom_hash[i].tuner;
++
++			em28xx_errdev("Your board has no unique USB ID.\n");
++			em28xx_errdev("A hint were successfully done, "
++				      "based on eeprom hash.\n");
++			em28xx_errdev("This method is not 100%% failproof.\n");
++			em28xx_errdev("If the board were missdetected, "
++				      "please email this log to:\n");
++			em28xx_errdev("\tV4L Mailing List "
++				      " <video4linux-list at redhat.com>\n");
++			em28xx_errdev("Board detected as %s\n",
++				      em28xx_boards[dev->model].name);
++
++			return 0;
++		}
 +	}
-+	*qctrl = cx23885_ctls[i].v;
-+	return 0;
-+}
-+EXPORT_SYMBOL(cx23885_ctrl_query);
 +
-+/* ------------------------------------------------------------------- */
-+/* resource management                                                 */
++	/* HINT method: I2C attached devices
++	 *
++	 * This method works for all boards.
++	 * Uses a hash of i2c scanned devices.
++	 * Devices with the same i2c attached chips will
++	 * be considered equal.
++	 * This method is less precise than the eeprom one.
++	 */
 +
-+static int res_get(struct cx23885_dev *dev, struct cx23885_fh *fh,
-+	unsigned int bit)
-+{
-+	dprintk(1, "%s()\n", __FUNCTION__);
-+	if (fh->resources & bit)
-+		/* have it already allocated */
-+		return 1;
++	/* user did not request i2c scanning => do it now */
++	if (!dev->i2c_hash)
++		em28xx_do_i2c_scan(dev);
 +
-+	/* is it free? */
-+	mutex_lock(&dev->lock);
-+	if (dev->resources & bit) {
-+		/* no, someone else uses it */
-+		mutex_unlock(&dev->lock);
-+		return 0;
++	for (i = 0; i < ARRAY_SIZE(em28xx_i2c_hash); i++) {
++		if (dev->i2c_hash == em28xx_i2c_hash[i].hash) {
++			dev->model = em28xx_i2c_hash[i].model;
++			dev->tuner_type = em28xx_i2c_hash[i].tuner;
++			em28xx_errdev("Your board has no unique USB ID.\n");
++			em28xx_errdev("A hint were successfully done, "
++				      "based on i2c devicelist hash.\n");
++			em28xx_errdev("This method is not 100%% failproof.\n");
++			em28xx_errdev("If the board were missdetected, "
++				      "please email this log to:\n");
++			em28xx_errdev("\tV4L Mailing List "
++				      " <video4linux-list at redhat.com>\n");
++			em28xx_errdev("Board detected as %s\n",
++				      em28xx_boards[dev->model].name);
++
++			return 0;
++		}
 +	}
-+	/* it's free, grab it */
-+	fh->resources  |= bit;
-+	dev->resources |= bit;
-+	dprintk(1, "res: get %d\n", bit);
-+	mutex_unlock(&dev->lock);
-+	return 1;
-+}
 +
-+static int res_check(struct cx23885_fh *fh, unsigned int bit)
-+{
-+	return (fh->resources & bit);
++	em28xx_errdev("Your board has no unique USB ID and thus need a "
++		      "hint to be detected.\n");
++	em28xx_errdev("You may try to use card=<n> insmod option to "
++		      "workaround that.\n");
++	em28xx_errdev("Please send an email with this log to:\n");
++	em28xx_errdev("\tV4L Mailing List <video4linux-list at redhat.com>\n");
++	em28xx_errdev("Board eeprom hash is 0x%08lx\n", dev->hash);
++	em28xx_errdev("Board i2c devicelist hash is 0x%08lx\n", dev->i2c_hash);
++
++	em28xx_errdev("Here is a list of valid choices for the card=<n>"
++		      " insmod option:\n");
++	for (i = 0; i < em28xx_bcount; i++) {
++		em28xx_errdev("    card=%d -> %s\n",
++				i, em28xx_boards[i].name);
++	}
++	return -1;
 +}
 +
-+static int res_locked(struct cx23885_dev *dev, unsigned int bit)
++
++static void em28xx_set_model(struct em28xx *dev)
 +{
-+	return (dev->resources & bit);
++	dev->is_em2800 = em28xx_boards[dev->model].is_em2800;
++	dev->has_msp34xx = em28xx_boards[dev->model].has_msp34xx;
++	dev->tda9887_conf = em28xx_boards[dev->model].tda9887_conf;
++	dev->decoder = em28xx_boards[dev->model].decoder;
++	dev->video_inputs = em28xx_boards[dev->model].vchannels;
++	dev->analog_gpio = em28xx_boards[dev->model].analog_gpio;
++	dev->has_12mhz_i2s = em28xx_boards[dev->model].has_12mhz_i2s;
++	dev->max_range_640_480 = em28xx_boards[dev->model].max_range_640_480;
 +}
 +
-+static void res_free(struct cx23885_dev *dev, struct cx23885_fh *fh,
-+	unsigned int bits)
++/* ----------------------------------------------------------------------- */
++void em28xx_set_ir(struct em28xx *dev, struct IR_i2c *ir)
 +{
-+	BUG_ON((fh->resources & bits) != bits);
-+	dprintk(1, "%s()\n", __FUNCTION__);
++	if (disable_ir) {
++		ir->get_key = NULL;
++		return ;
++	}
 +
-+	mutex_lock(&dev->lock);
-+	fh->resources  &= ~bits;
-+	dev->resources &= ~bits;
-+	dprintk(1, "res: put %d\n", bits);
-+	mutex_unlock(&dev->lock);
-+}
++	/* detect & configure */
++	switch (dev->model) {
++	case (EM2800_BOARD_UNKNOWN):
++		break;
++	case (EM2820_BOARD_UNKNOWN):
++		break;
++	case (EM2800_BOARD_TERRATEC_CINERGY_200):
++	case (EM2820_BOARD_TERRATEC_CINERGY_250):
++		ir->ir_codes = ir_codes_em_terratec;
++		ir->get_key = em28xx_get_key_terratec;
++		snprintf(ir->c.name, sizeof(ir->c.name),
++			 "i2c IR (EM28XX Terratec)");
++		break;
++	case (EM2820_BOARD_PINNACLE_USB_2):
++		ir->ir_codes = ir_codes_pinnacle_grey;
++		ir->get_key = em28xx_get_key_pinnacle_usb_grey;
++		snprintf(ir->c.name, sizeof(ir->c.name),
++			 "i2c IR (EM28XX Pinnacle PCTV)");
++		break;
++	case (EM2820_BOARD_HAUPPAUGE_WINTV_USB_2):
++		ir->ir_codes = ir_codes_hauppauge_new;
++		ir->get_key = em28xx_get_key_em_haup;
++		snprintf(ir->c.name, sizeof(ir->c.name),
++			 "i2c IR (EM2840 Hauppauge)");
++		break;
++	case (EM2820_BOARD_MSI_VOX_USB_2):
++		break;
++	case (EM2800_BOARD_LEADTEK_WINFAST_USBII):
++		break;
++	case (EM2800_BOARD_KWORLD_USB2800):
++		break;
+ 	}
+ }
+ 
+ void em28xx_card_setup(struct em28xx *dev)
+ {
++	em28xx_set_model(dev);
 +
-+int cx23885_video_mux(struct cx23885_dev *dev, unsigned int input)
++	dev->tuner_type = em28xx_boards[dev->model].tuner_type;
++
+ 	/* request some modules */
+-	switch(dev->model){
+-		case EM2820_BOARD_HAUPPAUGE_WINTV_USB_2:
+-			{
+-				struct tveeprom tv;
++	switch (dev->model) {
++	case EM2820_BOARD_HAUPPAUGE_WINTV_USB_2:
++	case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900:
++	case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950:
++	{
++		struct tveeprom tv;
+ #ifdef CONFIG_MODULES
+-				request_module("tveeprom");
+-				request_module("ir-kbd-i2c");
+-				request_module("msp3400");
++		request_module("tveeprom");
+ #endif
+-				/* Call first TVeeprom */
+-
+-				dev->i2c_client.addr = 0xa0 >> 1;
+-				tveeprom_hauppauge_analog(&dev->i2c_client, &tv, dev->eedata);
+-
+-				dev->tuner_type= tv.tuner_type;
+-				if (tv.audio_processor == AUDIO_CHIP_MSP34XX) {
+-					dev->i2s_speed=2048000;
+-					dev->has_msp34xx=1;
+-				} else
+-					dev->has_msp34xx=0;
+-				break;
+-			}
+-		case EM2820_BOARD_KWORLD_PVRTV2800RF:
+-			{
+-				em28xx_write_regs_req(dev,0x00,0x08, "\xf9", 1); // GPIO enables sound on KWORLD PVR TV 2800RF
+-				break;
+-			}
++		/* Call first TVeeprom */
++
++		dev->i2c_client.addr = 0xa0 >> 1;
++		tveeprom_hauppauge_analog(&dev->i2c_client, &tv, dev->eedata);
+ 
++		dev->tuner_type = tv.tuner_type;
++
++		if (tv.audio_processor == AUDIO_CHIP_MSP34XX) {
++			dev->i2s_speed = 2048000;
++			dev->has_msp34xx = 1;
++		}
++#ifdef CONFIG_MODULES
++		if (tv.has_ir)
++			request_module("ir-kbd-i2c");
++#endif
++		break;
++	}
++	case EM2820_BOARD_KWORLD_PVRTV2800RF:
++		/* GPIO enables sound on KWORLD PVR TV 2800RF */
++		em28xx_write_regs_req(dev, 0x00, 0x08, "\xf9", 1);
++		break;
++	case EM2820_BOARD_UNKNOWN:
++	case EM2800_BOARD_UNKNOWN:
++		if (!em28xx_hint_board(dev))
++			em28xx_set_model(dev);
+ 	}
+-}
+ 
+-MODULE_DEVICE_TABLE (usb, em28xx_id_table);
++	/* Allow override tuner type by a module parameter */
++	if (tuner >= 0)
++		dev->tuner_type = tuner;
++
++#ifdef CONFIG_MODULES
++	/* request some modules */
++	if (dev->has_msp34xx)
++		request_module("msp3400");
++	if (dev->decoder == EM28XX_SAA7113 || dev->decoder == EM28XX_SAA7114)
++		request_module("saa7115");
++	if (dev->decoder == EM28XX_TVP5150)
++		request_module("tvp5150");
++	if (dev->tuner_type != TUNER_ABSENT)
++		request_module("tuner");
++#endif
++
++	em28xx_config_tuner(dev);
++}
+diff --git a/drivers/media/video/em28xx/em28xx-core.c b/drivers/media/video/em28xx/em28xx-core.c
+index d56484f..f6b7835 100644
+--- a/drivers/media/video/em28xx/em28xx-core.c
++++ b/drivers/media/video/em28xx/em28xx-core.c
+@@ -252,7 +252,7 @@ int em28xx_write_reg_bits(struct em28xx *dev, u16 reg, u8 val,
+  * em28xx_write_ac97()
+  * write a 16 bit value to the specified AC97 address (LSB first!)
+  */
+-int em28xx_write_ac97(struct em28xx *dev, u8 reg, u8 * val)
++static int em28xx_write_ac97(struct em28xx *dev, u8 reg, u8 *val)
+ {
+ 	int ret;
+ 	u8 addr = reg & 0x7f;
+@@ -268,16 +268,98 @@ int em28xx_write_ac97(struct em28xx *dev, u8 reg, u8 * val)
+ 	return 0;
+ }
+ 
++int em28xx_set_audio_source(struct em28xx *dev)
 +{
-+	struct v4l2_routing route;
-+	memset(&route, 0, sizeof(route));
++	static char *enable  = "\x08\x08";
++	static char *disable = "\x08\x88";
++	char *video = enable, *line = disable;
++	int ret, no_ac97;
++	u8 input;
 +
-+	dprintk(1, "%s() video_mux: %d [vmux=%d, gpio=0x%x,0x%x,0x%x,0x%x]\n",
-+		__FUNCTION__,
-+		input, INPUT(input)->vmux,
-+		INPUT(input)->gpio0, INPUT(input)->gpio1,
-+		INPUT(input)->gpio2, INPUT(input)->gpio3);
-+	dev->input = input;
++	if (dev->is_em2800) {
++		if (dev->ctl_ainput)
++			input = EM2800_AUDIO_SRC_LINE;
++		else
++			input = EM2800_AUDIO_SRC_TUNER;
 +
-+	route.input = INPUT(input)->vmux;
++		ret = em28xx_write_regs(dev, EM2800_AUDIOSRC_REG, &input, 1);
++		if (ret < 0)
++			return ret;
++	}
 +
-+	/* Tell the internal A/V decoder */
-+	cx23885_call_i2c_clients(&dev->i2c_bus[2],
-+		VIDIOC_INT_S_VIDEO_ROUTING, &route);
++	if (dev->has_msp34xx)
++		input = EM28XX_AUDIO_SRC_TUNER;
++	else {
++		switch (dev->ctl_ainput) {
++		case EM28XX_AMUX_VIDEO:
++			input = EM28XX_AUDIO_SRC_TUNER;
++			no_ac97 = 1;
++			break;
++		case EM28XX_AMUX_LINE_IN:
++			input = EM28XX_AUDIO_SRC_LINE;
++			no_ac97 = 1;
++			break;
++		case EM28XX_AMUX_AC97_VIDEO:
++			input = EM28XX_AUDIO_SRC_LINE;
++			break;
++		case EM28XX_AMUX_AC97_LINE_IN:
++			input = EM28XX_AUDIO_SRC_LINE;
++			video = disable;
++			line  = enable;
++			break;
++		}
++	}
 +
-+	return 0;
++	ret = em28xx_write_reg_bits(dev, AUDIOSRC_REG, input, 0xc0);
++	if (ret < 0)
++		return ret;
++
++	if (no_ac97)
++		return 0;
++
++	/* Sets AC97 mixer registers */
++
++	ret = em28xx_write_ac97(dev, VIDEO_AC97, video);
++	if (ret < 0)
++		return ret;
++
++	ret = em28xx_write_ac97(dev, LINE_IN_AC97, line);
++
++	return ret;
 +}
-+EXPORT_SYMBOL(cx23885_video_mux);
 +
-+/* ------------------------------------------------------------------ */
-+int cx23885_set_scale(struct cx23885_dev *dev, unsigned int width,
-+	unsigned int height, enum v4l2_field field)
+ int em28xx_audio_analog_set(struct em28xx *dev)
+ {
++	int ret;
+ 	char s[2] = { 0x00, 0x00 };
++	u8 xclk = 0x07;
++
+ 	s[0] |= 0x1f - dev->volume;
+ 	s[1] |= 0x1f - dev->volume;
++
+ 	if (dev->mute)
+ 		s[1] |= 0x80;
+-	return em28xx_write_ac97(dev, MASTER_AC97, s);
+-}
++	ret = em28xx_write_ac97(dev, MASTER_AC97, s);
++	if (ret < 0)
++		return ret;
++
++	if (dev->has_12mhz_i2s)
++		xclk |= 0x20;
++
++	if (!dev->mute)
++		xclk |= 0x80;
+ 
++	ret = em28xx_write_reg_bits(dev, XCLK_REG, xclk, 0xa7);
++	if (ret < 0)
++		return ret;
++	msleep(10);
++
++	/* Selects the proper audio input */
++	ret = em28xx_set_audio_source(dev);
++
++	return ret;
++}
++EXPORT_SYMBOL_GPL(em28xx_audio_analog_set);
+ 
+ int em28xx_colorlevels_set_default(struct em28xx *dev)
+ {
+diff --git a/drivers/media/video/em28xx/em28xx-i2c.c b/drivers/media/video/em28xx/em28xx-i2c.c
+index e3a4aa7..cacd04d 100644
+--- a/drivers/media/video/em28xx/em28xx-i2c.c
++++ b/drivers/media/video/em28xx/em28xx-i2c.c
+@@ -25,9 +25,9 @@
+ #include <linux/kernel.h>
+ #include <linux/usb.h>
+ #include <linux/i2c.h>
+-#include <linux/video_decoder.h>
+ 
+ #include "em28xx.h"
++#include "tuner-xc2028.h"
+ #include <media/v4l2-common.h>
+ #include <media/tuner.h>
+ 
+@@ -291,6 +291,31 @@ static int em28xx_i2c_xfer(struct i2c_adapter *i2c_adap,
+ 	return rc;
+ }
+ 
++/* based on linux/sunrpc/svcauth.h and linux/hash.h
++ * The original hash function returns a different value, if arch is x86_64
++ *  or i386.
++ */
++static inline unsigned long em28xx_hash_mem(char *buf, int length, int bits)
 +{
-+	dprintk(1, "%s()\n", __FUNCTION__);
-+	return 0;
++	unsigned long hash = 0;
++	unsigned long l = 0;
++	int len = 0;
++	unsigned char c;
++	do {
++		if (len == length) {
++			c = (char)len;
++			len = -1;
++		} else
++			c = *buf++;
++		l = (l << 8) | c;
++		len++;
++		if ((len & (32 / 8 - 1)) == 0)
++			hash = ((hash^l) * 0x9e370001UL);
++	} while (len);
++
++	return (hash >> (32 - bits)) & 0xffffffffUL;
 +}
 +
-+static int cx23885_start_video_dma(struct cx23885_dev *dev,
-+			   struct cx23885_dmaqueue *q,
-+			   struct cx23885_buffer *buf)
-+{
-+	dprintk(1, "%s()\n", __FUNCTION__);
+ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len)
+ {
+ 	unsigned char buf, *p = eedata;
+@@ -334,7 +359,11 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len)
+ 			printk("\n");
+ 	}
+ 
+-	printk(KERN_INFO "EEPROM ID= 0x%08x\n", em_eeprom->id);
++	if (em_eeprom->id == 0x9567eb1a)
++		dev->hash = em28xx_hash_mem(eedata, len, 32);
 +
-+	/* setup fifo + format */
-+	cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH01],
-+				buf->bpl, buf->risc.dma);
-+	cx23885_set_scale(dev, buf->vb.width, buf->vb.height, buf->vb.field);
++	printk(KERN_INFO "EEPROM ID= 0x%08x, hash = 0x%08lx\n",
++	       em_eeprom->id, dev->hash);
+ 	printk(KERN_INFO "Vendor/Product ID= %04x:%04x\n", em_eeprom->vendor_ID,
+ 	       em_eeprom->product_ID);
+ 
+@@ -391,21 +420,6 @@ static u32 functionality(struct i2c_adapter *adap)
+ }
+ 
+ 
+-static int em28xx_set_tuner(int check_eeprom, struct i2c_client *client)
+-{
+-	struct em28xx *dev = client->adapter->algo_data;
+-	struct tuner_setup tun_setup;
+-
+-	if (dev->has_tuner) {
+-		tun_setup.mode_mask = T_ANALOG_TV | T_RADIO;
+-		tun_setup.type = dev->tuner_type;
+-		tun_setup.addr = dev->tuner_addr;
+-		em28xx_i2c_call_clients(dev, TUNER_SET_TYPE_ADDR, &tun_setup);
+-	}
+-
+-	return (0);
+-}
+-
+ /*
+  * attach_inform()
+  * gets called when a device attaches to the i2c bus
+@@ -421,6 +435,8 @@ static int attach_inform(struct i2c_client *client)
+ 		case 0x96:
+ 		case 0x94:
+ 		{
++			struct v4l2_priv_tun_config tda9887_cfg;
 +
-+	/* reset counter */
-+	cx_write(VID_A_GPCNT_CTL, 3);
-+	q->count = 1;
+ 			struct tuner_setup tun_setup;
+ 
+ 			tun_setup.mode_mask = T_ANALOG_TV | T_RADIO;
+@@ -428,7 +444,11 @@ static int attach_inform(struct i2c_client *client)
+ 			tun_setup.addr = client->addr;
+ 
+ 			em28xx_i2c_call_clients(dev, TUNER_SET_TYPE_ADDR, &tun_setup);
+-			em28xx_i2c_call_clients(dev, TDA9887_SET_CONFIG, &dev->tda9887_conf);
 +
-+	/* enable irq */
-+	cx_set(PCI_INT_MSK, cx_read(PCI_INT_MSK) | 0x01);
-+	cx_set(VID_A_INT_MSK, 0x000011);
++			tda9887_cfg.tuner = TUNER_TDA9887;
++			tda9887_cfg.priv = &dev->tda9887_conf;
++			em28xx_i2c_call_clients(dev, TUNER_SET_CONFIG,
++						&tda9887_cfg);
+ 			break;
+ 		}
+ 		case 0x42:
+@@ -458,9 +478,11 @@ static int attach_inform(struct i2c_client *client)
+ 			break;
+ 
+ 		default:
++			if (!dev->tuner_addr)
++				dev->tuner_addr = client->addr;
 +
-+	/* start dma */
-+	cx_set(DEV_CNTRL2, (1<<5));
-+	cx_set(VID_A_DMA_CTL, 0x11); /* FIFO and RISC enable */
+ 			dprintk1(1,"attach inform: detected I2C address %x\n", client->addr << 1);
+-			dev->tuner_addr = client->addr;
+-			em28xx_set_tuner(-1, client);
++
+ 	}
+ 
+ 	return 0;
+@@ -510,19 +532,26 @@ static char *i2c_devs[128] = {
+  * do_i2c_scan()
+  * check i2c address range for devices
+  */
+-static void do_i2c_scan(char *name, struct i2c_client *c)
++void em28xx_do_i2c_scan(struct em28xx *dev)
+ {
++	u8 i2c_devicelist[128];
+ 	unsigned char buf;
+ 	int i, rc;
+ 
++	memset(i2c_devicelist, 0, ARRAY_SIZE(i2c_devicelist));
++
+ 	for (i = 0; i < ARRAY_SIZE(i2c_devs); i++) {
+-		c->addr = i;
+-		rc = i2c_master_recv(c, &buf, 0);
++		dev->i2c_client.addr = i;
++		rc = i2c_master_recv(&dev->i2c_client, &buf, 0);
+ 		if (rc < 0)
+ 			continue;
+-		printk(KERN_INFO "%s: found i2c device @ 0x%x [%s]\n", name,
+-		       i << 1, i2c_devs[i] ? i2c_devs[i] : "???");
++		i2c_devicelist[i] = i;
++		printk(KERN_INFO "%s: found i2c device @ 0x%x [%s]\n",
++		       dev->name, i << 1, i2c_devs[i] ? i2c_devs[i] : "???");
+ 	}
++
++	dev->i2c_hash = em28xx_hash_mem(i2c_devicelist,
++					ARRAY_SIZE(i2c_devicelist), 32);
+ }
+ 
+ /*
+@@ -555,7 +584,7 @@ int em28xx_i2c_register(struct em28xx *dev)
+ 	em28xx_i2c_eeprom(dev, dev->eedata, sizeof(dev->eedata));
+ 
+ 	if (i2c_scan)
+-		do_i2c_scan(dev->name, &dev->i2c_client);
++		em28xx_do_i2c_scan(dev);
+ 	return 0;
+ }
+ 
+diff --git a/drivers/media/video/em28xx/em28xx-input.c b/drivers/media/video/em28xx/em28xx-input.c
+index e3894b6..10da2fd 100644
+--- a/drivers/media/video/em28xx/em28xx-input.c
++++ b/drivers/media/video/em28xx/em28xx-input.c
+@@ -30,11 +30,7 @@
+ 
+ #include "em28xx.h"
+ 
+-static unsigned int disable_ir = 0;
+-module_param(disable_ir, int, 0444);
+-MODULE_PARM_DESC(disable_ir,"disable infrared remote support");
+-
+-static unsigned int ir_debug = 0;
++static unsigned int ir_debug;
+ module_param(ir_debug, int, 0644);
+ MODULE_PARM_DESC(ir_debug,"enable debug messages [IR]");
+ 
+@@ -43,7 +39,7 @@ MODULE_PARM_DESC(ir_debug,"enable debug messages [IR]");
+ 
+ /* ----------------------------------------------------------------------- */
+ 
+-static int get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
++int em28xx_get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+ {
+ 	unsigned char b;
+ 
+@@ -72,7 +68,7 @@ static int get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+ }
+ 
+ 
+-static int get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
++int em28xx_get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+ {
+ 	unsigned char buf[2];
+ 	unsigned char code;
+@@ -103,7 +99,8 @@ static int get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+ 	return 1;
+ }
+ 
+-static int get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
++int em28xx_get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key,
++				     u32 *ir_raw)
+ {
+ 	unsigned char buf[3];
+ 
+@@ -125,45 +122,6 @@ static int get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw
+ 	return 1;
+ }
+ 
+-/* ----------------------------------------------------------------------- */
+-void em28xx_set_ir(struct em28xx * dev,struct IR_i2c *ir)
+-{
+-	if (disable_ir) {
+-		ir->get_key=NULL;
+-		return ;
+-	}
+-
+-	/* detect & configure */
+-	switch (dev->model) {
+-	case (EM2800_BOARD_UNKNOWN):
+-		break;
+-	case (EM2820_BOARD_UNKNOWN):
+-		break;
+-	case (EM2800_BOARD_TERRATEC_CINERGY_200):
+-	case (EM2820_BOARD_TERRATEC_CINERGY_250):
+-		ir->ir_codes = ir_codes_em_terratec;
+-		ir->get_key = get_key_terratec;
+-		snprintf(ir->c.name, sizeof(ir->c.name), "i2c IR (EM28XX Terratec)");
+-		break;
+-	case (EM2820_BOARD_PINNACLE_USB_2):
+-		ir->ir_codes = ir_codes_pinnacle_grey;
+-		ir->get_key = get_key_pinnacle_usb_grey;
+-		snprintf(ir->c.name, sizeof(ir->c.name), "i2c IR (EM28XX Pinnacle PCTV)");
+-		break;
+-	case (EM2820_BOARD_HAUPPAUGE_WINTV_USB_2):
+-		ir->ir_codes = ir_codes_hauppauge_new;
+-		ir->get_key = get_key_em_haup;
+-		snprintf(ir->c.name, sizeof(ir->c.name), "i2c IR (EM2840 Hauppauge)");
+-		break;
+-	case (EM2820_BOARD_MSI_VOX_USB_2):
+-		break;
+-	case (EM2800_BOARD_LEADTEK_WINFAST_USBII):
+-		break;
+-	case (EM2800_BOARD_KWORLD_USB2800):
+-		break;
+-	}
+-}
+-
+ /* ----------------------------------------------------------------------
+  * Local variables:
+  * c-basic-offset: 8
+diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c
+index 0906bc5..a0c3346 100644
+--- a/drivers/media/video/em28xx/em28xx-video.c
++++ b/drivers/media/video/em28xx/em28xx-video.c
+@@ -33,13 +33,12 @@
+ #include <linux/i2c.h>
+ #include <linux/version.h>
+ #include <linux/mm.h>
+-#include <linux/video_decoder.h>
+ #include <linux/mutex.h>
+ 
+ #include "em28xx.h"
+-#include <media/tuner.h>
+ #include <media/v4l2-common.h>
+ #include <media/msp3400.h>
++#include <media/tuner.h>
+ 
+ #define DRIVER_AUTHOR "Ludovico Cavedon <cavedon at sssup.it>, " \
+ 		      "Markus Rechberger <mrechberger at gmail.com>, " \
+@@ -48,7 +47,7 @@
+ 
+ #define DRIVER_NAME         "em28xx"
+ #define DRIVER_DESC         "Empia em28xx based USB video device driver"
+-#define EM28XX_VERSION_CODE  KERNEL_VERSION(0, 0, 1)
++#define EM28XX_VERSION_CODE  KERNEL_VERSION(0, 1, 0)
+ 
+ #define em28xx_videodbg(fmt, arg...) do {\
+ 	if (video_debug) \
+@@ -63,17 +62,17 @@ static LIST_HEAD(em28xx_devlist);
+ 
+ static unsigned int card[]     = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
+ static unsigned int video_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
+-static unsigned int vbi_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
++static unsigned int vbi_nr[]   = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
++static unsigned int radio_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
++
+ module_param_array(card,  int, NULL, 0444);
+ module_param_array(video_nr, int, NULL, 0444);
+ module_param_array(vbi_nr, int, NULL, 0444);
+-MODULE_PARM_DESC(card,"card type");
+-MODULE_PARM_DESC(video_nr,"video device numbers");
+-MODULE_PARM_DESC(vbi_nr,"vbi device numbers");
+-
+-static int tuner = -1;
+-module_param(tuner, int, 0444);
+-MODULE_PARM_DESC(tuner, "tuner type");
++module_param_array(radio_nr, int, NULL, 0444);
++MODULE_PARM_DESC(card,     "card type");
++MODULE_PARM_DESC(video_nr, "video device numbers");
++MODULE_PARM_DESC(vbi_nr,   "vbi device numbers");
++MODULE_PARM_DESC(radio_nr, "radio device numbers");
+ 
+ static unsigned int video_debug = 0;
+ module_param(video_debug,int,0644);
+@@ -82,29 +81,6 @@ MODULE_PARM_DESC(video_debug,"enable debug messages [video]");
+ /* Bitmask marking allocated devices from 0 to EM28XX_MAXBOARDS */
+ static unsigned long em28xx_devused;
+ 
+-/* supported tv norms */
+-static struct em28xx_tvnorm tvnorms[] = {
+-	{
+-		.name = "PAL",
+-		.id = V4L2_STD_PAL,
+-		.mode = VIDEO_MODE_PAL,
+-	 }, {
+-		.name = "NTSC",
+-		.id = V4L2_STD_NTSC,
+-		.mode = VIDEO_MODE_NTSC,
+-	}, {
+-		 .name = "SECAM",
+-		 .id = V4L2_STD_SECAM,
+-		 .mode = VIDEO_MODE_SECAM,
+-	}, {
+-		.name = "PAL-M",
+-		.id = V4L2_STD_PAL_M,
+-		.mode = VIDEO_MODE_PAL,
+-	}
+-};
+-
+-#define TVNORMS ARRAY_SIZE(tvnorms)
+-
+ /* supported controls */
+ /* Common to all boards */
+ static struct v4l2_queryctrl em28xx_qctrl[] = {
+@@ -131,8 +107,6 @@ static struct v4l2_queryctrl em28xx_qctrl[] = {
+ 
+ static struct usb_driver em28xx_usb_driver;
+ 
+-static DEFINE_MUTEX(em28xx_sysfs_lock);
+-static DECLARE_RWSEM(em28xx_disconnect);
+ 
+ /*********************  v4l2 interface  ******************************************/
+ 
+@@ -153,11 +127,9 @@ static int em28xx_config(struct em28xx *dev)
+ /*	em28xx_write_regs_req(dev,0x00,0x0f,"\x80",1); clk register */
+ 	em28xx_write_regs_req(dev,0x00,0x11,"\x51",1);
+ 
+-	em28xx_audio_usb_mute(dev, 1);
+ 	dev->mute = 1;		/* maybe not the right place... */
+ 	dev->volume = 0x1f;
+-	em28xx_audio_analog_set(dev);
+-	em28xx_audio_analog_setup(dev);
++
+ 	em28xx_outfmt_set_yuv422(dev);
+ 	em28xx_colorlevels_set_default(dev);
+ 	em28xx_compression_disable(dev);
+@@ -171,7 +143,6 @@ static int em28xx_config(struct em28xx *dev)
+  */
+ static void em28xx_config_i2c(struct em28xx *dev)
+ {
+-	struct v4l2_frequency f;
+ 	struct v4l2_routing route;
+ 
+ 	route.input = INPUT(dev->ctl_input)->vmux;
+@@ -179,18 +150,6 @@ static void em28xx_config_i2c(struct em28xx *dev)
+ 	em28xx_i2c_call_clients(dev, VIDIOC_INT_RESET, NULL);
+ 	em28xx_i2c_call_clients(dev, VIDIOC_INT_S_VIDEO_ROUTING, &route);
+ 	em28xx_i2c_call_clients(dev, VIDIOC_STREAMON, NULL);
+-
+-	/* configure tuner */
+-	f.tuner = 0;
+-	f.type = V4L2_TUNER_ANALOG_TV;
+-	f.frequency = 9076;	/* FIXME:remove magic number */
+-	dev->ctl_freq = f.frequency;
+-	em28xx_i2c_call_clients(dev, VIDIOC_S_FREQUENCY, &f);
+-
+-	/* configure tda9887 */
+-
+-
+-/*	em28xx_i2c_call_clients(dev,VIDIOC_S_STD,&dev->tvnorm->id); */
+ }
+ 
+ /*
+@@ -212,7 +171,6 @@ static void em28xx_empty_framequeues(struct em28xx *dev)
+ 
+ static void video_mux(struct em28xx *dev, int index)
+ {
+-	int ainput;
+ 	struct v4l2_routing route;
+ 
+ 	route.input = INPUT(index)->vmux;
+@@ -222,8 +180,6 @@ static void video_mux(struct em28xx *dev, int index)
+ 
+ 	em28xx_i2c_call_clients(dev, VIDIOC_INT_S_VIDEO_ROUTING, &route);
+ 
+-	em28xx_videodbg("Setting input index=%d, vmux=%d, amux=%d\n",index,route.input,dev->ctl_ainput);
+-
+ 	if (dev->has_msp34xx) {
+ 		if (dev->i2s_speed)
+ 			em28xx_i2c_call_clients(dev, VIDIOC_INT_I2S_CLOCK_FREQ, &dev->i2s_speed);
+@@ -231,18 +187,1068 @@ static void video_mux(struct em28xx *dev, int index)
+ 		route.output = MSP_OUTPUT(MSP_SC_IN_DSP_SCART1);
+ 		/* Note: this is msp3400 specific */
+ 		em28xx_i2c_call_clients(dev, VIDIOC_INT_S_AUDIO_ROUTING, &route);
+-		ainput = EM28XX_AUDIO_SRC_TUNER;
+-		em28xx_audio_source(dev, ainput);
++	}
 +
-+	return 0;
++	em28xx_set_audio_source(dev);
 +}
 +
-+
-+static int cx23885_restart_video_queue(struct cx23885_dev *dev,
-+			       struct cx23885_dmaqueue *q)
++/* Usage lock check functions */
++static int res_get(struct em28xx_fh *fh)
 +{
-+	struct cx23885_buffer *buf, *prev;
-+	struct list_head *item;
-+	dprintk(1, "%s()\n", __FUNCTION__);
++	struct em28xx    *dev = fh->dev;
++	int		 rc   = 0;
 +
-+	if (!list_empty(&q->active)) {
-+		buf = list_entry(q->active.next, struct cx23885_buffer,
-+			vb.queue);
-+		dprintk(2, "restart_queue [%p/%d]: restart dma\n",
-+			buf, buf->vb.i);
-+		cx23885_start_video_dma(dev, q, buf);
-+		list_for_each(item, &q->active) {
-+			buf = list_entry(item, struct cx23885_buffer,
-+				vb.queue);
-+			buf->count    = q->count++;
-+		}
-+		mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
-+		return 0;
-+	}
++	/* This instance already has stream_on */
++	if (fh->stream_on)
++		return rc;
 +
-+	prev = NULL;
-+	for (;;) {
-+		if (list_empty(&q->queued))
-+			return 0;
-+		buf = list_entry(q->queued.next, struct cx23885_buffer,
-+			vb.queue);
-+		if (NULL == prev) {
-+			list_move_tail(&buf->vb.queue, &q->active);
-+			cx23885_start_video_dma(dev, q, buf);
-+			buf->vb.state = VIDEOBUF_ACTIVE;
-+			buf->count    = q->count++;
-+			mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
-+			dprintk(2, "[%p/%d] restart_queue - first active\n",
-+				buf, buf->vb.i);
++	mutex_lock(&dev->lock);
 +
-+		} else if (prev->vb.width  == buf->vb.width  &&
-+			   prev->vb.height == buf->vb.height &&
-+			   prev->fmt       == buf->fmt) {
-+			list_move_tail(&buf->vb.queue, &q->active);
-+			buf->vb.state = VIDEOBUF_ACTIVE;
-+			buf->count    = q->count++;
-+			prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
-+			prev->risc.jmp[2] = cpu_to_le32(0); /* Bits 63 - 32 */
-+			dprintk(2, "[%p/%d] restart_queue - move to active\n",
-+				buf, buf->vb.i);
-+		} else {
-+			return 0;
-+		}
-+		prev = buf;
++	if (dev->stream_on)
++		rc = -EINVAL;
++	else {
++		dev->stream_on = 1;
++		fh->stream_on  = 1;
 +	}
++
++	mutex_unlock(&dev->lock);
++	return rc;
 +}
 +
-+static int buffer_setup(struct videobuf_queue *q, unsigned int *count,
-+	unsigned int *size)
++static int res_check(struct em28xx_fh *fh)
 +{
-+	struct cx23885_fh *fh = q->priv_data;
-+
-+	*size = fh->fmt->depth*fh->width*fh->height >> 3;
-+	if (0 == *count)
-+		*count = 32;
-+	while (*size * *count > vid_limit * 1024 * 1024)
-+		(*count)--;
-+	return 0;
++	return (fh->stream_on);
 +}
 +
-+static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
-+	       enum v4l2_field field)
++static void res_free(struct em28xx_fh *fh)
 +{
-+	struct cx23885_fh *fh  = q->priv_data;
-+	struct cx23885_dev *dev = fh->dev;
-+	struct cx23885_buffer *buf =
-+		container_of(vb, struct cx23885_buffer, vb);
-+	int rc, init_buffer = 0;
-+	u32 line0_offset, line1_offset;
-+	struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb);
-+
-+	BUG_ON(NULL == fh->fmt);
-+	if (fh->width  < 48 || fh->width  > norm_maxw(dev->tvnorm) ||
-+	    fh->height < 32 || fh->height > norm_maxh(dev->tvnorm))
-+		return -EINVAL;
-+	buf->vb.size = (fh->width * fh->height * fh->fmt->depth) >> 3;
-+	if (0 != buf->vb.baddr  &&  buf->vb.bsize < buf->vb.size)
-+		return -EINVAL;
-+
-+	if (buf->fmt       != fh->fmt    ||
-+	    buf->vb.width  != fh->width  ||
-+	    buf->vb.height != fh->height ||
-+	    buf->vb.field  != field) {
-+		buf->fmt       = fh->fmt;
-+		buf->vb.width  = fh->width;
-+		buf->vb.height = fh->height;
-+		buf->vb.field  = field;
-+		init_buffer = 1;
-+	}
-+
-+	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
-+		init_buffer = 1;
-+		rc = videobuf_iolock(q, &buf->vb, NULL);
-+		if (0 != rc)
-+			goto fail;
-+	}
-+
-+	if (init_buffer) {
-+		buf->bpl = buf->vb.width * buf->fmt->depth >> 3;
-+		switch (buf->vb.field) {
-+		case V4L2_FIELD_TOP:
-+			cx23885_risc_buffer(dev->pci, &buf->risc,
-+					 dma->sglist, 0, UNSET,
-+					 buf->bpl, 0, buf->vb.height);
-+			break;
-+		case V4L2_FIELD_BOTTOM:
-+			cx23885_risc_buffer(dev->pci, &buf->risc,
-+					 dma->sglist, UNSET, 0,
-+					 buf->bpl, 0, buf->vb.height);
-+			break;
-+		case V4L2_FIELD_INTERLACED:
-+			if (dev->tvnorm & V4L2_STD_NTSC) {
-+				/* cx25840 transmits NTSC bottom field first */
-+				dprintk(1, "%s() Creating NTSC risc\n",
-+					__FUNCTION__);
-+				line0_offset = buf->bpl;
-+				line1_offset = 0;
-+			} else {
-+				/* All other formats are top field first */
-+				dprintk(1, "%s() Creating PAL/SECAM risc\n",
-+					__FUNCTION__);
-+				line0_offset = 0;
-+				line1_offset = buf->bpl;
-+			}
-+			cx23885_risc_buffer(dev->pci, &buf->risc,
-+					dma->sglist, line0_offset,
-+					line1_offset,
-+					buf->bpl, buf->bpl,
-+					buf->vb.height >> 1);
-+			break;
-+		case V4L2_FIELD_SEQ_TB:
-+			cx23885_risc_buffer(dev->pci, &buf->risc,
-+					 dma->sglist,
-+					 0, buf->bpl * (buf->vb.height >> 1),
-+					 buf->bpl, 0,
-+					 buf->vb.height >> 1);
-+			break;
-+		case V4L2_FIELD_SEQ_BT:
-+			cx23885_risc_buffer(dev->pci, &buf->risc,
-+					 dma->sglist,
-+					 buf->bpl * (buf->vb.height >> 1), 0,
-+					 buf->bpl, 0,
-+					 buf->vb.height >> 1);
-+			break;
-+		default:
-+			BUG();
-+		}
-+	}
-+	dprintk(2, "[%p/%d] buffer_prep - %dx%d %dbpp \"%s\" - dma=0x%08lx\n",
-+		buf, buf->vb.i,
-+		fh->width, fh->height, fh->fmt->depth, fh->fmt->name,
-+		(unsigned long)buf->risc.dma);
-+
-+	buf->vb.state = VIDEOBUF_PREPARED;
-+	return 0;
++	struct em28xx    *dev = fh->dev;
 +
-+ fail:
-+	cx23885_free_buffer(q, buf);
-+	return rc;
++	mutex_lock(&dev->lock);
++	fh->stream_on = 0;
++	dev->stream_on = 0;
++	mutex_unlock(&dev->lock);
 +}
 +
-+static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
++/*
++ * em28xx_vm_open()
++ */
++static void em28xx_vm_open(struct vm_area_struct *vma)
 +{
-+	struct cx23885_buffer   *buf = container_of(vb,
-+		struct cx23885_buffer, vb);
-+	struct cx23885_buffer   *prev;
-+	struct cx23885_fh       *fh   = vq->priv_data;
-+	struct cx23885_dev      *dev  = fh->dev;
-+	struct cx23885_dmaqueue *q    = &dev->vidq;
-+
-+	/* add jump to stopper */
-+	buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
-+	buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma);
-+	buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */
-+
-+	if (!list_empty(&q->queued)) {
-+		list_add_tail(&buf->vb.queue, &q->queued);
-+		buf->vb.state = VIDEOBUF_QUEUED;
-+		dprintk(2, "[%p/%d] buffer_queue - append to queued\n",
-+			buf, buf->vb.i);
-+
-+	} else if (list_empty(&q->active)) {
-+		list_add_tail(&buf->vb.queue, &q->active);
-+		cx23885_start_video_dma(dev, q, buf);
-+		buf->vb.state = VIDEOBUF_ACTIVE;
-+		buf->count    = q->count++;
-+		mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
-+		dprintk(2, "[%p/%d] buffer_queue - first active\n",
-+			buf, buf->vb.i);
-+
-+	} else {
-+		prev = list_entry(q->active.prev, struct cx23885_buffer,
-+			vb.queue);
-+		if (prev->vb.width  == buf->vb.width  &&
-+		    prev->vb.height == buf->vb.height &&
-+		    prev->fmt       == buf->fmt) {
-+			list_add_tail(&buf->vb.queue, &q->active);
-+			buf->vb.state = VIDEOBUF_ACTIVE;
-+			buf->count    = q->count++;
-+			prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
-+			/* 64 bit bits 63-32 */
-+			prev->risc.jmp[2] = cpu_to_le32(0);
-+			dprintk(2, "[%p/%d] buffer_queue - append to active\n",
-+				buf, buf->vb.i);
-+
-+		} else {
-+			list_add_tail(&buf->vb.queue, &q->queued);
-+			buf->vb.state = VIDEOBUF_QUEUED;
-+			dprintk(2, "[%p/%d] buffer_queue - first queued\n",
-+				buf, buf->vb.i);
-+		}
-+	}
++	struct em28xx_frame_t *f = vma->vm_private_data;
++	f->vma_use_count++;
 +}
 +
-+static void buffer_release(struct videobuf_queue *q,
-+	struct videobuf_buffer *vb)
++/*
++ * em28xx_vm_close()
++ */
++static void em28xx_vm_close(struct vm_area_struct *vma)
 +{
-+	struct cx23885_buffer *buf = container_of(vb,
-+		struct cx23885_buffer, vb);
++	/* NOTE: buffers are not freed here */
++	struct em28xx_frame_t *f = vma->vm_private_data;
 +
-+	cx23885_free_buffer(q, buf);
++	if (f->vma_use_count)
++		f->vma_use_count--;
 +}
 +
-+static struct videobuf_queue_ops cx23885_video_qops = {
-+	.buf_setup    = buffer_setup,
-+	.buf_prepare  = buffer_prepare,
-+	.buf_queue    = buffer_queue,
-+	.buf_release  = buffer_release,
++static struct vm_operations_struct em28xx_vm_ops = {
++	.open = em28xx_vm_open,
++	.close = em28xx_vm_close,
 +};
 +
-+static struct videobuf_queue *get_queue(struct cx23885_fh *fh)
++
++/*
++ * em28xx_get_ctrl()
++ * return the current saturation, brightness or contrast, mute state
++ */
++static int em28xx_get_ctrl(struct em28xx *dev, struct v4l2_control *ctrl)
 +{
-+	switch (fh->type) {
-+	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-+		return &fh->vidq;
-+	case V4L2_BUF_TYPE_VBI_CAPTURE:
-+		return &fh->vbiq;
++	switch (ctrl->id) {
++	case V4L2_CID_AUDIO_MUTE:
++		ctrl->value = dev->mute;
++		return 0;
++	case V4L2_CID_AUDIO_VOLUME:
++		ctrl->value = dev->volume;
++		return 0;
 +	default:
-+		BUG();
-+		return NULL;
++		return -EINVAL;
 +	}
 +}
 +
-+static int get_resource(struct cx23885_fh *fh)
++/*
++ * em28xx_set_ctrl()
++ * mute or set new saturation, brightness or contrast
++ */
++static int em28xx_set_ctrl(struct em28xx *dev, const struct v4l2_control *ctrl)
 +{
-+	switch (fh->type) {
-+	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-+		return RESOURCE_VIDEO;
-+	case V4L2_BUF_TYPE_VBI_CAPTURE:
-+		return RESOURCE_VBI;
-+	default:
-+		BUG();
++	switch (ctrl->id) {
++	case V4L2_CID_AUDIO_MUTE:
++		if (ctrl->value != dev->mute) {
++			dev->mute = ctrl->value;
++			return em28xx_audio_analog_set(dev);
++		}
 +		return 0;
++	case V4L2_CID_AUDIO_VOLUME:
++		dev->volume = ctrl->value;
++		return em28xx_audio_analog_set(dev);
++	default:
++		return -EINVAL;
 +	}
 +}
 +
-+static int video_open(struct inode *inode, struct file *file)
++/*
++ * em28xx_stream_interrupt()
++ * stops streaming
++ */
++static int em28xx_stream_interrupt(struct em28xx *dev)
 +{
-+	int minor = iminor(inode);
-+	struct cx23885_dev *h, *dev = NULL;
-+	struct cx23885_fh *fh;
-+	struct list_head *list;
-+	enum v4l2_buf_type type = 0;
-+	int radio = 0;
-+
-+	list_for_each(list, &cx23885_devlist) {
-+		h = list_entry(list, struct cx23885_dev, devlist);
-+		if (h->video_dev->minor == minor) {
-+			dev  = h;
-+			type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-+		}
-+		if (h->vbi_dev &&
-+		   h->vbi_dev->minor == minor) {
-+			dev  = h;
-+			type = V4L2_BUF_TYPE_VBI_CAPTURE;
-+		}
-+		if (h->radio_dev &&
-+		    h->radio_dev->minor == minor) {
-+			radio = 1;
-+			dev   = h;
-+		}
-+	}
-+	if (NULL == dev)
-+		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)
-+		return -ENOMEM;
-+	file->private_data = fh;
-+	fh->dev      = dev;
-+	fh->radio    = radio;
-+	fh->type     = type;
-+	fh->width    = 320;
-+	fh->height   = 240;
-+	fh->fmt      = format_by_fourcc(V4L2_PIX_FMT_BGR24);
++	int rc = 0;
 +
-+	videobuf_queue_pci_init(&fh->vidq, &cx23885_video_qops,
-+			    dev->pci, &dev->slock,
-+			    V4L2_BUF_TYPE_VIDEO_CAPTURE,
-+			    V4L2_FIELD_INTERLACED,
-+			    sizeof(struct cx23885_buffer),
-+			    fh);
++	/* stop reading from the device */
 +
-+	dprintk(1, "post videobuf_queue_init()\n");
++	dev->stream = STREAM_INTERRUPT;
++	rc = wait_event_timeout(dev->wait_stream,
++				(dev->stream == STREAM_OFF) ||
++				(dev->state & DEV_DISCONNECTED),
++				EM28XX_URB_TIMEOUT);
 +
++	if (rc) {
++		dev->state |= DEV_MISCONFIGURED;
++		em28xx_videodbg("device is misconfigured; close and "
++			"open /dev/video%d again\n",
++				dev->vdev->minor-MINOR_VFL_TYPE_GRABBER_MIN);
++		return rc;
++	}
 +
 +	return 0;
 +}
 +
-+static ssize_t video_read(struct file *file, char __user *data,
-+	size_t count, loff_t *ppos)
-+{
-+	struct cx23885_fh *fh = file->private_data;
-+
-+	switch (fh->type) {
-+	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-+		if (res_locked(fh->dev, RESOURCE_VIDEO))
-+			return -EBUSY;
-+		return videobuf_read_one(&fh->vidq, data, count, ppos,
-+					 file->f_flags & O_NONBLOCK);
-+	case V4L2_BUF_TYPE_VBI_CAPTURE:
-+		if (!res_get(fh->dev, fh, RESOURCE_VBI))
-+			return -EBUSY;
-+		return videobuf_read_stream(&fh->vbiq, data, count, ppos, 1,
-+					    file->f_flags & O_NONBLOCK);
-+	default:
-+		BUG();
-+		return 0;
-+	}
-+}
 +
-+static unsigned int video_poll(struct file *file,
-+	struct poll_table_struct *wait)
++static int check_dev(struct em28xx *dev)
 +{
-+	struct cx23885_fh *fh = file->private_data;
-+	struct cx23885_buffer *buf;
-+
-+	if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) {
-+		if (!res_get(fh->dev, fh, RESOURCE_VBI))
-+			return POLLERR;
-+		return videobuf_poll_stream(file, &fh->vbiq, wait);
++	if (dev->state & DEV_DISCONNECTED) {
++		em28xx_errdev("v4l2 ioctl: device not present\n");
++		return -ENODEV;
 +	}
 +
-+	if (res_check(fh, RESOURCE_VIDEO)) {
-+		/* streaming capture */
-+		if (list_empty(&fh->vidq.stream))
-+			return POLLERR;
-+		buf = list_entry(fh->vidq.stream.next,
-+			struct cx23885_buffer, vb.stream);
-+	} else {
-+		/* read() capture */
-+		buf = (struct cx23885_buffer *)fh->vidq.read_buf;
-+		if (NULL == buf)
-+			return POLLERR;
++	if (dev->state & DEV_MISCONFIGURED) {
++		em28xx_errdev("v4l2 ioctl: device is misconfigured; "
++			      "close and open it again\n");
++		return -EIO;
 +	}
-+	poll_wait(file, &buf->vb.done, wait);
-+	if (buf->vb.state == VIDEOBUF_DONE ||
-+	    buf->vb.state == VIDEOBUF_ERROR)
-+		return POLLIN|POLLRDNORM;
 +	return 0;
 +}
 +
-+static int video_release(struct inode *inode, struct file *file)
++static void get_scale(struct em28xx *dev,
++			unsigned int width, unsigned int height,
++			unsigned int *hscale, unsigned int *vscale)
 +{
-+	struct cx23885_fh *fh = file->private_data;
-+	struct cx23885_dev *dev = fh->dev;
-+
-+	/* turn off overlay */
-+	if (res_check(fh, RESOURCE_OVERLAY)) {
-+		/* FIXME */
-+		res_free(dev, fh, RESOURCE_OVERLAY);
-+	}
-+
-+	/* stop video capture */
-+	if (res_check(fh, RESOURCE_VIDEO)) {
-+		videobuf_queue_cancel(&fh->vidq);
-+		res_free(dev, fh, RESOURCE_VIDEO);
-+	}
-+	if (fh->vidq.read_buf) {
-+		buffer_release(&fh->vidq, fh->vidq.read_buf);
-+		kfree(fh->vidq.read_buf);
-+	}
-+
-+	/* stop vbi capture */
-+	if (res_check(fh, RESOURCE_VBI)) {
-+		if (fh->vbiq.streaming)
-+			videobuf_streamoff(&fh->vbiq);
-+		if (fh->vbiq.reading)
-+			videobuf_read_stop(&fh->vbiq);
-+		res_free(dev, fh, RESOURCE_VBI);
-+	}
-+
-+	videobuf_mmap_free(&fh->vidq);
-+	file->private_data = NULL;
-+	kfree(fh);
++	unsigned int          maxw   = norm_maxw(dev);
++	unsigned int          maxh   = norm_maxh(dev);
 +
-+	/* We are not putting the tuner to sleep here on exit, because
-+	 * we want to use the mpeg encoder in another session to capture
-+	 * tuner video. Closing this will result in no video to the encoder.
-+	 */
++	*hscale = (((unsigned long)maxw) << 12) / width - 4096L;
++	if (*hscale >= 0x4000)
++		*hscale = 0x3fff;
 +
-+	return 0;
++	*vscale = (((unsigned long)maxh) << 12) / height - 4096L;
++	if (*vscale >= 0x4000)
++		*vscale = 0x3fff;
 +}
 +
-+static int video_mmap(struct file *file, struct vm_area_struct *vma)
++/* ------------------------------------------------------------------
++	IOCTL vidioc handling
++   ------------------------------------------------------------------*/
++
++static int vidioc_g_fmt_cap(struct file *file, void *priv,
++					struct v4l2_format *f)
 +{
-+	struct cx23885_fh *fh = file->private_data;
++	struct em28xx_fh      *fh  = priv;
++	struct em28xx         *dev = fh->dev;
 +
-+	return videobuf_mmap_mapper(get_queue(fh), vma);
-+}
++	mutex_lock(&dev->lock);
 +
-+/* ------------------------------------------------------------------ */
-+/* VIDEO CTRL IOCTLS                                                  */
++	f->fmt.pix.width = dev->width;
++	f->fmt.pix.height = dev->height;
++	f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
++	f->fmt.pix.bytesperline = dev->bytesperline;
++	f->fmt.pix.sizeimage = dev->frame_size;
++	f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
 +
-+int cx23885_get_control(struct cx23885_dev *dev, struct v4l2_control *ctl)
-+{
-+	dprintk(1, "%s() calling cx25840(VIDIOC_G_CTRL)\n", __FUNCTION__);
-+	cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_G_CTRL, ctl);
-+	return 0;
-+}
-+EXPORT_SYMBOL(cx23885_get_control);
++	/* FIXME: TOP? NONE? BOTTOM? ALTENATE? */
++	f->fmt.pix.field = dev->interlaced ?
++			   V4L2_FIELD_INTERLACED : V4L2_FIELD_TOP;
 +
-+int cx23885_set_control(struct cx23885_dev *dev, struct v4l2_control *ctl)
-+{
-+	dprintk(1, "%s() calling cx25840(VIDIOC_S_CTRL)"
-+		" (disabled - no action)\n", __FUNCTION__);
++	mutex_unlock(&dev->lock);
 +	return 0;
 +}
-+EXPORT_SYMBOL(cx23885_set_control);
 +
-+static void init_controls(struct cx23885_dev *dev)
++static int vidioc_try_fmt_cap(struct file *file, void *priv,
++			struct v4l2_format *f)
 +{
-+	struct v4l2_control ctrl;
-+	int i;
++	struct em28xx_fh      *fh    = priv;
++	struct em28xx         *dev   = fh->dev;
++	int                   width  = f->fmt.pix.width;
++	int                   height = f->fmt.pix.height;
++	unsigned int          maxw   = norm_maxw(dev);
++	unsigned int          maxh   = norm_maxh(dev);
++	unsigned int          hscale, vscale;
 +
-+	for (i = 0; i < CX23885_CTLS; i++) {
-+		ctrl.id = cx23885_ctls[i].v.id;
-+		ctrl.value = cx23885_ctls[i].v.default_value;
++	/* width must even because of the YUYV format
++	   height must be even because of interlacing */
++	height &= 0xfffe;
++	width &= 0xfffe;
 +
-+		cx23885_set_control(dev, &ctrl);
++	if (height < 32)
++		height = 32;
++	if (height > maxh)
++		height = maxh;
++	if (width < 48)
++		width = 48;
++	if (width > maxw)
++		width = maxw;
++
++	mutex_lock(&dev->lock);
++
++	if (dev->is_em2800) {
++		/* the em2800 can only scale down to 50% */
++		if (height % (maxh / 2))
++			height = maxh;
++		if (width % (maxw / 2))
++			width = maxw;
++		/* according to empiatech support */
++		/* the MaxPacketSize is to small to support */
++		/* framesizes larger than 640x480 @ 30 fps */
++		/* or 640x576 @ 25 fps. As this would cut */
++		/* of a part of the image we prefer */
++		/* 360x576 or 360x480 for now */
++		if (width == maxw && height == maxh)
++			width /= 2;
 +	}
-+}
 +
-+/* ------------------------------------------------------------------ */
-+/* VIDEO IOCTLS                                                       */
++	get_scale(dev, width, height, &hscale, &vscale);
 +
-+static int vidioc_g_fmt_cap(struct file *file, void *priv,
-+	struct v4l2_format *f)
-+{
-+	struct cx23885_fh *fh   = priv;
++	width = (((unsigned long)maxw) << 12) / (hscale + 4096L);
++	height = (((unsigned long)maxh) << 12) / (vscale + 4096L);
 +
-+	f->fmt.pix.width        = fh->width;
-+	f->fmt.pix.height       = fh->height;
-+	f->fmt.pix.field        = fh->vidq.field;
-+	f->fmt.pix.pixelformat  = fh->fmt->fourcc;
-+	f->fmt.pix.bytesperline =
-+		(f->fmt.pix.width * fh->fmt->depth) >> 3;
-+	f->fmt.pix.sizeimage =
-+		f->fmt.pix.height * f->fmt.pix.bytesperline;
++	f->fmt.pix.width = width;
++	f->fmt.pix.height = height;
++	f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
++	f->fmt.pix.bytesperline = width * 2;
++	f->fmt.pix.sizeimage = width * 2 * height;
++	f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
++	f->fmt.pix.field = V4L2_FIELD_INTERLACED;
 +
++	mutex_unlock(&dev->lock);
 +	return 0;
 +}
 +
-+static int vidioc_try_fmt_cap(struct file *file, void *priv,
-+	struct v4l2_format *f)
++static int vidioc_s_fmt_cap(struct file *file, void *priv,
++			struct v4l2_format *f)
 +{
-+	struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
-+	struct cx23885_fmt *fmt;
-+	enum v4l2_field   field;
-+	unsigned int      maxw, maxh;
++	struct em28xx_fh      *fh  = priv;
++	struct em28xx         *dev = fh->dev;
++	int                   rc, i;
 +
-+	fmt = format_by_fourcc(f->fmt.pix.pixelformat);
-+	if (NULL == fmt)
-+		return -EINVAL;
++	rc = check_dev(dev);
++	if (rc < 0)
++		return rc;
 +
-+	field = f->fmt.pix.field;
-+	maxw  = norm_maxw(dev->tvnorm);
-+	maxh  = norm_maxh(dev->tvnorm);
++	vidioc_try_fmt_cap(file, priv, f);
 +
-+	if (V4L2_FIELD_ANY == field) {
-+		field = (f->fmt.pix.height > maxh/2)
-+			? V4L2_FIELD_INTERLACED
-+			: V4L2_FIELD_BOTTOM;
-+	}
++	mutex_lock(&dev->lock);
 +
-+	switch (field) {
-+	case V4L2_FIELD_TOP:
-+	case V4L2_FIELD_BOTTOM:
-+		maxh = maxh / 2;
-+		break;
-+	case V4L2_FIELD_INTERLACED:
-+		break;
-+	default:
-+		return -EINVAL;
++	for (i = 0; i < dev->num_frames; i++)
++		if (dev->frame[i].vma_use_count) {
++			em28xx_videodbg("VIDIOC_S_FMT failed. "
++					"Unmap the buffers first.\n");
++			rc = -EINVAL;
++			goto err;
++		}
++
++	/* stop io in case it is already in progress */
++	if (dev->stream == STREAM_ON) {
++		em28xx_videodbg("VIDIOC_SET_FMT: interrupting stream\n");
++		rc = em28xx_stream_interrupt(dev);
++		if (rc < 0)
++			goto err;
 +	}
 +
-+	f->fmt.pix.field = field;
-+	if (f->fmt.pix.height < 32)
-+		f->fmt.pix.height = 32;
-+	if (f->fmt.pix.height > maxh)
-+		f->fmt.pix.height = maxh;
-+	if (f->fmt.pix.width < 48)
-+		f->fmt.pix.width = 48;
-+	if (f->fmt.pix.width > maxw)
-+		f->fmt.pix.width = maxw;
-+	f->fmt.pix.width &= ~0x03;
-+	f->fmt.pix.bytesperline =
-+		(f->fmt.pix.width * fmt->depth) >> 3;
-+	f->fmt.pix.sizeimage =
-+		f->fmt.pix.height * f->fmt.pix.bytesperline;
++	em28xx_release_buffers(dev);
++	dev->io = IO_NONE;
 +
-+	return 0;
++	/* set new image size */
++	dev->width = f->fmt.pix.width;
++	dev->height = f->fmt.pix.height;
++	dev->frame_size = dev->width * dev->height * 2;
++	dev->field_size = dev->frame_size >> 1;
++	dev->bytesperline = dev->width * 2;
++	get_scale(dev, dev->width, dev->height, &dev->hscale, &dev->vscale);
++
++	/* FIXME: This is really weird! Why capture is starting with
++	   this ioctl ???
++	 */
++	em28xx_uninit_isoc(dev);
++	em28xx_set_alternate(dev);
++	em28xx_capture_start(dev, 1);
++	em28xx_resolution_set(dev);
++	em28xx_init_isoc(dev);
++	rc = 0;
++
++err:
++	mutex_unlock(&dev->lock);
++	return rc;
 +}
 +
-+static int vidioc_s_fmt_cap(struct file *file, void *priv,
-+	struct v4l2_format *f)
++static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *norm)
 +{
-+	struct cx23885_fh *fh = priv;
-+	struct cx23885_dev *dev  = ((struct cx23885_fh *)priv)->dev;
-+	int err;
++	struct em28xx_fh   *fh  = priv;
++	struct em28xx      *dev = fh->dev;
++	struct v4l2_format f;
++	int                rc;
 +
-+	dprintk(2, "%s()\n", __FUNCTION__);
-+	err = vidioc_try_fmt_cap(file, priv, f);
++	rc = check_dev(dev);
++	if (rc < 0)
++		return rc;
 +
-+	if (0 != err)
-+		return err;
-+	fh->fmt        = format_by_fourcc(f->fmt.pix.pixelformat);
-+	fh->width      = f->fmt.pix.width;
-+	fh->height     = f->fmt.pix.height;
-+	fh->vidq.field = f->fmt.pix.field;
-+	dprintk(2, "%s() width=%d height=%d field=%d\n", __FUNCTION__,
-+		fh->width, fh->height, fh->vidq.field);
-+	cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_S_FMT, f);
-+	return 0;
-+}
++	mutex_lock(&dev->lock);
++	dev->norm = *norm;
++	mutex_unlock(&dev->lock);
 +
-+static int vidioc_querycap(struct file *file, void  *priv,
-+	struct v4l2_capability *cap)
-+{
-+	struct cx23885_dev *dev  = ((struct cx23885_fh *)priv)->dev;
++	/* Adjusts width/height, if needed */
++	f.fmt.pix.width = dev->width;
++	f.fmt.pix.height = dev->height;
++	vidioc_try_fmt_cap(file, priv, &f);
 +
-+	strcpy(cap->driver, "cx23885");
-+	strlcpy(cap->card, cx23885_boards[dev->board].name,
-+		sizeof(cap->card));
-+	sprintf(cap->bus_info, "PCIe:%s", pci_name(dev->pci));
-+	cap->version = CX23885_VERSION_CODE;
-+	cap->capabilities =
-+		V4L2_CAP_VIDEO_CAPTURE |
-+		V4L2_CAP_READWRITE     |
-+		V4L2_CAP_STREAMING     |
-+		V4L2_CAP_VBI_CAPTURE;
-+	if (UNSET != dev->tuner_type)
-+		cap->capabilities |= V4L2_CAP_TUNER;
-+	return 0;
-+}
++	mutex_lock(&dev->lock);
 +
-+static int vidioc_enum_fmt_cap(struct file *file, void  *priv,
-+	struct v4l2_fmtdesc *f)
-+{
-+	if (unlikely(f->index >= ARRAY_SIZE(formats)))
-+		return -EINVAL;
++	/* set new image size */
++	dev->width = f.fmt.pix.width;
++	dev->height = f.fmt.pix.height;
++	dev->frame_size = dev->width * dev->height * 2;
++	dev->field_size = dev->frame_size >> 1;
++	dev->bytesperline = dev->width * 2;
++	get_scale(dev, dev->width, dev->height, &dev->hscale, &dev->vscale);
 +
-+	strlcpy(f->description, formats[f->index].name,
-+		sizeof(f->description));
-+	f->pixelformat = formats[f->index].fourcc;
++	em28xx_resolution_set(dev);
++	em28xx_i2c_call_clients(dev, VIDIOC_S_STD, &dev->norm);
 +
++	mutex_unlock(&dev->lock);
 +	return 0;
 +}
 +
-+#ifdef CONFIG_VIDEO_V4L1_COMPAT
-+static int vidiocgmbuf(struct file *file, void *priv,
-+	struct video_mbuf *mbuf)
++static const char *iname[] = {
++	[EM28XX_VMUX_COMPOSITE1] = "Composite1",
++	[EM28XX_VMUX_COMPOSITE2] = "Composite2",
++	[EM28XX_VMUX_COMPOSITE3] = "Composite3",
++	[EM28XX_VMUX_COMPOSITE4] = "Composite4",
++	[EM28XX_VMUX_SVIDEO]     = "S-Video",
++	[EM28XX_VMUX_TELEVISION] = "Television",
++	[EM28XX_VMUX_CABLE]      = "Cable TV",
++	[EM28XX_VMUX_DVB]        = "DVB",
++	[EM28XX_VMUX_DEBUG]      = "for debug only",
++};
++
++static int vidioc_enum_input(struct file *file, void *priv,
++				struct v4l2_input *i)
 +{
-+	struct cx23885_fh *fh = priv;
-+	struct videobuf_queue *q;
-+	struct v4l2_requestbuffers req;
-+	unsigned int i;
-+	int err;
++	struct em28xx_fh   *fh  = priv;
++	struct em28xx      *dev = fh->dev;
++	unsigned int       n;
 +
-+	q = get_queue(fh);
-+	memset(&req, 0, sizeof(req));
-+	req.type   = q->type;
-+	req.count  = 8;
-+	req.memory = V4L2_MEMORY_MMAP;
-+	err = videobuf_reqbufs(q, &req);
-+	if (err < 0)
-+		return err;
++	n = i->index;
++	if (n >= MAX_EM28XX_INPUT)
++		return -EINVAL;
++	if (0 == INPUT(n)->type)
++		return -EINVAL;
 +
-+	mbuf->frames = req.count;
-+	mbuf->size   = 0;
-+	for (i = 0; i < mbuf->frames; i++) {
-+		mbuf->offsets[i]  = q->bufs[i]->boff;
-+		mbuf->size       += q->bufs[i]->bsize;
-+	}
-+	return 0;
-+}
-+#endif
++	i->index = n;
++	i->type = V4L2_INPUT_TYPE_CAMERA;
 +
-+static int vidioc_reqbufs(struct file *file, void *priv,
-+	struct v4l2_requestbuffers *p)
-+{
-+	struct cx23885_fh *fh = priv;
-+	return (videobuf_reqbufs(get_queue(fh), p));
-+}
++	strcpy(i->name, iname[INPUT(n)->type]);
 +
-+static int vidioc_querybuf(struct file *file, void *priv,
-+	struct v4l2_buffer *p)
-+{
-+	struct cx23885_fh *fh = priv;
-+	return (videobuf_querybuf(get_queue(fh), p));
-+}
++	if ((EM28XX_VMUX_TELEVISION == INPUT(n)->type) ||
++		(EM28XX_VMUX_CABLE == INPUT(n)->type))
++		i->type = V4L2_INPUT_TYPE_TUNER;
 +
-+static int vidioc_qbuf(struct file *file, void *priv,
-+	struct v4l2_buffer *p)
-+{
-+	struct cx23885_fh *fh = priv;
-+	return (videobuf_qbuf(get_queue(fh), p));
-+}
++	i->std = dev->vdev->tvnorms;
 +
-+static int vidioc_dqbuf(struct file *file, void *priv,
-+	struct v4l2_buffer *p)
-+{
-+	struct cx23885_fh *fh = priv;
-+	return (videobuf_dqbuf(get_queue(fh), p,
-+				file->f_flags & O_NONBLOCK));
++	return 0;
 +}
 +
-+static int vidioc_streamon(struct file *file, void *priv,
-+	enum v4l2_buf_type i)
++static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
 +{
-+	struct cx23885_fh *fh = priv;
-+	struct cx23885_dev *dev = fh->dev;
-+	dprintk(1, "%s()\n", __FUNCTION__);
++	struct em28xx_fh   *fh  = priv;
++	struct em28xx      *dev = fh->dev;
 +
-+	if (unlikely(fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE))
-+		return -EINVAL;
-+	if (unlikely(i != fh->type))
-+		return -EINVAL;
++	*i = dev->ctl_input;
 +
-+	if (unlikely(!res_get(dev, fh, get_resource(fh))))
-+		return -EBUSY;
-+	return videobuf_streamon(get_queue(fh));
++	return 0;
 +}
 +
-+static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
++static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
 +{
-+	struct cx23885_fh *fh = priv;
-+	struct cx23885_dev *dev = fh->dev;
-+	int err, res;
-+	dprintk(1, "%s()\n", __FUNCTION__);
++	struct em28xx_fh   *fh  = priv;
++	struct em28xx      *dev = fh->dev;
++	int                rc;
 +
-+	if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
++	rc = check_dev(dev);
++	if (rc < 0)
++		return rc;
++
++	if (i >= MAX_EM28XX_INPUT)
 +		return -EINVAL;
-+	if (i != fh->type)
++	if (0 == INPUT(i)->type)
 +		return -EINVAL;
 +
-+	res = get_resource(fh);
-+	err = videobuf_streamoff(get_queue(fh));
-+	if (err < 0)
-+		return err;
-+	res_free(dev, fh, res);
-+	return 0;
-+}
++	mutex_lock(&dev->lock);
 +
-+static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *tvnorms)
-+{
-+	struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
-+	dprintk(1, "%s()\n", __FUNCTION__);
++	video_mux(dev, i);
 +
-+	mutex_lock(&dev->lock);
-+	cx23885_set_tvnorm(dev, *tvnorms);
 +	mutex_unlock(&dev->lock);
-+
 +	return 0;
 +}
 +
-+int cx23885_enum_input(struct cx23885_dev *dev, struct v4l2_input *i)
++static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
 +{
-+	static const char *iname[] = {
-+		[CX23885_VMUX_COMPOSITE1] = "Composite1",
-+		[CX23885_VMUX_COMPOSITE2] = "Composite2",
-+		[CX23885_VMUX_COMPOSITE3] = "Composite3",
-+		[CX23885_VMUX_COMPOSITE4] = "Composite4",
-+		[CX23885_VMUX_SVIDEO]     = "S-Video",
-+		[CX23885_VMUX_TELEVISION] = "Television",
-+		[CX23885_VMUX_CABLE]      = "Cable TV",
-+		[CX23885_VMUX_DVB]        = "DVB",
-+		[CX23885_VMUX_DEBUG]      = "for debug only",
-+	};
-+	unsigned int n;
-+	dprintk(1, "%s()\n", __FUNCTION__);
++	struct em28xx_fh   *fh    = priv;
++	struct em28xx      *dev   = fh->dev;
++	unsigned int        index = a->index;
 +
-+	n = i->index;
-+	if (n >= 4)
++	if (a->index > 1)
 +		return -EINVAL;
 +
-+	if (0 == INPUT(n)->type)
-+		return -EINVAL;
++	index = dev->ctl_ainput;
++
++	if (index == 0) {
++		strcpy(a->name, "Television");
+ 	} else {
+-		switch (dev->ctl_ainput) {
+-			case 0:
+-				ainput = EM28XX_AUDIO_SRC_TUNER;
++		strcpy(a->name, "Line In");
++	}
++	a->capability = V4L2_AUDCAP_STEREO;
++	a->index = index;
 +
-+	memset(i, 0, sizeof(*i));
-+	i->index = n;
-+	i->type  = V4L2_INPUT_TYPE_CAMERA;
-+	strcpy(i->name, iname[INPUT(n)->type]);
-+	if ((CX23885_VMUX_TELEVISION == INPUT(n)->type) ||
-+		(CX23885_VMUX_CABLE == INPUT(n)->type))
-+		i->type = V4L2_INPUT_TYPE_TUNER;
-+		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)
++static int vidioc_s_audio(struct file *file, void *priv, struct v4l2_audio *a)
 +{
-+	struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
-+	dprintk(1, "%s()\n", __FUNCTION__);
-+	return cx23885_enum_input(dev, i);
-+}
++	struct em28xx_fh   *fh  = priv;
++	struct em28xx      *dev = fh->dev;
 +
-+static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
-+{
-+	struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
++	if (a->index != dev->ctl_ainput)
++		return -EINVAL;
 +
-+	*i = dev->input;
-+	dprintk(1, "%s() returns %d\n", __FUNCTION__, *i);
 +	return 0;
 +}
 +
-+static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
++static int vidioc_queryctrl(struct file *file, void *priv,
++				struct v4l2_queryctrl *qc)
 +{
-+	struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
++	struct em28xx_fh      *fh  = priv;
++	struct em28xx         *dev = fh->dev;
++	int                   id  = qc->id;
++	int                   i;
++	int                   rc;
 +
-+	dprintk(1, "%s(%d)\n", __FUNCTION__, i);
++	rc = check_dev(dev);
++	if (rc < 0)
++		return rc;
 +
-+	if (i >= 4) {
-+		dprintk(1, "%s() -EINVAL\n", __FUNCTION__);
-+		return -EINVAL;
-+	}
++	memset(qc, 0, sizeof(*qc));
++
++	qc->id = id;
 +
++	if (!dev->has_msp34xx) {
++		for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) {
++			if (qc->id && qc->id == em28xx_qctrl[i].id) {
++				memcpy(qc, &(em28xx_qctrl[i]), sizeof(*qc));
++				return 0;
++			}
++		}
++	}
 +	mutex_lock(&dev->lock);
-+	cx23885_video_mux(dev, i);
++	em28xx_i2c_call_clients(dev, VIDIOC_QUERYCTRL, qc);
 +	mutex_unlock(&dev->lock);
-+	return 0;
-+}
 +
-+static int vidioc_queryctrl(struct file *file, void *priv,
-+				struct v4l2_queryctrl *qctrl)
-+{
-+	qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id);
-+	if (unlikely(qctrl->id == 0))
++	if (qc->type)
++		return 0;
++	else
 +		return -EINVAL;
-+	return cx23885_ctrl_query(qctrl);
 +}
 +
 +static int vidioc_g_ctrl(struct file *file, void *priv,
-+				struct v4l2_control *ctl)
++				struct v4l2_control *ctrl)
 +{
-+	struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
++	struct em28xx_fh      *fh  = priv;
++	struct em28xx         *dev = fh->dev;
++	int                   rc;
++
++	rc = check_dev(dev);
++	if (rc < 0)
++		return rc;
++	mutex_lock(&dev->lock);
++
++	if (!dev->has_msp34xx)
++		rc = em28xx_get_ctrl(dev, ctrl);
++	else
++		rc = -EINVAL;
++
++	if (rc == -EINVAL) {
++		em28xx_i2c_call_clients(dev, VIDIOC_G_CTRL, ctrl);
++		rc = 0;
++	}
++
++	mutex_unlock(&dev->lock);
++	return rc;
++}
++
++static int vidioc_s_ctrl(struct file *file, void *priv,
++				struct v4l2_control *ctrl)
++{
++	struct em28xx_fh      *fh  = priv;
++	struct em28xx         *dev = fh->dev;
++	u8                    i;
++	int                   rc;
++
++	rc = check_dev(dev);
++	if (rc < 0)
++		return rc;
++
++	mutex_lock(&dev->lock);
++
++	if (dev->has_msp34xx)
++		em28xx_i2c_call_clients(dev, VIDIOC_S_CTRL, ctrl);
++	else {
++		rc = 1;
++		for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) {
++			if (ctrl->id == em28xx_qctrl[i].id) {
++				if (ctrl->value < em28xx_qctrl[i].minimum ||
++				    ctrl->value > em28xx_qctrl[i].maximum) {
++					rc = -ERANGE;
++					break;
++				}
 +
-+	return cx23885_get_control(dev, ctl);
-+}
++				rc = em28xx_set_ctrl(dev, ctrl);
+ 				break;
+-			default:
+-				ainput = EM28XX_AUDIO_SRC_LINE;
++			}
++		}
++	}
 +
-+static int vidioc_s_ctrl(struct file *file, void *priv,
-+				struct v4l2_control *ctl)
-+{
-+	struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
++	/* Control not found - try to send it to the attached devices */
++	if (rc == 1) {
++		em28xx_i2c_call_clients(dev, VIDIOC_S_CTRL, ctrl);
++		rc = 0;
++	}
 +
-+	return cx23885_set_control(dev, ctl);
++	mutex_unlock(&dev->lock);
++	return rc;
 +}
 +
 +static int vidioc_g_tuner(struct file *file, void *priv,
 +				struct v4l2_tuner *t)
 +{
-+	struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
++	struct em28xx_fh      *fh  = priv;
++	struct em28xx         *dev = fh->dev;
++	int                   rc;
++
++	rc = check_dev(dev);
++	if (rc < 0)
++		return rc;
 +
-+	if (unlikely(UNSET == dev->tuner_type))
-+		return -EINVAL;
 +	if (0 != t->index)
 +		return -EINVAL;
 +
-+	strcpy(t->name, "Television");
-+	t->type       = V4L2_TUNER_ANALOG_TV;
-+	t->capability = V4L2_TUNER_CAP_NORM;
-+	t->rangehigh  = 0xffffffffUL;
-+	t->signal = 0xffff ; /* LOCKED */
++	strcpy(t->name, "Tuner");
++
++	mutex_lock(&dev->lock);
++
++	em28xx_i2c_call_clients(dev, VIDIOC_G_TUNER, t);
++
++	mutex_unlock(&dev->lock);
 +	return 0;
 +}
 +
 +static int vidioc_s_tuner(struct file *file, void *priv,
 +				struct v4l2_tuner *t)
 +{
-+	struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
-+
-+	if (UNSET == dev->tuner_type)
-+		return -EINVAL;
-+	if (0 != t->index)
-+		return -EINVAL;
-+	return 0;
-+}
++	struct em28xx_fh      *fh  = priv;
++	struct em28xx         *dev = fh->dev;
++	int                   rc;
 +
-+static int vidioc_g_frequency(struct file *file, void *priv,
-+				struct v4l2_frequency *f)
-+{
-+	struct cx23885_fh *fh = priv;
-+	struct cx23885_dev *dev = fh->dev;
++	rc = check_dev(dev);
++	if (rc < 0)
++		return rc;
 +
-+	if (unlikely(UNSET == dev->tuner_type))
++	if (0 != t->index)
 +		return -EINVAL;
 +
-+	/* f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; */
-+	f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
-+	f->frequency = dev->freq;
++	mutex_lock(&dev->lock);
 +
-+	cx23885_call_i2c_clients(&dev->i2c_bus[1], VIDIOC_G_FREQUENCY, f);
++	em28xx_i2c_call_clients(dev, VIDIOC_S_TUNER, t);
 +
++	mutex_unlock(&dev->lock);
 +	return 0;
 +}
 +
-+int cx23885_set_freq(struct cx23885_dev *dev, struct v4l2_frequency *f)
++static int vidioc_g_frequency(struct file *file, void *priv,
++				struct v4l2_frequency *f)
 +{
-+	if (unlikely(UNSET == dev->tuner_type))
-+		return -EINVAL;
-+	if (unlikely(f->tuner != 0))
-+		return -EINVAL;
-+
-+	mutex_lock(&dev->lock);
-+	dev->freq = f->frequency;
-+
-+	cx23885_call_i2c_clients(&dev->i2c_bus[1], VIDIOC_S_FREQUENCY, f);
-+
-+	/* When changing channels it is required to reset TVAUDIO */
-+	msleep(10);
++	struct em28xx_fh      *fh  = priv;
++	struct em28xx         *dev = fh->dev;
 +
-+	mutex_unlock(&dev->lock);
++	f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
++	f->frequency = dev->ctl_freq;
 +
 +	return 0;
 +}
-+EXPORT_SYMBOL(cx23885_set_freq);
 +
 +static int vidioc_s_frequency(struct file *file, void *priv,
 +				struct v4l2_frequency *f)
 +{
-+	struct cx23885_fh *fh = priv;
-+	struct cx23885_dev *dev = fh->dev;
++	struct em28xx_fh      *fh  = priv;
++	struct em28xx         *dev = fh->dev;
++	int                   rc;
++
++	rc = check_dev(dev);
++	if (rc < 0)
++		return rc;
++
++	if (0 != f->tuner)
++		return -EINVAL;
 +
 +	if (unlikely(0 == fh->radio && f->type != V4L2_TUNER_ANALOG_TV))
 +		return -EINVAL;
 +	if (unlikely(1 == fh->radio && f->type != V4L2_TUNER_RADIO))
 +		return -EINVAL;
 +
-+	return
-+		cx23885_set_freq(dev, f);
-+}
-+
-+#ifdef CONFIG_VIDEO_ADV_DEBUG
-+static int vidioc_g_register(struct file *file, void *fh,
-+				struct v4l2_register *reg)
-+{
-+	struct cx23885_dev *dev = ((struct cx23885_fh *)fh)->dev;
-+
-+	if (!v4l2_chip_match_host(reg->match_type, reg->match_chip))
-+		return -EINVAL;
++	mutex_lock(&dev->lock);
 +
-+	cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_DBG_G_REGISTER, reg);
++	dev->ctl_freq = f->frequency;
++	em28xx_i2c_call_clients(dev, VIDIOC_S_FREQUENCY, f);
 +
++	mutex_unlock(&dev->lock);
 +	return 0;
 +}
 +
-+static int vidioc_s_register(struct file *file, void *fh,
-+				struct v4l2_register *reg)
++static int vidioc_cropcap(struct file *file, void *priv,
++					struct v4l2_cropcap *cc)
 +{
-+	struct cx23885_dev *dev = ((struct cx23885_fh *)fh)->dev;
++	struct em28xx_fh      *fh  = priv;
++	struct em28xx         *dev = fh->dev;
 +
-+	if (!v4l2_chip_match_host(reg->match_type, reg->match_chip))
++	if (cc->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
 +		return -EINVAL;
 +
-+	cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_DBG_S_REGISTER, reg);
++	cc->bounds.left = 0;
++	cc->bounds.top = 0;
++	cc->bounds.width = dev->width;
++	cc->bounds.height = dev->height;
++	cc->defrect = cc->bounds;
++	cc->pixelaspect.numerator = 54;	/* 4:3 FIXME: remove magic numbers */
++	cc->pixelaspect.denominator = 59;
 +
 +	return 0;
 +}
-+#endif
 +
-+/* ----------------------------------------------------------- */
-+
-+static void cx23885_vid_timeout(unsigned long data)
++static int vidioc_streamon(struct file *file, void *priv,
++					enum v4l2_buf_type type)
 +{
-+	struct cx23885_dev *dev = (struct cx23885_dev *)data;
-+	struct cx23885_dmaqueue *q = &dev->vidq;
-+	struct cx23885_buffer *buf;
-+	unsigned long flags;
-+
-+	cx23885_sram_channel_dump(dev, &dev->sram_channels[SRAM_CH01]);
++	struct em28xx_fh      *fh  = priv;
++	struct em28xx         *dev = fh->dev;
++	int                   rc;
 +
-+	cx_clear(VID_A_DMA_CTL, 0x11);
++	rc = check_dev(dev);
++	if (rc < 0)
++		return rc;
 +
-+	spin_lock_irqsave(&dev->slock, flags);
-+	while (!list_empty(&q->active)) {
-+		buf = list_entry(q->active.next,
-+			struct cx23885_buffer, vb.queue);
-+		list_del(&buf->vb.queue);
-+		buf->vb.state = VIDEOBUF_ERROR;
-+		wake_up(&buf->vb.done);
-+		printk(KERN_ERR "%s/0: [%p/%d] timeout - dma=0x%08lx\n",
-+			dev->name, buf, buf->vb.i,
-+			(unsigned long)buf->risc.dma);
-+	}
-+	cx23885_restart_video_queue(dev, q);
-+	spin_unlock_irqrestore(&dev->slock, flags);
-+}
++	if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || dev->io != IO_MMAP)
++		return -EINVAL;
 +
-+int cx23885_video_irq(struct cx23885_dev *dev, u32 status)
-+{
-+	u32 mask, count;
-+	int handled = 0;
++	if (list_empty(&dev->inqueue))
++		return -EINVAL;
 +
-+	mask   = cx_read(VID_A_INT_MSK);
-+	if (0 == (status & mask))
-+		return handled;
-+	cx_write(VID_A_INT_STAT, status);
++	mutex_lock(&dev->lock);
 +
-+	dprintk(2, "%s() status = 0x%08x\n", __FUNCTION__, status);
-+	/* risc op code error */
-+	if (status & (1 << 16)) {
-+		printk(KERN_WARNING "%s/0: video risc op code error\n",
-+			dev->name);
-+		cx_clear(VID_A_DMA_CTL, 0x11);
-+		cx23885_sram_channel_dump(dev, &dev->sram_channels[SRAM_CH01]);
++	if (unlikely(res_get(fh) < 0)) {
++		mutex_unlock(&dev->lock);
++		return -EBUSY;
 +	}
 +
-+	/* risc1 y */
-+	if (status & 0x01) {
-+		spin_lock(&dev->slock);
-+		count = cx_read(VID_A_GPCNT);
-+		cx23885_video_wakeup(dev, &dev->vidq, count);
-+		spin_unlock(&dev->slock);
-+		handled++;
-+	}
-+	/* risc2 y */
-+	if (status & 0x10) {
-+		dprintk(2, "stopper video\n");
-+		spin_lock(&dev->slock);
-+		cx23885_restart_video_queue(dev, &dev->vidq);
-+		spin_unlock(&dev->slock);
-+		handled++;
-+	}
++	dev->stream = STREAM_ON;	/* FIXME: Start video capture here? */
 +
-+	return handled;
++	mutex_unlock(&dev->lock);
++	return 0;
 +}
 +
-+/* ----------------------------------------------------------- */
-+/* exported stuff                                              */
-+
-+static const struct file_operations video_fops = {
-+	.owner	       = THIS_MODULE,
-+	.open	       = video_open,
-+	.release       = video_release,
-+	.read	       = video_read,
-+	.poll          = video_poll,
-+	.mmap	       = video_mmap,
-+	.ioctl	       = video_ioctl2,
-+	.compat_ioctl  = v4l_compat_ioctl32,
-+	.llseek        = no_llseek,
-+};
++static int vidioc_streamoff(struct file *file, void *priv,
++					enum v4l2_buf_type type)
++{
++	struct em28xx_fh      *fh  = priv;
++	struct em28xx         *dev = fh->dev;
++	int                   rc;
 +
-+static struct video_device cx23885_vbi_template;
-+static struct video_device cx23885_video_template = {
-+	.name                 = "cx23885-video",
-+	.type                 = VID_TYPE_CAPTURE|VID_TYPE_TUNER|VID_TYPE_SCALES,
-+	.fops                 = &video_fops,
-+	.minor                = -1,
-+	.vidioc_querycap      = vidioc_querycap,
-+	.vidioc_enum_fmt_cap  = vidioc_enum_fmt_cap,
-+	.vidioc_g_fmt_cap     = vidioc_g_fmt_cap,
-+	.vidioc_try_fmt_cap   = vidioc_try_fmt_cap,
-+	.vidioc_s_fmt_cap     = vidioc_s_fmt_cap,
-+	.vidioc_g_fmt_vbi     = cx23885_vbi_fmt,
-+	.vidioc_try_fmt_vbi   = cx23885_vbi_fmt,
-+	.vidioc_s_fmt_vbi     = cx23885_vbi_fmt,
-+	.vidioc_reqbufs       = vidioc_reqbufs,
-+	.vidioc_querybuf      = vidioc_querybuf,
-+	.vidioc_qbuf          = vidioc_qbuf,
-+	.vidioc_dqbuf         = vidioc_dqbuf,
-+	.vidioc_s_std         = vidioc_s_std,
-+	.vidioc_enum_input    = vidioc_enum_input,
-+	.vidioc_g_input       = vidioc_g_input,
-+	.vidioc_s_input       = vidioc_s_input,
-+	.vidioc_queryctrl     = vidioc_queryctrl,
-+	.vidioc_g_ctrl        = vidioc_g_ctrl,
-+	.vidioc_s_ctrl        = vidioc_s_ctrl,
-+	.vidioc_streamon      = vidioc_streamon,
-+	.vidioc_streamoff     = vidioc_streamoff,
-+#ifdef CONFIG_VIDEO_V4L1_COMPAT
-+	.vidiocgmbuf          = vidiocgmbuf,
-+#endif
-+	.vidioc_g_tuner       = vidioc_g_tuner,
-+	.vidioc_s_tuner       = vidioc_s_tuner,
-+	.vidioc_g_frequency   = vidioc_g_frequency,
-+	.vidioc_s_frequency   = vidioc_s_frequency,
-+#ifdef CONFIG_VIDEO_ADV_DEBUG
-+	.vidioc_g_register    = vidioc_g_register,
-+	.vidioc_s_register    = vidioc_s_register,
-+#endif
-+	.tvnorms              = CX23885_NORMS,
-+	.current_norm         = V4L2_STD_NTSC_M,
-+};
++	rc = check_dev(dev);
++	if (rc < 0)
++		return rc;
 +
-+static const struct file_operations radio_fops = {
-+	.owner         = THIS_MODULE,
-+	.open          = video_open,
-+	.release       = video_release,
-+	.ioctl         = video_ioctl2,
-+	.compat_ioctl  = v4l_compat_ioctl32,
-+	.llseek        = no_llseek,
-+};
++	if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || dev->io != IO_MMAP)
++		return -EINVAL;
 +
++	mutex_lock(&dev->lock);
 +
-+void cx23885_video_unregister(struct cx23885_dev *dev)
-+{
-+	dprintk(1, "%s()\n", __FUNCTION__);
-+	cx_clear(PCI_INT_MSK, 1);
++	if (dev->stream == STREAM_ON) {
++		em28xx_videodbg("VIDIOC_STREAMOFF: interrupting stream\n");
++		rc = em28xx_stream_interrupt(dev);
++		if (rc < 0) {
++			mutex_unlock(&dev->lock);
++			return rc;
++		}
++	}
 +
-+	if (dev->video_dev) {
-+		if (-1 != dev->video_dev->minor)
-+			video_unregister_device(dev->video_dev);
-+		else
-+			video_device_release(dev->video_dev);
-+		dev->video_dev = NULL;
++	em28xx_empty_framequeues(dev);
 +
-+		btcx_riscmem_free(dev->pci, &dev->vidq.stopper);
-+	}
++	mutex_unlock(&dev->lock);
++	return 0;
 +}
 +
-+int cx23885_video_register(struct cx23885_dev *dev)
++static int vidioc_querycap(struct file *file, void  *priv,
++					struct v4l2_capability *cap)
 +{
-+	int err;
-+
-+	dprintk(1, "%s()\n", __FUNCTION__);
-+	spin_lock_init(&dev->slock);
-+
-+	/* Initialize VBI template */
-+	memcpy(&cx23885_vbi_template, &cx23885_video_template,
-+		sizeof(cx23885_vbi_template));
-+	strcpy(cx23885_vbi_template.name, "cx23885-vbi");
-+	cx23885_vbi_template.type = VID_TYPE_TELETEXT|VID_TYPE_TUNER;
-+
-+	dev->tvnorm = cx23885_video_template.current_norm;
++	struct em28xx_fh      *fh  = priv;
++	struct em28xx         *dev = fh->dev;
 +
-+	/* init video dma queues */
-+	INIT_LIST_HEAD(&dev->vidq.active);
-+	INIT_LIST_HEAD(&dev->vidq.queued);
-+	dev->vidq.timeout.function = cx23885_vid_timeout;
-+	dev->vidq.timeout.data = (unsigned long)dev;
-+	init_timer(&dev->vidq.timeout);
-+	cx23885_risc_stopper(dev->pci, &dev->vidq.stopper,
-+		VID_A_DMA_CTL, 0x11, 0x00);
++	strlcpy(cap->driver, "em28xx", sizeof(cap->driver));
++	strlcpy(cap->card, em28xx_boards[dev->model].name, sizeof(cap->card));
++	strlcpy(cap->bus_info, dev->udev->dev.bus_id, sizeof(cap->bus_info));
 +
-+	/* Don't enable VBI yet */
-+	cx_set(PCI_INT_MSK, 1);
++	cap->version = EM28XX_VERSION_CODE;
 +
++	cap->capabilities =
++			V4L2_CAP_SLICED_VBI_CAPTURE |
++			V4L2_CAP_VIDEO_CAPTURE |
++			V4L2_CAP_AUDIO |
++			V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
 +
-+	/* register v4l devices */
-+	dev->video_dev = cx23885_vdev_init(dev, dev->pci,
-+		&cx23885_video_template, "video");
-+	err = video_register_device(dev->video_dev, VFL_TYPE_GRABBER,
-+				    video_nr[dev->nr]);
-+	if (err < 0) {
-+		printk(KERN_INFO "%s: can't register video device\n",
-+			dev->name);
-+		goto fail_unreg;
-+	}
-+	printk(KERN_INFO "%s/0: registered device video%d [v4l2]\n",
-+	       dev->name, dev->video_dev->minor & 0x1f);
-+	/* initial device configuration */
-+	mutex_lock(&dev->lock);
-+	cx23885_set_tvnorm(dev, dev->tvnorm);
-+	init_controls(dev);
-+	cx23885_video_mux(dev, 0);
-+	mutex_unlock(&dev->lock);
++	if (dev->tuner_type != TUNER_ABSENT)
++		cap->capabilities |= V4L2_CAP_TUNER;
 +
 +	return 0;
-+
-+fail_unreg:
-+	cx23885_video_unregister(dev);
-+	return err;
 +}
 +
-diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h
-index dec4dc2..7cb2179 100644
---- a/drivers/media/video/cx23885/cx23885.h
-+++ b/drivers/media/video/cx23885/cx23885.h
-@@ -44,6 +44,10 @@
- 
- /* Max number of inputs by card */
- #define MAX_CX23885_INPUT 8
-+#define INPUT(nr) (&cx23885_boards[dev->board].input[nr])
-+#define RESOURCE_OVERLAY       1
-+#define RESOURCE_VIDEO         2
-+#define RESOURCE_VBI           4
- 
- #define BUFFER_TIMEOUT     (HZ)  /* 0.5 seconds */
- 
-@@ -53,6 +57,62 @@
- #define CX23885_BOARD_HAUPPAUGE_HVR1800        2
- #define CX23885_BOARD_HAUPPAUGE_HVR1250        3
- #define CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP   4
-+#define CX23885_BOARD_HAUPPAUGE_HVR1500Q       5
-+#define CX23885_BOARD_HAUPPAUGE_HVR1500        6
-+
-+/* Currently unsupported by the driver: PAL/H, NTSC/Kr, SECAM B/G/H/LC */
-+#define CX23885_NORMS (\
-+	V4L2_STD_NTSC_M |  V4L2_STD_NTSC_M_JP |  V4L2_STD_NTSC_443 | \
-+	V4L2_STD_PAL_BG |  V4L2_STD_PAL_DK    |  V4L2_STD_PAL_I    | \
-+	V4L2_STD_PAL_M  |  V4L2_STD_PAL_N     |  V4L2_STD_PAL_Nc   | \
-+	V4L2_STD_PAL_60 |  V4L2_STD_SECAM_L   |  V4L2_STD_SECAM_DK)
++static int vidioc_enum_fmt_cap(struct file *file, void  *priv,
++					struct v4l2_fmtdesc *fmtd)
++{
++	if (fmtd->index != 0)
++		return -EINVAL;
 +
-+struct cx23885_fmt {
-+	char  *name;
-+	u32   fourcc;          /* v4l2 format id */
-+	int   depth;
-+	int   flags;
-+	u32   cxformat;
-+};
++	fmtd->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
++	strcpy(fmtd->description, "Packed YUY2");
++	fmtd->pixelformat = V4L2_PIX_FMT_YUYV;
++	memset(fmtd->reserved, 0, sizeof(fmtd->reserved));
 +
-+struct cx23885_ctrl {
-+	struct v4l2_queryctrl v;
-+	u32                   off;
-+	u32                   reg;
-+	u32                   mask;
-+	u32                   shift;
-+};
++	return 0;
++}
 +
-+struct cx23885_tvnorm {
-+	char		*name;
-+	v4l2_std_id	id;
-+	u32		cxiformat;
-+	u32		cxoformat;
-+};
++/* Sliced VBI ioctls */
++static int vidioc_g_fmt_vbi_capture(struct file *file, void *priv,
++					struct v4l2_format *f)
++{
++	struct em28xx_fh      *fh  = priv;
++	struct em28xx         *dev = fh->dev;
++	int                   rc;
 +
-+struct cx23885_fh {
-+	struct cx23885_dev         *dev;
-+	enum v4l2_buf_type         type;
-+	int                        radio;
-+	u32                        resources;
++	rc = check_dev(dev);
++	if (rc < 0)
++		return rc;
 +
-+	/* video overlay */
-+	struct v4l2_window         win;
-+	struct v4l2_clip           *clips;
-+	unsigned int               nclips;
++	mutex_lock(&dev->lock);
 +
-+	/* video capture */
-+	struct cx23885_fmt         *fmt;
-+	unsigned int               width, height;
++	f->fmt.sliced.service_set = 0;
 +
-+	/* vbi capture */
-+	struct videobuf_queue      vidq;
-+	struct videobuf_queue      vbiq;
++	em28xx_i2c_call_clients(dev, VIDIOC_G_FMT, f);
 +
-+	/* MPEG Encoder specifics ONLY */
-+	struct videobuf_queue      mpegq;
-+	atomic_t                   v4l_reading;
-+};
- 
- enum cx23885_itype {
- 	CX23885_VMUX_COMPOSITE1 = 1,
-@@ -92,12 +152,28 @@ struct cx23885_input {
- 
- typedef enum {
- 	CX23885_MPEG_UNDEFINED = 0,
--	CX23885_MPEG_DVB
-+	CX23885_MPEG_DVB,
-+	CX23885_ANALOG_VIDEO,
- } port_t;
- 
- struct cx23885_board {
- 	char                    *name;
--	port_t			portb, portc;
-+	port_t			porta, portb, portc;
-+	unsigned int		tuner_type;
-+	unsigned int		radio_type;
-+	unsigned char		tuner_addr;
-+	unsigned char		radio_addr;
++	if (f->fmt.sliced.service_set == 0)
++		rc = -EINVAL;
 +
-+	/* Vendors can and do run the PCIe bridge at different
-+	 * clock rates, driven physically by crystals on the PCBs.
-+	 * The core has to accomodate this. This allows the user
-+	 * to add new boards with new frequencys. The value is
-+	 * expressed in Hz.
-+	 *
-+	 * The core framework will default this value based on
-+	 * current designs, but it can vary.
-+	 */
-+	u32			clk_freq;
- 	struct cx23885_input    input[MAX_CX23885_INPUT];
- };
- 
-@@ -189,6 +265,11 @@ struct cx23885_dev {
- 	u32                        __iomem *lmmio;
- 	u8                         __iomem *bmmio;
- 	int                        pci_irqmask;
-+	int                        hwrevision;
++	mutex_unlock(&dev->lock);
++	return rc;
++}
 +
-+	/* This valud is board specific and is used to configure the
-+	 * AV core so we see nice clean and stable video and audio. */
-+	u32                        clk_freq;
- 
- 	/* I2C adapters: Master 1 & 2 (External) & Master 3 (Internal only) */
- 	struct cx23885_i2c         i2c_bus[3];
-@@ -210,8 +291,31 @@ struct cx23885_dev {
- 		CX23885_BRIDGE_885 = 885,
- 		CX23885_BRIDGE_887 = 887,
- 	} bridge;
++static int vidioc_try_set_vbi_capture(struct file *file, void *priv,
++			struct v4l2_format *f)
++{
++	struct em28xx_fh      *fh  = priv;
++	struct em28xx         *dev = fh->dev;
++	int                   rc;
 +
-+	/* Analog video */
-+	u32                        resources;
-+	unsigned int               input;
-+	u32                        tvaudio;
-+	v4l2_std_id                tvnorm;
-+	unsigned int               tuner_type;
-+	unsigned char              tuner_addr;
-+	unsigned int               radio_type;
-+	unsigned char              radio_addr;
-+	unsigned int               has_radio;
++	rc = check_dev(dev);
++	if (rc < 0)
++		return rc;
 +
-+	/* V4l */
-+	u32                        freq;
-+	struct video_device        *video_dev;
-+	struct video_device        *vbi_dev;
-+	struct video_device        *radio_dev;
++	mutex_lock(&dev->lock);
++	em28xx_i2c_call_clients(dev, VIDIOC_G_FMT, f);
++	mutex_unlock(&dev->lock);
 +
-+	struct cx23885_dmaqueue    vidq;
-+	struct cx23885_dmaqueue    vbiq;
-+	spinlock_t                 slock;
- };
- 
-+extern struct list_head cx23885_devlist;
++	if (f->fmt.sliced.service_set == 0)
++		return -EINVAL;
 +
- #define SRAM_CH01  0 /* Video A */
- #define SRAM_CH02  1 /* VBI A */
- #define SRAM_CH03  2 /* Video B */
-@@ -254,19 +358,42 @@ struct sram_channel {
- #define cx_set(reg,bit)          cx_andor((reg),(bit),(bit))
- #define cx_clear(reg,bit)        cx_andor((reg),(bit),0)
- 
-+/* ----------------------------------------------------------- */
-+/* cx23885-core.c                                              */
++	return 0;
++}
 +
- extern int cx23885_sram_channel_setup(struct cx23885_dev *dev,
- 	struct sram_channel *ch,
- 	unsigned int bpl, u32 risc);
- 
--/* ----------------------------------------------------------- */
--/* cx23885-cards.c                                                */
-+extern void cx23885_sram_channel_dump(struct cx23885_dev *dev,
-+	struct sram_channel *ch);
- 
-+extern int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc,
-+	u32 reg, u32 mask, u32 value);
 +
-+extern int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc,
-+	struct scatterlist *sglist,
-+	unsigned int top_offset, unsigned int bottom_offset,
-+	unsigned int bpl, unsigned int padding, unsigned int lines);
++static int vidioc_reqbufs(struct file *file, void *priv,
++			  struct v4l2_requestbuffers *rb)
++{
++	struct em28xx_fh      *fh  = priv;
++	struct em28xx         *dev = fh->dev;
++	u32                   i;
++	int                   rc;
 +
-+void cx23885_cancel_buffers(struct cx23885_tsport *port);
++	rc = check_dev(dev);
++	if (rc < 0)
++		return rc;
 +
-+extern int cx23885_restart_queue(struct cx23885_tsport *port,
-+				struct cx23885_dmaqueue *q);
++	if (rb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
++		rb->memory != V4L2_MEMORY_MMAP)
++		return -EINVAL;
 +
-+extern void cx23885_wakeup(struct cx23885_tsport *port,
-+			   struct cx23885_dmaqueue *q, u32 count);
++	if (dev->io == IO_READ) {
++		em28xx_videodbg("method is set to read;"
++				" close and open the device again to"
++				" choose the mmap I/O method\n");
++		return -EINVAL;
++	}
 +
++	for (i = 0; i < dev->num_frames; i++)
++		if (dev->frame[i].vma_use_count) {
++			em28xx_videodbg("VIDIOC_REQBUFS failed; "
++					"previous buffers are still mapped\n");
++			return -EINVAL;
++		}
 +
-+/* ----------------------------------------------------------- */
-+/* cx23885-cards.c                                             */
- extern struct cx23885_board cx23885_boards[];
- extern const unsigned int cx23885_bcount;
- 
- extern struct cx23885_subid cx23885_subids[];
- extern const unsigned int cx23885_idcount;
- 
-+extern int cx23885_tuner_callback(void *priv, 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);
-@@ -280,19 +407,50 @@ extern int cx23885_buf_prepare(struct videobuf_queue *q,
- 			       struct cx23885_tsport *port,
- 			       struct cx23885_buffer *buf,
- 			       enum v4l2_field field);
--
- extern void cx23885_buf_queue(struct cx23885_tsport *port,
- 			      struct cx23885_buffer *buf);
- extern void cx23885_free_buffer(struct videobuf_queue *q,
- 				struct cx23885_buffer *buf);
- 
- /* ----------------------------------------------------------- */
-+/* cx23885-video.c                                             */
-+/* Video */
-+extern int cx23885_video_register(struct cx23885_dev *dev);
-+extern void cx23885_video_unregister(struct cx23885_dev *dev);
-+extern int cx23885_video_irq(struct cx23885_dev *dev, u32 status);
++	mutex_lock(&dev->lock);
 +
-+/* ----------------------------------------------------------- */
-+/* cx23885-vbi.c                                               */
-+extern int cx23885_vbi_fmt(struct file *file, void *priv,
-+	struct v4l2_format *f);
-+extern void cx23885_vbi_timeout(unsigned long data);
-+extern struct videobuf_queue_ops cx23885_vbi_qops;
++	if (dev->stream == STREAM_ON) {
++		em28xx_videodbg("VIDIOC_REQBUFS: interrupting stream\n");
++		rc = em28xx_stream_interrupt(dev);
++		if (rc < 0) {
++			mutex_unlock(&dev->lock);
++			return rc;
+ 		}
+-		em28xx_audio_source(dev, ainput);
+ 	}
 +
- /* cx23885-i2c.c                                                */
- extern int cx23885_i2c_register(struct cx23885_i2c *bus);
- extern int cx23885_i2c_unregister(struct cx23885_i2c *bus);
- extern void cx23885_call_i2c_clients(struct cx23885_i2c *bus, unsigned int cmd,
- 				     void *arg);
- 
-+/* ----------------------------------------------------------- */
-+/* tv norms                                                    */
++	em28xx_empty_framequeues(dev);
 +
-+static inline unsigned int norm_maxw(v4l2_std_id norm)
-+{
-+	return (norm & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 720 : 768;
-+}
++	em28xx_release_buffers(dev);
++	if (rb->count)
++		rb->count = em28xx_request_buffers(dev, rb->count);
 +
-+static inline unsigned int norm_maxh(v4l2_std_id norm)
-+{
-+	return (norm & V4L2_STD_625_50) ? 576 : 480;
-+}
++	dev->frame_current = NULL;
++	dev->io = rb->count ? IO_MMAP : IO_NONE;
 +
-+static inline unsigned int norm_swidth(v4l2_std_id norm)
-+{
-+	return (norm & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 754 : 922;
++	mutex_unlock(&dev->lock);
++	return 0;
 +}
 +
-+
- /*
-  * Local variables:
-  * c-basic-offset: 8
-diff --git a/drivers/media/video/cx25840/cx25840-audio.c b/drivers/media/video/cx25840/cx25840-audio.c
-index 3d46a77..d6421e1 100644
---- a/drivers/media/video/cx25840/cx25840-audio.c
-+++ b/drivers/media/video/cx25840/cx25840-audio.c
-@@ -32,118 +32,156 @@ static int set_audclk_freq(struct i2c_client *client, u32 freq)
- 
- 	/* common for all inputs and rates */
- 	/* SA_MCLK_SEL=1, SA_MCLK_DIV=0x10 */
--	cx25840_write(client, 0x127, 0x50);
-+	if (!state->is_cx23885)
-+		cx25840_write(client, 0x127, 0x50);
- 
- 	if (state->aud_input != CX25840_AUDIO_SERIAL) {
- 		switch (freq) {
- 		case 32000:
-+			if (state->is_cx23885) {
-+				/* We don't have register values
-+				 * so avoid destroying registers. */
-+				break;
-+			}
- 			/* VID_PLL and AUX_PLL */
--			cx25840_write4(client, 0x108, 0x0f040610);
-+			cx25840_write4(client, 0x108, 0x1006040f);
- 
- 			/* AUX_PLL_FRAC */
--			cx25840_write4(client, 0x110, 0xee39bb01);
-+			cx25840_write4(client, 0x110, 0x01bb39ee);
- 
- 			if (state->is_cx25836)
- 				break;
- 
- 			/* src3/4/6_ctl = 0x0801f77f */
--			cx25840_write4(client, 0x900, 0x7ff70108);
--			cx25840_write4(client, 0x904, 0x7ff70108);
--			cx25840_write4(client, 0x90c, 0x7ff70108);
-+			cx25840_write4(client, 0x900, 0x0801f77f);
-+			cx25840_write4(client, 0x904, 0x0801f77f);
-+			cx25840_write4(client, 0x90c, 0x0801f77f);
- 			break;
- 
- 		case 44100:
-+			if (state->is_cx23885) {
-+				/* We don't have register values
-+				 * so avoid destroying registers. */
-+				break;
-+			}
- 			/* VID_PLL and AUX_PLL */
--			cx25840_write4(client, 0x108, 0x0f040910);
-+			cx25840_write4(client, 0x108, 0x1009040f);
- 
- 			/* AUX_PLL_FRAC */
--			cx25840_write4(client, 0x110, 0xd66bec00);
-+			cx25840_write4(client, 0x110, 0x00ec6bd6);
- 
- 			if (state->is_cx25836)
- 				break;
- 
- 			/* src3/4/6_ctl = 0x08016d59 */
--			cx25840_write4(client, 0x900, 0x596d0108);
--			cx25840_write4(client, 0x904, 0x596d0108);
--			cx25840_write4(client, 0x90c, 0x596d0108);
-+			cx25840_write4(client, 0x900, 0x08016d59);
-+			cx25840_write4(client, 0x904, 0x08016d59);
-+			cx25840_write4(client, 0x90c, 0x08016d59);
- 			break;
- 
- 		case 48000:
-+			if (state->is_cx23885) {
-+				/* We don't have register values
-+				 * so avoid destroying registers. */
-+				break;
-+			}
- 			/* VID_PLL and AUX_PLL */
--			cx25840_write4(client, 0x108, 0x0f040a10);
-+			cx25840_write4(client, 0x108, 0x100a040f);
- 
- 			/* AUX_PLL_FRAC */
--			cx25840_write4(client, 0x110, 0xe5d69800);
-+			cx25840_write4(client, 0x110, 0x0098d6e5);
- 
- 			if (state->is_cx25836)
- 				break;
- 
- 			/* src3/4/6_ctl = 0x08014faa */
--			cx25840_write4(client, 0x900, 0xaa4f0108);
--			cx25840_write4(client, 0x904, 0xaa4f0108);
--			cx25840_write4(client, 0x90c, 0xaa4f0108);
-+			cx25840_write4(client, 0x900, 0x08014faa);
-+			cx25840_write4(client, 0x904, 0x08014faa);
-+			cx25840_write4(client, 0x90c, 0x08014faa);
- 			break;
- 		}
- 	} else {
- 		switch (freq) {
- 		case 32000:
-+			if (state->is_cx23885) {
-+				/* We don't have register values
-+				 * so avoid destroying registers. */
-+				break;
-+			}
- 			/* VID_PLL and AUX_PLL */
--			cx25840_write4(client, 0x108, 0x0f04081e);
-+			cx25840_write4(client, 0x108, 0x1e08040f);
- 
- 			/* AUX_PLL_FRAC */
--			cx25840_write4(client, 0x110, 0x69082a01);
-+			cx25840_write4(client, 0x110, 0x012a0869);
- 
- 			if (state->is_cx25836)
- 				break;
- 
- 			/* src1_ctl = 0x08010000 */
--			cx25840_write4(client, 0x8f8, 0x00000108);
-+			cx25840_write4(client, 0x8f8, 0x08010000);
- 
- 			/* src3/4/6_ctl = 0x08020000 */
--			cx25840_write4(client, 0x900, 0x00000208);
--			cx25840_write4(client, 0x904, 0x00000208);
--			cx25840_write4(client, 0x90c, 0x00000208);
-+			cx25840_write4(client, 0x900, 0x08020000);
-+			cx25840_write4(client, 0x904, 0x08020000);
-+			cx25840_write4(client, 0x90c, 0x08020000);
- 
- 			/* SA_MCLK_SEL=1, SA_MCLK_DIV=0x14 */
- 			cx25840_write(client, 0x127, 0x54);
- 			break;
- 
- 		case 44100:
-+			if (state->is_cx23885) {
-+				/* We don't have register values
-+				 * so avoid destroying registers. */
-+				break;
-+			}
-+
- 			/* VID_PLL and AUX_PLL */
--			cx25840_write4(client, 0x108, 0x0f040918);
-+			cx25840_write4(client, 0x108, 0x1809040f);
- 
- 			/* AUX_PLL_FRAC */
--			cx25840_write4(client, 0x110, 0xd66bec00);
-+			cx25840_write4(client, 0x110, 0x00ec6bd6);
- 
- 			if (state->is_cx25836)
- 				break;
- 
- 			/* src1_ctl = 0x08010000 */
--			cx25840_write4(client, 0x8f8, 0xcd600108);
-+			cx25840_write4(client, 0x8f8, 0x080160cd);
- 
- 			/* src3/4/6_ctl = 0x08020000 */
--			cx25840_write4(client, 0x900, 0x85730108);
--			cx25840_write4(client, 0x904, 0x85730108);
--			cx25840_write4(client, 0x90c, 0x85730108);
-+			cx25840_write4(client, 0x900, 0x08017385);
-+			cx25840_write4(client, 0x904, 0x08017385);
-+			cx25840_write4(client, 0x90c, 0x08017385);
- 			break;
- 
- 		case 48000:
--			/* VID_PLL and AUX_PLL */
--			cx25840_write4(client, 0x108, 0x0f040a18);
-+			if (!state->is_cx23885) {
-+				/* VID_PLL and AUX_PLL */
-+				cx25840_write4(client, 0x108, 0x180a040f);
- 
--			/* AUX_PLL_FRAC */
--			cx25840_write4(client, 0x110, 0xe5d69800);
-+				/* AUX_PLL_FRAC */
-+				cx25840_write4(client, 0x110, 0x0098d6e5);
-+			}
- 
- 			if (state->is_cx25836)
- 				break;
- 
--			/* src1_ctl = 0x08010000 */
--			cx25840_write4(client, 0x8f8, 0x00800108);
-+			if (!state->is_cx23885) {
-+				/* src1_ctl */
-+				cx25840_write4(client, 0x8f8, 0x08018000);
- 
--			/* src3/4/6_ctl = 0x08020000 */
--			cx25840_write4(client, 0x900, 0x55550108);
--			cx25840_write4(client, 0x904, 0x55550108);
--			cx25840_write4(client, 0x90c, 0x55550108);
-+				/* src3/4/6_ctl */
-+				cx25840_write4(client, 0x900, 0x08015555);
-+				cx25840_write4(client, 0x904, 0x08015555);
-+				cx25840_write4(client, 0x90c, 0x08015555);
-+			} else {
-+
-+				cx25840_write4(client, 0x8f8, 0x0801867c);
-+
-+				cx25840_write4(client, 0x900, 0x08014faa);
-+				cx25840_write4(client, 0x904, 0x08014faa);
-+				cx25840_write4(client, 0x90c, 0x08014faa);
-+			}
- 			break;
- 		}
- 	}
-@@ -168,14 +206,14 @@ void cx25840_audio_set_path(struct i2c_client *client)
- 
- 	if (state->aud_input == CX25840_AUDIO_SERIAL) {
- 		/* Set Path1 to Serial Audio Input */
--		cx25840_write4(client, 0x8d0, 0x12100101);
-+		cx25840_write4(client, 0x8d0, 0x01011012);
- 
- 		/* The microcontroller should not be started for the
- 		 * non-tuner inputs: autodetection is specific for
- 		 * TV audio. */
- 	} else {
- 		/* Set Path1 to Analog Demod Main Channel */
--		cx25840_write4(client, 0x8d0, 0x7038061f);
-+		cx25840_write4(client, 0x8d0, 0x1f063870);
- 	}
- 
- 	set_audclk_freq(client, state->audclk_freq);
-@@ -188,6 +226,11 @@ void cx25840_audio_set_path(struct i2c_client *client)
- 
- 	/* deassert soft reset */
- 	cx25840_and_or(client, 0x810, ~0x1, 0x00);
-+
-+	if (state->is_cx23885) {
-+		/* Ensure the controller is running when we exit */
-+		cx25840_and_or(client, 0x803, ~0x10, 0x10);
-+	}
- }
- 
- static int get_volume(struct i2c_client *client)
-diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c
-index 15f191e..756a1ee 100644
---- a/drivers/media/video/cx25840/cx25840-core.c
-+++ b/drivers/media/video/cx25840/cx25840-core.c
-@@ -13,6 +13,8 @@
-  * NTSC sliced VBI support by Christopher Neufeld <television at cneufeld.ca>
-  * with additional fixes by Hans Verkuil <hverkuil at xs4all.nl>.
-  *
-+ * CX23885 support by Steven Toth <stoth at hauppauge.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
-@@ -37,6 +39,7 @@
- #include <linux/delay.h>
- #include <media/v4l2-common.h>
- #include <media/v4l2-chip-ident.h>
-+#include <media/v4l2-i2c-drv-legacy.h>
- #include <media/cx25840.h>
- 
- #include "cx25840-core.h"
-@@ -72,10 +75,10 @@ int cx25840_write4(struct i2c_client *client, u16 addr, u32 value)
- 	u8 buffer[6];
- 	buffer[0] = addr >> 8;
- 	buffer[1] = addr & 0xff;
--	buffer[2] = value >> 24;
--	buffer[3] = (value >> 16) & 0xff;
--	buffer[4] = (value >> 8) & 0xff;
--	buffer[5] = value & 0xff;
-+	buffer[2] = value & 0xff;
-+	buffer[3] = (value >> 8) & 0xff;
-+	buffer[4] = (value >> 16) & 0xff;
-+	buffer[5] = value >> 24;
- 	return i2c_master_send(client, buffer, 6);
- }
- 
-@@ -122,8 +125,6 @@ int cx25840_and_or(struct i2c_client *client, u16 addr, unsigned and_mask,
- 
- static int set_input(struct i2c_client *client, enum cx25840_video_input vid_input,
- 						enum cx25840_audio_input aud_input);
--static void log_audio_status(struct i2c_client *client);
--static void log_video_status(struct i2c_client *client);
- 
- /* ----------------------------------------------------------------------- */
- 
-@@ -256,6 +257,96 @@ static void cx25840_initialize(struct i2c_client *client)
- 	cx25840_and_or(client, 0x803, ~0x10, 0x10);
- }
- 
-+static void cx23885_initialize(struct i2c_client *client)
++static int vidioc_querybuf(struct file *file, void *priv,
++			   struct v4l2_buffer *b)
 +{
-+	DEFINE_WAIT(wait);
-+	struct cx25840_state *state = i2c_get_clientdata(client);
-+	struct workqueue_struct *q;
-+
-+	/* Internal Reset */
-+	cx25840_and_or(client, 0x102, ~0x01, 0x01);
-+	cx25840_and_or(client, 0x102, ~0x01, 0x00);
-+
-+	/* Stop microcontroller */
-+	cx25840_and_or(client, 0x803, ~0x10, 0x00);
++	struct em28xx_fh      *fh  = priv;
++	struct em28xx         *dev = fh->dev;
++	int                   rc;
 +
-+	/* DIF in reset? */
-+	cx25840_write(client, 0x398, 0);
++	rc = check_dev(dev);
++	if (rc < 0)
++		return rc;
 +
-+	/* Trust the default xtal, no division */
-+	/* This changes for the cx23888 products */
-+	cx25840_write(client, 0x2, 0x76);
++	if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
++		b->index >= dev->num_frames || dev->io != IO_MMAP)
++		return -EINVAL;
 +
-+	/* Bring down the regulator for AUX clk */
-+	cx25840_write(client, 0x1, 0x40);
++	mutex_lock(&dev->lock);
 +
-+	/* Sys PLL frac */
-+	cx25840_write4(client, 0x11c, 0x01d1744c);
++	memcpy(b, &dev->frame[b->index].buf, sizeof(*b));
 +
-+	/* Sys PLL int */
-+	cx25840_write4(client, 0x118, 0x00000416);
++	if (dev->frame[b->index].vma_use_count)
++		b->flags |= V4L2_BUF_FLAG_MAPPED;
 +
-+	/* Disable DIF bypass */
-+	cx25840_write4(client, 0x33c, 0x00000001);
++	if (dev->frame[b->index].state == F_DONE)
++		b->flags |= V4L2_BUF_FLAG_DONE;
++	else if (dev->frame[b->index].state != F_UNUSED)
++		b->flags |= V4L2_BUF_FLAG_QUEUED;
 +
-+	/* DIF Src phase inc */
-+	cx25840_write4(client, 0x340, 0x0df7df83);
++	mutex_unlock(&dev->lock);
++	return 0;
++}
 +
-+	/* Vid PLL frac */
-+	cx25840_write4(client, 0x10c, 0x01b6db7b);
++static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
++{
++	struct em28xx_fh      *fh  = priv;
++	struct em28xx         *dev = fh->dev;
++	unsigned long         lock_flags;
++	int                   rc;
 +
-+	/* Vid PLL int */
-+	cx25840_write4(client, 0x108, 0x00000512);
++	rc = check_dev(dev);
++	if (rc < 0)
++		return rc;
 +
-+	/* Luma */
-+	cx25840_write4(client, 0x414, 0x00107d12);
++	if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE  || dev->io != IO_MMAP ||
++						b->index >= dev->num_frames)
++		return -EINVAL;
 +
-+	/* Chroma */
-+	cx25840_write4(client, 0x420, 0x3d008282);
++	if (dev->frame[b->index].state != F_UNUSED)
++		return -EAGAIN;
 +
-+	/* Aux PLL frac */
-+	cx25840_write4(client, 0x114, 0x017dbf48);
++	dev->frame[b->index].state = F_QUEUED;
 +
-+	/* Aux PLL int */
-+	cx25840_write4(client, 0x110, 0x000a030e);
++	/* add frame to fifo */
++	spin_lock_irqsave(&dev->queue_lock, lock_flags);
++	list_add_tail(&dev->frame[b->index].frame, &dev->inqueue);
++	spin_unlock_irqrestore(&dev->queue_lock, lock_flags);
 +
-+	/* ADC2 input select */
-+	cx25840_write(client, 0x102, 0x10);
++	return 0;
++}
 +
-+	/* VIN1 & VIN5 */
-+	cx25840_write(client, 0x103, 0x11);
++static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
++{
++	struct em28xx_fh      *fh  = priv;
++	struct em28xx         *dev = fh->dev;
++	int                   rc;
++	struct em28xx_frame_t *f;
++	unsigned long         lock_flags;
 +
-+	/* Enable format auto detect */
-+	cx25840_write(client, 0x400, 0);
-+	/* Fast subchroma lock */
-+	/* White crush, Chroma AGC & Chroma Killer enabled */
-+	cx25840_write(client, 0x401, 0xe8);
++	rc = check_dev(dev);
++	if (rc < 0)
++		return rc;
 +
-+	/* Select AFE clock pad output source */
-+	cx25840_write(client, 0x144, 0x05);
++	if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || dev->io != IO_MMAP)
++		return -EINVAL;
 +
-+	/* Do the firmware load in a work handler to prevent.
-+	   Otherwise the kernel is blocked waiting for the
-+	   bit-banging i2c interface to finish uploading the
-+	   firmware. */
-+	INIT_WORK(&state->fw_work, cx25840_work_handler);
-+	init_waitqueue_head(&state->fw_wait);
-+	q = create_singlethread_workqueue("cx25840_fw");
-+	prepare_to_wait(&state->fw_wait, &wait, TASK_UNINTERRUPTIBLE);
-+	queue_work(q, &state->fw_work);
-+	schedule();
-+	finish_wait(&state->fw_wait, &wait);
-+	destroy_workqueue(q);
++	if (list_empty(&dev->outqueue)) {
++		if (dev->stream == STREAM_OFF)
++			return -EINVAL;
 +
-+	cx25840_vbi_setup(client);
++		if (file->f_flags & O_NONBLOCK)
++			return -EAGAIN;
 +
-+	/* (re)set input */
-+	set_input(client, state->vid_input, state->aud_input);
++		rc = wait_event_interruptible(dev->wait_frame,
++					(!list_empty(&dev->outqueue)) ||
++					(dev->state & DEV_DISCONNECTED));
++		if (rc)
++			return rc;
 +
-+	/* start microcontroller */
-+	cx25840_and_or(client, 0x803, ~0x10, 0x10);
-+}
++		if (dev->state & DEV_DISCONNECTED)
++			return -ENODEV;
++	}
 +
- /* ----------------------------------------------------------------------- */
- 
- static void input_change(struct i2c_client *client)
-@@ -319,9 +410,22 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp
- 			   vid_input <= CX25840_COMPOSITE8);
- 	u8 reg;
- 
--	v4l_dbg(1, cx25840_debug, client, "decoder set video input %d, audio input %d\n",
--			vid_input, aud_input);
-+	v4l_dbg(1, cx25840_debug, client,
-+		"decoder set video input %d, audio input %d\n",
-+		vid_input, aud_input);
++	spin_lock_irqsave(&dev->queue_lock, lock_flags);
++	f = list_entry(dev->outqueue.next, struct em28xx_frame_t, frame);
++	list_del(dev->outqueue.next);
++	spin_unlock_irqrestore(&dev->queue_lock, lock_flags);
 +
-+	if (vid_input >= CX25840_VIN1_CH1) {
-+		v4l_dbg(1, cx25840_debug, client, "vid_input 0x%x\n",
-+			vid_input);
-+		reg = vid_input & 0xff;
-+		if ((vid_input & CX25840_SVIDEO_ON) == CX25840_SVIDEO_ON)
-+			is_composite = 0;
-+		else
-+			is_composite = 1;
- 
-+		v4l_dbg(1, cx25840_debug, client, "mux cfg 0x%x comp=%d\n",
-+			reg, is_composite);
-+	} else
- 	if (is_composite) {
- 		reg = 0xf0 + (vid_input - CX25840_COMPOSITE1);
- 	} else {
-@@ -331,7 +435,8 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp
- 		if ((vid_input & ~0xff0) ||
- 		    luma < CX25840_SVIDEO_LUMA1 || luma > CX25840_SVIDEO_LUMA4 ||
- 		    chroma < CX25840_SVIDEO_CHROMA4 || chroma > CX25840_SVIDEO_CHROMA8) {
--			v4l_err(client, "0x%04x is not a valid video input!\n", vid_input);
-+			v4l_err(client, "0x%04x is not a valid video input!\n",
-+				vid_input);
- 			return -EINVAL;
- 		}
- 		reg = 0xf0 + ((luma - CX25840_SVIDEO_LUMA1) >> 4);
-@@ -344,31 +449,49 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp
- 		}
- 	}
- 
--	switch (aud_input) {
--	case CX25840_AUDIO_SERIAL:
--		/* do nothing, use serial audio input */
--		break;
--	case CX25840_AUDIO4: reg &= ~0x30; break;
--	case CX25840_AUDIO5: reg &= ~0x30; reg |= 0x10; break;
--	case CX25840_AUDIO6: reg &= ~0x30; reg |= 0x20; break;
--	case CX25840_AUDIO7: reg &= ~0xc0; break;
--	case CX25840_AUDIO8: reg &= ~0xc0; reg |= 0x40; break;
-+	/* The caller has previously prepared the correct routing
-+	 * configuration in reg (for the cx23885) so we have no
-+	 * need to attempt to flip bits for earlier av decoders.
-+	 */
-+	if (!state->is_cx23885) {
-+		switch (aud_input) {
-+		case CX25840_AUDIO_SERIAL:
-+			/* do nothing, use serial audio input */
-+			break;
-+		case CX25840_AUDIO4: reg &= ~0x30; break;
-+		case CX25840_AUDIO5: reg &= ~0x30; reg |= 0x10; break;
-+		case CX25840_AUDIO6: reg &= ~0x30; reg |= 0x20; break;
-+		case CX25840_AUDIO7: reg &= ~0xc0; break;
-+		case CX25840_AUDIO8: reg &= ~0xc0; reg |= 0x40; break;
- 
--	default:
--		v4l_err(client, "0x%04x is not a valid audio input!\n", aud_input);
--		return -EINVAL;
-+		default:
-+			v4l_err(client, "0x%04x is not a valid audio input!\n",
-+				aud_input);
-+			return -EINVAL;
-+		}
- 	}
- 
- 	cx25840_write(client, 0x103, reg);
++	f->state = F_UNUSED;
++	memcpy(b, &f->buf, sizeof(*b));
 +
- 	/* Set INPUT_MODE to Composite (0) or S-Video (1) */
- 	cx25840_and_or(client, 0x401, ~0x6, is_composite ? 0 : 0x02);
--	/* Set CH_SEL_ADC2 to 1 if input comes from CH3 */
--	cx25840_and_or(client, 0x102, ~0x2, (reg & 0x80) == 0 ? 2 : 0);
--	/* Set DUAL_MODE_ADC2 to 1 if input comes from both CH2 and CH3 */
--	if ((reg & 0xc0) != 0xc0 && (reg & 0x30) != 0x30)
--		cx25840_and_or(client, 0x102, ~0x4, 4);
--	else
--		cx25840_and_or(client, 0x102, ~0x4, 0);
++	if (f->vma_use_count)
++		b->flags |= V4L2_BUF_FLAG_MAPPED;
 +
-+	if (!state->is_cx23885) {
-+		/* Set CH_SEL_ADC2 to 1 if input comes from CH3 */
-+		cx25840_and_or(client, 0x102, ~0x2, (reg & 0x80) == 0 ? 2 : 0);
-+		/* Set DUAL_MODE_ADC2 to 1 if input comes from both CH2&CH3 */
-+		if ((reg & 0xc0) != 0xc0 && (reg & 0x30) != 0x30)
-+			cx25840_and_or(client, 0x102, ~0x4, 4);
-+		else
-+			cx25840_and_or(client, 0x102, ~0x4, 0);
-+	} else {
-+		if (is_composite)
-+			/* ADC2 input select channel 2 */
-+			cx25840_and_or(client, 0x102, ~0x2, 0);
-+		else
-+			/* ADC2 input select channel 3 */
-+			cx25840_and_or(client, 0x102, ~0x2, 2);
-+	}
- 
- 	state->vid_input = vid_input;
- 	state->aud_input = aud_input;
-@@ -376,6 +499,25 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp
- 		cx25840_audio_set_path(client);
- 		input_change(client);
- 	}
++	return 0;
++}
 +
-+	if (state->is_cx23885) {
-+		/* Audio channel 1 src : Parallel 1 */
-+		cx25840_write(client, 0x124, 0x03);
++/* ----------------------------------------------------------- */
++/* RADIO ESPECIFIC IOCTLS                                      */
++/* ----------------------------------------------------------- */
 +
-+		/* Select AFE clock pad output source */
-+		cx25840_write(client, 0x144, 0x05);
++static int radio_querycap(struct file *file, void  *priv,
++			  struct v4l2_capability *cap)
++{
++	struct em28xx *dev = ((struct em28xx_fh *)priv)->dev;
 +
-+		/* I2S_IN_CTL: I2S_IN_SONY_MODE, LEFT SAMPLE on WS=1 */
-+		cx25840_write(client, 0x914, 0xa0);
++	strlcpy(cap->driver, "em28xx", sizeof(cap->driver));
++	strlcpy(cap->card, em28xx_boards[dev->model].name, sizeof(cap->card));
++	strlcpy(cap->bus_info, dev->udev->dev.bus_id, sizeof(cap->bus_info));
 +
-+		/* I2S_OUT_CTL:
-+		 * I2S_IN_SONY_MODE, LEFT SAMPLE on WS=1
-+		 * I2S_OUT_MASTER_MODE = Master
-+		 */
-+		cx25840_write(client, 0x918, 0xa0);
-+		cx25840_write(client, 0x919, 0x01);
-+	}
++	cap->version = EM28XX_VERSION_CODE;
++	cap->capabilities = V4L2_CAP_TUNER;
++	return 0;
++}
 +
- 	return 0;
- }
- 
-@@ -641,6 +783,200 @@ static int set_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt)
- 
- /* ----------------------------------------------------------------------- */
- 
-+static void log_video_status(struct i2c_client *client)
++static int radio_g_tuner(struct file *file, void *priv,
++			 struct v4l2_tuner *t)
 +{
-+	static const char *const fmt_strs[] = {
-+		"0x0",
-+		"NTSC-M", "NTSC-J", "NTSC-4.43",
-+		"PAL-BDGHI", "PAL-M", "PAL-N", "PAL-Nc", "PAL-60",
-+		"0x9", "0xA", "0xB",
-+		"SECAM",
-+		"0xD", "0xE", "0xF"
-+	};
++	struct em28xx *dev = ((struct em28xx_fh *)priv)->dev;
 +
-+	struct cx25840_state *state = i2c_get_clientdata(client);
-+	u8 vidfmt_sel = cx25840_read(client, 0x400) & 0xf;
-+	u8 gen_stat1 = cx25840_read(client, 0x40d);
-+	u8 gen_stat2 = cx25840_read(client, 0x40e);
-+	int vid_input = state->vid_input;
++	if (unlikely(t->index > 0))
++		return -EINVAL;
 +
-+	v4l_info(client, "Video signal:              %spresent\n",
-+		    (gen_stat2 & 0x20) ? "" : "not ");
-+	v4l_info(client, "Detected format:           %s\n",
-+		    fmt_strs[gen_stat1 & 0xf]);
++	strcpy(t->name, "Radio");
++	t->type = V4L2_TUNER_RADIO;
 +
-+	v4l_info(client, "Specified standard:        %s\n",
-+		    vidfmt_sel ? fmt_strs[vidfmt_sel] : "automatic detection");
++	em28xx_i2c_call_clients(dev, VIDIOC_G_TUNER, t);
++	return 0;
++}
 +
-+	if (vid_input >= CX25840_COMPOSITE1 &&
-+	    vid_input <= CX25840_COMPOSITE8) {
-+		v4l_info(client, "Specified video input:     Composite %d\n",
-+			vid_input - CX25840_COMPOSITE1 + 1);
-+	} else {
-+		v4l_info(client, "Specified video input:     S-Video (Luma In%d, Chroma In%d)\n",
-+			(vid_input & 0xf0) >> 4, (vid_input & 0xf00) >> 8);
-+	}
++static int radio_enum_input(struct file *file, void *priv,
++			    struct v4l2_input *i)
++{
++	if (i->index != 0)
++		return -EINVAL;
++	strcpy(i->name, "Radio");
++	i->type = V4L2_INPUT_TYPE_TUNER;
 +
-+	v4l_info(client, "Specified audioclock freq: %d Hz\n", state->audclk_freq);
++	return 0;
 +}
 +
-+/* ----------------------------------------------------------------------- */
-+
-+static void log_audio_status(struct i2c_client *client)
++static int radio_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
 +{
-+	struct cx25840_state *state = i2c_get_clientdata(client);
-+	u8 download_ctl = cx25840_read(client, 0x803);
-+	u8 mod_det_stat0 = cx25840_read(client, 0x804);
-+	u8 mod_det_stat1 = cx25840_read(client, 0x805);
-+	u8 audio_config = cx25840_read(client, 0x808);
-+	u8 pref_mode = cx25840_read(client, 0x809);
-+	u8 afc0 = cx25840_read(client, 0x80b);
-+	u8 mute_ctl = cx25840_read(client, 0x8d3);
-+	int aud_input = state->aud_input;
-+	char *p;
-+
-+	switch (mod_det_stat0) {
-+	case 0x00: p = "mono"; break;
-+	case 0x01: p = "stereo"; break;
-+	case 0x02: p = "dual"; break;
-+	case 0x04: p = "tri"; break;
-+	case 0x10: p = "mono with SAP"; break;
-+	case 0x11: p = "stereo with SAP"; break;
-+	case 0x12: p = "dual with SAP"; break;
-+	case 0x14: p = "tri with SAP"; break;
-+	case 0xfe: p = "forced mode"; break;
-+	default: p = "not defined";
-+	}
-+	v4l_info(client, "Detected audio mode:       %s\n", p);
++	if (unlikely(a->index))
++		return -EINVAL;
 +
-+	switch (mod_det_stat1) {
-+	case 0x00: p = "not defined"; break;
-+	case 0x01: p = "EIAJ"; break;
-+	case 0x02: p = "A2-M"; break;
-+	case 0x03: p = "A2-BG"; break;
-+	case 0x04: p = "A2-DK1"; break;
-+	case 0x05: p = "A2-DK2"; break;
-+	case 0x06: p = "A2-DK3"; break;
-+	case 0x07: p = "A1 (6.0 MHz FM Mono)"; break;
-+	case 0x08: p = "AM-L"; break;
-+	case 0x09: p = "NICAM-BG"; break;
-+	case 0x0a: p = "NICAM-DK"; break;
-+	case 0x0b: p = "NICAM-I"; break;
-+	case 0x0c: p = "NICAM-L"; break;
-+	case 0x0d: p = "BTSC/EIAJ/A2-M Mono (4.5 MHz FMMono)"; break;
-+	case 0x0e: p = "IF FM Radio"; break;
-+	case 0x0f: p = "BTSC"; break;
-+	case 0x10: p = "high-deviation FM"; break;
-+	case 0x11: p = "very high-deviation FM"; break;
-+	case 0xfd: p = "unknown audio standard"; break;
-+	case 0xfe: p = "forced audio standard"; break;
-+	case 0xff: p = "no detected audio standard"; break;
-+	default: p = "not defined";
-+	}
-+	v4l_info(client, "Detected audio standard:   %s\n", p);
-+	v4l_info(client, "Audio muted:               %s\n",
-+		    (state->unmute_volume >= 0) ? "yes" : "no");
-+	v4l_info(client, "Audio microcontroller:     %s\n",
-+		    (download_ctl & 0x10) ?
-+				((mute_ctl & 0x2) ? "detecting" : "running") : "stopped");
++	strcpy(a->name, "Radio");
++	return 0;
++}
 +
-+	switch (audio_config >> 4) {
-+	case 0x00: p = "undefined"; break;
-+	case 0x01: p = "BTSC"; break;
-+	case 0x02: p = "EIAJ"; break;
-+	case 0x03: p = "A2-M"; break;
-+	case 0x04: p = "A2-BG"; break;
-+	case 0x05: p = "A2-DK1"; break;
-+	case 0x06: p = "A2-DK2"; break;
-+	case 0x07: p = "A2-DK3"; break;
-+	case 0x08: p = "A1 (6.0 MHz FM Mono)"; break;
-+	case 0x09: p = "AM-L"; break;
-+	case 0x0a: p = "NICAM-BG"; break;
-+	case 0x0b: p = "NICAM-DK"; break;
-+	case 0x0c: p = "NICAM-I"; break;
-+	case 0x0d: p = "NICAM-L"; break;
-+	case 0x0e: p = "FM radio"; break;
-+	case 0x0f: p = "automatic detection"; break;
-+	default: p = "undefined";
-+	}
-+	v4l_info(client, "Configured audio standard: %s\n", p);
++static int radio_s_tuner(struct file *file, void *priv,
++			 struct v4l2_tuner *t)
++{
++	struct em28xx *dev = ((struct em28xx_fh *)priv)->dev;
 +
-+	if ((audio_config >> 4) < 0xF) {
-+		switch (audio_config & 0xF) {
-+		case 0x00: p = "MONO1 (LANGUAGE A/Mono L+R channel for BTSC, EIAJ, A2)"; break;
-+		case 0x01: p = "MONO2 (LANGUAGE B)"; break;
-+		case 0x02: p = "MONO3 (STEREO forced MONO)"; break;
-+		case 0x03: p = "MONO4 (NICAM ANALOG-Language C/Analog Fallback)"; break;
-+		case 0x04: p = "STEREO"; break;
-+		case 0x05: p = "DUAL1 (AB)"; break;
-+		case 0x06: p = "DUAL2 (AC) (FM)"; break;
-+		case 0x07: p = "DUAL3 (BC) (FM)"; break;
-+		case 0x08: p = "DUAL4 (AC) (AM)"; break;
-+		case 0x09: p = "DUAL5 (BC) (AM)"; break;
-+		case 0x0a: p = "SAP"; break;
-+		default: p = "undefined";
-+		}
-+		v4l_info(client, "Configured audio mode:     %s\n", p);
-+	} else {
-+		switch (audio_config & 0xF) {
-+		case 0x00: p = "BG"; break;
-+		case 0x01: p = "DK1"; break;
-+		case 0x02: p = "DK2"; break;
-+		case 0x03: p = "DK3"; break;
-+		case 0x04: p = "I"; break;
-+		case 0x05: p = "L"; break;
-+		case 0x06: p = "BTSC"; break;
-+		case 0x07: p = "EIAJ"; break;
-+		case 0x08: p = "A2-M"; break;
-+		case 0x09: p = "FM Radio"; break;
-+		case 0x0f: p = "automatic standard and mode detection"; break;
-+		default: p = "undefined";
-+		}
-+		v4l_info(client, "Configured audio system:   %s\n", p);
-+	}
++	if (0 != t->index)
++		return -EINVAL;
 +
-+	if (aud_input) {
-+		v4l_info(client, "Specified audio input:     Tuner (In%d)\n", aud_input);
-+	} else {
-+		v4l_info(client, "Specified audio input:     External\n");
-+	}
++	em28xx_i2c_call_clients(dev, VIDIOC_S_TUNER, t);
 +
-+	switch (pref_mode & 0xf) {
-+	case 0: p = "mono/language A"; break;
-+	case 1: p = "language B"; break;
-+	case 2: p = "language C"; break;
-+	case 3: p = "analog fallback"; break;
-+	case 4: p = "stereo"; break;
-+	case 5: p = "language AC"; break;
-+	case 6: p = "language BC"; break;
-+	case 7: p = "language AB"; break;
-+	default: p = "undefined";
-+	}
-+	v4l_info(client, "Preferred audio mode:      %s\n", p);
++	return 0;
++}
 +
-+	if ((audio_config & 0xf) == 0xf) {
-+		switch ((afc0 >> 3) & 0x3) {
-+		case 0: p = "system DK"; break;
-+		case 1: p = "system L"; break;
-+		case 2: p = "autodetect"; break;
-+		default: p = "undefined";
-+		}
-+		v4l_info(client, "Selected 65 MHz format:    %s\n", p);
++static int radio_s_audio(struct file *file, void *fh,
++			 struct v4l2_audio *a)
++{
++	return 0;
++}
 +
-+		switch (afc0 & 0x7) {
-+		case 0: p = "chroma"; break;
-+		case 1: p = "BTSC"; break;
-+		case 2: p = "EIAJ"; break;
-+		case 3: p = "A2-M"; break;
-+		case 4: p = "autodetect"; break;
-+		default: p = "undefined";
-+		}
-+		v4l_info(client, "Selected 45 MHz format:    %s\n", p);
-+	}
++static int radio_s_input(struct file *file, void *fh, unsigned int i)
++{
++	return 0;
 +}
 +
-+/* ----------------------------------------------------------------------- */
++static int radio_queryctrl(struct file *file, void *priv,
++			   struct v4l2_queryctrl *qc)
++{
++	int i;
 +
- static int cx25840_command(struct i2c_client *client, unsigned int cmd,
- 			   void *arg)
- {
-@@ -660,6 +996,8 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd,
- 		state->is_initialized = 1;
- 		if (state->is_cx25836)
- 			cx25836_initialize(client);
-+		else if (state->is_cx23885)
-+			cx23885_initialize(client);
- 		else
- 			cx25840_initialize(client);
- 	}
-@@ -677,6 +1015,7 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd,
- 			return -EINVAL;
- 		if (!capable(CAP_SYS_ADMIN))
- 			return -EPERM;
++	if (qc->id <  V4L2_CID_BASE ||
++		qc->id >= V4L2_CID_LASTP1)
++		return -EINVAL;
 +
- 		if (cmd == VIDIOC_DBG_G_REGISTER)
- 			reg->val = cx25840_read(client, reg->reg & 0x0fff);
- 		else
-@@ -693,14 +1032,26 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd,
- 
- 	case VIDIOC_STREAMON:
- 		v4l_dbg(1, cx25840_debug, client, "enable output\n");
--		cx25840_write(client, 0x115, state->is_cx25836 ? 0x0c : 0x8c);
--		cx25840_write(client, 0x116, state->is_cx25836 ? 0x04 : 0x07);
-+		if (state->is_cx23885) {
-+			u8 v = (cx25840_read(client, 0x421) | 0x0b);
-+			cx25840_write(client, 0x421, v);
-+		} else {
-+			cx25840_write(client, 0x115,
-+				state->is_cx25836 ? 0x0c : 0x8c);
-+			cx25840_write(client, 0x116,
-+				state->is_cx25836 ? 0x04 : 0x07);
-+		}
- 		break;
- 
- 	case VIDIOC_STREAMOFF:
- 		v4l_dbg(1, cx25840_debug, client, "disable output\n");
--		cx25840_write(client, 0x115, 0x00);
--		cx25840_write(client, 0x116, 0x00);
-+		if (state->is_cx23885) {
-+			u8 v = cx25840_read(client, 0x421) & ~(0x0b);
-+			cx25840_write(client, 0x421, v);
-+		} else {
-+			cx25840_write(client, 0x115, 0x00);
-+			cx25840_write(client, 0x116, 0x00);
++	for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) {
++		if (qc->id && qc->id == em28xx_qctrl[i].id) {
++			memcpy(qc, &(em28xx_qctrl[i]), sizeof(*qc));
++			return 0;
 +		}
- 		break;
- 
- 	case VIDIOC_LOG_STATUS:
-@@ -863,6 +1214,8 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd,
- 	case VIDIOC_INT_RESET:
- 		if (state->is_cx25836)
- 			cx25836_initialize(client);
-+		else if (state->is_cx23885)
-+			cx23885_initialize(client);
- 		else
- 			cx25840_initialize(client);
- 		break;
-@@ -879,35 +1232,21 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd,
- 
- /* ----------------------------------------------------------------------- */
- 
--static struct i2c_driver i2c_driver_cx25840;
--
--static int cx25840_detect_client(struct i2c_adapter *adapter, int address,
--				 int kind)
-+static int cx25840_probe(struct i2c_client *client)
- {
--	struct i2c_client *client;
- 	struct cx25840_state *state;
- 	u32 id;
- 	u16 device_id;
- 
--	/* Check if the adapter supports the needed features
--	 * Not until kernel version 2.6.11 did the bit-algo
--	 * correctly report that it would do an I2C-level xfer */
--	if (!i2c_check_functionality(adapter, I2C_FUNC_I2C))
--		return 0;
--
--	client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
--	if (client == 0)
--		return -ENOMEM;
--
--	client->addr = address;
--	client->adapter = adapter;
--	client->driver = &i2c_driver_cx25840;
--	snprintf(client->name, sizeof(client->name) - 1, "cx25840");
-+	/* Check if the adapter supports the needed features */
-+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
-+		return -EIO;
- 
- 	v4l_dbg(1, cx25840_debug, client, "detecting cx25840 client on address 0x%x\n", client->addr << 1);
- 
- 	device_id = cx25840_read(client, 0x101) << 8;
- 	device_id |= cx25840_read(client, 0x100);
-+	v4l_dbg(1, cx25840_debug, client, "device_id = 0x%04x\n", device_id);
- 
- 	/* The high byte of the device ID should be
- 	 * 0x83 for the cx2583x and 0x84 for the cx2584x */
-@@ -916,16 +1255,18 @@ static int cx25840_detect_client(struct i2c_adapter *adapter, int address,
- 	}
- 	else if ((device_id & 0xff00) == 0x8400) {
- 		id = V4L2_IDENT_CX25840 + ((device_id >> 4) & 0xf);
-+	} else if (device_id == 0x0000) {
-+		id = V4L2_IDENT_CX25836 + ((device_id >> 4) & 0xf) - 6;
-+	} else if (device_id == 0x1313) {
-+		id = V4L2_IDENT_CX25836 + ((device_id >> 4) & 0xf) - 6;
- 	}
- 	else {
- 		v4l_dbg(1, cx25840_debug, client, "cx25840 not found\n");
--		kfree(client);
--		return 0;
-+		return -ENODEV;
- 	}
- 
- 	state = kzalloc(sizeof(struct cx25840_state), GFP_KERNEL);
- 	if (state == NULL) {
--		kfree(client);
- 		return -ENOMEM;
- 	}
- 
-@@ -939,6 +1280,7 @@ static int cx25840_detect_client(struct i2c_adapter *adapter, int address,
- 	i2c_set_clientdata(client, state);
- 	state->c = client;
- 	state->is_cx25836 = ((device_id & 0xff00) == 0x8300);
-+	state->is_cx23885 = (device_id == 0x0000) || (device_id == 0x1313);
- 	state->vid_input = CX25840_COMPOSITE7;
- 	state->aud_input = CX25840_AUDIO8;
- 	state->audclk_freq = 48000;
-@@ -949,250 +1291,19 @@ static int cx25840_detect_client(struct i2c_adapter *adapter, int address,
- 	state->id = id;
- 	state->rev = device_id;
- 
--	i2c_attach_client(client);
--
--	return 0;
--}
--
--static int cx25840_attach_adapter(struct i2c_adapter *adapter)
--{
--	if (adapter->class & I2C_CLASS_TV_ANALOG)
--		return i2c_probe(adapter, &addr_data, &cx25840_detect_client);
- 	return 0;
- }
- 
--static int cx25840_detach_client(struct i2c_client *client)
-+static int cx25840_remove(struct i2c_client *client)
- {
--	struct cx25840_state *state = i2c_get_clientdata(client);
--	int err;
--
--	err = i2c_detach_client(client);
--	if (err) {
--		return err;
--	}
--
--	kfree(state);
--	kfree(client);
--
-+	kfree(i2c_get_clientdata(client));
- 	return 0;
++	}
++
++	return -EINVAL;
  }
  
--/* ----------------------------------------------------------------------- */
--
--static struct i2c_driver i2c_driver_cx25840 = {
--	.driver = {
--		.name = "cx25840",
--	},
--	.id = I2C_DRIVERID_CX25840,
--	.attach_adapter = cx25840_attach_adapter,
--	.detach_client = cx25840_detach_client,
-+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
-+	.name = "cx25840",
-+	.driverid = I2C_DRIVERID_CX25840,
- 	.command = cx25840_command,
-+	.probe = cx25840_probe,
-+	.remove = cx25840_remove,
- };
--
--
--static int __init m__init(void)
--{
--	return i2c_add_driver(&i2c_driver_cx25840);
--}
--
--static void __exit m__exit(void)
--{
--	i2c_del_driver(&i2c_driver_cx25840);
--}
--
--module_init(m__init);
--module_exit(m__exit);
--
--/* ----------------------------------------------------------------------- */
--
--static void log_video_status(struct i2c_client *client)
--{
--	static const char *const fmt_strs[] = {
--		"0x0",
--		"NTSC-M", "NTSC-J", "NTSC-4.43",
--		"PAL-BDGHI", "PAL-M", "PAL-N", "PAL-Nc", "PAL-60",
--		"0x9", "0xA", "0xB",
--		"SECAM",
--		"0xD", "0xE", "0xF"
--	};
--
--	struct cx25840_state *state = i2c_get_clientdata(client);
--	u8 vidfmt_sel = cx25840_read(client, 0x400) & 0xf;
--	u8 gen_stat1 = cx25840_read(client, 0x40d);
--	u8 gen_stat2 = cx25840_read(client, 0x40e);
--	int vid_input = state->vid_input;
--
--	v4l_info(client, "Video signal:              %spresent\n",
--		    (gen_stat2 & 0x20) ? "" : "not ");
--	v4l_info(client, "Detected format:           %s\n",
--		    fmt_strs[gen_stat1 & 0xf]);
--
--	v4l_info(client, "Specified standard:        %s\n",
--		    vidfmt_sel ? fmt_strs[vidfmt_sel] : "automatic detection");
--
--	if (vid_input >= CX25840_COMPOSITE1 &&
--	    vid_input <= CX25840_COMPOSITE8) {
--		v4l_info(client, "Specified video input:     Composite %d\n",
--			vid_input - CX25840_COMPOSITE1 + 1);
--	} else {
--		v4l_info(client, "Specified video input:     S-Video (Luma In%d, Chroma In%d)\n",
--			(vid_input & 0xf0) >> 4, (vid_input & 0xf00) >> 8);
--	}
--
--	v4l_info(client, "Specified audioclock freq: %d Hz\n", state->audclk_freq);
--}
--
--/* ----------------------------------------------------------------------- */
--
--static void log_audio_status(struct i2c_client *client)
--{
--	struct cx25840_state *state = i2c_get_clientdata(client);
--	u8 download_ctl = cx25840_read(client, 0x803);
--	u8 mod_det_stat0 = cx25840_read(client, 0x804);
--	u8 mod_det_stat1 = cx25840_read(client, 0x805);
--	u8 audio_config = cx25840_read(client, 0x808);
--	u8 pref_mode = cx25840_read(client, 0x809);
--	u8 afc0 = cx25840_read(client, 0x80b);
--	u8 mute_ctl = cx25840_read(client, 0x8d3);
--	int aud_input = state->aud_input;
--	char *p;
--
--	switch (mod_det_stat0) {
--	case 0x00: p = "mono"; break;
--	case 0x01: p = "stereo"; break;
--	case 0x02: p = "dual"; break;
--	case 0x04: p = "tri"; break;
--	case 0x10: p = "mono with SAP"; break;
--	case 0x11: p = "stereo with SAP"; break;
--	case 0x12: p = "dual with SAP"; break;
--	case 0x14: p = "tri with SAP"; break;
--	case 0xfe: p = "forced mode"; break;
--	default: p = "not defined";
--	}
--	v4l_info(client, "Detected audio mode:       %s\n", p);
--
--	switch (mod_det_stat1) {
--	case 0x00: p = "not defined"; break;
--	case 0x01: p = "EIAJ"; break;
--	case 0x02: p = "A2-M"; break;
--	case 0x03: p = "A2-BG"; break;
--	case 0x04: p = "A2-DK1"; break;
--	case 0x05: p = "A2-DK2"; break;
--	case 0x06: p = "A2-DK3"; break;
--	case 0x07: p = "A1 (6.0 MHz FM Mono)"; break;
--	case 0x08: p = "AM-L"; break;
--	case 0x09: p = "NICAM-BG"; break;
--	case 0x0a: p = "NICAM-DK"; break;
--	case 0x0b: p = "NICAM-I"; break;
--	case 0x0c: p = "NICAM-L"; break;
--	case 0x0d: p = "BTSC/EIAJ/A2-M Mono (4.5 MHz FMMono)"; break;
--	case 0x0e: p = "IF FM Radio"; break;
--	case 0x0f: p = "BTSC"; break;
--	case 0x10: p = "high-deviation FM"; break;
--	case 0x11: p = "very high-deviation FM"; break;
--	case 0xfd: p = "unknown audio standard"; break;
--	case 0xfe: p = "forced audio standard"; break;
--	case 0xff: p = "no detected audio standard"; break;
--	default: p = "not defined";
--	}
--	v4l_info(client, "Detected audio standard:   %s\n", p);
--	v4l_info(client, "Audio muted:               %s\n",
--		    (state->unmute_volume >= 0) ? "yes" : "no");
--	v4l_info(client, "Audio microcontroller:     %s\n",
--		    (download_ctl & 0x10) ?
--				((mute_ctl & 0x2) ? "detecting" : "running") : "stopped");
--
--	switch (audio_config >> 4) {
--	case 0x00: p = "undefined"; break;
--	case 0x01: p = "BTSC"; break;
--	case 0x02: p = "EIAJ"; break;
--	case 0x03: p = "A2-M"; break;
--	case 0x04: p = "A2-BG"; break;
--	case 0x05: p = "A2-DK1"; break;
--	case 0x06: p = "A2-DK2"; break;
--	case 0x07: p = "A2-DK3"; break;
--	case 0x08: p = "A1 (6.0 MHz FM Mono)"; break;
--	case 0x09: p = "AM-L"; break;
--	case 0x0a: p = "NICAM-BG"; break;
--	case 0x0b: p = "NICAM-DK"; break;
--	case 0x0c: p = "NICAM-I"; break;
--	case 0x0d: p = "NICAM-L"; break;
--	case 0x0e: p = "FM radio"; break;
--	case 0x0f: p = "automatic detection"; break;
--	default: p = "undefined";
--	}
--	v4l_info(client, "Configured audio standard: %s\n", p);
--
--	if ((audio_config >> 4) < 0xF) {
--		switch (audio_config & 0xF) {
--		case 0x00: p = "MONO1 (LANGUAGE A/Mono L+R channel for BTSC, EIAJ, A2)"; break;
--		case 0x01: p = "MONO2 (LANGUAGE B)"; break;
--		case 0x02: p = "MONO3 (STEREO forced MONO)"; break;
--		case 0x03: p = "MONO4 (NICAM ANALOG-Language C/Analog Fallback)"; break;
--		case 0x04: p = "STEREO"; break;
--		case 0x05: p = "DUAL1 (AB)"; break;
--		case 0x06: p = "DUAL2 (AC) (FM)"; break;
--		case 0x07: p = "DUAL3 (BC) (FM)"; break;
--		case 0x08: p = "DUAL4 (AC) (AM)"; break;
--		case 0x09: p = "DUAL5 (BC) (AM)"; break;
--		case 0x0a: p = "SAP"; break;
--		default: p = "undefined";
--		}
--		v4l_info(client, "Configured audio mode:     %s\n", p);
--	} else {
--		switch (audio_config & 0xF) {
--		case 0x00: p = "BG"; break;
--		case 0x01: p = "DK1"; break;
--		case 0x02: p = "DK2"; break;
--		case 0x03: p = "DK3"; break;
--		case 0x04: p = "I"; break;
--		case 0x05: p = "L"; break;
--		case 0x06: p = "BTSC"; break;
--		case 0x07: p = "EIAJ"; break;
--		case 0x08: p = "A2-M"; break;
--		case 0x09: p = "FM Radio"; break;
--		case 0x0f: p = "automatic standard and mode detection"; break;
--		default: p = "undefined";
--		}
--		v4l_info(client, "Configured audio system:   %s\n", p);
--	}
--
--	if (aud_input) {
--		v4l_info(client, "Specified audio input:     Tuner (In%d)\n", aud_input);
--	} else {
--		v4l_info(client, "Specified audio input:     External\n");
--	}
--
--	switch (pref_mode & 0xf) {
--	case 0: p = "mono/language A"; break;
--	case 1: p = "language B"; break;
--	case 2: p = "language C"; break;
--	case 3: p = "analog fallback"; break;
--	case 4: p = "stereo"; break;
--	case 5: p = "language AC"; break;
--	case 6: p = "language BC"; break;
--	case 7: p = "language AB"; break;
--	default: p = "undefined";
--	}
--	v4l_info(client, "Preferred audio mode:      %s\n", p);
--
--	if ((audio_config & 0xf) == 0xf) {
--		switch ((afc0 >> 3) & 0x3) {
--		case 0: p = "system DK"; break;
--		case 1: p = "system L"; break;
--		case 2: p = "autodetect"; break;
--		default: p = "undefined";
--		}
--		v4l_info(client, "Selected 65 MHz format:    %s\n", p);
--
--		switch (afc0 & 0x7) {
--		case 0: p = "chroma"; break;
--		case 1: p = "BTSC"; break;
--		case 2: p = "EIAJ"; break;
--		case 3: p = "A2-M"; break;
--		case 4: p = "autodetect"; break;
--		default: p = "undefined";
--		}
--		v4l_info(client, "Selected 45 MHz format:    %s\n", p);
--	}
--}
-diff --git a/drivers/media/video/cx25840/cx25840-core.h b/drivers/media/video/cx25840/cx25840-core.h
-index ea669b1..95093ed 100644
---- a/drivers/media/video/cx25840/cx25840-core.h
-+++ b/drivers/media/video/cx25840/cx25840-core.h
-@@ -47,6 +47,7 @@ struct cx25840_state {
- 	u32 id;
- 	u32 rev;
- 	int is_cx25836;
-+	int is_cx23885;
- 	int is_initialized;
- 	wait_queue_head_t fw_wait;    /* wake up when the fw load is finished */
- 	struct work_struct fw_work;   /* work entry for fw load */
-diff --git a/drivers/media/video/cx25840/cx25840-firmware.c b/drivers/media/video/cx25840/cx25840-firmware.c
-index e852024..1ddf724 100644
---- a/drivers/media/video/cx25840/cx25840-firmware.c
-+++ b/drivers/media/video/cx25840/cx25840-firmware.c
-@@ -24,6 +24,7 @@
- #include "cx25840-core.h"
- 
- #define FWFILE "v4l-cx25840.fw"
-+#define FWFILE_CX23885 "v4l-cx23885-avcore-01.fw"
- 
  /*
-  * Mike Isely <isely at pobox.com> - The FWSEND parameter controls the
-@@ -92,10 +93,14 @@ static int fw_write(struct i2c_client *client, u8 * data, int size)
- 
- int cx25840_loadfw(struct i2c_client *client)
+@@ -252,8 +1258,9 @@ static void video_mux(struct em28xx *dev, int index)
+ static int em28xx_v4l2_open(struct inode *inode, struct file *filp)
  {
-+	struct cx25840_state *state = i2c_get_clientdata(client);
- 	const struct firmware *fw = NULL;
- 	u8 buffer[4], *ptr;
- 	int size, send, retval;
- 
-+	if (state->is_cx23885)
-+		firmware = FWFILE_CX23885;
-+
- 	if (request_firmware(&fw, firmware, FWDEV(client)) != 0) {
- 		v4l_err(client, "unable to open firmware %s\n", firmware);
- 		return -EINVAL;
-diff --git a/drivers/media/video/cx25840/cx25840-vbi.c b/drivers/media/video/cx25840/cx25840-vbi.c
-index ced13fe..6828f59 100644
---- a/drivers/media/video/cx25840/cx25840-vbi.c
-+++ b/drivers/media/video/cx25840/cx25840-vbi.c
-@@ -180,7 +180,7 @@ void cx25840_vbi_setup(struct i2c_client *client)
- 						fsc/1000000,fsc%1000000);
- 
- 		v4l_dbg(1, cx25840_debug, client, "hblank %i, hactive %i, "
--			"vblank %i , vactive %i, vblank656 %i, src_dec %i,"
-+			"vblank %i, vactive %i, vblank656 %i, src_dec %i, "
- 			"burst 0x%02x, luma_lpf %i, uv_lpf %i, comb 0x%02x,"
- 			" sc 0x%06x\n",
- 			hblank, hactive, vblank, vactive, vblank656,
-diff --git a/drivers/media/video/cx88/Kconfig b/drivers/media/video/cx88/Kconfig
-index ceb31d4..49d3813 100644
---- a/drivers/media/video/cx88/Kconfig
-+++ b/drivers/media/video/cx88/Kconfig
-@@ -8,6 +8,7 @@ config VIDEO_CX88
- 	select VIDEO_TUNER
- 	select VIDEO_TVEEPROM
- 	select VIDEO_IR
-+	select VIDEO_WM8775 if VIDEO_HELPER_CHIPS_AUTO
- 	---help---
- 	  This is a video4linux driver for Conexant 2388x based
- 	  TV cards.
-diff --git a/drivers/media/video/cx88/cx88-alsa.c b/drivers/media/video/cx88/cx88-alsa.c
-index 40ffd7a..8735227 100644
---- a/drivers/media/video/cx88/cx88-alsa.c
-+++ b/drivers/media/video/cx88/cx88-alsa.c
-@@ -417,7 +417,7 @@ static int snd_cx88_hw_params(struct snd_pcm_substream * substream,
- 	buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP|RISC_IRQ1|RISC_CNT_INC);
- 	buf->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
- 
--	buf->vb.state = STATE_PREPARED;
-+	buf->vb.state = VIDEOBUF_PREPARED;
- 
- 	chip->buf = buf;
- 	chip->dma_risc = dma;
-diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c
-index f802b56..a99e9d5 100644
---- a/drivers/media/video/cx88/cx88-blackbird.c
-+++ b/drivers/media/video/cx88/cx88-blackbird.c
-@@ -307,7 +307,7 @@ static int register_read(struct cx88_core *core, u32 address, u32 *value)
- 
- /* ------------------------------------------------------------------ */
+ 	int minor = iminor(inode);
+-	int errCode = 0;
++	int errCode = 0, radio = 0;
+ 	struct em28xx *h,*dev = NULL;
++	struct em28xx_fh *fh;
  
--static int blackbird_mbox_func(void *priv, int command, int in, int out, u32 data[CX2341X_MBOX_MAX_DATA])
-+static int blackbird_mbox_func(void *priv, u32 command, int in, int out, u32 data[CX2341X_MBOX_MAX_DATA])
- {
- 	struct cx8802_dev *dev = priv;
- 	unsigned long timeout;
-@@ -536,11 +536,12 @@ static int blackbird_initialize_codec(struct cx8802_dev *dev)
- 	dprintk(1,"Initialize codec\n");
- 	retval = blackbird_api_cmd(dev, CX2341X_ENC_PING_FW, 0, 0); /* ping */
- 	if (retval < 0) {
-+
-+		dev->mpeg_active = 0;
-+
- 		/* ping was not successful, reset and upload firmware */
- 		cx_write(MO_SRST_IO, 0); /* SYS_RSTO=0 */
--		msleep(1);
- 		cx_write(MO_SRST_IO, 1); /* SYS_RSTO=1 */
--		msleep(1);
- 		retval = blackbird_load_firmware(dev);
- 		if (retval < 0)
- 			return retval;
-@@ -562,7 +563,6 @@ static int blackbird_initialize_codec(struct cx8802_dev *dev)
+ 	list_for_each_entry(h, &em28xx_devlist, devlist) {
+ 		if (h->vdev->minor == minor) {
+@@ -264,6 +1271,11 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp)
+ 			dev  = h;
+ 			dev->type = V4L2_BUF_TYPE_VBI_CAPTURE;
  		}
- 		dprintk(0, "Firmware version is 0x%08x\n", version);
++		if (h->radio_dev &&
++		    h->radio_dev->minor == minor) {
++			radio = 1;
++			dev   = h;
++		}
  	}
--	msleep(1);
+ 	if (NULL == dev)
+ 		return -ENODEV;
+@@ -271,23 +1283,18 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp)
+ 	em28xx_videodbg("open minor=%d type=%s users=%d\n",
+ 				minor,v4l2_type_names[dev->type],dev->users);
  
- 	cx_write(MO_PINMUX_IO, 0x88); /* 656-8bit IO and enable MPEG parallel IO */
- 	cx_clear(MO_INPUT_FORMAT, 0x100); /* chroma subcarrier lock to normal? */
-@@ -570,40 +570,68 @@ static int blackbird_initialize_codec(struct cx8802_dev *dev)
- 	cx_clear(MO_OUTPUT_FORMAT, 0x0008); /* Normal Y-limits to let the mpeg encoder sync */
+-	if (!down_read_trylock(&em28xx_disconnect))
+-		return -ERESTARTSYS;
++	fh = kzalloc(sizeof(struct em28xx_fh), GFP_KERNEL);
  
- 	blackbird_codec_settings(dev);
--	msleep(1);
+-	if (dev->users) {
+-		em28xx_warn("this driver can be opened only once\n");
+-		up_read(&em28xx_disconnect);
+-		return -EBUSY;
++	if (!fh) {
++		em28xx_errdev("em28xx-video.c: Out of memory?!\n");
++		return -ENOMEM;
+ 	}
+-
+-	mutex_init(&dev->fileop_lock);	/* to 1 == available */
+-	spin_lock_init(&dev->queue_lock);
+-	init_waitqueue_head(&dev->wait_frame);
+-	init_waitqueue_head(&dev->wait_stream);
+-
+ 	mutex_lock(&dev->lock);
++	fh->dev = dev;
++	fh->radio = radio;
++	filp->private_data = fh;
  
--	/* blackbird_api_cmd(dev, IVTV_API_ASSIGN_NUM_VSYNC_LINES, 4, 0, 0xef, 0xef);
--	   blackbird_api_cmd(dev, IVTV_API_ASSIGN_NUM_VSYNC_LINES, 4, 0, 0xf0, 0xf0);
--	   blackbird_api_cmd(dev, IVTV_API_ASSIGN_NUM_VSYNC_LINES, 4, 0, 0x180, 0x180); */
- 	blackbird_api_cmd(dev, CX2341X_ENC_SET_NUM_VSYNC_LINES, 2, 0,
- 			BLACKBIRD_FIELD1_SAA7115,
- 			BLACKBIRD_FIELD2_SAA7115
- 		);
+-	if (dev->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
++	if (dev->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && dev->users == 0) {
+ 		em28xx_set_alternate(dev);
  
--	/* blackbird_api_cmd(dev, IVTV_API_ASSIGN_PLACEHOLDER, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); */
- 	blackbird_api_cmd(dev, CX2341X_ENC_SET_PLACEHOLDER, 12, 0,
- 			BLACKBIRD_CUSTOM_EXTENSION_USR_DATA,
- 			0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+ 		dev->width = norm_maxw(dev);
+@@ -301,30 +1308,23 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp)
+ 		em28xx_capture_start(dev, 1);
+ 		em28xx_resolution_set(dev);
  
--	/* initialize the video input */
--	blackbird_api_cmd(dev, CX2341X_ENC_INITIALIZE_INPUT, 0, 0);
-+	return 0;
-+}
+-		/* device needs to be initialized before isoc transfer */
+-		video_mux(dev, 0);
  
--	msleep(1);
-+static int blackbird_start_codec(struct file *file, void *priv)
-+{
-+	struct cx8802_dev *dev  = ((struct cx8802_fh *)priv)->dev;
-+	struct cx88_core *core = dev->core;
-+	/* start capturing to the host interface */
-+	u32 reg;
+ 		/* start the transfer */
+ 		errCode = em28xx_init_isoc(dev);
+ 		if (errCode)
+ 			goto err;
  
--	blackbird_api_cmd(dev, CX2341X_ENC_MUTE_VIDEO, 1, 0, BLACKBIRD_UNMUTE);
--	msleep(1);
--	blackbird_api_cmd(dev, CX2341X_ENC_MUTE_AUDIO, 1, 0, BLACKBIRD_UNMUTE);
--	msleep(1);
-+	int i;
-+	int lastchange = -1;
-+	int lastval = 0;
-+
-+	for (i = 0; (i < 10) && (i < (lastchange + 4)); i++) {
-+		reg = cx_read(AUD_STATUS);
-+
-+		dprintk(1, "AUD_STATUS:%dL: 0x%x\n", i, reg);
-+		if ((reg & 0x0F) != lastval) {
-+			lastval = reg & 0x0F;
-+			lastchange = i;
-+		}
-+		msleep(100);
++		em28xx_empty_framequeues(dev);
 +	}
-+
-+	/* unmute audio source */
-+	cx_clear(AUD_VOL_CTL, (1 << 6));
-+
-+	blackbird_api_cmd(dev, CX2341X_ENC_REFRESH_INPUT, 0, 0);
-+
-+	/* initialize the video input */
-+	blackbird_api_cmd(dev, CX2341X_ENC_INITIALIZE_INPUT, 0, 0);
++	if (fh->radio) {
++		em28xx_videodbg("video_open: setting radio device\n");
++		em28xx_i2c_call_clients(dev, AUDC_SET_RADIO, NULL);
+ 	}
  
- 	/* start capturing to the host interface */
--	/* blackbird_api_cmd(dev, CX2341X_ENC_START_CAPTURE, 2, 0, 0, 0x13); */
- 	blackbird_api_cmd(dev, CX2341X_ENC_START_CAPTURE, 2, 0,
- 			BLACKBIRD_MPEG_CAPTURE,
- 			BLACKBIRD_RAW_BITS_NONE
- 		);
--	msleep(10);
+ 	dev->users++;
+-	filp->private_data = dev;
+-	dev->io = IO_NONE;
+-	dev->stream = STREAM_OFF;
+-	dev->num_frames = 0;
+-
+-	/* prepare queues */
+-	em28xx_empty_framequeues(dev);
+-
+-	dev->state |= DEV_INITIALIZED;
  
--	blackbird_api_cmd(dev, CX2341X_ENC_REFRESH_INPUT, 0,0);
-+	dev->mpeg_active = 1;
-+	return 0;
-+}
-+
-+static int blackbird_stop_codec(struct cx8802_dev *dev)
-+{
-+	blackbird_api_cmd(dev, CX2341X_ENC_STOP_CAPTURE, 3, 0,
-+			BLACKBIRD_END_NOW,
-+			BLACKBIRD_MPEG_CAPTURE,
-+			BLACKBIRD_RAW_BITS_NONE
-+		);
-+
-+	dev->mpeg_active = 0;
- 	return 0;
+ err:
+ 	mutex_unlock(&dev->lock);
+-	up_read(&em28xx_disconnect);
+ 	return errCode;
  }
  
-@@ -833,6 +861,10 @@ static int vidioc_s_ext_ctrls (struct file *file, void *priv,
- 
- 	if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
- 		return -EINVAL;
-+
-+	if (dev->mpeg_active)
-+		blackbird_stop_codec(dev);
-+
- 	p = dev->params;
- 	err = cx2341x_ext_ctrls(&p, 0, f, VIDIOC_S_EXT_CTRLS);
- 	if (!err) {
-@@ -864,10 +896,9 @@ static int vidioc_s_frequency (struct file *file, void *priv,
- 	struct cx8802_dev *dev  = fh->dev;
- 	struct cx88_core  *core = dev->core;
- 
--	blackbird_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0,
--				BLACKBIRD_END_NOW,
--				BLACKBIRD_MPEG_CAPTURE,
--				BLACKBIRD_RAW_BITS_NONE);
-+	if (dev->mpeg_active)
-+		blackbird_stop_codec(dev);
-+
- 	cx88_set_freq (core,f);
- 	blackbird_initialize_codec(dev);
- 	cx88_set_scale(dev->core, dev->width, dev->height,
-@@ -1073,15 +1104,11 @@ static int mpeg_open(struct inode *inode, struct file *file)
- static int mpeg_release(struct inode *inode, struct file *file)
+@@ -335,7 +1335,6 @@ err:
+ */
+ static void em28xx_release_resources(struct em28xx *dev)
  {
- 	struct cx8802_fh  *fh  = file->private_data;
--	struct cx8802_dev *dev = NULL;
-+	struct cx8802_dev *dev = fh->dev;
- 	struct cx8802_driver *drv = NULL;
- 
--	/* blackbird_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0, BLACKBIRD_END_NOW, 0, 0x13); */
--	blackbird_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0,
--			BLACKBIRD_END_NOW,
--			BLACKBIRD_MPEG_CAPTURE,
--			BLACKBIRD_RAW_BITS_NONE
--		);
-+	if (dev->mpeg_active)
-+		blackbird_stop_codec(dev);
+-	mutex_lock(&em28xx_sysfs_lock);
  
- 	cx8802_cancel_buffers(fh->dev);
- 	/* stop mpeg capture */
-@@ -1107,6 +1134,10 @@ static ssize_t
- mpeg_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
- {
- 	struct cx8802_fh *fh = file->private_data;
-+	struct cx8802_dev *dev = fh->dev;
-+
-+	if (!dev->mpeg_active)
-+		blackbird_start_codec(file, fh);
+ 	/*FIXME: I2C IR should be disconnected */
  
- 	return videobuf_read_stream(&fh->mpegq, data, count, ppos, 0,
- 				    file->f_flags & O_NONBLOCK);
-@@ -1282,6 +1313,7 @@ static int cx8802_blackbird_probe(struct cx8802_driver *drv)
- 	       core->name);
- 	host_setup(dev->core);
+@@ -343,12 +1342,29 @@ static void em28xx_release_resources(struct em28xx *dev)
+ 				dev->vdev->minor-MINOR_VFL_TYPE_GRABBER_MIN,
+ 				dev->vbi_dev->minor-MINOR_VFL_TYPE_VBI_MIN);
+ 	list_del(&dev->devlist);
+-	video_unregister_device(dev->vdev);
+-	video_unregister_device(dev->vbi_dev);
++	if (dev->radio_dev) {
++		if (-1 != dev->radio_dev->minor)
++			video_unregister_device(dev->radio_dev);
++		else
++			video_device_release(dev->radio_dev);
++		dev->radio_dev = NULL;
++	}
++	if (dev->vbi_dev) {
++		if (-1 != dev->vbi_dev->minor)
++			video_unregister_device(dev->vbi_dev);
++		else
++			video_device_release(dev->vbi_dev);
++		dev->vbi_dev = NULL;
++	}
++	if (dev->vdev) {
++		if (-1 != dev->vdev->minor)
++			video_unregister_device(dev->vdev);
++		else
++			video_device_release(dev->vdev);
++		dev->vdev = NULL;
++	}
+ 	em28xx_i2c_unregister(dev);
+ 	usb_put_dev(dev->udev);
+-	mutex_unlock(&em28xx_sysfs_lock);
+-
  
-+	blackbird_initialize_codec(dev);
- 	blackbird_register_video(dev);
+ 	/* Mark device as unused */
+ 	em28xx_devused&=~(1<<dev->devno);
+@@ -360,34 +1376,42 @@ static void em28xx_release_resources(struct em28xx *dev)
+  */
+ static int em28xx_v4l2_close(struct inode *inode, struct file *filp)
+ {
+-	int errCode;
+-	struct em28xx *dev=filp->private_data;
++	struct em28xx_fh *fh  = filp->private_data;
++	struct em28xx    *dev = fh->dev;
++	int              errCode;
  
- 	/* initial device configuration: needed ? */
-diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c
-index a4eb6a8..e6b7f51 100644
---- a/drivers/media/video/cx88/cx88-cards.c
-+++ b/drivers/media/video/cx88/cx88-cards.c
-@@ -26,6 +26,7 @@
- #include <linux/delay.h>
+ 	em28xx_videodbg("users=%d\n", dev->users);
  
- #include "cx88.h"
-+#include "tea5767.h"
+-	mutex_lock(&dev->lock);
  
- static unsigned int tuner[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET };
- static unsigned int radio[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET };
-@@ -245,6 +246,10 @@ static const struct cx88_board cx88_boards[] = {
- 		}},
- 		.radio = {
- 			 .type   = CX88_RADIO,
-+			 .vmux   = 3,
-+			 .gpio0  = 0x000040bf,
-+			 .gpio1  = 0x000080c0,
-+			 .gpio2  = 0x0000ff20,
- 		},
- 	},
- 	[CX88_BOARD_WINFAST_DV2000] = {
-@@ -297,22 +302,22 @@ static const struct cx88_board cx88_boards[] = {
- 			.type   = CX88_VMUX_TELEVISION,
- 			.vmux   = 0,
- 			.gpio0  = 0x0000bde2,
--			.extadc = 1,
-+			.audioroute = 1,
- 		},{
- 			.type   = CX88_VMUX_COMPOSITE1,
- 			.vmux   = 1,
- 			.gpio0  = 0x0000bde6,
--			.extadc = 1,
-+			.audioroute = 1,
- 		},{
- 			.type   = CX88_VMUX_SVIDEO,
- 			.vmux   = 2,
- 			.gpio0  = 0x0000bde6,
--			.extadc = 1,
-+			.audioroute = 1,
- 		}},
- 		.radio = {
- 			.type   = CX88_RADIO,
- 			.gpio0  = 0x0000bd62,
--			.extadc = 1,
-+			.audioroute = 1,
- 		},
- 		.mpeg           = CX88_MPEG_BLACKBIRD,
- 	},
-@@ -373,7 +378,7 @@ static const struct cx88_board cx88_boards[] = {
- 			.type   = CX88_VMUX_SVIDEO,
- 			.vmux   = 2,
- 			.gpio0  = 0x0000fde6, // 0x0000fda6 L,R RCA audio in?
--			.extadc = 1,
-+			.audioroute = 1,
- 		}},
- 		.radio = {
- 			.type   = CX88_RADIO,
-@@ -544,7 +549,7 @@ static const struct cx88_board cx88_boards[] = {
- 		.input          = {{
- 			.type   = CX88_VMUX_TELEVISION,
- 			.vmux   = 0,
--			.extadc = 1,
-+			.audioroute = 1,
- 		}},
- 		.mpeg           = CX88_MPEG_BLACKBIRD,
- 	},
-@@ -667,22 +672,22 @@ static const struct cx88_board cx88_boards[] = {
- 			.type   = CX88_VMUX_TELEVISION,
- 			.vmux   = 0,
- 			.gpio0  = 0x00009d80,
--			.extadc = 1,
-+			.audioroute = 1,
- 		},{
- 			.type   = CX88_VMUX_COMPOSITE1,
- 			.vmux   = 1,
- 			.gpio0  = 0x00009d76,
--			.extadc = 1,
-+			.audioroute = 1,
- 		},{
- 			.type   = CX88_VMUX_SVIDEO,
- 			.vmux   = 2,
- 			.gpio0  = 0x00009d76,
--			.extadc = 1,
-+			.audioroute = 1,
- 		}},
- 		.radio = {
- 			.type   = CX88_RADIO,
- 			.gpio0  = 0x00009d00,
--			.extadc = 1,
-+			.audioroute = 1,
- 		},
- 		.mpeg           = CX88_MPEG_BLACKBIRD,
- 	},
-@@ -821,23 +826,23 @@ static const struct cx88_board cx88_boards[] = {
- 			.type   = CX88_VMUX_COMPOSITE1,
- 			.vmux   = 0,
- 			.gpio0  = 0x0000cd73,
--			.extadc = 1,
-+			.audioroute = 1,
- 		},{
- 			.type   = CX88_VMUX_SVIDEO,
- 			.vmux   = 1,
- 			.gpio0  = 0x0000cd73,
--			.extadc = 1,
-+			.audioroute = 1,
- 		},{
- 			.type   = CX88_VMUX_TELEVISION,
- 			.vmux   = 3,
- 			.gpio0  = 0x0000cdb3,
--			.extadc = 1,
-+			.audioroute = 1,
- 		}},
- 		.radio = {
- 			.type   = CX88_RADIO,
- 			.vmux   = 2,
- 			.gpio0  = 0x0000cdf3,
--			.extadc = 1,
-+			.audioroute = 1,
- 		},
- 		.mpeg           = CX88_MPEG_BLACKBIRD,
- 	},
-@@ -1105,12 +1110,12 @@ static const struct cx88_board cx88_boards[] = {
- 			.type   = CX88_VMUX_COMPOSITE1,
- 			.vmux   = 1,
- 			.gpio0  = 0x3de6,
--			.extadc = 1,
-+			.audioroute = 1,
- 		},{
- 			.type   = CX88_VMUX_SVIDEO,
- 			.vmux   = 2,
- 			.gpio0  = 0x3de6,
--			.extadc = 1,
-+			.audioroute = 1,
- 		}},
- 		.radio = {
- 			.type   = CX88_RADIO,
-@@ -1335,17 +1340,17 @@ static const struct cx88_board cx88_boards[] = {
- 			.type   = CX88_VMUX_TELEVISION,
- 			.vmux   = 0,
- 			.gpio0	= 0xe780,
--			.extadc = 1,
-+			.audioroute = 1,
- 		},{
- 			.type	= CX88_VMUX_COMPOSITE1,
- 			.vmux	= 1,
- 			.gpio0	= 0xe780,
--			.extadc = 1,
-+			.audioroute = 2,
- 		},{
- 			.type	= CX88_VMUX_SVIDEO,
- 			.vmux	= 2,
- 			.gpio0	= 0xe780,
--			.extadc = 1,
-+			.audioroute = 2,
- 		}},
- 		/* fixme: Add radio support */
- 		.mpeg           = CX88_MPEG_DVB | CX88_MPEG_BLACKBIRD,
-@@ -1370,6 +1375,32 @@ static const struct cx88_board cx88_boards[] = {
- 			.gpio0  = 0x07fa,
- 		}},
- 	},
-+	[CX88_BOARD_PINNACLE_PCTV_HD_800i] = {
-+		.name           = "Pinnacle PCTV HD 800i",
-+		.tuner_type     = TUNER_XC5000,
-+		.radio_type     = UNSET,
-+		.tuner_addr	= ADDR_UNSET,
-+		.radio_addr	= ADDR_UNSET,
-+		.input          = {{
-+			.type   = CX88_VMUX_TELEVISION,
-+			.vmux   = 0,
-+			.gpio0  = 0x04fb,
-+			.gpio1  = 0x10ff,
-+		},{
-+			.type   = CX88_VMUX_COMPOSITE1,
-+			.vmux   = 1,
-+			.gpio0  = 0x04fb,
-+			.gpio1  = 0x10ef,
-+			.audioroute = 1,
-+		},{
-+			.type   = CX88_VMUX_SVIDEO,
-+			.vmux   = 2,
-+			.gpio0  = 0x04fb,
-+			.gpio1  = 0x10ef,
-+			.audioroute = 1,
-+		}},
-+		.mpeg           = CX88_MPEG_DVB,
-+	},
- };
+-	em28xx_uninit_isoc(dev);
++	if (res_check(fh))
++		res_free(fh);
  
- /* ------------------------------------------------------------------ */
-@@ -1679,6 +1710,10 @@ static const struct cx88_subid cx88_subids[] = {
- 		.subvendor = 0x1421,
- 		.subdevice = 0x0390,
- 		.card      = CX88_BOARD_ADSTECH_PTV_390,
-+	},{
-+		.subvendor = 0x11bd,
-+		.subdevice = 0x0051,
-+		.card      = CX88_BOARD_PINNACLE_PCTV_HD_800i,
- 	},
- };
+-	em28xx_release_buffers(dev);
++	mutex_lock(&dev->lock);
  
-@@ -1846,6 +1881,36 @@ static void dvico_fusionhdtv_hybrid_init(struct cx88_core *core)
- }
+-	/* the device is already disconnect, free the remaining resources */
+-	if (dev->state & DEV_DISCONNECTED) {
+-		em28xx_release_resources(dev);
+-		mutex_unlock(&dev->lock);
+-		kfree(dev);
+-		return 0;
+-	}
++	if (dev->users == 1) {
++		em28xx_uninit_isoc(dev);
++		em28xx_release_buffers(dev);
++		dev->io = IO_NONE;
  
- /* ----------------------------------------------------------------------- */
-+/* Tuner callback function. Currently only needed for the Pinnacle 	   *
-+ * PCTV HD 800i with an xc5000 sillicon tuner. This is used for both	   *
-+ * analog tuner attach (tuner-core.c) and dvb tuner attach (cx88-dvb.c)    */
-+
-+int cx88_tuner_callback(void *priv, int command, int arg)
-+{
-+	struct i2c_algo_bit_data *i2c_algo = priv;
-+	struct cx88_core *core = i2c_algo->data;
-+
-+	switch(core->boardnr) {
-+	case CX88_BOARD_PINNACLE_PCTV_HD_800i:
-+		if(command == 0) { /* This is the reset command from xc5000 */
-+			/* Reset XC5000 tuner via SYS_RSTO_pin */
-+			cx_write(MO_SRST_IO, 0);
-+			msleep(10);
-+			cx_write(MO_SRST_IO, 1);
+-	/* set alternate 0 */
+-	dev->alt = 0;
+-	em28xx_videodbg("setting alternate 0\n");
+-	errCode = usb_set_interface(dev->udev, 0, 0);
+-	if (errCode < 0) {
+-		em28xx_errdev ("cannot change alternate number to 0 (error=%i)\n",
+-		     errCode);
+-	}
++		/* the device is already disconnect,
++		   free the remaining resources */
++		if (dev->state & DEV_DISCONNECTED) {
++			em28xx_release_resources(dev);
++			mutex_unlock(&dev->lock);
++			kfree(dev);
 +			return 0;
 +		}
-+		else {
-+			printk(KERN_ERR
-+				"xc5000: unknown tuner callback command.\n");
-+			return -EINVAL;
+ 
++		/* set alternate 0 */
++		dev->alt = 0;
++		em28xx_videodbg("setting alternate 0\n");
++		errCode = usb_set_interface(dev->udev, 0, 0);
++		if (errCode < 0) {
++			em28xx_errdev("cannot change alternate number to "
++					"0 (error=%i)\n", errCode);
 +		}
-+		break;
 +	}
-+	return 0; /* Should never be here */
-+}
-+EXPORT_SYMBOL(cx88_tuner_callback);
-+
-+/* ----------------------------------------------------------------------- */
++	kfree(fh);
+ 	dev->users--;
+ 	wake_up_interruptible_nr(&dev->open, 1);
+ 	mutex_unlock(&dev->lock);
+@@ -405,56 +1429,65 @@ em28xx_v4l2_read(struct file *filp, char __user * buf, size_t count,
+ 	struct em28xx_frame_t *f, *i;
+ 	unsigned long lock_flags;
+ 	int ret = 0;
+-	struct em28xx *dev = filp->private_data;
++	struct em28xx_fh *fh = filp->private_data;
++	struct em28xx *dev = fh->dev;
  
- static void cx88_card_list(struct cx88_core *core, struct pci_dev *pci)
- {
-@@ -1979,6 +2044,23 @@ static void cx88_card_setup(struct cx88_core *core)
- 						core->name, i);
- 		}
- 		break;
-+	case CX88_BOARD_MSI_TVANYWHERE_MASTER:
-+	{
-+		struct v4l2_priv_tun_config tea5767_cfg;
-+		struct tea5767_ctrl ctl;
+-	if (dev->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
++	/* FIXME: read() is not prepared to allow changing the video
++	   resolution while streaming. Seems a bug at em28xx_set_fmt
++	 */
 +
-+		memset(&ctl, 0, sizeof(ctl));
++	if (unlikely(res_get(fh) < 0))
++		return -EBUSY;
 +
-+		ctl.high_cut  = 1;
-+		ctl.st_noise  = 1;
-+		ctl.deemph_75 = 1;
-+		ctl.xtal_freq = TEA5767_HIGH_LO_13MHz;
++	mutex_lock(&dev->lock);
 +
-+		tea5767_cfg.tuner = TUNER_TEA5767;
-+		tea5767_cfg.priv  = &ctl;
++	if (dev->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ 		em28xx_videodbg("V4l2_Buf_type_videocapture is set\n");
+-	}
 +
-+		cx88_call_i2c_clients(core, TUNER_SET_CONFIG, &tea5767_cfg);
-+	}
+ 	if (dev->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
+ 		em28xx_videodbg("V4L2_BUF_TYPE_VBI_CAPTURE is set\n");
+ 		em28xx_videodbg("not supported yet! ...\n");
+ 		if (copy_to_user(buf, "", 1)) {
+-			mutex_unlock(&dev->fileop_lock);
++			mutex_unlock(&dev->lock);
+ 			return -EFAULT;
+ 		}
++		mutex_unlock(&dev->lock);
+ 		return (1);
+ 	}
+ 	if (dev->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) {
+ 		em28xx_videodbg("V4L2_BUF_TYPE_SLICED_VBI_CAPTURE is set\n");
+ 		em28xx_videodbg("not supported yet! ...\n");
+ 		if (copy_to_user(buf, "", 1)) {
+-			mutex_unlock(&dev->fileop_lock);
++			mutex_unlock(&dev->lock);
+ 			return -EFAULT;
+ 		}
++		mutex_unlock(&dev->lock);
+ 		return (1);
  	}
- }
  
-diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c
-index 62e8dd2..01e2ac9 100644
---- a/drivers/media/video/cx88/cx88-core.c
-+++ b/drivers/media/video/cx88/cx88-core.c
-@@ -220,7 +220,7 @@ cx88_free_buffer(struct videobuf_queue *q, struct cx88_buffer *buf)
- 	videobuf_dma_unmap(q, dma);
- 	videobuf_dma_free(dma);
- 	btcx_riscmem_free((struct pci_dev *)q->dev, &buf->risc);
--	buf->vb.state = STATE_NEEDS_INIT;
-+	buf->vb.state = VIDEOBUF_NEEDS_INIT;
- }
+-	if (mutex_lock_interruptible(&dev->fileop_lock))
+-		return -ERESTARTSYS;
+-
+ 	if (dev->state & DEV_DISCONNECTED) {
+ 		em28xx_videodbg("device not present\n");
+-		mutex_unlock(&dev->fileop_lock);
++		mutex_unlock(&dev->lock);
+ 		return -ENODEV;
+ 	}
  
- /* ------------------------------------------------------------------ */
-@@ -538,7 +538,7 @@ void cx88_wakeup(struct cx88_core *core,
- 		do_gettimeofday(&buf->vb.ts);
- 		dprintk(2,"[%p/%d] wakeup reg=%d buf=%d\n",buf,buf->vb.i,
- 			count, buf->count);
--		buf->vb.state = STATE_DONE;
-+		buf->vb.state = VIDEOBUF_DONE;
- 		list_del(&buf->vb.queue);
- 		wake_up(&buf->vb.done);
+ 	if (dev->state & DEV_MISCONFIGURED) {
+ 		em28xx_videodbg("device misconfigured; close and open it again\n");
+-		mutex_unlock(&dev->fileop_lock);
++		mutex_unlock(&dev->lock);
+ 		return -EIO;
  	}
-diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c
-index fce19ca..f7b41eb 100644
---- a/drivers/media/video/cx88/cx88-dvb.c
-+++ b/drivers/media/video/cx88/cx88-dvb.c
-@@ -40,6 +40,8 @@
- #include "cx22702.h"
- #include "or51132.h"
- #include "lgdt330x.h"
-+#include "s5h1409.h"
-+#include "xc5000.h"
- #include "nxt200x.h"
- #include "cx24123.h"
- #include "isl6421.h"
-@@ -371,6 +373,22 @@ static struct cx24123_config kworld_dvbs_100_config = {
- 	.lnb_polarity  = 1,
- };
  
-+static struct s5h1409_config pinnacle_pctv_hd_800i_config = {
-+	.demod_address = 0x32 >> 1,
-+	.output_mode   = S5H1409_PARALLEL_OUTPUT,
-+	.gpio	       = S5H1409_GPIO_ON,
-+	.qam_if	       = 44000,
-+	.inversion     = S5H1409_INVERSION_OFF,
-+	.status_mode   = S5H1409_DEMODLOCKING,
-+	.mpeg_timing   = S5H1409_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK,
-+};
-+
-+static struct xc5000_config pinnacle_pctv_hd_800i_tuner_config = {
-+	.i2c_address	= 0x64,
-+	.if_khz		= 5380,
-+	.tuner_callback	= cx88_tuner_callback,
-+};
-+
- static int dvb_register(struct cx8802_dev *dev)
- {
- 	/* init struct videobuf_dvb */
-@@ -625,6 +643,21 @@ static int dvb_register(struct cx8802_dev *dev)
- 			dev->dvb.frontend->ops.set_voltage = geniatech_dvbs_set_voltage;
- 		}
- 		break;
-+	case CX88_BOARD_PINNACLE_PCTV_HD_800i:
-+		dev->dvb.frontend = dvb_attach(s5h1409_attach,
-+					       &pinnacle_pctv_hd_800i_config,
-+					       &dev->core->i2c_adap);
-+		if (dev->dvb.frontend != NULL) {
-+			/* tuner_config.video_dev must point to
-+			 * i2c_adap.algo_data
-+			 */
-+			pinnacle_pctv_hd_800i_tuner_config.priv =
-+						dev->core->i2c_adap.algo_data;
-+			dvb_attach(xc5000_attach, dev->dvb.frontend,
-+				   &dev->core->i2c_adap,
-+				   &pinnacle_pctv_hd_800i_tuner_config);
-+		}
-+		break;
- 	default:
- 		printk(KERN_ERR "%s/2: The frontend of your DVB/ATSC card isn't supported yet\n",
- 		       dev->core->name);
-diff --git a/drivers/media/video/cx88/cx88-i2c.c b/drivers/media/video/cx88/cx88-i2c.c
-index c8b1c50..566b26a 100644
---- a/drivers/media/video/cx88/cx88-i2c.c
-+++ b/drivers/media/video/cx88/cx88-i2c.c
-@@ -109,26 +109,32 @@ static int attach_inform(struct i2c_client *client)
+ 	if (dev->io == IO_MMAP) {
+ 		em28xx_videodbg ("IO method is set to mmap; close and open"
+ 				" the device again to choose the read method\n");
+-		mutex_unlock(&dev->fileop_lock);
++		mutex_unlock(&dev->lock);
+ 		return -EINVAL;
+ 	}
  
- 	if (core->board.radio_type != UNSET) {
- 		if ((core->board.radio_addr==ADDR_UNSET)||(core->board.radio_addr==client->addr)) {
--			tun_setup.mode_mask = T_RADIO;
--			tun_setup.type = core->board.radio_type;
--			tun_setup.addr = core->board.radio_addr;
--
-+			tun_setup.mode_mask	 = T_RADIO;
-+			tun_setup.type		 = core->board.radio_type;
-+			tun_setup.addr		 = core->board.radio_addr;
-+			tun_setup.tuner_callback = cx88_tuner_callback;
- 			client->driver->command (client, TUNER_SET_TYPE_ADDR, &tun_setup);
+ 	if (dev->io == IO_NONE) {
+ 		if (!em28xx_request_buffers(dev, EM28XX_NUM_READ_FRAMES)) {
+ 			em28xx_errdev("read failed, not enough memory\n");
+-			mutex_unlock(&dev->fileop_lock);
++			mutex_unlock(&dev->lock);
+ 			return -ENOMEM;
  		}
+ 		dev->io = IO_READ;
+@@ -463,13 +1496,13 @@ em28xx_v4l2_read(struct file *filp, char __user * buf, size_t count,
  	}
- 	if (core->board.tuner_type != UNSET) {
- 		if ((core->board.tuner_addr==ADDR_UNSET)||(core->board.tuner_addr==client->addr)) {
  
--			tun_setup.mode_mask = T_ANALOG_TV;
--			tun_setup.type = core->board.tuner_type;
--			tun_setup.addr = core->board.tuner_addr;
--
-+			tun_setup.mode_mask	 = T_ANALOG_TV;
-+			tun_setup.type		 = core->board.tuner_type;
-+			tun_setup.addr		 = core->board.tuner_addr;
-+			tun_setup.tuner_callback = cx88_tuner_callback;
- 			client->driver->command (client,TUNER_SET_TYPE_ADDR, &tun_setup);
+ 	if (!count) {
+-		mutex_unlock(&dev->fileop_lock);
++		mutex_unlock(&dev->lock);
+ 		return 0;
+ 	}
+ 
+ 	if (list_empty(&dev->outqueue)) {
+ 		if (filp->f_flags & O_NONBLOCK) {
+-			mutex_unlock(&dev->fileop_lock);
++			mutex_unlock(&dev->lock);
+ 			return -EAGAIN;
+ 		}
+ 		ret = wait_event_interruptible
+@@ -477,35 +1510,46 @@ em28xx_v4l2_read(struct file *filp, char __user * buf, size_t count,
+ 		     (!list_empty(&dev->outqueue)) ||
+ 		     (dev->state & DEV_DISCONNECTED));
+ 		if (ret) {
+-			mutex_unlock(&dev->fileop_lock);
++			mutex_unlock(&dev->lock);
+ 			return ret;
+ 		}
+ 		if (dev->state & DEV_DISCONNECTED) {
+-			mutex_unlock(&dev->fileop_lock);
++			mutex_unlock(&dev->lock);
+ 			return -ENODEV;
  		}
++		dev->video_bytesread = 0;
  	}
  
--	if (core->board.tda9887_conf)
--		client->driver->command(client, TDA9887_SET_CONFIG, &core->board.tda9887_conf);
-+	if (core->board.tda9887_conf) {
-+		struct v4l2_priv_tun_config tda9887_cfg;
+ 	f = list_entry(dev->outqueue.prev, struct em28xx_frame_t, frame);
+ 
+-	spin_lock_irqsave(&dev->queue_lock, lock_flags);
+-	list_for_each_entry(i, &dev->outqueue, frame)
+-	    i->state = F_UNUSED;
+-	INIT_LIST_HEAD(&dev->outqueue);
+-	spin_unlock_irqrestore(&dev->queue_lock, lock_flags);
+-
+ 	em28xx_queue_unusedframes(dev);
+ 
+ 	if (count > f->buf.length)
+ 		count = f->buf.length;
+ 
+-	if (copy_to_user(buf, f->bufmem, count)) {
+-		mutex_unlock(&dev->fileop_lock);
++	if ((dev->video_bytesread + count) > dev->frame_size)
++		count = dev->frame_size - dev->video_bytesread;
 +
-+		tda9887_cfg.tuner = TUNER_TDA9887;
-+		tda9887_cfg.priv  = &core->board.tda9887_conf;
++	if (copy_to_user(buf, f->bufmem+dev->video_bytesread, count)) {
++		em28xx_err("Error while copying to user\n");
+ 		return -EFAULT;
+ 	}
++	dev->video_bytesread += count;
 +
-+		client->driver->command(client, TUNER_SET_CONFIG, &tda9887_cfg);
++	if (dev->video_bytesread == dev->frame_size) {
++		spin_lock_irqsave(&dev->queue_lock, lock_flags);
++		list_for_each_entry(i, &dev->outqueue, frame)
++				    i->state = F_UNUSED;
++		INIT_LIST_HEAD(&dev->outqueue);
++		spin_unlock_irqrestore(&dev->queue_lock, lock_flags);
++
++		em28xx_queue_unusedframes(dev);
++		dev->video_bytesread = 0;
 +	}
- 	return 0;
++
+ 	*f_pos += count;
+ 
+-	mutex_unlock(&dev->fileop_lock);
++	mutex_unlock(&dev->lock);
+ 
+ 	return count;
  }
+@@ -517,11 +1561,14 @@ em28xx_v4l2_read(struct file *filp, char __user * buf, size_t count,
+ static unsigned int em28xx_v4l2_poll(struct file *filp, poll_table * wait)
+ {
+ 	unsigned int mask = 0;
+-	struct em28xx *dev = filp->private_data;
++	struct em28xx_fh *fh = filp->private_data;
++	struct em28xx *dev = fh->dev;
  
-@@ -176,6 +182,7 @@ static char *i2c_devs[128] = {
- 	[ 0xa0 >> 1 ] = "eeprom",
- 	[ 0xc0 >> 1 ] = "tuner (analog)",
- 	[ 0xc2 >> 1 ] = "tuner (analog/dvb)",
-+	[ 0xc8 >> 1 ] = "xc5000",
- };
+-	if (mutex_lock_interruptible(&dev->fileop_lock))
++	if (unlikely(res_get(fh) < 0))
+ 		return POLLERR;
  
- static void do_i2c_scan(char *name, struct i2c_client *c)
-diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c
-index e52de39..bb0911b 100644
---- a/drivers/media/video/cx88/cx88-input.c
-+++ b/drivers/media/video/cx88/cx88-input.c
-@@ -305,6 +305,11 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
- 		ir->mask_keycode = 0xfa;
- 		ir->polling = 50; /* ms */
- 		break;
-+	case CX88_BOARD_PINNACLE_PCTV_HD_800i:
-+		ir_codes = ir_codes_pinnacle_pctv_hd;
-+		ir_type = IR_TYPE_RC5;
-+		ir->sampling = 1;
-+		break;
++	mutex_lock(&dev->lock);
++
+ 	if (dev->state & DEV_DISCONNECTED) {
+ 		em28xx_videodbg("device not present\n");
+ 	} else if (dev->state & DEV_MISCONFIGURED) {
+@@ -545,83 +1592,61 @@ static unsigned int em28xx_v4l2_poll(struct file *filp, poll_table * wait)
+ 			if (!list_empty(&dev->outqueue))
+ 				mask |= POLLIN | POLLRDNORM;
+ 
+-			mutex_unlock(&dev->fileop_lock);
++			mutex_unlock(&dev->lock);
+ 
+ 			return mask;
+ 		}
  	}
  
- 	if (NULL == ir_codes) {
-@@ -443,6 +448,7 @@ void cx88_ir_irq(struct cx88_core *core)
- 	case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1:
- 	case CX88_BOARD_HAUPPAUGE_HVR1100:
- 	case CX88_BOARD_HAUPPAUGE_HVR3000:
-+	case CX88_BOARD_PINNACLE_PCTV_HD_800i:
- 		ircode = ir_decode_biphase(ir->samples, ir->scount, 5, 7);
- 		ir_dprintk("biphase decoded: %x\n", ircode);
- 		if ((ircode & 0xfffff000) != 0x3000)
-diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c
-index 448c673..0aedbea 100644
---- a/drivers/media/video/cx88/cx88-mpeg.c
-+++ b/drivers/media/video/cx88/cx88-mpeg.c
-@@ -102,7 +102,7 @@ static int cx8802_start_dma(struct cx8802_dev    *dev,
- 		cx_write(TS_GEN_CNTRL, 0x0040 | dev->ts_gen_cntrl);
- 		udelay(100);
- 		cx_write(MO_PINMUX_IO, 0x00);
--		cx_write(TS_HW_SOP_CNTRL,0x47<<16|188<<4|0x01);
-+		cx_write(TS_HW_SOP_CNTRL, 0x47<<16|188<<4|0x01);
- 		switch (core->boardnr) {
- 		case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q:
- 		case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T:
-@@ -117,6 +117,15 @@ static int cx8802_start_dma(struct cx8802_dev    *dev,
- 			break;
- 		case CX88_BOARD_HAUPPAUGE_HVR1300:
- 			break;
-+		case CX88_BOARD_PINNACLE_PCTV_HD_800i:
-+			/* Enable MPEG parallel IO and video signal pins */
-+			cx_write(MO_PINMUX_IO, 0x88);
-+			cx_write(TS_HW_SOP_CNTRL, (0x47 << 16) | (188 << 4));
-+			dev->ts_gen_cntrl = 5;
-+			cx_write(TS_SOP_STAT, 0);
-+			cx_write(TS_VALERR_CNTRL, 0);
-+			udelay(100);
-+			break;
- 		default:
- 			cx_write(TS_SOP_STAT, 0x00);
- 			break;
-@@ -195,7 +204,7 @@ static int cx8802_restart_queue(struct cx8802_dev    *dev,
- 				list_del(&buf->vb.queue);
- 				list_add_tail(&buf->vb.queue,&q->active);
- 				cx8802_start_dma(dev, q, buf);
--				buf->vb.state = STATE_ACTIVE;
-+				buf->vb.state = VIDEOBUF_ACTIVE;
- 				buf->count    = q->count++;
- 				mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
- 				dprintk(1,"[%p/%d] restart_queue - first active\n",
-@@ -206,7 +215,7 @@ static int cx8802_restart_queue(struct cx8802_dev    *dev,
- 				   prev->fmt       == buf->fmt) {
- 				list_del(&buf->vb.queue);
- 				list_add_tail(&buf->vb.queue,&q->active);
--				buf->vb.state = STATE_ACTIVE;
-+				buf->vb.state = VIDEOBUF_ACTIVE;
- 				buf->count    = q->count++;
- 				prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
- 				dprintk(1,"[%p/%d] restart_queue - move to active\n",
-@@ -242,7 +251,7 @@ int cx8802_buf_prepare(struct videobuf_queue *q, struct cx8802_dev *dev,
- 	if (0 != buf->vb.baddr  &&  buf->vb.bsize < size)
+-	mutex_unlock(&dev->fileop_lock);
++	mutex_unlock(&dev->lock);
+ 	return POLLERR;
+ }
+ 
+ /*
+- * em28xx_vm_open()
+- */
+-static void em28xx_vm_open(struct vm_area_struct *vma)
+-{
+-	struct em28xx_frame_t *f = vma->vm_private_data;
+-	f->vma_use_count++;
+-}
+-
+-/*
+- * em28xx_vm_close()
+- */
+-static void em28xx_vm_close(struct vm_area_struct *vma)
+-{
+-	/* NOTE: buffers are not freed here */
+-	struct em28xx_frame_t *f = vma->vm_private_data;
+-
+-	if (f->vma_use_count)
+-		f->vma_use_count--;
+-}
+-
+-static struct vm_operations_struct em28xx_vm_ops = {
+-	.open = em28xx_vm_open,
+-	.close = em28xx_vm_close,
+-};
+-
+-/*
+  * em28xx_v4l2_mmap()
+  */
+ static int em28xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma)
+ {
+-	unsigned long size = vma->vm_end - vma->vm_start,
+-	    start = vma->vm_start;
+-	void *pos;
+-	u32 i;
+-
+-	struct em28xx *dev = filp->private_data;
++	struct em28xx_fh *fh    = filp->private_data;
++	struct em28xx	 *dev   = fh->dev;
++	unsigned long	 size   = vma->vm_end - vma->vm_start;
++	unsigned long	 start  = vma->vm_start;
++	void 		 *pos;
++	u32		 i;
++
++	if (unlikely(res_get(fh) < 0))
++		return -EBUSY;
+ 
+-	if (mutex_lock_interruptible(&dev->fileop_lock))
+-		return -ERESTARTSYS;
++	mutex_lock(&dev->lock);
+ 
+ 	if (dev->state & DEV_DISCONNECTED) {
+ 		em28xx_videodbg("mmap: device not present\n");
+-		mutex_unlock(&dev->fileop_lock);
++		mutex_unlock(&dev->lock);
+ 		return -ENODEV;
+ 	}
+ 
+ 	if (dev->state & DEV_MISCONFIGURED) {
+ 		em28xx_videodbg ("mmap: Device is misconfigured; close and "
+ 						"open it again\n");
+-		mutex_unlock(&dev->fileop_lock);
++		mutex_unlock(&dev->lock);
+ 		return -EIO;
+ 	}
+ 
+-	if (dev->io != IO_MMAP || !(vma->vm_flags & VM_WRITE) ||
+-	    size != PAGE_ALIGN(dev->frame[0].buf.length)) {
+-		mutex_unlock(&dev->fileop_lock);
++	if (dev->io != IO_MMAP || !(vma->vm_flags & VM_WRITE)) {
++		mutex_unlock(&dev->lock);
  		return -EINVAL;
+ 	}
  
--	if (STATE_NEEDS_INIT == buf->vb.state) {
-+	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
- 		buf->vb.width  = dev->ts_packet_size;
- 		buf->vb.height = dev->ts_packet_count;
- 		buf->vb.size   = size;
-@@ -254,7 +263,7 @@ int cx8802_buf_prepare(struct videobuf_queue *q, struct cx8802_dev *dev,
- 				     dma->sglist,
- 				     buf->vb.width, buf->vb.height, 0);
++	if (size > PAGE_ALIGN(dev->frame[0].buf.length))
++		size = PAGE_ALIGN(dev->frame[0].buf.length);
++
+ 	for (i = 0; i < dev->num_frames; i++) {
+ 		if ((dev->frame[i].buf.m.offset >> PAGE_SHIFT) == vma->vm_pgoff)
+ 			break;
  	}
--	buf->vb.state = STATE_PREPARED;
-+	buf->vb.state = VIDEOBUF_PREPARED;
+ 	if (i == dev->num_frames) {
+ 		em28xx_videodbg("mmap: user supplied mapping address is out of range\n");
+-		mutex_unlock(&dev->fileop_lock);
++		mutex_unlock(&dev->lock);
+ 		return -EINVAL;
+ 	}
+ 
+@@ -633,7 +1658,7 @@ static int em28xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma)
+ 	while (size > 0) {	/* size is page-aligned */
+ 		if (vm_insert_page(vma, start, vmalloc_to_page(pos))) {
+ 			em28xx_videodbg("mmap: vm_insert_page failed\n");
+-			mutex_unlock(&dev->fileop_lock);
++			mutex_unlock(&dev->lock);
+ 			return -EAGAIN;
+ 		}
+ 		start += PAGE_SIZE;
+@@ -645,900 +1670,210 @@ static int em28xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma)
+ 	vma->vm_private_data = &dev->frame[i];
+ 
+ 	em28xx_vm_open(vma);
+-	mutex_unlock(&dev->fileop_lock);
+-	return 0;
+-}
+-
+-/*
+- * em28xx_get_ctrl()
+- * return the current saturation, brightness or contrast, mute state
+- */
+-static int em28xx_get_ctrl(struct em28xx *dev, struct v4l2_control *ctrl)
+-{
+-	switch (ctrl->id) {
+-	case V4L2_CID_AUDIO_MUTE:
+-		ctrl->value = dev->mute;
+-		return 0;
+-	case V4L2_CID_AUDIO_VOLUME:
+-		ctrl->value = dev->volume;
+-		return 0;
+-	default:
+-		return -EINVAL;
+-	}
+-}
+-
+-/*
+- * em28xx_set_ctrl()
+- * mute or set new saturation, brightness or contrast
+- */
+-static int em28xx_set_ctrl(struct em28xx *dev, const struct v4l2_control *ctrl)
+-{
+-	switch (ctrl->id) {
+-	case V4L2_CID_AUDIO_MUTE:
+-		if (ctrl->value != dev->mute) {
+-			dev->mute = ctrl->value;
+-			em28xx_audio_usb_mute(dev, ctrl->value);
+-			return em28xx_audio_analog_set(dev);
+-		}
+-		return 0;
+-	case V4L2_CID_AUDIO_VOLUME:
+-		dev->volume = ctrl->value;
+-		return em28xx_audio_analog_set(dev);
+-	default:
+-		return -EINVAL;
+-	}
+-}
+-
+-/*
+- * em28xx_stream_interrupt()
+- * stops streaming
+- */
+-static int em28xx_stream_interrupt(struct em28xx *dev)
+-{
+-	int ret = 0;
+-
+-	/* stop reading from the device */
+-
+-	dev->stream = STREAM_INTERRUPT;
+-	ret = wait_event_timeout(dev->wait_stream,
+-				 (dev->stream == STREAM_OFF) ||
+-				 (dev->state & DEV_DISCONNECTED),
+-				 EM28XX_URB_TIMEOUT);
+-	if (dev->state & DEV_DISCONNECTED)
+-		return -ENODEV;
+-	else if (ret) {
+-		dev->state |= DEV_MISCONFIGURED;
+-		em28xx_videodbg("device is misconfigured; close and "
+-			"open /dev/video%d again\n",
+-				dev->vdev->minor-MINOR_VFL_TYPE_GRABBER_MIN);
+-		return ret;
+-	}
+-
+-	return 0;
+-}
+-
+-static int em28xx_set_norm(struct em28xx *dev, int width, int height)
+-{
+-	unsigned int hscale, vscale;
+-	unsigned int maxh, maxw;
+-
+-	maxw = norm_maxw(dev);
+-	maxh = norm_maxh(dev);
+-
+-	/* width must even because of the YUYV format */
+-	/* height must be even because of interlacing */
+-	height &= 0xfffe;
+-	width &= 0xfffe;
+-
+-	if (height < 32)
+-		height = 32;
+-	if (height > maxh)
+-		height = maxh;
+-	if (width < 48)
+-		width = 48;
+-	if (width > maxw)
+-		width = maxw;
+-
+-	if ((hscale = (((unsigned long)maxw) << 12) / width - 4096L) >= 0x4000)
+-		hscale = 0x3fff;
+-	width = (((unsigned long)maxw) << 12) / (hscale + 4096L);
+-
+-	if ((vscale = (((unsigned long)maxh) << 12) / height - 4096L) >= 0x4000)
+-		vscale = 0x3fff;
+-	height = (((unsigned long)maxh) << 12) / (vscale + 4096L);
+-
+-	/* set new image size */
+-	dev->width = width;
+-	dev->height = height;
+-	dev->frame_size = dev->width * dev->height * 2;
+-	dev->field_size = dev->frame_size >> 1;	/*both_fileds ? dev->frame_size>>1 : dev->frame_size; */
+-	dev->bytesperline = dev->width * 2;
+-	dev->hscale = hscale;
+-	dev->vscale = vscale;
+-
+-	em28xx_resolution_set(dev);
+-
++	mutex_unlock(&dev->lock);
  	return 0;
- 
-  fail:
-@@ -276,7 +285,7 @@ void cx8802_buf_queue(struct cx8802_dev *dev, struct cx88_buffer *buf)
- 		dprintk( 1, "queue is empty - first active\n" );
- 		list_add_tail(&buf->vb.queue,&cx88q->active);
- 		cx8802_start_dma(dev, cx88q, buf);
--		buf->vb.state = STATE_ACTIVE;
-+		buf->vb.state = VIDEOBUF_ACTIVE;
- 		buf->count    = cx88q->count++;
- 		mod_timer(&cx88q->timeout, jiffies+BUFFER_TIMEOUT);
- 		dprintk(1,"[%p/%d] %s - first active\n",
-@@ -286,7 +295,7 @@ void cx8802_buf_queue(struct cx8802_dev *dev, struct cx88_buffer *buf)
- 		dprintk( 1, "queue is not empty - append to active\n" );
- 		prev = list_entry(cx88q->active.prev, struct cx88_buffer, vb.queue);
- 		list_add_tail(&buf->vb.queue,&cx88q->active);
--		buf->vb.state = STATE_ACTIVE;
-+		buf->vb.state = VIDEOBUF_ACTIVE;
- 		buf->count    = cx88q->count++;
- 		prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
- 		dprintk( 1, "[%p/%d] %s - append to active\n",
-@@ -306,7 +315,7 @@ static void do_cancel_buffers(struct cx8802_dev *dev, char *reason, int restart)
- 	while (!list_empty(&q->active)) {
- 		buf = list_entry(q->active.next, struct cx88_buffer, vb.queue);
- 		list_del(&buf->vb.queue);
--		buf->vb.state = STATE_ERROR;
-+		buf->vb.state = VIDEOBUF_ERROR;
- 		wake_up(&buf->vb.done);
- 		dprintk(1,"[%p/%d] %s - dma=0x%08lx\n",
- 			buf, buf->vb.i, reason, (unsigned long)buf->risc.dma);
-@@ -437,10 +446,7 @@ static irqreturn_t cx8802_irq(int irq, void *dev_id)
- 	return IRQ_RETVAL(handled);
  }
  
--/* ----------------------------------------------------------- */
--/* exported stuff                                              */
+-static int em28xx_get_fmt(struct em28xx *dev, struct v4l2_format *format)
+-{
+-	em28xx_videodbg("VIDIOC_G_FMT: type=%s\n",
+-		(format->type ==V4L2_BUF_TYPE_VIDEO_CAPTURE) ?
+-		"V4L2_BUF_TYPE_VIDEO_CAPTURE" :
+-		(format->type ==V4L2_BUF_TYPE_VBI_CAPTURE) ?
+-		"V4L2_BUF_TYPE_VBI_CAPTURE" :
+-		(format->type ==V4L2_CAP_SLICED_VBI_CAPTURE) ?
+-		"V4L2_BUF_TYPE_SLICED_VBI_CAPTURE " :
+-		"not supported");
 -
--int cx8802_init_common(struct cx8802_dev *dev)
-+static int cx8802_init_common(struct cx8802_dev *dev)
- {
- 	struct cx88_core *core = dev->core;
- 	int err;
-@@ -488,7 +494,7 @@ int cx8802_init_common(struct cx8802_dev *dev)
- 	return 0;
- }
+-	switch (format->type) {
+-	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+-	{
+-		format->fmt.pix.width = dev->width;
+-		format->fmt.pix.height = dev->height;
+-		format->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
+-		format->fmt.pix.bytesperline = dev->bytesperline;
+-		format->fmt.pix.sizeimage = dev->frame_size;
+-		format->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+-		format->fmt.pix.field = dev->interlaced ? V4L2_FIELD_INTERLACED : V4L2_FIELD_TOP;	/* FIXME: TOP? NONE? BOTTOM? ALTENATE? */
++static const struct file_operations em28xx_v4l_fops = {
++	.owner         = THIS_MODULE,
++	.open          = em28xx_v4l2_open,
++	.release       = em28xx_v4l2_close,
++	.read          = em28xx_v4l2_read,
++	.poll          = em28xx_v4l2_poll,
++	.mmap          = em28xx_v4l2_mmap,
++	.ioctl	       = video_ioctl2,
++	.llseek        = no_llseek,
++	.compat_ioctl  = v4l_compat_ioctl32,
++};
  
--void cx8802_fini_common(struct cx8802_dev *dev)
-+static void cx8802_fini_common(struct cx8802_dev *dev)
- {
- 	dprintk( 2, "cx8802_fini_common\n" );
- 	cx8802_stop_dma(dev);
-@@ -504,7 +510,7 @@ void cx8802_fini_common(struct cx8802_dev *dev)
+-		em28xx_videodbg("VIDIOC_G_FMT: %dx%d\n", dev->width,
+-			dev->height);
+-		break;
+-	}
++static const struct file_operations radio_fops = {
++	.owner         = THIS_MODULE,
++	.open          = em28xx_v4l2_open,
++	.release       = em28xx_v4l2_close,
++	.ioctl	       = video_ioctl2,
++	.compat_ioctl  = v4l_compat_ioctl32,
++	.llseek        = no_llseek,
++};
  
- /* ----------------------------------------------------------- */
+-	case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+-	{
+-		format->fmt.sliced.service_set=0;
++static const struct video_device em28xx_video_template = {
++	.fops                       = &em28xx_v4l_fops,
++	.release                    = video_device_release,
++
++	.minor                      = -1,
++	.vidioc_querycap            = vidioc_querycap,
++	.vidioc_enum_fmt_cap        = vidioc_enum_fmt_cap,
++	.vidioc_g_fmt_cap           = vidioc_g_fmt_cap,
++	.vidioc_try_fmt_cap         = vidioc_try_fmt_cap,
++	.vidioc_s_fmt_cap           = vidioc_s_fmt_cap,
++	.vidioc_g_audio             = vidioc_g_audio,
++	.vidioc_s_audio             = vidioc_s_audio,
++	.vidioc_cropcap             = vidioc_cropcap,
++
++	.vidioc_g_fmt_vbi_capture   = vidioc_g_fmt_vbi_capture,
++	.vidioc_try_fmt_vbi_capture = vidioc_try_set_vbi_capture,
++	.vidioc_s_fmt_vbi_capture   = vidioc_try_set_vbi_capture,
++
++	.vidioc_reqbufs             = vidioc_reqbufs,
++	.vidioc_querybuf            = vidioc_querybuf,
++	.vidioc_qbuf                = vidioc_qbuf,
++	.vidioc_dqbuf               = vidioc_dqbuf,
++	.vidioc_s_std               = vidioc_s_std,
++	.vidioc_enum_input          = vidioc_enum_input,
++	.vidioc_g_input             = vidioc_g_input,
++	.vidioc_s_input             = vidioc_s_input,
++	.vidioc_queryctrl           = vidioc_queryctrl,
++	.vidioc_g_ctrl              = vidioc_g_ctrl,
++	.vidioc_s_ctrl              = vidioc_s_ctrl,
++	.vidioc_streamon            = vidioc_streamon,
++	.vidioc_streamoff           = vidioc_streamoff,
++	.vidioc_g_tuner             = vidioc_g_tuner,
++	.vidioc_s_tuner             = vidioc_s_tuner,
++	.vidioc_g_frequency         = vidioc_g_frequency,
++	.vidioc_s_frequency         = vidioc_s_frequency,
++
++	.tvnorms                    = V4L2_STD_ALL,
++	.current_norm               = V4L2_STD_PAL,
++};
  
--int cx8802_suspend_common(struct pci_dev *pci_dev, pm_message_t state)
-+static int cx8802_suspend_common(struct pci_dev *pci_dev, pm_message_t state)
- {
- 	struct cx8802_dev *dev = pci_get_drvdata(pci_dev);
- 	struct cx88_core *core = dev->core;
-@@ -530,7 +536,7 @@ int cx8802_suspend_common(struct pci_dev *pci_dev, pm_message_t state)
- 	return 0;
- }
+-		em28xx_i2c_call_clients(dev,VIDIOC_G_FMT,format);
++static struct video_device em28xx_radio_template = {
++	.name                 = "em28xx-radio",
++	.type                 = VID_TYPE_TUNER,
++	.fops                 = &radio_fops,
++	.minor                = -1,
++	.vidioc_querycap      = radio_querycap,
++	.vidioc_g_tuner       = radio_g_tuner,
++	.vidioc_enum_input    = radio_enum_input,
++	.vidioc_g_audio       = radio_g_audio,
++	.vidioc_s_tuner       = radio_s_tuner,
++	.vidioc_s_audio       = radio_s_audio,
++	.vidioc_s_input       = radio_s_input,
++	.vidioc_queryctrl     = radio_queryctrl,
++	.vidioc_g_ctrl        = vidioc_g_ctrl,
++	.vidioc_s_ctrl        = vidioc_s_ctrl,
++	.vidioc_g_frequency   = vidioc_g_frequency,
++	.vidioc_s_frequency   = vidioc_s_frequency,
++};
  
--int cx8802_resume_common(struct pci_dev *pci_dev)
-+static int cx8802_resume_common(struct pci_dev *pci_dev)
+-		if (format->fmt.sliced.service_set==0)
+-			return -EINVAL;
++/******************************** usb interface *****************************************/
+ 
+-		break;
+-	}
+ 
+-	default:
+-		return -EINVAL;
+-	}
+-	return (0);
+-}
++static LIST_HEAD(em28xx_extension_devlist);
++static DEFINE_MUTEX(em28xx_extension_devlist_lock);
+ 
+-static int em28xx_set_fmt(struct em28xx *dev, unsigned int cmd, struct v4l2_format *format)
++int em28xx_register_extension(struct em28xx_ops *ops)
  {
- 	struct cx8802_dev *dev = pci_get_drvdata(pci_dev);
- 	struct cx88_core *core = dev->core;
-@@ -874,9 +880,6 @@ EXPORT_SYMBOL(cx8802_buf_prepare);
- EXPORT_SYMBOL(cx8802_buf_queue);
- EXPORT_SYMBOL(cx8802_cancel_buffers);
+-	u32 i;
+-	int ret = 0;
+-	int width = format->fmt.pix.width;
+-	int height = format->fmt.pix.height;
+-	unsigned int hscale, vscale;
+-	unsigned int maxh, maxw;
++	struct em28xx *h, *dev = NULL;
  
--EXPORT_SYMBOL(cx8802_init_common);
--EXPORT_SYMBOL(cx8802_fini_common);
+-	maxw = norm_maxw(dev);
+-	maxh = norm_maxh(dev);
 -
- EXPORT_SYMBOL(cx8802_register_driver);
- EXPORT_SYMBOL(cx8802_unregister_driver);
- EXPORT_SYMBOL(cx8802_get_driver);
-diff --git a/drivers/media/video/cx88/cx88-vbi.c b/drivers/media/video/cx88/cx88-vbi.c
-index babb085..d96ecfc 100644
---- a/drivers/media/video/cx88/cx88-vbi.c
-+++ b/drivers/media/video/cx88/cx88-vbi.c
-@@ -130,7 +130,7 @@ void cx8800_vbi_timeout(unsigned long data)
- 	while (!list_empty(&q->active)) {
- 		buf = list_entry(q->active.next, struct cx88_buffer, vb.queue);
- 		list_del(&buf->vb.queue);
--		buf->vb.state = STATE_ERROR;
-+		buf->vb.state = VIDEOBUF_ERROR;
- 		wake_up(&buf->vb.done);
- 		printk("%s/0: [%p/%d] timeout - dma=0x%08lx\n", dev->core->name,
- 		       buf, buf->vb.i, (unsigned long)buf->risc.dma);
-@@ -168,7 +168,7 @@ vbi_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
- 	if (0 != buf->vb.baddr  &&  buf->vb.bsize < size)
- 		return -EINVAL;
+-	em28xx_videodbg("%s: type=%s\n",
+-			cmd == VIDIOC_TRY_FMT ?
+-			"VIDIOC_TRY_FMT" : "VIDIOC_S_FMT",
+-			format->type == V4L2_BUF_TYPE_VIDEO_CAPTURE ?
+-			"V4L2_BUF_TYPE_VIDEO_CAPTURE" :
+-			format->type == V4L2_BUF_TYPE_VBI_CAPTURE ?
+-			"V4L2_BUF_TYPE_VBI_CAPTURE " :
+-			"not supported");
+-
+-	if (format->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) {
+-		em28xx_i2c_call_clients(dev,VIDIOC_G_FMT,format);
+-
+-		if (format->fmt.sliced.service_set==0)
+-			return -EINVAL;
++	list_for_each_entry(h, &em28xx_devlist, devlist)
++		dev = h;
  
--	if (STATE_NEEDS_INIT == buf->vb.state) {
-+	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
- 		struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
- 		buf->vb.width  = VBI_LINE_LENGTH;
- 		buf->vb.height = VBI_LINE_COUNT;
-@@ -183,7 +183,7 @@ vbi_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
- 				 buf->vb.width, 0,
- 				 buf->vb.height);
- 	}
--	buf->vb.state = STATE_PREPARED;
-+	buf->vb.state = VIDEOBUF_PREPARED;
- 	return 0;
+-		return 0;
+-	}
++	mutex_lock(&em28xx_extension_devlist_lock);
++	list_add_tail(&ops->next, &em28xx_extension_devlist);
++	if (dev)
++		ops->init(dev);
  
-  fail:
-@@ -207,7 +207,7 @@ vbi_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
- 	if (list_empty(&q->active)) {
- 		list_add_tail(&buf->vb.queue,&q->active);
- 		cx8800_start_vbi_dma(dev, q, buf);
--		buf->vb.state = STATE_ACTIVE;
-+		buf->vb.state = VIDEOBUF_ACTIVE;
- 		buf->count    = q->count++;
- 		mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
- 		dprintk(2,"[%p/%d] vbi_queue - first active\n",
-@@ -216,7 +216,7 @@ vbi_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
- 	} else {
- 		prev = list_entry(q->active.prev, struct cx88_buffer, vb.queue);
- 		list_add_tail(&buf->vb.queue,&q->active);
--		buf->vb.state = STATE_ACTIVE;
-+		buf->vb.state = VIDEOBUF_ACTIVE;
- 		buf->count    = q->count++;
- 		prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
- 		dprintk(2,"[%p/%d] buffer_queue - append to active\n",
-diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c
-index c84dafb..7f1931a 100644
---- a/drivers/media/video/cx88/cx88-video.c
-+++ b/drivers/media/video/cx88/cx88-video.c
-@@ -392,13 +392,41 @@ int cx88_video_mux(struct cx88_core *core, unsigned int input)
- 		break;
- 	}
+-
+-	if (format->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+-		return -EINVAL;
+-
+-	em28xx_videodbg("%s: requested %dx%d\n",
+-		cmd == VIDIOC_TRY_FMT ?
+-		"VIDIOC_TRY_FMT" : "VIDIOC_S_FMT",
+-		format->fmt.pix.width, format->fmt.pix.height);
+-
+-	/* FIXME: Move some code away from here */
+-	/* width must even because of the YUYV format */
+-	/* height must be even because of interlacing */
+-	height &= 0xfffe;
+-	width &= 0xfffe;
+-
+-	if (height < 32)
+-		height = 32;
+-	if (height > maxh)
+-		height = maxh;
+-	if (width < 48)
+-		width = 48;
+-	if (width > maxw)
+-		width = maxw;
+-
+-	if(dev->is_em2800){
+-		/* the em2800 can only scale down to 50% */
+-		if(height % (maxh / 2))
+-			height=maxh;
+-		if(width % (maxw / 2))
+-			width=maxw;
+-		/* according to empiatech support */
+-		/* the MaxPacketSize is to small to support */
+-		/* framesizes larger than 640x480 @ 30 fps */
+-		/* or 640x576 @ 25 fps. As this would cut */
+-		/* of a part of the image we prefer */
+-		/* 360x576 or 360x480 for now */
+-		if(width == maxw && height == maxh)
+-			width /= 2;
+-	}
+-
+-	if ((hscale = (((unsigned long)maxw) << 12) / width - 4096L) >= 0x4000)
+-		hscale = 0x3fff;
+-
+-	width = (((unsigned long)maxw) << 12) / (hscale + 4096L);
+-
+-	if ((vscale = (((unsigned long)maxh) << 12) / height - 4096L) >= 0x4000)
+-		vscale = 0x3fff;
+-
+-	height = (((unsigned long)maxh) << 12) / (vscale + 4096L);
+-
+-	format->fmt.pix.width = width;
+-	format->fmt.pix.height = height;
+-	format->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
+-	format->fmt.pix.bytesperline = width * 2;
+-	format->fmt.pix.sizeimage = width * 2 * height;
+-	format->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+-	format->fmt.pix.field = V4L2_FIELD_INTERLACED;
+-
+-	em28xx_videodbg("%s: returned %dx%d (%d, %d)\n",
+-		cmd == VIDIOC_TRY_FMT ?
+-		"VIDIOC_TRY_FMT" :"VIDIOC_S_FMT",
+-		format->fmt.pix.width, format->fmt.pix.height, hscale, vscale);
+-
+-	if (cmd == VIDIOC_TRY_FMT)
+-		return 0;
+-
+-	for (i = 0; i < dev->num_frames; i++)
+-		if (dev->frame[i].vma_use_count) {
+-			em28xx_videodbg("VIDIOC_S_FMT failed. "
+-				"Unmap the buffers first.\n");
+-			return -EINVAL;
+-		}
+-
+-	/* stop io in case it is already in progress */
+-	if (dev->stream == STREAM_ON) {
+-		em28xx_videodbg("VIDIOC_SET_FMT: interrupting stream\n");
+-		if ((ret = em28xx_stream_interrupt(dev)))
+-			return ret;
+-	}
+-
+-	em28xx_release_buffers(dev);
+-	dev->io = IO_NONE;
+-
+-	/* set new image size */
+-	dev->width = width;
+-	dev->height = height;
+-	dev->frame_size = dev->width * dev->height * 2;
+-	dev->field_size = dev->frame_size >> 1;
+-	dev->bytesperline = dev->width * 2;
+-	dev->hscale = hscale;
+-	dev->vscale = vscale;
+-	em28xx_uninit_isoc(dev);
+-	em28xx_set_alternate(dev);
+-	em28xx_capture_start(dev, 1);
+-	em28xx_resolution_set(dev);
+-	em28xx_init_isoc(dev);
++	printk(KERN_INFO "Em28xx: Initialized (%s) extension\n", ops->name);
++	mutex_unlock(&em28xx_extension_devlist_lock);
  
--	if (core->board.mpeg & CX88_MPEG_BLACKBIRD) {
--		/* sets sound input from external adc */
--		if (INPUT(input).extadc)
-+	/* if there are audioroutes defined, we have an external
-+	   ADC to deal with audio */
-+
-+	if (INPUT(input).audioroute) {
-+
-+		/* cx2388's C-ADC is connected to the tuner only.
-+		   When used with S-Video, that ADC is busy dealing with
-+		   chroma, so an external must be used for baseband audio */
-+
-+		if (INPUT(input).type != CX88_VMUX_TELEVISION &&
-+			INPUT(input).type != CX88_RADIO) {
-+			/* "ADC mode" */
-+			cx_write(AUD_I2SCNTL, 0x1);
- 			cx_set(AUD_CTL, EN_I2SIN_ENABLE);
--		else
-+		} else {
-+			/* Normal mode */
-+			cx_write(AUD_I2SCNTL, 0x0);
- 			cx_clear(AUD_CTL, EN_I2SIN_ENABLE);
-+		}
-+
-+		/* The wm8775 module has the "2" route hardwired into
-+		   the initialization. Some boards may use different
-+		   routes for different inputs. HVR-1300 surely does */
-+		if (core->board.audio_chip &&
-+		    core->board.audio_chip == AUDIO_CHIP_WM8775) {
-+			struct v4l2_routing route;
-+
-+			route.input = INPUT(input).audioroute;
-+			cx88_call_i2c_clients(core,
-+				VIDIOC_INT_S_AUDIO_ROUTING, &route);
-+
-+		}
-+
- 	}
-+
  	return 0;
  }
- EXPORT_SYMBOL(cx88_video_mux);
-@@ -486,7 +514,7 @@ static int restart_video_queue(struct cx8800_dev    *dev,
- 		if (NULL == prev) {
- 			list_move_tail(&buf->vb.queue, &q->active);
- 			start_video_dma(dev, q, buf);
--			buf->vb.state = STATE_ACTIVE;
-+			buf->vb.state = VIDEOBUF_ACTIVE;
- 			buf->count    = q->count++;
- 			mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
- 			dprintk(2,"[%p/%d] restart_queue - first active\n",
-@@ -496,7 +524,7 @@ static int restart_video_queue(struct cx8800_dev    *dev,
- 			   prev->vb.height == buf->vb.height &&
- 			   prev->fmt       == buf->fmt) {
- 			list_move_tail(&buf->vb.queue, &q->active);
--			buf->vb.state = STATE_ACTIVE;
-+			buf->vb.state = VIDEOBUF_ACTIVE;
- 			buf->count    = q->count++;
- 			prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
- 			dprintk(2,"[%p/%d] restart_queue - move to active\n",
-@@ -553,7 +581,7 @@ buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
- 		init_buffer = 1;
- 	}
- 
--	if (STATE_NEEDS_INIT == buf->vb.state) {
-+	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
- 		init_buffer = 1;
- 		if (0 != (rc = videobuf_iolock(q,&buf->vb,NULL)))
- 			goto fail;
-@@ -601,7 +629,7 @@ buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
- 		fh->width, fh->height, fh->fmt->depth, fh->fmt->name,
- 		(unsigned long)buf->risc.dma);
- 
--	buf->vb.state = STATE_PREPARED;
-+	buf->vb.state = VIDEOBUF_PREPARED;
- 	return 0;
++EXPORT_SYMBOL(em28xx_register_extension);
  
-  fail:
-@@ -625,14 +653,14 @@ buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+-/*
+- * em28xx_v4l2_do_ioctl()
+- * This function is _not_ called directly, but from
+- * em28xx_v4l2_ioctl. Userspace
+- * copying is done already, arg is a kernel pointer.
+- */
+-static int em28xx_do_ioctl(struct inode *inode, struct file *filp,
+-			   struct em28xx *dev, unsigned int cmd, void *arg,
+-			   v4l2_kioctl driver_ioctl)
++void em28xx_unregister_extension(struct em28xx_ops *ops)
+ {
+-	int ret;
++	struct em28xx *h, *dev = NULL;
  
- 	if (!list_empty(&q->queued)) {
- 		list_add_tail(&buf->vb.queue,&q->queued);
--		buf->vb.state = STATE_QUEUED;
-+		buf->vb.state = VIDEOBUF_QUEUED;
- 		dprintk(2,"[%p/%d] buffer_queue - append to queued\n",
- 			buf, buf->vb.i);
+-	switch (cmd) {
+-		/* ---------- tv norms ---------- */
+-	case VIDIOC_ENUMSTD:
+-	{
+-		struct v4l2_standard *e = arg;
+-		unsigned int i;
++	list_for_each_entry(h, &em28xx_devlist, devlist)
++		dev = h;
  
- 	} else if (list_empty(&q->active)) {
- 		list_add_tail(&buf->vb.queue,&q->active);
- 		start_video_dma(dev, q, buf);
--		buf->vb.state = STATE_ACTIVE;
-+		buf->vb.state = VIDEOBUF_ACTIVE;
- 		buf->count    = q->count++;
- 		mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
- 		dprintk(2,"[%p/%d] buffer_queue - first active\n",
-@@ -644,7 +672,7 @@ buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
- 		    prev->vb.height == buf->vb.height &&
- 		    prev->fmt       == buf->fmt) {
- 			list_add_tail(&buf->vb.queue,&q->active);
--			buf->vb.state = STATE_ACTIVE;
-+			buf->vb.state = VIDEOBUF_ACTIVE;
- 			buf->count    = q->count++;
- 			prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
- 			dprintk(2,"[%p/%d] buffer_queue - append to active\n",
-@@ -652,7 +680,7 @@ buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+-		i = e->index;
+-		if (i >= TVNORMS)
+-			return -EINVAL;
+-		ret = v4l2_video_std_construct(e, tvnorms[e->index].id,
+-						tvnorms[e->index].name);
+-		e->index = i;
+-		if (ret < 0)
+-			return ret;
+-		return 0;
+-	}
+-	case VIDIOC_G_STD:
+-	{
+-		v4l2_std_id *id = arg;
++	if (dev)
++		ops->fini(dev);
  
- 		} else {
- 			list_add_tail(&buf->vb.queue,&q->queued);
--			buf->vb.state = STATE_QUEUED;
-+			buf->vb.state = VIDEOBUF_QUEUED;
- 			dprintk(2,"[%p/%d] buffer_queue - first queued\n",
- 				buf, buf->vb.i);
- 		}
-@@ -822,8 +850,8 @@ video_poll(struct file *file, struct poll_table_struct *wait)
- 			return POLLERR;
- 	}
- 	poll_wait(file, &buf->vb.done, wait);
--	if (buf->vb.state == STATE_DONE ||
--	    buf->vb.state == STATE_ERROR)
-+	if (buf->vb.state == VIDEOBUF_DONE ||
-+	    buf->vb.state == VIDEOBUF_ERROR)
- 		return POLLIN|POLLRDNORM;
- 	return 0;
+-		*id = dev->tvnorm->id;
+-		return 0;
+-	}
+-	case VIDIOC_S_STD:
+-	{
+-		v4l2_std_id *id = arg;
+-		unsigned int i;
+-
+-		for (i = 0; i < TVNORMS; i++)
+-			if (*id == tvnorms[i].id)
+-				break;
+-		if (i == TVNORMS)
+-			for (i = 0; i < TVNORMS; i++)
+-				if (*id & tvnorms[i].id)
+-					break;
+-		if (i == TVNORMS)
+-			return -EINVAL;
+-
+-		mutex_lock(&dev->lock);
+-		dev->tvnorm = &tvnorms[i];
+-
+-		em28xx_set_norm(dev, dev->width, dev->height);
+-
+-		em28xx_i2c_call_clients(dev, VIDIOC_S_STD,
+-					&dev->tvnorm->id);
+-
+-		mutex_unlock(&dev->lock);
+-
+-		return 0;
+-	}
+-
+-	/* ------ input switching ---------- */
+-	case VIDIOC_ENUMINPUT:
+-	{
+-		struct v4l2_input *i = arg;
+-		unsigned int n;
+-		static const char *iname[] = {
+-			[EM28XX_VMUX_COMPOSITE1] = "Composite1",
+-			[EM28XX_VMUX_COMPOSITE2] = "Composite2",
+-			[EM28XX_VMUX_COMPOSITE3] = "Composite3",
+-			[EM28XX_VMUX_COMPOSITE4] = "Composite4",
+-			[EM28XX_VMUX_SVIDEO] = "S-Video",
+-			[EM28XX_VMUX_TELEVISION] = "Television",
+-			[EM28XX_VMUX_CABLE] = "Cable TV",
+-			[EM28XX_VMUX_DVB] = "DVB",
+-			[EM28XX_VMUX_DEBUG] = "for debug only",
+-		};
+-
+-		n = i->index;
+-		if (n >= MAX_EM28XX_INPUT)
+-			return -EINVAL;
+-		if (0 == INPUT(n)->type)
+-			return -EINVAL;
+-		memset(i, 0, sizeof(*i));
+-		i->index = n;
+-		i->type = V4L2_INPUT_TYPE_CAMERA;
+-		strcpy(i->name, iname[INPUT(n)->type]);
+-		if ((EM28XX_VMUX_TELEVISION == INPUT(n)->type) ||
+-			(EM28XX_VMUX_CABLE == INPUT(n)->type))
+-			i->type = V4L2_INPUT_TYPE_TUNER;
+-		for (n = 0; n < ARRAY_SIZE(tvnorms); n++)
+-			i->std |= tvnorms[n].id;
+-		return 0;
+-	}
+-	case VIDIOC_G_INPUT:
+-	{
+-		int *i = arg;
+-		*i = dev->ctl_input;
+-
+-		return 0;
+-	}
+-	case VIDIOC_S_INPUT:
+-	{
+-		int *index = arg;
+-
+-		if (*index >= MAX_EM28XX_INPUT)
+-			return -EINVAL;
+-		if (0 == INPUT(*index)->type)
+-			return -EINVAL;
+-
+-		mutex_lock(&dev->lock);
+-		video_mux(dev, *index);
+-		mutex_unlock(&dev->lock);
+-
+-		return 0;
+-	}
+-	case VIDIOC_G_AUDIO:
+-	{
+-		struct v4l2_audio *a = arg;
+-		unsigned int index = a->index;
+-
+-		if (a->index > 1)
+-			return -EINVAL;
+-		memset(a, 0, sizeof(*a));
+-		index = dev->ctl_ainput;
+-
+-		if (index == 0) {
+-			strcpy(a->name, "Television");
+-		} else {
+-			strcpy(a->name, "Line In");
+-		}
+-		a->capability = V4L2_AUDCAP_STEREO;
+-		a->index = index;
+-		return 0;
+-	}
+-	case VIDIOC_S_AUDIO:
+-	{
+-		struct v4l2_audio *a = arg;
+-
+-		if (a->index != dev->ctl_ainput)
+-			return -EINVAL;
+-
+-		return 0;
+-	}
+-
+-	/* --- controls ---------------------------------------------- */
+-	case VIDIOC_QUERYCTRL:
+-	{
+-		struct v4l2_queryctrl *qc = arg;
+-		int i, id=qc->id;
+-
+-		memset(qc,0,sizeof(*qc));
+-		qc->id=id;
+-
+-		if (!dev->has_msp34xx) {
+-			for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) {
+-				if (qc->id && qc->id == em28xx_qctrl[i].id) {
+-					memcpy(qc, &(em28xx_qctrl[i]),
+-					sizeof(*qc));
+-					return 0;
+-				}
+-			}
+-		}
+-		em28xx_i2c_call_clients(dev,cmd,qc);
+-		if (qc->type)
+-			return 0;
+-		else
+-			return -EINVAL;
+-	}
+-	case VIDIOC_G_CTRL:
+-	{
+-		struct v4l2_control *ctrl = arg;
+-		int retval=-EINVAL;
+-
+-		if (!dev->has_msp34xx)
+-			retval=em28xx_get_ctrl(dev, ctrl);
+-		if (retval==-EINVAL) {
+-			em28xx_i2c_call_clients(dev,cmd,arg);
+-			return 0;
+-		} else return retval;
+-	}
+-	case VIDIOC_S_CTRL:
+-	{
+-		struct v4l2_control *ctrl = arg;
+-		u8 i;
+-
+-		if (!dev->has_msp34xx){
+-			for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) {
+-				if (ctrl->id == em28xx_qctrl[i].id) {
+-					if (ctrl->value <
+-					em28xx_qctrl[i].minimum
+-					|| ctrl->value >
+-					em28xx_qctrl[i].maximum)
+-						return -ERANGE;
+-					return em28xx_set_ctrl(dev, ctrl);
+-				}
+-			}
+-		}
+-
+-		em28xx_i2c_call_clients(dev,cmd,arg);
+-		return 0;
+-	}
+-	/* --- tuner ioctls ------------------------------------------ */
+-	case VIDIOC_G_TUNER:
+-	{
+-		struct v4l2_tuner *t = arg;
+-
+-		if (0 != t->index)
+-			return -EINVAL;
+-
+-		memset(t, 0, sizeof(*t));
+-		strcpy(t->name, "Tuner");
+-		mutex_lock(&dev->lock);
+-		/* let clients fill in the remainder of this struct */
+-		em28xx_i2c_call_clients(dev, cmd, t);
+-		mutex_unlock(&dev->lock);
+-		em28xx_videodbg("VIDIO_G_TUNER: signal=%x, afc=%x\n", t->signal,
+-				t->afc);
+-		return 0;
+-	}
+-	case VIDIOC_S_TUNER:
+-	{
+-		struct v4l2_tuner *t = arg;
+-
+-		if (0 != t->index)
+-			return -EINVAL;
+-		mutex_lock(&dev->lock);
+-		/* let clients handle this */
+-		em28xx_i2c_call_clients(dev, cmd, t);
+-		mutex_unlock(&dev->lock);
+-		return 0;
+-	}
+-	case VIDIOC_G_FREQUENCY:
+-	{
+-		struct v4l2_frequency *f = arg;
+-
+-		memset(f, 0, sizeof(*f));
+-		f->type = V4L2_TUNER_ANALOG_TV;
+-		f->frequency = dev->ctl_freq;
+-
+-		return 0;
+-	}
+-	case VIDIOC_S_FREQUENCY:
+-	{
+-		struct v4l2_frequency *f = arg;
+-
+-		if (0 != f->tuner)
+-			return -EINVAL;
+-
+-		if (V4L2_TUNER_ANALOG_TV != f->type)
+-			return -EINVAL;
+-
+-		mutex_lock(&dev->lock);
+-		dev->ctl_freq = f->frequency;
+-		em28xx_i2c_call_clients(dev, VIDIOC_S_FREQUENCY, f);
+-		mutex_unlock(&dev->lock);
+-		return 0;
+-	}
+-	case VIDIOC_CROPCAP:
+-	{
+-		struct v4l2_cropcap *cc = arg;
+-
+-		if (cc->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+-			return -EINVAL;
+-		cc->bounds.left = 0;
+-		cc->bounds.top = 0;
+-		cc->bounds.width = dev->width;
+-		cc->bounds.height = dev->height;
+-		cc->defrect = cc->bounds;
+-		cc->pixelaspect.numerator = 54;	/* 4:3 FIXME: remove magic numbers */
+-		cc->pixelaspect.denominator = 59;
+-		return 0;
+-	}
+-	case VIDIOC_STREAMON:
+-	{
+-		int *type = arg;
+-
+-		if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE
+-			|| dev->io != IO_MMAP)
+-			return -EINVAL;
+-
+-		if (list_empty(&dev->inqueue))
+-			return -EINVAL;
+-
+-		dev->stream = STREAM_ON;	/* FIXME: Start video capture here? */
+-
+-		em28xx_videodbg("VIDIOC_STREAMON: starting stream\n");
+-
+-		return 0;
+-	}
+-	case VIDIOC_STREAMOFF:
+-	{
+-		int *type = arg;
+-		int ret;
+-
+-		if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE
+-			|| dev->io != IO_MMAP)
+-			return -EINVAL;
+-
+-		if (dev->stream == STREAM_ON) {
+-			em28xx_videodbg ("VIDIOC_STREAMOFF: interrupting stream\n");
+-			if ((ret = em28xx_stream_interrupt(dev)))
+-				return ret;
+-		}
+-		em28xx_empty_framequeues(dev);
+-
+-		return 0;
+-	}
+-	default:
+-		return v4l_compat_translate_ioctl(inode, filp, cmd, arg,
+-						  driver_ioctl);
+-	}
+-	return 0;
+-}
+-
+-/*
+- * em28xx_v4l2_do_ioctl()
+- * This function is _not_ called directly, but from
+- * em28xx_v4l2_ioctl. Userspace
+- * copying is done already, arg is a kernel pointer.
+- */
+-static int em28xx_video_do_ioctl(struct inode *inode, struct file *filp,
+-				 unsigned int cmd, void *arg)
+-{
+-	struct em28xx *dev = filp->private_data;
+-
+-	if (!dev)
+-		return -ENODEV;
+-
+-	if (video_debug > 1)
+-		v4l_print_ioctl(dev->name,cmd);
+-
+-	switch (cmd) {
+-
+-		/* --- capabilities ------------------------------------------ */
+-	case VIDIOC_QUERYCAP:
+-		{
+-		struct v4l2_capability *cap = arg;
+-
+-		memset(cap, 0, sizeof(*cap));
+-		strlcpy(cap->driver, "em28xx", sizeof(cap->driver));
+-		strlcpy(cap->card, em28xx_boards[dev->model].name,
+-			sizeof(cap->card));
+-		strlcpy(cap->bus_info, dev->udev->dev.bus_id,
+-			sizeof(cap->bus_info));
+-		cap->version = EM28XX_VERSION_CODE;
+-		cap->capabilities =
+-				V4L2_CAP_SLICED_VBI_CAPTURE |
+-				V4L2_CAP_VIDEO_CAPTURE |
+-				V4L2_CAP_AUDIO |
+-				V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
+-		if (dev->has_tuner)
+-			cap->capabilities |= V4L2_CAP_TUNER;
+-		return 0;
+-	}
+-	/* --- capture ioctls ---------------------------------------- */
+-	case VIDIOC_ENUM_FMT:
+-	{
+-		struct v4l2_fmtdesc *fmtd = arg;
+-
+-		if (fmtd->index != 0)
+-			return -EINVAL;
+-		memset(fmtd, 0, sizeof(*fmtd));
+-		fmtd->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+-		strcpy(fmtd->description, "Packed YUY2");
+-		fmtd->pixelformat = V4L2_PIX_FMT_YUYV;
+-		memset(fmtd->reserved, 0, sizeof(fmtd->reserved));
+-		return 0;
+-	}
+-	case VIDIOC_G_FMT:
+-		return em28xx_get_fmt(dev, (struct v4l2_format *) arg);
+-
+-	case VIDIOC_TRY_FMT:
+-	case VIDIOC_S_FMT:
+-		return em28xx_set_fmt(dev, cmd, (struct v4l2_format *)arg);
+-
+-	case VIDIOC_REQBUFS:
+-	{
+-		struct v4l2_requestbuffers *rb = arg;
+-		u32 i;
+-		int ret;
+-
+-		if (rb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+-			rb->memory != V4L2_MEMORY_MMAP)
+-			return -EINVAL;
+-
+-		if (dev->io == IO_READ) {
+-			em28xx_videodbg ("method is set to read;"
+-				" close and open the device again to"
+-				" choose the mmap I/O method\n");
+-			return -EINVAL;
+-		}
+-
+-		for (i = 0; i < dev->num_frames; i++)
+-			if (dev->frame[i].vma_use_count) {
+-				em28xx_videodbg ("VIDIOC_REQBUFS failed; previous buffers are still mapped\n");
+-				return -EINVAL;
+-			}
+-
+-		if (dev->stream == STREAM_ON) {
+-			em28xx_videodbg("VIDIOC_REQBUFS: interrupting stream\n");
+-			if ((ret = em28xx_stream_interrupt(dev)))
+-				return ret;
+-		}
+-
+-		em28xx_empty_framequeues(dev);
+-
+-		em28xx_release_buffers(dev);
+-		if (rb->count)
+-			rb->count =
+-				em28xx_request_buffers(dev, rb->count);
+-
+-		dev->frame_current = NULL;
+-
+-		em28xx_videodbg ("VIDIOC_REQBUFS: setting io method to mmap: num bufs %i\n",
+-						rb->count);
+-		dev->io = rb->count ? IO_MMAP : IO_NONE;
+-		return 0;
+-	}
+-	case VIDIOC_QUERYBUF:
+-	{
+-		struct v4l2_buffer *b = arg;
+-
+-		if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+-			b->index >= dev->num_frames || dev->io != IO_MMAP)
+-			return -EINVAL;
+-
+-		memcpy(b, &dev->frame[b->index].buf, sizeof(*b));
+-
+-		if (dev->frame[b->index].vma_use_count) {
+-			b->flags |= V4L2_BUF_FLAG_MAPPED;
+-		}
+-		if (dev->frame[b->index].state == F_DONE)
+-			b->flags |= V4L2_BUF_FLAG_DONE;
+-		else if (dev->frame[b->index].state != F_UNUSED)
+-			b->flags |= V4L2_BUF_FLAG_QUEUED;
+-		return 0;
+-	}
+-	case VIDIOC_QBUF:
+-	{
+-		struct v4l2_buffer *b = arg;
+-		unsigned long lock_flags;
+-
+-		if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+-			b->index >= dev->num_frames || dev->io != IO_MMAP) {
+-			return -EINVAL;
+-		}
+-
+-		if (dev->frame[b->index].state != F_UNUSED) {
+-			return -EAGAIN;
+-		}
+-		dev->frame[b->index].state = F_QUEUED;
+-
+-		/* add frame to fifo */
+-		spin_lock_irqsave(&dev->queue_lock, lock_flags);
+-		list_add_tail(&dev->frame[b->index].frame,
+-				&dev->inqueue);
+-		spin_unlock_irqrestore(&dev->queue_lock, lock_flags);
+-
+-		return 0;
+-	}
+-	case VIDIOC_DQBUF:
+-	{
+-		struct v4l2_buffer *b = arg;
+-		struct em28xx_frame_t *f;
+-		unsigned long lock_flags;
+-		int ret = 0;
+-
+-		if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE
+-			|| dev->io != IO_MMAP)
+-			return -EINVAL;
+-
+-		if (list_empty(&dev->outqueue)) {
+-			if (dev->stream == STREAM_OFF)
+-				return -EINVAL;
+-			if (filp->f_flags & O_NONBLOCK)
+-				return -EAGAIN;
+-			ret = wait_event_interruptible
+-				(dev->wait_frame,
+-				(!list_empty(&dev->outqueue)) ||
+-				(dev->state & DEV_DISCONNECTED));
+-			if (ret)
+-				return ret;
+-			if (dev->state & DEV_DISCONNECTED)
+-				return -ENODEV;
+-		}
+-
+-		spin_lock_irqsave(&dev->queue_lock, lock_flags);
+-		f = list_entry(dev->outqueue.next,
+-				struct em28xx_frame_t, frame);
+-		list_del(dev->outqueue.next);
+-		spin_unlock_irqrestore(&dev->queue_lock, lock_flags);
+-
+-		f->state = F_UNUSED;
+-		memcpy(b, &f->buf, sizeof(*b));
+-
+-		if (f->vma_use_count)
+-			b->flags |= V4L2_BUF_FLAG_MAPPED;
+-
+-		return 0;
+-	}
+-	default:
+-		return em28xx_do_ioctl(inode, filp, dev, cmd, arg,
+-				       em28xx_video_do_ioctl);
+-	}
+-	return 0;
++	mutex_lock(&em28xx_extension_devlist_lock);
++	printk(KERN_INFO "Em28xx: Removed (%s) extension\n", ops->name);
++	list_del(&ops->next);
++	mutex_unlock(&em28xx_extension_devlist_lock);
  }
-@@ -1496,7 +1524,7 @@ static void cx8800_vid_timeout(unsigned long data)
- 	while (!list_empty(&q->active)) {
- 		buf = list_entry(q->active.next, struct cx88_buffer, vb.queue);
- 		list_del(&buf->vb.queue);
--		buf->vb.state = STATE_ERROR;
-+		buf->vb.state = VIDEOBUF_ERROR;
- 		wake_up(&buf->vb.done);
- 		printk("%s/0: [%p/%d] timeout - dma=0x%08lx\n", core->name,
- 		       buf, buf->vb.i, (unsigned long)buf->risc.dma);
-diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h
-index eb296bd..4e823f2 100644
---- a/drivers/media/video/cx88/cx88.h
-+++ b/drivers/media/video/cx88/cx88.h
-@@ -210,6 +210,7 @@ extern struct sram_channel cx88_sram_channels[];
- #define CX88_BOARD_TE_DTV_250_OEM_SWANN    55
- #define CX88_BOARD_HAUPPAUGE_HVR1300       56
- #define CX88_BOARD_ADSTECH_PTV_390         57
-+#define CX88_BOARD_PINNACLE_PCTV_HD_800i   58
++EXPORT_SYMBOL(em28xx_unregister_extension);
  
- enum cx88_itype {
- 	CX88_VMUX_COMPOSITE1 = 1,
-@@ -228,7 +229,7 @@ struct cx88_input {
- 	enum cx88_itype type;
- 	u32             gpio0, gpio1, gpio2, gpio3;
- 	unsigned int    vmux:2;
--	unsigned int    extadc:1;
-+	unsigned int    audioroute:2;
- };
+-/*
+- * em28xx_v4l2_ioctl()
+- * handle v4l2 ioctl the main action happens in em28xx_v4l2_do_ioctl()
+- */
+-static int em28xx_v4l2_ioctl(struct inode *inode, struct file *filp,
+-			     unsigned int cmd, unsigned long arg)
++struct video_device *em28xx_vdev_init(struct em28xx *dev,
++				      const struct video_device *template,
++				      const int type,
++				      const char *type_name)
+ {
+-	int ret = 0;
+-	struct em28xx *dev = filp->private_data;
+-
+-	if (mutex_lock_interruptible(&dev->fileop_lock))
+-		return -ERESTARTSYS;
+-
+-	if (dev->state & DEV_DISCONNECTED) {
+-		em28xx_errdev("v4l2 ioctl: device not present\n");
+-		mutex_unlock(&dev->fileop_lock);
+-		return -ENODEV;
+-	}
+-
+-	if (dev->state & DEV_MISCONFIGURED) {
+-		em28xx_errdev
+-		    ("v4l2 ioctl: device is misconfigured; close and open it again\n");
+-		mutex_unlock(&dev->fileop_lock);
+-		return -EIO;
+-	}
++	struct video_device *vfd;
  
- struct cx88_board {
-@@ -461,6 +462,7 @@ struct cx8802_dev {
- 	u32                        mailbox;
- 	int                        width;
- 	int                        height;
-+	unsigned char              mpeg_active; /* nonzero if mpeg encoder is active */
+-	ret = video_usercopy(inode, filp, cmd, arg, em28xx_video_do_ioctl);
++	vfd = video_device_alloc();
++	if (NULL == vfd)
++		return NULL;
++	*vfd = *template;
++	vfd->minor   = -1;
++	vfd->dev = &dev->udev->dev;
++	vfd->release = video_device_release;
++	vfd->type = type;
  
- 	/* mpeg params */
- 	struct cx2341x_mpeg_params params;
-@@ -588,6 +590,7 @@ extern void cx88_call_i2c_clients(struct cx88_core *core,
- /* ----------------------------------------------------------- */
- /* cx88-cards.c                                                */
+-	mutex_unlock(&dev->fileop_lock);
++	snprintf(vfd->name, sizeof(vfd->name), "%s %s",
++		 dev->name, type_name);
  
-+extern int cx88_tuner_callback(void *dev, 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);
-@@ -633,12 +636,6 @@ int cx8802_buf_prepare(struct videobuf_queue *q,struct cx8802_dev *dev,
- void cx8802_buf_queue(struct cx8802_dev *dev, struct cx88_buffer *buf);
- void cx8802_cancel_buffers(struct cx8802_dev *dev);
+-	return ret;
++	return vfd;
+ }
  
--int cx8802_init_common(struct cx8802_dev *dev);
--void cx8802_fini_common(struct cx8802_dev *dev);
+-static const struct file_operations em28xx_v4l_fops = {
+-	.owner = THIS_MODULE,
+-	.open = em28xx_v4l2_open,
+-	.release = em28xx_v4l2_close,
+-	.ioctl = em28xx_v4l2_ioctl,
+-	.read = em28xx_v4l2_read,
+-	.poll = em28xx_v4l2_poll,
+-	.mmap = em28xx_v4l2_mmap,
+-	.llseek = no_llseek,
+-	.compat_ioctl   = v4l_compat_ioctl32,
 -
--int cx8802_suspend_common(struct pci_dev *pci_dev, pm_message_t state);
--int cx8802_resume_common(struct pci_dev *pci_dev);
+-};
 -
- /* ----------------------------------------------------------- */
- /* cx88-video.c*/
- extern const u32 cx88_user_ctrls[];
-diff --git a/drivers/media/video/dpc7146.c b/drivers/media/video/dpc7146.c
-index 255dae3..566e479 100644
---- a/drivers/media/video/dpc7146.c
-+++ b/drivers/media/video/dpc7146.c
-@@ -87,11 +87,24 @@ struct dpc
- 	int cur_input;	/* current input */
- };
+-/******************************** usb interface *****************************************/
  
-+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)
+ /*
+  * em28xx_init_dev()
+  * allocates and inits the device structs, registers i2c bus and v4l device
+  */
+ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
+-			   int minor, int model)
++			   int minor)
  {
- 	struct dpc* dpc = NULL;
--	struct i2c_client *client;
++	struct em28xx_ops *ops = NULL;
+ 	struct em28xx *dev = *devhandle;
+ 	int retval = -ENOMEM;
+-	int errCode, i;
++	int errCode;
+ 	unsigned int maxh, maxw;
  
- 	dpc = kzalloc(sizeof(struct dpc), GFP_KERNEL);
- 	if( NULL == dpc ) {
-@@ -115,9 +128,7 @@ static int dpc_probe(struct saa7146_dev* dev)
- 	}
+ 	dev->udev = udev;
+-	dev->model = model;
+ 	mutex_init(&dev->lock);
++	spin_lock_init(&dev->queue_lock);
+ 	init_waitqueue_head(&dev->open);
++	init_waitqueue_head(&dev->wait_frame);
++	init_waitqueue_head(&dev->wait_stream);
  
- 	/* loop through all i2c-devices on the bus and look who is there */
--	list_for_each_entry(client, &dpc->i2c_adapter.clients, list)
--		if( I2C_SAA7111A == client->addr )
--			dpc->saa7111a = client;
-+	device_for_each_child(&dpc->i2c_adapter.dev, dpc, dpc_check_clients);
+ 	dev->em28xx_write_regs = em28xx_write_regs;
+ 	dev->em28xx_read_reg = em28xx_read_reg;
+ 	dev->em28xx_read_reg_req_len = em28xx_read_reg_req_len;
+ 	dev->em28xx_write_regs_req = em28xx_write_regs_req;
+ 	dev->em28xx_read_reg_req = em28xx_read_reg_req;
+-	dev->is_em2800 = em28xx_boards[model].is_em2800;
+-	dev->has_tuner = em28xx_boards[model].has_tuner;
+-	dev->has_msp34xx = em28xx_boards[model].has_msp34xx;
+-	dev->tda9887_conf = em28xx_boards[model].tda9887_conf;
+-	dev->decoder = em28xx_boards[model].decoder;
+-
+-	if (tuner >= 0)
+-		dev->tuner_type = tuner;
+-	else
+-		dev->tuner_type = em28xx_boards[model].tuner_type;
++	dev->is_em2800 = em28xx_boards[dev->model].is_em2800;
  
- 	/* check if all devices are present */
- 	if( 0 == dpc->saa7111a ) {
-diff --git a/drivers/media/video/em28xx/Kconfig b/drivers/media/video/em28xx/Kconfig
-index c112780..abbd38c 100644
---- a/drivers/media/video/em28xx/Kconfig
-+++ b/drivers/media/video/em28xx/Kconfig
-@@ -1,6 +1,6 @@
- config VIDEO_EM28XX
- 	tristate "Empia EM2800/2820/2840 USB video capture support"
--	depends on VIDEO_V4L1 && I2C && INPUT
-+	depends on VIDEO_DEV && I2C && INPUT
- 	select VIDEO_TUNER
- 	select VIDEO_TVEEPROM
- 	select VIDEO_IR
-@@ -11,3 +11,18 @@ config VIDEO_EM28XX
+-	dev->video_inputs = em28xx_boards[model].vchannels;
++	errCode = em28xx_read_reg(dev, CHIPID_REG);
++	if (errCode >= 0)
++		em28xx_info("em28xx chip ID = %d\n", errCode);
  
- 	  To compile this driver as a module, choose M here: the
- 	  module will be called em28xx
-+
-+config VIDEO_EM28XX_ALSA
-+	depends on VIDEO_EM28XX
-+	tristate "Empia EM28xx ALSA audio module"
-+	---help---
-+	  This is an ALSA driver for some Empia 28xx based TV cards.
-+
-+	  This is not required for em2800/em2820/em2821 boards. However,
-+	  newer em28xx devices uses Vendor Class for audio, instead of
-+	  implementing the USB Audio Class. For those chips, this module
-+	  will enable digital audio.
+-	for (i = 0; i < TVNORMS; i++)
+-		if (em28xx_boards[model].norm == tvnorms[i].mode)
+-			break;
+-	if (i == TVNORMS)
+-		i = 0;
++	em28xx_pre_card_setup(dev);
 +
-+	  To compile this driver as a module, choose M here: the
-+	  module will be called em28xx-alsa
++	errCode = em28xx_config(dev);
++	if (errCode) {
++		em28xx_errdev("error configuring device\n");
++		em28xx_devused &= ~(1<<dev->devno);
++		kfree(dev);
++		return -ENOMEM;
++	}
 +
-diff --git a/drivers/media/video/em28xx/Makefile b/drivers/media/video/em28xx/Makefile
-index 826d0e3..0924550 100644
---- a/drivers/media/video/em28xx/Makefile
-+++ b/drivers/media/video/em28xx/Makefile
-@@ -1,6 +1,12 @@
- em28xx-objs     := em28xx-video.o em28xx-i2c.o em28xx-cards.o em28xx-core.o \
- 		   em28xx-input.o
++	/* register i2c bus */
++	em28xx_i2c_register(dev);
  
-+em28xx-alsa-objs := em28xx-audio.o
-+
- obj-$(CONFIG_VIDEO_EM28XX) += em28xx.o
-+obj-$(CONFIG_VIDEO_EM28XX_ALSA) += em28xx-alsa.o
+-	dev->tvnorm = &tvnorms[i];	/* set default norm */
++	/* Do board specific init and eeprom reading */
++	em28xx_card_setup(dev);
  
- EXTRA_CFLAGS += -Idrivers/media/video
-+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
-+EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
-+
-diff --git a/drivers/media/video/em28xx/em28xx-audio.c b/drivers/media/video/em28xx/em28xx-audio.c
-new file mode 100644
-index 0000000..941357c
---- /dev/null
-+++ b/drivers/media/video/em28xx/em28xx-audio.c
-@@ -0,0 +1,489 @@
-+/*
-+ *  Empiatech em28x1 audio extension
-+ *
-+ *  Copyright (C) 2006 Markus Rechberger <mrechberger at gmail.com>
-+ *
-+ *  Copyright (C) 2007 Mauro Carvalho Chehab <mchehab at infradead.org>
-+ *	- Port to work with the in-kernel driver
-+ *	- Several cleanups
-+ *
-+ *  This driver is based on my previous au600 usb pstn audio driver
-+ *  and inherits all the copyrights
-+ *
-+ *  This program is free software; you can redistribute it and/or modify
-+ *  it under the terms of the GNU General Public License as published by
-+ *  the Free Software Foundation; either version 2 of the License, or
-+ *  (at your option) any later version.
-+ *
-+ *  This program is distributed in the hope that it will be useful,
-+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+ *  GNU General Public License for more details.
-+ *
-+ *  You 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/usb.h>
-+#include <linux/init.h>
-+#include <linux/sound.h>
-+#include <linux/spinlock.h>
-+#include <linux/soundcard.h>
-+#include <linux/slab.h>
-+#include <linux/vmalloc.h>
-+#include <linux/proc_fs.h>
-+#include <linux/module.h>
-+#include <sound/driver.h>
-+#include <sound/core.h>
-+#include <sound/pcm.h>
-+#include <sound/pcm_params.h>
-+#include <sound/info.h>
-+#include <sound/initval.h>
-+#include <sound/control.h>
-+#include <media/v4l2-common.h>
-+#include "em28xx.h"
-+
-+static int debug;
-+module_param(debug, int, 0644);
-+MODULE_PARM_DESC(debug, "activates debug info");
-+
-+#define dprintk(fmt, arg...) do {					\
-+	    if (debug)							\
-+		printk(KERN_INFO "em28xx-audio %s: " fmt,		\
-+				  __FUNCTION__, ##arg); 		\
-+	} while (0)
-+
-+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
-+
-+static int em28xx_isoc_audio_deinit(struct em28xx *dev)
-+{
-+	int i;
-+
-+	dprintk("Stopping isoc\n");
-+	for (i = 0; i < EM28XX_AUDIO_BUFS; i++) {
-+		usb_kill_urb(dev->adev->urb[i]);
-+		usb_free_urb(dev->adev->urb[i]);
-+		dev->adev->urb[i] = NULL;
-+	}
-+
-+	return 0;
-+}
-+
-+static void em28xx_audio_isocirq(struct urb *urb)
-+{
-+	struct em28xx            *dev = urb->context;
-+	int                      i;
-+	unsigned int             oldptr;
-+	unsigned long            flags;
-+	int                      period_elapsed = 0;
-+	int                      status;
-+	unsigned char            *cp;
-+	unsigned int             stride;
-+	struct snd_pcm_substream *substream;
-+	struct snd_pcm_runtime   *runtime;
-+	if (dev->adev->capture_pcm_substream) {
-+		substream = dev->adev->capture_pcm_substream;
-+		runtime = substream->runtime;
-+		stride = runtime->frame_bits >> 3;
-+
-+		for (i = 0; i < urb->number_of_packets; i++) {
-+			int length =
-+			    urb->iso_frame_desc[i].actual_length / stride;
-+			cp = (unsigned char *)urb->transfer_buffer +
-+			    urb->iso_frame_desc[i].offset;
-+
-+			if (!length)
-+				continue;
-+
-+			spin_lock_irqsave(&dev->adev->slock, flags);
-+
-+			oldptr = dev->adev->hwptr_done_capture;
-+			dev->adev->hwptr_done_capture += length;
-+			if (dev->adev->hwptr_done_capture >=
-+			    runtime->buffer_size)
-+				dev->adev->hwptr_done_capture -=
-+				    runtime->buffer_size;
-+
-+			dev->adev->capture_transfer_done += length;
-+			if (dev->adev->capture_transfer_done >=
-+			    runtime->period_size) {
-+				dev->adev->capture_transfer_done -=
-+				    runtime->period_size;
-+				period_elapsed = 1;
-+			}
+-	em28xx_videodbg("tvnorm=%s\n", dev->tvnorm->name);
++	/* Configure audio */
++	em28xx_audio_analog_set(dev);
 +
-+			spin_unlock_irqrestore(&dev->adev->slock, flags);
++	/* configure the device */
++	em28xx_config_i2c(dev);
 +
-+			if (oldptr + length >= runtime->buffer_size) {
-+				unsigned int cnt =
-+				    runtime->buffer_size - oldptr - 1;
-+				memcpy(runtime->dma_area + oldptr * stride, cp,
-+				       cnt * stride);
-+				memcpy(runtime->dma_area, cp + cnt,
-+				       length * stride - cnt * stride);
-+			} else {
-+				memcpy(runtime->dma_area + oldptr * stride, cp,
-+				       length * stride);
-+			}
++	/* set default norm */
++	dev->norm = em28xx_video_template.current_norm;
+ 
+ 	maxw = norm_maxw(dev);
+ 	maxh = norm_maxh(dev);
+@@ -1555,138 +1890,110 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
+ 	dev->vscale = 0;
+ 	dev->ctl_input = 2;
+ 
+-	/* setup video picture settings for saa7113h */
+-	memset(&dev->vpic, 0, sizeof(dev->vpic));
+-	dev->vpic.colour = 128 << 8;
+-	dev->vpic.hue = 128 << 8;
+-	dev->vpic.brightness = 128 << 8;
+-	dev->vpic.contrast = 192 << 8;
+-	dev->vpic.whiteness = 128 << 8;	/* This one isn't used */
+-	dev->vpic.depth = 16;
+-	dev->vpic.palette = VIDEO_PALETTE_YUV422;
+-
+-	em28xx_pre_card_setup(dev);
+-#ifdef CONFIG_MODULES
+-	/* request some modules */
+-	if (dev->decoder == EM28XX_SAA7113 || dev->decoder == EM28XX_SAA7114)
+-		request_module("saa7115");
+-	if (dev->decoder == EM28XX_TVP5150)
+-		request_module("tvp5150");
+-	if (dev->has_tuner)
+-		request_module("tuner");
+-#endif
+ 	errCode = em28xx_config(dev);
+-	if (errCode) {
+-		em28xx_errdev("error configuring device\n");
+-		em28xx_devused&=~(1<<dev->devno);
+-		kfree(dev);
+-		return -ENOMEM;
+-	}
+-
+-	mutex_lock(&dev->lock);
+-	/* register i2c bus */
+-	em28xx_i2c_register(dev);
+ 
+-	/* Do board specific init and eeprom reading */
+-	em28xx_card_setup(dev);
++	list_add_tail(&dev->devlist, &em28xx_devlist);
+ 
+-	/* configure the device */
+-	em28xx_config_i2c(dev);
+-
+-	mutex_unlock(&dev->lock);
+-
+-	errCode = em28xx_config(dev);
+-
+-#ifdef CONFIG_MODULES
+-	if (dev->has_msp34xx)
+-		request_module("msp3400");
+-#endif
+-	/* allocate and fill v4l2 device struct */
+-	dev->vdev = video_device_alloc();
++	/* allocate and fill video video_device struct */
++	dev->vdev = em28xx_vdev_init(dev, &em28xx_video_template,
++					  VID_TYPE_CAPTURE, "video");
+ 	if (NULL == dev->vdev) {
+ 		em28xx_errdev("cannot allocate video_device.\n");
+-		em28xx_devused&=~(1<<dev->devno);
+-		kfree(dev);
+-		return -ENOMEM;
+-	}
+-
+-	dev->vbi_dev = video_device_alloc();
+-	if (NULL == dev->vbi_dev) {
+-		em28xx_errdev("cannot allocate video_device.\n");
+-		kfree(dev->vdev);
+-		em28xx_devused&=~(1<<dev->devno);
+-		kfree(dev);
+-		return -ENOMEM;
++		goto fail_unreg;
+ 	}
+-
+-	/* Fills VBI device info */
+-	dev->vbi_dev->type = VFL_TYPE_VBI;
+-	dev->vbi_dev->fops = &em28xx_v4l_fops;
+-	dev->vbi_dev->minor = -1;
+-	dev->vbi_dev->dev = &dev->udev->dev;
+-	dev->vbi_dev->release = video_device_release;
+-	snprintf(dev->vbi_dev->name, sizeof(dev->vbi_dev->name), "%s#%d %s",
+-							 "em28xx",dev->devno,"vbi");
+-
+-	/* Fills CAPTURE device info */
+-	dev->vdev->type = VID_TYPE_CAPTURE;
+-	if (dev->has_tuner)
++	if (dev->tuner_type != TUNER_ABSENT)
+ 		dev->vdev->type |= VID_TYPE_TUNER;
+-	dev->vdev->fops = &em28xx_v4l_fops;
+-	dev->vdev->minor = -1;
+-	dev->vdev->dev = &dev->udev->dev;
+-	dev->vdev->release = video_device_release;
+-	snprintf(dev->vdev->name, sizeof(dev->vbi_dev->name), "%s#%d %s",
+-							 "em28xx",dev->devno,"video");
+-
+-	list_add_tail(&dev->devlist,&em28xx_devlist);
+ 
+-	/* register v4l2 device */
+-	mutex_lock(&dev->lock);
+-	if ((retval = video_register_device(dev->vdev, VFL_TYPE_GRABBER,
+-					 video_nr[dev->devno]))) {
++	/* register v4l2 video video_device */
++	retval = video_register_device(dev->vdev, VFL_TYPE_GRABBER,
++				       video_nr[dev->devno]);
++	if (retval) {
+ 		em28xx_errdev("unable to register video device (error=%i).\n",
+ 			      retval);
+-		mutex_unlock(&dev->lock);
+-		list_del(&dev->devlist);
+-		video_device_release(dev->vdev);
+-		em28xx_devused&=~(1<<dev->devno);
+-		kfree(dev);
+-		return -ENODEV;
++		goto fail_unreg;
+ 	}
+ 
++	/* Allocate and fill vbi video_device struct */
++	dev->vbi_dev = em28xx_vdev_init(dev, &em28xx_video_template,
++					  VFL_TYPE_VBI, "vbi");
++	/* register v4l2 vbi video_device */
+ 	if (video_register_device(dev->vbi_dev, VFL_TYPE_VBI,
+ 					vbi_nr[dev->devno]) < 0) {
+-		printk("unable to register vbi device\n");
+-		mutex_unlock(&dev->lock);
+-		list_del(&dev->devlist);
+-		video_device_release(dev->vbi_dev);
+-		video_device_release(dev->vdev);
+-		em28xx_devused&=~(1<<dev->devno);
+-		kfree(dev);
+-		return -ENODEV;
+-	} else {
+-		printk("registered VBI\n");
++		em28xx_errdev("unable to register vbi device\n");
++		retval = -ENODEV;
++		goto fail_unreg;
+ 	}
+ 
++	if (em28xx_boards[dev->model].radio.type == EM28XX_RADIO) {
++		dev->radio_dev = em28xx_vdev_init(dev, &em28xx_radio_template,
++					VFL_TYPE_RADIO, "radio");
++		if (NULL == dev->radio_dev) {
++			em28xx_errdev("cannot allocate video_device.\n");
++			goto fail_unreg;
 +		}
-+		if (period_elapsed)
-+			snd_pcm_period_elapsed(substream);
-+	}
-+	urb->status = 0;
-+
-+	if (dev->adev->shutdown)
-+		return;
-+
-+	status = usb_submit_urb(urb, GFP_ATOMIC);
-+	if (status < 0) {
-+		em28xx_errdev("resubmit of audio urb failed (error=%i)\n",
-+			      status);
-+	}
-+	return;
-+}
-+
-+static int em28xx_init_audio_isoc(struct em28xx *dev)
-+{
-+	int       i, errCode;
-+	const int sb_size = EM28XX_NUM_AUDIO_PACKETS *
-+			    EM28XX_AUDIO_MAX_PACKET_SIZE;
-+
-+	dprintk("Starting isoc transfers\n");
-+
-+	for (i = 0; i < EM28XX_AUDIO_BUFS; i++) {
-+		struct urb *urb;
-+		int j, k;
-+
-+		dev->adev->transfer_buffer[i] = kmalloc(sb_size, GFP_ATOMIC);
-+		if (!dev->adev->transfer_buffer[i])
-+			return -ENOMEM;
-+
-+		memset(dev->adev->transfer_buffer[i], 0x80, sb_size);
-+		urb = usb_alloc_urb(EM28XX_NUM_AUDIO_PACKETS, GFP_ATOMIC);
-+		if (!urb)
-+			return -ENOMEM;
-+
-+		urb->dev = dev->udev;
-+		urb->context = dev;
-+		urb->pipe = usb_rcvisocpipe(dev->udev, 0x83);
-+		urb->transfer_flags = URB_ISO_ASAP;
-+		urb->transfer_buffer = dev->adev->transfer_buffer[i];
-+		urb->interval = 1;
-+		urb->complete = em28xx_audio_isocirq;
-+		urb->number_of_packets = EM28XX_NUM_AUDIO_PACKETS;
-+		urb->transfer_buffer_length = sb_size;
-+
-+		for (j = k = 0; j < EM28XX_NUM_AUDIO_PACKETS;
-+			     j++, k += EM28XX_AUDIO_MAX_PACKET_SIZE) {
-+			urb->iso_frame_desc[j].offset = k;
-+			urb->iso_frame_desc[j].length =
-+			    EM28XX_AUDIO_MAX_PACKET_SIZE;
++		retval = video_register_device(dev->radio_dev, VFL_TYPE_RADIO,
++					    radio_nr[dev->devno]);
++		if (retval < 0) {
++			em28xx_errdev("can't register radio device\n");
++			goto fail_unreg;
 +		}
-+		dev->adev->urb[i] = urb;
++		em28xx_info("Registered radio device as /dev/radio%d\n",
++			    dev->radio_dev->minor & 0x1f);
 +	}
 +
-+	for (i = 0; i < EM28XX_AUDIO_BUFS; i++) {
-+		errCode = usb_submit_urb(dev->adev->urb[i], GFP_ATOMIC);
-+		if (errCode) {
-+			em28xx_isoc_audio_deinit(dev);
 +
-+			return errCode;
+ 	if (dev->has_msp34xx) {
+ 		/* Send a reset to other chips via gpio */
+ 		em28xx_write_regs_req(dev, 0x00, 0x08, "\xf7", 1);
+ 		msleep(3);
+ 		em28xx_write_regs_req(dev, 0x00, 0x08, "\xff", 1);
+ 		msleep(3);
+-
+ 	}
+-	video_mux(dev, 0);
+ 
+-	mutex_unlock(&dev->lock);
++	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);
+ 
++	mutex_lock(&em28xx_extension_devlist_lock);
++	if (!list_empty(&em28xx_extension_devlist)) {
++		list_for_each_entry(ops, &em28xx_extension_devlist, next) {
++			if (ops->id)
++				ops->init(dev);
 +		}
 +	}
++	mutex_unlock(&em28xx_extension_devlist_lock);
 +
-+	return 0;
+ 	return 0;
++
++fail_unreg:
++	em28xx_release_resources(dev);
++	mutex_unlock(&dev->lock);
++	kfree(dev);
++	return retval;
 +}
 +
-+static int em28xx_cmd(struct em28xx *dev, int cmd, int arg)
++#if defined(CONFIG_MODULES) && defined(MODULE)
++static void request_module_async(struct work_struct *work)
 +{
-+	dprintk("%s transfer\n", (dev->adev->capture_stream == STREAM_ON)?
-+				 "stop" : "start");
++	struct em28xx *dev = container_of(work,
++			     struct em28xx, request_module_wk);
 +
-+	switch (cmd) {
-+	case EM28XX_CAPTURE_STREAM_EN:
-+		if (dev->adev->capture_stream == STREAM_OFF && arg == 1) {
-+			dev->adev->capture_stream = STREAM_ON;
-+			em28xx_init_audio_isoc(dev);
-+		} else if (dev->adev->capture_stream == STREAM_ON && arg == 0) {
-+			dev->adev->capture_stream = STREAM_OFF;
-+			em28xx_isoc_audio_deinit(dev);
-+		} else {
-+			printk(KERN_ERR "An underrun very likely occurred. "
-+					"Ignoring it.\n");
-+		}
-+		return 0;
-+	default:
-+		return -EINVAL;
-+	}
++	if (dev->has_audio_class)
++		request_module("snd-usb-audio");
++	else
++		request_module("em28xx-alsa");
 +}
 +
-+static int snd_pcm_alloc_vmalloc_buffer(struct snd_pcm_substream *subs,
-+					size_t size)
++static void request_modules(struct em28xx *dev)
 +{
-+	struct snd_pcm_runtime *runtime = subs->runtime;
-+
-+	dprintk("Alocating vbuffer\n");
-+	if (runtime->dma_area) {
-+		if (runtime->dma_bytes > size)
-+			return 0;
++	INIT_WORK(&dev->request_module_wk, request_module_async);
++	schedule_work(&dev->request_module_wk);
+ }
++#else
++#define request_modules(dev)
++#endif /* CONFIG_MODULES */
+ 
+ /*
+  * em28xx_usb_probe()
+@@ -1700,7 +2007,7 @@ static int em28xx_usb_probe(struct usb_interface *interface,
+ 	struct usb_interface *uif;
+ 	struct em28xx *dev = NULL;
+ 	int retval = -ENODEV;
+-	int model,i,nr,ifnum;
++	int i, nr, ifnum;
+ 
+ 	udev = usb_get_dev(interface_to_usbdev(interface));
+ 	ifnum = interface->altsetting[0].desc.bInterfaceNumber;
+@@ -1740,8 +2047,6 @@ static int em28xx_usb_probe(struct usb_interface *interface,
+ 		return -ENODEV;
+ 	}
+ 
+-	model=id->driver_info;
+-
+ 	if (nr >= EM28XX_MAXBOARDS) {
+ 		printk (DRIVER_NAME ": Supports only %i em28xx boards.\n",EM28XX_MAXBOARDS);
+ 		em28xx_devused&=~(1<<nr);
+@@ -1757,7 +2062,20 @@ static int em28xx_usb_probe(struct usb_interface *interface,
+ 	}
+ 
+ 	snprintf(dev->name, 29, "em28xx #%d", nr);
+-	dev->devno=nr;
++	dev->devno = nr;
++	dev->model = id->driver_info;
 +
-+		vfree(runtime->dma_area);
++	/* Checks if audio is provided by some interface */
++	for (i = 0; i < udev->config->desc.bNumInterfaces; i++) {
++		uif = udev->config->interface[i];
++		if (uif->altsetting[0].desc.bInterfaceClass == USB_CLASS_AUDIO) {
++			dev->has_audio_class = 1;
++			break;
++		}
 +	}
-+	runtime->dma_area = vmalloc(size);
-+	if (!runtime->dma_area)
-+		return -ENOMEM;
-+
-+	runtime->dma_bytes = size;
 +
-+	return 0;
-+}
++	printk(KERN_INFO DRIVER_NAME " %s usb audio class\n",
++		   dev->has_audio_class ? "Has" : "Doesn't have");
+ 
+ 	/* compute alternate max packet sizes */
+ 	uif = udev->actconfig->interface[0];
+@@ -1784,33 +2102,20 @@ static int em28xx_usb_probe(struct usb_interface *interface,
+ 	}
+ 
+ 	if ((card[nr]>=0)&&(card[nr]<em28xx_bcount))
+-		model=card[nr];
+-
+-	if ((model==EM2800_BOARD_UNKNOWN)||(model==EM2820_BOARD_UNKNOWN)) {
+-		em28xx_errdev( "Your board has no eeprom inside it and thus can't\n"
+-			"%s: be autodetected.  Please pass card=<n> insmod option to\n"
+-			"%s: workaround that.  Redirect complaints to the vendor of\n"
+-			"%s: the TV card. Generic type will be used."
+-			"%s: Best regards,\n"
+-			"%s:         -- tux\n",
+-			dev->name,dev->name,dev->name,dev->name,dev->name);
+-		em28xx_errdev("%s: Here is a list of valid choices for the card=<n> insmod option:\n",
+-			dev->name);
+-		for (i = 0; i < em28xx_bcount; i++) {
+-			em28xx_errdev("    card=%d -> %s\n", i,
+-							em28xx_boards[i].name);
+-		}
+-	}
++		dev->model = card[nr];
+ 
+ 	/* allocate device struct */
+-	retval = em28xx_init_dev(&dev, udev, nr, model);
++	retval = em28xx_init_dev(&dev, udev, nr);
+ 	if (retval)
+ 		return retval;
+ 
+-	em28xx_info("Found %s\n", em28xx_boards[model].name);
++	em28xx_info("Found %s\n", em28xx_boards[dev->model].name);
+ 
+ 	/* save our data pointer in this interface device */
+ 	usb_set_intfdata(interface, dev);
 +
-+static struct snd_pcm_hardware snd_em28xx_hw_capture = {
-+	.info = SNDRV_PCM_INFO_BLOCK_TRANSFER |
-+		SNDRV_PCM_INFO_MMAP           |
-+		SNDRV_PCM_INFO_INTERLEAVED    |
-+		SNDRV_PCM_INFO_MMAP_VALID,
++	request_modules(dev);
 +
-+	.formats = SNDRV_PCM_FMTBIT_S16_LE,
+ 	return 0;
+ }
+ 
+@@ -1821,18 +2126,20 @@ static int em28xx_usb_probe(struct usb_interface *interface,
+  */
+ static void em28xx_usb_disconnect(struct usb_interface *interface)
+ {
+-	struct em28xx *dev = usb_get_intfdata(interface);
++	struct em28xx *dev;
++	struct em28xx_ops *ops = NULL;
 +
-+	.rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_KNOT,
++	dev = usb_get_intfdata(interface);
+ 	usb_set_intfdata(interface, NULL);
+ 
+ 	if (!dev)
+ 		return;
+ 
+-	down_write(&em28xx_disconnect);
++	em28xx_info("disconnecting %s\n", dev->vdev->name);
+ 
++	/* wait until all current v4l2 io is finished then deallocate resources */
+ 	mutex_lock(&dev->lock);
+ 
+-	em28xx_info("disconnecting %s\n", dev->vdev->name);
+-
+ 	wake_up_interruptible_all(&dev->open);
+ 
+ 	if (dev->users) {
+@@ -1850,15 +2157,20 @@ static void em28xx_usb_disconnect(struct usb_interface *interface)
+ 		dev->state |= DEV_DISCONNECTED;
+ 		em28xx_release_resources(dev);
+ 	}
+-
+ 	mutex_unlock(&dev->lock);
+ 
++	mutex_lock(&em28xx_extension_devlist_lock);
++	if (!list_empty(&em28xx_extension_devlist)) {
++		list_for_each_entry(ops, &em28xx_extension_devlist, next) {
++			ops->fini(dev);
++		}
++	}
++	mutex_unlock(&em28xx_extension_devlist_lock);
 +
-+	.rate_min = 48000,
-+	.rate_max = 48000,
-+	.channels_min = 2,
-+	.channels_max = 2,
-+	.buffer_bytes_max = 62720 * 8,	/* just about the value in usbaudio.c */
-+	.period_bytes_min = 64,		/* 12544/2, */
-+	.period_bytes_max = 12544,
-+	.periods_min = 2,
-+	.periods_max = 98,		/* 12544, */
+ 	if (!dev->users) {
+ 		kfree(dev->alt_max_pkt_size);
+ 		kfree(dev);
+ 	}
+-
+-	up_write(&em28xx_disconnect);
+ }
+ 
+ static struct usb_driver em28xx_usb_driver = {
+diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h
+index d8fcc9e..f3bad0c 100644
+--- a/drivers/media/video/em28xx/em28xx.h
++++ b/drivers/media/video/em28xx/em28xx.h
+@@ -25,28 +25,11 @@
+ #ifndef _EM28XX_H
+ #define _EM28XX_H
+ 
+-#include <linux/videodev.h>
++#include <linux/videodev2.h>
+ #include <linux/i2c.h>
+ #include <linux/mutex.h>
+ #include <media/ir-kbd-i2c.h>
+ 
+-/* Boards supported by driver */
+-
+-#define EM2800_BOARD_UNKNOWN			0
+-#define EM2820_BOARD_UNKNOWN			1
+-#define EM2820_BOARD_TERRATEC_CINERGY_250	2
+-#define EM2820_BOARD_PINNACLE_USB_2		3
+-#define EM2820_BOARD_HAUPPAUGE_WINTV_USB_2      4
+-#define EM2820_BOARD_MSI_VOX_USB_2              5
+-#define EM2800_BOARD_TERRATEC_CINERGY_200       6
+-#define EM2800_BOARD_LEADTEK_WINFAST_USBII      7
+-#define EM2800_BOARD_KWORLD_USB2800             8
+-#define EM2820_BOARD_PINNACLE_DVC_90		9
+-#define EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900	10
+-#define EM2880_BOARD_TERRATEC_HYBRID_XS		11
+-#define EM2820_BOARD_KWORLD_PVRTV2800RF		12
+-#define EM2880_BOARD_TERRATEC_PRODIGY_XS	13
+-
+ #define UNSET -1
+ 
+ /* maximum number of em28xx boards */
+@@ -148,10 +131,17 @@ enum enum28xx_itype {
+ 	EM28XX_RADIO,
+ };
+ 
++enum em28xx_amux {
++	EM28XX_AMUX_VIDEO,
++	EM28XX_AMUX_LINE_IN,
++	EM28XX_AMUX_AC97_VIDEO,
++	EM28XX_AMUX_AC97_LINE_IN,
 +};
 +
-+static int snd_em28xx_capture_open(struct snd_pcm_substream *substream)
-+{
-+	struct em28xx *dev = snd_pcm_substream_chip(substream);
-+	struct snd_pcm_runtime *runtime = substream->runtime;
-+	int ret = 0;
-+
-+	dprintk("opening device and trying to acquire exclusive lock\n");
-+
-+	/* Sets volume, mute, etc */
-+	dev->mute = 0;
-+	ret = em28xx_audio_analog_set(dev);
-+	if (ret < 0)
-+		goto err;
-+
-+	runtime->hw = snd_em28xx_hw_capture;
-+	if (dev->alt == 0 && dev->adev->users == 0) {
-+		int errCode;
-+		dev->alt = 7;
-+		errCode = usb_set_interface(dev->udev, 0, 7);
-+		dprintk("changing alternate number to 7\n");
-+	}
-+
-+	dev->adev->users++;
+ struct em28xx_input {
+ 	enum enum28xx_itype type;
+ 	unsigned int vmux;
+-	unsigned int amux;
++	enum em28xx_amux amux;
+ };
+ 
+ #define INPUT(nr) (&em28xx_boards[dev->model].input[nr])
+@@ -165,19 +155,23 @@ enum em28xx_decoder {
+ struct em28xx_board {
+ 	char *name;
+ 	int vchannels;
+-	int norm;
+ 	int tuner_type;
+ 
+ 	/* i2c flags */
+-	unsigned int is_em2800;
+ 	unsigned int tda9887_conf;
+ 
+-	unsigned int has_tuner:1;
++	unsigned int is_em2800:1;
+ 	unsigned int has_msp34xx:1;
++	unsigned int mts_firmware:1;
++	unsigned int has_12mhz_i2s:1;
++	unsigned int max_range_640_480:1;
 +
-+	snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
-+	dev->adev->capture_pcm_substream = substream;
-+	runtime->private_data = dev;
++	unsigned int analog_gpio;
+ 
+ 	enum em28xx_decoder decoder;
+ 
+ 	struct em28xx_input       input[MAX_EM28XX_INPUT];
++	struct em28xx_input	  radio;
+ };
+ 
+ struct em28xx_eeprom {
+@@ -201,12 +195,26 @@ enum em28xx_dev_state {
+ 	DEV_MISCONFIGURED = 0x04,
+ };
+ 
+-/* tvnorms */
+-struct em28xx_tvnorm {
+-	char *name;
+-	v4l2_std_id id;
+-	/* mode for saa7113h */
+-	int mode;
++#define EM28XX_AUDIO_BUFS 5
++#define EM28XX_NUM_AUDIO_PACKETS 64
++#define EM28XX_AUDIO_MAX_PACKET_SIZE 196 /* static value */
++#define EM28XX_CAPTURE_STREAM_EN 1
++#define EM28XX_AUDIO   0x10
 +
-+	return 0;
-+err:
-+	printk(KERN_ERR "Error while configuring em28xx mixer\n");
-+	return ret;
-+}
++struct em28xx_audio {
++	char name[50];
++	char *transfer_buffer[EM28XX_AUDIO_BUFS];
++	struct urb *urb[EM28XX_AUDIO_BUFS];
++	struct usb_device *udev;
++	unsigned int capture_transfer_done;
++	struct snd_pcm_substream   *capture_pcm_substream;
 +
-+static int snd_em28xx_pcm_close(struct snd_pcm_substream *substream)
-+{
-+	struct em28xx *dev = snd_pcm_substream_chip(substream);
-+	dev->adev->users--;
++	unsigned int hwptr_done_capture;
++	struct snd_card            *sndcard;
 +
-+	dprintk("closing device\n");
++	int users, shutdown;
++	enum em28xx_stream_state capture_stream;
++	spinlock_t slock;
+ };
+ 
+ /* main device struct */
+@@ -215,12 +223,17 @@ struct em28xx {
+ 	char name[30];		/* name (including minor) of the device */
+ 	int model;		/* index in the device_data struct */
+ 	int devno;		/* marks the number of this device */
+-	unsigned int is_em2800;
+-	int video_inputs;	/* number of video inputs */
+-	struct list_head	devlist;
+-	unsigned int has_tuner:1;
++	unsigned int analog_gpio;
++	unsigned int is_em2800:1;
+ 	unsigned int has_msp34xx:1;
+ 	unsigned int has_tda9887:1;
++	unsigned int stream_on:1;	/* Locks streams */
++	unsigned int has_audio_class:1;
++	unsigned int has_12mhz_i2s:1;
++	unsigned int max_range_640_480:1;
 +
-+	dev->mute = 1;
-+	em28xx_audio_analog_set(dev);
++	int video_inputs;	/* number of video inputs */
++	struct list_head	devlist;
+ 
+ 	u32 i2s_speed;		/* I2S speed for audio digital stream */
+ 
+@@ -235,8 +248,7 @@ struct em28xx {
+ 	/* video for linux */
+ 	int users;		/* user count for exclusive use */
+ 	struct video_device *vdev;	/* video for linux device struct */
+-	struct video_picture vpic;	/* picture settings only used to init saa7113h */
+-	struct em28xx_tvnorm *tvnorm;	/* selected tv norm */
++	v4l2_std_id norm;	/* selected tv norm */
+ 	int ctl_freq;		/* selected frequency */
+ 	unsigned int ctl_input;	/* selected input */
+ 	unsigned int ctl_ainput;	/* slected audio input */
+@@ -256,17 +268,27 @@ struct em28xx {
+ 	int vscale;		/* vertical scale factor (see datasheet) */
+ 	int interlaced;		/* 1=interlace fileds, 0=just top fileds */
+ 	int type;
++	unsigned int video_bytesread;	/* Number of bytes read */
 +
-+	if (dev->adev->users == 0 && dev->adev->shutdown == 1) {
-+		dprintk("audio users: %d\n", dev->adev->users);
-+		dprintk("disabling audio stream!\n");
-+		dev->adev->shutdown = 0;
-+		dprintk("released lock\n");
-+		em28xx_cmd(dev, EM28XX_CAPTURE_STREAM_EN, 0);
-+	}
-+	return 0;
-+}
++	unsigned long hash;	/* eeprom hash - for boards with generic ID */
++	unsigned long i2c_hash;	/* i2c devicelist hash - for boards with generic ID */
 +
-+static int snd_em28xx_hw_capture_params(struct snd_pcm_substream *substream,
-+					struct snd_pcm_hw_params *hw_params)
-+{
-+	unsigned int channels, rate, format;
-+	int ret;
++	struct em28xx_audio *adev;
+ 
+ 	/* states */
+ 	enum em28xx_dev_state state;
+ 	enum em28xx_stream_state stream;
+ 	enum em28xx_io_method io;
 +
-+	dprintk("Setting capture parameters\n");
++	struct work_struct         request_module_wk;
 +
-+	ret = snd_pcm_alloc_vmalloc_buffer(substream,
-+				params_buffer_bytes(hw_params));
-+	format = params_format(hw_params);
-+	rate = params_rate(hw_params);
-+	channels = params_channels(hw_params);
+ 	/* locks */
+-	struct mutex lock, fileop_lock;
++	struct mutex lock;
+ 	spinlock_t queue_lock;
+ 	struct list_head inqueue, outqueue;
+ 	wait_queue_head_t open, wait_frame, wait_stream;
+ 	struct video_device *vbi_dev;
++	struct video_device *radio_dev;
+ 
+ 	unsigned char eedata[256];
+ 
+@@ -289,16 +311,27 @@ struct em28xx {
+ 	int (*em28xx_read_reg_req) (struct em28xx * dev, u8 req, u16 reg);
+ };
+ 
++struct em28xx_fh {
++	struct em28xx *dev;
++	unsigned int  stream_on:1;	/* Locks streams */
++	int           radio;
++};
 +
-+	/* TODO: set up em28xx audio chip to deliver the correct audio format,
-+	   current default is 48000hz multiplexed => 96000hz mono
-+	   which shouldn't matter since analogue TV only supports mono */
-+	return 0;
-+}
++struct em28xx_ops {
++	struct list_head next;
++	char *name;
++	int id;
++	int (*init)(struct em28xx *);
++	int (*fini)(struct em28xx *);
++};
 +
-+static int snd_em28xx_hw_capture_free(struct snd_pcm_substream *substream)
-+{
-+	struct em28xx *dev = snd_pcm_substream_chip(substream);
+ /* Provided by em28xx-i2c.c */
+ 
+ void em28xx_i2c_call_clients(struct em28xx *dev, unsigned int cmd, void *arg);
++void em28xx_do_i2c_scan(struct em28xx *dev);
+ int em28xx_i2c_register(struct em28xx *dev);
+ int em28xx_i2c_unregister(struct em28xx *dev);
+ 
+-/* Provided by em28xx-input.c */
+-
+-void em28xx_set_ir(struct em28xx * dev,struct IR_i2c *ir);
+-
+ /* Provided by em28xx-core.c */
+ 
+ u32 em28xx_request_buffers(struct em28xx *dev, u32 count);
+@@ -314,8 +347,9 @@ int em28xx_write_regs_req(struct em28xx *dev, u8 req, u16 reg, char *buf,
+ int em28xx_write_regs(struct em28xx *dev, u16 reg, char *buf, int len);
+ int em28xx_write_reg_bits(struct em28xx *dev, u16 reg, u8 val,
+ 			  u8 bitmask);
+-int em28xx_write_ac97(struct em28xx *dev, u8 reg, u8 * val);
++int em28xx_set_audio_source(struct em28xx *dev);
+ int em28xx_audio_analog_set(struct em28xx *dev);
 +
-+	dprintk("Stop capture, if needed\n");
+ int em28xx_colorlevels_set_default(struct em28xx *dev);
+ int em28xx_capture_start(struct em28xx *dev, int start);
+ int em28xx_outfmt_set_yuv422(struct em28xx *dev);
+@@ -324,6 +358,10 @@ int em28xx_init_isoc(struct em28xx *dev);
+ void em28xx_uninit_isoc(struct em28xx *dev);
+ int em28xx_set_alternate(struct em28xx *dev);
+ 
++/* Provided by em28xx-video.c */
++int em28xx_register_extension(struct em28xx_ops *dev);
++void em28xx_unregister_extension(struct em28xx_ops *dev);
 +
-+	if (dev->adev->capture_stream == STREAM_ON)
-+		em28xx_cmd(dev, EM28XX_CAPTURE_STREAM_EN, 0);
+ /* Provided by em28xx-cards.c */
+ extern int em2800_variant_detect(struct usb_device* udev,int model);
+ extern void em28xx_pre_card_setup(struct em28xx *dev);
+@@ -331,8 +369,20 @@ extern void em28xx_card_setup(struct em28xx *dev);
+ extern struct em28xx_board em28xx_boards[];
+ 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);
 +
-+	return 0;
-+}
++/* Provided by em28xx-input.c */
++/* TODO: Check if the standard get_key handlers on ir-common can be used */
++int em28xx_get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw);
++int em28xx_get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw);
++int em28xx_get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key,
++				     u32 *ir_raw);
 +
-+static int snd_em28xx_prepare(struct snd_pcm_substream *substream)
-+{
-+	return 0;
-+}
++/* em2800 registers */
++#define EM2800_AUDIOSRC_REG 0x08
+ 
+ /* em28xx registers */
++#define I2C_CLK_REG	0x06
+ #define CHIPID_REG	0x0a
+ #define USBSUSP_REG	0x0c	/* */
+ 
+@@ -384,9 +434,12 @@ extern const unsigned int em28xx_bcount;
+ 
+ /* em202 registers */
+ #define MASTER_AC97	0x02
++#define LINE_IN_AC97    0x10
+ #define VIDEO_AC97	0x14
+ 
+ /* register settings */
++#define EM2800_AUDIO_SRC_TUNER  0x0d
++#define EM2800_AUDIO_SRC_LINE   0x0c
+ #define EM28XX_AUDIO_SRC_TUNER	0xc0
+ #define EM28XX_AUDIO_SRC_LINE	0x80
+ 
+@@ -406,22 +459,6 @@ extern const unsigned int em28xx_bcount;
+ 	printk(KERN_WARNING "%s: "fmt,\
+ 			dev->name , ##arg); } while (0)
+ 
+-inline static int em28xx_audio_source(struct em28xx *dev, int input)
+-{
+-	return em28xx_write_reg_bits(dev, AUDIOSRC_REG, input, 0xc0);
+-}
+-
+-inline static int em28xx_audio_usb_mute(struct em28xx *dev, int mute)
+-{
+-	return em28xx_write_reg_bits(dev, XCLK_REG, mute ? 0x00 : 0x80, 0x80);
+-}
+-
+-inline static int em28xx_audio_analog_setup(struct em28xx *dev)
+-{
+-	/* unmute video mixer with default volume level */
+-	return em28xx_write_ac97(dev, VIDEO_AC97, "\x08\x08");
+-}
+-
+ inline static int em28xx_compression_disable(struct em28xx *dev)
+ {
+ 	/* side effect of disabling scaler and mixer */
+@@ -497,18 +534,17 @@ inline static int em28xx_gamma_set(struct em28xx *dev, s32 val)
+ /*FIXME: maxw should be dependent of alt mode */
+ inline static unsigned int norm_maxw(struct em28xx *dev)
+ {
+-	switch(dev->model){
+-		case (EM2820_BOARD_MSI_VOX_USB_2): return(640);
+-		default: return(720);
+-	}
++	if (dev->max_range_640_480)
++		return 640;
++	else
++		return 720;
+ }
+ 
+ inline static unsigned int norm_maxh(struct em28xx *dev)
+ {
+-	switch(dev->model){
+-		case (EM2820_BOARD_MSI_VOX_USB_2): return(480);
+-		default: return (dev->tvnorm->id & V4L2_STD_625_50) ? 576 : 480;
+-	}
++	if (dev->max_range_640_480)
++		return 480;
++	else
++		return (dev->norm & V4L2_STD_625_50) ? 576 : 480;
+ }
+-
+ #endif
+diff --git a/drivers/media/video/et61x251/et61x251_core.c b/drivers/media/video/et61x251/et61x251_core.c
+index d19d73b..06b6a3a 100644
+--- a/drivers/media/video/et61x251/et61x251_core.c
++++ b/drivers/media/video/et61x251/et61x251_core.c
+@@ -227,7 +227,7 @@ int et61x251_write_reg(struct et61x251_device* cam, u8 value, u16 index)
+ }
+ 
+ 
+-int et61x251_read_reg(struct et61x251_device* cam, u16 index)
++static int et61x251_read_reg(struct et61x251_device* cam, u16 index)
+ {
+ 	struct usb_device* udev = cam->usbdev;
+ 	u8* buff = cam->control_buffer;
+@@ -269,73 +269,6 @@ et61x251_i2c_wait(struct et61x251_device* cam,
+ 
+ 
+ int
+-et61x251_i2c_try_read(struct et61x251_device* cam,
+-		      const struct et61x251_sensor* sensor, u8 address)
+-{
+-	struct usb_device* udev = cam->usbdev;
+-	u8* data = cam->control_buffer;
+-	int err = 0, res;
+-
+-	data[0] = address;
+-	data[1] = cam->sensor.i2c_slave_id;
+-	data[2] = cam->sensor.rsta | 0x10;
+-	data[3] = !(et61x251_read_reg(cam, 0x8b) & 0x02);
+-	res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41,
+-			      0, 0x88, data, 4, ET61X251_CTRL_TIMEOUT);
+-	if (res < 0)
+-		err += res;
+-
+-	err += et61x251_i2c_wait(cam, sensor);
+-
+-	res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00, 0xc1,
+-			      0, 0x80, data, 8, ET61X251_CTRL_TIMEOUT);
+-	if (res < 0)
+-		err += res;
+-
+-	if (err)
+-		DBG(3, "I2C read failed for %s image sensor", sensor->name);
+-
+-	PDBGG("I2C read: address 0x%02X, value: 0x%02X", address, data[0]);
+-
+-	return err ? -1 : (int)data[0];
+-}
+-
+-
+-int
+-et61x251_i2c_try_write(struct et61x251_device* cam,
+-		       const struct et61x251_sensor* sensor, u8 address,
+-		       u8 value)
+-{
+-	struct usb_device* udev = cam->usbdev;
+-	u8* data = cam->control_buffer;
+-	int err = 0, res;
+-
+-	data[0] = address;
+-	data[1] = cam->sensor.i2c_slave_id;
+-	data[2] = cam->sensor.rsta | 0x12;
+-	res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41,
+-			      0, 0x88, data, 3, ET61X251_CTRL_TIMEOUT);
+-	if (res < 0)
+-		err += res;
+-
+-	data[0] = value;
+-	res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41,
+-			      0, 0x80, data, 1, ET61X251_CTRL_TIMEOUT);
+-	if (res < 0)
+-		err += res;
+-
+-	err += et61x251_i2c_wait(cam, sensor);
+-
+-	if (err)
+-		DBG(3, "I2C write failed for %s image sensor", sensor->name);
+-
+-	PDBGG("I2C write: address 0x%02X, value: 0x%02X", address, value);
+-
+-	return err ? -1 : 0;
+-}
+-
+-
+-int
+ et61x251_i2c_raw_write(struct et61x251_device* cam, u8 n, u8 data1, u8 data2,
+ 		       u8 data3, u8 data4, u8 data5, u8 data6, u8 data7,
+ 		       u8 data8, u8 address)
+@@ -387,17 +320,6 @@ et61x251_i2c_raw_write(struct et61x251_device* cam, u8 n, u8 data1, u8 data2,
+ }
+ 
+ 
+-int et61x251_i2c_read(struct et61x251_device* cam, u8 address)
+-{
+-	return et61x251_i2c_try_read(cam, &cam->sensor, address);
+-}
+-
+-
+-int et61x251_i2c_write(struct et61x251_device* cam, u8 address, u8 value)
+-{
+-	return et61x251_i2c_try_write(cam, &cam->sensor, address, value);
+-}
+-
+ /*****************************************************************************/
+ 
+ static void et61x251_urb_complete(struct urb *urb)
+@@ -675,6 +597,83 @@ static int et61x251_stream_interrupt(struct et61x251_device* cam)
+ /*****************************************************************************/
+ 
+ #ifdef CONFIG_VIDEO_ADV_DEBUG
 +
-+static int snd_em28xx_capture_trigger(struct snd_pcm_substream *substream,
-+				      int cmd)
++static int et61x251_i2c_try_read(struct et61x251_device* cam,
++				 const struct et61x251_sensor* sensor,
++				 u8 address)
 +{
-+	struct em28xx *dev = snd_pcm_substream_chip(substream);
++	struct usb_device* udev = cam->usbdev;
++	u8* data = cam->control_buffer;
++	int err = 0, res;
 +
-+	dprintk("Should %s capture\n", (cmd == SNDRV_PCM_TRIGGER_START)?
-+				       "start": "stop");
-+	switch (cmd) {
-+	case SNDRV_PCM_TRIGGER_START:
-+		em28xx_cmd(dev, EM28XX_CAPTURE_STREAM_EN, 1);
-+		return 0;
-+	case SNDRV_PCM_TRIGGER_STOP:
-+		dev->adev->shutdown = 1;
-+		return 0;
-+	default:
-+		return -EINVAL;
-+	}
-+}
++	data[0] = address;
++	data[1] = cam->sensor.i2c_slave_id;
++	data[2] = cam->sensor.rsta | 0x10;
++	data[3] = !(et61x251_read_reg(cam, 0x8b) & 0x02);
++	res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41,
++			      0, 0x88, data, 4, ET61X251_CTRL_TIMEOUT);
++	if (res < 0)
++		err += res;
 +
-+static snd_pcm_uframes_t snd_em28xx_capture_pointer(struct snd_pcm_substream
-+						    *substream)
-+{
-+	struct em28xx *dev;
++	err += et61x251_i2c_wait(cam, sensor);
 +
-+	snd_pcm_uframes_t hwptr_done;
-+	dev = snd_pcm_substream_chip(substream);
-+	hwptr_done = dev->adev->hwptr_done_capture;
++	res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00, 0xc1,
++			      0, 0x80, data, 8, ET61X251_CTRL_TIMEOUT);
++	if (res < 0)
++		err += res;
 +
-+	return hwptr_done;
-+}
++	if (err)
++		DBG(3, "I2C read failed for %s image sensor", sensor->name);
 +
-+static struct page *snd_pcm_get_vmalloc_page(struct snd_pcm_substream *subs,
-+					     unsigned long offset)
-+{
-+	void *pageptr = subs->runtime->dma_area + offset;
++	PDBGG("I2C read: address 0x%02X, value: 0x%02X", address, data[0]);
 +
-+	return vmalloc_to_page(pageptr);
++	return err ? -1 : (int)data[0];
 +}
 +
-+static struct snd_pcm_ops snd_em28xx_pcm_capture = {
-+	.open      = snd_em28xx_capture_open,
-+	.close     = snd_em28xx_pcm_close,
-+	.ioctl     = snd_pcm_lib_ioctl,
-+	.hw_params = snd_em28xx_hw_capture_params,
-+	.hw_free   = snd_em28xx_hw_capture_free,
-+	.prepare   = snd_em28xx_prepare,
-+	.trigger   = snd_em28xx_capture_trigger,
-+	.pointer   = snd_em28xx_capture_pointer,
-+	.page      = snd_pcm_get_vmalloc_page,
-+};
 +
-+static int em28xx_audio_init(struct em28xx *dev)
++static int et61x251_i2c_try_write(struct et61x251_device* cam,
++				  const struct et61x251_sensor* sensor,
++				  u8 address, u8 value)
 +{
-+	struct em28xx_audio *adev;
-+	struct snd_pcm      *pcm;
-+	struct snd_card     *card;
-+	static int          devnr;
-+	int                 ret, err;
-+
-+	printk(KERN_INFO "em28xx-audio.c: probing for em28x1 "
-+			 "non standard usbaudio\n");
-+	printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2006 Markus "
-+			 "Rechberger\n");
-+
-+	adev = kzalloc(sizeof(*adev), GFP_KERNEL);
-+	if (!adev) {
-+		printk(KERN_ERR "em28xx-audio.c: out of memory\n");
-+		return -1;
-+	}
-+	card = snd_card_new(index[devnr], "Em28xx Audio", THIS_MODULE, 0);
-+	if (card == NULL) {
-+		kfree(adev);
-+		return -ENOMEM;
-+	}
++	struct usb_device* udev = cam->usbdev;
++	u8* data = cam->control_buffer;
++	int err = 0, res;
 +
-+	spin_lock_init(&adev->slock);
-+	ret = snd_pcm_new(card, "Em28xx Audio", 0, 0, 1, &pcm);
-+	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_em28xx_pcm_capture);
-+	pcm->info_flags = 0;
-+	pcm->private_data = dev;
-+	strcpy(pcm->name, "Empia 28xx Capture");
-+	strcpy(card->driver, "Empia Em28xx Audio");
-+	strcpy(card->shortname, "Em28xx Audio");
-+	strcpy(card->longname, "Empia Em28xx Audio");
++	data[0] = address;
++	data[1] = cam->sensor.i2c_slave_id;
++	data[2] = cam->sensor.rsta | 0x12;
++	res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41,
++			      0, 0x88, data, 3, ET61X251_CTRL_TIMEOUT);
++	if (res < 0)
++		err += res;
 +
-+	err = snd_card_register(card);
-+	if (err < 0) {
-+		snd_card_free(card);
-+		return -ENOMEM;
-+	}
-+	adev->sndcard = card;
-+	adev->udev = dev->udev;
-+	dev->adev = adev;
++	data[0] = value;
++	res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41,
++			      0, 0x80, data, 1, ET61X251_CTRL_TIMEOUT);
++	if (res < 0)
++		err += res;
 +
-+	return 0;
-+}
++	err += et61x251_i2c_wait(cam, sensor);
 +
-+static int em28xx_audio_fini(struct em28xx *dev)
-+{
-+	if (dev == NULL)
-+		return 0;
++	if (err)
++		DBG(3, "I2C write failed for %s image sensor", sensor->name);
 +
-+	if (dev->adev) {
-+		snd_card_free(dev->adev->sndcard);
-+		kfree(dev->adev);
-+		dev->adev = NULL;
-+	}
++	PDBGG("I2C write: address 0x%02X, value: 0x%02X", address, value);
 +
-+	return 0;
++	return err ? -1 : 0;
 +}
 +
-+static struct em28xx_ops audio_ops = {
-+	.id   = EM28XX_AUDIO,
-+	.name = "Em28xx Audio Extension",
-+	.init = em28xx_audio_init,
-+	.fini = em28xx_audio_fini,
-+};
-+
-+static int __init em28xx_alsa_register(void)
++static int et61x251_i2c_read(struct et61x251_device* cam, u8 address)
 +{
-+	return em28xx_register_extension(&audio_ops);
++	return et61x251_i2c_try_read(cam, &cam->sensor, address);
 +}
 +
-+static void __exit em28xx_alsa_unregister(void)
++static int et61x251_i2c_write(struct et61x251_device* cam,
++			      u8 address, u8 value)
 +{
-+	em28xx_unregister_extension(&audio_ops);
++	return et61x251_i2c_try_write(cam, &cam->sensor, address, value);
 +}
 +
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Markus Rechberger <mrechberger at gmail.com>");
-+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab at infradead.org>");
-+MODULE_DESCRIPTION("Em28xx Audio driver");
-+
-+module_init(em28xx_alsa_register);
-+module_exit(em28xx_alsa_unregister);
-diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c
-index 418ea8b..2159d01 100644
---- a/drivers/media/video/em28xx/em28xx-cards.c
-+++ b/drivers/media/video/em28xx/em28xx-cards.c
-@@ -1,5 +1,6 @@
- /*
--   em28xx-cards.c - driver for Empia EM2800/EM2820/2840 USB video capture devices
-+   em28xx-cards.c - driver for Empia EM2800/EM2820/2840 USB
-+		    video capture devices
+ static u8 et61x251_strtou8(const char* buff, size_t len, ssize_t* count)
+ {
+ 	char str[5];
+diff --git a/drivers/media/video/et61x251/et61x251_sensor.h b/drivers/media/video/et61x251/et61x251_sensor.h
+index e145863..71a0314 100644
+--- a/drivers/media/video/et61x251/et61x251_sensor.h
++++ b/drivers/media/video/et61x251/et61x251_sensor.h
+@@ -52,14 +52,6 @@ et61x251_attach_sensor(struct et61x251_device* cam,
+ /*****************************************************************************/
  
-    Copyright (C) 2005 Ludovico Cavedon <cavedon at sssup.it>
- 		      Markus Rechberger <mrechberger at gmail.com>
-@@ -35,294 +36,735 @@
- #include <media/v4l2-common.h>
+ extern int et61x251_write_reg(struct et61x251_device*, u8 value, u16 index);
+-extern int et61x251_read_reg(struct et61x251_device*, u16 index);
+-extern int et61x251_i2c_write(struct et61x251_device*, u8 address, u8 value);
+-extern int et61x251_i2c_read(struct et61x251_device*, u8 address);
+-extern int et61x251_i2c_try_write(struct et61x251_device*,
+-				  const struct et61x251_sensor*, u8 address,
+-				  u8 value);
+-extern int et61x251_i2c_try_read(struct et61x251_device*,
+-				 const struct et61x251_sensor*, u8 address);
+ extern int et61x251_i2c_raw_write(struct et61x251_device*, u8 n, u8 data1,
+ 				  u8 data2, u8 data3, u8 data4, u8 data5,
+ 				  u8 data6, u8 data7, u8 data8, u8 address);
+diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c
+index 29779d8..9851987 100644
+--- a/drivers/media/video/ir-kbd-i2c.c
++++ b/drivers/media/video/ir-kbd-i2c.c
+@@ -398,6 +398,7 @@ static int ir_attach(struct i2c_adapter *adap, int addr,
+ 	case 0x7a:
+ 	case 0x47:
+ 	case 0x71:
++	case 0x2d:
+ 		if (adap->id == I2C_HW_B_CX2388x) {
+ 			/* Handled by cx88-input */
+ 			name        = "CX2388x remote";
+@@ -504,7 +505,7 @@ static int ir_probe(struct i2c_adapter *adap)
+ 	*/
  
- #include "em28xx.h"
-+#include "tuner-xc2028.h"
+ 	static const int probe_bttv[] = { 0x1a, 0x18, 0x4b, 0x64, 0x30, -1};
+-	static const int probe_saa7134[] = { 0x7a, 0x47, 0x71, -1 };
++	static const int probe_saa7134[] = { 0x7a, 0x47, 0x71, 0x2d, -1 };
+ 	static const int probe_em28XX[] = { 0x30, 0x47, -1 };
+ 	static const int probe_cx88[] = { 0x18, 0x6b, 0x71, -1 };
+ 	static const int probe_cx23885[] = { 0x6b, -1 };
+diff --git a/drivers/media/video/ivtv/Kconfig b/drivers/media/video/ivtv/Kconfig
+index 854cc9c..270906f 100644
+--- a/drivers/media/video/ivtv/Kconfig
++++ b/drivers/media/video/ivtv/Kconfig
+@@ -3,6 +3,7 @@ config VIDEO_IVTV
+ 	depends on VIDEO_V4L1 && VIDEO_V4L2 && PCI && I2C && EXPERIMENTAL
+ 	select I2C_ALGOBIT
+ 	select FW_LOADER
++	select VIDEO_IR
+ 	select VIDEO_TUNER
+ 	select VIDEO_TVEEPROM
+ 	select VIDEO_CX2341X
+@@ -12,6 +13,7 @@ config VIDEO_IVTV
+ 	select VIDEO_SAA7127
+ 	select VIDEO_TVAUDIO
+ 	select VIDEO_CS53L32A
++	select VIDEO_M52790
+ 	select VIDEO_WM8775
+ 	select VIDEO_WM8739
+ 	select VIDEO_VP27SMPX
+diff --git a/drivers/media/video/ivtv/Makefile b/drivers/media/video/ivtv/Makefile
+index e8eefd9..a038901 100644
+--- a/drivers/media/video/ivtv/Makefile
++++ b/drivers/media/video/ivtv/Makefile
+@@ -6,3 +6,8 @@ ivtv-objs	:= ivtv-routing.o ivtv-cards.o ivtv-controls.o \
+ 
+ obj-$(CONFIG_VIDEO_IVTV) += ivtv.o
+ obj-$(CONFIG_VIDEO_FB_IVTV) += ivtvfb.o
 +
-+static int tuner = -1;
-+module_param(tuner, int, 0444);
-+MODULE_PARM_DESC(tuner, "tuner type");
++EXTRA_CFLAGS += -Idrivers/media/video
++EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
++EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
 +
-+static unsigned int disable_ir;
-+module_param(disable_ir, int, 0444);
-+MODULE_PARM_DESC(disable_ir, "disable infrared remote support");
+diff --git a/drivers/media/video/ivtv/ivtv-cards.c b/drivers/media/video/ivtv/ivtv-cards.c
+index b6a8be6..f23c6b8 100644
+--- a/drivers/media/video/ivtv/ivtv-cards.c
++++ b/drivers/media/video/ivtv/ivtv-cards.c
+@@ -23,6 +23,7 @@
+ #include "ivtv-i2c.h"
+ 
+ #include <media/msp3400.h>
++#include <media/m52790.h>
+ #include <media/wm8775.h>
+ #include <media/cs53l32a.h>
+ #include <media/cx25840.h>
+@@ -39,6 +40,27 @@
+ #define MSP_MONO   MSP_INPUT(MSP_IN_MONO, MSP_IN_TUNER1, \
+ 				MSP_DSP_IN_SCART, MSP_DSP_IN_SCART)
+ 
++/* usual i2c tuner addresses to probe */
++static struct ivtv_card_tuner_i2c ivtv_i2c_std = {
++	.radio = { I2C_CLIENT_END },
++	.demod = { 0x43, I2C_CLIENT_END },
++	.tv    = { 0x61, 0x60, I2C_CLIENT_END },
++};
 +
-+struct em28xx_hash_table {
-+	unsigned long hash;
-+	unsigned int  model;
-+	unsigned int  tuner;
++/* as above, but with possible radio tuner */
++static struct ivtv_card_tuner_i2c ivtv_i2c_radio = {
++	.radio = { 0x60, I2C_CLIENT_END },
++	.demod = { 0x43, I2C_CLIENT_END },
++	.tv    = { 0x61, I2C_CLIENT_END },
 +};
 +
-+/* Boards supported by driver */
++/* using the tda8290+75a combo */
++static struct ivtv_card_tuner_i2c ivtv_i2c_tda8290 = {
++	.radio = { I2C_CLIENT_END },
++	.demod = { I2C_CLIENT_END },
++	.tv    = { 0x4b, I2C_CLIENT_END },
++};
 +
-+#define EM2800_BOARD_UNKNOWN			0
-+#define EM2820_BOARD_UNKNOWN			1
-+#define EM2820_BOARD_TERRATEC_CINERGY_250	2
-+#define EM2820_BOARD_PINNACLE_USB_2		3
-+#define EM2820_BOARD_HAUPPAUGE_WINTV_USB_2      4
-+#define EM2820_BOARD_MSI_VOX_USB_2              5
-+#define EM2800_BOARD_TERRATEC_CINERGY_200       6
-+#define EM2800_BOARD_LEADTEK_WINFAST_USBII      7
-+#define EM2800_BOARD_KWORLD_USB2800             8
-+#define EM2820_BOARD_PINNACLE_DVC_90		9
-+#define EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900	10
-+#define EM2880_BOARD_TERRATEC_HYBRID_XS		11
-+#define EM2820_BOARD_KWORLD_PVRTV2800RF		12
-+#define EM2880_BOARD_TERRATEC_PRODIGY_XS	13
-+#define EM2820_BOARD_PROLINK_PLAYTV_USB2	14
-+#define EM2800_BOARD_VGEAR_POCKETTV             15
-+#define EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950	16
+ /********************** card configuration *******************************/
  
- struct em28xx_board em28xx_boards[] = {
- 	[EM2800_BOARD_UNKNOWN] = {
- 		.name         = "Unknown EM2800 video grabber",
- 		.is_em2800    = 1,
- 		.vchannels    = 2,
--		.norm         = VIDEO_MODE_PAL,
- 		.tda9887_conf = TDA9887_PRESENT,
--		.has_tuner    = 1,
- 		.decoder      = EM28XX_SAA7113,
--		.input           = {{
-+		.input           = { {
- 			.type     = EM28XX_VMUX_COMPOSITE1,
- 			.vmux     = SAA7115_COMPOSITE0,
- 			.amux     = 1,
--		},{
-+		}, {
- 			.type     = EM28XX_VMUX_SVIDEO,
- 			.vmux     = SAA7115_SVIDEO3,
- 			.amux     = 1,
--		}},
-+		} },
+ /* Please add new PCI IDs to: http://pci-ids.ucw.cz/iii
+@@ -72,6 +94,7 @@ static const struct ivtv_card ivtv_card_pvr250 = {
+ 		{ IVTV_CARD_INPUT_LINE_IN2,   MSP_SCART3 },
  	},
- 	[EM2820_BOARD_UNKNOWN] = {
--		.name         = "Unknown EM2820/2840 video grabber",
-+		.name         = "Unknown EM2750/28xx video grabber",
- 		.is_em2800    = 0,
--		.vchannels    = 2,
--		.norm         = VIDEO_MODE_PAL,
--		.tda9887_conf = TDA9887_PRESENT,
--		.has_tuner    = 1,
--		.decoder      = EM28XX_SAA7113,
--		.input           = {{
--			.type     = EM28XX_VMUX_COMPOSITE1,
--			.vmux     = SAA7115_COMPOSITE0,
--			.amux     = 1,
--		},{
--			.type     = EM28XX_VMUX_SVIDEO,
--			.vmux     = SAA7115_SVIDEO3,
--			.amux     = 1,
--		}},
-+		.tuner_type   = TUNER_ABSENT,
+ 	.radio_input = { IVTV_CARD_INPUT_AUD_TUNER, MSP_SCART2 },
++	.i2c = &ivtv_i2c_std,
+ };
+ 
+ /* ------------------------------------------------------------------------- */
+@@ -126,6 +149,7 @@ static const struct ivtv_card ivtv_card_pvr350 = {
+ 		{ IVTV_CARD_INPUT_LINE_IN2,   MSP_SCART3 },
  	},
- 	[EM2820_BOARD_KWORLD_PVRTV2800RF] = {
- 		.name         = "Kworld PVR TV 2800 RF",
- 		.is_em2800    = 0,
- 		.vchannels    = 2,
--		.norm         = VIDEO_MODE_PAL,
-+		.tuner_type   = TUNER_TEMIC_PAL,
- 		.tda9887_conf = TDA9887_PRESENT,
--		.has_tuner    = 1,
- 		.decoder      = EM28XX_SAA7113,
--		.input           = {{
-+		.input           = { {
- 			.type     = EM28XX_VMUX_COMPOSITE1,
- 			.vmux     = SAA7115_COMPOSITE0,
- 			.amux     = 1,
--		},{
-+		}, {
- 			.type     = EM28XX_VMUX_SVIDEO,
- 			.vmux     = SAA7115_SVIDEO3,
- 			.amux     = 1,
--		}},
-+		} },
+ 	.radio_input = { IVTV_CARD_INPUT_AUD_TUNER, MSP_SCART2 },
++	.i2c = &ivtv_i2c_std,
+ };
+ 
+ /* PVR-350 V1 boards have a different audio tuner input and use a
+@@ -157,6 +181,7 @@ static const struct ivtv_card ivtv_card_pvr350_v1 = {
+ 		{ IVTV_CARD_INPUT_LINE_IN2,   MSP_SCART3 },
  	},
- 	[EM2820_BOARD_TERRATEC_CINERGY_250] = {
- 		.name         = "Terratec Cinergy 250 USB",
- 		.vchannels    = 3,
--		.norm         = VIDEO_MODE_PAL,
- 		.tuner_type   = TUNER_LG_PAL_NEW_TAPC,
- 		.tda9887_conf = TDA9887_PRESENT,
--		.has_tuner    = 1,
- 		.decoder      = EM28XX_SAA7113,
--		.input          = {{
-+		.input          = { {
- 			.type     = EM28XX_VMUX_TELEVISION,
- 			.vmux     = SAA7115_COMPOSITE2,
- 			.amux     = 1,
--		},{
-+		}, {
- 			.type     = EM28XX_VMUX_COMPOSITE1,
- 			.vmux     = SAA7115_COMPOSITE0,
- 			.amux     = 1,
--		},{
-+		}, {
- 			.type     = EM28XX_VMUX_SVIDEO,
- 			.vmux     = SAA7115_SVIDEO3,
- 			.amux     = 1,
--		}},
-+		} },
+ 	.radio_input = { IVTV_CARD_INPUT_AUD_TUNER, MSP_SCART2 },
++	.i2c = &ivtv_i2c_std,
+ };
+ 
+ /* ------------------------------------------------------------------------- */
+@@ -192,6 +217,7 @@ static const struct ivtv_card ivtv_card_pvr150 = {
+ 			 CX25840_AUDIO_SERIAL, WM8775_AIN4 },
+ 	/* apparently needed for the IR blaster */
+ 	.gpio_init = { .direction = 0x1f01, .initial_value = 0x26f3 },
++	.i2c = &ivtv_i2c_std,
+ };
+ 
+ /* ------------------------------------------------------------------------- */
+@@ -234,6 +260,7 @@ static const struct ivtv_card ivtv_card_m179 = {
+ 		{ .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_NTSC },
  	},
- 	[EM2820_BOARD_PINNACLE_USB_2] = {
- 		.name         = "Pinnacle PCTV USB 2",
- 		.vchannels    = 3,
--		.norm         = VIDEO_MODE_PAL,
- 		.tuner_type   = TUNER_LG_PAL_NEW_TAPC,
- 		.tda9887_conf = TDA9887_PRESENT,
--		.has_tuner    = 1,
- 		.decoder      = EM28XX_SAA7113,
--		.input          = {{
-+		.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,
--		}},
-+		} },
+ 	.pci_list = ivtv_pci_m179,
++	.i2c = &ivtv_i2c_std,
+ };
+ 
+ /* ------------------------------------------------------------------------- */
+@@ -275,6 +302,7 @@ static const struct ivtv_card ivtv_card_mpg600 = {
+ 		{ .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FQ1286 },
  	},
- 	[EM2820_BOARD_HAUPPAUGE_WINTV_USB_2] = {
- 		.name         = "Hauppauge WinTV USB 2",
- 		.vchannels    = 3,
--		.norm         = VIDEO_MODE_NTSC,
- 		.tuner_type   = TUNER_PHILIPS_FM1236_MK3,
--		.tda9887_conf = TDA9887_PRESENT|TDA9887_PORT1_ACTIVE|TDA9887_PORT2_ACTIVE,
--		.has_tuner    = 1,
-+		.tda9887_conf = TDA9887_PRESENT |
-+				TDA9887_PORT1_ACTIVE|
-+				TDA9887_PORT2_ACTIVE,
- 		.decoder      = EM28XX_TVP5150,
- 		.has_msp34xx  = 1,
- 		/*FIXME: S-Video not tested */
--		.input          = {{
-+		.input          = { {
- 			.type     = EM28XX_VMUX_TELEVISION,
- 			.vmux     = TVP5150_COMPOSITE0,
- 			.amux     = MSP_INPUT_DEFAULT,
--		},{
-+		}, {
- 			.type     = EM28XX_VMUX_SVIDEO,
- 			.vmux     = TVP5150_SVIDEO,
- 			.amux     = MSP_INPUT(MSP_IN_SCART1, MSP_IN_TUNER1,
- 					MSP_DSP_IN_SCART, MSP_DSP_IN_SCART),
--		}},
-+		} },
+ 	.pci_list = ivtv_pci_mpg600,
++	.i2c = &ivtv_i2c_std,
+ };
+ 
+ /* ------------------------------------------------------------------------- */
+@@ -315,6 +343,7 @@ static const struct ivtv_card ivtv_card_mpg160 = {
+ 		{ .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FQ1286 },
  	},
--	[EM2820_BOARD_MSI_VOX_USB_2] = {
--		.name		= "MSI VOX USB 2.0",
--		.vchannels	= 3,
--		.norm		= VIDEO_MODE_PAL,
--		.tuner_type	= TUNER_LG_PAL_NEW_TAPC,
--		.tda9887_conf	= TDA9887_PRESENT|TDA9887_PORT1_ACTIVE|TDA9887_PORT2_ACTIVE,
--		.has_tuner	= 1,
--		.decoder        = EM28XX_SAA7114,
--		.input          = {{
-+	[EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900] = {
-+		.name         = "Hauppauge WinTV HVR 900",
-+		.vchannels    = 3,
-+		.tda9887_conf = TDA9887_PRESENT,
-+		.tuner_type   = TUNER_XC2028,
-+		.mts_firmware = 1,
-+		.decoder      = EM28XX_TVP5150,
-+		.input          = { {
-+			.type     = EM28XX_VMUX_TELEVISION,
-+			.vmux     = TVP5150_COMPOSITE0,
-+			.amux     = 0,
-+		}, {
-+			.type     = EM28XX_VMUX_COMPOSITE1,
-+			.vmux     = TVP5150_COMPOSITE1,
-+			.amux     = 1,
-+		}, {
-+			.type     = EM28XX_VMUX_SVIDEO,
-+			.vmux     = TVP5150_SVIDEO,
-+			.amux     = 1,
-+		} },
-+	},
-+	[EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950] = {
-+		.name           = "Hauppauge WinTV HVR 950",
-+		.vchannels      = 3,
-+		.tda9887_conf   = TDA9887_PRESENT,
-+		.tuner_type     = TUNER_XC2028,
-+		.mts_firmware   = 1,
-+		.has_12mhz_i2s  = 1,
-+		.decoder        = EM28XX_TVP5150,
-+		.input          = { {
- 			.type     = EM28XX_VMUX_TELEVISION,
--			.vmux     = SAA7115_COMPOSITE4,
-+			.vmux     = TVP5150_COMPOSITE0,
- 			.amux     = 0,
--		},{
-+		}, {
- 			.type     = EM28XX_VMUX_COMPOSITE1,
--			.vmux     = SAA7115_COMPOSITE0,
-+			.vmux     = TVP5150_COMPOSITE1,
- 			.amux     = 1,
--		},{
-+		}, {
- 			.type     = EM28XX_VMUX_SVIDEO,
--			.vmux     = SAA7115_SVIDEO3,
-+			.vmux     = TVP5150_SVIDEO,
- 			.amux     = 1,
--		}},
-+		} },
-+
-+		/* gpio's 4, 1, 0 */
-+		.analog_gpio = 0x003d2d,
-+	},
-+	[EM2880_BOARD_TERRATEC_HYBRID_XS] = {
-+		.name         = "Terratec Hybrid XS",
-+		.vchannels    = 3,
-+		.tda9887_conf = TDA9887_PRESENT,
-+		.tuner_type   = TUNER_XC2028,
-+		.decoder      = EM28XX_TVP5150,
-+		.input          = { {
-+			.type     = EM28XX_VMUX_TELEVISION,
-+			.vmux     = TVP5150_COMPOSITE0,
-+			.amux     = 0,
-+		}, {
-+			.type     = EM28XX_VMUX_COMPOSITE1,
-+			.vmux     = TVP5150_COMPOSITE1,
-+			.amux     = 1,
-+		}, {
-+			.type     = EM28XX_VMUX_SVIDEO,
-+			.vmux     = TVP5150_SVIDEO,
-+			.amux     = 1,
-+		} },
-+	},
-+	/* maybe there's a reason behind it why Terratec sells the Hybrid XS
-+	   as Prodigy XS with a different PID, let's keep it separated for now
-+	   maybe we'll need it lateron */
-+	[EM2880_BOARD_TERRATEC_PRODIGY_XS] = {
-+		.name         = "Terratec Prodigy XS",
-+		.vchannels    = 3,
-+		.tda9887_conf = TDA9887_PRESENT,
-+		.tuner_type   = TUNER_XC2028,
-+		.decoder      = EM28XX_TVP5150,
-+		.input          = { {
-+			.type     = EM28XX_VMUX_TELEVISION,
-+			.vmux     = TVP5150_COMPOSITE0,
-+			.amux     = 0,
-+		}, {
-+			.type     = EM28XX_VMUX_COMPOSITE1,
-+			.vmux     = TVP5150_COMPOSITE1,
-+			.amux     = 1,
-+		}, {
-+			.type     = EM28XX_VMUX_SVIDEO,
-+			.vmux     = TVP5150_SVIDEO,
-+			.amux     = 1,
-+		} },
-+	},
-+	[EM2820_BOARD_MSI_VOX_USB_2] = {
-+		.name		   = "MSI VOX USB 2.0",
-+		.vchannels	   = 3,
-+		.tuner_type	   = TUNER_LG_PAL_NEW_TAPC,
-+		.tda9887_conf	   = TDA9887_PRESENT      |
-+				     TDA9887_PORT1_ACTIVE |
-+				     TDA9887_PORT2_ACTIVE,
-+		.max_range_640_480 = 1,
-+
-+		.decoder           = EM28XX_SAA7114,
-+		.input             = { {
-+			.type      = EM28XX_VMUX_TELEVISION,
-+			.vmux      = SAA7115_COMPOSITE4,
-+			.amux      = 0,
-+		}, {
-+			.type      = EM28XX_VMUX_COMPOSITE1,
-+			.vmux      = SAA7115_COMPOSITE0,
-+			.amux      = 1,
-+		}, {
-+			.type      = EM28XX_VMUX_SVIDEO,
-+			.vmux      = SAA7115_SVIDEO3,
-+			.amux      = 1,
-+		} },
+ 	.pci_list = ivtv_pci_mpg160,
++	.i2c = &ivtv_i2c_std,
+ };
+ 
+ /* ------------------------------------------------------------------------- */
+@@ -350,6 +379,7 @@ static const struct ivtv_card ivtv_card_pg600 = {
+ 		{ .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FQ1286 },
+ 	},
+ 	.pci_list = ivtv_pci_pg600,
++	.i2c = &ivtv_i2c_std,
+ };
+ 
+ /* ------------------------------------------------------------------------- */
+@@ -393,6 +423,7 @@ static const struct ivtv_card ivtv_card_avc2410 = {
+ 		{ .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FM1236_MK3 },
+ 	},
+ 	.pci_list = ivtv_pci_avc2410,
++	.i2c = &ivtv_i2c_std,
+ };
+ 
+ /* ------------------------------------------------------------------------- */
+@@ -463,6 +494,7 @@ static const struct ivtv_card ivtv_card_tg5000tv = {
+ 		{ .std = V4L2_STD_525_60, .tuner = TUNER_PHILIPS_FQ1286 },
+ 	},
+ 	.pci_list = ivtv_pci_tg5000tv,
++	.i2c = &ivtv_i2c_std,
+ };
+ 
+ /* ------------------------------------------------------------------------- */
+@@ -493,6 +525,7 @@ static const struct ivtv_card ivtv_card_va2000 = {
+ 		{ .std = V4L2_STD_525_60, .tuner = TUNER_PHILIPS_FQ1286 },
+ 	},
+ 	.pci_list = ivtv_pci_va2000,
++	.i2c = &ivtv_i2c_std,
+ };
+ 
+ /* ------------------------------------------------------------------------- */
+@@ -537,6 +570,7 @@ static const struct ivtv_card ivtv_card_cx23416gyc = {
+ 		{ .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FM1236_MK3 },
+ 	},
+ 	.pci_list = ivtv_pci_cx23416gyc,
++	.i2c = &ivtv_i2c_std,
+ };
+ 
+ static const struct ivtv_card ivtv_card_cx23416gyc_nogr = {
+@@ -567,6 +601,7 @@ static const struct ivtv_card ivtv_card_cx23416gyc_nogr = {
+ 		{ .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
+ 		{ .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FM1236_MK3 },
+ 	},
++	.i2c = &ivtv_i2c_std,
+ };
+ 
+ static const struct ivtv_card ivtv_card_cx23416gyc_nogrycs = {
+@@ -596,6 +631,7 @@ static const struct ivtv_card ivtv_card_cx23416gyc_nogrycs = {
+ 		{ .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
+ 		{ .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FM1236_MK3 },
+ 	},
++	.i2c = &ivtv_i2c_std,
+ };
+ 
+ /* ------------------------------------------------------------------------- */
+@@ -635,6 +671,7 @@ static const struct ivtv_card ivtv_card_gv_mvprx = {
+ 		{ .std = V4L2_STD_525_60, .tuner = TUNER_PANASONIC_VP27 },
+ 	},
+ 	.pci_list = ivtv_pci_gv_mvprx,
++	.i2c = &ivtv_i2c_std,
+ };
+ 
+ /* ------------------------------------------------------------------------- */
+@@ -671,6 +708,7 @@ static const struct ivtv_card ivtv_card_gv_mvprx2e = {
+ 		{ .std = V4L2_STD_525_60, .tuner = TUNER_PANASONIC_VP27 },
+ 	},
+ 	.pci_list = ivtv_pci_gv_mvprx2e,
++	.i2c = &ivtv_i2c_std,
+ };
+ 
+ /* ------------------------------------------------------------------------- */
+@@ -705,6 +743,7 @@ static const struct ivtv_card ivtv_card_gotview_pci_dvd = {
+ 		{ .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
+ 	},
+ 	.pci_list = ivtv_pci_gotview_pci_dvd,
++	.i2c = &ivtv_i2c_std,
+ };
+ 
+ /* ------------------------------------------------------------------------- */
+@@ -743,6 +782,7 @@ static const struct ivtv_card ivtv_card_gotview_pci_dvd2 = {
+ 		{ .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
+ 	},
+ 	.pci_list = ivtv_pci_gotview_pci_dvd2,
++	.i2c = &ivtv_i2c_std,
+ };
+ 
+ /* ------------------------------------------------------------------------- */
+@@ -778,6 +818,7 @@ static const struct ivtv_card ivtv_card_yuan_mpc622 = {
+ 		{ .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_TDA8290 },
+ 	},
+ 	.pci_list = ivtv_pci_yuan_mpc622,
++	.i2c = &ivtv_i2c_tda8290,
+ };
+ 
+ /* ------------------------------------------------------------------------- */
+@@ -819,6 +860,7 @@ static const struct ivtv_card ivtv_card_dctmvtvp1 = {
+ 		{ .std = V4L2_STD_525_60, .tuner = TUNER_PHILIPS_FQ1286 },
+ 	},
+ 	.pci_list = ivtv_pci_dctmvtvp1,
++	.i2c = &ivtv_i2c_std,
+ };
+ 
+ /* ------------------------------------------------------------------------- */
+@@ -838,7 +880,7 @@ static const struct ivtv_card ivtv_card_pg600v2 = {
+ 	.hw_video = IVTV_HW_CX25840,
+ 	.hw_audio = IVTV_HW_CX25840,
+ 	.hw_audio_ctrl = IVTV_HW_CX25840,
+-	.hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER,
++	.hw_all = IVTV_HW_CX25840,
+ 	.video_inputs = {
+ 		{ IVTV_CARD_INPUT_SVIDEO1,    0,
+ 		  CX25840_SVIDEO_LUMA3 | CX25840_SVIDEO_CHROMA4 },
+@@ -847,10 +889,8 @@ static const struct ivtv_card ivtv_card_pg600v2 = {
+ 	.audio_inputs = {
+ 		{ IVTV_CARD_INPUT_LINE_IN1,   CX25840_AUDIO_SERIAL },
+ 	},
+-	.tuners = {
+-		{ .std = V4L2_STD_ALL, .tuner = TUNER_XCEIVE_XC3028 },
+-	},
+ 	.pci_list = ivtv_pci_pg600v2,
++	.i2c = &ivtv_i2c_std,
+ };
+ 
+ /* ------------------------------------------------------------------------- */
+@@ -871,17 +911,22 @@ static const struct ivtv_card ivtv_card_club3d = {
+ 	.hw_audio_ctrl = IVTV_HW_CX25840,
+ 	.hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER,
+ 	.video_inputs = {
+-		{ IVTV_CARD_INPUT_SVIDEO1,    0,
++		{ IVTV_CARD_INPUT_VID_TUNER,  0, CX25840_COMPOSITE2 },
++		{ IVTV_CARD_INPUT_SVIDEO1,    1,
+ 		  CX25840_SVIDEO_LUMA3 | CX25840_SVIDEO_CHROMA4 },
+-		{ IVTV_CARD_INPUT_COMPOSITE1, 0, CX25840_COMPOSITE3 },
++		{ IVTV_CARD_INPUT_COMPOSITE1, 1, CX25840_COMPOSITE3 },
  	},
- 	[EM2800_BOARD_TERRATEC_CINERGY_200] = {
- 		.name         = "Terratec Cinergy 200 USB",
- 		.is_em2800    = 1,
- 		.vchannels    = 3,
--		.norm         = VIDEO_MODE_PAL,
- 		.tuner_type   = TUNER_LG_PAL_NEW_TAPC,
- 		.tda9887_conf = TDA9887_PRESENT,
--		.has_tuner    = 1,
- 		.decoder      = EM28XX_SAA7113,
--		.input          = {{
-+		.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,
--		}},
-+		} },
+ 	.audio_inputs = {
++		{ IVTV_CARD_INPUT_AUD_TUNER,  CX25840_AUDIO5       },
+ 		{ IVTV_CARD_INPUT_LINE_IN1,   CX25840_AUDIO_SERIAL },
  	},
- 	[EM2800_BOARD_LEADTEK_WINFAST_USBII] = {
- 		.name         = "Leadtek Winfast USB II",
- 		.is_em2800    = 1,
- 		.vchannels    = 3,
--		.norm         = VIDEO_MODE_PAL,
- 		.tuner_type   = TUNER_LG_PAL_NEW_TAPC,
- 		.tda9887_conf = TDA9887_PRESENT,
--		.has_tuner    = 1,
- 		.decoder      = EM28XX_SAA7113,
--		.input          = {{
-+		.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,
--		}},
-+		} },
++	.radio_input = { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5 },
++	.gpio_init = { .direction = 0x1000, .initial_value = 0x1000 }, /* tuner reset */
+ 	.tuners = {
+-		{ .std = V4L2_STD_ALL, .tuner = TUNER_XCEIVE_XC3028 },
++		{ .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 },
  	},
- 	[EM2800_BOARD_KWORLD_USB2800] = {
- 		.name         = "Kworld USB2800",
- 		.is_em2800    = 1,
- 		.vchannels    = 3,
--		.norm         = VIDEO_MODE_PAL,
- 		.tuner_type   = TUNER_PHILIPS_ATSC,
- 		.tda9887_conf = TDA9887_PRESENT,
--		.has_tuner    = 1,
- 		.decoder      = EM28XX_SAA7113,
--		.input          = {{
-+		.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,
--		}},
-+		} },
+ 	.pci_list = ivtv_pci_club3d,
++	.i2c = &ivtv_i2c_std,
+ };
+ 
+ /* ------------------------------------------------------------------------- */
+@@ -900,7 +945,7 @@ static const struct ivtv_card ivtv_card_avertv_mce116 = {
+ 	.hw_video = IVTV_HW_CX25840,
+ 	.hw_audio = IVTV_HW_CX25840,
+ 	.hw_audio_ctrl = IVTV_HW_CX25840,
+-	.hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER | IVTV_HW_WM8739,
++	.hw_all = IVTV_HW_CX25840 | IVTV_HW_WM8739,
+ 	.video_inputs = {
+ 		{ IVTV_CARD_INPUT_SVIDEO1,    0, CX25840_SVIDEO3    },
+ 		{ IVTV_CARD_INPUT_COMPOSITE1, 0, CX25840_COMPOSITE1 },
+@@ -909,10 +954,115 @@ static const struct ivtv_card ivtv_card_avertv_mce116 = {
+ 		{ IVTV_CARD_INPUT_LINE_IN1,   CX25840_AUDIO_SERIAL, 1 },
  	},
- 	[EM2820_BOARD_PINNACLE_DVC_90] = {
--		.name         = "Pinnacle Dazzle DVC 90",
-+		.name         = "Pinnacle Dazzle DVC 90/DVC 100",
-+		.vchannels    = 3,
-+		.tuner_type   = TUNER_ABSENT,
-+		.decoder      = EM28XX_SAA7113,
-+		.input          = { {
-+			.type     = EM28XX_VMUX_COMPOSITE1,
-+			.vmux     = SAA7115_COMPOSITE0,
-+			.amux     = 1,
-+		}, {
-+			.type     = EM28XX_VMUX_SVIDEO,
-+			.vmux     = SAA7115_SVIDEO3,
-+			.amux     = 1,
-+		} },
+ 	.gpio_init = { .direction = 0xe000, .initial_value = 0x4000 }, /* enable line-in */
++	.pci_list = ivtv_pci_avertv_mce116,
++	.i2c = &ivtv_i2c_std,
++};
++
++/* ------------------------------------------------------------------------- */
++
++/* AVerMedia PVR-150 Plus (M113) card */
++
++static const struct ivtv_card_pci_info ivtv_pci_aver_pvr150[] = {
++	{ PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_AVERMEDIA, 0xc035 },
++	{ 0, 0, 0 }
++};
++
++static const struct ivtv_card ivtv_card_aver_pvr150 = {
++	.type = IVTV_CARD_AVER_PVR150PLUS,
++	.name = "AVerMedia PVR-150 Plus",
++	.v4l2_capabilities = IVTV_CAP_ENCODER,
++	.hw_video = IVTV_HW_CX25840,
++	.hw_audio = IVTV_HW_CX25840,
++	.hw_audio_ctrl = IVTV_HW_CX25840,
++	.hw_muxer = IVTV_HW_GPIO,
++	.hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER,
++	.video_inputs = {
++		{ IVTV_CARD_INPUT_VID_TUNER,  0, CX25840_COMPOSITE2 },
++		{ IVTV_CARD_INPUT_SVIDEO1,    1,
++		  CX25840_SVIDEO_LUMA3 | CX25840_SVIDEO_CHROMA4 },
++		{ IVTV_CARD_INPUT_COMPOSITE1, 1, CX25840_COMPOSITE1 },
 +	},
-+	[EM2800_BOARD_VGEAR_POCKETTV] = {
-+		.name         = "V-Gear PocketTV",
-+		.is_em2800    = 1,
-+		.vchannels    = 3,
-+		.tuner_type   = TUNER_LG_PAL_NEW_TAPC,
-+		.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,
-+		} },
++	.audio_inputs = {
++		{ IVTV_CARD_INPUT_AUD_TUNER,  CX25840_AUDIO5,       0 },
++		{ IVTV_CARD_INPUT_LINE_IN1,   CX25840_AUDIO_SERIAL, 1 },
 +	},
-+	[EM2820_BOARD_PROLINK_PLAYTV_USB2] = {
-+		.name         = "Pixelview Prolink PlayTV USB 2.0",
- 		.vchannels    = 3,
--		.norm         = VIDEO_MODE_PAL,
--		.has_tuner    = 0,
-+		.tda9887_conf = TDA9887_PRESENT,
-+		.tuner_type   = TUNER_YMEC_TVF_5533MF,
- 		.decoder      = EM28XX_SAA7113,
--		.input          = {{
-+		.input          = { {
-+			.type     = EM28XX_VMUX_TELEVISION,
-+			.vmux     = SAA7115_COMPOSITE2,
-+			.amux     = 1,
-+		}, {
- 			.type     = EM28XX_VMUX_COMPOSITE1,
- 			.vmux     = SAA7115_COMPOSITE0,
- 			.amux     = 1,
--		},{
-+		}, {
- 			.type     = EM28XX_VMUX_SVIDEO,
- 			.vmux     = SAA7115_SVIDEO3,
- 			.amux     = 1,
--		}},
-+		} },
++	.radio_input = { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO_SERIAL, 2 },
++	.gpio_init = { .direction = 0x0800, .initial_value = 0 },
++	.gpio_audio_input  = { .mask = 0x0800, .tuner = 0, .linein = 0, .radio = 0x0800 },
+ 	.tuners = {
+-		{ .std = V4L2_STD_ALL, .tuner = TUNER_XCEIVE_XC3028 },
++		/* This card has a Partsnic PTI-5NF05 tuner */
++		{ .std = V4L2_STD_525_60, .tuner = TUNER_TCL_2002N },
  	},
+-	.pci_list = ivtv_pci_avertv_mce116,
++	.pci_list = ivtv_pci_aver_pvr150,
++	.i2c = &ivtv_i2c_radio,
++};
++
++/* ------------------------------------------------------------------------- */
++
++/* AVerMedia EZMaker PCI Deluxe card */
++
++static const struct ivtv_card_pci_info ivtv_pci_aver_ezmaker[] = {
++	{ PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_AVERMEDIA, 0xc03f },
++	{ 0, 0, 0 }
++};
++
++static const struct ivtv_card ivtv_card_aver_ezmaker = {
++	.type = IVTV_CARD_AVER_EZMAKER,
++	.name = "AVerMedia EZMaker PCI Deluxe",
++	.v4l2_capabilities = IVTV_CAP_ENCODER,
++	.hw_video = IVTV_HW_CX25840,
++	.hw_audio = IVTV_HW_CX25840,
++	.hw_audio_ctrl = IVTV_HW_CX25840,
++	.hw_all = IVTV_HW_CX25840 | IVTV_HW_WM8739,
++	.video_inputs = {
++		{ IVTV_CARD_INPUT_SVIDEO1,    0, CX25840_SVIDEO3 },
++		{ IVTV_CARD_INPUT_COMPOSITE1, 0, CX25840_COMPOSITE1 },
++	},
++	.audio_inputs = {
++		{ IVTV_CARD_INPUT_LINE_IN1,   CX25840_AUDIO_SERIAL, 0 },
++	},
++	.gpio_init = { .direction = 0x4000, .initial_value = 0x4000 },
++	/* Does not have a tuner */
++	.pci_list = ivtv_pci_aver_ezmaker,
++};
++
++/* ------------------------------------------------------------------------- */
++
++/* ASUS Falcon2 */
++
++static const struct ivtv_card_pci_info ivtv_pci_asus_falcon2[] = {
++	{ PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_ASUSTEK, 0x4b66 },
++	{ PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_ASUSTEK, 0x462e },
++	{ PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_ASUSTEK, 0x4b2e },
++	{ 0, 0, 0 }
++};
++
++static const struct ivtv_card ivtv_card_asus_falcon2 = {
++	.type = IVTV_CARD_ASUS_FALCON2,
++	.name = "ASUS Falcon2",
++	.v4l2_capabilities = IVTV_CAP_ENCODER,
++	.hw_video = IVTV_HW_CX25840,
++	.hw_audio = IVTV_HW_CX25840,
++	.hw_audio_ctrl = IVTV_HW_CX25840,
++	.hw_muxer = IVTV_HW_M52790,
++	.hw_all = IVTV_HW_CX25840 | IVTV_HW_M52790 | IVTV_HW_TUNER,
++	.video_inputs = {
++		{ IVTV_CARD_INPUT_VID_TUNER,  0, CX25840_COMPOSITE2 },
++		{ IVTV_CARD_INPUT_SVIDEO1,    1, CX25840_SVIDEO3    },
++		{ IVTV_CARD_INPUT_COMPOSITE1, 2, CX25840_COMPOSITE2 },
++	},
++	.audio_inputs = {
++		{ IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5, M52790_IN_TUNER },
++		{ IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL,
++			M52790_IN_V2 | M52790_SW1_YCMIX | M52790_SW2_YCMIX },
++		{ IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL, M52790_IN_V2 },
++	},
++	.radio_input = { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO_SERIAL, M52790_IN_TUNER },
++	.tuners = {
++		{ .std = V4L2_STD_525_60, .tuner = TUNER_PHILIPS_FM1236_MK3 },
++	},
++	.pci_list = ivtv_pci_asus_falcon2,
++	.i2c = &ivtv_i2c_std,
  };
- const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards);
  
- /* table of devices that work with this driver */
- struct usb_device_id em28xx_id_table [] = {
--	{ USB_DEVICE(0xeb1a, 0x2800), .driver_info = EM2800_BOARD_UNKNOWN },
--	{ USB_DEVICE(0xeb1a, 0x2820), .driver_info = EM2820_BOARD_MSI_VOX_USB_2 },
--	{ USB_DEVICE(0x0ccd, 0x0036), .driver_info = EM2820_BOARD_TERRATEC_CINERGY_250 },
--	{ USB_DEVICE(0x2304, 0x0208), .driver_info = EM2820_BOARD_PINNACLE_USB_2 },
--	{ USB_DEVICE(0x2040, 0x4200), .driver_info = EM2820_BOARD_HAUPPAUGE_WINTV_USB_2 },
--	{ USB_DEVICE(0x2304, 0x0207), .driver_info = EM2820_BOARD_PINNACLE_DVC_90 },
-+	{ USB_DEVICE(0xeb1a, 0x2750),
-+			.driver_info = EM2820_BOARD_UNKNOWN },
-+	{ USB_DEVICE(0xeb1a, 0x2800),
-+			.driver_info = EM2800_BOARD_UNKNOWN },
-+	{ USB_DEVICE(0xeb1a, 0x2820),
-+			.driver_info = EM2820_BOARD_UNKNOWN },
-+	{ USB_DEVICE(0xeb1a, 0x2821),
-+			.driver_info = EM2820_BOARD_UNKNOWN },
-+	{ USB_DEVICE(0xeb1a, 0x2860),
-+			.driver_info = EM2820_BOARD_UNKNOWN },
-+	{ USB_DEVICE(0xeb1a, 0x2861),
-+			.driver_info = EM2820_BOARD_UNKNOWN },
-+	{ USB_DEVICE(0xeb1a, 0x2870),
-+			.driver_info = EM2820_BOARD_UNKNOWN },
-+	{ USB_DEVICE(0xeb1a, 0x2881),
-+			.driver_info = EM2820_BOARD_UNKNOWN },
-+	{ USB_DEVICE(0xeb1a, 0x2883),
-+			.driver_info = EM2820_BOARD_UNKNOWN },
-+	{ USB_DEVICE(0x0ccd, 0x0036),
-+			.driver_info = EM2820_BOARD_TERRATEC_CINERGY_250 },
-+	{ USB_DEVICE(0x2304, 0x0208),
-+			.driver_info = EM2820_BOARD_PINNACLE_USB_2 },
-+	{ USB_DEVICE(0x2040, 0x4200),
-+			.driver_info = EM2820_BOARD_HAUPPAUGE_WINTV_USB_2 },
-+	{ USB_DEVICE(0x2040, 0x4201),
-+			.driver_info = EM2820_BOARD_HAUPPAUGE_WINTV_USB_2 },
-+	{ USB_DEVICE(0x2304, 0x0207),
-+			.driver_info = EM2820_BOARD_PINNACLE_DVC_90 },
-+	{ USB_DEVICE(0x2304, 0x021a),
-+			.driver_info = EM2820_BOARD_PINNACLE_DVC_90 },
-+	{ USB_DEVICE(0x2040, 0x6500),
-+			.driver_info = EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900 },
-+	{ USB_DEVICE(0x2040, 0x6513),
-+			.driver_info = EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950 },
-+	{ USB_DEVICE(0x0ccd, 0x0042),
-+			.driver_info = EM2880_BOARD_TERRATEC_HYBRID_XS },
-+	{ USB_DEVICE(0x0ccd, 0x0047),
-+			.driver_info = EM2880_BOARD_TERRATEC_PRODIGY_XS },
- 	{ },
+ static const struct ivtv_card *ivtv_card_list[] = {
+@@ -937,6 +1087,9 @@ static const struct ivtv_card *ivtv_card_list[] = {
+ 	&ivtv_card_pg600v2,
+ 	&ivtv_card_club3d,
+ 	&ivtv_card_avertv_mce116,
++	&ivtv_card_asus_falcon2,
++	&ivtv_card_aver_pvr150,
++	&ivtv_card_aver_ezmaker,
+ 
+ 	/* Variations of standard cards but with the same PCI IDs.
+ 	   These cards must come last in this list. */
+diff --git a/drivers/media/video/ivtv/ivtv-cards.h b/drivers/media/video/ivtv/ivtv-cards.h
+index ff46e5a..191aafd 100644
+--- a/drivers/media/video/ivtv/ivtv-cards.h
++++ b/drivers/media/video/ivtv/ivtv-cards.h
+@@ -45,7 +45,10 @@
+ #define IVTV_CARD_PG600V2	     18 /* Yuan PG600V2/GotView PCI DVD Lite */
+ #define IVTV_CARD_CLUB3D	     19 /* Club3D ZAP-TV1x01 */
+ #define IVTV_CARD_AVERTV_MCE116	     20 /* AVerTV MCE 116 Plus */
+-#define IVTV_CARD_LAST 		     20
++#define IVTV_CARD_ASUS_FALCON2	     21 /* ASUS Falcon2 */
++#define IVTV_CARD_AVER_PVR150PLUS    22 /* AVerMedia PVR-150 Plus */
++#define IVTV_CARD_AVER_EZMAKER       23 /* AVerMedia EZMaker PCI Deluxe */
++#define IVTV_CARD_LAST 		     23
+ 
+ /* Variants of existing cards but with the same PCI IDs. The driver
+    detects these based on other device information.
+@@ -69,6 +72,7 @@
+ #define IVTV_PCI_ID_HAUPPAUGE_ALT1 	0x0270
+ #define IVTV_PCI_ID_HAUPPAUGE_ALT2 	0x4070
+ #define IVTV_PCI_ID_ADAPTEC 		0x9005
++#define IVTV_PCI_ID_ASUSTEK 		0x1043
+ #define IVTV_PCI_ID_AVERMEDIA 		0x1461
+ #define IVTV_PCI_ID_YUAN1		0x12ab
+ #define IVTV_PCI_ID_YUAN2 		0xff01
+@@ -80,7 +84,7 @@
+ #define IVTV_PCI_ID_GOTVIEW1		0xffac
+ #define IVTV_PCI_ID_GOTVIEW2 		0xffad
+ 
+-/* hardware flags */
++/* hardware flags, no gaps allowed, IVTV_HW_GPIO must always be last */
+ #define IVTV_HW_CX25840   (1 << 0)
+ #define IVTV_HW_SAA7115   (1 << 1)
+ #define IVTV_HW_SAA7127   (1 << 2)
+@@ -90,12 +94,12 @@
+ #define IVTV_HW_CS53L32A  (1 << 6)
+ #define IVTV_HW_TVEEPROM  (1 << 7)
+ #define IVTV_HW_SAA7114   (1 << 8)
+-#define IVTV_HW_TVAUDIO   (1 << 9)
+-#define IVTV_HW_UPD64031A (1 << 10)
+-#define IVTV_HW_UPD6408X  (1 << 11)
+-#define IVTV_HW_SAA717X   (1 << 12)
+-#define IVTV_HW_WM8739    (1 << 13)
+-#define IVTV_HW_VP27SMPX  (1 << 14)
++#define IVTV_HW_UPD64031A (1 << 9)
++#define IVTV_HW_UPD6408X  (1 << 10)
++#define IVTV_HW_SAA717X   (1 << 11)
++#define IVTV_HW_WM8739    (1 << 12)
++#define IVTV_HW_VP27SMPX  (1 << 13)
++#define IVTV_HW_M52790    (1 << 14)
+ #define IVTV_HW_GPIO      (1 << 15)
+ 
+ #define IVTV_HW_SAA711X   (IVTV_HW_SAA7115 | IVTV_HW_SAA7114)
+@@ -230,6 +234,12 @@ struct ivtv_card_tuner {
+ 	int 	    tuner; 	/* tuner ID (from tuner.h) */
  };
-+MODULE_DEVICE_TABLE(usb, em28xx_id_table);
-+
-+/* EEPROM hash table for devices with generic USB IDs */
-+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},
+ 
++struct ivtv_card_tuner_i2c {
++	unsigned short radio[2];/* radio tuner i2c address to probe */
++	unsigned short demod[2];/* demodulator i2c address to probe */
++	unsigned short tv[4];	/* tv tuner i2c addresses to probe */
 +};
 +
-+/* I2C devicelist hash table for devices with generic USB IDs */
-+static struct em28xx_hash_table em28xx_i2c_hash[] = {
-+	{0xb06a32c3, EM2800_BOARD_TERRATEC_CINERGY_200, TUNER_LG_PAL_NEW_TAPC},
-+	{0xf51200e3, EM2800_BOARD_VGEAR_POCKETTV, TUNER_LG_PAL_NEW_TAPC},
-+};
+ /* for card information/parameters */
+ struct ivtv_card {
+ 	int type;
+@@ -257,6 +267,7 @@ struct ivtv_card {
+ 	struct ivtv_gpio_audio_detect 	gpio_audio_detect;
  
-+/* Since em28xx_pre_card_setup() requires a proper dev->model,
-+ * this won't work for boards with generic PCI IDs
-+ */
- void em28xx_pre_card_setup(struct em28xx *dev)
+ 	struct ivtv_card_tuner tuners[IVTV_CARD_MAX_TUNERS];
++	struct ivtv_card_tuner_i2c *i2c;
+ 
+ 	/* list of device and subsystem vendor/devices that
+ 	   correspond to this card type. */
+diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c
+index 6d2dd87..d42f120 100644
+--- a/drivers/media/video/ivtv/ivtv-driver.c
++++ b/drivers/media/video/ivtv/ivtv-driver.c
+@@ -59,6 +59,7 @@
+ #include <media/tveeprom.h>
+ #include <media/saa7115.h>
+ #include <media/v4l2-chip-ident.h>
++#include "tuner-xc2028.h"
+ 
+ /* var to keep track of the number of array elements in use */
+ int ivtv_cards_active = 0;
+@@ -185,6 +186,9 @@ MODULE_PARM_DESC(cardtype,
+ 		 "\t\t\t19 = Yuan PG600V2/GotView PCI DVD Lite\n"
+ 		 "\t\t\t20 = Club3D ZAP-TV1x01\n"
+ 		 "\t\t\t21 = AverTV MCE 116 Plus\n"
++		 "\t\t\t22 = ASUS Falcon2\n"
++		 "\t\t\t23 = AverMedia PVR-150 Plus\n"
++		 "\t\t\t24 = AverMedia EZMaker PCI Deluxe\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");
+@@ -397,6 +401,7 @@ static void ivtv_process_eeprom(struct ivtv *itv)
+ 
+ 	itv->v4l2_cap = itv->card->v4l2_capabilities;
+ 	itv->card_name = itv->card->name;
++	itv->card_i2c = itv->card->i2c;
+ 
+ 	/* If this is a PVR500 then it should be possible to detect whether it is the
+ 	   first or second unit by looking at the subsystem device ID: is bit 4 is
+@@ -414,7 +419,14 @@ static void ivtv_process_eeprom(struct ivtv *itv)
+ 	   This detection is needed since the eeprom reports incorrectly that a radio is
+ 	   present on the second unit. */
+ 	if (tv.model / 1000 == 23) {
++		static const struct ivtv_card_tuner_i2c ivtv_i2c_radio = {
++			.radio = { 0x60, I2C_CLIENT_END },
++			.demod = { 0x43, I2C_CLIENT_END },
++			.tv = { 0x61, I2C_CLIENT_END },
++		};
++
+ 		itv->card_name = "WinTV PVR 500";
++		itv->card_i2c = &ivtv_i2c_radio;
+ 		if (pci_slot == 8 || pci_slot == 9) {
+ 			int is_first = (pci_slot & 1) == 0;
+ 
+@@ -628,10 +640,11 @@ done:
+ 		IVTV_ERR("Defaulting to %s card\n", itv->card->name);
+ 		IVTV_ERR("Please mail the vendor/device and subsystem vendor/device IDs and what kind of\n");
+ 		IVTV_ERR("card you have to the ivtv-devel mailinglist (www.ivtvdriver.org)\n");
+-		IVTV_ERR("Prefix your subject line with [UNKNOWN CARD].\n");
++		IVTV_ERR("Prefix your subject line with [UNKNOWN IVTV CARD].\n");
+ 	}
+ 	itv->v4l2_cap = itv->card->v4l2_capabilities;
+ 	itv->card_name = itv->card->name;
++	itv->card_i2c = itv->card->i2c;
+ }
+ 
+ /* Precondition: the ivtv structure has been memset to 0. Only
+@@ -695,6 +708,7 @@ static int __devinit ivtv_init_struct1(struct ivtv *itv)
+ 	atomic_set(&itv->yuv_info.next_dma_frame, -1);
+ 	itv->yuv_info.lace_mode = ivtv_yuv_mode;
+ 	itv->yuv_info.lace_threshold = ivtv_yuv_threshold;
++	itv->yuv_info.max_frames_buffered = 3;
+ 	return 0;
+ }
+ 
+@@ -812,75 +826,61 @@ static int ivtv_setup_pci(struct ivtv *itv, struct pci_dev *dev,
+ 	return 0;
+ }
+ 
+-static void ivtv_request_module(struct ivtv *itv, const char *name)
++static u32 ivtv_request_module(struct ivtv *itv, u32 hw,
++		const char *name, u32 id)
  {
- 	/* request some modules */
--	switch(dev->model){
--		case EM2880_BOARD_TERRATEC_PRODIGY_XS:
--		case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900:
--		case EM2880_BOARD_TERRATEC_HYBRID_XS:
--			{
--				em28xx_write_regs_req(dev, 0x00, 0x08, "\x7d", 1); // reset through GPIO?
--				break;
-+	switch (dev->model) {
-+	case EM2880_BOARD_TERRATEC_PRODIGY_XS:
-+	case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900:
-+	case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950:
-+	case EM2880_BOARD_TERRATEC_HYBRID_XS:
-+		em28xx_write_regs(dev, XCLK_REG, "\x27", 1);
-+		em28xx_write_regs(dev, I2C_CLK_REG, "\x40", 1);
-+		em28xx_write_regs(dev, 0x08, "\xff", 1);
-+		em28xx_write_regs(dev, 0x04, "\x00", 1);
-+		msleep(100);
-+		em28xx_write_regs(dev, 0x04, "\x08", 1);
-+		msleep(100);
-+		em28xx_write_regs(dev, 0x08, "\xff", 1);
-+		msleep(50);
-+		em28xx_write_regs(dev, 0x08, "\x2d", 1);
-+		msleep(50);
-+		em28xx_write_regs(dev, 0x08, "\x3d", 1);
-+		break;
-+	}
-+}
++	if ((hw & id) == 0)
++		return hw;
+ 	if (request_module(name) != 0) {
+ 		IVTV_ERR("Failed to load module %s\n", name);
+-	} else {
+-		IVTV_DEBUG_INFO("Loaded module %s\n", name);
++		return hw & ~id;
+ 	}
++	IVTV_DEBUG_INFO("Loaded module %s\n", name);
++	return hw;
+ }
+ 
+ static void ivtv_load_and_init_modules(struct ivtv *itv)
+ {
+ 	u32 hw = itv->card->hw_all;
+-	int i;
++	unsigned i;
+ 
+ 	/* load modules */
+ #ifndef CONFIG_VIDEO_TUNER
+-	if (hw & IVTV_HW_TUNER) {
+-		if (itv->options.tuner == TUNER_XCEIVE_XC3028) {
+-			IVTV_INFO("Xceive tuner not yet supported, only composite and S-Video inputs will be available\n");
+-			itv->tunerid = 1;
+-		}
+-		else {
+-			ivtv_request_module(itv, "tuner");
+-		}
+-	}
++	hw = ivtv_request_module(itv, hw, "tuner", IVTV_HW_TUNER);
+ #endif
+ #ifndef CONFIG_VIDEO_CX25840
+-	if (hw & IVTV_HW_CX25840)
+-		ivtv_request_module(itv, "cx25840");
++	hw = ivtv_request_module(itv, hw, "cx25840", IVTV_HW_CX25840);
+ #endif
+ #ifndef CONFIG_VIDEO_SAA711X
+-	if (hw & IVTV_HW_SAA711X)
+-		ivtv_request_module(itv, "saa7115");
++	hw = ivtv_request_module(itv, hw, "saa7115", IVTV_HW_SAA711X);
+ #endif
+ #ifndef CONFIG_VIDEO_SAA7127
+-	if (hw & IVTV_HW_SAA7127)
+-		ivtv_request_module(itv, "saa7127");
++	hw = ivtv_request_module(itv, hw, "saa7127", IVTV_HW_SAA7127);
+ #endif
+-	if (hw & IVTV_HW_SAA717X)
+-		ivtv_request_module(itv, "saa717x");
++	hw = ivtv_request_module(itv, hw, "saa717x", IVTV_HW_SAA717X);
+ #ifndef CONFIG_VIDEO_UPD64031A
+-	if (hw & IVTV_HW_UPD64031A)
+-		ivtv_request_module(itv, "upd64031a");
++	hw = ivtv_request_module(itv, hw, "upd64031a", IVTV_HW_UPD64031A);
+ #endif
+ #ifndef CONFIG_VIDEO_UPD64083
+-	if (hw & IVTV_HW_UPD6408X)
+-		ivtv_request_module(itv, "upd64083");
++	hw = ivtv_request_module(itv, hw, "upd64083", IVTV_HW_UPD6408X);
+ #endif
+ #ifndef CONFIG_VIDEO_MSP3400
+-	if (hw & IVTV_HW_MSP34XX)
+-		ivtv_request_module(itv, "msp3400");
++	hw = ivtv_request_module(itv, hw, "msp3400", IVTV_HW_MSP34XX);
+ #endif
+ #ifndef CONFIG_VIDEO_VP27SMPX
+-	if (hw & IVTV_HW_VP27SMPX)
+-		ivtv_request_module(itv, "vp27smpx");
++	hw = ivtv_request_module(itv, hw, "vp27smpx", IVTV_HW_VP27SMPX);
+ #endif
+-	if (hw & IVTV_HW_TVAUDIO)
+-		ivtv_request_module(itv, "tvaudio");
+ #ifndef CONFIG_VIDEO_WM8775
+-	if (hw & IVTV_HW_WM8775)
+-		ivtv_request_module(itv, "wm8775");
++	hw = ivtv_request_module(itv, hw, "wm8775", IVTV_HW_WM8775);
+ #endif
+ #ifndef CONFIG_VIDEO_WM8739
+-	if (hw & IVTV_HW_WM8739)
+-		ivtv_request_module(itv, "wm8739");
++	hw = ivtv_request_module(itv, hw, "wm8739", IVTV_HW_WM8739);
+ #endif
+ #ifndef CONFIG_VIDEO_CS53L32A
+-	if (hw & IVTV_HW_CS53L32A)
+-		ivtv_request_module(itv, "cs53l32a");
++	hw = ivtv_request_module(itv, hw, "cs53l32a", IVTV_HW_CS53L32A);
++#endif
++#ifndef CONFIG_VIDEO_M52790
++	hw = ivtv_request_module(itv, hw, "m52790", IVTV_HW_M52790);
+ #endif
+ 
+ 	/* check which i2c devices are actually found */
+@@ -889,11 +889,12 @@ static void ivtv_load_and_init_modules(struct ivtv *itv)
+ 
+ 		if (!(device & hw))
+ 			continue;
+-		if (device == IVTV_HW_GPIO) {
+-			/* GPIO is always available */
+-			itv->hw_flags |= IVTV_HW_GPIO;
++		if (device == IVTV_HW_GPIO || device == IVTV_HW_TVEEPROM) {
++			/* GPIO and TVEEPROM do not use i2c probing */
++			itv->hw_flags |= device;
+ 			continue;
+ 		}
++		ivtv_i2c_register(itv, i);
+ 		if (ivtv_i2c_hw_addr(itv, device) > 0)
+ 			itv->hw_flags |= device;
+ 	}
+@@ -964,7 +965,6 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
+ 				const struct pci_device_id *pci_id)
+ {
+ 	int retval = 0;
+-	int yuv_buf_size;
+ 	int vbi_buf_size;
+ 	struct ivtv *itv;
+ 
+@@ -979,7 +979,7 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
+ 	}
+ 
+ 	itv = kzalloc(sizeof(struct ivtv), GFP_ATOMIC);
+-	if (itv == 0) {
++	if (itv == NULL) {
+ 		spin_unlock(&ivtv_cards_lock);
+ 		return -ENOMEM;
+ 	}
+@@ -1068,9 +1068,6 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
+ 	IVTV_DEBUG_INFO("Active card count: %d.\n", ivtv_cards_active);
+ 
+ 	if (itv->card->hw_all & IVTV_HW_TVEEPROM) {
+-#ifdef CONFIG_VIDEO_TVEEPROM_MODULE
+-		ivtv_request_module(itv, "tveeprom");
+-#endif
+ 		/* Based on the model number the cardtype may be changed.
+ 		   The PCI IDs are not always reliable. */
+ 		ivtv_process_eeprom(itv);
+@@ -1111,16 +1108,19 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
+ 		itv->is_50hz = 1;
+ 		itv->is_out_50hz = 1;
+ 	}
 +
-+static int em28xx_tuner_callback(void *ptr, int command, int arg)
-+{
-+	int rc = 0;
-+	struct em28xx *dev = ptr;
++	itv->yuv_info.osd_full_w = 720;
++	itv->yuv_info.osd_full_h = itv->is_out_50hz ? 576 : 480;
++	itv->yuv_info.v4l2_src_w = itv->yuv_info.osd_full_w;
++	itv->yuv_info.v4l2_src_h = itv->yuv_info.osd_full_h;
 +
-+	if (dev->tuner_type != TUNER_XC2028)
-+		return 0;
+ 	itv->params.video_gop_size = itv->is_60hz ? 15 : 12;
+ 
+ 	itv->stream_buf_size[IVTV_ENC_STREAM_TYPE_MPG] = 0x08000;
+ 	itv->stream_buf_size[IVTV_ENC_STREAM_TYPE_PCM] = 0x01200;
+ 	itv->stream_buf_size[IVTV_DEC_STREAM_TYPE_MPG] = 0x10000;
+-
+-	/* 0x15180 == 720 * 480 / 4, 0x19500 == 720 * 576 / 4 */
+-	yuv_buf_size = itv->is_60hz ? 0x15180 : 0x19500;
+-	itv->stream_buf_size[IVTV_DEC_STREAM_TYPE_YUV] = yuv_buf_size / 2;
+-	itv->stream_buf_size[IVTV_ENC_STREAM_TYPE_YUV] = yuv_buf_size / 8;
++	itv->stream_buf_size[IVTV_DEC_STREAM_TYPE_YUV] = 0x10000;
++	itv->stream_buf_size[IVTV_ENC_STREAM_TYPE_YUV] = 0x08000;
+ 
+ 	/* Setup VBI Raw Size. Should be big enough to hold PAL.
+ 	   It is possible to switch between PAL and NTSC, so we need to
+@@ -1140,13 +1140,26 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
+ 	if (itv->options.radio > 0)
+ 		itv->v4l2_cap |= V4L2_CAP_RADIO;
+ 
+-	if (itv->options.tuner > -1 && itv->tunerid == 0) {
++	if (itv->options.tuner > -1) {
+ 		struct tuner_setup setup;
+ 
+ 		setup.addr = ADDR_UNSET;
+ 		setup.type = itv->options.tuner;
+ 		setup.mode_mask = T_ANALOG_TV;  /* matches TV tuners */
++		setup.tuner_callback = (setup.type == TUNER_XC2028) ?
++			ivtv_reset_tuner_gpio : NULL;
+ 		ivtv_call_i2c_clients(itv, TUNER_SET_TYPE_ADDR, &setup);
++		if (setup.type == TUNER_XC2028) {
++			static struct xc2028_ctrl ctrl = {
++				.fname = XC2028_DEFAULT_FIRMWARE,
++				.max_len = 64,
++			};
++			struct v4l2_priv_tun_config cfg = {
++				.tuner = itv->options.tuner,
++				.priv = &ctrl,
++			};
++			ivtv_call_i2c_clients(itv, TUNER_SET_CONFIG, &cfg);
++		}
+ 	}
+ 
+ 	/* The tuner is fixed to the standard. The other inputs (e.g. S-Video)
+diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h
+index 49ce14d..536140f 100644
+--- a/drivers/media/video/ivtv/ivtv-driver.h
++++ b/drivers/media/video/ivtv/ivtv-driver.h
+@@ -65,7 +65,6 @@
+ 
+ #include <linux/ivtv.h>
+ 
+-
+ /* Memory layout */
+ #define IVTV_ENCODER_OFFSET	0x00000000
+ #define IVTV_ENCODER_SIZE	0x00800000	/* Total size is 0x01000000, but only first half is used */
+@@ -392,6 +391,9 @@ struct yuv_frame_info
+ 	u32 tru_h;
+ 	u32 offset_y;
+ 	s32 lace_mode;
++	u32 sync_field;
++	u32 delay;
++	u32 interlaced;
+ };
+ 
+ #define IVTV_YUV_MODE_INTERLACED	0x00
+@@ -403,6 +405,8 @@ struct yuv_frame_info
+ #define IVTV_YUV_SYNC_ODD		0x04
+ #define IVTV_YUV_SYNC_MASK		0x04
+ 
++#define IVTV_YUV_BUFFERS 8
 +
-+	switch (command) {
-+	case XC2028_TUNER_RESET:
-+	{
-+		/* GPIO and initialization codes for analog TV and radio
-+		   This code should be complemented for DTV, since reset
-+		   codes are different.
-+		 */
+ struct yuv_playback_info
+ {
+ 	u32 reg_2834;
+@@ -461,9 +465,10 @@ struct yuv_playback_info
+ 	u32 osd_vis_w;
+ 	u32 osd_vis_h;
+ 
+-	int decode_height;
++	u32 osd_full_w;
++	u32 osd_full_h;
+ 
+-	int frame_interlaced;
++	int decode_height;
+ 
+ 	int lace_mode;
+ 	int lace_threshold;
+@@ -475,16 +480,23 @@ struct yuv_playback_info
+ 	u32 yuv_forced_update;
+ 	int update_frame;
+ 
+-	int sync_field[4];  /* Field to sync on */
+-	int field_delay[4]; /* Flag to extend duration of previous frame */
+ 	u8 fields_lapsed;   /* Counter used when delaying a frame */
+ 
+-	struct yuv_frame_info new_frame_info[4];
++	struct yuv_frame_info new_frame_info[IVTV_YUV_BUFFERS];
+ 	struct yuv_frame_info old_frame_info;
+ 	struct yuv_frame_info old_frame_info_args;
+ 
+ 	void *blanking_ptr;
+ 	dma_addr_t blanking_dmaptr;
 +
-+		dev->em28xx_write_regs_req(dev, 0x00, 0x48, "\x00", 1);
-+		dev->em28xx_write_regs_req(dev, 0x00, 0x12, "\x67", 1);
++	int stream_size;
 +
-+		if (dev->analog_gpio) {
-+			char gpio0 = dev->analog_gpio & 0xff;
-+			char gpio1 = (dev->analog_gpio >> 8) & 0xff;
-+			char gpio4 = dev->analog_gpio >> 24;
++	u8 draw_frame; /* PVR350 buffer to draw into */
++	u8 max_frames_buffered; /* Maximum number of frames to buffer */
 +
-+			if (gpio4) {
-+				dev->em28xx_write_regs(dev, 0x04, &gpio4, 1);
-+				msleep(140);
- 			}
++	struct v4l2_rect main_rect;
++	u32 v4l2_src_w;
++	u32 v4l2_src_h;
+ };
+ 
+ #define IVTV_VBI_FRAMES 32
+@@ -577,13 +589,13 @@ struct ivtv {
+ 	struct pci_dev *dev;		/* PCI device */
+ 	const struct ivtv_card *card;	/* card information */
+ 	const char *card_name;          /* full name of the card */
++	const struct ivtv_card_tuner_i2c *card_i2c; /* i2c addresses to probe for tuner */
+ 	u8 has_cx23415;			/* 1 if it is a cx23415 based card, 0 for cx23416 */
+ 	u8 pvr150_workaround;           /* 1 if the cx25840 needs to workaround a PVR150 bug */
+ 	u8 nof_inputs;			/* number of video inputs */
+ 	u8 nof_audio_inputs;		/* number of audio inputs */
+ 	u32 v4l2_cap;			/* V4L2 capabilities of card */
+ 	u32 hw_flags; 			/* hardware description of the board */
+-	int tunerid;			/* userspace tuner ID for experimental Xceive tuner support */
+ 	v4l2_std_id tuner_std;		/* the norm of the card's tuner (fixed) */
+ 					/* controlling video decoder function */
+ 	int (*video_dec_func)(struct ivtv *, unsigned int, void *);
+diff --git a/drivers/media/video/ivtv/ivtv-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c
+index a200a8a..6fb96f1 100644
+--- a/drivers/media/video/ivtv/ivtv-fileops.c
++++ b/drivers/media/video/ivtv/ivtv-fileops.c
+@@ -542,6 +542,7 @@ ssize_t ivtv_v4l2_write(struct file *filp, const char __user *user_buf, size_t c
+ 	struct ivtv_open_id *id = filp->private_data;
+ 	struct ivtv *itv = id->itv;
+ 	struct ivtv_stream *s = &itv->streams[id->type];
++	struct yuv_playback_info *yi = &itv->yuv_info;
+ 	struct ivtv_buffer *buf;
+ 	struct ivtv_queue q;
+ 	int bytes_written = 0;
+@@ -580,6 +581,24 @@ ssize_t ivtv_v4l2_write(struct file *filp, const char __user *user_buf, size_t c
+ 	set_bit(IVTV_F_S_APPL_IO, &s->s_flags);
+ 
+ retry:
++	/* If possible, just DMA the entire frame - Check the data transfer size
++	since we may get here before the stream has been fully set-up */
++	if (mode == OUT_YUV && s->q_full.length == 0 && itv->dma_data_req_size) {
++		while (count >= itv->dma_data_req_size) {
++			if (!ivtv_yuv_udma_stream_frame (itv, (void *)user_buf)) {
++				bytes_written += itv->dma_data_req_size;
++				user_buf += itv->dma_data_req_size;
++				count -= itv->dma_data_req_size;
++			} else {
++				break;
++			}
++		}
++		if (count == 0) {
++			IVTV_DEBUG_HI_FILE("Wrote %d bytes to %s (%d)\n", bytes_written, s->name, s->q_full.bytesused);
++			return bytes_written;
++		}
++	}
 +
-+			msleep(6);
-+			dev->em28xx_write_regs(dev, 0x08, &gpio0, 1);
-+			msleep(10);
-+			dev->em28xx_write_regs(dev, 0x08, &gpio1, 1);
-+			msleep(5);
+ 	for (;;) {
+ 		/* Gather buffers */
+ 		while (q.length - q.bytesused < count && (buf = ivtv_dequeue(s, &s->q_io)))
+@@ -604,9 +623,16 @@ retry:
+ 
+ 	/* copy user data into buffers */
+ 	while ((buf = ivtv_dequeue(s, &q))) {
+-		/* Make sure we really got all the user data */
+-		rc = ivtv_buf_copy_from_user(s, buf, user_buf, count);
++		/* yuv is a pain. Don't copy more data than needed for a single
++		   frame, otherwise we lose sync with the incoming stream */
++		if (s->type == IVTV_DEC_STREAM_TYPE_YUV &&
++		    yi->stream_size + count > itv->dma_data_req_size)
++			rc  = ivtv_buf_copy_from_user(s, buf, user_buf,
++				itv->dma_data_req_size - yi->stream_size);
++		else
++			rc = ivtv_buf_copy_from_user(s, buf, user_buf, count);
+ 
++		/* Make sure we really got all the user data */
+ 		if (rc < 0) {
+ 			ivtv_queue_move(s, &q, NULL, &s->q_free, 0);
+ 			return rc;
+@@ -615,6 +641,16 @@ retry:
+ 		count -= rc;
+ 		bytes_written += rc;
+ 
++		if (s->type == IVTV_DEC_STREAM_TYPE_YUV) {
++			yi->stream_size += rc;
++			/* If we have a complete yuv frame, break loop now */
++			if (yi->stream_size == itv->dma_data_req_size) {
++				ivtv_enqueue(s, buf, &s->q_full);
++				yi->stream_size = 0;
++				break;
++			}
 +		}
 +
-+		break;
-+	}
-+	}
-+	return rc;
-+}
+ 		if (buf->bytesused != s->buf_size) {
+ 			/* incomplete, leave in q_io for next time */
+ 			ivtv_enqueue(s, buf, &s->q_io);
+@@ -642,6 +678,9 @@ retry:
+ 		if (s->q_full.length >= itv->dma_data_req_size) {
+ 			int got_sig;
+ 
++			if (mode == OUT_YUV)
++				ivtv_yuv_setup_stream_frame(itv);
 +
-+static void em28xx_config_tuner(struct em28xx *dev)
+ 			prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE);
+ 			while (!(got_sig = signal_pending(current)) &&
+ 					test_bit(IVTV_F_S_DMA_PENDING, &s->s_flags)) {
+@@ -922,10 +961,15 @@ static int ivtv_serialized_open(struct ivtv_stream *s, struct file *filp)
+ 	}
+ 
+ 	/* YUV or MPG Decoding Mode? */
+-	if (s->type == IVTV_DEC_STREAM_TYPE_MPG)
++	if (s->type == IVTV_DEC_STREAM_TYPE_MPG) {
+ 		clear_bit(IVTV_F_I_DEC_YUV, &itv->i_flags);
+-	else if (s->type == IVTV_DEC_STREAM_TYPE_YUV)
++	} else if (s->type == IVTV_DEC_STREAM_TYPE_YUV) {
+ 		set_bit(IVTV_F_I_DEC_YUV, &itv->i_flags);
++		/* For yuv, we need to know the dma size before we start */
++		itv->dma_data_req_size =
++				1080 * ((itv->yuv_info.v4l2_src_h + 31) & ~31);
++		itv->yuv_info.stream_size = 0;
++	}
+ 	return 0;
+ }
+ 
+diff --git a/drivers/media/video/ivtv/ivtv-gpio.c b/drivers/media/video/ivtv/ivtv-gpio.c
+index 132fb5f..688cd38 100644
+--- a/drivers/media/video/ivtv/ivtv-gpio.c
++++ b/drivers/media/video/ivtv/ivtv-gpio.c
+@@ -22,6 +22,7 @@
+ #include "ivtv-driver.h"
+ #include "ivtv-cards.h"
+ #include "ivtv-gpio.h"
++#include "tuner-xc2028.h"
+ #include <media/tuner.h>
+ 
+ /*
+@@ -122,6 +123,29 @@ void ivtv_reset_ir_gpio(struct ivtv *itv)
+ 	write_reg(curdir, IVTV_REG_GPIO_DIR);
+ }
+ 
++/* Xceive tuner reset function */
++int ivtv_reset_tuner_gpio(void *dev, int cmd, int value)
 +{
-+	struct v4l2_priv_tun_config  xc2028_cfg;
-+	struct xc2028_ctrl           ctl;
-+	struct tuner_setup           tun_setup;
-+	struct v4l2_frequency        f;
-+
-+	if (dev->tuner_type == TUNER_ABSENT)
-+		return;
++	struct i2c_algo_bit_data *algo = dev;
++	struct ivtv *itv = algo->data;
++	int curdir, curout;
 +
-+	tun_setup.mode_mask = T_ANALOG_TV | T_RADIO;
-+	tun_setup.type = dev->tuner_type;
-+	tun_setup.addr = dev->tuner_addr;
-+	tun_setup.tuner_callback = em28xx_tuner_callback;
++	if (cmd != XC2028_TUNER_RESET)
++		return 0;
++	IVTV_DEBUG_INFO("Resetting tuner\n");
++	curout = read_reg(IVTV_REG_GPIO_OUT);
++	curdir = read_reg(IVTV_REG_GPIO_DIR);
++	curdir |= (1 << 12);  /* GPIO bit 12 */
 +
-+	em28xx_i2c_call_clients(dev, TUNER_SET_TYPE_ADDR, &tun_setup);
++	curout &= ~(1 << 12);
++	write_reg(curout, IVTV_REG_GPIO_OUT);
++	schedule_timeout_interruptible(msecs_to_jiffies(1));
 +
-+	if (dev->tuner_type == TUNER_XC2028) {
-+		memset(&ctl, 0, sizeof(ctl));
++	curout |= (1 << 12);
++	write_reg(curout, IVTV_REG_GPIO_OUT);
++	schedule_timeout_interruptible(msecs_to_jiffies(1));
++	return 0;
++}
+ 
+ void ivtv_gpio_init(struct ivtv *itv)
+ {
+diff --git a/drivers/media/video/ivtv/ivtv-i2c.c b/drivers/media/video/ivtv/ivtv-i2c.c
+index 36e54f7..fa5ab1e 100644
+--- a/drivers/media/video/ivtv/ivtv-i2c.c
++++ b/drivers/media/video/ivtv/ivtv-i2c.c
+@@ -80,6 +80,7 @@
+ #endif /* I2C_ADAP_CLASS_TV_ANALOG */
+ 
+ #define IVTV_CS53L32A_I2C_ADDR		0x11
++#define IVTV_M52790_I2C_ADDR		0x48
+ #define IVTV_CX25840_I2C_ADDR 		0x44
+ #define IVTV_SAA7115_I2C_ADDR 		0x21
+ #define IVTV_SAA7127_I2C_ADDR 		0x44
+@@ -91,7 +92,8 @@
+ #define IVTV_TEA5767_I2C_ADDR		0x60
+ #define IVTV_UPD64031A_I2C_ADDR 	0x12
+ #define IVTV_UPD64083_I2C_ADDR 		0x5c
+-#define IVTV_TDA985X_I2C_ADDR      	0x5b
++#define IVTV_VP27SMPX_I2C_ADDR      	0x5b
++#define IVTV_M52790_I2C_ADDR      	0x48
+ 
+ /* This array should match the IVTV_HW_ defines */
+ static const u8 hw_driverids[] = {
+@@ -104,18 +106,38 @@ static const u8 hw_driverids[] = {
+ 	I2C_DRIVERID_CS53L32A,
+ 	I2C_DRIVERID_TVEEPROM,
+ 	I2C_DRIVERID_SAA711X,
+-	I2C_DRIVERID_TVAUDIO,
+ 	I2C_DRIVERID_UPD64031A,
+ 	I2C_DRIVERID_UPD64083,
+ 	I2C_DRIVERID_SAA717X,
+ 	I2C_DRIVERID_WM8739,
+ 	I2C_DRIVERID_VP27SMPX,
++	I2C_DRIVERID_M52790,
++	0 		/* IVTV_HW_GPIO dummy driver ID */
++};
 +
-+		ctl.fname   = XC2028_DEFAULT_FIRMWARE;
-+		ctl.max_len = 64;
-+		ctl.mts = em28xx_boards[dev->model].mts_firmware;
++/* This array should match the IVTV_HW_ defines */
++static const u8 hw_addrs[] = {
++	IVTV_CX25840_I2C_ADDR,
++	IVTV_SAA7115_I2C_ADDR,
++	IVTV_SAA7127_I2C_ADDR,
++	IVTV_MSP3400_I2C_ADDR,
++	0,
++	IVTV_WM8775_I2C_ADDR,
++	IVTV_CS53L32A_I2C_ADDR,
++	0,
++	IVTV_SAA7115_I2C_ADDR,
++	IVTV_UPD64031A_I2C_ADDR,
++	IVTV_UPD64083_I2C_ADDR,
++	IVTV_SAA717x_I2C_ADDR,
++	IVTV_WM8739_I2C_ADDR,
++	IVTV_VP27SMPX_I2C_ADDR,
++	IVTV_M52790_I2C_ADDR,
+ 	0 		/* IVTV_HW_GPIO dummy driver ID */
+ };
+ 
+ /* This array should match the IVTV_HW_ defines */
+ static const char * const hw_drivernames[] = {
+-	"cx2584x",
++	"cx25840",
+ 	"saa7115",
+ 	"saa7127",
+ 	"msp3400",
+@@ -123,31 +145,67 @@ static const char * const hw_drivernames[] = {
+ 	"wm8775",
+ 	"cs53l32a",
+ 	"tveeprom",
+-	"saa7114",
+-	"tvaudio",
++	"saa7115",
+ 	"upd64031a",
+ 	"upd64083",
+ 	"saa717x",
+ 	"wm8739",
+ 	"vp27smpx",
++	"m52790",
+ 	"gpio",
+ };
+ 
+-static int attach_inform(struct i2c_client *client)
++int ivtv_i2c_register(struct ivtv *itv, unsigned idx)
+ {
+-	struct ivtv *itv = (struct ivtv *)i2c_get_adapdata(client->adapter);
++	struct i2c_board_info info;
++	struct i2c_client *c;
++	u8 id;
+ 	int i;
+ 
+-	IVTV_DEBUG_I2C("i2c client attach\n");
+-	for (i = 0; i < I2C_CLIENTS_MAX; i++) {
+-		if (itv->i2c_clients[i] == NULL) {
+-			itv->i2c_clients[i] = client;
+-			break;
+-		}
+-	}
++	IVTV_DEBUG_I2C("i2c client register\n");
++	if (idx >= ARRAY_SIZE(hw_driverids) || hw_driverids[idx] == 0)
++		return -1;
++	id = hw_driverids[idx];
++	memset(&info, 0, sizeof(info));
++	strcpy(info.driver_name, hw_drivernames[idx]);
++	info.addr = hw_addrs[idx];
++	for (i = 0; itv->i2c_clients[i] && i < I2C_CLIENTS_MAX; i++) {}
 +
-+		xc2028_cfg.tuner = TUNER_XC2028;
-+		xc2028_cfg.priv  = &ctl;
+ 	if (i == I2C_CLIENTS_MAX) {
+-		IVTV_ERR("Insufficient room for new I2C client\n");
++		IVTV_ERR("insufficient room for new I2C client!\n");
++		return -ENOMEM;
+ 	}
 +
-+		em28xx_i2c_call_clients(dev, TUNER_SET_CONFIG, &xc2028_cfg);
++	if (id != I2C_DRIVERID_TUNER) {
++		c = i2c_new_device(&itv->i2c_adap, &info);
++		if (c->driver == NULL)
++			i2c_unregister_device(c);
++		else
++			itv->i2c_clients[i] = c;
++		return itv->i2c_clients[i] ? 0 : -ENODEV;
 +	}
 +
-+	/* configure tuner */
-+	f.tuner = 0;
-+	f.type = V4L2_TUNER_ANALOG_TV;
-+	f.frequency = 9076;     /* just a magic number */
-+	dev->ctl_freq = f.frequency;
-+	em28xx_i2c_call_clients(dev, VIDIOC_S_FREQUENCY, &f);
++	/* special tuner handling */
++	c = i2c_new_probed_device(&itv->i2c_adap, &info, itv->card_i2c->radio);
++	if (c && c->driver == NULL)
++		i2c_unregister_device(c);
++	else if (c)
++		itv->i2c_clients[i++] = c;
++	c = i2c_new_probed_device(&itv->i2c_adap, &info, itv->card_i2c->demod);
++	if (c && c->driver == NULL)
++		i2c_unregister_device(c);
++	else if (c)
++		itv->i2c_clients[i++] = c;
++	c = i2c_new_probed_device(&itv->i2c_adap, &info, itv->card_i2c->tv);
++	if (c && c->driver == NULL)
++		i2c_unregister_device(c);
++	else if (c)
++		itv->i2c_clients[i++] = c;
++	return 0;
 +}
 +
-+static int em28xx_hint_board(struct em28xx *dev)
++static int attach_inform(struct i2c_client *client)
 +{
-+	int i;
-+
-+	/* HINT method: EEPROM
-+	 *
-+	 * This method works only for boards with eeprom.
-+	 * Uses a hash of all eeprom bytes. The hash should be
-+	 * unique for a vendor/tuner pair.
-+	 * There are a high chance that tuners for different
-+	 * video standards produce different hashes.
+ 	return 0;
+ }
+ 
+@@ -475,9 +533,6 @@ static struct i2c_adapter ivtv_i2c_adap_hw_template = {
+ 	.client_register = attach_inform,
+ 	.client_unregister = detach_inform,
+ 	.owner = THIS_MODULE,
+-#ifdef I2C_ADAP_CLASS_TV_ANALOG
+-	.class = I2C_ADAP_CLASS_TV_ANALOG,
+-#endif
+ };
+ 
+ static void ivtv_setscl_old(void *data, int state)
+@@ -525,15 +580,12 @@ static int ivtv_getsda_old(void *data)
+ /* template for i2c-bit-algo */
+ static struct i2c_adapter ivtv_i2c_adap_template = {
+ 	.name = "ivtv i2c driver",
+-	.id = I2C_HW_B_CX2341X,  	/* algo-bit is OR'd with this */
++	.id = I2C_HW_B_CX2341X,
+ 	.algo = NULL,                   /* set by i2c-algo-bit */
+ 	.algo_data = NULL,              /* filled from template */
+ 	.client_register = attach_inform,
+ 	.client_unregister = detach_inform,
+ 	.owner = THIS_MODULE,
+-#ifdef I2C_ADAP_CLASS_TV_ANALOG
+-	.class = I2C_ADAP_CLASS_TV_ANALOG,
+-#endif
+ };
+ 
+ static const struct i2c_algo_bit_data ivtv_i2c_algo_template = {
+@@ -558,12 +610,9 @@ int ivtv_call_i2c_client(struct ivtv *itv, int addr, unsigned int cmd, void *arg
+ 	IVTV_DEBUG_I2C("call_i2c_client addr=%02x\n", addr);
+ 	for (i = 0; i < I2C_CLIENTS_MAX; i++) {
+ 		client = itv->i2c_clients[i];
+-		if (client == NULL) {
+-			continue;
+-		}
+-		if (client->driver->command == NULL) {
++		if (client == NULL || client->driver == NULL ||
++		    client->driver->command == NULL)
+ 			continue;
+-		}
+ 		if (addr == client->addr) {
+ 			retval = client->driver->command(client, cmd, arg);
+ 			return retval;
+@@ -584,7 +633,7 @@ static int ivtv_i2c_id_addr(struct ivtv *itv, u32 id)
+ 
+ 	for (i = 0; i < I2C_CLIENTS_MAX; i++) {
+ 		client = itv->i2c_clients[i];
+-		if (client == NULL)
++		if (client == NULL || client->driver == NULL)
+ 			continue;
+ 		if (id == client->driver->id) {
+ 			retval = client->addr;
+@@ -710,6 +759,16 @@ int init_ivtv_i2c(struct ivtv *itv)
+ {
+ 	IVTV_DEBUG_I2C("i2c init\n");
+ 
++	/* Sanity checks for the I2C hardware arrays. They must be the
++	 * same size and GPIO must be the last entry.
 +	 */
-+	for (i = 0; i < ARRAY_SIZE(em28xx_eeprom_hash); i++) {
-+		if (dev->hash == em28xx_eeprom_hash[i].hash) {
-+			dev->model = em28xx_eeprom_hash[i].model;
-+			dev->tuner_type = em28xx_eeprom_hash[i].tuner;
-+
-+			em28xx_errdev("Your board has no unique USB ID.\n");
-+			em28xx_errdev("A hint were successfully done, "
-+				      "based on eeprom hash.\n");
-+			em28xx_errdev("This method is not 100%% failproof.\n");
-+			em28xx_errdev("If the board were missdetected, "
-+				      "please email this log to:\n");
-+			em28xx_errdev("\tV4L Mailing List "
-+				      " <video4linux-list at redhat.com>\n");
-+			em28xx_errdev("Board detected as %s\n",
-+				      em28xx_boards[dev->model].name);
-+
-+			return 0;
-+		}
++	if (ARRAY_SIZE(hw_driverids) != ARRAY_SIZE(hw_addrs) ||
++	    ARRAY_SIZE(hw_drivernames) != ARRAY_SIZE(hw_addrs) ||
++	    IVTV_HW_GPIO != (1 << (ARRAY_SIZE(hw_addrs) - 1)) ||
++	    hw_driverids[ARRAY_SIZE(hw_addrs) - 1]) {
++		IVTV_ERR("Mismatched I2C hardware arrays\n");
++		return -ENODEV;
 +	}
+ 	if (itv->options.newi2c > 0) {
+ 		memcpy(&itv->i2c_adap, &ivtv_i2c_adap_hw_template,
+ 		       sizeof(struct i2c_adapter));
+@@ -718,9 +777,9 @@ int init_ivtv_i2c(struct ivtv *itv)
+ 		       sizeof(struct i2c_adapter));
+ 		memcpy(&itv->i2c_algo, &ivtv_i2c_algo_template,
+ 		       sizeof(struct i2c_algo_bit_data));
+-		itv->i2c_algo.data = itv;
+-		itv->i2c_adap.algo_data = &itv->i2c_algo;
+ 	}
++	itv->i2c_algo.data = itv;
++	itv->i2c_adap.algo_data = &itv->i2c_algo;
+ 
+ 	sprintf(itv->i2c_adap.name + strlen(itv->i2c_adap.name), " #%d",
+ 		itv->num);
+diff --git a/drivers/media/video/ivtv/ivtv-i2c.h b/drivers/media/video/ivtv/ivtv-i2c.h
+index 987042c..022978c 100644
+--- a/drivers/media/video/ivtv/ivtv-i2c.h
++++ b/drivers/media/video/ivtv/ivtv-i2c.h
+@@ -33,6 +33,7 @@ int ivtv_i2c_hw(struct ivtv *itv, u32 hw, unsigned int cmd, void *arg);
+ int ivtv_i2c_id(struct ivtv *itv, u32 id, unsigned int cmd, void *arg);
+ int ivtv_call_i2c_client(struct ivtv *itv, int addr, unsigned int cmd, void *arg);
+ void ivtv_call_i2c_clients(struct ivtv *itv, unsigned int cmd, void *arg);
++int ivtv_i2c_register(struct ivtv *itv, unsigned idx);
+ 
+ /* init + register i2c algo-bit adapter */
+ int init_ivtv_i2c(struct ivtv *itv);
+diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c
+index fd6826f..edef2a5 100644
+--- a/drivers/media/video/ivtv/ivtv-ioctl.c
++++ b/drivers/media/video/ivtv/ivtv-ioctl.c
+@@ -372,7 +372,7 @@ static int ivtv_get_fmt(struct ivtv *itv, int streamtype, struct v4l2_format *fm
+ 		fmt->fmt.pix.height = itv->main_rect.height;
+ 		fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+ 		fmt->fmt.pix.field = V4L2_FIELD_INTERLACED;
+-		if (itv->output_mode == OUT_UDMA_YUV) {
++		if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) {
+ 			switch (itv->yuv_info.lace_mode & IVTV_YUV_MODE_MASK) {
+ 			case IVTV_YUV_MODE_INTERLACED:
+ 				fmt->fmt.pix.field = (itv->yuv_info.lace_mode & IVTV_YUV_SYNC_MASK) ?
+@@ -386,14 +386,13 @@ static int ivtv_get_fmt(struct ivtv *itv, int streamtype, struct v4l2_format *fm
+ 				break;
+ 			}
+ 			fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_HM12;
++			fmt->fmt.pix.bytesperline = 720;
++			fmt->fmt.pix.width = itv->yuv_info.v4l2_src_w;
++			fmt->fmt.pix.height = itv->yuv_info.v4l2_src_h;
+ 			/* YUV size is (Y=(h*w) + UV=(h*(w/2))) */
+ 			fmt->fmt.pix.sizeimage =
+-				fmt->fmt.pix.height * fmt->fmt.pix.width +
+-				fmt->fmt.pix.height * (fmt->fmt.pix.width / 2);
+-		}
+-		else if (itv->output_mode == OUT_YUV ||
+-				streamtype == IVTV_ENC_STREAM_TYPE_YUV ||
+-				streamtype == IVTV_DEC_STREAM_TYPE_YUV) {
++				1080 * ((fmt->fmt.pix.height + 31) & ~31);
++		} else if (streamtype == IVTV_ENC_STREAM_TYPE_YUV) {
+ 			fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_HM12;
+ 			/* YUV size is (Y=(h*w) + UV=(h*(w/2))) */
+ 			fmt->fmt.pix.sizeimage =
+@@ -490,6 +489,7 @@ static int ivtv_get_fmt(struct ivtv *itv, int streamtype, struct v4l2_format *fm
+ static int ivtv_try_or_set_fmt(struct ivtv *itv, int streamtype,
+ 		struct v4l2_format *fmt, int set_fmt)
+ {
++	struct yuv_playback_info *yi = &itv->yuv_info;
+ 	struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
+ 	u16 set;
+ 
+@@ -505,39 +505,52 @@ static int ivtv_try_or_set_fmt(struct ivtv *itv, int streamtype,
+ 		r.width = fmt->fmt.pix.width;
+ 		r.height = fmt->fmt.pix.height;
+ 		ivtv_get_fmt(itv, streamtype, fmt);
+-		if (itv->output_mode != OUT_UDMA_YUV) {
+-			/* TODO: would setting the rect also be valid for this mode? */
+-			fmt->fmt.pix.width = r.width;
+-			fmt->fmt.pix.height = r.height;
+-		}
+-		if (itv->output_mode == OUT_UDMA_YUV) {
+-			/* TODO: add checks for validity */
++		fmt->fmt.pix.width = r.width;
++		fmt->fmt.pix.height = r.height;
++		if (streamtype == 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;
+ 		}
+-		if (set_fmt) {
+-			if (itv->output_mode == OUT_UDMA_YUV) {
+-				switch (field) {
+-				case V4L2_FIELD_NONE:
+-					itv->yuv_info.lace_mode = IVTV_YUV_MODE_PROGRESSIVE;
+-					break;
+-				case V4L2_FIELD_ANY:
+-					itv->yuv_info.lace_mode = IVTV_YUV_MODE_AUTO;
+-					break;
+-				case V4L2_FIELD_INTERLACED_BT:
+-					itv->yuv_info.lace_mode =
+-						IVTV_YUV_MODE_INTERLACED|IVTV_YUV_SYNC_ODD;
+-					break;
+-				case V4L2_FIELD_INTERLACED_TB:
+-				default:
+-					itv->yuv_info.lace_mode = IVTV_YUV_MODE_INTERLACED;
+-					break;
+-				}
+-				itv->yuv_info.lace_sync_field = (itv->yuv_info.lace_mode & IVTV_YUV_SYNC_MASK) == IVTV_YUV_SYNC_EVEN ? 0 : 1;
++		if (set_fmt && streamtype == IVTV_DEC_STREAM_TYPE_YUV) {
++			/* Return now if we already have some frame data */
++			if (yi->stream_size)
++				return -EBUSY;
+ 
+-				/* Force update of yuv registers */
+-				itv->yuv_info.yuv_forced_update = 1;
+-				return 0;
++			yi->v4l2_src_w = r.width;
++			yi->v4l2_src_h = r.height;
 +
-+	/* HINT method: I2C attached devices
-+	 *
-+	 * This method works for all boards.
-+	 * Uses a hash of i2c scanned devices.
-+	 * Devices with the same i2c attached chips will
-+	 * be considered equal.
-+	 * This method is less precise than the eeprom one.
-+	 */
-+
-+	/* user did not request i2c scanning => do it now */
-+	if (!dev->i2c_hash)
-+		em28xx_do_i2c_scan(dev);
++			switch (field) {
++			case V4L2_FIELD_NONE:
++				yi->lace_mode = IVTV_YUV_MODE_PROGRESSIVE;
++				break;
++			case V4L2_FIELD_ANY:
++				yi->lace_mode = IVTV_YUV_MODE_AUTO;
++				break;
++			case V4L2_FIELD_INTERLACED_BT:
++				yi->lace_mode =
++				     IVTV_YUV_MODE_INTERLACED|IVTV_YUV_SYNC_ODD;
++				break;
++			case V4L2_FIELD_INTERLACED_TB:
++			default:
++				yi->lace_mode = IVTV_YUV_MODE_INTERLACED;
++				break;
+ 			}
++			yi->lace_sync_field = (yi->lace_mode & IVTV_YUV_SYNC_MASK) == IVTV_YUV_SYNC_EVEN ? 0 : 1;
 +
-+	for (i = 0; i < ARRAY_SIZE(em28xx_i2c_hash); i++) {
-+		if (dev->i2c_hash == em28xx_i2c_hash[i].hash) {
-+			dev->model = em28xx_i2c_hash[i].model;
-+			dev->tuner_type = em28xx_i2c_hash[i].tuner;
-+			em28xx_errdev("Your board has no unique USB ID.\n");
-+			em28xx_errdev("A hint were successfully done, "
-+				      "based on i2c devicelist hash.\n");
-+			em28xx_errdev("This method is not 100%% failproof.\n");
-+			em28xx_errdev("If the board were missdetected, "
-+				      "please email this log to:\n");
-+			em28xx_errdev("\tV4L Mailing List "
-+				      " <video4linux-list at redhat.com>\n");
-+			em28xx_errdev("Board detected as %s\n",
-+				      em28xx_boards[dev->model].name);
++			if (test_bit(IVTV_F_I_DEC_YUV, &itv->i_flags))
++				itv->dma_data_req_size =
++					   1080 * ((yi->v4l2_src_h + 31) & ~31);
 +
++			/* Force update of yuv registers */
++			yi->yuv_forced_update = 1;
 +			return 0;
-+		}
+ 		}
+ 		return 0;
+ 	}
+@@ -660,11 +673,8 @@ static int ivtv_debug_ioctls(struct file *filp, unsigned int cmd, void *arg)
+ 		chip->ident = V4L2_IDENT_NONE;
+ 		chip->revision = 0;
+ 		if (reg->match_type == V4L2_CHIP_MATCH_HOST) {
+-			if (v4l2_chip_match_host(reg->match_type, reg->match_chip)) {
+-				struct v4l2_chip_ident *chip = arg;
+-
++			if (v4l2_chip_match_host(reg->match_type, reg->match_chip))
+ 				chip->ident = itv->has_cx23415 ? V4L2_IDENT_CX23415 : V4L2_IDENT_CX23416;
+-			}
+ 			return 0;
+ 		}
+ 		if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER)
+@@ -688,7 +698,7 @@ static int ivtv_debug_ioctls(struct file *filp, unsigned int cmd, void *arg)
+ 			ivtv_reset_ir_gpio(itv);
+ 		}
+ 		if (val & 0x02) {
+-			itv->video_dec_func(itv, cmd, 0);
++			itv->video_dec_func(itv, cmd, NULL);
+ 		}
+ 		break;
+ 	}
+@@ -703,8 +713,12 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void
+ {
+ 	struct ivtv_open_id *id = NULL;
+ 	u32 data[CX2341X_MBOX_MAX_DATA];
++	int streamtype = 0;
+ 
+-	if (filp) id = (struct ivtv_open_id *)filp->private_data;
++	if (filp) {
++		id = (struct ivtv_open_id *)filp->private_data;
++		streamtype = id->type;
 +	}
+ 
+ 	switch (cmd) {
+ 	case VIDIOC_G_PRIORITY:
+@@ -822,6 +836,11 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void
+ 			cropcap->bounds.height = itv->is_50hz ? 576 : 480;
+ 			cropcap->pixelaspect.numerator = itv->is_50hz ? 59 : 10;
+ 			cropcap->pixelaspect.denominator = itv->is_50hz ? 54 : 11;
++		} else if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) {
++			cropcap->bounds.width = itv->yuv_info.osd_full_w;
++			cropcap->bounds.height = itv->yuv_info.osd_full_h;
++			cropcap->pixelaspect.numerator = itv->is_out_50hz ? 59 : 10;
++			cropcap->pixelaspect.denominator = itv->is_out_50hz ? 54 : 11;
+ 		} else {
+ 			cropcap->bounds.height = itv->is_out_50hz ? 576 : 480;
+ 			cropcap->pixelaspect.numerator = itv->is_out_50hz ? 59 : 10;
+@@ -836,10 +855,15 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void
+ 
+ 		if (crop->type == V4L2_BUF_TYPE_VIDEO_OUTPUT &&
+ 		    (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) {
+-			if (!ivtv_vapi(itv, CX2341X_OSD_SET_FRAMEBUFFER_WINDOW, 4,
+-				 crop->c.width, crop->c.height, crop->c.left, crop->c.top)) {
+-				itv->main_rect = crop->c;
++			if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) {
++				itv->yuv_info.main_rect = crop->c;
+ 				return 0;
++			} else {
++				if (!ivtv_vapi(itv, CX2341X_OSD_SET_FRAMEBUFFER_WINDOW, 4,
++					crop->c.width, crop->c.height, crop->c.left, crop->c.top)) {
++					itv->main_rect = crop->c;
++					return 0;
++				}
+ 			}
+ 			return -EINVAL;
+ 		}
+@@ -853,7 +877,10 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void
+ 
+ 		if (crop->type == V4L2_BUF_TYPE_VIDEO_OUTPUT &&
+ 		    (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) {
+-			crop->c = itv->main_rect;
++			if (streamtype == IVTV_DEC_STREAM_TYPE_YUV)
++				crop->c = itv->yuv_info.main_rect;
++			else
++				crop->c = itv->main_rect;
+ 			return 0;
+ 		}
+ 		if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+@@ -864,7 +891,7 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void
+ 	case VIDIOC_ENUM_FMT: {
+ 		static struct v4l2_fmtdesc formats[] = {
+ 			{ 0, 0, 0,
+-			  "HM12 (YUV 4:1:1)", V4L2_PIX_FMT_HM12,
++			  "HM12 (YUV 4:2:0)", V4L2_PIX_FMT_HM12,
+ 			  { 0, 0, 0, 0 }
+ 			},
+ 			{ 1, 0, V4L2_FMT_FLAG_COMPRESSED,
+@@ -1043,6 +1070,12 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void
+ 			itv->main_rect.height = itv->params.height;
+ 			ivtv_vapi(itv, CX2341X_OSD_SET_FRAMEBUFFER_WINDOW, 4,
+ 				720, itv->main_rect.height, 0, 0);
++			itv->yuv_info.main_rect = itv->main_rect;
++			if (!itv->osd_info) {
++				itv->yuv_info.osd_full_w = 720;
++				itv->yuv_info.osd_full_h =
++						itv->is_out_50hz ? 576 : 480;
++			}
+ 		}
+ 		break;
+ 	}
+diff --git a/drivers/media/video/ivtv/ivtv-irq.c b/drivers/media/video/ivtv/ivtv-irq.c
+index fd1688e..65604dd 100644
+--- a/drivers/media/video/ivtv/ivtv-irq.c
++++ b/drivers/media/video/ivtv/ivtv-irq.c
+@@ -204,7 +204,7 @@ static int stream_enc_dma_append(struct ivtv_stream *s, u32 data[CX2341X_MBOX_MA
+ 		s->sg_pending[idx].dst = buf->dma_handle;
+ 		s->sg_pending[idx].src = offset;
+ 		s->sg_pending[idx].size = s->buf_size;
+-		buf->bytesused = (size < s->buf_size) ? size : s->buf_size;
++		buf->bytesused = min(size, s->buf_size);
+ 		buf->dma_xfer_cnt = s->dma_xfer_cnt;
+ 
+ 		s->q_predma.bytesused += buf->bytesused;
+@@ -302,8 +302,11 @@ static void dma_post(struct ivtv_stream *s)
+ void ivtv_dma_stream_dec_prepare(struct ivtv_stream *s, u32 offset, int lock)
+ {
+ 	struct ivtv *itv = s->itv;
++	struct yuv_playback_info *yi = &itv->yuv_info;
++	u8 frame = yi->draw_frame;
++	struct yuv_frame_info *f = &yi->new_frame_info[frame];
+ 	struct ivtv_buffer *buf;
+-	u32 y_size = itv->params.height * itv->params.width;
++	u32 y_size = 720 * ((f->src_h + 31) & ~31);
+ 	u32 uv_offset = offset + IVTV_YUV_BUFFER_UV_OFFSET;
+ 	int y_done = 0;
+ 	int bytes_written = 0;
+@@ -311,17 +314,42 @@ void ivtv_dma_stream_dec_prepare(struct ivtv_stream *s, u32 offset, int lock)
+ 	int idx = 0;
+ 
+ 	IVTV_DEBUG_HI_DMA("DEC PREPARE DMA %s: %08x %08x\n", s->name, s->q_predma.bytesused, offset);
 +
-+	em28xx_errdev("Your board has no unique USB ID and thus need a "
-+		      "hint to be detected.\n");
-+	em28xx_errdev("You may try to use card=<n> insmod option to "
-+		      "workaround that.\n");
-+	em28xx_errdev("Please send an email with this log to:\n");
-+	em28xx_errdev("\tV4L Mailing List <video4linux-list at redhat.com>\n");
-+	em28xx_errdev("Board eeprom hash is 0x%08lx\n", dev->hash);
-+	em28xx_errdev("Board i2c devicelist hash is 0x%08lx\n", dev->i2c_hash);
-+
-+	em28xx_errdev("Here is a list of valid choices for the card=<n>"
-+		      " insmod option:\n");
-+	for (i = 0; i < em28xx_bcount; i++) {
-+		em28xx_errdev("    card=%d -> %s\n",
-+				i, em28xx_boards[i].name);
++	/* Insert buffer block for YUV if needed */
++	if (s->type == IVTV_DEC_STREAM_TYPE_YUV && f->offset_y) {
++		if (yi->blanking_dmaptr) {
++			s->sg_pending[idx].src = yi->blanking_dmaptr;
++			s->sg_pending[idx].dst = offset;
++			s->sg_pending[idx].size = 720 * 16;
++		}
++		offset += 720 * 16;
++		idx++;
 +	}
-+	return -1;
-+}
-+
-+
-+static void em28xx_set_model(struct em28xx *dev)
-+{
-+	dev->is_em2800 = em28xx_boards[dev->model].is_em2800;
-+	dev->has_msp34xx = em28xx_boards[dev->model].has_msp34xx;
-+	dev->tda9887_conf = em28xx_boards[dev->model].tda9887_conf;
-+	dev->decoder = em28xx_boards[dev->model].decoder;
-+	dev->video_inputs = em28xx_boards[dev->model].vchannels;
-+	dev->analog_gpio = em28xx_boards[dev->model].analog_gpio;
-+	dev->has_12mhz_i2s = em28xx_boards[dev->model].has_12mhz_i2s;
-+	dev->max_range_640_480 = em28xx_boards[dev->model].max_range_640_480;
-+}
 +
-+/* ----------------------------------------------------------------------- */
-+void em28xx_set_ir(struct em28xx *dev, struct IR_i2c *ir)
-+{
-+	if (disable_ir) {
-+		ir->get_key = NULL;
-+		return ;
-+	}
+ 	list_for_each_entry(buf, &s->q_predma.list, list) {
+ 		/* YUV UV Offset from Y Buffer */
+-		if (s->type == IVTV_DEC_STREAM_TYPE_YUV && !y_done && bytes_written >= y_size) {
++		if (s->type == IVTV_DEC_STREAM_TYPE_YUV && !y_done &&
++				(bytes_written + buf->bytesused) >= y_size) {
++			s->sg_pending[idx].src = buf->dma_handle;
++			s->sg_pending[idx].dst = offset;
++			s->sg_pending[idx].size = y_size - bytes_written;
+ 			offset = uv_offset;
++			if (s->sg_pending[idx].size != buf->bytesused) {
++				idx++;
++				s->sg_pending[idx].src =
++				  buf->dma_handle + s->sg_pending[idx - 1].size;
++				s->sg_pending[idx].dst = offset;
++				s->sg_pending[idx].size =
++				   buf->bytesused - s->sg_pending[idx - 1].size;
++				offset += s->sg_pending[idx].size;
++			}
+ 			y_done = 1;
++		} else {
++			s->sg_pending[idx].src = buf->dma_handle;
++			s->sg_pending[idx].dst = offset;
++			s->sg_pending[idx].size = buf->bytesused;
++			offset += buf->bytesused;
+ 		}
+-		s->sg_pending[idx].src = buf->dma_handle;
+-		s->sg_pending[idx].dst = offset;
+-		s->sg_pending[idx].size = buf->bytesused;
+-
+-		offset += buf->bytesused;
+ 		bytes_written += buf->bytesused;
+ 
+ 		/* Sync SG buffers */
+@@ -408,7 +436,7 @@ static void ivtv_dma_enc_start(struct ivtv_stream *s)
+ 		s_vbi->sg_pending_size = 0;
+ 		s_vbi->dma_xfer_cnt++;
+ 		set_bit(IVTV_F_S_DMA_HAS_VBI, &s->s_flags);
+-		IVTV_DEBUG_HI_DMA("include DMA for %s\n", s->name);
++		IVTV_DEBUG_HI_DMA("include DMA for %s\n", s_vbi->name);
+ 	}
+ 
+ 	s->dma_xfer_cnt++;
+@@ -700,12 +728,15 @@ static void ivtv_irq_dec_data_req(struct ivtv *itv)
+ 	ivtv_api_get_data(&itv->dec_mbox, IVTV_MBOX_DMA, data);
+ 
+ 	if (test_bit(IVTV_F_I_DEC_YUV, &itv->i_flags)) {
+-		itv->dma_data_req_size = itv->params.width * itv->params.height * 3 / 2;
+-		itv->dma_data_req_offset = data[1] ? data[1] : yuv_offset[0];
++		itv->dma_data_req_size =
++				 1080 * ((itv->yuv_info.v4l2_src_h + 31) & ~31);
++		itv->dma_data_req_offset = data[1];
++		if (atomic_read(&itv->yuv_info.next_dma_frame) >= 0)
++			ivtv_yuv_frame_complete(itv);
+ 		s = &itv->streams[IVTV_DEC_STREAM_TYPE_YUV];
+ 	}
+ 	else {
+-		itv->dma_data_req_size = data[2] >= 0x10000 ? 0x10000 : data[2];
++		itv->dma_data_req_size = min_t(u32, data[2], 0x10000);
+ 		itv->dma_data_req_offset = data[1];
+ 		s = &itv->streams[IVTV_DEC_STREAM_TYPE_MPG];
+ 	}
+@@ -715,6 +746,8 @@ static void ivtv_irq_dec_data_req(struct ivtv *itv)
+ 		set_bit(IVTV_F_S_NEEDS_DATA, &s->s_flags);
+ 	}
+ 	else {
++		if (test_bit(IVTV_F_I_DEC_YUV, &itv->i_flags))
++			ivtv_yuv_setup_stream_frame(itv);
+ 		clear_bit(IVTV_F_S_NEEDS_DATA, &s->s_flags);
+ 		ivtv_queue_move(s, &s->q_full, NULL, &s->q_predma, itv->dma_data_req_size);
+ 		ivtv_dma_stream_dec_prepare(s, itv->dma_data_req_offset + IVTV_DECODER_OFFSET, 0);
+@@ -731,24 +764,26 @@ static void ivtv_irq_vsync(struct ivtv *itv)
+ 	 * one vsync per frame.
+ 	 */
+ 	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);
++	struct yuv_frame_info *f = &yi->new_frame_info[last_dma_frame];
+ 
+ 	if (0) IVTV_DEBUG_IRQ("DEC VSYNC\n");
+ 
+-	if (((frame ^ itv->yuv_info.sync_field[last_dma_frame]) == 0 &&
+-		((itv->last_vsync_field & 1) ^ itv->yuv_info.sync_field[last_dma_frame])) ||
+-			(frame != (itv->last_vsync_field & 1) && !itv->yuv_info.frame_interlaced)) {
++	if (((frame ^ f->sync_field) == 0 &&
++		((itv->last_vsync_field & 1) ^ f->sync_field)) ||
++			(frame != (itv->last_vsync_field & 1) && !f->interlaced)) {
+ 		int next_dma_frame = last_dma_frame;
+ 
+-		if (!(itv->yuv_info.frame_interlaced && itv->yuv_info.field_delay[next_dma_frame] && itv->yuv_info.fields_lapsed < 1)) {
+-			if (next_dma_frame >= 0 && next_dma_frame != atomic_read(&itv->yuv_info.next_fill_frame)) {
++		if (!(f->interlaced && f->delay && yi->fields_lapsed < 1)) {
++			if (next_dma_frame >= 0 && next_dma_frame != atomic_read(&yi->next_fill_frame)) {
+ 				write_reg(yuv_offset[next_dma_frame] >> 4, 0x82c);
+ 				write_reg((yuv_offset[next_dma_frame] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x830);
+ 				write_reg(yuv_offset[next_dma_frame] >> 4, 0x834);
+ 				write_reg((yuv_offset[next_dma_frame] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x838);
+-				next_dma_frame = (next_dma_frame + 1) & 0x3;
+-				atomic_set(&itv->yuv_info.next_dma_frame, next_dma_frame);
+-				itv->yuv_info.fields_lapsed = -1;
++				next_dma_frame = (next_dma_frame + 1) % IVTV_YUV_BUFFERS;
++				atomic_set(&yi->next_dma_frame, next_dma_frame);
++				yi->fields_lapsed = -1;
+ 			}
+ 		}
+ 	}
+@@ -781,20 +816,22 @@ static void ivtv_irq_vsync(struct ivtv *itv)
+ 		}
+ 
+ 		/* Check if we need to update the yuv registers */
+-		if ((itv->yuv_info.yuv_forced_update || itv->yuv_info.new_frame_info[last_dma_frame].update) && last_dma_frame != -1) {
+-			if (!itv->yuv_info.new_frame_info[last_dma_frame].update)
+-				last_dma_frame = (last_dma_frame - 1) & 3;
+-
+-			if (itv->yuv_info.new_frame_info[last_dma_frame].src_w) {
+-				itv->yuv_info.update_frame = last_dma_frame;
+-				itv->yuv_info.new_frame_info[last_dma_frame].update = 0;
+-				itv->yuv_info.yuv_forced_update = 0;
++		if ((yi->yuv_forced_update || f->update) && last_dma_frame != -1) {
++			if (!f->update) {
++				last_dma_frame = (u8)(last_dma_frame - 1) % IVTV_YUV_BUFFERS;
++				f = &yi->new_frame_info[last_dma_frame];
++			}
 +
-+	/* detect & configure */
-+	switch (dev->model) {
-+	case (EM2800_BOARD_UNKNOWN):
-+		break;
-+	case (EM2820_BOARD_UNKNOWN):
-+		break;
-+	case (EM2800_BOARD_TERRATEC_CINERGY_200):
-+	case (EM2820_BOARD_TERRATEC_CINERGY_250):
-+		ir->ir_codes = ir_codes_em_terratec;
-+		ir->get_key = em28xx_get_key_terratec;
-+		snprintf(ir->c.name, sizeof(ir->c.name),
-+			 "i2c IR (EM28XX Terratec)");
-+		break;
-+	case (EM2820_BOARD_PINNACLE_USB_2):
-+		ir->ir_codes = ir_codes_pinnacle_grey;
-+		ir->get_key = em28xx_get_key_pinnacle_usb_grey;
-+		snprintf(ir->c.name, sizeof(ir->c.name),
-+			 "i2c IR (EM28XX Pinnacle PCTV)");
-+		break;
-+	case (EM2820_BOARD_HAUPPAUGE_WINTV_USB_2):
-+		ir->ir_codes = ir_codes_hauppauge_new;
-+		ir->get_key = em28xx_get_key_em_haup;
-+		snprintf(ir->c.name, sizeof(ir->c.name),
-+			 "i2c IR (EM2840 Hauppauge)");
-+		break;
-+	case (EM2820_BOARD_MSI_VOX_USB_2):
-+		break;
-+	case (EM2800_BOARD_LEADTEK_WINFAST_USBII):
-+		break;
-+	case (EM2800_BOARD_KWORLD_USB2800):
-+		break;
++			if (f->src_w) {
++				yi->update_frame = last_dma_frame;
++				f->update = 0;
++				yi->yuv_forced_update = 0;
+ 				set_bit(IVTV_F_I_WORK_HANDLER_YUV, &itv->i_flags);
+ 				set_bit(IVTV_F_I_HAVE_WORK, &itv->i_flags);
+ 			}
+ 		}
+ 
+-		itv->yuv_info.fields_lapsed ++;
++		yi->fields_lapsed++;
+ 	}
+ }
+ 
+diff --git a/drivers/media/video/ivtv/ivtv-mailbox.c b/drivers/media/video/ivtv/ivtv-mailbox.c
+index b05436d..13a6c37 100644
+--- a/drivers/media/video/ivtv/ivtv-mailbox.c
++++ b/drivers/media/video/ivtv/ivtv-mailbox.c
+@@ -333,7 +333,7 @@ int ivtv_api(struct ivtv *itv, int cmd, int args, u32 data[])
+ 	return (res == -EBUSY) ? ivtv_api_call(itv, cmd, args, data) : res;
+ }
+ 
+-int ivtv_api_func(void *priv, int cmd, int in, int out, u32 data[CX2341X_MBOX_MAX_DATA])
++int ivtv_api_func(void *priv, u32 cmd, int in, int out, u32 data[CX2341X_MBOX_MAX_DATA])
+ {
+ 	return ivtv_api(priv, cmd, in, data);
+ }
+diff --git a/drivers/media/video/ivtv/ivtv-mailbox.h b/drivers/media/video/ivtv/ivtv-mailbox.h
+index 71a54ee..6ef1209 100644
+--- a/drivers/media/video/ivtv/ivtv-mailbox.h
++++ b/drivers/media/video/ivtv/ivtv-mailbox.h
+@@ -28,6 +28,6 @@ void ivtv_api_get_data(struct ivtv_mailbox_data *mbox, int mb, u32 data[]);
+ int ivtv_api(struct ivtv *itv, int cmd, int args, u32 data[]);
+ int ivtv_vapi_result(struct ivtv *itv, u32 data[CX2341X_MBOX_MAX_DATA], int cmd, int args, ...);
+ int ivtv_vapi(struct ivtv *itv, int cmd, int args, ...);
+-int ivtv_api_func(void *priv, int cmd, int in, int out, u32 data[CX2341X_MBOX_MAX_DATA]);
++int ivtv_api_func(void *priv, u32 cmd, int in, int out, u32 data[CX2341X_MBOX_MAX_DATA]);
+ 
+ #endif
+diff --git a/drivers/media/video/ivtv/ivtv-routing.c b/drivers/media/video/ivtv/ivtv-routing.c
+index 398bd33..0556491 100644
+--- a/drivers/media/video/ivtv/ivtv-routing.c
++++ b/drivers/media/video/ivtv/ivtv-routing.c
+@@ -25,6 +25,7 @@
+ #include "ivtv-routing.h"
+ 
+ #include <media/msp3400.h>
++#include <media/m52790.h>
+ #include <media/upd64031a.h>
+ #include <media/upd64083.h>
+ 
+@@ -32,28 +33,26 @@
+    settings. */
+ void ivtv_audio_set_io(struct ivtv *itv)
+ {
++	const struct ivtv_card_audio_input *in;
+ 	struct v4l2_routing route;
+-	u32 audio_input;
+-	int mux_input;
+ 
+ 	/* Determine which input to use */
+-	if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags)) {
+-		audio_input = itv->card->radio_input.audio_input;
+-		mux_input = itv->card->radio_input.muxer_input;
+-	} else {
+-		audio_input = itv->card->audio_inputs[itv->audio_input].audio_input;
+-		mux_input = itv->card->audio_inputs[itv->audio_input].muxer_input;
+-	}
++	if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags))
++		in = &itv->card->radio_input;
++	else
++		in = &itv->card->audio_inputs[itv->audio_input];
+ 
+ 	/* handle muxer chips */
+-	route.input = mux_input;
++	route.input = in->muxer_input;
+ 	route.output = 0;
++	if (itv->card->hw_muxer & IVTV_HW_M52790)
++		route.output = M52790_OUT_STEREO;
+ 	ivtv_i2c_hw(itv, itv->card->hw_muxer, VIDIOC_INT_S_AUDIO_ROUTING, &route);
+ 
+-	route.input = audio_input;
+-	if (itv->card->hw_audio & IVTV_HW_MSP34XX) {
++	route.input = in->audio_input;
++	route.output = 0;
++	if (itv->card->hw_audio & IVTV_HW_MSP34XX)
+ 		route.output = MSP_OUTPUT(MSP_SC_IN_DSP_SCART1);
+-	}
+ 	ivtv_i2c_hw(itv, itv->card->hw_audio, VIDIOC_INT_S_AUDIO_ROUTING, &route);
+ }
+ 
+diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c
+index 74fb0e0..24d98ec 100644
+--- a/drivers/media/video/ivtv/ivtv-streams.c
++++ b/drivers/media/video/ivtv/ivtv-streams.c
+@@ -43,7 +43,7 @@
+ #include "ivtv-cards.h"
+ #include "ivtv-streams.h"
+ 
+-static struct file_operations ivtv_v4l2_enc_fops = {
++static const struct file_operations ivtv_v4l2_enc_fops = {
+       .owner = THIS_MODULE,
+       .read = ivtv_v4l2_read,
+       .write = ivtv_v4l2_write,
+@@ -53,7 +53,7 @@ static struct file_operations ivtv_v4l2_enc_fops = {
+       .poll = ivtv_v4l2_enc_poll,
+ };
+ 
+-static struct file_operations ivtv_v4l2_dec_fops = {
++static const struct file_operations ivtv_v4l2_dec_fops = {
+       .owner = THIS_MODULE,
+       .read = ivtv_v4l2_read,
+       .write = ivtv_v4l2_write,
+@@ -572,10 +572,10 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s)
+ 		clear_bit(IVTV_F_I_EOS, &itv->i_flags);
+ 
+ 		/* Initialize Digitizer for Capture */
+-		itv->video_dec_func(itv, VIDIOC_STREAMOFF, 0);
++		itv->video_dec_func(itv, VIDIOC_STREAMOFF, NULL);
+ 		ivtv_msleep_timeout(300, 1);
+ 		ivtv_vapi(itv, CX2341X_ENC_INITIALIZE_INPUT, 0);
+-		itv->video_dec_func(itv, VIDIOC_STREAMON, 0);
++		itv->video_dec_func(itv, VIDIOC_STREAMON, NULL);
+ 	}
+ 
+ 	/* begin_capture */
+@@ -661,27 +661,12 @@ int ivtv_start_v4l2_decode_stream(struct ivtv_stream *s, int gop_offset)
+ 
+ 	IVTV_DEBUG_INFO("Starting decode stream %s (gop_offset %d)\n", s->name, gop_offset);
+ 
+-	/* Clear Streamoff */
+-	if (s->type == IVTV_DEC_STREAM_TYPE_YUV) {
+-		/* Initialize Decoder */
+-		/* Reprogram Decoder YUV Buffers for YUV */
+-		write_reg(yuv_offset[0] >> 4, 0x82c);
+-		write_reg((yuv_offset[0] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x830);
+-		write_reg(yuv_offset[0] >> 4, 0x834);
+-		write_reg((yuv_offset[0] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x838);
+-
+-		write_reg_sync(0x00000000 | (0x0c << 16) | (0x0b << 8), 0x2d24);
+-
+-		write_reg_sync(0x00108080, 0x2898);
+-		/* Enable YUV decoder output */
+-		write_reg_sync(0x01, IVTV_REG_VDM);
+-	}
+-
+ 	ivtv_setup_v4l2_decode_stream(s);
+ 
+ 	/* set dma size to 65536 bytes */
+ 	ivtv_vapi(itv, CX2341X_DEC_SET_DMA_BLOCK_SIZE, 1, 65536);
+ 
++	/* Clear Streamoff */
+ 	clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags);
+ 
+ 	/* Zero out decoder counters */
+diff --git a/drivers/media/video/ivtv/ivtv-version.h b/drivers/media/video/ivtv/ivtv-version.h
+index d050de2..0f1d4cc 100644
+--- a/drivers/media/video/ivtv/ivtv-version.h
++++ b/drivers/media/video/ivtv/ivtv-version.h
+@@ -22,7 +22,7 @@
+ 
+ #define IVTV_DRIVER_NAME "ivtv"
+ #define IVTV_DRIVER_VERSION_MAJOR 1
+-#define IVTV_DRIVER_VERSION_MINOR 1
++#define IVTV_DRIVER_VERSION_MINOR 2
+ #define IVTV_DRIVER_VERSION_PATCHLEVEL 0
+ 
+ #define IVTV_VERSION __stringify(IVTV_DRIVER_VERSION_MAJOR) "." __stringify(IVTV_DRIVER_VERSION_MINOR) "." __stringify(IVTV_DRIVER_VERSION_PATCHLEVEL)
+diff --git a/drivers/media/video/ivtv/ivtv-yuv.c b/drivers/media/video/ivtv/ivtv-yuv.c
+index 9091c48..8518348 100644
+--- a/drivers/media/video/ivtv/ivtv-yuv.c
++++ b/drivers/media/video/ivtv/ivtv-yuv.c
+@@ -22,32 +22,37 @@
+ #include "ivtv-udma.h"
+ #include "ivtv-yuv.h"
+ 
+-const u32 yuv_offset[4] = {
+-	IVTV_YUV_BUFFER_OFFSET,
+-	IVTV_YUV_BUFFER_OFFSET_1,
+-	IVTV_YUV_BUFFER_OFFSET_2,
+-	IVTV_YUV_BUFFER_OFFSET_3
++/* YUV buffer offsets */
++const u32 yuv_offset[IVTV_YUV_BUFFERS] = {
++	0x001a8600,
++	0x00240400,
++	0x002d8200,
++	0x00370000,
++	0x00029000,
++	0x000C0E00,
++	0x006B0400,
++	0x00748200
+ };
+ 
+ static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma,
+-				 struct ivtv_dma_frame *args)
++				  struct ivtv_dma_frame *args)
+ {
+ 	struct ivtv_dma_page_info y_dma;
+ 	struct ivtv_dma_page_info uv_dma;
+-
++	struct yuv_playback_info *yi = &itv->yuv_info;
++	u8 frame = yi->draw_frame;
++	struct yuv_frame_info *f = &yi->new_frame_info[frame];
+ 	int i;
+ 	int y_pages, uv_pages;
+-
+ 	unsigned long y_buffer_offset, uv_buffer_offset;
+ 	int y_decode_height, uv_decode_height, y_size;
+-	int frame = atomic_read(&itv->yuv_info.next_fill_frame);
+ 
+ 	y_buffer_offset = IVTV_DECODER_OFFSET + yuv_offset[frame];
+ 	uv_buffer_offset = y_buffer_offset + IVTV_YUV_BUFFER_UV_OFFSET;
+ 
+-	y_decode_height = uv_decode_height = args->src.height + args->src.top;
++	y_decode_height = uv_decode_height = f->src_h + f->src_y;
+ 
+-	if (y_decode_height < 512-16)
++	if (f->offset_y)
+ 		y_buffer_offset += 720 * 16;
+ 
+ 	if (y_decode_height & 15)
+@@ -60,8 +65,9 @@ static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma,
+ 
+ 	/* Still in USE */
+ 	if (dma->SG_length || dma->page_count) {
+-		IVTV_DEBUG_WARN("prep_user_dma: SG_length %d page_count %d still full?\n",
+-				dma->SG_length, dma->page_count);
++		IVTV_DEBUG_WARN
++		    ("prep_user_dma: SG_length %d page_count %d still full?\n",
++		     dma->SG_length, dma->page_count);
+ 		return -EBUSY;
+ 	}
+ 
+@@ -77,8 +83,9 @@ static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma,
+ 	dma->page_count = y_dma.page_count + uv_dma.page_count;
+ 
+ 	if (y_pages + uv_pages != dma->page_count) {
+-		IVTV_DEBUG_WARN("failed to map user pages, returned %d instead of %d\n",
+-				y_pages + uv_pages, dma->page_count);
++		IVTV_DEBUG_WARN
++		    ("failed to map user pages, returned %d instead of %d\n",
++		     y_pages + uv_pages, dma->page_count);
+ 
+ 		for (i = 0; i < dma->page_count; i++) {
+ 			put_page(dma->map[i]);
+@@ -99,16 +106,14 @@ static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma,
+ 	dma->SG_length = pci_map_sg(itv->dev, dma->SGlist, dma->page_count, PCI_DMA_TODEVICE);
+ 
+ 	/* Fill SG Array with new values */
+-	ivtv_udma_fill_sg_array (dma, y_buffer_offset, uv_buffer_offset, y_size);
++	ivtv_udma_fill_sg_array(dma, y_buffer_offset, uv_buffer_offset, y_size);
+ 
+ 	/* If we've offset the y plane, ensure top area is blanked */
+-	if (args->src.height + args->src.top < 512-16) {
+-		if (itv->yuv_info.blanking_dmaptr) {
+-			dma->SGarray[dma->SG_length].size = cpu_to_le32(720*16);
+-			dma->SGarray[dma->SG_length].src = cpu_to_le32(itv->yuv_info.blanking_dmaptr);
+-			dma->SGarray[dma->SG_length].dst = cpu_to_le32(IVTV_DECODER_OFFSET + yuv_offset[frame]);
+-			dma->SG_length++;
+-		}
++	if (f->offset_y && yi->blanking_dmaptr) {
++		dma->SGarray[dma->SG_length].size = cpu_to_le32(720*16);
++		dma->SGarray[dma->SG_length].src = cpu_to_le32(yi->blanking_dmaptr);
++		dma->SGarray[dma->SG_length].dst = cpu_to_le32(IVTV_DECODER_OFFSET + yuv_offset[frame]);
++		dma->SG_length++;
+ 	}
+ 
+ 	/* Tag SG Array with Interrupt Bit */
+@@ -121,11 +126,11 @@ static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma,
+ /* We rely on a table held in the firmware - Quick check. */
+ int ivtv_yuv_filter_check(struct ivtv *itv)
+ {
+-	int i, offset_y, offset_uv;
++	int i, y, uv;
+ 
+-	for (i=0, offset_y = 16, offset_uv = 4; i<16; i++, offset_y += 24, offset_uv += 12) {
+-		if ((read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + offset_y) != i << 16) ||
+-		    (read_dec(IVTV_YUV_VERTICAL_FILTER_OFFSET + offset_uv) != i << 16)) {
++	for (i = 0, y = 16, uv = 4; i < 16; i++, y += 24, uv += 12) {
++		if ((read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + y) != i << 16) ||
++		    (read_dec(IVTV_YUV_VERTICAL_FILTER_OFFSET + uv) != i << 16)) {
+ 			IVTV_WARN ("YUV filter table not found in firmware.\n");
+ 			return -1;
+ 		}
+@@ -135,69 +140,67 @@ int ivtv_yuv_filter_check(struct ivtv *itv)
+ 
+ static void ivtv_yuv_filter(struct ivtv *itv, int h_filter, int v_filter_1, int v_filter_2)
+ {
+-	int filter_index, filter_line;
++	u32 i, line;
+ 
+ 	/* If any filter is -1, then don't update it */
+ 	if (h_filter > -1) {
+-		if (h_filter > 4) h_filter = 4;
+-		filter_index = h_filter * 384;
+-		filter_line = 0;
+-		while (filter_line < 16) {
+-			write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02804);
+-			write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x0281c);
+-			filter_index += 4;
+-			write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02808);
+-			write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02820);
+-			filter_index += 4;
+-			write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x0280c);
+-			write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02824);
+-			filter_index += 4;
+-			write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02810);
+-			write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02828);
+-			filter_index += 4;
+-			write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02814);
+-			write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x0282c);
+-			filter_index += 8;
++		if (h_filter > 4)
++			h_filter = 4;
++		i = IVTV_YUV_HORIZONTAL_FILTER_OFFSET + (h_filter * 384);
++		for (line = 0; line < 16; line++) {
++			write_reg(read_dec(i), 0x02804);
++			write_reg(read_dec(i), 0x0281c);
++			i += 4;
++			write_reg(read_dec(i), 0x02808);
++			write_reg(read_dec(i), 0x02820);
++			i += 4;
++			write_reg(read_dec(i), 0x0280c);
++			write_reg(read_dec(i), 0x02824);
++			i += 4;
++			write_reg(read_dec(i), 0x02810);
++			write_reg(read_dec(i), 0x02828);
++			i += 4;
++			write_reg(read_dec(i), 0x02814);
++			write_reg(read_dec(i), 0x0282c);
++			i += 8;
+ 			write_reg(0, 0x02818);
+ 			write_reg(0, 0x02830);
+-			filter_line ++;
+ 		}
+-		IVTV_DEBUG_YUV("h_filter -> %d\n",h_filter);
++		IVTV_DEBUG_YUV("h_filter -> %d\n", h_filter);
  	}
- }
- 
- void em28xx_card_setup(struct em28xx *dev)
- {
-+	em28xx_set_model(dev);
-+
-+	dev->tuner_type = em28xx_boards[dev->model].tuner_type;
-+
- 	/* request some modules */
--	switch(dev->model){
--		case EM2820_BOARD_HAUPPAUGE_WINTV_USB_2:
--			{
--				struct tveeprom tv;
-+	switch (dev->model) {
-+	case EM2820_BOARD_HAUPPAUGE_WINTV_USB_2:
-+	case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900:
-+	case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950:
-+	{
-+		struct tveeprom tv;
- #ifdef CONFIG_MODULES
--				request_module("tveeprom");
--				request_module("ir-kbd-i2c");
--				request_module("msp3400");
-+		request_module("tveeprom");
- #endif
--				/* Call first TVeeprom */
--
--				dev->i2c_client.addr = 0xa0 >> 1;
--				tveeprom_hauppauge_analog(&dev->i2c_client, &tv, dev->eedata);
--
--				dev->tuner_type= tv.tuner_type;
--				if (tv.audio_processor == AUDIO_CHIP_MSP34XX) {
--					dev->i2s_speed=2048000;
--					dev->has_msp34xx=1;
--				} else
--					dev->has_msp34xx=0;
--				break;
--			}
--		case EM2820_BOARD_KWORLD_PVRTV2800RF:
--			{
--				em28xx_write_regs_req(dev,0x00,0x08, "\xf9", 1); // GPIO enables sound on KWORLD PVR TV 2800RF
--				break;
--			}
-+		/* Call first TVeeprom */
-+
-+		dev->i2c_client.addr = 0xa0 >> 1;
-+		tveeprom_hauppauge_analog(&dev->i2c_client, &tv, dev->eedata);
  
-+		dev->tuner_type = tv.tuner_type;
-+
-+		if (tv.audio_processor == AUDIO_CHIP_MSP34XX) {
-+			dev->i2s_speed = 2048000;
-+			dev->has_msp34xx = 1;
-+		}
-+#ifdef CONFIG_MODULES
-+		if (tv.has_ir)
-+			request_module("ir-kbd-i2c");
-+#endif
-+		break;
-+	}
-+	case EM2820_BOARD_KWORLD_PVRTV2800RF:
-+		/* GPIO enables sound on KWORLD PVR TV 2800RF */
-+		em28xx_write_regs_req(dev, 0x00, 0x08, "\xf9", 1);
-+		break;
-+	case EM2820_BOARD_UNKNOWN:
-+	case EM2800_BOARD_UNKNOWN:
-+		if (!em28xx_hint_board(dev))
-+			em28xx_set_model(dev);
+ 	if (v_filter_1 > -1) {
+-		if (v_filter_1 > 4) v_filter_1 = 4;
+-		filter_index = v_filter_1 * 192;
+-		filter_line = 0;
+-		while (filter_line < 16) {
+-			write_reg(read_dec(IVTV_YUV_VERTICAL_FILTER_OFFSET + filter_index), 0x02900);
+-			filter_index += 4;
+-			write_reg(read_dec(IVTV_YUV_VERTICAL_FILTER_OFFSET + filter_index), 0x02904);
+-			filter_index += 8;
++		if (v_filter_1 > 4)
++			v_filter_1 = 4;
++		i = IVTV_YUV_VERTICAL_FILTER_OFFSET + (v_filter_1 * 192);
++		for (line = 0; line < 16; line++) {
++			write_reg(read_dec(i), 0x02900);
++			i += 4;
++			write_reg(read_dec(i), 0x02904);
++			i += 8;
+ 			write_reg(0, 0x02908);
+-			filter_line ++;
+ 		}
+-		IVTV_DEBUG_YUV("v_filter_1 -> %d\n",v_filter_1);
++		IVTV_DEBUG_YUV("v_filter_1 -> %d\n", v_filter_1);
  	}
--}
  
--MODULE_DEVICE_TABLE (usb, em28xx_id_table);
-+	/* Allow override tuner type by a module parameter */
-+	if (tuner >= 0)
-+		dev->tuner_type = tuner;
-+
-+#ifdef CONFIG_MODULES
-+	/* request some modules */
-+	if (dev->has_msp34xx)
-+		request_module("msp3400");
-+	if (dev->decoder == EM28XX_SAA7113 || dev->decoder == EM28XX_SAA7114)
-+		request_module("saa7115");
-+	if (dev->decoder == EM28XX_TVP5150)
-+		request_module("tvp5150");
-+	if (dev->tuner_type != TUNER_ABSENT)
-+		request_module("tuner");
-+#endif
-+
-+	em28xx_config_tuner(dev);
-+}
-diff --git a/drivers/media/video/em28xx/em28xx-core.c b/drivers/media/video/em28xx/em28xx-core.c
-index d56484f..f6b7835 100644
---- a/drivers/media/video/em28xx/em28xx-core.c
-+++ b/drivers/media/video/em28xx/em28xx-core.c
-@@ -252,7 +252,7 @@ int em28xx_write_reg_bits(struct em28xx *dev, u16 reg, u8 val,
-  * em28xx_write_ac97()
-  * write a 16 bit value to the specified AC97 address (LSB first!)
-  */
--int em28xx_write_ac97(struct em28xx *dev, u8 reg, u8 * val)
-+static int em28xx_write_ac97(struct em28xx *dev, u8 reg, u8 *val)
- {
- 	int ret;
- 	u8 addr = reg & 0x7f;
-@@ -268,16 +268,98 @@ int em28xx_write_ac97(struct em28xx *dev, u8 reg, u8 * val)
- 	return 0;
+ 	if (v_filter_2 > -1) {
+-		if (v_filter_2 > 4) v_filter_2 = 4;
+-		filter_index = v_filter_2 * 192;
+-		filter_line = 0;
+-		while (filter_line < 16) {
+-			write_reg(read_dec(IVTV_YUV_VERTICAL_FILTER_OFFSET + filter_index), 0x0290c);
+-			filter_index += 4;
+-			write_reg(read_dec(IVTV_YUV_VERTICAL_FILTER_OFFSET + filter_index), 0x02910);
+-			filter_index += 8;
++		if (v_filter_2 > 4)
++			v_filter_2 = 4;
++		i = IVTV_YUV_VERTICAL_FILTER_OFFSET + (v_filter_2 * 192);
++		for (line = 0; line < 16; line++) {
++			write_reg(read_dec(i), 0x0290c);
++			i += 4;
++			write_reg(read_dec(i), 0x02910);
++			i += 8;
+ 			write_reg(0, 0x02914);
+-			filter_line ++;
+ 		}
+-		IVTV_DEBUG_YUV("v_filter_2 -> %d\n",v_filter_2);
++		IVTV_DEBUG_YUV("v_filter_2 -> %d\n", v_filter_2);
+ 	}
  }
  
-+int em28xx_set_audio_source(struct em28xx *dev)
-+{
-+	static char *enable  = "\x08\x08";
-+	static char *disable = "\x08\x88";
-+	char *video = enable, *line = disable;
-+	int ret, no_ac97;
-+	u8 input;
-+
-+	if (dev->is_em2800) {
-+		if (dev->ctl_ainput)
-+			input = EM2800_AUDIO_SRC_LINE;
-+		else
-+			input = EM2800_AUDIO_SRC_TUNER;
-+
-+		ret = em28xx_write_regs(dev, EM2800_AUDIOSRC_REG, &input, 1);
-+		if (ret < 0)
-+			return ret;
-+	}
-+
-+	if (dev->has_msp34xx)
-+		input = EM28XX_AUDIO_SRC_TUNER;
-+	else {
-+		switch (dev->ctl_ainput) {
-+		case EM28XX_AMUX_VIDEO:
-+			input = EM28XX_AUDIO_SRC_TUNER;
-+			no_ac97 = 1;
-+			break;
-+		case EM28XX_AMUX_LINE_IN:
-+			input = EM28XX_AUDIO_SRC_LINE;
-+			no_ac97 = 1;
-+			break;
-+		case EM28XX_AMUX_AC97_VIDEO:
-+			input = EM28XX_AUDIO_SRC_LINE;
-+			break;
-+		case EM28XX_AMUX_AC97_LINE_IN:
-+			input = EM28XX_AUDIO_SRC_LINE;
-+			video = disable;
-+			line  = enable;
-+			break;
-+		}
-+	}
-+
-+	ret = em28xx_write_reg_bits(dev, AUDIOSRC_REG, input, 0xc0);
-+	if (ret < 0)
-+		return ret;
-+
-+	if (no_ac97)
-+		return 0;
-+
-+	/* Sets AC97 mixer registers */
-+
-+	ret = em28xx_write_ac97(dev, VIDEO_AC97, video);
-+	if (ret < 0)
-+		return ret;
-+
-+	ret = em28xx_write_ac97(dev, LINE_IN_AC97, line);
-+
-+	return ret;
-+}
-+
- int em28xx_audio_analog_set(struct em28xx *dev)
+-static void ivtv_yuv_handle_horizontal(struct ivtv *itv, struct yuv_frame_info *window)
++static void ivtv_yuv_handle_horizontal(struct ivtv *itv, struct yuv_frame_info *f)
  {
-+	int ret;
- 	char s[2] = { 0x00, 0x00 };
-+	u8 xclk = 0x07;
-+
- 	s[0] |= 0x1f - dev->volume;
- 	s[1] |= 0x1f - dev->volume;
-+
- 	if (dev->mute)
- 		s[1] |= 0x80;
--	return em28xx_write_ac97(dev, MASTER_AC97, s);
--}
-+	ret = em28xx_write_ac97(dev, MASTER_AC97, s);
-+	if (ret < 0)
-+		return ret;
-+
-+	if (dev->has_12mhz_i2s)
-+		xclk |= 0x20;
-+
-+	if (!dev->mute)
-+		xclk |= 0x80;
++	struct yuv_playback_info *yi = &itv->yuv_info;
+ 	u32 reg_2834, reg_2838, reg_283c;
+ 	u32 reg_2844, reg_2854, reg_285c;
+ 	u32 reg_2864, reg_2874, reg_2890;
+@@ -206,18 +209,19 @@ static void ivtv_yuv_handle_horizontal(struct ivtv *itv, struct yuv_frame_info *
+ 	int h_filter;
+ 	u32 master_width;
  
-+	ret = em28xx_write_reg_bits(dev, XCLK_REG, xclk, 0xa7);
-+	if (ret < 0)
-+		return ret;
-+	msleep(10);
-+
-+	/* Selects the proper audio input */
-+	ret = em28xx_set_audio_source(dev);
-+
-+	return ret;
-+}
-+EXPORT_SYMBOL_GPL(em28xx_audio_analog_set);
+-	IVTV_DEBUG_WARN( "Need to adjust to width %d src_w %d dst_w %d src_x %d dst_x %d\n",
+-			 window->tru_w, window->src_w, window->dst_w,window->src_x, window->dst_x);
++	IVTV_DEBUG_WARN
++	    ("Adjust to width %d src_w %d dst_w %d src_x %d dst_x %d\n",
++	     f->tru_w, f->src_w, f->dst_w, f->src_x, f->dst_x);
  
- int em28xx_colorlevels_set_default(struct em28xx *dev)
- {
-diff --git a/drivers/media/video/em28xx/em28xx-i2c.c b/drivers/media/video/em28xx/em28xx-i2c.c
-index e3a4aa7..cacd04d 100644
---- a/drivers/media/video/em28xx/em28xx-i2c.c
-+++ b/drivers/media/video/em28xx/em28xx-i2c.c
-@@ -25,9 +25,9 @@
- #include <linux/kernel.h>
- #include <linux/usb.h>
- #include <linux/i2c.h>
--#include <linux/video_decoder.h>
+ 	/* How wide is the src image */
+-	x_cutoff  = window->src_w + window->src_x;
++	x_cutoff = f->src_w + f->src_x;
  
- #include "em28xx.h"
-+#include "tuner-xc2028.h"
- #include <media/v4l2-common.h>
- #include <media/tuner.h>
+ 	/* Set the display width */
+-	reg_2834 = window->dst_w;
++	reg_2834 = f->dst_w;
+ 	reg_2838 = reg_2834;
  
-@@ -291,6 +291,31 @@ static int em28xx_i2c_xfer(struct i2c_adapter *i2c_adap,
- 	return rc;
- }
+ 	/* Set the display position */
+-	reg_2890 = window->dst_x;
++	reg_2890 = f->dst_x;
  
-+/* based on linux/sunrpc/svcauth.h and linux/hash.h
-+ * The original hash function returns a different value, if arch is x86_64
-+ *  or i386.
-+ */
-+static inline unsigned long em28xx_hash_mem(char *buf, int length, int bits)
-+{
-+	unsigned long hash = 0;
-+	unsigned long l = 0;
-+	int len = 0;
-+	unsigned char c;
-+	do {
-+		if (len == length) {
-+			c = (char)len;
-+			len = -1;
-+		} else
-+			c = *buf++;
-+		l = (l << 8) | c;
-+		len++;
-+		if ((len & (32 / 8 - 1)) == 0)
-+			hash = ((hash^l) * 0x9e370001UL);
-+	} while (len);
-+
-+	return (hash >> (32 - bits)) & 0xffffffffUL;
-+}
-+
- static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len)
- {
- 	unsigned char buf, *p = eedata;
-@@ -334,7 +359,11 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len)
- 			printk("\n");
+ 	/* Index into the image horizontally */
+ 	reg_2870 = 0;
+@@ -228,32 +232,31 @@ static void ivtv_yuv_handle_horizontal(struct ivtv *itv, struct yuv_frame_info *
+ 	   Gradually adjust the offset to avoid the video 'snapping'
+ 	   left/right if it gets dragged through this region.
+ 	   Only do this if osd is full width. */
+-	if (window->vis_w == 720) {
+-		if ((window->tru_x - window->pan_x > -1) && (window->tru_x - window->pan_x <= 40) && (window->dst_w >= 680)){
+-			reg_2870 = 10 - (window->tru_x - window->pan_x) / 4;
+-		}
+-		else if ((window->tru_x - window->pan_x < 0) && (window->tru_x - window->pan_x >= -20) && (window->dst_w >= 660)) {
+-			reg_2870 = (10 + (window->tru_x - window->pan_x) / 2);
+-		}
++	if (f->vis_w == 720) {
++		if ((f->tru_x - f->pan_x > -1) && (f->tru_x - f->pan_x <= 40) && (f->dst_w >= 680))
++			reg_2870 = 10 - (f->tru_x - f->pan_x) / 4;
++		else if ((f->tru_x - f->pan_x < 0) && (f->tru_x - f->pan_x >= -20) && (f->dst_w >= 660))
++			reg_2870 = (10 + (f->tru_x - f->pan_x) / 2);
+ 
+-		if (window->dst_w >= window->src_w)
++		if (f->dst_w >= f->src_w)
+ 			reg_2870 = reg_2870 << 16 | reg_2870;
+ 		else
+ 			reg_2870 = ((reg_2870 & ~1) << 15) | (reg_2870 & ~1);
  	}
  
--	printk(KERN_INFO "EEPROM ID= 0x%08x\n", em_eeprom->id);
-+	if (em_eeprom->id == 0x9567eb1a)
-+		dev->hash = em28xx_hash_mem(eedata, len, 32);
-+
-+	printk(KERN_INFO "EEPROM ID= 0x%08x, hash = 0x%08lx\n",
-+	       em_eeprom->id, dev->hash);
- 	printk(KERN_INFO "Vendor/Product ID= %04x:%04x\n", em_eeprom->vendor_ID,
- 	       em_eeprom->product_ID);
+-	if (window->dst_w < window->src_w)
++	if (f->dst_w < f->src_w)
+ 		reg_2870 = 0x000d000e - reg_2870;
+ 	else
+ 		reg_2870 = 0x0012000e - reg_2870;
  
-@@ -391,21 +420,6 @@ static u32 functionality(struct i2c_adapter *adap)
- }
+ 	/* We're also using 2870 to shift the image left (src_x & negative dst_x) */
+-	reg_2870_offset = (window->src_x*((window->dst_w << 21)/window->src_w))>>19;
++	reg_2870_offset = (f->src_x * ((f->dst_w << 21) / f->src_w)) >> 19;
  
+-	if (window->dst_w >= window->src_w) {
++	if (f->dst_w >= f->src_w) {
+ 		x_cutoff &= ~1;
+-		master_width = (window->src_w * 0x00200000) / (window->dst_w);
+-		if (master_width * window->dst_w != window->src_w * 0x00200000) master_width ++;
++		master_width = (f->src_w * 0x00200000) / (f->dst_w);
++		if (master_width * f->dst_w != f->src_w * 0x00200000)
++			master_width++;
+ 		reg_2834 = (reg_2834 << 16) | x_cutoff;
+ 		reg_2838 = (reg_2838 << 16) | x_cutoff;
+ 		reg_283c = master_width >> 2;
+@@ -264,17 +267,17 @@ static void ivtv_yuv_handle_horizontal(struct ivtv *itv, struct yuv_frame_info *
  
--static int em28xx_set_tuner(int check_eeprom, struct i2c_client *client)
--{
--	struct em28xx *dev = client->adapter->algo_data;
--	struct tuner_setup tun_setup;
--
--	if (dev->has_tuner) {
--		tun_setup.mode_mask = T_ANALOG_TV | T_RADIO;
--		tun_setup.type = dev->tuner_type;
--		tun_setup.addr = dev->tuner_addr;
--		em28xx_i2c_call_clients(dev, TUNER_SET_TYPE_ADDR, &tun_setup);
+ 		/* We also need to factor in the scaling
+ 		   (src_w - dst_w) / (src_w / 4) */
+-		if (window->dst_w > window->src_w)
+-			reg_2870_base = ((window->dst_w - window->src_w)<<16) / (window->src_w <<14);
++		if (f->dst_w > f->src_w)
++			reg_2870_base = ((f->dst_w - f->src_w)<<16) / (f->src_w <<14);
+ 		else
+ 			reg_2870_base = 0;
+ 
+ 		reg_2870 += (((reg_2870_offset << 14) & 0xFFFF0000) | reg_2870_offset >> 2) + (reg_2870_base << 17 | reg_2870_base);
+ 		reg_2874 = 0;
 -	}
--
--	return (0);
--}
--
- /*
-  * attach_inform()
-  * gets called when a device attaches to the i2c bus
-@@ -421,6 +435,8 @@ static int attach_inform(struct i2c_client *client)
- 		case 0x96:
- 		case 0x94:
- 		{
-+			struct v4l2_priv_tun_config tda9887_cfg;
-+
- 			struct tuner_setup tun_setup;
+-	else if (window->dst_w < window->src_w / 2) {
+-		master_width = (window->src_w * 0x00080000) / window->dst_w;
+-		if (master_width * window->dst_w != window->src_w * 0x00080000) master_width ++;
++	} else if (f->dst_w < f->src_w / 2) {
++		master_width = (f->src_w * 0x00080000) / f->dst_w;
++		if (master_width * f->dst_w != f->src_w * 0x00080000)
++			master_width++;
+ 		reg_2834 = (reg_2834 << 16) | x_cutoff;
+ 		reg_2838 = (reg_2838 << 16) | x_cutoff;
+ 		reg_283c = master_width >> 2;
+@@ -282,13 +285,13 @@ static void ivtv_yuv_handle_horizontal(struct ivtv *itv, struct yuv_frame_info *
+ 		reg_2854 = master_width;
+ 		reg_285c = master_width >> 1;
+ 		reg_2864 = master_width >> 1;
+-		reg_2870 += (((reg_2870_offset << 15) & 0xFFFF0000) | reg_2870_offset);
+-		reg_2870 += (5 - (((window->src_w + window->src_w / 2) - 1) / window->dst_w)) << 16;
++		reg_2870 += ((reg_2870_offset << 15) & 0xFFFF0000) | reg_2870_offset;
++		reg_2870 += (5 - (((f->src_w + f->src_w / 2) - 1) / f->dst_w)) << 16;
+ 		reg_2874 = 0x00000012;
+-	}
+-	else {
+-		master_width = (window->src_w * 0x00100000) / window->dst_w;
+-		if (master_width * window->dst_w != window->src_w * 0x00100000) master_width ++;
++	} else {
++		master_width = (f->src_w * 0x00100000) / f->dst_w;
++		if (master_width * f->dst_w != f->src_w * 0x00100000)
++			master_width++;
+ 		reg_2834 = (reg_2834 << 16) | x_cutoff;
+ 		reg_2838 = (reg_2838 << 16) | x_cutoff;
+ 		reg_283c = master_width >> 2;
+@@ -296,62 +299,70 @@ static void ivtv_yuv_handle_horizontal(struct ivtv *itv, struct yuv_frame_info *
+ 		reg_2854 = master_width;
+ 		reg_285c = master_width >> 1;
+ 		reg_2864 = master_width >> 1;
+-		reg_2870 += (((reg_2870_offset << 14) & 0xFFFF0000) | reg_2870_offset >> 1);
+-		reg_2870 += (5 - (((window->src_w * 3) - 1) / window->dst_w)) << 16;
++		reg_2870 += ((reg_2870_offset << 14) & 0xFFFF0000) | reg_2870_offset >> 1;
++		reg_2870 += (5 - (((f->src_w * 3) - 1) / f->dst_w)) << 16;
+ 		reg_2874 = 0x00000001;
+ 	}
  
- 			tun_setup.mode_mask = T_ANALOG_TV | T_RADIO;
-@@ -428,7 +444,11 @@ static int attach_inform(struct i2c_client *client)
- 			tun_setup.addr = client->addr;
+ 	/* Select the horizontal filter */
+-	if (window->src_w == window->dst_w) {
++	if (f->src_w == f->dst_w) {
+ 		/* An exact size match uses filter 0 */
+ 		h_filter = 0;
+-	}
+-	else {
++	} else {
+ 		/* Figure out which filter to use */
+-		h_filter = ((window->src_w << 16) / window->dst_w) >> 15;
++		h_filter = ((f->src_w << 16) / f->dst_w) >> 15;
+ 		h_filter = (h_filter >> 1) + (h_filter & 1);
+ 		/* Only an exact size match can use filter 0 */
+-		if (h_filter == 0) h_filter = 1;
++		h_filter += !h_filter;
+ 	}
  
- 			em28xx_i2c_call_clients(dev, TUNER_SET_TYPE_ADDR, &tun_setup);
--			em28xx_i2c_call_clients(dev, TDA9887_SET_CONFIG, &dev->tda9887_conf);
-+
-+			tda9887_cfg.tuner = TUNER_TDA9887;
-+			tda9887_cfg.priv = &dev->tda9887_conf;
-+			em28xx_i2c_call_clients(dev, TUNER_SET_CONFIG,
-+						&tda9887_cfg);
- 			break;
- 		}
- 		case 0x42:
-@@ -458,9 +478,11 @@ static int attach_inform(struct i2c_client *client)
- 			break;
+ 	write_reg(reg_2834, 0x02834);
+ 	write_reg(reg_2838, 0x02838);
+-	IVTV_DEBUG_YUV("Update reg 0x2834 %08x->%08x 0x2838 %08x->%08x\n",itv->yuv_info.reg_2834, reg_2834, itv->yuv_info.reg_2838, reg_2838);
++	IVTV_DEBUG_YUV("Update reg 0x2834 %08x->%08x 0x2838 %08x->%08x\n",
++		       yi->reg_2834, reg_2834, yi->reg_2838, reg_2838);
  
- 		default:
-+			if (!dev->tuner_addr)
-+				dev->tuner_addr = client->addr;
-+
- 			dprintk1(1,"attach inform: detected I2C address %x\n", client->addr << 1);
--			dev->tuner_addr = client->addr;
--			em28xx_set_tuner(-1, client);
-+
- 	}
+ 	write_reg(reg_283c, 0x0283c);
+ 	write_reg(reg_2844, 0x02844);
  
- 	return 0;
-@@ -510,19 +532,26 @@ static char *i2c_devs[128] = {
-  * do_i2c_scan()
-  * check i2c address range for devices
-  */
--static void do_i2c_scan(char *name, struct i2c_client *c)
-+void em28xx_do_i2c_scan(struct em28xx *dev)
- {
-+	u8 i2c_devicelist[128];
- 	unsigned char buf;
- 	int i, rc;
+-	IVTV_DEBUG_YUV("Update reg 0x283c %08x->%08x 0x2844 %08x->%08x\n",itv->yuv_info.reg_283c, reg_283c, itv->yuv_info.reg_2844, reg_2844);
++	IVTV_DEBUG_YUV("Update reg 0x283c %08x->%08x 0x2844 %08x->%08x\n",
++		       yi->reg_283c, reg_283c, yi->reg_2844, reg_2844);
  
-+	memset(i2c_devicelist, 0, ARRAY_SIZE(i2c_devicelist));
-+
- 	for (i = 0; i < ARRAY_SIZE(i2c_devs); i++) {
--		c->addr = i;
--		rc = i2c_master_recv(c, &buf, 0);
-+		dev->i2c_client.addr = i;
-+		rc = i2c_master_recv(&dev->i2c_client, &buf, 0);
- 		if (rc < 0)
- 			continue;
--		printk(KERN_INFO "%s: found i2c device @ 0x%x [%s]\n", name,
--		       i << 1, i2c_devs[i] ? i2c_devs[i] : "???");
-+		i2c_devicelist[i] = i;
-+		printk(KERN_INFO "%s: found i2c device @ 0x%x [%s]\n",
-+		       dev->name, i << 1, i2c_devs[i] ? i2c_devs[i] : "???");
- 	}
-+
-+	dev->i2c_hash = em28xx_hash_mem(i2c_devicelist,
-+					ARRAY_SIZE(i2c_devicelist), 32);
- }
+ 	write_reg(0x00080514, 0x02840);
+ 	write_reg(0x00100514, 0x02848);
+-	IVTV_DEBUG_YUV("Update reg 0x2840 %08x->%08x 0x2848 %08x->%08x\n",itv->yuv_info.reg_2840, 0x00080514, itv->yuv_info.reg_2848, 0x00100514);
++	IVTV_DEBUG_YUV("Update reg 0x2840 %08x->%08x 0x2848 %08x->%08x\n",
++		       yi->reg_2840, 0x00080514, yi->reg_2848, 0x00100514);
  
- /*
-@@ -555,7 +584,7 @@ int em28xx_i2c_register(struct em28xx *dev)
- 	em28xx_i2c_eeprom(dev, dev->eedata, sizeof(dev->eedata));
+ 	write_reg(reg_2854, 0x02854);
+-	IVTV_DEBUG_YUV("Update reg 0x2854 %08x->%08x \n",itv->yuv_info.reg_2854, reg_2854);
++	IVTV_DEBUG_YUV("Update reg 0x2854 %08x->%08x \n",
++		       yi->reg_2854, reg_2854);
  
- 	if (i2c_scan)
--		do_i2c_scan(dev->name, &dev->i2c_client);
-+		em28xx_do_i2c_scan(dev);
- 	return 0;
+ 	write_reg(reg_285c, 0x0285c);
+ 	write_reg(reg_2864, 0x02864);
+-	IVTV_DEBUG_YUV("Update reg 0x285c %08x->%08x 0x2864 %08x->%08x\n",itv->yuv_info.reg_285c, reg_285c, itv->yuv_info.reg_2864, reg_2864);
++	IVTV_DEBUG_YUV("Update reg 0x285c %08x->%08x 0x2864 %08x->%08x\n",
++		       yi->reg_285c, reg_285c, yi->reg_2864, reg_2864);
+ 
+ 	write_reg(reg_2874, 0x02874);
+-	IVTV_DEBUG_YUV("Update reg 0x2874 %08x->%08x\n",itv->yuv_info.reg_2874, reg_2874);
++	IVTV_DEBUG_YUV("Update reg 0x2874 %08x->%08x\n",
++		       yi->reg_2874, reg_2874);
+ 
+ 	write_reg(reg_2870, 0x02870);
+-	IVTV_DEBUG_YUV("Update reg 0x2870 %08x->%08x\n",itv->yuv_info.reg_2870, reg_2870);
++	IVTV_DEBUG_YUV("Update reg 0x2870 %08x->%08x\n",
++		       yi->reg_2870, reg_2870);
+ 
+-	write_reg( reg_2890,0x02890);
+-	IVTV_DEBUG_YUV("Update reg 0x2890 %08x->%08x\n",itv->yuv_info.reg_2890, reg_2890);
++	write_reg(reg_2890, 0x02890);
++	IVTV_DEBUG_YUV("Update reg 0x2890 %08x->%08x\n",
++		       yi->reg_2890, reg_2890);
+ 
+ 	/* Only update the filter if we really need to */
+-	if (h_filter != itv->yuv_info.h_filter) {
+-		ivtv_yuv_filter (itv,h_filter,-1,-1);
+-		itv->yuv_info.h_filter = h_filter;
++	if (h_filter != yi->h_filter) {
++		ivtv_yuv_filter(itv, h_filter, -1, -1);
++		yi->h_filter = h_filter;
+ 	}
  }
  
-diff --git a/drivers/media/video/em28xx/em28xx-input.c b/drivers/media/video/em28xx/em28xx-input.c
-index e3894b6..10da2fd 100644
---- a/drivers/media/video/em28xx/em28xx-input.c
-+++ b/drivers/media/video/em28xx/em28xx-input.c
-@@ -30,11 +30,7 @@
+-static void ivtv_yuv_handle_vertical(struct ivtv *itv, struct yuv_frame_info *window)
++static void ivtv_yuv_handle_vertical(struct ivtv *itv, struct yuv_frame_info *f)
+ {
++	struct yuv_playback_info *yi = &itv->yuv_info;
+ 	u32 master_height;
+ 	u32 reg_2918, reg_291c, reg_2920, reg_2928;
+ 	u32 reg_2930, reg_2934, reg_293c;
+@@ -359,69 +370,59 @@ static void ivtv_yuv_handle_vertical(struct ivtv *itv, struct yuv_frame_info *wi
+ 	u32 reg_2950, reg_2954, reg_2958, reg_295c;
+ 	u32 reg_2960, reg_2964, reg_2968, reg_296c;
+ 	u32 reg_289c;
+-	u32 src_y_major_y, src_y_minor_y;
+-	u32 src_y_major_uv, src_y_minor_uv;
++	u32 src_major_y, src_minor_y;
++	u32 src_major_uv, src_minor_uv;
+ 	u32 reg_2964_base, reg_2968_base;
+ 	int v_filter_1, v_filter_2;
  
- #include "em28xx.h"
+-	IVTV_DEBUG_WARN("Need to adjust to height %d src_h %d dst_h %d src_y %d dst_y %d\n",
+-		window->tru_h, window->src_h, window->dst_h,window->src_y, window->dst_y);
++	IVTV_DEBUG_WARN
++	    ("Adjust to height %d src_h %d dst_h %d src_y %d dst_y %d\n",
++	     f->tru_h, f->src_h, f->dst_h, f->src_y, f->dst_y);
  
--static unsigned int disable_ir = 0;
--module_param(disable_ir, int, 0444);
--MODULE_PARM_DESC(disable_ir,"disable infrared remote support");
--
--static unsigned int ir_debug = 0;
-+static unsigned int ir_debug;
- module_param(ir_debug, int, 0644);
- MODULE_PARM_DESC(ir_debug,"enable debug messages [IR]");
+ 	/* What scaling mode is being used... */
+-	if (window->interlaced_y) {
+-		IVTV_DEBUG_YUV("Scaling mode Y: Interlaced\n");
+-	}
+-	else {
+-		IVTV_DEBUG_YUV("Scaling mode Y: Progressive\n");
+-	}
++	IVTV_DEBUG_YUV("Scaling mode Y: %s\n",
++		       f->interlaced_y ? "Interlaced" : "Progressive");
  
-@@ -43,7 +39,7 @@ MODULE_PARM_DESC(ir_debug,"enable debug messages [IR]");
+-	if (window->interlaced_uv) {
+-		IVTV_DEBUG_YUV("Scaling mode UV: Interlaced\n");
+-	}
+-	else {
+-		IVTV_DEBUG_YUV("Scaling mode UV: Progressive\n");
+-	}
++	IVTV_DEBUG_YUV("Scaling mode UV: %s\n",
++		       f->interlaced_uv ? "Interlaced" : "Progressive");
  
- /* ----------------------------------------------------------------------- */
+ 	/* What is the source video being treated as... */
+-	if (itv->yuv_info.frame_interlaced) {
+-		IVTV_DEBUG_WARN("Source video: Interlaced\n");
+-	}
+-	else {
+-		IVTV_DEBUG_WARN("Source video: Non-interlaced\n");
+-	}
++	IVTV_DEBUG_WARN("Source video: %s\n",
++			f->interlaced ? "Interlaced" : "Progressive");
  
--static int get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
-+int em28xx_get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
- {
- 	unsigned char b;
+ 	/* We offset into the image using two different index methods, so split
+ 	   the y source coord into two parts. */
+-	if (window->src_y < 8) {
+-		src_y_minor_uv = window->src_y;
+-		src_y_major_uv = 0;
+-	}
+-	else {
+-		src_y_minor_uv = 8;
+-		src_y_major_uv = window->src_y - 8;
++	if (f->src_y < 8) {
++		src_minor_uv = f->src_y;
++		src_major_uv = 0;
++	} else {
++		src_minor_uv = 8;
++		src_major_uv = f->src_y - 8;
+ 	}
  
-@@ -72,7 +68,7 @@ static int get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
- }
+-	src_y_minor_y = src_y_minor_uv;
+-	src_y_major_y = src_y_major_uv;
++	src_minor_y = src_minor_uv;
++	src_major_y = src_major_uv;
  
+-	if (window->offset_y) src_y_minor_y += 16;
++	if (f->offset_y)
++		src_minor_y += 16;
  
--static int get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
-+int em28xx_get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
- {
- 	unsigned char buf[2];
- 	unsigned char code;
-@@ -103,7 +99,8 @@ static int get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
- 	return 1;
- }
+-	if (window->interlaced_y)
+-		reg_2918 = (window->dst_h << 16) | (window->src_h + src_y_minor_y);
++	if (f->interlaced_y)
++		reg_2918 = (f->dst_h << 16) | (f->src_h + src_minor_y);
+ 	else
+-		reg_2918 = (window->dst_h << 16) | ((window->src_h + src_y_minor_y) << 1);
++		reg_2918 = (f->dst_h << 16) | ((f->src_h + src_minor_y) << 1);
  
--static int get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
-+int em28xx_get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key,
-+				     u32 *ir_raw)
- {
- 	unsigned char buf[3];
+-	if (window->interlaced_uv)
+-		reg_291c = (window->dst_h << 16) | ((window->src_h + src_y_minor_uv) >> 1);
++	if (f->interlaced_uv)
++		reg_291c = (f->dst_h << 16) | ((f->src_h + src_minor_uv) >> 1);
+ 	else
+-		reg_291c = (window->dst_h << 16) | (window->src_h + src_y_minor_uv);
++		reg_291c = (f->dst_h << 16) | (f->src_h + src_minor_uv);
  
-@@ -125,45 +122,6 @@ static int get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw
- 	return 1;
- }
+-	reg_2964_base = (src_y_minor_y * ((window->dst_h << 16)/window->src_h)) >> 14;
+-	reg_2968_base = (src_y_minor_uv * ((window->dst_h << 16)/window->src_h)) >> 14;
++	reg_2964_base = (src_minor_y * ((f->dst_h << 16) / f->src_h)) >> 14;
++	reg_2968_base = (src_minor_uv * ((f->dst_h << 16) / f->src_h)) >> 14;
  
--/* ----------------------------------------------------------------------- */
--void em28xx_set_ir(struct em28xx * dev,struct IR_i2c *ir)
--{
--	if (disable_ir) {
--		ir->get_key=NULL;
--		return ;
+-	if (window->dst_h / 2 >= window->src_h && !window->interlaced_y) {
+-		master_height = (window->src_h * 0x00400000) / window->dst_h;
+-		if ((window->src_h * 0x00400000) - (master_height * window->dst_h) >= window->dst_h / 2) master_height ++;
++	if (f->dst_h / 2 >= f->src_h && !f->interlaced_y) {
++		master_height = (f->src_h * 0x00400000) / f->dst_h;
++		if ((f->src_h * 0x00400000) - (master_height * f->dst_h) >= f->dst_h / 2)
++			master_height++;
+ 		reg_2920 = master_height >> 2;
+ 		reg_2928 = master_height >> 3;
+ 		reg_2930 = master_height;
+@@ -429,45 +430,42 @@ static void ivtv_yuv_handle_vertical(struct ivtv *itv, struct yuv_frame_info *wi
+ 		reg_2964_base >>= 3;
+ 		reg_2968_base >>= 3;
+ 		reg_296c = 0x00000000;
 -	}
--
--	/* detect & configure */
--	switch (dev->model) {
--	case (EM2800_BOARD_UNKNOWN):
--		break;
--	case (EM2820_BOARD_UNKNOWN):
--		break;
--	case (EM2800_BOARD_TERRATEC_CINERGY_200):
--	case (EM2820_BOARD_TERRATEC_CINERGY_250):
--		ir->ir_codes = ir_codes_em_terratec;
--		ir->get_key = get_key_terratec;
--		snprintf(ir->c.name, sizeof(ir->c.name), "i2c IR (EM28XX Terratec)");
--		break;
--	case (EM2820_BOARD_PINNACLE_USB_2):
--		ir->ir_codes = ir_codes_pinnacle_grey;
--		ir->get_key = get_key_pinnacle_usb_grey;
--		snprintf(ir->c.name, sizeof(ir->c.name), "i2c IR (EM28XX Pinnacle PCTV)");
--		break;
--	case (EM2820_BOARD_HAUPPAUGE_WINTV_USB_2):
--		ir->ir_codes = ir_codes_hauppauge_new;
--		ir->get_key = get_key_em_haup;
--		snprintf(ir->c.name, sizeof(ir->c.name), "i2c IR (EM2840 Hauppauge)");
--		break;
--	case (EM2820_BOARD_MSI_VOX_USB_2):
--		break;
--	case (EM2800_BOARD_LEADTEK_WINFAST_USBII):
--		break;
--	case (EM2800_BOARD_KWORLD_USB2800):
--		break;
+-	else if (window->dst_h >= window->src_h) {
+-		master_height = (window->src_h * 0x00400000) / window->dst_h;
++	} else if (f->dst_h >= f->src_h) {
++		master_height = (f->src_h * 0x00400000) / f->dst_h;
+ 		master_height = (master_height >> 1) + (master_height & 1);
+ 		reg_2920 = master_height >> 2;
+ 		reg_2928 = master_height >> 2;
+ 		reg_2930 = master_height;
+ 		reg_2940 = master_height >> 1;
+ 		reg_296c = 0x00000000;
+-		if (window->interlaced_y) {
++		if (f->interlaced_y) {
+ 			reg_2964_base >>= 3;
+-		}
+-		else {
+-			reg_296c ++;
++		} else {
++			reg_296c++;
+ 			reg_2964_base >>= 2;
+ 		}
+-		if (window->interlaced_uv) reg_2928 >>= 1;
++		if (f->interlaced_uv)
++			reg_2928 >>= 1;
+ 		reg_2968_base >>= 3;
 -	}
--}
--
- /* ----------------------------------------------------------------------
-  * Local variables:
-  * c-basic-offset: 8
-diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c
-index 0906bc5..a0c3346 100644
---- a/drivers/media/video/em28xx/em28xx-video.c
-+++ b/drivers/media/video/em28xx/em28xx-video.c
-@@ -33,13 +33,12 @@
- #include <linux/i2c.h>
- #include <linux/version.h>
- #include <linux/mm.h>
--#include <linux/video_decoder.h>
- #include <linux/mutex.h>
+-	else if (window->dst_h >= window->src_h / 2) {
+-		master_height = (window->src_h * 0x00200000) / window->dst_h;
++	} else if (f->dst_h >= f->src_h / 2) {
++		master_height = (f->src_h * 0x00200000) / f->dst_h;
+ 		master_height = (master_height >> 1) + (master_height & 1);
+ 		reg_2920 = master_height >> 2;
+ 		reg_2928 = master_height >> 2;
+ 		reg_2930 = master_height;
+ 		reg_2940 = master_height;
+ 		reg_296c = 0x00000101;
+-		if (window->interlaced_y) {
++		if (f->interlaced_y) {
+ 			reg_2964_base >>= 2;
+-		}
+-		else {
+-			reg_296c ++;
++		} else {
++			reg_296c++;
+ 			reg_2964_base >>= 1;
+ 		}
+-		if (window->interlaced_uv) reg_2928 >>= 1;
++		if (f->interlaced_uv)
++			reg_2928 >>= 1;
+ 		reg_2968_base >>= 2;
+-	}
+-	else {
+-		master_height = (window->src_h * 0x00100000) / window->dst_h;
++	} else {
++		master_height = (f->src_h * 0x00100000) / f->dst_h;
+ 		master_height = (master_height >> 1) + (master_height & 1);
+ 		reg_2920 = master_height >> 2;
+ 		reg_2928 = master_height >> 2;
+@@ -480,13 +478,12 @@ static void ivtv_yuv_handle_vertical(struct ivtv *itv, struct yuv_frame_info *wi
  
- #include "em28xx.h"
--#include <media/tuner.h>
- #include <media/v4l2-common.h>
- #include <media/msp3400.h>
-+#include <media/tuner.h>
+ 	/* FIXME These registers change depending on scaled / unscaled output
+ 	   We really need to work out what they should be */
+-	if (window->src_h == window->dst_h){
++	if (f->src_h == f->dst_h) {
+ 		reg_2934 = 0x00020000;
+ 		reg_293c = 0x00100000;
+ 		reg_2944 = 0x00040000;
+ 		reg_294c = 0x000b0000;
+-	}
+-	else {
++	} else {
+ 		reg_2934 = 0x00000FF0;
+ 		reg_293c = 0x00000FF0;
+ 		reg_2944 = 0x00000FF0;
+@@ -494,34 +491,36 @@ static void ivtv_yuv_handle_vertical(struct ivtv *itv, struct yuv_frame_info *wi
+ 	}
  
- #define DRIVER_AUTHOR "Ludovico Cavedon <cavedon at sssup.it>, " \
- 		      "Markus Rechberger <mrechberger at gmail.com>, " \
-@@ -48,7 +47,7 @@
+ 	/* The first line to be displayed */
+-	reg_2950 = 0x00010000 + src_y_major_y;
+-	if (window->interlaced_y) reg_2950 += 0x00010000;
++	reg_2950 = 0x00010000 + src_major_y;
++	if (f->interlaced_y)
++		reg_2950 += 0x00010000;
+ 	reg_2954 = reg_2950 + 1;
  
- #define DRIVER_NAME         "em28xx"
- #define DRIVER_DESC         "Empia em28xx based USB video device driver"
--#define EM28XX_VERSION_CODE  KERNEL_VERSION(0, 0, 1)
-+#define EM28XX_VERSION_CODE  KERNEL_VERSION(0, 1, 0)
+-	reg_2958 = 0x00010000 + (src_y_major_y >> 1);
+-	if (window->interlaced_uv) reg_2958 += 0x00010000;
++	reg_2958 = 0x00010000 + (src_major_y >> 1);
++	if (f->interlaced_uv)
++		reg_2958 += 0x00010000;
+ 	reg_295c = reg_2958 + 1;
  
- #define em28xx_videodbg(fmt, arg...) do {\
- 	if (video_debug) \
-@@ -63,17 +62,17 @@ static LIST_HEAD(em28xx_devlist);
+-	if (itv->yuv_info.decode_height == 480)
++	if (yi->decode_height == 480)
+ 		reg_289c = 0x011e0017;
+ 	else
+ 		reg_289c = 0x01500017;
  
- static unsigned int card[]     = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
- static unsigned int video_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
--static unsigned int vbi_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
-+static unsigned int vbi_nr[]   = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
-+static unsigned int radio_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
-+
- module_param_array(card,  int, NULL, 0444);
- module_param_array(video_nr, int, NULL, 0444);
- module_param_array(vbi_nr, int, NULL, 0444);
--MODULE_PARM_DESC(card,"card type");
--MODULE_PARM_DESC(video_nr,"video device numbers");
--MODULE_PARM_DESC(vbi_nr,"vbi device numbers");
--
--static int tuner = -1;
--module_param(tuner, int, 0444);
--MODULE_PARM_DESC(tuner, "tuner type");
-+module_param_array(radio_nr, int, NULL, 0444);
-+MODULE_PARM_DESC(card,     "card type");
-+MODULE_PARM_DESC(video_nr, "video device numbers");
-+MODULE_PARM_DESC(vbi_nr,   "vbi device numbers");
-+MODULE_PARM_DESC(radio_nr, "radio device numbers");
+-	if (window->dst_y < 0)
+-		reg_289c = (reg_289c - ((window->dst_y & ~1)<<15))-(window->dst_y >>1);
++	if (f->dst_y < 0)
++		reg_289c = (reg_289c - ((f->dst_y & ~1)<<15))-(f->dst_y >>1);
+ 	else
+-		reg_289c = (reg_289c + ((window->dst_y & ~1)<<15))+(window->dst_y >>1);
++		reg_289c = (reg_289c + ((f->dst_y & ~1)<<15))+(f->dst_y >>1);
  
- static unsigned int video_debug = 0;
- module_param(video_debug,int,0644);
-@@ -82,29 +81,6 @@ MODULE_PARM_DESC(video_debug,"enable debug messages [video]");
- /* Bitmask marking allocated devices from 0 to EM28XX_MAXBOARDS */
- static unsigned long em28xx_devused;
+ 	/* How much of the source to decode.
+ 	   Take into account the source offset */
+-	reg_2960 = ((src_y_minor_y + window->src_h + src_y_major_y) - 1 ) |
+-			((((src_y_minor_uv + window->src_h + src_y_major_uv) - 1) & ~1) << 15);
++	reg_2960 = ((src_minor_y + f->src_h + src_major_y) - 1) |
++		(((src_minor_uv + f->src_h + src_major_uv - 1) & ~1) << 15);
  
--/* supported tv norms */
--static struct em28xx_tvnorm tvnorms[] = {
--	{
--		.name = "PAL",
--		.id = V4L2_STD_PAL,
--		.mode = VIDEO_MODE_PAL,
--	 }, {
--		.name = "NTSC",
--		.id = V4L2_STD_NTSC,
--		.mode = VIDEO_MODE_NTSC,
--	}, {
--		 .name = "SECAM",
--		 .id = V4L2_STD_SECAM,
--		 .mode = VIDEO_MODE_SECAM,
--	}, {
--		.name = "PAL-M",
--		.id = V4L2_STD_PAL_M,
--		.mode = VIDEO_MODE_PAL,
+ 	/* Calculate correct value for register 2964 */
+-	if (window->src_h == window->dst_h)
++	if (f->src_h == f->dst_h) {
+ 		reg_2964 = 1;
+-	else {
+-		reg_2964 = 2 + ((window->dst_h << 1) / window->src_h);
++	} else {
++		reg_2964 = 2 + ((f->dst_h << 1) / f->src_h);
+ 		reg_2964 = (reg_2964 >> 1) + (reg_2964 & 1);
+ 	}
+ 	reg_2968 = (reg_2964 << 16) + reg_2964 + (reg_2964 >> 1);
+@@ -536,283 +535,246 @@ static void ivtv_yuv_handle_vertical(struct ivtv *itv, struct yuv_frame_info *wi
+ 	/* Deviate further from what it should be. I find the flicker headache
+ 	   inducing so try to reduce it slightly. Leave 2968 as-is otherwise
+ 	   colours foul. */
+-	if ((reg_2964 != 0x00010001) && (window->dst_h / 2 <= window->src_h))
+-		reg_2964 = (reg_2964 & 0xFFFF0000) + ((reg_2964 & 0x0000FFFF)/2);
++	if ((reg_2964 != 0x00010001) && (f->dst_h / 2 <= f->src_h))
++		reg_2964 = (reg_2964 & 0xFFFF0000) + ((reg_2964 & 0x0000FFFF) / 2);
+ 
+-	if (!window->interlaced_y) reg_2964 -= 0x00010001;
+-	if (!window->interlaced_uv) reg_2968 -= 0x00010001;
++	if (!f->interlaced_y)
++		reg_2964 -= 0x00010001;
++	if (!f->interlaced_uv)
++		reg_2968 -= 0x00010001;
+ 
+ 	reg_2964 += ((reg_2964_base << 16) | reg_2964_base);
+ 	reg_2968 += ((reg_2968_base << 16) | reg_2968_base);
+ 
+ 	/* Select the vertical filter */
+-	if (window->src_h == window->dst_h) {
++	if (f->src_h == f->dst_h) {
+ 		/* An exact size match uses filter 0/1 */
+ 		v_filter_1 = 0;
+ 		v_filter_2 = 1;
 -	}
--};
--
--#define TVNORMS ARRAY_SIZE(tvnorms)
--
- /* supported controls */
- /* Common to all boards */
- static struct v4l2_queryctrl em28xx_qctrl[] = {
-@@ -131,8 +107,6 @@ static struct v4l2_queryctrl em28xx_qctrl[] = {
+-	else {
++	} else {
+ 		/* Figure out which filter to use */
+-		v_filter_1 = ((window->src_h << 16) / window->dst_h) >> 15;
++		v_filter_1 = ((f->src_h << 16) / f->dst_h) >> 15;
+ 		v_filter_1 = (v_filter_1 >> 1) + (v_filter_1 & 1);
+ 		/* Only an exact size match can use filter 0 */
+-		if (v_filter_1 == 0) v_filter_1 = 1;
++		v_filter_1 += !v_filter_1;
+ 		v_filter_2 = v_filter_1;
+ 	}
+ 
+ 	write_reg(reg_2934, 0x02934);
+ 	write_reg(reg_293c, 0x0293c);
+-	IVTV_DEBUG_YUV("Update reg 0x2934 %08x->%08x 0x293c %08x->%08x\n",itv->yuv_info.reg_2934, reg_2934, itv->yuv_info.reg_293c, reg_293c);
++	IVTV_DEBUG_YUV("Update reg 0x2934 %08x->%08x 0x293c %08x->%08x\n",
++		       yi->reg_2934, reg_2934, yi->reg_293c, reg_293c);
+ 	write_reg(reg_2944, 0x02944);
+ 	write_reg(reg_294c, 0x0294c);
+-	IVTV_DEBUG_YUV("Update reg 0x2944 %08x->%08x 0x294c %08x->%08x\n",itv->yuv_info.reg_2944, reg_2944, itv->yuv_info.reg_294c, reg_294c);
++	IVTV_DEBUG_YUV("Update reg 0x2944 %08x->%08x 0x294c %08x->%08x\n",
++		       yi->reg_2944, reg_2944, yi->reg_294c, reg_294c);
+ 
+ 	/* Ensure 2970 is 0 (does it ever change ?) */
+ /*	write_reg(0,0x02970); */
+-/*	IVTV_DEBUG_YUV("Update reg 0x2970 %08x->%08x\n",itv->yuv_info.reg_2970, 0); */
++/*	IVTV_DEBUG_YUV("Update reg 0x2970 %08x->%08x\n", yi->reg_2970, 0); */
+ 
+ 	write_reg(reg_2930, 0x02938);
+ 	write_reg(reg_2930, 0x02930);
+-	IVTV_DEBUG_YUV("Update reg 0x2930 %08x->%08x 0x2938 %08x->%08x\n",itv->yuv_info.reg_2930, reg_2930, itv->yuv_info.reg_2938, reg_2930);
++	IVTV_DEBUG_YUV("Update reg 0x2930 %08x->%08x 0x2938 %08x->%08x\n",
++		       yi->reg_2930, reg_2930, yi->reg_2938, reg_2930);
+ 
+ 	write_reg(reg_2928, 0x02928);
+-	write_reg(reg_2928+0x514, 0x0292C);
+-	IVTV_DEBUG_YUV("Update reg 0x2928 %08x->%08x 0x292c %08x->%08x\n",itv->yuv_info.reg_2928, reg_2928, itv->yuv_info.reg_292c, reg_2928+0x514);
++	write_reg(reg_2928 + 0x514, 0x0292C);
++	IVTV_DEBUG_YUV("Update reg 0x2928 %08x->%08x 0x292c %08x->%08x\n",
++		       yi->reg_2928, reg_2928, yi->reg_292c, reg_2928 + 0x514);
+ 
+ 	write_reg(reg_2920, 0x02920);
+-	write_reg(reg_2920+0x514, 0x02924);
+-	IVTV_DEBUG_YUV("Update reg 0x2920 %08x->%08x 0x2924 %08x->%08x\n",itv->yuv_info.reg_2920, reg_2920, itv->yuv_info.reg_2924, 0x514+reg_2920);
++	write_reg(reg_2920 + 0x514, 0x02924);
++	IVTV_DEBUG_YUV("Update reg 0x2920 %08x->%08x 0x2924 %08x->%08x\n",
++		       yi->reg_2920, reg_2920, yi->reg_2924, reg_2920 + 0x514);
+ 
+-	write_reg (reg_2918,0x02918);
+-	write_reg (reg_291c,0x0291C);
+-	IVTV_DEBUG_YUV("Update reg 0x2918 %08x->%08x 0x291C %08x->%08x\n",itv->yuv_info.reg_2918,reg_2918,itv->yuv_info.reg_291c,reg_291c);
++	write_reg(reg_2918, 0x02918);
++	write_reg(reg_291c, 0x0291C);
++	IVTV_DEBUG_YUV("Update reg 0x2918 %08x->%08x 0x291C %08x->%08x\n",
++		       yi->reg_2918, reg_2918, yi->reg_291c, reg_291c);
  
- static struct usb_driver em28xx_usb_driver;
+ 	write_reg(reg_296c, 0x0296c);
+-	IVTV_DEBUG_YUV("Update reg 0x296c %08x->%08x\n",itv->yuv_info.reg_296c, reg_296c);
++	IVTV_DEBUG_YUV("Update reg 0x296c %08x->%08x\n",
++		       yi->reg_296c, reg_296c);
  
--static DEFINE_MUTEX(em28xx_sysfs_lock);
--static DECLARE_RWSEM(em28xx_disconnect);
+ 	write_reg(reg_2940, 0x02948);
+ 	write_reg(reg_2940, 0x02940);
+-	IVTV_DEBUG_YUV("Update reg 0x2940 %08x->%08x 0x2948 %08x->%08x\n",itv->yuv_info.reg_2940, reg_2940, itv->yuv_info.reg_2948, reg_2940);
++	IVTV_DEBUG_YUV("Update reg 0x2940 %08x->%08x 0x2948 %08x->%08x\n",
++		       yi->reg_2940, reg_2940, yi->reg_2948, reg_2940);
  
- /*********************  v4l2 interface  ******************************************/
+ 	write_reg(reg_2950, 0x02950);
+ 	write_reg(reg_2954, 0x02954);
+-	IVTV_DEBUG_YUV("Update reg 0x2950 %08x->%08x 0x2954 %08x->%08x\n",itv->yuv_info.reg_2950, reg_2950, itv->yuv_info.reg_2954, reg_2954);
++	IVTV_DEBUG_YUV("Update reg 0x2950 %08x->%08x 0x2954 %08x->%08x\n",
++		       yi->reg_2950, reg_2950, yi->reg_2954, reg_2954);
  
-@@ -153,11 +127,9 @@ static int em28xx_config(struct em28xx *dev)
- /*	em28xx_write_regs_req(dev,0x00,0x0f,"\x80",1); clk register */
- 	em28xx_write_regs_req(dev,0x00,0x11,"\x51",1);
+ 	write_reg(reg_2958, 0x02958);
+ 	write_reg(reg_295c, 0x0295C);
+-	IVTV_DEBUG_YUV("Update reg 0x2958 %08x->%08x 0x295C %08x->%08x\n",itv->yuv_info.reg_2958, reg_2958, itv->yuv_info.reg_295c, reg_295c);
++	IVTV_DEBUG_YUV("Update reg 0x2958 %08x->%08x 0x295C %08x->%08x\n",
++		       yi->reg_2958, reg_2958, yi->reg_295c, reg_295c);
  
--	em28xx_audio_usb_mute(dev, 1);
- 	dev->mute = 1;		/* maybe not the right place... */
- 	dev->volume = 0x1f;
--	em28xx_audio_analog_set(dev);
--	em28xx_audio_analog_setup(dev);
-+
- 	em28xx_outfmt_set_yuv422(dev);
- 	em28xx_colorlevels_set_default(dev);
- 	em28xx_compression_disable(dev);
-@@ -171,7 +143,6 @@ static int em28xx_config(struct em28xx *dev)
-  */
- static void em28xx_config_i2c(struct em28xx *dev)
- {
--	struct v4l2_frequency f;
- 	struct v4l2_routing route;
+ 	write_reg(reg_2960, 0x02960);
+-	IVTV_DEBUG_YUV("Update reg 0x2960 %08x->%08x \n",itv->yuv_info.reg_2960, reg_2960);
++	IVTV_DEBUG_YUV("Update reg 0x2960 %08x->%08x \n",
++		       yi->reg_2960, reg_2960);
  
- 	route.input = INPUT(dev->ctl_input)->vmux;
-@@ -179,18 +150,6 @@ static void em28xx_config_i2c(struct em28xx *dev)
- 	em28xx_i2c_call_clients(dev, VIDIOC_INT_RESET, NULL);
- 	em28xx_i2c_call_clients(dev, VIDIOC_INT_S_VIDEO_ROUTING, &route);
- 	em28xx_i2c_call_clients(dev, VIDIOC_STREAMON, NULL);
--
--	/* configure tuner */
--	f.tuner = 0;
--	f.type = V4L2_TUNER_ANALOG_TV;
--	f.frequency = 9076;	/* FIXME:remove magic number */
--	dev->ctl_freq = f.frequency;
--	em28xx_i2c_call_clients(dev, VIDIOC_S_FREQUENCY, &f);
--
--	/* configure tda9887 */
--
--
--/*	em28xx_i2c_call_clients(dev,VIDIOC_S_STD,&dev->tvnorm->id); */
- }
+ 	write_reg(reg_2964, 0x02964);
+ 	write_reg(reg_2968, 0x02968);
+-	IVTV_DEBUG_YUV("Update reg 0x2964 %08x->%08x 0x2968 %08x->%08x\n",itv->yuv_info.reg_2964, reg_2964, itv->yuv_info.reg_2968, reg_2968);
++	IVTV_DEBUG_YUV("Update reg 0x2964 %08x->%08x 0x2968 %08x->%08x\n",
++		       yi->reg_2964, reg_2964, yi->reg_2968, reg_2968);
  
- /*
-@@ -212,7 +171,6 @@ static void em28xx_empty_framequeues(struct em28xx *dev)
+-	write_reg( reg_289c,0x0289c);
+-	IVTV_DEBUG_YUV("Update reg 0x289c %08x->%08x\n",itv->yuv_info.reg_289c, reg_289c);
++	write_reg(reg_289c, 0x0289c);
++	IVTV_DEBUG_YUV("Update reg 0x289c %08x->%08x\n",
++		       yi->reg_289c, reg_289c);
  
- static void video_mux(struct em28xx *dev, int index)
- {
--	int ainput;
- 	struct v4l2_routing route;
+ 	/* Only update filter 1 if we really need to */
+-	if (v_filter_1 != itv->yuv_info.v_filter_1) {
+-		ivtv_yuv_filter (itv,-1,v_filter_1,-1);
+-		itv->yuv_info.v_filter_1 = v_filter_1;
++	if (v_filter_1 != yi->v_filter_1) {
++		ivtv_yuv_filter(itv, -1, v_filter_1, -1);
++		yi->v_filter_1 = v_filter_1;
+ 	}
  
- 	route.input = INPUT(index)->vmux;
-@@ -222,8 +180,6 @@ static void video_mux(struct em28xx *dev, int index)
+ 	/* Only update filter 2 if we really need to */
+-	if (v_filter_2 != itv->yuv_info.v_filter_2) {
+-		ivtv_yuv_filter (itv,-1,-1,v_filter_2);
+-		itv->yuv_info.v_filter_2 = v_filter_2;
++	if (v_filter_2 != yi->v_filter_2) {
++		ivtv_yuv_filter(itv, -1, -1, v_filter_2);
++		yi->v_filter_2 = v_filter_2;
+ 	}
+-
+ }
  
- 	em28xx_i2c_call_clients(dev, VIDIOC_INT_S_VIDEO_ROUTING, &route);
+ /* Modify the supplied coordinate information to fit the visible osd area */
+-static u32 ivtv_yuv_window_setup (struct ivtv *itv, struct yuv_frame_info *window)
++static u32 ivtv_yuv_window_setup(struct ivtv *itv, struct yuv_frame_info *f)
+ {
+-	int osd_crop, lace_threshold;
++	struct yuv_frame_info *of = &itv->yuv_info.old_frame_info;
++	int osd_crop;
+ 	u32 osd_scale;
+ 	u32 yuv_update = 0;
  
--	em28xx_videodbg("Setting input index=%d, vmux=%d, amux=%d\n",index,route.input,dev->ctl_ainput);
+-	lace_threshold = itv->yuv_info.lace_threshold;
+-	if (lace_threshold < 0)
+-		lace_threshold = itv->yuv_info.decode_height - 1;
 -
- 	if (dev->has_msp34xx) {
- 		if (dev->i2s_speed)
- 			em28xx_i2c_call_clients(dev, VIDIOC_INT_I2S_CLOCK_FREQ, &dev->i2s_speed);
-@@ -231,18 +187,1068 @@ static void video_mux(struct em28xx *dev, int index)
- 		route.output = MSP_OUTPUT(MSP_SC_IN_DSP_SCART1);
- 		/* Note: this is msp3400 specific */
- 		em28xx_i2c_call_clients(dev, VIDIOC_INT_S_AUDIO_ROUTING, &route);
--		ainput = EM28XX_AUDIO_SRC_TUNER;
--		em28xx_audio_source(dev, ainput);
-+	}
-+
-+	em28xx_set_audio_source(dev);
-+}
-+
-+/* Usage lock check functions */
-+static int res_get(struct em28xx_fh *fh)
-+{
-+	struct em28xx    *dev = fh->dev;
-+	int		 rc   = 0;
-+
-+	/* This instance already has stream_on */
-+	if (fh->stream_on)
-+		return rc;
-+
-+	mutex_lock(&dev->lock);
-+
-+	if (dev->stream_on)
-+		rc = -EINVAL;
-+	else {
-+		dev->stream_on = 1;
-+		fh->stream_on  = 1;
-+	}
-+
-+	mutex_unlock(&dev->lock);
-+	return rc;
-+}
-+
-+static int res_check(struct em28xx_fh *fh)
-+{
-+	return (fh->stream_on);
-+}
-+
-+static void res_free(struct em28xx_fh *fh)
-+{
-+	struct em28xx    *dev = fh->dev;
-+
-+	mutex_lock(&dev->lock);
-+	fh->stream_on = 0;
-+	dev->stream_on = 0;
-+	mutex_unlock(&dev->lock);
-+}
-+
-+/*
-+ * em28xx_vm_open()
-+ */
-+static void em28xx_vm_open(struct vm_area_struct *vma)
-+{
-+	struct em28xx_frame_t *f = vma->vm_private_data;
-+	f->vma_use_count++;
-+}
-+
-+/*
-+ * em28xx_vm_close()
-+ */
-+static void em28xx_vm_close(struct vm_area_struct *vma)
-+{
-+	/* NOTE: buffers are not freed here */
-+	struct em28xx_frame_t *f = vma->vm_private_data;
-+
-+	if (f->vma_use_count)
-+		f->vma_use_count--;
-+}
-+
-+static struct vm_operations_struct em28xx_vm_ops = {
-+	.open = em28xx_vm_open,
-+	.close = em28xx_vm_close,
-+};
-+
-+
-+/*
-+ * em28xx_get_ctrl()
-+ * return the current saturation, brightness or contrast, mute state
-+ */
-+static int em28xx_get_ctrl(struct em28xx *dev, struct v4l2_control *ctrl)
-+{
-+	switch (ctrl->id) {
-+	case V4L2_CID_AUDIO_MUTE:
-+		ctrl->value = dev->mute;
-+		return 0;
-+	case V4L2_CID_AUDIO_VOLUME:
-+		ctrl->value = dev->volume;
-+		return 0;
-+	default:
-+		return -EINVAL;
-+	}
-+}
-+
-+/*
-+ * em28xx_set_ctrl()
-+ * mute or set new saturation, brightness or contrast
-+ */
-+static int em28xx_set_ctrl(struct em28xx *dev, const struct v4l2_control *ctrl)
-+{
-+	switch (ctrl->id) {
-+	case V4L2_CID_AUDIO_MUTE:
-+		if (ctrl->value != dev->mute) {
-+			dev->mute = ctrl->value;
-+			return em28xx_audio_analog_set(dev);
-+		}
-+		return 0;
-+	case V4L2_CID_AUDIO_VOLUME:
-+		dev->volume = ctrl->value;
-+		return em28xx_audio_analog_set(dev);
-+	default:
-+		return -EINVAL;
-+	}
-+}
-+
-+/*
-+ * em28xx_stream_interrupt()
-+ * stops streaming
-+ */
-+static int em28xx_stream_interrupt(struct em28xx *dev)
-+{
-+	int rc = 0;
-+
-+	/* stop reading from the device */
-+
-+	dev->stream = STREAM_INTERRUPT;
-+	rc = wait_event_timeout(dev->wait_stream,
-+				(dev->stream == STREAM_OFF) ||
-+				(dev->state & DEV_DISCONNECTED),
-+				EM28XX_URB_TIMEOUT);
-+
-+	if (rc) {
-+		dev->state |= DEV_MISCONFIGURED;
-+		em28xx_videodbg("device is misconfigured; close and "
-+			"open /dev/video%d again\n",
-+				dev->vdev->minor-MINOR_VFL_TYPE_GRABBER_MIN);
-+		return rc;
-+	}
-+
-+	return 0;
-+}
-+
-+
-+static int check_dev(struct em28xx *dev)
-+{
-+	if (dev->state & DEV_DISCONNECTED) {
-+		em28xx_errdev("v4l2 ioctl: device not present\n");
-+		return -ENODEV;
-+	}
-+
-+	if (dev->state & DEV_MISCONFIGURED) {
-+		em28xx_errdev("v4l2 ioctl: device is misconfigured; "
-+			      "close and open it again\n");
-+		return -EIO;
-+	}
-+	return 0;
-+}
-+
-+static void get_scale(struct em28xx *dev,
-+			unsigned int width, unsigned int height,
-+			unsigned int *hscale, unsigned int *vscale)
-+{
-+	unsigned int          maxw   = norm_maxw(dev);
-+	unsigned int          maxh   = norm_maxh(dev);
-+
-+	*hscale = (((unsigned long)maxw) << 12) / width - 4096L;
-+	if (*hscale >= 0x4000)
-+		*hscale = 0x3fff;
-+
-+	*vscale = (((unsigned long)maxh) << 12) / height - 4096L;
-+	if (*vscale >= 0x4000)
-+		*vscale = 0x3fff;
-+}
-+
-+/* ------------------------------------------------------------------
-+	IOCTL vidioc handling
-+   ------------------------------------------------------------------*/
-+
-+static int vidioc_g_fmt_cap(struct file *file, void *priv,
-+					struct v4l2_format *f)
-+{
-+	struct em28xx_fh      *fh  = priv;
-+	struct em28xx         *dev = fh->dev;
-+
-+	mutex_lock(&dev->lock);
-+
-+	f->fmt.pix.width = dev->width;
-+	f->fmt.pix.height = dev->height;
-+	f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
-+	f->fmt.pix.bytesperline = dev->bytesperline;
-+	f->fmt.pix.sizeimage = dev->frame_size;
-+	f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
-+
-+	/* FIXME: TOP? NONE? BOTTOM? ALTENATE? */
-+	f->fmt.pix.field = dev->interlaced ?
-+			   V4L2_FIELD_INTERLACED : V4L2_FIELD_TOP;
-+
-+	mutex_unlock(&dev->lock);
-+	return 0;
-+}
-+
-+static int vidioc_try_fmt_cap(struct file *file, void *priv,
-+			struct v4l2_format *f)
-+{
-+	struct em28xx_fh      *fh    = priv;
-+	struct em28xx         *dev   = fh->dev;
-+	int                   width  = f->fmt.pix.width;
-+	int                   height = f->fmt.pix.height;
-+	unsigned int          maxw   = norm_maxw(dev);
-+	unsigned int          maxh   = norm_maxh(dev);
-+	unsigned int          hscale, vscale;
-+
-+	/* width must even because of the YUYV format
-+	   height must be even because of interlacing */
-+	height &= 0xfffe;
-+	width &= 0xfffe;
-+
-+	if (height < 32)
-+		height = 32;
-+	if (height > maxh)
-+		height = maxh;
-+	if (width < 48)
-+		width = 48;
-+	if (width > maxw)
-+		width = maxw;
-+
-+	mutex_lock(&dev->lock);
-+
-+	if (dev->is_em2800) {
-+		/* the em2800 can only scale down to 50% */
-+		if (height % (maxh / 2))
-+			height = maxh;
-+		if (width % (maxw / 2))
-+			width = maxw;
-+		/* according to empiatech support */
-+		/* the MaxPacketSize is to small to support */
-+		/* framesizes larger than 640x480 @ 30 fps */
-+		/* or 640x576 @ 25 fps. As this would cut */
-+		/* of a part of the image we prefer */
-+		/* 360x576 or 360x480 for now */
-+		if (width == maxw && height == maxh)
-+			width /= 2;
-+	}
-+
-+	get_scale(dev, width, height, &hscale, &vscale);
-+
-+	width = (((unsigned long)maxw) << 12) / (hscale + 4096L);
-+	height = (((unsigned long)maxh) << 12) / (vscale + 4096L);
-+
-+	f->fmt.pix.width = width;
-+	f->fmt.pix.height = height;
-+	f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
-+	f->fmt.pix.bytesperline = width * 2;
-+	f->fmt.pix.sizeimage = width * 2 * height;
-+	f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
-+	f->fmt.pix.field = V4L2_FIELD_INTERLACED;
-+
-+	mutex_unlock(&dev->lock);
-+	return 0;
-+}
-+
-+static int vidioc_s_fmt_cap(struct file *file, void *priv,
-+			struct v4l2_format *f)
-+{
-+	struct em28xx_fh      *fh  = priv;
-+	struct em28xx         *dev = fh->dev;
-+	int                   rc, i;
-+
-+	rc = check_dev(dev);
-+	if (rc < 0)
-+		return rc;
-+
-+	vidioc_try_fmt_cap(file, priv, f);
-+
-+	mutex_lock(&dev->lock);
-+
-+	for (i = 0; i < dev->num_frames; i++)
-+		if (dev->frame[i].vma_use_count) {
-+			em28xx_videodbg("VIDIOC_S_FMT failed. "
-+					"Unmap the buffers first.\n");
-+			rc = -EINVAL;
-+			goto err;
-+		}
-+
-+	/* stop io in case it is already in progress */
-+	if (dev->stream == STREAM_ON) {
-+		em28xx_videodbg("VIDIOC_SET_FMT: interrupting stream\n");
-+		rc = em28xx_stream_interrupt(dev);
-+		if (rc < 0)
-+			goto err;
-+	}
-+
-+	em28xx_release_buffers(dev);
-+	dev->io = IO_NONE;
-+
-+	/* set new image size */
-+	dev->width = f->fmt.pix.width;
-+	dev->height = f->fmt.pix.height;
-+	dev->frame_size = dev->width * dev->height * 2;
-+	dev->field_size = dev->frame_size >> 1;
-+	dev->bytesperline = dev->width * 2;
-+	get_scale(dev, dev->width, dev->height, &dev->hscale, &dev->vscale);
-+
-+	/* FIXME: This is really weird! Why capture is starting with
-+	   this ioctl ???
-+	 */
-+	em28xx_uninit_isoc(dev);
-+	em28xx_set_alternate(dev);
-+	em28xx_capture_start(dev, 1);
-+	em28xx_resolution_set(dev);
-+	em28xx_init_isoc(dev);
-+	rc = 0;
-+
-+err:
-+	mutex_unlock(&dev->lock);
-+	return rc;
-+}
-+
-+static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *norm)
-+{
-+	struct em28xx_fh   *fh  = priv;
-+	struct em28xx      *dev = fh->dev;
-+	struct v4l2_format f;
-+	int                rc;
-+
-+	rc = check_dev(dev);
-+	if (rc < 0)
-+		return rc;
-+
-+	mutex_lock(&dev->lock);
-+	dev->norm = *norm;
-+	mutex_unlock(&dev->lock);
-+
-+	/* Adjusts width/height, if needed */
-+	f.fmt.pix.width = dev->width;
-+	f.fmt.pix.height = dev->height;
-+	vidioc_try_fmt_cap(file, priv, &f);
-+
-+	mutex_lock(&dev->lock);
-+
-+	/* set new image size */
-+	dev->width = f.fmt.pix.width;
-+	dev->height = f.fmt.pix.height;
-+	dev->frame_size = dev->width * dev->height * 2;
-+	dev->field_size = dev->frame_size >> 1;
-+	dev->bytesperline = dev->width * 2;
-+	get_scale(dev, dev->width, dev->height, &dev->hscale, &dev->vscale);
-+
-+	em28xx_resolution_set(dev);
-+	em28xx_i2c_call_clients(dev, VIDIOC_S_STD, &dev->norm);
-+
-+	mutex_unlock(&dev->lock);
-+	return 0;
-+}
-+
-+static const char *iname[] = {
-+	[EM28XX_VMUX_COMPOSITE1] = "Composite1",
-+	[EM28XX_VMUX_COMPOSITE2] = "Composite2",
-+	[EM28XX_VMUX_COMPOSITE3] = "Composite3",
-+	[EM28XX_VMUX_COMPOSITE4] = "Composite4",
-+	[EM28XX_VMUX_SVIDEO]     = "S-Video",
-+	[EM28XX_VMUX_TELEVISION] = "Television",
-+	[EM28XX_VMUX_CABLE]      = "Cable TV",
-+	[EM28XX_VMUX_DVB]        = "DVB",
-+	[EM28XX_VMUX_DEBUG]      = "for debug only",
-+};
-+
-+static int vidioc_enum_input(struct file *file, void *priv,
-+				struct v4l2_input *i)
-+{
-+	struct em28xx_fh   *fh  = priv;
-+	struct em28xx      *dev = fh->dev;
-+	unsigned int       n;
-+
-+	n = i->index;
-+	if (n >= MAX_EM28XX_INPUT)
-+		return -EINVAL;
-+	if (0 == INPUT(n)->type)
-+		return -EINVAL;
-+
-+	i->index = n;
-+	i->type = V4L2_INPUT_TYPE_CAMERA;
-+
-+	strcpy(i->name, iname[INPUT(n)->type]);
-+
-+	if ((EM28XX_VMUX_TELEVISION == INPUT(n)->type) ||
-+		(EM28XX_VMUX_CABLE == INPUT(n)->type))
-+		i->type = V4L2_INPUT_TYPE_TUNER;
-+
-+	i->std = dev->vdev->tvnorms;
-+
-+	return 0;
-+}
-+
-+static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
-+{
-+	struct em28xx_fh   *fh  = priv;
-+	struct em28xx      *dev = fh->dev;
-+
-+	*i = dev->ctl_input;
-+
-+	return 0;
-+}
-+
-+static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
-+{
-+	struct em28xx_fh   *fh  = priv;
-+	struct em28xx      *dev = fh->dev;
-+	int                rc;
-+
-+	rc = check_dev(dev);
-+	if (rc < 0)
-+		return rc;
-+
-+	if (i >= MAX_EM28XX_INPUT)
-+		return -EINVAL;
-+	if (0 == INPUT(i)->type)
-+		return -EINVAL;
-+
-+	mutex_lock(&dev->lock);
-+
-+	video_mux(dev, i);
-+
-+	mutex_unlock(&dev->lock);
-+	return 0;
-+}
-+
-+static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
-+{
-+	struct em28xx_fh   *fh    = priv;
-+	struct em28xx      *dev   = fh->dev;
-+	unsigned int        index = a->index;
-+
-+	if (a->index > 1)
-+		return -EINVAL;
-+
-+	index = dev->ctl_ainput;
-+
-+	if (index == 0) {
-+		strcpy(a->name, "Television");
- 	} else {
--		switch (dev->ctl_ainput) {
--			case 0:
--				ainput = EM28XX_AUDIO_SRC_TUNER;
-+		strcpy(a->name, "Line In");
-+	}
-+	a->capability = V4L2_AUDCAP_STEREO;
-+	a->index = index;
-+
-+	return 0;
-+}
-+
-+static int vidioc_s_audio(struct file *file, void *priv, struct v4l2_audio *a)
-+{
-+	struct em28xx_fh   *fh  = priv;
-+	struct em28xx      *dev = fh->dev;
-+
-+	if (a->index != dev->ctl_ainput)
-+		return -EINVAL;
-+
-+	return 0;
-+}
-+
-+static int vidioc_queryctrl(struct file *file, void *priv,
-+				struct v4l2_queryctrl *qc)
-+{
-+	struct em28xx_fh      *fh  = priv;
-+	struct em28xx         *dev = fh->dev;
-+	int                   id  = qc->id;
-+	int                   i;
-+	int                   rc;
-+
-+	rc = check_dev(dev);
-+	if (rc < 0)
-+		return rc;
-+
-+	memset(qc, 0, sizeof(*qc));
-+
-+	qc->id = id;
-+
-+	if (!dev->has_msp34xx) {
-+		for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) {
-+			if (qc->id && qc->id == em28xx_qctrl[i].id) {
-+				memcpy(qc, &(em28xx_qctrl[i]), sizeof(*qc));
-+				return 0;
-+			}
-+		}
-+	}
-+	mutex_lock(&dev->lock);
-+	em28xx_i2c_call_clients(dev, VIDIOC_QUERYCTRL, qc);
-+	mutex_unlock(&dev->lock);
-+
-+	if (qc->type)
-+		return 0;
-+	else
-+		return -EINVAL;
-+}
-+
-+static int vidioc_g_ctrl(struct file *file, void *priv,
-+				struct v4l2_control *ctrl)
-+{
-+	struct em28xx_fh      *fh  = priv;
-+	struct em28xx         *dev = fh->dev;
-+	int                   rc;
-+
-+	rc = check_dev(dev);
-+	if (rc < 0)
-+		return rc;
-+	mutex_lock(&dev->lock);
-+
-+	if (!dev->has_msp34xx)
-+		rc = em28xx_get_ctrl(dev, ctrl);
-+	else
-+		rc = -EINVAL;
-+
-+	if (rc == -EINVAL) {
-+		em28xx_i2c_call_clients(dev, VIDIOC_G_CTRL, ctrl);
-+		rc = 0;
-+	}
-+
-+	mutex_unlock(&dev->lock);
-+	return rc;
-+}
-+
-+static int vidioc_s_ctrl(struct file *file, void *priv,
-+				struct v4l2_control *ctrl)
-+{
-+	struct em28xx_fh      *fh  = priv;
-+	struct em28xx         *dev = fh->dev;
-+	u8                    i;
-+	int                   rc;
-+
-+	rc = check_dev(dev);
-+	if (rc < 0)
-+		return rc;
-+
-+	mutex_lock(&dev->lock);
-+
-+	if (dev->has_msp34xx)
-+		em28xx_i2c_call_clients(dev, VIDIOC_S_CTRL, ctrl);
-+	else {
-+		rc = 1;
-+		for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) {
-+			if (ctrl->id == em28xx_qctrl[i].id) {
-+				if (ctrl->value < em28xx_qctrl[i].minimum ||
-+				    ctrl->value > em28xx_qctrl[i].maximum) {
-+					rc = -ERANGE;
-+					break;
-+				}
-+
-+				rc = em28xx_set_ctrl(dev, ctrl);
- 				break;
--			default:
--				ainput = EM28XX_AUDIO_SRC_LINE;
-+			}
-+		}
-+	}
-+
-+	/* Control not found - try to send it to the attached devices */
-+	if (rc == 1) {
-+		em28xx_i2c_call_clients(dev, VIDIOC_S_CTRL, ctrl);
-+		rc = 0;
-+	}
-+
-+	mutex_unlock(&dev->lock);
-+	return rc;
-+}
-+
-+static int vidioc_g_tuner(struct file *file, void *priv,
-+				struct v4l2_tuner *t)
-+{
-+	struct em28xx_fh      *fh  = priv;
-+	struct em28xx         *dev = fh->dev;
-+	int                   rc;
-+
-+	rc = check_dev(dev);
-+	if (rc < 0)
-+		return rc;
-+
-+	if (0 != t->index)
-+		return -EINVAL;
-+
-+	strcpy(t->name, "Tuner");
-+
-+	mutex_lock(&dev->lock);
-+
-+	em28xx_i2c_call_clients(dev, VIDIOC_G_TUNER, t);
-+
-+	mutex_unlock(&dev->lock);
-+	return 0;
-+}
-+
-+static int vidioc_s_tuner(struct file *file, void *priv,
-+				struct v4l2_tuner *t)
-+{
-+	struct em28xx_fh      *fh  = priv;
-+	struct em28xx         *dev = fh->dev;
-+	int                   rc;
-+
-+	rc = check_dev(dev);
-+	if (rc < 0)
-+		return rc;
-+
-+	if (0 != t->index)
-+		return -EINVAL;
-+
-+	mutex_lock(&dev->lock);
-+
-+	em28xx_i2c_call_clients(dev, VIDIOC_S_TUNER, t);
-+
-+	mutex_unlock(&dev->lock);
-+	return 0;
-+}
-+
-+static int vidioc_g_frequency(struct file *file, void *priv,
-+				struct v4l2_frequency *f)
-+{
-+	struct em28xx_fh      *fh  = priv;
-+	struct em28xx         *dev = fh->dev;
-+
-+	f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
-+	f->frequency = dev->ctl_freq;
-+
-+	return 0;
-+}
-+
-+static int vidioc_s_frequency(struct file *file, void *priv,
-+				struct v4l2_frequency *f)
-+{
-+	struct em28xx_fh      *fh  = priv;
-+	struct em28xx         *dev = fh->dev;
-+	int                   rc;
-+
-+	rc = check_dev(dev);
-+	if (rc < 0)
-+		return rc;
-+
-+	if (0 != f->tuner)
-+		return -EINVAL;
-+
-+	if (unlikely(0 == fh->radio && f->type != V4L2_TUNER_ANALOG_TV))
-+		return -EINVAL;
-+	if (unlikely(1 == fh->radio && f->type != V4L2_TUNER_RADIO))
-+		return -EINVAL;
-+
-+	mutex_lock(&dev->lock);
-+
-+	dev->ctl_freq = f->frequency;
-+	em28xx_i2c_call_clients(dev, VIDIOC_S_FREQUENCY, f);
-+
-+	mutex_unlock(&dev->lock);
-+	return 0;
-+}
-+
-+static int vidioc_cropcap(struct file *file, void *priv,
-+					struct v4l2_cropcap *cc)
-+{
-+	struct em28xx_fh      *fh  = priv;
-+	struct em28xx         *dev = fh->dev;
-+
-+	if (cc->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-+		return -EINVAL;
-+
-+	cc->bounds.left = 0;
-+	cc->bounds.top = 0;
-+	cc->bounds.width = dev->width;
-+	cc->bounds.height = dev->height;
-+	cc->defrect = cc->bounds;
-+	cc->pixelaspect.numerator = 54;	/* 4:3 FIXME: remove magic numbers */
-+	cc->pixelaspect.denominator = 59;
-+
-+	return 0;
-+}
-+
-+static int vidioc_streamon(struct file *file, void *priv,
-+					enum v4l2_buf_type type)
-+{
-+	struct em28xx_fh      *fh  = priv;
-+	struct em28xx         *dev = fh->dev;
-+	int                   rc;
-+
-+	rc = check_dev(dev);
-+	if (rc < 0)
-+		return rc;
-+
-+	if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || dev->io != IO_MMAP)
-+		return -EINVAL;
-+
-+	if (list_empty(&dev->inqueue))
-+		return -EINVAL;
-+
-+	mutex_lock(&dev->lock);
-+
-+	if (unlikely(res_get(fh) < 0)) {
-+		mutex_unlock(&dev->lock);
-+		return -EBUSY;
-+	}
-+
-+	dev->stream = STREAM_ON;	/* FIXME: Start video capture here? */
-+
-+	mutex_unlock(&dev->lock);
-+	return 0;
-+}
-+
-+static int vidioc_streamoff(struct file *file, void *priv,
-+					enum v4l2_buf_type type)
-+{
-+	struct em28xx_fh      *fh  = priv;
-+	struct em28xx         *dev = fh->dev;
-+	int                   rc;
-+
-+	rc = check_dev(dev);
-+	if (rc < 0)
-+		return rc;
-+
-+	if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || dev->io != IO_MMAP)
-+		return -EINVAL;
-+
-+	mutex_lock(&dev->lock);
-+
-+	if (dev->stream == STREAM_ON) {
-+		em28xx_videodbg("VIDIOC_STREAMOFF: interrupting stream\n");
-+		rc = em28xx_stream_interrupt(dev);
-+		if (rc < 0) {
-+			mutex_unlock(&dev->lock);
-+			return rc;
-+		}
-+	}
-+
-+	em28xx_empty_framequeues(dev);
-+
-+	mutex_unlock(&dev->lock);
-+	return 0;
-+}
-+
-+static int vidioc_querycap(struct file *file, void  *priv,
-+					struct v4l2_capability *cap)
-+{
-+	struct em28xx_fh      *fh  = priv;
-+	struct em28xx         *dev = fh->dev;
-+
-+	strlcpy(cap->driver, "em28xx", sizeof(cap->driver));
-+	strlcpy(cap->card, em28xx_boards[dev->model].name, sizeof(cap->card));
-+	strlcpy(cap->bus_info, dev->udev->dev.bus_id, sizeof(cap->bus_info));
-+
-+	cap->version = EM28XX_VERSION_CODE;
-+
-+	cap->capabilities =
-+			V4L2_CAP_SLICED_VBI_CAPTURE |
-+			V4L2_CAP_VIDEO_CAPTURE |
-+			V4L2_CAP_AUDIO |
-+			V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
-+
-+	if (dev->tuner_type != TUNER_ABSENT)
-+		cap->capabilities |= V4L2_CAP_TUNER;
-+
-+	return 0;
-+}
-+
-+static int vidioc_enum_fmt_cap(struct file *file, void  *priv,
-+					struct v4l2_fmtdesc *fmtd)
-+{
-+	if (fmtd->index != 0)
-+		return -EINVAL;
-+
-+	fmtd->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-+	strcpy(fmtd->description, "Packed YUY2");
-+	fmtd->pixelformat = V4L2_PIX_FMT_YUYV;
-+	memset(fmtd->reserved, 0, sizeof(fmtd->reserved));
-+
-+	return 0;
-+}
-+
-+/* Sliced VBI ioctls */
-+static int vidioc_g_fmt_vbi_capture(struct file *file, void *priv,
-+					struct v4l2_format *f)
-+{
-+	struct em28xx_fh      *fh  = priv;
-+	struct em28xx         *dev = fh->dev;
-+	int                   rc;
-+
-+	rc = check_dev(dev);
-+	if (rc < 0)
-+		return rc;
-+
-+	mutex_lock(&dev->lock);
-+
-+	f->fmt.sliced.service_set = 0;
-+
-+	em28xx_i2c_call_clients(dev, VIDIOC_G_FMT, f);
-+
-+	if (f->fmt.sliced.service_set == 0)
-+		rc = -EINVAL;
-+
-+	mutex_unlock(&dev->lock);
-+	return rc;
-+}
-+
-+static int vidioc_try_set_vbi_capture(struct file *file, void *priv,
-+			struct v4l2_format *f)
-+{
-+	struct em28xx_fh      *fh  = priv;
-+	struct em28xx         *dev = fh->dev;
-+	int                   rc;
-+
-+	rc = check_dev(dev);
-+	if (rc < 0)
-+		return rc;
-+
-+	mutex_lock(&dev->lock);
-+	em28xx_i2c_call_clients(dev, VIDIOC_G_FMT, f);
-+	mutex_unlock(&dev->lock);
-+
-+	if (f->fmt.sliced.service_set == 0)
-+		return -EINVAL;
-+
-+	return 0;
-+}
-+
-+
-+static int vidioc_reqbufs(struct file *file, void *priv,
-+			  struct v4l2_requestbuffers *rb)
-+{
-+	struct em28xx_fh      *fh  = priv;
-+	struct em28xx         *dev = fh->dev;
-+	u32                   i;
-+	int                   rc;
-+
-+	rc = check_dev(dev);
-+	if (rc < 0)
-+		return rc;
-+
-+	if (rb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
-+		rb->memory != V4L2_MEMORY_MMAP)
-+		return -EINVAL;
-+
-+	if (dev->io == IO_READ) {
-+		em28xx_videodbg("method is set to read;"
-+				" close and open the device again to"
-+				" choose the mmap I/O method\n");
-+		return -EINVAL;
-+	}
-+
-+	for (i = 0; i < dev->num_frames; i++)
-+		if (dev->frame[i].vma_use_count) {
-+			em28xx_videodbg("VIDIOC_REQBUFS failed; "
-+					"previous buffers are still mapped\n");
-+			return -EINVAL;
-+		}
-+
-+	mutex_lock(&dev->lock);
-+
-+	if (dev->stream == STREAM_ON) {
-+		em28xx_videodbg("VIDIOC_REQBUFS: interrupting stream\n");
-+		rc = em28xx_stream_interrupt(dev);
-+		if (rc < 0) {
-+			mutex_unlock(&dev->lock);
-+			return rc;
+-	/* Work out the lace settings */
+-	switch (itv->yuv_info.lace_mode) {
+-		case IVTV_YUV_MODE_PROGRESSIVE: /* Progressive mode */
+-			itv->yuv_info.frame_interlaced = 0;
+-			if (window->tru_h < 512 || (window->tru_h > 576 && window->tru_h < 1021))
+-				window->interlaced_y = 0;
+-			else
+-				window->interlaced_y = 1;
+-
+-			if (window->tru_h < 1021 && (window->dst_h >= window->src_h /2))
+-				window->interlaced_uv = 0;
+-			else
+-				window->interlaced_uv = 1;
+-			break;
+-
+-		case IVTV_YUV_MODE_AUTO:
+-			if (window->tru_h <= lace_threshold || window->tru_h > 576 || window->tru_w > 720){
+-				itv->yuv_info.frame_interlaced = 0;
+-				if ((window->tru_h < 512) ||
+-				  (window->tru_h > 576 && window->tru_h < 1021) ||
+-				  (window->tru_w > 720 && window->tru_h < 1021))
+-					window->interlaced_y = 0;
+-				else
+-					window->interlaced_y = 1;
+-
+-				if (window->tru_h < 1021 && (window->dst_h >= window->src_h /2))
+-					window->interlaced_uv = 0;
+-				else
+-					window->interlaced_uv = 1;
+-			}
+-			else {
+-				itv->yuv_info.frame_interlaced = 1;
+-				window->interlaced_y = 1;
+-				window->interlaced_uv = 1;
+-			}
+-			break;
+-
+-			case IVTV_YUV_MODE_INTERLACED: /* Interlace mode */
+-		default:
+-			itv->yuv_info.frame_interlaced = 1;
+-			window->interlaced_y = 1;
+-			window->interlaced_uv = 1;
+-			break;
+-	}
+-
+ 	/* Sorry, but no negative coords for src */
+-	if (window->src_x < 0) window->src_x = 0;
+-	if (window->src_y < 0) window->src_y = 0;
++	if (f->src_x < 0)
++		f->src_x = 0;
++	if (f->src_y < 0)
++		f->src_y = 0;
+ 
+ 	/* Can only reduce width down to 1/4 original size */
+-	if ((osd_crop = window->src_w - ( 4 * window->dst_w )) > 0) {
+-		window->src_x += osd_crop / 2;
+-		window->src_w = (window->src_w - osd_crop) & ~3;
+-		window->dst_w = window->src_w / 4;
+-		window->dst_w += window->dst_w & 1;
++	if ((osd_crop = f->src_w - 4 * f->dst_w) > 0) {
++		f->src_x += osd_crop / 2;
++		f->src_w = (f->src_w - osd_crop) & ~3;
++		f->dst_w = f->src_w / 4;
++		f->dst_w += f->dst_w & 1;
+ 	}
+ 
+ 	/* Can only reduce height down to 1/4 original size */
+-	if (window->src_h / window->dst_h >= 2) {
+-		/* Overflow may be because we're running progressive, so force mode switch */
+-		window->interlaced_y = 1;
++	if (f->src_h / f->dst_h >= 2) {
++		/* Overflow may be because we're running progressive,
++		   so force mode switch */
++		f->interlaced_y = 1;
+ 		/* Make sure we're still within limits for interlace */
+-		if ((osd_crop = window->src_h - ( 4 * window->dst_h )) > 0) {
++		if ((osd_crop = f->src_h - 4 * f->dst_h) > 0) {
+ 			/* If we reach here we'll have to force the height. */
+-			window->src_y += osd_crop / 2;
+-			window->src_h = (window->src_h - osd_crop) & ~3;
+-			window->dst_h = window->src_h / 4;
+-			window->dst_h += window->dst_h & 1;
++			f->src_y += osd_crop / 2;
++			f->src_h = (f->src_h - osd_crop) & ~3;
++			f->dst_h = f->src_h / 4;
++			f->dst_h += f->dst_h & 1;
  		}
--		em28xx_audio_source(dev, ainput);
  	}
+ 
+ 	/* If there's nothing to safe to display, we may as well stop now */
+-	if ((int)window->dst_w <= 2 || (int)window->dst_h <= 2 || (int)window->src_w <= 2 || (int)window->src_h <= 2) {
++	if ((int)f->dst_w <= 2 || (int)f->dst_h <= 2 ||
++	    (int)f->src_w <= 2 || (int)f->src_h <= 2) {
+ 		return IVTV_YUV_UPDATE_INVALID;
+ 	}
+ 
+ 	/* Ensure video remains inside OSD area */
+-	osd_scale = (window->src_h << 16) / window->dst_h;
++	osd_scale = (f->src_h << 16) / f->dst_h;
+ 
+-	if ((osd_crop = window->pan_y - window->dst_y) > 0) {
++	if ((osd_crop = f->pan_y - f->dst_y) > 0) {
+ 		/* Falls off the upper edge - crop */
+-		window->src_y += (osd_scale * osd_crop) >> 16;
+-		window->src_h -= (osd_scale * osd_crop) >> 16;
+-		window->dst_h -= osd_crop;
+-		window->dst_y = 0;
+-	}
+-	else {
+-		window->dst_y -= window->pan_y;
++		f->src_y += (osd_scale * osd_crop) >> 16;
++		f->src_h -= (osd_scale * osd_crop) >> 16;
++		f->dst_h -= osd_crop;
++		f->dst_y = 0;
++	} else {
++		f->dst_y -= f->pan_y;
+ 	}
+ 
+-	if ((osd_crop = window->dst_h + window->dst_y - window->vis_h) > 0) {
++	if ((osd_crop = f->dst_h + f->dst_y - f->vis_h) > 0) {
+ 		/* Falls off the lower edge - crop */
+-		window->dst_h -= osd_crop;
+-		window->src_h -= (osd_scale * osd_crop) >> 16;
++		f->dst_h -= osd_crop;
++		f->src_h -= (osd_scale * osd_crop) >> 16;
+ 	}
+ 
+-	osd_scale = (window->src_w << 16) / window->dst_w;
++	osd_scale = (f->src_w << 16) / f->dst_w;
+ 
+-	if ((osd_crop = window->pan_x - window->dst_x) > 0) {
++	if ((osd_crop = f->pan_x - f->dst_x) > 0) {
+ 		/* Fall off the left edge - crop */
+-		window->src_x += (osd_scale * osd_crop) >> 16;
+-		window->src_w -= (osd_scale * osd_crop) >> 16;
+-		window->dst_w -= osd_crop;
+-		window->dst_x = 0;
+-	}
+-	else {
+-		window->dst_x -= window->pan_x;
++		f->src_x += (osd_scale * osd_crop) >> 16;
++		f->src_w -= (osd_scale * osd_crop) >> 16;
++		f->dst_w -= osd_crop;
++		f->dst_x = 0;
++	} else {
++		f->dst_x -= f->pan_x;
+ 	}
+ 
+-	if ((osd_crop = window->dst_w + window->dst_x - window->vis_w) > 0) {
++	if ((osd_crop = f->dst_w + f->dst_x - f->vis_w) > 0) {
+ 		/* Falls off the right edge - crop */
+-		window->dst_w -= osd_crop;
+-		window->src_w -= (osd_scale * osd_crop) >> 16;
++		f->dst_w -= osd_crop;
++		f->src_w -= (osd_scale * osd_crop) >> 16;
+ 	}
+ 
+ 	/* The OSD can be moved. Track to it */
+-	window->dst_x += itv->yuv_info.osd_x_offset;
+-	window->dst_y += itv->yuv_info.osd_y_offset;
++	f->dst_x += itv->yuv_info.osd_x_offset;
++	f->dst_y += itv->yuv_info.osd_y_offset;
+ 
+ 	/* Width & height for both src & dst must be even.
+ 	   Same for coordinates. */
+-	window->dst_w &= ~1;
+-	window->dst_x &= ~1;
++	f->dst_w &= ~1;
++	f->dst_x &= ~1;
+ 
+-	window->src_w += window->src_x & 1;
+-	window->src_x &= ~1;
++	f->src_w += f->src_x & 1;
++	f->src_x &= ~1;
+ 
+-	window->src_w &= ~1;
+-	window->dst_w &= ~1;
++	f->src_w &= ~1;
++	f->dst_w &= ~1;
+ 
+-	window->dst_h &= ~1;
+-	window->dst_y &= ~1;
++	f->dst_h &= ~1;
++	f->dst_y &= ~1;
+ 
+-	window->src_h += window->src_y & 1;
+-	window->src_y &= ~1;
++	f->src_h += f->src_y & 1;
++	f->src_y &= ~1;
+ 
+-	window->src_h &= ~1;
+-	window->dst_h &= ~1;
++	f->src_h &= ~1;
++	f->dst_h &= ~1;
+ 
+-	/* Due to rounding, we may have reduced the output size to <1/4 of the source
+-	   Check again, but this time just resize. Don't change source coordinates */
+-	if (window->dst_w < window->src_w / 4) {
+-		window->src_w &= ~3;
+-		window->dst_w = window->src_w / 4;
+-		window->dst_w += window->dst_w & 1;
++	/* Due to rounding, we may have reduced the output size to <1/4 of
++	   the source. Check again, but this time just resize. Don't change
++	   source coordinates */
++	if (f->dst_w < f->src_w / 4) {
++		f->src_w &= ~3;
++		f->dst_w = f->src_w / 4;
++		f->dst_w += f->dst_w & 1;
+ 	}
+-	if (window->dst_h < window->src_h / 4) {
+-		window->src_h &= ~3;
+-		window->dst_h = window->src_h / 4;
+-		window->dst_h += window->dst_h & 1;
++	if (f->dst_h < f->src_h / 4) {
++		f->src_h &= ~3;
++		f->dst_h = f->src_h / 4;
++		f->dst_h += f->dst_h & 1;
+ 	}
+ 
+ 	/* Check again. If there's nothing to safe to display, stop now */
+-	if ((int)window->dst_w <= 2 || (int)window->dst_h <= 2 || (int)window->src_w <= 2 || (int)window->src_h <= 2) {
++	if ((int)f->dst_w <= 2 || (int)f->dst_h <= 2 ||
++	    (int)f->src_w <= 2 || (int)f->src_h <= 2) {
+ 		return IVTV_YUV_UPDATE_INVALID;
+ 	}
+ 
+ 	/* Both x offset & width are linked, so they have to be done together */
+-	if ((itv->yuv_info.old_frame_info.dst_w != window->dst_w) ||
+-	    (itv->yuv_info.old_frame_info.src_w != window->src_w) ||
+-	    (itv->yuv_info.old_frame_info.dst_x != window->dst_x) ||
+-	    (itv->yuv_info.old_frame_info.src_x != window->src_x) ||
+-	    (itv->yuv_info.old_frame_info.pan_x != window->pan_x) ||
+-	    (itv->yuv_info.old_frame_info.vis_w != window->vis_w)) {
++	if ((of->dst_w != f->dst_w) || (of->src_w != f->src_w) ||
++	    (of->dst_x != f->dst_x) || (of->src_x != f->src_x) ||
++	    (of->pan_x != f->pan_x) || (of->vis_w != f->vis_w)) {
+ 		yuv_update |= IVTV_YUV_UPDATE_HORIZONTAL;
+ 	}
+ 
+-	if ((itv->yuv_info.old_frame_info.src_h != window->src_h) ||
+-	    (itv->yuv_info.old_frame_info.dst_h != window->dst_h) ||
+-	    (itv->yuv_info.old_frame_info.dst_y != window->dst_y) ||
+-	    (itv->yuv_info.old_frame_info.src_y != window->src_y) ||
+-	    (itv->yuv_info.old_frame_info.pan_y != window->pan_y) ||
+-	    (itv->yuv_info.old_frame_info.vis_h != window->vis_h) ||
+-	    (itv->yuv_info.old_frame_info.lace_mode != window->lace_mode) ||
+-	    (itv->yuv_info.old_frame_info.interlaced_y != window->interlaced_y) ||
+-	    (itv->yuv_info.old_frame_info.interlaced_uv != window->interlaced_uv)) {
++	if ((of->src_h != f->src_h) || (of->dst_h != f->dst_h) ||
++	    (of->dst_y != f->dst_y) || (of->src_y != f->src_y) ||
++	    (of->pan_y != f->pan_y) || (of->vis_h != f->vis_h) ||
++	    (of->lace_mode != f->lace_mode) ||
++	    (of->interlaced_y != f->interlaced_y) ||
++	    (of->interlaced_uv != f->interlaced_uv)) {
+ 		yuv_update |= IVTV_YUV_UPDATE_VERTICAL;
+ 	}
+ 
+@@ -820,24 +782,24 @@ static u32 ivtv_yuv_window_setup (struct ivtv *itv, struct yuv_frame_info *windo
+ }
+ 
+ /* Update the scaling register to the requested value */
+-void ivtv_yuv_work_handler (struct ivtv *itv)
++void ivtv_yuv_work_handler(struct ivtv *itv)
+ {
+-	struct yuv_frame_info window;
++	struct yuv_playback_info *yi = &itv->yuv_info;
++	struct yuv_frame_info f;
++	int frame = yi->update_frame;
+ 	u32 yuv_update;
+ 
+-	int frame = itv->yuv_info.update_frame;
+-
+-/*	IVTV_DEBUG_YUV("Update yuv registers for frame %d\n",frame); */
+-	memcpy(&window, &itv->yuv_info.new_frame_info[frame], sizeof (window));
++	IVTV_DEBUG_YUV("Update yuv registers for frame %d\n", frame);
++	f = yi->new_frame_info[frame];
+ 
+ 	/* Update the osd pan info */
+-	window.pan_x = itv->yuv_info.osd_x_pan;
+-	window.pan_y = itv->yuv_info.osd_y_pan;
+-	window.vis_w = itv->yuv_info.osd_vis_w;
+-	window.vis_h = itv->yuv_info.osd_vis_h;
++	f.pan_x = yi->osd_x_pan;
++	f.pan_y = yi->osd_y_pan;
++	f.vis_w = yi->osd_vis_w;
++	f.vis_h = yi->osd_vis_h;
+ 
+ 	/* Calculate the display window coordinates. Exit if nothing left */
+-	if (!(yuv_update = ivtv_yuv_window_setup (itv, &window)))
++	if (!(yuv_update = ivtv_yuv_window_setup(itv, &f)))
+ 		return;
+ 
+ 	if (yuv_update & IVTV_YUV_UPDATE_INVALID) {
+@@ -846,16 +808,15 @@ void ivtv_yuv_work_handler (struct ivtv *itv)
+ 		write_reg(0x00108080, 0x2898);
+ 
+ 		if (yuv_update & IVTV_YUV_UPDATE_HORIZONTAL)
+-			ivtv_yuv_handle_horizontal(itv, &window);
++			ivtv_yuv_handle_horizontal(itv, &f);
+ 
+ 		if (yuv_update & IVTV_YUV_UPDATE_VERTICAL)
+-			ivtv_yuv_handle_vertical(itv, &window);
++			ivtv_yuv_handle_vertical(itv, &f);
+ 	}
+-
+-	memcpy(&itv->yuv_info.old_frame_info, &window, sizeof (itv->yuv_info.old_frame_info));
++	yi->old_frame_info = f;
+ }
+ 
+-static void ivtv_yuv_init (struct ivtv *itv)
++static void ivtv_yuv_init(struct ivtv *itv)
+ {
+ 	struct yuv_playback_info *yi = &itv->yuv_info;
+ 
+@@ -924,25 +885,23 @@ static void ivtv_yuv_init (struct ivtv *itv)
+ 		if (!yi->osd_vis_w)
+ 			yi->osd_vis_w = 720 - yi->osd_x_offset;
+ 
+-		if (!yi->osd_vis_h)
++		if (!yi->osd_vis_h) {
+ 			yi->osd_vis_h = yi->decode_height - yi->osd_y_offset;
+-		else {
++		} else if (yi->osd_vis_h + yi->osd_y_offset > yi->decode_height) {
+ 			/* If output video standard has changed, requested height may
+-			not be legal */
+-			if (yi->osd_vis_h + yi->osd_y_offset > yi->decode_height) {
+-				IVTV_DEBUG_WARN("Clipping yuv output - fb size (%d) exceeds video standard limit (%d)\n",
+-						yi->osd_vis_h + yi->osd_y_offset,
+-						yi->decode_height);
+-				yi->osd_vis_h = yi->decode_height - yi->osd_y_offset;
+-			}
++			   not be legal */
++			IVTV_DEBUG_WARN("Clipping yuv output - fb size (%d) exceeds video standard limit (%d)\n",
++					yi->osd_vis_h + yi->osd_y_offset,
++					yi->decode_height);
++			yi->osd_vis_h = yi->decode_height - yi->osd_y_offset;
+ 		}
+ 	}
+ 
+ 	/* We need a buffer for blanking when Y plane is offset - non-fatal if we can't get one */
+-	yi->blanking_ptr = kzalloc(720*16, GFP_KERNEL);
+-	if (yi->blanking_ptr)
++	yi->blanking_ptr = kzalloc(720 * 16, GFP_KERNEL);
++	if (yi->blanking_ptr) {
+ 		yi->blanking_dmaptr = pci_map_single(itv->dev, yi->blanking_ptr, 720*16, PCI_DMA_TODEVICE);
+-	else {
++	} else {
+ 		yi->blanking_dmaptr = 0;
+ 		IVTV_DEBUG_WARN("Failed to allocate yuv blanking buffer\n");
+ 	}
+@@ -954,77 +913,140 @@ static void ivtv_yuv_init (struct ivtv *itv)
+ 	atomic_set(&yi->next_dma_frame, 0);
+ }
+ 
+-int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args)
++/* Get next available yuv buffer on PVR350 */
++void ivtv_yuv_next_free(struct ivtv *itv)
+ {
+-	DEFINE_WAIT(wait);
+-	int rc = 0;
+-	int got_sig = 0;
+-	int frame, next_fill_frame, last_fill_frame;
+-	int register_update = 0;
++	int draw, display;
++	struct yuv_playback_info *yi = &itv->yuv_info;
+ 
+-	IVTV_DEBUG_INFO("yuv_prep_frame\n");
++	if (atomic_read(&yi->next_dma_frame) == -1)
++		ivtv_yuv_init(itv);
+ 
+-	if (atomic_read(&itv->yuv_info.next_dma_frame) == -1) ivtv_yuv_init(itv);
++	draw = atomic_read(&yi->next_fill_frame);
++	display = atomic_read(&yi->next_dma_frame);
+ 
+-	frame = atomic_read(&itv->yuv_info.next_fill_frame);
+-	next_fill_frame = (frame + 1) & 0x3;
+-	last_fill_frame = (atomic_read(&itv->yuv_info.next_dma_frame)+1) & 0x3;
++	if (display > draw)
++		display -= IVTV_YUV_BUFFERS;
+ 
+-	if (next_fill_frame != last_fill_frame && last_fill_frame != frame) {
+-		/* Buffers are full - Overwrite the last frame */
+-		next_fill_frame = frame;
+-		frame = (frame - 1) & 3;
+-		register_update = itv->yuv_info.new_frame_info[frame].update;
+-	}
++	if (draw - display >= yi->max_frames_buffered)
++		draw = (u8)(draw - 1) % IVTV_YUV_BUFFERS;
++	else
++		yi->new_frame_info[draw].update = 0;
 +
-+	em28xx_empty_framequeues(dev);
-+
-+	em28xx_release_buffers(dev);
-+	if (rb->count)
-+		rb->count = em28xx_request_buffers(dev, rb->count);
-+
-+	dev->frame_current = NULL;
-+	dev->io = rb->count ? IO_MMAP : IO_NONE;
-+
-+	mutex_unlock(&dev->lock);
-+	return 0;
-+}
-+
-+static int vidioc_querybuf(struct file *file, void *priv,
-+			   struct v4l2_buffer *b)
-+{
-+	struct em28xx_fh      *fh  = priv;
-+	struct em28xx         *dev = fh->dev;
-+	int                   rc;
-+
-+	rc = check_dev(dev);
-+	if (rc < 0)
-+		return rc;
-+
-+	if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
-+		b->index >= dev->num_frames || dev->io != IO_MMAP)
-+		return -EINVAL;
-+
-+	mutex_lock(&dev->lock);
-+
-+	memcpy(b, &dev->frame[b->index].buf, sizeof(*b));
-+
-+	if (dev->frame[b->index].vma_use_count)
-+		b->flags |= V4L2_BUF_FLAG_MAPPED;
-+
-+	if (dev->frame[b->index].state == F_DONE)
-+		b->flags |= V4L2_BUF_FLAG_DONE;
-+	else if (dev->frame[b->index].state != F_UNUSED)
-+		b->flags |= V4L2_BUF_FLAG_QUEUED;
-+
-+	mutex_unlock(&dev->lock);
-+	return 0;
++	yi->draw_frame = draw;
 +}
 +
-+static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
++/* Set up frame according to ivtv_dma_frame parameters */
++void ivtv_yuv_setup_frame(struct ivtv *itv, struct ivtv_dma_frame *args)
 +{
-+	struct em28xx_fh      *fh  = priv;
-+	struct em28xx         *dev = fh->dev;
-+	unsigned long         lock_flags;
-+	int                   rc;
-+
-+	rc = check_dev(dev);
-+	if (rc < 0)
-+		return rc;
-+
-+	if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE  || dev->io != IO_MMAP ||
-+						b->index >= dev->num_frames)
-+		return -EINVAL;
-+
-+	if (dev->frame[b->index].state != F_UNUSED)
-+		return -EAGAIN;
-+
-+	dev->frame[b->index].state = F_QUEUED;
-+
-+	/* add frame to fifo */
-+	spin_lock_irqsave(&dev->queue_lock, lock_flags);
-+	list_add_tail(&dev->frame[b->index].frame, &dev->inqueue);
-+	spin_unlock_irqrestore(&dev->queue_lock, lock_flags);
-+
-+	return 0;
-+}
++	struct yuv_playback_info *yi = &itv->yuv_info;
++	u8 frame = yi->draw_frame;
++	u8 last_frame = (u8)(frame - 1) % IVTV_YUV_BUFFERS;
++	struct yuv_frame_info *nf = &yi->new_frame_info[frame];
++	struct yuv_frame_info *of = &yi->new_frame_info[last_frame];
++	int lace_threshold = yi->lace_threshold;
 +
-+static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
-+{
-+	struct em28xx_fh      *fh  = priv;
-+	struct em28xx         *dev = fh->dev;
-+	int                   rc;
-+	struct em28xx_frame_t *f;
-+	unsigned long         lock_flags;
++	/* Preserve old update flag in case we're overwriting a queued frame */
++	int update = nf->update;
+ 
+ 	/* Take a snapshot of the yuv coordinate information */
+-	itv->yuv_info.new_frame_info[frame].src_x = args->src.left;
+-	itv->yuv_info.new_frame_info[frame].src_y = args->src.top;
+-	itv->yuv_info.new_frame_info[frame].src_w = args->src.width;
+-	itv->yuv_info.new_frame_info[frame].src_h = args->src.height;
+-	itv->yuv_info.new_frame_info[frame].dst_x = args->dst.left;
+-	itv->yuv_info.new_frame_info[frame].dst_y = args->dst.top;
+-	itv->yuv_info.new_frame_info[frame].dst_w = args->dst.width;
+-	itv->yuv_info.new_frame_info[frame].dst_h = args->dst.height;
+-	itv->yuv_info.new_frame_info[frame].tru_x = args->dst.left;
+-	itv->yuv_info.new_frame_info[frame].tru_w = args->src_width;
+-	itv->yuv_info.new_frame_info[frame].tru_h = args->src_height;
+-
+-	/* Snapshot field order */
+-	itv->yuv_info.sync_field[frame] = itv->yuv_info.lace_sync_field;
++	nf->src_x = args->src.left;
++	nf->src_y = args->src.top;
++	nf->src_w = args->src.width;
++	nf->src_h = args->src.height;
++	nf->dst_x = args->dst.left;
++	nf->dst_y = args->dst.top;
++	nf->dst_w = args->dst.width;
++	nf->dst_h = args->dst.height;
++	nf->tru_x = args->dst.left;
++	nf->tru_w = args->src_width;
++	nf->tru_h = args->src_height;
+ 
+ 	/* Are we going to offset the Y plane */
+-	if (args->src.height + args->src.top < 512-16)
+-		itv->yuv_info.new_frame_info[frame].offset_y = 1;
+-	else
+-		itv->yuv_info.new_frame_info[frame].offset_y = 0;
++	nf->offset_y = (nf->tru_h + nf->src_x < 512 - 16) ? 1 : 0;
+ 
+ 	/* Snapshot the osd pan info */
+-	itv->yuv_info.new_frame_info[frame].pan_x = itv->yuv_info.osd_x_pan;
+-	itv->yuv_info.new_frame_info[frame].pan_y = itv->yuv_info.osd_y_pan;
+-	itv->yuv_info.new_frame_info[frame].vis_w = itv->yuv_info.osd_vis_w;
+-	itv->yuv_info.new_frame_info[frame].vis_h = itv->yuv_info.osd_vis_h;
+-
+-	itv->yuv_info.new_frame_info[frame].update = 0;
+-	itv->yuv_info.new_frame_info[frame].interlaced_y = 0;
+-	itv->yuv_info.new_frame_info[frame].interlaced_uv = 0;
+-	itv->yuv_info.new_frame_info[frame].lace_mode = itv->yuv_info.lace_mode;
+-
+-	if (memcmp (&itv->yuv_info.old_frame_info_args, &itv->yuv_info.new_frame_info[frame],
+-	    sizeof (itv->yuv_info.new_frame_info[frame]))) {
+-		memcpy(&itv->yuv_info.old_frame_info_args, &itv->yuv_info.new_frame_info[frame], sizeof (itv->yuv_info.old_frame_info_args));
+-		itv->yuv_info.new_frame_info[frame].update = 1;
+-/*		IVTV_DEBUG_YUV ("Requesting register update for frame %d\n",frame); */
++	nf->pan_x = yi->osd_x_pan;
++	nf->pan_y = yi->osd_y_pan;
++	nf->vis_w = yi->osd_vis_w;
++	nf->vis_h = yi->osd_vis_h;
 +
-+	rc = check_dev(dev);
-+	if (rc < 0)
-+		return rc;
++	nf->update = 0;
++	nf->interlaced_y = 0;
++	nf->interlaced_uv = 0;
++	nf->delay = 0;
++	nf->sync_field = 0;
++	nf->lace_mode = yi->lace_mode & IVTV_YUV_MODE_MASK;
 +
-+	if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || dev->io != IO_MMAP)
-+		return -EINVAL;
++	if (lace_threshold < 0)
++		lace_threshold = yi->decode_height - 1;
 +
-+	if (list_empty(&dev->outqueue)) {
-+		if (dev->stream == STREAM_OFF)
-+			return -EINVAL;
++	/* Work out the lace settings */
++	switch (nf->lace_mode) {
++	case IVTV_YUV_MODE_PROGRESSIVE: /* Progressive mode */
++		nf->interlaced = 0;
++		if (nf->tru_h < 512 || (nf->tru_h > 576 && nf->tru_h < 1021))
++			nf->interlaced_y = 0;
++		else
++			nf->interlaced_y = 1;
 +
-+		if (file->f_flags & O_NONBLOCK)
-+			return -EAGAIN;
++		if (nf->tru_h < 1021 && (nf->dst_h >= nf->src_h / 2))
++			nf->interlaced_uv = 0;
++		else
++			nf->interlaced_uv = 1;
++		break;
 +
-+		rc = wait_event_interruptible(dev->wait_frame,
-+					(!list_empty(&dev->outqueue)) ||
-+					(dev->state & DEV_DISCONNECTED));
-+		if (rc)
-+			return rc;
++	case IVTV_YUV_MODE_AUTO:
++		if (nf->tru_h <= lace_threshold || nf->tru_h > 576 || nf->tru_w > 720) {
++			nf->interlaced = 0;
++			if ((nf->tru_h < 512) ||
++			    (nf->tru_h > 576 && nf->tru_h < 1021) ||
++			    (nf->tru_w > 720 && nf->tru_h < 1021))
++				nf->interlaced_y = 0;
++			else
++				nf->interlaced_y = 1;
++			if (nf->tru_h < 1021 && (nf->dst_h >= nf->src_h / 2))
++				nf->interlaced_uv = 0;
++			else
++				nf->interlaced_uv = 1;
++		} else {
++			nf->interlaced = 1;
++			nf->interlaced_y = 1;
++			nf->interlaced_uv = 1;
++		}
++		break;
 +
-+		if (dev->state & DEV_DISCONNECTED)
-+			return -ENODEV;
++	case IVTV_YUV_MODE_INTERLACED: /* Interlace mode */
++	default:
++		nf->interlaced = 1;
++		nf->interlaced_y = 1;
++		nf->interlaced_uv = 1;
++		break;
+ 	}
+ 
+-	itv->yuv_info.new_frame_info[frame].update |= register_update;
++	if (memcmp(&yi->old_frame_info_args, nf, sizeof(*nf))) {
++		yi->old_frame_info_args = *nf;
++		nf->update = 1;
++		IVTV_DEBUG_YUV("Requesting reg update for frame %d\n", frame);
 +	}
-+
-+	spin_lock_irqsave(&dev->queue_lock, lock_flags);
-+	f = list_entry(dev->outqueue.next, struct em28xx_frame_t, frame);
-+	list_del(dev->outqueue.next);
-+	spin_unlock_irqrestore(&dev->queue_lock, lock_flags);
-+
-+	f->state = F_UNUSED;
-+	memcpy(b, &f->buf, sizeof(*b));
-+
-+	if (f->vma_use_count)
-+		b->flags |= V4L2_BUF_FLAG_MAPPED;
-+
-+	return 0;
+ 
+-	/* Should this frame be delayed ? */
+-	if (itv->yuv_info.sync_field[frame] != itv->yuv_info.sync_field[(frame - 1) & 3])
+-		itv->yuv_info.field_delay[frame] = 1;
+-	else
+-		itv->yuv_info.field_delay[frame] = 0;
++	nf->update |= update;
++	nf->sync_field = yi->lace_sync_field;
++	nf->delay = nf->sync_field != of->sync_field;
 +}
-+
-+/* ----------------------------------------------------------- */
-+/* RADIO ESPECIFIC IOCTLS                                      */
-+/* ----------------------------------------------------------- */
-+
-+static int radio_querycap(struct file *file, void  *priv,
-+			  struct v4l2_capability *cap)
+ 
++/* Frame is complete & ready for display */
++void ivtv_yuv_frame_complete(struct ivtv *itv)
 +{
-+	struct em28xx *dev = ((struct em28xx_fh *)priv)->dev;
-+
-+	strlcpy(cap->driver, "em28xx", sizeof(cap->driver));
-+	strlcpy(cap->card, em28xx_boards[dev->model].name, sizeof(cap->card));
-+	strlcpy(cap->bus_info, dev->udev->dev.bus_id, sizeof(cap->bus_info));
-+
-+	cap->version = EM28XX_VERSION_CODE;
-+	cap->capabilities = V4L2_CAP_TUNER;
-+	return 0;
++	atomic_set(&itv->yuv_info.next_fill_frame,
++			(itv->yuv_info.draw_frame + 1) % IVTV_YUV_BUFFERS);
 +}
 +
-+static int radio_g_tuner(struct file *file, void *priv,
-+			 struct v4l2_tuner *t)
++int ivtv_yuv_udma_frame(struct ivtv *itv, struct ivtv_dma_frame *args)
 +{
-+	struct em28xx *dev = ((struct em28xx_fh *)priv)->dev;
-+
-+	if (unlikely(t->index > 0))
-+		return -EINVAL;
-+
-+	strcpy(t->name, "Radio");
-+	t->type = V4L2_TUNER_RADIO;
-+
-+	em28xx_i2c_call_clients(dev, VIDIOC_G_TUNER, t);
-+	return 0;
-+}
-+
-+static int radio_enum_input(struct file *file, void *priv,
-+			    struct v4l2_input *i)
++	DEFINE_WAIT(wait);
++	int rc = 0;
++	int got_sig = 0;
+ 	/* DMA the frame */
+ 	mutex_lock(&itv->udma.lock);
+ 
+@@ -1036,10 +1058,10 @@ int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args)
+ 	ivtv_udma_prepare(itv);
+ 	prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE);
+ 	/* if no UDMA is pending and no UDMA is in progress, then the DMA
+-	is finished */
++	   is finished */
+ 	while (itv->i_flags & (IVTV_F_I_UDMA_PENDING | IVTV_F_I_UDMA)) {
+ 		/* don't interrupt if the DMA is in progress but break off
+-		a still pending DMA. */
++		   a still pending DMA. */
+ 		got_sig = signal_pending(current);
+ 		if (got_sig && test_and_clear_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags))
+ 			break;
+@@ -1057,99 +1079,148 @@ int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args)
+ 		return -EINTR;
+ 	}
+ 
+-	atomic_set(&itv->yuv_info.next_fill_frame, next_fill_frame);
++	ivtv_yuv_frame_complete(itv);
+ 
+ 	mutex_unlock(&itv->udma.lock);
+ 	return rc;
+ }
+ 
++/* Setup frame according to V4L2 parameters */
++void ivtv_yuv_setup_stream_frame(struct ivtv *itv)
 +{
-+	if (i->index != 0)
-+		return -EINVAL;
-+	strcpy(i->name, "Radio");
-+	i->type = V4L2_INPUT_TYPE_TUNER;
++	struct yuv_playback_info *yi = &itv->yuv_info;
++	struct ivtv_dma_frame dma_args;
 +
-+	return 0;
-+}
++	ivtv_yuv_next_free(itv);
 +
-+static int radio_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
-+{
-+	if (unlikely(a->index))
-+		return -EINVAL;
++	/* Copy V4L2 parameters to an ivtv_dma_frame struct... */
++	dma_args.y_source = 0L;
++	dma_args.uv_source = 0L;
++	dma_args.src.left = 0;
++	dma_args.src.top = 0;
++	dma_args.src.width = yi->v4l2_src_w;
++	dma_args.src.height = yi->v4l2_src_h;
++	dma_args.dst = yi->main_rect;
++	dma_args.src_width = yi->v4l2_src_w;
++	dma_args.src_height = yi->v4l2_src_h;
 +
-+	strcpy(a->name, "Radio");
-+	return 0;
++	/* ... and use the same setup routine as ivtv_yuv_prep_frame */
++	ivtv_yuv_setup_frame(itv, &dma_args);
++
++	if (!itv->dma_data_req_offset)
++		itv->dma_data_req_offset = yuv_offset[yi->draw_frame];
 +}
 +
-+static int radio_s_tuner(struct file *file, void *priv,
-+			 struct v4l2_tuner *t)
++/* Attempt to dma a frame from a user buffer */
++int ivtv_yuv_udma_stream_frame(struct ivtv *itv, void *src)
 +{
-+	struct em28xx *dev = ((struct em28xx_fh *)priv)->dev;
-+
-+	if (0 != t->index)
-+		return -EINVAL;
++	struct yuv_playback_info *yi = &itv->yuv_info;
++	struct ivtv_dma_frame dma_args;
 +
-+	em28xx_i2c_call_clients(dev, VIDIOC_S_TUNER, t);
++	ivtv_yuv_setup_stream_frame(itv);
 +
-+	return 0;
++	/* We only need to supply source addresses for this */
++	dma_args.y_source = src;
++	dma_args.uv_source = src + 720 * ((yi->v4l2_src_h + 31) & ~31);
++	return ivtv_yuv_udma_frame(itv, &dma_args);
 +}
 +
-+static int radio_s_audio(struct file *file, void *fh,
-+			 struct v4l2_audio *a)
++/* IVTV_IOC_DMA_FRAME ioctl handler */
++int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args)
 +{
-+	return 0;
-+}
++/*	IVTV_DEBUG_INFO("yuv_prep_frame\n"); */
 +
-+static int radio_s_input(struct file *file, void *fh, unsigned int i)
-+{
-+	return 0;
++	ivtv_yuv_next_free(itv);
++	ivtv_yuv_setup_frame(itv, args);
++	return ivtv_yuv_udma_frame(itv, args);
 +}
 +
-+static int radio_queryctrl(struct file *file, void *priv,
-+			   struct v4l2_queryctrl *qc)
-+{
-+	int i;
-+
-+	if (qc->id <  V4L2_CID_BASE ||
-+		qc->id >= V4L2_CID_LASTP1)
-+		return -EINVAL;
-+
-+	for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) {
-+		if (qc->id && qc->id == em28xx_qctrl[i].id) {
-+			memcpy(qc, &(em28xx_qctrl[i]), sizeof(*qc));
-+			return 0;
-+		}
-+	}
-+
-+	return -EINVAL;
- }
- 
- /*
-@@ -252,8 +1258,9 @@ static void video_mux(struct em28xx *dev, int index)
- static int em28xx_v4l2_open(struct inode *inode, struct file *filp)
+ void ivtv_yuv_close(struct ivtv *itv)
  {
- 	int minor = iminor(inode);
--	int errCode = 0;
-+	int errCode = 0, radio = 0;
- 	struct em28xx *h,*dev = NULL;
-+	struct em28xx_fh *fh;
- 
- 	list_for_each_entry(h, &em28xx_devlist, devlist) {
- 		if (h->vdev->minor == minor) {
-@@ -264,6 +1271,11 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp)
- 			dev  = h;
- 			dev->type = V4L2_BUF_TYPE_VBI_CAPTURE;
- 		}
-+		if (h->radio_dev &&
-+		    h->radio_dev->minor == minor) {
-+			radio = 1;
-+			dev   = h;
-+		}
- 	}
- 	if (NULL == dev)
- 		return -ENODEV;
-@@ -271,23 +1283,18 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp)
- 	em28xx_videodbg("open minor=%d type=%s users=%d\n",
- 				minor,v4l2_type_names[dev->type],dev->users);
- 
--	if (!down_read_trylock(&em28xx_disconnect))
--		return -ERESTARTSYS;
-+	fh = kzalloc(sizeof(struct em28xx_fh), GFP_KERNEL);
- 
--	if (dev->users) {
--		em28xx_warn("this driver can be opened only once\n");
--		up_read(&em28xx_disconnect);
--		return -EBUSY;
-+	if (!fh) {
-+		em28xx_errdev("em28xx-video.c: Out of memory?!\n");
-+		return -ENOMEM;
- 	}
--
--	mutex_init(&dev->fileop_lock);	/* to 1 == available */
--	spin_lock_init(&dev->queue_lock);
--	init_waitqueue_head(&dev->wait_frame);
--	init_waitqueue_head(&dev->wait_stream);
--
- 	mutex_lock(&dev->lock);
-+	fh->dev = dev;
-+	fh->radio = radio;
-+	filp->private_data = fh;
- 
--	if (dev->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-+	if (dev->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && dev->users == 0) {
- 		em28xx_set_alternate(dev);
- 
- 		dev->width = norm_maxw(dev);
-@@ -301,30 +1308,23 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp)
- 		em28xx_capture_start(dev, 1);
- 		em28xx_resolution_set(dev);
++	struct yuv_playback_info *yi = &itv->yuv_info;
+ 	int h_filter, v_filter_1, v_filter_2;
  
--		/* device needs to be initialized before isoc transfer */
--		video_mux(dev, 0);
+ 	IVTV_DEBUG_YUV("ivtv_yuv_close\n");
+ 	ivtv_waitq(&itv->vsync_waitq);
  
- 		/* start the transfer */
- 		errCode = em28xx_init_isoc(dev);
- 		if (errCode)
- 			goto err;
+-	atomic_set(&itv->yuv_info.next_dma_frame, -1);
+-	atomic_set(&itv->yuv_info.next_fill_frame, 0);
++	atomic_set(&yi->next_dma_frame, -1);
++	atomic_set(&yi->next_fill_frame, 0);
  
-+		em28xx_empty_framequeues(dev);
-+	}
-+	if (fh->radio) {
-+		em28xx_videodbg("video_open: setting radio device\n");
-+		em28xx_i2c_call_clients(dev, AUDC_SET_RADIO, NULL);
- 	}
+ 	/* Reset registers we have changed so mpeg playback works */
  
- 	dev->users++;
--	filp->private_data = dev;
--	dev->io = IO_NONE;
--	dev->stream = STREAM_OFF;
--	dev->num_frames = 0;
--
--	/* prepare queues */
--	em28xx_empty_framequeues(dev);
+ 	/* If we fully restore this register, the display may remain active.
+ 	   Restore, but set one bit to blank the video. Firmware will always
+ 	   clear this bit when needed, so not a problem. */
+-	write_reg(itv->yuv_info.reg_2898 | 0x01000000, 0x2898);
 -
--	dev->state |= DEV_INITIALIZED;
- 
- err:
- 	mutex_unlock(&dev->lock);
--	up_read(&em28xx_disconnect);
- 	return errCode;
- }
- 
-@@ -335,7 +1335,6 @@ err:
- */
- static void em28xx_release_resources(struct em28xx *dev)
- {
--	mutex_lock(&em28xx_sysfs_lock);
- 
- 	/*FIXME: I2C IR should be disconnected */
- 
-@@ -343,12 +1342,29 @@ static void em28xx_release_resources(struct em28xx *dev)
- 				dev->vdev->minor-MINOR_VFL_TYPE_GRABBER_MIN,
- 				dev->vbi_dev->minor-MINOR_VFL_TYPE_VBI_MIN);
- 	list_del(&dev->devlist);
--	video_unregister_device(dev->vdev);
--	video_unregister_device(dev->vbi_dev);
-+	if (dev->radio_dev) {
-+		if (-1 != dev->radio_dev->minor)
-+			video_unregister_device(dev->radio_dev);
-+		else
-+			video_device_release(dev->radio_dev);
-+		dev->radio_dev = NULL;
-+	}
-+	if (dev->vbi_dev) {
-+		if (-1 != dev->vbi_dev->minor)
-+			video_unregister_device(dev->vbi_dev);
-+		else
-+			video_device_release(dev->vbi_dev);
-+		dev->vbi_dev = NULL;
-+	}
-+	if (dev->vdev) {
-+		if (-1 != dev->vdev->minor)
-+			video_unregister_device(dev->vdev);
-+		else
-+			video_device_release(dev->vdev);
-+		dev->vdev = NULL;
-+	}
- 	em28xx_i2c_unregister(dev);
- 	usb_put_dev(dev->udev);
--	mutex_unlock(&em28xx_sysfs_lock);
+-	write_reg(itv->yuv_info.reg_2834, 0x02834);
+-	write_reg(itv->yuv_info.reg_2838, 0x02838);
+-	write_reg(itv->yuv_info.reg_283c, 0x0283c);
+-	write_reg(itv->yuv_info.reg_2840, 0x02840);
+-	write_reg(itv->yuv_info.reg_2844, 0x02844);
+-	write_reg(itv->yuv_info.reg_2848, 0x02848);
+-	write_reg(itv->yuv_info.reg_2854, 0x02854);
+-	write_reg(itv->yuv_info.reg_285c, 0x0285c);
+-	write_reg(itv->yuv_info.reg_2864, 0x02864);
+-	write_reg(itv->yuv_info.reg_2870, 0x02870);
+-	write_reg(itv->yuv_info.reg_2874, 0x02874);
+-	write_reg(itv->yuv_info.reg_2890, 0x02890);
+-	write_reg(itv->yuv_info.reg_289c, 0x0289c);
 -
- 
- 	/* Mark device as unused */
- 	em28xx_devused&=~(1<<dev->devno);
-@@ -360,34 +1376,42 @@ static void em28xx_release_resources(struct em28xx *dev)
-  */
- static int em28xx_v4l2_close(struct inode *inode, struct file *filp)
- {
--	int errCode;
--	struct em28xx *dev=filp->private_data;
-+	struct em28xx_fh *fh  = filp->private_data;
-+	struct em28xx    *dev = fh->dev;
-+	int              errCode;
- 
- 	em28xx_videodbg("users=%d\n", dev->users);
- 
--	mutex_lock(&dev->lock);
- 
--	em28xx_uninit_isoc(dev);
-+	if (res_check(fh))
-+		res_free(fh);
- 
--	em28xx_release_buffers(dev);
-+	mutex_lock(&dev->lock);
- 
--	/* the device is already disconnect, free the remaining resources */
--	if (dev->state & DEV_DISCONNECTED) {
--		em28xx_release_resources(dev);
--		mutex_unlock(&dev->lock);
--		kfree(dev);
--		return 0;
--	}
-+	if (dev->users == 1) {
-+		em28xx_uninit_isoc(dev);
-+		em28xx_release_buffers(dev);
-+		dev->io = IO_NONE;
- 
--	/* set alternate 0 */
--	dev->alt = 0;
--	em28xx_videodbg("setting alternate 0\n");
--	errCode = usb_set_interface(dev->udev, 0, 0);
--	if (errCode < 0) {
--		em28xx_errdev ("cannot change alternate number to 0 (error=%i)\n",
--		     errCode);
--	}
-+		/* the device is already disconnect,
-+		   free the remaining resources */
-+		if (dev->state & DEV_DISCONNECTED) {
-+			em28xx_release_resources(dev);
-+			mutex_unlock(&dev->lock);
-+			kfree(dev);
-+			return 0;
-+		}
- 
-+		/* set alternate 0 */
-+		dev->alt = 0;
-+		em28xx_videodbg("setting alternate 0\n");
-+		errCode = usb_set_interface(dev->udev, 0, 0);
-+		if (errCode < 0) {
-+			em28xx_errdev("cannot change alternate number to "
-+					"0 (error=%i)\n", errCode);
-+		}
-+	}
-+	kfree(fh);
- 	dev->users--;
- 	wake_up_interruptible_nr(&dev->open, 1);
- 	mutex_unlock(&dev->lock);
-@@ -405,56 +1429,65 @@ em28xx_v4l2_read(struct file *filp, char __user * buf, size_t count,
- 	struct em28xx_frame_t *f, *i;
- 	unsigned long lock_flags;
- 	int ret = 0;
--	struct em28xx *dev = filp->private_data;
-+	struct em28xx_fh *fh = filp->private_data;
-+	struct em28xx *dev = fh->dev;
- 
--	if (dev->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-+	/* FIXME: read() is not prepared to allow changing the video
-+	   resolution while streaming. Seems a bug at em28xx_set_fmt
-+	 */
-+
-+	if (unlikely(res_get(fh) < 0))
-+		return -EBUSY;
-+
-+	mutex_lock(&dev->lock);
+-	write_reg(itv->yuv_info.reg_2918, 0x02918);
+-	write_reg(itv->yuv_info.reg_291c, 0x0291c);
+-	write_reg(itv->yuv_info.reg_2920, 0x02920);
+-	write_reg(itv->yuv_info.reg_2924, 0x02924);
+-	write_reg(itv->yuv_info.reg_2928, 0x02928);
+-	write_reg(itv->yuv_info.reg_292c, 0x0292c);
+-	write_reg(itv->yuv_info.reg_2930, 0x02930);
+-	write_reg(itv->yuv_info.reg_2934, 0x02934);
+-	write_reg(itv->yuv_info.reg_2938, 0x02938);
+-	write_reg(itv->yuv_info.reg_293c, 0x0293c);
+-	write_reg(itv->yuv_info.reg_2940, 0x02940);
+-	write_reg(itv->yuv_info.reg_2944, 0x02944);
+-	write_reg(itv->yuv_info.reg_2948, 0x02948);
+-	write_reg(itv->yuv_info.reg_294c, 0x0294c);
+-	write_reg(itv->yuv_info.reg_2950, 0x02950);
+-	write_reg(itv->yuv_info.reg_2954, 0x02954);
+-	write_reg(itv->yuv_info.reg_2958, 0x02958);
+-	write_reg(itv->yuv_info.reg_295c, 0x0295c);
+-	write_reg(itv->yuv_info.reg_2960, 0x02960);
+-	write_reg(itv->yuv_info.reg_2964, 0x02964);
+-	write_reg(itv->yuv_info.reg_2968, 0x02968);
+-	write_reg(itv->yuv_info.reg_296c, 0x0296c);
+-	write_reg(itv->yuv_info.reg_2970, 0x02970);
++	write_reg(yi->reg_2898 | 0x01000000, 0x2898);
 +
-+	if (dev->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
- 		em28xx_videodbg("V4l2_Buf_type_videocapture is set\n");
--	}
++	write_reg(yi->reg_2834, 0x02834);
++	write_reg(yi->reg_2838, 0x02838);
++	write_reg(yi->reg_283c, 0x0283c);
++	write_reg(yi->reg_2840, 0x02840);
++	write_reg(yi->reg_2844, 0x02844);
++	write_reg(yi->reg_2848, 0x02848);
++	write_reg(yi->reg_2854, 0x02854);
++	write_reg(yi->reg_285c, 0x0285c);
++	write_reg(yi->reg_2864, 0x02864);
++	write_reg(yi->reg_2870, 0x02870);
++	write_reg(yi->reg_2874, 0x02874);
++	write_reg(yi->reg_2890, 0x02890);
++	write_reg(yi->reg_289c, 0x0289c);
 +
- 	if (dev->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
- 		em28xx_videodbg("V4L2_BUF_TYPE_VBI_CAPTURE is set\n");
- 		em28xx_videodbg("not supported yet! ...\n");
- 		if (copy_to_user(buf, "", 1)) {
--			mutex_unlock(&dev->fileop_lock);
-+			mutex_unlock(&dev->lock);
- 			return -EFAULT;
- 		}
-+		mutex_unlock(&dev->lock);
- 		return (1);
- 	}
- 	if (dev->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) {
- 		em28xx_videodbg("V4L2_BUF_TYPE_SLICED_VBI_CAPTURE is set\n");
- 		em28xx_videodbg("not supported yet! ...\n");
- 		if (copy_to_user(buf, "", 1)) {
--			mutex_unlock(&dev->fileop_lock);
-+			mutex_unlock(&dev->lock);
- 			return -EFAULT;
- 		}
-+		mutex_unlock(&dev->lock);
- 		return (1);
- 	}
++	write_reg(yi->reg_2918, 0x02918);
++	write_reg(yi->reg_291c, 0x0291c);
++	write_reg(yi->reg_2920, 0x02920);
++	write_reg(yi->reg_2924, 0x02924);
++	write_reg(yi->reg_2928, 0x02928);
++	write_reg(yi->reg_292c, 0x0292c);
++	write_reg(yi->reg_2930, 0x02930);
++	write_reg(yi->reg_2934, 0x02934);
++	write_reg(yi->reg_2938, 0x02938);
++	write_reg(yi->reg_293c, 0x0293c);
++	write_reg(yi->reg_2940, 0x02940);
++	write_reg(yi->reg_2944, 0x02944);
++	write_reg(yi->reg_2948, 0x02948);
++	write_reg(yi->reg_294c, 0x0294c);
++	write_reg(yi->reg_2950, 0x02950);
++	write_reg(yi->reg_2954, 0x02954);
++	write_reg(yi->reg_2958, 0x02958);
++	write_reg(yi->reg_295c, 0x0295c);
++	write_reg(yi->reg_2960, 0x02960);
++	write_reg(yi->reg_2964, 0x02964);
++	write_reg(yi->reg_2968, 0x02968);
++	write_reg(yi->reg_296c, 0x0296c);
++	write_reg(yi->reg_2970, 0x02970);
  
--	if (mutex_lock_interruptible(&dev->fileop_lock))
--		return -ERESTARTSYS;
--
- 	if (dev->state & DEV_DISCONNECTED) {
- 		em28xx_videodbg("device not present\n");
--		mutex_unlock(&dev->fileop_lock);
-+		mutex_unlock(&dev->lock);
- 		return -ENODEV;
- 	}
+ 	/* Prepare to restore filters */
  
- 	if (dev->state & DEV_MISCONFIGURED) {
- 		em28xx_videodbg("device misconfigured; close and open it again\n");
--		mutex_unlock(&dev->fileop_lock);
-+		mutex_unlock(&dev->lock);
- 		return -EIO;
+ 	/* First the horizontal filter */
+-	if ((itv->yuv_info.reg_2834 & 0x0000FFFF) == (itv->yuv_info.reg_2834 >> 16)) {
++	if ((yi->reg_2834 & 0x0000FFFF) == (yi->reg_2834 >> 16)) {
+ 		/* An exact size match uses filter 0 */
+ 		h_filter = 0;
+-	}
+-	else {
++	} else {
+ 		/* Figure out which filter to use */
+-		h_filter = ((itv->yuv_info.reg_2834 << 16) / (itv->yuv_info.reg_2834 >> 16)) >> 15;
++		h_filter = ((yi->reg_2834 << 16) / (yi->reg_2834 >> 16)) >> 15;
+ 		h_filter = (h_filter >> 1) + (h_filter & 1);
+ 		/* Only an exact size match can use filter 0. */
+-		if (h_filter < 1) h_filter = 1;
++		h_filter += !h_filter;
  	}
  
- 	if (dev->io == IO_MMAP) {
- 		em28xx_videodbg ("IO method is set to mmap; close and open"
- 				" the device again to choose the read method\n");
--		mutex_unlock(&dev->fileop_lock);
-+		mutex_unlock(&dev->lock);
- 		return -EINVAL;
+ 	/* Now the vertical filter */
+-	if ((itv->yuv_info.reg_2918 & 0x0000FFFF) == (itv->yuv_info.reg_2918 >> 16)) {
++	if ((yi->reg_2918 & 0x0000FFFF) == (yi->reg_2918 >> 16)) {
+ 		/* An exact size match uses filter 0/1 */
+ 		v_filter_1 = 0;
+ 		v_filter_2 = 1;
+-	}
+-	else {
++	} else {
+ 		/* Figure out which filter to use */
+-		v_filter_1 = ((itv->yuv_info.reg_2918 << 16) / (itv->yuv_info.reg_2918 >> 16)) >> 15;
++		v_filter_1 = ((yi->reg_2918 << 16) / (yi->reg_2918 >> 16)) >> 15;
+ 		v_filter_1 = (v_filter_1 >> 1) + (v_filter_1 & 1);
+ 		/* Only an exact size match can use filter 0 */
+-		if (v_filter_1 == 0) v_filter_1 = 1;
++		v_filter_1 += !v_filter_1;
+ 		v_filter_2 = v_filter_1;
  	}
  
- 	if (dev->io == IO_NONE) {
- 		if (!em28xx_request_buffers(dev, EM28XX_NUM_READ_FRAMES)) {
- 			em28xx_errdev("read failed, not enough memory\n");
--			mutex_unlock(&dev->fileop_lock);
-+			mutex_unlock(&dev->lock);
- 			return -ENOMEM;
- 		}
- 		dev->io = IO_READ;
-@@ -463,13 +1496,13 @@ em28xx_v4l2_read(struct file *filp, char __user * buf, size_t count,
- 	}
+ 	/* Now restore the filters */
+-	ivtv_yuv_filter (itv,h_filter,v_filter_1,v_filter_2);
++	ivtv_yuv_filter(itv, h_filter, v_filter_1, v_filter_2);
  
- 	if (!count) {
--		mutex_unlock(&dev->fileop_lock);
-+		mutex_unlock(&dev->lock);
- 		return 0;
- 	}
+ 	/* and clear a few registers */
+ 	write_reg(0, 0x02814);
+@@ -1158,19 +1229,18 @@ void ivtv_yuv_close(struct ivtv *itv)
+ 	write_reg(0, 0x02910);
  
- 	if (list_empty(&dev->outqueue)) {
- 		if (filp->f_flags & O_NONBLOCK) {
--			mutex_unlock(&dev->fileop_lock);
-+			mutex_unlock(&dev->lock);
- 			return -EAGAIN;
- 		}
- 		ret = wait_event_interruptible
-@@ -477,35 +1510,46 @@ em28xx_v4l2_read(struct file *filp, char __user * buf, size_t count,
- 		     (!list_empty(&dev->outqueue)) ||
- 		     (dev->state & DEV_DISCONNECTED));
- 		if (ret) {
--			mutex_unlock(&dev->fileop_lock);
-+			mutex_unlock(&dev->lock);
- 			return ret;
- 		}
- 		if (dev->state & DEV_DISCONNECTED) {
--			mutex_unlock(&dev->fileop_lock);
-+			mutex_unlock(&dev->lock);
- 			return -ENODEV;
- 		}
-+		dev->video_bytesread = 0;
+ 	/* Release the blanking buffer */
+-	if (itv->yuv_info.blanking_ptr) {
+-		kfree (itv->yuv_info.blanking_ptr);
+-		itv->yuv_info.blanking_ptr = NULL;
+-		pci_unmap_single(itv->dev, itv->yuv_info.blanking_dmaptr, 720*16, PCI_DMA_TODEVICE);
++	if (yi->blanking_ptr) {
++		kfree(yi->blanking_ptr);
++		yi->blanking_ptr = NULL;
++		pci_unmap_single(itv->dev, yi->blanking_dmaptr, 720*16, PCI_DMA_TODEVICE);
  	}
  
- 	f = list_entry(dev->outqueue.prev, struct em28xx_frame_t, frame);
+ 	/* Invalidate the old dimension information */
+-	itv->yuv_info.old_frame_info.src_w = 0;
+-	itv->yuv_info.old_frame_info.src_h = 0;
+-	itv->yuv_info.old_frame_info_args.src_w = 0;
+-	itv->yuv_info.old_frame_info_args.src_h = 0;
++	yi->old_frame_info.src_w = 0;
++	yi->old_frame_info.src_h = 0;
++	yi->old_frame_info_args.src_w = 0;
++	yi->old_frame_info_args.src_h = 0;
  
--	spin_lock_irqsave(&dev->queue_lock, lock_flags);
--	list_for_each_entry(i, &dev->outqueue, frame)
--	    i->state = F_UNUSED;
--	INIT_LIST_HEAD(&dev->outqueue);
--	spin_unlock_irqrestore(&dev->queue_lock, lock_flags);
+ 	/* All done. */
+ 	clear_bit(IVTV_F_I_DECODING_YUV, &itv->i_flags);
+ }
 -
- 	em28xx_queue_unusedframes(dev);
- 
- 	if (count > f->buf.length)
- 		count = f->buf.length;
- 
--	if (copy_to_user(buf, f->bufmem, count)) {
--		mutex_unlock(&dev->fileop_lock);
-+	if ((dev->video_bytesread + count) > dev->frame_size)
-+		count = dev->frame_size - dev->video_bytesread;
-+
-+	if (copy_to_user(buf, f->bufmem+dev->video_bytesread, count)) {
-+		em28xx_err("Error while copying to user\n");
- 		return -EFAULT;
- 	}
-+	dev->video_bytesread += count;
-+
-+	if (dev->video_bytesread == dev->frame_size) {
-+		spin_lock_irqsave(&dev->queue_lock, lock_flags);
-+		list_for_each_entry(i, &dev->outqueue, frame)
-+				    i->state = F_UNUSED;
-+		INIT_LIST_HEAD(&dev->outqueue);
-+		spin_unlock_irqrestore(&dev->queue_lock, lock_flags);
-+
-+		em28xx_queue_unusedframes(dev);
-+		dev->video_bytesread = 0;
-+	}
-+
- 	*f_pos += count;
- 
--	mutex_unlock(&dev->fileop_lock);
-+	mutex_unlock(&dev->lock);
+diff --git a/drivers/media/video/ivtv/ivtv-yuv.h b/drivers/media/video/ivtv/ivtv-yuv.h
+index 3b966f0..2fe5f12 100644
+--- a/drivers/media/video/ivtv/ivtv-yuv.h
++++ b/drivers/media/video/ivtv/ivtv-yuv.h
+@@ -21,11 +21,6 @@
+ #ifndef IVTV_YUV_H
+ #define IVTV_YUV_H
  
- 	return count;
- }
-@@ -517,11 +1561,14 @@ em28xx_v4l2_read(struct file *filp, char __user * buf, size_t count,
- static unsigned int em28xx_v4l2_poll(struct file *filp, poll_table * wait)
- {
- 	unsigned int mask = 0;
--	struct em28xx *dev = filp->private_data;
-+	struct em28xx_fh *fh = filp->private_data;
-+	struct em28xx *dev = fh->dev;
+-/* Buffers on hardware offsets */
+-#define IVTV_YUV_BUFFER_OFFSET    0x001a8600	/* First YUV Buffer */
+-#define IVTV_YUV_BUFFER_OFFSET_1  0x00240400	/* Second YUV Buffer */
+-#define IVTV_YUV_BUFFER_OFFSET_2  0x002d8200	/* Third YUV Buffer */
+-#define IVTV_YUV_BUFFER_OFFSET_3  0x00370000	/* Fourth YUV Buffer */
+ #define IVTV_YUV_BUFFER_UV_OFFSET 0x65400	/* Offset to UV Buffer */
  
--	if (mutex_lock_interruptible(&dev->fileop_lock))
-+	if (unlikely(res_get(fh) < 0))
- 		return POLLERR;
+ /* Offset to filter table in firmware */
+@@ -36,11 +31,14 @@
+ #define IVTV_YUV_UPDATE_VERTICAL    0x02
+ #define IVTV_YUV_UPDATE_INVALID     0x04
  
-+	mutex_lock(&dev->lock);
-+
- 	if (dev->state & DEV_DISCONNECTED) {
- 		em28xx_videodbg("device not present\n");
- 	} else if (dev->state & DEV_MISCONFIGURED) {
-@@ -545,83 +1592,61 @@ static unsigned int em28xx_v4l2_poll(struct file *filp, poll_table * wait)
- 			if (!list_empty(&dev->outqueue))
- 				mask |= POLLIN | POLLRDNORM;
+-extern const u32 yuv_offset[4];
++extern const u32 yuv_offset[IVTV_YUV_BUFFERS];
  
--			mutex_unlock(&dev->fileop_lock);
-+			mutex_unlock(&dev->lock);
+ int ivtv_yuv_filter_check(struct ivtv *itv);
++void ivtv_yuv_setup_stream_frame(struct ivtv *itv);
++int ivtv_yuv_udma_stream_frame(struct ivtv *itv, void *src);
++void ivtv_yuv_frame_complete(struct ivtv *itv);
+ int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args);
+ void ivtv_yuv_close(struct ivtv *itv);
+-void ivtv_yuv_work_handler (struct ivtv *itv);
++void ivtv_yuv_work_handler(struct ivtv *itv);
  
- 			return mask;
- 		}
- 	}
+ #endif
+diff --git a/drivers/media/video/ivtv/ivtvfb.c b/drivers/media/video/ivtv/ivtvfb.c
+index 52ffd15..3b23fc0 100644
+--- a/drivers/media/video/ivtv/ivtvfb.c
++++ b/drivers/media/video/ivtv/ivtvfb.c
+@@ -504,6 +504,10 @@ static int ivtvfb_set_var(struct ivtv *itv, struct fb_var_screeninfo *var)
  
--	mutex_unlock(&dev->fileop_lock);
-+	mutex_unlock(&dev->lock);
- 	return POLLERR;
- }
+ 	ivtvfb_set_display_window(itv, &ivtv_window);
  
- /*
-- * em28xx_vm_open()
-- */
--static void em28xx_vm_open(struct vm_area_struct *vma)
--{
--	struct em28xx_frame_t *f = vma->vm_private_data;
--	f->vma_use_count++;
--}
--
--/*
-- * em28xx_vm_close()
-- */
--static void em28xx_vm_close(struct vm_area_struct *vma)
--{
--	/* NOTE: buffers are not freed here */
--	struct em28xx_frame_t *f = vma->vm_private_data;
--
--	if (f->vma_use_count)
--		f->vma_use_count--;
--}
--
--static struct vm_operations_struct em28xx_vm_ops = {
--	.open = em28xx_vm_open,
--	.close = em28xx_vm_close,
--};
--
--/*
-  * em28xx_v4l2_mmap()
-  */
- static int em28xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma)
- {
--	unsigned long size = vma->vm_end - vma->vm_start,
--	    start = vma->vm_start;
--	void *pos;
--	u32 i;
--
--	struct em28xx *dev = filp->private_data;
-+	struct em28xx_fh *fh    = filp->private_data;
-+	struct em28xx	 *dev   = fh->dev;
-+	unsigned long	 size   = vma->vm_end - vma->vm_start;
-+	unsigned long	 start  = vma->vm_start;
-+	void 		 *pos;
-+	u32		 i;
++	/* Pass screen size back to yuv handler */
++	itv->yuv_info.osd_full_w = ivtv_osd.pixel_stride;
++	itv->yuv_info.osd_full_h = ivtv_osd.lines;
 +
-+	if (unlikely(res_get(fh) < 0))
-+		return -EBUSY;
- 
--	if (mutex_lock_interruptible(&dev->fileop_lock))
--		return -ERESTARTSYS;
-+	mutex_lock(&dev->lock);
- 
- 	if (dev->state & DEV_DISCONNECTED) {
- 		em28xx_videodbg("mmap: device not present\n");
--		mutex_unlock(&dev->fileop_lock);
-+		mutex_unlock(&dev->lock);
- 		return -ENODEV;
- 	}
+ 	/* Force update of yuv registers */
+ 	itv->yuv_info.yuv_forced_update = 1;
  
- 	if (dev->state & DEV_MISCONFIGURED) {
- 		em28xx_videodbg ("mmap: Device is misconfigured; close and "
- 						"open it again\n");
--		mutex_unlock(&dev->fileop_lock);
-+		mutex_unlock(&dev->lock);
- 		return -EIO;
+@@ -1053,7 +1057,7 @@ static int ivtvfb_init_card(struct ivtv *itv)
  	}
  
--	if (dev->io != IO_MMAP || !(vma->vm_flags & VM_WRITE) ||
--	    size != PAGE_ALIGN(dev->frame[0].buf.length)) {
--		mutex_unlock(&dev->fileop_lock);
-+	if (dev->io != IO_MMAP || !(vma->vm_flags & VM_WRITE)) {
-+		mutex_unlock(&dev->lock);
- 		return -EINVAL;
+ 	itv->osd_info = kzalloc(sizeof(struct osd_info), GFP_ATOMIC);
+-	if (itv->osd_info == 0) {
++	if (itv->osd_info == NULL) {
+ 		IVTVFB_ERR("Failed to allocate memory for osd_info\n");
+ 		return -ENOMEM;
  	}
+diff --git a/drivers/media/video/ks0127.c b/drivers/media/video/ks0127.c
+index b6cd21e..4895540 100644
+--- a/drivers/media/video/ks0127.c
++++ b/drivers/media/video/ks0127.c
+@@ -764,7 +764,6 @@ static struct i2c_client ks0127_client_tmpl =
+ 	.addr = 0,
+ 	.adapter = NULL,
+ 	.driver = &i2c_driver_ks0127,
+-	.usage_count = 0
+ };
  
-+	if (size > PAGE_ALIGN(dev->frame[0].buf.length))
-+		size = PAGE_ALIGN(dev->frame[0].buf.length);
+ static int ks0127_found_proc(struct i2c_adapter *adapter, int addr, int kind)
+diff --git a/drivers/media/video/m52790.c b/drivers/media/video/m52790.c
+new file mode 100644
+index 0000000..d4bf14c
+--- /dev/null
++++ b/drivers/media/video/m52790.c
+@@ -0,0 +1,168 @@
++/*
++ * m52790 i2c ivtv driver.
++ * Copyright (C) 2007  Hans Verkuil
++ *
++ * A/V source switching Mitsubishi M52790SP/FP
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You 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.
++ */
 +
- 	for (i = 0; i < dev->num_frames; i++) {
- 		if ((dev->frame[i].buf.m.offset >> PAGE_SHIFT) == vma->vm_pgoff)
- 			break;
- 	}
- 	if (i == dev->num_frames) {
- 		em28xx_videodbg("mmap: user supplied mapping address is out of range\n");
--		mutex_unlock(&dev->fileop_lock);
-+		mutex_unlock(&dev->lock);
- 		return -EINVAL;
- 	}
- 
-@@ -633,7 +1658,7 @@ static int em28xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma)
- 	while (size > 0) {	/* size is page-aligned */
- 		if (vm_insert_page(vma, start, vmalloc_to_page(pos))) {
- 			em28xx_videodbg("mmap: vm_insert_page failed\n");
--			mutex_unlock(&dev->fileop_lock);
-+			mutex_unlock(&dev->lock);
- 			return -EAGAIN;
- 		}
- 		start += PAGE_SIZE;
-@@ -645,900 +1670,210 @@ static int em28xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma)
- 	vma->vm_private_data = &dev->frame[i];
- 
- 	em28xx_vm_open(vma);
--	mutex_unlock(&dev->fileop_lock);
--	return 0;
--}
--
--/*
-- * em28xx_get_ctrl()
-- * return the current saturation, brightness or contrast, mute state
-- */
--static int em28xx_get_ctrl(struct em28xx *dev, struct v4l2_control *ctrl)
--{
--	switch (ctrl->id) {
--	case V4L2_CID_AUDIO_MUTE:
--		ctrl->value = dev->mute;
--		return 0;
--	case V4L2_CID_AUDIO_VOLUME:
--		ctrl->value = dev->volume;
--		return 0;
--	default:
--		return -EINVAL;
--	}
--}
--
--/*
-- * em28xx_set_ctrl()
-- * mute or set new saturation, brightness or contrast
-- */
--static int em28xx_set_ctrl(struct em28xx *dev, const struct v4l2_control *ctrl)
--{
--	switch (ctrl->id) {
--	case V4L2_CID_AUDIO_MUTE:
--		if (ctrl->value != dev->mute) {
--			dev->mute = ctrl->value;
--			em28xx_audio_usb_mute(dev, ctrl->value);
--			return em28xx_audio_analog_set(dev);
--		}
--		return 0;
--	case V4L2_CID_AUDIO_VOLUME:
--		dev->volume = ctrl->value;
--		return em28xx_audio_analog_set(dev);
--	default:
--		return -EINVAL;
--	}
--}
--
--/*
-- * em28xx_stream_interrupt()
-- * stops streaming
-- */
--static int em28xx_stream_interrupt(struct em28xx *dev)
--{
--	int ret = 0;
--
--	/* stop reading from the device */
--
--	dev->stream = STREAM_INTERRUPT;
--	ret = wait_event_timeout(dev->wait_stream,
--				 (dev->stream == STREAM_OFF) ||
--				 (dev->state & DEV_DISCONNECTED),
--				 EM28XX_URB_TIMEOUT);
--	if (dev->state & DEV_DISCONNECTED)
--		return -ENODEV;
--	else if (ret) {
--		dev->state |= DEV_MISCONFIGURED;
--		em28xx_videodbg("device is misconfigured; close and "
--			"open /dev/video%d again\n",
--				dev->vdev->minor-MINOR_VFL_TYPE_GRABBER_MIN);
--		return ret;
--	}
--
--	return 0;
--}
--
--static int em28xx_set_norm(struct em28xx *dev, int width, int height)
--{
--	unsigned int hscale, vscale;
--	unsigned int maxh, maxw;
--
--	maxw = norm_maxw(dev);
--	maxh = norm_maxh(dev);
--
--	/* width must even because of the YUYV format */
--	/* height must be even because of interlacing */
--	height &= 0xfffe;
--	width &= 0xfffe;
--
--	if (height < 32)
--		height = 32;
--	if (height > maxh)
--		height = maxh;
--	if (width < 48)
--		width = 48;
--	if (width > maxw)
--		width = maxw;
--
--	if ((hscale = (((unsigned long)maxw) << 12) / width - 4096L) >= 0x4000)
--		hscale = 0x3fff;
--	width = (((unsigned long)maxw) << 12) / (hscale + 4096L);
--
--	if ((vscale = (((unsigned long)maxh) << 12) / height - 4096L) >= 0x4000)
--		vscale = 0x3fff;
--	height = (((unsigned long)maxh) << 12) / (vscale + 4096L);
--
--	/* set new image size */
--	dev->width = width;
--	dev->height = height;
--	dev->frame_size = dev->width * dev->height * 2;
--	dev->field_size = dev->frame_size >> 1;	/*both_fileds ? dev->frame_size>>1 : dev->frame_size; */
--	dev->bytesperline = dev->width * 2;
--	dev->hscale = hscale;
--	dev->vscale = vscale;
--
--	em28xx_resolution_set(dev);
--
-+	mutex_unlock(&dev->lock);
- 	return 0;
- }
- 
--static int em28xx_get_fmt(struct em28xx *dev, struct v4l2_format *format)
--{
--	em28xx_videodbg("VIDIOC_G_FMT: type=%s\n",
--		(format->type ==V4L2_BUF_TYPE_VIDEO_CAPTURE) ?
--		"V4L2_BUF_TYPE_VIDEO_CAPTURE" :
--		(format->type ==V4L2_BUF_TYPE_VBI_CAPTURE) ?
--		"V4L2_BUF_TYPE_VBI_CAPTURE" :
--		(format->type ==V4L2_CAP_SLICED_VBI_CAPTURE) ?
--		"V4L2_BUF_TYPE_SLICED_VBI_CAPTURE " :
--		"not supported");
--
--	switch (format->type) {
--	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
--	{
--		format->fmt.pix.width = dev->width;
--		format->fmt.pix.height = dev->height;
--		format->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
--		format->fmt.pix.bytesperline = dev->bytesperline;
--		format->fmt.pix.sizeimage = dev->frame_size;
--		format->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
--		format->fmt.pix.field = dev->interlaced ? V4L2_FIELD_INTERLACED : V4L2_FIELD_TOP;	/* FIXME: TOP? NONE? BOTTOM? ALTENATE? */
-+static const struct file_operations em28xx_v4l_fops = {
-+	.owner         = THIS_MODULE,
-+	.open          = em28xx_v4l2_open,
-+	.release       = em28xx_v4l2_close,
-+	.read          = em28xx_v4l2_read,
-+	.poll          = em28xx_v4l2_poll,
-+	.mmap          = em28xx_v4l2_mmap,
-+	.ioctl	       = video_ioctl2,
-+	.llseek        = no_llseek,
-+	.compat_ioctl  = v4l_compat_ioctl32,
-+};
- 
--		em28xx_videodbg("VIDIOC_G_FMT: %dx%d\n", dev->width,
--			dev->height);
--		break;
--	}
-+static const struct file_operations radio_fops = {
-+	.owner         = THIS_MODULE,
-+	.open          = em28xx_v4l2_open,
-+	.release       = em28xx_v4l2_close,
-+	.ioctl	       = video_ioctl2,
-+	.compat_ioctl  = v4l_compat_ioctl32,
-+	.llseek        = no_llseek,
++
++#include <linux/module.h>
++#include <linux/types.h>
++#include <linux/ioctl.h>
++#include <asm/uaccess.h>
++#include <linux/i2c.h>
++#include <linux/i2c-id.h>
++#include <linux/videodev.h>
++#include <media/m52790.h>
++#include <media/v4l2-common.h>
++#include <media/v4l2-chip-ident.h>
++#include <media/v4l2-i2c-drv.h>
++
++MODULE_DESCRIPTION("i2c device driver for m52790 A/V switch");
++MODULE_AUTHOR("Hans Verkuil");
++MODULE_LICENSE("GPL");
++
++
++struct m52790_state {
++	u16 input;
++	u16 output;
 +};
- 
--	case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
--	{
--		format->fmt.sliced.service_set=0;
-+static const struct video_device em28xx_video_template = {
-+	.fops                       = &em28xx_v4l_fops,
-+	.release                    = video_device_release,
 +
-+	.minor                      = -1,
-+	.vidioc_querycap            = vidioc_querycap,
-+	.vidioc_enum_fmt_cap        = vidioc_enum_fmt_cap,
-+	.vidioc_g_fmt_cap           = vidioc_g_fmt_cap,
-+	.vidioc_try_fmt_cap         = vidioc_try_fmt_cap,
-+	.vidioc_s_fmt_cap           = vidioc_s_fmt_cap,
-+	.vidioc_g_audio             = vidioc_g_audio,
-+	.vidioc_s_audio             = vidioc_s_audio,
-+	.vidioc_cropcap             = vidioc_cropcap,
++/* ----------------------------------------------------------------------- */
 +
-+	.vidioc_g_fmt_vbi_capture   = vidioc_g_fmt_vbi_capture,
-+	.vidioc_try_fmt_vbi_capture = vidioc_try_set_vbi_capture,
-+	.vidioc_s_fmt_vbi_capture   = vidioc_try_set_vbi_capture,
++static int m52790_write(struct i2c_client *client)
++{
++	struct m52790_state *state = i2c_get_clientdata(client);
++	u8 sw1 = (state->input | state->output) & 0xff;
++	u8 sw2 = (state->input | state->output) >> 8;
 +
-+	.vidioc_reqbufs             = vidioc_reqbufs,
-+	.vidioc_querybuf            = vidioc_querybuf,
-+	.vidioc_qbuf                = vidioc_qbuf,
-+	.vidioc_dqbuf               = vidioc_dqbuf,
-+	.vidioc_s_std               = vidioc_s_std,
-+	.vidioc_enum_input          = vidioc_enum_input,
-+	.vidioc_g_input             = vidioc_g_input,
-+	.vidioc_s_input             = vidioc_s_input,
-+	.vidioc_queryctrl           = vidioc_queryctrl,
-+	.vidioc_g_ctrl              = vidioc_g_ctrl,
-+	.vidioc_s_ctrl              = vidioc_s_ctrl,
-+	.vidioc_streamon            = vidioc_streamon,
-+	.vidioc_streamoff           = vidioc_streamoff,
-+	.vidioc_g_tuner             = vidioc_g_tuner,
-+	.vidioc_s_tuner             = vidioc_s_tuner,
-+	.vidioc_g_frequency         = vidioc_g_frequency,
-+	.vidioc_s_frequency         = vidioc_s_frequency,
++	return i2c_smbus_write_byte_data(client, sw1, sw2);
++}
 +
-+	.tvnorms                    = V4L2_STD_ALL,
-+	.current_norm               = V4L2_STD_PAL,
++static int m52790_command(struct i2c_client *client, unsigned int cmd,
++			    void *arg)
++{
++	struct m52790_state *state = i2c_get_clientdata(client);
++	struct v4l2_routing *route = arg;
++
++	/* Note: audio and video are linked and cannot be switched separately.
++	   So audio and video routing commands are identical for this chip.
++	   In theory the video amplifier and audio modes could be handled
++	   separately for the output, but that seems to be overkill right now.
++	   The same holds for implementing an audio mute control, this is now
++	   part of the audio output routing. The normal case is that another
++	   chip takes care of the actual muting so making it part of the
++	   output routing seems to be the right thing to do for now. */
++	switch (cmd) {
++	case VIDIOC_INT_G_AUDIO_ROUTING:
++	case VIDIOC_INT_G_VIDEO_ROUTING:
++		route->input = state->input;
++		route->output = state->output;
++		break;
++
++	case VIDIOC_INT_S_AUDIO_ROUTING:
++	case VIDIOC_INT_S_VIDEO_ROUTING:
++		state->input = route->input;
++		state->output = route->output;
++		m52790_write(client);
++		break;
++
++#ifdef CONFIG_VIDEO_ADV_DEBUG
++	case VIDIOC_DBG_G_REGISTER:
++	case VIDIOC_DBG_S_REGISTER:
++	{
++		struct v4l2_register *reg = arg;
++
++		if (!v4l2_chip_match_i2c_client(client,
++					reg->match_type, reg->match_chip))
++			return -EINVAL;
++		if (!capable(CAP_SYS_ADMIN))
++			return -EPERM;
++		if (reg->reg != 0)
++			return -EINVAL;
++		if (cmd == VIDIOC_DBG_G_REGISTER)
++			reg->val = state->input | state->output;
++		else {
++			state->input = reg->val & 0x0303;
++			state->output = reg->val & ~0x0303;
++			m52790_write(client);
++		}
++		break;
++	}
++#endif
++
++	case VIDIOC_G_CHIP_IDENT:
++		return v4l2_chip_ident_i2c_client(client, arg,
++				V4L2_IDENT_M52790, 0);
++
++	case VIDIOC_LOG_STATUS:
++		v4l_info(client, "Switch 1: %02x\n",
++				(state->input | state->output) & 0xff);
++		v4l_info(client, "Switch 2: %02x\n",
++				(state->input | state->output) >> 8);
++		break;
++
++	default:
++		return -EINVAL;
++	}
++	return 0;
++}
++
++/* ----------------------------------------------------------------------- */
++
++/* i2c implementation */
++
++static int m52790_probe(struct i2c_client *client)
++{
++	struct m52790_state *state;
++
++	/* Check if the adapter supports the needed features */
++	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
++		return -EIO;
++
++	snprintf(client->name, sizeof(client->name) - 1, "m52790");
++
++	v4l_info(client, "chip found @ 0x%x (%s)\n",
++			client->addr << 1, client->adapter->name);
++
++	state = kmalloc(sizeof(struct m52790_state), GFP_KERNEL);
++	if (state == NULL)
++		return -ENOMEM;
++
++	state->input = M52790_IN_TUNER;
++	state->output = M52790_OUT_STEREO;
++	i2c_set_clientdata(client, state);
++	m52790_write(client);
++	return 0;
++}
++
++static int m52790_remove(struct i2c_client *client)
++{
++	kfree(i2c_get_clientdata(client));
++	return 0;
++}
++
++/* ----------------------------------------------------------------------- */
++
++static struct v4l2_i2c_driver_data v4l2_i2c_data = {
++	.name = "m52790",
++	.driverid = I2C_DRIVERID_M52790,
++	.command = m52790_command,
++	.probe = m52790_probe,
++	.remove = m52790_remove,
 +};
++
+diff --git a/drivers/media/video/meye.c b/drivers/media/video/meye.c
+index c311632..3d51fa0 100644
+--- a/drivers/media/video/meye.c
++++ b/drivers/media/video/meye.c
+@@ -2023,7 +2023,7 @@ static int __init meye_init(void)
+ 	if (gbufsize < 0 || gbufsize > MEYE_MAX_BUFSIZE)
+ 		gbufsize = MEYE_MAX_BUFSIZE;
+ 	gbufsize = PAGE_ALIGN(gbufsize);
+-	printk(KERN_INFO "meye: using %d buffers with %dk (%dk total)"
++	printk(KERN_INFO "meye: using %d buffers with %dk (%dk total) "
+ 			 "for capture\n",
+ 			 gbuffers,
+ 			 gbufsize / 1024, gbuffers * gbufsize / 1024);
+diff --git a/drivers/media/video/msp3400-driver.c b/drivers/media/video/msp3400-driver.c
+index c0c87e0..7a11f31 100644
+--- a/drivers/media/video/msp3400-driver.c
++++ b/drivers/media/video/msp3400-driver.c
+@@ -42,7 +42,8 @@
+  *
+  * You 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.
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
++ * 02110-1301, USA.
+  */
  
--		em28xx_i2c_call_clients(dev,VIDIOC_G_FMT,format);
-+static struct video_device em28xx_radio_template = {
-+	.name                 = "em28xx-radio",
-+	.type                 = VID_TYPE_TUNER,
-+	.fops                 = &radio_fops,
-+	.minor                = -1,
-+	.vidioc_querycap      = radio_querycap,
-+	.vidioc_g_tuner       = radio_g_tuner,
-+	.vidioc_enum_input    = radio_enum_input,
-+	.vidioc_g_audio       = radio_g_audio,
-+	.vidioc_s_tuner       = radio_s_tuner,
-+	.vidioc_s_audio       = radio_s_audio,
-+	.vidioc_s_input       = radio_s_input,
-+	.vidioc_queryctrl     = radio_queryctrl,
-+	.vidioc_g_ctrl        = vidioc_g_ctrl,
-+	.vidioc_s_ctrl        = vidioc_s_ctrl,
-+	.vidioc_g_frequency   = vidioc_g_frequency,
-+	.vidioc_s_frequency   = vidioc_s_frequency,
-+};
  
--		if (format->fmt.sliced.service_set==0)
--			return -EINVAL;
-+/******************************** usb interface *****************************************/
+@@ -53,6 +54,7 @@
+ #include <linux/videodev.h>
+ #include <linux/videodev2.h>
+ #include <media/v4l2-common.h>
++#include <media/v4l2-i2c-drv-legacy.h>
+ #include <media/tvaudio.h>
+ #include <media/msp3400.h>
+ #include <linux/kthread.h>
+@@ -71,7 +73,8 @@ int msp_debug;		 /* msp_debug output */
+ int msp_once;		 /* no continous stereo monitoring */
+ int msp_amsound;	 /* hard-wire AM sound at 6.5 Hz (france),
+ 			    the autoscan seems work well only with FM... */
+-int msp_standard = 1;    /* Override auto detect of audio msp_standard, if needed. */
++int msp_standard = 1;    /* Override auto detect of audio msp_standard,
++			    if needed. */
+ int msp_dolby;
  
--		break;
--	}
+ int msp_stereo_thresh = 0x190; /* a2 threshold for stereo/bilingual
+@@ -81,12 +84,12 @@ int msp_stereo_thresh = 0x190; /* a2 threshold for stereo/bilingual
+ module_param(opmode,           int, 0444);
  
--	default:
--		return -EINVAL;
--	}
--	return (0);
--}
-+static LIST_HEAD(em28xx_extension_devlist);
-+static DEFINE_MUTEX(em28xx_extension_devlist_lock);
+ /* read-write */
+-module_param_named(once,msp_once,                      bool, 0644);
+-module_param_named(debug,msp_debug,                    int,  0644);
+-module_param_named(stereo_threshold,msp_stereo_thresh, int,  0644);
+-module_param_named(standard,msp_standard,              int,  0644);
+-module_param_named(amsound,msp_amsound,                bool, 0644);
+-module_param_named(dolby,msp_dolby,                    bool, 0644);
++module_param_named(once, msp_once,                      bool, 0644);
++module_param_named(debug, msp_debug,                    int,  0644);
++module_param_named(stereo_threshold, msp_stereo_thresh, int,  0644);
++module_param_named(standard, msp_standard,              int,  0644);
++module_param_named(amsound, msp_amsound,                bool, 0644);
++module_param_named(dolby, msp_dolby,                    bool, 0644);
  
--static int em28xx_set_fmt(struct em28xx *dev, unsigned int cmd, struct v4l2_format *format)
-+int em28xx_register_extension(struct em28xx_ops *ops)
- {
--	u32 i;
--	int ret = 0;
--	int width = format->fmt.pix.width;
--	int height = format->fmt.pix.height;
--	unsigned int hscale, vscale;
--	unsigned int maxh, maxw;
-+	struct em28xx *h, *dev = NULL;
+ MODULE_PARM_DESC(opmode, "Forces a MSP3400 opmode. 0=Manual, 1=Autodetect, 2=Autodetect and autoselect");
+ MODULE_PARM_DESC(once, "No continuous stereo monitoring");
+@@ -160,12 +163,13 @@ static int msp_read(struct i2c_client *client, int dev, int addr)
+ 		schedule_timeout_interruptible(msecs_to_jiffies(10));
+ 	}
+ 	if (err == 3) {
+-		v4l_warn(client, "giving up, resetting chip. Sound will go off, sorry folks :-|\n");
++		v4l_warn(client, "resetting chip, sound will go off.\n");
+ 		msp_reset(client);
+ 		return -1;
+ 	}
+ 	retval = read[0] << 8 | read[1];
+-	v4l_dbg(3, msp_debug, client, "msp_read(0x%x, 0x%x): 0x%x\n", dev, addr, retval);
++	v4l_dbg(3, msp_debug, client, "msp_read(0x%x, 0x%x): 0x%x\n",
++			dev, addr, retval);
+ 	return retval;
+ }
  
--	maxw = norm_maxw(dev);
--	maxh = norm_maxh(dev);
--
--	em28xx_videodbg("%s: type=%s\n",
--			cmd == VIDIOC_TRY_FMT ?
--			"VIDIOC_TRY_FMT" : "VIDIOC_S_FMT",
--			format->type == V4L2_BUF_TYPE_VIDEO_CAPTURE ?
--			"V4L2_BUF_TYPE_VIDEO_CAPTURE" :
--			format->type == V4L2_BUF_TYPE_VBI_CAPTURE ?
--			"V4L2_BUF_TYPE_VBI_CAPTURE " :
--			"not supported");
--
--	if (format->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) {
--		em28xx_i2c_call_clients(dev,VIDIOC_G_FMT,format);
--
--		if (format->fmt.sliced.service_set==0)
--			return -EINVAL;
-+	list_for_each_entry(h, &em28xx_devlist, devlist)
-+		dev = h;
+@@ -190,7 +194,8 @@ static int msp_write(struct i2c_client *client, int dev, int addr, int val)
+ 	buffer[3] = val  >> 8;
+ 	buffer[4] = val  &  0xff;
  
--		return 0;
--	}
-+	mutex_lock(&em28xx_extension_devlist_lock);
-+	list_add_tail(&ops->next, &em28xx_extension_devlist);
-+	if (dev)
-+		ops->init(dev);
+-	v4l_dbg(3, msp_debug, client, "msp_write(0x%x, 0x%x, 0x%x)\n", dev, addr, val);
++	v4l_dbg(3, msp_debug, client, "msp_write(0x%x, 0x%x, 0x%x)\n",
++			dev, addr, val);
+ 	for (err = 0; err < 3; err++) {
+ 		if (i2c_master_send(client, buffer, 5) == 5)
+ 			break;
+@@ -199,7 +204,7 @@ static int msp_write(struct i2c_client *client, int dev, int addr, int val)
+ 		schedule_timeout_interruptible(msecs_to_jiffies(10));
+ 	}
+ 	if (err == 3) {
+-		v4l_warn(client, "giving up, resetting chip. Sound will go off, sorry folks :-|\n");
++		v4l_warn(client, "resetting chip, sound will go off.\n");
+ 		msp_reset(client);
+ 		return -1;
+ 	}
+@@ -273,7 +278,7 @@ void msp_set_scart(struct i2c_client *client, int in, int out)
+ 		state->acb = 0xf60; /* Mute Input and SCART 1 Output */
  
--
--	if (format->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
--		return -EINVAL;
--
--	em28xx_videodbg("%s: requested %dx%d\n",
--		cmd == VIDIOC_TRY_FMT ?
--		"VIDIOC_TRY_FMT" : "VIDIOC_S_FMT",
--		format->fmt.pix.width, format->fmt.pix.height);
--
--	/* FIXME: Move some code away from here */
--	/* width must even because of the YUYV format */
--	/* height must be even because of interlacing */
--	height &= 0xfffe;
--	width &= 0xfffe;
--
--	if (height < 32)
--		height = 32;
--	if (height > maxh)
--		height = maxh;
--	if (width < 48)
--		width = 48;
--	if (width > maxw)
--		width = maxw;
--
--	if(dev->is_em2800){
--		/* the em2800 can only scale down to 50% */
--		if(height % (maxh / 2))
--			height=maxh;
--		if(width % (maxw / 2))
--			width=maxw;
--		/* according to empiatech support */
--		/* the MaxPacketSize is to small to support */
--		/* framesizes larger than 640x480 @ 30 fps */
--		/* or 640x576 @ 25 fps. As this would cut */
--		/* of a part of the image we prefer */
--		/* 360x576 or 360x480 for now */
--		if(width == maxw && height == maxh)
--			width /= 2;
--	}
--
--	if ((hscale = (((unsigned long)maxw) << 12) / width - 4096L) >= 0x4000)
--		hscale = 0x3fff;
--
--	width = (((unsigned long)maxw) << 12) / (hscale + 4096L);
--
--	if ((vscale = (((unsigned long)maxh) << 12) / height - 4096L) >= 0x4000)
--		vscale = 0x3fff;
--
--	height = (((unsigned long)maxh) << 12) / (vscale + 4096L);
--
--	format->fmt.pix.width = width;
--	format->fmt.pix.height = height;
--	format->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
--	format->fmt.pix.bytesperline = width * 2;
--	format->fmt.pix.sizeimage = width * 2 * height;
--	format->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
--	format->fmt.pix.field = V4L2_FIELD_INTERLACED;
--
--	em28xx_videodbg("%s: returned %dx%d (%d, %d)\n",
--		cmd == VIDIOC_TRY_FMT ?
--		"VIDIOC_TRY_FMT" :"VIDIOC_S_FMT",
--		format->fmt.pix.width, format->fmt.pix.height, hscale, vscale);
--
--	if (cmd == VIDIOC_TRY_FMT)
--		return 0;
--
--	for (i = 0; i < dev->num_frames; i++)
--		if (dev->frame[i].vma_use_count) {
--			em28xx_videodbg("VIDIOC_S_FMT failed. "
--				"Unmap the buffers first.\n");
--			return -EINVAL;
--		}
--
--	/* stop io in case it is already in progress */
--	if (dev->stream == STREAM_ON) {
--		em28xx_videodbg("VIDIOC_SET_FMT: interrupting stream\n");
--		if ((ret = em28xx_stream_interrupt(dev)))
--			return ret;
--	}
--
--	em28xx_release_buffers(dev);
--	dev->io = IO_NONE;
--
--	/* set new image size */
--	dev->width = width;
--	dev->height = height;
--	dev->frame_size = dev->width * dev->height * 2;
--	dev->field_size = dev->frame_size >> 1;
--	dev->bytesperline = dev->width * 2;
--	dev->hscale = hscale;
--	dev->vscale = vscale;
--	em28xx_uninit_isoc(dev);
--	em28xx_set_alternate(dev);
--	em28xx_capture_start(dev, 1);
--	em28xx_resolution_set(dev);
--	em28xx_init_isoc(dev);
-+	printk(KERN_INFO "Em28xx: Initialized (%s) extension\n", ops->name);
-+	mutex_unlock(&em28xx_extension_devlist_lock);
+ 	v4l_dbg(1, msp_debug, client, "scart switch: %s => %d (ACB=0x%04x)\n",
+-						scart_names[in], out, state->acb);
++					scart_names[in], out, state->acb);
+ 	msp_write_dsp(client, 0x13, state->acb);
  
- 	return 0;
- }
-+EXPORT_SYMBOL(em28xx_register_extension);
+ 	/* Sets I2S speed 0 = 1.024 Mbps, 1 = 2.048 Mbps */
+@@ -292,7 +297,8 @@ void msp_set_audio(struct i2c_client *client)
+ 		val = (state->volume * 0x7f / 65535) << 8;
+ 
+ 	v4l_dbg(1, msp_debug, client, "mute=%s scanning=%s volume=%d\n",
+-		state->muted ? "on" : "off", state->scan_in_progress ? "yes" : "no",
++		state->muted ? "on" : "off",
++		state->scan_in_progress ? "yes" : "no",
+ 		state->volume);
+ 
+ 	msp_write_dsp(client, 0x0000, val);
+@@ -681,14 +687,14 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
+ 		v4l_dbg(1, msp_debug, client, "Setting I2S speed to %d\n", *a);
+ 
+ 		switch (*a) {
+-			case 1024000:
+-				state->i2s_mode = 0;
+-				break;
+-			case 2048000:
+-				state->i2s_mode = 1;
+-				break;
+-			default:
+-				return -EINVAL;
++		case 1024000:
++			state->i2s_mode = 0;
++			break;
++		case 2048000:
++			state->i2s_mode = 1;
++			break;
++		default:
++			return -EINVAL;
+ 		}
+ 		break;
+ 	}
+@@ -698,22 +704,22 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
+ 		struct v4l2_queryctrl *qc = arg;
+ 
+ 		switch (qc->id) {
+-			case V4L2_CID_AUDIO_VOLUME:
+-			case V4L2_CID_AUDIO_MUTE:
+-				return v4l2_ctrl_query_fill_std(qc);
+-			default:
+-				break;
++		case V4L2_CID_AUDIO_VOLUME:
++		case V4L2_CID_AUDIO_MUTE:
++			return v4l2_ctrl_query_fill_std(qc);
++		default:
++			break;
+ 		}
+ 		if (!state->has_sound_processing)
+ 			return -EINVAL;
+ 		switch (qc->id) {
+-			case V4L2_CID_AUDIO_LOUDNESS:
+-			case V4L2_CID_AUDIO_BALANCE:
+-			case V4L2_CID_AUDIO_BASS:
+-			case V4L2_CID_AUDIO_TREBLE:
+-				return v4l2_ctrl_query_fill_std(qc);
+-			default:
+-				return -EINVAL;
++		case V4L2_CID_AUDIO_LOUDNESS:
++		case V4L2_CID_AUDIO_BALANCE:
++		case V4L2_CID_AUDIO_BASS:
++		case V4L2_CID_AUDIO_TREBLE:
++			return v4l2_ctrl_query_fill_std(qc);
++		default:
++			return -EINVAL;
+ 		}
+ 	}
  
--/*
-- * em28xx_v4l2_do_ioctl()
-- * This function is _not_ called directly, but from
-- * em28xx_v4l2_ioctl. Userspace
-- * copying is done already, arg is a kernel pointer.
-- */
--static int em28xx_do_ioctl(struct inode *inode, struct file *filp,
--			   struct em28xx *dev, unsigned int cmd, void *arg,
--			   v4l2_kioctl driver_ioctl)
-+void em28xx_unregister_extension(struct em28xx_ops *ops)
- {
--	int ret;
-+	struct em28xx *h, *dev = NULL;
+@@ -735,13 +741,14 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
+ 				state->volume, state->muted ? " (muted)" : "");
+ 		if (state->has_sound_processing) {
+ 			v4l_info(client, "Audio:    balance %d bass %d treble %d loudness %s\n",
+-					state->balance, state->bass, state->treble,
++					state->balance, state->bass,
++					state->treble,
+ 					state->loudness ? "on" : "off");
+ 		}
+ 		switch (state->mode) {
+ 		case MSP_MODE_AM_DETECT: p = "AM (for carrier detect)"; break;
+ 		case MSP_MODE_FM_RADIO: p = "FM Radio"; break;
+-		case MSP_MODE_FM_TERRA: p = "Terrestial FM-mono + FM-stereo"; break;
++		case MSP_MODE_FM_TERRA: p = "Terrestial FM-mono/stereo"; break;
+ 		case MSP_MODE_FM_SAT: p = "Satellite FM-mono"; break;
+ 		case MSP_MODE_FM_NICAM1: p = "NICAM/FM (B/G, D/K)"; break;
+ 		case MSP_MODE_FM_NICAM2: p = "NICAM/FM (I)"; break;
+@@ -772,7 +779,8 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
+ 	}
  
--	switch (cmd) {
--		/* ---------- tv norms ---------- */
--	case VIDIOC_ENUMSTD:
--	{
--		struct v4l2_standard *e = arg;
--		unsigned int i;
-+	list_for_each_entry(h, &em28xx_devlist, devlist)
-+		dev = h;
+ 	case VIDIOC_G_CHIP_IDENT:
+-		return v4l2_chip_ident_i2c_client(client, arg, state->ident, (state->rev1 << 16) | state->rev2);
++		return v4l2_chip_ident_i2c_client(client, arg, state->ident,
++				(state->rev1 << 16) | state->rev2);
  
--		i = e->index;
--		if (i >= TVNORMS)
--			return -EINVAL;
--		ret = v4l2_video_std_construct(e, tvnorms[e->index].id,
--						tvnorms[e->index].name);
--		e->index = i;
--		if (ret < 0)
--			return ret;
--		return 0;
--	}
--	case VIDIOC_G_STD:
--	{
--		v4l2_std_id *id = arg;
-+	if (dev)
-+		ops->fini(dev);
+ 	default:
+ 		/* unknown */
+@@ -783,7 +791,6 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
  
--		*id = dev->tvnorm->id;
--		return 0;
--	}
--	case VIDIOC_S_STD:
--	{
--		v4l2_std_id *id = arg;
--		unsigned int i;
--
--		for (i = 0; i < TVNORMS; i++)
--			if (*id == tvnorms[i].id)
--				break;
--		if (i == TVNORMS)
--			for (i = 0; i < TVNORMS; i++)
--				if (*id & tvnorms[i].id)
--					break;
--		if (i == TVNORMS)
--			return -EINVAL;
--
--		mutex_lock(&dev->lock);
--		dev->tvnorm = &tvnorms[i];
--
--		em28xx_set_norm(dev, dev->width, dev->height);
--
--		em28xx_i2c_call_clients(dev, VIDIOC_S_STD,
--					&dev->tvnorm->id);
--
--		mutex_unlock(&dev->lock);
--
--		return 0;
--	}
--
--	/* ------ input switching ---------- */
--	case VIDIOC_ENUMINPUT:
--	{
--		struct v4l2_input *i = arg;
--		unsigned int n;
--		static const char *iname[] = {
--			[EM28XX_VMUX_COMPOSITE1] = "Composite1",
--			[EM28XX_VMUX_COMPOSITE2] = "Composite2",
--			[EM28XX_VMUX_COMPOSITE3] = "Composite3",
--			[EM28XX_VMUX_COMPOSITE4] = "Composite4",
--			[EM28XX_VMUX_SVIDEO] = "S-Video",
--			[EM28XX_VMUX_TELEVISION] = "Television",
--			[EM28XX_VMUX_CABLE] = "Cable TV",
--			[EM28XX_VMUX_DVB] = "DVB",
--			[EM28XX_VMUX_DEBUG] = "for debug only",
--		};
--
--		n = i->index;
--		if (n >= MAX_EM28XX_INPUT)
--			return -EINVAL;
--		if (0 == INPUT(n)->type)
--			return -EINVAL;
--		memset(i, 0, sizeof(*i));
--		i->index = n;
--		i->type = V4L2_INPUT_TYPE_CAMERA;
--		strcpy(i->name, iname[INPUT(n)->type]);
--		if ((EM28XX_VMUX_TELEVISION == INPUT(n)->type) ||
--			(EM28XX_VMUX_CABLE == INPUT(n)->type))
--			i->type = V4L2_INPUT_TYPE_TUNER;
--		for (n = 0; n < ARRAY_SIZE(tvnorms); n++)
--			i->std |= tvnorms[n].id;
--		return 0;
--	}
--	case VIDIOC_G_INPUT:
--	{
--		int *i = arg;
--		*i = dev->ctl_input;
--
--		return 0;
--	}
--	case VIDIOC_S_INPUT:
--	{
--		int *index = arg;
--
--		if (*index >= MAX_EM28XX_INPUT)
--			return -EINVAL;
--		if (0 == INPUT(*index)->type)
--			return -EINVAL;
--
--		mutex_lock(&dev->lock);
--		video_mux(dev, *index);
--		mutex_unlock(&dev->lock);
--
--		return 0;
--	}
--	case VIDIOC_G_AUDIO:
--	{
--		struct v4l2_audio *a = arg;
--		unsigned int index = a->index;
--
--		if (a->index > 1)
--			return -EINVAL;
--		memset(a, 0, sizeof(*a));
--		index = dev->ctl_ainput;
--
--		if (index == 0) {
--			strcpy(a->name, "Television");
--		} else {
--			strcpy(a->name, "Line In");
--		}
--		a->capability = V4L2_AUDCAP_STEREO;
--		a->index = index;
--		return 0;
--	}
--	case VIDIOC_S_AUDIO:
--	{
--		struct v4l2_audio *a = arg;
--
--		if (a->index != dev->ctl_ainput)
--			return -EINVAL;
--
--		return 0;
--	}
--
--	/* --- controls ---------------------------------------------- */
--	case VIDIOC_QUERYCTRL:
--	{
--		struct v4l2_queryctrl *qc = arg;
--		int i, id=qc->id;
--
--		memset(qc,0,sizeof(*qc));
--		qc->id=id;
--
--		if (!dev->has_msp34xx) {
--			for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) {
--				if (qc->id && qc->id == em28xx_qctrl[i].id) {
--					memcpy(qc, &(em28xx_qctrl[i]),
--					sizeof(*qc));
--					return 0;
--				}
--			}
--		}
--		em28xx_i2c_call_clients(dev,cmd,qc);
--		if (qc->type)
--			return 0;
--		else
--			return -EINVAL;
--	}
--	case VIDIOC_G_CTRL:
--	{
--		struct v4l2_control *ctrl = arg;
--		int retval=-EINVAL;
--
--		if (!dev->has_msp34xx)
--			retval=em28xx_get_ctrl(dev, ctrl);
--		if (retval==-EINVAL) {
--			em28xx_i2c_call_clients(dev,cmd,arg);
--			return 0;
--		} else return retval;
--	}
--	case VIDIOC_S_CTRL:
--	{
--		struct v4l2_control *ctrl = arg;
--		u8 i;
--
--		if (!dev->has_msp34xx){
--			for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) {
--				if (ctrl->id == em28xx_qctrl[i].id) {
--					if (ctrl->value <
--					em28xx_qctrl[i].minimum
--					|| ctrl->value >
--					em28xx_qctrl[i].maximum)
--						return -ERANGE;
--					return em28xx_set_ctrl(dev, ctrl);
--				}
--			}
--		}
--
--		em28xx_i2c_call_clients(dev,cmd,arg);
--		return 0;
--	}
--	/* --- tuner ioctls ------------------------------------------ */
--	case VIDIOC_G_TUNER:
--	{
--		struct v4l2_tuner *t = arg;
--
--		if (0 != t->index)
--			return -EINVAL;
--
--		memset(t, 0, sizeof(*t));
--		strcpy(t->name, "Tuner");
--		mutex_lock(&dev->lock);
--		/* let clients fill in the remainder of this struct */
--		em28xx_i2c_call_clients(dev, cmd, t);
--		mutex_unlock(&dev->lock);
--		em28xx_videodbg("VIDIO_G_TUNER: signal=%x, afc=%x\n", t->signal,
--				t->afc);
--		return 0;
--	}
--	case VIDIOC_S_TUNER:
--	{
--		struct v4l2_tuner *t = arg;
--
--		if (0 != t->index)
--			return -EINVAL;
--		mutex_lock(&dev->lock);
--		/* let clients handle this */
--		em28xx_i2c_call_clients(dev, cmd, t);
--		mutex_unlock(&dev->lock);
--		return 0;
--	}
--	case VIDIOC_G_FREQUENCY:
--	{
--		struct v4l2_frequency *f = arg;
--
--		memset(f, 0, sizeof(*f));
--		f->type = V4L2_TUNER_ANALOG_TV;
--		f->frequency = dev->ctl_freq;
--
--		return 0;
--	}
--	case VIDIOC_S_FREQUENCY:
--	{
--		struct v4l2_frequency *f = arg;
+ static int msp_suspend(struct i2c_client *client, pm_message_t state)
+ {
 -
--		if (0 != f->tuner)
--			return -EINVAL;
+ 	v4l_dbg(1, msp_debug, client, "suspend\n");
+ 	msp_reset(client);
+ 	return 0;
+@@ -791,7 +798,6 @@ static int msp_suspend(struct i2c_client *client, pm_message_t state)
+ 
+ static int msp_resume(struct i2c_client *client)
+ {
 -
--		if (V4L2_TUNER_ANALOG_TV != f->type)
--			return -EINVAL;
+ 	v4l_dbg(1, msp_debug, client, "resume\n");
+ 	msp_wake_thread(client);
+ 	return 0;
+@@ -799,11 +805,8 @@ static int msp_resume(struct i2c_client *client)
+ 
+ /* ----------------------------------------------------------------------- */
+ 
+-static struct i2c_driver i2c_driver;
 -
--		mutex_lock(&dev->lock);
--		dev->ctl_freq = f->frequency;
--		em28xx_i2c_call_clients(dev, VIDIOC_S_FREQUENCY, f);
--		mutex_unlock(&dev->lock);
--		return 0;
--	}
--	case VIDIOC_CROPCAP:
--	{
--		struct v4l2_cropcap *cc = arg;
+-static int msp_attach(struct i2c_adapter *adapter, int address, int kind)
++static int msp_probe(struct i2c_client *client)
+ {
+-	struct i2c_client *client;
+ 	struct msp_state *state;
+ 	int (*thread_func)(void *data) = NULL;
+ 	int msp_hard;
+@@ -812,26 +815,16 @@ static int msp_attach(struct i2c_adapter *adapter, int address, int kind)
+ 	int msp_product, msp_prod_hi, msp_prod_lo;
+ 	int msp_rom;
+ 
+-	client = kzalloc(sizeof(*client), GFP_KERNEL);
+-	if (!client)
+-		return -ENOMEM;
 -
--		if (cc->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
--			return -EINVAL;
--		cc->bounds.left = 0;
--		cc->bounds.top = 0;
--		cc->bounds.width = dev->width;
--		cc->bounds.height = dev->height;
--		cc->defrect = cc->bounds;
--		cc->pixelaspect.numerator = 54;	/* 4:3 FIXME: remove magic numbers */
--		cc->pixelaspect.denominator = 59;
+-	client->addr = address;
+-	client->adapter = adapter;
+-	client->driver = &i2c_driver;
+ 	snprintf(client->name, sizeof(client->name) - 1, "msp3400");
+ 
+ 	if (msp_reset(client) == -1) {
+ 		v4l_dbg(1, msp_debug, client, "msp3400 not found\n");
+-		kfree(client);
 -		return 0;
++		return -ENODEV;
+ 	}
+ 
+ 	state = kzalloc(sizeof(*state), GFP_KERNEL);
+-	if (!state) {
+-		kfree(client);
++	if (!state)
+ 		return -ENOMEM;
 -	}
--	case VIDIOC_STREAMON:
--	{
--		int *type = arg;
--
--		if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE
--			|| dev->io != IO_MMAP)
--			return -EINVAL;
--
--		if (list_empty(&dev->inqueue))
--			return -EINVAL;
--
--		dev->stream = STREAM_ON;	/* FIXME: Start video capture here? */
--
--		em28xx_videodbg("VIDIOC_STREAMON: starting stream\n");
--
+ 
+ 	i2c_set_clientdata(client, state);
+ 
+@@ -853,12 +846,13 @@ static int msp_attach(struct i2c_adapter *adapter, int address, int kind)
+ 	state->rev1 = msp_read_dsp(client, 0x1e);
+ 	if (state->rev1 != -1)
+ 		state->rev2 = msp_read_dsp(client, 0x1f);
+-	v4l_dbg(1, msp_debug, client, "rev1=0x%04x, rev2=0x%04x\n", state->rev1, state->rev2);
++	v4l_dbg(1, msp_debug, client, "rev1=0x%04x, rev2=0x%04x\n",
++			state->rev1, state->rev2);
+ 	if (state->rev1 == -1 || (state->rev1 == 0 && state->rev2 == 0)) {
+-		v4l_dbg(1, msp_debug, client, "not an msp3400 (cannot read chip version)\n");
++		v4l_dbg(1, msp_debug, client,
++				"not an msp3400 (cannot read chip version)\n");
+ 		kfree(state);
+-		kfree(client);
 -		return 0;
--	}
--	case VIDIOC_STREAMOFF:
--	{
--		int *type = arg;
--		int ret;
--
--		if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE
--			|| dev->io != IO_MMAP)
--			return -EINVAL;
++		return -ENODEV;
+ 	}
+ 
+ 	msp_set_audio(client);
+@@ -874,37 +868,55 @@ static int msp_attach(struct i2c_adapter *adapter, int address, int kind)
+ 			msp_family, msp_product,
+ 			msp_revision, msp_hard, msp_rom);
+ 	/* Rev B=2, C=3, D=4, G=7 */
+-	state->ident = msp_family * 10000 + 4000 + msp_product * 10 + msp_revision - '@';
++	state->ident = msp_family * 10000 + 4000 + msp_product * 10 +
++			msp_revision - '@';
+ 
+ 	/* Has NICAM support: all mspx41x and mspx45x products have NICAM */
+-	state->has_nicam = msp_prod_hi == 1 || msp_prod_hi == 5;
++	state->has_nicam =
++		msp_prod_hi == 1 || msp_prod_hi == 5;
+ 	/* Has radio support: was added with revision G */
+-	state->has_radio = msp_revision >= 'G';
++	state->has_radio =
++		msp_revision >= 'G';
+ 	/* Has headphones output: not for stripped down products */
+-	state->has_headphones = msp_prod_lo < 5;
++	state->has_headphones =
++		msp_prod_lo < 5;
+ 	/* Has scart2 input: not in stripped down products of the '3' family */
+-	state->has_scart2 = msp_family >= 4 || msp_prod_lo < 7;
++	state->has_scart2 =
++		msp_family >= 4 || msp_prod_lo < 7;
+ 	/* Has scart3 input: not in stripped down products of the '3' family */
+-	state->has_scart3 = msp_family >= 4 || msp_prod_lo < 5;
++	state->has_scart3 =
++		msp_family >= 4 || msp_prod_lo < 5;
+ 	/* Has scart4 input: not in pre D revisions, not in stripped D revs */
+-	state->has_scart4 = msp_family >= 4 || (msp_revision >= 'D' && msp_prod_lo < 5);
+-	/* Has scart2 output: not in stripped down products of the '3' family */
+-	state->has_scart2_out = msp_family >= 4 || msp_prod_lo < 5;
++	state->has_scart4 =
++		msp_family >= 4 || (msp_revision >= 'D' && msp_prod_lo < 5);
++	/* Has scart2 output: not in stripped down products of
++	 * the '3' family */
++	state->has_scart2_out =
++		msp_family >= 4 || msp_prod_lo < 5;
+ 	/* Has scart2 a volume control? Not in pre-D revisions. */
+-	state->has_scart2_out_volume = msp_revision > 'C' && state->has_scart2_out;
++	state->has_scart2_out_volume =
++		msp_revision > 'C' && state->has_scart2_out;
+ 	/* Has a configurable i2s out? */
+-	state->has_i2s_conf = msp_revision >= 'G' && msp_prod_lo < 7;
+-	/* Has subwoofer output: not in pre-D revs and not in stripped down products */
+-	state->has_subwoofer = msp_revision >= 'D' && msp_prod_lo < 5;
+-	/* Has soundprocessing (bass/treble/balance/loudness/equalizer): not in
+-	   stripped down products */
+-	state->has_sound_processing = msp_prod_lo < 7;
++	state->has_i2s_conf =
++		msp_revision >= 'G' && msp_prod_lo < 7;
++	/* Has subwoofer output: not in pre-D revs and not in stripped down
++	 * products */
++	state->has_subwoofer =
++		msp_revision >= 'D' && msp_prod_lo < 5;
++	/* Has soundprocessing (bass/treble/balance/loudness/equalizer):
++	 *  not in stripped down products */
++	state->has_sound_processing =
++		msp_prod_lo < 7;
+ 	/* Has Virtual Dolby Surround: only in msp34x1 */
+-	state->has_virtual_dolby_surround = msp_revision == 'G' && msp_prod_lo == 1;
++	state->has_virtual_dolby_surround =
++		msp_revision == 'G' && msp_prod_lo == 1;
+ 	/* Has Virtual Dolby Surround & Dolby Pro Logic: only in msp34x2 */
+-	state->has_dolby_pro_logic = msp_revision == 'G' && msp_prod_lo == 2;
+-	/* The msp343xG supports BTSC only and cannot do Automatic Standard Detection. */
+-	state->force_btsc = msp_family == 3 && msp_revision == 'G' && msp_prod_hi == 3;
++	state->has_dolby_pro_logic =
++		msp_revision == 'G' && msp_prod_lo == 2;
++	/* The msp343xG supports BTSC only and cannot do Automatic Standard
++	 * Detection. */
++	state->force_btsc =
++		msp_family == 3 && msp_revision == 'G' && msp_prod_hi == 3;
+ 
+ 	state->opmode = opmode;
+ 	if (state->opmode == OPMODE_AUTO) {
+@@ -919,32 +931,33 @@ static int msp_attach(struct i2c_adapter *adapter, int address, int kind)
+ 	}
+ 
+ 	/* hello world :-) */
+-	v4l_info(client, "%s found @ 0x%x (%s)\n", client->name, address << 1, adapter->name);
++	v4l_info(client, "%s found @ 0x%x (%s)\n", client->name,
++			client->addr << 1, client->adapter->name);
+ 	v4l_info(client, "%s ", client->name);
+ 	if (state->has_nicam && state->has_radio)
+-		printk("supports nicam and radio, ");
++		printk(KERN_CONT "supports nicam and radio, ");
+ 	else if (state->has_nicam)
+-		printk("supports nicam, ");
++		printk(KERN_CONT "supports nicam, ");
+ 	else if (state->has_radio)
+-		printk("supports radio, ");
+-	printk("mode is ");
++		printk(KERN_CONT "supports radio, ");
++	printk(KERN_CONT "mode is ");
+ 
+ 	/* version-specific initialization */
+ 	switch (state->opmode) {
+ 	case OPMODE_MANUAL:
+-		printk("manual");
++		printk(KERN_CONT "manual");
+ 		thread_func = msp3400c_thread;
+ 		break;
+ 	case OPMODE_AUTODETECT:
+-		printk("autodetect");
++		printk(KERN_CONT "autodetect");
+ 		thread_func = msp3410d_thread;
+ 		break;
+ 	case OPMODE_AUTOSELECT:
+-		printk("autodetect and autoselect");
++		printk(KERN_CONT "autodetect and autoselect");
+ 		thread_func = msp34xxg_thread;
+ 		break;
+ 	}
+-	printk("\n");
++	printk(KERN_CONT "\n");
+ 
+ 	/* startup control thread if needed */
+ 	if (thread_func) {
+@@ -954,24 +967,12 @@ static int msp_attach(struct i2c_adapter *adapter, int address, int kind)
+ 			v4l_warn(client, "kernel_thread() failed\n");
+ 		msp_wake_thread(client);
+ 	}
 -
--		if (dev->stream == STREAM_ON) {
--			em28xx_videodbg ("VIDIOC_STREAMOFF: interrupting stream\n");
--			if ((ret = em28xx_stream_interrupt(dev)))
--				return ret;
--		}
--		em28xx_empty_framequeues(dev);
+-	/* done */
+-	i2c_attach_client(client);
 -
--		return 0;
--	}
--	default:
--		return v4l_compat_translate_ioctl(inode, filp, cmd, arg,
--						  driver_ioctl);
--	}
+ 	return 0;
+ }
+ 
+-static int msp_probe(struct i2c_adapter *adapter)
+-{
+-	if (adapter->class & I2C_CLASS_TV_ANALOG)
+-		return i2c_probe(adapter, &addr_data, msp_attach);
 -	return 0;
 -}
 -
--/*
-- * em28xx_v4l2_do_ioctl()
-- * This function is _not_ called directly, but from
-- * em28xx_v4l2_ioctl. Userspace
-- * copying is done already, arg is a kernel pointer.
-- */
--static int em28xx_video_do_ioctl(struct inode *inode, struct file *filp,
--				 unsigned int cmd, void *arg)
--{
--	struct em28xx *dev = filp->private_data;
--
--	if (!dev)
--		return -ENODEV;
--
--	if (video_debug > 1)
--		v4l_print_ioctl(dev->name,cmd);
--
--	switch (cmd) {
--
--		/* --- capabilities ------------------------------------------ */
--	case VIDIOC_QUERYCAP:
--		{
--		struct v4l2_capability *cap = arg;
--
--		memset(cap, 0, sizeof(*cap));
--		strlcpy(cap->driver, "em28xx", sizeof(cap->driver));
--		strlcpy(cap->card, em28xx_boards[dev->model].name,
--			sizeof(cap->card));
--		strlcpy(cap->bus_info, dev->udev->dev.bus_id,
--			sizeof(cap->bus_info));
--		cap->version = EM28XX_VERSION_CODE;
--		cap->capabilities =
--				V4L2_CAP_SLICED_VBI_CAPTURE |
--				V4L2_CAP_VIDEO_CAPTURE |
--				V4L2_CAP_AUDIO |
--				V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
--		if (dev->has_tuner)
--			cap->capabilities |= V4L2_CAP_TUNER;
--		return 0;
--	}
--	/* --- capture ioctls ---------------------------------------- */
--	case VIDIOC_ENUM_FMT:
--	{
--		struct v4l2_fmtdesc *fmtd = arg;
--
--		if (fmtd->index != 0)
--			return -EINVAL;
--		memset(fmtd, 0, sizeof(*fmtd));
--		fmtd->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
--		strcpy(fmtd->description, "Packed YUY2");
--		fmtd->pixelformat = V4L2_PIX_FMT_YUYV;
--		memset(fmtd->reserved, 0, sizeof(fmtd->reserved));
--		return 0;
--	}
--	case VIDIOC_G_FMT:
--		return em28xx_get_fmt(dev, (struct v4l2_format *) arg);
--
--	case VIDIOC_TRY_FMT:
--	case VIDIOC_S_FMT:
--		return em28xx_set_fmt(dev, cmd, (struct v4l2_format *)arg);
--
--	case VIDIOC_REQBUFS:
--	{
--		struct v4l2_requestbuffers *rb = arg;
--		u32 i;
--		int ret;
--
--		if (rb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
--			rb->memory != V4L2_MEMORY_MMAP)
--			return -EINVAL;
--
--		if (dev->io == IO_READ) {
--			em28xx_videodbg ("method is set to read;"
--				" close and open the device again to"
--				" choose the mmap I/O method\n");
--			return -EINVAL;
--		}
--
--		for (i = 0; i < dev->num_frames; i++)
--			if (dev->frame[i].vma_use_count) {
--				em28xx_videodbg ("VIDIOC_REQBUFS failed; previous buffers are still mapped\n");
--				return -EINVAL;
--			}
--
--		if (dev->stream == STREAM_ON) {
--			em28xx_videodbg("VIDIOC_REQBUFS: interrupting stream\n");
--			if ((ret = em28xx_stream_interrupt(dev)))
--				return ret;
--		}
--
--		em28xx_empty_framequeues(dev);
--
--		em28xx_release_buffers(dev);
--		if (rb->count)
--			rb->count =
--				em28xx_request_buffers(dev, rb->count);
--
--		dev->frame_current = NULL;
--
--		em28xx_videodbg ("VIDIOC_REQBUFS: setting io method to mmap: num bufs %i\n",
--						rb->count);
--		dev->io = rb->count ? IO_MMAP : IO_NONE;
--		return 0;
--	}
--	case VIDIOC_QUERYBUF:
--	{
--		struct v4l2_buffer *b = arg;
--
--		if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
--			b->index >= dev->num_frames || dev->io != IO_MMAP)
--			return -EINVAL;
--
--		memcpy(b, &dev->frame[b->index].buf, sizeof(*b));
--
--		if (dev->frame[b->index].vma_use_count) {
--			b->flags |= V4L2_BUF_FLAG_MAPPED;
--		}
--		if (dev->frame[b->index].state == F_DONE)
--			b->flags |= V4L2_BUF_FLAG_DONE;
--		else if (dev->frame[b->index].state != F_UNUSED)
--			b->flags |= V4L2_BUF_FLAG_QUEUED;
--		return 0;
--	}
--	case VIDIOC_QBUF:
--	{
--		struct v4l2_buffer *b = arg;
--		unsigned long lock_flags;
--
--		if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
--			b->index >= dev->num_frames || dev->io != IO_MMAP) {
--			return -EINVAL;
--		}
--
--		if (dev->frame[b->index].state != F_UNUSED) {
--			return -EAGAIN;
--		}
--		dev->frame[b->index].state = F_QUEUED;
--
--		/* add frame to fifo */
--		spin_lock_irqsave(&dev->queue_lock, lock_flags);
--		list_add_tail(&dev->frame[b->index].frame,
--				&dev->inqueue);
--		spin_unlock_irqrestore(&dev->queue_lock, lock_flags);
--
--		return 0;
+-static int msp_detach(struct i2c_client *client)
++static int msp_remove(struct i2c_client *client)
+ {
+ 	struct msp_state *state = i2c_get_clientdata(client);
+-	int err;
+ 
+ 	/* shutdown control thread */
+ 	if (state->kthread) {
+@@ -980,43 +981,22 @@ static int msp_detach(struct i2c_client *client)
+ 	}
+ 	msp_reset(client);
+ 
+-	err = i2c_detach_client(client);
+-	if (err) {
+-		return err;
 -	}
--	case VIDIOC_DQBUF:
--	{
--		struct v4l2_buffer *b = arg;
--		struct em28xx_frame_t *f;
--		unsigned long lock_flags;
--		int ret = 0;
--
--		if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE
--			|| dev->io != IO_MMAP)
--			return -EINVAL;
--
--		if (list_empty(&dev->outqueue)) {
--			if (dev->stream == STREAM_OFF)
--				return -EINVAL;
--			if (filp->f_flags & O_NONBLOCK)
--				return -EAGAIN;
--			ret = wait_event_interruptible
--				(dev->wait_frame,
--				(!list_empty(&dev->outqueue)) ||
--				(dev->state & DEV_DISCONNECTED));
--			if (ret)
--				return ret;
--			if (dev->state & DEV_DISCONNECTED)
--				return -ENODEV;
--		}
--
--		spin_lock_irqsave(&dev->queue_lock, lock_flags);
--		f = list_entry(dev->outqueue.next,
--				struct em28xx_frame_t, frame);
--		list_del(dev->outqueue.next);
--		spin_unlock_irqrestore(&dev->queue_lock, lock_flags);
 -
--		f->state = F_UNUSED;
--		memcpy(b, &f->buf, sizeof(*b));
+ 	kfree(state);
+-	kfree(client);
+ 	return 0;
+ }
+ 
+ /* ----------------------------------------------------------------------- */
+ 
+-/* i2c implementation */
+-static struct i2c_driver i2c_driver = {
+-	.id             = I2C_DRIVERID_MSP3400,
+-	.attach_adapter = msp_probe,
+-	.detach_client  = msp_detach,
++static struct v4l2_i2c_driver_data v4l2_i2c_data = {
++	.name = "msp3400",
++	.driverid = I2C_DRIVERID_MSP3400,
++	.command = msp_command,
++	.probe = msp_probe,
++	.remove = msp_remove,
+ 	.suspend = msp_suspend,
+-	.resume  = msp_resume,
+-	.command        = msp_command,
+-	.driver = {
+-		.name    = "msp3400",
+-	},
++	.resume = msp_resume,
+ };
+ 
+-static int __init msp3400_init_module(void)
+-{
+-	return i2c_add_driver(&i2c_driver);
+-}
 -
--		if (f->vma_use_count)
--			b->flags |= V4L2_BUF_FLAG_MAPPED;
+-static void __exit msp3400_cleanup_module(void)
+-{
+-	i2c_del_driver(&i2c_driver);
+-}
 -
--		return 0;
+-module_init(msp3400_init_module);
+-module_exit(msp3400_cleanup_module);
+ 
+ /*
+  * Overrides for Emacs so that we follow Linus's tabbing style.
+diff --git a/drivers/media/video/msp3400-kthreads.c b/drivers/media/video/msp3400-kthreads.c
+index d5ee262..61ec794 100644
+--- a/drivers/media/video/msp3400-kthreads.c
++++ b/drivers/media/video/msp3400-kthreads.c
+@@ -15,7 +15,8 @@
+  *
+  * You 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.
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
++ * 02110-1301, USA.
+  */
+ 
+ 
+@@ -78,37 +79,37 @@ static struct msp3400c_init_data_dem {
+ 		{75, 19, 36, 35, 39, 40},
+ 		MSP_CARRIER(5.5), MSP_CARRIER(5.5),
+ 		0x00d0, 0x0500, 0x0020, 0x3000
+-	},{	/* AM (for carrier detect / msp3410) */
++	}, {	/* AM (for carrier detect / msp3410) */
+ 		{-1, -1, -8, 2, 59, 126},
+ 		{-1, -1, -8, 2, 59, 126},
+ 		MSP_CARRIER(5.5), MSP_CARRIER(5.5),
+ 		0x00d0, 0x0100, 0x0020, 0x3000
+-	},{	/* FM Radio */
++	}, {	/* FM Radio */
+ 		{-8, -8, 4, 6, 78, 107},
+ 		{-8, -8, 4, 6, 78, 107},
+ 		MSP_CARRIER(10.7), MSP_CARRIER(10.7),
+ 		0x00d0, 0x0480, 0x0020, 0x3000
+-	},{	/* Terrestial FM-mono + FM-stereo */
++	}, {	/* Terrestial FM-mono + FM-stereo */
+ 		{3, 18, 27, 48, 66, 72},
+ 		{3, 18, 27, 48, 66, 72},
+ 		MSP_CARRIER(5.5), MSP_CARRIER(5.5),
+ 		0x00d0, 0x0480, 0x0030, 0x3000
+-	},{	/* Sat FM-mono */
++	}, {	/* Sat FM-mono */
+ 		{ 1, 9, 14, 24, 33, 37},
+ 		{ 3, 18, 27, 48, 66, 72},
+ 		MSP_CARRIER(6.5), MSP_CARRIER(6.5),
+ 		0x00c6, 0x0480, 0x0000, 0x3000
+-	},{	/* NICAM/FM --  B/G (5.5/5.85), D/K (6.5/5.85) */
++	}, {	/* NICAM/FM --  B/G (5.5/5.85), D/K (6.5/5.85) */
+ 		{-2, -8, -10, 10, 50, 86},
+ 		{3, 18, 27, 48, 66, 72},
+ 		MSP_CARRIER(5.5), MSP_CARRIER(5.5),
+ 		0x00d0, 0x0040, 0x0120, 0x3000
+-	},{	/* NICAM/FM -- I (6.0/6.552) */
++	}, {	/* NICAM/FM -- I (6.0/6.552) */
+ 		{2, 4, -6, -4, 40, 94},
+ 		{3, 18, 27, 48, 66, 72},
+ 		MSP_CARRIER(6.0), MSP_CARRIER(6.0),
+ 		0x00d0, 0x0040, 0x0120, 0x3000
+-	},{	/* NICAM/AM -- L (6.5/5.85) */
++	}, {	/* NICAM/AM -- L (6.5/5.85) */
+ 		{-2, -8, -10, 10, 50, 86},
+ 		{-4, -12, -9, 23, 79, 126},
+ 		MSP_CARRIER(6.5), MSP_CARRIER(6.5),
+@@ -224,7 +225,9 @@ void msp3400c_set_mode(struct i2c_client *client, int mode)
+    nor do they support stereo BTSC. */
+ static void msp3400c_set_audmode(struct i2c_client *client)
+ {
+-	static char *strmode[] = { "mono", "stereo", "lang2", "lang1", "lang1+lang2" };
++	static char *strmode[] = {
++		"mono", "stereo", "lang2", "lang1", "lang1+lang2"
++	};
+ 	struct msp_state *state = i2c_get_clientdata(client);
+ 	char *modestr = (state->audmode >= 0 && state->audmode < 5) ?
+ 		strmode[state->audmode] : "unknown";
+@@ -298,19 +301,23 @@ static void msp3400c_set_audmode(struct i2c_client *client)
+ 	case MSP_MODE_FM_NICAM1:
+ 	case MSP_MODE_FM_NICAM2:
+ 	case MSP_MODE_AM_NICAM:
+-		v4l_dbg(1, msp_debug, client, "NICAM set_audmode: %s\n",modestr);
++		v4l_dbg(1, msp_debug, client,
++			"NICAM set_audmode: %s\n", modestr);
+ 		if (state->nicam_on)
+ 			src = 0x0100;  /* NICAM */
+ 		break;
+ 	case MSP_MODE_BTSC:
+-		v4l_dbg(1, msp_debug, client, "BTSC set_audmode: %s\n",modestr);
++		v4l_dbg(1, msp_debug, client,
++			"BTSC set_audmode: %s\n", modestr);
+ 		break;
+ 	case MSP_MODE_EXTERN:
+-		v4l_dbg(1, msp_debug, client, "extern set_audmode: %s\n",modestr);
++		v4l_dbg(1, msp_debug, client,
++			"extern set_audmode: %s\n", modestr);
+ 		src = 0x0200;  /* SCART */
+ 		break;
+ 	case MSP_MODE_FM_RADIO:
+-		v4l_dbg(1, msp_debug, client, "FM-Radio set_audmode: %s\n",modestr);
++		v4l_dbg(1, msp_debug, client,
++			"FM-Radio set_audmode: %s\n", modestr);
+ 		break;
+ 	default:
+ 		v4l_dbg(1, msp_debug, client, "mono set_audmode\n");
+@@ -342,7 +349,8 @@ static void msp3400c_set_audmode(struct i2c_client *client)
+ 		src |= 0x0010;
+ 		break;
+ 	}
+-	v4l_dbg(1, msp_debug, client, "set_audmode final source/matrix = 0x%x\n", src);
++	v4l_dbg(1, msp_debug, client,
++		"set_audmode final source/matrix = 0x%x\n", src);
+ 
+ 	msp_set_source(client, src);
+ }
+@@ -351,22 +359,26 @@ static void msp3400c_print_mode(struct i2c_client *client)
+ {
+ 	struct msp_state *state = i2c_get_clientdata(client);
+ 
+-	if (state->main == state->second) {
+-		v4l_dbg(1, msp_debug, client, "mono sound carrier: %d.%03d MHz\n",
+-		       state->main / 910000, (state->main / 910) % 1000);
+-	} else {
+-		v4l_dbg(1, msp_debug, client, "main sound carrier: %d.%03d MHz\n",
+-		       state->main / 910000, (state->main / 910) % 1000);
 -	}
--	default:
--		return em28xx_do_ioctl(inode, filp, dev, cmd, arg,
--				       em28xx_video_do_ioctl);
++	if (state->main == state->second)
++		v4l_dbg(1, msp_debug, client,
++			"mono sound carrier: %d.%03d MHz\n",
++			state->main / 910000, (state->main / 910) % 1000);
++	else
++		v4l_dbg(1, msp_debug, client,
++			"main sound carrier: %d.%03d MHz\n",
++			state->main / 910000, (state->main / 910) % 1000);
+ 	if (state->mode == MSP_MODE_FM_NICAM1 || state->mode == MSP_MODE_FM_NICAM2)
+-		v4l_dbg(1, msp_debug, client, "NICAM/FM carrier  : %d.%03d MHz\n",
+-		       state->second / 910000, (state->second/910) % 1000);
++		v4l_dbg(1, msp_debug, client,
++			"NICAM/FM carrier  : %d.%03d MHz\n",
++			state->second / 910000, (state->second/910) % 1000);
+ 	if (state->mode == MSP_MODE_AM_NICAM)
+-		v4l_dbg(1, msp_debug, client, "NICAM/AM carrier  : %d.%03d MHz\n",
+-		       state->second / 910000, (state->second / 910) % 1000);
++		v4l_dbg(1, msp_debug, client,
++			"NICAM/AM carrier  : %d.%03d MHz\n",
++			state->second / 910000, (state->second / 910) % 1000);
+ 	if (state->mode == MSP_MODE_FM_TERRA && state->main != state->second) {
+-		v4l_dbg(1, msp_debug, client, "FM-stereo carrier : %d.%03d MHz\n",
+-		       state->second / 910000, (state->second / 910) % 1000);
++		v4l_dbg(1, msp_debug, client,
++			"FM-stereo carrier : %d.%03d MHz\n",
++			state->second / 910000, (state->second / 910) % 1000);
+ 	}
+ }
+ 
+@@ -385,7 +397,8 @@ static int msp3400c_detect_stereo(struct i2c_client *client)
+ 		val = msp_read_dsp(client, 0x18);
+ 		if (val > 32767)
+ 			val -= 65536;
+-		v4l_dbg(2, msp_debug, client, "stereo detect register: %d\n", val);
++		v4l_dbg(2, msp_debug, client,
++			"stereo detect register: %d\n", val);
+ 		if (val > 8192) {
+ 			rxsubchans = V4L2_TUNER_SUB_STEREO;
+ 		} else if (val < -4096) {
+@@ -430,7 +443,8 @@ static int msp3400c_detect_stereo(struct i2c_client *client)
+ 	}
+ 	if (rxsubchans != state->rxsubchans) {
+ 		update = 1;
+-		v4l_dbg(1, msp_debug, client, "watch: rxsubchans %02x => %02x\n",
++		v4l_dbg(1, msp_debug, client,
++			"watch: rxsubchans %02x => %02x\n",
+ 			state->rxsubchans, rxsubchans);
+ 		state->rxsubchans = rxsubchans;
+ 	}
+@@ -452,9 +466,8 @@ static void watch_stereo(struct i2c_client *client)
+ {
+ 	struct msp_state *state = i2c_get_clientdata(client);
+ 
+-	if (msp_detect_stereo(client)) {
++	if (msp_detect_stereo(client))
+ 		msp_set_audmode(client);
 -	}
--	return 0;
-+	mutex_lock(&em28xx_extension_devlist_lock);
-+	printk(KERN_INFO "Em28xx: Removed (%s) extension\n", ops->name);
-+	list_del(&ops->next);
-+	mutex_unlock(&em28xx_extension_devlist_lock);
+ 
+ 	if (msp_once)
+ 		state->watch_stereo = 0;
+@@ -465,7 +478,7 @@ int msp3400c_thread(void *data)
+ 	struct i2c_client *client = data;
+ 	struct msp_state *state = i2c_get_clientdata(client);
+ 	struct msp3400c_carrier_detect *cd;
+-	int count, max1, max2, val1, val2, val, this;
++	int count, max1, max2, val1, val2, val, i;
+ 
+ 
+ 	v4l_dbg(1, msp_debug, client, "msp3400 daemon started\n");
+@@ -475,7 +488,7 @@ int msp3400c_thread(void *data)
+ 		msp_sleep(state, -1);
+ 		v4l_dbg(2, msp_debug, client, "msp3400 thread: wakeup\n");
+ 
+-	restart:
++restart:
+ 		v4l_dbg(2, msp_debug, client, "thread: restart scan\n");
+ 		state->restart = 0;
+ 		if (kthread_should_stop())
+@@ -483,7 +496,8 @@ int msp3400c_thread(void *data)
+ 
+ 		if (state->radio || MSP_MODE_EXTERN == state->mode) {
+ 			/* no carrier scan, just unmute */
+-			v4l_dbg(1, msp_debug, client, "thread: no carrier scan\n");
++			v4l_dbg(1, msp_debug, client,
++				"thread: no carrier scan\n");
+ 			state->scan_in_progress = 0;
+ 			msp_set_audio(client);
+ 			continue;
+@@ -514,16 +528,17 @@ int msp3400c_thread(void *data)
+ 			v4l_dbg(1, msp_debug, client, "AM sound override\n");
+ 		}
+ 
+-		for (this = 0; this < count; this++) {
+-			msp3400c_set_carrier(client, cd[this].cdo, cd[this].cdo);
+-			if (msp_sleep(state,100))
++		for (i = 0; i < count; i++) {
++			msp3400c_set_carrier(client, cd[i].cdo, cd[i].cdo);
++			if (msp_sleep(state, 100))
+ 				goto restart;
+ 			val = msp_read_dsp(client, 0x1b);
+ 			if (val > 32767)
+ 				val -= 65536;
+ 			if (val1 < val)
+-				val1 = val, max1 = this;
+-			v4l_dbg(1, msp_debug, client, "carrier1 val: %5d / %s\n", val,cd[this].name);
++				val1 = val, max1 = i;
++			v4l_dbg(1, msp_debug, client,
++				"carrier1 val: %5d / %s\n", val, cd[i].name);
+ 		}
+ 
+ 		/* carrier detect pass #2 -- second (stereo) carrier */
+@@ -550,16 +565,17 @@ int msp3400c_thread(void *data)
+ 			count = 0;
+ 			max2 = 0;
+ 		}
+-		for (this = 0; this < count; this++) {
+-			msp3400c_set_carrier(client, cd[this].cdo, cd[this].cdo);
+-			if (msp_sleep(state,100))
++		for (i = 0; i < count; i++) {
++			msp3400c_set_carrier(client, cd[i].cdo, cd[i].cdo);
++			if (msp_sleep(state, 100))
+ 				goto restart;
+ 			val = msp_read_dsp(client, 0x1b);
+ 			if (val > 32767)
+ 				val -= 65536;
+ 			if (val2 < val)
+-				val2 = val, max2 = this;
+-			v4l_dbg(1, msp_debug, client, "carrier2 val: %5d / %s\n", val,cd[this].name);
++				val2 = val, max2 = i;
++			v4l_dbg(1, msp_debug, client,
++				"carrier2 val: %5d / %s\n", val, cd[i].name);
+ 		}
+ 
+ 		/* program the msp3400 according to the results */
+@@ -611,7 +627,7 @@ int msp3400c_thread(void *data)
+ 			break;
+ 		case 0: /* 4.5 */
+ 		default:
+-		no_second:
++no_second:
+ 			state->second = msp3400c_carrier_detect_main[max1].cdo;
+ 			msp3400c_set_mode(client, MSP_MODE_FM_TERRA);
+ 			break;
+@@ -632,7 +648,8 @@ int msp3400c_thread(void *data)
+ 		while (state->watch_stereo) {
+ 			if (msp_sleep(state, count ? 1000 : 5000))
+ 				goto restart;
+-			if (count) count--;
++			if (count)
++				count--;
+ 			watch_stereo(client);
+ 		}
+ 	}
+@@ -651,10 +668,10 @@ int msp3410d_thread(void *data)
+ 	set_freezable();
+ 	for (;;) {
+ 		v4l_dbg(2, msp_debug, client, "msp3410 thread: sleep\n");
+-		msp_sleep(state,-1);
++		msp_sleep(state, -1);
+ 		v4l_dbg(2, msp_debug, client, "msp3410 thread: wakeup\n");
+ 
+-	restart:
++restart:
+ 		v4l_dbg(2, msp_debug, client, "thread: restart scan\n");
+ 		state->restart = 0;
+ 		if (kthread_should_stop())
+@@ -662,7 +679,8 @@ int msp3410d_thread(void *data)
+ 
+ 		if (state->mode == MSP_MODE_EXTERN) {
+ 			/* no carrier scan needed, just unmute */
+-			v4l_dbg(1, msp_debug, client, "thread: no carrier scan\n");
++			v4l_dbg(1, msp_debug, client,
++				"thread: no carrier scan\n");
+ 			state->scan_in_progress = 0;
+ 			msp_set_audio(client);
+ 			continue;
+@@ -673,7 +691,8 @@ int msp3410d_thread(void *data)
+ 		msp_set_audio(client);
+ 
+ 		/* start autodetect. Note: autodetect is not supported for
+-		   NTSC-M and radio, hence we force the standard in those cases. */
++		   NTSC-M and radio, hence we force the standard in those
++		   cases. */
+ 		if (state->radio)
+ 			std = 0x40;
+ 		else
+@@ -686,8 +705,9 @@ int msp3410d_thread(void *data)
+ 			goto restart;
+ 
+ 		if (msp_debug)
+-			v4l_dbg(2, msp_debug, client, "setting standard: %s (0x%04x)\n",
+-			       msp_standard_std_name(std), std);
++			v4l_dbg(2, msp_debug, client,
++				"setting standard: %s (0x%04x)\n",
++				msp_standard_std_name(std), std);
+ 
+ 		if (std != 1) {
+ 			/* programmed some specific mode */
+@@ -703,7 +723,8 @@ int msp3410d_thread(void *data)
+ 				val = msp_read_dem(client, 0x7e);
+ 				if (val < 0x07ff)
+ 					break;
+-				v4l_dbg(2, msp_debug, client, "detection still in progress\n");
++				v4l_dbg(2, msp_debug, client,
++					"detection still in progress\n");
+ 			}
+ 		}
+ 		for (i = 0; msp_stdlist[i].name != NULL; i++)
+@@ -716,12 +737,13 @@ int msp3410d_thread(void *data)
+ 		state->std = val;
+ 		state->rxsubchans = V4L2_TUNER_SUB_MONO;
+ 
+-		if (msp_amsound && !state->radio && (state->v4l2_std & V4L2_STD_SECAM) &&
+-				(val != 0x0009)) {
++		if (msp_amsound && !state->radio &&
++		    (state->v4l2_std & V4L2_STD_SECAM) && (val != 0x0009)) {
+ 			/* autodetection has failed, let backup */
+ 			v4l_dbg(1, msp_debug, client, "autodetection failed,"
+ 				" switching to backup standard: %s (0x%04x)\n",
+-				msp_stdlist[8].name ? msp_stdlist[8].name : "unknown",val);
++				msp_stdlist[8].name ?
++					msp_stdlist[8].name : "unknown", val);
+ 			state->std = val = 0x0009;
+ 			msp_write_dem(client, 0x20, val);
+ 		}
+@@ -786,7 +808,8 @@ int msp3410d_thread(void *data)
+ 		while (state->watch_stereo) {
+ 			if (msp_sleep(state, count ? 1000 : 5000))
+ 				goto restart;
+-			if (count) count--;
++			if (count)
++				count--;
+ 			watch_stereo(client);
+ 		}
+ 	}
+@@ -872,8 +895,8 @@ static void msp34xxg_set_source(struct i2c_client *client, u16 reg, int in)
+ 	else
+ 		source = (in << 8) | matrix;
+ 
+-	v4l_dbg(1, msp_debug, client, "set source to %d (0x%x) for output %02x\n",
+-			in, source, reg);
++	v4l_dbg(1, msp_debug, client,
++		"set source to %d (0x%x) for output %02x\n", in, source, reg);
+ 	msp_write_dsp(client, reg, source);
  }
-+EXPORT_SYMBOL(em28xx_unregister_extension);
  
--/*
-- * em28xx_v4l2_ioctl()
-- * handle v4l2 ioctl the main action happens in em28xx_v4l2_do_ioctl()
-- */
--static int em28xx_v4l2_ioctl(struct inode *inode, struct file *filp,
--			     unsigned int cmd, unsigned long arg)
-+struct video_device *em28xx_vdev_init(struct em28xx *dev,
-+				      const struct video_device *template,
-+				      const int type,
-+				      const char *type_name)
+@@ -948,7 +971,7 @@ int msp34xxg_thread(void *data)
+ 		msp_sleep(state, -1);
+ 		v4l_dbg(2, msp_debug, client, "msp34xxg thread: wakeup\n");
+ 
+-	restart:
++restart:
+ 		v4l_dbg(1, msp_debug, client, "thread: restart scan\n");
+ 		state->restart = 0;
+ 		if (kthread_should_stop())
+@@ -956,7 +979,8 @@ int msp34xxg_thread(void *data)
+ 
+ 		if (state->mode == MSP_MODE_EXTERN) {
+ 			/* no carrier scan needed, just unmute */
+-			v4l_dbg(1, msp_debug, client, "thread: no carrier scan\n");
++			v4l_dbg(1, msp_debug, client,
++				"thread: no carrier scan\n");
+ 			state->scan_in_progress = 0;
+ 			msp_set_audio(client);
+ 			continue;
+@@ -972,7 +996,8 @@ int msp34xxg_thread(void *data)
+ 			goto unmute;
+ 
+ 		/* watch autodetect */
+-		v4l_dbg(1, msp_debug, client, "started autodetect, waiting for result\n");
++		v4l_dbg(1, msp_debug, client,
++			"started autodetect, waiting for result\n");
+ 		for (i = 0; i < 10; i++) {
+ 			if (msp_sleep(state, 100))
+ 				goto restart;
+@@ -983,15 +1008,18 @@ int msp34xxg_thread(void *data)
+ 				state->std = val;
+ 				break;
+ 			}
+-			v4l_dbg(2, msp_debug, client, "detection still in progress\n");
++			v4l_dbg(2, msp_debug, client,
++				"detection still in progress\n");
+ 		}
+ 		if (state->std == 1) {
+-			v4l_dbg(1, msp_debug, client, "detection still in progress after 10 tries. giving up.\n");
++			v4l_dbg(1, msp_debug, client,
++				"detection still in progress after 10 tries. giving up.\n");
+ 			continue;
+ 		}
+ 
+-	unmute:
+-		v4l_dbg(1, msp_debug, client, "detected standard: %s (0x%04x)\n",
++unmute:
++		v4l_dbg(1, msp_debug, client,
++			"detected standard: %s (0x%04x)\n",
+ 			msp_standard_std_name(state->std), state->std);
+ 
+ 		if (state->std == 9) {
+@@ -1046,9 +1074,11 @@ static int msp34xxg_detect_stereo(struct i2c_client *client)
+ 		if (state->std == 0x20)
+ 			state->rxsubchans |= V4L2_TUNER_SUB_SAP;
+ 		else
+-			state->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
++			state->rxsubchans =
++				V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
+ 	}
+-	v4l_dbg(1, msp_debug, client, "status=0x%x, stereo=%d, bilingual=%d -> rxsubchans=%d\n",
++	v4l_dbg(1, msp_debug, client,
++		"status=0x%x, stereo=%d, bilingual=%d -> rxsubchans=%d\n",
+ 		status, is_stereo, is_bilingual, state->rxsubchans);
+ 	return (oldrx != state->rxsubchans);
+ }
+diff --git a/drivers/media/video/mt20xx.c b/drivers/media/video/mt20xx.c
+index f49d1f4..b630c26 100644
+--- a/drivers/media/video/mt20xx.c
++++ b/drivers/media/video/mt20xx.c
+@@ -14,7 +14,7 @@ static int debug = 0;
+ module_param(debug, int, 0644);
+ MODULE_PARM_DESC(debug, "enable verbose debug messages");
+ 
+-#define PREFIX "mt20xx "
++#define PREFIX "mt20xx"
+ 
+ /* ---------------------------------------------------------------------- */
+ 
+diff --git a/drivers/media/video/mxb.c b/drivers/media/video/mxb.c
+index 98ad309..add6d0d 100644
+--- a/drivers/media/video/mxb.c
++++ b/drivers/media/video/mxb.c
+@@ -149,10 +149,33 @@ struct mxb
+ 
+ static struct saa7146_extension extension;
+ 
++static int mxb_check_clients(struct device *dev, void *data)
++{
++	struct mxb* mxb = data;
++	struct i2c_client *client = i2c_verify_client(dev);
++
++	if( !client )
++		return 0;
++
++	if( I2C_ADDR_TEA6420_1 == client->addr )
++		mxb->tea6420_1 = client;
++	if( I2C_ADDR_TEA6420_2 == client->addr )
++		mxb->tea6420_2 = client;
++	if( I2C_TEA6415C_2 == client->addr )
++		mxb->tea6415c = client;
++	if( I2C_ADDR_TDA9840 == client->addr )
++		mxb->tda9840 = client;
++	if( I2C_SAA7111 == client->addr )
++		mxb->saa7111a = client;
++	if( 0x60 == client->addr )
++		mxb->tuner = client;
++
++	return 0;
++}
++
+ static int mxb_probe(struct saa7146_dev* dev)
  {
--	int ret = 0;
--	struct em28xx *dev = filp->private_data;
--
--	if (mutex_lock_interruptible(&dev->fileop_lock))
--		return -ERESTARTSYS;
--
--	if (dev->state & DEV_DISCONNECTED) {
--		em28xx_errdev("v4l2 ioctl: device not present\n");
--		mutex_unlock(&dev->fileop_lock);
--		return -ENODEV;
--	}
--
--	if (dev->state & DEV_MISCONFIGURED) {
--		em28xx_errdev
--		    ("v4l2 ioctl: device is misconfigured; close and open it again\n");
--		mutex_unlock(&dev->fileop_lock);
--		return -EIO;
+ 	struct mxb* mxb = NULL;
+-	struct i2c_client *client;
+ 	int result;
+ 
+ 	if ((result = request_module("saa7111")) < 0) {
+@@ -195,20 +218,7 @@ static int mxb_probe(struct saa7146_dev* dev)
+ 	}
+ 
+ 	/* loop through all i2c-devices on the bus and look who is there */
+-	list_for_each_entry(client, &mxb->i2c_adapter.clients, list) {
+-		if( I2C_ADDR_TEA6420_1 == client->addr )
+-			mxb->tea6420_1 = client;
+-		if( I2C_ADDR_TEA6420_2 == client->addr )
+-			mxb->tea6420_2 = client;
+-		if( I2C_TEA6415C_2 == client->addr )
+-			mxb->tea6415c = client;
+-		if( I2C_ADDR_TDA9840 == client->addr )
+-			mxb->tda9840 = client;
+-		if( I2C_SAA7111 == client->addr )
+-			mxb->saa7111a = client;
+-		if( 0x60 == client->addr )
+-			mxb->tuner = client;
 -	}
-+	struct video_device *vfd;
++	device_for_each_child(&mxb->i2c_adapter.dev, mxb, mxb_check_clients);
  
--	ret = video_usercopy(inode, filp, cmd, arg, em28xx_video_do_ioctl);
-+	vfd = video_device_alloc();
-+	if (NULL == vfd)
-+		return NULL;
-+	*vfd = *template;
-+	vfd->minor   = -1;
-+	vfd->dev = &dev->udev->dev;
-+	vfd->release = video_device_release;
-+	vfd->type = type;
+ 	/* check if all devices are present */
+ 	if(    0 == mxb->tea6420_1	|| 0 == mxb->tea6420_2	|| 0 == mxb->tea6415c
+diff --git a/drivers/media/video/pvrusb2/Kconfig b/drivers/media/video/pvrusb2/Kconfig
+index d0c2cd7..6fc1b8b 100644
+--- a/drivers/media/video/pvrusb2/Kconfig
++++ b/drivers/media/video/pvrusb2/Kconfig
+@@ -5,6 +5,10 @@ config VIDEO_PVRUSB2
+ 	select VIDEO_TUNER
+ 	select VIDEO_TVEEPROM
+ 	select VIDEO_CX2341X
++	select VIDEO_SAA711X
++	select VIDEO_CX25840
++	select VIDEO_MSP3400
++	select VIDEO_WM8775
+ 	---help---
+ 	  This is a video4linux driver for Conexant 23416 based
+ 	  usb2 personal video recorder devices.
+@@ -12,32 +16,29 @@ config VIDEO_PVRUSB2
+ 	  To compile this driver as a module, choose M here: the
+ 	  module will be called pvrusb2
  
--	mutex_unlock(&dev->fileop_lock);
-+	snprintf(vfd->name, sizeof(vfd->name), "%s %s",
-+		 dev->name, type_name);
+-config VIDEO_PVRUSB2_29XXX
+-	bool "Hauppauge WinTV-PVR USB2 support for 29xxx model series"
++config VIDEO_PVRUSB2_ONAIR_CREATOR
++	bool "pvrusb2 driver support for OnAir Creator model"
+ 	depends on VIDEO_PVRUSB2 && EXPERIMENTAL
+ 	select VIDEO_SAA711X
+-	select VIDEO_MSP3400
++	select VIDEO_CS53L32A
+ 	---help---
+-	  This option enables support for WinTV-PVR USB2 devices whose
+-	  model number is of the form "29xxx" (leading prefix of "29"
+-	  followed by 3 digits).
+-	  To see if you may need this option, examine the white
+-	  sticker on the underside of your device.
++
++	  This option enables support for the OnAir Creator USB tuner
++	  device.  This is a hybrid device, however currently only
++	  analog mode is supported.
  
--	return ret;
-+	return vfd;
+ 	  If you are in doubt, say Y.
+ 
+-config VIDEO_PVRUSB2_24XXX
+-	bool "Hauppauge WinTV-PVR USB2 support for 24xxx model series"
++config VIDEO_PVRUSB2_ONAIR_USB2
++	bool "pvrusb2 driver support for OnAir USB2 model"
+ 	depends on VIDEO_PVRUSB2 && EXPERIMENTAL
+-	select VIDEO_CX25840
+-	select VIDEO_WM8775
++	select VIDEO_SAA711X
++	select VIDEO_CS53L32A
+ 	---help---
+-	  This option enables inclusion of additional logic to operate
+-	  newer WinTV-PVR USB2 devices whose model number is of the
+-	  form "24xxx" (leading prefix of "24" followed by 3 digits).
+-	  To see if you may need this option, examine the white
+-	  sticker on the underside of your device.  Enabling this
+-	  option will not harm support for older devices.
++
++	  This option enables support for the OnAir USB2 tuner device
++	  (also known as the Sasem tuner).  This is a hybrid device,
++	  however currently only analog mode is supported.
+ 
+ 	  If you are in doubt, say Y.
+ 
+diff --git a/drivers/media/video/pvrusb2/Makefile b/drivers/media/video/pvrusb2/Makefile
+index 69b3e43..47284e5 100644
+--- a/drivers/media/video/pvrusb2/Makefile
++++ b/drivers/media/video/pvrusb2/Makefile
+@@ -6,7 +6,7 @@ pvrusb2-objs	:= pvrusb2-i2c-core.o pvrusb2-i2c-cmd-v4l2.o \
+ 		   pvrusb2-encoder.o pvrusb2-video-v4l.o \
+ 		   pvrusb2-eeprom.o pvrusb2-tuner.o \
+ 		   pvrusb2-main.o pvrusb2-hdw.o pvrusb2-v4l2.o \
+-		   pvrusb2-ctrl.o pvrusb2-std.o \
++		   pvrusb2-ctrl.o pvrusb2-std.o pvrusb2-devattr.o \
+ 		   pvrusb2-context.o pvrusb2-io.o pvrusb2-ioread.o \
+ 		   pvrusb2-cx2584x-v4l.o pvrusb2-wm8775.o \
+ 		   $(obj-pvrusb2-sysfs-y) $(obj-pvrusb2-debugifc-y)
+diff --git a/drivers/media/video/pvrusb2/pvrusb2-audio.c b/drivers/media/video/pvrusb2/pvrusb2-audio.c
+index 379645e..9a7c8e9 100644
+--- a/drivers/media/video/pvrusb2/pvrusb2-audio.c
++++ b/drivers/media/video/pvrusb2/pvrusb2-audio.c
+@@ -35,34 +35,58 @@ struct pvr2_msp3400_handler {
+ };
+ 
+ 
++
++struct routing_scheme {
++	const int *def;
++	unsigned int cnt;
++};
++
++static const int routing_scheme0[] = {
++	[PVR2_CVAL_INPUT_TV]        = MSP_INPUT_DEFAULT,
++	[PVR2_CVAL_INPUT_RADIO]     = MSP_INPUT(MSP_IN_SCART2,
++						MSP_IN_TUNER1,
++						MSP_DSP_IN_SCART,
++						MSP_DSP_IN_SCART),
++	[PVR2_CVAL_INPUT_COMPOSITE] = MSP_INPUT(MSP_IN_SCART1,
++						MSP_IN_TUNER1,
++						MSP_DSP_IN_SCART,
++						MSP_DSP_IN_SCART),
++	[PVR2_CVAL_INPUT_SVIDEO]    = MSP_INPUT(MSP_IN_SCART1,
++						MSP_IN_TUNER1,
++						MSP_DSP_IN_SCART,
++						MSP_DSP_IN_SCART),
++};
++
++static const struct routing_scheme routing_schemes[] = {
++	[PVR2_ROUTING_SCHEME_HAUPPAUGE] = {
++		.def = routing_scheme0,
++		.cnt = ARRAY_SIZE(routing_scheme0),
++	},
++};
++
+ /* This function selects the correct audio input source */
+ static void set_stereo(struct pvr2_msp3400_handler *ctxt)
+ {
+ 	struct pvr2_hdw *hdw = ctxt->hdw;
+ 	struct v4l2_routing route;
++	const struct routing_scheme *sp;
++	unsigned int sid = hdw->hdw_desc->signal_routing_scheme;
+ 
+ 	pvr2_trace(PVR2_TRACE_CHIPS,"i2c msp3400 v4l2 set_stereo");
+ 
+-	route.input = MSP_INPUT_DEFAULT;
+-	route.output = MSP_OUTPUT(MSP_SC_IN_DSP_SCART1);
+-	switch (hdw->input_val) {
+-	case PVR2_CVAL_INPUT_TV:
+-		break;
+-	case PVR2_CVAL_INPUT_RADIO:
+-		/* Assume that msp34xx also handle FM decoding, in which case
+-		   we're still using the tuner. */
+-		/* HV: actually it is more likely to be the SCART2 input if
+-		   the ivtv experience is any indication. */
+-		route.input = MSP_INPUT(MSP_IN_SCART2, MSP_IN_TUNER1,
+-				    MSP_DSP_IN_SCART, MSP_DSP_IN_SCART);
+-		break;
+-	case PVR2_CVAL_INPUT_SVIDEO:
+-	case PVR2_CVAL_INPUT_COMPOSITE:
+-		/* SCART 1 input */
+-		route.input = MSP_INPUT(MSP_IN_SCART1, MSP_IN_TUNER1,
+-				    MSP_DSP_IN_SCART, MSP_DSP_IN_SCART);
+-		break;
++	if ((sid < ARRAY_SIZE(routing_schemes)) &&
++	    ((sp = routing_schemes + sid) != 0) &&
++	    (hdw->input_val >= 0) &&
++	    (hdw->input_val < sp->cnt)) {
++		route.input = sp->def[hdw->input_val];
++	} else {
++		pvr2_trace(PVR2_TRACE_ERROR_LEGS,
++			   "*** WARNING *** i2c msp3400 v4l2 set_stereo:"
++			   " Invalid routing scheme (%u) and/or input (%d)",
++			   sid,hdw->input_val);
++		return;
+ 	}
++	route.output = MSP_OUTPUT(MSP_SC_IN_DSP_SCART1);
+ 	pvr2_i2c_client_cmd(ctxt->client,VIDIOC_INT_S_AUDIO_ROUTING,&route);
  }
  
--static const struct file_operations em28xx_v4l_fops = {
--	.owner = THIS_MODULE,
--	.open = em28xx_v4l2_open,
--	.release = em28xx_v4l2_close,
--	.ioctl = em28xx_v4l2_ioctl,
--	.read = em28xx_v4l2_read,
--	.poll = em28xx_v4l2_poll,
--	.mmap = em28xx_v4l2_mmap,
--	.llseek = no_llseek,
--	.compat_ioctl   = v4l_compat_ioctl32,
+diff --git a/drivers/media/video/pvrusb2/pvrusb2-context.c b/drivers/media/video/pvrusb2/pvrusb2-context.c
+index 22719ba..9d94aed 100644
+--- a/drivers/media/video/pvrusb2/pvrusb2-context.c
++++ b/drivers/media/video/pvrusb2/pvrusb2-context.c
+@@ -31,52 +31,32 @@
+ 
+ static void pvr2_context_destroy(struct pvr2_context *mp)
+ {
+-	if (mp->hdw) pvr2_hdw_destroy(mp->hdw);
+ 	pvr2_trace(PVR2_TRACE_STRUCT,"Destroying pvr_main id=%p",mp);
+-	if (mp->workqueue) {
+-		flush_workqueue(mp->workqueue);
+-		destroy_workqueue(mp->workqueue);
+-	}
++	if (mp->hdw) pvr2_hdw_destroy(mp->hdw);
+ 	kfree(mp);
+ }
+ 
+ 
+-static void pvr2_context_trigger_poll(struct pvr2_context *mp)
+-{
+-	queue_work(mp->workqueue,&mp->workpoll);
+-}
 -
--};
 -
--/******************************** usb interface *****************************************/
- 
- /*
-  * em28xx_init_dev()
-  * allocates and inits the device structs, registers i2c bus and v4l device
-  */
- static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
--			   int minor, int model)
-+			   int minor)
+-static void pvr2_context_poll(struct work_struct *work)
+-{
+-	struct pvr2_context *mp =
+-		container_of(work, struct pvr2_context, workpoll);
+-	pvr2_context_enter(mp); do {
+-		pvr2_hdw_poll(mp->hdw);
+-	} while (0); pvr2_context_exit(mp);
+-}
+-
+-
+-static void pvr2_context_setup(struct work_struct *work)
++static void pvr2_context_state_check(struct pvr2_context *mp)
  {
-+	struct em28xx_ops *ops = NULL;
- 	struct em28xx *dev = *devhandle;
- 	int retval = -ENOMEM;
--	int errCode, i;
-+	int errCode;
- 	unsigned int maxh, maxw;
+-	struct pvr2_context *mp =
+-		container_of(work, struct pvr2_context, workinit);
++	if (mp->init_flag) return;
++
++	switch (pvr2_hdw_get_state(mp->hdw)) {
++	case PVR2_STATE_WARM: break;
++	case PVR2_STATE_ERROR: break;
++	case PVR2_STATE_READY: break;
++	case PVR2_STATE_RUN: break;
++	default: return;
++	}
  
- 	dev->udev = udev;
--	dev->model = model;
- 	mutex_init(&dev->lock);
-+	spin_lock_init(&dev->queue_lock);
- 	init_waitqueue_head(&dev->open);
-+	init_waitqueue_head(&dev->wait_frame);
-+	init_waitqueue_head(&dev->wait_stream);
+ 	pvr2_context_enter(mp); do {
+-		if (!pvr2_hdw_dev_ok(mp->hdw)) break;
+-		pvr2_hdw_setup(mp->hdw);
+-		pvr2_hdw_setup_poll_trigger(
+-			mp->hdw,
+-			(void (*)(void *))pvr2_context_trigger_poll,
+-			mp);
+-		if (!pvr2_hdw_dev_ok(mp->hdw)) break;
+-		if (!pvr2_hdw_init_ok(mp->hdw)) break;
++		mp->init_flag = !0;
+ 		mp->video_stream.stream = pvr2_hdw_get_video_stream(mp->hdw);
+ 		if (mp->setup_func) {
+ 			mp->setup_func(mp);
+ 		}
+ 	} while (0); pvr2_context_exit(mp);
+-}
++ }
  
- 	dev->em28xx_write_regs = em28xx_write_regs;
- 	dev->em28xx_read_reg = em28xx_read_reg;
- 	dev->em28xx_read_reg_req_len = em28xx_read_reg_req_len;
- 	dev->em28xx_write_regs_req = em28xx_write_regs_req;
- 	dev->em28xx_read_reg_req = em28xx_read_reg_req;
--	dev->is_em2800 = em28xx_boards[model].is_em2800;
--	dev->has_tuner = em28xx_boards[model].has_tuner;
--	dev->has_msp34xx = em28xx_boards[model].has_msp34xx;
--	dev->tda9887_conf = em28xx_boards[model].tda9887_conf;
--	dev->decoder = em28xx_boards[model].decoder;
+ 
+ struct pvr2_context *pvr2_context_create(
+@@ -96,11 +76,10 @@ struct pvr2_context *pvr2_context_create(
+ 		mp = NULL;
+ 		goto done;
+ 	}
 -
--	if (tuner >= 0)
--		dev->tuner_type = tuner;
--	else
--		dev->tuner_type = em28xx_boards[model].tuner_type;
-+	dev->is_em2800 = em28xx_boards[dev->model].is_em2800;
+-	mp->workqueue = create_singlethread_workqueue("pvrusb2");
+-	INIT_WORK(&mp->workinit, pvr2_context_setup);
+-	INIT_WORK(&mp->workpoll, pvr2_context_poll);
+-	queue_work(mp->workqueue,&mp->workinit);
++	pvr2_hdw_set_state_callback(mp->hdw,
++				    (void (*)(void *))pvr2_context_state_check,
++				    mp);
++	pvr2_context_state_check(mp);
+  done:
+ 	return mp;
+ }
+diff --git a/drivers/media/video/pvrusb2/pvrusb2-context.h b/drivers/media/video/pvrusb2/pvrusb2-context.h
+index 6327fa1..a04187a 100644
+--- a/drivers/media/video/pvrusb2/pvrusb2-context.h
++++ b/drivers/media/video/pvrusb2/pvrusb2-context.h
+@@ -45,14 +45,11 @@ struct pvr2_context {
+ 	struct pvr2_context_stream video_stream;
+ 	struct mutex mutex;
+ 	int disconnect_flag;
++	int init_flag;
  
--	dev->video_inputs = em28xx_boards[model].vchannels;
-+	errCode = em28xx_read_reg(dev, CHIPID_REG);
-+	if (errCode >= 0)
-+		em28xx_info("em28xx chip ID = %d\n", errCode);
+ 	/* Called after pvr2_context initialization is complete */
+ 	void (*setup_func)(struct pvr2_context *);
  
--	for (i = 0; i < TVNORMS; i++)
--		if (em28xx_boards[model].norm == tvnorms[i].mode)
--			break;
--	if (i == TVNORMS)
--		i = 0;
-+	em28xx_pre_card_setup(dev);
-+
-+	errCode = em28xx_config(dev);
-+	if (errCode) {
-+		em28xx_errdev("error configuring device\n");
-+		em28xx_devused &= ~(1<<dev->devno);
-+		kfree(dev);
-+		return -ENOMEM;
-+	}
-+
-+	/* register i2c bus */
-+	em28xx_i2c_register(dev);
+-	/* Work queue overhead for out-of-line processing */
+-	struct workqueue_struct *workqueue;
+-	struct work_struct workinit;
+-	struct work_struct workpoll;
+ };
  
--	dev->tvnorm = &tvnorms[i];	/* set default norm */
-+	/* Do board specific init and eeprom reading */
-+	em28xx_card_setup(dev);
+ struct pvr2_channel {
+diff --git a/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c b/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c
+index e8a9252..ffdc45c 100644
+--- a/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c
++++ b/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c
+@@ -49,34 +49,89 @@ struct pvr2_v4l_cx2584x {
+ };
  
--	em28xx_videodbg("tvnorm=%s\n", dev->tvnorm->name);
-+	/* Configure audio */
-+	em28xx_audio_analog_set(dev);
+ 
++struct routing_scheme_item {
++	int vid;
++	int aud;
++};
 +
-+	/* configure the device */
-+	em28xx_config_i2c(dev);
++struct routing_scheme {
++	const struct routing_scheme_item *def;
++	unsigned int cnt;
++};
 +
-+	/* set default norm */
-+	dev->norm = em28xx_video_template.current_norm;
++static const struct routing_scheme_item routing_scheme0[] = {
++	[PVR2_CVAL_INPUT_TV] = {
++		.vid = CX25840_COMPOSITE7,
++		.aud = CX25840_AUDIO8,
++	},
++	[PVR2_CVAL_INPUT_RADIO] = { /* Treat the same as composite */
++		.vid = CX25840_COMPOSITE3,
++		.aud = CX25840_AUDIO_SERIAL,
++	},
++	[PVR2_CVAL_INPUT_COMPOSITE] = {
++		.vid = CX25840_COMPOSITE3,
++		.aud = CX25840_AUDIO_SERIAL,
++	},
++	[PVR2_CVAL_INPUT_SVIDEO] = {
++		.vid = CX25840_SVIDEO1,
++		.aud = CX25840_AUDIO_SERIAL,
++	},
++};
++
++/* Specific to gotview device */
++static const struct routing_scheme_item routing_schemegv[] = {
++	[PVR2_CVAL_INPUT_TV] = {
++		.vid = CX25840_COMPOSITE2,
++		.aud = CX25840_AUDIO5,
++	},
++	[PVR2_CVAL_INPUT_RADIO] = { /* Treat the same as composite */
++		.vid = CX25840_COMPOSITE1,
++		.aud = CX25840_AUDIO_SERIAL,
++	},
++	[PVR2_CVAL_INPUT_COMPOSITE] = {
++		.vid = CX25840_COMPOSITE1,
++		.aud = CX25840_AUDIO_SERIAL,
++	},
++	[PVR2_CVAL_INPUT_SVIDEO] = {
++		.vid = (CX25840_SVIDEO_LUMA3|CX25840_SVIDEO_CHROMA4),
++		.aud = CX25840_AUDIO_SERIAL,
++	},
++};
++
++static const struct routing_scheme routing_schemes[] = {
++	[PVR2_ROUTING_SCHEME_HAUPPAUGE] = {
++		.def = routing_scheme0,
++		.cnt = ARRAY_SIZE(routing_scheme0),
++	},
++	[PVR2_ROUTING_SCHEME_GOTVIEW] = {
++		.def = routing_schemegv,
++		.cnt = ARRAY_SIZE(routing_schemegv),
++	},
++};
++
+ static void set_input(struct pvr2_v4l_cx2584x *ctxt)
+ {
+ 	struct pvr2_hdw *hdw = ctxt->hdw;
+ 	struct v4l2_routing route;
+ 	enum cx25840_video_input vid_input;
+ 	enum cx25840_audio_input aud_input;
++	const struct routing_scheme *sp;
++	unsigned int sid = hdw->hdw_desc->signal_routing_scheme;
  
- 	maxw = norm_maxw(dev);
- 	maxh = norm_maxh(dev);
-@@ -1555,138 +1890,110 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
- 	dev->vscale = 0;
- 	dev->ctl_input = 2;
+ 	memset(&route,0,sizeof(route));
  
--	/* setup video picture settings for saa7113h */
--	memset(&dev->vpic, 0, sizeof(dev->vpic));
--	dev->vpic.colour = 128 << 8;
--	dev->vpic.hue = 128 << 8;
--	dev->vpic.brightness = 128 << 8;
--	dev->vpic.contrast = 192 << 8;
--	dev->vpic.whiteness = 128 << 8;	/* This one isn't used */
--	dev->vpic.depth = 16;
--	dev->vpic.palette = VIDEO_PALETTE_YUV422;
--
--	em28xx_pre_card_setup(dev);
--#ifdef CONFIG_MODULES
--	/* request some modules */
--	if (dev->decoder == EM28XX_SAA7113 || dev->decoder == EM28XX_SAA7114)
--		request_module("saa7115");
--	if (dev->decoder == EM28XX_TVP5150)
--		request_module("tvp5150");
--	if (dev->has_tuner)
--		request_module("tuner");
--#endif
- 	errCode = em28xx_config(dev);
--	if (errCode) {
--		em28xx_errdev("error configuring device\n");
--		em28xx_devused&=~(1<<dev->devno);
--		kfree(dev);
--		return -ENOMEM;
--	}
+-	switch(hdw->input_val) {
+-	case PVR2_CVAL_INPUT_TV:
+-		vid_input = CX25840_COMPOSITE7;
+-		aud_input = CX25840_AUDIO8;
+-		break;
+-	case PVR2_CVAL_INPUT_RADIO: // Treat same as composite
+-	case PVR2_CVAL_INPUT_COMPOSITE:
+-		vid_input = CX25840_COMPOSITE3;
+-		aud_input = CX25840_AUDIO_SERIAL;
+-		break;
+-	case PVR2_CVAL_INPUT_SVIDEO:
+-		vid_input = CX25840_SVIDEO1;
+-		aud_input = CX25840_AUDIO_SERIAL;
+-		break;
+-	default:
+-		// Just set it to be composite input for now...
+-		vid_input = CX25840_COMPOSITE3;
+-		aud_input = CX25840_AUDIO_SERIAL;
+-		break;
++	if ((sid < ARRAY_SIZE(routing_schemes)) &&
++	    ((sp = routing_schemes + sid) != 0) &&
++	    (hdw->input_val >= 0) &&
++	    (hdw->input_val < sp->cnt)) {
++		vid_input = sp->def[hdw->input_val].vid;
++		aud_input = sp->def[hdw->input_val].aud;
++	} else {
++		pvr2_trace(PVR2_TRACE_ERROR_LEGS,
++			   "*** WARNING *** i2c cx2584x set_input:"
++			   " Invalid routing scheme (%u) and/or input (%d)",
++			   sid,hdw->input_val);
++		return;
+ 	}
+ 
+ 	pvr2_trace(PVR2_TRACE_CHIPS,"i2c cx2584x set_input vid=0x%x aud=0x%x",
+@@ -140,7 +195,7 @@ static const struct pvr2_v4l_cx2584x_ops decoder_ops[] = {
+ static void decoder_detach(struct pvr2_v4l_cx2584x *ctxt)
+ {
+ 	ctxt->client->handler = NULL;
+-	ctxt->hdw->decoder_ctrl = NULL;
++	pvr2_hdw_set_decoder(ctxt->hdw,NULL);
+ 	kfree(ctxt);
+ }
+ 
+@@ -241,7 +296,7 @@ int pvr2_i2c_cx2584x_v4l_setup(struct pvr2_hdw *hdw,
+ 	ctxt->client = cp;
+ 	ctxt->hdw = hdw;
+ 	ctxt->stale_mask = (1 << ARRAY_SIZE(decoder_ops)) - 1;
+-	hdw->decoder_ctrl = &ctxt->ctrl;
++	pvr2_hdw_set_decoder(hdw,&ctxt->ctrl);
+ 	cp->handler = &ctxt->handler;
+ 	{
+ 		/*
+diff --git a/drivers/media/video/pvrusb2/pvrusb2-debug.h b/drivers/media/video/pvrusb2/pvrusb2-debug.h
+index da6441b..fca49d8 100644
+--- a/drivers/media/video/pvrusb2/pvrusb2-debug.h
++++ b/drivers/media/video/pvrusb2/pvrusb2-debug.h
+@@ -34,25 +34,26 @@ extern int pvrusb2_debug;
+ #define PVR2_TRACE_INIT       (1 <<  5) /* misc initialization steps */
+ #define PVR2_TRACE_START_STOP (1 <<  6) /* Streaming start / stop */
+ #define PVR2_TRACE_CTL        (1 <<  7) /* commit of control changes */
+-#define PVR2_TRACE_DEBUG      (1 <<  8) /* Temporary debug code */
+-#define PVR2_TRACE_EEPROM     (1 <<  9) /* eeprom parsing / report */
+-#define PVR2_TRACE_STRUCT     (1 << 10) /* internal struct creation */
+-#define PVR2_TRACE_OPEN_CLOSE (1 << 11) /* application open / close */
+-#define PVR2_TRACE_CREG       (1 << 12) /* Main critical region entry / exit */
+-#define PVR2_TRACE_SYSFS      (1 << 13) /* Sysfs driven I/O */
+-#define PVR2_TRACE_FIRMWARE   (1 << 14) /* firmware upload actions */
+-#define PVR2_TRACE_CHIPS      (1 << 15) /* chip broadcast operation */
+-#define PVR2_TRACE_I2C        (1 << 16) /* I2C related stuff */
+-#define PVR2_TRACE_I2C_CMD    (1 << 17) /* Software commands to I2C modules */
+-#define PVR2_TRACE_I2C_CORE   (1 << 18) /* I2C core debugging */
+-#define PVR2_TRACE_I2C_TRAF   (1 << 19) /* I2C traffic through the adapter */
+-#define PVR2_TRACE_V4LIOCTL   (1 << 20) /* v4l ioctl details */
+-#define PVR2_TRACE_ENCODER    (1 << 21) /* mpeg2 encoder operation */
+-#define PVR2_TRACE_BUF_POOL   (1 << 22) /* Track buffer pool management */
+-#define PVR2_TRACE_BUF_FLOW   (1 << 23) /* Track buffer flow in system */
+-#define PVR2_TRACE_DATA_FLOW  (1 << 24) /* Track data flow */
+-#define PVR2_TRACE_DEBUGIFC   (1 << 25) /* Debug interface actions */
+-#define PVR2_TRACE_GPIO       (1 << 26) /* GPIO state bit changes */
++#define PVR2_TRACE_STATE      (1 <<  8) /* Device state changes */
++#define PVR2_TRACE_STBITS     (1 <<  9) /* Individual bit state changes */
++#define PVR2_TRACE_EEPROM     (1 << 10) /* eeprom parsing / report */
++#define PVR2_TRACE_STRUCT     (1 << 11) /* internal struct creation */
++#define PVR2_TRACE_OPEN_CLOSE (1 << 12) /* application open / close */
++#define PVR2_TRACE_CREG       (1 << 13) /* Main critical region entry / exit */
++#define PVR2_TRACE_SYSFS      (1 << 14) /* Sysfs driven I/O */
++#define PVR2_TRACE_FIRMWARE   (1 << 15) /* firmware upload actions */
++#define PVR2_TRACE_CHIPS      (1 << 16) /* chip broadcast operation */
++#define PVR2_TRACE_I2C        (1 << 17) /* I2C related stuff */
++#define PVR2_TRACE_I2C_CMD    (1 << 18) /* Software commands to I2C modules */
++#define PVR2_TRACE_I2C_CORE   (1 << 19) /* I2C core debugging */
++#define PVR2_TRACE_I2C_TRAF   (1 << 20) /* I2C traffic through the adapter */
++#define PVR2_TRACE_V4LIOCTL   (1 << 21) /* v4l ioctl details */
++#define PVR2_TRACE_ENCODER    (1 << 22) /* mpeg2 encoder operation */
++#define PVR2_TRACE_BUF_POOL   (1 << 23) /* Track buffer pool management */
++#define PVR2_TRACE_BUF_FLOW   (1 << 24) /* Track buffer flow in system */
++#define PVR2_TRACE_DATA_FLOW  (1 << 25) /* Track data flow */
++#define PVR2_TRACE_DEBUGIFC   (1 << 26) /* Debug interface actions */
++#define PVR2_TRACE_GPIO       (1 << 27) /* GPIO state bit changes */
+ 
+ 
+ #endif /* __PVRUSB2_HDW_INTERNAL_H */
+diff --git a/drivers/media/video/pvrusb2/pvrusb2-debugifc.c b/drivers/media/video/pvrusb2/pvrusb2-debugifc.c
+index 6f135f4..b068743 100644
+--- a/drivers/media/video/pvrusb2/pvrusb2-debugifc.c
++++ b/drivers/media/video/pvrusb2/pvrusb2-debugifc.c
+@@ -31,14 +31,6 @@ struct debugifc_mask_item {
+ 	unsigned long msk;
+ };
+ 
+-static struct debugifc_mask_item mask_items[] = {
+-	{"ENC_FIRMWARE",(1<<PVR2_SUBSYS_B_ENC_FIRMWARE)},
+-	{"ENC_CFG",(1<<PVR2_SUBSYS_B_ENC_CFG)},
+-	{"DIG_RUN",(1<<PVR2_SUBSYS_B_DIGITIZER_RUN)},
+-	{"USB_RUN",(1<<PVR2_SUBSYS_B_USBSTREAM_RUN)},
+-	{"ENC_RUN",(1<<PVR2_SUBSYS_B_ENC_RUN)},
+-};
 -
--	mutex_lock(&dev->lock);
--	/* register i2c bus */
--	em28xx_i2c_register(dev);
  
--	/* Do board specific init and eeprom reading */
--	em28xx_card_setup(dev);
-+	list_add_tail(&dev->devlist, &em28xx_devlist);
+ static unsigned int debugifc_count_whitespace(const char *buf,
+ 					      unsigned int count)
+@@ -148,134 +140,14 @@ static int debugifc_match_keyword(const char *buf,unsigned int count,
+ }
  
--	/* configure the device */
--	em28xx_config_i2c(dev);
+ 
+-static unsigned long debugifc_find_mask(const char *buf,unsigned int count)
+-{
+-	struct debugifc_mask_item *mip;
+-	unsigned int idx;
+-	for (idx = 0; idx < ARRAY_SIZE(mask_items); idx++) {
+-		mip = mask_items + idx;
+-		if (debugifc_match_keyword(buf,count,mip->name)) {
+-			return mip->msk;
+-		}
+-	}
+-	return 0;
+-}
 -
--	mutex_unlock(&dev->lock);
 -
--	errCode = em28xx_config(dev);
+-static int debugifc_print_mask(char *buf,unsigned int sz,
+-			       unsigned long msk,unsigned long val)
+-{
+-	struct debugifc_mask_item *mip;
+-	unsigned int idx;
+-	int bcnt = 0;
+-	int ccnt;
+-	for (idx = 0; idx < ARRAY_SIZE(mask_items); idx++) {
+-		mip = mask_items + idx;
+-		if (!(mip->msk & msk)) continue;
+-		ccnt = scnprintf(buf,sz,"%s%c%s",
+-				 (bcnt ? " " : ""),
+-				 ((mip->msk & val) ? '+' : '-'),
+-				 mip->name);
+-		sz -= ccnt;
+-		buf += ccnt;
+-		bcnt += ccnt;
+-	}
+-	return bcnt;
+-}
 -
--#ifdef CONFIG_MODULES
--	if (dev->has_msp34xx)
--		request_module("msp3400");
--#endif
--	/* allocate and fill v4l2 device struct */
--	dev->vdev = video_device_alloc();
-+	/* allocate and fill video video_device struct */
-+	dev->vdev = em28xx_vdev_init(dev, &em28xx_video_template,
-+					  VID_TYPE_CAPTURE, "video");
- 	if (NULL == dev->vdev) {
- 		em28xx_errdev("cannot allocate video_device.\n");
--		em28xx_devused&=~(1<<dev->devno);
--		kfree(dev);
--		return -ENOMEM;
+-static unsigned int debugifc_parse_subsys_mask(const char *buf,
+-					       unsigned int count,
+-					       unsigned long *mskPtr,
+-					       unsigned long *valPtr)
+-{
+-	const char *wptr;
+-	unsigned int consume_cnt = 0;
+-	unsigned int scnt;
+-	unsigned int wlen;
+-	int mode;
+-	unsigned long m1,msk,val;
+-
+-	msk = 0;
+-	val = 0;
+-
+-	while (count) {
+-		scnt = debugifc_isolate_word(buf,count,&wptr,&wlen);
+-		if (!scnt) break;
+-		consume_cnt += scnt; count -= scnt; buf += scnt;
+-		if (!wptr) break;
+-
+-		mode = 0;
+-		if (wlen) switch (wptr[0]) {
+-		case '+':
+-			wptr++;
+-			wlen--;
+-			break;
+-		case '-':
+-			mode = 1;
+-			wptr++;
+-			wlen--;
+-			break;
+-		}
+-		if (!wlen) continue;
+-		m1 = debugifc_find_mask(wptr,wlen);
+-		if (!m1) break;
+-		msk |= m1;
+-		if (!mode) val |= m1;
 -	}
+-	*mskPtr = msk;
+-	*valPtr = val;
+-	return consume_cnt;
+-}
 -
--	dev->vbi_dev = video_device_alloc();
--	if (NULL == dev->vbi_dev) {
--		em28xx_errdev("cannot allocate video_device.\n");
--		kfree(dev->vdev);
--		em28xx_devused&=~(1<<dev->devno);
--		kfree(dev);
--		return -ENOMEM;
-+		goto fail_unreg;
- 	}
 -
--	/* Fills VBI device info */
--	dev->vbi_dev->type = VFL_TYPE_VBI;
--	dev->vbi_dev->fops = &em28xx_v4l_fops;
--	dev->vbi_dev->minor = -1;
--	dev->vbi_dev->dev = &dev->udev->dev;
--	dev->vbi_dev->release = video_device_release;
--	snprintf(dev->vbi_dev->name, sizeof(dev->vbi_dev->name), "%s#%d %s",
--							 "em28xx",dev->devno,"vbi");
+ int pvr2_debugifc_print_info(struct pvr2_hdw *hdw,char *buf,unsigned int acnt)
+ {
+ 	int bcnt = 0;
+ 	int ccnt;
+-	struct pvr2_hdw_debug_info dbg;
 -
--	/* Fills CAPTURE device info */
--	dev->vdev->type = VID_TYPE_CAPTURE;
--	if (dev->has_tuner)
-+	if (dev->tuner_type != TUNER_ABSENT)
- 		dev->vdev->type |= VID_TYPE_TUNER;
--	dev->vdev->fops = &em28xx_v4l_fops;
--	dev->vdev->minor = -1;
--	dev->vdev->dev = &dev->udev->dev;
--	dev->vdev->release = video_device_release;
--	snprintf(dev->vdev->name, sizeof(dev->vbi_dev->name), "%s#%d %s",
--							 "em28xx",dev->devno,"video");
+-	pvr2_hdw_get_debug_info(hdw,&dbg);
+-
+-	ccnt = scnprintf(buf,acnt,"big lock %s; ctl lock %s",
+-			 (dbg.big_lock_held ? "held" : "free"),
+-			 (dbg.ctl_lock_held ? "held" : "free"));
+-	bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+-	if (dbg.ctl_lock_held) {
+-		ccnt = scnprintf(buf,acnt,"; cmd_state=%d cmd_code=%d"
+-				 " cmd_wlen=%d cmd_rlen=%d"
+-				 " wpend=%d rpend=%d tmout=%d rstatus=%d"
+-				 " wstatus=%d",
+-				 dbg.cmd_debug_state,dbg.cmd_code,
+-				 dbg.cmd_debug_write_len,
+-				 dbg.cmd_debug_read_len,
+-				 dbg.cmd_debug_write_pend,
+-				 dbg.cmd_debug_read_pend,
+-				 dbg.cmd_debug_timeout,
+-				 dbg.cmd_debug_rstatus,
+-				 dbg.cmd_debug_wstatus);
+-		bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+-	}
+-	ccnt = scnprintf(buf,acnt,"\n");
+-	bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+-	ccnt = scnprintf(
+-		buf,acnt,"driver flags: %s %s %s\n",
+-		(dbg.flag_init_ok ? "initialized" : "uninitialized"),
+-		(dbg.flag_ok ? "ok" : "fail"),
+-		(dbg.flag_disconnected ? "disconnected" : "connected"));
+-	bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+-	ccnt = scnprintf(buf,acnt,"Subsystems enabled / configured: ");
++	ccnt = scnprintf(buf,acnt,"Driver state info:\n");
+ 	bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+-	ccnt = debugifc_print_mask(buf,acnt,dbg.subsys_flags,dbg.subsys_flags);
++	ccnt = pvr2_hdw_state_report(hdw,buf,acnt);
+ 	bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+-	ccnt = scnprintf(buf,acnt,"\n");
+-	bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+-	ccnt = scnprintf(buf,acnt,"Subsystems disabled / unconfigured: ");
+-	bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+-	ccnt = debugifc_print_mask(buf,acnt,~dbg.subsys_flags,dbg.subsys_flags);
+-	bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+-	ccnt = scnprintf(buf,acnt,"\n");
+-	bcnt += ccnt; acnt -= ccnt; buf += ccnt;
 -
--	list_add_tail(&dev->devlist,&em28xx_devlist);
+ 	ccnt = scnprintf(buf,acnt,"Attached I2C modules:\n");
+ 	bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+ 	ccnt = pvr2_i2c_report(hdw,buf,acnt);
+@@ -290,7 +162,6 @@ int pvr2_debugifc_print_status(struct pvr2_hdw *hdw,
+ {
+ 	int bcnt = 0;
+ 	int ccnt;
+-	unsigned long msk;
+ 	int ret;
+ 	u32 gpio_dir,gpio_in,gpio_out;
  
--	/* register v4l2 device */
--	mutex_lock(&dev->lock);
--	if ((retval = video_register_device(dev->vdev, VFL_TYPE_GRABBER,
--					 video_nr[dev->devno]))) {
-+	/* register v4l2 video video_device */
-+	retval = video_register_device(dev->vdev, VFL_TYPE_GRABBER,
-+				       video_nr[dev->devno]);
-+	if (retval) {
- 		em28xx_errdev("unable to register video device (error=%i).\n",
- 			      retval);
--		mutex_unlock(&dev->lock);
--		list_del(&dev->devlist);
--		video_device_release(dev->vdev);
--		em28xx_devused&=~(1<<dev->devno);
--		kfree(dev);
--		return -ENODEV;
-+		goto fail_unreg;
- 	}
+@@ -311,28 +182,6 @@ int pvr2_debugifc_print_status(struct pvr2_hdw *hdw,
+ 			 pvr2_hdw_get_streaming(hdw) ? "on" : "off");
+ 	bcnt += ccnt; acnt -= ccnt; buf += ccnt;
  
-+	/* Allocate and fill vbi video_device struct */
-+	dev->vbi_dev = em28xx_vdev_init(dev, &em28xx_video_template,
-+					  VFL_TYPE_VBI, "vbi");
-+	/* register v4l2 vbi video_device */
- 	if (video_register_device(dev->vbi_dev, VFL_TYPE_VBI,
- 					vbi_nr[dev->devno]) < 0) {
--		printk("unable to register vbi device\n");
--		mutex_unlock(&dev->lock);
--		list_del(&dev->devlist);
--		video_device_release(dev->vbi_dev);
--		video_device_release(dev->vdev);
--		em28xx_devused&=~(1<<dev->devno);
--		kfree(dev);
--		return -ENODEV;
--	} else {
--		printk("registered VBI\n");
-+		em28xx_errdev("unable to register vbi device\n");
-+		retval = -ENODEV;
-+		goto fail_unreg;
- 	}
+-	msk = pvr2_hdw_subsys_get(hdw);
+-	ccnt = scnprintf(buf,acnt,"Subsystems enabled / configured: ");
+-	bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+-	ccnt = debugifc_print_mask(buf,acnt,msk,msk);
+-	bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+-	ccnt = scnprintf(buf,acnt,"\n");
+-	bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+-	ccnt = scnprintf(buf,acnt,"Subsystems disabled / unconfigured: ");
+-	bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+-	ccnt = debugifc_print_mask(buf,acnt,~msk,msk);
+-	bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+-	ccnt = scnprintf(buf,acnt,"\n");
+-	bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+-
+-	msk = pvr2_hdw_subsys_stream_get(hdw);
+-	ccnt = scnprintf(buf,acnt,"Subsystems stopped on stream shutdown: ");
+-	bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+-	ccnt = debugifc_print_mask(buf,acnt,msk,msk);
+-	bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+-	ccnt = scnprintf(buf,acnt,"\n");
+-	bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+-
+ 	return bcnt;
+ }
  
-+	if (em28xx_boards[dev->model].radio.type == EM28XX_RADIO) {
-+		dev->radio_dev = em28xx_vdev_init(dev, &em28xx_radio_template,
-+					VFL_TYPE_RADIO, "radio");
-+		if (NULL == dev->radio_dev) {
-+			em28xx_errdev("cannot allocate video_device.\n");
-+			goto fail_unreg;
-+		}
-+		retval = video_register_device(dev->radio_dev, VFL_TYPE_RADIO,
-+					    radio_nr[dev->devno]);
-+		if (retval < 0) {
-+			em28xx_errdev("can't register radio device\n");
-+			goto fail_unreg;
-+		}
-+		em28xx_info("Registered radio device as /dev/radio%d\n",
-+			    dev->radio_dev->minor & 0x1f);
-+	}
+@@ -369,28 +218,10 @@ static int pvr2_debugifc_do1cmd(struct pvr2_hdw *hdw,const char *buf,
+ 			return pvr2_upload_firmware2(hdw);
+ 		} else if (debugifc_match_keyword(wptr,wlen,"decoder")) {
+ 			return pvr2_hdw_cmd_decoder_reset(hdw);
++		} else if (debugifc_match_keyword(wptr,wlen,"worker")) {
++			return pvr2_hdw_untrip(hdw);
+ 		}
+ 		return -EINVAL;
+-	} else if (debugifc_match_keyword(wptr,wlen,"subsys_flags")) {
+-		unsigned long msk = 0;
+-		unsigned long val = 0;
+-		if (debugifc_parse_subsys_mask(buf,count,&msk,&val) != count) {
+-			pvr2_trace(PVR2_TRACE_DEBUGIFC,
+-				   "debugifc parse error on subsys mask");
+-			return -EINVAL;
+-		}
+-		pvr2_hdw_subsys_bit_chg(hdw,msk,val);
+-		return 0;
+-	} else if (debugifc_match_keyword(wptr,wlen,"stream_flags")) {
+-		unsigned long msk = 0;
+-		unsigned long val = 0;
+-		if (debugifc_parse_subsys_mask(buf,count,&msk,&val) != count) {
+-			pvr2_trace(PVR2_TRACE_DEBUGIFC,
+-				   "debugifc parse error on stream mask");
+-			return -EINVAL;
+-		}
+-		pvr2_hdw_subsys_stream_bit_chg(hdw,msk,val);
+-		return 0;
+ 	} else if (debugifc_match_keyword(wptr,wlen,"cpufw")) {
+ 		scnt = debugifc_isolate_word(buf,count,&wptr,&wlen);
+ 		if (!scnt) return -EINVAL;
+diff --git a/drivers/media/video/pvrusb2/pvrusb2-devattr.c b/drivers/media/video/pvrusb2/pvrusb2-devattr.c
+new file mode 100644
+index 0000000..4df6d6d
+--- /dev/null
++++ b/drivers/media/video/pvrusb2/pvrusb2-devattr.c
+@@ -0,0 +1,217 @@
++/*
++ *
++ *  $Id$
++ *
++ *  Copyright (C) 2007 Mike Isely <isely at pobox.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
++ *
++ *  This program is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with this program; if not, write to the Free Software
++ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ *
++ */
 +
++/*
 +
- 	if (dev->has_msp34xx) {
- 		/* Send a reset to other chips via gpio */
- 		em28xx_write_regs_req(dev, 0x00, 0x08, "\xf7", 1);
- 		msleep(3);
- 		em28xx_write_regs_req(dev, 0x00, 0x08, "\xff", 1);
- 		msleep(3);
--
- 	}
--	video_mux(dev, 0);
- 
--	mutex_unlock(&dev->lock);
-+	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);
- 
-+	mutex_lock(&em28xx_extension_devlist_lock);
-+	if (!list_empty(&em28xx_extension_devlist)) {
-+		list_for_each_entry(ops, &em28xx_extension_devlist, next) {
-+			if (ops->id)
-+				ops->init(dev);
-+		}
-+	}
-+	mutex_unlock(&em28xx_extension_devlist_lock);
++This source file should encompass ALL per-device type information for the
++driver.  To define a new device, add elements to the pvr2_device_table and
++pvr2_device_desc structures.
 +
- 	return 0;
++*/
 +
-+fail_unreg:
-+	em28xx_release_resources(dev);
-+	mutex_unlock(&dev->lock);
-+	kfree(dev);
-+	return retval;
-+}
++#include "pvrusb2-devattr.h"
++#include <linux/usb.h>
++/* This is needed in order to pull in tuner type ids... */
++#include <linux/i2c.h>
++#include <media/tuner.h>
 +
-+#if defined(CONFIG_MODULES) && defined(MODULE)
-+static void request_module_async(struct work_struct *work)
-+{
-+	struct em28xx *dev = container_of(work,
-+			     struct em28xx, request_module_wk);
 +
-+	if (dev->has_audio_class)
-+		request_module("snd-usb-audio");
-+	else
-+		request_module("em28xx-alsa");
-+}
 +
-+static void request_modules(struct em28xx *dev)
-+{
-+	INIT_WORK(&dev->request_module_wk, request_module_async);
-+	schedule_work(&dev->request_module_wk);
- }
-+#else
-+#define request_modules(dev)
-+#endif /* CONFIG_MODULES */
++/*------------------------------------------------------------------------*/
++/* Hauppauge PVR-USB2 Model 29xxx */
++
++static const char *pvr2_client_29xxx[] = {
++	"msp3400",
++	"saa7115",
++	"tuner",
++};
++
++static const char *pvr2_fw1_names_29xxx[] = {
++		"v4l-pvrusb2-29xxx-01.fw",
++};
++
++static const struct pvr2_device_desc pvr2_device_29xxx = {
++		.description = "WinTV PVR USB2 Model Category 29xxxx",
++		.shortname = "29xxx",
++		.client_modules.lst = pvr2_client_29xxx,
++		.client_modules.cnt = ARRAY_SIZE(pvr2_client_29xxx),
++		.fx2_firmware.lst = pvr2_fw1_names_29xxx,
++		.fx2_firmware.cnt = ARRAY_SIZE(pvr2_fw1_names_29xxx),
++		.flag_has_hauppauge_rom = !0,
++		.signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE,
++};
++
++
++
++/*------------------------------------------------------------------------*/
++/* Hauppauge PVR-USB2 Model 24xxx */
++
++static const char *pvr2_client_24xxx[] = {
++	"cx25840",
++	"tuner",
++	"wm8775",
++};
++
++static const char *pvr2_fw1_names_24xxx[] = {
++		"v4l-pvrusb2-24xxx-01.fw",
++};
++
++static const struct pvr2_device_desc pvr2_device_24xxx = {
++		.description = "WinTV PVR USB2 Model Category 24xxxx",
++		.shortname = "24xxx",
++		.client_modules.lst = pvr2_client_24xxx,
++		.client_modules.cnt = ARRAY_SIZE(pvr2_client_24xxx),
++		.fx2_firmware.lst = pvr2_fw1_names_24xxx,
++		.fx2_firmware.cnt = ARRAY_SIZE(pvr2_fw1_names_24xxx),
++		.flag_has_cx25840 = !0,
++		.flag_has_wm8775 = !0,
++		.flag_has_hauppauge_rom = !0,
++		.flag_has_hauppauge_custom_ir = !0,
++		.signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE,
++};
++
++
++
++/*------------------------------------------------------------------------*/
++/* GOTVIEW USB2.0 DVD2 */
++
++static const char *pvr2_client_gotview_2[] = {
++	"cx25840",
++	"tuner",
++};
++
++static const struct pvr2_device_desc pvr2_device_gotview_2 = {
++		.description = "Gotview USB 2.0 DVD 2",
++		.shortname = "gv2",
++		.client_modules.lst = pvr2_client_gotview_2,
++		.client_modules.cnt = ARRAY_SIZE(pvr2_client_gotview_2),
++		.flag_has_cx25840 = !0,
++		.default_tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
++		.signal_routing_scheme = PVR2_ROUTING_SCHEME_GOTVIEW,
++};
++
++
++
++#ifdef CONFIG_VIDEO_PVRUSB2_ONAIR_CREATOR
++/*------------------------------------------------------------------------*/
++/* OnAir Creator */
++
++static const char *pvr2_client_onair_creator[] = {
++	"saa7115",
++	"tuner",
++	"cs53l32a",
++};
++
++static const struct pvr2_device_desc pvr2_device_onair_creator = {
++		.description = "OnAir Creator Hybrid USB tuner",
++		.shortname = "oac",
++		.client_modules.lst = pvr2_client_onair_creator,
++		.client_modules.cnt = ARRAY_SIZE(pvr2_client_onair_creator),
++		.default_tuner_type = TUNER_LG_TDVS_H06XF,
++		.signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE,
++};
++#endif
++
++
++
++#ifdef CONFIG_VIDEO_PVRUSB2_ONAIR_USB2
++/*------------------------------------------------------------------------*/
++/* OnAir USB 2.0 */
++
++static const char *pvr2_client_onair_usb2[] = {
++	"saa7115",
++	"tuner",
++	"cs53l32a",
++};
++
++static const struct pvr2_device_desc pvr2_device_onair_usb2 = {
++		.description = "OnAir USB2 Hybrid USB tuner",
++		.shortname = "oa2",
++		.client_modules.lst = pvr2_client_onair_usb2,
++		.client_modules.cnt = ARRAY_SIZE(pvr2_client_onair_usb2),
++		.default_tuner_type = TUNER_PHILIPS_ATSC,
++		.signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE,
++};
++#endif
++
++
++
++/*------------------------------------------------------------------------*/
++/* Hauppauge PVR-USB2 Model 75xxx */
++
++static const char *pvr2_client_75xxx[] = {
++	"cx25840",
++	"tuner",
++};
++
++static const char *pvr2_fw1_names_75xxx[] = {
++		"v4l-pvrusb2-73xxx-01.fw",
++};
++
++static const struct pvr2_device_desc pvr2_device_75xxx = {
++		.description = "WinTV PVR USB2 Model Category 75xxxx",
++		.shortname = "75xxx",
++		.client_modules.lst = pvr2_client_75xxx,
++		.client_modules.cnt = ARRAY_SIZE(pvr2_client_75xxx),
++		.fx2_firmware.lst = pvr2_fw1_names_75xxx,
++		.fx2_firmware.cnt = ARRAY_SIZE(pvr2_fw1_names_75xxx),
++		.flag_has_cx25840 = !0,
++		.flag_has_hauppauge_rom = !0,
++		.signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE,
++		.default_std_mask = V4L2_STD_NTSC_M,
++};
++
++
++
++/*------------------------------------------------------------------------*/
++
++struct usb_device_id pvr2_device_table[] = {
++	{ USB_DEVICE(0x2040, 0x2900),
++	  .driver_info = (kernel_ulong_t)&pvr2_device_29xxx},
++	{ USB_DEVICE(0x2040, 0x2400),
++	  .driver_info = (kernel_ulong_t)&pvr2_device_24xxx},
++	{ USB_DEVICE(0x1164, 0x0622),
++	  .driver_info = (kernel_ulong_t)&pvr2_device_gotview_2},
++#ifdef CONFIG_VIDEO_PVRUSB2_ONAIR_CREATOR
++	{ USB_DEVICE(0x11ba, 0x1003),
++	  .driver_info = (kernel_ulong_t)&pvr2_device_onair_creator},
++#endif
++#ifdef CONFIG_VIDEO_PVRUSB2_ONAIR_USB2
++	{ USB_DEVICE(0x11ba, 0x1001),
++	  .driver_info = (kernel_ulong_t)&pvr2_device_onair_usb2},
++#endif
++	{ USB_DEVICE(0x2040, 0x7500),
++	  .driver_info = (kernel_ulong_t)&pvr2_device_75xxx},
++	{ }
++};
++
++MODULE_DEVICE_TABLE(usb, pvr2_device_table);
++
++
++/*
++  Stuff for Emacs to see, in order to encourage consistent editing style:
++  *** Local Variables: ***
++  *** mode: c ***
++  *** fill-column: 75 ***
++  *** tab-width: 8 ***
++  *** c-basic-offset: 8 ***
++  *** End: ***
++  */
+diff --git a/drivers/media/video/pvrusb2/pvrusb2-devattr.h b/drivers/media/video/pvrusb2/pvrusb2-devattr.h
+new file mode 100644
+index 0000000..64b467f
+--- /dev/null
++++ b/drivers/media/video/pvrusb2/pvrusb2-devattr.h
+@@ -0,0 +1,119 @@
++/*
++ *
++ *  $Id$
++ *
++ *  Copyright (C) 2005 Mike Isely <isely at pobox.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
++ *
++ *  This program is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You 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 __PVRUSB2_DEVATTR_H
++#define __PVRUSB2_DEVATTR_H
++
++#include <linux/mod_devicetable.h>
++#include <linux/videodev2.h>
++
++/*
++
++  This header defines structures used to describe attributes of a device.
++
++*/
++
++
++struct pvr2_string_table {
++	const char **lst;
++	unsigned int cnt;
++};
++
++#define PVR2_ROUTING_SCHEME_HAUPPAUGE 0
++#define PVR2_ROUTING_SCHEME_GOTVIEW 1
++
++/* This describes a particular hardware type (except for the USB device ID
++   which must live in a separate structure due to environmental
++   constraints).  See the top of pvrusb2-hdw.c for where this is
++   instantiated. */
++struct pvr2_device_desc {
++	/* Single line text description of hardware */
++	const char *description;
++
++	/* Single token identifier for hardware */
++	const char *shortname;
++
++	/* List of additional client modules we need to load */
++	struct pvr2_string_table client_modules;
++
++	/* List of FX2 firmware file names we should search; if empty then
++	   FX2 firmware check / load is skipped and we assume the device
++	   was initialized from internal ROM. */
++	struct pvr2_string_table fx2_firmware;
++
++	/* Signal routing scheme used by device, contains one of
++	   PVR2_ROUTING_SCHEME_XXX.  Schemes have to be defined as we
++	   encounter them.  This is an arbitrary integer scheme id; its
++	   meaning is contained entirely within the driver and is
++	   interpreted by logic which must send commands to the chip-level
++	   drivers (search for things which touch this field). */
++	unsigned int signal_routing_scheme;
++
++	/* V4L tuner type ID to use with this device (only used if the
++	   driver could not discover the type any other way). */
++	int default_tuner_type;
++
++	/* Initial standard bits to use for this device, if not zero.
++	   Anything set here is also implied as an available standard.
++	   Note: This is ignored if overridden on the module load line via
++	   the video_std module option. */
++	v4l2_std_id default_std_mask;
++
++	/* If set, we don't bother trying to load cx23416 firmware. */
++	char flag_skip_cx23416_firmware;
++
++	/* Device has a hauppauge eeprom which we can interrogate. */
++	char flag_has_hauppauge_rom;
++
++	/* Device does not require a powerup command to be issued. */
++	char flag_no_powerup;
++
++	/* Device has a cx25840 - this enables special additional logic to
++	   handle it. */
++	char flag_has_cx25840;
++
++	/* Device has a wm8775 - this enables special additional logic to
++	   ensure that it is found. */
++	char flag_has_wm8775;
++
++	/* Device has IR hardware that can be faked into looking like a
++	   normal Hauppauge i2c IR receiver.  This is currently very
++	   specific to the 24xxx device, where Hauppauge had replaced their
++	   'standard' I2C IR receiver with a bunch of FPGA logic controlled
++	   directly via the FX2.  Turning this on tells the pvrusb2 driver
++	   to virtualize the presence of the non-existant IR receiver chip and
++	   implement the virtual receiver in terms of appropriate FX2
++	   commands. */
++	char flag_has_hauppauge_custom_ir;
++};
++
++extern struct usb_device_id pvr2_device_table[];
++
++#endif /* __PVRUSB2_HDW_INTERNAL_H */
++
++/*
++  Stuff for Emacs to see, in order to encourage consistent editing style:
++  *** Local Variables: ***
++  *** mode: c ***
++  *** fill-column: 75 ***
++  *** tab-width: 8 ***
++  *** c-basic-offset: 8 ***
++  *** End: ***
++  */
+diff --git a/drivers/media/video/pvrusb2/pvrusb2-eeprom.c b/drivers/media/video/pvrusb2/pvrusb2-eeprom.c
+index 45cbca0..5ef0059 100644
+--- a/drivers/media/video/pvrusb2/pvrusb2-eeprom.c
++++ b/drivers/media/video/pvrusb2/pvrusb2-eeprom.c
+@@ -144,6 +144,7 @@ int pvr2_eeprom_analyze(struct pvr2_hdw *hdw)
+ 	trace_eeprom("serial_number=%d",tvdata.serial_number);
+ 	trace_eeprom("rev_str=%s",tvdata.rev_str);
+ 	hdw->tuner_type = tvdata.tuner_type;
++	hdw->tuner_updated = !0;
+ 	hdw->serial_number = tvdata.serial_number;
+ 	hdw->std_mask_eeprom = tvdata.tuner_formats;
  
- /*
-  * em28xx_usb_probe()
-@@ -1700,7 +2007,7 @@ static int em28xx_usb_probe(struct usb_interface *interface,
- 	struct usb_interface *uif;
- 	struct em28xx *dev = NULL;
- 	int retval = -ENODEV;
--	int model,i,nr,ifnum;
-+	int i, nr, ifnum;
+diff --git a/drivers/media/video/pvrusb2/pvrusb2-encoder.c b/drivers/media/video/pvrusb2/pvrusb2-encoder.c
+index 205087a..6406287 100644
+--- a/drivers/media/video/pvrusb2/pvrusb2-encoder.c
++++ b/drivers/media/video/pvrusb2/pvrusb2-encoder.c
+@@ -140,7 +140,7 @@ static int pvr2_encoder_read_words(struct pvr2_hdw *hdw,
+    cx2341x.ko to write to our encoder (by handing it a pointer to this
+    function).  For earlier kernels this doesn't really matter. */
+ static int pvr2_encoder_cmd(void *ctxt,
+-			    int cmd,
++			    u32 cmd,
+ 			    int arg_cnt_send,
+ 			    int arg_cnt_recv,
+ 			    u32 *argp)
+@@ -209,7 +209,7 @@ static int pvr2_encoder_cmd(void *ctxt,
  
- 	udev = usb_get_dev(interface_to_usbdev(interface));
- 	ifnum = interface->altsetting[0].desc.bInterfaceNumber;
-@@ -1740,8 +2047,6 @@ static int em28xx_usb_probe(struct usb_interface *interface,
- 		return -ENODEV;
- 	}
+ 	LOCK_TAKE(hdw->ctl_lock); do {
  
--	model=id->driver_info;
--
- 	if (nr >= EM28XX_MAXBOARDS) {
- 		printk (DRIVER_NAME ": Supports only %i em28xx boards.\n",EM28XX_MAXBOARDS);
- 		em28xx_devused&=~(1<<nr);
-@@ -1757,7 +2062,20 @@ static int em28xx_usb_probe(struct usb_interface *interface,
+-		if (!hdw->flag_encoder_ok) {
++		if (!hdw->state_encoder_ok) {
+ 			ret = -EIO;
+ 			break;
+ 		}
+@@ -278,12 +278,15 @@ static int pvr2_encoder_cmd(void *ctxt,
+ 			ret = -EBUSY;
+ 		}
+ 		if (ret) {
+-			hdw->flag_encoder_ok = 0;
++			hdw->state_encoder_ok = 0;
++			pvr2_trace(PVR2_TRACE_STBITS,
++				   "State bit %s <-- %s",
++				   "state_encoder_ok",
++				   (hdw->state_encoder_ok ? "true" : "false"));
+ 			pvr2_trace(
+ 				PVR2_TRACE_ERROR_LEGS,
+ 				"Giving up on command."
+-				"  It is likely that"
+-				" this is a bad idea...");
++				"  This is normally recovered by the driver.");
+ 			break;
+ 		}
+ 		wrData[0] = 0x7;
+@@ -366,13 +369,13 @@ static int pvr2_encoder_prep_config(struct pvr2_hdw *hdw)
+ 
+ 	/* This ENC_MISC(3,encMisc3Arg) command is critical - without
+ 	   it there will eventually be video corruption.  Also, the
+-	   29xxx case is strange - the Windows driver is passing 1
+-	   regardless of device type but if we have 1 for 29xxx device
+-	   the video turns sluggish.  */
+-	switch (hdw->hdw_type) {
+-	case PVR2_HDW_TYPE_24XXX: encMisc3Arg = 1; break;
+-	case PVR2_HDW_TYPE_29XXX: encMisc3Arg = 0; break;
+-	default: break;
++	   saa7115 case is strange - the Windows driver is passing 1
++	   regardless of device type but if we have 1 for saa7115
++	   devices the video turns sluggish.  */
++	if (hdw->hdw_desc->flag_has_cx25840) {
++		encMisc3Arg = 1;
++	} else {
++		encMisc3Arg = 0;
  	}
+ 	ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_MISC,4, 3,
+ 				 encMisc3Arg,0,0);
+@@ -394,6 +397,24 @@ static int pvr2_encoder_prep_config(struct pvr2_hdw *hdw)
+ 	return ret;
+ }
  
- 	snprintf(dev->name, 29, "em28xx #%d", nr);
--	dev->devno=nr;
-+	dev->devno = nr;
-+	dev->model = id->driver_info;
-+
-+	/* Checks if audio is provided by some interface */
-+	for (i = 0; i < udev->config->desc.bNumInterfaces; i++) {
-+		uif = udev->config->interface[i];
-+		if (uif->altsetting[0].desc.bInterfaceClass == USB_CLASS_AUDIO) {
-+			dev->has_audio_class = 1;
-+			break;
-+		}
++int pvr2_encoder_adjust(struct pvr2_hdw *hdw)
++{
++	int ret;
++	ret = cx2341x_update(hdw,pvr2_encoder_cmd,
++			     (hdw->enc_cur_valid ? &hdw->enc_cur_state : NULL),
++			     &hdw->enc_ctl_state);
++	if (ret) {
++		pvr2_trace(PVR2_TRACE_ERROR_LEGS,
++			   "Error from cx2341x module code=%d",ret);
++	} else {
++		memcpy(&hdw->enc_cur_state,&hdw->enc_ctl_state,
++		       sizeof(struct cx2341x_mpeg_params));
++		hdw->enc_cur_valid = !0;
 +	}
++	return ret;
++}
 +
-+	printk(KERN_INFO DRIVER_NAME " %s usb audio class\n",
-+		   dev->has_audio_class ? "Has" : "Doesn't have");
++
+ int pvr2_encoder_configure(struct pvr2_hdw *hdw)
+ {
+ 	int ret;
+@@ -412,7 +433,7 @@ int pvr2_encoder_configure(struct pvr2_hdw *hdw)
  
- 	/* compute alternate max packet sizes */
- 	uif = udev->actconfig->interface[0];
-@@ -1784,33 +2102,20 @@ static int em28xx_usb_probe(struct usb_interface *interface,
+ 	/* saa7115: 0xf0 */
+ 	val = 0xf0;
+-	if (hdw->hdw_type == PVR2_HDW_TYPE_24XXX) {
++	if (hdw->hdw_desc->flag_has_cx25840) {
+ 		/* ivtv cx25840: 0x140 */
+ 		val = 0x140;
+ 	}
+@@ -436,18 +457,10 @@ int pvr2_encoder_configure(struct pvr2_hdw *hdw)
+ 		return ret;
  	}
  
- 	if ((card[nr]>=0)&&(card[nr]<em28xx_bcount))
--		model=card[nr];
--
--	if ((model==EM2800_BOARD_UNKNOWN)||(model==EM2820_BOARD_UNKNOWN)) {
--		em28xx_errdev( "Your board has no eeprom inside it and thus can't\n"
--			"%s: be autodetected.  Please pass card=<n> insmod option to\n"
--			"%s: workaround that.  Redirect complaints to the vendor of\n"
--			"%s: the TV card. Generic type will be used."
--			"%s: Best regards,\n"
--			"%s:         -- tux\n",
--			dev->name,dev->name,dev->name,dev->name,dev->name);
--		em28xx_errdev("%s: Here is a list of valid choices for the card=<n> insmod option:\n",
--			dev->name);
--		for (i = 0; i < em28xx_bcount; i++) {
--			em28xx_errdev("    card=%d -> %s\n", i,
--							em28xx_boards[i].name);
--		}
+-	ret = cx2341x_update(hdw,pvr2_encoder_cmd,
+-			     (hdw->enc_cur_valid ? &hdw->enc_cur_state : NULL),
+-			     &hdw->enc_ctl_state);
+-	if (ret) {
+-		pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+-			   "Error from cx2341x module code=%d",ret);
+-		return ret;
 -	}
-+		dev->model = card[nr];
+-
+-	ret = 0;
++	ret = pvr2_encoder_adjust(hdw);
++	if (ret) return ret;
  
- 	/* allocate device struct */
--	retval = em28xx_init_dev(&dev, udev, nr, model);
-+	retval = em28xx_init_dev(&dev, udev, nr);
- 	if (retval)
- 		return retval;
+-	if (!ret) ret = pvr2_encoder_vcmd(
++	ret = pvr2_encoder_vcmd(
+ 		hdw, CX2341X_ENC_INITIALIZE_INPUT, 0);
  
--	em28xx_info("Found %s\n", em28xx_boards[model].name);
-+	em28xx_info("Found %s\n", em28xx_boards[dev->model].name);
+ 	if (ret) {
+@@ -456,10 +469,6 @@ int pvr2_encoder_configure(struct pvr2_hdw *hdw)
+ 		return ret;
+ 	}
  
- 	/* save our data pointer in this interface device */
- 	usb_set_intfdata(interface, dev);
-+
-+	request_modules(dev);
-+
+-	hdw->subsys_enabled_mask |= (1<<PVR2_SUBSYS_B_ENC_CFG);
+-	memcpy(&hdw->enc_cur_state,&hdw->enc_ctl_state,
+-	       sizeof(struct cx2341x_mpeg_params));
+-	hdw->enc_cur_valid = !0;
  	return 0;
  }
  
-@@ -1821,18 +2126,20 @@ static int em28xx_usb_probe(struct usb_interface *interface,
-  */
- static void em28xx_usb_disconnect(struct usb_interface *interface)
- {
--	struct em28xx *dev = usb_get_intfdata(interface);
-+	struct em28xx *dev;
-+	struct em28xx_ops *ops = NULL;
-+
-+	dev = usb_get_intfdata(interface);
- 	usb_set_intfdata(interface, NULL);
+@@ -478,7 +487,7 @@ int pvr2_encoder_start(struct pvr2_hdw *hdw)
+ 	pvr2_encoder_vcmd(hdw,CX2341X_ENC_MUTE_VIDEO,1,
+ 			  hdw->input_val == PVR2_CVAL_INPUT_RADIO ? 1 : 0);
  
- 	if (!dev)
- 		return;
+-	switch (hdw->config) {
++	switch (hdw->active_stream_type) {
+ 	case pvr2_config_vbi:
+ 		status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_START_CAPTURE,2,
+ 					   0x01,0x14);
+@@ -492,9 +501,6 @@ int pvr2_encoder_start(struct pvr2_hdw *hdw)
+ 					   0,0x13);
+ 		break;
+ 	}
+-	if (!status) {
+-		hdw->subsys_enabled_mask |= (1<<PVR2_SUBSYS_B_ENC_RUN);
+-	}
+ 	return status;
+ }
  
--	down_write(&em28xx_disconnect);
-+	em28xx_info("disconnecting %s\n", dev->vdev->name);
+@@ -505,7 +511,7 @@ int pvr2_encoder_stop(struct pvr2_hdw *hdw)
+ 	/* mask all interrupts */
+ 	pvr2_write_register(hdw, 0x0048, 0xffffffff);
  
-+	/* wait until all current v4l2 io is finished then deallocate resources */
- 	mutex_lock(&dev->lock);
+-	switch (hdw->config) {
++	switch (hdw->active_stream_type) {
+ 	case pvr2_config_vbi:
+ 		status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_STOP_CAPTURE,3,
+ 					   0x01,0x01,0x14);
+@@ -526,9 +532,6 @@ int pvr2_encoder_stop(struct pvr2_hdw *hdw)
+ 	pvr2_hdw_gpio_chg_dir(hdw,0xffffffff,0x00000401);
+ 	pvr2_hdw_gpio_chg_out(hdw,0xffffffff,0x00000000);
  
--	em28xx_info("disconnecting %s\n", dev->vdev->name);
--
- 	wake_up_interruptible_all(&dev->open);
+-	if (!status) {
+-		hdw->subsys_enabled_mask &= ~(1<<PVR2_SUBSYS_B_ENC_RUN);
+-	}
+ 	return status;
+ }
  
- 	if (dev->users) {
-@@ -1850,15 +2157,20 @@ static void em28xx_usb_disconnect(struct usb_interface *interface)
- 		dev->state |= DEV_DISCONNECTED;
- 		em28xx_release_resources(dev);
- 	}
--
- 	mutex_unlock(&dev->lock);
+diff --git a/drivers/media/video/pvrusb2/pvrusb2-encoder.h b/drivers/media/video/pvrusb2/pvrusb2-encoder.h
+index 01b5a0b..54caf2e 100644
+--- a/drivers/media/video/pvrusb2/pvrusb2-encoder.h
++++ b/drivers/media/video/pvrusb2/pvrusb2-encoder.h
+@@ -25,6 +25,7 @@
  
-+	mutex_lock(&em28xx_extension_devlist_lock);
-+	if (!list_empty(&em28xx_extension_devlist)) {
-+		list_for_each_entry(ops, &em28xx_extension_devlist, next) {
-+			ops->fini(dev);
-+		}
-+	}
-+	mutex_unlock(&em28xx_extension_devlist_lock);
-+
- 	if (!dev->users) {
- 		kfree(dev->alt_max_pkt_size);
- 		kfree(dev);
- 	}
--
--	up_write(&em28xx_disconnect);
- }
+ struct pvr2_hdw;
  
- static struct usb_driver em28xx_usb_driver = {
-diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h
-index d8fcc9e..f3bad0c 100644
---- a/drivers/media/video/em28xx/em28xx.h
-+++ b/drivers/media/video/em28xx/em28xx.h
-@@ -25,28 +25,11 @@
- #ifndef _EM28XX_H
- #define _EM28XX_H
++int pvr2_encoder_adjust(struct pvr2_hdw *);
+ int pvr2_encoder_configure(struct pvr2_hdw *);
+ int pvr2_encoder_start(struct pvr2_hdw *);
+ int pvr2_encoder_stop(struct pvr2_hdw *);
+diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
+index f873994..d7a216b 100644
+--- a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
++++ b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
+@@ -35,10 +35,12 @@
  
--#include <linux/videodev.h>
-+#include <linux/videodev2.h>
+ #include <linux/videodev2.h>
  #include <linux/i2c.h>
++#include <linux/workqueue.h>
  #include <linux/mutex.h>
- #include <media/ir-kbd-i2c.h>
- 
--/* Boards supported by driver */
--
--#define EM2800_BOARD_UNKNOWN			0
--#define EM2820_BOARD_UNKNOWN			1
--#define EM2820_BOARD_TERRATEC_CINERGY_250	2
--#define EM2820_BOARD_PINNACLE_USB_2		3
--#define EM2820_BOARD_HAUPPAUGE_WINTV_USB_2      4
--#define EM2820_BOARD_MSI_VOX_USB_2              5
--#define EM2800_BOARD_TERRATEC_CINERGY_200       6
--#define EM2800_BOARD_LEADTEK_WINFAST_USBII      7
--#define EM2800_BOARD_KWORLD_USB2800             8
--#define EM2820_BOARD_PINNACLE_DVC_90		9
--#define EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900	10
--#define EM2880_BOARD_TERRATEC_HYBRID_XS		11
--#define EM2820_BOARD_KWORLD_PVRTV2800RF		12
--#define EM2880_BOARD_TERRATEC_PRODIGY_XS	13
--
- #define UNSET -1
- 
- /* maximum number of em28xx boards */
-@@ -148,10 +131,17 @@ enum enum28xx_itype {
- 	EM28XX_RADIO,
- };
+ #include "pvrusb2-hdw.h"
+ #include "pvrusb2-io.h"
+ #include <media/cx2341x.h>
++#include "pvrusb2-devattr.h"
  
-+enum em28xx_amux {
-+	EM28XX_AMUX_VIDEO,
-+	EM28XX_AMUX_LINE_IN,
-+	EM28XX_AMUX_AC97_VIDEO,
-+	EM28XX_AMUX_AC97_LINE_IN,
-+};
-+
- struct em28xx_input {
- 	enum enum28xx_itype type;
- 	unsigned int vmux;
--	unsigned int amux;
-+	enum em28xx_amux amux;
- };
+ /* Legal values for PVR2_CID_HSM */
+ #define PVR2_CVAL_HSM_FAIL 0
+@@ -161,10 +163,6 @@ struct pvr2_decoder_ctrl {
+ #define FW1_STATE_RELOAD 3
+ #define FW1_STATE_OK 4
  
- #define INPUT(nr) (&em28xx_boards[dev->model].input[nr])
-@@ -165,19 +155,23 @@ enum em28xx_decoder {
- struct em28xx_board {
- 	char *name;
- 	int vchannels;
--	int norm;
- 	int tuner_type;
+-/* Known major hardware variants, keyed from device ID */
+-#define PVR2_HDW_TYPE_29XXX 0
+-#define PVR2_HDW_TYPE_24XXX 1
+-
+ typedef int (*pvr2_i2c_func)(struct pvr2_hdw *,u8,u8 *,u16,u8 *, u16);
+ #define PVR2_I2C_FUNC_CNT 128
  
- 	/* i2c flags */
--	unsigned int is_em2800;
- 	unsigned int tda9887_conf;
+@@ -176,8 +174,15 @@ struct pvr2_hdw {
+ 	struct usb_device *usb_dev;
+ 	struct usb_interface *usb_intf;
  
--	unsigned int has_tuner:1;
-+	unsigned int is_em2800:1;
- 	unsigned int has_msp34xx:1;
-+	unsigned int mts_firmware:1;
-+	unsigned int has_12mhz_i2s:1;
-+	unsigned int max_range_640_480:1;
+-	/* Device type, one of PVR2_HDW_TYPE_xxxxx */
+-	unsigned int hdw_type;
++	/* Device description, anything that must adjust behavior based on
++	   device specific info will use information held here. */
++	const struct pvr2_device_desc *hdw_desc;
 +
-+	unsigned int analog_gpio;
- 
- 	enum em28xx_decoder decoder;
- 
- 	struct em28xx_input       input[MAX_EM28XX_INPUT];
-+	struct em28xx_input	  radio;
- };
- 
- struct em28xx_eeprom {
-@@ -201,12 +195,26 @@ enum em28xx_dev_state {
- 	DEV_MISCONFIGURED = 0x04,
- };
++	/* Kernel worker thread handling */
++	struct workqueue_struct *workqueue;
++	struct work_struct workpoll;     /* Update driver state */
++	struct work_struct worki2csync;  /* Update i2c clients */
++	struct work_struct workinit;     /* Driver initialization sequence */
  
--/* tvnorms */
--struct em28xx_tvnorm {
--	char *name;
--	v4l2_std_id id;
--	/* mode for saa7113h */
--	int mode;
-+#define EM28XX_AUDIO_BUFS 5
-+#define EM28XX_NUM_AUDIO_PACKETS 64
-+#define EM28XX_AUDIO_MAX_PACKET_SIZE 196 /* static value */
-+#define EM28XX_CAPTURE_STREAM_EN 1
-+#define EM28XX_AUDIO   0x10
-+
-+struct em28xx_audio {
-+	char name[50];
-+	char *transfer_buffer[EM28XX_AUDIO_BUFS];
-+	struct urb *urb[EM28XX_AUDIO_BUFS];
-+	struct usb_device *udev;
-+	unsigned int capture_transfer_done;
-+	struct snd_pcm_substream   *capture_pcm_substream;
-+
-+	unsigned int hwptr_done_capture;
-+	struct snd_card            *sndcard;
-+
-+	int users, shutdown;
-+	enum em28xx_stream_state capture_stream;
-+	spinlock_t slock;
- };
+ 	/* Video spigot */
+ 	struct pvr2_stream *vid_stream;
+@@ -186,9 +191,6 @@ struct pvr2_hdw {
+ 	struct mutex big_lock_mutex;
+ 	int big_lock_held;  /* For debugging */
  
- /* main device struct */
-@@ -215,12 +223,17 @@ struct em28xx {
- 	char name[30];		/* name (including minor) of the device */
- 	int model;		/* index in the device_data struct */
- 	int devno;		/* marks the number of this device */
--	unsigned int is_em2800;
--	int video_inputs;	/* number of video inputs */
--	struct list_head	devlist;
--	unsigned int has_tuner:1;
-+	unsigned int analog_gpio;
-+	unsigned int is_em2800:1;
- 	unsigned int has_msp34xx:1;
- 	unsigned int has_tda9887:1;
-+	unsigned int stream_on:1;	/* Locks streams */
-+	unsigned int has_audio_class:1;
-+	unsigned int has_12mhz_i2s:1;
-+	unsigned int max_range_640_480:1;
-+
-+	int video_inputs;	/* number of video inputs */
-+	struct list_head	devlist;
+-	void (*poll_trigger_func)(void *);
+-	void *poll_trigger_data;
+-
+ 	char name[32];
  
- 	u32 i2s_speed;		/* I2S speed for audio digital stream */
+ 	/* I2C stuff */
+@@ -215,9 +217,9 @@ struct pvr2_hdw {
+ 	struct urb *ctl_read_urb;
+ 	unsigned char *ctl_write_buffer;
+ 	unsigned char *ctl_read_buffer;
+-	volatile int ctl_write_pend_flag;
+-	volatile int ctl_read_pend_flag;
+-	volatile int ctl_timeout_flag;
++	int ctl_write_pend_flag;
++	int ctl_read_pend_flag;
++	int ctl_timeout_flag;
+ 	struct completion ctl_done;
+ 	unsigned char cmd_buffer[PVR2_CTL_BUFFSIZE];
+ 	int cmd_debug_state;               // Low level command debugging info
+@@ -225,14 +227,48 @@ struct pvr2_hdw {
+ 	unsigned int cmd_debug_write_len;  //
+ 	unsigned int cmd_debug_read_len;   //
  
-@@ -235,8 +248,7 @@ struct em28xx {
- 	/* video for linux */
- 	int users;		/* user count for exclusive use */
- 	struct video_device *vdev;	/* video for linux device struct */
--	struct video_picture vpic;	/* picture settings only used to init saa7113h */
--	struct em28xx_tvnorm *tvnorm;	/* selected tv norm */
-+	v4l2_std_id norm;	/* selected tv norm */
- 	int ctl_freq;		/* selected frequency */
- 	unsigned int ctl_input;	/* selected input */
- 	unsigned int ctl_ainput;	/* slected audio input */
-@@ -256,17 +268,27 @@ struct em28xx {
- 	int vscale;		/* vertical scale factor (see datasheet) */
- 	int interlaced;		/* 1=interlace fileds, 0=just top fileds */
- 	int type;
-+	unsigned int video_bytesread;	/* Number of bytes read */
++	/* Bits of state that describe what is going on with various parts
++	   of the driver. */
++	int state_encoder_ok;         /* Encoder is operational */
++	int state_encoder_run;        /* Encoder is running */
++	int state_encoder_config;     /* Encoder is configured */
++	int state_encoder_waitok;     /* Encoder pre-wait done */
++	int state_decoder_run;        /* Decoder is running */
++	int state_usbstream_run;      /* FX2 is streaming */
++	int state_decoder_quiescent;  /* Decoder idle for > 50msec */
++	int state_pipeline_config;    /* Pipeline is configured */
++	int state_pipeline_req;                /* Somebody wants to stream */
++	int state_pipeline_pause;              /* Pipeline must be paused */
++	int state_pipeline_idle;               /* Pipeline not running */
 +
-+	unsigned long hash;	/* eeprom hash - for boards with generic ID */
-+	unsigned long i2c_hash;	/* i2c devicelist hash - for boards with generic ID */
++	/* This is the master state of the driver.  It is the combined
++	   result of other bits of state.  Examining this will indicate the
++	   overall state of the driver.  Values here are one of
++	   PVR2_STATE_xxxx */
++	unsigned int master_state;
 +
-+	struct em28xx_audio *adev;
- 
- 	/* states */
- 	enum em28xx_dev_state state;
- 	enum em28xx_stream_state stream;
- 	enum em28xx_io_method io;
++	/* True if states must be re-evaluated */
++	int state_stale;
 +
-+	struct work_struct         request_module_wk;
++	void (*state_func)(void *);
++	void *state_data;
 +
- 	/* locks */
--	struct mutex lock, fileop_lock;
-+	struct mutex lock;
- 	spinlock_t queue_lock;
- 	struct list_head inqueue, outqueue;
- 	wait_queue_head_t open, wait_frame, wait_stream;
- 	struct video_device *vbi_dev;
-+	struct video_device *radio_dev;
++	/* Timer for measuring decoder settling time */
++	struct timer_list quiescent_timer;
++
++	/* Timer for measuring encoder pre-wait time */
++	struct timer_list encoder_wait_timer;
++
++	/* Place to block while waiting for state changes */
++	wait_queue_head_t state_wait_data;
++
++
+ 	int flag_ok;            /* device in known good state */
+ 	int flag_disconnected;  /* flag_ok == 0 due to disconnect */
+ 	int flag_init_ok;       /* true if structure is fully initialized */
+-	int flag_streaming_enabled; /* true if streaming should be on */
+ 	int fw1_state;          /* current situation with fw1 */
+-	int flag_encoder_ok;    /* True if encoder is healthy */
+-
+-	int flag_decoder_is_tuned;
++	int flag_decoder_missed;/* We've noticed missing decoder */
++	int flag_tripped;       /* Indicates overall failure to start */
  
- 	unsigned char eedata[256];
+ 	struct pvr2_decoder_ctrl *decoder_ctrl;
  
-@@ -289,16 +311,27 @@ struct em28xx {
- 	int (*em28xx_read_reg_req) (struct em28xx * dev, u8 req, u16 reg);
- };
+@@ -241,12 +277,6 @@ struct pvr2_hdw {
+ 	unsigned int fw_size;
+ 	int fw_cpu_flag; /* True if we are dealing with the CPU */
  
-+struct em28xx_fh {
-+	struct em28xx *dev;
-+	unsigned int  stream_on:1;	/* Locks streams */
-+	int           radio;
-+};
-+
-+struct em28xx_ops {
-+	struct list_head next;
-+	char *name;
-+	int id;
-+	int (*init)(struct em28xx *);
-+	int (*fini)(struct em28xx *);
-+};
-+
- /* Provided by em28xx-i2c.c */
+-	// Which subsystem pieces have been enabled / configured
+-	unsigned long subsys_enabled_mask;
+-
+-	// Which subsystems are manipulated to enable streaming
+-	unsigned long subsys_stream_mask;
+-
+ 	// True if there is a request to trigger logging of state in each
+ 	// module.
+ 	int log_requested;
+@@ -296,13 +326,16 @@ struct pvr2_hdw {
+ 	/* Location of eeprom or a negative number if none */
+ 	int eeprom_addr;
  
- void em28xx_i2c_call_clients(struct em28xx *dev, unsigned int cmd, void *arg);
-+void em28xx_do_i2c_scan(struct em28xx *dev);
- int em28xx_i2c_register(struct em28xx *dev);
- int em28xx_i2c_unregister(struct em28xx *dev);
+-	enum pvr2_config config;
++	enum pvr2_config active_stream_type;
++	enum pvr2_config desired_stream_type;
  
--/* Provided by em28xx-input.c */
+ 	/* Control state needed for cx2341x module */
+ 	struct cx2341x_mpeg_params enc_cur_state;
+ 	struct cx2341x_mpeg_params enc_ctl_state;
+ 	/* True if an encoder attribute has changed */
+ 	int enc_stale;
++	/* True if an unsafe encoder attribute has changed */
++	int enc_unsafe_stale;
+ 	/* True if enc_cur_state is valid */
+ 	int enc_cur_valid;
+ 
+@@ -332,6 +365,7 @@ struct pvr2_hdw {
+ 
+ /* This function gets the current frequency */
+ unsigned long pvr2_hdw_get_cur_freq(struct pvr2_hdw *);
++void pvr2_hdw_set_decoder(struct pvr2_hdw *,struct pvr2_decoder_ctrl *);
+ 
+ #endif /* __PVRUSB2_HDW_INTERNAL_H */
+ 
+diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c
+index 402c594..41ae980 100644
+--- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c
++++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c
+@@ -41,47 +41,6 @@
+ #define TV_MIN_FREQ     55250000L
+ #define TV_MAX_FREQ    850000000L
+ 
+-struct usb_device_id pvr2_device_table[] = {
+-	[PVR2_HDW_TYPE_29XXX] = { USB_DEVICE(0x2040, 0x2900) },
+-	[PVR2_HDW_TYPE_24XXX] = { USB_DEVICE(0x2040, 0x2400) },
+-	{ }
+-};
 -
--void em28xx_set_ir(struct em28xx * dev,struct IR_i2c *ir);
+-MODULE_DEVICE_TABLE(usb, pvr2_device_table);
 -
- /* Provided by em28xx-core.c */
+-static const char *pvr2_device_names[] = {
+-	[PVR2_HDW_TYPE_29XXX] = "WinTV PVR USB2 Model Category 29xxxx",
+-	[PVR2_HDW_TYPE_24XXX] = "WinTV PVR USB2 Model Category 24xxxx",
+-};
+-
+-struct pvr2_string_table {
+-	const char **lst;
+-	unsigned int cnt;
+-};
+-
+-// Names of other client modules to request for 24xxx model hardware
+-static const char *pvr2_client_24xxx[] = {
+-	"cx25840",
+-	"tuner",
+-	"wm8775",
+-};
+-
+-// Names of other client modules to request for 29xxx model hardware
+-static const char *pvr2_client_29xxx[] = {
+-	"msp3400",
+-	"saa7115",
+-	"tuner",
+-};
+-
+-static struct pvr2_string_table pvr2_client_lists[] = {
+-	[PVR2_HDW_TYPE_29XXX] = {
+-		pvr2_client_29xxx, ARRAY_SIZE(pvr2_client_29xxx)
+-	},
+-	[PVR2_HDW_TYPE_24XXX] = {
+-		pvr2_client_24xxx, ARRAY_SIZE(pvr2_client_24xxx)
+-	},
+-};
+-
+ static struct pvr2_hdw *unit_pointers[PVR_NUM] = {[ 0 ... PVR_NUM-1 ] = NULL};
+ static DEFINE_MUTEX(pvr2_unit_mtx);
  
- u32 em28xx_request_buffers(struct em28xx *dev, u32 count);
-@@ -314,8 +347,9 @@ int em28xx_write_regs_req(struct em28xx *dev, u8 req, u16 reg, char *buf,
- int em28xx_write_regs(struct em28xx *dev, u16 reg, char *buf, int len);
- int em28xx_write_reg_bits(struct em28xx *dev, u16 reg, u8 val,
- 			  u8 bitmask);
--int em28xx_write_ac97(struct em28xx *dev, u8 reg, u8 * val);
-+int em28xx_set_audio_source(struct em28xx *dev);
- int em28xx_audio_analog_set(struct em28xx *dev);
-+
- int em28xx_colorlevels_set_default(struct em28xx *dev);
- int em28xx_capture_start(struct em28xx *dev, int start);
- int em28xx_outfmt_set_yuv422(struct em28xx *dev);
-@@ -324,6 +358,10 @@ int em28xx_init_isoc(struct em28xx *dev);
- void em28xx_uninit_isoc(struct em28xx *dev);
- int em28xx_set_alternate(struct em28xx *dev);
+@@ -246,32 +205,46 @@ static const char *control_values_hsm[] = {
+ };
+ 
+ 
+-static const char *control_values_subsystem[] = {
+-	[PVR2_SUBSYS_B_ENC_FIRMWARE]  = "enc_firmware",
+-	[PVR2_SUBSYS_B_ENC_CFG] = "enc_config",
+-	[PVR2_SUBSYS_B_DIGITIZER_RUN] = "digitizer_run",
+-	[PVR2_SUBSYS_B_USBSTREAM_RUN] = "usbstream_run",
+-	[PVR2_SUBSYS_B_ENC_RUN] = "enc_run",
++static const char *pvr2_state_names[] = {
++	[PVR2_STATE_NONE] =    "none",
++	[PVR2_STATE_DEAD] =    "dead",
++	[PVR2_STATE_COLD] =    "cold",
++	[PVR2_STATE_WARM] =    "warm",
++	[PVR2_STATE_ERROR] =   "error",
++	[PVR2_STATE_READY] =   "ready",
++	[PVR2_STATE_RUN] =     "run",
+ };
  
-+/* Provided by em28xx-video.c */
-+int em28xx_register_extension(struct em28xx_ops *dev);
-+void em28xx_unregister_extension(struct em28xx_ops *dev);
 +
- /* Provided by em28xx-cards.c */
- extern int em2800_variant_detect(struct usb_device* udev,int model);
- extern void em28xx_pre_card_setup(struct em28xx *dev);
-@@ -331,8 +369,20 @@ extern void em28xx_card_setup(struct em28xx *dev);
- extern struct em28xx_board em28xx_boards[];
- 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);
++static void pvr2_hdw_state_sched(struct pvr2_hdw *);
++static int pvr2_hdw_state_eval(struct pvr2_hdw *);
+ static void pvr2_hdw_set_cur_freq(struct pvr2_hdw *,unsigned long);
++static void pvr2_hdw_worker_i2c(struct work_struct *work);
++static void pvr2_hdw_worker_poll(struct work_struct *work);
++static void pvr2_hdw_worker_init(struct work_struct *work);
++static int pvr2_hdw_wait(struct pvr2_hdw *,int state);
++static int pvr2_hdw_untrip_unlocked(struct pvr2_hdw *);
++static void pvr2_hdw_state_log_state(struct pvr2_hdw *);
+ static int pvr2_hdw_cmd_usbstream(struct pvr2_hdw *hdw,int runFl);
+-static int pvr2_hdw_commit_ctl_internal(struct pvr2_hdw *hdw);
++static int pvr2_hdw_commit_setup(struct pvr2_hdw *hdw);
+ static int pvr2_hdw_get_eeprom_addr(struct pvr2_hdw *hdw);
+ static void pvr2_hdw_internal_find_stdenum(struct pvr2_hdw *hdw);
+ static void pvr2_hdw_internal_set_std_avail(struct pvr2_hdw *hdw);
+-static void pvr2_hdw_render_useless_unlocked(struct pvr2_hdw *hdw);
+-static void pvr2_hdw_subsys_bit_chg_no_lock(struct pvr2_hdw *hdw,
+-					    unsigned long msk,
+-					    unsigned long val);
+-static void pvr2_hdw_subsys_stream_bit_chg_no_lock(struct pvr2_hdw *hdw,
+-						   unsigned long msk,
+-						   unsigned long val);
++static void pvr2_hdw_quiescent_timeout(unsigned long);
++static void pvr2_hdw_encoder_wait_timeout(unsigned long);
+ static int pvr2_send_request_ex(struct pvr2_hdw *hdw,
+ 				unsigned int timeout,int probe_fl,
+ 				void *write_data,unsigned int write_len,
+ 				void *read_data,unsigned int read_len);
+ 
 +
-+/* Provided by em28xx-input.c */
-+/* TODO: Check if the standard get_key handlers on ir-common can be used */
-+int em28xx_get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw);
-+int em28xx_get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw);
-+int em28xx_get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key,
-+				     u32 *ir_raw);
++static void trace_stbit(const char *name,int val)
++{
++	pvr2_trace(PVR2_TRACE_STBITS,
++		   "State bit %s <-- %s",
++		   name,(val ? "true" : "false"));
++}
 +
-+/* em2800 registers */
-+#define EM2800_AUDIOSRC_REG 0x08
+ static int ctrl_channelfreq_get(struct pvr2_ctrl *cptr,int *vp)
+ {
+ 	struct pvr2_hdw *hdw = cptr->hdw;
+@@ -380,8 +353,8 @@ static int ctrl_vres_max_get(struct pvr2_ctrl *cptr,int *vp)
  
- /* em28xx registers */
-+#define I2C_CLK_REG	0x06
- #define CHIPID_REG	0x0a
- #define USBSUSP_REG	0x0c	/* */
+ static int ctrl_vres_min_get(struct pvr2_ctrl *cptr,int *vp)
+ {
+-	/* Actual minimum depends on device type. */
+-	if (cptr->hdw->hdw_type == PVR2_HDW_TYPE_24XXX) {
++	/* Actual minimum depends on device digitizer type. */
++	if (cptr->hdw->hdw_desc->flag_has_cx25840) {
+ 		*vp = 75;
+ 	} else {
+ 		*vp = 17;
+@@ -480,6 +453,7 @@ static int ctrl_cx2341x_is_dirty(struct pvr2_ctrl *cptr)
+ static void ctrl_cx2341x_clear_dirty(struct pvr2_ctrl *cptr)
+ {
+ 	cptr->hdw->enc_stale = 0;
++	cptr->hdw->enc_unsafe_stale = 0;
+ }
  
-@@ -384,9 +434,12 @@ extern const unsigned int em28xx_bcount;
+ static int ctrl_cx2341x_get(struct pvr2_ctrl *cptr,int *vp)
+@@ -502,6 +476,7 @@ static int ctrl_cx2341x_get(struct pvr2_ctrl *cptr,int *vp)
+ static int ctrl_cx2341x_set(struct pvr2_ctrl *cptr,int m,int v)
+ {
+ 	int ret;
++	struct pvr2_hdw *hdw = cptr->hdw;
+ 	struct v4l2_ext_controls cs;
+ 	struct v4l2_ext_control c1;
+ 	memset(&cs,0,sizeof(cs));
+@@ -510,10 +485,22 @@ static int ctrl_cx2341x_set(struct pvr2_ctrl *cptr,int m,int v)
+ 	cs.count = 1;
+ 	c1.id = cptr->info->v4l_id;
+ 	c1.value = v;
+-	ret = cx2341x_ext_ctrls(&cptr->hdw->enc_ctl_state, 0, &cs,
++	ret = cx2341x_ext_ctrls(&hdw->enc_ctl_state,
++				hdw->state_encoder_run, &cs,
+ 				VIDIOC_S_EXT_CTRLS);
++	if (ret == -EBUSY) {
++		/* Oops.  cx2341x is telling us it's not safe to change
++		   this control while we're capturing.  Make a note of this
++		   fact so that the pipeline will be stopped the next time
++		   controls are committed.  Then go on ahead and store this
++		   change anyway. */
++		ret = cx2341x_ext_ctrls(&hdw->enc_ctl_state,
++					0, &cs,
++					VIDIOC_S_EXT_CTRLS);
++		if (!ret) hdw->enc_unsafe_stale = !0;
++	}
+ 	if (ret) return ret;
+-	cptr->hdw->enc_stale = !0;
++	hdw->enc_stale = !0;
+ 	return 0;
+ }
  
- /* em202 registers */
- #define MASTER_AC97	0x02
-+#define LINE_IN_AC97    0x10
- #define VIDEO_AC97	0x14
+@@ -544,7 +531,13 @@ static unsigned int ctrl_cx2341x_getv4lflags(struct pvr2_ctrl *cptr)
  
- /* register settings */
-+#define EM2800_AUDIO_SRC_TUNER  0x0d
-+#define EM2800_AUDIO_SRC_LINE   0x0c
- #define EM28XX_AUDIO_SRC_TUNER	0xc0
- #define EM28XX_AUDIO_SRC_LINE	0x80
+ static int ctrl_streamingenabled_get(struct pvr2_ctrl *cptr,int *vp)
+ {
+-	*vp = cptr->hdw->flag_streaming_enabled;
++	*vp = cptr->hdw->state_pipeline_req;
++	return 0;
++}
++
++static int ctrl_masterstate_get(struct pvr2_ctrl *cptr,int *vp)
++{
++	*vp = cptr->hdw->master_state;
+ 	return 0;
+ }
  
-@@ -406,22 +459,6 @@ extern const unsigned int em28xx_bcount;
- 	printk(KERN_WARNING "%s: "fmt,\
- 			dev->name , ##arg); } while (0)
+@@ -657,29 +650,6 @@ static int ctrl_audio_modes_present_get(struct pvr2_ctrl *cptr,int *vp)
+ 	return 0;
+ }
  
--inline static int em28xx_audio_source(struct em28xx *dev, int input)
+-static int ctrl_subsys_get(struct pvr2_ctrl *cptr,int *vp)
 -{
--	return em28xx_write_reg_bits(dev, AUDIOSRC_REG, input, 0xc0);
+-	*vp = cptr->hdw->subsys_enabled_mask;
+-	return 0;
 -}
 -
--inline static int em28xx_audio_usb_mute(struct em28xx *dev, int mute)
+-static int ctrl_subsys_set(struct pvr2_ctrl *cptr,int m,int v)
 -{
--	return em28xx_write_reg_bits(dev, XCLK_REG, mute ? 0x00 : 0x80, 0x80);
+-	pvr2_hdw_subsys_bit_chg_no_lock(cptr->hdw,m,v);
+-	return 0;
 -}
 -
--inline static int em28xx_audio_analog_setup(struct em28xx *dev)
+-static int ctrl_subsys_stream_get(struct pvr2_ctrl *cptr,int *vp)
 -{
--	/* unmute video mixer with default volume level */
--	return em28xx_write_ac97(dev, VIDEO_AC97, "\x08\x08");
+-	*vp = cptr->hdw->subsys_stream_mask;
+-	return 0;
 -}
 -
- inline static int em28xx_compression_disable(struct em28xx *dev)
- {
- 	/* side effect of disabling scaler and mixer */
-@@ -497,18 +534,17 @@ inline static int em28xx_gamma_set(struct em28xx *dev, s32 val)
- /*FIXME: maxw should be dependent of alt mode */
- inline static unsigned int norm_maxw(struct em28xx *dev)
- {
--	switch(dev->model){
--		case (EM2820_BOARD_MSI_VOX_USB_2): return(640);
--		default: return(720);
--	}
-+	if (dev->max_range_640_480)
-+		return 640;
-+	else
-+		return 720;
- }
+-static int ctrl_subsys_stream_set(struct pvr2_ctrl *cptr,int m,int v)
+-{
+-	pvr2_hdw_subsys_stream_bit_chg_no_lock(cptr->hdw,m,v);
+-	return 0;
+-}
  
- inline static unsigned int norm_maxh(struct em28xx *dev)
+ static int ctrl_stdenumcur_set(struct pvr2_ctrl *cptr,int m,int v)
  {
--	switch(dev->model){
--		case (EM2820_BOARD_MSI_VOX_USB_2): return(480);
--		default: return (dev->tvnorm->id & V4L2_STD_625_50) ? 576 : 480;
--	}
-+	if (dev->max_range_640_480)
-+		return 480;
-+	else
-+		return (dev->norm & V4L2_STD_625_50) ? 576 : 480;
- }
--
- #endif
-diff --git a/drivers/media/video/et61x251/et61x251_core.c b/drivers/media/video/et61x251/et61x251_core.c
-index d19d73b..06b6a3a 100644
---- a/drivers/media/video/et61x251/et61x251_core.c
-+++ b/drivers/media/video/et61x251/et61x251_core.c
-@@ -227,7 +227,7 @@ int et61x251_write_reg(struct et61x251_device* cam, u8 value, u16 index)
- }
+@@ -915,6 +885,11 @@ static const struct pvr2_ctl_info control_defs[] = {
+ 		.get_value = ctrl_hsm_get,
+ 		DEFENUM(control_values_hsm),
+ 	},{
++		.desc = "Master State",
++		.name = "master_state",
++		.get_value = ctrl_masterstate_get,
++		DEFENUM(pvr2_state_names),
++	},{
+ 		.desc = "Signal Present",
+ 		.name = "signal_present",
+ 		.get_value = ctrl_signal_get,
+@@ -955,20 +930,6 @@ static const struct pvr2_ctl_info control_defs[] = {
+ 		.sym_to_val = ctrl_std_sym_to_val,
+ 		.type = pvr2_ctl_bitmask,
+ 	},{
+-		.desc = "Subsystem enabled mask",
+-		.name = "debug_subsys_mask",
+-		.skip_init = !0,
+-		.get_value = ctrl_subsys_get,
+-		.set_value = ctrl_subsys_set,
+-		DEFMASK(PVR2_SUBSYS_ALL,control_values_subsystem),
+-	},{
+-		.desc = "Subsystem stream mask",
+-		.name = "debug_subsys_stream_mask",
+-		.skip_init = !0,
+-		.get_value = ctrl_subsys_stream_get,
+-		.set_value = ctrl_subsys_stream_set,
+-		DEFMASK(PVR2_SUBSYS_ALL,control_values_subsystem),
+-	},{
+ 		.desc = "Video Standard Name",
+ 		.name = "video_standard",
+ 		.internal_id = PVR2_CID_STDENUM,
+@@ -1129,25 +1090,13 @@ static int pvr2_upload_firmware1(struct pvr2_hdw *hdw)
+ 	unsigned int pipe;
+ 	int ret;
+ 	u16 address;
+-	static const char *fw_files_29xxx[] = {
+-		"v4l-pvrusb2-29xxx-01.fw",
+-	};
+-	static const char *fw_files_24xxx[] = {
+-		"v4l-pvrusb2-24xxx-01.fw",
+-	};
+-	static const struct pvr2_string_table fw_file_defs[] = {
+-		[PVR2_HDW_TYPE_29XXX] = {
+-			fw_files_29xxx, ARRAY_SIZE(fw_files_29xxx)
+-		},
+-		[PVR2_HDW_TYPE_24XXX] = {
+-			fw_files_24xxx, ARRAY_SIZE(fw_files_24xxx)
+-		},
+-	};
+ 
+-	if ((hdw->hdw_type >= ARRAY_SIZE(fw_file_defs)) ||
+-	    (!fw_file_defs[hdw->hdw_type].lst)) {
++	if (!hdw->hdw_desc->fx2_firmware.cnt) {
+ 		hdw->fw1_state = FW1_STATE_OK;
+-		return 0;
++		pvr2_trace(PVR2_TRACE_ERROR_LEGS,
++			   "Connected device type defines"
++			   " no firmware to upload; ignoring firmware");
++		return -ENOTTY;
+ 	}
  
+ 	hdw->fw1_state = FW1_STATE_FAILED; // default result
+@@ -1155,8 +1104,8 @@ static int pvr2_upload_firmware1(struct pvr2_hdw *hdw)
+ 	trace_firmware("pvr2_upload_firmware1");
  
--int et61x251_read_reg(struct et61x251_device* cam, u16 index)
-+static int et61x251_read_reg(struct et61x251_device* cam, u16 index)
- {
- 	struct usb_device* udev = cam->usbdev;
- 	u8* buff = cam->control_buffer;
-@@ -269,73 +269,6 @@ et61x251_i2c_wait(struct et61x251_device* cam,
+ 	ret = pvr2_locate_firmware(hdw,&fw_entry,"fx2 controller",
+-				   fw_file_defs[hdw->hdw_type].cnt,
+-				   fw_file_defs[hdw->hdw_type].lst);
++				   hdw->hdw_desc->fx2_firmware.cnt,
++				   hdw->hdw_desc->fx2_firmware.lst);
+ 	if (ret < 0) {
+ 		if (ret == -ENOENT) hdw->fw1_state = FW1_STATE_MISSING;
+ 		return ret;
+@@ -1231,8 +1180,7 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw)
+ 		CX2341X_FIRM_ENC_FILENAME,
+ 	};
+ 
+-	if ((hdw->hdw_type != PVR2_HDW_TYPE_29XXX) &&
+-	    (hdw->hdw_type != PVR2_HDW_TYPE_24XXX)) {
++	if (hdw->hdw_desc->flag_skip_cx23416_firmware) {
+ 		return 0;
+ 	}
  
+@@ -1248,8 +1196,6 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw)
+ 	   time we configure the encoder, then we'll fully configure it. */
+ 	hdw->enc_cur_valid = 0;
  
- int
--et61x251_i2c_try_read(struct et61x251_device* cam,
--		      const struct et61x251_sensor* sensor, u8 address)
--{
--	struct usb_device* udev = cam->usbdev;
--	u8* data = cam->control_buffer;
--	int err = 0, res;
--
--	data[0] = address;
--	data[1] = cam->sensor.i2c_slave_id;
--	data[2] = cam->sensor.rsta | 0x10;
--	data[3] = !(et61x251_read_reg(cam, 0x8b) & 0x02);
--	res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41,
--			      0, 0x88, data, 4, ET61X251_CTRL_TIMEOUT);
--	if (res < 0)
--		err += res;
--
--	err += et61x251_i2c_wait(cam, sensor);
+-	hdw->flag_encoder_ok = 0;
 -
--	res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00, 0xc1,
--			      0, 0x80, data, 8, ET61X251_CTRL_TIMEOUT);
--	if (res < 0)
--		err += res;
+ 	/* First prepare firmware loading */
+ 	ret |= pvr2_write_register(hdw, 0x0048, 0xffffffff); /*interrupt mask*/
+ 	ret |= pvr2_hdw_gpio_chg_dir(hdw,0xffffffff,0x00000088); /*gpio dir*/
+@@ -1347,293 +1293,129 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw)
+ 	if (ret) {
+ 		pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ 			   "firmware2 upload post-proc failure");
+-	} else {
+-		hdw->flag_encoder_ok = !0;
+-		hdw->subsys_enabled_mask |= (1<<PVR2_SUBSYS_B_ENC_FIRMWARE);
+ 	}
+ 	return ret;
+ }
+ 
+ 
+-#define FIRMWARE_RECOVERY_BITS \
+-	((1<<PVR2_SUBSYS_B_ENC_CFG) | \
+-	 (1<<PVR2_SUBSYS_B_ENC_RUN) | \
+-	 (1<<PVR2_SUBSYS_B_ENC_FIRMWARE) | \
+-	 (1<<PVR2_SUBSYS_B_USBSTREAM_RUN))
 -
--	if (err)
--		DBG(3, "I2C read failed for %s image sensor", sensor->name);
+-/*
 -
--	PDBGG("I2C read: address 0x%02X, value: 0x%02X", address, data[0]);
+-  This single function is key to pretty much everything.  The pvrusb2
+-  device can logically be viewed as a series of subsystems which can be
+-  stopped / started or unconfigured / configured.  To get things streaming,
+-  one must configure everything and start everything, but there may be
+-  various reasons over time to deconfigure something or stop something.
+-  This function handles all of this activity.  Everything EVERYWHERE that
+-  must affect a subsystem eventually comes here to do the work.
 -
--	return err ? -1 : (int)data[0];
--}
+-  The current state of all subsystems is represented by a single bit mask,
+-  known as subsys_enabled_mask.  The bit positions are defined by the
+-  PVR2_SUBSYS_xxxx macros, with one subsystem per bit position.  At any
+-  time the set of configured or active subsystems can be queried just by
+-  looking at that mask.  To change bits in that mask, this function here
+-  must be called.  The "msk" argument indicates which bit positions to
+-  change, and the "val" argument defines the new values for the positions
+-  defined by "msk".
 -
+-  There is a priority ordering of starting / stopping things, and for
+-  multiple requested changes, this function implements that ordering.
+-  (Thus we will act on a request to load encoder firmware before we
+-  configure the encoder.)  In addition to priority ordering, there is a
+-  recovery strategy implemented here.  If a particular step fails and we
+-  detect that failure, this function will clear the affected subsystem bits
+-  and restart.  Thus we have a means for recovering from a dead encoder:
+-  Clear all bits that correspond to subsystems that we need to restart /
+-  reconfigure and start over.
 -
--int
--et61x251_i2c_try_write(struct et61x251_device* cam,
--		       const struct et61x251_sensor* sensor, u8 address,
--		       u8 value)
+-*/
+-static void pvr2_hdw_subsys_bit_chg_no_lock(struct pvr2_hdw *hdw,
+-					    unsigned long msk,
+-					    unsigned long val)
 -{
--	struct usb_device* udev = cam->usbdev;
--	u8* data = cam->control_buffer;
--	int err = 0, res;
--
--	data[0] = address;
--	data[1] = cam->sensor.i2c_slave_id;
--	data[2] = cam->sensor.rsta | 0x12;
--	res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41,
--			      0, 0x88, data, 3, ET61X251_CTRL_TIMEOUT);
--	if (res < 0)
--		err += res;
--
--	data[0] = value;
--	res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41,
--			      0, 0x80, data, 1, ET61X251_CTRL_TIMEOUT);
--	if (res < 0)
--		err += res;
--
--	err += et61x251_i2c_wait(cam, sensor);
+-	unsigned long nmsk;
+-	unsigned long vmsk;
+-	int ret;
+-	unsigned int tryCount = 0;
 -
--	if (err)
--		DBG(3, "I2C write failed for %s image sensor", sensor->name);
+-	if (!hdw->flag_ok) return;
 -
--	PDBGG("I2C write: address 0x%02X, value: 0x%02X", address, value);
+-	msk &= PVR2_SUBSYS_ALL;
+-	nmsk = (hdw->subsys_enabled_mask & ~msk) | (val & msk);
+-	nmsk &= PVR2_SUBSYS_ALL;
 -
--	return err ? -1 : 0;
--}
+-	for (;;) {
+-		tryCount++;
+-		if (!((nmsk ^ hdw->subsys_enabled_mask) &
+-		      PVR2_SUBSYS_ALL)) break;
+-		if (tryCount > 4) {
+-			pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+-				   "Too many retries when configuring device;"
+-				   " giving up");
+-			pvr2_hdw_render_useless(hdw);
+-			break;
+-		}
+-		if (tryCount > 1) {
+-			pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+-				   "Retrying device reconfiguration");
+-		}
+-		pvr2_trace(PVR2_TRACE_INIT,
+-			   "subsys mask changing 0x%lx:0x%lx"
+-			   " from 0x%lx to 0x%lx",
+-			   msk,val,hdw->subsys_enabled_mask,nmsk);
 -
+-		vmsk = (nmsk ^ hdw->subsys_enabled_mask) &
+-			hdw->subsys_enabled_mask;
+-		if (vmsk) {
+-			if (vmsk & (1<<PVR2_SUBSYS_B_ENC_RUN)) {
+-				pvr2_trace(PVR2_TRACE_CTL,
+-					   "/*---TRACE_CTL----*/"
+-					   " pvr2_encoder_stop");
+-				ret = pvr2_encoder_stop(hdw);
+-				if (ret) {
+-					pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+-						   "Error recovery initiated");
+-					hdw->subsys_enabled_mask &=
+-						~FIRMWARE_RECOVERY_BITS;
+-					continue;
+-				}
+-			}
+-			if (vmsk & (1<<PVR2_SUBSYS_B_USBSTREAM_RUN)) {
+-				pvr2_trace(PVR2_TRACE_CTL,
+-					   "/*---TRACE_CTL----*/"
+-					   " pvr2_hdw_cmd_usbstream(0)");
+-				pvr2_hdw_cmd_usbstream(hdw,0);
+-			}
+-			if (vmsk & (1<<PVR2_SUBSYS_B_DIGITIZER_RUN)) {
+-				pvr2_trace(PVR2_TRACE_CTL,
+-					   "/*---TRACE_CTL----*/"
+-					   " decoder disable");
+-				if (hdw->decoder_ctrl) {
+-					hdw->decoder_ctrl->enable(
+-						hdw->decoder_ctrl->ctxt,0);
+-				} else {
+-					pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+-						   "WARNING:"
+-						   " No decoder present");
+-				}
+-				hdw->subsys_enabled_mask &=
+-					~(1<<PVR2_SUBSYS_B_DIGITIZER_RUN);
+-			}
+-			if (vmsk & PVR2_SUBSYS_CFG_ALL) {
+-				hdw->subsys_enabled_mask &=
+-					~(vmsk & PVR2_SUBSYS_CFG_ALL);
+-			}
+-		}
+-		vmsk = (nmsk ^ hdw->subsys_enabled_mask) & nmsk;
+-		if (vmsk) {
+-			if (vmsk & (1<<PVR2_SUBSYS_B_ENC_FIRMWARE)) {
+-				pvr2_trace(PVR2_TRACE_CTL,
+-					   "/*---TRACE_CTL----*/"
+-					   " pvr2_upload_firmware2");
+-				ret = pvr2_upload_firmware2(hdw);
+-				if (ret) {
+-					pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+-						   "Failure uploading encoder"
+-						   " firmware");
+-					pvr2_hdw_render_useless(hdw);
+-					break;
+-				}
+-			}
+-			if (vmsk & (1<<PVR2_SUBSYS_B_ENC_CFG)) {
+-				pvr2_trace(PVR2_TRACE_CTL,
+-					   "/*---TRACE_CTL----*/"
+-					   " pvr2_encoder_configure");
+-				ret = pvr2_encoder_configure(hdw);
+-				if (ret) {
+-					pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+-						   "Error recovery initiated");
+-					hdw->subsys_enabled_mask &=
+-						~FIRMWARE_RECOVERY_BITS;
+-					continue;
+-				}
+-			}
+-			if (vmsk & (1<<PVR2_SUBSYS_B_DIGITIZER_RUN)) {
+-				pvr2_trace(PVR2_TRACE_CTL,
+-					   "/*---TRACE_CTL----*/"
+-					   " decoder enable");
+-				if (hdw->decoder_ctrl) {
+-					hdw->decoder_ctrl->enable(
+-						hdw->decoder_ctrl->ctxt,!0);
+-				} else {
+-					pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+-						   "WARNING:"
+-						   " No decoder present");
+-				}
+-				hdw->subsys_enabled_mask |=
+-					(1<<PVR2_SUBSYS_B_DIGITIZER_RUN);
+-			}
+-			if (vmsk & (1<<PVR2_SUBSYS_B_USBSTREAM_RUN)) {
+-				pvr2_trace(PVR2_TRACE_CTL,
+-					   "/*---TRACE_CTL----*/"
+-					   " pvr2_hdw_cmd_usbstream(1)");
+-				pvr2_hdw_cmd_usbstream(hdw,!0);
+-			}
+-			if (vmsk & (1<<PVR2_SUBSYS_B_ENC_RUN)) {
+-				pvr2_trace(PVR2_TRACE_CTL,
+-					   "/*---TRACE_CTL----*/"
+-					   " pvr2_encoder_start");
+-				ret = pvr2_encoder_start(hdw);
+-				if (ret) {
+-					pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+-						   "Error recovery initiated");
+-					hdw->subsys_enabled_mask &=
+-						~FIRMWARE_RECOVERY_BITS;
+-					continue;
+-				}
+-			}
+-		}
++static const char *pvr2_get_state_name(unsigned int st)
++{
++	if (st < ARRAY_SIZE(pvr2_state_names)) {
++		return pvr2_state_names[st];
+ 	}
++	return "???";
+ }
+ 
 -
--int
- et61x251_i2c_raw_write(struct et61x251_device* cam, u8 n, u8 data1, u8 data2,
- 		       u8 data3, u8 data4, u8 data5, u8 data6, u8 data7,
- 		       u8 data8, u8 address)
-@@ -387,17 +320,6 @@ et61x251_i2c_raw_write(struct et61x251_device* cam, u8 n, u8 data1, u8 data2,
+-void pvr2_hdw_subsys_bit_chg(struct pvr2_hdw *hdw,
+-			     unsigned long msk,unsigned long val)
++static int pvr2_decoder_enable(struct pvr2_hdw *hdw,int enablefl)
+ {
+-	LOCK_TAKE(hdw->big_lock); do {
+-		pvr2_hdw_subsys_bit_chg_no_lock(hdw,msk,val);
+-	} while (0); LOCK_GIVE(hdw->big_lock);
++	if (!hdw->decoder_ctrl) {
++		if (!hdw->flag_decoder_missed) {
++			pvr2_trace(PVR2_TRACE_ERROR_LEGS,
++				   "WARNING: No decoder present");
++			hdw->flag_decoder_missed = !0;
++			trace_stbit("flag_decoder_missed",
++				    hdw->flag_decoder_missed);
++		}
++		return -EIO;
++	}
++	hdw->decoder_ctrl->enable(hdw->decoder_ctrl->ctxt,enablefl);
++	return 0;
  }
  
  
--int et61x251_i2c_read(struct et61x251_device* cam, u8 address)
--{
--	return et61x251_i2c_try_read(cam, &cam->sensor, address);
--}
--
--
--int et61x251_i2c_write(struct et61x251_device* cam, u8 address, u8 value)
--{
--	return et61x251_i2c_try_write(cam, &cam->sensor, address, value);
--}
--
- /*****************************************************************************/
+-unsigned long pvr2_hdw_subsys_get(struct pvr2_hdw *hdw)
++void pvr2_hdw_set_decoder(struct pvr2_hdw *hdw,struct pvr2_decoder_ctrl *ptr)
+ {
+-	return hdw->subsys_enabled_mask;
++	if (hdw->decoder_ctrl == ptr) return;
++	hdw->decoder_ctrl = ptr;
++	if (hdw->decoder_ctrl && hdw->flag_decoder_missed) {
++		hdw->flag_decoder_missed = 0;
++		trace_stbit("flag_decoder_missed",
++			    hdw->flag_decoder_missed);
++		pvr2_trace(PVR2_TRACE_ERROR_LEGS,
++			   "Decoder has appeared");
++		pvr2_hdw_state_sched(hdw);
++	}
+ }
  
- static void et61x251_urb_complete(struct urb *urb)
-@@ -675,6 +597,83 @@ static int et61x251_stream_interrupt(struct et61x251_device* cam)
- /*****************************************************************************/
  
- #ifdef CONFIG_VIDEO_ADV_DEBUG
-+
-+static int et61x251_i2c_try_read(struct et61x251_device* cam,
-+				 const struct et61x251_sensor* sensor,
-+				 u8 address)
-+{
-+	struct usb_device* udev = cam->usbdev;
-+	u8* data = cam->control_buffer;
-+	int err = 0, res;
-+
-+	data[0] = address;
-+	data[1] = cam->sensor.i2c_slave_id;
-+	data[2] = cam->sensor.rsta | 0x10;
-+	data[3] = !(et61x251_read_reg(cam, 0x8b) & 0x02);
-+	res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41,
-+			      0, 0x88, data, 4, ET61X251_CTRL_TIMEOUT);
-+	if (res < 0)
-+		err += res;
-+
-+	err += et61x251_i2c_wait(cam, sensor);
-+
-+	res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00, 0xc1,
-+			      0, 0x80, data, 8, ET61X251_CTRL_TIMEOUT);
-+	if (res < 0)
-+		err += res;
-+
-+	if (err)
-+		DBG(3, "I2C read failed for %s image sensor", sensor->name);
-+
-+	PDBGG("I2C read: address 0x%02X, value: 0x%02X", address, data[0]);
-+
-+	return err ? -1 : (int)data[0];
-+}
-+
-+
-+static int et61x251_i2c_try_write(struct et61x251_device* cam,
-+				  const struct et61x251_sensor* sensor,
-+				  u8 address, u8 value)
-+{
-+	struct usb_device* udev = cam->usbdev;
-+	u8* data = cam->control_buffer;
-+	int err = 0, res;
-+
-+	data[0] = address;
-+	data[1] = cam->sensor.i2c_slave_id;
-+	data[2] = cam->sensor.rsta | 0x12;
-+	res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41,
-+			      0, 0x88, data, 3, ET61X251_CTRL_TIMEOUT);
-+	if (res < 0)
-+		err += res;
-+
-+	data[0] = value;
-+	res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41,
-+			      0, 0x80, data, 1, ET61X251_CTRL_TIMEOUT);
-+	if (res < 0)
-+		err += res;
-+
-+	err += et61x251_i2c_wait(cam, sensor);
-+
-+	if (err)
-+		DBG(3, "I2C write failed for %s image sensor", sensor->name);
-+
-+	PDBGG("I2C write: address 0x%02X, value: 0x%02X", address, value);
-+
-+	return err ? -1 : 0;
-+}
-+
-+static int et61x251_i2c_read(struct et61x251_device* cam, u8 address)
-+{
-+	return et61x251_i2c_try_read(cam, &cam->sensor, address);
-+}
-+
-+static int et61x251_i2c_write(struct et61x251_device* cam,
-+			      u8 address, u8 value)
-+{
-+	return et61x251_i2c_try_write(cam, &cam->sensor, address, value);
-+}
-+
- static u8 et61x251_strtou8(const char* buff, size_t len, ssize_t* count)
+-unsigned long pvr2_hdw_subsys_stream_get(struct pvr2_hdw *hdw)
++int pvr2_hdw_get_state(struct pvr2_hdw *hdw)
  {
- 	char str[5];
-diff --git a/drivers/media/video/et61x251/et61x251_sensor.h b/drivers/media/video/et61x251/et61x251_sensor.h
-index e145863..71a0314 100644
---- a/drivers/media/video/et61x251/et61x251_sensor.h
-+++ b/drivers/media/video/et61x251/et61x251_sensor.h
-@@ -52,14 +52,6 @@ et61x251_attach_sensor(struct et61x251_device* cam,
- /*****************************************************************************/
+-	return hdw->subsys_stream_mask;
++	return hdw->master_state;
+ }
  
- extern int et61x251_write_reg(struct et61x251_device*, u8 value, u16 index);
--extern int et61x251_read_reg(struct et61x251_device*, u16 index);
--extern int et61x251_i2c_write(struct et61x251_device*, u8 address, u8 value);
--extern int et61x251_i2c_read(struct et61x251_device*, u8 address);
--extern int et61x251_i2c_try_write(struct et61x251_device*,
--				  const struct et61x251_sensor*, u8 address,
--				  u8 value);
--extern int et61x251_i2c_try_read(struct et61x251_device*,
--				 const struct et61x251_sensor*, u8 address);
- extern int et61x251_i2c_raw_write(struct et61x251_device*, u8 n, u8 data1,
- 				  u8 data2, u8 data3, u8 data4, u8 data5,
- 				  u8 data6, u8 data7, u8 data8, u8 address);
-diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c
-index 29779d8..9851987 100644
---- a/drivers/media/video/ir-kbd-i2c.c
-+++ b/drivers/media/video/ir-kbd-i2c.c
-@@ -398,6 +398,7 @@ static int ir_attach(struct i2c_adapter *adap, int addr,
- 	case 0x7a:
- 	case 0x47:
- 	case 0x71:
-+	case 0x2d:
- 		if (adap->id == I2C_HW_B_CX2388x) {
- 			/* Handled by cx88-input */
- 			name        = "CX2388x remote";
-@@ -504,7 +505,7 @@ static int ir_probe(struct i2c_adapter *adap)
- 	*/
  
- 	static const int probe_bttv[] = { 0x1a, 0x18, 0x4b, 0x64, 0x30, -1};
--	static const int probe_saa7134[] = { 0x7a, 0x47, 0x71, -1 };
-+	static const int probe_saa7134[] = { 0x7a, 0x47, 0x71, 0x2d, -1 };
- 	static const int probe_em28XX[] = { 0x30, 0x47, -1 };
- 	static const int probe_cx88[] = { 0x18, 0x6b, 0x71, -1 };
- 	static const int probe_cx23885[] = { 0x6b, -1 };
-diff --git a/drivers/media/video/ivtv/Kconfig b/drivers/media/video/ivtv/Kconfig
-index 854cc9c..270906f 100644
---- a/drivers/media/video/ivtv/Kconfig
-+++ b/drivers/media/video/ivtv/Kconfig
-@@ -3,6 +3,7 @@ config VIDEO_IVTV
- 	depends on VIDEO_V4L1 && VIDEO_V4L2 && PCI && I2C && EXPERIMENTAL
- 	select I2C_ALGOBIT
- 	select FW_LOADER
-+	select VIDEO_IR
- 	select VIDEO_TUNER
- 	select VIDEO_TVEEPROM
- 	select VIDEO_CX2341X
-@@ -12,6 +13,7 @@ config VIDEO_IVTV
- 	select VIDEO_SAA7127
- 	select VIDEO_TVAUDIO
- 	select VIDEO_CS53L32A
-+	select VIDEO_M52790
- 	select VIDEO_WM8775
- 	select VIDEO_WM8739
- 	select VIDEO_VP27SMPX
-diff --git a/drivers/media/video/ivtv/Makefile b/drivers/media/video/ivtv/Makefile
-index e8eefd9..a038901 100644
---- a/drivers/media/video/ivtv/Makefile
-+++ b/drivers/media/video/ivtv/Makefile
-@@ -6,3 +6,8 @@ ivtv-objs	:= ivtv-routing.o ivtv-cards.o ivtv-controls.o \
+-static void pvr2_hdw_subsys_stream_bit_chg_no_lock(struct pvr2_hdw *hdw,
+-						   unsigned long msk,
+-						   unsigned long val)
++static int pvr2_hdw_untrip_unlocked(struct pvr2_hdw *hdw)
+ {
+-	unsigned long val2;
+-	msk &= PVR2_SUBSYS_ALL;
+-	val2 = ((hdw->subsys_stream_mask & ~msk) | (val & msk));
+-	pvr2_trace(PVR2_TRACE_INIT,
+-		   "stream mask changing 0x%lx:0x%lx from 0x%lx to 0x%lx",
+-		   msk,val,hdw->subsys_stream_mask,val2);
+-	hdw->subsys_stream_mask = val2;
++	if (!hdw->flag_tripped) return 0;
++	hdw->flag_tripped = 0;
++	pvr2_trace(PVR2_TRACE_ERROR_LEGS,
++		   "Clearing driver error statuss");
++	return !0;
+ }
  
- obj-$(CONFIG_VIDEO_IVTV) += ivtv.o
- obj-$(CONFIG_VIDEO_FB_IVTV) += ivtvfb.o
-+
-+EXTRA_CFLAGS += -Idrivers/media/video
-+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
-+EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
-+
-diff --git a/drivers/media/video/ivtv/ivtv-cards.c b/drivers/media/video/ivtv/ivtv-cards.c
-index b6a8be6..f23c6b8 100644
---- a/drivers/media/video/ivtv/ivtv-cards.c
-+++ b/drivers/media/video/ivtv/ivtv-cards.c
-@@ -23,6 +23,7 @@
- #include "ivtv-i2c.h"
  
- #include <media/msp3400.h>
-+#include <media/m52790.h>
- #include <media/wm8775.h>
- #include <media/cs53l32a.h>
- #include <media/cx25840.h>
-@@ -39,6 +40,27 @@
- #define MSP_MONO   MSP_INPUT(MSP_IN_MONO, MSP_IN_TUNER1, \
- 				MSP_DSP_IN_SCART, MSP_DSP_IN_SCART)
+-void pvr2_hdw_subsys_stream_bit_chg(struct pvr2_hdw *hdw,
+-				    unsigned long msk,
+-				    unsigned long val)
++int pvr2_hdw_untrip(struct pvr2_hdw *hdw)
+ {
++	int fl;
+ 	LOCK_TAKE(hdw->big_lock); do {
+-		pvr2_hdw_subsys_stream_bit_chg_no_lock(hdw,msk,val);
++		fl = pvr2_hdw_untrip_unlocked(hdw);
+ 	} while (0); LOCK_GIVE(hdw->big_lock);
++	if (fl) pvr2_hdw_state_sched(hdw);
++	return 0;
+ }
+ 
+ 
+-static int pvr2_hdw_set_streaming_no_lock(struct pvr2_hdw *hdw,int enableFl)
++const char *pvr2_hdw_get_state_name(unsigned int id)
+ {
+-	if ((!enableFl) == !(hdw->flag_streaming_enabled)) return 0;
+-	if (enableFl) {
+-		pvr2_trace(PVR2_TRACE_START_STOP,
+-			   "/*--TRACE_STREAM--*/ enable");
+-		pvr2_hdw_subsys_bit_chg_no_lock(hdw,~0,~0);
+-	} else {
+-		pvr2_trace(PVR2_TRACE_START_STOP,
+-			   "/*--TRACE_STREAM--*/ disable");
+-		pvr2_hdw_subsys_bit_chg_no_lock(hdw,hdw->subsys_stream_mask,0);
+-	}
+-	if (!hdw->flag_ok) return -EIO;
+-	hdw->flag_streaming_enabled = enableFl != 0;
+-	return 0;
++	if (id >= ARRAY_SIZE(pvr2_state_names)) return NULL;
++	return pvr2_state_names[id];
+ }
+ 
+ 
+ int pvr2_hdw_get_streaming(struct pvr2_hdw *hdw)
+ {
+-	return hdw->flag_streaming_enabled != 0;
++	return hdw->state_pipeline_req != 0;
+ }
+ 
+ 
+ int pvr2_hdw_set_streaming(struct pvr2_hdw *hdw,int enable_flag)
+ {
+-	int ret;
++	int ret,st;
+ 	LOCK_TAKE(hdw->big_lock); do {
+-		ret = pvr2_hdw_set_streaming_no_lock(hdw,enable_flag);
++		pvr2_hdw_untrip_unlocked(hdw);
++		if ((!enable_flag) != !(hdw->state_pipeline_req)) {
++			hdw->state_pipeline_req = enable_flag != 0;
++			pvr2_trace(PVR2_TRACE_START_STOP,
++				   "/*--TRACE_STREAM--*/ %s",
++				   enable_flag ? "enable" : "disable");
++		}
++		pvr2_hdw_state_sched(hdw);
+ 	} while (0); LOCK_GIVE(hdw->big_lock);
+-	return ret;
+-}
+-
+-
+-static int pvr2_hdw_set_stream_type_no_lock(struct pvr2_hdw *hdw,
+-					    enum pvr2_config config)
+-{
+-	unsigned long sm = hdw->subsys_enabled_mask;
+-	if (!hdw->flag_ok) return -EIO;
+-	pvr2_hdw_subsys_bit_chg_no_lock(hdw,hdw->subsys_stream_mask,0);
+-	hdw->config = config;
+-	pvr2_hdw_subsys_bit_chg_no_lock(hdw,~0,sm);
++	if ((ret = pvr2_hdw_wait(hdw,0)) < 0) return ret;
++	if (enable_flag) {
++		while ((st = hdw->master_state) != PVR2_STATE_RUN) {
++			if (st != PVR2_STATE_READY) return -EIO;
++			if ((ret = pvr2_hdw_wait(hdw,st)) < 0) return ret;
++		}
++	}
+ 	return 0;
+ }
+ 
  
-+/* usual i2c tuner addresses to probe */
-+static struct ivtv_card_tuner_i2c ivtv_i2c_std = {
-+	.radio = { I2C_CLIENT_END },
-+	.demod = { 0x43, I2C_CLIENT_END },
-+	.tv    = { 0x61, 0x60, I2C_CLIENT_END },
-+};
-+
-+/* as above, but with possible radio tuner */
-+static struct ivtv_card_tuner_i2c ivtv_i2c_radio = {
-+	.radio = { 0x60, I2C_CLIENT_END },
-+	.demod = { 0x43, I2C_CLIENT_END },
-+	.tv    = { 0x61, I2C_CLIENT_END },
-+};
-+
-+/* using the tda8290+75a combo */
-+static struct ivtv_card_tuner_i2c ivtv_i2c_tda8290 = {
-+	.radio = { I2C_CLIENT_END },
-+	.demod = { I2C_CLIENT_END },
-+	.tv    = { 0x4b, I2C_CLIENT_END },
-+};
-+
- /********************** card configuration *******************************/
+ int pvr2_hdw_set_stream_type(struct pvr2_hdw *hdw,enum pvr2_config config)
+ {
+-	int ret;
+-	if (!hdw->flag_ok) return -EIO;
++	int fl;
+ 	LOCK_TAKE(hdw->big_lock);
+-	ret = pvr2_hdw_set_stream_type_no_lock(hdw,config);
++	if ((fl = (hdw->desired_stream_type != config)) != 0) {
++		hdw->desired_stream_type = config;
++		hdw->state_pipeline_config = 0;
++		trace_stbit("state_pipeline_config",
++			    hdw->state_pipeline_config);
++		pvr2_hdw_state_sched(hdw);
++	}
+ 	LOCK_GIVE(hdw->big_lock);
+-	return ret;
++	if (fl) return 0;
++	return pvr2_hdw_wait(hdw,0);
+ }
  
- /* Please add new PCI IDs to: http://pci-ids.ucw.cz/iii
-@@ -72,6 +94,7 @@ static const struct ivtv_card ivtv_card_pvr250 = {
- 		{ IVTV_CARD_INPUT_LINE_IN2,   MSP_SCART3 },
- 	},
- 	.radio_input = { IVTV_CARD_INPUT_AUD_TUNER, MSP_SCART2 },
-+	.i2c = &ivtv_i2c_std,
- };
  
- /* ------------------------------------------------------------------------- */
-@@ -126,6 +149,7 @@ static const struct ivtv_card ivtv_card_pvr350 = {
- 		{ IVTV_CARD_INPUT_LINE_IN2,   MSP_SCART3 },
- 	},
- 	.radio_input = { IVTV_CARD_INPUT_AUD_TUNER, MSP_SCART2 },
-+	.i2c = &ivtv_i2c_std,
- };
+@@ -1646,6 +1428,7 @@ static int get_default_tuner_type(struct pvr2_hdw *hdw)
+ 	}
+ 	if (tp < 0) return -EINVAL;
+ 	hdw->tuner_type = tp;
++	hdw->tuner_updated = !0;
+ 	return 0;
+ }
  
- /* PVR-350 V1 boards have a different audio tuner input and use a
-@@ -157,6 +181,7 @@ static const struct ivtv_card ivtv_card_pvr350_v1 = {
- 		{ IVTV_CARD_INPUT_LINE_IN2,   MSP_SCART3 },
- 	},
- 	.radio_input = { IVTV_CARD_INPUT_AUD_TUNER, MSP_SCART2 },
-+	.i2c = &ivtv_i2c_std,
- };
+@@ -1656,8 +1439,9 @@ static v4l2_std_id get_default_standard(struct pvr2_hdw *hdw)
+ 	int tp = 0;
+ 	if ((unit_number >= 0) && (unit_number < PVR_NUM)) {
+ 		tp = video_std[unit_number];
++		if (tp) return tp;
+ 	}
+-	return tp;
++	return 0;
+ }
  
- /* ------------------------------------------------------------------------- */
-@@ -192,6 +217,7 @@ static const struct ivtv_card ivtv_card_pvr150 = {
- 			 CX25840_AUDIO_SERIAL, WM8775_AIN4 },
- 	/* apparently needed for the IR blaster */
- 	.gpio_init = { .direction = 0x1f01, .initial_value = 0x26f3 },
-+	.i2c = &ivtv_i2c_std,
- };
  
- /* ------------------------------------------------------------------------- */
-@@ -234,6 +260,7 @@ static const struct ivtv_card ivtv_card_m179 = {
- 		{ .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_NTSC },
+@@ -1731,7 +1515,7 @@ const static struct pvr2_std_hack std_eeprom_maps[] = {
  	},
- 	.pci_list = ivtv_pci_m179,
-+	.i2c = &ivtv_i2c_std,
- };
- 
- /* ------------------------------------------------------------------------- */
-@@ -275,6 +302,7 @@ static const struct ivtv_card ivtv_card_mpg600 = {
- 		{ .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FQ1286 },
+ 	{	/* PAL(D/D1/K) */
+ 		.pat = V4L2_STD_DK,
+-		.std = V4L2_STD_PAL_D/V4L2_STD_PAL_D1|V4L2_STD_PAL_K,
++		.std = V4L2_STD_PAL_D|V4L2_STD_PAL_D1|V4L2_STD_PAL_K,
  	},
- 	.pci_list = ivtv_pci_mpg600,
-+	.i2c = &ivtv_i2c_std,
  };
  
- /* ------------------------------------------------------------------------- */
-@@ -315,6 +343,7 @@ static const struct ivtv_card ivtv_card_mpg160 = {
- 		{ .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FQ1286 },
- 	},
- 	.pci_list = ivtv_pci_mpg160,
-+	.i2c = &ivtv_i2c_std,
- };
+@@ -1739,18 +1523,20 @@ static void pvr2_hdw_setup_std(struct pvr2_hdw *hdw)
+ {
+ 	char buf[40];
+ 	unsigned int bcnt;
+-	v4l2_std_id std1,std2;
++	v4l2_std_id std1,std2,std3;
  
- /* ------------------------------------------------------------------------- */
-@@ -350,6 +379,7 @@ static const struct ivtv_card ivtv_card_pg600 = {
- 		{ .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FQ1286 },
- 	},
- 	.pci_list = ivtv_pci_pg600,
-+	.i2c = &ivtv_i2c_std,
- };
+ 	std1 = get_default_standard(hdw);
++	std3 = std1 ? 0 : hdw->hdw_desc->default_std_mask;
  
- /* ------------------------------------------------------------------------- */
-@@ -393,6 +423,7 @@ static const struct ivtv_card ivtv_card_avc2410 = {
- 		{ .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FM1236_MK3 },
- 	},
- 	.pci_list = ivtv_pci_avc2410,
-+	.i2c = &ivtv_i2c_std,
- };
+ 	bcnt = pvr2_std_id_to_str(buf,sizeof(buf),hdw->std_mask_eeprom);
+ 	pvr2_trace(PVR2_TRACE_STD,
+-		   "Supported video standard(s) reported by eeprom: %.*s",
++		   "Supported video standard(s) reported available"
++		   " in hardware: %.*s",
+ 		   bcnt,buf);
  
- /* ------------------------------------------------------------------------- */
-@@ -463,6 +494,7 @@ static const struct ivtv_card ivtv_card_tg5000tv = {
- 		{ .std = V4L2_STD_525_60, .tuner = TUNER_PHILIPS_FQ1286 },
- 	},
- 	.pci_list = ivtv_pci_tg5000tv,
-+	.i2c = &ivtv_i2c_std,
- };
+ 	hdw->std_mask_avail = hdw->std_mask_eeprom;
  
- /* ------------------------------------------------------------------------- */
-@@ -493,6 +525,7 @@ static const struct ivtv_card ivtv_card_va2000 = {
- 		{ .std = V4L2_STD_525_60, .tuner = TUNER_PHILIPS_FQ1286 },
- 	},
- 	.pci_list = ivtv_pci_va2000,
-+	.i2c = &ivtv_i2c_std,
- };
+-	std2 = std1 & ~hdw->std_mask_avail;
++	std2 = (std1|std3) & ~hdw->std_mask_avail;
+ 	if (std2) {
+ 		bcnt = pvr2_std_id_to_str(buf,sizeof(buf),std2);
+ 		pvr2_trace(PVR2_TRACE_STD,
+@@ -1772,6 +1558,16 @@ static void pvr2_hdw_setup_std(struct pvr2_hdw *hdw)
+ 		pvr2_hdw_internal_find_stdenum(hdw);
+ 		return;
+ 	}
++	if (std3) {
++		bcnt = pvr2_std_id_to_str(buf,sizeof(buf),std3);
++		pvr2_trace(PVR2_TRACE_STD,
++			   "Initial video standard"
++			   " (determined by device type): %.*s",bcnt,buf);
++		hdw->std_mask_cur = std3;
++		hdw->std_dirty = !0;
++		pvr2_hdw_internal_find_stdenum(hdw);
++		return;
++	}
  
- /* ------------------------------------------------------------------------- */
-@@ -537,6 +570,7 @@ static const struct ivtv_card ivtv_card_cx23416gyc = {
- 		{ .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FM1236_MK3 },
- 	},
- 	.pci_list = ivtv_pci_cx23416gyc,
-+	.i2c = &ivtv_i2c_std,
- };
+ 	{
+ 		unsigned int idx;
+@@ -1816,8 +1612,7 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw)
+ 	unsigned int idx;
+ 	struct pvr2_ctrl *cptr;
+ 	int reloadFl = 0;
+-	if ((hdw->hdw_type == PVR2_HDW_TYPE_29XXX) ||
+-	    (hdw->hdw_type == PVR2_HDW_TYPE_24XXX)) {
++	if (hdw->hdw_desc->fx2_firmware.cnt) {
+ 		if (!reloadFl) {
+ 			reloadFl =
+ 				(hdw->usb_intf->cur_altsetting->desc.bNumEndpoints
+@@ -1853,25 +1648,13 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw)
+ 	}
+ 	if (!pvr2_hdw_dev_ok(hdw)) return;
  
- static const struct ivtv_card ivtv_card_cx23416gyc_nogr = {
-@@ -567,6 +601,7 @@ static const struct ivtv_card ivtv_card_cx23416gyc_nogr = {
- 		{ .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
- 		{ .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FM1236_MK3 },
- 	},
-+	.i2c = &ivtv_i2c_std,
- };
+-	if (hdw->hdw_type < ARRAY_SIZE(pvr2_client_lists)) {
+-		for (idx = 0;
+-		     idx < pvr2_client_lists[hdw->hdw_type].cnt;
+-		     idx++) {
+-			request_module(
+-				pvr2_client_lists[hdw->hdw_type].lst[idx]);
+-		}
++	for (idx = 0; idx < hdw->hdw_desc->client_modules.cnt; idx++) {
++		request_module(hdw->hdw_desc->client_modules.lst[idx]);
+ 	}
  
- static const struct ivtv_card ivtv_card_cx23416gyc_nogrycs = {
-@@ -596,6 +631,7 @@ static const struct ivtv_card ivtv_card_cx23416gyc_nogrycs = {
- 		{ .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
- 		{ .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FM1236_MK3 },
- 	},
-+	.i2c = &ivtv_i2c_std,
- };
+-	if ((hdw->hdw_type == PVR2_HDW_TYPE_29XXX) ||
+-	    (hdw->hdw_type == PVR2_HDW_TYPE_24XXX)) {
++	if (!hdw->hdw_desc->flag_no_powerup) {
+ 		pvr2_hdw_cmd_powerup(hdw);
+ 		if (!pvr2_hdw_dev_ok(hdw)) return;
+-
+-		if (pvr2_upload_firmware2(hdw)){
+-			pvr2_trace(PVR2_TRACE_ERROR_LEGS,"device unstable!!");
+-			pvr2_hdw_render_useless(hdw);
+-			return;
+-		}
+ 	}
  
- /* ------------------------------------------------------------------------- */
-@@ -635,6 +671,7 @@ static const struct ivtv_card ivtv_card_gv_mvprx = {
- 		{ .std = V4L2_STD_525_60, .tuner = TUNER_PANASONIC_VP27 },
- 	},
- 	.pci_list = ivtv_pci_gv_mvprx,
-+	.i2c = &ivtv_i2c_std,
- };
+ 	// This step MUST happen after the earlier powerup step.
+@@ -1899,15 +1682,22 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw)
+ 	// thread-safe against the normal pvr2_send_request() mechanism.
+ 	// (We should make it thread safe).
  
- /* ------------------------------------------------------------------------- */
-@@ -671,6 +708,7 @@ static const struct ivtv_card ivtv_card_gv_mvprx2e = {
- 		{ .std = V4L2_STD_525_60, .tuner = TUNER_PANASONIC_VP27 },
- 	},
- 	.pci_list = ivtv_pci_gv_mvprx2e,
-+	.i2c = &ivtv_i2c_std,
- };
+-	ret = pvr2_hdw_get_eeprom_addr(hdw);
+-	if (!pvr2_hdw_dev_ok(hdw)) return;
+-	if (ret < 0) {
+-		pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+-			   "Unable to determine location of eeprom, skipping");
+-	} else {
+-		hdw->eeprom_addr = ret;
+-		pvr2_eeprom_analyze(hdw);
++	if (hdw->hdw_desc->flag_has_hauppauge_rom) {
++		ret = pvr2_hdw_get_eeprom_addr(hdw);
+ 		if (!pvr2_hdw_dev_ok(hdw)) return;
++		if (ret < 0) {
++			pvr2_trace(PVR2_TRACE_ERROR_LEGS,
++				   "Unable to determine location of eeprom,"
++				   " skipping");
++		} else {
++			hdw->eeprom_addr = ret;
++			pvr2_eeprom_analyze(hdw);
++			if (!pvr2_hdw_dev_ok(hdw)) return;
++		}
++	} else {
++		hdw->tuner_type = hdw->hdw_desc->default_tuner_type;
++		hdw->tuner_updated = !0;
++		hdw->std_mask_eeprom = V4L2_STD_ALL;
+ 	}
  
- /* ------------------------------------------------------------------------- */
-@@ -705,6 +743,7 @@ static const struct ivtv_card ivtv_card_gotview_pci_dvd = {
- 		{ .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
- 	},
- 	.pci_list = ivtv_pci_gotview_pci_dvd,
-+	.i2c = &ivtv_i2c_std,
- };
+ 	pvr2_hdw_setup_std(hdw);
+@@ -1918,14 +1708,12 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw)
+ 			   hdw->tuner_type);
+ 	}
  
- /* ------------------------------------------------------------------------- */
-@@ -743,6 +782,7 @@ static const struct ivtv_card ivtv_card_gotview_pci_dvd2 = {
- 		{ .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
- 	},
- 	.pci_list = ivtv_pci_gotview_pci_dvd2,
-+	.i2c = &ivtv_i2c_std,
- };
+-	hdw->tuner_updated = !0;
+ 	pvr2_i2c_core_check_stale(hdw);
+ 	hdw->tuner_updated = 0;
  
- /* ------------------------------------------------------------------------- */
-@@ -778,6 +818,7 @@ static const struct ivtv_card ivtv_card_yuan_mpc622 = {
- 		{ .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_TDA8290 },
- 	},
- 	.pci_list = ivtv_pci_yuan_mpc622,
-+	.i2c = &ivtv_i2c_tda8290,
- };
+ 	if (!pvr2_hdw_dev_ok(hdw)) return;
  
- /* ------------------------------------------------------------------------- */
-@@ -819,6 +860,7 @@ static const struct ivtv_card ivtv_card_dctmvtvp1 = {
- 		{ .std = V4L2_STD_525_60, .tuner = TUNER_PHILIPS_FQ1286 },
- 	},
- 	.pci_list = ivtv_pci_dctmvtvp1,
-+	.i2c = &ivtv_i2c_std,
- };
+-	pvr2_hdw_commit_ctl_internal(hdw);
+-	if (!pvr2_hdw_dev_ok(hdw)) return;
++	pvr2_hdw_commit_setup(hdw);
  
- /* ------------------------------------------------------------------------- */
-@@ -838,7 +880,7 @@ static const struct ivtv_card ivtv_card_pg600v2 = {
- 	.hw_video = IVTV_HW_CX25840,
- 	.hw_audio = IVTV_HW_CX25840,
- 	.hw_audio_ctrl = IVTV_HW_CX25840,
--	.hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER,
-+	.hw_all = IVTV_HW_CX25840,
- 	.video_inputs = {
- 		{ IVTV_CARD_INPUT_SVIDEO1,    0,
- 		  CX25840_SVIDEO_LUMA3 | CX25840_SVIDEO_CHROMA4 },
-@@ -847,10 +889,8 @@ static const struct ivtv_card ivtv_card_pg600v2 = {
- 	.audio_inputs = {
- 		{ IVTV_CARD_INPUT_LINE_IN1,   CX25840_AUDIO_SERIAL },
- 	},
--	.tuners = {
--		{ .std = V4L2_STD_ALL, .tuner = TUNER_XCEIVE_XC3028 },
--	},
- 	.pci_list = ivtv_pci_pg600v2,
-+	.i2c = &ivtv_i2c_std,
- };
+ 	hdw->vid_stream = pvr2_stream_create();
+ 	if (!pvr2_hdw_dev_ok(hdw)) return;
+@@ -1945,25 +1733,25 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw)
  
- /* ------------------------------------------------------------------------- */
-@@ -871,17 +911,22 @@ static const struct ivtv_card ivtv_card_club3d = {
- 	.hw_audio_ctrl = IVTV_HW_CX25840,
- 	.hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER,
- 	.video_inputs = {
--		{ IVTV_CARD_INPUT_SVIDEO1,    0,
-+		{ IVTV_CARD_INPUT_VID_TUNER,  0, CX25840_COMPOSITE2 },
-+		{ IVTV_CARD_INPUT_SVIDEO1,    1,
- 		  CX25840_SVIDEO_LUMA3 | CX25840_SVIDEO_CHROMA4 },
--		{ IVTV_CARD_INPUT_COMPOSITE1, 0, CX25840_COMPOSITE3 },
-+		{ IVTV_CARD_INPUT_COMPOSITE1, 1, CX25840_COMPOSITE3 },
- 	},
- 	.audio_inputs = {
-+		{ IVTV_CARD_INPUT_AUD_TUNER,  CX25840_AUDIO5       },
- 		{ IVTV_CARD_INPUT_LINE_IN1,   CX25840_AUDIO_SERIAL },
- 	},
-+	.radio_input = { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5 },
-+	.gpio_init = { .direction = 0x1000, .initial_value = 0x1000 }, /* tuner reset */
- 	.tuners = {
--		{ .std = V4L2_STD_ALL, .tuner = TUNER_XCEIVE_XC3028 },
-+		{ .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 },
- 	},
- 	.pci_list = ivtv_pci_club3d,
-+	.i2c = &ivtv_i2c_std,
- };
+ 	if (!pvr2_hdw_dev_ok(hdw)) return;
  
- /* ------------------------------------------------------------------------- */
-@@ -900,7 +945,7 @@ static const struct ivtv_card ivtv_card_avertv_mce116 = {
- 	.hw_video = IVTV_HW_CX25840,
- 	.hw_audio = IVTV_HW_CX25840,
- 	.hw_audio_ctrl = IVTV_HW_CX25840,
--	.hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER | IVTV_HW_WM8739,
-+	.hw_all = IVTV_HW_CX25840 | IVTV_HW_WM8739,
- 	.video_inputs = {
- 		{ IVTV_CARD_INPUT_SVIDEO1,    0, CX25840_SVIDEO3    },
- 		{ IVTV_CARD_INPUT_COMPOSITE1, 0, CX25840_COMPOSITE1 },
-@@ -909,10 +954,115 @@ static const struct ivtv_card ivtv_card_avertv_mce116 = {
- 		{ IVTV_CARD_INPUT_LINE_IN1,   CX25840_AUDIO_SERIAL, 1 },
- 	},
- 	.gpio_init = { .direction = 0xe000, .initial_value = 0x4000 }, /* enable line-in */
-+	.pci_list = ivtv_pci_avertv_mce116,
-+	.i2c = &ivtv_i2c_std,
-+};
-+
-+/* ------------------------------------------------------------------------- */
-+
-+/* AVerMedia PVR-150 Plus (M113) card */
-+
-+static const struct ivtv_card_pci_info ivtv_pci_aver_pvr150[] = {
-+	{ PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_AVERMEDIA, 0xc035 },
-+	{ 0, 0, 0 }
-+};
-+
-+static const struct ivtv_card ivtv_card_aver_pvr150 = {
-+	.type = IVTV_CARD_AVER_PVR150PLUS,
-+	.name = "AVerMedia PVR-150 Plus",
-+	.v4l2_capabilities = IVTV_CAP_ENCODER,
-+	.hw_video = IVTV_HW_CX25840,
-+	.hw_audio = IVTV_HW_CX25840,
-+	.hw_audio_ctrl = IVTV_HW_CX25840,
-+	.hw_muxer = IVTV_HW_GPIO,
-+	.hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER,
-+	.video_inputs = {
-+		{ IVTV_CARD_INPUT_VID_TUNER,  0, CX25840_COMPOSITE2 },
-+		{ IVTV_CARD_INPUT_SVIDEO1,    1,
-+		  CX25840_SVIDEO_LUMA3 | CX25840_SVIDEO_CHROMA4 },
-+		{ IVTV_CARD_INPUT_COMPOSITE1, 1, CX25840_COMPOSITE1 },
-+	},
-+	.audio_inputs = {
-+		{ IVTV_CARD_INPUT_AUD_TUNER,  CX25840_AUDIO5,       0 },
-+		{ IVTV_CARD_INPUT_LINE_IN1,   CX25840_AUDIO_SERIAL, 1 },
-+	},
-+	.radio_input = { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO_SERIAL, 2 },
-+	.gpio_init = { .direction = 0x0800, .initial_value = 0 },
-+	.gpio_audio_input  = { .mask = 0x0800, .tuner = 0, .linein = 0, .radio = 0x0800 },
- 	.tuners = {
--		{ .std = V4L2_STD_ALL, .tuner = TUNER_XCEIVE_XC3028 },
-+		/* This card has a Partsnic PTI-5NF05 tuner */
-+		{ .std = V4L2_STD_525_60, .tuner = TUNER_TCL_2002N },
- 	},
--	.pci_list = ivtv_pci_avertv_mce116,
-+	.pci_list = ivtv_pci_aver_pvr150,
-+	.i2c = &ivtv_i2c_radio,
-+};
-+
-+/* ------------------------------------------------------------------------- */
-+
-+/* AVerMedia EZMaker PCI Deluxe card */
-+
-+static const struct ivtv_card_pci_info ivtv_pci_aver_ezmaker[] = {
-+	{ PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_AVERMEDIA, 0xc03f },
-+	{ 0, 0, 0 }
-+};
-+
-+static const struct ivtv_card ivtv_card_aver_ezmaker = {
-+	.type = IVTV_CARD_AVER_EZMAKER,
-+	.name = "AVerMedia EZMaker PCI Deluxe",
-+	.v4l2_capabilities = IVTV_CAP_ENCODER,
-+	.hw_video = IVTV_HW_CX25840,
-+	.hw_audio = IVTV_HW_CX25840,
-+	.hw_audio_ctrl = IVTV_HW_CX25840,
-+	.hw_all = IVTV_HW_CX25840 | IVTV_HW_WM8739,
-+	.video_inputs = {
-+		{ IVTV_CARD_INPUT_SVIDEO1,    0, CX25840_SVIDEO3 },
-+		{ IVTV_CARD_INPUT_COMPOSITE1, 0, CX25840_COMPOSITE1 },
-+	},
-+	.audio_inputs = {
-+		{ IVTV_CARD_INPUT_LINE_IN1,   CX25840_AUDIO_SERIAL, 0 },
-+	},
-+	.gpio_init = { .direction = 0x4000, .initial_value = 0x4000 },
-+	/* Does not have a tuner */
-+	.pci_list = ivtv_pci_aver_ezmaker,
-+};
-+
-+/* ------------------------------------------------------------------------- */
-+
-+/* ASUS Falcon2 */
-+
-+static const struct ivtv_card_pci_info ivtv_pci_asus_falcon2[] = {
-+	{ PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_ASUSTEK, 0x4b66 },
-+	{ PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_ASUSTEK, 0x462e },
-+	{ PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_ASUSTEK, 0x4b2e },
-+	{ 0, 0, 0 }
-+};
+-	/* Make sure everything is up to date */
+-	pvr2_i2c_core_sync(hdw);
+-
+-	if (!pvr2_hdw_dev_ok(hdw)) return;
+-
+ 	hdw->flag_init_ok = !0;
 +
-+static const struct ivtv_card ivtv_card_asus_falcon2 = {
-+	.type = IVTV_CARD_ASUS_FALCON2,
-+	.name = "ASUS Falcon2",
-+	.v4l2_capabilities = IVTV_CAP_ENCODER,
-+	.hw_video = IVTV_HW_CX25840,
-+	.hw_audio = IVTV_HW_CX25840,
-+	.hw_audio_ctrl = IVTV_HW_CX25840,
-+	.hw_muxer = IVTV_HW_M52790,
-+	.hw_all = IVTV_HW_CX25840 | IVTV_HW_M52790 | IVTV_HW_TUNER,
-+	.video_inputs = {
-+		{ IVTV_CARD_INPUT_VID_TUNER,  0, CX25840_COMPOSITE2 },
-+		{ IVTV_CARD_INPUT_SVIDEO1,    1, CX25840_SVIDEO3    },
-+		{ IVTV_CARD_INPUT_COMPOSITE1, 2, CX25840_COMPOSITE2 },
-+	},
-+	.audio_inputs = {
-+		{ IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5, M52790_IN_TUNER },
-+		{ IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL,
-+			M52790_IN_V2 | M52790_SW1_YCMIX | M52790_SW2_YCMIX },
-+		{ IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL, M52790_IN_V2 },
-+	},
-+	.radio_input = { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO_SERIAL, M52790_IN_TUNER },
-+	.tuners = {
-+		{ .std = V4L2_STD_525_60, .tuner = TUNER_PHILIPS_FM1236_MK3 },
-+	},
-+	.pci_list = ivtv_pci_asus_falcon2,
-+	.i2c = &ivtv_i2c_std,
- };
++	pvr2_hdw_state_sched(hdw);
+ }
  
- static const struct ivtv_card *ivtv_card_list[] = {
-@@ -937,6 +1087,9 @@ static const struct ivtv_card *ivtv_card_list[] = {
- 	&ivtv_card_pg600v2,
- 	&ivtv_card_club3d,
- 	&ivtv_card_avertv_mce116,
-+	&ivtv_card_asus_falcon2,
-+	&ivtv_card_aver_pvr150,
-+	&ivtv_card_aver_ezmaker,
  
- 	/* Variations of standard cards but with the same PCI IDs.
- 	   These cards must come last in this list. */
-diff --git a/drivers/media/video/ivtv/ivtv-cards.h b/drivers/media/video/ivtv/ivtv-cards.h
-index ff46e5a..191aafd 100644
---- a/drivers/media/video/ivtv/ivtv-cards.h
-+++ b/drivers/media/video/ivtv/ivtv-cards.h
-@@ -45,7 +45,10 @@
- #define IVTV_CARD_PG600V2	     18 /* Yuan PG600V2/GotView PCI DVD Lite */
- #define IVTV_CARD_CLUB3D	     19 /* Club3D ZAP-TV1x01 */
- #define IVTV_CARD_AVERTV_MCE116	     20 /* AVerTV MCE 116 Plus */
--#define IVTV_CARD_LAST 		     20
-+#define IVTV_CARD_ASUS_FALCON2	     21 /* ASUS Falcon2 */
-+#define IVTV_CARD_AVER_PVR150PLUS    22 /* AVerMedia PVR-150 Plus */
-+#define IVTV_CARD_AVER_EZMAKER       23 /* AVerMedia EZMaker PCI Deluxe */
-+#define IVTV_CARD_LAST 		     23
+-int pvr2_hdw_setup(struct pvr2_hdw *hdw)
++/* Set up the structure and attempt to put the device into a usable state.
++   This can be a time-consuming operation, which is why it is not done
++   internally as part of the create() step. */
++static void pvr2_hdw_setup(struct pvr2_hdw *hdw)
+ {
+ 	pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_setup(hdw=%p) begin",hdw);
+-	LOCK_TAKE(hdw->big_lock); do {
++	do {
+ 		pvr2_hdw_setup_low(hdw);
+ 		pvr2_trace(PVR2_TRACE_INIT,
+ 			   "pvr2_hdw_setup(hdw=%p) done, ok=%d init_ok=%d",
+-			   hdw,hdw->flag_ok,hdw->flag_init_ok);
++			   hdw,pvr2_hdw_dev_ok(hdw),hdw->flag_init_ok);
+ 		if (pvr2_hdw_dev_ok(hdw)) {
+-			if (pvr2_hdw_init_ok(hdw)) {
++			if (hdw->flag_init_ok) {
+ 				pvr2_trace(
+ 					PVR2_TRACE_INFO,
+ 					"Device initialization"
+@@ -2013,9 +1801,8 @@ int pvr2_hdw_setup(struct pvr2_hdw *hdw)
+ 				" the pvrusb2 device"
+ 				" in order to recover.");
+ 		}
+-	} while (0); LOCK_GIVE(hdw->big_lock);
++	} while (0);
+ 	pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_setup(hdw=%p) end",hdw);
+-	return hdw->flag_init_ok;
+ }
  
- /* Variants of existing cards but with the same PCI IDs. The driver
-    detects these based on other device information.
-@@ -69,6 +72,7 @@
- #define IVTV_PCI_ID_HAUPPAUGE_ALT1 	0x0270
- #define IVTV_PCI_ID_HAUPPAUGE_ALT2 	0x4070
- #define IVTV_PCI_ID_ADAPTEC 		0x9005
-+#define IVTV_PCI_ID_ASUSTEK 		0x1043
- #define IVTV_PCI_ID_AVERMEDIA 		0x1461
- #define IVTV_PCI_ID_YUAN1		0x12ab
- #define IVTV_PCI_ID_YUAN2 		0xff01
-@@ -80,7 +84,7 @@
- #define IVTV_PCI_ID_GOTVIEW1		0xffac
- #define IVTV_PCI_ID_GOTVIEW2 		0xffad
  
--/* hardware flags */
-+/* hardware flags, no gaps allowed, IVTV_HW_GPIO must always be last */
- #define IVTV_HW_CX25840   (1 << 0)
- #define IVTV_HW_SAA7115   (1 << 1)
- #define IVTV_HW_SAA7127   (1 << 2)
-@@ -90,12 +94,12 @@
- #define IVTV_HW_CS53L32A  (1 << 6)
- #define IVTV_HW_TVEEPROM  (1 << 7)
- #define IVTV_HW_SAA7114   (1 << 8)
--#define IVTV_HW_TVAUDIO   (1 << 9)
--#define IVTV_HW_UPD64031A (1 << 10)
--#define IVTV_HW_UPD6408X  (1 << 11)
--#define IVTV_HW_SAA717X   (1 << 12)
--#define IVTV_HW_WM8739    (1 << 13)
--#define IVTV_HW_VP27SMPX  (1 << 14)
-+#define IVTV_HW_UPD64031A (1 << 9)
-+#define IVTV_HW_UPD6408X  (1 << 10)
-+#define IVTV_HW_SAA717X   (1 << 11)
-+#define IVTV_HW_WM8739    (1 << 12)
-+#define IVTV_HW_VP27SMPX  (1 << 13)
-+#define IVTV_HW_M52790    (1 << 14)
- #define IVTV_HW_GPIO      (1 << 15)
+@@ -2026,24 +1813,32 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
+ {
+ 	unsigned int idx,cnt1,cnt2;
+ 	struct pvr2_hdw *hdw;
+-	unsigned int hdw_type;
+ 	int valid_std_mask;
+ 	struct pvr2_ctrl *cptr;
++	const struct pvr2_device_desc *hdw_desc;
+ 	__u8 ifnum;
+ 	struct v4l2_queryctrl qctrl;
+ 	struct pvr2_ctl_info *ciptr;
  
- #define IVTV_HW_SAA711X   (IVTV_HW_SAA7115 | IVTV_HW_SAA7114)
-@@ -230,6 +234,12 @@ struct ivtv_card_tuner {
- 	int 	    tuner; 	/* tuner ID (from tuner.h) */
- };
+-	hdw_type = devid - pvr2_device_table;
+-	if (hdw_type >= ARRAY_SIZE(pvr2_device_names)) {
+-		pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+-			   "Bogus device type of %u reported",hdw_type);
+-		return NULL;
+-	}
++	hdw_desc = (const struct pvr2_device_desc *)(devid->driver_info);
  
-+struct ivtv_card_tuner_i2c {
-+	unsigned short radio[2];/* radio tuner i2c address to probe */
-+	unsigned short demod[2];/* demodulator i2c address to probe */
-+	unsigned short tv[4];	/* tv tuner i2c addresses to probe */
-+};
+ 	hdw = kzalloc(sizeof(*hdw),GFP_KERNEL);
+ 	pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_create: hdw=%p, type \"%s\"",
+-		   hdw,pvr2_device_names[hdw_type]);
++		   hdw,hdw_desc->description);
+ 	if (!hdw) goto fail;
 +
- /* for card information/parameters */
- struct ivtv_card {
- 	int type;
-@@ -257,6 +267,7 @@ struct ivtv_card {
- 	struct ivtv_gpio_audio_detect 	gpio_audio_detect;
- 
- 	struct ivtv_card_tuner tuners[IVTV_CARD_MAX_TUNERS];
-+	struct ivtv_card_tuner_i2c *i2c;
++	init_timer(&hdw->quiescent_timer);
++	hdw->quiescent_timer.data = (unsigned long)hdw;
++	hdw->quiescent_timer.function = pvr2_hdw_quiescent_timeout;
++
++	init_timer(&hdw->encoder_wait_timer);
++	hdw->encoder_wait_timer.data = (unsigned long)hdw;
++	hdw->encoder_wait_timer.function = pvr2_hdw_encoder_wait_timeout;
++
++	hdw->master_state = PVR2_STATE_DEAD;
++
++	init_waitqueue_head(&hdw->state_wait_data);
++
+ 	hdw->tuner_signal_stale = !0;
+ 	cx2341x_fill_defaults(&hdw->enc_ctl_state);
  
- 	/* list of device and subsystem vendor/devices that
- 	   correspond to this card type. */
-diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c
-index 6d2dd87..d42f120 100644
---- a/drivers/media/video/ivtv/ivtv-driver.c
-+++ b/drivers/media/video/ivtv/ivtv-driver.c
-@@ -59,6 +59,7 @@
- #include <media/tveeprom.h>
- #include <media/saa7115.h>
- #include <media/v4l2-chip-ident.h>
-+#include "tuner-xc2028.h"
+@@ -2052,7 +1847,7 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
+ 	hdw->controls = kzalloc(sizeof(struct pvr2_ctrl) * hdw->control_cnt,
+ 				GFP_KERNEL);
+ 	if (!hdw->controls) goto fail;
+-	hdw->hdw_type = hdw_type;
++	hdw->hdw_desc = hdw_desc;
+ 	for (idx = 0; idx < hdw->control_cnt; idx++) {
+ 		cptr = hdw->controls + idx;
+ 		cptr->hdw = hdw;
+@@ -2184,18 +1979,16 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
+ 	if (cnt1 >= sizeof(hdw->name)) cnt1 = sizeof(hdw->name)-1;
+ 	hdw->name[cnt1] = 0;
  
- /* var to keep track of the number of array elements in use */
- int ivtv_cards_active = 0;
-@@ -185,6 +186,9 @@ MODULE_PARM_DESC(cardtype,
- 		 "\t\t\t19 = Yuan PG600V2/GotView PCI DVD Lite\n"
- 		 "\t\t\t20 = Club3D ZAP-TV1x01\n"
- 		 "\t\t\t21 = AverTV MCE 116 Plus\n"
-+		 "\t\t\t22 = ASUS Falcon2\n"
-+		 "\t\t\t23 = AverMedia PVR-150 Plus\n"
-+		 "\t\t\t24 = AverMedia EZMaker PCI Deluxe\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");
-@@ -397,6 +401,7 @@ static void ivtv_process_eeprom(struct ivtv *itv)
++	hdw->workqueue = create_singlethread_workqueue(hdw->name);
++	INIT_WORK(&hdw->workpoll,pvr2_hdw_worker_poll);
++	INIT_WORK(&hdw->worki2csync,pvr2_hdw_worker_i2c);
++	INIT_WORK(&hdw->workinit,pvr2_hdw_worker_init);
++
+ 	pvr2_trace(PVR2_TRACE_INIT,"Driver unit number is %d, name is %s",
+ 		   hdw->unit_number,hdw->name);
  
- 	itv->v4l2_cap = itv->card->v4l2_capabilities;
- 	itv->card_name = itv->card->name;
-+	itv->card_i2c = itv->card->i2c;
+ 	hdw->tuner_type = -1;
+ 	hdw->flag_ok = !0;
+-	/* Initialize the mask of subsystems that we will shut down when we
+-	   stop streaming. */
+-	hdw->subsys_stream_mask = PVR2_SUBSYS_RUN_ALL;
+-	hdw->subsys_stream_mask |= (1<<PVR2_SUBSYS_B_ENC_CFG);
+-
+-	pvr2_trace(PVR2_TRACE_INIT,"subsys_stream_mask: 0x%lx",
+-		   hdw->subsys_stream_mask);
  
- 	/* If this is a PVR500 then it should be possible to detect whether it is the
- 	   first or second unit by looking at the subsystem device ID: is bit 4 is
-@@ -414,7 +419,14 @@ static void ivtv_process_eeprom(struct ivtv *itv)
- 	   This detection is needed since the eeprom reports incorrectly that a radio is
- 	   present on the second unit. */
- 	if (tv.model / 1000 == 23) {
-+		static const struct ivtv_card_tuner_i2c ivtv_i2c_radio = {
-+			.radio = { 0x60, I2C_CLIENT_END },
-+			.demod = { 0x43, I2C_CLIENT_END },
-+			.tv = { 0x61, I2C_CLIENT_END },
-+		};
-+
- 		itv->card_name = "WinTV PVR 500";
-+		itv->card_i2c = &ivtv_i2c_radio;
- 		if (pci_slot == 8 || pci_slot == 9) {
- 			int is_first = (pci_slot & 1) == 0;
+ 	hdw->usb_intf = intf;
+ 	hdw->usb_dev = interface_to_usbdev(intf);
+@@ -2211,15 +2004,25 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
+ 	mutex_init(&hdw->ctl_lock_mutex);
+ 	mutex_init(&hdw->big_lock_mutex);
  
-@@ -628,10 +640,11 @@ done:
- 		IVTV_ERR("Defaulting to %s card\n", itv->card->name);
- 		IVTV_ERR("Please mail the vendor/device and subsystem vendor/device IDs and what kind of\n");
- 		IVTV_ERR("card you have to the ivtv-devel mailinglist (www.ivtvdriver.org)\n");
--		IVTV_ERR("Prefix your subject line with [UNKNOWN CARD].\n");
-+		IVTV_ERR("Prefix your subject line with [UNKNOWN IVTV CARD].\n");
++	queue_work(hdw->workqueue,&hdw->workinit);
+ 	return hdw;
+  fail:
+ 	if (hdw) {
++		del_timer_sync(&hdw->quiescent_timer);
++		del_timer_sync(&hdw->encoder_wait_timer);
++		if (hdw->workqueue) {
++			flush_workqueue(hdw->workqueue);
++			destroy_workqueue(hdw->workqueue);
++			hdw->workqueue = NULL;
++		}
+ 		usb_free_urb(hdw->ctl_read_urb);
+ 		usb_free_urb(hdw->ctl_write_urb);
+ 		kfree(hdw->ctl_read_buffer);
+ 		kfree(hdw->ctl_write_buffer);
+ 		kfree(hdw->controls);
+ 		kfree(hdw->mpeg_ctrl_info);
++		kfree(hdw->std_defs);
++		kfree(hdw->std_enum_names);
+ 		kfree(hdw);
  	}
- 	itv->v4l2_cap = itv->card->v4l2_capabilities;
- 	itv->card_name = itv->card->name;
-+	itv->card_i2c = itv->card->i2c;
- }
- 
- /* Precondition: the ivtv structure has been memset to 0. Only
-@@ -695,6 +708,7 @@ static int __devinit ivtv_init_struct1(struct ivtv *itv)
- 	atomic_set(&itv->yuv_info.next_dma_frame, -1);
- 	itv->yuv_info.lace_mode = ivtv_yuv_mode;
- 	itv->yuv_info.lace_threshold = ivtv_yuv_threshold;
-+	itv->yuv_info.max_frames_buffered = 3;
- 	return 0;
+ 	return NULL;
+@@ -2250,10 +2053,10 @@ static void pvr2_hdw_remove_usb_stuff(struct pvr2_hdw *hdw)
+ 		kfree(hdw->ctl_write_buffer);
+ 		hdw->ctl_write_buffer = NULL;
+ 	}
+-	pvr2_hdw_render_useless_unlocked(hdw);
+ 	hdw->flag_disconnected = !0;
+ 	hdw->usb_dev = NULL;
+ 	hdw->usb_intf = NULL;
++	pvr2_hdw_render_useless(hdw);
  }
  
-@@ -812,75 +826,61 @@ static int ivtv_setup_pci(struct ivtv *itv, struct pci_dev *dev,
- 	return 0;
- }
  
--static void ivtv_request_module(struct ivtv *itv, const char *name)
-+static u32 ivtv_request_module(struct ivtv *itv, u32 hw,
-+		const char *name, u32 id)
+@@ -2262,6 +2065,13 @@ void pvr2_hdw_destroy(struct pvr2_hdw *hdw)
  {
-+	if ((hw & id) == 0)
-+		return hw;
- 	if (request_module(name) != 0) {
- 		IVTV_ERR("Failed to load module %s\n", name);
--	} else {
--		IVTV_DEBUG_INFO("Loaded module %s\n", name);
-+		return hw & ~id;
- 	}
-+	IVTV_DEBUG_INFO("Loaded module %s\n", name);
-+	return hw;
+ 	if (!hdw) return;
+ 	pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_destroy: hdw=%p",hdw);
++	del_timer_sync(&hdw->quiescent_timer);
++	del_timer_sync(&hdw->encoder_wait_timer);
++	if (hdw->workqueue) {
++		flush_workqueue(hdw->workqueue);
++		destroy_workqueue(hdw->workqueue);
++		hdw->workqueue = NULL;
++	}
+ 	if (hdw->fw_buffer) {
+ 		kfree(hdw->fw_buffer);
+ 		hdw->fw_buffer = NULL;
+@@ -2290,12 +2100,6 @@ void pvr2_hdw_destroy(struct pvr2_hdw *hdw)
  }
  
- static void ivtv_load_and_init_modules(struct ivtv *itv)
+ 
+-int pvr2_hdw_init_ok(struct pvr2_hdw *hdw)
+-{
+-	return hdw->flag_init_ok;
+-}
+-
+-
+ int pvr2_hdw_dev_ok(struct pvr2_hdw *hdw)
  {
- 	u32 hw = itv->card->hw_all;
--	int i;
-+	unsigned i;
+ 	return (hdw && hdw->flag_ok);
+@@ -2473,17 +2277,11 @@ static const char *get_ctrl_typename(enum pvr2_ctl_type tp)
+ }
  
- 	/* load modules */
- #ifndef CONFIG_VIDEO_TUNER
--	if (hw & IVTV_HW_TUNER) {
--		if (itv->options.tuner == TUNER_XCEIVE_XC3028) {
--			IVTV_INFO("Xceive tuner not yet supported, only composite and S-Video inputs will be available\n");
--			itv->tunerid = 1;
--		}
--		else {
--			ivtv_request_module(itv, "tuner");
--		}
--	}
-+	hw = ivtv_request_module(itv, hw, "tuner", IVTV_HW_TUNER);
- #endif
- #ifndef CONFIG_VIDEO_CX25840
--	if (hw & IVTV_HW_CX25840)
--		ivtv_request_module(itv, "cx25840");
-+	hw = ivtv_request_module(itv, hw, "cx25840", IVTV_HW_CX25840);
- #endif
- #ifndef CONFIG_VIDEO_SAA711X
--	if (hw & IVTV_HW_SAA711X)
--		ivtv_request_module(itv, "saa7115");
-+	hw = ivtv_request_module(itv, hw, "saa7115", IVTV_HW_SAA711X);
- #endif
- #ifndef CONFIG_VIDEO_SAA7127
--	if (hw & IVTV_HW_SAA7127)
--		ivtv_request_module(itv, "saa7127");
-+	hw = ivtv_request_module(itv, hw, "saa7127", IVTV_HW_SAA7127);
- #endif
--	if (hw & IVTV_HW_SAA717X)
--		ivtv_request_module(itv, "saa717x");
-+	hw = ivtv_request_module(itv, hw, "saa717x", IVTV_HW_SAA717X);
- #ifndef CONFIG_VIDEO_UPD64031A
--	if (hw & IVTV_HW_UPD64031A)
--		ivtv_request_module(itv, "upd64031a");
-+	hw = ivtv_request_module(itv, hw, "upd64031a", IVTV_HW_UPD64031A);
- #endif
- #ifndef CONFIG_VIDEO_UPD64083
--	if (hw & IVTV_HW_UPD6408X)
--		ivtv_request_module(itv, "upd64083");
-+	hw = ivtv_request_module(itv, hw, "upd64083", IVTV_HW_UPD6408X);
- #endif
- #ifndef CONFIG_VIDEO_MSP3400
--	if (hw & IVTV_HW_MSP34XX)
--		ivtv_request_module(itv, "msp3400");
-+	hw = ivtv_request_module(itv, hw, "msp3400", IVTV_HW_MSP34XX);
- #endif
- #ifndef CONFIG_VIDEO_VP27SMPX
--	if (hw & IVTV_HW_VP27SMPX)
--		ivtv_request_module(itv, "vp27smpx");
-+	hw = ivtv_request_module(itv, hw, "vp27smpx", IVTV_HW_VP27SMPX);
- #endif
--	if (hw & IVTV_HW_TVAUDIO)
--		ivtv_request_module(itv, "tvaudio");
- #ifndef CONFIG_VIDEO_WM8775
--	if (hw & IVTV_HW_WM8775)
--		ivtv_request_module(itv, "wm8775");
-+	hw = ivtv_request_module(itv, hw, "wm8775", IVTV_HW_WM8775);
- #endif
- #ifndef CONFIG_VIDEO_WM8739
--	if (hw & IVTV_HW_WM8739)
--		ivtv_request_module(itv, "wm8739");
-+	hw = ivtv_request_module(itv, hw, "wm8739", IVTV_HW_WM8739);
- #endif
- #ifndef CONFIG_VIDEO_CS53L32A
--	if (hw & IVTV_HW_CS53L32A)
--		ivtv_request_module(itv, "cs53l32a");
-+	hw = ivtv_request_module(itv, hw, "cs53l32a", IVTV_HW_CS53L32A);
-+#endif
-+#ifndef CONFIG_VIDEO_M52790
-+	hw = ivtv_request_module(itv, hw, "m52790", IVTV_HW_M52790);
- #endif
  
- 	/* check which i2c devices are actually found */
-@@ -889,11 +889,12 @@ static void ivtv_load_and_init_modules(struct ivtv *itv)
+-/* Commit all control changes made up to this point.  Subsystems can be
+-   indirectly affected by these changes.  For a given set of things being
+-   committed, we'll clear the affected subsystem bits and then once we're
+-   done committing everything we'll make a request to restore the subsystem
+-   state(s) back to their previous value before this function was called.
+-   Thus we can automatically reconfigure affected pieces of the driver as
+-   controls are changed. */
+-static int pvr2_hdw_commit_ctl_internal(struct pvr2_hdw *hdw)
++/* Figure out if we need to commit control changes.  If so, mark internal
++   state flags to indicate this fact and return true.  Otherwise do nothing
++   else and return false. */
++static int pvr2_hdw_commit_setup(struct pvr2_hdw *hdw)
+ {
+-	unsigned long saved_subsys_mask = hdw->subsys_enabled_mask;
+-	unsigned long stale_subsys_mask = 0;
+ 	unsigned int idx;
+ 	struct pvr2_ctrl *cptr;
+ 	int value;
+@@ -2518,6 +2316,25 @@ static int pvr2_hdw_commit_ctl_internal(struct pvr2_hdw *hdw)
+ 		return 0;
+ 	}
  
- 		if (!(device & hw))
- 			continue;
--		if (device == IVTV_HW_GPIO) {
--			/* GPIO is always available */
--			itv->hw_flags |= IVTV_HW_GPIO;
-+		if (device == IVTV_HW_GPIO || device == IVTV_HW_TVEEPROM) {
-+			/* GPIO and TVEEPROM do not use i2c probing */
-+			itv->hw_flags |= device;
- 			continue;
++	hdw->state_pipeline_config = 0;
++	trace_stbit("state_pipeline_config",hdw->state_pipeline_config);
++	pvr2_hdw_state_sched(hdw);
++
++	return !0;
++}
++
++
++/* Perform all operations needed to commit all control changes.  This must
++   be performed in synchronization with the pipeline state and is thus
++   expected to be called as part of the driver's worker thread.  Return
++   true if commit successful, otherwise return false to indicate that
++   commit isn't possible at this time. */
++static int pvr2_hdw_commit_execute(struct pvr2_hdw *hdw)
++{
++	unsigned int idx;
++	struct pvr2_ctrl *cptr;
++	int disruptive_change;
++
+ 	/* When video standard changes, reset the hres and vres values -
+ 	   but if the user has pending changes there, then let the changes
+ 	   take priority. */
+@@ -2536,24 +2353,26 @@ static int pvr2_hdw_commit_ctl_internal(struct pvr2_hdw *hdw)
  		}
-+		ivtv_i2c_register(itv, i);
- 		if (ivtv_i2c_hw_addr(itv, device) > 0)
- 			itv->hw_flags |= device;
  	}
-@@ -964,7 +965,6 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
- 				const struct pci_device_id *pci_id)
- {
- 	int retval = 0;
--	int yuv_buf_size;
- 	int vbi_buf_size;
- 	struct ivtv *itv;
  
-@@ -979,7 +979,7 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
+-	if (hdw->std_dirty ||
+-	    hdw->enc_stale ||
+-	    hdw->srate_dirty ||
+-	    hdw->res_ver_dirty ||
+-	    hdw->res_hor_dirty ||
+-	    0) {
+-		/* If any of this changes, then the encoder needs to be
+-		   reconfigured, and we need to reset the stream. */
+-		stale_subsys_mask |= (1<<PVR2_SUBSYS_B_ENC_CFG);
+-	}
+-
+-	if (hdw->input_dirty) {
+-		/* pk: If input changes to or from radio, then the encoder
+-		   needs to be restarted (for ENC_MUTE_VIDEO to work) */
+-		stale_subsys_mask |= (1<<PVR2_SUBSYS_B_ENC_RUN);
++	/* 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
++	   can proceed. */
++	disruptive_change =
++		(hdw->std_dirty ||
++		 hdw->enc_unsafe_stale ||
++		 hdw->srate_dirty ||
++		 hdw->res_ver_dirty ||
++		 hdw->res_hor_dirty ||
++		 hdw->input_dirty ||
++		 (hdw->active_stream_type != hdw->desired_stream_type));
++	if (disruptive_change && !hdw->state_pipeline_idle) {
++		/* Pipeline is not idle; we can't proceed.  Arrange to
++		   cause pipeline to stop so that we can try this again
++		   later.... */
++		hdw->state_pipeline_pause = !0;
++		return 0;
+ 	}
+ 
+-
+ 	if (hdw->srate_dirty) {
+ 		/* Write new sample rate into control structure since
+ 		 * the master copy is stale.  We must track srate
+@@ -2582,51 +2401,88 @@ static int pvr2_hdw_commit_ctl_internal(struct pvr2_hdw *hdw)
+ 		cptr->info->clear_dirty(cptr);
  	}
  
- 	itv = kzalloc(sizeof(struct ivtv), GFP_ATOMIC);
--	if (itv == 0) {
-+	if (itv == NULL) {
- 		spin_unlock(&ivtv_cards_lock);
- 		return -ENOMEM;
- 	}
-@@ -1068,9 +1068,6 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
- 	IVTV_DEBUG_INFO("Active card count: %d.\n", ivtv_cards_active);
++	if (hdw->active_stream_type != hdw->desired_stream_type) {
++		/* Handle any side effects of stream config here */
++		hdw->active_stream_type = hdw->desired_stream_type;
++	}
++
+ 	/* Now execute i2c core update */
+ 	pvr2_i2c_core_sync(hdw);
+ 
+-	pvr2_hdw_subsys_bit_chg_no_lock(hdw,stale_subsys_mask,0);
+-	pvr2_hdw_subsys_bit_chg_no_lock(hdw,~0,saved_subsys_mask);
++	if (hdw->state_encoder_run) {
++		/* If encoder isn't running, then this will get worked out
++		   later when we start the encoder. */
++		if (pvr2_encoder_adjust(hdw) < 0) return !0;
++	}
+ 
+-	return 0;
++	hdw->state_pipeline_config = !0;
++	trace_stbit("state_pipeline_config",hdw->state_pipeline_config);
++	return !0;
+ }
+ 
  
- 	if (itv->card->hw_all & IVTV_HW_TVEEPROM) {
--#ifdef CONFIG_VIDEO_TVEEPROM_MODULE
--		ivtv_request_module(itv, "tveeprom");
--#endif
- 		/* Based on the model number the cardtype may be changed.
- 		   The PCI IDs are not always reliable. */
- 		ivtv_process_eeprom(itv);
-@@ -1111,16 +1108,19 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
- 		itv->is_50hz = 1;
- 		itv->is_out_50hz = 1;
- 	}
+ int pvr2_hdw_commit_ctl(struct pvr2_hdw *hdw)
+ {
++	int fl;
++	LOCK_TAKE(hdw->big_lock);
++	fl = pvr2_hdw_commit_setup(hdw);
++	LOCK_GIVE(hdw->big_lock);
++	if (!fl) return 0;
++	return pvr2_hdw_wait(hdw,0);
++}
 +
-+	itv->yuv_info.osd_full_w = 720;
-+	itv->yuv_info.osd_full_h = itv->is_out_50hz ? 576 : 480;
-+	itv->yuv_info.v4l2_src_w = itv->yuv_info.osd_full_w;
-+	itv->yuv_info.v4l2_src_h = itv->yuv_info.osd_full_h;
 +
- 	itv->params.video_gop_size = itv->is_60hz ? 15 : 12;
++static void pvr2_hdw_worker_i2c(struct work_struct *work)
++{
++	struct pvr2_hdw *hdw = container_of(work,struct pvr2_hdw,worki2csync);
+ 	LOCK_TAKE(hdw->big_lock); do {
+-		pvr2_hdw_commit_ctl_internal(hdw);
++		pvr2_i2c_core_sync(hdw);
+ 	} while (0); LOCK_GIVE(hdw->big_lock);
+-	return 0;
+ }
  
- 	itv->stream_buf_size[IVTV_ENC_STREAM_TYPE_MPG] = 0x08000;
- 	itv->stream_buf_size[IVTV_ENC_STREAM_TYPE_PCM] = 0x01200;
- 	itv->stream_buf_size[IVTV_DEC_STREAM_TYPE_MPG] = 0x10000;
--
--	/* 0x15180 == 720 * 480 / 4, 0x19500 == 720 * 576 / 4 */
--	yuv_buf_size = itv->is_60hz ? 0x15180 : 0x19500;
--	itv->stream_buf_size[IVTV_DEC_STREAM_TYPE_YUV] = yuv_buf_size / 2;
--	itv->stream_buf_size[IVTV_ENC_STREAM_TYPE_YUV] = yuv_buf_size / 8;
-+	itv->stream_buf_size[IVTV_DEC_STREAM_TYPE_YUV] = 0x10000;
-+	itv->stream_buf_size[IVTV_ENC_STREAM_TYPE_YUV] = 0x08000;
  
- 	/* Setup VBI Raw Size. Should be big enough to hold PAL.
- 	   It is possible to switch between PAL and NTSC, so we need to
-@@ -1140,13 +1140,26 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
- 	if (itv->options.radio > 0)
- 		itv->v4l2_cap |= V4L2_CAP_RADIO;
+-void pvr2_hdw_poll(struct pvr2_hdw *hdw)
++static void pvr2_hdw_worker_poll(struct work_struct *work)
+ {
++	int fl = 0;
++	struct pvr2_hdw *hdw = container_of(work,struct pvr2_hdw,workpoll);
+ 	LOCK_TAKE(hdw->big_lock); do {
+-		pvr2_i2c_core_sync(hdw);
++		fl = pvr2_hdw_state_eval(hdw);
+ 	} while (0); LOCK_GIVE(hdw->big_lock);
++	if (fl && hdw->state_func) {
++		hdw->state_func(hdw->state_data);
++	}
+ }
  
--	if (itv->options.tuner > -1 && itv->tunerid == 0) {
-+	if (itv->options.tuner > -1) {
- 		struct tuner_setup setup;
  
- 		setup.addr = ADDR_UNSET;
- 		setup.type = itv->options.tuner;
- 		setup.mode_mask = T_ANALOG_TV;  /* matches TV tuners */
-+		setup.tuner_callback = (setup.type == TUNER_XC2028) ?
-+			ivtv_reset_tuner_gpio : NULL;
- 		ivtv_call_i2c_clients(itv, TUNER_SET_TYPE_ADDR, &setup);
-+		if (setup.type == TUNER_XC2028) {
-+			static struct xc2028_ctrl ctrl = {
-+				.fname = XC2028_DEFAULT_FIRMWARE,
-+				.max_len = 64,
-+			};
-+			struct v4l2_priv_tun_config cfg = {
-+				.tuner = itv->options.tuner,
-+				.priv = &ctrl,
-+			};
-+			ivtv_call_i2c_clients(itv, TUNER_SET_CONFIG, &cfg);
-+		}
- 	}
+-void pvr2_hdw_setup_poll_trigger(struct pvr2_hdw *hdw,
+-				 void (*func)(void *),
+-				 void *data)
++static void pvr2_hdw_worker_init(struct work_struct *work)
+ {
++	struct pvr2_hdw *hdw = container_of(work,struct pvr2_hdw,workinit);
+ 	LOCK_TAKE(hdw->big_lock); do {
+-		hdw->poll_trigger_func = func;
+-		hdw->poll_trigger_data = data;
++		pvr2_hdw_setup(hdw);
+ 	} while (0); LOCK_GIVE(hdw->big_lock);
+ }
  
- 	/* The tuner is fixed to the standard. The other inputs (e.g. S-Video)
-diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h
-index 49ce14d..536140f 100644
---- a/drivers/media/video/ivtv/ivtv-driver.h
-+++ b/drivers/media/video/ivtv/ivtv-driver.h
-@@ -65,7 +65,6 @@
  
- #include <linux/ivtv.h>
+-void pvr2_hdw_poll_trigger_unlocked(struct pvr2_hdw *hdw)
++static int pvr2_hdw_wait(struct pvr2_hdw *hdw,int state)
+ {
+-	if (hdw->poll_trigger_func) {
+-		hdw->poll_trigger_func(hdw->poll_trigger_data);
+-	}
++	return wait_event_interruptible(
++		hdw->state_wait_data,
++		(hdw->state_stale == 0) &&
++		(!state || (hdw->master_state != state)));
+ }
  
--
- /* Memory layout */
- #define IVTV_ENCODER_OFFSET	0x00000000
- #define IVTV_ENCODER_SIZE	0x00800000	/* Total size is 0x01000000, but only first half is used */
-@@ -392,6 +391,9 @@ struct yuv_frame_info
- 	u32 tru_h;
- 	u32 offset_y;
- 	s32 lace_mode;
-+	u32 sync_field;
-+	u32 delay;
-+	u32 interlaced;
- };
++
++void pvr2_hdw_set_state_callback(struct pvr2_hdw *hdw,
++				 void (*callback_func)(void *),
++				 void *callback_data)
++{
++	LOCK_TAKE(hdw->big_lock); do {
++		hdw->state_data = callback_data;
++		hdw->state_func = callback_func;
++	} while (0); LOCK_GIVE(hdw->big_lock);
++}
++
++
+ /* Return name for this driver instance */
+ const char *pvr2_hdw_get_driver_name(struct pvr2_hdw *hdw)
+ {
+@@ -2634,6 +2490,18 @@ const char *pvr2_hdw_get_driver_name(struct pvr2_hdw *hdw)
+ }
  
- #define IVTV_YUV_MODE_INTERLACED	0x00
-@@ -403,6 +405,8 @@ struct yuv_frame_info
- #define IVTV_YUV_SYNC_ODD		0x04
- #define IVTV_YUV_SYNC_MASK		0x04
  
-+#define IVTV_YUV_BUFFERS 8
++const char *pvr2_hdw_get_desc(struct pvr2_hdw *hdw)
++{
++	return hdw->hdw_desc->description;
++}
 +
- struct yuv_playback_info
++
++const char *pvr2_hdw_get_type(struct pvr2_hdw *hdw)
++{
++	return hdw->hdw_desc->shortname;
++}
++
++
+ int pvr2_hdw_is_hsm(struct pvr2_hdw *hdw)
  {
- 	u32 reg_2834;
-@@ -461,9 +465,10 @@ struct yuv_playback_info
- 	u32 osd_vis_w;
- 	u32 osd_vis_h;
+ 	int result;
+@@ -2689,6 +2557,7 @@ void pvr2_hdw_trigger_module_log(struct pvr2_hdw *hdw)
+ 		pvr2_i2c_core_sync(hdw);
+ 		pvr2_trace(PVR2_TRACE_INFO,"cx2341x config:");
+ 		cx2341x_log_status(&hdw->enc_ctl_state, "pvrusb2");
++		pvr2_hdw_state_log_state(hdw);
+ 		printk(KERN_INFO "pvrusb2: ==================  END STATUS CARD #%d  ==================\n", nr);
+ 	} while (0); LOCK_GIVE(hdw->big_lock);
+ }
+@@ -2959,7 +2828,7 @@ static int pvr2_send_request_ex(struct pvr2_hdw *hdw,
+ 			   " without lock!!");
+ 		return -EDEADLK;
+ 	}
+-	if ((!hdw->flag_ok) && !probe_fl) {
++	if (!hdw->flag_ok && !probe_fl) {
+ 		pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ 			   "Attempted to execute control transfer"
+ 			   " when device not ok");
+@@ -3167,7 +3036,7 @@ static int pvr2_send_request_ex(struct pvr2_hdw *hdw,
  
--	int decode_height;
-+	u32 osd_full_w;
-+	u32 osd_full_h;
+ 	hdw->cmd_debug_state = 0;
+ 	if ((status < 0) && (!probe_fl)) {
+-		pvr2_hdw_render_useless_unlocked(hdw);
++		pvr2_hdw_render_useless(hdw);
+ 	}
+ 	return status;
+ }
+@@ -3227,24 +3096,17 @@ static int pvr2_read_register(struct pvr2_hdw *hdw, u16 reg, u32 *data)
+ }
  
--	int frame_interlaced;
-+	int decode_height;
  
- 	int lace_mode;
- 	int lace_threshold;
-@@ -475,16 +480,23 @@ struct yuv_playback_info
- 	u32 yuv_forced_update;
- 	int update_frame;
+-static void pvr2_hdw_render_useless_unlocked(struct pvr2_hdw *hdw)
++void pvr2_hdw_render_useless(struct pvr2_hdw *hdw)
+ {
+ 	if (!hdw->flag_ok) return;
+-	pvr2_trace(PVR2_TRACE_INIT,"render_useless");
+-	hdw->flag_ok = 0;
++	pvr2_trace(PVR2_TRACE_ERROR_LEGS,
++		   "Device being rendered inoperable");
+ 	if (hdw->vid_stream) {
+ 		pvr2_stream_setup(hdw->vid_stream,NULL,0,0);
+ 	}
+-	hdw->flag_streaming_enabled = 0;
+-	hdw->subsys_enabled_mask = 0;
+-}
+-
+-
+-void pvr2_hdw_render_useless(struct pvr2_hdw *hdw)
+-{
+-	LOCK_TAKE(hdw->ctl_lock);
+-	pvr2_hdw_render_useless_unlocked(hdw);
+-	LOCK_GIVE(hdw->ctl_lock);
++	hdw->flag_ok = 0;
++	trace_stbit("flag_ok",hdw->flag_ok);
++	pvr2_hdw_state_sched(hdw);
+ }
  
--	int sync_field[4];  /* Field to sync on */
--	int field_delay[4]; /* Flag to extend duration of previous frame */
- 	u8 fields_lapsed;   /* Counter used when delaying a frame */
  
--	struct yuv_frame_info new_frame_info[4];
-+	struct yuv_frame_info new_frame_info[IVTV_YUV_BUFFERS];
- 	struct yuv_frame_info old_frame_info;
- 	struct yuv_frame_info old_frame_info_args;
+@@ -3299,7 +3161,6 @@ int pvr2_hdw_cmd_deep_reset(struct pvr2_hdw *hdw)
+ 	int status;
+ 	LOCK_TAKE(hdw->ctl_lock); do {
+ 		pvr2_trace(PVR2_TRACE_INIT,"Requesting uproc hard reset");
+-		hdw->flag_ok = !0;
+ 		hdw->cmd_buffer[0] = FX2CMD_DEEP_RESET;
+ 		status = pvr2_send_request(hdw,hdw->cmd_buffer,1,NULL,0);
+ 	} while (0); LOCK_GIVE(hdw->ctl_lock);
+@@ -3349,26 +3210,473 @@ static int pvr2_hdw_cmd_usbstream(struct pvr2_hdw *hdw,int runFl)
+ 			(runFl ? FX2CMD_STREAMING_ON : FX2CMD_STREAMING_OFF);
+ 		status = pvr2_send_request(hdw,hdw->cmd_buffer,1,NULL,0);
+ 	} while (0); LOCK_GIVE(hdw->ctl_lock);
+-	if (!status) {
+-		hdw->subsys_enabled_mask =
+-			((hdw->subsys_enabled_mask &
+-			  ~(1<<PVR2_SUBSYS_B_USBSTREAM_RUN)) |
+-			 (runFl ? (1<<PVR2_SUBSYS_B_USBSTREAM_RUN) : 0));
+-	}
+ 	return status;
+ }
  
- 	void *blanking_ptr;
- 	dma_addr_t blanking_dmaptr;
-+
-+	int stream_size;
+ 
+-void pvr2_hdw_get_debug_info(const struct pvr2_hdw *hdw,
+-			     struct pvr2_hdw_debug_info *ptr)
++/* Evaluate whether or not state_encoder_ok can change */
++static int state_eval_encoder_ok(struct pvr2_hdw *hdw)
++{
++	if (hdw->state_encoder_ok) return 0;
++	if (hdw->flag_tripped) return 0;
++	if (hdw->state_encoder_run) return 0;
++	if (hdw->state_encoder_config) return 0;
++	if (hdw->state_decoder_run) return 0;
++	if (hdw->state_usbstream_run) return 0;
++	if (pvr2_upload_firmware2(hdw) < 0) {
++		hdw->flag_tripped = !0;
++		trace_stbit("flag_tripped",hdw->flag_tripped);
++		return !0;
++	}
++	hdw->state_encoder_ok = !0;
++	trace_stbit("state_encoder_ok",hdw->state_encoder_ok);
++	return !0;
++}
 +
-+	u8 draw_frame; /* PVR350 buffer to draw into */
-+	u8 max_frames_buffered; /* Maximum number of frames to buffer */
 +
-+	struct v4l2_rect main_rect;
-+	u32 v4l2_src_w;
-+	u32 v4l2_src_h;
- };
- 
- #define IVTV_VBI_FRAMES 32
-@@ -577,13 +589,13 @@ struct ivtv {
- 	struct pci_dev *dev;		/* PCI device */
- 	const struct ivtv_card *card;	/* card information */
- 	const char *card_name;          /* full name of the card */
-+	const struct ivtv_card_tuner_i2c *card_i2c; /* i2c addresses to probe for tuner */
- 	u8 has_cx23415;			/* 1 if it is a cx23415 based card, 0 for cx23416 */
- 	u8 pvr150_workaround;           /* 1 if the cx25840 needs to workaround a PVR150 bug */
- 	u8 nof_inputs;			/* number of video inputs */
- 	u8 nof_audio_inputs;		/* number of audio inputs */
- 	u32 v4l2_cap;			/* V4L2 capabilities of card */
- 	u32 hw_flags; 			/* hardware description of the board */
--	int tunerid;			/* userspace tuner ID for experimental Xceive tuner support */
- 	v4l2_std_id tuner_std;		/* the norm of the card's tuner (fixed) */
- 					/* controlling video decoder function */
- 	int (*video_dec_func)(struct ivtv *, unsigned int, void *);
-diff --git a/drivers/media/video/ivtv/ivtv-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c
-index a200a8a..6fb96f1 100644
---- a/drivers/media/video/ivtv/ivtv-fileops.c
-+++ b/drivers/media/video/ivtv/ivtv-fileops.c
-@@ -542,6 +542,7 @@ ssize_t ivtv_v4l2_write(struct file *filp, const char __user *user_buf, size_t c
- 	struct ivtv_open_id *id = filp->private_data;
- 	struct ivtv *itv = id->itv;
- 	struct ivtv_stream *s = &itv->streams[id->type];
-+	struct yuv_playback_info *yi = &itv->yuv_info;
- 	struct ivtv_buffer *buf;
- 	struct ivtv_queue q;
- 	int bytes_written = 0;
-@@ -580,6 +581,24 @@ ssize_t ivtv_v4l2_write(struct file *filp, const char __user *user_buf, size_t c
- 	set_bit(IVTV_F_S_APPL_IO, &s->s_flags);
- 
- retry:
-+	/* If possible, just DMA the entire frame - Check the data transfer size
-+	since we may get here before the stream has been fully set-up */
-+	if (mode == OUT_YUV && s->q_full.length == 0 && itv->dma_data_req_size) {
-+		while (count >= itv->dma_data_req_size) {
-+			if (!ivtv_yuv_udma_stream_frame (itv, (void *)user_buf)) {
-+				bytes_written += itv->dma_data_req_size;
-+				user_buf += itv->dma_data_req_size;
-+				count -= itv->dma_data_req_size;
-+			} else {
-+				break;
++/* Evaluate whether or not state_encoder_config can change */
++static int state_eval_encoder_config(struct pvr2_hdw *hdw)
++{
++	if (hdw->state_encoder_config) {
++		if (hdw->state_encoder_ok) {
++			if (hdw->state_pipeline_req &&
++			    !hdw->state_pipeline_pause) return 0;
++		}
++		hdw->state_encoder_config = 0;
++		hdw->state_encoder_waitok = 0;
++		trace_stbit("state_encoder_waitok",hdw->state_encoder_waitok);
++		/* paranoia - solve race if timer just completed */
++		del_timer_sync(&hdw->encoder_wait_timer);
++	} else {
++		if (!hdw->state_encoder_ok ||
++		    !hdw->state_pipeline_idle ||
++		    hdw->state_pipeline_pause ||
++		    !hdw->state_pipeline_req ||
++		    !hdw->state_pipeline_config) {
++			/* We must reset the enforced wait interval if
++			   anything has happened that might have disturbed
++			   the encoder.  This should be a rare case. */
++			if (timer_pending(&hdw->encoder_wait_timer)) {
++				del_timer_sync(&hdw->encoder_wait_timer);
++			}
++			if (hdw->state_encoder_waitok) {
++				/* Must clear the state - therefore we did
++				   something to a state bit and must also
++				   return true. */
++				hdw->state_encoder_waitok = 0;
++				trace_stbit("state_encoder_waitok",
++					    hdw->state_encoder_waitok);
++				return !0;
 +			}
++			return 0;
 +		}
-+		if (count == 0) {
-+			IVTV_DEBUG_HI_FILE("Wrote %d bytes to %s (%d)\n", bytes_written, s->name, s->q_full.bytesused);
-+			return bytes_written;
++		if (!hdw->state_encoder_waitok) {
++			if (!timer_pending(&hdw->encoder_wait_timer)) {
++				/* waitok flag wasn't set and timer isn't
++				   running.  Check flag once more to avoid
++				   a race then start the timer.  This is
++				   the point when we measure out a minimal
++				   quiet interval before doing something to
++				   the encoder. */
++				if (!hdw->state_encoder_waitok) {
++					hdw->encoder_wait_timer.expires =
++						jiffies + (HZ*50/1000);
++					add_timer(&hdw->encoder_wait_timer);
++				}
++			}
++			/* We can't continue until we know we have been
++			   quiet for the interval measured by this
++			   timer. */
++			return 0;
 +		}
++		pvr2_encoder_configure(hdw);
++		if (hdw->state_encoder_ok) hdw->state_encoder_config = !0;
 +	}
++	trace_stbit("state_encoder_config",hdw->state_encoder_config);
++	return !0;
++}
 +
- 	for (;;) {
- 		/* Gather buffers */
- 		while (q.length - q.bytesused < count && (buf = ivtv_dequeue(s, &s->q_io)))
-@@ -604,9 +623,16 @@ retry:
- 
- 	/* copy user data into buffers */
- 	while ((buf = ivtv_dequeue(s, &q))) {
--		/* Make sure we really got all the user data */
--		rc = ivtv_buf_copy_from_user(s, buf, user_buf, count);
-+		/* yuv is a pain. Don't copy more data than needed for a single
-+		   frame, otherwise we lose sync with the incoming stream */
-+		if (s->type == IVTV_DEC_STREAM_TYPE_YUV &&
-+		    yi->stream_size + count > itv->dma_data_req_size)
-+			rc  = ivtv_buf_copy_from_user(s, buf, user_buf,
-+				itv->dma_data_req_size - yi->stream_size);
-+		else
-+			rc = ivtv_buf_copy_from_user(s, buf, user_buf, count);
- 
-+		/* Make sure we really got all the user data */
- 		if (rc < 0) {
- 			ivtv_queue_move(s, &q, NULL, &s->q_free, 0);
- 			return rc;
-@@ -615,6 +641,16 @@ retry:
- 		count -= rc;
- 		bytes_written += rc;
- 
-+		if (s->type == IVTV_DEC_STREAM_TYPE_YUV) {
-+			yi->stream_size += rc;
-+			/* If we have a complete yuv frame, break loop now */
-+			if (yi->stream_size == itv->dma_data_req_size) {
-+				ivtv_enqueue(s, buf, &s->q_full);
-+				yi->stream_size = 0;
-+				break;
-+			}
++
++/* Evaluate whether or not state_encoder_run can change */
++static int state_eval_encoder_run(struct pvr2_hdw *hdw)
++{
++	if (hdw->state_encoder_run) {
++		if (hdw->state_encoder_ok) {
++			if (hdw->state_decoder_run) return 0;
++			if (pvr2_encoder_stop(hdw) < 0) return !0;
 +		}
++		hdw->state_encoder_run = 0;
++	} else {
++		if (!hdw->state_encoder_ok) return 0;
++		if (!hdw->state_decoder_run) return 0;
++		if (pvr2_encoder_start(hdw) < 0) return !0;
++		hdw->state_encoder_run = !0;
++	}
++	trace_stbit("state_encoder_run",hdw->state_encoder_run);
++	return !0;
++}
 +
- 		if (buf->bytesused != s->buf_size) {
- 			/* incomplete, leave in q_io for next time */
- 			ivtv_enqueue(s, buf, &s->q_io);
-@@ -642,6 +678,9 @@ retry:
- 		if (s->q_full.length >= itv->dma_data_req_size) {
- 			int got_sig;
- 
-+			if (mode == OUT_YUV)
-+				ivtv_yuv_setup_stream_frame(itv);
 +
- 			prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE);
- 			while (!(got_sig = signal_pending(current)) &&
- 					test_bit(IVTV_F_S_DMA_PENDING, &s->s_flags)) {
-@@ -922,10 +961,15 @@ static int ivtv_serialized_open(struct ivtv_stream *s, struct file *filp)
- 	}
- 
- 	/* YUV or MPG Decoding Mode? */
--	if (s->type == IVTV_DEC_STREAM_TYPE_MPG)
-+	if (s->type == IVTV_DEC_STREAM_TYPE_MPG) {
- 		clear_bit(IVTV_F_I_DEC_YUV, &itv->i_flags);
--	else if (s->type == IVTV_DEC_STREAM_TYPE_YUV)
-+	} else if (s->type == IVTV_DEC_STREAM_TYPE_YUV) {
- 		set_bit(IVTV_F_I_DEC_YUV, &itv->i_flags);
-+		/* For yuv, we need to know the dma size before we start */
-+		itv->dma_data_req_size =
-+				1080 * ((itv->yuv_info.v4l2_src_h + 31) & ~31);
-+		itv->yuv_info.stream_size = 0;
++/* Timeout function for quiescent timer. */
++static void pvr2_hdw_quiescent_timeout(unsigned long data)
++{
++	struct pvr2_hdw *hdw = (struct pvr2_hdw *)data;
++	hdw->state_decoder_quiescent = !0;
++	trace_stbit("state_decoder_quiescent",hdw->state_decoder_quiescent);
++	hdw->state_stale = !0;
++	queue_work(hdw->workqueue,&hdw->workpoll);
++}
++
++
++/* Timeout function for encoder wait timer. */
++static void pvr2_hdw_encoder_wait_timeout(unsigned long data)
++{
++	struct pvr2_hdw *hdw = (struct pvr2_hdw *)data;
++	hdw->state_encoder_waitok = !0;
++	trace_stbit("state_encoder_waitok",hdw->state_encoder_waitok);
++	hdw->state_stale = !0;
++	queue_work(hdw->workqueue,&hdw->workpoll);
++}
++
++
++/* Evaluate whether or not state_decoder_run can change */
++static int state_eval_decoder_run(struct pvr2_hdw *hdw)
++{
++	if (hdw->state_decoder_run) {
++		if (hdw->state_encoder_ok) {
++			if (hdw->state_pipeline_req &&
++			    !hdw->state_pipeline_pause) return 0;
++		}
++		if (!hdw->flag_decoder_missed) {
++			pvr2_decoder_enable(hdw,0);
++		}
++		hdw->state_decoder_quiescent = 0;
++		hdw->state_decoder_run = 0;
++		/* paranoia - solve race if timer just completed */
++		del_timer_sync(&hdw->quiescent_timer);
++	} else {
++		if (!hdw->state_decoder_quiescent) {
++			if (!timer_pending(&hdw->quiescent_timer)) {
++				/* We don't do something about the
++				   quiescent timer until right here because
++				   we also want to catch cases where the
++				   decoder was already not running (like
++				   after initialization) as opposed to
++				   knowing that we had just stopped it.
++				   The second flag check is here to cover a
++				   race - the timer could have run and set
++				   this flag just after the previous check
++				   but before we did the pending check. */
++				if (!hdw->state_decoder_quiescent) {
++					hdw->quiescent_timer.expires =
++						jiffies + (HZ*50/1000);
++					add_timer(&hdw->quiescent_timer);
++				}
++			}
++			/* Don't allow decoder to start again until it has
++			   been quiesced first.  This little detail should
++			   hopefully further stabilize the encoder. */
++			return 0;
++		}
++		if (!hdw->state_pipeline_req ||
++		    hdw->state_pipeline_pause ||
++		    !hdw->state_pipeline_config ||
++		    !hdw->state_encoder_config ||
++		    !hdw->state_encoder_ok) return 0;
++		del_timer_sync(&hdw->quiescent_timer);
++		if (hdw->flag_decoder_missed) return 0;
++		if (pvr2_decoder_enable(hdw,!0) < 0) return 0;
++		hdw->state_decoder_quiescent = 0;
++		hdw->state_decoder_run = !0;
 +	}
- 	return 0;
- }
- 
-diff --git a/drivers/media/video/ivtv/ivtv-gpio.c b/drivers/media/video/ivtv/ivtv-gpio.c
-index 132fb5f..688cd38 100644
---- a/drivers/media/video/ivtv/ivtv-gpio.c
-+++ b/drivers/media/video/ivtv/ivtv-gpio.c
-@@ -22,6 +22,7 @@
- #include "ivtv-driver.h"
- #include "ivtv-cards.h"
- #include "ivtv-gpio.h"
-+#include "tuner-xc2028.h"
- #include <media/tuner.h>
- 
- /*
-@@ -122,6 +123,29 @@ void ivtv_reset_ir_gpio(struct ivtv *itv)
- 	write_reg(curdir, IVTV_REG_GPIO_DIR);
- }
- 
-+/* Xceive tuner reset function */
-+int ivtv_reset_tuner_gpio(void *dev, int cmd, int value)
++	trace_stbit("state_decoder_quiescent",hdw->state_decoder_quiescent);
++	trace_stbit("state_decoder_run",hdw->state_decoder_run);
++	return !0;
++}
++
++
++/* Evaluate whether or not state_usbstream_run can change */
++static int state_eval_usbstream_run(struct pvr2_hdw *hdw)
 +{
-+	struct i2c_algo_bit_data *algo = dev;
-+	struct ivtv *itv = algo->data;
-+	int curdir, curout;
++	if (hdw->state_usbstream_run) {
++		if (hdw->state_encoder_ok) {
++			if (hdw->state_encoder_run) return 0;
++		}
++		pvr2_hdw_cmd_usbstream(hdw,0);
++		hdw->state_usbstream_run = 0;
++	} else {
++		if (!hdw->state_encoder_ok ||
++		    !hdw->state_encoder_run ||
++		    !hdw->state_pipeline_req ||
++		    hdw->state_pipeline_pause) return 0;
++		if (pvr2_hdw_cmd_usbstream(hdw,!0) < 0) return 0;
++		hdw->state_usbstream_run = !0;
++	}
++	trace_stbit("state_usbstream_run",hdw->state_usbstream_run);
++	return !0;
++}
 +
-+	if (cmd != XC2028_TUNER_RESET)
-+		return 0;
-+	IVTV_DEBUG_INFO("Resetting tuner\n");
-+	curout = read_reg(IVTV_REG_GPIO_OUT);
-+	curdir = read_reg(IVTV_REG_GPIO_DIR);
-+	curdir |= (1 << 12);  /* GPIO bit 12 */
 +
-+	curout &= ~(1 << 12);
-+	write_reg(curout, IVTV_REG_GPIO_OUT);
-+	schedule_timeout_interruptible(msecs_to_jiffies(1));
++/* Attempt to configure pipeline, if needed */
++static int state_eval_pipeline_config(struct pvr2_hdw *hdw)
++{
++	if (hdw->state_pipeline_config ||
++	    hdw->state_pipeline_pause) return 0;
++	pvr2_hdw_commit_execute(hdw);
++	return !0;
++}
 +
-+	curout |= (1 << 12);
-+	write_reg(curout, IVTV_REG_GPIO_OUT);
-+	schedule_timeout_interruptible(msecs_to_jiffies(1));
-+	return 0;
++
++/* Update pipeline idle and pipeline pause tracking states based on other
++   inputs.  This must be called whenever the other relevant inputs have
++   changed. */
++static int state_update_pipeline_state(struct pvr2_hdw *hdw)
++{
++	unsigned int st;
++	int updatedFl = 0;
++	/* Update pipeline state */
++	st = !(hdw->state_encoder_run ||
++	       hdw->state_decoder_run ||
++	       hdw->state_usbstream_run ||
++	       (!hdw->state_decoder_quiescent));
++	if (!st != !hdw->state_pipeline_idle) {
++		hdw->state_pipeline_idle = st;
++		updatedFl = !0;
++	}
++	if (hdw->state_pipeline_idle && hdw->state_pipeline_pause) {
++		hdw->state_pipeline_pause = 0;
++		updatedFl = !0;
++	}
++	return updatedFl;
 +}
- 
- void ivtv_gpio_init(struct ivtv *itv)
- {
-diff --git a/drivers/media/video/ivtv/ivtv-i2c.c b/drivers/media/video/ivtv/ivtv-i2c.c
-index 36e54f7..fa5ab1e 100644
---- a/drivers/media/video/ivtv/ivtv-i2c.c
-+++ b/drivers/media/video/ivtv/ivtv-i2c.c
-@@ -80,6 +80,7 @@
- #endif /* I2C_ADAP_CLASS_TV_ANALOG */
- 
- #define IVTV_CS53L32A_I2C_ADDR		0x11
-+#define IVTV_M52790_I2C_ADDR		0x48
- #define IVTV_CX25840_I2C_ADDR 		0x44
- #define IVTV_SAA7115_I2C_ADDR 		0x21
- #define IVTV_SAA7127_I2C_ADDR 		0x44
-@@ -91,7 +92,8 @@
- #define IVTV_TEA5767_I2C_ADDR		0x60
- #define IVTV_UPD64031A_I2C_ADDR 	0x12
- #define IVTV_UPD64083_I2C_ADDR 		0x5c
--#define IVTV_TDA985X_I2C_ADDR      	0x5b
-+#define IVTV_VP27SMPX_I2C_ADDR      	0x5b
-+#define IVTV_M52790_I2C_ADDR      	0x48
- 
- /* This array should match the IVTV_HW_ defines */
- static const u8 hw_driverids[] = {
-@@ -104,18 +106,38 @@ static const u8 hw_driverids[] = {
- 	I2C_DRIVERID_CS53L32A,
- 	I2C_DRIVERID_TVEEPROM,
- 	I2C_DRIVERID_SAA711X,
--	I2C_DRIVERID_TVAUDIO,
- 	I2C_DRIVERID_UPD64031A,
- 	I2C_DRIVERID_UPD64083,
- 	I2C_DRIVERID_SAA717X,
- 	I2C_DRIVERID_WM8739,
- 	I2C_DRIVERID_VP27SMPX,
-+	I2C_DRIVERID_M52790,
-+	0 		/* IVTV_HW_GPIO dummy driver ID */
++
++
++typedef int (*state_eval_func)(struct pvr2_hdw *);
++
++/* Set of functions to be run to evaluate various states in the driver. */
++const static state_eval_func eval_funcs[] = {
++	state_eval_pipeline_config,
++	state_eval_encoder_ok,
++	state_eval_encoder_config,
++	state_eval_decoder_run,
++	state_eval_encoder_run,
++	state_eval_usbstream_run,
 +};
 +
-+/* This array should match the IVTV_HW_ defines */
-+static const u8 hw_addrs[] = {
-+	IVTV_CX25840_I2C_ADDR,
-+	IVTV_SAA7115_I2C_ADDR,
-+	IVTV_SAA7127_I2C_ADDR,
-+	IVTV_MSP3400_I2C_ADDR,
-+	0,
-+	IVTV_WM8775_I2C_ADDR,
-+	IVTV_CS53L32A_I2C_ADDR,
-+	0,
-+	IVTV_SAA7115_I2C_ADDR,
-+	IVTV_UPD64031A_I2C_ADDR,
-+	IVTV_UPD64083_I2C_ADDR,
-+	IVTV_SAA717x_I2C_ADDR,
-+	IVTV_WM8739_I2C_ADDR,
-+	IVTV_VP27SMPX_I2C_ADDR,
-+	IVTV_M52790_I2C_ADDR,
- 	0 		/* IVTV_HW_GPIO dummy driver ID */
- };
- 
- /* This array should match the IVTV_HW_ defines */
- static const char * const hw_drivernames[] = {
--	"cx2584x",
-+	"cx25840",
- 	"saa7115",
- 	"saa7127",
- 	"msp3400",
-@@ -123,31 +145,67 @@ static const char * const hw_drivernames[] = {
- 	"wm8775",
- 	"cs53l32a",
- 	"tveeprom",
--	"saa7114",
--	"tvaudio",
-+	"saa7115",
- 	"upd64031a",
- 	"upd64083",
- 	"saa717x",
- 	"wm8739",
- 	"vp27smpx",
-+	"m52790",
- 	"gpio",
- };
- 
--static int attach_inform(struct i2c_client *client)
-+int ivtv_i2c_register(struct ivtv *itv, unsigned idx)
- {
--	struct ivtv *itv = (struct ivtv *)i2c_get_adapdata(client->adapter);
-+	struct i2c_board_info info;
-+	struct i2c_client *c;
-+	u8 id;
- 	int i;
- 
--	IVTV_DEBUG_I2C("i2c client attach\n");
--	for (i = 0; i < I2C_CLIENTS_MAX; i++) {
--		if (itv->i2c_clients[i] == NULL) {
--			itv->i2c_clients[i] = client;
--			break;
--		}
--	}
-+	IVTV_DEBUG_I2C("i2c client register\n");
-+	if (idx >= ARRAY_SIZE(hw_driverids) || hw_driverids[idx] == 0)
-+		return -1;
-+	id = hw_driverids[idx];
-+	memset(&info, 0, sizeof(info));
-+	strcpy(info.driver_name, hw_drivernames[idx]);
-+	info.addr = hw_addrs[idx];
-+	for (i = 0; itv->i2c_clients[i] && i < I2C_CLIENTS_MAX; i++) {}
 +
- 	if (i == I2C_CLIENTS_MAX) {
--		IVTV_ERR("Insufficient room for new I2C client\n");
-+		IVTV_ERR("insufficient room for new I2C client!\n");
-+		return -ENOMEM;
- 	}
++/* Process various states and return true if we did anything interesting. */
++static int pvr2_hdw_state_update(struct pvr2_hdw *hdw)
++{
++	unsigned int i;
++	int state_updated = 0;
++	int check_flag;
 +
-+	if (id != I2C_DRIVERID_TUNER) {
-+		c = i2c_new_device(&itv->i2c_adap, &info);
-+		if (c->driver == NULL)
-+			i2c_unregister_device(c);
-+		else
-+			itv->i2c_clients[i] = c;
-+		return itv->i2c_clients[i] ? 0 : -ENODEV;
++	if (!hdw->state_stale) return 0;
++	if ((hdw->fw1_state != FW1_STATE_OK) ||
++	    !hdw->flag_ok) {
++		hdw->state_stale = 0;
++		return !0;
 +	}
-+
-+	/* special tuner handling */
-+	c = i2c_new_probed_device(&itv->i2c_adap, &info, itv->card_i2c->radio);
-+	if (c && c->driver == NULL)
-+		i2c_unregister_device(c);
-+	else if (c)
-+		itv->i2c_clients[i++] = c;
-+	c = i2c_new_probed_device(&itv->i2c_adap, &info, itv->card_i2c->demod);
-+	if (c && c->driver == NULL)
-+		i2c_unregister_device(c);
-+	else if (c)
-+		itv->i2c_clients[i++] = c;
-+	c = i2c_new_probed_device(&itv->i2c_adap, &info, itv->card_i2c->tv);
-+	if (c && c->driver == NULL)
-+		i2c_unregister_device(c);
-+	else if (c)
-+		itv->i2c_clients[i++] = c;
-+	return 0;
++	/* This loop is the heart of the entire driver.  It keeps trying to
++	   evaluate various bits of driver state until nothing changes for
++	   one full iteration.  Each "bit of state" tracks some global
++	   aspect of the driver, e.g. whether decoder should run, if
++	   pipeline is configured, usb streaming is on, etc.  We separately
++	   evaluate each of those questions based on other driver state to
++	   arrive at the correct running configuration. */
++	do {
++		check_flag = 0;
++		state_update_pipeline_state(hdw);
++		/* Iterate over each bit of state */
++		for (i = 0; (i<ARRAY_SIZE(eval_funcs)) && hdw->flag_ok; i++) {
++			if ((*eval_funcs[i])(hdw)) {
++				check_flag = !0;
++				state_updated = !0;
++				state_update_pipeline_state(hdw);
++			}
++		}
++	} while (check_flag && hdw->flag_ok);
++	hdw->state_stale = 0;
++	trace_stbit("state_stale",hdw->state_stale);
++	return state_updated;
 +}
 +
-+static int attach_inform(struct i2c_client *client)
++
++static unsigned int pvr2_hdw_report_unlocked(struct pvr2_hdw *hdw,int which,
++					     char *buf,unsigned int acnt)
 +{
- 	return 0;
- }
- 
-@@ -475,9 +533,6 @@ static struct i2c_adapter ivtv_i2c_adap_hw_template = {
- 	.client_register = attach_inform,
- 	.client_unregister = detach_inform,
- 	.owner = THIS_MODULE,
--#ifdef I2C_ADAP_CLASS_TV_ANALOG
--	.class = I2C_ADAP_CLASS_TV_ANALOG,
--#endif
- };
- 
- static void ivtv_setscl_old(void *data, int state)
-@@ -525,15 +580,12 @@ static int ivtv_getsda_old(void *data)
- /* template for i2c-bit-algo */
- static struct i2c_adapter ivtv_i2c_adap_template = {
- 	.name = "ivtv i2c driver",
--	.id = I2C_HW_B_CX2341X,  	/* algo-bit is OR'd with this */
-+	.id = I2C_HW_B_CX2341X,
- 	.algo = NULL,                   /* set by i2c-algo-bit */
- 	.algo_data = NULL,              /* filled from template */
- 	.client_register = attach_inform,
- 	.client_unregister = detach_inform,
- 	.owner = THIS_MODULE,
--#ifdef I2C_ADAP_CLASS_TV_ANALOG
--	.class = I2C_ADAP_CLASS_TV_ANALOG,
--#endif
- };
- 
- static const struct i2c_algo_bit_data ivtv_i2c_algo_template = {
-@@ -558,12 +610,9 @@ int ivtv_call_i2c_client(struct ivtv *itv, int addr, unsigned int cmd, void *arg
- 	IVTV_DEBUG_I2C("call_i2c_client addr=%02x\n", addr);
- 	for (i = 0; i < I2C_CLIENTS_MAX; i++) {
- 		client = itv->i2c_clients[i];
--		if (client == NULL) {
--			continue;
--		}
--		if (client->driver->command == NULL) {
-+		if (client == NULL || client->driver == NULL ||
-+		    client->driver->command == NULL)
- 			continue;
--		}
- 		if (addr == client->addr) {
- 			retval = client->driver->command(client, cmd, arg);
- 			return retval;
-@@ -584,7 +633,7 @@ static int ivtv_i2c_id_addr(struct ivtv *itv, u32 id)
- 
- 	for (i = 0; i < I2C_CLIENTS_MAX; i++) {
- 		client = itv->i2c_clients[i];
--		if (client == NULL)
-+		if (client == NULL || client->driver == NULL)
- 			continue;
- 		if (id == client->driver->id) {
- 			retval = client->addr;
-@@ -710,6 +759,16 @@ int init_ivtv_i2c(struct ivtv *itv)
- {
- 	IVTV_DEBUG_I2C("i2c init\n");
- 
-+	/* Sanity checks for the I2C hardware arrays. They must be the
-+	 * same size and GPIO must be the last entry.
-+	 */
-+	if (ARRAY_SIZE(hw_driverids) != ARRAY_SIZE(hw_addrs) ||
-+	    ARRAY_SIZE(hw_drivernames) != ARRAY_SIZE(hw_addrs) ||
-+	    IVTV_HW_GPIO != (1 << (ARRAY_SIZE(hw_addrs) - 1)) ||
-+	    hw_driverids[ARRAY_SIZE(hw_addrs) - 1]) {
-+		IVTV_ERR("Mismatched I2C hardware arrays\n");
-+		return -ENODEV;
-+	}
- 	if (itv->options.newi2c > 0) {
- 		memcpy(&itv->i2c_adap, &ivtv_i2c_adap_hw_template,
- 		       sizeof(struct i2c_adapter));
-@@ -718,9 +777,9 @@ int init_ivtv_i2c(struct ivtv *itv)
- 		       sizeof(struct i2c_adapter));
- 		memcpy(&itv->i2c_algo, &ivtv_i2c_algo_template,
- 		       sizeof(struct i2c_algo_bit_data));
--		itv->i2c_algo.data = itv;
--		itv->i2c_adap.algo_data = &itv->i2c_algo;
- 	}
-+	itv->i2c_algo.data = itv;
-+	itv->i2c_adap.algo_data = &itv->i2c_algo;
- 
- 	sprintf(itv->i2c_adap.name + strlen(itv->i2c_adap.name), " #%d",
- 		itv->num);
-diff --git a/drivers/media/video/ivtv/ivtv-i2c.h b/drivers/media/video/ivtv/ivtv-i2c.h
-index 987042c..022978c 100644
---- a/drivers/media/video/ivtv/ivtv-i2c.h
-+++ b/drivers/media/video/ivtv/ivtv-i2c.h
-@@ -33,6 +33,7 @@ int ivtv_i2c_hw(struct ivtv *itv, u32 hw, unsigned int cmd, void *arg);
- int ivtv_i2c_id(struct ivtv *itv, u32 id, unsigned int cmd, void *arg);
- int ivtv_call_i2c_client(struct ivtv *itv, int addr, unsigned int cmd, void *arg);
- void ivtv_call_i2c_clients(struct ivtv *itv, unsigned int cmd, void *arg);
-+int ivtv_i2c_register(struct ivtv *itv, unsigned idx);
- 
- /* init + register i2c algo-bit adapter */
- int init_ivtv_i2c(struct ivtv *itv);
-diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c
-index fd6826f..edef2a5 100644
---- a/drivers/media/video/ivtv/ivtv-ioctl.c
-+++ b/drivers/media/video/ivtv/ivtv-ioctl.c
-@@ -372,7 +372,7 @@ static int ivtv_get_fmt(struct ivtv *itv, int streamtype, struct v4l2_format *fm
- 		fmt->fmt.pix.height = itv->main_rect.height;
- 		fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
- 		fmt->fmt.pix.field = V4L2_FIELD_INTERLACED;
--		if (itv->output_mode == OUT_UDMA_YUV) {
-+		if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) {
- 			switch (itv->yuv_info.lace_mode & IVTV_YUV_MODE_MASK) {
- 			case IVTV_YUV_MODE_INTERLACED:
- 				fmt->fmt.pix.field = (itv->yuv_info.lace_mode & IVTV_YUV_SYNC_MASK) ?
-@@ -386,14 +386,13 @@ static int ivtv_get_fmt(struct ivtv *itv, int streamtype, struct v4l2_format *fm
- 				break;
- 			}
- 			fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_HM12;
-+			fmt->fmt.pix.bytesperline = 720;
-+			fmt->fmt.pix.width = itv->yuv_info.v4l2_src_w;
-+			fmt->fmt.pix.height = itv->yuv_info.v4l2_src_h;
- 			/* YUV size is (Y=(h*w) + UV=(h*(w/2))) */
- 			fmt->fmt.pix.sizeimage =
--				fmt->fmt.pix.height * fmt->fmt.pix.width +
--				fmt->fmt.pix.height * (fmt->fmt.pix.width / 2);
--		}
--		else if (itv->output_mode == OUT_YUV ||
--				streamtype == IVTV_ENC_STREAM_TYPE_YUV ||
--				streamtype == IVTV_DEC_STREAM_TYPE_YUV) {
-+				1080 * ((fmt->fmt.pix.height + 31) & ~31);
-+		} else if (streamtype == IVTV_ENC_STREAM_TYPE_YUV) {
- 			fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_HM12;
- 			/* YUV size is (Y=(h*w) + UV=(h*(w/2))) */
- 			fmt->fmt.pix.sizeimage =
-@@ -490,6 +489,7 @@ static int ivtv_get_fmt(struct ivtv *itv, int streamtype, struct v4l2_format *fm
- static int ivtv_try_or_set_fmt(struct ivtv *itv, int streamtype,
- 		struct v4l2_format *fmt, int set_fmt)
- {
-+	struct yuv_playback_info *yi = &itv->yuv_info;
- 	struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
- 	u16 set;
- 
-@@ -505,39 +505,52 @@ static int ivtv_try_or_set_fmt(struct ivtv *itv, int streamtype,
- 		r.width = fmt->fmt.pix.width;
- 		r.height = fmt->fmt.pix.height;
- 		ivtv_get_fmt(itv, streamtype, fmt);
--		if (itv->output_mode != OUT_UDMA_YUV) {
--			/* TODO: would setting the rect also be valid for this mode? */
--			fmt->fmt.pix.width = r.width;
--			fmt->fmt.pix.height = r.height;
--		}
--		if (itv->output_mode == OUT_UDMA_YUV) {
--			/* TODO: add checks for validity */
-+		fmt->fmt.pix.width = r.width;
-+		fmt->fmt.pix.height = r.height;
-+		if (streamtype == 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;
- 		}
--		if (set_fmt) {
--			if (itv->output_mode == OUT_UDMA_YUV) {
--				switch (field) {
--				case V4L2_FIELD_NONE:
--					itv->yuv_info.lace_mode = IVTV_YUV_MODE_PROGRESSIVE;
--					break;
--				case V4L2_FIELD_ANY:
--					itv->yuv_info.lace_mode = IVTV_YUV_MODE_AUTO;
--					break;
--				case V4L2_FIELD_INTERLACED_BT:
--					itv->yuv_info.lace_mode =
--						IVTV_YUV_MODE_INTERLACED|IVTV_YUV_SYNC_ODD;
--					break;
--				case V4L2_FIELD_INTERLACED_TB:
--				default:
--					itv->yuv_info.lace_mode = IVTV_YUV_MODE_INTERLACED;
--					break;
--				}
--				itv->yuv_info.lace_sync_field = (itv->yuv_info.lace_mode & IVTV_YUV_SYNC_MASK) == IVTV_YUV_SYNC_EVEN ? 0 : 1;
-+		if (set_fmt && streamtype == IVTV_DEC_STREAM_TYPE_YUV) {
-+			/* Return now if we already have some frame data */
-+			if (yi->stream_size)
-+				return -EBUSY;
- 
--				/* Force update of yuv registers */
--				itv->yuv_info.yuv_forced_update = 1;
--				return 0;
-+			yi->v4l2_src_w = r.width;
-+			yi->v4l2_src_h = r.height;
++	switch (which) {
++	case 0:
++		return scnprintf(
++			buf,acnt,
++			"driver:%s%s%s%s%s",
++			(hdw->flag_ok ? " <ok>" : " <fail>"),
++			(hdw->flag_init_ok ? " <init>" : " <uninitialized>"),
++			(hdw->flag_disconnected ? " <disconnected>" :
++			 " <connected>"),
++			(hdw->flag_tripped ? " <tripped>" : ""),
++			(hdw->flag_decoder_missed ? " <no decoder>" : ""));
++	case 1:
++		return scnprintf(
++			buf,acnt,
++			"pipeline:%s%s%s%s",
++			(hdw->state_pipeline_idle ? " <idle>" : ""),
++			(hdw->state_pipeline_config ?
++			 " <configok>" : " <stale>"),
++			(hdw->state_pipeline_req ? " <req>" : ""),
++			(hdw->state_pipeline_pause ? " <pause>" : ""));
++	case 2:
++		return scnprintf(
++			buf,acnt,
++			"worker:%s%s%s%s%s%s",
++			(hdw->state_decoder_run ?
++			 " <decode:run>" :
++			 (hdw->state_decoder_quiescent ?
++			  "" : " <decode:stop>")),
++			(hdw->state_decoder_quiescent ?
++			 " <decode:quiescent>" : ""),
++			(hdw->state_encoder_ok ?
++			 "" : " <encode:init>"),
++			(hdw->state_encoder_run ?
++			 " <encode:run>" : " <encode:stop>"),
++			(hdw->state_encoder_config ?
++			 " <encode:configok>" :
++			 (hdw->state_encoder_waitok ?
++			  "" : " <encode:wait>")),
++			(hdw->state_usbstream_run ?
++			 " <usb:run>" : " <usb:stop>"));
++		break;
++	case 3:
++		return scnprintf(
++			buf,acnt,
++			"state: %s",
++			pvr2_get_state_name(hdw->master_state));
++		break;
++	default: break;
++	}
++	return 0;
++}
 +
-+			switch (field) {
-+			case V4L2_FIELD_NONE:
-+				yi->lace_mode = IVTV_YUV_MODE_PROGRESSIVE;
-+				break;
-+			case V4L2_FIELD_ANY:
-+				yi->lace_mode = IVTV_YUV_MODE_AUTO;
-+				break;
-+			case V4L2_FIELD_INTERLACED_BT:
-+				yi->lace_mode =
-+				     IVTV_YUV_MODE_INTERLACED|IVTV_YUV_SYNC_ODD;
-+				break;
-+			case V4L2_FIELD_INTERLACED_TB:
-+			default:
-+				yi->lace_mode = IVTV_YUV_MODE_INTERLACED;
-+				break;
- 			}
-+			yi->lace_sync_field = (yi->lace_mode & IVTV_YUV_SYNC_MASK) == IVTV_YUV_SYNC_EVEN ? 0 : 1;
 +
-+			if (test_bit(IVTV_F_I_DEC_YUV, &itv->i_flags))
-+				itv->dma_data_req_size =
-+					   1080 * ((yi->v4l2_src_h + 31) & ~31);
++unsigned int pvr2_hdw_state_report(struct pvr2_hdw *hdw,
++				   char *buf,unsigned int acnt)
++{
++	unsigned int bcnt,ccnt,idx;
++	bcnt = 0;
++	LOCK_TAKE(hdw->big_lock);
++	for (idx = 0; ; idx++) {
++		ccnt = pvr2_hdw_report_unlocked(hdw,idx,buf,acnt);
++		if (!ccnt) break;
++		bcnt += ccnt; acnt -= ccnt; buf += ccnt;
++		if (!acnt) break;
++		buf[0] = '\n'; ccnt = 1;
++		bcnt += ccnt; acnt -= ccnt; buf += ccnt;
++	}
++	LOCK_GIVE(hdw->big_lock);
++	return bcnt;
++}
 +
-+			/* Force update of yuv registers */
-+			yi->yuv_forced_update = 1;
-+			return 0;
- 		}
- 		return 0;
- 	}
-@@ -660,11 +673,8 @@ static int ivtv_debug_ioctls(struct file *filp, unsigned int cmd, void *arg)
- 		chip->ident = V4L2_IDENT_NONE;
- 		chip->revision = 0;
- 		if (reg->match_type == V4L2_CHIP_MATCH_HOST) {
--			if (v4l2_chip_match_host(reg->match_type, reg->match_chip)) {
--				struct v4l2_chip_ident *chip = arg;
--
-+			if (v4l2_chip_match_host(reg->match_type, reg->match_chip))
- 				chip->ident = itv->has_cx23415 ? V4L2_IDENT_CX23415 : V4L2_IDENT_CX23416;
--			}
- 			return 0;
- 		}
- 		if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER)
-@@ -688,7 +698,7 @@ static int ivtv_debug_ioctls(struct file *filp, unsigned int cmd, void *arg)
- 			ivtv_reset_ir_gpio(itv);
- 		}
- 		if (val & 0x02) {
--			itv->video_dec_func(itv, cmd, 0);
-+			itv->video_dec_func(itv, cmd, NULL);
- 		}
- 		break;
- 	}
-@@ -703,8 +713,12 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void
- {
- 	struct ivtv_open_id *id = NULL;
- 	u32 data[CX2341X_MBOX_MAX_DATA];
-+	int streamtype = 0;
- 
--	if (filp) id = (struct ivtv_open_id *)filp->private_data;
-+	if (filp) {
-+		id = (struct ivtv_open_id *)filp->private_data;
-+		streamtype = id->type;
++
++static void pvr2_hdw_state_log_state(struct pvr2_hdw *hdw)
++{
++	char buf[128];
++	unsigned int idx,ccnt;
++
++	for (idx = 0; ; idx++) {
++		ccnt = pvr2_hdw_report_unlocked(hdw,idx,buf,sizeof(buf));
++		if (!ccnt) break;
++		printk(KERN_INFO "%s %.*s\n",hdw->name,ccnt,buf);
 +	}
- 
- 	switch (cmd) {
- 	case VIDIOC_G_PRIORITY:
-@@ -822,6 +836,11 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void
- 			cropcap->bounds.height = itv->is_50hz ? 576 : 480;
- 			cropcap->pixelaspect.numerator = itv->is_50hz ? 59 : 10;
- 			cropcap->pixelaspect.denominator = itv->is_50hz ? 54 : 11;
-+		} else if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) {
-+			cropcap->bounds.width = itv->yuv_info.osd_full_w;
-+			cropcap->bounds.height = itv->yuv_info.osd_full_h;
-+			cropcap->pixelaspect.numerator = itv->is_out_50hz ? 59 : 10;
-+			cropcap->pixelaspect.denominator = itv->is_out_50hz ? 54 : 11;
- 		} else {
- 			cropcap->bounds.height = itv->is_out_50hz ? 576 : 480;
- 			cropcap->pixelaspect.numerator = itv->is_out_50hz ? 59 : 10;
-@@ -836,10 +855,15 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void
- 
- 		if (crop->type == V4L2_BUF_TYPE_VIDEO_OUTPUT &&
- 		    (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) {
--			if (!ivtv_vapi(itv, CX2341X_OSD_SET_FRAMEBUFFER_WINDOW, 4,
--				 crop->c.width, crop->c.height, crop->c.left, crop->c.top)) {
--				itv->main_rect = crop->c;
-+			if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) {
-+				itv->yuv_info.main_rect = crop->c;
- 				return 0;
-+			} else {
-+				if (!ivtv_vapi(itv, CX2341X_OSD_SET_FRAMEBUFFER_WINDOW, 4,
-+					crop->c.width, crop->c.height, crop->c.left, crop->c.top)) {
-+					itv->main_rect = crop->c;
-+					return 0;
-+				}
- 			}
- 			return -EINVAL;
- 		}
-@@ -853,7 +877,10 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void
- 
- 		if (crop->type == V4L2_BUF_TYPE_VIDEO_OUTPUT &&
- 		    (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) {
--			crop->c = itv->main_rect;
-+			if (streamtype == IVTV_DEC_STREAM_TYPE_YUV)
-+				crop->c = itv->yuv_info.main_rect;
-+			else
-+				crop->c = itv->main_rect;
- 			return 0;
- 		}
- 		if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-@@ -864,7 +891,7 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void
- 	case VIDIOC_ENUM_FMT: {
- 		static struct v4l2_fmtdesc formats[] = {
- 			{ 0, 0, 0,
--			  "HM12 (YUV 4:1:1)", V4L2_PIX_FMT_HM12,
-+			  "HM12 (YUV 4:2:0)", V4L2_PIX_FMT_HM12,
- 			  { 0, 0, 0, 0 }
- 			},
- 			{ 1, 0, V4L2_FMT_FLAG_COMPRESSED,
-@@ -1043,6 +1070,12 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void
- 			itv->main_rect.height = itv->params.height;
- 			ivtv_vapi(itv, CX2341X_OSD_SET_FRAMEBUFFER_WINDOW, 4,
- 				720, itv->main_rect.height, 0, 0);
-+			itv->yuv_info.main_rect = itv->main_rect;
-+			if (!itv->osd_info) {
-+				itv->yuv_info.osd_full_w = 720;
-+				itv->yuv_info.osd_full_h =
-+						itv->is_out_50hz ? 576 : 480;
-+			}
- 		}
- 		break;
- 	}
-diff --git a/drivers/media/video/ivtv/ivtv-irq.c b/drivers/media/video/ivtv/ivtv-irq.c
-index fd1688e..65604dd 100644
---- a/drivers/media/video/ivtv/ivtv-irq.c
-+++ b/drivers/media/video/ivtv/ivtv-irq.c
-@@ -204,7 +204,7 @@ static int stream_enc_dma_append(struct ivtv_stream *s, u32 data[CX2341X_MBOX_MA
- 		s->sg_pending[idx].dst = buf->dma_handle;
- 		s->sg_pending[idx].src = offset;
- 		s->sg_pending[idx].size = s->buf_size;
--		buf->bytesused = (size < s->buf_size) ? size : s->buf_size;
-+		buf->bytesused = min(size, s->buf_size);
- 		buf->dma_xfer_cnt = s->dma_xfer_cnt;
- 
- 		s->q_predma.bytesused += buf->bytesused;
-@@ -302,8 +302,11 @@ static void dma_post(struct ivtv_stream *s)
- void ivtv_dma_stream_dec_prepare(struct ivtv_stream *s, u32 offset, int lock)
- {
- 	struct ivtv *itv = s->itv;
-+	struct yuv_playback_info *yi = &itv->yuv_info;
-+	u8 frame = yi->draw_frame;
-+	struct yuv_frame_info *f = &yi->new_frame_info[frame];
- 	struct ivtv_buffer *buf;
--	u32 y_size = itv->params.height * itv->params.width;
-+	u32 y_size = 720 * ((f->src_h + 31) & ~31);
- 	u32 uv_offset = offset + IVTV_YUV_BUFFER_UV_OFFSET;
- 	int y_done = 0;
- 	int bytes_written = 0;
-@@ -311,17 +314,42 @@ void ivtv_dma_stream_dec_prepare(struct ivtv_stream *s, u32 offset, int lock)
- 	int idx = 0;
- 
- 	IVTV_DEBUG_HI_DMA("DEC PREPARE DMA %s: %08x %08x\n", s->name, s->q_predma.bytesused, offset);
++}
 +
-+	/* Insert buffer block for YUV if needed */
-+	if (s->type == IVTV_DEC_STREAM_TYPE_YUV && f->offset_y) {
-+		if (yi->blanking_dmaptr) {
-+			s->sg_pending[idx].src = yi->blanking_dmaptr;
-+			s->sg_pending[idx].dst = offset;
-+			s->sg_pending[idx].size = 720 * 16;
-+		}
-+		offset += 720 * 16;
-+		idx++;
++
++/* Evaluate and update the driver's current state, taking various actions
++   as appropriate for the update. */
++static int pvr2_hdw_state_eval(struct pvr2_hdw *hdw)
++{
++	unsigned int st;
++	int state_updated = 0;
++	int callback_flag = 0;
++
++	pvr2_trace(PVR2_TRACE_STBITS,
++		   "Drive state check START");
++	if (pvrusb2_debug & PVR2_TRACE_STBITS) {
++		pvr2_hdw_state_log_state(hdw);
 +	}
 +
- 	list_for_each_entry(buf, &s->q_predma.list, list) {
- 		/* YUV UV Offset from Y Buffer */
--		if (s->type == IVTV_DEC_STREAM_TYPE_YUV && !y_done && bytes_written >= y_size) {
-+		if (s->type == IVTV_DEC_STREAM_TYPE_YUV && !y_done &&
-+				(bytes_written + buf->bytesused) >= y_size) {
-+			s->sg_pending[idx].src = buf->dma_handle;
-+			s->sg_pending[idx].dst = offset;
-+			s->sg_pending[idx].size = y_size - bytes_written;
- 			offset = uv_offset;
-+			if (s->sg_pending[idx].size != buf->bytesused) {
-+				idx++;
-+				s->sg_pending[idx].src =
-+				  buf->dma_handle + s->sg_pending[idx - 1].size;
-+				s->sg_pending[idx].dst = offset;
-+				s->sg_pending[idx].size =
-+				   buf->bytesused - s->sg_pending[idx - 1].size;
-+				offset += s->sg_pending[idx].size;
-+			}
- 			y_done = 1;
-+		} else {
-+			s->sg_pending[idx].src = buf->dma_handle;
-+			s->sg_pending[idx].dst = offset;
-+			s->sg_pending[idx].size = buf->bytesused;
-+			offset += buf->bytesused;
- 		}
--		s->sg_pending[idx].src = buf->dma_handle;
--		s->sg_pending[idx].dst = offset;
--		s->sg_pending[idx].size = buf->bytesused;
--
--		offset += buf->bytesused;
- 		bytes_written += buf->bytesused;
- 
- 		/* Sync SG buffers */
-@@ -408,7 +436,7 @@ static void ivtv_dma_enc_start(struct ivtv_stream *s)
- 		s_vbi->sg_pending_size = 0;
- 		s_vbi->dma_xfer_cnt++;
- 		set_bit(IVTV_F_S_DMA_HAS_VBI, &s->s_flags);
--		IVTV_DEBUG_HI_DMA("include DMA for %s\n", s->name);
-+		IVTV_DEBUG_HI_DMA("include DMA for %s\n", s_vbi->name);
- 	}
- 
- 	s->dma_xfer_cnt++;
-@@ -700,12 +728,15 @@ static void ivtv_irq_dec_data_req(struct ivtv *itv)
- 	ivtv_api_get_data(&itv->dec_mbox, IVTV_MBOX_DMA, data);
- 
- 	if (test_bit(IVTV_F_I_DEC_YUV, &itv->i_flags)) {
--		itv->dma_data_req_size = itv->params.width * itv->params.height * 3 / 2;
--		itv->dma_data_req_offset = data[1] ? data[1] : yuv_offset[0];
-+		itv->dma_data_req_size =
-+				 1080 * ((itv->yuv_info.v4l2_src_h + 31) & ~31);
-+		itv->dma_data_req_offset = data[1];
-+		if (atomic_read(&itv->yuv_info.next_dma_frame) >= 0)
-+			ivtv_yuv_frame_complete(itv);
- 		s = &itv->streams[IVTV_DEC_STREAM_TYPE_YUV];
- 	}
- 	else {
--		itv->dma_data_req_size = data[2] >= 0x10000 ? 0x10000 : data[2];
-+		itv->dma_data_req_size = min_t(u32, data[2], 0x10000);
- 		itv->dma_data_req_offset = data[1];
- 		s = &itv->streams[IVTV_DEC_STREAM_TYPE_MPG];
- 	}
-@@ -715,6 +746,8 @@ static void ivtv_irq_dec_data_req(struct ivtv *itv)
- 		set_bit(IVTV_F_S_NEEDS_DATA, &s->s_flags);
- 	}
- 	else {
-+		if (test_bit(IVTV_F_I_DEC_YUV, &itv->i_flags))
-+			ivtv_yuv_setup_stream_frame(itv);
- 		clear_bit(IVTV_F_S_NEEDS_DATA, &s->s_flags);
- 		ivtv_queue_move(s, &s->q_full, NULL, &s->q_predma, itv->dma_data_req_size);
- 		ivtv_dma_stream_dec_prepare(s, itv->dma_data_req_offset + IVTV_DECODER_OFFSET, 0);
-@@ -731,24 +764,26 @@ static void ivtv_irq_vsync(struct ivtv *itv)
- 	 * one vsync per frame.
- 	 */
- 	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);
-+	struct yuv_frame_info *f = &yi->new_frame_info[last_dma_frame];
- 
- 	if (0) IVTV_DEBUG_IRQ("DEC VSYNC\n");
- 
--	if (((frame ^ itv->yuv_info.sync_field[last_dma_frame]) == 0 &&
--		((itv->last_vsync_field & 1) ^ itv->yuv_info.sync_field[last_dma_frame])) ||
--			(frame != (itv->last_vsync_field & 1) && !itv->yuv_info.frame_interlaced)) {
-+	if (((frame ^ f->sync_field) == 0 &&
-+		((itv->last_vsync_field & 1) ^ f->sync_field)) ||
-+			(frame != (itv->last_vsync_field & 1) && !f->interlaced)) {
- 		int next_dma_frame = last_dma_frame;
- 
--		if (!(itv->yuv_info.frame_interlaced && itv->yuv_info.field_delay[next_dma_frame] && itv->yuv_info.fields_lapsed < 1)) {
--			if (next_dma_frame >= 0 && next_dma_frame != atomic_read(&itv->yuv_info.next_fill_frame)) {
-+		if (!(f->interlaced && f->delay && yi->fields_lapsed < 1)) {
-+			if (next_dma_frame >= 0 && next_dma_frame != atomic_read(&yi->next_fill_frame)) {
- 				write_reg(yuv_offset[next_dma_frame] >> 4, 0x82c);
- 				write_reg((yuv_offset[next_dma_frame] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x830);
- 				write_reg(yuv_offset[next_dma_frame] >> 4, 0x834);
- 				write_reg((yuv_offset[next_dma_frame] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x838);
--				next_dma_frame = (next_dma_frame + 1) & 0x3;
--				atomic_set(&itv->yuv_info.next_dma_frame, next_dma_frame);
--				itv->yuv_info.fields_lapsed = -1;
-+				next_dma_frame = (next_dma_frame + 1) % IVTV_YUV_BUFFERS;
-+				atomic_set(&yi->next_dma_frame, next_dma_frame);
-+				yi->fields_lapsed = -1;
- 			}
- 		}
- 	}
-@@ -781,20 +816,22 @@ static void ivtv_irq_vsync(struct ivtv *itv)
- 		}
- 
- 		/* Check if we need to update the yuv registers */
--		if ((itv->yuv_info.yuv_forced_update || itv->yuv_info.new_frame_info[last_dma_frame].update) && last_dma_frame != -1) {
--			if (!itv->yuv_info.new_frame_info[last_dma_frame].update)
--				last_dma_frame = (last_dma_frame - 1) & 3;
--
--			if (itv->yuv_info.new_frame_info[last_dma_frame].src_w) {
--				itv->yuv_info.update_frame = last_dma_frame;
--				itv->yuv_info.new_frame_info[last_dma_frame].update = 0;
--				itv->yuv_info.yuv_forced_update = 0;
-+		if ((yi->yuv_forced_update || f->update) && last_dma_frame != -1) {
-+			if (!f->update) {
-+				last_dma_frame = (u8)(last_dma_frame - 1) % IVTV_YUV_BUFFERS;
-+				f = &yi->new_frame_info[last_dma_frame];
-+			}
++	/* Process all state and get back over disposition */
++	state_updated = pvr2_hdw_state_update(hdw);
 +
-+			if (f->src_w) {
-+				yi->update_frame = last_dma_frame;
-+				f->update = 0;
-+				yi->yuv_forced_update = 0;
- 				set_bit(IVTV_F_I_WORK_HANDLER_YUV, &itv->i_flags);
- 				set_bit(IVTV_F_I_HAVE_WORK, &itv->i_flags);
- 			}
- 		}
- 
--		itv->yuv_info.fields_lapsed ++;
-+		yi->fields_lapsed++;
- 	}
- }
- 
-diff --git a/drivers/media/video/ivtv/ivtv-mailbox.c b/drivers/media/video/ivtv/ivtv-mailbox.c
-index b05436d..13a6c37 100644
---- a/drivers/media/video/ivtv/ivtv-mailbox.c
-+++ b/drivers/media/video/ivtv/ivtv-mailbox.c
-@@ -333,7 +333,7 @@ int ivtv_api(struct ivtv *itv, int cmd, int args, u32 data[])
- 	return (res == -EBUSY) ? ivtv_api_call(itv, cmd, args, data) : res;
- }
- 
--int ivtv_api_func(void *priv, int cmd, int in, int out, u32 data[CX2341X_MBOX_MAX_DATA])
-+int ivtv_api_func(void *priv, u32 cmd, int in, int out, u32 data[CX2341X_MBOX_MAX_DATA])
++	/* Update master state based upon all other states. */
++	if (!hdw->flag_ok) {
++		st = PVR2_STATE_DEAD;
++	} else if (hdw->fw1_state != FW1_STATE_OK) {
++		st = PVR2_STATE_COLD;
++	} else if (!hdw->state_encoder_ok) {
++		st = PVR2_STATE_WARM;
++	} else if (hdw->flag_tripped || hdw->flag_decoder_missed) {
++		st = PVR2_STATE_ERROR;
++	} else if (hdw->state_encoder_run &&
++		   hdw->state_decoder_run &&
++		   hdw->state_usbstream_run) {
++		st = PVR2_STATE_RUN;
++	} else {
++		st = PVR2_STATE_READY;
++	}
++	if (hdw->master_state != st) {
++		pvr2_trace(PVR2_TRACE_STATE,
++			   "Device state change from %s to %s",
++			   pvr2_get_state_name(hdw->master_state),
++			   pvr2_get_state_name(st));
++		hdw->master_state = st;
++		state_updated = !0;
++		callback_flag = !0;
++	}
++	if (state_updated) {
++		/* Trigger anyone waiting on any state changes here. */
++		wake_up(&hdw->state_wait_data);
++	}
++
++	if (pvrusb2_debug & PVR2_TRACE_STBITS) {
++		pvr2_hdw_state_log_state(hdw);
++	}
++	pvr2_trace(PVR2_TRACE_STBITS,
++		   "Drive state check DONE callback=%d",callback_flag);
++
++	return callback_flag;
++}
++
++
++/* Cause kernel thread to check / update driver state */
++static void pvr2_hdw_state_sched(struct pvr2_hdw *hdw)
++{
++	if (hdw->state_stale) return;
++	hdw->state_stale = !0;
++	trace_stbit("state_stale",hdw->state_stale);
++	queue_work(hdw->workqueue,&hdw->workpoll);
++}
++
++
++void pvr2_hdw_get_debug_info_unlocked(const struct pvr2_hdw *hdw,
++				      struct pvr2_hdw_debug_info *ptr)
  {
- 	return ivtv_api(priv, cmd, in, data);
+ 	ptr->big_lock_held = hdw->big_lock_held;
+ 	ptr->ctl_lock_held = hdw->ctl_lock_held;
+-	ptr->flag_ok = hdw->flag_ok;
+ 	ptr->flag_disconnected = hdw->flag_disconnected;
+ 	ptr->flag_init_ok = hdw->flag_init_ok;
+-	ptr->flag_streaming_enabled = hdw->flag_streaming_enabled;
+-	ptr->subsys_flags = hdw->subsys_enabled_mask;
++	ptr->flag_ok = hdw->flag_ok;
++	ptr->fw1_state = hdw->fw1_state;
++	ptr->flag_decoder_missed = hdw->flag_decoder_missed;
++	ptr->flag_tripped = hdw->flag_tripped;
++	ptr->state_encoder_ok = hdw->state_encoder_ok;
++	ptr->state_encoder_run = hdw->state_encoder_run;
++	ptr->state_decoder_run = hdw->state_decoder_run;
++	ptr->state_usbstream_run = hdw->state_usbstream_run;
++	ptr->state_decoder_quiescent = hdw->state_decoder_quiescent;
++	ptr->state_pipeline_config = hdw->state_pipeline_config;
++	ptr->state_pipeline_req = hdw->state_pipeline_req;
++	ptr->state_pipeline_pause = hdw->state_pipeline_pause;
++	ptr->state_pipeline_idle = hdw->state_pipeline_idle;
+ 	ptr->cmd_debug_state = hdw->cmd_debug_state;
+ 	ptr->cmd_code = hdw->cmd_debug_code;
+ 	ptr->cmd_debug_write_len = hdw->cmd_debug_write_len;
+@@ -3381,6 +3689,15 @@ void pvr2_hdw_get_debug_info(const struct pvr2_hdw *hdw,
  }
-diff --git a/drivers/media/video/ivtv/ivtv-mailbox.h b/drivers/media/video/ivtv/ivtv-mailbox.h
-index 71a54ee..6ef1209 100644
---- a/drivers/media/video/ivtv/ivtv-mailbox.h
-+++ b/drivers/media/video/ivtv/ivtv-mailbox.h
-@@ -28,6 +28,6 @@ void ivtv_api_get_data(struct ivtv_mailbox_data *mbox, int mb, u32 data[]);
- int ivtv_api(struct ivtv *itv, int cmd, int args, u32 data[]);
- int ivtv_vapi_result(struct ivtv *itv, u32 data[CX2341X_MBOX_MAX_DATA], int cmd, int args, ...);
- int ivtv_vapi(struct ivtv *itv, int cmd, int args, ...);
--int ivtv_api_func(void *priv, int cmd, int in, int out, u32 data[CX2341X_MBOX_MAX_DATA]);
-+int ivtv_api_func(void *priv, u32 cmd, int in, int out, u32 data[CX2341X_MBOX_MAX_DATA]);
- 
- #endif
-diff --git a/drivers/media/video/ivtv/ivtv-routing.c b/drivers/media/video/ivtv/ivtv-routing.c
-index 398bd33..0556491 100644
---- a/drivers/media/video/ivtv/ivtv-routing.c
-+++ b/drivers/media/video/ivtv/ivtv-routing.c
-@@ -25,6 +25,7 @@
- #include "ivtv-routing.h"
  
- #include <media/msp3400.h>
-+#include <media/m52790.h>
- #include <media/upd64031a.h>
- #include <media/upd64083.h>
  
-@@ -32,28 +33,26 @@
-    settings. */
- void ivtv_audio_set_io(struct ivtv *itv)
++void pvr2_hdw_get_debug_info_locked(struct pvr2_hdw *hdw,
++				    struct pvr2_hdw_debug_info *ptr)
++{
++	LOCK_TAKE(hdw->ctl_lock); do {
++		pvr2_hdw_get_debug_info_unlocked(hdw,ptr);
++	} while(0); LOCK_GIVE(hdw->ctl_lock);
++}
++
++
+ int pvr2_hdw_gpio_get_dir(struct pvr2_hdw *hdw,u32 *dp)
  {
-+	const struct ivtv_card_audio_input *in;
- 	struct v4l2_routing route;
--	u32 audio_input;
--	int mux_input;
- 
- 	/* Determine which input to use */
--	if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags)) {
--		audio_input = itv->card->radio_input.audio_input;
--		mux_input = itv->card->radio_input.muxer_input;
--	} else {
--		audio_input = itv->card->audio_inputs[itv->audio_input].audio_input;
--		mux_input = itv->card->audio_inputs[itv->audio_input].muxer_input;
--	}
-+	if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags))
-+		in = &itv->card->radio_input;
-+	else
-+		in = &itv->card->audio_inputs[itv->audio_input];
- 
- 	/* handle muxer chips */
--	route.input = mux_input;
-+	route.input = in->muxer_input;
- 	route.output = 0;
-+	if (itv->card->hw_muxer & IVTV_HW_M52790)
-+		route.output = M52790_OUT_STEREO;
- 	ivtv_i2c_hw(itv, itv->card->hw_muxer, VIDIOC_INT_S_AUDIO_ROUTING, &route);
- 
--	route.input = audio_input;
--	if (itv->card->hw_audio & IVTV_HW_MSP34XX) {
-+	route.input = in->audio_input;
-+	route.output = 0;
-+	if (itv->card->hw_audio & IVTV_HW_MSP34XX)
- 		route.output = MSP_OUTPUT(MSP_SC_IN_DSP_SCART1);
--	}
- 	ivtv_i2c_hw(itv, itv->card->hw_audio, VIDIOC_INT_S_AUDIO_ROUTING, &route);
- }
- 
-diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c
-index 74fb0e0..24d98ec 100644
---- a/drivers/media/video/ivtv/ivtv-streams.c
-+++ b/drivers/media/video/ivtv/ivtv-streams.c
-@@ -43,7 +43,7 @@
- #include "ivtv-cards.h"
- #include "ivtv-streams.h"
+ 	return pvr2_read_register(hdw,PVR2_GPIO_DIR,dp);
+diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.h b/drivers/media/video/pvrusb2/pvrusb2-hdw.h
+index e2f9d5e..3ad7a13 100644
+--- a/drivers/media/video/pvrusb2/pvrusb2-hdw.h
++++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.h
+@@ -44,27 +44,6 @@
+ #define PVR2_CVAL_INPUT_COMPOSITE 2
+ #define PVR2_CVAL_INPUT_RADIO 3
  
--static struct file_operations ivtv_v4l2_enc_fops = {
-+static const struct file_operations ivtv_v4l2_enc_fops = {
-       .owner = THIS_MODULE,
-       .read = ivtv_v4l2_read,
-       .write = ivtv_v4l2_write,
-@@ -53,7 +53,7 @@ static struct file_operations ivtv_v4l2_enc_fops = {
-       .poll = ivtv_v4l2_enc_poll,
+-/* Subsystem definitions - these are various pieces that can be
+-   independently stopped / started.  Usually you don't want to mess with
+-   this directly (let the driver handle things itself), but it is useful
+-   for debugging. */
+-#define PVR2_SUBSYS_B_ENC_FIRMWARE        0
+-#define PVR2_SUBSYS_B_ENC_CFG             1
+-#define PVR2_SUBSYS_B_DIGITIZER_RUN       2
+-#define PVR2_SUBSYS_B_USBSTREAM_RUN       3
+-#define PVR2_SUBSYS_B_ENC_RUN             4
+-
+-#define PVR2_SUBSYS_CFG_ALL ( \
+-	(1 << PVR2_SUBSYS_B_ENC_FIRMWARE) | \
+-	(1 << PVR2_SUBSYS_B_ENC_CFG) )
+-#define PVR2_SUBSYS_RUN_ALL ( \
+-	(1 << PVR2_SUBSYS_B_DIGITIZER_RUN) | \
+-	(1 << PVR2_SUBSYS_B_USBSTREAM_RUN) | \
+-	(1 << PVR2_SUBSYS_B_ENC_RUN) )
+-#define PVR2_SUBSYS_ALL ( \
+-	PVR2_SUBSYS_CFG_ALL | \
+-	PVR2_SUBSYS_RUN_ALL )
+-
+ enum pvr2_config {
+ 	pvr2_config_empty,    /* No configuration */
+ 	pvr2_config_mpeg,     /* Encoded / compressed video */
+@@ -79,8 +58,41 @@ enum pvr2_v4l_type {
+ 	pvr2_v4l_type_radio,
  };
  
--static struct file_operations ivtv_v4l2_dec_fops = {
-+static const struct file_operations ivtv_v4l2_dec_fops = {
-       .owner = THIS_MODULE,
-       .read = ivtv_v4l2_read,
-       .write = ivtv_v4l2_write,
-@@ -572,10 +572,10 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s)
- 		clear_bit(IVTV_F_I_EOS, &itv->i_flags);
- 
- 		/* Initialize Digitizer for Capture */
--		itv->video_dec_func(itv, VIDIOC_STREAMOFF, 0);
-+		itv->video_dec_func(itv, VIDIOC_STREAMOFF, NULL);
- 		ivtv_msleep_timeout(300, 1);
- 		ivtv_vapi(itv, CX2341X_ENC_INITIALIZE_INPUT, 0);
--		itv->video_dec_func(itv, VIDIOC_STREAMON, 0);
-+		itv->video_dec_func(itv, VIDIOC_STREAMON, NULL);
- 	}
++/* Major states that we can be in:
++ *
++ *  DEAD - Device is in an unusable state and cannot be recovered.  This
++ *  can happen if we completely lose the ability to communicate with it
++ *  (but it might still on the bus).  In this state there's nothing we can
++ *  do; it must be replugged in order to recover.
++ *
++ *  COLD - Device is in an unusuable state, needs microcontroller firmware.
++ *
++ *  WARM - We can communicate with the device and the proper
++ *  microcontroller firmware is running, but other device initialization is
++ *  still needed (e.g. encoder firmware).
++ *
++ *  ERROR - A problem prevents capture operation (e.g. encoder firmware
++ *  missing).
++ *
++ *  READY - Device is operational, but not streaming.
++ *
++ *  RUN - Device is streaming.
++ *
++ */
++#define PVR2_STATE_NONE 0
++#define PVR2_STATE_DEAD 1
++#define PVR2_STATE_COLD 2
++#define PVR2_STATE_WARM 3
++#define PVR2_STATE_ERROR 4
++#define PVR2_STATE_READY 5
++#define PVR2_STATE_RUN 6
++
++/* Translate configuration enum to a string label */
+ const char *pvr2_config_get_name(enum pvr2_config);
  
- 	/* begin_capture */
-@@ -661,27 +661,12 @@ int ivtv_start_v4l2_decode_stream(struct ivtv_stream *s, int gop_offset)
++/* Translate a master state enum to a string label */
++const char *pvr2_hdw_get_state_name(unsigned int);
++
+ struct pvr2_hdw;
  
- 	IVTV_DEBUG_INFO("Starting decode stream %s (gop_offset %d)\n", s->name, gop_offset);
+ /* Create and return a structure for interacting with the underlying
+@@ -88,28 +100,13 @@ struct pvr2_hdw;
+ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
+ 				 const struct usb_device_id *devid);
  
--	/* Clear Streamoff */
--	if (s->type == IVTV_DEC_STREAM_TYPE_YUV) {
--		/* Initialize Decoder */
--		/* Reprogram Decoder YUV Buffers for YUV */
--		write_reg(yuv_offset[0] >> 4, 0x82c);
--		write_reg((yuv_offset[0] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x830);
--		write_reg(yuv_offset[0] >> 4, 0x834);
--		write_reg((yuv_offset[0] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x838);
+-/* Poll for background activity (if any) */
+-void pvr2_hdw_poll(struct pvr2_hdw *);
 -
--		write_reg_sync(0x00000000 | (0x0c << 16) | (0x0b << 8), 0x2d24);
+-/* Trigger a poll to take place later at a convenient time */
+-void pvr2_hdw_poll_trigger_unlocked(struct pvr2_hdw *);
 -
--		write_reg_sync(0x00108080, 0x2898);
--		/* Enable YUV decoder output */
--		write_reg_sync(0x01, IVTV_REG_VDM);
--	}
+-/* Register a callback used to trigger a future poll */
+-void pvr2_hdw_setup_poll_trigger(struct pvr2_hdw *,
+-				 void (*func)(void *),
+-				 void *data);
 -
- 	ivtv_setup_v4l2_decode_stream(s);
+ /* Destroy hardware interaction structure */
+ void pvr2_hdw_destroy(struct pvr2_hdw *);
  
- 	/* set dma size to 65536 bytes */
- 	ivtv_vapi(itv, CX2341X_DEC_SET_DMA_BLOCK_SIZE, 1, 65536);
+-/* Set up the structure and attempt to put the device into a usable state.
+-   This can be a time-consuming operation, which is why it is not done
+-   internally as part of the create() step.  Return value is exactly the
+-   same as pvr2_hdw_init_ok(). */
+-int pvr2_hdw_setup(struct pvr2_hdw *);
+-
+-/* Initialization succeeded */
+-int pvr2_hdw_init_ok(struct pvr2_hdw *);
++/* Register a function to be called whenever the master state changes. */
++void pvr2_hdw_set_state_callback(struct pvr2_hdw *,
++				 void (*callback_func)(void *),
++				 void *callback_data);
  
-+	/* Clear Streamoff */
- 	clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags);
+ /* Return true if in the ready (normal) state */
+ int pvr2_hdw_dev_ok(struct pvr2_hdw *);
+@@ -161,12 +158,21 @@ int pvr2_hdw_get_tuner_status(struct pvr2_hdw *,struct v4l2_tuner *);
+ /* Query device and see if it thinks it is on a high-speed USB link */
+ int pvr2_hdw_is_hsm(struct pvr2_hdw *);
  
- 	/* Zero out decoder counters */
-diff --git a/drivers/media/video/ivtv/ivtv-version.h b/drivers/media/video/ivtv/ivtv-version.h
-index d050de2..0f1d4cc 100644
---- a/drivers/media/video/ivtv/ivtv-version.h
-+++ b/drivers/media/video/ivtv/ivtv-version.h
-@@ -22,7 +22,7 @@
++/* Return a string token representative of the hardware type */
++const char *pvr2_hdw_get_type(struct pvr2_hdw *);
++
++/* Return a single line description of the hardware type */
++const char *pvr2_hdw_get_desc(struct pvr2_hdw *);
++
+ /* Turn streaming on/off */
+ int pvr2_hdw_set_streaming(struct pvr2_hdw *,int);
  
- #define IVTV_DRIVER_NAME "ivtv"
- #define IVTV_DRIVER_VERSION_MAJOR 1
--#define IVTV_DRIVER_VERSION_MINOR 1
-+#define IVTV_DRIVER_VERSION_MINOR 2
- #define IVTV_DRIVER_VERSION_PATCHLEVEL 0
+ /* Find out if streaming is on */
+ int pvr2_hdw_get_streaming(struct pvr2_hdw *);
  
- #define IVTV_VERSION __stringify(IVTV_DRIVER_VERSION_MAJOR) "." __stringify(IVTV_DRIVER_VERSION_MINOR) "." __stringify(IVTV_DRIVER_VERSION_PATCHLEVEL)
-diff --git a/drivers/media/video/ivtv/ivtv-yuv.c b/drivers/media/video/ivtv/ivtv-yuv.c
-index 9091c48..8518348 100644
---- a/drivers/media/video/ivtv/ivtv-yuv.c
-+++ b/drivers/media/video/ivtv/ivtv-yuv.c
-@@ -22,32 +22,37 @@
- #include "ivtv-udma.h"
- #include "ivtv-yuv.h"
++/* Retrieve driver overall state */
++int pvr2_hdw_get_state(struct pvr2_hdw *);
++
+ /* Configure the type of stream to generate */
+ int pvr2_hdw_set_stream_type(struct pvr2_hdw *, enum pvr2_config);
  
--const u32 yuv_offset[4] = {
--	IVTV_YUV_BUFFER_OFFSET,
--	IVTV_YUV_BUFFER_OFFSET_1,
--	IVTV_YUV_BUFFER_OFFSET_2,
--	IVTV_YUV_BUFFER_OFFSET_3
-+/* YUV buffer offsets */
-+const u32 yuv_offset[IVTV_YUV_BUFFERS] = {
-+	0x001a8600,
-+	0x00240400,
-+	0x002d8200,
-+	0x00370000,
-+	0x00029000,
-+	0x000C0E00,
-+	0x006B0400,
-+	0x00748200
- };
+@@ -177,26 +183,6 @@ struct pvr2_stream *pvr2_hdw_get_video_stream(struct pvr2_hdw *);
+ int pvr2_hdw_get_stdenum_value(struct pvr2_hdw *hdw,struct v4l2_standard *std,
+ 			       unsigned int idx);
  
- static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma,
--				 struct ivtv_dma_frame *args)
-+				  struct ivtv_dma_frame *args)
- {
- 	struct ivtv_dma_page_info y_dma;
- 	struct ivtv_dma_page_info uv_dma;
+-/* Enable / disable various pieces of hardware.  Items to change are
+-   identified by bit positions within msk, and new state for each item is
+-   identified by corresponding bit positions within val. */
+-void pvr2_hdw_subsys_bit_chg(struct pvr2_hdw *hdw,
+-			     unsigned long msk,unsigned long val);
 -
-+	struct yuv_playback_info *yi = &itv->yuv_info;
-+	u8 frame = yi->draw_frame;
-+	struct yuv_frame_info *f = &yi->new_frame_info[frame];
- 	int i;
- 	int y_pages, uv_pages;
+-/* Retrieve mask indicating which pieces of hardware are currently enabled
+-   / configured. */
+-unsigned long pvr2_hdw_subsys_get(struct pvr2_hdw *);
 -
- 	unsigned long y_buffer_offset, uv_buffer_offset;
- 	int y_decode_height, uv_decode_height, y_size;
--	int frame = atomic_read(&itv->yuv_info.next_fill_frame);
- 
- 	y_buffer_offset = IVTV_DECODER_OFFSET + yuv_offset[frame];
- 	uv_buffer_offset = y_buffer_offset + IVTV_YUV_BUFFER_UV_OFFSET;
- 
--	y_decode_height = uv_decode_height = args->src.height + args->src.top;
-+	y_decode_height = uv_decode_height = f->src_h + f->src_y;
- 
--	if (y_decode_height < 512-16)
-+	if (f->offset_y)
- 		y_buffer_offset += 720 * 16;
- 
- 	if (y_decode_height & 15)
-@@ -60,8 +65,9 @@ static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma,
- 
- 	/* Still in USE */
- 	if (dma->SG_length || dma->page_count) {
--		IVTV_DEBUG_WARN("prep_user_dma: SG_length %d page_count %d still full?\n",
--				dma->SG_length, dma->page_count);
-+		IVTV_DEBUG_WARN
-+		    ("prep_user_dma: SG_length %d page_count %d still full?\n",
-+		     dma->SG_length, dma->page_count);
- 		return -EBUSY;
- 	}
- 
-@@ -77,8 +83,9 @@ static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma,
- 	dma->page_count = y_dma.page_count + uv_dma.page_count;
- 
- 	if (y_pages + uv_pages != dma->page_count) {
--		IVTV_DEBUG_WARN("failed to map user pages, returned %d instead of %d\n",
--				y_pages + uv_pages, dma->page_count);
-+		IVTV_DEBUG_WARN
-+		    ("failed to map user pages, returned %d instead of %d\n",
-+		     y_pages + uv_pages, dma->page_count);
- 
- 		for (i = 0; i < dma->page_count; i++) {
- 			put_page(dma->map[i]);
-@@ -99,16 +106,14 @@ static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma,
- 	dma->SG_length = pci_map_sg(itv->dev, dma->SGlist, dma->page_count, PCI_DMA_TODEVICE);
- 
- 	/* Fill SG Array with new values */
--	ivtv_udma_fill_sg_array (dma, y_buffer_offset, uv_buffer_offset, y_size);
-+	ivtv_udma_fill_sg_array(dma, y_buffer_offset, uv_buffer_offset, y_size);
- 
- 	/* If we've offset the y plane, ensure top area is blanked */
--	if (args->src.height + args->src.top < 512-16) {
--		if (itv->yuv_info.blanking_dmaptr) {
--			dma->SGarray[dma->SG_length].size = cpu_to_le32(720*16);
--			dma->SGarray[dma->SG_length].src = cpu_to_le32(itv->yuv_info.blanking_dmaptr);
--			dma->SGarray[dma->SG_length].dst = cpu_to_le32(IVTV_DECODER_OFFSET + yuv_offset[frame]);
--			dma->SG_length++;
--		}
-+	if (f->offset_y && yi->blanking_dmaptr) {
-+		dma->SGarray[dma->SG_length].size = cpu_to_le32(720*16);
-+		dma->SGarray[dma->SG_length].src = cpu_to_le32(yi->blanking_dmaptr);
-+		dma->SGarray[dma->SG_length].dst = cpu_to_le32(IVTV_DECODER_OFFSET + yuv_offset[frame]);
-+		dma->SG_length++;
- 	}
- 
- 	/* Tag SG Array with Interrupt Bit */
-@@ -121,11 +126,11 @@ static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma,
- /* We rely on a table held in the firmware - Quick check. */
- int ivtv_yuv_filter_check(struct ivtv *itv)
- {
--	int i, offset_y, offset_uv;
-+	int i, y, uv;
- 
--	for (i=0, offset_y = 16, offset_uv = 4; i<16; i++, offset_y += 24, offset_uv += 12) {
--		if ((read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + offset_y) != i << 16) ||
--		    (read_dec(IVTV_YUV_VERTICAL_FILTER_OFFSET + offset_uv) != i << 16)) {
-+	for (i = 0, y = 16, uv = 4; i < 16; i++, y += 24, uv += 12) {
-+		if ((read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + y) != i << 16) ||
-+		    (read_dec(IVTV_YUV_VERTICAL_FILTER_OFFSET + uv) != i << 16)) {
- 			IVTV_WARN ("YUV filter table not found in firmware.\n");
- 			return -1;
- 		}
-@@ -135,69 +140,67 @@ int ivtv_yuv_filter_check(struct ivtv *itv)
- 
- static void ivtv_yuv_filter(struct ivtv *itv, int h_filter, int v_filter_1, int v_filter_2)
- {
--	int filter_index, filter_line;
-+	u32 i, line;
- 
- 	/* If any filter is -1, then don't update it */
- 	if (h_filter > -1) {
--		if (h_filter > 4) h_filter = 4;
--		filter_index = h_filter * 384;
--		filter_line = 0;
--		while (filter_line < 16) {
--			write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02804);
--			write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x0281c);
--			filter_index += 4;
--			write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02808);
--			write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02820);
--			filter_index += 4;
--			write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x0280c);
--			write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02824);
--			filter_index += 4;
--			write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02810);
--			write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02828);
--			filter_index += 4;
--			write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02814);
--			write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x0282c);
--			filter_index += 8;
-+		if (h_filter > 4)
-+			h_filter = 4;
-+		i = IVTV_YUV_HORIZONTAL_FILTER_OFFSET + (h_filter * 384);
-+		for (line = 0; line < 16; line++) {
-+			write_reg(read_dec(i), 0x02804);
-+			write_reg(read_dec(i), 0x0281c);
-+			i += 4;
-+			write_reg(read_dec(i), 0x02808);
-+			write_reg(read_dec(i), 0x02820);
-+			i += 4;
-+			write_reg(read_dec(i), 0x0280c);
-+			write_reg(read_dec(i), 0x02824);
-+			i += 4;
-+			write_reg(read_dec(i), 0x02810);
-+			write_reg(read_dec(i), 0x02828);
-+			i += 4;
-+			write_reg(read_dec(i), 0x02814);
-+			write_reg(read_dec(i), 0x0282c);
-+			i += 8;
- 			write_reg(0, 0x02818);
- 			write_reg(0, 0x02830);
--			filter_line ++;
- 		}
--		IVTV_DEBUG_YUV("h_filter -> %d\n",h_filter);
-+		IVTV_DEBUG_YUV("h_filter -> %d\n", h_filter);
- 	}
- 
- 	if (v_filter_1 > -1) {
--		if (v_filter_1 > 4) v_filter_1 = 4;
--		filter_index = v_filter_1 * 192;
--		filter_line = 0;
--		while (filter_line < 16) {
--			write_reg(read_dec(IVTV_YUV_VERTICAL_FILTER_OFFSET + filter_index), 0x02900);
--			filter_index += 4;
--			write_reg(read_dec(IVTV_YUV_VERTICAL_FILTER_OFFSET + filter_index), 0x02904);
--			filter_index += 8;
-+		if (v_filter_1 > 4)
-+			v_filter_1 = 4;
-+		i = IVTV_YUV_VERTICAL_FILTER_OFFSET + (v_filter_1 * 192);
-+		for (line = 0; line < 16; line++) {
-+			write_reg(read_dec(i), 0x02900);
-+			i += 4;
-+			write_reg(read_dec(i), 0x02904);
-+			i += 8;
- 			write_reg(0, 0x02908);
--			filter_line ++;
- 		}
--		IVTV_DEBUG_YUV("v_filter_1 -> %d\n",v_filter_1);
-+		IVTV_DEBUG_YUV("v_filter_1 -> %d\n", v_filter_1);
- 	}
- 
- 	if (v_filter_2 > -1) {
--		if (v_filter_2 > 4) v_filter_2 = 4;
--		filter_index = v_filter_2 * 192;
--		filter_line = 0;
--		while (filter_line < 16) {
--			write_reg(read_dec(IVTV_YUV_VERTICAL_FILTER_OFFSET + filter_index), 0x0290c);
--			filter_index += 4;
--			write_reg(read_dec(IVTV_YUV_VERTICAL_FILTER_OFFSET + filter_index), 0x02910);
--			filter_index += 8;
-+		if (v_filter_2 > 4)
-+			v_filter_2 = 4;
-+		i = IVTV_YUV_VERTICAL_FILTER_OFFSET + (v_filter_2 * 192);
-+		for (line = 0; line < 16; line++) {
-+			write_reg(read_dec(i), 0x0290c);
-+			i += 4;
-+			write_reg(read_dec(i), 0x02910);
-+			i += 8;
- 			write_reg(0, 0x02914);
--			filter_line ++;
- 		}
--		IVTV_DEBUG_YUV("v_filter_2 -> %d\n",v_filter_2);
-+		IVTV_DEBUG_YUV("v_filter_2 -> %d\n", v_filter_2);
- 	}
- }
- 
--static void ivtv_yuv_handle_horizontal(struct ivtv *itv, struct yuv_frame_info *window)
-+static void ivtv_yuv_handle_horizontal(struct ivtv *itv, struct yuv_frame_info *f)
- {
-+	struct yuv_playback_info *yi = &itv->yuv_info;
- 	u32 reg_2834, reg_2838, reg_283c;
- 	u32 reg_2844, reg_2854, reg_285c;
- 	u32 reg_2864, reg_2874, reg_2890;
-@@ -206,18 +209,19 @@ static void ivtv_yuv_handle_horizontal(struct ivtv *itv, struct yuv_frame_info *
- 	int h_filter;
- 	u32 master_width;
- 
--	IVTV_DEBUG_WARN( "Need to adjust to width %d src_w %d dst_w %d src_x %d dst_x %d\n",
--			 window->tru_w, window->src_w, window->dst_w,window->src_x, window->dst_x);
-+	IVTV_DEBUG_WARN
-+	    ("Adjust to width %d src_w %d dst_w %d src_x %d dst_x %d\n",
-+	     f->tru_w, f->src_w, f->dst_w, f->src_x, f->dst_x);
+-/* Adjust mask of what get shut down when streaming is stopped.  This is a
+-   debugging aid. */
+-void pvr2_hdw_subsys_stream_bit_chg(struct pvr2_hdw *hdw,
+-				    unsigned long msk,unsigned long val);
+-
+-/* Retrieve mask indicating which pieces of hardware are disabled when
+-   streaming is turned off. */
+-unsigned long pvr2_hdw_subsys_stream_get(struct pvr2_hdw *);
+-
+-
+ /* Enable / disable retrieval of CPU firmware or prom contents.  This must
+    be enabled before pvr2_hdw_cpufw_get() will function.  Note that doing
+    this may prevent the device from running (and leaving this mode may
+@@ -253,6 +239,9 @@ void pvr2_hdw_cpureset_assert(struct pvr2_hdw *,int);
+ /* Execute a USB-commanded device reset */
+ void pvr2_hdw_device_reset(struct pvr2_hdw *);
  
- 	/* How wide is the src image */
--	x_cutoff  = window->src_w + window->src_x;
-+	x_cutoff = f->src_w + f->src_x;
++/* Reset worker's error trapping circuit breaker */
++int pvr2_hdw_untrip(struct pvr2_hdw *);
++
+ /* Execute hard reset command (after this point it's likely that the
+    encoder will have to be reconfigured).  This also clears the "useless"
+    state. */
+@@ -275,11 +264,21 @@ int pvr2_hdw_gpio_chg_out(struct pvr2_hdw *hdw,u32 msk,u32 val);
+ struct pvr2_hdw_debug_info {
+ 	int big_lock_held;
+ 	int ctl_lock_held;
+-	int flag_ok;
+ 	int flag_disconnected;
+ 	int flag_init_ok;
+-	int flag_streaming_enabled;
+-	unsigned long subsys_flags;
++	int flag_ok;
++	int fw1_state;
++	int flag_decoder_missed;
++	int flag_tripped;
++	int state_encoder_ok;
++	int state_encoder_run;
++	int state_decoder_run;
++	int state_usbstream_run;
++	int state_decoder_quiescent;
++	int state_pipeline_config;
++	int state_pipeline_req;
++	int state_pipeline_pause;
++	int state_pipeline_idle;
+ 	int cmd_debug_state;
+ 	int cmd_debug_write_len;
+ 	int cmd_debug_read_len;
+@@ -295,8 +294,20 @@ struct pvr2_hdw_debug_info {
+    diagnosing lockups.  Note that this operation is completed without any
+    kind of locking and so it is not atomic and may yield inconsistent
+    results.  This is *purely* a debugging aid. */
+-void pvr2_hdw_get_debug_info(const struct pvr2_hdw *hdw,
+-			     struct pvr2_hdw_debug_info *);
++void pvr2_hdw_get_debug_info_unlocked(const struct pvr2_hdw *hdw,
++				      struct pvr2_hdw_debug_info *);
++
++/* Intrusively retrieve internal state info - this is useful for
++   diagnosing overall driver state.  This operation synchronizes against
++   the overall driver mutex - so if there are locking problems this will
++   likely hang!  This is *purely* a debugging aid. */
++void pvr2_hdw_get_debug_info_locked(struct pvr2_hdw *hdw,
++				    struct pvr2_hdw_debug_info *);
++
++/* Report out several lines of text that describes driver internal state.
++   Results are written into the passed-in buffer. */
++unsigned int pvr2_hdw_state_report(struct pvr2_hdw *hdw,
++				   char *buf_ptr,unsigned int buf_size);
  
- 	/* Set the display width */
--	reg_2834 = window->dst_w;
-+	reg_2834 = f->dst_w;
- 	reg_2838 = reg_2834;
+ /* Cause modules to log their state once */
+ void pvr2_hdw_trigger_module_log(struct pvr2_hdw *hdw);
+@@ -306,9 +317,6 @@ void pvr2_hdw_trigger_module_log(struct pvr2_hdw *hdw);
+    a debugging aid. */
+ int pvr2_upload_firmware2(struct pvr2_hdw *hdw);
  
- 	/* Set the display position */
--	reg_2890 = window->dst_x;
-+	reg_2890 = f->dst_x;
+-/* List of device types that we can match */
+-extern struct usb_device_id pvr2_device_table[];
+-
+ #endif /* __PVRUSB2_HDW_H */
  
- 	/* Index into the image horizontally */
- 	reg_2870 = 0;
-@@ -228,32 +232,31 @@ static void ivtv_yuv_handle_horizontal(struct ivtv *itv, struct yuv_frame_info *
- 	   Gradually adjust the offset to avoid the video 'snapping'
- 	   left/right if it gets dragged through this region.
- 	   Only do this if osd is full width. */
--	if (window->vis_w == 720) {
--		if ((window->tru_x - window->pan_x > -1) && (window->tru_x - window->pan_x <= 40) && (window->dst_w >= 680)){
--			reg_2870 = 10 - (window->tru_x - window->pan_x) / 4;
--		}
--		else if ((window->tru_x - window->pan_x < 0) && (window->tru_x - window->pan_x >= -20) && (window->dst_w >= 660)) {
--			reg_2870 = (10 + (window->tru_x - window->pan_x) / 2);
--		}
-+	if (f->vis_w == 720) {
-+		if ((f->tru_x - f->pan_x > -1) && (f->tru_x - f->pan_x <= 40) && (f->dst_w >= 680))
-+			reg_2870 = 10 - (f->tru_x - f->pan_x) / 4;
-+		else if ((f->tru_x - f->pan_x < 0) && (f->tru_x - f->pan_x >= -20) && (f->dst_w >= 660))
-+			reg_2870 = (10 + (f->tru_x - f->pan_x) / 2);
+ /*
+diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
+index c817c86..62867fa 100644
+--- a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
++++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
+@@ -895,7 +895,7 @@ static int pvr2_i2c_attach_inform(struct i2c_client *client)
+ 		list_add_tail(&cp->list,&hdw->i2c_clients);
+ 		hdw->i2c_pend_types |= PVR2_I2C_PEND_DETECT;
+ 	} while (0); mutex_unlock(&hdw->i2c_list_lock);
+-	if (fl) pvr2_hdw_poll_trigger_unlocked(hdw);
++	if (fl) queue_work(hdw->workqueue,&hdw->worki2csync);
+ 	return 0;
+ }
  
--		if (window->dst_w >= window->src_w)
-+		if (f->dst_w >= f->src_w)
- 			reg_2870 = reg_2870 << 16 | reg_2870;
- 		else
- 			reg_2870 = ((reg_2870 & ~1) << 15) | (reg_2870 & ~1);
+@@ -980,14 +980,16 @@ void pvr2_i2c_core_init(struct pvr2_hdw *hdw)
+ 		printk(KERN_INFO "%s: IR disabled\n",hdw->name);
+ 		hdw->i2c_func[0x18] = i2c_black_hole;
+ 	} else if (ir_mode[hdw->unit_number] == 1) {
+-		if (hdw->hdw_type == PVR2_HDW_TYPE_24XXX) {
++		if (hdw->hdw_desc->flag_has_hauppauge_custom_ir) {
+ 			hdw->i2c_func[0x18] = i2c_24xxx_ir;
+ 		}
+ 	}
+-	if (hdw->hdw_type == PVR2_HDW_TYPE_24XXX) {
+-		hdw->i2c_func[0x1b] = i2c_hack_wm8775;
++	if (hdw->hdw_desc->flag_has_cx25840) {
+ 		hdw->i2c_func[0x44] = i2c_hack_cx25840;
  	}
++	if (hdw->hdw_desc->flag_has_wm8775) {
++		hdw->i2c_func[0x1b] = i2c_hack_wm8775;
++	}
  
--	if (window->dst_w < window->src_w)
-+	if (f->dst_w < f->src_w)
- 		reg_2870 = 0x000d000e - reg_2870;
- 	else
- 		reg_2870 = 0x0012000e - reg_2870;
+ 	// Configure the adapter and set up everything else related to it.
+ 	memcpy(&hdw->i2c_adap,&pvr2_i2c_adap_template,sizeof(hdw->i2c_adap));
+diff --git a/drivers/media/video/pvrusb2/pvrusb2-main.c b/drivers/media/video/pvrusb2/pvrusb2-main.c
+index 11b3b2e..b63b226 100644
+--- a/drivers/media/video/pvrusb2/pvrusb2-main.c
++++ b/drivers/media/video/pvrusb2/pvrusb2-main.c
+@@ -28,6 +28,7 @@
+ #include <linux/videodev2.h>
  
- 	/* We're also using 2870 to shift the image left (src_x & negative dst_x) */
--	reg_2870_offset = (window->src_x*((window->dst_w << 21)/window->src_w))>>19;
-+	reg_2870_offset = (f->src_x * ((f->dst_w << 21) / f->src_w)) >> 19;
+ #include "pvrusb2-hdw.h"
++#include "pvrusb2-devattr.h"
+ #include "pvrusb2-context.h"
+ #include "pvrusb2-debug.h"
+ #include "pvrusb2-v4l2.h"
+@@ -148,11 +149,6 @@ static void __exit pvr_exit(void)
+ module_init(pvr_init);
+ module_exit(pvr_exit);
  
--	if (window->dst_w >= window->src_w) {
-+	if (f->dst_w >= f->src_w) {
- 		x_cutoff &= ~1;
--		master_width = (window->src_w * 0x00200000) / (window->dst_w);
--		if (master_width * window->dst_w != window->src_w * 0x00200000) master_width ++;
-+		master_width = (f->src_w * 0x00200000) / (f->dst_w);
-+		if (master_width * f->dst_w != f->src_w * 0x00200000)
-+			master_width++;
- 		reg_2834 = (reg_2834 << 16) | x_cutoff;
- 		reg_2838 = (reg_2838 << 16) | x_cutoff;
- 		reg_283c = master_width >> 2;
-@@ -264,17 +267,17 @@ static void ivtv_yuv_handle_horizontal(struct ivtv *itv, struct yuv_frame_info *
+-/* Mike Isely <mcisely at pobox.com> 11-Mar-2006: See pvrusb2-hdw.c for
+-   MODULE_DEVICE_TABLE().  We have to declare that attribute there
+-   because that's where the device table actually is now and it seems
+-   that certain gcc configurations get angry if MODULE_DEVICE_TABLE()
+-   is used on what ends up being an external symbol. */
+ MODULE_AUTHOR(DRIVER_AUTHOR);
+ MODULE_DESCRIPTION(DRIVER_DESC);
+ MODULE_LICENSE("GPL");
+diff --git a/drivers/media/video/pvrusb2/pvrusb2-std.c b/drivers/media/video/pvrusb2/pvrusb2-std.c
+index 63e55bb..da30928 100644
+--- a/drivers/media/video/pvrusb2/pvrusb2-std.c
++++ b/drivers/media/video/pvrusb2/pvrusb2-std.c
+@@ -50,6 +50,10 @@ struct std_name {
+ 	 V4L2_STD_NTSC_M_KR| \
+ 	 V4L2_STD_NTSC_443)
  
- 		/* We also need to factor in the scaling
- 		   (src_w - dst_w) / (src_w / 4) */
--		if (window->dst_w > window->src_w)
--			reg_2870_base = ((window->dst_w - window->src_w)<<16) / (window->src_w <<14);
-+		if (f->dst_w > f->src_w)
-+			reg_2870_base = ((f->dst_w - f->src_w)<<16) / (f->src_w <<14);
- 		else
- 			reg_2870_base = 0;
++#define CSTD_ATSC \
++	(V4L2_STD_ATSC_8_VSB| \
++	 V4L2_STD_ATSC_16_VSB)
++
+ #define CSTD_SECAM \
+ 	(V4L2_STD_SECAM_B| \
+ 	 V4L2_STD_SECAM_D| \
+@@ -82,6 +86,7 @@ static const struct std_name std_groups[] = {
+ 	{"PAL",CSTD_PAL},
+ 	{"NTSC",CSTD_NTSC},
+ 	{"SECAM",CSTD_SECAM},
++	{"ATSC",CSTD_ATSC},
+ };
  
- 		reg_2870 += (((reg_2870_offset << 14) & 0xFFFF0000) | reg_2870_offset >> 2) + (reg_2870_base << 17 | reg_2870_base);
- 		reg_2874 = 0;
--	}
--	else if (window->dst_w < window->src_w / 2) {
--		master_width = (window->src_w * 0x00080000) / window->dst_w;
--		if (master_width * window->dst_w != window->src_w * 0x00080000) master_width ++;
-+	} else if (f->dst_w < f->src_w / 2) {
-+		master_width = (f->src_w * 0x00080000) / f->dst_w;
-+		if (master_width * f->dst_w != f->src_w * 0x00080000)
-+			master_width++;
- 		reg_2834 = (reg_2834 << 16) | x_cutoff;
- 		reg_2838 = (reg_2838 << 16) | x_cutoff;
- 		reg_283c = master_width >> 2;
-@@ -282,13 +285,13 @@ static void ivtv_yuv_handle_horizontal(struct ivtv *itv, struct yuv_frame_info *
- 		reg_2854 = master_width;
- 		reg_285c = master_width >> 1;
- 		reg_2864 = master_width >> 1;
--		reg_2870 += (((reg_2870_offset << 15) & 0xFFFF0000) | reg_2870_offset);
--		reg_2870 += (5 - (((window->src_w + window->src_w / 2) - 1) / window->dst_w)) << 16;
-+		reg_2870 += ((reg_2870_offset << 15) & 0xFFFF0000) | reg_2870_offset;
-+		reg_2870 += (5 - (((f->src_w + f->src_w / 2) - 1) / f->dst_w)) << 16;
- 		reg_2874 = 0x00000012;
--	}
--	else {
--		master_width = (window->src_w * 0x00100000) / window->dst_w;
--		if (master_width * window->dst_w != window->src_w * 0x00100000) master_width ++;
-+	} else {
-+		master_width = (f->src_w * 0x00100000) / f->dst_w;
-+		if (master_width * f->dst_w != f->src_w * 0x00100000)
-+			master_width++;
- 		reg_2834 = (reg_2834 << 16) | x_cutoff;
- 		reg_2838 = (reg_2838 << 16) | x_cutoff;
- 		reg_283c = master_width >> 2;
-@@ -296,62 +299,70 @@ static void ivtv_yuv_handle_horizontal(struct ivtv *itv, struct yuv_frame_info *
- 		reg_2854 = master_width;
- 		reg_285c = master_width >> 1;
- 		reg_2864 = master_width >> 1;
--		reg_2870 += (((reg_2870_offset << 14) & 0xFFFF0000) | reg_2870_offset >> 1);
--		reg_2870 += (5 - (((window->src_w * 3) - 1) / window->dst_w)) << 16;
-+		reg_2870 += ((reg_2870_offset << 14) & 0xFFFF0000) | reg_2870_offset >> 1;
-+		reg_2870 += (5 - (((f->src_w * 3) - 1) / f->dst_w)) << 16;
- 		reg_2874 = 0x00000001;
- 	}
+ /* Mapping of standard bits to modulation system */
+@@ -104,6 +109,8 @@ static const struct std_name std_items[] = {
+ 	{"N",TSTD_N},
+ 	{"Nc",TSTD_Nc},
+ 	{"60",TSTD_60},
++	{"8VSB",V4L2_STD_ATSC_8_VSB},
++	{"16VSB",V4L2_STD_ATSC_16_VSB},
+ };
  
- 	/* Select the horizontal filter */
--	if (window->src_w == window->dst_w) {
-+	if (f->src_w == f->dst_w) {
- 		/* An exact size match uses filter 0 */
- 		h_filter = 0;
--	}
--	else {
-+	} else {
- 		/* Figure out which filter to use */
--		h_filter = ((window->src_w << 16) / window->dst_w) >> 15;
-+		h_filter = ((f->src_w << 16) / f->dst_w) >> 15;
- 		h_filter = (h_filter >> 1) + (h_filter & 1);
- 		/* Only an exact size match can use filter 0 */
--		if (h_filter == 0) h_filter = 1;
-+		h_filter += !h_filter;
- 	}
  
- 	write_reg(reg_2834, 0x02834);
- 	write_reg(reg_2838, 0x02838);
--	IVTV_DEBUG_YUV("Update reg 0x2834 %08x->%08x 0x2838 %08x->%08x\n",itv->yuv_info.reg_2834, reg_2834, itv->yuv_info.reg_2838, reg_2838);
-+	IVTV_DEBUG_YUV("Update reg 0x2834 %08x->%08x 0x2838 %08x->%08x\n",
-+		       yi->reg_2834, reg_2834, yi->reg_2838, reg_2838);
+diff --git a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c
+index 3c57a7d..7a1cd87 100644
+--- a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c
++++ b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c
+@@ -43,10 +43,14 @@ struct pvr2_sysfs {
+ 	struct device_attribute attr_v4l_radio_minor_number;
+ 	struct device_attribute attr_unit_number;
+ 	struct device_attribute attr_bus_info;
++	struct device_attribute attr_hdw_name;
++	struct device_attribute attr_hdw_desc;
+ 	int v4l_minor_number_created_ok;
+ 	int v4l_radio_minor_number_created_ok;
+ 	int unit_number_created_ok;
+ 	int bus_info_created_ok;
++	int hdw_name_created_ok;
++	int hdw_desc_created_ok;
+ };
  
- 	write_reg(reg_283c, 0x0283c);
- 	write_reg(reg_2844, 0x02844);
+ #ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC
+@@ -712,6 +716,14 @@ static void class_dev_destroy(struct pvr2_sysfs *sfp)
+ 	pvr2_sysfs_tear_down_debugifc(sfp);
+ #endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */
+ 	pvr2_sysfs_tear_down_controls(sfp);
++	if (sfp->hdw_desc_created_ok) {
++		device_remove_file(sfp->class_dev,
++				   &sfp->attr_hdw_desc);
++	}
++	if (sfp->hdw_name_created_ok) {
++		device_remove_file(sfp->class_dev,
++				   &sfp->attr_hdw_name);
++	}
+ 	if (sfp->bus_info_created_ok) {
+ 		device_remove_file(sfp->class_dev,
+ 					 &sfp->attr_bus_info);
+@@ -758,6 +770,28 @@ static ssize_t bus_info_show(struct device *class_dev,
+ }
  
--	IVTV_DEBUG_YUV("Update reg 0x283c %08x->%08x 0x2844 %08x->%08x\n",itv->yuv_info.reg_283c, reg_283c, itv->yuv_info.reg_2844, reg_2844);
-+	IVTV_DEBUG_YUV("Update reg 0x283c %08x->%08x 0x2844 %08x->%08x\n",
-+		       yi->reg_283c, reg_283c, yi->reg_2844, reg_2844);
  
- 	write_reg(0x00080514, 0x02840);
- 	write_reg(0x00100514, 0x02848);
--	IVTV_DEBUG_YUV("Update reg 0x2840 %08x->%08x 0x2848 %08x->%08x\n",itv->yuv_info.reg_2840, 0x00080514, itv->yuv_info.reg_2848, 0x00100514);
-+	IVTV_DEBUG_YUV("Update reg 0x2840 %08x->%08x 0x2848 %08x->%08x\n",
-+		       yi->reg_2840, 0x00080514, yi->reg_2848, 0x00100514);
++static ssize_t hdw_name_show(struct device *class_dev,
++			     struct device_attribute *attr, char *buf)
++{
++	struct pvr2_sysfs *sfp;
++	sfp = (struct pvr2_sysfs *)class_dev->driver_data;
++	if (!sfp) return -EINVAL;
++	return scnprintf(buf,PAGE_SIZE,"%s\n",
++			 pvr2_hdw_get_type(sfp->channel.hdw));
++}
++
++
++static ssize_t hdw_desc_show(struct device *class_dev,
++			     struct device_attribute *attr, char *buf)
++{
++	struct pvr2_sysfs *sfp;
++	sfp = (struct pvr2_sysfs *)class_dev->driver_data;
++	if (!sfp) return -EINVAL;
++	return scnprintf(buf,PAGE_SIZE,"%s\n",
++			 pvr2_hdw_get_desc(sfp->channel.hdw));
++}
++
++
+ static ssize_t v4l_radio_minor_number_show(struct device *class_dev,
+ 					   struct device_attribute *attr,
+ 					   char *buf)
+@@ -871,6 +905,32 @@ static void class_dev_create(struct pvr2_sysfs *sfp,
+ 		sfp->bus_info_created_ok = !0;
+ 	}
  
- 	write_reg(reg_2854, 0x02854);
--	IVTV_DEBUG_YUV("Update reg 0x2854 %08x->%08x \n",itv->yuv_info.reg_2854, reg_2854);
-+	IVTV_DEBUG_YUV("Update reg 0x2854 %08x->%08x \n",
-+		       yi->reg_2854, reg_2854);
++	sfp->attr_hdw_name.attr.name = "device_hardware_type";
++	sfp->attr_hdw_name.attr.mode = S_IRUGO;
++	sfp->attr_hdw_name.show = hdw_name_show;
++	sfp->attr_hdw_name.store = NULL;
++	ret = device_create_file(sfp->class_dev,
++				 &sfp->attr_hdw_name);
++	if (ret < 0) {
++		printk(KERN_WARNING "%s: device_create_file error: %d\n",
++		       __FUNCTION__, ret);
++	} else {
++		sfp->hdw_name_created_ok = !0;
++	}
++
++	sfp->attr_hdw_desc.attr.name = "device_hardware_description";
++	sfp->attr_hdw_desc.attr.mode = S_IRUGO;
++	sfp->attr_hdw_desc.show = hdw_desc_show;
++	sfp->attr_hdw_desc.store = NULL;
++	ret = device_create_file(sfp->class_dev,
++				 &sfp->attr_hdw_desc);
++	if (ret < 0) {
++		printk(KERN_WARNING "%s: device_create_file error: %d\n",
++		       __FUNCTION__, ret);
++	} else {
++		sfp->hdw_desc_created_ok = !0;
++	}
++
+ 	pvr2_sysfs_add_controls(sfp);
+ #ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC
+ 	pvr2_sysfs_add_debugifc(sfp);
+diff --git a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
+index 7a596ea..8f0587e 100644
+--- a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
++++ b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
+@@ -205,6 +205,7 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
+ 		memcpy(cap, &pvr_capability, sizeof(struct v4l2_capability));
+ 		strlcpy(cap->bus_info,pvr2_hdw_get_bus_info(hdw),
+ 			sizeof(cap->bus_info));
++		strlcpy(cap->card,pvr2_hdw_get_desc(hdw),sizeof(cap->card));
  
- 	write_reg(reg_285c, 0x0285c);
- 	write_reg(reg_2864, 0x02864);
--	IVTV_DEBUG_YUV("Update reg 0x285c %08x->%08x 0x2864 %08x->%08x\n",itv->yuv_info.reg_285c, reg_285c, itv->yuv_info.reg_2864, reg_2864);
-+	IVTV_DEBUG_YUV("Update reg 0x285c %08x->%08x 0x2864 %08x->%08x\n",
-+		       yi->reg_285c, reg_285c, yi->reg_2864, reg_2864);
+ 		ret = 0;
+ 		break;
+@@ -1015,10 +1016,8 @@ static int pvr2_v4l2_iosetup(struct pvr2_v4l2_fh *fh)
+ 	sp = fh->dev_info->stream->stream;
+ 	pvr2_stream_set_callback(sp,(pvr2_stream_callback)pvr2_v4l2_notify,fh);
+ 	pvr2_hdw_set_stream_type(hdw,fh->dev_info->config);
+-	pvr2_hdw_set_streaming(hdw,!0);
+-	ret = pvr2_ioread_set_enabled(fh->rhp,!0);
+-
+-	return ret;
++	if ((ret = pvr2_hdw_set_streaming(hdw,!0)) < 0) return ret;
++	return pvr2_ioread_set_enabled(fh->rhp,!0);
+ }
  
- 	write_reg(reg_2874, 0x02874);
--	IVTV_DEBUG_YUV("Update reg 0x2874 %08x->%08x\n",itv->yuv_info.reg_2874, reg_2874);
-+	IVTV_DEBUG_YUV("Update reg 0x2874 %08x->%08x\n",
-+		       yi->reg_2874, reg_2874);
  
- 	write_reg(reg_2870, 0x02870);
--	IVTV_DEBUG_YUV("Update reg 0x2870 %08x->%08x\n",itv->yuv_info.reg_2870, reg_2870);
-+	IVTV_DEBUG_YUV("Update reg 0x2870 %08x->%08x\n",
-+		       yi->reg_2870, reg_2870);
+diff --git a/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c b/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c
+index 61efa6f..7c47345 100644
+--- a/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c
++++ b/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c
+@@ -49,29 +49,50 @@ struct pvr2_v4l_decoder {
+ };
  
--	write_reg( reg_2890,0x02890);
--	IVTV_DEBUG_YUV("Update reg 0x2890 %08x->%08x\n",itv->yuv_info.reg_2890, reg_2890);
-+	write_reg(reg_2890, 0x02890);
-+	IVTV_DEBUG_YUV("Update reg 0x2890 %08x->%08x\n",
-+		       yi->reg_2890, reg_2890);
  
- 	/* Only update the filter if we really need to */
--	if (h_filter != itv->yuv_info.h_filter) {
--		ivtv_yuv_filter (itv,h_filter,-1,-1);
--		itv->yuv_info.h_filter = h_filter;
-+	if (h_filter != yi->h_filter) {
-+		ivtv_yuv_filter(itv, h_filter, -1, -1);
-+		yi->h_filter = h_filter;
++struct routing_scheme {
++	const int *def;
++	unsigned int cnt;
++};
++
++
++static const int routing_scheme0[] = {
++	[PVR2_CVAL_INPUT_TV] = SAA7115_COMPOSITE4,
++	/* In radio mode, we mute the video, but point at one
++	   spot just to stay consistent */
++	[PVR2_CVAL_INPUT_RADIO] = SAA7115_COMPOSITE5,
++	[PVR2_CVAL_INPUT_COMPOSITE] = SAA7115_COMPOSITE5,
++	[PVR2_CVAL_INPUT_SVIDEO] =  SAA7115_SVIDEO2,
++};
++
++static const struct routing_scheme routing_schemes[] = {
++	[PVR2_ROUTING_SCHEME_HAUPPAUGE] = {
++		.def = routing_scheme0,
++		.cnt = ARRAY_SIZE(routing_scheme0),
++	},
++};
++
+ static void set_input(struct pvr2_v4l_decoder *ctxt)
+ {
+ 	struct pvr2_hdw *hdw = ctxt->hdw;
+ 	struct v4l2_routing route;
++	const struct routing_scheme *sp;
++	unsigned int sid = hdw->hdw_desc->signal_routing_scheme;
+ 
+ 	pvr2_trace(PVR2_TRACE_CHIPS,"i2c v4l2 set_input(%d)",hdw->input_val);
+-	switch(hdw->input_val) {
+-	case PVR2_CVAL_INPUT_TV:
+-		route.input = SAA7115_COMPOSITE4;
+-		break;
+-	case PVR2_CVAL_INPUT_COMPOSITE:
+-		route.input = SAA7115_COMPOSITE5;
+-		break;
+-	case PVR2_CVAL_INPUT_SVIDEO:
+-		route.input = SAA7115_SVIDEO2;
+-		break;
+-	case PVR2_CVAL_INPUT_RADIO:
+-		// In radio mode, we mute the video, but point at one
+-		// spot just to stay consistent
+-		route.input = SAA7115_COMPOSITE5;
+-	default:
++
++	if ((sid < ARRAY_SIZE(routing_schemes)) &&
++	    ((sp = routing_schemes + sid) != 0) &&
++	    (hdw->input_val >= 0) &&
++	    (hdw->input_val < sp->cnt)) {
++		route.input = sp->def[hdw->input_val];
++	} else {
++		pvr2_trace(PVR2_TRACE_ERROR_LEGS,
++			   "*** WARNING *** i2c v4l2 set_input:"
++			   " Invalid routing scheme (%u) and/or input (%d)",
++			   sid,hdw->input_val);
+ 		return;
  	}
++
+ 	route.output = 0;
+ 	pvr2_i2c_client_cmd(ctxt->client,VIDIOC_INT_S_VIDEO_ROUTING,&route);
  }
- 
--static void ivtv_yuv_handle_vertical(struct ivtv *itv, struct yuv_frame_info *window)
-+static void ivtv_yuv_handle_vertical(struct ivtv *itv, struct yuv_frame_info *f)
+@@ -129,7 +150,7 @@ static const struct pvr2_v4l_decoder_ops decoder_ops[] = {
+ static void decoder_detach(struct pvr2_v4l_decoder *ctxt)
  {
-+	struct yuv_playback_info *yi = &itv->yuv_info;
- 	u32 master_height;
- 	u32 reg_2918, reg_291c, reg_2920, reg_2928;
- 	u32 reg_2930, reg_2934, reg_293c;
-@@ -359,69 +370,59 @@ static void ivtv_yuv_handle_vertical(struct ivtv *itv, struct yuv_frame_info *wi
- 	u32 reg_2950, reg_2954, reg_2958, reg_295c;
- 	u32 reg_2960, reg_2964, reg_2968, reg_296c;
- 	u32 reg_289c;
--	u32 src_y_major_y, src_y_minor_y;
--	u32 src_y_major_uv, src_y_minor_uv;
-+	u32 src_major_y, src_minor_y;
-+	u32 src_major_uv, src_minor_uv;
- 	u32 reg_2964_base, reg_2968_base;
- 	int v_filter_1, v_filter_2;
+ 	ctxt->client->handler = NULL;
+-	ctxt->hdw->decoder_ctrl = NULL;
++	pvr2_hdw_set_decoder(ctxt->hdw,NULL);
+ 	kfree(ctxt);
+ }
  
--	IVTV_DEBUG_WARN("Need to adjust to height %d src_h %d dst_h %d src_y %d dst_y %d\n",
--		window->tru_h, window->src_h, window->dst_h,window->src_y, window->dst_y);
-+	IVTV_DEBUG_WARN
-+	    ("Adjust to height %d src_h %d dst_h %d src_y %d dst_y %d\n",
-+	     f->tru_h, f->src_h, f->dst_h, f->src_y, f->dst_y);
+@@ -217,7 +238,7 @@ int pvr2_i2c_decoder_v4l_setup(struct pvr2_hdw *hdw,
+ 	ctxt->client = cp;
+ 	ctxt->hdw = hdw;
+ 	ctxt->stale_mask = (1 << ARRAY_SIZE(decoder_ops)) - 1;
+-	hdw->decoder_ctrl = &ctxt->ctrl;
++	pvr2_hdw_set_decoder(hdw,&ctxt->ctrl);
+ 	cp->handler = &ctxt->handler;
+ 	pvr2_trace(PVR2_TRACE_CHIPS,"i2c 0x%x saa711x V4L2 handler set up",
+ 		   cp->client->addr);
+diff --git a/drivers/media/video/saa7115.c b/drivers/media/video/saa7115.c
+index 2d18f00..41e5e51 100644
+--- a/drivers/media/video/saa7115.c
++++ b/drivers/media/video/saa7115.c
+@@ -46,6 +46,7 @@
+ #include <linux/videodev2.h>
+ #include <media/v4l2-common.h>
+ #include <media/v4l2-chip-ident.h>
++#include <media/v4l2-i2c-drv-legacy.h>
+ #include <media/saa7115.h>
+ #include <asm/div64.h>
  
- 	/* What scaling mode is being used... */
--	if (window->interlaced_y) {
--		IVTV_DEBUG_YUV("Scaling mode Y: Interlaced\n");
--	}
--	else {
--		IVTV_DEBUG_YUV("Scaling mode Y: Progressive\n");
--	}
-+	IVTV_DEBUG_YUV("Scaling mode Y: %s\n",
-+		       f->interlaced_y ? "Interlaced" : "Progressive");
+@@ -1230,7 +1231,7 @@ static void saa711x_decode_vbi_line(struct i2c_client *client,
  
--	if (window->interlaced_uv) {
--		IVTV_DEBUG_YUV("Scaling mode UV: Interlaced\n");
--	}
--	else {
--		IVTV_DEBUG_YUV("Scaling mode UV: Progressive\n");
--	}
-+	IVTV_DEBUG_YUV("Scaling mode UV: %s\n",
-+		       f->interlaced_uv ? "Interlaced" : "Progressive");
+ /* ============ SAA7115 AUDIO settings (end) ============= */
  
- 	/* What is the source video being treated as... */
--	if (itv->yuv_info.frame_interlaced) {
--		IVTV_DEBUG_WARN("Source video: Interlaced\n");
--	}
--	else {
--		IVTV_DEBUG_WARN("Source video: Non-interlaced\n");
--	}
-+	IVTV_DEBUG_WARN("Source video: %s\n",
-+			f->interlaced ? "Interlaced" : "Progressive");
+-static int saa711x_command(struct i2c_client *client, unsigned int cmd, void *arg)
++static int saa7115_command(struct i2c_client *client, unsigned int cmd, void *arg)
+ {
+ 	struct saa711x_state *state = i2c_get_clientdata(client);
  
- 	/* We offset into the image using two different index methods, so split
- 	   the y source coord into two parts. */
--	if (window->src_y < 8) {
--		src_y_minor_uv = window->src_y;
--		src_y_major_uv = 0;
--	}
--	else {
--		src_y_minor_uv = 8;
--		src_y_major_uv = window->src_y - 8;
-+	if (f->src_y < 8) {
-+		src_minor_uv = f->src_y;
-+		src_major_uv = 0;
-+	} else {
-+		src_minor_uv = 8;
-+		src_major_uv = f->src_y - 8;
- 	}
+@@ -1449,26 +1450,17 @@ static int saa711x_command(struct i2c_client *client, unsigned int cmd, void *ar
  
--	src_y_minor_y = src_y_minor_uv;
--	src_y_major_y = src_y_major_uv;
-+	src_minor_y = src_minor_uv;
-+	src_major_y = src_major_uv;
+ /* ----------------------------------------------------------------------- */
  
--	if (window->offset_y) src_y_minor_y += 16;
-+	if (f->offset_y)
-+		src_minor_y += 16;
+-static struct i2c_driver i2c_driver_saa711x;
+-
+-static int saa711x_attach(struct i2c_adapter *adapter, int address, int kind)
++static int saa7115_probe(struct i2c_client *client)
+ {
+-	struct i2c_client *client;
+ 	struct saa711x_state *state;
+ 	int	i;
+ 	char	name[17];
+ 	u8 chip_id;
  
--	if (window->interlaced_y)
--		reg_2918 = (window->dst_h << 16) | (window->src_h + src_y_minor_y);
-+	if (f->interlaced_y)
-+		reg_2918 = (f->dst_h << 16) | (f->src_h + src_minor_y);
- 	else
--		reg_2918 = (window->dst_h << 16) | ((window->src_h + src_y_minor_y) << 1);
-+		reg_2918 = (f->dst_h << 16) | ((f->src_h + src_minor_y) << 1);
+ 	/* Check if the adapter supports the needed features */
+-	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+-		return 0;
++	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
++		return -EIO;
  
--	if (window->interlaced_uv)
--		reg_291c = (window->dst_h << 16) | ((window->src_h + src_y_minor_uv) >> 1);
-+	if (f->interlaced_uv)
-+		reg_291c = (f->dst_h << 16) | ((f->src_h + src_minor_uv) >> 1);
- 	else
--		reg_291c = (window->dst_h << 16) | (window->src_h + src_y_minor_uv);
-+		reg_291c = (f->dst_h << 16) | (f->src_h + src_minor_uv);
+-	client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
+-	if (client == 0)
+-		return -ENOMEM;
+-	client->addr = address;
+-	client->adapter = adapter;
+-	client->driver = &i2c_driver_saa711x;
+ 	snprintf(client->name, sizeof(client->name) - 1, "saa7115");
  
--	reg_2964_base = (src_y_minor_y * ((window->dst_h << 16)/window->src_h)) >> 14;
--	reg_2968_base = (src_y_minor_uv * ((window->dst_h << 16)/window->src_h)) >> 14;
-+	reg_2964_base = (src_minor_y * ((f->dst_h << 16) / f->src_h)) >> 14;
-+	reg_2968_base = (src_minor_uv * ((f->dst_h << 16) / f->src_h)) >> 14;
+ 	for (i = 0; i < 0x0f; i++) {
+@@ -1485,18 +1477,16 @@ static int saa711x_attach(struct i2c_adapter *adapter, int address, int kind)
+ 	/* Check whether this chip is part of the saa711x series */
+ 	if (memcmp(name, "1f711", 5)) {
+ 		v4l_dbg(1, debug, client, "chip found @ 0x%x (ID %s) does not match a known saa711x chip.\n",
+-			address << 1, name);
+-		kfree(client);
+-		return 0;
++			client->addr << 1, name);
++		return -ENODEV;
+ 	}
  
--	if (window->dst_h / 2 >= window->src_h && !window->interlaced_y) {
--		master_height = (window->src_h * 0x00400000) / window->dst_h;
--		if ((window->src_h * 0x00400000) - (master_height * window->dst_h) >= window->dst_h / 2) master_height ++;
-+	if (f->dst_h / 2 >= f->src_h && !f->interlaced_y) {
-+		master_height = (f->src_h * 0x00400000) / f->dst_h;
-+		if ((f->src_h * 0x00400000) - (master_height * f->dst_h) >= f->dst_h / 2)
-+			master_height++;
- 		reg_2920 = master_height >> 2;
- 		reg_2928 = master_height >> 3;
- 		reg_2930 = master_height;
-@@ -429,45 +430,42 @@ static void ivtv_yuv_handle_vertical(struct ivtv *itv, struct yuv_frame_info *wi
- 		reg_2964_base >>= 3;
- 		reg_2968_base >>= 3;
- 		reg_296c = 0x00000000;
--	}
--	else if (window->dst_h >= window->src_h) {
--		master_height = (window->src_h * 0x00400000) / window->dst_h;
-+	} else if (f->dst_h >= f->src_h) {
-+		master_height = (f->src_h * 0x00400000) / f->dst_h;
- 		master_height = (master_height >> 1) + (master_height & 1);
- 		reg_2920 = master_height >> 2;
- 		reg_2928 = master_height >> 2;
- 		reg_2930 = master_height;
- 		reg_2940 = master_height >> 1;
- 		reg_296c = 0x00000000;
--		if (window->interlaced_y) {
-+		if (f->interlaced_y) {
- 			reg_2964_base >>= 3;
--		}
--		else {
--			reg_296c ++;
-+		} else {
-+			reg_296c++;
- 			reg_2964_base >>= 2;
- 		}
--		if (window->interlaced_uv) reg_2928 >>= 1;
-+		if (f->interlaced_uv)
-+			reg_2928 >>= 1;
- 		reg_2968_base >>= 3;
--	}
--	else if (window->dst_h >= window->src_h / 2) {
--		master_height = (window->src_h * 0x00200000) / window->dst_h;
-+	} else if (f->dst_h >= f->src_h / 2) {
-+		master_height = (f->src_h * 0x00200000) / f->dst_h;
- 		master_height = (master_height >> 1) + (master_height & 1);
- 		reg_2920 = master_height >> 2;
- 		reg_2928 = master_height >> 2;
- 		reg_2930 = master_height;
- 		reg_2940 = master_height;
- 		reg_296c = 0x00000101;
--		if (window->interlaced_y) {
-+		if (f->interlaced_y) {
- 			reg_2964_base >>= 2;
--		}
--		else {
--			reg_296c ++;
-+		} else {
-+			reg_296c++;
- 			reg_2964_base >>= 1;
- 		}
--		if (window->interlaced_uv) reg_2928 >>= 1;
-+		if (f->interlaced_uv)
-+			reg_2928 >>= 1;
- 		reg_2968_base >>= 2;
--	}
--	else {
--		master_height = (window->src_h * 0x00100000) / window->dst_h;
-+	} else {
-+		master_height = (f->src_h * 0x00100000) / f->dst_h;
- 		master_height = (master_height >> 1) + (master_height & 1);
- 		reg_2920 = master_height >> 2;
- 		reg_2928 = master_height >> 2;
-@@ -480,13 +478,12 @@ static void ivtv_yuv_handle_vertical(struct ivtv *itv, struct yuv_frame_info *wi
+ 	snprintf(client->name, sizeof(client->name) - 1, "saa711%d",chip_id);
+-	v4l_info(client, "saa711%d found (%s) @ 0x%x (%s)\n", chip_id, name, address << 1, adapter->name);
++	v4l_info(client, "saa711%d found (%s) @ 0x%x (%s)\n", chip_id, name, client->addr << 1, client->adapter->name);
  
- 	/* FIXME These registers change depending on scaled / unscaled output
- 	   We really need to work out what they should be */
--	if (window->src_h == window->dst_h){
-+	if (f->src_h == f->dst_h) {
- 		reg_2934 = 0x00020000;
- 		reg_293c = 0x00100000;
- 		reg_2944 = 0x00040000;
- 		reg_294c = 0x000b0000;
--	}
--	else {
-+	} else {
- 		reg_2934 = 0x00000FF0;
- 		reg_293c = 0x00000FF0;
- 		reg_2944 = 0x00000FF0;
-@@ -494,34 +491,36 @@ static void ivtv_yuv_handle_vertical(struct ivtv *itv, struct yuv_frame_info *wi
+ 	state = kzalloc(sizeof(struct saa711x_state), GFP_KERNEL);
+ 	i2c_set_clientdata(client, state);
+ 	if (state == NULL) {
+-		kfree(client);
+ 		return -ENOMEM;
  	}
+ 	state->input = -1;
+@@ -1549,59 +1539,25 @@ static int saa711x_attach(struct i2c_adapter *adapter, int address, int kind)
+ 	saa711x_writeregs(client, saa7115_init_misc);
+ 	saa711x_set_v4lstd(client, V4L2_STD_NTSC);
  
- 	/* The first line to be displayed */
--	reg_2950 = 0x00010000 + src_y_major_y;
--	if (window->interlaced_y) reg_2950 += 0x00010000;
-+	reg_2950 = 0x00010000 + src_major_y;
-+	if (f->interlaced_y)
-+		reg_2950 += 0x00010000;
- 	reg_2954 = reg_2950 + 1;
+-	i2c_attach_client(client);
+-
+ 	v4l_dbg(1, debug, client, "status: (1E) 0x%02x, (1F) 0x%02x\n",
+ 		saa711x_read(client, R_1E_STATUS_BYTE_1_VD_DEC), saa711x_read(client, R_1F_STATUS_BYTE_2_VD_DEC));
+-
+ 	return 0;
+ }
  
--	reg_2958 = 0x00010000 + (src_y_major_y >> 1);
--	if (window->interlaced_uv) reg_2958 += 0x00010000;
-+	reg_2958 = 0x00010000 + (src_major_y >> 1);
-+	if (f->interlaced_uv)
-+		reg_2958 += 0x00010000;
- 	reg_295c = reg_2958 + 1;
+-static int saa711x_probe(struct i2c_adapter *adapter)
+-{
+-	if (adapter->class & I2C_CLASS_TV_ANALOG || adapter->class & I2C_CLASS_TV_DIGITAL)
+-		return i2c_probe(adapter, &addr_data, &saa711x_attach);
+-	return 0;
+-}
++/* ----------------------------------------------------------------------- */
  
--	if (itv->yuv_info.decode_height == 480)
-+	if (yi->decode_height == 480)
- 		reg_289c = 0x011e0017;
- 	else
- 		reg_289c = 0x01500017;
+-static int saa711x_detach(struct i2c_client *client)
++static int saa7115_remove(struct i2c_client *client)
+ {
+-	struct saa711x_state *state = i2c_get_clientdata(client);
+-	int err;
+-
+-	err = i2c_detach_client(client);
+-	if (err) {
+-		return err;
+-	}
+-
+-	kfree(state);
+-	kfree(client);
++	kfree(i2c_get_clientdata(client));
+ 	return 0;
+ }
  
--	if (window->dst_y < 0)
--		reg_289c = (reg_289c - ((window->dst_y & ~1)<<15))-(window->dst_y >>1);
-+	if (f->dst_y < 0)
-+		reg_289c = (reg_289c - ((f->dst_y & ~1)<<15))-(f->dst_y >>1);
- 	else
--		reg_289c = (reg_289c + ((window->dst_y & ~1)<<15))+(window->dst_y >>1);
-+		reg_289c = (reg_289c + ((f->dst_y & ~1)<<15))+(f->dst_y >>1);
+-/* ----------------------------------------------------------------------- */
+-
+-/* i2c implementation */
+-static struct i2c_driver i2c_driver_saa711x = {
+-	.driver = {
+-		.name = "saa7115",
+-	},
+-	.id = I2C_DRIVERID_SAA711X,
+-	.attach_adapter = saa711x_probe,
+-	.detach_client = saa711x_detach,
+-	.command = saa711x_command,
++static struct v4l2_i2c_driver_data v4l2_i2c_data = {
++	.name = "saa7115",
++	.driverid = I2C_DRIVERID_SAA711X,
++	.command = saa7115_command,
++	.probe = saa7115_probe,
++	.remove = saa7115_remove,
++	.legacy_class = I2C_CLASS_TV_ANALOG | I2C_CLASS_TV_DIGITAL,
+ };
  
- 	/* How much of the source to decode.
- 	   Take into account the source offset */
--	reg_2960 = ((src_y_minor_y + window->src_h + src_y_major_y) - 1 ) |
--			((((src_y_minor_uv + window->src_h + src_y_major_uv) - 1) & ~1) << 15);
-+	reg_2960 = ((src_minor_y + f->src_h + src_major_y) - 1) |
-+		(((src_minor_uv + f->src_h + src_major_uv - 1) & ~1) << 15);
+-
+-static int __init saa711x_init_module(void)
+-{
+-	return i2c_add_driver(&i2c_driver_saa711x);
+-}
+-
+-static void __exit saa711x_cleanup_module(void)
+-{
+-	i2c_del_driver(&i2c_driver_saa711x);
+-}
+-
+-module_init(saa711x_init_module);
+-module_exit(saa711x_cleanup_module);
+diff --git a/drivers/media/video/saa7127.c b/drivers/media/video/saa7127.c
+index e35ef32..06c88db 100644
+--- a/drivers/media/video/saa7127.c
++++ b/drivers/media/video/saa7127.c
+@@ -55,10 +55,11 @@
+ #include <linux/videodev2.h>
+ #include <media/v4l2-common.h>
+ #include <media/v4l2-chip-ident.h>
++#include <media/v4l2-i2c-drv.h>
+ #include <media/saa7127.h>
  
- 	/* Calculate correct value for register 2964 */
--	if (window->src_h == window->dst_h)
-+	if (f->src_h == f->dst_h) {
- 		reg_2964 = 1;
--	else {
--		reg_2964 = 2 + ((window->dst_h << 1) / window->src_h);
-+	} else {
-+		reg_2964 = 2 + ((f->dst_h << 1) / f->src_h);
- 		reg_2964 = (reg_2964 >> 1) + (reg_2964 & 1);
- 	}
- 	reg_2968 = (reg_2964 << 16) + reg_2964 + (reg_2964 >> 1);
-@@ -536,283 +535,246 @@ static void ivtv_yuv_handle_vertical(struct ivtv *itv, struct yuv_frame_info *wi
- 	/* Deviate further from what it should be. I find the flicker headache
- 	   inducing so try to reduce it slightly. Leave 2968 as-is otherwise
- 	   colours foul. */
--	if ((reg_2964 != 0x00010001) && (window->dst_h / 2 <= window->src_h))
--		reg_2964 = (reg_2964 & 0xFFFF0000) + ((reg_2964 & 0x0000FFFF)/2);
-+	if ((reg_2964 != 0x00010001) && (f->dst_h / 2 <= f->src_h))
-+		reg_2964 = (reg_2964 & 0xFFFF0000) + ((reg_2964 & 0x0000FFFF) / 2);
+-static int debug = 0;
+-static int test_image = 0;
++static int debug;
++static int test_image;
  
--	if (!window->interlaced_y) reg_2964 -= 0x00010001;
--	if (!window->interlaced_uv) reg_2968 -= 0x00010001;
-+	if (!f->interlaced_y)
-+		reg_2964 -= 0x00010001;
-+	if (!f->interlaced_uv)
-+		reg_2968 -= 0x00010001;
+ MODULE_DESCRIPTION("Philips SAA7127/9 video encoder driver");
+ MODULE_AUTHOR("Kevin Thayer, Chris Kennedy, Hans Verkuil");
+@@ -68,10 +69,6 @@ module_param(test_image, int, 0644);
+ MODULE_PARM_DESC(debug, "debug level (0-2)");
+ MODULE_PARM_DESC(test_image, "test_image (0-1)");
  
- 	reg_2964 += ((reg_2964_base << 16) | reg_2964_base);
- 	reg_2968 += ((reg_2968_base << 16) | reg_2968_base);
+-static unsigned short normal_i2c[] = { 0x88 >> 1, I2C_CLIENT_END };
+-
+-
+-I2C_CLIENT_INSMOD;
  
- 	/* Select the vertical filter */
--	if (window->src_h == window->dst_h) {
-+	if (f->src_h == f->dst_h) {
- 		/* An exact size match uses filter 0/1 */
- 		v_filter_1 = 0;
- 		v_filter_2 = 1;
--	}
--	else {
-+	} else {
- 		/* Figure out which filter to use */
--		v_filter_1 = ((window->src_h << 16) / window->dst_h) >> 15;
-+		v_filter_1 = ((f->src_h << 16) / f->dst_h) >> 15;
- 		v_filter_1 = (v_filter_1 >> 1) + (v_filter_1 & 1);
- 		/* Only an exact size match can use filter 0 */
--		if (v_filter_1 == 0) v_filter_1 = 1;
-+		v_filter_1 += !v_filter_1;
- 		v_filter_2 = v_filter_1;
+ /*
+  * SAA7127 registers
+@@ -360,9 +357,10 @@ static int saa7127_set_cc(struct i2c_client *client, struct v4l2_sliced_vbi_data
+ 	if (enable && (data->field != 0 || data->line != 21))
+ 		return -EINVAL;
+ 	if (state->cc_enable != enable) {
+-		v4l_dbg(1, debug, client, "Turn CC %s\n", enable ? "on" : "off");
++		v4l_dbg(1, debug, client,
++			"Turn CC %s\n", enable ? "on" : "off");
+ 		saa7127_write(client, SAA7127_REG_CLOSED_CAPTION,
+-				(state->xds_enable << 7) | (enable << 6) | 0x11);
++			(state->xds_enable << 7) | (enable << 6) | 0x11);
+ 		state->cc_enable = enable;
  	}
+ 	if (!enable)
+@@ -420,7 +418,8 @@ static int saa7127_set_wss(struct i2c_client *client, struct v4l2_sliced_vbi_dat
  
- 	write_reg(reg_2934, 0x02934);
- 	write_reg(reg_293c, 0x0293c);
--	IVTV_DEBUG_YUV("Update reg 0x2934 %08x->%08x 0x293c %08x->%08x\n",itv->yuv_info.reg_2934, reg_2934, itv->yuv_info.reg_293c, reg_293c);
-+	IVTV_DEBUG_YUV("Update reg 0x2934 %08x->%08x 0x293c %08x->%08x\n",
-+		       yi->reg_2934, reg_2934, yi->reg_293c, reg_293c);
- 	write_reg(reg_2944, 0x02944);
- 	write_reg(reg_294c, 0x0294c);
--	IVTV_DEBUG_YUV("Update reg 0x2944 %08x->%08x 0x294c %08x->%08x\n",itv->yuv_info.reg_2944, reg_2944, itv->yuv_info.reg_294c, reg_294c);
-+	IVTV_DEBUG_YUV("Update reg 0x2944 %08x->%08x 0x294c %08x->%08x\n",
-+		       yi->reg_2944, reg_2944, yi->reg_294c, reg_294c);
+ 	saa7127_write(client, 0x26, data->data[0]);
+ 	saa7127_write(client, 0x27, 0x80 | (data->data[1] & 0x3f));
+-	v4l_dbg(1, debug, client, "WSS mode: %s\n", wss_strs[data->data[0] & 0xf]);
++	v4l_dbg(1, debug, client,
++		"WSS mode: %s\n", wss_strs[data->data[0] & 0xf]);
+ 	state->wss_mode = (data->data[1] & 0x3f) << 8 | data->data[0];
+ 	return 0;
+ }
+@@ -507,7 +506,8 @@ static int saa7127_set_output_type(struct i2c_client *client, int output)
+ 	default:
+ 		return -EINVAL;
+ 	}
+-	v4l_dbg(1, debug, client, "Selecting %s output type\n", output_strs[output]);
++	v4l_dbg(1, debug, client,
++		"Selecting %s output type\n", output_strs[output]);
  
- 	/* Ensure 2970 is 0 (does it ever change ?) */
- /*	write_reg(0,0x02970); */
--/*	IVTV_DEBUG_YUV("Update reg 0x2970 %08x->%08x\n",itv->yuv_info.reg_2970, 0); */
-+/*	IVTV_DEBUG_YUV("Update reg 0x2970 %08x->%08x\n", yi->reg_2970, 0); */
+ 	/* Configure Encoder */
+ 	saa7127_write(client, 0x2d, state->reg_2d);
+@@ -569,12 +569,10 @@ static int saa7127_command(struct i2c_client *client,
+ 	{
+ 		int rc = 0;
  
- 	write_reg(reg_2930, 0x02938);
- 	write_reg(reg_2930, 0x02930);
--	IVTV_DEBUG_YUV("Update reg 0x2930 %08x->%08x 0x2938 %08x->%08x\n",itv->yuv_info.reg_2930, reg_2930, itv->yuv_info.reg_2938, reg_2930);
-+	IVTV_DEBUG_YUV("Update reg 0x2930 %08x->%08x 0x2938 %08x->%08x\n",
-+		       yi->reg_2930, reg_2930, yi->reg_2938, reg_2930);
+-		if (state->input_type != route->input) {
++		if (state->input_type != route->input)
+ 			rc = saa7127_set_input_type(client, route->input);
+-		}
+-		if (rc == 0 && state->output_type != route->output) {
++		if (rc == 0 && state->output_type != route->output)
+ 			rc = saa7127_set_output_type(client, route->output);
+-		}
+ 		return rc;
+ 	}
  
- 	write_reg(reg_2928, 0x02928);
--	write_reg(reg_2928+0x514, 0x0292C);
--	IVTV_DEBUG_YUV("Update reg 0x2928 %08x->%08x 0x292c %08x->%08x\n",itv->yuv_info.reg_2928, reg_2928, itv->yuv_info.reg_292c, reg_2928+0x514);
-+	write_reg(reg_2928 + 0x514, 0x0292C);
-+	IVTV_DEBUG_YUV("Update reg 0x2928 %08x->%08x 0x292c %08x->%08x\n",
-+		       yi->reg_2928, reg_2928, yi->reg_292c, reg_2928 + 0x514);
+@@ -620,7 +618,8 @@ static int saa7127_command(struct i2c_client *client,
+ 	{
+ 		struct v4l2_register *reg = arg;
  
- 	write_reg(reg_2920, 0x02920);
--	write_reg(reg_2920+0x514, 0x02924);
--	IVTV_DEBUG_YUV("Update reg 0x2920 %08x->%08x 0x2924 %08x->%08x\n",itv->yuv_info.reg_2920, reg_2920, itv->yuv_info.reg_2924, 0x514+reg_2920);
-+	write_reg(reg_2920 + 0x514, 0x02924);
-+	IVTV_DEBUG_YUV("Update reg 0x2920 %08x->%08x 0x2924 %08x->%08x\n",
-+		       yi->reg_2920, reg_2920, yi->reg_2924, reg_2920 + 0x514);
+-		if (!v4l2_chip_match_i2c_client(client, reg->match_type, reg->match_chip))
++		if (!v4l2_chip_match_i2c_client(client,
++					reg->match_type, reg->match_chip))
+ 			return -EINVAL;
+ 		if (!capable(CAP_SYS_ADMIN))
+ 			return -EPERM;
+@@ -637,16 +636,16 @@ static int saa7127_command(struct i2c_client *client,
+ 		struct v4l2_sliced_vbi_data *data = arg;
  
--	write_reg (reg_2918,0x02918);
--	write_reg (reg_291c,0x0291C);
--	IVTV_DEBUG_YUV("Update reg 0x2918 %08x->%08x 0x291C %08x->%08x\n",itv->yuv_info.reg_2918,reg_2918,itv->yuv_info.reg_291c,reg_291c);
-+	write_reg(reg_2918, 0x02918);
-+	write_reg(reg_291c, 0x0291C);
-+	IVTV_DEBUG_YUV("Update reg 0x2918 %08x->%08x 0x291C %08x->%08x\n",
-+		       yi->reg_2918, reg_2918, yi->reg_291c, reg_291c);
+ 		switch (data->id) {
+-			case V4L2_SLICED_WSS_625:
+-				return saa7127_set_wss(client, data);
+-			case V4L2_SLICED_VPS:
+-				return saa7127_set_vps(client, data);
+-			case V4L2_SLICED_CAPTION_525:
+-				if (data->field == 0)
+-					return saa7127_set_cc(client, data);
+-				return saa7127_set_xds(client, data);
+-			default:
+-				return -EINVAL;
++		case V4L2_SLICED_WSS_625:
++			return saa7127_set_wss(client, data);
++		case V4L2_SLICED_VPS:
++			return saa7127_set_vps(client, data);
++		case V4L2_SLICED_CAPTION_525:
++			if (data->field == 0)
++				return saa7127_set_cc(client, data);
++			return saa7127_set_xds(client, data);
++		default:
++			return -EINVAL;
+ 		}
+ 		break;
+ 	}
+@@ -662,31 +661,20 @@ static int saa7127_command(struct i2c_client *client,
  
- 	write_reg(reg_296c, 0x0296c);
--	IVTV_DEBUG_YUV("Update reg 0x296c %08x->%08x\n",itv->yuv_info.reg_296c, reg_296c);
-+	IVTV_DEBUG_YUV("Update reg 0x296c %08x->%08x\n",
-+		       yi->reg_296c, reg_296c);
+ /* ----------------------------------------------------------------------- */
  
- 	write_reg(reg_2940, 0x02948);
- 	write_reg(reg_2940, 0x02940);
--	IVTV_DEBUG_YUV("Update reg 0x2940 %08x->%08x 0x2948 %08x->%08x\n",itv->yuv_info.reg_2940, reg_2940, itv->yuv_info.reg_2948, reg_2940);
-+	IVTV_DEBUG_YUV("Update reg 0x2940 %08x->%08x 0x2948 %08x->%08x\n",
-+		       yi->reg_2940, reg_2940, yi->reg_2948, reg_2940);
+-static struct i2c_driver i2c_driver_saa7127;
+-
+-/* ----------------------------------------------------------------------- */
+-
+-static int saa7127_attach(struct i2c_adapter *adapter, int address, int kind)
++static int saa7127_probe(struct i2c_client *client)
+ {
+-	struct i2c_client *client;
+ 	struct saa7127_state *state;
+ 	struct v4l2_sliced_vbi_data vbi = { 0, 0, 0, 0 };  /* set to disabled */
+ 	int read_result = 0;
  
- 	write_reg(reg_2950, 0x02950);
- 	write_reg(reg_2954, 0x02954);
--	IVTV_DEBUG_YUV("Update reg 0x2950 %08x->%08x 0x2954 %08x->%08x\n",itv->yuv_info.reg_2950, reg_2950, itv->yuv_info.reg_2954, reg_2954);
-+	IVTV_DEBUG_YUV("Update reg 0x2950 %08x->%08x 0x2954 %08x->%08x\n",
-+		       yi->reg_2950, reg_2950, yi->reg_2954, reg_2954);
+ 	/* Check if the adapter supports the needed features */
+-	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+-		return 0;
+-
+-	client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
+-	if (client == 0)
+-		return -ENOMEM;
++	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
++		return -EIO;
  
- 	write_reg(reg_2958, 0x02958);
- 	write_reg(reg_295c, 0x0295C);
--	IVTV_DEBUG_YUV("Update reg 0x2958 %08x->%08x 0x295C %08x->%08x\n",itv->yuv_info.reg_2958, reg_2958, itv->yuv_info.reg_295c, reg_295c);
-+	IVTV_DEBUG_YUV("Update reg 0x2958 %08x->%08x 0x295C %08x->%08x\n",
-+		       yi->reg_2958, reg_2958, yi->reg_295c, reg_295c);
+-	client->addr = address;
+-	client->adapter = adapter;
+-	client->driver = &i2c_driver_saa7127;
+ 	snprintf(client->name, sizeof(client->name) - 1, "saa7127");
+ 
+-	v4l_dbg(1, debug, client, "detecting saa7127 client on address 0x%x\n", address << 1);
++	v4l_dbg(1, debug, client, "detecting saa7127 client on address 0x%x\n",
++			client->addr << 1);
  
- 	write_reg(reg_2960, 0x02960);
--	IVTV_DEBUG_YUV("Update reg 0x2960 %08x->%08x \n",itv->yuv_info.reg_2960, reg_2960);
-+	IVTV_DEBUG_YUV("Update reg 0x2960 %08x->%08x \n",
-+		       yi->reg_2960, reg_2960);
+ 	/* First test register 0: Bits 5-7 are a version ID (should be 0),
+ 	   and bit 2 should also be 0.
+@@ -696,15 +684,12 @@ static int saa7127_attach(struct i2c_adapter *adapter, int address, int kind)
+ 	if ((saa7127_read(client, 0) & 0xe4) != 0 ||
+ 			(saa7127_read(client, 0x29) & 0x3f) != 0x1d) {
+ 		v4l_dbg(1, debug, client, "saa7127 not found\n");
+-		kfree(client);
+-		return 0;
++		return -ENODEV;
+ 	}
+ 	state = kzalloc(sizeof(struct saa7127_state), GFP_KERNEL);
  
- 	write_reg(reg_2964, 0x02964);
- 	write_reg(reg_2968, 0x02968);
--	IVTV_DEBUG_YUV("Update reg 0x2964 %08x->%08x 0x2968 %08x->%08x\n",itv->yuv_info.reg_2964, reg_2964, itv->yuv_info.reg_2968, reg_2968);
-+	IVTV_DEBUG_YUV("Update reg 0x2964 %08x->%08x 0x2968 %08x->%08x\n",
-+		       yi->reg_2964, reg_2964, yi->reg_2968, reg_2968);
+-	if (state == NULL) {
+-		kfree(client);
+-		return (-ENOMEM);
+-	}
++	if (state == NULL)
++		return -ENOMEM;
  
--	write_reg( reg_289c,0x0289c);
--	IVTV_DEBUG_YUV("Update reg 0x289c %08x->%08x\n",itv->yuv_info.reg_289c, reg_289c);
-+	write_reg(reg_289c, 0x0289c);
-+	IVTV_DEBUG_YUV("Update reg 0x289c %08x->%08x\n",
-+		       yi->reg_289c, reg_289c);
+ 	i2c_set_clientdata(client, state);
  
- 	/* Only update filter 1 if we really need to */
--	if (v_filter_1 != itv->yuv_info.v_filter_1) {
--		ivtv_yuv_filter (itv,-1,v_filter_1,-1);
--		itv->yuv_info.v_filter_1 = v_filter_1;
-+	if (v_filter_1 != yi->v_filter_1) {
-+		ivtv_yuv_filter(itv, -1, v_filter_1, -1);
-+		yi->v_filter_1 = v_filter_1;
- 	}
+@@ -718,91 +703,48 @@ static int saa7127_attach(struct i2c_adapter *adapter, int address, int kind)
+ 	saa7127_set_wss(client, &vbi);
+ 	saa7127_set_cc(client, &vbi);
+ 	saa7127_set_xds(client, &vbi);
+-	if (test_image == 1) {
++	if (test_image == 1)
+ 		/* The Encoder has an internal Colorbar generator */
+ 		/* This can be used for debugging */
+ 		saa7127_set_input_type(client, SAA7127_INPUT_TYPE_TEST_IMAGE);
+-	} else {
++	else
+ 		saa7127_set_input_type(client, SAA7127_INPUT_TYPE_NORMAL);
+-	}
+ 	saa7127_set_video_enable(client, 1);
  
- 	/* Only update filter 2 if we really need to */
--	if (v_filter_2 != itv->yuv_info.v_filter_2) {
--		ivtv_yuv_filter (itv,-1,-1,v_filter_2);
--		itv->yuv_info.v_filter_2 = v_filter_2;
-+	if (v_filter_2 != yi->v_filter_2) {
-+		ivtv_yuv_filter(itv, -1, -1, v_filter_2);
-+		yi->v_filter_2 = v_filter_2;
+ 	/* Detect if it's an saa7129 */
+ 	read_result = saa7127_read(client, SAA7129_REG_FADE_KEY_COL2);
+ 	saa7127_write(client, SAA7129_REG_FADE_KEY_COL2, 0xaa);
+ 	if (saa7127_read(client, SAA7129_REG_FADE_KEY_COL2) == 0xaa) {
+-		v4l_info(client, "saa7129 found @ 0x%x (%s)\n", address << 1, adapter->name);
++		v4l_info(client, "saa7129 found @ 0x%x (%s)\n",
++				client->addr << 1, client->adapter->name);
+ 		saa7127_write(client, SAA7129_REG_FADE_KEY_COL2, read_result);
+ 		saa7127_write_inittab(client, saa7129_init_config_extra);
+ 		state->ident = V4L2_IDENT_SAA7129;
+ 	} else {
+-		v4l_info(client, "saa7127 found @ 0x%x (%s)\n", address << 1, adapter->name);
++		v4l_info(client, "saa7127 found @ 0x%x (%s)\n",
++				client->addr << 1, client->adapter->name);
+ 		state->ident = V4L2_IDENT_SAA7127;
  	}
 -
+-	i2c_attach_client(client);
+-
+ 	return 0;
  }
  
- /* Modify the supplied coordinate information to fit the visible osd area */
--static u32 ivtv_yuv_window_setup (struct ivtv *itv, struct yuv_frame_info *window)
-+static u32 ivtv_yuv_window_setup(struct ivtv *itv, struct yuv_frame_info *f)
- {
--	int osd_crop, lace_threshold;
-+	struct yuv_frame_info *of = &itv->yuv_info.old_frame_info;
-+	int osd_crop;
- 	u32 osd_scale;
- 	u32 yuv_update = 0;
+ /* ----------------------------------------------------------------------- */
  
--	lace_threshold = itv->yuv_info.lace_threshold;
--	if (lace_threshold < 0)
--		lace_threshold = itv->yuv_info.decode_height - 1;
+-static int saa7127_probe(struct i2c_adapter *adapter)
++static int saa7127_remove(struct i2c_client *client)
+ {
+-	if (adapter->class & I2C_CLASS_TV_ANALOG)
+-		return i2c_probe(adapter, &addr_data, saa7127_attach);
+-	return 0;
+-}
 -
--	/* Work out the lace settings */
--	switch (itv->yuv_info.lace_mode) {
--		case IVTV_YUV_MODE_PROGRESSIVE: /* Progressive mode */
--			itv->yuv_info.frame_interlaced = 0;
--			if (window->tru_h < 512 || (window->tru_h > 576 && window->tru_h < 1021))
--				window->interlaced_y = 0;
--			else
--				window->interlaced_y = 1;
+-/* ----------------------------------------------------------------------- */
 -
--			if (window->tru_h < 1021 && (window->dst_h >= window->src_h /2))
--				window->interlaced_uv = 0;
--			else
--				window->interlaced_uv = 1;
--			break;
+-static int saa7127_detach(struct i2c_client *client)
+-{
+-	struct saa7127_state *state = i2c_get_clientdata(client);
+-	int err;
 -
--		case IVTV_YUV_MODE_AUTO:
--			if (window->tru_h <= lace_threshold || window->tru_h > 576 || window->tru_w > 720){
--				itv->yuv_info.frame_interlaced = 0;
--				if ((window->tru_h < 512) ||
--				  (window->tru_h > 576 && window->tru_h < 1021) ||
--				  (window->tru_w > 720 && window->tru_h < 1021))
--					window->interlaced_y = 0;
--				else
--					window->interlaced_y = 1;
+ 	/* Turn off TV output */
+ 	saa7127_set_video_enable(client, 0);
 -
--				if (window->tru_h < 1021 && (window->dst_h >= window->src_h /2))
--					window->interlaced_uv = 0;
--				else
--					window->interlaced_uv = 1;
--			}
--			else {
--				itv->yuv_info.frame_interlaced = 1;
--				window->interlaced_y = 1;
--				window->interlaced_uv = 1;
--			}
--			break;
+-	err = i2c_detach_client(client);
 -
--			case IVTV_YUV_MODE_INTERLACED: /* Interlace mode */
--		default:
--			itv->yuv_info.frame_interlaced = 1;
--			window->interlaced_y = 1;
--			window->interlaced_uv = 1;
--			break;
+-	if (err) {
+-		return err;
 -	}
 -
- 	/* Sorry, but no negative coords for src */
--	if (window->src_x < 0) window->src_x = 0;
--	if (window->src_y < 0) window->src_y = 0;
-+	if (f->src_x < 0)
-+		f->src_x = 0;
-+	if (f->src_y < 0)
-+		f->src_y = 0;
+-	kfree(state);
+-	kfree(client);
++	kfree(i2c_get_clientdata(client));
+ 	return 0;
+ }
  
- 	/* Can only reduce width down to 1/4 original size */
--	if ((osd_crop = window->src_w - ( 4 * window->dst_w )) > 0) {
--		window->src_x += osd_crop / 2;
--		window->src_w = (window->src_w - osd_crop) & ~3;
--		window->dst_w = window->src_w / 4;
--		window->dst_w += window->dst_w & 1;
-+	if ((osd_crop = f->src_w - 4 * f->dst_w) > 0) {
-+		f->src_x += osd_crop / 2;
-+		f->src_w = (f->src_w - osd_crop) & ~3;
-+		f->dst_w = f->src_w / 4;
-+		f->dst_w += f->dst_w & 1;
- 	}
+ /* ----------------------------------------------------------------------- */
  
- 	/* Can only reduce height down to 1/4 original size */
--	if (window->src_h / window->dst_h >= 2) {
--		/* Overflow may be because we're running progressive, so force mode switch */
--		window->interlaced_y = 1;
-+	if (f->src_h / f->dst_h >= 2) {
-+		/* Overflow may be because we're running progressive,
-+		   so force mode switch */
-+		f->interlaced_y = 1;
- 		/* Make sure we're still within limits for interlace */
--		if ((osd_crop = window->src_h - ( 4 * window->dst_h )) > 0) {
-+		if ((osd_crop = f->src_h - 4 * f->dst_h) > 0) {
- 			/* If we reach here we'll have to force the height. */
--			window->src_y += osd_crop / 2;
--			window->src_h = (window->src_h - osd_crop) & ~3;
--			window->dst_h = window->src_h / 4;
--			window->dst_h += window->dst_h & 1;
-+			f->src_y += osd_crop / 2;
-+			f->src_h = (f->src_h - osd_crop) & ~3;
-+			f->dst_h = f->src_h / 4;
-+			f->dst_h += f->dst_h & 1;
- 		}
- 	}
+-static struct i2c_driver i2c_driver_saa7127 = {
+-	.driver = {
+-		.name = "saa7127",
+-	},
+-	.id = I2C_DRIVERID_SAA7127,
+-	.attach_adapter = saa7127_probe,
+-	.detach_client = saa7127_detach,
++static struct v4l2_i2c_driver_data v4l2_i2c_data = {
++	.name = "saa7127",
++	.driverid = I2C_DRIVERID_SAA7127,
+ 	.command = saa7127_command,
++	.probe = saa7127_probe,
++	.remove = saa7127_remove,
+ };
  
- 	/* If there's nothing to safe to display, we may as well stop now */
--	if ((int)window->dst_w <= 2 || (int)window->dst_h <= 2 || (int)window->src_w <= 2 || (int)window->src_h <= 2) {
-+	if ((int)f->dst_w <= 2 || (int)f->dst_h <= 2 ||
-+	    (int)f->src_w <= 2 || (int)f->src_h <= 2) {
- 		return IVTV_YUV_UPDATE_INVALID;
- 	}
+-
+-/* ----------------------------------------------------------------------- */
+-
+-static int __init saa7127_init_module(void)
+-{
+-	return i2c_add_driver(&i2c_driver_saa7127);
+-}
+-
+-/* ----------------------------------------------------------------------- */
+-
+-static void __exit saa7127_cleanup_module(void)
+-{
+-	i2c_del_driver(&i2c_driver_saa7127);
+-}
+-
+-/* ----------------------------------------------------------------------- */
+-
+-module_init(saa7127_init_module);
+-module_exit(saa7127_cleanup_module);
+diff --git a/drivers/media/video/saa7134/Kconfig b/drivers/media/video/saa7134/Kconfig
+index 3aa8cb2..96bc3b1 100644
+--- a/drivers/media/video/saa7134/Kconfig
++++ b/drivers/media/video/saa7134/Kconfig
+@@ -4,6 +4,7 @@ config VIDEO_SAA7134
+ 	select VIDEOBUF_DMA_SG
+ 	select VIDEO_IR
+ 	select VIDEO_TUNER
++	select VIDEO_TVEEPROM
+ 	select CRC32
+ 	---help---
+ 	  This is a video4linux driver for Philips SAA713x based
+@@ -23,18 +24,6 @@ config VIDEO_SAA7134_ALSA
+ 	  To compile this driver as a module, choose M here: the
+ 	  module will be called saa7134-alsa.
  
- 	/* Ensure video remains inside OSD area */
--	osd_scale = (window->src_h << 16) / window->dst_h;
-+	osd_scale = (f->src_h << 16) / f->dst_h;
+-config VIDEO_SAA7134_OSS
+-	tristate "Philips SAA7134 DMA audio support (OSS, DEPRECATED)"
+-	depends on VIDEO_SAA7134 && SOUND_PRIME && !VIDEO_SAA7134_ALSA
+-	---help---
+-	  This is a video4linux driver for direct (DMA) audio in
+-	  Philips SAA713x based TV cards using OSS
+-
+-	  This is deprecated in favor of the ALSA module
+-
+-	  To compile this driver as a module, choose M here: the
+-	  module will be called saa7134-oss.
+-
+ config VIDEO_SAA7134_DVB
+ 	tristate "DVB/ATSC Support for saa7134 based TV cards"
+ 	depends on VIDEO_SAA7134 && DVB_CORE
+diff --git a/drivers/media/video/saa7134/Makefile b/drivers/media/video/saa7134/Makefile
+index c85c8a8..9aff937 100644
+--- a/drivers/media/video/saa7134/Makefile
++++ b/drivers/media/video/saa7134/Makefile
+@@ -7,7 +7,6 @@ obj-$(CONFIG_VIDEO_SAA7134) +=  saa7134.o saa7134-empress.o \
+ 				saa6752hs.o
  
--	if ((osd_crop = window->pan_y - window->dst_y) > 0) {
-+	if ((osd_crop = f->pan_y - f->dst_y) > 0) {
- 		/* Falls off the upper edge - crop */
--		window->src_y += (osd_scale * osd_crop) >> 16;
--		window->src_h -= (osd_scale * osd_crop) >> 16;
--		window->dst_h -= osd_crop;
--		window->dst_y = 0;
--	}
--	else {
--		window->dst_y -= window->pan_y;
-+		f->src_y += (osd_scale * osd_crop) >> 16;
-+		f->src_h -= (osd_scale * osd_crop) >> 16;
-+		f->dst_h -= osd_crop;
-+		f->dst_y = 0;
-+	} else {
-+		f->dst_y -= f->pan_y;
- 	}
+ obj-$(CONFIG_VIDEO_SAA7134_ALSA) += saa7134-alsa.o
+-obj-$(CONFIG_VIDEO_SAA7134_OSS) += saa7134-oss.o
  
--	if ((osd_crop = window->dst_h + window->dst_y - window->vis_h) > 0) {
-+	if ((osd_crop = f->dst_h + f->dst_y - f->vis_h) > 0) {
- 		/* Falls off the lower edge - crop */
--		window->dst_h -= osd_crop;
--		window->src_h -= (osd_scale * osd_crop) >> 16;
-+		f->dst_h -= osd_crop;
-+		f->src_h -= (osd_scale * osd_crop) >> 16;
- 	}
+ obj-$(CONFIG_VIDEO_SAA7134_DVB) += saa7134-dvb.o
  
--	osd_scale = (window->src_w << 16) / window->dst_w;
-+	osd_scale = (f->src_w << 16) / f->dst_w;
+diff --git a/drivers/media/video/saa7134/saa7134-alsa.c b/drivers/media/video/saa7134/saa7134-alsa.c
+index 4878f30..ba25310 100644
+--- a/drivers/media/video/saa7134/saa7134-alsa.c
++++ b/drivers/media/video/saa7134/saa7134-alsa.c
+@@ -1077,24 +1077,14 @@ static int saa7134_alsa_init(void)
+ 	struct saa7134_dev *dev = NULL;
+ 	struct list_head *list;
  
--	if ((osd_crop = window->pan_x - window->dst_x) > 0) {
-+	if ((osd_crop = f->pan_x - f->dst_x) > 0) {
- 		/* Fall off the left edge - crop */
--		window->src_x += (osd_scale * osd_crop) >> 16;
--		window->src_w -= (osd_scale * osd_crop) >> 16;
--		window->dst_w -= osd_crop;
--		window->dst_x = 0;
+-	if (!saa7134_dmasound_init && !saa7134_dmasound_exit) {
+-		saa7134_dmasound_init = alsa_device_init;
+-		saa7134_dmasound_exit = alsa_device_exit;
+-	} else {
+-		printk(KERN_WARNING "saa7134 ALSA: can't load, DMA sound handler already assigned (probably to OSS)\n");
+-		return -EBUSY;
 -	}
--	else {
--		window->dst_x -= window->pan_x;
-+		f->src_x += (osd_scale * osd_crop) >> 16;
-+		f->src_w -= (osd_scale * osd_crop) >> 16;
-+		f->dst_w -= osd_crop;
-+		f->dst_x = 0;
-+	} else {
-+		f->dst_x -= f->pan_x;
- 	}
- 
--	if ((osd_crop = window->dst_w + window->dst_x - window->vis_w) > 0) {
-+	if ((osd_crop = f->dst_w + f->dst_x - f->vis_w) > 0) {
- 		/* Falls off the right edge - crop */
--		window->dst_w -= osd_crop;
--		window->src_w -= (osd_scale * osd_crop) >> 16;
-+		f->dst_w -= osd_crop;
-+		f->src_w -= (osd_scale * osd_crop) >> 16;
- 	}
++	saa7134_dmasound_init = alsa_device_init;
++	saa7134_dmasound_exit = alsa_device_exit;
  
- 	/* The OSD can be moved. Track to it */
--	window->dst_x += itv->yuv_info.osd_x_offset;
--	window->dst_y += itv->yuv_info.osd_y_offset;
-+	f->dst_x += itv->yuv_info.osd_x_offset;
-+	f->dst_y += itv->yuv_info.osd_y_offset;
+ 	printk(KERN_INFO "saa7134 ALSA driver for DMA sound loaded\n");
  
- 	/* Width & height for both src & dst must be even.
- 	   Same for coordinates. */
--	window->dst_w &= ~1;
--	window->dst_x &= ~1;
-+	f->dst_w &= ~1;
-+	f->dst_x &= ~1;
+ 	list_for_each(list,&saa7134_devlist) {
+ 		dev = list_entry(list, struct saa7134_dev, devlist);
+-		if (dev->dmasound.priv_data == NULL) {
+-			alsa_device_init(dev);
+-		} else {
+-			printk(KERN_ERR "saa7134 ALSA: DMA sound is being handled by OSS. ignoring %s\n",dev->name);
+-			return -EBUSY;
+-		}
++		alsa_device_init(dev);
+ 	}
  
--	window->src_w += window->src_x & 1;
--	window->src_x &= ~1;
-+	f->src_w += f->src_x & 1;
-+	f->src_x &= ~1;
+ 	if (dev == NULL)
+diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c
+index 98c1b08..7d7f383 100644
+--- a/drivers/media/video/saa7134/saa7134-cards.c
++++ b/drivers/media/video/saa7134/saa7134-cards.c
+@@ -26,6 +26,7 @@
+ #include "saa7134-reg.h"
+ #include "saa7134.h"
+ #include <media/v4l2-common.h>
++#include <media/tveeprom.h>
  
--	window->src_w &= ~1;
--	window->dst_w &= ~1;
-+	f->src_w &= ~1;
-+	f->dst_w &= ~1;
+ /* commly used strings */
+ static char name_mute[]    = "mute";
+@@ -349,6 +350,10 @@ struct saa7134_board saa7134_boards[] = {
+ 			.name = name_radio,
+ 			.amux = LINE2,
+ 		},
++	       .mute = {
++		       .name = name_mute,
++		       .amux = TV,
++	       },
+ 	},
+ 	[SAA7134_BOARD_TVSTATION_RDS] = {
+ 		/* Typhoon TV Tuner RDS: Art.Nr. 50694 */
+@@ -565,6 +570,10 @@ struct saa7134_board saa7134_boards[] = {
+ 		.radio = {
+ 			.name   = name_radio,
+ 			.amux   = LINE2,
++	       },
++	       .mute = {
++		       .name = name_mute,
++		       .amux = TV,
+ 		},
+ 	},
+ 	[SAA7134_BOARD_TYPHOON_90031] = {
+@@ -3553,6 +3562,356 @@ struct saa7134_board saa7134_boards[] = {
+ 			.tv     = 1,
+ 		}},
+ 	},
++	[SAA7134_BOARD_BEHOLD_401] = {
++		.name           = "Beholder BeholdTV 401",
++		.audio_clock    = 0x00187de7,
++		.tuner_type     = TUNER_PHILIPS_FQ1216ME,
++		.radio_type     = UNSET,
++		.tuner_addr	= ADDR_UNSET,
++		.radio_addr	= ADDR_UNSET,
++		.inputs         = {{
++			.name = name_svideo,
++			.vmux = 8,
++			.amux = LINE1,
++		},{
++			.name = name_comp1,
++			.vmux = 1,
++			.amux = LINE1,
++		},{
++			.name = name_tv,
++			.vmux = 3,
++			.amux = LINE2,
++			.tv   = 1,
++		}},
++		.mute = {
++			.name = name_mute,
++			.amux = LINE1,
++		},
++	},
++	[SAA7134_BOARD_BEHOLD_403] = {
++		.name           = "Beholder BeholdTV 403",
++		.audio_clock    = 0x00187de7,
++		.tuner_type     = TUNER_PHILIPS_FQ1216ME,
++		.radio_type     = UNSET,
++		.tuner_addr	= ADDR_UNSET,
++		.radio_addr	= ADDR_UNSET,
++		.inputs         = {{
++			.name = name_svideo,
++			.vmux = 8,
++			.amux = LINE1,
++		},{
++			.name   = name_comp1,
++			.vmux   = 1,
++			.amux   = LINE1,
++		},{
++			.name = name_tv,
++			.vmux = 3,
++			.amux = LINE2,
++			.tv   = 1,
++		}},
++	},
++	[SAA7134_BOARD_BEHOLD_403FM] = {
++		.name           = "Beholder BeholdTV 403 FM",
++		.audio_clock    = 0x00187de7,
++		.tuner_type     = TUNER_PHILIPS_FQ1216ME,
++		.radio_type     = UNSET,
++		.tuner_addr	= ADDR_UNSET,
++		.radio_addr	= ADDR_UNSET,
++		.inputs         = {{
++			.name = name_svideo,
++			.vmux = 8,
++			.amux = LINE1,
++		},{
++			.name   = name_comp1,
++			.vmux   = 1,
++			.amux   = LINE1,
++		},{
++			.name = name_tv,
++			.vmux = 3,
++			.amux = LINE2,
++			.tv   = 1,
++		}},
++		.radio = {
++			.name = name_radio,
++			.amux = LINE2,
++		},
++	},
++	[SAA7134_BOARD_BEHOLD_405] = {
++		.name           = "Beholder BeholdTV 405",
++		.audio_clock    = 0x00187de7,
++		.tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
++		.radio_type     = UNSET,
++		.tuner_addr     = ADDR_UNSET,
++		.radio_addr     = ADDR_UNSET,
++		.tda9887_conf   = TDA9887_PRESENT,
++		.inputs         = {{
++			.name = name_svideo,
++			.vmux = 8,
++			.amux = LINE1,
++		},{
++			.name = name_comp1,
++			.vmux = 3,
++			.amux = LINE1,
++		},{
++			.name = name_tv,
++			.vmux = 3,
++			.amux = LINE2,
++			.tv   = 1,
++		}},
++	},
++	[SAA7134_BOARD_BEHOLD_405FM] = {
++		/* Sergey <skiv at orel.ru> */
++		.name           = "Beholder BeholdTV 405 FM",
++		.audio_clock    = 0x00187de7,
++		.tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
++		.radio_type     = UNSET,
++		.tuner_addr     = ADDR_UNSET,
++		.radio_addr     = ADDR_UNSET,
++		.tda9887_conf   = TDA9887_PRESENT,
++		.inputs         = {{
++			.name = name_svideo,
++			.vmux = 8,
++			.amux = LINE1,
++		},{
++			.name = name_comp1,
++			.vmux = 3,
++			.amux = LINE1,
++		},{
++			.name = name_tv,
++			.vmux = 3,
++			.amux = LINE2,
++			.tv   = 1,
++		}},
++		.radio = {
++			.name = name_radio,
++			.amux = LINE2,
++		},
++	},
++	[SAA7134_BOARD_BEHOLD_407] = {
++		.name 		= "Beholder BeholdTV 407",
++		.audio_clock 	= 0x00187de7,
++		.tuner_type 	= TUNER_PHILIPS_FM1216ME_MK3,
++		.radio_type 	= UNSET,
++		.tuner_addr 	= ADDR_UNSET,
++		.radio_addr 	= ADDR_UNSET,
++		.tda9887_conf 	= TDA9887_PRESENT,
++		.gpiomask = 0xc0c000,
++		.inputs = {{
++			.name = name_svideo,
++			.vmux = 8,
++			.amux = LINE1,
++			.gpio = 0xc0c000,
++		},{
++			.name = name_comp1,
++			.vmux = 1,
++			.amux = LINE1,
++			.gpio = 0xc0c000,
++		},{
++			.name = name_tv,
++			.vmux = 3,
++			.amux = TV,
++			.tv = 1,
++			.gpio = 0xc0c000,
++		}},
++	},
++	[SAA7134_BOARD_BEHOLD_407FM] = {
++		.name 		= "Beholder BeholdTV 407 FM",
++		.audio_clock 	= 0x00187de7,
++		.tuner_type 	= TUNER_PHILIPS_FM1216ME_MK3,
++		.radio_type 	= UNSET,
++		.tuner_addr 	= ADDR_UNSET,
++		.radio_addr 	= ADDR_UNSET,
++		.tda9887_conf 	= TDA9887_PRESENT,
++		.gpiomask = 0xc0c000,
++		.inputs = {{
++			.name = name_svideo,
++			.vmux = 8,
++			.amux = LINE1,
++			.gpio = 0xc0c000,
++		},{
++			.name = name_comp1,
++			.vmux = 1,
++			.amux = LINE1,
++			.gpio = 0xc0c000,
++		},{
++			.name = name_tv,
++			.vmux = 3,
++			.amux = TV,
++			.tv = 1,
++			.gpio = 0xc0c000,
++		}},
++		.radio = {
++			.name = name_radio,
++			.amux = LINE2,
++			.gpio = 0xc0c000,
++		},
++	},
++	[SAA7134_BOARD_BEHOLD_409] = {
++		.name           = "Beholder BeholdTV 409",
++		.audio_clock    = 0x00187de7,
++		.tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
++		.radio_type     = UNSET,
++		.tuner_addr     = ADDR_UNSET,
++		.radio_addr     = ADDR_UNSET,
++		.tda9887_conf   = TDA9887_PRESENT,
++		.inputs         = {{
++			.name = name_tv,
++			.vmux = 3,
++			.amux = TV,
++			.tv   = 1,
++		},{
++			.name = name_comp1,
++			.vmux = 1,
++			.amux = LINE1,
++		},{
++			.name = name_svideo,
++			.vmux = 8,
++			.amux = LINE1,
++		}},
++	},
++	[SAA7134_BOARD_BEHOLD_505FM] = {
++		.name           = "Beholder BeholdTV 505 FM/RDS",
++		.audio_clock    = 0x00200000,
++		.tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
++		.radio_type     = UNSET,
++		.tuner_addr     = ADDR_UNSET,
++		.radio_addr     = ADDR_UNSET,
++		.tda9887_conf   = TDA9887_PRESENT,
++		.inputs         = {{
++			.name = name_tv,
++			.vmux = 3,
++			.amux = LINE2,
++			.tv   = 1,
++		},{
++			.name = name_comp1,
++			.vmux = 1,
++			.amux = LINE1,
++		},{
++			.name = name_svideo,
++			.vmux = 8,
++			.amux = LINE1,
++		}},
++		.mute = {
++			.name = name_mute,
++			.amux = LINE1,
++		},
++		.radio = {
++			.name = name_radio,
++			.amux = LINE2,
++		},
++	},
++	[SAA7134_BOARD_BEHOLD_507_9FM] = {
++		.name           = "Beholder BeholdTV 507 FM/RDS / BeholdTV 509 FM",
++		.audio_clock    = 0x00187de7,
++		.tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
++		.radio_type     = UNSET,
++		.tuner_addr     = ADDR_UNSET,
++		.radio_addr     = ADDR_UNSET,
++		.tda9887_conf   = TDA9887_PRESENT,
++		.inputs         = {{
++			.name = name_tv,
++			.vmux = 3,
++			.amux = TV,
++			.tv   = 1,
++		},{
++			.name = name_comp1,
++			.vmux = 1,
++			.amux = LINE1,
++		},{
++			.name = name_svideo,
++			.vmux = 8,
++			.amux = LINE1,
++		}},
++			.radio = {
++			.name = name_radio,
++			.amux = LINE2,
++		},
++	},
++	[SAA7134_BOARD_BEHOLD_COLUMBUS_TVFM] = {
++		.name           = "Beholder BeholdTV Columbus TVFM",
++		.audio_clock    = 0x00187de7,
++		.tuner_type     = TUNER_ALPS_TSBE5_PAL,
++		.radio_type     = UNSET,
++		.tuner_addr     = ADDR_UNSET,
++		.radio_addr     = ADDR_UNSET,
++		.tda9887_conf   = TDA9887_PRESENT,
++		.inputs         = {{
++			.name = name_tv,
++			.vmux = 3,
++			.amux = TV,
++			.tv   = 1,
++		},{
++			.name = name_comp1,
++			.vmux = 1,
++			.amux = LINE1,
++		},{
++			.name = name_svideo,
++			.vmux = 8,
++			.amux = LINE1,
++		}},
++		.radio = {
++			.name = name_radio,
++			.amux = LINE2,
++		},
++	},
++	[SAA7134_BOARD_BEHOLD_607_9FM] = {
++		/* Andrey Melnikoff <temnota at kmv.ru> */
++		.name           = "Beholder BeholdTV 607 / BeholdTV 609",
++		.audio_clock    = 0x00187de7,
++		.tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
++		.radio_type     = UNSET,
++		.tuner_addr     = ADDR_UNSET,
++		.radio_addr     = ADDR_UNSET,
++		.tda9887_conf   = TDA9887_PRESENT,
++		.inputs         = {{
++			.name = name_tv,
++			.vmux = 3,
++			.amux = TV,
++			.tv   = 1,
++		},{
++			.name = name_comp1,
++			.vmux = 1,
++			.amux = LINE1,
++		},{
++			.name = name_svideo,
++			.vmux = 8,
++			.amux = LINE1,
++		}},
++		.radio = {
++			.name = name_radio,
++			.amux = LINE2,
++		},
++	},
++	[SAA7134_BOARD_BEHOLD_M6] = {
++		/* Igor Kuznetsov <igk at igk.ru> */
++		/* Andrey Melnikoff <temnota at kmv.ru> */
++		.name           = "Beholder BeholdTV M6 / BeholdTV M6 Extra",
++		.audio_clock    = 0x00187de7,
++		.tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
++		.radio_type     = UNSET,
++		.tuner_addr     = ADDR_UNSET,
++		.radio_addr     = ADDR_UNSET,
++		.tda9887_conf   = TDA9887_PRESENT,
++		.inputs         = {{
++			.name = name_tv,
++			.vmux = 3,
++			.amux = TV,
++			.tv   = 1,
++		},{
++			.name = name_comp1,
++			.vmux = 1,
++			.amux = LINE1,
++		},{
++			.name = name_svideo,
++			.vmux = 8,
++			.amux = LINE1,
++		}},
++		.radio = {
++			.name = name_radio,
++			.amux = LINE2,
++		},
++		.mpeg  = SAA7134_MPEG_EMPRESS,
++	},
+ };
  
--	window->dst_h &= ~1;
--	window->dst_y &= ~1;
-+	f->dst_h &= ~1;
-+	f->dst_y &= ~1;
+ const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards);
+@@ -4033,7 +4392,13 @@ struct pci_device_id saa7134_pci_tbl[] = {
+ 		.vendor       = PCI_VENDOR_ID_PHILIPS,
+ 		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ 		.subvendor    = 0x1462,
+-		.subdevice    = 0x6231,
++		.subdevice    = 0x6231, /* tda8275a, ks003 IR */
++		.driver_data  = SAA7134_BOARD_MSI_TVATANYWHERE_PLUS,
++	},{
++		.vendor       = PCI_VENDOR_ID_PHILIPS,
++		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
++		.subvendor    = 0x1462,
++		.subdevice    = 0x8624, /* tda8275, ks003 IR */
+ 		.driver_data  = SAA7134_BOARD_MSI_TVATANYWHERE_PLUS,
+ 	},{
+ 		.vendor       = PCI_VENDOR_ID_PHILIPS,
+@@ -4207,11 +4572,41 @@ struct pci_device_id saa7134_pci_tbl[] = {
+ 		.vendor       = PCI_VENDOR_ID_PHILIPS,
+ 		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ 		.subvendor    = 0x0070,
++		.subdevice    = 0x6700,
++		.driver_data  = SAA7134_BOARD_HAUPPAUGE_HVR1110,
++	},{
++		.vendor       = PCI_VENDOR_ID_PHILIPS,
++		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
++		.subvendor    = 0x0070,
+ 		.subdevice    = 0x6701,
+ 		.driver_data  = SAA7134_BOARD_HAUPPAUGE_HVR1110,
+ 	},{
+ 		.vendor       = PCI_VENDOR_ID_PHILIPS,
+ 		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
++		.subvendor    = 0x0070,
++		.subdevice    = 0x6702,
++		.driver_data  = SAA7134_BOARD_HAUPPAUGE_HVR1110,
++	},{
++		.vendor       = PCI_VENDOR_ID_PHILIPS,
++		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
++		.subvendor    = 0x0070,
++		.subdevice    = 0x6703,
++		.driver_data  = SAA7134_BOARD_HAUPPAUGE_HVR1110,
++	},{
++		.vendor       = PCI_VENDOR_ID_PHILIPS,
++		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
++		.subvendor    = 0x0070,
++		.subdevice    = 0x6704,
++		.driver_data  = SAA7134_BOARD_HAUPPAUGE_HVR1110,
++	},{
++		.vendor       = PCI_VENDOR_ID_PHILIPS,
++		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
++		.subvendor    = 0x0070,
++		.subdevice    = 0x6705,
++		.driver_data  = SAA7134_BOARD_HAUPPAUGE_HVR1110,
++	},{
++		.vendor       = PCI_VENDOR_ID_PHILIPS,
++		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ 		.subvendor    = 0x153b,
+ 		.subdevice    = 0x1172,
+ 		.driver_data  = SAA7134_BOARD_CINERGY_HT_PCMCIA,
+@@ -4289,6 +4684,162 @@ struct pci_device_id saa7134_pci_tbl[] = {
+ 		.driver_data  = SAA7134_BOARD_AVERMEDIA_SUPER_007,
+ 	},{
+ 		.vendor       = PCI_VENDOR_ID_PHILIPS,
++		.device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
++		.subvendor    = 0x0000,
++		.subdevice    = 0x4016,
++		.driver_data  = SAA7134_BOARD_BEHOLD_401,
++	},{
++		.vendor       = PCI_VENDOR_ID_PHILIPS,
++		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
++		.subvendor    = 0x0000,
++		.subdevice    = 0x4036,
++		.driver_data  = SAA7134_BOARD_BEHOLD_403,
++	},{
++		.vendor       = PCI_VENDOR_ID_PHILIPS,
++		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
++		.subvendor    = 0x0000,
++		.subdevice    = 0x4037,
++		.driver_data  = SAA7134_BOARD_BEHOLD_403FM,
++	},{
++		.vendor       = PCI_VENDOR_ID_PHILIPS,
++		.device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
++		.subvendor    = 0x0000,
++		.subdevice    = 0x4050,
++		.driver_data  = SAA7134_BOARD_BEHOLD_405,
++	},{
++		.vendor       = PCI_VENDOR_ID_PHILIPS,
++		.device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
++		.subvendor    = 0x0000,
++		.subdevice    = 0x4051,
++		.driver_data  = SAA7134_BOARD_BEHOLD_405FM,
++	},{
++		.vendor       = PCI_VENDOR_ID_PHILIPS,
++		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
++		.subvendor    = 0x0000,
++		.subdevice    = 0x4070,
++		.driver_data  = SAA7134_BOARD_BEHOLD_407,
++	},{
++		.vendor       = PCI_VENDOR_ID_PHILIPS,
++		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
++		.subvendor    = 0x0000,
++		.subdevice    = 0x4071,
++		.driver_data  = SAA7134_BOARD_BEHOLD_407FM,
++	},{
++		.vendor       = PCI_VENDOR_ID_PHILIPS,
++		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
++		.subvendor    = 0x0000,
++		.subdevice    = 0x4090,
++		.driver_data  = SAA7134_BOARD_BEHOLD_409,
++	},{
++		.vendor       = PCI_VENDOR_ID_PHILIPS,
++		.device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
++		.subvendor    = 0x0000,
++		.subdevice    = 0x5051,
++		.driver_data  = SAA7134_BOARD_BEHOLD_505FM,
++	},{
++		.vendor       = PCI_VENDOR_ID_PHILIPS,
++		.device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
++		.subvendor    = 0x0000,
++		.subdevice    = 0x505B,
++		.driver_data  = SAA7134_BOARD_BEHOLD_505FM,
++	},{
++		.vendor       = PCI_VENDOR_ID_PHILIPS,
++		.device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
++		.subvendor    = 0x5ace,
++		.subdevice    = 0x5050,
++		.driver_data  = SAA7134_BOARD_BEHOLD_505FM,
++	},{
++		.vendor       = PCI_VENDOR_ID_PHILIPS,
++		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
++		.subvendor    = 0x0000,
++		.subdevice    = 0x5071,
++		.driver_data  = SAA7134_BOARD_BEHOLD_507_9FM,
++	},{
++		.vendor       = PCI_VENDOR_ID_PHILIPS,
++		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
++		.subvendor    = 0x0000,
++		.subdevice    = 0x507B,
++		.driver_data  = SAA7134_BOARD_BEHOLD_507_9FM,
++	},{
++		.vendor       = PCI_VENDOR_ID_PHILIPS,
++		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
++		.subvendor    = 0x5ace,
++		.subdevice    = 0x5070,
++		.driver_data  = SAA7134_BOARD_BEHOLD_507_9FM,
++	},{
++		.vendor       = PCI_VENDOR_ID_PHILIPS,
++		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
++		.subvendor    = 0x5ace,
++		.subdevice    = 0x5090,
++		.driver_data  = SAA7134_BOARD_BEHOLD_507_9FM,
++	},{
++		.vendor       = PCI_VENDOR_ID_PHILIPS,
++		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
++		.subvendor    = 0x0000,
++		.subdevice    = 0x5201,
++		.driver_data  = SAA7134_BOARD_BEHOLD_COLUMBUS_TVFM,
++	},{
++		.vendor       = PCI_VENDOR_ID_PHILIPS,
++		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
++		.subvendor    = 0x5ace,
++		.subdevice    = 0x6070,
++		.driver_data  = SAA7134_BOARD_BEHOLD_607_9FM,
++	},{
++		.vendor       = PCI_VENDOR_ID_PHILIPS,
++		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
++		.subvendor    = 0x5ace,
++		.subdevice    = 0x6071,
++		.driver_data  = SAA7134_BOARD_BEHOLD_607_9FM,
++	},{
++		.vendor       = PCI_VENDOR_ID_PHILIPS,
++		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
++		.subvendor    = 0x5ace,
++		.subdevice    = 0x6072,
++		.driver_data  = SAA7134_BOARD_BEHOLD_607_9FM,
++	},{
++		.vendor       = PCI_VENDOR_ID_PHILIPS,
++		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
++		.subvendor    = 0x5ace,
++		.subdevice    = 0x6073,
++		.driver_data  = SAA7134_BOARD_BEHOLD_607_9FM,
++	},{
++		.vendor       = PCI_VENDOR_ID_PHILIPS,
++		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
++		.subvendor    = 0x5ace,
++		.subdevice    = 0x6090,
++		.driver_data  = SAA7134_BOARD_BEHOLD_607_9FM,
++	},{
++		.vendor       = PCI_VENDOR_ID_PHILIPS,
++		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
++		.subvendor    = 0x5ace,
++		.subdevice    = 0x6091,
++		.driver_data  = SAA7134_BOARD_BEHOLD_607_9FM,
++	},{
++		.vendor       = PCI_VENDOR_ID_PHILIPS,
++		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
++		.subvendor    = 0x5ace,
++		.subdevice    = 0x6092,
++		.driver_data  = SAA7134_BOARD_BEHOLD_607_9FM,
++	},{
++		.vendor       = PCI_VENDOR_ID_PHILIPS,
++		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
++		.subvendor    = 0x5ace,
++		.subdevice    = 0x6093,
++		.driver_data  = SAA7134_BOARD_BEHOLD_607_9FM,
++	},{
++		.vendor       = PCI_VENDOR_ID_PHILIPS,
++		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
++		.subvendor    = 0x5ace,
++		.subdevice    = 0x6190,
++		.driver_data  = SAA7134_BOARD_BEHOLD_M6,
++	},{
++		.vendor       = PCI_VENDOR_ID_PHILIPS,
++		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
++		.subvendor    = 0x5ace,
++		.subdevice    = 0x6193,
++		.driver_data  = SAA7134_BOARD_BEHOLD_M6,
++	},{
++		.vendor       = PCI_VENDOR_ID_PHILIPS,
+ 		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ 		.subvendor    = 0x4e42,
+ 		.subdevice    = 0x3502,
+@@ -4351,6 +4902,34 @@ static void board_flyvideo(struct saa7134_dev *dev)
  
--	window->src_h += window->src_y & 1;
--	window->src_y &= ~1;
-+	f->src_h += f->src_y & 1;
-+	f->src_y &= ~1;
+ /* ----------------------------------------------------------- */
  
--	window->src_h &= ~1;
--	window->dst_h &= ~1;
-+	f->src_h &= ~1;
-+	f->dst_h &= ~1;
++static void hauppauge_eeprom(struct saa7134_dev *dev, u8 *eeprom_data)
++{
++	struct tveeprom tv;
++
++	tveeprom_hauppauge_analog(&dev->i2c_client, &tv, eeprom_data);
++
++	/* Make sure we support the board model */
++	switch (tv.model) {
++	case 67019: /* WinTV-HVR1110 (Retail, IR Blaster, hybrid, FM, SVid/Comp, 3.5mm audio in) */
++	case 67109: /* WinTV-HVR1000 (Retail, IR Receive, analog, no FM, SVid/Comp, 3.5mm audio in) */
++	case 67559: /* WinTV-HVR1110 (OEM, no IR, hybrid, FM, SVid/Comp, RCA aud) */
++	case 67569: /* WinTV-HVR1110 (OEM, no IR, hybrid, FM) */
++	case 67579: /* WinTV-HVR1110 (OEM, no IR, hybrid, no FM) */
++	case 67589: /* WinTV-HVR1110 (OEM, no IR, hybrid, no FM, SVid/Comp, RCA aud) */
++	case 67599: /* WinTV-HVR1110 (OEM, no IR, hybrid, no FM, SVid/Comp, RCA aud) */
++		break;
++	default:
++		printk(KERN_WARNING "%s: warning: "
++		       "unknown hauppauge model #%d\n", dev->name, tv.model);
++		break;
++	}
++
++	printk(KERN_INFO "%s: hauppauge eeprom: model=%d\n",
++	       dev->name, tv.model);
++}
++
++/* ----------------------------------------------------------- */
++
+ int saa7134_board_init1(struct saa7134_dev *dev)
+ {
+ 	/* Always print gpio, often manufacturers encode tuner type and other info. */
+@@ -4406,6 +4985,16 @@ int saa7134_board_init1(struct saa7134_dev *dev)
+ 	case SAA7134_BOARD_ENCORE_ENLTV:
+ 	case SAA7134_BOARD_ENCORE_ENLTV_FM:
+ 	case SAA7134_BOARD_10MOONSTVMASTER3:
++	case SAA7134_BOARD_BEHOLD_401:
++	case SAA7134_BOARD_BEHOLD_403:
++	case SAA7134_BOARD_BEHOLD_403FM:
++	case SAA7134_BOARD_BEHOLD_405:
++	case SAA7134_BOARD_BEHOLD_405FM:
++	case SAA7134_BOARD_BEHOLD_407:
++	case SAA7134_BOARD_BEHOLD_407FM:
++	case SAA7134_BOARD_BEHOLD_409:
++	case SAA7134_BOARD_BEHOLD_505FM:
++	case SAA7134_BOARD_BEHOLD_507_9FM:
+ 		dev->has_remote = SAA7134_REMOTE_GPIO;
+ 		break;
+ 	case SAA7134_BOARD_FLYDVBS_LR300:
+@@ -4445,6 +5034,7 @@ int saa7134_board_init1(struct saa7134_dev *dev)
+ 		saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x08000000, 0x00000000);
+ 		break;
+ 	case SAA7134_BOARD_AVERMEDIA_CARDBUS:
++	case SAA7134_BOARD_BEHOLD_COLUMBUS_TVFM:
+ 		/* power-up tuner chip */
+ 		saa_andorl(SAA7134_GPIO_GPMODE0 >> 2,   0xffffffff, 0xffffffff);
+ 		saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0xffffffff, 0xffffffff);
+@@ -4466,6 +5056,8 @@ int saa7134_board_init1(struct saa7134_dev *dev)
+ 	case SAA7134_BOARD_PINNACLE_PCTV_310i:
+ 	case SAA7134_BOARD_UPMOST_PURPLE_TV:
+ 	case SAA7134_BOARD_HAUPPAUGE_HVR1110:
++	case SAA7134_BOARD_BEHOLD_607_9FM:
++	case SAA7134_BOARD_BEHOLD_M6:
+ 		dev->has_remote = SAA7134_REMOTE_I2C;
+ 		break;
+ 	case SAA7134_BOARD_AVERMEDIA_A169_B:
+@@ -4477,6 +5069,7 @@ int saa7134_board_init1(struct saa7134_dev *dev)
+ 		break;
+ 	case SAA7134_BOARD_AVERMEDIA_M102:
+ 		/* enable tuner */
++	       dev->has_remote = SAA7134_REMOTE_GPIO;
+ 		saa_andorl(SAA7134_GPIO_GPMODE0 >> 2,   0x8c040007, 0x8c040007);
+ 		saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x0c0007cd, 0x0c0007cd);
+ 		break;
+@@ -4570,8 +5163,17 @@ int saa7134_board_init2(struct saa7134_dev *dev)
  
--	/* Due to rounding, we may have reduced the output size to <1/4 of the source
--	   Check again, but this time just resize. Don't change source coordinates */
--	if (window->dst_w < window->src_w / 4) {
--		window->src_w &= ~3;
--		window->dst_w = window->src_w / 4;
--		window->dst_w += window->dst_w & 1;
-+	/* Due to rounding, we may have reduced the output size to <1/4 of
-+	   the source. Check again, but this time just resize. Don't change
-+	   source coordinates */
-+	if (f->dst_w < f->src_w / 4) {
-+		f->src_w &= ~3;
-+		f->dst_w = f->src_w / 4;
-+		f->dst_w += f->dst_w & 1;
- 	}
--	if (window->dst_h < window->src_h / 4) {
--		window->src_h &= ~3;
--		window->dst_h = window->src_h / 4;
--		window->dst_h += window->dst_h & 1;
-+	if (f->dst_h < f->src_h / 4) {
-+		f->src_h &= ~3;
-+		f->dst_h = f->src_h / 4;
-+		f->dst_h += f->dst_h & 1;
- 	}
+ 		printk(KERN_INFO "%s Tuner type is %d\n", dev->name, dev->tuner_type);
+ 		if (dev->tuner_type == TUNER_PHILIPS_FMD1216ME_MK3) {
+-			dev->tda9887_conf = TDA9887_PRESENT | TDA9887_PORT1_ACTIVE | TDA9887_PORT2_ACTIVE;
+-			saa7134_i2c_call_clients(dev,TDA9887_SET_CONFIG, &dev->tda9887_conf);
++			struct v4l2_priv_tun_config tda9887_cfg;
++
++			tda9887_cfg.tuner = TUNER_TDA9887;
++			tda9887_cfg.priv  = &dev->tda9887_conf;
++
++			dev->tda9887_conf = TDA9887_PRESENT      |
++					    TDA9887_PORT1_ACTIVE |
++					    TDA9887_PORT2_ACTIVE;
++
++			saa7134_i2c_call_clients(dev, TUNER_SET_CONFIG,
++						 &tda9887_cfg);
+ 		}
  
- 	/* Check again. If there's nothing to safe to display, stop now */
--	if ((int)window->dst_w <= 2 || (int)window->dst_h <= 2 || (int)window->src_w <= 2 || (int)window->src_h <= 2) {
-+	if ((int)f->dst_w <= 2 || (int)f->dst_h <= 2 ||
-+	    (int)f->src_w <= 2 || (int)f->src_h <= 2) {
- 		return IVTV_YUV_UPDATE_INVALID;
- 	}
+ 		tun_setup.mode_mask = T_RADIO | T_ANALOG_TV | T_DIGITAL_TV;
+@@ -4601,7 +5203,6 @@ int saa7134_board_init2(struct saa7134_dev *dev)
+ 		break;
+ 	case SAA7134_BOARD_PHILIPS_TIGER:
+ 	case SAA7134_BOARD_PHILIPS_TIGER_S:
+-	case SAA7134_BOARD_AVERMEDIA_SUPER_007:
+ 		{
+ 		u8 data[] = { 0x3c, 0x33, 0x60};
+ 		struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)};
+@@ -4622,13 +5223,16 @@ int saa7134_board_init2(struct saa7134_dev *dev)
+ 		i2c_transfer(&dev->i2c_adap, &msg, 1);
+ 		}
+ 		break;
++	case SAA7134_BOARD_HAUPPAUGE_HVR1110:
++		hauppauge_eeprom(dev, dev->eedata+0x80);
++		/* break intentionally omitted */
+ 	case SAA7134_BOARD_PINNACLE_PCTV_310i:
+ 	case SAA7134_BOARD_KWORLD_DVBT_210:
+ 	case SAA7134_BOARD_TEVION_DVBT_220RF:
+ 	case SAA7134_BOARD_ASUSTeK_P7131_DUAL:
+ 	case SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA:
+ 	case SAA7134_BOARD_MEDION_MD8800_QUADRO:
+-	case SAA7134_BOARD_HAUPPAUGE_HVR1110:
++       case SAA7134_BOARD_AVERMEDIA_SUPER_007:
+ 		/* this is a hybrid board, initialize to analog mode
+ 		 * and configure firmware eeprom address
+ 		 */
+diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c
+index 4f0a915..52baa4f 100644
+--- a/drivers/media/video/saa7134/saa7134-core.c
++++ b/drivers/media/video/saa7134/saa7134-core.c
+@@ -294,7 +294,7 @@ void saa7134_dma_free(struct videobuf_queue *q,struct saa7134_buf *buf)
+ 	videobuf_waiton(&buf->vb,0,0);
+ 	videobuf_dma_unmap(q, dma);
+ 	videobuf_dma_free(dma);
+-	buf->vb.state = STATE_NEEDS_INIT;
++	buf->vb.state = VIDEOBUF_NEEDS_INIT;
+ }
  
- 	/* Both x offset & width are linked, so they have to be done together */
--	if ((itv->yuv_info.old_frame_info.dst_w != window->dst_w) ||
--	    (itv->yuv_info.old_frame_info.src_w != window->src_w) ||
--	    (itv->yuv_info.old_frame_info.dst_x != window->dst_x) ||
--	    (itv->yuv_info.old_frame_info.src_x != window->src_x) ||
--	    (itv->yuv_info.old_frame_info.pan_x != window->pan_x) ||
--	    (itv->yuv_info.old_frame_info.vis_w != window->vis_w)) {
-+	if ((of->dst_w != f->dst_w) || (of->src_w != f->src_w) ||
-+	    (of->dst_x != f->dst_x) || (of->src_x != f->src_x) ||
-+	    (of->pan_x != f->pan_x) || (of->vis_w != f->vis_w)) {
- 		yuv_update |= IVTV_YUV_UPDATE_HORIZONTAL;
+ /* ------------------------------------------------------------------ */
+@@ -313,7 +313,7 @@ int saa7134_buffer_queue(struct saa7134_dev *dev,
+ 			buf->activate(dev,buf,NULL);
+ 		} else if (list_empty(&q->queue)) {
+ 			list_add_tail(&buf->vb.queue,&q->queue);
+-			buf->vb.state = STATE_QUEUED;
++			buf->vb.state = VIDEOBUF_QUEUED;
+ 		} else {
+ 			next = list_entry(q->queue.next,struct saa7134_buf,
+ 					  vb.queue);
+@@ -322,7 +322,7 @@ int saa7134_buffer_queue(struct saa7134_dev *dev,
+ 		}
+ 	} else {
+ 		list_add_tail(&buf->vb.queue,&q->queue);
+-		buf->vb.state = STATE_QUEUED;
++		buf->vb.state = VIDEOBUF_QUEUED;
  	}
- 
--	if ((itv->yuv_info.old_frame_info.src_h != window->src_h) ||
--	    (itv->yuv_info.old_frame_info.dst_h != window->dst_h) ||
--	    (itv->yuv_info.old_frame_info.dst_y != window->dst_y) ||
--	    (itv->yuv_info.old_frame_info.src_y != window->src_y) ||
--	    (itv->yuv_info.old_frame_info.pan_y != window->pan_y) ||
--	    (itv->yuv_info.old_frame_info.vis_h != window->vis_h) ||
--	    (itv->yuv_info.old_frame_info.lace_mode != window->lace_mode) ||
--	    (itv->yuv_info.old_frame_info.interlaced_y != window->interlaced_y) ||
--	    (itv->yuv_info.old_frame_info.interlaced_uv != window->interlaced_uv)) {
-+	if ((of->src_h != f->src_h) || (of->dst_h != f->dst_h) ||
-+	    (of->dst_y != f->dst_y) || (of->src_y != f->src_y) ||
-+	    (of->pan_y != f->pan_y) || (of->vis_h != f->vis_h) ||
-+	    (of->lace_mode != f->lace_mode) ||
-+	    (of->interlaced_y != f->interlaced_y) ||
-+	    (of->interlaced_uv != f->interlaced_uv)) {
- 		yuv_update |= IVTV_YUV_UPDATE_VERTICAL;
+ 	return 0;
+ }
+@@ -387,7 +387,7 @@ void saa7134_buffer_timeout(unsigned long data)
+ 	   try to start over with the next one. */
+ 	if (q->curr) {
+ 		dprintk("timeout on %p\n",q->curr);
+-		saa7134_buffer_finish(dev,q,STATE_ERROR);
++		saa7134_buffer_finish(dev,q,VIDEOBUF_ERROR);
  	}
+ 	saa7134_buffer_next(dev,q);
+ 	spin_unlock_irqrestore(&dev->slock,flags);
+@@ -395,8 +395,8 @@ void saa7134_buffer_timeout(unsigned long data)
  
-@@ -820,24 +782,24 @@ static u32 ivtv_yuv_window_setup (struct ivtv *itv, struct yuv_frame_info *windo
- }
+ /* resends a current buffer in queue after resume */
  
- /* Update the scaling register to the requested value */
--void ivtv_yuv_work_handler (struct ivtv *itv)
-+void ivtv_yuv_work_handler(struct ivtv *itv)
+-int saa7134_buffer_requeue(struct saa7134_dev *dev,
+-			 struct saa7134_dmaqueue *q)
++static int saa7134_buffer_requeue(struct saa7134_dev *dev,
++				  struct saa7134_dmaqueue *q)
  {
--	struct yuv_frame_info window;
-+	struct yuv_playback_info *yi = &itv->yuv_info;
-+	struct yuv_frame_info f;
-+	int frame = yi->update_frame;
- 	u32 yuv_update;
+ 	struct saa7134_buf *buf, *next;
  
--	int frame = itv->yuv_info.update_frame;
--
--/*	IVTV_DEBUG_YUV("Update yuv registers for frame %d\n",frame); */
--	memcpy(&window, &itv->yuv_info.new_frame_info[frame], sizeof (window));
-+	IVTV_DEBUG_YUV("Update yuv registers for frame %d\n", frame);
-+	f = yi->new_frame_info[frame];
+@@ -834,6 +834,7 @@ static struct video_device *vdev_init(struct saa7134_dev *dev,
+ 	vfd->minor   = -1;
+ 	vfd->dev     = &dev->pci->dev;
+ 	vfd->release = video_device_release;
++	vfd->debug   = video_debug;
+ 	snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)",
+ 		 dev->name, type, saa7134_boards[dev->board].name);
+ 	return vfd;
+@@ -1052,7 +1053,9 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
+ 	printk(KERN_INFO "%s: registered device video%d [v4l2]\n",
+ 	       dev->name,dev->video_dev->minor & 0x1f);
  
- 	/* Update the osd pan info */
--	window.pan_x = itv->yuv_info.osd_x_pan;
--	window.pan_y = itv->yuv_info.osd_y_pan;
--	window.vis_w = itv->yuv_info.osd_vis_w;
--	window.vis_h = itv->yuv_info.osd_vis_h;
-+	f.pan_x = yi->osd_x_pan;
-+	f.pan_y = yi->osd_y_pan;
-+	f.vis_w = yi->osd_vis_w;
-+	f.vis_h = yi->osd_vis_h;
+-	dev->vbi_dev = vdev_init(dev,&saa7134_vbi_template,"vbi");
++	dev->vbi_dev = vdev_init(dev, &saa7134_video_template, "vbi");
++	dev->vbi_dev->type = VID_TYPE_TUNER | VID_TYPE_TELETEXT;
++
+ 	err = video_register_device(dev->vbi_dev,VFL_TYPE_VBI,
+ 				    vbi_nr[dev->nr]);
+ 	if (err < 0)
+@@ -1181,8 +1184,13 @@ static int saa7134_suspend(struct pci_dev *pci_dev , pm_message_t state)
+ 	saa_writel(SAA7134_IRQ2, 0);
+ 	saa_writel(SAA7134_MAIN_CTRL, 0);
  
- 	/* Calculate the display window coordinates. Exit if nothing left */
--	if (!(yuv_update = ivtv_yuv_window_setup (itv, &window)))
-+	if (!(yuv_update = ivtv_yuv_window_setup(itv, &f)))
- 		return;
+-	synchronize_irq(pci_dev->irq);
+ 	dev->insuspend = 1;
++	synchronize_irq(pci_dev->irq);
++
++	/* ACK interrupts once more, just in case,
++		since the IRQ handler won't ack them anymore*/
++
++	saa_writel(SAA7134_IRQ_REPORT, saa_readl(SAA7134_IRQ_REPORT));
  
- 	if (yuv_update & IVTV_YUV_UPDATE_INVALID) {
-@@ -846,16 +808,15 @@ void ivtv_yuv_work_handler (struct ivtv *itv)
- 		write_reg(0x00108080, 0x2898);
+ 	/* Disable timeout timers - if we have active buffers, we will
+ 	   fill them on resume*/
+@@ -1194,10 +1202,10 @@ static int saa7134_suspend(struct pci_dev *pci_dev , pm_message_t state)
+ 	if (dev->remote)
+ 		saa7134_ir_stop(dev);
  
- 		if (yuv_update & IVTV_YUV_UPDATE_HORIZONTAL)
--			ivtv_yuv_handle_horizontal(itv, &window);
-+			ivtv_yuv_handle_horizontal(itv, &f);
+-	pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state));
+ 	pci_save_state(pci_dev);
++	pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state));
  
- 		if (yuv_update & IVTV_YUV_UPDATE_VERTICAL)
--			ivtv_yuv_handle_vertical(itv, &window);
-+			ivtv_yuv_handle_vertical(itv, &f);
- 	}
--
--	memcpy(&itv->yuv_info.old_frame_info, &window, sizeof (itv->yuv_info.old_frame_info));
-+	yi->old_frame_info = f;
+-    return 0;
++	return 0;
  }
  
--static void ivtv_yuv_init (struct ivtv *itv)
-+static void ivtv_yuv_init(struct ivtv *itv)
- {
- 	struct yuv_playback_info *yi = &itv->yuv_info;
- 
-@@ -924,25 +885,23 @@ static void ivtv_yuv_init (struct ivtv *itv)
- 		if (!yi->osd_vis_w)
- 			yi->osd_vis_w = 720 - yi->osd_x_offset;
- 
--		if (!yi->osd_vis_h)
-+		if (!yi->osd_vis_h) {
- 			yi->osd_vis_h = yi->decode_height - yi->osd_y_offset;
--		else {
-+		} else if (yi->osd_vis_h + yi->osd_y_offset > yi->decode_height) {
- 			/* If output video standard has changed, requested height may
--			not be legal */
--			if (yi->osd_vis_h + yi->osd_y_offset > yi->decode_height) {
--				IVTV_DEBUG_WARN("Clipping yuv output - fb size (%d) exceeds video standard limit (%d)\n",
--						yi->osd_vis_h + yi->osd_y_offset,
--						yi->decode_height);
--				yi->osd_vis_h = yi->decode_height - yi->osd_y_offset;
--			}
-+			   not be legal */
-+			IVTV_DEBUG_WARN("Clipping yuv output - fb size (%d) exceeds video standard limit (%d)\n",
-+					yi->osd_vis_h + yi->osd_y_offset,
-+					yi->decode_height);
-+			yi->osd_vis_h = yi->decode_height - yi->osd_y_offset;
- 		}
- 	}
+ static int saa7134_resume(struct pci_dev *pci_dev)
+@@ -1205,8 +1213,8 @@ static int saa7134_resume(struct pci_dev *pci_dev)
+ 	struct saa7134_dev *dev = pci_get_drvdata(pci_dev);
+ 	unsigned long flags;
  
- 	/* We need a buffer for blanking when Y plane is offset - non-fatal if we can't get one */
--	yi->blanking_ptr = kzalloc(720*16, GFP_KERNEL);
--	if (yi->blanking_ptr)
-+	yi->blanking_ptr = kzalloc(720 * 16, GFP_KERNEL);
-+	if (yi->blanking_ptr) {
- 		yi->blanking_dmaptr = pci_map_single(itv->dev, yi->blanking_ptr, 720*16, PCI_DMA_TODEVICE);
--	else {
-+	} else {
- 		yi->blanking_dmaptr = 0;
- 		IVTV_DEBUG_WARN("Failed to allocate yuv blanking buffer\n");
- 	}
-@@ -954,77 +913,140 @@ static void ivtv_yuv_init (struct ivtv *itv)
- 	atomic_set(&yi->next_dma_frame, 0);
- }
+-	pci_restore_state(pci_dev);
+ 	pci_set_power_state(pci_dev, PCI_D0);
++	pci_restore_state(pci_dev);
  
--int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args)
-+/* Get next available yuv buffer on PVR350 */
-+void ivtv_yuv_next_free(struct ivtv *itv)
- {
--	DEFINE_WAIT(wait);
--	int rc = 0;
--	int got_sig = 0;
--	int frame, next_fill_frame, last_fill_frame;
--	int register_update = 0;
-+	int draw, display;
-+	struct yuv_playback_info *yi = &itv->yuv_info;
+ 	/* Do things that are done in saa7134_initdev ,
+ 		except of initializing memory structures.*/
+@@ -1222,6 +1230,7 @@ static int saa7134_resume(struct pci_dev *pci_dev)
+ 		saa7134_ir_start(dev, dev->remote);
+ 	saa7134_hw_enable1(dev);
  
--	IVTV_DEBUG_INFO("yuv_prep_frame\n");
-+	if (atomic_read(&yi->next_dma_frame) == -1)
-+		ivtv_yuv_init(itv);
++	msleep(100);
  
--	if (atomic_read(&itv->yuv_info.next_dma_frame) == -1) ivtv_yuv_init(itv);
-+	draw = atomic_read(&yi->next_fill_frame);
-+	display = atomic_read(&yi->next_dma_frame);
+ 	saa7134_board_init2(dev);
  
--	frame = atomic_read(&itv->yuv_info.next_fill_frame);
--	next_fill_frame = (frame + 1) & 0x3;
--	last_fill_frame = (atomic_read(&itv->yuv_info.next_dma_frame)+1) & 0x3;
-+	if (display > draw)
-+		display -= IVTV_YUV_BUFFERS;
+@@ -1229,10 +1238,13 @@ static int saa7134_resume(struct pci_dev *pci_dev)
+ 	saa7134_set_tvnorm_hw(dev);
+ 	saa7134_tvaudio_setmute(dev);
+ 	saa7134_tvaudio_setvolume(dev, dev->ctl_volume);
++	saa7134_tvaudio_init(dev);
+ 	saa7134_tvaudio_do_scan(dev);
+ 	saa7134_enable_i2s(dev);
+ 	saa7134_hw_enable2(dev);
  
--	if (next_fill_frame != last_fill_frame && last_fill_frame != frame) {
--		/* Buffers are full - Overwrite the last frame */
--		next_fill_frame = frame;
--		frame = (frame - 1) & 3;
--		register_update = itv->yuv_info.new_frame_info[frame].update;
--	}
-+	if (draw - display >= yi->max_frames_buffered)
-+		draw = (u8)(draw - 1) % IVTV_YUV_BUFFERS;
-+	else
-+		yi->new_frame_info[draw].update = 0;
-+
-+	yi->draw_frame = draw;
-+}
-+
-+/* Set up frame according to ivtv_dma_frame parameters */
-+void ivtv_yuv_setup_frame(struct ivtv *itv, struct ivtv_dma_frame *args)
-+{
-+	struct yuv_playback_info *yi = &itv->yuv_info;
-+	u8 frame = yi->draw_frame;
-+	u8 last_frame = (u8)(frame - 1) % IVTV_YUV_BUFFERS;
-+	struct yuv_frame_info *nf = &yi->new_frame_info[frame];
-+	struct yuv_frame_info *of = &yi->new_frame_info[last_frame];
-+	int lace_threshold = yi->lace_threshold;
++	saa7134_irq_video_signalchange(dev);
 +
-+	/* Preserve old update flag in case we're overwriting a queued frame */
-+	int update = nf->update;
+ 	/*resume unfinished buffer(s)*/
+ 	spin_lock_irqsave(&dev->slock, flags);
+ 	saa7134_buffer_requeue(dev, &dev->video_q);
+@@ -1246,6 +1258,7 @@ static int saa7134_resume(struct pci_dev *pci_dev)
  
- 	/* Take a snapshot of the yuv coordinate information */
--	itv->yuv_info.new_frame_info[frame].src_x = args->src.left;
--	itv->yuv_info.new_frame_info[frame].src_y = args->src.top;
--	itv->yuv_info.new_frame_info[frame].src_w = args->src.width;
--	itv->yuv_info.new_frame_info[frame].src_h = args->src.height;
--	itv->yuv_info.new_frame_info[frame].dst_x = args->dst.left;
--	itv->yuv_info.new_frame_info[frame].dst_y = args->dst.top;
--	itv->yuv_info.new_frame_info[frame].dst_w = args->dst.width;
--	itv->yuv_info.new_frame_info[frame].dst_h = args->dst.height;
--	itv->yuv_info.new_frame_info[frame].tru_x = args->dst.left;
--	itv->yuv_info.new_frame_info[frame].tru_w = args->src_width;
--	itv->yuv_info.new_frame_info[frame].tru_h = args->src_height;
--
--	/* Snapshot field order */
--	itv->yuv_info.sync_field[frame] = itv->yuv_info.lace_sync_field;
-+	nf->src_x = args->src.left;
-+	nf->src_y = args->src.top;
-+	nf->src_w = args->src.width;
-+	nf->src_h = args->src.height;
-+	nf->dst_x = args->dst.left;
-+	nf->dst_y = args->dst.top;
-+	nf->dst_w = args->dst.width;
-+	nf->dst_h = args->dst.height;
-+	nf->tru_x = args->dst.left;
-+	nf->tru_w = args->src_width;
-+	nf->tru_h = args->src_height;
+ 	/* start DMA now*/
+ 	dev->insuspend = 0;
++	smp_wmb();
+ 	saa7134_set_dmabits(dev);
+ 	spin_unlock_irqrestore(&dev->slock, flags);
  
- 	/* Are we going to offset the Y plane */
--	if (args->src.height + args->src.top < 512-16)
--		itv->yuv_info.new_frame_info[frame].offset_y = 1;
--	else
--		itv->yuv_info.new_frame_info[frame].offset_y = 0;
-+	nf->offset_y = (nf->tru_h + nf->src_x < 512 - 16) ? 1 : 0;
+diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c
+index e1ab099..a9ca573 100644
+--- a/drivers/media/video/saa7134/saa7134-dvb.c
++++ b/drivers/media/video/saa7134/saa7134-dvb.c
+@@ -1073,14 +1073,21 @@ static int dvb_init(struct saa7134_dev *dev)
  
- 	/* Snapshot the osd pan info */
--	itv->yuv_info.new_frame_info[frame].pan_x = itv->yuv_info.osd_x_pan;
--	itv->yuv_info.new_frame_info[frame].pan_y = itv->yuv_info.osd_y_pan;
--	itv->yuv_info.new_frame_info[frame].vis_w = itv->yuv_info.osd_vis_w;
--	itv->yuv_info.new_frame_info[frame].vis_h = itv->yuv_info.osd_vis_h;
--
--	itv->yuv_info.new_frame_info[frame].update = 0;
--	itv->yuv_info.new_frame_info[frame].interlaced_y = 0;
--	itv->yuv_info.new_frame_info[frame].interlaced_uv = 0;
--	itv->yuv_info.new_frame_info[frame].lace_mode = itv->yuv_info.lace_mode;
--
--	if (memcmp (&itv->yuv_info.old_frame_info_args, &itv->yuv_info.new_frame_info[frame],
--	    sizeof (itv->yuv_info.new_frame_info[frame]))) {
--		memcpy(&itv->yuv_info.old_frame_info_args, &itv->yuv_info.new_frame_info[frame], sizeof (itv->yuv_info.old_frame_info_args));
--		itv->yuv_info.new_frame_info[frame].update = 1;
--/*		IVTV_DEBUG_YUV ("Requesting register update for frame %d\n",frame); */
-+	nf->pan_x = yi->osd_x_pan;
-+	nf->pan_y = yi->osd_y_pan;
-+	nf->vis_w = yi->osd_vis_w;
-+	nf->vis_h = yi->osd_vis_h;
-+
-+	nf->update = 0;
-+	nf->interlaced_y = 0;
-+	nf->interlaced_uv = 0;
-+	nf->delay = 0;
-+	nf->sync_field = 0;
-+	nf->lace_mode = yi->lace_mode & IVTV_YUV_MODE_MASK;
-+
-+	if (lace_threshold < 0)
-+		lace_threshold = yi->decode_height - 1;
-+
-+	/* Work out the lace settings */
-+	switch (nf->lace_mode) {
-+	case IVTV_YUV_MODE_PROGRESSIVE: /* Progressive mode */
-+		nf->interlaced = 0;
-+		if (nf->tru_h < 512 || (nf->tru_h > 576 && nf->tru_h < 1021))
-+			nf->interlaced_y = 0;
-+		else
-+			nf->interlaced_y = 1;
-+
-+		if (nf->tru_h < 1021 && (nf->dst_h >= nf->src_h / 2))
-+			nf->interlaced_uv = 0;
-+		else
-+			nf->interlaced_uv = 1;
-+		break;
-+
-+	case IVTV_YUV_MODE_AUTO:
-+		if (nf->tru_h <= lace_threshold || nf->tru_h > 576 || nf->tru_w > 720) {
-+			nf->interlaced = 0;
-+			if ((nf->tru_h < 512) ||
-+			    (nf->tru_h > 576 && nf->tru_h < 1021) ||
-+			    (nf->tru_w > 720 && nf->tru_h < 1021))
-+				nf->interlaced_y = 0;
-+			else
-+				nf->interlaced_y = 1;
-+			if (nf->tru_h < 1021 && (nf->dst_h >= nf->src_h / 2))
-+				nf->interlaced_uv = 0;
-+			else
-+				nf->interlaced_uv = 1;
-+		} else {
-+			nf->interlaced = 1;
-+			nf->interlaced_y = 1;
-+			nf->interlaced_uv = 1;
-+		}
-+		break;
+ static int dvb_fini(struct saa7134_dev *dev)
+ {
+-	static int on  = TDA9887_PRESENT | TDA9887_PORT2_INACTIVE;
++	/* FIXME: I suspect that this code is bogus, since the entry for
++	   Pinnacle 300I DVB-T PAL already defines the proper init to allow
++	   the detection of mt2032 (TDA9887_PORT2_INACTIVE)
++	 */
++	if (dev->board == SAA7134_BOARD_PINNACLE_300I_DVBT_PAL) {
++		struct v4l2_priv_tun_config tda9887_cfg;
++		static int on  = TDA9887_PRESENT | TDA9887_PORT2_INACTIVE;
 +
-+	case IVTV_YUV_MODE_INTERLACED: /* Interlace mode */
-+	default:
-+		nf->interlaced = 1;
-+		nf->interlaced_y = 1;
-+		nf->interlaced_uv = 1;
-+		break;
- 	}
++		tda9887_cfg.tuner = TUNER_TDA9887;
++		tda9887_cfg.priv  = &on;
  
--	itv->yuv_info.new_frame_info[frame].update |= register_update;
-+	if (memcmp(&yi->old_frame_info_args, nf, sizeof(*nf))) {
-+		yi->old_frame_info_args = *nf;
-+		nf->update = 1;
-+		IVTV_DEBUG_YUV("Requesting reg update for frame %d\n", frame);
+-	switch (dev->board) {
+-	case SAA7134_BOARD_PINNACLE_300I_DVBT_PAL:
+ 		/* otherwise we don't detect the tuner on next insmod */
+-		saa7134_i2c_call_clients(dev,TDA9887_SET_CONFIG,&on);
+-		break;
+-	};
++		saa7134_i2c_call_clients(dev, TUNER_SET_CONFIG, &tda9887_cfg);
 +	}
- 
--	/* Should this frame be delayed ? */
--	if (itv->yuv_info.sync_field[frame] != itv->yuv_info.sync_field[(frame - 1) & 3])
--		itv->yuv_info.field_delay[frame] = 1;
--	else
--		itv->yuv_info.field_delay[frame] = 0;
-+	nf->update |= update;
-+	nf->sync_field = yi->lace_sync_field;
-+	nf->delay = nf->sync_field != of->sync_field;
-+}
- 
-+/* Frame is complete & ready for display */
-+void ivtv_yuv_frame_complete(struct ivtv *itv)
-+{
-+	atomic_set(&itv->yuv_info.next_fill_frame,
-+			(itv->yuv_info.draw_frame + 1) % IVTV_YUV_BUFFERS);
-+}
 +
-+int ivtv_yuv_udma_frame(struct ivtv *itv, struct ivtv_dma_frame *args)
-+{
-+	DEFINE_WAIT(wait);
-+	int rc = 0;
-+	int got_sig = 0;
- 	/* DMA the frame */
- 	mutex_lock(&itv->udma.lock);
- 
-@@ -1036,10 +1058,10 @@ int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args)
- 	ivtv_udma_prepare(itv);
- 	prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE);
- 	/* if no UDMA is pending and no UDMA is in progress, then the DMA
--	is finished */
-+	   is finished */
- 	while (itv->i_flags & (IVTV_F_I_UDMA_PENDING | IVTV_F_I_UDMA)) {
- 		/* don't interrupt if the DMA is in progress but break off
--		a still pending DMA. */
-+		   a still pending DMA. */
- 		got_sig = signal_pending(current);
- 		if (got_sig && test_and_clear_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags))
- 			break;
-@@ -1057,99 +1079,148 @@ int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args)
- 		return -EINTR;
- 	}
- 
--	atomic_set(&itv->yuv_info.next_fill_frame, next_fill_frame);
-+	ivtv_yuv_frame_complete(itv);
- 
- 	mutex_unlock(&itv->udma.lock);
- 	return rc;
+ 	videobuf_dvb_unregister(&dev->dvb);
+ 	return 0;
  }
- 
-+/* Setup frame according to V4L2 parameters */
-+void ivtv_yuv_setup_stream_frame(struct ivtv *itv)
-+{
-+	struct yuv_playback_info *yi = &itv->yuv_info;
-+	struct ivtv_dma_frame dma_args;
-+
-+	ivtv_yuv_next_free(itv);
-+
-+	/* Copy V4L2 parameters to an ivtv_dma_frame struct... */
-+	dma_args.y_source = 0L;
-+	dma_args.uv_source = 0L;
-+	dma_args.src.left = 0;
-+	dma_args.src.top = 0;
-+	dma_args.src.width = yi->v4l2_src_w;
-+	dma_args.src.height = yi->v4l2_src_h;
-+	dma_args.dst = yi->main_rect;
-+	dma_args.src_width = yi->v4l2_src_w;
-+	dma_args.src_height = yi->v4l2_src_h;
-+
-+	/* ... and use the same setup routine as ivtv_yuv_prep_frame */
-+	ivtv_yuv_setup_frame(itv, &dma_args);
-+
-+	if (!itv->dma_data_req_offset)
-+		itv->dma_data_req_offset = yuv_offset[yi->draw_frame];
-+}
-+
-+/* Attempt to dma a frame from a user buffer */
-+int ivtv_yuv_udma_stream_frame(struct ivtv *itv, void *src)
-+{
-+	struct yuv_playback_info *yi = &itv->yuv_info;
-+	struct ivtv_dma_frame dma_args;
-+
-+	ivtv_yuv_setup_stream_frame(itv);
-+
-+	/* We only need to supply source addresses for this */
-+	dma_args.y_source = src;
-+	dma_args.uv_source = src + 720 * ((yi->v4l2_src_h + 31) & ~31);
-+	return ivtv_yuv_udma_frame(itv, &dma_args);
-+}
-+
-+/* IVTV_IOC_DMA_FRAME ioctl handler */
-+int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args)
-+{
-+/*	IVTV_DEBUG_INFO("yuv_prep_frame\n"); */
-+
-+	ivtv_yuv_next_free(itv);
-+	ivtv_yuv_setup_frame(itv, args);
-+	return ivtv_yuv_udma_frame(itv, args);
-+}
+diff --git a/drivers/media/video/saa7134/saa7134-empress.c b/drivers/media/video/saa7134/saa7134-empress.c
+index 9322f44..b1b01fa 100644
+--- a/drivers/media/video/saa7134/saa7134-empress.c
++++ b/drivers/media/video/saa7134/saa7134-empress.c
+@@ -161,152 +161,176 @@ ts_mmap(struct file *file, struct vm_area_struct * vma)
+  * video_generic_ioctl (and maybe others).  userspace
+  * copying is done already, arg is a kernel pointer.
+  */
+-static int ts_do_ioctl(struct inode *inode, struct file *file,
+-		       unsigned int cmd, void *arg)
 +
- void ivtv_yuv_close(struct ivtv *itv)
++static int empress_querycap(struct file *file, void  *priv,
++					struct v4l2_capability *cap)
  {
-+	struct yuv_playback_info *yi = &itv->yuv_info;
- 	int h_filter, v_filter_1, v_filter_2;
- 
- 	IVTV_DEBUG_YUV("ivtv_yuv_close\n");
- 	ivtv_waitq(&itv->vsync_waitq);
- 
--	atomic_set(&itv->yuv_info.next_dma_frame, -1);
--	atomic_set(&itv->yuv_info.next_fill_frame, 0);
-+	atomic_set(&yi->next_dma_frame, -1);
-+	atomic_set(&yi->next_fill_frame, 0);
- 
- 	/* Reset registers we have changed so mpeg playback works */
- 
- 	/* If we fully restore this register, the display may remain active.
- 	   Restore, but set one bit to blank the video. Firmware will always
- 	   clear this bit when needed, so not a problem. */
--	write_reg(itv->yuv_info.reg_2898 | 0x01000000, 0x2898);
+-	struct saa7134_dev *dev = file->private_data;
+-	struct v4l2_ext_controls *ctrls = arg;
 -
--	write_reg(itv->yuv_info.reg_2834, 0x02834);
--	write_reg(itv->yuv_info.reg_2838, 0x02838);
--	write_reg(itv->yuv_info.reg_283c, 0x0283c);
--	write_reg(itv->yuv_info.reg_2840, 0x02840);
--	write_reg(itv->yuv_info.reg_2844, 0x02844);
--	write_reg(itv->yuv_info.reg_2848, 0x02848);
--	write_reg(itv->yuv_info.reg_2854, 0x02854);
--	write_reg(itv->yuv_info.reg_285c, 0x0285c);
--	write_reg(itv->yuv_info.reg_2864, 0x02864);
--	write_reg(itv->yuv_info.reg_2870, 0x02870);
--	write_reg(itv->yuv_info.reg_2874, 0x02874);
--	write_reg(itv->yuv_info.reg_2890, 0x02890);
--	write_reg(itv->yuv_info.reg_289c, 0x0289c);
+-	if (debug > 1)
+-		v4l_print_ioctl(dev->name,cmd);
+-	switch (cmd) {
+-	case VIDIOC_QUERYCAP:
+-	{
+-		struct v4l2_capability *cap = arg;
 -
--	write_reg(itv->yuv_info.reg_2918, 0x02918);
--	write_reg(itv->yuv_info.reg_291c, 0x0291c);
--	write_reg(itv->yuv_info.reg_2920, 0x02920);
--	write_reg(itv->yuv_info.reg_2924, 0x02924);
--	write_reg(itv->yuv_info.reg_2928, 0x02928);
--	write_reg(itv->yuv_info.reg_292c, 0x0292c);
--	write_reg(itv->yuv_info.reg_2930, 0x02930);
--	write_reg(itv->yuv_info.reg_2934, 0x02934);
--	write_reg(itv->yuv_info.reg_2938, 0x02938);
--	write_reg(itv->yuv_info.reg_293c, 0x0293c);
--	write_reg(itv->yuv_info.reg_2940, 0x02940);
--	write_reg(itv->yuv_info.reg_2944, 0x02944);
--	write_reg(itv->yuv_info.reg_2948, 0x02948);
--	write_reg(itv->yuv_info.reg_294c, 0x0294c);
--	write_reg(itv->yuv_info.reg_2950, 0x02950);
--	write_reg(itv->yuv_info.reg_2954, 0x02954);
--	write_reg(itv->yuv_info.reg_2958, 0x02958);
--	write_reg(itv->yuv_info.reg_295c, 0x0295c);
--	write_reg(itv->yuv_info.reg_2960, 0x02960);
--	write_reg(itv->yuv_info.reg_2964, 0x02964);
--	write_reg(itv->yuv_info.reg_2968, 0x02968);
--	write_reg(itv->yuv_info.reg_296c, 0x0296c);
--	write_reg(itv->yuv_info.reg_2970, 0x02970);
-+	write_reg(yi->reg_2898 | 0x01000000, 0x2898);
-+
-+	write_reg(yi->reg_2834, 0x02834);
-+	write_reg(yi->reg_2838, 0x02838);
-+	write_reg(yi->reg_283c, 0x0283c);
-+	write_reg(yi->reg_2840, 0x02840);
-+	write_reg(yi->reg_2844, 0x02844);
-+	write_reg(yi->reg_2848, 0x02848);
-+	write_reg(yi->reg_2854, 0x02854);
-+	write_reg(yi->reg_285c, 0x0285c);
-+	write_reg(yi->reg_2864, 0x02864);
-+	write_reg(yi->reg_2870, 0x02870);
-+	write_reg(yi->reg_2874, 0x02874);
-+	write_reg(yi->reg_2890, 0x02890);
-+	write_reg(yi->reg_289c, 0x0289c);
+-		memset(cap,0,sizeof(*cap));
+-		strcpy(cap->driver, "saa7134");
+-		strlcpy(cap->card, saa7134_boards[dev->board].name,
+-			sizeof(cap->card));
+-		sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci));
+-		cap->version = SAA7134_VERSION_CODE;
+-		cap->capabilities =
+-			V4L2_CAP_VIDEO_CAPTURE |
+-			V4L2_CAP_READWRITE |
+-			V4L2_CAP_STREAMING;
+-		return 0;
+-	}
++	struct saa7134_fh *fh = priv;
++	struct saa7134_dev *dev = fh->dev;
 +
-+	write_reg(yi->reg_2918, 0x02918);
-+	write_reg(yi->reg_291c, 0x0291c);
-+	write_reg(yi->reg_2920, 0x02920);
-+	write_reg(yi->reg_2924, 0x02924);
-+	write_reg(yi->reg_2928, 0x02928);
-+	write_reg(yi->reg_292c, 0x0292c);
-+	write_reg(yi->reg_2930, 0x02930);
-+	write_reg(yi->reg_2934, 0x02934);
-+	write_reg(yi->reg_2938, 0x02938);
-+	write_reg(yi->reg_293c, 0x0293c);
-+	write_reg(yi->reg_2940, 0x02940);
-+	write_reg(yi->reg_2944, 0x02944);
-+	write_reg(yi->reg_2948, 0x02948);
-+	write_reg(yi->reg_294c, 0x0294c);
-+	write_reg(yi->reg_2950, 0x02950);
-+	write_reg(yi->reg_2954, 0x02954);
-+	write_reg(yi->reg_2958, 0x02958);
-+	write_reg(yi->reg_295c, 0x0295c);
-+	write_reg(yi->reg_2960, 0x02960);
-+	write_reg(yi->reg_2964, 0x02964);
-+	write_reg(yi->reg_2968, 0x02968);
-+	write_reg(yi->reg_296c, 0x0296c);
-+	write_reg(yi->reg_2970, 0x02970);
++	strcpy(cap->driver, "saa7134");
++	strlcpy(cap->card, saa7134_boards[dev->board].name,
++		sizeof(cap->card));
++	sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci));
++	cap->version = SAA7134_VERSION_CODE;
++	cap->capabilities =
++		V4L2_CAP_VIDEO_CAPTURE |
++		V4L2_CAP_READWRITE |
++		V4L2_CAP_STREAMING;
++	return 0;
++}
  
- 	/* Prepare to restore filters */
+-	/* --- input switching --------------------------------------- */
+-	case VIDIOC_ENUMINPUT:
+-	{
+-		struct v4l2_input *i = arg;
++static int empress_enum_input(struct file *file, void *priv,
++					struct v4l2_input *i)
++{
++	if (i->index != 0)
++		return -EINVAL;
  
- 	/* First the horizontal filter */
--	if ((itv->yuv_info.reg_2834 & 0x0000FFFF) == (itv->yuv_info.reg_2834 >> 16)) {
-+	if ((yi->reg_2834 & 0x0000FFFF) == (yi->reg_2834 >> 16)) {
- 		/* An exact size match uses filter 0 */
- 		h_filter = 0;
+-		if (i->index != 0)
+-			return -EINVAL;
+-		i->type = V4L2_INPUT_TYPE_CAMERA;
+-		strcpy(i->name,"CCIR656");
+-		return 0;
 -	}
--	else {
-+	} else {
- 		/* Figure out which filter to use */
--		h_filter = ((itv->yuv_info.reg_2834 << 16) / (itv->yuv_info.reg_2834 >> 16)) >> 15;
-+		h_filter = ((yi->reg_2834 << 16) / (yi->reg_2834 >> 16)) >> 15;
- 		h_filter = (h_filter >> 1) + (h_filter & 1);
- 		/* Only an exact size match can use filter 0. */
--		if (h_filter < 1) h_filter = 1;
-+		h_filter += !h_filter;
- 	}
- 
- 	/* Now the vertical filter */
--	if ((itv->yuv_info.reg_2918 & 0x0000FFFF) == (itv->yuv_info.reg_2918 >> 16)) {
-+	if ((yi->reg_2918 & 0x0000FFFF) == (yi->reg_2918 >> 16)) {
- 		/* An exact size match uses filter 0/1 */
- 		v_filter_1 = 0;
- 		v_filter_2 = 1;
+-	case VIDIOC_G_INPUT:
+-	{
+-		int *i = arg;
+-		*i = 0;
+-		return 0;
 -	}
--	else {
-+	} else {
- 		/* Figure out which filter to use */
--		v_filter_1 = ((itv->yuv_info.reg_2918 << 16) / (itv->yuv_info.reg_2918 >> 16)) >> 15;
-+		v_filter_1 = ((yi->reg_2918 << 16) / (yi->reg_2918 >> 16)) >> 15;
- 		v_filter_1 = (v_filter_1 >> 1) + (v_filter_1 & 1);
- 		/* Only an exact size match can use filter 0 */
--		if (v_filter_1 == 0) v_filter_1 = 1;
-+		v_filter_1 += !v_filter_1;
- 		v_filter_2 = v_filter_1;
- 	}
- 
- 	/* Now restore the filters */
--	ivtv_yuv_filter (itv,h_filter,v_filter_1,v_filter_2);
-+	ivtv_yuv_filter(itv, h_filter, v_filter_1, v_filter_2);
- 
- 	/* and clear a few registers */
- 	write_reg(0, 0x02814);
-@@ -1158,19 +1229,18 @@ void ivtv_yuv_close(struct ivtv *itv)
- 	write_reg(0, 0x02910);
- 
- 	/* Release the blanking buffer */
--	if (itv->yuv_info.blanking_ptr) {
--		kfree (itv->yuv_info.blanking_ptr);
--		itv->yuv_info.blanking_ptr = NULL;
--		pci_unmap_single(itv->dev, itv->yuv_info.blanking_dmaptr, 720*16, PCI_DMA_TODEVICE);
-+	if (yi->blanking_ptr) {
-+		kfree(yi->blanking_ptr);
-+		yi->blanking_ptr = NULL;
-+		pci_unmap_single(itv->dev, yi->blanking_dmaptr, 720*16, PCI_DMA_TODEVICE);
- 	}
- 
- 	/* Invalidate the old dimension information */
--	itv->yuv_info.old_frame_info.src_w = 0;
--	itv->yuv_info.old_frame_info.src_h = 0;
--	itv->yuv_info.old_frame_info_args.src_w = 0;
--	itv->yuv_info.old_frame_info_args.src_h = 0;
-+	yi->old_frame_info.src_w = 0;
-+	yi->old_frame_info.src_h = 0;
-+	yi->old_frame_info_args.src_w = 0;
-+	yi->old_frame_info_args.src_h = 0;
+-	case VIDIOC_S_INPUT:
+-	{
+-		int *i = arg;
++	i->type = V4L2_INPUT_TYPE_CAMERA;
++	strcpy(i->name, "CCIR656");
  
- 	/* All done. */
- 	clear_bit(IVTV_F_I_DECODING_YUV, &itv->i_flags);
- }
+-		if (*i != 0)
+-			return -EINVAL;
+-		return 0;
+-	}
+-	/* --- capture ioctls ---------------------------------------- */
 -
-diff --git a/drivers/media/video/ivtv/ivtv-yuv.h b/drivers/media/video/ivtv/ivtv-yuv.h
-index 3b966f0..2fe5f12 100644
---- a/drivers/media/video/ivtv/ivtv-yuv.h
-+++ b/drivers/media/video/ivtv/ivtv-yuv.h
-@@ -21,11 +21,6 @@
- #ifndef IVTV_YUV_H
- #define IVTV_YUV_H
- 
--/* Buffers on hardware offsets */
--#define IVTV_YUV_BUFFER_OFFSET    0x001a8600	/* First YUV Buffer */
--#define IVTV_YUV_BUFFER_OFFSET_1  0x00240400	/* Second YUV Buffer */
--#define IVTV_YUV_BUFFER_OFFSET_2  0x002d8200	/* Third YUV Buffer */
--#define IVTV_YUV_BUFFER_OFFSET_3  0x00370000	/* Fourth YUV Buffer */
- #define IVTV_YUV_BUFFER_UV_OFFSET 0x65400	/* Offset to UV Buffer */
- 
- /* Offset to filter table in firmware */
-@@ -36,11 +31,14 @@
- #define IVTV_YUV_UPDATE_VERTICAL    0x02
- #define IVTV_YUV_UPDATE_INVALID     0x04
- 
--extern const u32 yuv_offset[4];
-+extern const u32 yuv_offset[IVTV_YUV_BUFFERS];
- 
- int ivtv_yuv_filter_check(struct ivtv *itv);
-+void ivtv_yuv_setup_stream_frame(struct ivtv *itv);
-+int ivtv_yuv_udma_stream_frame(struct ivtv *itv, void *src);
-+void ivtv_yuv_frame_complete(struct ivtv *itv);
- int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args);
- void ivtv_yuv_close(struct ivtv *itv);
--void ivtv_yuv_work_handler (struct ivtv *itv);
-+void ivtv_yuv_work_handler(struct ivtv *itv);
+-	case VIDIOC_ENUM_FMT:
+-	{
+-		struct v4l2_fmtdesc *f = arg;
+-		int index;
+-
+-		index = f->index;
+-		if (index != 0)
+-			return -EINVAL;
+-
+-		memset(f,0,sizeof(*f));
+-		f->index = index;
+-		strlcpy(f->description, "MPEG TS", sizeof(f->description));
+-		f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+-		f->pixelformat = V4L2_PIX_FMT_MPEG;
+-		return 0;
+-	}
++	return 0;
++}
  
- #endif
-diff --git a/drivers/media/video/ivtv/ivtvfb.c b/drivers/media/video/ivtv/ivtvfb.c
-index 52ffd15..3b23fc0 100644
---- a/drivers/media/video/ivtv/ivtvfb.c
-+++ b/drivers/media/video/ivtv/ivtvfb.c
-@@ -504,6 +504,10 @@ static int ivtvfb_set_var(struct ivtv *itv, struct fb_var_screeninfo *var)
+-	case VIDIOC_G_FMT:
+-	{
+-		struct v4l2_format *f = arg;
++static int empress_g_input(struct file *file, void *priv, unsigned int *i)
++{
++	*i = 0;
++	return 0;
++}
  
- 	ivtvfb_set_display_window(itv, &ivtv_window);
+-		memset(f,0,sizeof(*f));
+-		f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
++static int empress_s_input(struct file *file, void *priv, unsigned int i)
++{
++	if (i != 0)
++		return -EINVAL;
  
-+	/* Pass screen size back to yuv handler */
-+	itv->yuv_info.osd_full_w = ivtv_osd.pixel_stride;
-+	itv->yuv_info.osd_full_h = ivtv_osd.lines;
-+
- 	/* Force update of yuv registers */
- 	itv->yuv_info.yuv_forced_update = 1;
+-		saa7134_i2c_call_clients(dev, cmd, arg);
+-		f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
+-		f->fmt.pix.sizeimage    = TS_PACKET_SIZE * dev->ts.nr_packets;
+-		return 0;
+-	}
++	return 0;
++}
  
-@@ -1053,7 +1057,7 @@ static int ivtvfb_init_card(struct ivtv *itv)
- 	}
+-	case VIDIOC_S_FMT:
+-	{
+-		struct v4l2_format *f = arg;
++static int empress_enum_fmt_cap(struct file *file, void  *priv,
++					struct v4l2_fmtdesc *f)
++{
++	if (f->index != 0)
++		return -EINVAL;
  
- 	itv->osd_info = kzalloc(sizeof(struct osd_info), GFP_ATOMIC);
--	if (itv->osd_info == 0) {
-+	if (itv->osd_info == NULL) {
- 		IVTVFB_ERR("Failed to allocate memory for osd_info\n");
- 		return -ENOMEM;
- 	}
-diff --git a/drivers/media/video/ks0127.c b/drivers/media/video/ks0127.c
-index b6cd21e..4895540 100644
---- a/drivers/media/video/ks0127.c
-+++ b/drivers/media/video/ks0127.c
-@@ -764,7 +764,6 @@ static struct i2c_client ks0127_client_tmpl =
- 	.addr = 0,
- 	.adapter = NULL,
- 	.driver = &i2c_driver_ks0127,
--	.usage_count = 0
- };
+-		if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+-		    return -EINVAL;
++	strlcpy(f->description, "MPEG TS", sizeof(f->description));
++	f->pixelformat = V4L2_PIX_FMT_MPEG;
  
- static int ks0127_found_proc(struct i2c_adapter *adapter, int addr, int kind)
-diff --git a/drivers/media/video/m52790.c b/drivers/media/video/m52790.c
-new file mode 100644
-index 0000000..d4bf14c
---- /dev/null
-+++ b/drivers/media/video/m52790.c
-@@ -0,0 +1,168 @@
-+/*
-+ * m52790 i2c ivtv driver.
-+ * Copyright (C) 2007  Hans Verkuil
-+ *
-+ * A/V source switching Mitsubishi M52790SP/FP
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+ * GNU General Public License for more details.
-+ *
-+ * You 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/types.h>
-+#include <linux/ioctl.h>
-+#include <asm/uaccess.h>
-+#include <linux/i2c.h>
-+#include <linux/i2c-id.h>
-+#include <linux/videodev.h>
-+#include <media/m52790.h>
-+#include <media/v4l2-common.h>
-+#include <media/v4l2-chip-ident.h>
-+#include <media/v4l2-i2c-drv.h>
-+
-+MODULE_DESCRIPTION("i2c device driver for m52790 A/V switch");
-+MODULE_AUTHOR("Hans Verkuil");
-+MODULE_LICENSE("GPL");
-+
-+
-+struct m52790_state {
-+	u16 input;
-+	u16 output;
-+};
+-		saa7134_i2c_call_clients(dev, cmd, arg);
+-		f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
+-		f->fmt.pix.sizeimage    = TS_PACKET_SIZE* dev->ts.nr_packets;
+-		return 0;
+-	}
++	return 0;
++}
+ 
+-	case VIDIOC_REQBUFS:
+-		return videobuf_reqbufs(&dev->empress_tsq,arg);
++static int empress_g_fmt_cap(struct file *file, void *priv,
++				struct v4l2_format *f)
++{
++	struct saa7134_fh *fh = priv;
++	struct saa7134_dev *dev = fh->dev;
+ 
+-	case VIDIOC_QUERYBUF:
+-		return videobuf_querybuf(&dev->empress_tsq,arg);
++	saa7134_i2c_call_clients(dev, VIDIOC_G_FMT, f);
+ 
+-	case VIDIOC_QBUF:
+-		return videobuf_qbuf(&dev->empress_tsq,arg);
++	f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
++	f->fmt.pix.sizeimage    = TS_PACKET_SIZE * dev->ts.nr_packets;
+ 
+-	case VIDIOC_DQBUF:
+-		return videobuf_dqbuf(&dev->empress_tsq,arg,
+-				      file->f_flags & O_NONBLOCK);
++	return 0;
++}
+ 
+-	case VIDIOC_STREAMON:
+-		return videobuf_streamon(&dev->empress_tsq);
++static int empress_s_fmt_cap(struct file *file, void *priv,
++				struct v4l2_format *f)
++{
++	struct saa7134_fh *fh = priv;
++	struct saa7134_dev *dev = fh->dev;
+ 
+-	case VIDIOC_STREAMOFF:
+-		return videobuf_streamoff(&dev->empress_tsq);
++	saa7134_i2c_call_clients(dev, VIDIOC_S_FMT, f);
+ 
+-	case VIDIOC_QUERYCTRL:
+-	case VIDIOC_G_CTRL:
+-	case VIDIOC_S_CTRL:
+-		return saa7134_common_ioctl(dev, cmd, arg);
++	f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
++	f->fmt.pix.sizeimage    = TS_PACKET_SIZE * dev->ts.nr_packets;
+ 
+-	case VIDIOC_S_EXT_CTRLS:
+-		/* count == 0 is abused in saa6752hs.c, so that special
+-		   case is handled here explicitly. */
+-		if (ctrls->count == 0)
+-			return 0;
+-		if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG)
+-			return -EINVAL;
+-		saa7134_i2c_call_clients(dev, VIDIOC_S_EXT_CTRLS, arg);
+-		ts_init_encoder(dev);
+-		return 0;
+-	case VIDIOC_G_EXT_CTRLS:
+-		if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG)
+-			return -EINVAL;
+-		saa7134_i2c_call_clients(dev, VIDIOC_G_EXT_CTRLS, arg);
++	return 0;
++}
 +
-+/* ----------------------------------------------------------------------- */
 +
-+static int m52790_write(struct i2c_client *client)
++static int empress_reqbufs(struct file *file, void *priv,
++					struct v4l2_requestbuffers *p)
 +{
-+	struct m52790_state *state = i2c_get_clientdata(client);
-+	u8 sw1 = (state->input | state->output) & 0xff;
-+	u8 sw2 = (state->input | state->output) >> 8;
++	struct saa7134_fh *fh = priv;
++	struct saa7134_dev *dev = fh->dev;
 +
-+	return i2c_smbus_write_byte_data(client, sw1, sw2);
++	return videobuf_reqbufs(&dev->empress_tsq, p);
 +}
 +
-+static int m52790_command(struct i2c_client *client, unsigned int cmd,
-+			    void *arg)
++static int empress_querybuf(struct file *file, void *priv,
++					struct v4l2_buffer *b)
 +{
-+	struct m52790_state *state = i2c_get_clientdata(client);
-+	struct v4l2_routing *route = arg;
++	struct saa7134_fh *fh = priv;
++	struct saa7134_dev *dev = fh->dev;
 +
-+	/* Note: audio and video are linked and cannot be switched separately.
-+	   So audio and video routing commands are identical for this chip.
-+	   In theory the video amplifier and audio modes could be handled
-+	   separately for the output, but that seems to be overkill right now.
-+	   The same holds for implementing an audio mute control, this is now
-+	   part of the audio output routing. The normal case is that another
-+	   chip takes care of the actual muting so making it part of the
-+	   output routing seems to be the right thing to do for now. */
-+	switch (cmd) {
-+	case VIDIOC_INT_G_AUDIO_ROUTING:
-+	case VIDIOC_INT_G_VIDEO_ROUTING:
-+		route->input = state->input;
-+		route->output = state->output;
-+		break;
++	return videobuf_querybuf(&dev->empress_tsq, b);
++}
 +
-+	case VIDIOC_INT_S_AUDIO_ROUTING:
-+	case VIDIOC_INT_S_VIDEO_ROUTING:
-+		state->input = route->input;
-+		state->output = route->output;
-+		m52790_write(client);
-+		break;
++static int empress_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
++{
++	struct saa7134_fh *fh = priv;
++	struct saa7134_dev *dev = fh->dev;
 +
-+#ifdef CONFIG_VIDEO_ADV_DEBUG
-+	case VIDIOC_DBG_G_REGISTER:
-+	case VIDIOC_DBG_S_REGISTER:
-+	{
-+		struct v4l2_register *reg = arg;
++	return videobuf_qbuf(&dev->empress_tsq, b);
++}
 +
-+		if (!v4l2_chip_match_i2c_client(client,
-+					reg->match_type, reg->match_chip))
-+			return -EINVAL;
-+		if (!capable(CAP_SYS_ADMIN))
-+			return -EPERM;
-+		if (reg->reg != 0)
-+			return -EINVAL;
-+		if (cmd == VIDIOC_DBG_G_REGISTER)
-+			reg->val = state->input | state->output;
-+		else {
-+			state->input = reg->val & 0x0303;
-+			state->output = reg->val & ~0x0303;
-+			m52790_write(client);
-+		}
-+		break;
-+	}
-+#endif
++static int empress_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
++{
++	struct saa7134_fh *fh = priv;
++	struct saa7134_dev *dev = fh->dev;
 +
-+	case VIDIOC_G_CHIP_IDENT:
-+		return v4l2_chip_ident_i2c_client(client, arg,
-+				V4L2_IDENT_M52790, 0);
++	return videobuf_dqbuf(&dev->empress_tsq, b,
++				file->f_flags & O_NONBLOCK);
++}
 +
-+	case VIDIOC_LOG_STATUS:
-+		v4l_info(client, "Switch 1: %02x\n",
-+				(state->input | state->output) & 0xff);
-+		v4l_info(client, "Switch 2: %02x\n",
-+				(state->input | state->output) >> 8);
-+		break;
++static int empress_streamon(struct file *file, void *priv,
++					enum v4l2_buf_type type)
++{
++	struct saa7134_fh *fh = priv;
++	struct saa7134_dev *dev = fh->dev;
 +
-+	default:
-+		return -EINVAL;
-+	}
-+	return 0;
++	return videobuf_streamon(&dev->empress_tsq);
 +}
 +
-+/* ----------------------------------------------------------------------- */
++static int empress_streamoff(struct file *file, void *priv,
++					enum v4l2_buf_type type)
++{
++	struct saa7134_fh *fh = priv;
++	struct saa7134_dev *dev = fh->dev;
 +
-+/* i2c implementation */
++	return videobuf_streamoff(&dev->empress_tsq);
++}
 +
-+static int m52790_probe(struct i2c_client *client)
++static int empress_s_ext_ctrls(struct file *file, void *priv,
++			       struct v4l2_ext_controls *ctrls)
 +{
-+	struct m52790_state *state;
-+
-+	/* Check if the adapter supports the needed features */
-+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
-+		return -EIO;
++	struct saa7134_fh *fh = priv;
++	struct saa7134_dev *dev = fh->dev;
 +
-+	snprintf(client->name, sizeof(client->name) - 1, "m52790");
++	/* count == 0 is abused in saa6752hs.c, so that special
++		case is handled here explicitly. */
++	if (ctrls->count == 0)
+ 		return 0;
+ 
+-	default:
+-		return -ENOIOCTLCMD;
+-	}
++	if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG)
++		return -EINVAL;
 +
-+	v4l_info(client, "chip found @ 0x%x (%s)\n",
-+			client->addr << 1, client->adapter->name);
++	saa7134_i2c_call_clients(dev, VIDIOC_S_EXT_CTRLS, ctrls);
++	ts_init_encoder(dev);
 +
-+	state = kmalloc(sizeof(struct m52790_state), GFP_KERNEL);
-+	if (state == NULL)
-+		return -ENOMEM;
+ 	return 0;
+ }
+ 
+-static int ts_ioctl(struct inode *inode, struct file *file,
+-		     unsigned int cmd, unsigned long arg)
++static int empress_g_ext_ctrls(struct file *file, void *priv,
++			       struct v4l2_ext_controls *ctrls)
+ {
+-	return video_usercopy(inode, file, cmd, arg, ts_do_ioctl);
++	struct saa7134_fh *fh = priv;
++	struct saa7134_dev *dev = fh->dev;
 +
-+	state->input = M52790_IN_TUNER;
-+	state->output = M52790_OUT_STEREO;
-+	i2c_set_clientdata(client, state);
-+	m52790_write(client);
-+	return 0;
-+}
++	if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG)
++		return -EINVAL;
++	saa7134_i2c_call_clients(dev, VIDIOC_G_EXT_CTRLS, ctrls);
 +
-+static int m52790_remove(struct i2c_client *client)
-+{
-+	kfree(i2c_get_clientdata(client));
 +	return 0;
-+}
+ }
+ 
+ static const struct file_operations ts_fops =
+@@ -317,7 +341,7 @@ static const struct file_operations ts_fops =
+ 	.read	  = ts_read,
+ 	.poll	  = ts_poll,
+ 	.mmap	  = ts_mmap,
+-	.ioctl	  = ts_ioctl,
++	.ioctl	  = video_ioctl2,
+ 	.llseek   = no_llseek,
+ };
+ 
+@@ -330,6 +354,29 @@ static struct video_device saa7134_empress_template =
+ 	.type2         = 0 /* FIXME */,
+ 	.fops          = &ts_fops,
+ 	.minor	       = -1,
 +
-+/* ----------------------------------------------------------------------- */
++	.vidioc_querycap		= empress_querycap,
++	.vidioc_enum_fmt_cap		= empress_enum_fmt_cap,
++	.vidioc_s_fmt_cap		= empress_s_fmt_cap,
++	.vidioc_g_fmt_cap		= empress_g_fmt_cap,
++	.vidioc_reqbufs			= empress_reqbufs,
++	.vidioc_querybuf		= empress_querybuf,
++	.vidioc_qbuf			= empress_qbuf,
++	.vidioc_dqbuf			= empress_dqbuf,
++	.vidioc_streamon		= empress_streamon,
++	.vidioc_streamoff		= empress_streamoff,
++	.vidioc_s_ext_ctrls		= empress_s_ext_ctrls,
++	.vidioc_g_ext_ctrls		= empress_g_ext_ctrls,
++	.vidioc_enum_input		= empress_enum_input,
++	.vidioc_g_input			= empress_g_input,
++	.vidioc_s_input			= empress_s_input,
 +
-+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
-+	.name = "m52790",
-+	.driverid = I2C_DRIVERID_M52790,
-+	.command = m52790_command,
-+	.probe = m52790_probe,
-+	.remove = m52790_remove,
-+};
++	.vidioc_queryctrl		= saa7134_queryctrl,
++	.vidioc_g_ctrl			= saa7134_g_ctrl,
++	.vidioc_s_ctrl			= saa7134_s_ctrl,
 +
-diff --git a/drivers/media/video/meye.c b/drivers/media/video/meye.c
-index c311632..3d51fa0 100644
---- a/drivers/media/video/meye.c
-+++ b/drivers/media/video/meye.c
-@@ -2023,7 +2023,7 @@ static int __init meye_init(void)
- 	if (gbufsize < 0 || gbufsize > MEYE_MAX_BUFSIZE)
- 		gbufsize = MEYE_MAX_BUFSIZE;
- 	gbufsize = PAGE_ALIGN(gbufsize);
--	printk(KERN_INFO "meye: using %d buffers with %dk (%dk total)"
-+	printk(KERN_INFO "meye: using %d buffers with %dk (%dk total) "
- 			 "for capture\n",
- 			 gbuffers,
- 			 gbufsize / 1024, gbuffers * gbufsize / 1024);
-diff --git a/drivers/media/video/msp3400-driver.c b/drivers/media/video/msp3400-driver.c
-index c0c87e0..7a11f31 100644
---- a/drivers/media/video/msp3400-driver.c
-+++ b/drivers/media/video/msp3400-driver.c
-@@ -42,7 +42,8 @@
-  *
-  * You 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.
-+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-+ * 02110-1301, USA.
-  */
- 
- 
-@@ -53,6 +54,7 @@
- #include <linux/videodev.h>
- #include <linux/videodev2.h>
- #include <media/v4l2-common.h>
-+#include <media/v4l2-i2c-drv-legacy.h>
- #include <media/tvaudio.h>
- #include <media/msp3400.h>
- #include <linux/kthread.h>
-@@ -71,7 +73,8 @@ int msp_debug;		 /* msp_debug output */
- int msp_once;		 /* no continous stereo monitoring */
- int msp_amsound;	 /* hard-wire AM sound at 6.5 Hz (france),
- 			    the autoscan seems work well only with FM... */
--int msp_standard = 1;    /* Override auto detect of audio msp_standard, if needed. */
-+int msp_standard = 1;    /* Override auto detect of audio msp_standard,
-+			    if needed. */
- int msp_dolby;
- 
- int msp_stereo_thresh = 0x190; /* a2 threshold for stereo/bilingual
-@@ -81,12 +84,12 @@ int msp_stereo_thresh = 0x190; /* a2 threshold for stereo/bilingual
- module_param(opmode,           int, 0444);
- 
- /* read-write */
--module_param_named(once,msp_once,                      bool, 0644);
--module_param_named(debug,msp_debug,                    int,  0644);
--module_param_named(stereo_threshold,msp_stereo_thresh, int,  0644);
--module_param_named(standard,msp_standard,              int,  0644);
--module_param_named(amsound,msp_amsound,                bool, 0644);
--module_param_named(dolby,msp_dolby,                    bool, 0644);
-+module_param_named(once, msp_once,                      bool, 0644);
-+module_param_named(debug, msp_debug,                    int,  0644);
-+module_param_named(stereo_threshold, msp_stereo_thresh, int,  0644);
-+module_param_named(standard, msp_standard,              int,  0644);
-+module_param_named(amsound, msp_amsound,                bool, 0644);
-+module_param_named(dolby, msp_dolby,                    bool, 0644);
- 
- MODULE_PARM_DESC(opmode, "Forces a MSP3400 opmode. 0=Manual, 1=Autodetect, 2=Autodetect and autoselect");
- MODULE_PARM_DESC(once, "No continuous stereo monitoring");
-@@ -160,12 +163,13 @@ static int msp_read(struct i2c_client *client, int dev, int addr)
- 		schedule_timeout_interruptible(msecs_to_jiffies(10));
- 	}
- 	if (err == 3) {
--		v4l_warn(client, "giving up, resetting chip. Sound will go off, sorry folks :-|\n");
-+		v4l_warn(client, "resetting chip, sound will go off.\n");
- 		msp_reset(client);
- 		return -1;
- 	}
- 	retval = read[0] << 8 | read[1];
--	v4l_dbg(3, msp_debug, client, "msp_read(0x%x, 0x%x): 0x%x\n", dev, addr, retval);
-+	v4l_dbg(3, msp_debug, client, "msp_read(0x%x, 0x%x): 0x%x\n",
-+			dev, addr, retval);
- 	return retval;
- }
++	.tvnorms			= SAA7134_NORMS,
++	.current_norm			= V4L2_STD_PAL,
+ };
  
-@@ -190,7 +194,8 @@ static int msp_write(struct i2c_client *client, int dev, int addr, int val)
- 	buffer[3] = val  >> 8;
- 	buffer[4] = val  &  0xff;
+ static void empress_signal_update(struct work_struct *work)
+diff --git a/drivers/media/video/saa7134/saa7134-i2c.c b/drivers/media/video/saa7134/saa7134-i2c.c
+index 6deaad1..d3322c3 100644
+--- a/drivers/media/video/saa7134/saa7134-i2c.c
++++ b/drivers/media/video/saa7134/saa7134-i2c.c
+@@ -323,7 +323,6 @@ static int attach_inform(struct i2c_client *client)
+ {
+ 	struct saa7134_dev *dev = client->adapter->algo_data;
+ 	int tuner = dev->tuner_type;
+-	int conf  = dev->tda9887_conf;
+ 	struct tuner_setup tun_setup;
  
--	v4l_dbg(3, msp_debug, client, "msp_write(0x%x, 0x%x, 0x%x)\n", dev, addr, val);
-+	v4l_dbg(3, msp_debug, client, "msp_write(0x%x, 0x%x, 0x%x)\n",
-+			dev, addr, val);
- 	for (err = 0; err < 3; err++) {
- 		if (i2c_master_send(client, buffer, 5) == 5)
- 			break;
-@@ -199,7 +204,7 @@ static int msp_write(struct i2c_client *client, int dev, int addr, int val)
- 		schedule_timeout_interruptible(msecs_to_jiffies(10));
- 	}
- 	if (err == 3) {
--		v4l_warn(client, "giving up, resetting chip. Sound will go off, sorry folks :-|\n");
-+		v4l_warn(client, "resetting chip, sound will go off.\n");
- 		msp_reset(client);
- 		return -1;
+ 	d1printk( "%s i2c attach [addr=0x%x,client=%s]\n",
+@@ -335,6 +334,7 @@ static int attach_inform(struct i2c_client *client)
+ 		case 0x7a:
+ 		case 0x47:
+ 		case 0x71:
++		case 0x2d:
+ 		{
+ 			struct IR_i2c *ir = i2c_get_clientdata(client);
+ 			d1printk("%s i2c IR detected (%s).\n",
+@@ -360,7 +360,6 @@ static int attach_inform(struct i2c_client *client)
  	}
-@@ -273,7 +278,7 @@ void msp_set_scart(struct i2c_client *client, int in, int out)
- 		state->acb = 0xf60; /* Mute Input and SCART 1 Output */
- 
- 	v4l_dbg(1, msp_debug, client, "scart switch: %s => %d (ACB=0x%04x)\n",
--						scart_names[in], out, state->acb);
-+					scart_names[in], out, state->acb);
- 	msp_write_dsp(client, 0x13, state->acb);
- 
- 	/* Sets I2S speed 0 = 1.024 Mbps, 1 = 2.048 Mbps */
-@@ -292,7 +297,8 @@ void msp_set_audio(struct i2c_client *client)
- 		val = (state->volume * 0x7f / 65535) << 8;
- 
- 	v4l_dbg(1, msp_debug, client, "mute=%s scanning=%s volume=%d\n",
--		state->muted ? "on" : "off", state->scan_in_progress ? "yes" : "no",
-+		state->muted ? "on" : "off",
-+		state->scan_in_progress ? "yes" : "no",
- 		state->volume);
  
- 	msp_write_dsp(client, 0x0000, val);
-@@ -681,14 +687,14 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
- 		v4l_dbg(1, msp_debug, client, "Setting I2S speed to %d\n", *a);
+ 	if (tuner != UNSET) {
+-
+ 		tun_setup.type = tuner;
+ 		tun_setup.addr = saa7134_boards[dev->board].tuner_addr;
+ 		tun_setup.config = saa7134_boards[dev->board].tuner_config;
+@@ -372,9 +371,18 @@ static int attach_inform(struct i2c_client *client)
  
- 		switch (*a) {
--			case 1024000:
--				state->i2s_mode = 0;
--				break;
--			case 2048000:
--				state->i2s_mode = 1;
--				break;
--			default:
--				return -EINVAL;
-+		case 1024000:
-+			state->i2s_mode = 0;
-+			break;
-+		case 2048000:
-+			state->i2s_mode = 1;
-+			break;
-+		default:
-+			return -EINVAL;
+ 			client->driver->command(client,TUNER_SET_TYPE_ADDR, &tun_setup);
  		}
- 		break;
++
++		if (tuner == TUNER_TDA9887) {
++			struct v4l2_priv_tun_config tda9887_cfg;
++
++			tda9887_cfg.tuner = TUNER_TDA9887;
++			tda9887_cfg.priv = &dev->tda9887_conf;
++
++			client->driver->command(client, TUNER_SET_CONFIG,
++						&tda9887_cfg);
++		}
  	}
-@@ -698,22 +704,22 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
- 		struct v4l2_queryctrl *qc = arg;
  
- 		switch (qc->id) {
--			case V4L2_CID_AUDIO_VOLUME:
--			case V4L2_CID_AUDIO_MUTE:
--				return v4l2_ctrl_query_fill_std(qc);
--			default:
--				break;
-+		case V4L2_CID_AUDIO_VOLUME:
-+		case V4L2_CID_AUDIO_MUTE:
-+			return v4l2_ctrl_query_fill_std(qc);
-+		default:
-+			break;
- 		}
- 		if (!state->has_sound_processing)
- 			return -EINVAL;
- 		switch (qc->id) {
--			case V4L2_CID_AUDIO_LOUDNESS:
--			case V4L2_CID_AUDIO_BALANCE:
--			case V4L2_CID_AUDIO_BASS:
--			case V4L2_CID_AUDIO_TREBLE:
--				return v4l2_ctrl_query_fill_std(qc);
--			default:
--				return -EINVAL;
-+		case V4L2_CID_AUDIO_LOUDNESS:
-+		case V4L2_CID_AUDIO_BALANCE:
-+		case V4L2_CID_AUDIO_BASS:
-+		case V4L2_CID_AUDIO_TREBLE:
-+			return v4l2_ctrl_query_fill_std(qc);
-+		default:
-+			return -EINVAL;
- 		}
- 	}
+-	client->driver->command(client, TDA9887_SET_CONFIG, &conf);
  
-@@ -735,13 +741,14 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
- 				state->volume, state->muted ? " (muted)" : "");
- 		if (state->has_sound_processing) {
- 			v4l_info(client, "Audio:    balance %d bass %d treble %d loudness %s\n",
--					state->balance, state->bass, state->treble,
-+					state->balance, state->bass,
-+					state->treble,
- 					state->loudness ? "on" : "off");
- 		}
- 		switch (state->mode) {
- 		case MSP_MODE_AM_DETECT: p = "AM (for carrier detect)"; break;
- 		case MSP_MODE_FM_RADIO: p = "FM Radio"; break;
--		case MSP_MODE_FM_TERRA: p = "Terrestial FM-mono + FM-stereo"; break;
-+		case MSP_MODE_FM_TERRA: p = "Terrestial FM-mono/stereo"; break;
- 		case MSP_MODE_FM_SAT: p = "Satellite FM-mono"; break;
- 		case MSP_MODE_FM_NICAM1: p = "NICAM/FM (B/G, D/K)"; break;
- 		case MSP_MODE_FM_NICAM2: p = "NICAM/FM (I)"; break;
-@@ -772,7 +779,8 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
- 	}
+ 	return 0;
+ }
+@@ -432,6 +440,7 @@ static char *i2c_devs[128] = {
+ 	[ 0xa0 >> 1 ] = "eeprom",
+ 	[ 0xc0 >> 1 ] = "tuner (analog)",
+ 	[ 0x86 >> 1 ] = "tda9887",
++	[ 0x5a >> 1 ] = "remote control",
+ };
  
- 	case VIDIOC_G_CHIP_IDENT:
--		return v4l2_chip_ident_i2c_client(client, arg, state->ident, (state->rev1 << 16) | state->rev2);
-+		return v4l2_chip_ident_i2c_client(client, arg, state->ident,
-+				(state->rev1 << 16) | state->rev2);
+ static void do_i2c_scan(char *name, struct i2c_client *c)
+diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c
+index 3abaa1b..0db955c 100644
+--- a/drivers/media/video/saa7134/saa7134-input.c
++++ b/drivers/media/video/saa7134/saa7134-input.c
+@@ -49,9 +49,14 @@ module_param(repeat_delay, int, 0644);
+ MODULE_PARM_DESC(repeat_delay, "delay before key repeat started");
+ static int repeat_period = 33;
+ module_param(repeat_period, int, 0644);
+-MODULE_PARM_DESC(repeat_period, "repeat period between"
++MODULE_PARM_DESC(repeat_period, "repeat period between "
+     "keypresses when key is down");
  
- 	default:
- 		/* unknown */
-@@ -783,7 +791,6 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
++static unsigned int disable_other_ir;
++module_param(disable_other_ir, int, 0644);
++MODULE_PARM_DESC(disable_other_ir, "disable full codes of "
++    "alternative remotes from other manufacturers");
++
+ #define dprintk(fmt, arg...)	if (ir_debug) \
+ 	printk(KERN_DEBUG "%s/ir: " fmt, dev->name , ## arg)
+ #define i2cdprintk(fmt, arg...)    if (ir_debug) \
+@@ -154,6 +159,45 @@ static int get_key_hvr1110(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+ 	return 1;
+ }
  
- static int msp_suspend(struct i2c_client *client, pm_message_t state)
++
++static int get_key_beholdm6xx(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
++{
++	unsigned char data[12];
++	u32 gpio;
++
++	struct saa7134_dev *dev = ir->c.adapter->algo_data;
++
++	/* 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);
++
++	if (0x400000 & ~gpio)
++		return 0; /* No button press */
++
++	ir->c.addr = 0x5a >> 1;
++
++	if (12 != i2c_master_recv(&ir->c, data, 12)) {
++		i2cdprintk("read error\n");
++		return -EIO;
++	}
++	/* IR of this card normally decode signals NEC-standard from
++	 * - Sven IHOO MT 5.1R remote. xxyye718
++	 * - Sven DVD HD-10xx remote. xxyyf708
++	 * - BBK ...
++	 * - mayby others
++	 * So, skip not our, if disable full codes mode.
++	 */
++	if (data[10] != 0x6b && data[11] != 0x86 && disable_other_ir)
++		return 0;
++
++	*ir_key = data[9];
++	*ir_raw = data[9];
++
++	return 1;
++}
++
+ void saa7134_input_irq(struct saa7134_dev *dev)
  {
+ 	struct card_ir *ir = dev->remote;
+@@ -260,6 +304,7 @@ int saa7134_input_init1(struct saa7134_dev *dev)
+ 	case SAA7134_BOARD_AVERMEDIA_STUDIO_307:
+ 	case SAA7134_BOARD_AVERMEDIA_STUDIO_507:
+ 	case SAA7134_BOARD_AVERMEDIA_GO_007_FM:
++	case SAA7134_BOARD_AVERMEDIA_M102:
+ 		ir_codes     = ir_codes_avermedia;
+ 		mask_keycode = 0x0007C8;
+ 		mask_keydown = 0x000010;
+@@ -287,6 +332,16 @@ int saa7134_input_init1(struct saa7134_dev *dev)
+ 	case SAA7134_BOARD_MANLI_MTV001:
+ 	case SAA7134_BOARD_MANLI_MTV002:
+ 	case SAA7134_BOARD_BEHOLD_409FM:
++	case SAA7134_BOARD_BEHOLD_401:
++	case SAA7134_BOARD_BEHOLD_403:
++	case SAA7134_BOARD_BEHOLD_403FM:
++	case SAA7134_BOARD_BEHOLD_405:
++	case SAA7134_BOARD_BEHOLD_405FM:
++	case SAA7134_BOARD_BEHOLD_407:
++	case SAA7134_BOARD_BEHOLD_407FM:
++	case SAA7134_BOARD_BEHOLD_409:
++	case SAA7134_BOARD_BEHOLD_505FM:
++	case SAA7134_BOARD_BEHOLD_507_9FM:
+ 		ir_codes     = ir_codes_manli;
+ 		mask_keycode = 0x001f00;
+ 		mask_keyup   = 0x004000;
+@@ -457,6 +512,12 @@ void saa7134_set_i2c_ir(struct saa7134_dev *dev, struct IR_i2c *ir)
+ 		ir->get_key   = get_key_hvr1110;
+ 		ir->ir_codes  = ir_codes_hauppauge_new;
+ 		break;
++	case SAA7134_BOARD_BEHOLD_607_9FM:
++	case SAA7134_BOARD_BEHOLD_M6:
++		snprintf(ir->c.name, sizeof(ir->c.name), "BeholdTV");
++		ir->get_key   = get_key_beholdm6xx;
++		ir->ir_codes  = ir_codes_behold;
++		break;
+ 	default:
+ 		dprintk("Shouldn't get here: Unknown board %x for I2C IR?\n",dev->board);
+ 		break;
+diff --git a/drivers/media/video/saa7134/saa7134-oss.c b/drivers/media/video/saa7134/saa7134-oss.c
+deleted file mode 100644
+index aedf046..0000000
+--- a/drivers/media/video/saa7134/saa7134-oss.c
++++ /dev/null
+@@ -1,1046 +0,0 @@
+-/*
+- *
+- * device driver for philips saa7134 based TV cards
+- * oss dsp interface
+- *
+- * (c) 2001,02 Gerd Knorr <kraxel at bytesex.org> [SuSE Labs]
+- *     2005 conversion to standalone module:
+- *         Ricardo Cerqueira <v4l at cerqueira.org>
+- *
+- *  This program is free software; you can redistribute it and/or modify
+- *  it under the terms of the GNU General Public License as published by
+- *  the Free Software Foundation; either version 2 of the License, or
+- *  (at your option) any later version.
+- *
+- *  This program is distributed in the hope that it will be useful,
+- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+- *  GNU General Public License for more details.
+- *
+- *  You should have received a copy of the GNU General Public License
+- *  along with this program; if not, write to the Free Software
+- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+- */
+-
+-#include <linux/init.h>
+-#include <linux/list.h>
+-#include <linux/module.h>
+-#include <linux/kernel.h>
+-#include <linux/interrupt.h>
+-#include <linux/slab.h>
+-#include <linux/sound.h>
+-#include <linux/soundcard.h>
+-
+-#include "saa7134-reg.h"
+-#include "saa7134.h"
+-
+-/* ------------------------------------------------------------------ */
+-
+-static unsigned int debug  = 0;
+-module_param(debug, int, 0644);
+-MODULE_PARM_DESC(debug,"enable debug messages [oss]");
+-
+-static unsigned int rate  = 0;
+-module_param(rate, int, 0444);
+-MODULE_PARM_DESC(rate,"sample rate (valid are: 32000,48000)");
+-
+-static unsigned int dsp_nr[]   = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET };
+-MODULE_PARM_DESC(dsp_nr, "device numbers for SAA7134 capture interface(s).");
+-module_param_array(dsp_nr,   int, NULL, 0444);
+-
+-static unsigned int mixer_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET };
+-MODULE_PARM_DESC(mixer_nr, "mixer numbers for SAA7134 capture interface(s).");
+-module_param_array(mixer_nr, int, NULL, 0444);
+-
+-#define dprintk(fmt, arg...)	if (debug) \
+-	printk(KERN_DEBUG "%s/oss: " fmt, dev->name , ## arg)
+-
+-
+-/* ------------------------------------------------------------------ */
+-
+-static int dsp_buffer_conf(struct saa7134_dev *dev, int blksize, int blocks)
+-{
+-	if (blksize < 0x100)
+-		blksize = 0x100;
+-	if (blksize > 0x10000)
+-		blksize = 0x10000;
+-
+-	if (blocks < 2)
+-		blocks = 2;
+-	if ((blksize * blocks) > 1024*1024)
+-		blocks = 1024*1024 / blksize;
+-
+-	dev->dmasound.blocks  = blocks;
+-	dev->dmasound.blksize = blksize;
+-	dev->dmasound.bufsize = blksize * blocks;
+-
+-	dprintk("buffer config: %d blocks / %d bytes, %d kB total\n",
+-		blocks,blksize,blksize * blocks / 1024);
+-	return 0;
+-}
+-
+-static int dsp_buffer_init(struct saa7134_dev *dev)
+-{
+-	int err;
+-
+-	BUG_ON(!dev->dmasound.bufsize);
+-	videobuf_dma_init(&dev->dmasound.dma);
+-	err = videobuf_dma_init_kernel(&dev->dmasound.dma, PCI_DMA_FROMDEVICE,
+-				       (dev->dmasound.bufsize + PAGE_SIZE) >> PAGE_SHIFT);
+-	if (0 != err)
+-		return err;
+-	return 0;
+-}
+-
+-static int dsp_buffer_free(struct saa7134_dev *dev)
+-{
+-	BUG_ON(!dev->dmasound.blksize);
+-	videobuf_dma_free(&dev->dmasound.dma);
+-	dev->dmasound.blocks  = 0;
+-	dev->dmasound.blksize = 0;
+-	dev->dmasound.bufsize = 0;
+-	return 0;
+-}
+-
+-static void dsp_dma_start(struct saa7134_dev *dev)
+-{
+-	dev->dmasound.dma_blk     = 0;
+-	dev->dmasound.dma_running = 1;
+-	saa7134_set_dmabits(dev);
+-}
+-
+-static void dsp_dma_stop(struct saa7134_dev *dev)
+-{
+-	dev->dmasound.dma_blk     = -1;
+-	dev->dmasound.dma_running = 0;
+-	saa7134_set_dmabits(dev);
+-}
+-
+-static int dsp_rec_start(struct saa7134_dev *dev)
+-{
+-	int err, bswap, sign;
+-	u32 fmt, control;
+-	unsigned long flags;
+-
+-	/* prepare buffer */
+-	if (0 != (err = videobuf_pci_dma_map(dev->pci,&dev->dmasound.dma)))
+-		return err;
+-	if (0 != (err = saa7134_pgtable_alloc(dev->pci,&dev->dmasound.pt)))
+-		goto fail1;
+-	if (0 != (err = saa7134_pgtable_build(dev->pci,&dev->dmasound.pt,
+-					      dev->dmasound.dma.sglist,
+-					      dev->dmasound.dma.sglen,
+-					      0)))
+-		goto fail2;
+-
+-	/* sample format */
+-	switch (dev->dmasound.afmt) {
+-	case AFMT_U8:
+-	case AFMT_S8:     fmt = 0x00;  break;
+-	case AFMT_U16_LE:
+-	case AFMT_U16_BE:
+-	case AFMT_S16_LE:
+-	case AFMT_S16_BE: fmt = 0x01;  break;
+-	default:
+-		err = -EINVAL;
+-		goto fail2;
+-	}
+-
+-	switch (dev->dmasound.afmt) {
+-	case AFMT_S8:
+-	case AFMT_S16_LE:
+-	case AFMT_S16_BE: sign = 1; break;
+-	default:          sign = 0; break;
+-	}
+-
+-	switch (dev->dmasound.afmt) {
+-	case AFMT_U16_BE:
+-	case AFMT_S16_BE: bswap = 1; break;
+-	default:          bswap = 0; break;
+-	}
+-
+-	switch (dev->pci->device) {
+-	case PCI_DEVICE_ID_PHILIPS_SAA7134:
+-		if (1 == dev->dmasound.channels)
+-			fmt |= (1 << 3);
+-		if (2 == dev->dmasound.channels)
+-			fmt |= (3 << 3);
+-		if (sign)
+-			fmt |= 0x04;
+-		fmt |= (TV == dev->dmasound.input) ? 0xc0 : 0x80;
+-
+-		saa_writeb(SAA7134_NUM_SAMPLES0, ((dev->dmasound.blksize - 1) & 0x0000ff));
+-		saa_writeb(SAA7134_NUM_SAMPLES1, ((dev->dmasound.blksize - 1) & 0x00ff00) >>  8);
+-		saa_writeb(SAA7134_NUM_SAMPLES2, ((dev->dmasound.blksize - 1) & 0xff0000) >> 16);
+-		saa_writeb(SAA7134_AUDIO_FORMAT_CTRL, fmt);
+-
+-		break;
+-	case PCI_DEVICE_ID_PHILIPS_SAA7133:
+-	case PCI_DEVICE_ID_PHILIPS_SAA7135:
+-		if (1 == dev->dmasound.channels)
+-			fmt |= (1 << 4);
+-		if (2 == dev->dmasound.channels)
+-			fmt |= (2 << 4);
+-		if (!sign)
+-			fmt |= 0x04;
+-		saa_writel(SAA7133_NUM_SAMPLES, dev->dmasound.blksize -4);
+-		saa_writel(SAA7133_AUDIO_CHANNEL, 0x543210 | (fmt << 24));
+-		break;
+-	}
+-	dprintk("rec_start: afmt=%d ch=%d  =>  fmt=0x%x swap=%c\n",
+-		dev->dmasound.afmt, dev->dmasound.channels, fmt,
+-		bswap ? 'b' : '-');
+-
+-	/* dma: setup channel 6 (= AUDIO) */
+-	control = SAA7134_RS_CONTROL_BURST_16 |
+-		SAA7134_RS_CONTROL_ME |
+-		(dev->dmasound.pt.dma >> 12);
+-	if (bswap)
+-		control |= SAA7134_RS_CONTROL_BSWAP;
+-	saa_writel(SAA7134_RS_BA1(6),0);
+-	saa_writel(SAA7134_RS_BA2(6),dev->dmasound.blksize);
+-	saa_writel(SAA7134_RS_PITCH(6),0);
+-	saa_writel(SAA7134_RS_CONTROL(6),control);
+-
+-	/* start dma */
+-	dev->dmasound.recording_on = 1;
+-	spin_lock_irqsave(&dev->slock,flags);
+-	dsp_dma_start(dev);
+-	spin_unlock_irqrestore(&dev->slock,flags);
+-	return 0;
+-
+- fail2:
+-	saa7134_pgtable_free(dev->pci,&dev->dmasound.pt);
+- fail1:
+-	videobuf_pci_dma_unmap(dev->pci,&dev->dmasound.dma);
+-	return err;
+-}
+-
+-static int dsp_rec_stop(struct saa7134_dev *dev)
+-{
+-	unsigned long flags;
+-
+-	dprintk("rec_stop dma_blk=%d\n",dev->dmasound.dma_blk);
+-
+-	/* stop dma */
+-	dev->dmasound.recording_on = 0;
+-	spin_lock_irqsave(&dev->slock,flags);
+-	dsp_dma_stop(dev);
+-	spin_unlock_irqrestore(&dev->slock,flags);
+-
+-	/* unlock buffer */
+-	saa7134_pgtable_free(dev->pci,&dev->dmasound.pt);
+-	videobuf_pci_dma_unmap(dev->pci,&dev->dmasound.dma);
+-	return 0;
+-}
+-
+-/* ------------------------------------------------------------------ */
+-
+-static int dsp_open(struct inode *inode, struct file *file)
+-{
+-	int minor = iminor(inode);
+-	struct saa7134_dev *dev;
+-	int err;
+-
+-	list_for_each_entry(dev, &saa7134_devlist, devlist)
+-		if (dev->dmasound.minor_dsp == minor)
+-			goto found;
+-	return -ENODEV;
+- found:
+-
+-	mutex_lock(&dev->dmasound.lock);
+-	err = -EBUSY;
+-	if (dev->dmasound.users_dsp)
+-		goto fail1;
+-	dev->dmasound.users_dsp++;
+-	file->private_data = dev;
+-
+-	dev->dmasound.afmt        = AFMT_U8;
+-	dev->dmasound.channels    = 1;
+-	dev->dmasound.read_count  = 0;
+-	dev->dmasound.read_offset = 0;
+-	dsp_buffer_conf(dev,PAGE_SIZE,64);
+-	err = dsp_buffer_init(dev);
+-	if (0 != err)
+-		goto fail2;
+-
+-	mutex_unlock(&dev->dmasound.lock);
+-	return 0;
+-
+- fail2:
+-	dev->dmasound.users_dsp--;
+- fail1:
+-	mutex_unlock(&dev->dmasound.lock);
+-	return err;
+-}
+-
+-static int dsp_release(struct inode *inode, struct file *file)
+-{
+-	struct saa7134_dev *dev = file->private_data;
+-
+-	mutex_lock(&dev->dmasound.lock);
+-	if (dev->dmasound.recording_on)
+-		dsp_rec_stop(dev);
+-	dsp_buffer_free(dev);
+-	dev->dmasound.users_dsp--;
+-	file->private_data = NULL;
+-	mutex_unlock(&dev->dmasound.lock);
+-	return 0;
+-}
+-
+-static ssize_t dsp_read(struct file *file, char __user *buffer,
+-			size_t count, loff_t *ppos)
+-{
+-	struct saa7134_dev *dev = file->private_data;
+-	DECLARE_WAITQUEUE(wait, current);
+-	unsigned int bytes;
+-	unsigned long flags;
+-	int err,ret = 0;
+-
+-	add_wait_queue(&dev->dmasound.wq, &wait);
+-	mutex_lock(&dev->dmasound.lock);
+-	while (count > 0) {
+-		/* wait for data if needed */
+-		if (0 == dev->dmasound.read_count) {
+-			if (!dev->dmasound.recording_on) {
+-				err = dsp_rec_start(dev);
+-				if (err < 0) {
+-					if (0 == ret)
+-						ret = err;
+-					break;
+-				}
+-			}
+-			if (dev->dmasound.recording_on &&
+-			    !dev->dmasound.dma_running) {
+-				/* recover from overruns */
+-				spin_lock_irqsave(&dev->slock,flags);
+-				dsp_dma_start(dev);
+-				spin_unlock_irqrestore(&dev->slock,flags);
+-			}
+-			if (file->f_flags & O_NONBLOCK) {
+-				if (0 == ret)
+-					ret = -EAGAIN;
+-				break;
+-			}
+-			mutex_unlock(&dev->dmasound.lock);
+-			set_current_state(TASK_INTERRUPTIBLE);
+-			if (0 == dev->dmasound.read_count)
+-				schedule();
+-			set_current_state(TASK_RUNNING);
+-			mutex_lock(&dev->dmasound.lock);
+-			if (signal_pending(current)) {
+-				if (0 == ret)
+-					ret = -EINTR;
+-				break;
+-			}
+-		}
+-
+-		/* copy data to userspace */
+-		bytes = count;
+-		if (bytes > dev->dmasound.read_count)
+-			bytes = dev->dmasound.read_count;
+-		if (bytes > dev->dmasound.bufsize - dev->dmasound.read_offset)
+-			bytes = dev->dmasound.bufsize - dev->dmasound.read_offset;
+-		if (copy_to_user(buffer + ret,
+-				 dev->dmasound.dma.vmalloc + dev->dmasound.read_offset,
+-				 bytes)) {
+-			if (0 == ret)
+-				ret = -EFAULT;
+-			break;
+-		}
+-
+-		ret   += bytes;
+-		count -= bytes;
+-		dev->dmasound.read_count  -= bytes;
+-		dev->dmasound.read_offset += bytes;
+-		if (dev->dmasound.read_offset == dev->dmasound.bufsize)
+-			dev->dmasound.read_offset = 0;
+-	}
+-	mutex_unlock(&dev->dmasound.lock);
+-	remove_wait_queue(&dev->dmasound.wq, &wait);
+-	return ret;
+-}
+-
+-static ssize_t dsp_write(struct file *file, const char __user *buffer,
+-			 size_t count, loff_t *ppos)
+-{
+-	return -EINVAL;
+-}
+-
+-static const char *osspcm_ioctls[] = {
+-	"RESET", "SYNC", "SPEED", "STEREO", "GETBLKSIZE", "SETFMT",
+-	"CHANNELS", "?", "POST", "SUBDIVIDE", "SETFRAGMENT", "GETFMTS",
+-	"GETOSPACE", "GETISPACE", "NONBLOCK", "GETCAPS", "GET/SETTRIGGER",
+-	"GETIPTR", "GETOPTR", "MAPINBUF", "MAPOUTBUF", "SETSYNCRO",
+-	"SETDUPLEX", "GETODELAY"
+-};
+-#define OSSPCM_IOCTLS ARRAY_SIZE(osspcm_ioctls)
+-
+-static void saa7134_oss_print_ioctl(char *name, unsigned int cmd)
+-{
+-	char *dir;
+-
+-	switch (_IOC_DIR(cmd)) {
+-	case _IOC_NONE:              dir = "--"; break;
+-	case _IOC_READ:              dir = "r-"; break;
+-	case _IOC_WRITE:             dir = "-w"; break;
+-	case _IOC_READ | _IOC_WRITE: dir = "rw"; break;
+-	default:                     dir = "??"; break;
+-	}
+-	switch (_IOC_TYPE(cmd)) {
+-	case 'P':
+-		printk(KERN_DEBUG "%s: ioctl 0x%08x (oss dsp, %s, SNDCTL_DSP_%s)\n",
+-		       name, cmd, dir, (_IOC_NR(cmd) < OSSPCM_IOCTLS) ?
+-		       osspcm_ioctls[_IOC_NR(cmd)] : "???");
+-		break;
+-	case 'M':
+-		printk(KERN_DEBUG "%s: ioctl 0x%08x (oss mixer, %s, #%d)\n",
+-		       name, cmd, dir, _IOC_NR(cmd));
+-		break;
+-	default:
+-		printk(KERN_DEBUG "%s: ioctl 0x%08x (???, %s, #%d)\n",
+-		       name, cmd, dir, _IOC_NR(cmd));
+-	}
+-}
+-
+-static int dsp_ioctl(struct inode *inode, struct file *file,
+-		     unsigned int cmd, unsigned long arg)
+-{
+-	struct saa7134_dev *dev = file->private_data;
+-	void __user *argp = (void __user *) arg;
+-	int __user *p = argp;
+-	int val = 0;
 -
- 	v4l_dbg(1, msp_debug, client, "suspend\n");
- 	msp_reset(client);
- 	return 0;
-@@ -791,7 +798,6 @@ static int msp_suspend(struct i2c_client *client, pm_message_t state)
- 
- static int msp_resume(struct i2c_client *client)
- {
+-	if (debug > 1)
+-		saa7134_oss_print_ioctl(dev->name,cmd);
+-	switch (cmd) {
+-	case OSS_GETVERSION:
+-		return put_user(SOUND_VERSION, p);
+-	case SNDCTL_DSP_GETCAPS:
+-		return 0;
 -
- 	v4l_dbg(1, msp_debug, client, "resume\n");
- 	msp_wake_thread(client);
- 	return 0;
-@@ -799,11 +805,8 @@ static int msp_resume(struct i2c_client *client)
- 
- /* ----------------------------------------------------------------------- */
- 
--static struct i2c_driver i2c_driver;
+-	case SNDCTL_DSP_SPEED:
+-		if (get_user(val, p))
+-			return -EFAULT;
+-		/* fall through */
+-	case SOUND_PCM_READ_RATE:
+-		return put_user(dev->dmasound.rate, p);
 -
--static int msp_attach(struct i2c_adapter *adapter, int address, int kind)
-+static int msp_probe(struct i2c_client *client)
- {
--	struct i2c_client *client;
- 	struct msp_state *state;
- 	int (*thread_func)(void *data) = NULL;
- 	int msp_hard;
-@@ -812,26 +815,16 @@ static int msp_attach(struct i2c_adapter *adapter, int address, int kind)
- 	int msp_product, msp_prod_hi, msp_prod_lo;
- 	int msp_rom;
- 
--	client = kzalloc(sizeof(*client), GFP_KERNEL);
--	if (!client)
--		return -ENOMEM;
+-	case SNDCTL_DSP_STEREO:
+-		if (get_user(val, p))
+-			return -EFAULT;
+-		mutex_lock(&dev->dmasound.lock);
+-		dev->dmasound.channels = val ? 2 : 1;
+-		if (dev->dmasound.recording_on) {
+-			dsp_rec_stop(dev);
+-			dsp_rec_start(dev);
+-		}
+-		mutex_unlock(&dev->dmasound.lock);
+-		return put_user(dev->dmasound.channels-1, p);
 -
--	client->addr = address;
--	client->adapter = adapter;
--	client->driver = &i2c_driver;
- 	snprintf(client->name, sizeof(client->name) - 1, "msp3400");
- 
- 	if (msp_reset(client) == -1) {
- 		v4l_dbg(1, msp_debug, client, "msp3400 not found\n");
--		kfree(client);
+-	case SNDCTL_DSP_CHANNELS:
+-		if (get_user(val, p))
+-			return -EFAULT;
+-		if (val != 1 && val != 2)
+-			return -EINVAL;
+-		mutex_lock(&dev->dmasound.lock);
+-		dev->dmasound.channels = val;
+-		if (dev->dmasound.recording_on) {
+-			dsp_rec_stop(dev);
+-			dsp_rec_start(dev);
+-		}
+-		mutex_unlock(&dev->dmasound.lock);
+-		/* fall through */
+-	case SOUND_PCM_READ_CHANNELS:
+-		return put_user(dev->dmasound.channels, p);
+-
+-	case SNDCTL_DSP_GETFMTS: /* Returns a mask */
+-		return put_user(AFMT_U8     | AFMT_S8     |
+-				AFMT_U16_LE | AFMT_U16_BE |
+-				AFMT_S16_LE | AFMT_S16_BE, p);
+-
+-	case SNDCTL_DSP_SETFMT: /* Selects ONE fmt */
+-		if (get_user(val, p))
+-			return -EFAULT;
+-		switch (val) {
+-		case AFMT_QUERY:
+-			/* nothing to do */
+-			break;
+-		case AFMT_U8:
+-		case AFMT_S8:
+-		case AFMT_U16_LE:
+-		case AFMT_U16_BE:
+-		case AFMT_S16_LE:
+-		case AFMT_S16_BE:
+-			mutex_lock(&dev->dmasound.lock);
+-			dev->dmasound.afmt = val;
+-			if (dev->dmasound.recording_on) {
+-				dsp_rec_stop(dev);
+-				dsp_rec_start(dev);
+-			}
+-			mutex_unlock(&dev->dmasound.lock);
+-			return put_user(dev->dmasound.afmt, p);
+-		default:
+-			return -EINVAL;
+-		}
+-
+-	case SOUND_PCM_READ_BITS:
+-		switch (dev->dmasound.afmt) {
+-		case AFMT_U8:
+-		case AFMT_S8:
+-			return put_user(8, p);
+-		case AFMT_U16_LE:
+-		case AFMT_U16_BE:
+-		case AFMT_S16_LE:
+-		case AFMT_S16_BE:
+-			return put_user(16, p);
+-		default:
+-			return -EINVAL;
+-		}
+-
+-	case SNDCTL_DSP_NONBLOCK:
+-		file->f_flags |= O_NONBLOCK;
+-		return 0;
+-
+-	case SNDCTL_DSP_RESET:
+-		mutex_lock(&dev->dmasound.lock);
+-		if (dev->dmasound.recording_on)
+-			dsp_rec_stop(dev);
+-		mutex_unlock(&dev->dmasound.lock);
+-		return 0;
+-	case SNDCTL_DSP_GETBLKSIZE:
+-		return put_user(dev->dmasound.blksize, p);
+-
+-	case SNDCTL_DSP_SETFRAGMENT:
+-		if (get_user(val, p))
+-			return -EFAULT;
+-		if (dev->dmasound.recording_on)
+-			return -EBUSY;
+-		dsp_buffer_free(dev);
+-		/* used to be arg >> 16 instead of val >> 16; fixed */
+-		dsp_buffer_conf(dev,1 << (val & 0xffff), (val >> 16) & 0xffff);
+-		dsp_buffer_init(dev);
+-		return 0;
+-
+-	case SNDCTL_DSP_SYNC:
+-		/* NOP */
+-		return 0;
+-
+-	case SNDCTL_DSP_GETISPACE:
+-	{
+-		audio_buf_info info;
+-		info.fragsize   = dev->dmasound.blksize;
+-		info.fragstotal = dev->dmasound.blocks;
+-		info.bytes      = dev->dmasound.read_count;
+-		info.fragments  = info.bytes / info.fragsize;
+-		if (copy_to_user(argp, &info, sizeof(info)))
+-			return -EFAULT;
 -		return 0;
-+		return -ENODEV;
- 	}
- 
- 	state = kzalloc(sizeof(*state), GFP_KERNEL);
--	if (!state) {
--		kfree(client);
-+	if (!state)
- 		return -ENOMEM;
 -	}
- 
- 	i2c_set_clientdata(client, state);
- 
-@@ -853,12 +846,13 @@ static int msp_attach(struct i2c_adapter *adapter, int address, int kind)
- 	state->rev1 = msp_read_dsp(client, 0x1e);
- 	if (state->rev1 != -1)
- 		state->rev2 = msp_read_dsp(client, 0x1f);
--	v4l_dbg(1, msp_debug, client, "rev1=0x%04x, rev2=0x%04x\n", state->rev1, state->rev2);
-+	v4l_dbg(1, msp_debug, client, "rev1=0x%04x, rev2=0x%04x\n",
-+			state->rev1, state->rev2);
- 	if (state->rev1 == -1 || (state->rev1 == 0 && state->rev2 == 0)) {
--		v4l_dbg(1, msp_debug, client, "not an msp3400 (cannot read chip version)\n");
-+		v4l_dbg(1, msp_debug, client,
-+				"not an msp3400 (cannot read chip version)\n");
- 		kfree(state);
--		kfree(client);
+-	default:
+-		return -EINVAL;
+-	}
+-}
+-
+-static unsigned int dsp_poll(struct file *file, struct poll_table_struct *wait)
+-{
+-	struct saa7134_dev *dev = file->private_data;
+-	unsigned int mask = 0;
+-
+-	poll_wait(file, &dev->dmasound.wq, wait);
+-
+-	if (0 == dev->dmasound.read_count) {
+-		mutex_lock(&dev->dmasound.lock);
+-		if (!dev->dmasound.recording_on)
+-			dsp_rec_start(dev);
+-		mutex_unlock(&dev->dmasound.lock);
+-	} else
+-		mask |= (POLLIN | POLLRDNORM);
+-	return mask;
+-}
+-
+-const struct file_operations saa7134_dsp_fops = {
+-	.owner   = THIS_MODULE,
+-	.open    = dsp_open,
+-	.release = dsp_release,
+-	.read    = dsp_read,
+-	.write   = dsp_write,
+-	.ioctl   = dsp_ioctl,
+-	.poll    = dsp_poll,
+-	.llseek  = no_llseek,
+-};
+-
+-/* ------------------------------------------------------------------ */
+-
+-static int
+-mixer_recsrc_7134(struct saa7134_dev *dev)
+-{
+-	int analog_io,rate;
+-
+-	switch (dev->dmasound.input) {
+-	case TV:
+-		saa_andorb(SAA7134_AUDIO_FORMAT_CTRL, 0xc0, 0xc0);
+-		saa_andorb(SAA7134_SIF_SAMPLE_FREQ,   0x03, 0x00);
+-		break;
+-	case LINE1:
+-	case LINE2:
+-	case LINE2_LEFT:
+-		analog_io = (LINE1 == dev->dmasound.input) ? 0x00 : 0x08;
+-		rate = (32000 == dev->dmasound.rate) ? 0x01 : 0x03;
+-		saa_andorb(SAA7134_ANALOG_IO_SELECT,  0x08, analog_io);
+-		saa_andorb(SAA7134_AUDIO_FORMAT_CTRL, 0xc0, 0x80);
+-		saa_andorb(SAA7134_SIF_SAMPLE_FREQ,   0x03, rate);
+-		break;
+-	}
+-	return 0;
+-}
+-
+-static int
+-mixer_recsrc_7133(struct saa7134_dev *dev)
+-{
+-	u32 anabar, xbarin;
+-
+-	xbarin = 0x03; // adc
+-    anabar = 0;
+-	switch (dev->dmasound.input) {
+-	case TV:
+-		xbarin = 0; // Demodulator
+-	anabar = 2; // DACs
+-		break;
+-	case LINE1:
+-		anabar = 0;  // aux1, aux1
+-		break;
+-	case LINE2:
+-	case LINE2_LEFT:
+-		anabar = 9;  // aux2, aux2
+-		break;
+-	}
+-    /* output xbar always main channel */
+-	saa_dsp_writel(dev, 0x46c >> 2, 0xbbbb10);
+-	saa_dsp_writel(dev, 0x464 >> 2, xbarin);
+-	saa_writel(0x594 >> 2, anabar);
+-
+-	return 0;
+-}
+-
+-static int
+-mixer_recsrc(struct saa7134_dev *dev, enum saa7134_audio_in src)
+-{
+-	static const char *iname[] = { "Oops", "TV", "LINE1", "LINE2" };
+-
+-	dev->dmasound.count++;
+-	dev->dmasound.input = src;
+-	dprintk("mixer input = %s\n",iname[dev->dmasound.input]);
+-
+-	switch (dev->pci->device) {
+-	case PCI_DEVICE_ID_PHILIPS_SAA7134:
+-		mixer_recsrc_7134(dev);
+-		break;
+-	case PCI_DEVICE_ID_PHILIPS_SAA7133:
+-	case PCI_DEVICE_ID_PHILIPS_SAA7135:
+-		mixer_recsrc_7133(dev);
+-		break;
+-	}
+-	return 0;
+-}
+-
+-static int
+-mixer_level(struct saa7134_dev *dev, enum saa7134_audio_in src, int level)
+-{
+-	switch (dev->pci->device) {
+-	case PCI_DEVICE_ID_PHILIPS_SAA7134:
+-		switch (src) {
+-		case TV:
+-			/* nothing */
+-			break;
+-		case LINE1:
+-			saa_andorb(SAA7134_ANALOG_IO_SELECT,  0x10,
+-				   (100 == level) ? 0x00 : 0x10);
+-			break;
+-		case LINE2:
+-		case LINE2_LEFT:
+-			saa_andorb(SAA7134_ANALOG_IO_SELECT,  0x20,
+-				   (100 == level) ? 0x00 : 0x20);
+-			break;
+-		}
+-		break;
+-	case PCI_DEVICE_ID_PHILIPS_SAA7133:
+-	case PCI_DEVICE_ID_PHILIPS_SAA7135:
+-		/* nothing */
+-		break;
+-	}
+-	return 0;
+-}
+-
+-/* ------------------------------------------------------------------ */
+-
+-static int mixer_open(struct inode *inode, struct file *file)
+-{
+-	int minor = iminor(inode);
+-	struct saa7134_dev *dev;
+-
+-	list_for_each_entry(dev, &saa7134_devlist, devlist)
+-		if (dev->dmasound.minor_mixer == minor) {
+-			file->private_data = dev;
+-			return 0;
+-		}
+-	return -ENODEV;
+-}
+-
+-static int mixer_release(struct inode *inode, struct file *file)
+-{
+-	file->private_data = NULL;
+-	return 0;
+-}
+-
+-static int mixer_ioctl(struct inode *inode, struct file *file,
+-		     unsigned int cmd, unsigned long arg)
+-{
+-	struct saa7134_dev *dev = file->private_data;
+-	enum saa7134_audio_in input;
+-	int val,ret;
+-	void __user *argp = (void __user *) arg;
+-	int __user *p = argp;
+-
+-	if (debug > 1)
+-		saa7134_oss_print_ioctl(dev->name,cmd);
+-	switch (cmd) {
+-	case OSS_GETVERSION:
+-		return put_user(SOUND_VERSION, p);
+-	case SOUND_MIXER_INFO:
+-	{
+-		mixer_info info;
+-		memset(&info,0,sizeof(info));
+-		strlcpy(info.id,   "TV audio", sizeof(info.id));
+-		strlcpy(info.name, dev->name,  sizeof(info.name));
+-		info.modify_counter = dev->dmasound.count;
+-		if (copy_to_user(argp, &info, sizeof(info)))
+-			return -EFAULT;
 -		return 0;
-+		return -ENODEV;
- 	}
- 
- 	msp_set_audio(client);
-@@ -874,37 +868,55 @@ static int msp_attach(struct i2c_adapter *adapter, int address, int kind)
- 			msp_family, msp_product,
- 			msp_revision, msp_hard, msp_rom);
- 	/* Rev B=2, C=3, D=4, G=7 */
--	state->ident = msp_family * 10000 + 4000 + msp_product * 10 + msp_revision - '@';
-+	state->ident = msp_family * 10000 + 4000 + msp_product * 10 +
-+			msp_revision - '@';
- 
- 	/* Has NICAM support: all mspx41x and mspx45x products have NICAM */
--	state->has_nicam = msp_prod_hi == 1 || msp_prod_hi == 5;
-+	state->has_nicam =
-+		msp_prod_hi == 1 || msp_prod_hi == 5;
- 	/* Has radio support: was added with revision G */
--	state->has_radio = msp_revision >= 'G';
-+	state->has_radio =
-+		msp_revision >= 'G';
- 	/* Has headphones output: not for stripped down products */
--	state->has_headphones = msp_prod_lo < 5;
-+	state->has_headphones =
-+		msp_prod_lo < 5;
- 	/* Has scart2 input: not in stripped down products of the '3' family */
--	state->has_scart2 = msp_family >= 4 || msp_prod_lo < 7;
-+	state->has_scart2 =
-+		msp_family >= 4 || msp_prod_lo < 7;
- 	/* Has scart3 input: not in stripped down products of the '3' family */
--	state->has_scart3 = msp_family >= 4 || msp_prod_lo < 5;
-+	state->has_scart3 =
-+		msp_family >= 4 || msp_prod_lo < 5;
- 	/* Has scart4 input: not in pre D revisions, not in stripped D revs */
--	state->has_scart4 = msp_family >= 4 || (msp_revision >= 'D' && msp_prod_lo < 5);
--	/* Has scart2 output: not in stripped down products of the '3' family */
--	state->has_scart2_out = msp_family >= 4 || msp_prod_lo < 5;
-+	state->has_scart4 =
-+		msp_family >= 4 || (msp_revision >= 'D' && msp_prod_lo < 5);
-+	/* Has scart2 output: not in stripped down products of
-+	 * the '3' family */
-+	state->has_scart2_out =
-+		msp_family >= 4 || msp_prod_lo < 5;
- 	/* Has scart2 a volume control? Not in pre-D revisions. */
--	state->has_scart2_out_volume = msp_revision > 'C' && state->has_scart2_out;
-+	state->has_scart2_out_volume =
-+		msp_revision > 'C' && state->has_scart2_out;
- 	/* Has a configurable i2s out? */
--	state->has_i2s_conf = msp_revision >= 'G' && msp_prod_lo < 7;
--	/* Has subwoofer output: not in pre-D revs and not in stripped down products */
--	state->has_subwoofer = msp_revision >= 'D' && msp_prod_lo < 5;
--	/* Has soundprocessing (bass/treble/balance/loudness/equalizer): not in
--	   stripped down products */
--	state->has_sound_processing = msp_prod_lo < 7;
-+	state->has_i2s_conf =
-+		msp_revision >= 'G' && msp_prod_lo < 7;
-+	/* Has subwoofer output: not in pre-D revs and not in stripped down
-+	 * products */
-+	state->has_subwoofer =
-+		msp_revision >= 'D' && msp_prod_lo < 5;
-+	/* Has soundprocessing (bass/treble/balance/loudness/equalizer):
-+	 *  not in stripped down products */
-+	state->has_sound_processing =
-+		msp_prod_lo < 7;
- 	/* Has Virtual Dolby Surround: only in msp34x1 */
--	state->has_virtual_dolby_surround = msp_revision == 'G' && msp_prod_lo == 1;
-+	state->has_virtual_dolby_surround =
-+		msp_revision == 'G' && msp_prod_lo == 1;
- 	/* Has Virtual Dolby Surround & Dolby Pro Logic: only in msp34x2 */
--	state->has_dolby_pro_logic = msp_revision == 'G' && msp_prod_lo == 2;
--	/* The msp343xG supports BTSC only and cannot do Automatic Standard Detection. */
--	state->force_btsc = msp_family == 3 && msp_revision == 'G' && msp_prod_hi == 3;
-+	state->has_dolby_pro_logic =
-+		msp_revision == 'G' && msp_prod_lo == 2;
-+	/* The msp343xG supports BTSC only and cannot do Automatic Standard
-+	 * Detection. */
-+	state->force_btsc =
-+		msp_family == 3 && msp_revision == 'G' && msp_prod_hi == 3;
- 
- 	state->opmode = opmode;
- 	if (state->opmode == OPMODE_AUTO) {
-@@ -919,32 +931,33 @@ static int msp_attach(struct i2c_adapter *adapter, int address, int kind)
- 	}
- 
- 	/* hello world :-) */
--	v4l_info(client, "%s found @ 0x%x (%s)\n", client->name, address << 1, adapter->name);
-+	v4l_info(client, "%s found @ 0x%x (%s)\n", client->name,
-+			client->addr << 1, client->adapter->name);
- 	v4l_info(client, "%s ", client->name);
- 	if (state->has_nicam && state->has_radio)
--		printk("supports nicam and radio, ");
-+		printk(KERN_CONT "supports nicam and radio, ");
- 	else if (state->has_nicam)
--		printk("supports nicam, ");
-+		printk(KERN_CONT "supports nicam, ");
- 	else if (state->has_radio)
--		printk("supports radio, ");
--	printk("mode is ");
-+		printk(KERN_CONT "supports radio, ");
-+	printk(KERN_CONT "mode is ");
- 
- 	/* version-specific initialization */
- 	switch (state->opmode) {
- 	case OPMODE_MANUAL:
--		printk("manual");
-+		printk(KERN_CONT "manual");
- 		thread_func = msp3400c_thread;
- 		break;
- 	case OPMODE_AUTODETECT:
--		printk("autodetect");
-+		printk(KERN_CONT "autodetect");
- 		thread_func = msp3410d_thread;
- 		break;
- 	case OPMODE_AUTOSELECT:
--		printk("autodetect and autoselect");
-+		printk(KERN_CONT "autodetect and autoselect");
- 		thread_func = msp34xxg_thread;
- 		break;
- 	}
--	printk("\n");
-+	printk(KERN_CONT "\n");
- 
- 	/* startup control thread if needed */
- 	if (thread_func) {
-@@ -954,24 +967,12 @@ static int msp_attach(struct i2c_adapter *adapter, int address, int kind)
- 			v4l_warn(client, "kernel_thread() failed\n");
- 		msp_wake_thread(client);
- 	}
+-	}
+-	case SOUND_OLD_MIXER_INFO:
+-	{
+-		_old_mixer_info info;
+-		memset(&info,0,sizeof(info));
+-		strlcpy(info.id,   "TV audio", sizeof(info.id));
+-		strlcpy(info.name, dev->name,  sizeof(info.name));
+-		if (copy_to_user(argp, &info, sizeof(info)))
+-			return -EFAULT;
+-		return 0;
+-	}
+-	case MIXER_READ(SOUND_MIXER_CAPS):
+-		return put_user(SOUND_CAP_EXCL_INPUT, p);
+-	case MIXER_READ(SOUND_MIXER_STEREODEVS):
+-		return put_user(0, p);
+-	case MIXER_READ(SOUND_MIXER_RECMASK):
+-	case MIXER_READ(SOUND_MIXER_DEVMASK):
+-		val = SOUND_MASK_LINE1 | SOUND_MASK_LINE2;
+-		if (32000 == dev->dmasound.rate)
+-			val |= SOUND_MASK_VIDEO;
+-		return put_user(val, p);
 -
--	/* done */
--	i2c_attach_client(client);
+-	case MIXER_WRITE(SOUND_MIXER_RECSRC):
+-		if (get_user(val, p))
+-			return -EFAULT;
+-		input = dev->dmasound.input;
+-		if (32000 == dev->dmasound.rate  &&
+-		    val & SOUND_MASK_VIDEO  &&  dev->dmasound.input != TV)
+-			input = TV;
+-		if (val & SOUND_MASK_LINE1  &&  dev->dmasound.input != LINE1)
+-			input = LINE1;
+-		if (val & SOUND_MASK_LINE2  &&  dev->dmasound.input != LINE2)
+-			input = LINE2;
+-		if (input != dev->dmasound.input)
+-			mixer_recsrc(dev,input);
+-		/* fall throuth */
+-	case MIXER_READ(SOUND_MIXER_RECSRC):
+-		switch (dev->dmasound.input) {
+-		case TV:    ret = SOUND_MASK_VIDEO; break;
+-		case LINE1: ret = SOUND_MASK_LINE1; break;
+-		case LINE2: ret = SOUND_MASK_LINE2; break;
+-		default:    ret = 0;
+-		}
+-		return put_user(ret, p);
 -
- 	return 0;
- }
- 
--static int msp_probe(struct i2c_adapter *adapter)
+-	case MIXER_WRITE(SOUND_MIXER_VIDEO):
+-	case MIXER_READ(SOUND_MIXER_VIDEO):
+-		if (32000 != dev->dmasound.rate)
+-			return -EINVAL;
+-		return put_user(100 | 100 << 8, p);
+-
+-	case MIXER_WRITE(SOUND_MIXER_LINE1):
+-		if (get_user(val, p))
+-			return -EFAULT;
+-		val &= 0xff;
+-		val = (val <= 50) ? 50 : 100;
+-		dev->dmasound.line1 = val;
+-		mixer_level(dev,LINE1,dev->dmasound.line1);
+-		/* fall throuth */
+-	case MIXER_READ(SOUND_MIXER_LINE1):
+-		return put_user(dev->dmasound.line1 | dev->dmasound.line1 << 8, p);
+-
+-	case MIXER_WRITE(SOUND_MIXER_LINE2):
+-		if (get_user(val, p))
+-			return -EFAULT;
+-		val &= 0xff;
+-		val = (val <= 50) ? 50 : 100;
+-		dev->dmasound.line2 = val;
+-		mixer_level(dev,LINE2,dev->dmasound.line2);
+-		/* fall throuth */
+-	case MIXER_READ(SOUND_MIXER_LINE2):
+-		return put_user(dev->dmasound.line2 | dev->dmasound.line2 << 8, p);
+-
+-	default:
+-		return -EINVAL;
+-	}
+-}
+-
+-const struct file_operations saa7134_mixer_fops = {
+-	.owner   = THIS_MODULE,
+-	.open    = mixer_open,
+-	.release = mixer_release,
+-	.ioctl   = mixer_ioctl,
+-	.llseek  = no_llseek,
+-};
+-
+-/* ------------------------------------------------------------------ */
+-
+-static irqreturn_t saa7134_oss_irq(int irq, void *dev_id)
 -{
--	if (adapter->class & I2C_CLASS_TV_ANALOG)
--		return i2c_probe(adapter, &addr_data, msp_attach);
+-	struct saa7134_dmasound *dmasound = dev_id;
+-	struct saa7134_dev *dev = dmasound->priv_data;
+-	unsigned long report, status;
+-	int loop, handled = 0;
+-
+-	for (loop = 0; loop < 10; loop++) {
+-		report = saa_readl(SAA7134_IRQ_REPORT);
+-		status = saa_readl(SAA7134_IRQ_STATUS);
+-
+-		if (report & SAA7134_IRQ_REPORT_DONE_RA3) {
+-			handled = 1;
+-			saa_writel(SAA7134_IRQ_REPORT,report);
+-			saa7134_irq_oss_done(dev, status);
+-		} else {
+-			goto out;
+-		}
+-	}
+-
+-	if (loop == 10) {
+-		dprintk("error! looping IRQ!");
+-	}
+-out:
+-	return IRQ_RETVAL(handled);
+-}
+-
+-int saa7134_oss_init1(struct saa7134_dev *dev)
+-{
+-
+-	if ((request_irq(dev->pci->irq, saa7134_oss_irq,
+-			 IRQF_SHARED | IRQF_DISABLED, dev->name,
+-			(void*) &dev->dmasound)) < 0)
+-		return -1;
+-
+-	/* general */
+-	mutex_init(&dev->dmasound.lock);
+-	init_waitqueue_head(&dev->dmasound.wq);
+-
+-	switch (dev->pci->device) {
+-	case PCI_DEVICE_ID_PHILIPS_SAA7133:
+-	case PCI_DEVICE_ID_PHILIPS_SAA7135:
+-		saa_writel(0x588 >> 2, 0x00000fff);
+-		saa_writel(0x58c >> 2, 0x00543210);
+-		saa_dsp_writel(dev, 0x46c >> 2, 0xbbbbbb);
+-		break;
+-	}
+-
+-	/* dsp */
+-	dev->dmasound.rate = 32000;
+-	if (rate)
+-		dev->dmasound.rate = rate;
+-	dev->dmasound.rate = (dev->dmasound.rate > 40000) ? 48000 : 32000;
+-
+-	/* mixer */
+-	dev->dmasound.line1 = 50;
+-	dev->dmasound.line2 = 50;
+-	mixer_level(dev,LINE1,dev->dmasound.line1);
+-	mixer_level(dev,LINE2,dev->dmasound.line2);
+-	mixer_recsrc(dev, (dev->dmasound.rate == 32000) ? TV : LINE2);
+-
 -	return 0;
 -}
 -
--static int msp_detach(struct i2c_client *client)
-+static int msp_remove(struct i2c_client *client)
- {
- 	struct msp_state *state = i2c_get_clientdata(client);
+-int saa7134_oss_fini(struct saa7134_dev *dev)
+-{
+-	/* nothing */
+-	return 0;
+-}
+-
+-void saa7134_irq_oss_done(struct saa7134_dev *dev, unsigned long status)
+-{
+-	int next_blk, reg = 0;
+-
+-	spin_lock(&dev->slock);
+-	if (UNSET == dev->dmasound.dma_blk) {
+-		dprintk("irq: recording stopped\n");
+-		goto done;
+-	}
+-	if (0 != (status & 0x0f000000))
+-		dprintk("irq: lost %ld\n", (status >> 24) & 0x0f);
+-	if (0 == (status & 0x10000000)) {
+-		/* odd */
+-		if (0 == (dev->dmasound.dma_blk & 0x01))
+-			reg = SAA7134_RS_BA1(6);
+-	} else {
+-		/* even */
+-		if (1 == (dev->dmasound.dma_blk & 0x01))
+-			reg = SAA7134_RS_BA2(6);
+-	}
+-	if (0 == reg) {
+-		dprintk("irq: field oops [%s]\n",
+-			(status & 0x10000000) ? "even" : "odd");
+-		goto done;
+-	}
+-	if (dev->dmasound.read_count >= dev->dmasound.blksize * (dev->dmasound.blocks-2)) {
+-		dprintk("irq: overrun [full=%d/%d]\n",dev->dmasound.read_count,
+-			dev->dmasound.bufsize);
+-		dsp_dma_stop(dev);
+-		goto done;
+-	}
+-
+-	/* next block addr */
+-	next_blk = (dev->dmasound.dma_blk + 2) % dev->dmasound.blocks;
+-	saa_writel(reg,next_blk * dev->dmasound.blksize);
+-	if (debug > 2)
+-		dprintk("irq: ok, %s, next_blk=%d, addr=%x\n",
+-			(status & 0x10000000) ? "even" : "odd ", next_blk,
+-			next_blk * dev->dmasound.blksize);
+-
+-	/* update status & wake waiting readers */
+-	dev->dmasound.dma_blk = (dev->dmasound.dma_blk + 1) % dev->dmasound.blocks;
+-	dev->dmasound.read_count += dev->dmasound.blksize;
+-	wake_up(&dev->dmasound.wq);
+-
+- done:
+-	spin_unlock(&dev->slock);
+-}
+-
+-static int saa7134_dsp_create(struct saa7134_dev *dev)
+-{
 -	int err;
- 
- 	/* shutdown control thread */
- 	if (state->kthread) {
-@@ -980,43 +981,22 @@ static int msp_detach(struct i2c_client *client)
- 	}
- 	msp_reset(client);
- 
--	err = i2c_detach_client(client);
--	if (err) {
--		return err;
+-
+-	err = dev->dmasound.minor_dsp =
+-		register_sound_dsp(&saa7134_dsp_fops,
+-				   dsp_nr[dev->nr]);
+-	if (err < 0) {
+-		goto fail;
 -	}
+-	printk(KERN_INFO "%s: registered device dsp%d\n",
+-	       dev->name,dev->dmasound.minor_dsp >> 4);
 -
- 	kfree(state);
--	kfree(client);
- 	return 0;
- }
- 
- /* ----------------------------------------------------------------------- */
- 
--/* i2c implementation */
--static struct i2c_driver i2c_driver = {
--	.id             = I2C_DRIVERID_MSP3400,
--	.attach_adapter = msp_probe,
--	.detach_client  = msp_detach,
-+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
-+	.name = "msp3400",
-+	.driverid = I2C_DRIVERID_MSP3400,
-+	.command = msp_command,
-+	.probe = msp_probe,
-+	.remove = msp_remove,
- 	.suspend = msp_suspend,
--	.resume  = msp_resume,
--	.command        = msp_command,
--	.driver = {
--		.name    = "msp3400",
--	},
-+	.resume = msp_resume,
- };
- 
--static int __init msp3400_init_module(void)
+-	err = dev->dmasound.minor_mixer =
+-		register_sound_mixer(&saa7134_mixer_fops,
+-				     mixer_nr[dev->nr]);
+-	if (err < 0)
+-		goto fail;
+-	printk(KERN_INFO "%s: registered device mixer%d\n",
+-	       dev->name,dev->dmasound.minor_mixer >> 4);
+-
+-	return 0;
+-
+-fail:
+-	unregister_sound_dsp(dev->dmasound.minor_dsp);
+-	return 0;
+-
+-
+-}
+-
+-static int oss_device_init(struct saa7134_dev *dev)
 -{
--	return i2c_add_driver(&i2c_driver);
+-	dev->dmasound.priv_data = dev;
+-	saa7134_oss_init1(dev);
+-	saa7134_dsp_create(dev);
+-	return 1;
 -}
 -
--static void __exit msp3400_cleanup_module(void)
+-static int oss_device_exit(struct saa7134_dev *dev)
 -{
--	i2c_del_driver(&i2c_driver);
+-
+-	unregister_sound_mixer(dev->dmasound.minor_mixer);
+-	unregister_sound_dsp(dev->dmasound.minor_dsp);
+-
+-	saa7134_oss_fini(dev);
+-
+-	if (dev->pci->irq > 0) {
+-		synchronize_irq(dev->pci->irq);
+-		free_irq(dev->pci->irq,&dev->dmasound);
+-	}
+-
+-	dev->dmasound.priv_data = NULL;
+-	return 1;
 -}
 -
--module_init(msp3400_init_module);
--module_exit(msp3400_cleanup_module);
- 
- /*
-  * Overrides for Emacs so that we follow Linus's tabbing style.
-diff --git a/drivers/media/video/msp3400-kthreads.c b/drivers/media/video/msp3400-kthreads.c
-index d5ee262..61ec794 100644
---- a/drivers/media/video/msp3400-kthreads.c
-+++ b/drivers/media/video/msp3400-kthreads.c
-@@ -15,7 +15,8 @@
-  *
-  * You 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.
-+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-+ * 02110-1301, USA.
-  */
- 
- 
-@@ -78,37 +79,37 @@ static struct msp3400c_init_data_dem {
- 		{75, 19, 36, 35, 39, 40},
- 		MSP_CARRIER(5.5), MSP_CARRIER(5.5),
- 		0x00d0, 0x0500, 0x0020, 0x3000
--	},{	/* AM (for carrier detect / msp3410) */
-+	}, {	/* AM (for carrier detect / msp3410) */
- 		{-1, -1, -8, 2, 59, 126},
- 		{-1, -1, -8, 2, 59, 126},
- 		MSP_CARRIER(5.5), MSP_CARRIER(5.5),
- 		0x00d0, 0x0100, 0x0020, 0x3000
--	},{	/* FM Radio */
-+	}, {	/* FM Radio */
- 		{-8, -8, 4, 6, 78, 107},
- 		{-8, -8, 4, 6, 78, 107},
- 		MSP_CARRIER(10.7), MSP_CARRIER(10.7),
- 		0x00d0, 0x0480, 0x0020, 0x3000
--	},{	/* Terrestial FM-mono + FM-stereo */
-+	}, {	/* Terrestial FM-mono + FM-stereo */
- 		{3, 18, 27, 48, 66, 72},
- 		{3, 18, 27, 48, 66, 72},
- 		MSP_CARRIER(5.5), MSP_CARRIER(5.5),
- 		0x00d0, 0x0480, 0x0030, 0x3000
--	},{	/* Sat FM-mono */
-+	}, {	/* Sat FM-mono */
- 		{ 1, 9, 14, 24, 33, 37},
- 		{ 3, 18, 27, 48, 66, 72},
- 		MSP_CARRIER(6.5), MSP_CARRIER(6.5),
- 		0x00c6, 0x0480, 0x0000, 0x3000
--	},{	/* NICAM/FM --  B/G (5.5/5.85), D/K (6.5/5.85) */
-+	}, {	/* NICAM/FM --  B/G (5.5/5.85), D/K (6.5/5.85) */
- 		{-2, -8, -10, 10, 50, 86},
- 		{3, 18, 27, 48, 66, 72},
- 		MSP_CARRIER(5.5), MSP_CARRIER(5.5),
- 		0x00d0, 0x0040, 0x0120, 0x3000
--	},{	/* NICAM/FM -- I (6.0/6.552) */
-+	}, {	/* NICAM/FM -- I (6.0/6.552) */
- 		{2, 4, -6, -4, 40, 94},
- 		{3, 18, 27, 48, 66, 72},
- 		MSP_CARRIER(6.0), MSP_CARRIER(6.0),
- 		0x00d0, 0x0040, 0x0120, 0x3000
--	},{	/* NICAM/AM -- L (6.5/5.85) */
-+	}, {	/* NICAM/AM -- L (6.5/5.85) */
- 		{-2, -8, -10, 10, 50, 86},
- 		{-4, -12, -9, 23, 79, 126},
- 		MSP_CARRIER(6.5), MSP_CARRIER(6.5),
-@@ -224,7 +225,9 @@ void msp3400c_set_mode(struct i2c_client *client, int mode)
-    nor do they support stereo BTSC. */
- static void msp3400c_set_audmode(struct i2c_client *client)
- {
--	static char *strmode[] = { "mono", "stereo", "lang2", "lang1", "lang1+lang2" };
-+	static char *strmode[] = {
-+		"mono", "stereo", "lang2", "lang1", "lang1+lang2"
-+	};
- 	struct msp_state *state = i2c_get_clientdata(client);
- 	char *modestr = (state->audmode >= 0 && state->audmode < 5) ?
- 		strmode[state->audmode] : "unknown";
-@@ -298,19 +301,23 @@ static void msp3400c_set_audmode(struct i2c_client *client)
- 	case MSP_MODE_FM_NICAM1:
- 	case MSP_MODE_FM_NICAM2:
- 	case MSP_MODE_AM_NICAM:
--		v4l_dbg(1, msp_debug, client, "NICAM set_audmode: %s\n",modestr);
-+		v4l_dbg(1, msp_debug, client,
-+			"NICAM set_audmode: %s\n", modestr);
- 		if (state->nicam_on)
- 			src = 0x0100;  /* NICAM */
- 		break;
- 	case MSP_MODE_BTSC:
--		v4l_dbg(1, msp_debug, client, "BTSC set_audmode: %s\n",modestr);
-+		v4l_dbg(1, msp_debug, client,
-+			"BTSC set_audmode: %s\n", modestr);
- 		break;
- 	case MSP_MODE_EXTERN:
--		v4l_dbg(1, msp_debug, client, "extern set_audmode: %s\n",modestr);
-+		v4l_dbg(1, msp_debug, client,
-+			"extern set_audmode: %s\n", modestr);
- 		src = 0x0200;  /* SCART */
- 		break;
- 	case MSP_MODE_FM_RADIO:
--		v4l_dbg(1, msp_debug, client, "FM-Radio set_audmode: %s\n",modestr);
-+		v4l_dbg(1, msp_debug, client,
-+			"FM-Radio set_audmode: %s\n", modestr);
- 		break;
- 	default:
- 		v4l_dbg(1, msp_debug, client, "mono set_audmode\n");
-@@ -342,7 +349,8 @@ static void msp3400c_set_audmode(struct i2c_client *client)
- 		src |= 0x0010;
- 		break;
- 	}
--	v4l_dbg(1, msp_debug, client, "set_audmode final source/matrix = 0x%x\n", src);
-+	v4l_dbg(1, msp_debug, client,
-+		"set_audmode final source/matrix = 0x%x\n", src);
- 
- 	msp_set_source(client, src);
- }
-@@ -351,22 +359,26 @@ static void msp3400c_print_mode(struct i2c_client *client)
- {
- 	struct msp_state *state = i2c_get_clientdata(client);
- 
--	if (state->main == state->second) {
--		v4l_dbg(1, msp_debug, client, "mono sound carrier: %d.%03d MHz\n",
--		       state->main / 910000, (state->main / 910) % 1000);
+-static int saa7134_oss_init(void)
+-{
+-	struct saa7134_dev *dev = NULL;
+-	struct list_head *list;
+-
+-	if (!saa7134_dmasound_init && !saa7134_dmasound_exit) {
+-		saa7134_dmasound_init = oss_device_init;
+-		saa7134_dmasound_exit = oss_device_exit;
 -	} else {
--		v4l_dbg(1, msp_debug, client, "main sound carrier: %d.%03d MHz\n",
--		       state->main / 910000, (state->main / 910) % 1000);
+-		printk(KERN_WARNING "saa7134 OSS: can't load, DMA sound handler already assigned (probably to ALSA)\n");
+-		return -EBUSY;
 -	}
-+	if (state->main == state->second)
-+		v4l_dbg(1, msp_debug, client,
-+			"mono sound carrier: %d.%03d MHz\n",
-+			state->main / 910000, (state->main / 910) % 1000);
-+	else
-+		v4l_dbg(1, msp_debug, client,
-+			"main sound carrier: %d.%03d MHz\n",
-+			state->main / 910000, (state->main / 910) % 1000);
- 	if (state->mode == MSP_MODE_FM_NICAM1 || state->mode == MSP_MODE_FM_NICAM2)
--		v4l_dbg(1, msp_debug, client, "NICAM/FM carrier  : %d.%03d MHz\n",
--		       state->second / 910000, (state->second/910) % 1000);
-+		v4l_dbg(1, msp_debug, client,
-+			"NICAM/FM carrier  : %d.%03d MHz\n",
-+			state->second / 910000, (state->second/910) % 1000);
- 	if (state->mode == MSP_MODE_AM_NICAM)
--		v4l_dbg(1, msp_debug, client, "NICAM/AM carrier  : %d.%03d MHz\n",
--		       state->second / 910000, (state->second / 910) % 1000);
-+		v4l_dbg(1, msp_debug, client,
-+			"NICAM/AM carrier  : %d.%03d MHz\n",
-+			state->second / 910000, (state->second / 910) % 1000);
- 	if (state->mode == MSP_MODE_FM_TERRA && state->main != state->second) {
--		v4l_dbg(1, msp_debug, client, "FM-stereo carrier : %d.%03d MHz\n",
--		       state->second / 910000, (state->second / 910) % 1000);
-+		v4l_dbg(1, msp_debug, client,
-+			"FM-stereo carrier : %d.%03d MHz\n",
-+			state->second / 910000, (state->second / 910) % 1000);
- 	}
- }
- 
-@@ -385,7 +397,8 @@ static int msp3400c_detect_stereo(struct i2c_client *client)
- 		val = msp_read_dsp(client, 0x18);
- 		if (val > 32767)
- 			val -= 65536;
--		v4l_dbg(2, msp_debug, client, "stereo detect register: %d\n", val);
-+		v4l_dbg(2, msp_debug, client,
-+			"stereo detect register: %d\n", val);
- 		if (val > 8192) {
- 			rxsubchans = V4L2_TUNER_SUB_STEREO;
- 		} else if (val < -4096) {
-@@ -430,7 +443,8 @@ static int msp3400c_detect_stereo(struct i2c_client *client)
- 	}
- 	if (rxsubchans != state->rxsubchans) {
- 		update = 1;
--		v4l_dbg(1, msp_debug, client, "watch: rxsubchans %02x => %02x\n",
-+		v4l_dbg(1, msp_debug, client,
-+			"watch: rxsubchans %02x => %02x\n",
- 			state->rxsubchans, rxsubchans);
- 		state->rxsubchans = rxsubchans;
- 	}
-@@ -452,9 +466,8 @@ static void watch_stereo(struct i2c_client *client)
+-
+-	printk(KERN_INFO "saa7134 OSS driver for DMA sound loaded\n");
+-
+-
+-	list_for_each(list,&saa7134_devlist) {
+-		dev = list_entry(list, struct saa7134_dev, devlist);
+-		if (dev->dmasound.priv_data == NULL) {
+-			oss_device_init(dev);
+-		} else {
+-			printk(KERN_ERR "saa7134 OSS: DMA sound is being handled by ALSA, ignoring %s\n",dev->name);
+-			return -EBUSY;
+-		}
+-	}
+-
+-	if (dev == NULL)
+-		printk(KERN_INFO "saa7134 OSS: no saa7134 cards found\n");
+-
+-	return 0;
+-
+-}
+-
+-static void saa7134_oss_exit(void)
+-{
+-	struct saa7134_dev *dev;
+-
+-	list_for_each_entry(dev, &saa7134_devlist, devlist) {
+-		/* Device isn't registered by OSS, probably ALSA's */
+-		if (!dev->dmasound.minor_dsp)
+-			continue;
+-
+-		oss_device_exit(dev);
+-	}
+-
+-	saa7134_dmasound_init = NULL;
+-	saa7134_dmasound_exit = NULL;
+-
+-	printk(KERN_INFO "saa7134 OSS driver for DMA sound unloaded\n");
+-
+-	return;
+-}
+-
+-/* We initialize this late, to make sure the sound system is up and running */
+-late_initcall(saa7134_oss_init);
+-module_exit(saa7134_oss_exit);
+-MODULE_LICENSE("GPL");
+-MODULE_AUTHOR("Gerd Knorr <kraxel at bytesex.org> [SuSE Labs]");
+-
+-/* ----------------------------------------------------------- */
+-/*
+- * Local variables:
+- * c-basic-offset: 8
+- * End:
+- */
+diff --git a/drivers/media/video/saa7134/saa7134-ts.c b/drivers/media/video/saa7134/saa7134-ts.c
+index 4b63ad3..f1b8fca 100644
+--- a/drivers/media/video/saa7134/saa7134-ts.c
++++ b/drivers/media/video/saa7134/saa7134-ts.c
+@@ -47,7 +47,7 @@ static int buffer_activate(struct saa7134_dev *dev,
  {
- 	struct msp_state *state = i2c_get_clientdata(client);
- 
--	if (msp_detect_stereo(client)) {
-+	if (msp_detect_stereo(client))
- 		msp_set_audmode(client);
--	}
- 
- 	if (msp_once)
- 		state->watch_stereo = 0;
-@@ -465,7 +478,7 @@ int msp3400c_thread(void *data)
- 	struct i2c_client *client = data;
- 	struct msp_state *state = i2c_get_clientdata(client);
- 	struct msp3400c_carrier_detect *cd;
--	int count, max1, max2, val1, val2, val, this;
-+	int count, max1, max2, val1, val2, val, i;
- 
- 
- 	v4l_dbg(1, msp_debug, client, "msp3400 daemon started\n");
-@@ -475,7 +488,7 @@ int msp3400c_thread(void *data)
- 		msp_sleep(state, -1);
- 		v4l_dbg(2, msp_debug, client, "msp3400 thread: wakeup\n");
- 
--	restart:
-+restart:
- 		v4l_dbg(2, msp_debug, client, "thread: restart scan\n");
- 		state->restart = 0;
- 		if (kthread_should_stop())
-@@ -483,7 +496,8 @@ int msp3400c_thread(void *data)
- 
- 		if (state->radio || MSP_MODE_EXTERN == state->mode) {
- 			/* no carrier scan, just unmute */
--			v4l_dbg(1, msp_debug, client, "thread: no carrier scan\n");
-+			v4l_dbg(1, msp_debug, client,
-+				"thread: no carrier scan\n");
- 			state->scan_in_progress = 0;
- 			msp_set_audio(client);
- 			continue;
-@@ -514,16 +528,17 @@ int msp3400c_thread(void *data)
- 			v4l_dbg(1, msp_debug, client, "AM sound override\n");
- 		}
- 
--		for (this = 0; this < count; this++) {
--			msp3400c_set_carrier(client, cd[this].cdo, cd[this].cdo);
--			if (msp_sleep(state,100))
-+		for (i = 0; i < count; i++) {
-+			msp3400c_set_carrier(client, cd[i].cdo, cd[i].cdo);
-+			if (msp_sleep(state, 100))
- 				goto restart;
- 			val = msp_read_dsp(client, 0x1b);
- 			if (val > 32767)
- 				val -= 65536;
- 			if (val1 < val)
--				val1 = val, max1 = this;
--			v4l_dbg(1, msp_debug, client, "carrier1 val: %5d / %s\n", val,cd[this].name);
-+				val1 = val, max1 = i;
-+			v4l_dbg(1, msp_debug, client,
-+				"carrier1 val: %5d / %s\n", val, cd[i].name);
- 		}
  
- 		/* carrier detect pass #2 -- second (stereo) carrier */
-@@ -550,16 +565,17 @@ int msp3400c_thread(void *data)
- 			count = 0;
- 			max2 = 0;
- 		}
--		for (this = 0; this < count; this++) {
--			msp3400c_set_carrier(client, cd[this].cdo, cd[this].cdo);
--			if (msp_sleep(state,100))
-+		for (i = 0; i < count; i++) {
-+			msp3400c_set_carrier(client, cd[i].cdo, cd[i].cdo);
-+			if (msp_sleep(state, 100))
- 				goto restart;
- 			val = msp_read_dsp(client, 0x1b);
- 			if (val > 32767)
- 				val -= 65536;
- 			if (val2 < val)
--				val2 = val, max2 = this;
--			v4l_dbg(1, msp_debug, client, "carrier2 val: %5d / %s\n", val,cd[this].name);
-+				val2 = val, max2 = i;
-+			v4l_dbg(1, msp_debug, client,
-+				"carrier2 val: %5d / %s\n", val, cd[i].name);
- 		}
+ 	dprintk("buffer_activate [%p]",buf);
+-	buf->vb.state = STATE_ACTIVE;
++	buf->vb.state = VIDEOBUF_ACTIVE;
+ 	buf->top_seen = 0;
  
- 		/* program the msp3400 according to the results */
-@@ -611,7 +627,7 @@ int msp3400c_thread(void *data)
- 			break;
- 		case 0: /* 4.5 */
- 		default:
--		no_second:
-+no_second:
- 			state->second = msp3400c_carrier_detect_main[max1].cdo;
- 			msp3400c_set_mode(client, MSP_MODE_FM_TERRA);
- 			break;
-@@ -632,7 +648,8 @@ int msp3400c_thread(void *data)
- 		while (state->watch_stereo) {
- 			if (msp_sleep(state, count ? 1000 : 5000))
- 				goto restart;
--			if (count) count--;
-+			if (count)
-+				count--;
- 			watch_stereo(client);
- 		}
+ 	if (NULL == next)
+@@ -91,7 +91,7 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
+ 		saa7134_dma_free(q,buf);
  	}
-@@ -651,10 +668,10 @@ int msp3410d_thread(void *data)
- 	set_freezable();
- 	for (;;) {
- 		v4l_dbg(2, msp_debug, client, "msp3410 thread: sleep\n");
--		msp_sleep(state,-1);
-+		msp_sleep(state, -1);
- 		v4l_dbg(2, msp_debug, client, "msp3410 thread: wakeup\n");
- 
--	restart:
-+restart:
- 		v4l_dbg(2, msp_debug, client, "thread: restart scan\n");
- 		state->restart = 0;
- 		if (kthread_should_stop())
-@@ -662,7 +679,8 @@ int msp3410d_thread(void *data)
- 
- 		if (state->mode == MSP_MODE_EXTERN) {
- 			/* no carrier scan needed, just unmute */
--			v4l_dbg(1, msp_debug, client, "thread: no carrier scan\n");
-+			v4l_dbg(1, msp_debug, client,
-+				"thread: no carrier scan\n");
- 			state->scan_in_progress = 0;
- 			msp_set_audio(client);
- 			continue;
-@@ -673,7 +691,8 @@ int msp3410d_thread(void *data)
- 		msp_set_audio(client);
- 
- 		/* start autodetect. Note: autodetect is not supported for
--		   NTSC-M and radio, hence we force the standard in those cases. */
-+		   NTSC-M and radio, hence we force the standard in those
-+		   cases. */
- 		if (state->radio)
- 			std = 0x40;
- 		else
-@@ -686,8 +705,9 @@ int msp3410d_thread(void *data)
- 			goto restart;
  
- 		if (msp_debug)
--			v4l_dbg(2, msp_debug, client, "setting standard: %s (0x%04x)\n",
--			       msp_standard_std_name(std), std);
-+			v4l_dbg(2, msp_debug, client,
-+				"setting standard: %s (0x%04x)\n",
-+				msp_standard_std_name(std), std);
+-	if (STATE_NEEDS_INIT == buf->vb.state) {
++	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
+ 		struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
  
- 		if (std != 1) {
- 			/* programmed some specific mode */
-@@ -703,7 +723,8 @@ int msp3410d_thread(void *data)
- 				val = msp_read_dem(client, 0x7e);
- 				if (val < 0x07ff)
- 					break;
--				v4l_dbg(2, msp_debug, client, "detection still in progress\n");
-+				v4l_dbg(2, msp_debug, client,
-+					"detection still in progress\n");
- 			}
- 		}
- 		for (i = 0; msp_stdlist[i].name != NULL; i++)
-@@ -716,12 +737,13 @@ int msp3410d_thread(void *data)
- 		state->std = val;
- 		state->rxsubchans = V4L2_TUNER_SUB_MONO;
+ 		buf->vb.width  = llength;
+@@ -121,7 +121,7 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
+ 	saa_writel(SAA7134_RS_PITCH(5),TS_PACKET_SIZE);
+ 	saa_writel(SAA7134_RS_CONTROL(5),control);
  
--		if (msp_amsound && !state->radio && (state->v4l2_std & V4L2_STD_SECAM) &&
--				(val != 0x0009)) {
-+		if (msp_amsound && !state->radio &&
-+		    (state->v4l2_std & V4L2_STD_SECAM) && (val != 0x0009)) {
- 			/* autodetection has failed, let backup */
- 			v4l_dbg(1, msp_debug, client, "autodetection failed,"
- 				" switching to backup standard: %s (0x%04x)\n",
--				msp_stdlist[8].name ? msp_stdlist[8].name : "unknown",val);
-+				msp_stdlist[8].name ?
-+					msp_stdlist[8].name : "unknown", val);
- 			state->std = val = 0x0009;
- 			msp_write_dem(client, 0x20, val);
- 		}
-@@ -786,7 +808,8 @@ int msp3410d_thread(void *data)
- 		while (state->watch_stereo) {
- 			if (msp_sleep(state, count ? 1000 : 5000))
- 				goto restart;
--			if (count) count--;
-+			if (count)
-+				count--;
- 			watch_stereo(client);
+-	buf->vb.state = STATE_PREPARED;
++	buf->vb.state = VIDEOBUF_PREPARED;
+ 	buf->activate = buffer_activate;
+ 	buf->vb.field = field;
+ 	return 0;
+@@ -242,7 +242,7 @@ void saa7134_irq_ts_done(struct saa7134_dev *dev, unsigned long status)
+ 			if ((status & 0x100000) != 0x100000)
+ 				goto done;
  		}
+-		saa7134_buffer_finish(dev,&dev->ts_q,STATE_DONE);
++		saa7134_buffer_finish(dev,&dev->ts_q,VIDEOBUF_DONE);
  	}
-@@ -872,8 +895,8 @@ static void msp34xxg_set_source(struct i2c_client *client, u16 reg, int in)
- 	else
- 		source = (in << 8) | matrix;
+ 	saa7134_buffer_next(dev,&dev->ts_q);
  
--	v4l_dbg(1, msp_debug, client, "set source to %d (0x%x) for output %02x\n",
--			in, source, reg);
-+	v4l_dbg(1, msp_debug, client,
-+		"set source to %d (0x%x) for output %02x\n", in, source, reg);
- 	msp_write_dsp(client, reg, source);
- }
+diff --git a/drivers/media/video/saa7134/saa7134-tvaudio.c b/drivers/media/video/saa7134/saa7134-tvaudio.c
+index f8e304c..4e98104 100644
+--- a/drivers/media/video/saa7134/saa7134-tvaudio.c
++++ b/drivers/media/video/saa7134/saa7134-tvaudio.c
+@@ -163,32 +163,6 @@ static struct saa7134_tvaudio tvaudio[] = {
  
-@@ -948,7 +971,7 @@ int msp34xxg_thread(void *data)
- 		msp_sleep(state, -1);
- 		v4l_dbg(2, msp_debug, client, "msp34xxg thread: wakeup\n");
+ /* ------------------------------------------------------------------ */
  
--	restart:
-+restart:
- 		v4l_dbg(1, msp_debug, client, "thread: restart scan\n");
- 		state->restart = 0;
- 		if (kthread_should_stop())
-@@ -956,7 +979,8 @@ int msp34xxg_thread(void *data)
+-static void tvaudio_init(struct saa7134_dev *dev)
+-{
+-	int clock = saa7134_boards[dev->board].audio_clock;
+-
+-	if (UNSET != audio_clock_override)
+-		clock = audio_clock_override;
+-
+-	/* init all audio registers */
+-	saa_writeb(SAA7134_AUDIO_PLL_CTRL,   0x00);
+-	if (need_resched())
+-		schedule();
+-	else
+-		udelay(10);
+-
+-	saa_writeb(SAA7134_AUDIO_CLOCK0,      clock        & 0xff);
+-	saa_writeb(SAA7134_AUDIO_CLOCK1,     (clock >>  8) & 0xff);
+-	saa_writeb(SAA7134_AUDIO_CLOCK2,     (clock >> 16) & 0xff);
+-	/* frame locked audio is mandatory for NICAM */
+-	saa_writeb(SAA7134_AUDIO_PLL_CTRL,   0x01);
+-
+-	saa_writeb(SAA7134_NICAM_ERROR_LOW,  0x14);
+-	saa_writeb(SAA7134_NICAM_ERROR_HIGH, 0x50);
+-	saa_writeb(SAA7134_MONITOR_SELECT,   0xa0);
+-	saa_writeb(SAA7134_FM_DEMATRIX,      0x80);
+-}
+-
+ static u32 tvaudio_carr2reg(u32 carrier)
+ {
+ 	u64 a = carrier;
+@@ -517,9 +491,13 @@ static int tvaudio_thread(void *data)
+ 		dev->thread.scan1 = dev->thread.scan2;
+ 		dprintk("tvaudio thread scan start [%d]\n",dev->thread.scan1);
+ 		dev->tvaudio  = NULL;
+-		tvaudio_init(dev);
++
++		saa_writeb(SAA7134_MONITOR_SELECT,   0xa0);
++		saa_writeb(SAA7134_FM_DEMATRIX,      0x80);
++
+ 		if (dev->ctl_automute)
+ 			dev->automute = 1;
++
+ 		mute_input_7134(dev);
  
- 		if (state->mode == MSP_MODE_EXTERN) {
- 			/* no carrier scan needed, just unmute */
--			v4l_dbg(1, msp_debug, client, "thread: no carrier scan\n");
-+			v4l_dbg(1, msp_debug, client,
-+				"thread: no carrier scan\n");
- 			state->scan_in_progress = 0;
- 			msp_set_audio(client);
- 			continue;
-@@ -972,7 +996,8 @@ int msp34xxg_thread(void *data)
- 			goto unmute;
+ 		/* give the tuner some time */
+@@ -784,27 +762,15 @@ static int mute_input_7133(struct saa7134_dev *dev)
+ static int tvaudio_thread_ddep(void *data)
+ {
+ 	struct saa7134_dev *dev = data;
+-	u32 value, norms, clock;
++	u32 value, norms;
  
- 		/* watch autodetect */
--		v4l_dbg(1, msp_debug, client, "started autodetect, waiting for result\n");
-+		v4l_dbg(1, msp_debug, client,
-+			"started autodetect, waiting for result\n");
- 		for (i = 0; i < 10; i++) {
- 			if (msp_sleep(state, 100))
- 				goto restart;
-@@ -983,15 +1008,18 @@ int msp34xxg_thread(void *data)
- 				state->std = val;
- 				break;
- 			}
--			v4l_dbg(2, msp_debug, client, "detection still in progress\n");
-+			v4l_dbg(2, msp_debug, client,
-+				"detection still in progress\n");
- 		}
- 		if (state->std == 1) {
--			v4l_dbg(1, msp_debug, client, "detection still in progress after 10 tries. giving up.\n");
-+			v4l_dbg(1, msp_debug, client,
-+				"detection still in progress after 10 tries. giving up.\n");
- 			continue;
- 		}
  
--	unmute:
--		v4l_dbg(1, msp_debug, client, "detected standard: %s (0x%04x)\n",
-+unmute:
-+		v4l_dbg(1, msp_debug, client,
-+			"detected standard: %s (0x%04x)\n",
- 			msp_standard_std_name(state->std), state->std);
+ 	set_freezable();
+-
+-	clock = saa7134_boards[dev->board].audio_clock;
+-	if (UNSET != audio_clock_override)
+-		clock = audio_clock_override;
+-	saa_writel(0x598 >> 2, clock);
+-
+-	/* unmute */
+-	saa_dsp_writel(dev, 0x474 >> 2, 0x00);
+-	saa_dsp_writel(dev, 0x450 >> 2, 0x00);
+-
+ 	for (;;) {
+ 		tvaudio_sleep(dev,-1);
+ 		if (kthread_should_stop())
+ 			goto done;
+-
+ 	restart:
+-
+ 		try_to_freeze();
  
- 		if (state->std == 9) {
-@@ -1046,9 +1074,11 @@ static int msp34xxg_detect_stereo(struct i2c_client *client)
- 		if (state->std == 0x20)
- 			state->rxsubchans |= V4L2_TUNER_SUB_SAP;
- 		else
--			state->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
-+			state->rxsubchans =
-+				V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
- 	}
--	v4l_dbg(1, msp_debug, client, "status=0x%x, stereo=%d, bilingual=%d -> rxsubchans=%d\n",
-+	v4l_dbg(1, msp_debug, client,
-+		"status=0x%x, stereo=%d, bilingual=%d -> rxsubchans=%d\n",
- 		status, is_stereo, is_bilingual, state->rxsubchans);
- 	return (oldrx != state->rxsubchans);
+ 		dev->thread.scan1 = dev->thread.scan2;
+@@ -978,6 +944,38 @@ int saa7134_tvaudio_getstereo(struct saa7134_dev *dev)
+ 	return retval;
  }
-diff --git a/drivers/media/video/mt20xx.c b/drivers/media/video/mt20xx.c
-index f49d1f4..b630c26 100644
---- a/drivers/media/video/mt20xx.c
-+++ b/drivers/media/video/mt20xx.c
-@@ -14,7 +14,7 @@ static int debug = 0;
- module_param(debug, int, 0644);
- MODULE_PARM_DESC(debug, "enable verbose debug messages");
- 
--#define PREFIX "mt20xx "
-+#define PREFIX "mt20xx"
- 
- /* ---------------------------------------------------------------------- */
- 
-diff --git a/drivers/media/video/mxb.c b/drivers/media/video/mxb.c
-index 98ad309..add6d0d 100644
---- a/drivers/media/video/mxb.c
-+++ b/drivers/media/video/mxb.c
-@@ -149,10 +149,33 @@ struct mxb
  
- static struct saa7146_extension extension;
- 
-+static int mxb_check_clients(struct device *dev, void *data)
++void saa7134_tvaudio_init(struct saa7134_dev *dev)
 +{
-+	struct mxb* mxb = data;
-+	struct i2c_client *client = i2c_verify_client(dev);
++	int clock = saa7134_boards[dev->board].audio_clock;
 +
-+	if( !client )
-+		return 0;
++	if (UNSET != audio_clock_override)
++		clock = audio_clock_override;
 +
-+	if( I2C_ADDR_TEA6420_1 == client->addr )
-+		mxb->tea6420_1 = client;
-+	if( I2C_ADDR_TEA6420_2 == client->addr )
-+		mxb->tea6420_2 = client;
-+	if( I2C_TEA6415C_2 == client->addr )
-+		mxb->tea6415c = client;
-+	if( I2C_ADDR_TDA9840 == client->addr )
-+		mxb->tda9840 = client;
-+	if( I2C_SAA7111 == client->addr )
-+		mxb->saa7111a = client;
-+	if( 0x60 == client->addr )
-+		mxb->tuner = client;
++	switch (dev->pci->device) {
++	case PCI_DEVICE_ID_PHILIPS_SAA7134:
++		/* init all audio registers */
++		saa_writeb(SAA7134_AUDIO_PLL_CTRL,   0x00);
++		if (need_resched())
++			schedule();
++		else
++			udelay(10);
 +
-+	return 0;
++		saa_writeb(SAA7134_AUDIO_CLOCK0,      clock        & 0xff);
++		saa_writeb(SAA7134_AUDIO_CLOCK1,     (clock >>  8) & 0xff);
++		saa_writeb(SAA7134_AUDIO_CLOCK2,     (clock >> 16) & 0xff);
++		/* frame locked audio is mandatory for NICAM */
++		saa_writeb(SAA7134_AUDIO_PLL_CTRL,   0x01);
++		saa_writeb(SAA7134_NICAM_ERROR_LOW,  0x14);
++		saa_writeb(SAA7134_NICAM_ERROR_HIGH, 0x50);
++		break;
++	case PCI_DEVICE_ID_PHILIPS_SAA7133:
++	case PCI_DEVICE_ID_PHILIPS_SAA7135:
++		saa_writel(0x598 >> 2, clock);
++		saa_dsp_writel(dev, 0x474 >> 2, 0x00);
++		saa_dsp_writel(dev, 0x450 >> 2, 0x00);
++	}
 +}
 +
- static int mxb_probe(struct saa7146_dev* dev)
+ int saa7134_tvaudio_init2(struct saa7134_dev *dev)
  {
- 	struct mxb* mxb = NULL;
--	struct i2c_client *client;
- 	int result;
+ 	int (*my_thread)(void *data) = NULL;
+@@ -994,6 +992,7 @@ int saa7134_tvaudio_init2(struct saa7134_dev *dev)
  
- 	if ((result = request_module("saa7111")) < 0) {
-@@ -195,20 +218,7 @@ static int mxb_probe(struct saa7146_dev* dev)
- 	}
+ 	dev->thread.thread = NULL;
+ 	if (my_thread) {
++		saa7134_tvaudio_init(dev);
+ 		/* start tvaudio thread */
+ 		dev->thread.thread = kthread_run(my_thread, dev, "%s", dev->name);
+ 		if (IS_ERR(dev->thread.thread)) {
+diff --git a/drivers/media/video/saa7134/saa7134-vbi.c b/drivers/media/video/saa7134/saa7134-vbi.c
+index 81a2aed..f0d5ed9 100644
+--- a/drivers/media/video/saa7134/saa7134-vbi.c
++++ b/drivers/media/video/saa7134/saa7134-vbi.c
+@@ -85,7 +85,7 @@ static int buffer_activate(struct saa7134_dev *dev,
+ 	unsigned long control,base;
  
- 	/* loop through all i2c-devices on the bus and look who is there */
--	list_for_each_entry(client, &mxb->i2c_adapter.clients, list) {
--		if( I2C_ADDR_TEA6420_1 == client->addr )
--			mxb->tea6420_1 = client;
--		if( I2C_ADDR_TEA6420_2 == client->addr )
--			mxb->tea6420_2 = client;
--		if( I2C_TEA6415C_2 == client->addr )
--			mxb->tea6415c = client;
--		if( I2C_ADDR_TDA9840 == client->addr )
--			mxb->tda9840 = client;
--		if( I2C_SAA7111 == client->addr )
--			mxb->saa7111a = client;
--		if( 0x60 == client->addr )
--			mxb->tuner = client;
--	}
-+	device_for_each_child(&mxb->i2c_adapter.dev, mxb, mxb_check_clients);
+ 	dprintk("buffer_activate [%p]\n",buf);
+-	buf->vb.state = STATE_ACTIVE;
++	buf->vb.state = VIDEOBUF_ACTIVE;
+ 	buf->top_seen = 0;
  
- 	/* check if all devices are present */
- 	if(    0 == mxb->tea6420_1	|| 0 == mxb->tea6420_2	|| 0 == mxb->tea6415c
-diff --git a/drivers/media/video/pvrusb2/Kconfig b/drivers/media/video/pvrusb2/Kconfig
-index d0c2cd7..6fc1b8b 100644
---- a/drivers/media/video/pvrusb2/Kconfig
-+++ b/drivers/media/video/pvrusb2/Kconfig
-@@ -5,6 +5,10 @@ config VIDEO_PVRUSB2
- 	select VIDEO_TUNER
- 	select VIDEO_TVEEPROM
- 	select VIDEO_CX2341X
-+	select VIDEO_SAA711X
-+	select VIDEO_CX25840
-+	select VIDEO_MSP3400
-+	select VIDEO_WM8775
- 	---help---
- 	  This is a video4linux driver for Conexant 23416 based
- 	  usb2 personal video recorder devices.
-@@ -12,32 +16,29 @@ config VIDEO_PVRUSB2
- 	  To compile this driver as a module, choose M here: the
- 	  module will be called pvrusb2
+ 	task_init(dev,buf,TASK_A);
+@@ -136,7 +136,7 @@ static int buffer_prepare(struct videobuf_queue *q,
+ 	if (buf->vb.size != size)
+ 		saa7134_dma_free(q,buf);
  
--config VIDEO_PVRUSB2_29XXX
--	bool "Hauppauge WinTV-PVR USB2 support for 29xxx model series"
-+config VIDEO_PVRUSB2_ONAIR_CREATOR
-+	bool "pvrusb2 driver support for OnAir Creator model"
- 	depends on VIDEO_PVRUSB2 && EXPERIMENTAL
- 	select VIDEO_SAA711X
--	select VIDEO_MSP3400
-+	select VIDEO_CS53L32A
- 	---help---
--	  This option enables support for WinTV-PVR USB2 devices whose
--	  model number is of the form "29xxx" (leading prefix of "29"
--	  followed by 3 digits).
--	  To see if you may need this option, examine the white
--	  sticker on the underside of your device.
-+
-+	  This option enables support for the OnAir Creator USB tuner
-+	  device.  This is a hybrid device, however currently only
-+	  analog mode is supported.
+-	if (STATE_NEEDS_INIT == buf->vb.state) {
++	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
+ 		struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
  
- 	  If you are in doubt, say Y.
+ 		buf->vb.width  = llength;
+@@ -154,7 +154,7 @@ static int buffer_prepare(struct videobuf_queue *q,
+ 		if (err)
+ 			goto oops;
+ 	}
+-	buf->vb.state = STATE_PREPARED;
++	buf->vb.state = VIDEOBUF_PREPARED;
+ 	buf->activate = buffer_activate;
+ 	buf->vb.field = field;
+ 	return 0;
+@@ -240,7 +240,7 @@ void saa7134_irq_vbi_done(struct saa7134_dev *dev, unsigned long status)
+ 			goto done;
  
--config VIDEO_PVRUSB2_24XXX
--	bool "Hauppauge WinTV-PVR USB2 support for 24xxx model series"
-+config VIDEO_PVRUSB2_ONAIR_USB2
-+	bool "pvrusb2 driver support for OnAir USB2 model"
- 	depends on VIDEO_PVRUSB2 && EXPERIMENTAL
--	select VIDEO_CX25840
--	select VIDEO_WM8775
-+	select VIDEO_SAA711X
-+	select VIDEO_CS53L32A
- 	---help---
--	  This option enables inclusion of additional logic to operate
--	  newer WinTV-PVR USB2 devices whose model number is of the
--	  form "24xxx" (leading prefix of "24" followed by 3 digits).
--	  To see if you may need this option, examine the white
--	  sticker on the underside of your device.  Enabling this
--	  option will not harm support for older devices.
-+
-+	  This option enables support for the OnAir USB2 tuner device
-+	  (also known as the Sasem tuner).  This is a hybrid device,
-+	  however currently only analog mode is supported.
+ 		dev->vbi_q.curr->vb.field_count = dev->vbi_fieldcount;
+-		saa7134_buffer_finish(dev,&dev->vbi_q,STATE_DONE);
++		saa7134_buffer_finish(dev,&dev->vbi_q,VIDEOBUF_DONE);
+ 	}
+ 	saa7134_buffer_next(dev,&dev->vbi_q);
  
- 	  If you are in doubt, say Y.
+diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c
+index 6396d9b..1184d35 100644
+--- a/drivers/media/video/saa7134/saa7134-video.c
++++ b/drivers/media/video/saa7134/saa7134-video.c
+@@ -38,7 +38,7 @@
  
-diff --git a/drivers/media/video/pvrusb2/Makefile b/drivers/media/video/pvrusb2/Makefile
-index 69b3e43..47284e5 100644
---- a/drivers/media/video/pvrusb2/Makefile
-+++ b/drivers/media/video/pvrusb2/Makefile
-@@ -6,7 +6,7 @@ pvrusb2-objs	:= pvrusb2-i2c-core.o pvrusb2-i2c-cmd-v4l2.o \
- 		   pvrusb2-encoder.o pvrusb2-video-v4l.o \
- 		   pvrusb2-eeprom.o pvrusb2-tuner.o \
- 		   pvrusb2-main.o pvrusb2-hdw.o pvrusb2-v4l2.o \
--		   pvrusb2-ctrl.o pvrusb2-std.o \
-+		   pvrusb2-ctrl.o pvrusb2-std.o pvrusb2-devattr.o \
- 		   pvrusb2-context.o pvrusb2-io.o pvrusb2-ioread.o \
- 		   pvrusb2-cx2584x-v4l.o pvrusb2-wm8775.o \
- 		   $(obj-pvrusb2-sysfs-y) $(obj-pvrusb2-debugifc-y)
-diff --git a/drivers/media/video/pvrusb2/pvrusb2-audio.c b/drivers/media/video/pvrusb2/pvrusb2-audio.c
-index 379645e..9a7c8e9 100644
---- a/drivers/media/video/pvrusb2/pvrusb2-audio.c
-+++ b/drivers/media/video/pvrusb2/pvrusb2-audio.c
-@@ -35,34 +35,58 @@ struct pvr2_msp3400_handler {
- };
+ /* ------------------------------------------------------------------ */
  
+-static unsigned int video_debug   = 0;
++unsigned int video_debug;
+ static unsigned int gbuffers      = 8;
+ static unsigned int noninterlaced = 0;
+ static unsigned int gbufsize      = 720*576*4;
+@@ -54,7 +54,7 @@ module_param_string(secam, secam, sizeof(secam), 0644);
+ MODULE_PARM_DESC(secam, "force SECAM variant, either DK,L or Lc");
  
-+
-+struct routing_scheme {
-+	const int *def;
-+	unsigned int cnt;
-+};
-+
-+static const int routing_scheme0[] = {
-+	[PVR2_CVAL_INPUT_TV]        = MSP_INPUT_DEFAULT,
-+	[PVR2_CVAL_INPUT_RADIO]     = MSP_INPUT(MSP_IN_SCART2,
-+						MSP_IN_TUNER1,
-+						MSP_DSP_IN_SCART,
-+						MSP_DSP_IN_SCART),
-+	[PVR2_CVAL_INPUT_COMPOSITE] = MSP_INPUT(MSP_IN_SCART1,
-+						MSP_IN_TUNER1,
-+						MSP_DSP_IN_SCART,
-+						MSP_DSP_IN_SCART),
-+	[PVR2_CVAL_INPUT_SVIDEO]    = MSP_INPUT(MSP_IN_SCART1,
-+						MSP_IN_TUNER1,
-+						MSP_DSP_IN_SCART,
-+						MSP_DSP_IN_SCART),
-+};
-+
-+static const struct routing_scheme routing_schemes[] = {
-+	[PVR2_ROUTING_SCHEME_HAUPPAUGE] = {
-+		.def = routing_scheme0,
-+		.cnt = ARRAY_SIZE(routing_scheme0),
-+	},
-+};
-+
- /* This function selects the correct audio input source */
- static void set_stereo(struct pvr2_msp3400_handler *ctxt)
- {
- 	struct pvr2_hdw *hdw = ctxt->hdw;
- 	struct v4l2_routing route;
-+	const struct routing_scheme *sp;
-+	unsigned int sid = hdw->hdw_desc->signal_routing_scheme;
  
- 	pvr2_trace(PVR2_TRACE_CHIPS,"i2c msp3400 v4l2 set_stereo");
+-#define dprintk(fmt, arg...)	if (video_debug) \
++#define dprintk(fmt, arg...)	if (video_debug&0x04) \
+ 	printk(KERN_DEBUG "%s/video: " fmt, dev->name , ## arg)
  
--	route.input = MSP_INPUT_DEFAULT;
--	route.output = MSP_OUTPUT(MSP_SC_IN_DSP_SCART1);
--	switch (hdw->input_val) {
--	case PVR2_CVAL_INPUT_TV:
--		break;
--	case PVR2_CVAL_INPUT_RADIO:
--		/* Assume that msp34xx also handle FM decoding, in which case
--		   we're still using the tuner. */
--		/* HV: actually it is more likely to be the SCART2 input if
--		   the ivtv experience is any indication. */
--		route.input = MSP_INPUT(MSP_IN_SCART2, MSP_IN_TUNER1,
--				    MSP_DSP_IN_SCART, MSP_DSP_IN_SCART);
--		break;
--	case PVR2_CVAL_INPUT_SVIDEO:
--	case PVR2_CVAL_INPUT_COMPOSITE:
--		/* SCART 1 input */
--		route.input = MSP_INPUT(MSP_IN_SCART1, MSP_IN_TUNER1,
--				    MSP_DSP_IN_SCART, MSP_DSP_IN_SCART);
--		break;
-+	if ((sid < ARRAY_SIZE(routing_schemes)) &&
-+	    ((sp = routing_schemes + sid) != 0) &&
-+	    (hdw->input_val >= 0) &&
-+	    (hdw->input_val < sp->cnt)) {
-+		route.input = sp->def[hdw->input_val];
-+	} else {
-+		pvr2_trace(PVR2_TRACE_ERROR_LEGS,
-+			   "*** WARNING *** i2c msp3400 v4l2 set_stereo:"
-+			   " Invalid routing scheme (%u) and/or input (%d)",
-+			   sid,hdw->input_val);
-+		return;
- 	}
-+	route.output = MSP_OUTPUT(MSP_SC_IN_DSP_SCART1);
- 	pvr2_i2c_client_cmd(ctxt->client,VIDIOC_INT_S_AUDIO_ROUTING,&route);
- }
+ /* ------------------------------------------------------------------ */
+@@ -540,9 +540,8 @@ void res_free(struct saa7134_dev *dev, struct saa7134_fh *fh, unsigned int bits)
  
-diff --git a/drivers/media/video/pvrusb2/pvrusb2-context.c b/drivers/media/video/pvrusb2/pvrusb2-context.c
-index 22719ba..9d94aed 100644
---- a/drivers/media/video/pvrusb2/pvrusb2-context.c
-+++ b/drivers/media/video/pvrusb2/pvrusb2-context.c
-@@ -31,52 +31,32 @@
+ /* ------------------------------------------------------------------ */
  
- static void pvr2_context_destroy(struct pvr2_context *mp)
+-void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm)
++static void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm)
  {
--	if (mp->hdw) pvr2_hdw_destroy(mp->hdw);
- 	pvr2_trace(PVR2_TRACE_STRUCT,"Destroying pvr_main id=%p",mp);
--	if (mp->workqueue) {
--		flush_workqueue(mp->workqueue);
--		destroy_workqueue(mp->workqueue);
--	}
-+	if (mp->hdw) pvr2_hdw_destroy(mp->hdw);
- 	kfree(mp);
- }
+-
+ 	dprintk("set tv norm = %s\n",norm->name);
+ 	dev->tvnorm = norm;
  
+@@ -561,7 +560,6 @@ void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm)
+ 	dev->crop_current = dev->crop_defrect;
  
--static void pvr2_context_trigger_poll(struct pvr2_context *mp)
--{
--	queue_work(mp->workqueue,&mp->workpoll);
--}
--
--
--static void pvr2_context_poll(struct work_struct *work)
--{
--	struct pvr2_context *mp =
--		container_of(work, struct pvr2_context, workpoll);
--	pvr2_context_enter(mp); do {
--		pvr2_hdw_poll(mp->hdw);
--	} while (0); pvr2_context_exit(mp);
--}
--
+ 	saa7134_set_tvnorm_hw(dev);
 -
--static void pvr2_context_setup(struct work_struct *work)
-+static void pvr2_context_state_check(struct pvr2_context *mp)
- {
--	struct pvr2_context *mp =
--		container_of(work, struct pvr2_context, workinit);
-+	if (mp->init_flag) return;
-+
-+	switch (pvr2_hdw_get_state(mp->hdw)) {
-+	case PVR2_STATE_WARM: break;
-+	case PVR2_STATE_ERROR: break;
-+	case PVR2_STATE_READY: break;
-+	case PVR2_STATE_RUN: break;
-+	default: return;
-+	}
+ }
  
- 	pvr2_context_enter(mp); do {
--		if (!pvr2_hdw_dev_ok(mp->hdw)) break;
--		pvr2_hdw_setup(mp->hdw);
--		pvr2_hdw_setup_poll_trigger(
--			mp->hdw,
--			(void (*)(void *))pvr2_context_trigger_poll,
--			mp);
--		if (!pvr2_hdw_dev_ok(mp->hdw)) break;
--		if (!pvr2_hdw_init_ok(mp->hdw)) break;
-+		mp->init_flag = !0;
- 		mp->video_stream.stream = pvr2_hdw_get_video_stream(mp->hdw);
- 		if (mp->setup_func) {
- 			mp->setup_func(mp);
- 		}
- 	} while (0); pvr2_context_exit(mp);
--}
-+ }
+ static void video_mux(struct saa7134_dev *dev, int input)
+@@ -945,7 +943,7 @@ static int buffer_activate(struct saa7134_dev *dev,
+ 	unsigned long bpl_uv,lines_uv,base2,base3,tmp; /* planar */
  
+ 	dprintk("buffer_activate buf=%p\n",buf);
+-	buf->vb.state = STATE_ACTIVE;
++	buf->vb.state = VIDEOBUF_ACTIVE;
+ 	buf->top_seen = 0;
  
- struct pvr2_context *pvr2_context_create(
-@@ -96,11 +76,10 @@ struct pvr2_context *pvr2_context_create(
- 		mp = NULL;
- 		goto done;
+ 	set_size(dev,TASK_A,buf->vb.width,buf->vb.height,
+@@ -1054,7 +1052,7 @@ static int buffer_prepare(struct videobuf_queue *q,
+ 		saa7134_dma_free(q,buf);
  	}
--
--	mp->workqueue = create_singlethread_workqueue("pvrusb2");
--	INIT_WORK(&mp->workinit, pvr2_context_setup);
--	INIT_WORK(&mp->workpoll, pvr2_context_poll);
--	queue_work(mp->workqueue,&mp->workinit);
-+	pvr2_hdw_set_state_callback(mp->hdw,
-+				    (void (*)(void *))pvr2_context_state_check,
-+				    mp);
-+	pvr2_context_state_check(mp);
-  done:
- 	return mp;
- }
-diff --git a/drivers/media/video/pvrusb2/pvrusb2-context.h b/drivers/media/video/pvrusb2/pvrusb2-context.h
-index 6327fa1..a04187a 100644
---- a/drivers/media/video/pvrusb2/pvrusb2-context.h
-+++ b/drivers/media/video/pvrusb2/pvrusb2-context.h
-@@ -45,14 +45,11 @@ struct pvr2_context {
- 	struct pvr2_context_stream video_stream;
- 	struct mutex mutex;
- 	int disconnect_flag;
-+	int init_flag;
  
- 	/* Called after pvr2_context initialization is complete */
- 	void (*setup_func)(struct pvr2_context *);
+-	if (STATE_NEEDS_INIT == buf->vb.state) {
++	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
+ 		struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
  
--	/* Work queue overhead for out-of-line processing */
--	struct workqueue_struct *workqueue;
--	struct work_struct workinit;
--	struct work_struct workpoll;
- };
+ 		buf->vb.width  = fh->width;
+@@ -1074,7 +1072,7 @@ static int buffer_prepare(struct videobuf_queue *q,
+ 		if (err)
+ 			goto oops;
+ 	}
+-	buf->vb.state = STATE_PREPARED;
++	buf->vb.state = VIDEOBUF_PREPARED;
+ 	buf->activate = buffer_activate;
+ 	return 0;
  
- struct pvr2_channel {
-diff --git a/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c b/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c
-index e8a9252..ffdc45c 100644
---- a/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c
-+++ b/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c
-@@ -49,34 +49,89 @@ struct pvr2_v4l_cx2584x {
- };
+@@ -1119,8 +1117,10 @@ static struct videobuf_queue_ops video_qops = {
  
+ /* ------------------------------------------------------------------ */
  
-+struct routing_scheme_item {
-+	int vid;
-+	int aud;
-+};
-+
-+struct routing_scheme {
-+	const struct routing_scheme_item *def;
-+	unsigned int cnt;
-+};
-+
-+static const struct routing_scheme_item routing_scheme0[] = {
-+	[PVR2_CVAL_INPUT_TV] = {
-+		.vid = CX25840_COMPOSITE7,
-+		.aud = CX25840_AUDIO8,
-+	},
-+	[PVR2_CVAL_INPUT_RADIO] = { /* Treat the same as composite */
-+		.vid = CX25840_COMPOSITE3,
-+		.aud = CX25840_AUDIO_SERIAL,
-+	},
-+	[PVR2_CVAL_INPUT_COMPOSITE] = {
-+		.vid = CX25840_COMPOSITE3,
-+		.aud = CX25840_AUDIO_SERIAL,
-+	},
-+	[PVR2_CVAL_INPUT_SVIDEO] = {
-+		.vid = CX25840_SVIDEO1,
-+		.aud = CX25840_AUDIO_SERIAL,
-+	},
-+};
-+
-+/* Specific to gotview device */
-+static const struct routing_scheme_item routing_schemegv[] = {
-+	[PVR2_CVAL_INPUT_TV] = {
-+		.vid = CX25840_COMPOSITE2,
-+		.aud = CX25840_AUDIO5,
-+	},
-+	[PVR2_CVAL_INPUT_RADIO] = { /* Treat the same as composite */
-+		.vid = CX25840_COMPOSITE1,
-+		.aud = CX25840_AUDIO_SERIAL,
-+	},
-+	[PVR2_CVAL_INPUT_COMPOSITE] = {
-+		.vid = CX25840_COMPOSITE1,
-+		.aud = CX25840_AUDIO_SERIAL,
-+	},
-+	[PVR2_CVAL_INPUT_SVIDEO] = {
-+		.vid = (CX25840_SVIDEO_LUMA3|CX25840_SVIDEO_CHROMA4),
-+		.aud = CX25840_AUDIO_SERIAL,
-+	},
-+};
-+
-+static const struct routing_scheme routing_schemes[] = {
-+	[PVR2_ROUTING_SCHEME_HAUPPAUGE] = {
-+		.def = routing_scheme0,
-+		.cnt = ARRAY_SIZE(routing_scheme0),
-+	},
-+	[PVR2_ROUTING_SCHEME_GOTVIEW] = {
-+		.def = routing_schemegv,
-+		.cnt = ARRAY_SIZE(routing_schemegv),
-+	},
-+};
-+
- static void set_input(struct pvr2_v4l_cx2584x *ctxt)
+-static int get_control(struct saa7134_dev *dev, struct v4l2_control *c)
++int saa7134_g_ctrl(struct file *file, void *priv, struct v4l2_control *c)
  {
- 	struct pvr2_hdw *hdw = ctxt->hdw;
- 	struct v4l2_routing route;
- 	enum cx25840_video_input vid_input;
- 	enum cx25840_audio_input aud_input;
-+	const struct routing_scheme *sp;
-+	unsigned int sid = hdw->hdw_desc->signal_routing_scheme;
- 
- 	memset(&route,0,sizeof(route));
++	struct saa7134_fh *fh = priv;
++	struct saa7134_dev *dev = fh->dev;
+ 	const struct v4l2_queryctrl* ctrl;
  
--	switch(hdw->input_val) {
--	case PVR2_CVAL_INPUT_TV:
--		vid_input = CX25840_COMPOSITE7;
--		aud_input = CX25840_AUDIO8;
--		break;
--	case PVR2_CVAL_INPUT_RADIO: // Treat same as composite
--	case PVR2_CVAL_INPUT_COMPOSITE:
--		vid_input = CX25840_COMPOSITE3;
--		aud_input = CX25840_AUDIO_SERIAL;
--		break;
--	case PVR2_CVAL_INPUT_SVIDEO:
--		vid_input = CX25840_SVIDEO1;
--		aud_input = CX25840_AUDIO_SERIAL;
--		break;
--	default:
--		// Just set it to be composite input for now...
--		vid_input = CX25840_COMPOSITE3;
--		aud_input = CX25840_AUDIO_SERIAL;
--		break;
-+	if ((sid < ARRAY_SIZE(routing_schemes)) &&
-+	    ((sp = routing_schemes + sid) != 0) &&
-+	    (hdw->input_val >= 0) &&
-+	    (hdw->input_val < sp->cnt)) {
-+		vid_input = sp->def[hdw->input_val].vid;
-+		aud_input = sp->def[hdw->input_val].aud;
-+	} else {
-+		pvr2_trace(PVR2_TRACE_ERROR_LEGS,
-+			   "*** WARNING *** i2c cx2584x set_input:"
-+			   " Invalid routing scheme (%u) and/or input (%d)",
-+			   sid,hdw->input_val);
-+		return;
+ 	ctrl = ctrl_by_id(c->id);
+@@ -1165,17 +1165,27 @@ static int get_control(struct saa7134_dev *dev, struct v4l2_control *c)
  	}
- 
- 	pvr2_trace(PVR2_TRACE_CHIPS,"i2c cx2584x set_input vid=0x%x aud=0x%x",
-@@ -140,7 +195,7 @@ static const struct pvr2_v4l_cx2584x_ops decoder_ops[] = {
- static void decoder_detach(struct pvr2_v4l_cx2584x *ctxt)
- {
- 	ctxt->client->handler = NULL;
--	ctxt->hdw->decoder_ctrl = NULL;
-+	pvr2_hdw_set_decoder(ctxt->hdw,NULL);
- 	kfree(ctxt);
+ 	return 0;
  }
++EXPORT_SYMBOL_GPL(saa7134_g_ctrl);
  
-@@ -241,7 +296,7 @@ int pvr2_i2c_cx2584x_v4l_setup(struct pvr2_hdw *hdw,
- 	ctxt->client = cp;
- 	ctxt->hdw = hdw;
- 	ctxt->stale_mask = (1 << ARRAY_SIZE(decoder_ops)) - 1;
--	hdw->decoder_ctrl = &ctxt->ctrl;
-+	pvr2_hdw_set_decoder(hdw,&ctxt->ctrl);
- 	cp->handler = &ctxt->handler;
- 	{
- 		/*
-diff --git a/drivers/media/video/pvrusb2/pvrusb2-debug.h b/drivers/media/video/pvrusb2/pvrusb2-debug.h
-index da6441b..fca49d8 100644
---- a/drivers/media/video/pvrusb2/pvrusb2-debug.h
-+++ b/drivers/media/video/pvrusb2/pvrusb2-debug.h
-@@ -34,25 +34,26 @@ extern int pvrusb2_debug;
- #define PVR2_TRACE_INIT       (1 <<  5) /* misc initialization steps */
- #define PVR2_TRACE_START_STOP (1 <<  6) /* Streaming start / stop */
- #define PVR2_TRACE_CTL        (1 <<  7) /* commit of control changes */
--#define PVR2_TRACE_DEBUG      (1 <<  8) /* Temporary debug code */
--#define PVR2_TRACE_EEPROM     (1 <<  9) /* eeprom parsing / report */
--#define PVR2_TRACE_STRUCT     (1 << 10) /* internal struct creation */
--#define PVR2_TRACE_OPEN_CLOSE (1 << 11) /* application open / close */
--#define PVR2_TRACE_CREG       (1 << 12) /* Main critical region entry / exit */
--#define PVR2_TRACE_SYSFS      (1 << 13) /* Sysfs driven I/O */
--#define PVR2_TRACE_FIRMWARE   (1 << 14) /* firmware upload actions */
--#define PVR2_TRACE_CHIPS      (1 << 15) /* chip broadcast operation */
--#define PVR2_TRACE_I2C        (1 << 16) /* I2C related stuff */
--#define PVR2_TRACE_I2C_CMD    (1 << 17) /* Software commands to I2C modules */
--#define PVR2_TRACE_I2C_CORE   (1 << 18) /* I2C core debugging */
--#define PVR2_TRACE_I2C_TRAF   (1 << 19) /* I2C traffic through the adapter */
--#define PVR2_TRACE_V4LIOCTL   (1 << 20) /* v4l ioctl details */
--#define PVR2_TRACE_ENCODER    (1 << 21) /* mpeg2 encoder operation */
--#define PVR2_TRACE_BUF_POOL   (1 << 22) /* Track buffer pool management */
--#define PVR2_TRACE_BUF_FLOW   (1 << 23) /* Track buffer flow in system */
--#define PVR2_TRACE_DATA_FLOW  (1 << 24) /* Track data flow */
--#define PVR2_TRACE_DEBUGIFC   (1 << 25) /* Debug interface actions */
--#define PVR2_TRACE_GPIO       (1 << 26) /* GPIO state bit changes */
-+#define PVR2_TRACE_STATE      (1 <<  8) /* Device state changes */
-+#define PVR2_TRACE_STBITS     (1 <<  9) /* Individual bit state changes */
-+#define PVR2_TRACE_EEPROM     (1 << 10) /* eeprom parsing / report */
-+#define PVR2_TRACE_STRUCT     (1 << 11) /* internal struct creation */
-+#define PVR2_TRACE_OPEN_CLOSE (1 << 12) /* application open / close */
-+#define PVR2_TRACE_CREG       (1 << 13) /* Main critical region entry / exit */
-+#define PVR2_TRACE_SYSFS      (1 << 14) /* Sysfs driven I/O */
-+#define PVR2_TRACE_FIRMWARE   (1 << 15) /* firmware upload actions */
-+#define PVR2_TRACE_CHIPS      (1 << 16) /* chip broadcast operation */
-+#define PVR2_TRACE_I2C        (1 << 17) /* I2C related stuff */
-+#define PVR2_TRACE_I2C_CMD    (1 << 18) /* Software commands to I2C modules */
-+#define PVR2_TRACE_I2C_CORE   (1 << 19) /* I2C core debugging */
-+#define PVR2_TRACE_I2C_TRAF   (1 << 20) /* I2C traffic through the adapter */
-+#define PVR2_TRACE_V4LIOCTL   (1 << 21) /* v4l ioctl details */
-+#define PVR2_TRACE_ENCODER    (1 << 22) /* mpeg2 encoder operation */
-+#define PVR2_TRACE_BUF_POOL   (1 << 23) /* Track buffer pool management */
-+#define PVR2_TRACE_BUF_FLOW   (1 << 24) /* Track buffer flow in system */
-+#define PVR2_TRACE_DATA_FLOW  (1 << 25) /* Track data flow */
-+#define PVR2_TRACE_DEBUGIFC   (1 << 26) /* Debug interface actions */
-+#define PVR2_TRACE_GPIO       (1 << 27) /* GPIO state bit changes */
+-static int set_control(struct saa7134_dev *dev, struct saa7134_fh *fh,
+-		       struct v4l2_control *c)
++int saa7134_s_ctrl(struct file *file, void *f, struct v4l2_control *c)
+ {
+ 	const struct v4l2_queryctrl* ctrl;
++	struct saa7134_fh *fh = f;
++	struct saa7134_dev *dev = fh->dev;
+ 	unsigned long flags;
+ 	int restart_overlay = 0;
++	int err = -EINVAL;
++
++	err = v4l2_prio_check(&dev->prio, &fh->prio);
++	if (0 != err)
++		return err;
++
++	mutex_lock(&dev->lock);
  
+ 	ctrl = ctrl_by_id(c->id);
+ 	if (NULL == ctrl)
+-		return -EINVAL;
++		goto error;
++
+ 	dprintk("set_control name=%s val=%d\n",ctrl->name,c->value);
+ 	switch (ctrl->type) {
+ 	case V4L2_CTRL_TYPE_BOOLEAN:
+@@ -1236,18 +1246,26 @@ static int set_control(struct saa7134_dev *dev, struct saa7134_fh *fh,
+ 		restart_overlay = 1;
+ 		break;
+ 	case V4L2_CID_PRIVATE_AUTOMUTE:
++	{
++		struct v4l2_priv_tun_config tda9887_cfg;
++
++		tda9887_cfg.tuner = TUNER_TDA9887;
++		tda9887_cfg.priv = &dev->tda9887_conf;
++
+ 		dev->ctl_automute = c->value;
+ 		if (dev->tda9887_conf) {
+ 			if (dev->ctl_automute)
+ 				dev->tda9887_conf |= TDA9887_AUTOMUTE;
+ 			else
+ 				dev->tda9887_conf &= ~TDA9887_AUTOMUTE;
+-			saa7134_i2c_call_clients(dev, TDA9887_SET_CONFIG,
+-						 &dev->tda9887_conf);
++
++			saa7134_i2c_call_clients(dev, TUNER_SET_CONFIG,
++						 &tda9887_cfg);
+ 		}
+ 		break;
++	}
+ 	default:
+-		return -EINVAL;
++		goto error;
+ 	}
+ 	if (restart_overlay && fh && res_check(fh, RESOURCE_OVERLAY)) {
+ 		spin_lock_irqsave(&dev->slock,flags);
+@@ -1255,8 +1273,13 @@ static int set_control(struct saa7134_dev *dev, struct saa7134_fh *fh,
+ 		start_preview(dev,fh);
+ 		spin_unlock_irqrestore(&dev->slock,flags);
+ 	}
+-	return 0;
++	err = 0;
++
++error:
++	mutex_unlock(&dev->lock);
++	return err;
+ }
++EXPORT_SYMBOL_GPL(saa7134_s_ctrl);
  
- #endif /* __PVRUSB2_HDW_INTERNAL_H */
-diff --git a/drivers/media/video/pvrusb2/pvrusb2-debugifc.c b/drivers/media/video/pvrusb2/pvrusb2-debugifc.c
-index 6f135f4..b068743 100644
---- a/drivers/media/video/pvrusb2/pvrusb2-debugifc.c
-+++ b/drivers/media/video/pvrusb2/pvrusb2-debugifc.c
-@@ -31,14 +31,6 @@ struct debugifc_mask_item {
- 	unsigned long msk;
- };
+ /* ------------------------------------------------------------------ */
  
--static struct debugifc_mask_item mask_items[] = {
--	{"ENC_FIRMWARE",(1<<PVR2_SUBSYS_B_ENC_FIRMWARE)},
--	{"ENC_CFG",(1<<PVR2_SUBSYS_B_ENC_CFG)},
--	{"DIG_RUN",(1<<PVR2_SUBSYS_B_DIGITIZER_RUN)},
--	{"USB_RUN",(1<<PVR2_SUBSYS_B_USBSTREAM_RUN)},
--	{"ENC_RUN",(1<<PVR2_SUBSYS_B_ENC_RUN)},
--};
--
+@@ -1413,8 +1436,8 @@ video_poll(struct file *file, struct poll_table_struct *wait)
+ 		return POLLERR;
  
- static unsigned int debugifc_count_whitespace(const char *buf,
- 					      unsigned int count)
-@@ -148,134 +140,14 @@ static int debugifc_match_keyword(const char *buf,unsigned int count,
+ 	poll_wait(file, &buf->done, wait);
+-	if (buf->state == STATE_DONE ||
+-	    buf->state == STATE_ERROR)
++	if (buf->state == VIDEOBUF_DONE ||
++	    buf->state == VIDEOBUF_ERROR)
+ 		return POLLIN|POLLRDNORM;
+ 	return 0;
  }
+@@ -1478,8 +1501,11 @@ static int video_mmap(struct file *file, struct vm_area_struct * vma)
  
+ /* ------------------------------------------------------------------ */
  
--static unsigned long debugifc_find_mask(const char *buf,unsigned int count)
--{
--	struct debugifc_mask_item *mip;
--	unsigned int idx;
--	for (idx = 0; idx < ARRAY_SIZE(mask_items); idx++) {
--		mip = mask_items + idx;
--		if (debugifc_match_keyword(buf,count,mip->name)) {
--			return mip->msk;
--		}
--	}
--	return 0;
--}
--
--
--static int debugifc_print_mask(char *buf,unsigned int sz,
--			       unsigned long msk,unsigned long val)
--{
--	struct debugifc_mask_item *mip;
--	unsigned int idx;
--	int bcnt = 0;
--	int ccnt;
--	for (idx = 0; idx < ARRAY_SIZE(mask_items); idx++) {
--		mip = mask_items + idx;
--		if (!(mip->msk & msk)) continue;
--		ccnt = scnprintf(buf,sz,"%s%c%s",
--				 (bcnt ? " " : ""),
--				 ((mip->msk & val) ? '+' : '-'),
--				 mip->name);
--		sz -= ccnt;
--		buf += ccnt;
--		bcnt += ccnt;
--	}
--	return bcnt;
--}
--
--static unsigned int debugifc_parse_subsys_mask(const char *buf,
--					       unsigned int count,
--					       unsigned long *mskPtr,
--					       unsigned long *valPtr)
--{
--	const char *wptr;
--	unsigned int consume_cnt = 0;
--	unsigned int scnt;
--	unsigned int wlen;
--	int mode;
--	unsigned long m1,msk,val;
--
--	msk = 0;
--	val = 0;
--
--	while (count) {
--		scnt = debugifc_isolate_word(buf,count,&wptr,&wlen);
--		if (!scnt) break;
--		consume_cnt += scnt; count -= scnt; buf += scnt;
--		if (!wptr) break;
--
--		mode = 0;
--		if (wlen) switch (wptr[0]) {
--		case '+':
--			wptr++;
--			wlen--;
--			break;
--		case '-':
--			mode = 1;
--			wptr++;
--			wlen--;
--			break;
--		}
--		if (!wlen) continue;
--		m1 = debugifc_find_mask(wptr,wlen);
--		if (!m1) break;
--		msk |= m1;
--		if (!mode) val |= m1;
--	}
--	*mskPtr = msk;
--	*valPtr = val;
--	return consume_cnt;
--}
--
--
- int pvr2_debugifc_print_info(struct pvr2_hdw *hdw,char *buf,unsigned int acnt)
+-static void saa7134_vbi_fmt(struct saa7134_dev *dev, struct v4l2_format *f)
++static int saa7134_try_get_set_fmt_vbi(struct file *file, void *priv,
++						struct v4l2_format *f)
  {
- 	int bcnt = 0;
- 	int ccnt;
--	struct pvr2_hdw_debug_info dbg;
--
--	pvr2_hdw_get_debug_info(hdw,&dbg);
--
--	ccnt = scnprintf(buf,acnt,"big lock %s; ctl lock %s",
--			 (dbg.big_lock_held ? "held" : "free"),
--			 (dbg.ctl_lock_held ? "held" : "free"));
--	bcnt += ccnt; acnt -= ccnt; buf += ccnt;
--	if (dbg.ctl_lock_held) {
--		ccnt = scnprintf(buf,acnt,"; cmd_state=%d cmd_code=%d"
--				 " cmd_wlen=%d cmd_rlen=%d"
--				 " wpend=%d rpend=%d tmout=%d rstatus=%d"
--				 " wstatus=%d",
--				 dbg.cmd_debug_state,dbg.cmd_code,
--				 dbg.cmd_debug_write_len,
--				 dbg.cmd_debug_read_len,
--				 dbg.cmd_debug_write_pend,
--				 dbg.cmd_debug_read_pend,
--				 dbg.cmd_debug_timeout,
--				 dbg.cmd_debug_rstatus,
--				 dbg.cmd_debug_wstatus);
--		bcnt += ccnt; acnt -= ccnt; buf += ccnt;
++	struct saa7134_fh *fh = priv;
++	struct saa7134_dev *dev = fh->dev;
+ 	struct saa7134_tvnorm *norm = dev->tvnorm;
+ 
+ 	f->fmt.vbi.sampling_rate = 6750000 * 4;
+@@ -1492,837 +1518,805 @@ static void saa7134_vbi_fmt(struct saa7134_dev *dev, struct v4l2_format *f)
+ 	f->fmt.vbi.count[1] = f->fmt.vbi.count[0];
+ 	f->fmt.vbi.flags = 0; /* VBI_UNSYNC VBI_INTERLACED */
+ 
++	return 0;
+ }
+ 
+-static int saa7134_g_fmt(struct saa7134_dev *dev, struct saa7134_fh *fh,
+-			 struct v4l2_format *f)
++static int saa7134_g_fmt_cap(struct file *file, void *priv,
++				struct v4l2_format *f)
+ {
+-	switch (f->type) {
+-	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+-		memset(&f->fmt.pix,0,sizeof(f->fmt.pix));
+-		f->fmt.pix.width        = fh->width;
+-		f->fmt.pix.height       = fh->height;
+-		f->fmt.pix.field        = fh->cap.field;
+-		f->fmt.pix.pixelformat  = fh->fmt->fourcc;
+-		f->fmt.pix.bytesperline =
+-			(f->fmt.pix.width * fh->fmt->depth) >> 3;
+-		f->fmt.pix.sizeimage =
+-			f->fmt.pix.height * f->fmt.pix.bytesperline;
+-		return 0;
+-	case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+-		if (saa7134_no_overlay > 0) {
+-			printk ("V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
+-			return -EINVAL;
+-		}
+-		f->fmt.win = fh->win;
+-		return 0;
+-	case V4L2_BUF_TYPE_VBI_CAPTURE:
+-		saa7134_vbi_fmt(dev,f);
+-		return 0;
+-	default:
+-		return -EINVAL;
 -	}
--	ccnt = scnprintf(buf,acnt,"\n");
--	bcnt += ccnt; acnt -= ccnt; buf += ccnt;
--	ccnt = scnprintf(
--		buf,acnt,"driver flags: %s %s %s\n",
--		(dbg.flag_init_ok ? "initialized" : "uninitialized"),
--		(dbg.flag_ok ? "ok" : "fail"),
--		(dbg.flag_disconnected ? "disconnected" : "connected"));
--	bcnt += ccnt; acnt -= ccnt; buf += ccnt;
--	ccnt = scnprintf(buf,acnt,"Subsystems enabled / configured: ");
-+	ccnt = scnprintf(buf,acnt,"Driver state info:\n");
- 	bcnt += ccnt; acnt -= ccnt; buf += ccnt;
--	ccnt = debugifc_print_mask(buf,acnt,dbg.subsys_flags,dbg.subsys_flags);
-+	ccnt = pvr2_hdw_state_report(hdw,buf,acnt);
- 	bcnt += ccnt; acnt -= ccnt; buf += ccnt;
--	ccnt = scnprintf(buf,acnt,"\n");
--	bcnt += ccnt; acnt -= ccnt; buf += ccnt;
--	ccnt = scnprintf(buf,acnt,"Subsystems disabled / unconfigured: ");
--	bcnt += ccnt; acnt -= ccnt; buf += ccnt;
--	ccnt = debugifc_print_mask(buf,acnt,~dbg.subsys_flags,dbg.subsys_flags);
--	bcnt += ccnt; acnt -= ccnt; buf += ccnt;
--	ccnt = scnprintf(buf,acnt,"\n");
--	bcnt += ccnt; acnt -= ccnt; buf += ccnt;
--
- 	ccnt = scnprintf(buf,acnt,"Attached I2C modules:\n");
- 	bcnt += ccnt; acnt -= ccnt; buf += ccnt;
- 	ccnt = pvr2_i2c_report(hdw,buf,acnt);
-@@ -290,7 +162,6 @@ int pvr2_debugifc_print_status(struct pvr2_hdw *hdw,
++	struct saa7134_fh *fh = priv;
++
++	f->fmt.pix.width        = fh->width;
++	f->fmt.pix.height       = fh->height;
++	f->fmt.pix.field        = fh->cap.field;
++	f->fmt.pix.pixelformat  = fh->fmt->fourcc;
++	f->fmt.pix.bytesperline =
++		(f->fmt.pix.width * fh->fmt->depth) >> 3;
++	f->fmt.pix.sizeimage =
++		f->fmt.pix.height * f->fmt.pix.bytesperline;
++	return 0;
+ }
+ 
+-static int saa7134_try_fmt(struct saa7134_dev *dev, struct saa7134_fh *fh,
+-			   struct v4l2_format *f)
++static int saa7134_g_fmt_overlay(struct file *file, void *priv,
++				struct v4l2_format *f)
  {
- 	int bcnt = 0;
- 	int ccnt;
--	unsigned long msk;
- 	int ret;
- 	u32 gpio_dir,gpio_in,gpio_out;
+-	int err;
++	struct saa7134_fh *fh = priv;
  
-@@ -311,28 +182,6 @@ int pvr2_debugifc_print_status(struct pvr2_hdw *hdw,
- 			 pvr2_hdw_get_streaming(hdw) ? "on" : "off");
- 	bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+-	switch (f->type) {
+-	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+-	{
+-		struct saa7134_format *fmt;
+-		enum v4l2_field field;
+-		unsigned int maxw, maxh;
++	if (saa7134_no_overlay > 0) {
++		printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
++		return -EINVAL;
++	}
++	f->fmt.win = fh->win;
  
--	msk = pvr2_hdw_subsys_get(hdw);
--	ccnt = scnprintf(buf,acnt,"Subsystems enabled / configured: ");
--	bcnt += ccnt; acnt -= ccnt; buf += ccnt;
--	ccnt = debugifc_print_mask(buf,acnt,msk,msk);
--	bcnt += ccnt; acnt -= ccnt; buf += ccnt;
--	ccnt = scnprintf(buf,acnt,"\n");
--	bcnt += ccnt; acnt -= ccnt; buf += ccnt;
--	ccnt = scnprintf(buf,acnt,"Subsystems disabled / unconfigured: ");
--	bcnt += ccnt; acnt -= ccnt; buf += ccnt;
--	ccnt = debugifc_print_mask(buf,acnt,~msk,msk);
--	bcnt += ccnt; acnt -= ccnt; buf += ccnt;
--	ccnt = scnprintf(buf,acnt,"\n");
--	bcnt += ccnt; acnt -= ccnt; buf += ccnt;
--
--	msk = pvr2_hdw_subsys_stream_get(hdw);
--	ccnt = scnprintf(buf,acnt,"Subsystems stopped on stream shutdown: ");
--	bcnt += ccnt; acnt -= ccnt; buf += ccnt;
--	ccnt = debugifc_print_mask(buf,acnt,msk,msk);
--	bcnt += ccnt; acnt -= ccnt; buf += ccnt;
--	ccnt = scnprintf(buf,acnt,"\n");
--	bcnt += ccnt; acnt -= ccnt; buf += ccnt;
--
- 	return bcnt;
- }
+-		fmt = format_by_fourcc(f->fmt.pix.pixelformat);
+-		if (NULL == fmt)
+-			return -EINVAL;
++	return 0;
++}
  
-@@ -369,28 +218,10 @@ static int pvr2_debugifc_do1cmd(struct pvr2_hdw *hdw,const char *buf,
- 			return pvr2_upload_firmware2(hdw);
- 		} else if (debugifc_match_keyword(wptr,wlen,"decoder")) {
- 			return pvr2_hdw_cmd_decoder_reset(hdw);
-+		} else if (debugifc_match_keyword(wptr,wlen,"worker")) {
-+			return pvr2_hdw_untrip(hdw);
- 		}
- 		return -EINVAL;
--	} else if (debugifc_match_keyword(wptr,wlen,"subsys_flags")) {
--		unsigned long msk = 0;
--		unsigned long val = 0;
--		if (debugifc_parse_subsys_mask(buf,count,&msk,&val) != count) {
--			pvr2_trace(PVR2_TRACE_DEBUGIFC,
--				   "debugifc parse error on subsys mask");
+-		field = f->fmt.pix.field;
+-		maxw  = min(dev->crop_current.width*4,  dev->crop_bounds.width);
+-		maxh  = min(dev->crop_current.height*4, dev->crop_bounds.height);
++static int saa7134_try_fmt_cap(struct file *file, void *priv,
++						struct v4l2_format *f)
++{
++	struct saa7134_fh *fh = priv;
++	struct saa7134_dev *dev = fh->dev;
++	struct saa7134_format *fmt;
++	enum v4l2_field field;
++	unsigned int maxw, maxh;
+ 
+-		if (V4L2_FIELD_ANY == field) {
+-			field = (f->fmt.pix.height > maxh/2)
+-				? V4L2_FIELD_INTERLACED
+-				: V4L2_FIELD_BOTTOM;
+-		}
+-		switch (field) {
+-		case V4L2_FIELD_TOP:
+-		case V4L2_FIELD_BOTTOM:
+-			maxh = maxh / 2;
+-			break;
+-		case V4L2_FIELD_INTERLACED:
+-			break;
+-		default:
 -			return -EINVAL;
 -		}
--		pvr2_hdw_subsys_bit_chg(hdw,msk,val);
++	fmt = format_by_fourcc(f->fmt.pix.pixelformat);
++	if (NULL == fmt)
++		return -EINVAL;
+ 
+-		f->fmt.pix.field = field;
+-		if (f->fmt.pix.width  < 48)
+-			f->fmt.pix.width  = 48;
+-		if (f->fmt.pix.height < 32)
+-			f->fmt.pix.height = 32;
+-		if (f->fmt.pix.width > maxw)
+-			f->fmt.pix.width = maxw;
+-		if (f->fmt.pix.height > maxh)
+-			f->fmt.pix.height = maxh;
+-		f->fmt.pix.width &= ~0x03;
+-		f->fmt.pix.bytesperline =
+-			(f->fmt.pix.width * fmt->depth) >> 3;
+-		f->fmt.pix.sizeimage =
+-			f->fmt.pix.height * f->fmt.pix.bytesperline;
++	field = f->fmt.pix.field;
++	maxw  = min(dev->crop_current.width*4,  dev->crop_bounds.width);
++	maxh  = min(dev->crop_current.height*4, dev->crop_bounds.height);
+ 
 -		return 0;
--	} else if (debugifc_match_keyword(wptr,wlen,"stream_flags")) {
--		unsigned long msk = 0;
--		unsigned long val = 0;
--		if (debugifc_parse_subsys_mask(buf,count,&msk,&val) != count) {
--			pvr2_trace(PVR2_TRACE_DEBUGIFC,
--				   "debugifc parse error on stream mask");
++	if (V4L2_FIELD_ANY == field) {
++		field = (f->fmt.pix.height > maxh/2)
++			? V4L2_FIELD_INTERLACED
++			: V4L2_FIELD_BOTTOM;
+ 	}
+-	case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+-		if (saa7134_no_overlay > 0) {
+-			printk ("V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
 -			return -EINVAL;
 -		}
--		pvr2_hdw_subsys_stream_bit_chg(hdw,msk,val);
+-		err = verify_preview(dev,&f->fmt.win);
+-		if (0 != err)
+-			return err;
 -		return 0;
- 	} else if (debugifc_match_keyword(wptr,wlen,"cpufw")) {
- 		scnt = debugifc_isolate_word(buf,count,&wptr,&wlen);
- 		if (!scnt) return -EINVAL;
-diff --git a/drivers/media/video/pvrusb2/pvrusb2-devattr.c b/drivers/media/video/pvrusb2/pvrusb2-devattr.c
-new file mode 100644
-index 0000000..4df6d6d
---- /dev/null
-+++ b/drivers/media/video/pvrusb2/pvrusb2-devattr.c
-@@ -0,0 +1,217 @@
-+/*
-+ *
-+ *  $Id$
-+ *
-+ *  Copyright (C) 2007 Mike Isely <isely at pobox.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
-+ *
-+ *  This program is distributed in the hope that it will be useful,
-+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+ *  GNU General Public License for more details.
-+ *
-+ *  You should have received a copy of the GNU General Public License
-+ *  along with this program; if not, write to the Free Software
-+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-+ *
-+ */
-+
-+/*
-+
-+This source file should encompass ALL per-device type information for the
-+driver.  To define a new device, add elements to the pvr2_device_table and
-+pvr2_device_desc structures.
-+
-+*/
-+
-+#include "pvrusb2-devattr.h"
-+#include <linux/usb.h>
-+/* This is needed in order to pull in tuner type ids... */
-+#include <linux/i2c.h>
-+#include <media/tuner.h>
-+
-+
-+
-+/*------------------------------------------------------------------------*/
-+/* Hauppauge PVR-USB2 Model 29xxx */
-+
-+static const char *pvr2_client_29xxx[] = {
-+	"msp3400",
-+	"saa7115",
-+	"tuner",
-+};
-+
-+static const char *pvr2_fw1_names_29xxx[] = {
-+		"v4l-pvrusb2-29xxx-01.fw",
-+};
-+
-+static const struct pvr2_device_desc pvr2_device_29xxx = {
-+		.description = "WinTV PVR USB2 Model Category 29xxxx",
-+		.shortname = "29xxx",
-+		.client_modules.lst = pvr2_client_29xxx,
-+		.client_modules.cnt = ARRAY_SIZE(pvr2_client_29xxx),
-+		.fx2_firmware.lst = pvr2_fw1_names_29xxx,
-+		.fx2_firmware.cnt = ARRAY_SIZE(pvr2_fw1_names_29xxx),
-+		.flag_has_hauppauge_rom = !0,
-+		.signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE,
-+};
-+
-+
-+
-+/*------------------------------------------------------------------------*/
-+/* Hauppauge PVR-USB2 Model 24xxx */
-+
-+static const char *pvr2_client_24xxx[] = {
-+	"cx25840",
-+	"tuner",
-+	"wm8775",
-+};
-+
-+static const char *pvr2_fw1_names_24xxx[] = {
-+		"v4l-pvrusb2-24xxx-01.fw",
-+};
-+
-+static const struct pvr2_device_desc pvr2_device_24xxx = {
-+		.description = "WinTV PVR USB2 Model Category 24xxxx",
-+		.shortname = "24xxx",
-+		.client_modules.lst = pvr2_client_24xxx,
-+		.client_modules.cnt = ARRAY_SIZE(pvr2_client_24xxx),
-+		.fx2_firmware.lst = pvr2_fw1_names_24xxx,
-+		.fx2_firmware.cnt = ARRAY_SIZE(pvr2_fw1_names_24xxx),
-+		.flag_has_cx25840 = !0,
-+		.flag_has_wm8775 = !0,
-+		.flag_has_hauppauge_rom = !0,
-+		.flag_has_hauppauge_custom_ir = !0,
-+		.signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE,
-+};
-+
-+
-+
-+/*------------------------------------------------------------------------*/
-+/* GOTVIEW USB2.0 DVD2 */
-+
-+static const char *pvr2_client_gotview_2[] = {
-+	"cx25840",
-+	"tuner",
-+};
-+
-+static const struct pvr2_device_desc pvr2_device_gotview_2 = {
-+		.description = "Gotview USB 2.0 DVD 2",
-+		.shortname = "gv2",
-+		.client_modules.lst = pvr2_client_gotview_2,
-+		.client_modules.cnt = ARRAY_SIZE(pvr2_client_gotview_2),
-+		.flag_has_cx25840 = !0,
-+		.default_tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
-+		.signal_routing_scheme = PVR2_ROUTING_SCHEME_GOTVIEW,
-+};
-+
-+
-+
-+#ifdef CONFIG_VIDEO_PVRUSB2_ONAIR_CREATOR
-+/*------------------------------------------------------------------------*/
-+/* OnAir Creator */
-+
-+static const char *pvr2_client_onair_creator[] = {
-+	"saa7115",
-+	"tuner",
-+	"cs53l32a",
-+};
-+
-+static const struct pvr2_device_desc pvr2_device_onair_creator = {
-+		.description = "OnAir Creator Hybrid USB tuner",
-+		.shortname = "oac",
-+		.client_modules.lst = pvr2_client_onair_creator,
-+		.client_modules.cnt = ARRAY_SIZE(pvr2_client_onair_creator),
-+		.default_tuner_type = TUNER_LG_TDVS_H06XF,
-+		.signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE,
-+};
-+#endif
-+
-+
-+
-+#ifdef CONFIG_VIDEO_PVRUSB2_ONAIR_USB2
-+/*------------------------------------------------------------------------*/
-+/* OnAir USB 2.0 */
-+
-+static const char *pvr2_client_onair_usb2[] = {
-+	"saa7115",
-+	"tuner",
-+	"cs53l32a",
-+};
-+
-+static const struct pvr2_device_desc pvr2_device_onair_usb2 = {
-+		.description = "OnAir USB2 Hybrid USB tuner",
-+		.shortname = "oa2",
-+		.client_modules.lst = pvr2_client_onair_usb2,
-+		.client_modules.cnt = ARRAY_SIZE(pvr2_client_onair_usb2),
-+		.default_tuner_type = TUNER_PHILIPS_ATSC,
-+		.signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE,
-+};
-+#endif
-+
-+
-+
-+/*------------------------------------------------------------------------*/
-+/* Hauppauge PVR-USB2 Model 75xxx */
-+
-+static const char *pvr2_client_75xxx[] = {
-+	"cx25840",
-+	"tuner",
-+};
-+
-+static const char *pvr2_fw1_names_75xxx[] = {
-+		"v4l-pvrusb2-73xxx-01.fw",
-+};
-+
-+static const struct pvr2_device_desc pvr2_device_75xxx = {
-+		.description = "WinTV PVR USB2 Model Category 75xxxx",
-+		.shortname = "75xxx",
-+		.client_modules.lst = pvr2_client_75xxx,
-+		.client_modules.cnt = ARRAY_SIZE(pvr2_client_75xxx),
-+		.fx2_firmware.lst = pvr2_fw1_names_75xxx,
-+		.fx2_firmware.cnt = ARRAY_SIZE(pvr2_fw1_names_75xxx),
-+		.flag_has_cx25840 = !0,
-+		.flag_has_hauppauge_rom = !0,
-+		.signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE,
-+		.default_std_mask = V4L2_STD_NTSC_M,
-+};
-+
-+
-+
-+/*------------------------------------------------------------------------*/
-+
-+struct usb_device_id pvr2_device_table[] = {
-+	{ USB_DEVICE(0x2040, 0x2900),
-+	  .driver_info = (kernel_ulong_t)&pvr2_device_29xxx},
-+	{ USB_DEVICE(0x2040, 0x2400),
-+	  .driver_info = (kernel_ulong_t)&pvr2_device_24xxx},
-+	{ USB_DEVICE(0x1164, 0x0622),
-+	  .driver_info = (kernel_ulong_t)&pvr2_device_gotview_2},
-+#ifdef CONFIG_VIDEO_PVRUSB2_ONAIR_CREATOR
-+	{ USB_DEVICE(0x11ba, 0x1003),
-+	  .driver_info = (kernel_ulong_t)&pvr2_device_onair_creator},
-+#endif
-+#ifdef CONFIG_VIDEO_PVRUSB2_ONAIR_USB2
-+	{ USB_DEVICE(0x11ba, 0x1001),
-+	  .driver_info = (kernel_ulong_t)&pvr2_device_onair_usb2},
-+#endif
-+	{ USB_DEVICE(0x2040, 0x7500),
-+	  .driver_info = (kernel_ulong_t)&pvr2_device_75xxx},
-+	{ }
-+};
-+
-+MODULE_DEVICE_TABLE(usb, pvr2_device_table);
-+
-+
-+/*
-+  Stuff for Emacs to see, in order to encourage consistent editing style:
-+  *** Local Variables: ***
-+  *** mode: c ***
-+  *** fill-column: 75 ***
-+  *** tab-width: 8 ***
-+  *** c-basic-offset: 8 ***
-+  *** End: ***
-+  */
-diff --git a/drivers/media/video/pvrusb2/pvrusb2-devattr.h b/drivers/media/video/pvrusb2/pvrusb2-devattr.h
-new file mode 100644
-index 0000000..64b467f
---- /dev/null
-+++ b/drivers/media/video/pvrusb2/pvrusb2-devattr.h
-@@ -0,0 +1,119 @@
-+/*
-+ *
-+ *  $Id$
-+ *
-+ *  Copyright (C) 2005 Mike Isely <isely at pobox.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
-+ *
-+ *  This program is distributed in the hope that it will be useful,
-+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+ *  GNU General Public License for more details.
-+ *
-+ *  You 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 __PVRUSB2_DEVATTR_H
-+#define __PVRUSB2_DEVATTR_H
-+
-+#include <linux/mod_devicetable.h>
-+#include <linux/videodev2.h>
-+
-+/*
-+
-+  This header defines structures used to describe attributes of a device.
-+
-+*/
-+
-+
-+struct pvr2_string_table {
-+	const char **lst;
-+	unsigned int cnt;
-+};
-+
-+#define PVR2_ROUTING_SCHEME_HAUPPAUGE 0
-+#define PVR2_ROUTING_SCHEME_GOTVIEW 1
-+
-+/* This describes a particular hardware type (except for the USB device ID
-+   which must live in a separate structure due to environmental
-+   constraints).  See the top of pvrusb2-hdw.c for where this is
-+   instantiated. */
-+struct pvr2_device_desc {
-+	/* Single line text description of hardware */
-+	const char *description;
-+
-+	/* Single token identifier for hardware */
-+	const char *shortname;
-+
-+	/* List of additional client modules we need to load */
-+	struct pvr2_string_table client_modules;
-+
-+	/* List of FX2 firmware file names we should search; if empty then
-+	   FX2 firmware check / load is skipped and we assume the device
-+	   was initialized from internal ROM. */
-+	struct pvr2_string_table fx2_firmware;
-+
-+	/* Signal routing scheme used by device, contains one of
-+	   PVR2_ROUTING_SCHEME_XXX.  Schemes have to be defined as we
-+	   encounter them.  This is an arbitrary integer scheme id; its
-+	   meaning is contained entirely within the driver and is
-+	   interpreted by logic which must send commands to the chip-level
-+	   drivers (search for things which touch this field). */
-+	unsigned int signal_routing_scheme;
-+
-+	/* V4L tuner type ID to use with this device (only used if the
-+	   driver could not discover the type any other way). */
-+	int default_tuner_type;
-+
-+	/* Initial standard bits to use for this device, if not zero.
-+	   Anything set here is also implied as an available standard.
-+	   Note: This is ignored if overridden on the module load line via
-+	   the video_std module option. */
-+	v4l2_std_id default_std_mask;
-+
-+	/* If set, we don't bother trying to load cx23416 firmware. */
-+	char flag_skip_cx23416_firmware;
-+
-+	/* Device has a hauppauge eeprom which we can interrogate. */
-+	char flag_has_hauppauge_rom;
-+
-+	/* Device does not require a powerup command to be issued. */
-+	char flag_no_powerup;
-+
-+	/* Device has a cx25840 - this enables special additional logic to
-+	   handle it. */
-+	char flag_has_cx25840;
+-	case V4L2_BUF_TYPE_VBI_CAPTURE:
+-		saa7134_vbi_fmt(dev,f);
+-		return 0;
++	switch (field) {
++	case V4L2_FIELD_TOP:
++	case V4L2_FIELD_BOTTOM:
++		maxh = maxh / 2;
++		break;
++	case V4L2_FIELD_INTERLACED:
++		break;
+ 	default:
+ 		return -EINVAL;
+ 	}
 +
-+	/* Device has a wm8775 - this enables special additional logic to
-+	   ensure that it is found. */
-+	char flag_has_wm8775;
++	f->fmt.pix.field = field;
++	if (f->fmt.pix.width  < 48)
++		f->fmt.pix.width  = 48;
++	if (f->fmt.pix.height < 32)
++		f->fmt.pix.height = 32;
++	if (f->fmt.pix.width > maxw)
++		f->fmt.pix.width = maxw;
++	if (f->fmt.pix.height > maxh)
++		f->fmt.pix.height = maxh;
++	f->fmt.pix.width &= ~0x03;
++	f->fmt.pix.bytesperline =
++		(f->fmt.pix.width * fmt->depth) >> 3;
++	f->fmt.pix.sizeimage =
++		f->fmt.pix.height * f->fmt.pix.bytesperline;
 +
-+	/* Device has IR hardware that can be faked into looking like a
-+	   normal Hauppauge i2c IR receiver.  This is currently very
-+	   specific to the 24xxx device, where Hauppauge had replaced their
-+	   'standard' I2C IR receiver with a bunch of FPGA logic controlled
-+	   directly via the FX2.  Turning this on tells the pvrusb2 driver
-+	   to virtualize the presence of the non-existant IR receiver chip and
-+	   implement the virtual receiver in terms of appropriate FX2
-+	   commands. */
-+	char flag_has_hauppauge_custom_ir;
-+};
++	return 0;
+ }
+ 
+-static int saa7134_s_fmt(struct saa7134_dev *dev, struct saa7134_fh *fh,
+-			 struct v4l2_format *f)
++static int saa7134_try_fmt_overlay(struct file *file, void *priv,
++						struct v4l2_format *f)
+ {
+-	unsigned long flags;
+-	int err;
+-
+-	switch (f->type) {
+-	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+-		err = saa7134_try_fmt(dev,fh,f);
+-		if (0 != err)
+-			return err;
+-
+-		fh->fmt       = format_by_fourcc(f->fmt.pix.pixelformat);
+-		fh->width     = f->fmt.pix.width;
+-		fh->height    = f->fmt.pix.height;
+-		fh->cap.field = f->fmt.pix.field;
+-		return 0;
+-	case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+-		if (saa7134_no_overlay > 0) {
+-			printk ("V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
+-			return -EINVAL;
+-		}
+-		err = verify_preview(dev,&f->fmt.win);
+-		if (0 != err)
+-			return err;
+-
+-		mutex_lock(&dev->lock);
+-		fh->win    = f->fmt.win;
+-		fh->nclips = f->fmt.win.clipcount;
+-		if (fh->nclips > 8)
+-			fh->nclips = 8;
+-		if (copy_from_user(fh->clips,f->fmt.win.clips,
+-				   sizeof(struct v4l2_clip)*fh->nclips)) {
+-			mutex_unlock(&dev->lock);
+-			return -EFAULT;
+-		}
++	struct saa7134_fh *fh = priv;
++	struct saa7134_dev *dev = fh->dev;
+ 
+-		if (res_check(fh, RESOURCE_OVERLAY)) {
+-			spin_lock_irqsave(&dev->slock,flags);
+-			stop_preview(dev,fh);
+-			start_preview(dev,fh);
+-			spin_unlock_irqrestore(&dev->slock,flags);
+-		}
+-		mutex_unlock(&dev->lock);
+-		return 0;
+-	case V4L2_BUF_TYPE_VBI_CAPTURE:
+-		saa7134_vbi_fmt(dev,f);
+-		return 0;
+-	default:
++	if (saa7134_no_overlay > 0) {
++		printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
+ 		return -EINVAL;
+ 	}
 +
-+extern struct usb_device_id pvr2_device_table[];
++	return verify_preview(dev, &f->fmt.win);
+ }
+ 
+-int saa7134_common_ioctl(struct saa7134_dev *dev,
+-			 unsigned int cmd, void *arg)
++static int saa7134_s_fmt_cap(struct file *file, void *priv,
++					struct v4l2_format *f)
+ {
++	struct saa7134_fh *fh = priv;
+ 	int err;
+ 
+-	switch (cmd) {
+-	case VIDIOC_QUERYCTRL:
+-	{
+-		const struct v4l2_queryctrl *ctrl;
+-		struct v4l2_queryctrl *c = arg;
++	err = saa7134_try_fmt_cap(file, priv, f);
++	if (0 != err)
++		return err;
+ 
+-		if ((c->id <  V4L2_CID_BASE ||
+-		     c->id >= V4L2_CID_LASTP1) &&
+-		    (c->id <  V4L2_CID_PRIVATE_BASE ||
+-		     c->id >= V4L2_CID_PRIVATE_LASTP1))
+-			return -EINVAL;
+-		ctrl = ctrl_by_id(c->id);
+-		*c = (NULL != ctrl) ? *ctrl : no_ctrl;
+-		return 0;
++	fh->fmt       = format_by_fourcc(f->fmt.pix.pixelformat);
++	fh->width     = f->fmt.pix.width;
++	fh->height    = f->fmt.pix.height;
++	fh->cap.field = f->fmt.pix.field;
++	return 0;
++}
 +
-+#endif /* __PVRUSB2_HDW_INTERNAL_H */
++static int saa7134_s_fmt_overlay(struct file *file, void *priv,
++					struct v4l2_format *f)
++{
++	struct saa7134_fh *fh = priv;
++	struct saa7134_dev *dev = fh->dev;
++	int err;
++	unsigned int flags;
 +
-+/*
-+  Stuff for Emacs to see, in order to encourage consistent editing style:
-+  *** Local Variables: ***
-+  *** mode: c ***
-+  *** fill-column: 75 ***
-+  *** tab-width: 8 ***
-+  *** c-basic-offset: 8 ***
-+  *** End: ***
-+  */
-diff --git a/drivers/media/video/pvrusb2/pvrusb2-eeprom.c b/drivers/media/video/pvrusb2/pvrusb2-eeprom.c
-index 45cbca0..5ef0059 100644
---- a/drivers/media/video/pvrusb2/pvrusb2-eeprom.c
-+++ b/drivers/media/video/pvrusb2/pvrusb2-eeprom.c
-@@ -144,6 +144,7 @@ int pvr2_eeprom_analyze(struct pvr2_hdw *hdw)
- 	trace_eeprom("serial_number=%d",tvdata.serial_number);
- 	trace_eeprom("rev_str=%s",tvdata.rev_str);
- 	hdw->tuner_type = tvdata.tuner_type;
-+	hdw->tuner_updated = !0;
- 	hdw->serial_number = tvdata.serial_number;
- 	hdw->std_mask_eeprom = tvdata.tuner_formats;
- 
-diff --git a/drivers/media/video/pvrusb2/pvrusb2-encoder.c b/drivers/media/video/pvrusb2/pvrusb2-encoder.c
-index 205087a..6406287 100644
---- a/drivers/media/video/pvrusb2/pvrusb2-encoder.c
-+++ b/drivers/media/video/pvrusb2/pvrusb2-encoder.c
-@@ -140,7 +140,7 @@ static int pvr2_encoder_read_words(struct pvr2_hdw *hdw,
-    cx2341x.ko to write to our encoder (by handing it a pointer to this
-    function).  For earlier kernels this doesn't really matter. */
- static int pvr2_encoder_cmd(void *ctxt,
--			    int cmd,
-+			    u32 cmd,
- 			    int arg_cnt_send,
- 			    int arg_cnt_recv,
- 			    u32 *argp)
-@@ -209,7 +209,7 @@ static int pvr2_encoder_cmd(void *ctxt,
++	if (saa7134_no_overlay > 0) {
++		printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
++		return -EINVAL;
+ 	}
+-	case VIDIOC_G_CTRL:
+-		return get_control(dev,arg);
+-	case VIDIOC_S_CTRL:
+-	{
+-		mutex_lock(&dev->lock);
+-		err = set_control(dev,NULL,arg);
+-		mutex_unlock(&dev->lock);
++	err = verify_preview(dev, &f->fmt.win);
++	if (0 != err)
+ 		return err;
+-	}
+-	/* --- input switching --------------------------------------- */
+-	case VIDIOC_ENUMINPUT:
+-	{
+-		struct v4l2_input *i = arg;
+-		unsigned int n;
  
- 	LOCK_TAKE(hdw->ctl_lock); do {
+-		n = i->index;
+-		if (n >= SAA7134_INPUT_MAX)
+-			return -EINVAL;
+-		if (NULL == card_in(dev,i->index).name)
+-			return -EINVAL;
+-		memset(i,0,sizeof(*i));
+-		i->index = n;
+-		i->type  = V4L2_INPUT_TYPE_CAMERA;
+-		strcpy(i->name,card_in(dev,n).name);
+-		if (card_in(dev,n).tv)
+-			i->type = V4L2_INPUT_TYPE_TUNER;
+-		i->audioset = 1;
+-		if (n == dev->ctl_input) {
+-			int v1 = saa_readb(SAA7134_STATUS_VIDEO1);
+-			int v2 = saa_readb(SAA7134_STATUS_VIDEO2);
+-
+-			if (0 != (v1 & 0x40))
+-				i->status |= V4L2_IN_ST_NO_H_LOCK;
+-			if (0 != (v2 & 0x40))
+-				i->status |= V4L2_IN_ST_NO_SYNC;
+-			if (0 != (v2 & 0x0e))
+-				i->status |= V4L2_IN_ST_MACROVISION;
+-		}
+-		for (n = 0; n < TVNORMS; n++)
+-			i->std |= tvnorms[n].id;
+-		return 0;
+-	}
+-	case VIDIOC_G_INPUT:
+-	{
+-		int *i = arg;
+-		*i = dev->ctl_input;
+-		return 0;
+-	}
+-	case VIDIOC_S_INPUT:
+-	{
+-		int *i = arg;
++	mutex_lock(&dev->lock);
  
--		if (!hdw->flag_encoder_ok) {
-+		if (!hdw->state_encoder_ok) {
- 			ret = -EIO;
- 			break;
- 		}
-@@ -278,12 +278,15 @@ static int pvr2_encoder_cmd(void *ctxt,
- 			ret = -EBUSY;
- 		}
- 		if (ret) {
--			hdw->flag_encoder_ok = 0;
-+			hdw->state_encoder_ok = 0;
-+			pvr2_trace(PVR2_TRACE_STBITS,
-+				   "State bit %s <-- %s",
-+				   "state_encoder_ok",
-+				   (hdw->state_encoder_ok ? "true" : "false"));
- 			pvr2_trace(
- 				PVR2_TRACE_ERROR_LEGS,
- 				"Giving up on command."
--				"  It is likely that"
--				" this is a bad idea...");
-+				"  This is normally recovered by the driver.");
- 			break;
- 		}
- 		wrData[0] = 0x7;
-@@ -366,13 +369,13 @@ static int pvr2_encoder_prep_config(struct pvr2_hdw *hdw)
+-		if (*i < 0  ||  *i >= SAA7134_INPUT_MAX)
+-			return -EINVAL;
+-		if (NULL == card_in(dev,*i).name)
+-			return -EINVAL;
+-		mutex_lock(&dev->lock);
+-		video_mux(dev,*i);
++	fh->win    = f->fmt.win;
++	fh->nclips = f->fmt.win.clipcount;
++
++	if (fh->nclips > 8)
++		fh->nclips = 8;
++
++	if (copy_from_user(fh->clips, f->fmt.win.clips,
++			   sizeof(struct v4l2_clip)*fh->nclips)) {
+ 		mutex_unlock(&dev->lock);
+-		return 0;
++		return -EFAULT;
+ 	}
  
- 	/* This ENC_MISC(3,encMisc3Arg) command is critical - without
- 	   it there will eventually be video corruption.  Also, the
--	   29xxx case is strange - the Windows driver is passing 1
--	   regardless of device type but if we have 1 for 29xxx device
--	   the video turns sluggish.  */
--	switch (hdw->hdw_type) {
--	case PVR2_HDW_TYPE_24XXX: encMisc3Arg = 1; break;
--	case PVR2_HDW_TYPE_29XXX: encMisc3Arg = 0; break;
--	default: break;
-+	   saa7115 case is strange - the Windows driver is passing 1
-+	   regardless of device type but if we have 1 for saa7115
-+	   devices the video turns sluggish.  */
-+	if (hdw->hdw_desc->flag_has_cx25840) {
-+		encMisc3Arg = 1;
-+	} else {
-+		encMisc3Arg = 0;
++	if (res_check(fh, RESOURCE_OVERLAY)) {
++		spin_lock_irqsave(&dev->slock, flags);
++		stop_preview(dev, fh);
++		start_preview(dev, fh);
++		spin_unlock_irqrestore(&dev->slock, flags);
  	}
- 	ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_MISC,4, 3,
- 				 encMisc3Arg,0,0);
-@@ -394,6 +397,24 @@ static int pvr2_encoder_prep_config(struct pvr2_hdw *hdw)
- 	return ret;
++
++	mutex_unlock(&dev->lock);
+ 	return 0;
  }
+-EXPORT_SYMBOL(saa7134_common_ioctl);
  
-+int pvr2_encoder_adjust(struct pvr2_hdw *hdw)
-+{
-+	int ret;
-+	ret = cx2341x_update(hdw,pvr2_encoder_cmd,
-+			     (hdw->enc_cur_valid ? &hdw->enc_cur_state : NULL),
-+			     &hdw->enc_ctl_state);
-+	if (ret) {
-+		pvr2_trace(PVR2_TRACE_ERROR_LEGS,
-+			   "Error from cx2341x module code=%d",ret);
-+	} else {
-+		memcpy(&hdw->enc_cur_state,&hdw->enc_ctl_state,
-+		       sizeof(struct cx2341x_mpeg_params));
-+		hdw->enc_cur_valid = !0;
+-/*
+- * This function is _not_ called directly, but from
+- * video_generic_ioctl (and maybe others).  userspace
+- * copying is done already, arg is a kernel pointer.
+- */
+-static int video_do_ioctl(struct inode *inode, struct file *file,
+-			  unsigned int cmd, void *arg)
++int saa7134_queryctrl(struct file *file, void *priv, struct v4l2_queryctrl *c)
+ {
+-	struct saa7134_fh *fh = file->private_data;
++	const struct v4l2_queryctrl *ctrl;
++
++	if ((c->id <  V4L2_CID_BASE ||
++	     c->id >= V4L2_CID_LASTP1) &&
++	    (c->id <  V4L2_CID_PRIVATE_BASE ||
++	     c->id >= V4L2_CID_PRIVATE_LASTP1))
++		return -EINVAL;
++	ctrl = ctrl_by_id(c->id);
++	*c = (NULL != ctrl) ? *ctrl : no_ctrl;
++	return 0;
++}
++EXPORT_SYMBOL_GPL(saa7134_queryctrl);
++
++static int saa7134_enum_input(struct file *file, void *priv,
++					struct v4l2_input *i)
++{
++	struct saa7134_fh *fh = priv;
++	struct saa7134_dev *dev = fh->dev;
++	unsigned int n;
++
++	n = i->index;
++	if (n >= SAA7134_INPUT_MAX)
++		return -EINVAL;
++	if (NULL == card_in(dev, i->index).name)
++		return -EINVAL;
++	memset(i, 0, sizeof(*i));
++	i->index = n;
++	i->type  = V4L2_INPUT_TYPE_CAMERA;
++	strcpy(i->name, card_in(dev, n).name);
++	if (card_in(dev, n).tv)
++		i->type = V4L2_INPUT_TYPE_TUNER;
++	i->audioset = 1;
++	if (n == dev->ctl_input) {
++		int v1 = saa_readb(SAA7134_STATUS_VIDEO1);
++		int v2 = saa_readb(SAA7134_STATUS_VIDEO2);
++
++		if (0 != (v1 & 0x40))
++			i->status |= V4L2_IN_ST_NO_H_LOCK;
++		if (0 != (v2 & 0x40))
++			i->status |= V4L2_IN_ST_NO_SYNC;
++		if (0 != (v2 & 0x0e))
++			i->status |= V4L2_IN_ST_MACROVISION;
 +	}
-+	return ret;
++	i->std = SAA7134_NORMS;
++	return 0;
 +}
 +
++static int saa7134_g_input(struct file *file, void *priv, unsigned int *i)
++{
++	struct saa7134_fh *fh = priv;
++	struct saa7134_dev *dev = fh->dev;
++
++	*i = dev->ctl_input;
++	return 0;
++}
 +
- int pvr2_encoder_configure(struct pvr2_hdw *hdw)
- {
- 	int ret;
-@@ -412,7 +433,7 @@ int pvr2_encoder_configure(struct pvr2_hdw *hdw)
- 
- 	/* saa7115: 0xf0 */
- 	val = 0xf0;
--	if (hdw->hdw_type == PVR2_HDW_TYPE_24XXX) {
-+	if (hdw->hdw_desc->flag_has_cx25840) {
- 		/* ivtv cx25840: 0x140 */
- 		val = 0x140;
- 	}
-@@ -436,18 +457,10 @@ int pvr2_encoder_configure(struct pvr2_hdw *hdw)
- 		return ret;
- 	}
++static int saa7134_s_input(struct file *file, void *priv, unsigned int i)
++{
++	struct saa7134_fh *fh = priv;
+ 	struct saa7134_dev *dev = fh->dev;
+-	unsigned long flags;
+ 	int err;
  
--	ret = cx2341x_update(hdw,pvr2_encoder_cmd,
--			     (hdw->enc_cur_valid ? &hdw->enc_cur_state : NULL),
--			     &hdw->enc_ctl_state);
--	if (ret) {
--		pvr2_trace(PVR2_TRACE_ERROR_LEGS,
--			   "Error from cx2341x module code=%d",ret);
--		return ret;
+-	if (video_debug > 1)
+-		v4l_print_ioctl(dev->name,cmd);
+-
+-	switch (cmd) {
+-	case VIDIOC_S_CTRL:
+-	case VIDIOC_S_STD:
+-	case VIDIOC_S_INPUT:
+-	case VIDIOC_S_TUNER:
+-	case VIDIOC_S_FREQUENCY:
+-		err = v4l2_prio_check(&dev->prio,&fh->prio);
+-		if (0 != err)
+-			return err;
 -	}
++	err = v4l2_prio_check(&dev->prio, &fh->prio);
++	if (0 != err)
++		return err;
+ 
+-	switch (cmd) {
+-	case VIDIOC_QUERYCAP:
+-	{
+-		struct v4l2_capability *cap = arg;
+-		unsigned int tuner_type = dev->tuner_type;
 -
--	ret = 0;
-+	ret = pvr2_encoder_adjust(hdw);
-+	if (ret) return ret;
+-		memset(cap,0,sizeof(*cap));
+-		strcpy(cap->driver, "saa7134");
+-		strlcpy(cap->card, saa7134_boards[dev->board].name,
+-			sizeof(cap->card));
+-		sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci));
+-		cap->version = SAA7134_VERSION_CODE;
+-		cap->capabilities =
+-			V4L2_CAP_VIDEO_CAPTURE |
+-			V4L2_CAP_VBI_CAPTURE |
+-			V4L2_CAP_READWRITE |
+-			V4L2_CAP_STREAMING |
+-			V4L2_CAP_TUNER;
+-		if (saa7134_no_overlay <= 0) {
+-			cap->capabilities |= V4L2_CAP_VIDEO_OVERLAY;
+-		}
++	if (i < 0  ||  i >= SAA7134_INPUT_MAX)
++		return -EINVAL;
++	if (NULL == card_in(dev, i).name)
++		return -EINVAL;
++	mutex_lock(&dev->lock);
++	video_mux(dev, i);
++	mutex_unlock(&dev->lock);
++	return 0;
++}
  
--	if (!ret) ret = pvr2_encoder_vcmd(
-+	ret = pvr2_encoder_vcmd(
- 		hdw, CX2341X_ENC_INITIALIZE_INPUT, 0);
+-		if ((tuner_type == TUNER_ABSENT) || (tuner_type == UNSET))
+-			cap->capabilities &= ~V4L2_CAP_TUNER;
++static int saa7134_querycap(struct file *file, void  *priv,
++					struct v4l2_capability *cap)
++{
++	struct saa7134_fh *fh = priv;
++	struct saa7134_dev *dev = fh->dev;
  
- 	if (ret) {
-@@ -456,10 +469,6 @@ int pvr2_encoder_configure(struct pvr2_hdw *hdw)
- 		return ret;
- 	}
++	unsigned int tuner_type = dev->tuner_type;
++
++	strcpy(cap->driver, "saa7134");
++	strlcpy(cap->card, saa7134_boards[dev->board].name,
++		sizeof(cap->card));
++	sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci));
++	cap->version = SAA7134_VERSION_CODE;
++	cap->capabilities =
++		V4L2_CAP_VIDEO_CAPTURE |
++		V4L2_CAP_VBI_CAPTURE |
++		V4L2_CAP_READWRITE |
++		V4L2_CAP_STREAMING |
++		V4L2_CAP_TUNER;
++	if (saa7134_no_overlay <= 0)
++		cap->capabilities |= V4L2_CAP_VIDEO_OVERLAY;
++
++	if ((tuner_type == TUNER_ABSENT) || (tuner_type == UNSET))
++		cap->capabilities &= ~V4L2_CAP_TUNER;
+ 		return 0;
+-	}
++}
  
--	hdw->subsys_enabled_mask |= (1<<PVR2_SUBSYS_B_ENC_CFG);
--	memcpy(&hdw->enc_cur_state,&hdw->enc_ctl_state,
--	       sizeof(struct cx2341x_mpeg_params));
--	hdw->enc_cur_valid = !0;
- 	return 0;
- }
+-	/* --- tv standards ------------------------------------------ */
+-	case VIDIOC_ENUMSTD:
+-	{
+-		struct v4l2_standard *e = arg;
+-		unsigned int i;
++static int saa7134_s_std(struct file *file, void *priv, 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;
  
-@@ -478,7 +487,7 @@ int pvr2_encoder_start(struct pvr2_hdw *hdw)
- 	pvr2_encoder_vcmd(hdw,CX2341X_ENC_MUTE_VIDEO,1,
- 			  hdw->input_val == PVR2_CVAL_INPUT_RADIO ? 1 : 0);
+-		i = e->index;
+-		if (i >= TVNORMS)
+-			return -EINVAL;
+-		err = v4l2_video_std_construct(e, tvnorms[e->index].id,
+-					       tvnorms[e->index].name);
+-		e->index = i;
+-		if (err < 0)
+-			return err;
+-		return 0;
+-	}
+-	case VIDIOC_G_STD:
+-	{
+-		v4l2_std_id *id = arg;
++	err = v4l2_prio_check(&dev->prio, &fh->prio);
++	if (0 != err)
++		return err;
  
--	switch (hdw->config) {
-+	switch (hdw->active_stream_type) {
- 	case pvr2_config_vbi:
- 		status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_START_CAPTURE,2,
- 					   0x01,0x14);
-@@ -492,9 +501,6 @@ int pvr2_encoder_start(struct pvr2_hdw *hdw)
- 					   0,0x13);
- 		break;
- 	}
--	if (!status) {
--		hdw->subsys_enabled_mask |= (1<<PVR2_SUBSYS_B_ENC_RUN);
+-		*id = dev->tvnorm->id;
+-		return 0;
 -	}
- 	return status;
- }
+-	case VIDIOC_S_STD:
+-	{
+-		v4l2_std_id *id = arg;
+-		unsigned int i;
+-		v4l2_std_id fixup;
++	for (i = 0; i < TVNORMS; i++)
++		if (*id == tvnorms[i].id)
++			break;
  
-@@ -505,7 +511,7 @@ int pvr2_encoder_stop(struct pvr2_hdw *hdw)
- 	/* mask all interrupts */
- 	pvr2_write_register(hdw, 0x0048, 0xffffffff);
++	if (i == TVNORMS)
+ 		for (i = 0; i < TVNORMS; i++)
+-			if (*id == tvnorms[i].id)
++			if (*id & tvnorms[i].id)
+ 				break;
+-		if (i == TVNORMS)
+-			for (i = 0; i < TVNORMS; i++)
+-				if (*id & tvnorms[i].id)
+-					break;
+-		if (i == TVNORMS)
+-			return -EINVAL;
+-		if ((*id & V4L2_STD_SECAM) && (secam[0] != '-')) {
+-			if (secam[0] == 'L' || secam[0] == 'l') {
+-				if (secam[1] == 'C' || secam[1] == 'c')
+-					fixup = V4L2_STD_SECAM_LC;
+-				else
+-					fixup = V4L2_STD_SECAM_L;
+-			} else {
+-				if (secam[0] == 'D' || secam[0] == 'd')
+-					fixup = V4L2_STD_SECAM_DK;
+-				else
+-					fixup = V4L2_STD_SECAM;
+-			}
+-			for (i = 0; i < TVNORMS; i++)
+-				if (fixup == tvnorms[i].id)
+-					break;
++	if (i == TVNORMS)
++		return -EINVAL;
++
++	if ((*id & V4L2_STD_SECAM) && (secam[0] != '-')) {
++		if (secam[0] == 'L' || secam[0] == 'l') {
++			if (secam[1] == 'C' || secam[1] == 'c')
++				fixup = V4L2_STD_SECAM_LC;
++			else
++				fixup = V4L2_STD_SECAM_L;
++		} else {
++			if (secam[0] == 'D' || secam[0] == 'd')
++				fixup = V4L2_STD_SECAM_DK;
++			else
++				fixup = V4L2_STD_SECAM;
+ 		}
+-		mutex_lock(&dev->lock);
+-		if (res_check(fh, RESOURCE_OVERLAY)) {
+-			spin_lock_irqsave(&dev->slock,flags);
+-			stop_preview(dev,fh);
+-			spin_unlock_irqrestore(&dev->slock, flags);
+-
+-			set_tvnorm(dev,&tvnorms[i]);
+-
+-			spin_lock_irqsave(&dev->slock, flags);
+-			start_preview(dev,fh);
+-			spin_unlock_irqrestore(&dev->slock,flags);
+-		} else
+-			set_tvnorm(dev,&tvnorms[i]);
+-		saa7134_tvaudio_do_scan(dev);
+-		mutex_unlock(&dev->lock);
+-		return 0;
++		for (i = 0; i < TVNORMS; i++)
++			if (fixup == tvnorms[i].id)
++				break;
+ 	}
  
--	switch (hdw->config) {
-+	switch (hdw->active_stream_type) {
- 	case pvr2_config_vbi:
- 		status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_STOP_CAPTURE,3,
- 					   0x01,0x01,0x14);
-@@ -526,9 +532,6 @@ int pvr2_encoder_stop(struct pvr2_hdw *hdw)
- 	pvr2_hdw_gpio_chg_dir(hdw,0xffffffff,0x00000401);
- 	pvr2_hdw_gpio_chg_out(hdw,0xffffffff,0x00000000);
+-	case VIDIOC_CROPCAP:
+-	{
+-		struct v4l2_cropcap *cap = arg;
++	*id = tvnorms[i].id;
  
--	if (!status) {
--		hdw->subsys_enabled_mask &= ~(1<<PVR2_SUBSYS_B_ENC_RUN);
+-		if (cap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+-		    cap->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
+-			return -EINVAL;
+-		cap->bounds  = dev->crop_bounds;
+-		cap->defrect = dev->crop_defrect;
+-		cap->pixelaspect.numerator   = 1;
+-		cap->pixelaspect.denominator = 1;
+-		if (dev->tvnorm->id & V4L2_STD_525_60) {
+-			cap->pixelaspect.numerator   = 11;
+-			cap->pixelaspect.denominator = 10;
+-		}
+-		if (dev->tvnorm->id & V4L2_STD_625_50) {
+-			cap->pixelaspect.numerator   = 54;
+-			cap->pixelaspect.denominator = 59;
+-		}
+-		return 0;
 -	}
- 	return status;
- }
- 
-diff --git a/drivers/media/video/pvrusb2/pvrusb2-encoder.h b/drivers/media/video/pvrusb2/pvrusb2-encoder.h
-index 01b5a0b..54caf2e 100644
---- a/drivers/media/video/pvrusb2/pvrusb2-encoder.h
-+++ b/drivers/media/video/pvrusb2/pvrusb2-encoder.h
-@@ -25,6 +25,7 @@
++	mutex_lock(&dev->lock);
++	if (res_check(fh, RESOURCE_OVERLAY)) {
++		spin_lock_irqsave(&dev->slock, flags);
++		stop_preview(dev, fh);
++		spin_unlock_irqrestore(&dev->slock, flags);
  
- struct pvr2_hdw;
+-	case VIDIOC_G_CROP:
+-	{
+-		struct v4l2_crop * crop = arg;
++		set_tvnorm(dev, &tvnorms[i]);
  
-+int pvr2_encoder_adjust(struct pvr2_hdw *);
- int pvr2_encoder_configure(struct pvr2_hdw *);
- int pvr2_encoder_start(struct pvr2_hdw *);
- int pvr2_encoder_stop(struct pvr2_hdw *);
-diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
-index f873994..d7a216b 100644
---- a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
-+++ b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
-@@ -35,10 +35,12 @@
+-		if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+-		    crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
+-			return -EINVAL;
+-		crop->c = dev->crop_current;
+-		return 0;
+-	}
+-	case VIDIOC_S_CROP:
+-	{
+-		struct v4l2_crop *crop = arg;
+-		struct v4l2_rect *b = &dev->crop_bounds;
++		spin_lock_irqsave(&dev->slock, flags);
++		start_preview(dev, fh);
++		spin_unlock_irqrestore(&dev->slock, flags);
++	} else
++		set_tvnorm(dev, &tvnorms[i]);
  
- #include <linux/videodev2.h>
- #include <linux/i2c.h>
-+#include <linux/workqueue.h>
- #include <linux/mutex.h>
- #include "pvrusb2-hdw.h"
- #include "pvrusb2-io.h"
- #include <media/cx2341x.h>
-+#include "pvrusb2-devattr.h"
+-		if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+-		    crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
+-			return -EINVAL;
+-		if (crop->c.height < 0)
+-			return -EINVAL;
+-		if (crop->c.width < 0)
+-			return -EINVAL;
++	saa7134_tvaudio_do_scan(dev);
++	mutex_unlock(&dev->lock);
++	return 0;
++}
  
- /* Legal values for PVR2_CID_HSM */
- #define PVR2_CVAL_HSM_FAIL 0
-@@ -161,10 +163,6 @@ struct pvr2_decoder_ctrl {
- #define FW1_STATE_RELOAD 3
- #define FW1_STATE_OK 4
+-		if (res_locked(fh->dev,RESOURCE_OVERLAY))
+-			return -EBUSY;
+-		if (res_locked(fh->dev,RESOURCE_VIDEO))
+-			return -EBUSY;
++static int saa7134_cropcap(struct file *file, void *priv,
++					struct v4l2_cropcap *cap)
++{
++	struct saa7134_fh *fh = priv;
++	struct saa7134_dev *dev = fh->dev;
  
--/* Known major hardware variants, keyed from device ID */
--#define PVR2_HDW_TYPE_29XXX 0
--#define PVR2_HDW_TYPE_24XXX 1
+-		if (crop->c.top < b->top)
+-			crop->c.top = b->top;
+-		if (crop->c.top > b->top + b->height)
+-			crop->c.top = b->top + b->height;
+-		if (crop->c.height > b->top - crop->c.top + b->height)
+-			crop->c.height = b->top - crop->c.top + b->height;
 -
- typedef int (*pvr2_i2c_func)(struct pvr2_hdw *,u8,u8 *,u16,u8 *, u16);
- #define PVR2_I2C_FUNC_CNT 128
- 
-@@ -176,8 +174,15 @@ struct pvr2_hdw {
- 	struct usb_device *usb_dev;
- 	struct usb_interface *usb_intf;
+-		if (crop->c.left < b->left)
+-			crop->c.left = b->left;
+-		if (crop->c.left > b->left + b->width)
+-			crop->c.left = b->left + b->width;
+-		if (crop->c.width > b->left - crop->c.left + b->width)
+-			crop->c.width = b->left - crop->c.left + b->width;
+-
+-		dev->crop_current = crop->c;
+-		return 0;
++	if (cap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
++	    cap->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
++		return -EINVAL;
++	cap->bounds  = dev->crop_bounds;
++	cap->defrect = dev->crop_defrect;
++	cap->pixelaspect.numerator   = 1;
++	cap->pixelaspect.denominator = 1;
++	if (dev->tvnorm->id & V4L2_STD_525_60) {
++		cap->pixelaspect.numerator   = 11;
++		cap->pixelaspect.denominator = 10;
++	}
++	if (dev->tvnorm->id & V4L2_STD_625_50) {
++		cap->pixelaspect.numerator   = 54;
++		cap->pixelaspect.denominator = 59;
+ 	}
++	return 0;
++}
  
--	/* Device type, one of PVR2_HDW_TYPE_xxxxx */
--	unsigned int hdw_type;
-+	/* Device description, anything that must adjust behavior based on
-+	   device specific info will use information held here. */
-+	const struct pvr2_device_desc *hdw_desc;
-+
-+	/* Kernel worker thread handling */
-+	struct workqueue_struct *workqueue;
-+	struct work_struct workpoll;     /* Update driver state */
-+	struct work_struct worki2csync;  /* Update i2c clients */
-+	struct work_struct workinit;     /* Driver initialization sequence */
+-	/* --- tuner ioctls ------------------------------------------ */
+-	case VIDIOC_G_TUNER:
+-	{
+-		struct v4l2_tuner *t = arg;
+-		int n;
++static int saa7134_g_crop(struct file *file, void *f, struct v4l2_crop *crop)
++{
++	struct saa7134_fh *fh = f;
++	struct saa7134_dev *dev = fh->dev;
  
- 	/* Video spigot */
- 	struct pvr2_stream *vid_stream;
-@@ -186,9 +191,6 @@ struct pvr2_hdw {
- 	struct mutex big_lock_mutex;
- 	int big_lock_held;  /* For debugging */
+-		if (0 != t->index)
+-			return -EINVAL;
+-		memset(t,0,sizeof(*t));
+-		for (n = 0; n < SAA7134_INPUT_MAX; n++)
+-			if (card_in(dev,n).tv)
+-				break;
+-		if (NULL != card_in(dev,n).name) {
+-			strcpy(t->name, "Television");
+-			t->type = V4L2_TUNER_ANALOG_TV;
+-			t->capability = V4L2_TUNER_CAP_NORM |
+-				V4L2_TUNER_CAP_STEREO |
+-				V4L2_TUNER_CAP_LANG1 |
+-				V4L2_TUNER_CAP_LANG2;
+-			t->rangehigh = 0xffffffffUL;
+-			t->rxsubchans = saa7134_tvaudio_getstereo(dev);
+-			t->audmode = saa7134_tvaudio_rx2mode(t->rxsubchans);
+-		}
+-		if (0 != (saa_readb(SAA7134_STATUS_VIDEO1) & 0x03))
+-			t->signal = 0xffff;
+-		return 0;
+-	}
+-	case VIDIOC_S_TUNER:
+-	{
+-		struct v4l2_tuner *t = arg;
+-		int rx,mode;
++	if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
++	    crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
++		return -EINVAL;
++	crop->c = dev->crop_current;
++	return 0;
++}
  
--	void (*poll_trigger_func)(void *);
--	void *poll_trigger_data;
--
- 	char name[32];
+-		mode = dev->thread.mode;
+-		if (UNSET == mode) {
+-			rx   = saa7134_tvaudio_getstereo(dev);
+-			mode = saa7134_tvaudio_rx2mode(t->rxsubchans);
+-		}
+-		if (mode != t->audmode) {
+-			dev->thread.mode = t->audmode;
+-		}
+-		return 0;
+-	}
+-	case VIDIOC_G_FREQUENCY:
+-	{
+-		struct v4l2_frequency *f = arg;
++static int saa7134_s_crop(struct file *file, void *f, struct v4l2_crop *crop)
++{
++	struct saa7134_fh *fh = f;
++	struct saa7134_dev *dev = fh->dev;
++	struct v4l2_rect *b = &dev->crop_bounds;
  
- 	/* I2C stuff */
-@@ -215,9 +217,9 @@ struct pvr2_hdw {
- 	struct urb *ctl_read_urb;
- 	unsigned char *ctl_write_buffer;
- 	unsigned char *ctl_read_buffer;
--	volatile int ctl_write_pend_flag;
--	volatile int ctl_read_pend_flag;
--	volatile int ctl_timeout_flag;
-+	int ctl_write_pend_flag;
-+	int ctl_read_pend_flag;
-+	int ctl_timeout_flag;
- 	struct completion ctl_done;
- 	unsigned char cmd_buffer[PVR2_CTL_BUFFSIZE];
- 	int cmd_debug_state;               // Low level command debugging info
-@@ -225,14 +227,48 @@ struct pvr2_hdw {
- 	unsigned int cmd_debug_write_len;  //
- 	unsigned int cmd_debug_read_len;   //
+-		memset(f,0,sizeof(*f));
+-		f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
+-		f->frequency = dev->ctl_freq;
+-		return 0;
+-	}
+-	case VIDIOC_S_FREQUENCY:
+-	{
+-		struct v4l2_frequency *f = arg;
++	if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
++	    crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
++		return -EINVAL;
++	if (crop->c.height < 0)
++		return -EINVAL;
++	if (crop->c.width < 0)
++		return -EINVAL;
  
-+	/* Bits of state that describe what is going on with various parts
-+	   of the driver. */
-+	int state_encoder_ok;         /* Encoder is operational */
-+	int state_encoder_run;        /* Encoder is running */
-+	int state_encoder_config;     /* Encoder is configured */
-+	int state_encoder_waitok;     /* Encoder pre-wait done */
-+	int state_decoder_run;        /* Decoder is running */
-+	int state_usbstream_run;      /* FX2 is streaming */
-+	int state_decoder_quiescent;  /* Decoder idle for > 50msec */
-+	int state_pipeline_config;    /* Pipeline is configured */
-+	int state_pipeline_req;                /* Somebody wants to stream */
-+	int state_pipeline_pause;              /* Pipeline must be paused */
-+	int state_pipeline_idle;               /* Pipeline not running */
-+
-+	/* This is the master state of the driver.  It is the combined
-+	   result of other bits of state.  Examining this will indicate the
-+	   overall state of the driver.  Values here are one of
-+	   PVR2_STATE_xxxx */
-+	unsigned int master_state;
-+
-+	/* True if states must be re-evaluated */
-+	int state_stale;
-+
-+	void (*state_func)(void *);
-+	void *state_data;
-+
-+	/* Timer for measuring decoder settling time */
-+	struct timer_list quiescent_timer;
-+
-+	/* Timer for measuring encoder pre-wait time */
-+	struct timer_list encoder_wait_timer;
+-		if (0 != f->tuner)
+-			return -EINVAL;
+-		if (0 == fh->radio && V4L2_TUNER_ANALOG_TV != f->type)
+-			return -EINVAL;
+-		if (1 == fh->radio && V4L2_TUNER_RADIO != f->type)
+-			return -EINVAL;
+-		mutex_lock(&dev->lock);
+-		dev->ctl_freq = f->frequency;
++	if (res_locked(fh->dev, RESOURCE_OVERLAY))
++		return -EBUSY;
++	if (res_locked(fh->dev, RESOURCE_VIDEO))
++		return -EBUSY;
 +
-+	/* Place to block while waiting for state changes */
-+	wait_queue_head_t state_wait_data;
++	if (crop->c.top < b->top)
++		crop->c.top = b->top;
++	if (crop->c.top > b->top + b->height)
++		crop->c.top = b->top + b->height;
++	if (crop->c.height > b->top - crop->c.top + b->height)
++		crop->c.height = b->top - crop->c.top + b->height;
 +
++	if (crop->c.left < b->left)
++		crop->c.left = b->left;
++	if (crop->c.left > b->left + b->width)
++		crop->c.left = b->left + b->width;
++	if (crop->c.width > b->left - crop->c.left + b->width)
++		crop->c.width = b->left - crop->c.left + b->width;
 +
- 	int flag_ok;            /* device in known good state */
- 	int flag_disconnected;  /* flag_ok == 0 due to disconnect */
- 	int flag_init_ok;       /* true if structure is fully initialized */
--	int flag_streaming_enabled; /* true if streaming should be on */
- 	int fw1_state;          /* current situation with fw1 */
--	int flag_encoder_ok;    /* True if encoder is healthy */
--
--	int flag_decoder_is_tuned;
-+	int flag_decoder_missed;/* We've noticed missing decoder */
-+	int flag_tripped;       /* Indicates overall failure to start */
- 
- 	struct pvr2_decoder_ctrl *decoder_ctrl;
++	dev->crop_current = crop->c;
++	return 0;
++}
  
-@@ -241,12 +277,6 @@ struct pvr2_hdw {
- 	unsigned int fw_size;
- 	int fw_cpu_flag; /* True if we are dealing with the CPU */
+-		saa7134_i2c_call_clients(dev,VIDIOC_S_FREQUENCY,f);
++static int saa7134_g_tuner(struct file *file, void *priv,
++					struct v4l2_tuner *t)
++{
++	struct saa7134_fh *fh = priv;
++	struct saa7134_dev *dev = fh->dev;
++	int n;
  
--	// Which subsystem pieces have been enabled / configured
--	unsigned long subsys_enabled_mask;
--
--	// Which subsystems are manipulated to enable streaming
--	unsigned long subsys_stream_mask;
--
- 	// True if there is a request to trigger logging of state in each
- 	// module.
- 	int log_requested;
-@@ -296,13 +326,16 @@ struct pvr2_hdw {
- 	/* Location of eeprom or a negative number if none */
- 	int eeprom_addr;
+-		saa7134_tvaudio_do_scan(dev);
+-		mutex_unlock(&dev->lock);
+-		return 0;
+-	}
++	if (0 != t->index)
++		return -EINVAL;
++	memset(t, 0, sizeof(*t));
++	for (n = 0; n < SAA7134_INPUT_MAX; n++)
++		if (card_in(dev, n).tv)
++			break;
++	if (NULL != card_in(dev, n).name) {
++		strcpy(t->name, "Television");
++		t->type = V4L2_TUNER_ANALOG_TV;
++		t->capability = V4L2_TUNER_CAP_NORM |
++			V4L2_TUNER_CAP_STEREO |
++			V4L2_TUNER_CAP_LANG1 |
++			V4L2_TUNER_CAP_LANG2;
++		t->rangehigh = 0xffffffffUL;
++		t->rxsubchans = saa7134_tvaudio_getstereo(dev);
++		t->audmode = saa7134_tvaudio_rx2mode(t->rxsubchans);
++	}
++	if (0 != (saa_readb(SAA7134_STATUS_VIDEO1) & 0x03))
++		t->signal = 0xffff;
++	return 0;
++}
  
--	enum pvr2_config config;
-+	enum pvr2_config active_stream_type;
-+	enum pvr2_config desired_stream_type;
+-	/* --- control ioctls ---------------------------------------- */
+-	case VIDIOC_ENUMINPUT:
+-	case VIDIOC_G_INPUT:
+-	case VIDIOC_S_INPUT:
+-	case VIDIOC_QUERYCTRL:
+-	case VIDIOC_G_CTRL:
+-	case VIDIOC_S_CTRL:
+-		return saa7134_common_ioctl(dev, cmd, arg);
++static int saa7134_s_tuner(struct file *file, void *priv,
++					struct v4l2_tuner *t)
++{
++	struct saa7134_fh *fh = priv;
++	struct saa7134_dev *dev = fh->dev;
++	int rx, mode, err;
  
- 	/* Control state needed for cx2341x module */
- 	struct cx2341x_mpeg_params enc_cur_state;
- 	struct cx2341x_mpeg_params enc_ctl_state;
- 	/* True if an encoder attribute has changed */
- 	int enc_stale;
-+	/* True if an unsafe encoder attribute has changed */
-+	int enc_unsafe_stale;
- 	/* True if enc_cur_state is valid */
- 	int enc_cur_valid;
+-	case VIDIOC_G_AUDIO:
+-	{
+-		struct v4l2_audio *a = arg;
++	err = v4l2_prio_check(&dev->prio, &fh->prio);
++	if (0 != err)
++		return err;
  
-@@ -332,6 +365,7 @@ struct pvr2_hdw {
+-		memset(a,0,sizeof(*a));
+-		strcpy(a->name,"audio");
+-		return 0;
+-	}
+-	case VIDIOC_S_AUDIO:
+-		return 0;
+-	case VIDIOC_G_PARM:
+-	{
+-		struct v4l2_captureparm *parm = arg;
+-		memset(parm,0,sizeof(*parm));
+-		return 0;
++	mode = dev->thread.mode;
++	if (UNSET == mode) {
++		rx   = saa7134_tvaudio_getstereo(dev);
++		mode = saa7134_tvaudio_rx2mode(t->rxsubchans);
+ 	}
++	if (mode != t->audmode)
++		dev->thread.mode = t->audmode;
  
- /* This function gets the current frequency */
- unsigned long pvr2_hdw_get_cur_freq(struct pvr2_hdw *);
-+void pvr2_hdw_set_decoder(struct pvr2_hdw *,struct pvr2_decoder_ctrl *);
+-	case VIDIOC_G_PRIORITY:
+-	{
+-		enum v4l2_priority *p = arg;
++	return 0;
++}
  
- #endif /* __PVRUSB2_HDW_INTERNAL_H */
+-		*p = v4l2_prio_max(&dev->prio);
+-		return 0;
+-	}
+-	case VIDIOC_S_PRIORITY:
+-	{
+-		enum v4l2_priority *prio = arg;
++static int saa7134_g_frequency(struct file *file, void *priv,
++					struct v4l2_frequency *f)
++{
++	struct saa7134_fh *fh = priv;
++	struct saa7134_dev *dev = fh->dev;
  
-diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c
-index 402c594..41ae980 100644
---- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c
-+++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c
-@@ -41,47 +41,6 @@
- #define TV_MIN_FREQ     55250000L
- #define TV_MAX_FREQ    850000000L
+-		return v4l2_prio_change(&dev->prio, &fh->prio, *prio);
+-	}
++	f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
++	f->frequency = dev->ctl_freq;
  
--struct usb_device_id pvr2_device_table[] = {
--	[PVR2_HDW_TYPE_29XXX] = { USB_DEVICE(0x2040, 0x2900) },
--	[PVR2_HDW_TYPE_24XXX] = { USB_DEVICE(0x2040, 0x2400) },
--	{ }
--};
--
--MODULE_DEVICE_TABLE(usb, pvr2_device_table);
--
--static const char *pvr2_device_names[] = {
--	[PVR2_HDW_TYPE_29XXX] = "WinTV PVR USB2 Model Category 29xxxx",
--	[PVR2_HDW_TYPE_24XXX] = "WinTV PVR USB2 Model Category 24xxxx",
--};
--
--struct pvr2_string_table {
--	const char **lst;
--	unsigned int cnt;
--};
--
--// Names of other client modules to request for 24xxx model hardware
--static const char *pvr2_client_24xxx[] = {
--	"cx25840",
--	"tuner",
--	"wm8775",
--};
--
--// Names of other client modules to request for 29xxx model hardware
--static const char *pvr2_client_29xxx[] = {
--	"msp3400",
--	"saa7115",
--	"tuner",
--};
--
--static struct pvr2_string_table pvr2_client_lists[] = {
--	[PVR2_HDW_TYPE_29XXX] = {
--		pvr2_client_29xxx, ARRAY_SIZE(pvr2_client_29xxx)
--	},
--	[PVR2_HDW_TYPE_24XXX] = {
--		pvr2_client_24xxx, ARRAY_SIZE(pvr2_client_24xxx)
--	},
--};
+-	/* --- preview ioctls ---------------------------------------- */
+-	case VIDIOC_ENUM_FMT:
+-	{
+-		struct v4l2_fmtdesc *f = arg;
+-		enum v4l2_buf_type type;
+-		unsigned int index;
 -
- static struct pvr2_hdw *unit_pointers[PVR_NUM] = {[ 0 ... PVR_NUM-1 ] = NULL};
- static DEFINE_MUTEX(pvr2_unit_mtx);
+-		index = f->index;
+-		type  = f->type;
+-		switch (type) {
+-		case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+-		case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+-			if (saa7134_no_overlay > 0) {
+-				printk ("V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
+-				return -EINVAL;
+-			}
+-			if (index >= FORMATS)
+-				return -EINVAL;
+-			if (f->type == V4L2_BUF_TYPE_VIDEO_OVERLAY &&
+-			    formats[index].planar)
+-				return -EINVAL;
+-			memset(f,0,sizeof(*f));
+-			f->index = index;
+-			f->type  = type;
+-			strlcpy(f->description,formats[index].name,sizeof(f->description));
+-			f->pixelformat = formats[index].fourcc;
+-			break;
+-		case V4L2_BUF_TYPE_VBI_CAPTURE:
+-			if (0 != index)
+-				return -EINVAL;
+-			memset(f,0,sizeof(*f));
+-			f->index = index;
+-			f->type  = type;
+-			f->pixelformat = V4L2_PIX_FMT_GREY;
+-			strcpy(f->description,"vbi data");
+-			break;
+-		default:
+-			return -EINVAL;
+-		}
+-		return 0;
+-	}
+-	case VIDIOC_G_FBUF:
+-	{
+-		struct v4l2_framebuffer *fb = arg;
++	return 0;
++}
  
-@@ -246,32 +205,46 @@ static const char *control_values_hsm[] = {
- };
+-		*fb = dev->ovbuf;
+-		fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING;
+-		return 0;
+-	}
+-	case VIDIOC_S_FBUF:
+-	{
+-		struct v4l2_framebuffer *fb = arg;
+-		struct saa7134_format *fmt;
++static int saa7134_s_frequency(struct file *file, void *priv,
++					struct v4l2_frequency *f)
++{
++	struct saa7134_fh *fh = priv;
++	struct saa7134_dev *dev = fh->dev;
++	int err;
  
+-		if(!capable(CAP_SYS_ADMIN) &&
+-		   !capable(CAP_SYS_RAWIO))
+-			return -EPERM;
++	err = v4l2_prio_check(&dev->prio, &fh->prio);
++	if (0 != err)
++		return err;
  
--static const char *control_values_subsystem[] = {
--	[PVR2_SUBSYS_B_ENC_FIRMWARE]  = "enc_firmware",
--	[PVR2_SUBSYS_B_ENC_CFG] = "enc_config",
--	[PVR2_SUBSYS_B_DIGITIZER_RUN] = "digitizer_run",
--	[PVR2_SUBSYS_B_USBSTREAM_RUN] = "usbstream_run",
--	[PVR2_SUBSYS_B_ENC_RUN] = "enc_run",
-+static const char *pvr2_state_names[] = {
-+	[PVR2_STATE_NONE] =    "none",
-+	[PVR2_STATE_DEAD] =    "dead",
-+	[PVR2_STATE_COLD] =    "cold",
-+	[PVR2_STATE_WARM] =    "warm",
-+	[PVR2_STATE_ERROR] =   "error",
-+	[PVR2_STATE_READY] =   "ready",
-+	[PVR2_STATE_RUN] =     "run",
- };
+-		/* check args */
+-		fmt = format_by_fourcc(fb->fmt.pixelformat);
+-		if (NULL == fmt)
+-			return -EINVAL;
++	if (0 != f->tuner)
++		return -EINVAL;
++	if (0 == fh->radio && V4L2_TUNER_ANALOG_TV != f->type)
++		return -EINVAL;
++	if (1 == fh->radio && V4L2_TUNER_RADIO != f->type)
++		return -EINVAL;
++	mutex_lock(&dev->lock);
++	dev->ctl_freq = f->frequency;
  
+-		/* ok, accept it */
+-		dev->ovbuf = *fb;
+-		dev->ovfmt = fmt;
+-		if (0 == dev->ovbuf.fmt.bytesperline)
+-			dev->ovbuf.fmt.bytesperline =
+-				dev->ovbuf.fmt.width*fmt->depth/8;
+-		return 0;
++	saa7134_i2c_call_clients(dev, VIDIOC_S_FREQUENCY, f);
 +
-+static void pvr2_hdw_state_sched(struct pvr2_hdw *);
-+static int pvr2_hdw_state_eval(struct pvr2_hdw *);
- static void pvr2_hdw_set_cur_freq(struct pvr2_hdw *,unsigned long);
-+static void pvr2_hdw_worker_i2c(struct work_struct *work);
-+static void pvr2_hdw_worker_poll(struct work_struct *work);
-+static void pvr2_hdw_worker_init(struct work_struct *work);
-+static int pvr2_hdw_wait(struct pvr2_hdw *,int state);
-+static int pvr2_hdw_untrip_unlocked(struct pvr2_hdw *);
-+static void pvr2_hdw_state_log_state(struct pvr2_hdw *);
- static int pvr2_hdw_cmd_usbstream(struct pvr2_hdw *hdw,int runFl);
--static int pvr2_hdw_commit_ctl_internal(struct pvr2_hdw *hdw);
-+static int pvr2_hdw_commit_setup(struct pvr2_hdw *hdw);
- static int pvr2_hdw_get_eeprom_addr(struct pvr2_hdw *hdw);
- static void pvr2_hdw_internal_find_stdenum(struct pvr2_hdw *hdw);
- static void pvr2_hdw_internal_set_std_avail(struct pvr2_hdw *hdw);
--static void pvr2_hdw_render_useless_unlocked(struct pvr2_hdw *hdw);
--static void pvr2_hdw_subsys_bit_chg_no_lock(struct pvr2_hdw *hdw,
--					    unsigned long msk,
--					    unsigned long val);
--static void pvr2_hdw_subsys_stream_bit_chg_no_lock(struct pvr2_hdw *hdw,
--						   unsigned long msk,
--						   unsigned long val);
-+static void pvr2_hdw_quiescent_timeout(unsigned long);
-+static void pvr2_hdw_encoder_wait_timeout(unsigned long);
- static int pvr2_send_request_ex(struct pvr2_hdw *hdw,
- 				unsigned int timeout,int probe_fl,
- 				void *write_data,unsigned int write_len,
- 				void *read_data,unsigned int read_len);
++	saa7134_tvaudio_do_scan(dev);
++	mutex_unlock(&dev->lock);
++	return 0;
++}
++
++static int saa7134_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
++{
++	strcpy(a->name, "audio");
++	return 0;
++}
++
++static int saa7134_s_audio(struct file *file, void *priv, struct v4l2_audio *a)
++{
++	return 0;
++}
++
++static int saa7134_g_priority(struct file *file, void *f, enum v4l2_priority *p)
++{
++	struct saa7134_fh *fh = f;
++	struct saa7134_dev *dev = fh->dev;
++
++	*p = v4l2_prio_max(&dev->prio);
++	return 0;
++}
++
++static int saa7134_s_priority(struct file *file, void *f,
++					enum v4l2_priority prio)
++{
++	struct saa7134_fh *fh = f;
++	struct saa7134_dev *dev = fh->dev;
++
++	return v4l2_prio_change(&dev->prio, &fh->prio, prio);
++}
++
++static int saa7134_enum_fmt_cap(struct file *file, void  *priv,
++					struct v4l2_fmtdesc *f)
++{
++	if (f->index >= FORMATS)
++		return -EINVAL;
++
++	strlcpy(f->description, formats[f->index].name,
++		sizeof(f->description));
++
++	f->pixelformat = formats[f->index].fourcc;
++
++	return 0;
++}
++
++static int saa7134_enum_fmt_overlay(struct file *file, void  *priv,
++					struct v4l2_fmtdesc *f)
++{
++	if (saa7134_no_overlay > 0) {
++		printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
++		return -EINVAL;
+ 	}
+-	case VIDIOC_OVERLAY:
+-	{
+-		int *on = arg;
+ 
+-		if (*on) {
+-			if (saa7134_no_overlay > 0) {
+-				printk ("no_overlay\n");
+-				return -EINVAL;
+-			}
++	if ((f->index >= FORMATS) || formats[f->index].planar)
++		return -EINVAL;
  
+-			if (!res_get(dev,fh,RESOURCE_OVERLAY))
+-				return -EBUSY;
+-			spin_lock_irqsave(&dev->slock,flags);
+-			start_preview(dev,fh);
+-			spin_unlock_irqrestore(&dev->slock,flags);
+-		}
+-		if (!*on) {
+-			if (!res_check(fh, RESOURCE_OVERLAY))
+-				return -EINVAL;
+-			spin_lock_irqsave(&dev->slock,flags);
+-			stop_preview(dev,fh);
+-			spin_unlock_irqrestore(&dev->slock,flags);
+-			res_free(dev,fh,RESOURCE_OVERLAY);
++	strlcpy(f->description, formats[f->index].name,
++		sizeof(f->description));
++
++	f->pixelformat = formats[f->index].fourcc;
++
++	return 0;
++}
++
++static int saa7134_enum_fmt_vbi(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)
++{
++	struct saa7134_fh *fh = f;
++	struct saa7134_dev *dev = fh->dev;
++
++	*fb = dev->ovbuf;
++	fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING;
++
++	return 0;
++}
++
++static int saa7134_s_fbuf(struct file *file, void *f,
++					struct v4l2_framebuffer *fb)
++{
++	struct saa7134_fh *fh = f;
++	struct saa7134_dev *dev = fh->dev;
++	struct saa7134_format *fmt;
++
++	if (!capable(CAP_SYS_ADMIN) &&
++	   !capable(CAP_SYS_RAWIO))
++		return -EPERM;
 +
-+static void trace_stbit(const char *name,int val)
-+{
-+	pvr2_trace(PVR2_TRACE_STBITS,
-+		   "State bit %s <-- %s",
-+		   name,(val ? "true" : "false"));
-+}
++	/* check args */
++	fmt = format_by_fourcc(fb->fmt.pixelformat);
++	if (NULL == fmt)
++		return -EINVAL;
 +
- static int ctrl_channelfreq_get(struct pvr2_ctrl *cptr,int *vp)
- {
- 	struct pvr2_hdw *hdw = cptr->hdw;
-@@ -380,8 +353,8 @@ static int ctrl_vres_max_get(struct pvr2_ctrl *cptr,int *vp)
- 
- static int ctrl_vres_min_get(struct pvr2_ctrl *cptr,int *vp)
- {
--	/* Actual minimum depends on device type. */
--	if (cptr->hdw->hdw_type == PVR2_HDW_TYPE_24XXX) {
-+	/* Actual minimum depends on device digitizer type. */
-+	if (cptr->hdw->hdw_desc->flag_has_cx25840) {
- 		*vp = 75;
- 	} else {
- 		*vp = 17;
-@@ -480,6 +453,7 @@ static int ctrl_cx2341x_is_dirty(struct pvr2_ctrl *cptr)
- static void ctrl_cx2341x_clear_dirty(struct pvr2_ctrl *cptr)
- {
- 	cptr->hdw->enc_stale = 0;
-+	cptr->hdw->enc_unsafe_stale = 0;
- }
- 
- static int ctrl_cx2341x_get(struct pvr2_ctrl *cptr,int *vp)
-@@ -502,6 +476,7 @@ static int ctrl_cx2341x_get(struct pvr2_ctrl *cptr,int *vp)
- static int ctrl_cx2341x_set(struct pvr2_ctrl *cptr,int m,int v)
- {
- 	int ret;
-+	struct pvr2_hdw *hdw = cptr->hdw;
- 	struct v4l2_ext_controls cs;
- 	struct v4l2_ext_control c1;
- 	memset(&cs,0,sizeof(cs));
-@@ -510,10 +485,22 @@ static int ctrl_cx2341x_set(struct pvr2_ctrl *cptr,int m,int v)
- 	cs.count = 1;
- 	c1.id = cptr->info->v4l_id;
- 	c1.value = v;
--	ret = cx2341x_ext_ctrls(&cptr->hdw->enc_ctl_state, 0, &cs,
-+	ret = cx2341x_ext_ctrls(&hdw->enc_ctl_state,
-+				hdw->state_encoder_run, &cs,
- 				VIDIOC_S_EXT_CTRLS);
-+	if (ret == -EBUSY) {
-+		/* Oops.  cx2341x is telling us it's not safe to change
-+		   this control while we're capturing.  Make a note of this
-+		   fact so that the pipeline will be stopped the next time
-+		   controls are committed.  Then go on ahead and store this
-+		   change anyway. */
-+		ret = cx2341x_ext_ctrls(&hdw->enc_ctl_state,
-+					0, &cs,
-+					VIDIOC_S_EXT_CTRLS);
-+		if (!ret) hdw->enc_unsafe_stale = !0;
-+	}
- 	if (ret) return ret;
--	cptr->hdw->enc_stale = !0;
-+	hdw->enc_stale = !0;
- 	return 0;
- }
- 
-@@ -544,7 +531,13 @@ static unsigned int ctrl_cx2341x_getv4lflags(struct pvr2_ctrl *cptr)
- 
- static int ctrl_streamingenabled_get(struct pvr2_ctrl *cptr,int *vp)
- {
--	*vp = cptr->hdw->flag_streaming_enabled;
-+	*vp = cptr->hdw->state_pipeline_req;
++	/* ok, accept it */
++	dev->ovbuf = *fb;
++	dev->ovfmt = fmt;
++	if (0 == dev->ovbuf.fmt.bytesperline)
++		dev->ovbuf.fmt.bytesperline =
++			dev->ovbuf.fmt.width*fmt->depth/8;
 +	return 0;
 +}
 +
-+static int ctrl_masterstate_get(struct pvr2_ctrl *cptr,int *vp)
++static int saa7134_overlay(struct file *file, void *f, unsigned int on)
 +{
-+	*vp = cptr->hdw->master_state;
- 	return 0;
- }
- 
-@@ -657,29 +650,6 @@ static int ctrl_audio_modes_present_get(struct pvr2_ctrl *cptr,int *vp)
- 	return 0;
- }
- 
--static int ctrl_subsys_get(struct pvr2_ctrl *cptr,int *vp)
--{
--	*vp = cptr->hdw->subsys_enabled_mask;
--	return 0;
--}
--
--static int ctrl_subsys_set(struct pvr2_ctrl *cptr,int m,int v)
--{
--	pvr2_hdw_subsys_bit_chg_no_lock(cptr->hdw,m,v);
--	return 0;
--}
--
--static int ctrl_subsys_stream_get(struct pvr2_ctrl *cptr,int *vp)
--{
--	*vp = cptr->hdw->subsys_stream_mask;
--	return 0;
--}
--
--static int ctrl_subsys_stream_set(struct pvr2_ctrl *cptr,int m,int v)
--{
--	pvr2_hdw_subsys_stream_bit_chg_no_lock(cptr->hdw,m,v);
--	return 0;
--}
- 
- static int ctrl_stdenumcur_set(struct pvr2_ctrl *cptr,int m,int v)
- {
-@@ -915,6 +885,11 @@ static const struct pvr2_ctl_info control_defs[] = {
- 		.get_value = ctrl_hsm_get,
- 		DEFENUM(control_values_hsm),
- 	},{
-+		.desc = "Master State",
-+		.name = "master_state",
-+		.get_value = ctrl_masterstate_get,
-+		DEFENUM(pvr2_state_names),
-+	},{
- 		.desc = "Signal Present",
- 		.name = "signal_present",
- 		.get_value = ctrl_signal_get,
-@@ -955,20 +930,6 @@ static const struct pvr2_ctl_info control_defs[] = {
- 		.sym_to_val = ctrl_std_sym_to_val,
- 		.type = pvr2_ctl_bitmask,
- 	},{
--		.desc = "Subsystem enabled mask",
--		.name = "debug_subsys_mask",
--		.skip_init = !0,
--		.get_value = ctrl_subsys_get,
--		.set_value = ctrl_subsys_set,
--		DEFMASK(PVR2_SUBSYS_ALL,control_values_subsystem),
--	},{
--		.desc = "Subsystem stream mask",
--		.name = "debug_subsys_stream_mask",
--		.skip_init = !0,
--		.get_value = ctrl_subsys_stream_get,
--		.set_value = ctrl_subsys_stream_set,
--		DEFMASK(PVR2_SUBSYS_ALL,control_values_subsystem),
--	},{
- 		.desc = "Video Standard Name",
- 		.name = "video_standard",
- 		.internal_id = PVR2_CID_STDENUM,
-@@ -1129,25 +1090,13 @@ static int pvr2_upload_firmware1(struct pvr2_hdw *hdw)
- 	unsigned int pipe;
- 	int ret;
- 	u16 address;
--	static const char *fw_files_29xxx[] = {
--		"v4l-pvrusb2-29xxx-01.fw",
--	};
--	static const char *fw_files_24xxx[] = {
--		"v4l-pvrusb2-24xxx-01.fw",
--	};
--	static const struct pvr2_string_table fw_file_defs[] = {
--		[PVR2_HDW_TYPE_29XXX] = {
--			fw_files_29xxx, ARRAY_SIZE(fw_files_29xxx)
--		},
--		[PVR2_HDW_TYPE_24XXX] = {
--			fw_files_24xxx, ARRAY_SIZE(fw_files_24xxx)
--		},
--	};
- 
--	if ((hdw->hdw_type >= ARRAY_SIZE(fw_file_defs)) ||
--	    (!fw_file_defs[hdw->hdw_type].lst)) {
-+	if (!hdw->hdw_desc->fx2_firmware.cnt) {
- 		hdw->fw1_state = FW1_STATE_OK;
++	struct saa7134_fh *fh = f;
++	struct saa7134_dev *dev = fh->dev;
++	unsigned long flags;
++
++	if (on) {
++		if (saa7134_no_overlay > 0) {
++			dprintk("no_overlay\n");
++			return -EINVAL;
+ 		}
 -		return 0;
-+		pvr2_trace(PVR2_TRACE_ERROR_LEGS,
-+			   "Connected device type defines"
-+			   " no firmware to upload; ignoring firmware");
-+		return -ENOTTY;
+-	}
+ 
+-	/* --- capture ioctls ---------------------------------------- */
+-	case VIDIOC_G_FMT:
+-	{
+-		struct v4l2_format *f = arg;
+-		return saa7134_g_fmt(dev,fh,f);
+-	}
+-	case VIDIOC_S_FMT:
+-	{
+-		struct v4l2_format *f = arg;
+-		return saa7134_s_fmt(dev,fh,f);
++		if (!res_get(dev, fh, RESOURCE_OVERLAY))
++			return -EBUSY;
++		spin_lock_irqsave(&dev->slock, flags);
++		start_preview(dev, fh);
++		spin_unlock_irqrestore(&dev->slock, flags);
+ 	}
+-	case VIDIOC_TRY_FMT:
+-	{
+-		struct v4l2_format *f = arg;
+-		return saa7134_try_fmt(dev,fh,f);
++	if (!on) {
++		if (!res_check(fh, RESOURCE_OVERLAY))
++			return -EINVAL;
++		spin_lock_irqsave(&dev->slock, flags);
++		stop_preview(dev, fh);
++		spin_unlock_irqrestore(&dev->slock, flags);
++		res_free(dev, fh, RESOURCE_OVERLAY);
  	}
++	return 0;
++}
++
+ #ifdef CONFIG_VIDEO_V4L1_COMPAT
+-	case VIDIOCGMBUF:
+-		return videobuf_cgmbuf(saa7134_queue(fh), arg, gbuffers);
++static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf)
++{
++	struct saa7134_fh *fh = file->private_data;
++	return videobuf_cgmbuf(saa7134_queue(fh), mbuf, 8);
++}
+ #endif
+-	case VIDIOC_REQBUFS:
+-		return videobuf_reqbufs(saa7134_queue(fh),arg);
  
- 	hdw->fw1_state = FW1_STATE_FAILED; // default result
-@@ -1155,8 +1104,8 @@ static int pvr2_upload_firmware1(struct pvr2_hdw *hdw)
- 	trace_firmware("pvr2_upload_firmware1");
+-	case VIDIOC_QUERYBUF:
+-		return videobuf_querybuf(saa7134_queue(fh),arg);
++static int saa7134_reqbufs(struct file *file, void *priv,
++					struct v4l2_requestbuffers *p)
++{
++	struct saa7134_fh *fh = priv;
++	return videobuf_reqbufs(saa7134_queue(fh), p);
++}
  
- 	ret = pvr2_locate_firmware(hdw,&fw_entry,"fx2 controller",
--				   fw_file_defs[hdw->hdw_type].cnt,
--				   fw_file_defs[hdw->hdw_type].lst);
-+				   hdw->hdw_desc->fx2_firmware.cnt,
-+				   hdw->hdw_desc->fx2_firmware.lst);
- 	if (ret < 0) {
- 		if (ret == -ENOENT) hdw->fw1_state = FW1_STATE_MISSING;
- 		return ret;
-@@ -1231,8 +1180,7 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw)
- 		CX2341X_FIRM_ENC_FILENAME,
- 	};
+-	case VIDIOC_QBUF:
+-		return videobuf_qbuf(saa7134_queue(fh),arg);
++static int saa7134_querybuf(struct file *file, void *priv,
++					struct v4l2_buffer *b)
++{
++	struct saa7134_fh *fh = priv;
++	return videobuf_querybuf(saa7134_queue(fh), b);
++}
  
--	if ((hdw->hdw_type != PVR2_HDW_TYPE_29XXX) &&
--	    (hdw->hdw_type != PVR2_HDW_TYPE_24XXX)) {
-+	if (hdw->hdw_desc->flag_skip_cx23416_firmware) {
- 		return 0;
- 	}
+-	case VIDIOC_DQBUF:
+-		return videobuf_dqbuf(saa7134_queue(fh),arg,
+-				      file->f_flags & O_NONBLOCK);
++static int saa7134_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
++{
++	struct saa7134_fh *fh = priv;
++	return videobuf_qbuf(saa7134_queue(fh), b);
++}
  
-@@ -1248,8 +1196,6 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw)
- 	   time we configure the encoder, then we'll fully configure it. */
- 	hdw->enc_cur_valid = 0;
+-	case VIDIOC_STREAMON:
+-	{
+-		int res = saa7134_resource(fh);
++static int saa7134_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
++{
++	struct saa7134_fh *fh = priv;
++	return videobuf_dqbuf(saa7134_queue(fh), b,
++				file->f_flags & O_NONBLOCK);
++}
  
--	hdw->flag_encoder_ok = 0;
--
- 	/* First prepare firmware loading */
- 	ret |= pvr2_write_register(hdw, 0x0048, 0xffffffff); /*interrupt mask*/
- 	ret |= pvr2_hdw_gpio_chg_dir(hdw,0xffffffff,0x00000088); /*gpio dir*/
-@@ -1347,293 +1293,129 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw)
- 	if (ret) {
- 		pvr2_trace(PVR2_TRACE_ERROR_LEGS,
- 			   "firmware2 upload post-proc failure");
--	} else {
--		hdw->flag_encoder_ok = !0;
--		hdw->subsys_enabled_mask |= (1<<PVR2_SUBSYS_B_ENC_FIRMWARE);
- 	}
- 	return ret;
- }
+-		if (!res_get(dev,fh,res))
+-			return -EBUSY;
+-		return videobuf_streamon(saa7134_queue(fh));
+-	}
+-	case VIDIOC_STREAMOFF:
+-	{
+-		int res = saa7134_resource(fh);
++static int saa7134_streamon(struct file *file, void *priv,
++					enum v4l2_buf_type type)
++{
++	struct saa7134_fh *fh = priv;
++	struct saa7134_dev *dev = fh->dev;
++	int res = saa7134_resource(fh);
  
+-		err = videobuf_streamoff(saa7134_queue(fh));
+-		if (err < 0)
+-			return err;
+-		res_free(dev,fh,res);
+-		return 0;
+-	}
++	if (!res_get(dev, fh, res))
++		return -EBUSY;
  
--#define FIRMWARE_RECOVERY_BITS \
--	((1<<PVR2_SUBSYS_B_ENC_CFG) | \
--	 (1<<PVR2_SUBSYS_B_ENC_RUN) | \
--	 (1<<PVR2_SUBSYS_B_ENC_FIRMWARE) | \
--	 (1<<PVR2_SUBSYS_B_USBSTREAM_RUN))
--
--/*
--
--  This single function is key to pretty much everything.  The pvrusb2
--  device can logically be viewed as a series of subsystems which can be
--  stopped / started or unconfigured / configured.  To get things streaming,
--  one must configure everything and start everything, but there may be
--  various reasons over time to deconfigure something or stop something.
--  This function handles all of this activity.  Everything EVERYWHERE that
--  must affect a subsystem eventually comes here to do the work.
--
--  The current state of all subsystems is represented by a single bit mask,
--  known as subsys_enabled_mask.  The bit positions are defined by the
--  PVR2_SUBSYS_xxxx macros, with one subsystem per bit position.  At any
--  time the set of configured or active subsystems can be queried just by
--  looking at that mask.  To change bits in that mask, this function here
--  must be called.  The "msk" argument indicates which bit positions to
--  change, and the "val" argument defines the new values for the positions
--  defined by "msk".
--
--  There is a priority ordering of starting / stopping things, and for
--  multiple requested changes, this function implements that ordering.
--  (Thus we will act on a request to load encoder firmware before we
--  configure the encoder.)  In addition to priority ordering, there is a
--  recovery strategy implemented here.  If a particular step fails and we
--  detect that failure, this function will clear the affected subsystem bits
--  and restart.  Thus we have a means for recovering from a dead encoder:
--  Clear all bits that correspond to subsystems that we need to restart /
--  reconfigure and start over.
--
--*/
--static void pvr2_hdw_subsys_bit_chg_no_lock(struct pvr2_hdw *hdw,
--					    unsigned long msk,
--					    unsigned long val)
--{
--	unsigned long nmsk;
--	unsigned long vmsk;
--	int ret;
--	unsigned int tryCount = 0;
--
--	if (!hdw->flag_ok) return;
--
--	msk &= PVR2_SUBSYS_ALL;
--	nmsk = (hdw->subsys_enabled_mask & ~msk) | (val & msk);
--	nmsk &= PVR2_SUBSYS_ALL;
--
--	for (;;) {
--		tryCount++;
--		if (!((nmsk ^ hdw->subsys_enabled_mask) &
--		      PVR2_SUBSYS_ALL)) break;
--		if (tryCount > 4) {
--			pvr2_trace(PVR2_TRACE_ERROR_LEGS,
--				   "Too many retries when configuring device;"
--				   " giving up");
--			pvr2_hdw_render_useless(hdw);
--			break;
--		}
--		if (tryCount > 1) {
--			pvr2_trace(PVR2_TRACE_ERROR_LEGS,
--				   "Retrying device reconfiguration");
--		}
--		pvr2_trace(PVR2_TRACE_INIT,
--			   "subsys mask changing 0x%lx:0x%lx"
--			   " from 0x%lx to 0x%lx",
--			   msk,val,hdw->subsys_enabled_mask,nmsk);
--
--		vmsk = (nmsk ^ hdw->subsys_enabled_mask) &
--			hdw->subsys_enabled_mask;
--		if (vmsk) {
--			if (vmsk & (1<<PVR2_SUBSYS_B_ENC_RUN)) {
--				pvr2_trace(PVR2_TRACE_CTL,
--					   "/*---TRACE_CTL----*/"
--					   " pvr2_encoder_stop");
--				ret = pvr2_encoder_stop(hdw);
--				if (ret) {
--					pvr2_trace(PVR2_TRACE_ERROR_LEGS,
--						   "Error recovery initiated");
--					hdw->subsys_enabled_mask &=
--						~FIRMWARE_RECOVERY_BITS;
--					continue;
--				}
--			}
--			if (vmsk & (1<<PVR2_SUBSYS_B_USBSTREAM_RUN)) {
--				pvr2_trace(PVR2_TRACE_CTL,
--					   "/*---TRACE_CTL----*/"
--					   " pvr2_hdw_cmd_usbstream(0)");
--				pvr2_hdw_cmd_usbstream(hdw,0);
--			}
--			if (vmsk & (1<<PVR2_SUBSYS_B_DIGITIZER_RUN)) {
--				pvr2_trace(PVR2_TRACE_CTL,
--					   "/*---TRACE_CTL----*/"
--					   " decoder disable");
--				if (hdw->decoder_ctrl) {
--					hdw->decoder_ctrl->enable(
--						hdw->decoder_ctrl->ctxt,0);
--				} else {
--					pvr2_trace(PVR2_TRACE_ERROR_LEGS,
--						   "WARNING:"
--						   " No decoder present");
--				}
--				hdw->subsys_enabled_mask &=
--					~(1<<PVR2_SUBSYS_B_DIGITIZER_RUN);
--			}
--			if (vmsk & PVR2_SUBSYS_CFG_ALL) {
--				hdw->subsys_enabled_mask &=
--					~(vmsk & PVR2_SUBSYS_CFG_ALL);
--			}
--		}
--		vmsk = (nmsk ^ hdw->subsys_enabled_mask) & nmsk;
--		if (vmsk) {
--			if (vmsk & (1<<PVR2_SUBSYS_B_ENC_FIRMWARE)) {
--				pvr2_trace(PVR2_TRACE_CTL,
--					   "/*---TRACE_CTL----*/"
--					   " pvr2_upload_firmware2");
--				ret = pvr2_upload_firmware2(hdw);
--				if (ret) {
--					pvr2_trace(PVR2_TRACE_ERROR_LEGS,
--						   "Failure uploading encoder"
--						   " firmware");
--					pvr2_hdw_render_useless(hdw);
--					break;
--				}
--			}
--			if (vmsk & (1<<PVR2_SUBSYS_B_ENC_CFG)) {
--				pvr2_trace(PVR2_TRACE_CTL,
--					   "/*---TRACE_CTL----*/"
--					   " pvr2_encoder_configure");
--				ret = pvr2_encoder_configure(hdw);
--				if (ret) {
--					pvr2_trace(PVR2_TRACE_ERROR_LEGS,
--						   "Error recovery initiated");
--					hdw->subsys_enabled_mask &=
--						~FIRMWARE_RECOVERY_BITS;
--					continue;
--				}
--			}
--			if (vmsk & (1<<PVR2_SUBSYS_B_DIGITIZER_RUN)) {
--				pvr2_trace(PVR2_TRACE_CTL,
--					   "/*---TRACE_CTL----*/"
--					   " decoder enable");
--				if (hdw->decoder_ctrl) {
--					hdw->decoder_ctrl->enable(
--						hdw->decoder_ctrl->ctxt,!0);
--				} else {
--					pvr2_trace(PVR2_TRACE_ERROR_LEGS,
--						   "WARNING:"
--						   " No decoder present");
--				}
--				hdw->subsys_enabled_mask |=
--					(1<<PVR2_SUBSYS_B_DIGITIZER_RUN);
--			}
--			if (vmsk & (1<<PVR2_SUBSYS_B_USBSTREAM_RUN)) {
--				pvr2_trace(PVR2_TRACE_CTL,
--					   "/*---TRACE_CTL----*/"
--					   " pvr2_hdw_cmd_usbstream(1)");
--				pvr2_hdw_cmd_usbstream(hdw,!0);
--			}
--			if (vmsk & (1<<PVR2_SUBSYS_B_ENC_RUN)) {
--				pvr2_trace(PVR2_TRACE_CTL,
--					   "/*---TRACE_CTL----*/"
--					   " pvr2_encoder_start");
--				ret = pvr2_encoder_start(hdw);
--				if (ret) {
--					pvr2_trace(PVR2_TRACE_ERROR_LEGS,
--						   "Error recovery initiated");
--					hdw->subsys_enabled_mask &=
--						~FIRMWARE_RECOVERY_BITS;
--					continue;
--				}
--			}
--		}
-+static const char *pvr2_get_state_name(unsigned int st)
+-	default:
+-		return v4l_compat_translate_ioctl(inode,file,cmd,arg,
+-						  video_do_ioctl);
+-	}
++	return videobuf_streamon(saa7134_queue(fh));
++}
++
++static int saa7134_streamoff(struct file *file, void *priv,
++					enum v4l2_buf_type type)
 +{
-+	if (st < ARRAY_SIZE(pvr2_state_names)) {
-+		return pvr2_state_names[st];
- 	}
-+	return "???";
++	int err;
++	struct saa7134_fh *fh = priv;
++	struct saa7134_dev *dev = fh->dev;
++	int res = saa7134_resource(fh);
++
++	err = videobuf_streamoff(saa7134_queue(fh));
++	if (err < 0)
++		return err;
++	res_free(dev, fh, res);
+ 	return 0;
  }
  
--
--void pvr2_hdw_subsys_bit_chg(struct pvr2_hdw *hdw,
--			     unsigned long msk,unsigned long val)
-+static int pvr2_decoder_enable(struct pvr2_hdw *hdw,int enablefl)
+-static int video_ioctl(struct inode *inode, struct file *file,
+-		       unsigned int cmd, unsigned long arg)
++static int saa7134_g_parm(struct file *file, void *fh,
++				struct v4l2_streamparm *parm)
  {
--	LOCK_TAKE(hdw->big_lock); do {
--		pvr2_hdw_subsys_bit_chg_no_lock(hdw,msk,val);
--	} while (0); LOCK_GIVE(hdw->big_lock);
-+	if (!hdw->decoder_ctrl) {
-+		if (!hdw->flag_decoder_missed) {
-+			pvr2_trace(PVR2_TRACE_ERROR_LEGS,
-+				   "WARNING: No decoder present");
-+			hdw->flag_decoder_missed = !0;
-+			trace_stbit("flag_decoder_missed",
-+				    hdw->flag_decoder_missed);
-+		}
-+		return -EIO;
-+	}
-+	hdw->decoder_ctrl->enable(hdw->decoder_ctrl->ctxt,enablefl);
+-	return video_usercopy(inode, file, cmd, arg, video_do_ioctl);
 +	return 0;
  }
  
- 
--unsigned long pvr2_hdw_subsys_get(struct pvr2_hdw *hdw)
-+void pvr2_hdw_set_decoder(struct pvr2_hdw *hdw,struct pvr2_decoder_ctrl *ptr)
+-static int radio_do_ioctl(struct inode *inode, struct file *file,
+-			  unsigned int cmd, void *arg)
++static int radio_querycap(struct file *file, void *priv,
++					struct v4l2_capability *cap)
  {
--	return hdw->subsys_enabled_mask;
-+	if (hdw->decoder_ctrl == ptr) return;
-+	hdw->decoder_ctrl = ptr;
-+	if (hdw->decoder_ctrl && hdw->flag_decoder_missed) {
-+		hdw->flag_decoder_missed = 0;
-+		trace_stbit("flag_decoder_missed",
-+			    hdw->flag_decoder_missed);
-+		pvr2_trace(PVR2_TRACE_ERROR_LEGS,
-+			   "Decoder has appeared");
-+		pvr2_hdw_state_sched(hdw);
-+	}
- }
+ 	struct saa7134_fh *fh = file->private_data;
+ 	struct saa7134_dev *dev = fh->dev;
  
+-	if (video_debug > 1)
+-		v4l_print_ioctl(dev->name,cmd);
+-	switch (cmd) {
+-	case VIDIOC_QUERYCAP:
+-	{
+-		struct v4l2_capability *cap = arg;
+-
+-		memset(cap,0,sizeof(*cap));
+-		strcpy(cap->driver, "saa7134");
+-		strlcpy(cap->card, saa7134_boards[dev->board].name,
+-			sizeof(cap->card));
+-		sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci));
+-		cap->version = SAA7134_VERSION_CODE;
+-		cap->capabilities = V4L2_CAP_TUNER;
+-		return 0;
+-	}
+-	case VIDIOC_G_TUNER:
+-	{
+-		struct v4l2_tuner *t = arg;
++	strcpy(cap->driver, "saa7134");
++	strlcpy(cap->card, saa7134_boards[dev->board].name, sizeof(cap->card));
++	sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci));
++	cap->version = SAA7134_VERSION_CODE;
++	cap->capabilities = V4L2_CAP_TUNER;
++	return 0;
++}
  
--unsigned long pvr2_hdw_subsys_stream_get(struct pvr2_hdw *hdw)
-+int pvr2_hdw_get_state(struct pvr2_hdw *hdw)
- {
--	return hdw->subsys_stream_mask;
-+	return hdw->master_state;
- }
+-		if (0 != t->index)
+-			return -EINVAL;
++static int radio_g_tuner(struct file *file, void *priv,
++					struct v4l2_tuner *t)
++{
++	struct saa7134_fh *fh = file->private_data;
++	struct saa7134_dev *dev = fh->dev;
  
+-		memset(t,0,sizeof(*t));
+-		strcpy(t->name, "Radio");
+-		t->type = V4L2_TUNER_RADIO;
++	if (0 != t->index)
++		return -EINVAL;
  
--static void pvr2_hdw_subsys_stream_bit_chg_no_lock(struct pvr2_hdw *hdw,
--						   unsigned long msk,
--						   unsigned long val)
-+static int pvr2_hdw_untrip_unlocked(struct pvr2_hdw *hdw)
- {
--	unsigned long val2;
--	msk &= PVR2_SUBSYS_ALL;
--	val2 = ((hdw->subsys_stream_mask & ~msk) | (val & msk));
--	pvr2_trace(PVR2_TRACE_INIT,
--		   "stream mask changing 0x%lx:0x%lx from 0x%lx to 0x%lx",
--		   msk,val,hdw->subsys_stream_mask,val2);
--	hdw->subsys_stream_mask = val2;
-+	if (!hdw->flag_tripped) return 0;
-+	hdw->flag_tripped = 0;
-+	pvr2_trace(PVR2_TRACE_ERROR_LEGS,
-+		   "Clearing driver error statuss");
-+	return !0;
- }
+-		saa7134_i2c_call_clients(dev, VIDIOC_G_TUNER, t);
+-		if (dev->input->amux == TV) {
+-			t->signal = 0xf800 - ((saa_readb(0x581) & 0x1f) << 11);
+-			t->rxsubchans = (saa_readb(0x529) & 0x08) ?
+-					V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO;
+-		}
+-		return 0;
++	memset(t, 0, sizeof(*t));
++	strcpy(t->name, "Radio");
++	t->type = V4L2_TUNER_RADIO;
++
++	saa7134_i2c_call_clients(dev, VIDIOC_G_TUNER, t);
++	if (dev->input->amux == TV) {
++		t->signal = 0xf800 - ((saa_readb(0x581) & 0x1f) << 11);
++		t->rxsubchans = (saa_readb(0x529) & 0x08) ?
++				V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO;
+ 	}
+-	case VIDIOC_S_TUNER:
+-	{
+-		struct v4l2_tuner *t = arg;
++	return 0;
++}
++static int radio_s_tuner(struct file *file, void *priv,
++					struct v4l2_tuner *t)
++{
++	struct saa7134_fh *fh = file->private_data;
++	struct saa7134_dev *dev = fh->dev;
  
+-		if (0 != t->index)
+-			return -EINVAL;
++	if (0 != t->index)
++		return -EINVAL;
  
--void pvr2_hdw_subsys_stream_bit_chg(struct pvr2_hdw *hdw,
--				    unsigned long msk,
--				    unsigned long val)
-+int pvr2_hdw_untrip(struct pvr2_hdw *hdw)
- {
-+	int fl;
- 	LOCK_TAKE(hdw->big_lock); do {
--		pvr2_hdw_subsys_stream_bit_chg_no_lock(hdw,msk,val);
-+		fl = pvr2_hdw_untrip_unlocked(hdw);
- 	} while (0); LOCK_GIVE(hdw->big_lock);
-+	if (fl) pvr2_hdw_state_sched(hdw);
+-		saa7134_i2c_call_clients(dev,VIDIOC_S_TUNER,t);
++	saa7134_i2c_call_clients(dev, VIDIOC_S_TUNER, t);
 +	return 0;
- }
- 
++}
  
--static int pvr2_hdw_set_streaming_no_lock(struct pvr2_hdw *hdw,int enableFl)
-+const char *pvr2_hdw_get_state_name(unsigned int id)
- {
--	if ((!enableFl) == !(hdw->flag_streaming_enabled)) return 0;
--	if (enableFl) {
--		pvr2_trace(PVR2_TRACE_START_STOP,
--			   "/*--TRACE_STREAM--*/ enable");
--		pvr2_hdw_subsys_bit_chg_no_lock(hdw,~0,~0);
--	} else {
--		pvr2_trace(PVR2_TRACE_START_STOP,
--			   "/*--TRACE_STREAM--*/ disable");
--		pvr2_hdw_subsys_bit_chg_no_lock(hdw,hdw->subsys_stream_mask,0);
+-		return 0;
 -	}
--	if (!hdw->flag_ok) return -EIO;
--	hdw->flag_streaming_enabled = enableFl != 0;
--	return 0;
-+	if (id >= ARRAY_SIZE(pvr2_state_names)) return NULL;
-+	return pvr2_state_names[id];
- }
- 
- 
- int pvr2_hdw_get_streaming(struct pvr2_hdw *hdw)
- {
--	return hdw->flag_streaming_enabled != 0;
-+	return hdw->state_pipeline_req != 0;
- }
+-	case VIDIOC_ENUMINPUT:
+-	{
+-		struct v4l2_input *i = arg;
++static int radio_enum_input(struct file *file, void *priv,
++					struct v4l2_input *i)
++{
++	if (i->index != 0)
++		return -EINVAL;
  
+-		if (i->index != 0)
+-			return -EINVAL;
+-		strcpy(i->name,"Radio");
+-		i->type = V4L2_INPUT_TYPE_TUNER;
+-		return 0;
+-	}
+-	case VIDIOC_G_INPUT:
+-	{
+-		int *i = arg;
+-		*i = 0;
+-		return 0;
+-	}
+-	case VIDIOC_G_AUDIO:
+-	{
+-		struct v4l2_audio *a = arg;
++	strcpy(i->name, "Radio");
++	i->type = V4L2_INPUT_TYPE_TUNER;
  
- int pvr2_hdw_set_streaming(struct pvr2_hdw *hdw,int enable_flag)
- {
--	int ret;
-+	int ret,st;
- 	LOCK_TAKE(hdw->big_lock); do {
--		ret = pvr2_hdw_set_streaming_no_lock(hdw,enable_flag);
-+		pvr2_hdw_untrip_unlocked(hdw);
-+		if ((!enable_flag) != !(hdw->state_pipeline_req)) {
-+			hdw->state_pipeline_req = enable_flag != 0;
-+			pvr2_trace(PVR2_TRACE_START_STOP,
-+				   "/*--TRACE_STREAM--*/ %s",
-+				   enable_flag ? "enable" : "disable");
-+		}
-+		pvr2_hdw_state_sched(hdw);
- 	} while (0); LOCK_GIVE(hdw->big_lock);
--	return ret;
--}
--
--
--static int pvr2_hdw_set_stream_type_no_lock(struct pvr2_hdw *hdw,
--					    enum pvr2_config config)
--{
--	unsigned long sm = hdw->subsys_enabled_mask;
--	if (!hdw->flag_ok) return -EIO;
--	pvr2_hdw_subsys_bit_chg_no_lock(hdw,hdw->subsys_stream_mask,0);
--	hdw->config = config;
--	pvr2_hdw_subsys_bit_chg_no_lock(hdw,~0,sm);
-+	if ((ret = pvr2_hdw_wait(hdw,0)) < 0) return ret;
-+	if (enable_flag) {
-+		while ((st = hdw->master_state) != PVR2_STATE_RUN) {
-+			if (st != PVR2_STATE_READY) return -EIO;
-+			if ((ret = pvr2_hdw_wait(hdw,st)) < 0) return ret;
-+		}
-+	}
- 	return 0;
- }
+-		memset(a,0,sizeof(*a));
+-		strcpy(a->name,"Radio");
+-		return 0;
+-	}
+-	case VIDIOC_G_STD:
+-	{
+-		v4l2_std_id *id = arg;
+-		*id = 0;
+-		return 0;
+-	}
+-	case VIDIOC_S_AUDIO:
+-	case VIDIOC_S_INPUT:
+-	case VIDIOC_S_STD:
+-		return 0;
++	return 0;
++}
  
+-	case VIDIOC_QUERYCTRL:
+-	{
+-		const struct v4l2_queryctrl *ctrl;
+-		struct v4l2_queryctrl *c = arg;
++static int radio_g_input(struct file *filp, void *priv, unsigned int *i)
++{
++	*i = 0;
++	return 0;
++}
  
- int pvr2_hdw_set_stream_type(struct pvr2_hdw *hdw,enum pvr2_config config)
- {
--	int ret;
--	if (!hdw->flag_ok) return -EIO;
-+	int fl;
- 	LOCK_TAKE(hdw->big_lock);
--	ret = pvr2_hdw_set_stream_type_no_lock(hdw,config);
-+	if ((fl = (hdw->desired_stream_type != config)) != 0) {
-+		hdw->desired_stream_type = config;
-+		hdw->state_pipeline_config = 0;
-+		trace_stbit("state_pipeline_config",
-+			    hdw->state_pipeline_config);
-+		pvr2_hdw_state_sched(hdw);
-+	}
- 	LOCK_GIVE(hdw->big_lock);
--	return ret;
-+	if (fl) return 0;
-+	return pvr2_hdw_wait(hdw,0);
- }
+-		if (c->id <  V4L2_CID_BASE ||
+-		    c->id >= V4L2_CID_LASTP1)
+-			return -EINVAL;
+-		if (c->id == V4L2_CID_AUDIO_MUTE) {
+-			ctrl = ctrl_by_id(c->id);
+-			*c = *ctrl;
+-		} else
+-			*c = no_ctrl;
+-		return 0;
+-	}
++static int radio_g_audio(struct file *file, void *priv,
++					struct v4l2_audio *a)
++{
++	memset(a, 0, sizeof(*a));
++	strcpy(a->name, "Radio");
++	return 0;
++}
  
+-	case VIDIOC_G_CTRL:
+-	case VIDIOC_S_CTRL:
+-	case VIDIOC_G_FREQUENCY:
+-	case VIDIOC_S_FREQUENCY:
+-		return video_do_ioctl(inode,file,cmd,arg);
++static int radio_s_audio(struct file *file, void *priv,
++					struct v4l2_audio *a)
++{
++	return 0;
++}
  
-@@ -1646,6 +1428,7 @@ static int get_default_tuner_type(struct pvr2_hdw *hdw)
- 	}
- 	if (tp < 0) return -EINVAL;
- 	hdw->tuner_type = tp;
-+	hdw->tuner_updated = !0;
+-	default:
+-		return v4l_compat_translate_ioctl(inode,file,cmd,arg,
+-						  radio_do_ioctl);
+-	}
++static int radio_s_input(struct file *filp, void *priv, unsigned int i)
++{
  	return 0;
  }
  
-@@ -1656,8 +1439,9 @@ static v4l2_std_id get_default_standard(struct pvr2_hdw *hdw)
- 	int tp = 0;
- 	if ((unit_number >= 0) && (unit_number < PVR_NUM)) {
- 		tp = video_std[unit_number];
-+		if (tp) return tp;
- 	}
--	return tp;
+-static int radio_ioctl(struct inode *inode, struct file *file,
+-		       unsigned int cmd, unsigned long arg)
++static int radio_s_std(struct file *file, void *fh, v4l2_std_id *norm)
+ {
+-	return video_usercopy(inode, file, cmd, arg, radio_do_ioctl);
++	return 0;
++}
++
++static int radio_queryctrl(struct file *file, void *priv,
++					struct v4l2_queryctrl *c)
++{
++	const struct v4l2_queryctrl *ctrl;
++
++	if (c->id <  V4L2_CID_BASE ||
++	    c->id >= V4L2_CID_LASTP1)
++		return -EINVAL;
++	if (c->id == V4L2_CID_AUDIO_MUTE) {
++		ctrl = ctrl_by_id(c->id);
++		*c = *ctrl;
++	} else
++		*c = no_ctrl;
 +	return 0;
  }
  
- 
-@@ -1731,7 +1515,7 @@ const static struct pvr2_std_hack std_eeprom_maps[] = {
- 	},
- 	{	/* PAL(D/D1/K) */
- 		.pat = V4L2_STD_DK,
--		.std = V4L2_STD_PAL_D/V4L2_STD_PAL_D1|V4L2_STD_PAL_K,
-+		.std = V4L2_STD_PAL_D|V4L2_STD_PAL_D1|V4L2_STD_PAL_K,
- 	},
+ static const struct file_operations video_fops =
+@@ -2333,7 +2327,7 @@ static const struct file_operations video_fops =
+ 	.read	  = video_read,
+ 	.poll     = video_poll,
+ 	.mmap	  = video_mmap,
+-	.ioctl	  = video_ioctl,
++	.ioctl	  = video_ioctl2,
+ 	.compat_ioctl	= v4l_compat_ioctl32,
+ 	.llseek   = no_llseek,
+ };
+@@ -2343,7 +2337,7 @@ static const struct file_operations radio_fops =
+ 	.owner	  = THIS_MODULE,
+ 	.open	  = video_open,
+ 	.release  = video_release,
+-	.ioctl	  = radio_ioctl,
++	.ioctl	  = video_ioctl2,
+ 	.compat_ioctl	= v4l_compat_ioctl32,
+ 	.llseek   = no_llseek,
  };
+@@ -2353,27 +2347,79 @@ static const struct file_operations radio_fops =
  
-@@ -1739,18 +1523,20 @@ static void pvr2_hdw_setup_std(struct pvr2_hdw *hdw)
+ struct video_device saa7134_video_template =
  {
- 	char buf[40];
- 	unsigned int bcnt;
--	v4l2_std_id std1,std2;
-+	v4l2_std_id std1,std2,std3;
- 
- 	std1 = get_default_standard(hdw);
-+	std3 = std1 ? 0 : hdw->hdw_desc->default_std_mask;
- 
- 	bcnt = pvr2_std_id_to_str(buf,sizeof(buf),hdw->std_mask_eeprom);
- 	pvr2_trace(PVR2_TRACE_STD,
--		   "Supported video standard(s) reported by eeprom: %.*s",
-+		   "Supported video standard(s) reported available"
-+		   " in hardware: %.*s",
- 		   bcnt,buf);
- 
- 	hdw->std_mask_avail = hdw->std_mask_eeprom;
- 
--	std2 = std1 & ~hdw->std_mask_avail;
-+	std2 = (std1|std3) & ~hdw->std_mask_avail;
- 	if (std2) {
- 		bcnt = pvr2_std_id_to_str(buf,sizeof(buf),std2);
- 		pvr2_trace(PVR2_TRACE_STD,
-@@ -1772,6 +1558,16 @@ static void pvr2_hdw_setup_std(struct pvr2_hdw *hdw)
- 		pvr2_hdw_internal_find_stdenum(hdw);
- 		return;
- 	}
-+	if (std3) {
-+		bcnt = pvr2_std_id_to_str(buf,sizeof(buf),std3);
-+		pvr2_trace(PVR2_TRACE_STD,
-+			   "Initial video standard"
-+			   " (determined by device type): %.*s",bcnt,buf);
-+		hdw->std_mask_cur = std3;
-+		hdw->std_dirty = !0;
-+		pvr2_hdw_internal_find_stdenum(hdw);
-+		return;
-+	}
- 
- 	{
- 		unsigned int idx;
-@@ -1816,8 +1612,7 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw)
- 	unsigned int idx;
- 	struct pvr2_ctrl *cptr;
- 	int reloadFl = 0;
--	if ((hdw->hdw_type == PVR2_HDW_TYPE_29XXX) ||
--	    (hdw->hdw_type == PVR2_HDW_TYPE_24XXX)) {
-+	if (hdw->hdw_desc->fx2_firmware.cnt) {
- 		if (!reloadFl) {
- 			reloadFl =
- 				(hdw->usb_intf->cur_altsetting->desc.bNumEndpoints
-@@ -1853,25 +1648,13 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw)
- 	}
- 	if (!pvr2_hdw_dev_ok(hdw)) return;
- 
--	if (hdw->hdw_type < ARRAY_SIZE(pvr2_client_lists)) {
--		for (idx = 0;
--		     idx < pvr2_client_lists[hdw->hdw_type].cnt;
--		     idx++) {
--			request_module(
--				pvr2_client_lists[hdw->hdw_type].lst[idx]);
--		}
-+	for (idx = 0; idx < hdw->hdw_desc->client_modules.cnt; idx++) {
-+		request_module(hdw->hdw_desc->client_modules.lst[idx]);
- 	}
- 
--	if ((hdw->hdw_type == PVR2_HDW_TYPE_29XXX) ||
--	    (hdw->hdw_type == PVR2_HDW_TYPE_24XXX)) {
-+	if (!hdw->hdw_desc->flag_no_powerup) {
- 		pvr2_hdw_cmd_powerup(hdw);
- 		if (!pvr2_hdw_dev_ok(hdw)) return;
+-	.name          = "saa7134-video",
+-	.type          = VID_TYPE_CAPTURE|VID_TYPE_TUNER|
+-			 VID_TYPE_CLIPPING|VID_TYPE_SCALES,
+-	.fops          = &video_fops,
+-	.minor         = -1,
+-};
 -
--		if (pvr2_upload_firmware2(hdw)){
--			pvr2_trace(PVR2_TRACE_ERROR_LEGS,"device unstable!!");
--			pvr2_hdw_render_useless(hdw);
--			return;
--		}
- 	}
- 
- 	// This step MUST happen after the earlier powerup step.
-@@ -1899,15 +1682,22 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw)
- 	// thread-safe against the normal pvr2_send_request() mechanism.
- 	// (We should make it thread safe).
+-struct video_device saa7134_vbi_template =
+-{
+-	.name          = "saa7134-vbi",
+-	.type          = VID_TYPE_TUNER|VID_TYPE_TELETEXT,
+-	.fops          = &video_fops,
+-	.minor         = -1,
++	.name				= "saa7134-video",
++	.type				= VID_TYPE_CAPTURE|VID_TYPE_TUNER |
++					VID_TYPE_CLIPPING|VID_TYPE_SCALES,
++	.fops				= &video_fops,
++	.minor				= -1,
++	.vidioc_querycap		= saa7134_querycap,
++	.vidioc_enum_fmt_cap		= saa7134_enum_fmt_cap,
++	.vidioc_g_fmt_cap		= saa7134_g_fmt_cap,
++	.vidioc_try_fmt_cap		= saa7134_try_fmt_cap,
++	.vidioc_s_fmt_cap		= saa7134_s_fmt_cap,
++	.vidioc_enum_fmt_overlay	= saa7134_enum_fmt_overlay,
++	.vidioc_g_fmt_overlay		= saa7134_g_fmt_overlay,
++	.vidioc_try_fmt_overlay		= saa7134_try_fmt_overlay,
++	.vidioc_s_fmt_overlay		= saa7134_s_fmt_overlay,
++	.vidioc_enum_fmt_vbi		= saa7134_enum_fmt_vbi,
++	.vidioc_g_fmt_vbi		= saa7134_try_get_set_fmt_vbi,
++	.vidioc_try_fmt_vbi		= saa7134_try_get_set_fmt_vbi,
++	.vidioc_s_fmt_vbi		= saa7134_try_get_set_fmt_vbi,
++	.vidioc_g_audio			= saa7134_g_audio,
++	.vidioc_s_audio			= saa7134_s_audio,
++	.vidioc_cropcap			= saa7134_cropcap,
++	.vidioc_reqbufs			= saa7134_reqbufs,
++	.vidioc_querybuf		= saa7134_querybuf,
++	.vidioc_qbuf			= saa7134_qbuf,
++	.vidioc_dqbuf			= saa7134_dqbuf,
++	.vidioc_s_std			= saa7134_s_std,
++	.vidioc_enum_input		= saa7134_enum_input,
++	.vidioc_g_input			= saa7134_g_input,
++	.vidioc_s_input			= saa7134_s_input,
++	.vidioc_queryctrl		= saa7134_queryctrl,
++	.vidioc_g_ctrl			= saa7134_g_ctrl,
++	.vidioc_s_ctrl			= saa7134_s_ctrl,
++	.vidioc_streamon		= saa7134_streamon,
++	.vidioc_streamoff		= saa7134_streamoff,
++	.vidioc_g_tuner			= saa7134_g_tuner,
++	.vidioc_s_tuner			= saa7134_s_tuner,
++#ifdef CONFIG_VIDEO_V4L1_COMPAT
++	.vidiocgmbuf			= vidiocgmbuf,
++#endif
++	.vidioc_g_crop			= saa7134_g_crop,
++	.vidioc_s_crop			= saa7134_s_crop,
++	.vidioc_g_fbuf			= saa7134_g_fbuf,
++	.vidioc_s_fbuf			= saa7134_s_fbuf,
++	.vidioc_overlay			= saa7134_overlay,
++	.vidioc_g_priority		= saa7134_g_priority,
++	.vidioc_s_priority		= saa7134_s_priority,
++	.vidioc_g_parm			= saa7134_g_parm,
++	.vidioc_g_frequency		= saa7134_g_frequency,
++	.vidioc_s_frequency		= saa7134_s_frequency,
++	.tvnorms			= SAA7134_NORMS,
++	.current_norm			= V4L2_STD_PAL,
+ };
  
--	ret = pvr2_hdw_get_eeprom_addr(hdw);
--	if (!pvr2_hdw_dev_ok(hdw)) return;
--	if (ret < 0) {
--		pvr2_trace(PVR2_TRACE_ERROR_LEGS,
--			   "Unable to determine location of eeprom, skipping");
--	} else {
--		hdw->eeprom_addr = ret;
--		pvr2_eeprom_analyze(hdw);
-+	if (hdw->hdw_desc->flag_has_hauppauge_rom) {
-+		ret = pvr2_hdw_get_eeprom_addr(hdw);
- 		if (!pvr2_hdw_dev_ok(hdw)) return;
-+		if (ret < 0) {
-+			pvr2_trace(PVR2_TRACE_ERROR_LEGS,
-+				   "Unable to determine location of eeprom,"
-+				   " skipping");
-+		} else {
-+			hdw->eeprom_addr = ret;
-+			pvr2_eeprom_analyze(hdw);
-+			if (!pvr2_hdw_dev_ok(hdw)) return;
-+		}
-+	} else {
-+		hdw->tuner_type = hdw->hdw_desc->default_tuner_type;
-+		hdw->tuner_updated = !0;
-+		hdw->std_mask_eeprom = V4L2_STD_ALL;
- 	}
+ struct video_device saa7134_radio_template =
+ {
+-	.name          = "saa7134-radio",
+-	.type          = VID_TYPE_TUNER,
+-	.fops          = &radio_fops,
+-	.minor         = -1,
++	.name			= "saa7134-radio",
++	.type			= VID_TYPE_TUNER,
++	.fops			= &radio_fops,
++	.minor			= -1,
++	.vidioc_querycap	= radio_querycap,
++	.vidioc_g_tuner		= radio_g_tuner,
++	.vidioc_enum_input	= radio_enum_input,
++	.vidioc_g_audio		= radio_g_audio,
++	.vidioc_s_tuner		= radio_s_tuner,
++	.vidioc_s_audio		= radio_s_audio,
++	.vidioc_s_input		= radio_s_input,
++	.vidioc_s_std		= radio_s_std,
++	.vidioc_queryctrl	= radio_queryctrl,
++	.vidioc_g_input		= radio_g_input,
++	.vidioc_g_ctrl		= saa7134_g_ctrl,
++	.vidioc_s_ctrl		= saa7134_s_ctrl,
++	.vidioc_g_frequency	= saa7134_g_frequency,
++	.vidioc_s_frequency	= saa7134_s_frequency,
+ };
  
- 	pvr2_hdw_setup_std(hdw);
-@@ -1918,14 +1708,12 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw)
- 			   hdw->tuner_type);
+ int saa7134_video_init1(struct saa7134_dev *dev)
+@@ -2511,7 +2557,7 @@ void saa7134_irq_video_done(struct saa7134_dev *dev, unsigned long status)
+ 				goto done;
+ 		}
+ 		dev->video_q.curr->vb.field_count = dev->video_fieldcount;
+-		saa7134_buffer_finish(dev,&dev->video_q,STATE_DONE);
++		saa7134_buffer_finish(dev,&dev->video_q,VIDEOBUF_DONE);
  	}
+ 	saa7134_buffer_next(dev,&dev->video_q);
  
--	hdw->tuner_updated = !0;
- 	pvr2_i2c_core_check_stale(hdw);
- 	hdw->tuner_updated = 0;
- 
- 	if (!pvr2_hdw_dev_ok(hdw)) return;
+diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h
+index 66a390c..ce45030 100644
+--- a/drivers/media/video/saa7134/saa7134.h
++++ b/drivers/media/video/saa7134/saa7134.h
+@@ -240,6 +240,19 @@ struct saa7134_format {
+ #define SAA7134_BOARD_SABRENT_TV_PCB05     115
+ #define SAA7134_BOARD_10MOONSTVMASTER3     116
+ #define SAA7134_BOARD_AVERMEDIA_SUPER_007  117
++#define SAA7134_BOARD_BEHOLD_401  	118
++#define SAA7134_BOARD_BEHOLD_403  	119
++#define SAA7134_BOARD_BEHOLD_403FM	120
++#define SAA7134_BOARD_BEHOLD_405	121
++#define SAA7134_BOARD_BEHOLD_405FM	122
++#define SAA7134_BOARD_BEHOLD_407	123
++#define SAA7134_BOARD_BEHOLD_407FM	124
++#define SAA7134_BOARD_BEHOLD_409	125
++#define SAA7134_BOARD_BEHOLD_505FM	126
++#define SAA7134_BOARD_BEHOLD_507_9FM	127
++#define SAA7134_BOARD_BEHOLD_COLUMBUS_TVFM 128
++#define SAA7134_BOARD_BEHOLD_607_9FM	129
++#define SAA7134_BOARD_BEHOLD_M6		130
  
--	pvr2_hdw_commit_ctl_internal(hdw);
--	if (!pvr2_hdw_dev_ok(hdw)) return;
-+	pvr2_hdw_commit_setup(hdw);
+ #define SAA7134_MAXBOARDS 8
+ #define SAA7134_INPUT_MAX 8
+@@ -481,7 +494,7 @@ struct saa7134_dev {
+ 	/* i2c i/o */
+ 	struct i2c_adapter         i2c_adap;
+ 	struct i2c_client          i2c_client;
+-	unsigned char              eedata[128];
++	unsigned char              eedata[256];
  
- 	hdw->vid_stream = pvr2_stream_create();
- 	if (!pvr2_hdw_dev_ok(hdw)) return;
-@@ -1945,25 +1733,25 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw)
+ 	/* video overlay */
+ 	struct v4l2_framebuffer    ovbuf;
+@@ -566,6 +579,12 @@ struct saa7134_dev {
  
- 	if (!pvr2_hdw_dev_ok(hdw)) return;
+ #define saa_wait(us) { udelay(us); }
  
--	/* Make sure everything is up to date */
--	pvr2_i2c_core_sync(hdw);
--
--	if (!pvr2_hdw_dev_ok(hdw)) return;
--
- 	hdw->flag_init_ok = !0;
++#define SAA7134_NORMS	(\
++		V4L2_STD_PAL    | V4L2_STD_PAL_N | \
++		V4L2_STD_PAL_Nc | V4L2_STD_SECAM | \
++		V4L2_STD_NTSC   | V4L2_STD_PAL_M | \
++		V4L2_STD_PAL_60)
 +
-+	pvr2_hdw_state_sched(hdw);
- }
- 
- 
--int pvr2_hdw_setup(struct pvr2_hdw *hdw)
-+/* Set up the structure and attempt to put the device into a usable state.
-+   This can be a time-consuming operation, which is why it is not done
-+   internally as part of the create() step. */
-+static void pvr2_hdw_setup(struct pvr2_hdw *hdw)
- {
- 	pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_setup(hdw=%p) begin",hdw);
--	LOCK_TAKE(hdw->big_lock); do {
-+	do {
- 		pvr2_hdw_setup_low(hdw);
- 		pvr2_trace(PVR2_TRACE_INIT,
- 			   "pvr2_hdw_setup(hdw=%p) done, ok=%d init_ok=%d",
--			   hdw,hdw->flag_ok,hdw->flag_init_ok);
-+			   hdw,pvr2_hdw_dev_ok(hdw),hdw->flag_init_ok);
- 		if (pvr2_hdw_dev_ok(hdw)) {
--			if (pvr2_hdw_init_ok(hdw)) {
-+			if (hdw->flag_init_ok) {
- 				pvr2_trace(
- 					PVR2_TRACE_INFO,
- 					"Device initialization"
-@@ -2013,9 +1801,8 @@ int pvr2_hdw_setup(struct pvr2_hdw *hdw)
- 				" the pvrusb2 device"
- 				" in order to recover.");
- 		}
--	} while (0); LOCK_GIVE(hdw->big_lock);
-+	} while (0);
- 	pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_setup(hdw=%p) end",hdw);
--	return hdw->flag_init_ok;
- }
- 
+ /* ----------------------------------------------------------- */
+ /* saa7134-core.c                                              */
  
-@@ -2026,24 +1813,32 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
- {
- 	unsigned int idx,cnt1,cnt2;
- 	struct pvr2_hdw *hdw;
--	unsigned int hdw_type;
- 	int valid_std_mask;
- 	struct pvr2_ctrl *cptr;
-+	const struct pvr2_device_desc *hdw_desc;
- 	__u8 ifnum;
- 	struct v4l2_queryctrl qctrl;
- 	struct pvr2_ctl_info *ciptr;
+@@ -596,9 +615,6 @@ void saa7134_buffer_next(struct saa7134_dev *dev, struct saa7134_dmaqueue *q);
+ void saa7134_buffer_timeout(unsigned long data);
+ void saa7134_dma_free(struct videobuf_queue *q,struct saa7134_buf *buf);
  
--	hdw_type = devid - pvr2_device_table;
--	if (hdw_type >= ARRAY_SIZE(pvr2_device_names)) {
--		pvr2_trace(PVR2_TRACE_ERROR_LEGS,
--			   "Bogus device type of %u reported",hdw_type);
--		return NULL;
--	}
-+	hdw_desc = (const struct pvr2_device_desc *)(devid->driver_info);
+-int saa7134_buffer_requeue(struct saa7134_dev *dev,
+-			 struct saa7134_dmaqueue *q);
+-
+ int saa7134_set_dmabits(struct saa7134_dev *dev);
  
- 	hdw = kzalloc(sizeof(*hdw),GFP_KERNEL);
- 	pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_create: hdw=%p, type \"%s\"",
--		   hdw,pvr2_device_names[hdw_type]);
-+		   hdw,hdw_desc->description);
- 	if (!hdw) goto fail;
-+
-+	init_timer(&hdw->quiescent_timer);
-+	hdw->quiescent_timer.data = (unsigned long)hdw;
-+	hdw->quiescent_timer.function = pvr2_hdw_quiescent_timeout;
-+
-+	init_timer(&hdw->encoder_wait_timer);
-+	hdw->encoder_wait_timer.data = (unsigned long)hdw;
-+	hdw->encoder_wait_timer.function = pvr2_hdw_encoder_wait_timeout;
-+
-+	hdw->master_state = PVR2_STATE_DEAD;
-+
-+	init_waitqueue_head(&hdw->state_wait_data);
-+
- 	hdw->tuner_signal_stale = !0;
- 	cx2341x_fill_defaults(&hdw->enc_ctl_state);
+ extern int (*saa7134_dmasound_init)(struct saa7134_dev *dev);
+@@ -628,16 +644,17 @@ void saa7134_i2c_call_clients(struct saa7134_dev *dev,
+ /* ----------------------------------------------------------- */
+ /* saa7134-video.c                                             */
  
-@@ -2052,7 +1847,7 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
- 	hdw->controls = kzalloc(sizeof(struct pvr2_ctrl) * hdw->control_cnt,
- 				GFP_KERNEL);
- 	if (!hdw->controls) goto fail;
--	hdw->hdw_type = hdw_type;
-+	hdw->hdw_desc = hdw_desc;
- 	for (idx = 0; idx < hdw->control_cnt; idx++) {
- 		cptr = hdw->controls + idx;
- 		cptr->hdw = hdw;
-@@ -2184,18 +1979,16 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
- 	if (cnt1 >= sizeof(hdw->name)) cnt1 = sizeof(hdw->name)-1;
- 	hdw->name[cnt1] = 0;
++extern unsigned int video_debug;
+ extern struct video_device saa7134_video_template;
+ extern struct video_device saa7134_radio_template;
  
-+	hdw->workqueue = create_singlethread_workqueue(hdw->name);
-+	INIT_WORK(&hdw->workpoll,pvr2_hdw_worker_poll);
-+	INIT_WORK(&hdw->worki2csync,pvr2_hdw_worker_i2c);
-+	INIT_WORK(&hdw->workinit,pvr2_hdw_worker_init);
+-void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm);
++int saa7134_g_ctrl(struct file *file, void *priv, struct v4l2_control *c);
++int saa7134_s_ctrl(struct file *file, void *f, struct v4l2_control *c);
++int saa7134_queryctrl(struct file *file, void *priv, struct v4l2_queryctrl *c);
 +
- 	pvr2_trace(PVR2_TRACE_INIT,"Driver unit number is %d, name is %s",
- 		   hdw->unit_number,hdw->name);
+ int saa7134_videoport_init(struct saa7134_dev *dev);
+ void saa7134_set_tvnorm_hw(struct saa7134_dev *dev);
  
- 	hdw->tuner_type = -1;
- 	hdw->flag_ok = !0;
--	/* Initialize the mask of subsystems that we will shut down when we
--	   stop streaming. */
--	hdw->subsys_stream_mask = PVR2_SUBSYS_RUN_ALL;
--	hdw->subsys_stream_mask |= (1<<PVR2_SUBSYS_B_ENC_CFG);
+-int saa7134_common_ioctl(struct saa7134_dev *dev,
+-			 unsigned int cmd, void *arg);
 -
--	pvr2_trace(PVR2_TRACE_INIT,"subsys_stream_mask: 0x%lx",
--		   hdw->subsys_stream_mask);
- 
- 	hdw->usb_intf = intf;
- 	hdw->usb_dev = interface_to_usbdev(intf);
-@@ -2211,15 +2004,25 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
- 	mutex_init(&hdw->ctl_lock_mutex);
- 	mutex_init(&hdw->big_lock_mutex);
- 
-+	queue_work(hdw->workqueue,&hdw->workinit);
- 	return hdw;
-  fail:
- 	if (hdw) {
-+		del_timer_sync(&hdw->quiescent_timer);
-+		del_timer_sync(&hdw->encoder_wait_timer);
-+		if (hdw->workqueue) {
-+			flush_workqueue(hdw->workqueue);
-+			destroy_workqueue(hdw->workqueue);
-+			hdw->workqueue = NULL;
-+		}
- 		usb_free_urb(hdw->ctl_read_urb);
- 		usb_free_urb(hdw->ctl_write_urb);
- 		kfree(hdw->ctl_read_buffer);
- 		kfree(hdw->ctl_write_buffer);
- 		kfree(hdw->controls);
- 		kfree(hdw->mpeg_ctrl_info);
-+		kfree(hdw->std_defs);
-+		kfree(hdw->std_enum_names);
- 		kfree(hdw);
- 	}
- 	return NULL;
-@@ -2250,10 +2053,10 @@ static void pvr2_hdw_remove_usb_stuff(struct pvr2_hdw *hdw)
- 		kfree(hdw->ctl_write_buffer);
- 		hdw->ctl_write_buffer = NULL;
- 	}
--	pvr2_hdw_render_useless_unlocked(hdw);
- 	hdw->flag_disconnected = !0;
- 	hdw->usb_dev = NULL;
- 	hdw->usb_intf = NULL;
-+	pvr2_hdw_render_useless(hdw);
- }
+ int saa7134_video_init1(struct saa7134_dev *dev);
+ int saa7134_video_init2(struct saa7134_dev *dev);
+ void saa7134_irq_video_signalchange(struct saa7134_dev *dev);
+@@ -682,6 +699,7 @@ void saa7134_tvaudio_setinput(struct saa7134_dev *dev,
+ void saa7134_tvaudio_setvolume(struct saa7134_dev *dev, int level);
+ int saa7134_tvaudio_getstereo(struct saa7134_dev *dev);
  
++void saa7134_tvaudio_init(struct saa7134_dev *dev);
+ int saa7134_tvaudio_init2(struct saa7134_dev *dev);
+ int saa7134_tvaudio_fini(struct saa7134_dev *dev);
+ int saa7134_tvaudio_do_scan(struct saa7134_dev *dev);
+diff --git a/drivers/media/video/sn9c102/Makefile b/drivers/media/video/sn9c102/Makefile
+index a56d16f..7ecd5a9 100644
+--- a/drivers/media/video/sn9c102/Makefile
++++ b/drivers/media/video/sn9c102/Makefile
+@@ -3,6 +3,7 @@ sn9c102-objs := sn9c102_core.o \
+ 		sn9c102_hv7131r.o \
+ 		sn9c102_mi0343.o \
+ 		sn9c102_mi0360.o \
++		sn9c102_mt9v111.o \
+ 		sn9c102_ov7630.o \
+ 		sn9c102_ov7660.o \
+ 		sn9c102_pas106b.o \
+diff --git a/drivers/media/video/sn9c102/sn9c102_core.c b/drivers/media/video/sn9c102/sn9c102_core.c
+index 5118479..c40ba3a 100644
+--- a/drivers/media/video/sn9c102/sn9c102_core.c
++++ b/drivers/media/video/sn9c102/sn9c102_core.c
+@@ -47,7 +47,7 @@
+ #define SN9C102_MODULE_AUTHOR   "(C) 2004-2007 Luca Risolia"
+ #define SN9C102_AUTHOR_EMAIL    "<luca.risolia at studio.unibo.it>"
+ #define SN9C102_MODULE_LICENSE  "GPL"
+-#define SN9C102_MODULE_VERSION  "1:1.47"
++#define SN9C102_MODULE_VERSION  "1:1.47pre49"
+ #define SN9C102_MODULE_VERSION_CODE  KERNEL_VERSION(1, 1, 47)
  
-@@ -2262,6 +2065,13 @@ void pvr2_hdw_destroy(struct pvr2_hdw *hdw)
- {
- 	if (!hdw) return;
- 	pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_destroy: hdw=%p",hdw);
-+	del_timer_sync(&hdw->quiescent_timer);
-+	del_timer_sync(&hdw->encoder_wait_timer);
-+	if (hdw->workqueue) {
-+		flush_workqueue(hdw->workqueue);
-+		destroy_workqueue(hdw->workqueue);
-+		hdw->workqueue = NULL;
-+	}
- 	if (hdw->fw_buffer) {
- 		kfree(hdw->fw_buffer);
- 		hdw->fw_buffer = NULL;
-@@ -2290,12 +2100,6 @@ void pvr2_hdw_destroy(struct pvr2_hdw *hdw)
- }
+ /*****************************************************************************/
+@@ -3322,7 +3322,6 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
+ 	cam->v4ldev->fops = &sn9c102_fops;
+ 	cam->v4ldev->minor = video_nr[dev_nr];
+ 	cam->v4ldev->release = video_device_release;
+-	video_set_drvdata(cam->v4ldev, cam);
  
+ 	init_completion(&cam->probe);
  
--int pvr2_hdw_init_ok(struct pvr2_hdw *hdw)
--{
--	return hdw->flag_init_ok;
--}
--
--
- int pvr2_hdw_dev_ok(struct pvr2_hdw *hdw)
- {
- 	return (hdw && hdw->flag_ok);
-@@ -2473,17 +2277,11 @@ static const char *get_ctrl_typename(enum pvr2_ctl_type tp)
- }
+@@ -3340,6 +3339,7 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
  
+ 	DBG(2, "V4L2 device registered as /dev/video%d", cam->v4ldev->minor);
  
--/* Commit all control changes made up to this point.  Subsystems can be
--   indirectly affected by these changes.  For a given set of things being
--   committed, we'll clear the affected subsystem bits and then once we're
--   done committing everything we'll make a request to restore the subsystem
--   state(s) back to their previous value before this function was called.
--   Thus we can automatically reconfigure affected pieces of the driver as
--   controls are changed. */
--static int pvr2_hdw_commit_ctl_internal(struct pvr2_hdw *hdw)
-+/* Figure out if we need to commit control changes.  If so, mark internal
-+   state flags to indicate this fact and return true.  Otherwise do nothing
-+   else and return false. */
-+static int pvr2_hdw_commit_setup(struct pvr2_hdw *hdw)
- {
--	unsigned long saved_subsys_mask = hdw->subsys_enabled_mask;
--	unsigned long stale_subsys_mask = 0;
- 	unsigned int idx;
- 	struct pvr2_ctrl *cptr;
- 	int value;
-@@ -2518,6 +2316,25 @@ static int pvr2_hdw_commit_ctl_internal(struct pvr2_hdw *hdw)
- 		return 0;
- 	}
++	video_set_drvdata(cam->v4ldev, cam);
+ 	cam->module_param.force_munmap = force_munmap[dev_nr];
+ 	cam->module_param.frame_timeout = frame_timeout[dev_nr];
  
-+	hdw->state_pipeline_config = 0;
-+	trace_stbit("state_pipeline_config",hdw->state_pipeline_config);
-+	pvr2_hdw_state_sched(hdw);
+diff --git a/drivers/media/video/sn9c102/sn9c102_devtable.h b/drivers/media/video/sn9c102/sn9c102_devtable.h
+index 916054f..35223e0 100644
+--- a/drivers/media/video/sn9c102/sn9c102_devtable.h
++++ b/drivers/media/video/sn9c102/sn9c102_devtable.h
+@@ -126,6 +126,7 @@ extern int sn9c102_probe_hv7131d(struct sn9c102_device* cam);
+ extern int sn9c102_probe_hv7131r(struct sn9c102_device* cam);
+ extern int sn9c102_probe_mi0343(struct sn9c102_device* cam);
+ extern int sn9c102_probe_mi0360(struct sn9c102_device* cam);
++extern int sn9c102_probe_mt9v111(struct sn9c102_device *cam);
+ extern int sn9c102_probe_ov7630(struct sn9c102_device* cam);
+ extern int sn9c102_probe_ov7660(struct sn9c102_device* cam);
+ extern int sn9c102_probe_pas106b(struct sn9c102_device* cam);
+@@ -144,6 +145,7 @@ static int (*sn9c102_sensor_table[])(struct sn9c102_device*) = {
+ 	&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 */
+diff --git a/drivers/media/video/sn9c102/sn9c102_mt9v111.c b/drivers/media/video/sn9c102/sn9c102_mt9v111.c
+new file mode 100644
+index 0000000..3b98ac3
+--- /dev/null
++++ b/drivers/media/video/sn9c102/sn9c102_mt9v111.c
+@@ -0,0 +1,259 @@
++/***************************************************************************
++ * Plug-in for MT9V111 image sensor connected to the SN9C1xx PC Camera     *
++ * Controllers                                                             *
++ *                                                                         *
++ * Copyright (C) 2007 by Luca Risolia <luca.risolia at studio.unibo.it>       *
++ *                                                                         *
++ * This program is free software; you can redistribute it and/or modify    *
++ * it under the terms of the GNU General Public License as published by    *
++ * the Free Software Foundation; either version 2 of the License, or       *
++ * (at your option) any later version.                                     *
++ *                                                                         *
++ * This program is distributed in the hope that it will be useful,         *
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
++ * GNU General Public License for more details.                            *
++ *                                                                         *
++ * You 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.               *
++ ***************************************************************************/
 +
-+	return !0;
-+}
++#include "sn9c102_sensor.h"
 +
 +
-+/* Perform all operations needed to commit all control changes.  This must
-+   be performed in synchronization with the pipeline state and is thus
-+   expected to be called as part of the driver's worker thread.  Return
-+   true if commit successful, otherwise return false to indicate that
-+   commit isn't possible at this time. */
-+static int pvr2_hdw_commit_execute(struct pvr2_hdw *hdw)
++static int mt9v111_init(struct sn9c102_device *cam)
 +{
-+	unsigned int idx;
-+	struct pvr2_ctrl *cptr;
-+	int disruptive_change;
++	struct sn9c102_sensor *s = sn9c102_get_sensor(cam);
++	int err = 0;
 +
- 	/* When video standard changes, reset the hres and vres values -
- 	   but if the user has pending changes there, then let the changes
- 	   take priority. */
-@@ -2536,24 +2353,26 @@ static int pvr2_hdw_commit_ctl_internal(struct pvr2_hdw *hdw)
- 		}
- 	}
- 
--	if (hdw->std_dirty ||
--	    hdw->enc_stale ||
--	    hdw->srate_dirty ||
--	    hdw->res_ver_dirty ||
--	    hdw->res_hor_dirty ||
--	    0) {
--		/* If any of this changes, then the encoder needs to be
--		   reconfigured, and we need to reset the stream. */
--		stale_subsys_mask |= (1<<PVR2_SUBSYS_B_ENC_CFG);
--	}
--
--	if (hdw->input_dirty) {
--		/* pk: If input changes to or from radio, then the encoder
--		   needs to be restarted (for ENC_MUTE_VIDEO to work) */
--		stale_subsys_mask |= (1<<PVR2_SUBSYS_B_ENC_RUN);
-+	/* 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
-+	   can proceed. */
-+	disruptive_change =
-+		(hdw->std_dirty ||
-+		 hdw->enc_unsafe_stale ||
-+		 hdw->srate_dirty ||
-+		 hdw->res_ver_dirty ||
-+		 hdw->res_hor_dirty ||
-+		 hdw->input_dirty ||
-+		 (hdw->active_stream_type != hdw->desired_stream_type));
-+	if (disruptive_change && !hdw->state_pipeline_idle) {
-+		/* Pipeline is not idle; we can't proceed.  Arrange to
-+		   cause pipeline to stop so that we can try this again
-+		   later.... */
-+		hdw->state_pipeline_pause = !0;
++	err = sn9c102_write_const_regs(cam, {0x44, 0x01}, {0x40, 0x02},
++				       {0x00, 0x03}, {0x1a, 0x04},
++				       {0x1f, 0x05}, {0x20, 0x06},
++				       {0x1f, 0x07}, {0x81, 0x08},
++				       {0x5c, 0x09}, {0x00, 0x0a},
++				       {0x00, 0x0b}, {0x00, 0x0c},
++				       {0x00, 0x0d}, {0x00, 0x0e},
++				       {0x00, 0x0f}, {0x03, 0x10},
++				       {0x00, 0x11}, {0x00, 0x12},
++				       {0x02, 0x13}, {0x14, 0x14},
++				       {0x28, 0x15}, {0x1e, 0x16},
++				       {0xe2, 0x17}, {0x06, 0x18},
++				       {0x00, 0x19}, {0x00, 0x1a},
++				       {0x00, 0x1b}, {0x08, 0x20},
++				       {0x39, 0x21}, {0x51, 0x22},
++				       {0x63, 0x23}, {0x73, 0x24},
++				       {0x82, 0x25}, {0x8f, 0x26},
++				       {0x9b, 0x27}, {0xa7, 0x28},
++				       {0xb1, 0x29}, {0xbc, 0x2a},
++				       {0xc6, 0x2b}, {0xcf, 0x2c},
++				       {0xd8, 0x2d}, {0xe1, 0x2e},
++				       {0xea, 0x2f}, {0xf2, 0x30},
++				       {0x13, 0x84}, {0x00, 0x85},
++				       {0x25, 0x86}, {0x00, 0x87},
++				       {0x07, 0x88}, {0x00, 0x89},
++				       {0xee, 0x8a}, {0x0f, 0x8b},
++				       {0xe5, 0x8c}, {0x0f, 0x8d},
++				       {0x2e, 0x8e}, {0x00, 0x8f},
++				       {0x30, 0x90}, {0x00, 0x91},
++				       {0xd4, 0x92}, {0x0f, 0x93},
++				       {0xfc, 0x94}, {0x0f, 0x95},
++				       {0x14, 0x96}, {0x00, 0x97},
++				       {0x00, 0x98}, {0x60, 0x99},
++				       {0x07, 0x9a}, {0x40, 0x9b},
++				       {0x20, 0x9c}, {0x00, 0x9d},
++				       {0x00, 0x9e}, {0x00, 0x9f},
++				       {0x2d, 0xc0}, {0x2d, 0xc1},
++				       {0x3a, 0xc2}, {0x05, 0xc3},
++				       {0x04, 0xc4}, {0x3f, 0xc5},
++				       {0x00, 0xc6}, {0x00, 0xc7},
++				       {0x50, 0xc8}, {0x3c, 0xc9},
++				       {0x28, 0xca}, {0xd8, 0xcb},
++				       {0x14, 0xcc}, {0xec, 0xcd},
++				       {0x32, 0xce}, {0xdd, 0xcf},
++				       {0x2d, 0xd0}, {0xdd, 0xd1},
++				       {0x6a, 0xd2}, {0x50, 0xd3},
++				       {0x60, 0xd4}, {0x00, 0xd5},
++				       {0x00, 0xd6});
++
++	err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x01,
++					 0x00, 0x01, 0, 0);
++	err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x0d,
++					 0x00, 0x01, 0, 0);
++	err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x0d,
++					 0x00, 0x00, 0, 0);
++	err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x08,
++					 0x04, 0x80, 0, 0);
++	err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x01,
++					 0x00, 0x04, 0, 0);
++	err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x08,
++					 0x00, 0x08, 0, 0);
++	err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x02,
++					 0x00, 0x16, 0, 0);
++	err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x03,
++					 0x01, 0xe7, 0, 0);
++	err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x04,
++					 0x02, 0x87, 0, 0);
++	err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x06,
++					 0x00, 0x40, 0, 0);
++	err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x05,
++					 0x00, 0x09, 0, 0);
++	err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x07,
++					 0x30, 0x02, 0, 0);
++	err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x0c,
++					 0x00, 0x00, 0, 0);
++	err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x12,
++					 0x00, 0xb0, 0, 0);
++	err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x13,
++					 0x00, 0x7c, 0, 0);
++	err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x1e,
++					 0x00, 0x00, 0, 0);
++	err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x20,
++					 0x00, 0x00, 0, 0);
++	err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x20,
++					 0x00, 0x00, 0, 0);
++	err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x01,
++					 0x00, 0x04, 0, 0);
++
++	return err;
++}
++
++static int mt9v111_get_ctrl(struct sn9c102_device *cam,
++			    struct v4l2_control *ctrl)
++{
++	struct sn9c102_sensor *s = sn9c102_get_sensor(cam);
++	u8 data[2];
++	int err = 0;
++
++	switch (ctrl->id) {
++	case V4L2_CID_VFLIP:
++		if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x20, 2,
++					     data) < 0)
++			return -EIO;
++		ctrl->value = data[1] & 0x80 ? 1 : 0;
 +		return 0;
- 	}
- 
--
- 	if (hdw->srate_dirty) {
- 		/* Write new sample rate into control structure since
- 		 * the master copy is stale.  We must track srate
-@@ -2582,51 +2401,88 @@ static int pvr2_hdw_commit_ctl_internal(struct pvr2_hdw *hdw)
- 		cptr->info->clear_dirty(cptr);
- 	}
- 
-+	if (hdw->active_stream_type != hdw->desired_stream_type) {
-+		/* Handle any side effects of stream config here */
-+		hdw->active_stream_type = hdw->desired_stream_type;
++	default:
++		return -EINVAL;
 +	}
 +
- 	/* Now execute i2c core update */
- 	pvr2_i2c_core_sync(hdw);
- 
--	pvr2_hdw_subsys_bit_chg_no_lock(hdw,stale_subsys_mask,0);
--	pvr2_hdw_subsys_bit_chg_no_lock(hdw,~0,saved_subsys_mask);
-+	if (hdw->state_encoder_run) {
-+		/* If encoder isn't running, then this will get worked out
-+		   later when we start the encoder. */
-+		if (pvr2_encoder_adjust(hdw) < 0) return !0;
++	return err ? -EIO : 0;
++}
++
++static int mt9v111_set_ctrl(struct sn9c102_device *cam,
++			    const struct v4l2_control *ctrl)
++{
++	struct sn9c102_sensor *s = sn9c102_get_sensor(cam);
++	int err = 0;
++
++	switch (ctrl->id) {
++	case V4L2_CID_VFLIP:
++		err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
++						 0x20,
++						 ctrl->value ? 0x80 : 0x00,
++						 ctrl->value ? 0x80 : 0x00, 0,
++						 0);
++		break;
++	default:
++		return -EINVAL;
 +	}
- 
--	return 0;
-+	hdw->state_pipeline_config = !0;
-+	trace_stbit("state_pipeline_config",hdw->state_pipeline_config);
-+	return !0;
- }
- 
- 
- int pvr2_hdw_commit_ctl(struct pvr2_hdw *hdw)
- {
-+	int fl;
-+	LOCK_TAKE(hdw->big_lock);
-+	fl = pvr2_hdw_commit_setup(hdw);
-+	LOCK_GIVE(hdw->big_lock);
-+	if (!fl) return 0;
-+	return pvr2_hdw_wait(hdw,0);
++
++	return err ? -EIO : 0;
 +}
 +
++static int mt9v111_set_crop(struct sn9c102_device *cam,
++			    const struct v4l2_rect *rect)
++{
++	struct sn9c102_sensor *s = sn9c102_get_sensor(cam);
++	int err = 0;
++	u8 v_start = (u8) (rect->top - s->cropcap.bounds.top) + 2;
++
++	err += sn9c102_write_reg(cam, v_start, 0x13);
 +
-+static void pvr2_hdw_worker_i2c(struct work_struct *work)
++	return err;
++}
++
++static int mt9v111_set_pix_format(struct sn9c102_device *cam,
++				  const struct v4l2_pix_format *pix)
 +{
-+	struct pvr2_hdw *hdw = container_of(work,struct pvr2_hdw,worki2csync);
- 	LOCK_TAKE(hdw->big_lock); do {
--		pvr2_hdw_commit_ctl_internal(hdw);
-+		pvr2_i2c_core_sync(hdw);
- 	} while (0); LOCK_GIVE(hdw->big_lock);
--	return 0;
- }
- 
- 
--void pvr2_hdw_poll(struct pvr2_hdw *hdw)
-+static void pvr2_hdw_worker_poll(struct work_struct *work)
- {
-+	int fl = 0;
-+	struct pvr2_hdw *hdw = container_of(work,struct pvr2_hdw,workpoll);
- 	LOCK_TAKE(hdw->big_lock); do {
--		pvr2_i2c_core_sync(hdw);
-+		fl = pvr2_hdw_state_eval(hdw);
- 	} while (0); LOCK_GIVE(hdw->big_lock);
-+	if (fl && hdw->state_func) {
-+		hdw->state_func(hdw->state_data);
++	int err = 0;
++
++	if (pix->pixelformat == V4L2_PIX_FMT_SBGGR8) {
++		err += sn9c102_write_reg(cam, 0xb4, 0x17);
++	} else {
++		err += sn9c102_write_reg(cam, 0xe2, 0x17);
 +	}
- }
- 
- 
--void pvr2_hdw_setup_poll_trigger(struct pvr2_hdw *hdw,
--				 void (*func)(void *),
--				 void *data)
-+static void pvr2_hdw_worker_init(struct work_struct *work)
- {
-+	struct pvr2_hdw *hdw = container_of(work,struct pvr2_hdw,workinit);
- 	LOCK_TAKE(hdw->big_lock); do {
--		hdw->poll_trigger_func = func;
--		hdw->poll_trigger_data = data;
-+		pvr2_hdw_setup(hdw);
- 	} while (0); LOCK_GIVE(hdw->big_lock);
- }
- 
- 
--void pvr2_hdw_poll_trigger_unlocked(struct pvr2_hdw *hdw)
-+static int pvr2_hdw_wait(struct pvr2_hdw *hdw,int state)
- {
--	if (hdw->poll_trigger_func) {
--		hdw->poll_trigger_func(hdw->poll_trigger_data);
--	}
-+	return wait_event_interruptible(
-+		hdw->state_wait_data,
-+		(hdw->state_stale == 0) &&
-+		(!state || (hdw->master_state != state)));
- }
- 
 +
-+void pvr2_hdw_set_state_callback(struct pvr2_hdw *hdw,
-+				 void (*callback_func)(void *),
-+				 void *callback_data)
++	return err;
++}
++
++
++static const struct sn9c102_sensor mt9v111 = {
++	.name = "MT9V111",
++	.maintainer = "Luca Risolia <luca.risolia at studio.unibo.it>",
++	.supported_bridge = BRIDGE_SN9C105 | BRIDGE_SN9C120,
++	.frequency = SN9C102_I2C_100KHZ,
++	.interface = SN9C102_I2C_2WIRES,
++	.i2c_slave_id = 0x5c,
++	.init = &mt9v111_init,
++	.qctrl = {
++		{
++			.id = V4L2_CID_VFLIP,
++			.type = V4L2_CTRL_TYPE_BOOLEAN,
++			.name = "vertical mirror",
++			.minimum = 0,
++			.maximum = 1,
++			.step = 1,
++			.default_value = 0,
++			.flags = 0,
++		},
++	},
++	.get_ctrl = &mt9v111_get_ctrl,
++	.set_ctrl = &mt9v111_set_ctrl,
++	.cropcap = {
++		.bounds = {
++			.left = 0,
++			.top = 0,
++			.width = 640,
++			.height = 480,
++		},
++		.defrect = {
++			.left = 0,
++			.top = 0,
++			.width = 640,
++			.height = 480,
++		},
++	},
++	.set_crop = &mt9v111_set_crop,
++	.pix_format = {
++		.width = 640,
++		.height = 480,
++		.pixelformat = V4L2_PIX_FMT_SBGGR8,
++		.priv = 8,
++	},
++	.set_pix_format = &mt9v111_set_pix_format
++};
++
++
++int sn9c102_probe_mt9v111(struct sn9c102_device *cam)
 +{
-+	LOCK_TAKE(hdw->big_lock); do {
-+		hdw->state_data = callback_data;
-+		hdw->state_func = callback_func;
-+	} while (0); LOCK_GIVE(hdw->big_lock);
++	u8 data[2];
++	int err = 0;
++
++	err += sn9c102_write_const_regs(cam, {0x01, 0xf1}, {0x00, 0xf1},
++					{0x29, 0x01}, {0x42, 0x17},
++					{0x62, 0x17}, {0x08, 0x01});
++	err += sn9c102_i2c_try_raw_write(cam, &mt9v111, 4,
++					 mt9v111.i2c_slave_id, 0x01, 0x00,
++					 0x04, 0, 0);
++	if (err || sn9c102_i2c_try_raw_read(cam, &mt9v111,
++					    mt9v111.i2c_slave_id, 0x36, 2,
++					    data) < 0)
++		return -EIO;
++
++	if (data[0] != 0x82 || data[1] != 0x3a)
++		return -ENODEV;
++
++	sn9c102_attach_sensor(cam, &mt9v111);
++
++	return 0;
 +}
+diff --git a/drivers/media/video/stk-sensor.c b/drivers/media/video/stk-sensor.c
+new file mode 100644
+index 0000000..4a9a0b6
+--- /dev/null
++++ b/drivers/media/video/stk-sensor.c
+@@ -0,0 +1,578 @@
++/* stk-sensor.c: Driver for ov96xx sensor (used in some Syntek webcams)
++ *
++ * Copyright 2007-2008 Jaime Velasco Juan <jsagarribay at gmail.com>
++ *
++ * Some parts derived from ov7670.c:
++ * Copyright 2006 One Laptop Per Child Association, Inc.  Written
++ * by Jonathan Corbet with substantial inspiration from Mark
++ * McClelland's ovcamchip code.
++ *
++ * Copyright 2006-7 Jonathan Corbet <corbet at lwn.net>
++ *
++ * This file may be distributed under the terms of the GNU General
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You 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.
++ */
++
++/* Controlling the sensor via the STK1125 vendor specific control interface:
++ * The camera uses an OmniVision sensor and the stk1125 provides an
++ * SCCB(i2c)-USB bridge which let us program the sensor.
++ * In my case the sensor id is 0x9652, it can be read from sensor's register
++ * 0x0A and 0x0B as follows:
++ * - read register #R:
++ *   output #R to index 0x0208
++ *   output 0x0070 to index 0x0200
++ *   input 1 byte from index 0x0201 (some kind of status register)
++ *     until its value is 0x01
++ *   input 1 byte from index 0x0209. This is the value of #R
++ * - write value V to register #R
++ *   output #R to index 0x0204
++ *   output V to index 0x0205
++ *   output 0x0005 to index 0x0200
++ *   input 1 byte from index 0x0201 until its value becomes 0x04
++ */
++
++/* It seems the i2c bus is controlled with these registers */
++
++#include "stk-webcam.h"
++
++#define STK_IIC_BASE		(0x0200)
++#  define STK_IIC_OP		(STK_IIC_BASE)
++#    define STK_IIC_OP_TX	(0x05)
++#    define STK_IIC_OP_RX	(0x70)
++#  define STK_IIC_STAT		(STK_IIC_BASE+1)
++#    define STK_IIC_STAT_TX_OK	(0x04)
++#    define STK_IIC_STAT_RX_OK	(0x01)
++/* I don't know what does this register.
++ * when it is 0x00 or 0x01, we cannot talk to the sensor,
++ * other values work */
++#  define STK_IIC_ENABLE	(STK_IIC_BASE+2)
++#    define STK_IIC_ENABLE_NO	(0x00)
++/* This is what the driver writes in windows */
++#    define STK_IIC_ENABLE_YES	(0x1e)
++/*
++ * Address of the slave. Seems like the binary driver look for the
++ * sensor in multiple places, attempting a reset sequence.
++ * We only know about the ov9650
++ */
++#  define STK_IIC_ADDR		(STK_IIC_BASE+3)
++#  define STK_IIC_TX_INDEX	(STK_IIC_BASE+4)
++#  define STK_IIC_TX_VALUE	(STK_IIC_BASE+5)
++#  define STK_IIC_RX_INDEX	(STK_IIC_BASE+8)
++#  define STK_IIC_RX_VALUE	(STK_IIC_BASE+9)
++
++#define MAX_RETRIES		(50)
++
++#define SENSOR_ADDRESS		(0x60)
++
++/* From ov7670.c (These registers aren't fully accurate) */
++
++/* Registers */
++#define REG_GAIN	0x00	/* Gain lower 8 bits (rest in vref) */
++#define REG_BLUE	0x01	/* blue gain */
++#define REG_RED		0x02	/* red gain */
++#define REG_VREF	0x03	/* Pieces of GAIN, VSTART, VSTOP */
++#define REG_COM1	0x04	/* Control 1 */
++#define  COM1_CCIR656	  0x40  /* CCIR656 enable */
++#define  COM1_QFMT	  0x20  /* QVGA/QCIF format */
++#define  COM1_SKIP_0	  0x00  /* Do not skip any row */
++#define  COM1_SKIP_2	  0x04  /* Skip 2 rows of 4 */
++#define  COM1_SKIP_3	  0x08  /* Skip 3 rows of 4 */
++#define REG_BAVE	0x05	/* U/B Average level */
++#define REG_GbAVE	0x06	/* Y/Gb Average level */
++#define REG_AECHH	0x07	/* AEC MS 5 bits */
++#define REG_RAVE	0x08	/* V/R Average level */
++#define REG_COM2	0x09	/* Control 2 */
++#define  COM2_SSLEEP	  0x10	/* Soft sleep mode */
++#define REG_PID		0x0a	/* Product ID MSB */
++#define REG_VER		0x0b	/* Product ID LSB */
++#define REG_COM3	0x0c	/* Control 3 */
++#define  COM3_SWAP	  0x40	  /* Byte swap */
++#define  COM3_SCALEEN	  0x08	  /* Enable scaling */
++#define  COM3_DCWEN	  0x04	  /* Enable downsamp/crop/window */
++#define REG_COM4	0x0d	/* Control 4 */
++#define REG_COM5	0x0e	/* All "reserved" */
++#define REG_COM6	0x0f	/* Control 6 */
++#define REG_AECH	0x10	/* More bits of AEC value */
++#define REG_CLKRC	0x11	/* Clock control */
++#define   CLK_PLL	  0x80	  /* Enable internal PLL */
++#define   CLK_EXT	  0x40	  /* Use external clock directly */
++#define   CLK_SCALE	  0x3f	  /* Mask for internal clock scale */
++#define REG_COM7	0x12	/* Control 7 */
++#define   COM7_RESET	  0x80	  /* Register reset */
++#define   COM7_FMT_MASK	  0x38
++#define   COM7_FMT_SXGA	  0x00
++#define   COM7_FMT_VGA	  0x40
++#define	  COM7_FMT_CIF	  0x20	  /* CIF format */
++#define   COM7_FMT_QVGA	  0x10	  /* QVGA format */
++#define   COM7_FMT_QCIF	  0x08	  /* QCIF format */
++#define	  COM7_RGB	  0x04	  /* bits 0 and 2 - RGB format */
++#define	  COM7_YUV	  0x00	  /* YUV */
++#define	  COM7_BAYER	  0x01	  /* Bayer format */
++#define	  COM7_PBAYER	  0x05	  /* "Processed bayer" */
++#define REG_COM8	0x13	/* Control 8 */
++#define   COM8_FASTAEC	  0x80	  /* Enable fast AGC/AEC */
++#define   COM8_AECSTEP	  0x40	  /* Unlimited AEC step size */
++#define   COM8_BFILT	  0x20	  /* Band filter enable */
++#define   COM8_AGC	  0x04	  /* Auto gain enable */
++#define   COM8_AWB	  0x02	  /* White balance enable */
++#define   COM8_AEC	  0x01	  /* Auto exposure enable */
++#define REG_COM9	0x14	/* Control 9  - gain ceiling */
++#define REG_COM10	0x15	/* Control 10 */
++#define   COM10_HSYNC	  0x40	  /* HSYNC instead of HREF */
++#define   COM10_PCLK_HB	  0x20	  /* Suppress PCLK on horiz blank */
++#define   COM10_HREF_REV  0x08	  /* Reverse HREF */
++#define   COM10_VS_LEAD	  0x04	  /* VSYNC on clock leading edge */
++#define   COM10_VS_NEG	  0x02	  /* VSYNC negative */
++#define   COM10_HS_NEG	  0x01	  /* HSYNC negative */
++#define REG_HSTART	0x17	/* Horiz start high bits */
++#define REG_HSTOP	0x18	/* Horiz stop high bits */
++#define REG_VSTART	0x19	/* Vert start high bits */
++#define REG_VSTOP	0x1a	/* Vert stop high bits */
++#define REG_PSHFT	0x1b	/* Pixel delay after HREF */
++#define REG_MIDH	0x1c	/* Manuf. ID high */
++#define REG_MIDL	0x1d	/* Manuf. ID low */
++#define REG_MVFP	0x1e	/* Mirror / vflip */
++#define   MVFP_MIRROR	  0x20	  /* Mirror image */
++#define   MVFP_FLIP	  0x10	  /* Vertical flip */
++
++#define REG_AEW		0x24	/* AGC upper limit */
++#define REG_AEB		0x25	/* AGC lower limit */
++#define REG_VPT		0x26	/* AGC/AEC fast mode op region */
++#define REG_ADVFL	0x2d	/* Insert dummy lines (LSB) */
++#define REG_ADVFH	0x2e	/* Insert dummy lines (MSB) */
++#define REG_HSYST	0x30	/* HSYNC rising edge delay */
++#define REG_HSYEN	0x31	/* HSYNC falling edge delay */
++#define REG_HREF	0x32	/* HREF pieces */
++#define REG_TSLB	0x3a	/* lots of stuff */
++#define   TSLB_YLAST	  0x04	  /* UYVY or VYUY - see com13 */
++#define   TSLB_BYTEORD	  0x08	  /* swap bytes in 16bit mode? */
++#define REG_COM11	0x3b	/* Control 11 */
++#define   COM11_NIGHT	  0x80	  /* NIght mode enable */
++#define   COM11_NMFR	  0x60	  /* Two bit NM frame rate */
++#define   COM11_HZAUTO	  0x10	  /* Auto detect 50/60 Hz */
++#define	  COM11_50HZ	  0x08	  /* Manual 50Hz select */
++#define   COM11_EXP	  0x02
++#define REG_COM12	0x3c	/* Control 12 */
++#define   COM12_HREF	  0x80	  /* HREF always */
++#define REG_COM13	0x3d	/* Control 13 */
++#define   COM13_GAMMA	  0x80	  /* Gamma enable */
++#define	  COM13_UVSAT	  0x40	  /* UV saturation auto adjustment */
++#define	  COM13_CMATRIX	  0x10	  /* Enable color matrix for RGB or YUV */
++#define   COM13_UVSWAP	  0x01	  /* V before U - w/TSLB */
++#define REG_COM14	0x3e	/* Control 14 */
++#define   COM14_DCWEN	  0x10	  /* DCW/PCLK-scale enable */
++#define REG_EDGE	0x3f	/* Edge enhancement factor */
++#define REG_COM15	0x40	/* Control 15 */
++#define   COM15_R10F0	  0x00	  /* Data range 10 to F0 */
++#define	  COM15_R01FE	  0x80	  /*            01 to FE */
++#define   COM15_R00FF	  0xc0	  /*            00 to FF */
++#define   COM15_RGB565	  0x10	  /* RGB565 output */
++#define   COM15_RGBFIXME	  0x20	  /* FIXME  */
++#define   COM15_RGB555	  0x30	  /* RGB555 output */
++#define REG_COM16	0x41	/* Control 16 */
++#define   COM16_AWBGAIN   0x08	  /* AWB gain enable */
++#define REG_COM17	0x42	/* Control 17 */
++#define   COM17_AECWIN	  0xc0	  /* AEC window - must match COM4 */
++#define   COM17_CBAR	  0x08	  /* DSP Color bar */
++
++/*
++ * This matrix defines how the colors are generated, must be
++ * tweaked to adjust hue and saturation.
++ *
++ * Order: v-red, v-green, v-blue, u-red, u-green, u-blue
++ *
++ * They are nine-bit signed quantities, with the sign bit
++ * stored in 0x58.  Sign for v-red is bit 0, and up from there.
++ */
++#define	REG_CMATRIX_BASE 0x4f
++#define   CMATRIX_LEN 6
++#define REG_CMATRIX_SIGN 0x58
++
++
++#define REG_BRIGHT	0x55	/* Brightness */
++#define REG_CONTRAS	0x56	/* Contrast control */
++
++#define REG_GFIX	0x69	/* Fix gain control */
++
++#define REG_RGB444	0x8c	/* RGB 444 control */
++#define   R444_ENABLE	  0x02	  /* Turn on RGB444, overrides 5x5 */
++#define   R444_RGBX	  0x01	  /* Empty nibble at end */
++
++#define REG_HAECC1	0x9f	/* Hist AEC/AGC control 1 */
++#define REG_HAECC2	0xa0	/* Hist AEC/AGC control 2 */
++
++#define REG_BD50MAX	0xa5	/* 50hz banding step limit */
++#define REG_HAECC3	0xa6	/* Hist AEC/AGC control 3 */
++#define REG_HAECC4	0xa7	/* Hist AEC/AGC control 4 */
++#define REG_HAECC5	0xa8	/* Hist AEC/AGC control 5 */
++#define REG_HAECC6	0xa9	/* Hist AEC/AGC control 6 */
++#define REG_HAECC7	0xaa	/* Hist AEC/AGC control 7 */
++#define REG_BD60MAX	0xab	/* 60hz banding step limit */
 +
 +
- /* Return name for this driver instance */
- const char *pvr2_hdw_get_driver_name(struct pvr2_hdw *hdw)
- {
-@@ -2634,6 +2490,18 @@ const char *pvr2_hdw_get_driver_name(struct pvr2_hdw *hdw)
- }
- 
- 
-+const char *pvr2_hdw_get_desc(struct pvr2_hdw *hdw)
-+{
-+	return hdw->hdw_desc->description;
-+}
 +
 +
-+const char *pvr2_hdw_get_type(struct pvr2_hdw *hdw)
++/* Returns 0 if OK */
++int stk_sensor_outb(struct stk_camera *dev, u8 reg, u8 val)
 +{
-+	return hdw->hdw_desc->shortname;
-+}
++	int i = 0;
++	int tmpval = 0;
 +
++	if (stk_camera_write_reg(dev, STK_IIC_TX_INDEX, reg))
++		return 1;
++	if (stk_camera_write_reg(dev, STK_IIC_TX_VALUE, val))
++		return 1;
++	if (stk_camera_write_reg(dev, STK_IIC_OP, STK_IIC_OP_TX))
++		return 1;
++	do {
++		if (stk_camera_read_reg(dev, STK_IIC_STAT, &tmpval))
++			return 1;
++		i++;
++	} while (tmpval == 0 && i < MAX_RETRIES);
++	if (tmpval != STK_IIC_STAT_TX_OK) {
++		if (tmpval)
++			STK_ERROR("stk_sensor_outb failed, status=0x%02x\n",
++				tmpval);
++		return 1;
++	} else
++		return 0;
++}
 +
- int pvr2_hdw_is_hsm(struct pvr2_hdw *hdw)
- {
- 	int result;
-@@ -2689,6 +2557,7 @@ void pvr2_hdw_trigger_module_log(struct pvr2_hdw *hdw)
- 		pvr2_i2c_core_sync(hdw);
- 		pvr2_trace(PVR2_TRACE_INFO,"cx2341x config:");
- 		cx2341x_log_status(&hdw->enc_ctl_state, "pvrusb2");
-+		pvr2_hdw_state_log_state(hdw);
- 		printk(KERN_INFO "pvrusb2: ==================  END STATUS CARD #%d  ==================\n", nr);
- 	} while (0); LOCK_GIVE(hdw->big_lock);
- }
-@@ -2959,7 +2828,7 @@ static int pvr2_send_request_ex(struct pvr2_hdw *hdw,
- 			   " without lock!!");
- 		return -EDEADLK;
- 	}
--	if ((!hdw->flag_ok) && !probe_fl) {
-+	if (!hdw->flag_ok && !probe_fl) {
- 		pvr2_trace(PVR2_TRACE_ERROR_LEGS,
- 			   "Attempted to execute control transfer"
- 			   " when device not ok");
-@@ -3167,7 +3036,7 @@ static int pvr2_send_request_ex(struct pvr2_hdw *hdw,
- 
- 	hdw->cmd_debug_state = 0;
- 	if ((status < 0) && (!probe_fl)) {
--		pvr2_hdw_render_useless_unlocked(hdw);
-+		pvr2_hdw_render_useless(hdw);
- 	}
- 	return status;
- }
-@@ -3227,24 +3096,17 @@ static int pvr2_read_register(struct pvr2_hdw *hdw, u16 reg, u32 *data)
- }
- 
- 
--static void pvr2_hdw_render_useless_unlocked(struct pvr2_hdw *hdw)
-+void pvr2_hdw_render_useless(struct pvr2_hdw *hdw)
- {
- 	if (!hdw->flag_ok) return;
--	pvr2_trace(PVR2_TRACE_INIT,"render_useless");
--	hdw->flag_ok = 0;
-+	pvr2_trace(PVR2_TRACE_ERROR_LEGS,
-+		   "Device being rendered inoperable");
- 	if (hdw->vid_stream) {
- 		pvr2_stream_setup(hdw->vid_stream,NULL,0,0);
- 	}
--	hdw->flag_streaming_enabled = 0;
--	hdw->subsys_enabled_mask = 0;
--}
--
--
--void pvr2_hdw_render_useless(struct pvr2_hdw *hdw)
--{
--	LOCK_TAKE(hdw->ctl_lock);
--	pvr2_hdw_render_useless_unlocked(hdw);
--	LOCK_GIVE(hdw->ctl_lock);
-+	hdw->flag_ok = 0;
-+	trace_stbit("flag_ok",hdw->flag_ok);
-+	pvr2_hdw_state_sched(hdw);
- }
- 
- 
-@@ -3299,7 +3161,6 @@ int pvr2_hdw_cmd_deep_reset(struct pvr2_hdw *hdw)
- 	int status;
- 	LOCK_TAKE(hdw->ctl_lock); do {
- 		pvr2_trace(PVR2_TRACE_INIT,"Requesting uproc hard reset");
--		hdw->flag_ok = !0;
- 		hdw->cmd_buffer[0] = FX2CMD_DEEP_RESET;
- 		status = pvr2_send_request(hdw,hdw->cmd_buffer,1,NULL,0);
- 	} while (0); LOCK_GIVE(hdw->ctl_lock);
-@@ -3349,26 +3210,473 @@ static int pvr2_hdw_cmd_usbstream(struct pvr2_hdw *hdw,int runFl)
- 			(runFl ? FX2CMD_STREAMING_ON : FX2CMD_STREAMING_OFF);
- 		status = pvr2_send_request(hdw,hdw->cmd_buffer,1,NULL,0);
- 	} while (0); LOCK_GIVE(hdw->ctl_lock);
--	if (!status) {
--		hdw->subsys_enabled_mask =
--			((hdw->subsys_enabled_mask &
--			  ~(1<<PVR2_SUBSYS_B_USBSTREAM_RUN)) |
--			 (runFl ? (1<<PVR2_SUBSYS_B_USBSTREAM_RUN) : 0));
--	}
- 	return status;
- }
- 
- 
--void pvr2_hdw_get_debug_info(const struct pvr2_hdw *hdw,
--			     struct pvr2_hdw_debug_info *ptr)
-+/* Evaluate whether or not state_encoder_ok can change */
-+static int state_eval_encoder_ok(struct pvr2_hdw *hdw)
++int stk_sensor_inb(struct stk_camera *dev, u8 reg, u8 *val)
 +{
-+	if (hdw->state_encoder_ok) return 0;
-+	if (hdw->flag_tripped) return 0;
-+	if (hdw->state_encoder_run) return 0;
-+	if (hdw->state_encoder_config) return 0;
-+	if (hdw->state_decoder_run) return 0;
-+	if (hdw->state_usbstream_run) return 0;
-+	if (pvr2_upload_firmware2(hdw) < 0) {
-+		hdw->flag_tripped = !0;
-+		trace_stbit("flag_tripped",hdw->flag_tripped);
-+		return !0;
++	int i = 0;
++	int tmpval = 0;
++
++	if (stk_camera_write_reg(dev, STK_IIC_RX_INDEX, reg))
++		return 1;
++	if (stk_camera_write_reg(dev, STK_IIC_OP, STK_IIC_OP_RX))
++		return 1;
++	do {
++		if (stk_camera_read_reg(dev, STK_IIC_STAT, &tmpval))
++			return 1;
++		i++;
++	} while (tmpval == 0 && i < MAX_RETRIES);
++	if (tmpval != STK_IIC_STAT_RX_OK) {
++		if (tmpval)
++			STK_ERROR("stk_sensor_inb failed, status=0x%02x\n",
++				tmpval);
++		return 1;
 +	}
-+	hdw->state_encoder_ok = !0;
-+	trace_stbit("state_encoder_ok",hdw->state_encoder_ok);
-+	return !0;
-+}
 +
++	if (stk_camera_read_reg(dev, STK_IIC_RX_VALUE, &tmpval))
++		return 1;
 +
-+/* Evaluate whether or not state_encoder_config can change */
-+static int state_eval_encoder_config(struct pvr2_hdw *hdw)
-+{
-+	if (hdw->state_encoder_config) {
-+		if (hdw->state_encoder_ok) {
-+			if (hdw->state_pipeline_req &&
-+			    !hdw->state_pipeline_pause) return 0;
-+		}
-+		hdw->state_encoder_config = 0;
-+		hdw->state_encoder_waitok = 0;
-+		trace_stbit("state_encoder_waitok",hdw->state_encoder_waitok);
-+		/* paranoia - solve race if timer just completed */
-+		del_timer_sync(&hdw->encoder_wait_timer);
-+	} else {
-+		if (!hdw->state_encoder_ok ||
-+		    !hdw->state_pipeline_idle ||
-+		    hdw->state_pipeline_pause ||
-+		    !hdw->state_pipeline_req ||
-+		    !hdw->state_pipeline_config) {
-+			/* We must reset the enforced wait interval if
-+			   anything has happened that might have disturbed
-+			   the encoder.  This should be a rare case. */
-+			if (timer_pending(&hdw->encoder_wait_timer)) {
-+				del_timer_sync(&hdw->encoder_wait_timer);
-+			}
-+			if (hdw->state_encoder_waitok) {
-+				/* Must clear the state - therefore we did
-+				   something to a state bit and must also
-+				   return true. */
-+				hdw->state_encoder_waitok = 0;
-+				trace_stbit("state_encoder_waitok",
-+					    hdw->state_encoder_waitok);
-+				return !0;
-+			}
-+			return 0;
-+		}
-+		if (!hdw->state_encoder_waitok) {
-+			if (!timer_pending(&hdw->encoder_wait_timer)) {
-+				/* waitok flag wasn't set and timer isn't
-+				   running.  Check flag once more to avoid
-+				   a race then start the timer.  This is
-+				   the point when we measure out a minimal
-+				   quiet interval before doing something to
-+				   the encoder. */
-+				if (!hdw->state_encoder_waitok) {
-+					hdw->encoder_wait_timer.expires =
-+						jiffies + (HZ*50/1000);
-+					add_timer(&hdw->encoder_wait_timer);
-+				}
-+			}
-+			/* We can't continue until we know we have been
-+			   quiet for the interval measured by this
-+			   timer. */
-+			return 0;
-+		}
-+		pvr2_encoder_configure(hdw);
-+		if (hdw->state_encoder_ok) hdw->state_encoder_config = !0;
-+	}
-+	trace_stbit("state_encoder_config",hdw->state_encoder_config);
-+	return !0;
++	*val = (u8) tmpval;
++	return 0;
 +}
 +
-+
-+/* Evaluate whether or not state_encoder_run can change */
-+static int state_eval_encoder_run(struct pvr2_hdw *hdw)
++static int stk_sensor_write_regvals(struct stk_camera *dev,
++		struct regval *rv)
 +{
-+	if (hdw->state_encoder_run) {
-+		if (hdw->state_encoder_ok) {
-+			if (hdw->state_decoder_run) return 0;
-+			if (pvr2_encoder_stop(hdw) < 0) return !0;
-+		}
-+		hdw->state_encoder_run = 0;
-+	} else {
-+		if (!hdw->state_encoder_ok) return 0;
-+		if (!hdw->state_decoder_run) return 0;
-+		if (pvr2_encoder_start(hdw) < 0) return !0;
-+		hdw->state_encoder_run = !0;
++	int ret;
++	if (rv == NULL)
++		return 0;
++	while (rv->reg != 0xff || rv->val != 0xff) {
++		ret = stk_sensor_outb(dev, rv->reg, rv->val);
++		if (ret != 0)
++			return ret;
++		rv++;
 +	}
-+	trace_stbit("state_encoder_run",hdw->state_encoder_run);
-+	return !0;
++	return 0;
 +}
 +
-+
-+/* Timeout function for quiescent timer. */
-+static void pvr2_hdw_quiescent_timeout(unsigned long data)
++int stk_sensor_sleep(struct stk_camera *dev)
 +{
-+	struct pvr2_hdw *hdw = (struct pvr2_hdw *)data;
-+	hdw->state_decoder_quiescent = !0;
-+	trace_stbit("state_decoder_quiescent",hdw->state_decoder_quiescent);
-+	hdw->state_stale = !0;
-+	queue_work(hdw->workqueue,&hdw->workpoll);
++	u8 tmp;
++	return stk_sensor_inb(dev, REG_COM2, &tmp)
++		|| stk_sensor_outb(dev, REG_COM2, tmp|COM2_SSLEEP);
 +}
 +
-+
-+/* Timeout function for encoder wait timer. */
-+static void pvr2_hdw_encoder_wait_timeout(unsigned long data)
++int stk_sensor_wakeup(struct stk_camera *dev)
 +{
-+	struct pvr2_hdw *hdw = (struct pvr2_hdw *)data;
-+	hdw->state_encoder_waitok = !0;
-+	trace_stbit("state_encoder_waitok",hdw->state_encoder_waitok);
-+	hdw->state_stale = !0;
-+	queue_work(hdw->workqueue,&hdw->workpoll);
++	u8 tmp;
++	return stk_sensor_inb(dev, REG_COM2, &tmp)
++		|| stk_sensor_outb(dev, REG_COM2, tmp&~COM2_SSLEEP);
 +}
 +
++static struct regval ov_initvals[] = {
++	{REG_CLKRC, CLK_PLL},
++	{REG_COM11, 0x01},
++	{0x6a, 0x7d},
++	{REG_AECH, 0x40},
++	{REG_GAIN, 0x00},
++	{REG_BLUE, 0x80},
++	{REG_RED, 0x80},
++	/* Do not enable fast AEC for now */
++	/*{REG_COM8, COM8_FASTAEC|COM8_AECSTEP|COM8_BFILT|COM8_AGC|COM8_AEC},*/
++	{REG_COM8, COM8_AECSTEP|COM8_BFILT|COM8_AGC|COM8_AEC},
++	{0x39, 0x50}, {0x38, 0x93},
++	{0x37, 0x00}, {0x35, 0x81},
++	{REG_COM5, 0x20},
++	{REG_COM1, 0x00},
++	{REG_COM3, 0x00},
++	{REG_COM4, 0x00},
++	{REG_PSHFT, 0x00},
++	{0x16, 0x07},
++	{0x33, 0xe2}, {0x34, 0xbf},
++	{REG_COM16, 0x00},
++	{0x96, 0x04},
++	/* Gamma curve values */
++/*	{ 0x7a, 0x20 },		{ 0x7b, 0x10 },
++	{ 0x7c, 0x1e },		{ 0x7d, 0x35 },
++	{ 0x7e, 0x5a },		{ 0x7f, 0x69 },
++	{ 0x80, 0x76 },		{ 0x81, 0x80 },
++	{ 0x82, 0x88 },		{ 0x83, 0x8f },
++	{ 0x84, 0x96 },		{ 0x85, 0xa3 },
++	{ 0x86, 0xaf },		{ 0x87, 0xc4 },
++	{ 0x88, 0xd7 },		{ 0x89, 0xe8 },
++*/
++	{REG_GFIX, 0x40},
++	{0x8e, 0x00},
++	{REG_COM12, 0x73},
++	{0x8f, 0xdf}, {0x8b, 0x06},
++	{0x8c, 0x20},
++	{0x94, 0x88}, {0x95, 0x88},
++/*	{REG_COM15, 0xc1}, TODO */
++	{0x29, 0x3f},
++	{REG_COM6, 0x42},
++	{REG_BD50MAX, 0x80},
++	{REG_HAECC6, 0xb8}, {REG_HAECC7, 0x92},
++	{REG_BD60MAX, 0x0a},
++	{0x90, 0x00}, {0x91, 0x00},
++	{REG_HAECC1, 0x00}, {REG_HAECC2, 0x00},
++	{REG_AEW, 0x68}, {REG_AEB, 0x5c},
++	{REG_VPT, 0xc3},
++	{REG_COM9, 0x2e},
++	{0x2a, 0x00}, {0x2b, 0x00},
++
++	{0xff, 0xff}, /* END MARKER */
++};
 +
-+/* Evaluate whether or not state_decoder_run can change */
-+static int state_eval_decoder_run(struct pvr2_hdw *hdw)
++/* Probe the I2C bus and initialise the sensor chip */
++int stk_sensor_init(struct stk_camera *dev)
 +{
-+	if (hdw->state_decoder_run) {
-+		if (hdw->state_encoder_ok) {
-+			if (hdw->state_pipeline_req &&
-+			    !hdw->state_pipeline_pause) return 0;
-+		}
-+		if (!hdw->flag_decoder_missed) {
-+			pvr2_decoder_enable(hdw,0);
-+		}
-+		hdw->state_decoder_quiescent = 0;
-+		hdw->state_decoder_run = 0;
-+		/* paranoia - solve race if timer just completed */
-+		del_timer_sync(&hdw->quiescent_timer);
-+	} else {
-+		if (!hdw->state_decoder_quiescent) {
-+			if (!timer_pending(&hdw->quiescent_timer)) {
-+				/* We don't do something about the
-+				   quiescent timer until right here because
-+				   we also want to catch cases where the
-+				   decoder was already not running (like
-+				   after initialization) as opposed to
-+				   knowing that we had just stopped it.
-+				   The second flag check is here to cover a
-+				   race - the timer could have run and set
-+				   this flag just after the previous check
-+				   but before we did the pending check. */
-+				if (!hdw->state_decoder_quiescent) {
-+					hdw->quiescent_timer.expires =
-+						jiffies + (HZ*50/1000);
-+					add_timer(&hdw->quiescent_timer);
-+				}
-+			}
-+			/* Don't allow decoder to start again until it has
-+			   been quiesced first.  This little detail should
-+			   hopefully further stabilize the encoder. */
-+			return 0;
-+		}
-+		if (!hdw->state_pipeline_req ||
-+		    hdw->state_pipeline_pause ||
-+		    !hdw->state_pipeline_config ||
-+		    !hdw->state_encoder_config ||
-+		    !hdw->state_encoder_ok) return 0;
-+		del_timer_sync(&hdw->quiescent_timer);
-+		if (hdw->flag_decoder_missed) return 0;
-+		if (pvr2_decoder_enable(hdw,!0) < 0) return 0;
-+		hdw->state_decoder_quiescent = 0;
-+		hdw->state_decoder_run = !0;
++	u8 idl = 0;
++	u8 idh = 0;
++
++	if (stk_camera_write_reg(dev, STK_IIC_ENABLE, STK_IIC_ENABLE_YES)
++		|| stk_camera_write_reg(dev, STK_IIC_ADDR, SENSOR_ADDRESS)
++		|| stk_sensor_outb(dev, REG_COM7, COM7_RESET)) {
++		STK_ERROR("Sensor resetting failed\n");
++		return -ENODEV;
 +	}
-+	trace_stbit("state_decoder_quiescent",hdw->state_decoder_quiescent);
-+	trace_stbit("state_decoder_run",hdw->state_decoder_run);
-+	return !0;
++	msleep(10);
++	/* Read the manufacturer ID: ov = 0x7FA2 */
++	if (stk_sensor_inb(dev, REG_MIDH, &idh)
++	    || stk_sensor_inb(dev, REG_MIDL, &idl)) {
++		STK_ERROR("Strange error reading sensor ID\n");
++		return -ENODEV;
++	}
++	if (idh != 0x7F || idl != 0xA2) {
++		STK_ERROR("Huh? you don't have a sensor from ovt\n");
++		return -ENODEV;
++	}
++	if (stk_sensor_inb(dev, REG_PID, &idh)
++	    || stk_sensor_inb(dev, REG_VER, &idl)) {
++		STK_ERROR("Could not read sensor model\n");
++		return -ENODEV;
++	}
++	stk_sensor_write_regvals(dev, ov_initvals);
++	msleep(10);
++	STK_INFO("OmniVision sensor detected, id %02X%02X"
++		" at address %x\n", idh, idl, SENSOR_ADDRESS);
++	return 0;
 +}
 +
++/* V4L2_PIX_FMT_UYVY */
++static struct regval ov_fmt_uyvy[] = {
++	{REG_TSLB, TSLB_YLAST|0x08 },
++	{ 0x4f, 0x80 }, 	/* "matrix coefficient 1" */
++	{ 0x50, 0x80 }, 	/* "matrix coefficient 2" */
++	{ 0x51, 0    },		/* vb */
++	{ 0x52, 0x22 }, 	/* "matrix coefficient 4" */
++	{ 0x53, 0x5e }, 	/* "matrix coefficient 5" */
++	{ 0x54, 0x80 }, 	/* "matrix coefficient 6" */
++	{REG_COM13, COM13_UVSAT|COM13_CMATRIX},
++	{REG_COM15, COM15_R00FF },
++	{0xff, 0xff}, /* END MARKER */
++};
 +
-+/* Evaluate whether or not state_usbstream_run can change */
-+static int state_eval_usbstream_run(struct pvr2_hdw *hdw)
-+{
-+	if (hdw->state_usbstream_run) {
-+		if (hdw->state_encoder_ok) {
-+			if (hdw->state_encoder_run) return 0;
-+		}
-+		pvr2_hdw_cmd_usbstream(hdw,0);
-+		hdw->state_usbstream_run = 0;
-+	} else {
-+		if (!hdw->state_encoder_ok ||
-+		    !hdw->state_encoder_run ||
-+		    !hdw->state_pipeline_req ||
-+		    hdw->state_pipeline_pause) return 0;
-+		if (pvr2_hdw_cmd_usbstream(hdw,!0) < 0) return 0;
-+		hdw->state_usbstream_run = !0;
-+	}
-+	trace_stbit("state_usbstream_run",hdw->state_usbstream_run);
-+	return !0;
-+}
++/* V4L2_PIX_FMT_RGB565X rrrrrggg gggbbbbb */
++static struct regval ov_fmt_rgbr[] = {
++	{ REG_RGB444, 0 },	/* No RGB444 please */
++	{REG_TSLB, 0x00},
++	{ REG_COM1, 0x0 },
++	{ REG_COM9, 0x38 }, 	/* 16x gain ceiling; 0x8 is reserved bit */
++	{ 0x4f, 0xb3 }, 	/* "matrix coefficient 1" */
++	{ 0x50, 0xb3 }, 	/* "matrix coefficient 2" */
++	{ 0x51, 0    },		/* vb */
++	{ 0x52, 0x3d }, 	/* "matrix coefficient 4" */
++	{ 0x53, 0xa7 }, 	/* "matrix coefficient 5" */
++	{ 0x54, 0xe4 }, 	/* "matrix coefficient 6" */
++	{ REG_COM13, COM13_GAMMA },
++	{ REG_COM15, COM15_RGB565|COM15_R00FF },
++	{ 0xff, 0xff },
++};
 +
++/* V4L2_PIX_FMT_RGB565 gggbbbbb rrrrrggg */
++static struct regval ov_fmt_rgbp[] = {
++	{ REG_RGB444, 0 },	/* No RGB444 please */
++	{REG_TSLB, TSLB_BYTEORD },
++	{ REG_COM1, 0x0 },
++	{ REG_COM9, 0x38 }, 	/* 16x gain ceiling; 0x8 is reserved bit */
++	{ 0x4f, 0xb3 }, 	/* "matrix coefficient 1" */
++	{ 0x50, 0xb3 }, 	/* "matrix coefficient 2" */
++	{ 0x51, 0    },		/* vb */
++	{ 0x52, 0x3d }, 	/* "matrix coefficient 4" */
++	{ 0x53, 0xa7 }, 	/* "matrix coefficient 5" */
++	{ 0x54, 0xe4 }, 	/* "matrix coefficient 6" */
++	{ REG_COM13, COM13_GAMMA },
++	{ REG_COM15, COM15_RGB565|COM15_R00FF },
++	{ 0xff, 0xff },
++};
 +
-+/* Attempt to configure pipeline, if needed */
-+static int state_eval_pipeline_config(struct pvr2_hdw *hdw)
++/* V4L2_PIX_FMT_SRGGB8 */
++static struct regval ov_fmt_bayer[] = {
++	/* This changes color order */
++	{REG_TSLB, 0x40}, /* BGGR */
++	/* {REG_TSLB, 0x08}, */ /* BGGR with vertical image flipping */
++	{REG_COM15, COM15_R00FF },
++	{0xff, 0xff}, /* END MARKER */
++};
++/*
++ * Store a set of start/stop values into the camera.
++ */
++static int stk_sensor_set_hw(struct stk_camera *dev,
++		int hstart, int hstop, int vstart, int vstop)
 +{
-+	if (hdw->state_pipeline_config ||
-+	    hdw->state_pipeline_pause) return 0;
-+	pvr2_hdw_commit_execute(hdw);
-+	return !0;
++	int ret;
++	unsigned char v;
++/*
++ * Horizontal: 11 bits, top 8 live in hstart and hstop.  Bottom 3 of
++ * hstart are in href[2:0], bottom 3 of hstop in href[5:3].  There is
++ * a mystery "edge offset" value in the top two bits of href.
++ */
++	ret =  stk_sensor_outb(dev, REG_HSTART, (hstart >> 3) & 0xff);
++	ret += stk_sensor_outb(dev, REG_HSTOP, (hstop >> 3) & 0xff);
++	ret += stk_sensor_inb(dev, REG_HREF, &v);
++	v = (v & 0xc0) | ((hstop & 0x7) << 3) | (hstart & 0x7);
++	msleep(10);
++	ret += stk_sensor_outb(dev, REG_HREF, v);
++/*
++ * Vertical: similar arrangement (note: this is different from ov7670.c)
++ */
++	ret += stk_sensor_outb(dev, REG_VSTART, (vstart >> 3) & 0xff);
++	ret += stk_sensor_outb(dev, REG_VSTOP, (vstop >> 3) & 0xff);
++	ret += stk_sensor_inb(dev, REG_VREF, &v);
++	v = (v & 0xc0) | ((vstop & 0x7) << 3) | (vstart & 0x7);
++	msleep(10);
++	ret += stk_sensor_outb(dev, REG_VREF, v);
++	return ret;
 +}
 +
 +
-+/* Update pipeline idle and pipeline pause tracking states based on other
-+   inputs.  This must be called whenever the other relevant inputs have
-+   changed. */
-+static int state_update_pipeline_state(struct pvr2_hdw *hdw)
++int stk_sensor_configure(struct stk_camera *dev)
 +{
-+	unsigned int st;
-+	int updatedFl = 0;
-+	/* Update pipeline state */
-+	st = !(hdw->state_encoder_run ||
-+	       hdw->state_decoder_run ||
-+	       hdw->state_usbstream_run ||
-+	       (!hdw->state_decoder_quiescent));
-+	if (!st != !hdw->state_pipeline_idle) {
-+		hdw->state_pipeline_idle = st;
-+		updatedFl = !0;
++	int com7;
++	/*
++	 * We setup the sensor to output dummy lines in low-res modes,
++	 * so we don't get absurdly hight framerates.
++	 */
++	unsigned dummylines;
++	int flip;
++	struct regval *rv;
++
++	switch (dev->vsettings.mode) {
++	case MODE_QCIF: com7 = COM7_FMT_QCIF;
++		dummylines = 604;
++		break;
++	case MODE_QVGA: com7 = COM7_FMT_QVGA;
++		dummylines = 267;
++		break;
++	case MODE_CIF: com7 = COM7_FMT_CIF;
++		dummylines = 412;
++		break;
++	case MODE_VGA: com7 = COM7_FMT_VGA;
++		dummylines = 11;
++		break;
++	case MODE_SXGA: com7 = COM7_FMT_SXGA;
++		dummylines = 0;
++		break;
++	default: STK_ERROR("Unsupported mode %d\n", dev->vsettings.mode);
++		return -EFAULT;
 +	}
-+	if (hdw->state_pipeline_idle && hdw->state_pipeline_pause) {
-+		hdw->state_pipeline_pause = 0;
-+		updatedFl = !0;
++	switch (dev->vsettings.palette) {
++	case V4L2_PIX_FMT_UYVY:
++		com7 |= COM7_YUV;
++		rv = ov_fmt_uyvy;
++		break;
++	case V4L2_PIX_FMT_RGB565:
++		com7 |= COM7_RGB;
++		rv = ov_fmt_rgbp;
++		break;
++	case V4L2_PIX_FMT_RGB565X:
++		com7 |= COM7_RGB;
++		rv = ov_fmt_rgbr;
++		break;
++	case V4L2_PIX_FMT_SBGGR8:
++		com7 |= COM7_PBAYER;
++		rv = ov_fmt_bayer;
++		break;
++	default: STK_ERROR("Unsupported colorspace\n");
++		return -EFAULT;
 +	}
-+	return updatedFl;
++	/*FIXME sometimes the sensor go to a bad state
++	stk_sensor_write_regvals(dev, ov_initvals); */
++	stk_sensor_outb(dev, REG_COM7, com7);
++	msleep(50);
++	stk_sensor_write_regvals(dev, rv);
++	flip = (dev->vsettings.vflip?MVFP_FLIP:0)
++		| (dev->vsettings.hflip?MVFP_MIRROR:0);
++	stk_sensor_outb(dev, REG_MVFP, flip);
++	if (dev->vsettings.palette == V4L2_PIX_FMT_SBGGR8
++			&& !dev->vsettings.vflip)
++		stk_sensor_outb(dev, REG_TSLB, 0x08);
++	stk_sensor_outb(dev, REG_ADVFH, dummylines >> 8);
++	stk_sensor_outb(dev, REG_ADVFL, dummylines & 0xff);
++	msleep(50);
++	switch (dev->vsettings.mode) {
++	case MODE_VGA:
++		if (stk_sensor_set_hw(dev, 302, 1582, 6, 486))
++			STK_ERROR("stk_sensor_set_hw failed (VGA)\n");
++		break;
++	case MODE_SXGA:
++	case MODE_CIF:
++	case MODE_QVGA:
++	case MODE_QCIF:
++		/*FIXME These settings seem ignored by the sensor
++		if (stk_sensor_set_hw(dev, 220, 1500, 10, 1034))
++			STK_ERROR("stk_sensor_set_hw failed (SXGA)\n");
++		*/
++		break;
++	}
++	msleep(10);
++	return 0;
 +}
 +
++int stk_sensor_set_brightness(struct stk_camera *dev, int br)
++{
++	if (br < 0 || br > 0xff)
++		return -EINVAL;
++	stk_sensor_outb(dev, REG_AEB, max(0x00, br - 6));
++	stk_sensor_outb(dev, REG_AEW, min(0xff, br + 6));
++	return 0;
++}
 +
-+typedef int (*state_eval_func)(struct pvr2_hdw *);
+diff --git a/drivers/media/video/stk-webcam.c b/drivers/media/video/stk-webcam.c
+new file mode 100644
+index 0000000..d37e5e2
+--- /dev/null
++++ b/drivers/media/video/stk-webcam.c
+@@ -0,0 +1,1465 @@
++/*
++ * stk-webcam.c : Driver for Syntek 1125 USB webcam controller
++ *
++ * Copyright (C) 2006 Nicolas VIVIEN
++ * Copyright 2007-2008 Jaime Velasco Juan <jsagarribay at gmail.com>
++ *
++ * Some parts are inspired from cafe_ccic.c
++ * Copyright 2006-2007 Jonathan Corbet
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * 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
++ */
 +
-+/* Set of functions to be run to evaluate various states in the driver. */
-+const static state_eval_func eval_funcs[] = {
-+	state_eval_pipeline_config,
-+	state_eval_encoder_ok,
-+	state_eval_encoder_config,
-+	state_eval_decoder_run,
-+	state_eval_encoder_run,
-+	state_eval_usbstream_run,
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/errno.h>
++#include <linux/slab.h>
++#include <linux/kref.h>
++
++#include <linux/usb.h>
++#include <linux/vmalloc.h>
++#include <linux/videodev2.h>
++#include <media/v4l2-common.h>
++
++#include "stk-webcam.h"
++
++
++static int hflip = 1;
++module_param(hflip, bool, 0444);
++MODULE_PARM_DESC(hflip, "Horizontal image flip (mirror). Defaults to 1");
++
++static int vflip = 1;
++module_param(vflip, bool, 0444);
++MODULE_PARM_DESC(vflip, "Vertical image flip. Defaults to 1");
++
++static int debug;
++module_param(debug, int, 0444);
++MODULE_PARM_DESC(debug, "Debug v4l ioctls. Defaults to 0");
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Jaime Velasco Juan <jsagarribay at gmail.com> and Nicolas VIVIEN");
++MODULE_DESCRIPTION("Syntek DC1125 webcam driver");
++
++
++
++/* Some cameras have audio interfaces, we aren't interested in those */
++static struct usb_device_id stkwebcam_table[] = {
++	{ USB_DEVICE_AND_INTERFACE_INFO(0x174f, 0xa311, 0xff, 0xff, 0xff) },
++	{ USB_DEVICE_AND_INTERFACE_INFO(0x05e1, 0x0501, 0xff, 0xff, 0xff) },
++	{ }
 +};
++MODULE_DEVICE_TABLE(usb, stkwebcam_table);
 +
++void stk_camera_cleanup(struct kref *kref)
++{
++	struct stk_camera *dev = to_stk_camera(kref);
 +
-+/* Process various states and return true if we did anything interesting. */
-+static int pvr2_hdw_state_update(struct pvr2_hdw *hdw)
++	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
++ */
++int stk_camera_write_reg(struct stk_camera *dev, u16 index, u8 value)
 +{
-+	unsigned int i;
-+	int state_updated = 0;
-+	int check_flag;
++	struct usb_device *udev = dev->udev;
++	int ret;
 +
-+	if (!hdw->state_stale) return 0;
-+	if ((hdw->fw1_state != FW1_STATE_OK) ||
-+	    !hdw->flag_ok) {
-+		hdw->state_stale = 0;
-+		return !0;
-+	}
-+	/* This loop is the heart of the entire driver.  It keeps trying to
-+	   evaluate various bits of driver state until nothing changes for
-+	   one full iteration.  Each "bit of state" tracks some global
-+	   aspect of the driver, e.g. whether decoder should run, if
-+	   pipeline is configured, usb streaming is on, etc.  We separately
-+	   evaluate each of those questions based on other driver state to
-+	   arrive at the correct running configuration. */
-+	do {
-+		check_flag = 0;
-+		state_update_pipeline_state(hdw);
-+		/* Iterate over each bit of state */
-+		for (i = 0; (i<ARRAY_SIZE(eval_funcs)) && hdw->flag_ok; i++) {
-+			if ((*eval_funcs[i])(hdw)) {
-+				check_flag = !0;
-+				state_updated = !0;
-+				state_update_pipeline_state(hdw);
-+			}
-+		}
-+	} while (check_flag && hdw->flag_ok);
-+	hdw->state_stale = 0;
-+	trace_stbit("state_stale",hdw->state_stale);
-+	return state_updated;
++	ret =  usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
++			0x01,
++			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
++			value,
++			index,
++			NULL,
++			0,
++			500);
++	if (ret < 0)
++		return ret;
++	else
++		return 0;
 +}
 +
++int stk_camera_read_reg(struct stk_camera *dev, u16 index, int *value)
++{
++	struct usb_device *udev = dev->udev;
++	int ret;
++
++	ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
++			0x00,
++			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
++			0x00,
++			index,
++			(u8 *) value,
++			sizeof(u8),
++			500);
++	if (ret < 0)
++		return ret;
++	else
++		return 0;
++}
 +
-+static unsigned int pvr2_hdw_report_unlocked(struct pvr2_hdw *hdw,int which,
-+					     char *buf,unsigned int acnt)
++static int stk_start_stream(struct stk_camera *dev)
 +{
-+	switch (which) {
-+	case 0:
-+		return scnprintf(
-+			buf,acnt,
-+			"driver:%s%s%s%s%s",
-+			(hdw->flag_ok ? " <ok>" : " <fail>"),
-+			(hdw->flag_init_ok ? " <init>" : " <uninitialized>"),
-+			(hdw->flag_disconnected ? " <disconnected>" :
-+			 " <connected>"),
-+			(hdw->flag_tripped ? " <tripped>" : ""),
-+			(hdw->flag_decoder_missed ? " <no decoder>" : ""));
-+	case 1:
-+		return scnprintf(
-+			buf,acnt,
-+			"pipeline:%s%s%s%s",
-+			(hdw->state_pipeline_idle ? " <idle>" : ""),
-+			(hdw->state_pipeline_config ?
-+			 " <configok>" : " <stale>"),
-+			(hdw->state_pipeline_req ? " <req>" : ""),
-+			(hdw->state_pipeline_pause ? " <pause>" : ""));
-+	case 2:
-+		return scnprintf(
-+			buf,acnt,
-+			"worker:%s%s%s%s%s%s",
-+			(hdw->state_decoder_run ?
-+			 " <decode:run>" :
-+			 (hdw->state_decoder_quiescent ?
-+			  "" : " <decode:stop>")),
-+			(hdw->state_decoder_quiescent ?
-+			 " <decode:quiescent>" : ""),
-+			(hdw->state_encoder_ok ?
-+			 "" : " <encode:init>"),
-+			(hdw->state_encoder_run ?
-+			 " <encode:run>" : " <encode:stop>"),
-+			(hdw->state_encoder_config ?
-+			 " <encode:configok>" :
-+			 (hdw->state_encoder_waitok ?
-+			  "" : " <encode:wait>")),
-+			(hdw->state_usbstream_run ?
-+			 " <usb:run>" : " <usb:stop>"));
-+		break;
-+	case 3:
-+		return scnprintf(
-+			buf,acnt,
-+			"state: %s",
-+			pvr2_get_state_name(hdw->master_state));
-+		break;
-+	default: break;
++	int value;
++	int i, ret;
++	int value_116, value_117;
++
++	if (!is_present(dev))
++		return -ENODEV;
++	if (!is_memallocd(dev) || !is_initialised(dev)) {
++		STK_ERROR("FIXME: Buffers are not allocated\n");
++		return -EFAULT;
++	}
++	ret = usb_set_interface(dev->udev, 0, 5);
++
++	if (ret < 0)
++		STK_ERROR("usb_set_interface failed !\n");
++	if (stk_sensor_wakeup(dev))
++		STK_ERROR("error awaking the sensor\n");
++
++	stk_camera_read_reg(dev, 0x0116, &value_116);
++	stk_camera_read_reg(dev, 0x0117, &value_117);
++
++	stk_camera_write_reg(dev, 0x0116, 0x0000);
++	stk_camera_write_reg(dev, 0x0117, 0x0000);
++
++	stk_camera_read_reg(dev, 0x0100, &value);
++	stk_camera_write_reg(dev, 0x0100, value | 0x80);
++
++	stk_camera_write_reg(dev, 0x0116, value_116);
++	stk_camera_write_reg(dev, 0x0117, value_117);
++	for (i = 0; i < MAX_ISO_BUFS; i++) {
++		if (dev->isobufs[i].urb) {
++			ret = usb_submit_urb(dev->isobufs[i].urb, GFP_KERNEL);
++			atomic_inc(&dev->urbs_used);
++			if (ret)
++				return ret;
++		}
 +	}
++	set_streaming(dev);
 +	return 0;
 +}
 +
-+
-+unsigned int pvr2_hdw_state_report(struct pvr2_hdw *hdw,
-+				   char *buf,unsigned int acnt)
++static int stk_stop_stream(struct stk_camera *dev)
 +{
-+	unsigned int bcnt,ccnt,idx;
-+	bcnt = 0;
-+	LOCK_TAKE(hdw->big_lock);
-+	for (idx = 0; ; idx++) {
-+		ccnt = pvr2_hdw_report_unlocked(hdw,idx,buf,acnt);
-+		if (!ccnt) break;
-+		bcnt += ccnt; acnt -= ccnt; buf += ccnt;
-+		if (!acnt) break;
-+		buf[0] = '\n'; ccnt = 1;
-+		bcnt += ccnt; acnt -= ccnt; buf += ccnt;
++	int value;
++	int i;
++	if (is_present(dev)) {
++		stk_camera_read_reg(dev, 0x0100, &value);
++		stk_camera_write_reg(dev, 0x0100, value & ~0x80);
++		if (dev->isobufs != NULL) {
++			for (i = 0; i < MAX_ISO_BUFS; i++) {
++				if (dev->isobufs[i].urb)
++					usb_kill_urb(dev->isobufs[i].urb);
++			}
++		}
++		unset_streaming(dev);
++
++		if (usb_set_interface(dev->udev, 0, 0))
++			STK_ERROR("usb_set_interface failed !\n");
++		if (stk_sensor_sleep(dev))
++			STK_ERROR("error suspending the sensor\n");
 +	}
-+	LOCK_GIVE(hdw->big_lock);
-+	return bcnt;
++	return 0;
 +}
 +
++/*
++ * This seems to be the shortest init sequence we
++ * must do in order to find the sensor
++ * Bit 5 of reg. 0x0000 here is important, when reset to 0 the sensor
++ * is also reset. Maybe powers down it?
++ * Rest of values don't make a difference
++ */
 +
-+static void pvr2_hdw_state_log_state(struct pvr2_hdw *hdw)
-+{
-+	char buf[128];
-+	unsigned int idx,ccnt;
++static struct regval stk1125_initvals[] = {
++	/*TODO: What means this sequence? */
++	{0x0000, 0x24},
++	{0x0100, 0x21},
++	{0x0002, 0x68},
++	{0x0003, 0x80},
++	{0x0005, 0x00},
++	{0x0007, 0x03},
++	{0x000d, 0x00},
++	{0x000f, 0x02},
++	{0x0300, 0x12},
++	{0x0350, 0x41},
++	{0x0351, 0x00},
++	{0x0352, 0x00},
++	{0x0353, 0x00},
++	{0x0018, 0x10},
++	{0x0019, 0x00},
++	{0x001b, 0x0e},
++	{0x001c, 0x46},
++	{0x0300, 0x80},
++	{0x001a, 0x04},
++	{0x0110, 0x00},
++	{0x0111, 0x00},
++	{0x0112, 0x00},
++	{0x0113, 0x00},
 +
-+	for (idx = 0; ; idx++) {
-+		ccnt = pvr2_hdw_report_unlocked(hdw,idx,buf,sizeof(buf));
-+		if (!ccnt) break;
-+		printk(KERN_INFO "%s %.*s\n",hdw->name,ccnt,buf);
++	{0xffff, 0xff},
++};
++
++
++static int stk_initialise(struct stk_camera *dev)
++{
++	struct regval *rv;
++	int ret;
++	if (!is_present(dev))
++		return -ENODEV;
++	if (is_initialised(dev))
++		return 0;
++	rv = stk1125_initvals;
++	while (rv->reg != 0xffff) {
++		ret = stk_camera_write_reg(dev, rv->reg, rv->val);
++		if (ret)
++			return ret;
++		rv++;
 +	}
++	if (stk_sensor_init(dev) == 0) {
++		set_initialised(dev);
++		return 0;
++	} else
++		return -1;
 +}
 +
++/* sysfs functions */
++/*FIXME cleanup this */
 +
-+/* Evaluate and update the driver's current state, taking various actions
-+   as appropriate for the update. */
-+static int pvr2_hdw_state_eval(struct pvr2_hdw *hdw)
++static ssize_t show_brightness(struct device *class,
++			struct device_attribute *attr, char *buf)
 +{
-+	unsigned int st;
-+	int state_updated = 0;
-+	int callback_flag = 0;
-+
-+	pvr2_trace(PVR2_TRACE_STBITS,
-+		   "Drive state check START");
-+	if (pvrusb2_debug & PVR2_TRACE_STBITS) {
-+		pvr2_hdw_state_log_state(hdw);
-+	}
++	struct video_device *vdev = to_video_device(class);
++	struct stk_camera *dev = vdev_to_camera(vdev);
 +
-+	/* Process all state and get back over disposition */
-+	state_updated = pvr2_hdw_state_update(hdw);
++	return sprintf(buf, "%X\n", dev->vsettings.brightness);
++}
 +
-+	/* Update master state based upon all other states. */
-+	if (!hdw->flag_ok) {
-+		st = PVR2_STATE_DEAD;
-+	} else if (hdw->fw1_state != FW1_STATE_OK) {
-+		st = PVR2_STATE_COLD;
-+	} else if (!hdw->state_encoder_ok) {
-+		st = PVR2_STATE_WARM;
-+	} else if (hdw->flag_tripped || hdw->flag_decoder_missed) {
-+		st = PVR2_STATE_ERROR;
-+	} else if (hdw->state_encoder_run &&
-+		   hdw->state_decoder_run &&
-+		   hdw->state_usbstream_run) {
-+		st = PVR2_STATE_RUN;
-+	} else {
-+		st = PVR2_STATE_READY;
-+	}
-+	if (hdw->master_state != st) {
-+		pvr2_trace(PVR2_TRACE_STATE,
-+			   "Device state change from %s to %s",
-+			   pvr2_get_state_name(hdw->master_state),
-+			   pvr2_get_state_name(st));
-+		hdw->master_state = st;
-+		state_updated = !0;
-+		callback_flag = !0;
-+	}
-+	if (state_updated) {
-+		/* Trigger anyone waiting on any state changes here. */
-+		wake_up(&hdw->state_wait_data);
-+	}
++static ssize_t store_brightness(struct device *class,
++		struct device_attribute *attr, const char *buf, size_t count)
++{
++	char *endp;
++	unsigned long value;
++	int ret;
 +
-+	if (pvrusb2_debug & PVR2_TRACE_STBITS) {
-+		pvr2_hdw_state_log_state(hdw);
-+	}
-+	pvr2_trace(PVR2_TRACE_STBITS,
-+		   "Drive state check DONE callback=%d",callback_flag);
++	struct video_device *vdev = to_video_device(class);
++	struct stk_camera *dev = vdev_to_camera(vdev);
 +
-+	return callback_flag;
-+}
++	value = simple_strtoul(buf, &endp, 16);
 +
++	dev->vsettings.brightness = (int) value;
 +
-+/* Cause kernel thread to check / update driver state */
-+static void pvr2_hdw_state_sched(struct pvr2_hdw *hdw)
-+{
-+	if (hdw->state_stale) return;
-+	hdw->state_stale = !0;
-+	trace_stbit("state_stale",hdw->state_stale);
-+	queue_work(hdw->workqueue,&hdw->workpoll);
++	ret = stk_sensor_set_brightness(dev, value >> 8);
++	if (ret)
++		return ret;
++	else
++		return count;
 +}
 +
-+
-+void pvr2_hdw_get_debug_info_unlocked(const struct pvr2_hdw *hdw,
-+				      struct pvr2_hdw_debug_info *ptr)
- {
- 	ptr->big_lock_held = hdw->big_lock_held;
- 	ptr->ctl_lock_held = hdw->ctl_lock_held;
--	ptr->flag_ok = hdw->flag_ok;
- 	ptr->flag_disconnected = hdw->flag_disconnected;
- 	ptr->flag_init_ok = hdw->flag_init_ok;
--	ptr->flag_streaming_enabled = hdw->flag_streaming_enabled;
--	ptr->subsys_flags = hdw->subsys_enabled_mask;
-+	ptr->flag_ok = hdw->flag_ok;
-+	ptr->fw1_state = hdw->fw1_state;
-+	ptr->flag_decoder_missed = hdw->flag_decoder_missed;
-+	ptr->flag_tripped = hdw->flag_tripped;
-+	ptr->state_encoder_ok = hdw->state_encoder_ok;
-+	ptr->state_encoder_run = hdw->state_encoder_run;
-+	ptr->state_decoder_run = hdw->state_decoder_run;
-+	ptr->state_usbstream_run = hdw->state_usbstream_run;
-+	ptr->state_decoder_quiescent = hdw->state_decoder_quiescent;
-+	ptr->state_pipeline_config = hdw->state_pipeline_config;
-+	ptr->state_pipeline_req = hdw->state_pipeline_req;
-+	ptr->state_pipeline_pause = hdw->state_pipeline_pause;
-+	ptr->state_pipeline_idle = hdw->state_pipeline_idle;
- 	ptr->cmd_debug_state = hdw->cmd_debug_state;
- 	ptr->cmd_code = hdw->cmd_debug_code;
- 	ptr->cmd_debug_write_len = hdw->cmd_debug_write_len;
-@@ -3381,6 +3689,15 @@ void pvr2_hdw_get_debug_info(const struct pvr2_hdw *hdw,
- }
- 
- 
-+void pvr2_hdw_get_debug_info_locked(struct pvr2_hdw *hdw,
-+				    struct pvr2_hdw_debug_info *ptr)
++static ssize_t show_hflip(struct device *class,
++		struct device_attribute *attr, char *buf)
 +{
-+	LOCK_TAKE(hdw->ctl_lock); do {
-+		pvr2_hdw_get_debug_info_unlocked(hdw,ptr);
-+	} while(0); LOCK_GIVE(hdw->ctl_lock);
++	struct video_device *vdev = to_video_device(class);
++	struct stk_camera *dev = vdev_to_camera(vdev);
++
++	return sprintf(buf, "%d\n", dev->vsettings.hflip);
 +}
 +
++static ssize_t store_hflip(struct device *class,
++		struct device_attribute *attr, const char *buf, size_t count)
++{
++	struct video_device *vdev = to_video_device(class);
++	struct stk_camera *dev = vdev_to_camera(vdev);
 +
- int pvr2_hdw_gpio_get_dir(struct pvr2_hdw *hdw,u32 *dp)
- {
- 	return pvr2_read_register(hdw,PVR2_GPIO_DIR,dp);
-diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.h b/drivers/media/video/pvrusb2/pvrusb2-hdw.h
-index e2f9d5e..3ad7a13 100644
---- a/drivers/media/video/pvrusb2/pvrusb2-hdw.h
-+++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.h
-@@ -44,27 +44,6 @@
- #define PVR2_CVAL_INPUT_COMPOSITE 2
- #define PVR2_CVAL_INPUT_RADIO 3
- 
--/* Subsystem definitions - these are various pieces that can be
--   independently stopped / started.  Usually you don't want to mess with
--   this directly (let the driver handle things itself), but it is useful
--   for debugging. */
--#define PVR2_SUBSYS_B_ENC_FIRMWARE        0
--#define PVR2_SUBSYS_B_ENC_CFG             1
--#define PVR2_SUBSYS_B_DIGITIZER_RUN       2
--#define PVR2_SUBSYS_B_USBSTREAM_RUN       3
--#define PVR2_SUBSYS_B_ENC_RUN             4
--
--#define PVR2_SUBSYS_CFG_ALL ( \
--	(1 << PVR2_SUBSYS_B_ENC_FIRMWARE) | \
--	(1 << PVR2_SUBSYS_B_ENC_CFG) )
--#define PVR2_SUBSYS_RUN_ALL ( \
--	(1 << PVR2_SUBSYS_B_DIGITIZER_RUN) | \
--	(1 << PVR2_SUBSYS_B_USBSTREAM_RUN) | \
--	(1 << PVR2_SUBSYS_B_ENC_RUN) )
--#define PVR2_SUBSYS_ALL ( \
--	PVR2_SUBSYS_CFG_ALL | \
--	PVR2_SUBSYS_RUN_ALL )
--
- enum pvr2_config {
- 	pvr2_config_empty,    /* No configuration */
- 	pvr2_config_mpeg,     /* Encoded / compressed video */
-@@ -79,8 +58,41 @@ enum pvr2_v4l_type {
- 	pvr2_v4l_type_radio,
- };
- 
-+/* Major states that we can be in:
-+ *
-+ *  DEAD - Device is in an unusable state and cannot be recovered.  This
-+ *  can happen if we completely lose the ability to communicate with it
-+ *  (but it might still on the bus).  In this state there's nothing we can
-+ *  do; it must be replugged in order to recover.
-+ *
-+ *  COLD - Device is in an unusuable state, needs microcontroller firmware.
-+ *
-+ *  WARM - We can communicate with the device and the proper
-+ *  microcontroller firmware is running, but other device initialization is
-+ *  still needed (e.g. encoder firmware).
-+ *
-+ *  ERROR - A problem prevents capture operation (e.g. encoder firmware
-+ *  missing).
-+ *
-+ *  READY - Device is operational, but not streaming.
-+ *
-+ *  RUN - Device is streaming.
-+ *
-+ */
-+#define PVR2_STATE_NONE 0
-+#define PVR2_STATE_DEAD 1
-+#define PVR2_STATE_COLD 2
-+#define PVR2_STATE_WARM 3
-+#define PVR2_STATE_ERROR 4
-+#define PVR2_STATE_READY 5
-+#define PVR2_STATE_RUN 6
++	if (strncmp(buf, "1", 1) == 0)
++		dev->vsettings.hflip = 1;
++	else if (strncmp(buf, "0", 1) == 0)
++		dev->vsettings.hflip = 0;
++	else
++		return -EINVAL;
 +
-+/* Translate configuration enum to a string label */
- const char *pvr2_config_get_name(enum pvr2_config);
- 
-+/* Translate a master state enum to a string label */
-+const char *pvr2_hdw_get_state_name(unsigned int);
++	return strlen(buf);
++}
 +
- struct pvr2_hdw;
- 
- /* Create and return a structure for interacting with the underlying
-@@ -88,28 +100,13 @@ struct pvr2_hdw;
- struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
- 				 const struct usb_device_id *devid);
- 
--/* Poll for background activity (if any) */
--void pvr2_hdw_poll(struct pvr2_hdw *);
--
--/* Trigger a poll to take place later at a convenient time */
--void pvr2_hdw_poll_trigger_unlocked(struct pvr2_hdw *);
--
--/* Register a callback used to trigger a future poll */
--void pvr2_hdw_setup_poll_trigger(struct pvr2_hdw *,
--				 void (*func)(void *),
--				 void *data);
--
- /* Destroy hardware interaction structure */
- void pvr2_hdw_destroy(struct pvr2_hdw *);
- 
--/* Set up the structure and attempt to put the device into a usable state.
--   This can be a time-consuming operation, which is why it is not done
--   internally as part of the create() step.  Return value is exactly the
--   same as pvr2_hdw_init_ok(). */
--int pvr2_hdw_setup(struct pvr2_hdw *);
--
--/* Initialization succeeded */
--int pvr2_hdw_init_ok(struct pvr2_hdw *);
-+/* Register a function to be called whenever the master state changes. */
-+void pvr2_hdw_set_state_callback(struct pvr2_hdw *,
-+				 void (*callback_func)(void *),
-+				 void *callback_data);
- 
- /* Return true if in the ready (normal) state */
- int pvr2_hdw_dev_ok(struct pvr2_hdw *);
-@@ -161,12 +158,21 @@ int pvr2_hdw_get_tuner_status(struct pvr2_hdw *,struct v4l2_tuner *);
- /* Query device and see if it thinks it is on a high-speed USB link */
- int pvr2_hdw_is_hsm(struct pvr2_hdw *);
- 
-+/* Return a string token representative of the hardware type */
-+const char *pvr2_hdw_get_type(struct pvr2_hdw *);
++static ssize_t show_vflip(struct device *class,
++		struct device_attribute *attr, char *buf)
++{
++	struct video_device *vdev = to_video_device(class);
++	struct stk_camera *dev = vdev_to_camera(vdev);
 +
-+/* Return a single line description of the hardware type */
-+const char *pvr2_hdw_get_desc(struct pvr2_hdw *);
++	return sprintf(buf, "%d\n", dev->vsettings.vflip);
++}
 +
- /* Turn streaming on/off */
- int pvr2_hdw_set_streaming(struct pvr2_hdw *,int);
- 
- /* Find out if streaming is on */
- int pvr2_hdw_get_streaming(struct pvr2_hdw *);
- 
-+/* Retrieve driver overall state */
-+int pvr2_hdw_get_state(struct pvr2_hdw *);
++static ssize_t store_vflip(struct device *class,
++		struct device_attribute *attr, const char *buf, size_t count)
++{
++	struct video_device *vdev = to_video_device(class);
++	struct stk_camera *dev = vdev_to_camera(vdev);
 +
- /* Configure the type of stream to generate */
- int pvr2_hdw_set_stream_type(struct pvr2_hdw *, enum pvr2_config);
- 
-@@ -177,26 +183,6 @@ struct pvr2_stream *pvr2_hdw_get_video_stream(struct pvr2_hdw *);
- int pvr2_hdw_get_stdenum_value(struct pvr2_hdw *hdw,struct v4l2_standard *std,
- 			       unsigned int idx);
- 
--/* Enable / disable various pieces of hardware.  Items to change are
--   identified by bit positions within msk, and new state for each item is
--   identified by corresponding bit positions within val. */
--void pvr2_hdw_subsys_bit_chg(struct pvr2_hdw *hdw,
--			     unsigned long msk,unsigned long val);
--
--/* Retrieve mask indicating which pieces of hardware are currently enabled
--   / configured. */
--unsigned long pvr2_hdw_subsys_get(struct pvr2_hdw *);
--
--/* Adjust mask of what get shut down when streaming is stopped.  This is a
--   debugging aid. */
--void pvr2_hdw_subsys_stream_bit_chg(struct pvr2_hdw *hdw,
--				    unsigned long msk,unsigned long val);
--
--/* Retrieve mask indicating which pieces of hardware are disabled when
--   streaming is turned off. */
--unsigned long pvr2_hdw_subsys_stream_get(struct pvr2_hdw *);
--
--
- /* Enable / disable retrieval of CPU firmware or prom contents.  This must
-    be enabled before pvr2_hdw_cpufw_get() will function.  Note that doing
-    this may prevent the device from running (and leaving this mode may
-@@ -253,6 +239,9 @@ void pvr2_hdw_cpureset_assert(struct pvr2_hdw *,int);
- /* Execute a USB-commanded device reset */
- void pvr2_hdw_device_reset(struct pvr2_hdw *);
- 
-+/* Reset worker's error trapping circuit breaker */
-+int pvr2_hdw_untrip(struct pvr2_hdw *);
++	if (strncmp(buf, "1", 1) == 0)
++		dev->vsettings.vflip = 1;
++	else if (strncmp(buf, "0", 1) == 0)
++		dev->vsettings.vflip = 0;
++	else
++		return -EINVAL;
 +
- /* Execute hard reset command (after this point it's likely that the
-    encoder will have to be reconfigured).  This also clears the "useless"
-    state. */
-@@ -275,11 +264,21 @@ int pvr2_hdw_gpio_chg_out(struct pvr2_hdw *hdw,u32 msk,u32 val);
- struct pvr2_hdw_debug_info {
- 	int big_lock_held;
- 	int ctl_lock_held;
--	int flag_ok;
- 	int flag_disconnected;
- 	int flag_init_ok;
--	int flag_streaming_enabled;
--	unsigned long subsys_flags;
-+	int flag_ok;
-+	int fw1_state;
-+	int flag_decoder_missed;
-+	int flag_tripped;
-+	int state_encoder_ok;
-+	int state_encoder_run;
-+	int state_decoder_run;
-+	int state_usbstream_run;
-+	int state_decoder_quiescent;
-+	int state_pipeline_config;
-+	int state_pipeline_req;
-+	int state_pipeline_pause;
-+	int state_pipeline_idle;
- 	int cmd_debug_state;
- 	int cmd_debug_write_len;
- 	int cmd_debug_read_len;
-@@ -295,8 +294,20 @@ struct pvr2_hdw_debug_info {
-    diagnosing lockups.  Note that this operation is completed without any
-    kind of locking and so it is not atomic and may yield inconsistent
-    results.  This is *purely* a debugging aid. */
--void pvr2_hdw_get_debug_info(const struct pvr2_hdw *hdw,
--			     struct pvr2_hdw_debug_info *);
-+void pvr2_hdw_get_debug_info_unlocked(const struct pvr2_hdw *hdw,
-+				      struct pvr2_hdw_debug_info *);
++	return strlen(buf);
++}
 +
-+/* Intrusively retrieve internal state info - this is useful for
-+   diagnosing overall driver state.  This operation synchronizes against
-+   the overall driver mutex - so if there are locking problems this will
-+   likely hang!  This is *purely* a debugging aid. */
-+void pvr2_hdw_get_debug_info_locked(struct pvr2_hdw *hdw,
-+				    struct pvr2_hdw_debug_info *);
++static DEVICE_ATTR(brightness, S_IRUGO | S_IWUGO,
++			show_brightness, store_brightness);
++static DEVICE_ATTR(hflip, S_IRUGO | S_IWUGO, show_hflip, store_hflip);
++static DEVICE_ATTR(vflip, S_IRUGO | S_IWUGO, show_vflip, store_vflip);
 +
-+/* Report out several lines of text that describes driver internal state.
-+   Results are written into the passed-in buffer. */
-+unsigned int pvr2_hdw_state_report(struct pvr2_hdw *hdw,
-+				   char *buf_ptr,unsigned int buf_size);
- 
- /* Cause modules to log their state once */
- void pvr2_hdw_trigger_module_log(struct pvr2_hdw *hdw);
-@@ -306,9 +317,6 @@ void pvr2_hdw_trigger_module_log(struct pvr2_hdw *hdw);
-    a debugging aid. */
- int pvr2_upload_firmware2(struct pvr2_hdw *hdw);
- 
--/* List of device types that we can match */
--extern struct usb_device_id pvr2_device_table[];
--
- #endif /* __PVRUSB2_HDW_H */
- 
- /*
-diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
-index c817c86..62867fa 100644
---- a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
-+++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
-@@ -895,7 +895,7 @@ static int pvr2_i2c_attach_inform(struct i2c_client *client)
- 		list_add_tail(&cp->list,&hdw->i2c_clients);
- 		hdw->i2c_pend_types |= PVR2_I2C_PEND_DETECT;
- 	} while (0); mutex_unlock(&hdw->i2c_list_lock);
--	if (fl) pvr2_hdw_poll_trigger_unlocked(hdw);
-+	if (fl) queue_work(hdw->workqueue,&hdw->worki2csync);
- 	return 0;
- }
- 
-@@ -980,14 +980,16 @@ void pvr2_i2c_core_init(struct pvr2_hdw *hdw)
- 		printk(KERN_INFO "%s: IR disabled\n",hdw->name);
- 		hdw->i2c_func[0x18] = i2c_black_hole;
- 	} else if (ir_mode[hdw->unit_number] == 1) {
--		if (hdw->hdw_type == PVR2_HDW_TYPE_24XXX) {
-+		if (hdw->hdw_desc->flag_has_hauppauge_custom_ir) {
- 			hdw->i2c_func[0x18] = i2c_24xxx_ir;
- 		}
- 	}
--	if (hdw->hdw_type == PVR2_HDW_TYPE_24XXX) {
--		hdw->i2c_func[0x1b] = i2c_hack_wm8775;
-+	if (hdw->hdw_desc->flag_has_cx25840) {
- 		hdw->i2c_func[0x44] = i2c_hack_cx25840;
- 	}
-+	if (hdw->hdw_desc->flag_has_wm8775) {
-+		hdw->i2c_func[0x1b] = i2c_hack_wm8775;
-+	}
- 
- 	// Configure the adapter and set up everything else related to it.
- 	memcpy(&hdw->i2c_adap,&pvr2_i2c_adap_template,sizeof(hdw->i2c_adap));
-diff --git a/drivers/media/video/pvrusb2/pvrusb2-main.c b/drivers/media/video/pvrusb2/pvrusb2-main.c
-index 11b3b2e..b63b226 100644
---- a/drivers/media/video/pvrusb2/pvrusb2-main.c
-+++ b/drivers/media/video/pvrusb2/pvrusb2-main.c
-@@ -28,6 +28,7 @@
- #include <linux/videodev2.h>
- 
- #include "pvrusb2-hdw.h"
-+#include "pvrusb2-devattr.h"
- #include "pvrusb2-context.h"
- #include "pvrusb2-debug.h"
- #include "pvrusb2-v4l2.h"
-@@ -148,11 +149,6 @@ static void __exit pvr_exit(void)
- module_init(pvr_init);
- module_exit(pvr_exit);
- 
--/* Mike Isely <mcisely at pobox.com> 11-Mar-2006: See pvrusb2-hdw.c for
--   MODULE_DEVICE_TABLE().  We have to declare that attribute there
--   because that's where the device table actually is now and it seems
--   that certain gcc configurations get angry if MODULE_DEVICE_TABLE()
--   is used on what ends up being an external symbol. */
- MODULE_AUTHOR(DRIVER_AUTHOR);
- MODULE_DESCRIPTION(DRIVER_DESC);
- MODULE_LICENSE("GPL");
-diff --git a/drivers/media/video/pvrusb2/pvrusb2-std.c b/drivers/media/video/pvrusb2/pvrusb2-std.c
-index 63e55bb..da30928 100644
---- a/drivers/media/video/pvrusb2/pvrusb2-std.c
-+++ b/drivers/media/video/pvrusb2/pvrusb2-std.c
-@@ -50,6 +50,10 @@ struct std_name {
- 	 V4L2_STD_NTSC_M_KR| \
- 	 V4L2_STD_NTSC_443)
- 
-+#define CSTD_ATSC \
-+	(V4L2_STD_ATSC_8_VSB| \
-+	 V4L2_STD_ATSC_16_VSB)
++static int stk_create_sysfs_files(struct video_device *vdev)
++{
++	int ret;
 +
- #define CSTD_SECAM \
- 	(V4L2_STD_SECAM_B| \
- 	 V4L2_STD_SECAM_D| \
-@@ -82,6 +86,7 @@ static const struct std_name std_groups[] = {
- 	{"PAL",CSTD_PAL},
- 	{"NTSC",CSTD_NTSC},
- 	{"SECAM",CSTD_SECAM},
-+	{"ATSC",CSTD_ATSC},
- };
- 
- /* Mapping of standard bits to modulation system */
-@@ -104,6 +109,8 @@ static const struct std_name std_items[] = {
- 	{"N",TSTD_N},
- 	{"Nc",TSTD_Nc},
- 	{"60",TSTD_60},
-+	{"8VSB",V4L2_STD_ATSC_8_VSB},
-+	{"16VSB",V4L2_STD_ATSC_16_VSB},
- };
- 
- 
-diff --git a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c
-index 3c57a7d..7a1cd87 100644
---- a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c
-+++ b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c
-@@ -43,10 +43,14 @@ struct pvr2_sysfs {
- 	struct device_attribute attr_v4l_radio_minor_number;
- 	struct device_attribute attr_unit_number;
- 	struct device_attribute attr_bus_info;
-+	struct device_attribute attr_hdw_name;
-+	struct device_attribute attr_hdw_desc;
- 	int v4l_minor_number_created_ok;
- 	int v4l_radio_minor_number_created_ok;
- 	int unit_number_created_ok;
- 	int bus_info_created_ok;
-+	int hdw_name_created_ok;
-+	int hdw_desc_created_ok;
- };
- 
- #ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC
-@@ -712,6 +716,14 @@ static void class_dev_destroy(struct pvr2_sysfs *sfp)
- 	pvr2_sysfs_tear_down_debugifc(sfp);
- #endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */
- 	pvr2_sysfs_tear_down_controls(sfp);
-+	if (sfp->hdw_desc_created_ok) {
-+		device_remove_file(sfp->class_dev,
-+				   &sfp->attr_hdw_desc);
-+	}
-+	if (sfp->hdw_name_created_ok) {
-+		device_remove_file(sfp->class_dev,
-+				   &sfp->attr_hdw_name);
-+	}
- 	if (sfp->bus_info_created_ok) {
- 		device_remove_file(sfp->class_dev,
- 					 &sfp->attr_bus_info);
-@@ -758,6 +770,28 @@ static ssize_t bus_info_show(struct device *class_dev,
- }
- 
- 
-+static ssize_t hdw_name_show(struct device *class_dev,
-+			     struct device_attribute *attr, char *buf)
++	ret = video_device_create_file(vdev, &dev_attr_brightness);
++	ret += video_device_create_file(vdev, &dev_attr_hflip);
++	ret += video_device_create_file(vdev, &dev_attr_vflip);
++	return ret;
++}
++
++static void stk_remove_sysfs_files(struct video_device *vdev)
 +{
-+	struct pvr2_sysfs *sfp;
-+	sfp = (struct pvr2_sysfs *)class_dev->driver_data;
-+	if (!sfp) return -EINVAL;
-+	return scnprintf(buf,PAGE_SIZE,"%s\n",
-+			 pvr2_hdw_get_type(sfp->channel.hdw));
++	video_device_remove_file(vdev, &dev_attr_brightness);
++	video_device_remove_file(vdev, &dev_attr_hflip);
++	video_device_remove_file(vdev, &dev_attr_vflip);
 +}
 +
 +
-+static ssize_t hdw_desc_show(struct device *class_dev,
-+			     struct device_attribute *attr, char *buf)
++/* *********************************************** */
++/*
++ * This function is called as an URB transfert is complete (Isochronous pipe).
++ * So, the traitement is done in interrupt time, so it has be fast, not crash,
++ * and not stall. Neat.
++ */
++static void stk_isoc_handler(struct urb *urb)
 +{
-+	struct pvr2_sysfs *sfp;
-+	sfp = (struct pvr2_sysfs *)class_dev->driver_data;
-+	if (!sfp) return -EINVAL;
-+	return scnprintf(buf,PAGE_SIZE,"%s\n",
-+			 pvr2_hdw_get_desc(sfp->channel.hdw));
-+}
++	int i;
++	int ret;
++	int framelen;
++	unsigned long flags;
 +
++	unsigned char *fill = NULL;
++	unsigned char *iso_buf = NULL;
 +
- static ssize_t v4l_radio_minor_number_show(struct device *class_dev,
- 					   struct device_attribute *attr,
- 					   char *buf)
-@@ -871,6 +905,32 @@ static void class_dev_create(struct pvr2_sysfs *sfp,
- 		sfp->bus_info_created_ok = !0;
- 	}
- 
-+	sfp->attr_hdw_name.attr.name = "device_hardware_type";
-+	sfp->attr_hdw_name.attr.mode = S_IRUGO;
-+	sfp->attr_hdw_name.show = hdw_name_show;
-+	sfp->attr_hdw_name.store = NULL;
-+	ret = device_create_file(sfp->class_dev,
-+				 &sfp->attr_hdw_name);
-+	if (ret < 0) {
-+		printk(KERN_WARNING "%s: device_create_file error: %d\n",
-+		       __FUNCTION__, ret);
-+	} else {
-+		sfp->hdw_name_created_ok = !0;
-+	}
++	struct stk_camera *dev;
++	struct stk_sio_buffer *fb;
 +
-+	sfp->attr_hdw_desc.attr.name = "device_hardware_description";
-+	sfp->attr_hdw_desc.attr.mode = S_IRUGO;
-+	sfp->attr_hdw_desc.show = hdw_desc_show;
-+	sfp->attr_hdw_desc.store = NULL;
-+	ret = device_create_file(sfp->class_dev,
-+				 &sfp->attr_hdw_desc);
-+	if (ret < 0) {
-+		printk(KERN_WARNING "%s: device_create_file error: %d\n",
-+		       __FUNCTION__, ret);
-+	} else {
-+		sfp->hdw_desc_created_ok = !0;
++	dev = (struct stk_camera *) urb->context;
++
++	if (dev == NULL) {
++		STK_ERROR("isoc_handler called with NULL device !\n");
++		return;
 +	}
 +
- 	pvr2_sysfs_add_controls(sfp);
- #ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC
- 	pvr2_sysfs_add_debugifc(sfp);
-diff --git a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
-index 7a596ea..8f0587e 100644
---- a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
-+++ b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
-@@ -205,6 +205,7 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
- 		memcpy(cap, &pvr_capability, sizeof(struct v4l2_capability));
- 		strlcpy(cap->bus_info,pvr2_hdw_get_bus_info(hdw),
- 			sizeof(cap->bus_info));
-+		strlcpy(cap->card,pvr2_hdw_get_desc(hdw),sizeof(cap->card));
- 
- 		ret = 0;
- 		break;
-@@ -1015,10 +1016,8 @@ static int pvr2_v4l2_iosetup(struct pvr2_v4l2_fh *fh)
- 	sp = fh->dev_info->stream->stream;
- 	pvr2_stream_set_callback(sp,(pvr2_stream_callback)pvr2_v4l2_notify,fh);
- 	pvr2_hdw_set_stream_type(hdw,fh->dev_info->config);
--	pvr2_hdw_set_streaming(hdw,!0);
--	ret = pvr2_ioread_set_enabled(fh->rhp,!0);
--
--	return ret;
-+	if ((ret = pvr2_hdw_set_streaming(hdw,!0)) < 0) return ret;
-+	return pvr2_ioread_set_enabled(fh->rhp,!0);
- }
- 
- 
-diff --git a/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c b/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c
-index 61efa6f..7c47345 100644
---- a/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c
-+++ b/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c
-@@ -49,29 +49,50 @@ struct pvr2_v4l_decoder {
- };
- 
- 
-+struct routing_scheme {
-+	const int *def;
-+	unsigned int cnt;
-+};
++	if (urb->status == -ENOENT || urb->status == -ECONNRESET
++		|| urb->status == -ESHUTDOWN) {
++		atomic_dec(&dev->urbs_used);
++		return;
++	}
 +
++	spin_lock_irqsave(&dev->spinlock, flags);
 +
-+static const int routing_scheme0[] = {
-+	[PVR2_CVAL_INPUT_TV] = SAA7115_COMPOSITE4,
-+	/* In radio mode, we mute the video, but point at one
-+	   spot just to stay consistent */
-+	[PVR2_CVAL_INPUT_RADIO] = SAA7115_COMPOSITE5,
-+	[PVR2_CVAL_INPUT_COMPOSITE] = SAA7115_COMPOSITE5,
-+	[PVR2_CVAL_INPUT_SVIDEO] =  SAA7115_SVIDEO2,
-+};
++	if (urb->status != -EINPROGRESS && urb->status != 0) {
++		STK_ERROR("isoc_handler: urb->status == %d\n", urb->status);
++		goto resubmit;
++	}
 +
-+static const struct routing_scheme routing_schemes[] = {
-+	[PVR2_ROUTING_SCHEME_HAUPPAUGE] = {
-+		.def = routing_scheme0,
-+		.cnt = ARRAY_SIZE(routing_scheme0),
-+	},
-+};
++	if (list_empty(&dev->sio_avail)) {
++		/*FIXME Stop streaming after a while */
++		(void) (printk_ratelimit() &&
++		STK_ERROR("isoc_handler without available buffer!\n"));
++		goto resubmit;
++	}
++	fb = list_first_entry(&dev->sio_avail,
++			struct stk_sio_buffer, list);
++	fill = fb->buffer + fb->v4lbuf.bytesused;
 +
- static void set_input(struct pvr2_v4l_decoder *ctxt)
- {
- 	struct pvr2_hdw *hdw = ctxt->hdw;
- 	struct v4l2_routing route;
-+	const struct routing_scheme *sp;
-+	unsigned int sid = hdw->hdw_desc->signal_routing_scheme;
- 
- 	pvr2_trace(PVR2_TRACE_CHIPS,"i2c v4l2 set_input(%d)",hdw->input_val);
--	switch(hdw->input_val) {
--	case PVR2_CVAL_INPUT_TV:
--		route.input = SAA7115_COMPOSITE4;
--		break;
--	case PVR2_CVAL_INPUT_COMPOSITE:
--		route.input = SAA7115_COMPOSITE5;
--		break;
--	case PVR2_CVAL_INPUT_SVIDEO:
--		route.input = SAA7115_SVIDEO2;
--		break;
--	case PVR2_CVAL_INPUT_RADIO:
--		// In radio mode, we mute the video, but point at one
--		// spot just to stay consistent
--		route.input = SAA7115_COMPOSITE5;
--	default:
++	for (i = 0; i < urb->number_of_packets; i++) {
++		if (urb->iso_frame_desc[i].status != 0) {
++			if (urb->iso_frame_desc[i].status != -EXDEV)
++				STK_ERROR("Frame %d has error %d\n", i,
++					urb->iso_frame_desc[i].status);
++			continue;
++		}
++		framelen = urb->iso_frame_desc[i].actual_length;
++		iso_buf = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
 +
-+	if ((sid < ARRAY_SIZE(routing_schemes)) &&
-+	    ((sp = routing_schemes + sid) != 0) &&
-+	    (hdw->input_val >= 0) &&
-+	    (hdw->input_val < sp->cnt)) {
-+		route.input = sp->def[hdw->input_val];
-+	} else {
-+		pvr2_trace(PVR2_TRACE_ERROR_LEGS,
-+			   "*** WARNING *** i2c v4l2 set_input:"
-+			   " Invalid routing scheme (%u) and/or input (%d)",
-+			   sid,hdw->input_val);
- 		return;
- 	}
++		if (framelen <= 4)
++			continue; /* no data */
 +
- 	route.output = 0;
- 	pvr2_i2c_client_cmd(ctxt->client,VIDIOC_INT_S_VIDEO_ROUTING,&route);
- }
-@@ -129,7 +150,7 @@ static const struct pvr2_v4l_decoder_ops decoder_ops[] = {
- static void decoder_detach(struct pvr2_v4l_decoder *ctxt)
- {
- 	ctxt->client->handler = NULL;
--	ctxt->hdw->decoder_ctrl = NULL;
-+	pvr2_hdw_set_decoder(ctxt->hdw,NULL);
- 	kfree(ctxt);
- }
- 
-@@ -217,7 +238,7 @@ int pvr2_i2c_decoder_v4l_setup(struct pvr2_hdw *hdw,
- 	ctxt->client = cp;
- 	ctxt->hdw = hdw;
- 	ctxt->stale_mask = (1 << ARRAY_SIZE(decoder_ops)) - 1;
--	hdw->decoder_ctrl = &ctxt->ctrl;
-+	pvr2_hdw_set_decoder(hdw,&ctxt->ctrl);
- 	cp->handler = &ctxt->handler;
- 	pvr2_trace(PVR2_TRACE_CHIPS,"i2c 0x%x saa711x V4L2 handler set up",
- 		   cp->client->addr);
-diff --git a/drivers/media/video/saa7115.c b/drivers/media/video/saa7115.c
-index 2d18f00..41e5e51 100644
---- a/drivers/media/video/saa7115.c
-+++ b/drivers/media/video/saa7115.c
-@@ -46,6 +46,7 @@
- #include <linux/videodev2.h>
- #include <media/v4l2-common.h>
- #include <media/v4l2-chip-ident.h>
-+#include <media/v4l2-i2c-drv-legacy.h>
- #include <media/saa7115.h>
- #include <asm/div64.h>
- 
-@@ -1230,7 +1231,7 @@ static void saa711x_decode_vbi_line(struct i2c_client *client,
- 
- /* ============ SAA7115 AUDIO settings (end) ============= */
- 
--static int saa711x_command(struct i2c_client *client, unsigned int cmd, void *arg)
-+static int saa7115_command(struct i2c_client *client, unsigned int cmd, void *arg)
- {
- 	struct saa711x_state *state = i2c_get_clientdata(client);
- 
-@@ -1449,26 +1450,17 @@ static int saa711x_command(struct i2c_client *client, unsigned int cmd, void *ar
- 
- /* ----------------------------------------------------------------------- */
- 
--static struct i2c_driver i2c_driver_saa711x;
--
--static int saa711x_attach(struct i2c_adapter *adapter, int address, int kind)
-+static int saa7115_probe(struct i2c_client *client)
- {
--	struct i2c_client *client;
- 	struct saa711x_state *state;
- 	int	i;
- 	char	name[17];
- 	u8 chip_id;
- 
- 	/* Check if the adapter supports the needed features */
--	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
--		return 0;
-+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
-+		return -EIO;
- 
--	client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
--	if (client == 0)
--		return -ENOMEM;
--	client->addr = address;
--	client->adapter = adapter;
--	client->driver = &i2c_driver_saa711x;
- 	snprintf(client->name, sizeof(client->name) - 1, "saa7115");
- 
- 	for (i = 0; i < 0x0f; i++) {
-@@ -1485,18 +1477,16 @@ static int saa711x_attach(struct i2c_adapter *adapter, int address, int kind)
- 	/* Check whether this chip is part of the saa711x series */
- 	if (memcmp(name, "1f711", 5)) {
- 		v4l_dbg(1, debug, client, "chip found @ 0x%x (ID %s) does not match a known saa711x chip.\n",
--			address << 1, name);
--		kfree(client);
--		return 0;
-+			client->addr << 1, name);
-+		return -ENODEV;
- 	}
- 
- 	snprintf(client->name, sizeof(client->name) - 1, "saa711%d",chip_id);
--	v4l_info(client, "saa711%d found (%s) @ 0x%x (%s)\n", chip_id, name, address << 1, adapter->name);
-+	v4l_info(client, "saa711%d found (%s) @ 0x%x (%s)\n", chip_id, name, client->addr << 1, client->adapter->name);
- 
- 	state = kzalloc(sizeof(struct saa711x_state), GFP_KERNEL);
- 	i2c_set_clientdata(client, state);
- 	if (state == NULL) {
--		kfree(client);
- 		return -ENOMEM;
- 	}
- 	state->input = -1;
-@@ -1549,59 +1539,25 @@ static int saa711x_attach(struct i2c_adapter *adapter, int address, int kind)
- 	saa711x_writeregs(client, saa7115_init_misc);
- 	saa711x_set_v4lstd(client, V4L2_STD_NTSC);
- 
--	i2c_attach_client(client);
--
- 	v4l_dbg(1, debug, client, "status: (1E) 0x%02x, (1F) 0x%02x\n",
- 		saa711x_read(client, R_1E_STATUS_BYTE_1_VD_DEC), saa711x_read(client, R_1F_STATUS_BYTE_2_VD_DEC));
--
- 	return 0;
- }
- 
--static int saa711x_probe(struct i2c_adapter *adapter)
--{
--	if (adapter->class & I2C_CLASS_TV_ANALOG || adapter->class & I2C_CLASS_TV_DIGITAL)
--		return i2c_probe(adapter, &addr_data, &saa711x_attach);
--	return 0;
--}
-+/* ----------------------------------------------------------------------- */
- 
--static int saa711x_detach(struct i2c_client *client)
-+static int saa7115_remove(struct i2c_client *client)
- {
--	struct saa711x_state *state = i2c_get_clientdata(client);
--	int err;
--
--	err = i2c_detach_client(client);
--	if (err) {
--		return err;
--	}
--
--	kfree(state);
--	kfree(client);
-+	kfree(i2c_get_clientdata(client));
- 	return 0;
- }
- 
--/* ----------------------------------------------------------------------- */
--
--/* i2c implementation */
--static struct i2c_driver i2c_driver_saa711x = {
--	.driver = {
--		.name = "saa7115",
--	},
--	.id = I2C_DRIVERID_SAA711X,
--	.attach_adapter = saa711x_probe,
--	.detach_client = saa711x_detach,
--	.command = saa711x_command,
-+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
-+	.name = "saa7115",
-+	.driverid = I2C_DRIVERID_SAA711X,
-+	.command = saa7115_command,
-+	.probe = saa7115_probe,
-+	.remove = saa7115_remove,
-+	.legacy_class = I2C_CLASS_TV_ANALOG | I2C_CLASS_TV_DIGITAL,
- };
- 
--
--static int __init saa711x_init_module(void)
--{
--	return i2c_add_driver(&i2c_driver_saa711x);
--}
--
--static void __exit saa711x_cleanup_module(void)
--{
--	i2c_del_driver(&i2c_driver_saa711x);
--}
--
--module_init(saa711x_init_module);
--module_exit(saa711x_cleanup_module);
-diff --git a/drivers/media/video/saa7127.c b/drivers/media/video/saa7127.c
-index e35ef32..06c88db 100644
---- a/drivers/media/video/saa7127.c
-+++ b/drivers/media/video/saa7127.c
-@@ -55,10 +55,11 @@
- #include <linux/videodev2.h>
- #include <media/v4l2-common.h>
- #include <media/v4l2-chip-ident.h>
-+#include <media/v4l2-i2c-drv.h>
- #include <media/saa7127.h>
- 
--static int debug = 0;
--static int test_image = 0;
-+static int debug;
-+static int test_image;
- 
- MODULE_DESCRIPTION("Philips SAA7127/9 video encoder driver");
- MODULE_AUTHOR("Kevin Thayer, Chris Kennedy, Hans Verkuil");
-@@ -68,10 +69,6 @@ module_param(test_image, int, 0644);
- MODULE_PARM_DESC(debug, "debug level (0-2)");
- MODULE_PARM_DESC(test_image, "test_image (0-1)");
- 
--static unsigned short normal_i2c[] = { 0x88 >> 1, I2C_CLIENT_END };
--
--
--I2C_CLIENT_INSMOD;
- 
- /*
-  * SAA7127 registers
-@@ -360,9 +357,10 @@ static int saa7127_set_cc(struct i2c_client *client, struct v4l2_sliced_vbi_data
- 	if (enable && (data->field != 0 || data->line != 21))
- 		return -EINVAL;
- 	if (state->cc_enable != enable) {
--		v4l_dbg(1, debug, client, "Turn CC %s\n", enable ? "on" : "off");
-+		v4l_dbg(1, debug, client,
-+			"Turn CC %s\n", enable ? "on" : "off");
- 		saa7127_write(client, SAA7127_REG_CLOSED_CAPTION,
--				(state->xds_enable << 7) | (enable << 6) | 0x11);
-+			(state->xds_enable << 7) | (enable << 6) | 0x11);
- 		state->cc_enable = enable;
- 	}
- 	if (!enable)
-@@ -420,7 +418,8 @@ static int saa7127_set_wss(struct i2c_client *client, struct v4l2_sliced_vbi_dat
- 
- 	saa7127_write(client, 0x26, data->data[0]);
- 	saa7127_write(client, 0x27, 0x80 | (data->data[1] & 0x3f));
--	v4l_dbg(1, debug, client, "WSS mode: %s\n", wss_strs[data->data[0] & 0xf]);
-+	v4l_dbg(1, debug, client,
-+		"WSS mode: %s\n", wss_strs[data->data[0] & 0xf]);
- 	state->wss_mode = (data->data[1] & 0x3f) << 8 | data->data[0];
- 	return 0;
- }
-@@ -507,7 +506,8 @@ static int saa7127_set_output_type(struct i2c_client *client, int output)
- 	default:
- 		return -EINVAL;
- 	}
--	v4l_dbg(1, debug, client, "Selecting %s output type\n", output_strs[output]);
-+	v4l_dbg(1, debug, client,
-+		"Selecting %s output type\n", output_strs[output]);
- 
- 	/* Configure Encoder */
- 	saa7127_write(client, 0x2d, state->reg_2d);
-@@ -569,12 +569,10 @@ static int saa7127_command(struct i2c_client *client,
- 	{
- 		int rc = 0;
- 
--		if (state->input_type != route->input) {
-+		if (state->input_type != route->input)
- 			rc = saa7127_set_input_type(client, route->input);
--		}
--		if (rc == 0 && state->output_type != route->output) {
-+		if (rc == 0 && state->output_type != route->output)
- 			rc = saa7127_set_output_type(client, route->output);
--		}
- 		return rc;
- 	}
- 
-@@ -620,7 +618,8 @@ static int saa7127_command(struct i2c_client *client,
- 	{
- 		struct v4l2_register *reg = arg;
- 
--		if (!v4l2_chip_match_i2c_client(client, reg->match_type, reg->match_chip))
-+		if (!v4l2_chip_match_i2c_client(client,
-+					reg->match_type, reg->match_chip))
- 			return -EINVAL;
- 		if (!capable(CAP_SYS_ADMIN))
- 			return -EPERM;
-@@ -637,16 +636,16 @@ static int saa7127_command(struct i2c_client *client,
- 		struct v4l2_sliced_vbi_data *data = arg;
- 
- 		switch (data->id) {
--			case V4L2_SLICED_WSS_625:
--				return saa7127_set_wss(client, data);
--			case V4L2_SLICED_VPS:
--				return saa7127_set_vps(client, data);
--			case V4L2_SLICED_CAPTION_525:
--				if (data->field == 0)
--					return saa7127_set_cc(client, data);
--				return saa7127_set_xds(client, data);
--			default:
--				return -EINVAL;
-+		case V4L2_SLICED_WSS_625:
-+			return saa7127_set_wss(client, data);
-+		case V4L2_SLICED_VPS:
-+			return saa7127_set_vps(client, data);
-+		case V4L2_SLICED_CAPTION_525:
-+			if (data->field == 0)
-+				return saa7127_set_cc(client, data);
-+			return saa7127_set_xds(client, data);
-+		default:
-+			return -EINVAL;
- 		}
- 		break;
- 	}
-@@ -662,31 +661,20 @@ static int saa7127_command(struct i2c_client *client,
- 
- /* ----------------------------------------------------------------------- */
- 
--static struct i2c_driver i2c_driver_saa7127;
--
--/* ----------------------------------------------------------------------- */
--
--static int saa7127_attach(struct i2c_adapter *adapter, int address, int kind)
-+static int saa7127_probe(struct i2c_client *client)
- {
--	struct i2c_client *client;
- 	struct saa7127_state *state;
- 	struct v4l2_sliced_vbi_data vbi = { 0, 0, 0, 0 };  /* set to disabled */
- 	int read_result = 0;
- 
- 	/* Check if the adapter supports the needed features */
--	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
--		return 0;
--
--	client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
--	if (client == 0)
--		return -ENOMEM;
-+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
-+		return -EIO;
- 
--	client->addr = address;
--	client->adapter = adapter;
--	client->driver = &i2c_driver_saa7127;
- 	snprintf(client->name, sizeof(client->name) - 1, "saa7127");
- 
--	v4l_dbg(1, debug, client, "detecting saa7127 client on address 0x%x\n", address << 1);
-+	v4l_dbg(1, debug, client, "detecting saa7127 client on address 0x%x\n",
-+			client->addr << 1);
- 
- 	/* First test register 0: Bits 5-7 are a version ID (should be 0),
- 	   and bit 2 should also be 0.
-@@ -696,15 +684,12 @@ static int saa7127_attach(struct i2c_adapter *adapter, int address, int kind)
- 	if ((saa7127_read(client, 0) & 0xe4) != 0 ||
- 			(saa7127_read(client, 0x29) & 0x3f) != 0x1d) {
- 		v4l_dbg(1, debug, client, "saa7127 not found\n");
--		kfree(client);
--		return 0;
-+		return -ENODEV;
- 	}
- 	state = kzalloc(sizeof(struct saa7127_state), GFP_KERNEL);
- 
--	if (state == NULL) {
--		kfree(client);
--		return (-ENOMEM);
--	}
-+	if (state == NULL)
-+		return -ENOMEM;
- 
- 	i2c_set_clientdata(client, state);
- 
-@@ -718,91 +703,48 @@ static int saa7127_attach(struct i2c_adapter *adapter, int address, int kind)
- 	saa7127_set_wss(client, &vbi);
- 	saa7127_set_cc(client, &vbi);
- 	saa7127_set_xds(client, &vbi);
--	if (test_image == 1) {
-+	if (test_image == 1)
- 		/* The Encoder has an internal Colorbar generator */
- 		/* This can be used for debugging */
- 		saa7127_set_input_type(client, SAA7127_INPUT_TYPE_TEST_IMAGE);
--	} else {
++		/*
++		 * we found something informational from there
++		 * the isoc frames have to type of headers
++		 * type1: 00 xx 00 00 or 20 xx 00 00
++		 * type2: 80 xx 00 00 00 00 00 00 or a0 xx 00 00 00 00 00 00
++		 * xx is a sequencer which has never been seen over 0x3f
++		 * imho data written down looks like bayer, i see similarities
++		 * after every 640 bytes
++		 */
++		if (*iso_buf & 0x80) {
++			framelen -= 8;
++			iso_buf += 8;
++			/* This marks a new frame */
++			if (fb->v4lbuf.bytesused != 0
++				&& fb->v4lbuf.bytesused != dev->frame_size) {
++				(void) (printk_ratelimit() &&
++				STK_ERROR("frame %d, "
++					"bytesused=%d, skipping\n",
++					i, fb->v4lbuf.bytesused));
++				fb->v4lbuf.bytesused = 0;
++				fill = fb->buffer;
++			} else if (fb->v4lbuf.bytesused == dev->frame_size) {
++				list_move_tail(dev->sio_avail.next,
++					&dev->sio_full);
++				wake_up(&dev->wait_frame);
++				if (list_empty(&dev->sio_avail)) {
++					(void) (printk_ratelimit() &&
++					STK_ERROR("No buffer available\n"));
++					goto resubmit;
++				}
++				fb = list_first_entry(&dev->sio_avail,
++					struct stk_sio_buffer, list);
++				fb->v4lbuf.bytesused = 0;
++				fill = fb->buffer;
++			}
++		} else {
++			framelen -= 4;
++			iso_buf += 4;
++		}
++
++		/* Our buffer is full !!! */
++		if (framelen + fb->v4lbuf.bytesused > dev->frame_size) {
++			(void) (printk_ratelimit() &&
++			STK_ERROR("Frame buffer overflow, lost sync\n"));
++			/*FIXME Do something here? */
++			continue;
++		}
++		spin_unlock_irqrestore(&dev->spinlock, flags);
++		memcpy(fill, iso_buf, framelen);
++		spin_lock_irqsave(&dev->spinlock, flags);
++		fill += framelen;
++
++		/* New size of our buffer */
++		fb->v4lbuf.bytesused += framelen;
++	}
++
++resubmit:
++	spin_unlock_irqrestore(&dev->spinlock, flags);
++	urb->dev = dev->udev;
++	ret = usb_submit_urb(urb, GFP_ATOMIC);
++	if (ret != 0) {
++		STK_ERROR("Error (%d) re-submitting urb in stk_isoc_handler.\n",
++			ret);
++	}
++}
++
++/* -------------------------------------------- */
++
++static int stk_prepare_iso(struct stk_camera *dev)
++{
++	void *kbuf;
++	int i, j;
++	struct urb *urb;
++	struct usb_device *udev;
++
++	if (dev == NULL)
++		return -ENXIO;
++	udev = dev->udev;
++
++	if (dev->isobufs)
++		STK_ERROR("isobufs already allocated. Bad\n");
 +	else
- 		saa7127_set_input_type(client, SAA7127_INPUT_TYPE_NORMAL);
--	}
- 	saa7127_set_video_enable(client, 1);
- 
- 	/* Detect if it's an saa7129 */
- 	read_result = saa7127_read(client, SAA7129_REG_FADE_KEY_COL2);
- 	saa7127_write(client, SAA7129_REG_FADE_KEY_COL2, 0xaa);
- 	if (saa7127_read(client, SAA7129_REG_FADE_KEY_COL2) == 0xaa) {
--		v4l_info(client, "saa7129 found @ 0x%x (%s)\n", address << 1, adapter->name);
-+		v4l_info(client, "saa7129 found @ 0x%x (%s)\n",
-+				client->addr << 1, client->adapter->name);
- 		saa7127_write(client, SAA7129_REG_FADE_KEY_COL2, read_result);
- 		saa7127_write_inittab(client, saa7129_init_config_extra);
- 		state->ident = V4L2_IDENT_SAA7129;
- 	} else {
--		v4l_info(client, "saa7127 found @ 0x%x (%s)\n", address << 1, adapter->name);
-+		v4l_info(client, "saa7127 found @ 0x%x (%s)\n",
-+				client->addr << 1, client->adapter->name);
- 		state->ident = V4L2_IDENT_SAA7127;
- 	}
--
--	i2c_attach_client(client);
--
- 	return 0;
- }
- 
- /* ----------------------------------------------------------------------- */
- 
--static int saa7127_probe(struct i2c_adapter *adapter)
-+static int saa7127_remove(struct i2c_client *client)
- {
--	if (adapter->class & I2C_CLASS_TV_ANALOG)
--		return i2c_probe(adapter, &addr_data, saa7127_attach);
--	return 0;
--}
--
--/* ----------------------------------------------------------------------- */
--
--static int saa7127_detach(struct i2c_client *client)
--{
--	struct saa7127_state *state = i2c_get_clientdata(client);
--	int err;
--
- 	/* Turn off TV output */
- 	saa7127_set_video_enable(client, 0);
--
--	err = i2c_detach_client(client);
--
--	if (err) {
--		return err;
--	}
--
--	kfree(state);
--	kfree(client);
-+	kfree(i2c_get_clientdata(client));
- 	return 0;
- }
- 
- /* ----------------------------------------------------------------------- */
- 
--static struct i2c_driver i2c_driver_saa7127 = {
--	.driver = {
--		.name = "saa7127",
--	},
--	.id = I2C_DRIVERID_SAA7127,
--	.attach_adapter = saa7127_probe,
--	.detach_client = saa7127_detach,
-+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
-+	.name = "saa7127",
-+	.driverid = I2C_DRIVERID_SAA7127,
- 	.command = saa7127_command,
-+	.probe = saa7127_probe,
-+	.remove = saa7127_remove,
- };
- 
--
--/* ----------------------------------------------------------------------- */
--
--static int __init saa7127_init_module(void)
--{
--	return i2c_add_driver(&i2c_driver_saa7127);
--}
--
--/* ----------------------------------------------------------------------- */
--
--static void __exit saa7127_cleanup_module(void)
--{
--	i2c_del_driver(&i2c_driver_saa7127);
--}
--
--/* ----------------------------------------------------------------------- */
--
--module_init(saa7127_init_module);
--module_exit(saa7127_cleanup_module);
-diff --git a/drivers/media/video/saa7134/Kconfig b/drivers/media/video/saa7134/Kconfig
-index 3aa8cb2..96bc3b1 100644
---- a/drivers/media/video/saa7134/Kconfig
-+++ b/drivers/media/video/saa7134/Kconfig
-@@ -4,6 +4,7 @@ config VIDEO_SAA7134
- 	select VIDEOBUF_DMA_SG
- 	select VIDEO_IR
- 	select VIDEO_TUNER
-+	select VIDEO_TVEEPROM
- 	select CRC32
- 	---help---
- 	  This is a video4linux driver for Philips SAA713x based
-@@ -23,18 +24,6 @@ config VIDEO_SAA7134_ALSA
- 	  To compile this driver as a module, choose M here: the
- 	  module will be called saa7134-alsa.
- 
--config VIDEO_SAA7134_OSS
--	tristate "Philips SAA7134 DMA audio support (OSS, DEPRECATED)"
--	depends on VIDEO_SAA7134 && SOUND_PRIME && !VIDEO_SAA7134_ALSA
--	---help---
--	  This is a video4linux driver for direct (DMA) audio in
--	  Philips SAA713x based TV cards using OSS
--
--	  This is deprecated in favor of the ALSA module
--
--	  To compile this driver as a module, choose M here: the
--	  module will be called saa7134-oss.
--
- config VIDEO_SAA7134_DVB
- 	tristate "DVB/ATSC Support for saa7134 based TV cards"
- 	depends on VIDEO_SAA7134 && DVB_CORE
-diff --git a/drivers/media/video/saa7134/Makefile b/drivers/media/video/saa7134/Makefile
-index c85c8a8..9aff937 100644
---- a/drivers/media/video/saa7134/Makefile
-+++ b/drivers/media/video/saa7134/Makefile
-@@ -7,7 +7,6 @@ obj-$(CONFIG_VIDEO_SAA7134) +=  saa7134.o saa7134-empress.o \
- 				saa6752hs.o
- 
- obj-$(CONFIG_VIDEO_SAA7134_ALSA) += saa7134-alsa.o
--obj-$(CONFIG_VIDEO_SAA7134_OSS) += saa7134-oss.o
- 
- obj-$(CONFIG_VIDEO_SAA7134_DVB) += saa7134-dvb.o
- 
-diff --git a/drivers/media/video/saa7134/saa7134-alsa.c b/drivers/media/video/saa7134/saa7134-alsa.c
-index 4878f30..ba25310 100644
---- a/drivers/media/video/saa7134/saa7134-alsa.c
-+++ b/drivers/media/video/saa7134/saa7134-alsa.c
-@@ -1077,24 +1077,14 @@ static int saa7134_alsa_init(void)
- 	struct saa7134_dev *dev = NULL;
- 	struct list_head *list;
- 
--	if (!saa7134_dmasound_init && !saa7134_dmasound_exit) {
--		saa7134_dmasound_init = alsa_device_init;
--		saa7134_dmasound_exit = alsa_device_exit;
--	} else {
--		printk(KERN_WARNING "saa7134 ALSA: can't load, DMA sound handler already assigned (probably to OSS)\n");
--		return -EBUSY;
--	}
-+	saa7134_dmasound_init = alsa_device_init;
-+	saa7134_dmasound_exit = alsa_device_exit;
- 
- 	printk(KERN_INFO "saa7134 ALSA driver for DMA sound loaded\n");
- 
- 	list_for_each(list,&saa7134_devlist) {
- 		dev = list_entry(list, struct saa7134_dev, devlist);
--		if (dev->dmasound.priv_data == NULL) {
--			alsa_device_init(dev);
--		} else {
--			printk(KERN_ERR "saa7134 ALSA: DMA sound is being handled by OSS. ignoring %s\n",dev->name);
--			return -EBUSY;
--		}
-+		alsa_device_init(dev);
- 	}
- 
- 	if (dev == NULL)
-diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c
-index 98c1b08..7d7f383 100644
---- a/drivers/media/video/saa7134/saa7134-cards.c
-+++ b/drivers/media/video/saa7134/saa7134-cards.c
-@@ -26,6 +26,7 @@
- #include "saa7134-reg.h"
- #include "saa7134.h"
- #include <media/v4l2-common.h>
-+#include <media/tveeprom.h>
- 
- /* commly used strings */
- static char name_mute[]    = "mute";
-@@ -349,6 +350,10 @@ struct saa7134_board saa7134_boards[] = {
- 			.name = name_radio,
- 			.amux = LINE2,
- 		},
-+	       .mute = {
-+		       .name = name_mute,
-+		       .amux = TV,
-+	       },
- 	},
- 	[SAA7134_BOARD_TVSTATION_RDS] = {
- 		/* Typhoon TV Tuner RDS: Art.Nr. 50694 */
-@@ -565,6 +570,10 @@ struct saa7134_board saa7134_boards[] = {
- 		.radio = {
- 			.name   = name_radio,
- 			.amux   = LINE2,
-+	       },
-+	       .mute = {
-+		       .name = name_mute,
-+		       .amux = TV,
- 		},
- 	},
- 	[SAA7134_BOARD_TYPHOON_90031] = {
-@@ -3553,6 +3562,356 @@ struct saa7134_board saa7134_boards[] = {
- 			.tv     = 1,
- 		}},
- 	},
-+	[SAA7134_BOARD_BEHOLD_401] = {
-+		.name           = "Beholder BeholdTV 401",
-+		.audio_clock    = 0x00187de7,
-+		.tuner_type     = TUNER_PHILIPS_FQ1216ME,
-+		.radio_type     = UNSET,
-+		.tuner_addr	= ADDR_UNSET,
-+		.radio_addr	= ADDR_UNSET,
-+		.inputs         = {{
-+			.name = name_svideo,
-+			.vmux = 8,
-+			.amux = LINE1,
-+		},{
-+			.name = name_comp1,
-+			.vmux = 1,
-+			.amux = LINE1,
-+		},{
-+			.name = name_tv,
-+			.vmux = 3,
-+			.amux = LINE2,
-+			.tv   = 1,
-+		}},
-+		.mute = {
-+			.name = name_mute,
-+			.amux = LINE1,
-+		},
-+	},
-+	[SAA7134_BOARD_BEHOLD_403] = {
-+		.name           = "Beholder BeholdTV 403",
-+		.audio_clock    = 0x00187de7,
-+		.tuner_type     = TUNER_PHILIPS_FQ1216ME,
-+		.radio_type     = UNSET,
-+		.tuner_addr	= ADDR_UNSET,
-+		.radio_addr	= ADDR_UNSET,
-+		.inputs         = {{
-+			.name = name_svideo,
-+			.vmux = 8,
-+			.amux = LINE1,
-+		},{
-+			.name   = name_comp1,
-+			.vmux   = 1,
-+			.amux   = LINE1,
-+		},{
-+			.name = name_tv,
-+			.vmux = 3,
-+			.amux = LINE2,
-+			.tv   = 1,
-+		}},
-+	},
-+	[SAA7134_BOARD_BEHOLD_403FM] = {
-+		.name           = "Beholder BeholdTV 403 FM",
-+		.audio_clock    = 0x00187de7,
-+		.tuner_type     = TUNER_PHILIPS_FQ1216ME,
-+		.radio_type     = UNSET,
-+		.tuner_addr	= ADDR_UNSET,
-+		.radio_addr	= ADDR_UNSET,
-+		.inputs         = {{
-+			.name = name_svideo,
-+			.vmux = 8,
-+			.amux = LINE1,
-+		},{
-+			.name   = name_comp1,
-+			.vmux   = 1,
-+			.amux   = LINE1,
-+		},{
-+			.name = name_tv,
-+			.vmux = 3,
-+			.amux = LINE2,
-+			.tv   = 1,
-+		}},
-+		.radio = {
-+			.name = name_radio,
-+			.amux = LINE2,
-+		},
-+	},
-+	[SAA7134_BOARD_BEHOLD_405] = {
-+		.name           = "Beholder BeholdTV 405",
-+		.audio_clock    = 0x00187de7,
-+		.tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
-+		.radio_type     = UNSET,
-+		.tuner_addr     = ADDR_UNSET,
-+		.radio_addr     = ADDR_UNSET,
-+		.tda9887_conf   = TDA9887_PRESENT,
-+		.inputs         = {{
-+			.name = name_svideo,
-+			.vmux = 8,
-+			.amux = LINE1,
-+		},{
-+			.name = name_comp1,
-+			.vmux = 3,
-+			.amux = LINE1,
-+		},{
-+			.name = name_tv,
-+			.vmux = 3,
-+			.amux = LINE2,
-+			.tv   = 1,
-+		}},
-+	},
-+	[SAA7134_BOARD_BEHOLD_405FM] = {
-+		/* Sergey <skiv at orel.ru> */
-+		.name           = "Beholder BeholdTV 405 FM",
-+		.audio_clock    = 0x00187de7,
-+		.tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
-+		.radio_type     = UNSET,
-+		.tuner_addr     = ADDR_UNSET,
-+		.radio_addr     = ADDR_UNSET,
-+		.tda9887_conf   = TDA9887_PRESENT,
-+		.inputs         = {{
-+			.name = name_svideo,
-+			.vmux = 8,
-+			.amux = LINE1,
-+		},{
-+			.name = name_comp1,
-+			.vmux = 3,
-+			.amux = LINE1,
-+		},{
-+			.name = name_tv,
-+			.vmux = 3,
-+			.amux = LINE2,
-+			.tv   = 1,
-+		}},
-+		.radio = {
-+			.name = name_radio,
-+			.amux = LINE2,
-+		},
-+	},
-+	[SAA7134_BOARD_BEHOLD_407] = {
-+		.name 		= "Beholder BeholdTV 407",
-+		.audio_clock 	= 0x00187de7,
-+		.tuner_type 	= TUNER_PHILIPS_FM1216ME_MK3,
-+		.radio_type 	= UNSET,
-+		.tuner_addr 	= ADDR_UNSET,
-+		.radio_addr 	= ADDR_UNSET,
-+		.tda9887_conf 	= TDA9887_PRESENT,
-+		.gpiomask = 0xc0c000,
-+		.inputs = {{
-+			.name = name_svideo,
-+			.vmux = 8,
-+			.amux = LINE1,
-+			.gpio = 0xc0c000,
-+		},{
-+			.name = name_comp1,
-+			.vmux = 1,
-+			.amux = LINE1,
-+			.gpio = 0xc0c000,
-+		},{
-+			.name = name_tv,
-+			.vmux = 3,
-+			.amux = TV,
-+			.tv = 1,
-+			.gpio = 0xc0c000,
-+		}},
-+	},
-+	[SAA7134_BOARD_BEHOLD_407FM] = {
-+		.name 		= "Beholder BeholdTV 407 FM",
-+		.audio_clock 	= 0x00187de7,
-+		.tuner_type 	= TUNER_PHILIPS_FM1216ME_MK3,
-+		.radio_type 	= UNSET,
-+		.tuner_addr 	= ADDR_UNSET,
-+		.radio_addr 	= ADDR_UNSET,
-+		.tda9887_conf 	= TDA9887_PRESENT,
-+		.gpiomask = 0xc0c000,
-+		.inputs = {{
-+			.name = name_svideo,
-+			.vmux = 8,
-+			.amux = LINE1,
-+			.gpio = 0xc0c000,
-+		},{
-+			.name = name_comp1,
-+			.vmux = 1,
-+			.amux = LINE1,
-+			.gpio = 0xc0c000,
-+		},{
-+			.name = name_tv,
-+			.vmux = 3,
-+			.amux = TV,
-+			.tv = 1,
-+			.gpio = 0xc0c000,
-+		}},
-+		.radio = {
-+			.name = name_radio,
-+			.amux = LINE2,
-+			.gpio = 0xc0c000,
-+		},
-+	},
-+	[SAA7134_BOARD_BEHOLD_409] = {
-+		.name           = "Beholder BeholdTV 409",
-+		.audio_clock    = 0x00187de7,
-+		.tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
-+		.radio_type     = UNSET,
-+		.tuner_addr     = ADDR_UNSET,
-+		.radio_addr     = ADDR_UNSET,
-+		.tda9887_conf   = TDA9887_PRESENT,
-+		.inputs         = {{
-+			.name = name_tv,
-+			.vmux = 3,
-+			.amux = TV,
-+			.tv   = 1,
-+		},{
-+			.name = name_comp1,
-+			.vmux = 1,
-+			.amux = LINE1,
-+		},{
-+			.name = name_svideo,
-+			.vmux = 8,
-+			.amux = LINE1,
-+		}},
-+	},
-+	[SAA7134_BOARD_BEHOLD_505FM] = {
-+		.name           = "Beholder BeholdTV 505 FM/RDS",
-+		.audio_clock    = 0x00200000,
-+		.tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
-+		.radio_type     = UNSET,
-+		.tuner_addr     = ADDR_UNSET,
-+		.radio_addr     = ADDR_UNSET,
-+		.tda9887_conf   = TDA9887_PRESENT,
-+		.inputs         = {{
-+			.name = name_tv,
-+			.vmux = 3,
-+			.amux = LINE2,
-+			.tv   = 1,
-+		},{
-+			.name = name_comp1,
-+			.vmux = 1,
-+			.amux = LINE1,
-+		},{
-+			.name = name_svideo,
-+			.vmux = 8,
-+			.amux = LINE1,
-+		}},
-+		.mute = {
-+			.name = name_mute,
-+			.amux = LINE1,
-+		},
-+		.radio = {
-+			.name = name_radio,
-+			.amux = LINE2,
-+		},
-+	},
-+	[SAA7134_BOARD_BEHOLD_507_9FM] = {
-+		.name           = "Beholder BeholdTV 507 FM/RDS / BeholdTV 509 FM",
-+		.audio_clock    = 0x00187de7,
-+		.tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
-+		.radio_type     = UNSET,
-+		.tuner_addr     = ADDR_UNSET,
-+		.radio_addr     = ADDR_UNSET,
-+		.tda9887_conf   = TDA9887_PRESENT,
-+		.inputs         = {{
-+			.name = name_tv,
-+			.vmux = 3,
-+			.amux = TV,
-+			.tv   = 1,
-+		},{
-+			.name = name_comp1,
-+			.vmux = 1,
-+			.amux = LINE1,
-+		},{
-+			.name = name_svideo,
-+			.vmux = 8,
-+			.amux = LINE1,
-+		}},
-+			.radio = {
-+			.name = name_radio,
-+			.amux = LINE2,
-+		},
-+	},
-+	[SAA7134_BOARD_BEHOLD_COLUMBUS_TVFM] = {
-+		.name           = "Beholder BeholdTV Columbus TVFM",
-+		.audio_clock    = 0x00187de7,
-+		.tuner_type     = TUNER_ALPS_TSBE5_PAL,
-+		.radio_type     = UNSET,
-+		.tuner_addr     = ADDR_UNSET,
-+		.radio_addr     = ADDR_UNSET,
-+		.tda9887_conf   = TDA9887_PRESENT,
-+		.inputs         = {{
-+			.name = name_tv,
-+			.vmux = 3,
-+			.amux = TV,
-+			.tv   = 1,
-+		},{
-+			.name = name_comp1,
-+			.vmux = 1,
-+			.amux = LINE1,
-+		},{
-+			.name = name_svideo,
-+			.vmux = 8,
-+			.amux = LINE1,
-+		}},
-+		.radio = {
-+			.name = name_radio,
-+			.amux = LINE2,
-+		},
-+	},
-+	[SAA7134_BOARD_BEHOLD_607_9FM] = {
-+		/* Andrey Melnikoff <temnota at kmv.ru> */
-+		.name           = "Beholder BeholdTV 607 / BeholdTV 609",
-+		.audio_clock    = 0x00187de7,
-+		.tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
-+		.radio_type     = UNSET,
-+		.tuner_addr     = ADDR_UNSET,
-+		.radio_addr     = ADDR_UNSET,
-+		.tda9887_conf   = TDA9887_PRESENT,
-+		.inputs         = {{
-+			.name = name_tv,
-+			.vmux = 3,
-+			.amux = TV,
-+			.tv   = 1,
-+		},{
-+			.name = name_comp1,
-+			.vmux = 1,
-+			.amux = LINE1,
-+		},{
-+			.name = name_svideo,
-+			.vmux = 8,
-+			.amux = LINE1,
-+		}},
-+		.radio = {
-+			.name = name_radio,
-+			.amux = LINE2,
-+		},
-+	},
-+	[SAA7134_BOARD_BEHOLD_M6] = {
-+		/* Igor Kuznetsov <igk at igk.ru> */
-+		/* Andrey Melnikoff <temnota at kmv.ru> */
-+		.name           = "Beholder BeholdTV M6 / BeholdTV M6 Extra",
-+		.audio_clock    = 0x00187de7,
-+		.tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
-+		.radio_type     = UNSET,
-+		.tuner_addr     = ADDR_UNSET,
-+		.radio_addr     = ADDR_UNSET,
-+		.tda9887_conf   = TDA9887_PRESENT,
-+		.inputs         = {{
-+			.name = name_tv,
-+			.vmux = 3,
-+			.amux = TV,
-+			.tv   = 1,
-+		},{
-+			.name = name_comp1,
-+			.vmux = 1,
-+			.amux = LINE1,
-+		},{
-+			.name = name_svideo,
-+			.vmux = 8,
-+			.amux = LINE1,
-+		}},
-+		.radio = {
-+			.name = name_radio,
-+			.amux = LINE2,
-+		},
-+		.mpeg  = SAA7134_MPEG_EMPRESS,
-+	},
- };
- 
- const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards);
-@@ -4033,7 +4392,13 @@ struct pci_device_id saa7134_pci_tbl[] = {
- 		.vendor       = PCI_VENDOR_ID_PHILIPS,
- 		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
- 		.subvendor    = 0x1462,
--		.subdevice    = 0x6231,
-+		.subdevice    = 0x6231, /* tda8275a, ks003 IR */
-+		.driver_data  = SAA7134_BOARD_MSI_TVATANYWHERE_PLUS,
-+	},{
-+		.vendor       = PCI_VENDOR_ID_PHILIPS,
-+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
-+		.subvendor    = 0x1462,
-+		.subdevice    = 0x8624, /* tda8275, ks003 IR */
- 		.driver_data  = SAA7134_BOARD_MSI_TVATANYWHERE_PLUS,
- 	},{
- 		.vendor       = PCI_VENDOR_ID_PHILIPS,
-@@ -4207,11 +4572,41 @@ struct pci_device_id saa7134_pci_tbl[] = {
- 		.vendor       = PCI_VENDOR_ID_PHILIPS,
- 		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
- 		.subvendor    = 0x0070,
-+		.subdevice    = 0x6700,
-+		.driver_data  = SAA7134_BOARD_HAUPPAUGE_HVR1110,
-+	},{
-+		.vendor       = PCI_VENDOR_ID_PHILIPS,
-+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
-+		.subvendor    = 0x0070,
- 		.subdevice    = 0x6701,
- 		.driver_data  = SAA7134_BOARD_HAUPPAUGE_HVR1110,
- 	},{
- 		.vendor       = PCI_VENDOR_ID_PHILIPS,
- 		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
-+		.subvendor    = 0x0070,
-+		.subdevice    = 0x6702,
-+		.driver_data  = SAA7134_BOARD_HAUPPAUGE_HVR1110,
-+	},{
-+		.vendor       = PCI_VENDOR_ID_PHILIPS,
-+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
-+		.subvendor    = 0x0070,
-+		.subdevice    = 0x6703,
-+		.driver_data  = SAA7134_BOARD_HAUPPAUGE_HVR1110,
-+	},{
-+		.vendor       = PCI_VENDOR_ID_PHILIPS,
-+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
-+		.subvendor    = 0x0070,
-+		.subdevice    = 0x6704,
-+		.driver_data  = SAA7134_BOARD_HAUPPAUGE_HVR1110,
-+	},{
-+		.vendor       = PCI_VENDOR_ID_PHILIPS,
-+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
-+		.subvendor    = 0x0070,
-+		.subdevice    = 0x6705,
-+		.driver_data  = SAA7134_BOARD_HAUPPAUGE_HVR1110,
-+	},{
-+		.vendor       = PCI_VENDOR_ID_PHILIPS,
-+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
- 		.subvendor    = 0x153b,
- 		.subdevice    = 0x1172,
- 		.driver_data  = SAA7134_BOARD_CINERGY_HT_PCMCIA,
-@@ -4289,6 +4684,162 @@ struct pci_device_id saa7134_pci_tbl[] = {
- 		.driver_data  = SAA7134_BOARD_AVERMEDIA_SUPER_007,
- 	},{
- 		.vendor       = PCI_VENDOR_ID_PHILIPS,
-+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
-+		.subvendor    = 0x0000,
-+		.subdevice    = 0x4016,
-+		.driver_data  = SAA7134_BOARD_BEHOLD_401,
-+	},{
-+		.vendor       = PCI_VENDOR_ID_PHILIPS,
-+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
-+		.subvendor    = 0x0000,
-+		.subdevice    = 0x4036,
-+		.driver_data  = SAA7134_BOARD_BEHOLD_403,
-+	},{
-+		.vendor       = PCI_VENDOR_ID_PHILIPS,
-+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
-+		.subvendor    = 0x0000,
-+		.subdevice    = 0x4037,
-+		.driver_data  = SAA7134_BOARD_BEHOLD_403FM,
-+	},{
-+		.vendor       = PCI_VENDOR_ID_PHILIPS,
-+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
-+		.subvendor    = 0x0000,
-+		.subdevice    = 0x4050,
-+		.driver_data  = SAA7134_BOARD_BEHOLD_405,
-+	},{
-+		.vendor       = PCI_VENDOR_ID_PHILIPS,
-+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
-+		.subvendor    = 0x0000,
-+		.subdevice    = 0x4051,
-+		.driver_data  = SAA7134_BOARD_BEHOLD_405FM,
-+	},{
-+		.vendor       = PCI_VENDOR_ID_PHILIPS,
-+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
-+		.subvendor    = 0x0000,
-+		.subdevice    = 0x4070,
-+		.driver_data  = SAA7134_BOARD_BEHOLD_407,
-+	},{
-+		.vendor       = PCI_VENDOR_ID_PHILIPS,
-+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
-+		.subvendor    = 0x0000,
-+		.subdevice    = 0x4071,
-+		.driver_data  = SAA7134_BOARD_BEHOLD_407FM,
-+	},{
-+		.vendor       = PCI_VENDOR_ID_PHILIPS,
-+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
-+		.subvendor    = 0x0000,
-+		.subdevice    = 0x4090,
-+		.driver_data  = SAA7134_BOARD_BEHOLD_409,
-+	},{
-+		.vendor       = PCI_VENDOR_ID_PHILIPS,
-+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
-+		.subvendor    = 0x0000,
-+		.subdevice    = 0x5051,
-+		.driver_data  = SAA7134_BOARD_BEHOLD_505FM,
-+	},{
-+		.vendor       = PCI_VENDOR_ID_PHILIPS,
-+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
-+		.subvendor    = 0x0000,
-+		.subdevice    = 0x505B,
-+		.driver_data  = SAA7134_BOARD_BEHOLD_505FM,
-+	},{
-+		.vendor       = PCI_VENDOR_ID_PHILIPS,
-+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
-+		.subvendor    = 0x5ace,
-+		.subdevice    = 0x5050,
-+		.driver_data  = SAA7134_BOARD_BEHOLD_505FM,
-+	},{
-+		.vendor       = PCI_VENDOR_ID_PHILIPS,
-+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
-+		.subvendor    = 0x0000,
-+		.subdevice    = 0x5071,
-+		.driver_data  = SAA7134_BOARD_BEHOLD_507_9FM,
-+	},{
-+		.vendor       = PCI_VENDOR_ID_PHILIPS,
-+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
-+		.subvendor    = 0x0000,
-+		.subdevice    = 0x507B,
-+		.driver_data  = SAA7134_BOARD_BEHOLD_507_9FM,
-+	},{
-+		.vendor       = PCI_VENDOR_ID_PHILIPS,
-+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
-+		.subvendor    = 0x5ace,
-+		.subdevice    = 0x5070,
-+		.driver_data  = SAA7134_BOARD_BEHOLD_507_9FM,
-+	},{
-+		.vendor       = PCI_VENDOR_ID_PHILIPS,
-+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
-+		.subvendor    = 0x5ace,
-+		.subdevice    = 0x5090,
-+		.driver_data  = SAA7134_BOARD_BEHOLD_507_9FM,
-+	},{
-+		.vendor       = PCI_VENDOR_ID_PHILIPS,
-+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
-+		.subvendor    = 0x0000,
-+		.subdevice    = 0x5201,
-+		.driver_data  = SAA7134_BOARD_BEHOLD_COLUMBUS_TVFM,
-+	},{
-+		.vendor       = PCI_VENDOR_ID_PHILIPS,
-+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
-+		.subvendor    = 0x5ace,
-+		.subdevice    = 0x6070,
-+		.driver_data  = SAA7134_BOARD_BEHOLD_607_9FM,
-+	},{
-+		.vendor       = PCI_VENDOR_ID_PHILIPS,
-+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
-+		.subvendor    = 0x5ace,
-+		.subdevice    = 0x6071,
-+		.driver_data  = SAA7134_BOARD_BEHOLD_607_9FM,
-+	},{
-+		.vendor       = PCI_VENDOR_ID_PHILIPS,
-+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
-+		.subvendor    = 0x5ace,
-+		.subdevice    = 0x6072,
-+		.driver_data  = SAA7134_BOARD_BEHOLD_607_9FM,
-+	},{
-+		.vendor       = PCI_VENDOR_ID_PHILIPS,
-+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
-+		.subvendor    = 0x5ace,
-+		.subdevice    = 0x6073,
-+		.driver_data  = SAA7134_BOARD_BEHOLD_607_9FM,
-+	},{
-+		.vendor       = PCI_VENDOR_ID_PHILIPS,
-+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
-+		.subvendor    = 0x5ace,
-+		.subdevice    = 0x6090,
-+		.driver_data  = SAA7134_BOARD_BEHOLD_607_9FM,
-+	},{
-+		.vendor       = PCI_VENDOR_ID_PHILIPS,
-+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
-+		.subvendor    = 0x5ace,
-+		.subdevice    = 0x6091,
-+		.driver_data  = SAA7134_BOARD_BEHOLD_607_9FM,
-+	},{
-+		.vendor       = PCI_VENDOR_ID_PHILIPS,
-+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
-+		.subvendor    = 0x5ace,
-+		.subdevice    = 0x6092,
-+		.driver_data  = SAA7134_BOARD_BEHOLD_607_9FM,
-+	},{
-+		.vendor       = PCI_VENDOR_ID_PHILIPS,
-+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
-+		.subvendor    = 0x5ace,
-+		.subdevice    = 0x6093,
-+		.driver_data  = SAA7134_BOARD_BEHOLD_607_9FM,
-+	},{
-+		.vendor       = PCI_VENDOR_ID_PHILIPS,
-+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
-+		.subvendor    = 0x5ace,
-+		.subdevice    = 0x6190,
-+		.driver_data  = SAA7134_BOARD_BEHOLD_M6,
-+	},{
-+		.vendor       = PCI_VENDOR_ID_PHILIPS,
-+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
-+		.subvendor    = 0x5ace,
-+		.subdevice    = 0x6193,
-+		.driver_data  = SAA7134_BOARD_BEHOLD_M6,
-+	},{
-+		.vendor       = PCI_VENDOR_ID_PHILIPS,
- 		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
- 		.subvendor    = 0x4e42,
- 		.subdevice    = 0x3502,
-@@ -4351,6 +4902,34 @@ static void board_flyvideo(struct saa7134_dev *dev)
- 
- /* ----------------------------------------------------------- */
- 
-+static void hauppauge_eeprom(struct saa7134_dev *dev, u8 *eeprom_data)
++		dev->isobufs = kzalloc(MAX_ISO_BUFS * sizeof(*dev->isobufs),
++					GFP_KERNEL);
++	if (dev->isobufs == NULL) {
++		STK_ERROR("Unable to allocate iso buffers\n");
++		return -ENOMEM;
++	}
++	for (i = 0; i < MAX_ISO_BUFS; i++) {
++		if (dev->isobufs[i].data == NULL) {
++			kbuf = kzalloc(ISO_BUFFER_SIZE, GFP_KERNEL);
++			if (kbuf == NULL) {
++				STK_ERROR("Failed to allocate iso buffer %d\n",
++					i);
++				goto isobufs_out;
++			}
++			dev->isobufs[i].data = kbuf;
++		} else
++			STK_ERROR("isobuf data already allocated\n");
++		if (dev->isobufs[i].urb == NULL) {
++			urb = usb_alloc_urb(ISO_FRAMES_PER_DESC, GFP_KERNEL);
++			if (urb == NULL) {
++				STK_ERROR("Failed to allocate URB %d\n", i);
++				goto isobufs_out;
++			}
++			dev->isobufs[i].urb = urb;
++		} else {
++			STK_ERROR("Killing URB\n");
++			usb_kill_urb(dev->isobufs[i].urb);
++			urb = dev->isobufs[i].urb;
++		}
++		urb->interval = 1;
++		urb->dev = udev;
++		urb->pipe = usb_rcvisocpipe(udev, dev->isoc_ep);
++		urb->transfer_flags = URB_ISO_ASAP;
++		urb->transfer_buffer = dev->isobufs[i].data;
++		urb->transfer_buffer_length = ISO_BUFFER_SIZE;
++		urb->complete = stk_isoc_handler;
++		urb->context = dev;
++		urb->start_frame = 0;
++		urb->number_of_packets = ISO_FRAMES_PER_DESC;
++
++		for (j = 0; j < ISO_FRAMES_PER_DESC; j++) {
++			urb->iso_frame_desc[j].offset = j * ISO_MAX_FRAME_SIZE;
++			urb->iso_frame_desc[j].length = ISO_MAX_FRAME_SIZE;
++		}
++	}
++	set_memallocd(dev);
++	return 0;
++
++isobufs_out:
++	for (i = 0; i < MAX_ISO_BUFS && dev->isobufs[i].data; i++)
++		kfree(dev->isobufs[i].data);
++	for (i = 0; i < MAX_ISO_BUFS && dev->isobufs[i].urb; i++)
++		usb_free_urb(dev->isobufs[i].urb);
++	kfree(dev->isobufs);
++	dev->isobufs = NULL;
++	return -ENOMEM;
++}
++
++static void stk_clean_iso(struct stk_camera *dev)
++{
++	int i;
++
++	if (dev == NULL || dev->isobufs == NULL)
++		return;
++
++	for (i = 0; i < MAX_ISO_BUFS; i++) {
++		struct urb *urb;
++
++		urb = dev->isobufs[i].urb;
++		if (urb) {
++			if (atomic_read(&dev->urbs_used))
++				usb_kill_urb(urb);
++			usb_free_urb(urb);
++		}
++		kfree(dev->isobufs[i].data);
++	}
++	kfree(dev->isobufs);
++	dev->isobufs = NULL;
++	unset_memallocd(dev);
++}
++
++static int stk_setup_siobuf(struct stk_camera *dev, int index)
++{
++	struct stk_sio_buffer *buf = dev->sio_bufs + index;
++	INIT_LIST_HEAD(&buf->list);
++	buf->v4lbuf.length = PAGE_ALIGN(dev->frame_size);
++	buf->buffer = vmalloc_user(buf->v4lbuf.length);
++	if (buf->buffer == NULL)
++		return -ENOMEM;
++	buf->mapcount = 0;
++	buf->dev = dev;
++	buf->v4lbuf.index = index;
++	buf->v4lbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
++	buf->v4lbuf.field = V4L2_FIELD_NONE;
++	buf->v4lbuf.memory = V4L2_MEMORY_MMAP;
++	buf->v4lbuf.m.offset = 2*index*buf->v4lbuf.length;
++	return 0;
++}
++
++static int stk_free_sio_buffers(struct stk_camera *dev)
++{
++	int i;
++	int nbufs;
++	unsigned long flags;
++	if (dev->n_sbufs == 0 || dev->sio_bufs == NULL)
++		return 0;
++	/*
++	* If any buffers are mapped, we cannot free them at all.
++	*/
++	for (i = 0; i < dev->n_sbufs; i++) {
++		if (dev->sio_bufs[i].mapcount > 0)
++			return -EBUSY;
++	}
++	/*
++	* OK, let's do it.
++	*/
++	spin_lock_irqsave(&dev->spinlock, flags);
++	INIT_LIST_HEAD(&dev->sio_avail);
++	INIT_LIST_HEAD(&dev->sio_full);
++	nbufs = dev->n_sbufs;
++	dev->n_sbufs = 0;
++	spin_unlock_irqrestore(&dev->spinlock, flags);
++	for (i = 0; i < nbufs; i++) {
++		if (dev->sio_bufs[i].buffer != NULL)
++			vfree(dev->sio_bufs[i].buffer);
++	}
++	kfree(dev->sio_bufs);
++	dev->sio_bufs = NULL;
++	return 0;
++}
++
++static int stk_prepare_sio_buffers(struct stk_camera *dev, unsigned n_sbufs)
++{
++	int i;
++	if (dev->sio_bufs != NULL)
++		STK_ERROR("sio_bufs already allocated\n");
++	else {
++		dev->sio_bufs = kzalloc(n_sbufs * sizeof(struct stk_sio_buffer),
++				GFP_KERNEL);
++		if (dev->sio_bufs == NULL)
++			return -ENOMEM;
++		for (i = 0; i < n_sbufs; i++) {
++			if (stk_setup_siobuf(dev, i))
++				return (dev->n_sbufs > 1)? 0 : -ENOMEM;
++			dev->n_sbufs = i+1;
++		}
++	}
++	return 0;
++}
++
++static int stk_allocate_buffers(struct stk_camera *dev, unsigned n_sbufs)
++{
++	int err;
++	err = stk_prepare_iso(dev);
++	if (err) {
++		stk_clean_iso(dev);
++		return err;
++	}
++	err = stk_prepare_sio_buffers(dev, n_sbufs);
++	if (err) {
++		stk_free_sio_buffers(dev);
++		return err;
++	}
++	return 0;
++}
++
++static void stk_free_buffers(struct stk_camera *dev)
++{
++	stk_clean_iso(dev);
++	stk_free_sio_buffers(dev);
++}
++/* -------------------------------------------- */
++
++/* v4l file operations */
++
++static int v4l_stk_open(struct inode *inode, struct file *fp)
++{
++	struct stk_camera *dev;
++	struct video_device *vdev;
++
++	vdev = video_devdata(fp);
++	dev = vdev_to_camera(vdev);
++
++	if (dev == NULL || !is_present(dev))
++		return -ENXIO;
++	fp->private_data = vdev;
++	kref_get(&dev->kref);
++
++	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;
++	}
++
++	if (dev->owner != fp) {
++		kref_put(&dev->kref, stk_camera_cleanup);
++		return 0;
++	}
++
++	stk_stop_stream(dev);
++
++	stk_free_buffers(dev);
++
++	dev->owner = NULL;
++
++	kref_put(&dev->kref, stk_camera_cleanup);
++
++	return 0;
++}
++
++static ssize_t v4l_stk_read(struct file *fp, char __user *buf,
++		size_t count, loff_t *f_pos)
 +{
-+	struct tveeprom tv;
++	int i;
++	int ret;
++	unsigned long flags;
++	struct stk_camera *dev;
++	struct video_device *vdev;
++	struct stk_sio_buffer *sbuf;
 +
-+	tveeprom_hauppauge_analog(&dev->i2c_client, &tv, eeprom_data);
++	vdev = video_devdata(fp);
++	if (vdev == NULL)
++		return -EFAULT;
++	dev = vdev_to_camera(vdev);
 +
-+	/* Make sure we support the board model */
-+	switch (tv.model) {
-+	case 67019: /* WinTV-HVR1110 (Retail, IR Blaster, hybrid, FM, SVid/Comp, 3.5mm audio in) */
-+	case 67109: /* WinTV-HVR1000 (Retail, IR Receive, analog, no FM, SVid/Comp, 3.5mm audio in) */
-+	case 67559: /* WinTV-HVR1110 (OEM, no IR, hybrid, FM, SVid/Comp, RCA aud) */
-+	case 67569: /* WinTV-HVR1110 (OEM, no IR, hybrid, FM) */
-+	case 67579: /* WinTV-HVR1110 (OEM, no IR, hybrid, no FM) */
-+	case 67589: /* WinTV-HVR1110 (OEM, no IR, hybrid, no FM, SVid/Comp, RCA aud) */
-+	case 67599: /* WinTV-HVR1110 (OEM, no IR, hybrid, no FM, SVid/Comp, RCA aud) */
-+		break;
-+	default:
-+		printk(KERN_WARNING "%s: warning: "
-+		       "unknown hauppauge model #%d\n", dev->name, tv.model);
-+		break;
++	if (dev == NULL)
++		return -EIO;
++
++	if (!is_present(dev))
++		return -EIO;
++	if (dev->owner && dev->owner != fp)
++		return -EBUSY;
++	dev->owner = fp;
++	if (!is_streaming(dev)) {
++		if (stk_initialise(dev)
++			|| stk_allocate_buffers(dev, 3)
++			|| stk_start_stream(dev))
++			return -ENOMEM;
++		spin_lock_irqsave(&dev->spinlock, flags);
++		for (i = 0; i < dev->n_sbufs; i++) {
++			list_add_tail(&dev->sio_bufs[i].list, &dev->sio_avail);
++			dev->sio_bufs[i].v4lbuf.flags = V4L2_BUF_FLAG_QUEUED;
++		}
++		spin_unlock_irqrestore(&dev->spinlock, flags);
++	}
++	if (*f_pos == 0) {
++		if (fp->f_flags & O_NONBLOCK && list_empty(&dev->sio_full))
++			return -EWOULDBLOCK;
++		ret = wait_event_interruptible(dev->wait_frame,
++			!list_empty(&dev->sio_full) || !is_present(dev));
++		if (ret)
++			return ret;
++		if (!is_present(dev))
++			return -EIO;
++	}
++	if (count + *f_pos > dev->frame_size)
++		count = dev->frame_size - *f_pos;
++	spin_lock_irqsave(&dev->spinlock, flags);
++	if (list_empty(&dev->sio_full)) {
++		spin_unlock_irqrestore(&dev->spinlock, flags);
++		STK_ERROR("BUG: No siobufs ready\n");
++		return 0;
 +	}
++	sbuf = list_first_entry(&dev->sio_full, struct stk_sio_buffer, list);
++	spin_unlock_irqrestore(&dev->spinlock, flags);
 +
-+	printk(KERN_INFO "%s: hauppauge eeprom: model=%d\n",
-+	       dev->name, tv.model);
++	if (copy_to_user(buf, sbuf->buffer + *f_pos, count))
++		return -EFAULT;
++
++	*f_pos += count;
++
++	if (*f_pos >= dev->frame_size) {
++		*f_pos = 0;
++		spin_lock_irqsave(&dev->spinlock, flags);
++		list_move_tail(&sbuf->list, &dev->sio_avail);
++		spin_unlock_irqrestore(&dev->spinlock, flags);
++	}
++	return count;
 +}
 +
-+/* ----------------------------------------------------------- */
++static unsigned int v4l_stk_poll(struct file *fp, poll_table *wait)
++{
++	struct stk_camera *dev;
++	struct video_device *vdev;
 +
- int saa7134_board_init1(struct saa7134_dev *dev)
- {
- 	/* Always print gpio, often manufacturers encode tuner type and other info. */
-@@ -4406,6 +4985,16 @@ int saa7134_board_init1(struct saa7134_dev *dev)
- 	case SAA7134_BOARD_ENCORE_ENLTV:
- 	case SAA7134_BOARD_ENCORE_ENLTV_FM:
- 	case SAA7134_BOARD_10MOONSTVMASTER3:
-+	case SAA7134_BOARD_BEHOLD_401:
-+	case SAA7134_BOARD_BEHOLD_403:
-+	case SAA7134_BOARD_BEHOLD_403FM:
-+	case SAA7134_BOARD_BEHOLD_405:
-+	case SAA7134_BOARD_BEHOLD_405FM:
-+	case SAA7134_BOARD_BEHOLD_407:
-+	case SAA7134_BOARD_BEHOLD_407FM:
-+	case SAA7134_BOARD_BEHOLD_409:
-+	case SAA7134_BOARD_BEHOLD_505FM:
-+	case SAA7134_BOARD_BEHOLD_507_9FM:
- 		dev->has_remote = SAA7134_REMOTE_GPIO;
- 		break;
- 	case SAA7134_BOARD_FLYDVBS_LR300:
-@@ -4445,6 +5034,7 @@ int saa7134_board_init1(struct saa7134_dev *dev)
- 		saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x08000000, 0x00000000);
- 		break;
- 	case SAA7134_BOARD_AVERMEDIA_CARDBUS:
-+	case SAA7134_BOARD_BEHOLD_COLUMBUS_TVFM:
- 		/* power-up tuner chip */
- 		saa_andorl(SAA7134_GPIO_GPMODE0 >> 2,   0xffffffff, 0xffffffff);
- 		saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0xffffffff, 0xffffffff);
-@@ -4466,6 +5056,8 @@ int saa7134_board_init1(struct saa7134_dev *dev)
- 	case SAA7134_BOARD_PINNACLE_PCTV_310i:
- 	case SAA7134_BOARD_UPMOST_PURPLE_TV:
- 	case SAA7134_BOARD_HAUPPAUGE_HVR1110:
-+	case SAA7134_BOARD_BEHOLD_607_9FM:
-+	case SAA7134_BOARD_BEHOLD_M6:
- 		dev->has_remote = SAA7134_REMOTE_I2C;
- 		break;
- 	case SAA7134_BOARD_AVERMEDIA_A169_B:
-@@ -4477,6 +5069,7 @@ int saa7134_board_init1(struct saa7134_dev *dev)
- 		break;
- 	case SAA7134_BOARD_AVERMEDIA_M102:
- 		/* enable tuner */
-+	       dev->has_remote = SAA7134_REMOTE_GPIO;
- 		saa_andorl(SAA7134_GPIO_GPMODE0 >> 2,   0x8c040007, 0x8c040007);
- 		saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x0c0007cd, 0x0c0007cd);
- 		break;
-@@ -4570,8 +5163,17 @@ int saa7134_board_init2(struct saa7134_dev *dev)
- 
- 		printk(KERN_INFO "%s Tuner type is %d\n", dev->name, dev->tuner_type);
- 		if (dev->tuner_type == TUNER_PHILIPS_FMD1216ME_MK3) {
--			dev->tda9887_conf = TDA9887_PRESENT | TDA9887_PORT1_ACTIVE | TDA9887_PORT2_ACTIVE;
--			saa7134_i2c_call_clients(dev,TDA9887_SET_CONFIG, &dev->tda9887_conf);
-+			struct v4l2_priv_tun_config tda9887_cfg;
++	vdev = video_devdata(fp);
 +
-+			tda9887_cfg.tuner = TUNER_TDA9887;
-+			tda9887_cfg.priv  = &dev->tda9887_conf;
++	if (vdev == NULL)
++		return -EFAULT;
 +
-+			dev->tda9887_conf = TDA9887_PRESENT      |
-+					    TDA9887_PORT1_ACTIVE |
-+					    TDA9887_PORT2_ACTIVE;
++	dev = vdev_to_camera(vdev);
++	if (dev == NULL)
++		return -ENODEV;
 +
-+			saa7134_i2c_call_clients(dev, TUNER_SET_CONFIG,
-+						 &tda9887_cfg);
- 		}
- 
- 		tun_setup.mode_mask = T_RADIO | T_ANALOG_TV | T_DIGITAL_TV;
-@@ -4601,7 +5203,6 @@ int saa7134_board_init2(struct saa7134_dev *dev)
- 		break;
- 	case SAA7134_BOARD_PHILIPS_TIGER:
- 	case SAA7134_BOARD_PHILIPS_TIGER_S:
--	case SAA7134_BOARD_AVERMEDIA_SUPER_007:
- 		{
- 		u8 data[] = { 0x3c, 0x33, 0x60};
- 		struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)};
-@@ -4622,13 +5223,16 @@ int saa7134_board_init2(struct saa7134_dev *dev)
- 		i2c_transfer(&dev->i2c_adap, &msg, 1);
- 		}
- 		break;
-+	case SAA7134_BOARD_HAUPPAUGE_HVR1110:
-+		hauppauge_eeprom(dev, dev->eedata+0x80);
-+		/* break intentionally omitted */
- 	case SAA7134_BOARD_PINNACLE_PCTV_310i:
- 	case SAA7134_BOARD_KWORLD_DVBT_210:
- 	case SAA7134_BOARD_TEVION_DVBT_220RF:
- 	case SAA7134_BOARD_ASUSTeK_P7131_DUAL:
- 	case SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA:
- 	case SAA7134_BOARD_MEDION_MD8800_QUADRO:
--	case SAA7134_BOARD_HAUPPAUGE_HVR1110:
-+       case SAA7134_BOARD_AVERMEDIA_SUPER_007:
- 		/* this is a hybrid board, initialize to analog mode
- 		 * and configure firmware eeprom address
- 		 */
-diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c
-index 4f0a915..52baa4f 100644
---- a/drivers/media/video/saa7134/saa7134-core.c
-+++ b/drivers/media/video/saa7134/saa7134-core.c
-@@ -294,7 +294,7 @@ void saa7134_dma_free(struct videobuf_queue *q,struct saa7134_buf *buf)
- 	videobuf_waiton(&buf->vb,0,0);
- 	videobuf_dma_unmap(q, dma);
- 	videobuf_dma_free(dma);
--	buf->vb.state = STATE_NEEDS_INIT;
-+	buf->vb.state = VIDEOBUF_NEEDS_INIT;
- }
- 
- /* ------------------------------------------------------------------ */
-@@ -313,7 +313,7 @@ int saa7134_buffer_queue(struct saa7134_dev *dev,
- 			buf->activate(dev,buf,NULL);
- 		} else if (list_empty(&q->queue)) {
- 			list_add_tail(&buf->vb.queue,&q->queue);
--			buf->vb.state = STATE_QUEUED;
-+			buf->vb.state = VIDEOBUF_QUEUED;
- 		} else {
- 			next = list_entry(q->queue.next,struct saa7134_buf,
- 					  vb.queue);
-@@ -322,7 +322,7 @@ int saa7134_buffer_queue(struct saa7134_dev *dev,
- 		}
- 	} else {
- 		list_add_tail(&buf->vb.queue,&q->queue);
--		buf->vb.state = STATE_QUEUED;
-+		buf->vb.state = VIDEOBUF_QUEUED;
- 	}
- 	return 0;
- }
-@@ -387,7 +387,7 @@ void saa7134_buffer_timeout(unsigned long data)
- 	   try to start over with the next one. */
- 	if (q->curr) {
- 		dprintk("timeout on %p\n",q->curr);
--		saa7134_buffer_finish(dev,q,STATE_ERROR);
-+		saa7134_buffer_finish(dev,q,VIDEOBUF_ERROR);
- 	}
- 	saa7134_buffer_next(dev,q);
- 	spin_unlock_irqrestore(&dev->slock,flags);
-@@ -395,8 +395,8 @@ void saa7134_buffer_timeout(unsigned long data)
- 
- /* resends a current buffer in queue after resume */
- 
--int saa7134_buffer_requeue(struct saa7134_dev *dev,
--			 struct saa7134_dmaqueue *q)
-+static int saa7134_buffer_requeue(struct saa7134_dev *dev,
-+				  struct saa7134_dmaqueue *q)
- {
- 	struct saa7134_buf *buf, *next;
- 
-@@ -834,6 +834,7 @@ static struct video_device *vdev_init(struct saa7134_dev *dev,
- 	vfd->minor   = -1;
- 	vfd->dev     = &dev->pci->dev;
- 	vfd->release = video_device_release;
-+	vfd->debug   = video_debug;
- 	snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)",
- 		 dev->name, type, saa7134_boards[dev->board].name);
- 	return vfd;
-@@ -1052,7 +1053,9 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
- 	printk(KERN_INFO "%s: registered device video%d [v4l2]\n",
- 	       dev->name,dev->video_dev->minor & 0x1f);
- 
--	dev->vbi_dev = vdev_init(dev,&saa7134_vbi_template,"vbi");
-+	dev->vbi_dev = vdev_init(dev, &saa7134_video_template, "vbi");
-+	dev->vbi_dev->type = VID_TYPE_TUNER | VID_TYPE_TELETEXT;
++	poll_wait(fp, &dev->wait_frame, wait);
 +
- 	err = video_register_device(dev->vbi_dev,VFL_TYPE_VBI,
- 				    vbi_nr[dev->nr]);
- 	if (err < 0)
-@@ -1181,8 +1184,13 @@ static int saa7134_suspend(struct pci_dev *pci_dev , pm_message_t state)
- 	saa_writel(SAA7134_IRQ2, 0);
- 	saa_writel(SAA7134_MAIN_CTRL, 0);
- 
--	synchronize_irq(pci_dev->irq);
- 	dev->insuspend = 1;
-+	synchronize_irq(pci_dev->irq);
++	if (!is_present(dev))
++		return POLLERR;
 +
-+	/* ACK interrupts once more, just in case,
-+		since the IRQ handler won't ack them anymore*/
++	if (!list_empty(&dev->sio_full))
++		return (POLLIN | POLLRDNORM);
 +
-+	saa_writel(SAA7134_IRQ_REPORT, saa_readl(SAA7134_IRQ_REPORT));
- 
- 	/* Disable timeout timers - if we have active buffers, we will
- 	   fill them on resume*/
-@@ -1194,10 +1202,10 @@ static int saa7134_suspend(struct pci_dev *pci_dev , pm_message_t state)
- 	if (dev->remote)
- 		saa7134_ir_stop(dev);
- 
--	pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state));
- 	pci_save_state(pci_dev);
-+	pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state));
- 
--    return 0;
 +	return 0;
- }
- 
- static int saa7134_resume(struct pci_dev *pci_dev)
-@@ -1205,8 +1213,8 @@ static int saa7134_resume(struct pci_dev *pci_dev)
- 	struct saa7134_dev *dev = pci_get_drvdata(pci_dev);
- 	unsigned long flags;
- 
--	pci_restore_state(pci_dev);
- 	pci_set_power_state(pci_dev, PCI_D0);
-+	pci_restore_state(pci_dev);
- 
- 	/* Do things that are done in saa7134_initdev ,
- 		except of initializing memory structures.*/
-@@ -1222,6 +1230,7 @@ static int saa7134_resume(struct pci_dev *pci_dev)
- 		saa7134_ir_start(dev, dev->remote);
- 	saa7134_hw_enable1(dev);
- 
-+	msleep(100);
- 
- 	saa7134_board_init2(dev);
- 
-@@ -1229,10 +1238,13 @@ static int saa7134_resume(struct pci_dev *pci_dev)
- 	saa7134_set_tvnorm_hw(dev);
- 	saa7134_tvaudio_setmute(dev);
- 	saa7134_tvaudio_setvolume(dev, dev->ctl_volume);
-+	saa7134_tvaudio_init(dev);
- 	saa7134_tvaudio_do_scan(dev);
- 	saa7134_enable_i2s(dev);
- 	saa7134_hw_enable2(dev);
- 
-+	saa7134_irq_video_signalchange(dev);
++}
 +
- 	/*resume unfinished buffer(s)*/
- 	spin_lock_irqsave(&dev->slock, flags);
- 	saa7134_buffer_requeue(dev, &dev->video_q);
-@@ -1246,6 +1258,7 @@ static int saa7134_resume(struct pci_dev *pci_dev)
- 
- 	/* start DMA now*/
- 	dev->insuspend = 0;
-+	smp_wmb();
- 	saa7134_set_dmabits(dev);
- 	spin_unlock_irqrestore(&dev->slock, flags);
- 
-diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c
-index e1ab099..a9ca573 100644
---- a/drivers/media/video/saa7134/saa7134-dvb.c
-+++ b/drivers/media/video/saa7134/saa7134-dvb.c
-@@ -1073,14 +1073,21 @@ static int dvb_init(struct saa7134_dev *dev)
- 
- static int dvb_fini(struct saa7134_dev *dev)
- {
--	static int on  = TDA9887_PRESENT | TDA9887_PORT2_INACTIVE;
-+	/* FIXME: I suspect that this code is bogus, since the entry for
-+	   Pinnacle 300I DVB-T PAL already defines the proper init to allow
-+	   the detection of mt2032 (TDA9887_PORT2_INACTIVE)
-+	 */
-+	if (dev->board == SAA7134_BOARD_PINNACLE_300I_DVBT_PAL) {
-+		struct v4l2_priv_tun_config tda9887_cfg;
-+		static int on  = TDA9887_PRESENT | TDA9887_PORT2_INACTIVE;
 +
-+		tda9887_cfg.tuner = TUNER_TDA9887;
-+		tda9887_cfg.priv  = &on;
- 
--	switch (dev->board) {
--	case SAA7134_BOARD_PINNACLE_300I_DVBT_PAL:
- 		/* otherwise we don't detect the tuner on next insmod */
--		saa7134_i2c_call_clients(dev,TDA9887_SET_CONFIG,&on);
--		break;
--	};
-+		saa7134_i2c_call_clients(dev, TUNER_SET_CONFIG, &tda9887_cfg);
++static void stk_v4l_vm_open(struct vm_area_struct *vma)
++{
++	struct stk_sio_buffer *sbuf = vma->vm_private_data;
++	sbuf->mapcount++;
++}
++static void stk_v4l_vm_close(struct vm_area_struct *vma)
++{
++	struct stk_sio_buffer *sbuf = vma->vm_private_data;
++	sbuf->mapcount--;
++	if (sbuf->mapcount == 0)
++		sbuf->v4lbuf.flags &= ~V4L2_BUF_FLAG_MAPPED;
++}
++static struct vm_operations_struct stk_v4l_vm_ops = {
++	.open = stk_v4l_vm_open,
++	.close = stk_v4l_vm_close
++};
++
++static int v4l_stk_mmap(struct file *fp, struct vm_area_struct *vma)
++{
++	unsigned int i;
++	int ret;
++	unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
++	struct stk_camera *dev;
++	struct video_device *vdev;
++	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;
++			break;
++		}
 +	}
++	if (sbuf == NULL)
++		return -EINVAL;
++	ret = remap_vmalloc_range(vma, sbuf->buffer, 0);
++	if (ret)
++		return ret;
++	vma->vm_flags |= VM_DONTEXPAND;
++	vma->vm_private_data = sbuf;
++	vma->vm_ops = &stk_v4l_vm_ops;
++	sbuf->v4lbuf.flags |= V4L2_BUF_FLAG_MAPPED;
++	stk_v4l_vm_open(vma);
++	return 0;
++}
 +
- 	videobuf_dvb_unregister(&dev->dvb);
- 	return 0;
- }
-diff --git a/drivers/media/video/saa7134/saa7134-empress.c b/drivers/media/video/saa7134/saa7134-empress.c
-index 9322f44..b1b01fa 100644
---- a/drivers/media/video/saa7134/saa7134-empress.c
-+++ b/drivers/media/video/saa7134/saa7134-empress.c
-@@ -161,152 +161,176 @@ ts_mmap(struct file *file, struct vm_area_struct * vma)
-  * video_generic_ioctl (and maybe others).  userspace
-  * copying is done already, arg is a kernel pointer.
-  */
--static int ts_do_ioctl(struct inode *inode, struct file *file,
--		       unsigned int cmd, void *arg)
++/* v4l ioctl handlers */
 +
-+static int empress_querycap(struct file *file, void  *priv,
-+					struct v4l2_capability *cap)
- {
--	struct saa7134_dev *dev = file->private_data;
--	struct v4l2_ext_controls *ctrls = arg;
--
--	if (debug > 1)
--		v4l_print_ioctl(dev->name,cmd);
--	switch (cmd) {
--	case VIDIOC_QUERYCAP:
--	{
--		struct v4l2_capability *cap = arg;
--
--		memset(cap,0,sizeof(*cap));
--		strcpy(cap->driver, "saa7134");
--		strlcpy(cap->card, saa7134_boards[dev->board].name,
--			sizeof(cap->card));
--		sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci));
--		cap->version = SAA7134_VERSION_CODE;
--		cap->capabilities =
--			V4L2_CAP_VIDEO_CAPTURE |
--			V4L2_CAP_READWRITE |
--			V4L2_CAP_STREAMING;
--		return 0;
--	}
-+	struct saa7134_fh *fh = priv;
-+	struct saa7134_dev *dev = fh->dev;
++static int stk_vidioc_querycap(struct file *filp,
++		void *priv, struct v4l2_capability *cap)
++{
++	strcpy(cap->driver, "stk");
++	strcpy(cap->card, "stk");
++	cap->version = DRIVER_VERSION_NUM;
 +
-+	strcpy(cap->driver, "saa7134");
-+	strlcpy(cap->card, saa7134_boards[dev->board].name,
-+		sizeof(cap->card));
-+	sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci));
-+	cap->version = SAA7134_VERSION_CODE;
-+	cap->capabilities =
-+		V4L2_CAP_VIDEO_CAPTURE |
-+		V4L2_CAP_READWRITE |
-+		V4L2_CAP_STREAMING;
++	cap->capabilities = V4L2_CAP_VIDEO_CAPTURE
++		| V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
 +	return 0;
 +}
- 
--	/* --- input switching --------------------------------------- */
--	case VIDIOC_ENUMINPUT:
--	{
--		struct v4l2_input *i = arg;
-+static int empress_enum_input(struct file *file, void *priv,
-+					struct v4l2_input *i)
++
++static int stk_vidioc_enum_input(struct file *filp,
++		void *priv, struct v4l2_input *input)
 +{
-+	if (i->index != 0)
++	if (input->index != 0)
 +		return -EINVAL;
- 
--		if (i->index != 0)
--			return -EINVAL;
--		i->type = V4L2_INPUT_TYPE_CAMERA;
--		strcpy(i->name,"CCIR656");
--		return 0;
--	}
--	case VIDIOC_G_INPUT:
--	{
--		int *i = arg;
--		*i = 0;
--		return 0;
--	}
--	case VIDIOC_S_INPUT:
--	{
--		int *i = arg;
-+	i->type = V4L2_INPUT_TYPE_CAMERA;
-+	strcpy(i->name, "CCIR656");
- 
--		if (*i != 0)
--			return -EINVAL;
--		return 0;
--	}
--	/* --- capture ioctls ---------------------------------------- */
--
--	case VIDIOC_ENUM_FMT:
--	{
--		struct v4l2_fmtdesc *f = arg;
--		int index;
--
--		index = f->index;
--		if (index != 0)
--			return -EINVAL;
--
--		memset(f,0,sizeof(*f));
--		f->index = index;
--		strlcpy(f->description, "MPEG TS", sizeof(f->description));
--		f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
--		f->pixelformat = V4L2_PIX_FMT_MPEG;
--		return 0;
--	}
++
++	strcpy(input->name, "Syntek USB Camera");
++	input->type = V4L2_INPUT_TYPE_CAMERA;
 +	return 0;
 +}
- 
--	case VIDIOC_G_FMT:
--	{
--		struct v4l2_format *f = arg;
-+static int empress_g_input(struct file *file, void *priv, unsigned int *i)
++
++
++static int stk_vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
 +{
 +	*i = 0;
 +	return 0;
 +}
- 
--		memset(f,0,sizeof(*f));
--		f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-+static int empress_s_input(struct file *file, void *priv, unsigned int i)
++
++static int stk_vidioc_s_input(struct file *filp, void *priv, unsigned int i)
 +{
 +	if (i != 0)
 +		return -EINVAL;
- 
--		saa7134_i2c_call_clients(dev, cmd, arg);
--		f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
--		f->fmt.pix.sizeimage    = TS_PACKET_SIZE * dev->ts.nr_packets;
--		return 0;
--	}
++	else
++		return 0;
++}
++
++/* from vivi.c */
++static int stk_vidioc_s_std(struct file *filp, void *priv, v4l2_std_id *a)
++{
 +	return 0;
 +}
- 
--	case VIDIOC_S_FMT:
--	{
--		struct v4l2_format *f = arg;
-+static int empress_enum_fmt_cap(struct file *file, void  *priv,
-+					struct v4l2_fmtdesc *f)
++
++/* List of all V4Lv2 controls supported by the driver */
++static struct v4l2_queryctrl stk_controls[] = {
++	{
++		.id      = V4L2_CID_BRIGHTNESS,
++		.type    = V4L2_CTRL_TYPE_INTEGER,
++		.name    = "Brightness",
++		.minimum = 0,
++		.maximum = 0xffff,
++		.step    = 0x0100,
++		.default_value = 0x6000,
++	},
++	/*TODO: get more controls to work */
++};
++
++static int stk_vidioc_queryctrl(struct file *filp,
++		void *priv, struct v4l2_queryctrl *c)
 +{
-+	if (f->index != 0)
++	int i;
++	int nbr;
++	nbr = ARRAY_SIZE(stk_controls);
++
++	for (i = 0; i < nbr; i++) {
++		if (stk_controls[i].id == c->id) {
++			memcpy(c, &stk_controls[i],
++				sizeof(struct v4l2_queryctrl));
++			return 0;
++		}
++	}
++	return -EINVAL;
++}
++
++static int stk_vidioc_g_ctrl(struct file *filp,
++		void *priv, struct v4l2_control *c)
++{
++	struct stk_camera *dev = priv;
++	switch (c->id) {
++	case V4L2_CID_BRIGHTNESS:
++		c->value = dev->vsettings.brightness;
++		break;
++	default:
 +		return -EINVAL;
- 
--		if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
--		    return -EINVAL;
-+	strlcpy(f->description, "MPEG TS", sizeof(f->description));
-+	f->pixelformat = V4L2_PIX_FMT_MPEG;
- 
--		saa7134_i2c_call_clients(dev, cmd, arg);
--		f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
--		f->fmt.pix.sizeimage    = TS_PACKET_SIZE* dev->ts.nr_packets;
--		return 0;
--	}
++	}
 +	return 0;
 +}
- 
--	case VIDIOC_REQBUFS:
--		return videobuf_reqbufs(&dev->empress_tsq,arg);
-+static int empress_g_fmt_cap(struct file *file, void *priv,
-+				struct v4l2_format *f)
++
++static int stk_vidioc_s_ctrl(struct file *filp,
++		void *priv, struct v4l2_control *c)
 +{
-+	struct saa7134_fh *fh = priv;
-+	struct saa7134_dev *dev = fh->dev;
- 
--	case VIDIOC_QUERYBUF:
--		return videobuf_querybuf(&dev->empress_tsq,arg);
-+	saa7134_i2c_call_clients(dev, VIDIOC_G_FMT, f);
- 
--	case VIDIOC_QBUF:
--		return videobuf_qbuf(&dev->empress_tsq,arg);
-+	f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
-+	f->fmt.pix.sizeimage    = TS_PACKET_SIZE * dev->ts.nr_packets;
- 
--	case VIDIOC_DQBUF:
--		return videobuf_dqbuf(&dev->empress_tsq,arg,
--				      file->f_flags & O_NONBLOCK);
++	struct stk_camera *dev = priv;
++	switch (c->id) {
++	case V4L2_CID_BRIGHTNESS:
++		dev->vsettings.brightness = c->value;
++		return stk_sensor_set_brightness(dev, c->value >> 8);
++	default:
++		return -EINVAL;
++	}
 +	return 0;
 +}
- 
--	case VIDIOC_STREAMON:
--		return videobuf_streamon(&dev->empress_tsq);
-+static int empress_s_fmt_cap(struct file *file, void *priv,
-+				struct v4l2_format *f)
++
++
++static int stk_vidioc_enum_fmt_cap(struct file *filp,
++		void *priv, struct v4l2_fmtdesc *fmtd)
 +{
-+	struct saa7134_fh *fh = priv;
-+	struct saa7134_dev *dev = fh->dev;
- 
--	case VIDIOC_STREAMOFF:
--		return videobuf_streamoff(&dev->empress_tsq);
-+	saa7134_i2c_call_clients(dev, VIDIOC_S_FMT, f);
- 
--	case VIDIOC_QUERYCTRL:
--	case VIDIOC_G_CTRL:
--	case VIDIOC_S_CTRL:
--		return saa7134_common_ioctl(dev, cmd, arg);
-+	f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
-+	f->fmt.pix.sizeimage    = TS_PACKET_SIZE * dev->ts.nr_packets;
- 
--	case VIDIOC_S_EXT_CTRLS:
--		/* count == 0 is abused in saa6752hs.c, so that special
--		   case is handled here explicitly. */
--		if (ctrls->count == 0)
--			return 0;
--		if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG)
--			return -EINVAL;
--		saa7134_i2c_call_clients(dev, VIDIOC_S_EXT_CTRLS, arg);
--		ts_init_encoder(dev);
--		return 0;
--	case VIDIOC_G_EXT_CTRLS:
--		if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG)
--			return -EINVAL;
--		saa7134_i2c_call_clients(dev, VIDIOC_G_EXT_CTRLS, arg);
++	fmtd->flags = 0;
++
++	switch (fmtd->index) {
++	case 0:
++		fmtd->pixelformat = V4L2_PIX_FMT_RGB565;
++		strcpy(fmtd->description, "r5g6b5");
++		break;
++	case 1:
++		fmtd->pixelformat = V4L2_PIX_FMT_RGB565X;
++		strcpy(fmtd->description, "r5g6b5BE");
++		break;
++	case 2:
++		fmtd->pixelformat = V4L2_PIX_FMT_UYVY;
++		strcpy(fmtd->description, "yuv4:2:2");
++		break;
++	case 3:
++		fmtd->pixelformat = V4L2_PIX_FMT_SBGGR8;
++		strcpy(fmtd->description, "Raw bayer");
++		break;
++	default:
++		return -EINVAL;
++	}
++	return 0;
++}
++
++static struct stk_size {
++	unsigned w;
++	unsigned h;
++	enum stk_mode m;
++} stk_sizes[] = {
++	{ .w = 1280, .h = 1024, .m = MODE_SXGA, },
++	{ .w = 640,  .h = 480,  .m = MODE_VGA,  },
++	{ .w = 352,  .h = 288,  .m = MODE_CIF,  },
++	{ .w = 320,  .h = 240,  .m = MODE_QVGA, },
++	{ .w = 176,  .h = 144,  .m = MODE_QCIF, },
++};
++
++static int stk_vidioc_g_fmt_cap(struct file *filp,
++		void *priv, struct v4l2_format *f)
++{
++	struct v4l2_pix_format *pix_format = &f->fmt.pix;
++	struct stk_camera *dev = priv;
++	int i;
++
++	for (i = 0; i < ARRAY_SIZE(stk_sizes)
++			&& stk_sizes[i].m != dev->vsettings.mode;
++		i++);
++	if (i == ARRAY_SIZE(stk_sizes)) {
++		STK_ERROR("ERROR: mode invalid\n");
++		return -EINVAL;
++	}
++	pix_format->width = stk_sizes[i].w;
++	pix_format->height = stk_sizes[i].h;
++	pix_format->field = V4L2_FIELD_NONE;
++	pix_format->colorspace = V4L2_COLORSPACE_SRGB;
++	pix_format->priv = 0;
++	pix_format->pixelformat = dev->vsettings.palette;
++	if (dev->vsettings.palette == V4L2_PIX_FMT_SBGGR8)
++		pix_format->bytesperline = pix_format->width;
++	else
++		pix_format->bytesperline = 2 * pix_format->width;
++	pix_format->sizeimage = pix_format->bytesperline
++				* pix_format->height;
++	return 0;
++}
++
++static int stk_vidioc_try_fmt_cap(struct file *filp,
++		void *priv, struct v4l2_format *fmtd)
++{
++	int i;
++	switch (fmtd->fmt.pix.pixelformat) {
++	case V4L2_PIX_FMT_RGB565:
++	case V4L2_PIX_FMT_RGB565X:
++	case V4L2_PIX_FMT_UYVY:
++	case V4L2_PIX_FMT_SBGGR8:
++		break;
++	default:
++		return -EINVAL;
++	}
++	for (i = 1; i < ARRAY_SIZE(stk_sizes); i++) {
++		if (fmtd->fmt.pix.width > stk_sizes[i].w)
++			break;
++	}
++	if (i == ARRAY_SIZE(stk_sizes)
++		|| (abs(fmtd->fmt.pix.width - stk_sizes[i-1].w)
++			< abs(fmtd->fmt.pix.width - stk_sizes[i].w))) {
++		fmtd->fmt.pix.height = stk_sizes[i-1].h;
++		fmtd->fmt.pix.width = stk_sizes[i-1].w;
++		fmtd->fmt.pix.priv = i - 1;
++	} else {
++		fmtd->fmt.pix.height = stk_sizes[i].h;
++		fmtd->fmt.pix.width = stk_sizes[i].w;
++		fmtd->fmt.pix.priv = i;
++	}
++
++	fmtd->fmt.pix.field = V4L2_FIELD_NONE;
++	fmtd->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB;
++	if (fmtd->fmt.pix.pixelformat == V4L2_PIX_FMT_SBGGR8)
++		fmtd->fmt.pix.bytesperline = fmtd->fmt.pix.width;
++	else
++		fmtd->fmt.pix.bytesperline = 2 * fmtd->fmt.pix.width;
++	fmtd->fmt.pix.sizeimage = fmtd->fmt.pix.bytesperline
++		* fmtd->fmt.pix.height;
++	return 0;
++}
++
++static int stk_vidioc_s_fmt_cap(struct file *filp,
++		void *priv, struct v4l2_format *fmtd)
++{
++	int ret;
++	struct stk_camera *dev = priv;
++
++	if (dev == NULL)
++		return -ENODEV;
++	if (!is_present(dev))
++		return -ENODEV;
++	if (is_streaming(dev))
++		return -EBUSY;
++	if (dev->owner && dev->owner != filp)
++		return -EBUSY;
++	dev->owner = filp;
++	ret = stk_vidioc_try_fmt_cap(filp, priv, fmtd);
++	if (ret)
++		return ret;
++
++	dev->vsettings.palette = fmtd->fmt.pix.pixelformat;
++	stk_free_buffers(dev);
++	dev->frame_size = fmtd->fmt.pix.sizeimage;
++	dev->vsettings.mode = stk_sizes[fmtd->fmt.pix.priv].m;
++
++	stk_initialise(dev);
++	/* This registers controls some timings, not sure of what. */
++	stk_camera_write_reg(dev, 0x001b, 0x0e);
++	if (dev->vsettings.mode == MODE_SXGA)
++		stk_camera_write_reg(dev, 0x001c, 0x0e);
++	else
++		stk_camera_write_reg(dev, 0x001c, 0x46);
++	/*
++	 * Registers 0x0115 0x0114 are the size of each line (bytes),
++	 * regs 0x0117 0x0116 are the heigth of the image.
++	 */
++	stk_camera_write_reg(dev, 0x0115,
++		(fmtd->fmt.pix.bytesperline >> 8) & 0xff);
++	stk_camera_write_reg(dev, 0x0114,
++		fmtd->fmt.pix.bytesperline & 0xff);
++	stk_camera_write_reg(dev, 0x0117,
++		(fmtd->fmt.pix.height >> 8) & 0xff);
++	stk_camera_write_reg(dev, 0x0116,
++		fmtd->fmt.pix.height & 0xff);
++	return stk_sensor_configure(dev);
++}
++
++static int stk_vidioc_reqbufs(struct file *filp,
++		void *priv, struct v4l2_requestbuffers *rb)
++{
++	struct stk_camera *dev = priv;
++
++	if (dev == NULL)
++		return -ENODEV;
++	if (rb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
++		return -EINVAL;
++	if (rb->memory != V4L2_MEMORY_MMAP)
++		return -EINVAL;
++	if (is_streaming(dev)
++		|| (dev->owner && dev->owner != filp))
++		return -EBUSY;
++	dev->owner = filp;
++
++	/*FIXME If they ask for zero, we must stop streaming and free */
++	if (rb->count < 3)
++		rb->count = 3;
++	/* Arbitrary limit */
++	else if (rb->count > 5)
++		rb->count = 5;
++
++	stk_allocate_buffers(dev, rb->count);
++	rb->count = dev->n_sbufs;
++	return 0;
++}
++
++static int stk_vidioc_querybuf(struct file *filp,
++		void *priv, struct v4l2_buffer *buf)
++{
++	int index;
++	struct stk_camera *dev = priv;
++	struct stk_sio_buffer *sbuf;
++
++	if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
++		return -EINVAL;
++
++	index = buf->index;
++
++	if (index < 0 || index >= dev->n_sbufs)
++		return -EINVAL;
++	sbuf = dev->sio_bufs + buf->index;
++	*buf = sbuf->v4lbuf;
++	return 0;
++}
++
++static int stk_vidioc_qbuf(struct file *filp,
++		void *priv, struct v4l2_buffer *buf)
++{
++	struct stk_camera *dev = priv;
++	struct stk_sio_buffer *sbuf;
++	unsigned long flags;
++	if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
++		return -EINVAL;
++
++	if (buf->memory != V4L2_MEMORY_MMAP)
++		return -EINVAL;
++
++	if (buf->index < 0 || buf->index >= dev->n_sbufs)
++		return -EINVAL;
++	sbuf = dev->sio_bufs + buf->index;
++	if (sbuf->v4lbuf.flags & V4L2_BUF_FLAG_QUEUED)
++		return 0;
++	sbuf->v4lbuf.flags |= V4L2_BUF_FLAG_QUEUED;
++	sbuf->v4lbuf.flags &= ~V4L2_BUF_FLAG_DONE;
++	spin_lock_irqsave(&dev->spinlock, flags);
++	list_add_tail(&sbuf->list, &dev->sio_avail);
++	*buf = sbuf->v4lbuf;
++	spin_unlock_irqrestore(&dev->spinlock, flags);
++	return 0;
++}
++
++static int stk_vidioc_dqbuf(struct file *filp,
++		void *priv, struct v4l2_buffer *buf)
++{
++	struct stk_camera *dev = priv;
++	struct stk_sio_buffer *sbuf;
++	unsigned long flags;
++	int ret;
++
++	if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE
++		|| !is_streaming(dev))
++		return -EINVAL;
++
++	if (filp->f_flags & O_NONBLOCK && list_empty(&dev->sio_full))
++		return -EWOULDBLOCK;
++	ret = wait_event_interruptible(dev->wait_frame,
++		!list_empty(&dev->sio_full) || !is_present(dev));
++	if (ret)
++		return ret;
++	if (!is_present(dev))
++		return -EIO;
++
++	spin_lock_irqsave(&dev->spinlock, flags);
++	sbuf = list_first_entry(&dev->sio_full, struct stk_sio_buffer, list);
++	list_del_init(&sbuf->list);
++	spin_unlock_irqrestore(&dev->spinlock, flags);
++	sbuf->v4lbuf.flags &= ~V4L2_BUF_FLAG_QUEUED;
++	sbuf->v4lbuf.flags |= V4L2_BUF_FLAG_DONE;
++	sbuf->v4lbuf.sequence = ++dev->sequence;
++	do_gettimeofday(&sbuf->v4lbuf.timestamp);
++
++	*buf = sbuf->v4lbuf;
++	return 0;
++}
++
++static int stk_vidioc_streamon(struct file *filp,
++		void *priv, enum v4l2_buf_type type)
++{
++	struct stk_camera *dev = priv;
++	if (is_streaming(dev))
++		return 0;
++	if (dev->sio_bufs == NULL)
++		return -EINVAL;
++	dev->sequence = 0;
++	return stk_start_stream(dev);
++}
++
++static int stk_vidioc_streamoff(struct file *filp,
++		void *priv, enum v4l2_buf_type type)
++{
++	struct stk_camera *dev = priv;
++	unsigned long flags;
++	int i;
++	stk_stop_stream(dev);
++	spin_lock_irqsave(&dev->spinlock, flags);
++	INIT_LIST_HEAD(&dev->sio_avail);
++	INIT_LIST_HEAD(&dev->sio_full);
++	for (i = 0; i < dev->n_sbufs; i++) {
++		INIT_LIST_HEAD(&dev->sio_bufs[i].list);
++		dev->sio_bufs[i].v4lbuf.flags = 0;
++	}
++	spin_unlock_irqrestore(&dev->spinlock, flags);
++	return 0;
++}
++
++
++static int stk_vidioc_g_parm(struct file *filp,
++		void *priv, struct v4l2_streamparm *sp)
++{
++	if (sp->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
++		return -EINVAL;
++
++	sp->parm.capture.capability = 0;
++	sp->parm.capture.capturemode = 0;
++	/*FIXME This is not correct */
++	sp->parm.capture.timeperframe.numerator = 1;
++	sp->parm.capture.timeperframe.denominator = 30;
++	sp->parm.capture.readbuffers = 2;
++	sp->parm.capture.extendedmode = 0;
 +	return 0;
 +}
 +
++static struct file_operations v4l_stk_fops = {
++	.owner = THIS_MODULE,
++	.open = v4l_stk_open,
++	.release = v4l_stk_release,
++	.read = v4l_stk_read,
++	.poll = v4l_stk_poll,
++	.mmap = v4l_stk_mmap,
++	.ioctl = video_ioctl2,
++	.llseek = no_llseek
++};
++
++static void stk_v4l_dev_release(struct video_device *vd)
++{
++}
++
++static struct video_device stk_v4l_data = {
++	.name = "stkwebcam",
++	.type = VFL_TYPE_GRABBER,
++	.type2 = VID_TYPE_CAPTURE,
++	.minor = -1,
++	.tvnorms = V4L2_STD_UNKNOWN,
++	.current_norm = V4L2_STD_UNKNOWN,
++	.fops = &v4l_stk_fops,
++	.release = stk_v4l_dev_release,
++
++	.vidioc_querycap = stk_vidioc_querycap,
++	.vidioc_enum_fmt_cap = stk_vidioc_enum_fmt_cap,
++	.vidioc_try_fmt_cap = stk_vidioc_try_fmt_cap,
++	.vidioc_s_fmt_cap = stk_vidioc_s_fmt_cap,
++	.vidioc_g_fmt_cap = stk_vidioc_g_fmt_cap,
++	.vidioc_enum_input = stk_vidioc_enum_input,
++	.vidioc_s_input = stk_vidioc_s_input,
++	.vidioc_g_input = stk_vidioc_g_input,
++	.vidioc_s_std = stk_vidioc_s_std,
++	.vidioc_reqbufs = stk_vidioc_reqbufs,
++	.vidioc_querybuf = stk_vidioc_querybuf,
++	.vidioc_qbuf = stk_vidioc_qbuf,
++	.vidioc_dqbuf = stk_vidioc_dqbuf,
++	.vidioc_streamon = stk_vidioc_streamon,
++	.vidioc_streamoff = stk_vidioc_streamoff,
++	.vidioc_queryctrl = stk_vidioc_queryctrl,
++	.vidioc_g_ctrl = stk_vidioc_g_ctrl,
++	.vidioc_s_ctrl = stk_vidioc_s_ctrl,
++	.vidioc_g_parm = stk_vidioc_g_parm,
++};
++
 +
-+static int empress_reqbufs(struct file *file, void *priv,
-+					struct v4l2_requestbuffers *p)
++static int stk_register_video_device(struct stk_camera *dev)
 +{
-+	struct saa7134_fh *fh = priv;
-+	struct saa7134_dev *dev = fh->dev;
++	int err;
 +
-+	return videobuf_reqbufs(&dev->empress_tsq, p);
++	dev->vdev = stk_v4l_data;
++	dev->vdev.debug = debug;
++	dev->vdev.dev = &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");
++	else
++		STK_INFO("Syntek USB2.0 Camera is now controlling video device"
++			" /dev/video%d\n", dev->vdev.minor);
++	return err;
 +}
 +
-+static int empress_querybuf(struct file *file, void *priv,
-+					struct v4l2_buffer *b)
-+{
-+	struct saa7134_fh *fh = priv;
-+	struct saa7134_dev *dev = fh->dev;
 +
-+	return videobuf_querybuf(&dev->empress_tsq, b);
-+}
++/* USB Stuff */
 +
-+static int empress_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
++static int stk_camera_probe(struct usb_interface *interface,
++		const struct usb_device_id *id)
 +{
-+	struct saa7134_fh *fh = priv;
-+	struct saa7134_dev *dev = fh->dev;
++	int i;
++	int err;
 +
-+	return videobuf_qbuf(&dev->empress_tsq, b);
-+}
++	struct stk_camera *dev = NULL;
++	struct usb_device *udev = interface_to_usbdev(interface);
++	struct usb_host_interface *iface_desc;
++	struct usb_endpoint_descriptor *endpoint;
 +
-+static int empress_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
-+{
-+	struct saa7134_fh *fh = priv;
-+	struct saa7134_dev *dev = fh->dev;
++	dev = kzalloc(sizeof(struct stk_camera), GFP_KERNEL);
++	if (dev == NULL) {
++		STK_ERROR("Out of memory !\n");
++		return -ENOMEM;
++	}
 +
-+	return videobuf_dqbuf(&dev->empress_tsq, b,
-+				file->f_flags & O_NONBLOCK);
++	kref_init(&dev->kref);
++	spin_lock_init(&dev->spinlock);
++	init_waitqueue_head(&dev->wait_frame);
++
++	dev->udev = udev;
++	dev->interface = interface;
++	usb_get_intf(interface);
++
++	dev->vsettings.vflip = vflip;
++	dev->vsettings.hflip = hflip;
++	dev->n_sbufs = 0;
++	set_present(dev);
++
++	/* Set up the endpoint information
++	 * use only the first isoc-in endpoint
++	 * for the current alternate setting */
++	iface_desc = interface->cur_altsetting;
++
++	for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
++		endpoint = &iface_desc->endpoint[i].desc;
++
++		if (!dev->isoc_ep
++			&& ((endpoint->bEndpointAddress
++				& USB_ENDPOINT_DIR_MASK) == USB_DIR_IN)
++			&& ((endpoint->bmAttributes
++				& USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_ISOC)) {
++			/* we found an isoc in endpoint */
++			dev->isoc_ep = (endpoint->bEndpointAddress & 0xF);
++			break;
++		}
++	}
++	if (!dev->isoc_ep) {
++		STK_ERROR("Could not find isoc-in endpoint");
++		kref_put(&dev->kref, stk_camera_cleanup);
++		return -ENODEV;
++	}
++	dev->vsettings.brightness = 0x7fff;
++	dev->vsettings.palette = V4L2_PIX_FMT_RGB565;
++	dev->vsettings.mode = MODE_VGA;
++	dev->frame_size = 640*480*2;
++
++	INIT_LIST_HEAD(&dev->sio_avail);
++	INIT_LIST_HEAD(&dev->sio_full);
++
++	usb_set_intfdata(interface, dev);
++
++	err = stk_register_video_device(dev);
++	if (err) {
++		kref_put(&dev->kref, stk_camera_cleanup);
++		return err;
++	}
++
++	stk_create_sysfs_files(&dev->vdev);
++
++	return 0;
 +}
 +
-+static int empress_streamon(struct file *file, void *priv,
-+					enum v4l2_buf_type type)
++static void stk_camera_disconnect(struct usb_interface *interface)
 +{
-+	struct saa7134_fh *fh = priv;
-+	struct saa7134_dev *dev = fh->dev;
++	struct stk_camera *dev = usb_get_intfdata(interface);
 +
-+	return videobuf_streamon(&dev->empress_tsq);
++	usb_set_intfdata(interface, NULL);
++	unset_present(dev);
++
++	wake_up_interruptible(&dev->wait_frame);
++	stk_remove_sysfs_files(&dev->vdev);
++
++	kref_put(&dev->kref, stk_camera_cleanup);
 +}
 +
-+static int empress_streamoff(struct file *file, void *priv,
-+					enum v4l2_buf_type type)
++static struct usb_driver stk_camera_driver = {
++	.name = "stkwebcam",
++	.probe = stk_camera_probe,
++	.disconnect = stk_camera_disconnect,
++	.id_table = stkwebcam_table,
++};
++
++
++static int __init stk_camera_init(void)
 +{
-+	struct saa7134_fh *fh = priv;
-+	struct saa7134_dev *dev = fh->dev;
++	int result;
 +
-+	return videobuf_streamoff(&dev->empress_tsq);
++	result = usb_register(&stk_camera_driver);
++	if (result)
++		STK_ERROR("usb_register failed ! Error number %d\n", result);
++
++
++	return result;
 +}
 +
-+static int empress_s_ext_ctrls(struct file *file, void *priv,
-+			       struct v4l2_ext_controls *ctrls)
++static void __exit stk_camera_exit(void)
 +{
-+	struct saa7134_fh *fh = priv;
-+	struct saa7134_dev *dev = fh->dev;
++	usb_deregister(&stk_camera_driver);
++}
 +
-+	/* count == 0 is abused in saa6752hs.c, so that special
-+		case is handled here explicitly. */
-+	if (ctrls->count == 0)
- 		return 0;
- 
--	default:
--		return -ENOIOCTLCMD;
--	}
-+	if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG)
-+		return -EINVAL;
++module_init(stk_camera_init);
++module_exit(stk_camera_exit);
 +
-+	saa7134_i2c_call_clients(dev, VIDIOC_S_EXT_CTRLS, ctrls);
-+	ts_init_encoder(dev);
 +
- 	return 0;
- }
- 
--static int ts_ioctl(struct inode *inode, struct file *file,
--		     unsigned int cmd, unsigned long arg)
-+static int empress_g_ext_ctrls(struct file *file, void *priv,
-+			       struct v4l2_ext_controls *ctrls)
- {
--	return video_usercopy(inode, file, cmd, arg, ts_do_ioctl);
-+	struct saa7134_fh *fh = priv;
-+	struct saa7134_dev *dev = fh->dev;
+diff --git a/drivers/media/video/stk-webcam.h b/drivers/media/video/stk-webcam.h
+new file mode 100644
+index 0000000..7e989d1
+--- /dev/null
++++ b/drivers/media/video/stk-webcam.h
+@@ -0,0 +1,138 @@
++/*
++ * stk-webcam.h : Driver for Syntek 1125 USB webcam controller
++ *
++ * Copyright (C) 2006 Nicolas VIVIEN
++ * Copyright 2007-2008 Jaime Velasco Juan <jsagarribay at 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
++ * any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ */
 +
-+	if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG)
-+		return -EINVAL;
-+	saa7134_i2c_call_clients(dev, VIDIOC_G_EXT_CTRLS, ctrls);
++#ifndef STKWEBCAM_H
++#define STKWEBCAM_H
 +
-+	return 0;
- }
- 
- static const struct file_operations ts_fops =
-@@ -317,7 +341,7 @@ static const struct file_operations ts_fops =
- 	.read	  = ts_read,
- 	.poll	  = ts_poll,
- 	.mmap	  = ts_mmap,
--	.ioctl	  = ts_ioctl,
-+	.ioctl	  = video_ioctl2,
- 	.llseek   = no_llseek,
- };
- 
-@@ -330,6 +354,29 @@ static struct video_device saa7134_empress_template =
- 	.type2         = 0 /* FIXME */,
- 	.fops          = &ts_fops,
- 	.minor	       = -1,
++#include <linux/usb.h>
++#include <media/v4l2-common.h>
 +
-+	.vidioc_querycap		= empress_querycap,
-+	.vidioc_enum_fmt_cap		= empress_enum_fmt_cap,
-+	.vidioc_s_fmt_cap		= empress_s_fmt_cap,
-+	.vidioc_g_fmt_cap		= empress_g_fmt_cap,
-+	.vidioc_reqbufs			= empress_reqbufs,
-+	.vidioc_querybuf		= empress_querybuf,
-+	.vidioc_qbuf			= empress_qbuf,
-+	.vidioc_dqbuf			= empress_dqbuf,
-+	.vidioc_streamon		= empress_streamon,
-+	.vidioc_streamoff		= empress_streamoff,
-+	.vidioc_s_ext_ctrls		= empress_s_ext_ctrls,
-+	.vidioc_g_ext_ctrls		= empress_g_ext_ctrls,
-+	.vidioc_enum_input		= empress_enum_input,
-+	.vidioc_g_input			= empress_g_input,
-+	.vidioc_s_input			= empress_s_input,
++#define DRIVER_VERSION		"v0.0.1"
++#define DRIVER_VERSION_NUM	0x000001
 +
-+	.vidioc_queryctrl		= saa7134_queryctrl,
-+	.vidioc_g_ctrl			= saa7134_g_ctrl,
-+	.vidioc_s_ctrl			= saa7134_s_ctrl,
++#define MAX_ISO_BUFS		3
++#define ISO_FRAMES_PER_DESC	16
++#define ISO_MAX_FRAME_SIZE	3 * 1024
++#define ISO_BUFFER_SIZE		(ISO_FRAMES_PER_DESC * ISO_MAX_FRAME_SIZE)
 +
-+	.tvnorms			= SAA7134_NORMS,
-+	.current_norm			= V4L2_STD_PAL,
- };
- 
- static void empress_signal_update(struct work_struct *work)
-diff --git a/drivers/media/video/saa7134/saa7134-i2c.c b/drivers/media/video/saa7134/saa7134-i2c.c
-index 6deaad1..d3322c3 100644
---- a/drivers/media/video/saa7134/saa7134-i2c.c
-+++ b/drivers/media/video/saa7134/saa7134-i2c.c
-@@ -323,7 +323,6 @@ static int attach_inform(struct i2c_client *client)
- {
- 	struct saa7134_dev *dev = client->adapter->algo_data;
- 	int tuner = dev->tuner_type;
--	int conf  = dev->tda9887_conf;
- 	struct tuner_setup tun_setup;
- 
- 	d1printk( "%s i2c attach [addr=0x%x,client=%s]\n",
-@@ -335,6 +334,7 @@ static int attach_inform(struct i2c_client *client)
- 		case 0x7a:
- 		case 0x47:
- 		case 0x71:
-+		case 0x2d:
- 		{
- 			struct IR_i2c *ir = i2c_get_clientdata(client);
- 			d1printk("%s i2c IR detected (%s).\n",
-@@ -360,7 +360,6 @@ static int attach_inform(struct i2c_client *client)
- 	}
- 
- 	if (tuner != UNSET) {
--
- 		tun_setup.type = tuner;
- 		tun_setup.addr = saa7134_boards[dev->board].tuner_addr;
- 		tun_setup.config = saa7134_boards[dev->board].tuner_config;
-@@ -372,9 +371,18 @@ static int attach_inform(struct i2c_client *client)
- 
- 			client->driver->command(client,TUNER_SET_TYPE_ADDR, &tun_setup);
- 		}
 +
-+		if (tuner == TUNER_TDA9887) {
-+			struct v4l2_priv_tun_config tda9887_cfg;
++#define PREFIX				"stkwebcam: "
++#define STK_INFO(str, args...)		printk(KERN_INFO PREFIX str, ##args)
++#define STK_ERROR(str, args...)		printk(KERN_ERR PREFIX str, ##args)
++#define STK_WARNING(str, args...)	printk(KERN_WARNING PREFIX str, ##args)
 +
-+			tda9887_cfg.tuner = TUNER_TDA9887;
-+			tda9887_cfg.priv = &dev->tda9887_conf;
++struct stk_iso_buf {
++	void *data;
++	int length;
++	int read;
++	struct urb *urb;
++};
 +
-+			client->driver->command(client, TUNER_SET_CONFIG,
-+						&tda9887_cfg);
-+		}
- 	}
- 
--	client->driver->command(client, TDA9887_SET_CONFIG, &conf);
- 
- 	return 0;
- }
-@@ -432,6 +440,7 @@ static char *i2c_devs[128] = {
- 	[ 0xa0 >> 1 ] = "eeprom",
- 	[ 0xc0 >> 1 ] = "tuner (analog)",
- 	[ 0x86 >> 1 ] = "tda9887",
-+	[ 0x5a >> 1 ] = "remote control",
- };
- 
- static void do_i2c_scan(char *name, struct i2c_client *c)
-diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c
-index 3abaa1b..0db955c 100644
---- a/drivers/media/video/saa7134/saa7134-input.c
-+++ b/drivers/media/video/saa7134/saa7134-input.c
-@@ -49,9 +49,14 @@ module_param(repeat_delay, int, 0644);
- MODULE_PARM_DESC(repeat_delay, "delay before key repeat started");
- static int repeat_period = 33;
- module_param(repeat_period, int, 0644);
--MODULE_PARM_DESC(repeat_period, "repeat period between"
-+MODULE_PARM_DESC(repeat_period, "repeat period between "
-     "keypresses when key is down");
- 
-+static unsigned int disable_other_ir;
-+module_param(disable_other_ir, int, 0644);
-+MODULE_PARM_DESC(disable_other_ir, "disable full codes of "
-+    "alternative remotes from other manufacturers");
++/* Streaming IO buffers */
++struct stk_sio_buffer {
++	struct v4l2_buffer v4lbuf;
++	char *buffer;
++	int mapcount;
++	struct stk_camera *dev;
++	struct list_head list;
++};
 +
- #define dprintk(fmt, arg...)	if (ir_debug) \
- 	printk(KERN_DEBUG "%s/ir: " fmt, dev->name , ## arg)
- #define i2cdprintk(fmt, arg...)    if (ir_debug) \
-@@ -154,6 +159,45 @@ static int get_key_hvr1110(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
- 	return 1;
- }
- 
++enum stk_mode {MODE_VGA, MODE_SXGA, MODE_CIF, MODE_QVGA, MODE_QCIF};
 +
-+static int get_key_beholdm6xx(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
-+{
-+	unsigned char data[12];
-+	u32 gpio;
++struct stk_video {
++	enum stk_mode mode;
++	int brightness;
++	__u32 palette;
++	int hflip;
++	int vflip;
++};
 +
-+	struct saa7134_dev *dev = ir->c.adapter->algo_data;
++enum stk_status {
++	S_PRESENT = 1,
++	S_INITIALISED = 2,
++	S_MEMALLOCD = 4,
++	S_STREAMING = 8,
++};
++#define is_present(dev)		((dev)->status & S_PRESENT)
++#define is_initialised(dev)	((dev)->status & S_INITIALISED)
++#define is_streaming(dev)	((dev)->status & S_STREAMING)
++#define is_memallocd(dev)	((dev)->status & S_MEMALLOCD)
++#define set_present(dev)	((dev)->status = S_PRESENT)
++#define unset_present(dev)	((dev)->status &= \
++					~(S_PRESENT|S_INITIALISED|S_STREAMING))
++#define set_initialised(dev)	((dev)->status |= S_INITIALISED)
++#define set_memallocd(dev)	((dev)->status |= S_MEMALLOCD)
++#define unset_memallocd(dev)	((dev)->status &= ~S_MEMALLOCD)
++#define set_streaming(dev)	((dev)->status |= S_STREAMING)
++#define unset_streaming(dev)	((dev)->status &= ~S_STREAMING)
 +
-+	/* rising SAA7134_GPIO_GPRESCAN reads the status */
-+	saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
-+	saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
++struct regval {
++	unsigned reg;
++	unsigned val;
++};
 +
-+	gpio = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2);
++struct stk_camera {
++	struct video_device vdev;
++	struct usb_device *udev;
++	struct usb_interface *interface;
++	int webcam_model;
++	struct file *owner;
 +
-+	if (0x400000 & ~gpio)
-+		return 0; /* No button press */
++	u8 isoc_ep;
 +
-+	ir->c.addr = 0x5a >> 1;
++	struct kref kref;
++	/* Not sure if this is right */
++	atomic_t urbs_used;
 +
-+	if (12 != i2c_master_recv(&ir->c, data, 12)) {
-+		i2cdprintk("read error\n");
-+		return -EIO;
-+	}
-+	/* IR of this card normally decode signals NEC-standard from
-+	 * - Sven IHOO MT 5.1R remote. xxyye718
-+	 * - Sven DVD HD-10xx remote. xxyyf708
-+	 * - BBK ...
-+	 * - mayby others
-+	 * So, skip not our, if disable full codes mode.
-+	 */
-+	if (data[10] != 0x6b && data[11] != 0x86 && disable_other_ir)
-+		return 0;
++	struct stk_video vsettings;
 +
-+	*ir_key = data[9];
-+	*ir_raw = data[9];
++	enum stk_status status;
 +
-+	return 1;
-+}
++	spinlock_t spinlock;
++	wait_queue_head_t wait_frame;
 +
- void saa7134_input_irq(struct saa7134_dev *dev)
++	struct stk_iso_buf *isobufs;
++
++	int frame_size;
++	/* Streaming buffers */
++	unsigned int n_sbufs;
++	struct stk_sio_buffer *sio_bufs;
++	struct list_head sio_avail;
++	struct list_head sio_full;
++	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 *);
++int stk_camera_write_reg(struct stk_camera *, u16, u8);
++int stk_camera_read_reg(struct stk_camera *, u16, int *);
++
++int stk_sensor_outb(struct stk_camera *dev, u8 reg, u8 val);
++int stk_sensor_inb(struct stk_camera *dev, u8 reg, u8 *val);
++int stk_sensor_init(struct stk_camera *);
++int stk_sensor_configure(struct stk_camera *);
++int stk_sensor_sleep(struct stk_camera *dev);
++int stk_sensor_wakeup(struct stk_camera *dev);
++int stk_sensor_set_brightness(struct stk_camera *dev, int br);
++
++#endif
+diff --git a/drivers/media/video/tda7432.c b/drivers/media/video/tda7432.c
+index 4322580..b4d10f7 100644
+--- a/drivers/media/video/tda7432.c
++++ b/drivers/media/video/tda7432.c
+@@ -8,6 +8,7 @@
+  * Muting and tone control by Jonathan Isom <jisom at ematic.com>
+  *
+  * Copyright (c) 2000 Eric Sandeen <eric_sandeen at bigfoot.com>
++ * Copyright (c) 2006 Mauro Carvalho Chehab <mchehab at infradead.org>
+  * This code is placed under the terms of the GNU General Public License
+  * Based on tda9855.c by Steve VanDeBogart (vandebo at uclink.berkeley.edu)
+  * Which was based on tda8425.c by Greg Alexander (c) 1998
+@@ -276,7 +277,7 @@ static void do_tda7432_init(struct i2c_client *client)
+ 	t->volume =  0x3b ;				 /* -27dB Volume            */
+ 	if (loudness)			 /* Turn loudness on?     */
+ 		t->volume |= TDA7432_LD_ON;
+-	t->muted    = VIDEO_AUDIO_MUTE;
++	t->muted    = 1;
+ 	t->treble   = TDA7432_TREBLE_0DB; /* 0dB Treble            */
+ 	t->bass		= TDA7432_BASS_0DB; 	 /* 0dB Bass              */
+ 	t->lf     = TDA7432_ATTEN_0DB;	 /* 0dB attenuation       */
+@@ -332,151 +333,160 @@ static int tda7432_detach(struct i2c_client *client)
+ 	return 0;
+ }
+ 
+-static int tda7432_command(struct i2c_client *client,
+-			   unsigned int cmd, void *arg)
++static int tda7432_get_ctrl(struct i2c_client *client,
++			    struct v4l2_control *ctrl)
  {
- 	struct card_ir *ir = dev->remote;
-@@ -260,6 +304,7 @@ int saa7134_input_init1(struct saa7134_dev *dev)
- 	case SAA7134_BOARD_AVERMEDIA_STUDIO_307:
- 	case SAA7134_BOARD_AVERMEDIA_STUDIO_507:
- 	case SAA7134_BOARD_AVERMEDIA_GO_007_FM:
-+	case SAA7134_BOARD_AVERMEDIA_M102:
- 		ir_codes     = ir_codes_avermedia;
- 		mask_keycode = 0x0007C8;
- 		mask_keydown = 0x000010;
-@@ -287,6 +332,16 @@ int saa7134_input_init1(struct saa7134_dev *dev)
- 	case SAA7134_BOARD_MANLI_MTV001:
- 	case SAA7134_BOARD_MANLI_MTV002:
- 	case SAA7134_BOARD_BEHOLD_409FM:
-+	case SAA7134_BOARD_BEHOLD_401:
-+	case SAA7134_BOARD_BEHOLD_403:
-+	case SAA7134_BOARD_BEHOLD_403FM:
-+	case SAA7134_BOARD_BEHOLD_405:
-+	case SAA7134_BOARD_BEHOLD_405FM:
-+	case SAA7134_BOARD_BEHOLD_407:
-+	case SAA7134_BOARD_BEHOLD_407FM:
-+	case SAA7134_BOARD_BEHOLD_409:
-+	case SAA7134_BOARD_BEHOLD_505FM:
-+	case SAA7134_BOARD_BEHOLD_507_9FM:
- 		ir_codes     = ir_codes_manli;
- 		mask_keycode = 0x001f00;
- 		mask_keyup   = 0x004000;
-@@ -457,6 +512,12 @@ void saa7134_set_i2c_ir(struct saa7134_dev *dev, struct IR_i2c *ir)
- 		ir->get_key   = get_key_hvr1110;
- 		ir->ir_codes  = ir_codes_hauppauge_new;
- 		break;
-+	case SAA7134_BOARD_BEHOLD_607_9FM:
-+	case SAA7134_BOARD_BEHOLD_M6:
-+		snprintf(ir->c.name, sizeof(ir->c.name), "BeholdTV");
-+		ir->get_key   = get_key_beholdm6xx;
-+		ir->ir_codes  = ir_codes_behold;
-+		break;
- 	default:
- 		dprintk("Shouldn't get here: Unknown board %x for I2C IR?\n",dev->board);
- 		break;
-diff --git a/drivers/media/video/saa7134/saa7134-oss.c b/drivers/media/video/saa7134/saa7134-oss.c
-deleted file mode 100644
-index aedf046..0000000
---- a/drivers/media/video/saa7134/saa7134-oss.c
-+++ /dev/null
-@@ -1,1046 +0,0 @@
--/*
-- *
-- * device driver for philips saa7134 based TV cards
-- * oss dsp interface
-- *
-- * (c) 2001,02 Gerd Knorr <kraxel at bytesex.org> [SuSE Labs]
-- *     2005 conversion to standalone module:
-- *         Ricardo Cerqueira <v4l at cerqueira.org>
-- *
-- *  This program is free software; you can redistribute it and/or modify
-- *  it under the terms of the GNU General Public License as published by
-- *  the Free Software Foundation; either version 2 of the License, or
-- *  (at your option) any later version.
-- *
-- *  This program is distributed in the hope that it will be useful,
-- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
-- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-- *  GNU General Public License for more details.
-- *
-- *  You should have received a copy of the GNU General Public License
-- *  along with this program; if not, write to the Free Software
-- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-- */
--
--#include <linux/init.h>
--#include <linux/list.h>
--#include <linux/module.h>
--#include <linux/kernel.h>
--#include <linux/interrupt.h>
--#include <linux/slab.h>
--#include <linux/sound.h>
--#include <linux/soundcard.h>
--
--#include "saa7134-reg.h"
--#include "saa7134.h"
--
--/* ------------------------------------------------------------------ */
--
--static unsigned int debug  = 0;
--module_param(debug, int, 0644);
--MODULE_PARM_DESC(debug,"enable debug messages [oss]");
--
--static unsigned int rate  = 0;
--module_param(rate, int, 0444);
--MODULE_PARM_DESC(rate,"sample rate (valid are: 32000,48000)");
--
--static unsigned int dsp_nr[]   = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET };
--MODULE_PARM_DESC(dsp_nr, "device numbers for SAA7134 capture interface(s).");
--module_param_array(dsp_nr,   int, NULL, 0444);
--
--static unsigned int mixer_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET };
--MODULE_PARM_DESC(mixer_nr, "mixer numbers for SAA7134 capture interface(s).");
--module_param_array(mixer_nr, int, NULL, 0444);
--
--#define dprintk(fmt, arg...)	if (debug) \
--	printk(KERN_DEBUG "%s/oss: " fmt, dev->name , ## arg)
--
--
--/* ------------------------------------------------------------------ */
--
--static int dsp_buffer_conf(struct saa7134_dev *dev, int blksize, int blocks)
--{
--	if (blksize < 0x100)
--		blksize = 0x100;
--	if (blksize > 0x10000)
--		blksize = 0x10000;
--
--	if (blocks < 2)
--		blocks = 2;
--	if ((blksize * blocks) > 1024*1024)
--		blocks = 1024*1024 / blksize;
--
--	dev->dmasound.blocks  = blocks;
--	dev->dmasound.blksize = blksize;
--	dev->dmasound.bufsize = blksize * blocks;
--
--	dprintk("buffer config: %d blocks / %d bytes, %d kB total\n",
--		blocks,blksize,blksize * blocks / 1024);
--	return 0;
--}
--
--static int dsp_buffer_init(struct saa7134_dev *dev)
--{
--	int err;
--
--	BUG_ON(!dev->dmasound.bufsize);
--	videobuf_dma_init(&dev->dmasound.dma);
--	err = videobuf_dma_init_kernel(&dev->dmasound.dma, PCI_DMA_FROMDEVICE,
--				       (dev->dmasound.bufsize + PAGE_SIZE) >> PAGE_SHIFT);
--	if (0 != err)
--		return err;
--	return 0;
--}
--
--static int dsp_buffer_free(struct saa7134_dev *dev)
--{
--	BUG_ON(!dev->dmasound.blksize);
--	videobuf_dma_free(&dev->dmasound.dma);
--	dev->dmasound.blocks  = 0;
--	dev->dmasound.blksize = 0;
--	dev->dmasound.bufsize = 0;
--	return 0;
--}
--
--static void dsp_dma_start(struct saa7134_dev *dev)
--{
--	dev->dmasound.dma_blk     = 0;
--	dev->dmasound.dma_running = 1;
--	saa7134_set_dmabits(dev);
--}
--
--static void dsp_dma_stop(struct saa7134_dev *dev)
--{
--	dev->dmasound.dma_blk     = -1;
--	dev->dmasound.dma_running = 0;
--	saa7134_set_dmabits(dev);
--}
--
--static int dsp_rec_start(struct saa7134_dev *dev)
--{
--	int err, bswap, sign;
--	u32 fmt, control;
--	unsigned long flags;
--
--	/* prepare buffer */
--	if (0 != (err = videobuf_pci_dma_map(dev->pci,&dev->dmasound.dma)))
--		return err;
--	if (0 != (err = saa7134_pgtable_alloc(dev->pci,&dev->dmasound.pt)))
--		goto fail1;
--	if (0 != (err = saa7134_pgtable_build(dev->pci,&dev->dmasound.pt,
--					      dev->dmasound.dma.sglist,
--					      dev->dmasound.dma.sglen,
--					      0)))
--		goto fail2;
--
--	/* sample format */
--	switch (dev->dmasound.afmt) {
--	case AFMT_U8:
--	case AFMT_S8:     fmt = 0x00;  break;
--	case AFMT_U16_LE:
--	case AFMT_U16_BE:
--	case AFMT_S16_LE:
--	case AFMT_S16_BE: fmt = 0x01;  break;
--	default:
--		err = -EINVAL;
--		goto fail2;
--	}
--
--	switch (dev->dmasound.afmt) {
--	case AFMT_S8:
--	case AFMT_S16_LE:
--	case AFMT_S16_BE: sign = 1; break;
--	default:          sign = 0; break;
--	}
--
--	switch (dev->dmasound.afmt) {
--	case AFMT_U16_BE:
--	case AFMT_S16_BE: bswap = 1; break;
--	default:          bswap = 0; break;
--	}
--
--	switch (dev->pci->device) {
--	case PCI_DEVICE_ID_PHILIPS_SAA7134:
--		if (1 == dev->dmasound.channels)
--			fmt |= (1 << 3);
--		if (2 == dev->dmasound.channels)
--			fmt |= (3 << 3);
--		if (sign)
--			fmt |= 0x04;
--		fmt |= (TV == dev->dmasound.input) ? 0xc0 : 0x80;
--
--		saa_writeb(SAA7134_NUM_SAMPLES0, ((dev->dmasound.blksize - 1) & 0x0000ff));
--		saa_writeb(SAA7134_NUM_SAMPLES1, ((dev->dmasound.blksize - 1) & 0x00ff00) >>  8);
--		saa_writeb(SAA7134_NUM_SAMPLES2, ((dev->dmasound.blksize - 1) & 0xff0000) >> 16);
--		saa_writeb(SAA7134_AUDIO_FORMAT_CTRL, fmt);
--
--		break;
--	case PCI_DEVICE_ID_PHILIPS_SAA7133:
--	case PCI_DEVICE_ID_PHILIPS_SAA7135:
--		if (1 == dev->dmasound.channels)
--			fmt |= (1 << 4);
--		if (2 == dev->dmasound.channels)
--			fmt |= (2 << 4);
--		if (!sign)
--			fmt |= 0x04;
--		saa_writel(SAA7133_NUM_SAMPLES, dev->dmasound.blksize -4);
--		saa_writel(SAA7133_AUDIO_CHANNEL, 0x543210 | (fmt << 24));
--		break;
--	}
--	dprintk("rec_start: afmt=%d ch=%d  =>  fmt=0x%x swap=%c\n",
--		dev->dmasound.afmt, dev->dmasound.channels, fmt,
--		bswap ? 'b' : '-');
--
--	/* dma: setup channel 6 (= AUDIO) */
--	control = SAA7134_RS_CONTROL_BURST_16 |
--		SAA7134_RS_CONTROL_ME |
--		(dev->dmasound.pt.dma >> 12);
--	if (bswap)
--		control |= SAA7134_RS_CONTROL_BSWAP;
--	saa_writel(SAA7134_RS_BA1(6),0);
--	saa_writel(SAA7134_RS_BA2(6),dev->dmasound.blksize);
--	saa_writel(SAA7134_RS_PITCH(6),0);
--	saa_writel(SAA7134_RS_CONTROL(6),control);
--
--	/* start dma */
--	dev->dmasound.recording_on = 1;
--	spin_lock_irqsave(&dev->slock,flags);
--	dsp_dma_start(dev);
--	spin_unlock_irqrestore(&dev->slock,flags);
--	return 0;
--
-- fail2:
--	saa7134_pgtable_free(dev->pci,&dev->dmasound.pt);
-- fail1:
--	videobuf_pci_dma_unmap(dev->pci,&dev->dmasound.dma);
--	return err;
--}
--
--static int dsp_rec_stop(struct saa7134_dev *dev)
--{
--	unsigned long flags;
--
--	dprintk("rec_stop dma_blk=%d\n",dev->dmasound.dma_blk);
--
--	/* stop dma */
--	dev->dmasound.recording_on = 0;
--	spin_lock_irqsave(&dev->slock,flags);
--	dsp_dma_stop(dev);
--	spin_unlock_irqrestore(&dev->slock,flags);
--
--	/* unlock buffer */
--	saa7134_pgtable_free(dev->pci,&dev->dmasound.pt);
--	videobuf_pci_dma_unmap(dev->pci,&dev->dmasound.dma);
--	return 0;
--}
--
--/* ------------------------------------------------------------------ */
--
--static int dsp_open(struct inode *inode, struct file *file)
--{
--	int minor = iminor(inode);
--	struct saa7134_dev *dev;
--	int err;
--
--	list_for_each_entry(dev, &saa7134_devlist, devlist)
--		if (dev->dmasound.minor_dsp == minor)
--			goto found;
--	return -ENODEV;
-- found:
--
--	mutex_lock(&dev->dmasound.lock);
--	err = -EBUSY;
--	if (dev->dmasound.users_dsp)
--		goto fail1;
--	dev->dmasound.users_dsp++;
--	file->private_data = dev;
--
--	dev->dmasound.afmt        = AFMT_U8;
--	dev->dmasound.channels    = 1;
--	dev->dmasound.read_count  = 0;
--	dev->dmasound.read_offset = 0;
--	dsp_buffer_conf(dev,PAGE_SIZE,64);
--	err = dsp_buffer_init(dev);
--	if (0 != err)
--		goto fail2;
--
--	mutex_unlock(&dev->dmasound.lock);
--	return 0;
--
-- fail2:
--	dev->dmasound.users_dsp--;
-- fail1:
--	mutex_unlock(&dev->dmasound.lock);
--	return err;
--}
--
--static int dsp_release(struct inode *inode, struct file *file)
--{
--	struct saa7134_dev *dev = file->private_data;
--
--	mutex_lock(&dev->dmasound.lock);
--	if (dev->dmasound.recording_on)
--		dsp_rec_stop(dev);
--	dsp_buffer_free(dev);
--	dev->dmasound.users_dsp--;
--	file->private_data = NULL;
--	mutex_unlock(&dev->dmasound.lock);
--	return 0;
--}
--
--static ssize_t dsp_read(struct file *file, char __user *buffer,
--			size_t count, loff_t *ppos)
--{
--	struct saa7134_dev *dev = file->private_data;
--	DECLARE_WAITQUEUE(wait, current);
--	unsigned int bytes;
--	unsigned long flags;
--	int err,ret = 0;
--
--	add_wait_queue(&dev->dmasound.wq, &wait);
--	mutex_lock(&dev->dmasound.lock);
--	while (count > 0) {
--		/* wait for data if needed */
--		if (0 == dev->dmasound.read_count) {
--			if (!dev->dmasound.recording_on) {
--				err = dsp_rec_start(dev);
--				if (err < 0) {
--					if (0 == ret)
--						ret = err;
--					break;
--				}
--			}
--			if (dev->dmasound.recording_on &&
--			    !dev->dmasound.dma_running) {
--				/* recover from overruns */
--				spin_lock_irqsave(&dev->slock,flags);
--				dsp_dma_start(dev);
--				spin_unlock_irqrestore(&dev->slock,flags);
--			}
--			if (file->f_flags & O_NONBLOCK) {
--				if (0 == ret)
--					ret = -EAGAIN;
--				break;
--			}
--			mutex_unlock(&dev->dmasound.lock);
--			set_current_state(TASK_INTERRUPTIBLE);
--			if (0 == dev->dmasound.read_count)
--				schedule();
--			set_current_state(TASK_RUNNING);
--			mutex_lock(&dev->dmasound.lock);
--			if (signal_pending(current)) {
--				if (0 == ret)
--					ret = -EINTR;
--				break;
--			}
--		}
--
--		/* copy data to userspace */
--		bytes = count;
--		if (bytes > dev->dmasound.read_count)
--			bytes = dev->dmasound.read_count;
--		if (bytes > dev->dmasound.bufsize - dev->dmasound.read_offset)
--			bytes = dev->dmasound.bufsize - dev->dmasound.read_offset;
--		if (copy_to_user(buffer + ret,
--				 dev->dmasound.dma.vmalloc + dev->dmasound.read_offset,
--				 bytes)) {
--			if (0 == ret)
--				ret = -EFAULT;
--			break;
--		}
--
--		ret   += bytes;
--		count -= bytes;
--		dev->dmasound.read_count  -= bytes;
--		dev->dmasound.read_offset += bytes;
--		if (dev->dmasound.read_offset == dev->dmasound.bufsize)
--			dev->dmasound.read_offset = 0;
--	}
--	mutex_unlock(&dev->dmasound.lock);
--	remove_wait_queue(&dev->dmasound.wq, &wait);
--	return ret;
--}
--
--static ssize_t dsp_write(struct file *file, const char __user *buffer,
--			 size_t count, loff_t *ppos)
--{
--	return -EINVAL;
--}
--
--static const char *osspcm_ioctls[] = {
--	"RESET", "SYNC", "SPEED", "STEREO", "GETBLKSIZE", "SETFMT",
--	"CHANNELS", "?", "POST", "SUBDIVIDE", "SETFRAGMENT", "GETFMTS",
--	"GETOSPACE", "GETISPACE", "NONBLOCK", "GETCAPS", "GET/SETTRIGGER",
--	"GETIPTR", "GETOPTR", "MAPINBUF", "MAPOUTBUF", "SETSYNCRO",
--	"SETDUPLEX", "GETODELAY"
--};
--#define OSSPCM_IOCTLS ARRAY_SIZE(osspcm_ioctls)
--
--static void saa7134_oss_print_ioctl(char *name, unsigned int cmd)
--{
--	char *dir;
--
--	switch (_IOC_DIR(cmd)) {
--	case _IOC_NONE:              dir = "--"; break;
--	case _IOC_READ:              dir = "r-"; break;
--	case _IOC_WRITE:             dir = "-w"; break;
--	case _IOC_READ | _IOC_WRITE: dir = "rw"; break;
--	default:                     dir = "??"; break;
--	}
--	switch (_IOC_TYPE(cmd)) {
--	case 'P':
--		printk(KERN_DEBUG "%s: ioctl 0x%08x (oss dsp, %s, SNDCTL_DSP_%s)\n",
--		       name, cmd, dir, (_IOC_NR(cmd) < OSSPCM_IOCTLS) ?
--		       osspcm_ioctls[_IOC_NR(cmd)] : "???");
--		break;
--	case 'M':
--		printk(KERN_DEBUG "%s: ioctl 0x%08x (oss mixer, %s, #%d)\n",
--		       name, cmd, dir, _IOC_NR(cmd));
--		break;
--	default:
--		printk(KERN_DEBUG "%s: ioctl 0x%08x (???, %s, #%d)\n",
--		       name, cmd, dir, _IOC_NR(cmd));
--	}
--}
+ 	struct tda7432 *t = i2c_get_clientdata(client);
+-	v4l_dbg(2, debug,client,"In tda7432_command\n");
+-	if (debug>1)
+-		v4l_i2c_print_ioctl(client,cmd);
+ 
+-	switch (cmd) {
+-	/* --- v4l ioctls --- */
+-	/* take care: bttv does userspace copying, we'll get a
+-	   kernel pointer here... */
 -
--static int dsp_ioctl(struct inode *inode, struct file *file,
--		     unsigned int cmd, unsigned long arg)
--{
--	struct saa7134_dev *dev = file->private_data;
--	void __user *argp = (void __user *) arg;
--	int __user *p = argp;
--	int val = 0;
+-	/* Query card - scale from TDA7432 settings to V4L settings */
+-	case VIDIOCGAUDIO:
+-	{
+-		struct video_audio *va = arg;
 -
--	if (debug > 1)
--		saa7134_oss_print_ioctl(dev->name,cmd);
--	switch (cmd) {
--	case OSS_GETVERSION:
--		return put_user(SOUND_VERSION, p);
--	case SNDCTL_DSP_GETCAPS:
--		return 0;
+-		va->flags |= VIDEO_AUDIO_VOLUME |
+-			VIDEO_AUDIO_BASS |
+-			VIDEO_AUDIO_TREBLE |
+-			VIDEO_AUDIO_MUTABLE;
+-		if (t->muted)
+-			va->flags |= VIDEO_AUDIO_MUTE;
+-		va->mode |= VIDEO_SOUND_STEREO;
+-		/* Master volume control
+-		 * V4L volume is min 0, max 65535
+-		 * TDA7432 Volume:
+-		 * Min (-79dB) is 0x6f
+-		 * Max (+20dB) is 0x07 (630)
+-		 * Max (0dB) is 0x20 (829)
+-		 * (Mask out bit 7 of vol - it's for the loudness setting)
+-		 */
++	switch (ctrl->id) {
++	case V4L2_CID_AUDIO_MUTE:
++		ctrl->value=t->muted;
++		return 0;
++	case V4L2_CID_AUDIO_VOLUME:
+ 		if (!maxvol){  /* max +20db */
+-			va->volume = ( 0x6f - (t->volume & 0x7F) ) * 630;
++			ctrl->value = ( 0x6f - (t->volume & 0x7F) ) * 630;
+ 		} else {       /* max 0db   */
+-			va->volume = ( 0x6f - (t->volume & 0x7F) ) * 829;
++			ctrl->value = ( 0x6f - (t->volume & 0x7F) ) * 829;
+ 		}
 -
--	case SNDCTL_DSP_SPEED:
--		if (get_user(val, p))
--			return -EFAULT;
--		/* fall through */
--	case SOUND_PCM_READ_RATE:
--		return put_user(dev->dmasound.rate, p);
+-		/* Balance depends on L,R attenuation
+-		 * V4L balance is 0 to 65535, middle is 32768
+-		 * TDA7432 attenuation: min (0dB) is 0, max (-37.5dB) is 0x1f
+-		 * to scale up to V4L numbers, mult by 1057
+-		 * attenuation exists for lf, lr, rf, rr
+-		 * we use only lf and rf (front channels)
+-		 */
 -
--	case SNDCTL_DSP_STEREO:
--		if (get_user(val, p))
--			return -EFAULT;
--		mutex_lock(&dev->dmasound.lock);
--		dev->dmasound.channels = val ? 2 : 1;
--		if (dev->dmasound.recording_on) {
--			dsp_rec_stop(dev);
--			dsp_rec_start(dev);
--		}
--		mutex_unlock(&dev->dmasound.lock);
--		return put_user(dev->dmasound.channels-1, p);
++		return 0;
++	case V4L2_CID_AUDIO_BALANCE:
++	{
+ 		if ( (t->lf) < (t->rf) )
+ 			/* right is attenuated, balance shifted left */
+-			va->balance = (32768 - 1057*(t->rf));
++			ctrl->value = (32768 - 1057*(t->rf));
+ 		else
+ 			/* left is attenuated, balance shifted right */
+-			va->balance = (32768 + 1057*(t->lf));
 -
--	case SNDCTL_DSP_CHANNELS:
--		if (get_user(val, p))
--			return -EFAULT;
--		if (val != 1 && val != 2)
--			return -EINVAL;
--		mutex_lock(&dev->dmasound.lock);
--		dev->dmasound.channels = val;
--		if (dev->dmasound.recording_on) {
--			dsp_rec_stop(dev);
--			dsp_rec_start(dev);
--		}
--		mutex_unlock(&dev->dmasound.lock);
--		/* fall through */
--	case SOUND_PCM_READ_CHANNELS:
--		return put_user(dev->dmasound.channels, p);
++			ctrl->value = (32768 + 1057*(t->lf));
++		return 0;
++	}
++	case V4L2_CID_AUDIO_BASS:
++	{
+ 		/* Bass/treble 4 bits each */
+-		va->bass=t->bass;
+-		if(va->bass >= 0x8)
+-			va->bass = ~(va->bass - 0x8) & 0xf;
+-		va->bass = (va->bass << 12)+(va->bass << 8)+(va->bass << 4)+(va->bass);
+-		va->treble=t->treble;
+-		if(va->treble >= 0x8)
+-			va->treble = ~(va->treble - 0x8) & 0xf;
+-		va->treble = (va->treble << 12)+(va->treble << 8)+(va->treble << 4)+(va->treble);
 -
--	case SNDCTL_DSP_GETFMTS: /* Returns a mask */
--		return put_user(AFMT_U8     | AFMT_S8     |
--				AFMT_U16_LE | AFMT_U16_BE |
--				AFMT_S16_LE | AFMT_S16_BE, p);
+-		break; /* VIDIOCGAUDIO case */
++		int bass=t->bass;
++		if(bass >= 0x8)
++			bass = ~(bass - 0x8) & 0xf;
++		ctrl->value = (bass << 12)+(bass << 8)+(bass << 4)+(bass);
++		return 0;
+ 	}
 -
--	case SNDCTL_DSP_SETFMT: /* Selects ONE fmt */
--		if (get_user(val, p))
--			return -EFAULT;
--		switch (val) {
--		case AFMT_QUERY:
--			/* nothing to do */
--			break;
--		case AFMT_U8:
--		case AFMT_S8:
--		case AFMT_U16_LE:
--		case AFMT_U16_BE:
--		case AFMT_S16_LE:
--		case AFMT_S16_BE:
--			mutex_lock(&dev->dmasound.lock);
--			dev->dmasound.afmt = val;
--			if (dev->dmasound.recording_on) {
--				dsp_rec_stop(dev);
--				dsp_rec_start(dev);
+-	/* Set card - scale from V4L settings to TDA7432 settings */
+-	case VIDIOCSAUDIO:
++	case V4L2_CID_AUDIO_TREBLE:
+ 	{
+-		struct video_audio *va = arg;
++		int treble=t->treble;
++		if(treble >= 0x8)
++			treble = ~(treble - 0x8) & 0xf;
++		ctrl->value = (treble << 12)+(treble << 8)+(treble << 4)+(treble);
++		return 0;
++	}
++	}
++	return -EINVAL;
++}
+ 
+-		if(va->flags & VIDEO_AUDIO_VOLUME){
+-			if(!maxvol){ /* max +20db */
+-				t->volume = 0x6f - ((va->volume)/630);
+-			} else {    /* max 0db   */
+-				t->volume = 0x6f - ((va->volume)/829);
 -			}
--			mutex_unlock(&dev->dmasound.lock);
--			return put_user(dev->dmasound.afmt, p);
--		default:
--			return -EINVAL;
++static int tda7432_set_ctrl(struct i2c_client *client,
++			    struct v4l2_control *ctrl)
++{
++	struct tda7432 *t = i2c_get_clientdata(client);
+ 
++	switch (ctrl->id) {
++	case V4L2_CID_AUDIO_MUTE:
++		t->muted=ctrl->value;
++		break;
++	case V4L2_CID_AUDIO_VOLUME:
++		if(!maxvol){ /* max +20db */
++			t->volume = 0x6f - ((ctrl->value)/630);
++		} else {    /* max 0db   */
++			t->volume = 0x6f - ((ctrl->value)/829);
++		}
+ 		if (loudness)		/* Turn on the loudness bit */
+ 			t->volume |= TDA7432_LD_ON;
+ 
+-			tda7432_write(client,TDA7432_VL, t->volume);
 -		}
 -
--	case SOUND_PCM_READ_BITS:
--		switch (dev->dmasound.afmt) {
--		case AFMT_U8:
--		case AFMT_S8:
--			return put_user(8, p);
--		case AFMT_U16_LE:
--		case AFMT_U16_BE:
--		case AFMT_S16_LE:
--		case AFMT_S16_BE:
--			return put_user(16, p);
--		default:
--			return -EINVAL;
+-		if(va->flags & VIDEO_AUDIO_BASS)
+-		{
+-			t->bass = va->bass >> 12;
+-			if(t->bass>= 0x8)
+-					t->bass = (~t->bass & 0xf) + 0x8 ;
 -		}
+-		if(va->flags & VIDEO_AUDIO_TREBLE)
+-		{
+-			t->treble= va->treble >> 12;
+-			if(t->treble>= 0x8)
+-					t->treble = (~t->treble & 0xf) + 0x8 ;
+-		}
+-		if(va->flags & (VIDEO_AUDIO_TREBLE| VIDEO_AUDIO_BASS))
+-			tda7432_write(client,TDA7432_TN, 0x10 | (t->bass << 4) | t->treble );
 -
--	case SNDCTL_DSP_NONBLOCK:
--		file->f_flags |= O_NONBLOCK;
--		return 0;
--
--	case SNDCTL_DSP_RESET:
--		mutex_lock(&dev->dmasound.lock);
--		if (dev->dmasound.recording_on)
--			dsp_rec_stop(dev);
--		mutex_unlock(&dev->dmasound.lock);
--		return 0;
--	case SNDCTL_DSP_GETBLKSIZE:
--		return put_user(dev->dmasound.blksize, p);
--
--	case SNDCTL_DSP_SETFRAGMENT:
--		if (get_user(val, p))
--			return -EFAULT;
--		if (dev->dmasound.recording_on)
--			return -EBUSY;
--		dsp_buffer_free(dev);
--		/* used to be arg >> 16 instead of val >> 16; fixed */
--		dsp_buffer_conf(dev,1 << (val & 0xffff), (val >> 16) & 0xffff);
--		dsp_buffer_init(dev);
--		return 0;
+-		if(va->flags & VIDEO_AUDIO_BALANCE)	{
+-		if (va->balance < 32768)
+-		{
++		tda7432_write(client,TDA7432_VL, t->volume);
++		return 0;
++	case V4L2_CID_AUDIO_BALANCE:
++		if (ctrl->value < 32768) {
+ 			/* shifted to left, attenuate right */
+-			t->rr = (32768 - va->balance)/1057;
++			t->rr = (32768 - ctrl->value)/1057;
+ 			t->rf = t->rr;
+ 			t->lr = TDA7432_ATTEN_0DB;
+ 			t->lf = TDA7432_ATTEN_0DB;
+-		}
+-		else if(va->balance > 32769)
+-		{
++		} else if(ctrl->value > 32769) {
+ 			/* shifted to right, attenuate left */
+-			t->lf = (va->balance - 32768)/1057;
++			t->lf = (ctrl->value - 32768)/1057;
+ 			t->lr = t->lf;
+ 			t->rr = TDA7432_ATTEN_0DB;
+ 			t->rf = TDA7432_ATTEN_0DB;
+-		}
+-		else
+-		{
++		} else {
+ 			/* centered */
+ 			t->rr = TDA7432_ATTEN_0DB;
+ 			t->rf = TDA7432_ATTEN_0DB;
+ 			t->lf = TDA7432_ATTEN_0DB;
+ 			t->lr = TDA7432_ATTEN_0DB;
+ 		}
+-		}
++		break;
++	case V4L2_CID_AUDIO_BASS:
++		t->bass = ctrl->value >> 12;
++		if(t->bass>= 0x8)
++				t->bass = (~t->bass & 0xf) + 0x8 ;
++
++		tda7432_write(client,TDA7432_TN, 0x10 | (t->bass << 4) | t->treble );
++		return 0;
++	case V4L2_CID_AUDIO_TREBLE:
++		t->treble= ctrl->value >> 12;
++		if(t->treble>= 0x8)
++				t->treble = (~t->treble & 0xf) + 0x8 ;
++
++		tda7432_write(client,TDA7432_TN, 0x10 | (t->bass << 4) | t->treble );
++		return 0;
++	default:
++		return -EINVAL;
++	}
+ 
+-		t->muted=(va->flags & VIDEO_AUDIO_MUTE);
+-		if (t->muted)
+-		{
+-			/* Mute & update balance*/
+-			tda7432_write(client,TDA7432_LF, t->lf | TDA7432_MUTE);
+-			tda7432_write(client,TDA7432_LR, t->lr | TDA7432_MUTE);
+-			tda7432_write(client,TDA7432_RF, t->rf | TDA7432_MUTE);
+-			tda7432_write(client,TDA7432_RR, t->rr | TDA7432_MUTE);
+-		} else {
+-			tda7432_write(client,TDA7432_LF, t->lf);
+-			tda7432_write(client,TDA7432_LR, t->lr);
+-			tda7432_write(client,TDA7432_RF, t->rf);
+-			tda7432_write(client,TDA7432_RR, t->rr);
+-		}
++	/* Used for both mute and balance changes */
++	if (t->muted)
++	{
++		/* Mute & update balance*/
++		tda7432_write(client,TDA7432_LF, t->lf | TDA7432_MUTE);
++		tda7432_write(client,TDA7432_LR, t->lr | TDA7432_MUTE);
++		tda7432_write(client,TDA7432_RF, t->rf | TDA7432_MUTE);
++		tda7432_write(client,TDA7432_RR, t->rr | TDA7432_MUTE);
++	} else {
++		tda7432_write(client,TDA7432_LF, t->lf);
++		tda7432_write(client,TDA7432_LR, t->lr);
++		tda7432_write(client,TDA7432_RF, t->rf);
++		tda7432_write(client,TDA7432_RR, t->rr);
++	}
++	return 0;
++}
+ 
+-		break;
++static int tda7432_command(struct i2c_client *client,
++			   unsigned int cmd, void *arg)
++{
++	v4l_dbg(2, debug,client,"In tda7432_command\n");
++	if (debug>1)
++		v4l_i2c_print_ioctl(client,cmd);
++
++	switch (cmd) {
++	/* --- v4l ioctls --- */
++	/* take care: bttv does userspace copying, we'll get a
++	   kernel pointer here... */
++	case VIDIOC_QUERYCTRL:
++	{
++		struct v4l2_queryctrl *qc = arg;
++
++		switch (qc->id) {
++			case V4L2_CID_AUDIO_MUTE:
++			case V4L2_CID_AUDIO_VOLUME:
++			case V4L2_CID_AUDIO_BALANCE:
++			case V4L2_CID_AUDIO_BASS:
++			case V4L2_CID_AUDIO_TREBLE:
++			default:
++				return -EINVAL;
++		}
++		return v4l2_ctrl_query_fill_std(qc);
++	}
++	case VIDIOC_S_CTRL:
++		return tda7432_set_ctrl(client, arg);
+ 
+-	} /* end of VIDEOCSAUDIO case */
++	case VIDIOC_G_CTRL:
++		return tda7432_get_ctrl(client, arg);
+ 
+ 	} /* end of (cmd) switch */
+ 
+diff --git a/drivers/media/video/tda8290.c b/drivers/media/video/tda8290.c
+index 0e5cf45..55bc89a 100644
+--- a/drivers/media/video/tda8290.c
++++ b/drivers/media/video/tda8290.c
+@@ -25,12 +25,14 @@
+ #include <linux/videodev.h>
+ #include "tuner-i2c.h"
+ #include "tda8290.h"
++#include "tda827x.h"
++#include "tda18271.h"
+ 
+-static int debug = 0;
++static int debug;
+ module_param(debug, int, 0644);
+ MODULE_PARM_DESC(debug, "enable verbose debug messages");
+ 
+-#define PREFIX "tda8290 "
++#define PREFIX "tda8290"
+ 
+ /* ---------------------------------------------------------------------- */
+ 
+@@ -38,345 +40,71 @@ struct tda8290_priv {
+ 	struct tuner_i2c_props i2c_props;
+ 
+ 	unsigned char tda8290_easy_mode;
+-	unsigned char tda827x_lpsel;
+-	unsigned char tda827x_addr;
+-	unsigned char tda827x_ver;
+-	unsigned int sgIF;
 -
--	case SNDCTL_DSP_SYNC:
--		/* NOP */
--		return 0;
+-	u32 frequency;
 -
--	case SNDCTL_DSP_GETISPACE:
--	{
--		audio_buf_info info;
--		info.fragsize   = dev->dmasound.blksize;
--		info.fragstotal = dev->dmasound.blocks;
--		info.bytes      = dev->dmasound.read_count;
--		info.fragments  = info.bytes / info.fragsize;
--		if (copy_to_user(argp, &info, sizeof(info)))
--			return -EFAULT;
--		return 0;
--	}
--	default:
--		return -EINVAL;
--	}
--}
+-	unsigned int *lna_cfg;
+-	int (*tuner_callback) (void *dev, int command,int arg);
+-};
 -
--static unsigned int dsp_poll(struct file *file, struct poll_table_struct *wait)
--{
--	struct saa7134_dev *dev = file->private_data;
--	unsigned int mask = 0;
+-/* ---------------------------------------------------------------------- */
 -
--	poll_wait(file, &dev->dmasound.wq, wait);
+-struct tda827x_data {
+-	u32 lomax;
+-	u8  spd;
+-	u8  bs;
+-	u8  bp;
+-	u8  cp;
+-	u8  gc3;
+-	u8 div1p5;
+-};
 -
--	if (0 == dev->dmasound.read_count) {
--		mutex_lock(&dev->dmasound.lock);
--		if (!dev->dmasound.recording_on)
--			dsp_rec_start(dev);
--		mutex_unlock(&dev->dmasound.lock);
--	} else
--		mask |= (POLLIN | POLLRDNORM);
--	return mask;
--}
+-     /* Note lomax entry is lo / 62500 */
 -
--const struct file_operations saa7134_dsp_fops = {
--	.owner   = THIS_MODULE,
--	.open    = dsp_open,
--	.release = dsp_release,
--	.read    = dsp_read,
--	.write   = dsp_write,
--	.ioctl   = dsp_ioctl,
--	.poll    = dsp_poll,
--	.llseek  = no_llseek,
+-static struct tda827x_data tda827x_analog[] = {
+-	{ .lomax =   992, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 1}, /*  62 MHz */
+-	{ .lomax =  1056, .spd = 3, .bs = 3, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 1}, /*  66 MHz */
+-	{ .lomax =  1216, .spd = 3, .bs = 1, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 0}, /*  76 MHz */
+-	{ .lomax =  1344, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 0}, /*  84 MHz */
+-	{ .lomax =  1488, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 1, .div1p5 = 0}, /*  93 MHz */
+-	{ .lomax =  1568, .spd = 3, .bs = 3, .bp = 0, .cp = 0, .gc3 = 1, .div1p5 = 0}, /*  98 MHz */
+-	{ .lomax =  1744, .spd = 3, .bs = 3, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 109 MHz */
+-	{ .lomax =  1968, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 1}, /* 123 MHz */
+-	{ .lomax =  2128, .spd = 2, .bs = 3, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 1}, /* 133 MHz */
+-	{ .lomax =  2416, .spd = 2, .bs = 1, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 151 MHz */
+-	{ .lomax =  2464, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 154 MHz */
+-	{ .lomax =  2896, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 0, .div1p5 = 0}, /* 181 MHz */
+-	{ .lomax =  2960, .spd = 2, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 185 MHz */
+-	{ .lomax =  3472, .spd = 2, .bs = 3, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 217 MHz */
+-	{ .lomax =  3904, .spd = 1, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 1}, /* 244 MHz */
+-	{ .lomax =  4240, .spd = 1, .bs = 3, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 1}, /* 265 MHz */
+-	{ .lomax =  4832, .spd = 1, .bs = 1, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 302 MHz */
+-	{ .lomax =  5184, .spd = 1, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 324 MHz */
+-	{ .lomax =  5920, .spd = 1, .bs = 2, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 370 MHz */
+-	{ .lomax =  7264, .spd = 1, .bs = 3, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 454 MHz */
+-	{ .lomax =  7888, .spd = 0, .bs = 2, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 1}, /* 493 MHz */
+-	{ .lomax =  8480, .spd = 0, .bs = 3, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 1}, /* 530 MHz */
+-	{ .lomax =  8864, .spd = 0, .bs = 1, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 554 MHz */
+-	{ .lomax =  9664, .spd = 0, .bs = 1, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0}, /* 604 MHz */
+-	{ .lomax = 11088, .spd = 0, .bs = 2, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0}, /* 696 MHz */
+-	{ .lomax = 11840, .spd = 0, .bs = 2, .bp = 4, .cp = 1, .gc3 = 0, .div1p5 = 0}, /* 740 MHz */
+-	{ .lomax = 13120, .spd = 0, .bs = 3, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0}, /* 820 MHz */
+-	{ .lomax = 13840, .spd = 0, .bs = 3, .bp = 4, .cp = 1, .gc3 = 0, .div1p5 = 0}, /* 865 MHz */
+-	{ .lomax =     0, .spd = 0, .bs = 0, .bp = 0, .cp = 0, .gc3 = 0, .div1p5 = 0}  /* End      */
 -};
 -
--/* ------------------------------------------------------------------ */
--
--static int
--mixer_recsrc_7134(struct saa7134_dev *dev)
+-static void tda827x_set_analog_params(struct dvb_frontend *fe,
+-				      struct analog_parameters *params)
 -{
--	int analog_io,rate;
+-	unsigned char tuner_reg[8];
+-	unsigned char reg2[2];
+-	u32 N;
+-	int i;
+-	struct tda8290_priv *priv = fe->tuner_priv;
+-	struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags = 0};
+-	unsigned int freq = params->frequency;
 -
--	switch (dev->dmasound.input) {
--	case TV:
--		saa_andorb(SAA7134_AUDIO_FORMAT_CTRL, 0xc0, 0xc0);
--		saa_andorb(SAA7134_SIF_SAMPLE_FREQ,   0x03, 0x00);
--		break;
--	case LINE1:
--	case LINE2:
--	case LINE2_LEFT:
--		analog_io = (LINE1 == dev->dmasound.input) ? 0x00 : 0x08;
--		rate = (32000 == dev->dmasound.rate) ? 0x01 : 0x03;
--		saa_andorb(SAA7134_ANALOG_IO_SELECT,  0x08, analog_io);
--		saa_andorb(SAA7134_AUDIO_FORMAT_CTRL, 0xc0, 0x80);
--		saa_andorb(SAA7134_SIF_SAMPLE_FREQ,   0x03, rate);
--		break;
+-	if (params->mode == V4L2_TUNER_RADIO)
+-		freq = freq / 1000;
+-
+-	N = freq + priv->sgIF;
+-	i = 0;
+-	while (tda827x_analog[i].lomax < N) {
+-		if(tda827x_analog[i + 1].lomax == 0)
+-			break;
+-		i++;
 -	}
--	return 0;
--}
 -
--static int
--mixer_recsrc_7133(struct saa7134_dev *dev)
--{
--	u32 anabar, xbarin;
+-	N = N << tda827x_analog[i].spd;
 -
--	xbarin = 0x03; // adc
--    anabar = 0;
--	switch (dev->dmasound.input) {
--	case TV:
--		xbarin = 0; // Demodulator
--	anabar = 2; // DACs
--		break;
--	case LINE1:
--		anabar = 0;  // aux1, aux1
--		break;
--	case LINE2:
--	case LINE2_LEFT:
--		anabar = 9;  // aux2, aux2
--		break;
--	}
--    /* output xbar always main channel */
--	saa_dsp_writel(dev, 0x46c >> 2, 0xbbbb10);
--	saa_dsp_writel(dev, 0x464 >> 2, xbarin);
--	saa_writel(0x594 >> 2, anabar);
+-	tuner_reg[0] = 0;
+-	tuner_reg[1] = (unsigned char)(N>>8);
+-	tuner_reg[2] = (unsigned char) N;
+-	tuner_reg[3] = 0x40;
+-	tuner_reg[4] = 0x52 + (priv->tda827x_lpsel << 5);
+-	tuner_reg[5] = (tda827x_analog[i].spd   << 6) + (tda827x_analog[i].div1p5 <<5) +
+-		       (tda827x_analog[i].bs     <<3) +  tda827x_analog[i].bp;
+-	tuner_reg[6] = 0x8f + (tda827x_analog[i].gc3 << 4);
+-	tuner_reg[7] = 0x8f;
 -
--	return 0;
--}
+-	msg.buf = tuner_reg;
+-	msg.len = 8;
+-	i2c_transfer(priv->i2c_props.adap, &msg, 1);
 -
--static int
--mixer_recsrc(struct saa7134_dev *dev, enum saa7134_audio_in src)
--{
--	static const char *iname[] = { "Oops", "TV", "LINE1", "LINE2" };
+-	msg.buf= reg2;
+-	msg.len = 2;
+-	reg2[0] = 0x80;
+-	reg2[1] = 0;
+-	i2c_transfer(priv->i2c_props.adap, &msg, 1);
 -
--	dev->dmasound.count++;
--	dev->dmasound.input = src;
--	dprintk("mixer input = %s\n",iname[dev->dmasound.input]);
+-	reg2[0] = 0x60;
+-	reg2[1] = 0xbf;
+-	i2c_transfer(priv->i2c_props.adap, &msg, 1);
 -
--	switch (dev->pci->device) {
--	case PCI_DEVICE_ID_PHILIPS_SAA7134:
--		mixer_recsrc_7134(dev);
--		break;
--	case PCI_DEVICE_ID_PHILIPS_SAA7133:
--	case PCI_DEVICE_ID_PHILIPS_SAA7135:
--		mixer_recsrc_7133(dev);
--		break;
--	}
--	return 0;
--}
+-	reg2[0] = 0x30;
+-	reg2[1] = tuner_reg[4] + 0x80;
+-	i2c_transfer(priv->i2c_props.adap, &msg, 1);
 -
--static int
--mixer_level(struct saa7134_dev *dev, enum saa7134_audio_in src, int level)
--{
--	switch (dev->pci->device) {
--	case PCI_DEVICE_ID_PHILIPS_SAA7134:
--		switch (src) {
--		case TV:
--			/* nothing */
--			break;
--		case LINE1:
--			saa_andorb(SAA7134_ANALOG_IO_SELECT,  0x10,
--				   (100 == level) ? 0x00 : 0x10);
--			break;
--		case LINE2:
--		case LINE2_LEFT:
--			saa_andorb(SAA7134_ANALOG_IO_SELECT,  0x20,
--				   (100 == level) ? 0x00 : 0x20);
--			break;
--		}
--		break;
--	case PCI_DEVICE_ID_PHILIPS_SAA7133:
--	case PCI_DEVICE_ID_PHILIPS_SAA7135:
--		/* nothing */
--		break;
--	}
--	return 0;
--}
+-	msleep(1);
+-	reg2[0] = 0x30;
+-	reg2[1] = tuner_reg[4] + 4;
+-	i2c_transfer(priv->i2c_props.adap, &msg, 1);
 -
--/* ------------------------------------------------------------------ */
+-	msleep(1);
+-	reg2[0] = 0x30;
+-	reg2[1] = tuner_reg[4];
+-	i2c_transfer(priv->i2c_props.adap, &msg, 1);
 -
--static int mixer_open(struct inode *inode, struct file *file)
--{
--	int minor = iminor(inode);
--	struct saa7134_dev *dev;
+-	msleep(550);
+-	reg2[0] = 0x30;
+-	reg2[1] = (tuner_reg[4] & 0xfc) + tda827x_analog[i].cp ;
+-	i2c_transfer(priv->i2c_props.adap, &msg, 1);
 -
--	list_for_each_entry(dev, &saa7134_devlist, devlist)
--		if (dev->dmasound.minor_mixer == minor) {
--			file->private_data = dev;
--			return 0;
--		}
--	return -ENODEV;
--}
+-	reg2[0] = 0x60;
+-	reg2[1] = 0x3f;
+-	i2c_transfer(priv->i2c_props.adap, &msg, 1);
 -
--static int mixer_release(struct inode *inode, struct file *file)
+-	reg2[0] = 0x80;
+-	reg2[1] = 0x08;   // Vsync en
+-	i2c_transfer(priv->i2c_props.adap, &msg, 1);
+-}
+ 
+-static void tda827x_agcf(struct dvb_frontend *fe)
 -{
--	file->private_data = NULL;
--	return 0;
+-	struct tda8290_priv *priv = fe->tuner_priv;
+-	unsigned char data[] = {0x80, 0x0c};
+-	struct i2c_msg msg = {.addr = priv->tda827x_addr, .buf = data,
+-			      .flags = 0, .len = 2};
+-	i2c_transfer(priv->i2c_props.adap, &msg, 1);
 -}
 -
--static int mixer_ioctl(struct inode *inode, struct file *file,
--		     unsigned int cmd, unsigned long arg)
+-/* ---------------------------------------------------------------------- */
++	unsigned char tda827x_addr;
+ 
+-struct tda827xa_data {
+-	u32 lomax;
+-	u8  svco;
+-	u8  spd;
+-	u8  scr;
+-	u8  sbs;
+-	u8  gc3;
+-};
++	unsigned char ver;
++#define TDA8290   1
++#define TDA8295   2
++#define TDA8275   4
++#define TDA8275A  8
++#define TDA18271 16
+ 
+-static struct tda827xa_data tda827xa_analog[] = {
+-	{ .lomax =   910, .svco = 3, .spd = 4, .scr = 0, .sbs = 0, .gc3 = 3},  /*  56.875 MHz */
+-	{ .lomax =  1076, .svco = 0, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3},  /*  67.25 MHz */
+-	{ .lomax =  1300, .svco = 1, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3},  /*  81.25 MHz */
+-	{ .lomax =  1560, .svco = 2, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3},  /*  97.5  MHz */
+-	{ .lomax =  1820, .svco = 3, .spd = 3, .scr = 0, .sbs = 1, .gc3 = 1},  /* 113.75 MHz */
+-	{ .lomax =  2152, .svco = 0, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},  /* 134.5 MHz */
+-	{ .lomax =  2464, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},  /* 154   MHz */
+-	{ .lomax =  2600, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},  /* 162.5 MHz */
+-	{ .lomax =  2928, .svco = 2, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},  /* 183   MHz */
+-	{ .lomax =  3120, .svco = 2, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 1},  /* 195   MHz */
+-	{ .lomax =  3640, .svco = 3, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 3},  /* 227.5 MHz */
+-	{ .lomax =  4304, .svco = 0, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 3},  /* 269   MHz */
+-	{ .lomax =  5200, .svco = 1, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 1},  /* 325   MHz */
+-	{ .lomax =  6240, .svco = 2, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 3},  /* 390   MHz */
+-	{ .lomax =  7280, .svco = 3, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 3},  /* 455   MHz */
+-	{ .lomax =  8320, .svco = 0, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1},  /* 520   MHz */
+-	{ .lomax =  8608, .svco = 0, .spd = 0, .scr = 1, .sbs = 3, .gc3 = 1},  /* 538   MHz */
+-	{ .lomax =  8864, .svco = 1, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1},  /* 554   MHz */
+-	{ .lomax =  9920, .svco = 1, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0},  /* 620   MHz */
+-	{ .lomax = 10400, .svco = 1, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0},  /* 650   MHz */
+-	{ .lomax = 11200, .svco = 2, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0},  /* 700   MHz */
+-	{ .lomax = 12480, .svco = 2, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0},  /* 780   MHz */
+-	{ .lomax = 13120, .svco = 3, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0},  /* 820   MHz */
+-	{ .lomax = 13920, .svco = 3, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0},  /* 870   MHz */
+-	{ .lomax = 14576, .svco = 3, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 0},  /* 911   MHz */
+-	{ .lomax =     0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0}   /* End */
++	struct tda827x_config cfg;
+ };
+ 
+-static void tda827xa_lna_gain(struct dvb_frontend *fe, int high,
+-			      struct analog_parameters *params)
 -{
--	struct saa7134_dev *dev = file->private_data;
--	enum saa7134_audio_in input;
--	int val,ret;
--	void __user *argp = (void __user *) arg;
--	int __user *p = argp;
+-	struct tda8290_priv *priv = fe->tuner_priv;
+-	unsigned char buf[] = {0x22, 0x01};
+-	int arg;
+-	struct i2c_msg msg = {.addr = priv->i2c_props.addr, .flags = 0, .buf = buf, .len = sizeof(buf)};
 -
--	if (debug > 1)
--		saa7134_oss_print_ioctl(dev->name,cmd);
--	switch (cmd) {
--	case OSS_GETVERSION:
--		return put_user(SOUND_VERSION, p);
--	case SOUND_MIXER_INFO:
--	{
--		mixer_info info;
--		memset(&info,0,sizeof(info));
--		strlcpy(info.id,   "TV audio", sizeof(info.id));
--		strlcpy(info.name, dev->name,  sizeof(info.name));
--		info.modify_counter = dev->dmasound.count;
--		if (copy_to_user(argp, &info, sizeof(info)))
--			return -EFAULT;
--		return 0;
+-	if ((priv->lna_cfg == NULL)  || (priv->tuner_callback == NULL))
+-	    return;
+-
+-	if (*priv->lna_cfg) {
+-		if (high)
+-			tuner_dbg("setting LNA to high gain\n");
+-		else
+-			tuner_dbg("setting LNA to low gain\n");
 -	}
--	case SOUND_OLD_MIXER_INFO:
--	{
--		_old_mixer_info info;
--		memset(&info,0,sizeof(info));
--		strlcpy(info.id,   "TV audio", sizeof(info.id));
--		strlcpy(info.name, dev->name,  sizeof(info.name));
--		if (copy_to_user(argp, &info, sizeof(info)))
--			return -EFAULT;
--		return 0;
+-	switch (*priv->lna_cfg) {
+-	case 0: /* no LNA */
+-		break;
+-	case 1: /* switch is GPIO 0 of tda8290 */
+-	case 2:
+-		/* turn Vsync on */
+-		if (params->std & V4L2_STD_MN)
+-			arg = 1;
+-		else
+-			arg = 0;
+-		if (priv->tuner_callback)
+-			priv->tuner_callback(priv->i2c_props.adap->algo_data, 1, arg);
+-		buf[1] = high ? 0 : 1;
+-		if (*priv->lna_cfg == 2)
+-			buf[1] = high ? 1 : 0;
+-		i2c_transfer(priv->i2c_props.adap, &msg, 1);
+-		break;
+-	case 3: /* switch with GPIO of saa713x */
+-		if (priv->tuner_callback)
+-			priv->tuner_callback(priv->i2c_props.adap->algo_data, 0, high);
+-		break;
 -	}
--	case MIXER_READ(SOUND_MIXER_CAPS):
--		return put_user(SOUND_CAP_EXCL_INPUT, p);
--	case MIXER_READ(SOUND_MIXER_STEREODEVS):
--		return put_user(0, p);
--	case MIXER_READ(SOUND_MIXER_RECMASK):
--	case MIXER_READ(SOUND_MIXER_DEVMASK):
--		val = SOUND_MASK_LINE1 | SOUND_MASK_LINE2;
--		if (32000 == dev->dmasound.rate)
--			val |= SOUND_MASK_VIDEO;
--		return put_user(val, p);
+-}
++/*---------------------------------------------------------------------*/
+ 
+-static void tda827xa_set_analog_params(struct dvb_frontend *fe,
+-				       struct analog_parameters *params)
++static int tda8290_i2c_bridge(struct dvb_frontend *fe, int close)
+ {
+-	unsigned char tuner_reg[11];
+-	u32 N;
+-	int i;
+-	struct tda8290_priv *priv = fe->tuner_priv;
+-	struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags = 0, .buf = tuner_reg};
+-	unsigned int freq = params->frequency;
++	struct tda8290_priv *priv = fe->analog_demod_priv;
+ 
+-	tda827xa_lna_gain(fe, 1, params);
+-	msleep(10);
 -
--	case MIXER_WRITE(SOUND_MIXER_RECSRC):
--		if (get_user(val, p))
--			return -EFAULT;
--		input = dev->dmasound.input;
--		if (32000 == dev->dmasound.rate  &&
--		    val & SOUND_MASK_VIDEO  &&  dev->dmasound.input != TV)
--			input = TV;
--		if (val & SOUND_MASK_LINE1  &&  dev->dmasound.input != LINE1)
--			input = LINE1;
--		if (val & SOUND_MASK_LINE2  &&  dev->dmasound.input != LINE2)
--			input = LINE2;
--		if (input != dev->dmasound.input)
--			mixer_recsrc(dev,input);
--		/* fall throuth */
--	case MIXER_READ(SOUND_MIXER_RECSRC):
--		switch (dev->dmasound.input) {
--		case TV:    ret = SOUND_MASK_VIDEO; break;
--		case LINE1: ret = SOUND_MASK_LINE1; break;
--		case LINE2: ret = SOUND_MASK_LINE2; break;
--		default:    ret = 0;
--		}
--		return put_user(ret, p);
+-	if (params->mode == V4L2_TUNER_RADIO)
+-		freq = freq / 1000;
++	unsigned char  enable[2] = { 0x21, 0xC0 };
++	unsigned char disable[2] = { 0x21, 0x00 };
++	unsigned char *msg;
+ 
+-	N = freq + priv->sgIF;
+-	i = 0;
+-	while (tda827xa_analog[i].lomax < N) {
+-		if(tda827xa_analog[i + 1].lomax == 0)
+-			break;
+-		i++;
++	if (close) {
++		msg = enable;
++		tuner_i2c_xfer_send(&priv->i2c_props, msg, 2);
++		/* let the bridge stabilize */
++		msleep(20);
++	} else {
++		msg = disable;
++		tuner_i2c_xfer_send(&priv->i2c_props, msg, 2);
+ 	}
+ 
+-	N = N << tda827xa_analog[i].spd;
 -
--	case MIXER_WRITE(SOUND_MIXER_VIDEO):
--	case MIXER_READ(SOUND_MIXER_VIDEO):
--		if (32000 != dev->dmasound.rate)
--			return -EINVAL;
--		return put_user(100 | 100 << 8, p);
+-	tuner_reg[0] = 0;
+-	tuner_reg[1] = (unsigned char)(N>>8);
+-	tuner_reg[2] = (unsigned char) N;
+-	tuner_reg[3] = 0;
+-	tuner_reg[4] = 0x16;
+-	tuner_reg[5] = (tda827xa_analog[i].spd << 5) + (tda827xa_analog[i].svco << 3) +
+-			tda827xa_analog[i].sbs;
+-	tuner_reg[6] = 0x8b + (tda827xa_analog[i].gc3 << 4);
+-	tuner_reg[7] = 0x1c;
+-	tuner_reg[8] = 4;
+-	tuner_reg[9] = 0x20;
+-	tuner_reg[10] = 0x00;
+-	msg.len = 11;
+-	i2c_transfer(priv->i2c_props.adap, &msg, 1);
 -
--	case MIXER_WRITE(SOUND_MIXER_LINE1):
--		if (get_user(val, p))
--			return -EFAULT;
--		val &= 0xff;
--		val = (val <= 50) ? 50 : 100;
--		dev->dmasound.line1 = val;
--		mixer_level(dev,LINE1,dev->dmasound.line1);
--		/* fall throuth */
--	case MIXER_READ(SOUND_MIXER_LINE1):
--		return put_user(dev->dmasound.line1 | dev->dmasound.line1 << 8, p);
+-	tuner_reg[0] = 0x90;
+-	tuner_reg[1] = 0xff;
+-	tuner_reg[2] = 0xe0;
+-	tuner_reg[3] = 0;
+-	tuner_reg[4] = 0x99 + (priv->tda827x_lpsel << 1);
+-	msg.len = 5;
+-	i2c_transfer(priv->i2c_props.adap, &msg, 1);
 -
--	case MIXER_WRITE(SOUND_MIXER_LINE2):
--		if (get_user(val, p))
--			return -EFAULT;
--		val &= 0xff;
--		val = (val <= 50) ? 50 : 100;
--		dev->dmasound.line2 = val;
--		mixer_level(dev,LINE2,dev->dmasound.line2);
--		/* fall throuth */
--	case MIXER_READ(SOUND_MIXER_LINE2):
--		return put_user(dev->dmasound.line2 | dev->dmasound.line2 << 8, p);
+-	tuner_reg[0] = 0xa0;
+-	tuner_reg[1] = 0xc0;
+-	msg.len = 2;
+-	i2c_transfer(priv->i2c_props.adap, &msg, 1);
 -
--	default:
--		return -EINVAL;
--	}
--}
+-	tuner_reg[0] = 0x30;
+-	tuner_reg[1] = 0x10 + tda827xa_analog[i].scr;
+-	i2c_transfer(priv->i2c_props.adap, &msg, 1);
 -
--const struct file_operations saa7134_mixer_fops = {
--	.owner   = THIS_MODULE,
--	.open    = mixer_open,
--	.release = mixer_release,
--	.ioctl   = mixer_ioctl,
--	.llseek  = no_llseek,
--};
+-	msg.flags = I2C_M_RD;
+-	i2c_transfer(priv->i2c_props.adap, &msg, 1);
+-	msg.flags = 0;
+-	tuner_reg[1] >>= 4;
+-	tuner_dbg("AGC2 gain is: %d\n", tuner_reg[1]);
+-	if (tuner_reg[1] < 1)
+-		tda827xa_lna_gain(fe, 0, params);
 -
--/* ------------------------------------------------------------------ */
+-	msleep(100);
+-	tuner_reg[0] = 0x60;
+-	tuner_reg[1] = 0x3c;
+-	i2c_transfer(priv->i2c_props.adap, &msg, 1);
 -
--static irqreturn_t saa7134_oss_irq(int irq, void *dev_id)
--{
--	struct saa7134_dmasound *dmasound = dev_id;
--	struct saa7134_dev *dev = dmasound->priv_data;
--	unsigned long report, status;
--	int loop, handled = 0;
+-	msleep(163);
+-	tuner_reg[0] = 0x50;
+-	tuner_reg[1] = 0x8f + (tda827xa_analog[i].gc3 << 4);
+-	i2c_transfer(priv->i2c_props.adap, &msg, 1);
 -
--	for (loop = 0; loop < 10; loop++) {
--		report = saa_readl(SAA7134_IRQ_REPORT);
--		status = saa_readl(SAA7134_IRQ_STATUS);
+-	tuner_reg[0] = 0x80;
+-	tuner_reg[1] = 0x28;
+-	i2c_transfer(priv->i2c_props.adap, &msg, 1);
 -
--		if (report & SAA7134_IRQ_REPORT_DONE_RA3) {
--			handled = 1;
--			saa_writel(SAA7134_IRQ_REPORT,report);
--			saa7134_irq_oss_done(dev, status);
--		} else {
--			goto out;
--		}
--	}
+-	tuner_reg[0] = 0xb0;
+-	tuner_reg[1] = 0x01;
+-	i2c_transfer(priv->i2c_props.adap, &msg, 1);
 -
--	if (loop == 10) {
--		dprintk("error! looping IRQ!");
--	}
--out:
--	return IRQ_RETVAL(handled);
+-	tuner_reg[0] = 0xc0;
+-	tuner_reg[1] = 0x19 + (priv->tda827x_lpsel << 1);
+-	i2c_transfer(priv->i2c_props.adap, &msg, 1);
 -}
 -
--int saa7134_oss_init1(struct saa7134_dev *dev)
+-static void tda827xa_agcf(struct dvb_frontend *fe)
 -{
+-	struct tda8290_priv *priv = fe->tuner_priv;
+-	unsigned char data[] = {0x80, 0x2c};
+-	struct i2c_msg msg = {.addr = priv->tda827x_addr, .buf = data,
+-			      .flags = 0, .len = 2};
+-	i2c_transfer(priv->i2c_props.adap, &msg, 1);
++	return 0;
+ }
+ 
+-/*---------------------------------------------------------------------*/
 -
--	if ((request_irq(dev->pci->irq, saa7134_oss_irq,
--			 IRQF_SHARED | IRQF_DISABLED, dev->name,
--			(void*) &dev->dmasound)) < 0)
--		return -1;
--
--	/* general */
--	mutex_init(&dev->dmasound.lock);
--	init_waitqueue_head(&dev->dmasound.wq);
--
--	switch (dev->pci->device) {
--	case PCI_DEVICE_ID_PHILIPS_SAA7133:
--	case PCI_DEVICE_ID_PHILIPS_SAA7135:
--		saa_writel(0x588 >> 2, 0x00000fff);
--		saa_writel(0x58c >> 2, 0x00543210);
--		saa_dsp_writel(dev, 0x46c >> 2, 0xbbbbbb);
--		break;
--	}
--
--	/* dsp */
--	dev->dmasound.rate = 32000;
--	if (rate)
--		dev->dmasound.rate = rate;
--	dev->dmasound.rate = (dev->dmasound.rate > 40000) ? 48000 : 32000;
--
--	/* mixer */
--	dev->dmasound.line1 = 50;
--	dev->dmasound.line2 = 50;
--	mixer_level(dev,LINE1,dev->dmasound.line1);
--	mixer_level(dev,LINE2,dev->dmasound.line2);
--	mixer_recsrc(dev, (dev->dmasound.rate == 32000) ? TV : LINE2);
+-static void tda8290_i2c_bridge(struct dvb_frontend *fe, int close)
++static int tda8295_i2c_bridge(struct dvb_frontend *fe, int close)
+ {
+-	struct tda8290_priv *priv = fe->tuner_priv;
++	struct tda8290_priv *priv = fe->analog_demod_priv;
+ 
+-	unsigned char  enable[2] = { 0x21, 0xC0 };
+-	unsigned char disable[2] = { 0x21, 0x00 };
++	unsigned char  enable[2] = { 0x45, 0xc1 };
++	unsigned char disable[2] = { 0x46, 0x00 };
++	unsigned char buf[3] = { 0x45, 0x01, 0x00 };
+ 	unsigned char *msg;
+-	if(close) {
++
++	if (close) {
+ 		msg = enable;
+ 		tuner_i2c_xfer_send(&priv->i2c_props, msg, 2);
+ 		/* let the bridge stabilize */
+ 		msleep(20);
+ 	} else {
+ 		msg = disable;
++		tuner_i2c_xfer_send(&priv->i2c_props, msg, 1);
++		tuner_i2c_xfer_recv(&priv->i2c_props, &msg[1], 1);
++
++		buf[2] = msg[1];
++		buf[2] &= ~0x04;
++		tuner_i2c_xfer_send(&priv->i2c_props, buf, 3);
++		msleep(5);
++
++		msg[1] |= 0x04;
+ 		tuner_i2c_xfer_send(&priv->i2c_props, msg, 2);
+ 	}
++
++	return 0;
+ }
+ 
+ /*---------------------------------------------------------------------*/
+@@ -384,55 +112,43 @@ static void tda8290_i2c_bridge(struct dvb_frontend *fe, int close)
+ static void set_audio(struct dvb_frontend *fe,
+ 		      struct analog_parameters *params)
+ {
+-	struct tda8290_priv *priv = fe->tuner_priv;
++	struct tda8290_priv *priv = fe->analog_demod_priv;
+ 	char* mode;
+ 
+-	priv->tda827x_lpsel = 0;
+ 	if (params->std & V4L2_STD_MN) {
+-		priv->sgIF = 92;
+ 		priv->tda8290_easy_mode = 0x01;
+-		priv->tda827x_lpsel = 1;
+ 		mode = "MN";
+ 	} else if (params->std & V4L2_STD_B) {
+-		priv->sgIF = 108;
+ 		priv->tda8290_easy_mode = 0x02;
+ 		mode = "B";
+ 	} else if (params->std & V4L2_STD_GH) {
+-		priv->sgIF = 124;
+ 		priv->tda8290_easy_mode = 0x04;
+ 		mode = "GH";
+ 	} else if (params->std & V4L2_STD_PAL_I) {
+-		priv->sgIF = 124;
+ 		priv->tda8290_easy_mode = 0x08;
+ 		mode = "I";
+ 	} else if (params->std & V4L2_STD_DK) {
+-		priv->sgIF = 124;
+ 		priv->tda8290_easy_mode = 0x10;
+ 		mode = "DK";
+ 	} else if (params->std & V4L2_STD_SECAM_L) {
+-		priv->sgIF = 124;
+ 		priv->tda8290_easy_mode = 0x20;
+ 		mode = "L";
+ 	} else if (params->std & V4L2_STD_SECAM_LC) {
+-		priv->sgIF = 20;
+ 		priv->tda8290_easy_mode = 0x40;
+ 		mode = "LC";
+ 	} else {
+-		priv->sgIF = 124;
+ 		priv->tda8290_easy_mode = 0x10;
+ 		mode = "xx";
+ 	}
+ 
+-	if (params->mode == V4L2_TUNER_RADIO)
+-		priv->sgIF = 88; /* if frequency is 5.5 MHz */
 -
+-	tuner_dbg("setting tda8290 to system %s\n", mode);
++	tuner_dbg("setting tda829x to system %s\n", mode);
+ }
+ 
+-static int tda8290_set_params(struct dvb_frontend *fe,
+-			      struct analog_parameters *params)
++static void tda8290_set_params(struct dvb_frontend *fe,
++			       struct analog_parameters *params)
+ {
+-	struct tda8290_priv *priv = fe->tuner_priv;
++	struct tda8290_priv *priv = fe->analog_demod_priv;
++
+ 	unsigned char soft_reset[]  = { 0x00, 0x00 };
+ 	unsigned char easy_mode[]   = { 0x01, priv->tda8290_easy_mode };
+ 	unsigned char expert_mode[] = { 0x01, 0x80 };
+@@ -457,8 +173,8 @@ static int tda8290_set_params(struct dvb_frontend *fe,
+ 
+ 	set_audio(fe, params);
+ 
+-	if (priv->lna_cfg)
+-		tuner_dbg("tda827xa config is 0x%02x\n", *priv->lna_cfg);
++	if (priv->cfg.config)
++		tuner_dbg("tda827xa config is 0x%02x\n", *priv->cfg.config);
+ 	tuner_i2c_xfer_send(&priv->i2c_props, easy_mode, 2);
+ 	tuner_i2c_xfer_send(&priv->i2c_props, agc_out_on, 2);
+ 	tuner_i2c_xfer_send(&priv->i2c_props, soft_reset, 2);
+@@ -475,10 +191,10 @@ static int tda8290_set_params(struct dvb_frontend *fe,
+ 	tuner_i2c_xfer_send(&priv->i2c_props, pll_bw_nom, 2);
+ 
+ 	tda8290_i2c_bridge(fe, 1);
+-	if (priv->tda827x_ver != 0)
+-		tda827xa_set_analog_params(fe, params);
+-	else
+-		tda827x_set_analog_params(fe, params);
++
++	if (fe->ops.tuner_ops.set_analog_params)
++		fe->ops.tuner_ops.set_analog_params(fe, params);
++
+ 	for (i = 0; i < 3; i++) {
+ 		tuner_i2c_xfer_send(&priv->i2c_props, &addr_pll_stat, 1);
+ 		tuner_i2c_xfer_recv(&priv->i2c_props, &pll_stat, 1);
+@@ -507,10 +223,8 @@ static int tda8290_set_params(struct dvb_frontend *fe,
+ 		if ((agc_stat > 115) || !(pll_stat & 0x80)) {
+ 			tuner_dbg("adjust gain, step 2. Agc: %d, lock: %d\n",
+ 				   agc_stat, pll_stat & 0x80);
+-			if (priv->tda827x_ver != 0)
+-				tda827xa_agcf(fe);
+-			else
+-				tda827x_agcf(fe);
++			if (priv->cfg.agcf)
++				priv->cfg.agcf(fe);
+ 			msleep(100);
+ 			tuner_i2c_xfer_send(&priv->i2c_props, &addr_agc_stat, 1);
+ 			tuner_i2c_xfer_recv(&priv->i2c_props, &agc_stat, 1);
+@@ -541,99 +255,242 @@ static int tda8290_set_params(struct dvb_frontend *fe,
+ 
+ 	tda8290_i2c_bridge(fe, 0);
+ 	tuner_i2c_xfer_send(&priv->i2c_props, if_agc_set, 2);
++}
++
++/*---------------------------------------------------------------------*/
++
++static void tda8295_power(struct dvb_frontend *fe, int enable)
++{
++	struct tda8290_priv *priv = fe->analog_demod_priv;
++	unsigned char buf[] = { 0x30, 0x00 }; /* clb_stdbt */
+ 
+-	priv->frequency = (V4L2_TUNER_RADIO == params->mode) ?
+-		params->frequency * 125 / 2 : params->frequency * 62500;
++	tuner_i2c_xfer_send(&priv->i2c_props, &buf[0], 1);
++	tuner_i2c_xfer_recv(&priv->i2c_props, &buf[1], 1);
+ 
 -	return 0;
--}
--
--int saa7134_oss_fini(struct saa7134_dev *dev)
--{
--	/* nothing */
++	if (enable)
++		buf[1] = 0x01;
++	else
++		buf[1] = 0x03;
++
++	tuner_i2c_xfer_send(&priv->i2c_props, buf, 2);
++}
++
++static void tda8295_set_easy_mode(struct dvb_frontend *fe, int enable)
++{
++	struct tda8290_priv *priv = fe->analog_demod_priv;
++	unsigned char buf[] = { 0x01, 0x00 };
++
++	tuner_i2c_xfer_send(&priv->i2c_props, &buf[0], 1);
++	tuner_i2c_xfer_recv(&priv->i2c_props, &buf[1], 1);
++
++	if (enable)
++		buf[1] = 0x01; /* rising edge sets regs 0x02 - 0x23 */
++	else
++		buf[1] = 0x00; /* reset active bit */
++
++	tuner_i2c_xfer_send(&priv->i2c_props, buf, 2);
++}
++
++static void tda8295_set_video_std(struct dvb_frontend *fe)
++{
++	struct tda8290_priv *priv = fe->analog_demod_priv;
++	unsigned char buf[] = { 0x00, priv->tda8290_easy_mode };
++
++	tuner_i2c_xfer_send(&priv->i2c_props, buf, 2);
++
++	tda8295_set_easy_mode(fe, 1);
++	msleep(20);
++	tda8295_set_easy_mode(fe, 0);
+ }
+ 
+ /*---------------------------------------------------------------------*/
+ 
+-static int tda8290_has_signal(struct dvb_frontend *fe)
++static void tda8295_agc1_out(struct dvb_frontend *fe, int enable)
+ {
+-	struct tda8290_priv *priv = fe->tuner_priv;
+-	int ret;
++	struct tda8290_priv *priv = fe->analog_demod_priv;
++	unsigned char buf[] = { 0x02, 0x00 }; /* DIV_FUNC */
+ 
+-	unsigned char i2c_get_afc[1] = { 0x1B };
+-	unsigned char afc = 0;
++	tuner_i2c_xfer_send(&priv->i2c_props, &buf[0], 1);
++	tuner_i2c_xfer_recv(&priv->i2c_props, &buf[1], 1);
+ 
+-	/* for now, report based on afc status */
+-	tuner_i2c_xfer_send(&priv->i2c_props, i2c_get_afc, ARRAY_SIZE(i2c_get_afc));
+-	tuner_i2c_xfer_recv(&priv->i2c_props, &afc, 1);
++	if (enable)
++		buf[1] &= ~0x40;
++	else
++		buf[1] |= 0x40;
+ 
+-	ret = (afc & 0x80) ? 65535 : 0;
++	tuner_i2c_xfer_send(&priv->i2c_props, buf, 2);
++}
++
++static void tda8295_agc2_out(struct dvb_frontend *fe, int enable)
++{
++	struct tda8290_priv *priv = fe->analog_demod_priv;
++	unsigned char set_gpio_cf[]    = { 0x44, 0x00 };
++	unsigned char set_gpio_val[]   = { 0x46, 0x00 };
++
++	tuner_i2c_xfer_send(&priv->i2c_props, &set_gpio_cf[0], 1);
++	tuner_i2c_xfer_recv(&priv->i2c_props, &set_gpio_cf[1], 1);
++	tuner_i2c_xfer_send(&priv->i2c_props, &set_gpio_val[0], 1);
++	tuner_i2c_xfer_recv(&priv->i2c_props, &set_gpio_val[1], 1);
+ 
+-	tuner_dbg("AFC status: %d\n", ret);
++	set_gpio_cf[1] &= 0xf0; /* clear GPIO_0 bits 3-0 */
+ 
+-	return ret;
++	if (enable) {
++		set_gpio_cf[1]  |= 0x01; /* config GPIO_0 as Open Drain Out */
++		set_gpio_val[1] &= 0xfe; /* set GPIO_0 pin low */
++	}
++	tuner_i2c_xfer_send(&priv->i2c_props, set_gpio_cf, 2);
++	tuner_i2c_xfer_send(&priv->i2c_props, set_gpio_val, 2);
+ }
+ 
+-static int tda8290_get_status(struct dvb_frontend *fe, u32 *status)
++static int tda8295_has_signal(struct dvb_frontend *fe)
+ {
+-	*status = 0;
++	struct tda8290_priv *priv = fe->analog_demod_priv;
+ 
+-	if (tda8290_has_signal(fe))
+-		*status = TUNER_STATUS_LOCKED;
++	unsigned char hvpll_stat = 0x26;
++	unsigned char ret;
+ 
 -	return 0;
--}
--
--void saa7134_irq_oss_done(struct saa7134_dev *dev, unsigned long status)
--{
--	int next_blk, reg = 0;
--
--	spin_lock(&dev->slock);
--	if (UNSET == dev->dmasound.dma_blk) {
--		dprintk("irq: recording stopped\n");
--		goto done;
--	}
--	if (0 != (status & 0x0f000000))
--		dprintk("irq: lost %ld\n", (status >> 24) & 0x0f);
--	if (0 == (status & 0x10000000)) {
--		/* odd */
--		if (0 == (dev->dmasound.dma_blk & 0x01))
--			reg = SAA7134_RS_BA1(6);
--	} else {
--		/* even */
--		if (1 == (dev->dmasound.dma_blk & 0x01))
--			reg = SAA7134_RS_BA2(6);
--	}
--	if (0 == reg) {
--		dprintk("irq: field oops [%s]\n",
--			(status & 0x10000000) ? "even" : "odd");
--		goto done;
--	}
--	if (dev->dmasound.read_count >= dev->dmasound.blksize * (dev->dmasound.blocks-2)) {
--		dprintk("irq: overrun [full=%d/%d]\n",dev->dmasound.read_count,
--			dev->dmasound.bufsize);
--		dsp_dma_stop(dev);
--		goto done;
--	}
--
--	/* next block addr */
--	next_blk = (dev->dmasound.dma_blk + 2) % dev->dmasound.blocks;
--	saa_writel(reg,next_blk * dev->dmasound.blksize);
--	if (debug > 2)
--		dprintk("irq: ok, %s, next_blk=%d, addr=%x\n",
--			(status & 0x10000000) ? "even" : "odd ", next_blk,
--			next_blk * dev->dmasound.blksize);
--
--	/* update status & wake waiting readers */
--	dev->dmasound.dma_blk = (dev->dmasound.dma_blk + 1) % dev->dmasound.blocks;
--	dev->dmasound.read_count += dev->dmasound.blksize;
--	wake_up(&dev->dmasound.wq);
--
-- done:
--	spin_unlock(&dev->slock);
--}
--
--static int saa7134_dsp_create(struct saa7134_dev *dev)
--{
--	int err;
--
--	err = dev->dmasound.minor_dsp =
--		register_sound_dsp(&saa7134_dsp_fops,
--				   dsp_nr[dev->nr]);
--	if (err < 0) {
--		goto fail;
--	}
--	printk(KERN_INFO "%s: registered device dsp%d\n",
--	       dev->name,dev->dmasound.minor_dsp >> 4);
--
--	err = dev->dmasound.minor_mixer =
--		register_sound_mixer(&saa7134_mixer_fops,
--				     mixer_nr[dev->nr]);
--	if (err < 0)
--		goto fail;
--	printk(KERN_INFO "%s: registered device mixer%d\n",
--	       dev->name,dev->dmasound.minor_mixer >> 4);
--
++	tuner_i2c_xfer_send(&priv->i2c_props, &hvpll_stat, 1);
++	tuner_i2c_xfer_recv(&priv->i2c_props, &ret, 1);
++	return (ret & 0x01) ? 65535 : 0;
+ }
+ 
+-static int tda8290_get_rf_strength(struct dvb_frontend *fe, u16 *strength)
++/*---------------------------------------------------------------------*/
++
++static void tda8295_set_params(struct dvb_frontend *fe,
++			       struct analog_parameters *params)
+ {
+-	*strength = tda8290_has_signal(fe);
++	struct tda8290_priv *priv = fe->analog_demod_priv;
+ 
 -	return 0;
++	unsigned char blanking_mode[]     = { 0x1d, 0x00 };
++
++	set_audio(fe, params);
++
++	tuner_dbg("%s: freq = %d\n", __FUNCTION__, params->frequency);
++
++	tda8295_power(fe, 1);
++	tda8295_agc1_out(fe, 1);
++
++	tuner_i2c_xfer_send(&priv->i2c_props, &blanking_mode[0], 1);
++	tuner_i2c_xfer_recv(&priv->i2c_props, &blanking_mode[1], 1);
++
++	tda8295_set_video_std(fe);
++
++	blanking_mode[1] = 0x03;
++	tuner_i2c_xfer_send(&priv->i2c_props, blanking_mode, 2);
++	msleep(20);
++
++	tda8295_i2c_bridge(fe, 1);
++
++	if (fe->ops.tuner_ops.set_analog_params)
++		fe->ops.tuner_ops.set_analog_params(fe, params);
++
++	if (priv->cfg.agcf)
++		priv->cfg.agcf(fe);
++
++	if (tda8295_has_signal(fe))
++		tuner_dbg("tda8295 is locked\n");
++	else
++		tuner_dbg("tda8295 not locked, no signal?\n");
++
++	tda8295_i2c_bridge(fe, 0);
++}
++
++/*---------------------------------------------------------------------*/
++
++static int tda8290_has_signal(struct dvb_frontend *fe)
++{
++	struct tda8290_priv *priv = fe->analog_demod_priv;
++
++	unsigned char i2c_get_afc[1] = { 0x1B };
++	unsigned char afc = 0;
++
++	tuner_i2c_xfer_send(&priv->i2c_props, i2c_get_afc, ARRAY_SIZE(i2c_get_afc));
++	tuner_i2c_xfer_recv(&priv->i2c_props, &afc, 1);
++	return (afc & 0x80)? 65535:0;
+ }
+ 
+ /*---------------------------------------------------------------------*/
+ 
+-static int tda8290_standby(struct dvb_frontend *fe)
++static void tda8290_standby(struct dvb_frontend *fe)
+ {
+-	struct tda8290_priv *priv = fe->tuner_priv;
++	struct tda8290_priv *priv = fe->analog_demod_priv;
++
+ 	unsigned char cb1[] = { 0x30, 0xD0 };
+ 	unsigned char tda8290_standby[] = { 0x00, 0x02 };
+ 	unsigned char tda8290_agc_tri[] = { 0x02, 0x20 };
+ 	struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags=0, .buf=cb1, .len = 2};
+ 
+ 	tda8290_i2c_bridge(fe, 1);
+-	if (priv->tda827x_ver != 0)
++	if (priv->ver & TDA8275A)
+ 		cb1[1] = 0x90;
+ 	i2c_transfer(priv->i2c_props.adap, &msg, 1);
+ 	tda8290_i2c_bridge(fe, 0);
+ 	tuner_i2c_xfer_send(&priv->i2c_props, tda8290_agc_tri, 2);
+ 	tuner_i2c_xfer_send(&priv->i2c_props, tda8290_standby, 2);
 -
--fail:
--	unregister_sound_dsp(dev->dmasound.minor_dsp);
 -	return 0;
--
--
--}
--
--static int oss_device_init(struct saa7134_dev *dev)
--{
--	dev->dmasound.priv_data = dev;
--	saa7134_oss_init1(dev);
--	saa7134_dsp_create(dev);
--	return 1;
--}
--
--static int oss_device_exit(struct saa7134_dev *dev)
--{
--
--	unregister_sound_mixer(dev->dmasound.minor_mixer);
--	unregister_sound_dsp(dev->dmasound.minor_dsp);
--
--	saa7134_oss_fini(dev);
--
--	if (dev->pci->irq > 0) {
--		synchronize_irq(dev->pci->irq);
--		free_irq(dev->pci->irq,&dev->dmasound);
--	}
--
--	dev->dmasound.priv_data = NULL;
--	return 1;
--}
--
--static int saa7134_oss_init(void)
--{
--	struct saa7134_dev *dev = NULL;
--	struct list_head *list;
--
--	if (!saa7134_dmasound_init && !saa7134_dmasound_exit) {
--		saa7134_dmasound_init = oss_device_init;
--		saa7134_dmasound_exit = oss_device_exit;
--	} else {
--		printk(KERN_WARNING "saa7134 OSS: can't load, DMA sound handler already assigned (probably to ALSA)\n");
--		return -EBUSY;
--	}
--
--	printk(KERN_INFO "saa7134 OSS driver for DMA sound loaded\n");
--
--
--	list_for_each(list,&saa7134_devlist) {
--		dev = list_entry(list, struct saa7134_dev, devlist);
--		if (dev->dmasound.priv_data == NULL) {
--			oss_device_init(dev);
--		} else {
--			printk(KERN_ERR "saa7134 OSS: DMA sound is being handled by ALSA, ignoring %s\n",dev->name);
--			return -EBUSY;
--		}
--	}
--
--	if (dev == NULL)
--		printk(KERN_INFO "saa7134 OSS: no saa7134 cards found\n");
--
+ }
+ 
++static void tda8295_standby(struct dvb_frontend *fe)
++{
++	tda8295_agc1_out(fe, 0); /* Put AGC in tri-state */
++
++	tda8295_power(fe, 0);
++}
+ 
+ static void tda8290_init_if(struct dvb_frontend *fe)
+ {
+-	struct tda8290_priv *priv = fe->tuner_priv;
++	struct tda8290_priv *priv = fe->analog_demod_priv;
+ 
+ 	unsigned char set_VS[] = { 0x30, 0x6F };
+ 	unsigned char set_GP00_CF[] = { 0x20, 0x01 };
+ 	unsigned char set_GP01_CF[] = { 0x20, 0x0B };
+ 
+-	if ((priv->lna_cfg) &&
+-	    ((*priv->lna_cfg == 1) || (*priv->lna_cfg == 2)))
++	if ((priv->cfg.config) &&
++	    ((*priv->cfg.config == 1) || (*priv->cfg.config == 2)))
+ 		tuner_i2c_xfer_send(&priv->i2c_props, set_GP00_CF, 2);
+ 	else
+ 		tuner_i2c_xfer_send(&priv->i2c_props, set_GP01_CF, 2);
+ 	tuner_i2c_xfer_send(&priv->i2c_props, set_VS, 2);
+ }
+ 
++static void tda8295_init_if(struct dvb_frontend *fe)
++{
++	struct tda8290_priv *priv = fe->analog_demod_priv;
++
++	static unsigned char set_adc_ctl[]       = { 0x33, 0x14 };
++	static unsigned char set_adc_ctl2[]      = { 0x34, 0x00 };
++	static unsigned char set_pll_reg6[]      = { 0x3e, 0x63 };
++	static unsigned char set_pll_reg0[]      = { 0x38, 0x23 };
++	static unsigned char set_pll_reg7[]      = { 0x3f, 0x01 };
++	static unsigned char set_pll_reg10[]     = { 0x42, 0x61 };
++	static unsigned char set_gpio_reg0[]     = { 0x44, 0x0b };
++
++	tda8295_power(fe, 1);
++
++	tda8295_set_easy_mode(fe, 0);
++	tda8295_set_video_std(fe);
++
++	tuner_i2c_xfer_send(&priv->i2c_props, set_adc_ctl, 2);
++	tuner_i2c_xfer_send(&priv->i2c_props, set_adc_ctl2, 2);
++	tuner_i2c_xfer_send(&priv->i2c_props, set_pll_reg6, 2);
++	tuner_i2c_xfer_send(&priv->i2c_props, set_pll_reg0, 2);
++	tuner_i2c_xfer_send(&priv->i2c_props, set_pll_reg7, 2);
++	tuner_i2c_xfer_send(&priv->i2c_props, set_pll_reg10, 2);
++	tuner_i2c_xfer_send(&priv->i2c_props, set_gpio_reg0, 2);
++
++	tda8295_agc1_out(fe, 0);
++	tda8295_agc2_out(fe, 0);
++}
++
+ static void tda8290_init_tuner(struct dvb_frontend *fe)
+ {
+-	struct tda8290_priv *priv = fe->tuner_priv;
++	struct tda8290_priv *priv = fe->analog_demod_priv;
+ 	unsigned char tda8275_init[]  = { 0x00, 0x00, 0x00, 0x40, 0xdC, 0x04, 0xAf,
+ 					  0x3F, 0x2A, 0x04, 0xFF, 0x00, 0x00, 0x40 };
+ 	unsigned char tda8275a_init[] = { 0x00, 0x00, 0x00, 0x00, 0xdC, 0x05, 0x8b,
+ 					  0x0c, 0x04, 0x20, 0xFF, 0x00, 0x00, 0x4b };
+ 	struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags=0,
+ 			      .buf=tda8275_init, .len = 14};
+-	if (priv->tda827x_ver != 0)
++	if (priv->ver & TDA8275A)
+ 		msg.buf = tda8275a_init;
+ 
+ 	tda8290_i2c_bridge(fe, 1);
+@@ -643,58 +500,42 @@ static void tda8290_init_tuner(struct dvb_frontend *fe)
+ 
+ /*---------------------------------------------------------------------*/
+ 
+-static int tda8290_release(struct dvb_frontend *fe)
++static void tda829x_release(struct dvb_frontend *fe)
+ {
+-	kfree(fe->tuner_priv);
+-	fe->tuner_priv = NULL;
++	struct tda8290_priv *priv = fe->analog_demod_priv;
+ 
 -	return 0;
--
 -}
--
--static void saa7134_oss_exit(void)
++	/* only try to release the tuner if we've
++	 * attached it from within this module */
++	if (priv->ver & (TDA18271 | TDA8275 | TDA8275A))
++		if (fe->ops.tuner_ops.release)
++			fe->ops.tuner_ops.release(fe);
+ 
+-static int tda8290_get_frequency(struct dvb_frontend *fe, u32 *frequency)
 -{
--	struct saa7134_dev *dev;
--
--	list_for_each_entry(dev, &saa7134_devlist, devlist) {
--		/* Device isn't registered by OSS, probably ALSA's */
--		if (!dev->dmasound.minor_dsp)
--			continue;
--
--		oss_device_exit(dev);
+-	struct tda8290_priv *priv = fe->tuner_priv;
+-	*frequency = priv->frequency;
+-	return 0;
++	kfree(fe->analog_demod_priv);
++	fe->analog_demod_priv = NULL;
+ }
+ 
+-static struct dvb_tuner_ops tda8290_tuner_ops = {
+-	.sleep             = tda8290_standby,
+-	.set_analog_params = tda8290_set_params,
+-	.release           = tda8290_release,
+-	.get_frequency     = tda8290_get_frequency,
+-	.get_status        = tda8290_get_status,
+-	.get_rf_strength   = tda8290_get_rf_strength,
++static struct tda18271_config tda829x_tda18271_config = {
++	.gate    = TDA18271_GATE_ANALOG,
+ };
+ 
+-struct dvb_frontend *tda8290_attach(struct dvb_frontend *fe,
+-				    struct i2c_adapter* i2c_adap,
+-				    u8 i2c_addr,
+-				    struct tda8290_config *cfg)
++static int tda829x_find_tuner(struct dvb_frontend *fe)
+ {
+-	struct tda8290_priv *priv = NULL;
+-	u8 data;
++	struct tda8290_priv *priv = fe->analog_demod_priv;
++	struct analog_demod_ops *analog_ops = &fe->ops.analog_ops;
+ 	int i, ret, tuners_found;
+ 	u32 tuner_addrs;
+-	struct i2c_msg msg = {.flags=I2C_M_RD, .buf=&data, .len = 1};
++	u8 data;
++	struct i2c_msg msg = { .flags = I2C_M_RD, .buf = &data, .len = 1 };
+ 
+-	priv = kzalloc(sizeof(struct tda8290_priv), GFP_KERNEL);
+-	if (priv == NULL)
+-		return NULL;
+-	fe->tuner_priv = priv;
++	if (NULL == analog_ops->i2c_gate_ctrl)
++		return -EINVAL;
+ 
+-	priv->i2c_props.addr = i2c_addr;
+-	priv->i2c_props.adap = i2c_adap;
+-	if (cfg) {
+-		priv->lna_cfg        = cfg->lna_cfg;
+-		priv->tuner_callback = cfg->tuner_callback;
 -	}
++	analog_ops->i2c_gate_ctrl(fe, 1);
+ 
+-	tda8290_i2c_bridge(fe, 1);
+ 	/* probe for tuner chip */
+ 	tuners_found = 0;
+ 	tuner_addrs = 0;
+-	for (i=0x60; i<= 0x63; i++) {
++	for (i = 0x60; i <= 0x63; i++) {
+ 		msg.addr = i;
+ 		ret = i2c_transfer(priv->i2c_props.adap, &msg, 1);
+ 		if (ret == 1) {
+@@ -706,20 +547,23 @@ struct dvb_frontend *tda8290_attach(struct dvb_frontend *fe,
+ 	   behind the bridge and we choose the highest address that doesn't
+ 	   give a response now
+ 	 */
+-	tda8290_i2c_bridge(fe, 0);
+-	if(tuners_found > 1)
++
++	analog_ops->i2c_gate_ctrl(fe, 0);
++
++	if (tuners_found > 1)
+ 		for (i = 0; i < tuners_found; i++) {
+ 			msg.addr = tuner_addrs  & 0xff;
+ 			ret = i2c_transfer(priv->i2c_props.adap, &msg, 1);
+-			if(ret == 1)
++			if (ret == 1)
+ 				tuner_addrs = tuner_addrs >> 8;
+ 			else
+ 				break;
+ 		}
++
+ 	if (tuner_addrs == 0) {
+-		tuner_addrs = 0x61;
+-		tuner_info("could not clearly identify tuner address, defaulting to %x\n",
+-			     tuner_addrs);
++		tuner_addrs = 0x60;
++		tuner_info("could not clearly identify tuner address, "
++			   "defaulting to %x\n", tuner_addrs);
+ 	} else {
+ 		tuner_addrs = tuner_addrs & 0xff;
+ 		tuner_info("setting tuner address to %x\n", tuner_addrs);
+@@ -727,42 +571,181 @@ struct dvb_frontend *tda8290_attach(struct dvb_frontend *fe,
+ 	priv->tda827x_addr = tuner_addrs;
+ 	msg.addr = tuner_addrs;
+ 
+-	tda8290_i2c_bridge(fe, 1);
++	analog_ops->i2c_gate_ctrl(fe, 1);
+ 	ret = i2c_transfer(priv->i2c_props.adap, &msg, 1);
+-	if( ret != 1)
+-		tuner_warn("TDA827x access failed!\n");
 -
--	saa7134_dmasound_init = NULL;
--	saa7134_dmasound_exit = NULL;
--
--	printk(KERN_INFO "saa7134 OSS driver for DMA sound unloaded\n");
--
--	return;
--}
--
--/* We initialize this late, to make sure the sound system is up and running */
--late_initcall(saa7134_oss_init);
--module_exit(saa7134_oss_exit);
--MODULE_LICENSE("GPL");
--MODULE_AUTHOR("Gerd Knorr <kraxel at bytesex.org> [SuSE Labs]");
+-	memcpy(&fe->ops.tuner_ops, &tda8290_tuner_ops,
+-	       sizeof(struct dvb_tuner_ops));
 -
--/* ----------------------------------------------------------- */
--/*
-- * Local variables:
-- * c-basic-offset: 8
-- * End:
-- */
-diff --git a/drivers/media/video/saa7134/saa7134-ts.c b/drivers/media/video/saa7134/saa7134-ts.c
-index 4b63ad3..f1b8fca 100644
---- a/drivers/media/video/saa7134/saa7134-ts.c
-+++ b/drivers/media/video/saa7134/saa7134-ts.c
-@@ -47,7 +47,7 @@ static int buffer_activate(struct saa7134_dev *dev,
- {
+-	if ((data & 0x3c) == 0) {
+-		strlcpy(fe->ops.tuner_ops.info.name, "tda8290+75",
+-			sizeof(fe->ops.tuner_ops.info.name));
+-		fe->ops.tuner_ops.info.frequency_min  =  55000000;
+-		fe->ops.tuner_ops.info.frequency_max  = 860000000;
+-		fe->ops.tuner_ops.info.frequency_step =    250000;
+-		priv->tda827x_ver = 0;
++
++	if (ret != 1) {
++		tuner_warn("tuner access failed!\n");
++		return -EREMOTEIO;
++	}
++
++	if ((data == 0x83) || (data == 0x84)) {
++		priv->ver |= TDA18271;
++		tda18271_attach(fe, priv->tda827x_addr,
++				priv->i2c_props.adap,
++				&tda829x_tda18271_config);
+ 	} else {
+-		strlcpy(fe->ops.tuner_ops.info.name, "tda8290+75a",
+-			sizeof(fe->ops.tuner_ops.info.name));
+-		fe->ops.tuner_ops.info.frequency_min  =  44000000;
+-		fe->ops.tuner_ops.info.frequency_max  = 906000000;
+-		fe->ops.tuner_ops.info.frequency_step =     62500;
+-		priv->tda827x_ver = 2;
++		if ((data & 0x3c) == 0)
++			priv->ver |= TDA8275;
++		else
++			priv->ver |= TDA8275A;
++
++		tda827x_attach(fe, priv->tda827x_addr,
++			       priv->i2c_props.adap, &priv->cfg);
++	}
++	if (fe->ops.tuner_ops.init)
++		fe->ops.tuner_ops.init(fe);
++
++	if (fe->ops.tuner_ops.sleep)
++		fe->ops.tuner_ops.sleep(fe);
++
++	analog_ops->i2c_gate_ctrl(fe, 0);
++
++	return 0;
++}
++
++static int tda8290_probe(struct tuner_i2c_props *i2c_props)
++{
++#define TDA8290_ID 0x89
++	unsigned char tda8290_id[] = { 0x1f, 0x00 };
++
++	/* detect tda8290 */
++	tuner_i2c_xfer_send(i2c_props, &tda8290_id[0], 1);
++	tuner_i2c_xfer_recv(i2c_props, &tda8290_id[1], 1);
++
++	if (tda8290_id[1] == TDA8290_ID) {
++		if (debug)
++			printk(KERN_DEBUG "%s: tda8290 detected @ %d-%04x\n",
++			       __FUNCTION__, i2c_adapter_id(i2c_props->adap),
++			       i2c_props->addr);
++		return 0;
++	}
++
++	return -ENODEV;
++}
++
++static int tda8295_probe(struct tuner_i2c_props *i2c_props)
++{
++#define TDA8295_ID 0x8a
++	unsigned char tda8295_id[] = { 0x2f, 0x00 };
++
++	/* detect tda8295 */
++	tuner_i2c_xfer_send(i2c_props, &tda8295_id[0], 1);
++	tuner_i2c_xfer_recv(i2c_props, &tda8295_id[1], 1);
++
++	if (tda8295_id[1] == TDA8295_ID) {
++		if (debug)
++			printk(KERN_DEBUG "%s: tda8295 detected @ %d-%04x\n",
++			       __FUNCTION__, i2c_adapter_id(i2c_props->adap),
++			       i2c_props->addr);
++		return 0;
+ 	}
  
- 	dprintk("buffer_activate [%p]",buf);
--	buf->vb.state = STATE_ACTIVE;
-+	buf->vb.state = VIDEOBUF_ACTIVE;
- 	buf->top_seen = 0;
+-	priv->tda827x_lpsel = 0;
++	return -ENODEV;
++}
++
++static struct analog_demod_ops tda8290_ops = {
++	.set_params     = tda8290_set_params,
++	.has_signal     = tda8290_has_signal,
++	.standby        = tda8290_standby,
++	.release        = tda829x_release,
++	.i2c_gate_ctrl  = tda8290_i2c_bridge,
++};
++
++static struct analog_demod_ops tda8295_ops = {
++	.set_params     = tda8295_set_params,
++	.has_signal     = tda8295_has_signal,
++	.standby        = tda8295_standby,
++	.release        = tda829x_release,
++	.i2c_gate_ctrl  = tda8295_i2c_bridge,
++};
++
++struct dvb_frontend *tda829x_attach(struct dvb_frontend *fe,
++				    struct i2c_adapter *i2c_adap, u8 i2c_addr,
++				    struct tda829x_config *cfg)
++{
++	struct tda8290_priv *priv = NULL;
++	char *name;
++
++	priv = kzalloc(sizeof(struct tda8290_priv), GFP_KERNEL);
++	if (priv == NULL)
++		return NULL;
++	fe->analog_demod_priv = priv;
++
++	priv->i2c_props.addr     = i2c_addr;
++	priv->i2c_props.adap     = i2c_adap;
++	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;
++		memcpy(&fe->ops.analog_ops, &tda8290_ops,
++		       sizeof(struct analog_demod_ops));
++	}
++
++	if (tda8295_probe(&priv->i2c_props) == 0) {
++		priv->ver = TDA8295;
++		memcpy(&fe->ops.analog_ops, &tda8295_ops,
++		       sizeof(struct analog_demod_ops));
++	}
++
++	if ((!(cfg) || (TDA829X_PROBE_TUNER == cfg->probe_tuner)) &&
++	    (tda829x_find_tuner(fe) < 0))
++		goto fail;
++
++	switch (priv->ver) {
++	case TDA8290:
++		name = "tda8290";
++		break;
++	case TDA8295:
++		name = "tda8295";
++		break;
++	case TDA8290 | TDA8275:
++		name = "tda8290+75";
++		break;
++	case TDA8295 | TDA8275:
++		name = "tda8295+75";
++		break;
++	case TDA8290 | TDA8275A:
++		name = "tda8290+75a";
++		break;
++	case TDA8295 | TDA8275A:
++		name = "tda8295+75a";
++		break;
++	case TDA8290 | TDA18271:
++		name = "tda8290+18271";
++		break;
++	case TDA8295 | TDA18271:
++		name = "tda8295+18271";
++		break;
++	default:
++		goto fail;
++	}
++	tuner_info("type set to %s\n", name);
++
++	fe->ops.analog_ops.info.name = name;
++
++	if (priv->ver & TDA8290) {
++		tda8290_init_tuner(fe);
++		tda8290_init_if(fe);
++	} else if (priv->ver & TDA8295)
++		tda8295_init_if(fe);
  
- 	if (NULL == next)
-@@ -91,7 +91,7 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
- 		saa7134_dma_free(q,buf);
- 	}
+-	tda8290_init_tuner(fe);
+-	tda8290_init_if(fe);
+ 	return fe;
++
++fail:
++	tda829x_release(fe);
++	return NULL;
+ }
++EXPORT_SYMBOL_GPL(tda829x_attach);
  
--	if (STATE_NEEDS_INIT == buf->vb.state) {
-+	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
- 		struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
+-int tda8290_probe(struct i2c_adapter* i2c_adap, u8 i2c_addr)
++int tda829x_probe(struct i2c_adapter *i2c_adap, u8 i2c_addr)
+ {
+ 	struct tuner_i2c_props i2c_props = {
+ 		.adap = i2c_adap,
+-		.addr = i2c_addr
++		.addr = i2c_addr,
+ 	};
  
- 		buf->vb.width  = llength;
-@@ -121,7 +121,7 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
- 	saa_writel(SAA7134_RS_PITCH(5),TS_PACKET_SIZE);
- 	saa_writel(SAA7134_RS_CONTROL(5),control);
+ 	unsigned char soft_reset[]   = { 0x00, 0x00 };
+@@ -771,7 +754,27 @@ int tda8290_probe(struct i2c_adapter* i2c_adap, u8 i2c_addr)
+ 	unsigned char restore_9886[] = { 0x00, 0xd6, 0x30 };
+ 	unsigned char addr_dto_lsb = 0x07;
+ 	unsigned char data;
++#define PROBE_BUFFER_SIZE 8
++	unsigned char buf[PROBE_BUFFER_SIZE];
++	int i;
++
++	/* rule out tda9887, which would return the same byte repeatedly */
++	tuner_i2c_xfer_send(&i2c_props, soft_reset, 1);
++	tuner_i2c_xfer_recv(&i2c_props, buf, PROBE_BUFFER_SIZE);
++	for (i = 1; i < PROBE_BUFFER_SIZE; i++) {
++		if (buf[i] != buf[0])
++			break;
++	}
  
--	buf->vb.state = STATE_PREPARED;
-+	buf->vb.state = VIDEOBUF_PREPARED;
- 	buf->activate = buffer_activate;
- 	buf->vb.field = field;
- 	return 0;
-@@ -242,7 +242,7 @@ void saa7134_irq_ts_done(struct saa7134_dev *dev, unsigned long status)
- 			if ((status & 0x100000) != 0x100000)
- 				goto done;
++	/* all bytes are equal, not a tda829x - probably a tda9887 */
++	if (i == PROBE_BUFFER_SIZE)
++		return -ENODEV;
++
++	if ((tda8290_probe(&i2c_props) == 0) ||
++	    (tda8295_probe(&i2c_props) == 0))
++		return 0;
++
++	/* fall back to old probing method */
+ 	tuner_i2c_xfer_send(&i2c_props, easy_mode_b, 2);
+ 	tuner_i2c_xfer_send(&i2c_props, soft_reset, 2);
+ 	tuner_i2c_xfer_send(&i2c_props, &addr_dto_lsb, 1);
+@@ -786,14 +789,12 @@ int tda8290_probe(struct i2c_adapter* i2c_adap, u8 i2c_addr)
  		}
--		saa7134_buffer_finish(dev,&dev->ts_q,STATE_DONE);
-+		saa7134_buffer_finish(dev,&dev->ts_q,VIDEOBUF_DONE);
  	}
- 	saa7134_buffer_next(dev,&dev->ts_q);
+ 	tuner_i2c_xfer_send(&i2c_props, restore_9886, 3);
+-	return -1;
++	return -ENODEV;
+ }
++EXPORT_SYMBOL_GPL(tda829x_probe);
  
-diff --git a/drivers/media/video/saa7134/saa7134-tvaudio.c b/drivers/media/video/saa7134/saa7134-tvaudio.c
-index f8e304c..4e98104 100644
---- a/drivers/media/video/saa7134/saa7134-tvaudio.c
-+++ b/drivers/media/video/saa7134/saa7134-tvaudio.c
-@@ -163,32 +163,6 @@ static struct saa7134_tvaudio tvaudio[] = {
+-EXPORT_SYMBOL_GPL(tda8290_probe);
+-EXPORT_SYMBOL_GPL(tda8290_attach);
+-
+-MODULE_DESCRIPTION("Philips TDA8290 + TDA8275 / TDA8275a tuner driver");
+-MODULE_AUTHOR("Gerd Knorr, Hartmut Hackmann");
++MODULE_DESCRIPTION("Philips/NXP TDA8290/TDA8295 analog IF demodulator driver");
++MODULE_AUTHOR("Gerd Knorr, Hartmut Hackmann, Michael Krufky");
+ MODULE_LICENSE("GPL");
  
- /* ------------------------------------------------------------------ */
+ /*
+diff --git a/drivers/media/video/tda8290.h b/drivers/media/video/tda8290.h
+index 107b24b..dc8ef31 100644
+--- a/drivers/media/video/tda8290.h
++++ b/drivers/media/video/tda8290.h
+@@ -20,33 +20,36 @@
+ #include <linux/i2c.h>
+ #include "dvb_frontend.h"
  
--static void tvaudio_init(struct saa7134_dev *dev)
+-struct tda8290_config
 -{
--	int clock = saa7134_boards[dev->board].audio_clock;
--
--	if (UNSET != audio_clock_override)
--		clock = audio_clock_override;
--
--	/* init all audio registers */
--	saa_writeb(SAA7134_AUDIO_PLL_CTRL,   0x00);
--	if (need_resched())
--		schedule();
--	else
--		udelay(10);
--
--	saa_writeb(SAA7134_AUDIO_CLOCK0,      clock        & 0xff);
--	saa_writeb(SAA7134_AUDIO_CLOCK1,     (clock >>  8) & 0xff);
--	saa_writeb(SAA7134_AUDIO_CLOCK2,     (clock >> 16) & 0xff);
--	/* frame locked audio is mandatory for NICAM */
--	saa_writeb(SAA7134_AUDIO_PLL_CTRL,   0x01);
--
--	saa_writeb(SAA7134_NICAM_ERROR_LOW,  0x14);
--	saa_writeb(SAA7134_NICAM_ERROR_HIGH, 0x50);
--	saa_writeb(SAA7134_MONITOR_SELECT,   0xa0);
--	saa_writeb(SAA7134_FM_DEMATRIX,      0x80);
--}
--
- static u32 tvaudio_carr2reg(u32 carrier)
++struct tda829x_config {
+ 	unsigned int *lna_cfg;
+-	int (*tuner_callback) (void *dev, int command,int arg);
++	int (*tuner_callback) (void *dev, int command, int arg);
++
++	unsigned int probe_tuner:1;
++#define TDA829X_PROBE_TUNER 0
++#define TDA829X_DONT_PROBE  1
+ };
+ 
+ #if defined(CONFIG_TUNER_TDA8290) || (defined(CONFIG_TUNER_TDA8290_MODULE) && defined(MODULE))
+-extern int tda8290_probe(struct i2c_adapter* i2c_adap, u8 i2c_addr);
++extern int tda829x_probe(struct i2c_adapter *i2c_adap, u8 i2c_addr);
+ 
+-extern struct dvb_frontend *tda8290_attach(struct dvb_frontend *fe,
+-					   struct i2c_adapter* i2c_adap,
++extern struct dvb_frontend *tda829x_attach(struct dvb_frontend *fe,
++					   struct i2c_adapter *i2c_adap,
+ 					   u8 i2c_addr,
+-					   struct tda8290_config *cfg);
++					   struct tda829x_config *cfg);
+ #else
+-static inline int tda8290_probe(struct i2c_adapter* i2c_adap, u8 i2c_addr)
++static inline int tda829x_probe(struct i2c_adapter *i2c_adap, u8 i2c_addr)
  {
- 	u64 a = carrier;
-@@ -517,9 +491,13 @@ static int tvaudio_thread(void *data)
- 		dev->thread.scan1 = dev->thread.scan2;
- 		dprintk("tvaudio thread scan start [%d]\n",dev->thread.scan1);
- 		dev->tvaudio  = NULL;
--		tvaudio_init(dev);
+-	printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n",
+-	       __FUNCTION__);
++	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+ 	return -EINVAL;
+ }
+ 
+-static inline struct dvb_frontend *tda8290_attach(struct dvb_frontend *fe,
+-						  struct i2c_adapter* i2c_adap,
++static inline struct dvb_frontend *tda829x_attach(struct dvb_frontend *fe,
++						  struct i2c_adapter *i2c_adap,
+ 						  u8 i2c_addr,
+-						  struct tda8290_config *cfg)
++						  struct tda829x_config *cfg)
+ {
+-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
++	printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n",
++	       __FUNCTION__);
+ 	return NULL;
+ }
+ #endif
+diff --git a/drivers/media/video/tda9875.c b/drivers/media/video/tda9875.c
+index d110441..3c05571 100644
+--- a/drivers/media/video/tda9875.c
++++ b/drivers/media/video/tda9875.c
+@@ -7,6 +7,7 @@
+  *
+  * Copyright (c) 2000 Guillaume Delvit based on Gerd Knorr source and
+  * Eric Sandeen
++ * Copyright (c) 2006 Mauro Carvalho Chehab <mchehab at infradead.org>
+  * This code is placed under the terms of the GNU General Public License
+  * Based on tda9855.c by Steve VanDeBogart (vandebo at uclink.berkeley.edu)
+  * Which was based on tda8425.c by Greg Alexander (c) 1998
+@@ -268,87 +269,143 @@ static int tda9875_detach(struct i2c_client *client)
+ 	return 0;
+ }
+ 
+-static int tda9875_command(struct i2c_client *client,
+-				unsigned int cmd, void *arg)
++static int tda9875_get_ctrl(struct i2c_client *client,
++			    struct v4l2_control *ctrl)
+ {
+ 	struct tda9875 *t = i2c_get_clientdata(client);
+ 
+-	dprintk("In tda9875_command...\n");
++	switch (ctrl->id) {
++	case V4L2_CID_AUDIO_VOLUME:
++	{
++		int left = (t->lvol+84)*606;
++		int right = (t->rvol+84)*606;
+ 
+-	switch (cmd) {
+-	/* --- v4l ioctls --- */
+-	/* take care: bttv does userspace copying, we'll get a
+-	   kernel pointer here... */
+-	case VIDIOCGAUDIO:
++		ctrl->value=max(left,right);
++		return 0;
++	}
++	case V4L2_CID_AUDIO_BALANCE:
+ 	{
+-		struct video_audio *va = arg;
+-		int left,right;
++		int left = (t->lvol+84)*606;
++		int right = (t->rvol+84)*606;
++		int volume = max(left,right);
++		int balance = (32768*min(left,right))/
++			      (volume ? volume : 1);
++		ctrl->value=(left<right)?
++			(65535-balance) : balance;
++		return 0;
++	}
++	case V4L2_CID_AUDIO_BASS:
++		ctrl->value = (t->bass+12)*2427;    /* min -12 max +15 */
++		return 0;
++	case V4L2_CID_AUDIO_TREBLE:
++		ctrl->value = (t->treble+12)*2730;/* min -12 max +12 */
++		return 0;
++	}
++	return -EINVAL;
++}
+ 
+-		dprintk("VIDIOCGAUDIO\n");
++static int tda9875_set_ctrl(struct i2c_client *client,
++			    struct v4l2_control *ctrl)
++{
++	struct tda9875 *t = i2c_get_clientdata(client);
++	int chvol=0, volume, balance, left, right;
+ 
+-		va->flags |= VIDEO_AUDIO_VOLUME |
+-			VIDEO_AUDIO_BASS |
+-			VIDEO_AUDIO_TREBLE;
++	switch (ctrl->id) {
++	case V4L2_CID_AUDIO_VOLUME:
++		left = (t->lvol+84)*606;
++		right = (t->rvol+84)*606;
 +
-+		saa_writeb(SAA7134_MONITOR_SELECT,   0xa0);
-+		saa_writeb(SAA7134_FM_DEMATRIX,      0x80);
++		volume = max(left,right);
++		balance = (32768*min(left,right))/
++			      (volume ? volume : 1);
++		balance =(left<right)?
++			(65535-balance) : balance;
 +
- 		if (dev->ctl_automute)
- 			dev->automute = 1;
++		volume = ctrl->value;
+ 
+-		/* min is -84 max is 24 */
++		chvol=1;
++		break;
++	case V4L2_CID_AUDIO_BALANCE:
+ 		left = (t->lvol+84)*606;
+ 		right = (t->rvol+84)*606;
+-		va->volume=max(left,right);
+-		va->balance=(32768*min(left,right))/
+-			(va->volume ? va->volume : 1);
+-		va->balance=(left<right)?
+-			(65535-va->balance) : va->balance;
+-		va->bass = (t->bass+12)*2427;    /* min -12 max +15 */
+-		va->treble = (t->treble+12)*2730;/* min -12 max +12 */
+-		va->mode |= VIDEO_SOUND_MONO;
+-
+-		break; /* VIDIOCGAUDIO case */
++
++		volume=max(left,right);
 +
- 		mute_input_7134(dev);
- 
- 		/* give the tuner some time */
-@@ -784,27 +762,15 @@ static int mute_input_7133(struct saa7134_dev *dev)
- static int tvaudio_thread_ddep(void *data)
- {
- 	struct saa7134_dev *dev = data;
--	u32 value, norms, clock;
-+	u32 value, norms;
- 
++		balance = ctrl->value;
++
++		chvol=1;
++		break;
++	case V4L2_CID_AUDIO_BASS:
++		t->bass = ((ctrl->value/2400)-12) & 0xff;
++		if (t->bass > 15)
++			t->bass = 15;
++		if (t->bass < -12)
++			t->bass = -12 & 0xff;
++		break;
++	case V4L2_CID_AUDIO_TREBLE:
++		t->treble = ((ctrl->value/2700)-12) & 0xff;
++		if (t->treble > 12)
++			t->treble = 12;
++		if (t->treble < -12)
++			t->treble = -12 & 0xff;
++		break;
++	default:
++		return -EINVAL;
+ 	}
  
- 	set_freezable();
--
--	clock = saa7134_boards[dev->board].audio_clock;
--	if (UNSET != audio_clock_override)
--		clock = audio_clock_override;
--	saa_writel(0x598 >> 2, clock);
--
--	/* unmute */
--	saa_dsp_writel(dev, 0x474 >> 2, 0x00);
--	saa_dsp_writel(dev, 0x450 >> 2, 0x00);
+-	case VIDIOCSAUDIO:
+-	{
+-		struct video_audio *va = arg;
+-		int left,right;
 -
- 	for (;;) {
- 		tvaudio_sleep(dev,-1);
- 		if (kthread_should_stop())
- 			goto done;
+-		dprintk("VIDEOCSAUDIO...\n");
+-		left = (min(65536 - va->balance,32768) *
+-			va->volume) / 32768;
+-		right = (min(va->balance,(__u16)32768) *
+-			 va->volume) / 32768;
++	if (chvol) {
++		left = (min(65536 - balance,32768) *
++			volume) / 32768;
++		right = (min(balance,32768) *
++				volume) / 32768;
+ 		t->lvol = ((left/606)-84) & 0xff;
+ 		if (t->lvol > 24)
+-		 t->lvol = 24;
++			t->lvol = 24;
+ 		if (t->lvol < -84)
+-		 t->lvol = -84 & 0xff;
++			t->lvol = -84 & 0xff;
+ 
+ 		t->rvol = ((right/606)-84) & 0xff;
+ 		if (t->rvol > 24)
+-		 t->rvol = 24;
++			t->rvol = 24;
+ 		if (t->rvol < -84)
+-		 t->rvol = -84 & 0xff;
 -
- 	restart:
+-		t->bass = ((va->bass/2400)-12) & 0xff;
+-		if (t->bass > 15)
+-		 t->bass = 15;
+-		if (t->bass < -12)
+-		 t->bass = -12 & 0xff;
 -
- 		try_to_freeze();
+-		t->treble = ((va->treble/2700)-12) & 0xff;
+-		if (t->treble > 12)
+-		 t->treble = 12;
+-		if (t->treble < -12)
+-		 t->treble = -12 & 0xff;
++			t->rvol = -84 & 0xff;
++	}
  
- 		dev->thread.scan1 = dev->thread.scan2;
-@@ -978,6 +944,38 @@ int saa7134_tvaudio_getstereo(struct saa7134_dev *dev)
- 	return retval;
- }
++//printk("tda9875 bal:%04x vol:%04x bass:%04x treble:%04x\n",va->balance,va->volume,va->bass,va->treble);
  
-+void saa7134_tvaudio_init(struct saa7134_dev *dev)
-+{
-+	int clock = saa7134_boards[dev->board].audio_clock;
-+
-+	if (UNSET != audio_clock_override)
-+		clock = audio_clock_override;
-+
-+	switch (dev->pci->device) {
-+	case PCI_DEVICE_ID_PHILIPS_SAA7134:
-+		/* init all audio registers */
-+		saa_writeb(SAA7134_AUDIO_PLL_CTRL,   0x00);
-+		if (need_resched())
-+			schedule();
-+		else
-+			udelay(10);
-+
-+		saa_writeb(SAA7134_AUDIO_CLOCK0,      clock        & 0xff);
-+		saa_writeb(SAA7134_AUDIO_CLOCK1,     (clock >>  8) & 0xff);
-+		saa_writeb(SAA7134_AUDIO_CLOCK2,     (clock >> 16) & 0xff);
-+		/* frame locked audio is mandatory for NICAM */
-+		saa_writeb(SAA7134_AUDIO_PLL_CTRL,   0x01);
-+		saa_writeb(SAA7134_NICAM_ERROR_LOW,  0x14);
-+		saa_writeb(SAA7134_NICAM_ERROR_HIGH, 0x50);
-+		break;
-+	case PCI_DEVICE_ID_PHILIPS_SAA7133:
-+	case PCI_DEVICE_ID_PHILIPS_SAA7135:
-+		saa_writel(0x598 >> 2, clock);
-+		saa_dsp_writel(dev, 0x474 >> 2, 0x00);
-+		saa_dsp_writel(dev, 0x450 >> 2, 0x00);
-+	}
++	tda9875_set(client);
+ 
+-//printk("tda9875 bal:%04x vol:%04x bass:%04x treble:%04x\n",va->balance,va->volume,va->bass,va->treble);
++	return 0;
 +}
-+
- int saa7134_tvaudio_init2(struct saa7134_dev *dev)
- {
- 	int (*my_thread)(void *data) = NULL;
-@@ -994,6 +992,7 @@ int saa7134_tvaudio_init2(struct saa7134_dev *dev)
  
- 	dev->thread.thread = NULL;
- 	if (my_thread) {
-+		saa7134_tvaudio_init(dev);
- 		/* start tvaudio thread */
- 		dev->thread.thread = kthread_run(my_thread, dev, "%s", dev->name);
- 		if (IS_ERR(dev->thread.thread)) {
-diff --git a/drivers/media/video/saa7134/saa7134-vbi.c b/drivers/media/video/saa7134/saa7134-vbi.c
-index 81a2aed..f0d5ed9 100644
---- a/drivers/media/video/saa7134/saa7134-vbi.c
-+++ b/drivers/media/video/saa7134/saa7134-vbi.c
-@@ -85,7 +85,7 @@ static int buffer_activate(struct saa7134_dev *dev,
- 	unsigned long control,base;
  
- 	dprintk("buffer_activate [%p]\n",buf);
--	buf->vb.state = STATE_ACTIVE;
-+	buf->vb.state = VIDEOBUF_ACTIVE;
- 	buf->top_seen = 0;
+-		tda9875_set(client);
++static int tda9875_command(struct i2c_client *client,
++				unsigned int cmd, void *arg)
++{
++	dprintk("In tda9875_command...\n");
  
- 	task_init(dev,buf,TASK_A);
-@@ -136,7 +136,7 @@ static int buffer_prepare(struct videobuf_queue *q,
- 	if (buf->vb.size != size)
- 		saa7134_dma_free(q,buf);
+-		break;
++	switch (cmd) {
++	/* --- v4l ioctls --- */
++	/* take care: bttv does userspace copying, we'll get a
++	   kernel pointer here... */
++	case VIDIOC_QUERYCTRL:
++	{
++		struct v4l2_queryctrl *qc = arg;
++
++		switch (qc->id) {
++			case V4L2_CID_AUDIO_VOLUME:
++			case V4L2_CID_AUDIO_BASS:
++			case V4L2_CID_AUDIO_TREBLE:
++			default:
++				return -EINVAL;
++		}
++		return v4l2_ctrl_query_fill_std(qc);
++	}
++	case VIDIOC_S_CTRL:
++		return tda9875_set_ctrl(client, arg);
  
--	if (STATE_NEEDS_INIT == buf->vb.state) {
-+	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
- 		struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
+-	} /* end of VIDEOCSAUDIO case */
++	case VIDIOC_G_CTRL:
++		return tda9875_get_ctrl(client, arg);
  
- 		buf->vb.width  = llength;
-@@ -154,7 +154,7 @@ static int buffer_prepare(struct videobuf_queue *q,
- 		if (err)
- 			goto oops;
- 	}
--	buf->vb.state = STATE_PREPARED;
-+	buf->vb.state = VIDEOBUF_PREPARED;
- 	buf->activate = buffer_activate;
- 	buf->vb.field = field;
- 	return 0;
-@@ -240,7 +240,7 @@ void saa7134_irq_vbi_done(struct saa7134_dev *dev, unsigned long status)
- 			goto done;
+ 	default: /* Not VIDEOCGAUDIO or VIDEOCSAUDIO */
  
- 		dev->vbi_q.curr->vb.field_count = dev->vbi_fieldcount;
--		saa7134_buffer_finish(dev,&dev->vbi_q,STATE_DONE);
-+		saa7134_buffer_finish(dev,&dev->vbi_q,VIDEOBUF_DONE);
- 	}
- 	saa7134_buffer_next(dev,&dev->vbi_q);
+diff --git a/drivers/media/video/tda9887.c b/drivers/media/video/tda9887.c
+index be5387f..106c93b 100644
+--- a/drivers/media/video/tda9887.c
++++ b/drivers/media/video/tda9887.c
+@@ -9,7 +9,8 @@
+ #include <linux/videodev.h>
+ #include <media/v4l2-common.h>
+ #include <media/tuner.h>
+-#include "tuner-driver.h"
++#include "tuner-i2c.h"
++#include "tda9887.h"
  
-diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c
-index 6396d9b..1184d35 100644
---- a/drivers/media/video/saa7134/saa7134-video.c
-+++ b/drivers/media/video/saa7134/saa7134-video.c
-@@ -38,7 +38,7 @@
  
- /* ------------------------------------------------------------------ */
+ /* Chips:
+@@ -20,18 +21,20 @@
+    Used as part of several tuners
+ */
  
--static unsigned int video_debug   = 0;
-+unsigned int video_debug;
- static unsigned int gbuffers      = 8;
- static unsigned int noninterlaced = 0;
- static unsigned int gbufsize      = 720*576*4;
-@@ -54,7 +54,7 @@ module_param_string(secam, secam, sizeof(secam), 0644);
- MODULE_PARM_DESC(secam, "force SECAM variant, either DK,L or Lc");
+-#define tda9887_info(fmt, arg...) do {\
+-	printk(KERN_INFO "%s %d-%04x: " fmt, t->i2c.name, \
+-			i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0)
+-#define tda9887_dbg(fmt, arg...) do {\
+-	if (tuner_debug) \
+-		printk(KERN_INFO "%s %d-%04x: " fmt, t->i2c.name, \
+-			i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0)
++static int debug;
++module_param(debug, int, 0644);
++MODULE_PARM_DESC(debug, "enable verbose debug messages");
++
++#define PREFIX "tda9887"
  
+ struct tda9887_priv {
+ 	struct tuner_i2c_props i2c_props;
  
--#define dprintk(fmt, arg...)	if (video_debug) \
-+#define dprintk(fmt, arg...)	if (video_debug&0x04) \
- 	printk(KERN_DEBUG "%s/video: " fmt, dev->name , ## arg)
+ 	unsigned char 	   data[4];
++	unsigned int       config;
++	unsigned int       mode;
++	unsigned int       audmode;
++	v4l2_std_id        std;
+ };
  
- /* ------------------------------------------------------------------ */
-@@ -540,9 +540,8 @@ void res_free(struct saa7134_dev *dev, struct saa7134_fh *fh, unsigned int bits)
+ /* ---------------------------------------------------------------------- */
+@@ -262,8 +265,10 @@ static struct tvnorm radio_mono = {
  
- /* ------------------------------------------------------------------ */
+ /* ---------------------------------------------------------------------- */
  
--void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm)
-+static void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm)
+-static void dump_read_message(struct tuner *t, unsigned char *buf)
++static void dump_read_message(struct dvb_frontend *fe, unsigned char *buf)
  {
--
- 	dprintk("set tv norm = %s\n",norm->name);
- 	dev->tvnorm = norm;
++	struct tda9887_priv *priv = fe->analog_demod_priv;
++
+ 	static char *afc[16] = {
+ 		"- 12.5 kHz",
+ 		"- 37.5 kHz",
+@@ -282,16 +287,18 @@ static void dump_read_message(struct tuner *t, unsigned char *buf)
+ 		"+ 37.5 kHz",
+ 		"+ 12.5 kHz",
+ 	};
+-	tda9887_info("read: 0x%2x\n", buf[0]);
+-	tda9887_info("  after power on : %s\n", (buf[0] & 0x01) ? "yes" : "no");
+-	tda9887_info("  afc            : %s\n", afc[(buf[0] >> 1) & 0x0f]);
+-	tda9887_info("  fmif level     : %s\n", (buf[0] & 0x20) ? "high" : "low");
+-	tda9887_info("  afc window     : %s\n", (buf[0] & 0x40) ? "in" : "out");
+-	tda9887_info("  vfi level      : %s\n", (buf[0] & 0x80) ? "high" : "low");
++	tuner_info("read: 0x%2x\n", buf[0]);
++	tuner_info("  after power on : %s\n", (buf[0] & 0x01) ? "yes" : "no");
++	tuner_info("  afc            : %s\n", afc[(buf[0] >> 1) & 0x0f]);
++	tuner_info("  fmif level     : %s\n", (buf[0] & 0x20) ? "high" : "low");
++	tuner_info("  afc window     : %s\n", (buf[0] & 0x40) ? "in" : "out");
++	tuner_info("  vfi level      : %s\n", (buf[0] & 0x80) ? "high" : "low");
+ }
  
-@@ -561,7 +560,6 @@ void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm)
- 	dev->crop_current = dev->crop_defrect;
+-static void dump_write_message(struct tuner *t, unsigned char *buf)
++static void dump_write_message(struct dvb_frontend *fe, unsigned char *buf)
+ {
++	struct tda9887_priv *priv = fe->analog_demod_priv;
++
+ 	static char *sound[4] = {
+ 		"AM/TV",
+ 		"FM/radio",
+@@ -330,86 +337,90 @@ static void dump_write_message(struct tuner *t, unsigned char *buf)
+ 		"44 MHz",
+ 	};
  
- 	saa7134_set_tvnorm_hw(dev);
+-	tda9887_info("write: byte B 0x%02x\n",buf[1]);
+-	tda9887_info("  B0   video mode      : %s\n",
+-	       (buf[1] & 0x01) ? "video trap" : "sound trap");
+-	tda9887_info("  B1   auto mute fm    : %s\n",
+-	       (buf[1] & 0x02) ? "yes" : "no");
+-	tda9887_info("  B2   carrier mode    : %s\n",
+-	       (buf[1] & 0x04) ? "QSS" : "Intercarrier");
+-	tda9887_info("  B3-4 tv sound/radio  : %s\n",
+-	       sound[(buf[1] & 0x18) >> 3]);
+-	tda9887_info("  B5   force mute audio: %s\n",
+-	       (buf[1] & 0x20) ? "yes" : "no");
+-	tda9887_info("  B6   output port 1   : %s\n",
+-	       (buf[1] & 0x40) ? "high (inactive)" : "low (active)");
+-	tda9887_info("  B7   output port 2   : %s\n",
+-	       (buf[1] & 0x80) ? "high (inactive)" : "low (active)");
+-
+-	tda9887_info("write: byte C 0x%02x\n",buf[2]);
+-	tda9887_info("  C0-4 top adjustment  : %s dB\n", adjust[buf[2] & 0x1f]);
+-	tda9887_info("  C5-6 de-emphasis     : %s\n", deemph[(buf[2] & 0x60) >> 5]);
+-	tda9887_info("  C7   audio gain      : %s\n",
+-	       (buf[2] & 0x80) ? "-6" : "0");
 -
+-	tda9887_info("write: byte E 0x%02x\n",buf[3]);
+-	tda9887_info("  E0-1 sound carrier   : %s\n",
+-	       carrier[(buf[3] & 0x03)]);
+-	tda9887_info("  E6   l pll gating   : %s\n",
+-	       (buf[3] & 0x40) ? "36" : "13");
++	tuner_info("write: byte B 0x%02x\n", buf[1]);
++	tuner_info("  B0   video mode      : %s\n",
++		   (buf[1] & 0x01) ? "video trap" : "sound trap");
++	tuner_info("  B1   auto mute fm    : %s\n",
++		   (buf[1] & 0x02) ? "yes" : "no");
++	tuner_info("  B2   carrier mode    : %s\n",
++		   (buf[1] & 0x04) ? "QSS" : "Intercarrier");
++	tuner_info("  B3-4 tv sound/radio  : %s\n",
++		   sound[(buf[1] & 0x18) >> 3]);
++	tuner_info("  B5   force mute audio: %s\n",
++		   (buf[1] & 0x20) ? "yes" : "no");
++	tuner_info("  B6   output port 1   : %s\n",
++		   (buf[1] & 0x40) ? "high (inactive)" : "low (active)");
++	tuner_info("  B7   output port 2   : %s\n",
++		   (buf[1] & 0x80) ? "high (inactive)" : "low (active)");
++
++	tuner_info("write: byte C 0x%02x\n", buf[2]);
++	tuner_info("  C0-4 top adjustment  : %s dB\n",
++		   adjust[buf[2] & 0x1f]);
++	tuner_info("  C5-6 de-emphasis     : %s\n",
++		   deemph[(buf[2] & 0x60) >> 5]);
++	tuner_info("  C7   audio gain      : %s\n",
++		   (buf[2] & 0x80) ? "-6" : "0");
++
++	tuner_info("write: byte E 0x%02x\n", buf[3]);
++	tuner_info("  E0-1 sound carrier   : %s\n",
++		   carrier[(buf[3] & 0x03)]);
++	tuner_info("  E6   l pll gating   : %s\n",
++		   (buf[3] & 0x40) ? "36" : "13");
+ 
+ 	if (buf[1] & 0x08) {
+ 		/* radio */
+-		tda9887_info("  E2-4 video if        : %s\n",
+-		       rif[(buf[3] & 0x0c) >> 2]);
+-		tda9887_info("  E7   vif agc output  : %s\n",
+-		       (buf[3] & 0x80)
+-		       ? ((buf[3] & 0x10) ? "fm-agc radio" : "sif-agc radio")
+-		       : "fm radio carrier afc");
++		tuner_info("  E2-4 video if        : %s\n",
++			   rif[(buf[3] & 0x0c) >> 2]);
++		tuner_info("  E7   vif agc output  : %s\n",
++			   (buf[3] & 0x80)
++			   ? ((buf[3] & 0x10) ? "fm-agc radio" :
++						"sif-agc radio")
++			   : "fm radio carrier afc");
+ 	} else {
+ 		/* video */
+-		tda9887_info("  E2-4 video if        : %s\n",
+-		       vif[(buf[3] & 0x1c) >> 2]);
+-		tda9887_info("  E5   tuner gain      : %s\n",
+-		       (buf[3] & 0x80)
+-		       ? ((buf[3] & 0x20) ? "external" : "normal")
+-		       : ((buf[3] & 0x20) ? "minimum"  : "normal"));
+-		tda9887_info("  E7   vif agc output  : %s\n",
+-		       (buf[3] & 0x80)
+-		       ? ((buf[3] & 0x20)
+-			  ? "pin3 port, pin22 vif agc out"
+-			  : "pin22 port, pin3 vif acg ext in")
+-		       : "pin3+pin22 port");
++		tuner_info("  E2-4 video if        : %s\n",
++			   vif[(buf[3] & 0x1c) >> 2]);
++		tuner_info("  E5   tuner gain      : %s\n",
++			   (buf[3] & 0x80)
++			   ? ((buf[3] & 0x20) ? "external" : "normal")
++			   : ((buf[3] & 0x20) ? "minimum"  : "normal"));
++		tuner_info("  E7   vif agc output  : %s\n",
++			   (buf[3] & 0x80) ? ((buf[3] & 0x20)
++				? "pin3 port, pin22 vif agc out"
++				: "pin22 port, pin3 vif acg ext in")
++				: "pin3+pin22 port");
+ 	}
+-	tda9887_info("--\n");
++	tuner_info("--\n");
  }
  
- static void video_mux(struct saa7134_dev *dev, int input)
-@@ -945,7 +943,7 @@ static int buffer_activate(struct saa7134_dev *dev,
- 	unsigned long bpl_uv,lines_uv,base2,base3,tmp; /* planar */
+ /* ---------------------------------------------------------------------- */
  
- 	dprintk("buffer_activate buf=%p\n",buf);
--	buf->vb.state = STATE_ACTIVE;
-+	buf->vb.state = VIDEOBUF_ACTIVE;
- 	buf->top_seen = 0;
+-static int tda9887_set_tvnorm(struct tuner *t, char *buf)
++static int tda9887_set_tvnorm(struct dvb_frontend *fe)
+ {
++	struct tda9887_priv *priv = fe->analog_demod_priv;
+ 	struct tvnorm *norm = NULL;
++	char *buf = priv->data;
+ 	int i;
  
- 	set_size(dev,TASK_A,buf->vb.width,buf->vb.height,
-@@ -1054,7 +1052,7 @@ static int buffer_prepare(struct videobuf_queue *q,
- 		saa7134_dma_free(q,buf);
+-	if (t->mode == V4L2_TUNER_RADIO) {
+-		if (t->audmode == V4L2_TUNER_MODE_MONO)
++	if (priv->mode == V4L2_TUNER_RADIO) {
++		if (priv->audmode == V4L2_TUNER_MODE_MONO)
+ 			norm = &radio_mono;
+ 		else
+ 			norm = &radio_stereo;
+ 	} else {
+ 		for (i = 0; i < ARRAY_SIZE(tvnorms); i++) {
+-			if (tvnorms[i].std & t->std) {
++			if (tvnorms[i].std & priv->std) {
+ 				norm = tvnorms+i;
+ 				break;
+ 			}
+ 		}
  	}
- 
--	if (STATE_NEEDS_INIT == buf->vb.state) {
-+	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
- 		struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
- 
- 		buf->vb.width  = fh->width;
-@@ -1074,7 +1072,7 @@ static int buffer_prepare(struct videobuf_queue *q,
- 		if (err)
- 			goto oops;
+ 	if (NULL == norm) {
+-		tda9887_dbg("Unsupported tvnorm entry - audio muted\n");
++		tuner_dbg("Unsupported tvnorm entry - audio muted\n");
+ 		return -1;
  	}
--	buf->vb.state = STATE_PREPARED;
-+	buf->vb.state = VIDEOBUF_PREPARED;
- 	buf->activate = buffer_activate;
- 	return 0;
- 
-@@ -1119,8 +1117,10 @@ static struct videobuf_queue_ops video_qops = {
  
- /* ------------------------------------------------------------------ */
+-	tda9887_dbg("configure for: %s\n",norm->name);
++	tuner_dbg("configure for: %s\n", norm->name);
+ 	buf[1] = norm->b;
+ 	buf[2] = norm->c;
+ 	buf[3] = norm->e;
+@@ -426,8 +437,11 @@ module_param(port2, int, 0644);
+ module_param(qss, int, 0644);
+ module_param(adjust, int, 0644);
  
--static int get_control(struct saa7134_dev *dev, struct v4l2_control *c)
-+int saa7134_g_ctrl(struct file *file, void *priv, struct v4l2_control *c)
+-static int tda9887_set_insmod(struct tuner *t, char *buf)
++static int tda9887_set_insmod(struct dvb_frontend *fe)
  {
-+	struct saa7134_fh *fh = priv;
-+	struct saa7134_dev *dev = fh->dev;
- 	const struct v4l2_queryctrl* ctrl;
- 
- 	ctrl = ctrl_by_id(c->id);
-@@ -1165,17 +1165,27 @@ static int get_control(struct saa7134_dev *dev, struct v4l2_control *c)
- 	}
++	struct tda9887_priv *priv = fe->analog_demod_priv;
++	char *buf = priv->data;
++
+ 	if (UNSET != port1) {
+ 		if (port1)
+ 			buf[1] |= cOutputPort1Inactive;
+@@ -455,27 +469,30 @@ static int tda9887_set_insmod(struct tuner *t, char *buf)
  	return 0;
  }
-+EXPORT_SYMBOL_GPL(saa7134_g_ctrl);
  
--static int set_control(struct saa7134_dev *dev, struct saa7134_fh *fh,
--		       struct v4l2_control *c)
-+int saa7134_s_ctrl(struct file *file, void *f, struct v4l2_control *c)
+-static int tda9887_set_config(struct tuner *t, char *buf)
++static int tda9887_do_config(struct dvb_frontend *fe)
  {
- 	const struct v4l2_queryctrl* ctrl;
-+	struct saa7134_fh *fh = f;
-+	struct saa7134_dev *dev = fh->dev;
- 	unsigned long flags;
- 	int restart_overlay = 0;
-+	int err = -EINVAL;
-+
-+	err = v4l2_prio_check(&dev->prio, &fh->prio);
-+	if (0 != err)
-+		return err;
+-	if (t->tda9887_config & TDA9887_PORT1_ACTIVE)
++	struct tda9887_priv *priv = fe->analog_demod_priv;
++	char *buf = priv->data;
 +
-+	mutex_lock(&dev->lock);
++	if (priv->config & TDA9887_PORT1_ACTIVE)
+ 		buf[1] &= ~cOutputPort1Inactive;
+-	if (t->tda9887_config & TDA9887_PORT1_INACTIVE)
++	if (priv->config & TDA9887_PORT1_INACTIVE)
+ 		buf[1] |= cOutputPort1Inactive;
+-	if (t->tda9887_config & TDA9887_PORT2_ACTIVE)
++	if (priv->config & TDA9887_PORT2_ACTIVE)
+ 		buf[1] &= ~cOutputPort2Inactive;
+-	if (t->tda9887_config & TDA9887_PORT2_INACTIVE)
++	if (priv->config & TDA9887_PORT2_INACTIVE)
+ 		buf[1] |= cOutputPort2Inactive;
  
- 	ctrl = ctrl_by_id(c->id);
- 	if (NULL == ctrl)
--		return -EINVAL;
-+		goto error;
-+
- 	dprintk("set_control name=%s val=%d\n",ctrl->name,c->value);
- 	switch (ctrl->type) {
- 	case V4L2_CTRL_TYPE_BOOLEAN:
-@@ -1236,18 +1246,26 @@ static int set_control(struct saa7134_dev *dev, struct saa7134_fh *fh,
- 		restart_overlay = 1;
- 		break;
- 	case V4L2_CID_PRIVATE_AUTOMUTE:
-+	{
-+		struct v4l2_priv_tun_config tda9887_cfg;
-+
-+		tda9887_cfg.tuner = TUNER_TDA9887;
-+		tda9887_cfg.priv = &dev->tda9887_conf;
-+
- 		dev->ctl_automute = c->value;
- 		if (dev->tda9887_conf) {
- 			if (dev->ctl_automute)
- 				dev->tda9887_conf |= TDA9887_AUTOMUTE;
- 			else
- 				dev->tda9887_conf &= ~TDA9887_AUTOMUTE;
--			saa7134_i2c_call_clients(dev, TDA9887_SET_CONFIG,
--						 &dev->tda9887_conf);
-+
-+			saa7134_i2c_call_clients(dev, TUNER_SET_CONFIG,
-+						 &tda9887_cfg);
+-	if (t->tda9887_config & TDA9887_QSS)
++	if (priv->config & TDA9887_QSS)
+ 		buf[1] |= cQSS;
+-	if (t->tda9887_config & TDA9887_INTERCARRIER)
++	if (priv->config & TDA9887_INTERCARRIER)
+ 		buf[1] &= ~cQSS;
+ 
+-	if (t->tda9887_config & TDA9887_AUTOMUTE)
++	if (priv->config & TDA9887_AUTOMUTE)
+ 		buf[1] |= cAutoMuteFmActive;
+-	if (t->tda9887_config & TDA9887_DEEMPHASIS_MASK) {
++	if (priv->config & TDA9887_DEEMPHASIS_MASK) {
+ 		buf[2] &= ~0x60;
+-		switch (t->tda9887_config & TDA9887_DEEMPHASIS_MASK) {
++		switch (priv->config & TDA9887_DEEMPHASIS_MASK) {
+ 		case TDA9887_DEEMPHASIS_NONE:
+ 			buf[2] |= cDeemphasisOFF;
+ 			break;
+@@ -487,21 +504,22 @@ static int tda9887_set_config(struct tuner *t, char *buf)
+ 			break;
  		}
- 		break;
-+	}
- 	default:
--		return -EINVAL;
-+		goto error;
  	}
- 	if (restart_overlay && fh && res_check(fh, RESOURCE_OVERLAY)) {
- 		spin_lock_irqsave(&dev->slock,flags);
-@@ -1255,8 +1273,13 @@ static int set_control(struct saa7134_dev *dev, struct saa7134_fh *fh,
- 		start_preview(dev,fh);
- 		spin_unlock_irqrestore(&dev->slock,flags);
+-	if (t->tda9887_config & TDA9887_TOP_SET) {
++	if (priv->config & TDA9887_TOP_SET) {
+ 		buf[2] &= ~cTopMask;
+-		buf[2] |= (t->tda9887_config >> 8) & cTopMask;
++		buf[2] |= (priv->config >> 8) & cTopMask;
  	}
--	return 0;
-+	err = 0;
-+
-+error:
-+	mutex_unlock(&dev->lock);
-+	return err;
- }
-+EXPORT_SYMBOL_GPL(saa7134_s_ctrl);
- 
- /* ------------------------------------------------------------------ */
+-	if ((t->tda9887_config & TDA9887_INTERCARRIER_NTSC) && (t->std & V4L2_STD_NTSC))
++	if ((priv->config & TDA9887_INTERCARRIER_NTSC) &&
++	    (priv->std & V4L2_STD_NTSC))
+ 		buf[1] &= ~cQSS;
+-	if (t->tda9887_config & TDA9887_GATING_18)
++	if (priv->config & TDA9887_GATING_18)
+ 		buf[3] &= ~cGating_36;
  
-@@ -1413,8 +1436,8 @@ video_poll(struct file *file, struct poll_table_struct *wait)
- 		return POLLERR;
+-	if (t->mode == V4L2_TUNER_RADIO) {
+-		if (t->tda9887_config & TDA9887_RIF_41_3) {
++	if (priv->mode == V4L2_TUNER_RADIO) {
++		if (priv->config & TDA9887_RIF_41_3) {
+ 			buf[3] &= ~cVideoIFMask;
+ 			buf[3] |= cRadioIF_41_30;
+ 		}
+-		if (t->tda9887_config & TDA9887_GAIN_NORMAL)
++		if (priv->config & TDA9887_GAIN_NORMAL)
+ 			buf[3] &= ~cTunerGainLow;
+ 	}
  
- 	poll_wait(file, &buf->done, wait);
--	if (buf->state == STATE_DONE ||
--	    buf->state == STATE_ERROR)
-+	if (buf->state == VIDEOBUF_DONE ||
-+	    buf->state == VIDEOBUF_ERROR)
- 		return POLLIN|POLLRDNORM;
- 	return 0;
- }
-@@ -1478,8 +1501,11 @@ static int video_mmap(struct file *file, struct vm_area_struct * vma)
+@@ -510,26 +528,26 @@ static int tda9887_set_config(struct tuner *t, char *buf)
  
- /* ------------------------------------------------------------------ */
+ /* ---------------------------------------------------------------------- */
  
--static void saa7134_vbi_fmt(struct saa7134_dev *dev, struct v4l2_format *f)
-+static int saa7134_try_get_set_fmt_vbi(struct file *file, void *priv,
-+						struct v4l2_format *f)
+-static int tda9887_status(struct tuner *t)
++static int tda9887_status(struct dvb_frontend *fe)
  {
-+	struct saa7134_fh *fh = priv;
-+	struct saa7134_dev *dev = fh->dev;
- 	struct saa7134_tvnorm *norm = dev->tvnorm;
- 
- 	f->fmt.vbi.sampling_rate = 6750000 * 4;
-@@ -1492,837 +1518,805 @@ static void saa7134_vbi_fmt(struct saa7134_dev *dev, struct v4l2_format *f)
- 	f->fmt.vbi.count[1] = f->fmt.vbi.count[0];
- 	f->fmt.vbi.flags = 0; /* VBI_UNSYNC VBI_INTERLACED */
+-	struct tda9887_priv *priv = t->priv;
++	struct tda9887_priv *priv = fe->analog_demod_priv;
+ 	unsigned char buf[1];
+ 	int rc;
  
-+	return 0;
+ 	memset(buf,0,sizeof(buf));
+ 	if (1 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props,buf,1)))
+-		tda9887_info("i2c i/o error: rc == %d (should be 1)\n",rc);
+-	dump_read_message(t, buf);
++		tuner_info("i2c i/o error: rc == %d (should be 1)\n", rc);
++	dump_read_message(fe, buf);
+ 	return 0;
  }
  
--static int saa7134_g_fmt(struct saa7134_dev *dev, struct saa7134_fh *fh,
--			 struct v4l2_format *f)
-+static int saa7134_g_fmt_cap(struct file *file, void *priv,
-+				struct v4l2_format *f)
+-static void tda9887_configure(struct tuner *t)
++static void tda9887_configure(struct dvb_frontend *fe)
  {
--	switch (f->type) {
--	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
--		memset(&f->fmt.pix,0,sizeof(f->fmt.pix));
--		f->fmt.pix.width        = fh->width;
--		f->fmt.pix.height       = fh->height;
--		f->fmt.pix.field        = fh->cap.field;
--		f->fmt.pix.pixelformat  = fh->fmt->fourcc;
--		f->fmt.pix.bytesperline =
--			(f->fmt.pix.width * fh->fmt->depth) >> 3;
--		f->fmt.pix.sizeimage =
--			f->fmt.pix.height * f->fmt.pix.bytesperline;
--		return 0;
--	case V4L2_BUF_TYPE_VIDEO_OVERLAY:
--		if (saa7134_no_overlay > 0) {
--			printk ("V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
--			return -EINVAL;
--		}
--		f->fmt.win = fh->win;
--		return 0;
--	case V4L2_BUF_TYPE_VBI_CAPTURE:
--		saa7134_vbi_fmt(dev,f);
--		return 0;
--	default:
--		return -EINVAL;
--	}
-+	struct saa7134_fh *fh = priv;
-+
-+	f->fmt.pix.width        = fh->width;
-+	f->fmt.pix.height       = fh->height;
-+	f->fmt.pix.field        = fh->cap.field;
-+	f->fmt.pix.pixelformat  = fh->fmt->fourcc;
-+	f->fmt.pix.bytesperline =
-+		(f->fmt.pix.width * fh->fmt->depth) >> 3;
-+	f->fmt.pix.sizeimage =
-+		f->fmt.pix.height * f->fmt.pix.bytesperline;
-+	return 0;
- }
+-	struct tda9887_priv *priv = t->priv;
++	struct tda9887_priv *priv = fe->analog_demod_priv;
+ 	int rc;
  
--static int saa7134_try_fmt(struct saa7134_dev *dev, struct saa7134_fh *fh,
--			   struct v4l2_format *f)
-+static int saa7134_g_fmt_overlay(struct file *file, void *priv,
-+				struct v4l2_format *f)
- {
--	int err;
-+	struct saa7134_fh *fh = priv;
+ 	memset(priv->data,0,sizeof(priv->data));
+-	tda9887_set_tvnorm(t,priv->data);
++	tda9887_set_tvnorm(fe);
  
--	switch (f->type) {
--	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
--	{
--		struct saa7134_format *fmt;
--		enum v4l2_field field;
--		unsigned int maxw, maxh;
-+	if (saa7134_no_overlay > 0) {
-+		printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
-+		return -EINVAL;
-+	}
-+	f->fmt.win = fh->win;
+ 	/* A note on the port settings:
+ 	   These settings tend to depend on the specifics of the board.
+@@ -547,38 +565,38 @@ static void tda9887_configure(struct tuner *t)
+ 	priv->data[1] |= cOutputPort1Inactive;
+ 	priv->data[1] |= cOutputPort2Inactive;
  
--		fmt = format_by_fourcc(f->fmt.pix.pixelformat);
--		if (NULL == fmt)
--			return -EINVAL;
-+	return 0;
-+}
+-	tda9887_set_config(t,priv->data);
+-	tda9887_set_insmod(t,priv->data);
++	tda9887_do_config(fe);
++	tda9887_set_insmod(fe);
  
--		field = f->fmt.pix.field;
--		maxw  = min(dev->crop_current.width*4,  dev->crop_bounds.width);
--		maxh  = min(dev->crop_current.height*4, dev->crop_bounds.height);
-+static int saa7134_try_fmt_cap(struct file *file, void *priv,
-+						struct v4l2_format *f)
-+{
-+	struct saa7134_fh *fh = priv;
-+	struct saa7134_dev *dev = fh->dev;
-+	struct saa7134_format *fmt;
-+	enum v4l2_field field;
-+	unsigned int maxw, maxh;
+-	if (t->mode == T_STANDBY) {
++	if (priv->mode == T_STANDBY)
+ 		priv->data[1] |= cForcedMuteAudioON;
+-	}
  
--		if (V4L2_FIELD_ANY == field) {
--			field = (f->fmt.pix.height > maxh/2)
--				? V4L2_FIELD_INTERLACED
--				: V4L2_FIELD_BOTTOM;
--		}
--		switch (field) {
--		case V4L2_FIELD_TOP:
--		case V4L2_FIELD_BOTTOM:
--			maxh = maxh / 2;
--			break;
--		case V4L2_FIELD_INTERLACED:
--			break;
--		default:
--			return -EINVAL;
--		}
-+	fmt = format_by_fourcc(f->fmt.pix.pixelformat);
-+	if (NULL == fmt)
-+		return -EINVAL;
+-	tda9887_dbg("writing: b=0x%02x c=0x%02x e=0x%02x\n",
+-		priv->data[1],priv->data[2],priv->data[3]);
+-	if (tuner_debug > 1)
+-		dump_write_message(t, priv->data);
++	tuner_dbg("writing: b=0x%02x c=0x%02x e=0x%02x\n",
++		  priv->data[1], priv->data[2], priv->data[3]);
++	if (debug > 1)
++		dump_write_message(fe, priv->data);
  
--		f->fmt.pix.field = field;
--		if (f->fmt.pix.width  < 48)
--			f->fmt.pix.width  = 48;
--		if (f->fmt.pix.height < 32)
--			f->fmt.pix.height = 32;
--		if (f->fmt.pix.width > maxw)
--			f->fmt.pix.width = maxw;
--		if (f->fmt.pix.height > maxh)
--			f->fmt.pix.height = maxh;
--		f->fmt.pix.width &= ~0x03;
--		f->fmt.pix.bytesperline =
--			(f->fmt.pix.width * fmt->depth) >> 3;
--		f->fmt.pix.sizeimage =
--			f->fmt.pix.height * f->fmt.pix.bytesperline;
-+	field = f->fmt.pix.field;
-+	maxw  = min(dev->crop_current.width*4,  dev->crop_bounds.width);
-+	maxh  = min(dev->crop_current.height*4, dev->crop_bounds.height);
+ 	if (4 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,priv->data,4)))
+-		tda9887_info("i2c i/o error: rc == %d (should be 4)\n",rc);
++		tuner_info("i2c i/o error: rc == %d (should be 4)\n", rc);
  
--		return 0;
-+	if (V4L2_FIELD_ANY == field) {
-+		field = (f->fmt.pix.height > maxh/2)
-+			? V4L2_FIELD_INTERLACED
-+			: V4L2_FIELD_BOTTOM;
- 	}
--	case V4L2_BUF_TYPE_VIDEO_OVERLAY:
--		if (saa7134_no_overlay > 0) {
--			printk ("V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
--			return -EINVAL;
--		}
--		err = verify_preview(dev,&f->fmt.win);
--		if (0 != err)
--			return err;
--		return 0;
--	case V4L2_BUF_TYPE_VBI_CAPTURE:
--		saa7134_vbi_fmt(dev,f);
--		return 0;
-+	switch (field) {
-+	case V4L2_FIELD_TOP:
-+	case V4L2_FIELD_BOTTOM:
-+		maxh = maxh / 2;
-+		break;
-+	case V4L2_FIELD_INTERLACED:
-+		break;
- 	default:
- 		return -EINVAL;
+-	if (tuner_debug > 2) {
++	if (debug > 2) {
+ 		msleep_interruptible(1000);
+-		tda9887_status(t);
++		tda9887_status(fe);
  	}
-+
-+	f->fmt.pix.field = field;
-+	if (f->fmt.pix.width  < 48)
-+		f->fmt.pix.width  = 48;
-+	if (f->fmt.pix.height < 32)
-+		f->fmt.pix.height = 32;
-+	if (f->fmt.pix.width > maxw)
-+		f->fmt.pix.width = maxw;
-+	if (f->fmt.pix.height > maxh)
-+		f->fmt.pix.height = maxh;
-+	f->fmt.pix.width &= ~0x03;
-+	f->fmt.pix.bytesperline =
-+		(f->fmt.pix.width * fmt->depth) >> 3;
-+	f->fmt.pix.sizeimage =
-+		f->fmt.pix.height * f->fmt.pix.bytesperline;
-+
-+	return 0;
  }
  
--static int saa7134_s_fmt(struct saa7134_dev *dev, struct saa7134_fh *fh,
--			 struct v4l2_format *f)
-+static int saa7134_try_fmt_overlay(struct file *file, void *priv,
-+						struct v4l2_format *f)
- {
--	unsigned long flags;
--	int err;
--
--	switch (f->type) {
--	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
--		err = saa7134_try_fmt(dev,fh,f);
--		if (0 != err)
--			return err;
--
--		fh->fmt       = format_by_fourcc(f->fmt.pix.pixelformat);
--		fh->width     = f->fmt.pix.width;
--		fh->height    = f->fmt.pix.height;
--		fh->cap.field = f->fmt.pix.field;
--		return 0;
--	case V4L2_BUF_TYPE_VIDEO_OVERLAY:
--		if (saa7134_no_overlay > 0) {
--			printk ("V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
--			return -EINVAL;
--		}
--		err = verify_preview(dev,&f->fmt.win);
--		if (0 != err)
--			return err;
--
--		mutex_lock(&dev->lock);
--		fh->win    = f->fmt.win;
--		fh->nclips = f->fmt.win.clipcount;
--		if (fh->nclips > 8)
--			fh->nclips = 8;
--		if (copy_from_user(fh->clips,f->fmt.win.clips,
--				   sizeof(struct v4l2_clip)*fh->nclips)) {
--			mutex_unlock(&dev->lock);
--			return -EFAULT;
--		}
-+	struct saa7134_fh *fh = priv;
-+	struct saa7134_dev *dev = fh->dev;
- 
--		if (res_check(fh, RESOURCE_OVERLAY)) {
--			spin_lock_irqsave(&dev->slock,flags);
--			stop_preview(dev,fh);
--			start_preview(dev,fh);
--			spin_unlock_irqrestore(&dev->slock,flags);
--		}
--		mutex_unlock(&dev->lock);
--		return 0;
--	case V4L2_BUF_TYPE_VBI_CAPTURE:
--		saa7134_vbi_fmt(dev,f);
--		return 0;
--	default:
-+	if (saa7134_no_overlay > 0) {
-+		printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
- 		return -EINVAL;
- 	}
-+
-+	return verify_preview(dev, &f->fmt.win);
- }
+ /* ---------------------------------------------------------------------- */
  
--int saa7134_common_ioctl(struct saa7134_dev *dev,
--			 unsigned int cmd, void *arg)
-+static int saa7134_s_fmt_cap(struct file *file, void *priv,
-+					struct v4l2_format *f)
+-static void tda9887_tuner_status(struct tuner *t)
++static void tda9887_tuner_status(struct dvb_frontend *fe)
  {
-+	struct saa7134_fh *fh = priv;
- 	int err;
- 
--	switch (cmd) {
--	case VIDIOC_QUERYCTRL:
--	{
--		const struct v4l2_queryctrl *ctrl;
--		struct v4l2_queryctrl *c = arg;
-+	err = saa7134_try_fmt_cap(file, priv, f);
-+	if (0 != err)
-+		return err;
- 
--		if ((c->id <  V4L2_CID_BASE ||
--		     c->id >= V4L2_CID_LASTP1) &&
--		    (c->id <  V4L2_CID_PRIVATE_BASE ||
--		     c->id >= V4L2_CID_PRIVATE_LASTP1))
--			return -EINVAL;
--		ctrl = ctrl_by_id(c->id);
--		*c = (NULL != ctrl) ? *ctrl : no_ctrl;
--		return 0;
-+	fh->fmt       = format_by_fourcc(f->fmt.pix.pixelformat);
-+	fh->width     = f->fmt.pix.width;
-+	fh->height    = f->fmt.pix.height;
-+	fh->cap.field = f->fmt.pix.field;
-+	return 0;
-+}
-+
-+static int saa7134_s_fmt_overlay(struct file *file, void *priv,
-+					struct v4l2_format *f)
-+{
-+	struct saa7134_fh *fh = priv;
-+	struct saa7134_dev *dev = fh->dev;
-+	int err;
-+	unsigned int flags;
-+
-+	if (saa7134_no_overlay > 0) {
-+		printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
-+		return -EINVAL;
- 	}
--	case VIDIOC_G_CTRL:
--		return get_control(dev,arg);
--	case VIDIOC_S_CTRL:
--	{
--		mutex_lock(&dev->lock);
--		err = set_control(dev,NULL,arg);
--		mutex_unlock(&dev->lock);
-+	err = verify_preview(dev, &f->fmt.win);
-+	if (0 != err)
- 		return err;
--	}
--	/* --- input switching --------------------------------------- */
--	case VIDIOC_ENUMINPUT:
--	{
--		struct v4l2_input *i = arg;
--		unsigned int n;
- 
--		n = i->index;
--		if (n >= SAA7134_INPUT_MAX)
--			return -EINVAL;
--		if (NULL == card_in(dev,i->index).name)
--			return -EINVAL;
--		memset(i,0,sizeof(*i));
--		i->index = n;
--		i->type  = V4L2_INPUT_TYPE_CAMERA;
--		strcpy(i->name,card_in(dev,n).name);
--		if (card_in(dev,n).tv)
--			i->type = V4L2_INPUT_TYPE_TUNER;
--		i->audioset = 1;
--		if (n == dev->ctl_input) {
--			int v1 = saa_readb(SAA7134_STATUS_VIDEO1);
--			int v2 = saa_readb(SAA7134_STATUS_VIDEO2);
--
--			if (0 != (v1 & 0x40))
--				i->status |= V4L2_IN_ST_NO_H_LOCK;
--			if (0 != (v2 & 0x40))
--				i->status |= V4L2_IN_ST_NO_SYNC;
--			if (0 != (v2 & 0x0e))
--				i->status |= V4L2_IN_ST_MACROVISION;
--		}
--		for (n = 0; n < TVNORMS; n++)
--			i->std |= tvnorms[n].id;
--		return 0;
--	}
--	case VIDIOC_G_INPUT:
--	{
--		int *i = arg;
--		*i = dev->ctl_input;
--		return 0;
--	}
--	case VIDIOC_S_INPUT:
--	{
--		int *i = arg;
-+	mutex_lock(&dev->lock);
- 
--		if (*i < 0  ||  *i >= SAA7134_INPUT_MAX)
--			return -EINVAL;
--		if (NULL == card_in(dev,*i).name)
--			return -EINVAL;
--		mutex_lock(&dev->lock);
--		video_mux(dev,*i);
-+	fh->win    = f->fmt.win;
-+	fh->nclips = f->fmt.win.clipcount;
-+
-+	if (fh->nclips > 8)
-+		fh->nclips = 8;
-+
-+	if (copy_from_user(fh->clips, f->fmt.win.clips,
-+			   sizeof(struct v4l2_clip)*fh->nclips)) {
- 		mutex_unlock(&dev->lock);
--		return 0;
-+		return -EFAULT;
- 	}
- 
-+	if (res_check(fh, RESOURCE_OVERLAY)) {
-+		spin_lock_irqsave(&dev->slock, flags);
-+		stop_preview(dev, fh);
-+		start_preview(dev, fh);
-+		spin_unlock_irqrestore(&dev->slock, flags);
- 	}
-+
-+	mutex_unlock(&dev->lock);
- 	return 0;
+-	struct tda9887_priv *priv = t->priv;
+-	tda9887_info("Data bytes: b=0x%02x c=0x%02x e=0x%02x\n", priv->data[1], priv->data[2], priv->data[3]);
++	struct tda9887_priv *priv = fe->analog_demod_priv;
++	tuner_info("Data bytes: b=0x%02x c=0x%02x e=0x%02x\n",
++		   priv->data[1], priv->data[2], priv->data[3]);
  }
--EXPORT_SYMBOL(saa7134_common_ioctl);
  
--/*
-- * This function is _not_ called directly, but from
-- * video_generic_ioctl (and maybe others).  userspace
-- * copying is done already, arg is a kernel pointer.
-- */
--static int video_do_ioctl(struct inode *inode, struct file *file,
--			  unsigned int cmd, void *arg)
-+int saa7134_queryctrl(struct file *file, void *priv, struct v4l2_queryctrl *c)
+-static int tda9887_get_afc(struct tuner *t)
++static int tda9887_get_afc(struct dvb_frontend *fe)
  {
--	struct saa7134_fh *fh = file->private_data;
-+	const struct v4l2_queryctrl *ctrl;
-+
-+	if ((c->id <  V4L2_CID_BASE ||
-+	     c->id >= V4L2_CID_LASTP1) &&
-+	    (c->id <  V4L2_CID_PRIVATE_BASE ||
-+	     c->id >= V4L2_CID_PRIVATE_LASTP1))
-+		return -EINVAL;
-+	ctrl = ctrl_by_id(c->id);
-+	*c = (NULL != ctrl) ? *ctrl : no_ctrl;
-+	return 0;
-+}
-+EXPORT_SYMBOL_GPL(saa7134_queryctrl);
-+
-+static int saa7134_enum_input(struct file *file, void *priv,
-+					struct v4l2_input *i)
+-	struct tda9887_priv *priv = t->priv;
++	struct tda9887_priv *priv = fe->analog_demod_priv;
+ 	static int AFC_BITS_2_kHz[] = {
+ 		-12500,  -37500,  -62500,  -97500,
+ 		-112500, -137500, -162500, -187500,
+@@ -594,52 +612,79 @@ static int tda9887_get_afc(struct tuner *t)
+ 	return afc;
+ }
+ 
+-static void tda9887_standby(struct tuner *t)
++static void tda9887_standby(struct dvb_frontend *fe)
 +{
-+	struct saa7134_fh *fh = priv;
-+	struct saa7134_dev *dev = fh->dev;
-+	unsigned int n;
++	struct tda9887_priv *priv = fe->analog_demod_priv;
 +
-+	n = i->index;
-+	if (n >= SAA7134_INPUT_MAX)
-+		return -EINVAL;
-+	if (NULL == card_in(dev, i->index).name)
-+		return -EINVAL;
-+	memset(i, 0, sizeof(*i));
-+	i->index = n;
-+	i->type  = V4L2_INPUT_TYPE_CAMERA;
-+	strcpy(i->name, card_in(dev, n).name);
-+	if (card_in(dev, n).tv)
-+		i->type = V4L2_INPUT_TYPE_TUNER;
-+	i->audioset = 1;
-+	if (n == dev->ctl_input) {
-+		int v1 = saa_readb(SAA7134_STATUS_VIDEO1);
-+		int v2 = saa_readb(SAA7134_STATUS_VIDEO2);
++	priv->mode = T_STANDBY;
 +
-+		if (0 != (v1 & 0x40))
-+			i->status |= V4L2_IN_ST_NO_H_LOCK;
-+		if (0 != (v2 & 0x40))
-+			i->status |= V4L2_IN_ST_NO_SYNC;
-+		if (0 != (v2 & 0x0e))
-+			i->status |= V4L2_IN_ST_MACROVISION;
-+	}
-+	i->std = SAA7134_NORMS;
-+	return 0;
++	tda9887_configure(fe);
 +}
 +
-+static int saa7134_g_input(struct file *file, void *priv, unsigned int *i)
-+{
-+	struct saa7134_fh *fh = priv;
-+	struct saa7134_dev *dev = fh->dev;
++static void tda9887_set_params(struct dvb_frontend *fe,
++			       struct analog_parameters *params)
+ {
+-	tda9887_configure(t);
++	struct tda9887_priv *priv = fe->analog_demod_priv;
 +
-+	*i = dev->ctl_input;
-+	return 0;
-+}
++	priv->mode    = params->mode;
++	priv->audmode = params->audmode;
++	priv->std     = params->std;
++	tda9887_configure(fe);
+ }
+ 
+-static void tda9887_set_freq(struct tuner *t, unsigned int freq)
++static int tda9887_set_config(struct dvb_frontend *fe, void *priv_cfg)
+ {
+-	tda9887_configure(t);
++	struct tda9887_priv *priv = fe->analog_demod_priv;
 +
-+static int saa7134_s_input(struct file *file, void *priv, unsigned int i)
-+{
-+	struct saa7134_fh *fh = priv;
- 	struct saa7134_dev *dev = fh->dev;
--	unsigned long flags;
- 	int err;
++	priv->config = *(unsigned int *)priv_cfg;
++	tda9887_configure(fe);
++
++	return 0;
+ }
  
--	if (video_debug > 1)
--		v4l_print_ioctl(dev->name,cmd);
--
--	switch (cmd) {
--	case VIDIOC_S_CTRL:
--	case VIDIOC_S_STD:
--	case VIDIOC_S_INPUT:
--	case VIDIOC_S_TUNER:
--	case VIDIOC_S_FREQUENCY:
--		err = v4l2_prio_check(&dev->prio,&fh->prio);
--		if (0 != err)
--			return err;
--	}
-+	err = v4l2_prio_check(&dev->prio, &fh->prio);
-+	if (0 != err)
-+		return err;
+-static void tda9887_release(struct tuner *t)
++static void tda9887_release(struct dvb_frontend *fe)
+ {
+-	kfree(t->priv);
+-	t->priv = NULL;
++	kfree(fe->analog_demod_priv);
++	fe->analog_demod_priv = NULL;
+ }
  
--	switch (cmd) {
--	case VIDIOC_QUERYCAP:
--	{
--		struct v4l2_capability *cap = arg;
--		unsigned int tuner_type = dev->tuner_type;
+-static struct tuner_operations tda9887_tuner_ops = {
+-	.set_tv_freq    = tda9887_set_freq,
+-	.set_radio_freq = tda9887_set_freq,
++static struct analog_demod_ops tda9887_ops = {
++	.info		= {
++		.name	= "tda9887",
++	},
++	.set_params     = tda9887_set_params,
+ 	.standby        = tda9887_standby,
+ 	.tuner_status   = tda9887_tuner_status,
+ 	.get_afc        = tda9887_get_afc,
+ 	.release        = tda9887_release,
++	.set_config     = tda9887_set_config,
+ };
+ 
+-int tda9887_tuner_init(struct tuner *t)
++struct dvb_frontend *tda9887_attach(struct dvb_frontend *fe,
++				    struct i2c_adapter *i2c_adap,
++				    u8 i2c_addr)
+ {
+ 	struct tda9887_priv *priv = NULL;
+ 
+ 	priv = kzalloc(sizeof(struct tda9887_priv), GFP_KERNEL);
+ 	if (priv == NULL)
+-		return -ENOMEM;
+-	t->priv = priv;
 -
--		memset(cap,0,sizeof(*cap));
--		strcpy(cap->driver, "saa7134");
--		strlcpy(cap->card, saa7134_boards[dev->board].name,
--			sizeof(cap->card));
--		sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci));
--		cap->version = SAA7134_VERSION_CODE;
--		cap->capabilities =
--			V4L2_CAP_VIDEO_CAPTURE |
--			V4L2_CAP_VBI_CAPTURE |
--			V4L2_CAP_READWRITE |
--			V4L2_CAP_STREAMING |
--			V4L2_CAP_TUNER;
--		if (saa7134_no_overlay <= 0) {
--			cap->capabilities |= V4L2_CAP_VIDEO_OVERLAY;
--		}
-+	if (i < 0  ||  i >= SAA7134_INPUT_MAX)
-+		return -EINVAL;
-+	if (NULL == card_in(dev, i).name)
-+		return -EINVAL;
-+	mutex_lock(&dev->lock);
-+	video_mux(dev, i);
-+	mutex_unlock(&dev->lock);
-+	return 0;
-+}
+-	priv->i2c_props.addr = t->i2c.addr;
+-	priv->i2c_props.adap = t->i2c.adapter;
++		return NULL;
++	fe->analog_demod_priv = priv;
  
--		if ((tuner_type == TUNER_ABSENT) || (tuner_type == UNSET))
--			cap->capabilities &= ~V4L2_CAP_TUNER;
-+static int saa7134_querycap(struct file *file, void  *priv,
-+					struct v4l2_capability *cap)
-+{
-+	struct saa7134_fh *fh = priv;
-+	struct saa7134_dev *dev = fh->dev;
+-	strlcpy(t->i2c.name, "tda9887", sizeof(t->i2c.name));
++	priv->i2c_props.addr = i2c_addr;
++	priv->i2c_props.adap = i2c_adap;
++	priv->mode = T_STANDBY;
  
-+	unsigned int tuner_type = dev->tuner_type;
+-	tda9887_info("tda988[5/6/7] found @ 0x%x (%s)\n", t->i2c.addr,
+-						t->i2c.driver->driver.name);
++	tuner_info("tda988[5/6/7] found\n");
+ 
+-	memcpy(&t->ops, &tda9887_tuner_ops, sizeof(struct tuner_operations));
++	memcpy(&fe->ops.analog_ops, &tda9887_ops,
++	       sizeof(struct analog_demod_ops));
+ 
+-	return 0;
++	return fe;
+ }
++EXPORT_SYMBOL_GPL(tda9887_attach);
 +
-+	strcpy(cap->driver, "saa7134");
-+	strlcpy(cap->card, saa7134_boards[dev->board].name,
-+		sizeof(cap->card));
-+	sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci));
-+	cap->version = SAA7134_VERSION_CODE;
-+	cap->capabilities =
-+		V4L2_CAP_VIDEO_CAPTURE |
-+		V4L2_CAP_VBI_CAPTURE |
-+		V4L2_CAP_READWRITE |
-+		V4L2_CAP_STREAMING |
-+		V4L2_CAP_TUNER;
-+	if (saa7134_no_overlay <= 0)
-+		cap->capabilities |= V4L2_CAP_VIDEO_OVERLAY;
++MODULE_LICENSE("GPL");
+ 
+ /*
+  * Overrides for Emacs so that we follow Linus's tabbing style.
+diff --git a/drivers/media/video/tda9887.h b/drivers/media/video/tda9887.h
+new file mode 100644
+index 0000000..8f873a8
+--- /dev/null
++++ b/drivers/media/video/tda9887.h
+@@ -0,0 +1,38 @@
++/*
++    This program is free software; you can redistribute it and/or modify
++    it under the terms of the GNU General Public License as published by
++    the Free Software Foundation; either version 2 of the License, or
++    (at your option) any later version.
 +
-+	if ((tuner_type == TUNER_ABSENT) || (tuner_type == UNSET))
-+		cap->capabilities &= ~V4L2_CAP_TUNER;
- 		return 0;
--	}
++    This program is distributed in the hope that it will be useful,
++    but WITHOUT ANY WARRANTY; without even the implied warranty of
++    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++    GNU General Public License for more details.
++
++    You 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 __TDA9887_H__
++#define __TDA9887_H__
++
++#include <linux/i2c.h>
++#include "dvb_frontend.h"
++
++/* ------------------------------------------------------------------------ */
++#if defined(CONFIG_TUNER_TDA9887) || (defined(CONFIG_TUNER_TDA9887_MODULE) && defined(MODULE))
++extern struct dvb_frontend *tda9887_attach(struct dvb_frontend *fe,
++					   struct i2c_adapter *i2c_adap,
++					   u8 i2c_addr);
++#else
++static inline struct dvb_frontend *tda9887_attach(struct dvb_frontend *fe,
++						  struct i2c_adapter *i2c_adap,
++						  u8 i2c_addr)
++{
++	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
++	return NULL;
 +}
++#endif
++
++#endif /* __TDA9887_H__ */
+diff --git a/drivers/media/video/tea5761.c b/drivers/media/video/tea5761.c
+index 2150222..5326eec 100644
+--- a/drivers/media/video/tea5761.c
++++ b/drivers/media/video/tea5761.c
+@@ -18,7 +18,7 @@ static int debug = 0;
+ module_param(debug, int, 0644);
+ MODULE_PARM_DESC(debug, "enable verbose debug messages");
  
--	/* --- tv standards ------------------------------------------ */
--	case VIDIOC_ENUMSTD:
--	{
--		struct v4l2_standard *e = arg;
--		unsigned int i;
-+static int saa7134_s_std(struct file *file, void *priv, 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;
+-#define PREFIX "tea5761 "
++#define PREFIX "tea5761"
  
--		i = e->index;
--		if (i >= TVNORMS)
--			return -EINVAL;
--		err = v4l2_video_std_construct(e, tvnorms[e->index].id,
--					       tvnorms[e->index].name);
--		e->index = i;
--		if (err < 0)
--			return err;
--		return 0;
--	}
--	case VIDIOC_G_STD:
--	{
--		v4l2_std_id *id = arg;
-+	err = v4l2_prio_check(&dev->prio, &fh->prio);
-+	if (0 != err)
-+		return err;
+ struct tea5761_priv {
+ 	struct tuner_i2c_props i2c_props;
+diff --git a/drivers/media/video/tea5767.c b/drivers/media/video/tea5767.c
+index 71df419..e1b48d8 100644
+--- a/drivers/media/video/tea5767.c
++++ b/drivers/media/video/tea5767.c
+@@ -20,12 +20,14 @@ static int debug = 0;
+ module_param(debug, int, 0644);
+ MODULE_PARM_DESC(debug, "enable verbose debug messages");
  
--		*id = dev->tvnorm->id;
--		return 0;
--	}
--	case VIDIOC_S_STD:
--	{
--		v4l2_std_id *id = arg;
--		unsigned int i;
--		v4l2_std_id fixup;
-+	for (i = 0; i < TVNORMS; i++)
-+		if (*id == tvnorms[i].id)
-+			break;
+-#define PREFIX "tea5767 "
++#define PREFIX "tea5767"
  
-+	if (i == TVNORMS)
- 		for (i = 0; i < TVNORMS; i++)
--			if (*id == tvnorms[i].id)
-+			if (*id & tvnorms[i].id)
- 				break;
--		if (i == TVNORMS)
--			for (i = 0; i < TVNORMS; i++)
--				if (*id & tvnorms[i].id)
--					break;
--		if (i == TVNORMS)
--			return -EINVAL;
--		if ((*id & V4L2_STD_SECAM) && (secam[0] != '-')) {
--			if (secam[0] == 'L' || secam[0] == 'l') {
--				if (secam[1] == 'C' || secam[1] == 'c')
--					fixup = V4L2_STD_SECAM_LC;
--				else
--					fixup = V4L2_STD_SECAM_L;
--			} else {
--				if (secam[0] == 'D' || secam[0] == 'd')
--					fixup = V4L2_STD_SECAM_DK;
--				else
--					fixup = V4L2_STD_SECAM;
--			}
--			for (i = 0; i < TVNORMS; i++)
--				if (fixup == tvnorms[i].id)
--					break;
-+	if (i == TVNORMS)
-+		return -EINVAL;
-+
-+	if ((*id & V4L2_STD_SECAM) && (secam[0] != '-')) {
-+		if (secam[0] == 'L' || secam[0] == 'l') {
-+			if (secam[1] == 'C' || secam[1] == 'c')
-+				fixup = V4L2_STD_SECAM_LC;
-+			else
-+				fixup = V4L2_STD_SECAM_L;
-+		} else {
-+			if (secam[0] == 'D' || secam[0] == 'd')
-+				fixup = V4L2_STD_SECAM_DK;
-+			else
-+				fixup = V4L2_STD_SECAM;
- 		}
--		mutex_lock(&dev->lock);
--		if (res_check(fh, RESOURCE_OVERLAY)) {
--			spin_lock_irqsave(&dev->slock,flags);
--			stop_preview(dev,fh);
--			spin_unlock_irqrestore(&dev->slock, flags);
+-struct tea5767_priv {
+-	struct tuner_i2c_props i2c_props;
++/*****************************************************************************/
+ 
+-	u32 frequency;
++struct tea5767_priv {
++	struct tuner_i2c_props	i2c_props;
++	u32			frequency;
++	struct tea5767_ctrl	ctrl;
+ };
+ 
+ /*****************************************************************************/
+@@ -127,17 +129,10 @@ struct tea5767_priv {
+ /* Reserved for future extensions */
+ #define TEA5767_RESERVED_MASK	0xff
+ 
+-enum tea5767_xtal_freq {
+-	TEA5767_LOW_LO_32768    = 0,
+-	TEA5767_HIGH_LO_32768   = 1,
+-	TEA5767_LOW_LO_13MHz    = 2,
+-	TEA5767_HIGH_LO_13MHz   = 3,
+-};
 -
--			set_tvnorm(dev,&tvnorms[i]);
 -
--			spin_lock_irqsave(&dev->slock, flags);
--			start_preview(dev,fh);
--			spin_unlock_irqrestore(&dev->slock,flags);
--		} else
--			set_tvnorm(dev,&tvnorms[i]);
--		saa7134_tvaudio_do_scan(dev);
--		mutex_unlock(&dev->lock);
--		return 0;
-+		for (i = 0; i < TVNORMS; i++)
-+			if (fixup == tvnorms[i].id)
-+				break;
- 	}
+ /*****************************************************************************/
  
--	case VIDIOC_CROPCAP:
--	{
--		struct v4l2_cropcap *cap = arg;
-+	*id = tvnorms[i].id;
+-static void tea5767_status_dump(unsigned char *buffer)
++static void tea5767_status_dump(struct tea5767_priv *priv,
++				unsigned char *buffer)
+ {
+ 	unsigned int div, frq;
  
--		if (cap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
--		    cap->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
--			return -EINVAL;
--		cap->bounds  = dev->crop_bounds;
--		cap->defrect = dev->crop_defrect;
--		cap->pixelaspect.numerator   = 1;
--		cap->pixelaspect.denominator = 1;
--		if (dev->tvnorm->id & V4L2_STD_525_60) {
--			cap->pixelaspect.numerator   = 11;
--			cap->pixelaspect.denominator = 10;
--		}
--		if (dev->tvnorm->id & V4L2_STD_625_50) {
--			cap->pixelaspect.numerator   = 54;
--			cap->pixelaspect.denominator = 59;
--		}
--		return 0;
--	}
-+	mutex_lock(&dev->lock);
-+	if (res_check(fh, RESOURCE_OVERLAY)) {
-+		spin_lock_irqsave(&dev->slock, flags);
-+		stop_preview(dev, fh);
-+		spin_unlock_irqrestore(&dev->slock, flags);
+@@ -153,7 +148,7 @@ static void tea5767_status_dump(unsigned char *buffer)
  
--	case VIDIOC_G_CROP:
--	{
--		struct v4l2_crop * crop = arg;
-+		set_tvnorm(dev, &tvnorms[i]);
+ 	div = ((buffer[0] & 0x3f) << 8) | buffer[1];
  
--		if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
--		    crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
--			return -EINVAL;
--		crop->c = dev->crop_current;
--		return 0;
--	}
--	case VIDIOC_S_CROP:
--	{
--		struct v4l2_crop *crop = arg;
--		struct v4l2_rect *b = &dev->crop_bounds;
-+		spin_lock_irqsave(&dev->slock, flags);
-+		start_preview(dev, fh);
-+		spin_unlock_irqrestore(&dev->slock, flags);
-+	} else
-+		set_tvnorm(dev, &tvnorms[i]);
+-	switch (TEA5767_HIGH_LO_32768) {
++	switch (priv->ctrl.xtal_freq) {
+ 	case TEA5767_HIGH_LO_13MHz:
+ 		frq = (div * 50000 - 700000 - 225000) / 4;	/* Freq in KHz */
+ 		break;
+@@ -202,13 +197,10 @@ static int set_radio_freq(struct dvb_frontend *fe,
  
--		if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
--		    crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
--			return -EINVAL;
--		if (crop->c.height < 0)
--			return -EINVAL;
--		if (crop->c.width < 0)
--			return -EINVAL;
-+	saa7134_tvaudio_do_scan(dev);
-+	mutex_unlock(&dev->lock);
-+	return 0;
-+}
+ 	tuner_dbg("radio freq = %d.%03d MHz\n", frq/16000,(frq/16)%1000);
  
--		if (res_locked(fh->dev,RESOURCE_OVERLAY))
--			return -EBUSY;
--		if (res_locked(fh->dev,RESOURCE_VIDEO))
--			return -EBUSY;
-+static int saa7134_cropcap(struct file *file, void *priv,
-+					struct v4l2_cropcap *cap)
-+{
-+	struct saa7134_fh *fh = priv;
-+	struct saa7134_dev *dev = fh->dev;
+-	/* Rounds freq to next decimal value - for 62.5 KHz step */
+-	/* frq = 20*(frq/16)+radio_frq[frq%16]; */
++	buffer[2] = 0;
  
--		if (crop->c.top < b->top)
--			crop->c.top = b->top;
--		if (crop->c.top > b->top + b->height)
--			crop->c.top = b->top + b->height;
--		if (crop->c.height > b->top - crop->c.top + b->height)
--			crop->c.height = b->top - crop->c.top + b->height;
--
--		if (crop->c.left < b->left)
--			crop->c.left = b->left;
--		if (crop->c.left > b->left + b->width)
--			crop->c.left = b->left + b->width;
--		if (crop->c.width > b->left - crop->c.left + b->width)
--			crop->c.width = b->left - crop->c.left + b->width;
--
--		dev->crop_current = crop->c;
--		return 0;
-+	if (cap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
-+	    cap->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
-+		return -EINVAL;
-+	cap->bounds  = dev->crop_bounds;
-+	cap->defrect = dev->crop_defrect;
-+	cap->pixelaspect.numerator   = 1;
-+	cap->pixelaspect.denominator = 1;
-+	if (dev->tvnorm->id & V4L2_STD_525_60) {
-+		cap->pixelaspect.numerator   = 11;
-+		cap->pixelaspect.denominator = 10;
-+	}
-+	if (dev->tvnorm->id & V4L2_STD_625_50) {
-+		cap->pixelaspect.numerator   = 54;
-+		cap->pixelaspect.denominator = 59;
+-	buffer[2] = TEA5767_PORT1_HIGH;
+-	buffer[3] = TEA5767_PORT2_HIGH | TEA5767_HIGH_CUT_CTRL |
+-		    TEA5767_ST_NOISE_CTL | TEA5767_JAPAN_BAND;
+-	buffer[4] = 0;
++	if (priv->ctrl.port1)
++		buffer[2] |= TEA5767_PORT1_HIGH;
+ 
+ 	if (params->audmode == V4L2_TUNER_MODE_MONO) {
+ 		tuner_dbg("TEA5767 set to mono\n");
+@@ -217,18 +209,45 @@ static int set_radio_freq(struct dvb_frontend *fe,
+ 		tuner_dbg("TEA5767 set to stereo\n");
  	}
-+	return 0;
-+}
  
--	/* --- tuner ioctls ------------------------------------------ */
--	case VIDIOC_G_TUNER:
--	{
--		struct v4l2_tuner *t = arg;
--		int n;
-+static int saa7134_g_crop(struct file *file, void *f, struct v4l2_crop *crop)
-+{
-+	struct saa7134_fh *fh = f;
-+	struct saa7134_dev *dev = fh->dev;
+-	/* Should be replaced */
+-	switch (TEA5767_HIGH_LO_32768) {
++
++	buffer[3] = 0;
++
++	if (priv->ctrl.port2)
++		buffer[3] |= TEA5767_PORT2_HIGH;
++
++	if (priv->ctrl.high_cut)
++		buffer[3] |= TEA5767_HIGH_CUT_CTRL;
++
++	if (priv->ctrl.st_noise)
++		buffer[3] |= TEA5767_ST_NOISE_CTL;
++
++	if (priv->ctrl.soft_mute)
++		buffer[3] |= TEA5767_SOFT_MUTE;
++
++	if (priv->ctrl.japan_band)
++		buffer[3] |= TEA5767_JAPAN_BAND;
++
++	buffer[4] = 0;
++
++	if (priv->ctrl.deemph_75)
++		buffer[4] |= TEA5767_DEEMPH_75;
++
++	if (priv->ctrl.pllref)
++		buffer[4] |= TEA5767_PLLREF_ENABLE;
++
++
++	/* Rounds freq to next decimal value - for 62.5 KHz step */
++	/* frq = 20*(frq/16)+radio_frq[frq%16]; */
++
++	switch (priv->ctrl.xtal_freq) {
+ 	case TEA5767_HIGH_LO_13MHz:
+ 		tuner_dbg("radio HIGH LO inject xtal @ 13 MHz\n");
+ 		buffer[2] |= TEA5767_HIGH_LO_INJECT;
+-		buffer[4] |= TEA5767_PLLREF_ENABLE;
+ 		div = (frq * (4000 / 16) + 700000 + 225000 + 25000) / 50000;
+ 		break;
+ 	case TEA5767_LOW_LO_13MHz:
+ 		tuner_dbg("radio LOW LO inject xtal @ 13 MHz\n");
  
--		if (0 != t->index)
--			return -EINVAL;
--		memset(t,0,sizeof(*t));
--		for (n = 0; n < SAA7134_INPUT_MAX; n++)
--			if (card_in(dev,n).tv)
--				break;
--		if (NULL != card_in(dev,n).name) {
--			strcpy(t->name, "Television");
--			t->type = V4L2_TUNER_ANALOG_TV;
--			t->capability = V4L2_TUNER_CAP_NORM |
--				V4L2_TUNER_CAP_STEREO |
--				V4L2_TUNER_CAP_LANG1 |
--				V4L2_TUNER_CAP_LANG2;
--			t->rangehigh = 0xffffffffUL;
--			t->rxsubchans = saa7134_tvaudio_getstereo(dev);
--			t->audmode = saa7134_tvaudio_rx2mode(t->rxsubchans);
--		}
--		if (0 != (saa_readb(SAA7134_STATUS_VIDEO1) & 0x03))
--			t->signal = 0xffff;
--		return 0;
--	}
--	case VIDIOC_S_TUNER:
--	{
--		struct v4l2_tuner *t = arg;
--		int rx,mode;
-+	if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
-+	    crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
-+		return -EINVAL;
-+	crop->c = dev->crop_current;
+-		buffer[4] |= TEA5767_PLLREF_ENABLE;
+ 		div = (frq * (4000 / 16) - 700000 - 225000 + 25000) / 50000;
+ 		break;
+ 	case TEA5767_LOW_LO_32768:
+@@ -256,7 +275,7 @@ static int set_radio_freq(struct dvb_frontend *fe,
+ 		if (5 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 5)))
+ 			tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc);
+ 		else
+-			tea5767_status_dump(buffer);
++			tea5767_status_dump(priv, buffer);
+ 	}
+ 
+ 	priv->frequency = frq * 125 / 2;
+@@ -382,7 +401,6 @@ int tea5767_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr)
+ 		return EINVAL;
+ 	}
+ 
+-	printk(KERN_WARNING "TEA5767 detected.\n");
+ 	return 0;
+ }
+ 
+@@ -398,6 +416,16 @@ static int tea5767_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+ {
+ 	struct tea5767_priv *priv = fe->tuner_priv;
+ 	*frequency = priv->frequency;
++
 +	return 0;
 +}
- 
--		mode = dev->thread.mode;
--		if (UNSET == mode) {
--			rx   = saa7134_tvaudio_getstereo(dev);
--			mode = saa7134_tvaudio_rx2mode(t->rxsubchans);
--		}
--		if (mode != t->audmode) {
--			dev->thread.mode = t->audmode;
--		}
--		return 0;
--	}
--	case VIDIOC_G_FREQUENCY:
--	{
--		struct v4l2_frequency *f = arg;
-+static int saa7134_s_crop(struct file *file, void *f, struct v4l2_crop *crop)
++
++static int tea5767_set_config (struct dvb_frontend *fe, void *priv_cfg)
 +{
-+	struct saa7134_fh *fh = f;
-+	struct saa7134_dev *dev = fh->dev;
-+	struct v4l2_rect *b = &dev->crop_bounds;
++	struct tea5767_priv *priv = fe->tuner_priv;
++
++	memcpy(&priv->ctrl, priv_cfg, sizeof(priv->ctrl));
++
+ 	return 0;
+ }
  
--		memset(f,0,sizeof(*f));
--		f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
--		f->frequency = dev->ctl_freq;
--		return 0;
--	}
--	case VIDIOC_S_FREQUENCY:
--	{
--		struct v4l2_frequency *f = arg;
-+	if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
-+	    crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
-+		return -EINVAL;
-+	if (crop->c.height < 0)
-+		return -EINVAL;
-+	if (crop->c.width < 0)
-+		return -EINVAL;
+@@ -407,6 +435,7 @@ static struct dvb_tuner_ops tea5767_tuner_ops = {
+ 	},
  
--		if (0 != f->tuner)
--			return -EINVAL;
--		if (0 == fh->radio && V4L2_TUNER_ANALOG_TV != f->type)
--			return -EINVAL;
--		if (1 == fh->radio && V4L2_TUNER_RADIO != f->type)
--			return -EINVAL;
--		mutex_lock(&dev->lock);
--		dev->ctl_freq = f->frequency;
-+	if (res_locked(fh->dev, RESOURCE_OVERLAY))
-+		return -EBUSY;
-+	if (res_locked(fh->dev, RESOURCE_VIDEO))
-+		return -EBUSY;
-+
-+	if (crop->c.top < b->top)
-+		crop->c.top = b->top;
-+	if (crop->c.top > b->top + b->height)
-+		crop->c.top = b->top + b->height;
-+	if (crop->c.height > b->top - crop->c.top + b->height)
-+		crop->c.height = b->top - crop->c.top + b->height;
+ 	.set_analog_params = set_radio_freq,
++	.set_config	   = tea5767_set_config,
+ 	.sleep             = tea5767_standby,
+ 	.release           = tea5767_release,
+ 	.get_frequency     = tea5767_get_frequency,
+@@ -425,8 +454,14 @@ struct dvb_frontend *tea5767_attach(struct dvb_frontend *fe,
+ 		return NULL;
+ 	fe->tuner_priv = priv;
+ 
+-	priv->i2c_props.addr = i2c_addr;
+-	priv->i2c_props.adap = i2c_adap;
++	priv->i2c_props.addr  = i2c_addr;
++	priv->i2c_props.adap  = i2c_adap;
++	priv->ctrl.xtal_freq  = TEA5767_HIGH_LO_32768;
++	priv->ctrl.port1      = 1;
++	priv->ctrl.port2      = 1;
++	priv->ctrl.high_cut   = 1;
++	priv->ctrl.st_noise   = 1;
++	priv->ctrl.japan_band = 1;
+ 
+ 	memcpy(&fe->ops.tuner_ops, &tea5767_tuner_ops,
+ 	       sizeof(struct dvb_tuner_ops));
+@@ -436,7 +471,6 @@ struct dvb_frontend *tea5767_attach(struct dvb_frontend *fe,
+ 	return fe;
+ }
+ 
+-
+ EXPORT_SYMBOL_GPL(tea5767_attach);
+ EXPORT_SYMBOL_GPL(tea5767_autodetection);
+ 
+diff --git a/drivers/media/video/tea5767.h b/drivers/media/video/tea5767.h
+index 5d78281..a44451f 100644
+--- a/drivers/media/video/tea5767.h
++++ b/drivers/media/video/tea5767.h
+@@ -20,6 +20,25 @@
+ #include <linux/i2c.h>
+ #include "dvb_frontend.h"
+ 
++enum tea5767_xtal {
++	TEA5767_LOW_LO_32768    = 0,
++	TEA5767_HIGH_LO_32768   = 1,
++	TEA5767_LOW_LO_13MHz    = 2,
++	TEA5767_HIGH_LO_13MHz   = 3,
++};
 +
-+	if (crop->c.left < b->left)
-+		crop->c.left = b->left;
-+	if (crop->c.left > b->left + b->width)
-+		crop->c.left = b->left + b->width;
-+	if (crop->c.width > b->left - crop->c.left + b->width)
-+		crop->c.width = b->left - crop->c.left + b->width;
++struct tea5767_ctrl {
++	unsigned int		port1:1;
++	unsigned int		port2:1;
++	unsigned int		high_cut:1;
++	unsigned int		st_noise:1;
++	unsigned int		soft_mute:1;
++	unsigned int		japan_band:1;
++	unsigned int		deemph_75:1;
++	unsigned int		pllref:1;
++	enum tea5767_xtal	xtal_freq;
++};
 +
-+	dev->crop_current = crop->c;
-+	return 0;
-+}
+ #if defined(CONFIG_TUNER_TEA5767) || (defined(CONFIG_TUNER_TEA5767_MODULE) && defined(MODULE))
+ extern int tea5767_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr);
  
--		saa7134_i2c_call_clients(dev,VIDIOC_S_FREQUENCY,f);
-+static int saa7134_g_tuner(struct file *file, void *priv,
-+					struct v4l2_tuner *t)
-+{
-+	struct saa7134_fh *fh = priv;
-+	struct saa7134_dev *dev = fh->dev;
-+	int n;
+diff --git a/drivers/media/video/tlv320aic23b.c b/drivers/media/video/tlv320aic23b.c
+index 76b2e96..dc7b9c2 100644
+--- a/drivers/media/video/tlv320aic23b.c
++++ b/drivers/media/video/tlv320aic23b.c
+@@ -31,6 +31,7 @@
+ #include <linux/i2c-id.h>
+ #include <linux/videodev.h>
+ #include <media/v4l2-common.h>
++#include <media/v4l2-i2c-drv-legacy.h>
  
--		saa7134_tvaudio_do_scan(dev);
--		mutex_unlock(&dev->lock);
--		return 0;
+ MODULE_DESCRIPTION("tlv320aic23b driver");
+ MODULE_AUTHOR("Scott Alfter, Ulf Eklund, Hans Verkuil");
+@@ -56,37 +57,35 @@ static int tlv320aic23b_write(struct i2c_client *client, int reg, u16 val)
+ 		return -1;
+ 	}
+ 
+-	for (i = 0; i < 3; i++) {
+-		if (i2c_smbus_write_byte_data(client, (reg << 1) |
+-					(val >> 8), val & 0xff) == 0) {
++	for (i = 0; i < 3; i++)
++		if (i2c_smbus_write_byte_data(client,
++				(reg << 1) | (val >> 8), val & 0xff) == 0)
+ 			return 0;
+-		}
 -	}
-+	if (0 != t->index)
-+		return -EINVAL;
-+	memset(t, 0, sizeof(*t));
-+	for (n = 0; n < SAA7134_INPUT_MAX; n++)
-+		if (card_in(dev, n).tv)
-+			break;
-+	if (NULL != card_in(dev, n).name) {
-+		strcpy(t->name, "Television");
-+		t->type = V4L2_TUNER_ANALOG_TV;
-+		t->capability = V4L2_TUNER_CAP_NORM |
-+			V4L2_TUNER_CAP_STEREO |
-+			V4L2_TUNER_CAP_LANG1 |
-+			V4L2_TUNER_CAP_LANG2;
-+		t->rangehigh = 0xffffffffUL;
-+		t->rxsubchans = saa7134_tvaudio_getstereo(dev);
-+		t->audmode = saa7134_tvaudio_rx2mode(t->rxsubchans);
-+	}
-+	if (0 != (saa_readb(SAA7134_STATUS_VIDEO1) & 0x03))
-+		t->signal = 0xffff;
-+	return 0;
-+}
+ 	v4l_err(client, "I2C: cannot write %03x to register R%d\n", val, reg);
+ 	return -1;
+ }
  
--	/* --- control ioctls ---------------------------------------- */
--	case VIDIOC_ENUMINPUT:
--	case VIDIOC_G_INPUT:
--	case VIDIOC_S_INPUT:
--	case VIDIOC_QUERYCTRL:
--	case VIDIOC_G_CTRL:
--	case VIDIOC_S_CTRL:
--		return saa7134_common_ioctl(dev, cmd, arg);
-+static int saa7134_s_tuner(struct file *file, void *priv,
-+					struct v4l2_tuner *t)
-+{
-+	struct saa7134_fh *fh = priv;
-+	struct saa7134_dev *dev = fh->dev;
-+	int rx, mode, err;
+-static int tlv320aic23b_command(struct i2c_client *client, unsigned int cmd,
+-			  void *arg)
++static int tlv320aic23b_command(struct i2c_client *client,
++				unsigned int cmd, void *arg)
+ {
+ 	struct tlv320aic23b_state *state = i2c_get_clientdata(client);
+ 	struct v4l2_control *ctrl = arg;
+-	u32* freq = arg;
++	u32 *freq = arg;
  
--	case VIDIOC_G_AUDIO:
--	{
--		struct v4l2_audio *a = arg;
-+	err = v4l2_prio_check(&dev->prio, &fh->prio);
-+	if (0 != err)
-+		return err;
+ 	switch (cmd) {
+ 	case VIDIOC_INT_AUDIO_CLOCK_FREQ:
+ 		switch (*freq) {
+-			case 32000: /* set sample rate to 32 kHz */
+-				tlv320aic23b_write(client, 8, 0x018);
+-				break;
+-			case 44100: /* set sample rate to 44.1 kHz */
+-				tlv320aic23b_write(client, 8, 0x022);
+-				break;
+-			case 48000: /* set sample rate to 48 kHz */
+-				tlv320aic23b_write(client, 8, 0x000);
+-				break;
+-			default:
+-				return -EINVAL;
++		case 32000: /* set sample rate to 32 kHz */
++			tlv320aic23b_write(client, 8, 0x018);
++			break;
++		case 44100: /* set sample rate to 44.1 kHz */
++			tlv320aic23b_write(client, 8, 0x022);
++			break;
++		case 48000: /* set sample rate to 48 kHz */
++			tlv320aic23b_write(client, 8, 0x000);
++			break;
++		default:
++			return -EINVAL;
+ 		}
+ 		break;
  
--		memset(a,0,sizeof(*a));
--		strcpy(a->name,"audio");
--		return 0;
--	}
--	case VIDIOC_S_AUDIO:
--		return 0;
--	case VIDIOC_G_PARM:
--	{
--		struct v4l2_captureparm *parm = arg;
--		memset(parm,0,sizeof(*parm));
--		return 0;
-+	mode = dev->thread.mode;
-+	if (UNSET == mode) {
-+		rx   = saa7134_tvaudio_getstereo(dev);
-+		mode = saa7134_tvaudio_rx2mode(t->rxsubchans);
- 	}
-+	if (mode != t->audmode)
-+		dev->thread.mode = t->audmode;
+@@ -126,92 +125,53 @@ static int tlv320aic23b_command(struct i2c_client *client, unsigned int cmd,
+  * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
+  */
  
--	case VIDIOC_G_PRIORITY:
--	{
--		enum v4l2_priority *p = arg;
-+	return 0;
-+}
+-static struct i2c_driver i2c_driver;
+-
+-static int tlv320aic23b_attach(struct i2c_adapter *adapter, int address, int kind)
++static int tlv320aic23b_probe(struct i2c_client *client)
+ {
+-	struct i2c_client *client;
+ 	struct tlv320aic23b_state *state;
  
--		*p = v4l2_prio_max(&dev->prio);
+ 	/* Check if the adapter supports the needed features */
+-	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
 -		return 0;
--	}
--	case VIDIOC_S_PRIORITY:
--	{
--		enum v4l2_priority *prio = arg;
-+static int saa7134_g_frequency(struct file *file, void *priv,
-+					struct v4l2_frequency *f)
-+{
-+	struct saa7134_fh *fh = priv;
-+	struct saa7134_dev *dev = fh->dev;
+-
+-	client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
+-	if (client == 0)
+-		return -ENOMEM;
+-
+-	client->addr = address;
+-	client->adapter = adapter;
+-	client->driver = &i2c_driver;
+-	snprintf(client->name, sizeof(client->name) - 1, "tlv320aic23b");
++	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
++		return -EIO;
  
--		return v4l2_prio_change(&dev->prio, &fh->prio, *prio);
+-	v4l_info(client, "chip found @ 0x%x (%s)\n", address << 1, adapter->name);
++	v4l_info(client, "chip found @ 0x%x (%s)\n",
++			client->addr << 1, client->adapter->name);
+ 
+ 	state = kmalloc(sizeof(struct tlv320aic23b_state), GFP_KERNEL);
+-	if (state == NULL) {
+-		kfree(client);
++	if (state == NULL)
+ 		return -ENOMEM;
 -	}
-+	f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
-+	f->frequency = dev->ctl_freq;
+ 	state->muted = 0;
+ 	i2c_set_clientdata(client, state);
  
--	/* --- preview ioctls ---------------------------------------- */
--	case VIDIOC_ENUM_FMT:
--	{
--		struct v4l2_fmtdesc *f = arg;
--		enum v4l2_buf_type type;
--		unsigned int index;
+-	/* initialize tlv320aic23b */
+-	tlv320aic23b_write(client, 15, 0x000);	/* RESET */
+-	tlv320aic23b_write(client, 6, 0x00A);   /* turn off DAC & mic input */
+-	tlv320aic23b_write(client, 7, 0x049);   /* left-justified, 24-bit, master mode */
+-	tlv320aic23b_write(client, 0, 0x119);   /* set gain on both channels to +3.0 dB */
+-	tlv320aic23b_write(client, 8, 0x000);   /* set sample rate to 48 kHz */
+-	tlv320aic23b_write(client, 9, 0x001);   /* activate digital interface */
 -
--		index = f->index;
--		type  = f->type;
--		switch (type) {
--		case V4L2_BUF_TYPE_VIDEO_CAPTURE:
--		case V4L2_BUF_TYPE_VIDEO_OVERLAY:
--			if (saa7134_no_overlay > 0) {
--				printk ("V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
--				return -EINVAL;
--			}
--			if (index >= FORMATS)
--				return -EINVAL;
--			if (f->type == V4L2_BUF_TYPE_VIDEO_OVERLAY &&
--			    formats[index].planar)
--				return -EINVAL;
--			memset(f,0,sizeof(*f));
--			f->index = index;
--			f->type  = type;
--			strlcpy(f->description,formats[index].name,sizeof(f->description));
--			f->pixelformat = formats[index].fourcc;
--			break;
--		case V4L2_BUF_TYPE_VBI_CAPTURE:
--			if (0 != index)
--				return -EINVAL;
--			memset(f,0,sizeof(*f));
--			f->index = index;
--			f->type  = type;
--			f->pixelformat = V4L2_PIX_FMT_GREY;
--			strcpy(f->description,"vbi data");
--			break;
--		default:
--			return -EINVAL;
--		}
--		return 0;
--	}
--	case VIDIOC_G_FBUF:
--	{
--		struct v4l2_framebuffer *fb = arg;
-+	return 0;
-+}
+-	i2c_attach_client(client);
+-
++	/* Initialize tlv320aic23b */
++
++	/* RESET */
++	tlv320aic23b_write(client, 15, 0x000);
++	/* turn off DAC & mic input */
++	tlv320aic23b_write(client, 6, 0x00A);
++	/* left-justified, 24-bit, master mode */
++	tlv320aic23b_write(client, 7, 0x049);
++	/* set gain on both channels to +3.0 dB */
++	tlv320aic23b_write(client, 0, 0x119);
++	/* set sample rate to 48 kHz */
++	tlv320aic23b_write(client, 8, 0x000);
++	/* activate digital interface */
++	tlv320aic23b_write(client, 9, 0x001);
+ 	return 0;
+ }
  
--		*fb = dev->ovbuf;
--		fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING;
--		return 0;
+-static int tlv320aic23b_probe(struct i2c_adapter *adapter)
++static int tlv320aic23b_remove(struct i2c_client *client)
+ {
+-	if (adapter->class & I2C_CLASS_TV_ANALOG)
+-		return i2c_probe(adapter, &addr_data, tlv320aic23b_attach);
+-	return 0;
+-}
+-
+-static int tlv320aic23b_detach(struct i2c_client *client)
+-{
+-	int err;
+-
+-	err = i2c_detach_client(client);
+-	if (err) {
+-		return err;
 -	}
--	case VIDIOC_S_FBUF:
--	{
--		struct v4l2_framebuffer *fb = arg;
--		struct saa7134_format *fmt;
-+static int saa7134_s_frequency(struct file *file, void *priv,
-+					struct v4l2_frequency *f)
-+{
-+	struct saa7134_fh *fh = priv;
-+	struct saa7134_dev *dev = fh->dev;
-+	int err;
+-	kfree(client);
+-
++	kfree(i2c_get_clientdata(client));
+ 	return 0;
+ }
  
--		if(!capable(CAP_SYS_ADMIN) &&
--		   !capable(CAP_SYS_RAWIO))
--			return -EPERM;
-+	err = v4l2_prio_check(&dev->prio, &fh->prio);
-+	if (0 != err)
-+		return err;
+ /* ----------------------------------------------------------------------- */
  
--		/* check args */
--		fmt = format_by_fourcc(fb->fmt.pixelformat);
--		if (NULL == fmt)
--			return -EINVAL;
-+	if (0 != f->tuner)
-+		return -EINVAL;
-+	if (0 == fh->radio && V4L2_TUNER_ANALOG_TV != f->type)
-+		return -EINVAL;
-+	if (1 == fh->radio && V4L2_TUNER_RADIO != f->type)
-+		return -EINVAL;
-+	mutex_lock(&dev->lock);
-+	dev->ctl_freq = f->frequency;
+-/* i2c implementation */
+-static struct i2c_driver i2c_driver = {
+-	.driver = {
+-		.name = "tlv320aic23b",
+-	},
+-	.id             = I2C_DRIVERID_TLV320AIC23B,
+-	.attach_adapter = tlv320aic23b_probe,
+-	.detach_client  = tlv320aic23b_detach,
+-	.command        = tlv320aic23b_command,
+-};
+-
  
--		/* ok, accept it */
--		dev->ovbuf = *fb;
--		dev->ovfmt = fmt;
--		if (0 == dev->ovbuf.fmt.bytesperline)
--			dev->ovbuf.fmt.bytesperline =
--				dev->ovbuf.fmt.width*fmt->depth/8;
--		return 0;
-+	saa7134_i2c_call_clients(dev, VIDIOC_S_FREQUENCY, f);
-+
-+	saa7134_tvaudio_do_scan(dev);
-+	mutex_unlock(&dev->lock);
-+	return 0;
-+}
-+
-+static int saa7134_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
-+{
-+	strcpy(a->name, "audio");
-+	return 0;
-+}
+-static int __init tlv320aic23b_init_module(void)
+-{
+-	return i2c_add_driver(&i2c_driver);
+-}
+-
+-static void __exit tlv320aic23b_cleanup_module(void)
+-{
+-	i2c_del_driver(&i2c_driver);
+-}
+-
+-module_init(tlv320aic23b_init_module);
+-module_exit(tlv320aic23b_cleanup_module);
++static struct v4l2_i2c_driver_data v4l2_i2c_data = {
++	.name = "tlv320aic23b",
++	.driverid = I2C_DRIVERID_TLV320AIC23B,
++	.command = tlv320aic23b_command,
++	.probe = tlv320aic23b_probe,
++	.remove = tlv320aic23b_remove,
++};
+diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c
+index 9e99f36..ba538f6 100644
+--- a/drivers/media/video/tuner-core.c
++++ b/drivers/media/video/tuner-core.c
+@@ -19,15 +19,41 @@
+ #include <media/tuner.h>
+ #include <media/tuner-types.h>
+ #include <media/v4l2-common.h>
+-#include "tuner-driver.h"
++#include <media/v4l2-i2c-drv-legacy.h>
+ #include "mt20xx.h"
+ #include "tda8290.h"
+ #include "tea5761.h"
+ #include "tea5767.h"
++#include "tuner-xc2028.h"
+ #include "tuner-simple.h"
++#include "tda9887.h"
++#include "xc5000.h"
+ 
+ #define UNSET (-1U)
+ 
++#define PREFIX t->i2c->driver->driver.name
 +
-+static int saa7134_s_audio(struct file *file, void *priv, struct v4l2_audio *a)
-+{
-+	return 0;
-+}
++struct tuner {
++	/* device */
++	struct dvb_frontend fe;
++	struct i2c_client   *i2c;
++	struct list_head    list;
++	unsigned int        using_v4l2:1;
 +
-+static int saa7134_g_priority(struct file *file, void *f, enum v4l2_priority *p)
-+{
-+	struct saa7134_fh *fh = f;
-+	struct saa7134_dev *dev = fh->dev;
++	/* keep track of the current settings */
++	v4l2_std_id         std;
++	unsigned int        tv_freq;
++	unsigned int        radio_freq;
++	unsigned int        audmode;
 +
-+	*p = v4l2_prio_max(&dev->prio);
-+	return 0;
-+}
++	unsigned int        mode;
++	unsigned int        mode_mask; /* Combination of allowable modes */
 +
-+static int saa7134_s_priority(struct file *file, void *f,
-+					enum v4l2_priority prio)
-+{
-+	struct saa7134_fh *fh = f;
-+	struct saa7134_dev *dev = fh->dev;
++	unsigned int        type; /* chip type id */
++	unsigned int        config;
++	int (*tuner_callback) (void *dev, int command, int arg);
++};
 +
-+	return v4l2_prio_change(&dev->prio, &fh->prio, prio);
-+}
+ /* standard i2c insmod options */
+ static unsigned short normal_i2c[] = {
+ #if defined(CONFIG_TUNER_TEA5761) || (defined(CONFIG_TUNER_TEA5761_MODULE) && defined(MODULE))
+@@ -47,7 +73,34 @@ static unsigned int no_autodetect = 0;
+ static unsigned int show_i2c = 0;
+ 
+ /* insmod options used at runtime => read/write */
+-int tuner_debug = 0;
++static int tuner_debug;
 +
-+static int saa7134_enum_fmt_cap(struct file *file, void  *priv,
-+					struct v4l2_fmtdesc *f)
-+{
-+	if (f->index >= FORMATS)
-+		return -EINVAL;
++#define tuner_warn(fmt, arg...) do {			\
++	printk(KERN_WARNING "%s %d-%04x: " fmt, PREFIX, \
++	       i2c_adapter_id(t->i2c->adapter),		\
++	       t->i2c->addr, ##arg);			\
++	 } while (0)
 +
-+	strlcpy(f->description, formats[f->index].name,
-+		sizeof(f->description));
++#define tuner_info(fmt, arg...) do {			\
++	printk(KERN_INFO "%s %d-%04x: " fmt, PREFIX,	\
++	       i2c_adapter_id(t->i2c->adapter),		\
++	       t->i2c->addr, ##arg);			\
++	 } while (0)
 +
-+	f->pixelformat = formats[f->index].fourcc;
++#define tuner_err(fmt, arg...) do {			\
++	printk(KERN_ERR "%s %d-%04x: " fmt, PREFIX,	\
++	       i2c_adapter_id(t->i2c->adapter),		\
++	       t->i2c->addr, ##arg);			\
++	 } while (0)
 +
-+	return 0;
-+}
++#define tuner_dbg(fmt, arg...) do {				\
++	if (tuner_debug)					\
++		printk(KERN_DEBUG "%s %d-%04x: " fmt, PREFIX,	\
++		       i2c_adapter_id(t->i2c->adapter),		\
++		       t->i2c->addr, ##arg);			\
++	 } while (0)
 +
-+static int saa7134_enum_fmt_overlay(struct file *file, void  *priv,
-+					struct v4l2_fmtdesc *f)
-+{
-+	if (saa7134_no_overlay > 0) {
-+		printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
-+		return -EINVAL;
- 	}
--	case VIDIOC_OVERLAY:
--	{
--		int *on = arg;
++/* ------------------------------------------------------------------------ */
  
--		if (*on) {
--			if (saa7134_no_overlay > 0) {
--				printk ("no_overlay\n");
--				return -EINVAL;
--			}
-+	if ((f->index >= FORMATS) || formats[f->index].planar)
-+		return -EINVAL;
+ static unsigned int tv_range[2] = { 44, 958 };
+ static unsigned int radio_range[2] = { 65, 108 };
+@@ -71,66 +124,96 @@ MODULE_DESCRIPTION("device driver for various TV and TV+FM radio tuners");
+ MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer");
+ MODULE_LICENSE("GPL");
  
--			if (!res_get(dev,fh,RESOURCE_OVERLAY))
--				return -EBUSY;
--			spin_lock_irqsave(&dev->slock,flags);
--			start_preview(dev,fh);
--			spin_unlock_irqrestore(&dev->slock,flags);
--		}
--		if (!*on) {
--			if (!res_check(fh, RESOURCE_OVERLAY))
--				return -EINVAL;
--			spin_lock_irqsave(&dev->slock,flags);
--			stop_preview(dev,fh);
--			spin_unlock_irqrestore(&dev->slock,flags);
--			res_free(dev,fh,RESOURCE_OVERLAY);
-+	strlcpy(f->description, formats[f->index].name,
-+		sizeof(f->description));
-+
-+	f->pixelformat = formats[f->index].fourcc;
-+
-+	return 0;
-+}
+-static struct i2c_driver driver;
+-static struct i2c_client client_template;
+-
+ /* ---------------------------------------------------------------------- */
+ 
+-static void fe_set_freq(struct tuner *t, unsigned int freq)
++static void fe_set_params(struct dvb_frontend *fe,
++			  struct analog_parameters *params)
+ {
+-	struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
+-
+-	struct analog_parameters params = {
+-		.frequency = freq,
+-		.mode      = t->mode,
+-		.audmode   = t->audmode,
+-		.std       = t->std
+-	};
++	struct dvb_tuner_ops *fe_tuner_ops = &fe->ops.tuner_ops;
++	struct tuner *t = fe->analog_demod_priv;
+ 
+ 	if (NULL == fe_tuner_ops->set_analog_params) {
+ 		tuner_warn("Tuner frontend module has no way to set freq\n");
+ 		return;
+ 	}
+-	fe_tuner_ops->set_analog_params(&t->fe, &params);
++	fe_tuner_ops->set_analog_params(fe, params);
+ }
+ 
+-static void fe_release(struct tuner *t)
++static void fe_release(struct dvb_frontend *fe)
+ {
+-	struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
+-
+-	if (fe_tuner_ops->release)
+-		fe_tuner_ops->release(&t->fe);
++	if (fe->ops.tuner_ops.release)
++		fe->ops.tuner_ops.release(fe);
 +
-+static int saa7134_enum_fmt_vbi(struct file *file, void  *priv,
-+					struct v4l2_fmtdesc *f)
++	/* DO NOT kfree(fe->analog_demod_priv)
++	 *
++	 * If we are in this function, analog_demod_priv contains a pointer
++	 * to struct tuner *t.  This will be kfree'd in tuner_detach().
++	 *
++	 * Otherwise, fe->ops.analog_demod_ops->release will
++	 * handle the cleanup for analog demodulator modules.
++	 */
++	fe->analog_demod_priv = NULL;
+ }
+ 
+-static void fe_standby(struct tuner *t)
++static void fe_standby(struct dvb_frontend *fe)
+ {
+-	struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
++	struct dvb_tuner_ops *fe_tuner_ops = &fe->ops.tuner_ops;
+ 
+ 	if (fe_tuner_ops->sleep)
+-		fe_tuner_ops->sleep(&t->fe);
++		fe_tuner_ops->sleep(fe);
+ }
+ 
+-static int fe_has_signal(struct tuner *t)
++static int fe_has_signal(struct dvb_frontend *fe)
+ {
+-	struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
+ 	u16 strength = 0;
+ 
+-	if (fe_tuner_ops->get_rf_strength)
+-		fe_tuner_ops->get_rf_strength(&t->fe, &strength);
++	if (fe->ops.tuner_ops.get_rf_strength)
++		fe->ops.tuner_ops.get_rf_strength(fe, &strength);
+ 
+ 	return strength;
+ }
+ 
++static int fe_set_config(struct dvb_frontend *fe, void *priv_cfg)
 +{
-+	if (0 != f->index)
-+		return -EINVAL;
-+
-+	f->pixelformat = V4L2_PIX_FMT_GREY;
-+	strcpy(f->description, "vbi data");
-+
-+	return 0;
-+}
++	struct dvb_tuner_ops *fe_tuner_ops = &fe->ops.tuner_ops;
++	struct tuner *t = fe->analog_demod_priv;
 +
-+static int saa7134_g_fbuf(struct file *file, void *f,
-+				struct v4l2_framebuffer *fb)
-+{
-+	struct saa7134_fh *fh = f;
-+	struct saa7134_dev *dev = fh->dev;
++	if (fe_tuner_ops->set_config)
++		return fe_tuner_ops->set_config(fe, priv_cfg);
 +
-+	*fb = dev->ovbuf;
-+	fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING;
++	tuner_warn("Tuner frontend module has no way to set config\n");
 +
 +	return 0;
 +}
 +
-+static int saa7134_s_fbuf(struct file *file, void *f,
-+					struct v4l2_framebuffer *fb)
-+{
-+	struct saa7134_fh *fh = f;
-+	struct saa7134_dev *dev = fh->dev;
-+	struct saa7134_format *fmt;
-+
-+	if (!capable(CAP_SYS_ADMIN) &&
-+	   !capable(CAP_SYS_RAWIO))
-+		return -EPERM;
-+
-+	/* check args */
-+	fmt = format_by_fourcc(fb->fmt.pixelformat);
-+	if (NULL == fmt)
-+		return -EINVAL;
++static void tuner_status(struct dvb_frontend *fe);
 +
-+	/* ok, accept it */
-+	dev->ovbuf = *fb;
-+	dev->ovfmt = fmt;
-+	if (0 == dev->ovbuf.fmt.bytesperline)
-+		dev->ovbuf.fmt.bytesperline =
-+			dev->ovbuf.fmt.width*fmt->depth/8;
-+	return 0;
-+}
++static struct analog_demod_ops tuner_core_ops = {
++	.set_params     = fe_set_params,
++	.standby        = fe_standby,
++	.release        = fe_release,
++	.has_signal     = fe_has_signal,
++	.set_config     = fe_set_config,
++	.tuner_status   = tuner_status
++};
 +
-+static int saa7134_overlay(struct file *file, void *f, unsigned int on)
-+{
-+	struct saa7134_fh *fh = f;
-+	struct saa7134_dev *dev = fh->dev;
-+	unsigned long flags;
+ /* Set tuner frequency,  freq in Units of 62.5kHz = 1/16MHz */
+ static void set_tv_freq(struct i2c_client *c, unsigned int freq)
+ {
+ 	struct tuner *t = i2c_get_clientdata(c);
++	struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
 +
-+	if (on) {
-+		if (saa7134_no_overlay > 0) {
-+			dprintk("no_overlay\n");
-+			return -EINVAL;
- 		}
--		return 0;
--	}
++	struct analog_parameters params = {
++		.mode      = t->mode,
++		.audmode   = t->audmode,
++		.std       = t->std
++	};
  
--	/* --- capture ioctls ---------------------------------------- */
--	case VIDIOC_G_FMT:
--	{
--		struct v4l2_format *f = arg;
--		return saa7134_g_fmt(dev,fh,f);
--	}
--	case VIDIOC_S_FMT:
--	{
--		struct v4l2_format *f = arg;
--		return saa7134_s_fmt(dev,fh,f);
-+		if (!res_get(dev, fh, RESOURCE_OVERLAY))
-+			return -EBUSY;
-+		spin_lock_irqsave(&dev->slock, flags);
-+		start_preview(dev, fh);
-+		spin_unlock_irqrestore(&dev->slock, flags);
+ 	if (t->type == UNSET) {
+ 		tuner_warn ("tuner type not set\n");
+ 		return;
  	}
--	case VIDIOC_TRY_FMT:
--	{
--		struct v4l2_format *f = arg;
--		return saa7134_try_fmt(dev,fh,f);
-+	if (!on) {
-+		if (!res_check(fh, RESOURCE_OVERLAY))
-+			return -EINVAL;
-+		spin_lock_irqsave(&dev->slock, flags);
-+		stop_preview(dev, fh);
-+		spin_unlock_irqrestore(&dev->slock, flags);
-+		res_free(dev, fh, RESOURCE_OVERLAY);
+-	if (NULL == t->ops.set_tv_freq) {
++	if (NULL == analog_ops->set_params) {
+ 		tuner_warn ("Tuner has no way to set tv freq\n");
+ 		return;
  	}
-+	return 0;
-+}
+@@ -145,18 +228,27 @@ static void set_tv_freq(struct i2c_client *c, unsigned int freq)
+ 		else
+ 			freq = tv_range[1] * 16;
+ 	}
+-	t->ops.set_tv_freq(t, freq);
++	params.frequency = freq;
 +
- #ifdef CONFIG_VIDEO_V4L1_COMPAT
--	case VIDIOCGMBUF:
--		return videobuf_cgmbuf(saa7134_queue(fh), arg, gbuffers);
-+static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf)
-+{
-+	struct saa7134_fh *fh = file->private_data;
-+	return videobuf_cgmbuf(saa7134_queue(fh), mbuf, 8);
-+}
- #endif
--	case VIDIOC_REQBUFS:
--		return videobuf_reqbufs(saa7134_queue(fh),arg);
- 
--	case VIDIOC_QUERYBUF:
--		return videobuf_querybuf(saa7134_queue(fh),arg);
-+static int saa7134_reqbufs(struct file *file, void *priv,
-+					struct v4l2_requestbuffers *p)
-+{
-+	struct saa7134_fh *fh = priv;
-+	return videobuf_reqbufs(saa7134_queue(fh), p);
-+}
- 
--	case VIDIOC_QBUF:
--		return videobuf_qbuf(saa7134_queue(fh),arg);
-+static int saa7134_querybuf(struct file *file, void *priv,
-+					struct v4l2_buffer *b)
-+{
-+	struct saa7134_fh *fh = priv;
-+	return videobuf_querybuf(saa7134_queue(fh), b);
-+}
++	analog_ops->set_params(&t->fe, &params);
+ }
  
--	case VIDIOC_DQBUF:
--		return videobuf_dqbuf(saa7134_queue(fh),arg,
--				      file->f_flags & O_NONBLOCK);
-+static int saa7134_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
-+{
-+	struct saa7134_fh *fh = priv;
-+	return videobuf_qbuf(saa7134_queue(fh), b);
-+}
+ static void set_radio_freq(struct i2c_client *c, unsigned int freq)
+ {
+ 	struct tuner *t = i2c_get_clientdata(c);
++	struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
++
++	struct analog_parameters params = {
++		.mode      = t->mode,
++		.audmode   = t->audmode,
++		.std       = t->std
++	};
  
--	case VIDIOC_STREAMON:
--	{
--		int res = saa7134_resource(fh);
-+static int saa7134_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
-+{
-+	struct saa7134_fh *fh = priv;
-+	return videobuf_dqbuf(saa7134_queue(fh), b,
-+				file->f_flags & O_NONBLOCK);
-+}
+ 	if (t->type == UNSET) {
+ 		tuner_warn ("tuner type not set\n");
+ 		return;
+ 	}
+-	if (NULL == t->ops.set_radio_freq) {
++	if (NULL == analog_ops->set_params) {
+ 		tuner_warn ("tuner has no way to set radio frequency\n");
+ 		return;
+ 	}
+@@ -171,8 +263,9 @@ static void set_radio_freq(struct i2c_client *c, unsigned int freq)
+ 		else
+ 			freq = radio_range[1] * 16000;
+ 	}
++	params.frequency = freq;
  
--		if (!res_get(dev,fh,res))
--			return -EBUSY;
--		return videobuf_streamon(saa7134_queue(fh));
--	}
--	case VIDIOC_STREAMOFF:
--	{
--		int res = saa7134_resource(fh);
-+static int saa7134_streamon(struct file *file, void *priv,
-+					enum v4l2_buf_type type)
-+{
-+	struct saa7134_fh *fh = priv;
-+	struct saa7134_dev *dev = fh->dev;
-+	int res = saa7134_resource(fh);
+-	t->ops.set_radio_freq(t, freq);
++	analog_ops->set_params(&t->fe, &params);
+ }
  
--		err = videobuf_streamoff(saa7134_queue(fh));
--		if (err < 0)
--			return err;
--		res_free(dev,fh,res);
--		return 0;
--	}
-+	if (!res_get(dev, fh, res))
-+		return -EBUSY;
+ static void set_freq(struct i2c_client *c, unsigned long freq)
+@@ -193,54 +286,65 @@ static void set_freq(struct i2c_client *c, unsigned long freq)
+ 		set_tv_freq(c, freq);
+ 		t->tv_freq = freq;
+ 		break;
++	default:
++		tuner_dbg("freq set: unknown mode: 0x%04x!\n",t->mode);
+ 	}
+ }
  
--	default:
--		return v4l_compat_translate_ioctl(inode,file,cmd,arg,
--						  video_do_ioctl);
--	}
-+	return videobuf_streamon(saa7134_queue(fh));
-+}
-+
-+static int saa7134_streamoff(struct file *file, void *priv,
-+					enum v4l2_buf_type type)
-+{
-+	int err;
-+	struct saa7134_fh *fh = priv;
-+	struct saa7134_dev *dev = fh->dev;
-+	int res = saa7134_resource(fh);
+ static void tuner_i2c_address_check(struct tuner *t)
+ {
+ 	if ((t->type == UNSET || t->type == TUNER_ABSENT) ||
+-	    ((t->i2c.addr < 0x64) || (t->i2c.addr > 0x6f)))
++	    ((t->i2c->addr < 0x64) || (t->i2c->addr > 0x6f)))
++		return;
 +
-+	err = videobuf_streamoff(saa7134_queue(fh));
-+	if (err < 0)
-+		return err;
-+	res_free(dev, fh, res);
- 	return 0;
++	/* We already know that the XC5000 can only be located at
++	 * i2c address 0x61, 0x62, 0x63 or 0x64 */
++	if ((t->type == TUNER_XC5000) &&
++	    ((t->i2c->addr <= 0x64)) && (t->i2c->addr >= 0x61))
+ 		return;
+ 
+ 	tuner_warn("====================== WARNING! ======================\n");
+ 	tuner_warn("Support for tuners in i2c address range 0x64 thru 0x6f\n");
+ 	tuner_warn("will soon be dropped. This message indicates that your\n");
+ 	tuner_warn("hardware has a %s tuner at i2c address 0x%02x.\n",
+-		   t->i2c.name, t->i2c.addr);
++		   t->i2c->name, t->i2c->addr);
+ 	tuner_warn("To ensure continued support for your device, please\n");
+ 	tuner_warn("send a copy of this message, along with full dmesg\n");
+ 	tuner_warn("output to v4l-dvb-maintainer at linuxtv.org\n");
+ 	tuner_warn("Please use subject line: \"obsolete tuner i2c address.\"\n");
+ 	tuner_warn("driver: %s, addr: 0x%02x, type: %d (%s)\n",
+-		   t->i2c.adapter->name, t->i2c.addr, t->type,
++		   t->i2c->adapter->name, t->i2c->addr, t->type,
+ 		   tuners[t->type].name);
+ 	tuner_warn("====================== WARNING! ======================\n");
  }
  
--static int video_ioctl(struct inode *inode, struct file *file,
--		       unsigned int cmd, unsigned long arg)
-+static int saa7134_g_parm(struct file *file, void *fh,
-+				struct v4l2_streamparm *parm)
+-static void attach_tda8290(struct tuner *t)
+-{
+-	struct tda8290_config cfg = {
+-		.lna_cfg        = &t->config,
+-		.tuner_callback = t->tuner_callback
+-	};
+-	tda8290_attach(&t->fe, t->i2c.adapter, t->i2c.addr, &cfg);
+-}
+-
+ static void attach_simple_tuner(struct tuner *t)
  {
--	return video_usercopy(inode, file, cmd, arg, video_do_ioctl);
-+	return 0;
+ 	struct simple_tuner_config cfg = {
+ 		.type = t->type,
+ 		.tun  = &tuners[t->type]
+ 	};
+-	simple_tuner_attach(&t->fe, t->i2c.adapter, t->i2c.addr, &cfg);
++	simple_tuner_attach(&t->fe, t->i2c->adapter, t->i2c->addr, &cfg);
  }
  
--static int radio_do_ioctl(struct inode *inode, struct file *file,
--			  unsigned int cmd, void *arg)
-+static int radio_querycap(struct file *file, void *priv,
-+					struct v4l2_capability *cap)
++static void attach_tda829x(struct tuner *t)
++{
++	struct tda829x_config cfg = {
++		.lna_cfg        = &t->config,
++		.tuner_callback = t->tuner_callback,
++	};
++	tda829x_attach(&t->fe, t->i2c->adapter, t->i2c->addr, &cfg);
++}
++
++static struct xc5000_config xc5000_cfg;
++
+ 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))
  {
- 	struct saa7134_fh *fh = file->private_data;
- 	struct saa7134_dev *dev = fh->dev;
+ 	struct tuner *t = i2c_get_clientdata(c);
+ 	struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
++	struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
+ 	unsigned char buffer[4];
  
--	if (video_debug > 1)
--		v4l_print_ioctl(dev->name,cmd);
--	switch (cmd) {
--	case VIDIOC_QUERYCAP:
--	{
--		struct v4l2_capability *cap = arg;
--
--		memset(cap,0,sizeof(*cap));
--		strcpy(cap->driver, "saa7134");
--		strlcpy(cap->card, saa7134_boards[dev->board].name,
--			sizeof(cap->card));
--		sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci));
--		cap->version = SAA7134_VERSION_CODE;
--		cap->capabilities = V4L2_CAP_TUNER;
--		return 0;
+ 	if (type == UNSET || type == TUNER_ABSENT) {
+@@ -260,32 +364,27 @@ static void set_type(struct i2c_client *c, unsigned int type,
+ 		t->tuner_callback = tuner_callback;
+ 	}
+ 
+-	/* This code detects calls by card attach_inform */
+-	if (NULL == t->i2c.dev.driver) {
++	if (t->mode == T_UNINITIALIZED) {
+ 		tuner_dbg ("tuner 0x%02x: called during i2c_client register by adapter's attach_inform\n", c->addr);
+ 
+ 		return;
+ 	}
+ 
+ 	/* discard private data, in case set_type() was previously called */
+-	if (t->ops.release)
+-		t->ops.release(t);
+-	else {
+-		kfree(t->priv);
+-		t->priv = NULL;
 -	}
--	case VIDIOC_G_TUNER:
--	{
--		struct v4l2_tuner *t = arg;
-+	strcpy(cap->driver, "saa7134");
-+	strlcpy(cap->card, saa7134_boards[dev->board].name, sizeof(cap->card));
-+	sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci));
-+	cap->version = SAA7134_VERSION_CODE;
-+	cap->capabilities = V4L2_CAP_TUNER;
-+	return 0;
-+}
++	if (analog_ops->release)
++		analog_ops->release(&t->fe);
  
--		if (0 != t->index)
--			return -EINVAL;
-+static int radio_g_tuner(struct file *file, void *priv,
-+					struct v4l2_tuner *t)
-+{
-+	struct saa7134_fh *fh = file->private_data;
-+	struct saa7134_dev *dev = fh->dev;
+ 	switch (t->type) {
+ 	case TUNER_MT2032:
+-		microtune_attach(&t->fe, t->i2c.adapter, t->i2c.addr);
++		microtune_attach(&t->fe, t->i2c->adapter, t->i2c->addr);
+ 		break;
+ 	case TUNER_PHILIPS_TDA8290:
+ 	{
+-		attach_tda8290(t);
++		attach_tda829x(t);
+ 		break;
+ 	}
+ 	case TUNER_TEA5767:
+-		if (tea5767_attach(&t->fe, t->i2c.adapter, t->i2c.addr) == NULL) {
++		if (tea5767_attach(&t->fe, t->i2c->adapter, t->i2c->addr) == NULL) {
+ 			t->type = TUNER_ABSENT;
+ 			t->mode_mask = T_UNINITIALIZED;
+ 			return;
+@@ -293,7 +392,7 @@ static void set_type(struct i2c_client *c, unsigned int type,
+ 		t->mode_mask = T_RADIO;
+ 		break;
+ 	case TUNER_TEA5761:
+-		if (tea5761_attach(&t->fe, t->i2c.adapter, t->i2c.addr) == NULL) {
++		if (tea5761_attach(&t->fe, t->i2c->adapter, t->i2c->addr) == NULL) {
+ 			t->type = TUNER_ABSENT;
+ 			t->mode_mask = T_UNINITIALIZED;
+ 			return;
+@@ -320,25 +419,60 @@ static void set_type(struct i2c_client *c, unsigned int type,
+ 		i2c_master_send(c,buffer,4);
+ 		attach_simple_tuner(t);
+ 		break;
++	case TUNER_XC2028:
++	{
++		struct xc2028_config cfg = {
++			.i2c_adap  = t->i2c->adapter,
++			.i2c_addr  = t->i2c->addr,
++			.video_dev = c->adapter->algo_data,
++			.callback  = t->tuner_callback,
++		};
++		if (!xc2028_attach(&t->fe, &cfg)) {
++			t->type = TUNER_ABSENT;
++			t->mode_mask = T_UNINITIALIZED;
++			return;
++		}
++		break;
++	}
+ 	case TUNER_TDA9887:
+-		tda9887_tuner_init(t);
++		tda9887_attach(&t->fe, t->i2c->adapter, t->i2c->addr);
++		break;
++	case TUNER_XC5000:
++		xc5000_cfg.i2c_address	  = t->i2c->addr;
++		xc5000_cfg.if_khz	  = 5380;
++		xc5000_cfg.priv           = c->adapter->algo_data;
++		xc5000_cfg.tuner_callback = t->tuner_callback;
++		if (!xc5000_attach(&t->fe, t->i2c->adapter, &xc5000_cfg)) {
++			t->type = TUNER_ABSENT;
++			t->mode_mask = T_UNINITIALIZED;
++			return;
++		}
++		{
++		struct dvb_tuner_ops *xc_tuner_ops;
++		xc_tuner_ops = &t->fe.ops.tuner_ops;
++		if(xc_tuner_ops->init != NULL)
++			xc_tuner_ops->init(&t->fe);
++		}
+ 		break;
+ 	default:
+ 		attach_simple_tuner(t);
+ 		break;
+ 	}
  
--		memset(t,0,sizeof(*t));
--		strcpy(t->name, "Radio");
--		t->type = V4L2_TUNER_RADIO;
-+	if (0 != t->index)
-+		return -EINVAL;
+-	if (fe_tuner_ops->set_analog_params) {
+-		strlcpy(t->i2c.name, fe_tuner_ops->info.name, sizeof(t->i2c.name));
++	if ((NULL == analog_ops->set_params) &&
++	    (fe_tuner_ops->set_analog_params)) {
++		strlcpy(t->i2c->name, fe_tuner_ops->info.name,
++			sizeof(t->i2c->name));
  
--		saa7134_i2c_call_clients(dev, VIDIOC_G_TUNER, t);
--		if (dev->input->amux == TV) {
--			t->signal = 0xf800 - ((saa_readb(0x581) & 0x1f) << 11);
--			t->rxsubchans = (saa_readb(0x529) & 0x08) ?
--					V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO;
--		}
--		return 0;
-+	memset(t, 0, sizeof(*t));
-+	strcpy(t->name, "Radio");
-+	t->type = V4L2_TUNER_RADIO;
-+
-+	saa7134_i2c_call_clients(dev, VIDIOC_G_TUNER, t);
-+	if (dev->input->amux == TV) {
-+		t->signal = 0xf800 - ((saa_readb(0x581) & 0x1f) << 11);
-+		t->rxsubchans = (saa_readb(0x529) & 0x08) ?
-+				V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO;
+-		t->ops.set_tv_freq    = fe_set_freq;
+-		t->ops.set_radio_freq = fe_set_freq;
+-		t->ops.standby        = fe_standby;
+-		t->ops.release        = fe_release;
+-		t->ops.has_signal     = fe_has_signal;
++		t->fe.analog_demod_priv = t;
++		memcpy(analog_ops, &tuner_core_ops,
++		       sizeof(struct analog_demod_ops));
++	} else {
++		strlcpy(t->i2c->name, analog_ops->info.name,
++			sizeof(t->i2c->name));
  	}
--	case VIDIOC_S_TUNER:
--	{
--		struct v4l2_tuner *t = arg;
-+	return 0;
-+}
-+static int radio_s_tuner(struct file *file, void *priv,
-+					struct v4l2_tuner *t)
-+{
-+	struct saa7134_fh *fh = file->private_data;
-+	struct saa7134_dev *dev = fh->dev;
  
--		if (0 != t->index)
--			return -EINVAL;
-+	if (0 != t->index)
-+		return -EINVAL;
+-	tuner_info("type set to %s\n", t->i2c.name);
++	tuner_dbg("type set to %s\n", t->i2c->name);
  
--		saa7134_i2c_call_clients(dev,VIDIOC_S_TUNER,t);
-+	saa7134_i2c_call_clients(dev, VIDIOC_S_TUNER, t);
-+	return 0;
-+}
+ 	if (t->mode_mask == T_UNINITIALIZED)
+ 		t->mode_mask = new_mode_mask;
+@@ -508,10 +642,12 @@ static int tuner_fixup_std(struct tuner *t)
+ 	return 0;
+ }
  
--		return 0;
--	}
--	case VIDIOC_ENUMINPUT:
--	{
--		struct v4l2_input *i = arg;
-+static int radio_enum_input(struct file *file, void *priv,
-+					struct v4l2_input *i)
-+{
-+	if (i->index != 0)
-+		return -EINVAL;
+-static void tuner_status(struct tuner *t)
++static void tuner_status(struct dvb_frontend *fe)
+ {
++	struct tuner *t = fe->analog_demod_priv;
+ 	unsigned long freq, freq_fraction;
+ 	struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
++	struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
+ 	const char *p;
  
--		if (i->index != 0)
--			return -EINVAL;
--		strcpy(i->name,"Radio");
--		i->type = V4L2_INPUT_TYPE_TUNER;
--		return 0;
+ 	switch (t->mode) {
+@@ -541,172 +677,16 @@ static void tuner_status(struct tuner *t)
+ 		if (tuner_status & TUNER_STATUS_STEREO)
+ 			tuner_info("Stereo:          yes\n");
+ 	}
+-	if (t->ops.has_signal) {
+-		tuner_info("Signal strength: %d\n", t->ops.has_signal(t));
 -	}
--	case VIDIOC_G_INPUT:
--	{
--		int *i = arg;
--		*i = 0;
--		return 0;
+-	if (t->ops.is_stereo) {
+-		tuner_info("Stereo:          %s\n", t->ops.is_stereo(t) ? "yes" : "no");
 -	}
--	case VIDIOC_G_AUDIO:
--	{
--		struct v4l2_audio *a = arg;
-+	strcpy(i->name, "Radio");
-+	i->type = V4L2_INPUT_TYPE_TUNER;
++	if (analog_ops->has_signal)
++		tuner_info("Signal strength: %d\n",
++			   analog_ops->has_signal(fe));
++	if (analog_ops->is_stereo)
++		tuner_info("Stereo:          %s\n",
++			   analog_ops->is_stereo(fe) ? "yes" : "no");
+ }
  
--		memset(a,0,sizeof(*a));
--		strcpy(a->name,"Radio");
--		return 0;
+ /* ---------------------------------------------------------------------- */
+ 
+-/* static vars: used only in tuner_attach and tuner_probe */
+-static unsigned default_mode_mask;
+-
+-/* During client attach, set_type is called by adapter's attach_inform callback.
+-   set_type must then be completed by tuner_attach.
+- */
+-static int tuner_attach(struct i2c_adapter *adap, int addr, int kind)
+-{
+-	struct tuner *t;
+-
+-	client_template.adapter = adap;
+-	client_template.addr = addr;
+-
+-	t = kzalloc(sizeof(struct tuner), GFP_KERNEL);
+-	if (NULL == t)
+-		return -ENOMEM;
+-	memcpy(&t->i2c, &client_template, sizeof(struct i2c_client));
+-	i2c_set_clientdata(&t->i2c, t);
+-	t->type = UNSET;
+-	t->audmode = V4L2_TUNER_MODE_STEREO;
+-	t->mode_mask = T_UNINITIALIZED;
+-	t->ops.tuner_status = tuner_status;
+-
+-	if (show_i2c) {
+-		unsigned char buffer[16];
+-		int i,rc;
+-
+-		memset(buffer, 0, sizeof(buffer));
+-		rc = i2c_master_recv(&t->i2c, buffer, sizeof(buffer));
+-		tuner_info("I2C RECV = ");
+-		for (i=0;i<rc;i++)
+-			printk("%02x ",buffer[i]);
+-		printk("\n");
 -	}
--	case VIDIOC_G_STD:
--	{
--		v4l2_std_id *id = arg;
--		*id = 0;
--		return 0;
+-	/* HACK: This test were added to avoid tuner to probe tda9840 and tea6415c on the MXB card */
+-	if (adap->id == I2C_HW_SAA7146 && addr < 0x4a)
+-		return -ENODEV;
+-
+-	/* autodetection code based on the i2c addr */
+-	if (!no_autodetect) {
+-		switch (addr) {
+-		case 0x10:
+-			if (tea5761_autodetection(t->i2c.adapter, t->i2c.addr) != EINVAL) {
+-				t->type = TUNER_TEA5761;
+-				t->mode_mask = T_RADIO;
+-				t->mode = T_STANDBY;
+-				t->radio_freq = 87.5 * 16000; /* Sets freq to FM range */
+-				default_mode_mask &= ~T_RADIO;
+-
+-				goto register_client;
+-			}
+-			break;
+-		case 0x42:
+-		case 0x43:
+-		case 0x4a:
+-		case 0x4b:
+-			/* If chip is not tda8290, don't register.
+-			   since it can be tda9887*/
+-			if (tda8290_probe(t->i2c.adapter, t->i2c.addr) == 0) {
+-				tuner_dbg("chip at addr %x is a tda8290\n", addr);
+-			} else {
+-				/* Default is being tda9887 */
+-				t->type = TUNER_TDA9887;
+-				t->mode_mask = T_RADIO | T_ANALOG_TV | T_DIGITAL_TV;
+-				t->mode = T_STANDBY;
+-				goto register_client;
+-			}
+-			break;
+-		case 0x60:
+-			if (tea5767_autodetection(t->i2c.adapter, t->i2c.addr) != EINVAL) {
+-				t->type = TUNER_TEA5767;
+-				t->mode_mask = T_RADIO;
+-				t->mode = T_STANDBY;
+-				t->radio_freq = 87.5 * 16000; /* Sets freq to FM range */
+-				default_mode_mask &= ~T_RADIO;
+-
+-				goto register_client;
+-			}
+-			break;
+-		}
 -	}
--	case VIDIOC_S_AUDIO:
--	case VIDIOC_S_INPUT:
--	case VIDIOC_S_STD:
--		return 0;
-+	return 0;
-+}
- 
--	case VIDIOC_QUERYCTRL:
--	{
--		const struct v4l2_queryctrl *ctrl;
--		struct v4l2_queryctrl *c = arg;
-+static int radio_g_input(struct file *filp, void *priv, unsigned int *i)
-+{
-+	*i = 0;
-+	return 0;
-+}
- 
--		if (c->id <  V4L2_CID_BASE ||
--		    c->id >= V4L2_CID_LASTP1)
--			return -EINVAL;
--		if (c->id == V4L2_CID_AUDIO_MUTE) {
--			ctrl = ctrl_by_id(c->id);
--			*c = *ctrl;
+-
+-	/* Initializes only the first adapter found */
+-	if (default_mode_mask != T_UNINITIALIZED) {
+-		tuner_dbg ("Setting mode_mask to 0x%02x\n", default_mode_mask);
+-		t->mode_mask = default_mode_mask;
+-		t->tv_freq = 400 * 16; /* Sets freq to VHF High */
+-		t->radio_freq = 87.5 * 16000; /* Sets freq to FM range */
+-		default_mode_mask = T_UNINITIALIZED;
+-	}
+-
+-	/* Should be just before return */
+-register_client:
+-	tuner_info("chip found @ 0x%x (%s)\n", addr << 1, adap->name);
+-	i2c_attach_client (&t->i2c);
+-	set_type (&t->i2c,t->type, t->mode_mask, t->config, t->tuner_callback);
+-	return 0;
+-}
+-
+-static int tuner_probe(struct i2c_adapter *adap)
+-{
+-	if (0 != addr) {
+-		normal_i2c[0] = addr;
+-		normal_i2c[1] = I2C_CLIENT_END;
+-	}
+-
+-	/* HACK: Ignore 0x6b and 0x6f on cx88 boards.
+-	 * FusionHDTV5 RT Gold has an ir receiver at 0x6b
+-	 * and an RTC at 0x6f which can get corrupted if probed.
+-	 */
+-	if ((adap->id == I2C_HW_B_CX2388x) ||
+-	    (adap->id == I2C_HW_B_CX23885)) {
+-		unsigned int i = 0;
+-
+-		while (i < I2C_CLIENT_MAX_OPTS && ignore[i] != I2C_CLIENT_END)
+-			i += 2;
+-		if (i + 4 < I2C_CLIENT_MAX_OPTS) {
+-			ignore[i+0] = adap->nr;
+-			ignore[i+1] = 0x6b;
+-			ignore[i+2] = adap->nr;
+-			ignore[i+3] = 0x6f;
+-			ignore[i+4] = I2C_CLIENT_END;
 -		} else
--			*c = no_ctrl;
--		return 0;
+-			printk(KERN_WARNING "tuner: "
+-			       "too many options specified "
+-			       "in i2c probe ignore list!\n");
 -	}
-+static int radio_g_audio(struct file *file, void *priv,
-+					struct v4l2_audio *a)
-+{
-+	memset(a, 0, sizeof(*a));
-+	strcpy(a->name, "Radio");
-+	return 0;
-+}
- 
--	case VIDIOC_G_CTRL:
--	case VIDIOC_S_CTRL:
--	case VIDIOC_G_FREQUENCY:
--	case VIDIOC_S_FREQUENCY:
--		return video_do_ioctl(inode,file,cmd,arg);
-+static int radio_s_audio(struct file *file, void *priv,
-+					struct v4l2_audio *a)
-+{
-+	return 0;
-+}
- 
--	default:
--		return v4l_compat_translate_ioctl(inode,file,cmd,arg,
--						  radio_do_ioctl);
+-
+-	default_mode_mask = T_RADIO | T_ANALOG_TV | T_DIGITAL_TV;
+-
+-	if (adap->class & I2C_CLASS_TV_ANALOG)
+-		return i2c_probe(adap, &addr_data, tuner_attach);
+-	return 0;
+-}
+-
+-static int tuner_detach(struct i2c_client *client)
+-{
+-	struct tuner *t = i2c_get_clientdata(client);
+-	int err;
+-
+-	err = i2c_detach_client(&t->i2c);
+-	if (err) {
+-		tuner_warn
+-		    ("Client deregistration failed, client not detached.\n");
+-		return err;
 -	}
-+static int radio_s_input(struct file *filp, void *priv, unsigned int i)
-+{
- 	return 0;
- }
+-
+-	if (t->ops.release)
+-		t->ops.release(t);
+-	else {
+-		kfree(t->priv);
+-	}
+-	kfree(t);
+-	return 0;
+-}
+-
+ /*
+  * Switch tuner to other mode. If tuner support both tv and radio,
+  * set another frequency to some value (This is needed for some pal
+@@ -716,6 +696,8 @@ static int tuner_detach(struct i2c_client *client)
  
--static int radio_ioctl(struct inode *inode, struct file *file,
--		       unsigned int cmd, unsigned long arg)
-+static int radio_s_std(struct file *file, void *fh, v4l2_std_id *norm)
+ static inline int set_mode(struct i2c_client *client, struct tuner *t, int mode, char *cmd)
  {
--	return video_usercopy(inode, file, cmd, arg, radio_do_ioctl);
-+	return 0;
-+}
-+
-+static int radio_queryctrl(struct file *file, void *priv,
-+					struct v4l2_queryctrl *c)
-+{
-+	const struct v4l2_queryctrl *ctrl;
++	struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
 +
-+	if (c->id <  V4L2_CID_BASE ||
-+	    c->id >= V4L2_CID_LASTP1)
-+		return -EINVAL;
-+	if (c->id == V4L2_CID_AUDIO_MUTE) {
-+		ctrl = ctrl_by_id(c->id);
-+		*c = *ctrl;
-+	} else
-+		*c = no_ctrl;
-+	return 0;
- }
- 
- static const struct file_operations video_fops =
-@@ -2333,7 +2327,7 @@ static const struct file_operations video_fops =
- 	.read	  = video_read,
- 	.poll     = video_poll,
- 	.mmap	  = video_mmap,
--	.ioctl	  = video_ioctl,
-+	.ioctl	  = video_ioctl2,
- 	.compat_ioctl	= v4l_compat_ioctl32,
- 	.llseek   = no_llseek,
- };
-@@ -2343,7 +2337,7 @@ static const struct file_operations radio_fops =
- 	.owner	  = THIS_MODULE,
- 	.open	  = video_open,
- 	.release  = video_release,
--	.ioctl	  = radio_ioctl,
-+	.ioctl	  = video_ioctl2,
- 	.compat_ioctl	= v4l_compat_ioctl32,
- 	.llseek   = no_llseek,
- };
-@@ -2353,27 +2347,79 @@ static const struct file_operations radio_fops =
- 
- struct video_device saa7134_video_template =
- {
--	.name          = "saa7134-video",
--	.type          = VID_TYPE_CAPTURE|VID_TYPE_TUNER|
--			 VID_TYPE_CLIPPING|VID_TYPE_SCALES,
--	.fops          = &video_fops,
--	.minor         = -1,
--};
--
--struct video_device saa7134_vbi_template =
--{
--	.name          = "saa7134-vbi",
--	.type          = VID_TYPE_TUNER|VID_TYPE_TELETEXT,
--	.fops          = &video_fops,
--	.minor         = -1,
-+	.name				= "saa7134-video",
-+	.type				= VID_TYPE_CAPTURE|VID_TYPE_TUNER |
-+					VID_TYPE_CLIPPING|VID_TYPE_SCALES,
-+	.fops				= &video_fops,
-+	.minor				= -1,
-+	.vidioc_querycap		= saa7134_querycap,
-+	.vidioc_enum_fmt_cap		= saa7134_enum_fmt_cap,
-+	.vidioc_g_fmt_cap		= saa7134_g_fmt_cap,
-+	.vidioc_try_fmt_cap		= saa7134_try_fmt_cap,
-+	.vidioc_s_fmt_cap		= saa7134_s_fmt_cap,
-+	.vidioc_enum_fmt_overlay	= saa7134_enum_fmt_overlay,
-+	.vidioc_g_fmt_overlay		= saa7134_g_fmt_overlay,
-+	.vidioc_try_fmt_overlay		= saa7134_try_fmt_overlay,
-+	.vidioc_s_fmt_overlay		= saa7134_s_fmt_overlay,
-+	.vidioc_enum_fmt_vbi		= saa7134_enum_fmt_vbi,
-+	.vidioc_g_fmt_vbi		= saa7134_try_get_set_fmt_vbi,
-+	.vidioc_try_fmt_vbi		= saa7134_try_get_set_fmt_vbi,
-+	.vidioc_s_fmt_vbi		= saa7134_try_get_set_fmt_vbi,
-+	.vidioc_g_audio			= saa7134_g_audio,
-+	.vidioc_s_audio			= saa7134_s_audio,
-+	.vidioc_cropcap			= saa7134_cropcap,
-+	.vidioc_reqbufs			= saa7134_reqbufs,
-+	.vidioc_querybuf		= saa7134_querybuf,
-+	.vidioc_qbuf			= saa7134_qbuf,
-+	.vidioc_dqbuf			= saa7134_dqbuf,
-+	.vidioc_s_std			= saa7134_s_std,
-+	.vidioc_enum_input		= saa7134_enum_input,
-+	.vidioc_g_input			= saa7134_g_input,
-+	.vidioc_s_input			= saa7134_s_input,
-+	.vidioc_queryctrl		= saa7134_queryctrl,
-+	.vidioc_g_ctrl			= saa7134_g_ctrl,
-+	.vidioc_s_ctrl			= saa7134_s_ctrl,
-+	.vidioc_streamon		= saa7134_streamon,
-+	.vidioc_streamoff		= saa7134_streamoff,
-+	.vidioc_g_tuner			= saa7134_g_tuner,
-+	.vidioc_s_tuner			= saa7134_s_tuner,
-+#ifdef CONFIG_VIDEO_V4L1_COMPAT
-+	.vidiocgmbuf			= vidiocgmbuf,
-+#endif
-+	.vidioc_g_crop			= saa7134_g_crop,
-+	.vidioc_s_crop			= saa7134_s_crop,
-+	.vidioc_g_fbuf			= saa7134_g_fbuf,
-+	.vidioc_s_fbuf			= saa7134_s_fbuf,
-+	.vidioc_overlay			= saa7134_overlay,
-+	.vidioc_g_priority		= saa7134_g_priority,
-+	.vidioc_s_priority		= saa7134_s_priority,
-+	.vidioc_g_parm			= saa7134_g_parm,
-+	.vidioc_g_frequency		= saa7134_g_frequency,
-+	.vidioc_s_frequency		= saa7134_s_frequency,
-+	.tvnorms			= SAA7134_NORMS,
-+	.current_norm			= V4L2_STD_PAL,
- };
+ 	if (mode == t->mode)
+ 		return 0;
  
- struct video_device saa7134_radio_template =
- {
--	.name          = "saa7134-radio",
--	.type          = VID_TYPE_TUNER,
--	.fops          = &radio_fops,
--	.minor         = -1,
-+	.name			= "saa7134-radio",
-+	.type			= VID_TYPE_TUNER,
-+	.fops			= &radio_fops,
-+	.minor			= -1,
-+	.vidioc_querycap	= radio_querycap,
-+	.vidioc_g_tuner		= radio_g_tuner,
-+	.vidioc_enum_input	= radio_enum_input,
-+	.vidioc_g_audio		= radio_g_audio,
-+	.vidioc_s_tuner		= radio_s_tuner,
-+	.vidioc_s_audio		= radio_s_audio,
-+	.vidioc_s_input		= radio_s_input,
-+	.vidioc_s_std		= radio_s_std,
-+	.vidioc_queryctrl	= radio_queryctrl,
-+	.vidioc_g_input		= radio_g_input,
-+	.vidioc_g_ctrl		= saa7134_g_ctrl,
-+	.vidioc_s_ctrl		= saa7134_s_ctrl,
-+	.vidioc_g_frequency	= saa7134_g_frequency,
-+	.vidioc_s_frequency	= saa7134_s_frequency,
- };
+@@ -723,8 +705,8 @@ static inline int set_mode(struct i2c_client *client, struct tuner *t, int mode,
  
- int saa7134_video_init1(struct saa7134_dev *dev)
-@@ -2511,7 +2557,7 @@ void saa7134_irq_video_done(struct saa7134_dev *dev, unsigned long status)
- 				goto done;
- 		}
- 		dev->video_q.curr->vb.field_count = dev->video_fieldcount;
--		saa7134_buffer_finish(dev,&dev->video_q,STATE_DONE);
-+		saa7134_buffer_finish(dev,&dev->video_q,VIDEOBUF_DONE);
+ 	if (check_mode(t, cmd) == EINVAL) {
+ 		t->mode = T_STANDBY;
+-		if (t->ops.standby)
+-			t->ops.standby(t);
++		if (analog_ops->standby)
++			analog_ops->standby(&t->fe);
+ 		return EINVAL;
  	}
- 	saa7134_buffer_next(dev,&dev->video_q);
+ 	return 0;
+@@ -747,9 +729,10 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
+ {
+ 	struct tuner *t = i2c_get_clientdata(client);
+ 	struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
++	struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
  
-diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h
-index 66a390c..ce45030 100644
---- a/drivers/media/video/saa7134/saa7134.h
-+++ b/drivers/media/video/saa7134/saa7134.h
-@@ -240,6 +240,19 @@ struct saa7134_format {
- #define SAA7134_BOARD_SABRENT_TV_PCB05     115
- #define SAA7134_BOARD_10MOONSTVMASTER3     116
- #define SAA7134_BOARD_AVERMEDIA_SUPER_007  117
-+#define SAA7134_BOARD_BEHOLD_401  	118
-+#define SAA7134_BOARD_BEHOLD_403  	119
-+#define SAA7134_BOARD_BEHOLD_403FM	120
-+#define SAA7134_BOARD_BEHOLD_405	121
-+#define SAA7134_BOARD_BEHOLD_405FM	122
-+#define SAA7134_BOARD_BEHOLD_407	123
-+#define SAA7134_BOARD_BEHOLD_407FM	124
-+#define SAA7134_BOARD_BEHOLD_409	125
-+#define SAA7134_BOARD_BEHOLD_505FM	126
-+#define SAA7134_BOARD_BEHOLD_507_9FM	127
-+#define SAA7134_BOARD_BEHOLD_COLUMBUS_TVFM 128
-+#define SAA7134_BOARD_BEHOLD_607_9FM	129
-+#define SAA7134_BOARD_BEHOLD_M6		130
+ 	if (tuner_debug>1)
+-		v4l_i2c_print_ioctl(&(t->i2c),cmd);
++		v4l_i2c_print_ioctl(client,cmd);
  
- #define SAA7134_MAXBOARDS 8
- #define SAA7134_INPUT_MAX 8
-@@ -481,7 +494,7 @@ struct saa7134_dev {
- 	/* i2c i/o */
- 	struct i2c_adapter         i2c_adap;
- 	struct i2c_client          i2c_client;
--	unsigned char              eedata[128];
-+	unsigned char              eedata[256];
+ 	switch (cmd) {
+ 	/* --- configuration --- */
+@@ -773,8 +756,8 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
+ 		if (check_mode(t, "TUNER_SET_STANDBY") == EINVAL)
+ 			return 0;
+ 		t->mode = T_STANDBY;
+-		if (t->ops.standby)
+-			t->ops.standby(t);
++		if (analog_ops->standby)
++			analog_ops->standby(&t->fe);
+ 		break;
+ #ifdef CONFIG_VIDEO_V4L1
+ 	case VIDIOCSAUDIO:
+@@ -842,8 +825,8 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
+ 					else
+ 						vt->flags &= ~VIDEO_TUNER_STEREO_ON;
+ 				} else {
+-					if (t->ops.is_stereo) {
+-						if (t->ops.is_stereo(t))
++					if (analog_ops->is_stereo) {
++						if (analog_ops->is_stereo(&t->fe))
+ 							vt->flags |=
+ 								VIDEO_TUNER_STEREO_ON;
+ 						else
+@@ -851,8 +834,9 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
+ 								~VIDEO_TUNER_STEREO_ON;
+ 					}
+ 				}
+-				if (t->ops.has_signal)
+-					vt->signal = t->ops.has_signal(t);
++				if (analog_ops->has_signal)
++					vt->signal =
++						analog_ops->has_signal(&t->fe);
  
- 	/* video overlay */
- 	struct v4l2_framebuffer    ovbuf;
-@@ -566,6 +579,12 @@ struct saa7134_dev {
+ 				vt->flags |= VIDEO_TUNER_LOW;	/* Allow freqs at 62.5 Hz */
  
- #define saa_wait(us) { udelay(us); }
+@@ -882,21 +866,28 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
+ 					fe_tuner_ops->get_status(&t->fe, &tuner_status);
+ 					va->mode = (tuner_status & TUNER_STATUS_STEREO)
+ 					    ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO;
+-				} else if (t->ops.is_stereo)
+-					va->mode = t->ops.is_stereo(t)
++				} else if (analog_ops->is_stereo)
++					va->mode = analog_ops->is_stereo(&t->fe)
+ 					    ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO;
+ 			}
+ 			return 0;
+ 		}
+ #endif
+-	case TDA9887_SET_CONFIG:
+-		if (t->type == TUNER_TDA9887) {
+-			int *i = arg;
++	case TUNER_SET_CONFIG:
++	{
++		struct v4l2_priv_tun_config *cfg = arg;
  
-+#define SAA7134_NORMS	(\
-+		V4L2_STD_PAL    | V4L2_STD_PAL_N | \
-+		V4L2_STD_PAL_Nc | V4L2_STD_SECAM | \
-+		V4L2_STD_NTSC   | V4L2_STD_PAL_M | \
-+		V4L2_STD_PAL_60)
+-			t->tda9887_config = *i;
+-			set_freq(client, t->tv_freq);
++		if (t->type != cfg->tuner)
++			break;
 +
- /* ----------------------------------------------------------- */
- /* saa7134-core.c                                              */
- 
-@@ -596,9 +615,6 @@ void saa7134_buffer_next(struct saa7134_dev *dev, struct saa7134_dmaqueue *q);
- void saa7134_buffer_timeout(unsigned long data);
- void saa7134_dma_free(struct videobuf_queue *q,struct saa7134_buf *buf);
- 
--int saa7134_buffer_requeue(struct saa7134_dev *dev,
--			 struct saa7134_dmaqueue *q);
--
- int saa7134_set_dmabits(struct saa7134_dev *dev);
- 
- extern int (*saa7134_dmasound_init)(struct saa7134_dev *dev);
-@@ -628,16 +644,17 @@ void saa7134_i2c_call_clients(struct saa7134_dev *dev,
- /* ----------------------------------------------------------- */
- /* saa7134-video.c                                             */
++		if (analog_ops->set_config) {
++			analog_ops->set_config(&t->fe, cfg->priv);
++			break;
+ 		}
++
++		tuner_dbg("Tuner frontend module has no way to set config\n");
+ 		break;
++	}
+ 	/* --- v4l ioctls --- */
+ 	/* take care: bttv does userspace copying, we'll get a
+ 	   kernel pointer here... */
+@@ -958,8 +949,8 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
+ 			switch_v4l2();
  
-+extern unsigned int video_debug;
- extern struct video_device saa7134_video_template;
- extern struct video_device saa7134_radio_template;
+ 			tuner->type = t->mode;
+-			if (t->ops.get_afc)
+-				tuner->afc=t->ops.get_afc(t);
++			if (analog_ops->get_afc)
++				tuner->afc = analog_ops->get_afc(&t->fe);
+ 			if (t->mode == V4L2_TUNER_ANALOG_TV)
+ 				tuner->capability |= V4L2_TUNER_CAP_NORM;
+ 			if (t->mode != V4L2_TUNER_RADIO) {
+@@ -975,16 +966,20 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
+ 				u32 tuner_status;
  
--void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm);
-+int saa7134_g_ctrl(struct file *file, void *priv, struct v4l2_control *c);
-+int saa7134_s_ctrl(struct file *file, void *f, struct v4l2_control *c);
-+int saa7134_queryctrl(struct file *file, void *priv, struct v4l2_queryctrl *c);
-+
- int saa7134_videoport_init(struct saa7134_dev *dev);
- void saa7134_set_tvnorm_hw(struct saa7134_dev *dev);
+ 				fe_tuner_ops->get_status(&t->fe, &tuner_status);
+-				tuner->rxsubchans = (tuner_status & TUNER_STATUS_STEREO) ?
+-					V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO;
++				tuner->rxsubchans =
++					(tuner_status & TUNER_STATUS_STEREO) ?
++					V4L2_TUNER_SUB_STEREO :
++					V4L2_TUNER_SUB_MONO;
+ 			} else {
+-				if (t->ops.is_stereo) {
+-					tuner->rxsubchans = t->ops.is_stereo(t) ?
+-						V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO;
++				if (analog_ops->is_stereo) {
++					tuner->rxsubchans =
++						analog_ops->is_stereo(&t->fe) ?
++						V4L2_TUNER_SUB_STEREO :
++						V4L2_TUNER_SUB_MONO;
+ 				}
+ 			}
+-			if (t->ops.has_signal)
+-				tuner->signal = t->ops.has_signal(t);
++			if (analog_ops->has_signal)
++				tuner->signal = analog_ops->has_signal(&t->fe);
+ 			tuner->capability |=
+ 			    V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
+ 			tuner->audmode = t->audmode;
+@@ -1009,8 +1004,8 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
+ 			break;
+ 		}
+ 	case VIDIOC_LOG_STATUS:
+-		if (t->ops.tuner_status)
+-			t->ops.tuner_status(t);
++		if (analog_ops->tuner_status)
++			analog_ops->tuner_status(&t->fe);
+ 		break;
+ 	}
  
--int saa7134_common_ioctl(struct saa7134_dev *dev,
--			 unsigned int cmd, void *arg);
--
- int saa7134_video_init1(struct saa7134_dev *dev);
- int saa7134_video_init2(struct saa7134_dev *dev);
- void saa7134_irq_video_signalchange(struct saa7134_dev *dev);
-@@ -682,6 +699,7 @@ void saa7134_tvaudio_setinput(struct saa7134_dev *dev,
- void saa7134_tvaudio_setvolume(struct saa7134_dev *dev, int level);
- int saa7134_tvaudio_getstereo(struct saa7134_dev *dev);
+@@ -1019,18 +1014,18 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
  
-+void saa7134_tvaudio_init(struct saa7134_dev *dev);
- int saa7134_tvaudio_init2(struct saa7134_dev *dev);
- int saa7134_tvaudio_fini(struct saa7134_dev *dev);
- int saa7134_tvaudio_do_scan(struct saa7134_dev *dev);
-diff --git a/drivers/media/video/sn9c102/Makefile b/drivers/media/video/sn9c102/Makefile
-index a56d16f..7ecd5a9 100644
---- a/drivers/media/video/sn9c102/Makefile
-+++ b/drivers/media/video/sn9c102/Makefile
-@@ -3,6 +3,7 @@ sn9c102-objs := sn9c102_core.o \
- 		sn9c102_hv7131r.o \
- 		sn9c102_mi0343.o \
- 		sn9c102_mi0360.o \
-+		sn9c102_mt9v111.o \
- 		sn9c102_ov7630.o \
- 		sn9c102_ov7660.o \
- 		sn9c102_pas106b.o \
-diff --git a/drivers/media/video/sn9c102/sn9c102_core.c b/drivers/media/video/sn9c102/sn9c102_core.c
-index 5118479..c40ba3a 100644
---- a/drivers/media/video/sn9c102/sn9c102_core.c
-+++ b/drivers/media/video/sn9c102/sn9c102_core.c
-@@ -47,7 +47,7 @@
- #define SN9C102_MODULE_AUTHOR   "(C) 2004-2007 Luca Risolia"
- #define SN9C102_AUTHOR_EMAIL    "<luca.risolia at studio.unibo.it>"
- #define SN9C102_MODULE_LICENSE  "GPL"
--#define SN9C102_MODULE_VERSION  "1:1.47"
-+#define SN9C102_MODULE_VERSION  "1:1.47pre49"
- #define SN9C102_MODULE_VERSION_CODE  KERNEL_VERSION(1, 1, 47)
+ static int tuner_suspend(struct i2c_client *c, pm_message_t state)
+ {
+-	struct tuner *t = i2c_get_clientdata (c);
++	struct tuner *t = i2c_get_clientdata(c);
  
- /*****************************************************************************/
-@@ -3322,7 +3322,6 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
- 	cam->v4ldev->fops = &sn9c102_fops;
- 	cam->v4ldev->minor = video_nr[dev_nr];
- 	cam->v4ldev->release = video_device_release;
--	video_set_drvdata(cam->v4ldev, cam);
+-	tuner_dbg ("suspend\n");
++	tuner_dbg("suspend\n");
+ 	/* FIXME: power down ??? */
+ 	return 0;
+ }
  
- 	init_completion(&cam->probe);
+ static int tuner_resume(struct i2c_client *c)
+ {
+-	struct tuner *t = i2c_get_clientdata (c);
++	struct tuner *t = i2c_get_clientdata(c);
  
-@@ -3340,6 +3339,7 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
+-	tuner_dbg ("resume\n");
++	tuner_dbg("resume\n");
+ 	if (V4L2_TUNER_RADIO == t->mode) {
+ 		if (t->radio_freq)
+ 			set_freq(c, t->radio_freq);
+@@ -1041,36 +1036,227 @@ static int tuner_resume(struct i2c_client *c)
+ 	return 0;
+ }
  
- 	DBG(2, "V4L2 device registered as /dev/video%d", cam->v4ldev->minor);
+-/* ----------------------------------------------------------------------- */
++/* ---------------------------------------------------------------------- */
  
-+	video_set_drvdata(cam->v4ldev, cam);
- 	cam->module_param.force_munmap = force_munmap[dev_nr];
- 	cam->module_param.frame_timeout = frame_timeout[dev_nr];
+-static struct i2c_driver driver = {
+-	.id = I2C_DRIVERID_TUNER,
+-	.attach_adapter = tuner_probe,
+-	.detach_client = tuner_detach,
+-	.command = tuner_command,
+-	.suspend = tuner_suspend,
+-	.resume  = tuner_resume,
+-	.driver = {
+-		.name    = "tuner",
+-	},
+-};
+-static struct i2c_client client_template = {
+-	.name = "(tuner unset)",
+-	.driver = &driver,
+-};
++LIST_HEAD(tuner_list);
  
-diff --git a/drivers/media/video/sn9c102/sn9c102_devtable.h b/drivers/media/video/sn9c102/sn9c102_devtable.h
-index 916054f..35223e0 100644
---- a/drivers/media/video/sn9c102/sn9c102_devtable.h
-+++ b/drivers/media/video/sn9c102/sn9c102_devtable.h
-@@ -126,6 +126,7 @@ extern int sn9c102_probe_hv7131d(struct sn9c102_device* cam);
- extern int sn9c102_probe_hv7131r(struct sn9c102_device* cam);
- extern int sn9c102_probe_mi0343(struct sn9c102_device* cam);
- extern int sn9c102_probe_mi0360(struct sn9c102_device* cam);
-+extern int sn9c102_probe_mt9v111(struct sn9c102_device *cam);
- extern int sn9c102_probe_ov7630(struct sn9c102_device* cam);
- extern int sn9c102_probe_ov7660(struct sn9c102_device* cam);
- extern int sn9c102_probe_pas106b(struct sn9c102_device* cam);
-@@ -144,6 +145,7 @@ static int (*sn9c102_sensor_table[])(struct sn9c102_device*) = {
- 	&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 */
-diff --git a/drivers/media/video/sn9c102/sn9c102_mt9v111.c b/drivers/media/video/sn9c102/sn9c102_mt9v111.c
-new file mode 100644
-index 0000000..3b98ac3
---- /dev/null
-+++ b/drivers/media/video/sn9c102/sn9c102_mt9v111.c
-@@ -0,0 +1,259 @@
-+/***************************************************************************
-+ * Plug-in for MT9V111 image sensor connected to the SN9C1xx PC Camera     *
-+ * Controllers                                                             *
-+ *                                                                         *
-+ * Copyright (C) 2007 by Luca Risolia <luca.risolia at studio.unibo.it>       *
-+ *                                                                         *
-+ * This program is free software; you can redistribute it and/or modify    *
-+ * it under the terms of the GNU General Public License as published by    *
-+ * the Free Software Foundation; either version 2 of the License, or       *
-+ * (at your option) any later version.                                     *
-+ *                                                                         *
-+ * This program is distributed in the hope that it will be useful,         *
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
-+ * GNU General Public License for more details.                            *
-+ *                                                                         *
-+ * You 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 "sn9c102_sensor.h"
+-static int __init tuner_init_module(void)
++/* Search for existing radio and/or TV tuners on the given I2C adapter.
++   Note that when this function is called from tuner_probe you can be
++   certain no other devices will be added/deleted at the same time, I2C
++   core protects against that. */
++static void tuner_lookup(struct i2c_adapter *adap,
++		struct tuner **radio, struct tuner **tv)
+ {
+-	return i2c_add_driver(&driver);
++	struct tuner *pos;
 +
++	*radio = NULL;
++	*tv = NULL;
 +
-+static int mt9v111_init(struct sn9c102_device *cam)
-+{
-+	struct sn9c102_sensor *s = sn9c102_get_sensor(cam);
-+	int err = 0;
++	list_for_each_entry(pos, &tuner_list, list) {
++		int mode_mask;
 +
-+	err = sn9c102_write_const_regs(cam, {0x44, 0x01}, {0x40, 0x02},
-+				       {0x00, 0x03}, {0x1a, 0x04},
-+				       {0x1f, 0x05}, {0x20, 0x06},
-+				       {0x1f, 0x07}, {0x81, 0x08},
-+				       {0x5c, 0x09}, {0x00, 0x0a},
-+				       {0x00, 0x0b}, {0x00, 0x0c},
-+				       {0x00, 0x0d}, {0x00, 0x0e},
-+				       {0x00, 0x0f}, {0x03, 0x10},
-+				       {0x00, 0x11}, {0x00, 0x12},
-+				       {0x02, 0x13}, {0x14, 0x14},
-+				       {0x28, 0x15}, {0x1e, 0x16},
-+				       {0xe2, 0x17}, {0x06, 0x18},
-+				       {0x00, 0x19}, {0x00, 0x1a},
-+				       {0x00, 0x1b}, {0x08, 0x20},
-+				       {0x39, 0x21}, {0x51, 0x22},
-+				       {0x63, 0x23}, {0x73, 0x24},
-+				       {0x82, 0x25}, {0x8f, 0x26},
-+				       {0x9b, 0x27}, {0xa7, 0x28},
-+				       {0xb1, 0x29}, {0xbc, 0x2a},
-+				       {0xc6, 0x2b}, {0xcf, 0x2c},
-+				       {0xd8, 0x2d}, {0xe1, 0x2e},
-+				       {0xea, 0x2f}, {0xf2, 0x30},
-+				       {0x13, 0x84}, {0x00, 0x85},
-+				       {0x25, 0x86}, {0x00, 0x87},
-+				       {0x07, 0x88}, {0x00, 0x89},
-+				       {0xee, 0x8a}, {0x0f, 0x8b},
-+				       {0xe5, 0x8c}, {0x0f, 0x8d},
-+				       {0x2e, 0x8e}, {0x00, 0x8f},
-+				       {0x30, 0x90}, {0x00, 0x91},
-+				       {0xd4, 0x92}, {0x0f, 0x93},
-+				       {0xfc, 0x94}, {0x0f, 0x95},
-+				       {0x14, 0x96}, {0x00, 0x97},
-+				       {0x00, 0x98}, {0x60, 0x99},
-+				       {0x07, 0x9a}, {0x40, 0x9b},
-+				       {0x20, 0x9c}, {0x00, 0x9d},
-+				       {0x00, 0x9e}, {0x00, 0x9f},
-+				       {0x2d, 0xc0}, {0x2d, 0xc1},
-+				       {0x3a, 0xc2}, {0x05, 0xc3},
-+				       {0x04, 0xc4}, {0x3f, 0xc5},
-+				       {0x00, 0xc6}, {0x00, 0xc7},
-+				       {0x50, 0xc8}, {0x3c, 0xc9},
-+				       {0x28, 0xca}, {0xd8, 0xcb},
-+				       {0x14, 0xcc}, {0xec, 0xcd},
-+				       {0x32, 0xce}, {0xdd, 0xcf},
-+				       {0x2d, 0xd0}, {0xdd, 0xd1},
-+				       {0x6a, 0xd2}, {0x50, 0xd3},
-+				       {0x60, 0xd4}, {0x00, 0xd5},
-+				       {0x00, 0xd6});
++		if (pos->i2c->adapter != adap ||
++		    pos->i2c->driver->id != I2C_DRIVERID_TUNER)
++			continue;
 +
-+	err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x01,
-+					 0x00, 0x01, 0, 0);
-+	err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x0d,
-+					 0x00, 0x01, 0, 0);
-+	err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x0d,
-+					 0x00, 0x00, 0, 0);
-+	err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x08,
-+					 0x04, 0x80, 0, 0);
-+	err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x01,
-+					 0x00, 0x04, 0, 0);
-+	err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x08,
-+					 0x00, 0x08, 0, 0);
-+	err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x02,
-+					 0x00, 0x16, 0, 0);
-+	err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x03,
-+					 0x01, 0xe7, 0, 0);
-+	err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x04,
-+					 0x02, 0x87, 0, 0);
-+	err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x06,
-+					 0x00, 0x40, 0, 0);
-+	err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x05,
-+					 0x00, 0x09, 0, 0);
-+	err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x07,
-+					 0x30, 0x02, 0, 0);
-+	err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x0c,
-+					 0x00, 0x00, 0, 0);
-+	err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x12,
-+					 0x00, 0xb0, 0, 0);
-+	err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x13,
-+					 0x00, 0x7c, 0, 0);
-+	err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x1e,
-+					 0x00, 0x00, 0, 0);
-+	err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x20,
-+					 0x00, 0x00, 0, 0);
-+	err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x20,
-+					 0x00, 0x00, 0, 0);
-+	err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x01,
-+					 0x00, 0x04, 0, 0);
++		mode_mask = pos->mode_mask & ~T_STANDBY;
++		if (*radio == NULL && mode_mask == T_RADIO)
++			*radio = pos;
++		/* Note: currently TDA9887 is the only demod-only
++		   device. If other devices appear then we need to
++		   make this test more general. */
++		else if (*tv == NULL && pos->type != TUNER_TDA9887 &&
++			 (pos->mode_mask & (T_ANALOG_TV | T_DIGITAL_TV)))
++			*tv = pos;
++	}
+ }
+ 
+-static void __exit tuner_cleanup_module(void)
++/* During client attach, set_type is called by adapter's attach_inform callback.
++   set_type must then be completed by tuner_probe.
++ */
++static int tuner_probe(struct i2c_client *client)
+ {
+-	i2c_del_driver(&driver);
++	struct tuner *t;
++	struct tuner *radio;
++	struct tuner *tv;
 +
-+	return err;
-+}
++	t = kzalloc(sizeof(struct tuner), GFP_KERNEL);
++	if (NULL == t)
++		return -ENOMEM;
++	t->i2c = client;
++	strlcpy(client->name, "(tuner unset)", sizeof(client->name));
++	i2c_set_clientdata(client, t);
++	t->type = UNSET;
++	t->audmode = V4L2_TUNER_MODE_STEREO;
++	t->mode_mask = T_UNINITIALIZED;
 +
-+static int mt9v111_get_ctrl(struct sn9c102_device *cam,
-+			    struct v4l2_control *ctrl)
-+{
-+	struct sn9c102_sensor *s = sn9c102_get_sensor(cam);
-+	u8 data[2];
-+	int err = 0;
++	if (show_i2c) {
++		unsigned char buffer[16];
++		int i, rc;
 +
-+	switch (ctrl->id) {
-+	case V4L2_CID_VFLIP:
-+		if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x20, 2,
-+					     data) < 0)
-+			return -EIO;
-+		ctrl->value = data[1] & 0x80 ? 1 : 0;
-+		return 0;
-+	default:
-+		return -EINVAL;
++		memset(buffer, 0, sizeof(buffer));
++		rc = i2c_master_recv(client, buffer, sizeof(buffer));
++		tuner_info("I2C RECV = ");
++		for (i = 0; i < rc; i++)
++			printk(KERN_CONT "%02x ", buffer[i]);
++		printk("\n");
++	}
++	/* HACK: This test was added to avoid tuner to probe tda9840 and
++	   tea6415c on the MXB card */
++	if (client->adapter->id == I2C_HW_SAA7146 && client->addr < 0x4a) {
++		kfree(t);
++		return -ENODEV;
 +	}
 +
-+	return err ? -EIO : 0;
-+}
++	/* autodetection code based on the i2c addr */
++	if (!no_autodetect) {
++		switch (client->addr) {
++		case 0x10:
++			if (tea5761_autodetection(t->i2c->adapter, t->i2c->addr)
++					!= EINVAL) {
++				t->type = TUNER_TEA5761;
++				t->mode_mask = T_RADIO;
++				t->mode = T_STANDBY;
++				/* Sets freq to FM range */
++				t->radio_freq = 87.5 * 16000;
++				tuner_lookup(t->i2c->adapter, &radio, &tv);
++				if (tv)
++					tv->mode_mask &= ~T_RADIO;
 +
-+static int mt9v111_set_ctrl(struct sn9c102_device *cam,
-+			    const struct v4l2_control *ctrl)
-+{
-+	struct sn9c102_sensor *s = sn9c102_get_sensor(cam);
-+	int err = 0;
++				goto register_client;
++			}
++			break;
++		case 0x42:
++		case 0x43:
++		case 0x4a:
++		case 0x4b:
++			/* If chip is not tda8290, don't register.
++			   since it can be tda9887*/
++			if (tda829x_probe(t->i2c->adapter,
++					  t->i2c->addr) == 0) {
++				tuner_dbg("tda829x detected\n");
++			} else {
++				/* Default is being tda9887 */
++				t->type = TUNER_TDA9887;
++				t->mode_mask = T_RADIO | T_ANALOG_TV |
++					       T_DIGITAL_TV;
++				t->mode = T_STANDBY;
++				goto register_client;
++			}
++			break;
++		case 0x60:
++			if (tea5767_autodetection(t->i2c->adapter, t->i2c->addr)
++					!= EINVAL) {
++				t->type = TUNER_TEA5767;
++				t->mode_mask = T_RADIO;
++				t->mode = T_STANDBY;
++				/* Sets freq to FM range */
++				t->radio_freq = 87.5 * 16000;
++				tuner_lookup(t->i2c->adapter, &radio, &tv);
++				if (tv)
++					tv->mode_mask &= ~T_RADIO;
 +
-+	switch (ctrl->id) {
-+	case V4L2_CID_VFLIP:
-+		err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
-+						 0x20,
-+						 ctrl->value ? 0x80 : 0x00,
-+						 ctrl->value ? 0x80 : 0x00, 0,
-+						 0);
-+		break;
-+	default:
-+		return -EINVAL;
++				goto register_client;
++			}
++			break;
++		}
 +	}
 +
-+	return err ? -EIO : 0;
++	/* Initializes only the first TV tuner on this adapter. Why only the
++	   first? Because there are some devices (notably the ones with TI
++	   tuners) that have more than one i2c address for the *same* device.
++	   Experience shows that, except for just one case, the first
++	   address is the right one. The exception is a Russian tuner
++	   (ACORP_Y878F). So, the desired behavior is just to enable the
++	   first found TV tuner. */
++	tuner_lookup(t->i2c->adapter, &radio, &tv);
++	if (tv == NULL) {
++		t->mode_mask = T_ANALOG_TV | T_DIGITAL_TV;
++		if (radio == NULL)
++			t->mode_mask |= T_RADIO;
++		tuner_dbg("Setting mode_mask to 0x%02x\n", t->mode_mask);
++		t->tv_freq = 400 * 16; /* Sets freq to VHF High */
++		t->radio_freq = 87.5 * 16000; /* Sets freq to FM range */
++	}
++
++	/* Should be just before return */
++register_client:
++	tuner_info("chip found @ 0x%x (%s)\n", client->addr << 1,
++		       client->adapter->name);
++
++	/* Sets a default mode */
++	if (t->mode_mask & T_ANALOG_TV) {
++		t->mode = V4L2_TUNER_ANALOG_TV;
++	} else  if (t->mode_mask & T_RADIO) {
++		t->mode = V4L2_TUNER_RADIO;
++	} else {
++		t->mode = V4L2_TUNER_DIGITAL_TV;
++	}
++	set_type(client, t->type, t->mode_mask, t->config, t->tuner_callback);
++	list_add_tail(&t->list, &tuner_list);
++	return 0;
 +}
 +
-+static int mt9v111_set_crop(struct sn9c102_device *cam,
-+			    const struct v4l2_rect *rect)
++static int tuner_legacy_probe(struct i2c_adapter *adap)
 +{
-+	struct sn9c102_sensor *s = sn9c102_get_sensor(cam);
-+	int err = 0;
-+	u8 v_start = (u8) (rect->top - s->cropcap.bounds.top) + 2;
++	if (0 != addr) {
++		normal_i2c[0] = addr;
++		normal_i2c[1] = I2C_CLIENT_END;
++	}
 +
-+	err += sn9c102_write_reg(cam, v_start, 0x13);
++	if ((adap->class & I2C_CLASS_TV_ANALOG) == 0)
++		return 0;
 +
-+	return err;
-+}
++	/* HACK: Ignore 0x6b and 0x6f on cx88 boards.
++	 * FusionHDTV5 RT Gold has an ir receiver at 0x6b
++	 * and an RTC at 0x6f which can get corrupted if probed.
++	 */
++	if ((adap->id == I2C_HW_B_CX2388x) ||
++	    (adap->id == I2C_HW_B_CX23885)) {
++		unsigned int i = 0;
 +
-+static int mt9v111_set_pix_format(struct sn9c102_device *cam,
-+				  const struct v4l2_pix_format *pix)
++		while (i < I2C_CLIENT_MAX_OPTS && ignore[i] != I2C_CLIENT_END)
++			i += 2;
++		if (i + 4 < I2C_CLIENT_MAX_OPTS) {
++			ignore[i+0] = adap->nr;
++			ignore[i+1] = 0x6b;
++			ignore[i+2] = adap->nr;
++			ignore[i+3] = 0x6f;
++			ignore[i+4] = I2C_CLIENT_END;
++		} else
++			printk(KERN_WARNING "tuner: "
++			       "too many options specified "
++			       "in i2c probe ignore list!\n");
++	}
++	return 1;
+ }
+ 
+-module_init(tuner_init_module);
+-module_exit(tuner_cleanup_module);
++static int tuner_remove(struct i2c_client *client)
 +{
-+	int err = 0;
++	struct tuner *t = i2c_get_clientdata(client);
++	struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
 +
-+	if (pix->pixelformat == V4L2_PIX_FMT_SBGGR8) {
-+		err += sn9c102_write_reg(cam, 0xb4, 0x17);
-+	} else {
-+		err += sn9c102_write_reg(cam, 0xe2, 0x17);
-+	}
++	if (analog_ops->release)
++		analog_ops->release(&t->fe);
 +
-+	return err;
++	list_del(&t->list);
++	kfree(t);
++	return 0;
 +}
 +
++/* ----------------------------------------------------------------------- */
++
++static struct v4l2_i2c_driver_data v4l2_i2c_data = {
++	.name = "tuner",
++	.driverid = I2C_DRIVERID_TUNER,
++	.command = tuner_command,
++	.probe = tuner_probe,
++	.remove = tuner_remove,
++	.suspend = tuner_suspend,
++	.resume = tuner_resume,
++	.legacy_probe = tuner_legacy_probe,
++};
++
+ 
+ /*
+  * Overrides for Emacs so that we follow Linus's tabbing style.
+diff --git a/drivers/media/video/tuner-driver.h b/drivers/media/video/tuner-driver.h
+deleted file mode 100644
+index 28a10da..0000000
+--- a/drivers/media/video/tuner-driver.h
++++ /dev/null
+@@ -1,99 +0,0 @@
+-/*
+-    tuner-driver.h - interface for different tuners
+-
+-    Copyright (C) 1997 Markus Schroeder (schroedm at uni-duesseldorf.de)
+-    minor modifications by Ralph Metzler (rjkm at 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.
+-*/
+-
+-#ifndef __TUNER_DRIVER_H__
+-#define __TUNER_DRIVER_H__
+-
+-#include <linux/videodev2.h>
+-#include <linux/i2c.h>
+-#include "tuner-i2c.h"
+-#include "dvb_frontend.h"
+-
+-extern unsigned const int tuner_count;
+-
+-struct tuner;
+-
+-struct tuner_operations {
+-	void (*set_tv_freq)(struct tuner *t, unsigned int freq);
+-	void (*set_radio_freq)(struct tuner *t, unsigned int freq);
+-	int  (*has_signal)(struct tuner *t);
+-	int  (*is_stereo)(struct tuner *t);
+-	int  (*get_afc)(struct tuner *t);
+-	void (*tuner_status)(struct tuner *t);
+-	void (*standby)(struct tuner *t);
+-	void (*release)(struct tuner *t);
+-};
+-
+-struct tuner {
+-	/* device */
+-	struct i2c_client i2c;
+-
+-	unsigned int type;	/* chip type */
+-
+-	unsigned int mode;
+-	unsigned int mode_mask;	/* Combination of allowable modes */
+-
+-	unsigned int tv_freq;	/* keep track of the current settings */
+-	unsigned int radio_freq;
+-	unsigned int audmode;
+-	v4l2_std_id  std;
+-
+-	int          using_v4l2;
+-	void *priv;
+-
+-	struct dvb_frontend fe;
+-
+-	/* used by tda9887 */
+-	unsigned int       tda9887_config;
+-
+-	unsigned int config;
+-	int (*tuner_callback) (void *dev, int command,int arg);
+-
+-	struct tuner_operations ops;
+-};
+-
+-/* ------------------------------------------------------------------------ */
+-
+-extern int tda9887_tuner_init(struct tuner *t);
+-
+-/* ------------------------------------------------------------------------ */
+-
+-#define tuner_warn(fmt, arg...) do {\
+-	printk(KERN_WARNING "%s %d-%04x: " fmt, t->i2c.driver->driver.name, \
+-			i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0)
+-#define tuner_info(fmt, arg...) do {\
+-	printk(KERN_INFO "%s %d-%04x: " fmt, t->i2c.driver->driver.name, \
+-			i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0)
+-#define tuner_dbg(fmt, arg...) do {\
+-	extern int tuner_debug; \
+-	if (tuner_debug) \
+-		printk(KERN_DEBUG "%s %d-%04x: " fmt, t->i2c.driver->driver.name, \
+-			i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0)
+-
+-#endif /* __TUNER_DRIVER_H__ */
+-
+-/*
+- * Overrides for Emacs so that we follow Linus's tabbing style.
+- * ---------------------------------------------------------------------------
+- * Local variables:
+- * c-basic-offset: 8
+- * End:
+- */
+diff --git a/drivers/media/video/tuner-i2c.h b/drivers/media/video/tuner-i2c.h
+index 159019e..de52e8f 100644
+--- a/drivers/media/video/tuner-i2c.h
++++ b/drivers/media/video/tuner-i2c.h
+@@ -46,25 +46,42 @@ static inline int tuner_i2c_xfer_recv(struct tuner_i2c_props *props, char *buf,
+ 	return (ret == 1) ? len : ret;
+ }
+ 
+-#ifndef __TUNER_DRIVER_H__
+-#define tuner_warn(fmt, arg...) do {\
+-	printk(KERN_WARNING PREFIX "%d-%04x: " fmt, \
+-			i2c_adapter_id(priv->i2c_props.adap), priv->i2c_props.addr , ##arg); } while (0)
+-#define tuner_info(fmt, arg...) do {\
+-	printk(KERN_INFO PREFIX "%d-%04x: " fmt, \
+-			i2c_adapter_id(priv->i2c_props.adap), priv->i2c_props.addr , ##arg); } while (0)
+-#define tuner_dbg(fmt, arg...) do {\
+-	if ((debug)) \
+-		printk(KERN_DEBUG PREFIX "%d-%04x: " fmt, \
+-			i2c_adapter_id(priv->i2c_props.adap), priv->i2c_props.addr , ##arg); } while (0)
+-#endif /* __TUNER_DRIVER_H__ */
++static inline int tuner_i2c_xfer_send_recv(struct tuner_i2c_props *props,
++					   char *obuf, int olen,
++					   char *ibuf, int ilen)
++{
++	struct i2c_msg msg[2] = { { .addr = props->addr, .flags = 0,
++				    .buf = obuf, .len = olen },
++				  { .addr = props->addr, .flags = I2C_M_RD,
++				    .buf = ibuf, .len = ilen } };
++	int ret = i2c_transfer(props->adap, msg, 2);
+ 
+-#endif /* __TUNER_I2C_H__ */
++	return (ret == 2) ? ilen : ret;
++}
+ 
+-/*
+- * Overrides for Emacs so that we follow Linus's tabbing style.
+- * ---------------------------------------------------------------------------
+- * Local variables:
+- * c-basic-offset: 8
+- * End:
+- */
++#define tuner_warn(fmt, arg...) do {					\
++	printk(KERN_WARNING "%s %d-%04x: " fmt, PREFIX,			\
++			i2c_adapter_id(priv->i2c_props.adap),		\
++			priv->i2c_props.addr, ##arg);			\
++	 } while (0)
 +
-+static const struct sn9c102_sensor mt9v111 = {
-+	.name = "MT9V111",
-+	.maintainer = "Luca Risolia <luca.risolia at studio.unibo.it>",
-+	.supported_bridge = BRIDGE_SN9C105 | BRIDGE_SN9C120,
-+	.frequency = SN9C102_I2C_100KHZ,
-+	.interface = SN9C102_I2C_2WIRES,
-+	.i2c_slave_id = 0x5c,
-+	.init = &mt9v111_init,
-+	.qctrl = {
-+		{
-+			.id = V4L2_CID_VFLIP,
-+			.type = V4L2_CTRL_TYPE_BOOLEAN,
-+			.name = "vertical mirror",
-+			.minimum = 0,
-+			.maximum = 1,
-+			.step = 1,
-+			.default_value = 0,
-+			.flags = 0,
-+		},
-+	},
-+	.get_ctrl = &mt9v111_get_ctrl,
-+	.set_ctrl = &mt9v111_set_ctrl,
-+	.cropcap = {
-+		.bounds = {
-+			.left = 0,
-+			.top = 0,
-+			.width = 640,
-+			.height = 480,
-+		},
-+		.defrect = {
-+			.left = 0,
-+			.top = 0,
-+			.width = 640,
-+			.height = 480,
-+		},
-+	},
-+	.set_crop = &mt9v111_set_crop,
-+	.pix_format = {
-+		.width = 640,
-+		.height = 480,
-+		.pixelformat = V4L2_PIX_FMT_SBGGR8,
-+		.priv = 8,
-+	},
-+	.set_pix_format = &mt9v111_set_pix_format
-+};
++#define tuner_info(fmt, arg...) do {					\
++	printk(KERN_INFO "%s %d-%04x: " fmt, PREFIX,			\
++			i2c_adapter_id(priv->i2c_props.adap),		\
++			priv->i2c_props.addr , ##arg);			\
++	} while (0)
 +
++#define tuner_err(fmt, arg...) do {					\
++	printk(KERN_ERR "%s %d-%04x: " fmt, PREFIX, 			\
++			i2c_adapter_id(priv->i2c_props.adap),		\
++			priv->i2c_props.addr , ##arg);			\
++	} while (0)
 +
-+int sn9c102_probe_mt9v111(struct sn9c102_device *cam)
-+{
-+	u8 data[2];
-+	int err = 0;
++#define tuner_dbg(fmt, arg...) do {					\
++	if ((debug))							\
++		printk(KERN_DEBUG "%s %d-%04x: " fmt, PREFIX,		\
++			i2c_adapter_id(priv->i2c_props.adap),		\
++			priv->i2c_props.addr , ##arg);			\
++	} while (0)
 +
-+	err += sn9c102_write_const_regs(cam, {0x01, 0xf1}, {0x00, 0xf1},
-+					{0x29, 0x01}, {0x42, 0x17},
-+					{0x62, 0x17}, {0x08, 0x01});
-+	err += sn9c102_i2c_try_raw_write(cam, &mt9v111, 4,
-+					 mt9v111.i2c_slave_id, 0x01, 0x00,
-+					 0x04, 0, 0);
-+	if (err || sn9c102_i2c_try_raw_read(cam, &mt9v111,
-+					    mt9v111.i2c_slave_id, 0x36, 2,
-+					    data) < 0)
-+		return -EIO;
++#endif /* __TUNER_I2C_H__ */
+diff --git a/drivers/media/video/tuner-simple.c b/drivers/media/video/tuner-simple.c
+index 7b93d3b..c1db576 100644
+--- a/drivers/media/video/tuner-simple.c
++++ b/drivers/media/video/tuner-simple.c
+@@ -17,7 +17,7 @@ static int debug = 0;
+ module_param(debug, int, 0644);
+ MODULE_PARM_DESC(debug, "enable verbose debug messages");
+ 
+-#define PREFIX "tuner-simple "
++#define PREFIX "tuner-simple"
+ 
+ static int offset = 0;
+ module_param(offset, int, 0664);
+@@ -355,10 +355,14 @@ static int simple_set_tv_freq(struct dvb_frontend *fe,
+ 	}
+ 	priv->last_div = div;
+ 	if (t_params->has_tda9887) {
++		struct v4l2_priv_tun_config tda9887_cfg;
+ 		int config = 0;
+ 		int is_secam_l = (params->std & (V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC)) &&
+ 			!(params->std & ~(V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC));
+ 
++		tda9887_cfg.tuner = TUNER_TDA9887;
++		tda9887_cfg.priv  = &config;
 +
-+	if (data[0] != 0x82 || data[1] != 0x3a)
-+		return -ENODEV;
+ 		if (params->std == V4L2_STD_SECAM_LC) {
+ 			if (t_params->port1_active ^ t_params->port1_invert_for_secam_lc)
+ 				config |= TDA9887_PORT1_ACTIVE;
+@@ -391,7 +395,8 @@ static int simple_set_tv_freq(struct dvb_frontend *fe,
+ 		}
+ 		if (t_params->default_pll_gating_18)
+ 			config |= TDA9887_GATING_18;
+-		i2c_clients_command(priv->i2c_props.adap, TDA9887_SET_CONFIG, &config);
++		i2c_clients_command(priv->i2c_props.adap, TUNER_SET_CONFIG,
++				    &tda9887_cfg);
+ 	}
+ 	tuner_dbg("tv 0x%02x 0x%02x 0x%02x 0x%02x\n",
+ 		  buffer[0],buffer[1],buffer[2],buffer[3]);
+@@ -534,6 +539,11 @@ static int simple_set_radio_freq(struct dvb_frontend *fe,
+ 
+ 	if (t_params->has_tda9887) {
+ 		int config = 0;
++		struct v4l2_priv_tun_config tda9887_cfg;
 +
-+	sn9c102_attach_sensor(cam, &mt9v111);
++		tda9887_cfg.tuner = TUNER_TDA9887;
++		tda9887_cfg.priv = &config;
 +
-+	return 0;
-+}
-diff --git a/drivers/media/video/stk-sensor.c b/drivers/media/video/stk-sensor.c
+ 		if (t_params->port1_active && !t_params->port1_fm_high_sensitivity)
+ 			config |= TDA9887_PORT1_ACTIVE;
+ 		if (t_params->port2_active && !t_params->port2_fm_high_sensitivity)
+@@ -546,7 +556,8 @@ static int simple_set_radio_freq(struct dvb_frontend *fe,
+ 			config |= TDA9887_GAIN_NORMAL;
+ 		if (t_params->radio_if == 2)
+ 			config |= TDA9887_RIF_41_3;
+-		i2c_clients_command(priv->i2c_props.adap, TDA9887_SET_CONFIG, &config);
++		i2c_clients_command(priv->i2c_props.adap, TUNER_SET_CONFIG,
++					&tda9887_cfg);
+ 	}
+ 	if (4 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,buffer,4)))
+ 		tuner_warn("i2c i/o error: rc == %d (should be 4)\n",rc);
+diff --git a/drivers/media/video/tuner-types.c b/drivers/media/video/tuner-types.c
+index c6a7934..883047f 100644
+--- a/drivers/media/video/tuner-types.c
++++ b/drivers/media/video/tuner-types.c
+@@ -1366,7 +1366,7 @@ struct tunertype tuners[] = {
+ 		.count  = ARRAY_SIZE(tuner_philips_fq1286_params),
+ 	},
+ 	[TUNER_PHILIPS_TDA8290] = { /* Philips PAL|NTSC */
+-		.name   = "tda8290+75",
++		.name   = "Philips/NXP TDA 8290/8295 + 8275/8275A/18271",
+ 		/* see tda8290.c for details */ },
+ 	[TUNER_TCL_2002MB] = { /* TCL PAL */
+ 		.name   = "TCL 2002MB",
+@@ -1452,9 +1452,9 @@ struct tunertype tuners[] = {
+ 		.params = tuner_samsung_tcpn_2121p30a_params,
+ 		.count  = ARRAY_SIZE(tuner_samsung_tcpn_2121p30a_params),
+ 	},
+-	[TUNER_XCEIVE_XC3028] = { /* Xceive 3028 */
+-		.name	= "Xceive xc3028",
+-		/* see xc3028.c for details */
++	[TUNER_XC2028] = { /* Xceive 2028 */
++		.name   = "Xceive xc2028/xc3028 tuner",
++		/* see tuner-xc2028.c for details */
+ 	},
+ 	[TUNER_THOMSON_FE6600] = { /* Thomson PAL / DVB-T */
+ 		.name   = "Thomson FE6600",
+@@ -1475,6 +1475,10 @@ struct tunertype tuners[] = {
+ 		.name   = "Philips TEA5761 FM Radio",
+ 		/* see tea5767.c for details */
+ 	},
++	[TUNER_XC5000] = { /* Xceive 5000 */
++		.name   = "Xceive 5000 tuner",
++		/* see xc5000.c for details */
++	},
+ };
+ 
+ unsigned const int tuner_count = ARRAY_SIZE(tuners);
+diff --git a/drivers/media/video/tuner-xc2028-types.h b/drivers/media/video/tuner-xc2028-types.h
 new file mode 100644
-index 0000000..4a9a0b6
+index 0000000..d0057fb
 --- /dev/null
-+++ b/drivers/media/video/stk-sensor.c
-@@ -0,0 +1,578 @@
-+/* stk-sensor.c: Driver for ov96xx sensor (used in some Syntek webcams)
-+ *
-+ * Copyright 2007-2008 Jaime Velasco Juan <jsagarribay at gmail.com>
-+ *
-+ * Some parts derived from ov7670.c:
-+ * Copyright 2006 One Laptop Per Child Association, Inc.  Written
-+ * by Jonathan Corbet with substantial inspiration from Mark
-+ * McClelland's ovcamchip code.
-+ *
-+ * Copyright 2006-7 Jonathan Corbet <corbet at lwn.net>
-+ *
-+ * This file may be distributed under the terms of the GNU General
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+ * GNU General Public License for more details.
++++ b/drivers/media/video/tuner-xc2028-types.h
+@@ -0,0 +1,128 @@
++/* tuner-xc2028_types
 + *
-+ * You 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.
++ * Copyright (c) 2007 Mauro Carvalho Chehab (mchehab at infradead.org)
++ * This code is placed under the terms of the GNU General Public License v2
 + */
 +
-+/* Controlling the sensor via the STK1125 vendor specific control interface:
-+ * The camera uses an OmniVision sensor and the stk1125 provides an
-+ * SCCB(i2c)-USB bridge which let us program the sensor.
-+ * In my case the sensor id is 0x9652, it can be read from sensor's register
-+ * 0x0A and 0x0B as follows:
-+ * - read register #R:
-+ *   output #R to index 0x0208
-+ *   output 0x0070 to index 0x0200
-+ *   input 1 byte from index 0x0201 (some kind of status register)
-+ *     until its value is 0x01
-+ *   input 1 byte from index 0x0209. This is the value of #R
-+ * - write value V to register #R
-+ *   output #R to index 0x0204
-+ *   output V to index 0x0205
-+ *   output 0x0005 to index 0x0200
-+ *   input 1 byte from index 0x0201 until its value becomes 0x04
-+ */
++/* xc3028 firmware types */
 +
-+/* It seems the i2c bus is controlled with these registers */
++/* BASE firmware should be loaded before any other firmware */
++#define BASE		(1<<0)
++#define BASE_TYPES	(BASE|F8MHZ|MTS|FM|INPUT1|INPUT2|INIT1)
 +
-+#include "stk-webcam.h"
++/* F8MHZ marks BASE firmwares for 8 MHz Bandwidth */
++#define F8MHZ		(1<<1)
 +
-+#define STK_IIC_BASE		(0x0200)
-+#  define STK_IIC_OP		(STK_IIC_BASE)
-+#    define STK_IIC_OP_TX	(0x05)
-+#    define STK_IIC_OP_RX	(0x70)
-+#  define STK_IIC_STAT		(STK_IIC_BASE+1)
-+#    define STK_IIC_STAT_TX_OK	(0x04)
-+#    define STK_IIC_STAT_RX_OK	(0x01)
-+/* I don't know what does this register.
-+ * when it is 0x00 or 0x01, we cannot talk to the sensor,
-+ * other values work */
-+#  define STK_IIC_ENABLE	(STK_IIC_BASE+2)
-+#    define STK_IIC_ENABLE_NO	(0x00)
-+/* This is what the driver writes in windows */
-+#    define STK_IIC_ENABLE_YES	(0x1e)
-+/*
-+ * Address of the slave. Seems like the binary driver look for the
-+ * sensor in multiple places, attempting a reset sequence.
-+ * We only know about the ov9650
++/* Multichannel Television Sound (MTS)
++   Those firmwares are capable of using xc2038 DSP to decode audio and
++   produce a baseband audio output on some pins of the chip.
++   There are MTS firmwares for the most used video standards. It should be
++   required to use MTS firmwares, depending on the way audio is routed into
++   the bridge chip
 + */
-+#  define STK_IIC_ADDR		(STK_IIC_BASE+3)
-+#  define STK_IIC_TX_INDEX	(STK_IIC_BASE+4)
-+#  define STK_IIC_TX_VALUE	(STK_IIC_BASE+5)
-+#  define STK_IIC_RX_INDEX	(STK_IIC_BASE+8)
-+#  define STK_IIC_RX_VALUE	(STK_IIC_BASE+9)
++#define MTS		(1<<2)
 +
-+#define MAX_RETRIES		(50)
++/* FIXME: I have no idea what's the difference between
++   D2620 and D2633 firmwares
++ */
++#define D2620		(1<<3)
++#define D2633		(1<<4)
 +
-+#define SENSOR_ADDRESS		(0x60)
++/* DTV firmwares for 6, 7 and 8 MHz
++   DTV6 - 6MHz - ATSC/DVB-C/DVB-T/ISDB-T/DOCSIS
++   DTV8 - 8MHz - DVB-C/DVB-T
++ */
++#define DTV6           (1 << 5)
++#define QAM            (1 << 6)
++#define DTV7		(1<<7)
++#define DTV78		(1<<8)
++#define DTV8		(1<<9)
 +
-+/* From ov7670.c (These registers aren't fully accurate) */
++#define DTV_TYPES	(D2620|D2633|DTV6|QAM|DTV7|DTV78|DTV8|ATSC)
 +
-+/* Registers */
-+#define REG_GAIN	0x00	/* Gain lower 8 bits (rest in vref) */
-+#define REG_BLUE	0x01	/* blue gain */
-+#define REG_RED		0x02	/* red gain */
-+#define REG_VREF	0x03	/* Pieces of GAIN, VSTART, VSTOP */
-+#define REG_COM1	0x04	/* Control 1 */
-+#define  COM1_CCIR656	  0x40  /* CCIR656 enable */
-+#define  COM1_QFMT	  0x20  /* QVGA/QCIF format */
-+#define  COM1_SKIP_0	  0x00  /* Do not skip any row */
-+#define  COM1_SKIP_2	  0x04  /* Skip 2 rows of 4 */
-+#define  COM1_SKIP_3	  0x08  /* Skip 3 rows of 4 */
-+#define REG_BAVE	0x05	/* U/B Average level */
-+#define REG_GbAVE	0x06	/* Y/Gb Average level */
-+#define REG_AECHH	0x07	/* AEC MS 5 bits */
-+#define REG_RAVE	0x08	/* V/R Average level */
-+#define REG_COM2	0x09	/* Control 2 */
-+#define  COM2_SSLEEP	  0x10	/* Soft sleep mode */
-+#define REG_PID		0x0a	/* Product ID MSB */
-+#define REG_VER		0x0b	/* Product ID LSB */
-+#define REG_COM3	0x0c	/* Control 3 */
-+#define  COM3_SWAP	  0x40	  /* Byte swap */
-+#define  COM3_SCALEEN	  0x08	  /* Enable scaling */
-+#define  COM3_DCWEN	  0x04	  /* Enable downsamp/crop/window */
-+#define REG_COM4	0x0d	/* Control 4 */
-+#define REG_COM5	0x0e	/* All "reserved" */
-+#define REG_COM6	0x0f	/* Control 6 */
-+#define REG_AECH	0x10	/* More bits of AEC value */
-+#define REG_CLKRC	0x11	/* Clock control */
-+#define   CLK_PLL	  0x80	  /* Enable internal PLL */
-+#define   CLK_EXT	  0x40	  /* Use external clock directly */
-+#define   CLK_SCALE	  0x3f	  /* Mask for internal clock scale */
-+#define REG_COM7	0x12	/* Control 7 */
-+#define   COM7_RESET	  0x80	  /* Register reset */
-+#define   COM7_FMT_MASK	  0x38
-+#define   COM7_FMT_SXGA	  0x00
-+#define   COM7_FMT_VGA	  0x40
-+#define	  COM7_FMT_CIF	  0x20	  /* CIF format */
-+#define   COM7_FMT_QVGA	  0x10	  /* QVGA format */
-+#define   COM7_FMT_QCIF	  0x08	  /* QCIF format */
-+#define	  COM7_RGB	  0x04	  /* bits 0 and 2 - RGB format */
-+#define	  COM7_YUV	  0x00	  /* YUV */
-+#define	  COM7_BAYER	  0x01	  /* Bayer format */
-+#define	  COM7_PBAYER	  0x05	  /* "Processed bayer" */
-+#define REG_COM8	0x13	/* Control 8 */
-+#define   COM8_FASTAEC	  0x80	  /* Enable fast AGC/AEC */
-+#define   COM8_AECSTEP	  0x40	  /* Unlimited AEC step size */
-+#define   COM8_BFILT	  0x20	  /* Band filter enable */
-+#define   COM8_AGC	  0x04	  /* Auto gain enable */
-+#define   COM8_AWB	  0x02	  /* White balance enable */
-+#define   COM8_AEC	  0x01	  /* Auto exposure enable */
-+#define REG_COM9	0x14	/* Control 9  - gain ceiling */
-+#define REG_COM10	0x15	/* Control 10 */
-+#define   COM10_HSYNC	  0x40	  /* HSYNC instead of HREF */
-+#define   COM10_PCLK_HB	  0x20	  /* Suppress PCLK on horiz blank */
-+#define   COM10_HREF_REV  0x08	  /* Reverse HREF */
-+#define   COM10_VS_LEAD	  0x04	  /* VSYNC on clock leading edge */
-+#define   COM10_VS_NEG	  0x02	  /* VSYNC negative */
-+#define   COM10_HS_NEG	  0x01	  /* HSYNC negative */
-+#define REG_HSTART	0x17	/* Horiz start high bits */
-+#define REG_HSTOP	0x18	/* Horiz stop high bits */
-+#define REG_VSTART	0x19	/* Vert start high bits */
-+#define REG_VSTOP	0x1a	/* Vert stop high bits */
-+#define REG_PSHFT	0x1b	/* Pixel delay after HREF */
-+#define REG_MIDH	0x1c	/* Manuf. ID high */
-+#define REG_MIDL	0x1d	/* Manuf. ID low */
-+#define REG_MVFP	0x1e	/* Mirror / vflip */
-+#define   MVFP_MIRROR	  0x20	  /* Mirror image */
-+#define   MVFP_FLIP	  0x10	  /* Vertical flip */
++/* There's a FM | BASE firmware + FM specific firmware (std=0) */
++#define	FM		(1<<10)
 +
-+#define REG_AEW		0x24	/* AGC upper limit */
-+#define REG_AEB		0x25	/* AGC lower limit */
-+#define REG_VPT		0x26	/* AGC/AEC fast mode op region */
-+#define REG_ADVFL	0x2d	/* Insert dummy lines (LSB) */
-+#define REG_ADVFH	0x2e	/* Insert dummy lines (MSB) */
-+#define REG_HSYST	0x30	/* HSYNC rising edge delay */
-+#define REG_HSYEN	0x31	/* HSYNC falling edge delay */
-+#define REG_HREF	0x32	/* HREF pieces */
-+#define REG_TSLB	0x3a	/* lots of stuff */
-+#define   TSLB_YLAST	  0x04	  /* UYVY or VYUY - see com13 */
-+#define   TSLB_BYTEORD	  0x08	  /* swap bytes in 16bit mode? */
-+#define REG_COM11	0x3b	/* Control 11 */
-+#define   COM11_NIGHT	  0x80	  /* NIght mode enable */
-+#define   COM11_NMFR	  0x60	  /* Two bit NM frame rate */
-+#define   COM11_HZAUTO	  0x10	  /* Auto detect 50/60 Hz */
-+#define	  COM11_50HZ	  0x08	  /* Manual 50Hz select */
-+#define   COM11_EXP	  0x02
-+#define REG_COM12	0x3c	/* Control 12 */
-+#define   COM12_HREF	  0x80	  /* HREF always */
-+#define REG_COM13	0x3d	/* Control 13 */
-+#define   COM13_GAMMA	  0x80	  /* Gamma enable */
-+#define	  COM13_UVSAT	  0x40	  /* UV saturation auto adjustment */
-+#define	  COM13_CMATRIX	  0x10	  /* Enable color matrix for RGB or YUV */
-+#define   COM13_UVSWAP	  0x01	  /* V before U - w/TSLB */
-+#define REG_COM14	0x3e	/* Control 14 */
-+#define   COM14_DCWEN	  0x10	  /* DCW/PCLK-scale enable */
-+#define REG_EDGE	0x3f	/* Edge enhancement factor */
-+#define REG_COM15	0x40	/* Control 15 */
-+#define   COM15_R10F0	  0x00	  /* Data range 10 to F0 */
-+#define	  COM15_R01FE	  0x80	  /*            01 to FE */
-+#define   COM15_R00FF	  0xc0	  /*            00 to FF */
-+#define   COM15_RGB565	  0x10	  /* RGB565 output */
-+#define   COM15_RGBFIXME	  0x20	  /* FIXME  */
-+#define   COM15_RGB555	  0x30	  /* RGB555 output */
-+#define REG_COM16	0x41	/* Control 16 */
-+#define   COM16_AWBGAIN   0x08	  /* AWB gain enable */
-+#define REG_COM17	0x42	/* Control 17 */
-+#define   COM17_AECWIN	  0xc0	  /* AEC window - must match COM4 */
-+#define   COM17_CBAR	  0x08	  /* DSP Color bar */
++#define STD_SPECIFIC_TYPES (MTS|FM|LCD|NOGD)
 +
-+/*
-+ * This matrix defines how the colors are generated, must be
-+ * tweaked to adjust hue and saturation.
-+ *
-+ * Order: v-red, v-green, v-blue, u-red, u-green, u-blue
-+ *
-+ * They are nine-bit signed quantities, with the sign bit
-+ * stored in 0x58.  Sign for v-red is bit 0, and up from there.
++/* Applies only for FM firmware
++   Makes it use RF input 1 (pin #2) instead of input 2 (pin #4)
 + */
-+#define	REG_CMATRIX_BASE 0x4f
-+#define   CMATRIX_LEN 6
-+#define REG_CMATRIX_SIGN 0x58
++#define INPUT1		(1<<11)
 +
 +
-+#define REG_BRIGHT	0x55	/* Brightness */
-+#define REG_CONTRAS	0x56	/* Contrast control */
++/* LCD firmwares exist only for MTS STD/MN (PAL or NTSC/M)
++	and for non-MTS STD/MN (PAL, NTSC/M or NTSC/Kr)
++	There are variants both with and without NOGD
++ */
++#define LCD		(1<<12)
 +
-+#define REG_GFIX	0x69	/* Fix gain control */
++/* NOGD firmwares exist only for MTS STD/MN (PAL or NTSC/M)
++	and for non-MTS STD/MN (PAL, NTSC/M or NTSC/Kr)
++ */
++#define NOGD		(1<<13)
 +
-+#define REG_RGB444	0x8c	/* RGB 444 control */
-+#define   R444_ENABLE	  0x02	  /* Turn on RGB444, overrides 5x5 */
-+#define   R444_RGBX	  0x01	  /* Empty nibble at end */
++/* Old firmwares were broken into init0 and init1 */
++#define INIT1		(1<<14)
 +
-+#define REG_HAECC1	0x9f	/* Hist AEC/AGC control 1 */
-+#define REG_HAECC2	0xa0	/* Hist AEC/AGC control 2 */
++/* SCODE firmware selects particular behaviours */
++#define MONO           (1 << 15)
++#define ATSC           (1 << 16)
++#define IF             (1 << 17)
++#define LG60           (1 << 18)
++#define ATI638         (1 << 19)
++#define OREN538        (1 << 20)
++#define OREN36         (1 << 21)
++#define TOYOTA388      (1 << 22)
++#define TOYOTA794      (1 << 23)
++#define DIBCOM52       (1 << 24)
++#define ZARLINK456     (1 << 25)
++#define CHINA          (1 << 26)
++#define F6MHZ          (1 << 27)
++#define INPUT2         (1 << 28)
++#define SCODE          (1 << 29)
 +
-+#define REG_BD50MAX	0xa5	/* 50hz banding step limit */
-+#define REG_HAECC3	0xa6	/* Hist AEC/AGC control 3 */
-+#define REG_HAECC4	0xa7	/* Hist AEC/AGC control 4 */
-+#define REG_HAECC5	0xa8	/* Hist AEC/AGC control 5 */
-+#define REG_HAECC6	0xa9	/* Hist AEC/AGC control 6 */
-+#define REG_HAECC7	0xaa	/* Hist AEC/AGC control 7 */
-+#define REG_BD60MAX	0xab	/* 60hz banding step limit */
++/* This flag identifies that the scode table has a new format */
++#define HAS_IF         (1 << 30)
 +
++#define SCODE_TYPES	(MTS|DTV6|QAM|DTV7|DTV78|DTV8|LCD|NOGD|MONO|ATSC|IF| \
++			 LG60|ATI638|OREN538|OREN36|TOYOTA388|TOYOTA794|     \
++			 DIBCOM52|ZARLINK456|CHINA|F6MHZ|SCODE)
 +
++/* Newer types to be moved to videodev2.h */
 +
++#define V4L2_STD_SECAM_K3	(0x04000000)
 +
-+/* Returns 0 if OK */
-+int stk_sensor_outb(struct stk_camera *dev, u8 reg, u8 val)
-+{
-+	int i = 0;
-+	int tmpval = 0;
++/* Audio types */
 +
-+	if (stk_camera_write_reg(dev, STK_IIC_TX_INDEX, reg))
-+		return 1;
-+	if (stk_camera_write_reg(dev, STK_IIC_TX_VALUE, val))
-+		return 1;
-+	if (stk_camera_write_reg(dev, STK_IIC_OP, STK_IIC_OP_TX))
-+		return 1;
-+	do {
-+		if (stk_camera_read_reg(dev, STK_IIC_STAT, &tmpval))
-+			return 1;
-+		i++;
-+	} while (tmpval == 0 && i < MAX_RETRIES);
-+	if (tmpval != STK_IIC_STAT_TX_OK) {
-+		if (tmpval)
-+			STK_ERROR("stk_sensor_outb failed, status=0x%02x\n",
-+				tmpval);
-+		return 1;
-+	} else
-+		return 0;
-+}
++#define V4L2_STD_A2_A		(1LL<<32)
++#define V4L2_STD_A2_B		(1LL<<33)
++#define V4L2_STD_NICAM_A	(1LL<<34)
++#define V4L2_STD_NICAM_B	(1LL<<35)
++#define V4L2_STD_AM		(1LL<<36)
++#define V4L2_STD_BTSC		(1LL<<37)
++#define V4L2_STD_EIAJ		(1LL<<38)
 +
-+int stk_sensor_inb(struct stk_camera *dev, u8 reg, u8 *val)
-+{
-+	int i = 0;
-+	int tmpval = 0;
++#define V4L2_STD_A2		(V4L2_STD_A2_A    | V4L2_STD_A2_B)
++#define V4L2_STD_NICAM		(V4L2_STD_NICAM_A | V4L2_STD_NICAM_B)
 +
-+	if (stk_camera_write_reg(dev, STK_IIC_RX_INDEX, reg))
-+		return 1;
-+	if (stk_camera_write_reg(dev, STK_IIC_OP, STK_IIC_OP_RX))
-+		return 1;
-+	do {
-+		if (stk_camera_read_reg(dev, STK_IIC_STAT, &tmpval))
-+			return 1;
-+		i++;
-+	} while (tmpval == 0 && i < MAX_RETRIES);
-+	if (tmpval != STK_IIC_STAT_RX_OK) {
-+		if (tmpval)
-+			STK_ERROR("stk_sensor_inb failed, status=0x%02x\n",
-+				tmpval);
-+		return 1;
-+	}
++/* To preserve backward compatibilty,
++   (std & V4L2_STD_AUDIO) = 0 means that ALL audio stds are supported
++ */
 +
-+	if (stk_camera_read_reg(dev, STK_IIC_RX_VALUE, &tmpval))
-+		return 1;
++#define V4L2_STD_AUDIO		(V4L2_STD_A2    | \
++				 V4L2_STD_NICAM | \
++				 V4L2_STD_AM    | \
++				 V4L2_STD_BTSC  | \
++				 V4L2_STD_EIAJ)
 +
-+	*val = (u8) tmpval;
-+	return 0;
-+}
++/* Used standards with audio restrictions */
 +
-+static int stk_sensor_write_regvals(struct stk_camera *dev,
-+		struct regval *rv)
-+{
-+	int ret;
-+	if (rv == NULL)
-+		return 0;
-+	while (rv->reg != 0xff || rv->val != 0xff) {
-+		ret = stk_sensor_outb(dev, rv->reg, rv->val);
-+		if (ret != 0)
-+			return ret;
-+		rv++;
-+	}
-+	return 0;
-+}
++#define V4L2_STD_PAL_BG_A2_A	(V4L2_STD_PAL_BG | V4L2_STD_A2_A)
++#define V4L2_STD_PAL_BG_A2_B	(V4L2_STD_PAL_BG | V4L2_STD_A2_B)
++#define V4L2_STD_PAL_BG_NICAM_A	(V4L2_STD_PAL_BG | V4L2_STD_NICAM_A)
++#define V4L2_STD_PAL_BG_NICAM_B	(V4L2_STD_PAL_BG | V4L2_STD_NICAM_B)
++#define V4L2_STD_PAL_DK_A2	(V4L2_STD_PAL_DK | V4L2_STD_A2)
++#define V4L2_STD_PAL_DK_NICAM	(V4L2_STD_PAL_DK | V4L2_STD_NICAM)
++#define V4L2_STD_SECAM_L_NICAM	(V4L2_STD_SECAM_L | V4L2_STD_NICAM)
++#define V4L2_STD_SECAM_L_AM	(V4L2_STD_SECAM_L | V4L2_STD_AM)
+diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/video/tuner-xc2028.c
+new file mode 100644
+index 0000000..f191f6a
+--- /dev/null
++++ b/drivers/media/video/tuner-xc2028.c
+@@ -0,0 +1,1213 @@
++/* tuner-xc2028
++ *
++ * Copyright (c) 2007 Mauro Carvalho Chehab (mchehab at infradead.org)
++ *
++ * Copyright (c) 2007 Michel Ludwig (michel.ludwig at gmail.com)
++ *       - frontend interface
++ *
++ * This code is placed under the terms of the GNU General Public License v2
++ */
 +
-+int stk_sensor_sleep(struct stk_camera *dev)
-+{
-+	u8 tmp;
-+	return stk_sensor_inb(dev, REG_COM2, &tmp)
-+		|| stk_sensor_outb(dev, REG_COM2, tmp|COM2_SSLEEP);
-+}
++#include <linux/i2c.h>
++#include <asm/div64.h>
++#include <linux/firmware.h>
++#include <linux/videodev2.h>
++#include <linux/delay.h>
++#include <media/tuner.h>
++#include <linux/mutex.h>
++#include "tuner-i2c.h"
++#include "tuner-xc2028.h"
++#include "tuner-xc2028-types.h"
 +
-+int stk_sensor_wakeup(struct stk_camera *dev)
-+{
-+	u8 tmp;
-+	return stk_sensor_inb(dev, REG_COM2, &tmp)
-+		|| stk_sensor_outb(dev, REG_COM2, tmp&~COM2_SSLEEP);
-+}
++#include <linux/dvb/frontend.h>
++#include "dvb_frontend.h"
 +
-+static struct regval ov_initvals[] = {
-+	{REG_CLKRC, CLK_PLL},
-+	{REG_COM11, 0x01},
-+	{0x6a, 0x7d},
-+	{REG_AECH, 0x40},
-+	{REG_GAIN, 0x00},
-+	{REG_BLUE, 0x80},
-+	{REG_RED, 0x80},
-+	/* Do not enable fast AEC for now */
-+	/*{REG_COM8, COM8_FASTAEC|COM8_AECSTEP|COM8_BFILT|COM8_AGC|COM8_AEC},*/
-+	{REG_COM8, COM8_AECSTEP|COM8_BFILT|COM8_AGC|COM8_AEC},
-+	{0x39, 0x50}, {0x38, 0x93},
-+	{0x37, 0x00}, {0x35, 0x81},
-+	{REG_COM5, 0x20},
-+	{REG_COM1, 0x00},
-+	{REG_COM3, 0x00},
-+	{REG_COM4, 0x00},
-+	{REG_PSHFT, 0x00},
-+	{0x16, 0x07},
-+	{0x33, 0xe2}, {0x34, 0xbf},
-+	{REG_COM16, 0x00},
-+	{0x96, 0x04},
-+	/* Gamma curve values */
-+/*	{ 0x7a, 0x20 },		{ 0x7b, 0x10 },
-+	{ 0x7c, 0x1e },		{ 0x7d, 0x35 },
-+	{ 0x7e, 0x5a },		{ 0x7f, 0x69 },
-+	{ 0x80, 0x76 },		{ 0x81, 0x80 },
-+	{ 0x82, 0x88 },		{ 0x83, 0x8f },
-+	{ 0x84, 0x96 },		{ 0x85, 0xa3 },
-+	{ 0x86, 0xaf },		{ 0x87, 0xc4 },
-+	{ 0x88, 0xd7 },		{ 0x89, 0xe8 },
-+*/
-+	{REG_GFIX, 0x40},
-+	{0x8e, 0x00},
-+	{REG_COM12, 0x73},
-+	{0x8f, 0xdf}, {0x8b, 0x06},
-+	{0x8c, 0x20},
-+	{0x94, 0x88}, {0x95, 0x88},
-+/*	{REG_COM15, 0xc1}, TODO */
-+	{0x29, 0x3f},
-+	{REG_COM6, 0x42},
-+	{REG_BD50MAX, 0x80},
-+	{REG_HAECC6, 0xb8}, {REG_HAECC7, 0x92},
-+	{REG_BD60MAX, 0x0a},
-+	{0x90, 0x00}, {0x91, 0x00},
-+	{REG_HAECC1, 0x00}, {REG_HAECC2, 0x00},
-+	{REG_AEW, 0x68}, {REG_AEB, 0x5c},
-+	{REG_VPT, 0xc3},
-+	{REG_COM9, 0x2e},
-+	{0x2a, 0x00}, {0x2b, 0x00},
 +
-+	{0xff, 0xff}, /* END MARKER */
-+};
++#define PREFIX "xc2028"
 +
-+/* Probe the I2C bus and initialise the sensor chip */
-+int stk_sensor_init(struct stk_camera *dev)
-+{
-+	u8 idl = 0;
-+	u8 idh = 0;
++static int debug;
++module_param(debug, int, 0644);
++MODULE_PARM_DESC(debug, "enable verbose debug messages");
 +
-+	if (stk_camera_write_reg(dev, STK_IIC_ENABLE, STK_IIC_ENABLE_YES)
-+		|| stk_camera_write_reg(dev, STK_IIC_ADDR, SENSOR_ADDRESS)
-+		|| stk_sensor_outb(dev, REG_COM7, COM7_RESET)) {
-+		STK_ERROR("Sensor resetting failed\n");
-+		return -ENODEV;
-+	}
-+	msleep(10);
-+	/* Read the manufacturer ID: ov = 0x7FA2 */
-+	if (stk_sensor_inb(dev, REG_MIDH, &idh)
-+	    || stk_sensor_inb(dev, REG_MIDL, &idl)) {
-+		STK_ERROR("Strange error reading sensor ID\n");
-+		return -ENODEV;
-+	}
-+	if (idh != 0x7F || idl != 0xA2) {
-+		STK_ERROR("Huh? you don't have a sensor from ovt\n");
-+		return -ENODEV;
-+	}
-+	if (stk_sensor_inb(dev, REG_PID, &idh)
-+	    || stk_sensor_inb(dev, REG_VER, &idl)) {
-+		STK_ERROR("Could not read sensor model\n");
-+		return -ENODEV;
-+	}
-+	stk_sensor_write_regvals(dev, ov_initvals);
-+	msleep(10);
-+	STK_INFO("OmniVision sensor detected, id %02X%02X"
-+		" at address %x\n", idh, idl, SENSOR_ADDRESS);
-+	return 0;
-+}
++static char audio_std[8];
++module_param_string(audio_std, audio_std, sizeof(audio_std), 0);
++MODULE_PARM_DESC(audio_std,
++	"Audio standard. XC3028 audio decoder explicitly "
++	"needs to know what audio\n"
++	"standard is needed for some video standards with audio A2 or NICAM.\n"
++	"The valid values are:\n"
++	"A2\n"
++	"A2/A\n"
++	"A2/B\n"
++	"NICAM\n"
++	"NICAM/A\n"
++	"NICAM/B\n");
 +
-+/* V4L2_PIX_FMT_UYVY */
-+static struct regval ov_fmt_uyvy[] = {
-+	{REG_TSLB, TSLB_YLAST|0x08 },
-+	{ 0x4f, 0x80 }, 	/* "matrix coefficient 1" */
-+	{ 0x50, 0x80 }, 	/* "matrix coefficient 2" */
-+	{ 0x51, 0    },		/* vb */
-+	{ 0x52, 0x22 }, 	/* "matrix coefficient 4" */
-+	{ 0x53, 0x5e }, 	/* "matrix coefficient 5" */
-+	{ 0x54, 0x80 }, 	/* "matrix coefficient 6" */
-+	{REG_COM13, COM13_UVSAT|COM13_CMATRIX},
-+	{REG_COM15, COM15_R00FF },
-+	{0xff, 0xff}, /* END MARKER */
-+};
++static LIST_HEAD(xc2028_list);
++static DEFINE_MUTEX(xc2028_list_mutex);
 +
-+/* V4L2_PIX_FMT_RGB565X rrrrrggg gggbbbbb */
-+static struct regval ov_fmt_rgbr[] = {
-+	{ REG_RGB444, 0 },	/* No RGB444 please */
-+	{REG_TSLB, 0x00},
-+	{ REG_COM1, 0x0 },
-+	{ REG_COM9, 0x38 }, 	/* 16x gain ceiling; 0x8 is reserved bit */
-+	{ 0x4f, 0xb3 }, 	/* "matrix coefficient 1" */
-+	{ 0x50, 0xb3 }, 	/* "matrix coefficient 2" */
-+	{ 0x51, 0    },		/* vb */
-+	{ 0x52, 0x3d }, 	/* "matrix coefficient 4" */
-+	{ 0x53, 0xa7 }, 	/* "matrix coefficient 5" */
-+	{ 0x54, 0xe4 }, 	/* "matrix coefficient 6" */
-+	{ REG_COM13, COM13_GAMMA },
-+	{ REG_COM15, COM15_RGB565|COM15_R00FF },
-+	{ 0xff, 0xff },
++/* struct for storing firmware table */
++struct firmware_description {
++	unsigned int  type;
++	v4l2_std_id   id;
++	__u16         int_freq;
++	unsigned char *ptr;
++	unsigned int  size;
 +};
 +
-+/* V4L2_PIX_FMT_RGB565 gggbbbbb rrrrrggg */
-+static struct regval ov_fmt_rgbp[] = {
-+	{ REG_RGB444, 0 },	/* No RGB444 please */
-+	{REG_TSLB, TSLB_BYTEORD },
-+	{ REG_COM1, 0x0 },
-+	{ REG_COM9, 0x38 }, 	/* 16x gain ceiling; 0x8 is reserved bit */
-+	{ 0x4f, 0xb3 }, 	/* "matrix coefficient 1" */
-+	{ 0x50, 0xb3 }, 	/* "matrix coefficient 2" */
-+	{ 0x51, 0    },		/* vb */
-+	{ 0x52, 0x3d }, 	/* "matrix coefficient 4" */
-+	{ 0x53, 0xa7 }, 	/* "matrix coefficient 5" */
-+	{ 0x54, 0xe4 }, 	/* "matrix coefficient 6" */
-+	{ REG_COM13, COM13_GAMMA },
-+	{ REG_COM15, COM15_RGB565|COM15_R00FF },
-+	{ 0xff, 0xff },
++struct firmware_properties {
++	unsigned int	type;
++	v4l2_std_id	id;
++	v4l2_std_id	std_req;
++	__u16		int_freq;
++	unsigned int	scode_table;
++	int 		scode_nr;
 +};
 +
-+/* V4L2_PIX_FMT_SRGGB8 */
-+static struct regval ov_fmt_bayer[] = {
-+	/* This changes color order */
-+	{REG_TSLB, 0x40}, /* BGGR */
-+	/* {REG_TSLB, 0x08}, */ /* BGGR with vertical image flipping */
-+	{REG_COM15, COM15_R00FF },
-+	{0xff, 0xff}, /* END MARKER */
++struct xc2028_data {
++	struct list_head        xc2028_list;
++	struct tuner_i2c_props  i2c_props;
++	int                     (*tuner_callback) (void *dev,
++						   int command, int arg);
++	void			*video_dev;
++	int			count;
++	__u32			frequency;
++
++	struct firmware_description *firm;
++	int			firm_size;
++	__u16			firm_version;
++
++	__u16			hwmodel;
++	__u16			hwvers;
++
++	struct xc2028_ctrl	ctrl;
++
++	struct firmware_properties cur_fw;
++
++	struct mutex lock;
 +};
-+/*
-+ * Store a set of start/stop values into the camera.
-+ */
-+static int stk_sensor_set_hw(struct stk_camera *dev,
-+		int hstart, int hstop, int vstart, int vstop)
-+{
-+	int ret;
-+	unsigned char v;
-+/*
-+ * Horizontal: 11 bits, top 8 live in hstart and hstop.  Bottom 3 of
-+ * hstart are in href[2:0], bottom 3 of hstop in href[5:3].  There is
-+ * a mystery "edge offset" value in the top two bits of href.
-+ */
-+	ret =  stk_sensor_outb(dev, REG_HSTART, (hstart >> 3) & 0xff);
-+	ret += stk_sensor_outb(dev, REG_HSTOP, (hstop >> 3) & 0xff);
-+	ret += stk_sensor_inb(dev, REG_HREF, &v);
-+	v = (v & 0xc0) | ((hstop & 0x7) << 3) | (hstart & 0x7);
-+	msleep(10);
-+	ret += stk_sensor_outb(dev, REG_HREF, v);
-+/*
-+ * Vertical: similar arrangement (note: this is different from ov7670.c)
-+ */
-+	ret += stk_sensor_outb(dev, REG_VSTART, (vstart >> 3) & 0xff);
-+	ret += stk_sensor_outb(dev, REG_VSTOP, (vstop >> 3) & 0xff);
-+	ret += stk_sensor_inb(dev, REG_VREF, &v);
-+	v = (v & 0xc0) | ((vstop & 0x7) << 3) | (vstart & 0x7);
-+	msleep(10);
-+	ret += stk_sensor_outb(dev, REG_VREF, v);
-+	return ret;
-+}
 +
++#define i2c_send(priv, buf, size) ({					\
++	int _rc;							\
++	_rc = tuner_i2c_xfer_send(&priv->i2c_props, buf, size);		\
++	if (size != _rc)						\
++		tuner_info("i2c output error: rc = %d (should be %d)\n",\
++			   _rc, (int)size);				\
++	_rc;								\
++})
 +
-+int stk_sensor_configure(struct stk_camera *dev)
-+{
-+	int com7;
-+	/*
-+	 * We setup the sensor to output dummy lines in low-res modes,
-+	 * so we don't get absurdly hight framerates.
-+	 */
-+	unsigned dummylines;
-+	int flip;
-+	struct regval *rv;
++#define i2c_rcv(priv, buf, size) ({					\
++	int _rc;							\
++	_rc = tuner_i2c_xfer_recv(&priv->i2c_props, buf, size);		\
++	if (size != _rc)						\
++		tuner_err("i2c input error: rc = %d (should be %d)\n",	\
++			   _rc, (int)size); 				\
++	_rc;								\
++})
 +
-+	switch (dev->vsettings.mode) {
-+	case MODE_QCIF: com7 = COM7_FMT_QCIF;
-+		dummylines = 604;
-+		break;
-+	case MODE_QVGA: com7 = COM7_FMT_QVGA;
-+		dummylines = 267;
-+		break;
-+	case MODE_CIF: com7 = COM7_FMT_CIF;
-+		dummylines = 412;
-+		break;
-+	case MODE_VGA: com7 = COM7_FMT_VGA;
-+		dummylines = 11;
-+		break;
-+	case MODE_SXGA: com7 = COM7_FMT_SXGA;
-+		dummylines = 0;
-+		break;
-+	default: STK_ERROR("Unsupported mode %d\n", dev->vsettings.mode);
-+		return -EFAULT;
-+	}
-+	switch (dev->vsettings.palette) {
-+	case V4L2_PIX_FMT_UYVY:
-+		com7 |= COM7_YUV;
-+		rv = ov_fmt_uyvy;
-+		break;
-+	case V4L2_PIX_FMT_RGB565:
-+		com7 |= COM7_RGB;
-+		rv = ov_fmt_rgbp;
-+		break;
-+	case V4L2_PIX_FMT_RGB565X:
-+		com7 |= COM7_RGB;
-+		rv = ov_fmt_rgbr;
-+		break;
-+	case V4L2_PIX_FMT_SBGGR8:
-+		com7 |= COM7_PBAYER;
-+		rv = ov_fmt_bayer;
-+		break;
-+	default: STK_ERROR("Unsupported colorspace\n");
-+		return -EFAULT;
-+	}
-+	/*FIXME sometimes the sensor go to a bad state
-+	stk_sensor_write_regvals(dev, ov_initvals); */
-+	stk_sensor_outb(dev, REG_COM7, com7);
-+	msleep(50);
-+	stk_sensor_write_regvals(dev, rv);
-+	flip = (dev->vsettings.vflip?MVFP_FLIP:0)
-+		| (dev->vsettings.hflip?MVFP_MIRROR:0);
-+	stk_sensor_outb(dev, REG_MVFP, flip);
-+	if (dev->vsettings.palette == V4L2_PIX_FMT_SBGGR8
-+			&& !dev->vsettings.vflip)
-+		stk_sensor_outb(dev, REG_TSLB, 0x08);
-+	stk_sensor_outb(dev, REG_ADVFH, dummylines >> 8);
-+	stk_sensor_outb(dev, REG_ADVFL, dummylines & 0xff);
-+	msleep(50);
-+	switch (dev->vsettings.mode) {
-+	case MODE_VGA:
-+		if (stk_sensor_set_hw(dev, 302, 1582, 6, 486))
-+			STK_ERROR("stk_sensor_set_hw failed (VGA)\n");
-+		break;
-+	case MODE_SXGA:
-+	case MODE_CIF:
-+	case MODE_QVGA:
-+	case MODE_QCIF:
-+		/*FIXME These settings seem ignored by the sensor
-+		if (stk_sensor_set_hw(dev, 220, 1500, 10, 1034))
-+			STK_ERROR("stk_sensor_set_hw failed (SXGA)\n");
-+		*/
-+		break;
-+	}
-+	msleep(10);
-+	return 0;
-+}
++#define i2c_send_recv(priv, obuf, osize, ibuf, isize) ({		\
++	int _rc;							\
++	_rc = tuner_i2c_xfer_send_recv(&priv->i2c_props, obuf, osize,	\
++				       ibuf, isize);			\
++	if (isize != _rc)						\
++		tuner_err("i2c input error: rc = %d (should be %d)\n",	\
++			   _rc, (int)isize); 				\
++	_rc;								\
++})
 +
-+int stk_sensor_set_brightness(struct stk_camera *dev, int br)
++#define send_seq(priv, data...)	({					\
++	static u8 _val[] = data;					\
++	int _rc;							\
++	if (sizeof(_val) !=						\
++			(_rc = tuner_i2c_xfer_send(&priv->i2c_props,	\
++						_val, sizeof(_val)))) {	\
++		tuner_err("Error on line %d: %d\n", __LINE__, _rc);	\
++	} else 								\
++		msleep(10);						\
++	_rc;								\
++})
++
++static unsigned int xc2028_get_reg(struct xc2028_data *priv, u16 reg, u16 *val)
 +{
-+	if (br < 0 || br > 0xff)
-+		return -EINVAL;
-+	stk_sensor_outb(dev, REG_AEB, max(0x00, br - 6));
-+	stk_sensor_outb(dev, REG_AEW, min(0xff, br + 6));
-+	return 0;
-+}
++	unsigned char buf[2];
++	unsigned char ibuf[2];
 +
-diff --git a/drivers/media/video/stk-webcam.c b/drivers/media/video/stk-webcam.c
-new file mode 100644
-index 0000000..d37e5e2
---- /dev/null
-+++ b/drivers/media/video/stk-webcam.c
-@@ -0,0 +1,1465 @@
-+/*
-+ * stk-webcam.c : Driver for Syntek 1125 USB webcam controller
-+ *
-+ * Copyright (C) 2006 Nicolas VIVIEN
-+ * Copyright 2007-2008 Jaime Velasco Juan <jsagarribay at gmail.com>
-+ *
-+ * Some parts are inspired from cafe_ccic.c
-+ * Copyright 2006-2007 Jonathan Corbet
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * 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
-+ */
++	tuner_dbg("%s %04x called\n", __FUNCTION__, reg);
 +
-+#include <linux/module.h>
-+#include <linux/init.h>
-+#include <linux/kernel.h>
-+#include <linux/errno.h>
-+#include <linux/slab.h>
-+#include <linux/kref.h>
++	buf[0] = reg >> 8;
++	buf[1] = (unsigned char) reg;
 +
-+#include <linux/usb.h>
-+#include <linux/vmalloc.h>
-+#include <linux/videodev2.h>
-+#include <media/v4l2-common.h>
++	if (i2c_send_recv(priv, buf, 2, ibuf, 2) != 2)
++		return -EIO;
 +
-+#include "stk-webcam.h"
++	*val = (ibuf[1]) | (ibuf[0] << 8);
++	return 0;
++}
++
++#define dump_firm_type(t) 	dump_firm_type_and_int_freq(t, 0)
++void dump_firm_type_and_int_freq(unsigned int type, u16 int_freq)
++{
++	 if (type & BASE)
++		printk("BASE ");
++	 if (type & INIT1)
++		printk("INIT1 ");
++	 if (type & F8MHZ)
++		printk("F8MHZ ");
++	 if (type & MTS)
++		printk("MTS ");
++	 if (type & D2620)
++		printk("D2620 ");
++	 if (type & D2633)
++		printk("D2633 ");
++	 if (type & DTV6)
++		printk("DTV6 ");
++	 if (type & QAM)
++		printk("QAM ");
++	 if (type & DTV7)
++		printk("DTV7 ");
++	 if (type & DTV78)
++		printk("DTV78 ");
++	 if (type & DTV8)
++		printk("DTV8 ");
++	 if (type & FM)
++		printk("FM ");
++	 if (type & INPUT1)
++		printk("INPUT1 ");
++	 if (type & LCD)
++		printk("LCD ");
++	 if (type & NOGD)
++		printk("NOGD ");
++	 if (type & MONO)
++		printk("MONO ");
++	 if (type & ATSC)
++		printk("ATSC ");
++	 if (type & IF)
++		printk("IF ");
++	 if (type & LG60)
++		printk("LG60 ");
++	 if (type & ATI638)
++		printk("ATI638 ");
++	 if (type & OREN538)
++		printk("OREN538 ");
++	 if (type & OREN36)
++		printk("OREN36 ");
++	 if (type & TOYOTA388)
++		printk("TOYOTA388 ");
++	 if (type & TOYOTA794)
++		printk("TOYOTA794 ");
++	 if (type & DIBCOM52)
++		printk("DIBCOM52 ");
++	 if (type & ZARLINK456)
++		printk("ZARLINK456 ");
++	 if (type & CHINA)
++		printk("CHINA ");
++	 if (type & F6MHZ)
++		printk("F6MHZ ");
++	 if (type & INPUT2)
++		printk("INPUT2 ");
++	 if (type & SCODE)
++		printk("SCODE ");
++	 if (type & HAS_IF)
++		printk("HAS_IF_%d ", int_freq);
++}
 +
++static  v4l2_std_id parse_audio_std_option(void)
++{
++	if (strcasecmp(audio_std, "A2") == 0)
++		return V4L2_STD_A2;
++	if (strcasecmp(audio_std, "A2/A") == 0)
++		return V4L2_STD_A2_A;
++	if (strcasecmp(audio_std, "A2/B") == 0)
++		return V4L2_STD_A2_B;
++	if (strcasecmp(audio_std, "NICAM") == 0)
++		return V4L2_STD_NICAM;
++	if (strcasecmp(audio_std, "NICAM/A") == 0)
++		return V4L2_STD_NICAM_A;
++	if (strcasecmp(audio_std, "NICAM/B") == 0)
++		return V4L2_STD_NICAM_B;
 +
-+static int hflip = 1;
-+module_param(hflip, bool, 0444);
-+MODULE_PARM_DESC(hflip, "Horizontal image flip (mirror). Defaults to 1");
++	return 0;
++}
 +
-+static int vflip = 1;
-+module_param(vflip, bool, 0444);
-+MODULE_PARM_DESC(vflip, "Vertical image flip. Defaults to 1");
++static void free_firmware(struct xc2028_data *priv)
++{
++	int i;
 +
-+static int debug;
-+module_param(debug, int, 0444);
-+MODULE_PARM_DESC(debug, "Debug v4l ioctls. Defaults to 0");
++	if (!priv->firm)
++		return;
 +
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Jaime Velasco Juan <jsagarribay at gmail.com> and Nicolas VIVIEN");
-+MODULE_DESCRIPTION("Syntek DC1125 webcam driver");
++	for (i = 0; i < priv->firm_size; i++)
++		kfree(priv->firm[i].ptr);
 +
++	kfree(priv->firm);
 +
++	priv->firm = NULL;
++	priv->firm_size = 0;
 +
-+/* Some cameras have audio interfaces, we aren't interested in those */
-+static struct usb_device_id stkwebcam_table[] = {
-+	{ USB_DEVICE_AND_INTERFACE_INFO(0x174f, 0xa311, 0xff, 0xff, 0xff) },
-+	{ USB_DEVICE_AND_INTERFACE_INFO(0x05e1, 0x0501, 0xff, 0xff, 0xff) },
-+	{ }
-+};
-+MODULE_DEVICE_TABLE(usb, stkwebcam_table);
++	memset(&priv->cur_fw, 0, sizeof(priv->cur_fw));
++}
 +
-+void stk_camera_cleanup(struct kref *kref)
++static int load_all_firmwares(struct dvb_frontend *fe)
 +{
-+	struct stk_camera *dev = to_stk_camera(kref);
++	struct xc2028_data    *priv = fe->tuner_priv;
++	const struct firmware *fw   = NULL;
++	unsigned char         *p, *endp;
++	int                   rc = 0;
++	int		      n, n_array;
++	char		      name[33];
 +
-+	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;
++	tuner_dbg("%s called\n", __FUNCTION__);
 +
-+	if (dev->sio_bufs != NULL || dev->isobufs != NULL)
-+		STK_ERROR("We are leaking memory\n");
-+	usb_put_intf(dev->interface);
-+	kfree(dev);
-+}
++	tuner_dbg("Reading firmware %s\n", priv->ctrl.fname);
++	rc = request_firmware(&fw, priv->ctrl.fname,
++			      &priv->i2c_props.adap->dev);
++	if (rc < 0) {
++		if (rc == -ENOENT)
++			tuner_err("Error: firmware %s not found.\n",
++				   priv->ctrl.fname);
++		else
++			tuner_err("Error %d while requesting firmware %s \n",
++				   rc, priv->ctrl.fname);
 +
++		return rc;
++	}
++	p = fw->data;
++	endp = p + fw->size;
 +
-+/*
-+ * Basic stuff
-+ */
-+int stk_camera_write_reg(struct stk_camera *dev, u16 index, u8 value)
-+{
-+	struct usb_device *udev = dev->udev;
-+	int ret;
++	if (fw->size < sizeof(name) - 1 + 2 + 2) {
++		tuner_err("Error: firmware file %s has invalid size!\n",
++			  priv->ctrl.fname);
++		goto corrupt;
++	}
 +
-+	ret =  usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
-+			0x01,
-+			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-+			value,
-+			index,
-+			NULL,
-+			0,
-+			500);
-+	if (ret < 0)
-+		return ret;
-+	else
-+		return 0;
-+}
++	memcpy(name, p, sizeof(name) - 1);
++	name[sizeof(name) - 1] = 0;
++	p += sizeof(name) - 1;
 +
-+int stk_camera_read_reg(struct stk_camera *dev, u16 index, int *value)
-+{
-+	struct usb_device *udev = dev->udev;
-+	int ret;
++	priv->firm_version = le16_to_cpu(*(__u16 *) p);
++	p += 2;
 +
-+	ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
-+			0x00,
-+			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-+			0x00,
-+			index,
-+			(u8 *) value,
-+			sizeof(u8),
-+			500);
-+	if (ret < 0)
-+		return ret;
-+	else
-+		return 0;
-+}
++	n_array = le16_to_cpu(*(__u16 *) p);
++	p += 2;
 +
-+static int stk_start_stream(struct stk_camera *dev)
-+{
-+	int value;
-+	int i, ret;
-+	int value_116, value_117;
++	tuner_info("Loading %d firmware images from %s, type: %s, ver %d.%d\n",
++		   n_array, priv->ctrl.fname, name,
++		   priv->firm_version >> 8, priv->firm_version & 0xff);
 +
-+	if (!is_present(dev))
-+		return -ENODEV;
-+	if (!is_memallocd(dev) || !is_initialised(dev)) {
-+		STK_ERROR("FIXME: Buffers are not allocated\n");
-+		return -EFAULT;
++	priv->firm = kzalloc(sizeof(*priv->firm) * n_array, GFP_KERNEL);
++	if (priv->firm == NULL) {
++		tuner_err("Not enough memory to load firmware file.\n");
++		rc = -ENOMEM;
++		goto err;
 +	}
-+	ret = usb_set_interface(dev->udev, 0, 5);
-+
-+	if (ret < 0)
-+		STK_ERROR("usb_set_interface failed !\n");
-+	if (stk_sensor_wakeup(dev))
-+		STK_ERROR("error awaking the sensor\n");
-+
-+	stk_camera_read_reg(dev, 0x0116, &value_116);
-+	stk_camera_read_reg(dev, 0x0117, &value_117);
-+
-+	stk_camera_write_reg(dev, 0x0116, 0x0000);
-+	stk_camera_write_reg(dev, 0x0117, 0x0000);
++	priv->firm_size = n_array;
 +
-+	stk_camera_read_reg(dev, 0x0100, &value);
-+	stk_camera_write_reg(dev, 0x0100, value | 0x80);
++	n = -1;
++	while (p < endp) {
++		__u32 type, size;
++		v4l2_std_id id;
++		__u16 int_freq = 0;
 +
-+	stk_camera_write_reg(dev, 0x0116, value_116);
-+	stk_camera_write_reg(dev, 0x0117, value_117);
-+	for (i = 0; i < MAX_ISO_BUFS; i++) {
-+		if (dev->isobufs[i].urb) {
-+			ret = usb_submit_urb(dev->isobufs[i].urb, GFP_KERNEL);
-+			atomic_inc(&dev->urbs_used);
-+			if (ret)
-+				return ret;
++		n++;
++		if (n >= n_array) {
++			tuner_err("More firmware images in file than "
++				  "were expected!\n");
++			goto corrupt;
 +		}
-+	}
-+	set_streaming(dev);
-+	return 0;
-+}
 +
-+static int stk_stop_stream(struct stk_camera *dev)
-+{
-+	int value;
-+	int i;
-+	if (is_present(dev)) {
-+		stk_camera_read_reg(dev, 0x0100, &value);
-+		stk_camera_write_reg(dev, 0x0100, value & ~0x80);
-+		if (dev->isobufs != NULL) {
-+			for (i = 0; i < MAX_ISO_BUFS; i++) {
-+				if (dev->isobufs[i].urb)
-+					usb_kill_urb(dev->isobufs[i].urb);
-+			}
++		/* Checks if there's enough bytes to read */
++		if (p + sizeof(type) + sizeof(id) + sizeof(size) > endp) {
++			tuner_err("Firmware header is incomplete!\n");
++			goto corrupt;
 +		}
-+		unset_streaming(dev);
 +
-+		if (usb_set_interface(dev->udev, 0, 0))
-+			STK_ERROR("usb_set_interface failed !\n");
-+		if (stk_sensor_sleep(dev))
-+			STK_ERROR("error suspending the sensor\n");
-+	}
-+	return 0;
-+}
++		type = le32_to_cpu(*(__u32 *) p);
++		p += sizeof(type);
 +
-+/*
-+ * This seems to be the shortest init sequence we
-+ * must do in order to find the sensor
-+ * Bit 5 of reg. 0x0000 here is important, when reset to 0 the sensor
-+ * is also reset. Maybe powers down it?
-+ * Rest of values don't make a difference
-+ */
++		id = le64_to_cpu(*(v4l2_std_id *) p);
++		p += sizeof(id);
 +
-+static struct regval stk1125_initvals[] = {
-+	/*TODO: What means this sequence? */
-+	{0x0000, 0x24},
-+	{0x0100, 0x21},
-+	{0x0002, 0x68},
-+	{0x0003, 0x80},
-+	{0x0005, 0x00},
-+	{0x0007, 0x03},
-+	{0x000d, 0x00},
-+	{0x000f, 0x02},
-+	{0x0300, 0x12},
-+	{0x0350, 0x41},
-+	{0x0351, 0x00},
-+	{0x0352, 0x00},
-+	{0x0353, 0x00},
-+	{0x0018, 0x10},
-+	{0x0019, 0x00},
-+	{0x001b, 0x0e},
-+	{0x001c, 0x46},
-+	{0x0300, 0x80},
-+	{0x001a, 0x04},
-+	{0x0110, 0x00},
-+	{0x0111, 0x00},
-+	{0x0112, 0x00},
-+	{0x0113, 0x00},
++		if (type & HAS_IF) {
++			int_freq = le16_to_cpu(*(__u16 *) p);
++			p += sizeof(int_freq);
++		}
 +
-+	{0xffff, 0xff},
-+};
++		size = le32_to_cpu(*(__u32 *) p);
++		p += sizeof(size);
 +
++		if ((!size) || (size + p > endp)) {
++			tuner_err("Firmware type ");
++			dump_firm_type(type);
++			printk("(%x), id %llx is corrupted "
++			       "(size=%d, expected %d)\n",
++			       type, (unsigned long long)id,
++			       (unsigned)(endp - p), size);
++			goto corrupt;
++		}
 +
-+static int stk_initialise(struct stk_camera *dev)
-+{
-+	struct regval *rv;
-+	int ret;
-+	if (!is_present(dev))
-+		return -ENODEV;
-+	if (is_initialised(dev))
-+		return 0;
-+	rv = stk1125_initvals;
-+	while (rv->reg != 0xffff) {
-+		ret = stk_camera_write_reg(dev, rv->reg, rv->val);
-+		if (ret)
-+			return ret;
-+		rv++;
-+	}
-+	if (stk_sensor_init(dev) == 0) {
-+		set_initialised(dev);
-+		return 0;
-+	} else
-+		return -1;
-+}
++		priv->firm[n].ptr = kzalloc(size, GFP_KERNEL);
++		if (priv->firm[n].ptr == NULL) {
++			tuner_err("Not enough memory to load firmware file.\n");
++			rc = -ENOMEM;
++			goto err;
++		}
++		tuner_dbg("Reading firmware type ");
++		if (debug) {
++			dump_firm_type_and_int_freq(type, int_freq);
++			printk("(%x), id %llx, size=%d.\n",
++			       type, (unsigned long long)id, size);
++		}
 +
-+/* sysfs functions */
-+/*FIXME cleanup this */
++		memcpy(priv->firm[n].ptr, p, size);
++		priv->firm[n].type = type;
++		priv->firm[n].id   = id;
++		priv->firm[n].size = size;
++		priv->firm[n].int_freq = int_freq;
 +
-+static ssize_t show_brightness(struct device *class,
-+			struct device_attribute *attr, char *buf)
-+{
-+	struct video_device *vdev = to_video_device(class);
-+	struct stk_camera *dev = vdev_to_camera(vdev);
++		p += size;
++	}
 +
-+	return sprintf(buf, "%X\n", dev->vsettings.brightness);
-+}
++	if (n + 1 != priv->firm_size) {
++		tuner_err("Firmware file is incomplete!\n");
++		goto corrupt;
++	}
 +
-+static ssize_t store_brightness(struct device *class,
-+		struct device_attribute *attr, const char *buf, size_t count)
-+{
-+	char *endp;
-+	unsigned long value;
-+	int ret;
++	goto done;
 +
-+	struct video_device *vdev = to_video_device(class);
-+	struct stk_camera *dev = vdev_to_camera(vdev);
++corrupt:
++	rc = -EINVAL;
++	tuner_err("Error: firmware file is corrupted!\n");
 +
-+	value = simple_strtoul(buf, &endp, 16);
++err:
++	tuner_info("Releasing partially loaded firmware file.\n");
++	free_firmware(priv);
 +
-+	dev->vsettings.brightness = (int) value;
++done:
++	release_firmware(fw);
++	if (rc == 0)
++		tuner_dbg("Firmware files loaded.\n");
 +
-+	ret = stk_sensor_set_brightness(dev, value >> 8);
-+	if (ret)
-+		return ret;
-+	else
-+		return count;
++	return rc;
 +}
 +
-+static ssize_t show_hflip(struct device *class,
-+		struct device_attribute *attr, char *buf)
++static int seek_firmware(struct dvb_frontend *fe, unsigned int type,
++			 v4l2_std_id *id)
 +{
-+	struct video_device *vdev = to_video_device(class);
-+	struct stk_camera *dev = vdev_to_camera(vdev);
-+
-+	return sprintf(buf, "%d\n", dev->vsettings.hflip);
-+}
++	struct xc2028_data *priv = fe->tuner_priv;
++	int                 i, best_i = -1, best_nr_matches = 0;
++	unsigned int        ign_firm_type_mask = 0;
 +
-+static ssize_t store_hflip(struct device *class,
-+		struct device_attribute *attr, const char *buf, size_t count)
-+{
-+	struct video_device *vdev = to_video_device(class);
-+	struct stk_camera *dev = vdev_to_camera(vdev);
++	tuner_dbg("%s called, want type=", __FUNCTION__);
++	if (debug) {
++		dump_firm_type(type);
++		printk("(%x), id %016llx.\n", type, (unsigned long long)*id);
++	}
 +
-+	if (strncmp(buf, "1", 1) == 0)
-+		dev->vsettings.hflip = 1;
-+	else if (strncmp(buf, "0", 1) == 0)
-+		dev->vsettings.hflip = 0;
-+	else
++	if (!priv->firm) {
++		tuner_err("Error! firmware not loaded\n");
 +		return -EINVAL;
++	}
 +
-+	return strlen(buf);
-+}
++	if (((type & ~SCODE) == 0) && (*id == 0))
++		*id = V4L2_STD_PAL;
 +
-+static ssize_t show_vflip(struct device *class,
-+		struct device_attribute *attr, char *buf)
-+{
-+	struct video_device *vdev = to_video_device(class);
-+	struct stk_camera *dev = vdev_to_camera(vdev);
++	if (type & BASE)
++		type &= BASE_TYPES;
++	else if (type & SCODE) {
++		type &= SCODE_TYPES;
++		ign_firm_type_mask = HAS_IF;
++	} else if (type & DTV_TYPES)
++		type &= DTV_TYPES;
++	else if (type & STD_SPECIFIC_TYPES)
++		type &= STD_SPECIFIC_TYPES;
 +
-+	return sprintf(buf, "%d\n", dev->vsettings.vflip);
-+}
++	/* Seek for exact match */
++	for (i = 0; i < priv->firm_size; i++) {
++		if ((type == (priv->firm[i].type & ~ign_firm_type_mask)) &&
++		    (*id == priv->firm[i].id))
++			goto found;
++	}
 +
-+static ssize_t store_vflip(struct device *class,
-+		struct device_attribute *attr, const char *buf, size_t count)
-+{
-+	struct video_device *vdev = to_video_device(class);
-+	struct stk_camera *dev = vdev_to_camera(vdev);
++	/* Seek for generic video standard match */
++	for (i = 0; i < priv->firm_size; i++) {
++		v4l2_std_id match_mask;
++		int nr_matches;
 +
-+	if (strncmp(buf, "1", 1) == 0)
-+		dev->vsettings.vflip = 1;
-+	else if (strncmp(buf, "0", 1) == 0)
-+		dev->vsettings.vflip = 0;
-+	else
-+		return -EINVAL;
++		if (type != (priv->firm[i].type & ~ign_firm_type_mask))
++			continue;
 +
-+	return strlen(buf);
-+}
++		match_mask = *id & priv->firm[i].id;
++		if (!match_mask)
++			continue;
 +
-+static DEVICE_ATTR(brightness, S_IRUGO | S_IWUGO,
-+			show_brightness, store_brightness);
-+static DEVICE_ATTR(hflip, S_IRUGO | S_IWUGO, show_hflip, store_hflip);
-+static DEVICE_ATTR(vflip, S_IRUGO | S_IWUGO, show_vflip, store_vflip);
++		if ((*id & match_mask) == *id)
++			goto found; /* Supports all the requested standards */
 +
-+static int stk_create_sysfs_files(struct video_device *vdev)
-+{
-+	int ret;
++		nr_matches = hweight64(match_mask);
++		if (nr_matches > best_nr_matches) {
++			best_nr_matches = nr_matches;
++			best_i = i;
++		}
++	}
 +
-+	ret = video_device_create_file(vdev, &dev_attr_brightness);
-+	ret += video_device_create_file(vdev, &dev_attr_hflip);
-+	ret += video_device_create_file(vdev, &dev_attr_vflip);
-+	return ret;
-+}
++	if (best_nr_matches > 0) {
++		tuner_dbg("Selecting best matching firmware (%d bits) for "
++			  "type=", best_nr_matches);
++		dump_firm_type(type);
++		printk("(%x), id %016llx:\n", type, (unsigned long long)*id);
++		i = best_i;
++		goto found;
++	}
 +
-+static void stk_remove_sysfs_files(struct video_device *vdev)
-+{
-+	video_device_remove_file(vdev, &dev_attr_brightness);
-+	video_device_remove_file(vdev, &dev_attr_hflip);
-+	video_device_remove_file(vdev, &dev_attr_vflip);
-+}
++	/*FIXME: Would make sense to seek for type "hint" match ? */
 +
++	i = -ENOENT;
++	goto ret;
 +
-+/* *********************************************** */
-+/*
-+ * This function is called as an URB transfert is complete (Isochronous pipe).
-+ * So, the traitement is done in interrupt time, so it has be fast, not crash,
-+ * and not stall. Neat.
-+ */
-+static void stk_isoc_handler(struct urb *urb)
++found:
++	*id = priv->firm[i].id;
++
++ret:
++	tuner_dbg("%s firmware for type=", (i < 0) ? "Can't find" : "Found");
++	if (debug) {
++		dump_firm_type(type);
++		printk("(%x), id %016llx.\n", type, (unsigned long long)*id);
++	}
++	return i;
++}
++
++static int load_firmware(struct dvb_frontend *fe, unsigned int type,
++			 v4l2_std_id *id)
 +{
-+	int i;
-+	int ret;
-+	int framelen;
-+	unsigned long flags;
++	struct xc2028_data *priv = fe->tuner_priv;
++	int                pos, rc;
++	unsigned char      *p, *endp, buf[priv->ctrl.max_len];
 +
-+	unsigned char *fill = NULL;
-+	unsigned char *iso_buf = NULL;
++	tuner_dbg("%s called\n", __FUNCTION__);
 +
-+	struct stk_camera *dev;
-+	struct stk_sio_buffer *fb;
++	pos = seek_firmware(fe, type, id);
++	if (pos < 0)
++		return pos;
 +
-+	dev = (struct stk_camera *) urb->context;
++	tuner_info("Loading firmware for type=");
++	dump_firm_type(priv->firm[pos].type);
++	printk("(%x), id %016llx.\n", priv->firm[pos].type,
++	       (unsigned long long)*id);
 +
-+	if (dev == NULL) {
-+		STK_ERROR("isoc_handler called with NULL device !\n");
-+		return;
-+	}
++	p = priv->firm[pos].ptr;
++	endp = p + priv->firm[pos].size;
 +
-+	if (urb->status == -ENOENT || urb->status == -ECONNRESET
-+		|| urb->status == -ESHUTDOWN) {
-+		atomic_dec(&dev->urbs_used);
-+		return;
-+	}
++	while (p < endp) {
++		__u16 size;
 +
-+	spin_lock_irqsave(&dev->spinlock, flags);
++		/* Checks if there's enough bytes to read */
++		if (p + sizeof(size) > endp) {
++			tuner_err("Firmware chunk size is wrong\n");
++			return -EINVAL;
++		}
 +
-+	if (urb->status != -EINPROGRESS && urb->status != 0) {
-+		STK_ERROR("isoc_handler: urb->status == %d\n", urb->status);
-+		goto resubmit;
-+	}
++		size = le16_to_cpu(*(__u16 *) p);
++		p += sizeof(size);
 +
-+	if (list_empty(&dev->sio_avail)) {
-+		/*FIXME Stop streaming after a while */
-+		(void) (printk_ratelimit() &&
-+		STK_ERROR("isoc_handler without available buffer!\n"));
-+		goto resubmit;
-+	}
-+	fb = list_first_entry(&dev->sio_avail,
-+			struct stk_sio_buffer, list);
-+	fill = fb->buffer + fb->v4lbuf.bytesused;
++		if (size == 0xffff)
++			return 0;
 +
-+	for (i = 0; i < urb->number_of_packets; i++) {
-+		if (urb->iso_frame_desc[i].status != 0) {
-+			if (urb->iso_frame_desc[i].status != -EXDEV)
-+				STK_ERROR("Frame %d has error %d\n", i,
-+					urb->iso_frame_desc[i].status);
++		if (!size) {
++			/* Special callback command received */
++			rc = priv->tuner_callback(priv->video_dev,
++						  XC2028_TUNER_RESET, 0);
++			if (rc < 0) {
++				tuner_err("Error at RESET code %d\n",
++					   (*p) & 0x7f);
++				return -EINVAL;
++			}
 +			continue;
 +		}
-+		framelen = urb->iso_frame_desc[i].actual_length;
-+		iso_buf = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
-+
-+		if (framelen <= 4)
-+			continue; /* no data */
-+
-+		/*
-+		 * we found something informational from there
-+		 * the isoc frames have to type of headers
-+		 * type1: 00 xx 00 00 or 20 xx 00 00
-+		 * type2: 80 xx 00 00 00 00 00 00 or a0 xx 00 00 00 00 00 00
-+		 * xx is a sequencer which has never been seen over 0x3f
-+		 * imho data written down looks like bayer, i see similarities
-+		 * after every 640 bytes
-+		 */
-+		if (*iso_buf & 0x80) {
-+			framelen -= 8;
-+			iso_buf += 8;
-+			/* This marks a new frame */
-+			if (fb->v4lbuf.bytesused != 0
-+				&& fb->v4lbuf.bytesused != dev->frame_size) {
-+				(void) (printk_ratelimit() &&
-+				STK_ERROR("frame %d, "
-+					"bytesused=%d, skipping\n",
-+					i, fb->v4lbuf.bytesused));
-+				fb->v4lbuf.bytesused = 0;
-+				fill = fb->buffer;
-+			} else if (fb->v4lbuf.bytesused == dev->frame_size) {
-+				list_move_tail(dev->sio_avail.next,
-+					&dev->sio_full);
-+				wake_up(&dev->wait_frame);
-+				if (list_empty(&dev->sio_avail)) {
-+					(void) (printk_ratelimit() &&
-+					STK_ERROR("No buffer available\n"));
-+					goto resubmit;
++		if (size >= 0xff00) {
++			switch (size) {
++			case 0xff00:
++				rc = priv->tuner_callback(priv->video_dev,
++							XC2028_RESET_CLK, 0);
++				if (rc < 0) {
++					tuner_err("Error at RESET code %d\n",
++						  (*p) & 0x7f);
++					return -EINVAL;
 +				}
-+				fb = list_first_entry(&dev->sio_avail,
-+					struct stk_sio_buffer, list);
-+				fb->v4lbuf.bytesused = 0;
-+				fill = fb->buffer;
++				break;
++			default:
++				tuner_info("Invalid RESET code %d\n",
++					   size & 0x7f);
++				return -EINVAL;
++
 +			}
-+		} else {
-+			framelen -= 4;
-+			iso_buf += 4;
++			continue;
 +		}
 +
-+		/* Our buffer is full !!! */
-+		if (framelen + fb->v4lbuf.bytesused > dev->frame_size) {
-+			(void) (printk_ratelimit() &&
-+			STK_ERROR("Frame buffer overflow, lost sync\n"));
-+			/*FIXME Do something here? */
++		/* Checks for a sleep command */
++		if (size & 0x8000) {
++			msleep(size & 0x7fff);
 +			continue;
 +		}
-+		spin_unlock_irqrestore(&dev->spinlock, flags);
-+		memcpy(fill, iso_buf, framelen);
-+		spin_lock_irqsave(&dev->spinlock, flags);
-+		fill += framelen;
-+
-+		/* New size of our buffer */
-+		fb->v4lbuf.bytesused += framelen;
-+	}
 +
-+resubmit:
-+	spin_unlock_irqrestore(&dev->spinlock, flags);
-+	urb->dev = dev->udev;
-+	ret = usb_submit_urb(urb, GFP_ATOMIC);
-+	if (ret != 0) {
-+		STK_ERROR("Error (%d) re-submitting urb in stk_isoc_handler.\n",
-+			ret);
-+	}
-+}
++		if ((size + p > endp)) {
++			tuner_err("missing bytes: need %d, have %d\n",
++				   size, (int)(endp - p));
++			return -EINVAL;
++		}
 +
-+/* -------------------------------------------- */
++		buf[0] = *p;
++		p++;
++		size--;
 +
-+static int stk_prepare_iso(struct stk_camera *dev)
-+{
-+	void *kbuf;
-+	int i, j;
-+	struct urb *urb;
-+	struct usb_device *udev;
++		/* Sends message chunks */
++		while (size > 0) {
++			int len = (size < priv->ctrl.max_len - 1) ?
++				   size : priv->ctrl.max_len - 1;
 +
-+	if (dev == NULL)
-+		return -ENXIO;
-+	udev = dev->udev;
++			memcpy(buf + 1, p, len);
 +
-+	if (dev->isobufs)
-+		STK_ERROR("isobufs already allocated. Bad\n");
-+	else
-+		dev->isobufs = kzalloc(MAX_ISO_BUFS * sizeof(*dev->isobufs),
-+					GFP_KERNEL);
-+	if (dev->isobufs == NULL) {
-+		STK_ERROR("Unable to allocate iso buffers\n");
-+		return -ENOMEM;
-+	}
-+	for (i = 0; i < MAX_ISO_BUFS; i++) {
-+		if (dev->isobufs[i].data == NULL) {
-+			kbuf = kzalloc(ISO_BUFFER_SIZE, GFP_KERNEL);
-+			if (kbuf == NULL) {
-+				STK_ERROR("Failed to allocate iso buffer %d\n",
-+					i);
-+				goto isobufs_out;
-+			}
-+			dev->isobufs[i].data = kbuf;
-+		} else
-+			STK_ERROR("isobuf data already allocated\n");
-+		if (dev->isobufs[i].urb == NULL) {
-+			urb = usb_alloc_urb(ISO_FRAMES_PER_DESC, GFP_KERNEL);
-+			if (urb == NULL) {
-+				STK_ERROR("Failed to allocate URB %d\n", i);
-+				goto isobufs_out;
++			rc = i2c_send(priv, buf, len + 1);
++			if (rc < 0) {
++				tuner_err("%d returned from send\n", rc);
++				return -EINVAL;
 +			}
-+			dev->isobufs[i].urb = urb;
-+		} else {
-+			STK_ERROR("Killing URB\n");
-+			usb_kill_urb(dev->isobufs[i].urb);
-+			urb = dev->isobufs[i].urb;
-+		}
-+		urb->interval = 1;
-+		urb->dev = udev;
-+		urb->pipe = usb_rcvisocpipe(udev, dev->isoc_ep);
-+		urb->transfer_flags = URB_ISO_ASAP;
-+		urb->transfer_buffer = dev->isobufs[i].data;
-+		urb->transfer_buffer_length = ISO_BUFFER_SIZE;
-+		urb->complete = stk_isoc_handler;
-+		urb->context = dev;
-+		urb->start_frame = 0;
-+		urb->number_of_packets = ISO_FRAMES_PER_DESC;
 +
-+		for (j = 0; j < ISO_FRAMES_PER_DESC; j++) {
-+			urb->iso_frame_desc[j].offset = j * ISO_MAX_FRAME_SIZE;
-+			urb->iso_frame_desc[j].length = ISO_MAX_FRAME_SIZE;
++			p += len;
++			size -= len;
 +		}
 +	}
-+	set_memallocd(dev);
 +	return 0;
-+
-+isobufs_out:
-+	for (i = 0; i < MAX_ISO_BUFS && dev->isobufs[i].data; i++)
-+		kfree(dev->isobufs[i].data);
-+	for (i = 0; i < MAX_ISO_BUFS && dev->isobufs[i].urb; i++)
-+		usb_free_urb(dev->isobufs[i].urb);
-+	kfree(dev->isobufs);
-+	dev->isobufs = NULL;
-+	return -ENOMEM;
 +}
 +
-+static void stk_clean_iso(struct stk_camera *dev)
++static int load_scode(struct dvb_frontend *fe, unsigned int type,
++			 v4l2_std_id *id, __u16 int_freq, int scode)
 +{
-+	int i;
-+
-+	if (dev == NULL || dev->isobufs == NULL)
-+		return;
++	struct xc2028_data *priv = fe->tuner_priv;
++	int                pos, rc;
++	unsigned char	   *p;
 +
-+	for (i = 0; i < MAX_ISO_BUFS; i++) {
-+		struct urb *urb;
++	tuner_dbg("%s called\n", __FUNCTION__);
 +
-+		urb = dev->isobufs[i].urb;
-+		if (urb) {
-+			if (atomic_read(&dev->urbs_used))
-+				usb_kill_urb(urb);
-+			usb_free_urb(urb);
++	if (!int_freq) {
++		pos = seek_firmware(fe, type, id);
++		if (pos < 0)
++			return pos;
++	} else {
++		for (pos = 0; pos < priv->firm_size; pos++) {
++			if ((priv->firm[pos].int_freq == int_freq) &&
++			    (priv->firm[pos].type & HAS_IF))
++				break;
 +		}
-+		kfree(dev->isobufs[i].data);
-+	}
-+	kfree(dev->isobufs);
-+	dev->isobufs = NULL;
-+	unset_memallocd(dev);
-+}
-+
-+static int stk_setup_siobuf(struct stk_camera *dev, int index)
-+{
-+	struct stk_sio_buffer *buf = dev->sio_bufs + index;
-+	INIT_LIST_HEAD(&buf->list);
-+	buf->v4lbuf.length = PAGE_ALIGN(dev->frame_size);
-+	buf->buffer = vmalloc_user(buf->v4lbuf.length);
-+	if (buf->buffer == NULL)
-+		return -ENOMEM;
-+	buf->mapcount = 0;
-+	buf->dev = dev;
-+	buf->v4lbuf.index = index;
-+	buf->v4lbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-+	buf->v4lbuf.field = V4L2_FIELD_NONE;
-+	buf->v4lbuf.memory = V4L2_MEMORY_MMAP;
-+	buf->v4lbuf.m.offset = 2*index*buf->v4lbuf.length;
-+	return 0;
-+}
-+
-+static int stk_free_sio_buffers(struct stk_camera *dev)
-+{
-+	int i;
-+	int nbufs;
-+	unsigned long flags;
-+	if (dev->n_sbufs == 0 || dev->sio_bufs == NULL)
-+		return 0;
-+	/*
-+	* If any buffers are mapped, we cannot free them at all.
-+	*/
-+	for (i = 0; i < dev->n_sbufs; i++) {
-+		if (dev->sio_bufs[i].mapcount > 0)
-+			return -EBUSY;
-+	}
-+	/*
-+	* OK, let's do it.
-+	*/
-+	spin_lock_irqsave(&dev->spinlock, flags);
-+	INIT_LIST_HEAD(&dev->sio_avail);
-+	INIT_LIST_HEAD(&dev->sio_full);
-+	nbufs = dev->n_sbufs;
-+	dev->n_sbufs = 0;
-+	spin_unlock_irqrestore(&dev->spinlock, flags);
-+	for (i = 0; i < nbufs; i++) {
-+		if (dev->sio_bufs[i].buffer != NULL)
-+			vfree(dev->sio_bufs[i].buffer);
++		if (pos == priv->firm_size)
++			return -ENOENT;
 +	}
-+	kfree(dev->sio_bufs);
-+	dev->sio_bufs = NULL;
-+	return 0;
-+}
 +
-+static int stk_prepare_sio_buffers(struct stk_camera *dev, unsigned n_sbufs)
-+{
-+	int i;
-+	if (dev->sio_bufs != NULL)
-+		STK_ERROR("sio_bufs already allocated\n");
-+	else {
-+		dev->sio_bufs = kzalloc(n_sbufs * sizeof(struct stk_sio_buffer),
-+				GFP_KERNEL);
-+		if (dev->sio_bufs == NULL)
-+			return -ENOMEM;
-+		for (i = 0; i < n_sbufs; i++) {
-+			if (stk_setup_siobuf(dev, i))
-+				return (dev->n_sbufs > 1)? 0 : -ENOMEM;
-+			dev->n_sbufs = i+1;
-+		}
-+	}
-+	return 0;
-+}
++	p = priv->firm[pos].ptr;
 +
-+static int stk_allocate_buffers(struct stk_camera *dev, unsigned n_sbufs)
-+{
-+	int err;
-+	err = stk_prepare_iso(dev);
-+	if (err) {
-+		stk_clean_iso(dev);
-+		return err;
-+	}
-+	err = stk_prepare_sio_buffers(dev, n_sbufs);
-+	if (err) {
-+		stk_free_sio_buffers(dev);
-+		return err;
++	if (priv->firm[pos].type & HAS_IF) {
++		if (priv->firm[pos].size != 12 * 16 || scode >= 16)
++			return -EINVAL;
++		p += 12 * scode;
++	} else {
++		/* 16 SCODE entries per file; each SCODE entry is 12 bytes and
++		 * has a 2-byte size header in the firmware format. */
++		if (priv->firm[pos].size != 14 * 16 || scode >= 16 ||
++		    le16_to_cpu(*(__u16 *)(p + 14 * scode)) != 12)
++			return -EINVAL;
++		p += 14 * scode + 2;
 +	}
-+	return 0;
-+}
-+
-+static void stk_free_buffers(struct stk_camera *dev)
-+{
-+	stk_clean_iso(dev);
-+	stk_free_sio_buffers(dev);
-+}
-+/* -------------------------------------------- */
 +
-+/* v4l file operations */
++	tuner_info("Loading SCODE for type=");
++	dump_firm_type_and_int_freq(priv->firm[pos].type,
++				    priv->firm[pos].int_freq);
++	printk("(%x), id %016llx.\n", priv->firm[pos].type,
++	       (unsigned long long)*id);
 +
-+static int v4l_stk_open(struct inode *inode, struct file *fp)
-+{
-+	struct stk_camera *dev;
-+	struct video_device *vdev;
++	if (priv->firm_version < 0x0202)
++		rc = send_seq(priv, {0x20, 0x00, 0x00, 0x00});
++	else
++		rc = send_seq(priv, {0xa0, 0x00, 0x00, 0x00});
++	if (rc < 0)
++		return -EIO;
 +
-+	vdev = video_devdata(fp);
-+	dev = vdev_to_camera(vdev);
++	rc = i2c_send(priv, p, 12);
++	if (rc < 0)
++		return -EIO;
 +
-+	if (dev == NULL || !is_present(dev))
-+		return -ENXIO;
-+	fp->private_data = vdev;
-+	kref_get(&dev->kref);
++	rc = send_seq(priv, {0x00, 0x8c});
++	if (rc < 0)
++		return -EIO;
 +
 +	return 0;
 +}
 +
-+static int v4l_stk_release(struct inode *inode, struct file *fp)
++static int check_firmware(struct dvb_frontend *fe, unsigned int type,
++			  v4l2_std_id std, __u16 int_freq)
 +{
-+	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;
-+	}
-+
-+	if (dev->owner != fp) {
-+		kref_put(&dev->kref, stk_camera_cleanup);
-+		return 0;
-+	}
-+
-+	stk_stop_stream(dev);
-+
-+	stk_free_buffers(dev);
-+
-+	dev->owner = NULL;
++	struct xc2028_data         *priv = fe->tuner_priv;
++	struct firmware_properties new_fw;
++	int			   rc = 0, is_retry = 0;
++	u16			   version, hwmodel;
++	v4l2_std_id		   std0;
 +
-+	kref_put(&dev->kref, stk_camera_cleanup);
++	tuner_dbg("%s called\n", __FUNCTION__);
 +
-+	return 0;
-+}
++	if (!priv->firm) {
++		if (!priv->ctrl.fname) {
++			tuner_info("xc2028/3028 firmware name not set!\n");
++			return -EINVAL;
++		}
 +
-+static ssize_t v4l_stk_read(struct file *fp, char __user *buf,
-+		size_t count, loff_t *f_pos)
-+{
-+	int i;
-+	int ret;
-+	unsigned long flags;
-+	struct stk_camera *dev;
-+	struct video_device *vdev;
-+	struct stk_sio_buffer *sbuf;
++		rc = load_all_firmwares(fe);
++		if (rc < 0)
++			return rc;
++	}
 +
-+	vdev = video_devdata(fp);
-+	if (vdev == NULL)
-+		return -EFAULT;
-+	dev = vdev_to_camera(vdev);
++	if (priv->ctrl.mts && !(type & FM))
++		type |= MTS;
 +
-+	if (dev == NULL)
-+		return -EIO;
++retry:
++	new_fw.type = type;
++	new_fw.id = std;
++	new_fw.std_req = std;
++	new_fw.scode_table = SCODE | priv->ctrl.scode_table;
++	new_fw.scode_nr = 0;
++	new_fw.int_freq = int_freq;
 +
-+	if (!is_present(dev))
-+		return -EIO;
-+	if (dev->owner && dev->owner != fp)
-+		return -EBUSY;
-+	dev->owner = fp;
-+	if (!is_streaming(dev)) {
-+		if (stk_initialise(dev)
-+			|| stk_allocate_buffers(dev, 3)
-+			|| stk_start_stream(dev))
-+			return -ENOMEM;
-+		spin_lock_irqsave(&dev->spinlock, flags);
-+		for (i = 0; i < dev->n_sbufs; i++) {
-+			list_add_tail(&dev->sio_bufs[i].list, &dev->sio_avail);
-+			dev->sio_bufs[i].v4lbuf.flags = V4L2_BUF_FLAG_QUEUED;
-+		}
-+		spin_unlock_irqrestore(&dev->spinlock, flags);
-+	}
-+	if (*f_pos == 0) {
-+		if (fp->f_flags & O_NONBLOCK && list_empty(&dev->sio_full))
-+			return -EWOULDBLOCK;
-+		ret = wait_event_interruptible(dev->wait_frame,
-+			!list_empty(&dev->sio_full) || !is_present(dev));
-+		if (ret)
-+			return ret;
-+		if (!is_present(dev))
-+			return -EIO;
++	tuner_dbg("checking firmware, user requested type=");
++	if (debug) {
++		dump_firm_type(new_fw.type);
++		printk("(%x), id %016llx, ", new_fw.type,
++		       (unsigned long long)new_fw.std_req);
++		if (!int_freq) {
++			printk("scode_tbl ");
++			dump_firm_type(priv->ctrl.scode_table);
++			printk("(%x), ", priv->ctrl.scode_table);
++		} else
++			printk("int_freq %d, ", new_fw.int_freq);
++		printk("scode_nr %d\n", new_fw.scode_nr);
 +	}
-+	if (count + *f_pos > dev->frame_size)
-+		count = dev->frame_size - *f_pos;
-+	spin_lock_irqsave(&dev->spinlock, flags);
-+	if (list_empty(&dev->sio_full)) {
-+		spin_unlock_irqrestore(&dev->spinlock, flags);
-+		STK_ERROR("BUG: No siobufs ready\n");
-+		return 0;
++
++	/* No need to reload base firmware if it matches */
++	if (((BASE | new_fw.type) & BASE_TYPES) ==
++	    (priv->cur_fw.type & BASE_TYPES)) {
++		tuner_dbg("BASE firmware not changed.\n");
++		goto skip_base;
 +	}
-+	sbuf = list_first_entry(&dev->sio_full, struct stk_sio_buffer, list);
-+	spin_unlock_irqrestore(&dev->spinlock, flags);
 +
-+	if (copy_to_user(buf, sbuf->buffer + *f_pos, count))
-+		return -EFAULT;
++	/* Updating BASE - forget about all currently loaded firmware */
++	memset(&priv->cur_fw, 0, sizeof(priv->cur_fw));
 +
-+	*f_pos += count;
++	/* Reset is needed before loading firmware */
++	rc = priv->tuner_callback(priv->video_dev,
++				  XC2028_TUNER_RESET, 0);
++	if (rc < 0)
++		goto fail;
 +
-+	if (*f_pos >= dev->frame_size) {
-+		*f_pos = 0;
-+		spin_lock_irqsave(&dev->spinlock, flags);
-+		list_move_tail(&sbuf->list, &dev->sio_avail);
-+		spin_unlock_irqrestore(&dev->spinlock, flags);
++	/* BASE firmwares are all std0 */
++	std0 = 0;
++	rc = load_firmware(fe, BASE | new_fw.type, &std0);
++	if (rc < 0) {
++		tuner_err("Error %d while loading base firmware\n",
++			  rc);
++		goto fail;
 +	}
-+	return count;
-+}
-+
-+static unsigned int v4l_stk_poll(struct file *fp, poll_table *wait)
-+{
-+	struct stk_camera *dev;
-+	struct video_device *vdev;
 +
-+	vdev = video_devdata(fp);
++	/* Load INIT1, if needed */
++	tuner_dbg("Load init1 firmware, if exists\n");
 +
-+	if (vdev == NULL)
-+		return -EFAULT;
++	rc = load_firmware(fe, BASE | INIT1 | new_fw.type, &std0);
++	if (rc == -ENOENT)
++		rc = load_firmware(fe, (BASE | INIT1 | new_fw.type) & ~F8MHZ,
++				   &std0);
++	if (rc < 0 && rc != -ENOENT) {
++		tuner_err("Error %d while loading init1 firmware\n",
++			  rc);
++		goto fail;
++	}
 +
-+	dev = vdev_to_camera(vdev);
-+	if (dev == NULL)
-+		return -ENODEV;
++skip_base:
++	/*
++	 * No need to reload standard specific firmware if base firmware
++	 * was not reloaded and requested video standards have not changed.
++	 */
++	if (priv->cur_fw.type == (BASE | new_fw.type) &&
++	    priv->cur_fw.std_req == std) {
++		tuner_dbg("Std-specific firmware already loaded.\n");
++		goto skip_std_specific;
++	}
 +
-+	poll_wait(fp, &dev->wait_frame, wait);
++	/* Reloading std-specific firmware forces a SCODE update */
++	priv->cur_fw.scode_table = 0;
 +
-+	if (!is_present(dev))
-+		return POLLERR;
++	rc = load_firmware(fe, new_fw.type, &new_fw.id);
++	if (rc == -ENOENT)
++		rc = load_firmware(fe, new_fw.type & ~F8MHZ, &new_fw.id);
 +
-+	if (!list_empty(&dev->sio_full))
-+		return (POLLIN | POLLRDNORM);
++	if (rc < 0)
++		goto fail;
 +
-+	return 0;
-+}
++skip_std_specific:
++	if (priv->cur_fw.scode_table == new_fw.scode_table &&
++	    priv->cur_fw.scode_nr == new_fw.scode_nr) {
++		tuner_dbg("SCODE firmware already loaded.\n");
++		goto check_device;
++	}
 +
++	/* Load SCODE firmware, if exists */
++	tuner_dbg("Trying to load scode %d\n", new_fw.scode_nr);
 +
-+static void stk_v4l_vm_open(struct vm_area_struct *vma)
-+{
-+	struct stk_sio_buffer *sbuf = vma->vm_private_data;
-+	sbuf->mapcount++;
-+}
-+static void stk_v4l_vm_close(struct vm_area_struct *vma)
-+{
-+	struct stk_sio_buffer *sbuf = vma->vm_private_data;
-+	sbuf->mapcount--;
-+	if (sbuf->mapcount == 0)
-+		sbuf->v4lbuf.flags &= ~V4L2_BUF_FLAG_MAPPED;
-+}
-+static struct vm_operations_struct stk_v4l_vm_ops = {
-+	.open = stk_v4l_vm_open,
-+	.close = stk_v4l_vm_close
-+};
++	rc = load_scode(fe, new_fw.type | new_fw.scode_table, &new_fw.id,
++			new_fw.int_freq, new_fw.scode_nr);
 +
-+static int v4l_stk_mmap(struct file *fp, struct vm_area_struct *vma)
-+{
-+	unsigned int i;
-+	int ret;
-+	unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
-+	struct stk_camera *dev;
-+	struct video_device *vdev;
-+	struct stk_sio_buffer *sbuf = NULL;
++check_device:
++	if (xc2028_get_reg(priv, 0x0004, &version) < 0 ||
++	    xc2028_get_reg(priv, 0x0008, &hwmodel) < 0) {
++		tuner_err("Unable to read tuner registers.\n");
++		goto fail;
++	}
 +
-+	if (!(vma->vm_flags & VM_WRITE) || !(vma->vm_flags & VM_SHARED))
-+		return -EINVAL;
++	tuner_info("Device is Xceive %d version %d.%d, "
++		   "firmware version %d.%d\n",
++		   hwmodel, (version & 0xf000) >> 12, (version & 0xf00) >> 8,
++		   (version & 0xf0) >> 4, version & 0xf);
 +
-+	vdev = video_devdata(fp);
-+	dev = vdev_to_camera(vdev);
++	/* Check firmware version against what we downloaded. */
++	if (priv->firm_version != ((version & 0xf0) << 4 | (version & 0x0f))) {
++		tuner_err("Incorrect readback of firmware version.\n");
++		goto fail;
++	}
 +
-+	for (i = 0; i < dev->n_sbufs; i++) {
-+		if (dev->sio_bufs[i].v4lbuf.m.offset == offset) {
-+			sbuf = dev->sio_bufs + i;
-+			break;
-+		}
++	/* Check that the tuner hardware model remains consistent over time. */
++	if (priv->hwmodel == 0 && (hwmodel == 2028 || hwmodel == 3028)) {
++		priv->hwmodel = hwmodel;
++		priv->hwvers  = version & 0xff00;
++	} else if (priv->hwmodel == 0 || priv->hwmodel != hwmodel ||
++		   priv->hwvers != (version & 0xff00)) {
++		tuner_err("Read invalid device hardware information - tuner "
++			  "hung?\n");
++		goto fail;
 +	}
-+	if (sbuf == NULL)
-+		return -EINVAL;
-+	ret = remap_vmalloc_range(vma, sbuf->buffer, 0);
-+	if (ret)
-+		return ret;
-+	vma->vm_flags |= VM_DONTEXPAND;
-+	vma->vm_private_data = sbuf;
-+	vma->vm_ops = &stk_v4l_vm_ops;
-+	sbuf->v4lbuf.flags |= V4L2_BUF_FLAG_MAPPED;
-+	stk_v4l_vm_open(vma);
-+	return 0;
-+}
 +
-+/* v4l ioctl handlers */
++	memcpy(&priv->cur_fw, &new_fw, sizeof(priv->cur_fw));
 +
-+static int stk_vidioc_querycap(struct file *filp,
-+		void *priv, struct v4l2_capability *cap)
-+{
-+	strcpy(cap->driver, "stk");
-+	strcpy(cap->card, "stk");
-+	cap->version = DRIVER_VERSION_NUM;
++	/*
++	 * By setting BASE in cur_fw.type only after successfully loading all
++	 * firmwares, we can:
++	 * 1. Identify that BASE firmware with type=0 has been loaded;
++	 * 2. Tell whether BASE firmware was just changed the next time through.
++	 */
++	priv->cur_fw.type |= BASE;
 +
-+	cap->capabilities = V4L2_CAP_VIDEO_CAPTURE
-+		| V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
 +	return 0;
-+}
 +
-+static int stk_vidioc_enum_input(struct file *filp,
-+		void *priv, struct v4l2_input *input)
-+{
-+	if (input->index != 0)
-+		return -EINVAL;
++fail:
++	memset(&priv->cur_fw, 0, sizeof(priv->cur_fw));
++	if (!is_retry) {
++		msleep(50);
++		is_retry = 1;
++		tuner_dbg("Retrying firmware load\n");
++		goto retry;
++	}
 +
-+	strcpy(input->name, "Syntek USB Camera");
-+	input->type = V4L2_INPUT_TYPE_CAMERA;
-+	return 0;
++	if (rc == -ENOENT)
++		rc = -EINVAL;
++	return rc;
 +}
 +
-+
-+static int stk_vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
++static int xc2028_signal(struct dvb_frontend *fe, u16 *strength)
 +{
-+	*i = 0;
-+	return 0;
-+}
++	struct xc2028_data *priv = fe->tuner_priv;
++	u16                 frq_lock, signal = 0;
++	int                 rc;
 +
-+static int stk_vidioc_s_input(struct file *filp, void *priv, unsigned int i)
-+{
-+	if (i != 0)
-+		return -EINVAL;
-+	else
-+		return 0;
-+}
++	tuner_dbg("%s called\n", __FUNCTION__);
 +
-+/* from vivi.c */
-+static int stk_vidioc_s_std(struct file *filp, void *priv, v4l2_std_id *a)
-+{
-+	return 0;
-+}
++	mutex_lock(&priv->lock);
 +
-+/* List of all V4Lv2 controls supported by the driver */
-+static struct v4l2_queryctrl stk_controls[] = {
-+	{
-+		.id      = V4L2_CID_BRIGHTNESS,
-+		.type    = V4L2_CTRL_TYPE_INTEGER,
-+		.name    = "Brightness",
-+		.minimum = 0,
-+		.maximum = 0xffff,
-+		.step    = 0x0100,
-+		.default_value = 0x6000,
-+	},
-+	/*TODO: get more controls to work */
-+};
++	/* Sync Lock Indicator */
++	rc = xc2028_get_reg(priv, 0x0002, &frq_lock);
++	if (rc < 0 || frq_lock == 0)
++		goto ret;
 +
-+static int stk_vidioc_queryctrl(struct file *filp,
-+		void *priv, struct v4l2_queryctrl *c)
-+{
-+	int i;
-+	int nbr;
-+	nbr = ARRAY_SIZE(stk_controls);
++	/* Frequency is locked. Return signal quality */
 +
-+	for (i = 0; i < nbr; i++) {
-+		if (stk_controls[i].id == c->id) {
-+			memcpy(c, &stk_controls[i],
-+				sizeof(struct v4l2_queryctrl));
-+			return 0;
-+		}
-+	}
-+	return -EINVAL;
-+}
++	/* Get SNR of the video signal */
++	rc = xc2028_get_reg(priv, 0x0040, &signal);
++	if (rc < 0)
++		signal = -frq_lock;
 +
-+static int stk_vidioc_g_ctrl(struct file *filp,
-+		void *priv, struct v4l2_control *c)
-+{
-+	struct stk_camera *dev = priv;
-+	switch (c->id) {
-+	case V4L2_CID_BRIGHTNESS:
-+		c->value = dev->vsettings.brightness;
-+		break;
-+	default:
-+		return -EINVAL;
-+	}
-+	return 0;
-+}
++ret:
++	mutex_unlock(&priv->lock);
 +
-+static int stk_vidioc_s_ctrl(struct file *filp,
-+		void *priv, struct v4l2_control *c)
-+{
-+	struct stk_camera *dev = priv;
-+	switch (c->id) {
-+	case V4L2_CID_BRIGHTNESS:
-+		dev->vsettings.brightness = c->value;
-+		return stk_sensor_set_brightness(dev, c->value >> 8);
-+	default:
-+		return -EINVAL;
-+	}
-+	return 0;
++	*strength = signal;
++
++	return rc;
 +}
 +
++#define DIV 15625
 +
-+static int stk_vidioc_enum_fmt_cap(struct file *filp,
-+		void *priv, struct v4l2_fmtdesc *fmtd)
++static int generic_set_freq(struct dvb_frontend *fe, u32 freq /* in HZ */,
++			    enum tuner_mode new_mode,
++			    unsigned int type,
++			    v4l2_std_id std,
++			    u16 int_freq)
 +{
-+	fmtd->flags = 0;
++	struct xc2028_data *priv = fe->tuner_priv;
++	int		   rc = -EINVAL;
++	unsigned char	   buf[4];
++	u32		   div, offset = 0;
 +
-+	switch (fmtd->index) {
-+	case 0:
-+		fmtd->pixelformat = V4L2_PIX_FMT_RGB565;
-+		strcpy(fmtd->description, "r5g6b5");
-+		break;
-+	case 1:
-+		fmtd->pixelformat = V4L2_PIX_FMT_RGB565X;
-+		strcpy(fmtd->description, "r5g6b5BE");
-+		break;
-+	case 2:
-+		fmtd->pixelformat = V4L2_PIX_FMT_UYVY;
-+		strcpy(fmtd->description, "yuv4:2:2");
-+		break;
-+	case 3:
-+		fmtd->pixelformat = V4L2_PIX_FMT_SBGGR8;
-+		strcpy(fmtd->description, "Raw bayer");
-+		break;
-+	default:
-+		return -EINVAL;
-+	}
-+	return 0;
-+}
++	tuner_dbg("%s called\n", __FUNCTION__);
 +
-+static struct stk_size {
-+	unsigned w;
-+	unsigned h;
-+	enum stk_mode m;
-+} stk_sizes[] = {
-+	{ .w = 1280, .h = 1024, .m = MODE_SXGA, },
-+	{ .w = 640,  .h = 480,  .m = MODE_VGA,  },
-+	{ .w = 352,  .h = 288,  .m = MODE_CIF,  },
-+	{ .w = 320,  .h = 240,  .m = MODE_QVGA, },
-+	{ .w = 176,  .h = 144,  .m = MODE_QCIF, },
-+};
++	mutex_lock(&priv->lock);
 +
-+static int stk_vidioc_g_fmt_cap(struct file *filp,
-+		void *priv, struct v4l2_format *f)
-+{
-+	struct v4l2_pix_format *pix_format = &f->fmt.pix;
-+	struct stk_camera *dev = priv;
-+	int i;
++	tuner_dbg("should set frequency %d kHz\n", freq / 1000);
 +
-+	for (i = 0; i < ARRAY_SIZE(stk_sizes)
-+			&& stk_sizes[i].m != dev->vsettings.mode;
-+		i++);
-+	if (i == ARRAY_SIZE(stk_sizes)) {
-+		STK_ERROR("ERROR: mode invalid\n");
-+		return -EINVAL;
-+	}
-+	pix_format->width = stk_sizes[i].w;
-+	pix_format->height = stk_sizes[i].h;
-+	pix_format->field = V4L2_FIELD_NONE;
-+	pix_format->colorspace = V4L2_COLORSPACE_SRGB;
-+	pix_format->priv = 0;
-+	pix_format->pixelformat = dev->vsettings.palette;
-+	if (dev->vsettings.palette == V4L2_PIX_FMT_SBGGR8)
-+		pix_format->bytesperline = pix_format->width;
-+	else
-+		pix_format->bytesperline = 2 * pix_format->width;
-+	pix_format->sizeimage = pix_format->bytesperline
-+				* pix_format->height;
-+	return 0;
-+}
++	if (check_firmware(fe, type, std, int_freq) < 0)
++		goto ret;
 +
-+static int stk_vidioc_try_fmt_cap(struct file *filp,
-+		void *priv, struct v4l2_format *fmtd)
-+{
-+	int i;
-+	switch (fmtd->fmt.pix.pixelformat) {
-+	case V4L2_PIX_FMT_RGB565:
-+	case V4L2_PIX_FMT_RGB565X:
-+	case V4L2_PIX_FMT_UYVY:
-+	case V4L2_PIX_FMT_SBGGR8:
-+		break;
-+	default:
-+		return -EINVAL;
-+	}
-+	for (i = 1; i < ARRAY_SIZE(stk_sizes); i++) {
-+		if (fmtd->fmt.pix.width > stk_sizes[i].w)
-+			break;
-+	}
-+	if (i == ARRAY_SIZE(stk_sizes)
-+		|| (abs(fmtd->fmt.pix.width - stk_sizes[i-1].w)
-+			< abs(fmtd->fmt.pix.width - stk_sizes[i].w))) {
-+		fmtd->fmt.pix.height = stk_sizes[i-1].h;
-+		fmtd->fmt.pix.width = stk_sizes[i-1].w;
-+		fmtd->fmt.pix.priv = i - 1;
++	/* On some cases xc2028 can disable video output, if
++	 * very weak signals are received. By sending a soft
++	 * reset, this is re-enabled. So, it is better to always
++	 * send a soft reset before changing channels, to be sure
++	 * that xc2028 will be in a safe state.
++	 * Maybe this might also be needed for DTV.
++	 */
++	if (new_mode == T_ANALOG_TV) {
++		rc = send_seq(priv, {0x00, 0x00});
++	} else if (priv->cur_fw.type & ATSC) {
++		offset = 1750000;
 +	} else {
-+		fmtd->fmt.pix.height = stk_sizes[i].h;
-+		fmtd->fmt.pix.width = stk_sizes[i].w;
-+		fmtd->fmt.pix.priv = i;
++		offset = 2750000;
++		/*
++		 * We must adjust the offset by 500kHz in two cases in order
++		 * to correctly center the IF output:
++		 * 1) When the ZARLINK456 or DIBCOM52 tables were explicitly
++		 *    selected and a 7MHz channel is tuned;
++		 * 2) When tuning a VHF channel with DTV78 firmware.
++		 */
++		if (((priv->cur_fw.type & DTV7) &&
++		     (priv->cur_fw.scode_table & (ZARLINK456 | DIBCOM52))) ||
++		    ((priv->cur_fw.type & DTV78) && freq < 470000000))
++			offset -= 500000;
 +	}
 +
-+	fmtd->fmt.pix.field = V4L2_FIELD_NONE;
-+	fmtd->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB;
-+	if (fmtd->fmt.pix.pixelformat == V4L2_PIX_FMT_SBGGR8)
-+		fmtd->fmt.pix.bytesperline = fmtd->fmt.pix.width;
++	div = (freq - offset + DIV / 2) / DIV;
++
++	/* CMD= Set frequency */
++	if (priv->firm_version < 0x0202)
++		rc = send_seq(priv, {0x00, 0x02, 0x00, 0x00});
 +	else
-+		fmtd->fmt.pix.bytesperline = 2 * fmtd->fmt.pix.width;
-+	fmtd->fmt.pix.sizeimage = fmtd->fmt.pix.bytesperline
-+		* fmtd->fmt.pix.height;
-+	return 0;
-+}
++		rc = send_seq(priv, {0x80, 0x02, 0x00, 0x00});
++	if (rc < 0)
++		goto ret;
 +
-+static int stk_vidioc_s_fmt_cap(struct file *filp,
-+		void *priv, struct v4l2_format *fmtd)
-+{
-+	int ret;
-+	struct stk_camera *dev = priv;
++	rc = priv->tuner_callback(priv->video_dev, XC2028_RESET_CLK, 1);
++	if (rc < 0)
++		goto ret;
 +
-+	if (dev == NULL)
-+		return -ENODEV;
-+	if (!is_present(dev))
-+		return -ENODEV;
-+	if (is_streaming(dev))
-+		return -EBUSY;
-+	if (dev->owner && dev->owner != filp)
-+		return -EBUSY;
-+	dev->owner = filp;
-+	ret = stk_vidioc_try_fmt_cap(filp, priv, fmtd);
-+	if (ret)
-+		return ret;
++	msleep(10);
 +
-+	dev->vsettings.palette = fmtd->fmt.pix.pixelformat;
-+	stk_free_buffers(dev);
-+	dev->frame_size = fmtd->fmt.pix.sizeimage;
-+	dev->vsettings.mode = stk_sizes[fmtd->fmt.pix.priv].m;
++	buf[0] = 0xff & (div >> 24);
++	buf[1] = 0xff & (div >> 16);
++	buf[2] = 0xff & (div >> 8);
++	buf[3] = 0xff & (div);
 +
-+	stk_initialise(dev);
-+	/* This registers controls some timings, not sure of what. */
-+	stk_camera_write_reg(dev, 0x001b, 0x0e);
-+	if (dev->vsettings.mode == MODE_SXGA)
-+		stk_camera_write_reg(dev, 0x001c, 0x0e);
-+	else
-+		stk_camera_write_reg(dev, 0x001c, 0x46);
-+	/*
-+	 * Registers 0x0115 0x0114 are the size of each line (bytes),
-+	 * regs 0x0117 0x0116 are the heigth of the image.
-+	 */
-+	stk_camera_write_reg(dev, 0x0115,
-+		(fmtd->fmt.pix.bytesperline >> 8) & 0xff);
-+	stk_camera_write_reg(dev, 0x0114,
-+		fmtd->fmt.pix.bytesperline & 0xff);
-+	stk_camera_write_reg(dev, 0x0117,
-+		(fmtd->fmt.pix.height >> 8) & 0xff);
-+	stk_camera_write_reg(dev, 0x0116,
-+		fmtd->fmt.pix.height & 0xff);
-+	return stk_sensor_configure(dev);
-+}
++	rc = i2c_send(priv, buf, sizeof(buf));
++	if (rc < 0)
++		goto ret;
++	msleep(100);
 +
-+static int stk_vidioc_reqbufs(struct file *filp,
-+		void *priv, struct v4l2_requestbuffers *rb)
-+{
-+	struct stk_camera *dev = priv;
++	priv->frequency = freq;
 +
-+	if (dev == NULL)
-+		return -ENODEV;
-+	if (rb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-+		return -EINVAL;
-+	if (rb->memory != V4L2_MEMORY_MMAP)
-+		return -EINVAL;
-+	if (is_streaming(dev)
-+		|| (dev->owner && dev->owner != filp))
-+		return -EBUSY;
-+	dev->owner = filp;
++	tuner_dbg("divisor= %02x %02x %02x %02x (freq=%d.%03d)\n",
++	       buf[0], buf[1], buf[2], buf[3],
++	       freq / 1000000, (freq % 1000000) / 1000);
 +
-+	/*FIXME If they ask for zero, we must stop streaming and free */
-+	if (rb->count < 3)
-+		rb->count = 3;
-+	/* Arbitrary limit */
-+	else if (rb->count > 5)
-+		rb->count = 5;
++	rc = 0;
 +
-+	stk_allocate_buffers(dev, rb->count);
-+	rb->count = dev->n_sbufs;
-+	return 0;
++ret:
++	mutex_unlock(&priv->lock);
++
++	return rc;
 +}
 +
-+static int stk_vidioc_querybuf(struct file *filp,
-+		void *priv, struct v4l2_buffer *buf)
++static int xc2028_set_analog_freq(struct dvb_frontend *fe,
++			      struct analog_parameters *p)
 +{
-+	int index;
-+	struct stk_camera *dev = priv;
-+	struct stk_sio_buffer *sbuf;
++	struct xc2028_data *priv = fe->tuner_priv;
++	unsigned int       type=0;
 +
-+	if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-+		return -EINVAL;
++	tuner_dbg("%s called\n", __FUNCTION__);
 +
-+	index = buf->index;
++	if (p->mode == V4L2_TUNER_RADIO) {
++		type |= FM;
++		if (priv->ctrl.input1)
++			type |= INPUT1;
++		return generic_set_freq(fe, (625l * p->frequency) / 10,
++				T_ANALOG_TV, type, 0, 0);
++	}
 +
-+	if (index < 0 || index >= dev->n_sbufs)
-+		return -EINVAL;
-+	sbuf = dev->sio_bufs + buf->index;
-+	*buf = sbuf->v4lbuf;
-+	return 0;
-+}
++	/* if std is not defined, choose one */
++	if (!p->std)
++		p->std = V4L2_STD_MN;
 +
-+static int stk_vidioc_qbuf(struct file *filp,
-+		void *priv, struct v4l2_buffer *buf)
-+{
-+	struct stk_camera *dev = priv;
-+	struct stk_sio_buffer *sbuf;
-+	unsigned long flags;
-+	if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-+		return -EINVAL;
++	/* PAL/M, PAL/N, PAL/Nc and NTSC variants should use 6MHz firmware */
++	if (!(p->std & V4L2_STD_MN))
++		type |= F8MHZ;
 +
-+	if (buf->memory != V4L2_MEMORY_MMAP)
-+		return -EINVAL;
++	/* Add audio hack to std mask */
++	p->std |= parse_audio_std_option();
 +
-+	if (buf->index < 0 || buf->index >= dev->n_sbufs)
-+		return -EINVAL;
-+	sbuf = dev->sio_bufs + buf->index;
-+	if (sbuf->v4lbuf.flags & V4L2_BUF_FLAG_QUEUED)
-+		return 0;
-+	sbuf->v4lbuf.flags |= V4L2_BUF_FLAG_QUEUED;
-+	sbuf->v4lbuf.flags &= ~V4L2_BUF_FLAG_DONE;
-+	spin_lock_irqsave(&dev->spinlock, flags);
-+	list_add_tail(&sbuf->list, &dev->sio_avail);
-+	*buf = sbuf->v4lbuf;
-+	spin_unlock_irqrestore(&dev->spinlock, flags);
-+	return 0;
++	return generic_set_freq(fe, 62500l * p->frequency,
++				T_ANALOG_TV, type, p->std, 0);
 +}
 +
-+static int stk_vidioc_dqbuf(struct file *filp,
-+		void *priv, struct v4l2_buffer *buf)
++static int xc2028_set_params(struct dvb_frontend *fe,
++			     struct dvb_frontend_parameters *p)
 +{
-+	struct stk_camera *dev = priv;
-+	struct stk_sio_buffer *sbuf;
-+	unsigned long flags;
-+	int ret;
-+
-+	if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE
-+		|| !is_streaming(dev))
-+		return -EINVAL;
-+
-+	if (filp->f_flags & O_NONBLOCK && list_empty(&dev->sio_full))
-+		return -EWOULDBLOCK;
-+	ret = wait_event_interruptible(dev->wait_frame,
-+		!list_empty(&dev->sio_full) || !is_present(dev));
-+	if (ret)
-+		return ret;
-+	if (!is_present(dev))
-+		return -EIO;
++	struct xc2028_data *priv = fe->tuner_priv;
++	unsigned int       type=0;
++	fe_bandwidth_t     bw = BANDWIDTH_8_MHZ;
++	u16                demod = 0;
 +
-+	spin_lock_irqsave(&dev->spinlock, flags);
-+	sbuf = list_first_entry(&dev->sio_full, struct stk_sio_buffer, list);
-+	list_del_init(&sbuf->list);
-+	spin_unlock_irqrestore(&dev->spinlock, flags);
-+	sbuf->v4lbuf.flags &= ~V4L2_BUF_FLAG_QUEUED;
-+	sbuf->v4lbuf.flags |= V4L2_BUF_FLAG_DONE;
-+	sbuf->v4lbuf.sequence = ++dev->sequence;
-+	do_gettimeofday(&sbuf->v4lbuf.timestamp);
++	tuner_dbg("%s called\n", __FUNCTION__);
 +
-+	*buf = sbuf->v4lbuf;
-+	return 0;
-+}
++	if (priv->ctrl.d2633)
++		type |= D2633;
++	else
++		type |= D2620;
 +
-+static int stk_vidioc_streamon(struct file *filp,
-+		void *priv, enum v4l2_buf_type type)
-+{
-+	struct stk_camera *dev = priv;
-+	if (is_streaming(dev))
-+		return 0;
-+	if (dev->sio_bufs == NULL)
++	switch(fe->ops.info.type) {
++	case FE_OFDM:
++		bw = p->u.ofdm.bandwidth;
++		break;
++	case FE_QAM:
++		tuner_info("WARN: There are some reports that "
++			   "QAM 6 MHz doesn't work.\n"
++			   "If this works for you, please report by "
++			   "e-mail to: v4l-dvb-maintainer at linuxtv.org\n");
++		bw = BANDWIDTH_6_MHZ;
++		type |= QAM;
++		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;
++		break;
++	/* DVB-S is not supported */
++	default:
 +		return -EINVAL;
-+	dev->sequence = 0;
-+	return stk_start_stream(dev);
-+}
-+
-+static int stk_vidioc_streamoff(struct file *filp,
-+		void *priv, enum v4l2_buf_type type)
-+{
-+	struct stk_camera *dev = priv;
-+	unsigned long flags;
-+	int i;
-+	stk_stop_stream(dev);
-+	spin_lock_irqsave(&dev->spinlock, flags);
-+	INIT_LIST_HEAD(&dev->sio_avail);
-+	INIT_LIST_HEAD(&dev->sio_full);
-+	for (i = 0; i < dev->n_sbufs; i++) {
-+		INIT_LIST_HEAD(&dev->sio_bufs[i].list);
-+		dev->sio_bufs[i].v4lbuf.flags = 0;
 +	}
-+	spin_unlock_irqrestore(&dev->spinlock, flags);
-+	return 0;
-+}
 +
++	switch (bw) {
++	case BANDWIDTH_8_MHZ:
++		if (p->frequency < 470000000)
++			priv->ctrl.vhfbw7 = 0;
++		else
++			priv->ctrl.uhfbw8 = 1;
++		type |= (priv->ctrl.vhfbw7 && priv->ctrl.uhfbw8) ? DTV78 : DTV8;
++		type |= F8MHZ;
++		break;
++	case BANDWIDTH_7_MHZ:
++		if (p->frequency < 470000000)
++			priv->ctrl.vhfbw7 = 1;
++		else
++			priv->ctrl.uhfbw8 = 0;
++		type |= (priv->ctrl.vhfbw7 && priv->ctrl.uhfbw8) ? DTV78 : DTV7;
++		type |= F8MHZ;
++		break;
++	case BANDWIDTH_6_MHZ:
++		type |= DTV6;
++		priv->ctrl.vhfbw7 = 0;
++		priv->ctrl.uhfbw8 = 0;
++		break;
++	default:
++		tuner_err("error: bandwidth not supported.\n");
++	};
 +
-+static int stk_vidioc_g_parm(struct file *filp,
-+		void *priv, struct v4l2_streamparm *sp)
-+{
-+	if (sp->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-+		return -EINVAL;
++	/* All S-code tables need a 200kHz shift */
++	if (priv->ctrl.demod)
++		demod = priv->ctrl.demod + 200;
 +
-+	sp->parm.capture.capability = 0;
-+	sp->parm.capture.capturemode = 0;
-+	/*FIXME This is not correct */
-+	sp->parm.capture.timeperframe.numerator = 1;
-+	sp->parm.capture.timeperframe.denominator = 30;
-+	sp->parm.capture.readbuffers = 2;
-+	sp->parm.capture.extendedmode = 0;
-+	return 0;
++	return generic_set_freq(fe, p->frequency,
++				T_DIGITAL_TV, type, 0, demod);
 +}
 +
-+static struct file_operations v4l_stk_fops = {
-+	.owner = THIS_MODULE,
-+	.open = v4l_stk_open,
-+	.release = v4l_stk_release,
-+	.read = v4l_stk_read,
-+	.poll = v4l_stk_poll,
-+	.mmap = v4l_stk_mmap,
-+	.ioctl = video_ioctl2,
-+	.llseek = no_llseek
-+};
-+
-+static void stk_v4l_dev_release(struct video_device *vd)
++static int xc2028_sleep(struct dvb_frontend *fe)
 +{
-+}
-+
-+static struct video_device stk_v4l_data = {
-+	.name = "stkwebcam",
-+	.type = VFL_TYPE_GRABBER,
-+	.type2 = VID_TYPE_CAPTURE,
-+	.minor = -1,
-+	.tvnorms = V4L2_STD_UNKNOWN,
-+	.current_norm = V4L2_STD_UNKNOWN,
-+	.fops = &v4l_stk_fops,
-+	.release = stk_v4l_dev_release,
-+
-+	.vidioc_querycap = stk_vidioc_querycap,
-+	.vidioc_enum_fmt_cap = stk_vidioc_enum_fmt_cap,
-+	.vidioc_try_fmt_cap = stk_vidioc_try_fmt_cap,
-+	.vidioc_s_fmt_cap = stk_vidioc_s_fmt_cap,
-+	.vidioc_g_fmt_cap = stk_vidioc_g_fmt_cap,
-+	.vidioc_enum_input = stk_vidioc_enum_input,
-+	.vidioc_s_input = stk_vidioc_s_input,
-+	.vidioc_g_input = stk_vidioc_g_input,
-+	.vidioc_s_std = stk_vidioc_s_std,
-+	.vidioc_reqbufs = stk_vidioc_reqbufs,
-+	.vidioc_querybuf = stk_vidioc_querybuf,
-+	.vidioc_qbuf = stk_vidioc_qbuf,
-+	.vidioc_dqbuf = stk_vidioc_dqbuf,
-+	.vidioc_streamon = stk_vidioc_streamon,
-+	.vidioc_streamoff = stk_vidioc_streamoff,
-+	.vidioc_queryctrl = stk_vidioc_queryctrl,
-+	.vidioc_g_ctrl = stk_vidioc_g_ctrl,
-+	.vidioc_s_ctrl = stk_vidioc_s_ctrl,
-+	.vidioc_g_parm = stk_vidioc_g_parm,
-+};
++	struct xc2028_data *priv = fe->tuner_priv;
++	int rc = 0;
 +
++	tuner_dbg("%s called\n", __FUNCTION__);
 +
-+static int stk_register_video_device(struct stk_camera *dev)
-+{
-+	int err;
++	mutex_lock(&priv->lock);
 +
-+	dev->vdev = stk_v4l_data;
-+	dev->vdev.debug = debug;
-+	dev->vdev.dev = &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");
++	if (priv->firm_version < 0x0202)
++		rc = send_seq(priv, {0x00, 0x08, 0x00, 0x00});
 +	else
-+		STK_INFO("Syntek USB2.0 Camera is now controlling video device"
-+			" /dev/video%d\n", dev->vdev.minor);
-+	return err;
-+}
-+
-+
-+/* USB Stuff */
-+
-+static int stk_camera_probe(struct usb_interface *interface,
-+		const struct usb_device_id *id)
-+{
-+	int i;
-+	int err;
++		rc = send_seq(priv, {0x80, 0x08, 0x00, 0x00});
 +
-+	struct stk_camera *dev = NULL;
-+	struct usb_device *udev = interface_to_usbdev(interface);
-+	struct usb_host_interface *iface_desc;
-+	struct usb_endpoint_descriptor *endpoint;
++	priv->cur_fw.type = 0;	/* need firmware reload */
 +
-+	dev = kzalloc(sizeof(struct stk_camera), GFP_KERNEL);
-+	if (dev == NULL) {
-+		STK_ERROR("Out of memory !\n");
-+		return -ENOMEM;
-+	}
++	mutex_unlock(&priv->lock);
 +
-+	kref_init(&dev->kref);
-+	spin_lock_init(&dev->spinlock);
-+	init_waitqueue_head(&dev->wait_frame);
++	return rc;
++}
 +
-+	dev->udev = udev;
-+	dev->interface = interface;
-+	usb_get_intf(interface);
 +
-+	dev->vsettings.vflip = vflip;
-+	dev->vsettings.hflip = hflip;
-+	dev->n_sbufs = 0;
-+	set_present(dev);
++static int xc2028_dvb_release(struct dvb_frontend *fe)
++{
++	struct xc2028_data *priv = fe->tuner_priv;
 +
-+	/* Set up the endpoint information
-+	 * use only the first isoc-in endpoint
-+	 * for the current alternate setting */
-+	iface_desc = interface->cur_altsetting;
++	tuner_dbg("%s called\n", __FUNCTION__);
 +
-+	for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
-+		endpoint = &iface_desc->endpoint[i].desc;
++	mutex_lock(&xc2028_list_mutex);
 +
-+		if (!dev->isoc_ep
-+			&& ((endpoint->bEndpointAddress
-+				& USB_ENDPOINT_DIR_MASK) == USB_DIR_IN)
-+			&& ((endpoint->bmAttributes
-+				& USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_ISOC)) {
-+			/* we found an isoc in endpoint */
-+			dev->isoc_ep = (endpoint->bEndpointAddress & 0xF);
-+			break;
-+		}
-+	}
-+	if (!dev->isoc_ep) {
-+		STK_ERROR("Could not find isoc-in endpoint");
-+		kref_put(&dev->kref, stk_camera_cleanup);
-+		return -ENODEV;
-+	}
-+	dev->vsettings.brightness = 0x7fff;
-+	dev->vsettings.palette = V4L2_PIX_FMT_RGB565;
-+	dev->vsettings.mode = MODE_VGA;
-+	dev->frame_size = 640*480*2;
++	priv->count--;
 +
-+	INIT_LIST_HEAD(&dev->sio_avail);
-+	INIT_LIST_HEAD(&dev->sio_full);
++	if (!priv->count) {
++		list_del(&priv->xc2028_list);
 +
-+	usb_set_intfdata(interface, dev);
++		kfree(priv->ctrl.fname);
 +
-+	err = stk_register_video_device(dev);
-+	if (err) {
-+		kref_put(&dev->kref, stk_camera_cleanup);
-+		return err;
++		free_firmware(priv);
++		kfree(priv);
++		fe->tuner_priv = NULL;
 +	}
 +
-+	stk_create_sysfs_files(&dev->vdev);
++	mutex_unlock(&xc2028_list_mutex);
 +
 +	return 0;
 +}
 +
-+static void stk_camera_disconnect(struct usb_interface *interface)
++static int xc2028_get_frequency(struct dvb_frontend *fe, u32 *frequency)
 +{
-+	struct stk_camera *dev = usb_get_intfdata(interface);
++	struct xc2028_data *priv = fe->tuner_priv;
 +
-+	usb_set_intfdata(interface, NULL);
-+	unset_present(dev);
++	tuner_dbg("%s called\n", __FUNCTION__);
 +
-+	wake_up_interruptible(&dev->wait_frame);
-+	stk_remove_sysfs_files(&dev->vdev);
++	*frequency = priv->frequency;
 +
-+	kref_put(&dev->kref, stk_camera_cleanup);
++	return 0;
 +}
 +
-+static struct usb_driver stk_camera_driver = {
-+	.name = "stkwebcam",
-+	.probe = stk_camera_probe,
-+	.disconnect = stk_camera_disconnect,
-+	.id_table = stkwebcam_table,
-+};
++static int xc2028_set_config(struct dvb_frontend *fe, void *priv_cfg)
++{
++	struct xc2028_data *priv = fe->tuner_priv;
++	struct xc2028_ctrl *p    = priv_cfg;
++	int                 rc   = 0;
 +
++	tuner_dbg("%s called\n", __FUNCTION__);
 +
-+static int __init stk_camera_init(void)
-+{
-+	int result;
++	mutex_lock(&priv->lock);
 +
-+	result = usb_register(&stk_camera_driver);
-+	if (result)
-+		STK_ERROR("usb_register failed ! Error number %d\n", result);
++	kfree(priv->ctrl.fname);
++	free_firmware(priv);
 +
++	memcpy(&priv->ctrl, p, sizeof(priv->ctrl));
++	priv->ctrl.fname = NULL;
 +
-+	return result;
-+}
++	if (p->fname) {
++		priv->ctrl.fname = kstrdup(p->fname, GFP_KERNEL);
++		if (priv->ctrl.fname == NULL)
++			rc = -ENOMEM;
++	}
 +
-+static void __exit stk_camera_exit(void)
-+{
-+	usb_deregister(&stk_camera_driver);
-+}
++	if (priv->ctrl.max_len < 9)
++		priv->ctrl.max_len = 13;
 +
-+module_init(stk_camera_init);
-+module_exit(stk_camera_exit);
++	mutex_unlock(&priv->lock);
 +
++	return rc;
++}
 +
-diff --git a/drivers/media/video/stk-webcam.h b/drivers/media/video/stk-webcam.h
-new file mode 100644
-index 0000000..7e989d1
---- /dev/null
-+++ b/drivers/media/video/stk-webcam.h
-@@ -0,0 +1,138 @@
-+/*
-+ * stk-webcam.h : Driver for Syntek 1125 USB webcam controller
-+ *
-+ * Copyright (C) 2006 Nicolas VIVIEN
-+ * Copyright 2007-2008 Jaime Velasco Juan <jsagarribay at 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
-+ * any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You 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
-+ */
++static const struct dvb_tuner_ops xc2028_dvb_tuner_ops = {
++	.info = {
++		 .name = "Xceive XC3028",
++		 .frequency_min = 42000000,
++		 .frequency_max = 864000000,
++		 .frequency_step = 50000,
++		 },
 +
-+#ifndef STKWEBCAM_H
-+#define STKWEBCAM_H
++	.set_config	   = xc2028_set_config,
++	.set_analog_params = xc2028_set_analog_freq,
++	.release           = xc2028_dvb_release,
++	.get_frequency     = xc2028_get_frequency,
++	.get_rf_strength   = xc2028_signal,
++	.set_params        = xc2028_set_params,
++	.sleep             = xc2028_sleep,
 +
-+#include <linux/usb.h>
-+#include <media/v4l2-common.h>
++};
 +
-+#define DRIVER_VERSION		"v0.0.1"
-+#define DRIVER_VERSION_NUM	0x000001
++struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe,
++				   struct xc2028_config *cfg)
++{
++	struct xc2028_data *priv;
++	void               *video_dev;
 +
-+#define MAX_ISO_BUFS		3
-+#define ISO_FRAMES_PER_DESC	16
-+#define ISO_MAX_FRAME_SIZE	3 * 1024
-+#define ISO_BUFFER_SIZE		(ISO_FRAMES_PER_DESC * ISO_MAX_FRAME_SIZE)
++	if (debug)
++		printk(KERN_DEBUG PREFIX ": Xcv2028/3028 init called!\n");
 +
++	if (NULL == cfg || NULL == cfg->video_dev)
++		return NULL;
 +
-+#define PREFIX				"stkwebcam: "
-+#define STK_INFO(str, args...)		printk(KERN_INFO PREFIX str, ##args)
-+#define STK_ERROR(str, args...)		printk(KERN_ERR PREFIX str, ##args)
-+#define STK_WARNING(str, args...)	printk(KERN_WARNING PREFIX str, ##args)
++	if (!fe) {
++		printk(KERN_ERR PREFIX ": No frontend!\n");
++		return NULL;
++	}
 +
-+struct stk_iso_buf {
-+	void *data;
-+	int length;
-+	int read;
-+	struct urb *urb;
-+};
++	video_dev = cfg->video_dev;
 +
-+/* Streaming IO buffers */
-+struct stk_sio_buffer {
-+	struct v4l2_buffer v4lbuf;
-+	char *buffer;
-+	int mapcount;
-+	struct stk_camera *dev;
-+	struct list_head list;
-+};
++	mutex_lock(&xc2028_list_mutex);
 +
-+enum stk_mode {MODE_VGA, MODE_SXGA, MODE_CIF, MODE_QVGA, MODE_QCIF};
++	list_for_each_entry(priv, &xc2028_list, xc2028_list) {
++		if (priv->video_dev == cfg->video_dev) {
++			video_dev = NULL;
++			break;
++		}
++	}
 +
-+struct stk_video {
-+	enum stk_mode mode;
-+	int brightness;
-+	__u32 palette;
-+	int hflip;
-+	int vflip;
-+};
++	if (video_dev) {
++		priv = kzalloc(sizeof(*priv), GFP_KERNEL);
++		if (priv == NULL) {
++			mutex_unlock(&xc2028_list_mutex);
++			return NULL;
++		}
 +
-+enum stk_status {
-+	S_PRESENT = 1,
-+	S_INITIALISED = 2,
-+	S_MEMALLOCD = 4,
-+	S_STREAMING = 8,
-+};
-+#define is_present(dev)		((dev)->status & S_PRESENT)
-+#define is_initialised(dev)	((dev)->status & S_INITIALISED)
-+#define is_streaming(dev)	((dev)->status & S_STREAMING)
-+#define is_memallocd(dev)	((dev)->status & S_MEMALLOCD)
-+#define set_present(dev)	((dev)->status = S_PRESENT)
-+#define unset_present(dev)	((dev)->status &= \
-+					~(S_PRESENT|S_INITIALISED|S_STREAMING))
-+#define set_initialised(dev)	((dev)->status |= S_INITIALISED)
-+#define set_memallocd(dev)	((dev)->status |= S_MEMALLOCD)
-+#define unset_memallocd(dev)	((dev)->status &= ~S_MEMALLOCD)
-+#define set_streaming(dev)	((dev)->status |= S_STREAMING)
-+#define unset_streaming(dev)	((dev)->status &= ~S_STREAMING)
++		priv->i2c_props.addr = cfg->i2c_addr;
++		priv->i2c_props.adap = cfg->i2c_adap;
++		priv->video_dev = video_dev;
++		priv->tuner_callback = cfg->callback;
++		priv->ctrl.max_len = 13;
 +
-+struct regval {
-+	unsigned reg;
-+	unsigned val;
-+};
++		mutex_init(&priv->lock);
 +
-+struct stk_camera {
-+	struct video_device vdev;
-+	struct usb_device *udev;
-+	struct usb_interface *interface;
-+	int webcam_model;
-+	struct file *owner;
++		list_add_tail(&priv->xc2028_list, &xc2028_list);
++	}
 +
-+	u8 isoc_ep;
++	fe->tuner_priv = priv;
++	priv->count++;
 +
-+	struct kref kref;
-+	/* Not sure if this is right */
-+	atomic_t urbs_used;
++	memcpy(&fe->ops.tuner_ops, &xc2028_dvb_tuner_ops,
++	       sizeof(xc2028_dvb_tuner_ops));
 +
-+	struct stk_video vsettings;
++	tuner_info("type set to %s\n", "XCeive xc2028/xc3028 tuner");
 +
-+	enum stk_status status;
++	if (cfg->ctrl)
++		xc2028_set_config(fe, cfg->ctrl);
 +
-+	spinlock_t spinlock;
-+	wait_queue_head_t wait_frame;
++	mutex_unlock(&xc2028_list_mutex);
 +
-+	struct stk_iso_buf *isobufs;
++	return fe;
++}
 +
-+	int frame_size;
-+	/* Streaming buffers */
-+	unsigned int n_sbufs;
-+	struct stk_sio_buffer *sio_bufs;
-+	struct list_head sio_avail;
-+	struct list_head sio_full;
-+	unsigned sequence;
-+};
++EXPORT_SYMBOL(xc2028_attach);
 +
-+#define to_stk_camera(d) container_of(d, struct stk_camera, kref)
-+#define vdev_to_camera(d) container_of(d, struct stk_camera, vdev)
++MODULE_DESCRIPTION("Xceive xc2028/xc3028 tuner driver");
++MODULE_AUTHOR("Michel Ludwig <michel.ludwig at gmail.com>");
++MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab at infradead.org>");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/media/video/tuner-xc2028.h b/drivers/media/video/tuner-xc2028.h
+new file mode 100644
+index 0000000..3eb8420
+--- /dev/null
++++ b/drivers/media/video/tuner-xc2028.h
+@@ -0,0 +1,63 @@
++/* tuner-xc2028
++ *
++ * Copyright (c) 2007 Mauro Carvalho Chehab (mchehab at infradead.org)
++ * This code is placed under the terms of the GNU General Public License v2
++ */
 +
-+void stk_camera_delete(struct kref *);
-+int stk_camera_write_reg(struct stk_camera *, u16, u8);
-+int stk_camera_read_reg(struct stk_camera *, u16, int *);
++#ifndef __TUNER_XC2028_H__
++#define __TUNER_XC2028_H__
 +
-+int stk_sensor_outb(struct stk_camera *dev, u8 reg, u8 val);
-+int stk_sensor_inb(struct stk_camera *dev, u8 reg, u8 *val);
-+int stk_sensor_init(struct stk_camera *);
-+int stk_sensor_configure(struct stk_camera *);
-+int stk_sensor_sleep(struct stk_camera *dev);
-+int stk_sensor_wakeup(struct stk_camera *dev);
-+int stk_sensor_set_brightness(struct stk_camera *dev, int br);
++#include "dvb_frontend.h"
++
++#define XC2028_DEFAULT_FIRMWARE "xc3028-v27.fw"
++
++/*      Dmoduler		IF (kHz) */
++#define	XC3028_FE_DEFAULT	0
++#define XC3028_FE_LG60		6000
++#define	XC3028_FE_ATI638	6380
++#define	XC3028_FE_OREN538	5380
++#define	XC3028_FE_OREN36	3600
++#define	XC3028_FE_TOYOTA388	3880
++#define	XC3028_FE_TOYOTA794	7940
++#define	XC3028_FE_DIBCOM52	5200
++#define	XC3028_FE_ZARLINK456	4560
++#define	XC3028_FE_CHINA		5200
++
++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;
++};
++
++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 */
++#define XC2028_TUNER_RESET	0
++#define XC2028_RESET_CLK	1
 +
++#if defined(CONFIG_TUNER_XC2028) || (defined(CONFIG_TUNER_XC2028_MODULE) && defined(MODULE))
++extern struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe,
++					  struct xc2028_config *cfg);
++#else
++static inline struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe,
++						 struct xc2028_config *cfg)
++{
++	printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n",
++	       __FUNCTION__);
++	return NULL;
++}
 +#endif
-diff --git a/drivers/media/video/tda7432.c b/drivers/media/video/tda7432.c
-index 4322580..b4d10f7 100644
---- a/drivers/media/video/tda7432.c
-+++ b/drivers/media/video/tda7432.c
-@@ -8,6 +8,7 @@
-  * Muting and tone control by Jonathan Isom <jisom at ematic.com>
-  *
-  * Copyright (c) 2000 Eric Sandeen <eric_sandeen at bigfoot.com>
-+ * Copyright (c) 2006 Mauro Carvalho Chehab <mchehab at infradead.org>
-  * This code is placed under the terms of the GNU General Public License
-  * Based on tda9855.c by Steve VanDeBogart (vandebo at uclink.berkeley.edu)
-  * Which was based on tda8425.c by Greg Alexander (c) 1998
-@@ -276,7 +277,7 @@ static void do_tda7432_init(struct i2c_client *client)
- 	t->volume =  0x3b ;				 /* -27dB Volume            */
- 	if (loudness)			 /* Turn loudness on?     */
- 		t->volume |= TDA7432_LD_ON;
--	t->muted    = VIDEO_AUDIO_MUTE;
-+	t->muted    = 1;
- 	t->treble   = TDA7432_TREBLE_0DB; /* 0dB Treble            */
- 	t->bass		= TDA7432_BASS_0DB; 	 /* 0dB Bass              */
- 	t->lf     = TDA7432_ATTEN_0DB;	 /* 0dB attenuation       */
-@@ -332,151 +333,160 @@ static int tda7432_detach(struct i2c_client *client)
++
++#endif /* __TUNER_XC2028_H__ */
+diff --git a/drivers/media/video/tvaudio.c b/drivers/media/video/tvaudio.c
+index a19cdcc..a755605 100644
+--- a/drivers/media/video/tvaudio.c
++++ b/drivers/media/video/tvaudio.c
+@@ -31,6 +31,7 @@
+ #include <media/tvaudio.h>
+ #include <media/v4l2-common.h>
+ #include <media/v4l2-chip-ident.h>
++#include <media/v4l2-i2c-drv-legacy.h>
+ 
+ #include <media/i2c-addr.h>
+ 
+@@ -109,7 +110,7 @@ static struct CHIPDESC chiplist[];
+ 
+ /* current state of the chip */
+ struct CHIPSTATE {
+-	struct i2c_client c;
++	struct i2c_client *c;
+ 
+ 	/* index into CHIPDESC array */
+ 	int type;
+@@ -145,10 +146,6 @@ static unsigned short normal_i2c[] = {
+ 	I2C_CLIENT_END };
+ I2C_CLIENT_INSMOD;
+ 
+-static struct i2c_driver driver;
+-static struct i2c_client client_template;
+-
+-
+ /* ---------------------------------------------------------------------- */
+ /* i2c I/O functions                                                      */
+ 
+@@ -157,24 +154,24 @@ static int chip_write(struct CHIPSTATE *chip, int subaddr, int val)
+ 	unsigned char buffer[2];
+ 
+ 	if (-1 == subaddr) {
+-		v4l_dbg(1, debug, &chip->c, "%s: chip_write: 0x%x\n",
+-			chip->c.name, val);
++		v4l_dbg(1, debug, chip->c, "%s: chip_write: 0x%x\n",
++			chip->c->name, val);
+ 		chip->shadow.bytes[1] = val;
+ 		buffer[0] = val;
+-		if (1 != i2c_master_send(&chip->c,buffer,1)) {
+-			v4l_warn(&chip->c, "%s: I/O error (write 0x%x)\n",
+-				chip->c.name, val);
++		if (1 != i2c_master_send(chip->c,buffer,1)) {
++			v4l_warn(chip->c, "%s: I/O error (write 0x%x)\n",
++				chip->c->name, val);
+ 			return -1;
+ 		}
+ 	} else {
+-		v4l_dbg(1, debug, &chip->c, "%s: chip_write: reg%d=0x%x\n",
+-			chip->c.name, subaddr, val);
++		v4l_dbg(1, debug, chip->c, "%s: chip_write: reg%d=0x%x\n",
++			chip->c->name, subaddr, val);
+ 		chip->shadow.bytes[subaddr+1] = val;
+ 		buffer[0] = subaddr;
+ 		buffer[1] = val;
+-		if (2 != i2c_master_send(&chip->c,buffer,2)) {
+-			v4l_warn(&chip->c, "%s: I/O error (write reg%d=0x%x)\n",
+-			chip->c.name, subaddr, val);
++		if (2 != i2c_master_send(chip->c,buffer,2)) {
++			v4l_warn(chip->c, "%s: I/O error (write reg%d=0x%x)\n",
++			chip->c->name, subaddr, val);
+ 			return -1;
+ 		}
+ 	}
+@@ -197,12 +194,12 @@ static int chip_read(struct CHIPSTATE *chip)
+ {
+ 	unsigned char buffer;
+ 
+-	if (1 != i2c_master_recv(&chip->c,&buffer,1)) {
+-		v4l_warn(&chip->c, "%s: I/O error (read)\n",
+-		chip->c.name);
++	if (1 != i2c_master_recv(chip->c,&buffer,1)) {
++		v4l_warn(chip->c, "%s: I/O error (read)\n",
++		chip->c->name);
+ 		return -1;
+ 	}
+-	v4l_dbg(1, debug, &chip->c, "%s: chip_read: 0x%x\n",chip->c.name, buffer);
++	v4l_dbg(1, debug, chip->c, "%s: chip_read: 0x%x\n",chip->c->name, buffer);
+ 	return buffer;
+ }
+ 
+@@ -211,17 +208,17 @@ static int chip_read2(struct CHIPSTATE *chip, int subaddr)
+ 	unsigned char write[1];
+ 	unsigned char read[1];
+ 	struct i2c_msg msgs[2] = {
+-		{ chip->c.addr, 0,        1, write },
+-		{ chip->c.addr, I2C_M_RD, 1, read  }
++		{ chip->c->addr, 0,        1, write },
++		{ chip->c->addr, I2C_M_RD, 1, read  }
+ 	};
+ 	write[0] = subaddr;
+ 
+-	if (2 != i2c_transfer(chip->c.adapter,msgs,2)) {
+-		v4l_warn(&chip->c, "%s: I/O error (read2)\n", chip->c.name);
++	if (2 != i2c_transfer(chip->c->adapter,msgs,2)) {
++		v4l_warn(chip->c, "%s: I/O error (read2)\n", chip->c->name);
+ 		return -1;
+ 	}
+-	v4l_dbg(1, debug, &chip->c, "%s: chip_read2: reg%d=0x%x\n",
+-		chip->c.name, subaddr,read[0]);
++	v4l_dbg(1, debug, chip->c, "%s: chip_read2: reg%d=0x%x\n",
++		chip->c->name, subaddr,read[0]);
+ 	return read[0];
+ }
+ 
+@@ -233,8 +230,8 @@ static int chip_cmd(struct CHIPSTATE *chip, char *name, audiocmd *cmd)
+ 		return 0;
+ 
+ 	/* update our shadow register set; print bytes if (debug > 0) */
+-	v4l_dbg(1, debug, &chip->c, "%s: chip_cmd(%s): reg=%d, data:",
+-		chip->c.name, name,cmd->bytes[0]);
++	v4l_dbg(1, debug, chip->c, "%s: chip_cmd(%s): reg=%d, data:",
++		chip->c->name, name,cmd->bytes[0]);
+ 	for (i = 1; i < cmd->count; i++) {
+ 		if (debug)
+ 			printk(" 0x%x",cmd->bytes[i]);
+@@ -244,8 +241,8 @@ static int chip_cmd(struct CHIPSTATE *chip, char *name, audiocmd *cmd)
+ 		printk("\n");
+ 
+ 	/* send data to the chip */
+-	if (cmd->count != i2c_master_send(&chip->c,cmd->bytes,cmd->count)) {
+-		v4l_warn(&chip->c, "%s: I/O error (%s)\n", chip->c.name, name);
++	if (cmd->count != i2c_master_send(chip->c,cmd->bytes,cmd->count)) {
++		v4l_warn(chip->c, "%s: I/O error (%s)\n", chip->c->name, name);
+ 		return -1;
+ 	}
+ 	return 0;
+@@ -269,7 +266,7 @@ static int chip_thread(void *data)
+ 	struct CHIPSTATE *chip = data;
+ 	struct CHIPDESC  *desc = chiplist + chip->type;
+ 
+-	v4l_dbg(1, debug, &chip->c, "%s: thread started\n", chip->c.name);
++	v4l_dbg(1, debug, chip->c, "%s: thread started\n", chip->c->name);
+ 	set_freezable();
+ 	for (;;) {
+ 		set_current_state(TASK_INTERRUPTIBLE);
+@@ -279,7 +276,7 @@ static int chip_thread(void *data)
+ 		try_to_freeze();
+ 		if (kthread_should_stop())
+ 			break;
+-		v4l_dbg(1, debug, &chip->c, "%s: thread wakeup\n", chip->c.name);
++		v4l_dbg(1, debug, chip->c, "%s: thread wakeup\n", chip->c->name);
+ 
+ 		/* don't do anything for radio or if mode != auto */
+ 		if (chip->radio || chip->mode != 0)
+@@ -292,7 +289,7 @@ static int chip_thread(void *data)
+ 		mod_timer(&chip->wt, jiffies+msecs_to_jiffies(2000));
+ 	}
+ 
+-	v4l_dbg(1, debug, &chip->c, "%s: thread exiting\n", chip->c.name);
++	v4l_dbg(1, debug, chip->c, "%s: thread exiting\n", chip->c->name);
  	return 0;
  }
  
--static int tda7432_command(struct i2c_client *client,
--			   unsigned int cmd, void *arg)
-+static int tda7432_get_ctrl(struct i2c_client *client,
-+			    struct v4l2_control *ctrl)
+@@ -304,17 +301,19 @@ static void generic_checkmode(struct CHIPSTATE *chip)
+ 	if (mode == chip->prevmode)
+ 	return;
+ 
+-	v4l_dbg(1, debug, &chip->c, "%s: thread checkmode\n", chip->c.name);
++	v4l_dbg(1, debug, chip->c, "%s: thread checkmode\n", chip->c->name);
+ 	chip->prevmode = mode;
+ 
+-	if (mode & VIDEO_SOUND_STEREO)
+-		desc->setmode(chip,VIDEO_SOUND_STEREO);
+-	else if (mode & VIDEO_SOUND_LANG1)
+-		desc->setmode(chip,VIDEO_SOUND_LANG1);
+-	else if (mode & VIDEO_SOUND_LANG2)
+-		desc->setmode(chip,VIDEO_SOUND_LANG2);
++	if (mode & V4L2_TUNER_MODE_STEREO)
++		desc->setmode(chip,V4L2_TUNER_MODE_STEREO);
++	if (mode & V4L2_TUNER_MODE_LANG1_LANG2)
++		desc->setmode(chip,V4L2_TUNER_MODE_STEREO);
++	else if (mode & V4L2_TUNER_MODE_LANG1)
++		desc->setmode(chip,V4L2_TUNER_MODE_LANG1);
++	else if (mode & V4L2_TUNER_MODE_LANG2)
++		desc->setmode(chip,V4L2_TUNER_MODE_LANG2);
+ 	else
+-		desc->setmode(chip,VIDEO_SOUND_MONO);
++		desc->setmode(chip,V4L2_TUNER_MODE_MONO);
+ }
+ 
+ /* ---------------------------------------------------------------------- */
+@@ -345,13 +344,13 @@ static int tda9840_getmode(struct CHIPSTATE *chip)
+ 	int val, mode;
+ 
+ 	val = chip_read(chip);
+-	mode = VIDEO_SOUND_MONO;
++	mode = V4L2_TUNER_MODE_MONO;
+ 	if (val & TDA9840_DS_DUAL)
+-		mode |= VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
++		mode |= V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2;
+ 	if (val & TDA9840_ST_STEREO)
+-		mode |= VIDEO_SOUND_STEREO;
++		mode |= V4L2_TUNER_MODE_STEREO;
+ 
+-	v4l_dbg(1, debug, &chip->c, "tda9840_getmode(): raw chip read: %d, return: %d\n",
++	v4l_dbg(1, debug, chip->c, "tda9840_getmode(): raw chip read: %d, return: %d\n",
+ 		val, mode);
+ 	return mode;
+ }
+@@ -362,16 +361,16 @@ static void tda9840_setmode(struct CHIPSTATE *chip, int mode)
+ 	int t = chip->shadow.bytes[TDA9840_SW + 1] & ~0x7e;
+ 
+ 	switch (mode) {
+-	case VIDEO_SOUND_MONO:
++	case V4L2_TUNER_MODE_MONO:
+ 		t |= TDA9840_MONO;
+ 		break;
+-	case VIDEO_SOUND_STEREO:
++	case V4L2_TUNER_MODE_STEREO:
+ 		t |= TDA9840_STEREO;
+ 		break;
+-	case VIDEO_SOUND_LANG1:
++	case V4L2_TUNER_MODE_LANG1:
+ 		t |= TDA9840_DUALA;
+ 		break;
+-	case VIDEO_SOUND_LANG2:
++	case V4L2_TUNER_MODE_LANG2:
+ 		t |= TDA9840_DUALB;
+ 		break;
+ 	default:
+@@ -502,7 +501,7 @@ static int  tda985x_getmode(struct CHIPSTATE *chip)
+ 		chip_read(chip)) >> 4;
+ 	/* Add mono mode regardless of SAP and stereo */
+ 	/* Allows forced mono */
+-	return mode | VIDEO_SOUND_MONO;
++	return mode | V4L2_TUNER_MODE_MONO;
+ }
+ 
+ static void tda985x_setmode(struct CHIPSTATE *chip, int mode)
+@@ -511,13 +510,13 @@ static void tda985x_setmode(struct CHIPSTATE *chip, int mode)
+ 	int c6 = chip->shadow.bytes[TDA985x_C6+1] & 0x3f;
+ 
+ 	switch (mode) {
+-	case VIDEO_SOUND_MONO:
++	case V4L2_TUNER_MODE_MONO:
+ 		c6 |= TDA985x_MONO;
+ 		break;
+-	case VIDEO_SOUND_STEREO:
++	case V4L2_TUNER_MODE_STEREO:
+ 		c6 |= TDA985x_STEREO;
+ 		break;
+-	case VIDEO_SOUND_LANG1:
++	case V4L2_TUNER_MODE_LANG1:
+ 		c6 |= TDA985x_SAP;
+ 		break;
+ 	default:
+@@ -650,12 +649,12 @@ static int tda9873_getmode(struct CHIPSTATE *chip)
+ 	int val,mode;
+ 
+ 	val = chip_read(chip);
+-	mode = VIDEO_SOUND_MONO;
++	mode = V4L2_TUNER_MODE_MONO;
+ 	if (val & TDA9873_STEREO)
+-		mode |= VIDEO_SOUND_STEREO;
++		mode |= V4L2_TUNER_MODE_STEREO;
+ 	if (val & TDA9873_DUAL)
+-		mode |= VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
+-	v4l_dbg(1, debug, &chip->c, "tda9873_getmode(): raw chip read: %d, return: %d\n",
++		mode |= V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2;
++	v4l_dbg(1, debug, chip->c, "tda9873_getmode(): raw chip read: %d, return: %d\n",
+ 		val, mode);
+ 	return mode;
+ }
+@@ -666,24 +665,24 @@ static void tda9873_setmode(struct CHIPSTATE *chip, int mode)
+ 	/*	int adj_data = chip->shadow.bytes[TDA9873_AD+1] ; */
+ 
+ 	if ((sw_data & TDA9873_INP_MASK) != TDA9873_INTERNAL) {
+-		v4l_dbg(1, debug, &chip->c, "tda9873_setmode(): external input\n");
++		v4l_dbg(1, debug, chip->c, "tda9873_setmode(): external input\n");
+ 		return;
+ 	}
+ 
+-	v4l_dbg(1, debug, &chip->c, "tda9873_setmode(): chip->shadow.bytes[%d] = %d\n", TDA9873_SW+1, chip->shadow.bytes[TDA9873_SW+1]);
+-	v4l_dbg(1, debug, &chip->c, "tda9873_setmode(): sw_data  = %d\n", sw_data);
++	v4l_dbg(1, debug, chip->c, "tda9873_setmode(): chip->shadow.bytes[%d] = %d\n", TDA9873_SW+1, chip->shadow.bytes[TDA9873_SW+1]);
++	v4l_dbg(1, debug, chip->c, "tda9873_setmode(): sw_data  = %d\n", sw_data);
+ 
+ 	switch (mode) {
+-	case VIDEO_SOUND_MONO:
++	case V4L2_TUNER_MODE_MONO:
+ 		sw_data |= TDA9873_TR_MONO;
+ 		break;
+-	case VIDEO_SOUND_STEREO:
++	case V4L2_TUNER_MODE_STEREO:
+ 		sw_data |= TDA9873_TR_STEREO;
+ 		break;
+-	case VIDEO_SOUND_LANG1:
++	case V4L2_TUNER_MODE_LANG1:
+ 		sw_data |= TDA9873_TR_DUALA;
+ 		break;
+-	case VIDEO_SOUND_LANG2:
++	case V4L2_TUNER_MODE_LANG2:
+ 		sw_data |= TDA9873_TR_DUALB;
+ 		break;
+ 	default:
+@@ -692,7 +691,7 @@ static void tda9873_setmode(struct CHIPSTATE *chip, int mode)
+ 	}
+ 
+ 	chip_write(chip, TDA9873_SW, sw_data);
+-	v4l_dbg(1, debug, &chip->c, "tda9873_setmode(): req. mode %d; chip_write: %d\n",
++	v4l_dbg(1, debug, chip->c, "tda9873_setmode(): req. mode %d; chip_write: %d\n",
+ 		mode, sw_data);
+ }
+ 
+@@ -831,7 +830,7 @@ static int tda9874a_setup(struct CHIPSTATE *chip)
+ 		chip_write(chip, TDA9874A_SDACOSR, (tda9874a_mode) ? 0x81:0x80);
+ 		chip_write(chip, TDA9874A_AOSR, 0x00); /* or 0x10 */
+ 	}
+-	v4l_dbg(1, debug, &chip->c, "tda9874a_setup(): %s [0x%02X].\n",
++	v4l_dbg(1, debug, chip->c, "tda9874a_setup(): %s [0x%02X].\n",
+ 		tda9874a_modelist[tda9874a_STD].name,tda9874a_STD);
+ 	return 1;
+ }
+@@ -841,7 +840,7 @@ static int tda9874a_getmode(struct CHIPSTATE *chip)
+ 	int dsr,nsr,mode;
+ 	int necr; /* just for debugging */
+ 
+-	mode = VIDEO_SOUND_MONO;
++	mode = V4L2_TUNER_MODE_MONO;
+ 
+ 	if(-1 == (dsr = chip_read2(chip,TDA9874A_DSR)))
+ 		return mode;
+@@ -860,21 +859,21 @@ static int tda9874a_getmode(struct CHIPSTATE *chip)
+ 		 * that sound has (temporarily) switched from NICAM to
+ 		 * mono FM (or AM) on 1st sound carrier due to high NICAM bit
+ 		 * error count. So in fact there is no stereo in this case :-(
+-		 * But changing the mode to VIDEO_SOUND_MONO would switch
++		 * But changing the mode to V4L2_TUNER_MODE_MONO would switch
+ 		 * external 4052 multiplexer in audio_hook().
+ 		 */
+ 		if(nsr & 0x02) /* NSR.S/MB=1 */
+-			mode |= VIDEO_SOUND_STEREO;
++			mode |= V4L2_TUNER_MODE_STEREO;
+ 		if(nsr & 0x01) /* NSR.D/SB=1 */
+-			mode |= VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
++			mode |= V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2;
+ 	} else {
+ 		if(dsr & 0x02) /* DSR.IDSTE=1 */
+-			mode |= VIDEO_SOUND_STEREO;
++			mode |= V4L2_TUNER_MODE_STEREO;
+ 		if(dsr & 0x04) /* DSR.IDDUA=1 */
+-			mode |= VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
++			mode |= V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2;
+ 	}
+ 
+-	v4l_dbg(1, debug, &chip->c, "tda9874a_getmode(): DSR=0x%X, NSR=0x%X, NECR=0x%X, return: %d.\n",
++	v4l_dbg(1, debug, chip->c, "tda9874a_getmode(): DSR=0x%X, NSR=0x%X, NECR=0x%X, return: %d.\n",
+ 		 dsr, nsr, necr, mode);
+ 	return mode;
+ }
+@@ -902,14 +901,14 @@ static void tda9874a_setmode(struct CHIPSTATE *chip, int mode)
+ 		int mdacosr = (tda9874a_mode) ? 0x82:0x80;
+ 
+ 		switch(mode) {
+-		case VIDEO_SOUND_MONO:
+-		case VIDEO_SOUND_STEREO:
++		case V4L2_TUNER_MODE_MONO:
++		case V4L2_TUNER_MODE_STEREO:
+ 			break;
+-		case VIDEO_SOUND_LANG1:
++		case V4L2_TUNER_MODE_LANG1:
+ 			aosr = 0x80; /* auto-select, dual A/A */
+ 			mdacosr = (tda9874a_mode) ? 0x82:0x80;
+ 			break;
+-		case VIDEO_SOUND_LANG2:
++		case V4L2_TUNER_MODE_LANG2:
+ 			aosr = 0xa0; /* auto-select, dual B/B */
+ 			mdacosr = (tda9874a_mode) ? 0x83:0x81;
+ 			break;
+@@ -920,18 +919,18 @@ static void tda9874a_setmode(struct CHIPSTATE *chip, int mode)
+ 		chip_write(chip, TDA9874A_AOSR, aosr);
+ 		chip_write(chip, TDA9874A_MDACOSR, mdacosr);
+ 
+-		v4l_dbg(1, debug, &chip->c, "tda9874a_setmode(): req. mode %d; AOSR=0x%X, MDACOSR=0x%X.\n",
++		v4l_dbg(1, debug, chip->c, "tda9874a_setmode(): req. mode %d; AOSR=0x%X, MDACOSR=0x%X.\n",
+ 			mode, aosr, mdacosr);
+ 
+ 	} else { /* dic == 0x07 */
+ 		int fmmr,aosr;
+ 
+ 		switch(mode) {
+-		case VIDEO_SOUND_MONO:
++		case V4L2_TUNER_MODE_MONO:
+ 			fmmr = 0x00; /* mono */
+ 			aosr = 0x10; /* A/A */
+ 			break;
+-		case VIDEO_SOUND_STEREO:
++		case V4L2_TUNER_MODE_STEREO:
+ 			if(tda9874a_mode) {
+ 				fmmr = 0x00;
+ 				aosr = 0x00; /* handled by NICAM auto-mute */
+@@ -940,11 +939,11 @@ static void tda9874a_setmode(struct CHIPSTATE *chip, int mode)
+ 				aosr = 0x00;
+ 			}
+ 			break;
+-		case VIDEO_SOUND_LANG1:
++		case V4L2_TUNER_MODE_LANG1:
+ 			fmmr = 0x02; /* dual */
+ 			aosr = 0x10; /* dual A/A */
+ 			break;
+-		case VIDEO_SOUND_LANG2:
++		case V4L2_TUNER_MODE_LANG2:
+ 			fmmr = 0x02; /* dual */
+ 			aosr = 0x20; /* dual B/B */
+ 			break;
+@@ -955,7 +954,7 @@ static void tda9874a_setmode(struct CHIPSTATE *chip, int mode)
+ 		chip_write(chip, TDA9874A_FMMR, fmmr);
+ 		chip_write(chip, TDA9874A_AOSR, aosr);
+ 
+-		v4l_dbg(1, debug, &chip->c, "tda9874a_setmode(): req. mode %d; FMMR=0x%X, AOSR=0x%X.\n",
++		v4l_dbg(1, debug, chip->c, "tda9874a_setmode(): req. mode %d; FMMR=0x%X, AOSR=0x%X.\n",
+ 			mode, fmmr, aosr);
+ 	}
+ }
+@@ -969,10 +968,10 @@ static int tda9874a_checkit(struct CHIPSTATE *chip)
+ 	if(-1 == (sic = chip_read2(chip,TDA9874A_SIC)))
+ 		return 0;
+ 
+-	v4l_dbg(1, debug, &chip->c, "tda9874a_checkit(): DIC=0x%X, SIC=0x%X.\n", dic, sic);
++	v4l_dbg(1, debug, chip->c, "tda9874a_checkit(): DIC=0x%X, SIC=0x%X.\n", dic, sic);
+ 
+ 	if((dic == 0x11)||(dic == 0x07)) {
+-		v4l_info(&chip->c, "found tda9874%s.\n", (dic == 0x11) ? "a":"h");
++		v4l_info(chip->c, "found tda9874%s.\n", (dic == 0x11) ? "a":"h");
+ 		tda9874a_dic = dic;	/* remember device id. */
+ 		return 1;
+ 	}
+@@ -1095,7 +1094,7 @@ static int tda8425_initialize(struct CHIPSTATE *chip)
+ 	int inputmap[4] = { /* tuner	*/ TDA8425_S1_CH2, /* radio  */ TDA8425_S1_CH1,
+ 			    /* extern	*/ TDA8425_S1_CH1, /* intern */ TDA8425_S1_OFF};
+ 
+-	if (chip->c.adapter->id == I2C_HW_B_RIVA) {
++	if (chip->c->adapter->id == I2C_HW_B_RIVA) {
+ 		memcpy (desc->inputmap, inputmap, sizeof (inputmap));
+ 	}
+ 	return 0;
+@@ -1105,20 +1104,20 @@ static void tda8425_setmode(struct CHIPSTATE *chip, int mode)
  {
- 	struct tda7432 *t = i2c_get_clientdata(client);
--	v4l_dbg(2, debug,client,"In tda7432_command\n");
--	if (debug>1)
--		v4l_i2c_print_ioctl(client,cmd);
+ 	int s1 = chip->shadow.bytes[TDA8425_S1+1] & 0xe1;
  
--	switch (cmd) {
--	/* --- v4l ioctls --- */
--	/* take care: bttv does userspace copying, we'll get a
--	   kernel pointer here... */
--
--	/* Query card - scale from TDA7432 settings to V4L settings */
--	case VIDIOCGAUDIO:
--	{
--		struct video_audio *va = arg;
+-	if (mode & VIDEO_SOUND_LANG1) {
++	if (mode & V4L2_TUNER_MODE_LANG1) {
+ 		s1 |= TDA8425_S1_ML_SOUND_A;
+ 		s1 |= TDA8425_S1_STEREO_PSEUDO;
+ 
+-	} else if (mode & VIDEO_SOUND_LANG2) {
++	} else if (mode & V4L2_TUNER_MODE_LANG2) {
+ 		s1 |= TDA8425_S1_ML_SOUND_B;
+ 		s1 |= TDA8425_S1_STEREO_PSEUDO;
+ 
+ 	} else {
+ 		s1 |= TDA8425_S1_ML_STEREO;
+ 
+-		if (mode & VIDEO_SOUND_MONO)
++		if (mode & V4L2_TUNER_MODE_MONO)
+ 			s1 |= TDA8425_S1_STEREO_MONO;
+-		if (mode & VIDEO_SOUND_STEREO)
++		if (mode & V4L2_TUNER_MODE_STEREO)
+ 			s1 |= TDA8425_S1_STEREO_SPATIAL;
+ 	}
+ 	chip_write(chip,TDA8425_S1,s1);
+@@ -1177,13 +1176,13 @@ static int ta8874z_getmode(struct CHIPSTATE *chip)
+ 	int val, mode;
+ 
+ 	val = chip_read(chip);
+-	mode = VIDEO_SOUND_MONO;
++	mode = V4L2_TUNER_MODE_MONO;
+ 	if (val & TA8874Z_B1){
+-		mode |= VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
++		mode |= V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2;
+ 	}else if (!(val & TA8874Z_B0)){
+-		mode |= VIDEO_SOUND_STEREO;
++		mode |= V4L2_TUNER_MODE_STEREO;
+ 	}
+-	/* v4l_dbg(1, debug, &chip->c, "ta8874z_getmode(): raw chip read: 0x%02x, return: 0x%02x\n", val, mode); */
++	/* v4l_dbg(1, debug, chip->c, "ta8874z_getmode(): raw chip read: 0x%02x, return: 0x%02x\n", val, mode); */
+ 	return mode;
+ }
+ 
+@@ -1196,19 +1195,19 @@ static void ta8874z_setmode(struct CHIPSTATE *chip, int mode)
+ {
+ 	int update = 1;
+ 	audiocmd *t = NULL;
+-	v4l_dbg(1, debug, &chip->c, "ta8874z_setmode(): mode: 0x%02x\n", mode);
++	v4l_dbg(1, debug, chip->c, "ta8874z_setmode(): mode: 0x%02x\n", mode);
+ 
+ 	switch(mode){
+-	case VIDEO_SOUND_MONO:
++	case V4L2_TUNER_MODE_MONO:
+ 		t = &ta8874z_mono;
+ 		break;
+-	case VIDEO_SOUND_STEREO:
++	case V4L2_TUNER_MODE_STEREO:
+ 		t = &ta8874z_stereo;
+ 		break;
+-	case VIDEO_SOUND_LANG1:
++	case V4L2_TUNER_MODE_LANG1:
+ 		t = &ta8874z_main;
+ 		break;
+-	case VIDEO_SOUND_LANG2:
++	case V4L2_TUNER_MODE_LANG2:
+ 		t = &ta8874z_sub;
+ 		break;
+ 	default:
+@@ -1462,51 +1461,55 @@ static struct CHIPDESC chiplist[] = {
+ /* ---------------------------------------------------------------------- */
+ /* i2c registration                                                       */
+ 
+-static int chip_attach(struct i2c_adapter *adap, int addr, int kind)
++static int chip_probe(struct i2c_client *client)
+ {
+ 	struct CHIPSTATE *chip;
+ 	struct CHIPDESC  *desc;
+ 
++	if (debug) {
++		printk(KERN_INFO "tvaudio: TV audio decoder + audio/video mux driver\n");
++		printk(KERN_INFO "tvaudio: known chips: ");
++		for (desc = chiplist; desc->name != NULL; desc++)
++			printk("%s%s", (desc == chiplist) ? "" : ", ", desc->name);
++		printk("\n");
++	}
++
+ 	chip = kzalloc(sizeof(*chip),GFP_KERNEL);
+ 	if (!chip)
+ 		return -ENOMEM;
+-	memcpy(&chip->c,&client_template,sizeof(struct i2c_client));
+-	chip->c.adapter = adap;
+-	chip->c.addr = addr;
+-	i2c_set_clientdata(&chip->c, chip);
++	chip->c = client;
++	i2c_set_clientdata(client, chip);
+ 
+ 	/* find description for the chip */
+-	v4l_dbg(1, debug, &chip->c, "chip found @ 0x%x\n", addr<<1);
++	v4l_dbg(1, debug, client, "chip found @ 0x%x\n", client->addr<<1);
+ 	for (desc = chiplist; desc->name != NULL; desc++) {
+ 		if (0 == *(desc->insmodopt))
+ 			continue;
+-		if (addr < desc->addr_lo ||
+-		    addr > desc->addr_hi)
++		if (client->addr < desc->addr_lo ||
++		    client->addr > desc->addr_hi)
+ 			continue;
+ 		if (desc->checkit && !desc->checkit(chip))
+ 			continue;
+ 		break;
+ 	}
+ 	if (desc->name == NULL) {
+-		v4l_dbg(1, debug, &chip->c, "no matching chip description found\n");
++		v4l_dbg(1, debug, client, "no matching chip description found\n");
+ 		return -EIO;
+ 	}
+-	v4l_info(&chip->c, "%s found @ 0x%x (%s)\n", desc->name, addr<<1, adap->name);
++	v4l_info(client, "%s found @ 0x%x (%s)\n", desc->name, client->addr<<1, client->adapter->name);
+ 	if (desc->flags) {
+-		v4l_dbg(1, debug, &chip->c, "matches:%s%s%s.\n",
++		v4l_dbg(1, debug, client, "matches:%s%s%s.\n",
+ 			(desc->flags & CHIP_HAS_VOLUME)     ? " volume"      : "",
+ 			(desc->flags & CHIP_HAS_BASSTREBLE) ? " bass/treble" : "",
+ 			(desc->flags & CHIP_HAS_INPUTSEL)   ? " audiomux"    : "");
+ 	}
+ 
+ 	/* fill required data structures */
+-	strcpy(chip->c.name, desc->name);
++	strcpy(client->name, desc->name);
+ 	chip->type = desc-chiplist;
+ 	chip->shadow.count = desc->registers+1;
+ 	chip->prevmode = -1;
+ 	chip->audmode = V4L2_TUNER_MODE_LANG1;
+-	/* register */
+-	i2c_attach_client(&chip->c);
+ 
+ 	/* initialization  */
+ 	if (desc->initialize != NULL)
+@@ -1533,28 +1536,17 @@ static int chip_attach(struct i2c_adapter *adap, int addr, int kind)
+ 		init_timer(&chip->wt);
+ 		chip->wt.function = chip_thread_wake;
+ 		chip->wt.data     = (unsigned long)chip;
+-		chip->thread = kthread_run(chip_thread, chip, chip->c.name);
++		chip->thread = kthread_run(chip_thread, chip, chip->c->name);
+ 		if (IS_ERR(chip->thread)) {
+-			v4l_warn(&chip->c, "%s: failed to create kthread\n",
+-			       chip->c.name);
++			v4l_warn(chip->c, "%s: failed to create kthread\n",
++			       chip->c->name);
+ 			chip->thread = NULL;
+ 		}
+ 	}
+ 	return 0;
+ }
+ 
+-static int chip_probe(struct i2c_adapter *adap)
+-{
+-	/* don't attach on saa7146 based cards,
+-	   because dedicated drivers are used */
+-	if ((adap->id == I2C_HW_SAA7146))
+-		return 0;
+-	if (adap->class & I2C_CLASS_TV_ANALOG)
+-		return i2c_probe(adap, &addr_data, chip_attach);
+-	return 0;
+-}
 -
--		va->flags |= VIDEO_AUDIO_VOLUME |
--			VIDEO_AUDIO_BASS |
--			VIDEO_AUDIO_TREBLE |
--			VIDEO_AUDIO_MUTABLE;
--		if (t->muted)
--			va->flags |= VIDEO_AUDIO_MUTE;
--		va->mode |= VIDEO_SOUND_STEREO;
--		/* Master volume control
--		 * V4L volume is min 0, max 65535
--		 * TDA7432 Volume:
--		 * Min (-79dB) is 0x6f
--		 * Max (+20dB) is 0x07 (630)
--		 * Max (0dB) is 0x20 (829)
--		 * (Mask out bit 7 of vol - it's for the loudness setting)
--		 */
+-static int chip_detach(struct i2c_client *client)
++static int chip_remove(struct i2c_client *client)
+ {
+ 	struct CHIPSTATE *chip = i2c_get_clientdata(client);
+ 
+@@ -1565,12 +1557,52 @@ static int chip_detach(struct i2c_client *client)
+ 		chip->thread = NULL;
+ 	}
+ 
+-	i2c_detach_client(&chip->c);
+ 	kfree(chip);
+ 	return 0;
+ }
+ 
+-static int tvaudio_set_ctrl(struct CHIPSTATE *chip, struct v4l2_control *ctrl)
++static int tvaudio_get_ctrl(struct CHIPSTATE *chip,
++			    struct v4l2_control *ctrl)
++{
++	struct CHIPDESC *desc = chiplist + chip->type;
++
 +	switch (ctrl->id) {
 +	case V4L2_CID_AUDIO_MUTE:
-+		ctrl->value=t->muted;
++		ctrl->value=chip->muted;
 +		return 0;
 +	case V4L2_CID_AUDIO_VOLUME:
- 		if (!maxvol){  /* max +20db */
--			va->volume = ( 0x6f - (t->volume & 0x7F) ) * 630;
-+			ctrl->value = ( 0x6f - (t->volume & 0x7F) ) * 630;
- 		} else {       /* max 0db   */
--			va->volume = ( 0x6f - (t->volume & 0x7F) ) * 829;
-+			ctrl->value = ( 0x6f - (t->volume & 0x7F) ) * 829;
- 		}
--
--		/* Balance depends on L,R attenuation
--		 * V4L balance is 0 to 65535, middle is 32768
--		 * TDA7432 attenuation: min (0dB) is 0, max (-37.5dB) is 0x1f
--		 * to scale up to V4L numbers, mult by 1057
--		 * attenuation exists for lf, lr, rf, rr
--		 * we use only lf and rf (front channels)
--		 */
--
++		if (!desc->flags & CHIP_HAS_VOLUME)
++			break;
++		ctrl->value = max(chip->left,chip->right);
 +		return 0;
 +	case V4L2_CID_AUDIO_BALANCE:
 +	{
- 		if ( (t->lf) < (t->rf) )
- 			/* right is attenuated, balance shifted left */
--			va->balance = (32768 - 1057*(t->rf));
-+			ctrl->value = (32768 - 1057*(t->rf));
- 		else
- 			/* left is attenuated, balance shifted right */
--			va->balance = (32768 + 1057*(t->lf));
--
-+			ctrl->value = (32768 + 1057*(t->lf));
++		int volume;
++		if (!desc->flags & CHIP_HAS_VOLUME)
++			break;
++		volume = max(chip->left,chip->right);
++		if (volume)
++			ctrl->value=(32768*min(chip->left,chip->right))/volume;
++		else
++			ctrl->value=32768;
 +		return 0;
 +	}
 +	case V4L2_CID_AUDIO_BASS:
-+	{
- 		/* Bass/treble 4 bits each */
--		va->bass=t->bass;
--		if(va->bass >= 0x8)
--			va->bass = ~(va->bass - 0x8) & 0xf;
--		va->bass = (va->bass << 12)+(va->bass << 8)+(va->bass << 4)+(va->bass);
--		va->treble=t->treble;
--		if(va->treble >= 0x8)
--			va->treble = ~(va->treble - 0x8) & 0xf;
--		va->treble = (va->treble << 12)+(va->treble << 8)+(va->treble << 4)+(va->treble);
--
--		break; /* VIDIOCGAUDIO case */
-+		int bass=t->bass;
-+		if(bass >= 0x8)
-+			bass = ~(bass - 0x8) & 0xf;
-+		ctrl->value = (bass << 12)+(bass << 8)+(bass << 4)+(bass);
++		if (desc->flags & CHIP_HAS_BASSTREBLE)
++			break;
++		ctrl->value = chip->bass;
 +		return 0;
- 	}
--
--	/* Set card - scale from V4L settings to TDA7432 settings */
--	case VIDIOCSAUDIO:
 +	case V4L2_CID_AUDIO_TREBLE:
- 	{
--		struct video_audio *va = arg;
-+		int treble=t->treble;
-+		if(treble >= 0x8)
-+			treble = ~(treble - 0x8) & 0xf;
-+		ctrl->value = (treble << 12)+(treble << 8)+(treble << 4)+(treble);
++		if (desc->flags & CHIP_HAS_BASSTREBLE)
++			return -EINVAL;
++		ctrl->value = chip->treble;
 +		return 0;
 +	}
-+	}
 +	return -EINVAL;
 +}
- 
--		if(va->flags & VIDEO_AUDIO_VOLUME){
--			if(!maxvol){ /* max +20db */
--				t->volume = 0x6f - ((va->volume)/630);
--			} else {    /* max 0db   */
--				t->volume = 0x6f - ((va->volume)/829);
--			}
-+static int tda7432_set_ctrl(struct i2c_client *client,
++
++static int tvaudio_set_ctrl(struct CHIPSTATE *chip,
 +			    struct v4l2_control *ctrl)
-+{
-+	struct tda7432 *t = i2c_get_clientdata(client);
+ {
+ 	struct CHIPDESC *desc = chiplist + chip->type;
  
-+	switch (ctrl->id) {
-+	case V4L2_CID_AUDIO_MUTE:
-+		t->muted=ctrl->value;
-+		break;
+@@ -1584,11 +1616,60 @@ static int tvaudio_set_ctrl(struct CHIPSTATE *chip, struct v4l2_control *ctrl)
+ 		else
+ 			chip_write_masked(chip,desc->inputreg,
+ 					desc->inputmap[chip->input],desc->inputmask);
+-		break;
+-	default:
+-		return -EINVAL;
++		return 0;
 +	case V4L2_CID_AUDIO_VOLUME:
-+		if(!maxvol){ /* max +20db */
-+			t->volume = 0x6f - ((ctrl->value)/630);
-+		} else {    /* max 0db   */
-+			t->volume = 0x6f - ((ctrl->value)/829);
-+		}
- 		if (loudness)		/* Turn on the loudness bit */
- 			t->volume |= TDA7432_LD_ON;
- 
--			tda7432_write(client,TDA7432_VL, t->volume);
--		}
--
--		if(va->flags & VIDEO_AUDIO_BASS)
--		{
--			t->bass = va->bass >> 12;
--			if(t->bass>= 0x8)
--					t->bass = (~t->bass & 0xf) + 0x8 ;
--		}
--		if(va->flags & VIDEO_AUDIO_TREBLE)
--		{
--			t->treble= va->treble >> 12;
--			if(t->treble>= 0x8)
--					t->treble = (~t->treble & 0xf) + 0x8 ;
--		}
--		if(va->flags & (VIDEO_AUDIO_TREBLE| VIDEO_AUDIO_BASS))
--			tda7432_write(client,TDA7432_TN, 0x10 | (t->bass << 4) | t->treble );
--
--		if(va->flags & VIDEO_AUDIO_BALANCE)	{
--		if (va->balance < 32768)
--		{
-+		tda7432_write(client,TDA7432_VL, t->volume);
++	{
++		int volume,balance;
++
++		if (!desc->flags & CHIP_HAS_VOLUME)
++			break;
++
++		volume = max(chip->left,chip->right);
++		if (volume)
++			balance=(32768*min(chip->left,chip->right))/volume;
++		else
++			balance=32768;
++
++		volume=ctrl->value;
++		chip->left = (min(65536 - balance,32768) * volume) / 32768;
++		chip->right = (min(balance,volume *(__u16)32768)) / 32768;
++
++		chip_write(chip,desc->leftreg,desc->volfunc(chip->left));
++		chip_write(chip,desc->rightreg,desc->volfunc(chip->right));
++
 +		return 0;
+ 	}
+-	return 0;
 +	case V4L2_CID_AUDIO_BALANCE:
-+		if (ctrl->value < 32768) {
- 			/* shifted to left, attenuate right */
--			t->rr = (32768 - va->balance)/1057;
-+			t->rr = (32768 - ctrl->value)/1057;
- 			t->rf = t->rr;
- 			t->lr = TDA7432_ATTEN_0DB;
- 			t->lf = TDA7432_ATTEN_0DB;
--		}
--		else if(va->balance > 32769)
--		{
-+		} else if(ctrl->value > 32769) {
- 			/* shifted to right, attenuate left */
--			t->lf = (va->balance - 32768)/1057;
-+			t->lf = (ctrl->value - 32768)/1057;
- 			t->lr = t->lf;
- 			t->rr = TDA7432_ATTEN_0DB;
- 			t->rf = TDA7432_ATTEN_0DB;
--		}
--		else
--		{
-+		} else {
- 			/* centered */
- 			t->rr = TDA7432_ATTEN_0DB;
- 			t->rf = TDA7432_ATTEN_0DB;
- 			t->lf = TDA7432_ATTEN_0DB;
- 			t->lr = TDA7432_ATTEN_0DB;
- 		}
--		}
-+		break;
-+	case V4L2_CID_AUDIO_BASS:
-+		t->bass = ctrl->value >> 12;
-+		if(t->bass>= 0x8)
-+				t->bass = (~t->bass & 0xf) + 0x8 ;
++	{
++		int volume, balance;
++		if (!desc->flags & CHIP_HAS_VOLUME)
++			break;
 +
-+		tda7432_write(client,TDA7432_TN, 0x10 | (t->bass << 4) | t->treble );
-+		return 0;
-+	case V4L2_CID_AUDIO_TREBLE:
-+		t->treble= ctrl->value >> 12;
-+		if(t->treble>= 0x8)
-+				t->treble = (~t->treble & 0xf) + 0x8 ;
++		volume = max(chip->left,chip->right);
++		balance = ctrl->value;
++
++		chip_write(chip,desc->leftreg,desc->volfunc(chip->left));
++		chip_write(chip,desc->rightreg,desc->volfunc(chip->right));
 +
-+		tda7432_write(client,TDA7432_TN, 0x10 | (t->bass << 4) | t->treble );
 +		return 0;
-+	default:
-+		return -EINVAL;
 +	}
- 
--		t->muted=(va->flags & VIDEO_AUDIO_MUTE);
--		if (t->muted)
--		{
--			/* Mute & update balance*/
--			tda7432_write(client,TDA7432_LF, t->lf | TDA7432_MUTE);
--			tda7432_write(client,TDA7432_LR, t->lr | TDA7432_MUTE);
--			tda7432_write(client,TDA7432_RF, t->rf | TDA7432_MUTE);
--			tda7432_write(client,TDA7432_RR, t->rr | TDA7432_MUTE);
--		} else {
--			tda7432_write(client,TDA7432_LF, t->lf);
--			tda7432_write(client,TDA7432_LR, t->lr);
--			tda7432_write(client,TDA7432_RF, t->rf);
--			tda7432_write(client,TDA7432_RR, t->rr);
--		}
-+	/* Used for both mute and balance changes */
-+	if (t->muted)
-+	{
-+		/* Mute & update balance*/
-+		tda7432_write(client,TDA7432_LF, t->lf | TDA7432_MUTE);
-+		tda7432_write(client,TDA7432_LR, t->lr | TDA7432_MUTE);
-+		tda7432_write(client,TDA7432_RF, t->rf | TDA7432_MUTE);
-+		tda7432_write(client,TDA7432_RR, t->rr | TDA7432_MUTE);
-+	} else {
-+		tda7432_write(client,TDA7432_LF, t->lf);
-+		tda7432_write(client,TDA7432_LR, t->lr);
-+		tda7432_write(client,TDA7432_RF, t->rf);
-+		tda7432_write(client,TDA7432_RR, t->rr);
++	case V4L2_CID_AUDIO_BASS:
++		if (desc->flags & CHIP_HAS_BASSTREBLE)
++			break;
++		chip->bass = ctrl->value;
++		chip_write(chip,desc->bassreg,desc->bassfunc(chip->bass));
++
++		return 0;
++	case V4L2_CID_AUDIO_TREBLE:
++		if (desc->flags & CHIP_HAS_BASSTREBLE)
++			return -EINVAL;
++
++		chip->treble = ctrl->value;
++		chip_write(chip,desc->treblereg,desc->treblefunc(chip->treble));
++
++		return 0;
 +	}
-+	return 0;
-+}
++	return -EINVAL;
+ }
+ 
+ 
+@@ -1601,7 +1682,7 @@ static int chip_command(struct i2c_client *client,
+ 	struct CHIPSTATE *chip = i2c_get_clientdata(client);
+ 	struct CHIPDESC  *desc = chiplist + chip->type;
+ 
+-	v4l_dbg(1, debug, &chip->c, "%s: chip_command 0x%x\n", chip->c.name, cmd);
++	v4l_dbg(1, debug, chip->c, "%s: chip_command 0x%x\n", chip->c->name, cmd);
  
+ 	switch (cmd) {
+ 	case AUDC_SET_RADIO:
+@@ -1609,67 +1690,36 @@ static int chip_command(struct i2c_client *client,
+ 		chip->watch_stereo = 0;
+ 		/* del_timer(&chip->wt); */
+ 		break;
+-
+ 	/* --- v4l ioctls --- */
+ 	/* take care: bttv does userspace copying, we'll get a
+ 	kernel pointer here... */
+-	case VIDIOCGAUDIO:
+-	{
+-		struct video_audio *va = arg;
+-
+-		if (desc->flags & CHIP_HAS_VOLUME) {
+-			va->flags  |= VIDEO_AUDIO_VOLUME;
+-			va->volume  = max(chip->left,chip->right);
+-			if (va->volume)
+-				va->balance = (32768*min(chip->left,chip->right))/
+-					va->volume;
+-			else
+-				va->balance = 32768;
+-		}
+-		if (desc->flags & CHIP_HAS_BASSTREBLE) {
+-			va->flags |= VIDEO_AUDIO_BASS | VIDEO_AUDIO_TREBLE;
+-			va->bass   = chip->bass;
+-			va->treble = chip->treble;
+-		}
+-		if (!chip->radio) {
+-			if (desc->getmode)
+-				va->mode = desc->getmode(chip);
+-			else
+-				va->mode = VIDEO_SOUND_MONO;
+-		}
 -		break;
-+static int tda7432_command(struct i2c_client *client,
-+			   unsigned int cmd, void *arg)
-+{
-+	v4l_dbg(2, debug,client,"In tda7432_command\n");
-+	if (debug>1)
-+		v4l_i2c_print_ioctl(client,cmd);
-+
-+	switch (cmd) {
-+	/* --- v4l ioctls --- */
-+	/* take care: bttv does userspace copying, we'll get a
-+	   kernel pointer here... */
+-	}
+-
+-	case VIDIOCSAUDIO:
 +	case VIDIOC_QUERYCTRL:
-+	{
+ 	{
+-		struct video_audio *va = arg;
+-
+-		if (desc->flags & CHIP_HAS_VOLUME) {
+-			chip->left = (min(65536 - va->balance,32768) *
+-				va->volume) / 32768;
+-			chip->right = (min(va->balance,(__u16)32768) *
+-				va->volume) / 32768;
+-			chip_write(chip,desc->leftreg,desc->volfunc(chip->left));
+-			chip_write(chip,desc->rightreg,desc->volfunc(chip->right));
+-		}
+-		if (desc->flags & CHIP_HAS_BASSTREBLE) {
+-			chip->bass = va->bass;
+-			chip->treble = va->treble;
+-			chip_write(chip,desc->bassreg,desc->bassfunc(chip->bass));
+-			chip_write(chip,desc->treblereg,desc->treblefunc(chip->treble));
+-		}
+-		if (desc->setmode && va->mode) {
+-			chip->watch_stereo = 0;
+-			/* del_timer(&chip->wt); */
+-			chip->mode = va->mode;
+-			desc->setmode(chip,va->mode);
 +		struct v4l2_queryctrl *qc = arg;
 +
 +		switch (qc->id) {
 +			case V4L2_CID_AUDIO_MUTE:
++				break;
 +			case V4L2_CID_AUDIO_VOLUME:
 +			case V4L2_CID_AUDIO_BALANCE:
++				if (!desc->flags & CHIP_HAS_VOLUME)
++					return -EINVAL;
++				break;
 +			case V4L2_CID_AUDIO_BASS:
 +			case V4L2_CID_AUDIO_TREBLE:
++				if (desc->flags & CHIP_HAS_BASSTREBLE)
++					return -EINVAL;
++				break;
 +			default:
 +				return -EINVAL;
-+		}
+ 		}
+-		break;
 +		return v4l2_ctrl_query_fill_std(qc);
-+	}
-+	case VIDIOC_S_CTRL:
-+		return tda7432_set_ctrl(client, arg);
+ 	}
+-
+ 	case VIDIOC_S_CTRL:
+ 		return tvaudio_set_ctrl(chip, arg);
  
--	} /* end of VIDEOCSAUDIO case */
 +	case VIDIOC_G_CTRL:
-+		return tda7432_get_ctrl(client, arg);
- 
- 	} /* end of (cmd) switch */
- 
-diff --git a/drivers/media/video/tda8290.c b/drivers/media/video/tda8290.c
-index 0e5cf45..55bc89a 100644
---- a/drivers/media/video/tda8290.c
-+++ b/drivers/media/video/tda8290.c
-@@ -25,12 +25,14 @@
- #include <linux/videodev.h>
- #include "tuner-i2c.h"
- #include "tda8290.h"
-+#include "tda827x.h"
-+#include "tda18271.h"
- 
--static int debug = 0;
-+static int debug;
- module_param(debug, int, 0644);
- MODULE_PARM_DESC(debug, "enable verbose debug messages");
- 
--#define PREFIX "tda8290 "
-+#define PREFIX "tda8290"
- 
- /* ---------------------------------------------------------------------- */
- 
-@@ -38,345 +40,71 @@ struct tda8290_priv {
- 	struct tuner_i2c_props i2c_props;
- 
- 	unsigned char tda8290_easy_mode;
--	unsigned char tda827x_lpsel;
--	unsigned char tda827x_addr;
--	unsigned char tda827x_ver;
--	unsigned int sgIF;
--
--	u32 frequency;
--
--	unsigned int *lna_cfg;
--	int (*tuner_callback) (void *dev, int command,int arg);
--};
--
--/* ---------------------------------------------------------------------- */
--
--struct tda827x_data {
--	u32 lomax;
--	u8  spd;
--	u8  bs;
--	u8  bp;
--	u8  cp;
--	u8  gc3;
--	u8 div1p5;
--};
--
--     /* Note lomax entry is lo / 62500 */
--
--static struct tda827x_data tda827x_analog[] = {
--	{ .lomax =   992, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 1}, /*  62 MHz */
--	{ .lomax =  1056, .spd = 3, .bs = 3, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 1}, /*  66 MHz */
--	{ .lomax =  1216, .spd = 3, .bs = 1, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 0}, /*  76 MHz */
--	{ .lomax =  1344, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 0}, /*  84 MHz */
--	{ .lomax =  1488, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 1, .div1p5 = 0}, /*  93 MHz */
--	{ .lomax =  1568, .spd = 3, .bs = 3, .bp = 0, .cp = 0, .gc3 = 1, .div1p5 = 0}, /*  98 MHz */
--	{ .lomax =  1744, .spd = 3, .bs = 3, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 109 MHz */
--	{ .lomax =  1968, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 1}, /* 123 MHz */
--	{ .lomax =  2128, .spd = 2, .bs = 3, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 1}, /* 133 MHz */
--	{ .lomax =  2416, .spd = 2, .bs = 1, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 151 MHz */
--	{ .lomax =  2464, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 154 MHz */
--	{ .lomax =  2896, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 0, .div1p5 = 0}, /* 181 MHz */
--	{ .lomax =  2960, .spd = 2, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 185 MHz */
--	{ .lomax =  3472, .spd = 2, .bs = 3, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 217 MHz */
--	{ .lomax =  3904, .spd = 1, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 1}, /* 244 MHz */
--	{ .lomax =  4240, .spd = 1, .bs = 3, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 1}, /* 265 MHz */
--	{ .lomax =  4832, .spd = 1, .bs = 1, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 302 MHz */
--	{ .lomax =  5184, .spd = 1, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 324 MHz */
--	{ .lomax =  5920, .spd = 1, .bs = 2, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 370 MHz */
--	{ .lomax =  7264, .spd = 1, .bs = 3, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 454 MHz */
--	{ .lomax =  7888, .spd = 0, .bs = 2, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 1}, /* 493 MHz */
--	{ .lomax =  8480, .spd = 0, .bs = 3, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 1}, /* 530 MHz */
--	{ .lomax =  8864, .spd = 0, .bs = 1, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 554 MHz */
--	{ .lomax =  9664, .spd = 0, .bs = 1, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0}, /* 604 MHz */
--	{ .lomax = 11088, .spd = 0, .bs = 2, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0}, /* 696 MHz */
--	{ .lomax = 11840, .spd = 0, .bs = 2, .bp = 4, .cp = 1, .gc3 = 0, .div1p5 = 0}, /* 740 MHz */
--	{ .lomax = 13120, .spd = 0, .bs = 3, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0}, /* 820 MHz */
--	{ .lomax = 13840, .spd = 0, .bs = 3, .bp = 4, .cp = 1, .gc3 = 0, .div1p5 = 0}, /* 865 MHz */
--	{ .lomax =     0, .spd = 0, .bs = 0, .bp = 0, .cp = 0, .gc3 = 0, .div1p5 = 0}  /* End      */
--};
--
--static void tda827x_set_analog_params(struct dvb_frontend *fe,
--				      struct analog_parameters *params)
--{
--	unsigned char tuner_reg[8];
--	unsigned char reg2[2];
--	u32 N;
--	int i;
--	struct tda8290_priv *priv = fe->tuner_priv;
--	struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags = 0};
--	unsigned int freq = params->frequency;
++		return tvaudio_get_ctrl(chip, arg);
+ 	case VIDIOC_INT_G_AUDIO_ROUTING:
+ 	{
+ 		struct v4l2_routing *rt = arg;
+@@ -1678,7 +1728,6 @@ static int chip_command(struct i2c_client *client,
+ 		rt->output = 0;
+ 		break;
+ 	}
 -
--	if (params->mode == V4L2_TUNER_RADIO)
--		freq = freq / 1000;
+ 	case VIDIOC_INT_S_AUDIO_ROUTING:
+ 	{
+ 		struct v4l2_routing *rt = arg;
+@@ -1693,7 +1742,6 @@ static int chip_command(struct i2c_client *client,
+ 				desc->inputmap[chip->input], desc->inputmask);
+ 		break;
+ 	}
 -
--	N = freq + priv->sgIF;
--	i = 0;
--	while (tda827x_analog[i].lomax < N) {
--		if(tda827x_analog[i + 1].lomax == 0)
+ 	case VIDIOC_S_TUNER:
+ 	{
+ 		struct v4l2_tuner *vt = arg;
+@@ -1703,17 +1751,13 @@ static int chip_command(struct i2c_client *client,
+ 			break;
+ 		switch (vt->audmode) {
+ 		case V4L2_TUNER_MODE_MONO:
+-			mode = VIDEO_SOUND_MONO;
 -			break;
--		i++;
--	}
--
--	N = N << tda827x_analog[i].spd;
--
--	tuner_reg[0] = 0;
--	tuner_reg[1] = (unsigned char)(N>>8);
--	tuner_reg[2] = (unsigned char) N;
--	tuner_reg[3] = 0x40;
--	tuner_reg[4] = 0x52 + (priv->tda827x_lpsel << 5);
--	tuner_reg[5] = (tda827x_analog[i].spd   << 6) + (tda827x_analog[i].div1p5 <<5) +
--		       (tda827x_analog[i].bs     <<3) +  tda827x_analog[i].bp;
--	tuner_reg[6] = 0x8f + (tda827x_analog[i].gc3 << 4);
--	tuner_reg[7] = 0x8f;
--
--	msg.buf = tuner_reg;
--	msg.len = 8;
--	i2c_transfer(priv->i2c_props.adap, &msg, 1);
--
--	msg.buf= reg2;
--	msg.len = 2;
--	reg2[0] = 0x80;
--	reg2[1] = 0;
--	i2c_transfer(priv->i2c_props.adap, &msg, 1);
--
--	reg2[0] = 0x60;
--	reg2[1] = 0xbf;
--	i2c_transfer(priv->i2c_props.adap, &msg, 1);
--
--	reg2[0] = 0x30;
--	reg2[1] = tuner_reg[4] + 0x80;
--	i2c_transfer(priv->i2c_props.adap, &msg, 1);
--
--	msleep(1);
--	reg2[0] = 0x30;
--	reg2[1] = tuner_reg[4] + 4;
--	i2c_transfer(priv->i2c_props.adap, &msg, 1);
--
--	msleep(1);
--	reg2[0] = 0x30;
--	reg2[1] = tuner_reg[4];
--	i2c_transfer(priv->i2c_props.adap, &msg, 1);
--
--	msleep(550);
--	reg2[0] = 0x30;
--	reg2[1] = (tuner_reg[4] & 0xfc) + tda827x_analog[i].cp ;
--	i2c_transfer(priv->i2c_props.adap, &msg, 1);
--
--	reg2[0] = 0x60;
--	reg2[1] = 0x3f;
--	i2c_transfer(priv->i2c_props.adap, &msg, 1);
--
--	reg2[0] = 0x80;
--	reg2[1] = 0x08;   // Vsync en
--	i2c_transfer(priv->i2c_props.adap, &msg, 1);
--}
- 
--static void tda827x_agcf(struct dvb_frontend *fe)
--{
--	struct tda8290_priv *priv = fe->tuner_priv;
--	unsigned char data[] = {0x80, 0x0c};
--	struct i2c_msg msg = {.addr = priv->tda827x_addr, .buf = data,
--			      .flags = 0, .len = 2};
--	i2c_transfer(priv->i2c_props.adap, &msg, 1);
--}
--
--/* ---------------------------------------------------------------------- */
-+	unsigned char tda827x_addr;
- 
--struct tda827xa_data {
--	u32 lomax;
--	u8  svco;
--	u8  spd;
--	u8  scr;
--	u8  sbs;
--	u8  gc3;
--};
-+	unsigned char ver;
-+#define TDA8290   1
-+#define TDA8295   2
-+#define TDA8275   4
-+#define TDA8275A  8
-+#define TDA18271 16
- 
--static struct tda827xa_data tda827xa_analog[] = {
--	{ .lomax =   910, .svco = 3, .spd = 4, .scr = 0, .sbs = 0, .gc3 = 3},  /*  56.875 MHz */
--	{ .lomax =  1076, .svco = 0, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3},  /*  67.25 MHz */
--	{ .lomax =  1300, .svco = 1, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3},  /*  81.25 MHz */
--	{ .lomax =  1560, .svco = 2, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3},  /*  97.5  MHz */
--	{ .lomax =  1820, .svco = 3, .spd = 3, .scr = 0, .sbs = 1, .gc3 = 1},  /* 113.75 MHz */
--	{ .lomax =  2152, .svco = 0, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},  /* 134.5 MHz */
--	{ .lomax =  2464, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},  /* 154   MHz */
--	{ .lomax =  2600, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},  /* 162.5 MHz */
--	{ .lomax =  2928, .svco = 2, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},  /* 183   MHz */
--	{ .lomax =  3120, .svco = 2, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 1},  /* 195   MHz */
--	{ .lomax =  3640, .svco = 3, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 3},  /* 227.5 MHz */
--	{ .lomax =  4304, .svco = 0, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 3},  /* 269   MHz */
--	{ .lomax =  5200, .svco = 1, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 1},  /* 325   MHz */
--	{ .lomax =  6240, .svco = 2, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 3},  /* 390   MHz */
--	{ .lomax =  7280, .svco = 3, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 3},  /* 455   MHz */
--	{ .lomax =  8320, .svco = 0, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1},  /* 520   MHz */
--	{ .lomax =  8608, .svco = 0, .spd = 0, .scr = 1, .sbs = 3, .gc3 = 1},  /* 538   MHz */
--	{ .lomax =  8864, .svco = 1, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1},  /* 554   MHz */
--	{ .lomax =  9920, .svco = 1, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0},  /* 620   MHz */
--	{ .lomax = 10400, .svco = 1, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0},  /* 650   MHz */
--	{ .lomax = 11200, .svco = 2, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0},  /* 700   MHz */
--	{ .lomax = 12480, .svco = 2, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0},  /* 780   MHz */
--	{ .lomax = 13120, .svco = 3, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0},  /* 820   MHz */
--	{ .lomax = 13920, .svco = 3, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0},  /* 870   MHz */
--	{ .lomax = 14576, .svco = 3, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 0},  /* 911   MHz */
--	{ .lomax =     0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0}   /* End */
-+	struct tda827x_config cfg;
- };
- 
--static void tda827xa_lna_gain(struct dvb_frontend *fe, int high,
--			      struct analog_parameters *params)
--{
--	struct tda8290_priv *priv = fe->tuner_priv;
--	unsigned char buf[] = {0x22, 0x01};
--	int arg;
--	struct i2c_msg msg = {.addr = priv->i2c_props.addr, .flags = 0, .buf = buf, .len = sizeof(buf)};
--
--	if ((priv->lna_cfg == NULL)  || (priv->tuner_callback == NULL))
--	    return;
+ 		case V4L2_TUNER_MODE_STEREO:
+-		case V4L2_TUNER_MODE_LANG1_LANG2:
+-			mode = VIDEO_SOUND_STEREO;
+-			break;
+ 		case V4L2_TUNER_MODE_LANG1:
+-			mode = VIDEO_SOUND_LANG1;
+-			break;
+ 		case V4L2_TUNER_MODE_LANG2:
+-			mode = VIDEO_SOUND_LANG2;
++			mode = vt->audmode;
++			break;
++		case V4L2_TUNER_MODE_LANG1_LANG2:
++			mode = V4L2_TUNER_MODE_STEREO;
+ 			break;
+ 		default:
+ 			return -EINVAL;
+@@ -1728,11 +1772,10 @@ static int chip_command(struct i2c_client *client,
+ 		}
+ 		break;
+ 	}
 -
--	if (*priv->lna_cfg) {
--		if (high)
--			tuner_dbg("setting LNA to high gain\n");
--		else
--			tuner_dbg("setting LNA to low gain\n");
--	}
--	switch (*priv->lna_cfg) {
--	case 0: /* no LNA */
--		break;
--	case 1: /* switch is GPIO 0 of tda8290 */
--	case 2:
--		/* turn Vsync on */
--		if (params->std & V4L2_STD_MN)
--			arg = 1;
--		else
--			arg = 0;
--		if (priv->tuner_callback)
--			priv->tuner_callback(priv->i2c_props.adap->algo_data, 1, arg);
--		buf[1] = high ? 0 : 1;
--		if (*priv->lna_cfg == 2)
--			buf[1] = high ? 1 : 0;
--		i2c_transfer(priv->i2c_props.adap, &msg, 1);
--		break;
--	case 3: /* switch with GPIO of saa713x */
--		if (priv->tuner_callback)
--			priv->tuner_callback(priv->i2c_props.adap->algo_data, 0, high);
--		break;
--	}
--}
-+/*---------------------------------------------------------------------*/
- 
--static void tda827xa_set_analog_params(struct dvb_frontend *fe,
--				       struct analog_parameters *params)
-+static int tda8290_i2c_bridge(struct dvb_frontend *fe, int close)
- {
--	unsigned char tuner_reg[11];
--	u32 N;
--	int i;
--	struct tda8290_priv *priv = fe->tuner_priv;
--	struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags = 0, .buf = tuner_reg};
--	unsigned int freq = params->frequency;
-+	struct tda8290_priv *priv = fe->analog_demod_priv;
+ 	case VIDIOC_G_TUNER:
+ 	{
+ 		struct v4l2_tuner *vt = arg;
+-		int mode = VIDEO_SOUND_MONO;
++		int mode = V4L2_TUNER_MODE_MONO;
  
--	tda827xa_lna_gain(fe, 1, params);
--	msleep(10);
--
--	if (params->mode == V4L2_TUNER_RADIO)
--		freq = freq / 1000;
-+	unsigned char  enable[2] = { 0x21, 0xC0 };
-+	unsigned char disable[2] = { 0x21, 0x00 };
-+	unsigned char *msg;
+ 		if (chip->radio)
+ 			break;
+@@ -1744,30 +1787,26 @@ static int chip_command(struct i2c_client *client,
+ 		if (desc->getmode)
+ 			mode = desc->getmode(chip);
  
--	N = freq + priv->sgIF;
--	i = 0;
--	while (tda827xa_analog[i].lomax < N) {
--		if(tda827xa_analog[i + 1].lomax == 0)
--			break;
--		i++;
-+	if (close) {
-+		msg = enable;
-+		tuner_i2c_xfer_send(&priv->i2c_props, msg, 2);
-+		/* let the bridge stabilize */
-+		msleep(20);
-+	} else {
-+		msg = disable;
-+		tuner_i2c_xfer_send(&priv->i2c_props, msg, 2);
+-		if (mode & VIDEO_SOUND_MONO)
++		if (mode & V4L2_TUNER_MODE_MONO)
+ 			vt->rxsubchans |= V4L2_TUNER_SUB_MONO;
+-		if (mode & VIDEO_SOUND_STEREO)
++		if (mode & V4L2_TUNER_MODE_STEREO)
+ 			vt->rxsubchans |= V4L2_TUNER_SUB_STEREO;
+ 		/* Note: for SAP it should be mono/lang2 or stereo/lang2.
+ 		   When this module is converted fully to v4l2, then this
+ 		   should change for those chips that can detect SAP. */
+-		if (mode & VIDEO_SOUND_LANG1)
++		if (mode & V4L2_TUNER_MODE_LANG1)
+ 			vt->rxsubchans = V4L2_TUNER_SUB_LANG1 |
+ 					 V4L2_TUNER_SUB_LANG2;
+ 		break;
  	}
- 
--	N = N << tda827xa_analog[i].spd;
--
--	tuner_reg[0] = 0;
--	tuner_reg[1] = (unsigned char)(N>>8);
--	tuner_reg[2] = (unsigned char) N;
--	tuner_reg[3] = 0;
--	tuner_reg[4] = 0x16;
--	tuner_reg[5] = (tda827xa_analog[i].spd << 5) + (tda827xa_analog[i].svco << 3) +
--			tda827xa_analog[i].sbs;
--	tuner_reg[6] = 0x8b + (tda827xa_analog[i].gc3 << 4);
--	tuner_reg[7] = 0x1c;
--	tuner_reg[8] = 4;
--	tuner_reg[9] = 0x20;
--	tuner_reg[10] = 0x00;
--	msg.len = 11;
--	i2c_transfer(priv->i2c_props.adap, &msg, 1);
--
--	tuner_reg[0] = 0x90;
--	tuner_reg[1] = 0xff;
--	tuner_reg[2] = 0xe0;
--	tuner_reg[3] = 0;
--	tuner_reg[4] = 0x99 + (priv->tda827x_lpsel << 1);
--	msg.len = 5;
--	i2c_transfer(priv->i2c_props.adap, &msg, 1);
--
--	tuner_reg[0] = 0xa0;
--	tuner_reg[1] = 0xc0;
--	msg.len = 2;
--	i2c_transfer(priv->i2c_props.adap, &msg, 1);
--
--	tuner_reg[0] = 0x30;
--	tuner_reg[1] = 0x10 + tda827xa_analog[i].scr;
--	i2c_transfer(priv->i2c_props.adap, &msg, 1);
 -
--	msg.flags = I2C_M_RD;
--	i2c_transfer(priv->i2c_props.adap, &msg, 1);
--	msg.flags = 0;
--	tuner_reg[1] >>= 4;
--	tuner_dbg("AGC2 gain is: %d\n", tuner_reg[1]);
--	if (tuner_reg[1] < 1)
--		tda827xa_lna_gain(fe, 0, params);
+-	case VIDIOCSCHAN:
+ 	case VIDIOC_S_STD:
+ 		chip->radio = 0;
+ 		break;
 -
--	msleep(100);
--	tuner_reg[0] = 0x60;
--	tuner_reg[1] = 0x3c;
--	i2c_transfer(priv->i2c_props.adap, &msg, 1);
+-	case VIDIOCSFREQ:
+ 	case VIDIOC_S_FREQUENCY:
+ 		chip->mode = 0; /* automatic */
+ 		if (desc->checkmode) {
+-			desc->setmode(chip,VIDEO_SOUND_MONO);
+-			if (chip->prevmode != VIDEO_SOUND_MONO)
++			desc->setmode(chip,V4L2_TUNER_MODE_MONO);
++			if (chip->prevmode != V4L2_TUNER_MODE_MONO)
+ 				chip->prevmode = -1; /* reset previous mode */
+ 			mod_timer(&chip->wt, jiffies+msecs_to_jiffies(2000));
+ 			/* the thread will call checkmode() later */
+@@ -1780,44 +1819,25 @@ static int chip_command(struct i2c_client *client,
+ 	return 0;
+ }
+ 
+-static struct i2c_driver driver = {
+-	.driver = {
+-		.name    = "tvaudio",
+-	},
+-	.id              = I2C_DRIVERID_TVAUDIO,
+-	.attach_adapter  = chip_probe,
+-	.detach_client   = chip_detach,
+-	.command         = chip_command,
+-};
 -
--	msleep(163);
--	tuner_reg[0] = 0x50;
--	tuner_reg[1] = 0x8f + (tda827xa_analog[i].gc3 << 4);
--	i2c_transfer(priv->i2c_props.adap, &msg, 1);
+-static struct i2c_client client_template =
++static int chip_legacy_probe(struct i2c_adapter *adap)
+ {
+-	.name       = "(unset)",
+-	.driver     = &driver,
+-};
 -
--	tuner_reg[0] = 0x80;
--	tuner_reg[1] = 0x28;
--	i2c_transfer(priv->i2c_props.adap, &msg, 1);
+-static int __init audiochip_init_module(void)
+-{
+-	struct CHIPDESC  *desc;
 -
--	tuner_reg[0] = 0xb0;
--	tuner_reg[1] = 0x01;
--	i2c_transfer(priv->i2c_props.adap, &msg, 1);
+-	if (debug) {
+-		printk(KERN_INFO "tvaudio: TV audio decoder + audio/video mux driver\n");
+-		printk(KERN_INFO "tvaudio: known chips: ");
+-		for (desc = chiplist; desc->name != NULL; desc++)
+-			printk("%s%s", (desc == chiplist) ? "" : ", ", desc->name);
+-		printk("\n");
+-	}
 -
--	tuner_reg[0] = 0xc0;
--	tuner_reg[1] = 0x19 + (priv->tda827x_lpsel << 1);
--	i2c_transfer(priv->i2c_props.adap, &msg, 1);
+-	return i2c_add_driver(&driver);
 -}
 -
--static void tda827xa_agcf(struct dvb_frontend *fe)
+-static void __exit audiochip_cleanup_module(void)
 -{
--	struct tda8290_priv *priv = fe->tuner_priv;
--	unsigned char data[] = {0x80, 0x2c};
--	struct i2c_msg msg = {.addr = priv->tda827x_addr, .buf = data,
--			      .flags = 0, .len = 2};
--	i2c_transfer(priv->i2c_props.adap, &msg, 1);
+-	i2c_del_driver(&driver);
++	/* don't attach on saa7146 based cards,
++	   because dedicated drivers are used */
++	if ((adap->id == I2C_HW_SAA7146))
++		return 0;
++	if (adap->class & I2C_CLASS_TV_ANALOG)
++		return 1;
 +	return 0;
  }
  
--/*---------------------------------------------------------------------*/
--
--static void tda8290_i2c_bridge(struct dvb_frontend *fe, int close)
-+static int tda8295_i2c_bridge(struct dvb_frontend *fe, int close)
- {
--	struct tda8290_priv *priv = fe->tuner_priv;
-+	struct tda8290_priv *priv = fe->analog_demod_priv;
+-module_init(audiochip_init_module);
+-module_exit(audiochip_cleanup_module);
++static struct v4l2_i2c_driver_data v4l2_i2c_data = {
++	.name = "tvaudio",
++	.driverid = I2C_DRIVERID_TVAUDIO,
++	.command = chip_command,
++	.probe = chip_probe,
++	.remove = chip_remove,
++	.legacy_probe = chip_legacy_probe,
++};
  
--	unsigned char  enable[2] = { 0x21, 0xC0 };
--	unsigned char disable[2] = { 0x21, 0x00 };
-+	unsigned char  enable[2] = { 0x45, 0xc1 };
-+	unsigned char disable[2] = { 0x46, 0x00 };
-+	unsigned char buf[3] = { 0x45, 0x01, 0x00 };
- 	unsigned char *msg;
--	if(close) {
-+
-+	if (close) {
- 		msg = enable;
- 		tuner_i2c_xfer_send(&priv->i2c_props, msg, 2);
- 		/* let the bridge stabilize */
- 		msleep(20);
- 	} else {
- 		msg = disable;
-+		tuner_i2c_xfer_send(&priv->i2c_props, msg, 1);
-+		tuner_i2c_xfer_recv(&priv->i2c_props, &msg[1], 1);
-+
-+		buf[2] = msg[1];
-+		buf[2] &= ~0x04;
-+		tuner_i2c_xfer_send(&priv->i2c_props, buf, 3);
-+		msleep(5);
-+
-+		msg[1] |= 0x04;
- 		tuner_i2c_xfer_send(&priv->i2c_props, msg, 2);
- 	}
-+
-+	return 0;
- }
+ /*
+  * Local variables:
+diff --git a/drivers/media/video/tveeprom.c b/drivers/media/video/tveeprom.c
+index 4b2c403..0b8fbad 100644
+--- a/drivers/media/video/tveeprom.c
++++ b/drivers/media/video/tveeprom.c
+@@ -46,11 +46,12 @@ MODULE_DESCRIPTION("i2c Hauppauge eeprom decoder driver");
+ MODULE_AUTHOR("John Klar");
+ MODULE_LICENSE("GPL");
  
- /*---------------------------------------------------------------------*/
-@@ -384,55 +112,43 @@ static void tda8290_i2c_bridge(struct dvb_frontend *fe, int close)
- static void set_audio(struct dvb_frontend *fe,
- 		      struct analog_parameters *params)
+-static int debug = 0;
++static int debug;
+ module_param(debug, int, 0644);
+ MODULE_PARM_DESC(debug, "Debug level (0-1)");
+ 
+-#define STRM(array,i) (i < sizeof(array)/sizeof(char*) ? array[i] : "unknown")
++#define STRM(array, i) \
++	(i < sizeof(array) / sizeof(char *) ? array[i] : "unknown")
+ 
+ #define tveeprom_info(fmt, arg...) \
+ 	v4l_printk(KERN_INFO, "tveeprom", c->adapter, c->addr, fmt , ## arg)
+@@ -58,7 +59,8 @@ MODULE_PARM_DESC(debug, "Debug level (0-1)");
+ 	v4l_printk(KERN_WARNING, "tveeprom", c->adapter, c->addr, fmt , ## arg)
+ #define tveeprom_dbg(fmt, arg...) do { \
+ 	if (debug) \
+-		v4l_printk(KERN_DEBUG, "tveeprom", c->adapter, c->addr, fmt , ## arg); \
++		v4l_printk(KERN_DEBUG, "tveeprom", \
++				c->adapter, c->addr, fmt , ## arg); \
+ 	} while (0)
+ 
+ /*
+@@ -94,170 +96,172 @@ static struct HAUPPAUGE_TUNER
+ hauppauge_tuner[] =
  {
--	struct tda8290_priv *priv = fe->tuner_priv;
-+	struct tda8290_priv *priv = fe->analog_demod_priv;
- 	char* mode;
+ 	/* 0-9 */
+-	{ TUNER_ABSENT,        "None" },
+-	{ TUNER_ABSENT,        "External" },
+-	{ TUNER_ABSENT,        "Unspecified" },
+-	{ TUNER_PHILIPS_PAL,   "Philips FI1216" },
+-	{ TUNER_PHILIPS_SECAM, "Philips FI1216MF" },
+-	{ TUNER_PHILIPS_NTSC,  "Philips FI1236" },
+-	{ TUNER_PHILIPS_PAL_I, "Philips FI1246" },
+-	{ TUNER_PHILIPS_PAL_DK,"Philips FI1256" },
+-	{ TUNER_PHILIPS_PAL,   "Philips FI1216 MK2" },
+-	{ TUNER_PHILIPS_SECAM, "Philips FI1216MF MK2" },
++	{ TUNER_ABSENT,        		"None" },
++	{ TUNER_ABSENT,        		"External" },
++	{ TUNER_ABSENT,        		"Unspecified" },
++	{ TUNER_PHILIPS_PAL,   		"Philips FI1216" },
++	{ TUNER_PHILIPS_SECAM, 		"Philips FI1216MF" },
++	{ TUNER_PHILIPS_NTSC,  		"Philips FI1236" },
++	{ TUNER_PHILIPS_PAL_I, 		"Philips FI1246" },
++	{ TUNER_PHILIPS_PAL_DK,		"Philips FI1256" },
++	{ TUNER_PHILIPS_PAL,   		"Philips FI1216 MK2" },
++	{ TUNER_PHILIPS_SECAM, 		"Philips FI1216MF MK2" },
+ 	/* 10-19 */
+-	{ TUNER_PHILIPS_NTSC,  "Philips FI1236 MK2" },
+-	{ TUNER_PHILIPS_PAL_I, "Philips FI1246 MK2" },
+-	{ TUNER_PHILIPS_PAL_DK,"Philips FI1256 MK2" },
+-	{ TUNER_TEMIC_NTSC,    "Temic 4032FY5" },
+-	{ TUNER_TEMIC_PAL,     "Temic 4002FH5" },
+-	{ TUNER_TEMIC_PAL_I,   "Temic 4062FY5" },
+-	{ TUNER_PHILIPS_PAL,   "Philips FR1216 MK2" },
+-	{ TUNER_PHILIPS_SECAM, "Philips FR1216MF MK2" },
+-	{ TUNER_PHILIPS_NTSC,  "Philips FR1236 MK2" },
+-	{ TUNER_PHILIPS_PAL_I, "Philips FR1246 MK2" },
++	{ TUNER_PHILIPS_NTSC,  		"Philips FI1236 MK2" },
++	{ TUNER_PHILIPS_PAL_I, 		"Philips FI1246 MK2" },
++	{ TUNER_PHILIPS_PAL_DK,		"Philips FI1256 MK2" },
++	{ TUNER_TEMIC_NTSC,    		"Temic 4032FY5" },
++	{ TUNER_TEMIC_PAL,     		"Temic 4002FH5" },
++	{ TUNER_TEMIC_PAL_I,   		"Temic 4062FY5" },
++	{ TUNER_PHILIPS_PAL,   		"Philips FR1216 MK2" },
++	{ TUNER_PHILIPS_SECAM, 		"Philips FR1216MF MK2" },
++	{ TUNER_PHILIPS_NTSC,  		"Philips FR1236 MK2" },
++	{ TUNER_PHILIPS_PAL_I, 		"Philips FR1246 MK2" },
+ 	/* 20-29 */
+-	{ TUNER_PHILIPS_PAL_DK,"Philips FR1256 MK2" },
+-	{ TUNER_PHILIPS_PAL,   "Philips FM1216" },
+-	{ TUNER_PHILIPS_SECAM, "Philips FM1216MF" },
+-	{ TUNER_PHILIPS_NTSC,  "Philips FM1236" },
+-	{ TUNER_PHILIPS_PAL_I, "Philips FM1246" },
+-	{ TUNER_PHILIPS_PAL_DK,"Philips FM1256" },
+-	{ TUNER_TEMIC_4036FY5_NTSC, "Temic 4036FY5" },
+-	{ TUNER_ABSENT,        "Samsung TCPN9082D" },
+-	{ TUNER_ABSENT,        "Samsung TCPM9092P" },
+-	{ TUNER_TEMIC_4006FH5_PAL, "Temic 4006FH5" },
++	{ TUNER_PHILIPS_PAL_DK,		"Philips FR1256 MK2" },
++	{ TUNER_PHILIPS_PAL,   		"Philips FM1216" },
++	{ TUNER_PHILIPS_SECAM, 		"Philips FM1216MF" },
++	{ TUNER_PHILIPS_NTSC,  		"Philips FM1236" },
++	{ TUNER_PHILIPS_PAL_I, 		"Philips FM1246" },
++	{ TUNER_PHILIPS_PAL_DK,		"Philips FM1256" },
++	{ TUNER_TEMIC_4036FY5_NTSC, 	"Temic 4036FY5" },
++	{ TUNER_ABSENT,        		"Samsung TCPN9082D" },
++	{ TUNER_ABSENT,        		"Samsung TCPM9092P" },
++	{ TUNER_TEMIC_4006FH5_PAL, 	"Temic 4006FH5" },
+ 	/* 30-39 */
+-	{ TUNER_ABSENT,        "Samsung TCPN9085D" },
+-	{ TUNER_ABSENT,        "Samsung TCPB9085P" },
+-	{ TUNER_ABSENT,        "Samsung TCPL9091P" },
+-	{ TUNER_TEMIC_4039FR5_NTSC, "Temic 4039FR5" },
+-	{ TUNER_PHILIPS_FQ1216ME,   "Philips FQ1216 ME" },
+-	{ TUNER_TEMIC_4066FY5_PAL_I, "Temic 4066FY5" },
+-	{ TUNER_PHILIPS_NTSC,        "Philips TD1536" },
+-	{ TUNER_PHILIPS_NTSC,        "Philips TD1536D" },
+-	{ TUNER_PHILIPS_NTSC,  "Philips FMR1236" }, /* mono radio */
+-	{ TUNER_ABSENT,        "Philips FI1256MP" },
++	{ TUNER_ABSENT,        		"Samsung TCPN9085D" },
++	{ TUNER_ABSENT,        		"Samsung TCPB9085P" },
++	{ TUNER_ABSENT,        		"Samsung TCPL9091P" },
++	{ TUNER_TEMIC_4039FR5_NTSC, 	"Temic 4039FR5" },
++	{ TUNER_PHILIPS_FQ1216ME,   	"Philips FQ1216 ME" },
++	{ TUNER_TEMIC_4066FY5_PAL_I, 	"Temic 4066FY5" },
++	{ TUNER_PHILIPS_NTSC,        	"Philips TD1536" },
++	{ TUNER_PHILIPS_NTSC,        	"Philips TD1536D" },
++	{ TUNER_PHILIPS_NTSC,  		"Philips FMR1236" }, /* mono radio */
++	{ TUNER_ABSENT,        		"Philips FI1256MP" },
+ 	/* 40-49 */
+-	{ TUNER_ABSENT,        "Samsung TCPQ9091P" },
++	{ TUNER_ABSENT,        		"Samsung TCPQ9091P" },
+ 	{ TUNER_TEMIC_4006FN5_MULTI_PAL, "Temic 4006FN5" },
+-	{ TUNER_TEMIC_4009FR5_PAL, "Temic 4009FR5" },
+-	{ TUNER_TEMIC_4046FM5,     "Temic 4046FM5" },
++	{ TUNER_TEMIC_4009FR5_PAL, 	"Temic 4009FR5" },
++	{ TUNER_TEMIC_4046FM5,     	"Temic 4046FM5" },
+ 	{ TUNER_TEMIC_4009FN5_MULTI_PAL_FM, "Temic 4009FN5" },
+-	{ TUNER_ABSENT,        "Philips TD1536D FH 44"},
+-	{ TUNER_LG_NTSC_FM,    "LG TP18NSR01F"},
+-	{ TUNER_LG_PAL_FM,     "LG TP18PSB01D"},
+-	{ TUNER_LG_PAL,        "LG TP18PSB11D"},
+-	{ TUNER_LG_PAL_I_FM,   "LG TAPC-I001D"},
++	{ TUNER_ABSENT,        		"Philips TD1536D FH 44"},
++	{ TUNER_LG_NTSC_FM,    		"LG TP18NSR01F"},
++	{ TUNER_LG_PAL_FM,     		"LG TP18PSB01D"},
++	{ TUNER_LG_PAL,        		"LG TP18PSB11D"},
++	{ TUNER_LG_PAL_I_FM,   		"LG TAPC-I001D"},
+ 	/* 50-59 */
+-	{ TUNER_LG_PAL_I,      "LG TAPC-I701D"},
+-	{ TUNER_ABSENT,        "Temic 4042FI5"},
+-	{ TUNER_MICROTUNE_4049FM5, "Microtune 4049 FM5"},
+-	{ TUNER_ABSENT,        "LG TPI8NSR11F"},
+-	{ TUNER_ABSENT,        "Microtune 4049 FM5 Alt I2C"},
+-	{ TUNER_PHILIPS_FM1216ME_MK3, "Philips FQ1216ME MK3"},
+-	{ TUNER_ABSENT,        "Philips FI1236 MK3"},
+-	{ TUNER_PHILIPS_FM1216ME_MK3, "Philips FM1216 ME MK3"},
+-	{ TUNER_PHILIPS_FM1236_MK3, "Philips FM1236 MK3"},
+-	{ TUNER_ABSENT,        "Philips FM1216MP MK3"},
++	{ TUNER_LG_PAL_I,      		"LG TAPC-I701D"},
++	{ TUNER_ABSENT,       		"Temic 4042FI5"},
++	{ TUNER_MICROTUNE_4049FM5, 	"Microtune 4049 FM5"},
++	{ TUNER_ABSENT,        		"LG TPI8NSR11F"},
++	{ TUNER_ABSENT,        		"Microtune 4049 FM5 Alt I2C"},
++	{ TUNER_PHILIPS_FM1216ME_MK3, 	"Philips FQ1216ME MK3"},
++	{ TUNER_ABSENT,        		"Philips FI1236 MK3"},
++	{ TUNER_PHILIPS_FM1216ME_MK3, 	"Philips FM1216 ME MK3"},
++	{ TUNER_PHILIPS_FM1236_MK3, 	"Philips FM1236 MK3"},
++	{ TUNER_ABSENT,        		"Philips FM1216MP MK3"},
+ 	/* 60-69 */
+-	{ TUNER_PHILIPS_FM1216ME_MK3, "LG S001D MK3"},
+-	{ TUNER_ABSENT,        "LG M001D MK3"},
+-	{ TUNER_PHILIPS_FM1216ME_MK3, "LG S701D MK3"},
+-	{ TUNER_ABSENT,        "LG M701D MK3"},
+-	{ TUNER_ABSENT,        "Temic 4146FM5"},
+-	{ TUNER_ABSENT,        "Temic 4136FY5"},
+-	{ TUNER_ABSENT,        "Temic 4106FH5"},
+-	{ TUNER_ABSENT,        "Philips FQ1216LMP MK3"},
+-	{ TUNER_LG_NTSC_TAPE,  "LG TAPE H001F MK3"},
+-	{ TUNER_LG_NTSC_TAPE,  "LG TAPE H701F MK3"},
++	{ TUNER_PHILIPS_FM1216ME_MK3, 	"LG S001D MK3"},
++	{ TUNER_ABSENT,        		"LG M001D MK3"},
++	{ TUNER_PHILIPS_FM1216ME_MK3, 	"LG S701D MK3"},
++	{ TUNER_ABSENT,        		"LG M701D MK3"},
++	{ TUNER_ABSENT,        		"Temic 4146FM5"},
++	{ TUNER_ABSENT,        		"Temic 4136FY5"},
++	{ TUNER_ABSENT,        		"Temic 4106FH5"},
++	{ TUNER_ABSENT,        		"Philips FQ1216LMP MK3"},
++	{ TUNER_LG_NTSC_TAPE,  		"LG TAPE H001F MK3"},
++	{ TUNER_LG_NTSC_TAPE,  		"LG TAPE H701F MK3"},
+ 	/* 70-79 */
+-	{ TUNER_ABSENT,        "LG TALN H200T"},
+-	{ TUNER_ABSENT,        "LG TALN H250T"},
+-	{ TUNER_ABSENT,        "LG TALN M200T"},
+-	{ TUNER_ABSENT,        "LG TALN Z200T"},
+-	{ TUNER_ABSENT,        "LG TALN S200T"},
+-	{ TUNER_ABSENT,        "Thompson DTT7595"},
+-	{ TUNER_ABSENT,        "Thompson DTT7592"},
+-	{ TUNER_ABSENT,        "Silicon TDA8275C1 8290"},
+-	{ TUNER_ABSENT,        "Silicon TDA8275C1 8290 FM"},
+-	{ TUNER_ABSENT,        "Thompson DTT757"},
++	{ TUNER_ABSENT,        		"LG TALN H200T"},
++	{ TUNER_ABSENT,        		"LG TALN H250T"},
++	{ TUNER_ABSENT,        		"LG TALN M200T"},
++	{ TUNER_ABSENT,        		"LG TALN Z200T"},
++	{ TUNER_ABSENT,        		"LG TALN S200T"},
++	{ TUNER_ABSENT,        		"Thompson DTT7595"},
++	{ TUNER_ABSENT,        		"Thompson DTT7592"},
++	{ TUNER_ABSENT,        		"Silicon TDA8275C1 8290"},
++	{ TUNER_ABSENT,        		"Silicon TDA8275C1 8290 FM"},
++	{ TUNER_ABSENT,        		"Thompson DTT757"},
+ 	/* 80-89 */
+-	{ TUNER_PHILIPS_FM1216ME_MK3, "Philips FQ1216LME MK3"},
+-	{ TUNER_LG_PAL_NEW_TAPC, "LG TAPC G701D"},
+-	{ TUNER_LG_NTSC_NEW_TAPC, "LG TAPC H791F"},
+-	{ TUNER_LG_PAL_NEW_TAPC, "TCL 2002MB 3"},
+-	{ TUNER_LG_PAL_NEW_TAPC, "TCL 2002MI 3"},
+-	{ TUNER_TCL_2002N,     "TCL 2002N 6A"},
+-	{ TUNER_PHILIPS_FM1236_MK3, "Philips FQ1236 MK3"},
+-	{ TUNER_SAMSUNG_TCPN_2121P30A, "Samsung TCPN 2121P30A"},
+-	{ TUNER_ABSENT,        "Samsung TCPE 4121P30A"},
+-	{ TUNER_PHILIPS_FM1216ME_MK3, "TCL MFPE05 2"},
++	{ TUNER_PHILIPS_FM1216ME_MK3, 	"Philips FQ1216LME MK3"},
++	{ TUNER_LG_PAL_NEW_TAPC, 	"LG TAPC G701D"},
++	{ TUNER_LG_NTSC_NEW_TAPC, 	"LG TAPC H791F"},
++	{ TUNER_LG_PAL_NEW_TAPC, 	"TCL 2002MB 3"},
++	{ TUNER_LG_PAL_NEW_TAPC, 	"TCL 2002MI 3"},
++	{ TUNER_TCL_2002N,     		"TCL 2002N 6A"},
++	{ TUNER_PHILIPS_FM1236_MK3, 	"Philips FQ1236 MK3"},
++	{ TUNER_SAMSUNG_TCPN_2121P30A, 	"Samsung TCPN 2121P30A"},
++	{ TUNER_ABSENT,        		"Samsung TCPE 4121P30A"},
++	{ TUNER_PHILIPS_FM1216ME_MK3, 	"TCL MFPE05 2"},
+ 	/* 90-99 */
+-	{ TUNER_ABSENT,        "LG TALN H202T"},
+-	{ TUNER_PHILIPS_FQ1216AME_MK4, "Philips FQ1216AME MK4"},
+-	{ TUNER_PHILIPS_FQ1236A_MK4, "Philips FQ1236A MK4"},
+-	{ TUNER_ABSENT,        "Philips FQ1286A MK4"},
+-	{ TUNER_ABSENT,        "Philips FQ1216ME MK5"},
+-	{ TUNER_ABSENT,        "Philips FQ1236 MK5"},
+-	{ TUNER_SAMSUNG_TCPG_6121P30A, "Samsung TCPG 6121P30A"},
+-	{ TUNER_TCL_2002MB,    "TCL 2002MB_3H"},
+-	{ TUNER_ABSENT,        "TCL 2002MI_3H"},
+-	{ TUNER_TCL_2002N,     "TCL 2002N 5H"},
++	{ TUNER_ABSENT,        		"LG TALN H202T"},
++	{ TUNER_PHILIPS_FQ1216AME_MK4, 	"Philips FQ1216AME MK4"},
++	{ TUNER_PHILIPS_FQ1236A_MK4, 	"Philips FQ1236A MK4"},
++	{ TUNER_ABSENT,       		"Philips FQ1286A MK4"},
++	{ TUNER_ABSENT,        		"Philips FQ1216ME MK5"},
++	{ TUNER_ABSENT,        		"Philips FQ1236 MK5"},
++	{ TUNER_SAMSUNG_TCPG_6121P30A, 	"Samsung TCPG 6121P30A"},
++	{ TUNER_TCL_2002MB,    		"TCL 2002MB_3H"},
++	{ TUNER_ABSENT,        		"TCL 2002MI_3H"},
++	{ TUNER_TCL_2002N,     		"TCL 2002N 5H"},
+ 	/* 100-109 */
+-	{ TUNER_PHILIPS_FMD1216ME_MK3, "Philips FMD1216ME"},
+-	{ TUNER_TEA5767,       "Philips TEA5768HL FM Radio"},
+-	{ TUNER_ABSENT,        "Panasonic ENV57H12D5"},
+-	{ TUNER_PHILIPS_FM1236_MK3, "TCL MFNM05-4"},
+-	{ TUNER_ABSENT,        "TCL MNM05-4"},
+-	{ TUNER_PHILIPS_FM1216ME_MK3, "TCL MPE05-2"},
+-	{ TUNER_ABSENT,        "TCL MQNM05-4"},
+-	{ TUNER_ABSENT,        "LG TAPC-W701D"},
+-	{ TUNER_ABSENT,        "TCL 9886P-WM"},
+-	{ TUNER_ABSENT,        "TCL 1676NM-WM"},
++	{ TUNER_PHILIPS_FMD1216ME_MK3, 	"Philips FMD1216ME"},
++	{ TUNER_TEA5767,       		"Philips TEA5768HL FM Radio"},
++	{ TUNER_ABSENT,        		"Panasonic ENV57H12D5"},
++	{ TUNER_PHILIPS_FM1236_MK3, 	"TCL MFNM05-4"},
++	{ TUNER_ABSENT,        		"TCL MNM05-4"},
++	{ TUNER_PHILIPS_FM1216ME_MK3, 	"TCL MPE05-2"},
++	{ TUNER_ABSENT,        		"TCL MQNM05-4"},
++	{ TUNER_ABSENT,        		"LG TAPC-W701D"},
++	{ TUNER_ABSENT,        		"TCL 9886P-WM"},
++	{ TUNER_ABSENT,        		"TCL 1676NM-WM"},
+ 	/* 110-119 */
+-	{ TUNER_ABSENT,        "Thompson DTT75105"},
+-	{ TUNER_ABSENT,        "Conexant_CX24109"},
+-	{ TUNER_TCL_2002N,     "TCL M2523_5N_E"},
+-	{ TUNER_TCL_2002MB,    "TCL M2523_3DB_E"},
+-	{ TUNER_ABSENT,        "Philips 8275A"},
+-	{ TUNER_ABSENT,        "Microtune MT2060"},
+-	{ TUNER_PHILIPS_FM1236_MK3, "Philips FM1236 MK5"},
+-	{ TUNER_PHILIPS_FM1216ME_MK3, "Philips FM1216ME MK5"},
+-	{ TUNER_ABSENT,        "TCL M2523_3DI_E"},
+-	{ TUNER_ABSENT,        "Samsung THPD5222FG30A"},
++	{ TUNER_ABSENT,        		"Thompson DTT75105"},
++	{ TUNER_ABSENT,        		"Conexant_CX24109"},
++	{ TUNER_TCL_2002N,     		"TCL M2523_5N_E"},
++	{ TUNER_TCL_2002MB,    		"TCL M2523_3DB_E"},
++	{ TUNER_ABSENT,        		"Philips 8275A"},
++	{ TUNER_ABSENT,        		"Microtune MT2060"},
++	{ TUNER_PHILIPS_FM1236_MK3, 	"Philips FM1236 MK5"},
++	{ TUNER_PHILIPS_FM1216ME_MK3, 	"Philips FM1216ME MK5"},
++	{ TUNER_ABSENT,        		"TCL M2523_3DI_E"},
++	{ TUNER_ABSENT,        		"Samsung THPD5222FG30A"},
+ 	/* 120-129 */
+-	{ TUNER_ABSENT,        "Xceive XC3028"},
+-	{ TUNER_ABSENT,        "Philips FQ1216LME MK5"},
+-	{ TUNER_ABSENT,        "Philips FQD1216LME"},
+-	{ TUNER_ABSENT,        "Conexant CX24118A"},
+-	{ TUNER_ABSENT,        "TCL DMF11WIP"},
+-	{ TUNER_ABSENT,        "TCL MFNM05_4H_E"},
+-	{ TUNER_ABSENT,        "TCL MNM05_4H_E"},
+-	{ TUNER_ABSENT,        "TCL MPE05_2H_E"},
+-	{ TUNER_ABSENT,        "TCL MQNM05_4_U"},
+-	{ TUNER_ABSENT,        "TCL M2523_5NH_E"},
++	{ TUNER_XC2028,        		"Xceive XC3028"},
++	{ TUNER_ABSENT,        		"Philips FQ1216LME MK5"},
++	{ TUNER_ABSENT,        		"Philips FQD1216LME"},
++	{ TUNER_ABSENT,        		"Conexant CX24118A"},
++	{ TUNER_ABSENT,        		"TCL DMF11WIP"},
++	{ TUNER_ABSENT,        		"TCL MFNM05_4H_E"},
++	{ TUNER_ABSENT,        		"TCL MNM05_4H_E"},
++	{ TUNER_ABSENT,        		"TCL MPE05_2H_E"},
++	{ TUNER_ABSENT,        		"TCL MQNM05_4_U"},
++	{ TUNER_ABSENT,        		"TCL M2523_5NH_E"},
+ 	/* 130-139 */
+-	{ TUNER_ABSENT,        "TCL M2523_3DBH_E"},
+-	{ TUNER_ABSENT,        "TCL M2523_3DIH_E"},
+-	{ TUNER_ABSENT,        "TCL MFPE05_2_U"},
+-	{ TUNER_ABSENT,        "Philips FMD1216MEX"},
+-	{ TUNER_ABSENT,        "Philips FRH2036B"},
+-	{ TUNER_ABSENT,        "Panasonic ENGF75_01GF"},
+-	{ TUNER_ABSENT,        "MaxLinear MXL5005"},
+-	{ TUNER_ABSENT,        "MaxLinear MXL5003"},
+-	{ TUNER_ABSENT,        "Xceive XC2028"},
+-	{ TUNER_ABSENT,        "Microtune MT2131"},
++	{ TUNER_ABSENT,        		"TCL M2523_3DBH_E"},
++	{ TUNER_ABSENT,        		"TCL M2523_3DIH_E"},
++	{ TUNER_ABSENT,        		"TCL MFPE05_2_U"},
++	{ TUNER_ABSENT,        		"Philips FMD1216MEX"},
++	{ TUNER_ABSENT,        		"Philips FRH2036B"},
++	{ TUNER_ABSENT,        		"Panasonic ENGF75_01GF"},
++	{ TUNER_ABSENT,        		"MaxLinear MXL5005"},
++	{ TUNER_ABSENT,        		"MaxLinear MXL5003"},
++	{ TUNER_ABSENT,        		"Xceive XC2028"},
++	{ TUNER_ABSENT,        		"Microtune MT2131"},
+ 	/* 140-149 */
+-	{ TUNER_ABSENT,        "Philips 8275A_8295"},
+-	{ TUNER_ABSENT,        "TCL MF02GIP_5N_E"},
+-	{ TUNER_ABSENT,        "TCL MF02GIP_3DB_E"},
+-	{ TUNER_ABSENT,        "TCL MF02GIP_3DI_E"},
+-	{ TUNER_ABSENT,        "Microtune MT2266"},
+-	{ TUNER_ABSENT,        "TCL MF10WPP_4N_E"},
+-	{ TUNER_ABSENT,        "LG TAPQ_H702F"},
+-	{ TUNER_ABSENT,        "TCL M09WPP_4N_E"},
+-	{ TUNER_ABSENT,        "MaxLinear MXL5005_v2"},
+-	{ TUNER_ABSENT,        "Philips 18271_8295"},
++	{ TUNER_ABSENT,        		"Philips 8275A_8295"},
++	{ TUNER_ABSENT,        		"TCL MF02GIP_5N_E"},
++	{ TUNER_ABSENT,        		"TCL MF02GIP_3DB_E"},
++	{ TUNER_ABSENT,        		"TCL MF02GIP_3DI_E"},
++	{ TUNER_ABSENT,        		"Microtune MT2266"},
++	{ TUNER_ABSENT,        		"TCL MF10WPP_4N_E"},
++	{ TUNER_ABSENT,        		"LG TAPQ_H702F"},
++	{ TUNER_ABSENT,        		"TCL M09WPP_4N_E"},
++	{ TUNER_ABSENT,        		"MaxLinear MXL5005_v2"},
++	{ TUNER_PHILIPS_TDA8290, 	"Philips 18271_8295"},
++	/* 150-159 */
++	{ TUNER_ABSENT,        "Xceive XC5000"},
+ };
  
--	priv->tda827x_lpsel = 0;
- 	if (params->std & V4L2_STD_MN) {
--		priv->sgIF = 92;
- 		priv->tda8290_easy_mode = 0x01;
--		priv->tda827x_lpsel = 1;
- 		mode = "MN";
- 	} else if (params->std & V4L2_STD_B) {
--		priv->sgIF = 108;
- 		priv->tda8290_easy_mode = 0x02;
- 		mode = "B";
- 	} else if (params->std & V4L2_STD_GH) {
--		priv->sgIF = 124;
- 		priv->tda8290_easy_mode = 0x04;
- 		mode = "GH";
- 	} else if (params->std & V4L2_STD_PAL_I) {
--		priv->sgIF = 124;
- 		priv->tda8290_easy_mode = 0x08;
- 		mode = "I";
- 	} else if (params->std & V4L2_STD_DK) {
--		priv->sgIF = 124;
- 		priv->tda8290_easy_mode = 0x10;
- 		mode = "DK";
- 	} else if (params->std & V4L2_STD_SECAM_L) {
--		priv->sgIF = 124;
- 		priv->tda8290_easy_mode = 0x20;
- 		mode = "L";
- 	} else if (params->std & V4L2_STD_SECAM_LC) {
--		priv->sgIF = 20;
- 		priv->tda8290_easy_mode = 0x40;
- 		mode = "LC";
- 	} else {
--		priv->sgIF = 124;
- 		priv->tda8290_easy_mode = 0x10;
- 		mode = "xx";
+ static struct HAUPPAUGE_AUDIOIC
+@@ -344,37 +348,37 @@ static const char *decoderIC[] = {
+ static int hasRadioTuner(int tunerType)
+ {
+ 	switch (tunerType) {
+-		case 18: //PNPEnv_TUNER_FR1236_MK2:
+-		case 23: //PNPEnv_TUNER_FM1236:
+-		case 38: //PNPEnv_TUNER_FMR1236:
+-		case 16: //PNPEnv_TUNER_FR1216_MK2:
+-		case 19: //PNPEnv_TUNER_FR1246_MK2:
+-		case 21: //PNPEnv_TUNER_FM1216:
+-		case 24: //PNPEnv_TUNER_FM1246:
+-		case 17: //PNPEnv_TUNER_FR1216MF_MK2:
+-		case 22: //PNPEnv_TUNER_FM1216MF:
+-		case 20: //PNPEnv_TUNER_FR1256_MK2:
+-		case 25: //PNPEnv_TUNER_FM1256:
+-		case 33: //PNPEnv_TUNER_4039FR5:
+-		case 42: //PNPEnv_TUNER_4009FR5:
+-		case 52: //PNPEnv_TUNER_4049FM5:
+-		case 54: //PNPEnv_TUNER_4049FM5_AltI2C:
+-		case 44: //PNPEnv_TUNER_4009FN5:
+-		case 31: //PNPEnv_TUNER_TCPB9085P:
+-		case 30: //PNPEnv_TUNER_TCPN9085D:
+-		case 46: //PNPEnv_TUNER_TP18NSR01F:
+-		case 47: //PNPEnv_TUNER_TP18PSB01D:
+-		case 49: //PNPEnv_TUNER_TAPC_I001D:
+-		case 60: //PNPEnv_TUNER_TAPE_S001D_MK3:
+-		case 57: //PNPEnv_TUNER_FM1216ME_MK3:
+-		case 59: //PNPEnv_TUNER_FM1216MP_MK3:
+-		case 58: //PNPEnv_TUNER_FM1236_MK3:
+-		case 68: //PNPEnv_TUNER_TAPE_H001F_MK3:
+-		case 61: //PNPEnv_TUNER_TAPE_M001D_MK3:
+-		case 78: //PNPEnv_TUNER_TDA8275C1_8290_FM:
+-		case 89: //PNPEnv_TUNER_TCL_MFPE05_2:
+-		case 92: //PNPEnv_TUNER_PHILIPS_FQ1236A_MK4:
+-		case 105:
++	case 18: /* PNPEnv_TUNER_FR1236_MK2 */
++	case 23: /* PNPEnv_TUNER_FM1236 */
++	case 38: /* PNPEnv_TUNER_FMR1236 */
++	case 16: /* PNPEnv_TUNER_FR1216_MK2 */
++	case 19: /* PNPEnv_TUNER_FR1246_MK2 */
++	case 21: /* PNPEnv_TUNER_FM1216 */
++	case 24: /* PNPEnv_TUNER_FM1246 */
++	case 17: /* PNPEnv_TUNER_FR1216MF_MK2 */
++	case 22: /* PNPEnv_TUNER_FM1216MF */
++	case 20: /* PNPEnv_TUNER_FR1256_MK2 */
++	case 25: /* PNPEnv_TUNER_FM1256 */
++	case 33: /* PNPEnv_TUNER_4039FR5 */
++	case 42: /* PNPEnv_TUNER_4009FR5 */
++	case 52: /* PNPEnv_TUNER_4049FM5 */
++	case 54: /* PNPEnv_TUNER_4049FM5_AltI2C */
++	case 44: /* PNPEnv_TUNER_4009FN5 */
++	case 31: /* PNPEnv_TUNER_TCPB9085P */
++	case 30: /* PNPEnv_TUNER_TCPN9085D */
++	case 46: /* PNPEnv_TUNER_TP18NSR01F */
++	case 47: /* PNPEnv_TUNER_TP18PSB01D */
++	case 49: /* PNPEnv_TUNER_TAPC_I001D */
++	case 60: /* PNPEnv_TUNER_TAPE_S001D_MK3 */
++	case 57: /* PNPEnv_TUNER_FM1216ME_MK3 */
++	case 59: /* PNPEnv_TUNER_FM1216MP_MK3 */
++	case 58: /* PNPEnv_TUNER_FM1236_MK3 */
++	case 68: /* PNPEnv_TUNER_TAPE_H001F_MK3 */
++	case 61: /* PNPEnv_TUNER_TAPE_M001D_MK3 */
++	case 78: /* PNPEnv_TUNER_TDA8275C1_8290_FM */
++	case 89: /* PNPEnv_TUNER_TCL_MFPE05_2 */
++	case 92: /* PNPEnv_TUNER_PHILIPS_FQ1236A_MK4 */
++	case 105:
+ 		return 1;
  	}
+ 	return 0;
+@@ -392,7 +396,8 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
+ 	**
+ 	** In our (ivtv) case we're interested in the following:
+ 	** tuner type:   tag [00].05 or [0a].01 (index into hauppauge_tuner)
+-	** tuner fmts:   tag [00].04 or [0a].00 (bitmask index into hauppauge_tuner_fmt)
++	** tuner fmts:   tag [00].04 or [0a].00 (bitmask index into
++	**		 hauppauge_tuner_fmt)
+ 	** radio:        tag [00].{last} or [0e].00  (bitmask.  bit2=FM)
+ 	** audio proc:   tag [02].01 or [05].00 (mask with 0x7f)
+ 	** decoder proc: tag [09].01)
+@@ -405,9 +410,9 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
+ 	** # of inputs/outputs ???
+ 	*/
  
--	if (params->mode == V4L2_TUNER_RADIO)
--		priv->sgIF = 88; /* if frequency is 5.5 MHz */
--
--	tuner_dbg("setting tda8290 to system %s\n", mode);
-+	tuner_dbg("setting tda829x to system %s\n", mode);
- }
+-	int i, j, len, done, beenhere, tag,start;
++	int i, j, len, done, beenhere, tag, start;
  
--static int tda8290_set_params(struct dvb_frontend *fe,
--			      struct analog_parameters *params)
-+static void tda8290_set_params(struct dvb_frontend *fe,
-+			       struct analog_parameters *params)
- {
--	struct tda8290_priv *priv = fe->tuner_priv;
-+	struct tda8290_priv *priv = fe->analog_demod_priv;
-+
- 	unsigned char soft_reset[]  = { 0x00, 0x00 };
- 	unsigned char easy_mode[]   = { 0x01, priv->tda8290_easy_mode };
- 	unsigned char expert_mode[] = { 0x01, 0x80 };
-@@ -457,8 +173,8 @@ static int tda8290_set_params(struct dvb_frontend *fe,
+-	int tuner1 = 0, t_format1 = 0, audioic=-1;
++	int tuner1 = 0, t_format1 = 0, audioic = -1;
+ 	char *t_name1 = NULL;
+ 	const char *t_fmt_name1[8] = { " none", "", "", "", "", "", "", "" };
  
- 	set_audio(fe, params);
+@@ -418,17 +423,24 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
+ 	memset(tvee, 0, sizeof(*tvee));
+ 	done = len = beenhere = 0;
  
--	if (priv->lna_cfg)
--		tuner_dbg("tda827xa config is 0x%02x\n", *priv->lna_cfg);
-+	if (priv->cfg.config)
-+		tuner_dbg("tda827xa config is 0x%02x\n", *priv->cfg.config);
- 	tuner_i2c_xfer_send(&priv->i2c_props, easy_mode, 2);
- 	tuner_i2c_xfer_send(&priv->i2c_props, agc_out_on, 2);
- 	tuner_i2c_xfer_send(&priv->i2c_props, soft_reset, 2);
-@@ -475,10 +191,10 @@ static int tda8290_set_params(struct dvb_frontend *fe,
- 	tuner_i2c_xfer_send(&priv->i2c_props, pll_bw_nom, 2);
+-	/* Hack for processing eeprom for em28xx and cx 2388x*/
+-	if ((eeprom_data[0] == 0x1a) && (eeprom_data[1] == 0xeb) &&
+-			(eeprom_data[2] == 0x67) && (eeprom_data[3] == 0x95))
+-		start=0xa0; /* Generic em28xx offset */
+-	else if (((eeprom_data[0] & 0xe1) == 0x01) &&
+-					(eeprom_data[1] == 0x00) &&
+-					(eeprom_data[2] == 0x00) &&
+-					(eeprom_data[8] == 0x84))
+-		start=8; /* Generic cx2388x offset */
++	/* Different eeprom start offsets for em28xx, cx2388x and cx23418 */
++	if (eeprom_data[0] == 0x1a &&
++	    eeprom_data[1] == 0xeb &&
++	    eeprom_data[2] == 0x67 &&
++	    eeprom_data[3] == 0x95)
++		start = 0xa0; /* Generic em28xx offset */
++	else if ((eeprom_data[0] & 0xe1) == 0x01 &&
++		 eeprom_data[1] == 0x00 &&
++		 eeprom_data[2] == 0x00 &&
++		 eeprom_data[8] == 0x84)
++		start = 8; /* Generic cx2388x offset */
++	else if (eeprom_data[1] == 0x70 &&
++		 eeprom_data[2] == 0x00 &&
++		 eeprom_data[4] == 0x74 &&
++		 eeprom_data[8] == 0x84)
++		start = 8; /* Generic cx23418 offset (models 74xxx) */
+ 	else
+-		start=0;
++		start = 0;
  
- 	tda8290_i2c_bridge(fe, 1);
--	if (priv->tda827x_ver != 0)
--		tda827xa_set_analog_params(fe, params);
--	else
--		tda827x_set_analog_params(fe, params);
-+
-+	if (fe->ops.tuner_ops.set_analog_params)
-+		fe->ops.tuner_ops.set_analog_params(fe, params);
-+
- 	for (i = 0; i < 3; i++) {
- 		tuner_i2c_xfer_send(&priv->i2c_props, &addr_pll_stat, 1);
- 		tuner_i2c_xfer_recv(&priv->i2c_props, &pll_stat, 1);
-@@ -507,10 +223,8 @@ static int tda8290_set_params(struct dvb_frontend *fe,
- 		if ((agc_stat > 115) || !(pll_stat & 0x80)) {
- 			tuner_dbg("adjust gain, step 2. Agc: %d, lock: %d\n",
- 				   agc_stat, pll_stat & 0x80);
--			if (priv->tda827x_ver != 0)
--				tda827xa_agcf(fe);
--			else
--				tda827x_agcf(fe);
-+			if (priv->cfg.agcf)
-+				priv->cfg.agcf(fe);
- 			msleep(100);
- 			tuner_i2c_xfer_send(&priv->i2c_props, &addr_agc_stat, 1);
- 			tuner_i2c_xfer_recv(&priv->i2c_props, &agc_stat, 1);
-@@ -541,99 +255,242 @@ static int tda8290_set_params(struct dvb_frontend *fe,
+ 	for (i = start; !done && i < 256; i += len) {
+ 		if (eeprom_data[i] == 0x84) {
+@@ -444,16 +456,17 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
+ 			++i;
+ 		} else {
+ 			tveeprom_warn("Encountered bad packet header [%02x]. "
+-				"Corrupt or not a Hauppauge eeprom.\n", eeprom_data[i]);
++				"Corrupt or not a Hauppauge eeprom.\n",
++				eeprom_data[i]);
+ 			return;
+ 		}
  
- 	tda8290_i2c_bridge(fe, 0);
- 	tuner_i2c_xfer_send(&priv->i2c_props, if_agc_set, 2);
-+}
-+
-+/*---------------------------------------------------------------------*/
-+
-+static void tda8295_power(struct dvb_frontend *fe, int enable)
-+{
-+	struct tda8290_priv *priv = fe->analog_demod_priv;
-+	unsigned char buf[] = { 0x30, 0x00 }; /* clb_stdbt */
+ 		if (debug) {
+-			tveeprom_info("Tag [%02x] + %d bytes:", eeprom_data[i], len - 1);
+-			for(j = 1; j < len; j++) {
+-				printk(" %02x", eeprom_data[i + j]);
+-			}
+-			printk("\n");
++			tveeprom_info("Tag [%02x] + %d bytes:",
++					eeprom_data[i], len - 1);
++			for (j = 1; j < len; j++)
++				printk(KERN_CONT " %02x", eeprom_data[i + j]);
++			printk(KERN_CONT "\n");
+ 		}
  
--	priv->frequency = (V4L2_TUNER_RADIO == params->mode) ?
--		params->frequency * 125 / 2 : params->frequency * 62500;
-+	tuner_i2c_xfer_send(&priv->i2c_props, &buf[0], 1);
-+	tuner_i2c_xfer_recv(&priv->i2c_props, &buf[1], 1);
+ 		/* process by tag */
+@@ -504,16 +517,16 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
+ 				(eeprom_data[i+6] << 8) +
+ 				(eeprom_data[i+7] << 16);
  
--	return 0;
-+	if (enable)
-+		buf[1] = 0x01;
-+	else
-+		buf[1] = 0x03;
-+
-+	tuner_i2c_xfer_send(&priv->i2c_props, buf, 2);
-+}
-+
-+static void tda8295_set_easy_mode(struct dvb_frontend *fe, int enable)
-+{
-+	struct tda8290_priv *priv = fe->analog_demod_priv;
-+	unsigned char buf[] = { 0x01, 0x00 };
-+
-+	tuner_i2c_xfer_send(&priv->i2c_props, &buf[0], 1);
-+	tuner_i2c_xfer_recv(&priv->i2c_props, &buf[1], 1);
-+
-+	if (enable)
-+		buf[1] = 0x01; /* rising edge sets regs 0x02 - 0x23 */
-+	else
-+		buf[1] = 0x00; /* reset active bit */
-+
-+	tuner_i2c_xfer_send(&priv->i2c_props, buf, 2);
-+}
-+
-+static void tda8295_set_video_std(struct dvb_frontend *fe)
-+{
-+	struct tda8290_priv *priv = fe->analog_demod_priv;
-+	unsigned char buf[] = { 0x00, priv->tda8290_easy_mode };
-+
-+	tuner_i2c_xfer_send(&priv->i2c_props, buf, 2);
-+
-+	tda8295_set_easy_mode(fe, 1);
-+	msleep(20);
-+	tda8295_set_easy_mode(fe, 0);
- }
+-				if ( (eeprom_data[i + 8] & 0xf0) &&
+-					(tvee->serial_number < 0xffffff) ) {
+-					tvee->MAC_address[0] = 0x00;
+-					tvee->MAC_address[1] = 0x0D;
+-					tvee->MAC_address[2] = 0xFE;
+-					tvee->MAC_address[3] = eeprom_data[i + 7];
+-					tvee->MAC_address[4] = eeprom_data[i + 6];
+-					tvee->MAC_address[5] = eeprom_data[i + 5];
+-					tvee->has_MAC_address = 1;
+-				}
++			if ((eeprom_data[i + 8] & 0xf0) &&
++					(tvee->serial_number < 0xffffff)) {
++				tvee->MAC_address[0] = 0x00;
++				tvee->MAC_address[1] = 0x0D;
++				tvee->MAC_address[2] = 0xFE;
++				tvee->MAC_address[3] = eeprom_data[i + 7];
++				tvee->MAC_address[4] = eeprom_data[i + 6];
++				tvee->MAC_address[5] = eeprom_data[i + 5];
++				tvee->has_MAC_address = 1;
++			}
+ 			break;
  
- /*---------------------------------------------------------------------*/
+ 		case 0x05:
+@@ -537,7 +550,7 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
+ 				(eeprom_data[i + 3] << 16) +
+ 				(eeprom_data[i + 4] << 24);
+ 			tvee->revision =
+-				eeprom_data[i +5 ] +
++				eeprom_data[i + 5] +
+ 				(eeprom_data[i + 6] << 8) +
+ 				(eeprom_data[i + 7] << 16);
+ 			break;
+@@ -557,16 +570,16 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
+ 		case 0x0a:
+ 			/* tag 'Tuner' */
+ 			if (beenhere == 0) {
+-				tuner1 = eeprom_data[i+2];
+-				t_format1 = eeprom_data[i+1];
++				tuner1 = eeprom_data[i + 2];
++				t_format1 = eeprom_data[i + 1];
+ 				beenhere = 1;
+ 			} else {
+ 				/* a second (radio) tuner may be present */
+-				tuner2 = eeprom_data[i+2];
+-				t_format2 = eeprom_data[i+1];
+-				if (t_format2 == 0) {  /* not a TV tuner? */
++				tuner2 = eeprom_data[i + 2];
++				t_format2 = eeprom_data[i + 1];
++				/* not a TV tuner? */
++				if (t_format2 == 0)
+ 					tvee->has_radio = 1; /* must be radio */
+-				}
+ 			}
+ 			break;
  
--static int tda8290_has_signal(struct dvb_frontend *fe)
-+static void tda8295_agc1_out(struct dvb_frontend *fe, int enable)
- {
--	struct tda8290_priv *priv = fe->tuner_priv;
--	int ret;
-+	struct tda8290_priv *priv = fe->analog_demod_priv;
-+	unsigned char buf[] = { 0x02, 0x00 }; /* DIV_FUNC */
+@@ -594,7 +607,8 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
+ 		/* case 0x12: tag 'InfoBits' */
  
--	unsigned char i2c_get_afc[1] = { 0x1B };
--	unsigned char afc = 0;
-+	tuner_i2c_xfer_send(&priv->i2c_props, &buf[0], 1);
-+	tuner_i2c_xfer_recv(&priv->i2c_props, &buf[1], 1);
+ 		default:
+-			tveeprom_dbg("Not sure what to do with tag [%02x]\n", tag);
++			tveeprom_dbg("Not sure what to do with tag [%02x]\n",
++					tag);
+ 			/* dump the rest of the packet? */
+ 		}
+ 	}
+@@ -608,7 +622,7 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
+ 		tvee->rev_str[0] = 32 + ((tvee->revision >> 18) & 0x3f);
+ 		tvee->rev_str[1] = 32 + ((tvee->revision >> 12) & 0x3f);
+ 		tvee->rev_str[2] = 32 + ((tvee->revision >>  6) & 0x3f);
+-		tvee->rev_str[3] = 32 + ( tvee->revision        & 0x3f);
++		tvee->rev_str[3] = 32 + (tvee->revision & 0x3f);
+ 		tvee->rev_str[4] = 0;
+ 	}
  
--	/* for now, report based on afc status */
--	tuner_i2c_xfer_send(&priv->i2c_props, i2c_get_afc, ARRAY_SIZE(i2c_get_afc));
--	tuner_i2c_xfer_recv(&priv->i2c_props, &afc, 1);
-+	if (enable)
-+		buf[1] &= ~0x40;
-+	else
-+		buf[1] |= 0x40;
+@@ -651,44 +665,40 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
  
--	ret = (afc & 0x80) ? 65535 : 0;
-+	tuner_i2c_xfer_send(&priv->i2c_props, buf, 2);
-+}
-+
-+static void tda8295_agc2_out(struct dvb_frontend *fe, int enable)
-+{
-+	struct tda8290_priv *priv = fe->analog_demod_priv;
-+	unsigned char set_gpio_cf[]    = { 0x44, 0x00 };
-+	unsigned char set_gpio_val[]   = { 0x46, 0x00 };
-+
-+	tuner_i2c_xfer_send(&priv->i2c_props, &set_gpio_cf[0], 1);
-+	tuner_i2c_xfer_recv(&priv->i2c_props, &set_gpio_cf[1], 1);
-+	tuner_i2c_xfer_send(&priv->i2c_props, &set_gpio_val[0], 1);
-+	tuner_i2c_xfer_recv(&priv->i2c_props, &set_gpio_val[1], 1);
+ 	tveeprom_info("Hauppauge model %d, rev %s, serial# %d\n",
+ 		tvee->model, tvee->rev_str, tvee->serial_number);
+-	if (tvee->has_MAC_address == 1) {
++	if (tvee->has_MAC_address == 1)
+ 		tveeprom_info("MAC address is %02X-%02X-%02X-%02X-%02X-%02X\n",
+ 			tvee->MAC_address[0], tvee->MAC_address[1],
+ 			tvee->MAC_address[2], tvee->MAC_address[3],
+ 			tvee->MAC_address[4], tvee->MAC_address[5]);
+-	}
+ 	tveeprom_info("tuner model is %s (idx %d, type %d)\n",
+ 		t_name1, tuner1, tvee->tuner_type);
+ 	tveeprom_info("TV standards%s%s%s%s%s%s%s%s (eeprom 0x%02x)\n",
+-		t_fmt_name1[0], t_fmt_name1[1], t_fmt_name1[2], t_fmt_name1[3],
+-		t_fmt_name1[4], t_fmt_name1[5], t_fmt_name1[6], t_fmt_name1[7],
+-		t_format1);
+-	if (tuner2) {
++		t_fmt_name1[0], t_fmt_name1[1], t_fmt_name1[2],
++		t_fmt_name1[3],	t_fmt_name1[4], t_fmt_name1[5],
++		t_fmt_name1[6], t_fmt_name1[7],	t_format1);
++	if (tuner2)
+ 		tveeprom_info("second tuner model is %s (idx %d, type %d)\n",
+ 					t_name2, tuner2, tvee->tuner2_type);
+-	}
+-	if (t_format2) {
++	if (t_format2)
+ 		tveeprom_info("TV standards%s%s%s%s%s%s%s%s (eeprom 0x%02x)\n",
+-			t_fmt_name2[0], t_fmt_name2[1], t_fmt_name2[2], t_fmt_name2[3],
+-			t_fmt_name2[4], t_fmt_name2[5], t_fmt_name2[6], t_fmt_name2[7],
+-			t_format2);
+-	}
+-	if (audioic<0) {
++			t_fmt_name2[0], t_fmt_name2[1], t_fmt_name2[2],
++			t_fmt_name2[3],	t_fmt_name2[4], t_fmt_name2[5],
++			t_fmt_name2[6], t_fmt_name2[7], t_format2);
++	if (audioic < 0) {
+ 		tveeprom_info("audio processor is unknown (no idx)\n");
+-		tvee->audio_processor=AUDIO_CHIP_UNKNOWN;
++		tvee->audio_processor = AUDIO_CHIP_UNKNOWN;
+ 	} else {
+ 		if (audioic < ARRAY_SIZE(audioIC))
+ 			tveeprom_info("audio processor is %s (idx %d)\n",
+-					audioIC[audioic].name,audioic);
++					audioIC[audioic].name, audioic);
+ 		else
+ 			tveeprom_info("audio processor is unknown (idx %d)\n",
+ 								audioic);
+ 	}
+-	if (tvee->decoder_processor) {
++	if (tvee->decoder_processor)
+ 		tveeprom_info("decoder processor is %s (idx %d)\n",
+ 			STRM(decoderIC, tvee->decoder_processor),
+ 			tvee->decoder_processor);
+-	}
+ 	if (tvee->has_ir == -1)
+ 		tveeprom_info("has %sradio\n",
+ 				tvee->has_radio ? "" : "no ");
+@@ -709,11 +719,13 @@ int tveeprom_read(struct i2c_client *c, unsigned char *eedata, int len)
+ 	int err;
  
--	tuner_dbg("AFC status: %d\n", ret);
-+	set_gpio_cf[1] &= 0xf0; /* clear GPIO_0 bits 3-0 */
+ 	buf = 0;
+-	if (1 != (err = i2c_master_send(c, &buf, 1))) {
++	err = i2c_master_send(c, &buf, 1);
++	if (err != 1) {
+ 		tveeprom_info("Huh, no eeprom present (err=%d)?\n", err);
+ 		return -1;
+ 	}
+-	if (len != (err = i2c_master_recv(c, eedata, len))) {
++	err = i2c_master_recv(c, eedata, len);
++	if (err != len) {
+ 		tveeprom_warn("i2c eeprom read error (err=%d)\n", err);
+ 		return -1;
+ 	}
+@@ -724,9 +736,9 @@ int tveeprom_read(struct i2c_client *c, unsigned char *eedata, int len)
+ 		for (i = 0; i < len; i++) {
+ 			if (0 == (i % 16))
+ 				tveeprom_info("%02x:", i);
+-			printk(" %02x", eedata[i]);
++			printk(KERN_CONT " %02x", eedata[i]);
+ 			if (15 == (i % 16))
+-				printk("\n");
++				printk(KERN_CONT "\n");
+ 		}
+ 	}
+ 	return 0;
+@@ -758,9 +770,9 @@ tveeprom_command(struct i2c_client *client,
  
--	return ret;
-+	if (enable) {
-+		set_gpio_cf[1]  |= 0x01; /* config GPIO_0 as Open Drain Out */
-+		set_gpio_val[1] &= 0xfe; /* set GPIO_0 pin low */
-+	}
-+	tuner_i2c_xfer_send(&priv->i2c_props, set_gpio_cf, 2);
-+	tuner_i2c_xfer_send(&priv->i2c_props, set_gpio_val, 2);
+ 	switch (cmd) {
+ 	case 0:
+-		buf = kzalloc(256,GFP_KERNEL);
+-		tveeprom_read(client,buf,256);
+-		tveeprom_hauppauge_analog(client, &eeprom,buf);
++		buf = kzalloc(256, GFP_KERNEL);
++		tveeprom_read(client, buf, 256);
++		tveeprom_hauppauge_analog(client, &eeprom, buf);
+ 		kfree(buf);
+ 		eeprom_props[0] = eeprom.tuner_type;
+ 		eeprom_props[1] = eeprom.tuner_formats;
+@@ -794,7 +806,7 @@ tveeprom_detect_client(struct i2c_adapter *adapter,
  }
  
--static int tda8290_get_status(struct dvb_frontend *fe, u32 *status)
-+static int tda8295_has_signal(struct dvb_frontend *fe)
+ static int
+-tveeprom_attach_adapter (struct i2c_adapter *adapter)
++tveeprom_attach_adapter(struct i2c_adapter *adapter)
  {
--	*status = 0;
-+	struct tda8290_priv *priv = fe->analog_demod_priv;
- 
--	if (tda8290_has_signal(fe))
--		*status = TUNER_STATUS_LOCKED;
-+	unsigned char hvpll_stat = 0x26;
-+	unsigned char ret;
- 
--	return 0;
-+	tuner_i2c_xfer_send(&priv->i2c_props, &hvpll_stat, 1);
-+	tuner_i2c_xfer_recv(&priv->i2c_props, &ret, 1);
-+	return (ret & 0x01) ? 65535 : 0;
+ 	if (adapter->class & I2C_CLASS_TV_ANALOG)
+ 		return i2c_probe(adapter, &addr_data, tveeprom_detect_client);
+@@ -802,7 +814,7 @@ tveeprom_attach_adapter (struct i2c_adapter *adapter)
  }
  
--static int tda8290_get_rf_strength(struct dvb_frontend *fe, u16 *strength)
-+/*---------------------------------------------------------------------*/
-+
-+static void tda8295_set_params(struct dvb_frontend *fe,
-+			       struct analog_parameters *params)
+ static int
+-tveeprom_detach_client (struct i2c_client *client)
++tveeprom_detach_client(struct i2c_client *client)
  {
--	*strength = tda8290_has_signal(fe);
-+	struct tda8290_priv *priv = fe->analog_demod_priv;
+ 	int err;
  
--	return 0;
-+	unsigned char blanking_mode[]     = { 0x1d, 0x00 };
-+
-+	set_audio(fe, params);
-+
-+	tuner_dbg("%s: freq = %d\n", __FUNCTION__, params->frequency);
-+
-+	tda8295_power(fe, 1);
-+	tda8295_agc1_out(fe, 1);
-+
-+	tuner_i2c_xfer_send(&priv->i2c_props, &blanking_mode[0], 1);
-+	tuner_i2c_xfer_recv(&priv->i2c_props, &blanking_mode[1], 1);
-+
-+	tda8295_set_video_std(fe);
-+
-+	blanking_mode[1] = 0x03;
-+	tuner_i2c_xfer_send(&priv->i2c_props, blanking_mode, 2);
-+	msleep(20);
-+
-+	tda8295_i2c_bridge(fe, 1);
-+
-+	if (fe->ops.tuner_ops.set_analog_params)
-+		fe->ops.tuner_ops.set_analog_params(fe, params);
-+
-+	if (priv->cfg.agcf)
-+		priv->cfg.agcf(fe);
-+
-+	if (tda8295_has_signal(fe))
-+		tuner_dbg("tda8295 is locked\n");
-+	else
-+		tuner_dbg("tda8295 not locked, no signal?\n");
-+
-+	tda8295_i2c_bridge(fe, 0);
-+}
-+
-+/*---------------------------------------------------------------------*/
-+
-+static int tda8290_has_signal(struct dvb_frontend *fe)
-+{
-+	struct tda8290_priv *priv = fe->analog_demod_priv;
-+
-+	unsigned char i2c_get_afc[1] = { 0x1B };
-+	unsigned char afc = 0;
-+
-+	tuner_i2c_xfer_send(&priv->i2c_props, i2c_get_afc, ARRAY_SIZE(i2c_get_afc));
-+	tuner_i2c_xfer_recv(&priv->i2c_props, &afc, 1);
-+	return (afc & 0x80)? 65535:0;
- }
+diff --git a/drivers/media/video/upd64031a.c b/drivers/media/video/upd64031a.c
+index 0b2a961..bd20139 100644
+--- a/drivers/media/video/upd64031a.c
++++ b/drivers/media/video/upd64031a.c
+@@ -28,30 +28,27 @@
+ #include <linux/videodev2.h>
+ #include <media/v4l2-common.h>
+ #include <media/v4l2-chip-ident.h>
++#include <media/v4l2-i2c-drv.h>
+ #include <media/upd64031a.h>
  
- /*---------------------------------------------------------------------*/
+-// --------------------- read registers functions define -----------------------
++/* --------------------- read registers functions define -------------------- */
  
--static int tda8290_standby(struct dvb_frontend *fe)
-+static void tda8290_standby(struct dvb_frontend *fe)
- {
--	struct tda8290_priv *priv = fe->tuner_priv;
-+	struct tda8290_priv *priv = fe->analog_demod_priv;
-+
- 	unsigned char cb1[] = { 0x30, 0xD0 };
- 	unsigned char tda8290_standby[] = { 0x00, 0x02 };
- 	unsigned char tda8290_agc_tri[] = { 0x02, 0x20 };
- 	struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags=0, .buf=cb1, .len = 2};
+ /* bit masks */
+ #define GR_MODE_MASK              0xc0
+ #define DIRECT_3DYCS_CONNECT_MASK 0xc0
+ #define SYNC_CIRCUIT_MASK         0xa0
  
- 	tda8290_i2c_bridge(fe, 1);
--	if (priv->tda827x_ver != 0)
-+	if (priv->ver & TDA8275A)
- 		cb1[1] = 0x90;
- 	i2c_transfer(priv->i2c_props.adap, &msg, 1);
- 	tda8290_i2c_bridge(fe, 0);
- 	tuner_i2c_xfer_send(&priv->i2c_props, tda8290_agc_tri, 2);
- 	tuner_i2c_xfer_send(&priv->i2c_props, tda8290_standby, 2);
--
--	return 0;
- }
+-// -----------------------------------------------------------------------------
++/* -------------------------------------------------------------------------- */
  
-+static void tda8295_standby(struct dvb_frontend *fe)
-+{
-+	tda8295_agc1_out(fe, 0); /* Put AGC in tri-state */
-+
-+	tda8295_power(fe, 0);
-+}
+ MODULE_DESCRIPTION("uPD64031A driver");
+ MODULE_AUTHOR("T. Adachi, Takeru KOMORIYA, Hans Verkuil");
+ MODULE_LICENSE("GPL");
  
- static void tda8290_init_if(struct dvb_frontend *fe)
- {
--	struct tda8290_priv *priv = fe->tuner_priv;
-+	struct tda8290_priv *priv = fe->analog_demod_priv;
+-static int debug = 0;
++static int debug;
+ module_param(debug, int, 0644);
  
- 	unsigned char set_VS[] = { 0x30, 0x6F };
- 	unsigned char set_GP00_CF[] = { 0x20, 0x01 };
- 	unsigned char set_GP01_CF[] = { 0x20, 0x0B };
+ MODULE_PARM_DESC(debug, "Debug level (0-1)");
  
--	if ((priv->lna_cfg) &&
--	    ((*priv->lna_cfg == 1) || (*priv->lna_cfg == 2)))
-+	if ((priv->cfg.config) &&
-+	    ((*priv->cfg.config == 1) || (*priv->cfg.config == 2)))
- 		tuner_i2c_xfer_send(&priv->i2c_props, set_GP00_CF, 2);
- 	else
- 		tuner_i2c_xfer_send(&priv->i2c_props, set_GP01_CF, 2);
- 	tuner_i2c_xfer_send(&priv->i2c_props, set_VS, 2);
- }
+-static unsigned short normal_i2c[] = { 0x24 >> 1, 0x26 >> 1, I2C_CLIENT_END };
+-
+-
+-I2C_CLIENT_INSMOD;
  
-+static void tda8295_init_if(struct dvb_frontend *fe)
-+{
-+	struct tda8290_priv *priv = fe->analog_demod_priv;
-+
-+	static unsigned char set_adc_ctl[]       = { 0x33, 0x14 };
-+	static unsigned char set_adc_ctl2[]      = { 0x34, 0x00 };
-+	static unsigned char set_pll_reg6[]      = { 0x3e, 0x63 };
-+	static unsigned char set_pll_reg0[]      = { 0x38, 0x23 };
-+	static unsigned char set_pll_reg7[]      = { 0x3f, 0x01 };
-+	static unsigned char set_pll_reg10[]     = { 0x42, 0x61 };
-+	static unsigned char set_gpio_reg0[]     = { 0x44, 0x0b };
-+
-+	tda8295_power(fe, 1);
-+
-+	tda8295_set_easy_mode(fe, 0);
-+	tda8295_set_video_std(fe);
-+
-+	tuner_i2c_xfer_send(&priv->i2c_props, set_adc_ctl, 2);
-+	tuner_i2c_xfer_send(&priv->i2c_props, set_adc_ctl2, 2);
-+	tuner_i2c_xfer_send(&priv->i2c_props, set_pll_reg6, 2);
-+	tuner_i2c_xfer_send(&priv->i2c_props, set_pll_reg0, 2);
-+	tuner_i2c_xfer_send(&priv->i2c_props, set_pll_reg7, 2);
-+	tuner_i2c_xfer_send(&priv->i2c_props, set_pll_reg10, 2);
-+	tuner_i2c_xfer_send(&priv->i2c_props, set_gpio_reg0, 2);
-+
-+	tda8295_agc1_out(fe, 0);
-+	tda8295_agc2_out(fe, 0);
-+}
-+
- static void tda8290_init_tuner(struct dvb_frontend *fe)
- {
--	struct tda8290_priv *priv = fe->tuner_priv;
-+	struct tda8290_priv *priv = fe->analog_demod_priv;
- 	unsigned char tda8275_init[]  = { 0x00, 0x00, 0x00, 0x40, 0xdC, 0x04, 0xAf,
- 					  0x3F, 0x2A, 0x04, 0xFF, 0x00, 0x00, 0x40 };
- 	unsigned char tda8275a_init[] = { 0x00, 0x00, 0x00, 0x00, 0xdC, 0x05, 0x8b,
- 					  0x0c, 0x04, 0x20, 0xFF, 0x00, 0x00, 0x4b };
- 	struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags=0,
- 			      .buf=tda8275_init, .len = 14};
--	if (priv->tda827x_ver != 0)
-+	if (priv->ver & TDA8275A)
- 		msg.buf = tda8275a_init;
+ enum {
+ 	R00 = 0, R01, R02, R03, R04,
+@@ -99,7 +96,7 @@ static void upd64031a_write(struct i2c_client *client, u8 reg, u8 val)
  
- 	tda8290_i2c_bridge(fe, 1);
-@@ -643,58 +500,42 @@ static void tda8290_init_tuner(struct dvb_frontend *fe)
+ 	buf[0] = reg;
+ 	buf[1] = val;
+-	v4l_dbg(1, debug, client, "writing reg addr: %02X val: %02X\n", reg, val);
++	v4l_dbg(1, debug, client, "write reg: %02X val: %02X\n", reg, val);
+ 	if (i2c_master_send(client, buf, 2) != 2)
+ 		v4l_err(client, "I/O error write 0x%02x/0x%02x\n", reg, val);
+ }
+@@ -119,7 +116,7 @@ static void upd64031a_change(struct i2c_client *client)
  
- /*---------------------------------------------------------------------*/
+ /* ------------------------------------------------------------------------ */
  
--static int tda8290_release(struct dvb_frontend *fe)
-+static void tda829x_release(struct dvb_frontend *fe)
+-static int upd64031a_command(struct i2c_client *client, unsigned int cmd, void *arg)
++static int upd64031a_command(struct i2c_client *client, unsigned cmd, void *arg)
  {
--	kfree(fe->tuner_priv);
--	fe->tuner_priv = NULL;
-+	struct tda8290_priv *priv = fe->analog_demod_priv;
- 
--	return 0;
--}
-+	/* only try to release the tuner if we've
-+	 * attached it from within this module */
-+	if (priv->ver & (TDA18271 | TDA8275 | TDA8275A))
-+		if (fe->ops.tuner_ops.release)
-+			fe->ops.tuner_ops.release(fe);
+ 	struct upd64031a_state *state = i2c_get_clientdata(client);
+ 	struct v4l2_routing *route = arg;
+@@ -143,8 +140,10 @@ static int upd64031a_command(struct i2c_client *client, unsigned int cmd, void *
  
--static int tda8290_get_frequency(struct dvb_frontend *fe, u32 *frequency)
--{
--	struct tda8290_priv *priv = fe->tuner_priv;
--	*frequency = priv->frequency;
--	return 0;
-+	kfree(fe->analog_demod_priv);
-+	fe->analog_demod_priv = NULL;
- }
+ 		state->gr_mode = (route->input & 3) << 6;
+ 		state->direct_3dycs_connect = (route->input & 0xc) << 4;
+-		state->ext_comp_sync = (route->input & UPD64031A_COMPOSITE_EXTERNAL) << 1;
+-		state->ext_vert_sync = (route->input & UPD64031A_VERTICAL_EXTERNAL) << 2;
++		state->ext_comp_sync =
++			(route->input & UPD64031A_COMPOSITE_EXTERNAL) << 1;
++		state->ext_vert_sync =
++			(route->input & UPD64031A_VERTICAL_EXTERNAL) << 2;
+ 		r00 = (state->regs[R00] & ~GR_MODE_MASK) | state->gr_mode;
+ 		r05 = (state->regs[R00] & ~SYNC_CIRCUIT_MASK) |
+ 			state->ext_comp_sync | state->ext_vert_sync;
+@@ -168,20 +167,23 @@ static int upd64031a_command(struct i2c_client *client, unsigned int cmd, void *
+ 	{
+ 		struct v4l2_register *reg = arg;
  
--static struct dvb_tuner_ops tda8290_tuner_ops = {
--	.sleep             = tda8290_standby,
--	.set_analog_params = tda8290_set_params,
--	.release           = tda8290_release,
--	.get_frequency     = tda8290_get_frequency,
--	.get_status        = tda8290_get_status,
--	.get_rf_strength   = tda8290_get_rf_strength,
-+static struct tda18271_config tda829x_tda18271_config = {
-+	.gate    = TDA18271_GATE_ANALOG,
- };
+-		if (!v4l2_chip_match_i2c_client(client, reg->match_type, reg->match_chip))
++		if (!v4l2_chip_match_i2c_client(client,
++					reg->match_type, reg->match_chip))
+ 			return -EINVAL;
+ 		if (!capable(CAP_SYS_ADMIN))
+ 			return -EPERM;
+-		if (cmd == VIDIOC_DBG_G_REGISTER)
++		if (cmd == VIDIOC_DBG_G_REGISTER) {
+ 			reg->val = upd64031a_read(client, reg->reg & 0xff);
+-		else
+-			upd64031a_write(client, reg->reg & 0xff, reg->val & 0xff);
++			break;
++		}
++		upd64031a_write(client, reg->reg & 0xff, reg->val & 0xff);
+ 		break;
+ 	}
+ #endif
  
--struct dvb_frontend *tda8290_attach(struct dvb_frontend *fe,
--				    struct i2c_adapter* i2c_adap,
--				    u8 i2c_addr,
--				    struct tda8290_config *cfg)
-+static int tda829x_find_tuner(struct dvb_frontend *fe)
- {
--	struct tda8290_priv *priv = NULL;
--	u8 data;
-+	struct tda8290_priv *priv = fe->analog_demod_priv;
-+	struct analog_demod_ops *analog_ops = &fe->ops.analog_ops;
- 	int i, ret, tuners_found;
- 	u32 tuner_addrs;
--	struct i2c_msg msg = {.flags=I2C_M_RD, .buf=&data, .len = 1};
-+	u8 data;
-+	struct i2c_msg msg = { .flags = I2C_M_RD, .buf = &data, .len = 1 };
+ 	case VIDIOC_G_CHIP_IDENT:
+-		return v4l2_chip_ident_i2c_client(client, arg, V4L2_IDENT_UPD64031A, 0);
++		return v4l2_chip_ident_i2c_client(client, arg,
++				V4L2_IDENT_UPD64031A, 0);
  
--	priv = kzalloc(sizeof(struct tda8290_priv), GFP_KERNEL);
--	if (priv == NULL)
--		return NULL;
--	fe->tuner_priv = priv;
-+	if (NULL == analog_ops->i2c_gate_ctrl)
-+		return -EINVAL;
+ 	default:
+ 		break;
+@@ -193,90 +195,43 @@ static int upd64031a_command(struct i2c_client *client, unsigned int cmd, void *
  
--	priv->i2c_props.addr = i2c_addr;
--	priv->i2c_props.adap = i2c_adap;
--	if (cfg) {
--		priv->lna_cfg        = cfg->lna_cfg;
--		priv->tuner_callback = cfg->tuner_callback;
--	}
-+	analog_ops->i2c_gate_ctrl(fe, 1);
+ /* i2c implementation */
  
--	tda8290_i2c_bridge(fe, 1);
- 	/* probe for tuner chip */
- 	tuners_found = 0;
- 	tuner_addrs = 0;
--	for (i=0x60; i<= 0x63; i++) {
-+	for (i = 0x60; i <= 0x63; i++) {
- 		msg.addr = i;
- 		ret = i2c_transfer(priv->i2c_props.adap, &msg, 1);
- 		if (ret == 1) {
-@@ -706,20 +547,23 @@ struct dvb_frontend *tda8290_attach(struct dvb_frontend *fe,
- 	   behind the bridge and we choose the highest address that doesn't
- 	   give a response now
- 	 */
--	tda8290_i2c_bridge(fe, 0);
--	if(tuners_found > 1)
-+
-+	analog_ops->i2c_gate_ctrl(fe, 0);
-+
-+	if (tuners_found > 1)
- 		for (i = 0; i < tuners_found; i++) {
- 			msg.addr = tuner_addrs  & 0xff;
- 			ret = i2c_transfer(priv->i2c_props.adap, &msg, 1);
--			if(ret == 1)
-+			if (ret == 1)
- 				tuner_addrs = tuner_addrs >> 8;
- 			else
- 				break;
- 		}
-+
- 	if (tuner_addrs == 0) {
--		tuner_addrs = 0x61;
--		tuner_info("could not clearly identify tuner address, defaulting to %x\n",
--			     tuner_addrs);
-+		tuner_addrs = 0x60;
-+		tuner_info("could not clearly identify tuner address, "
-+			   "defaulting to %x\n", tuner_addrs);
- 	} else {
- 		tuner_addrs = tuner_addrs & 0xff;
- 		tuner_info("setting tuner address to %x\n", tuner_addrs);
-@@ -727,42 +571,181 @@ struct dvb_frontend *tda8290_attach(struct dvb_frontend *fe,
- 	priv->tda827x_addr = tuner_addrs;
- 	msg.addr = tuner_addrs;
+-static struct i2c_driver i2c_driver;
+-
+-static int upd64031a_attach(struct i2c_adapter *adapter, int address, int kind)
++static int upd64031a_probe(struct i2c_client *client)
+ {
+-	struct i2c_client *client;
+ 	struct upd64031a_state *state;
+ 	int i;
  
--	tda8290_i2c_bridge(fe, 1);
-+	analog_ops->i2c_gate_ctrl(fe, 1);
- 	ret = i2c_transfer(priv->i2c_props.adap, &msg, 1);
--	if( ret != 1)
--		tuner_warn("TDA827x access failed!\n");
+-	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+-		return 0;
 -
--	memcpy(&fe->ops.tuner_ops, &tda8290_tuner_ops,
--	       sizeof(struct dvb_tuner_ops));
+-	client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
+-	if (client == NULL) {
+-		return -ENOMEM;
+-	}
 -
--	if ((data & 0x3c) == 0) {
--		strlcpy(fe->ops.tuner_ops.info.name, "tda8290+75",
--			sizeof(fe->ops.tuner_ops.info.name));
--		fe->ops.tuner_ops.info.frequency_min  =  55000000;
--		fe->ops.tuner_ops.info.frequency_max  = 860000000;
--		fe->ops.tuner_ops.info.frequency_step =    250000;
--		priv->tda827x_ver = 0;
-+
-+	if (ret != 1) {
-+		tuner_warn("tuner access failed!\n");
-+		return -EREMOTEIO;
-+	}
-+
-+	if ((data == 0x83) || (data == 0x84)) {
-+		priv->ver |= TDA18271;
-+		tda18271_attach(fe, priv->tda827x_addr,
-+				priv->i2c_props.adap,
-+				&tda829x_tda18271_config);
- 	} else {
--		strlcpy(fe->ops.tuner_ops.info.name, "tda8290+75a",
--			sizeof(fe->ops.tuner_ops.info.name));
--		fe->ops.tuner_ops.info.frequency_min  =  44000000;
--		fe->ops.tuner_ops.info.frequency_max  = 906000000;
--		fe->ops.tuner_ops.info.frequency_step =     62500;
--		priv->tda827x_ver = 2;
-+		if ((data & 0x3c) == 0)
-+			priv->ver |= TDA8275;
-+		else
-+			priv->ver |= TDA8275A;
-+
-+		tda827x_attach(fe, priv->tda827x_addr,
-+			       priv->i2c_props.adap, &priv->cfg);
-+	}
-+	if (fe->ops.tuner_ops.init)
-+		fe->ops.tuner_ops.init(fe);
-+
-+	if (fe->ops.tuner_ops.sleep)
-+		fe->ops.tuner_ops.sleep(fe);
-+
-+	analog_ops->i2c_gate_ctrl(fe, 0);
-+
-+	return 0;
-+}
-+
-+static int tda8290_probe(struct tuner_i2c_props *i2c_props)
-+{
-+#define TDA8290_ID 0x89
-+	unsigned char tda8290_id[] = { 0x1f, 0x00 };
-+
-+	/* detect tda8290 */
-+	tuner_i2c_xfer_send(i2c_props, &tda8290_id[0], 1);
-+	tuner_i2c_xfer_recv(i2c_props, &tda8290_id[1], 1);
-+
-+	if (tda8290_id[1] == TDA8290_ID) {
-+		if (debug)
-+			printk(KERN_DEBUG "%s: tda8290 detected @ %d-%04x\n",
-+			       __FUNCTION__, i2c_adapter_id(i2c_props->adap),
-+			       i2c_props->addr);
-+		return 0;
-+	}
-+
-+	return -ENODEV;
-+}
-+
-+static int tda8295_probe(struct tuner_i2c_props *i2c_props)
-+{
-+#define TDA8295_ID 0x8a
-+	unsigned char tda8295_id[] = { 0x2f, 0x00 };
-+
-+	/* detect tda8295 */
-+	tuner_i2c_xfer_send(i2c_props, &tda8295_id[0], 1);
-+	tuner_i2c_xfer_recv(i2c_props, &tda8295_id[1], 1);
-+
-+	if (tda8295_id[1] == TDA8295_ID) {
-+		if (debug)
-+			printk(KERN_DEBUG "%s: tda8295 detected @ %d-%04x\n",
-+			       __FUNCTION__, i2c_adapter_id(i2c_props->adap),
-+			       i2c_props->addr);
-+		return 0;
- 	}
+-	client->addr = address;
+-	client->adapter = adapter;
+-	client->driver = &i2c_driver;
+-	snprintf(client->name, sizeof(client->name) - 1, "uPD64031A");
++	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
++		return -EIO;
  
--	priv->tda827x_lpsel = 0;
-+	return -ENODEV;
-+}
-+
-+static struct analog_demod_ops tda8290_ops = {
-+	.set_params     = tda8290_set_params,
-+	.has_signal     = tda8290_has_signal,
-+	.standby        = tda8290_standby,
-+	.release        = tda829x_release,
-+	.i2c_gate_ctrl  = tda8290_i2c_bridge,
-+};
-+
-+static struct analog_demod_ops tda8295_ops = {
-+	.set_params     = tda8295_set_params,
-+	.has_signal     = tda8295_has_signal,
-+	.standby        = tda8295_standby,
-+	.release        = tda829x_release,
-+	.i2c_gate_ctrl  = tda8295_i2c_bridge,
-+};
-+
-+struct dvb_frontend *tda829x_attach(struct dvb_frontend *fe,
-+				    struct i2c_adapter *i2c_adap, u8 i2c_addr,
-+				    struct tda829x_config *cfg)
-+{
-+	struct tda8290_priv *priv = NULL;
-+	char *name;
-+
-+	priv = kzalloc(sizeof(struct tda8290_priv), GFP_KERNEL);
-+	if (priv == NULL)
-+		return NULL;
-+	fe->analog_demod_priv = priv;
-+
-+	priv->i2c_props.addr     = i2c_addr;
-+	priv->i2c_props.adap     = i2c_adap;
-+	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;
-+		memcpy(&fe->ops.analog_ops, &tda8290_ops,
-+		       sizeof(struct analog_demod_ops));
-+	}
-+
-+	if (tda8295_probe(&priv->i2c_props) == 0) {
-+		priv->ver = TDA8295;
-+		memcpy(&fe->ops.analog_ops, &tda8295_ops,
-+		       sizeof(struct analog_demod_ops));
-+	}
-+
-+	if ((!(cfg) || (TDA829X_PROBE_TUNER == cfg->probe_tuner)) &&
-+	    (tda829x_find_tuner(fe) < 0))
-+		goto fail;
-+
-+	switch (priv->ver) {
-+	case TDA8290:
-+		name = "tda8290";
-+		break;
-+	case TDA8295:
-+		name = "tda8295";
-+		break;
-+	case TDA8290 | TDA8275:
-+		name = "tda8290+75";
-+		break;
-+	case TDA8295 | TDA8275:
-+		name = "tda8295+75";
-+		break;
-+	case TDA8290 | TDA8275A:
-+		name = "tda8290+75a";
-+		break;
-+	case TDA8295 | TDA8275A:
-+		name = "tda8295+75a";
-+		break;
-+	case TDA8290 | TDA18271:
-+		name = "tda8290+18271";
-+		break;
-+	case TDA8295 | TDA18271:
-+		name = "tda8295+18271";
-+		break;
-+	default:
-+		goto fail;
-+	}
-+	tuner_info("type set to %s\n", name);
-+
-+	fe->ops.analog_ops.info.name = name;
-+
-+	if (priv->ver & TDA8290) {
-+		tda8290_init_tuner(fe);
-+		tda8290_init_if(fe);
-+	} else if (priv->ver & TDA8295)
-+		tda8295_init_if(fe);
+-	v4l_info(client, "chip found @ 0x%x (%s)\n", address << 1, adapter->name);
++	v4l_info(client, "chip found @ 0x%x (%s)\n",
++			client->addr << 1, client->adapter->name);
  
--	tda8290_init_tuner(fe);
--	tda8290_init_if(fe);
- 	return fe;
-+
-+fail:
-+	tda829x_release(fe);
-+	return NULL;
+ 	state = kmalloc(sizeof(struct upd64031a_state), GFP_KERNEL);
+-	if (state == NULL) {
+-		kfree(client);
++	if (state == NULL)
+ 		return -ENOMEM;
+-	}
+ 	i2c_set_clientdata(client, state);
+ 	memcpy(state->regs, upd64031a_init, sizeof(state->regs));
+ 	state->gr_mode = UPD64031A_GR_ON << 6;
+ 	state->direct_3dycs_connect = UPD64031A_3DYCS_COMPOSITE << 4;
+ 	state->ext_comp_sync = state->ext_vert_sync = 0;
+-	for (i = 0; i < TOT_REGS; i++) {
++	for (i = 0; i < TOT_REGS; i++)
+ 		upd64031a_write(client, i, state->regs[i]);
+-	}
+-
+-	i2c_attach_client(client);
+-
+ 	return 0;
  }
-+EXPORT_SYMBOL_GPL(tda829x_attach);
  
--int tda8290_probe(struct i2c_adapter* i2c_adap, u8 i2c_addr)
-+int tda829x_probe(struct i2c_adapter *i2c_adap, u8 i2c_addr)
+-static int upd64031a_probe(struct i2c_adapter *adapter)
++static int upd64031a_remove(struct i2c_client *client)
  {
- 	struct tuner_i2c_props i2c_props = {
- 		.adap = i2c_adap,
--		.addr = i2c_addr
-+		.addr = i2c_addr,
- 	};
+-	if (adapter->class & I2C_CLASS_TV_ANALOG)
+-		return i2c_probe(adapter, &addr_data, upd64031a_attach);
+-	return 0;
+-}
+-
+-static int upd64031a_detach(struct i2c_client *client)
+-{
+-	int err;
+-
+-	err = i2c_detach_client(client);
+-	if (err)
+-		return err;
+-
+-	kfree(client);
++	kfree(i2c_get_clientdata(client));
+ 	return 0;
+ }
  
- 	unsigned char soft_reset[]   = { 0x00, 0x00 };
-@@ -771,7 +754,27 @@ int tda8290_probe(struct i2c_adapter* i2c_adap, u8 i2c_addr)
- 	unsigned char restore_9886[] = { 0x00, 0xd6, 0x30 };
- 	unsigned char addr_dto_lsb = 0x07;
- 	unsigned char data;
-+#define PROBE_BUFFER_SIZE 8
-+	unsigned char buf[PROBE_BUFFER_SIZE];
-+	int i;
-+
-+	/* rule out tda9887, which would return the same byte repeatedly */
-+	tuner_i2c_xfer_send(&i2c_props, soft_reset, 1);
-+	tuner_i2c_xfer_recv(&i2c_props, buf, PROBE_BUFFER_SIZE);
-+	for (i = 1; i < PROBE_BUFFER_SIZE; i++) {
-+		if (buf[i] != buf[0])
-+			break;
-+	}
+ /* ----------------------------------------------------------------------- */
  
-+	/* all bytes are equal, not a tda829x - probably a tda9887 */
-+	if (i == PROBE_BUFFER_SIZE)
-+		return -ENODEV;
-+
-+	if ((tda8290_probe(&i2c_props) == 0) ||
-+	    (tda8295_probe(&i2c_props) == 0))
-+		return 0;
+-/* i2c implementation */
+-static struct i2c_driver i2c_driver = {
+-	.driver = {
+-		.name = "upd64031a",
+-	},
+-	.id = I2C_DRIVERID_UPD64031A,
+-	.attach_adapter = upd64031a_probe,
+-	.detach_client  = upd64031a_detach,
 +
-+	/* fall back to old probing method */
- 	tuner_i2c_xfer_send(&i2c_props, easy_mode_b, 2);
- 	tuner_i2c_xfer_send(&i2c_props, soft_reset, 2);
- 	tuner_i2c_xfer_send(&i2c_props, &addr_dto_lsb, 1);
-@@ -786,14 +789,12 @@ int tda8290_probe(struct i2c_adapter* i2c_adap, u8 i2c_addr)
- 		}
- 	}
- 	tuner_i2c_xfer_send(&i2c_props, restore_9886, 3);
--	return -1;
-+	return -ENODEV;
- }
-+EXPORT_SYMBOL_GPL(tda829x_probe);
- 
--EXPORT_SYMBOL_GPL(tda8290_probe);
--EXPORT_SYMBOL_GPL(tda8290_attach);
++static struct v4l2_i2c_driver_data v4l2_i2c_data = {
++	.name = "upd64031a",
++	.driverid = I2C_DRIVERID_UPD64031A,
+ 	.command = upd64031a_command,
++	.probe = upd64031a_probe,
++	.remove = upd64031a_remove,
+ };
 -
--MODULE_DESCRIPTION("Philips TDA8290 + TDA8275 / TDA8275a tuner driver");
--MODULE_AUTHOR("Gerd Knorr, Hartmut Hackmann");
-+MODULE_DESCRIPTION("Philips/NXP TDA8290/TDA8295 analog IF demodulator driver");
-+MODULE_AUTHOR("Gerd Knorr, Hartmut Hackmann, Michael Krufky");
+-
+-static int __init upd64031a_init_module(void)
+-{
+-	return i2c_add_driver(&i2c_driver);
+-}
+-
+-static void __exit upd64031a_exit_module(void)
+-{
+-	i2c_del_driver(&i2c_driver);
+-}
+-
+-module_init(upd64031a_init_module);
+-module_exit(upd64031a_exit_module);
+diff --git a/drivers/media/video/upd64083.c b/drivers/media/video/upd64083.c
+index 401bd21..2d9a88f 100644
+--- a/drivers/media/video/upd64083.c
++++ b/drivers/media/video/upd64083.c
+@@ -17,7 +17,8 @@
+  *
+  * You 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.
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
++ * 02110-1301, USA.
+  */
+ 
+ #include <linux/version.h>
+@@ -27,21 +28,18 @@
+ #include <linux/videodev2.h>
+ #include <media/v4l2-common.h>
+ #include <media/v4l2-chip-ident.h>
++#include <media/v4l2-i2c-drv.h>
+ #include <media/upd64083.h>
+ 
+ MODULE_DESCRIPTION("uPD64083 driver");
+ MODULE_AUTHOR("T. Adachi, Takeru KOMORIYA, Hans Verkuil");
  MODULE_LICENSE("GPL");
  
- /*
-diff --git a/drivers/media/video/tda8290.h b/drivers/media/video/tda8290.h
-index 107b24b..dc8ef31 100644
---- a/drivers/media/video/tda8290.h
-+++ b/drivers/media/video/tda8290.h
-@@ -20,33 +20,36 @@
- #include <linux/i2c.h>
- #include "dvb_frontend.h"
+-static int debug = 0;
++static int debug;
+ module_param(debug, bool, 0644);
  
--struct tda8290_config
--{
-+struct tda829x_config {
- 	unsigned int *lna_cfg;
--	int (*tuner_callback) (void *dev, int command,int arg);
-+	int (*tuner_callback) (void *dev, int command, int arg);
-+
-+	unsigned int probe_tuner:1;
-+#define TDA829X_PROBE_TUNER 0
-+#define TDA829X_DONT_PROBE  1
- };
+ MODULE_PARM_DESC(debug, "Debug level (0-1)");
  
- #if defined(CONFIG_TUNER_TDA8290) || (defined(CONFIG_TUNER_TDA8290_MODULE) && defined(MODULE))
--extern int tda8290_probe(struct i2c_adapter* i2c_adap, u8 i2c_addr);
-+extern int tda829x_probe(struct i2c_adapter *i2c_adap, u8 i2c_addr);
+-static unsigned short normal_i2c[] = { 0xb8 >> 1, 0xba >> 1, I2C_CLIENT_END };
+-
+-
+-I2C_CLIENT_INSMOD;
  
--extern struct dvb_frontend *tda8290_attach(struct dvb_frontend *fe,
--					   struct i2c_adapter* i2c_adap,
-+extern struct dvb_frontend *tda829x_attach(struct dvb_frontend *fe,
-+					   struct i2c_adapter *i2c_adap,
- 					   u8 i2c_addr,
--					   struct tda8290_config *cfg);
-+					   struct tda829x_config *cfg);
- #else
--static inline int tda8290_probe(struct i2c_adapter* i2c_adap, u8 i2c_addr)
-+static inline int tda829x_probe(struct i2c_adapter *i2c_adap, u8 i2c_addr)
- {
--	printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n",
--	       __FUNCTION__);
-+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
- 	return -EINVAL;
- }
+ enum {
+ 	R00 = 0, R01, R02, R03, R04,
+@@ -88,7 +86,7 @@ static void upd64083_write(struct i2c_client *client, u8 reg, u8 val)
  
--static inline struct dvb_frontend *tda8290_attach(struct dvb_frontend *fe,
--						  struct i2c_adapter* i2c_adap,
-+static inline struct dvb_frontend *tda829x_attach(struct dvb_frontend *fe,
-+						  struct i2c_adapter *i2c_adap,
- 						  u8 i2c_addr,
--						  struct tda8290_config *cfg)
-+						  struct tda829x_config *cfg)
- {
--	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
-+	printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n",
-+	       __FUNCTION__);
- 	return NULL;
- }
- #endif
-diff --git a/drivers/media/video/tda9875.c b/drivers/media/video/tda9875.c
-index d110441..3c05571 100644
---- a/drivers/media/video/tda9875.c
-+++ b/drivers/media/video/tda9875.c
-@@ -7,6 +7,7 @@
-  *
-  * Copyright (c) 2000 Guillaume Delvit based on Gerd Knorr source and
-  * Eric Sandeen
-+ * Copyright (c) 2006 Mauro Carvalho Chehab <mchehab at infradead.org>
-  * This code is placed under the terms of the GNU General Public License
-  * Based on tda9855.c by Steve VanDeBogart (vandebo at uclink.berkeley.edu)
-  * Which was based on tda8425.c by Greg Alexander (c) 1998
-@@ -268,87 +269,143 @@ static int tda9875_detach(struct i2c_client *client)
- 	return 0;
+ 	buf[0] = reg;
+ 	buf[1] = val;
+-	v4l_dbg(1, debug, client, "writing reg addr: %02x val: %02x\n", reg, val);
++	v4l_dbg(1, debug, client, "write reg: %02x val: %02x\n", reg, val);
+ 	if (i2c_master_send(client, buf, 2) != 2)
+ 		v4l_err(client, "I/O error write 0x%02x/0x%02x\n", reg, val);
  }
+@@ -109,7 +107,7 @@ static u8 upd64083_read(struct i2c_client *client, u8 reg)
  
--static int tda9875_command(struct i2c_client *client,
--				unsigned int cmd, void *arg)
-+static int tda9875_get_ctrl(struct i2c_client *client,
-+			    struct v4l2_control *ctrl)
+ /* ------------------------------------------------------------------------ */
+ 
+-static int upd64083_command(struct i2c_client *client, unsigned int cmd, void *arg)
++static int upd64083_command(struct i2c_client *client, unsigned cmd, void *arg)
  {
- 	struct tda9875 *t = i2c_get_clientdata(client);
+ 	struct upd64083_state *state = i2c_get_clientdata(client);
+ 	struct v4l2_routing *route = arg;
+@@ -145,20 +143,23 @@ static int upd64083_command(struct i2c_client *client, unsigned int cmd, void *a
+ 	{
+ 		struct v4l2_register *reg = arg;
  
--	dprintk("In tda9875_command...\n");
-+	switch (ctrl->id) {
-+	case V4L2_CID_AUDIO_VOLUME:
-+	{
-+		int left = (t->lvol+84)*606;
-+		int right = (t->rvol+84)*606;
+-		if (!v4l2_chip_match_i2c_client(client, reg->match_type, reg->match_chip))
++		if (!v4l2_chip_match_i2c_client(client,
++				reg->match_type, reg->match_chip))
+ 			return -EINVAL;
+ 		if (!capable(CAP_SYS_ADMIN))
+ 			return -EPERM;
+-		if (cmd == VIDIOC_DBG_G_REGISTER)
++		if (cmd == VIDIOC_DBG_G_REGISTER) {
+ 			reg->val = upd64083_read(client, reg->reg & 0xff);
+-		else
+-			upd64083_write(client, reg->reg & 0xff, reg->val & 0xff);
++			break;
++		}
++		upd64083_write(client, reg->reg & 0xff, reg->val & 0xff);
+ 		break;
+ 	}
+ #endif
  
--	switch (cmd) {
--	/* --- v4l ioctls --- */
--	/* take care: bttv does userspace copying, we'll get a
--	   kernel pointer here... */
--	case VIDIOCGAUDIO:
-+		ctrl->value=max(left,right);
-+		return 0;
-+	}
-+	case V4L2_CID_AUDIO_BALANCE:
- 	{
--		struct video_audio *va = arg;
--		int left,right;
-+		int left = (t->lvol+84)*606;
-+		int right = (t->rvol+84)*606;
-+		int volume = max(left,right);
-+		int balance = (32768*min(left,right))/
-+			      (volume ? volume : 1);
-+		ctrl->value=(left<right)?
-+			(65535-balance) : balance;
-+		return 0;
-+	}
-+	case V4L2_CID_AUDIO_BASS:
-+		ctrl->value = (t->bass+12)*2427;    /* min -12 max +15 */
-+		return 0;
-+	case V4L2_CID_AUDIO_TREBLE:
-+		ctrl->value = (t->treble+12)*2730;/* min -12 max +12 */
-+		return 0;
-+	}
-+	return -EINVAL;
-+}
+ 	case VIDIOC_G_CHIP_IDENT:
+-		return v4l2_chip_ident_i2c_client(client, arg, V4L2_IDENT_UPD64083, 0);
++		return v4l2_chip_ident_i2c_client(client, arg,
++				V4L2_IDENT_UPD64083, 0);
  
--		dprintk("VIDIOCGAUDIO\n");
-+static int tda9875_set_ctrl(struct i2c_client *client,
-+			    struct v4l2_control *ctrl)
-+{
-+	struct tda9875 *t = i2c_get_clientdata(client);
-+	int chvol=0, volume, balance, left, right;
+ 	default:
+ 		break;
+@@ -171,89 +172,43 @@ static int upd64083_command(struct i2c_client *client, unsigned int cmd, void *a
  
--		va->flags |= VIDEO_AUDIO_VOLUME |
--			VIDEO_AUDIO_BASS |
--			VIDEO_AUDIO_TREBLE;
-+	switch (ctrl->id) {
-+	case V4L2_CID_AUDIO_VOLUME:
-+		left = (t->lvol+84)*606;
-+		right = (t->rvol+84)*606;
-+
-+		volume = max(left,right);
-+		balance = (32768*min(left,right))/
-+			      (volume ? volume : 1);
-+		balance =(left<right)?
-+			(65535-balance) : balance;
-+
-+		volume = ctrl->value;
+ /* i2c implementation */
  
--		/* min is -84 max is 24 */
-+		chvol=1;
-+		break;
-+	case V4L2_CID_AUDIO_BALANCE:
- 		left = (t->lvol+84)*606;
- 		right = (t->rvol+84)*606;
--		va->volume=max(left,right);
--		va->balance=(32768*min(left,right))/
--			(va->volume ? va->volume : 1);
--		va->balance=(left<right)?
--			(65535-va->balance) : va->balance;
--		va->bass = (t->bass+12)*2427;    /* min -12 max +15 */
--		va->treble = (t->treble+12)*2730;/* min -12 max +12 */
--		va->mode |= VIDEO_SOUND_MONO;
+-static struct i2c_driver i2c_driver;
 -
--		break; /* VIDIOCGAUDIO case */
-+
-+		volume=max(left,right);
-+
-+		balance = ctrl->value;
-+
-+		chvol=1;
-+		break;
-+	case V4L2_CID_AUDIO_BASS:
-+		t->bass = ((ctrl->value/2400)-12) & 0xff;
-+		if (t->bass > 15)
-+			t->bass = 15;
-+		if (t->bass < -12)
-+			t->bass = -12 & 0xff;
-+		break;
-+	case V4L2_CID_AUDIO_TREBLE:
-+		t->treble = ((ctrl->value/2700)-12) & 0xff;
-+		if (t->treble > 12)
-+			t->treble = 12;
-+		if (t->treble < -12)
-+			t->treble = -12 & 0xff;
-+		break;
-+	default:
-+		return -EINVAL;
- 	}
+-static int upd64083_attach(struct i2c_adapter *adapter, int address, int kind)
++static int upd64083_probe(struct i2c_client *client)
+ {
+-	struct i2c_client *client;
+ 	struct upd64083_state *state;
+ 	int i;
  
--	case VIDIOCSAUDIO:
--	{
--		struct video_audio *va = arg;
--		int left,right;
+-	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+-		return 0;
 -
--		dprintk("VIDEOCSAUDIO...\n");
--		left = (min(65536 - va->balance,32768) *
--			va->volume) / 32768;
--		right = (min(va->balance,(__u16)32768) *
--			 va->volume) / 32768;
-+	if (chvol) {
-+		left = (min(65536 - balance,32768) *
-+			volume) / 32768;
-+		right = (min(balance,32768) *
-+				volume) / 32768;
- 		t->lvol = ((left/606)-84) & 0xff;
- 		if (t->lvol > 24)
--		 t->lvol = 24;
-+			t->lvol = 24;
- 		if (t->lvol < -84)
--		 t->lvol = -84 & 0xff;
-+			t->lvol = -84 & 0xff;
+-	client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
+-	if (client == NULL) {
+-		return -ENOMEM;
+-	}
+-
+-	client->addr = address;
+-	client->adapter = adapter;
+-	client->driver = &i2c_driver;
+-	snprintf(client->name, sizeof(client->name) - 1, "uPD64083");
++	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
++		return -EIO;
  
- 		t->rvol = ((right/606)-84) & 0xff;
- 		if (t->rvol > 24)
--		 t->rvol = 24;
-+			t->rvol = 24;
- 		if (t->rvol < -84)
--		 t->rvol = -84 & 0xff;
+-	v4l_info(client, "chip found @ 0x%x (%s)\n", address << 1, adapter->name);
++	v4l_info(client, "chip found @ 0x%x (%s)\n",
++			client->addr << 1, client->adapter->name);
+ 
+ 	state = kmalloc(sizeof(struct upd64083_state), GFP_KERNEL);
+-	if (state == NULL) {
+-		kfree(client);
++	if (state == NULL)
+ 		return -ENOMEM;
+-	}
+ 	i2c_set_clientdata(client, state);
+ 	/* Initially assume that a ghost reduction chip is present */
+ 	state->mode = 0;  /* YCS mode */
+ 	state->ext_y_adc = (1 << 5);
+ 	memcpy(state->regs, upd64083_init, TOT_REGS);
+-	for (i = 0; i < TOT_REGS; i++) {
++	for (i = 0; i < TOT_REGS; i++)
+ 		upd64083_write(client, i, state->regs[i]);
+-	}
+-	i2c_attach_client(client);
 -
--		t->bass = ((va->bass/2400)-12) & 0xff;
--		if (t->bass > 15)
--		 t->bass = 15;
--		if (t->bass < -12)
--		 t->bass = -12 & 0xff;
+-	return 0;
+-}
 -
--		t->treble = ((va->treble/2700)-12) & 0xff;
--		if (t->treble > 12)
--		 t->treble = 12;
--		if (t->treble < -12)
--		 t->treble = -12 & 0xff;
-+			t->rvol = -84 & 0xff;
-+	}
- 
-+//printk("tda9875 bal:%04x vol:%04x bass:%04x treble:%04x\n",va->balance,va->volume,va->bass,va->treble);
+-static int upd64083_probe(struct i2c_adapter *adapter)
+-{
+-	if (adapter->class & I2C_CLASS_TV_ANALOG)
+-		return i2c_probe(adapter, &addr_data, upd64083_attach);
+ 	return 0;
+ }
  
-+	tda9875_set(client);
+-static int upd64083_detach(struct i2c_client *client)
++static int upd64083_remove(struct i2c_client *client)
+ {
+-	int err;
+-
+-	err = i2c_detach_client(client);
+-	if (err)
+-		return err;
+-
+-	kfree(client);
++	kfree(i2c_get_clientdata(client));
+ 	return 0;
+ }
  
--//printk("tda9875 bal:%04x vol:%04x bass:%04x treble:%04x\n",va->balance,va->volume,va->bass,va->treble);
-+	return 0;
-+}
+ /* ----------------------------------------------------------------------- */
  
+-/* i2c implementation */
+-static struct i2c_driver i2c_driver = {
+-	.driver = {
+-		.name = "upd64083",
+-	},
+-	.id = I2C_DRIVERID_UPD64083,
+-	.attach_adapter = upd64083_probe,
+-	.detach_client  = upd64083_detach,
++
++static struct v4l2_i2c_driver_data v4l2_i2c_data = {
++	.name = "upd64083",
++	.driverid = I2C_DRIVERID_UPD64083,
+ 	.command = upd64083_command,
++	.probe = upd64083_probe,
++	.remove = upd64083_remove,
+ };
+-
+-
+-static int __init upd64083_init_module(void)
+-{
+-	return i2c_add_driver(&i2c_driver);
+-}
+-
+-static void __exit upd64083_exit_module(void)
+-{
+-	i2c_del_driver(&i2c_driver);
+-}
+-
+-module_init(upd64083_init_module);
+-module_exit(upd64083_exit_module);
+diff --git a/drivers/media/video/usbvision/usbvision-cards.c b/drivers/media/video/usbvision/usbvision-cards.c
+index f09eb10..503b13b 100644
+--- a/drivers/media/video/usbvision/usbvision-cards.c
++++ b/drivers/media/video/usbvision/usbvision-cards.c
+@@ -901,6 +901,20 @@ struct usbvision_device_data_st  usbvision_device_data[] = {
+ 		.Y_Offset      = -1,
+ 		.ModelString   = "Pinnacle Studio PCTV USB (NTSC) FM",
+ 	},
++	[PINNA_PCTV_USB_NTSC_FM_V3] = {
++		.Interface     = -1,
++		.Codec         = CODEC_SAA7111,
++		.VideoChannels = 3,
++		.VideoNorm     = V4L2_STD_NTSC,
++		.AudioChannels = 1,
++		.Radio         = 1,
++		.vbi           = 1,
++		.Tuner         = 1,
++		.TunerType     = TUNER_PHILIPS_NTSC_M,
++		.X_Offset      = -1,
++		.Y_Offset      = -1,
++		.ModelString   = "Pinnacle Studio PCTV USB (NTSC) FM V3",
++	},
+ 	[PINNA_PCTV_USB_PAL_FM_V2] = {
+ 		.Interface     = -1,
+ 		.Codec         = CODEC_SAA7113,
+@@ -1044,7 +1058,7 @@ struct usb_device_id usbvision_table [] = {
+ 	{ USB_DEVICE(0x0573, 0x4d2a), .driver_info=HPG_WINTV_PRO_NTSC_MN },
+ 	{ USB_DEVICE(0x0573, 0x4d2b), .driver_info=HPG_WINTV_PRO_NTSC_MN_V2 },
+ 	{ USB_DEVICE(0x0573, 0x4d2c), .driver_info=HPG_WINTV_PRO_PAL },
+-	{ USB_DEVICE(0x0573, 0x4d20), .driver_info=HPG_WINTV_PRO_NTSC_MN_V3 },
++	{ USB_DEVICE(0x0573, 0x4d20), .driver_info = HPG_WINTV_PRO_NTSC_MN_V3 },
+ 	{ USB_DEVICE(0x0573, 0x4d21), .driver_info=HPG_WINTV_PRO_PAL_BG },
+ 	{ USB_DEVICE(0x0573, 0x4d22), .driver_info=HPG_WINTV_PRO_PAL_I },
+ 	{ USB_DEVICE(0x0573, 0x4d23), .driver_info=HPG_WINTV_PRO_PAL_SECAM_L },
+@@ -1074,6 +1088,8 @@ struct usb_device_id usbvision_table [] = {
+ 	{ USB_DEVICE(0x2304, 0x0110), .driver_info=PINNA_PCTV_USB_PAL_FM },
+ 	{ USB_DEVICE(0x2304, 0x0111), .driver_info=MIRO_PCTV_USB },
+ 	{ USB_DEVICE(0x2304, 0x0112), .driver_info=PINNA_PCTV_USB_NTSC_FM },
++	{ USB_DEVICE(0x2304, 0x0113),
++	  .driver_info = PINNA_PCTV_USB_NTSC_FM_V3 },
+ 	{ USB_DEVICE(0x2304, 0x0210), .driver_info=PINNA_PCTV_USB_PAL_FM_V2 },
+ 	{ USB_DEVICE(0x2304, 0x0212), .driver_info=PINNA_PCTV_USB_NTSC_FM_V2 },
+ 	{ USB_DEVICE(0x2304, 0x0214), .driver_info=PINNA_PCTV_USB_PAL_FM_V3 },
+diff --git a/drivers/media/video/usbvision/usbvision-cards.h b/drivers/media/video/usbvision/usbvision-cards.h
+index 512c5ce..9c6ad22 100644
+--- a/drivers/media/video/usbvision/usbvision-cards.h
++++ b/drivers/media/video/usbvision/usbvision-cards.h
+@@ -62,5 +62,6 @@
+ #define PINNA_LINX_VD_IN_CAB_PAL                 61
+ #define PINNA_PCTV_BUNGEE_PAL_FM                 62
+ #define HPG_WINTV                                63
++#define PINNA_PCTV_USB_NTSC_FM_V3                64
  
--		tda9875_set(client);
-+static int tda9875_command(struct i2c_client *client,
-+				unsigned int cmd, void *arg)
-+{
-+	dprintk("In tda9875_command...\n");
+ extern const int usbvision_device_data_size;
+diff --git a/drivers/media/video/usbvision/usbvision-core.c b/drivers/media/video/usbvision/usbvision-core.c
+index c7d5f9e..56775ab 100644
+--- a/drivers/media/video/usbvision/usbvision-core.c
++++ b/drivers/media/video/usbvision/usbvision-core.c
+@@ -69,6 +69,15 @@ static int SwitchSVideoInput = 0;			// To help people with Black and White outpu
+ module_param(SwitchSVideoInput, int, 0444);
+ MODULE_PARM_DESC(SwitchSVideoInput, " Set the S-Video input.  Some cables and input device are wired differently. Default: 0 (Off)");
  
--		break;
-+	switch (cmd) {
-+	/* --- v4l ioctls --- */
-+	/* take care: bttv does userspace copying, we'll get a
-+	   kernel pointer here... */
-+	case VIDIOC_QUERYCTRL:
-+	{
-+		struct v4l2_queryctrl *qc = arg;
++static unsigned int adjust_X_Offset = -1;
++module_param(adjust_X_Offset, int, 0644);
++MODULE_PARM_DESC(adjust_X_Offset, "adjust X offset display [core]");
 +
-+		switch (qc->id) {
-+			case V4L2_CID_AUDIO_VOLUME:
-+			case V4L2_CID_AUDIO_BASS:
-+			case V4L2_CID_AUDIO_TREBLE:
-+			default:
-+				return -EINVAL;
-+		}
-+		return v4l2_ctrl_query_fill_std(qc);
-+	}
-+	case VIDIOC_S_CTRL:
-+		return tda9875_set_ctrl(client, arg);
- 
--	} /* end of VIDEOCSAUDIO case */
-+	case VIDIOC_G_CTRL:
-+		return tda9875_get_ctrl(client, arg);
++static unsigned int adjust_Y_Offset = -1;
++module_param(adjust_Y_Offset, int, 0644);
++MODULE_PARM_DESC(adjust_Y_Offset, "adjust Y offset display [core]");
++
++
+ #define	ENABLE_HEXDUMP	0	/* Enable if you need it */
  
- 	default: /* Not VIDEOCGAUDIO or VIDEOCSAUDIO */
  
-diff --git a/drivers/media/video/tda9887.c b/drivers/media/video/tda9887.c
-index be5387f..106c93b 100644
---- a/drivers/media/video/tda9887.c
-+++ b/drivers/media/video/tda9887.c
-@@ -9,7 +9,8 @@
- #include <linux/videodev.h>
- #include <media/v4l2-common.h>
- #include <media/tuner.h>
--#include "tuner-driver.h"
-+#include "tuner-i2c.h"
-+#include "tda9887.h"
+@@ -624,25 +633,29 @@ static enum ParseState usbvision_parse_lines_422(struct usb_usbvision *usbvision
  
+ 			YUV_TO_RGB_BY_THE_BOOK(yuyv[0], yuyv[1], yuyv[3], rv, gv, bv);
+ 			switch (frame->v4l2_format.format) {
+-				case V4L2_PIX_FMT_RGB565:
+-					*f++ = (0x1F & (bv >> 3)) | (0xE0 & (gv << 3));
+-					*f++ = (0x07 & (gv >> 5)) | (0xF8 &  rv);
+-					break;
+-				case V4L2_PIX_FMT_RGB24:
+-					*f++ = bv;
+-					*f++ = gv;
+-					*f++ = rv;
+-					break;
+-				case V4L2_PIX_FMT_RGB32:
+-					*f++ = bv;
+-					*f++ = gv;
+-					*f++ = rv;
+-					f++;
+-					break;
+-				case V4L2_PIX_FMT_RGB555:
+-					*f++ = (0x1F & (bv >> 3)) | (0xE0 & (gv << 2));
+-					*f++ = (0x03 & (gv >> 6)) | (0x7C & (rv >> 1));
+-					break;
++			case V4L2_PIX_FMT_RGB565:
++				*f++ = (0x1F & rv) |
++					(0xE0 & (gv << 5));
++				*f++ = (0x07 & (gv >> 3)) |
++					(0xF8 &  bv);
++				break;
++			case V4L2_PIX_FMT_RGB24:
++				*f++ = rv;
++				*f++ = gv;
++				*f++ = bv;
++				break;
++			case V4L2_PIX_FMT_RGB32:
++				*f++ = rv;
++				*f++ = gv;
++				*f++ = bv;
++				f++;
++				break;
++			case V4L2_PIX_FMT_RGB555:
++				*f++ = (0x1F & rv) |
++					(0xE0 & (gv << 5));
++				*f++ = (0x03 & (gv >> 3)) |
++					(0x7C & (bv << 2));
++				break;
+ 			}
+ 		}
+ 		clipmask_index += clipmask_add;
+@@ -656,25 +669,29 @@ static enum ParseState usbvision_parse_lines_422(struct usb_usbvision *usbvision
  
- /* Chips:
-@@ -20,18 +21,20 @@
-    Used as part of several tuners
- */
+ 			YUV_TO_RGB_BY_THE_BOOK(yuyv[2], yuyv[1], yuyv[3], rv, gv, bv);
+ 			switch (frame->v4l2_format.format) {
+-				case V4L2_PIX_FMT_RGB565:
+-					*f++ = (0x1F & (bv >> 3)) | (0xE0 & (gv << 3));
+-					*f++ = (0x07 & (gv >> 5)) | (0xF8 &  rv);
+-					break;
+-				case V4L2_PIX_FMT_RGB24:
+-					*f++ = bv;
+-					*f++ = gv;
+-					*f++ = rv;
+-					break;
+-				case V4L2_PIX_FMT_RGB32:
+-					*f++ = bv;
+-					*f++ = gv;
+-					*f++ = rv;
+-					f++;
+-					break;
+-				case V4L2_PIX_FMT_RGB555:
+-					*f++ = (0x1F & (bv >> 3)) | (0xE0 & (gv << 2));
+-					*f++ = (0x03 & (gv >> 6)) | (0x7C & (rv >> 1));
+-					break;
++			case V4L2_PIX_FMT_RGB565:
++				*f++ = (0x1F & rv) |
++					(0xE0 & (gv << 5));
++				*f++ = (0x07 & (gv >> 3)) |
++					(0xF8 &  bv);
++				break;
++			case V4L2_PIX_FMT_RGB24:
++				*f++ = rv;
++				*f++ = gv;
++				*f++ = bv;
++				break;
++			case V4L2_PIX_FMT_RGB32:
++				*f++ = rv;
++				*f++ = gv;
++				*f++ = bv;
++				f++;
++				break;
++			case V4L2_PIX_FMT_RGB555:
++				*f++ = (0x1F & rv) |
++					(0xE0 & (gv << 5));
++				*f++ = (0x03 & (gv >> 3)) |
++					(0x7C & (bv << 2));
++				break;
+ 			}
+ 		}
+ 		clipmask_index += clipmask_add;
+@@ -942,22 +959,26 @@ static enum ParseState usbvision_parse_compress(struct usb_usbvision *usbvision,
+ 					*f++ = Y[Idx];
+ 					break;
+ 				case V4L2_PIX_FMT_RGB555:
+-					*f++ = (0x1F & (bv >> 3)) | (0xE0 & (gv << 2));
+-					*f++ = (0x03 & (gv >> 6)) | (0x7C & (rv >> 1));
++					*f++ = (0x1F & rv) |
++						(0xE0 & (gv << 5));
++					*f++ = (0x03 & (gv >> 3)) |
++						(0x7C & (bv << 2));
+ 					break;
+ 				case V4L2_PIX_FMT_RGB565:
+-					*f++ = (0x1F & (bv >> 3)) | (0xE0 & (gv << 3));
+-					*f++ = (0x07 & (gv >> 5)) | (0xF8 &  rv);
++					*f++ = (0x1F & rv) |
++						(0xE0 & (gv << 5));
++					*f++ = (0x07 & (gv >> 3)) |
++						(0xF8 &  bv);
+ 					break;
+ 				case V4L2_PIX_FMT_RGB24:
+-					*f++ = bv;
+-					*f++ = gv;
+ 					*f++ = rv;
++					*f++ = gv;
++					*f++ = bv;
+ 					break;
+ 				case V4L2_PIX_FMT_RGB32:
+-					*f++ = bv;
+-					*f++ = gv;
+ 					*f++ = rv;
++					*f++ = gv;
++					*f++ = bv;
+ 					f++;
+ 					break;
+ 			}
+@@ -1071,28 +1092,33 @@ static enum ParseState usbvision_parse_lines_420(struct usb_usbvision *usbvision
+ 				r_ = (y_ + ur) >> 16;
  
--#define tda9887_info(fmt, arg...) do {\
--	printk(KERN_INFO "%s %d-%04x: " fmt, t->i2c.name, \
--			i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0)
--#define tda9887_dbg(fmt, arg...) do {\
--	if (tuner_debug) \
--		printk(KERN_INFO "%s %d-%04x: " fmt, t->i2c.name, \
--			i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0)
-+static int debug;
-+module_param(debug, int, 0644);
-+MODULE_PARM_DESC(debug, "enable verbose debug messages");
-+
-+#define PREFIX "tda9887"
+ 				switch (frame->v4l2_format.format) {
+-					case V4L2_PIX_FMT_RGB565:
+-						g = LIMIT_RGB(g_);
+-						*f_even++ = (0x1F & (LIMIT_RGB(b_) >> 3)) | (0xE0 & (g << 3));
+-						*f_even++ = (0x07 & (          g   >> 5)) | (0xF8 & LIMIT_RGB(r_));
+-						break;
+-					case V4L2_PIX_FMT_RGB24:
+-						*f_even++ = LIMIT_RGB(b_);
+-						*f_even++ = LIMIT_RGB(g_);
+-						*f_even++ = LIMIT_RGB(r_);
+-						break;
+-					case V4L2_PIX_FMT_RGB32:
+-						*f_even++ = LIMIT_RGB(b_);
+-						*f_even++ = LIMIT_RGB(g_);
+-						*f_even++ = LIMIT_RGB(r_);
+-						f_even++;
+-						break;
+-					case V4L2_PIX_FMT_RGB555:
+-						g = LIMIT_RGB(g_);
+-						*f_even++ = (0x1F & (LIMIT_RGB(b_) >> 3)) | (0xE0 & (g << 2));
+-						*f_even++ = (0x03 & (          g   >> 6)) |
+-							    (0x7C & (LIMIT_RGB(r_) >> 1));
+-						break;
++				case V4L2_PIX_FMT_RGB565:
++					g = LIMIT_RGB(g_);
++					*f_even++ =
++						(0x1F & LIMIT_RGB(r_)) |
++						(0xE0 & (g << 5));
++					*f_even++ =
++						(0x07 & (g >> 3)) |
++						(0xF8 &  LIMIT_RGB(b_));
++					break;
++				case V4L2_PIX_FMT_RGB24:
++					*f_even++ = LIMIT_RGB(r_);
++					*f_even++ = LIMIT_RGB(g_);
++					*f_even++ = LIMIT_RGB(b_);
++					break;
++				case V4L2_PIX_FMT_RGB32:
++					*f_even++ = LIMIT_RGB(r_);
++					*f_even++ = LIMIT_RGB(g_);
++					*f_even++ = LIMIT_RGB(b_);
++					f_even++;
++					break;
++				case V4L2_PIX_FMT_RGB555:
++					g = LIMIT_RGB(g_);
++					*f_even++ = (0x1F & LIMIT_RGB(r_)) |
++						(0xE0 & (g << 5));
++					*f_even++ = (0x03 & (g >> 3)) |
++						(0x7C & (LIMIT_RGB(b_) << 2));
++					break;
+ 				}
+ 			}
+ 			clipmask_even_index += clipmask_add;
+@@ -1110,28 +1136,33 @@ static enum ParseState usbvision_parse_lines_420(struct usb_usbvision *usbvision
+ 				r_ = (y_ + ur) >> 16;
  
- struct tda9887_priv {
- 	struct tuner_i2c_props i2c_props;
+ 				switch (frame->v4l2_format.format) {
+-					case V4L2_PIX_FMT_RGB565:
+-						g = LIMIT_RGB(g_);
+-						*f_even++ = (0x1F & (LIMIT_RGB(b_) >> 3)) | (0xE0 & (g << 3));
+-						*f_even++ = (0x07 & (          g   >> 5)) | (0xF8 & LIMIT_RGB(r_));
+-						break;
+-					case V4L2_PIX_FMT_RGB24:
+-						*f_even++ = LIMIT_RGB(b_);
+-						*f_even++ = LIMIT_RGB(g_);
+-						*f_even++ = LIMIT_RGB(r_);
+-						break;
+-					case V4L2_PIX_FMT_RGB32:
+-						*f_even++ = LIMIT_RGB(b_);
+-						*f_even++ = LIMIT_RGB(g_);
+-						*f_even++ = LIMIT_RGB(r_);
+-						f_even++;
+-						break;
+-					case V4L2_PIX_FMT_RGB555:
+-						g = LIMIT_RGB(g_);
+-						*f_even++ = (0x1F & (LIMIT_RGB(b_) >> 3)) | (0xE0 & (g << 2));
+-						*f_even++ = (0x03 & (          g   >> 6)) |
+-							    (0x7C & (LIMIT_RGB(r_) >> 1));
+-						break;
++				case V4L2_PIX_FMT_RGB565:
++					g = LIMIT_RGB(g_);
++					*f_even++ =
++						(0x1F & LIMIT_RGB(r_)) |
++						(0xE0 & (g << 5));
++					*f_even++ =
++						(0x07 & (g >> 3)) |
++						(0xF8 &  LIMIT_RGB(b_));
++					break;
++				case V4L2_PIX_FMT_RGB24:
++					*f_even++ = LIMIT_RGB(r_);
++					*f_even++ = LIMIT_RGB(g_);
++					*f_even++ = LIMIT_RGB(b_);
++					break;
++				case V4L2_PIX_FMT_RGB32:
++					*f_even++ = LIMIT_RGB(r_);
++					*f_even++ = LIMIT_RGB(g_);
++					*f_even++ = LIMIT_RGB(b_);
++					f_even++;
++					break;
++				case V4L2_PIX_FMT_RGB555:
++					g = LIMIT_RGB(g_);
++					*f_even++ = (0x1F & LIMIT_RGB(r_)) |
++						(0xE0 & (g << 5));
++					*f_even++ = (0x03 & (g >> 3)) |
++						(0x7C & (LIMIT_RGB(b_) << 2));
++					break;
+ 				}
+ 			}
+ 			clipmask_even_index += clipmask_add;
+@@ -1151,28 +1182,33 @@ static enum ParseState usbvision_parse_lines_420(struct usb_usbvision *usbvision
+ 				r_ = (y_ + ur) >> 16;
  
- 	unsigned char 	   data[4];
-+	unsigned int       config;
-+	unsigned int       mode;
-+	unsigned int       audmode;
-+	v4l2_std_id        std;
- };
+ 				switch (frame->v4l2_format.format) {
+-					case V4L2_PIX_FMT_RGB565:
+-						g = LIMIT_RGB(g_);
+-						*f_odd++ = (0x1F & (LIMIT_RGB(b_) >> 3)) | (0xE0 & (g << 3));
+-						*f_odd++ = (0x07 & (          g   >> 5)) | (0xF8 & LIMIT_RGB(r_));
+-						break;
+-					case V4L2_PIX_FMT_RGB24:
+-						*f_odd++ = LIMIT_RGB(b_);
+-						*f_odd++ = LIMIT_RGB(g_);
+-						*f_odd++ = LIMIT_RGB(r_);
+-						break;
+-					case V4L2_PIX_FMT_RGB32:
+-						*f_odd++ = LIMIT_RGB(b_);
+-						*f_odd++ = LIMIT_RGB(g_);
+-						*f_odd++ = LIMIT_RGB(r_);
+-						f_odd++;
+-						break;
+-					case V4L2_PIX_FMT_RGB555:
+-						g = LIMIT_RGB(g_);
+-						*f_odd++ = (0x1F & (LIMIT_RGB(b_) >> 3)) | (0xE0 & (g << 2));
+-						*f_odd++ = (0x03 & (          g   >> 6)) |
+-							   (0x7C & (LIMIT_RGB(r_) >> 1));
+-						break;
++				case V4L2_PIX_FMT_RGB565:
++					g = LIMIT_RGB(g_);
++					*f_odd++ =
++						(0x1F & LIMIT_RGB(r_)) |
++						(0xE0 & (g << 5));
++					*f_odd++ =
++						(0x07 & (g >> 3)) |
++						(0xF8 &  LIMIT_RGB(b_));
++					break;
++				case V4L2_PIX_FMT_RGB24:
++					*f_odd++ = LIMIT_RGB(r_);
++					*f_odd++ = LIMIT_RGB(g_);
++					*f_odd++ = LIMIT_RGB(b_);
++					break;
++				case V4L2_PIX_FMT_RGB32:
++					*f_odd++ = LIMIT_RGB(r_);
++					*f_odd++ = LIMIT_RGB(g_);
++					*f_odd++ = LIMIT_RGB(b_);
++					f_odd++;
++					break;
++				case V4L2_PIX_FMT_RGB555:
++					g = LIMIT_RGB(g_);
++					*f_odd++ = (0x1F & LIMIT_RGB(r_)) |
++						(0xE0 & (g << 5));
++					*f_odd++ = (0x03 & (g >> 3)) |
++						(0x7C & (LIMIT_RGB(b_) << 2));
++					break;
+ 				}
+ 			}
+ 			clipmask_odd_index += clipmask_add;
+@@ -1190,28 +1226,33 @@ static enum ParseState usbvision_parse_lines_420(struct usb_usbvision *usbvision
+ 				r_ = (y_ + ur) >> 16;
  
- /* ---------------------------------------------------------------------- */
-@@ -262,8 +265,10 @@ static struct tvnorm radio_mono = {
+ 				switch (frame->v4l2_format.format) {
+-					case V4L2_PIX_FMT_RGB565:
+-						g = LIMIT_RGB(g_);
+-						*f_odd++ = (0x1F & (LIMIT_RGB(b_) >> 3)) | (0xE0 & (g << 3));
+-						*f_odd++ = (0x07 & (          g   >> 5)) | (0xF8 & LIMIT_RGB(r_));
+-						break;
+-					case V4L2_PIX_FMT_RGB24:
+-						*f_odd++ = LIMIT_RGB(b_);
+-						*f_odd++ = LIMIT_RGB(g_);
+-						*f_odd++ = LIMIT_RGB(r_);
+-						break;
+-					case V4L2_PIX_FMT_RGB32:
+-						*f_odd++ = LIMIT_RGB(b_);
+-						*f_odd++ = LIMIT_RGB(g_);
+-						*f_odd++ = LIMIT_RGB(r_);
+-						f_odd++;
+-						break;
+-					case V4L2_PIX_FMT_RGB555:
+-						g = LIMIT_RGB(g_);
+-						*f_odd++ = (0x1F & (LIMIT_RGB(b_) >> 3)) | (0xE0 & (g << 2));
+-						*f_odd++ = (0x03 & (          g   >> 6)) |
+-							   (0x7C & (LIMIT_RGB(r_) >> 1));
+-						break;
++				case V4L2_PIX_FMT_RGB565:
++					g = LIMIT_RGB(g_);
++					*f_odd++ =
++						(0x1F & LIMIT_RGB(r_)) |
++						(0xE0 & (g << 5));
++					*f_odd++ =
++						(0x07 & (g >> 3)) |
++						(0xF8 &  LIMIT_RGB(b_));
++					break;
++				case V4L2_PIX_FMT_RGB24:
++					*f_odd++ = LIMIT_RGB(r_);
++					*f_odd++ = LIMIT_RGB(g_);
++					*f_odd++ = LIMIT_RGB(b_);
++					break;
++				case V4L2_PIX_FMT_RGB32:
++					*f_odd++ = LIMIT_RGB(r_);
++					*f_odd++ = LIMIT_RGB(g_);
++					*f_odd++ = LIMIT_RGB(b_);
++					f_odd++;
++					break;
++				case V4L2_PIX_FMT_RGB555:
++					g = LIMIT_RGB(g_);
++					*f_odd++ = (0x1F & LIMIT_RGB(r_)) |
++						(0xE0 & (g << 5));
++					*f_odd++ = (0x03 & (g >> 3)) |
++						(0x7C & (LIMIT_RGB(b_) << 2));
++					break;
+ 				}
+ 			}
+ 			clipmask_odd_index += clipmask_add;
+@@ -1561,13 +1602,10 @@ static int usbvision_write_reg_irq(struct usb_usbvision *usbvision,int address,
+ 	if (len > 8) {
+ 		return -EFAULT;
+ 	}
+-//	down(&usbvision->ctrlUrbLock);
+ 	if (usbvision->ctrlUrbBusy) {
+-//		up(&usbvision->ctrlUrbLock);
+ 		return -EBUSY;
+ 	}
+ 	usbvision->ctrlUrbBusy = 1;
+-//	up(&usbvision->ctrlUrbLock);
  
- /* ---------------------------------------------------------------------- */
+ 	usbvision->ctrlUrbSetup.bRequestType = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT;
+ 	usbvision->ctrlUrbSetup.bRequest     = USBVISION_OP_CODE;
+@@ -2100,11 +2138,21 @@ int usbvision_set_input(struct usb_usbvision *usbvision)
+ 		value[5]=(usbvision_device_data[usbvision->DevModel].X_Offset & 0x0300) >> 8;
+ 	}
  
--static void dump_read_message(struct tuner *t, unsigned char *buf)
-+static void dump_read_message(struct dvb_frontend *fe, unsigned char *buf)
- {
-+	struct tda9887_priv *priv = fe->analog_demod_priv;
-+
- 	static char *afc[16] = {
- 		"- 12.5 kHz",
- 		"- 37.5 kHz",
-@@ -282,16 +287,18 @@ static void dump_read_message(struct tuner *t, unsigned char *buf)
- 		"+ 37.5 kHz",
- 		"+ 12.5 kHz",
- 	};
--	tda9887_info("read: 0x%2x\n", buf[0]);
--	tda9887_info("  after power on : %s\n", (buf[0] & 0x01) ? "yes" : "no");
--	tda9887_info("  afc            : %s\n", afc[(buf[0] >> 1) & 0x0f]);
--	tda9887_info("  fmif level     : %s\n", (buf[0] & 0x20) ? "high" : "low");
--	tda9887_info("  afc window     : %s\n", (buf[0] & 0x40) ? "in" : "out");
--	tda9887_info("  vfi level      : %s\n", (buf[0] & 0x80) ? "high" : "low");
-+	tuner_info("read: 0x%2x\n", buf[0]);
-+	tuner_info("  after power on : %s\n", (buf[0] & 0x01) ? "yes" : "no");
-+	tuner_info("  afc            : %s\n", afc[(buf[0] >> 1) & 0x0f]);
-+	tuner_info("  fmif level     : %s\n", (buf[0] & 0x20) ? "high" : "low");
-+	tuner_info("  afc window     : %s\n", (buf[0] & 0x40) ? "in" : "out");
-+	tuner_info("  vfi level      : %s\n", (buf[0] & 0x80) ? "high" : "low");
- }
++	if (adjust_X_Offset != -1) {
++		value[4] = adjust_X_Offset & 0xff;
++		value[5] = (adjust_X_Offset & 0x0300) >> 8;
++	}
++
+ 	if (usbvision_device_data[usbvision->DevModel].Y_Offset >= 0) {
+ 		value[6]=usbvision_device_data[usbvision->DevModel].Y_Offset & 0xff;
+ 		value[7]=(usbvision_device_data[usbvision->DevModel].Y_Offset & 0x0300) >> 8;
+ 	}
  
--static void dump_write_message(struct tuner *t, unsigned char *buf)
-+static void dump_write_message(struct dvb_frontend *fe, unsigned char *buf)
- {
-+	struct tda9887_priv *priv = fe->analog_demod_priv;
++	if (adjust_Y_Offset != -1) {
++		value[6] = adjust_Y_Offset & 0xff;
++		value[7] = (adjust_Y_Offset & 0x0300) >> 8;
++	}
 +
- 	static char *sound[4] = {
- 		"AM/TV",
- 		"FM/radio",
-@@ -330,86 +337,90 @@ static void dump_write_message(struct tuner *t, unsigned char *buf)
- 		"44 MHz",
- 	};
+ 	rc = usb_control_msg(usbvision->dev, usb_sndctrlpipe(usbvision->dev, 1),
+ 			     USBVISION_OP_CODE,	/* USBVISION specific code */
+ 			     USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT, 0,
+@@ -2242,14 +2290,18 @@ static void call_usbvision_power_off(struct work_struct *work)
+ 	struct usb_usbvision *usbvision = container_of(work, struct usb_usbvision, powerOffWork);
  
--	tda9887_info("write: byte B 0x%02x\n",buf[1]);
--	tda9887_info("  B0   video mode      : %s\n",
--	       (buf[1] & 0x01) ? "video trap" : "sound trap");
--	tda9887_info("  B1   auto mute fm    : %s\n",
--	       (buf[1] & 0x02) ? "yes" : "no");
--	tda9887_info("  B2   carrier mode    : %s\n",
--	       (buf[1] & 0x04) ? "QSS" : "Intercarrier");
--	tda9887_info("  B3-4 tv sound/radio  : %s\n",
--	       sound[(buf[1] & 0x18) >> 3]);
--	tda9887_info("  B5   force mute audio: %s\n",
--	       (buf[1] & 0x20) ? "yes" : "no");
--	tda9887_info("  B6   output port 1   : %s\n",
--	       (buf[1] & 0x40) ? "high (inactive)" : "low (active)");
--	tda9887_info("  B7   output port 2   : %s\n",
--	       (buf[1] & 0x80) ? "high (inactive)" : "low (active)");
--
--	tda9887_info("write: byte C 0x%02x\n",buf[2]);
--	tda9887_info("  C0-4 top adjustment  : %s dB\n", adjust[buf[2] & 0x1f]);
--	tda9887_info("  C5-6 de-emphasis     : %s\n", deemph[(buf[2] & 0x60) >> 5]);
--	tda9887_info("  C7   audio gain      : %s\n",
--	       (buf[2] & 0x80) ? "-6" : "0");
--
--	tda9887_info("write: byte E 0x%02x\n",buf[3]);
--	tda9887_info("  E0-1 sound carrier   : %s\n",
--	       carrier[(buf[3] & 0x03)]);
--	tda9887_info("  E6   l pll gating   : %s\n",
--	       (buf[3] & 0x40) ? "36" : "13");
-+	tuner_info("write: byte B 0x%02x\n", buf[1]);
-+	tuner_info("  B0   video mode      : %s\n",
-+		   (buf[1] & 0x01) ? "video trap" : "sound trap");
-+	tuner_info("  B1   auto mute fm    : %s\n",
-+		   (buf[1] & 0x02) ? "yes" : "no");
-+	tuner_info("  B2   carrier mode    : %s\n",
-+		   (buf[1] & 0x04) ? "QSS" : "Intercarrier");
-+	tuner_info("  B3-4 tv sound/radio  : %s\n",
-+		   sound[(buf[1] & 0x18) >> 3]);
-+	tuner_info("  B5   force mute audio: %s\n",
-+		   (buf[1] & 0x20) ? "yes" : "no");
-+	tuner_info("  B6   output port 1   : %s\n",
-+		   (buf[1] & 0x40) ? "high (inactive)" : "low (active)");
-+	tuner_info("  B7   output port 2   : %s\n",
-+		   (buf[1] & 0x80) ? "high (inactive)" : "low (active)");
+ 	PDEBUG(DBG_FUNC, "");
+-	down_interruptible(&usbvision->lock);
++	if(mutex_lock_interruptible(&usbvision->lock)) {
++		return;
++	}
 +
-+	tuner_info("write: byte C 0x%02x\n", buf[2]);
-+	tuner_info("  C0-4 top adjustment  : %s dB\n",
-+		   adjust[buf[2] & 0x1f]);
-+	tuner_info("  C5-6 de-emphasis     : %s\n",
-+		   deemph[(buf[2] & 0x60) >> 5]);
-+	tuner_info("  C7   audio gain      : %s\n",
-+		   (buf[2] & 0x80) ? "-6" : "0");
 +
-+	tuner_info("write: byte E 0x%02x\n", buf[3]);
-+	tuner_info("  E0-1 sound carrier   : %s\n",
-+		   carrier[(buf[3] & 0x03)]);
-+	tuner_info("  E6   l pll gating   : %s\n",
-+		   (buf[3] & 0x40) ? "36" : "13");
+ 	if(usbvision->user == 0) {
+ 		usbvision_i2c_unregister(usbvision);
  
- 	if (buf[1] & 0x08) {
- 		/* radio */
--		tda9887_info("  E2-4 video if        : %s\n",
--		       rif[(buf[3] & 0x0c) >> 2]);
--		tda9887_info("  E7   vif agc output  : %s\n",
--		       (buf[3] & 0x80)
--		       ? ((buf[3] & 0x10) ? "fm-agc radio" : "sif-agc radio")
--		       : "fm radio carrier afc");
-+		tuner_info("  E2-4 video if        : %s\n",
-+			   rif[(buf[3] & 0x0c) >> 2]);
-+		tuner_info("  E7   vif agc output  : %s\n",
-+			   (buf[3] & 0x80)
-+			   ? ((buf[3] & 0x10) ? "fm-agc radio" :
-+						"sif-agc radio")
-+			   : "fm radio carrier afc");
- 	} else {
- 		/* video */
--		tda9887_info("  E2-4 video if        : %s\n",
--		       vif[(buf[3] & 0x1c) >> 2]);
--		tda9887_info("  E5   tuner gain      : %s\n",
--		       (buf[3] & 0x80)
--		       ? ((buf[3] & 0x20) ? "external" : "normal")
--		       : ((buf[3] & 0x20) ? "minimum"  : "normal"));
--		tda9887_info("  E7   vif agc output  : %s\n",
--		       (buf[3] & 0x80)
--		       ? ((buf[3] & 0x20)
--			  ? "pin3 port, pin22 vif agc out"
--			  : "pin22 port, pin3 vif acg ext in")
--		       : "pin3+pin22 port");
-+		tuner_info("  E2-4 video if        : %s\n",
-+			   vif[(buf[3] & 0x1c) >> 2]);
-+		tuner_info("  E5   tuner gain      : %s\n",
-+			   (buf[3] & 0x80)
-+			   ? ((buf[3] & 0x20) ? "external" : "normal")
-+			   : ((buf[3] & 0x20) ? "minimum"  : "normal"));
-+		tuner_info("  E7   vif agc output  : %s\n",
-+			   (buf[3] & 0x80) ? ((buf[3] & 0x20)
-+				? "pin3 port, pin22 vif agc out"
-+				: "pin22 port, pin3 vif acg ext in")
-+				: "pin3+pin22 port");
+ 		usbvision_power_off(usbvision);
+ 		usbvision->initialized = 0;
  	}
--	tda9887_info("--\n");
-+	tuner_info("--\n");
+-	up(&usbvision->lock);
++	mutex_unlock(&usbvision->lock);
  }
  
- /* ---------------------------------------------------------------------- */
- 
--static int tda9887_set_tvnorm(struct tuner *t, char *buf)
-+static int tda9887_set_tvnorm(struct dvb_frontend *fe)
- {
-+	struct tda9887_priv *priv = fe->analog_demod_priv;
- 	struct tvnorm *norm = NULL;
-+	char *buf = priv->data;
- 	int i;
+ static void usbvision_powerOffTimer(unsigned long data)
+diff --git a/drivers/media/video/usbvision/usbvision-video.c b/drivers/media/video/usbvision/usbvision-video.c
+index 36e689f..b52b826 100644
+--- a/drivers/media/video/usbvision/usbvision-video.c
++++ b/drivers/media/video/usbvision/usbvision-video.c
+@@ -410,7 +410,7 @@ static int usbvision_v4l2_open(struct inode *inode, struct file *file)
  
--	if (t->mode == V4L2_TUNER_RADIO) {
--		if (t->audmode == V4L2_TUNER_MODE_MONO)
-+	if (priv->mode == V4L2_TUNER_RADIO) {
-+		if (priv->audmode == V4L2_TUNER_MODE_MONO)
- 			norm = &radio_mono;
- 		else
- 			norm = &radio_stereo;
- 	} else {
- 		for (i = 0; i < ARRAY_SIZE(tvnorms); i++) {
--			if (tvnorms[i].std & t->std) {
-+			if (tvnorms[i].std & priv->std) {
- 				norm = tvnorms+i;
- 				break;
+ 	/* If so far no errors then we shall start the camera */
+ 	if (!errCode) {
+-		down(&usbvision->lock);
++		mutex_lock(&usbvision->lock);
+ 		if (usbvision->power == 0) {
+ 			usbvision_power_on(usbvision);
+ 			usbvision_i2c_register(usbvision);
+@@ -439,7 +439,7 @@ static int usbvision_v4l2_open(struct inode *inode, struct file *file)
+ 				usbvision->initialized = 0;
  			}
  		}
+-		up(&usbvision->lock);
++		mutex_unlock(&usbvision->lock);
  	}
- 	if (NULL == norm) {
--		tda9887_dbg("Unsupported tvnorm entry - audio muted\n");
-+		tuner_dbg("Unsupported tvnorm entry - audio muted\n");
- 		return -1;
- 	}
- 
--	tda9887_dbg("configure for: %s\n",norm->name);
-+	tuner_dbg("configure for: %s\n", norm->name);
- 	buf[1] = norm->b;
- 	buf[2] = norm->c;
- 	buf[3] = norm->e;
-@@ -426,8 +437,11 @@ module_param(port2, int, 0644);
- module_param(qss, int, 0644);
- module_param(adjust, int, 0644);
- 
--static int tda9887_set_insmod(struct tuner *t, char *buf)
-+static int tda9887_set_insmod(struct dvb_frontend *fe)
- {
-+	struct tda9887_priv *priv = fe->analog_demod_priv;
-+	char *buf = priv->data;
-+
- 	if (UNSET != port1) {
- 		if (port1)
- 			buf[1] |= cOutputPort1Inactive;
-@@ -455,27 +469,30 @@ static int tda9887_set_insmod(struct tuner *t, char *buf)
- 	return 0;
- }
- 
--static int tda9887_set_config(struct tuner *t, char *buf)
-+static int tda9887_do_config(struct dvb_frontend *fe)
- {
--	if (t->tda9887_config & TDA9887_PORT1_ACTIVE)
-+	struct tda9887_priv *priv = fe->analog_demod_priv;
-+	char *buf = priv->data;
-+
-+	if (priv->config & TDA9887_PORT1_ACTIVE)
- 		buf[1] &= ~cOutputPort1Inactive;
--	if (t->tda9887_config & TDA9887_PORT1_INACTIVE)
-+	if (priv->config & TDA9887_PORT1_INACTIVE)
- 		buf[1] |= cOutputPort1Inactive;
--	if (t->tda9887_config & TDA9887_PORT2_ACTIVE)
-+	if (priv->config & TDA9887_PORT2_ACTIVE)
- 		buf[1] &= ~cOutputPort2Inactive;
--	if (t->tda9887_config & TDA9887_PORT2_INACTIVE)
-+	if (priv->config & TDA9887_PORT2_INACTIVE)
- 		buf[1] |= cOutputPort2Inactive;
  
--	if (t->tda9887_config & TDA9887_QSS)
-+	if (priv->config & TDA9887_QSS)
- 		buf[1] |= cQSS;
--	if (t->tda9887_config & TDA9887_INTERCARRIER)
-+	if (priv->config & TDA9887_INTERCARRIER)
- 		buf[1] &= ~cQSS;
+ 	if (errCode) {
+@@ -467,7 +467,7 @@ static int usbvision_v4l2_close(struct inode *inode, struct file *file)
+ 		(struct usb_usbvision *) video_get_drvdata(dev);
  
--	if (t->tda9887_config & TDA9887_AUTOMUTE)
-+	if (priv->config & TDA9887_AUTOMUTE)
- 		buf[1] |= cAutoMuteFmActive;
--	if (t->tda9887_config & TDA9887_DEEMPHASIS_MASK) {
-+	if (priv->config & TDA9887_DEEMPHASIS_MASK) {
- 		buf[2] &= ~0x60;
--		switch (t->tda9887_config & TDA9887_DEEMPHASIS_MASK) {
-+		switch (priv->config & TDA9887_DEEMPHASIS_MASK) {
- 		case TDA9887_DEEMPHASIS_NONE:
- 			buf[2] |= cDeemphasisOFF;
- 			break;
-@@ -487,21 +504,22 @@ static int tda9887_set_config(struct tuner *t, char *buf)
- 			break;
- 		}
- 	}
--	if (t->tda9887_config & TDA9887_TOP_SET) {
-+	if (priv->config & TDA9887_TOP_SET) {
- 		buf[2] &= ~cTopMask;
--		buf[2] |= (t->tda9887_config >> 8) & cTopMask;
-+		buf[2] |= (priv->config >> 8) & cTopMask;
- 	}
--	if ((t->tda9887_config & TDA9887_INTERCARRIER_NTSC) && (t->std & V4L2_STD_NTSC))
-+	if ((priv->config & TDA9887_INTERCARRIER_NTSC) &&
-+	    (priv->std & V4L2_STD_NTSC))
- 		buf[1] &= ~cQSS;
--	if (t->tda9887_config & TDA9887_GATING_18)
-+	if (priv->config & TDA9887_GATING_18)
- 		buf[3] &= ~cGating_36;
+ 	PDEBUG(DBG_IO, "close");
+-	down(&usbvision->lock);
++	mutex_lock(&usbvision->lock);
  
--	if (t->mode == V4L2_TUNER_RADIO) {
--		if (t->tda9887_config & TDA9887_RIF_41_3) {
-+	if (priv->mode == V4L2_TUNER_RADIO) {
-+		if (priv->config & TDA9887_RIF_41_3) {
- 			buf[3] &= ~cVideoIFMask;
- 			buf[3] |= cRadioIF_41_30;
- 		}
--		if (t->tda9887_config & TDA9887_GAIN_NORMAL)
-+		if (priv->config & TDA9887_GAIN_NORMAL)
- 			buf[3] &= ~cTunerGainLow;
+ 	usbvision_audio_off(usbvision);
+ 	usbvision_restart_isoc(usbvision);
+@@ -487,7 +487,7 @@ static int usbvision_v4l2_close(struct inode *inode, struct file *file)
+ 		usbvision->initialized = 0;
  	}
  
-@@ -510,26 +528,26 @@ static int tda9887_set_config(struct tuner *t, char *buf)
- 
- /* ---------------------------------------------------------------------- */
+-	up(&usbvision->lock);
++	mutex_unlock(&usbvision->lock);
  
--static int tda9887_status(struct tuner *t)
-+static int tda9887_status(struct dvb_frontend *fe)
- {
--	struct tda9887_priv *priv = t->priv;
-+	struct tda9887_priv *priv = fe->analog_demod_priv;
- 	unsigned char buf[1];
- 	int rc;
+ 	if (usbvision->remove_pending) {
+ 		printk(KERN_INFO "%s: Final disconnect\n", __FUNCTION__);
+@@ -647,13 +647,13 @@ static int vidioc_s_input (struct file *file, void *priv, unsigned int input)
+ 	if ((input >= usbvision->video_inputs) || (input < 0) )
+ 		return -EINVAL;
  
- 	memset(buf,0,sizeof(buf));
- 	if (1 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props,buf,1)))
--		tda9887_info("i2c i/o error: rc == %d (should be 1)\n",rc);
--	dump_read_message(t, buf);
-+		tuner_info("i2c i/o error: rc == %d (should be 1)\n", rc);
-+	dump_read_message(fe, buf);
+-	down(&usbvision->lock);
++	mutex_lock(&usbvision->lock);
+ 	usbvision_muxsel(usbvision, input);
+ 	usbvision_set_input(usbvision);
+ 	usbvision_set_output(usbvision,
+ 			     usbvision->curwidth,
+ 			     usbvision->curheight);
+-	up(&usbvision->lock);
++	mutex_unlock(&usbvision->lock);
  	return 0;
  }
  
--static void tda9887_configure(struct tuner *t)
-+static void tda9887_configure(struct dvb_frontend *fe)
- {
--	struct tda9887_priv *priv = t->priv;
-+	struct tda9887_priv *priv = fe->analog_demod_priv;
- 	int rc;
+@@ -664,10 +664,10 @@ static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id *id)
+ 		(struct usb_usbvision *) video_get_drvdata(dev);
+ 	usbvision->tvnormId=*id;
  
- 	memset(priv->data,0,sizeof(priv->data));
--	tda9887_set_tvnorm(t,priv->data);
-+	tda9887_set_tvnorm(fe);
+-	down(&usbvision->lock);
++	mutex_lock(&usbvision->lock);
+ 	call_i2c_clients(usbvision, VIDIOC_S_STD,
+ 			 &usbvision->tvnormId);
+-	up(&usbvision->lock);
++	mutex_unlock(&usbvision->lock);
+ 	/* propagate the change to the decoder */
+ 	usbvision_muxsel(usbvision, usbvision->ctl_input);
  
- 	/* A note on the port settings:
- 	   These settings tend to depend on the specifics of the board.
-@@ -547,38 +565,38 @@ static void tda9887_configure(struct tuner *t)
- 	priv->data[1] |= cOutputPort1Inactive;
- 	priv->data[1] |= cOutputPort2Inactive;
+@@ -1083,9 +1083,9 @@ static int vidioc_s_fmt_cap(struct file *file, void *priv,
+ 	usbvision->curFrame = NULL;
  
--	tda9887_set_config(t,priv->data);
--	tda9887_set_insmod(t,priv->data);
-+	tda9887_do_config(fe);
-+	tda9887_set_insmod(fe);
+ 	/* by now we are committed to the new data... */
+-	down(&usbvision->lock);
++	mutex_lock(&usbvision->lock);
+ 	usbvision_set_output(usbvision, vf->fmt.pix.width, vf->fmt.pix.height);
+-	up(&usbvision->lock);
++	mutex_unlock(&usbvision->lock);
  
--	if (t->mode == T_STANDBY) {
-+	if (priv->mode == T_STANDBY)
- 		priv->data[1] |= cForcedMuteAudioON;
--	}
+ 	return 0;
+ }
+@@ -1211,16 +1211,16 @@ static int usbvision_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
  
--	tda9887_dbg("writing: b=0x%02x c=0x%02x e=0x%02x\n",
--		priv->data[1],priv->data[2],priv->data[3]);
--	if (tuner_debug > 1)
--		dump_write_message(t, priv->data);
-+	tuner_dbg("writing: b=0x%02x c=0x%02x e=0x%02x\n",
-+		  priv->data[1], priv->data[2], priv->data[3]);
-+	if (debug > 1)
-+		dump_write_message(fe, priv->data);
+ 	PDEBUG(DBG_MMAP, "mmap");
  
- 	if (4 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,priv->data,4)))
--		tda9887_info("i2c i/o error: rc == %d (should be 4)\n",rc);
-+		tuner_info("i2c i/o error: rc == %d (should be 4)\n", rc);
+-	down(&usbvision->lock);
++	mutex_lock(&usbvision->lock);
  
--	if (tuner_debug > 2) {
-+	if (debug > 2) {
- 		msleep_interruptible(1000);
--		tda9887_status(t);
-+		tda9887_status(fe);
+ 	if (!USBVISION_IS_OPERATIONAL(usbvision)) {
+-		up(&usbvision->lock);
++		mutex_unlock(&usbvision->lock);
+ 		return -EFAULT;
  	}
- }
  
- /* ---------------------------------------------------------------------- */
- 
--static void tda9887_tuner_status(struct tuner *t)
-+static void tda9887_tuner_status(struct dvb_frontend *fe)
- {
--	struct tda9887_priv *priv = t->priv;
--	tda9887_info("Data bytes: b=0x%02x c=0x%02x e=0x%02x\n", priv->data[1], priv->data[2], priv->data[3]);
-+	struct tda9887_priv *priv = fe->analog_demod_priv;
-+	tuner_info("Data bytes: b=0x%02x c=0x%02x e=0x%02x\n",
-+		   priv->data[1], priv->data[2], priv->data[3]);
- }
+ 	if (!(vma->vm_flags & VM_WRITE) ||
+ 	    size != PAGE_ALIGN(usbvision->max_frame_size)) {
+-		up(&usbvision->lock);
++		mutex_unlock(&usbvision->lock);
+ 		return -EINVAL;
+ 	}
  
--static int tda9887_get_afc(struct tuner *t)
-+static int tda9887_get_afc(struct dvb_frontend *fe)
- {
--	struct tda9887_priv *priv = t->priv;
-+	struct tda9887_priv *priv = fe->analog_demod_priv;
- 	static int AFC_BITS_2_kHz[] = {
- 		-12500,  -37500,  -62500,  -97500,
- 		-112500, -137500, -162500, -187500,
-@@ -594,52 +612,79 @@ static int tda9887_get_afc(struct tuner *t)
- 	return afc;
- }
+@@ -1232,7 +1232,7 @@ static int usbvision_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
+ 	if (i == usbvision->num_frames) {
+ 		PDEBUG(DBG_MMAP,
+ 		       "mmap: user supplied mapping address is out of range");
+-		up(&usbvision->lock);
++		mutex_unlock(&usbvision->lock);
+ 		return -EINVAL;
+ 	}
  
--static void tda9887_standby(struct tuner *t)
-+static void tda9887_standby(struct dvb_frontend *fe)
-+{
-+	struct tda9887_priv *priv = fe->analog_demod_priv;
-+
-+	priv->mode = T_STANDBY;
-+
-+	tda9887_configure(fe);
-+}
-+
-+static void tda9887_set_params(struct dvb_frontend *fe,
-+			       struct analog_parameters *params)
- {
--	tda9887_configure(t);
-+	struct tda9887_priv *priv = fe->analog_demod_priv;
-+
-+	priv->mode    = params->mode;
-+	priv->audmode = params->audmode;
-+	priv->std     = params->std;
-+	tda9887_configure(fe);
- }
+@@ -1245,7 +1245,7 @@ static int usbvision_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
  
--static void tda9887_set_freq(struct tuner *t, unsigned int freq)
-+static int tda9887_set_config(struct dvb_frontend *fe, void *priv_cfg)
- {
--	tda9887_configure(t);
-+	struct tda9887_priv *priv = fe->analog_demod_priv;
-+
-+	priv->config = *(unsigned int *)priv_cfg;
-+	tda9887_configure(fe);
-+
-+	return 0;
- }
+ 		if (vm_insert_page(vma, start, vmalloc_to_page(pos))) {
+ 			PDEBUG(DBG_MMAP, "mmap: vm_insert_page failed");
+-			up(&usbvision->lock);
++			mutex_unlock(&usbvision->lock);
+ 			return -EAGAIN;
+ 		}
+ 		start += PAGE_SIZE;
+@@ -1253,7 +1253,7 @@ static int usbvision_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
+ 		size -= PAGE_SIZE;
+ 	}
  
--static void tda9887_release(struct tuner *t)
-+static void tda9887_release(struct dvb_frontend *fe)
- {
--	kfree(t->priv);
--	t->priv = NULL;
-+	kfree(fe->analog_demod_priv);
-+	fe->analog_demod_priv = NULL;
+-	up(&usbvision->lock);
++	mutex_unlock(&usbvision->lock);
+ 	return 0;
  }
  
--static struct tuner_operations tda9887_tuner_ops = {
--	.set_tv_freq    = tda9887_set_freq,
--	.set_radio_freq = tda9887_set_freq,
-+static struct analog_demod_ops tda9887_ops = {
-+	.info		= {
-+		.name	= "tda9887",
-+	},
-+	.set_params     = tda9887_set_params,
- 	.standby        = tda9887_standby,
- 	.tuner_status   = tda9887_tuner_status,
- 	.get_afc        = tda9887_get_afc,
- 	.release        = tda9887_release,
-+	.set_config     = tda9887_set_config,
- };
- 
--int tda9887_tuner_init(struct tuner *t)
-+struct dvb_frontend *tda9887_attach(struct dvb_frontend *fe,
-+				    struct i2c_adapter *i2c_adap,
-+				    u8 i2c_addr)
- {
- 	struct tda9887_priv *priv = NULL;
- 
- 	priv = kzalloc(sizeof(struct tda9887_priv), GFP_KERNEL);
- 	if (priv == NULL)
--		return -ENOMEM;
--	t->priv = priv;
--
--	priv->i2c_props.addr = t->i2c.addr;
--	priv->i2c_props.adap = t->i2c.adapter;
-+		return NULL;
-+	fe->analog_demod_priv = priv;
+@@ -1271,7 +1271,7 @@ static int usbvision_radio_open(struct inode *inode, struct file *file)
  
--	strlcpy(t->i2c.name, "tda9887", sizeof(t->i2c.name));
-+	priv->i2c_props.addr = i2c_addr;
-+	priv->i2c_props.adap = i2c_adap;
-+	priv->mode = T_STANDBY;
+ 	PDEBUG(DBG_IO, "%s:", __FUNCTION__);
  
--	tda9887_info("tda988[5/6/7] found @ 0x%x (%s)\n", t->i2c.addr,
--						t->i2c.driver->driver.name);
-+	tuner_info("tda988[5/6/7] found\n");
+-	down(&usbvision->lock);
++	mutex_lock(&usbvision->lock);
  
--	memcpy(&t->ops, &tda9887_tuner_ops, sizeof(struct tuner_operations));
-+	memcpy(&fe->ops.analog_ops, &tda9887_ops,
-+	       sizeof(struct analog_demod_ops));
+ 	if (usbvision->user) {
+ 		err("%s: Someone tried to open an already opened USBVision Radio!", __FUNCTION__);
+@@ -1290,7 +1290,8 @@ static int usbvision_radio_open(struct inode *inode, struct file *file)
+ 		errCode = usbvision_set_alternate(usbvision);
+ 		if (errCode < 0) {
+ 			usbvision->last_error = errCode;
+-			return -EBUSY;
++			errCode = -EBUSY;
++			goto out;
+ 		}
  
--	return 0;
-+	return fe;
+ 		// If so far no errors then we shall start the radio
+@@ -1307,7 +1308,8 @@ static int usbvision_radio_open(struct inode *inode, struct file *file)
+ 			usbvision->initialized = 0;
+ 		}
+ 	}
+-	up(&usbvision->lock);
++out:
++	mutex_unlock(&usbvision->lock);
+ 	return errCode;
  }
-+EXPORT_SYMBOL_GPL(tda9887_attach);
-+
-+MODULE_LICENSE("GPL");
  
- /*
-  * Overrides for Emacs so that we follow Linus's tabbing style.
-diff --git a/drivers/media/video/tda9887.h b/drivers/media/video/tda9887.h
-new file mode 100644
-index 0000000..8f873a8
---- /dev/null
-+++ b/drivers/media/video/tda9887.h
-@@ -0,0 +1,38 @@
-+/*
-+    This program is free software; you can redistribute it and/or modify
-+    it under the terms of the GNU General Public License as published by
-+    the Free Software Foundation; either version 2 of the License, or
-+    (at your option) any later version.
-+
-+    This program is distributed in the hope that it will be useful,
-+    but WITHOUT ANY WARRANTY; without even the implied warranty of
-+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+    GNU General Public License for more details.
-+
-+    You 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 __TDA9887_H__
-+#define __TDA9887_H__
-+
-+#include <linux/i2c.h>
-+#include "dvb_frontend.h"
-+
-+/* ------------------------------------------------------------------------ */
-+#if defined(CONFIG_TUNER_TDA9887) || (defined(CONFIG_TUNER_TDA9887_MODULE) && defined(MODULE))
-+extern struct dvb_frontend *tda9887_attach(struct dvb_frontend *fe,
-+					   struct i2c_adapter *i2c_adap,
-+					   u8 i2c_addr);
-+#else
-+static inline struct dvb_frontend *tda9887_attach(struct dvb_frontend *fe,
-+						  struct i2c_adapter *i2c_adap,
-+						  u8 i2c_addr)
-+{
-+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
-+	return NULL;
-+}
-+#endif
-+
-+#endif /* __TDA9887_H__ */
-diff --git a/drivers/media/video/tea5761.c b/drivers/media/video/tea5761.c
-index 2150222..5326eec 100644
---- a/drivers/media/video/tea5761.c
-+++ b/drivers/media/video/tea5761.c
-@@ -18,7 +18,7 @@ static int debug = 0;
- module_param(debug, int, 0644);
- MODULE_PARM_DESC(debug, "enable verbose debug messages");
+@@ -1321,7 +1323,7 @@ static int usbvision_radio_close(struct inode *inode, struct file *file)
  
--#define PREFIX "tea5761 "
-+#define PREFIX "tea5761"
+ 	PDEBUG(DBG_IO, "");
  
- struct tea5761_priv {
- 	struct tuner_i2c_props i2c_props;
-diff --git a/drivers/media/video/tea5767.c b/drivers/media/video/tea5767.c
-index 71df419..e1b48d8 100644
---- a/drivers/media/video/tea5767.c
-+++ b/drivers/media/video/tea5767.c
-@@ -20,12 +20,14 @@ static int debug = 0;
- module_param(debug, int, 0644);
- MODULE_PARM_DESC(debug, "enable verbose debug messages");
+-	down(&usbvision->lock);
++	mutex_lock(&usbvision->lock);
  
--#define PREFIX "tea5767 "
-+#define PREFIX "tea5767"
+ 	/* Set packet size to 0 */
+ 	usbvision->ifaceAlt=0;
+@@ -1337,7 +1339,7 @@ static int usbvision_radio_close(struct inode *inode, struct file *file)
+ 		usbvision->initialized = 0;
+ 	}
  
--struct tea5767_priv {
--	struct tuner_i2c_props i2c_props;
-+/*****************************************************************************/
+-	up(&usbvision->lock);
++	mutex_unlock(&usbvision->lock);
  
--	u32 frequency;
-+struct tea5767_priv {
-+	struct tuner_i2c_props	i2c_props;
-+	u32			frequency;
-+	struct tea5767_ctrl	ctrl;
- };
+ 	if (usbvision->remove_pending) {
+ 		printk(KERN_INFO "%s: Final disconnect\n", __FUNCTION__);
+@@ -1641,7 +1643,7 @@ static struct usb_usbvision *usbvision_alloc(struct usb_device *dev)
  
- /*****************************************************************************/
-@@ -127,17 +129,10 @@ struct tea5767_priv {
- /* Reserved for future extensions */
- #define TEA5767_RESERVED_MASK	0xff
+ 	usbvision->dev = dev;
  
--enum tea5767_xtal_freq {
--	TEA5767_LOW_LO_32768    = 0,
--	TEA5767_HIGH_LO_32768   = 1,
--	TEA5767_LOW_LO_13MHz    = 2,
--	TEA5767_HIGH_LO_13MHz   = 3,
--};
--
--
- /*****************************************************************************/
+-	init_MUTEX(&usbvision->lock);	/* to 1 == available */
++	mutex_init(&usbvision->lock);	/* available */
  
--static void tea5767_status_dump(unsigned char *buffer)
-+static void tea5767_status_dump(struct tea5767_priv *priv,
-+				unsigned char *buffer)
- {
- 	unsigned int div, frq;
+ 	// prepare control urb for control messages during interrupts
+ 	usbvision->ctrlUrb = usb_alloc_urb(USBVISION_URB_FRAMES, GFP_KERNEL);
+@@ -1649,7 +1651,6 @@ static struct usb_usbvision *usbvision_alloc(struct usb_device *dev)
+ 		goto err_exit;
+ 	}
+ 	init_waitqueue_head(&usbvision->ctrlUrb_wq);
+-	init_MUTEX(&usbvision->ctrlUrbLock);	/* to 1 == available */
  
-@@ -153,7 +148,7 @@ static void tea5767_status_dump(unsigned char *buffer)
+ 	usbvision_init_powerOffTimer(usbvision);
  
- 	div = ((buffer[0] & 0x3f) << 8) | buffer[1];
+@@ -1676,13 +1677,13 @@ static void usbvision_release(struct usb_usbvision *usbvision)
+ {
+ 	PDEBUG(DBG_PROBE, "");
  
--	switch (TEA5767_HIGH_LO_32768) {
-+	switch (priv->ctrl.xtal_freq) {
- 	case TEA5767_HIGH_LO_13MHz:
- 		frq = (div * 50000 - 700000 - 225000) / 4;	/* Freq in KHz */
- 		break;
-@@ -202,13 +197,10 @@ static int set_radio_freq(struct dvb_frontend *fe,
+-	down(&usbvision->lock);
++	mutex_lock(&usbvision->lock);
  
- 	tuner_dbg("radio freq = %d.%03d MHz\n", frq/16000,(frq/16)%1000);
+ 	usbvision_reset_powerOffTimer(usbvision);
  
--	/* Rounds freq to next decimal value - for 62.5 KHz step */
--	/* frq = 20*(frq/16)+radio_frq[frq%16]; */
-+	buffer[2] = 0;
+ 	usbvision->initialized = 0;
  
--	buffer[2] = TEA5767_PORT1_HIGH;
--	buffer[3] = TEA5767_PORT2_HIGH | TEA5767_HIGH_CUT_CTRL |
--		    TEA5767_ST_NOISE_CTL | TEA5767_JAPAN_BAND;
--	buffer[4] = 0;
-+	if (priv->ctrl.port1)
-+		buffer[2] |= TEA5767_PORT1_HIGH;
+-	up(&usbvision->lock);
++	mutex_unlock(&usbvision->lock);
  
- 	if (params->audmode == V4L2_TUNER_MODE_MONO) {
- 		tuner_dbg("TEA5767 set to mono\n");
-@@ -217,18 +209,45 @@ static int set_radio_freq(struct dvb_frontend *fe,
- 		tuner_dbg("TEA5767 set to stereo\n");
+ 	usbvision_remove_sysfs(usbvision->vdev);
+ 	usbvision_unregister_video(usbvision);
+@@ -1796,7 +1797,7 @@ static int __devinit usbvision_probe(struct usb_interface *intf,
  	}
+ 	PDEBUG(DBG_PROBE, "bridgeType %d", usbvision->bridgeType);
  
--	/* Should be replaced */
--	switch (TEA5767_HIGH_LO_32768) {
-+
-+	buffer[3] = 0;
-+
-+	if (priv->ctrl.port2)
-+		buffer[3] |= TEA5767_PORT2_HIGH;
-+
-+	if (priv->ctrl.high_cut)
-+		buffer[3] |= TEA5767_HIGH_CUT_CTRL;
-+
-+	if (priv->ctrl.st_noise)
-+		buffer[3] |= TEA5767_ST_NOISE_CTL;
-+
-+	if (priv->ctrl.soft_mute)
-+		buffer[3] |= TEA5767_SOFT_MUTE;
-+
-+	if (priv->ctrl.japan_band)
-+		buffer[3] |= TEA5767_JAPAN_BAND;
-+
-+	buffer[4] = 0;
-+
-+	if (priv->ctrl.deemph_75)
-+		buffer[4] |= TEA5767_DEEMPH_75;
-+
-+	if (priv->ctrl.pllref)
-+		buffer[4] |= TEA5767_PLLREF_ENABLE;
-+
-+
-+	/* Rounds freq to next decimal value - for 62.5 KHz step */
-+	/* frq = 20*(frq/16)+radio_frq[frq%16]; */
-+
-+	switch (priv->ctrl.xtal_freq) {
- 	case TEA5767_HIGH_LO_13MHz:
- 		tuner_dbg("radio HIGH LO inject xtal @ 13 MHz\n");
- 		buffer[2] |= TEA5767_HIGH_LO_INJECT;
--		buffer[4] |= TEA5767_PLLREF_ENABLE;
- 		div = (frq * (4000 / 16) + 700000 + 225000 + 25000) / 50000;
- 		break;
- 	case TEA5767_LOW_LO_13MHz:
- 		tuner_dbg("radio LOW LO inject xtal @ 13 MHz\n");
- 
--		buffer[4] |= TEA5767_PLLREF_ENABLE;
- 		div = (frq * (4000 / 16) - 700000 - 225000 + 25000) / 50000;
- 		break;
- 	case TEA5767_LOW_LO_32768:
-@@ -256,7 +275,7 @@ static int set_radio_freq(struct dvb_frontend *fe,
- 		if (5 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 5)))
- 			tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc);
- 		else
--			tea5767_status_dump(buffer);
-+			tea5767_status_dump(priv, buffer);
- 	}
+-	down(&usbvision->lock);
++	mutex_lock(&usbvision->lock);
  
- 	priv->frequency = frq * 125 / 2;
-@@ -382,7 +401,6 @@ int tea5767_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr)
- 		return EINVAL;
+ 	/* compute alternate max packet sizes */
+ 	uif = dev->actconfig->interface[0];
+@@ -1807,6 +1808,7 @@ static int __devinit usbvision_probe(struct usb_interface *intf,
+ 					      usbvision->num_alt,GFP_KERNEL);
+ 	if (usbvision->alt_max_pkt_size == NULL) {
+ 		err("usbvision: out of memory!\n");
++		mutex_unlock(&usbvision->lock);
+ 		return -ENOMEM;
  	}
  
--	printk(KERN_WARNING "TEA5767 detected.\n");
- 	return 0;
- }
- 
-@@ -398,6 +416,16 @@ static int tea5767_get_frequency(struct dvb_frontend *fe, u32 *frequency)
- {
- 	struct tea5767_priv *priv = fe->tuner_priv;
- 	*frequency = priv->frequency;
-+
-+	return 0;
-+}
-+
-+static int tea5767_set_config (struct dvb_frontend *fe, void *priv_cfg)
-+{
-+	struct tea5767_priv *priv = fe->tuner_priv;
-+
-+	memcpy(&priv->ctrl, priv_cfg, sizeof(priv->ctrl));
-+
- 	return 0;
- }
+@@ -1840,7 +1842,7 @@ static int __devinit usbvision_probe(struct usb_interface *intf,
+ 	usbvision->streaming = Stream_Off;
+ 	usbvision_register_video(usbvision);
+ 	usbvision_configure_video(usbvision);
+-	up(&usbvision->lock);
++	mutex_unlock(&usbvision->lock);
  
-@@ -407,6 +435,7 @@ static struct dvb_tuner_ops tea5767_tuner_ops = {
- 	},
  
- 	.set_analog_params = set_radio_freq,
-+	.set_config	   = tea5767_set_config,
- 	.sleep             = tea5767_standby,
- 	.release           = tea5767_release,
- 	.get_frequency     = tea5767_get_frequency,
-@@ -425,8 +454,14 @@ struct dvb_frontend *tea5767_attach(struct dvb_frontend *fe,
- 		return NULL;
- 	fe->tuner_priv = priv;
+ 	usb_set_intfdata (intf, usbvision);
+@@ -1871,7 +1873,7 @@ static void __devexit usbvision_disconnect(struct usb_interface *intf)
+ 	}
+ 	usb_set_intfdata (intf, NULL);
  
--	priv->i2c_props.addr = i2c_addr;
--	priv->i2c_props.adap = i2c_adap;
-+	priv->i2c_props.addr  = i2c_addr;
-+	priv->i2c_props.adap  = i2c_adap;
-+	priv->ctrl.xtal_freq  = TEA5767_HIGH_LO_32768;
-+	priv->ctrl.port1      = 1;
-+	priv->ctrl.port2      = 1;
-+	priv->ctrl.high_cut   = 1;
-+	priv->ctrl.st_noise   = 1;
-+	priv->ctrl.japan_band = 1;
+-	down(&usbvision->lock);
++	mutex_lock(&usbvision->lock);
  
- 	memcpy(&fe->ops.tuner_ops, &tea5767_tuner_ops,
- 	       sizeof(struct dvb_tuner_ops));
-@@ -436,7 +471,6 @@ struct dvb_frontend *tea5767_attach(struct dvb_frontend *fe,
- 	return fe;
- }
+ 	// At this time we ask to cancel outstanding URBs
+ 	usbvision_stop_isoc(usbvision);
+@@ -1885,7 +1887,7 @@ static void __devexit usbvision_disconnect(struct usb_interface *intf)
+ 	usb_put_dev(usbvision->dev);
+ 	usbvision->dev = NULL;	// USB device is no more
  
--
- EXPORT_SYMBOL_GPL(tea5767_attach);
- EXPORT_SYMBOL_GPL(tea5767_autodetection);
+-	up(&usbvision->lock);
++	mutex_unlock(&usbvision->lock);
  
-diff --git a/drivers/media/video/tea5767.h b/drivers/media/video/tea5767.h
-index 5d78281..a44451f 100644
---- a/drivers/media/video/tea5767.h
-+++ b/drivers/media/video/tea5767.h
-@@ -20,6 +20,25 @@
+ 	if (usbvision->user) {
+ 		printk(KERN_INFO "%s: In use, disconnect pending\n",
+diff --git a/drivers/media/video/usbvision/usbvision.h b/drivers/media/video/usbvision/usbvision.h
+index c5b6c50..20d7ec6 100644
+--- a/drivers/media/video/usbvision/usbvision.h
++++ b/drivers/media/video/usbvision/usbvision.h
+@@ -34,16 +34,13 @@
+ #include <linux/list.h>
+ #include <linux/usb.h>
  #include <linux/i2c.h>
- #include "dvb_frontend.h"
- 
-+enum tea5767_xtal {
-+	TEA5767_LOW_LO_32768    = 0,
-+	TEA5767_HIGH_LO_32768   = 1,
-+	TEA5767_LOW_LO_13MHz    = 2,
-+	TEA5767_HIGH_LO_13MHz   = 3,
-+};
-+
-+struct tea5767_ctrl {
-+	unsigned int		port1:1;
-+	unsigned int		port2:1;
-+	unsigned int		high_cut:1;
-+	unsigned int		st_noise:1;
-+	unsigned int		soft_mute:1;
-+	unsigned int		japan_band:1;
-+	unsigned int		deemph_75:1;
-+	unsigned int		pllref:1;
-+	enum tea5767_xtal	xtal_freq;
-+};
-+
- #if defined(CONFIG_TUNER_TEA5767) || (defined(CONFIG_TUNER_TEA5767_MODULE) && defined(MODULE))
- extern int tea5767_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr);
- 
-diff --git a/drivers/media/video/tlv320aic23b.c b/drivers/media/video/tlv320aic23b.c
-index 76b2e96..dc7b9c2 100644
---- a/drivers/media/video/tlv320aic23b.c
-+++ b/drivers/media/video/tlv320aic23b.c
-@@ -31,6 +31,7 @@
- #include <linux/i2c-id.h>
- #include <linux/videodev.h>
++#include <linux/mutex.h>
  #include <media/v4l2-common.h>
-+#include <media/v4l2-i2c-drv-legacy.h>
- 
- MODULE_DESCRIPTION("tlv320aic23b driver");
- MODULE_AUTHOR("Scott Alfter, Ulf Eklund, Hans Verkuil");
-@@ -56,37 +57,35 @@ static int tlv320aic23b_write(struct i2c_client *client, int reg, u16 val)
- 		return -1;
- 	}
- 
--	for (i = 0; i < 3; i++) {
--		if (i2c_smbus_write_byte_data(client, (reg << 1) |
--					(val >> 8), val & 0xff) == 0) {
-+	for (i = 0; i < 3; i++)
-+		if (i2c_smbus_write_byte_data(client,
-+				(reg << 1) | (val >> 8), val & 0xff) == 0)
- 			return 0;
--		}
--	}
- 	v4l_err(client, "I2C: cannot write %03x to register R%d\n", val, reg);
- 	return -1;
- }
- 
--static int tlv320aic23b_command(struct i2c_client *client, unsigned int cmd,
--			  void *arg)
-+static int tlv320aic23b_command(struct i2c_client *client,
-+				unsigned int cmd, void *arg)
- {
- 	struct tlv320aic23b_state *state = i2c_get_clientdata(client);
- 	struct v4l2_control *ctrl = arg;
--	u32* freq = arg;
-+	u32 *freq = arg;
- 
- 	switch (cmd) {
- 	case VIDIOC_INT_AUDIO_CLOCK_FREQ:
- 		switch (*freq) {
--			case 32000: /* set sample rate to 32 kHz */
--				tlv320aic23b_write(client, 8, 0x018);
--				break;
--			case 44100: /* set sample rate to 44.1 kHz */
--				tlv320aic23b_write(client, 8, 0x022);
--				break;
--			case 48000: /* set sample rate to 48 kHz */
--				tlv320aic23b_write(client, 8, 0x000);
--				break;
--			default:
--				return -EINVAL;
-+		case 32000: /* set sample rate to 32 kHz */
-+			tlv320aic23b_write(client, 8, 0x018);
-+			break;
-+		case 44100: /* set sample rate to 44.1 kHz */
-+			tlv320aic23b_write(client, 8, 0x022);
-+			break;
-+		case 48000: /* set sample rate to 48 kHz */
-+			tlv320aic23b_write(client, 8, 0x000);
-+			break;
-+		default:
-+			return -EINVAL;
- 		}
- 		break;
- 
-@@ -126,92 +125,53 @@ static int tlv320aic23b_command(struct i2c_client *client, unsigned int cmd,
-  * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
-  */
- 
--static struct i2c_driver i2c_driver;
--
--static int tlv320aic23b_attach(struct i2c_adapter *adapter, int address, int kind)
-+static int tlv320aic23b_probe(struct i2c_client *client)
- {
--	struct i2c_client *client;
- 	struct tlv320aic23b_state *state;
- 
- 	/* Check if the adapter supports the needed features */
--	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
--		return 0;
--
--	client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
--	if (client == 0)
--		return -ENOMEM;
--
--	client->addr = address;
--	client->adapter = adapter;
--	client->driver = &i2c_driver;
--	snprintf(client->name, sizeof(client->name) - 1, "tlv320aic23b");
-+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
-+		return -EIO;
- 
--	v4l_info(client, "chip found @ 0x%x (%s)\n", address << 1, adapter->name);
-+	v4l_info(client, "chip found @ 0x%x (%s)\n",
-+			client->addr << 1, client->adapter->name);
- 
- 	state = kmalloc(sizeof(struct tlv320aic23b_state), GFP_KERNEL);
--	if (state == NULL) {
--		kfree(client);
-+	if (state == NULL)
- 		return -ENOMEM;
--	}
- 	state->muted = 0;
- 	i2c_set_clientdata(client, state);
+ #include <media/tuner.h>
+ #include <linux/videodev2.h>
  
--	/* initialize tlv320aic23b */
--	tlv320aic23b_write(client, 15, 0x000);	/* RESET */
--	tlv320aic23b_write(client, 6, 0x00A);   /* turn off DAC & mic input */
--	tlv320aic23b_write(client, 7, 0x049);   /* left-justified, 24-bit, master mode */
--	tlv320aic23b_write(client, 0, 0x119);   /* set gain on both channels to +3.0 dB */
--	tlv320aic23b_write(client, 8, 0x000);   /* set sample rate to 48 kHz */
--	tlv320aic23b_write(client, 9, 0x001);   /* activate digital interface */
--
--	i2c_attach_client(client);
--
-+	/* Initialize tlv320aic23b */
-+
-+	/* RESET */
-+	tlv320aic23b_write(client, 15, 0x000);
-+	/* turn off DAC & mic input */
-+	tlv320aic23b_write(client, 6, 0x00A);
-+	/* left-justified, 24-bit, master mode */
-+	tlv320aic23b_write(client, 7, 0x049);
-+	/* set gain on both channels to +3.0 dB */
-+	tlv320aic23b_write(client, 0, 0x119);
-+	/* set sample rate to 48 kHz */
-+	tlv320aic23b_write(client, 8, 0x000);
-+	/* activate digital interface */
-+	tlv320aic23b_write(client, 9, 0x001);
- 	return 0;
- }
+ #define USBVISION_DEBUG		/* Turn on debug messages */
  
--static int tlv320aic23b_probe(struct i2c_adapter *adapter)
-+static int tlv320aic23b_remove(struct i2c_client *client)
- {
--	if (adapter->class & I2C_CLASS_TV_ANALOG)
--		return i2c_probe(adapter, &addr_data, tlv320aic23b_attach);
--	return 0;
--}
--
--static int tlv320aic23b_detach(struct i2c_client *client)
--{
--	int err;
--
--	err = i2c_detach_client(client);
--	if (err) {
--		return err;
--	}
--	kfree(client);
+-#ifndef VID_HARDWARE_USBVISION
+-	#define VID_HARDWARE_USBVISION 34   /* USBVision Video Grabber */
+-#endif
 -
-+	kfree(i2c_get_clientdata(client));
- 	return 0;
- }
+ #define USBVISION_PWR_REG		0x00
+ 	#define USBVISION_SSPND_EN		(1 << 1)
+ 	#define USBVISION_RES2			(1 << 2)
+@@ -373,7 +370,6 @@ struct usb_usbvision {
+ 	int ctrlUrbBusy;
+ 	struct usb_ctrlrequest ctrlUrbSetup;
+ 	wait_queue_head_t ctrlUrb_wq;					// Processes waiting
+-	struct semaphore ctrlUrbLock;
  
- /* ----------------------------------------------------------------------- */
+ 	/* configuration part */
+ 	int have_tuner;
+@@ -396,7 +392,7 @@ struct usb_usbvision {
+ 	unsigned char iface;						/* Video interface number */
+ 	unsigned char ifaceAlt;			/* Alt settings */
+ 	unsigned char Vin_Reg2_Preset;
+-	struct semaphore lock;
++	struct mutex               lock;
+ 	struct timer_list powerOffTimer;
+ 	struct work_struct powerOffWork;
+ 	int power;							/* is the device powered on? */
+diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c
+index 1141b4b..c056ff6 100644
+--- a/drivers/media/video/v4l2-common.c
++++ b/drivers/media/video/v4l2-common.c
+@@ -400,7 +400,7 @@ static const char *v4l2_int_ioctls[] = {
  
--/* i2c implementation */
--static struct i2c_driver i2c_driver = {
--	.driver = {
--		.name = "tlv320aic23b",
--	},
--	.id             = I2C_DRIVERID_TLV320AIC23B,
--	.attach_adapter = tlv320aic23b_probe,
--	.detach_client  = tlv320aic23b_detach,
--	.command        = tlv320aic23b_command,
--};
--
+ 	[_IOC_NR(TUNER_SET_TYPE_ADDR)]         = "TUNER_SET_TYPE_ADDR",
+ 	[_IOC_NR(TUNER_SET_STANDBY)]           = "TUNER_SET_STANDBY",
+-	[_IOC_NR(TDA9887_SET_CONFIG)]          = "TDA9887_SET_CONFIG",
++	[_IOC_NR(TUNER_SET_CONFIG)]            = "TUNER_SET_CONFIG",
  
--static int __init tlv320aic23b_init_module(void)
--{
--	return i2c_add_driver(&i2c_driver);
--}
--
--static void __exit tlv320aic23b_cleanup_module(void)
--{
--	i2c_del_driver(&i2c_driver);
--}
--
--module_init(tlv320aic23b_init_module);
--module_exit(tlv320aic23b_cleanup_module);
-+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
-+	.name = "tlv320aic23b",
-+	.driverid = I2C_DRIVERID_TLV320AIC23B,
-+	.command = tlv320aic23b_command,
-+	.probe = tlv320aic23b_probe,
-+	.remove = tlv320aic23b_remove,
-+};
-diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c
-index 9e99f36..ba538f6 100644
---- a/drivers/media/video/tuner-core.c
-+++ b/drivers/media/video/tuner-core.c
-@@ -19,15 +19,41 @@
- #include <media/tuner.h>
- #include <media/tuner-types.h>
- #include <media/v4l2-common.h>
--#include "tuner-driver.h"
-+#include <media/v4l2-i2c-drv-legacy.h>
- #include "mt20xx.h"
- #include "tda8290.h"
- #include "tea5761.h"
- #include "tea5767.h"
-+#include "tuner-xc2028.h"
- #include "tuner-simple.h"
-+#include "tda9887.h"
-+#include "xc5000.h"
+ 	[_IOC_NR(VIDIOC_INT_S_TUNER_MODE)]     = "VIDIOC_INT_S_TUNER_MODE",
+ 	[_IOC_NR(VIDIOC_INT_RESET)]            = "VIDIOC_INT_RESET",
+@@ -1013,6 +1013,34 @@ int v4l2_chip_match_host(u32 match_type, u32 match_chip)
  
- #define UNSET (-1U)
+ /* ----------------------------------------------------------------- */
  
-+#define PREFIX t->i2c->driver->driver.name
-+
-+struct tuner {
-+	/* device */
-+	struct dvb_frontend fe;
-+	struct i2c_client   *i2c;
-+	struct list_head    list;
-+	unsigned int        using_v4l2:1;
-+
-+	/* keep track of the current settings */
-+	v4l2_std_id         std;
-+	unsigned int        tv_freq;
-+	unsigned int        radio_freq;
-+	unsigned int        audmode;
-+
-+	unsigned int        mode;
-+	unsigned int        mode_mask; /* Combination of allowable modes */
++/* Helper function for I2C legacy drivers */
 +
-+	unsigned int        type; /* chip type id */
-+	unsigned int        config;
-+	int (*tuner_callback) (void *dev, int command, int arg);
-+};
++int v4l2_i2c_attach(struct i2c_adapter *adapter, int address, struct i2c_driver *driver,
++		const char *name, int (*probe)(struct i2c_client *))
++{
++	struct i2c_client *client;
++	int err;
 +
- /* standard i2c insmod options */
- static unsigned short normal_i2c[] = {
- #if defined(CONFIG_TUNER_TEA5761) || (defined(CONFIG_TUNER_TEA5761_MODULE) && defined(MODULE))
-@@ -47,7 +73,34 @@ static unsigned int no_autodetect = 0;
- static unsigned int show_i2c = 0;
- 
- /* insmod options used at runtime => read/write */
--int tuner_debug = 0;
-+static int tuner_debug;
++	client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
++	if (client == 0)
++		return -ENOMEM;
 +
-+#define tuner_warn(fmt, arg...) do {			\
-+	printk(KERN_WARNING "%s %d-%04x: " fmt, PREFIX, \
-+	       i2c_adapter_id(t->i2c->adapter),		\
-+	       t->i2c->addr, ##arg);			\
-+	 } while (0)
++	client->addr = address;
++	client->adapter = adapter;
++	client->driver = driver;
++	strlcpy(client->name, name, sizeof(client->name));
 +
-+#define tuner_info(fmt, arg...) do {			\
-+	printk(KERN_INFO "%s %d-%04x: " fmt, PREFIX,	\
-+	       i2c_adapter_id(t->i2c->adapter),		\
-+	       t->i2c->addr, ##arg);			\
-+	 } while (0)
++	err = probe(client);
++	if (err == 0) {
++		i2c_attach_client(client);
++	} else {
++		kfree(client);
++	}
++	return err != -ENOMEM ? 0 : err;
++}
 +
-+#define tuner_err(fmt, arg...) do {			\
-+	printk(KERN_ERR "%s %d-%04x: " fmt, PREFIX,	\
-+	       i2c_adapter_id(t->i2c->adapter),		\
-+	       t->i2c->addr, ##arg);			\
-+	 } while (0)
++/* ----------------------------------------------------------------- */
 +
-+#define tuner_dbg(fmt, arg...) do {				\
-+	if (tuner_debug)					\
-+		printk(KERN_DEBUG "%s %d-%04x: " fmt, PREFIX,	\
-+		       i2c_adapter_id(t->i2c->adapter),		\
-+		       t->i2c->addr, ##arg);			\
-+	 } while (0)
+ EXPORT_SYMBOL(v4l2_norm_to_name);
+ EXPORT_SYMBOL(v4l2_video_std_construct);
+ 
+@@ -1038,6 +1066,8 @@ EXPORT_SYMBOL(v4l2_chip_match_i2c_client);
+ EXPORT_SYMBOL(v4l2_chip_ident_i2c_client);
+ EXPORT_SYMBOL(v4l2_chip_match_host);
+ 
++EXPORT_SYMBOL(v4l2_i2c_attach);
 +
-+/* ------------------------------------------------------------------------ */
+ /*
+  * Local variables:
+  * c-basic-offset: 8
+diff --git a/drivers/media/video/v4l2-int-device.c b/drivers/media/video/v4l2-int-device.c
+index 8b4ef53..a545dca 100644
+--- a/drivers/media/video/v4l2-int-device.c
++++ b/drivers/media/video/v4l2-int-device.c
+@@ -57,12 +57,12 @@ static void v4l2_int_device_try_attach_all(void)
+ 			if (!try_module_get(m->module))
+ 				continue;
  
- static unsigned int tv_range[2] = { 44, 958 };
- static unsigned int radio_range[2] = { 65, 108 };
-@@ -71,66 +124,96 @@ MODULE_DESCRIPTION("device driver for various TV and TV+FM radio tuners");
- MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer");
+-			if (m->u.master->attach(m, s)) {
++			s->u.slave->master = m;
++			if (m->u.master->attach(s)) {
++				s->u.slave->master = NULL;
+ 				module_put(m->module);
+ 				continue;
+ 			}
+-
+-			s->u.slave->master = m;
+ 		}
+ 	}
+ }
+diff --git a/drivers/media/video/videobuf-core.c b/drivers/media/video/videobuf-core.c
+index c8a5cb5..80a14da 100644
+--- a/drivers/media/video/videobuf-core.c
++++ b/drivers/media/video/videobuf-core.c
+@@ -22,29 +22,32 @@
+ #include <media/videobuf-core.h>
+ 
+ #define MAGIC_BUFFER 0x20070728
+-#define MAGIC_CHECK(is,should)	if (unlikely((is) != (should))) \
+-	{ printk(KERN_ERR "magic mismatch: %x (expected %x)\n",is,should); BUG(); }
++#define MAGIC_CHECK(is, should) do {					   \
++	if (unlikely((is) != (should))) {				   \
++	printk(KERN_ERR "magic mismatch: %x (expected %x)\n", is, should); \
++	BUG(); } } while (0)
+ 
+-static int debug = 0;
++static int debug;
+ module_param(debug, int, 0644);
+ 
+ MODULE_DESCRIPTION("helper module to manage video4linux buffers");
+ MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab at infradead.org>");
  MODULE_LICENSE("GPL");
  
--static struct i2c_driver driver;
--static struct i2c_client client_template;
--
- /* ---------------------------------------------------------------------- */
+-#define dprintk(level, fmt, arg...)	if (debug >= level) \
+-	printk(KERN_DEBUG "vbuf: " fmt , ## arg)
++#define dprintk(level, fmt, arg...) do {			\
++	if (debug >= level) 					\
++	printk(KERN_DEBUG "vbuf: " fmt , ## arg); } while (0)
  
--static void fe_set_freq(struct tuner *t, unsigned int freq)
-+static void fe_set_params(struct dvb_frontend *fe,
-+			  struct analog_parameters *params)
+ /* --------------------------------------------------------------------- */
+ 
+ #define CALL(q, f, arg...)						\
+-	( (q->int_ops->f)? q->int_ops->f(arg) : 0)
++	((q->int_ops->f) ? q->int_ops->f(arg) : 0)
+ 
+-void* videobuf_alloc(struct videobuf_queue* q)
++void *videobuf_alloc(struct videobuf_queue *q)
  {
--	struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
--
--	struct analog_parameters params = {
--		.frequency = freq,
--		.mode      = t->mode,
--		.audmode   = t->audmode,
--		.std       = t->std
--	};
-+	struct dvb_tuner_ops *fe_tuner_ops = &fe->ops.tuner_ops;
-+	struct tuner *t = fe->analog_demod_priv;
+ 	struct videobuf_buffer *vb;
  
- 	if (NULL == fe_tuner_ops->set_analog_params) {
- 		tuner_warn("Tuner frontend module has no way to set freq\n");
- 		return;
- 	}
--	fe_tuner_ops->set_analog_params(&t->fe, &params);
-+	fe_tuner_ops->set_analog_params(fe, params);
+-	BUG_ON (q->msize<sizeof(*vb));
++	BUG_ON(q->msize < sizeof(*vb));
+ 
+ 	if (!q->int_ops || !q->int_ops->alloc) {
+ 		printk(KERN_ERR "No specific ops defined!\n");
+@@ -66,20 +69,21 @@ int videobuf_waiton(struct videobuf_buffer *vb, int non_blocking, int intr)
+ 	int retval = 0;
+ 	DECLARE_WAITQUEUE(wait, current);
+ 
+-	MAGIC_CHECK(vb->magic,MAGIC_BUFFER);
++	MAGIC_CHECK(vb->magic, MAGIC_BUFFER);
+ 	add_wait_queue(&vb->done, &wait);
+-	while (vb->state == STATE_ACTIVE || vb->state == STATE_QUEUED) {
++	while (vb->state == VIDEOBUF_ACTIVE || vb->state == VIDEOBUF_QUEUED) {
+ 		if (non_blocking) {
+ 			retval = -EAGAIN;
+ 			break;
+ 		}
+ 		set_current_state(intr  ? TASK_INTERRUPTIBLE
+ 					: TASK_UNINTERRUPTIBLE);
+-		if (vb->state == STATE_ACTIVE || vb->state == STATE_QUEUED)
++		if (vb->state == VIDEOBUF_ACTIVE ||
++		    vb->state == VIDEOBUF_QUEUED)
+ 			schedule();
+ 		set_current_state(TASK_RUNNING);
+ 		if (intr && signal_pending(current)) {
+-			dprintk(1,"buffer waiton: -EINTR\n");
++			dprintk(1, "buffer waiton: -EINTR\n");
+ 			retval = -EINTR;
+ 			break;
+ 		}
+@@ -88,27 +92,33 @@ int videobuf_waiton(struct videobuf_buffer *vb, int non_blocking, int intr)
+ 	return retval;
  }
  
--static void fe_release(struct tuner *t)
-+static void fe_release(struct dvb_frontend *fe)
+-int videobuf_iolock(struct videobuf_queue* q, struct videobuf_buffer *vb,
++int videobuf_iolock(struct videobuf_queue *q, struct videobuf_buffer *vb,
+ 		    struct v4l2_framebuffer *fbuf)
  {
--	struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
+-	MAGIC_CHECK(vb->magic,MAGIC_BUFFER);
+-	MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);
++	MAGIC_CHECK(vb->magic, MAGIC_BUFFER);
++	MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
+ 
+-	/* FIXME: This is required to avoid OOPS on some cases, since mmap_mapper()
+-	   method should be called before _iolock.
++	/* This is required to avoid OOPS on some cases,
++	   since mmap_mapper() method should be called before _iolock.
+ 	   On some cases, the mmap_mapper() is called only after scheduling.
 -
--	if (fe_tuner_ops->release)
--		fe_tuner_ops->release(&t->fe);
-+	if (fe->ops.tuner_ops.release)
-+		fe->ops.tuner_ops.release(fe);
-+
-+	/* DO NOT kfree(fe->analog_demod_priv)
-+	 *
-+	 * If we are in this function, analog_demod_priv contains a pointer
-+	 * to struct tuner *t.  This will be kfree'd in tuner_detach().
-+	 *
-+	 * Otherwise, fe->ops.analog_demod_ops->release will
-+	 * handle the cleanup for analog demodulator modules.
-+	 */
-+	fe->analog_demod_priv = NULL;
+-	   However, this way is just too dirty! Better to wait for some event.
+ 	 */
+-	schedule_timeout(HZ);
++	if (vb->memory == V4L2_MEMORY_MMAP) {
++		wait_event_timeout(vb->done, q->is_mmapped,
++				   msecs_to_jiffies(100));
++		if (!q->is_mmapped) {
++			printk(KERN_ERR
++			       "Error: mmap_mapper() never called!\n");
++			return -EINVAL;
++		}
++	}
+ 
+-	return CALL(q,iolock,q,vb,fbuf);
++	return CALL(q, iolock, q, vb, fbuf);
  }
  
--static void fe_standby(struct tuner *t)
-+static void fe_standby(struct dvb_frontend *fe)
+ /* --------------------------------------------------------------------- */
+ 
+ 
+-void videobuf_queue_core_init(struct videobuf_queue* q,
++void videobuf_queue_core_init(struct videobuf_queue *q,
+ 			 struct videobuf_queue_ops *ops,
+ 			 void *dev,
+ 			 spinlock_t *irqlock,
+@@ -118,7 +128,7 @@ void videobuf_queue_core_init(struct videobuf_queue* q,
+ 			 void *priv,
+ 			 struct videobuf_qtype_ops *int_ops)
  {
--	struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
-+	struct dvb_tuner_ops *fe_tuner_ops = &fe->ops.tuner_ops;
+-	memset(q,0,sizeof(*q));
++	memset(q, 0, sizeof(*q));
+ 	q->irqlock   = irqlock;
+ 	q->dev       = dev;
+ 	q->type      = type;
+@@ -129,13 +139,13 @@ void videobuf_queue_core_init(struct videobuf_queue* q,
+ 	q->int_ops   = int_ops;
  
- 	if (fe_tuner_ops->sleep)
--		fe_tuner_ops->sleep(&t->fe);
-+		fe_tuner_ops->sleep(fe);
- }
+ 	/* All buffer operations are mandatory */
+-	BUG_ON (!q->ops->buf_setup);
+-	BUG_ON (!q->ops->buf_prepare);
+-	BUG_ON (!q->ops->buf_queue);
+-	BUG_ON (!q->ops->buf_release);
++	BUG_ON(!q->ops->buf_setup);
++	BUG_ON(!q->ops->buf_prepare);
++	BUG_ON(!q->ops->buf_queue);
++	BUG_ON(!q->ops->buf_release);
  
--static int fe_has_signal(struct tuner *t)
-+static int fe_has_signal(struct dvb_frontend *fe)
+ 	/* Having implementations for abstract methods are mandatory */
+-	BUG_ON (!q->int_ops);
++	BUG_ON(!q->int_ops);
+ 
+ 	mutex_init(&q->lock);
+ 	INIT_LIST_HEAD(&q->stream);
+@@ -146,33 +156,33 @@ int videobuf_queue_is_busy(struct videobuf_queue *q)
  {
--	struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
- 	u16 strength = 0;
+ 	int i;
  
--	if (fe_tuner_ops->get_rf_strength)
--		fe_tuner_ops->get_rf_strength(&t->fe, &strength);
-+	if (fe->ops.tuner_ops.get_rf_strength)
-+		fe->ops.tuner_ops.get_rf_strength(fe, &strength);
+-	MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);
++	MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
  
- 	return strength;
+ 	if (q->streaming) {
+-		dprintk(1,"busy: streaming active\n");
++		dprintk(1, "busy: streaming active\n");
+ 		return 1;
+ 	}
+ 	if (q->reading) {
+-		dprintk(1,"busy: pending read #1\n");
++		dprintk(1, "busy: pending read #1\n");
+ 		return 1;
+ 	}
+ 	if (q->read_buf) {
+-		dprintk(1,"busy: pending read #2\n");
++		dprintk(1, "busy: pending read #2\n");
+ 		return 1;
+ 	}
+ 	for (i = 0; i < VIDEO_MAX_FRAME; i++) {
+ 		if (NULL == q->bufs[i])
+ 			continue;
+ 		if (q->bufs[i]->map) {
+-			dprintk(1,"busy: buffer #%d mapped\n",i);
++			dprintk(1, "busy: buffer #%d mapped\n", i);
+ 			return 1;
+ 		}
+-		if (q->bufs[i]->state == STATE_QUEUED) {
+-			dprintk(1,"busy: buffer #%d queued\n",i);
++		if (q->bufs[i]->state == VIDEOBUF_QUEUED) {
++			dprintk(1, "busy: buffer #%d queued\n", i);
+ 			return 1;
+ 		}
+-		if (q->bufs[i]->state == STATE_ACTIVE) {
+-			dprintk(1,"busy: buffer #%d avtive\n",i);
++		if (q->bufs[i]->state == VIDEOBUF_ACTIVE) {
++			dprintk(1, "busy: buffer #%d avtive\n", i);
+ 			return 1;
+ 		}
+ 	}
+@@ -182,28 +192,28 @@ int videobuf_queue_is_busy(struct videobuf_queue *q)
+ /* Locking: Caller holds q->lock */
+ void videobuf_queue_cancel(struct videobuf_queue *q)
+ {
+-	unsigned long flags=0;
++	unsigned long flags = 0;
+ 	int i;
+ 
+ 	/* remove queued buffers from list */
+ 	if (q->irqlock)
+-		spin_lock_irqsave(q->irqlock,flags);
++		spin_lock_irqsave(q->irqlock, flags);
+ 	for (i = 0; i < VIDEO_MAX_FRAME; i++) {
+ 		if (NULL == q->bufs[i])
+ 			continue;
+-		if (q->bufs[i]->state == STATE_QUEUED) {
++		if (q->bufs[i]->state == VIDEOBUF_QUEUED) {
+ 			list_del(&q->bufs[i]->queue);
+-			q->bufs[i]->state = STATE_ERROR;
++			q->bufs[i]->state = VIDEOBUF_ERROR;
+ 		}
+ 	}
+ 	if (q->irqlock)
+-		spin_unlock_irqrestore(q->irqlock,flags);
++		spin_unlock_irqrestore(q->irqlock, flags);
+ 
+ 	/* free all buffers + clear queue */
+ 	for (i = 0; i < VIDEO_MAX_FRAME; i++) {
+ 		if (NULL == q->bufs[i])
+ 			continue;
+-		q->ops->buf_release(q,q->bufs[i]);
++		q->ops->buf_release(q, q->bufs[i]);
+ 	}
+ 	INIT_LIST_HEAD(&q->stream);
  }
+@@ -233,8 +243,8 @@ enum v4l2_field videobuf_next_field(struct videobuf_queue *q)
+ static void videobuf_status(struct videobuf_queue *q, struct v4l2_buffer *b,
+ 			    struct videobuf_buffer *vb, enum v4l2_buf_type type)
+ {
+-	MAGIC_CHECK(vb->magic,MAGIC_BUFFER);
+-	MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);
++	MAGIC_CHECK(vb->magic, MAGIC_BUFFER);
++	MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
  
-+static int fe_set_config(struct dvb_frontend *fe, void *priv_cfg)
-+{
-+	struct dvb_tuner_ops *fe_tuner_ops = &fe->ops.tuner_ops;
-+	struct tuner *t = fe->analog_demod_priv;
-+
-+	if (fe_tuner_ops->set_config)
-+		return fe_tuner_ops->set_config(fe, priv_cfg);
-+
-+	tuner_warn("Tuner frontend module has no way to set config\n");
-+
-+	return 0;
-+}
+ 	b->index    = vb->i;
+ 	b->type     = type;
+@@ -259,17 +269,17 @@ static void videobuf_status(struct videobuf_queue *q, struct v4l2_buffer *b,
+ 		b->flags |= V4L2_BUF_FLAG_MAPPED;
+ 
+ 	switch (vb->state) {
+-	case STATE_PREPARED:
+-	case STATE_QUEUED:
+-	case STATE_ACTIVE:
++	case VIDEOBUF_PREPARED:
++	case VIDEOBUF_QUEUED:
++	case VIDEOBUF_ACTIVE:
+ 		b->flags |= V4L2_BUF_FLAG_QUEUED;
+ 		break;
+-	case STATE_DONE:
+-	case STATE_ERROR:
++	case VIDEOBUF_DONE:
++	case VIDEOBUF_ERROR:
+ 		b->flags |= V4L2_BUF_FLAG_DONE;
+ 		break;
+-	case STATE_NEEDS_INIT:
+-	case STATE_IDLE:
++	case VIDEOBUF_NEEDS_INIT:
++	case VIDEOBUF_IDLE:
+ 		/* nothing */
+ 		break;
+ 	}
+@@ -294,16 +304,20 @@ static int __videobuf_mmap_free(struct videobuf_queue *q)
+ 	if (!q)
+ 		return 0;
+ 
+-	MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);
++	MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
 +
-+static void tuner_status(struct dvb_frontend *fe);
 +
-+static struct analog_demod_ops tuner_core_ops = {
-+	.set_params     = fe_set_params,
-+	.standby        = fe_standby,
-+	.release        = fe_release,
-+	.has_signal     = fe_has_signal,
-+	.set_config     = fe_set_config,
-+	.tuner_status   = tuner_status
-+};
++	rc  = CALL(q, mmap_free, q);
 +
- /* Set tuner frequency,  freq in Units of 62.5kHz = 1/16MHz */
- static void set_tv_freq(struct i2c_client *c, unsigned int freq)
++	q->is_mmapped = 0;
+ 
+-	rc  = CALL(q,mmap_free,q);
+-	if (rc<0)
++	if (rc < 0)
+ 		return rc;
+ 
+ 	for (i = 0; i < VIDEO_MAX_FRAME; i++) {
+ 		if (NULL == q->bufs[i])
+ 			continue;
+-		q->ops->buf_release(q,q->bufs[i]);
++		q->ops->buf_release(q, q->bufs[i]);
+ 		kfree(q->bufs[i]);
+ 		q->bufs[i] = NULL;
+ 	}
+@@ -328,7 +342,7 @@ static int __videobuf_mmap_setup(struct videobuf_queue *q,
+ 	unsigned int i;
+ 	int err;
+ 
+-	MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);
++	MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
+ 
+ 	err = __videobuf_mmap_free(q);
+ 	if (0 != err)
+@@ -359,7 +373,7 @@ static int __videobuf_mmap_setup(struct videobuf_queue *q,
+ 	if (!i)
+ 		return -ENOMEM;
+ 
+-	dprintk(1,"mmap setup: %d buffers, %d bytes each\n",
++	dprintk(1, "mmap setup: %d buffers, %d bytes each\n",
+ 		i, bsize);
+ 
+ 	return i;
+@@ -379,35 +393,35 @@ int videobuf_mmap_setup(struct videobuf_queue *q,
+ int videobuf_reqbufs(struct videobuf_queue *q,
+ 		 struct v4l2_requestbuffers *req)
  {
- 	struct tuner *t = i2c_get_clientdata(c);
-+	struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
-+
-+	struct analog_parameters params = {
-+		.mode      = t->mode,
-+		.audmode   = t->audmode,
-+		.std       = t->std
-+	};
+-	unsigned int size,count;
++	unsigned int size, count;
+ 	int retval;
  
- 	if (t->type == UNSET) {
- 		tuner_warn ("tuner type not set\n");
- 		return;
+ 	if (req->count < 1) {
+-		dprintk(1,"reqbufs: count invalid (%d)\n",req->count);
++		dprintk(1, "reqbufs: count invalid (%d)\n", req->count);
+ 		return -EINVAL;
  	}
--	if (NULL == t->ops.set_tv_freq) {
-+	if (NULL == analog_ops->set_params) {
- 		tuner_warn ("Tuner has no way to set tv freq\n");
- 		return;
+ 
+ 	if (req->memory != V4L2_MEMORY_MMAP     &&
+ 	    req->memory != V4L2_MEMORY_USERPTR  &&
+ 	    req->memory != V4L2_MEMORY_OVERLAY) {
+-		dprintk(1,"reqbufs: memory type invalid\n");
++		dprintk(1, "reqbufs: memory type invalid\n");
+ 		return -EINVAL;
  	}
-@@ -145,18 +228,27 @@ static void set_tv_freq(struct i2c_client *c, unsigned int freq)
- 		else
- 			freq = tv_range[1] * 16;
+ 
+ 	mutex_lock(&q->lock);
+ 	if (req->type != q->type) {
+-		dprintk(1,"reqbufs: queue type invalid\n");
++		dprintk(1, "reqbufs: queue type invalid\n");
+ 		retval = -EINVAL;
+ 		goto done;
  	}
--	t->ops.set_tv_freq(t, freq);
-+	params.frequency = freq;
-+
-+	analog_ops->set_params(&t->fe, &params);
- }
  
- static void set_radio_freq(struct i2c_client *c, unsigned int freq)
+ 	if (q->streaming) {
+-		dprintk(1,"reqbufs: streaming already exists\n");
++		dprintk(1, "reqbufs: streaming already exists\n");
+ 		retval = -EBUSY;
+ 		goto done;
+ 	}
+ 	if (!list_empty(&q->stream)) {
+-		dprintk(1,"reqbufs: stream running\n");
++		dprintk(1, "reqbufs: stream running\n");
+ 		retval = -EBUSY;
+ 		goto done;
+ 	}
+@@ -416,14 +430,14 @@ int videobuf_reqbufs(struct videobuf_queue *q,
+ 	if (count > VIDEO_MAX_FRAME)
+ 		count = VIDEO_MAX_FRAME;
+ 	size = 0;
+-	q->ops->buf_setup(q,&count,&size);
++	q->ops->buf_setup(q, &count, &size);
+ 	size = PAGE_ALIGN(size);
+-	dprintk(1,"reqbufs: bufs=%d, size=0x%x [%d pages total]\n",
++	dprintk(1, "reqbufs: bufs=%d, size=0x%x [%d pages total]\n",
+ 		count, size, (count*size)>>PAGE_SHIFT);
+ 
+-	retval = __videobuf_mmap_setup(q,count,size,req->memory);
++	retval = __videobuf_mmap_setup(q, count, size, req->memory);
+ 	if (retval < 0) {
+-		dprintk(1,"reqbufs: mmap setup returned %d\n",retval);
++		dprintk(1, "reqbufs: mmap setup returned %d\n", retval);
+ 		goto done;
+ 	}
+ 
+@@ -440,19 +454,19 @@ int videobuf_querybuf(struct videobuf_queue *q, struct v4l2_buffer *b)
+ 
+ 	mutex_lock(&q->lock);
+ 	if (unlikely(b->type != q->type)) {
+-		dprintk(1,"querybuf: Wrong type.\n");
++		dprintk(1, "querybuf: Wrong type.\n");
+ 		goto done;
+ 	}
+ 	if (unlikely(b->index < 0 || b->index >= VIDEO_MAX_FRAME)) {
+-		dprintk(1,"querybuf: index out of range.\n");
++		dprintk(1, "querybuf: index out of range.\n");
+ 		goto done;
+ 	}
+ 	if (unlikely(NULL == q->bufs[b->index])) {
+-		dprintk(1,"querybuf: buffer is null.\n");
++		dprintk(1, "querybuf: buffer is null.\n");
+ 		goto done;
+ 	}
+ 
+-	videobuf_status(q,b,q->bufs[b->index],q->type);
++	videobuf_status(q, b, q->bufs[b->index], q->type);
+ 
+ 	ret = 0;
+ done:
+@@ -465,10 +479,10 @@ int videobuf_qbuf(struct videobuf_queue *q,
  {
- 	struct tuner *t = i2c_get_clientdata(c);
-+	struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
-+
-+	struct analog_parameters params = {
-+		.mode      = t->mode,
-+		.audmode   = t->audmode,
-+		.std       = t->std
-+	};
+ 	struct videobuf_buffer *buf;
+ 	enum v4l2_field field;
+-	unsigned long flags=0;
++	unsigned long flags = 0;
+ 	int retval;
  
- 	if (t->type == UNSET) {
- 		tuner_warn ("tuner type not set\n");
- 		return;
+-	MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);
++	MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
+ 
+ 	if (b->memory == V4L2_MEMORY_MMAP)
+ 		down_read(&current->mm->mmap_sem);
+@@ -476,36 +490,36 @@ int videobuf_qbuf(struct videobuf_queue *q,
+ 	mutex_lock(&q->lock);
+ 	retval = -EBUSY;
+ 	if (q->reading) {
+-		dprintk(1,"qbuf: Reading running...\n");
++		dprintk(1, "qbuf: Reading running...\n");
+ 		goto done;
  	}
--	if (NULL == t->ops.set_radio_freq) {
-+	if (NULL == analog_ops->set_params) {
- 		tuner_warn ("tuner has no way to set radio frequency\n");
- 		return;
+ 	retval = -EINVAL;
+ 	if (b->type != q->type) {
+-		dprintk(1,"qbuf: Wrong type.\n");
++		dprintk(1, "qbuf: Wrong type.\n");
+ 		goto done;
  	}
-@@ -171,8 +263,9 @@ static void set_radio_freq(struct i2c_client *c, unsigned int freq)
- 		else
- 			freq = radio_range[1] * 16000;
+ 	if (b->index < 0 || b->index >= VIDEO_MAX_FRAME) {
+-		dprintk(1,"qbuf: index out of range.\n");
++		dprintk(1, "qbuf: index out of range.\n");
+ 		goto done;
+ 	}
+ 	buf = q->bufs[b->index];
+ 	if (NULL == buf) {
+-		dprintk(1,"qbuf: buffer is null.\n");
++		dprintk(1, "qbuf: buffer is null.\n");
+ 		goto done;
+ 	}
+-	MAGIC_CHECK(buf->magic,MAGIC_BUFFER);
++	MAGIC_CHECK(buf->magic, MAGIC_BUFFER);
+ 	if (buf->memory != b->memory) {
+-		dprintk(1,"qbuf: memory type is wrong.\n");
++		dprintk(1, "qbuf: memory type is wrong.\n");
+ 		goto done;
+ 	}
+-	if (buf->state != STATE_NEEDS_INIT && buf->state != STATE_IDLE) {
+-		dprintk(1,"qbuf: buffer is already queued or active.\n");
++	if (buf->state != VIDEOBUF_NEEDS_INIT && buf->state != VIDEOBUF_IDLE) {
++		dprintk(1, "qbuf: buffer is already queued or active.\n");
+ 		goto done;
  	}
-+	params.frequency = freq;
  
--	t->ops.set_radio_freq(t, freq);
-+	analog_ops->set_params(&t->fe, &params);
- }
+ 	if (b->flags & V4L2_BUF_FLAG_INPUT) {
+ 		if (b->input >= q->inputs) {
+-			dprintk(1,"qbuf: wrong input.\n");
++			dprintk(1, "qbuf: wrong input.\n");
+ 			goto done;
+ 		}
+ 		buf->input = b->input;
+@@ -516,44 +530,46 @@ int videobuf_qbuf(struct videobuf_queue *q,
+ 	switch (b->memory) {
+ 	case V4L2_MEMORY_MMAP:
+ 		if (0 == buf->baddr) {
+-			dprintk(1,"qbuf: mmap requested but buffer addr is zero!\n");
++			dprintk(1, "qbuf: mmap requested "
++				   "but buffer addr is zero!\n");
+ 			goto done;
+ 		}
+ 		break;
+ 	case V4L2_MEMORY_USERPTR:
+ 		if (b->length < buf->bsize) {
+-			dprintk(1,"qbuf: buffer length is not enough\n");
++			dprintk(1, "qbuf: buffer length is not enough\n");
+ 			goto done;
+ 		}
+-		if (STATE_NEEDS_INIT != buf->state && buf->baddr != b->m.userptr)
+-			q->ops->buf_release(q,buf);
++		if (VIDEOBUF_NEEDS_INIT != buf->state &&
++		    buf->baddr != b->m.userptr)
++			q->ops->buf_release(q, buf);
+ 		buf->baddr = b->m.userptr;
+ 		break;
+ 	case V4L2_MEMORY_OVERLAY:
+ 		buf->boff = b->m.offset;
+ 		break;
+ 	default:
+-		dprintk(1,"qbuf: wrong memory type\n");
++		dprintk(1, "qbuf: wrong memory type\n");
+ 		goto done;
+ 	}
  
- static void set_freq(struct i2c_client *c, unsigned long freq)
-@@ -193,54 +286,65 @@ static void set_freq(struct i2c_client *c, unsigned long freq)
- 		set_tv_freq(c, freq);
- 		t->tv_freq = freq;
+-	dprintk(1,"qbuf: requesting next field\n");
++	dprintk(1, "qbuf: requesting next field\n");
+ 	field = videobuf_next_field(q);
+-	retval = q->ops->buf_prepare(q,buf,field);
++	retval = q->ops->buf_prepare(q, buf, field);
+ 	if (0 != retval) {
+-		dprintk(1,"qbuf: buffer_prepare returned %d\n",retval);
++		dprintk(1, "qbuf: buffer_prepare returned %d\n", retval);
+ 		goto done;
+ 	}
+ 
+-	list_add_tail(&buf->stream,&q->stream);
++	list_add_tail(&buf->stream, &q->stream);
+ 	if (q->streaming) {
+ 		if (q->irqlock)
+-			spin_lock_irqsave(q->irqlock,flags);
+-		q->ops->buf_queue(q,buf);
++			spin_lock_irqsave(q->irqlock, flags);
++		q->ops->buf_queue(q, buf);
+ 		if (q->irqlock)
+-			spin_unlock_irqrestore(q->irqlock,flags);
++			spin_unlock_irqrestore(q->irqlock, flags);
+ 	}
+-	dprintk(1,"qbuf: succeded\n");
++	dprintk(1, "qbuf: succeded\n");
+ 	retval = 0;
+ 
+  done:
+@@ -571,49 +587,49 @@ int videobuf_dqbuf(struct videobuf_queue *q,
+ 	struct videobuf_buffer *buf;
+ 	int retval;
+ 
+-	MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);
++	MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
+ 
+ 	mutex_lock(&q->lock);
+ 	retval = -EBUSY;
+ 	if (q->reading) {
+-		dprintk(1,"dqbuf: Reading running...\n");
++		dprintk(1, "dqbuf: Reading running...\n");
+ 		goto done;
+ 	}
+ 	retval = -EINVAL;
+ 	if (b->type != q->type) {
+-		dprintk(1,"dqbuf: Wrong type.\n");
++		dprintk(1, "dqbuf: Wrong type.\n");
+ 		goto done;
+ 	}
+ 	if (list_empty(&q->stream)) {
+-		dprintk(1,"dqbuf: stream running\n");
++		dprintk(1, "dqbuf: stream running\n");
+ 		goto done;
+ 	}
+ 	buf = list_entry(q->stream.next, struct videobuf_buffer, stream);
+ 	retval = videobuf_waiton(buf, nonblocking, 1);
+ 	if (retval < 0) {
+-		dprintk(1,"dqbuf: waiton returned %d\n",retval);
++		dprintk(1, "dqbuf: waiton returned %d\n", retval);
+ 		goto done;
+ 	}
+ 	switch (buf->state) {
+-	case STATE_ERROR:
+-		dprintk(1,"dqbuf: state is error\n");
++	case VIDEOBUF_ERROR:
++		dprintk(1, "dqbuf: state is error\n");
+ 		retval = -EIO;
+-		CALL(q,sync,q, buf);
+-		buf->state = STATE_IDLE;
++		CALL(q, sync, q, buf);
++		buf->state = VIDEOBUF_IDLE;
  		break;
-+	default:
-+		tuner_dbg("freq set: unknown mode: 0x%04x!\n",t->mode);
+-	case STATE_DONE:
+-		dprintk(1,"dqbuf: state is done\n");
+-		CALL(q,sync,q, buf);
+-		buf->state = STATE_IDLE;
++	case VIDEOBUF_DONE:
++		dprintk(1, "dqbuf: state is done\n");
++		CALL(q, sync, q, buf);
++		buf->state = VIDEOBUF_IDLE;
+ 		break;
+ 	default:
+-		dprintk(1,"dqbuf: state invalid\n");
++		dprintk(1, "dqbuf: state invalid\n");
+ 		retval = -EINVAL;
+ 		goto done;
  	}
- }
+ 	list_del(&buf->stream);
+-	memset(b,0,sizeof(*b));
+-	videobuf_status(q,b,buf,q->type);
++	memset(b, 0, sizeof(*b));
++	videobuf_status(q, b, buf, q->type);
  
- static void tuner_i2c_address_check(struct tuner *t)
+  done:
+ 	mutex_unlock(&q->lock);
+@@ -623,7 +639,7 @@ int videobuf_dqbuf(struct videobuf_queue *q,
+ int videobuf_streamon(struct videobuf_queue *q)
  {
- 	if ((t->type == UNSET || t->type == TUNER_ABSENT) ||
--	    ((t->i2c.addr < 0x64) || (t->i2c.addr > 0x6f)))
-+	    ((t->i2c->addr < 0x64) || (t->i2c->addr > 0x6f)))
-+		return;
-+
-+	/* We already know that the XC5000 can only be located at
-+	 * i2c address 0x61, 0x62, 0x63 or 0x64 */
-+	if ((t->type == TUNER_XC5000) &&
-+	    ((t->i2c->addr <= 0x64)) && (t->i2c->addr >= 0x61))
- 		return;
+ 	struct videobuf_buffer *buf;
+-	unsigned long flags=0;
++	unsigned long flags = 0;
+ 	int retval;
  
- 	tuner_warn("====================== WARNING! ======================\n");
- 	tuner_warn("Support for tuners in i2c address range 0x64 thru 0x6f\n");
- 	tuner_warn("will soon be dropped. This message indicates that your\n");
- 	tuner_warn("hardware has a %s tuner at i2c address 0x%02x.\n",
--		   t->i2c.name, t->i2c.addr);
-+		   t->i2c->name, t->i2c->addr);
- 	tuner_warn("To ensure continued support for your device, please\n");
- 	tuner_warn("send a copy of this message, along with full dmesg\n");
- 	tuner_warn("output to v4l-dvb-maintainer at linuxtv.org\n");
- 	tuner_warn("Please use subject line: \"obsolete tuner i2c address.\"\n");
- 	tuner_warn("driver: %s, addr: 0x%02x, type: %d (%s)\n",
--		   t->i2c.adapter->name, t->i2c.addr, t->type,
-+		   t->i2c->adapter->name, t->i2c->addr, t->type,
- 		   tuners[t->type].name);
- 	tuner_warn("====================== WARNING! ======================\n");
- }
+ 	mutex_lock(&q->lock);
+@@ -635,12 +651,12 @@ int videobuf_streamon(struct videobuf_queue *q)
+ 		goto done;
+ 	q->streaming = 1;
+ 	if (q->irqlock)
+-		spin_lock_irqsave(q->irqlock,flags);
++		spin_lock_irqsave(q->irqlock, flags);
+ 	list_for_each_entry(buf, &q->stream, stream)
+-		if (buf->state == STATE_PREPARED)
+-			q->ops->buf_queue(q,buf);
++		if (buf->state == VIDEOBUF_PREPARED)
++			q->ops->buf_queue(q, buf);
+ 	if (q->irqlock)
+-		spin_unlock_irqrestore(q->irqlock,flags);
++		spin_unlock_irqrestore(q->irqlock, flags);
  
--static void attach_tda8290(struct tuner *t)
--{
--	struct tda8290_config cfg = {
--		.lna_cfg        = &t->config,
--		.tuner_callback = t->tuner_callback
--	};
--	tda8290_attach(&t->fe, t->i2c.adapter, t->i2c.addr, &cfg);
--}
--
- static void attach_simple_tuner(struct tuner *t)
+  done:
+ 	mutex_unlock(&q->lock);
+@@ -676,10 +692,10 @@ static ssize_t videobuf_read_zerocopy(struct videobuf_queue *q,
+ 				      size_t count, loff_t *ppos)
  {
- 	struct simple_tuner_config cfg = {
- 		.type = t->type,
- 		.tun  = &tuners[t->type]
- 	};
--	simple_tuner_attach(&t->fe, t->i2c.adapter, t->i2c.addr, &cfg);
-+	simple_tuner_attach(&t->fe, t->i2c->adapter, t->i2c->addr, &cfg);
- }
+ 	enum v4l2_field field;
+-	unsigned long flags=0;
++	unsigned long flags = 0;
+ 	int retval;
  
-+static void attach_tda829x(struct tuner *t)
-+{
-+	struct tda829x_config cfg = {
-+		.lna_cfg        = &t->config,
-+		.tuner_callback = t->tuner_callback,
-+	};
-+	tda829x_attach(&t->fe, t->i2c->adapter, t->i2c->addr, &cfg);
-+}
-+
-+static struct xc5000_config xc5000_cfg;
-+
- 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))
+-	MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);
++	MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
+ 
+ 	/* setup stuff */
+ 	q->read_buf = videobuf_alloc(q);
+@@ -691,20 +707,20 @@ static ssize_t videobuf_read_zerocopy(struct videobuf_queue *q,
+ 	q->read_buf->bsize  = count;
+ 
+ 	field = videobuf_next_field(q);
+-	retval = q->ops->buf_prepare(q,q->read_buf,field);
++	retval = q->ops->buf_prepare(q, q->read_buf, field);
+ 	if (0 != retval)
+ 		goto done;
+ 
+ 	/* start capture & wait */
+ 	if (q->irqlock)
+-		spin_lock_irqsave(q->irqlock,flags);
+-	q->ops->buf_queue(q,q->read_buf);
++		spin_lock_irqsave(q->irqlock, flags);
++	q->ops->buf_queue(q, q->read_buf);
+ 	if (q->irqlock)
+-		spin_unlock_irqrestore(q->irqlock,flags);
+-	retval = videobuf_waiton(q->read_buf,0,0);
++		spin_unlock_irqrestore(q->irqlock, flags);
++	retval = videobuf_waiton(q->read_buf, 0, 0);
+ 	if (0 == retval) {
+-		CALL(q,sync,q,q->read_buf);
+-		if (STATE_ERROR == q->read_buf->state)
++		CALL(q, sync, q, q->read_buf);
++		if (VIDEOBUF_ERROR == q->read_buf->state)
+ 			retval = -EIO;
+ 		else
+ 			retval = q->read_buf->size;
+@@ -712,7 +728,7 @@ static ssize_t videobuf_read_zerocopy(struct videobuf_queue *q,
+ 
+  done:
+ 	/* cleanup */
+-	q->ops->buf_release(q,q->read_buf);
++	q->ops->buf_release(q, q->read_buf);
+ 	kfree(q->read_buf);
+ 	q->read_buf = NULL;
+ 	return retval;
+@@ -723,21 +739,21 @@ ssize_t videobuf_read_one(struct videobuf_queue *q,
+ 			  int nonblocking)
  {
- 	struct tuner *t = i2c_get_clientdata(c);
- 	struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
-+	struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
- 	unsigned char buffer[4];
+ 	enum v4l2_field field;
+-	unsigned long flags=0;
++	unsigned long flags = 0;
+ 	unsigned size, nbufs;
+ 	int retval;
+ 
+-	MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);
++	MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
+ 
+ 	mutex_lock(&q->lock);
+ 
+ 	nbufs = 1; size = 0;
+-	q->ops->buf_setup(q,&nbufs,&size);
++	q->ops->buf_setup(q, &nbufs, &size);
+ 
+ 	if (NULL == q->read_buf  &&
+ 	    count >= size        &&
+ 	    !nonblocking) {
+-		retval = videobuf_read_zerocopy(q,data,count,ppos);
++		retval = videobuf_read_zerocopy(q, data, count, ppos);
+ 		if (retval >= 0  ||  retval == -EIO)
+ 			/* ok, all done */
+ 			goto done;
+@@ -749,25 +765,25 @@ ssize_t videobuf_read_one(struct videobuf_queue *q,
+ 		retval = -ENOMEM;
+ 		q->read_buf = videobuf_alloc(q);
+ 
+-		dprintk(1,"video alloc=0x%p\n", q->read_buf);
++		dprintk(1, "video alloc=0x%p\n", q->read_buf);
+ 		if (NULL == q->read_buf)
+ 			goto done;
+ 		q->read_buf->memory = V4L2_MEMORY_USERPTR;
+ 		q->read_buf->bsize = count; /* preferred size */
+ 		field = videobuf_next_field(q);
+-		retval = q->ops->buf_prepare(q,q->read_buf,field);
++		retval = q->ops->buf_prepare(q, q->read_buf, field);
+ 
+ 		if (0 != retval) {
+-			kfree (q->read_buf);
++			kfree(q->read_buf);
+ 			q->read_buf = NULL;
+ 			goto done;
+ 		}
+ 		if (q->irqlock)
+-			spin_lock_irqsave(q->irqlock,flags);
++			spin_lock_irqsave(q->irqlock, flags);
  
- 	if (type == UNSET || type == TUNER_ABSENT) {
-@@ -260,32 +364,27 @@ static void set_type(struct i2c_client *c, unsigned int type,
- 		t->tuner_callback = tuner_callback;
+-		q->ops->buf_queue(q,q->read_buf);
++		q->ops->buf_queue(q, q->read_buf);
+ 		if (q->irqlock)
+-			spin_unlock_irqrestore(q->irqlock,flags);
++			spin_unlock_irqrestore(q->irqlock, flags);
+ 		q->read_off = 0;
  	}
  
--	/* This code detects calls by card attach_inform */
--	if (NULL == t->i2c.dev.driver) {
-+	if (t->mode == T_UNINITIALIZED) {
- 		tuner_dbg ("tuner 0x%02x: called during i2c_client register by adapter's attach_inform\n", c->addr);
- 
- 		return;
- 	}
+@@ -776,11 +792,11 @@ ssize_t videobuf_read_one(struct videobuf_queue *q,
+ 	if (0 != retval)
+ 		goto done;
  
- 	/* discard private data, in case set_type() was previously called */
--	if (t->ops.release)
--		t->ops.release(t);
--	else {
--		kfree(t->priv);
--		t->priv = NULL;
--	}
-+	if (analog_ops->release)
-+		analog_ops->release(&t->fe);
+-	CALL(q,sync,q,q->read_buf);
++	CALL(q, sync, q, q->read_buf);
  
- 	switch (t->type) {
- 	case TUNER_MT2032:
--		microtune_attach(&t->fe, t->i2c.adapter, t->i2c.addr);
-+		microtune_attach(&t->fe, t->i2c->adapter, t->i2c->addr);
- 		break;
- 	case TUNER_PHILIPS_TDA8290:
- 	{
--		attach_tda8290(t);
-+		attach_tda829x(t);
- 		break;
- 	}
- 	case TUNER_TEA5767:
--		if (tea5767_attach(&t->fe, t->i2c.adapter, t->i2c.addr) == NULL) {
-+		if (tea5767_attach(&t->fe, t->i2c->adapter, t->i2c->addr) == NULL) {
- 			t->type = TUNER_ABSENT;
- 			t->mode_mask = T_UNINITIALIZED;
- 			return;
-@@ -293,7 +392,7 @@ static void set_type(struct i2c_client *c, unsigned int type,
- 		t->mode_mask = T_RADIO;
- 		break;
- 	case TUNER_TEA5761:
--		if (tea5761_attach(&t->fe, t->i2c.adapter, t->i2c.addr) == NULL) {
-+		if (tea5761_attach(&t->fe, t->i2c->adapter, t->i2c->addr) == NULL) {
- 			t->type = TUNER_ABSENT;
- 			t->mode_mask = T_UNINITIALIZED;
- 			return;
-@@ -320,25 +419,60 @@ static void set_type(struct i2c_client *c, unsigned int type,
- 		i2c_master_send(c,buffer,4);
- 		attach_simple_tuner(t);
- 		break;
-+	case TUNER_XC2028:
-+	{
-+		struct xc2028_config cfg = {
-+			.i2c_adap  = t->i2c->adapter,
-+			.i2c_addr  = t->i2c->addr,
-+			.video_dev = c->adapter->algo_data,
-+			.callback  = t->tuner_callback,
-+		};
-+		if (!xc2028_attach(&t->fe, &cfg)) {
-+			t->type = TUNER_ABSENT;
-+			t->mode_mask = T_UNINITIALIZED;
-+			return;
-+		}
-+		break;
-+	}
- 	case TUNER_TDA9887:
--		tda9887_tuner_init(t);
-+		tda9887_attach(&t->fe, t->i2c->adapter, t->i2c->addr);
-+		break;
-+	case TUNER_XC5000:
-+		xc5000_cfg.i2c_address	  = t->i2c->addr;
-+		xc5000_cfg.if_khz	  = 5380;
-+		xc5000_cfg.priv           = c->adapter->algo_data;
-+		xc5000_cfg.tuner_callback = t->tuner_callback;
-+		if (!xc5000_attach(&t->fe, t->i2c->adapter, &xc5000_cfg)) {
-+			t->type = TUNER_ABSENT;
-+			t->mode_mask = T_UNINITIALIZED;
-+			return;
-+		}
-+		{
-+		struct dvb_tuner_ops *xc_tuner_ops;
-+		xc_tuner_ops = &t->fe.ops.tuner_ops;
-+		if(xc_tuner_ops->init != NULL)
-+			xc_tuner_ops->init(&t->fe);
-+		}
- 		break;
- 	default:
- 		attach_simple_tuner(t);
- 		break;
+-	if (STATE_ERROR == q->read_buf->state) {
++	if (VIDEOBUF_ERROR == q->read_buf->state) {
+ 		/* catch I/O errors */
+-		q->ops->buf_release(q,q->read_buf);
++		q->ops->buf_release(q, q->read_buf);
+ 		kfree(q->read_buf);
+ 		q->read_buf = NULL;
+ 		retval = -EIO;
+@@ -788,14 +804,14 @@ ssize_t videobuf_read_one(struct videobuf_queue *q,
  	}
  
--	if (fe_tuner_ops->set_analog_params) {
--		strlcpy(t->i2c.name, fe_tuner_ops->info.name, sizeof(t->i2c.name));
-+	if ((NULL == analog_ops->set_params) &&
-+	    (fe_tuner_ops->set_analog_params)) {
-+		strlcpy(t->i2c->name, fe_tuner_ops->info.name,
-+			sizeof(t->i2c->name));
+ 	/* Copy to userspace */
+-	retval=CALL(q,video_copy_to_user,q,data,count,nonblocking);
+-	if (retval<0)
++	retval = CALL(q, video_copy_to_user, q, data, count, nonblocking);
++	if (retval < 0)
+ 		goto done;
  
--		t->ops.set_tv_freq    = fe_set_freq;
--		t->ops.set_radio_freq = fe_set_freq;
--		t->ops.standby        = fe_standby;
--		t->ops.release        = fe_release;
--		t->ops.has_signal     = fe_has_signal;
-+		t->fe.analog_demod_priv = t;
-+		memcpy(analog_ops, &tuner_core_ops,
-+		       sizeof(struct analog_demod_ops));
-+	} else {
-+		strlcpy(t->i2c->name, analog_ops->info.name,
-+			sizeof(t->i2c->name));
+ 	q->read_off += retval;
+ 	if (q->read_off == q->read_buf->size) {
+ 		/* all data copied, cleanup */
+-		q->ops->buf_release(q,q->read_buf);
++		q->ops->buf_release(q, q->read_buf);
+ 		kfree(q->read_buf);
+ 		q->read_buf = NULL;
  	}
- 
--	tuner_info("type set to %s\n", t->i2c.name);
-+	tuner_dbg("type set to %s\n", t->i2c->name);
- 
- 	if (t->mode_mask == T_UNINITIALIZED)
- 		t->mode_mask = new_mode_mask;
-@@ -508,10 +642,12 @@ static int tuner_fixup_std(struct tuner *t)
- 	return 0;
+@@ -806,14 +822,14 @@ ssize_t videobuf_read_one(struct videobuf_queue *q,
  }
  
--static void tuner_status(struct tuner *t)
-+static void tuner_status(struct dvb_frontend *fe)
+ /* Locking: Caller holds q->lock */
+-int __videobuf_read_start(struct videobuf_queue *q)
++static int __videobuf_read_start(struct videobuf_queue *q)
  {
-+	struct tuner *t = fe->analog_demod_priv;
- 	unsigned long freq, freq_fraction;
- 	struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
-+	struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
- 	const char *p;
+ 	enum v4l2_field field;
+-	unsigned long flags=0;
++	unsigned long flags = 0;
+ 	unsigned int count = 0, size = 0;
+ 	int err, i;
  
- 	switch (t->mode) {
-@@ -541,172 +677,16 @@ static void tuner_status(struct tuner *t)
- 		if (tuner_status & TUNER_STATUS_STEREO)
- 			tuner_info("Stereo:          yes\n");
+-	q->ops->buf_setup(q,&count,&size);
++	q->ops->buf_setup(q, &count, &size);
+ 	if (count < 2)
+ 		count = 2;
+ 	if (count > VIDEO_MAX_FRAME)
+@@ -828,17 +844,17 @@ int __videobuf_read_start(struct videobuf_queue *q)
+ 
+ 	for (i = 0; i < count; i++) {
+ 		field = videobuf_next_field(q);
+-		err = q->ops->buf_prepare(q,q->bufs[i],field);
++		err = q->ops->buf_prepare(q, q->bufs[i], field);
+ 		if (err)
+ 			return err;
+ 		list_add_tail(&q->bufs[i]->stream, &q->stream);
  	}
--	if (t->ops.has_signal) {
--		tuner_info("Signal strength: %d\n", t->ops.has_signal(t));
--	}
--	if (t->ops.is_stereo) {
--		tuner_info("Stereo:          %s\n", t->ops.is_stereo(t) ? "yes" : "no");
--	}
-+	if (analog_ops->has_signal)
-+		tuner_info("Signal strength: %d\n",
-+			   analog_ops->has_signal(fe));
-+	if (analog_ops->is_stereo)
-+		tuner_info("Stereo:          %s\n",
-+			   analog_ops->is_stereo(fe) ? "yes" : "no");
+ 	if (q->irqlock)
+-		spin_lock_irqsave(q->irqlock,flags);
++		spin_lock_irqsave(q->irqlock, flags);
+ 	for (i = 0; i < count; i++)
+-		q->ops->buf_queue(q,q->bufs[i]);
++		q->ops->buf_queue(q, q->bufs[i]);
+ 	if (q->irqlock)
+-		spin_unlock_irqrestore(q->irqlock,flags);
++		spin_unlock_irqrestore(q->irqlock, flags);
+ 	q->reading = 1;
+ 	return 0;
+ }
+@@ -859,7 +875,7 @@ static void __videobuf_read_stop(struct videobuf_queue *q)
+ 	}
+ 	q->read_buf = NULL;
+ 	q->reading  = 0;
+-	
++
  }
  
- /* ---------------------------------------------------------------------- */
+ int videobuf_read_start(struct videobuf_queue *q)
+@@ -899,11 +915,11 @@ ssize_t videobuf_read_stream(struct videobuf_queue *q,
+ 			     int vbihack, int nonblocking)
+ {
+ 	int rc, retval;
+-	unsigned long flags=0;
++	unsigned long flags = 0;
  
--/* static vars: used only in tuner_attach and tuner_probe */
--static unsigned default_mode_mask;
--
--/* During client attach, set_type is called by adapter's attach_inform callback.
--   set_type must then be completed by tuner_attach.
-- */
--static int tuner_attach(struct i2c_adapter *adap, int addr, int kind)
--{
--	struct tuner *t;
--
--	client_template.adapter = adap;
--	client_template.addr = addr;
--
--	t = kzalloc(sizeof(struct tuner), GFP_KERNEL);
--	if (NULL == t)
--		return -ENOMEM;
--	memcpy(&t->i2c, &client_template, sizeof(struct i2c_client));
--	i2c_set_clientdata(&t->i2c, t);
--	t->type = UNSET;
--	t->audmode = V4L2_TUNER_MODE_STEREO;
--	t->mode_mask = T_UNINITIALIZED;
--	t->ops.tuner_status = tuner_status;
--
--	if (show_i2c) {
--		unsigned char buffer[16];
--		int i,rc;
--
--		memset(buffer, 0, sizeof(buffer));
--		rc = i2c_master_recv(&t->i2c, buffer, sizeof(buffer));
--		tuner_info("I2C RECV = ");
--		for (i=0;i<rc;i++)
--			printk("%02x ",buffer[i]);
--		printk("\n");
--	}
--	/* HACK: This test were added to avoid tuner to probe tda9840 and tea6415c on the MXB card */
--	if (adap->id == I2C_HW_SAA7146 && addr < 0x4a)
--		return -ENODEV;
--
--	/* autodetection code based on the i2c addr */
--	if (!no_autodetect) {
--		switch (addr) {
--		case 0x10:
--			if (tea5761_autodetection(t->i2c.adapter, t->i2c.addr) != EINVAL) {
--				t->type = TUNER_TEA5761;
--				t->mode_mask = T_RADIO;
--				t->mode = T_STANDBY;
--				t->radio_freq = 87.5 * 16000; /* Sets freq to FM range */
--				default_mode_mask &= ~T_RADIO;
--
--				goto register_client;
--			}
--			break;
--		case 0x42:
--		case 0x43:
--		case 0x4a:
--		case 0x4b:
--			/* If chip is not tda8290, don't register.
--			   since it can be tda9887*/
--			if (tda8290_probe(t->i2c.adapter, t->i2c.addr) == 0) {
--				tuner_dbg("chip at addr %x is a tda8290\n", addr);
--			} else {
--				/* Default is being tda9887 */
--				t->type = TUNER_TDA9887;
--				t->mode_mask = T_RADIO | T_ANALOG_TV | T_DIGITAL_TV;
--				t->mode = T_STANDBY;
--				goto register_client;
--			}
--			break;
--		case 0x60:
--			if (tea5767_autodetection(t->i2c.adapter, t->i2c.addr) != EINVAL) {
--				t->type = TUNER_TEA5767;
--				t->mode_mask = T_RADIO;
--				t->mode = T_STANDBY;
--				t->radio_freq = 87.5 * 16000; /* Sets freq to FM range */
--				default_mode_mask &= ~T_RADIO;
--
--				goto register_client;
--			}
--			break;
--		}
--	}
--
--	/* Initializes only the first adapter found */
--	if (default_mode_mask != T_UNINITIALIZED) {
--		tuner_dbg ("Setting mode_mask to 0x%02x\n", default_mode_mask);
--		t->mode_mask = default_mode_mask;
--		t->tv_freq = 400 * 16; /* Sets freq to VHF High */
--		t->radio_freq = 87.5 * 16000; /* Sets freq to FM range */
--		default_mode_mask = T_UNINITIALIZED;
--	}
--
--	/* Should be just before return */
--register_client:
--	tuner_info("chip found @ 0x%x (%s)\n", addr << 1, adap->name);
--	i2c_attach_client (&t->i2c);
--	set_type (&t->i2c,t->type, t->mode_mask, t->config, t->tuner_callback);
--	return 0;
--}
--
--static int tuner_probe(struct i2c_adapter *adap)
--{
--	if (0 != addr) {
--		normal_i2c[0] = addr;
--		normal_i2c[1] = I2C_CLIENT_END;
--	}
--
--	/* HACK: Ignore 0x6b and 0x6f on cx88 boards.
--	 * FusionHDTV5 RT Gold has an ir receiver at 0x6b
--	 * and an RTC at 0x6f which can get corrupted if probed.
--	 */
--	if ((adap->id == I2C_HW_B_CX2388x) ||
--	    (adap->id == I2C_HW_B_CX23885)) {
--		unsigned int i = 0;
--
--		while (i < I2C_CLIENT_MAX_OPTS && ignore[i] != I2C_CLIENT_END)
--			i += 2;
--		if (i + 4 < I2C_CLIENT_MAX_OPTS) {
--			ignore[i+0] = adap->nr;
--			ignore[i+1] = 0x6b;
--			ignore[i+2] = adap->nr;
--			ignore[i+3] = 0x6f;
--			ignore[i+4] = I2C_CLIENT_END;
--		} else
--			printk(KERN_WARNING "tuner: "
--			       "too many options specified "
--			       "in i2c probe ignore list!\n");
--	}
--
--	default_mode_mask = T_RADIO | T_ANALOG_TV | T_DIGITAL_TV;
--
--	if (adap->class & I2C_CLASS_TV_ANALOG)
--		return i2c_probe(adap, &addr_data, tuner_attach);
--	return 0;
--}
--
--static int tuner_detach(struct i2c_client *client)
--{
--	struct tuner *t = i2c_get_clientdata(client);
--	int err;
--
--	err = i2c_detach_client(&t->i2c);
--	if (err) {
--		tuner_warn
--		    ("Client deregistration failed, client not detached.\n");
--		return err;
--	}
--
--	if (t->ops.release)
--		t->ops.release(t);
--	else {
--		kfree(t->priv);
--	}
--	kfree(t);
--	return 0;
--}
--
- /*
-  * Switch tuner to other mode. If tuner support both tv and radio,
-  * set another frequency to some value (This is needed for some pal
-@@ -716,6 +696,8 @@ static int tuner_detach(struct i2c_client *client)
+-	MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);
++	MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
  
- static inline int set_mode(struct i2c_client *client, struct tuner *t, int mode, char *cmd)
- {
-+	struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
-+
- 	if (mode == t->mode)
- 		return 0;
+-	dprintk(2,"%s\n",__FUNCTION__);
++	dprintk(2, "%s\n", __FUNCTION__);
+ 	mutex_lock(&q->lock);
+ 	retval = -EBUSY;
+ 	if (q->streaming)
+@@ -931,8 +947,8 @@ ssize_t videobuf_read_stream(struct videobuf_queue *q,
+ 			break;
+ 		}
  
-@@ -723,8 +705,8 @@ static inline int set_mode(struct i2c_client *client, struct tuner *t, int mode,
+-		if (q->read_buf->state == STATE_DONE) {
+-			rc = CALL (q,copy_stream, q, data + retval, count,
++		if (q->read_buf->state == VIDEOBUF_DONE) {
++			rc = CALL(q, copy_stream, q, data + retval, count,
+ 					retval, vbihack, nonblocking);
+ 			if (rc < 0) {
+ 				retval = rc;
+@@ -953,10 +969,10 @@ ssize_t videobuf_read_stream(struct videobuf_queue *q,
+ 			list_add_tail(&q->read_buf->stream,
+ 				      &q->stream);
+ 			if (q->irqlock)
+-				spin_lock_irqsave(q->irqlock,flags);
+-			q->ops->buf_queue(q,q->read_buf);
++				spin_lock_irqsave(q->irqlock, flags);
++			q->ops->buf_queue(q, q->read_buf);
+ 			if (q->irqlock)
+-				spin_unlock_irqrestore(q->irqlock,flags);
++				spin_unlock_irqrestore(q->irqlock, flags);
+ 			q->read_buf = NULL;
+ 		}
+ 		if (retval < 0)
+@@ -999,8 +1015,8 @@ unsigned int videobuf_poll_stream(struct file *file,
  
- 	if (check_mode(t, cmd) == EINVAL) {
- 		t->mode = T_STANDBY;
--		if (t->ops.standby)
--			t->ops.standby(t);
-+		if (analog_ops->standby)
-+			analog_ops->standby(&t->fe);
- 		return EINVAL;
+ 	if (0 == rc) {
+ 		poll_wait(file, &buf->done, wait);
+-		if (buf->state == STATE_DONE ||
+-		    buf->state == STATE_ERROR)
++		if (buf->state == VIDEOBUF_DONE ||
++		    buf->state == VIDEOBUF_ERROR)
+ 			rc = POLLIN|POLLRDNORM;
  	}
- 	return 0;
-@@ -747,9 +729,10 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
+ 	mutex_unlock(&q->lock);
+@@ -1012,10 +1028,11 @@ int videobuf_mmap_mapper(struct videobuf_queue *q,
  {
- 	struct tuner *t = i2c_get_clientdata(client);
- 	struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
-+	struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
- 
- 	if (tuner_debug>1)
--		v4l_i2c_print_ioctl(&(t->i2c),cmd);
-+		v4l_i2c_print_ioctl(client,cmd);
- 
- 	switch (cmd) {
- 	/* --- configuration --- */
-@@ -773,8 +756,8 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
- 		if (check_mode(t, "TUNER_SET_STANDBY") == EINVAL)
- 			return 0;
- 		t->mode = T_STANDBY;
--		if (t->ops.standby)
--			t->ops.standby(t);
-+		if (analog_ops->standby)
-+			analog_ops->standby(&t->fe);
- 		break;
- #ifdef CONFIG_VIDEO_V4L1
- 	case VIDIOCSAUDIO:
-@@ -842,8 +825,8 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
- 					else
- 						vt->flags &= ~VIDEO_TUNER_STEREO_ON;
- 				} else {
--					if (t->ops.is_stereo) {
--						if (t->ops.is_stereo(t))
-+					if (analog_ops->is_stereo) {
-+						if (analog_ops->is_stereo(&t->fe))
- 							vt->flags |=
- 								VIDEO_TUNER_STEREO_ON;
- 						else
-@@ -851,8 +834,9 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
- 								~VIDEO_TUNER_STEREO_ON;
- 					}
- 				}
--				if (t->ops.has_signal)
--					vt->signal = t->ops.has_signal(t);
-+				if (analog_ops->has_signal)
-+					vt->signal =
-+						analog_ops->has_signal(&t->fe);
- 
- 				vt->flags |= VIDEO_TUNER_LOW;	/* Allow freqs at 62.5 Hz */
+ 	int retval;
  
-@@ -882,21 +866,28 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
- 					fe_tuner_ops->get_status(&t->fe, &tuner_status);
- 					va->mode = (tuner_status & TUNER_STATUS_STEREO)
- 					    ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO;
--				} else if (t->ops.is_stereo)
--					va->mode = t->ops.is_stereo(t)
-+				} else if (analog_ops->is_stereo)
-+					va->mode = analog_ops->is_stereo(&t->fe)
- 					    ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO;
- 			}
- 			return 0;
- 		}
- #endif
--	case TDA9887_SET_CONFIG:
--		if (t->type == TUNER_TDA9887) {
--			int *i = arg;
-+	case TUNER_SET_CONFIG:
-+	{
-+		struct v4l2_priv_tun_config *cfg = arg;
+-	MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);
++	MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
  
--			t->tda9887_config = *i;
--			set_freq(client, t->tv_freq);
-+		if (t->type != cfg->tuner)
-+			break;
-+
-+		if (analog_ops->set_config) {
-+			analog_ops->set_config(&t->fe, cfg->priv);
-+			break;
- 		}
-+
-+		tuner_dbg("Tuner frontend module has no way to set config\n");
- 		break;
-+	}
- 	/* --- v4l ioctls --- */
- 	/* take care: bttv does userspace copying, we'll get a
- 	   kernel pointer here... */
-@@ -958,8 +949,8 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
- 			switch_v4l2();
+ 	mutex_lock(&q->lock);
+-	retval=CALL(q,mmap_mapper,q,vma);
++	retval = CALL(q, mmap_mapper, q, vma);
++	q->is_mmapped = 1;
+ 	mutex_unlock(&q->lock);
  
- 			tuner->type = t->mode;
--			if (t->ops.get_afc)
--				tuner->afc=t->ops.get_afc(t);
-+			if (analog_ops->get_afc)
-+				tuner->afc = analog_ops->get_afc(&t->fe);
- 			if (t->mode == V4L2_TUNER_ANALOG_TV)
- 				tuner->capability |= V4L2_TUNER_CAP_NORM;
- 			if (t->mode != V4L2_TUNER_RADIO) {
-@@ -975,16 +966,20 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
- 				u32 tuner_status;
+ 	return retval;
+@@ -1026,15 +1043,15 @@ int videobuf_cgmbuf(struct videobuf_queue *q,
+ 		    struct video_mbuf *mbuf, int count)
+ {
+ 	struct v4l2_requestbuffers req;
+-	int rc,i;
++	int rc, i;
  
- 				fe_tuner_ops->get_status(&t->fe, &tuner_status);
--				tuner->rxsubchans = (tuner_status & TUNER_STATUS_STEREO) ?
--					V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO;
-+				tuner->rxsubchans =
-+					(tuner_status & TUNER_STATUS_STEREO) ?
-+					V4L2_TUNER_SUB_STEREO :
-+					V4L2_TUNER_SUB_MONO;
- 			} else {
--				if (t->ops.is_stereo) {
--					tuner->rxsubchans = t->ops.is_stereo(t) ?
--						V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO;
-+				if (analog_ops->is_stereo) {
-+					tuner->rxsubchans =
-+						analog_ops->is_stereo(&t->fe) ?
-+						V4L2_TUNER_SUB_STEREO :
-+						V4L2_TUNER_SUB_MONO;
- 				}
- 			}
--			if (t->ops.has_signal)
--				tuner->signal = t->ops.has_signal(t);
-+			if (analog_ops->has_signal)
-+				tuner->signal = analog_ops->has_signal(&t->fe);
- 			tuner->capability |=
- 			    V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
- 			tuner->audmode = t->audmode;
-@@ -1009,8 +1004,8 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
- 			break;
- 		}
- 	case VIDIOC_LOG_STATUS:
--		if (t->ops.tuner_status)
--			t->ops.tuner_status(t);
-+		if (analog_ops->tuner_status)
-+			analog_ops->tuner_status(&t->fe);
- 		break;
- 	}
+-	MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);
++	MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
  
-@@ -1019,18 +1014,18 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
+-	memset(&req,0,sizeof(req));
++	memset(&req, 0, sizeof(req));
+ 	req.type   = q->type;
+ 	req.count  = count;
+ 	req.memory = V4L2_MEMORY_MMAP;
+-	rc = videobuf_reqbufs(q,&req);
++	rc = videobuf_reqbufs(q, &req);
+ 	if (rc < 0)
+ 		return rc;
  
- static int tuner_suspend(struct i2c_client *c, pm_message_t state)
+@@ -1079,9 +1096,3 @@ EXPORT_SYMBOL_GPL(videobuf_poll_stream);
+ EXPORT_SYMBOL_GPL(videobuf_mmap_setup);
+ EXPORT_SYMBOL_GPL(videobuf_mmap_free);
+ EXPORT_SYMBOL_GPL(videobuf_mmap_mapper);
+-
+-/*
+- * Local variables:
+- * c-basic-offset: 8
+- * End:
+- */
+diff --git a/drivers/media/video/videobuf-dma-sg.c b/drivers/media/video/videobuf-dma-sg.c
+index 44ee408..98efd7a 100644
+--- a/drivers/media/video/videobuf-dma-sg.c
++++ b/drivers/media/video/videobuf-dma-sg.c
+@@ -385,30 +385,27 @@ videobuf_vm_close(struct vm_area_struct *vma)
+  * now ...).  Bounce buffers don't work very well for the data rates
+  * video capture has.
+  */
+-static struct page*
+-videobuf_vm_nopage(struct vm_area_struct *vma, unsigned long vaddr,
+-		   int *type)
++static int
++videobuf_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
  {
--	struct tuner *t = i2c_get_clientdata (c);
-+	struct tuner *t = i2c_get_clientdata(c);
+ 	struct page *page;
  
--	tuner_dbg ("suspend\n");
-+	tuner_dbg("suspend\n");
- 	/* FIXME: power down ??? */
- 	return 0;
+-	dprintk(3,"nopage: fault @ %08lx [vma %08lx-%08lx]\n",
+-		vaddr,vma->vm_start,vma->vm_end);
+-	if (vaddr > vma->vm_end)
+-		return NOPAGE_SIGBUS;
++	dprintk(3,"fault: fault @ %08lx [vma %08lx-%08lx]\n",
++		(unsigned long)vmf->virtual_address,vma->vm_start,vma->vm_end);
+ 	page = alloc_page(GFP_USER | __GFP_DMA32);
+ 	if (!page)
+-		return NOPAGE_OOM;
+-	clear_user_page(page_address(page), vaddr, page);
+-	if (type)
+-		*type = VM_FAULT_MINOR;
+-	return page;
++		return VM_FAULT_OOM;
++	clear_user_page(page_address(page), (unsigned long)vmf->virtual_address,
++			page);
++	vmf->page = page;
++	return 0;
  }
  
- static int tuner_resume(struct i2c_client *c)
+ static struct vm_operations_struct videobuf_vm_ops =
  {
--	struct tuner *t = i2c_get_clientdata (c);
-+	struct tuner *t = i2c_get_clientdata(c);
+ 	.open     = videobuf_vm_open,
+ 	.close    = videobuf_vm_close,
+-	.nopage   = videobuf_vm_nopage,
++	.fault    = videobuf_vm_fault,
+ };
  
--	tuner_dbg ("resume\n");
-+	tuner_dbg("resume\n");
- 	if (V4L2_TUNER_RADIO == t->mode) {
- 		if (t->radio_freq)
- 			set_freq(c, t->radio_freq);
-@@ -1041,36 +1036,227 @@ static int tuner_resume(struct i2c_client *c)
- 	return 0;
- }
+ /* ---------------------------------------------------------------------
+diff --git a/drivers/media/video/videobuf-dvb.c b/drivers/media/video/videobuf-dvb.c
+index 880317e..b73aba6 100644
+--- a/drivers/media/video/videobuf-dvb.c
++++ b/drivers/media/video/videobuf-dvb.c
+@@ -67,7 +67,7 @@ static int videobuf_dvb_thread(void *data)
  
--/* ----------------------------------------------------------------------- */
-+/* ---------------------------------------------------------------------- */
+ 		/* feed buffer data to demux */
+ 		dma=videobuf_to_dma(buf);
+-		if (buf->state == STATE_DONE)
++		if (buf->state == VIDEOBUF_DONE)
+ 			dvb_dmx_swfilter(&dvb->demux, dma->vmalloc,
+ 					 buf->size);
  
--static struct i2c_driver driver = {
--	.id = I2C_DRIVERID_TUNER,
--	.attach_adapter = tuner_probe,
--	.detach_client = tuner_detach,
--	.command = tuner_command,
--	.suspend = tuner_suspend,
--	.resume  = tuner_resume,
--	.driver = {
--		.name    = "tuner",
--	},
--};
--static struct i2c_client client_template = {
--	.name = "(tuner unset)",
--	.driver = &driver,
--};
-+LIST_HEAD(tuner_list);
+diff --git a/drivers/media/video/videobuf-vmalloc.c b/drivers/media/video/videobuf-vmalloc.c
+index e012594..9b38983 100644
+--- a/drivers/media/video/videobuf-vmalloc.c
++++ b/drivers/media/video/videobuf-vmalloc.c
+@@ -41,7 +41,7 @@ MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab at infradead.org>");
+ MODULE_LICENSE("GPL");
  
--static int __init tuner_init_module(void)
-+/* Search for existing radio and/or TV tuners on the given I2C adapter.
-+   Note that when this function is called from tuner_probe you can be
-+   certain no other devices will be added/deleted at the same time, I2C
-+   core protects against that. */
-+static void tuner_lookup(struct i2c_adapter *adap,
-+		struct tuner **radio, struct tuner **tv)
- {
--	return i2c_add_driver(&driver);
-+	struct tuner *pos;
-+
-+	*radio = NULL;
-+	*tv = NULL;
-+
-+	list_for_each_entry(pos, &tuner_list, list) {
-+		int mode_mask;
-+
-+		if (pos->i2c->adapter != adap ||
-+		    pos->i2c->driver->id != I2C_DRIVERID_TUNER)
-+			continue;
-+
-+		mode_mask = pos->mode_mask & ~T_STANDBY;
-+		if (*radio == NULL && mode_mask == T_RADIO)
-+			*radio = pos;
-+		/* Note: currently TDA9887 is the only demod-only
-+		   device. If other devices appear then we need to
-+		   make this test more general. */
-+		else if (*tv == NULL && pos->type != TUNER_TDA9887 &&
-+			 (pos->mode_mask & (T_ANALOG_TV | T_DIGITAL_TV)))
-+			*tv = pos;
-+	}
- }
+ #define dprintk(level, fmt, arg...)	if (debug >= level) \
+-	printk(KERN_DEBUG "vbuf-sg: " fmt , ## arg)
++	printk(KERN_DEBUG "vbuf-vmalloc: " fmt , ## arg)
  
--static void __exit tuner_cleanup_module(void)
-+/* During client attach, set_type is called by adapter's attach_inform callback.
-+   set_type must then be completed by tuner_probe.
-+ */
-+static int tuner_probe(struct i2c_client *client)
- {
--	i2c_del_driver(&driver);
-+	struct tuner *t;
-+	struct tuner *radio;
-+	struct tuner *tv;
-+
-+	t = kzalloc(sizeof(struct tuner), GFP_KERNEL);
-+	if (NULL == t)
-+		return -ENOMEM;
-+	t->i2c = client;
-+	strlcpy(client->name, "(tuner unset)", sizeof(client->name));
-+	i2c_set_clientdata(client, t);
-+	t->type = UNSET;
-+	t->audmode = V4L2_TUNER_MODE_STEREO;
-+	t->mode_mask = T_UNINITIALIZED;
-+
-+	if (show_i2c) {
-+		unsigned char buffer[16];
-+		int i, rc;
-+
-+		memset(buffer, 0, sizeof(buffer));
-+		rc = i2c_master_recv(client, buffer, sizeof(buffer));
-+		tuner_info("I2C RECV = ");
-+		for (i = 0; i < rc; i++)
-+			printk(KERN_CONT "%02x ", buffer[i]);
-+		printk("\n");
-+	}
-+	/* HACK: This test was added to avoid tuner to probe tda9840 and
-+	   tea6415c on the MXB card */
-+	if (client->adapter->id == I2C_HW_SAA7146 && client->addr < 0x4a) {
-+		kfree(t);
-+		return -ENODEV;
-+	}
-+
-+	/* autodetection code based on the i2c addr */
-+	if (!no_autodetect) {
-+		switch (client->addr) {
-+		case 0x10:
-+			if (tea5761_autodetection(t->i2c->adapter, t->i2c->addr)
-+					!= EINVAL) {
-+				t->type = TUNER_TEA5761;
-+				t->mode_mask = T_RADIO;
-+				t->mode = T_STANDBY;
-+				/* Sets freq to FM range */
-+				t->radio_freq = 87.5 * 16000;
-+				tuner_lookup(t->i2c->adapter, &radio, &tv);
-+				if (tv)
-+					tv->mode_mask &= ~T_RADIO;
-+
-+				goto register_client;
-+			}
-+			break;
-+		case 0x42:
-+		case 0x43:
-+		case 0x4a:
-+		case 0x4b:
-+			/* If chip is not tda8290, don't register.
-+			   since it can be tda9887*/
-+			if (tda829x_probe(t->i2c->adapter,
-+					  t->i2c->addr) == 0) {
-+				tuner_dbg("tda829x detected\n");
-+			} else {
-+				/* Default is being tda9887 */
-+				t->type = TUNER_TDA9887;
-+				t->mode_mask = T_RADIO | T_ANALOG_TV |
-+					       T_DIGITAL_TV;
-+				t->mode = T_STANDBY;
-+				goto register_client;
-+			}
-+			break;
-+		case 0x60:
-+			if (tea5767_autodetection(t->i2c->adapter, t->i2c->addr)
-+					!= EINVAL) {
-+				t->type = TUNER_TEA5767;
-+				t->mode_mask = T_RADIO;
-+				t->mode = T_STANDBY;
-+				/* Sets freq to FM range */
-+				t->radio_freq = 87.5 * 16000;
-+				tuner_lookup(t->i2c->adapter, &radio, &tv);
-+				if (tv)
-+					tv->mode_mask &= ~T_RADIO;
-+
-+				goto register_client;
-+			}
-+			break;
-+		}
-+	}
-+
-+	/* Initializes only the first TV tuner on this adapter. Why only the
-+	   first? Because there are some devices (notably the ones with TI
-+	   tuners) that have more than one i2c address for the *same* device.
-+	   Experience shows that, except for just one case, the first
-+	   address is the right one. The exception is a Russian tuner
-+	   (ACORP_Y878F). So, the desired behavior is just to enable the
-+	   first found TV tuner. */
-+	tuner_lookup(t->i2c->adapter, &radio, &tv);
-+	if (tv == NULL) {
-+		t->mode_mask = T_ANALOG_TV | T_DIGITAL_TV;
-+		if (radio == NULL)
-+			t->mode_mask |= T_RADIO;
-+		tuner_dbg("Setting mode_mask to 0x%02x\n", t->mode_mask);
-+		t->tv_freq = 400 * 16; /* Sets freq to VHF High */
-+		t->radio_freq = 87.5 * 16000; /* Sets freq to FM range */
-+	}
-+
-+	/* Should be just before return */
-+register_client:
-+	tuner_info("chip found @ 0x%x (%s)\n", client->addr << 1,
-+		       client->adapter->name);
-+
-+	/* Sets a default mode */
-+	if (t->mode_mask & T_ANALOG_TV) {
-+		t->mode = V4L2_TUNER_ANALOG_TV;
-+	} else  if (t->mode_mask & T_RADIO) {
-+		t->mode = V4L2_TUNER_RADIO;
-+	} else {
-+		t->mode = V4L2_TUNER_DIGITAL_TV;
-+	}
-+	set_type(client, t->type, t->mode_mask, t->config, t->tuner_callback);
-+	list_add_tail(&t->list, &tuner_list);
-+	return 0;
-+}
-+
-+static int tuner_legacy_probe(struct i2c_adapter *adap)
-+{
-+	if (0 != addr) {
-+		normal_i2c[0] = addr;
-+		normal_i2c[1] = I2C_CLIENT_END;
-+	}
-+
-+	if ((adap->class & I2C_CLASS_TV_ANALOG) == 0)
-+		return 0;
-+
-+	/* HACK: Ignore 0x6b and 0x6f on cx88 boards.
-+	 * FusionHDTV5 RT Gold has an ir receiver at 0x6b
-+	 * and an RTC at 0x6f which can get corrupted if probed.
-+	 */
-+	if ((adap->id == I2C_HW_B_CX2388x) ||
-+	    (adap->id == I2C_HW_B_CX23885)) {
-+		unsigned int i = 0;
-+
-+		while (i < I2C_CLIENT_MAX_OPTS && ignore[i] != I2C_CLIENT_END)
-+			i += 2;
-+		if (i + 4 < I2C_CLIENT_MAX_OPTS) {
-+			ignore[i+0] = adap->nr;
-+			ignore[i+1] = 0x6b;
-+			ignore[i+2] = adap->nr;
-+			ignore[i+3] = 0x6f;
-+			ignore[i+4] = I2C_CLIENT_END;
-+		} else
-+			printk(KERN_WARNING "tuner: "
-+			       "too many options specified "
-+			       "in i2c probe ignore list!\n");
-+	}
-+	return 1;
- }
  
--module_init(tuner_init_module);
--module_exit(tuner_cleanup_module);
-+static int tuner_remove(struct i2c_client *client)
-+{
-+	struct tuner *t = i2c_get_clientdata(client);
-+	struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
-+
-+	if (analog_ops->release)
-+		analog_ops->release(&t->fe);
-+
-+	list_del(&t->list);
-+	kfree(t);
-+	return 0;
-+}
-+
-+/* ----------------------------------------------------------------------- */
-+
-+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
-+	.name = "tuner",
-+	.driverid = I2C_DRIVERID_TUNER,
-+	.command = tuner_command,
-+	.probe = tuner_probe,
-+	.remove = tuner_remove,
-+	.suspend = tuner_suspend,
-+	.resume = tuner_resume,
-+	.legacy_probe = tuner_legacy_probe,
-+};
-+
+ /***************************************************************************/
+diff --git a/drivers/media/video/videodev.c b/drivers/media/video/videodev.c
+index 9611c39..28655f8 100644
+--- a/drivers/media/video/videodev.c
++++ b/drivers/media/video/videodev.c
+@@ -973,7 +973,7 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
  
- /*
-  * Overrides for Emacs so that we follow Linus's tabbing style.
-diff --git a/drivers/media/video/tuner-driver.h b/drivers/media/video/tuner-driver.h
-deleted file mode 100644
-index 28a10da..0000000
---- a/drivers/media/video/tuner-driver.h
-+++ /dev/null
-@@ -1,99 +0,0 @@
--/*
--    tuner-driver.h - interface for different tuners
--
--    Copyright (C) 1997 Markus Schroeder (schroedm at uni-duesseldorf.de)
--    minor modifications by Ralph Metzler (rjkm at 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.
--*/
--
--#ifndef __TUNER_DRIVER_H__
--#define __TUNER_DRIVER_H__
--
--#include <linux/videodev2.h>
--#include <linux/i2c.h>
--#include "tuner-i2c.h"
--#include "dvb_frontend.h"
--
--extern unsigned const int tuner_count;
--
--struct tuner;
--
--struct tuner_operations {
--	void (*set_tv_freq)(struct tuner *t, unsigned int freq);
--	void (*set_radio_freq)(struct tuner *t, unsigned int freq);
--	int  (*has_signal)(struct tuner *t);
--	int  (*is_stereo)(struct tuner *t);
--	int  (*get_afc)(struct tuner *t);
--	void (*tuner_status)(struct tuner *t);
--	void (*standby)(struct tuner *t);
--	void (*release)(struct tuner *t);
--};
--
--struct tuner {
--	/* device */
--	struct i2c_client i2c;
--
--	unsigned int type;	/* chip type */
--
--	unsigned int mode;
--	unsigned int mode_mask;	/* Combination of allowable modes */
--
--	unsigned int tv_freq;	/* keep track of the current settings */
--	unsigned int radio_freq;
--	unsigned int audmode;
--	v4l2_std_id  std;
--
--	int          using_v4l2;
--	void *priv;
--
--	struct dvb_frontend fe;
--
--	/* used by tda9887 */
--	unsigned int       tda9887_config;
--
--	unsigned int config;
--	int (*tuner_callback) (void *dev, int command,int arg);
--
--	struct tuner_operations ops;
--};
--
--/* ------------------------------------------------------------------------ */
--
--extern int tda9887_tuner_init(struct tuner *t);
--
--/* ------------------------------------------------------------------------ */
+ 		*id = vfd->current_norm;
+ 
+-		dbgarg (cmd, "value=%Lu\n", (long long unsigned) *id);
++		dbgarg (cmd, "value=%08Lx\n", (long long unsigned) *id);
+ 
+ 		ret=0;
+ 		break;
+@@ -982,7 +982,7 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
+ 	{
+ 		v4l2_std_id *id = arg,norm;
+ 
+-		dbgarg (cmd, "value=%Lu\n", (long long unsigned) *id);
++		dbgarg (cmd, "value=%08Lx\n", (long long unsigned) *id);
+ 
+ 		norm = (*id) & vfd->tvnorms;
+ 		if ( vfd->tvnorms && !norm)	/* Check if std is supported */
+@@ -1008,7 +1008,7 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
+ 			break;
+ 		ret=vfd->vidioc_querystd(file, fh, arg);
+ 		if (!ret)
+-			dbgarg (cmd, "detected std=%Lu\n",
++			dbgarg (cmd, "detected std=%08Lx\n",
+ 						(unsigned long long)*p);
+ 		break;
+ 	}
+@@ -1028,7 +1028,7 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
+ 		if (!ret)
+ 			dbgarg (cmd, "index=%d, name=%s, type=%d, "
+ 					"audioset=%d, "
+-					"tuner=%d, std=%Ld, status=%d\n",
++					"tuner=%d, std=%08Lx, status=%d\n",
+ 					p->index,p->name,p->type,p->audioset,
+ 					p->tuner,
+ 					(unsigned long long)p->std,
+diff --git a/drivers/media/video/vino.c b/drivers/media/video/vino.c
+index 9a03dc8..5bb7529 100644
+--- a/drivers/media/video/vino.c
++++ b/drivers/media/video/vino.c
+@@ -2589,11 +2589,7 @@ static int vino_acquire_input(struct vino_channel_settings *vcs)
+ 	/* First try D1 and then SAA7191 */
+ 	if (vino_drvdata->camera.driver
+ 	    && (vino_drvdata->camera.owner == VINO_NO_CHANNEL)) {
+-		if (i2c_use_client(vino_drvdata->camera.driver)) {
+-			ret = -ENODEV;
+-			goto out;
+-		}
 -
--#define tuner_warn(fmt, arg...) do {\
--	printk(KERN_WARNING "%s %d-%04x: " fmt, t->i2c.driver->driver.name, \
--			i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0)
--#define tuner_info(fmt, arg...) do {\
--	printk(KERN_INFO "%s %d-%04x: " fmt, t->i2c.driver->driver.name, \
--			i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0)
--#define tuner_dbg(fmt, arg...) do {\
--	extern int tuner_debug; \
--	if (tuner_debug) \
--		printk(KERN_DEBUG "%s %d-%04x: " fmt, t->i2c.driver->driver.name, \
--			i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0)
++		i2c_use_client(vino_drvdata->camera.driver);
+ 		vino_drvdata->camera.owner = vcs->channel;
+ 		vcs->input = VINO_INPUT_D1;
+ 		vcs->data_norm = VINO_DATA_NORM_D1;
+@@ -2602,11 +2598,7 @@ static int vino_acquire_input(struct vino_channel_settings *vcs)
+ 		int input, data_norm;
+ 		int saa7191_input;
+ 
+-		if (i2c_use_client(vino_drvdata->decoder.driver)) {
+-			ret = -ENODEV;
+-			goto out;
+-		}
 -
--#endif /* __TUNER_DRIVER_H__ */
++		i2c_use_client(vino_drvdata->decoder.driver);
+ 		input = VINO_INPUT_COMPOSITE;
+ 
+ 		saa7191_input = vino_get_saa7191_input(input);
+@@ -2688,10 +2680,7 @@ static int vino_set_input(struct vino_channel_settings *vcs, int input)
+ 		}
+ 
+ 		if (vino_drvdata->decoder.owner == VINO_NO_CHANNEL) {
+-			if (i2c_use_client(vino_drvdata->decoder.driver)) {
+-				ret = -ENODEV;
+-				goto out;
+-			}
++			i2c_use_client(vino_drvdata->decoder.driver);
+ 			vino_drvdata->decoder.owner = vcs->channel;
+ 		}
+ 
+@@ -2759,10 +2748,7 @@ static int vino_set_input(struct vino_channel_settings *vcs, int input)
+ 		}
+ 
+ 		if (vino_drvdata->camera.owner == VINO_NO_CHANNEL) {
+-			if (i2c_use_client(vino_drvdata->camera.driver)) {
+-				ret = -ENODEV;
+-				goto out;
+-			}
++			i2c_use_client(vino_drvdata->camera.driver);
+ 			vino_drvdata->camera.owner = vcs->channel;
+ 		}
+ 
+diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c
+index 9b54ff9..1db067c 100644
+--- a/drivers/media/video/vivi.c
++++ b/drivers/media/video/vivi.c
+@@ -44,21 +44,18 @@
+ #define WAKE_DENOMINATOR 1001
+ #define BUFFER_TIMEOUT     msecs_to_jiffies(500)  /* 0.5 seconds */
+ 
+-/* These timers are for 1 fps - used only for testing */
+-//#define WAKE_DENOMINATOR 30 /* hack for testing purposes */
+-//#define BUFFER_TIMEOUT     msecs_to_jiffies(5000)  /* 5 seconds */
 -
--/*
-- * Overrides for Emacs so that we follow Linus's tabbing style.
-- * ---------------------------------------------------------------------------
-- * Local variables:
-- * c-basic-offset: 8
-- * End:
-- */
-diff --git a/drivers/media/video/tuner-i2c.h b/drivers/media/video/tuner-i2c.h
-index 159019e..de52e8f 100644
---- a/drivers/media/video/tuner-i2c.h
-+++ b/drivers/media/video/tuner-i2c.h
-@@ -46,25 +46,42 @@ static inline int tuner_i2c_xfer_recv(struct tuner_i2c_props *props, char *buf,
- 	return (ret == 1) ? len : ret;
- }
+ #include "font.h"
  
--#ifndef __TUNER_DRIVER_H__
--#define tuner_warn(fmt, arg...) do {\
--	printk(KERN_WARNING PREFIX "%d-%04x: " fmt, \
--			i2c_adapter_id(priv->i2c_props.adap), priv->i2c_props.addr , ##arg); } while (0)
--#define tuner_info(fmt, arg...) do {\
--	printk(KERN_INFO PREFIX "%d-%04x: " fmt, \
--			i2c_adapter_id(priv->i2c_props.adap), priv->i2c_props.addr , ##arg); } while (0)
--#define tuner_dbg(fmt, arg...) do {\
--	if ((debug)) \
--		printk(KERN_DEBUG PREFIX "%d-%04x: " fmt, \
--			i2c_adapter_id(priv->i2c_props.adap), priv->i2c_props.addr , ##arg); } while (0)
--#endif /* __TUNER_DRIVER_H__ */
-+static inline int tuner_i2c_xfer_send_recv(struct tuner_i2c_props *props,
-+					   char *obuf, int olen,
-+					   char *ibuf, int ilen)
-+{
-+	struct i2c_msg msg[2] = { { .addr = props->addr, .flags = 0,
-+				    .buf = obuf, .len = olen },
-+				  { .addr = props->addr, .flags = I2C_M_RD,
-+				    .buf = ibuf, .len = ilen } };
-+	int ret = i2c_transfer(props->adap, msg, 2);
+ #define VIVI_MAJOR_VERSION 0
+ #define VIVI_MINOR_VERSION 4
+ #define VIVI_RELEASE 0
+-#define VIVI_VERSION KERNEL_VERSION(VIVI_MAJOR_VERSION, VIVI_MINOR_VERSION, VIVI_RELEASE)
++#define VIVI_VERSION \
++	KERNEL_VERSION(VIVI_MAJOR_VERSION, VIVI_MINOR_VERSION, VIVI_RELEASE)
  
--#endif /* __TUNER_I2C_H__ */
-+	return (ret == 2) ? ilen : ret;
-+}
+ /* Declare static vars that will be used as parameters */
+ static unsigned int vid_limit = 16;	/* Video memory limit, in Mb */
+-static struct video_device vivi;	/* Video device */
+ static int video_nr = -1;		/* /dev/videoN, -1 for autodetect */
++static int n_devs = 1;			/* Number of virtual devices */
  
--/*
-- * Overrides for Emacs so that we follow Linus's tabbing style.
-- * ---------------------------------------------------------------------------
-- * Local variables:
-- * c-basic-offset: 8
-- * End:
-- */
-+#define tuner_warn(fmt, arg...) do {					\
-+	printk(KERN_WARNING "%s %d-%04x: " fmt, PREFIX,			\
-+			i2c_adapter_id(priv->i2c_props.adap),		\
-+			priv->i2c_props.addr, ##arg);			\
-+	 } while (0)
-+
-+#define tuner_info(fmt, arg...) do {					\
-+	printk(KERN_INFO "%s %d-%04x: " fmt, PREFIX,			\
-+			i2c_adapter_id(priv->i2c_props.adap),		\
-+			priv->i2c_props.addr , ##arg);			\
-+	} while (0)
-+
-+#define tuner_err(fmt, arg...) do {					\
-+	printk(KERN_ERR "%s %d-%04x: " fmt, PREFIX, 			\
-+			i2c_adapter_id(priv->i2c_props.adap),		\
-+			priv->i2c_props.addr , ##arg);			\
-+	} while (0)
-+
-+#define tuner_dbg(fmt, arg...) do {					\
-+	if ((debug))							\
-+		printk(KERN_DEBUG "%s %d-%04x: " fmt, PREFIX,		\
-+			i2c_adapter_id(priv->i2c_props.adap),		\
-+			priv->i2c_props.addr , ##arg);			\
-+	} while (0)
-+
-+#endif /* __TUNER_I2C_H__ */
-diff --git a/drivers/media/video/tuner-simple.c b/drivers/media/video/tuner-simple.c
-index 7b93d3b..c1db576 100644
---- a/drivers/media/video/tuner-simple.c
-+++ b/drivers/media/video/tuner-simple.c
-@@ -17,7 +17,7 @@ static int debug = 0;
- module_param(debug, int, 0644);
- MODULE_PARM_DESC(debug, "enable verbose debug messages");
+ /* supported controls */
+ static struct v4l2_queryctrl vivi_qctrl[] = {
+@@ -71,7 +68,7 @@ static struct v4l2_queryctrl vivi_qctrl[] = {
+ 		.default_value = 65535,
+ 		.flags         = 0,
+ 		.type          = V4L2_CTRL_TYPE_INTEGER,
+-	},{
++	}, {
+ 		.id            = V4L2_CID_BRIGHTNESS,
+ 		.type          = V4L2_CTRL_TYPE_INTEGER,
+ 		.name          = "Brightness",
+@@ -112,9 +109,9 @@ static struct v4l2_queryctrl vivi_qctrl[] = {
  
--#define PREFIX "tuner-simple "
-+#define PREFIX "tuner-simple"
+ static int qctl_regs[ARRAY_SIZE(vivi_qctrl)];
  
- static int offset = 0;
- module_param(offset, int, 0664);
-@@ -355,10 +355,14 @@ static int simple_set_tv_freq(struct dvb_frontend *fe,
- 	}
- 	priv->last_div = div;
- 	if (t_params->has_tda9887) {
-+		struct v4l2_priv_tun_config tda9887_cfg;
- 		int config = 0;
- 		int is_secam_l = (params->std & (V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC)) &&
- 			!(params->std & ~(V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC));
+-#define dprintk(level,fmt, arg...)					\
++#define dprintk(dev, level, fmt, arg...)				\
+ 	do {								\
+-		if (vivi.debug >= (level))				\
++		if (dev->vfd->debug >= (level))				\
+ 			printk(KERN_DEBUG "vivi: " fmt , ## arg);	\
+ 	} while (0)
  
-+		tda9887_cfg.tuner = TUNER_TDA9887;
-+		tda9887_cfg.priv  = &config;
-+
- 		if (params->std == V4L2_STD_SECAM_LC) {
- 			if (t_params->port1_active ^ t_params->port1_invert_for_secam_lc)
- 				config |= TDA9887_PORT1_ACTIVE;
-@@ -391,7 +395,8 @@ static int simple_set_tv_freq(struct dvb_frontend *fe,
- 		}
- 		if (t_params->default_pll_gating_18)
- 			config |= TDA9887_GATING_18;
--		i2c_clients_command(priv->i2c_props.adap, TDA9887_SET_CONFIG, &config);
-+		i2c_clients_command(priv->i2c_props.adap, TUNER_SET_CONFIG,
-+				    &tda9887_cfg);
- 	}
- 	tuner_dbg("tv 0x%02x 0x%02x 0x%02x 0x%02x\n",
- 		  buffer[0],buffer[1],buffer[2],buffer[3]);
-@@ -534,6 +539,11 @@ static int simple_set_radio_freq(struct dvb_frontend *fe,
+@@ -166,17 +163,21 @@ struct vivi_dev {
+ 	struct list_head           vivi_devlist;
  
- 	if (t_params->has_tda9887) {
- 		int config = 0;
-+		struct v4l2_priv_tun_config tda9887_cfg;
-+
-+		tda9887_cfg.tuner = TUNER_TDA9887;
-+		tda9887_cfg.priv = &config;
-+
- 		if (t_params->port1_active && !t_params->port1_fm_high_sensitivity)
- 			config |= TDA9887_PORT1_ACTIVE;
- 		if (t_params->port2_active && !t_params->port2_fm_high_sensitivity)
-@@ -546,7 +556,8 @@ static int simple_set_radio_freq(struct dvb_frontend *fe,
- 			config |= TDA9887_GAIN_NORMAL;
- 		if (t_params->radio_if == 2)
- 			config |= TDA9887_RIF_41_3;
--		i2c_clients_command(priv->i2c_props.adap, TDA9887_SET_CONFIG, &config);
-+		i2c_clients_command(priv->i2c_props.adap, TUNER_SET_CONFIG,
-+					&tda9887_cfg);
- 	}
- 	if (4 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,buffer,4)))
- 		tuner_warn("i2c i/o error: rc == %d (should be 4)\n",rc);
-diff --git a/drivers/media/video/tuner-types.c b/drivers/media/video/tuner-types.c
-index c6a7934..883047f 100644
---- a/drivers/media/video/tuner-types.c
-+++ b/drivers/media/video/tuner-types.c
-@@ -1366,7 +1366,7 @@ struct tunertype tuners[] = {
- 		.count  = ARRAY_SIZE(tuner_philips_fq1286_params),
- 	},
- 	[TUNER_PHILIPS_TDA8290] = { /* Philips PAL|NTSC */
--		.name   = "tda8290+75",
-+		.name   = "Philips/NXP TDA 8290/8295 + 8275/8275A/18271",
- 		/* see tda8290.c for details */ },
- 	[TUNER_TCL_2002MB] = { /* TCL PAL */
- 		.name   = "TCL 2002MB",
-@@ -1452,9 +1452,9 @@ struct tunertype tuners[] = {
- 		.params = tuner_samsung_tcpn_2121p30a_params,
- 		.count  = ARRAY_SIZE(tuner_samsung_tcpn_2121p30a_params),
- 	},
--	[TUNER_XCEIVE_XC3028] = { /* Xceive 3028 */
--		.name	= "Xceive xc3028",
--		/* see xc3028.c for details */
-+	[TUNER_XC2028] = { /* Xceive 2028 */
-+		.name   = "Xceive xc2028/xc3028 tuner",
-+		/* see tuner-xc2028.c for details */
- 	},
- 	[TUNER_THOMSON_FE6600] = { /* Thomson PAL / DVB-T */
- 		.name   = "Thomson FE6600",
-@@ -1475,6 +1475,10 @@ struct tunertype tuners[] = {
- 		.name   = "Philips TEA5761 FM Radio",
- 		/* see tea5767.c for details */
- 	},
-+	[TUNER_XC5000] = { /* Xceive 5000 */
-+		.name   = "Xceive 5000 tuner",
-+		/* see xc5000.c for details */
-+	},
- };
+ 	struct mutex               lock;
++	spinlock_t                 slock;
  
- unsigned const int tuner_count = ARRAY_SIZE(tuners);
-diff --git a/drivers/media/video/tuner-xc2028-types.h b/drivers/media/video/tuner-xc2028-types.h
-new file mode 100644
-index 0000000..d0057fb
---- /dev/null
-+++ b/drivers/media/video/tuner-xc2028-types.h
-@@ -0,0 +1,128 @@
-+/* tuner-xc2028_types
-+ *
-+ * Copyright (c) 2007 Mauro Carvalho Chehab (mchehab at infradead.org)
-+ * This code is placed under the terms of the GNU General Public License v2
-+ */
-+
-+/* xc3028 firmware types */
-+
-+/* BASE firmware should be loaded before any other firmware */
-+#define BASE		(1<<0)
-+#define BASE_TYPES	(BASE|F8MHZ|MTS|FM|INPUT1|INPUT2|INIT1)
-+
-+/* F8MHZ marks BASE firmwares for 8 MHz Bandwidth */
-+#define F8MHZ		(1<<1)
-+
-+/* Multichannel Television Sound (MTS)
-+   Those firmwares are capable of using xc2038 DSP to decode audio and
-+   produce a baseband audio output on some pins of the chip.
-+   There are MTS firmwares for the most used video standards. It should be
-+   required to use MTS firmwares, depending on the way audio is routed into
-+   the bridge chip
-+ */
-+#define MTS		(1<<2)
-+
-+/* FIXME: I have no idea what's the difference between
-+   D2620 and D2633 firmwares
-+ */
-+#define D2620		(1<<3)
-+#define D2633		(1<<4)
-+
-+/* DTV firmwares for 6, 7 and 8 MHz
-+   DTV6 - 6MHz - ATSC/DVB-C/DVB-T/ISDB-T/DOCSIS
-+   DTV8 - 8MHz - DVB-C/DVB-T
-+ */
-+#define DTV6           (1 << 5)
-+#define QAM            (1 << 6)
-+#define DTV7		(1<<7)
-+#define DTV78		(1<<8)
-+#define DTV8		(1<<9)
-+
-+#define DTV_TYPES	(D2620|D2633|DTV6|QAM|DTV7|DTV78|DTV8|ATSC)
-+
-+/* There's a FM | BASE firmware + FM specific firmware (std=0) */
-+#define	FM		(1<<10)
-+
-+#define STD_SPECIFIC_TYPES (MTS|FM|LCD|NOGD)
-+
-+/* Applies only for FM firmware
-+   Makes it use RF input 1 (pin #2) instead of input 2 (pin #4)
-+ */
-+#define INPUT1		(1<<11)
-+
-+
-+/* LCD firmwares exist only for MTS STD/MN (PAL or NTSC/M)
-+	and for non-MTS STD/MN (PAL, NTSC/M or NTSC/Kr)
-+	There are variants both with and without NOGD
-+ */
-+#define LCD		(1<<12)
-+
-+/* NOGD firmwares exist only for MTS STD/MN (PAL or NTSC/M)
-+	and for non-MTS STD/MN (PAL, NTSC/M or NTSC/Kr)
-+ */
-+#define NOGD		(1<<13)
-+
-+/* Old firmwares were broken into init0 and init1 */
-+#define INIT1		(1<<14)
-+
-+/* SCODE firmware selects particular behaviours */
-+#define MONO           (1 << 15)
-+#define ATSC           (1 << 16)
-+#define IF             (1 << 17)
-+#define LG60           (1 << 18)
-+#define ATI638         (1 << 19)
-+#define OREN538        (1 << 20)
-+#define OREN36         (1 << 21)
-+#define TOYOTA388      (1 << 22)
-+#define TOYOTA794      (1 << 23)
-+#define DIBCOM52       (1 << 24)
-+#define ZARLINK456     (1 << 25)
-+#define CHINA          (1 << 26)
-+#define F6MHZ          (1 << 27)
-+#define INPUT2         (1 << 28)
-+#define SCODE          (1 << 29)
-+
-+/* This flag identifies that the scode table has a new format */
-+#define HAS_IF         (1 << 30)
-+
-+#define SCODE_TYPES	(MTS|DTV6|QAM|DTV7|DTV78|DTV8|LCD|NOGD|MONO|ATSC|IF| \
-+			 LG60|ATI638|OREN538|OREN36|TOYOTA388|TOYOTA794|     \
-+			 DIBCOM52|ZARLINK456|CHINA|F6MHZ|SCODE)
-+
-+/* Newer types to be moved to videodev2.h */
-+
-+#define V4L2_STD_SECAM_K3	(0x04000000)
-+
-+/* Audio types */
-+
-+#define V4L2_STD_A2_A		(1LL<<32)
-+#define V4L2_STD_A2_B		(1LL<<33)
-+#define V4L2_STD_NICAM_A	(1LL<<34)
-+#define V4L2_STD_NICAM_B	(1LL<<35)
-+#define V4L2_STD_AM		(1LL<<36)
-+#define V4L2_STD_BTSC		(1LL<<37)
-+#define V4L2_STD_EIAJ		(1LL<<38)
-+
-+#define V4L2_STD_A2		(V4L2_STD_A2_A    | V4L2_STD_A2_B)
-+#define V4L2_STD_NICAM		(V4L2_STD_NICAM_A | V4L2_STD_NICAM_B)
-+
-+/* To preserve backward compatibilty,
-+   (std & V4L2_STD_AUDIO) = 0 means that ALL audio stds are supported
-+ */
-+
-+#define V4L2_STD_AUDIO		(V4L2_STD_A2    | \
-+				 V4L2_STD_NICAM | \
-+				 V4L2_STD_AM    | \
-+				 V4L2_STD_BTSC  | \
-+				 V4L2_STD_EIAJ)
-+
-+/* Used standards with audio restrictions */
-+
-+#define V4L2_STD_PAL_BG_A2_A	(V4L2_STD_PAL_BG | V4L2_STD_A2_A)
-+#define V4L2_STD_PAL_BG_A2_B	(V4L2_STD_PAL_BG | V4L2_STD_A2_B)
-+#define V4L2_STD_PAL_BG_NICAM_A	(V4L2_STD_PAL_BG | V4L2_STD_NICAM_A)
-+#define V4L2_STD_PAL_BG_NICAM_B	(V4L2_STD_PAL_BG | V4L2_STD_NICAM_B)
-+#define V4L2_STD_PAL_DK_A2	(V4L2_STD_PAL_DK | V4L2_STD_A2)
-+#define V4L2_STD_PAL_DK_NICAM	(V4L2_STD_PAL_DK | V4L2_STD_NICAM)
-+#define V4L2_STD_SECAM_L_NICAM	(V4L2_STD_SECAM_L | V4L2_STD_NICAM)
-+#define V4L2_STD_SECAM_L_AM	(V4L2_STD_SECAM_L | V4L2_STD_AM)
-diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/video/tuner-xc2028.c
-new file mode 100644
-index 0000000..f191f6a
---- /dev/null
-+++ b/drivers/media/video/tuner-xc2028.c
-@@ -0,0 +1,1213 @@
-+/* tuner-xc2028
-+ *
-+ * Copyright (c) 2007 Mauro Carvalho Chehab (mchehab at infradead.org)
-+ *
-+ * Copyright (c) 2007 Michel Ludwig (michel.ludwig at gmail.com)
-+ *       - frontend interface
-+ *
-+ * This code is placed under the terms of the GNU General Public License v2
-+ */
-+
-+#include <linux/i2c.h>
-+#include <asm/div64.h>
-+#include <linux/firmware.h>
-+#include <linux/videodev2.h>
-+#include <linux/delay.h>
-+#include <media/tuner.h>
-+#include <linux/mutex.h>
-+#include "tuner-i2c.h"
-+#include "tuner-xc2028.h"
-+#include "tuner-xc2028-types.h"
-+
-+#include <linux/dvb/frontend.h>
-+#include "dvb_frontend.h"
-+
-+
-+#define PREFIX "xc2028"
-+
-+static int debug;
-+module_param(debug, int, 0644);
-+MODULE_PARM_DESC(debug, "enable verbose debug messages");
-+
-+static char audio_std[8];
-+module_param_string(audio_std, audio_std, sizeof(audio_std), 0);
-+MODULE_PARM_DESC(audio_std,
-+	"Audio standard. XC3028 audio decoder explicitly "
-+	"needs to know what audio\n"
-+	"standard is needed for some video standards with audio A2 or NICAM.\n"
-+	"The valid values are:\n"
-+	"A2\n"
-+	"A2/A\n"
-+	"A2/B\n"
-+	"NICAM\n"
-+	"NICAM/A\n"
-+	"NICAM/B\n");
-+
-+static LIST_HEAD(xc2028_list);
-+static DEFINE_MUTEX(xc2028_list_mutex);
-+
-+/* struct for storing firmware table */
-+struct firmware_description {
-+	unsigned int  type;
-+	v4l2_std_id   id;
-+	__u16         int_freq;
-+	unsigned char *ptr;
-+	unsigned int  size;
-+};
-+
-+struct firmware_properties {
-+	unsigned int	type;
-+	v4l2_std_id	id;
-+	v4l2_std_id	std_req;
-+	__u16		int_freq;
-+	unsigned int	scode_table;
-+	int 		scode_nr;
-+};
-+
-+struct xc2028_data {
-+	struct list_head        xc2028_list;
-+	struct tuner_i2c_props  i2c_props;
-+	int                     (*tuner_callback) (void *dev,
-+						   int command, int arg);
-+	void			*video_dev;
-+	int			count;
-+	__u32			frequency;
-+
-+	struct firmware_description *firm;
-+	int			firm_size;
-+	__u16			firm_version;
-+
-+	__u16			hwmodel;
-+	__u16			hwvers;
-+
-+	struct xc2028_ctrl	ctrl;
-+
-+	struct firmware_properties cur_fw;
-+
-+	struct mutex lock;
-+};
-+
-+#define i2c_send(priv, buf, size) ({					\
-+	int _rc;							\
-+	_rc = tuner_i2c_xfer_send(&priv->i2c_props, buf, size);		\
-+	if (size != _rc)						\
-+		tuner_info("i2c output error: rc = %d (should be %d)\n",\
-+			   _rc, (int)size);				\
-+	_rc;								\
-+})
-+
-+#define i2c_rcv(priv, buf, size) ({					\
-+	int _rc;							\
-+	_rc = tuner_i2c_xfer_recv(&priv->i2c_props, buf, size);		\
-+	if (size != _rc)						\
-+		tuner_err("i2c input error: rc = %d (should be %d)\n",	\
-+			   _rc, (int)size); 				\
-+	_rc;								\
-+})
-+
-+#define i2c_send_recv(priv, obuf, osize, ibuf, isize) ({		\
-+	int _rc;							\
-+	_rc = tuner_i2c_xfer_send_recv(&priv->i2c_props, obuf, osize,	\
-+				       ibuf, isize);			\
-+	if (isize != _rc)						\
-+		tuner_err("i2c input error: rc = %d (should be %d)\n",	\
-+			   _rc, (int)isize); 				\
-+	_rc;								\
-+})
-+
-+#define send_seq(priv, data...)	({					\
-+	static u8 _val[] = data;					\
-+	int _rc;							\
-+	if (sizeof(_val) !=						\
-+			(_rc = tuner_i2c_xfer_send(&priv->i2c_props,	\
-+						_val, sizeof(_val)))) {	\
-+		tuner_err("Error on line %d: %d\n", __LINE__, _rc);	\
-+	} else 								\
-+		msleep(10);						\
-+	_rc;								\
-+})
-+
-+static unsigned int xc2028_get_reg(struct xc2028_data *priv, u16 reg, u16 *val)
-+{
-+	unsigned char buf[2];
-+	unsigned char ibuf[2];
-+
-+	tuner_dbg("%s %04x called\n", __FUNCTION__, reg);
-+
-+	buf[0] = reg >> 8;
-+	buf[1] = (unsigned char) reg;
-+
-+	if (i2c_send_recv(priv, buf, 2, ibuf, 2) != 2)
-+		return -EIO;
-+
-+	*val = (ibuf[1]) | (ibuf[0] << 8);
-+	return 0;
-+}
-+
-+#define dump_firm_type(t) 	dump_firm_type_and_int_freq(t, 0)
-+void dump_firm_type_and_int_freq(unsigned int type, u16 int_freq)
-+{
-+	 if (type & BASE)
-+		printk("BASE ");
-+	 if (type & INIT1)
-+		printk("INIT1 ");
-+	 if (type & F8MHZ)
-+		printk("F8MHZ ");
-+	 if (type & MTS)
-+		printk("MTS ");
-+	 if (type & D2620)
-+		printk("D2620 ");
-+	 if (type & D2633)
-+		printk("D2633 ");
-+	 if (type & DTV6)
-+		printk("DTV6 ");
-+	 if (type & QAM)
-+		printk("QAM ");
-+	 if (type & DTV7)
-+		printk("DTV7 ");
-+	 if (type & DTV78)
-+		printk("DTV78 ");
-+	 if (type & DTV8)
-+		printk("DTV8 ");
-+	 if (type & FM)
-+		printk("FM ");
-+	 if (type & INPUT1)
-+		printk("INPUT1 ");
-+	 if (type & LCD)
-+		printk("LCD ");
-+	 if (type & NOGD)
-+		printk("NOGD ");
-+	 if (type & MONO)
-+		printk("MONO ");
-+	 if (type & ATSC)
-+		printk("ATSC ");
-+	 if (type & IF)
-+		printk("IF ");
-+	 if (type & LG60)
-+		printk("LG60 ");
-+	 if (type & ATI638)
-+		printk("ATI638 ");
-+	 if (type & OREN538)
-+		printk("OREN538 ");
-+	 if (type & OREN36)
-+		printk("OREN36 ");
-+	 if (type & TOYOTA388)
-+		printk("TOYOTA388 ");
-+	 if (type & TOYOTA794)
-+		printk("TOYOTA794 ");
-+	 if (type & DIBCOM52)
-+		printk("DIBCOM52 ");
-+	 if (type & ZARLINK456)
-+		printk("ZARLINK456 ");
-+	 if (type & CHINA)
-+		printk("CHINA ");
-+	 if (type & F6MHZ)
-+		printk("F6MHZ ");
-+	 if (type & INPUT2)
-+		printk("INPUT2 ");
-+	 if (type & SCODE)
-+		printk("SCODE ");
-+	 if (type & HAS_IF)
-+		printk("HAS_IF_%d ", int_freq);
-+}
-+
-+static  v4l2_std_id parse_audio_std_option(void)
-+{
-+	if (strcasecmp(audio_std, "A2") == 0)
-+		return V4L2_STD_A2;
-+	if (strcasecmp(audio_std, "A2/A") == 0)
-+		return V4L2_STD_A2_A;
-+	if (strcasecmp(audio_std, "A2/B") == 0)
-+		return V4L2_STD_A2_B;
-+	if (strcasecmp(audio_std, "NICAM") == 0)
-+		return V4L2_STD_NICAM;
-+	if (strcasecmp(audio_std, "NICAM/A") == 0)
-+		return V4L2_STD_NICAM_A;
-+	if (strcasecmp(audio_std, "NICAM/B") == 0)
-+		return V4L2_STD_NICAM_B;
-+
-+	return 0;
-+}
-+
-+static void free_firmware(struct xc2028_data *priv)
-+{
-+	int i;
-+
-+	if (!priv->firm)
-+		return;
-+
-+	for (i = 0; i < priv->firm_size; i++)
-+		kfree(priv->firm[i].ptr);
-+
-+	kfree(priv->firm);
-+
-+	priv->firm = NULL;
-+	priv->firm_size = 0;
-+
-+	memset(&priv->cur_fw, 0, sizeof(priv->cur_fw));
-+}
-+
-+static int load_all_firmwares(struct dvb_frontend *fe)
-+{
-+	struct xc2028_data    *priv = fe->tuner_priv;
-+	const struct firmware *fw   = NULL;
-+	unsigned char         *p, *endp;
-+	int                   rc = 0;
-+	int		      n, n_array;
-+	char		      name[33];
-+
-+	tuner_dbg("%s called\n", __FUNCTION__);
-+
-+	tuner_dbg("Reading firmware %s\n", priv->ctrl.fname);
-+	rc = request_firmware(&fw, priv->ctrl.fname,
-+			      &priv->i2c_props.adap->dev);
-+	if (rc < 0) {
-+		if (rc == -ENOENT)
-+			tuner_err("Error: firmware %s not found.\n",
-+				   priv->ctrl.fname);
-+		else
-+			tuner_err("Error %d while requesting firmware %s \n",
-+				   rc, priv->ctrl.fname);
-+
-+		return rc;
-+	}
-+	p = fw->data;
-+	endp = p + fw->size;
-+
-+	if (fw->size < sizeof(name) - 1 + 2 + 2) {
-+		tuner_err("Error: firmware file %s has invalid size!\n",
-+			  priv->ctrl.fname);
-+		goto corrupt;
-+	}
-+
-+	memcpy(name, p, sizeof(name) - 1);
-+	name[sizeof(name) - 1] = 0;
-+	p += sizeof(name) - 1;
-+
-+	priv->firm_version = le16_to_cpu(*(__u16 *) p);
-+	p += 2;
-+
-+	n_array = le16_to_cpu(*(__u16 *) p);
-+	p += 2;
-+
-+	tuner_info("Loading %d firmware images from %s, type: %s, ver %d.%d\n",
-+		   n_array, priv->ctrl.fname, name,
-+		   priv->firm_version >> 8, priv->firm_version & 0xff);
-+
-+	priv->firm = kzalloc(sizeof(*priv->firm) * n_array, GFP_KERNEL);
-+	if (priv->firm == NULL) {
-+		tuner_err("Not enough memory to load firmware file.\n");
-+		rc = -ENOMEM;
-+		goto err;
-+	}
-+	priv->firm_size = n_array;
-+
-+	n = -1;
-+	while (p < endp) {
-+		__u32 type, size;
-+		v4l2_std_id id;
-+		__u16 int_freq = 0;
-+
-+		n++;
-+		if (n >= n_array) {
-+			tuner_err("More firmware images in file than "
-+				  "were expected!\n");
-+			goto corrupt;
-+		}
-+
-+		/* Checks if there's enough bytes to read */
-+		if (p + sizeof(type) + sizeof(id) + sizeof(size) > endp) {
-+			tuner_err("Firmware header is incomplete!\n");
-+			goto corrupt;
-+		}
-+
-+		type = le32_to_cpu(*(__u32 *) p);
-+		p += sizeof(type);
-+
-+		id = le64_to_cpu(*(v4l2_std_id *) p);
-+		p += sizeof(id);
-+
-+		if (type & HAS_IF) {
-+			int_freq = le16_to_cpu(*(__u16 *) p);
-+			p += sizeof(int_freq);
-+		}
-+
-+		size = le32_to_cpu(*(__u32 *) p);
-+		p += sizeof(size);
-+
-+		if ((!size) || (size + p > endp)) {
-+			tuner_err("Firmware type ");
-+			dump_firm_type(type);
-+			printk("(%x), id %llx is corrupted "
-+			       "(size=%d, expected %d)\n",
-+			       type, (unsigned long long)id,
-+			       (unsigned)(endp - p), size);
-+			goto corrupt;
-+		}
-+
-+		priv->firm[n].ptr = kzalloc(size, GFP_KERNEL);
-+		if (priv->firm[n].ptr == NULL) {
-+			tuner_err("Not enough memory to load firmware file.\n");
-+			rc = -ENOMEM;
-+			goto err;
-+		}
-+		tuner_dbg("Reading firmware type ");
-+		if (debug) {
-+			dump_firm_type_and_int_freq(type, int_freq);
-+			printk("(%x), id %llx, size=%d.\n",
-+			       type, (unsigned long long)id, size);
-+		}
-+
-+		memcpy(priv->firm[n].ptr, p, size);
-+		priv->firm[n].type = type;
-+		priv->firm[n].id   = id;
-+		priv->firm[n].size = size;
-+		priv->firm[n].int_freq = int_freq;
-+
-+		p += size;
-+	}
-+
-+	if (n + 1 != priv->firm_size) {
-+		tuner_err("Firmware file is incomplete!\n");
-+		goto corrupt;
-+	}
-+
-+	goto done;
-+
-+corrupt:
-+	rc = -EINVAL;
-+	tuner_err("Error: firmware file is corrupted!\n");
-+
-+err:
-+	tuner_info("Releasing partially loaded firmware file.\n");
-+	free_firmware(priv);
-+
-+done:
-+	release_firmware(fw);
-+	if (rc == 0)
-+		tuner_dbg("Firmware files loaded.\n");
-+
-+	return rc;
-+}
-+
-+static int seek_firmware(struct dvb_frontend *fe, unsigned int type,
-+			 v4l2_std_id *id)
-+{
-+	struct xc2028_data *priv = fe->tuner_priv;
-+	int                 i, best_i = -1, best_nr_matches = 0;
-+	unsigned int        ign_firm_type_mask = 0;
-+
-+	tuner_dbg("%s called, want type=", __FUNCTION__);
-+	if (debug) {
-+		dump_firm_type(type);
-+		printk("(%x), id %016llx.\n", type, (unsigned long long)*id);
-+	}
-+
-+	if (!priv->firm) {
-+		tuner_err("Error! firmware not loaded\n");
-+		return -EINVAL;
-+	}
-+
-+	if (((type & ~SCODE) == 0) && (*id == 0))
-+		*id = V4L2_STD_PAL;
-+
-+	if (type & BASE)
-+		type &= BASE_TYPES;
-+	else if (type & SCODE) {
-+		type &= SCODE_TYPES;
-+		ign_firm_type_mask = HAS_IF;
-+	} else if (type & DTV_TYPES)
-+		type &= DTV_TYPES;
-+	else if (type & STD_SPECIFIC_TYPES)
-+		type &= STD_SPECIFIC_TYPES;
-+
-+	/* Seek for exact match */
-+	for (i = 0; i < priv->firm_size; i++) {
-+		if ((type == (priv->firm[i].type & ~ign_firm_type_mask)) &&
-+		    (*id == priv->firm[i].id))
-+			goto found;
-+	}
-+
-+	/* Seek for generic video standard match */
-+	for (i = 0; i < priv->firm_size; i++) {
-+		v4l2_std_id match_mask;
-+		int nr_matches;
-+
-+		if (type != (priv->firm[i].type & ~ign_firm_type_mask))
-+			continue;
-+
-+		match_mask = *id & priv->firm[i].id;
-+		if (!match_mask)
-+			continue;
-+
-+		if ((*id & match_mask) == *id)
-+			goto found; /* Supports all the requested standards */
-+
-+		nr_matches = hweight64(match_mask);
-+		if (nr_matches > best_nr_matches) {
-+			best_nr_matches = nr_matches;
-+			best_i = i;
-+		}
-+	}
-+
-+	if (best_nr_matches > 0) {
-+		tuner_dbg("Selecting best matching firmware (%d bits) for "
-+			  "type=", best_nr_matches);
-+		dump_firm_type(type);
-+		printk("(%x), id %016llx:\n", type, (unsigned long long)*id);
-+		i = best_i;
-+		goto found;
-+	}
-+
-+	/*FIXME: Would make sense to seek for type "hint" match ? */
-+
-+	i = -ENOENT;
-+	goto ret;
-+
-+found:
-+	*id = priv->firm[i].id;
-+
-+ret:
-+	tuner_dbg("%s firmware for type=", (i < 0) ? "Can't find" : "Found");
-+	if (debug) {
-+		dump_firm_type(type);
-+		printk("(%x), id %016llx.\n", type, (unsigned long long)*id);
-+	}
-+	return i;
-+}
-+
-+static int load_firmware(struct dvb_frontend *fe, unsigned int type,
-+			 v4l2_std_id *id)
-+{
-+	struct xc2028_data *priv = fe->tuner_priv;
-+	int                pos, rc;
-+	unsigned char      *p, *endp, buf[priv->ctrl.max_len];
-+
-+	tuner_dbg("%s called\n", __FUNCTION__);
-+
-+	pos = seek_firmware(fe, type, id);
-+	if (pos < 0)
-+		return pos;
-+
-+	tuner_info("Loading firmware for type=");
-+	dump_firm_type(priv->firm[pos].type);
-+	printk("(%x), id %016llx.\n", priv->firm[pos].type,
-+	       (unsigned long long)*id);
-+
-+	p = priv->firm[pos].ptr;
-+	endp = p + priv->firm[pos].size;
-+
-+	while (p < endp) {
-+		__u16 size;
-+
-+		/* Checks if there's enough bytes to read */
-+		if (p + sizeof(size) > endp) {
-+			tuner_err("Firmware chunk size is wrong\n");
-+			return -EINVAL;
-+		}
-+
-+		size = le16_to_cpu(*(__u16 *) p);
-+		p += sizeof(size);
-+
-+		if (size == 0xffff)
-+			return 0;
-+
-+		if (!size) {
-+			/* Special callback command received */
-+			rc = priv->tuner_callback(priv->video_dev,
-+						  XC2028_TUNER_RESET, 0);
-+			if (rc < 0) {
-+				tuner_err("Error at RESET code %d\n",
-+					   (*p) & 0x7f);
-+				return -EINVAL;
-+			}
-+			continue;
-+		}
-+		if (size >= 0xff00) {
-+			switch (size) {
-+			case 0xff00:
-+				rc = priv->tuner_callback(priv->video_dev,
-+							XC2028_RESET_CLK, 0);
-+				if (rc < 0) {
-+					tuner_err("Error at RESET code %d\n",
-+						  (*p) & 0x7f);
-+					return -EINVAL;
-+				}
-+				break;
-+			default:
-+				tuner_info("Invalid RESET code %d\n",
-+					   size & 0x7f);
-+				return -EINVAL;
-+
-+			}
-+			continue;
-+		}
-+
-+		/* Checks for a sleep command */
-+		if (size & 0x8000) {
-+			msleep(size & 0x7fff);
-+			continue;
-+		}
-+
-+		if ((size + p > endp)) {
-+			tuner_err("missing bytes: need %d, have %d\n",
-+				   size, (int)(endp - p));
-+			return -EINVAL;
-+		}
-+
-+		buf[0] = *p;
-+		p++;
-+		size--;
-+
-+		/* Sends message chunks */
-+		while (size > 0) {
-+			int len = (size < priv->ctrl.max_len - 1) ?
-+				   size : priv->ctrl.max_len - 1;
-+
-+			memcpy(buf + 1, p, len);
-+
-+			rc = i2c_send(priv, buf, len + 1);
-+			if (rc < 0) {
-+				tuner_err("%d returned from send\n", rc);
-+				return -EINVAL;
-+			}
-+
-+			p += len;
-+			size -= len;
-+		}
-+	}
-+	return 0;
-+}
-+
-+static int load_scode(struct dvb_frontend *fe, unsigned int type,
-+			 v4l2_std_id *id, __u16 int_freq, int scode)
-+{
-+	struct xc2028_data *priv = fe->tuner_priv;
-+	int                pos, rc;
-+	unsigned char	   *p;
-+
-+	tuner_dbg("%s called\n", __FUNCTION__);
+ 	int                        users;
+ 
+ 	/* various device info */
+-	struct video_device        vfd;
++	struct video_device        *vfd;
+ 
+ 	struct vivi_dmaqueue       vidq;
+ 
+ 	/* Several counters */
+-	int                        h,m,s,us,jiffies;
++	int                        h, m, s, ms;
++	unsigned long              jiffies;
+ 	char                       timestr[13];
 +
-+	if (!int_freq) {
-+		pos = seek_firmware(fe, type, id);
-+		if (pos < 0)
-+			return pos;
-+	} else {
-+		for (pos = 0; pos < priv->firm_size; pos++) {
-+			if ((priv->firm[pos].int_freq == int_freq) &&
-+			    (priv->firm[pos].type & HAS_IF))
++	int			   mv_count;	/* Controls bars movement */
+ };
+ 
+ struct vivi_fh {
+@@ -184,7 +185,7 @@ struct vivi_fh {
+ 
+ 	/* video capture */
+ 	struct vivi_fmt            *fmt;
+-	unsigned int               width,height;
++	unsigned int               width, height;
+ 	struct videobuf_queue      vb_vidq;
+ 
+ 	enum v4l2_buf_type         type;
+@@ -203,109 +204,113 @@ enum colors {
+ 	GREEN,
+ 	MAGENTA,
+ 	RED,
+-	BLUE
++	BLUE,
++	BLACK,
+ };
+ 
+ static u8 bars[8][3] = {
+ 	/* R   G   B */
+-	{204,204,204},	/* white */
+-	{208,208,  0},  /* ambar */
+-	{  0,206,206},  /* cyan */
+-	{  0,239,  0},  /* green */
+-	{239,  0,239},  /* magenta */
+-	{205,  0,  0},  /* red */
+-	{  0,  0,255},  /* blue */
+-	{  0,  0,  0}
++	{204, 204, 204},  /* white */
++	{208, 208,   0},  /* ambar */
++	{  0, 206, 206},  /* cyan */
++	{  0, 239,   0},  /* green */
++	{239,   0, 239},  /* magenta */
++	{205,   0,   0},  /* red */
++	{  0,   0, 255},  /* blue */
++	{  0,   0,   0},  /* black */
+ };
+ 
+-#define TO_Y(r,g,b) (((16829*r +33039*g +6416*b  + 32768)>>16)+16)
++#define TO_Y(r, g, b) \
++	(((16829 * r + 33039 * g + 6416 * b  + 32768) >> 16) + 16)
+ /* RGB to  V(Cr) Color transform */
+-#define TO_V(r,g,b) (((28784*r -24103*g -4681*b  + 32768)>>16)+128)
++#define TO_V(r, g, b) \
++	(((28784 * r - 24103 * g - 4681 * b  + 32768) >> 16) + 128)
+ /* RGB to  U(Cb) Color transform */
+-#define TO_U(r,g,b) (((-9714*r -19070*g +28784*b + 32768)>>16)+128)
++#define TO_U(r, g, b) \
++	(((-9714 * r - 19070 * g + 28784 * b + 32768) >> 16) + 128)
+ 
+ #define TSTAMP_MIN_Y 24
+ #define TSTAMP_MAX_Y TSTAMP_MIN_Y+15
+ #define TSTAMP_MIN_X 64
+ 
+-static void gen_line(char *basep,int inipos,int wmax,
+-		     int hmax, int line, int count, char *timestr)
++static void gen_line(char *basep, int inipos, int wmax,
++		int hmax, int line, int count, char *timestr)
+ {
+-	int  w,i,j,pos=inipos,y;
+-	char *p,*s;
+-	u8   chr,r,g,b,color;
++	int  w, i, j, y;
++	int pos = inipos;
++	char *p, *s;
++	u8   chr, r, g, b, color;
+ 
+ 	/* We will just duplicate the second pixel at the packet */
+-	wmax/=2;
++	wmax /= 2;
+ 
+ 	/* Generate a standard color bar pattern */
+-	for (w=0;w<wmax;w++) {
+-		int colorpos=((w+count)*8/(wmax+1)) % 8;
+-		r=bars[colorpos][0];
+-		g=bars[colorpos][1];
+-		b=bars[colorpos][2];
++	for (w = 0; w < wmax; w++) {
++		int colorpos = ((w + count) * 8/(wmax + 1)) % 8;
++		r = bars[colorpos][0];
++		g = bars[colorpos][1];
++		b = bars[colorpos][2];
+ 
+-		for (color=0;color<4;color++) {
+-			p=basep+pos;
++		for (color = 0; color < 4; color++) {
++			p = basep + pos;
+ 
+ 			switch (color) {
+-				case 0:
+-				case 2:
+-					*p=TO_Y(r,g,b);		/* Luminance */
+-					break;
+-				case 1:
+-					*p=TO_U(r,g,b);		/* Cb */
+-					break;
+-				case 3:
+-					*p=TO_V(r,g,b);		/* Cr */
+-					break;
++			case 0:
++			case 2:
++				*p = TO_Y(r, g, b);	/* Luma */
 +				break;
-+		}
-+		if (pos == priv->firm_size)
-+			return -ENOENT;
-+	}
-+
-+	p = priv->firm[pos].ptr;
++			case 1:
++				*p = TO_U(r, g, b);	/* Cb */
++				break;
++			case 3:
++				*p = TO_V(r, g, b);	/* Cr */
++				break;
+ 			}
+ 			pos++;
+ 		}
+ 	}
+ 
+ 	/* Checks if it is possible to show timestamp */
+-	if (TSTAMP_MAX_Y>=hmax)
++	if (TSTAMP_MAX_Y >= hmax)
+ 		goto end;
+-	if (TSTAMP_MIN_X+strlen(timestr)>=wmax)
++	if (TSTAMP_MIN_X + strlen(timestr) >= wmax)
+ 		goto end;
+ 
+ 	/* Print stream time */
+-	if (line>=TSTAMP_MIN_Y && line<=TSTAMP_MAX_Y) {
+-		j=TSTAMP_MIN_X;
+-		for (s=timestr;*s;s++) {
+-			chr=rom8x16_bits[(*s-0x30)*16+line-TSTAMP_MIN_Y];
+-			for (i=0;i<7;i++) {
+-				if (chr&1<<(7-i)) { /* Font color*/
+-					r=bars[BLUE][0];
+-					g=bars[BLUE][1];
+-					b=bars[BLUE][2];
+-					r=g=b=0;
+-					g=198;
+-				} else { /* Background color */
+-					r=bars[WHITE][0];
+-					g=bars[WHITE][1];
+-					b=bars[WHITE][2];
+-					r=g=b=0;
++	if (line >= TSTAMP_MIN_Y && line <= TSTAMP_MAX_Y) {
++		j = TSTAMP_MIN_X;
++		for (s = timestr; *s; s++) {
++			chr = rom8x16_bits[(*s-0x30)*16+line-TSTAMP_MIN_Y];
++			for (i = 0; i < 7; i++) {
++				if (chr & 1 << (7 - i)) {
++					/* Font color*/
++					r = 0;
++					g = 198;
++					b = 0;
++				} else {
++					/* Background color */
++					r = bars[BLACK][0];
++					g = bars[BLACK][1];
++					b = bars[BLACK][2];
+ 				}
+ 
+-				pos=inipos+j*2;
+-				for (color=0;color<4;color++) {
+-					p=basep+pos;
++				pos = inipos + j * 2;
++				for (color = 0; color < 4; color++) {
++					p = basep + pos;
+ 
+-					y=TO_Y(r,g,b);
++					y = TO_Y(r, g, b);
+ 
+ 					switch (color) {
+-						case 0:
+-						case 2:
+-							*p=TO_Y(r,g,b);		/* Luminance */
+-							break;
+-						case 1:
+-							*p=TO_U(r,g,b);		/* Cb */
+-							break;
+-						case 3:
+-							*p=TO_V(r,g,b);		/* Cr */
+-							break;
++					case 0:
++					case 2:
++						*p = TO_Y(r, g, b); /* Luma */
++						break;
++					case 1:
++						*p = TO_U(r, g, b); /* Cb */
++						break;
++					case 3:
++						*p = TO_V(r, g, b); /* Cr */
++						break;
+ 					}
+ 					pos++;
+ 				}
+@@ -314,63 +319,60 @@ static void gen_line(char *basep,int inipos,int wmax,
+ 		}
+ 	}
+ 
+-
+ end:
+ 	return;
+ }
+-static void vivi_fillbuff(struct vivi_dev *dev,struct vivi_buffer *buf)
++static void vivi_fillbuff(struct vivi_dev *dev, struct vivi_buffer *buf)
+ {
+-	int h,pos=0;
++	int h , pos = 0;
+ 	int hmax  = buf->vb.height;
+ 	int wmax  = buf->vb.width;
+ 	struct timeval ts;
+-	char *tmpbuf = kmalloc(wmax*2,GFP_KERNEL);
+-	void *vbuf=videobuf_to_vmalloc (&buf->vb);
+-	/* FIXME: move to dev struct */
+-	static int mv_count=0;
++	char *tmpbuf = kmalloc(wmax * 2, GFP_KERNEL);
++	void *vbuf = videobuf_to_vmalloc(&buf->vb);
+ 
+ 	if (!tmpbuf)
+ 		return;
+ 
+-	for (h=0;h<hmax;h++) {
+-		gen_line(tmpbuf,0,wmax,hmax,h,mv_count,
++	for (h = 0; h < hmax; h++) {
++		gen_line(tmpbuf, 0, wmax, hmax, h, dev->mv_count,
+ 			 dev->timestr);
+ 		/* FIXME: replacing to __copy_to_user */
+-		if (copy_to_user(vbuf+pos,tmpbuf,wmax*2)!=0)
+-			dprintk(2,"vivifill copy_to_user failed.\n");
++		if (copy_to_user(vbuf + pos, tmpbuf, wmax * 2) != 0)
++			dprintk(dev, 2, "vivifill copy_to_user failed.\n");
+ 		pos += wmax*2;
+ 	}
+ 
+-	mv_count++;
++	dev->mv_count++;
+ 
+ 	kfree(tmpbuf);
+ 
+ 	/* Updates stream time */
+ 
+-	dev->us+=jiffies_to_usecs(jiffies-dev->jiffies);
+-	dev->jiffies=jiffies;
+-	if (dev->us>=1000000) {
+-		dev->us-=1000000;
++	dev->ms += jiffies_to_msecs(jiffies-dev->jiffies);
++	dev->jiffies = jiffies;
++	if (dev->ms >= 1000) {
++		dev->ms -= 1000;
+ 		dev->s++;
+-		if (dev->s>=60) {
+-			dev->s-=60;
++		if (dev->s >= 60) {
++			dev->s -= 60;
+ 			dev->m++;
+-			if (dev->m>60) {
+-				dev->m-=60;
++			if (dev->m > 60) {
++				dev->m -= 60;
+ 				dev->h++;
+-				if (dev->h>24)
+-					dev->h-=24;
++				if (dev->h > 24)
++					dev->h -= 24;
+ 			}
+ 		}
+ 	}
+-	sprintf(dev->timestr,"%02d:%02d:%02d:%03d",
+-			dev->h,dev->m,dev->s,(dev->us+500)/1000);
++	sprintf(dev->timestr, "%02d:%02d:%02d:%03d",
++			dev->h, dev->m, dev->s, dev->ms);
+ 
+-	dprintk(2,"vivifill at %s: Buffer 0x%08lx size= %d\n",dev->timestr,
+-			(unsigned long)tmpbuf,pos);
++	dprintk(dev, 2, "vivifill at %s: Buffer 0x%08lx size= %d\n",
++			dev->timestr, (unsigned long)tmpbuf, pos);
+ 
+ 	/* Advice that buffer was filled */
+-	buf->vb.state = STATE_DONE;
++	buf->vb.state = VIDEOBUF_DONE;
+ 	buf->vb.field_count++;
+ 	do_gettimeofday(&ts);
+ 	buf->vb.ts = ts;
+@@ -384,14 +386,15 @@ static int restart_video_queue(struct vivi_dmaqueue *dma_q);
+ static void vivi_thread_tick(struct vivi_dmaqueue  *dma_q)
+ {
+ 	struct vivi_buffer    *buf;
+-	struct vivi_dev *dev= container_of(dma_q,struct vivi_dev,vidq);
++	struct vivi_dev *dev = container_of(dma_q, struct vivi_dev, vidq);
+ 
+ 	int bc;
+ 
++	spin_lock(&dev->slock);
+ 	/* Announces videobuf that all went ok */
+ 	for (bc = 0;; bc++) {
+ 		if (list_empty(&dma_q->active)) {
+-			dprintk(1,"No active queue to serve\n");
++			dprintk(dev, 1, "No active queue to serve\n");
+ 			break;
+ 		}
+ 
+@@ -401,65 +404,89 @@ static void vivi_thread_tick(struct vivi_dmaqueue  *dma_q)
+ 		/* Nobody is waiting something to be done, just return */
+ 		if (!waitqueue_active(&buf->vb.done)) {
+ 			mod_timer(&dma_q->timeout, jiffies+BUFFER_TIMEOUT);
++			spin_unlock(&dev->slock);
+ 			return;
+ 		}
+ 
+ 		do_gettimeofday(&buf->vb.ts);
+-		dprintk(2,"[%p/%d] wakeup\n",buf,buf->vb.i);
++		dprintk(dev, 2, "[%p/%d] wakeup\n", buf, buf->vb. i);
+ 
+ 		/* Fill buffer */
+-		vivi_fillbuff(dev,buf);
++		vivi_fillbuff(dev, buf);
+ 
+ 		if (list_empty(&dma_q->active)) {
+ 			del_timer(&dma_q->timeout);
+ 		} else {
+-			mod_timer(&dma_q->timeout, jiffies+BUFFER_TIMEOUT);
++			mod_timer(&dma_q->timeout, jiffies + BUFFER_TIMEOUT);
+ 		}
+ 	}
+ 	if (bc != 1)
+-		dprintk(1,"%s: %d buffers handled (should be 1)\n",__FUNCTION__,bc);
++		dprintk(dev, 1, "%s: %d buffers handled (should be 1)\n",
++			__FUNCTION__, bc);
++	spin_unlock(&dev->slock);
+ }
+ 
++#define frames_to_ms(frames)					\
++	((frames * WAKE_NUMERATOR * 1000) / WAKE_DENOMINATOR)
 +
-+	if (priv->firm[pos].type & HAS_IF) {
-+		if (priv->firm[pos].size != 12 * 16 || scode >= 16)
-+			return -EINVAL;
-+		p += 12 * scode;
-+	} else {
-+		/* 16 SCODE entries per file; each SCODE entry is 12 bytes and
-+		 * has a 2-byte size header in the firmware format. */
-+		if (priv->firm[pos].size != 14 * 16 || scode >= 16 ||
-+		    le16_to_cpu(*(__u16 *)(p + 14 * scode)) != 12)
-+			return -EINVAL;
-+		p += 14 * scode + 2;
-+	}
+ static void vivi_sleep(struct vivi_dmaqueue  *dma_q)
+ {
+-	int timeout;
++	struct vivi_dev *dev = container_of(dma_q, struct vivi_dev, vidq);
++	int timeout, running_time;
+ 	DECLARE_WAITQUEUE(wait, current);
+ 
+-	dprintk(1,"%s dma_q=0x%08lx\n",__FUNCTION__,(unsigned long)dma_q);
++	dprintk(dev, 1, "%s dma_q=0x%08lx\n", __FUNCTION__,
++		(unsigned long)dma_q);
+ 
+ 	add_wait_queue(&dma_q->wq, &wait);
+-	if (!kthread_should_stop()) {
+-		dma_q->frame++;
++	if (kthread_should_stop())
++		goto stop_task;
+ 
+-		/* Calculate time to wake up */
+-		timeout=dma_q->ini_jiffies+msecs_to_jiffies((dma_q->frame*WAKE_NUMERATOR*1000)/WAKE_DENOMINATOR)-jiffies;
++	running_time = jiffies - dma_q->ini_jiffies;
++	dma_q->frame++;
+ 
+-		if (timeout <= 0) {
+-			int old=dma_q->frame;
+-			dma_q->frame=(jiffies_to_msecs(jiffies-dma_q->ini_jiffies)*WAKE_DENOMINATOR)/(WAKE_NUMERATOR*1000)+1;
++	/* Calculate time to wake up */
++	timeout = msecs_to_jiffies(frames_to_ms(dma_q->frame)) - running_time;
+ 
+-			timeout=dma_q->ini_jiffies+msecs_to_jiffies((dma_q->frame*WAKE_NUMERATOR*1000)/WAKE_DENOMINATOR)-jiffies;
++	if (timeout > msecs_to_jiffies(frames_to_ms(2)) || timeout <= 0) {
++		int old = dma_q->frame;
++		int nframes;
+ 
+-			dprintk(1,"underrun, losed %d frames. "
+-				  "Now, frame is %d. Waking on %d jiffies\n",
+-					dma_q->frame-old,dma_q->frame,timeout);
+-		} else
+-			dprintk(1,"will sleep for %i jiffies\n",timeout);
++		dma_q->frame = (jiffies_to_msecs(running_time) /
++			       frames_to_ms(1)) + 1;
+ 
+-		vivi_thread_tick(dma_q);
++		timeout = msecs_to_jiffies(frames_to_ms(dma_q->frame))
++			  - running_time;
+ 
+-		schedule_timeout_interruptible (timeout);
+-	}
++		if (unlikely (timeout <= 0))
++			timeout = 1;
 +
-+	tuner_info("Loading SCODE for type=");
-+	dump_firm_type_and_int_freq(priv->firm[pos].type,
-+				    priv->firm[pos].int_freq);
-+	printk("(%x), id %016llx.\n", priv->firm[pos].type,
-+	       (unsigned long long)*id);
++		nframes = (dma_q->frame > old)?
++				  dma_q->frame - old : old - dma_q->frame;
 +
-+	if (priv->firm_version < 0x0202)
-+		rc = send_seq(priv, {0x20, 0x00, 0x00, 0x00});
-+	else
-+		rc = send_seq(priv, {0xa0, 0x00, 0x00, 0x00});
-+	if (rc < 0)
-+		return -EIO;
++		dprintk(dev, 1, "%ld: %s %d frames. "
++			"Current frame is %d. Will sleep for %d jiffies\n",
++			jiffies,
++			(dma_q->frame > old)? "Underrun, losed" : "Overrun of",
++			nframes, dma_q->frame, timeout);
++	} else
++		dprintk(dev, 1, "will sleep for %d jiffies\n", timeout);
+ 
++	vivi_thread_tick(dma_q);
 +
-+	rc = i2c_send(priv, p, 12);
-+	if (rc < 0)
-+		return -EIO;
++	schedule_timeout_interruptible(timeout);
 +
-+	rc = send_seq(priv, {0x00, 0x8c});
-+	if (rc < 0)
-+		return -EIO;
++stop_task:
+ 	remove_wait_queue(&dma_q->wq, &wait);
+ 	try_to_freeze();
+ }
+ 
+ static int vivi_thread(void *data)
+ {
+-	struct vivi_dmaqueue  *dma_q=data;
++	struct vivi_dmaqueue  *dma_q = data;
++	struct vivi_dev *dev = container_of(dma_q, struct vivi_dev, vidq);
+ 
+-	dprintk(1,"thread started\n");
++	dprintk(dev, 1, "thread started\n");
+ 
+ 	mod_timer(&dma_q->timeout, jiffies+BUFFER_TIMEOUT);
+ 	set_freezable();
+@@ -470,16 +497,18 @@ static int vivi_thread(void *data)
+ 		if (kthread_should_stop())
+ 			break;
+ 	}
+-	dprintk(1, "thread: exit\n");
++	dprintk(dev, 1, "thread: exit\n");
+ 	return 0;
+ }
+ 
+ static int vivi_start_thread(struct vivi_dmaqueue  *dma_q)
+ {
+-	dma_q->frame=0;
+-	dma_q->ini_jiffies=jiffies;
++	struct vivi_dev *dev = container_of(dma_q, struct vivi_dev, vidq);
+ 
+-	dprintk(1,"%s\n",__FUNCTION__);
++	dma_q->frame = 0;
++	dma_q->ini_jiffies = jiffies;
 +
-+	return 0;
-+}
++	dprintk(dev, 1, "%s\n", __FUNCTION__);
+ 
+ 	dma_q->kthread = kthread_run(vivi_thread, dma_q, "vivi");
+ 
+@@ -490,39 +519,43 @@ static int vivi_start_thread(struct vivi_dmaqueue  *dma_q)
+ 	/* Wakes thread */
+ 	wake_up_interruptible(&dma_q->wq);
+ 
+-	dprintk(1,"returning from %s\n",__FUNCTION__);
++	dprintk(dev, 1, "returning from %s\n", __FUNCTION__);
+ 	return 0;
+ }
+ 
+ static void vivi_stop_thread(struct vivi_dmaqueue  *dma_q)
+ {
+-	dprintk(1,"%s\n",__FUNCTION__);
++	struct vivi_dev *dev = container_of(dma_q, struct vivi_dev, vidq);
 +
-+static int check_firmware(struct dvb_frontend *fe, unsigned int type,
-+			  v4l2_std_id std, __u16 int_freq)
-+{
-+	struct xc2028_data         *priv = fe->tuner_priv;
-+	struct firmware_properties new_fw;
-+	int			   rc = 0, is_retry = 0;
-+	u16			   version, hwmodel;
-+	v4l2_std_id		   std0;
++	dprintk(dev, 1, "%s\n", __FUNCTION__);
+ 	/* shutdown control thread */
+ 	if (dma_q->kthread) {
+ 		kthread_stop(dma_q->kthread);
+-		dma_q->kthread=NULL;
++		dma_q->kthread = NULL;
+ 	}
+ }
+ 
+ static int restart_video_queue(struct vivi_dmaqueue *dma_q)
+ {
++	struct vivi_dev *dev = container_of(dma_q, struct vivi_dev, vidq);
+ 	struct vivi_buffer *buf, *prev;
+ 
+-	dprintk(1,"%s dma_q=0x%08lx\n",__FUNCTION__,(unsigned long)dma_q);
++	dprintk(dev, 1, "%s dma_q=0x%08lx\n", __FUNCTION__,
++		(unsigned long)dma_q);
+ 
+ 	if (!list_empty(&dma_q->active)) {
+-		buf = list_entry(dma_q->active.next, struct vivi_buffer, vb.queue);
+-		dprintk(2,"restart_queue [%p/%d]: restart dma\n",
++		buf = list_entry(dma_q->active.next,
++				 struct vivi_buffer, vb.queue);
++		dprintk(dev, 2, "restart_queue [%p/%d]: restart dma\n",
+ 			buf, buf->vb.i);
+ 
+-		dprintk(1,"Restarting video dma\n");
++		dprintk(dev, 1, "Restarting video dma\n");
+ 		vivi_stop_thread(dma_q);
+-//		vivi_start_thread(dma_q);
+ 
+ 		/* cancel all outstanding capture / vbi requests */
+ 		list_for_each_entry_safe(buf, prev, &dma_q->active, vb.queue) {
+ 			list_del(&buf->vb.queue);
+-			buf->vb.state = STATE_ERROR;
++			buf->vb.state = VIDEOBUF_ERROR;
+ 			wake_up(&buf->vb.done);
+ 		}
+ 		mod_timer(&dma_q->timeout, jiffies+BUFFER_TIMEOUT);
+@@ -534,28 +567,31 @@ static int restart_video_queue(struct vivi_dmaqueue *dma_q)
+ 	for (;;) {
+ 		if (list_empty(&dma_q->queued))
+ 			return 0;
+-		buf = list_entry(dma_q->queued.next, struct vivi_buffer, vb.queue);
++		buf = list_entry(dma_q->queued.next,
++				 struct vivi_buffer, vb.queue);
+ 		if (NULL == prev) {
+ 			list_del(&buf->vb.queue);
+-			list_add_tail(&buf->vb.queue,&dma_q->active);
++			list_add_tail(&buf->vb.queue, &dma_q->active);
+ 
+-			dprintk(1,"Restarting video dma\n");
++			dprintk(dev, 1, "Restarting video dma\n");
+ 			vivi_stop_thread(dma_q);
+ 			vivi_start_thread(dma_q);
+ 
+-			buf->vb.state = STATE_ACTIVE;
++			buf->vb.state = VIDEOBUF_ACTIVE;
+ 			mod_timer(&dma_q->timeout, jiffies+BUFFER_TIMEOUT);
+-			dprintk(2,"[%p/%d] restart_queue - first active\n",
+-				buf,buf->vb.i);
++			dprintk(dev, 2,
++				"[%p/%d] restart_queue - first active\n",
++				buf, buf->vb.i);
+ 
+ 		} else if (prev->vb.width  == buf->vb.width  &&
+ 			   prev->vb.height == buf->vb.height &&
+ 			   prev->fmt       == buf->fmt) {
+ 			list_del(&buf->vb.queue);
+-			list_add_tail(&buf->vb.queue,&dma_q->active);
+-			buf->vb.state = STATE_ACTIVE;
+-			dprintk(2,"[%p/%d] restart_queue - move to active\n",
+-				buf,buf->vb.i);
++			list_add_tail(&buf->vb.queue, &dma_q->active);
++			buf->vb.state = VIDEOBUF_ACTIVE;
++			dprintk(dev, 2,
++				"[%p/%d] restart_queue - move to active\n",
++				buf, buf->vb.i);
+ 		} else {
+ 			return 0;
+ 		}
+@@ -565,19 +601,23 @@ static int restart_video_queue(struct vivi_dmaqueue *dma_q)
+ 
+ static void vivi_vid_timeout(unsigned long data)
+ {
+-	struct vivi_dev      *dev  = (struct vivi_dev*)data;
++	struct vivi_dev      *dev  = (struct vivi_dev *)data;
+ 	struct vivi_dmaqueue *vidq = &dev->vidq;
+ 	struct vivi_buffer   *buf;
+ 
++	spin_lock(&dev->slock);
 +
-+	tuner_dbg("%s called\n", __FUNCTION__);
+ 	while (!list_empty(&vidq->active)) {
+-		buf = list_entry(vidq->active.next, struct vivi_buffer, vb.queue);
++		buf = list_entry(vidq->active.next,
++				 struct vivi_buffer, vb.queue);
+ 		list_del(&buf->vb.queue);
+-		buf->vb.state = STATE_ERROR;
++		buf->vb.state = VIDEOBUF_ERROR;
+ 		wake_up(&buf->vb.done);
+-		printk("vivi/0: [%p/%d] timeout\n", buf, buf->vb.i);
++		printk(KERN_INFO "vivi/0: [%p/%d] timeout\n", buf, buf->vb.i);
+ 	}
+-
+ 	restart_video_queue(vidq);
 +
-+	if (!priv->firm) {
-+		if (!priv->ctrl.fname) {
-+			tuner_info("xc2028/3028 firmware name not set!\n");
-+			return -EINVAL;
-+		}
++	spin_unlock(&dev->slock);
+ }
+ 
+ /* ------------------------------------------------------------------
+@@ -586,7 +626,8 @@ static void vivi_vid_timeout(unsigned long data)
+ static int
+ buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size)
+ {
+-	struct vivi_fh *fh = vq->priv_data;
++	struct vivi_fh  *fh = vq->priv_data;
++	struct vivi_dev *dev  = fh->dev;
+ 
+ 	*size = fh->width*fh->height*2;
+ 
+@@ -596,21 +637,25 @@ buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size)
+ 	while (*size * *count > vid_limit * 1024 * 1024)
+ 		(*count)--;
+ 
+-	dprintk(1,"%s, count=%d, size=%d\n",__FUNCTION__,*count, *size);
++	dprintk(dev, 1, "%s, count=%d, size=%d\n", __FUNCTION__,
++		*count, *size);
+ 
+ 	return 0;
+ }
+ 
+ static void free_buffer(struct videobuf_queue *vq, struct vivi_buffer *buf)
+ {
+-	dprintk(1,"%s\n",__FUNCTION__);
++	struct vivi_fh  *fh = vq->priv_data;
++	struct vivi_dev *dev  = fh->dev;
 +
-+		rc = load_all_firmwares(fe);
++	dprintk(dev, 1, "%s\n", __FUNCTION__);
+ 
+ 	if (in_interrupt())
+ 		BUG();
+ 
+-	videobuf_waiton(&buf->vb,0,0);
++	videobuf_waiton(&buf->vb, 0, 0);
+ 	videobuf_vmalloc_free(&buf->vb);
+-	buf->vb.state = STATE_NEEDS_INIT;
++	buf->vb.state = VIDEOBUF_NEEDS_INIT;
+ }
+ 
+ #define norm_maxw() 1024
+@@ -620,10 +665,11 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
+ 						enum v4l2_field field)
+ {
+ 	struct vivi_fh     *fh  = vq->priv_data;
+-	struct vivi_buffer *buf = container_of(vb,struct vivi_buffer,vb);
++	struct vivi_dev    *dev = fh->dev;
++	struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb);
+ 	int rc, init_buffer = 0;
+ 
+-	dprintk(1,"%s, field=%d\n",__FUNCTION__,field);
++	dprintk(dev, 1, "%s, field=%d\n", __FUNCTION__, field);
+ 
+ 	BUG_ON(NULL == fh->fmt);
+ 	if (fh->width  < 48 || fh->width  > norm_maxw() ||
+@@ -644,75 +690,81 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
+ 		init_buffer = 1;
+ 	}
+ 
+-	if (STATE_NEEDS_INIT == buf->vb.state) {
+-		if (0 != (rc = videobuf_iolock(vq,&buf->vb,NULL)))
++	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
++		rc = videobuf_iolock(vq, &buf->vb, NULL);
 +		if (rc < 0)
-+			return rc;
-+	}
-+
-+	if (priv->ctrl.mts && !(type & FM))
-+		type |= MTS;
-+
-+retry:
-+	new_fw.type = type;
-+	new_fw.id = std;
-+	new_fw.std_req = std;
-+	new_fw.scode_table = SCODE | priv->ctrl.scode_table;
-+	new_fw.scode_nr = 0;
-+	new_fw.int_freq = int_freq;
-+
-+	tuner_dbg("checking firmware, user requested type=");
-+	if (debug) {
-+		dump_firm_type(new_fw.type);
-+		printk("(%x), id %016llx, ", new_fw.type,
-+		       (unsigned long long)new_fw.std_req);
-+		if (!int_freq) {
-+			printk("scode_tbl ");
-+			dump_firm_type(priv->ctrl.scode_table);
-+			printk("(%x), ", priv->ctrl.scode_table);
-+		} else
-+			printk("int_freq %d, ", new_fw.int_freq);
-+		printk("scode_nr %d\n", new_fw.scode_nr);
-+	}
-+
-+	/* No need to reload base firmware if it matches */
-+	if (((BASE | new_fw.type) & BASE_TYPES) ==
-+	    (priv->cur_fw.type & BASE_TYPES)) {
-+		tuner_dbg("BASE firmware not changed.\n");
-+		goto skip_base;
-+	}
-+
-+	/* Updating BASE - forget about all currently loaded firmware */
-+	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);
-+	if (rc < 0)
-+		goto fail;
-+
-+	/* BASE firmwares are all std0 */
-+	std0 = 0;
-+	rc = load_firmware(fe, BASE | new_fw.type, &std0);
-+	if (rc < 0) {
-+		tuner_err("Error %d while loading base firmware\n",
-+			  rc);
-+		goto fail;
-+	}
-+
-+	/* Load INIT1, if needed */
-+	tuner_dbg("Load init1 firmware, if exists\n");
-+
-+	rc = load_firmware(fe, BASE | INIT1 | new_fw.type, &std0);
-+	if (rc == -ENOENT)
-+		rc = load_firmware(fe, (BASE | INIT1 | new_fw.type) & ~F8MHZ,
-+				   &std0);
-+	if (rc < 0 && rc != -ENOENT) {
-+		tuner_err("Error %d while loading init1 firmware\n",
-+			  rc);
-+		goto fail;
-+	}
-+
-+skip_base:
-+	/*
-+	 * No need to reload standard specific firmware if base firmware
-+	 * was not reloaded and requested video standards have not changed.
-+	 */
-+	if (priv->cur_fw.type == (BASE | new_fw.type) &&
-+	    priv->cur_fw.std_req == std) {
-+		tuner_dbg("Std-specific firmware already loaded.\n");
-+		goto skip_std_specific;
-+	}
-+
-+	/* Reloading std-specific firmware forces a SCODE update */
-+	priv->cur_fw.scode_table = 0;
-+
-+	rc = load_firmware(fe, new_fw.type, &new_fw.id);
-+	if (rc == -ENOENT)
-+		rc = load_firmware(fe, new_fw.type & ~F8MHZ, &new_fw.id);
-+
-+	if (rc < 0)
-+		goto fail;
-+
-+skip_std_specific:
-+	if (priv->cur_fw.scode_table == new_fw.scode_table &&
-+	    priv->cur_fw.scode_nr == new_fw.scode_nr) {
-+		tuner_dbg("SCODE firmware already loaded.\n");
-+		goto check_device;
-+	}
-+
-+	/* Load SCODE firmware, if exists */
-+	tuner_dbg("Trying to load scode %d\n", new_fw.scode_nr);
-+
-+	rc = load_scode(fe, new_fw.type | new_fw.scode_table, &new_fw.id,
-+			new_fw.int_freq, new_fw.scode_nr);
-+
-+check_device:
-+	if (xc2028_get_reg(priv, 0x0004, &version) < 0 ||
-+	    xc2028_get_reg(priv, 0x0008, &hwmodel) < 0) {
-+		tuner_err("Unable to read tuner registers.\n");
-+		goto fail;
-+	}
+ 			goto fail;
+ 	}
+ 
+-	buf->vb.state = STATE_PREPARED;
++	buf->vb.state = VIDEOBUF_PREPARED;
+ 
+ 	return 0;
+ 
+ fail:
+-	free_buffer(vq,buf);
++	free_buffer(vq, buf);
+ 	return rc;
+ }
+ 
+ static void
+ buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+ {
+-	struct vivi_buffer    *buf     = container_of(vb,struct vivi_buffer,vb);
+-	struct vivi_fh        *fh      = vq->priv_data;
+-	struct vivi_dev       *dev     = fh->dev;
+-	struct vivi_dmaqueue  *vidq    = &dev->vidq;
++	struct vivi_buffer    *buf  = container_of(vb, struct vivi_buffer, vb);
++	struct vivi_fh        *fh   = vq->priv_data;
++	struct vivi_dev       *dev  = fh->dev;
++	struct vivi_dmaqueue  *vidq = &dev->vidq;
+ 	struct vivi_buffer    *prev;
+ 
+ 	if (!list_empty(&vidq->queued)) {
+-		dprintk(1,"adding vb queue=0x%08lx\n",(unsigned long)&buf->vb.queue);
+-		list_add_tail(&buf->vb.queue,&vidq->queued);
+-		buf->vb.state = STATE_QUEUED;
+-		dprintk(2,"[%p/%d] buffer_queue - append to queued\n",
++		dprintk(dev, 1, "adding vb queue=0x%08lx\n",
++			(unsigned long)&buf->vb.queue);
++		list_add_tail(&buf->vb.queue, &vidq->queued);
++		buf->vb.state = VIDEOBUF_QUEUED;
++		dprintk(dev, 2, "[%p/%d] buffer_queue - append to queued\n",
+ 			buf, buf->vb.i);
+ 	} else if (list_empty(&vidq->active)) {
+-		list_add_tail(&buf->vb.queue,&vidq->active);
++		list_add_tail(&buf->vb.queue, &vidq->active);
+ 
+-		buf->vb.state = STATE_ACTIVE;
++		buf->vb.state = VIDEOBUF_ACTIVE;
+ 		mod_timer(&vidq->timeout, jiffies+BUFFER_TIMEOUT);
+-		dprintk(2,"[%p/%d] buffer_queue - first active\n",
++		dprintk(dev, 2, "[%p/%d] buffer_queue - first active\n",
+ 			buf, buf->vb.i);
+ 
+ 		vivi_start_thread(vidq);
+ 	} else {
+-		prev = list_entry(vidq->active.prev, struct vivi_buffer, vb.queue);
++		prev = list_entry(vidq->active.prev,
++				  struct vivi_buffer, vb.queue);
+ 		if (prev->vb.width  == buf->vb.width  &&
+ 		    prev->vb.height == buf->vb.height &&
+ 		    prev->fmt       == buf->fmt) {
+-			list_add_tail(&buf->vb.queue,&vidq->active);
+-			buf->vb.state = STATE_ACTIVE;
+-			dprintk(2,"[%p/%d] buffer_queue - append to active\n",
++			list_add_tail(&buf->vb.queue, &vidq->active);
++			buf->vb.state = VIDEOBUF_ACTIVE;
++			dprintk(dev, 2,
++				"[%p/%d] buffer_queue - append to active\n",
+ 				buf, buf->vb.i);
+ 
+ 		} else {
+-			list_add_tail(&buf->vb.queue,&vidq->queued);
+-			buf->vb.state = STATE_QUEUED;
+-			dprintk(2,"[%p/%d] buffer_queue - first queued\n",
++			list_add_tail(&buf->vb.queue, &vidq->queued);
++			buf->vb.state = VIDEOBUF_QUEUED;
++			dprintk(dev, 2,
++				"[%p/%d] buffer_queue - first queued\n",
+ 				buf, buf->vb.i);
+ 		}
+ 	}
+ }
+ 
+-static void buffer_release(struct videobuf_queue *vq, struct videobuf_buffer *vb)
++static void buffer_release(struct videobuf_queue *vq,
++			   struct videobuf_buffer *vb)
+ {
+-	struct vivi_buffer   *buf  = container_of(vb,struct vivi_buffer,vb);
++	struct vivi_buffer   *buf  = container_of(vb, struct vivi_buffer, vb);
+ 	struct vivi_fh       *fh   = vq->priv_data;
+-	struct vivi_dev      *dev  = (struct vivi_dev*)fh->dev;
++	struct vivi_dev      *dev  = (struct vivi_dev *)fh->dev;
+ 	struct vivi_dmaqueue *vidq = &dev->vidq;
+ 
+-	dprintk(1,"%s\n",__FUNCTION__);
++	dprintk(dev, 1, "%s\n", __FUNCTION__);
+ 
+ 	vivi_stop_thread(vidq);
+ 
+-	free_buffer(vq,buf);
++	free_buffer(vq, buf);
+ }
+ 
+ static struct videobuf_queue_ops vivi_video_qops = {
+@@ -725,7 +777,7 @@ static struct videobuf_queue_ops vivi_video_qops = {
+ /* ------------------------------------------------------------------
+ 	IOCTL vidioc handling
+    ------------------------------------------------------------------*/
+-static int vidioc_querycap (struct file *file, void  *priv,
++static int vidioc_querycap(struct file *file, void  *priv,
+ 					struct v4l2_capability *cap)
+ {
+ 	strcpy(cap->driver, "vivi");
+@@ -737,21 +789,21 @@ static int vidioc_querycap (struct file *file, void  *priv,
+ 	return 0;
+ }
+ 
+-static int vidioc_enum_fmt_cap (struct file *file, void  *priv,
++static int vidioc_enum_fmt_cap(struct file *file, void  *priv,
+ 					struct v4l2_fmtdesc *f)
+ {
+ 	if (f->index > 0)
+ 		return -EINVAL;
+ 
+-	strlcpy(f->description,format.name,sizeof(f->description));
++	strlcpy(f->description, format.name, sizeof(f->description));
+ 	f->pixelformat = format.fourcc;
+ 	return 0;
+ }
+ 
+-static int vidioc_g_fmt_cap (struct file *file, void *priv,
++static int vidioc_g_fmt_cap(struct file *file, void *priv,
+ 					struct v4l2_format *f)
+ {
+-	struct vivi_fh  *fh=priv;
++	struct vivi_fh *fh = priv;
+ 
+ 	f->fmt.pix.width        = fh->width;
+ 	f->fmt.pix.height       = fh->height;
+@@ -765,26 +817,29 @@ static int vidioc_g_fmt_cap (struct file *file, void *priv,
+ 	return (0);
+ }
+ 
+-static int vidioc_try_fmt_cap (struct file *file, void *priv,
++static int vidioc_try_fmt_cap(struct file *file, void *priv,
+ 			struct v4l2_format *f)
+ {
++	struct vivi_fh  *fh  = priv;
++	struct vivi_dev *dev = fh->dev;
+ 	struct vivi_fmt *fmt;
+ 	enum v4l2_field field;
+ 	unsigned int maxw, maxh;
+ 
+ 	if (format.fourcc != f->fmt.pix.pixelformat) {
+-		dprintk(1,"Fourcc format (0x%08x) invalid. Driver accepts "
+-			"only 0x%08x\n",f->fmt.pix.pixelformat,format.fourcc);
++		dprintk(dev, 1, "Fourcc format (0x%08x) invalid. "
++			"Driver accepts only 0x%08x\n",
++			f->fmt.pix.pixelformat, format.fourcc);
+ 		return -EINVAL;
+ 	}
+-	fmt=&format;
++	fmt = &format;
+ 
+ 	field = f->fmt.pix.field;
+ 
+ 	if (field == V4L2_FIELD_ANY) {
+-		field=V4L2_FIELD_INTERLACED;
++		field = V4L2_FIELD_INTERLACED;
+ 	} else if (V4L2_FIELD_INTERLACED != field) {
+-		dprintk(1,"Field type invalid.\n");
++		dprintk(dev, 1, "Field type invalid.\n");
+ 		return -EINVAL;
+ 	}
+ 
+@@ -810,11 +865,11 @@ static int vidioc_try_fmt_cap (struct file *file, void *priv,
+ }
+ 
+ /*FIXME: This seems to be generic enough to be at videodev2 */
+-static int vidioc_s_fmt_cap (struct file *file, void *priv,
++static int vidioc_s_fmt_cap(struct file *file, void *priv,
+ 					struct v4l2_format *f)
+ {
+-	struct vivi_fh  *fh=priv;
+-	int ret = vidioc_try_fmt_cap(file,fh,f);
++	struct vivi_fh  *fh = priv;
++	int ret = vidioc_try_fmt_cap(file, fh, f);
+ 	if (ret < 0)
+ 		return (ret);
+ 
+@@ -827,47 +882,48 @@ static int vidioc_s_fmt_cap (struct file *file, void *priv,
+ 	return (0);
+ }
+ 
+-static int vidioc_reqbufs (struct file *file, void *priv, struct v4l2_requestbuffers *p)
++static int vidioc_reqbufs(struct file *file, void *priv,
++			  struct v4l2_requestbuffers *p)
+ {
+-	struct vivi_fh  *fh=priv;
++	struct vivi_fh  *fh = priv;
+ 
+ 	return (videobuf_reqbufs(&fh->vb_vidq, p));
+ }
+ 
+-static int vidioc_querybuf (struct file *file, void *priv, struct v4l2_buffer *p)
++static int vidioc_querybuf(struct file *file, void *priv, struct v4l2_buffer *p)
+ {
+-	struct vivi_fh  *fh=priv;
++	struct vivi_fh  *fh = priv;
+ 
+ 	return (videobuf_querybuf(&fh->vb_vidq, p));
+ }
+ 
+-static int vidioc_qbuf (struct file *file, void *priv, struct v4l2_buffer *p)
++static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
+ {
+-	struct vivi_fh  *fh=priv;
++	struct vivi_fh *fh = priv;
+ 
+ 	return (videobuf_qbuf(&fh->vb_vidq, p));
+ }
+ 
+-static int vidioc_dqbuf (struct file *file, void *priv, struct v4l2_buffer *p)
++static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
+ {
+-	struct vivi_fh  *fh=priv;
++	struct vivi_fh  *fh = priv;
+ 
+ 	return (videobuf_dqbuf(&fh->vb_vidq, p,
+ 				file->f_flags & O_NONBLOCK));
+ }
+ 
+ #ifdef CONFIG_VIDEO_V4L1_COMPAT
+-static int vidiocgmbuf (struct file *file, void *priv, struct video_mbuf *mbuf)
++static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf)
+ {
+-	struct vivi_fh  *fh=priv;
++	struct vivi_fh  *fh = priv;
+ 
+-	return videobuf_cgmbuf (&fh->vb_vidq, mbuf, 8);
++	return videobuf_cgmbuf(&fh->vb_vidq, mbuf, 8);
+ }
+ #endif
+ 
+ static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
+ {
+-	struct vivi_fh  *fh=priv;
++	struct vivi_fh  *fh = priv;
+ 
+ 	if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ 		return -EINVAL;
+@@ -879,7 +935,7 @@ static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
+ 
+ static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
+ {
+-	struct vivi_fh  *fh=priv;
++	struct vivi_fh  *fh = priv;
+ 
+ 	if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ 		return -EINVAL;
+@@ -889,32 +945,32 @@ static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
+ 	return videobuf_streamoff(&fh->vb_vidq);
+ }
+ 
+-static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id *i)
++static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *i)
+ {
+ 	return 0;
+ }
+ 
+ /* only one input in this sample driver */
+-static int vidioc_enum_input (struct file *file, void *priv,
++static int vidioc_enum_input(struct file *file, void *priv,
+ 				struct v4l2_input *inp)
+ {
+ 	if (inp->index != 0)
+ 		return -EINVAL;
+ 
+ 	inp->type = V4L2_INPUT_TYPE_CAMERA;
+-	inp->std = V4L2_STD_NTSC_M;
+-	strcpy(inp->name,"Camera");
++	inp->std = V4L2_STD_525_60;
++	strcpy(inp->name, "Camera");
+ 
+ 	return (0);
+ }
+ 
+-static int vidioc_g_input (struct file *file, void *priv, unsigned int *i)
++static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
+ {
+ 	*i = 0;
+ 
+ 	return (0);
+ }
+-static int vidioc_s_input (struct file *file, void *priv, unsigned int i)
++static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
+ {
+ 	if (i > 0)
+ 		return -EINVAL;
+@@ -923,8 +979,8 @@ static int vidioc_s_input (struct file *file, void *priv, unsigned int i)
+ }
+ 
+ 	/* --- controls ---------------------------------------------- */
+-static int vidioc_queryctrl (struct file *file, void *priv,
+-				struct v4l2_queryctrl *qc)
++static int vidioc_queryctrl(struct file *file, void *priv,
++			    struct v4l2_queryctrl *qc)
+ {
+ 	int i;
+ 
+@@ -938,33 +994,31 @@ static int vidioc_queryctrl (struct file *file, void *priv,
+ 	return -EINVAL;
+ }
+ 
+-static int vidioc_g_ctrl (struct file *file, void *priv,
+-				struct v4l2_control *ctrl)
++static int vidioc_g_ctrl(struct file *file, void *priv,
++			 struct v4l2_control *ctrl)
+ {
+ 	int i;
+ 
+ 	for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++)
+ 		if (ctrl->id == vivi_qctrl[i].id) {
+-			ctrl->value=qctl_regs[i];
++			ctrl->value = qctl_regs[i];
+ 			return (0);
+ 		}
+ 
+ 	return -EINVAL;
+ }
+-static int vidioc_s_ctrl (struct file *file, void *priv,
++static int vidioc_s_ctrl(struct file *file, void *priv,
+ 				struct v4l2_control *ctrl)
+ {
+ 	int i;
+ 
+ 	for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++)
+ 		if (ctrl->id == vivi_qctrl[i].id) {
+-			if (ctrl->value <
+-				vivi_qctrl[i].minimum
+-				|| ctrl->value >
+-				vivi_qctrl[i].maximum) {
++			if (ctrl->value < vivi_qctrl[i].minimum
++			    || ctrl->value > vivi_qctrl[i].maximum) {
+ 					return (-ERANGE);
+ 				}
+-			qctl_regs[i]=ctrl->value;
++			qctl_regs[i] = ctrl->value;
+ 			return (0);
+ 		}
+ 	return -EINVAL;
+@@ -983,24 +1037,22 @@ static int vivi_open(struct inode *inode, struct file *file)
+ 	struct vivi_fh *fh;
+ 	int i;
+ 
+-	printk(KERN_DEBUG "vivi: open called (minor=%d)\n",minor);
++	printk(KERN_DEBUG "vivi: open called (minor=%d)\n", minor);
+ 
+ 	list_for_each_entry(dev, &vivi_devlist, vivi_devlist)
+-		if (dev->vfd.minor == minor)
++		if (dev->vfd->minor == minor)
+ 			goto found;
+ 	return -ENODEV;
+-found:
+-
+-
+ 
++found:
+ 	/* If more than one user, mutex should be added */
+ 	dev->users++;
+ 
+-	dprintk(1, "open minor=%d type=%s users=%d\n", minor,
++	dprintk(dev, 1, "open minor=%d type=%s users=%d\n", minor,
+ 		v4l2_type_names[V4L2_BUF_TYPE_VIDEO_CAPTURE], dev->users);
+ 
+ 	/* allocate + initialize per filehandle data */
+-	fh = kzalloc(sizeof(*fh),GFP_KERNEL);
++	fh = kzalloc(sizeof(*fh), GFP_KERNEL);
+ 	if (NULL == fh) {
+ 		dev->users--;
+ 		return -ENOMEM;
+@@ -1016,27 +1068,21 @@ found:
+ 
+ 	/* Put all controls at a sane state */
+ 	for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++)
+-		qctl_regs[i] =vivi_qctrl[i].default_value;
+-
+-	dprintk(1,"Open: fh=0x%08lx, dev=0x%08lx, dev->vidq=0x%08lx\n",
+-		(unsigned long)fh,(unsigned long)dev,(unsigned long)&dev->vidq);
+-	dprintk(1,"Open: list_empty queued=%d\n",list_empty(&dev->vidq.queued));
+-	dprintk(1,"Open: list_empty active=%d\n",list_empty(&dev->vidq.active));
++		qctl_regs[i] = vivi_qctrl[i].default_value;
+ 
+ 	/* Resets frame counters */
+-	dev->h=0;
+-	dev->m=0;
+-	dev->s=0;
+-	dev->us=0;
+-	dev->jiffies=jiffies;
+-	sprintf(dev->timestr,"%02d:%02d:%02d:%03d",
+-			dev->h,dev->m,dev->s,(dev->us+500)/1000);
++	dev->h = 0;
++	dev->m = 0;
++	dev->s = 0;
++	dev->ms = 0;
++	dev->mv_count = 0;
++	dev->jiffies = jiffies;
++	sprintf(dev->timestr, "%02d:%02d:%02d:%03d",
++			dev->h, dev->m, dev->s, dev->ms);
+ 
+ 	videobuf_queue_vmalloc_init(&fh->vb_vidq, &vivi_video_qops,
+-			NULL, NULL,
+-			fh->type,
+-			V4L2_FIELD_INTERLACED,
+-			sizeof(struct vivi_buffer),fh);
++			NULL, &dev->slock, fh->type, V4L2_FIELD_INTERLACED,
++			sizeof(struct vivi_buffer), fh);
+ 
+ 	return 0;
+ }
+@@ -1044,9 +1090,9 @@ found:
+ static ssize_t
+ vivi_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
+ {
+-	struct vivi_fh        *fh = file->private_data;
++	struct vivi_fh *fh = file->private_data;
+ 
+-	if (fh->type==V4L2_BUF_TYPE_VIDEO_CAPTURE) {
++	if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ 		return videobuf_read_stream(&fh->vb_vidq, data, count, ppos, 0,
+ 					file->f_flags & O_NONBLOCK);
+ 	}
+@@ -1057,9 +1103,10 @@ static unsigned int
+ vivi_poll(struct file *file, struct poll_table_struct *wait)
+ {
+ 	struct vivi_fh        *fh = file->private_data;
++	struct vivi_dev       *dev = fh->dev;
+ 	struct videobuf_queue *q = &fh->vb_vidq;
+ 
+-	dprintk(1,"%s\n",__FUNCTION__);
++	dprintk(dev, 1, "%s\n", __FUNCTION__);
+ 
+ 	if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type)
+ 		return POLLERR;
+@@ -1067,7 +1114,7 @@ vivi_poll(struct file *file, struct poll_table_struct *wait)
+ 	return videobuf_poll_stream(file, q, wait);
+ }
+ 
+-static int vivi_release(struct inode *inode, struct file *file)
++static int vivi_close(struct inode *inode, struct file *file)
+ {
+ 	struct vivi_fh         *fh = file->private_data;
+ 	struct vivi_dev *dev       = fh->dev;
+@@ -1079,26 +1126,48 @@ static int vivi_release(struct inode *inode, struct file *file)
+ 	videobuf_stop(&fh->vb_vidq);
+ 	videobuf_mmap_free(&fh->vb_vidq);
+ 
+-	kfree (fh);
++	kfree(fh);
+ 
+ 	dev->users--;
+ 
+-	printk(KERN_DEBUG "vivi: close called (minor=%d, users=%d)\n",minor,dev->users);
++	dprintk(dev, 1, "close called (minor=%d, users=%d)\n",
++		minor, dev->users);
+ 
+ 	return 0;
+ }
+ 
+-static int
+-vivi_mmap(struct file *file, struct vm_area_struct * vma)
++static int vivi_release(void)
+ {
+-	struct vivi_fh        *fh = file->private_data;
++	struct vivi_dev *dev;
++	struct list_head *list;
 +
-+	tuner_info("Device is Xceive %d version %d.%d, "
-+		   "firmware version %d.%d\n",
-+		   hwmodel, (version & 0xf000) >> 12, (version & 0xf00) >> 8,
-+		   (version & 0xf0) >> 4, version & 0xf);
++	while (!list_empty(&vivi_devlist)) {
++		list = vivi_devlist.next;
++		list_del(list);
++		dev = list_entry(list, struct vivi_dev, vivi_devlist);
 +
-+	/* Check firmware version against what we downloaded. */
-+	if (priv->firm_version != ((version & 0xf0) << 4 | (version & 0x0f))) {
-+		tuner_err("Incorrect readback of firmware version.\n");
-+		goto fail;
-+	}
++		if (-1 != dev->vfd->minor)
++			video_unregister_device(dev->vfd);
++		else
++			video_device_release(dev->vfd);
 +
-+	/* Check that the tuner hardware model remains consistent over time. */
-+	if (priv->hwmodel == 0 && (hwmodel == 2028 || hwmodel == 3028)) {
-+		priv->hwmodel = hwmodel;
-+		priv->hwvers  = version & 0xff00;
-+	} else if (priv->hwmodel == 0 || priv->hwmodel != hwmodel ||
-+		   priv->hwvers != (version & 0xff00)) {
-+		tuner_err("Read invalid device hardware information - tuner "
-+			  "hung?\n");
-+		goto fail;
++		kfree(dev);
 +	}
 +
-+	memcpy(&priv->cur_fw, &new_fw, sizeof(priv->cur_fw));
-+
-+	/*
-+	 * By setting BASE in cur_fw.type only after successfully loading all
-+	 * firmwares, we can:
-+	 * 1. Identify that BASE firmware with type=0 has been loaded;
-+	 * 2. Tell whether BASE firmware was just changed the next time through.
-+	 */
-+	priv->cur_fw.type |= BASE;
-+
 +	return 0;
-+
-+fail:
-+	memset(&priv->cur_fw, 0, sizeof(priv->cur_fw));
-+	if (!is_retry) {
-+		msleep(50);
-+		is_retry = 1;
-+		tuner_dbg("Retrying firmware load\n");
-+		goto retry;
-+	}
-+
-+	if (rc == -ENOENT)
-+		rc = -EINVAL;
-+	return rc;
-+}
-+
-+static int xc2028_signal(struct dvb_frontend *fe, u16 *strength)
-+{
-+	struct xc2028_data *priv = fe->tuner_priv;
-+	u16                 frq_lock, signal = 0;
-+	int                 rc;
-+
-+	tuner_dbg("%s called\n", __FUNCTION__);
-+
-+	mutex_lock(&priv->lock);
-+
-+	/* Sync Lock Indicator */
-+	rc = xc2028_get_reg(priv, 0x0002, &frq_lock);
-+	if (rc < 0 || frq_lock == 0)
-+		goto ret;
-+
-+	/* Frequency is locked. Return signal quality */
-+
-+	/* Get SNR of the video signal */
-+	rc = xc2028_get_reg(priv, 0x0040, &signal);
-+	if (rc < 0)
-+		signal = -frq_lock;
-+
-+ret:
-+	mutex_unlock(&priv->lock);
-+
-+	*strength = signal;
-+
-+	return rc;
-+}
-+
-+#define DIV 15625
-+
-+static int generic_set_freq(struct dvb_frontend *fe, u32 freq /* in HZ */,
-+			    enum tuner_mode new_mode,
-+			    unsigned int type,
-+			    v4l2_std_id std,
-+			    u16 int_freq)
-+{
-+	struct xc2028_data *priv = fe->tuner_priv;
-+	int		   rc = -EINVAL;
-+	unsigned char	   buf[4];
-+	u32		   div, offset = 0;
-+
-+	tuner_dbg("%s called\n", __FUNCTION__);
-+
-+	mutex_lock(&priv->lock);
-+
-+	tuner_dbg("should set frequency %d kHz\n", freq / 1000);
-+
-+	if (check_firmware(fe, type, std, int_freq) < 0)
-+		goto ret;
-+
-+	/* On some cases xc2028 can disable video output, if
-+	 * very weak signals are received. By sending a soft
-+	 * reset, this is re-enabled. So, it is better to always
-+	 * send a soft reset before changing channels, to be sure
-+	 * that xc2028 will be in a safe state.
-+	 * Maybe this might also be needed for DTV.
-+	 */
-+	if (new_mode == T_ANALOG_TV) {
-+		rc = send_seq(priv, {0x00, 0x00});
-+	} else if (priv->cur_fw.type & ATSC) {
-+		offset = 1750000;
-+	} else {
-+		offset = 2750000;
-+		/*
-+		 * We must adjust the offset by 500kHz in two cases in order
-+		 * to correctly center the IF output:
-+		 * 1) When the ZARLINK456 or DIBCOM52 tables were explicitly
-+		 *    selected and a 7MHz channel is tuned;
-+		 * 2) When tuning a VHF channel with DTV78 firmware.
-+		 */
-+		if (((priv->cur_fw.type & DTV7) &&
-+		     (priv->cur_fw.scode_table & (ZARLINK456 | DIBCOM52))) ||
-+		    ((priv->cur_fw.type & DTV78) && freq < 470000000))
-+			offset -= 500000;
-+	}
-+
-+	div = (freq - offset + DIV / 2) / DIV;
-+
-+	/* CMD= Set frequency */
-+	if (priv->firm_version < 0x0202)
-+		rc = send_seq(priv, {0x00, 0x02, 0x00, 0x00});
-+	else
-+		rc = send_seq(priv, {0x80, 0x02, 0x00, 0x00});
-+	if (rc < 0)
-+		goto ret;
-+
-+	rc = priv->tuner_callback(priv->video_dev, XC2028_RESET_CLK, 1);
-+	if (rc < 0)
-+		goto ret;
-+
-+	msleep(10);
-+
-+	buf[0] = 0xff & (div >> 24);
-+	buf[1] = 0xff & (div >> 16);
-+	buf[2] = 0xff & (div >> 8);
-+	buf[3] = 0xff & (div);
-+
-+	rc = i2c_send(priv, buf, sizeof(buf));
-+	if (rc < 0)
-+		goto ret;
-+	msleep(100);
-+
-+	priv->frequency = freq;
-+
-+	tuner_dbg("divisor= %02x %02x %02x %02x (freq=%d.%03d)\n",
-+	       buf[0], buf[1], buf[2], buf[3],
-+	       freq / 1000000, (freq % 1000000) / 1000);
-+
-+	rc = 0;
-+
-+ret:
-+	mutex_unlock(&priv->lock);
-+
-+	return rc;
 +}
 +
-+static int xc2028_set_analog_freq(struct dvb_frontend *fe,
-+			      struct analog_parameters *p)
++static int vivi_mmap(struct file *file, struct vm_area_struct *vma)
 +{
-+	struct xc2028_data *priv = fe->tuner_priv;
-+	unsigned int       type=0;
-+
-+	tuner_dbg("%s called\n", __FUNCTION__);
-+
-+	if (p->mode == V4L2_TUNER_RADIO) {
-+		type |= FM;
-+		if (priv->ctrl.input1)
-+			type |= INPUT1;
-+		return generic_set_freq(fe, (625l * p->frequency) / 10,
-+				T_ANALOG_TV, type, 0, 0);
-+	}
-+
-+	/* if std is not defined, choose one */
-+	if (!p->std)
-+		p->std = V4L2_STD_MN;
-+
-+	/* PAL/M, PAL/N, PAL/Nc and NTSC variants should use 6MHz firmware */
-+	if (!(p->std & V4L2_STD_MN))
-+		type |= F8MHZ;
++	struct vivi_fh  *fh = file->private_data;
++	struct vivi_dev *dev = fh->dev;
+ 	int ret;
+ 
+-	dprintk (1,"mmap called, vma=0x%08lx\n",(unsigned long)vma);
++	dprintk(dev, 1, "mmap called, vma=0x%08lx\n", (unsigned long)vma);
+ 
+-	ret=videobuf_mmap_mapper(&fh->vb_vidq, vma);
++	ret = videobuf_mmap_mapper(&fh->vb_vidq, vma);
+ 
+-	dprintk (1,"vma start=0x%08lx, size=%ld, ret=%d\n",
++	dprintk(dev, 1, "vma start=0x%08lx, size=%ld, ret=%d\n",
+ 		(unsigned long)vma->vm_start,
+ 		(unsigned long)vma->vm_end-(unsigned long)vma->vm_start,
+ 		ret);
+@@ -1109,7 +1178,7 @@ vivi_mmap(struct file *file, struct vm_area_struct * vma)
+ static const struct file_operations vivi_fops = {
+ 	.owner		= THIS_MODULE,
+ 	.open           = vivi_open,
+-	.release        = vivi_release,
++	.release        = vivi_close,
+ 	.read           = vivi_read,
+ 	.poll		= vivi_poll,
+ 	.ioctl          = video_ioctl2, /* V4L2 ioctl handler */
+@@ -1117,12 +1186,12 @@ static const struct file_operations vivi_fops = {
+ 	.llseek         = no_llseek,
+ };
+ 
+-static struct video_device vivi = {
++static struct video_device vivi_template = {
+ 	.name		= "vivi",
+ 	.type		= VID_TYPE_CAPTURE,
+ 	.fops           = &vivi_fops,
+ 	.minor		= -1,
+-//	.release	= video_device_release,
++	.release	= video_device_release,
+ 
+ 	.vidioc_querycap      = vidioc_querycap,
+ 	.vidioc_enum_fmt_cap  = vidioc_enum_fmt_cap,
+@@ -1145,7 +1214,7 @@ static struct video_device vivi = {
+ #ifdef CONFIG_VIDEO_V4L1_COMPAT
+ 	.vidiocgmbuf          = vidiocgmbuf,
+ #endif
+-	.tvnorms              = V4L2_STD_NTSC_M,
++	.tvnorms              = V4L2_STD_525_60,
+ 	.current_norm         = V4L2_STD_NTSC_M,
+ };
+ /* -----------------------------------------------------------------
+@@ -1154,43 +1223,61 @@ static struct video_device vivi = {
+ 
+ static int __init vivi_init(void)
+ {
+-	int ret;
++	int ret = -ENOMEM, i;
+ 	struct vivi_dev *dev;
++	struct video_device *vfd;
+ 
+-	dev = kzalloc(sizeof(*dev),GFP_KERNEL);
+-	if (NULL == dev)
+-		return -ENOMEM;
+-	list_add_tail(&dev->vivi_devlist,&vivi_devlist);
++	for (i = 0; i < n_devs; i++) {
++		dev = kzalloc(sizeof(*dev), GFP_KERNEL);
++		if (NULL == dev)
++			break;
+ 
+-	/* init video dma queues */
+-	INIT_LIST_HEAD(&dev->vidq.active);
+-	INIT_LIST_HEAD(&dev->vidq.queued);
+-	init_waitqueue_head(&dev->vidq.wq);
++		list_add_tail(&dev->vivi_devlist, &vivi_devlist);
+ 
+-	/* initialize locks */
+-	mutex_init(&dev->lock);
++		/* init video dma queues */
++		INIT_LIST_HEAD(&dev->vidq.active);
++		INIT_LIST_HEAD(&dev->vidq.queued);
++		init_waitqueue_head(&dev->vidq.wq);
+ 
+-	dev->vidq.timeout.function = vivi_vid_timeout;
+-	dev->vidq.timeout.data     = (unsigned long)dev;
+-	init_timer(&dev->vidq.timeout);
++		/* initialize locks */
++		mutex_init(&dev->lock);
++		spin_lock_init(&dev->slock);
+ 
+-	ret = video_register_device(&vivi, VFL_TYPE_GRABBER, video_nr);
+-	printk(KERN_INFO "Video Technology Magazine Virtual Video Capture Board (Load status: %d)\n", ret);
++		dev->vidq.timeout.function = vivi_vid_timeout;
++		dev->vidq.timeout.data     = (unsigned long)dev;
++		init_timer(&dev->vidq.timeout);
 +
-+	/* Add audio hack to std mask */
-+	p->std |= parse_audio_std_option();
++		vfd = video_device_alloc();
++		if (NULL == vfd)
++			break;
 +
-+	return generic_set_freq(fe, 62500l * p->frequency,
-+				T_ANALOG_TV, type, p->std, 0);
-+}
++		*vfd = vivi_template;
 +
-+static int xc2028_set_params(struct dvb_frontend *fe,
-+			     struct dvb_frontend_parameters *p)
-+{
-+	struct xc2028_data *priv = fe->tuner_priv;
-+	unsigned int       type=0;
-+	fe_bandwidth_t     bw = BANDWIDTH_8_MHZ;
-+	u16                demod = 0;
++		ret = video_register_device(vfd, VFL_TYPE_GRABBER, video_nr);
++		if (ret < 0)
++			break;
 +
-+	tuner_dbg("%s called\n", __FUNCTION__);
++		snprintf(vfd->name, sizeof(vfd->name), "%s (%i)",
++			 vivi_template.name, vfd->minor);
 +
-+	if (priv->ctrl.d2633)
-+		type |= D2633;
-+	else
-+		type |= D2620;
++		if (video_nr >= 0)
++			video_nr++;
 +
-+	switch(fe->ops.info.type) {
-+	case FE_OFDM:
-+		bw = p->u.ofdm.bandwidth;
-+		break;
-+	case FE_QAM:
-+		tuner_info("WARN: There are some reports that "
-+			   "QAM 6 MHz doesn't work.\n"
-+			   "If this works for you, please report by "
-+			   "e-mail to: v4l-dvb-maintainer at linuxtv.org\n");
-+		bw = BANDWIDTH_6_MHZ;
-+		type |= QAM;
-+		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;
-+		break;
-+	/* DVB-S is not supported */
-+	default:
-+		return -EINVAL;
++		dev->vfd = vfd;
 +	}
 +
-+	switch (bw) {
-+	case BANDWIDTH_8_MHZ:
-+		if (p->frequency < 470000000)
-+			priv->ctrl.vhfbw7 = 0;
-+		else
-+			priv->ctrl.uhfbw8 = 1;
-+		type |= (priv->ctrl.vhfbw7 && priv->ctrl.uhfbw8) ? DTV78 : DTV8;
-+		type |= F8MHZ;
++	if (ret < 0) {
++		vivi_release();
++		printk(KERN_INFO "Error %d while loading vivi driver\n", ret);
++	} else
++		printk(KERN_INFO "Video Technology Magazine Virtual Video "
++				 "Capture Board successfully loaded.\n");
+ 	return ret;
+ }
+ 
+ static void __exit vivi_exit(void)
+ {
+-	struct vivi_dev *h;
+-	struct list_head *list;
+-
+-	while (!list_empty(&vivi_devlist)) {
+-		list = vivi_devlist.next;
+-		list_del(list);
+-		h = list_entry(list, struct vivi_dev, vivi_devlist);
+-		kfree (h);
+-	}
+-	video_unregister_device(&vivi);
++	vivi_release();
+ }
+ 
+ module_init(vivi_init);
+@@ -1201,10 +1288,13 @@ MODULE_AUTHOR("Mauro Carvalho Chehab, Ted Walther and John Sokol");
+ MODULE_LICENSE("Dual BSD/GPL");
+ 
+ module_param(video_nr, int, 0);
++MODULE_PARM_DESC(video_nr, "video iminor start number");
+ 
+-module_param_named(debug,vivi.debug, int, 0644);
+-MODULE_PARM_DESC(debug,"activates debug info");
++module_param(n_devs, int, 0);
++MODULE_PARM_DESC(n_devs, "number of video devices to create");
+ 
+-module_param(vid_limit,int,0644);
+-MODULE_PARM_DESC(vid_limit,"capture memory limit in megabytes");
++module_param_named(debug, vivi_template.debug, int, 0444);
++MODULE_PARM_DESC(debug, "activates debug info");
+ 
++module_param(vid_limit, int, 0644);
++MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes");
+diff --git a/drivers/media/video/vp27smpx.c b/drivers/media/video/vp27smpx.c
+index 63002e0..282c814 100644
+--- a/drivers/media/video/vp27smpx.c
++++ b/drivers/media/video/vp27smpx.c
+@@ -30,15 +30,12 @@
+ #include <linux/videodev.h>
+ #include <media/v4l2-common.h>
+ #include <media/v4l2-chip-ident.h>
++#include <media/v4l2-i2c-drv.h>
+ 
+ MODULE_DESCRIPTION("vp27smpx driver");
+ MODULE_AUTHOR("Hans Verkuil");
+ MODULE_LICENSE("GPL");
+ 
+-static unsigned short normal_i2c[] = { 0xb6 >> 1, I2C_CLIENT_END };
+-
+-
+-I2C_CLIENT_INSMOD;
+ 
+ /* ----------------------------------------------------------------------- */
+ 
+@@ -53,28 +50,26 @@ static void vp27smpx_set_audmode(struct i2c_client *client, u32 audmode)
+ 	u8 data[3] = { 0x00, 0x00, 0x04 };
+ 
+ 	switch (audmode) {
+-		case V4L2_TUNER_MODE_MONO:
+-		case V4L2_TUNER_MODE_LANG1:
+-			break;
+-		case V4L2_TUNER_MODE_STEREO:
+-		case V4L2_TUNER_MODE_LANG1_LANG2:
+-			data[1] = 0x01;
+-			break;
+-		case V4L2_TUNER_MODE_LANG2:
+-			data[1] = 0x02;
+-			break;
++	case V4L2_TUNER_MODE_MONO:
++	case V4L2_TUNER_MODE_LANG1:
 +		break;
-+	case BANDWIDTH_7_MHZ:
-+		if (p->frequency < 470000000)
-+			priv->ctrl.vhfbw7 = 1;
-+		else
-+			priv->ctrl.uhfbw8 = 0;
-+		type |= (priv->ctrl.vhfbw7 && priv->ctrl.uhfbw8) ? DTV78 : DTV7;
-+		type |= F8MHZ;
++	case V4L2_TUNER_MODE_STEREO:
++	case V4L2_TUNER_MODE_LANG1_LANG2:
++		data[1] = 0x01;
 +		break;
-+	case BANDWIDTH_6_MHZ:
-+		type |= DTV6;
-+		priv->ctrl.vhfbw7 = 0;
-+		priv->ctrl.uhfbw8 = 0;
++	case V4L2_TUNER_MODE_LANG2:
++		data[1] = 0x02;
 +		break;
-+	default:
-+		tuner_err("error: bandwidth not supported.\n");
-+	};
-+
-+	/* All S-code tables need a 200kHz shift */
-+	if (priv->ctrl.demod)
-+		demod = priv->ctrl.demod + 200;
-+
-+	return generic_set_freq(fe, p->frequency,
-+				T_DIGITAL_TV, type, 0, demod);
-+}
-+
-+static int xc2028_sleep(struct dvb_frontend *fe)
-+{
-+	struct xc2028_data *priv = fe->tuner_priv;
-+	int rc = 0;
-+
-+	tuner_dbg("%s called\n", __FUNCTION__);
-+
-+	mutex_lock(&priv->lock);
-+
-+	if (priv->firm_version < 0x0202)
-+		rc = send_seq(priv, {0x00, 0x08, 0x00, 0x00});
+ 	}
+ 
+-	if (i2c_master_send(client, data, sizeof(data)) != sizeof(data)) {
+-		v4l_err(client, "%s: I/O error setting audmode\n", client->name);
+-	}
+-	else {
++	if (i2c_master_send(client, data, sizeof(data)) != sizeof(data))
++		v4l_err(client, "%s: I/O error setting audmode\n",
++				client->name);
 +	else
-+		rc = send_seq(priv, {0x80, 0x08, 0x00, 0x00});
-+
-+	priv->cur_fw.type = 0;	/* need firmware reload */
-+
-+	mutex_unlock(&priv->lock);
-+
-+	return rc;
-+}
-+
-+
-+static int xc2028_dvb_release(struct dvb_frontend *fe)
-+{
-+	struct xc2028_data *priv = fe->tuner_priv;
-+
-+	tuner_dbg("%s called\n", __FUNCTION__);
-+
-+	mutex_lock(&xc2028_list_mutex);
-+
-+	priv->count--;
-+
-+	if (!priv->count) {
-+		list_del(&priv->xc2028_list);
-+
-+		kfree(priv->ctrl.fname);
-+
-+		free_firmware(priv);
-+		kfree(priv);
-+		fe->tuner_priv = NULL;
-+	}
-+
-+	mutex_unlock(&xc2028_list_mutex);
-+
-+	return 0;
-+}
-+
-+static int xc2028_get_frequency(struct dvb_frontend *fe, u32 *frequency)
-+{
-+	struct xc2028_data *priv = fe->tuner_priv;
-+
-+	tuner_dbg("%s called\n", __FUNCTION__);
-+
-+	*frequency = priv->frequency;
-+
-+	return 0;
-+}
-+
-+static int xc2028_set_config(struct dvb_frontend *fe, void *priv_cfg)
-+{
-+	struct xc2028_data *priv = fe->tuner_priv;
-+	struct xc2028_ctrl *p    = priv_cfg;
-+	int                 rc   = 0;
-+
-+	tuner_dbg("%s called\n", __FUNCTION__);
-+
-+	mutex_lock(&priv->lock);
-+
-+	kfree(priv->ctrl.fname);
-+	free_firmware(priv);
-+
-+	memcpy(&priv->ctrl, p, sizeof(priv->ctrl));
-+	priv->ctrl.fname = NULL;
-+
-+	if (p->fname) {
-+		priv->ctrl.fname = kstrdup(p->fname, GFP_KERNEL);
-+		if (priv->ctrl.fname == NULL)
-+			rc = -ENOMEM;
-+	}
-+
-+	if (priv->ctrl.max_len < 9)
-+		priv->ctrl.max_len = 13;
-+
-+	mutex_unlock(&priv->lock);
-+
-+	return rc;
-+}
-+
-+static const struct dvb_tuner_ops xc2028_dvb_tuner_ops = {
-+	.info = {
-+		 .name = "Xceive XC3028",
-+		 .frequency_min = 42000000,
-+		 .frequency_max = 864000000,
-+		 .frequency_step = 50000,
-+		 },
-+
-+	.set_config	   = xc2028_set_config,
-+	.set_analog_params = xc2028_set_analog_freq,
-+	.release           = xc2028_dvb_release,
-+	.get_frequency     = xc2028_get_frequency,
-+	.get_rf_strength   = xc2028_signal,
-+	.set_params        = xc2028_set_params,
-+	.sleep             = xc2028_sleep,
-+
-+};
-+
-+struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe,
-+				   struct xc2028_config *cfg)
-+{
-+	struct xc2028_data *priv;
-+	void               *video_dev;
-+
-+	if (debug)
-+		printk(KERN_DEBUG PREFIX ": Xcv2028/3028 init called!\n");
-+
-+	if (NULL == cfg || NULL == cfg->video_dev)
-+		return NULL;
-+
-+	if (!fe) {
-+		printk(KERN_ERR PREFIX ": No frontend!\n");
-+		return NULL;
-+	}
-+
-+	video_dev = cfg->video_dev;
-+
-+	mutex_lock(&xc2028_list_mutex);
-+
-+	list_for_each_entry(priv, &xc2028_list, xc2028_list) {
-+		if (priv->video_dev == cfg->video_dev) {
-+			video_dev = NULL;
-+			break;
-+		}
-+	}
-+
-+	if (video_dev) {
-+		priv = kzalloc(sizeof(*priv), GFP_KERNEL);
-+		if (priv == NULL) {
-+			mutex_unlock(&xc2028_list_mutex);
-+			return NULL;
-+		}
-+
-+		priv->i2c_props.addr = cfg->i2c_addr;
-+		priv->i2c_props.adap = cfg->i2c_adap;
-+		priv->video_dev = video_dev;
-+		priv->tuner_callback = cfg->callback;
-+		priv->ctrl.max_len = 13;
-+
-+		mutex_init(&priv->lock);
-+
-+		list_add_tail(&priv->xc2028_list, &xc2028_list);
-+	}
-+
-+	fe->tuner_priv = priv;
-+	priv->count++;
-+
-+	memcpy(&fe->ops.tuner_ops, &xc2028_dvb_tuner_ops,
-+	       sizeof(xc2028_dvb_tuner_ops));
-+
-+	tuner_info("type set to %s\n", "XCeive xc2028/xc3028 tuner");
-+
-+	if (cfg->ctrl)
-+		xc2028_set_config(fe, cfg->ctrl);
-+
-+	mutex_unlock(&xc2028_list_mutex);
-+
-+	return fe;
-+}
-+
-+EXPORT_SYMBOL(xc2028_attach);
-+
-+MODULE_DESCRIPTION("Xceive xc2028/xc3028 tuner driver");
-+MODULE_AUTHOR("Michel Ludwig <michel.ludwig at gmail.com>");
-+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab at infradead.org>");
-+MODULE_LICENSE("GPL");
-diff --git a/drivers/media/video/tuner-xc2028.h b/drivers/media/video/tuner-xc2028.h
-new file mode 100644
-index 0000000..3eb8420
---- /dev/null
-+++ b/drivers/media/video/tuner-xc2028.h
-@@ -0,0 +1,63 @@
-+/* tuner-xc2028
-+ *
-+ * Copyright (c) 2007 Mauro Carvalho Chehab (mchehab at infradead.org)
-+ * This code is placed under the terms of the GNU General Public License v2
-+ */
-+
-+#ifndef __TUNER_XC2028_H__
-+#define __TUNER_XC2028_H__
-+
-+#include "dvb_frontend.h"
-+
-+#define XC2028_DEFAULT_FIRMWARE "xc3028-v27.fw"
-+
-+/*      Dmoduler		IF (kHz) */
-+#define	XC3028_FE_DEFAULT	0
-+#define XC3028_FE_LG60		6000
-+#define	XC3028_FE_ATI638	6380
-+#define	XC3028_FE_OREN538	5380
-+#define	XC3028_FE_OREN36	3600
-+#define	XC3028_FE_TOYOTA388	3880
-+#define	XC3028_FE_TOYOTA794	7940
-+#define	XC3028_FE_DIBCOM52	5200
-+#define	XC3028_FE_ZARLINK456	4560
-+#define	XC3028_FE_CHINA		5200
-+
-+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;
-+};
-+
-+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 */
-+#define XC2028_TUNER_RESET	0
-+#define XC2028_RESET_CLK	1
-+
-+#if defined(CONFIG_TUNER_XC2028) || (defined(CONFIG_TUNER_XC2028_MODULE) && defined(MODULE))
-+extern struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe,
-+					  struct xc2028_config *cfg);
-+#else
-+static inline struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe,
-+						 struct xc2028_config *cfg)
-+{
-+	printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n",
-+	       __FUNCTION__);
-+	return NULL;
-+}
-+#endif
-+
-+#endif /* __TUNER_XC2028_H__ */
-diff --git a/drivers/media/video/tvaudio.c b/drivers/media/video/tvaudio.c
-index a19cdcc..a755605 100644
---- a/drivers/media/video/tvaudio.c
-+++ b/drivers/media/video/tvaudio.c
-@@ -31,6 +31,7 @@
- #include <media/tvaudio.h>
+ 		state->audmode = audmode;
+-	}
+ }
+ 
+-static int vp27smpx_command(struct i2c_client *client, unsigned int cmd,
+-			  void *arg)
++static int vp27smpx_command(struct i2c_client *client, unsigned cmd, void *arg)
+ {
+ 	struct vp27smpx_state *state = i2c_get_clientdata(client);
+ 	struct v4l2_tuner *vt = arg;
+@@ -103,7 +98,8 @@ static int vp27smpx_command(struct i2c_client *client, unsigned int cmd,
+ 		break;
+ 
+ 	case VIDIOC_G_CHIP_IDENT:
+-		return v4l2_chip_ident_i2c_client(client, arg, V4L2_IDENT_VP27SMPX, 0);
++		return v4l2_chip_ident_i2c_client(client, arg,
++				V4L2_IDENT_VP27SMPX, 0);
+ 
+ 	case VIDIOC_LOG_STATUS:
+ 		v4l_info(client, "Audio Mode: %u%s\n", state->audmode,
+@@ -125,88 +121,43 @@ static int vp27smpx_command(struct i2c_client *client, unsigned int cmd,
+  * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
+  */
+ 
+-static struct i2c_driver i2c_driver;
+-
+-static int vp27smpx_attach(struct i2c_adapter *adapter, int address, int kind)
++static int vp27smpx_probe(struct i2c_client *client)
+ {
+-	struct i2c_client *client;
+ 	struct vp27smpx_state *state;
+ 
+ 	/* Check if the adapter supports the needed features */
+-	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+-		return 0;
+-
+-	client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
+-	if (client == 0)
+-		return -ENOMEM;
++	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
++		return -EIO;
+ 
+-	client->addr = address;
+-	client->adapter = adapter;
+-	client->driver = &i2c_driver;
+ 	snprintf(client->name, sizeof(client->name) - 1, "vp27smpx");
+ 
+-	v4l_info(client, "chip found @ 0x%x (%s)\n", address << 1, adapter->name);
++	v4l_info(client, "chip found @ 0x%x (%s)\n",
++			client->addr << 1, client->adapter->name);
+ 
+ 	state = kzalloc(sizeof(struct vp27smpx_state), GFP_KERNEL);
+-	if (state == NULL) {
+-		kfree(client);
++	if (state == NULL)
+ 		return -ENOMEM;
+-	}
+ 	state->audmode = V4L2_TUNER_MODE_STEREO;
+ 	i2c_set_clientdata(client, state);
+ 
+ 	/* initialize vp27smpx */
+ 	vp27smpx_set_audmode(client, state->audmode);
+-	i2c_attach_client(client);
+-
+ 	return 0;
+ }
+ 
+-static int vp27smpx_probe(struct i2c_adapter *adapter)
++static int vp27smpx_remove(struct i2c_client *client)
+ {
+-	if (adapter->class & I2C_CLASS_TV_ANALOG)
+-		return i2c_probe(adapter, &addr_data, vp27smpx_attach);
+-	return 0;
+-}
+-
+-static int vp27smpx_detach(struct i2c_client *client)
+-{
+-	struct vp27smpx_state *state = i2c_get_clientdata(client);
+-	int err;
+-
+-	err = i2c_detach_client(client);
+-	if (err) {
+-		return err;
+-	}
+-	kfree(state);
+-	kfree(client);
+-
++	kfree(i2c_get_clientdata(client));
+ 	return 0;
+ }
+ 
+ /* ----------------------------------------------------------------------- */
+ 
+-/* i2c implementation */
+-static struct i2c_driver i2c_driver = {
+-	.driver = {
+-		.name = "vp27smpx",
+-	},
+-	.id             = I2C_DRIVERID_VP27SMPX,
+-	.attach_adapter = vp27smpx_probe,
+-	.detach_client  = vp27smpx_detach,
+-	.command        = vp27smpx_command,
++static struct v4l2_i2c_driver_data v4l2_i2c_data = {
++	.name = "vp27smpx",
++	.driverid = I2C_DRIVERID_VP27SMPX,
++	.command = vp27smpx_command,
++	.probe = vp27smpx_probe,
++	.remove = vp27smpx_remove,
+ };
+ 
+-
+-static int __init vp27smpx_init_module(void)
+-{
+-	return i2c_add_driver(&i2c_driver);
+-}
+-
+-static void __exit vp27smpx_cleanup_module(void)
+-{
+-	i2c_del_driver(&i2c_driver);
+-}
+-
+-module_init(vp27smpx_init_module);
+-module_exit(vp27smpx_cleanup_module);
+diff --git a/drivers/media/video/wm8739.c b/drivers/media/video/wm8739.c
+index 1bf4cbe..31795b4 100644
+--- a/drivers/media/video/wm8739.c
++++ b/drivers/media/video/wm8739.c
+@@ -30,21 +30,19 @@
+ #include <linux/videodev.h>
  #include <media/v4l2-common.h>
  #include <media/v4l2-chip-ident.h>
-+#include <media/v4l2-i2c-drv-legacy.h>
++#include <media/v4l2-i2c-drv.h>
  
- #include <media/i2c-addr.h>
+ MODULE_DESCRIPTION("wm8739 driver");
+ MODULE_AUTHOR("T. Adachi, Hans Verkuil");
+ MODULE_LICENSE("GPL");
  
-@@ -109,7 +110,7 @@ static struct CHIPDESC chiplist[];
+-static int debug = 0;
+-static unsigned short normal_i2c[] = { 0x34 >> 1, 0x36 >> 1, I2C_CLIENT_END };
++static int debug;
  
- /* current state of the chip */
- struct CHIPSTATE {
--	struct i2c_client c;
-+	struct i2c_client *c;
+ module_param(debug, int, 0644);
  
- 	/* index into CHIPDESC array */
- 	int type;
-@@ -145,10 +146,6 @@ static unsigned short normal_i2c[] = {
- 	I2C_CLIENT_END };
- I2C_CLIENT_INSMOD;
+ MODULE_PARM_DESC(debug, "Debug level (0-1)");
  
--static struct i2c_driver driver;
--static struct i2c_client client_template;
--
+ 
+-I2C_CLIENT_INSMOD;
 -
- /* ---------------------------------------------------------------------- */
- /* i2c I/O functions                                                      */
+ /* ------------------------------------------------------------------------ */
  
-@@ -157,24 +154,24 @@ static int chip_write(struct CHIPSTATE *chip, int subaddr, int val)
- 	unsigned char buffer[2];
+ enum {
+@@ -75,12 +73,10 @@ static int wm8739_write(struct i2c_client *client, int reg, u16 val)
  
- 	if (-1 == subaddr) {
--		v4l_dbg(1, debug, &chip->c, "%s: chip_write: 0x%x\n",
--			chip->c.name, val);
-+		v4l_dbg(1, debug, chip->c, "%s: chip_write: 0x%x\n",
-+			chip->c->name, val);
- 		chip->shadow.bytes[1] = val;
- 		buffer[0] = val;
--		if (1 != i2c_master_send(&chip->c,buffer,1)) {
--			v4l_warn(&chip->c, "%s: I/O error (write 0x%x)\n",
--				chip->c.name, val);
-+		if (1 != i2c_master_send(chip->c,buffer,1)) {
-+			v4l_warn(chip->c, "%s: I/O error (write 0x%x)\n",
-+				chip->c->name, val);
- 			return -1;
- 		}
- 	} else {
--		v4l_dbg(1, debug, &chip->c, "%s: chip_write: reg%d=0x%x\n",
--			chip->c.name, subaddr, val);
-+		v4l_dbg(1, debug, chip->c, "%s: chip_write: reg%d=0x%x\n",
-+			chip->c->name, subaddr, val);
- 		chip->shadow.bytes[subaddr+1] = val;
- 		buffer[0] = subaddr;
- 		buffer[1] = val;
--		if (2 != i2c_master_send(&chip->c,buffer,2)) {
--			v4l_warn(&chip->c, "%s: I/O error (write reg%d=0x%x)\n",
--			chip->c.name, subaddr, val);
-+		if (2 != i2c_master_send(chip->c,buffer,2)) {
-+			v4l_warn(chip->c, "%s: I/O error (write reg%d=0x%x)\n",
-+			chip->c->name, subaddr, val);
- 			return -1;
+ 	v4l_dbg(1, debug, client, "write: %02x %02x\n", reg, val);
+ 
+-	for (i = 0; i < 3; i++) {
+-		if (i2c_smbus_write_byte_data(client, (reg << 1) |
+-					(val >> 8), val & 0xff) == 0) {
++	for (i = 0; i < 3; i++)
++		if (i2c_smbus_write_byte_data(client,
++				(reg << 1) | (val >> 8), val & 0xff) == 0)
+ 			return 0;
+-		}
+-	}
+ 	v4l_err(client, "I2C: cannot write %03x to register R%d\n", val, reg);
+ 	return -1;
+ }
+@@ -167,7 +163,7 @@ static struct v4l2_queryctrl wm8739_qctrl[] = {
+ 		.default_value = 58880,
+ 		.flags         = 0,
+ 		.type          = V4L2_CTRL_TYPE_INTEGER,
+-	},{
++	}, {
+ 		.id            = V4L2_CID_AUDIO_MUTE,
+ 		.name          = "Mute",
+ 		.minimum       = 0,
+@@ -176,7 +172,7 @@ static struct v4l2_queryctrl wm8739_qctrl[] = {
+ 		.default_value = 1,
+ 		.flags         = 0,
+ 		.type          = V4L2_CTRL_TYPE_BOOLEAN,
+-	},{
++	}, {
+ 		.id            = V4L2_CID_AUDIO_BALANCE,
+ 		.name          = "Balance",
+ 		.minimum       = 0,
+@@ -190,7 +186,7 @@ static struct v4l2_queryctrl wm8739_qctrl[] = {
+ 
+ /* ------------------------------------------------------------------------ */
+ 
+-static int wm8739_command(struct i2c_client *client, unsigned int cmd, void *arg)
++static int wm8739_command(struct i2c_client *client, unsigned cmd, void *arg)
+ {
+ 	struct wm8739_state *state = i2c_get_clientdata(client);
+ 
+@@ -200,21 +196,26 @@ static int wm8739_command(struct i2c_client *client, unsigned int cmd, void *arg
+ 		u32 audiofreq = *(u32 *)arg;
+ 
+ 		state->clock_freq = audiofreq;
+-		wm8739_write(client, R9, 0x000);	/* de-activate */
++		/* de-activate */
++		wm8739_write(client, R9, 0x000);
+ 		switch (audiofreq) {
+ 		case 44100:
+-			wm8739_write(client, R8, 0x020); /* 256fps, fs=44.1k     */
++			/* 256fps, fs=44.1k */
++			wm8739_write(client, R8, 0x020);
+ 			break;
+ 		case 48000:
+-			wm8739_write(client, R8, 0x000); /* 256fps, fs=48k       */
++			/* 256fps, fs=48k */
++			wm8739_write(client, R8, 0x000);
+ 			break;
+ 		case 32000:
+-			wm8739_write(client, R8, 0x018); /* 256fps, fs=32k       */
++			/* 256fps, fs=32k */
++			wm8739_write(client, R8, 0x018);
+ 			break;
+ 		default:
+ 			break;
  		}
+-		wm8739_write(client, R9, 0x001);	/* activate */
++		/* activate */
++		wm8739_write(client, R9, 0x001);
+ 		break;
  	}
-@@ -197,12 +194,12 @@ static int chip_read(struct CHIPSTATE *chip)
- {
- 	unsigned char buffer;
  
--	if (1 != i2c_master_recv(&chip->c,&buffer,1)) {
--		v4l_warn(&chip->c, "%s: I/O error (read)\n",
--		chip->c.name);
-+	if (1 != i2c_master_recv(chip->c,&buffer,1)) {
-+		v4l_warn(chip->c, "%s: I/O error (read)\n",
-+		chip->c->name);
- 		return -1;
+@@ -238,7 +239,8 @@ static int wm8739_command(struct i2c_client *client, unsigned int cmd, void *arg
  	}
--	v4l_dbg(1, debug, &chip->c, "%s: chip_read: 0x%x\n",chip->c.name, buffer);
-+	v4l_dbg(1, debug, chip->c, "%s: chip_read: 0x%x\n",chip->c->name, buffer);
- 	return buffer;
- }
  
-@@ -211,17 +208,17 @@ static int chip_read2(struct CHIPSTATE *chip, int subaddr)
- 	unsigned char write[1];
- 	unsigned char read[1];
- 	struct i2c_msg msgs[2] = {
--		{ chip->c.addr, 0,        1, write },
--		{ chip->c.addr, I2C_M_RD, 1, read  }
-+		{ chip->c->addr, 0,        1, write },
-+		{ chip->c->addr, I2C_M_RD, 1, read  }
- 	};
- 	write[0] = subaddr;
+ 	case VIDIOC_G_CHIP_IDENT:
+-		return v4l2_chip_ident_i2c_client(client, arg, V4L2_IDENT_WM8739, 0);
++		return v4l2_chip_ident_i2c_client(client,
++				arg, V4L2_IDENT_WM8739, 0);
  
--	if (2 != i2c_transfer(chip->c.adapter,msgs,2)) {
--		v4l_warn(&chip->c, "%s: I/O error (read2)\n", chip->c.name);
-+	if (2 != i2c_transfer(chip->c->adapter,msgs,2)) {
-+		v4l_warn(chip->c, "%s: I/O error (read2)\n", chip->c->name);
- 		return -1;
- 	}
--	v4l_dbg(1, debug, &chip->c, "%s: chip_read2: reg%d=0x%x\n",
--		chip->c.name, subaddr,read[0]);
-+	v4l_dbg(1, debug, chip->c, "%s: chip_read2: reg%d=0x%x\n",
-+		chip->c->name, subaddr,read[0]);
- 	return read[0];
- }
+ 	case VIDIOC_LOG_STATUS:
+ 		v4l_info(client, "Frequency: %u Hz\n", state->clock_freq);
+@@ -259,27 +261,16 @@ static int wm8739_command(struct i2c_client *client, unsigned int cmd, void *arg
  
-@@ -233,8 +230,8 @@ static int chip_cmd(struct CHIPSTATE *chip, char *name, audiocmd *cmd)
- 		return 0;
+ /* i2c implementation */
  
- 	/* update our shadow register set; print bytes if (debug > 0) */
--	v4l_dbg(1, debug, &chip->c, "%s: chip_cmd(%s): reg=%d, data:",
--		chip->c.name, name,cmd->bytes[0]);
-+	v4l_dbg(1, debug, chip->c, "%s: chip_cmd(%s): reg=%d, data:",
-+		chip->c->name, name,cmd->bytes[0]);
- 	for (i = 1; i < cmd->count; i++) {
- 		if (debug)
- 			printk(" 0x%x",cmd->bytes[i]);
-@@ -244,8 +241,8 @@ static int chip_cmd(struct CHIPSTATE *chip, char *name, audiocmd *cmd)
- 		printk("\n");
+-static struct i2c_driver i2c_driver;
+-
+-static int wm8739_attach(struct i2c_adapter *adapter, int address, int kind)
++static int wm8739_probe(struct i2c_client *client)
+ {
+-	struct i2c_client *client;
+ 	struct wm8739_state *state;
  
- 	/* send data to the chip */
--	if (cmd->count != i2c_master_send(&chip->c,cmd->bytes,cmd->count)) {
--		v4l_warn(&chip->c, "%s: I/O error (%s)\n", chip->c.name, name);
-+	if (cmd->count != i2c_master_send(chip->c,cmd->bytes,cmd->count)) {
-+		v4l_warn(chip->c, "%s: I/O error (%s)\n", chip->c->name, name);
- 		return -1;
- 	}
- 	return 0;
-@@ -269,7 +266,7 @@ static int chip_thread(void *data)
- 	struct CHIPSTATE *chip = data;
- 	struct CHIPDESC  *desc = chiplist + chip->type;
+ 	/* Check if the adapter supports the needed features */
+-	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+-		return 0;
+-
+-	client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
+-	if (client == NULL)
+-		return -ENOMEM;
+-
+-	client->addr = address;
+-	client->adapter = adapter;
+-	client->driver = &i2c_driver;
+-	snprintf(client->name, sizeof(client->name) - 1, "wm8739");
++	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
++		return -EIO;
  
--	v4l_dbg(1, debug, &chip->c, "%s: thread started\n", chip->c.name);
-+	v4l_dbg(1, debug, chip->c, "%s: thread started\n", chip->c->name);
- 	set_freezable();
- 	for (;;) {
- 		set_current_state(TASK_INTERRUPTIBLE);
-@@ -279,7 +276,7 @@ static int chip_thread(void *data)
- 		try_to_freeze();
- 		if (kthread_should_stop())
- 			break;
--		v4l_dbg(1, debug, &chip->c, "%s: thread wakeup\n", chip->c.name);
-+		v4l_dbg(1, debug, chip->c, "%s: thread wakeup\n", chip->c->name);
+-	v4l_info(client, "chip found @ 0x%x (%s)\n", address << 1, adapter->name);
++	v4l_info(client, "chip found @ 0x%x (%s)\n",
++			client->addr << 1, client->adapter->name);
  
- 		/* don't do anything for radio or if mode != auto */
- 		if (chip->radio || chip->mode != 0)
-@@ -292,7 +289,7 @@ static int chip_thread(void *data)
- 		mod_timer(&chip->wt, jiffies+msecs_to_jiffies(2000));
- 	}
+ 	state = kmalloc(sizeof(struct wm8739_state), GFP_KERNEL);
+ 	if (state == NULL) {
+@@ -295,67 +286,37 @@ static int wm8739_attach(struct i2c_adapter *adapter, int address, int kind)
+ 	state->clock_freq = 48000;
+ 	i2c_set_clientdata(client, state);
  
--	v4l_dbg(1, debug, &chip->c, "%s: thread exiting\n", chip->c.name);
-+	v4l_dbg(1, debug, chip->c, "%s: thread exiting\n", chip->c->name);
+-	/* initialize wm8739 */
+-	wm8739_write(client, R15, 0x00); /* reset */
+-	wm8739_write(client, R5, 0x000); /* filter setting, high path, offet clear */
+-	wm8739_write(client, R6, 0x000); /* ADC, OSC, Power Off mode Disable */
+-	wm8739_write(client, R7, 0x049); /* Digital Audio interface format */
+-					 /* Enable Master mode */
+-					 /* 24 bit, MSB first/left justified */
+-	wm8739_write(client, R8, 0x000); /* sampling control */
+-					 /* normal, 256fs, 48KHz sampling rate */
+-	wm8739_write(client, R9, 0x001); /* activate */
+-	wm8739_set_audio(client); 	 /* set volume/mute */
+-
+-	i2c_attach_client(client);
+-
+-	return 0;
+-}
+-
+-static int wm8739_probe(struct i2c_adapter *adapter)
+-{
+-	if (adapter->class & I2C_CLASS_TV_ANALOG)
+-		return i2c_probe(adapter, &addr_data, wm8739_attach);
++	/* Initialize wm8739 */
++
++	/* reset */
++	wm8739_write(client, R15, 0x00);
++	/* filter setting, high path, offet clear */
++	wm8739_write(client, R5, 0x000);
++	/* ADC, OSC, Power Off mode Disable */
++	wm8739_write(client, R6, 0x000);
++	/* Digital Audio interface format:
++	   Enable Master mode, 24 bit, MSB first/left justified */
++	wm8739_write(client, R7, 0x049);
++	/* sampling control: normal, 256fs, 48KHz sampling rate */
++	wm8739_write(client, R8, 0x000);
++	/* activate */
++	wm8739_write(client, R9, 0x001);
++	/* set volume/mute */
++	wm8739_set_audio(client);
  	return 0;
  }
  
-@@ -304,17 +301,19 @@ static void generic_checkmode(struct CHIPSTATE *chip)
- 	if (mode == chip->prevmode)
- 	return;
+-static int wm8739_detach(struct i2c_client *client)
++static int wm8739_remove(struct i2c_client *client)
+ {
+-	struct wm8739_state *state = i2c_get_clientdata(client);
+-	int err;
+-
+-	err = i2c_detach_client(client);
+-	if (err)
+-		return err;
+-
+-	kfree(state);
+-	kfree(client);
++	kfree(i2c_get_clientdata(client));
+ 	return 0;
+ }
  
--	v4l_dbg(1, debug, &chip->c, "%s: thread checkmode\n", chip->c.name);
-+	v4l_dbg(1, debug, chip->c, "%s: thread checkmode\n", chip->c->name);
- 	chip->prevmode = mode;
+-/* ----------------------------------------------------------------------- */
+-
+-/* i2c implementation */
+-static struct i2c_driver i2c_driver = {
+-	.driver = {
+-		.name = "wm8739",
+-	},
+-	.id = I2C_DRIVERID_WM8739,
+-	.attach_adapter = wm8739_probe,
+-	.detach_client  = wm8739_detach,
++static struct v4l2_i2c_driver_data v4l2_i2c_data = {
++	.name = "wm8739",
++	.driverid = I2C_DRIVERID_WM8739,
+ 	.command = wm8739_command,
++	.probe = wm8739_probe,
++	.remove = wm8739_remove,
+ };
  
--	if (mode & VIDEO_SOUND_STEREO)
--		desc->setmode(chip,VIDEO_SOUND_STEREO);
--	else if (mode & VIDEO_SOUND_LANG1)
--		desc->setmode(chip,VIDEO_SOUND_LANG1);
--	else if (mode & VIDEO_SOUND_LANG2)
--		desc->setmode(chip,VIDEO_SOUND_LANG2);
-+	if (mode & V4L2_TUNER_MODE_STEREO)
-+		desc->setmode(chip,V4L2_TUNER_MODE_STEREO);
-+	if (mode & V4L2_TUNER_MODE_LANG1_LANG2)
-+		desc->setmode(chip,V4L2_TUNER_MODE_STEREO);
-+	else if (mode & V4L2_TUNER_MODE_LANG1)
-+		desc->setmode(chip,V4L2_TUNER_MODE_LANG1);
-+	else if (mode & V4L2_TUNER_MODE_LANG2)
-+		desc->setmode(chip,V4L2_TUNER_MODE_LANG2);
- 	else
--		desc->setmode(chip,VIDEO_SOUND_MONO);
-+		desc->setmode(chip,V4L2_TUNER_MODE_MONO);
- }
+-
+-static int __init wm8739_init_module(void)
+-{
+-	return i2c_add_driver(&i2c_driver);
+-}
+-
+-static void __exit wm8739_cleanup_module(void)
+-{
+-	i2c_del_driver(&i2c_driver);
+-}
+-
+-module_init(wm8739_init_module);
+-module_exit(wm8739_cleanup_module);
+diff --git a/drivers/media/video/wm8775.c b/drivers/media/video/wm8775.c
+index 9f7e894..869f9e7 100644
+--- a/drivers/media/video/wm8775.c
++++ b/drivers/media/video/wm8775.c
+@@ -34,6 +34,7 @@
+ #include <linux/videodev.h>
+ #include <media/v4l2-common.h>
+ #include <media/v4l2-chip-ident.h>
++#include <media/v4l2-i2c-drv-legacy.h>
  
- /* ---------------------------------------------------------------------- */
-@@ -345,13 +344,13 @@ static int tda9840_getmode(struct CHIPSTATE *chip)
- 	int val, mode;
+ MODULE_DESCRIPTION("wm8775 driver");
+ MODULE_AUTHOR("Ulf Eklund, Hans Verkuil");
+@@ -44,6 +45,7 @@ static unsigned short normal_i2c[] = { 0x36 >> 1, I2C_CLIENT_END };
  
- 	val = chip_read(chip);
--	mode = VIDEO_SOUND_MONO;
-+	mode = V4L2_TUNER_MODE_MONO;
- 	if (val & TDA9840_DS_DUAL)
--		mode |= VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
-+		mode |= V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2;
- 	if (val & TDA9840_ST_STEREO)
--		mode |= VIDEO_SOUND_STEREO;
-+		mode |= V4L2_TUNER_MODE_STEREO;
+ I2C_CLIENT_INSMOD;
  
--	v4l_dbg(1, debug, &chip->c, "tda9840_getmode(): raw chip read: %d, return: %d\n",
-+	v4l_dbg(1, debug, chip->c, "tda9840_getmode(): raw chip read: %d, return: %d\n",
- 		val, mode);
- 	return mode;
++
+ /* ----------------------------------------------------------------------- */
+ 
+ enum {
+@@ -66,18 +68,15 @@ static int wm8775_write(struct i2c_client *client, int reg, u16 val)
+ 		return -1;
+ 	}
+ 
+-	for (i = 0; i < 3; i++) {
+-		if (i2c_smbus_write_byte_data(client, (reg << 1) |
+-					(val >> 8), val & 0xff) == 0) {
++	for (i = 0; i < 3; i++)
++		if (i2c_smbus_write_byte_data(client,
++				(reg << 1) | (val >> 8), val & 0xff) == 0)
+ 			return 0;
+-		}
+-	}
+ 	v4l_err(client, "I2C: cannot write %03x to register R%d\n", val, reg);
+ 	return -1;
  }
-@@ -362,16 +361,16 @@ static void tda9840_setmode(struct CHIPSTATE *chip, int mode)
- 	int t = chip->shadow.bytes[TDA9840_SW + 1] & ~0x7e;
  
- 	switch (mode) {
--	case VIDEO_SOUND_MONO:
-+	case V4L2_TUNER_MODE_MONO:
- 		t |= TDA9840_MONO;
- 		break;
--	case VIDEO_SOUND_STEREO:
-+	case V4L2_TUNER_MODE_STEREO:
- 		t |= TDA9840_STEREO;
- 		break;
--	case VIDEO_SOUND_LANG1:
-+	case V4L2_TUNER_MODE_LANG1:
- 		t |= TDA9840_DUALA;
- 		break;
--	case VIDEO_SOUND_LANG2:
-+	case V4L2_TUNER_MODE_LANG2:
- 		t |= TDA9840_DUALB;
+-static int wm8775_command(struct i2c_client *client, unsigned int cmd,
+-			  void *arg)
++static int wm8775_command(struct i2c_client *client, unsigned cmd, void *arg)
+ {
+ 	struct wm8775_state *state = i2c_get_clientdata(client);
+ 	struct v4l2_routing *route = arg;
+@@ -126,7 +125,8 @@ static int wm8775_command(struct i2c_client *client, unsigned int cmd,
  		break;
- 	default:
-@@ -502,7 +501,7 @@ static int  tda985x_getmode(struct CHIPSTATE *chip)
- 		chip_read(chip)) >> 4;
- 	/* Add mono mode regardless of SAP and stereo */
- 	/* Allows forced mono */
--	return mode | VIDEO_SOUND_MONO;
-+	return mode | V4L2_TUNER_MODE_MONO;
- }
  
- static void tda985x_setmode(struct CHIPSTATE *chip, int mode)
-@@ -511,13 +510,13 @@ static void tda985x_setmode(struct CHIPSTATE *chip, int mode)
- 	int c6 = chip->shadow.bytes[TDA985x_C6+1] & 0x3f;
+ 	case VIDIOC_G_CHIP_IDENT:
+-		return v4l2_chip_ident_i2c_client(client, arg, V4L2_IDENT_WM8775, 0);
++		return v4l2_chip_ident_i2c_client(client,
++				arg, V4L2_IDENT_WM8775, 0);
  
- 	switch (mode) {
--	case VIDEO_SOUND_MONO:
-+	case V4L2_TUNER_MODE_MONO:
- 		c6 |= TDA985x_MONO;
- 		break;
--	case VIDEO_SOUND_STEREO:
-+	case V4L2_TUNER_MODE_STEREO:
- 		c6 |= TDA985x_STEREO;
- 		break;
--	case VIDEO_SOUND_LANG1:
-+	case V4L2_TUNER_MODE_LANG1:
- 		c6 |= TDA985x_SAP;
- 		break;
- 	default:
-@@ -650,12 +649,12 @@ static int tda9873_getmode(struct CHIPSTATE *chip)
- 	int val,mode;
+ 	case VIDIOC_LOG_STATUS:
+ 		v4l_info(client, "Input: %d%s\n", state->input,
+@@ -159,105 +159,67 @@ static int wm8775_command(struct i2c_client *client, unsigned int cmd,
+  * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
+  */
  
- 	val = chip_read(chip);
--	mode = VIDEO_SOUND_MONO;
-+	mode = V4L2_TUNER_MODE_MONO;
- 	if (val & TDA9873_STEREO)
--		mode |= VIDEO_SOUND_STEREO;
-+		mode |= V4L2_TUNER_MODE_STEREO;
- 	if (val & TDA9873_DUAL)
--		mode |= VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
--	v4l_dbg(1, debug, &chip->c, "tda9873_getmode(): raw chip read: %d, return: %d\n",
-+		mode |= V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2;
-+	v4l_dbg(1, debug, chip->c, "tda9873_getmode(): raw chip read: %d, return: %d\n",
- 		val, mode);
- 	return mode;
- }
-@@ -666,24 +665,24 @@ static void tda9873_setmode(struct CHIPSTATE *chip, int mode)
- 	/*	int adj_data = chip->shadow.bytes[TDA9873_AD+1] ; */
+-static struct i2c_driver i2c_driver;
+-
+-static int wm8775_attach(struct i2c_adapter *adapter, int address, int kind)
++static int wm8775_probe(struct i2c_client *client)
+ {
+-	struct i2c_client *client;
+ 	struct wm8775_state *state;
  
- 	if ((sw_data & TDA9873_INP_MASK) != TDA9873_INTERNAL) {
--		v4l_dbg(1, debug, &chip->c, "tda9873_setmode(): external input\n");
-+		v4l_dbg(1, debug, chip->c, "tda9873_setmode(): external input\n");
- 		return;
- 	}
+ 	/* Check if the adapter supports the needed features */
+-	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+-		return 0;
+-
+-	client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
+-	if (client == 0)
+-		return -ENOMEM;
+-
+-	client->addr = address;
+-	client->adapter = adapter;
+-	client->driver = &i2c_driver;
+-	snprintf(client->name, sizeof(client->name) - 1, "wm8775");
++	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
++		return -EIO;
  
--	v4l_dbg(1, debug, &chip->c, "tda9873_setmode(): chip->shadow.bytes[%d] = %d\n", TDA9873_SW+1, chip->shadow.bytes[TDA9873_SW+1]);
--	v4l_dbg(1, debug, &chip->c, "tda9873_setmode(): sw_data  = %d\n", sw_data);
-+	v4l_dbg(1, debug, chip->c, "tda9873_setmode(): chip->shadow.bytes[%d] = %d\n", TDA9873_SW+1, chip->shadow.bytes[TDA9873_SW+1]);
-+	v4l_dbg(1, debug, chip->c, "tda9873_setmode(): sw_data  = %d\n", sw_data);
+-	v4l_info(client, "chip found @ 0x%x (%s)\n", address << 1, adapter->name);
++	v4l_info(client, "chip found @ 0x%x (%s)\n",
++			client->addr << 1, client->adapter->name);
  
- 	switch (mode) {
--	case VIDEO_SOUND_MONO:
-+	case V4L2_TUNER_MODE_MONO:
- 		sw_data |= TDA9873_TR_MONO;
- 		break;
--	case VIDEO_SOUND_STEREO:
-+	case V4L2_TUNER_MODE_STEREO:
- 		sw_data |= TDA9873_TR_STEREO;
- 		break;
--	case VIDEO_SOUND_LANG1:
-+	case V4L2_TUNER_MODE_LANG1:
- 		sw_data |= TDA9873_TR_DUALA;
- 		break;
--	case VIDEO_SOUND_LANG2:
-+	case V4L2_TUNER_MODE_LANG2:
- 		sw_data |= TDA9873_TR_DUALB;
- 		break;
- 	default:
-@@ -692,7 +691,7 @@ static void tda9873_setmode(struct CHIPSTATE *chip, int mode)
- 	}
+ 	state = kmalloc(sizeof(struct wm8775_state), GFP_KERNEL);
+-	if (state == NULL) {
+-		kfree(client);
++	if (state == NULL)
+ 		return -ENOMEM;
+-	}
+ 	state->input = 2;
+ 	state->muted = 0;
+ 	i2c_set_clientdata(client, state);
  
- 	chip_write(chip, TDA9873_SW, sw_data);
--	v4l_dbg(1, debug, &chip->c, "tda9873_setmode(): req. mode %d; chip_write: %d\n",
-+	v4l_dbg(1, debug, chip->c, "tda9873_setmode(): req. mode %d; chip_write: %d\n",
- 		mode, sw_data);
+-	/* initialize wm8775 */
+-	wm8775_write(client, R23, 0x000);	/* RESET */
+-	wm8775_write(client, R7, 0x000);	/* Disable zero cross detect timeout */
+-	wm8775_write(client, R11, 0x021);	/* Left justified, 24-bit mode */
+-	wm8775_write(client, R12, 0x102);	/* Master mode, clock ratio 256fs */
+-	wm8775_write(client, R13, 0x000);	/* Powered up */
+-	wm8775_write(client, R14, 0x1d4);	/* ADC gain +2.5dB, enable zero cross */
+-	wm8775_write(client, R15, 0x1d4);	/* ADC gain +2.5dB, enable zero cross */
+-	wm8775_write(client, R16, 0x1bf);	/* ALC Stereo, ALC target level -1dB FS */
+-	/* max gain +8dB */
+-	wm8775_write(client, R17, 0x185);	/* Enable gain control, use zero cross */
+-	/* detection, ALC hold time 42.6 ms */
+-	wm8775_write(client, R18, 0x0a2);	/* ALC gain ramp up delay 34 s, */
+-	/* ALC gain ramp down delay 33 ms */
+-	wm8775_write(client, R19, 0x005);	/* Enable noise gate, threshold -72dBfs */
+-	wm8775_write(client, R20, 0x07a);	/* Transient window 4ms, lower PGA gain */
+-	/* limit -1dB */
+-	wm8775_write(client, R21, 0x102);	/* LRBOTH = 1, use input 2. */
+-	i2c_attach_client(client);
+-
++	/* Initialize wm8775 */
++
++	/* RESET */
++	wm8775_write(client, R23, 0x000);
++	/* Disable zero cross detect timeout */
++	wm8775_write(client, R7, 0x000);
++	/* Left justified, 24-bit mode */
++	wm8775_write(client, R11, 0x021);
++	/* Master mode, clock ratio 256fs */
++	wm8775_write(client, R12, 0x102);
++	/* Powered up */
++	wm8775_write(client, R13, 0x000);
++	/* ADC gain +2.5dB, enable zero cross */
++	wm8775_write(client, R14, 0x1d4);
++	/* ADC gain +2.5dB, enable zero cross */
++	wm8775_write(client, R15, 0x1d4);
++	/* ALC Stereo, ALC target level -1dB FS max gain +8dB */
++	wm8775_write(client, R16, 0x1bf);
++	/* Enable gain control, use zero cross detection,
++	   ALC hold time 42.6 ms */
++	wm8775_write(client, R17, 0x185);
++	/* ALC gain ramp up delay 34 s, ALC gain ramp down delay 33 ms */
++	wm8775_write(client, R18, 0x0a2);
++	/* Enable noise gate, threshold -72dBfs */
++	wm8775_write(client, R19, 0x005);
++	/* Transient window 4ms, lower PGA gain limit -1dB */
++	wm8775_write(client, R20, 0x07a);
++	/* LRBOTH = 1, use input 2. */
++	wm8775_write(client, R21, 0x102);
+ 	return 0;
  }
  
-@@ -831,7 +830,7 @@ static int tda9874a_setup(struct CHIPSTATE *chip)
- 		chip_write(chip, TDA9874A_SDACOSR, (tda9874a_mode) ? 0x81:0x80);
- 		chip_write(chip, TDA9874A_AOSR, 0x00); /* or 0x10 */
- 	}
--	v4l_dbg(1, debug, &chip->c, "tda9874a_setup(): %s [0x%02X].\n",
-+	v4l_dbg(1, debug, chip->c, "tda9874a_setup(): %s [0x%02X].\n",
- 		tda9874a_modelist[tda9874a_STD].name,tda9874a_STD);
- 	return 1;
+-static int wm8775_probe(struct i2c_adapter *adapter)
++static int wm8775_remove(struct i2c_client *client)
+ {
+-	if (adapter->class & I2C_CLASS_TV_ANALOG)
+-		return i2c_probe(adapter, &addr_data, wm8775_attach);
++	kfree(i2c_get_clientdata(client));
+ 	return 0;
  }
-@@ -841,7 +840,7 @@ static int tda9874a_getmode(struct CHIPSTATE *chip)
- 	int dsr,nsr,mode;
- 	int necr; /* just for debugging */
- 
--	mode = VIDEO_SOUND_MONO;
-+	mode = V4L2_TUNER_MODE_MONO;
  
- 	if(-1 == (dsr = chip_read2(chip,TDA9874A_DSR)))
- 		return mode;
-@@ -860,21 +859,21 @@ static int tda9874a_getmode(struct CHIPSTATE *chip)
- 		 * that sound has (temporarily) switched from NICAM to
- 		 * mono FM (or AM) on 1st sound carrier due to high NICAM bit
- 		 * error count. So in fact there is no stereo in this case :-(
--		 * But changing the mode to VIDEO_SOUND_MONO would switch
-+		 * But changing the mode to V4L2_TUNER_MODE_MONO would switch
- 		 * external 4052 multiplexer in audio_hook().
- 		 */
- 		if(nsr & 0x02) /* NSR.S/MB=1 */
--			mode |= VIDEO_SOUND_STEREO;
-+			mode |= V4L2_TUNER_MODE_STEREO;
- 		if(nsr & 0x01) /* NSR.D/SB=1 */
--			mode |= VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
-+			mode |= V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2;
- 	} else {
- 		if(dsr & 0x02) /* DSR.IDSTE=1 */
--			mode |= VIDEO_SOUND_STEREO;
-+			mode |= V4L2_TUNER_MODE_STEREO;
- 		if(dsr & 0x04) /* DSR.IDDUA=1 */
--			mode |= VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
-+			mode |= V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2;
- 	}
+-static int wm8775_detach(struct i2c_client *client)
+-{
+-	struct wm8775_state *state = i2c_get_clientdata(client);
+-	int err;
+-
+-	err = i2c_detach_client(client);
+-	if (err) {
+-		return err;
+-	}
+-	kfree(state);
+-	kfree(client);
+-
+-	return 0;
+-}
+-
+-/* ----------------------------------------------------------------------- */
+-
+-/* i2c implementation */
+-static struct i2c_driver i2c_driver = {
+-	.driver = {
+-		.name = "wm8775",
+-	},
+-	.id             = I2C_DRIVERID_WM8775,
+-	.attach_adapter = wm8775_probe,
+-	.detach_client  = wm8775_detach,
+-	.command        = wm8775_command,
++static struct v4l2_i2c_driver_data v4l2_i2c_data = {
++	.name = "wm8775",
++	.driverid = I2C_DRIVERID_WM8775,
++	.command = wm8775_command,
++	.probe = wm8775_probe,
++	.remove = wm8775_remove,
+ };
  
--	v4l_dbg(1, debug, &chip->c, "tda9874a_getmode(): DSR=0x%X, NSR=0x%X, NECR=0x%X, return: %d.\n",
-+	v4l_dbg(1, debug, chip->c, "tda9874a_getmode(): DSR=0x%X, NSR=0x%X, NECR=0x%X, return: %d.\n",
- 		 dsr, nsr, necr, mode);
- 	return mode;
+-
+-static int __init wm8775_init_module(void)
+-{
+-	return i2c_add_driver(&i2c_driver);
+-}
+-
+-static void __exit wm8775_cleanup_module(void)
+-{
+-	i2c_del_driver(&i2c_driver);
+-}
+-
+-module_init(wm8775_init_module);
+-module_exit(wm8775_cleanup_module);
+diff --git a/drivers/media/video/zr364xx.c b/drivers/media/video/zr364xx.c
+index 6f18925..1fdbb46 100644
+--- a/drivers/media/video/zr364xx.c
++++ b/drivers/media/video/zr364xx.c
+@@ -749,7 +749,7 @@ static int zr364xx_mmap(struct file *file, struct vm_area_struct *vma)
  }
-@@ -902,14 +901,14 @@ static void tda9874a_setmode(struct CHIPSTATE *chip, int mode)
- 		int mdacosr = (tda9874a_mode) ? 0x82:0x80;
  
- 		switch(mode) {
--		case VIDEO_SOUND_MONO:
--		case VIDEO_SOUND_STEREO:
-+		case V4L2_TUNER_MODE_MONO:
-+		case V4L2_TUNER_MODE_STEREO:
- 			break;
--		case VIDEO_SOUND_LANG1:
-+		case V4L2_TUNER_MODE_LANG1:
- 			aosr = 0x80; /* auto-select, dual A/A */
- 			mdacosr = (tda9874a_mode) ? 0x82:0x80;
- 			break;
--		case VIDEO_SOUND_LANG2:
-+		case V4L2_TUNER_MODE_LANG2:
- 			aosr = 0xa0; /* auto-select, dual B/B */
- 			mdacosr = (tda9874a_mode) ? 0x83:0x81;
- 			break;
-@@ -920,18 +919,18 @@ static void tda9874a_setmode(struct CHIPSTATE *chip, int mode)
- 		chip_write(chip, TDA9874A_AOSR, aosr);
- 		chip_write(chip, TDA9874A_MDACOSR, mdacosr);
  
--		v4l_dbg(1, debug, &chip->c, "tda9874a_setmode(): req. mode %d; AOSR=0x%X, MDACOSR=0x%X.\n",
-+		v4l_dbg(1, debug, chip->c, "tda9874a_setmode(): req. mode %d; AOSR=0x%X, MDACOSR=0x%X.\n",
- 			mode, aosr, mdacosr);
+-static struct file_operations zr364xx_fops = {
++static const struct file_operations zr364xx_fops = {
+ 	.owner = THIS_MODULE,
+ 	.open = zr364xx_open,
+ 	.release = zr364xx_release,
+diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c
+index 52fb216..425f60c 100644
+--- a/drivers/message/fusion/mptbase.c
++++ b/drivers/message/fusion/mptbase.c
+@@ -2056,7 +2056,7 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
+ 						ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ 						    "mpt_upload:  alt_%s has cached_fw=%p \n",
+ 						    ioc->name, ioc->alt_ioc->name, ioc->alt_ioc->cached_fw));
+-						ioc->alt_ioc->cached_fw = NULL;
++						ioc->cached_fw = NULL;
+ 					}
+ 				} else {
+ 					printk(MYIOC_s_WARN_FMT
+@@ -2262,10 +2262,12 @@ mpt_adapter_disable(MPT_ADAPTER *ioc)
+ 	int ret;
  
- 	} else { /* dic == 0x07 */
- 		int fmmr,aosr;
+ 	if (ioc->cached_fw != NULL) {
+-		ddlprintk(ioc, printk(MYIOC_s_INFO_FMT
+-		    "mpt_adapter_disable: Pushing FW onto adapter\n", ioc->name));
+-		if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *)ioc->cached_fw, NO_SLEEP)) < 0) {
+-			printk(MYIOC_s_WARN_FMT "firmware downloadboot failure (%d)!\n",
++		ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: Pushing FW onto "
++		    "adapter\n", __FUNCTION__, ioc->name));
++		if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *)
++		    ioc->cached_fw, CAN_SLEEP)) < 0) {
++			printk(MYIOC_s_WARN_FMT
++			    ": firmware downloadboot failure (%d)!\n",
+ 			    ioc->name, ret);
+ 		}
+ 	}
+@@ -2303,13 +2305,7 @@ mpt_adapter_disable(MPT_ADAPTER *ioc)
+ 		ioc->alloc_total -= sz;
+ 	}
  
- 		switch(mode) {
--		case VIDEO_SOUND_MONO:
-+		case V4L2_TUNER_MODE_MONO:
- 			fmmr = 0x00; /* mono */
- 			aosr = 0x10; /* A/A */
- 			break;
--		case VIDEO_SOUND_STEREO:
-+		case V4L2_TUNER_MODE_STEREO:
- 			if(tda9874a_mode) {
- 				fmmr = 0x00;
- 				aosr = 0x00; /* handled by NICAM auto-mute */
-@@ -940,11 +939,11 @@ static void tda9874a_setmode(struct CHIPSTATE *chip, int mode)
- 				aosr = 0x00;
- 			}
- 			break;
--		case VIDEO_SOUND_LANG1:
-+		case V4L2_TUNER_MODE_LANG1:
- 			fmmr = 0x02; /* dual */
- 			aosr = 0x10; /* dual A/A */
- 			break;
--		case VIDEO_SOUND_LANG2:
-+		case V4L2_TUNER_MODE_LANG2:
- 			fmmr = 0x02; /* dual */
- 			aosr = 0x20; /* dual B/B */
- 			break;
-@@ -955,7 +954,7 @@ static void tda9874a_setmode(struct CHIPSTATE *chip, int mode)
- 		chip_write(chip, TDA9874A_FMMR, fmmr);
- 		chip_write(chip, TDA9874A_AOSR, aosr);
+-	if (ioc->cached_fw != NULL) {
+-		sz = ioc->facts.FWImageSize;
+-		pci_free_consistent(ioc->pcidev, sz,
+-			ioc->cached_fw, ioc->cached_fw_dma);
+-		ioc->cached_fw = NULL;
+-		ioc->alloc_total -= sz;
+-	}
++	mpt_free_fw_memory(ioc);
  
--		v4l_dbg(1, debug, &chip->c, "tda9874a_setmode(): req. mode %d; FMMR=0x%X, AOSR=0x%X.\n",
-+		v4l_dbg(1, debug, chip->c, "tda9874a_setmode(): req. mode %d; FMMR=0x%X, AOSR=0x%X.\n",
- 			mode, fmmr, aosr);
+ 	kfree(ioc->spi_data.nvram);
+ 	mpt_inactive_raid_list_free(ioc);
+@@ -3047,44 +3043,62 @@ SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
+  *
+  *	If memory has already been allocated, the same (cached) value
+  *	is returned.
+- */
+-void
++ *
++ *	Return 0 if successfull, or non-zero for failure
++ **/
++int
+ mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size)
+ {
+-	if (ioc->cached_fw)
+-		return;  /* use already allocated memory */
+-	if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
++	int rc;
++
++	if (ioc->cached_fw) {
++		rc = 0;  /* use already allocated memory */
++		goto out;
++	}
++	else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
+ 		ioc->cached_fw = ioc->alt_ioc->cached_fw;  /* use alt_ioc's memory */
+ 		ioc->cached_fw_dma = ioc->alt_ioc->cached_fw_dma;
+-		ioc->alloc_total += size;
+-		ioc->alt_ioc->alloc_total -= size;
++		rc = 0;
++		goto out;
++	}
++	ioc->cached_fw = pci_alloc_consistent(ioc->pcidev, size, &ioc->cached_fw_dma);
++	if (!ioc->cached_fw) {
++		printk(MYIOC_s_ERR_FMT "Unable to allocate memory for the cached firmware image!\n",
++		    ioc->name);
++		rc = -1;
+ 	} else {
+-		if ( (ioc->cached_fw = pci_alloc_consistent(ioc->pcidev, size, &ioc->cached_fw_dma) ) )
+-			ioc->alloc_total += size;
++		dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FW Image  @ %p[%p], sz=%d[%x] bytes\n",
++		    ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, size, size));
++		ioc->alloc_total += size;
++		rc = 0;
  	}
++ out:
++	return rc;
  }
-@@ -969,10 +968,10 @@ static int tda9874a_checkit(struct CHIPSTATE *chip)
- 	if(-1 == (sic = chip_read2(chip,TDA9874A_SIC)))
++
+ /**
+  *	mpt_free_fw_memory - free firmware memory
+  *	@ioc: Pointer to MPT_ADAPTER structure
+  *
+  *	If alt_img is NULL, delete from ioc structure.
+  *	Else, delete a secondary image in same format.
+- */
++ **/
+ void
+ mpt_free_fw_memory(MPT_ADAPTER *ioc)
+ {
+ 	int sz;
+ 
++	if (!ioc->cached_fw)
++		return;
++
+ 	sz = ioc->facts.FWImageSize;
+-	dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "free_fw_memory: FW Image  @ %p[%p], sz=%d[%x] bytes\n",
+-	    ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
++	dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "free_fw_memory: FW Image  @ %p[%p], sz=%d[%x] bytes\n",
++		 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
+ 	pci_free_consistent(ioc->pcidev, sz, ioc->cached_fw, ioc->cached_fw_dma);
++	ioc->alloc_total -= sz;
+ 	ioc->cached_fw = NULL;
+-
+-	return;
+ }
+ 
+-
+ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+ /**
+  *	mpt_do_upload - Construct and Send FWUpload request to MPT adapter port.
+@@ -3116,17 +3130,12 @@ mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
+ 	if ((sz = ioc->facts.FWImageSize) == 0)
  		return 0;
  
--	v4l_dbg(1, debug, &chip->c, "tda9874a_checkit(): DIC=0x%X, SIC=0x%X.\n", dic, sic);
-+	v4l_dbg(1, debug, chip->c, "tda9874a_checkit(): DIC=0x%X, SIC=0x%X.\n", dic, sic);
+-	mpt_alloc_fw_memory(ioc, sz);
++	if (mpt_alloc_fw_memory(ioc, ioc->facts.FWImageSize) != 0)
++		return -ENOMEM;
+ 
+ 	dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": FW Image  @ %p[%p], sz=%d[%x] bytes\n",
+ 	    ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
+ 
+-	if (ioc->cached_fw == NULL) {
+-		/* Major Failure.
+-		 */
+-		return -ENOMEM;
+-	}
+-
+ 	prequest = (sleepFlag == NO_SLEEP) ? kzalloc(ioc->req_sz, GFP_ATOMIC) :
+ 	    kzalloc(ioc->req_sz, GFP_KERNEL);
+ 	if (!prequest) {
+@@ -3498,12 +3507,12 @@ KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag)
+ static int
+ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
+ {
+-	MPT_ADAPTER	*iocp=NULL;
+ 	u32 diag0val;
+ 	u32 doorbell;
+ 	int hard_reset_done = 0;
+ 	int count = 0;
+ 	u32 diag1val = 0;
++	MpiFwHeader_t *cached_fw;	/* Pointer to FW */
+ 
+ 	/* Clear any existing interrupts */
+ 	CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
+@@ -3635,22 +3644,24 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
+ 		}
+ 
+ 		if (ioc->cached_fw)
+-			iocp = ioc;
++			cached_fw = (MpiFwHeader_t *)ioc->cached_fw;
+ 		else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw)
+-			iocp = ioc->alt_ioc;
+-		if (iocp) {
++			cached_fw = (MpiFwHeader_t *)ioc->alt_ioc->cached_fw;
++		else
++			cached_fw = NULL;
++		if (cached_fw) {
+ 			/* If the DownloadBoot operation fails, the
+ 			 * IOC will be left unusable. This is a fatal error
+ 			 * case.  _diag_reset will return < 0
+ 			 */
+ 			for (count = 0; count < 30; count ++) {
+-				diag0val = CHIPREG_READ32(&iocp->chip->Diagnostic);
++				diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
+ 				if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
+ 					break;
+ 				}
+ 
+ 				dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "cached_fw: diag0val=%x count=%d\n",
+-					iocp->name, diag0val, count));
++					ioc->name, diag0val, count));
+ 				/* wait 1 sec */
+ 				if (sleepFlag == CAN_SLEEP) {
+ 					msleep (1000);
+@@ -3658,8 +3669,7 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
+ 					mdelay (1000);
+ 				}
+ 			}
+-			if ((count = mpt_downloadboot(ioc,
+-				(MpiFwHeader_t *)iocp->cached_fw, sleepFlag)) < 0) {
++			if ((count = mpt_downloadboot(ioc, cached_fw, sleepFlag)) < 0) {
+ 				printk(MYIOC_s_WARN_FMT
+ 					"firmware downloadboot failure (%d)!\n", ioc->name, count);
+ 			}
+diff --git a/drivers/message/fusion/mptbase.h b/drivers/message/fusion/mptbase.h
+index d7682e0..b49b706 100644
+--- a/drivers/message/fusion/mptbase.h
++++ b/drivers/message/fusion/mptbase.h
+@@ -907,7 +907,7 @@ extern u32	 mpt_GetIocState(MPT_ADAPTER *ioc, int cooked);
+ extern void	 mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buf, int *size, int len, int showlan);
+ extern int	 mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag);
+ extern int	 mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *cfg);
+-extern void	 mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size);
++extern int	 mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size);
+ extern void	 mpt_free_fw_memory(MPT_ADAPTER *ioc);
+ extern int	 mpt_findImVolumes(MPT_ADAPTER *ioc);
+ extern int	 mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode);
+diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c
+index e4c94f9..f77b329 100644
+--- a/drivers/message/fusion/mptsas.c
++++ b/drivers/message/fusion/mptsas.c
+@@ -1343,6 +1343,8 @@ static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
+ 		smprep = (SmpPassthroughReply_t *)ioc->sas_mgmt.reply;
+ 		memcpy(req->sense, smprep, sizeof(*smprep));
+ 		req->sense_len = sizeof(*smprep);
++		req->data_len = 0;
++		rsp->data_len -= smprep->ResponseDataLength;
+ 	} else {
+ 		printk(MYIOC_s_ERR_FMT "%s: smp passthru reply failed to be returned\n",
+ 		    ioc->name, __FUNCTION__);
+diff --git a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c
+index 626bb3c..5c614ec 100644
+--- a/drivers/message/fusion/mptscsih.c
++++ b/drivers/message/fusion/mptscsih.c
+@@ -111,7 +111,7 @@ int 		mptscsih_suspend(struct pci_dev *pdev, pm_message_t state);
+ int 		mptscsih_resume(struct pci_dev *pdev);
+ #endif
+ 
+-#define SNS_LEN(scp)	sizeof((scp)->sense_buffer)
++#define SNS_LEN(scp)	SCSI_SENSE_BUFFERSIZE
  
- 	if((dic == 0x11)||(dic == 0x07)) {
--		v4l_info(&chip->c, "found tda9874%s.\n", (dic == 0x11) ? "a":"h");
-+		v4l_info(chip->c, "found tda9874%s.\n", (dic == 0x11) ? "a":"h");
- 		tda9874a_dic = dic;	/* remember device id. */
- 		return 1;
- 	}
-@@ -1095,7 +1094,7 @@ static int tda8425_initialize(struct CHIPSTATE *chip)
- 	int inputmap[4] = { /* tuner	*/ TDA8425_S1_CH2, /* radio  */ TDA8425_S1_CH1,
- 			    /* extern	*/ TDA8425_S1_CH1, /* intern */ TDA8425_S1_OFF};
+ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+ /**
+diff --git a/drivers/message/i2o/i2o_block.c b/drivers/message/i2o/i2o_block.c
+index e4ad7a1..a953148 100644
+--- a/drivers/message/i2o/i2o_block.c
++++ b/drivers/message/i2o/i2o_block.c
+@@ -412,13 +412,13 @@ static void i2o_block_delayed_request_fn(struct work_struct *work)
+ /**
+  *	i2o_block_end_request - Post-processing of completed commands
+  *	@req: request which should be completed
+- *	@uptodate: 1 for success, 0 for I/O error, < 0 for specific error
++ *	@error: 0 for success, < 0 for error
+  *	@nr_bytes: number of bytes to complete
+  *
+  *	Mark the request as complete. The lock must not be held when entering.
+  *
+  */
+-static void i2o_block_end_request(struct request *req, int uptodate,
++static void i2o_block_end_request(struct request *req, int error,
+ 				  int nr_bytes)
+ {
+ 	struct i2o_block_request *ireq = req->special;
+@@ -426,22 +426,18 @@ static void i2o_block_end_request(struct request *req, int uptodate,
+ 	struct request_queue *q = req->q;
+ 	unsigned long flags;
  
--	if (chip->c.adapter->id == I2C_HW_B_RIVA) {
-+	if (chip->c->adapter->id == I2C_HW_B_RIVA) {
- 		memcpy (desc->inputmap, inputmap, sizeof (inputmap));
+-	if (end_that_request_chunk(req, uptodate, nr_bytes)) {
++	if (blk_end_request(req, error, nr_bytes)) {
+ 		int leftover = (req->hard_nr_sectors << KERNEL_SECTOR_SHIFT);
+ 
+ 		if (blk_pc_request(req))
+ 			leftover = req->data_len;
+ 
+-		if (end_io_error(uptodate))
+-			end_that_request_chunk(req, 0, leftover);
++		if (error)
++			blk_end_request(req, -EIO, leftover);
  	}
- 	return 0;
-@@ -1105,20 +1104,20 @@ static void tda8425_setmode(struct CHIPSTATE *chip, int mode)
- {
- 	int s1 = chip->shadow.bytes[TDA8425_S1+1] & 0xe1;
  
--	if (mode & VIDEO_SOUND_LANG1) {
-+	if (mode & V4L2_TUNER_MODE_LANG1) {
- 		s1 |= TDA8425_S1_ML_SOUND_A;
- 		s1 |= TDA8425_S1_STEREO_PSEUDO;
+-	add_disk_randomness(req->rq_disk);
+-
+ 	spin_lock_irqsave(q->queue_lock, flags);
  
--	} else if (mode & VIDEO_SOUND_LANG2) {
-+	} else if (mode & V4L2_TUNER_MODE_LANG2) {
- 		s1 |= TDA8425_S1_ML_SOUND_B;
- 		s1 |= TDA8425_S1_STEREO_PSEUDO;
+-	end_that_request_last(req, uptodate);
+-
+ 	if (likely(dev)) {
+ 		dev->open_queue_depth--;
+ 		list_del(&ireq->queue);
+@@ -468,7 +464,7 @@ static int i2o_block_reply(struct i2o_controller *c, u32 m,
+ 			   struct i2o_message *msg)
+ {
+ 	struct request *req;
+-	int uptodate = 1;
++	int error = 0;
  
- 	} else {
- 		s1 |= TDA8425_S1_ML_STEREO;
+ 	req = i2o_cntxt_list_get(c, le32_to_cpu(msg->u.s.tcntxt));
+ 	if (unlikely(!req)) {
+@@ -501,10 +497,10 @@ static int i2o_block_reply(struct i2o_controller *c, u32 m,
  
--		if (mode & VIDEO_SOUND_MONO)
-+		if (mode & V4L2_TUNER_MODE_MONO)
- 			s1 |= TDA8425_S1_STEREO_MONO;
--		if (mode & VIDEO_SOUND_STEREO)
-+		if (mode & V4L2_TUNER_MODE_STEREO)
- 			s1 |= TDA8425_S1_STEREO_SPATIAL;
- 	}
- 	chip_write(chip,TDA8425_S1,s1);
-@@ -1177,13 +1176,13 @@ static int ta8874z_getmode(struct CHIPSTATE *chip)
- 	int val, mode;
+ 		req->errors++;
  
- 	val = chip_read(chip);
--	mode = VIDEO_SOUND_MONO;
-+	mode = V4L2_TUNER_MODE_MONO;
- 	if (val & TA8874Z_B1){
--		mode |= VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
-+		mode |= V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2;
- 	}else if (!(val & TA8874Z_B0)){
--		mode |= VIDEO_SOUND_STEREO;
-+		mode |= V4L2_TUNER_MODE_STEREO;
+-		uptodate = 0;
++		error = -EIO;
  	}
--	/* v4l_dbg(1, debug, &chip->c, "ta8874z_getmode(): raw chip read: 0x%02x, return: 0x%02x\n", val, mode); */
-+	/* v4l_dbg(1, debug, chip->c, "ta8874z_getmode(): raw chip read: 0x%02x, return: 0x%02x\n", val, mode); */
- 	return mode;
- }
- 
-@@ -1196,19 +1195,19 @@ static void ta8874z_setmode(struct CHIPSTATE *chip, int mode)
- {
- 	int update = 1;
- 	audiocmd *t = NULL;
--	v4l_dbg(1, debug, &chip->c, "ta8874z_setmode(): mode: 0x%02x\n", mode);
-+	v4l_dbg(1, debug, chip->c, "ta8874z_setmode(): mode: 0x%02x\n", mode);
  
- 	switch(mode){
--	case VIDEO_SOUND_MONO:
-+	case V4L2_TUNER_MODE_MONO:
- 		t = &ta8874z_mono;
- 		break;
--	case VIDEO_SOUND_STEREO:
-+	case V4L2_TUNER_MODE_STEREO:
- 		t = &ta8874z_stereo;
- 		break;
--	case VIDEO_SOUND_LANG1:
-+	case V4L2_TUNER_MODE_LANG1:
- 		t = &ta8874z_main;
- 		break;
--	case VIDEO_SOUND_LANG2:
-+	case V4L2_TUNER_MODE_LANG2:
- 		t = &ta8874z_sub;
- 		break;
- 	default:
-@@ -1462,51 +1461,55 @@ static struct CHIPDESC chiplist[] = {
- /* ---------------------------------------------------------------------- */
- /* i2c registration                                                       */
+-	i2o_block_end_request(req, uptodate, le32_to_cpu(msg->body[1]));
++	i2o_block_end_request(req, error, le32_to_cpu(msg->body[1]));
  
--static int chip_attach(struct i2c_adapter *adap, int addr, int kind)
-+static int chip_probe(struct i2c_client *client)
- {
- 	struct CHIPSTATE *chip;
- 	struct CHIPDESC  *desc;
+ 	return 1;
+ };
+diff --git a/drivers/message/i2o/i2o_scsi.c b/drivers/message/i2o/i2o_scsi.c
+index aa6fb94..1bcdbbb 100644
+--- a/drivers/message/i2o/i2o_scsi.c
++++ b/drivers/message/i2o/i2o_scsi.c
+@@ -370,7 +370,7 @@ static int i2o_scsi_reply(struct i2o_controller *c, u32 m,
+ 	 */
+ 	if (cmd->result)
+ 		memcpy(cmd->sense_buffer, &msg->body[3],
+-		       min(sizeof(cmd->sense_buffer), (size_t) 40));
++		       min(SCSI_SENSE_BUFFERSIZE, 40));
  
-+	if (debug) {
-+		printk(KERN_INFO "tvaudio: TV audio decoder + audio/video mux driver\n");
-+		printk(KERN_INFO "tvaudio: known chips: ");
-+		for (desc = chiplist; desc->name != NULL; desc++)
-+			printk("%s%s", (desc == chiplist) ? "" : ", ", desc->name);
-+		printk("\n");
-+	}
-+
- 	chip = kzalloc(sizeof(*chip),GFP_KERNEL);
- 	if (!chip)
- 		return -ENOMEM;
--	memcpy(&chip->c,&client_template,sizeof(struct i2c_client));
--	chip->c.adapter = adap;
--	chip->c.addr = addr;
--	i2c_set_clientdata(&chip->c, chip);
-+	chip->c = client;
-+	i2c_set_clientdata(client, chip);
+ 	/* only output error code if AdapterStatus is not HBA_SUCCESS */
+ 	if ((error >> 8) & 0xff)
+diff --git a/drivers/mfd/ucb1x00-assabet.c b/drivers/mfd/ucb1x00-assabet.c
+index e325fa7..61aeaf7 100644
+--- a/drivers/mfd/ucb1x00-assabet.c
++++ b/drivers/mfd/ucb1x00-assabet.c
+@@ -20,7 +20,8 @@
+ #include "ucb1x00.h"
  
- 	/* find description for the chip */
--	v4l_dbg(1, debug, &chip->c, "chip found @ 0x%x\n", addr<<1);
-+	v4l_dbg(1, debug, client, "chip found @ 0x%x\n", client->addr<<1);
- 	for (desc = chiplist; desc->name != NULL; desc++) {
- 		if (0 == *(desc->insmodopt))
- 			continue;
--		if (addr < desc->addr_lo ||
--		    addr > desc->addr_hi)
-+		if (client->addr < desc->addr_lo ||
-+		    client->addr > desc->addr_hi)
- 			continue;
- 		if (desc->checkit && !desc->checkit(chip))
- 			continue;
- 		break;
- 	}
- 	if (desc->name == NULL) {
--		v4l_dbg(1, debug, &chip->c, "no matching chip description found\n");
-+		v4l_dbg(1, debug, client, "no matching chip description found\n");
- 		return -EIO;
- 	}
--	v4l_info(&chip->c, "%s found @ 0x%x (%s)\n", desc->name, addr<<1, adap->name);
-+	v4l_info(client, "%s found @ 0x%x (%s)\n", desc->name, client->addr<<1, client->adapter->name);
- 	if (desc->flags) {
--		v4l_dbg(1, debug, &chip->c, "matches:%s%s%s.\n",
-+		v4l_dbg(1, debug, client, "matches:%s%s%s.\n",
- 			(desc->flags & CHIP_HAS_VOLUME)     ? " volume"      : "",
- 			(desc->flags & CHIP_HAS_BASSTREBLE) ? " bass/treble" : "",
- 			(desc->flags & CHIP_HAS_INPUTSEL)   ? " audiomux"    : "");
- 	}
+ #define UCB1X00_ATTR(name,input)\
+-static ssize_t name##_show(struct class_device *dev, char *buf)	\
++static ssize_t name##_show(struct device *dev, struct device_attribute *attr, \
++			   char *buf)	\
+ {								\
+ 	struct ucb1x00 *ucb = classdev_to_ucb1x00(dev);		\
+ 	int val;						\
+@@ -29,7 +30,7 @@ static ssize_t name##_show(struct class_device *dev, char *buf)	\
+ 	ucb1x00_adc_disable(ucb);				\
+ 	return sprintf(buf, "%d\n", val);			\
+ }								\
+-static CLASS_DEVICE_ATTR(name,0444,name##_show,NULL)
++static DEVICE_ATTR(name,0444,name##_show,NULL)
  
- 	/* fill required data structures */
--	strcpy(chip->c.name, desc->name);
-+	strcpy(client->name, desc->name);
- 	chip->type = desc-chiplist;
- 	chip->shadow.count = desc->registers+1;
- 	chip->prevmode = -1;
- 	chip->audmode = V4L2_TUNER_MODE_LANG1;
--	/* register */
--	i2c_attach_client(&chip->c);
+ UCB1X00_ATTR(vbatt, UCB_ADC_INP_AD1);
+ UCB1X00_ATTR(vcharger, UCB_ADC_INP_AD0);
+@@ -37,17 +38,17 @@ UCB1X00_ATTR(batt_temp, UCB_ADC_INP_AD2);
  
- 	/* initialization  */
- 	if (desc->initialize != NULL)
-@@ -1533,28 +1536,17 @@ static int chip_attach(struct i2c_adapter *adap, int addr, int kind)
- 		init_timer(&chip->wt);
- 		chip->wt.function = chip_thread_wake;
- 		chip->wt.data     = (unsigned long)chip;
--		chip->thread = kthread_run(chip_thread, chip, chip->c.name);
-+		chip->thread = kthread_run(chip_thread, chip, chip->c->name);
- 		if (IS_ERR(chip->thread)) {
--			v4l_warn(&chip->c, "%s: failed to create kthread\n",
--			       chip->c.name);
-+			v4l_warn(chip->c, "%s: failed to create kthread\n",
-+			       chip->c->name);
- 			chip->thread = NULL;
- 		}
- 	}
+ static int ucb1x00_assabet_add(struct ucb1x00_dev *dev)
+ {
+-	class_device_create_file(&dev->ucb->cdev, &class_device_attr_vbatt);
+-	class_device_create_file(&dev->ucb->cdev, &class_device_attr_vcharger);
+-	class_device_create_file(&dev->ucb->cdev, &class_device_attr_batt_temp);
++	device_create_file(&dev->ucb->dev, &dev_attr_vbatt);
++	device_create_file(&dev->ucb->dev, &dev_attr_vcharger);
++	device_create_file(&dev->ucb->dev, &dev_attr_batt_temp);
  	return 0;
  }
  
--static int chip_probe(struct i2c_adapter *adap)
--{
--	/* don't attach on saa7146 based cards,
--	   because dedicated drivers are used */
--	if ((adap->id == I2C_HW_SAA7146))
--		return 0;
--	if (adap->class & I2C_CLASS_TV_ANALOG)
--		return i2c_probe(adap, &addr_data, chip_attach);
--	return 0;
--}
--
--static int chip_detach(struct i2c_client *client)
-+static int chip_remove(struct i2c_client *client)
+ static void ucb1x00_assabet_remove(struct ucb1x00_dev *dev)
  {
- 	struct CHIPSTATE *chip = i2c_get_clientdata(client);
- 
-@@ -1565,12 +1557,52 @@ static int chip_detach(struct i2c_client *client)
- 		chip->thread = NULL;
- 	}
+-	class_device_remove_file(&dev->ucb->cdev, &class_device_attr_batt_temp);
+-	class_device_remove_file(&dev->ucb->cdev, &class_device_attr_vcharger);
+-	class_device_remove_file(&dev->ucb->cdev, &class_device_attr_vbatt);
++	device_remove_file(&dev->ucb->dev, &dev_attr_batt_temp);
++	device_remove_file(&dev->ucb->dev, &dev_attr_vcharger);
++	device_remove_file(&dev->ucb->dev, &dev_attr_vbatt);
+ }
  
--	i2c_detach_client(&chip->c);
- 	kfree(chip);
- 	return 0;
+ static struct ucb1x00_driver ucb1x00_assabet_driver = {
+diff --git a/drivers/mfd/ucb1x00-core.c b/drivers/mfd/ucb1x00-core.c
+index e03f1bc..f6b10dd 100644
+--- a/drivers/mfd/ucb1x00-core.c
++++ b/drivers/mfd/ucb1x00-core.c
+@@ -458,7 +458,7 @@ static int ucb1x00_detect_irq(struct ucb1x00 *ucb)
+ 	return probe_irq_off(mask);
  }
  
--static int tvaudio_set_ctrl(struct CHIPSTATE *chip, struct v4l2_control *ctrl)
-+static int tvaudio_get_ctrl(struct CHIPSTATE *chip,
-+			    struct v4l2_control *ctrl)
-+{
-+	struct CHIPDESC *desc = chiplist + chip->type;
-+
-+	switch (ctrl->id) {
-+	case V4L2_CID_AUDIO_MUTE:
-+		ctrl->value=chip->muted;
-+		return 0;
-+	case V4L2_CID_AUDIO_VOLUME:
-+		if (!desc->flags & CHIP_HAS_VOLUME)
-+			break;
-+		ctrl->value = max(chip->left,chip->right);
-+		return 0;
-+	case V4L2_CID_AUDIO_BALANCE:
-+	{
-+		int volume;
-+		if (!desc->flags & CHIP_HAS_VOLUME)
-+			break;
-+		volume = max(chip->left,chip->right);
-+		if (volume)
-+			ctrl->value=(32768*min(chip->left,chip->right))/volume;
-+		else
-+			ctrl->value=32768;
-+		return 0;
-+	}
-+	case V4L2_CID_AUDIO_BASS:
-+		if (desc->flags & CHIP_HAS_BASSTREBLE)
-+			break;
-+		ctrl->value = chip->bass;
-+		return 0;
-+	case V4L2_CID_AUDIO_TREBLE:
-+		if (desc->flags & CHIP_HAS_BASSTREBLE)
-+			return -EINVAL;
-+		ctrl->value = chip->treble;
-+		return 0;
-+	}
-+	return -EINVAL;
-+}
-+
-+static int tvaudio_set_ctrl(struct CHIPSTATE *chip,
-+			    struct v4l2_control *ctrl)
+-static void ucb1x00_release(struct class_device *dev)
++static void ucb1x00_release(struct device *dev)
  {
- 	struct CHIPDESC *desc = chiplist + chip->type;
+ 	struct ucb1x00 *ucb = classdev_to_ucb1x00(dev);
+ 	kfree(ucb);
+@@ -466,7 +466,7 @@ static void ucb1x00_release(struct class_device *dev)
  
-@@ -1584,11 +1616,60 @@ static int tvaudio_set_ctrl(struct CHIPSTATE *chip, struct v4l2_control *ctrl)
- 		else
- 			chip_write_masked(chip,desc->inputreg,
- 					desc->inputmap[chip->input],desc->inputmask);
--		break;
--	default:
--		return -EINVAL;
-+		return 0;
-+	case V4L2_CID_AUDIO_VOLUME:
-+	{
-+		int volume,balance;
-+
-+		if (!desc->flags & CHIP_HAS_VOLUME)
-+			break;
-+
-+		volume = max(chip->left,chip->right);
-+		if (volume)
-+			balance=(32768*min(chip->left,chip->right))/volume;
-+		else
-+			balance=32768;
-+
-+		volume=ctrl->value;
-+		chip->left = (min(65536 - balance,32768) * volume) / 32768;
-+		chip->right = (min(balance,volume *(__u16)32768)) / 32768;
-+
-+		chip_write(chip,desc->leftreg,desc->volfunc(chip->left));
-+		chip_write(chip,desc->rightreg,desc->volfunc(chip->right));
-+
-+		return 0;
- 	}
--	return 0;
-+	case V4L2_CID_AUDIO_BALANCE:
-+	{
-+		int volume, balance;
-+		if (!desc->flags & CHIP_HAS_VOLUME)
-+			break;
-+
-+		volume = max(chip->left,chip->right);
-+		balance = ctrl->value;
-+
-+		chip_write(chip,desc->leftreg,desc->volfunc(chip->left));
-+		chip_write(chip,desc->rightreg,desc->volfunc(chip->right));
-+
-+		return 0;
-+	}
-+	case V4L2_CID_AUDIO_BASS:
-+		if (desc->flags & CHIP_HAS_BASSTREBLE)
-+			break;
-+		chip->bass = ctrl->value;
-+		chip_write(chip,desc->bassreg,desc->bassfunc(chip->bass));
-+
-+		return 0;
-+	case V4L2_CID_AUDIO_TREBLE:
-+		if (desc->flags & CHIP_HAS_BASSTREBLE)
-+			return -EINVAL;
-+
-+		chip->treble = ctrl->value;
-+		chip_write(chip,desc->treblereg,desc->treblefunc(chip->treble));
-+
-+		return 0;
-+	}
-+	return -EINVAL;
- }
+ static struct class ucb1x00_class = {
+ 	.name		= "ucb1x00",
+-	.release	= ucb1x00_release,
++	.dev_release	= ucb1x00_release,
+ };
  
+ static int ucb1x00_probe(struct mcp *mcp)
+@@ -490,9 +490,9 @@ static int ucb1x00_probe(struct mcp *mcp)
+ 		goto err_disable;
  
-@@ -1601,7 +1682,7 @@ static int chip_command(struct i2c_client *client,
- 	struct CHIPSTATE *chip = i2c_get_clientdata(client);
- 	struct CHIPDESC  *desc = chiplist + chip->type;
  
--	v4l_dbg(1, debug, &chip->c, "%s: chip_command 0x%x\n", chip->c.name, cmd);
-+	v4l_dbg(1, debug, chip->c, "%s: chip_command 0x%x\n", chip->c->name, cmd);
+-	ucb->cdev.class = &ucb1x00_class;
+-	ucb->cdev.dev = &mcp->attached_device;
+-	strlcpy(ucb->cdev.class_id, "ucb1x00", sizeof(ucb->cdev.class_id));
++	ucb->dev.class = &ucb1x00_class;
++	ucb->dev.parent = &mcp->attached_device;
++	strlcpy(ucb->dev.bus_id, "ucb1x00", sizeof(ucb->dev.bus_id));
  
- 	switch (cmd) {
- 	case AUDC_SET_RADIO:
-@@ -1609,67 +1690,36 @@ static int chip_command(struct i2c_client *client,
- 		chip->watch_stereo = 0;
- 		/* del_timer(&chip->wt); */
- 		break;
--
- 	/* --- v4l ioctls --- */
- 	/* take care: bttv does userspace copying, we'll get a
- 	kernel pointer here... */
--	case VIDIOCGAUDIO:
--	{
--		struct video_audio *va = arg;
--
--		if (desc->flags & CHIP_HAS_VOLUME) {
--			va->flags  |= VIDEO_AUDIO_VOLUME;
--			va->volume  = max(chip->left,chip->right);
--			if (va->volume)
--				va->balance = (32768*min(chip->left,chip->right))/
--					va->volume;
--			else
--				va->balance = 32768;
--		}
--		if (desc->flags & CHIP_HAS_BASSTREBLE) {
--			va->flags |= VIDEO_AUDIO_BASS | VIDEO_AUDIO_TREBLE;
--			va->bass   = chip->bass;
--			va->treble = chip->treble;
--		}
--		if (!chip->radio) {
--			if (desc->getmode)
--				va->mode = desc->getmode(chip);
--			else
--				va->mode = VIDEO_SOUND_MONO;
--		}
--		break;
--	}
--
--	case VIDIOCSAUDIO:
-+	case VIDIOC_QUERYCTRL:
- 	{
--		struct video_audio *va = arg;
--
--		if (desc->flags & CHIP_HAS_VOLUME) {
--			chip->left = (min(65536 - va->balance,32768) *
--				va->volume) / 32768;
--			chip->right = (min(va->balance,(__u16)32768) *
--				va->volume) / 32768;
--			chip_write(chip,desc->leftreg,desc->volfunc(chip->left));
--			chip_write(chip,desc->rightreg,desc->volfunc(chip->right));
--		}
--		if (desc->flags & CHIP_HAS_BASSTREBLE) {
--			chip->bass = va->bass;
--			chip->treble = va->treble;
--			chip_write(chip,desc->bassreg,desc->bassfunc(chip->bass));
--			chip_write(chip,desc->treblereg,desc->treblefunc(chip->treble));
--		}
--		if (desc->setmode && va->mode) {
--			chip->watch_stereo = 0;
--			/* del_timer(&chip->wt); */
--			chip->mode = va->mode;
--			desc->setmode(chip,va->mode);
-+		struct v4l2_queryctrl *qc = arg;
-+
-+		switch (qc->id) {
-+			case V4L2_CID_AUDIO_MUTE:
-+				break;
-+			case V4L2_CID_AUDIO_VOLUME:
-+			case V4L2_CID_AUDIO_BALANCE:
-+				if (!desc->flags & CHIP_HAS_VOLUME)
-+					return -EINVAL;
-+				break;
-+			case V4L2_CID_AUDIO_BASS:
-+			case V4L2_CID_AUDIO_TREBLE:
-+				if (desc->flags & CHIP_HAS_BASSTREBLE)
-+					return -EINVAL;
-+				break;
-+			default:
-+				return -EINVAL;
- 		}
--		break;
-+		return v4l2_ctrl_query_fill_std(qc);
- 	}
--
- 	case VIDIOC_S_CTRL:
- 		return tvaudio_set_ctrl(chip, arg);
+ 	spin_lock_init(&ucb->lock);
+ 	spin_lock_init(&ucb->io_lock);
+@@ -517,7 +517,7 @@ static int ucb1x00_probe(struct mcp *mcp)
  
-+	case VIDIOC_G_CTRL:
-+		return tvaudio_get_ctrl(chip, arg);
- 	case VIDIOC_INT_G_AUDIO_ROUTING:
- 	{
- 		struct v4l2_routing *rt = arg;
-@@ -1678,7 +1728,6 @@ static int chip_command(struct i2c_client *client,
- 		rt->output = 0;
- 		break;
- 	}
--
- 	case VIDIOC_INT_S_AUDIO_ROUTING:
- 	{
- 		struct v4l2_routing *rt = arg;
-@@ -1693,7 +1742,6 @@ static int chip_command(struct i2c_client *client,
- 				desc->inputmap[chip->input], desc->inputmask);
- 		break;
- 	}
--
- 	case VIDIOC_S_TUNER:
- 	{
- 		struct v4l2_tuner *vt = arg;
-@@ -1703,17 +1751,13 @@ static int chip_command(struct i2c_client *client,
- 			break;
- 		switch (vt->audmode) {
- 		case V4L2_TUNER_MODE_MONO:
--			mode = VIDEO_SOUND_MONO;
--			break;
- 		case V4L2_TUNER_MODE_STEREO:
--		case V4L2_TUNER_MODE_LANG1_LANG2:
--			mode = VIDEO_SOUND_STEREO;
--			break;
- 		case V4L2_TUNER_MODE_LANG1:
--			mode = VIDEO_SOUND_LANG1;
--			break;
- 		case V4L2_TUNER_MODE_LANG2:
--			mode = VIDEO_SOUND_LANG2;
-+			mode = vt->audmode;
-+			break;
-+		case V4L2_TUNER_MODE_LANG1_LANG2:
-+			mode = V4L2_TUNER_MODE_STEREO;
- 			break;
- 		default:
- 			return -EINVAL;
-@@ -1728,11 +1772,10 @@ static int chip_command(struct i2c_client *client,
- 		}
- 		break;
- 	}
--
- 	case VIDIOC_G_TUNER:
- 	{
- 		struct v4l2_tuner *vt = arg;
--		int mode = VIDEO_SOUND_MONO;
-+		int mode = V4L2_TUNER_MODE_MONO;
+ 	mcp_set_drvdata(mcp, ucb);
  
- 		if (chip->radio)
- 			break;
-@@ -1744,30 +1787,26 @@ static int chip_command(struct i2c_client *client,
- 		if (desc->getmode)
- 			mode = desc->getmode(chip);
+-	ret = class_device_register(&ucb->cdev);
++	ret = device_register(&ucb->dev);
+ 	if (ret)
+ 		goto err_irq;
  
--		if (mode & VIDEO_SOUND_MONO)
-+		if (mode & V4L2_TUNER_MODE_MONO)
- 			vt->rxsubchans |= V4L2_TUNER_SUB_MONO;
--		if (mode & VIDEO_SOUND_STEREO)
-+		if (mode & V4L2_TUNER_MODE_STEREO)
- 			vt->rxsubchans |= V4L2_TUNER_SUB_STEREO;
- 		/* Note: for SAP it should be mono/lang2 or stereo/lang2.
- 		   When this module is converted fully to v4l2, then this
- 		   should change for those chips that can detect SAP. */
--		if (mode & VIDEO_SOUND_LANG1)
-+		if (mode & V4L2_TUNER_MODE_LANG1)
- 			vt->rxsubchans = V4L2_TUNER_SUB_LANG1 |
- 					 V4L2_TUNER_SUB_LANG2;
- 		break;
- 	}
--
--	case VIDIOCSCHAN:
- 	case VIDIOC_S_STD:
- 		chip->radio = 0;
- 		break;
--
--	case VIDIOCSFREQ:
- 	case VIDIOC_S_FREQUENCY:
- 		chip->mode = 0; /* automatic */
- 		if (desc->checkmode) {
--			desc->setmode(chip,VIDEO_SOUND_MONO);
--			if (chip->prevmode != VIDEO_SOUND_MONO)
-+			desc->setmode(chip,V4L2_TUNER_MODE_MONO);
-+			if (chip->prevmode != V4L2_TUNER_MODE_MONO)
- 				chip->prevmode = -1; /* reset previous mode */
- 			mod_timer(&chip->wt, jiffies+msecs_to_jiffies(2000));
- 			/* the thread will call checkmode() later */
-@@ -1780,44 +1819,25 @@ static int chip_command(struct i2c_client *client,
- 	return 0;
+@@ -554,7 +554,7 @@ static void ucb1x00_remove(struct mcp *mcp)
+ 	mutex_unlock(&ucb1x00_mutex);
+ 
+ 	free_irq(ucb->irq, ucb);
+-	class_device_unregister(&ucb->cdev);
++	device_unregister(&ucb->dev);
  }
  
--static struct i2c_driver driver = {
--	.driver = {
--		.name    = "tvaudio",
--	},
--	.id              = I2C_DRIVERID_TVAUDIO,
--	.attach_adapter  = chip_probe,
--	.detach_client   = chip_detach,
--	.command         = chip_command,
--};
+ int ucb1x00_register_driver(struct ucb1x00_driver *drv)
+diff --git a/drivers/mfd/ucb1x00.h b/drivers/mfd/ucb1x00.h
+index ca8df80..a8ad8a0 100644
+--- a/drivers/mfd/ucb1x00.h
++++ b/drivers/mfd/ucb1x00.h
+@@ -120,7 +120,7 @@ struct ucb1x00 {
+ 	u16			irq_fal_enbl;
+ 	u16			irq_ris_enbl;
+ 	struct ucb1x00_irq	irq_handler[16];
+-	struct class_device	cdev;
++	struct device		dev;
+ 	struct list_head	node;
+ 	struct list_head	devs;
+ };
+@@ -144,7 +144,7 @@ struct ucb1x00_driver {
+ 	int	(*resume)(struct ucb1x00_dev *dev);
+ };
+ 
+-#define classdev_to_ucb1x00(cd)	container_of(cd, struct ucb1x00, cdev)
++#define classdev_to_ucb1x00(cd)	container_of(cd, struct ucb1x00, dev)
+ 
+ int ucb1x00_register_driver(struct ucb1x00_driver *);
+ void ucb1x00_unregister_driver(struct ucb1x00_driver *);
+diff --git a/drivers/misc/ibmasm/command.c b/drivers/misc/ibmasm/command.c
+index 6497872..1a0e797 100644
+--- a/drivers/misc/ibmasm/command.c
++++ b/drivers/misc/ibmasm/command.c
+@@ -26,11 +26,6 @@
+ #include "lowlevel.h"
+ 
+ static void exec_next_command(struct service_processor *sp);
+-static void free_command(struct kobject *kobj);
 -
--static struct i2c_client client_template =
-+static int chip_legacy_probe(struct i2c_adapter *adap)
- {
--	.name       = "(unset)",
--	.driver     = &driver,
+-static struct kobj_type ibmasm_cmd_kobj_type = {
+-	.release = free_command,
 -};
--
--static int __init audiochip_init_module(void)
--{
--	struct CHIPDESC  *desc;
--
--	if (debug) {
--		printk(KERN_INFO "tvaudio: TV audio decoder + audio/video mux driver\n");
--		printk(KERN_INFO "tvaudio: known chips: ");
--		for (desc = chiplist; desc->name != NULL; desc++)
--			printk("%s%s", (desc == chiplist) ? "" : ", ", desc->name);
--		printk("\n");
--	}
--
--	return i2c_add_driver(&driver);
--}
--
--static void __exit audiochip_cleanup_module(void)
--{
--	i2c_del_driver(&driver);
-+	/* don't attach on saa7146 based cards,
-+	   because dedicated drivers are used */
-+	if ((adap->id == I2C_HW_SAA7146))
-+		return 0;
-+	if (adap->class & I2C_CLASS_TV_ANALOG)
-+		return 1;
-+	return 0;
- }
- 
--module_init(audiochip_init_module);
--module_exit(audiochip_cleanup_module);
-+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
-+	.name = "tvaudio",
-+	.driverid = I2C_DRIVERID_TVAUDIO,
-+	.command = chip_command,
-+	.probe = chip_probe,
-+	.remove = chip_remove,
-+	.legacy_probe = chip_legacy_probe,
-+};
  
- /*
-  * Local variables:
-diff --git a/drivers/media/video/tveeprom.c b/drivers/media/video/tveeprom.c
-index 4b2c403..0b8fbad 100644
---- a/drivers/media/video/tveeprom.c
-+++ b/drivers/media/video/tveeprom.c
-@@ -46,11 +46,12 @@ MODULE_DESCRIPTION("i2c Hauppauge eeprom decoder driver");
- MODULE_AUTHOR("John Klar");
- MODULE_LICENSE("GPL");
+ static atomic_t command_count = ATOMIC_INIT(0);
  
--static int debug = 0;
-+static int debug;
- module_param(debug, int, 0644);
- MODULE_PARM_DESC(debug, "Debug level (0-1)");
+@@ -53,8 +48,7 @@ struct command *ibmasm_new_command(struct service_processor *sp, size_t buffer_s
+ 	}
+ 	cmd->buffer_size = buffer_size;
  
--#define STRM(array,i) (i < sizeof(array)/sizeof(char*) ? array[i] : "unknown")
-+#define STRM(array, i) \
-+	(i < sizeof(array) / sizeof(char *) ? array[i] : "unknown")
+-	kobject_init(&cmd->kobj);
+-	cmd->kobj.ktype = &ibmasm_cmd_kobj_type;
++	kref_init(&cmd->kref);
+ 	cmd->lock = &sp->lock;
  
- #define tveeprom_info(fmt, arg...) \
- 	v4l_printk(KERN_INFO, "tveeprom", c->adapter, c->addr, fmt , ## arg)
-@@ -58,7 +59,8 @@ MODULE_PARM_DESC(debug, "Debug level (0-1)");
- 	v4l_printk(KERN_WARNING, "tveeprom", c->adapter, c->addr, fmt , ## arg)
- #define tveeprom_dbg(fmt, arg...) do { \
- 	if (debug) \
--		v4l_printk(KERN_DEBUG, "tveeprom", c->adapter, c->addr, fmt , ## arg); \
-+		v4l_printk(KERN_DEBUG, "tveeprom", \
-+				c->adapter, c->addr, fmt , ## arg); \
- 	} while (0)
+ 	cmd->status = IBMASM_CMD_PENDING;
+@@ -67,9 +61,9 @@ struct command *ibmasm_new_command(struct service_processor *sp, size_t buffer_s
+ 	return cmd;
+ }
  
- /*
-@@ -94,170 +96,172 @@ static struct HAUPPAUGE_TUNER
- hauppauge_tuner[] =
+-static void free_command(struct kobject *kobj)
++void ibmasm_free_command(struct kref *kref)
  {
- 	/* 0-9 */
--	{ TUNER_ABSENT,        "None" },
--	{ TUNER_ABSENT,        "External" },
--	{ TUNER_ABSENT,        "Unspecified" },
--	{ TUNER_PHILIPS_PAL,   "Philips FI1216" },
--	{ TUNER_PHILIPS_SECAM, "Philips FI1216MF" },
--	{ TUNER_PHILIPS_NTSC,  "Philips FI1236" },
--	{ TUNER_PHILIPS_PAL_I, "Philips FI1246" },
--	{ TUNER_PHILIPS_PAL_DK,"Philips FI1256" },
--	{ TUNER_PHILIPS_PAL,   "Philips FI1216 MK2" },
--	{ TUNER_PHILIPS_SECAM, "Philips FI1216MF MK2" },
-+	{ TUNER_ABSENT,        		"None" },
-+	{ TUNER_ABSENT,        		"External" },
-+	{ TUNER_ABSENT,        		"Unspecified" },
-+	{ TUNER_PHILIPS_PAL,   		"Philips FI1216" },
-+	{ TUNER_PHILIPS_SECAM, 		"Philips FI1216MF" },
-+	{ TUNER_PHILIPS_NTSC,  		"Philips FI1236" },
-+	{ TUNER_PHILIPS_PAL_I, 		"Philips FI1246" },
-+	{ TUNER_PHILIPS_PAL_DK,		"Philips FI1256" },
-+	{ TUNER_PHILIPS_PAL,   		"Philips FI1216 MK2" },
-+	{ TUNER_PHILIPS_SECAM, 		"Philips FI1216MF MK2" },
- 	/* 10-19 */
--	{ TUNER_PHILIPS_NTSC,  "Philips FI1236 MK2" },
--	{ TUNER_PHILIPS_PAL_I, "Philips FI1246 MK2" },
--	{ TUNER_PHILIPS_PAL_DK,"Philips FI1256 MK2" },
--	{ TUNER_TEMIC_NTSC,    "Temic 4032FY5" },
--	{ TUNER_TEMIC_PAL,     "Temic 4002FH5" },
--	{ TUNER_TEMIC_PAL_I,   "Temic 4062FY5" },
--	{ TUNER_PHILIPS_PAL,   "Philips FR1216 MK2" },
--	{ TUNER_PHILIPS_SECAM, "Philips FR1216MF MK2" },
--	{ TUNER_PHILIPS_NTSC,  "Philips FR1236 MK2" },
--	{ TUNER_PHILIPS_PAL_I, "Philips FR1246 MK2" },
-+	{ TUNER_PHILIPS_NTSC,  		"Philips FI1236 MK2" },
-+	{ TUNER_PHILIPS_PAL_I, 		"Philips FI1246 MK2" },
-+	{ TUNER_PHILIPS_PAL_DK,		"Philips FI1256 MK2" },
-+	{ TUNER_TEMIC_NTSC,    		"Temic 4032FY5" },
-+	{ TUNER_TEMIC_PAL,     		"Temic 4002FH5" },
-+	{ TUNER_TEMIC_PAL_I,   		"Temic 4062FY5" },
-+	{ TUNER_PHILIPS_PAL,   		"Philips FR1216 MK2" },
-+	{ TUNER_PHILIPS_SECAM, 		"Philips FR1216MF MK2" },
-+	{ TUNER_PHILIPS_NTSC,  		"Philips FR1236 MK2" },
-+	{ TUNER_PHILIPS_PAL_I, 		"Philips FR1246 MK2" },
- 	/* 20-29 */
--	{ TUNER_PHILIPS_PAL_DK,"Philips FR1256 MK2" },
--	{ TUNER_PHILIPS_PAL,   "Philips FM1216" },
--	{ TUNER_PHILIPS_SECAM, "Philips FM1216MF" },
--	{ TUNER_PHILIPS_NTSC,  "Philips FM1236" },
--	{ TUNER_PHILIPS_PAL_I, "Philips FM1246" },
--	{ TUNER_PHILIPS_PAL_DK,"Philips FM1256" },
--	{ TUNER_TEMIC_4036FY5_NTSC, "Temic 4036FY5" },
--	{ TUNER_ABSENT,        "Samsung TCPN9082D" },
--	{ TUNER_ABSENT,        "Samsung TCPM9092P" },
--	{ TUNER_TEMIC_4006FH5_PAL, "Temic 4006FH5" },
-+	{ TUNER_PHILIPS_PAL_DK,		"Philips FR1256 MK2" },
-+	{ TUNER_PHILIPS_PAL,   		"Philips FM1216" },
-+	{ TUNER_PHILIPS_SECAM, 		"Philips FM1216MF" },
-+	{ TUNER_PHILIPS_NTSC,  		"Philips FM1236" },
-+	{ TUNER_PHILIPS_PAL_I, 		"Philips FM1246" },
-+	{ TUNER_PHILIPS_PAL_DK,		"Philips FM1256" },
-+	{ TUNER_TEMIC_4036FY5_NTSC, 	"Temic 4036FY5" },
-+	{ TUNER_ABSENT,        		"Samsung TCPN9082D" },
-+	{ TUNER_ABSENT,        		"Samsung TCPM9092P" },
-+	{ TUNER_TEMIC_4006FH5_PAL, 	"Temic 4006FH5" },
- 	/* 30-39 */
--	{ TUNER_ABSENT,        "Samsung TCPN9085D" },
--	{ TUNER_ABSENT,        "Samsung TCPB9085P" },
--	{ TUNER_ABSENT,        "Samsung TCPL9091P" },
--	{ TUNER_TEMIC_4039FR5_NTSC, "Temic 4039FR5" },
--	{ TUNER_PHILIPS_FQ1216ME,   "Philips FQ1216 ME" },
--	{ TUNER_TEMIC_4066FY5_PAL_I, "Temic 4066FY5" },
--	{ TUNER_PHILIPS_NTSC,        "Philips TD1536" },
--	{ TUNER_PHILIPS_NTSC,        "Philips TD1536D" },
--	{ TUNER_PHILIPS_NTSC,  "Philips FMR1236" }, /* mono radio */
--	{ TUNER_ABSENT,        "Philips FI1256MP" },
-+	{ TUNER_ABSENT,        		"Samsung TCPN9085D" },
-+	{ TUNER_ABSENT,        		"Samsung TCPB9085P" },
-+	{ TUNER_ABSENT,        		"Samsung TCPL9091P" },
-+	{ TUNER_TEMIC_4039FR5_NTSC, 	"Temic 4039FR5" },
-+	{ TUNER_PHILIPS_FQ1216ME,   	"Philips FQ1216 ME" },
-+	{ TUNER_TEMIC_4066FY5_PAL_I, 	"Temic 4066FY5" },
-+	{ TUNER_PHILIPS_NTSC,        	"Philips TD1536" },
-+	{ TUNER_PHILIPS_NTSC,        	"Philips TD1536D" },
-+	{ TUNER_PHILIPS_NTSC,  		"Philips FMR1236" }, /* mono radio */
-+	{ TUNER_ABSENT,        		"Philips FI1256MP" },
- 	/* 40-49 */
--	{ TUNER_ABSENT,        "Samsung TCPQ9091P" },
-+	{ TUNER_ABSENT,        		"Samsung TCPQ9091P" },
- 	{ TUNER_TEMIC_4006FN5_MULTI_PAL, "Temic 4006FN5" },
--	{ TUNER_TEMIC_4009FR5_PAL, "Temic 4009FR5" },
--	{ TUNER_TEMIC_4046FM5,     "Temic 4046FM5" },
-+	{ TUNER_TEMIC_4009FR5_PAL, 	"Temic 4009FR5" },
-+	{ TUNER_TEMIC_4046FM5,     	"Temic 4046FM5" },
- 	{ TUNER_TEMIC_4009FN5_MULTI_PAL_FM, "Temic 4009FN5" },
--	{ TUNER_ABSENT,        "Philips TD1536D FH 44"},
--	{ TUNER_LG_NTSC_FM,    "LG TP18NSR01F"},
--	{ TUNER_LG_PAL_FM,     "LG TP18PSB01D"},
--	{ TUNER_LG_PAL,        "LG TP18PSB11D"},
--	{ TUNER_LG_PAL_I_FM,   "LG TAPC-I001D"},
-+	{ TUNER_ABSENT,        		"Philips TD1536D FH 44"},
-+	{ TUNER_LG_NTSC_FM,    		"LG TP18NSR01F"},
-+	{ TUNER_LG_PAL_FM,     		"LG TP18PSB01D"},
-+	{ TUNER_LG_PAL,        		"LG TP18PSB11D"},
-+	{ TUNER_LG_PAL_I_FM,   		"LG TAPC-I001D"},
- 	/* 50-59 */
--	{ TUNER_LG_PAL_I,      "LG TAPC-I701D"},
--	{ TUNER_ABSENT,        "Temic 4042FI5"},
--	{ TUNER_MICROTUNE_4049FM5, "Microtune 4049 FM5"},
--	{ TUNER_ABSENT,        "LG TPI8NSR11F"},
--	{ TUNER_ABSENT,        "Microtune 4049 FM5 Alt I2C"},
--	{ TUNER_PHILIPS_FM1216ME_MK3, "Philips FQ1216ME MK3"},
--	{ TUNER_ABSENT,        "Philips FI1236 MK3"},
--	{ TUNER_PHILIPS_FM1216ME_MK3, "Philips FM1216 ME MK3"},
--	{ TUNER_PHILIPS_FM1236_MK3, "Philips FM1236 MK3"},
--	{ TUNER_ABSENT,        "Philips FM1216MP MK3"},
-+	{ TUNER_LG_PAL_I,      		"LG TAPC-I701D"},
-+	{ TUNER_ABSENT,       		"Temic 4042FI5"},
-+	{ TUNER_MICROTUNE_4049FM5, 	"Microtune 4049 FM5"},
-+	{ TUNER_ABSENT,        		"LG TPI8NSR11F"},
-+	{ TUNER_ABSENT,        		"Microtune 4049 FM5 Alt I2C"},
-+	{ TUNER_PHILIPS_FM1216ME_MK3, 	"Philips FQ1216ME MK3"},
-+	{ TUNER_ABSENT,        		"Philips FI1236 MK3"},
-+	{ TUNER_PHILIPS_FM1216ME_MK3, 	"Philips FM1216 ME MK3"},
-+	{ TUNER_PHILIPS_FM1236_MK3, 	"Philips FM1236 MK3"},
-+	{ TUNER_ABSENT,        		"Philips FM1216MP MK3"},
- 	/* 60-69 */
--	{ TUNER_PHILIPS_FM1216ME_MK3, "LG S001D MK3"},
--	{ TUNER_ABSENT,        "LG M001D MK3"},
--	{ TUNER_PHILIPS_FM1216ME_MK3, "LG S701D MK3"},
--	{ TUNER_ABSENT,        "LG M701D MK3"},
--	{ TUNER_ABSENT,        "Temic 4146FM5"},
--	{ TUNER_ABSENT,        "Temic 4136FY5"},
--	{ TUNER_ABSENT,        "Temic 4106FH5"},
--	{ TUNER_ABSENT,        "Philips FQ1216LMP MK3"},
--	{ TUNER_LG_NTSC_TAPE,  "LG TAPE H001F MK3"},
--	{ TUNER_LG_NTSC_TAPE,  "LG TAPE H701F MK3"},
-+	{ TUNER_PHILIPS_FM1216ME_MK3, 	"LG S001D MK3"},
-+	{ TUNER_ABSENT,        		"LG M001D MK3"},
-+	{ TUNER_PHILIPS_FM1216ME_MK3, 	"LG S701D MK3"},
-+	{ TUNER_ABSENT,        		"LG M701D MK3"},
-+	{ TUNER_ABSENT,        		"Temic 4146FM5"},
-+	{ TUNER_ABSENT,        		"Temic 4136FY5"},
-+	{ TUNER_ABSENT,        		"Temic 4106FH5"},
-+	{ TUNER_ABSENT,        		"Philips FQ1216LMP MK3"},
-+	{ TUNER_LG_NTSC_TAPE,  		"LG TAPE H001F MK3"},
-+	{ TUNER_LG_NTSC_TAPE,  		"LG TAPE H701F MK3"},
- 	/* 70-79 */
--	{ TUNER_ABSENT,        "LG TALN H200T"},
--	{ TUNER_ABSENT,        "LG TALN H250T"},
--	{ TUNER_ABSENT,        "LG TALN M200T"},
--	{ TUNER_ABSENT,        "LG TALN Z200T"},
--	{ TUNER_ABSENT,        "LG TALN S200T"},
--	{ TUNER_ABSENT,        "Thompson DTT7595"},
--	{ TUNER_ABSENT,        "Thompson DTT7592"},
--	{ TUNER_ABSENT,        "Silicon TDA8275C1 8290"},
--	{ TUNER_ABSENT,        "Silicon TDA8275C1 8290 FM"},
--	{ TUNER_ABSENT,        "Thompson DTT757"},
-+	{ TUNER_ABSENT,        		"LG TALN H200T"},
-+	{ TUNER_ABSENT,        		"LG TALN H250T"},
-+	{ TUNER_ABSENT,        		"LG TALN M200T"},
-+	{ TUNER_ABSENT,        		"LG TALN Z200T"},
-+	{ TUNER_ABSENT,        		"LG TALN S200T"},
-+	{ TUNER_ABSENT,        		"Thompson DTT7595"},
-+	{ TUNER_ABSENT,        		"Thompson DTT7592"},
-+	{ TUNER_ABSENT,        		"Silicon TDA8275C1 8290"},
-+	{ TUNER_ABSENT,        		"Silicon TDA8275C1 8290 FM"},
-+	{ TUNER_ABSENT,        		"Thompson DTT757"},
- 	/* 80-89 */
--	{ TUNER_PHILIPS_FM1216ME_MK3, "Philips FQ1216LME MK3"},
--	{ TUNER_LG_PAL_NEW_TAPC, "LG TAPC G701D"},
--	{ TUNER_LG_NTSC_NEW_TAPC, "LG TAPC H791F"},
--	{ TUNER_LG_PAL_NEW_TAPC, "TCL 2002MB 3"},
--	{ TUNER_LG_PAL_NEW_TAPC, "TCL 2002MI 3"},
--	{ TUNER_TCL_2002N,     "TCL 2002N 6A"},
--	{ TUNER_PHILIPS_FM1236_MK3, "Philips FQ1236 MK3"},
--	{ TUNER_SAMSUNG_TCPN_2121P30A, "Samsung TCPN 2121P30A"},
--	{ TUNER_ABSENT,        "Samsung TCPE 4121P30A"},
--	{ TUNER_PHILIPS_FM1216ME_MK3, "TCL MFPE05 2"},
-+	{ TUNER_PHILIPS_FM1216ME_MK3, 	"Philips FQ1216LME MK3"},
-+	{ TUNER_LG_PAL_NEW_TAPC, 	"LG TAPC G701D"},
-+	{ TUNER_LG_NTSC_NEW_TAPC, 	"LG TAPC H791F"},
-+	{ TUNER_LG_PAL_NEW_TAPC, 	"TCL 2002MB 3"},
-+	{ TUNER_LG_PAL_NEW_TAPC, 	"TCL 2002MI 3"},
-+	{ TUNER_TCL_2002N,     		"TCL 2002N 6A"},
-+	{ TUNER_PHILIPS_FM1236_MK3, 	"Philips FQ1236 MK3"},
-+	{ TUNER_SAMSUNG_TCPN_2121P30A, 	"Samsung TCPN 2121P30A"},
-+	{ TUNER_ABSENT,        		"Samsung TCPE 4121P30A"},
-+	{ TUNER_PHILIPS_FM1216ME_MK3, 	"TCL MFPE05 2"},
- 	/* 90-99 */
--	{ TUNER_ABSENT,        "LG TALN H202T"},
--	{ TUNER_PHILIPS_FQ1216AME_MK4, "Philips FQ1216AME MK4"},
--	{ TUNER_PHILIPS_FQ1236A_MK4, "Philips FQ1236A MK4"},
--	{ TUNER_ABSENT,        "Philips FQ1286A MK4"},
--	{ TUNER_ABSENT,        "Philips FQ1216ME MK5"},
--	{ TUNER_ABSENT,        "Philips FQ1236 MK5"},
--	{ TUNER_SAMSUNG_TCPG_6121P30A, "Samsung TCPG 6121P30A"},
--	{ TUNER_TCL_2002MB,    "TCL 2002MB_3H"},
--	{ TUNER_ABSENT,        "TCL 2002MI_3H"},
--	{ TUNER_TCL_2002N,     "TCL 2002N 5H"},
-+	{ TUNER_ABSENT,        		"LG TALN H202T"},
-+	{ TUNER_PHILIPS_FQ1216AME_MK4, 	"Philips FQ1216AME MK4"},
-+	{ TUNER_PHILIPS_FQ1236A_MK4, 	"Philips FQ1236A MK4"},
-+	{ TUNER_ABSENT,       		"Philips FQ1286A MK4"},
-+	{ TUNER_ABSENT,        		"Philips FQ1216ME MK5"},
-+	{ TUNER_ABSENT,        		"Philips FQ1236 MK5"},
-+	{ TUNER_SAMSUNG_TCPG_6121P30A, 	"Samsung TCPG 6121P30A"},
-+	{ TUNER_TCL_2002MB,    		"TCL 2002MB_3H"},
-+	{ TUNER_ABSENT,        		"TCL 2002MI_3H"},
-+	{ TUNER_TCL_2002N,     		"TCL 2002N 5H"},
- 	/* 100-109 */
--	{ TUNER_PHILIPS_FMD1216ME_MK3, "Philips FMD1216ME"},
--	{ TUNER_TEA5767,       "Philips TEA5768HL FM Radio"},
--	{ TUNER_ABSENT,        "Panasonic ENV57H12D5"},
--	{ TUNER_PHILIPS_FM1236_MK3, "TCL MFNM05-4"},
--	{ TUNER_ABSENT,        "TCL MNM05-4"},
--	{ TUNER_PHILIPS_FM1216ME_MK3, "TCL MPE05-2"},
--	{ TUNER_ABSENT,        "TCL MQNM05-4"},
--	{ TUNER_ABSENT,        "LG TAPC-W701D"},
--	{ TUNER_ABSENT,        "TCL 9886P-WM"},
--	{ TUNER_ABSENT,        "TCL 1676NM-WM"},
-+	{ TUNER_PHILIPS_FMD1216ME_MK3, 	"Philips FMD1216ME"},
-+	{ TUNER_TEA5767,       		"Philips TEA5768HL FM Radio"},
-+	{ TUNER_ABSENT,        		"Panasonic ENV57H12D5"},
-+	{ TUNER_PHILIPS_FM1236_MK3, 	"TCL MFNM05-4"},
-+	{ TUNER_ABSENT,        		"TCL MNM05-4"},
-+	{ TUNER_PHILIPS_FM1216ME_MK3, 	"TCL MPE05-2"},
-+	{ TUNER_ABSENT,        		"TCL MQNM05-4"},
-+	{ TUNER_ABSENT,        		"LG TAPC-W701D"},
-+	{ TUNER_ABSENT,        		"TCL 9886P-WM"},
-+	{ TUNER_ABSENT,        		"TCL 1676NM-WM"},
- 	/* 110-119 */
--	{ TUNER_ABSENT,        "Thompson DTT75105"},
--	{ TUNER_ABSENT,        "Conexant_CX24109"},
--	{ TUNER_TCL_2002N,     "TCL M2523_5N_E"},
--	{ TUNER_TCL_2002MB,    "TCL M2523_3DB_E"},
--	{ TUNER_ABSENT,        "Philips 8275A"},
--	{ TUNER_ABSENT,        "Microtune MT2060"},
--	{ TUNER_PHILIPS_FM1236_MK3, "Philips FM1236 MK5"},
--	{ TUNER_PHILIPS_FM1216ME_MK3, "Philips FM1216ME MK5"},
--	{ TUNER_ABSENT,        "TCL M2523_3DI_E"},
--	{ TUNER_ABSENT,        "Samsung THPD5222FG30A"},
-+	{ TUNER_ABSENT,        		"Thompson DTT75105"},
-+	{ TUNER_ABSENT,        		"Conexant_CX24109"},
-+	{ TUNER_TCL_2002N,     		"TCL M2523_5N_E"},
-+	{ TUNER_TCL_2002MB,    		"TCL M2523_3DB_E"},
-+	{ TUNER_ABSENT,        		"Philips 8275A"},
-+	{ TUNER_ABSENT,        		"Microtune MT2060"},
-+	{ TUNER_PHILIPS_FM1236_MK3, 	"Philips FM1236 MK5"},
-+	{ TUNER_PHILIPS_FM1216ME_MK3, 	"Philips FM1216ME MK5"},
-+	{ TUNER_ABSENT,        		"TCL M2523_3DI_E"},
-+	{ TUNER_ABSENT,        		"Samsung THPD5222FG30A"},
- 	/* 120-129 */
--	{ TUNER_ABSENT,        "Xceive XC3028"},
--	{ TUNER_ABSENT,        "Philips FQ1216LME MK5"},
--	{ TUNER_ABSENT,        "Philips FQD1216LME"},
--	{ TUNER_ABSENT,        "Conexant CX24118A"},
--	{ TUNER_ABSENT,        "TCL DMF11WIP"},
--	{ TUNER_ABSENT,        "TCL MFNM05_4H_E"},
--	{ TUNER_ABSENT,        "TCL MNM05_4H_E"},
--	{ TUNER_ABSENT,        "TCL MPE05_2H_E"},
--	{ TUNER_ABSENT,        "TCL MQNM05_4_U"},
--	{ TUNER_ABSENT,        "TCL M2523_5NH_E"},
-+	{ TUNER_XC2028,        		"Xceive XC3028"},
-+	{ TUNER_ABSENT,        		"Philips FQ1216LME MK5"},
-+	{ TUNER_ABSENT,        		"Philips FQD1216LME"},
-+	{ TUNER_ABSENT,        		"Conexant CX24118A"},
-+	{ TUNER_ABSENT,        		"TCL DMF11WIP"},
-+	{ TUNER_ABSENT,        		"TCL MFNM05_4H_E"},
-+	{ TUNER_ABSENT,        		"TCL MNM05_4H_E"},
-+	{ TUNER_ABSENT,        		"TCL MPE05_2H_E"},
-+	{ TUNER_ABSENT,        		"TCL MQNM05_4_U"},
-+	{ TUNER_ABSENT,        		"TCL M2523_5NH_E"},
- 	/* 130-139 */
--	{ TUNER_ABSENT,        "TCL M2523_3DBH_E"},
--	{ TUNER_ABSENT,        "TCL M2523_3DIH_E"},
--	{ TUNER_ABSENT,        "TCL MFPE05_2_U"},
--	{ TUNER_ABSENT,        "Philips FMD1216MEX"},
--	{ TUNER_ABSENT,        "Philips FRH2036B"},
--	{ TUNER_ABSENT,        "Panasonic ENGF75_01GF"},
--	{ TUNER_ABSENT,        "MaxLinear MXL5005"},
--	{ TUNER_ABSENT,        "MaxLinear MXL5003"},
--	{ TUNER_ABSENT,        "Xceive XC2028"},
--	{ TUNER_ABSENT,        "Microtune MT2131"},
-+	{ TUNER_ABSENT,        		"TCL M2523_3DBH_E"},
-+	{ TUNER_ABSENT,        		"TCL M2523_3DIH_E"},
-+	{ TUNER_ABSENT,        		"TCL MFPE05_2_U"},
-+	{ TUNER_ABSENT,        		"Philips FMD1216MEX"},
-+	{ TUNER_ABSENT,        		"Philips FRH2036B"},
-+	{ TUNER_ABSENT,        		"Panasonic ENGF75_01GF"},
-+	{ TUNER_ABSENT,        		"MaxLinear MXL5005"},
-+	{ TUNER_ABSENT,        		"MaxLinear MXL5003"},
-+	{ TUNER_ABSENT,        		"Xceive XC2028"},
-+	{ TUNER_ABSENT,        		"Microtune MT2131"},
- 	/* 140-149 */
--	{ TUNER_ABSENT,        "Philips 8275A_8295"},
--	{ TUNER_ABSENT,        "TCL MF02GIP_5N_E"},
--	{ TUNER_ABSENT,        "TCL MF02GIP_3DB_E"},
--	{ TUNER_ABSENT,        "TCL MF02GIP_3DI_E"},
--	{ TUNER_ABSENT,        "Microtune MT2266"},
--	{ TUNER_ABSENT,        "TCL MF10WPP_4N_E"},
--	{ TUNER_ABSENT,        "LG TAPQ_H702F"},
--	{ TUNER_ABSENT,        "TCL M09WPP_4N_E"},
--	{ TUNER_ABSENT,        "MaxLinear MXL5005_v2"},
--	{ TUNER_ABSENT,        "Philips 18271_8295"},
-+	{ TUNER_ABSENT,        		"Philips 8275A_8295"},
-+	{ TUNER_ABSENT,        		"TCL MF02GIP_5N_E"},
-+	{ TUNER_ABSENT,        		"TCL MF02GIP_3DB_E"},
-+	{ TUNER_ABSENT,        		"TCL MF02GIP_3DI_E"},
-+	{ TUNER_ABSENT,        		"Microtune MT2266"},
-+	{ TUNER_ABSENT,        		"TCL MF10WPP_4N_E"},
-+	{ TUNER_ABSENT,        		"LG TAPQ_H702F"},
-+	{ TUNER_ABSENT,        		"TCL M09WPP_4N_E"},
-+	{ TUNER_ABSENT,        		"MaxLinear MXL5005_v2"},
-+	{ TUNER_PHILIPS_TDA8290, 	"Philips 18271_8295"},
-+	/* 150-159 */
-+	{ TUNER_ABSENT,        "Xceive XC5000"},
+-	struct command *cmd = to_command(kobj);
++	struct command *cmd = to_command(kref);
+ 
+ 	list_del(&cmd->queue_node);
+ 	atomic_dec(&command_count);
+diff --git a/drivers/misc/ibmasm/ibmasm.h b/drivers/misc/ibmasm/ibmasm.h
+index de860bc..4d8a4e2 100644
+--- a/drivers/misc/ibmasm/ibmasm.h
++++ b/drivers/misc/ibmasm/ibmasm.h
+@@ -31,6 +31,7 @@
+ #include <linux/slab.h>
+ #include <linux/module.h>
+ #include <linux/interrupt.h>
++#include <linux/kref.h>
+ #include <linux/device.h>
+ #include <linux/input.h>
+ 
+@@ -92,24 +93,25 @@ struct command {
+ 	unsigned char		*buffer;
+ 	size_t			buffer_size;
+ 	int			status;
+-	struct kobject		kobj;
++	struct kref		kref;
+ 	spinlock_t		*lock;
  };
+-#define to_command(c) container_of(c, struct command, kobj)
++#define to_command(c) container_of(c, struct command, kref)
  
- static struct HAUPPAUGE_AUDIOIC
-@@ -344,37 +348,37 @@ static const char *decoderIC[] = {
- static int hasRadioTuner(int tunerType)
++void ibmasm_free_command(struct kref *kref);
+ static inline void command_put(struct command *cmd)
  {
- 	switch (tunerType) {
--		case 18: //PNPEnv_TUNER_FR1236_MK2:
--		case 23: //PNPEnv_TUNER_FM1236:
--		case 38: //PNPEnv_TUNER_FMR1236:
--		case 16: //PNPEnv_TUNER_FR1216_MK2:
--		case 19: //PNPEnv_TUNER_FR1246_MK2:
--		case 21: //PNPEnv_TUNER_FM1216:
--		case 24: //PNPEnv_TUNER_FM1246:
--		case 17: //PNPEnv_TUNER_FR1216MF_MK2:
--		case 22: //PNPEnv_TUNER_FM1216MF:
--		case 20: //PNPEnv_TUNER_FR1256_MK2:
--		case 25: //PNPEnv_TUNER_FM1256:
--		case 33: //PNPEnv_TUNER_4039FR5:
--		case 42: //PNPEnv_TUNER_4009FR5:
--		case 52: //PNPEnv_TUNER_4049FM5:
--		case 54: //PNPEnv_TUNER_4049FM5_AltI2C:
--		case 44: //PNPEnv_TUNER_4009FN5:
--		case 31: //PNPEnv_TUNER_TCPB9085P:
--		case 30: //PNPEnv_TUNER_TCPN9085D:
--		case 46: //PNPEnv_TUNER_TP18NSR01F:
--		case 47: //PNPEnv_TUNER_TP18PSB01D:
--		case 49: //PNPEnv_TUNER_TAPC_I001D:
--		case 60: //PNPEnv_TUNER_TAPE_S001D_MK3:
--		case 57: //PNPEnv_TUNER_FM1216ME_MK3:
--		case 59: //PNPEnv_TUNER_FM1216MP_MK3:
--		case 58: //PNPEnv_TUNER_FM1236_MK3:
--		case 68: //PNPEnv_TUNER_TAPE_H001F_MK3:
--		case 61: //PNPEnv_TUNER_TAPE_M001D_MK3:
--		case 78: //PNPEnv_TUNER_TDA8275C1_8290_FM:
--		case 89: //PNPEnv_TUNER_TCL_MFPE05_2:
--		case 92: //PNPEnv_TUNER_PHILIPS_FQ1236A_MK4:
--		case 105:
-+	case 18: /* PNPEnv_TUNER_FR1236_MK2 */
-+	case 23: /* PNPEnv_TUNER_FM1236 */
-+	case 38: /* PNPEnv_TUNER_FMR1236 */
-+	case 16: /* PNPEnv_TUNER_FR1216_MK2 */
-+	case 19: /* PNPEnv_TUNER_FR1246_MK2 */
-+	case 21: /* PNPEnv_TUNER_FM1216 */
-+	case 24: /* PNPEnv_TUNER_FM1246 */
-+	case 17: /* PNPEnv_TUNER_FR1216MF_MK2 */
-+	case 22: /* PNPEnv_TUNER_FM1216MF */
-+	case 20: /* PNPEnv_TUNER_FR1256_MK2 */
-+	case 25: /* PNPEnv_TUNER_FM1256 */
-+	case 33: /* PNPEnv_TUNER_4039FR5 */
-+	case 42: /* PNPEnv_TUNER_4009FR5 */
-+	case 52: /* PNPEnv_TUNER_4049FM5 */
-+	case 54: /* PNPEnv_TUNER_4049FM5_AltI2C */
-+	case 44: /* PNPEnv_TUNER_4009FN5 */
-+	case 31: /* PNPEnv_TUNER_TCPB9085P */
-+	case 30: /* PNPEnv_TUNER_TCPN9085D */
-+	case 46: /* PNPEnv_TUNER_TP18NSR01F */
-+	case 47: /* PNPEnv_TUNER_TP18PSB01D */
-+	case 49: /* PNPEnv_TUNER_TAPC_I001D */
-+	case 60: /* PNPEnv_TUNER_TAPE_S001D_MK3 */
-+	case 57: /* PNPEnv_TUNER_FM1216ME_MK3 */
-+	case 59: /* PNPEnv_TUNER_FM1216MP_MK3 */
-+	case 58: /* PNPEnv_TUNER_FM1236_MK3 */
-+	case 68: /* PNPEnv_TUNER_TAPE_H001F_MK3 */
-+	case 61: /* PNPEnv_TUNER_TAPE_M001D_MK3 */
-+	case 78: /* PNPEnv_TUNER_TDA8275C1_8290_FM */
-+	case 89: /* PNPEnv_TUNER_TCL_MFPE05_2 */
-+	case 92: /* PNPEnv_TUNER_PHILIPS_FQ1236A_MK4 */
-+	case 105:
- 		return 1;
- 	}
- 	return 0;
-@@ -392,7 +396,8 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
- 	**
- 	** In our (ivtv) case we're interested in the following:
- 	** tuner type:   tag [00].05 or [0a].01 (index into hauppauge_tuner)
--	** tuner fmts:   tag [00].04 or [0a].00 (bitmask index into hauppauge_tuner_fmt)
-+	** tuner fmts:   tag [00].04 or [0a].00 (bitmask index into
-+	**		 hauppauge_tuner_fmt)
- 	** radio:        tag [00].{last} or [0e].00  (bitmask.  bit2=FM)
- 	** audio proc:   tag [02].01 or [05].00 (mask with 0x7f)
- 	** decoder proc: tag [09].01)
-@@ -405,9 +410,9 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
- 	** # of inputs/outputs ???
- 	*/
- 
--	int i, j, len, done, beenhere, tag,start;
-+	int i, j, len, done, beenhere, tag, start;
+ 	unsigned long flags;
+ 	spinlock_t *lock = cmd->lock;
  
--	int tuner1 = 0, t_format1 = 0, audioic=-1;
-+	int tuner1 = 0, t_format1 = 0, audioic = -1;
- 	char *t_name1 = NULL;
- 	const char *t_fmt_name1[8] = { " none", "", "", "", "", "", "", "" };
+ 	spin_lock_irqsave(lock, flags);
+-	kobject_put(&cmd->kobj);
++	kref_put(&cmd->kref, ibmasm_free_command);
+ 	spin_unlock_irqrestore(lock, flags);
+ }
  
-@@ -418,17 +423,24 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
- 	memset(tvee, 0, sizeof(*tvee));
- 	done = len = beenhere = 0;
+ static inline void command_get(struct command *cmd)
+ {
+-	kobject_get(&cmd->kobj);
++	kref_get(&cmd->kref);
+ }
  
--	/* Hack for processing eeprom for em28xx and cx 2388x*/
--	if ((eeprom_data[0] == 0x1a) && (eeprom_data[1] == 0xeb) &&
--			(eeprom_data[2] == 0x67) && (eeprom_data[3] == 0x95))
--		start=0xa0; /* Generic em28xx offset */
--	else if (((eeprom_data[0] & 0xe1) == 0x01) &&
--					(eeprom_data[1] == 0x00) &&
--					(eeprom_data[2] == 0x00) &&
--					(eeprom_data[8] == 0x84))
--		start=8; /* Generic cx2388x offset */
-+	/* Different eeprom start offsets for em28xx, cx2388x and cx23418 */
-+	if (eeprom_data[0] == 0x1a &&
-+	    eeprom_data[1] == 0xeb &&
-+	    eeprom_data[2] == 0x67 &&
-+	    eeprom_data[3] == 0x95)
-+		start = 0xa0; /* Generic em28xx offset */
-+	else if ((eeprom_data[0] & 0xe1) == 0x01 &&
-+		 eeprom_data[1] == 0x00 &&
-+		 eeprom_data[2] == 0x00 &&
-+		 eeprom_data[8] == 0x84)
-+		start = 8; /* Generic cx2388x offset */
-+	else if (eeprom_data[1] == 0x70 &&
-+		 eeprom_data[2] == 0x00 &&
-+		 eeprom_data[4] == 0x74 &&
-+		 eeprom_data[8] == 0x84)
-+		start = 8; /* Generic cx23418 offset (models 74xxx) */
- 	else
--		start=0;
-+		start = 0;
  
- 	for (i = start; !done && i < 256; i += len) {
- 		if (eeprom_data[i] == 0x84) {
-@@ -444,16 +456,17 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
- 			++i;
- 		} else {
- 			tveeprom_warn("Encountered bad packet header [%02x]. "
--				"Corrupt or not a Hauppauge eeprom.\n", eeprom_data[i]);
-+				"Corrupt or not a Hauppauge eeprom.\n",
-+				eeprom_data[i]);
- 			return;
- 		}
+diff --git a/drivers/misc/tifm_7xx1.c b/drivers/misc/tifm_7xx1.c
+index 2d1b3df..54380da 100644
+--- a/drivers/misc/tifm_7xx1.c
++++ b/drivers/misc/tifm_7xx1.c
+@@ -149,7 +149,7 @@ static void tifm_7xx1_switch_media(struct work_struct *work)
+ 	socket_change_set = fm->socket_change_set;
+ 	fm->socket_change_set = 0;
  
- 		if (debug) {
--			tveeprom_info("Tag [%02x] + %d bytes:", eeprom_data[i], len - 1);
--			for(j = 1; j < len; j++) {
--				printk(" %02x", eeprom_data[i + j]);
--			}
--			printk("\n");
-+			tveeprom_info("Tag [%02x] + %d bytes:",
-+					eeprom_data[i], len - 1);
-+			for (j = 1; j < len; j++)
-+				printk(KERN_CONT " %02x", eeprom_data[i + j]);
-+			printk(KERN_CONT "\n");
- 		}
+-	dev_dbg(fm->cdev.dev, "checking media set %x\n",
++	dev_dbg(fm->dev.parent, "checking media set %x\n",
+ 		socket_change_set);
  
- 		/* process by tag */
-@@ -504,16 +517,16 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
- 				(eeprom_data[i+6] << 8) +
- 				(eeprom_data[i+7] << 16);
+ 	if (!socket_change_set) {
+@@ -164,7 +164,7 @@ static void tifm_7xx1_switch_media(struct work_struct *work)
+ 		if (sock) {
+ 			printk(KERN_INFO
+ 			       "%s : demand removing card from socket %u:%u\n",
+-			       fm->cdev.class_id, fm->id, cnt);
++			       fm->dev.bus_id, fm->id, cnt);
+ 			fm->sockets[cnt] = NULL;
+ 			sock_addr = sock->addr;
+ 			spin_unlock_irqrestore(&fm->lock, flags);
+diff --git a/drivers/misc/tifm_core.c b/drivers/misc/tifm_core.c
+index 8f77949..9754405 100644
+--- a/drivers/misc/tifm_core.c
++++ b/drivers/misc/tifm_core.c
+@@ -160,16 +160,16 @@ static struct bus_type tifm_bus_type = {
+ 	.resume    = tifm_device_resume
+ };
  
--				if ( (eeprom_data[i + 8] & 0xf0) &&
--					(tvee->serial_number < 0xffffff) ) {
--					tvee->MAC_address[0] = 0x00;
--					tvee->MAC_address[1] = 0x0D;
--					tvee->MAC_address[2] = 0xFE;
--					tvee->MAC_address[3] = eeprom_data[i + 7];
--					tvee->MAC_address[4] = eeprom_data[i + 6];
--					tvee->MAC_address[5] = eeprom_data[i + 5];
--					tvee->has_MAC_address = 1;
--				}
-+			if ((eeprom_data[i + 8] & 0xf0) &&
-+					(tvee->serial_number < 0xffffff)) {
-+				tvee->MAC_address[0] = 0x00;
-+				tvee->MAC_address[1] = 0x0D;
-+				tvee->MAC_address[2] = 0xFE;
-+				tvee->MAC_address[3] = eeprom_data[i + 7];
-+				tvee->MAC_address[4] = eeprom_data[i + 6];
-+				tvee->MAC_address[5] = eeprom_data[i + 5];
-+				tvee->has_MAC_address = 1;
-+			}
- 			break;
+-static void tifm_free(struct class_device *cdev)
++static void tifm_free(struct device *dev)
+ {
+-	struct tifm_adapter *fm = container_of(cdev, struct tifm_adapter, cdev);
++	struct tifm_adapter *fm = container_of(dev, struct tifm_adapter, dev);
  
- 		case 0x05:
-@@ -537,7 +550,7 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
- 				(eeprom_data[i + 3] << 16) +
- 				(eeprom_data[i + 4] << 24);
- 			tvee->revision =
--				eeprom_data[i +5 ] +
-+				eeprom_data[i + 5] +
- 				(eeprom_data[i + 6] << 8) +
- 				(eeprom_data[i + 7] << 16);
- 			break;
-@@ -557,16 +570,16 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
- 		case 0x0a:
- 			/* tag 'Tuner' */
- 			if (beenhere == 0) {
--				tuner1 = eeprom_data[i+2];
--				t_format1 = eeprom_data[i+1];
-+				tuner1 = eeprom_data[i + 2];
-+				t_format1 = eeprom_data[i + 1];
- 				beenhere = 1;
- 			} else {
- 				/* a second (radio) tuner may be present */
--				tuner2 = eeprom_data[i+2];
--				t_format2 = eeprom_data[i+1];
--				if (t_format2 == 0) {  /* not a TV tuner? */
-+				tuner2 = eeprom_data[i + 2];
-+				t_format2 = eeprom_data[i + 1];
-+				/* not a TV tuner? */
-+				if (t_format2 == 0)
- 					tvee->has_radio = 1; /* must be radio */
--				}
- 			}
- 			break;
+ 	kfree(fm);
+ }
  
-@@ -594,7 +607,8 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
- 		/* case 0x12: tag 'InfoBits' */
+ static struct class tifm_adapter_class = {
+ 	.name    = "tifm_adapter",
+-	.release = tifm_free
++	.dev_release = tifm_free
+ };
  
- 		default:
--			tveeprom_dbg("Not sure what to do with tag [%02x]\n", tag);
-+			tveeprom_dbg("Not sure what to do with tag [%02x]\n",
-+					tag);
- 			/* dump the rest of the packet? */
- 		}
- 	}
-@@ -608,7 +622,7 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
- 		tvee->rev_str[0] = 32 + ((tvee->revision >> 18) & 0x3f);
- 		tvee->rev_str[1] = 32 + ((tvee->revision >> 12) & 0x3f);
- 		tvee->rev_str[2] = 32 + ((tvee->revision >>  6) & 0x3f);
--		tvee->rev_str[3] = 32 + ( tvee->revision        & 0x3f);
-+		tvee->rev_str[3] = 32 + (tvee->revision & 0x3f);
- 		tvee->rev_str[4] = 0;
+ struct tifm_adapter *tifm_alloc_adapter(unsigned int num_sockets,
+@@ -180,9 +180,9 @@ struct tifm_adapter *tifm_alloc_adapter(unsigned int num_sockets,
+ 	fm = kzalloc(sizeof(struct tifm_adapter)
+ 		     + sizeof(struct tifm_dev*) * num_sockets, GFP_KERNEL);
+ 	if (fm) {
+-		fm->cdev.class = &tifm_adapter_class;
+-		fm->cdev.dev = dev;
+-		class_device_initialize(&fm->cdev);
++		fm->dev.class = &tifm_adapter_class;
++		fm->dev.parent = dev;
++		device_initialize(&fm->dev);
+ 		spin_lock_init(&fm->lock);
+ 		fm->num_sockets = num_sockets;
  	}
+@@ -203,8 +203,8 @@ int tifm_add_adapter(struct tifm_adapter *fm)
+ 	if (rc)
+ 		return rc;
  
-@@ -651,44 +665,40 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
+-	snprintf(fm->cdev.class_id, BUS_ID_SIZE, "tifm%u", fm->id);
+-	rc = class_device_add(&fm->cdev);
++	snprintf(fm->dev.bus_id, BUS_ID_SIZE, "tifm%u", fm->id);
++	rc = device_add(&fm->dev);
+ 	if (rc) {
+ 		spin_lock(&tifm_adapter_lock);
+ 		idr_remove(&tifm_adapter_idr, fm->id);
+@@ -228,13 +228,13 @@ void tifm_remove_adapter(struct tifm_adapter *fm)
+ 	spin_lock(&tifm_adapter_lock);
+ 	idr_remove(&tifm_adapter_idr, fm->id);
+ 	spin_unlock(&tifm_adapter_lock);
+-	class_device_del(&fm->cdev);
++	device_del(&fm->dev);
+ }
+ EXPORT_SYMBOL(tifm_remove_adapter);
  
- 	tveeprom_info("Hauppauge model %d, rev %s, serial# %d\n",
- 		tvee->model, tvee->rev_str, tvee->serial_number);
--	if (tvee->has_MAC_address == 1) {
-+	if (tvee->has_MAC_address == 1)
- 		tveeprom_info("MAC address is %02X-%02X-%02X-%02X-%02X-%02X\n",
- 			tvee->MAC_address[0], tvee->MAC_address[1],
- 			tvee->MAC_address[2], tvee->MAC_address[3],
- 			tvee->MAC_address[4], tvee->MAC_address[5]);
--	}
- 	tveeprom_info("tuner model is %s (idx %d, type %d)\n",
- 		t_name1, tuner1, tvee->tuner_type);
- 	tveeprom_info("TV standards%s%s%s%s%s%s%s%s (eeprom 0x%02x)\n",
--		t_fmt_name1[0], t_fmt_name1[1], t_fmt_name1[2], t_fmt_name1[3],
--		t_fmt_name1[4], t_fmt_name1[5], t_fmt_name1[6], t_fmt_name1[7],
--		t_format1);
--	if (tuner2) {
-+		t_fmt_name1[0], t_fmt_name1[1], t_fmt_name1[2],
-+		t_fmt_name1[3],	t_fmt_name1[4], t_fmt_name1[5],
-+		t_fmt_name1[6], t_fmt_name1[7],	t_format1);
-+	if (tuner2)
- 		tveeprom_info("second tuner model is %s (idx %d, type %d)\n",
- 					t_name2, tuner2, tvee->tuner2_type);
--	}
--	if (t_format2) {
-+	if (t_format2)
- 		tveeprom_info("TV standards%s%s%s%s%s%s%s%s (eeprom 0x%02x)\n",
--			t_fmt_name2[0], t_fmt_name2[1], t_fmt_name2[2], t_fmt_name2[3],
--			t_fmt_name2[4], t_fmt_name2[5], t_fmt_name2[6], t_fmt_name2[7],
--			t_format2);
--	}
--	if (audioic<0) {
-+			t_fmt_name2[0], t_fmt_name2[1], t_fmt_name2[2],
-+			t_fmt_name2[3],	t_fmt_name2[4], t_fmt_name2[5],
-+			t_fmt_name2[6], t_fmt_name2[7], t_format2);
-+	if (audioic < 0) {
- 		tveeprom_info("audio processor is unknown (no idx)\n");
--		tvee->audio_processor=AUDIO_CHIP_UNKNOWN;
-+		tvee->audio_processor = AUDIO_CHIP_UNKNOWN;
- 	} else {
- 		if (audioic < ARRAY_SIZE(audioIC))
- 			tveeprom_info("audio processor is %s (idx %d)\n",
--					audioIC[audioic].name,audioic);
-+					audioIC[audioic].name, audioic);
- 		else
- 			tveeprom_info("audio processor is unknown (idx %d)\n",
- 								audioic);
- 	}
--	if (tvee->decoder_processor) {
-+	if (tvee->decoder_processor)
- 		tveeprom_info("decoder processor is %s (idx %d)\n",
- 			STRM(decoderIC, tvee->decoder_processor),
- 			tvee->decoder_processor);
+ void tifm_free_adapter(struct tifm_adapter *fm)
+ {
+-	class_device_put(&fm->cdev);
++	put_device(&fm->dev);
+ }
+ EXPORT_SYMBOL(tifm_free_adapter);
+ 
+@@ -261,9 +261,9 @@ struct tifm_dev *tifm_alloc_device(struct tifm_adapter *fm, unsigned int id,
+ 		sock->card_event = tifm_dummy_event;
+ 		sock->data_event = tifm_dummy_event;
+ 
+-		sock->dev.parent = fm->cdev.dev;
++		sock->dev.parent = fm->dev.parent;
+ 		sock->dev.bus = &tifm_bus_type;
+-		sock->dev.dma_mask = fm->cdev.dev->dma_mask;
++		sock->dev.dma_mask = fm->dev.parent->dma_mask;
+ 		sock->dev.release = tifm_free_device;
+ 
+ 		snprintf(sock->dev.bus_id, BUS_ID_SIZE,
+diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
+index aeb32a9..91ded3e 100644
+--- a/drivers/mmc/card/block.c
++++ b/drivers/mmc/card/block.c
+@@ -348,15 +348,7 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
+ 		 * A block was successfully transferred.
+ 		 */
+ 		spin_lock_irq(&md->lock);
+-		ret = end_that_request_chunk(req, 1, brq.data.bytes_xfered);
+-		if (!ret) {
+-			/*
+-			 * The whole request completed successfully.
+-			 */
+-			add_disk_randomness(req->rq_disk);
+-			blkdev_dequeue_request(req);
+-			end_that_request_last(req, 1);
+-		}
++		ret = __blk_end_request(req, 0, brq.data.bytes_xfered);
+ 		spin_unlock_irq(&md->lock);
+ 	} while (ret);
+ 
+@@ -386,27 +378,21 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
+ 			else
+ 				bytes = blocks << 9;
+ 			spin_lock_irq(&md->lock);
+-			ret = end_that_request_chunk(req, 1, bytes);
++			ret = __blk_end_request(req, 0, bytes);
+ 			spin_unlock_irq(&md->lock);
+ 		}
+ 	} else if (rq_data_dir(req) != READ &&
+ 		   (card->host->caps & MMC_CAP_MULTIWRITE)) {
+ 		spin_lock_irq(&md->lock);
+-		ret = end_that_request_chunk(req, 1, brq.data.bytes_xfered);
++		ret = __blk_end_request(req, 0, brq.data.bytes_xfered);
+ 		spin_unlock_irq(&md->lock);
+ 	}
+ 
+ 	mmc_release_host(card->host);
+ 
+ 	spin_lock_irq(&md->lock);
+-	while (ret) {
+-		ret = end_that_request_chunk(req, 0,
+-				req->current_nr_sectors << 9);
 -	}
- 	if (tvee->has_ir == -1)
- 		tveeprom_info("has %sradio\n",
- 				tvee->has_radio ? "" : "no ");
-@@ -709,11 +719,13 @@ int tveeprom_read(struct i2c_client *c, unsigned char *eedata, int len)
- 	int err;
+-
+-	add_disk_randomness(req->rq_disk);
+-	blkdev_dequeue_request(req);
+-	end_that_request_last(req, 0);
++	while (ret)
++		ret = __blk_end_request(req, -EIO, blk_rq_cur_bytes(req));
+ 	spin_unlock_irq(&md->lock);
  
- 	buf = 0;
--	if (1 != (err = i2c_master_send(c, &buf, 1))) {
-+	err = i2c_master_send(c, &buf, 1);
-+	if (err != 1) {
- 		tveeprom_info("Huh, no eeprom present (err=%d)?\n", err);
- 		return -1;
- 	}
--	if (len != (err = i2c_master_recv(c, eedata, len))) {
-+	err = i2c_master_recv(c, eedata, len);
-+	if (err != len) {
- 		tveeprom_warn("i2c eeprom read error (err=%d)\n", err);
- 		return -1;
- 	}
-@@ -724,9 +736,9 @@ int tveeprom_read(struct i2c_client *c, unsigned char *eedata, int len)
- 		for (i = 0; i < len; i++) {
- 			if (0 == (i % 16))
- 				tveeprom_info("%02x:", i);
--			printk(" %02x", eedata[i]);
-+			printk(KERN_CONT " %02x", eedata[i]);
- 			if (15 == (i % 16))
--				printk("\n");
-+				printk(KERN_CONT "\n");
+ 	return 0;
+diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c
+index 30cd13b..7731dde 100644
+--- a/drivers/mmc/card/queue.c
++++ b/drivers/mmc/card/queue.c
+@@ -94,8 +94,8 @@ static void mmc_request(struct request_queue *q)
+ 		printk(KERN_ERR "MMC: killing requests for dead queue\n");
+ 		while ((req = elv_next_request(q)) != NULL) {
+ 			do {
+-				ret = end_that_request_chunk(req, 0,
+-					req->current_nr_sectors << 9);
++				ret = __blk_end_request(req, -EIO,
++							blk_rq_cur_bytes(req));
+ 			} while (ret);
  		}
+ 		return;
+diff --git a/drivers/mmc/host/omap.c b/drivers/mmc/host/omap.c
+index 971e18b..c9dfeb1 100644
+--- a/drivers/mmc/host/omap.c
++++ b/drivers/mmc/host/omap.c
+@@ -25,6 +25,7 @@
+ #include <linux/mmc/card.h>
+ #include <linux/clk.h>
+ #include <linux/scatterlist.h>
++#include <linux/i2c/tps65010.h>
+ 
+ #include <asm/io.h>
+ #include <asm/irq.h>
+@@ -35,7 +36,6 @@
+ #include <asm/arch/dma.h>
+ #include <asm/arch/mux.h>
+ #include <asm/arch/fpga.h>
+-#include <asm/arch/tps65010.h>
+ 
+ #define	OMAP_MMC_REG_CMD	0x00
+ #define	OMAP_MMC_REG_ARGL	0x04
+diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c
+index 1654a33..1ea8482 100644
+--- a/drivers/mmc/host/pxamci.c
++++ b/drivers/mmc/host/pxamci.c
+@@ -65,6 +65,8 @@ struct pxamci_host {
+ 	unsigned int		dma_len;
+ 
+ 	unsigned int		dma_dir;
++	unsigned int		dma_drcmrrx;
++	unsigned int		dma_drcmrtx;
+ };
+ 
+ static void pxamci_stop_clock(struct pxamci_host *host)
+@@ -131,13 +133,13 @@ static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data)
+ 	if (data->flags & MMC_DATA_READ) {
+ 		host->dma_dir = DMA_FROM_DEVICE;
+ 		dcmd = DCMD_INCTRGADDR | DCMD_FLOWTRG;
+-		DRCMRTXMMC = 0;
+-		DRCMRRXMMC = host->dma | DRCMR_MAPVLD;
++		DRCMR(host->dma_drcmrtx) = 0;
++		DRCMR(host->dma_drcmrrx) = host->dma | DRCMR_MAPVLD;
+ 	} else {
+ 		host->dma_dir = DMA_TO_DEVICE;
+ 		dcmd = DCMD_INCSRCADDR | DCMD_FLOWSRC;
+-		DRCMRRXMMC = 0;
+-		DRCMRTXMMC = host->dma | DRCMR_MAPVLD;
++		DRCMR(host->dma_drcmrrx) = 0;
++		DRCMR(host->dma_drcmrtx) = host->dma | DRCMR_MAPVLD;
  	}
- 	return 0;
-@@ -758,9 +770,9 @@ tveeprom_command(struct i2c_client *client,
  
- 	switch (cmd) {
- 	case 0:
--		buf = kzalloc(256,GFP_KERNEL);
--		tveeprom_read(client,buf,256);
--		tveeprom_hauppauge_analog(client, &eeprom,buf);
-+		buf = kzalloc(256, GFP_KERNEL);
-+		tveeprom_read(client, buf, 256);
-+		tveeprom_hauppauge_analog(client, &eeprom, buf);
- 		kfree(buf);
- 		eeprom_props[0] = eeprom.tuner_type;
- 		eeprom_props[1] = eeprom.tuner_formats;
-@@ -794,7 +806,7 @@ tveeprom_detect_client(struct i2c_adapter *adapter,
- }
+ 	dcmd |= DCMD_BURST32 | DCMD_WIDTH1;
+@@ -375,14 +377,23 @@ static void pxamci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+ 		if (host->clkrt == CLKRT_OFF)
+ 			clk_enable(host->clk);
  
- static int
--tveeprom_attach_adapter (struct i2c_adapter *adapter)
-+tveeprom_attach_adapter(struct i2c_adapter *adapter)
- {
- 	if (adapter->class & I2C_CLASS_TV_ANALOG)
- 		return i2c_probe(adapter, &addr_data, tveeprom_detect_client);
-@@ -802,7 +814,7 @@ tveeprom_attach_adapter (struct i2c_adapter *adapter)
- }
+-		/*
+-		 * clk might result in a lower divisor than we
+-		 * desire.  check for that condition and adjust
+-		 * as appropriate.
+-		 */
+-		if (rate / clk > ios->clock)
+-			clk <<= 1;
+-		host->clkrt = fls(clk) - 1;
++		if (ios->clock == 26000000) {
++			/* to support 26MHz on pxa300/pxa310 */
++			host->clkrt = 7;
++		} else {
++			/* to handle (19.5MHz, 26MHz) */
++			if (!clk)
++				clk = 1;
++
++			/*
++			 * clk might result in a lower divisor than we
++			 * desire.  check for that condition and adjust
++			 * as appropriate.
++			 */
++			if (rate / clk > ios->clock)
++				clk <<= 1;
++			host->clkrt = fls(clk) - 1;
++		}
  
- static int
--tveeprom_detach_client (struct i2c_client *client)
-+tveeprom_detach_client(struct i2c_client *client)
+ 		/*
+ 		 * we write clkrt on the next command
+@@ -459,7 +470,7 @@ static int pxamci_probe(struct platform_device *pdev)
  {
- 	int err;
+ 	struct mmc_host *mmc;
+ 	struct pxamci_host *host = NULL;
+-	struct resource *r;
++	struct resource *r, *dmarx, *dmatx;
+ 	int ret, irq;
+ 
+ 	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+@@ -519,7 +530,8 @@ static int pxamci_probe(struct platform_device *pdev)
+ 	 * Calculate minimum clock rate, rounding up.
+ 	 */
+ 	mmc->f_min = (host->clkrate + 63) / 64;
+-	mmc->f_max = host->clkrate;
++	mmc->f_max = (cpu_is_pxa300() || cpu_is_pxa310()) ? 26000000
++							  : host->clkrate;
+ 
+ 	mmc->ocr_avail = host->pdata ?
+ 			 host->pdata->ocr_mask :
+@@ -529,6 +541,9 @@ static int pxamci_probe(struct platform_device *pdev)
+ 	if (!cpu_is_pxa21x() && !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())
++			mmc->caps |= MMC_CAP_MMC_HIGHSPEED |
++				     MMC_CAP_SD_HIGHSPEED;
+ 	}
+ 
+ 	host->sg_cpu = dma_alloc_coherent(&pdev->dev, PAGE_SIZE, &host->sg_dma, GFP_KERNEL);
+@@ -570,6 +585,20 @@ static int pxamci_probe(struct platform_device *pdev)
+ 
+ 	platform_set_drvdata(pdev, mmc);
+ 
++	dmarx = platform_get_resource(pdev, IORESOURCE_DMA, 0);
++	if (!dmarx) {
++		ret = -ENXIO;
++		goto out;
++	}
++	host->dma_drcmrrx = dmarx->start;
++
++	dmatx = platform_get_resource(pdev, IORESOURCE_DMA, 1);
++	if (!dmatx) {
++		ret = -ENXIO;
++		goto out;
++	}
++	host->dma_drcmrtx = dmatx->start;
++
+ 	if (host->pdata && host->pdata->init)
+ 		host->pdata->init(&pdev->dev, pxamci_detect_irq, mmc);
  
-diff --git a/drivers/media/video/upd64031a.c b/drivers/media/video/upd64031a.c
-index 0b2a961..bd20139 100644
---- a/drivers/media/video/upd64031a.c
-+++ b/drivers/media/video/upd64031a.c
-@@ -28,30 +28,27 @@
- #include <linux/videodev2.h>
- #include <media/v4l2-common.h>
- #include <media/v4l2-chip-ident.h>
-+#include <media/v4l2-i2c-drv.h>
- #include <media/upd64031a.h>
+@@ -613,8 +642,8 @@ static int pxamci_remove(struct platform_device *pdev)
+ 		       END_CMD_RES|PRG_DONE|DATA_TRAN_DONE,
+ 		       host->base + MMC_I_MASK);
+ 
+-		DRCMRRXMMC = 0;
+-		DRCMRTXMMC = 0;
++		DRCMR(host->dma_drcmrrx) = 0;
++		DRCMR(host->dma_drcmrtx) = 0;
+ 
+ 		free_irq(host->irq, host);
+ 		pxa_free_dma(host->dma);
+diff --git a/drivers/mmc/host/pxamci.h b/drivers/mmc/host/pxamci.h
+index 748c770..f6c2e2f 100644
+--- a/drivers/mmc/host/pxamci.h
++++ b/drivers/mmc/host/pxamci.h
+@@ -68,7 +68,7 @@
+ #define PRG_DONE		(1 << 1)
+ #define DATA_TRAN_DONE		(1 << 0)
  
--// --------------------- read registers functions define -----------------------
-+/* --------------------- read registers functions define -------------------- */
+-#ifdef CONFIG_PXA27x
++#if defined(CONFIG_PXA27x) || defined(CONFIG_PXA3xx)
+ #define MMC_I_MASK_ALL          0x00001fff
+ #else
+ #define MMC_I_MASK_ALL          0x0000007f
+diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c
+index 22ed96c..a0cee86 100644
+--- a/drivers/mtd/mtdchar.c
++++ b/drivers/mtd/mtdchar.c
+@@ -27,12 +27,10 @@ static void mtd_notify_add(struct mtd_info* mtd)
+ 	if (!mtd)
+ 		return;
  
- /* bit masks */
- #define GR_MODE_MASK              0xc0
- #define DIRECT_3DYCS_CONNECT_MASK 0xc0
- #define SYNC_CIRCUIT_MASK         0xa0
+-	class_device_create(mtd_class, NULL, MKDEV(MTD_CHAR_MAJOR, mtd->index*2),
+-			    NULL, "mtd%d", mtd->index);
++	device_create(mtd_class, NULL, MKDEV(MTD_CHAR_MAJOR, mtd->index*2), "mtd%d", mtd->index);
  
--// -----------------------------------------------------------------------------
-+/* -------------------------------------------------------------------------- */
+-	class_device_create(mtd_class, NULL,
+-			    MKDEV(MTD_CHAR_MAJOR, mtd->index*2+1),
+-			    NULL, "mtd%dro", mtd->index);
++	device_create(mtd_class, NULL,
++		      MKDEV(MTD_CHAR_MAJOR, mtd->index*2+1), "mtd%dro", mtd->index);
+ }
  
- MODULE_DESCRIPTION("uPD64031A driver");
- MODULE_AUTHOR("T. Adachi, Takeru KOMORIYA, Hans Verkuil");
- MODULE_LICENSE("GPL");
+ static void mtd_notify_remove(struct mtd_info* mtd)
+@@ -40,8 +38,8 @@ static void mtd_notify_remove(struct mtd_info* mtd)
+ 	if (!mtd)
+ 		return;
  
--static int debug = 0;
-+static int debug;
- module_param(debug, int, 0644);
+-	class_device_destroy(mtd_class, MKDEV(MTD_CHAR_MAJOR, mtd->index*2));
+-	class_device_destroy(mtd_class, MKDEV(MTD_CHAR_MAJOR, mtd->index*2+1));
++	device_destroy(mtd_class, MKDEV(MTD_CHAR_MAJOR, mtd->index*2));
++	device_destroy(mtd_class, MKDEV(MTD_CHAR_MAJOR, mtd->index*2+1));
+ }
  
- MODULE_PARM_DESC(debug, "Debug level (0-1)");
+ static struct mtd_notifier notifier = {
+diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
+index 9af05a2..a672866 100644
+--- a/drivers/net/Kconfig
++++ b/drivers/net/Kconfig
+@@ -212,7 +212,7 @@ config MII
+ 
+ config MACB
+ 	tristate "Atmel MACB support"
+-	depends on AVR32 || ARCH_AT91SAM9260 || ARCH_AT91SAM9263
++	depends on AVR32 || ARCH_AT91SAM9260 || ARCH_AT91SAM9263 || ARCH_AT91CAP9
+ 	select PHYLIB
+ 	help
+ 	  The Atmel MACB ethernet interface is found on many AT32 and AT91
+diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c
+index 3286d2a..6a20a54 100644
+--- a/drivers/net/dm9000.c
++++ b/drivers/net/dm9000.c
+@@ -66,6 +66,7 @@
+ #include <linux/dm9000.h>
+ #include <linux/delay.h>
+ #include <linux/platform_device.h>
++#include <linux/irq.h>
  
--static unsigned short normal_i2c[] = { 0x24 >> 1, 0x26 >> 1, I2C_CLIENT_END };
--
--
--I2C_CLIENT_INSMOD;
+ #include <asm/delay.h>
+ #include <asm/irq.h>
+@@ -113,7 +114,7 @@
+ #define writesl	outsl
+ #define DM9000_IRQ_FLAGS	(IRQF_SHARED | IRQF_TRIGGER_HIGH)
+ #else
+-#define DM9000_IRQ_FLAGS	IRQF_SHARED
++#define DM9000_IRQ_FLAGS	(IRQF_SHARED | IRQT_RISING)
+ #endif
  
- enum {
- 	R00 = 0, R01, R02, R03, R04,
-@@ -99,7 +96,7 @@ static void upd64031a_write(struct i2c_client *client, u8 reg, u8 val)
+ /*
+diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c
+index 7d7758f..57772be 100644
+--- a/drivers/net/ibmveth.c
++++ b/drivers/net/ibmveth.c
+@@ -1179,13 +1179,15 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_
  
- 	buf[0] = reg;
- 	buf[1] = val;
--	v4l_dbg(1, debug, client, "writing reg addr: %02X val: %02X\n", reg, val);
-+	v4l_dbg(1, debug, client, "write reg: %02X val: %02X\n", reg, val);
- 	if (i2c_master_send(client, buf, 2) != 2)
- 		v4l_err(client, "I/O error write 0x%02x/0x%02x\n", reg, val);
- }
-@@ -119,7 +116,7 @@ static void upd64031a_change(struct i2c_client *client)
+ 	for(i = 0; i<IbmVethNumBufferPools; i++) {
+ 		struct kobject *kobj = &adapter->rx_buff_pool[i].kobj;
++		int error;
++
+ 		ibmveth_init_buffer_pool(&adapter->rx_buff_pool[i], i,
+ 					 pool_count[i], pool_size[i],
+ 					 pool_active[i]);
+-		kobj->parent = &dev->dev.kobj;
+-		kobject_set_name(kobj, "pool%d", i);
+-		kobj->ktype = &ktype_veth_pool;
+-		kobject_register(kobj);
++		error = kobject_init_and_add(kobj, &ktype_veth_pool,
++					     &dev->dev.kobj, "pool%d", i);
++		if (!error)
++			kobject_uevent(kobj, KOBJ_ADD);
+ 	}
  
- /* ------------------------------------------------------------------------ */
+ 	ibmveth_debug_printk("adapter @ 0x%p\n", adapter);
+@@ -1234,7 +1236,7 @@ static int __devexit ibmveth_remove(struct vio_dev *dev)
+ 	int i;
  
--static int upd64031a_command(struct i2c_client *client, unsigned int cmd, void *arg)
-+static int upd64031a_command(struct i2c_client *client, unsigned cmd, void *arg)
+ 	for(i = 0; i<IbmVethNumBufferPools; i++)
+-		kobject_unregister(&adapter->rx_buff_pool[i].kobj);
++		kobject_put(&adapter->rx_buff_pool[i].kobj);
+ 
+ 	unregister_netdev(netdev);
+ 
+diff --git a/drivers/net/iseries_veth.c b/drivers/net/iseries_veth.c
+index 97bd9dc..419861c 100644
+--- a/drivers/net/iseries_veth.c
++++ b/drivers/net/iseries_veth.c
+@@ -815,7 +815,7 @@ static int veth_init_connection(u8 rlp)
  {
- 	struct upd64031a_state *state = i2c_get_clientdata(client);
- 	struct v4l2_routing *route = arg;
-@@ -143,8 +140,10 @@ static int upd64031a_command(struct i2c_client *client, unsigned int cmd, void *
+ 	struct veth_lpar_connection *cnx;
+ 	struct veth_msg *msgs;
+-	int i, rc;
++	int i;
  
- 		state->gr_mode = (route->input & 3) << 6;
- 		state->direct_3dycs_connect = (route->input & 0xc) << 4;
--		state->ext_comp_sync = (route->input & UPD64031A_COMPOSITE_EXTERNAL) << 1;
--		state->ext_vert_sync = (route->input & UPD64031A_VERTICAL_EXTERNAL) << 2;
-+		state->ext_comp_sync =
-+			(route->input & UPD64031A_COMPOSITE_EXTERNAL) << 1;
-+		state->ext_vert_sync =
-+			(route->input & UPD64031A_VERTICAL_EXTERNAL) << 2;
- 		r00 = (state->regs[R00] & ~GR_MODE_MASK) | state->gr_mode;
- 		r05 = (state->regs[R00] & ~SYNC_CIRCUIT_MASK) |
- 			state->ext_comp_sync | state->ext_vert_sync;
-@@ -168,20 +167,23 @@ static int upd64031a_command(struct i2c_client *client, unsigned int cmd, void *
- 	{
- 		struct v4l2_register *reg = arg;
+ 	if ( (rlp == this_lp)
+ 	     || ! HvLpConfig_doLpsCommunicateOnVirtualLan(this_lp, rlp) )
+@@ -844,11 +844,7 @@ static int veth_init_connection(u8 rlp)
  
--		if (!v4l2_chip_match_i2c_client(client, reg->match_type, reg->match_chip))
-+		if (!v4l2_chip_match_i2c_client(client,
-+					reg->match_type, reg->match_chip))
- 			return -EINVAL;
- 		if (!capable(CAP_SYS_ADMIN))
- 			return -EPERM;
--		if (cmd == VIDIOC_DBG_G_REGISTER)
-+		if (cmd == VIDIOC_DBG_G_REGISTER) {
- 			reg->val = upd64031a_read(client, reg->reg & 0xff);
--		else
--			upd64031a_write(client, reg->reg & 0xff, reg->val & 0xff);
-+			break;
-+		}
-+		upd64031a_write(client, reg->reg & 0xff, reg->val & 0xff);
- 		break;
+ 	/* This gets us 1 reference, which is held on behalf of the driver
+ 	 * infrastructure. It's released at module unload. */
+-	kobject_init(&cnx->kobject);
+-	cnx->kobject.ktype = &veth_lpar_connection_ktype;
+-	rc = kobject_set_name(&cnx->kobject, "cnx%.2d", rlp);
+-	if (rc != 0)
+-		return rc;
++	kobject_init(&cnx->kobject, &veth_lpar_connection_ktype);
+ 
+ 	msgs = kcalloc(VETH_NUMBUFFERS, sizeof(struct veth_msg), GFP_KERNEL);
+ 	if (! msgs) {
+@@ -1087,11 +1083,8 @@ static struct net_device * __init veth_probe_one(int vlan,
+ 		return NULL;
  	}
- #endif
  
- 	case VIDIOC_G_CHIP_IDENT:
--		return v4l2_chip_ident_i2c_client(client, arg, V4L2_IDENT_UPD64031A, 0);
-+		return v4l2_chip_ident_i2c_client(client, arg,
-+				V4L2_IDENT_UPD64031A, 0);
+-	kobject_init(&port->kobject);
+-	port->kobject.parent = &dev->dev.kobj;
+-	port->kobject.ktype  = &veth_port_ktype;
+-	kobject_set_name(&port->kobject, "veth_port");
+-	if (0 != kobject_add(&port->kobject))
++	kobject_init(&port->kobject, &veth_port_ktype);
++	if (0 != kobject_add(&port->kobject, &dev->dev.kobj, "veth_port"))
+ 		veth_error("Failed adding port for %s to sysfs.\n", dev->name);
  
- 	default:
- 		break;
-@@ -193,90 +195,43 @@ static int upd64031a_command(struct i2c_client *client, unsigned int cmd, void *
+ 	veth_info("%s attached to iSeries vlan %d (LPAR map = 0x%.4X)\n",
+@@ -1711,9 +1704,9 @@ static int __init veth_module_init(void)
+ 			continue;
  
- /* i2c implementation */
+ 		kobj = &veth_cnx[i]->kobject;
+-		kobj->parent = &veth_driver.driver.kobj;
+ 		/* If the add failes, complain but otherwise continue */
+-		if (0 != kobject_add(kobj))
++		if (0 != driver_add_kobj(&veth_driver.driver, kobj,
++					"cnx%.2d", veth_cnx[i]->remote_lp))
+ 			veth_error("cnx %d: Failed adding to sysfs.\n", i);
+ 	}
  
--static struct i2c_driver i2c_driver;
+diff --git a/drivers/net/mlx4/fw.c b/drivers/net/mlx4/fw.c
+index 5064873..535a446 100644
+--- a/drivers/net/mlx4/fw.c
++++ b/drivers/net/mlx4/fw.c
+@@ -202,7 +202,7 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
+ 	MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_EQ_OFFSET);
+ 	dev_cap->reserved_eqs = 1 << (field & 0xf);
+ 	MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_EQ_OFFSET);
+-	dev_cap->max_eqs = 1 << (field & 0x7);
++	dev_cap->max_eqs = 1 << (field & 0xf);
+ 	MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_MTT_OFFSET);
+ 	dev_cap->reserved_mtts = 1 << (field >> 4);
+ 	MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_MRW_SZ_OFFSET);
+diff --git a/drivers/net/smc91x.c b/drivers/net/smc91x.c
+index 7da7589..4020e9e 100644
+--- a/drivers/net/smc91x.c
++++ b/drivers/net/smc91x.c
+@@ -1775,7 +1775,8 @@ static int __init smc_findirq(void __iomem *ioaddr)
+  * o  actually GRAB the irq.
+  * o  GRAB the region
+  */
+-static int __init smc_probe(struct net_device *dev, void __iomem *ioaddr)
++static int __init smc_probe(struct net_device *dev, void __iomem *ioaddr,
++			    unsigned long irq_flags)
+ {
+ 	struct smc_local *lp = netdev_priv(dev);
+ 	static int version_printed = 0;
+@@ -1941,7 +1942,7 @@ static int __init smc_probe(struct net_device *dev, void __iomem *ioaddr)
+ 	}
+ 
+ 	/* Grab the IRQ */
+-      	retval = request_irq(dev->irq, &smc_interrupt, SMC_IRQ_FLAGS, dev->name, dev);
++	retval = request_irq(dev->irq, &smc_interrupt, irq_flags, dev->name, dev);
+       	if (retval)
+       		goto err_out;
+ 
+@@ -2123,8 +2124,9 @@ static void smc_release_datacs(struct platform_device *pdev, struct net_device *
+ static int smc_drv_probe(struct platform_device *pdev)
+ {
+ 	struct net_device *ndev;
+-	struct resource *res;
++	struct resource *res, *ires;
+ 	unsigned int __iomem *addr;
++	unsigned long irq_flags = SMC_IRQ_FLAGS;
+ 	int ret;
+ 
+ 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "smc91x-regs");
+@@ -2150,12 +2152,17 @@ static int smc_drv_probe(struct platform_device *pdev)
+ 	SET_NETDEV_DEV(ndev, &pdev->dev);
+ 
+ 	ndev->dma = (unsigned char)-1;
+-	ndev->irq = platform_get_irq(pdev, 0);
+-	if (ndev->irq < 0) {
++
++	ires = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
++	if (!ires) {
+ 		ret = -ENODEV;
+ 		goto out_free_netdev;
+ 	}
+ 
++	ndev->irq = ires->start;
++	if (SMC_IRQ_FLAGS == -1)
++		irq_flags = ires->flags & IRQF_TRIGGER_MASK;
++
+ 	ret = smc_request_attrib(pdev);
+ 	if (ret)
+ 		goto out_free_netdev;
+@@ -2181,7 +2188,7 @@ static int smc_drv_probe(struct platform_device *pdev)
+ #endif
+ 
+ 	platform_set_drvdata(pdev, ndev);
+-	ret = smc_probe(ndev, addr);
++	ret = smc_probe(ndev, addr, irq_flags);
+ 	if (ret != 0)
+ 		goto out_iounmap;
+ 
+diff --git a/drivers/net/smc91x.h b/drivers/net/smc91x.h
+index 07b7f71..271c28d 100644
+--- a/drivers/net/smc91x.h
++++ b/drivers/net/smc91x.h
+@@ -54,6 +54,7 @@
+ #define SMC_outw(v, a, r)	writew(v, (a) + (r))
+ #define SMC_insw(a, r, p, l)	readsw((a) + (r), p, l)
+ #define SMC_outsw(a, r, p, l)	writesw((a) + (r), p, l)
++#define SMC_IRQ_FLAGS		(-1)	/* from resource */
+ 
+ #elif defined(CONFIG_BLACKFIN)
+ 
+@@ -158,7 +159,7 @@
+ #define SMC_outw(v, a, r)	writew(v, (a) + (r))
+ #define SMC_outsw(a, r, p, l)	writesw((a) + (r), p, l)
+ 
+-#define SMC_IRQ_FLAGS		(0)
++#define SMC_IRQ_FLAGS		(-1)
+ 
+ #elif defined(CONFIG_SA1100_ASSABET)
+ 
+@@ -177,6 +178,7 @@
+ #define SMC_outb(v, a, r)	writeb(v, (a) + (r))
+ #define SMC_insb(a, r, p, l)	readsb((a) + (r), p, (l))
+ #define SMC_outsb(a, r, p, l)	writesb((a) + (r), p, (l))
++#define SMC_IRQ_FLAGS		(-1)	/* from resource */
+ 
+ #elif	defined(CONFIG_MACH_LOGICPD_PXA270)
+ 
+@@ -194,7 +196,8 @@
+ #elif	defined(CONFIG_ARCH_INNOKOM) || \
+ 	defined(CONFIG_MACH_MAINSTONE) || \
+ 	defined(CONFIG_ARCH_PXA_IDP) || \
+-	defined(CONFIG_ARCH_RAMSES)
++	defined(CONFIG_ARCH_RAMSES) || \
++	defined(CONFIG_ARCH_PCM027)
+ 
+ #define SMC_CAN_USE_8BIT	1
+ #define SMC_CAN_USE_16BIT	1
+@@ -210,6 +213,7 @@
+ #define SMC_outl(v, a, r)	writel(v, (a) + (r))
+ #define SMC_insl(a, r, p, l)	readsl((a) + (r), p, l)
+ #define SMC_outsl(a, r, p, l)	writesl((a) + (r), p, l)
++#define SMC_IRQ_FLAGS		(-1)	/* from resource */
+ 
+ /* We actually can't write halfwords properly if not word aligned */
+ static inline void
+@@ -238,6 +242,7 @@ SMC_outw(u16 val, void __iomem *ioaddr, int reg)
+ #define SMC_outsw(a, r, p, l)   outsw((a) + (r), p, l)
+ #define SMC_outb(v, a, r)       writeb(v, (a) + (r))
+ #define SMC_outw(v, a, r)       writew(v, (a) + (r))
++#define SMC_IRQ_FLAGS		(-1)	/* from resource */
+ 
+ #elif	defined(CONFIG_ARCH_OMAP)
+ 
+@@ -252,17 +257,7 @@ SMC_outw(u16 val, void __iomem *ioaddr, int reg)
+ #define SMC_outw(v, a, r)	writew(v, (a) + (r))
+ #define SMC_insw(a, r, p, l)	readsw((a) + (r), p, l)
+ #define SMC_outsw(a, r, p, l)	writesw((a) + (r), p, l)
+-
+-#include <asm/mach-types.h>
+-#include <asm/arch/cpu.h>
+-
+-#define	SMC_IRQ_FLAGS (( \
+-		   machine_is_omap_h2() \
+-		|| machine_is_omap_h3() \
+-		|| machine_is_omap_h4() \
+-		|| (machine_is_omap_innovator() && !cpu_is_omap1510()) \
+-	) ? IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING)
+-
++#define	SMC_IRQ_FLAGS		(-1)	/* from resource */
+ 
+ #elif	defined(CONFIG_SH_SH4202_MICRODEV)
+ 
+@@ -453,8 +448,7 @@ static inline void LPD7_SMC_outsw (unsigned char* a, int r,
+ #define SMC_outl(v, a, r)	writel(v, (a) + (r))
+ #define SMC_insl(a, r, p, l)	readsl((a) + (r), p, l)
+ #define SMC_outsl(a, r, p, l)	writesl((a) + (r), p, l)
 -
--static int upd64031a_attach(struct i2c_adapter *adapter, int address, int kind)
-+static int upd64031a_probe(struct i2c_client *client)
+-#define SMC_IRQ_FLAGS		(0)
++#define SMC_IRQ_FLAGS		(-1)	/* from resource */
+ 
+ #else
+ 
+diff --git a/drivers/net/wan/cosa.c b/drivers/net/wan/cosa.c
+index ff37bf4..1d706ea 100644
+--- a/drivers/net/wan/cosa.c
++++ b/drivers/net/wan/cosa.c
+@@ -395,8 +395,7 @@ static int __init cosa_init(void)
+ 		goto out_chrdev;
+ 	}
+ 	for (i=0; i<nr_cards; i++) {
+-		class_device_create(cosa_class, NULL, MKDEV(cosa_major, i),
+-				NULL, "cosa%d", i);
++		device_create(cosa_class, NULL, MKDEV(cosa_major, i), "cosa%d", i);
+ 	}
+ 	err = 0;
+ 	goto out;
+@@ -415,7 +414,7 @@ static void __exit cosa_exit(void)
+ 	printk(KERN_INFO "Unloading the cosa module\n");
+ 
+ 	for (i=0; i<nr_cards; i++)
+-		class_device_destroy(cosa_class, MKDEV(cosa_major, i));
++		device_destroy(cosa_class, MKDEV(cosa_major, i));
+ 	class_destroy(cosa_class);
+ 	for (cosa=cosa_cards; nr_cards--; cosa++) {
+ 		/* Clean up the per-channel data */
+diff --git a/drivers/parisc/pdc_stable.c b/drivers/parisc/pdc_stable.c
+index ebb09e9..de34aa9 100644
+--- a/drivers/parisc/pdc_stable.c
++++ b/drivers/parisc/pdc_stable.c
+@@ -120,7 +120,7 @@ struct pdcspath_entry pdcspath_entry_##_name = { \
+ };
+ 
+ #define PDCS_ATTR(_name, _mode, _show, _store) \
+-struct subsys_attribute pdcs_attr_##_name = { \
++struct kobj_attribute pdcs_attr_##_name = { \
+ 	.attr = {.name = __stringify(_name), .mode = _mode}, \
+ 	.show = _show, \
+ 	.store = _store, \
+@@ -523,15 +523,15 @@ static struct pdcspath_entry *pdcspath_entries[] = {
+ 
+ /**
+  * pdcs_size_read - Stable Storage size output.
+- * @kset: An allocated and populated struct kset. We don't use it tho.
+  * @buf: The output buffer to write to.
+  */
+-static ssize_t
+-pdcs_size_read(struct kset *kset, char *buf)
++static ssize_t pdcs_size_read(struct kobject *kobj,
++			      struct kobj_attribute *attr,
++			      char *buf)
  {
--	struct i2c_client *client;
- 	struct upd64031a_state *state;
- 	int i;
+ 	char *out = buf;
  
--	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
--		return 0;
--
--	client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
--	if (client == NULL) {
--		return -ENOMEM;
--	}
--
--	client->addr = address;
--	client->adapter = adapter;
--	client->driver = &i2c_driver;
--	snprintf(client->name, sizeof(client->name) - 1, "uPD64031A");
-+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
-+		return -EIO;
+-	if (!kset || !buf)
++	if (!buf)
+ 		return -EINVAL;
  
--	v4l_info(client, "chip found @ 0x%x (%s)\n", address << 1, adapter->name);
-+	v4l_info(client, "chip found @ 0x%x (%s)\n",
-+			client->addr << 1, client->adapter->name);
+ 	/* show the size of the stable storage */
+@@ -542,17 +542,17 @@ pdcs_size_read(struct kset *kset, char *buf)
  
- 	state = kmalloc(sizeof(struct upd64031a_state), GFP_KERNEL);
--	if (state == NULL) {
--		kfree(client);
-+	if (state == NULL)
- 		return -ENOMEM;
--	}
- 	i2c_set_clientdata(client, state);
- 	memcpy(state->regs, upd64031a_init, sizeof(state->regs));
- 	state->gr_mode = UPD64031A_GR_ON << 6;
- 	state->direct_3dycs_connect = UPD64031A_3DYCS_COMPOSITE << 4;
- 	state->ext_comp_sync = state->ext_vert_sync = 0;
--	for (i = 0; i < TOT_REGS; i++) {
-+	for (i = 0; i < TOT_REGS; i++)
- 		upd64031a_write(client, i, state->regs[i]);
--	}
--
--	i2c_attach_client(client);
--
- 	return 0;
+ /**
+  * pdcs_auto_read - Stable Storage autoboot/search flag output.
+- * @kset: An allocated and populated struct kset. We don't use it tho.
+  * @buf: The output buffer to write to.
+  * @knob: The PF_AUTOBOOT or PF_AUTOSEARCH flag
+  */
+-static ssize_t
+-pdcs_auto_read(struct kset *kset, char *buf, int knob)
++static ssize_t pdcs_auto_read(struct kobject *kobj,
++			      struct kobj_attribute *attr,
++			      char *buf, int knob)
+ {
+ 	char *out = buf;
+ 	struct pdcspath_entry *pathentry;
+ 
+-	if (!kset || !buf)
++	if (!buf)
+ 		return -EINVAL;
+ 
+ 	/* Current flags are stored in primary boot path entry */
+@@ -568,40 +568,37 @@ pdcs_auto_read(struct kset *kset, char *buf, int knob)
+ 
+ /**
+  * pdcs_autoboot_read - Stable Storage autoboot flag output.
+- * @kset: An allocated and populated struct kset. We don't use it tho.
+  * @buf: The output buffer to write to.
+  */
+-static inline ssize_t
+-pdcs_autoboot_read(struct kset *kset, char *buf)
++static ssize_t pdcs_autoboot_read(struct kobject *kobj,
++				  struct kobj_attribute *attr, char *buf)
+ {
+-	return pdcs_auto_read(kset, buf, PF_AUTOBOOT);
++	return pdcs_auto_read(kobj, attr, buf, PF_AUTOBOOT);
  }
  
--static int upd64031a_probe(struct i2c_adapter *adapter)
-+static int upd64031a_remove(struct i2c_client *client)
+ /**
+  * pdcs_autosearch_read - Stable Storage autoboot flag output.
+- * @kset: An allocated and populated struct kset. We don't use it tho.
+  * @buf: The output buffer to write to.
+  */
+-static inline ssize_t
+-pdcs_autosearch_read(struct kset *kset, char *buf)
++static ssize_t pdcs_autosearch_read(struct kobject *kobj,
++				    struct kobj_attribute *attr, char *buf)
  {
--	if (adapter->class & I2C_CLASS_TV_ANALOG)
--		return i2c_probe(adapter, &addr_data, upd64031a_attach);
--	return 0;
--}
--
--static int upd64031a_detach(struct i2c_client *client)
--{
--	int err;
--
--	err = i2c_detach_client(client);
--	if (err)
--		return err;
--
--	kfree(client);
-+	kfree(i2c_get_clientdata(client));
- 	return 0;
+-	return pdcs_auto_read(kset, buf, PF_AUTOSEARCH);
++	return pdcs_auto_read(kobj, attr, buf, PF_AUTOSEARCH);
  }
  
- /* ----------------------------------------------------------------------- */
+ /**
+  * pdcs_timer_read - Stable Storage timer count output (in seconds).
+- * @kset: An allocated and populated struct kset. We don't use it tho.
+  * @buf: The output buffer to write to.
+  *
+  * The value of the timer field correponds to a number of seconds in powers of 2.
+  */
+-static ssize_t
+-pdcs_timer_read(struct kset *kset, char *buf)
++static ssize_t pdcs_timer_read(struct kobject *kobj,
++			       struct kobj_attribute *attr, char *buf)
+ {
+ 	char *out = buf;
+ 	struct pdcspath_entry *pathentry;
  
--/* i2c implementation */
--static struct i2c_driver i2c_driver = {
--	.driver = {
--		.name = "upd64031a",
--	},
--	.id = I2C_DRIVERID_UPD64031A,
--	.attach_adapter = upd64031a_probe,
--	.detach_client  = upd64031a_detach,
-+
-+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
-+	.name = "upd64031a",
-+	.driverid = I2C_DRIVERID_UPD64031A,
- 	.command = upd64031a_command,
-+	.probe = upd64031a_probe,
-+	.remove = upd64031a_remove,
- };
--
--
--static int __init upd64031a_init_module(void)
--{
--	return i2c_add_driver(&i2c_driver);
--}
--
--static void __exit upd64031a_exit_module(void)
--{
--	i2c_del_driver(&i2c_driver);
--}
--
--module_init(upd64031a_init_module);
--module_exit(upd64031a_exit_module);
-diff --git a/drivers/media/video/upd64083.c b/drivers/media/video/upd64083.c
-index 401bd21..2d9a88f 100644
---- a/drivers/media/video/upd64083.c
-+++ b/drivers/media/video/upd64083.c
-@@ -17,7 +17,8 @@
+-	if (!kset || !buf)
++	if (!buf)
+ 		return -EINVAL;
+ 
+ 	/* Current flags are stored in primary boot path entry */
+@@ -618,15 +615,14 @@ pdcs_timer_read(struct kset *kset, char *buf)
+ 
+ /**
+  * pdcs_osid_read - Stable Storage OS ID register output.
+- * @kset: An allocated and populated struct kset. We don't use it tho.
+  * @buf: The output buffer to write to.
+  */
+-static ssize_t
+-pdcs_osid_read(struct kset *kset, char *buf)
++static ssize_t pdcs_osid_read(struct kobject *kobj,
++			      struct kobj_attribute *attr, char *buf)
+ {
+ 	char *out = buf;
+ 
+-	if (!kset || !buf)
++	if (!buf)
+ 		return -EINVAL;
+ 
+ 	out += sprintf(out, "%s dependent data (0x%.4x)\n",
+@@ -637,18 +633,17 @@ pdcs_osid_read(struct kset *kset, char *buf)
+ 
+ /**
+  * pdcs_osdep1_read - Stable Storage OS-Dependent data area 1 output.
+- * @kset: An allocated and populated struct kset. We don't use it tho.
+  * @buf: The output buffer to write to.
   *
-  * You 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.
-+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-+ * 02110-1301, USA.
+  * This can hold 16 bytes of OS-Dependent data.
   */
+-static ssize_t
+-pdcs_osdep1_read(struct kset *kset, char *buf)
++static ssize_t pdcs_osdep1_read(struct kobject *kobj,
++				struct kobj_attribute *attr, char *buf)
+ {
+ 	char *out = buf;
+ 	u32 result[4];
  
- #include <linux/version.h>
-@@ -27,21 +28,18 @@
- #include <linux/videodev2.h>
- #include <media/v4l2-common.h>
- #include <media/v4l2-chip-ident.h>
-+#include <media/v4l2-i2c-drv.h>
- #include <media/upd64083.h>
+-	if (!kset || !buf)
++	if (!buf)
+ 		return -EINVAL;
  
- MODULE_DESCRIPTION("uPD64083 driver");
- MODULE_AUTHOR("T. Adachi, Takeru KOMORIYA, Hans Verkuil");
- MODULE_LICENSE("GPL");
+ 	if (pdc_stable_read(PDCS_ADDR_OSD1, &result, sizeof(result)) != PDC_OK)
+@@ -664,18 +659,17 @@ pdcs_osdep1_read(struct kset *kset, char *buf)
  
--static int debug = 0;
-+static int debug;
- module_param(debug, bool, 0644);
+ /**
+  * pdcs_diagnostic_read - Stable Storage Diagnostic register output.
+- * @kset: An allocated and populated struct kset. We don't use it tho.
+  * @buf: The output buffer to write to.
+  *
+  * I have NFC how to interpret the content of that register ;-).
+  */
+-static ssize_t
+-pdcs_diagnostic_read(struct kset *kset, char *buf)
++static ssize_t pdcs_diagnostic_read(struct kobject *kobj,
++				    struct kobj_attribute *attr, char *buf)
+ {
+ 	char *out = buf;
+ 	u32 result;
  
- MODULE_PARM_DESC(debug, "Debug level (0-1)");
+-	if (!kset || !buf)
++	if (!buf)
+ 		return -EINVAL;
  
--static unsigned short normal_i2c[] = { 0xb8 >> 1, 0xba >> 1, I2C_CLIENT_END };
--
--
--I2C_CLIENT_INSMOD;
+ 	/* get diagnostic */
+@@ -689,18 +683,17 @@ pdcs_diagnostic_read(struct kset *kset, char *buf)
  
- enum {
- 	R00 = 0, R01, R02, R03, R04,
-@@ -88,7 +86,7 @@ static void upd64083_write(struct i2c_client *client, u8 reg, u8 val)
+ /**
+  * pdcs_fastsize_read - Stable Storage FastSize register output.
+- * @kset: An allocated and populated struct kset. We don't use it tho.
+  * @buf: The output buffer to write to.
+  *
+  * This register holds the amount of system RAM to be tested during boot sequence.
+  */
+-static ssize_t
+-pdcs_fastsize_read(struct kset *kset, char *buf)
++static ssize_t pdcs_fastsize_read(struct kobject *kobj,
++				  struct kobj_attribute *attr, char *buf)
+ {
+ 	char *out = buf;
+ 	u32 result;
  
- 	buf[0] = reg;
- 	buf[1] = val;
--	v4l_dbg(1, debug, client, "writing reg addr: %02x val: %02x\n", reg, val);
-+	v4l_dbg(1, debug, client, "write reg: %02x val: %02x\n", reg, val);
- 	if (i2c_master_send(client, buf, 2) != 2)
- 		v4l_err(client, "I/O error write 0x%02x/0x%02x\n", reg, val);
- }
-@@ -109,7 +107,7 @@ static u8 upd64083_read(struct i2c_client *client, u8 reg)
+-	if (!kset || !buf)
++	if (!buf)
+ 		return -EINVAL;
  
- /* ------------------------------------------------------------------------ */
+ 	/* get fast-size */
+@@ -718,13 +711,12 @@ pdcs_fastsize_read(struct kset *kset, char *buf)
  
--static int upd64083_command(struct i2c_client *client, unsigned int cmd, void *arg)
-+static int upd64083_command(struct i2c_client *client, unsigned cmd, void *arg)
+ /**
+  * pdcs_osdep2_read - Stable Storage OS-Dependent data area 2 output.
+- * @kset: An allocated and populated struct kset. We don't use it tho.
+  * @buf: The output buffer to write to.
+  *
+  * This can hold pdcs_size - 224 bytes of OS-Dependent data, when available.
+  */
+-static ssize_t
+-pdcs_osdep2_read(struct kset *kset, char *buf)
++static ssize_t pdcs_osdep2_read(struct kobject *kobj,
++				struct kobj_attribute *attr, char *buf)
  {
- 	struct upd64083_state *state = i2c_get_clientdata(client);
- 	struct v4l2_routing *route = arg;
-@@ -145,20 +143,23 @@ static int upd64083_command(struct i2c_client *client, unsigned int cmd, void *a
- 	{
- 		struct v4l2_register *reg = arg;
- 
--		if (!v4l2_chip_match_i2c_client(client, reg->match_type, reg->match_chip))
-+		if (!v4l2_chip_match_i2c_client(client,
-+				reg->match_type, reg->match_chip))
- 			return -EINVAL;
- 		if (!capable(CAP_SYS_ADMIN))
- 			return -EPERM;
--		if (cmd == VIDIOC_DBG_G_REGISTER)
-+		if (cmd == VIDIOC_DBG_G_REGISTER) {
- 			reg->val = upd64083_read(client, reg->reg & 0xff);
--		else
--			upd64083_write(client, reg->reg & 0xff, reg->val & 0xff);
-+			break;
-+		}
-+		upd64083_write(client, reg->reg & 0xff, reg->val & 0xff);
- 		break;
- 	}
- #endif
+ 	char *out = buf;
+ 	unsigned long size;
+@@ -736,7 +728,7 @@ pdcs_osdep2_read(struct kset *kset, char *buf)
  
- 	case VIDIOC_G_CHIP_IDENT:
--		return v4l2_chip_ident_i2c_client(client, arg, V4L2_IDENT_UPD64083, 0);
-+		return v4l2_chip_ident_i2c_client(client, arg,
-+				V4L2_IDENT_UPD64083, 0);
+ 	size = pdcs_size - 224;
  
- 	default:
- 		break;
-@@ -171,89 +172,43 @@ static int upd64083_command(struct i2c_client *client, unsigned int cmd, void *a
+-	if (!kset || !buf)
++	if (!buf)
+ 		return -EINVAL;
  
- /* i2c implementation */
+ 	for (i=0; i<size; i+=4) {
+@@ -751,7 +743,6 @@ pdcs_osdep2_read(struct kset *kset, char *buf)
  
--static struct i2c_driver i2c_driver;
--
--static int upd64083_attach(struct i2c_adapter *adapter, int address, int kind)
-+static int upd64083_probe(struct i2c_client *client)
+ /**
+  * pdcs_auto_write - This function handles autoboot/search flag modifying.
+- * @kset: An allocated and populated struct kset. We don't use it tho.
+  * @buf: The input buffer to read from.
+  * @count: The number of bytes to be read.
+  * @knob: The PF_AUTOBOOT or PF_AUTOSEARCH flag
+@@ -760,8 +751,9 @@ pdcs_osdep2_read(struct kset *kset, char *buf)
+  * We expect a precise syntax:
+  *	\"n\" (n == 0 or 1) to toggle AutoBoot Off or On
+  */
+-static ssize_t
+-pdcs_auto_write(struct kset *kset, const char *buf, size_t count, int knob)
++static ssize_t pdcs_auto_write(struct kobject *kobj,
++			       struct kobj_attribute *attr, const char *buf,
++			       size_t count, int knob)
  {
--	struct i2c_client *client;
- 	struct upd64083_state *state;
- 	int i;
+ 	struct pdcspath_entry *pathentry;
+ 	unsigned char flags;
+@@ -771,7 +763,7 @@ pdcs_auto_write(struct kset *kset, const char *buf, size_t count, int knob)
+ 	if (!capable(CAP_SYS_ADMIN))
+ 		return -EACCES;
  
--	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
--		return 0;
--
--	client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
--	if (client == NULL) {
--		return -ENOMEM;
--	}
--
--	client->addr = address;
--	client->adapter = adapter;
--	client->driver = &i2c_driver;
--	snprintf(client->name, sizeof(client->name) - 1, "uPD64083");
-+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
-+		return -EIO;
+-	if (!kset || !buf || !count)
++	if (!buf || !count)
+ 		return -EINVAL;
  
--	v4l_info(client, "chip found @ 0x%x (%s)\n", address << 1, adapter->name);
-+	v4l_info(client, "chip found @ 0x%x (%s)\n",
-+			client->addr << 1, client->adapter->name);
+ 	/* We'll use a local copy of buf */
+@@ -826,7 +818,6 @@ parse_error:
  
- 	state = kmalloc(sizeof(struct upd64083_state), GFP_KERNEL);
--	if (state == NULL) {
--		kfree(client);
-+	if (state == NULL)
- 		return -ENOMEM;
--	}
- 	i2c_set_clientdata(client, state);
- 	/* Initially assume that a ghost reduction chip is present */
- 	state->mode = 0;  /* YCS mode */
- 	state->ext_y_adc = (1 << 5);
- 	memcpy(state->regs, upd64083_init, TOT_REGS);
--	for (i = 0; i < TOT_REGS; i++) {
-+	for (i = 0; i < TOT_REGS; i++)
- 		upd64083_write(client, i, state->regs[i]);
--	}
--	i2c_attach_client(client);
--
--	return 0;
--}
--
--static int upd64083_probe(struct i2c_adapter *adapter)
--{
--	if (adapter->class & I2C_CLASS_TV_ANALOG)
--		return i2c_probe(adapter, &addr_data, upd64083_attach);
- 	return 0;
+ /**
+  * pdcs_autoboot_write - This function handles autoboot flag modifying.
+- * @kset: An allocated and populated struct kset. We don't use it tho.
+  * @buf: The input buffer to read from.
+  * @count: The number of bytes to be read.
+  *
+@@ -834,15 +825,15 @@ parse_error:
+  * We expect a precise syntax:
+  *	\"n\" (n == 0 or 1) to toggle AutoSearch Off or On
+  */
+-static inline ssize_t
+-pdcs_autoboot_write(struct kset *kset, const char *buf, size_t count)
++static ssize_t pdcs_autoboot_write(struct kobject *kobj,
++				   struct kobj_attribute *attr,
++				   const char *buf, size_t count)
+ {
+-	return pdcs_auto_write(kset, buf, count, PF_AUTOBOOT);
++	return pdcs_auto_write(kset, attr, buf, count, PF_AUTOBOOT);
  }
  
--static int upd64083_detach(struct i2c_client *client)
-+static int upd64083_remove(struct i2c_client *client)
+ /**
+  * pdcs_autosearch_write - This function handles autosearch flag modifying.
+- * @kset: An allocated and populated struct kset. We don't use it tho.
+  * @buf: The input buffer to read from.
+  * @count: The number of bytes to be read.
+  *
+@@ -850,15 +841,15 @@ pdcs_autoboot_write(struct kset *kset, const char *buf, size_t count)
+  * We expect a precise syntax:
+  *	\"n\" (n == 0 or 1) to toggle AutoSearch Off or On
+  */
+-static inline ssize_t
+-pdcs_autosearch_write(struct kset *kset, const char *buf, size_t count)
++static ssize_t pdcs_autosearch_write(struct kobject *kobj,
++				     struct kobj_attribute *attr,
++				     const char *buf, size_t count)
  {
--	int err;
--
--	err = i2c_detach_client(client);
--	if (err)
--		return err;
--
--	kfree(client);
-+	kfree(i2c_get_clientdata(client));
- 	return 0;
+-	return pdcs_auto_write(kset, buf, count, PF_AUTOSEARCH);
++	return pdcs_auto_write(kset, attr, buf, count, PF_AUTOSEARCH);
  }
  
- /* ----------------------------------------------------------------------- */
+ /**
+  * pdcs_osdep1_write - Stable Storage OS-Dependent data area 1 input.
+- * @kset: An allocated and populated struct kset. We don't use it tho.
+  * @buf: The input buffer to read from.
+  * @count: The number of bytes to be read.
+  *
+@@ -866,15 +857,16 @@ pdcs_autosearch_write(struct kset *kset, const char *buf, size_t count)
+  * write approach. It's up to userspace to deal with it when constructing
+  * its input buffer.
+  */
+-static ssize_t
+-pdcs_osdep1_write(struct kset *kset, const char *buf, size_t count)
++static ssize_t pdcs_osdep1_write(struct kobject *kobj,
++				 struct kobj_attribute *attr,
++				 const char *buf, size_t count)
+ {
+ 	u8 in[16];
  
--/* i2c implementation */
--static struct i2c_driver i2c_driver = {
--	.driver = {
--		.name = "upd64083",
--	},
--	.id = I2C_DRIVERID_UPD64083,
--	.attach_adapter = upd64083_probe,
--	.detach_client  = upd64083_detach,
-+
-+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
-+	.name = "upd64083",
-+	.driverid = I2C_DRIVERID_UPD64083,
- 	.command = upd64083_command,
-+	.probe = upd64083_probe,
-+	.remove = upd64083_remove,
- };
--
--
--static int __init upd64083_init_module(void)
--{
--	return i2c_add_driver(&i2c_driver);
--}
--
--static void __exit upd64083_exit_module(void)
--{
--	i2c_del_driver(&i2c_driver);
--}
--
--module_init(upd64083_init_module);
--module_exit(upd64083_exit_module);
-diff --git a/drivers/media/video/usbvision/usbvision-cards.c b/drivers/media/video/usbvision/usbvision-cards.c
-index f09eb10..503b13b 100644
---- a/drivers/media/video/usbvision/usbvision-cards.c
-+++ b/drivers/media/video/usbvision/usbvision-cards.c
-@@ -901,6 +901,20 @@ struct usbvision_device_data_st  usbvision_device_data[] = {
- 		.Y_Offset      = -1,
- 		.ModelString   = "Pinnacle Studio PCTV USB (NTSC) FM",
- 	},
-+	[PINNA_PCTV_USB_NTSC_FM_V3] = {
-+		.Interface     = -1,
-+		.Codec         = CODEC_SAA7111,
-+		.VideoChannels = 3,
-+		.VideoNorm     = V4L2_STD_NTSC,
-+		.AudioChannels = 1,
-+		.Radio         = 1,
-+		.vbi           = 1,
-+		.Tuner         = 1,
-+		.TunerType     = TUNER_PHILIPS_NTSC_M,
-+		.X_Offset      = -1,
-+		.Y_Offset      = -1,
-+		.ModelString   = "Pinnacle Studio PCTV USB (NTSC) FM V3",
-+	},
- 	[PINNA_PCTV_USB_PAL_FM_V2] = {
- 		.Interface     = -1,
- 		.Codec         = CODEC_SAA7113,
-@@ -1044,7 +1058,7 @@ struct usb_device_id usbvision_table [] = {
- 	{ USB_DEVICE(0x0573, 0x4d2a), .driver_info=HPG_WINTV_PRO_NTSC_MN },
- 	{ USB_DEVICE(0x0573, 0x4d2b), .driver_info=HPG_WINTV_PRO_NTSC_MN_V2 },
- 	{ USB_DEVICE(0x0573, 0x4d2c), .driver_info=HPG_WINTV_PRO_PAL },
--	{ USB_DEVICE(0x0573, 0x4d20), .driver_info=HPG_WINTV_PRO_NTSC_MN_V3 },
-+	{ USB_DEVICE(0x0573, 0x4d20), .driver_info = HPG_WINTV_PRO_NTSC_MN_V3 },
- 	{ USB_DEVICE(0x0573, 0x4d21), .driver_info=HPG_WINTV_PRO_PAL_BG },
- 	{ USB_DEVICE(0x0573, 0x4d22), .driver_info=HPG_WINTV_PRO_PAL_I },
- 	{ USB_DEVICE(0x0573, 0x4d23), .driver_info=HPG_WINTV_PRO_PAL_SECAM_L },
-@@ -1074,6 +1088,8 @@ struct usb_device_id usbvision_table [] = {
- 	{ USB_DEVICE(0x2304, 0x0110), .driver_info=PINNA_PCTV_USB_PAL_FM },
- 	{ USB_DEVICE(0x2304, 0x0111), .driver_info=MIRO_PCTV_USB },
- 	{ USB_DEVICE(0x2304, 0x0112), .driver_info=PINNA_PCTV_USB_NTSC_FM },
-+	{ USB_DEVICE(0x2304, 0x0113),
-+	  .driver_info = PINNA_PCTV_USB_NTSC_FM_V3 },
- 	{ USB_DEVICE(0x2304, 0x0210), .driver_info=PINNA_PCTV_USB_PAL_FM_V2 },
- 	{ USB_DEVICE(0x2304, 0x0212), .driver_info=PINNA_PCTV_USB_NTSC_FM_V2 },
- 	{ USB_DEVICE(0x2304, 0x0214), .driver_info=PINNA_PCTV_USB_PAL_FM_V3 },
-diff --git a/drivers/media/video/usbvision/usbvision-cards.h b/drivers/media/video/usbvision/usbvision-cards.h
-index 512c5ce..9c6ad22 100644
---- a/drivers/media/video/usbvision/usbvision-cards.h
-+++ b/drivers/media/video/usbvision/usbvision-cards.h
-@@ -62,5 +62,6 @@
- #define PINNA_LINX_VD_IN_CAB_PAL                 61
- #define PINNA_PCTV_BUNGEE_PAL_FM                 62
- #define HPG_WINTV                                63
-+#define PINNA_PCTV_USB_NTSC_FM_V3                64
+ 	if (!capable(CAP_SYS_ADMIN))
+ 		return -EACCES;
  
- extern const int usbvision_device_data_size;
-diff --git a/drivers/media/video/usbvision/usbvision-core.c b/drivers/media/video/usbvision/usbvision-core.c
-index c7d5f9e..56775ab 100644
---- a/drivers/media/video/usbvision/usbvision-core.c
-+++ b/drivers/media/video/usbvision/usbvision-core.c
-@@ -69,6 +69,15 @@ static int SwitchSVideoInput = 0;			// To help people with Black and White outpu
- module_param(SwitchSVideoInput, int, 0444);
- MODULE_PARM_DESC(SwitchSVideoInput, " Set the S-Video input.  Some cables and input device are wired differently. Default: 0 (Off)");
+-	if (!kset || !buf || !count)
++	if (!buf || !count)
+ 		return -EINVAL;
  
-+static unsigned int adjust_X_Offset = -1;
-+module_param(adjust_X_Offset, int, 0644);
-+MODULE_PARM_DESC(adjust_X_Offset, "adjust X offset display [core]");
-+
-+static unsigned int adjust_Y_Offset = -1;
-+module_param(adjust_Y_Offset, int, 0644);
-+MODULE_PARM_DESC(adjust_Y_Offset, "adjust Y offset display [core]");
-+
-+
- #define	ENABLE_HEXDUMP	0	/* Enable if you need it */
+ 	if (unlikely(pdcs_osid != OS_ID_LINUX))
+@@ -895,7 +887,6 @@ pdcs_osdep1_write(struct kset *kset, const char *buf, size_t count)
  
+ /**
+  * pdcs_osdep2_write - Stable Storage OS-Dependent data area 2 input.
+- * @kset: An allocated and populated struct kset. We don't use it tho.
+  * @buf: The input buffer to read from.
+  * @count: The number of bytes to be read.
+  *
+@@ -903,8 +894,9 @@ pdcs_osdep1_write(struct kset *kset, const char *buf, size_t count)
+  * byte-by-byte write approach. It's up to userspace to deal with it when
+  * constructing its input buffer.
+  */
+-static ssize_t
+-pdcs_osdep2_write(struct kset *kset, const char *buf, size_t count)
++static ssize_t pdcs_osdep2_write(struct kobject *kobj,
++				 struct kobj_attribute *attr,
++				 const char *buf, size_t count)
+ {
+ 	unsigned long size;
+ 	unsigned short i;
+@@ -913,7 +905,7 @@ pdcs_osdep2_write(struct kset *kset, const char *buf, size_t count)
+ 	if (!capable(CAP_SYS_ADMIN))
+ 		return -EACCES;
  
-@@ -624,25 +633,29 @@ static enum ParseState usbvision_parse_lines_422(struct usb_usbvision *usbvision
+-	if (!kset || !buf || !count)
++	if (!buf || !count)
+ 		return -EINVAL;
  
- 			YUV_TO_RGB_BY_THE_BOOK(yuyv[0], yuyv[1], yuyv[3], rv, gv, bv);
- 			switch (frame->v4l2_format.format) {
--				case V4L2_PIX_FMT_RGB565:
--					*f++ = (0x1F & (bv >> 3)) | (0xE0 & (gv << 3));
--					*f++ = (0x07 & (gv >> 5)) | (0xF8 &  rv);
--					break;
--				case V4L2_PIX_FMT_RGB24:
--					*f++ = bv;
--					*f++ = gv;
--					*f++ = rv;
--					break;
--				case V4L2_PIX_FMT_RGB32:
--					*f++ = bv;
--					*f++ = gv;
--					*f++ = rv;
--					f++;
--					break;
--				case V4L2_PIX_FMT_RGB555:
--					*f++ = (0x1F & (bv >> 3)) | (0xE0 & (gv << 2));
--					*f++ = (0x03 & (gv >> 6)) | (0x7C & (rv >> 1));
--					break;
-+			case V4L2_PIX_FMT_RGB565:
-+				*f++ = (0x1F & rv) |
-+					(0xE0 & (gv << 5));
-+				*f++ = (0x07 & (gv >> 3)) |
-+					(0xF8 &  bv);
-+				break;
-+			case V4L2_PIX_FMT_RGB24:
-+				*f++ = rv;
-+				*f++ = gv;
-+				*f++ = bv;
-+				break;
-+			case V4L2_PIX_FMT_RGB32:
-+				*f++ = rv;
-+				*f++ = gv;
-+				*f++ = bv;
-+				f++;
-+				break;
-+			case V4L2_PIX_FMT_RGB555:
-+				*f++ = (0x1F & rv) |
-+					(0xE0 & (gv << 5));
-+				*f++ = (0x03 & (gv >> 3)) |
-+					(0x7C & (bv << 2));
-+				break;
- 			}
- 		}
- 		clipmask_index += clipmask_add;
-@@ -656,25 +669,29 @@ static enum ParseState usbvision_parse_lines_422(struct usb_usbvision *usbvision
+ 	if (unlikely(pdcs_size <= 224))
+@@ -951,21 +943,25 @@ static PDCS_ATTR(diagnostic, 0400, pdcs_diagnostic_read, NULL);
+ static PDCS_ATTR(fastsize, 0400, pdcs_fastsize_read, NULL);
+ static PDCS_ATTR(osdep2, 0600, pdcs_osdep2_read, pdcs_osdep2_write);
  
- 			YUV_TO_RGB_BY_THE_BOOK(yuyv[2], yuyv[1], yuyv[3], rv, gv, bv);
- 			switch (frame->v4l2_format.format) {
--				case V4L2_PIX_FMT_RGB565:
--					*f++ = (0x1F & (bv >> 3)) | (0xE0 & (gv << 3));
--					*f++ = (0x07 & (gv >> 5)) | (0xF8 &  rv);
--					break;
--				case V4L2_PIX_FMT_RGB24:
--					*f++ = bv;
--					*f++ = gv;
--					*f++ = rv;
--					break;
--				case V4L2_PIX_FMT_RGB32:
--					*f++ = bv;
--					*f++ = gv;
--					*f++ = rv;
--					f++;
--					break;
--				case V4L2_PIX_FMT_RGB555:
--					*f++ = (0x1F & (bv >> 3)) | (0xE0 & (gv << 2));
--					*f++ = (0x03 & (gv >> 6)) | (0x7C & (rv >> 1));
--					break;
-+			case V4L2_PIX_FMT_RGB565:
-+				*f++ = (0x1F & rv) |
-+					(0xE0 & (gv << 5));
-+				*f++ = (0x07 & (gv >> 3)) |
-+					(0xF8 &  bv);
-+				break;
-+			case V4L2_PIX_FMT_RGB24:
-+				*f++ = rv;
-+				*f++ = gv;
-+				*f++ = bv;
-+				break;
-+			case V4L2_PIX_FMT_RGB32:
-+				*f++ = rv;
-+				*f++ = gv;
-+				*f++ = bv;
-+				f++;
-+				break;
-+			case V4L2_PIX_FMT_RGB555:
-+				*f++ = (0x1F & rv) |
-+					(0xE0 & (gv << 5));
-+				*f++ = (0x03 & (gv >> 3)) |
-+					(0x7C & (bv << 2));
-+				break;
- 			}
- 		}
- 		clipmask_index += clipmask_add;
-@@ -942,22 +959,26 @@ static enum ParseState usbvision_parse_compress(struct usb_usbvision *usbvision,
- 					*f++ = Y[Idx];
- 					break;
- 				case V4L2_PIX_FMT_RGB555:
--					*f++ = (0x1F & (bv >> 3)) | (0xE0 & (gv << 2));
--					*f++ = (0x03 & (gv >> 6)) | (0x7C & (rv >> 1));
-+					*f++ = (0x1F & rv) |
-+						(0xE0 & (gv << 5));
-+					*f++ = (0x03 & (gv >> 3)) |
-+						(0x7C & (bv << 2));
- 					break;
- 				case V4L2_PIX_FMT_RGB565:
--					*f++ = (0x1F & (bv >> 3)) | (0xE0 & (gv << 3));
--					*f++ = (0x07 & (gv >> 5)) | (0xF8 &  rv);
-+					*f++ = (0x1F & rv) |
-+						(0xE0 & (gv << 5));
-+					*f++ = (0x07 & (gv >> 3)) |
-+						(0xF8 &  bv);
- 					break;
- 				case V4L2_PIX_FMT_RGB24:
--					*f++ = bv;
--					*f++ = gv;
- 					*f++ = rv;
-+					*f++ = gv;
-+					*f++ = bv;
- 					break;
- 				case V4L2_PIX_FMT_RGB32:
--					*f++ = bv;
--					*f++ = gv;
- 					*f++ = rv;
-+					*f++ = gv;
-+					*f++ = bv;
- 					f++;
- 					break;
- 			}
-@@ -1071,28 +1092,33 @@ static enum ParseState usbvision_parse_lines_420(struct usb_usbvision *usbvision
- 				r_ = (y_ + ur) >> 16;
+-static struct subsys_attribute *pdcs_subsys_attrs[] = {
+-	&pdcs_attr_size,
+-	&pdcs_attr_autoboot,
+-	&pdcs_attr_autosearch,
+-	&pdcs_attr_timer,
+-	&pdcs_attr_osid,
+-	&pdcs_attr_osdep1,
+-	&pdcs_attr_diagnostic,
+-	&pdcs_attr_fastsize,
+-	&pdcs_attr_osdep2,
++static struct attribute *pdcs_subsys_attrs[] = {
++	&pdcs_attr_size.attr,
++	&pdcs_attr_autoboot.attr,
++	&pdcs_attr_autosearch.attr,
++	&pdcs_attr_timer.attr,
++	&pdcs_attr_osid.attr,
++	&pdcs_attr_osdep1.attr,
++	&pdcs_attr_diagnostic.attr,
++	&pdcs_attr_fastsize.attr,
++	&pdcs_attr_osdep2.attr,
+ 	NULL,
+ };
  
- 				switch (frame->v4l2_format.format) {
--					case V4L2_PIX_FMT_RGB565:
--						g = LIMIT_RGB(g_);
--						*f_even++ = (0x1F & (LIMIT_RGB(b_) >> 3)) | (0xE0 & (g << 3));
--						*f_even++ = (0x07 & (          g   >> 5)) | (0xF8 & LIMIT_RGB(r_));
--						break;
--					case V4L2_PIX_FMT_RGB24:
--						*f_even++ = LIMIT_RGB(b_);
--						*f_even++ = LIMIT_RGB(g_);
--						*f_even++ = LIMIT_RGB(r_);
--						break;
--					case V4L2_PIX_FMT_RGB32:
--						*f_even++ = LIMIT_RGB(b_);
--						*f_even++ = LIMIT_RGB(g_);
--						*f_even++ = LIMIT_RGB(r_);
--						f_even++;
--						break;
--					case V4L2_PIX_FMT_RGB555:
--						g = LIMIT_RGB(g_);
--						*f_even++ = (0x1F & (LIMIT_RGB(b_) >> 3)) | (0xE0 & (g << 2));
--						*f_even++ = (0x03 & (          g   >> 6)) |
--							    (0x7C & (LIMIT_RGB(r_) >> 1));
--						break;
-+				case V4L2_PIX_FMT_RGB565:
-+					g = LIMIT_RGB(g_);
-+					*f_even++ =
-+						(0x1F & LIMIT_RGB(r_)) |
-+						(0xE0 & (g << 5));
-+					*f_even++ =
-+						(0x07 & (g >> 3)) |
-+						(0xF8 &  LIMIT_RGB(b_));
-+					break;
-+				case V4L2_PIX_FMT_RGB24:
-+					*f_even++ = LIMIT_RGB(r_);
-+					*f_even++ = LIMIT_RGB(g_);
-+					*f_even++ = LIMIT_RGB(b_);
-+					break;
-+				case V4L2_PIX_FMT_RGB32:
-+					*f_even++ = LIMIT_RGB(r_);
-+					*f_even++ = LIMIT_RGB(g_);
-+					*f_even++ = LIMIT_RGB(b_);
-+					f_even++;
-+					break;
-+				case V4L2_PIX_FMT_RGB555:
-+					g = LIMIT_RGB(g_);
-+					*f_even++ = (0x1F & LIMIT_RGB(r_)) |
-+						(0xE0 & (g << 5));
-+					*f_even++ = (0x03 & (g >> 3)) |
-+						(0x7C & (LIMIT_RGB(b_) << 2));
-+					break;
- 				}
- 			}
- 			clipmask_even_index += clipmask_add;
-@@ -1110,28 +1136,33 @@ static enum ParseState usbvision_parse_lines_420(struct usb_usbvision *usbvision
- 				r_ = (y_ + ur) >> 16;
+-static decl_subsys(paths, &ktype_pdcspath, NULL);
+-static decl_subsys(stable, NULL, NULL);
++static struct attribute_group pdcs_attr_group = {
++	.attrs = pdcs_subsys_attrs,
++};
++
++static struct kobject *stable_kobj;
++static struct kset *paths_kset;
  
- 				switch (frame->v4l2_format.format) {
--					case V4L2_PIX_FMT_RGB565:
--						g = LIMIT_RGB(g_);
--						*f_even++ = (0x1F & (LIMIT_RGB(b_) >> 3)) | (0xE0 & (g << 3));
--						*f_even++ = (0x07 & (          g   >> 5)) | (0xF8 & LIMIT_RGB(r_));
--						break;
--					case V4L2_PIX_FMT_RGB24:
--						*f_even++ = LIMIT_RGB(b_);
--						*f_even++ = LIMIT_RGB(g_);
--						*f_even++ = LIMIT_RGB(r_);
--						break;
--					case V4L2_PIX_FMT_RGB32:
--						*f_even++ = LIMIT_RGB(b_);
--						*f_even++ = LIMIT_RGB(g_);
--						*f_even++ = LIMIT_RGB(r_);
--						f_even++;
--						break;
--					case V4L2_PIX_FMT_RGB555:
--						g = LIMIT_RGB(g_);
--						*f_even++ = (0x1F & (LIMIT_RGB(b_) >> 3)) | (0xE0 & (g << 2));
--						*f_even++ = (0x03 & (          g   >> 6)) |
--							    (0x7C & (LIMIT_RGB(r_) >> 1));
--						break;
-+				case V4L2_PIX_FMT_RGB565:
-+					g = LIMIT_RGB(g_);
-+					*f_even++ =
-+						(0x1F & LIMIT_RGB(r_)) |
-+						(0xE0 & (g << 5));
-+					*f_even++ =
-+						(0x07 & (g >> 3)) |
-+						(0xF8 &  LIMIT_RGB(b_));
-+					break;
-+				case V4L2_PIX_FMT_RGB24:
-+					*f_even++ = LIMIT_RGB(r_);
-+					*f_even++ = LIMIT_RGB(g_);
-+					*f_even++ = LIMIT_RGB(b_);
-+					break;
-+				case V4L2_PIX_FMT_RGB32:
-+					*f_even++ = LIMIT_RGB(r_);
-+					*f_even++ = LIMIT_RGB(g_);
-+					*f_even++ = LIMIT_RGB(b_);
-+					f_even++;
-+					break;
-+				case V4L2_PIX_FMT_RGB555:
-+					g = LIMIT_RGB(g_);
-+					*f_even++ = (0x1F & LIMIT_RGB(r_)) |
-+						(0xE0 & (g << 5));
-+					*f_even++ = (0x03 & (g >> 3)) |
-+						(0x7C & (LIMIT_RGB(b_) << 2));
-+					break;
- 				}
- 			}
- 			clipmask_even_index += clipmask_add;
-@@ -1151,28 +1182,33 @@ static enum ParseState usbvision_parse_lines_420(struct usb_usbvision *usbvision
- 				r_ = (y_ + ur) >> 16;
+ /**
+  * pdcs_register_pathentries - Prepares path entries kobjects for sysfs usage.
+@@ -995,12 +991,12 @@ pdcs_register_pathentries(void)
+ 		if (err < 0)
+ 			continue;
  
- 				switch (frame->v4l2_format.format) {
--					case V4L2_PIX_FMT_RGB565:
--						g = LIMIT_RGB(g_);
--						*f_odd++ = (0x1F & (LIMIT_RGB(b_) >> 3)) | (0xE0 & (g << 3));
--						*f_odd++ = (0x07 & (          g   >> 5)) | (0xF8 & LIMIT_RGB(r_));
--						break;
--					case V4L2_PIX_FMT_RGB24:
--						*f_odd++ = LIMIT_RGB(b_);
--						*f_odd++ = LIMIT_RGB(g_);
--						*f_odd++ = LIMIT_RGB(r_);
--						break;
--					case V4L2_PIX_FMT_RGB32:
--						*f_odd++ = LIMIT_RGB(b_);
--						*f_odd++ = LIMIT_RGB(g_);
--						*f_odd++ = LIMIT_RGB(r_);
--						f_odd++;
--						break;
--					case V4L2_PIX_FMT_RGB555:
--						g = LIMIT_RGB(g_);
--						*f_odd++ = (0x1F & (LIMIT_RGB(b_) >> 3)) | (0xE0 & (g << 2));
--						*f_odd++ = (0x03 & (          g   >> 6)) |
--							   (0x7C & (LIMIT_RGB(r_) >> 1));
--						break;
-+				case V4L2_PIX_FMT_RGB565:
-+					g = LIMIT_RGB(g_);
-+					*f_odd++ =
-+						(0x1F & LIMIT_RGB(r_)) |
-+						(0xE0 & (g << 5));
-+					*f_odd++ =
-+						(0x07 & (g >> 3)) |
-+						(0xF8 &  LIMIT_RGB(b_));
-+					break;
-+				case V4L2_PIX_FMT_RGB24:
-+					*f_odd++ = LIMIT_RGB(r_);
-+					*f_odd++ = LIMIT_RGB(g_);
-+					*f_odd++ = LIMIT_RGB(b_);
-+					break;
-+				case V4L2_PIX_FMT_RGB32:
-+					*f_odd++ = LIMIT_RGB(r_);
-+					*f_odd++ = LIMIT_RGB(g_);
-+					*f_odd++ = LIMIT_RGB(b_);
-+					f_odd++;
-+					break;
-+				case V4L2_PIX_FMT_RGB555:
-+					g = LIMIT_RGB(g_);
-+					*f_odd++ = (0x1F & LIMIT_RGB(r_)) |
-+						(0xE0 & (g << 5));
-+					*f_odd++ = (0x03 & (g >> 3)) |
-+						(0x7C & (LIMIT_RGB(b_) << 2));
-+					break;
- 				}
- 			}
- 			clipmask_odd_index += clipmask_add;
-@@ -1190,28 +1226,33 @@ static enum ParseState usbvision_parse_lines_420(struct usb_usbvision *usbvision
- 				r_ = (y_ + ur) >> 16;
+-		if ((err = kobject_set_name(&entry->kobj, "%s", entry->name)))
+-			return err;
+-		kobj_set_kset_s(entry, paths_subsys);
+-		if ((err = kobject_register(&entry->kobj)))
++		entry->kobj.kset = paths_kset;
++		err = kobject_init_and_add(&entry->kobj, &ktype_pdcspath, NULL,
++					   "%s", entry->name);
++		if (err)
+ 			return err;
+-		
++
+ 		/* kobject is now registered */
+ 		write_lock(&entry->rw_lock);
+ 		entry->ready = 2;
+@@ -1012,6 +1008,7 @@ pdcs_register_pathentries(void)
+ 		}
  
- 				switch (frame->v4l2_format.format) {
--					case V4L2_PIX_FMT_RGB565:
--						g = LIMIT_RGB(g_);
--						*f_odd++ = (0x1F & (LIMIT_RGB(b_) >> 3)) | (0xE0 & (g << 3));
--						*f_odd++ = (0x07 & (          g   >> 5)) | (0xF8 & LIMIT_RGB(r_));
--						break;
--					case V4L2_PIX_FMT_RGB24:
--						*f_odd++ = LIMIT_RGB(b_);
--						*f_odd++ = LIMIT_RGB(g_);
--						*f_odd++ = LIMIT_RGB(r_);
--						break;
--					case V4L2_PIX_FMT_RGB32:
--						*f_odd++ = LIMIT_RGB(b_);
--						*f_odd++ = LIMIT_RGB(g_);
--						*f_odd++ = LIMIT_RGB(r_);
--						f_odd++;
--						break;
--					case V4L2_PIX_FMT_RGB555:
--						g = LIMIT_RGB(g_);
--						*f_odd++ = (0x1F & (LIMIT_RGB(b_) >> 3)) | (0xE0 & (g << 2));
--						*f_odd++ = (0x03 & (          g   >> 6)) |
--							   (0x7C & (LIMIT_RGB(r_) >> 1));
--						break;
-+				case V4L2_PIX_FMT_RGB565:
-+					g = LIMIT_RGB(g_);
-+					*f_odd++ =
-+						(0x1F & LIMIT_RGB(r_)) |
-+						(0xE0 & (g << 5));
-+					*f_odd++ =
-+						(0x07 & (g >> 3)) |
-+						(0xF8 &  LIMIT_RGB(b_));
-+					break;
-+				case V4L2_PIX_FMT_RGB24:
-+					*f_odd++ = LIMIT_RGB(r_);
-+					*f_odd++ = LIMIT_RGB(g_);
-+					*f_odd++ = LIMIT_RGB(b_);
-+					break;
-+				case V4L2_PIX_FMT_RGB32:
-+					*f_odd++ = LIMIT_RGB(r_);
-+					*f_odd++ = LIMIT_RGB(g_);
-+					*f_odd++ = LIMIT_RGB(b_);
-+					f_odd++;
-+					break;
-+				case V4L2_PIX_FMT_RGB555:
-+					g = LIMIT_RGB(g_);
-+					*f_odd++ = (0x1F & LIMIT_RGB(r_)) |
-+						(0xE0 & (g << 5));
-+					*f_odd++ = (0x03 & (g >> 3)) |
-+						(0x7C & (LIMIT_RGB(b_) << 2));
-+					break;
- 				}
- 			}
- 			clipmask_odd_index += clipmask_add;
-@@ -1561,13 +1602,10 @@ static int usbvision_write_reg_irq(struct usb_usbvision *usbvision,int address,
- 	if (len > 8) {
- 		return -EFAULT;
+ 		write_unlock(&entry->rw_lock);
++		kobject_uevent(&entry->kobj, KOBJ_ADD);
  	}
--//	down(&usbvision->ctrlUrbLock);
- 	if (usbvision->ctrlUrbBusy) {
--//		up(&usbvision->ctrlUrbLock);
- 		return -EBUSY;
+ 	
+ 	return 0;
+@@ -1029,7 +1026,7 @@ pdcs_unregister_pathentries(void)
+ 	for (i = 0; (entry = pdcspath_entries[i]); i++) {
+ 		read_lock(&entry->rw_lock);
+ 		if (entry->ready >= 2)
+-			kobject_unregister(&entry->kobj);
++			kobject_put(&entry->kobj);
+ 		read_unlock(&entry->rw_lock);
  	}
- 	usbvision->ctrlUrbBusy = 1;
--//	up(&usbvision->ctrlUrbLock);
+ }
+@@ -1041,8 +1038,7 @@ pdcs_unregister_pathentries(void)
+ static int __init
+ pdc_stable_init(void)
+ {
+-	struct subsys_attribute *attr;
+-	int i, rc = 0, error = 0;
++	int rc = 0, error = 0;
+ 	u32 result;
  
- 	usbvision->ctrlUrbSetup.bRequestType = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT;
- 	usbvision->ctrlUrbSetup.bRequest     = USBVISION_OP_CODE;
-@@ -2100,11 +2138,21 @@ int usbvision_set_input(struct usb_usbvision *usbvision)
- 		value[5]=(usbvision_device_data[usbvision->DevModel].X_Offset & 0x0300) >> 8;
- 	}
+ 	/* find the size of the stable storage */
+@@ -1062,21 +1058,24 @@ pdc_stable_init(void)
+ 	/* the actual result is 16 bits away */
+ 	pdcs_osid = (u16)(result >> 16);
  
-+	if (adjust_X_Offset != -1) {
-+		value[4] = adjust_X_Offset & 0xff;
-+		value[5] = (adjust_X_Offset & 0x0300) >> 8;
+-	/* For now we'll register the stable subsys within this driver */
+-	if ((rc = firmware_register(&stable_subsys)))
++	/* For now we'll register the directory at /sys/firmware/stable */
++	stable_kobj = kobject_create_and_add("stable", firmware_kobj);
++	if (!stable_kobj) {
++		rc = -ENOMEM;
+ 		goto fail_firmreg;
 +	}
-+
- 	if (usbvision_device_data[usbvision->DevModel].Y_Offset >= 0) {
- 		value[6]=usbvision_device_data[usbvision->DevModel].Y_Offset & 0xff;
- 		value[7]=(usbvision_device_data[usbvision->DevModel].Y_Offset & 0x0300) >> 8;
- 	}
  
-+	if (adjust_Y_Offset != -1) {
-+		value[6] = adjust_Y_Offset & 0xff;
-+		value[7] = (adjust_Y_Offset & 0x0300) >> 8;
-+	}
-+
- 	rc = usb_control_msg(usbvision->dev, usb_sndctrlpipe(usbvision->dev, 1),
- 			     USBVISION_OP_CODE,	/* USBVISION specific code */
- 			     USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT, 0,
-@@ -2242,14 +2290,18 @@ static void call_usbvision_power_off(struct work_struct *work)
- 	struct usb_usbvision *usbvision = container_of(work, struct usb_usbvision, powerOffWork);
+ 	/* Don't forget the root entries */
+-	for (i = 0; (attr = pdcs_subsys_attrs[i]) && !error; i++)
+-		if (attr->show)
+-			error = subsys_create_file(&stable_subsys, attr);
+-	
+-	/* register the paths subsys as a subsystem of stable subsys */
+-	kobj_set_kset_s(&paths_subsys, stable_subsys);
+-	if ((rc = subsystem_register(&paths_subsys)))
+-		goto fail_subsysreg;
++	error = sysfs_create_group(stable_kobj, pdcs_attr_group);
  
- 	PDEBUG(DBG_FUNC, "");
--	down_interruptible(&usbvision->lock);
-+	if(mutex_lock_interruptible(&usbvision->lock)) {
-+		return;
+-	/* now we create all "files" for the paths subsys */
++	/* register the paths kset as a child of the stable kset */
++	paths_kset = kset_create_and_add("paths", NULL, stable_kobj);
++	if (!paths_kset) {
++		rc = -ENOMEM;
++		goto fail_ksetreg;
 +	}
 +
-+
- 	if(usbvision->user == 0) {
- 		usbvision_i2c_unregister(usbvision);
++	/* now we create all "files" for the paths kset */
+ 	if ((rc = pdcs_register_pathentries()))
+ 		goto fail_pdcsreg;
  
- 		usbvision_power_off(usbvision);
- 		usbvision->initialized = 0;
- 	}
--	up(&usbvision->lock);
-+	mutex_unlock(&usbvision->lock);
+@@ -1084,10 +1083,10 @@ pdc_stable_init(void)
+ 	
+ fail_pdcsreg:
+ 	pdcs_unregister_pathentries();
+-	subsystem_unregister(&paths_subsys);
++	kset_unregister(paths_kset);
+ 	
+-fail_subsysreg:
+-	firmware_unregister(&stable_subsys);
++fail_ksetreg:
++	kobject_put(stable_kobj);
+ 	
+ fail_firmreg:
+ 	printk(KERN_INFO PDCS_PREFIX " bailing out\n");
+@@ -1098,9 +1097,8 @@ static void __exit
+ pdc_stable_exit(void)
+ {
+ 	pdcs_unregister_pathentries();
+-	subsystem_unregister(&paths_subsys);
+-
+-	firmware_unregister(&stable_subsys);
++	kset_unregister(paths_kset);
++	kobject_put(stable_kobj);
  }
  
- static void usbvision_powerOffTimer(unsigned long data)
-diff --git a/drivers/media/video/usbvision/usbvision-video.c b/drivers/media/video/usbvision/usbvision-video.c
-index 36e689f..b52b826 100644
---- a/drivers/media/video/usbvision/usbvision-video.c
-+++ b/drivers/media/video/usbvision/usbvision-video.c
-@@ -410,7 +410,7 @@ static int usbvision_v4l2_open(struct inode *inode, struct file *file)
- 
- 	/* If so far no errors then we shall start the camera */
- 	if (!errCode) {
--		down(&usbvision->lock);
-+		mutex_lock(&usbvision->lock);
- 		if (usbvision->power == 0) {
- 			usbvision_power_on(usbvision);
- 			usbvision_i2c_register(usbvision);
-@@ -439,7 +439,7 @@ static int usbvision_v4l2_open(struct inode *inode, struct file *file)
- 				usbvision->initialized = 0;
- 			}
- 		}
--		up(&usbvision->lock);
-+		mutex_unlock(&usbvision->lock);
- 	}
- 
- 	if (errCode) {
-@@ -467,7 +467,7 @@ static int usbvision_v4l2_close(struct inode *inode, struct file *file)
- 		(struct usb_usbvision *) video_get_drvdata(dev);
- 
- 	PDEBUG(DBG_IO, "close");
--	down(&usbvision->lock);
-+	mutex_lock(&usbvision->lock);
- 
- 	usbvision_audio_off(usbvision);
- 	usbvision_restart_isoc(usbvision);
-@@ -487,7 +487,7 @@ static int usbvision_v4l2_close(struct inode *inode, struct file *file)
- 		usbvision->initialized = 0;
- 	}
- 
--	up(&usbvision->lock);
-+	mutex_unlock(&usbvision->lock);
- 
- 	if (usbvision->remove_pending) {
- 		printk(KERN_INFO "%s: Final disconnect\n", __FUNCTION__);
-@@ -647,13 +647,13 @@ static int vidioc_s_input (struct file *file, void *priv, unsigned int input)
- 	if ((input >= usbvision->video_inputs) || (input < 0) )
- 		return -EINVAL;
- 
--	down(&usbvision->lock);
-+	mutex_lock(&usbvision->lock);
- 	usbvision_muxsel(usbvision, input);
- 	usbvision_set_input(usbvision);
- 	usbvision_set_output(usbvision,
- 			     usbvision->curwidth,
- 			     usbvision->curheight);
--	up(&usbvision->lock);
-+	mutex_unlock(&usbvision->lock);
- 	return 0;
- }
  
-@@ -664,10 +664,10 @@ static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id *id)
- 		(struct usb_usbvision *) video_get_drvdata(dev);
- 	usbvision->tvnormId=*id;
+diff --git a/drivers/pci/hotplug/acpiphp_ibm.c b/drivers/pci/hotplug/acpiphp_ibm.c
+index 47d26b6..750ebd7 100644
+--- a/drivers/pci/hotplug/acpiphp_ibm.c
++++ b/drivers/pci/hotplug/acpiphp_ibm.c
+@@ -429,7 +429,7 @@ static int __init ibm_acpiphp_init(void)
+ 	int retval = 0;
+ 	acpi_status status;
+ 	struct acpi_device *device;
+-	struct kobject *sysdir = &pci_hotplug_slots_subsys.kobj;
++	struct kobject *sysdir = &pci_hotplug_slots_kset->kobj;
  
--	down(&usbvision->lock);
-+	mutex_lock(&usbvision->lock);
- 	call_i2c_clients(usbvision, VIDIOC_S_STD,
- 			 &usbvision->tvnormId);
--	up(&usbvision->lock);
-+	mutex_unlock(&usbvision->lock);
- 	/* propagate the change to the decoder */
- 	usbvision_muxsel(usbvision, usbvision->ctl_input);
+ 	dbg("%s\n", __FUNCTION__);
  
-@@ -1083,9 +1083,9 @@ static int vidioc_s_fmt_cap(struct file *file, void *priv,
- 	usbvision->curFrame = NULL;
+@@ -476,7 +476,7 @@ init_return:
+ static void __exit ibm_acpiphp_exit(void)
+ {
+ 	acpi_status status;
+-	struct kobject *sysdir = &pci_hotplug_slots_subsys.kobj;
++	struct kobject *sysdir = &pci_hotplug_slots_kset->kobj;
  
- 	/* by now we are committed to the new data... */
--	down(&usbvision->lock);
-+	mutex_lock(&usbvision->lock);
- 	usbvision_set_output(usbvision, vf->fmt.pix.width, vf->fmt.pix.height);
--	up(&usbvision->lock);
-+	mutex_unlock(&usbvision->lock);
+ 	dbg("%s\n", __FUNCTION__);
  
- 	return 0;
- }
-@@ -1211,16 +1211,16 @@ static int usbvision_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
+diff --git a/drivers/pci/hotplug/pci_hotplug_core.c b/drivers/pci/hotplug/pci_hotplug_core.c
+index 01c351c..47bb0e1 100644
+--- a/drivers/pci/hotplug/pci_hotplug_core.c
++++ b/drivers/pci/hotplug/pci_hotplug_core.c
+@@ -61,7 +61,7 @@ static int debug;
  
- 	PDEBUG(DBG_MMAP, "mmap");
+ static LIST_HEAD(pci_hotplug_slot_list);
  
--	down(&usbvision->lock);
-+	mutex_lock(&usbvision->lock);
+-struct kset pci_hotplug_slots_subsys;
++struct kset *pci_hotplug_slots_kset;
  
- 	if (!USBVISION_IS_OPERATIONAL(usbvision)) {
--		up(&usbvision->lock);
-+		mutex_unlock(&usbvision->lock);
- 		return -EFAULT;
- 	}
+ static ssize_t hotplug_slot_attr_show(struct kobject *kobj,
+ 		struct attribute *attr, char *buf)
+@@ -96,8 +96,6 @@ static struct kobj_type hotplug_slot_ktype = {
+ 	.release = &hotplug_slot_release,
+ };
  
- 	if (!(vma->vm_flags & VM_WRITE) ||
- 	    size != PAGE_ALIGN(usbvision->max_frame_size)) {
--		up(&usbvision->lock);
-+		mutex_unlock(&usbvision->lock);
+-decl_subsys_name(pci_hotplug_slots, slots, &hotplug_slot_ktype, NULL);
+-
+ /* these strings match up with the values in pci_bus_speed */
+ static char *pci_bus_speed_strings[] = {
+ 	"33 MHz PCI",		/* 0x00 */
+@@ -632,18 +630,19 @@ int pci_hp_register (struct hotplug_slot *slot)
  		return -EINVAL;
  	}
  
-@@ -1232,7 +1232,7 @@ static int usbvision_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
- 	if (i == usbvision->num_frames) {
- 		PDEBUG(DBG_MMAP,
- 		       "mmap: user supplied mapping address is out of range");
--		up(&usbvision->lock);
-+		mutex_unlock(&usbvision->lock);
+-	kobject_set_name(&slot->kobj, "%s", slot->name);
+-	kobj_set_kset_s(slot, pci_hotplug_slots_subsys);
+-
+ 	/* this can fail if we have already registered a slot with the same name */
+-	if (kobject_register(&slot->kobj)) {
+-		err("Unable to register kobject");
++	slot->kobj.kset = pci_hotplug_slots_kset;
++	result = kobject_init_and_add(&slot->kobj, &hotplug_slot_ktype, NULL,
++				      "%s", slot->name);
++	if (result) {
++		err("Unable to register kobject '%s'", slot->name);
  		return -EINVAL;
  	}
+-		
++
+ 	list_add (&slot->slot_list, &pci_hotplug_slot_list);
  
-@@ -1245,7 +1245,7 @@ static int usbvision_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
+ 	result = fs_add_slot (slot);
++	kobject_uevent(&slot->kobj, KOBJ_ADD);
+ 	dbg ("Added slot %s to the list\n", slot->name);
+ 	return result;
+ }
+@@ -672,7 +671,7 @@ int pci_hp_deregister (struct hotplug_slot *slot)
+ 
+ 	fs_remove_slot (slot);
+ 	dbg ("Removed slot %s from the list\n", slot->name);
+-	kobject_unregister(&slot->kobj);
++	kobject_put(&slot->kobj);
+ 	return 0;
+ }
+ 
+@@ -700,11 +699,15 @@ int __must_check pci_hp_change_slot_info(struct hotplug_slot *slot,
+ static int __init pci_hotplug_init (void)
+ {
+ 	int result;
++	struct kset *pci_bus_kset;
  
- 		if (vm_insert_page(vma, start, vmalloc_to_page(pos))) {
- 			PDEBUG(DBG_MMAP, "mmap: vm_insert_page failed");
--			up(&usbvision->lock);
-+			mutex_unlock(&usbvision->lock);
- 			return -EAGAIN;
- 		}
- 		start += PAGE_SIZE;
-@@ -1253,7 +1253,7 @@ static int usbvision_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
- 		size -= PAGE_SIZE;
+-	kobj_set_kset_s(&pci_hotplug_slots_subsys, pci_bus_type.subsys);
+-	result = subsystem_register(&pci_hotplug_slots_subsys);
+-	if (result) {
+-		err("Register subsys with error %d\n", result);
++	pci_bus_kset = bus_get_kset(&pci_bus_type);
++
++	pci_hotplug_slots_kset = kset_create_and_add("slots", NULL,
++						     &pci_bus_kset->kobj);
++	if (!pci_hotplug_slots_kset) {
++		result = -ENOMEM;
++		err("Register subsys error\n");
+ 		goto exit;
  	}
+ 	result = cpci_hotplug_init(debug);
+@@ -715,9 +718,9 @@ static int __init pci_hotplug_init (void)
  
--	up(&usbvision->lock);
-+	mutex_unlock(&usbvision->lock);
- 	return 0;
+ 	info (DRIVER_DESC " version: " DRIVER_VERSION "\n");
+ 	goto exit;
+-	
++
+ err_subsys:
+-	subsystem_unregister(&pci_hotplug_slots_subsys);
++	kset_unregister(pci_hotplug_slots_kset);
+ exit:
+ 	return result;
+ }
+@@ -725,7 +728,7 @@ exit:
+ static void __exit pci_hotplug_exit (void)
+ {
+ 	cpci_hotplug_exit();
+-	subsystem_unregister(&pci_hotplug_slots_subsys);
++	kset_unregister(pci_hotplug_slots_kset);
  }
  
-@@ -1271,7 +1271,7 @@ static int usbvision_radio_open(struct inode *inode, struct file *file)
+ module_init(pci_hotplug_init);
+@@ -737,7 +740,7 @@ MODULE_LICENSE("GPL");
+ module_param(debug, bool, 0644);
+ MODULE_PARM_DESC(debug, "Debugging mode enabled or not");
  
- 	PDEBUG(DBG_IO, "%s:", __FUNCTION__);
+-EXPORT_SYMBOL_GPL(pci_hotplug_slots_subsys);
++EXPORT_SYMBOL_GPL(pci_hotplug_slots_kset);
+ EXPORT_SYMBOL_GPL(pci_hp_register);
+ EXPORT_SYMBOL_GPL(pci_hp_deregister);
+ EXPORT_SYMBOL_GPL(pci_hp_change_slot_info);
+diff --git a/drivers/pci/hotplug/rpadlpar_sysfs.c b/drivers/pci/hotplug/rpadlpar_sysfs.c
+index a080fed..e32148a 100644
+--- a/drivers/pci/hotplug/rpadlpar_sysfs.c
++++ b/drivers/pci/hotplug/rpadlpar_sysfs.c
+@@ -23,44 +23,13 @@
  
--	down(&usbvision->lock);
-+	mutex_lock(&usbvision->lock);
+ #define MAX_DRC_NAME_LEN 64
  
- 	if (usbvision->user) {
- 		err("%s: Someone tried to open an already opened USBVision Radio!", __FUNCTION__);
-@@ -1290,7 +1290,8 @@ static int usbvision_radio_open(struct inode *inode, struct file *file)
- 		errCode = usbvision_set_alternate(usbvision);
- 		if (errCode < 0) {
- 			usbvision->last_error = errCode;
--			return -EBUSY;
-+			errCode = -EBUSY;
-+			goto out;
- 		}
+-/* Store return code of dlpar operation in attribute struct */
+-struct dlpar_io_attr {
+-	int rc;
+-	struct attribute attr;
+-	ssize_t (*store)(struct dlpar_io_attr *dlpar_attr, const char *buf,
+-		size_t nbytes);
+-};
  
- 		// If so far no errors then we shall start the radio
-@@ -1307,7 +1308,8 @@ static int usbvision_radio_open(struct inode *inode, struct file *file)
- 			usbvision->initialized = 0;
- 		}
- 	}
--	up(&usbvision->lock);
-+out:
-+	mutex_unlock(&usbvision->lock);
- 	return errCode;
- }
+-/* Common show callback for all attrs, display the return code
+- * of the dlpar op */
+-static ssize_t
+-dlpar_attr_show(struct kobject * kobj, struct attribute * attr, char * buf)
+-{
+-	struct dlpar_io_attr *dlpar_attr = container_of(attr,
+-						struct dlpar_io_attr, attr);
+-	return sprintf(buf, "%d\n", dlpar_attr->rc);
+-}
+-
+-static ssize_t
+-dlpar_attr_store(struct kobject * kobj, struct attribute * attr,
+-		 const char *buf, size_t nbytes)
+-{
+-	struct dlpar_io_attr *dlpar_attr = container_of(attr,
+-						struct dlpar_io_attr, attr);
+-	return dlpar_attr->store ?
+-		dlpar_attr->store(dlpar_attr, buf, nbytes) : -EIO;
+-}
+-
+-static struct sysfs_ops dlpar_attr_sysfs_ops = {
+-	.show = dlpar_attr_show,
+-	.store = dlpar_attr_store,
+-};
+-
+-static ssize_t add_slot_store(struct dlpar_io_attr *dlpar_attr,
+-				const char *buf, size_t nbytes)
++static ssize_t add_slot_store(struct kobject *kobj, struct kobj_attribute *attr,
++			      const char *buf, size_t nbytes)
+ {
+ 	char drc_name[MAX_DRC_NAME_LEN];
+ 	char *end;
++	int rc;
  
-@@ -1321,7 +1323,7 @@ static int usbvision_radio_close(struct inode *inode, struct file *file)
+ 	if (nbytes >= MAX_DRC_NAME_LEN)
+ 		return 0;
+@@ -72,15 +41,25 @@ static ssize_t add_slot_store(struct dlpar_io_attr *dlpar_attr,
+ 		end = &drc_name[nbytes];
+ 	*end = '\0';
  
- 	PDEBUG(DBG_IO, "");
+-	dlpar_attr->rc = dlpar_add_slot(drc_name);
++	rc = dlpar_add_slot(drc_name);
++	if (rc)
++		return rc;
  
--	down(&usbvision->lock);
-+	mutex_lock(&usbvision->lock);
+ 	return nbytes;
+ }
  
- 	/* Set packet size to 0 */
- 	usbvision->ifaceAlt=0;
-@@ -1337,7 +1339,7 @@ static int usbvision_radio_close(struct inode *inode, struct file *file)
- 		usbvision->initialized = 0;
- 	}
+-static ssize_t remove_slot_store(struct dlpar_io_attr *dlpar_attr,
+-		 		const char *buf, size_t nbytes)
++static ssize_t add_slot_show(struct kobject *kobj,
++			     struct kobj_attribute *attr, char *buf)
++{
++	return sprintf(buf, "0\n");
++}
++
++static ssize_t remove_slot_store(struct kobject *kobj,
++				 struct kobj_attribute *attr,
++				 const char *buf, size_t nbytes)
+ {
+ 	char drc_name[MAX_DRC_NAME_LEN];
++	int rc;
+ 	char *end;
  
--	up(&usbvision->lock);
-+	mutex_unlock(&usbvision->lock);
+ 	if (nbytes >= MAX_DRC_NAME_LEN)
+@@ -93,22 +72,24 @@ static ssize_t remove_slot_store(struct dlpar_io_attr *dlpar_attr,
+ 		end = &drc_name[nbytes];
+ 	*end = '\0';
  
- 	if (usbvision->remove_pending) {
- 		printk(KERN_INFO "%s: Final disconnect\n", __FUNCTION__);
-@@ -1641,7 +1643,7 @@ static struct usb_usbvision *usbvision_alloc(struct usb_device *dev)
+-	dlpar_attr->rc = dlpar_remove_slot(drc_name);
++	rc = dlpar_remove_slot(drc_name);
++	if (rc)
++		return rc;
  
- 	usbvision->dev = dev;
+ 	return nbytes;
+ }
  
--	init_MUTEX(&usbvision->lock);	/* to 1 == available */
-+	mutex_init(&usbvision->lock);	/* available */
+-static struct dlpar_io_attr add_slot_attr = {
+-	.rc = 0,
+-	.attr = { .name = ADD_SLOT_ATTR_NAME, .mode = 0644, },
+-	.store = add_slot_store,
+-};
++static ssize_t remove_slot_show(struct kobject *kobj,
++				struct kobj_attribute *attr, char *buf)
++{
++	return sprintf(buf, "0\n");
++}
  
- 	// prepare control urb for control messages during interrupts
- 	usbvision->ctrlUrb = usb_alloc_urb(USBVISION_URB_FRAMES, GFP_KERNEL);
-@@ -1649,7 +1651,6 @@ static struct usb_usbvision *usbvision_alloc(struct usb_device *dev)
- 		goto err_exit;
- 	}
- 	init_waitqueue_head(&usbvision->ctrlUrb_wq);
--	init_MUTEX(&usbvision->ctrlUrbLock);	/* to 1 == available */
+-static struct dlpar_io_attr remove_slot_attr = {
+-	.rc = 0,
+-	.attr = { .name = REMOVE_SLOT_ATTR_NAME, .mode = 0644},
+-	.store = remove_slot_store,
+-};
++static struct kobj_attribute add_slot_attr =
++	__ATTR(ADD_SLOT_ATTR_NAME, 0644, add_slot_show, add_slot_store);
++
++static struct kobj_attribute remove_slot_attr =
++	__ATTR(REMOVE_SLOT_ATTR_NAME, 0644, remove_slot_show, remove_slot_store);
  
- 	usbvision_init_powerOffTimer(usbvision);
+ static struct attribute *default_attrs[] = {
+ 	&add_slot_attr.attr,
+@@ -116,37 +97,29 @@ static struct attribute *default_attrs[] = {
+ 	NULL,
+ };
  
-@@ -1676,13 +1677,13 @@ static void usbvision_release(struct usb_usbvision *usbvision)
- {
- 	PDEBUG(DBG_PROBE, "");
+-static void dlpar_io_release(struct kobject *kobj)
+-{
+-	/* noop */
+-	return;
+-}
+-
+-struct kobj_type ktype_dlpar_io = {
+-	.release = dlpar_io_release,
+-	.sysfs_ops = &dlpar_attr_sysfs_ops,
+-	.default_attrs = default_attrs,
++static struct attribute_group dlpar_attr_group = {
++	.attrs = default_attrs,
+ };
  
--	down(&usbvision->lock);
-+	mutex_lock(&usbvision->lock);
+-struct kset dlpar_io_kset = {
+-	.kobj = {.ktype = &ktype_dlpar_io,
+-		 .parent = &pci_hotplug_slots_subsys.kobj},
+-	.ktype = &ktype_dlpar_io,
+-};
++static struct kobject *dlpar_kobj;
  
- 	usbvision_reset_powerOffTimer(usbvision);
+ int dlpar_sysfs_init(void)
+ {
+-	kobject_set_name(&dlpar_io_kset.kobj, DLPAR_KOBJ_NAME);
+-	if (kset_register(&dlpar_io_kset)) {
+-		printk(KERN_ERR "rpadlpar_io: cannot register kset for %s\n",
+-				kobject_name(&dlpar_io_kset.kobj));
++	int error;
++
++	dlpar_kobj = kobject_create_and_add(DLPAR_KOBJ_NAME,
++					    &pci_hotplug_slots_kset->kobj);
++	if (!dlpar_kobj)
+ 		return -EINVAL;
+-	}
  
- 	usbvision->initialized = 0;
+-	return 0;
++	error = sysfs_create_group(dlpar_kobj, &dlpar_attr_group);
++	if (error)
++		kobject_put(dlpar_kobj);
++	return error;
+ }
  
--	up(&usbvision->lock);
-+	mutex_unlock(&usbvision->lock);
+ void dlpar_sysfs_exit(void)
+ {
+-	kset_unregister(&dlpar_io_kset);
++	sysfs_remove_group(dlpar_kobj, &dlpar_attr_group);
++	kobject_put(dlpar_kobj);
+ }
+diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
+index 6d1a216..c4fa35d 100644
+--- a/drivers/pci/pci-driver.c
++++ b/drivers/pci/pci-driver.c
+@@ -1,6 +1,11 @@
+ /*
+  * drivers/pci/pci-driver.c
+  *
++ * (C) Copyright 2002-2004, 2007 Greg Kroah-Hartman <greg at kroah.com>
++ * (C) Copyright 2007 Novell Inc.
++ *
++ * Released under the GPL v2 only.
++ *
+  */
  
- 	usbvision_remove_sysfs(usbvision->vdev);
- 	usbvision_unregister_video(usbvision);
-@@ -1796,7 +1797,7 @@ static int __devinit usbvision_probe(struct usb_interface *intf,
- 	}
- 	PDEBUG(DBG_PROBE, "bridgeType %d", usbvision->bridgeType);
+ #include <linux/pci.h>
+@@ -96,17 +101,21 @@ pci_create_newid_file(struct pci_driver *drv)
+ {
+ 	int error = 0;
+ 	if (drv->probe != NULL)
+-		error = sysfs_create_file(&drv->driver.kobj,
+-					  &driver_attr_new_id.attr);
++		error = driver_create_file(&drv->driver, &driver_attr_new_id);
+ 	return error;
+ }
  
--	down(&usbvision->lock);
-+	mutex_lock(&usbvision->lock);
++static void pci_remove_newid_file(struct pci_driver *drv)
++{
++	driver_remove_file(&drv->driver, &driver_attr_new_id);
++}
+ #else /* !CONFIG_HOTPLUG */
+ static inline void pci_free_dynids(struct pci_driver *drv) {}
+ static inline int pci_create_newid_file(struct pci_driver *drv)
+ {
+ 	return 0;
+ }
++static inline void pci_remove_newid_file(struct pci_driver *drv) {}
+ #endif
  
- 	/* compute alternate max packet sizes */
- 	uif = dev->actconfig->interface[0];
-@@ -1807,6 +1808,7 @@ static int __devinit usbvision_probe(struct usb_interface *intf,
- 					      usbvision->num_alt,GFP_KERNEL);
- 	if (usbvision->alt_max_pkt_size == NULL) {
- 		err("usbvision: out of memory!\n");
-+		mutex_unlock(&usbvision->lock);
- 		return -ENOMEM;
- 	}
+ /**
+@@ -352,50 +361,6 @@ static void pci_device_shutdown(struct device *dev)
+ 		drv->shutdown(pci_dev);
+ }
  
-@@ -1840,7 +1842,7 @@ static int __devinit usbvision_probe(struct usb_interface *intf,
- 	usbvision->streaming = Stream_Off;
- 	usbvision_register_video(usbvision);
- 	usbvision_configure_video(usbvision);
--	up(&usbvision->lock);
-+	mutex_unlock(&usbvision->lock);
+-#define kobj_to_pci_driver(obj) container_of(obj, struct device_driver, kobj)
+-#define attr_to_driver_attribute(obj) container_of(obj, struct driver_attribute, attr)
+-
+-static ssize_t
+-pci_driver_attr_show(struct kobject * kobj, struct attribute *attr, char *buf)
+-{
+-	struct device_driver *driver = kobj_to_pci_driver(kobj);
+-	struct driver_attribute *dattr = attr_to_driver_attribute(attr);
+-	ssize_t ret;
+-
+-	if (!get_driver(driver))
+-		return -ENODEV;
+-
+-	ret = dattr->show ? dattr->show(driver, buf) : -EIO;
+-
+-	put_driver(driver);
+-	return ret;
+-}
+-
+-static ssize_t
+-pci_driver_attr_store(struct kobject * kobj, struct attribute *attr,
+-		      const char *buf, size_t count)
+-{
+-	struct device_driver *driver = kobj_to_pci_driver(kobj);
+-	struct driver_attribute *dattr = attr_to_driver_attribute(attr);
+-	ssize_t ret;
+-
+-	if (!get_driver(driver))
+-		return -ENODEV;
+-
+-	ret = dattr->store ? dattr->store(driver, buf, count) : -EIO;
+-
+-	put_driver(driver);
+-	return ret;
+-}
+-
+-static struct sysfs_ops pci_driver_sysfs_ops = {
+-	.show = pci_driver_attr_show,
+-	.store = pci_driver_attr_store,
+-};
+-static struct kobj_type pci_driver_kobj_type = {
+-	.sysfs_ops = &pci_driver_sysfs_ops,
+-};
+-
+ /**
+  * __pci_register_driver - register a new pci driver
+  * @drv: the driver structure to register
+@@ -417,7 +382,6 @@ int __pci_register_driver(struct pci_driver *drv, struct module *owner,
+ 	drv->driver.bus = &pci_bus_type;
+ 	drv->driver.owner = owner;
+ 	drv->driver.mod_name = mod_name;
+-	drv->driver.kobj.ktype = &pci_driver_kobj_type;
  
+ 	spin_lock_init(&drv->dynids.lock);
+ 	INIT_LIST_HEAD(&drv->dynids.list);
+@@ -447,6 +411,7 @@ int __pci_register_driver(struct pci_driver *drv, struct module *owner,
+ void
+ pci_unregister_driver(struct pci_driver *drv)
+ {
++	pci_remove_newid_file(drv);
+ 	driver_unregister(&drv->driver);
+ 	pci_free_dynids(drv);
+ }
+diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
+index c5ca313..5fd5852 100644
+--- a/drivers/pci/probe.c
++++ b/drivers/pci/probe.c
+@@ -1210,16 +1210,19 @@ static void __init pci_sort_breadthfirst_klist(void)
+ 	struct klist_node *n;
+ 	struct device *dev;
+ 	struct pci_dev *pdev;
++	struct klist *device_klist;
  
- 	usb_set_intfdata (intf, usbvision);
-@@ -1871,7 +1873,7 @@ static void __devexit usbvision_disconnect(struct usb_interface *intf)
+-	spin_lock(&pci_bus_type.klist_devices.k_lock);
+-	list_for_each_safe(pos, tmp, &pci_bus_type.klist_devices.k_list) {
++	device_klist = bus_get_device_klist(&pci_bus_type);
++
++	spin_lock(&device_klist->k_lock);
++	list_for_each_safe(pos, tmp, &device_klist->k_list) {
+ 		n = container_of(pos, struct klist_node, n_node);
+ 		dev = container_of(n, struct device, knode_bus);
+ 		pdev = to_pci_dev(dev);
+ 		pci_insertion_sort_klist(pdev, &sorted_devices);
  	}
- 	usb_set_intfdata (intf, NULL);
+-	list_splice(&sorted_devices, &pci_bus_type.klist_devices.k_list);
+-	spin_unlock(&pci_bus_type.klist_devices.k_lock);
++	list_splice(&sorted_devices, &device_klist->k_list);
++	spin_unlock(&device_klist->k_lock);
+ }
  
--	down(&usbvision->lock);
-+	mutex_lock(&usbvision->lock);
+ static void __init pci_insertion_sort_devices(struct pci_dev *a, struct list_head *list)
+diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c
+index 5cf89a9..15c18f5 100644
+--- a/drivers/pcmcia/ds.c
++++ b/drivers/pcmcia/ds.c
+@@ -312,8 +312,7 @@ pcmcia_create_newid_file(struct pcmcia_driver *drv)
+ {
+ 	int error = 0;
+ 	if (drv->probe != NULL)
+-		error = sysfs_create_file(&drv->drv.kobj,
+-					  &driver_attr_new_id.attr);
++		error = driver_create_file(&drv->drv, &driver_attr_new_id);
+ 	return error;
+ }
  
- 	// At this time we ask to cancel outstanding URBs
- 	usbvision_stop_isoc(usbvision);
-@@ -1885,7 +1887,7 @@ static void __devexit usbvision_disconnect(struct usb_interface *intf)
- 	usb_put_dev(usbvision->dev);
- 	usbvision->dev = NULL;	// USB device is no more
+diff --git a/drivers/pcmcia/pxa2xx_base.c b/drivers/pcmcia/pxa2xx_base.c
+index 874923f..e439044 100644
+--- a/drivers/pcmcia/pxa2xx_base.c
++++ b/drivers/pcmcia/pxa2xx_base.c
+@@ -29,6 +29,7 @@
+ #include <asm/irq.h>
+ #include <asm/system.h>
+ #include <asm/arch/pxa-regs.h>
++#include <asm/arch/pxa2xx-regs.h>
  
--	up(&usbvision->lock);
-+	mutex_unlock(&usbvision->lock);
+ #include <pcmcia/cs_types.h>
+ #include <pcmcia/ss.h>
+diff --git a/drivers/power/apm_power.c b/drivers/power/apm_power.c
+index bbf3ee1..7e29b90 100644
+--- a/drivers/power/apm_power.c
++++ b/drivers/power/apm_power.c
+@@ -13,6 +13,7 @@
+ #include <linux/power_supply.h>
+ #include <linux/apm-emulation.h>
  
- 	if (usbvision->user) {
- 		printk(KERN_INFO "%s: In use, disconnect pending\n",
-diff --git a/drivers/media/video/usbvision/usbvision.h b/drivers/media/video/usbvision/usbvision.h
-index c5b6c50..20d7ec6 100644
---- a/drivers/media/video/usbvision/usbvision.h
-+++ b/drivers/media/video/usbvision/usbvision.h
-@@ -34,16 +34,13 @@
- #include <linux/list.h>
- #include <linux/usb.h>
- #include <linux/i2c.h>
-+#include <linux/mutex.h>
- #include <media/v4l2-common.h>
- #include <media/tuner.h>
- #include <linux/videodev2.h>
++static DEFINE_MUTEX(apm_mutex);
+ #define PSY_PROP(psy, prop, val) psy->get_property(psy, \
+ 			 POWER_SUPPLY_PROP_##prop, val)
  
- #define USBVISION_DEBUG		/* Turn on debug messages */
+@@ -23,67 +24,86 @@
  
--#ifndef VID_HARDWARE_USBVISION
--	#define VID_HARDWARE_USBVISION 34   /* USBVision Video Grabber */
--#endif
--
- #define USBVISION_PWR_REG		0x00
- 	#define USBVISION_SSPND_EN		(1 << 1)
- 	#define USBVISION_RES2			(1 << 2)
-@@ -373,7 +370,6 @@ struct usb_usbvision {
- 	int ctrlUrbBusy;
- 	struct usb_ctrlrequest ctrlUrbSetup;
- 	wait_queue_head_t ctrlUrb_wq;					// Processes waiting
--	struct semaphore ctrlUrbLock;
+ static struct power_supply *main_battery;
  
- 	/* configuration part */
- 	int have_tuner;
-@@ -396,7 +392,7 @@ struct usb_usbvision {
- 	unsigned char iface;						/* Video interface number */
- 	unsigned char ifaceAlt;			/* Alt settings */
- 	unsigned char Vin_Reg2_Preset;
--	struct semaphore lock;
-+	struct mutex               lock;
- 	struct timer_list powerOffTimer;
- 	struct work_struct powerOffWork;
- 	int power;							/* is the device powered on? */
-diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c
-index 1141b4b..c056ff6 100644
---- a/drivers/media/video/v4l2-common.c
-+++ b/drivers/media/video/v4l2-common.c
-@@ -400,7 +400,7 @@ static const char *v4l2_int_ioctls[] = {
+-static void find_main_battery(void)
+-{
+-	struct device *dev;
+-	struct power_supply *bat = NULL;
+-	struct power_supply *max_charge_bat = NULL;
+-	struct power_supply *max_energy_bat = NULL;
++struct find_bat_param {
++	struct power_supply *main;
++	struct power_supply *bat;
++	struct power_supply *max_charge_bat;
++	struct power_supply *max_energy_bat;
+ 	union power_supply_propval full;
+-	int max_charge = 0;
+-	int max_energy = 0;
++	int max_charge;
++	int max_energy;
++};
  
- 	[_IOC_NR(TUNER_SET_TYPE_ADDR)]         = "TUNER_SET_TYPE_ADDR",
- 	[_IOC_NR(TUNER_SET_STANDBY)]           = "TUNER_SET_STANDBY",
--	[_IOC_NR(TDA9887_SET_CONFIG)]          = "TDA9887_SET_CONFIG",
-+	[_IOC_NR(TUNER_SET_CONFIG)]            = "TUNER_SET_CONFIG",
+-	main_battery = NULL;
++static int __find_main_battery(struct device *dev, void *data)
++{
++	struct find_bat_param *bp = (struct find_bat_param *)data;
  
- 	[_IOC_NR(VIDIOC_INT_S_TUNER_MODE)]     = "VIDIOC_INT_S_TUNER_MODE",
- 	[_IOC_NR(VIDIOC_INT_RESET)]            = "VIDIOC_INT_RESET",
-@@ -1013,6 +1013,34 @@ int v4l2_chip_match_host(u32 match_type, u32 match_chip)
+-	list_for_each_entry(dev, &power_supply_class->devices, node) {
+-		bat = dev_get_drvdata(dev);
++	bp->bat = dev_get_drvdata(dev);
  
- /* ----------------------------------------------------------------- */
+-		if (bat->use_for_apm) {
+-			/* nice, we explicitly asked to report this battery. */
+-			main_battery = bat;
+-			return;
+-		}
++	if (bp->bat->use_for_apm) {
++		/* nice, we explicitly asked to report this battery. */
++		bp->main = bp->bat;
++		return 1;
++	}
  
-+/* Helper function for I2C legacy drivers */
+-		if (!PSY_PROP(bat, CHARGE_FULL_DESIGN, &full) ||
+-				!PSY_PROP(bat, CHARGE_FULL, &full)) {
+-			if (full.intval > max_charge) {
+-				max_charge_bat = bat;
+-				max_charge = full.intval;
+-			}
+-		} else if (!PSY_PROP(bat, ENERGY_FULL_DESIGN, &full) ||
+-				!PSY_PROP(bat, ENERGY_FULL, &full)) {
+-			if (full.intval > max_energy) {
+-				max_energy_bat = bat;
+-				max_energy = full.intval;
+-			}
++	if (!PSY_PROP(bp->bat, CHARGE_FULL_DESIGN, &bp->full) ||
++			!PSY_PROP(bp->bat, CHARGE_FULL, &bp->full)) {
++		if (bp->full.intval > bp->max_charge) {
++			bp->max_charge_bat = bp->bat;
++			bp->max_charge = bp->full.intval;
++		}
++	} else if (!PSY_PROP(bp->bat, ENERGY_FULL_DESIGN, &bp->full) ||
++			!PSY_PROP(bp->bat, ENERGY_FULL, &bp->full)) {
++		if (bp->full.intval > bp->max_energy) {
++			bp->max_energy_bat = bp->bat;
++			bp->max_energy = bp->full.intval;
+ 		}
+ 	}
++	return 0;
++}
 +
-+int v4l2_i2c_attach(struct i2c_adapter *adapter, int address, struct i2c_driver *driver,
-+		const char *name, int (*probe)(struct i2c_client *))
++static void find_main_battery(void)
 +{
-+	struct i2c_client *client;
-+	int err;
-+
-+	client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
-+	if (client == 0)
-+		return -ENOMEM;
++	struct find_bat_param bp;
++	int error;
 +
-+	client->addr = address;
-+	client->adapter = adapter;
-+	client->driver = driver;
-+	strlcpy(client->name, name, sizeof(client->name));
++	memset(&bp, 0, sizeof(struct find_bat_param));
++	main_battery = NULL;
++	bp.main = main_battery;
 +
-+	err = probe(client);
-+	if (err == 0) {
-+		i2c_attach_client(client);
-+	} else {
-+		kfree(client);
++	error = class_for_each_device(power_supply_class, &bp,
++				      __find_main_battery);
++	if (error) {
++		main_battery = bp.main;
++		return;
 +	}
-+	return err != -ENOMEM ? 0 : err;
-+}
-+
-+/* ----------------------------------------------------------------- */
-+
- EXPORT_SYMBOL(v4l2_norm_to_name);
- EXPORT_SYMBOL(v4l2_video_std_construct);
- 
-@@ -1038,6 +1066,8 @@ EXPORT_SYMBOL(v4l2_chip_match_i2c_client);
- EXPORT_SYMBOL(v4l2_chip_ident_i2c_client);
- EXPORT_SYMBOL(v4l2_chip_match_host);
- 
-+EXPORT_SYMBOL(v4l2_i2c_attach);
-+
- /*
-  * Local variables:
-  * c-basic-offset: 8
-diff --git a/drivers/media/video/v4l2-int-device.c b/drivers/media/video/v4l2-int-device.c
-index 8b4ef53..a545dca 100644
---- a/drivers/media/video/v4l2-int-device.c
-+++ b/drivers/media/video/v4l2-int-device.c
-@@ -57,12 +57,12 @@ static void v4l2_int_device_try_attach_all(void)
- 			if (!try_module_get(m->module))
- 				continue;
  
--			if (m->u.master->attach(m, s)) {
-+			s->u.slave->master = m;
-+			if (m->u.master->attach(s)) {
-+				s->u.slave->master = NULL;
- 				module_put(m->module);
- 				continue;
- 			}
--
--			s->u.slave->master = m;
+-	if ((max_energy_bat && max_charge_bat) &&
+-			(max_energy_bat != max_charge_bat)) {
++	if ((bp.max_energy_bat && bp.max_charge_bat) &&
++			(bp.max_energy_bat != bp.max_charge_bat)) {
+ 		/* try guess battery with more capacity */
+-		if (!PSY_PROP(max_charge_bat, VOLTAGE_MAX_DESIGN, &full)) {
+-			if (max_energy > max_charge * full.intval)
+-				main_battery = max_energy_bat;
++		if (!PSY_PROP(bp.max_charge_bat, VOLTAGE_MAX_DESIGN,
++			      &bp.full)) {
++			if (bp.max_energy > bp.max_charge * bp.full.intval)
++				main_battery = bp.max_energy_bat;
+ 			else
+-				main_battery = max_charge_bat;
+-		} else if (!PSY_PROP(max_energy_bat, VOLTAGE_MAX_DESIGN,
+-								  &full)) {
+-			if (max_charge > max_energy / full.intval)
+-				main_battery = max_charge_bat;
++				main_battery = bp.max_charge_bat;
++		} else if (!PSY_PROP(bp.max_energy_bat, VOLTAGE_MAX_DESIGN,
++								  &bp.full)) {
++			if (bp.max_charge > bp.max_energy / bp.full.intval)
++				main_battery = bp.max_charge_bat;
+ 			else
+-				main_battery = max_energy_bat;
++				main_battery = bp.max_energy_bat;
+ 		} else {
+ 			/* give up, choice any */
+-			main_battery = max_energy_bat;
++			main_battery = bp.max_energy_bat;
  		}
+-	} else if (max_charge_bat) {
+-		main_battery = max_charge_bat;
+-	} else if (max_energy_bat) {
+-		main_battery = max_energy_bat;
++	} else if (bp.max_charge_bat) {
++		main_battery = bp.max_charge_bat;
++	} else if (bp.max_energy_bat) {
++		main_battery = bp.max_energy_bat;
+ 	} else {
+ 		/* give up, try the last if any */
+-		main_battery = bat;
++		main_battery = bp.bat;
  	}
  }
-diff --git a/drivers/media/video/videobuf-core.c b/drivers/media/video/videobuf-core.c
-index c8a5cb5..80a14da 100644
---- a/drivers/media/video/videobuf-core.c
-+++ b/drivers/media/video/videobuf-core.c
-@@ -22,29 +22,32 @@
- #include <media/videobuf-core.h>
- 
- #define MAGIC_BUFFER 0x20070728
--#define MAGIC_CHECK(is,should)	if (unlikely((is) != (should))) \
--	{ printk(KERN_ERR "magic mismatch: %x (expected %x)\n",is,should); BUG(); }
-+#define MAGIC_CHECK(is, should) do {					   \
-+	if (unlikely((is) != (should))) {				   \
-+	printk(KERN_ERR "magic mismatch: %x (expected %x)\n", is, should); \
-+	BUG(); } } while (0)
- 
--static int debug = 0;
-+static int debug;
- module_param(debug, int, 0644);
- 
- MODULE_DESCRIPTION("helper module to manage video4linux buffers");
- MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab at infradead.org>");
- MODULE_LICENSE("GPL");
- 
--#define dprintk(level, fmt, arg...)	if (debug >= level) \
--	printk(KERN_DEBUG "vbuf: " fmt , ## arg)
-+#define dprintk(level, fmt, arg...) do {			\
-+	if (debug >= level) 					\
-+	printk(KERN_DEBUG "vbuf: " fmt , ## arg); } while (0)
- 
- /* --------------------------------------------------------------------- */
- 
- #define CALL(q, f, arg...)						\
--	( (q->int_ops->f)? q->int_ops->f(arg) : 0)
-+	((q->int_ops->f) ? q->int_ops->f(arg) : 0)
- 
--void* videobuf_alloc(struct videobuf_queue* q)
-+void *videobuf_alloc(struct videobuf_queue *q)
- {
- 	struct videobuf_buffer *vb;
  
--	BUG_ON (q->msize<sizeof(*vb));
-+	BUG_ON(q->msize < sizeof(*vb));
+@@ -207,10 +227,10 @@ static void apm_battery_apm_get_power_status(struct apm_power_info *info)
+ 	union power_supply_propval status;
+ 	union power_supply_propval capacity, time_to_full, time_to_empty;
  
- 	if (!q->int_ops || !q->int_ops->alloc) {
- 		printk(KERN_ERR "No specific ops defined!\n");
-@@ -66,20 +69,21 @@ int videobuf_waiton(struct videobuf_buffer *vb, int non_blocking, int intr)
- 	int retval = 0;
- 	DECLARE_WAITQUEUE(wait, current);
+-	down(&power_supply_class->sem);
++	mutex_lock(&apm_mutex);
+ 	find_main_battery();
+ 	if (!main_battery) {
+-		up(&power_supply_class->sem);
++		mutex_unlock(&apm_mutex);
+ 		return;
+ 	}
  
--	MAGIC_CHECK(vb->magic,MAGIC_BUFFER);
-+	MAGIC_CHECK(vb->magic, MAGIC_BUFFER);
- 	add_wait_queue(&vb->done, &wait);
--	while (vb->state == STATE_ACTIVE || vb->state == STATE_QUEUED) {
-+	while (vb->state == VIDEOBUF_ACTIVE || vb->state == VIDEOBUF_QUEUED) {
- 		if (non_blocking) {
- 			retval = -EAGAIN;
- 			break;
- 		}
- 		set_current_state(intr  ? TASK_INTERRUPTIBLE
- 					: TASK_UNINTERRUPTIBLE);
--		if (vb->state == STATE_ACTIVE || vb->state == STATE_QUEUED)
-+		if (vb->state == VIDEOBUF_ACTIVE ||
-+		    vb->state == VIDEOBUF_QUEUED)
- 			schedule();
- 		set_current_state(TASK_RUNNING);
- 		if (intr && signal_pending(current)) {
--			dprintk(1,"buffer waiton: -EINTR\n");
-+			dprintk(1, "buffer waiton: -EINTR\n");
- 			retval = -EINTR;
- 			break;
+@@ -278,7 +298,7 @@ static void apm_battery_apm_get_power_status(struct apm_power_info *info)
  		}
-@@ -88,27 +92,33 @@ int videobuf_waiton(struct videobuf_buffer *vb, int non_blocking, int intr)
- 	return retval;
- }
- 
--int videobuf_iolock(struct videobuf_queue* q, struct videobuf_buffer *vb,
-+int videobuf_iolock(struct videobuf_queue *q, struct videobuf_buffer *vb,
- 		    struct v4l2_framebuffer *fbuf)
- {
--	MAGIC_CHECK(vb->magic,MAGIC_BUFFER);
--	MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);
-+	MAGIC_CHECK(vb->magic, MAGIC_BUFFER);
-+	MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
- 
--	/* FIXME: This is required to avoid OOPS on some cases, since mmap_mapper()
--	   method should be called before _iolock.
-+	/* This is required to avoid OOPS on some cases,
-+	   since mmap_mapper() method should be called before _iolock.
- 	   On some cases, the mmap_mapper() is called only after scheduling.
--
--	   However, this way is just too dirty! Better to wait for some event.
- 	 */
--	schedule_timeout(HZ);
-+	if (vb->memory == V4L2_MEMORY_MMAP) {
-+		wait_event_timeout(vb->done, q->is_mmapped,
-+				   msecs_to_jiffies(100));
-+		if (!q->is_mmapped) {
-+			printk(KERN_ERR
-+			       "Error: mmap_mapper() never called!\n");
-+			return -EINVAL;
-+		}
-+	}
+ 	}
  
--	return CALL(q,iolock,q,vb,fbuf);
-+	return CALL(q, iolock, q, vb, fbuf);
+-	up(&power_supply_class->sem);
++	mutex_unlock(&apm_mutex);
  }
  
- /* --------------------------------------------------------------------- */
+ static int __init apm_battery_init(void)
+diff --git a/drivers/power/power_supply_core.c b/drivers/power/power_supply_core.c
+index a63b75c..03d6a38 100644
+--- a/drivers/power/power_supply_core.c
++++ b/drivers/power/power_supply_core.c
+@@ -20,28 +20,29 @@
  
+ struct class *power_supply_class;
  
--void videobuf_queue_core_init(struct videobuf_queue* q,
-+void videobuf_queue_core_init(struct videobuf_queue *q,
- 			 struct videobuf_queue_ops *ops,
- 			 void *dev,
- 			 spinlock_t *irqlock,
-@@ -118,7 +128,7 @@ void videobuf_queue_core_init(struct videobuf_queue* q,
- 			 void *priv,
- 			 struct videobuf_qtype_ops *int_ops)
++static int __power_supply_changed_work(struct device *dev, void *data)
++{
++	struct power_supply *psy = (struct power_supply *)data;
++	struct power_supply *pst = dev_get_drvdata(dev);
++	int i;
++
++	for (i = 0; i < psy->num_supplicants; i++)
++		if (!strcmp(psy->supplied_to[i], pst->name)) {
++			if (pst->external_power_changed)
++				pst->external_power_changed(pst);
++		}
++	return 0;
++}
++
+ static void power_supply_changed_work(struct work_struct *work)
  {
--	memset(q,0,sizeof(*q));
-+	memset(q, 0, sizeof(*q));
- 	q->irqlock   = irqlock;
- 	q->dev       = dev;
- 	q->type      = type;
-@@ -129,13 +139,13 @@ void videobuf_queue_core_init(struct videobuf_queue* q,
- 	q->int_ops   = int_ops;
+ 	struct power_supply *psy = container_of(work, struct power_supply,
+ 						changed_work);
+-	int i;
  
- 	/* All buffer operations are mandatory */
--	BUG_ON (!q->ops->buf_setup);
--	BUG_ON (!q->ops->buf_prepare);
--	BUG_ON (!q->ops->buf_queue);
--	BUG_ON (!q->ops->buf_release);
-+	BUG_ON(!q->ops->buf_setup);
-+	BUG_ON(!q->ops->buf_prepare);
-+	BUG_ON(!q->ops->buf_queue);
-+	BUG_ON(!q->ops->buf_release);
+ 	dev_dbg(psy->dev, "%s\n", __FUNCTION__);
  
- 	/* Having implementations for abstract methods are mandatory */
--	BUG_ON (!q->int_ops);
-+	BUG_ON(!q->int_ops);
+-	for (i = 0; i < psy->num_supplicants; i++) {
+-		struct device *dev;
+-
+-		down(&power_supply_class->sem);
+-		list_for_each_entry(dev, &power_supply_class->devices, node) {
+-			struct power_supply *pst = dev_get_drvdata(dev);
+-
+-			if (!strcmp(psy->supplied_to[i], pst->name)) {
+-				if (pst->external_power_changed)
+-					pst->external_power_changed(pst);
+-			}
+-		}
+-		up(&power_supply_class->sem);
+-	}
++	class_for_each_device(power_supply_class, psy,
++			      __power_supply_changed_work);
  
- 	mutex_init(&q->lock);
- 	INIT_LIST_HEAD(&q->stream);
-@@ -146,33 +156,33 @@ int videobuf_queue_is_busy(struct videobuf_queue *q)
- {
- 	int i;
+ 	power_supply_update_leds(psy);
  
--	MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);
-+	MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
+@@ -55,32 +56,35 @@ void power_supply_changed(struct power_supply *psy)
+ 	schedule_work(&psy->changed_work);
+ }
  
- 	if (q->streaming) {
--		dprintk(1,"busy: streaming active\n");
-+		dprintk(1, "busy: streaming active\n");
- 		return 1;
- 	}
- 	if (q->reading) {
--		dprintk(1,"busy: pending read #1\n");
-+		dprintk(1, "busy: pending read #1\n");
- 		return 1;
- 	}
- 	if (q->read_buf) {
--		dprintk(1,"busy: pending read #2\n");
-+		dprintk(1, "busy: pending read #2\n");
- 		return 1;
- 	}
- 	for (i = 0; i < VIDEO_MAX_FRAME; i++) {
- 		if (NULL == q->bufs[i])
- 			continue;
- 		if (q->bufs[i]->map) {
--			dprintk(1,"busy: buffer #%d mapped\n",i);
-+			dprintk(1, "busy: buffer #%d mapped\n", i);
- 			return 1;
- 		}
--		if (q->bufs[i]->state == STATE_QUEUED) {
--			dprintk(1,"busy: buffer #%d queued\n",i);
-+		if (q->bufs[i]->state == VIDEOBUF_QUEUED) {
-+			dprintk(1, "busy: buffer #%d queued\n", i);
- 			return 1;
- 		}
--		if (q->bufs[i]->state == STATE_ACTIVE) {
--			dprintk(1,"busy: buffer #%d avtive\n",i);
-+		if (q->bufs[i]->state == VIDEOBUF_ACTIVE) {
-+			dprintk(1, "busy: buffer #%d avtive\n", i);
- 			return 1;
- 		}
- 	}
-@@ -182,28 +192,28 @@ int videobuf_queue_is_busy(struct videobuf_queue *q)
- /* Locking: Caller holds q->lock */
- void videobuf_queue_cancel(struct videobuf_queue *q)
+-int power_supply_am_i_supplied(struct power_supply *psy)
++static int __power_supply_am_i_supplied(struct device *dev, void *data)
  {
--	unsigned long flags=0;
-+	unsigned long flags = 0;
- 	int i;
- 
- 	/* remove queued buffers from list */
- 	if (q->irqlock)
--		spin_lock_irqsave(q->irqlock,flags);
-+		spin_lock_irqsave(q->irqlock, flags);
- 	for (i = 0; i < VIDEO_MAX_FRAME; i++) {
- 		if (NULL == q->bufs[i])
- 			continue;
--		if (q->bufs[i]->state == STATE_QUEUED) {
-+		if (q->bufs[i]->state == VIDEOBUF_QUEUED) {
- 			list_del(&q->bufs[i]->queue);
--			q->bufs[i]->state = STATE_ERROR;
-+			q->bufs[i]->state = VIDEOBUF_ERROR;
+ 	union power_supply_propval ret = {0,};
+-	struct device *dev;
+-
+-	down(&power_supply_class->sem);
+-	list_for_each_entry(dev, &power_supply_class->devices, node) {
+-		struct power_supply *epsy = dev_get_drvdata(dev);
+-		int i;
+-
+-		for (i = 0; i < epsy->num_supplicants; i++) {
+-			if (!strcmp(epsy->supplied_to[i], psy->name)) {
+-				if (epsy->get_property(epsy,
+-					  POWER_SUPPLY_PROP_ONLINE, &ret))
+-					continue;
+-				if (ret.intval)
+-					goto out;
+-			}
++	struct power_supply *psy = (struct power_supply *)data;
++	struct power_supply *epsy = dev_get_drvdata(dev);
++	int i;
++
++	for (i = 0; i < epsy->num_supplicants; i++) {
++		if (!strcmp(epsy->supplied_to[i], psy->name)) {
++			if (epsy->get_property(epsy,
++				  POWER_SUPPLY_PROP_ONLINE, &ret))
++				continue;
++			if (ret.intval)
++				return ret.intval;
  		}
  	}
- 	if (q->irqlock)
--		spin_unlock_irqrestore(q->irqlock,flags);
-+		spin_unlock_irqrestore(q->irqlock, flags);
- 
- 	/* free all buffers + clear queue */
- 	for (i = 0; i < VIDEO_MAX_FRAME; i++) {
- 		if (NULL == q->bufs[i])
- 			continue;
--		q->ops->buf_release(q,q->bufs[i]);
-+		q->ops->buf_release(q, q->bufs[i]);
- 	}
- 	INIT_LIST_HEAD(&q->stream);
- }
-@@ -233,8 +243,8 @@ enum v4l2_field videobuf_next_field(struct videobuf_queue *q)
- static void videobuf_status(struct videobuf_queue *q, struct v4l2_buffer *b,
- 			    struct videobuf_buffer *vb, enum v4l2_buf_type type)
- {
--	MAGIC_CHECK(vb->magic,MAGIC_BUFFER);
--	MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);
-+	MAGIC_CHECK(vb->magic, MAGIC_BUFFER);
-+	MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
+-out:
+-	up(&power_supply_class->sem);
++	return 0;
++}
++
++int power_supply_am_i_supplied(struct power_supply *psy)
++{
++	int error;
++
++	error = class_for_each_device(power_supply_class, psy,
++				      __power_supply_am_i_supplied);
  
- 	b->index    = vb->i;
- 	b->type     = type;
-@@ -259,17 +269,17 @@ static void videobuf_status(struct videobuf_queue *q, struct v4l2_buffer *b,
- 		b->flags |= V4L2_BUF_FLAG_MAPPED;
+-	dev_dbg(psy->dev, "%s %d\n", __FUNCTION__, ret.intval);
++	dev_dbg(psy->dev, "%s %d\n", __FUNCTION__, error);
  
- 	switch (vb->state) {
--	case STATE_PREPARED:
--	case STATE_QUEUED:
--	case STATE_ACTIVE:
-+	case VIDEOBUF_PREPARED:
-+	case VIDEOBUF_QUEUED:
-+	case VIDEOBUF_ACTIVE:
- 		b->flags |= V4L2_BUF_FLAG_QUEUED;
- 		break;
--	case STATE_DONE:
--	case STATE_ERROR:
-+	case VIDEOBUF_DONE:
-+	case VIDEOBUF_ERROR:
- 		b->flags |= V4L2_BUF_FLAG_DONE;
- 		break;
--	case STATE_NEEDS_INIT:
--	case STATE_IDLE:
-+	case VIDEOBUF_NEEDS_INIT:
-+	case VIDEOBUF_IDLE:
- 		/* nothing */
- 		break;
- 	}
-@@ -294,16 +304,20 @@ static int __videobuf_mmap_free(struct videobuf_queue *q)
- 	if (!q)
- 		return 0;
+-	return ret.intval;
++	return error;
+ }
  
--	MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);
-+	MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
-+
+ int power_supply_register(struct device *parent, struct power_supply *psy)
+diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
+index 1e6715e..45e4b96 100644
+--- a/drivers/rtc/Kconfig
++++ b/drivers/rtc/Kconfig
+@@ -404,7 +404,7 @@ config RTC_DRV_SA1100
+ 
+ config RTC_DRV_SH
+ 	tristate "SuperH On-Chip RTC"
+-	depends on RTC_CLASS && (CPU_SH3 || CPU_SH4)
++	depends on RTC_CLASS && SUPERH
+ 	help
+ 	  Say Y here to enable support for the on-chip RTC found in
+ 	  most SuperH processors.
+diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c
+index f1e00ff..7e3ad4f 100644
+--- a/drivers/rtc/interface.c
++++ b/drivers/rtc/interface.c
+@@ -251,20 +251,23 @@ void rtc_update_irq(struct rtc_device *rtc,
+ }
+ EXPORT_SYMBOL_GPL(rtc_update_irq);
+ 
++static int __rtc_match(struct device *dev, void *data)
++{
++	char *name = (char *)data;
 +
-+	rc  = CALL(q, mmap_free, q);
++	if (strncmp(dev->bus_id, name, BUS_ID_SIZE) == 0)
++		return 1;
++	return 0;
++}
 +
-+	q->is_mmapped = 0;
+ struct rtc_device *rtc_class_open(char *name)
+ {
+ 	struct device *dev;
+ 	struct rtc_device *rtc = NULL;
  
--	rc  = CALL(q,mmap_free,q);
--	if (rc<0)
-+	if (rc < 0)
- 		return rc;
+-	down(&rtc_class->sem);
+-	list_for_each_entry(dev, &rtc_class->devices, node) {
+-		if (strncmp(dev->bus_id, name, BUS_ID_SIZE) == 0) {
+-			dev = get_device(dev);
+-			if (dev)
+-				rtc = to_rtc_device(dev);
+-			break;
+-		}
+-	}
++	dev = class_find_device(rtc_class, name, __rtc_match);
++	if (dev)
++		rtc = to_rtc_device(dev);
  
- 	for (i = 0; i < VIDEO_MAX_FRAME; i++) {
- 		if (NULL == q->bufs[i])
- 			continue;
--		q->ops->buf_release(q,q->bufs[i]);
-+		q->ops->buf_release(q, q->bufs[i]);
- 		kfree(q->bufs[i]);
- 		q->bufs[i] = NULL;
+ 	if (rtc) {
+ 		if (!try_module_get(rtc->owner)) {
+@@ -272,7 +275,6 @@ struct rtc_device *rtc_class_open(char *name)
+ 			rtc = NULL;
+ 		}
  	}
-@@ -328,7 +342,7 @@ static int __videobuf_mmap_setup(struct videobuf_queue *q,
- 	unsigned int i;
- 	int err;
+-	up(&rtc_class->sem);
  
--	MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);
-+	MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
+ 	return rtc;
+ }
+diff --git a/drivers/rtc/rtc-ds1672.c b/drivers/rtc/rtc-ds1672.c
+index dfef163..e0900ca 100644
+--- a/drivers/rtc/rtc-ds1672.c
++++ b/drivers/rtc/rtc-ds1672.c
+@@ -16,7 +16,7 @@
+ #define DRV_VERSION "0.3"
  
- 	err = __videobuf_mmap_free(q);
- 	if (0 != err)
-@@ -359,7 +373,7 @@ static int __videobuf_mmap_setup(struct videobuf_queue *q,
- 	if (!i)
- 		return -ENOMEM;
+ /* Addresses to scan: none. This chip cannot be detected. */
+-static unsigned short normal_i2c[] = { I2C_CLIENT_END };
++static const unsigned short normal_i2c[] = { I2C_CLIENT_END };
  
--	dprintk(1,"mmap setup: %d buffers, %d bytes each\n",
-+	dprintk(1, "mmap setup: %d buffers, %d bytes each\n",
- 		i, bsize);
+ /* Insmod parameters */
+ I2C_CLIENT_INSMOD;
+diff --git a/drivers/rtc/rtc-isl1208.c b/drivers/rtc/rtc-isl1208.c
+index 1c74364..725b0c7 100644
+--- a/drivers/rtc/rtc-isl1208.c
++++ b/drivers/rtc/rtc-isl1208.c
+@@ -61,7 +61,7 @@
+ /* i2c configuration */
+ #define ISL1208_I2C_ADDR 0xde
  
- 	return i;
-@@ -379,35 +393,35 @@ int videobuf_mmap_setup(struct videobuf_queue *q,
- int videobuf_reqbufs(struct videobuf_queue *q,
- 		 struct v4l2_requestbuffers *req)
- {
--	unsigned int size,count;
-+	unsigned int size, count;
- 	int retval;
+-static unsigned short normal_i2c[] = {
++static const unsigned short normal_i2c[] = {
+ 	ISL1208_I2C_ADDR>>1, I2C_CLIENT_END
+ };
+ I2C_CLIENT_INSMOD; /* defines addr_data */
+diff --git a/drivers/rtc/rtc-max6900.c b/drivers/rtc/rtc-max6900.c
+index a1cd448..7683412 100644
+--- a/drivers/rtc/rtc-max6900.c
++++ b/drivers/rtc/rtc-max6900.c
+@@ -54,7 +54,7 @@
  
- 	if (req->count < 1) {
--		dprintk(1,"reqbufs: count invalid (%d)\n",req->count);
-+		dprintk(1, "reqbufs: count invalid (%d)\n", req->count);
- 		return -EINVAL;
- 	}
+ #define MAX6900_I2C_ADDR		0xa0
  
- 	if (req->memory != V4L2_MEMORY_MMAP     &&
- 	    req->memory != V4L2_MEMORY_USERPTR  &&
- 	    req->memory != V4L2_MEMORY_OVERLAY) {
--		dprintk(1,"reqbufs: memory type invalid\n");
-+		dprintk(1, "reqbufs: memory type invalid\n");
- 		return -EINVAL;
- 	}
+-static unsigned short normal_i2c[] = {
++static const unsigned short normal_i2c[] = {
+ 	MAX6900_I2C_ADDR >> 1,
+ 	I2C_CLIENT_END
+ };
+diff --git a/drivers/rtc/rtc-pcf8563.c b/drivers/rtc/rtc-pcf8563.c
+index 0242d80..b3317fc 100644
+--- a/drivers/rtc/rtc-pcf8563.c
++++ b/drivers/rtc/rtc-pcf8563.c
+@@ -25,7 +25,7 @@
+  * located at 0x51 will pass the validation routine due to
+  * the way the registers are implemented.
+  */
+-static unsigned short normal_i2c[] = { I2C_CLIENT_END };
++static const unsigned short normal_i2c[] = { I2C_CLIENT_END };
  
- 	mutex_lock(&q->lock);
- 	if (req->type != q->type) {
--		dprintk(1,"reqbufs: queue type invalid\n");
-+		dprintk(1, "reqbufs: queue type invalid\n");
- 		retval = -EINVAL;
- 		goto done;
- 	}
+ /* Module parameters */
+ I2C_CLIENT_INSMOD;
+diff --git a/drivers/rtc/rtc-pcf8583.c b/drivers/rtc/rtc-pcf8583.c
+index 556d0e7..c973ba9 100644
+--- a/drivers/rtc/rtc-pcf8583.c
++++ b/drivers/rtc/rtc-pcf8583.c
+@@ -40,7 +40,7 @@ struct pcf8583 {
+ #define CTRL_ALARM	0x02
+ #define CTRL_TIMER	0x01
  
- 	if (q->streaming) {
--		dprintk(1,"reqbufs: streaming already exists\n");
-+		dprintk(1, "reqbufs: streaming already exists\n");
- 		retval = -EBUSY;
- 		goto done;
- 	}
- 	if (!list_empty(&q->stream)) {
--		dprintk(1,"reqbufs: stream running\n");
-+		dprintk(1, "reqbufs: stream running\n");
- 		retval = -EBUSY;
- 		goto done;
- 	}
-@@ -416,14 +430,14 @@ int videobuf_reqbufs(struct videobuf_queue *q,
- 	if (count > VIDEO_MAX_FRAME)
- 		count = VIDEO_MAX_FRAME;
- 	size = 0;
--	q->ops->buf_setup(q,&count,&size);
-+	q->ops->buf_setup(q, &count, &size);
- 	size = PAGE_ALIGN(size);
--	dprintk(1,"reqbufs: bufs=%d, size=0x%x [%d pages total]\n",
-+	dprintk(1, "reqbufs: bufs=%d, size=0x%x [%d pages total]\n",
- 		count, size, (count*size)>>PAGE_SHIFT);
+-static unsigned short normal_i2c[] = { 0x50, I2C_CLIENT_END };
++static const unsigned short normal_i2c[] = { 0x50, I2C_CLIENT_END };
  
--	retval = __videobuf_mmap_setup(q,count,size,req->memory);
-+	retval = __videobuf_mmap_setup(q, count, size, req->memory);
- 	if (retval < 0) {
--		dprintk(1,"reqbufs: mmap setup returned %d\n",retval);
-+		dprintk(1, "reqbufs: mmap setup returned %d\n", retval);
- 		goto done;
- 	}
+ /* Module parameters */
+ I2C_CLIENT_INSMOD;
+diff --git a/drivers/rtc/rtc-sa1100.c b/drivers/rtc/rtc-sa1100.c
+index 6f1e9a9..2eb3852 100644
+--- a/drivers/rtc/rtc-sa1100.c
++++ b/drivers/rtc/rtc-sa1100.c
+@@ -337,6 +337,8 @@ static int sa1100_rtc_probe(struct platform_device *pdev)
+ 	if (IS_ERR(rtc))
+ 		return PTR_ERR(rtc);
  
-@@ -440,19 +454,19 @@ int videobuf_querybuf(struct videobuf_queue *q, struct v4l2_buffer *b)
++	device_init_wakeup(&pdev->dev, 1);
++
+ 	platform_set_drvdata(pdev, rtc);
  
- 	mutex_lock(&q->lock);
- 	if (unlikely(b->type != q->type)) {
--		dprintk(1,"querybuf: Wrong type.\n");
-+		dprintk(1, "querybuf: Wrong type.\n");
- 		goto done;
- 	}
- 	if (unlikely(b->index < 0 || b->index >= VIDEO_MAX_FRAME)) {
--		dprintk(1,"querybuf: index out of range.\n");
-+		dprintk(1, "querybuf: index out of range.\n");
- 		goto done;
- 	}
- 	if (unlikely(NULL == q->bufs[b->index])) {
--		dprintk(1,"querybuf: buffer is null.\n");
-+		dprintk(1, "querybuf: buffer is null.\n");
- 		goto done;
- 	}
+ 	return 0;
+@@ -352,9 +354,38 @@ static int sa1100_rtc_remove(struct platform_device *pdev)
+ 	return 0;
+ }
  
--	videobuf_status(q,b,q->bufs[b->index],q->type);
-+	videobuf_status(q, b, q->bufs[b->index], q->type);
++#ifdef CONFIG_PM
++static int sa1100_rtc_suspend(struct platform_device *pdev, pm_message_t state)
++{
++	if (pdev->dev.power.power_state.event != state.event) {
++		if (state.event == PM_EVENT_SUSPEND &&
++		    device_may_wakeup(&pdev->dev))
++			enable_irq_wake(IRQ_RTCAlrm);
++
++		pdev->dev.power.power_state = state;
++	}
++	return 0;
++}
++
++static int sa1100_rtc_resume(struct platform_device *pdev)
++{
++	if (pdev->dev.power.power_state.event != PM_EVENT_ON) {
++		if (device_may_wakeup(&pdev->dev))
++			disable_irq_wake(IRQ_RTCAlrm);
++		pdev->dev.power.power_state = PMSG_ON;
++	}
++	return 0;
++}
++#else
++#define sa1100_rtc_suspend	NULL
++#define sa1100_rtc_resume	NULL
++#endif
++
+ static struct platform_driver sa1100_rtc_driver = {
+ 	.probe		= sa1100_rtc_probe,
+ 	.remove		= sa1100_rtc_remove,
++	.suspend	= sa1100_rtc_suspend,
++	.resume		= sa1100_rtc_resume,
+ 	.driver		= {
+ 		.name		= "sa1100-rtc",
+ 	},
+diff --git a/drivers/rtc/rtc-sh.c b/drivers/rtc/rtc-sh.c
+index 8e8c8b8..c1d6a18 100644
+--- a/drivers/rtc/rtc-sh.c
++++ b/drivers/rtc/rtc-sh.c
+@@ -26,17 +26,7 @@
+ #include <asm/rtc.h>
+ 
+ #define DRV_NAME	"sh-rtc"
+-#define DRV_VERSION	"0.1.3"
+-
+-#ifdef CONFIG_CPU_SH3
+-#define rtc_reg_size		sizeof(u16)
+-#define RTC_BIT_INVERTED	0	/* No bug on SH7708, SH7709A */
+-#define RTC_DEF_CAPABILITIES	0UL
+-#elif defined(CONFIG_CPU_SH4)
+-#define rtc_reg_size		sizeof(u32)
+-#define RTC_BIT_INVERTED	0x40	/* bug on SH7750, SH7750S */
+-#define RTC_DEF_CAPABILITIES	RTC_CAP_4_DIGIT_YEAR
+-#endif
++#define DRV_VERSION	"0.1.6"
  
- 	ret = 0;
- done:
-@@ -465,10 +479,10 @@ int videobuf_qbuf(struct videobuf_queue *q,
- {
- 	struct videobuf_buffer *buf;
- 	enum v4l2_field field;
--	unsigned long flags=0;
-+	unsigned long flags = 0;
- 	int retval;
+ #define RTC_REG(r)	((r) * rtc_reg_size)
  
--	MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);
-+	MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
+@@ -58,6 +48,18 @@
+ #define RCR1		RTC_REG(14)	/* Control */
+ #define RCR2		RTC_REG(15)	/* Control */
  
- 	if (b->memory == V4L2_MEMORY_MMAP)
- 		down_read(&current->mm->mmap_sem);
-@@ -476,36 +490,36 @@ int videobuf_qbuf(struct videobuf_queue *q,
- 	mutex_lock(&q->lock);
- 	retval = -EBUSY;
- 	if (q->reading) {
--		dprintk(1,"qbuf: Reading running...\n");
-+		dprintk(1, "qbuf: Reading running...\n");
- 		goto done;
- 	}
- 	retval = -EINVAL;
- 	if (b->type != q->type) {
--		dprintk(1,"qbuf: Wrong type.\n");
-+		dprintk(1, "qbuf: Wrong type.\n");
- 		goto done;
- 	}
- 	if (b->index < 0 || b->index >= VIDEO_MAX_FRAME) {
--		dprintk(1,"qbuf: index out of range.\n");
-+		dprintk(1, "qbuf: index out of range.\n");
- 		goto done;
- 	}
- 	buf = q->bufs[b->index];
- 	if (NULL == buf) {
--		dprintk(1,"qbuf: buffer is null.\n");
-+		dprintk(1, "qbuf: buffer is null.\n");
- 		goto done;
- 	}
--	MAGIC_CHECK(buf->magic,MAGIC_BUFFER);
-+	MAGIC_CHECK(buf->magic, MAGIC_BUFFER);
- 	if (buf->memory != b->memory) {
--		dprintk(1,"qbuf: memory type is wrong.\n");
-+		dprintk(1, "qbuf: memory type is wrong.\n");
- 		goto done;
- 	}
--	if (buf->state != STATE_NEEDS_INIT && buf->state != STATE_IDLE) {
--		dprintk(1,"qbuf: buffer is already queued or active.\n");
-+	if (buf->state != VIDEOBUF_NEEDS_INIT && buf->state != VIDEOBUF_IDLE) {
-+		dprintk(1, "qbuf: buffer is already queued or active.\n");
- 		goto done;
- 	}
++/*
++ * Note on RYRAR and RCR3: Up until this point most of the register
++ * definitions are consistent across all of the available parts. However,
++ * the placement of the optional RYRAR and RCR3 (the RYRAR control
++ * register used to control RYRCNT/RYRAR compare) varies considerably
++ * across various parts, occasionally being mapped in to a completely
++ * unrelated address space. For proper RYRAR support a separate resource
++ * would have to be handed off, but as this is purely optional in
++ * practice, we simply opt not to support it, thereby keeping the code
++ * quite a bit more simplified.
++ */
++
+ /* ALARM Bits - or with BCD encoded value */
+ #define AR_ENB		0x80	/* Enable for alarm cmp   */
  
- 	if (b->flags & V4L2_BUF_FLAG_INPUT) {
- 		if (b->input >= q->inputs) {
--			dprintk(1,"qbuf: wrong input.\n");
-+			dprintk(1, "qbuf: wrong input.\n");
- 			goto done;
- 		}
- 		buf->input = b->input;
-@@ -516,44 +530,46 @@ int videobuf_qbuf(struct videobuf_queue *q,
- 	switch (b->memory) {
- 	case V4L2_MEMORY_MMAP:
- 		if (0 == buf->baddr) {
--			dprintk(1,"qbuf: mmap requested but buffer addr is zero!\n");
-+			dprintk(1, "qbuf: mmap requested "
-+				   "but buffer addr is zero!\n");
- 			goto done;
- 		}
- 		break;
- 	case V4L2_MEMORY_USERPTR:
- 		if (b->length < buf->bsize) {
--			dprintk(1,"qbuf: buffer length is not enough\n");
-+			dprintk(1, "qbuf: buffer length is not enough\n");
- 			goto done;
- 		}
--		if (STATE_NEEDS_INIT != buf->state && buf->baddr != b->m.userptr)
--			q->ops->buf_release(q,buf);
-+		if (VIDEOBUF_NEEDS_INIT != buf->state &&
-+		    buf->baddr != b->m.userptr)
-+			q->ops->buf_release(q, buf);
- 		buf->baddr = b->m.userptr;
- 		break;
- 	case V4L2_MEMORY_OVERLAY:
- 		buf->boff = b->m.offset;
- 		break;
- 	default:
--		dprintk(1,"qbuf: wrong memory type\n");
-+		dprintk(1, "qbuf: wrong memory type\n");
- 		goto done;
- 	}
+diff --git a/drivers/rtc/rtc-x1205.c b/drivers/rtc/rtc-x1205.c
+index b3fae35..b90fb18 100644
+--- a/drivers/rtc/rtc-x1205.c
++++ b/drivers/rtc/rtc-x1205.c
+@@ -32,7 +32,7 @@
+  * unknown chips, the user must explicitly set the probe parameter.
+  */
  
--	dprintk(1,"qbuf: requesting next field\n");
-+	dprintk(1, "qbuf: requesting next field\n");
- 	field = videobuf_next_field(q);
--	retval = q->ops->buf_prepare(q,buf,field);
-+	retval = q->ops->buf_prepare(q, buf, field);
- 	if (0 != retval) {
--		dprintk(1,"qbuf: buffer_prepare returned %d\n",retval);
-+		dprintk(1, "qbuf: buffer_prepare returned %d\n", retval);
- 		goto done;
- 	}
+-static unsigned short normal_i2c[] = { I2C_CLIENT_END };
++static const unsigned short normal_i2c[] = { I2C_CLIENT_END };
  
--	list_add_tail(&buf->stream,&q->stream);
-+	list_add_tail(&buf->stream, &q->stream);
- 	if (q->streaming) {
- 		if (q->irqlock)
--			spin_lock_irqsave(q->irqlock,flags);
--		q->ops->buf_queue(q,buf);
-+			spin_lock_irqsave(q->irqlock, flags);
-+		q->ops->buf_queue(q, buf);
- 		if (q->irqlock)
--			spin_unlock_irqrestore(q->irqlock,flags);
-+			spin_unlock_irqrestore(q->irqlock, flags);
- 	}
--	dprintk(1,"qbuf: succeded\n");
-+	dprintk(1, "qbuf: succeded\n");
- 	retval = 0;
+ /* Insmod parameters */
+ I2C_CLIENT_INSMOD;
+diff --git a/drivers/s390/block/Makefile b/drivers/s390/block/Makefile
+index be9f22d..0a89e08 100644
+--- a/drivers/s390/block/Makefile
++++ b/drivers/s390/block/Makefile
+@@ -2,8 +2,8 @@
+ # S/390 block devices
+ #
  
-  done:
-@@ -571,49 +587,49 @@ int videobuf_dqbuf(struct videobuf_queue *q,
- 	struct videobuf_buffer *buf;
- 	int retval;
+-dasd_eckd_mod-objs := dasd_eckd.o dasd_3990_erp.o dasd_9343_erp.o
+-dasd_fba_mod-objs  := dasd_fba.o dasd_3370_erp.o dasd_9336_erp.o
++dasd_eckd_mod-objs := dasd_eckd.o dasd_3990_erp.o dasd_alias.o
++dasd_fba_mod-objs  := dasd_fba.o
+ dasd_diag_mod-objs := dasd_diag.o
+ dasd_mod-objs      := dasd.o dasd_ioctl.o dasd_proc.o dasd_devmap.o \
+ 			dasd_genhd.o dasd_erp.o
+diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
+index e6bfce6..d640427 100644
+--- a/drivers/s390/block/dasd.c
++++ b/drivers/s390/block/dasd.c
+@@ -48,13 +48,15 @@ MODULE_LICENSE("GPL");
+ /*
+  * SECTION: prototypes for static functions of dasd.c
+  */
+-static int  dasd_alloc_queue(struct dasd_device * device);
+-static void dasd_setup_queue(struct dasd_device * device);
+-static void dasd_free_queue(struct dasd_device * device);
+-static void dasd_flush_request_queue(struct dasd_device *);
+-static int dasd_flush_ccw_queue(struct dasd_device *, int);
+-static void dasd_tasklet(struct dasd_device *);
++static int  dasd_alloc_queue(struct dasd_block *);
++static void dasd_setup_queue(struct dasd_block *);
++static void dasd_free_queue(struct dasd_block *);
++static void dasd_flush_request_queue(struct dasd_block *);
++static int dasd_flush_block_queue(struct dasd_block *);
++static void dasd_device_tasklet(struct dasd_device *);
++static void dasd_block_tasklet(struct dasd_block *);
+ static void do_kick_device(struct work_struct *);
++static void dasd_return_cqr_cb(struct dasd_ccw_req *, void *);
  
--	MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);
-+	MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
+ /*
+  * SECTION: Operations on the device structure.
+@@ -65,26 +67,23 @@ static wait_queue_head_t dasd_flush_wq;
+ /*
+  * Allocate memory for a new device structure.
+  */
+-struct dasd_device *
+-dasd_alloc_device(void)
++struct dasd_device *dasd_alloc_device(void)
+ {
+ 	struct dasd_device *device;
  
- 	mutex_lock(&q->lock);
- 	retval = -EBUSY;
- 	if (q->reading) {
--		dprintk(1,"dqbuf: Reading running...\n");
-+		dprintk(1, "dqbuf: Reading running...\n");
- 		goto done;
- 	}
- 	retval = -EINVAL;
- 	if (b->type != q->type) {
--		dprintk(1,"dqbuf: Wrong type.\n");
-+		dprintk(1, "dqbuf: Wrong type.\n");
- 		goto done;
- 	}
- 	if (list_empty(&q->stream)) {
--		dprintk(1,"dqbuf: stream running\n");
-+		dprintk(1, "dqbuf: stream running\n");
- 		goto done;
- 	}
- 	buf = list_entry(q->stream.next, struct videobuf_buffer, stream);
- 	retval = videobuf_waiton(buf, nonblocking, 1);
- 	if (retval < 0) {
--		dprintk(1,"dqbuf: waiton returned %d\n",retval);
-+		dprintk(1, "dqbuf: waiton returned %d\n", retval);
- 		goto done;
- 	}
- 	switch (buf->state) {
--	case STATE_ERROR:
--		dprintk(1,"dqbuf: state is error\n");
-+	case VIDEOBUF_ERROR:
-+		dprintk(1, "dqbuf: state is error\n");
- 		retval = -EIO;
--		CALL(q,sync,q, buf);
--		buf->state = STATE_IDLE;
-+		CALL(q, sync, q, buf);
-+		buf->state = VIDEOBUF_IDLE;
- 		break;
--	case STATE_DONE:
--		dprintk(1,"dqbuf: state is done\n");
--		CALL(q,sync,q, buf);
--		buf->state = STATE_IDLE;
-+	case VIDEOBUF_DONE:
-+		dprintk(1, "dqbuf: state is done\n");
-+		CALL(q, sync, q, buf);
-+		buf->state = VIDEOBUF_IDLE;
- 		break;
- 	default:
--		dprintk(1,"dqbuf: state invalid\n");
-+		dprintk(1, "dqbuf: state invalid\n");
- 		retval = -EINVAL;
- 		goto done;
+-	device = kzalloc(sizeof (struct dasd_device), GFP_ATOMIC);
+-	if (device == NULL)
++	device = kzalloc(sizeof(struct dasd_device), GFP_ATOMIC);
++	if (!device)
+ 		return ERR_PTR(-ENOMEM);
+-	/* open_count = 0 means device online but not in use */
+-	atomic_set(&device->open_count, -1);
+ 
+ 	/* Get two pages for normal block device operations. */
+ 	device->ccw_mem = (void *) __get_free_pages(GFP_ATOMIC | GFP_DMA, 1);
+-	if (device->ccw_mem == NULL) {
++	if (!device->ccw_mem) {
+ 		kfree(device);
+ 		return ERR_PTR(-ENOMEM);
  	}
- 	list_del(&buf->stream);
--	memset(b,0,sizeof(*b));
--	videobuf_status(q,b,buf,q->type);
-+	memset(b, 0, sizeof(*b));
-+	videobuf_status(q, b, buf, q->type);
+ 	/* Get one page for error recovery. */
+ 	device->erp_mem = (void *) get_zeroed_page(GFP_ATOMIC | GFP_DMA);
+-	if (device->erp_mem == NULL) {
++	if (!device->erp_mem) {
+ 		free_pages((unsigned long) device->ccw_mem, 1);
+ 		kfree(device);
+ 		return ERR_PTR(-ENOMEM);
+@@ -93,10 +92,9 @@ dasd_alloc_device(void)
+ 	dasd_init_chunklist(&device->ccw_chunks, device->ccw_mem, PAGE_SIZE*2);
+ 	dasd_init_chunklist(&device->erp_chunks, device->erp_mem, PAGE_SIZE);
+ 	spin_lock_init(&device->mem_lock);
+-	spin_lock_init(&device->request_queue_lock);
+-	atomic_set (&device->tasklet_scheduled, 0);
++	atomic_set(&device->tasklet_scheduled, 0);
+ 	tasklet_init(&device->tasklet,
+-		     (void (*)(unsigned long)) dasd_tasklet,
++		     (void (*)(unsigned long)) dasd_device_tasklet,
+ 		     (unsigned long) device);
+ 	INIT_LIST_HEAD(&device->ccw_queue);
+ 	init_timer(&device->timer);
+@@ -110,8 +108,7 @@ dasd_alloc_device(void)
+ /*
+  * Free memory of a device structure.
+  */
+-void
+-dasd_free_device(struct dasd_device *device)
++void dasd_free_device(struct dasd_device *device)
+ {
+ 	kfree(device->private);
+ 	free_page((unsigned long) device->erp_mem);
+@@ -120,10 +117,42 @@ dasd_free_device(struct dasd_device *device)
+ }
  
-  done:
- 	mutex_unlock(&q->lock);
-@@ -623,7 +639,7 @@ int videobuf_dqbuf(struct videobuf_queue *q,
- int videobuf_streamon(struct videobuf_queue *q)
+ /*
++ * Allocate memory for a new device structure.
++ */
++struct dasd_block *dasd_alloc_block(void)
++{
++	struct dasd_block *block;
++
++	block = kzalloc(sizeof(*block), GFP_ATOMIC);
++	if (!block)
++		return ERR_PTR(-ENOMEM);
++	/* open_count = 0 means device online but not in use */
++	atomic_set(&block->open_count, -1);
++
++	spin_lock_init(&block->request_queue_lock);
++	atomic_set(&block->tasklet_scheduled, 0);
++	tasklet_init(&block->tasklet,
++		     (void (*)(unsigned long)) dasd_block_tasklet,
++		     (unsigned long) block);
++	INIT_LIST_HEAD(&block->ccw_queue);
++	spin_lock_init(&block->queue_lock);
++	init_timer(&block->timer);
++
++	return block;
++}
++
++/*
++ * Free memory of a device structure.
++ */
++void dasd_free_block(struct dasd_block *block)
++{
++	kfree(block);
++}
++
++/*
+  * Make a new device known to the system.
+  */
+-static int
+-dasd_state_new_to_known(struct dasd_device *device)
++static int dasd_state_new_to_known(struct dasd_device *device)
  {
- 	struct videobuf_buffer *buf;
--	unsigned long flags=0;
-+	unsigned long flags = 0;
- 	int retval;
+ 	int rc;
  
- 	mutex_lock(&q->lock);
-@@ -635,12 +651,12 @@ int videobuf_streamon(struct videobuf_queue *q)
- 		goto done;
- 	q->streaming = 1;
- 	if (q->irqlock)
--		spin_lock_irqsave(q->irqlock,flags);
-+		spin_lock_irqsave(q->irqlock, flags);
- 	list_for_each_entry(buf, &q->stream, stream)
--		if (buf->state == STATE_PREPARED)
--			q->ops->buf_queue(q,buf);
-+		if (buf->state == VIDEOBUF_PREPARED)
-+			q->ops->buf_queue(q, buf);
- 	if (q->irqlock)
--		spin_unlock_irqrestore(q->irqlock,flags);
-+		spin_unlock_irqrestore(q->irqlock, flags);
+@@ -133,12 +162,13 @@ dasd_state_new_to_known(struct dasd_device *device)
+ 	 */
+ 	dasd_get_device(device);
  
-  done:
- 	mutex_unlock(&q->lock);
-@@ -676,10 +692,10 @@ static ssize_t videobuf_read_zerocopy(struct videobuf_queue *q,
- 				      size_t count, loff_t *ppos)
+-	rc = dasd_alloc_queue(device);
+-	if (rc) {
+-		dasd_put_device(device);
+-		return rc;
++	if (device->block) {
++		rc = dasd_alloc_queue(device->block);
++		if (rc) {
++			dasd_put_device(device);
++			return rc;
++		}
+ 	}
+-
+ 	device->state = DASD_STATE_KNOWN;
+ 	return 0;
+ }
+@@ -146,21 +176,24 @@ dasd_state_new_to_known(struct dasd_device *device)
+ /*
+  * Let the system forget about a device.
+  */
+-static int
+-dasd_state_known_to_new(struct dasd_device * device)
++static int dasd_state_known_to_new(struct dasd_device *device)
  {
- 	enum v4l2_field field;
--	unsigned long flags=0;
-+	unsigned long flags = 0;
- 	int retval;
+ 	/* Disable extended error reporting for this device. */
+ 	dasd_eer_disable(device);
+ 	/* Forget the discipline information. */
+-	if (device->discipline)
++	if (device->discipline) {
++		if (device->discipline->uncheck_device)
++			device->discipline->uncheck_device(device);
+ 		module_put(device->discipline->owner);
++	}
+ 	device->discipline = NULL;
+ 	if (device->base_discipline)
+ 		module_put(device->base_discipline->owner);
+ 	device->base_discipline = NULL;
+ 	device->state = DASD_STATE_NEW;
  
--	MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);
-+	MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
+-	dasd_free_queue(device);
++	if (device->block)
++		dasd_free_queue(device->block);
  
- 	/* setup stuff */
- 	q->read_buf = videobuf_alloc(q);
-@@ -691,20 +707,20 @@ static ssize_t videobuf_read_zerocopy(struct videobuf_queue *q,
- 	q->read_buf->bsize  = count;
+ 	/* Give up reference we took in dasd_state_new_to_known. */
+ 	dasd_put_device(device);
+@@ -170,19 +203,19 @@ dasd_state_known_to_new(struct dasd_device * device)
+ /*
+  * Request the irq line for the device.
+  */
+-static int
+-dasd_state_known_to_basic(struct dasd_device * device)
++static int dasd_state_known_to_basic(struct dasd_device *device)
+ {
+ 	int rc;
  
- 	field = videobuf_next_field(q);
--	retval = q->ops->buf_prepare(q,q->read_buf,field);
-+	retval = q->ops->buf_prepare(q, q->read_buf, field);
- 	if (0 != retval)
- 		goto done;
+ 	/* Allocate and register gendisk structure. */
+-	rc = dasd_gendisk_alloc(device);
+-	if (rc)
+-		return rc;
+-
++	if (device->block) {
++		rc = dasd_gendisk_alloc(device->block);
++		if (rc)
++			return rc;
++	}
+ 	/* register 'device' debug area, used for all DBF_DEV_XXX calls */
+-	device->debug_area = debug_register(device->cdev->dev.bus_id, 1, 2,
+-					    8 * sizeof (long));
++	device->debug_area = debug_register(device->cdev->dev.bus_id, 1, 1,
++					    8 * sizeof(long));
+ 	debug_register_view(device->debug_area, &debug_sprintf_view);
+ 	debug_set_level(device->debug_area, DBF_WARNING);
+ 	DBF_DEV_EVENT(DBF_EMERG, device, "%s", "debug area created");
+@@ -194,16 +227,17 @@ dasd_state_known_to_basic(struct dasd_device * device)
+ /*
+  * Release the irq line for the device. Terminate any running i/o.
+  */
+-static int
+-dasd_state_basic_to_known(struct dasd_device * device)
++static int dasd_state_basic_to_known(struct dasd_device *device)
+ {
+ 	int rc;
+-
+-	dasd_gendisk_free(device);
+-	rc = dasd_flush_ccw_queue(device, 1);
++	if (device->block) {
++		dasd_gendisk_free(device->block);
++		dasd_block_clear_timer(device->block);
++	}
++	rc = dasd_flush_device_queue(device);
+ 	if (rc)
+ 		return rc;
+-	dasd_clear_timer(device);
++	dasd_device_clear_timer(device);
  
- 	/* start capture & wait */
- 	if (q->irqlock)
--		spin_lock_irqsave(q->irqlock,flags);
--	q->ops->buf_queue(q,q->read_buf);
-+		spin_lock_irqsave(q->irqlock, flags);
-+	q->ops->buf_queue(q, q->read_buf);
- 	if (q->irqlock)
--		spin_unlock_irqrestore(q->irqlock,flags);
--	retval = videobuf_waiton(q->read_buf,0,0);
-+		spin_unlock_irqrestore(q->irqlock, flags);
-+	retval = videobuf_waiton(q->read_buf, 0, 0);
- 	if (0 == retval) {
--		CALL(q,sync,q,q->read_buf);
--		if (STATE_ERROR == q->read_buf->state)
-+		CALL(q, sync, q, q->read_buf);
-+		if (VIDEOBUF_ERROR == q->read_buf->state)
- 			retval = -EIO;
- 		else
- 			retval = q->read_buf->size;
-@@ -712,7 +728,7 @@ static ssize_t videobuf_read_zerocopy(struct videobuf_queue *q,
+ 	DBF_DEV_EVENT(DBF_EMERG, device, "%p debug area deleted", device);
+ 	if (device->debug_area != NULL) {
+@@ -228,26 +262,32 @@ dasd_state_basic_to_known(struct dasd_device * device)
+  * In case the analysis returns an error, the device setup is stopped
+  * (a fake disk was already added to allow formatting).
+  */
+-static int
+-dasd_state_basic_to_ready(struct dasd_device * device)
++static int dasd_state_basic_to_ready(struct dasd_device *device)
+ {
+ 	int rc;
++	struct dasd_block *block;
  
-  done:
- 	/* cleanup */
--	q->ops->buf_release(q,q->read_buf);
-+	q->ops->buf_release(q, q->read_buf);
- 	kfree(q->read_buf);
- 	q->read_buf = NULL;
- 	return retval;
-@@ -723,21 +739,21 @@ ssize_t videobuf_read_one(struct videobuf_queue *q,
- 			  int nonblocking)
+ 	rc = 0;
+-	if (device->discipline->do_analysis != NULL)
+-		rc = device->discipline->do_analysis(device);
+-	if (rc) {
+-		if (rc != -EAGAIN)
+-			device->state = DASD_STATE_UNFMT;
+-		return rc;
+-	}
++	block = device->block;
+ 	/* make disk known with correct capacity */
+-	dasd_setup_queue(device);
+-	set_capacity(device->gdp, device->blocks << device->s2b_shift);
+-	device->state = DASD_STATE_READY;
+-	rc = dasd_scan_partitions(device);
+-	if (rc)
+-		device->state = DASD_STATE_BASIC;
++	if (block) {
++		if (block->base->discipline->do_analysis != NULL)
++			rc = block->base->discipline->do_analysis(block);
++		if (rc) {
++			if (rc != -EAGAIN)
++				device->state = DASD_STATE_UNFMT;
++			return rc;
++		}
++		dasd_setup_queue(block);
++		set_capacity(block->gdp,
++			     block->blocks << block->s2b_shift);
++		device->state = DASD_STATE_READY;
++		rc = dasd_scan_partitions(block);
++		if (rc)
++			device->state = DASD_STATE_BASIC;
++	} else {
++		device->state = DASD_STATE_READY;
++	}
+ 	return rc;
+ }
+ 
+@@ -256,28 +296,31 @@ dasd_state_basic_to_ready(struct dasd_device * device)
+  * Forget format information. Check if the target level is basic
+  * and if it is create fake disk for formatting.
+  */
+-static int
+-dasd_state_ready_to_basic(struct dasd_device * device)
++static int dasd_state_ready_to_basic(struct dasd_device *device)
  {
- 	enum v4l2_field field;
--	unsigned long flags=0;
-+	unsigned long flags = 0;
- 	unsigned size, nbufs;
- 	int retval;
+ 	int rc;
  
--	MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);
-+	MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
+-	rc = dasd_flush_ccw_queue(device, 0);
+-	if (rc)
+-		return rc;
+-	dasd_destroy_partitions(device);
+-	dasd_flush_request_queue(device);
+-	device->blocks = 0;
+-	device->bp_block = 0;
+-	device->s2b_shift = 0;
+ 	device->state = DASD_STATE_BASIC;
++	if (device->block) {
++		struct dasd_block *block = device->block;
++		rc = dasd_flush_block_queue(block);
++		if (rc) {
++			device->state = DASD_STATE_READY;
++			return rc;
++		}
++		dasd_destroy_partitions(block);
++		dasd_flush_request_queue(block);
++		block->blocks = 0;
++		block->bp_block = 0;
++		block->s2b_shift = 0;
++	}
+ 	return 0;
+ }
  
- 	mutex_lock(&q->lock);
+ /*
+  * Back to basic.
+  */
+-static int
+-dasd_state_unfmt_to_basic(struct dasd_device * device)
++static int dasd_state_unfmt_to_basic(struct dasd_device *device)
+ {
+ 	device->state = DASD_STATE_BASIC;
+ 	return 0;
+@@ -291,17 +334,31 @@ dasd_state_unfmt_to_basic(struct dasd_device * device)
+ static int
+ dasd_state_ready_to_online(struct dasd_device * device)
+ {
++	int rc;
++
++	if (device->discipline->ready_to_online) {
++		rc = device->discipline->ready_to_online(device);
++		if (rc)
++			return rc;
++	}
+ 	device->state = DASD_STATE_ONLINE;
+-	dasd_schedule_bh(device);
++	if (device->block)
++		dasd_schedule_block_bh(device->block);
+ 	return 0;
+ }
  
- 	nbufs = 1; size = 0;
--	q->ops->buf_setup(q,&nbufs,&size);
-+	q->ops->buf_setup(q, &nbufs, &size);
+ /*
+  * Stop the requeueing of requests again.
+  */
+-static int
+-dasd_state_online_to_ready(struct dasd_device * device)
++static int dasd_state_online_to_ready(struct dasd_device *device)
+ {
++	int rc;
++
++	if (device->discipline->online_to_ready) {
++		rc = device->discipline->online_to_ready(device);
++		if (rc)
++			return rc;
++	}
+ 	device->state = DASD_STATE_READY;
+ 	return 0;
+ }
+@@ -309,8 +366,7 @@ dasd_state_online_to_ready(struct dasd_device * device)
+ /*
+  * Device startup state changes.
+  */
+-static int
+-dasd_increase_state(struct dasd_device *device)
++static int dasd_increase_state(struct dasd_device *device)
+ {
+ 	int rc;
  
- 	if (NULL == q->read_buf  &&
- 	    count >= size        &&
- 	    !nonblocking) {
--		retval = videobuf_read_zerocopy(q,data,count,ppos);
-+		retval = videobuf_read_zerocopy(q, data, count, ppos);
- 		if (retval >= 0  ||  retval == -EIO)
- 			/* ok, all done */
- 			goto done;
-@@ -749,25 +765,25 @@ ssize_t videobuf_read_one(struct videobuf_queue *q,
- 		retval = -ENOMEM;
- 		q->read_buf = videobuf_alloc(q);
+@@ -345,8 +401,7 @@ dasd_increase_state(struct dasd_device *device)
+ /*
+  * Device shutdown state changes.
+  */
+-static int
+-dasd_decrease_state(struct dasd_device *device)
++static int dasd_decrease_state(struct dasd_device *device)
+ {
+ 	int rc;
  
--		dprintk(1,"video alloc=0x%p\n", q->read_buf);
-+		dprintk(1, "video alloc=0x%p\n", q->read_buf);
- 		if (NULL == q->read_buf)
- 			goto done;
- 		q->read_buf->memory = V4L2_MEMORY_USERPTR;
- 		q->read_buf->bsize = count; /* preferred size */
- 		field = videobuf_next_field(q);
--		retval = q->ops->buf_prepare(q,q->read_buf,field);
-+		retval = q->ops->buf_prepare(q, q->read_buf, field);
+@@ -381,8 +436,7 @@ dasd_decrease_state(struct dasd_device *device)
+ /*
+  * This is the main startup/shutdown routine.
+  */
+-static void
+-dasd_change_state(struct dasd_device *device)
++static void dasd_change_state(struct dasd_device *device)
+ {
+         int rc;
  
- 		if (0 != retval) {
--			kfree (q->read_buf);
-+			kfree(q->read_buf);
- 			q->read_buf = NULL;
- 			goto done;
- 		}
- 		if (q->irqlock)
--			spin_lock_irqsave(q->irqlock,flags);
-+			spin_lock_irqsave(q->irqlock, flags);
+@@ -409,17 +463,15 @@ dasd_change_state(struct dasd_device *device)
+  * dasd_kick_device will schedule a call do do_kick_device to the kernel
+  * event daemon.
+  */
+-static void
+-do_kick_device(struct work_struct *work)
++static void do_kick_device(struct work_struct *work)
+ {
+ 	struct dasd_device *device = container_of(work, struct dasd_device, kick_work);
+ 	dasd_change_state(device);
+-	dasd_schedule_bh(device);
++	dasd_schedule_device_bh(device);
+ 	dasd_put_device(device);
+ }
  
--		q->ops->buf_queue(q,q->read_buf);
-+		q->ops->buf_queue(q, q->read_buf);
- 		if (q->irqlock)
--			spin_unlock_irqrestore(q->irqlock,flags);
-+			spin_unlock_irqrestore(q->irqlock, flags);
- 		q->read_off = 0;
- 	}
+-void
+-dasd_kick_device(struct dasd_device *device)
++void dasd_kick_device(struct dasd_device *device)
+ {
+ 	dasd_get_device(device);
+ 	/* queue call to dasd_kick_device to the kernel event daemon. */
+@@ -429,8 +481,7 @@ dasd_kick_device(struct dasd_device *device)
+ /*
+  * Set the target state for a device and starts the state change.
+  */
+-void
+-dasd_set_target_state(struct dasd_device *device, int target)
++void dasd_set_target_state(struct dasd_device *device, int target)
+ {
+ 	/* If we are in probeonly mode stop at DASD_STATE_READY. */
+ 	if (dasd_probeonly && target > DASD_STATE_READY)
+@@ -447,14 +498,12 @@ dasd_set_target_state(struct dasd_device *device, int target)
+ /*
+  * Enable devices with device numbers in [from..to].
+  */
+-static inline int
+-_wait_for_device(struct dasd_device *device)
++static inline int _wait_for_device(struct dasd_device *device)
+ {
+ 	return (device->state == device->target);
+ }
  
-@@ -776,11 +792,11 @@ ssize_t videobuf_read_one(struct videobuf_queue *q,
- 	if (0 != retval)
- 		goto done;
+-void
+-dasd_enable_device(struct dasd_device *device)
++void dasd_enable_device(struct dasd_device *device)
+ {
+ 	dasd_set_target_state(device, DASD_STATE_ONLINE);
+ 	if (device->state <= DASD_STATE_KNOWN)
+@@ -475,20 +524,20 @@ unsigned int dasd_profile_level = DASD_PROFILE_OFF;
+ /*
+  * Increments counter in global and local profiling structures.
+  */
+-#define dasd_profile_counter(value, counter, device) \
++#define dasd_profile_counter(value, counter, block) \
+ { \
+ 	int index; \
+ 	for (index = 0; index < 31 && value >> (2+index); index++); \
+ 	dasd_global_profile.counter[index]++; \
+-	device->profile.counter[index]++; \
++	block->profile.counter[index]++; \
+ }
  
--	CALL(q,sync,q,q->read_buf);
-+	CALL(q, sync, q, q->read_buf);
+ /*
+  * Add profiling information for cqr before execution.
+  */
+-static void
+-dasd_profile_start(struct dasd_device *device, struct dasd_ccw_req * cqr,
+-		   struct request *req)
++static void dasd_profile_start(struct dasd_block *block,
++			       struct dasd_ccw_req *cqr,
++			       struct request *req)
+ {
+ 	struct list_head *l;
+ 	unsigned int counter;
+@@ -498,19 +547,19 @@ dasd_profile_start(struct dasd_device *device, struct dasd_ccw_req * cqr,
  
--	if (STATE_ERROR == q->read_buf->state) {
-+	if (VIDEOBUF_ERROR == q->read_buf->state) {
- 		/* catch I/O errors */
--		q->ops->buf_release(q,q->read_buf);
-+		q->ops->buf_release(q, q->read_buf);
- 		kfree(q->read_buf);
- 		q->read_buf = NULL;
- 		retval = -EIO;
-@@ -788,14 +804,14 @@ ssize_t videobuf_read_one(struct videobuf_queue *q,
- 	}
+ 	/* count the length of the chanq for statistics */
+ 	counter = 0;
+-	list_for_each(l, &device->ccw_queue)
++	list_for_each(l, &block->ccw_queue)
+ 		if (++counter >= 31)
+ 			break;
+ 	dasd_global_profile.dasd_io_nr_req[counter]++;
+-	device->profile.dasd_io_nr_req[counter]++;
++	block->profile.dasd_io_nr_req[counter]++;
+ }
  
- 	/* Copy to userspace */
--	retval=CALL(q,video_copy_to_user,q,data,count,nonblocking);
--	if (retval<0)
-+	retval = CALL(q, video_copy_to_user, q, data, count, nonblocking);
-+	if (retval < 0)
- 		goto done;
+ /*
+  * Add profiling information for cqr after execution.
+  */
+-static void
+-dasd_profile_end(struct dasd_device *device, struct dasd_ccw_req * cqr,
+-		 struct request *req)
++static void dasd_profile_end(struct dasd_block *block,
++			     struct dasd_ccw_req *cqr,
++			     struct request *req)
+ {
+ 	long strtime, irqtime, endtime, tottime;	/* in microseconds */
+ 	long tottimeps, sectors;
+@@ -532,27 +581,27 @@ dasd_profile_end(struct dasd_device *device, struct dasd_ccw_req * cqr,
+ 
+ 	if (!dasd_global_profile.dasd_io_reqs)
+ 		memset(&dasd_global_profile, 0,
+-		       sizeof (struct dasd_profile_info_t));
++		       sizeof(struct dasd_profile_info_t));
+ 	dasd_global_profile.dasd_io_reqs++;
+ 	dasd_global_profile.dasd_io_sects += sectors;
+ 
+-	if (!device->profile.dasd_io_reqs)
+-		memset(&device->profile, 0,
+-		       sizeof (struct dasd_profile_info_t));
+-	device->profile.dasd_io_reqs++;
+-	device->profile.dasd_io_sects += sectors;
++	if (!block->profile.dasd_io_reqs)
++		memset(&block->profile, 0,
++		       sizeof(struct dasd_profile_info_t));
++	block->profile.dasd_io_reqs++;
++	block->profile.dasd_io_sects += sectors;
  
- 	q->read_off += retval;
- 	if (q->read_off == q->read_buf->size) {
- 		/* all data copied, cleanup */
--		q->ops->buf_release(q,q->read_buf);
-+		q->ops->buf_release(q, q->read_buf);
- 		kfree(q->read_buf);
- 		q->read_buf = NULL;
- 	}
-@@ -806,14 +822,14 @@ ssize_t videobuf_read_one(struct videobuf_queue *q,
+-	dasd_profile_counter(sectors, dasd_io_secs, device);
+-	dasd_profile_counter(tottime, dasd_io_times, device);
+-	dasd_profile_counter(tottimeps, dasd_io_timps, device);
+-	dasd_profile_counter(strtime, dasd_io_time1, device);
+-	dasd_profile_counter(irqtime, dasd_io_time2, device);
+-	dasd_profile_counter(irqtime / sectors, dasd_io_time2ps, device);
+-	dasd_profile_counter(endtime, dasd_io_time3, device);
++	dasd_profile_counter(sectors, dasd_io_secs, block);
++	dasd_profile_counter(tottime, dasd_io_times, block);
++	dasd_profile_counter(tottimeps, dasd_io_timps, block);
++	dasd_profile_counter(strtime, dasd_io_time1, block);
++	dasd_profile_counter(irqtime, dasd_io_time2, block);
++	dasd_profile_counter(irqtime / sectors, dasd_io_time2ps, block);
++	dasd_profile_counter(endtime, dasd_io_time3, block);
  }
+ #else
+-#define dasd_profile_start(device, cqr, req) do {} while (0)
+-#define dasd_profile_end(device, cqr, req) do {} while (0)
++#define dasd_profile_start(block, cqr, req) do {} while (0)
++#define dasd_profile_end(block, cqr, req) do {} while (0)
+ #endif				/* CONFIG_DASD_PROFILE */
  
- /* Locking: Caller holds q->lock */
--int __videobuf_read_start(struct videobuf_queue *q)
-+static int __videobuf_read_start(struct videobuf_queue *q)
+ /*
+@@ -562,9 +611,9 @@ dasd_profile_end(struct dasd_device *device, struct dasd_ccw_req * cqr,
+  * memory and 2) dasd_smalloc_request uses the static ccw memory
+  * that gets allocated for each device.
+  */
+-struct dasd_ccw_req *
+-dasd_kmalloc_request(char *magic, int cplength, int datasize,
+-		   struct dasd_device * device)
++struct dasd_ccw_req *dasd_kmalloc_request(char *magic, int cplength,
++					  int datasize,
++					  struct dasd_device *device)
  {
- 	enum v4l2_field field;
--	unsigned long flags=0;
-+	unsigned long flags = 0;
- 	unsigned int count = 0, size = 0;
- 	int err, i;
- 
--	q->ops->buf_setup(q,&count,&size);
-+	q->ops->buf_setup(q, &count, &size);
- 	if (count < 2)
- 		count = 2;
- 	if (count > VIDEO_MAX_FRAME)
-@@ -828,17 +844,17 @@ int __videobuf_read_start(struct videobuf_queue *q)
+ 	struct dasd_ccw_req *cqr;
  
- 	for (i = 0; i < count; i++) {
- 		field = videobuf_next_field(q);
--		err = q->ops->buf_prepare(q,q->bufs[i],field);
-+		err = q->ops->buf_prepare(q, q->bufs[i], field);
- 		if (err)
- 			return err;
- 		list_add_tail(&q->bufs[i]->stream, &q->stream);
- 	}
- 	if (q->irqlock)
--		spin_lock_irqsave(q->irqlock,flags);
-+		spin_lock_irqsave(q->irqlock, flags);
- 	for (i = 0; i < count; i++)
--		q->ops->buf_queue(q,q->bufs[i]);
-+		q->ops->buf_queue(q, q->bufs[i]);
- 	if (q->irqlock)
--		spin_unlock_irqrestore(q->irqlock,flags);
-+		spin_unlock_irqrestore(q->irqlock, flags);
- 	q->reading = 1;
- 	return 0;
- }
-@@ -859,7 +875,7 @@ static void __videobuf_read_stop(struct videobuf_queue *q)
- 	}
- 	q->read_buf = NULL;
- 	q->reading  = 0;
--	
-+
+@@ -600,9 +649,9 @@ dasd_kmalloc_request(char *magic, int cplength, int datasize,
+ 	return cqr;
  }
  
- int videobuf_read_start(struct videobuf_queue *q)
-@@ -899,11 +915,11 @@ ssize_t videobuf_read_stream(struct videobuf_queue *q,
- 			     int vbihack, int nonblocking)
+-struct dasd_ccw_req *
+-dasd_smalloc_request(char *magic, int cplength, int datasize,
+-		   struct dasd_device * device)
++struct dasd_ccw_req *dasd_smalloc_request(char *magic, int cplength,
++					  int datasize,
++					  struct dasd_device *device)
  {
- 	int rc, retval;
--	unsigned long flags=0;
-+	unsigned long flags = 0;
+ 	unsigned long flags;
+ 	struct dasd_ccw_req *cqr;
+@@ -649,8 +698,7 @@ dasd_smalloc_request(char *magic, int cplength, int datasize,
+  * idal lists that might have been created by dasd_set_cda and the
+  * struct dasd_ccw_req itself.
+  */
+-void
+-dasd_kfree_request(struct dasd_ccw_req * cqr, struct dasd_device * device)
++void dasd_kfree_request(struct dasd_ccw_req *cqr, struct dasd_device *device)
+ {
+ #ifdef CONFIG_64BIT
+ 	struct ccw1 *ccw;
+@@ -667,8 +715,7 @@ dasd_kfree_request(struct dasd_ccw_req * cqr, struct dasd_device * device)
+ 	dasd_put_device(device);
+ }
  
--	MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);
-+	MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
+-void
+-dasd_sfree_request(struct dasd_ccw_req * cqr, struct dasd_device * device)
++void dasd_sfree_request(struct dasd_ccw_req *cqr, struct dasd_device *device)
+ {
+ 	unsigned long flags;
  
--	dprintk(2,"%s\n",__FUNCTION__);
-+	dprintk(2, "%s\n", __FUNCTION__);
- 	mutex_lock(&q->lock);
- 	retval = -EBUSY;
- 	if (q->streaming)
-@@ -931,8 +947,8 @@ ssize_t videobuf_read_stream(struct videobuf_queue *q,
- 			break;
- 		}
+@@ -681,14 +728,13 @@ dasd_sfree_request(struct dasd_ccw_req * cqr, struct dasd_device * device)
+ /*
+  * Check discipline magic in cqr.
+  */
+-static inline int
+-dasd_check_cqr(struct dasd_ccw_req *cqr)
++static inline int dasd_check_cqr(struct dasd_ccw_req *cqr)
+ {
+ 	struct dasd_device *device;
  
--		if (q->read_buf->state == STATE_DONE) {
--			rc = CALL (q,copy_stream, q, data + retval, count,
-+		if (q->read_buf->state == VIDEOBUF_DONE) {
-+			rc = CALL(q, copy_stream, q, data + retval, count,
- 					retval, vbihack, nonblocking);
- 			if (rc < 0) {
- 				retval = rc;
-@@ -953,10 +969,10 @@ ssize_t videobuf_read_stream(struct videobuf_queue *q,
- 			list_add_tail(&q->read_buf->stream,
- 				      &q->stream);
- 			if (q->irqlock)
--				spin_lock_irqsave(q->irqlock,flags);
--			q->ops->buf_queue(q,q->read_buf);
-+				spin_lock_irqsave(q->irqlock, flags);
-+			q->ops->buf_queue(q, q->read_buf);
- 			if (q->irqlock)
--				spin_unlock_irqrestore(q->irqlock,flags);
-+				spin_unlock_irqrestore(q->irqlock, flags);
- 			q->read_buf = NULL;
+ 	if (cqr == NULL)
+ 		return -EINVAL;
+-	device = cqr->device;
++	device = cqr->startdev;
+ 	if (strncmp((char *) &cqr->magic, device->discipline->ebcname, 4)) {
+ 		DEV_MESSAGE(KERN_WARNING, device,
+ 			    " dasd_ccw_req 0x%08x magic doesn't match"
+@@ -706,8 +752,7 @@ dasd_check_cqr(struct dasd_ccw_req *cqr)
+  * ccw_device_clear can fail if the i/o subsystem
+  * is in a bad mood.
+  */
+-int
+-dasd_term_IO(struct dasd_ccw_req * cqr)
++int dasd_term_IO(struct dasd_ccw_req *cqr)
+ {
+ 	struct dasd_device *device;
+ 	int retries, rc;
+@@ -717,13 +762,13 @@ dasd_term_IO(struct dasd_ccw_req * cqr)
+ 	if (rc)
+ 		return rc;
+ 	retries = 0;
+-	device = (struct dasd_device *) cqr->device;
++	device = (struct dasd_device *) cqr->startdev;
+ 	while ((retries < 5) && (cqr->status == DASD_CQR_IN_IO)) {
+ 		rc = ccw_device_clear(device->cdev, (long) cqr);
+ 		switch (rc) {
+ 		case 0:	/* termination successful */
+ 			cqr->retries--;
+-			cqr->status = DASD_CQR_CLEAR;
++			cqr->status = DASD_CQR_CLEAR_PENDING;
+ 			cqr->stopclk = get_clock();
+ 			cqr->starttime = 0;
+ 			DBF_DEV_EVENT(DBF_DEBUG, device,
+@@ -753,7 +798,7 @@ dasd_term_IO(struct dasd_ccw_req * cqr)
  		}
- 		if (retval < 0)
-@@ -999,8 +1015,8 @@ unsigned int videobuf_poll_stream(struct file *file,
+ 		retries++;
+ 	}
+-	dasd_schedule_bh(device);
++	dasd_schedule_device_bh(device);
+ 	return rc;
+ }
  
- 	if (0 == rc) {
- 		poll_wait(file, &buf->done, wait);
--		if (buf->state == STATE_DONE ||
--		    buf->state == STATE_ERROR)
-+		if (buf->state == VIDEOBUF_DONE ||
-+		    buf->state == VIDEOBUF_ERROR)
- 			rc = POLLIN|POLLRDNORM;
+@@ -761,8 +806,7 @@ dasd_term_IO(struct dasd_ccw_req * cqr)
+  * Start the i/o. This start_IO can fail if the channel is really busy.
+  * In that case set up a timer to start the request later.
+  */
+-int
+-dasd_start_IO(struct dasd_ccw_req * cqr)
++int dasd_start_IO(struct dasd_ccw_req *cqr)
+ {
+ 	struct dasd_device *device;
+ 	int rc;
+@@ -771,12 +815,12 @@ dasd_start_IO(struct dasd_ccw_req * cqr)
+ 	rc = dasd_check_cqr(cqr);
+ 	if (rc)
+ 		return rc;
+-	device = (struct dasd_device *) cqr->device;
++	device = (struct dasd_device *) cqr->startdev;
+ 	if (cqr->retries < 0) {
+ 		DEV_MESSAGE(KERN_DEBUG, device,
+ 			    "start_IO: request %p (%02x/%i) - no retry left.",
+ 			    cqr, cqr->status, cqr->retries);
+-		cqr->status = DASD_CQR_FAILED;
++		cqr->status = DASD_CQR_ERROR;
+ 		return -EIO;
  	}
- 	mutex_unlock(&q->lock);
-@@ -1012,10 +1028,11 @@ int videobuf_mmap_mapper(struct videobuf_queue *q,
+ 	cqr->startclk = get_clock();
+@@ -833,8 +877,7 @@ dasd_start_IO(struct dasd_ccw_req * cqr)
+  * The head of the ccw queue will have status DASD_CQR_IN_IO for 1),
+  * DASD_CQR_QUEUED for 2) and 3).
+  */
+-static void
+-dasd_timeout_device(unsigned long ptr)
++static void dasd_device_timeout(unsigned long ptr)
  {
- 	int retval;
- 
--	MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);
-+	MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
+ 	unsigned long flags;
+ 	struct dasd_device *device;
+@@ -844,14 +887,13 @@ dasd_timeout_device(unsigned long ptr)
+ 	/* re-activate request queue */
+         device->stopped &= ~DASD_STOPPED_PENDING;
+ 	spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
+-	dasd_schedule_bh(device);
++	dasd_schedule_device_bh(device);
+ }
  
- 	mutex_lock(&q->lock);
--	retval=CALL(q,mmap_mapper,q,vma);
-+	retval = CALL(q, mmap_mapper, q, vma);
-+	q->is_mmapped = 1;
- 	mutex_unlock(&q->lock);
+ /*
+  * Setup timeout for a device in jiffies.
+  */
+-void
+-dasd_set_timer(struct dasd_device *device, int expires)
++void dasd_device_set_timer(struct dasd_device *device, int expires)
+ {
+ 	if (expires == 0) {
+ 		if (timer_pending(&device->timer))
+@@ -862,7 +904,7 @@ dasd_set_timer(struct dasd_device *device, int expires)
+ 		if (mod_timer(&device->timer, jiffies + expires))
+ 			return;
+ 	}
+-	device->timer.function = dasd_timeout_device;
++	device->timer.function = dasd_device_timeout;
+ 	device->timer.data = (unsigned long) device;
+ 	device->timer.expires = jiffies + expires;
+ 	add_timer(&device->timer);
+@@ -871,15 +913,14 @@ dasd_set_timer(struct dasd_device *device, int expires)
+ /*
+  * Clear timeout for a device.
+  */
+-void
+-dasd_clear_timer(struct dasd_device *device)
++void dasd_device_clear_timer(struct dasd_device *device)
+ {
+ 	if (timer_pending(&device->timer))
+ 		del_timer(&device->timer);
+ }
  
- 	return retval;
-@@ -1026,15 +1043,15 @@ int videobuf_cgmbuf(struct videobuf_queue *q,
- 		    struct video_mbuf *mbuf, int count)
+-static void
+-dasd_handle_killed_request(struct ccw_device *cdev, unsigned long intparm)
++static void dasd_handle_killed_request(struct ccw_device *cdev,
++				       unsigned long intparm)
  {
- 	struct v4l2_requestbuffers req;
--	int rc,i;
-+	int rc, i;
+ 	struct dasd_ccw_req *cqr;
+ 	struct dasd_device *device;
+@@ -893,7 +934,7 @@ dasd_handle_killed_request(struct ccw_device *cdev, unsigned long intparm)
+ 		return;
+ 	}
  
--	MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);
-+	MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
+-	device = (struct dasd_device *) cqr->device;
++	device = (struct dasd_device *) cqr->startdev;
+ 	if (device == NULL ||
+ 	    device != dasd_device_from_cdev_locked(cdev) ||
+ 	    strncmp(device->discipline->ebcname, (char *) &cqr->magic, 4)) {
+@@ -905,46 +946,32 @@ dasd_handle_killed_request(struct ccw_device *cdev, unsigned long intparm)
+ 	/* Schedule request to be retried. */
+ 	cqr->status = DASD_CQR_QUEUED;
  
--	memset(&req,0,sizeof(req));
-+	memset(&req, 0, sizeof(req));
- 	req.type   = q->type;
- 	req.count  = count;
- 	req.memory = V4L2_MEMORY_MMAP;
--	rc = videobuf_reqbufs(q,&req);
-+	rc = videobuf_reqbufs(q, &req);
- 	if (rc < 0)
- 		return rc;
+-	dasd_clear_timer(device);
+-	dasd_schedule_bh(device);
++	dasd_device_clear_timer(device);
++	dasd_schedule_device_bh(device);
+ 	dasd_put_device(device);
+ }
  
-@@ -1079,9 +1096,3 @@ EXPORT_SYMBOL_GPL(videobuf_poll_stream);
- EXPORT_SYMBOL_GPL(videobuf_mmap_setup);
- EXPORT_SYMBOL_GPL(videobuf_mmap_free);
- EXPORT_SYMBOL_GPL(videobuf_mmap_mapper);
--
--/*
-- * Local variables:
-- * c-basic-offset: 8
-- * End:
-- */
-diff --git a/drivers/media/video/videobuf-dma-sg.c b/drivers/media/video/videobuf-dma-sg.c
-index 44ee408..98efd7a 100644
---- a/drivers/media/video/videobuf-dma-sg.c
-+++ b/drivers/media/video/videobuf-dma-sg.c
-@@ -385,30 +385,27 @@ videobuf_vm_close(struct vm_area_struct *vma)
-  * now ...).  Bounce buffers don't work very well for the data rates
-  * video capture has.
-  */
--static struct page*
--videobuf_vm_nopage(struct vm_area_struct *vma, unsigned long vaddr,
--		   int *type)
-+static int
-+videobuf_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
+-static void
+-dasd_handle_state_change_pending(struct dasd_device *device)
++void dasd_generic_handle_state_change(struct dasd_device *device)
  {
- 	struct page *page;
+-	struct dasd_ccw_req *cqr;
+-	struct list_head *l, *n;
+-
+ 	/* First of all start sense subsystem status request. */
+ 	dasd_eer_snss(device);
  
--	dprintk(3,"nopage: fault @ %08lx [vma %08lx-%08lx]\n",
--		vaddr,vma->vm_start,vma->vm_end);
--	if (vaddr > vma->vm_end)
--		return NOPAGE_SIGBUS;
-+	dprintk(3,"fault: fault @ %08lx [vma %08lx-%08lx]\n",
-+		(unsigned long)vmf->virtual_address,vma->vm_start,vma->vm_end);
- 	page = alloc_page(GFP_USER | __GFP_DMA32);
- 	if (!page)
--		return NOPAGE_OOM;
--	clear_user_page(page_address(page), vaddr, page);
--	if (type)
--		*type = VM_FAULT_MINOR;
--	return page;
-+		return VM_FAULT_OOM;
-+	clear_user_page(page_address(page), (unsigned long)vmf->virtual_address,
-+			page);
-+	vmf->page = page;
-+	return 0;
+ 	device->stopped &= ~DASD_STOPPED_PENDING;
+-
+-        /* restart all 'running' IO on queue */
+-	list_for_each_safe(l, n, &device->ccw_queue) {
+-		cqr = list_entry(l, struct dasd_ccw_req, list);
+-                if (cqr->status == DASD_CQR_IN_IO) {
+-                        cqr->status = DASD_CQR_QUEUED;
+-		}
+-        }
+-	dasd_clear_timer(device);
+-	dasd_schedule_bh(device);
++	dasd_schedule_device_bh(device);
++	if (device->block)
++		dasd_schedule_block_bh(device->block);
  }
  
- static struct vm_operations_struct videobuf_vm_ops =
+ /*
+  * Interrupt handler for "normal" ssch-io based dasd devices.
+  */
+-void
+-dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
+-		 struct irb *irb)
++void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
++		      struct irb *irb)
  {
- 	.open     = videobuf_vm_open,
- 	.close    = videobuf_vm_close,
--	.nopage   = videobuf_vm_nopage,
-+	.fault    = videobuf_vm_fault,
- };
- 
- /* ---------------------------------------------------------------------
-diff --git a/drivers/media/video/videobuf-dvb.c b/drivers/media/video/videobuf-dvb.c
-index 880317e..b73aba6 100644
---- a/drivers/media/video/videobuf-dvb.c
-+++ b/drivers/media/video/videobuf-dvb.c
-@@ -67,7 +67,7 @@ static int videobuf_dvb_thread(void *data)
+ 	struct dasd_ccw_req *cqr, *next;
+ 	struct dasd_device *device;
+ 	unsigned long long now;
+ 	int expires;
+-	dasd_era_t era;
+-	char mask;
  
- 		/* feed buffer data to demux */
- 		dma=videobuf_to_dma(buf);
--		if (buf->state == STATE_DONE)
-+		if (buf->state == VIDEOBUF_DONE)
- 			dvb_dmx_swfilter(&dvb->demux, dma->vmalloc,
- 					 buf->size);
+ 	if (IS_ERR(irb)) {
+ 		switch (PTR_ERR(irb)) {
+@@ -969,29 +996,25 @@ dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
+ 		  cdev->dev.bus_id, ((irb->scsw.cstat<<8)|irb->scsw.dstat),
+ 		  (unsigned int) intparm);
  
-diff --git a/drivers/media/video/videobuf-vmalloc.c b/drivers/media/video/videobuf-vmalloc.c
-index e012594..9b38983 100644
---- a/drivers/media/video/videobuf-vmalloc.c
-+++ b/drivers/media/video/videobuf-vmalloc.c
-@@ -41,7 +41,7 @@ MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab at infradead.org>");
- MODULE_LICENSE("GPL");
+-	/* first of all check for state change pending interrupt */
+-	mask = DEV_STAT_ATTENTION | DEV_STAT_DEV_END | DEV_STAT_UNIT_EXCEP;
+-	if ((irb->scsw.dstat & mask) == mask) {
++	/* check for unsolicited interrupts */
++	cqr = (struct dasd_ccw_req *) intparm;
++	if (!cqr || ((irb->scsw.cc == 1) &&
++		     (irb->scsw.fctl & SCSW_FCTL_START_FUNC) &&
++		     (irb->scsw.stctl & SCSW_STCTL_STATUS_PEND)) ) {
++		if (cqr && cqr->status == DASD_CQR_IN_IO)
++			cqr->status = DASD_CQR_QUEUED;
+ 		device = dasd_device_from_cdev_locked(cdev);
+ 		if (!IS_ERR(device)) {
+-			dasd_handle_state_change_pending(device);
++			dasd_device_clear_timer(device);
++			device->discipline->handle_unsolicited_interrupt(device,
++									 irb);
+ 			dasd_put_device(device);
+ 		}
+ 		return;
+ 	}
  
- #define dprintk(level, fmt, arg...)	if (debug >= level) \
--	printk(KERN_DEBUG "vbuf-sg: " fmt , ## arg)
-+	printk(KERN_DEBUG "vbuf-vmalloc: " fmt , ## arg)
+-	cqr = (struct dasd_ccw_req *) intparm;
+-
+-	/* check for unsolicited interrupts */
+-	if (cqr == NULL) {
+-		MESSAGE(KERN_DEBUG,
+-			"unsolicited interrupt received: bus_id %s",
+-			cdev->dev.bus_id);
+-		return;
+-	}
+-
+-	device = (struct dasd_device *) cqr->device;
+-	if (device == NULL ||
++	device = (struct dasd_device *) cqr->startdev;
++	if (!device ||
+ 	    strncmp(device->discipline->ebcname, (char *) &cqr->magic, 4)) {
+ 		MESSAGE(KERN_DEBUG, "invalid device in request: bus_id %s",
+ 			cdev->dev.bus_id);
+@@ -999,12 +1022,12 @@ dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
+ 	}
  
+ 	/* Check for clear pending */
+-	if (cqr->status == DASD_CQR_CLEAR &&
++	if (cqr->status == DASD_CQR_CLEAR_PENDING &&
+ 	    irb->scsw.fctl & SCSW_FCTL_CLEAR_FUNC) {
+-		cqr->status = DASD_CQR_QUEUED;
+-		dasd_clear_timer(device);
++		cqr->status = DASD_CQR_CLEARED;
++		dasd_device_clear_timer(device);
+ 		wake_up(&dasd_flush_wq);
+-		dasd_schedule_bh(device);
++		dasd_schedule_device_bh(device);
+ 		return;
+ 	}
  
- /***************************************************************************/
-diff --git a/drivers/media/video/videodev.c b/drivers/media/video/videodev.c
-index 9611c39..28655f8 100644
---- a/drivers/media/video/videodev.c
-+++ b/drivers/media/video/videodev.c
-@@ -973,7 +973,7 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
+@@ -1017,277 +1040,170 @@ dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
+ 	}
+ 	DBF_DEV_EVENT(DBF_DEBUG, device, "Int: CS/DS 0x%04x for cqr %p",
+ 		      ((irb->scsw.cstat << 8) | irb->scsw.dstat), cqr);
+-
+- 	/* Find out the appropriate era_action. */
+-	if (irb->scsw.fctl & SCSW_FCTL_HALT_FUNC)
+-		era = dasd_era_fatal;
+-	else if (irb->scsw.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END) &&
+-		 irb->scsw.cstat == 0 &&
+-		 !irb->esw.esw0.erw.cons)
+-		era = dasd_era_none;
+-	else if (irb->esw.esw0.erw.cons)
+-		era = device->discipline->examine_error(cqr, irb);
+-	else
+-		era = dasd_era_recover;
+-
+-	DBF_DEV_EVENT(DBF_DEBUG, device, "era_code %d", era);
++	next = NULL;
+ 	expires = 0;
+-	if (era == dasd_era_none) {
+-		cqr->status = DASD_CQR_DONE;
++	if (irb->scsw.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END) &&
++	    irb->scsw.cstat == 0 && !irb->esw.esw0.erw.cons) {
++		/* request was completed successfully */
++		cqr->status = DASD_CQR_SUCCESS;
+ 		cqr->stopclk = now;
+ 		/* Start first request on queue if possible -> fast_io. */
+-		if (cqr->list.next != &device->ccw_queue) {
+-			next = list_entry(cqr->list.next,
+-					  struct dasd_ccw_req, list);
+-			if ((next->status == DASD_CQR_QUEUED) &&
+-			    (!device->stopped)) {
+-				if (device->discipline->start_IO(next) == 0)
+-					expires = next->expires;
+-				else
+-					DEV_MESSAGE(KERN_DEBUG, device, "%s",
+-						    "Interrupt fastpath "
+-						    "failed!");
+-			}
++		if (cqr->devlist.next != &device->ccw_queue) {
++			next = list_entry(cqr->devlist.next,
++					  struct dasd_ccw_req, devlist);
+ 		}
+-	} else {		/* error */
+-		memcpy(&cqr->irb, irb, sizeof (struct irb));
++	} else {  /* error */
++		memcpy(&cqr->irb, irb, sizeof(struct irb));
+ 		if (device->features & DASD_FEATURE_ERPLOG) {
+-			/* dump sense data */
+ 			dasd_log_sense(cqr, irb);
+ 		}
+-		switch (era) {
+-		case dasd_era_fatal:
+-			cqr->status = DASD_CQR_FAILED;
+-			cqr->stopclk = now;
+-			break;
+-		case dasd_era_recover:
++		/* If we have no sense data, or we just don't want complex ERP
++		 * for this request, but if we have retries left, then just
++		 * reset this request and retry it in the fastpath
++		 */
++		if (!(cqr->irb.esw.esw0.erw.cons &&
++		      test_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags)) &&
++		    cqr->retries > 0) {
++			DEV_MESSAGE(KERN_DEBUG, device,
++				    "default ERP in fastpath (%i retries left)",
++				    cqr->retries);
++			cqr->lpm    = LPM_ANYPATH;
++			cqr->status = DASD_CQR_QUEUED;
++			next = cqr;
++		} else
+ 			cqr->status = DASD_CQR_ERROR;
+-			break;
+-		default:
+-			BUG();
+-		}
++	}
++	if (next && (next->status == DASD_CQR_QUEUED) &&
++	    (!device->stopped)) {
++		if (device->discipline->start_IO(next) == 0)
++			expires = next->expires;
++		else
++			DEV_MESSAGE(KERN_DEBUG, device, "%s",
++				    "Interrupt fastpath "
++				    "failed!");
+ 	}
+ 	if (expires != 0)
+-		dasd_set_timer(device, expires);
++		dasd_device_set_timer(device, expires);
+ 	else
+-		dasd_clear_timer(device);
+-	dasd_schedule_bh(device);
++		dasd_device_clear_timer(device);
++	dasd_schedule_device_bh(device);
+ }
  
- 		*id = vfd->current_norm;
+ /*
+- * posts the buffer_cache about a finalized request
++ * If we have an error on a dasd_block layer request then we cancel
++ * and return all further requests from the same dasd_block as well.
+  */
+-static inline void
+-dasd_end_request(struct request *req, int uptodate)
++static void __dasd_device_recovery(struct dasd_device *device,
++				   struct dasd_ccw_req *ref_cqr)
+ {
+-	if (end_that_request_first(req, uptodate, req->hard_nr_sectors))
+-		BUG();
+-	add_disk_randomness(req->rq_disk);
+-	end_that_request_last(req, uptodate);
+-}
++	struct list_head *l, *n;
++	struct dasd_ccw_req *cqr;
  
--		dbgarg (cmd, "value=%Lu\n", (long long unsigned) *id);
-+		dbgarg (cmd, "value=%08Lx\n", (long long unsigned) *id);
+-/*
+- * Process finished error recovery ccw.
+- */
+-static inline void
+-__dasd_process_erp(struct dasd_device *device, struct dasd_ccw_req *cqr)
+-{
+-	dasd_erp_fn_t erp_fn;
++	/*
++	 * only requeue request that came from the dasd_block layer
++	 */
++	if (!ref_cqr->block)
++		return;
  
- 		ret=0;
- 		break;
-@@ -982,7 +982,7 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
- 	{
- 		v4l2_std_id *id = arg,norm;
+-	if (cqr->status == DASD_CQR_DONE)
+-		DBF_DEV_EVENT(DBF_NOTICE, device, "%s", "ERP successful");
+-	else
+-		DEV_MESSAGE(KERN_ERR, device, "%s", "ERP unsuccessful");
+-	erp_fn = device->discipline->erp_postaction(cqr);
+-	erp_fn(cqr);
+-}
++	list_for_each_safe(l, n, &device->ccw_queue) {
++		cqr = list_entry(l, struct dasd_ccw_req, devlist);
++		if (cqr->status == DASD_CQR_QUEUED &&
++		    ref_cqr->block == cqr->block) {
++			cqr->status = DASD_CQR_CLEARED;
++		}
++	}
++};
  
--		dbgarg (cmd, "value=%Lu\n", (long long unsigned) *id);
-+		dbgarg (cmd, "value=%08Lx\n", (long long unsigned) *id);
+ /*
+- * Process ccw request queue.
++ * Remove those ccw requests from the queue that need to be returned
++ * to the upper layer.
+  */
+-static void
+-__dasd_process_ccw_queue(struct dasd_device * device,
+-			 struct list_head *final_queue)
++static void __dasd_device_process_ccw_queue(struct dasd_device *device,
++					    struct list_head *final_queue)
+ {
+ 	struct list_head *l, *n;
+ 	struct dasd_ccw_req *cqr;
+-	dasd_erp_fn_t erp_fn;
  
- 		norm = (*id) & vfd->tvnorms;
- 		if ( vfd->tvnorms && !norm)	/* Check if std is supported */
-@@ -1008,7 +1008,7 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
+-restart:
+ 	/* Process request with final status. */
+ 	list_for_each_safe(l, n, &device->ccw_queue) {
+-		cqr = list_entry(l, struct dasd_ccw_req, list);
++		cqr = list_entry(l, struct dasd_ccw_req, devlist);
++
+ 		/* Stop list processing at the first non-final request. */
+-		if (cqr->status != DASD_CQR_DONE &&
+-		    cqr->status != DASD_CQR_FAILED &&
+-		    cqr->status != DASD_CQR_ERROR)
++		if (cqr->status == DASD_CQR_QUEUED ||
++		    cqr->status == DASD_CQR_IN_IO ||
++		    cqr->status == DASD_CQR_CLEAR_PENDING)
  			break;
- 		ret=vfd->vidioc_querystd(file, fh, arg);
- 		if (!ret)
--			dbgarg (cmd, "detected std=%Lu\n",
-+			dbgarg (cmd, "detected std=%08Lx\n",
- 						(unsigned long long)*p);
- 		break;
- 	}
-@@ -1028,7 +1028,7 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
- 		if (!ret)
- 			dbgarg (cmd, "index=%d, name=%s, type=%d, "
- 					"audioset=%d, "
--					"tuner=%d, std=%Ld, status=%d\n",
-+					"tuner=%d, std=%08Lx, status=%d\n",
- 					p->index,p->name,p->type,p->audioset,
- 					p->tuner,
- 					(unsigned long long)p->std,
-diff --git a/drivers/media/video/vino.c b/drivers/media/video/vino.c
-index 9a03dc8..5bb7529 100644
---- a/drivers/media/video/vino.c
-+++ b/drivers/media/video/vino.c
-@@ -2589,11 +2589,7 @@ static int vino_acquire_input(struct vino_channel_settings *vcs)
- 	/* First try D1 and then SAA7191 */
- 	if (vino_drvdata->camera.driver
- 	    && (vino_drvdata->camera.owner == VINO_NO_CHANNEL)) {
--		if (i2c_use_client(vino_drvdata->camera.driver)) {
--			ret = -ENODEV;
--			goto out;
+-		/*  Process requests with DASD_CQR_ERROR */
+ 		if (cqr->status == DASD_CQR_ERROR) {
+-			if (cqr->irb.scsw.fctl & SCSW_FCTL_HALT_FUNC) {
+-				cqr->status = DASD_CQR_FAILED;
+-				cqr->stopclk = get_clock();
+-			} else {
+-				if (cqr->irb.esw.esw0.erw.cons &&
+-				    test_bit(DASD_CQR_FLAGS_USE_ERP,
+-					     &cqr->flags)) {
+-					erp_fn = device->discipline->
+-						erp_action(cqr);
+-					erp_fn(cqr);
+-				} else
+-					dasd_default_erp_action(cqr);
+-			}
+-			goto restart;
 -		}
 -
-+		i2c_use_client(vino_drvdata->camera.driver);
- 		vino_drvdata->camera.owner = vcs->channel;
- 		vcs->input = VINO_INPUT_D1;
- 		vcs->data_norm = VINO_DATA_NORM_D1;
-@@ -2602,11 +2598,7 @@ static int vino_acquire_input(struct vino_channel_settings *vcs)
- 		int input, data_norm;
- 		int saa7191_input;
- 
--		if (i2c_use_client(vino_drvdata->decoder.driver)) {
--			ret = -ENODEV;
--			goto out;
+-		/* First of all call extended error reporting. */
+-		if (dasd_eer_enabled(device) &&
+-		    cqr->status == DASD_CQR_FAILED) {
+-			dasd_eer_write(device, cqr, DASD_EER_FATALERROR);
+-
+-			/* restart request  */
+-			cqr->status = DASD_CQR_QUEUED;
+-			cqr->retries = 255;
+-			device->stopped |= DASD_STOPPED_QUIESCE;
+-			goto restart;
++			__dasd_device_recovery(device, cqr);
+ 		}
+-
+-		/* Process finished ERP request. */
+-		if (cqr->refers) {
+-			__dasd_process_erp(device, cqr);
+-			goto restart;
 -		}
 -
-+		i2c_use_client(vino_drvdata->decoder.driver);
- 		input = VINO_INPUT_COMPOSITE;
+ 		/* Rechain finished requests to final queue */
+-		cqr->endclk = get_clock();
+-		list_move_tail(&cqr->list, final_queue);
++		list_move_tail(&cqr->devlist, final_queue);
+ 	}
+ }
  
- 		saa7191_input = vino_get_saa7191_input(input);
-@@ -2688,10 +2680,7 @@ static int vino_set_input(struct vino_channel_settings *vcs, int input)
- 		}
+-static void
+-dasd_end_request_cb(struct dasd_ccw_req * cqr, void *data)
+-{
+-	struct request *req;
+-	struct dasd_device *device;
+-	int status;
+-
+-	req = (struct request *) data;
+-	device = cqr->device;
+-	dasd_profile_end(device, cqr, req);
+-	status = cqr->device->discipline->free_cp(cqr,req);
+-	spin_lock_irq(&device->request_queue_lock);
+-	dasd_end_request(req, status);
+-	spin_unlock_irq(&device->request_queue_lock);
+-}
+-
+-
+ /*
+- * Fetch requests from the block device queue.
++ * the cqrs from the final queue are returned to the upper layer
++ * by setting a dasd_block state and calling the callback function
+  */
+-static void
+-__dasd_process_blk_queue(struct dasd_device * device)
++static void __dasd_device_process_final_queue(struct dasd_device *device,
++					      struct list_head *final_queue)
+ {
+-	struct request_queue *queue;
+-	struct request *req;
++	struct list_head *l, *n;
+ 	struct dasd_ccw_req *cqr;
+-	int nr_queued;
+-
+-	queue = device->request_queue;
+-	/* No queue ? Then there is nothing to do. */
+-	if (queue == NULL)
+-		return;
+-
+-	/*
+-	 * We requeue request from the block device queue to the ccw
+-	 * queue only in two states. In state DASD_STATE_READY the
+-	 * partition detection is done and we need to requeue requests
+-	 * for that. State DASD_STATE_ONLINE is normal block device
+-	 * operation.
+-	 */
+-	if (device->state != DASD_STATE_READY &&
+-	    device->state != DASD_STATE_ONLINE)
+-		return;
+-	nr_queued = 0;
+-	/* Now we try to fetch requests from the request queue */
+-	list_for_each_entry(cqr, &device->ccw_queue, list)
+-		if (cqr->status == DASD_CQR_QUEUED)
+-			nr_queued++;
+-	while (!blk_queue_plugged(queue) &&
+-	       elv_next_request(queue) &&
+-		nr_queued < DASD_CHANQ_MAX_SIZE) {
+-		req = elv_next_request(queue);
  
- 		if (vino_drvdata->decoder.owner == VINO_NO_CHANNEL) {
--			if (i2c_use_client(vino_drvdata->decoder.driver)) {
--				ret = -ENODEV;
--				goto out;
+-		if (device->features & DASD_FEATURE_READONLY &&
+-		    rq_data_dir(req) == WRITE) {
+-			DBF_DEV_EVENT(DBF_ERR, device,
+-				      "Rejecting write request %p",
+-				      req);
+-			blkdev_dequeue_request(req);
+-			dasd_end_request(req, 0);
+-			continue;
+-		}
+-		if (device->stopped & DASD_STOPPED_DC_EIO) {
+-			blkdev_dequeue_request(req);
+-			dasd_end_request(req, 0);
+-			continue;
+-		}
+-		cqr = device->discipline->build_cp(device, req);
+-		if (IS_ERR(cqr)) {
+-			if (PTR_ERR(cqr) == -ENOMEM)
+-				break;	/* terminate request queue loop */
+-			if (PTR_ERR(cqr) == -EAGAIN) {
+-				/*
+-				 * The current request cannot be build right
+-				 * now, we have to try later. If this request
+-				 * is the head-of-queue we stop the device
+-				 * for 1/2 second.
+-				 */
+-				if (!list_empty(&device->ccw_queue))
+-					break;
+-				device->stopped |= DASD_STOPPED_PENDING;
+-				dasd_set_timer(device, HZ/2);
+-				break;
 -			}
-+			i2c_use_client(vino_drvdata->decoder.driver);
- 			vino_drvdata->decoder.owner = vcs->channel;
+-			DBF_DEV_EVENT(DBF_ERR, device,
+-				      "CCW creation failed (rc=%ld) "
+-				      "on request %p",
+-				      PTR_ERR(cqr), req);
+-			blkdev_dequeue_request(req);
+-			dasd_end_request(req, 0);
+-			continue;
++	list_for_each_safe(l, n, final_queue) {
++		cqr = list_entry(l, struct dasd_ccw_req, devlist);
++		list_del_init(&cqr->devlist);
++		if (cqr->block)
++			spin_lock_bh(&cqr->block->queue_lock);
++		switch (cqr->status) {
++		case DASD_CQR_SUCCESS:
++			cqr->status = DASD_CQR_DONE;
++			break;
++		case DASD_CQR_ERROR:
++			cqr->status = DASD_CQR_NEED_ERP;
++			break;
++		case DASD_CQR_CLEARED:
++			cqr->status = DASD_CQR_TERMINATED;
++			break;
++		default:
++			DEV_MESSAGE(KERN_ERR, device,
++				    "wrong cqr status in __dasd_process_final_queue "
++				    "for cqr %p, status %x",
++				    cqr, cqr->status);
++			BUG();
  		}
+-		cqr->callback = dasd_end_request_cb;
+-		cqr->callback_data = (void *) req;
+-		cqr->status = DASD_CQR_QUEUED;
+-		blkdev_dequeue_request(req);
+-		list_add_tail(&cqr->list, &device->ccw_queue);
+-		dasd_profile_start(device, cqr, req);
+-		nr_queued++;
++		if (cqr->block)
++			spin_unlock_bh(&cqr->block->queue_lock);
++		if (cqr->callback != NULL)
++			(cqr->callback)(cqr, cqr->callback_data);
+ 	}
+ }
  
-@@ -2759,10 +2748,7 @@ static int vino_set_input(struct vino_channel_settings *vcs, int input)
- 		}
++
++
+ /*
+  * Take a look at the first request on the ccw queue and check
+  * if it reached its expire time. If so, terminate the IO.
+  */
+-static void
+-__dasd_check_expire(struct dasd_device * device)
++static void __dasd_device_check_expire(struct dasd_device *device)
+ {
+ 	struct dasd_ccw_req *cqr;
  
- 		if (vino_drvdata->camera.owner == VINO_NO_CHANNEL) {
--			if (i2c_use_client(vino_drvdata->camera.driver)) {
--				ret = -ENODEV;
--				goto out;
--			}
-+			i2c_use_client(vino_drvdata->camera.driver);
- 			vino_drvdata->camera.owner = vcs->channel;
+ 	if (list_empty(&device->ccw_queue))
+ 		return;
+-	cqr = list_entry(device->ccw_queue.next, struct dasd_ccw_req, list);
++	cqr = list_entry(device->ccw_queue.next, struct dasd_ccw_req, devlist);
+ 	if ((cqr->status == DASD_CQR_IN_IO && cqr->expires != 0) &&
+ 	    (time_after_eq(jiffies, cqr->expires + cqr->starttime))) {
+ 		if (device->discipline->term_IO(cqr) != 0) {
+ 			/* Hmpf, try again in 5 sec */
+-			dasd_set_timer(device, 5*HZ);
+ 			DEV_MESSAGE(KERN_ERR, device,
+ 				    "internal error - timeout (%is) expired "
+ 				    "for cqr %p, termination failed, "
+ 				    "retrying in 5s",
+ 				    (cqr->expires/HZ), cqr);
++			cqr->expires += 5*HZ;
++			dasd_device_set_timer(device, 5*HZ);
+ 		} else {
+ 			DEV_MESSAGE(KERN_ERR, device,
+ 				    "internal error - timeout (%is) expired "
+@@ -1301,77 +1217,53 @@ __dasd_check_expire(struct dasd_device * device)
+  * Take a look at the first request on the ccw queue and check
+  * if it needs to be started.
+  */
+-static void
+-__dasd_start_head(struct dasd_device * device)
++static void __dasd_device_start_head(struct dasd_device *device)
+ {
+ 	struct dasd_ccw_req *cqr;
+ 	int rc;
+ 
+ 	if (list_empty(&device->ccw_queue))
+ 		return;
+-	cqr = list_entry(device->ccw_queue.next, struct dasd_ccw_req, list);
++	cqr = list_entry(device->ccw_queue.next, struct dasd_ccw_req, devlist);
+ 	if (cqr->status != DASD_CQR_QUEUED)
+ 		return;
+-	/* Non-temporary stop condition will trigger fail fast */
+-	if (device->stopped & ~DASD_STOPPED_PENDING &&
+-	    test_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags) &&
+-	    (!dasd_eer_enabled(device))) {
+-		cqr->status = DASD_CQR_FAILED;
+-		dasd_schedule_bh(device);
++	/* when device is stopped, return request to previous layer */
++	if (device->stopped) {
++		cqr->status = DASD_CQR_CLEARED;
++		dasd_schedule_device_bh(device);
+ 		return;
+ 	}
+-	/* Don't try to start requests if device is stopped */
+-	if (device->stopped)
+-		return;
+ 
+ 	rc = device->discipline->start_IO(cqr);
+ 	if (rc == 0)
+-		dasd_set_timer(device, cqr->expires);
++		dasd_device_set_timer(device, cqr->expires);
+ 	else if (rc == -EACCES) {
+-		dasd_schedule_bh(device);
++		dasd_schedule_device_bh(device);
+ 	} else
+ 		/* Hmpf, try again in 1/2 sec */
+-		dasd_set_timer(device, 50);
+-}
+-
+-static inline int
+-_wait_for_clear(struct dasd_ccw_req *cqr)
+-{
+-	return (cqr->status == DASD_CQR_QUEUED);
++		dasd_device_set_timer(device, 50);
+ }
+ 
+ /*
+- * Remove all requests from the ccw queue (all = '1') or only block device
+- * requests in case all = '0'.
+- * Take care of the erp-chain (chained via cqr->refers) and remove either
+- * the whole erp-chain or none of the erp-requests.
+- * If a request is currently running, term_IO is called and the request
+- * is re-queued. Prior to removing the terminated request we need to wait
+- * for the clear-interrupt.
+- * In case termination is not possible we stop processing and just finishing
+- * the already moved requests.
++ * Go through all request on the dasd_device request queue,
++ * terminate them on the cdev if necessary, and return them to the
++ * submitting layer via callback.
++ * Note:
++ * Make sure that all 'submitting layers' still exist when
++ * this function is called!. In other words, when 'device' is a base
++ * device then all block layer requests must have been removed before
++ * via dasd_flush_block_queue.
+  */
+-static int
+-dasd_flush_ccw_queue(struct dasd_device * device, int all)
++int dasd_flush_device_queue(struct dasd_device *device)
+ {
+-	struct dasd_ccw_req *cqr, *orig, *n;
+-	int rc, i;
+-
++	struct dasd_ccw_req *cqr, *n;
++	int rc;
+ 	struct list_head flush_queue;
+ 
+ 	INIT_LIST_HEAD(&flush_queue);
+ 	spin_lock_irq(get_ccwdev_lock(device->cdev));
+ 	rc = 0;
+-restart:
+-	list_for_each_entry_safe(cqr, n, &device->ccw_queue, list) {
+-		/* get original request of erp request-chain */
+-		for (orig = cqr; orig->refers != NULL; orig = orig->refers);
+-
+-		/* Flush all request or only block device requests? */
+-		if (all == 0 && cqr->callback != dasd_end_request_cb &&
+-		    orig->callback != dasd_end_request_cb) {
+-			continue;
+-		}
++	list_for_each_entry_safe(cqr, n, &device->ccw_queue, devlist) {
+ 		/* Check status and move request to flush_queue */
+ 		switch (cqr->status) {
+ 		case DASD_CQR_IN_IO:
+@@ -1387,90 +1279,60 @@ restart:
+ 			}
+ 			break;
+ 		case DASD_CQR_QUEUED:
+-		case DASD_CQR_ERROR:
+-			/* set request to FAILED */
+ 			cqr->stopclk = get_clock();
+-			cqr->status = DASD_CQR_FAILED;
++			cqr->status = DASD_CQR_CLEARED;
+ 			break;
+-		default: /* do not touch the others */
++		default: /* no need to modify the others */
+ 			break;
  		}
- 
-diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c
-index 9b54ff9..1db067c 100644
---- a/drivers/media/video/vivi.c
-+++ b/drivers/media/video/vivi.c
-@@ -44,21 +44,18 @@
- #define WAKE_DENOMINATOR 1001
- #define BUFFER_TIMEOUT     msecs_to_jiffies(500)  /* 0.5 seconds */
- 
--/* These timers are for 1 fps - used only for testing */
--//#define WAKE_DENOMINATOR 30 /* hack for testing purposes */
--//#define BUFFER_TIMEOUT     msecs_to_jiffies(5000)  /* 5 seconds */
+-		/* Rechain request (including erp chain) */
+-		for (i = 0; cqr != NULL; cqr = cqr->refers, i++) {
+-			cqr->endclk = get_clock();
+-			list_move_tail(&cqr->list, &flush_queue);
+-		}
+-		if (i > 1)
+-			/* moved more than one request - need to restart */
+-			goto restart;
++		list_move_tail(&cqr->devlist, &flush_queue);
+ 	}
 -
- #include "font.h"
- 
- #define VIVI_MAJOR_VERSION 0
- #define VIVI_MINOR_VERSION 4
- #define VIVI_RELEASE 0
--#define VIVI_VERSION KERNEL_VERSION(VIVI_MAJOR_VERSION, VIVI_MINOR_VERSION, VIVI_RELEASE)
-+#define VIVI_VERSION \
-+	KERNEL_VERSION(VIVI_MAJOR_VERSION, VIVI_MINOR_VERSION, VIVI_RELEASE)
- 
- /* Declare static vars that will be used as parameters */
- static unsigned int vid_limit = 16;	/* Video memory limit, in Mb */
--static struct video_device vivi;	/* Video device */
- static int video_nr = -1;		/* /dev/videoN, -1 for autodetect */
-+static int n_devs = 1;			/* Number of virtual devices */
- 
- /* supported controls */
- static struct v4l2_queryctrl vivi_qctrl[] = {
-@@ -71,7 +68,7 @@ static struct v4l2_queryctrl vivi_qctrl[] = {
- 		.default_value = 65535,
- 		.flags         = 0,
- 		.type          = V4L2_CTRL_TYPE_INTEGER,
--	},{
-+	}, {
- 		.id            = V4L2_CID_BRIGHTNESS,
- 		.type          = V4L2_CTRL_TYPE_INTEGER,
- 		.name          = "Brightness",
-@@ -112,9 +109,9 @@ static struct v4l2_queryctrl vivi_qctrl[] = {
+ finished:
+ 	spin_unlock_irq(get_ccwdev_lock(device->cdev));
+-	/* Now call the callback function of flushed requests */
+-restart_cb:
+-	list_for_each_entry_safe(cqr, n, &flush_queue, list) {
+-		if (cqr->status == DASD_CQR_CLEAR) {
+-			/* wait for clear interrupt! */
+-			wait_event(dasd_flush_wq, _wait_for_clear(cqr));
+-			cqr->status = DASD_CQR_FAILED;
+-		}
+-		/* Process finished ERP request. */
+-		if (cqr->refers) {
+-			__dasd_process_erp(device, cqr);
+-			/* restart list_for_xx loop since dasd_process_erp
+-			 * might remove multiple elements */
+-			goto restart_cb;
+-		}
+-		/* call the callback function */
+-		cqr->endclk = get_clock();
+-		if (cqr->callback != NULL)
+-			(cqr->callback)(cqr, cqr->callback_data);
+-	}
++	/*
++	 * After this point all requests must be in state CLEAR_PENDING,
++	 * CLEARED, SUCCESS or ERROR. Now wait for CLEAR_PENDING to become
++	 * one of the others.
++	 */
++	list_for_each_entry_safe(cqr, n, &flush_queue, devlist)
++		wait_event(dasd_flush_wq,
++			   (cqr->status != DASD_CQR_CLEAR_PENDING));
++	/*
++	 * Now set each request back to TERMINATED, DONE or NEED_ERP
++	 * and call the callback function of flushed requests
++	 */
++	__dasd_device_process_final_queue(device, &flush_queue);
+ 	return rc;
+ }
  
- static int qctl_regs[ARRAY_SIZE(vivi_qctrl)];
+ /*
+  * Acquire the device lock and process queues for the device.
+  */
+-static void
+-dasd_tasklet(struct dasd_device * device)
++static void dasd_device_tasklet(struct dasd_device *device)
+ {
+ 	struct list_head final_queue;
+-	struct list_head *l, *n;
+-	struct dasd_ccw_req *cqr;
  
--#define dprintk(level,fmt, arg...)					\
-+#define dprintk(dev, level, fmt, arg...)				\
- 	do {								\
--		if (vivi.debug >= (level))				\
-+		if (dev->vfd->debug >= (level))				\
- 			printk(KERN_DEBUG "vivi: " fmt , ## arg);	\
- 	} while (0)
+ 	atomic_set (&device->tasklet_scheduled, 0);
+ 	INIT_LIST_HEAD(&final_queue);
+ 	spin_lock_irq(get_ccwdev_lock(device->cdev));
+ 	/* Check expire time of first request on the ccw queue. */
+-	__dasd_check_expire(device);
+-	/* Finish off requests on ccw queue */
+-	__dasd_process_ccw_queue(device, &final_queue);
++	__dasd_device_check_expire(device);
++	/* find final requests on ccw queue */
++	__dasd_device_process_ccw_queue(device, &final_queue);
+ 	spin_unlock_irq(get_ccwdev_lock(device->cdev));
+ 	/* Now call the callback function of requests with final status */
+-	list_for_each_safe(l, n, &final_queue) {
+-		cqr = list_entry(l, struct dasd_ccw_req, list);
+-		list_del_init(&cqr->list);
+-		if (cqr->callback != NULL)
+-			(cqr->callback)(cqr, cqr->callback_data);
+-	}
+-	spin_lock_irq(&device->request_queue_lock);
+-	spin_lock(get_ccwdev_lock(device->cdev));
+-	/* Get new request from the block device request queue */
+-	__dasd_process_blk_queue(device);
++	__dasd_device_process_final_queue(device, &final_queue);
++	spin_lock_irq(get_ccwdev_lock(device->cdev));
+ 	/* Now check if the head of the ccw queue needs to be started. */
+-	__dasd_start_head(device);
+-	spin_unlock(get_ccwdev_lock(device->cdev));
+-	spin_unlock_irq(&device->request_queue_lock);
++	__dasd_device_start_head(device);
++	spin_unlock_irq(get_ccwdev_lock(device->cdev));
+ 	dasd_put_device(device);
+ }
  
-@@ -166,17 +163,21 @@ struct vivi_dev {
- 	struct list_head           vivi_devlist;
+ /*
+  * Schedules a call to dasd_tasklet over the device tasklet.
+  */
+-void
+-dasd_schedule_bh(struct dasd_device * device)
++void dasd_schedule_device_bh(struct dasd_device *device)
+ {
+ 	/* Protect against rescheduling. */
+ 	if (atomic_cmpxchg (&device->tasklet_scheduled, 0, 1) != 0)
+@@ -1480,160 +1342,109 @@ dasd_schedule_bh(struct dasd_device * device)
+ }
  
- 	struct mutex               lock;
-+	spinlock_t                 slock;
+ /*
+- * Queue a request to the head of the ccw_queue. Start the I/O if
+- * possible.
++ * Queue a request to the head of the device ccw_queue.
++ * Start the I/O if possible.
+  */
+-void
+-dasd_add_request_head(struct dasd_ccw_req *req)
++void dasd_add_request_head(struct dasd_ccw_req *cqr)
+ {
+ 	struct dasd_device *device;
+ 	unsigned long flags;
  
- 	int                        users;
+-	device = req->device;
++	device = cqr->startdev;
+ 	spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
+-	req->status = DASD_CQR_QUEUED;
+-	req->device = device;
+-	list_add(&req->list, &device->ccw_queue);
++	cqr->status = DASD_CQR_QUEUED;
++	list_add(&cqr->devlist, &device->ccw_queue);
+ 	/* let the bh start the request to keep them in order */
+-	dasd_schedule_bh(device);
++	dasd_schedule_device_bh(device);
+ 	spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
+ }
  
- 	/* various device info */
--	struct video_device        vfd;
-+	struct video_device        *vfd;
+ /*
+- * Queue a request to the tail of the ccw_queue. Start the I/O if
+- * possible.
++ * Queue a request to the tail of the device ccw_queue.
++ * Start the I/O if possible.
+  */
+-void
+-dasd_add_request_tail(struct dasd_ccw_req *req)
++void dasd_add_request_tail(struct dasd_ccw_req *cqr)
+ {
+ 	struct dasd_device *device;
+ 	unsigned long flags;
  
- 	struct vivi_dmaqueue       vidq;
+-	device = req->device;
++	device = cqr->startdev;
+ 	spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
+-	req->status = DASD_CQR_QUEUED;
+-	req->device = device;
+-	list_add_tail(&req->list, &device->ccw_queue);
++	cqr->status = DASD_CQR_QUEUED;
++	list_add_tail(&cqr->devlist, &device->ccw_queue);
+ 	/* let the bh start the request to keep them in order */
+-	dasd_schedule_bh(device);
++	dasd_schedule_device_bh(device);
+ 	spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
+ }
  
- 	/* Several counters */
--	int                        h,m,s,us,jiffies;
-+	int                        h, m, s, ms;
-+	unsigned long              jiffies;
- 	char                       timestr[13];
-+
-+	int			   mv_count;	/* Controls bars movement */
- };
+ /*
+- * Wakeup callback.
++ * Wakeup helper for the 'sleep_on' functions.
+  */
+-static void
+-dasd_wakeup_cb(struct dasd_ccw_req *cqr, void *data)
++static void dasd_wakeup_cb(struct dasd_ccw_req *cqr, void *data)
+ {
+ 	wake_up((wait_queue_head_t *) data);
+ }
  
- struct vivi_fh {
-@@ -184,7 +185,7 @@ struct vivi_fh {
+-static inline int
+-_wait_for_wakeup(struct dasd_ccw_req *cqr)
++static inline int _wait_for_wakeup(struct dasd_ccw_req *cqr)
+ {
+ 	struct dasd_device *device;
+ 	int rc;
  
- 	/* video capture */
- 	struct vivi_fmt            *fmt;
--	unsigned int               width,height;
-+	unsigned int               width, height;
- 	struct videobuf_queue      vb_vidq;
+-	device = cqr->device;
++	device = cqr->startdev;
+ 	spin_lock_irq(get_ccwdev_lock(device->cdev));
+ 	rc = ((cqr->status == DASD_CQR_DONE ||
+-	       cqr->status == DASD_CQR_FAILED) &&
+-	      list_empty(&cqr->list));
++	       cqr->status == DASD_CQR_NEED_ERP ||
++	       cqr->status == DASD_CQR_TERMINATED) &&
++	      list_empty(&cqr->devlist));
+ 	spin_unlock_irq(get_ccwdev_lock(device->cdev));
+ 	return rc;
+ }
  
- 	enum v4l2_buf_type         type;
-@@ -203,109 +204,113 @@ enum colors {
- 	GREEN,
- 	MAGENTA,
- 	RED,
--	BLUE
-+	BLUE,
-+	BLACK,
- };
+ /*
+- * Attempts to start a special ccw queue and waits for its completion.
++ * Queue a request to the tail of the device ccw_queue and wait for
++ * it's completion.
+  */
+-int
+-dasd_sleep_on(struct dasd_ccw_req * cqr)
++int dasd_sleep_on(struct dasd_ccw_req *cqr)
+ {
+ 	wait_queue_head_t wait_q;
+ 	struct dasd_device *device;
+ 	int rc;
  
- static u8 bars[8][3] = {
- 	/* R   G   B */
--	{204,204,204},	/* white */
--	{208,208,  0},  /* ambar */
--	{  0,206,206},  /* cyan */
--	{  0,239,  0},  /* green */
--	{239,  0,239},  /* magenta */
--	{205,  0,  0},  /* red */
--	{  0,  0,255},  /* blue */
--	{  0,  0,  0}
-+	{204, 204, 204},  /* white */
-+	{208, 208,   0},  /* ambar */
-+	{  0, 206, 206},  /* cyan */
-+	{  0, 239,   0},  /* green */
-+	{239,   0, 239},  /* magenta */
-+	{205,   0,   0},  /* red */
-+	{  0,   0, 255},  /* blue */
-+	{  0,   0,   0},  /* black */
- };
+-	device = cqr->device;
+-	spin_lock_irq(get_ccwdev_lock(device->cdev));
++	device = cqr->startdev;
  
--#define TO_Y(r,g,b) (((16829*r +33039*g +6416*b  + 32768)>>16)+16)
-+#define TO_Y(r, g, b) \
-+	(((16829 * r + 33039 * g + 6416 * b  + 32768) >> 16) + 16)
- /* RGB to  V(Cr) Color transform */
--#define TO_V(r,g,b) (((28784*r -24103*g -4681*b  + 32768)>>16)+128)
-+#define TO_V(r, g, b) \
-+	(((28784 * r - 24103 * g - 4681 * b  + 32768) >> 16) + 128)
- /* RGB to  U(Cb) Color transform */
--#define TO_U(r,g,b) (((-9714*r -19070*g +28784*b + 32768)>>16)+128)
-+#define TO_U(r, g, b) \
-+	(((-9714 * r - 19070 * g + 28784 * b + 32768) >> 16) + 128)
+ 	init_waitqueue_head (&wait_q);
+ 	cqr->callback = dasd_wakeup_cb;
+ 	cqr->callback_data = (void *) &wait_q;
+-	cqr->status = DASD_CQR_QUEUED;
+-	list_add_tail(&cqr->list, &device->ccw_queue);
+-
+-	/* let the bh start the request to keep them in order */
+-	dasd_schedule_bh(device);
+-
+-	spin_unlock_irq(get_ccwdev_lock(device->cdev));
+-
++	dasd_add_request_tail(cqr);
+ 	wait_event(wait_q, _wait_for_wakeup(cqr));
  
- #define TSTAMP_MIN_Y 24
- #define TSTAMP_MAX_Y TSTAMP_MIN_Y+15
- #define TSTAMP_MIN_X 64
+ 	/* Request status is either done or failed. */
+-	rc = (cqr->status == DASD_CQR_FAILED) ? -EIO : 0;
++	rc = (cqr->status == DASD_CQR_DONE) ? 0 : -EIO;
+ 	return rc;
+ }
  
--static void gen_line(char *basep,int inipos,int wmax,
--		     int hmax, int line, int count, char *timestr)
-+static void gen_line(char *basep, int inipos, int wmax,
-+		int hmax, int line, int count, char *timestr)
+ /*
+- * Attempts to start a special ccw queue and wait interruptible
+- * for its completion.
++ * Queue a request to the tail of the device ccw_queue and wait
++ * interruptible for it's completion.
+  */
+-int
+-dasd_sleep_on_interruptible(struct dasd_ccw_req * cqr)
++int dasd_sleep_on_interruptible(struct dasd_ccw_req *cqr)
  {
--	int  w,i,j,pos=inipos,y;
--	char *p,*s;
--	u8   chr,r,g,b,color;
-+	int  w, i, j, y;
-+	int pos = inipos;
-+	char *p, *s;
-+	u8   chr, r, g, b, color;
- 
- 	/* We will just duplicate the second pixel at the packet */
--	wmax/=2;
-+	wmax /= 2;
+ 	wait_queue_head_t wait_q;
+ 	struct dasd_device *device;
+-	int rc, finished;
+-
+-	device = cqr->device;
+-	spin_lock_irq(get_ccwdev_lock(device->cdev));
++	int rc;
  
- 	/* Generate a standard color bar pattern */
--	for (w=0;w<wmax;w++) {
--		int colorpos=((w+count)*8/(wmax+1)) % 8;
--		r=bars[colorpos][0];
--		g=bars[colorpos][1];
--		b=bars[colorpos][2];
-+	for (w = 0; w < wmax; w++) {
-+		int colorpos = ((w + count) * 8/(wmax + 1)) % 8;
-+		r = bars[colorpos][0];
-+		g = bars[colorpos][1];
-+		b = bars[colorpos][2];
++	device = cqr->startdev;
+ 	init_waitqueue_head (&wait_q);
+ 	cqr->callback = dasd_wakeup_cb;
+ 	cqr->callback_data = (void *) &wait_q;
+-	cqr->status = DASD_CQR_QUEUED;
+-	list_add_tail(&cqr->list, &device->ccw_queue);
+-
+-	/* let the bh start the request to keep them in order */
+-	dasd_schedule_bh(device);
+-	spin_unlock_irq(get_ccwdev_lock(device->cdev));
+-
+-	finished = 0;
+-	while (!finished) {
+-		rc = wait_event_interruptible(wait_q, _wait_for_wakeup(cqr));
+-		if (rc != -ERESTARTSYS) {
+-			/* Request is final (done or failed) */
+-			rc = (cqr->status == DASD_CQR_DONE) ? 0 : -EIO;
+-			break;
+-		}
+-		spin_lock_irq(get_ccwdev_lock(device->cdev));
+-		switch (cqr->status) {
+-		case DASD_CQR_IN_IO:
+-                        /* terminate runnig cqr */
+-			if (device->discipline->term_IO) {
+-				cqr->retries = -1;
+-				device->discipline->term_IO(cqr);
+-				/* wait (non-interruptible) for final status
+-				 * because signal ist still pending */
+-				spin_unlock_irq(get_ccwdev_lock(device->cdev));
+-				wait_event(wait_q, _wait_for_wakeup(cqr));
+-				spin_lock_irq(get_ccwdev_lock(device->cdev));
+-				rc = (cqr->status == DASD_CQR_DONE) ? 0 : -EIO;
+-				finished = 1;
+-			}
+-			break;
+-		case DASD_CQR_QUEUED:
+-			/* request  */
+-			list_del_init(&cqr->list);
+-			rc = -EIO;
+-			finished = 1;
+-			break;
+-		default:
+-			/* cqr with 'non-interruptable' status - just wait */
+-			break;
+-		}
+-		spin_unlock_irq(get_ccwdev_lock(device->cdev));
++	dasd_add_request_tail(cqr);
++	rc = wait_event_interruptible(wait_q, _wait_for_wakeup(cqr));
++	if (rc == -ERESTARTSYS) {
++		dasd_cancel_req(cqr);
++		/* wait (non-interruptible) for final status */
++		wait_event(wait_q, _wait_for_wakeup(cqr));
+ 	}
++	rc = (cqr->status == DASD_CQR_DONE) ? 0 : -EIO;
+ 	return rc;
+ }
  
--		for (color=0;color<4;color++) {
--			p=basep+pos;
-+		for (color = 0; color < 4; color++) {
-+			p = basep + pos;
+@@ -1643,25 +1454,23 @@ dasd_sleep_on_interruptible(struct dasd_ccw_req * cqr)
+  * and be put back to status queued, before the special request is added
+  * to the head of the queue. Then the special request is waited on normally.
+  */
+-static inline int
+-_dasd_term_running_cqr(struct dasd_device *device)
++static inline int _dasd_term_running_cqr(struct dasd_device *device)
+ {
+ 	struct dasd_ccw_req *cqr;
  
- 			switch (color) {
--				case 0:
--				case 2:
--					*p=TO_Y(r,g,b);		/* Luminance */
--					break;
--				case 1:
--					*p=TO_U(r,g,b);		/* Cb */
--					break;
--				case 3:
--					*p=TO_V(r,g,b);		/* Cr */
--					break;
-+			case 0:
-+			case 2:
-+				*p = TO_Y(r, g, b);	/* Luma */
-+				break;
-+			case 1:
-+				*p = TO_U(r, g, b);	/* Cb */
-+				break;
-+			case 3:
-+				*p = TO_V(r, g, b);	/* Cr */
-+				break;
- 			}
- 			pos++;
- 		}
- 	}
+ 	if (list_empty(&device->ccw_queue))
+ 		return 0;
+-	cqr = list_entry(device->ccw_queue.next, struct dasd_ccw_req, list);
++	cqr = list_entry(device->ccw_queue.next, struct dasd_ccw_req, devlist);
+ 	return device->discipline->term_IO(cqr);
+ }
  
- 	/* Checks if it is possible to show timestamp */
--	if (TSTAMP_MAX_Y>=hmax)
-+	if (TSTAMP_MAX_Y >= hmax)
- 		goto end;
--	if (TSTAMP_MIN_X+strlen(timestr)>=wmax)
-+	if (TSTAMP_MIN_X + strlen(timestr) >= wmax)
- 		goto end;
+-int
+-dasd_sleep_on_immediatly(struct dasd_ccw_req * cqr)
++int dasd_sleep_on_immediatly(struct dasd_ccw_req *cqr)
+ {
+ 	wait_queue_head_t wait_q;
+ 	struct dasd_device *device;
+ 	int rc;
  
- 	/* Print stream time */
--	if (line>=TSTAMP_MIN_Y && line<=TSTAMP_MAX_Y) {
--		j=TSTAMP_MIN_X;
--		for (s=timestr;*s;s++) {
--			chr=rom8x16_bits[(*s-0x30)*16+line-TSTAMP_MIN_Y];
--			for (i=0;i<7;i++) {
--				if (chr&1<<(7-i)) { /* Font color*/
--					r=bars[BLUE][0];
--					g=bars[BLUE][1];
--					b=bars[BLUE][2];
--					r=g=b=0;
--					g=198;
--				} else { /* Background color */
--					r=bars[WHITE][0];
--					g=bars[WHITE][1];
--					b=bars[WHITE][2];
--					r=g=b=0;
-+	if (line >= TSTAMP_MIN_Y && line <= TSTAMP_MAX_Y) {
-+		j = TSTAMP_MIN_X;
-+		for (s = timestr; *s; s++) {
-+			chr = rom8x16_bits[(*s-0x30)*16+line-TSTAMP_MIN_Y];
-+			for (i = 0; i < 7; i++) {
-+				if (chr & 1 << (7 - i)) {
-+					/* Font color*/
-+					r = 0;
-+					g = 198;
-+					b = 0;
-+				} else {
-+					/* Background color */
-+					r = bars[BLACK][0];
-+					g = bars[BLACK][1];
-+					b = bars[BLACK][2];
- 				}
+-	device = cqr->device;
++	device = cqr->startdev;
+ 	spin_lock_irq(get_ccwdev_lock(device->cdev));
+ 	rc = _dasd_term_running_cqr(device);
+ 	if (rc) {
+@@ -1673,17 +1482,17 @@ dasd_sleep_on_immediatly(struct dasd_ccw_req * cqr)
+ 	cqr->callback = dasd_wakeup_cb;
+ 	cqr->callback_data = (void *) &wait_q;
+ 	cqr->status = DASD_CQR_QUEUED;
+-	list_add(&cqr->list, &device->ccw_queue);
++	list_add(&cqr->devlist, &device->ccw_queue);
  
--				pos=inipos+j*2;
--				for (color=0;color<4;color++) {
--					p=basep+pos;
-+				pos = inipos + j * 2;
-+				for (color = 0; color < 4; color++) {
-+					p = basep + pos;
+ 	/* let the bh start the request to keep them in order */
+-	dasd_schedule_bh(device);
++	dasd_schedule_device_bh(device);
  
--					y=TO_Y(r,g,b);
-+					y = TO_Y(r, g, b);
+ 	spin_unlock_irq(get_ccwdev_lock(device->cdev));
  
- 					switch (color) {
--						case 0:
--						case 2:
--							*p=TO_Y(r,g,b);		/* Luminance */
--							break;
--						case 1:
--							*p=TO_U(r,g,b);		/* Cb */
--							break;
--						case 3:
--							*p=TO_V(r,g,b);		/* Cr */
--							break;
-+					case 0:
-+					case 2:
-+						*p = TO_Y(r, g, b); /* Luma */
-+						break;
-+					case 1:
-+						*p = TO_U(r, g, b); /* Cb */
-+						break;
-+					case 3:
-+						*p = TO_V(r, g, b); /* Cr */
-+						break;
- 					}
- 					pos++;
- 				}
-@@ -314,63 +319,60 @@ static void gen_line(char *basep,int inipos,int wmax,
- 		}
- 	}
+ 	wait_event(wait_q, _wait_for_wakeup(cqr));
  
--
- end:
- 	return;
+ 	/* Request status is either done or failed. */
+-	rc = (cqr->status == DASD_CQR_FAILED) ? -EIO : 0;
++	rc = (cqr->status == DASD_CQR_DONE) ? 0 : -EIO;
+ 	return rc;
  }
--static void vivi_fillbuff(struct vivi_dev *dev,struct vivi_buffer *buf)
-+static void vivi_fillbuff(struct vivi_dev *dev, struct vivi_buffer *buf)
+ 
+@@ -1692,11 +1501,14 @@ dasd_sleep_on_immediatly(struct dasd_ccw_req * cqr)
+  * This is useful to timeout requests. The request will be
+  * terminated if it is currently in i/o.
+  * Returns 1 if the request has been terminated.
++ *	   0 if there was no need to terminate the request (not started yet)
++ *	   negative error code if termination failed
++ * Cancellation of a request is an asynchronous operation! The calling
++ * function has to wait until the request is properly returned via callback.
+  */
+-int
+-dasd_cancel_req(struct dasd_ccw_req *cqr)
++int dasd_cancel_req(struct dasd_ccw_req *cqr)
  {
--	int h,pos=0;
-+	int h , pos = 0;
- 	int hmax  = buf->vb.height;
- 	int wmax  = buf->vb.width;
- 	struct timeval ts;
--	char *tmpbuf = kmalloc(wmax*2,GFP_KERNEL);
--	void *vbuf=videobuf_to_vmalloc (&buf->vb);
--	/* FIXME: move to dev struct */
--	static int mv_count=0;
-+	char *tmpbuf = kmalloc(wmax * 2, GFP_KERNEL);
-+	void *vbuf = videobuf_to_vmalloc(&buf->vb);
+-	struct dasd_device *device = cqr->device;
++	struct dasd_device *device = cqr->startdev;
+ 	unsigned long flags;
+ 	int rc;
  
- 	if (!tmpbuf)
- 		return;
+@@ -1704,74 +1516,454 @@ dasd_cancel_req(struct dasd_ccw_req *cqr)
+ 	spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
+ 	switch (cqr->status) {
+ 	case DASD_CQR_QUEUED:
+-		/* request was not started - just set to failed */
+-		cqr->status = DASD_CQR_FAILED;
++		/* request was not started - just set to cleared */
++		cqr->status = DASD_CQR_CLEARED;
+ 		break;
+ 	case DASD_CQR_IN_IO:
+ 		/* request in IO - terminate IO and release again */
+-		if (device->discipline->term_IO(cqr) != 0)
+-			/* what to do if unable to terminate ??????
+-			   e.g. not _IN_IO */
+-			cqr->status = DASD_CQR_FAILED;
+-		cqr->stopclk = get_clock();
+-		rc = 1;
++		rc = device->discipline->term_IO(cqr);
++		if (rc) {
++			DEV_MESSAGE(KERN_ERR, device,
++				    "dasd_cancel_req is unable "
++				    " to terminate request %p, rc = %d",
++				    cqr, rc);
++		} else {
++			cqr->stopclk = get_clock();
++			rc = 1;
++		}
+ 		break;
+-	case DASD_CQR_DONE:
+-	case DASD_CQR_FAILED:
+-		/* already finished - do nothing */
++	default: /* already finished or clear pending - do nothing */
+ 		break;
+-	default:
+-		DEV_MESSAGE(KERN_ALERT, device,
+-			    "invalid status %02x in request",
+-			    cqr->status);
++	}
++	spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
++	dasd_schedule_device_bh(device);
++	return rc;
++}
++
++
++/*
++ * SECTION: Operations of the dasd_block layer.
++ */
++
++/*
++ * Timeout function for dasd_block. This is used when the block layer
++ * is waiting for something that may not come reliably, (e.g. a state
++ * change interrupt)
++ */
++static void dasd_block_timeout(unsigned long ptr)
++{
++	unsigned long flags;
++	struct dasd_block *block;
++
++	block = (struct dasd_block *) ptr;
++	spin_lock_irqsave(get_ccwdev_lock(block->base->cdev), flags);
++	/* re-activate request queue */
++	block->base->stopped &= ~DASD_STOPPED_PENDING;
++	spin_unlock_irqrestore(get_ccwdev_lock(block->base->cdev), flags);
++	dasd_schedule_block_bh(block);
++}
++
++/*
++ * Setup timeout for a dasd_block in jiffies.
++ */
++void dasd_block_set_timer(struct dasd_block *block, int expires)
++{
++	if (expires == 0) {
++		if (timer_pending(&block->timer))
++			del_timer(&block->timer);
++		return;
++	}
++	if (timer_pending(&block->timer)) {
++		if (mod_timer(&block->timer, jiffies + expires))
++			return;
++	}
++	block->timer.function = dasd_block_timeout;
++	block->timer.data = (unsigned long) block;
++	block->timer.expires = jiffies + expires;
++	add_timer(&block->timer);
++}
++
++/*
++ * Clear timeout for a dasd_block.
++ */
++void dasd_block_clear_timer(struct dasd_block *block)
++{
++	if (timer_pending(&block->timer))
++		del_timer(&block->timer);
++}
++
++/*
++ * posts the buffer_cache about a finalized request
++ */
++static inline void dasd_end_request(struct request *req, int error)
++{
++	if (__blk_end_request(req, error, blk_rq_bytes(req)))
+ 		BUG();
++}
++
++/*
++ * Process finished error recovery ccw.
++ */
++static inline void __dasd_block_process_erp(struct dasd_block *block,
++					    struct dasd_ccw_req *cqr)
++{
++	dasd_erp_fn_t erp_fn;
++	struct dasd_device *device = block->base;
++
++	if (cqr->status == DASD_CQR_DONE)
++		DBF_DEV_EVENT(DBF_NOTICE, device, "%s", "ERP successful");
++	else
++		DEV_MESSAGE(KERN_ERR, device, "%s", "ERP unsuccessful");
++	erp_fn = device->discipline->erp_postaction(cqr);
++	erp_fn(cqr);
++}
  
--	for (h=0;h<hmax;h++) {
--		gen_line(tmpbuf,0,wmax,hmax,h,mv_count,
-+	for (h = 0; h < hmax; h++) {
-+		gen_line(tmpbuf, 0, wmax, hmax, h, dev->mv_count,
- 			 dev->timestr);
- 		/* FIXME: replacing to __copy_to_user */
--		if (copy_to_user(vbuf+pos,tmpbuf,wmax*2)!=0)
--			dprintk(2,"vivifill copy_to_user failed.\n");
-+		if (copy_to_user(vbuf + pos, tmpbuf, wmax * 2) != 0)
-+			dprintk(dev, 2, "vivifill copy_to_user failed.\n");
- 		pos += wmax*2;
++/*
++ * Fetch requests from the block device queue.
++ */
++static void __dasd_process_request_queue(struct dasd_block *block)
++{
++	struct request_queue *queue;
++	struct request *req;
++	struct dasd_ccw_req *cqr;
++	struct dasd_device *basedev;
++	unsigned long flags;
++	queue = block->request_queue;
++	basedev = block->base;
++	/* No queue ? Then there is nothing to do. */
++	if (queue == NULL)
++		return;
++
++	/*
++	 * We requeue request from the block device queue to the ccw
++	 * queue only in two states. In state DASD_STATE_READY the
++	 * partition detection is done and we need to requeue requests
++	 * for that. State DASD_STATE_ONLINE is normal block device
++	 * operation.
++	 */
++	if (basedev->state < DASD_STATE_READY)
++		return;
++	/* Now we try to fetch requests from the request queue */
++	while (!blk_queue_plugged(queue) &&
++	       elv_next_request(queue)) {
++
++		req = elv_next_request(queue);
++
++		if (basedev->features & DASD_FEATURE_READONLY &&
++		    rq_data_dir(req) == WRITE) {
++			DBF_DEV_EVENT(DBF_ERR, basedev,
++				      "Rejecting write request %p",
++				      req);
++			blkdev_dequeue_request(req);
++			dasd_end_request(req, -EIO);
++			continue;
++		}
++		cqr = basedev->discipline->build_cp(basedev, block, req);
++		if (IS_ERR(cqr)) {
++			if (PTR_ERR(cqr) == -EBUSY)
++				break;	/* normal end condition */
++			if (PTR_ERR(cqr) == -ENOMEM)
++				break;	/* terminate request queue loop */
++			if (PTR_ERR(cqr) == -EAGAIN) {
++				/*
++				 * The current request cannot be build right
++				 * now, we have to try later. If this request
++				 * is the head-of-queue we stop the device
++				 * for 1/2 second.
++				 */
++				if (!list_empty(&block->ccw_queue))
++					break;
++				spin_lock_irqsave(get_ccwdev_lock(basedev->cdev), flags);
++				basedev->stopped |= DASD_STOPPED_PENDING;
++				spin_unlock_irqrestore(get_ccwdev_lock(basedev->cdev), flags);
++				dasd_block_set_timer(block, HZ/2);
++				break;
++			}
++			DBF_DEV_EVENT(DBF_ERR, basedev,
++				      "CCW creation failed (rc=%ld) "
++				      "on request %p",
++				      PTR_ERR(cqr), req);
++			blkdev_dequeue_request(req);
++			dasd_end_request(req, -EIO);
++			continue;
++		}
++		/*
++		 *  Note: callback is set to dasd_return_cqr_cb in
++		 * __dasd_block_start_head to cover erp requests as well
++		 */
++		cqr->callback_data = (void *) req;
++		cqr->status = DASD_CQR_FILLED;
++		blkdev_dequeue_request(req);
++		list_add_tail(&cqr->blocklist, &block->ccw_queue);
++		dasd_profile_start(block, cqr, req);
++	}
++}
++
++static void __dasd_cleanup_cqr(struct dasd_ccw_req *cqr)
++{
++	struct request *req;
++	int status;
++	int error = 0;
++
++	req = (struct request *) cqr->callback_data;
++	dasd_profile_end(cqr->block, cqr, req);
++	status = cqr->memdev->discipline->free_cp(cqr, req);
++	if (status <= 0)
++		error = status ? status : -EIO;
++	dasd_end_request(req, error);
++}
++
++/*
++ * Process ccw request queue.
++ */
++static void __dasd_process_block_ccw_queue(struct dasd_block *block,
++					   struct list_head *final_queue)
++{
++	struct list_head *l, *n;
++	struct dasd_ccw_req *cqr;
++	dasd_erp_fn_t erp_fn;
++	unsigned long flags;
++	struct dasd_device *base = block->base;
++
++restart:
++	/* Process request with final status. */
++	list_for_each_safe(l, n, &block->ccw_queue) {
++		cqr = list_entry(l, struct dasd_ccw_req, blocklist);
++		if (cqr->status != DASD_CQR_DONE &&
++		    cqr->status != DASD_CQR_FAILED &&
++		    cqr->status != DASD_CQR_NEED_ERP &&
++		    cqr->status != DASD_CQR_TERMINATED)
++			continue;
++
++		if (cqr->status == DASD_CQR_TERMINATED) {
++			base->discipline->handle_terminated_request(cqr);
++			goto restart;
++		}
++
++		/*  Process requests that may be recovered */
++		if (cqr->status == DASD_CQR_NEED_ERP) {
++			if (cqr->irb.esw.esw0.erw.cons &&
++			    test_bit(DASD_CQR_FLAGS_USE_ERP,
++				     &cqr->flags)) {
++				erp_fn = base->discipline->erp_action(cqr);
++				erp_fn(cqr);
++			}
++			goto restart;
++		}
++
++		/* First of all call extended error reporting. */
++		if (dasd_eer_enabled(base) &&
++		    cqr->status == DASD_CQR_FAILED) {
++			dasd_eer_write(base, cqr, DASD_EER_FATALERROR);
++
++			/* restart request  */
++			cqr->status = DASD_CQR_FILLED;
++			cqr->retries = 255;
++			spin_lock_irqsave(get_ccwdev_lock(base->cdev), flags);
++			base->stopped |= DASD_STOPPED_QUIESCE;
++			spin_unlock_irqrestore(get_ccwdev_lock(base->cdev),
++					       flags);
++			goto restart;
++		}
++
++		/* Process finished ERP request. */
++		if (cqr->refers) {
++			__dasd_block_process_erp(block, cqr);
++			goto restart;
++		}
++
++		/* Rechain finished requests to final queue */
++		cqr->endclk = get_clock();
++		list_move_tail(&cqr->blocklist, final_queue);
++	}
++}
++
++static void dasd_return_cqr_cb(struct dasd_ccw_req *cqr, void *data)
++{
++	dasd_schedule_block_bh(cqr->block);
++}
++
++static void __dasd_block_start_head(struct dasd_block *block)
++{
++	struct dasd_ccw_req *cqr;
++
++	if (list_empty(&block->ccw_queue))
++		return;
++	/* We allways begin with the first requests on the queue, as some
++	 * of previously started requests have to be enqueued on a
++	 * dasd_device again for error recovery.
++	 */
++	list_for_each_entry(cqr, &block->ccw_queue, blocklist) {
++		if (cqr->status != DASD_CQR_FILLED)
++			continue;
++		/* Non-temporary stop condition will trigger fail fast */
++		if (block->base->stopped & ~DASD_STOPPED_PENDING &&
++		    test_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags) &&
++		    (!dasd_eer_enabled(block->base))) {
++			cqr->status = DASD_CQR_FAILED;
++			dasd_schedule_block_bh(block);
++			continue;
++		}
++		/* Don't try to start requests if device is stopped */
++		if (block->base->stopped)
++			return;
++
++		/* just a fail safe check, should not happen */
++		if (!cqr->startdev)
++			cqr->startdev = block->base;
++
++		/* make sure that the requests we submit find their way back */
++		cqr->callback = dasd_return_cqr_cb;
++
++		dasd_add_request_tail(cqr);
++	}
++}
++
++/*
++ * Central dasd_block layer routine. Takes requests from the generic
++ * block layer request queue, creates ccw requests, enqueues them on
++ * a dasd_device and processes ccw requests that have been returned.
++ */
++static void dasd_block_tasklet(struct dasd_block *block)
++{
++	struct list_head final_queue;
++	struct list_head *l, *n;
++	struct dasd_ccw_req *cqr;
++
++	atomic_set(&block->tasklet_scheduled, 0);
++	INIT_LIST_HEAD(&final_queue);
++	spin_lock(&block->queue_lock);
++	/* Finish off requests on ccw queue */
++	__dasd_process_block_ccw_queue(block, &final_queue);
++	spin_unlock(&block->queue_lock);
++	/* Now call the callback function of requests with final status */
++	spin_lock_irq(&block->request_queue_lock);
++	list_for_each_safe(l, n, &final_queue) {
++		cqr = list_entry(l, struct dasd_ccw_req, blocklist);
++		list_del_init(&cqr->blocklist);
++		__dasd_cleanup_cqr(cqr);
++	}
++	spin_lock(&block->queue_lock);
++	/* Get new request from the block device request queue */
++	__dasd_process_request_queue(block);
++	/* Now check if the head of the ccw queue needs to be started. */
++	__dasd_block_start_head(block);
++	spin_unlock(&block->queue_lock);
++	spin_unlock_irq(&block->request_queue_lock);
++	dasd_put_device(block->base);
++}
++
++static void _dasd_wake_block_flush_cb(struct dasd_ccw_req *cqr, void *data)
++{
++	wake_up(&dasd_flush_wq);
++}
++
++/*
++ * Go through all request on the dasd_block request queue, cancel them
++ * on the respective dasd_device, and return them to the generic
++ * block layer.
++ */
++static int dasd_flush_block_queue(struct dasd_block *block)
++{
++	struct dasd_ccw_req *cqr, *n;
++	int rc, i;
++	struct list_head flush_queue;
++
++	INIT_LIST_HEAD(&flush_queue);
++	spin_lock_bh(&block->queue_lock);
++	rc = 0;
++restart:
++	list_for_each_entry_safe(cqr, n, &block->ccw_queue, blocklist) {
++		/* if this request currently owned by a dasd_device cancel it */
++		if (cqr->status >= DASD_CQR_QUEUED)
++			rc = dasd_cancel_req(cqr);
++		if (rc < 0)
++			break;
++		/* Rechain request (including erp chain) so it won't be
++		 * touched by the dasd_block_tasklet anymore.
++		 * Replace the callback so we notice when the request
++		 * is returned from the dasd_device layer.
++		 */
++		cqr->callback = _dasd_wake_block_flush_cb;
++		for (i = 0; cqr != NULL; cqr = cqr->refers, i++)
++			list_move_tail(&cqr->blocklist, &flush_queue);
++		if (i > 1)
++			/* moved more than one request - need to restart */
++			goto restart;
++	}
++	spin_unlock_bh(&block->queue_lock);
++	/* Now call the callback function of flushed requests */
++restart_cb:
++	list_for_each_entry_safe(cqr, n, &flush_queue, blocklist) {
++		wait_event(dasd_flush_wq, (cqr->status < DASD_CQR_QUEUED));
++		/* Process finished ERP request. */
++		if (cqr->refers) {
++			__dasd_block_process_erp(block, cqr);
++			/* restart list_for_xx loop since dasd_process_erp
++			 * might remove multiple elements */
++			goto restart_cb;
++		}
++		/* call the callback function */
++		cqr->endclk = get_clock();
++		list_del_init(&cqr->blocklist);
++		__dasd_cleanup_cqr(cqr);
  	}
+-	spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
+-	dasd_schedule_bh(device);
+ 	return rc;
+ }
  
--	mv_count++;
-+	dev->mv_count++;
- 
- 	kfree(tmpbuf);
- 
- 	/* Updates stream time */
+ /*
+- * SECTION: Block device operations (request queue, partitions, open, release).
++ * Schedules a call to dasd_tasklet over the device tasklet.
++ */
++void dasd_schedule_block_bh(struct dasd_block *block)
++{
++	/* Protect against rescheduling. */
++	if (atomic_cmpxchg(&block->tasklet_scheduled, 0, 1) != 0)
++		return;
++	/* life cycle of block is bound to it's base device */
++	dasd_get_device(block->base);
++	tasklet_hi_schedule(&block->tasklet);
++}
++
++
++/*
++ * SECTION: external block device operations
++ * (request queue handling, open, release, etc.)
+  */
  
--	dev->us+=jiffies_to_usecs(jiffies-dev->jiffies);
--	dev->jiffies=jiffies;
--	if (dev->us>=1000000) {
--		dev->us-=1000000;
-+	dev->ms += jiffies_to_msecs(jiffies-dev->jiffies);
-+	dev->jiffies = jiffies;
-+	if (dev->ms >= 1000) {
-+		dev->ms -= 1000;
- 		dev->s++;
--		if (dev->s>=60) {
--			dev->s-=60;
-+		if (dev->s >= 60) {
-+			dev->s -= 60;
- 			dev->m++;
--			if (dev->m>60) {
--				dev->m-=60;
-+			if (dev->m > 60) {
-+				dev->m -= 60;
- 				dev->h++;
--				if (dev->h>24)
--					dev->h-=24;
-+				if (dev->h > 24)
-+					dev->h -= 24;
- 			}
- 		}
- 	}
--	sprintf(dev->timestr,"%02d:%02d:%02d:%03d",
--			dev->h,dev->m,dev->s,(dev->us+500)/1000);
-+	sprintf(dev->timestr, "%02d:%02d:%02d:%03d",
-+			dev->h, dev->m, dev->s, dev->ms);
+ /*
+  * Dasd request queue function. Called from ll_rw_blk.c
+  */
+-static void
+-do_dasd_request(struct request_queue * queue)
++static void do_dasd_request(struct request_queue *queue)
+ {
+-	struct dasd_device *device;
++	struct dasd_block *block;
  
--	dprintk(2,"vivifill at %s: Buffer 0x%08lx size= %d\n",dev->timestr,
--			(unsigned long)tmpbuf,pos);
-+	dprintk(dev, 2, "vivifill at %s: Buffer 0x%08lx size= %d\n",
-+			dev->timestr, (unsigned long)tmpbuf, pos);
+-	device = (struct dasd_device *) queue->queuedata;
+-	spin_lock(get_ccwdev_lock(device->cdev));
++	block = queue->queuedata;
++	spin_lock(&block->queue_lock);
+ 	/* Get new request from the block device request queue */
+-	__dasd_process_blk_queue(device);
++	__dasd_process_request_queue(block);
+ 	/* Now check if the head of the ccw queue needs to be started. */
+-	__dasd_start_head(device);
+-	spin_unlock(get_ccwdev_lock(device->cdev));
++	__dasd_block_start_head(block);
++	spin_unlock(&block->queue_lock);
+ }
  
- 	/* Advice that buffer was filled */
--	buf->vb.state = STATE_DONE;
-+	buf->vb.state = VIDEOBUF_DONE;
- 	buf->vb.field_count++;
- 	do_gettimeofday(&ts);
- 	buf->vb.ts = ts;
-@@ -384,14 +386,15 @@ static int restart_video_queue(struct vivi_dmaqueue *dma_q);
- static void vivi_thread_tick(struct vivi_dmaqueue  *dma_q)
+ /*
+  * Allocate and initialize request queue and default I/O scheduler.
+  */
+-static int
+-dasd_alloc_queue(struct dasd_device * device)
++static int dasd_alloc_queue(struct dasd_block *block)
  {
- 	struct vivi_buffer    *buf;
--	struct vivi_dev *dev= container_of(dma_q,struct vivi_dev,vidq);
-+	struct vivi_dev *dev = container_of(dma_q, struct vivi_dev, vidq);
- 
- 	int bc;
+ 	int rc;
  
-+	spin_lock(&dev->slock);
- 	/* Announces videobuf that all went ok */
- 	for (bc = 0;; bc++) {
- 		if (list_empty(&dma_q->active)) {
--			dprintk(1,"No active queue to serve\n");
-+			dprintk(dev, 1, "No active queue to serve\n");
- 			break;
- 		}
+-	device->request_queue = blk_init_queue(do_dasd_request,
+-					       &device->request_queue_lock);
+-	if (device->request_queue == NULL)
++	block->request_queue = blk_init_queue(do_dasd_request,
++					       &block->request_queue_lock);
++	if (block->request_queue == NULL)
+ 		return -ENOMEM;
  
-@@ -401,65 +404,89 @@ static void vivi_thread_tick(struct vivi_dmaqueue  *dma_q)
- 		/* Nobody is waiting something to be done, just return */
- 		if (!waitqueue_active(&buf->vb.done)) {
- 			mod_timer(&dma_q->timeout, jiffies+BUFFER_TIMEOUT);
-+			spin_unlock(&dev->slock);
- 			return;
- 		}
+-	device->request_queue->queuedata = device;
++	block->request_queue->queuedata = block;
  
- 		do_gettimeofday(&buf->vb.ts);
--		dprintk(2,"[%p/%d] wakeup\n",buf,buf->vb.i);
-+		dprintk(dev, 2, "[%p/%d] wakeup\n", buf, buf->vb. i);
+-	elevator_exit(device->request_queue->elevator);
+-	rc = elevator_init(device->request_queue, "deadline");
++	elevator_exit(block->request_queue->elevator);
++	rc = elevator_init(block->request_queue, "deadline");
+ 	if (rc) {
+-		blk_cleanup_queue(device->request_queue);
++		blk_cleanup_queue(block->request_queue);
+ 		return rc;
+ 	}
+ 	return 0;
+@@ -1780,79 +1972,76 @@ dasd_alloc_queue(struct dasd_device * device)
+ /*
+  * Allocate and initialize request queue.
+  */
+-static void
+-dasd_setup_queue(struct dasd_device * device)
++static void dasd_setup_queue(struct dasd_block *block)
+ {
+ 	int max;
  
- 		/* Fill buffer */
--		vivi_fillbuff(dev,buf);
-+		vivi_fillbuff(dev, buf);
+-	blk_queue_hardsect_size(device->request_queue, device->bp_block);
+-	max = device->discipline->max_blocks << device->s2b_shift;
+-	blk_queue_max_sectors(device->request_queue, max);
+-	blk_queue_max_phys_segments(device->request_queue, -1L);
+-	blk_queue_max_hw_segments(device->request_queue, -1L);
+-	blk_queue_max_segment_size(device->request_queue, -1L);
+-	blk_queue_segment_boundary(device->request_queue, -1L);
+-	blk_queue_ordered(device->request_queue, QUEUE_ORDERED_TAG, NULL);
++	blk_queue_hardsect_size(block->request_queue, block->bp_block);
++	max = block->base->discipline->max_blocks << block->s2b_shift;
++	blk_queue_max_sectors(block->request_queue, max);
++	blk_queue_max_phys_segments(block->request_queue, -1L);
++	blk_queue_max_hw_segments(block->request_queue, -1L);
++	blk_queue_max_segment_size(block->request_queue, -1L);
++	blk_queue_segment_boundary(block->request_queue, -1L);
++	blk_queue_ordered(block->request_queue, QUEUE_ORDERED_DRAIN, NULL);
+ }
  
- 		if (list_empty(&dma_q->active)) {
- 			del_timer(&dma_q->timeout);
- 		} else {
--			mod_timer(&dma_q->timeout, jiffies+BUFFER_TIMEOUT);
-+			mod_timer(&dma_q->timeout, jiffies + BUFFER_TIMEOUT);
- 		}
+ /*
+  * Deactivate and free request queue.
+  */
+-static void
+-dasd_free_queue(struct dasd_device * device)
++static void dasd_free_queue(struct dasd_block *block)
+ {
+-	if (device->request_queue) {
+-		blk_cleanup_queue(device->request_queue);
+-		device->request_queue = NULL;
++	if (block->request_queue) {
++		blk_cleanup_queue(block->request_queue);
++		block->request_queue = NULL;
  	}
- 	if (bc != 1)
--		dprintk(1,"%s: %d buffers handled (should be 1)\n",__FUNCTION__,bc);
-+		dprintk(dev, 1, "%s: %d buffers handled (should be 1)\n",
-+			__FUNCTION__, bc);
-+	spin_unlock(&dev->slock);
  }
  
-+#define frames_to_ms(frames)					\
-+	((frames * WAKE_NUMERATOR * 1000) / WAKE_DENOMINATOR)
-+
- static void vivi_sleep(struct vivi_dmaqueue  *dma_q)
+ /*
+  * Flush request on the request queue.
+  */
+-static void
+-dasd_flush_request_queue(struct dasd_device * device)
++static void dasd_flush_request_queue(struct dasd_block *block)
  {
--	int timeout;
-+	struct vivi_dev *dev = container_of(dma_q, struct vivi_dev, vidq);
-+	int timeout, running_time;
- 	DECLARE_WAITQUEUE(wait, current);
- 
--	dprintk(1,"%s dma_q=0x%08lx\n",__FUNCTION__,(unsigned long)dma_q);
-+	dprintk(dev, 1, "%s dma_q=0x%08lx\n", __FUNCTION__,
-+		(unsigned long)dma_q);
+ 	struct request *req;
  
- 	add_wait_queue(&dma_q->wq, &wait);
--	if (!kthread_should_stop()) {
--		dma_q->frame++;
-+	if (kthread_should_stop())
-+		goto stop_task;
+-	if (!device->request_queue)
++	if (!block->request_queue)
+ 		return;
  
--		/* Calculate time to wake up */
--		timeout=dma_q->ini_jiffies+msecs_to_jiffies((dma_q->frame*WAKE_NUMERATOR*1000)/WAKE_DENOMINATOR)-jiffies;
-+	running_time = jiffies - dma_q->ini_jiffies;
-+	dma_q->frame++;
+-	spin_lock_irq(&device->request_queue_lock);
+-	while ((req = elv_next_request(device->request_queue))) {
++	spin_lock_irq(&block->request_queue_lock);
++	while ((req = elv_next_request(block->request_queue))) {
+ 		blkdev_dequeue_request(req);
+-		dasd_end_request(req, 0);
++		dasd_end_request(req, -EIO);
+ 	}
+-	spin_unlock_irq(&device->request_queue_lock);
++	spin_unlock_irq(&block->request_queue_lock);
+ }
  
--		if (timeout <= 0) {
--			int old=dma_q->frame;
--			dma_q->frame=(jiffies_to_msecs(jiffies-dma_q->ini_jiffies)*WAKE_DENOMINATOR)/(WAKE_NUMERATOR*1000)+1;
-+	/* Calculate time to wake up */
-+	timeout = msecs_to_jiffies(frames_to_ms(dma_q->frame)) - running_time;
+-static int
+-dasd_open(struct inode *inp, struct file *filp)
++static int dasd_open(struct inode *inp, struct file *filp)
+ {
+ 	struct gendisk *disk = inp->i_bdev->bd_disk;
+-	struct dasd_device *device = disk->private_data;
++	struct dasd_block *block = disk->private_data;
++	struct dasd_device *base = block->base;
+ 	int rc;
  
--			timeout=dma_q->ini_jiffies+msecs_to_jiffies((dma_q->frame*WAKE_NUMERATOR*1000)/WAKE_DENOMINATOR)-jiffies;
-+	if (timeout > msecs_to_jiffies(frames_to_ms(2)) || timeout <= 0) {
-+		int old = dma_q->frame;
-+		int nframes;
+-        atomic_inc(&device->open_count);
+-	if (test_bit(DASD_FLAG_OFFLINE, &device->flags)) {
++	atomic_inc(&block->open_count);
++	if (test_bit(DASD_FLAG_OFFLINE, &base->flags)) {
+ 		rc = -ENODEV;
+ 		goto unlock;
+ 	}
  
--			dprintk(1,"underrun, losed %d frames. "
--				  "Now, frame is %d. Waking on %d jiffies\n",
--					dma_q->frame-old,dma_q->frame,timeout);
--		} else
--			dprintk(1,"will sleep for %i jiffies\n",timeout);
-+		dma_q->frame = (jiffies_to_msecs(running_time) /
-+			       frames_to_ms(1)) + 1;
+-	if (!try_module_get(device->discipline->owner)) {
++	if (!try_module_get(base->discipline->owner)) {
+ 		rc = -EINVAL;
+ 		goto unlock;
+ 	}
  
--		vivi_thread_tick(dma_q);
-+		timeout = msecs_to_jiffies(frames_to_ms(dma_q->frame))
-+			  - running_time;
+ 	if (dasd_probeonly) {
+-		DEV_MESSAGE(KERN_INFO, device, "%s",
++		DEV_MESSAGE(KERN_INFO, base, "%s",
+ 			    "No access to device due to probeonly mode");
+ 		rc = -EPERM;
+ 		goto out;
+ 	}
  
--		schedule_timeout_interruptible (timeout);
--	}
-+		if (unlikely (timeout <= 0))
-+			timeout = 1;
-+
-+		nframes = (dma_q->frame > old)?
-+				  dma_q->frame - old : old - dma_q->frame;
-+
-+		dprintk(dev, 1, "%ld: %s %d frames. "
-+			"Current frame is %d. Will sleep for %d jiffies\n",
-+			jiffies,
-+			(dma_q->frame > old)? "Underrun, losed" : "Overrun of",
-+			nframes, dma_q->frame, timeout);
-+	} else
-+		dprintk(dev, 1, "will sleep for %d jiffies\n", timeout);
+-	if (device->state <= DASD_STATE_BASIC) {
+-		DBF_DEV_EVENT(DBF_ERR, device, " %s",
++	if (base->state <= DASD_STATE_BASIC) {
++		DBF_DEV_EVENT(DBF_ERR, base, " %s",
+ 			      " Cannot open unrecognized device");
+ 		rc = -ENODEV;
+ 		goto out;
+@@ -1861,41 +2050,41 @@ dasd_open(struct inode *inp, struct file *filp)
+ 	return 0;
  
-+	vivi_thread_tick(dma_q);
-+
-+	schedule_timeout_interruptible(timeout);
-+
-+stop_task:
- 	remove_wait_queue(&dma_q->wq, &wait);
- 	try_to_freeze();
+ out:
+-	module_put(device->discipline->owner);
++	module_put(base->discipline->owner);
+ unlock:
+-	atomic_dec(&device->open_count);
++	atomic_dec(&block->open_count);
+ 	return rc;
  }
  
- static int vivi_thread(void *data)
+-static int
+-dasd_release(struct inode *inp, struct file *filp)
++static int dasd_release(struct inode *inp, struct file *filp)
  {
--	struct vivi_dmaqueue  *dma_q=data;
-+	struct vivi_dmaqueue  *dma_q = data;
-+	struct vivi_dev *dev = container_of(dma_q, struct vivi_dev, vidq);
- 
--	dprintk(1,"thread started\n");
-+	dprintk(dev, 1, "thread started\n");
+ 	struct gendisk *disk = inp->i_bdev->bd_disk;
+-	struct dasd_device *device = disk->private_data;
++	struct dasd_block *block = disk->private_data;
  
- 	mod_timer(&dma_q->timeout, jiffies+BUFFER_TIMEOUT);
- 	set_freezable();
-@@ -470,16 +497,18 @@ static int vivi_thread(void *data)
- 		if (kthread_should_stop())
- 			break;
- 	}
--	dprintk(1, "thread: exit\n");
-+	dprintk(dev, 1, "thread: exit\n");
+-	atomic_dec(&device->open_count);
+-	module_put(device->discipline->owner);
++	atomic_dec(&block->open_count);
++	module_put(block->base->discipline->owner);
  	return 0;
  }
  
- static int vivi_start_thread(struct vivi_dmaqueue  *dma_q)
+ /*
+  * Return disk geometry.
+  */
+-static int
+-dasd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
++static int dasd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
  {
--	dma_q->frame=0;
--	dma_q->ini_jiffies=jiffies;
-+	struct vivi_dev *dev = container_of(dma_q, struct vivi_dev, vidq);
- 
--	dprintk(1,"%s\n",__FUNCTION__);
-+	dma_q->frame = 0;
-+	dma_q->ini_jiffies = jiffies;
-+
-+	dprintk(dev, 1, "%s\n", __FUNCTION__);
+-	struct dasd_device *device;
++	struct dasd_block *block;
++	struct dasd_device *base;
  
- 	dma_q->kthread = kthread_run(vivi_thread, dma_q, "vivi");
+-	device = bdev->bd_disk->private_data;
+-	if (!device)
++	block = bdev->bd_disk->private_data;
++	base = block->base;
++	if (!block)
+ 		return -ENODEV;
  
-@@ -490,39 +519,43 @@ static int vivi_start_thread(struct vivi_dmaqueue  *dma_q)
- 	/* Wakes thread */
- 	wake_up_interruptible(&dma_q->wq);
+-	if (!device->discipline ||
+-	    !device->discipline->fill_geometry)
++	if (!base->discipline ||
++	    !base->discipline->fill_geometry)
+ 		return -EINVAL;
  
--	dprintk(1,"returning from %s\n",__FUNCTION__);
-+	dprintk(dev, 1, "returning from %s\n", __FUNCTION__);
+-	device->discipline->fill_geometry(device, geo);
+-	geo->start = get_start_sect(bdev) >> device->s2b_shift;
++	base->discipline->fill_geometry(block, geo);
++	geo->start = get_start_sect(bdev) >> block->s2b_shift;
  	return 0;
  }
  
- static void vivi_stop_thread(struct vivi_dmaqueue  *dma_q)
- {
--	dprintk(1,"%s\n",__FUNCTION__);
-+	struct vivi_dev *dev = container_of(dma_q, struct vivi_dev, vidq);
-+
-+	dprintk(dev, 1, "%s\n", __FUNCTION__);
- 	/* shutdown control thread */
- 	if (dma_q->kthread) {
- 		kthread_stop(dma_q->kthread);
--		dma_q->kthread=NULL;
-+		dma_q->kthread = NULL;
- 	}
- }
- 
- static int restart_video_queue(struct vivi_dmaqueue *dma_q)
- {
-+	struct vivi_dev *dev = container_of(dma_q, struct vivi_dev, vidq);
- 	struct vivi_buffer *buf, *prev;
- 
--	dprintk(1,"%s dma_q=0x%08lx\n",__FUNCTION__,(unsigned long)dma_q);
-+	dprintk(dev, 1, "%s dma_q=0x%08lx\n", __FUNCTION__,
-+		(unsigned long)dma_q);
+@@ -1909,6 +2098,9 @@ dasd_device_operations = {
+ 	.getgeo		= dasd_getgeo,
+ };
  
- 	if (!list_empty(&dma_q->active)) {
--		buf = list_entry(dma_q->active.next, struct vivi_buffer, vb.queue);
--		dprintk(2,"restart_queue [%p/%d]: restart dma\n",
-+		buf = list_entry(dma_q->active.next,
-+				 struct vivi_buffer, vb.queue);
-+		dprintk(dev, 2, "restart_queue [%p/%d]: restart dma\n",
- 			buf, buf->vb.i);
++/*******************************************************************************
++ * end of block device operations
++ */
  
--		dprintk(1,"Restarting video dma\n");
-+		dprintk(dev, 1, "Restarting video dma\n");
- 		vivi_stop_thread(dma_q);
--//		vivi_start_thread(dma_q);
+ static void
+ dasd_exit(void)
+@@ -1937,9 +2129,8 @@ dasd_exit(void)
+  * Initial attempt at a probe function. this can be simplified once
+  * the other detection code is gone.
+  */
+-int
+-dasd_generic_probe (struct ccw_device *cdev,
+-		    struct dasd_discipline *discipline)
++int dasd_generic_probe(struct ccw_device *cdev,
++		       struct dasd_discipline *discipline)
+ {
+ 	int ret;
  
- 		/* cancel all outstanding capture / vbi requests */
- 		list_for_each_entry_safe(buf, prev, &dma_q->active, vb.queue) {
- 			list_del(&buf->vb.queue);
--			buf->vb.state = STATE_ERROR;
-+			buf->vb.state = VIDEOBUF_ERROR;
- 			wake_up(&buf->vb.done);
- 		}
- 		mod_timer(&dma_q->timeout, jiffies+BUFFER_TIMEOUT);
-@@ -534,28 +567,31 @@ static int restart_video_queue(struct vivi_dmaqueue *dma_q)
- 	for (;;) {
- 		if (list_empty(&dma_q->queued))
- 			return 0;
--		buf = list_entry(dma_q->queued.next, struct vivi_buffer, vb.queue);
-+		buf = list_entry(dma_q->queued.next,
-+				 struct vivi_buffer, vb.queue);
- 		if (NULL == prev) {
- 			list_del(&buf->vb.queue);
--			list_add_tail(&buf->vb.queue,&dma_q->active);
-+			list_add_tail(&buf->vb.queue, &dma_q->active);
+@@ -1969,19 +2160,20 @@ dasd_generic_probe (struct ccw_device *cdev,
+ 		ret = ccw_device_set_online(cdev);
+ 	if (ret)
+ 		printk(KERN_WARNING
+-		       "dasd_generic_probe: could not initially online "
+-		       "ccw-device %s\n", cdev->dev.bus_id);
+-	return ret;
++		       "dasd_generic_probe: could not initially "
++		       "online ccw-device %s; return code: %d\n",
++		       cdev->dev.bus_id, ret);
++	return 0;
+ }
  
--			dprintk(1,"Restarting video dma\n");
-+			dprintk(dev, 1, "Restarting video dma\n");
- 			vivi_stop_thread(dma_q);
- 			vivi_start_thread(dma_q);
+ /*
+  * This will one day be called from a global not_oper handler.
+  * It is also used by driver_unregister during module unload.
+  */
+-void
+-dasd_generic_remove (struct ccw_device *cdev)
++void dasd_generic_remove(struct ccw_device *cdev)
+ {
+ 	struct dasd_device *device;
++	struct dasd_block *block;
  
--			buf->vb.state = STATE_ACTIVE;
-+			buf->vb.state = VIDEOBUF_ACTIVE;
- 			mod_timer(&dma_q->timeout, jiffies+BUFFER_TIMEOUT);
--			dprintk(2,"[%p/%d] restart_queue - first active\n",
--				buf,buf->vb.i);
-+			dprintk(dev, 2,
-+				"[%p/%d] restart_queue - first active\n",
-+				buf, buf->vb.i);
+ 	cdev->handler = NULL;
  
- 		} else if (prev->vb.width  == buf->vb.width  &&
- 			   prev->vb.height == buf->vb.height &&
- 			   prev->fmt       == buf->fmt) {
- 			list_del(&buf->vb.queue);
--			list_add_tail(&buf->vb.queue,&dma_q->active);
--			buf->vb.state = STATE_ACTIVE;
--			dprintk(2,"[%p/%d] restart_queue - move to active\n",
--				buf,buf->vb.i);
-+			list_add_tail(&buf->vb.queue, &dma_q->active);
-+			buf->vb.state = VIDEOBUF_ACTIVE;
-+			dprintk(dev, 2,
-+				"[%p/%d] restart_queue - move to active\n",
-+				buf, buf->vb.i);
- 		} else {
- 			return 0;
- 		}
-@@ -565,19 +601,23 @@ static int restart_video_queue(struct vivi_dmaqueue *dma_q)
+@@ -2001,7 +2193,15 @@ dasd_generic_remove (struct ccw_device *cdev)
+ 	 */
+ 	dasd_set_target_state(device, DASD_STATE_NEW);
+ 	/* dasd_delete_device destroys the device reference. */
++	block = device->block;
++	device->block = NULL;
+ 	dasd_delete_device(device);
++	/*
++	 * life cycle of block is bound to device, so delete it after
++	 * device was safely removed
++	 */
++	if (block)
++		dasd_free_block(block);
+ }
  
- static void vivi_vid_timeout(unsigned long data)
+ /*
+@@ -2009,10 +2209,8 @@ dasd_generic_remove (struct ccw_device *cdev)
+  * the device is detected for the first time and is supposed to be used
+  * or the user has started activation through sysfs.
+  */
+-int
+-dasd_generic_set_online (struct ccw_device *cdev,
+-			 struct dasd_discipline *base_discipline)
+-
++int dasd_generic_set_online(struct ccw_device *cdev,
++			    struct dasd_discipline *base_discipline)
  {
--	struct vivi_dev      *dev  = (struct vivi_dev*)data;
-+	struct vivi_dev      *dev  = (struct vivi_dev *)data;
- 	struct vivi_dmaqueue *vidq = &dev->vidq;
- 	struct vivi_buffer   *buf;
+ 	struct dasd_discipline *discipline;
+ 	struct dasd_device *device;
+@@ -2048,6 +2246,7 @@ dasd_generic_set_online (struct ccw_device *cdev,
+ 	device->base_discipline = base_discipline;
+ 	device->discipline = discipline;
  
-+	spin_lock(&dev->slock);
-+
- 	while (!list_empty(&vidq->active)) {
--		buf = list_entry(vidq->active.next, struct vivi_buffer, vb.queue);
-+		buf = list_entry(vidq->active.next,
-+				 struct vivi_buffer, vb.queue);
- 		list_del(&buf->vb.queue);
--		buf->vb.state = STATE_ERROR;
-+		buf->vb.state = VIDEOBUF_ERROR;
- 		wake_up(&buf->vb.done);
--		printk("vivi/0: [%p/%d] timeout\n", buf, buf->vb.i);
-+		printk(KERN_INFO "vivi/0: [%p/%d] timeout\n", buf, buf->vb.i);
- 	}
--
- 	restart_video_queue(vidq);
-+
-+	spin_unlock(&dev->slock);
++	/* check_device will allocate block device if necessary */
+ 	rc = discipline->check_device(device);
+ 	if (rc) {
+ 		printk (KERN_WARNING
+@@ -2067,6 +2266,8 @@ dasd_generic_set_online (struct ccw_device *cdev,
+ 			cdev->dev.bus_id);
+ 		rc = -ENODEV;
+ 		dasd_set_target_state(device, DASD_STATE_NEW);
++		if (device->block)
++			dasd_free_block(device->block);
+ 		dasd_delete_device(device);
+ 	} else
+ 		pr_debug("dasd_generic device %s found\n",
+@@ -2081,10 +2282,10 @@ dasd_generic_set_online (struct ccw_device *cdev,
+ 	return rc;
  }
  
- /* ------------------------------------------------------------------
-@@ -586,7 +626,8 @@ static void vivi_vid_timeout(unsigned long data)
- static int
- buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size)
+-int
+-dasd_generic_set_offline (struct ccw_device *cdev)
++int dasd_generic_set_offline(struct ccw_device *cdev)
  {
--	struct vivi_fh *fh = vq->priv_data;
-+	struct vivi_fh  *fh = vq->priv_data;
-+	struct vivi_dev *dev  = fh->dev;
- 
- 	*size = fh->width*fh->height*2;
- 
-@@ -596,21 +637,25 @@ buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size)
- 	while (*size * *count > vid_limit * 1024 * 1024)
- 		(*count)--;
- 
--	dprintk(1,"%s, count=%d, size=%d\n",__FUNCTION__,*count, *size);
-+	dprintk(dev, 1, "%s, count=%d, size=%d\n", __FUNCTION__,
-+		*count, *size);
+ 	struct dasd_device *device;
++	struct dasd_block *block;
+ 	int max_count, open_count;
  
+ 	device = dasd_device_from_cdev(cdev);
+@@ -2101,30 +2302,39 @@ dasd_generic_set_offline (struct ccw_device *cdev)
+ 	 * the blkdev_get in dasd_scan_partitions. We are only interested
+ 	 * in the other openers.
+ 	 */
+-	max_count = device->bdev ? 0 : -1;
+-	open_count = (int) atomic_read(&device->open_count);
+-	if (open_count > max_count) {
+-		if (open_count > 0)
+-			printk (KERN_WARNING "Can't offline dasd device with "
+-				"open count = %i.\n",
+-				open_count);
+-		else
+-			printk (KERN_WARNING "%s",
+-				"Can't offline dasd device due to internal "
+-				"use\n");
+-		clear_bit(DASD_FLAG_OFFLINE, &device->flags);
+-		dasd_put_device(device);
+-		return -EBUSY;
++	if (device->block) {
++		struct dasd_block *block = device->block;
++		max_count = block->bdev ? 0 : -1;
++		open_count = (int) atomic_read(&block->open_count);
++		if (open_count > max_count) {
++			if (open_count > 0)
++				printk(KERN_WARNING "Can't offline dasd "
++				       "device with open count = %i.\n",
++				       open_count);
++			else
++				printk(KERN_WARNING "%s",
++				       "Can't offline dasd device due "
++				       "to internal use\n");
++			clear_bit(DASD_FLAG_OFFLINE, &device->flags);
++			dasd_put_device(device);
++			return -EBUSY;
++		}
+ 	}
+ 	dasd_set_target_state(device, DASD_STATE_NEW);
+ 	/* dasd_delete_device destroys the device reference. */
++	block = device->block;
++	device->block = NULL;
+ 	dasd_delete_device(device);
+-
++	/*
++	 * life cycle of block is bound to device, so delete it after
++	 * device was safely removed
++	 */
++	if (block)
++		dasd_free_block(block);
  	return 0;
  }
  
- static void free_buffer(struct videobuf_queue *vq, struct vivi_buffer *buf)
+-int
+-dasd_generic_notify(struct ccw_device *cdev, int event)
++int dasd_generic_notify(struct ccw_device *cdev, int event)
  {
--	dprintk(1,"%s\n",__FUNCTION__);
-+	struct vivi_fh  *fh = vq->priv_data;
-+	struct vivi_dev *dev  = fh->dev;
-+
-+	dprintk(dev, 1, "%s\n", __FUNCTION__);
+ 	struct dasd_device *device;
+ 	struct dasd_ccw_req *cqr;
+@@ -2145,27 +2355,22 @@ dasd_generic_notify(struct ccw_device *cdev, int event)
+ 		if (device->state < DASD_STATE_BASIC)
+ 			break;
+ 		/* Device is active. We want to keep it. */
+-		if (test_bit(DASD_FLAG_DSC_ERROR, &device->flags)) {
+-			list_for_each_entry(cqr, &device->ccw_queue, list)
+-				if (cqr->status == DASD_CQR_IN_IO)
+-					cqr->status = DASD_CQR_FAILED;
+-			device->stopped |= DASD_STOPPED_DC_EIO;
+-		} else {
+-			list_for_each_entry(cqr, &device->ccw_queue, list)
+-				if (cqr->status == DASD_CQR_IN_IO) {
+-					cqr->status = DASD_CQR_QUEUED;
+-					cqr->retries++;
+-				}
+-			device->stopped |= DASD_STOPPED_DC_WAIT;
+-			dasd_set_timer(device, 0);
+-		}
+-		dasd_schedule_bh(device);
++		list_for_each_entry(cqr, &device->ccw_queue, devlist)
++			if (cqr->status == DASD_CQR_IN_IO) {
++				cqr->status = DASD_CQR_QUEUED;
++				cqr->retries++;
++			}
++		device->stopped |= DASD_STOPPED_DC_WAIT;
++		dasd_device_clear_timer(device);
++		dasd_schedule_device_bh(device);
+ 		ret = 1;
+ 		break;
+ 	case CIO_OPER:
+ 		/* FIXME: add a sanity check. */
+-		device->stopped &= ~(DASD_STOPPED_DC_WAIT|DASD_STOPPED_DC_EIO);
+-		dasd_schedule_bh(device);
++		device->stopped &= ~DASD_STOPPED_DC_WAIT;
++		dasd_schedule_device_bh(device);
++		if (device->block)
++			dasd_schedule_block_bh(device->block);
+ 		ret = 1;
+ 		break;
+ 	}
+@@ -2195,7 +2400,8 @@ static struct dasd_ccw_req *dasd_generic_build_rdc(struct dasd_device *device,
+ 	ccw->cda = (__u32)(addr_t)rdc_buffer;
+ 	ccw->count = rdc_buffer_size;
  
- 	if (in_interrupt())
- 		BUG();
+-	cqr->device = device;
++	cqr->startdev = device;
++	cqr->memdev = device;
+ 	cqr->expires = 10*HZ;
+ 	clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
+ 	cqr->retries = 2;
+@@ -2217,13 +2423,12 @@ int dasd_generic_read_dev_chars(struct dasd_device *device, char *magic,
+ 		return PTR_ERR(cqr);
  
--	videobuf_waiton(&buf->vb,0,0);
-+	videobuf_waiton(&buf->vb, 0, 0);
- 	videobuf_vmalloc_free(&buf->vb);
--	buf->vb.state = STATE_NEEDS_INIT;
-+	buf->vb.state = VIDEOBUF_NEEDS_INIT;
+ 	ret = dasd_sleep_on(cqr);
+-	dasd_sfree_request(cqr, cqr->device);
++	dasd_sfree_request(cqr, cqr->memdev);
+ 	return ret;
  }
+ EXPORT_SYMBOL_GPL(dasd_generic_read_dev_chars);
  
- #define norm_maxw() 1024
-@@ -620,10 +665,11 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
- 						enum v4l2_field field)
+-static int __init
+-dasd_init(void)
++static int __init dasd_init(void)
  {
- 	struct vivi_fh     *fh  = vq->priv_data;
--	struct vivi_buffer *buf = container_of(vb,struct vivi_buffer,vb);
-+	struct vivi_dev    *dev = fh->dev;
-+	struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb);
- 	int rc, init_buffer = 0;
- 
--	dprintk(1,"%s, field=%d\n",__FUNCTION__,field);
-+	dprintk(dev, 1, "%s, field=%d\n", __FUNCTION__, field);
- 
- 	BUG_ON(NULL == fh->fmt);
- 	if (fh->width  < 48 || fh->width  > norm_maxw() ||
-@@ -644,75 +690,81 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
- 		init_buffer = 1;
- 	}
- 
--	if (STATE_NEEDS_INIT == buf->vb.state) {
--		if (0 != (rc = videobuf_iolock(vq,&buf->vb,NULL)))
-+	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
-+		rc = videobuf_iolock(vq, &buf->vb, NULL);
-+		if (rc < 0)
- 			goto fail;
- 	}
- 
--	buf->vb.state = STATE_PREPARED;
-+	buf->vb.state = VIDEOBUF_PREPARED;
+ 	int rc;
  
- 	return 0;
+@@ -2231,7 +2436,7 @@ dasd_init(void)
+ 	init_waitqueue_head(&dasd_flush_wq);
  
- fail:
--	free_buffer(vq,buf);
-+	free_buffer(vq, buf);
- 	return rc;
- }
+ 	/* register 'common' DASD debug area, used for all DBF_XXX calls */
+-	dasd_debug_area = debug_register("dasd", 1, 2, 8 * sizeof (long));
++	dasd_debug_area = debug_register("dasd", 1, 1, 8 * sizeof(long));
+ 	if (dasd_debug_area == NULL) {
+ 		rc = -ENOMEM;
+ 		goto failed;
+@@ -2277,15 +2482,18 @@ EXPORT_SYMBOL(dasd_diag_discipline_pointer);
+ EXPORT_SYMBOL(dasd_add_request_head);
+ EXPORT_SYMBOL(dasd_add_request_tail);
+ EXPORT_SYMBOL(dasd_cancel_req);
+-EXPORT_SYMBOL(dasd_clear_timer);
++EXPORT_SYMBOL(dasd_device_clear_timer);
++EXPORT_SYMBOL(dasd_block_clear_timer);
+ EXPORT_SYMBOL(dasd_enable_device);
+ EXPORT_SYMBOL(dasd_int_handler);
+ EXPORT_SYMBOL(dasd_kfree_request);
+ EXPORT_SYMBOL(dasd_kick_device);
+ EXPORT_SYMBOL(dasd_kmalloc_request);
+-EXPORT_SYMBOL(dasd_schedule_bh);
++EXPORT_SYMBOL(dasd_schedule_device_bh);
++EXPORT_SYMBOL(dasd_schedule_block_bh);
+ EXPORT_SYMBOL(dasd_set_target_state);
+-EXPORT_SYMBOL(dasd_set_timer);
++EXPORT_SYMBOL(dasd_device_set_timer);
++EXPORT_SYMBOL(dasd_block_set_timer);
+ EXPORT_SYMBOL(dasd_sfree_request);
+ EXPORT_SYMBOL(dasd_sleep_on);
+ EXPORT_SYMBOL(dasd_sleep_on_immediatly);
+@@ -2299,4 +2507,7 @@ EXPORT_SYMBOL_GPL(dasd_generic_remove);
+ EXPORT_SYMBOL_GPL(dasd_generic_notify);
+ EXPORT_SYMBOL_GPL(dasd_generic_set_online);
+ EXPORT_SYMBOL_GPL(dasd_generic_set_offline);
+-
++EXPORT_SYMBOL_GPL(dasd_generic_handle_state_change);
++EXPORT_SYMBOL_GPL(dasd_flush_device_queue);
++EXPORT_SYMBOL_GPL(dasd_alloc_block);
++EXPORT_SYMBOL_GPL(dasd_free_block);
+diff --git a/drivers/s390/block/dasd_3370_erp.c b/drivers/s390/block/dasd_3370_erp.c
+deleted file mode 100644
+index 1ddab89..0000000
+--- a/drivers/s390/block/dasd_3370_erp.c
++++ /dev/null
+@@ -1,84 +0,0 @@
+-/*
+- * File...........: linux/drivers/s390/block/dasd_3370_erp.c
+- * Author(s)......: Holger Smolinski <Holger.Smolinski at de.ibm.com>
+- * Bugreports.to..: <Linux390 at de.ibm.com>
+- * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000
+- *
+- */
+-
+-#define PRINTK_HEADER "dasd_erp(3370)"
+-
+-#include "dasd_int.h"
+-
+-
+-/*
+- * DASD_3370_ERP_EXAMINE
+- *
+- * DESCRIPTION
+- *   Checks only for fatal/no/recover error.
+- *   A detailed examination of the sense data is done later outside
+- *   the interrupt handler.
+- *
+- *   The logic is based on the 'IBM 3880 Storage Control Reference' manual
+- *   'Chapter 7. 3370 Sense Data'.
+- *
+- * RETURN VALUES
+- *   dasd_era_none	no error
+- *   dasd_era_fatal	for all fatal (unrecoverable errors)
+- *   dasd_era_recover	for all others.
+- */
+-dasd_era_t
+-dasd_3370_erp_examine(struct dasd_ccw_req * cqr, struct irb * irb)
+-{
+-	char *sense = irb->ecw;
+-
+-	/* check for successful execution first */
+-	if (irb->scsw.cstat == 0x00 &&
+-	    irb->scsw.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))
+-		return dasd_era_none;
+-	if (sense[0] & 0x80) {	/* CMD reject */
+-		return dasd_era_fatal;
+-	}
+-	if (sense[0] & 0x40) {	/* Drive offline */
+-		return dasd_era_recover;
+-	}
+-	if (sense[0] & 0x20) {	/* Bus out parity */
+-		return dasd_era_recover;
+-	}
+-	if (sense[0] & 0x10) {	/* equipment check */
+-		if (sense[1] & 0x80) {
+-			return dasd_era_fatal;
+-		}
+-		return dasd_era_recover;
+-	}
+-	if (sense[0] & 0x08) {	/* data check */
+-		if (sense[1] & 0x80) {
+-			return dasd_era_fatal;
+-		}
+-		return dasd_era_recover;
+-	}
+-	if (sense[0] & 0x04) {	/* overrun */
+-		if (sense[1] & 0x80) {
+-			return dasd_era_fatal;
+-		}
+-		return dasd_era_recover;
+-	}
+-	if (sense[1] & 0x40) {	/* invalid blocksize */
+-		return dasd_era_fatal;
+-	}
+-	if (sense[1] & 0x04) {	/* file protected */
+-		return dasd_era_recover;
+-	}
+-	if (sense[1] & 0x01) {	/* operation incomplete */
+-		return dasd_era_recover;
+-	}
+-	if (sense[2] & 0x80) {	/* check data erroor */
+-		return dasd_era_recover;
+-	}
+-	if (sense[2] & 0x10) {	/* Env. data present */
+-		return dasd_era_recover;
+-	}
+-	/* examine the 24 byte sense data */
+-	return dasd_era_recover;
+-
+-}				/* END dasd_3370_erp_examine */
+diff --git a/drivers/s390/block/dasd_3990_erp.c b/drivers/s390/block/dasd_3990_erp.c
+index 5b7385e..c361ab6 100644
+--- a/drivers/s390/block/dasd_3990_erp.c
++++ b/drivers/s390/block/dasd_3990_erp.c
+@@ -26,158 +26,6 @@ struct DCTL_data {
  
- static void
- buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+ /*
+  *****************************************************************************
+- * SECTION ERP EXAMINATION
+- *****************************************************************************
+- */
+-
+-/*
+- * DASD_3990_ERP_EXAMINE_24
+- *
+- * DESCRIPTION
+- *   Checks only for fatal (unrecoverable) error.
+- *   A detailed examination of the sense data is done later outside
+- *   the interrupt handler.
+- *
+- *   Each bit configuration leading to an action code 2 (Exit with
+- *   programming error or unusual condition indication)
+- *   are handled as fatal errors.
+- *
+- *   All other configurations are handled as recoverable errors.
+- *
+- * RETURN VALUES
+- *   dasd_era_fatal	for all fatal (unrecoverable errors)
+- *   dasd_era_recover	for all others.
+- */
+-static dasd_era_t
+-dasd_3990_erp_examine_24(struct dasd_ccw_req * cqr, char *sense)
+-{
+-
+-	struct dasd_device *device = cqr->device;
+-
+-	/* check for 'Command Reject' */
+-	if ((sense[0] & SNS0_CMD_REJECT) &&
+-	    (!(sense[2] & SNS2_ENV_DATA_PRESENT))) {
+-
+-		DEV_MESSAGE(KERN_ERR, device, "%s",
+-			    "EXAMINE 24: Command Reject detected - "
+-			    "fatal error");
+-
+-		return dasd_era_fatal;
+-	}
+-
+-	/* check for 'Invalid Track Format' */
+-	if ((sense[1] & SNS1_INV_TRACK_FORMAT) &&
+-	    (!(sense[2] & SNS2_ENV_DATA_PRESENT))) {
+-
+-		DEV_MESSAGE(KERN_ERR, device, "%s",
+-			    "EXAMINE 24: Invalid Track Format detected "
+-			    "- fatal error");
+-
+-		return dasd_era_fatal;
+-	}
+-
+-	/* check for 'No Record Found' */
+-	if (sense[1] & SNS1_NO_REC_FOUND) {
+-
+-                /* FIXME: fatal error ?!? */
+-		DEV_MESSAGE(KERN_ERR, device,
+-			    "EXAMINE 24: No Record Found detected %s",
+-                            device->state <= DASD_STATE_BASIC ?
+-			    " " : "- fatal error");
+-
+-		return dasd_era_fatal;
+-	}
+-
+-	/* return recoverable for all others */
+-	return dasd_era_recover;
+-}				/* END dasd_3990_erp_examine_24 */
+-
+-/*
+- * DASD_3990_ERP_EXAMINE_32
+- *
+- * DESCRIPTION
+- *   Checks only for fatal/no/recoverable error.
+- *   A detailed examination of the sense data is done later outside
+- *   the interrupt handler.
+- *
+- * RETURN VALUES
+- *   dasd_era_none	no error
+- *   dasd_era_fatal	for all fatal (unrecoverable errors)
+- *   dasd_era_recover	for recoverable others.
+- */
+-static dasd_era_t
+-dasd_3990_erp_examine_32(struct dasd_ccw_req * cqr, char *sense)
+-{
+-
+-	struct dasd_device *device = cqr->device;
+-
+-	switch (sense[25]) {
+-	case 0x00:
+-		return dasd_era_none;
+-
+-	case 0x01:
+-		DEV_MESSAGE(KERN_ERR, device, "%s", "EXAMINE 32: fatal error");
+-
+-		return dasd_era_fatal;
+-
+-	default:
+-
+-		return dasd_era_recover;
+-	}
+-
+-}				/* end dasd_3990_erp_examine_32 */
+-
+-/*
+- * DASD_3990_ERP_EXAMINE
+- *
+- * DESCRIPTION
+- *   Checks only for fatal/no/recover error.
+- *   A detailed examination of the sense data is done later outside
+- *   the interrupt handler.
+- *
+- *   The logic is based on the 'IBM 3990 Storage Control  Reference' manual
+- *   'Chapter 7. Error Recovery Procedures'.
+- *
+- * RETURN VALUES
+- *   dasd_era_none	no error
+- *   dasd_era_fatal	for all fatal (unrecoverable errors)
+- *   dasd_era_recover	for all others.
+- */
+-dasd_era_t
+-dasd_3990_erp_examine(struct dasd_ccw_req * cqr, struct irb * irb)
+-{
+-
+-	char *sense = irb->ecw;
+-	dasd_era_t era = dasd_era_recover;
+-	struct dasd_device *device = cqr->device;
+-
+-	/* check for successful execution first */
+-	if (irb->scsw.cstat == 0x00 &&
+-	    irb->scsw.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))
+-		return dasd_era_none;
+-
+-	/* distinguish between 24 and 32 byte sense data */
+-	if (sense[27] & DASD_SENSE_BIT_0) {
+-
+-		era = dasd_3990_erp_examine_24(cqr, sense);
+-
+-	} else {
+-
+-		era = dasd_3990_erp_examine_32(cqr, sense);
+-
+-	}
+-
+-	/* log the erp chain if fatal error occurred */
+-	if ((era == dasd_era_fatal) && (device->state >= DASD_STATE_READY)) {
+-		dasd_log_sense(cqr, irb);
+-	}
+-
+-	return era;
+-
+-}				/* END dasd_3990_erp_examine */
+-
+-/*
+- *****************************************************************************
+  * SECTION ERP HANDLING
+  *****************************************************************************
+  */
+@@ -206,7 +54,7 @@ dasd_3990_erp_cleanup(struct dasd_ccw_req * erp, char final_status)
  {
--	struct vivi_buffer    *buf     = container_of(vb,struct vivi_buffer,vb);
--	struct vivi_fh        *fh      = vq->priv_data;
--	struct vivi_dev       *dev     = fh->dev;
--	struct vivi_dmaqueue  *vidq    = &dev->vidq;
-+	struct vivi_buffer    *buf  = container_of(vb, struct vivi_buffer, vb);
-+	struct vivi_fh        *fh   = vq->priv_data;
-+	struct vivi_dev       *dev  = fh->dev;
-+	struct vivi_dmaqueue  *vidq = &dev->vidq;
- 	struct vivi_buffer    *prev;
- 
- 	if (!list_empty(&vidq->queued)) {
--		dprintk(1,"adding vb queue=0x%08lx\n",(unsigned long)&buf->vb.queue);
--		list_add_tail(&buf->vb.queue,&vidq->queued);
--		buf->vb.state = STATE_QUEUED;
--		dprintk(2,"[%p/%d] buffer_queue - append to queued\n",
-+		dprintk(dev, 1, "adding vb queue=0x%08lx\n",
-+			(unsigned long)&buf->vb.queue);
-+		list_add_tail(&buf->vb.queue, &vidq->queued);
-+		buf->vb.state = VIDEOBUF_QUEUED;
-+		dprintk(dev, 2, "[%p/%d] buffer_queue - append to queued\n",
- 			buf, buf->vb.i);
- 	} else if (list_empty(&vidq->active)) {
--		list_add_tail(&buf->vb.queue,&vidq->active);
-+		list_add_tail(&buf->vb.queue, &vidq->active);
- 
--		buf->vb.state = STATE_ACTIVE;
-+		buf->vb.state = VIDEOBUF_ACTIVE;
- 		mod_timer(&vidq->timeout, jiffies+BUFFER_TIMEOUT);
--		dprintk(2,"[%p/%d] buffer_queue - first active\n",
-+		dprintk(dev, 2, "[%p/%d] buffer_queue - first active\n",
- 			buf, buf->vb.i);
- 
- 		vivi_start_thread(vidq);
- 	} else {
--		prev = list_entry(vidq->active.prev, struct vivi_buffer, vb.queue);
-+		prev = list_entry(vidq->active.prev,
-+				  struct vivi_buffer, vb.queue);
- 		if (prev->vb.width  == buf->vb.width  &&
- 		    prev->vb.height == buf->vb.height &&
- 		    prev->fmt       == buf->fmt) {
--			list_add_tail(&buf->vb.queue,&vidq->active);
--			buf->vb.state = STATE_ACTIVE;
--			dprintk(2,"[%p/%d] buffer_queue - append to active\n",
-+			list_add_tail(&buf->vb.queue, &vidq->active);
-+			buf->vb.state = VIDEOBUF_ACTIVE;
-+			dprintk(dev, 2,
-+				"[%p/%d] buffer_queue - append to active\n",
- 				buf, buf->vb.i);
+ 	struct dasd_ccw_req *cqr = erp->refers;
  
- 		} else {
--			list_add_tail(&buf->vb.queue,&vidq->queued);
--			buf->vb.state = STATE_QUEUED;
--			dprintk(2,"[%p/%d] buffer_queue - first queued\n",
-+			list_add_tail(&buf->vb.queue, &vidq->queued);
-+			buf->vb.state = VIDEOBUF_QUEUED;
-+			dprintk(dev, 2,
-+				"[%p/%d] buffer_queue - first queued\n",
- 				buf, buf->vb.i);
- 		}
- 	}
- }
+-	dasd_free_erp_request(erp, erp->device);
++	dasd_free_erp_request(erp, erp->memdev);
+ 	cqr->status = final_status;
+ 	return cqr;
  
--static void buffer_release(struct videobuf_queue *vq, struct videobuf_buffer *vb)
-+static void buffer_release(struct videobuf_queue *vq,
-+			   struct videobuf_buffer *vb)
+@@ -224,15 +72,17 @@ static void
+ dasd_3990_erp_block_queue(struct dasd_ccw_req * erp, int expires)
  {
--	struct vivi_buffer   *buf  = container_of(vb,struct vivi_buffer,vb);
-+	struct vivi_buffer   *buf  = container_of(vb, struct vivi_buffer, vb);
- 	struct vivi_fh       *fh   = vq->priv_data;
--	struct vivi_dev      *dev  = (struct vivi_dev*)fh->dev;
-+	struct vivi_dev      *dev  = (struct vivi_dev *)fh->dev;
- 	struct vivi_dmaqueue *vidq = &dev->vidq;
- 
--	dprintk(1,"%s\n",__FUNCTION__);
-+	dprintk(dev, 1, "%s\n", __FUNCTION__);
- 
- 	vivi_stop_thread(vidq);
- 
--	free_buffer(vq,buf);
-+	free_buffer(vq, buf);
- }
  
- static struct videobuf_queue_ops vivi_video_qops = {
-@@ -725,7 +777,7 @@ static struct videobuf_queue_ops vivi_video_qops = {
- /* ------------------------------------------------------------------
- 	IOCTL vidioc handling
-    ------------------------------------------------------------------*/
--static int vidioc_querycap (struct file *file, void  *priv,
-+static int vidioc_querycap(struct file *file, void  *priv,
- 					struct v4l2_capability *cap)
- {
- 	strcpy(cap->driver, "vivi");
-@@ -737,21 +789,21 @@ static int vidioc_querycap (struct file *file, void  *priv,
- 	return 0;
- }
+-	struct dasd_device *device = erp->device;
++	struct dasd_device *device = erp->startdev;
++	unsigned long flags;
  
--static int vidioc_enum_fmt_cap (struct file *file, void  *priv,
-+static int vidioc_enum_fmt_cap(struct file *file, void  *priv,
- 					struct v4l2_fmtdesc *f)
- {
- 	if (f->index > 0)
- 		return -EINVAL;
+ 	DEV_MESSAGE(KERN_INFO, device,
+ 		    "blocking request queue for %is", expires/HZ);
  
--	strlcpy(f->description,format.name,sizeof(f->description));
-+	strlcpy(f->description, format.name, sizeof(f->description));
- 	f->pixelformat = format.fourcc;
- 	return 0;
++	spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
+ 	device->stopped |= DASD_STOPPED_PENDING;
+-	erp->status = DASD_CQR_QUEUED;
+-
+-	dasd_set_timer(device, expires);
++	spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
++	erp->status = DASD_CQR_FILLED;
++	dasd_block_set_timer(device->block, expires);
  }
  
--static int vidioc_g_fmt_cap (struct file *file, void *priv,
-+static int vidioc_g_fmt_cap(struct file *file, void *priv,
- 					struct v4l2_format *f)
+ /*
+@@ -251,7 +101,7 @@ static struct dasd_ccw_req *
+ dasd_3990_erp_int_req(struct dasd_ccw_req * erp)
  {
--	struct vivi_fh  *fh=priv;
-+	struct vivi_fh *fh = priv;
  
- 	f->fmt.pix.width        = fh->width;
- 	f->fmt.pix.height       = fh->height;
-@@ -765,26 +817,29 @@ static int vidioc_g_fmt_cap (struct file *file, void *priv,
- 	return (0);
- }
+-	struct dasd_device *device = erp->device;
++	struct dasd_device *device = erp->startdev;
  
--static int vidioc_try_fmt_cap (struct file *file, void *priv,
-+static int vidioc_try_fmt_cap(struct file *file, void *priv,
- 			struct v4l2_format *f)
+ 	/* first time set initial retry counter and erp_function */
+ 	/* and retry once without blocking queue		 */
+@@ -292,11 +142,14 @@ dasd_3990_erp_int_req(struct dasd_ccw_req * erp)
+ static void
+ dasd_3990_erp_alternate_path(struct dasd_ccw_req * erp)
  {
-+	struct vivi_fh  *fh  = priv;
-+	struct vivi_dev *dev = fh->dev;
- 	struct vivi_fmt *fmt;
- 	enum v4l2_field field;
- 	unsigned int maxw, maxh;
+-	struct dasd_device *device = erp->device;
++	struct dasd_device *device = erp->startdev;
+ 	__u8 opm;
++	unsigned long flags;
  
- 	if (format.fourcc != f->fmt.pix.pixelformat) {
--		dprintk(1,"Fourcc format (0x%08x) invalid. Driver accepts "
--			"only 0x%08x\n",f->fmt.pix.pixelformat,format.fourcc);
-+		dprintk(dev, 1, "Fourcc format (0x%08x) invalid. "
-+			"Driver accepts only 0x%08x\n",
-+			f->fmt.pix.pixelformat, format.fourcc);
- 		return -EINVAL;
- 	}
--	fmt=&format;
-+	fmt = &format;
+ 	/* try alternate valid path */
++	spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
+ 	opm = ccw_device_get_path_mask(device->cdev);
++	spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
+ 	//FIXME: start with get_opm ?
+ 	if (erp->lpm == 0)
+ 		erp->lpm = LPM_ANYPATH & ~(erp->irb.esw.esw0.sublog.lpum);
+@@ -309,9 +162,8 @@ dasd_3990_erp_alternate_path(struct dasd_ccw_req * erp)
+ 			    "try alternate lpm=%x (lpum=%x / opm=%x)",
+ 			    erp->lpm, erp->irb.esw.esw0.sublog.lpum, opm);
  
- 	field = f->fmt.pix.field;
+-		/* reset status to queued to handle the request again... */
+-		if (erp->status > DASD_CQR_QUEUED)
+-			erp->status = DASD_CQR_QUEUED;
++		/* reset status to submit the request again... */
++		erp->status = DASD_CQR_FILLED;
+ 		erp->retries = 1;
+ 	} else {
+ 		DEV_MESSAGE(KERN_ERR, device,
+@@ -320,8 +172,7 @@ dasd_3990_erp_alternate_path(struct dasd_ccw_req * erp)
+ 			    erp->irb.esw.esw0.sublog.lpum, opm);
  
- 	if (field == V4L2_FIELD_ANY) {
--		field=V4L2_FIELD_INTERLACED;
-+		field = V4L2_FIELD_INTERLACED;
- 	} else if (V4L2_FIELD_INTERLACED != field) {
--		dprintk(1,"Field type invalid.\n");
-+		dprintk(dev, 1, "Field type invalid.\n");
- 		return -EINVAL;
+ 		/* post request with permanent error */
+-		if (erp->status > DASD_CQR_QUEUED)
+-			erp->status = DASD_CQR_FAILED;
++		erp->status = DASD_CQR_FAILED;
  	}
+ }				/* end dasd_3990_erp_alternate_path */
  
-@@ -810,11 +865,11 @@ static int vidioc_try_fmt_cap (struct file *file, void *priv,
- }
- 
- /*FIXME: This seems to be generic enough to be at videodev2 */
--static int vidioc_s_fmt_cap (struct file *file, void *priv,
-+static int vidioc_s_fmt_cap(struct file *file, void *priv,
- 					struct v4l2_format *f)
+@@ -344,14 +195,14 @@ static struct dasd_ccw_req *
+ dasd_3990_erp_DCTL(struct dasd_ccw_req * erp, char modifier)
  {
--	struct vivi_fh  *fh=priv;
--	int ret = vidioc_try_fmt_cap(file,fh,f);
-+	struct vivi_fh  *fh = priv;
-+	int ret = vidioc_try_fmt_cap(file, fh, f);
- 	if (ret < 0)
- 		return (ret);
- 
-@@ -827,47 +882,48 @@ static int vidioc_s_fmt_cap (struct file *file, void *priv,
- 	return (0);
- }
  
--static int vidioc_reqbufs (struct file *file, void *priv, struct v4l2_requestbuffers *p)
-+static int vidioc_reqbufs(struct file *file, void *priv,
-+			  struct v4l2_requestbuffers *p)
- {
--	struct vivi_fh  *fh=priv;
-+	struct vivi_fh  *fh = priv;
+-	struct dasd_device *device = erp->device;
++	struct dasd_device *device = erp->startdev;
+ 	struct DCTL_data *DCTL_data;
+ 	struct ccw1 *ccw;
+ 	struct dasd_ccw_req *dctl_cqr;
  
- 	return (videobuf_reqbufs(&fh->vb_vidq, p));
- }
+ 	dctl_cqr = dasd_alloc_erp_request((char *) &erp->magic, 1,
+-					  sizeof (struct DCTL_data),
+-					  erp->device);
++					  sizeof(struct DCTL_data),
++					  device);
+ 	if (IS_ERR(dctl_cqr)) {
+ 		DEV_MESSAGE(KERN_ERR, device, "%s",
+ 			    "Unable to allocate DCTL-CQR");
+@@ -365,13 +216,14 @@ dasd_3990_erp_DCTL(struct dasd_ccw_req * erp, char modifier)
+ 	DCTL_data->modifier = modifier;
  
--static int vidioc_querybuf (struct file *file, void *priv, struct v4l2_buffer *p)
-+static int vidioc_querybuf(struct file *file, void *priv, struct v4l2_buffer *p)
+ 	ccw = dctl_cqr->cpaddr;
+-	memset(ccw, 0, sizeof (struct ccw1));
++	memset(ccw, 0, sizeof(struct ccw1));
+ 	ccw->cmd_code = CCW_CMD_DCTL;
+ 	ccw->count = 4;
+ 	ccw->cda = (__u32)(addr_t) DCTL_data;
+ 	dctl_cqr->function = dasd_3990_erp_DCTL;
+ 	dctl_cqr->refers = erp;
+-	dctl_cqr->device = erp->device;
++	dctl_cqr->startdev = device;
++	dctl_cqr->memdev = device;
+ 	dctl_cqr->magic = erp->magic;
+ 	dctl_cqr->expires = 5 * 60 * HZ;
+ 	dctl_cqr->retries = 2;
+@@ -435,7 +287,7 @@ static struct dasd_ccw_req *
+ dasd_3990_erp_action_4(struct dasd_ccw_req * erp, char *sense)
  {
--	struct vivi_fh  *fh=priv;
-+	struct vivi_fh  *fh = priv;
  
- 	return (videobuf_querybuf(&fh->vb_vidq, p));
- }
- 
--static int vidioc_qbuf (struct file *file, void *priv, struct v4l2_buffer *p)
-+static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
- {
--	struct vivi_fh  *fh=priv;
-+	struct vivi_fh *fh = priv;
+-	struct dasd_device *device = erp->device;
++	struct dasd_device *device = erp->startdev;
  
- 	return (videobuf_qbuf(&fh->vb_vidq, p));
- }
+ 	/* first time set initial retry counter and erp_function    */
+ 	/* and retry once without waiting for state change pending  */
+@@ -472,7 +324,7 @@ dasd_3990_erp_action_4(struct dasd_ccw_req * erp, char *sense)
+ 				     "redriving request immediately, "
+ 				     "%d retries left",
+ 				     erp->retries);
+-			erp->status = DASD_CQR_QUEUED;
++			erp->status = DASD_CQR_FILLED;
+ 		}
+ 	}
  
--static int vidioc_dqbuf (struct file *file, void *priv, struct v4l2_buffer *p)
-+static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
+@@ -530,7 +382,7 @@ static void
+ dasd_3990_handle_env_data(struct dasd_ccw_req * erp, char *sense)
  {
--	struct vivi_fh  *fh=priv;
-+	struct vivi_fh  *fh = priv;
  
- 	return (videobuf_dqbuf(&fh->vb_vidq, p,
- 				file->f_flags & O_NONBLOCK));
- }
+-	struct dasd_device *device = erp->device;
++	struct dasd_device *device = erp->startdev;
+ 	char msg_format = (sense[7] & 0xF0);
+ 	char msg_no = (sense[7] & 0x0F);
  
- #ifdef CONFIG_VIDEO_V4L1_COMPAT
--static int vidiocgmbuf (struct file *file, void *priv, struct video_mbuf *mbuf)
-+static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf)
+@@ -1157,7 +1009,7 @@ static struct dasd_ccw_req *
+ dasd_3990_erp_com_rej(struct dasd_ccw_req * erp, char *sense)
  {
--	struct vivi_fh  *fh=priv;
-+	struct vivi_fh  *fh = priv;
- 
--	return videobuf_cgmbuf (&fh->vb_vidq, mbuf, 8);
-+	return videobuf_cgmbuf(&fh->vb_vidq, mbuf, 8);
- }
- #endif
  
- static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
- {
--	struct vivi_fh  *fh=priv;
-+	struct vivi_fh  *fh = priv;
+-	struct dasd_device *device = erp->device;
++	struct dasd_device *device = erp->startdev;
  
- 	if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- 		return -EINVAL;
-@@ -879,7 +935,7 @@ static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
+ 	erp->function = dasd_3990_erp_com_rej;
  
- static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
+@@ -1198,7 +1050,7 @@ static struct dasd_ccw_req *
+ dasd_3990_erp_bus_out(struct dasd_ccw_req * erp)
  {
--	struct vivi_fh  *fh=priv;
-+	struct vivi_fh  *fh = priv;
- 
- 	if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- 		return -EINVAL;
-@@ -889,32 +945,32 @@ static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
- 	return videobuf_streamoff(&fh->vb_vidq);
- }
  
--static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id *i)
-+static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *i)
- {
- 	return 0;
- }
+-	struct dasd_device *device = erp->device;
++	struct dasd_device *device = erp->startdev;
  
- /* only one input in this sample driver */
--static int vidioc_enum_input (struct file *file, void *priv,
-+static int vidioc_enum_input(struct file *file, void *priv,
- 				struct v4l2_input *inp)
+ 	/* first time set initial retry counter and erp_function */
+ 	/* and retry once without blocking queue		 */
+@@ -1237,7 +1089,7 @@ static struct dasd_ccw_req *
+ dasd_3990_erp_equip_check(struct dasd_ccw_req * erp, char *sense)
  {
- 	if (inp->index != 0)
- 		return -EINVAL;
  
- 	inp->type = V4L2_INPUT_TYPE_CAMERA;
--	inp->std = V4L2_STD_NTSC_M;
--	strcpy(inp->name,"Camera");
-+	inp->std = V4L2_STD_525_60;
-+	strcpy(inp->name, "Camera");
+-	struct dasd_device *device = erp->device;
++	struct dasd_device *device = erp->startdev;
  
- 	return (0);
- }
+ 	erp->function = dasd_3990_erp_equip_check;
  
--static int vidioc_g_input (struct file *file, void *priv, unsigned int *i)
-+static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
- {
- 	*i = 0;
+@@ -1279,7 +1131,6 @@ dasd_3990_erp_equip_check(struct dasd_ccw_req * erp, char *sense)
  
- 	return (0);
- }
--static int vidioc_s_input (struct file *file, void *priv, unsigned int i)
-+static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
- {
- 	if (i > 0)
- 		return -EINVAL;
-@@ -923,8 +979,8 @@ static int vidioc_s_input (struct file *file, void *priv, unsigned int i)
- }
+ 		erp = dasd_3990_erp_action_5(erp);
+ 	}
+-
+ 	return erp;
  
- 	/* --- controls ---------------------------------------------- */
--static int vidioc_queryctrl (struct file *file, void *priv,
--				struct v4l2_queryctrl *qc)
-+static int vidioc_queryctrl(struct file *file, void *priv,
-+			    struct v4l2_queryctrl *qc)
+ }				/* end dasd_3990_erp_equip_check */
+@@ -1299,7 +1150,7 @@ static struct dasd_ccw_req *
+ dasd_3990_erp_data_check(struct dasd_ccw_req * erp, char *sense)
  {
- 	int i;
- 
-@@ -938,33 +994,31 @@ static int vidioc_queryctrl (struct file *file, void *priv,
- 	return -EINVAL;
- }
  
--static int vidioc_g_ctrl (struct file *file, void *priv,
--				struct v4l2_control *ctrl)
-+static int vidioc_g_ctrl(struct file *file, void *priv,
-+			 struct v4l2_control *ctrl)
- {
- 	int i;
+-	struct dasd_device *device = erp->device;
++	struct dasd_device *device = erp->startdev;
  
- 	for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++)
- 		if (ctrl->id == vivi_qctrl[i].id) {
--			ctrl->value=qctl_regs[i];
-+			ctrl->value = qctl_regs[i];
- 			return (0);
- 		}
+ 	erp->function = dasd_3990_erp_data_check;
  
- 	return -EINVAL;
- }
--static int vidioc_s_ctrl (struct file *file, void *priv,
-+static int vidioc_s_ctrl(struct file *file, void *priv,
- 				struct v4l2_control *ctrl)
+@@ -1358,7 +1209,7 @@ static struct dasd_ccw_req *
+ dasd_3990_erp_overrun(struct dasd_ccw_req * erp, char *sense)
  {
- 	int i;
- 
- 	for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++)
- 		if (ctrl->id == vivi_qctrl[i].id) {
--			if (ctrl->value <
--				vivi_qctrl[i].minimum
--				|| ctrl->value >
--				vivi_qctrl[i].maximum) {
-+			if (ctrl->value < vivi_qctrl[i].minimum
-+			    || ctrl->value > vivi_qctrl[i].maximum) {
- 					return (-ERANGE);
- 				}
--			qctl_regs[i]=ctrl->value;
-+			qctl_regs[i] = ctrl->value;
- 			return (0);
- 		}
- 	return -EINVAL;
-@@ -983,24 +1037,22 @@ static int vivi_open(struct inode *inode, struct file *file)
- 	struct vivi_fh *fh;
- 	int i;
  
--	printk(KERN_DEBUG "vivi: open called (minor=%d)\n",minor);
-+	printk(KERN_DEBUG "vivi: open called (minor=%d)\n", minor);
- 
- 	list_for_each_entry(dev, &vivi_devlist, vivi_devlist)
--		if (dev->vfd.minor == minor)
-+		if (dev->vfd->minor == minor)
- 			goto found;
- 	return -ENODEV;
--found:
--
--
- 
-+found:
- 	/* If more than one user, mutex should be added */
- 	dev->users++;
+-	struct dasd_device *device = erp->device;
++	struct dasd_device *device = erp->startdev;
  
--	dprintk(1, "open minor=%d type=%s users=%d\n", minor,
-+	dprintk(dev, 1, "open minor=%d type=%s users=%d\n", minor,
- 		v4l2_type_names[V4L2_BUF_TYPE_VIDEO_CAPTURE], dev->users);
+ 	erp->function = dasd_3990_erp_overrun;
  
- 	/* allocate + initialize per filehandle data */
--	fh = kzalloc(sizeof(*fh),GFP_KERNEL);
-+	fh = kzalloc(sizeof(*fh), GFP_KERNEL);
- 	if (NULL == fh) {
- 		dev->users--;
- 		return -ENOMEM;
-@@ -1016,27 +1068,21 @@ found:
+@@ -1387,7 +1238,7 @@ static struct dasd_ccw_req *
+ dasd_3990_erp_inv_format(struct dasd_ccw_req * erp, char *sense)
+ {
  
- 	/* Put all controls at a sane state */
- 	for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++)
--		qctl_regs[i] =vivi_qctrl[i].default_value;
--
--	dprintk(1,"Open: fh=0x%08lx, dev=0x%08lx, dev->vidq=0x%08lx\n",
--		(unsigned long)fh,(unsigned long)dev,(unsigned long)&dev->vidq);
--	dprintk(1,"Open: list_empty queued=%d\n",list_empty(&dev->vidq.queued));
--	dprintk(1,"Open: list_empty active=%d\n",list_empty(&dev->vidq.active));
-+		qctl_regs[i] = vivi_qctrl[i].default_value;
+-	struct dasd_device *device = erp->device;
++	struct dasd_device *device = erp->startdev;
  
- 	/* Resets frame counters */
--	dev->h=0;
--	dev->m=0;
--	dev->s=0;
--	dev->us=0;
--	dev->jiffies=jiffies;
--	sprintf(dev->timestr,"%02d:%02d:%02d:%03d",
--			dev->h,dev->m,dev->s,(dev->us+500)/1000);
-+	dev->h = 0;
-+	dev->m = 0;
-+	dev->s = 0;
-+	dev->ms = 0;
-+	dev->mv_count = 0;
-+	dev->jiffies = jiffies;
-+	sprintf(dev->timestr, "%02d:%02d:%02d:%03d",
-+			dev->h, dev->m, dev->s, dev->ms);
+ 	erp->function = dasd_3990_erp_inv_format;
  
- 	videobuf_queue_vmalloc_init(&fh->vb_vidq, &vivi_video_qops,
--			NULL, NULL,
--			fh->type,
--			V4L2_FIELD_INTERLACED,
--			sizeof(struct vivi_buffer),fh);
-+			NULL, &dev->slock, fh->type, V4L2_FIELD_INTERLACED,
-+			sizeof(struct vivi_buffer), fh);
+@@ -1403,8 +1254,7 @@ dasd_3990_erp_inv_format(struct dasd_ccw_req * erp, char *sense)
  
- 	return 0;
- }
-@@ -1044,9 +1090,9 @@ found:
- static ssize_t
- vivi_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
- {
--	struct vivi_fh        *fh = file->private_data;
-+	struct vivi_fh *fh = file->private_data;
+ 	} else {
+ 		DEV_MESSAGE(KERN_ERR, device, "%s",
+-			    "Invalid Track Format - Fatal error should have "
+-			    "been handled within the interrupt handler");
++			    "Invalid Track Format - Fatal error");
  
--	if (fh->type==V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-+	if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- 		return videobuf_read_stream(&fh->vb_vidq, data, count, ppos, 0,
- 					file->f_flags & O_NONBLOCK);
+ 		erp = dasd_3990_erp_cleanup(erp, DASD_CQR_FAILED);
  	}
-@@ -1057,9 +1103,10 @@ static unsigned int
- vivi_poll(struct file *file, struct poll_table_struct *wait)
+@@ -1428,7 +1278,7 @@ static struct dasd_ccw_req *
+ dasd_3990_erp_EOC(struct dasd_ccw_req * default_erp, char *sense)
  {
- 	struct vivi_fh        *fh = file->private_data;
-+	struct vivi_dev       *dev = fh->dev;
- 	struct videobuf_queue *q = &fh->vb_vidq;
  
--	dprintk(1,"%s\n",__FUNCTION__);
-+	dprintk(dev, 1, "%s\n", __FUNCTION__);
- 
- 	if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type)
- 		return POLLERR;
-@@ -1067,7 +1114,7 @@ vivi_poll(struct file *file, struct poll_table_struct *wait)
- 	return videobuf_poll_stream(file, q, wait);
- }
+-	struct dasd_device *device = default_erp->device;
++	struct dasd_device *device = default_erp->startdev;
  
--static int vivi_release(struct inode *inode, struct file *file)
-+static int vivi_close(struct inode *inode, struct file *file)
+ 	DEV_MESSAGE(KERN_ERR, device, "%s",
+ 		    "End-of-Cylinder - must never happen");
+@@ -1453,7 +1303,7 @@ static struct dasd_ccw_req *
+ dasd_3990_erp_env_data(struct dasd_ccw_req * erp, char *sense)
  {
- 	struct vivi_fh         *fh = file->private_data;
- 	struct vivi_dev *dev       = fh->dev;
-@@ -1079,26 +1126,48 @@ static int vivi_release(struct inode *inode, struct file *file)
- 	videobuf_stop(&fh->vb_vidq);
- 	videobuf_mmap_free(&fh->vb_vidq);
  
--	kfree (fh);
-+	kfree(fh);
+-	struct dasd_device *device = erp->device;
++	struct dasd_device *device = erp->startdev;
  
- 	dev->users--;
+ 	erp->function = dasd_3990_erp_env_data;
  
--	printk(KERN_DEBUG "vivi: close called (minor=%d, users=%d)\n",minor,dev->users);
-+	dprintk(dev, 1, "close called (minor=%d, users=%d)\n",
-+		minor, dev->users);
+@@ -1463,11 +1313,9 @@ dasd_3990_erp_env_data(struct dasd_ccw_req * erp, char *sense)
  
- 	return 0;
- }
+ 	/* don't retry on disabled interface */
+ 	if (sense[7] != 0x0F) {
+-
+ 		erp = dasd_3990_erp_action_4(erp, sense);
+ 	} else {
+-
+-		erp = dasd_3990_erp_cleanup(erp, DASD_CQR_IN_IO);
++		erp->status = DASD_CQR_FILLED;
+ 	}
  
--static int
--vivi_mmap(struct file *file, struct vm_area_struct * vma)
-+static int vivi_release(void)
+ 	return erp;
+@@ -1490,11 +1338,10 @@ static struct dasd_ccw_req *
+ dasd_3990_erp_no_rec(struct dasd_ccw_req * default_erp, char *sense)
  {
--	struct vivi_fh        *fh = file->private_data;
-+	struct vivi_dev *dev;
-+	struct list_head *list;
-+
-+	while (!list_empty(&vivi_devlist)) {
-+		list = vivi_devlist.next;
-+		list_del(list);
-+		dev = list_entry(list, struct vivi_dev, vivi_devlist);
-+
-+		if (-1 != dev->vfd->minor)
-+			video_unregister_device(dev->vfd);
-+		else
-+			video_device_release(dev->vfd);
-+
-+		kfree(dev);
-+	}
-+
-+	return 0;
-+}
-+
-+static int vivi_mmap(struct file *file, struct vm_area_struct *vma)
-+{
-+	struct vivi_fh  *fh = file->private_data;
-+	struct vivi_dev *dev = fh->dev;
- 	int ret;
- 
--	dprintk (1,"mmap called, vma=0x%08lx\n",(unsigned long)vma);
-+	dprintk(dev, 1, "mmap called, vma=0x%08lx\n", (unsigned long)vma);
  
--	ret=videobuf_mmap_mapper(&fh->vb_vidq, vma);
-+	ret = videobuf_mmap_mapper(&fh->vb_vidq, vma);
- 
--	dprintk (1,"vma start=0x%08lx, size=%ld, ret=%d\n",
-+	dprintk(dev, 1, "vma start=0x%08lx, size=%ld, ret=%d\n",
- 		(unsigned long)vma->vm_start,
- 		(unsigned long)vma->vm_end-(unsigned long)vma->vm_start,
- 		ret);
-@@ -1109,7 +1178,7 @@ vivi_mmap(struct file *file, struct vm_area_struct * vma)
- static const struct file_operations vivi_fops = {
- 	.owner		= THIS_MODULE,
- 	.open           = vivi_open,
--	.release        = vivi_release,
-+	.release        = vivi_close,
- 	.read           = vivi_read,
- 	.poll		= vivi_poll,
- 	.ioctl          = video_ioctl2, /* V4L2 ioctl handler */
-@@ -1117,12 +1186,12 @@ static const struct file_operations vivi_fops = {
- 	.llseek         = no_llseek,
- };
+-	struct dasd_device *device = default_erp->device;
++	struct dasd_device *device = default_erp->startdev;
  
--static struct video_device vivi = {
-+static struct video_device vivi_template = {
- 	.name		= "vivi",
- 	.type		= VID_TYPE_CAPTURE,
- 	.fops           = &vivi_fops,
- 	.minor		= -1,
--//	.release	= video_device_release,
-+	.release	= video_device_release,
+ 	DEV_MESSAGE(KERN_ERR, device, "%s",
+-		    "No Record Found - Fatal error should "
+-		    "have been handled within the interrupt handler");
++		    "No Record Found - Fatal error ");
  
- 	.vidioc_querycap      = vidioc_querycap,
- 	.vidioc_enum_fmt_cap  = vidioc_enum_fmt_cap,
-@@ -1145,7 +1214,7 @@ static struct video_device vivi = {
- #ifdef CONFIG_VIDEO_V4L1_COMPAT
- 	.vidiocgmbuf          = vidiocgmbuf,
- #endif
--	.tvnorms              = V4L2_STD_NTSC_M,
-+	.tvnorms              = V4L2_STD_525_60,
- 	.current_norm         = V4L2_STD_NTSC_M,
- };
- /* -----------------------------------------------------------------
-@@ -1154,43 +1223,61 @@ static struct video_device vivi = {
+ 	return dasd_3990_erp_cleanup(default_erp, DASD_CQR_FAILED);
  
- static int __init vivi_init(void)
+@@ -1517,7 +1364,7 @@ static struct dasd_ccw_req *
+ dasd_3990_erp_file_prot(struct dasd_ccw_req * erp)
  {
--	int ret;
-+	int ret = -ENOMEM, i;
- 	struct vivi_dev *dev;
-+	struct video_device *vfd;
- 
--	dev = kzalloc(sizeof(*dev),GFP_KERNEL);
--	if (NULL == dev)
--		return -ENOMEM;
--	list_add_tail(&dev->vivi_devlist,&vivi_devlist);
-+	for (i = 0; i < n_devs; i++) {
-+		dev = kzalloc(sizeof(*dev), GFP_KERNEL);
-+		if (NULL == dev)
-+			break;
  
--	/* init video dma queues */
--	INIT_LIST_HEAD(&dev->vidq.active);
--	INIT_LIST_HEAD(&dev->vidq.queued);
--	init_waitqueue_head(&dev->vidq.wq);
-+		list_add_tail(&dev->vivi_devlist, &vivi_devlist);
+-	struct dasd_device *device = erp->device;
++	struct dasd_device *device = erp->startdev;
  
--	/* initialize locks */
--	mutex_init(&dev->lock);
-+		/* init video dma queues */
-+		INIT_LIST_HEAD(&dev->vidq.active);
-+		INIT_LIST_HEAD(&dev->vidq.queued);
-+		init_waitqueue_head(&dev->vidq.wq);
+ 	DEV_MESSAGE(KERN_ERR, device, "%s", "File Protected");
  
--	dev->vidq.timeout.function = vivi_vid_timeout;
--	dev->vidq.timeout.data     = (unsigned long)dev;
--	init_timer(&dev->vidq.timeout);
-+		/* initialize locks */
-+		mutex_init(&dev->lock);
-+		spin_lock_init(&dev->slock);
+@@ -1526,6 +1373,43 @@ dasd_3990_erp_file_prot(struct dasd_ccw_req * erp)
+ }				/* end dasd_3990_erp_file_prot */
  
--	ret = video_register_device(&vivi, VFL_TYPE_GRABBER, video_nr);
--	printk(KERN_INFO "Video Technology Magazine Virtual Video Capture Board (Load status: %d)\n", ret);
-+		dev->vidq.timeout.function = vivi_vid_timeout;
-+		dev->vidq.timeout.data     = (unsigned long)dev;
-+		init_timer(&dev->vidq.timeout);
-+
-+		vfd = video_device_alloc();
-+		if (NULL == vfd)
-+			break;
-+
-+		*vfd = vivi_template;
-+
-+		ret = video_register_device(vfd, VFL_TYPE_GRABBER, video_nr);
-+		if (ret < 0)
-+			break;
+ /*
++ * DASD_3990_ERP_INSPECT_ALIAS
++ *
++ * DESCRIPTION
++ *   Checks if the original request was started on an alias device.
++ *   If yes, it modifies the original and the erp request so that
++ *   the erp request can be started on a base device.
++ *
++ * PARAMETER
++ *   erp		pointer to the currently created default ERP
++ *
++ * RETURN VALUES
++ *   erp		pointer to the modified ERP, or NULL
++ */
 +
-+		snprintf(vfd->name, sizeof(vfd->name), "%s (%i)",
-+			 vivi_template.name, vfd->minor);
++static struct dasd_ccw_req *dasd_3990_erp_inspect_alias(
++						struct dasd_ccw_req *erp)
++{
++	struct dasd_ccw_req *cqr = erp->refers;
 +
-+		if (video_nr >= 0)
-+			video_nr++;
++	if (cqr->block &&
++	    (cqr->block->base != cqr->startdev)) {
++		if (cqr->startdev->features & DASD_FEATURE_ERPLOG) {
++			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);
++		}
++		dasd_eckd_reset_ccw_to_base_io(cqr);
++		erp->startdev = cqr->block->base;
++		erp->function = dasd_3990_erp_inspect_alias;
++		return erp;
++	} else
++		return NULL;
++}
 +
-+		dev->vfd = vfd;
-+	}
 +
-+	if (ret < 0) {
-+		vivi_release();
-+		printk(KERN_INFO "Error %d while loading vivi driver\n", ret);
-+	} else
-+		printk(KERN_INFO "Video Technology Magazine Virtual Video "
-+				 "Capture Board successfully loaded.\n");
- 	return ret;
- }
- 
- static void __exit vivi_exit(void)
++/*
+  * DASD_3990_ERP_INSPECT_24
+  *
+  * DESCRIPTION
+@@ -1623,7 +1507,7 @@ static struct dasd_ccw_req *
+ dasd_3990_erp_action_10_32(struct dasd_ccw_req * erp, char *sense)
  {
--	struct vivi_dev *h;
--	struct list_head *list;
--
--	while (!list_empty(&vivi_devlist)) {
--		list = vivi_devlist.next;
--		list_del(list);
--		h = list_entry(list, struct vivi_dev, vivi_devlist);
--		kfree (h);
--	}
--	video_unregister_device(&vivi);
-+	vivi_release();
- }
- 
- module_init(vivi_init);
-@@ -1201,10 +1288,13 @@ MODULE_AUTHOR("Mauro Carvalho Chehab, Ted Walther and John Sokol");
- MODULE_LICENSE("Dual BSD/GPL");
  
- module_param(video_nr, int, 0);
-+MODULE_PARM_DESC(video_nr, "video iminor start number");
+-	struct dasd_device *device = erp->device;
++	struct dasd_device *device = erp->startdev;
  
--module_param_named(debug,vivi.debug, int, 0644);
--MODULE_PARM_DESC(debug,"activates debug info");
-+module_param(n_devs, int, 0);
-+MODULE_PARM_DESC(n_devs, "number of video devices to create");
+ 	erp->retries = 256;
+ 	erp->function = dasd_3990_erp_action_10_32;
+@@ -1657,13 +1541,14 @@ static struct dasd_ccw_req *
+ dasd_3990_erp_action_1B_32(struct dasd_ccw_req * default_erp, char *sense)
+ {
  
--module_param(vid_limit,int,0644);
--MODULE_PARM_DESC(vid_limit,"capture memory limit in megabytes");
-+module_param_named(debug, vivi_template.debug, int, 0444);
-+MODULE_PARM_DESC(debug, "activates debug info");
+-	struct dasd_device *device = default_erp->device;
++	struct dasd_device *device = default_erp->startdev;
+ 	__u32 cpa = 0;
+ 	struct dasd_ccw_req *cqr;
+ 	struct dasd_ccw_req *erp;
+ 	struct DE_eckd_data *DE_data;
++	struct PFX_eckd_data *PFX_data;
+ 	char *LO_data;		/* LO_eckd_data_t */
+-	struct ccw1 *ccw;
++	struct ccw1 *ccw, *oldccw;
  
-+module_param(vid_limit, int, 0644);
-+MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes");
-diff --git a/drivers/media/video/vp27smpx.c b/drivers/media/video/vp27smpx.c
-index 63002e0..282c814 100644
---- a/drivers/media/video/vp27smpx.c
-+++ b/drivers/media/video/vp27smpx.c
-@@ -30,15 +30,12 @@
- #include <linux/videodev.h>
- #include <media/v4l2-common.h>
- #include <media/v4l2-chip-ident.h>
-+#include <media/v4l2-i2c-drv.h>
+ 	DEV_MESSAGE(KERN_DEBUG, device, "%s",
+ 		    "Write not finished because of unexpected condition");
+@@ -1702,8 +1587,8 @@ dasd_3990_erp_action_1B_32(struct dasd_ccw_req * default_erp, char *sense)
+ 	/* Build new ERP request including DE/LO */
+ 	erp = dasd_alloc_erp_request((char *) &cqr->magic,
+ 				     2 + 1,/* DE/LO + TIC */
+-				     sizeof (struct DE_eckd_data) +
+-				     sizeof (struct LO_eckd_data), device);
++				     sizeof(struct DE_eckd_data) +
++				     sizeof(struct LO_eckd_data), device);
  
- MODULE_DESCRIPTION("vp27smpx driver");
- MODULE_AUTHOR("Hans Verkuil");
- MODULE_LICENSE("GPL");
+ 	if (IS_ERR(erp)) {
+ 		DEV_MESSAGE(KERN_ERR, device, "%s", "Unable to allocate ERP");
+@@ -1712,10 +1597,16 @@ dasd_3990_erp_action_1B_32(struct dasd_ccw_req * default_erp, char *sense)
  
--static unsigned short normal_i2c[] = { 0xb6 >> 1, I2C_CLIENT_END };
--
--
--I2C_CLIENT_INSMOD;
+ 	/* use original DE */
+ 	DE_data = erp->data;
+-	memcpy(DE_data, cqr->data, sizeof (struct DE_eckd_data));
++	oldccw = cqr->cpaddr;
++	if (oldccw->cmd_code == DASD_ECKD_CCW_PFX) {
++		PFX_data = cqr->data;
++		memcpy(DE_data, &PFX_data->define_extend,
++		       sizeof(struct DE_eckd_data));
++	} else
++		memcpy(DE_data, cqr->data, sizeof(struct DE_eckd_data));
  
- /* ----------------------------------------------------------------------- */
+ 	/* create LO */
+-	LO_data = erp->data + sizeof (struct DE_eckd_data);
++	LO_data = erp->data + sizeof(struct DE_eckd_data);
  
-@@ -53,28 +50,26 @@ static void vp27smpx_set_audmode(struct i2c_client *client, u32 audmode)
- 	u8 data[3] = { 0x00, 0x00, 0x04 };
+ 	if ((sense[3] == 0x01) && (LO_data[1] & 0x01)) {
  
- 	switch (audmode) {
--		case V4L2_TUNER_MODE_MONO:
--		case V4L2_TUNER_MODE_LANG1:
--			break;
--		case V4L2_TUNER_MODE_STEREO:
--		case V4L2_TUNER_MODE_LANG1_LANG2:
--			data[1] = 0x01;
--			break;
--		case V4L2_TUNER_MODE_LANG2:
--			data[1] = 0x02;
--			break;
-+	case V4L2_TUNER_MODE_MONO:
-+	case V4L2_TUNER_MODE_LANG1:
-+		break;
-+	case V4L2_TUNER_MODE_STEREO:
-+	case V4L2_TUNER_MODE_LANG1_LANG2:
-+		data[1] = 0x01;
-+		break;
-+	case V4L2_TUNER_MODE_LANG2:
-+		data[1] = 0x02;
-+		break;
- 	}
+@@ -1748,7 +1639,7 @@ dasd_3990_erp_action_1B_32(struct dasd_ccw_req * default_erp, char *sense)
  
--	if (i2c_master_send(client, data, sizeof(data)) != sizeof(data)) {
--		v4l_err(client, "%s: I/O error setting audmode\n", client->name);
--	}
--	else {
-+	if (i2c_master_send(client, data, sizeof(data)) != sizeof(data))
-+		v4l_err(client, "%s: I/O error setting audmode\n",
-+				client->name);
-+	else
- 		state->audmode = audmode;
--	}
- }
+ 	/* create DE ccw */
+ 	ccw = erp->cpaddr;
+-	memset(ccw, 0, sizeof (struct ccw1));
++	memset(ccw, 0, sizeof(struct ccw1));
+ 	ccw->cmd_code = DASD_ECKD_CCW_DEFINE_EXTENT;
+ 	ccw->flags = CCW_FLAG_CC;
+ 	ccw->count = 16;
+@@ -1756,7 +1647,7 @@ dasd_3990_erp_action_1B_32(struct dasd_ccw_req * default_erp, char *sense)
  
--static int vp27smpx_command(struct i2c_client *client, unsigned int cmd,
--			  void *arg)
-+static int vp27smpx_command(struct i2c_client *client, unsigned cmd, void *arg)
+ 	/* create LO ccw */
+ 	ccw++;
+-	memset(ccw, 0, sizeof (struct ccw1));
++	memset(ccw, 0, sizeof(struct ccw1));
+ 	ccw->cmd_code = DASD_ECKD_CCW_LOCATE_RECORD;
+ 	ccw->flags = CCW_FLAG_CC;
+ 	ccw->count = 16;
+@@ -1770,7 +1661,8 @@ dasd_3990_erp_action_1B_32(struct dasd_ccw_req * default_erp, char *sense)
+ 	/* fill erp related fields */
+ 	erp->function = dasd_3990_erp_action_1B_32;
+ 	erp->refers = default_erp->refers;
+-	erp->device = device;
++	erp->startdev = device;
++	erp->memdev = device;
+ 	erp->magic = default_erp->magic;
+ 	erp->expires = 0;
+ 	erp->retries = 256;
+@@ -1803,7 +1695,7 @@ static struct dasd_ccw_req *
+ dasd_3990_update_1B(struct dasd_ccw_req * previous_erp, char *sense)
  {
- 	struct vp27smpx_state *state = i2c_get_clientdata(client);
- 	struct v4l2_tuner *vt = arg;
-@@ -103,7 +98,8 @@ static int vp27smpx_command(struct i2c_client *client, unsigned int cmd,
- 		break;
- 
- 	case VIDIOC_G_CHIP_IDENT:
--		return v4l2_chip_ident_i2c_client(client, arg, V4L2_IDENT_VP27SMPX, 0);
-+		return v4l2_chip_ident_i2c_client(client, arg,
-+				V4L2_IDENT_VP27SMPX, 0);
- 
- 	case VIDIOC_LOG_STATUS:
- 		v4l_info(client, "Audio Mode: %u%s\n", state->audmode,
-@@ -125,88 +121,43 @@ static int vp27smpx_command(struct i2c_client *client, unsigned int cmd,
-  * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
-  */
  
--static struct i2c_driver i2c_driver;
--
--static int vp27smpx_attach(struct i2c_adapter *adapter, int address, int kind)
-+static int vp27smpx_probe(struct i2c_client *client)
- {
--	struct i2c_client *client;
- 	struct vp27smpx_state *state;
+-	struct dasd_device *device = previous_erp->device;
++	struct dasd_device *device = previous_erp->startdev;
+ 	__u32 cpa = 0;
+ 	struct dasd_ccw_req *cqr;
+ 	struct dasd_ccw_req *erp;
+@@ -1827,7 +1719,7 @@ dasd_3990_update_1B(struct dasd_ccw_req * previous_erp, char *sense)
+ 		DEV_MESSAGE(KERN_DEBUG, device, "%s",
+ 			    "Imprecise ending is set - just retry");
  
- 	/* Check if the adapter supports the needed features */
--	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
--		return 0;
--
--	client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
--	if (client == 0)
--		return -ENOMEM;
-+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
-+		return -EIO;
+-		previous_erp->status = DASD_CQR_QUEUED;
++		previous_erp->status = DASD_CQR_FILLED;
  
--	client->addr = address;
--	client->adapter = adapter;
--	client->driver = &i2c_driver;
- 	snprintf(client->name, sizeof(client->name) - 1, "vp27smpx");
+ 		return previous_erp;
+ 	}
+@@ -1850,7 +1742,7 @@ dasd_3990_update_1B(struct dasd_ccw_req * previous_erp, char *sense)
+ 	erp = previous_erp;
  
--	v4l_info(client, "chip found @ 0x%x (%s)\n", address << 1, adapter->name);
-+	v4l_info(client, "chip found @ 0x%x (%s)\n",
-+			client->addr << 1, client->adapter->name);
+ 	/* update the LO with the new returned sense data  */
+-	LO_data = erp->data + sizeof (struct DE_eckd_data);
++	LO_data = erp->data + sizeof(struct DE_eckd_data);
  
- 	state = kzalloc(sizeof(struct vp27smpx_state), GFP_KERNEL);
--	if (state == NULL) {
--		kfree(client);
-+	if (state == NULL)
- 		return -ENOMEM;
--	}
- 	state->audmode = V4L2_TUNER_MODE_STEREO;
- 	i2c_set_clientdata(client, state);
+ 	if ((sense[3] == 0x01) && (LO_data[1] & 0x01)) {
  
- 	/* initialize vp27smpx */
- 	vp27smpx_set_audmode(client, state->audmode);
--	i2c_attach_client(client);
--
- 	return 0;
- }
+@@ -1889,7 +1781,7 @@ dasd_3990_update_1B(struct dasd_ccw_req * previous_erp, char *sense)
+ 	ccw++;			/* addr of TIC ccw */
+ 	ccw->cda = cpa;
  
--static int vp27smpx_probe(struct i2c_adapter *adapter)
-+static int vp27smpx_remove(struct i2c_client *client)
- {
--	if (adapter->class & I2C_CLASS_TV_ANALOG)
--		return i2c_probe(adapter, &addr_data, vp27smpx_attach);
--	return 0;
--}
--
--static int vp27smpx_detach(struct i2c_client *client)
--{
--	struct vp27smpx_state *state = i2c_get_clientdata(client);
--	int err;
--
--	err = i2c_detach_client(client);
--	if (err) {
--		return err;
--	}
--	kfree(state);
--	kfree(client);
--
-+	kfree(i2c_get_clientdata(client));
- 	return 0;
- }
+-	erp->status = DASD_CQR_QUEUED;
++	erp->status = DASD_CQR_FILLED;
  
- /* ----------------------------------------------------------------------- */
+ 	return erp;
  
--/* i2c implementation */
--static struct i2c_driver i2c_driver = {
--	.driver = {
--		.name = "vp27smpx",
--	},
--	.id             = I2C_DRIVERID_VP27SMPX,
--	.attach_adapter = vp27smpx_probe,
--	.detach_client  = vp27smpx_detach,
--	.command        = vp27smpx_command,
-+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
-+	.name = "vp27smpx",
-+	.driverid = I2C_DRIVERID_VP27SMPX,
-+	.command = vp27smpx_command,
-+	.probe = vp27smpx_probe,
-+	.remove = vp27smpx_remove,
- };
+@@ -1968,9 +1860,7 @@ dasd_3990_erp_compound_path(struct dasd_ccw_req * erp, char *sense)
+ 			 * try further actions. */
  
+ 			erp->lpm = 0;
 -
--static int __init vp27smpx_init_module(void)
--{
--	return i2c_add_driver(&i2c_driver);
--}
--
--static void __exit vp27smpx_cleanup_module(void)
--{
--	i2c_del_driver(&i2c_driver);
--}
+-			erp->status = DASD_CQR_ERROR;
 -
--module_init(vp27smpx_init_module);
--module_exit(vp27smpx_cleanup_module);
-diff --git a/drivers/media/video/wm8739.c b/drivers/media/video/wm8739.c
-index 1bf4cbe..31795b4 100644
---- a/drivers/media/video/wm8739.c
-+++ b/drivers/media/video/wm8739.c
-@@ -30,21 +30,19 @@
- #include <linux/videodev.h>
- #include <media/v4l2-common.h>
- #include <media/v4l2-chip-ident.h>
-+#include <media/v4l2-i2c-drv.h>
++			erp->status = DASD_CQR_NEED_ERP;
+ 		}
+ 	}
  
- MODULE_DESCRIPTION("wm8739 driver");
- MODULE_AUTHOR("T. Adachi, Hans Verkuil");
- MODULE_LICENSE("GPL");
+@@ -2047,7 +1937,7 @@ dasd_3990_erp_compound_config(struct dasd_ccw_req * erp, char *sense)
+ 	if ((sense[25] & DASD_SENSE_BIT_1) && (sense[26] & DASD_SENSE_BIT_2)) {
  
--static int debug = 0;
--static unsigned short normal_i2c[] = { 0x34 >> 1, 0x36 >> 1, I2C_CLIENT_END };
-+static int debug;
+ 		/* set to suspended duplex state then restart */
+-		struct dasd_device *device = erp->device;
++		struct dasd_device *device = erp->startdev;
  
- module_param(debug, int, 0644);
+ 		DEV_MESSAGE(KERN_ERR, device, "%s",
+ 			    "Set device to suspended duplex state should be "
+@@ -2081,28 +1971,26 @@ dasd_3990_erp_compound(struct dasd_ccw_req * erp, char *sense)
+ {
  
- MODULE_PARM_DESC(debug, "Debug level (0-1)");
+ 	if ((erp->function == dasd_3990_erp_compound_retry) &&
+-	    (erp->status == DASD_CQR_ERROR)) {
++	    (erp->status == DASD_CQR_NEED_ERP)) {
  
+ 		dasd_3990_erp_compound_path(erp, sense);
+ 	}
  
--I2C_CLIENT_INSMOD;
--
- /* ------------------------------------------------------------------------ */
+ 	if ((erp->function == dasd_3990_erp_compound_path) &&
+-	    (erp->status == DASD_CQR_ERROR)) {
++	    (erp->status == DASD_CQR_NEED_ERP)) {
  
- enum {
-@@ -75,12 +73,10 @@ static int wm8739_write(struct i2c_client *client, int reg, u16 val)
+ 		erp = dasd_3990_erp_compound_code(erp, sense);
+ 	}
  
- 	v4l_dbg(1, debug, client, "write: %02x %02x\n", reg, val);
+ 	if ((erp->function == dasd_3990_erp_compound_code) &&
+-	    (erp->status == DASD_CQR_ERROR)) {
++	    (erp->status == DASD_CQR_NEED_ERP)) {
  
--	for (i = 0; i < 3; i++) {
--		if (i2c_smbus_write_byte_data(client, (reg << 1) |
--					(val >> 8), val & 0xff) == 0) {
-+	for (i = 0; i < 3; i++)
-+		if (i2c_smbus_write_byte_data(client,
-+				(reg << 1) | (val >> 8), val & 0xff) == 0)
- 			return 0;
--		}
+ 		dasd_3990_erp_compound_config(erp, sense);
+ 	}
+ 
+ 	/* if no compound action ERP specified, the request failed */
+-	if (erp->status == DASD_CQR_ERROR) {
+-
++	if (erp->status == DASD_CQR_NEED_ERP)
+ 		erp->status = DASD_CQR_FAILED;
 -	}
- 	v4l_err(client, "I2C: cannot write %03x to register R%d\n", val, reg);
- 	return -1;
- }
-@@ -167,7 +163,7 @@ static struct v4l2_queryctrl wm8739_qctrl[] = {
- 		.default_value = 58880,
- 		.flags         = 0,
- 		.type          = V4L2_CTRL_TYPE_INTEGER,
--	},{
-+	}, {
- 		.id            = V4L2_CID_AUDIO_MUTE,
- 		.name          = "Mute",
- 		.minimum       = 0,
-@@ -176,7 +172,7 @@ static struct v4l2_queryctrl wm8739_qctrl[] = {
- 		.default_value = 1,
- 		.flags         = 0,
- 		.type          = V4L2_CTRL_TYPE_BOOLEAN,
--	},{
-+	}, {
- 		.id            = V4L2_CID_AUDIO_BALANCE,
- 		.name          = "Balance",
- 		.minimum       = 0,
-@@ -190,7 +186,7 @@ static struct v4l2_queryctrl wm8739_qctrl[] = {
  
- /* ------------------------------------------------------------------------ */
+ 	return erp;
  
--static int wm8739_command(struct i2c_client *client, unsigned int cmd, void *arg)
-+static int wm8739_command(struct i2c_client *client, unsigned cmd, void *arg)
+@@ -2127,7 +2015,7 @@ static struct dasd_ccw_req *
+ dasd_3990_erp_inspect_32(struct dasd_ccw_req * erp, char *sense)
  {
- 	struct wm8739_state *state = i2c_get_clientdata(client);
  
-@@ -200,21 +196,26 @@ static int wm8739_command(struct i2c_client *client, unsigned int cmd, void *arg
- 		u32 audiofreq = *(u32 *)arg;
+-	struct dasd_device *device = erp->device;
++	struct dasd_device *device = erp->startdev;
  
- 		state->clock_freq = audiofreq;
--		wm8739_write(client, R9, 0x000);	/* de-activate */
-+		/* de-activate */
-+		wm8739_write(client, R9, 0x000);
- 		switch (audiofreq) {
- 		case 44100:
--			wm8739_write(client, R8, 0x020); /* 256fps, fs=44.1k     */
-+			/* 256fps, fs=44.1k */
-+			wm8739_write(client, R8, 0x020);
- 			break;
- 		case 48000:
--			wm8739_write(client, R8, 0x000); /* 256fps, fs=48k       */
-+			/* 256fps, fs=48k */
-+			wm8739_write(client, R8, 0x000);
- 			break;
- 		case 32000:
--			wm8739_write(client, R8, 0x018); /* 256fps, fs=32k       */
-+			/* 256fps, fs=32k */
-+			wm8739_write(client, R8, 0x018);
- 			break;
- 		default:
+ 	erp->function = dasd_3990_erp_inspect_32;
+ 
+@@ -2149,8 +2037,7 @@ dasd_3990_erp_inspect_32(struct dasd_ccw_req * erp, char *sense)
+ 
+ 		case 0x01:	/* fatal error */
+ 			DEV_MESSAGE(KERN_ERR, device, "%s",
+-				    "Fatal error should have been "
+-				    "handled within the interrupt handler");
++				    "Retry not recommended - Fatal error");
+ 
+ 			erp = dasd_3990_erp_cleanup(erp, DASD_CQR_FAILED);
  			break;
- 		}
--		wm8739_write(client, R9, 0x001);	/* activate */
-+		/* activate */
-+		wm8739_write(client, R9, 0x001);
- 		break;
- 	}
+@@ -2253,6 +2140,11 @@ dasd_3990_erp_inspect(struct dasd_ccw_req * erp)
+ 	/* already set up new ERP !			      */
+ 	char *sense = erp->refers->irb.ecw;
  
-@@ -238,7 +239,8 @@ static int wm8739_command(struct i2c_client *client, unsigned int cmd, void *arg
- 	}
++	/* if this problem occured on an alias retry on base */
++	erp_new = dasd_3990_erp_inspect_alias(erp);
++	if (erp_new)
++		return erp_new;
++
+ 	/* distinguish between 24 and 32 byte sense data */
+ 	if (sense[27] & DASD_SENSE_BIT_0) {
  
- 	case VIDIOC_G_CHIP_IDENT:
--		return v4l2_chip_ident_i2c_client(client, arg, V4L2_IDENT_WM8739, 0);
-+		return v4l2_chip_ident_i2c_client(client,
-+				arg, V4L2_IDENT_WM8739, 0);
+@@ -2287,13 +2179,13 @@ static struct dasd_ccw_req *
+ dasd_3990_erp_add_erp(struct dasd_ccw_req * cqr)
+ {
  
- 	case VIDIOC_LOG_STATUS:
- 		v4l_info(client, "Frequency: %u Hz\n", state->clock_freq);
-@@ -259,27 +261,16 @@ static int wm8739_command(struct i2c_client *client, unsigned int cmd, void *arg
+-	struct dasd_device *device = cqr->device;
++	struct dasd_device *device = cqr->startdev;
+ 	struct ccw1 *ccw;
  
- /* i2c implementation */
+ 	/* allocate additional request block */
+ 	struct dasd_ccw_req *erp;
  
--static struct i2c_driver i2c_driver;
--
--static int wm8739_attach(struct i2c_adapter *adapter, int address, int kind)
-+static int wm8739_probe(struct i2c_client *client)
+-	erp = dasd_alloc_erp_request((char *) &cqr->magic, 2, 0, cqr->device);
++	erp = dasd_alloc_erp_request((char *) &cqr->magic, 2, 0, device);
+ 	if (IS_ERR(erp)) {
+                 if (cqr->retries <= 0) {
+ 		        DEV_MESSAGE(KERN_ERR, device, "%s",
+@@ -2305,7 +2197,7 @@ dasd_3990_erp_add_erp(struct dasd_ccw_req * cqr)
+                                      "Unable to allocate ERP request "
+ 				     "(%i retries left)",
+                                      cqr->retries);
+-			dasd_set_timer(device, (HZ << 3));
++			dasd_block_set_timer(device->block, (HZ << 3));
+                 }
+ 		return cqr;
+ 	}
+@@ -2319,7 +2211,9 @@ dasd_3990_erp_add_erp(struct dasd_ccw_req * cqr)
+ 	ccw->cda      = (long)(cqr->cpaddr);
+ 	erp->function = dasd_3990_erp_add_erp;
+ 	erp->refers   = cqr;
+-	erp->device   = cqr->device;
++	erp->startdev = device;
++	erp->memdev   = device;
++	erp->block    = cqr->block;
+ 	erp->magic    = cqr->magic;
+ 	erp->expires  = 0;
+ 	erp->retries  = 256;
+@@ -2466,7 +2360,7 @@ static struct dasd_ccw_req *
+ dasd_3990_erp_further_erp(struct dasd_ccw_req *erp)
  {
--	struct i2c_client *client;
- 	struct wm8739_state *state;
  
- 	/* Check if the adapter supports the needed features */
--	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
--		return 0;
--
--	client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
--	if (client == NULL)
--		return -ENOMEM;
+-	struct dasd_device *device = erp->device;
++	struct dasd_device *device = erp->startdev;
+ 	char *sense = erp->irb.ecw;
+ 
+ 	/* check for 24 byte sense ERP */
+@@ -2557,7 +2451,7 @@ dasd_3990_erp_handle_match_erp(struct dasd_ccw_req *erp_head,
+ 			       struct dasd_ccw_req *erp)
+ {
+ 
+-	struct dasd_device *device = erp_head->device;
++	struct dasd_device *device = erp_head->startdev;
+ 	struct dasd_ccw_req *erp_done = erp_head;	/* finished req */
+ 	struct dasd_ccw_req *erp_free = NULL;	/* req to be freed */
+ 
+@@ -2569,13 +2463,13 @@ dasd_3990_erp_handle_match_erp(struct dasd_ccw_req *erp_head,
+ 			      "original request was lost\n");
+ 
+ 		/* remove the request from the device queue */
+-		list_del(&erp_done->list);
++		list_del(&erp_done->blocklist);
+ 
+ 		erp_free = erp_done;
+ 		erp_done = erp_done->refers;
+ 
+ 		/* free the finished erp request */
+-		dasd_free_erp_request(erp_free, erp_free->device);
++		dasd_free_erp_request(erp_free, erp_free->memdev);
+ 
+ 	}			/* end while */
+ 
+@@ -2603,7 +2497,7 @@ dasd_3990_erp_handle_match_erp(struct dasd_ccw_req *erp_head,
+ 				    erp->retries, erp);
+ 
+ 			/* handle the request again... */
+-			erp->status = DASD_CQR_QUEUED;
++			erp->status = DASD_CQR_FILLED;
+ 		}
+ 
+ 	} else {
+@@ -2620,7 +2514,7 @@ dasd_3990_erp_handle_match_erp(struct dasd_ccw_req *erp_head,
+  * DASD_3990_ERP_ACTION
+  *
+  * DESCRIPTION
+- *   controll routine for 3990 erp actions.
++ *   control routine for 3990 erp actions.
+  *   Has to be called with the queue lock (namely the s390_irq_lock) acquired.
+  *
+  * PARAMETER
+@@ -2636,9 +2530,8 @@ dasd_3990_erp_handle_match_erp(struct dasd_ccw_req *erp_head,
+ struct dasd_ccw_req *
+ dasd_3990_erp_action(struct dasd_ccw_req * cqr)
+ {
 -
--	client->addr = address;
--	client->adapter = adapter;
--	client->driver = &i2c_driver;
--	snprintf(client->name, sizeof(client->name) - 1, "wm8739");
-+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
-+		return -EIO;
+ 	struct dasd_ccw_req *erp = NULL;
+-	struct dasd_device *device = cqr->device;
++	struct dasd_device *device = cqr->startdev;
+ 	struct dasd_ccw_req *temp_erp = NULL;
  
--	v4l_info(client, "chip found @ 0x%x (%s)\n", address << 1, adapter->name);
-+	v4l_info(client, "chip found @ 0x%x (%s)\n",
-+			client->addr << 1, client->adapter->name);
+ 	if (device->features & DASD_FEATURE_ERPLOG) {
+@@ -2704,10 +2597,11 @@ dasd_3990_erp_action(struct dasd_ccw_req * cqr)
+ 		}
+ 	}
  
- 	state = kmalloc(sizeof(struct wm8739_state), GFP_KERNEL);
- 	if (state == NULL) {
-@@ -295,67 +286,37 @@ static int wm8739_attach(struct i2c_adapter *adapter, int address, int kind)
- 	state->clock_freq = 48000;
- 	i2c_set_clientdata(client, state);
+-	/* enqueue added ERP request */
+-	if (erp->status == DASD_CQR_FILLED) {
+-		erp->status = DASD_CQR_QUEUED;
+-		list_add(&erp->list, &device->ccw_queue);
++	/* enqueue ERP request if it's a new one */
++	if (list_empty(&erp->blocklist)) {
++		cqr->status = DASD_CQR_IN_ERP;
++		/* add erp request before the cqr */
++		list_add_tail(&erp->blocklist, &cqr->blocklist);
+ 	}
  
--	/* initialize wm8739 */
--	wm8739_write(client, R15, 0x00); /* reset */
--	wm8739_write(client, R5, 0x000); /* filter setting, high path, offet clear */
--	wm8739_write(client, R6, 0x000); /* ADC, OSC, Power Off mode Disable */
--	wm8739_write(client, R7, 0x049); /* Digital Audio interface format */
--					 /* Enable Master mode */
--					 /* 24 bit, MSB first/left justified */
--	wm8739_write(client, R8, 0x000); /* sampling control */
--					 /* normal, 256fs, 48KHz sampling rate */
--	wm8739_write(client, R9, 0x001); /* activate */
--	wm8739_set_audio(client); 	 /* set volume/mute */
+ 	return erp;
+diff --git a/drivers/s390/block/dasd_9336_erp.c b/drivers/s390/block/dasd_9336_erp.c
+deleted file mode 100644
+index 6e08268..0000000
+--- a/drivers/s390/block/dasd_9336_erp.c
++++ /dev/null
+@@ -1,41 +0,0 @@
+-/*
+- * File...........: linux/drivers/s390/block/dasd_9336_erp.c
+- * Author(s)......: Holger Smolinski <Holger.Smolinski at de.ibm.com>
+- * Bugreports.to..: <Linux390 at de.ibm.com>
+- * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000
+- *
+- */
 -
--	i2c_attach_client(client);
+-#define PRINTK_HEADER "dasd_erp(9336)"
 -
--	return 0;
--}
+-#include "dasd_int.h"
 -
--static int wm8739_probe(struct i2c_adapter *adapter)
+-
+-/*
+- * DASD_9336_ERP_EXAMINE
+- *
+- * DESCRIPTION
+- *   Checks only for fatal/no/recover error.
+- *   A detailed examination of the sense data is done later outside
+- *   the interrupt handler.
+- *
+- *   The logic is based on the 'IBM 3880 Storage Control Reference' manual
+- *   'Chapter 7. 9336 Sense Data'.
+- *
+- * RETURN VALUES
+- *   dasd_era_none	no error
+- *   dasd_era_fatal	for all fatal (unrecoverable errors)
+- *   dasd_era_recover	for all others.
+- */
+-dasd_era_t
+-dasd_9336_erp_examine(struct dasd_ccw_req * cqr, struct irb * irb)
 -{
--	if (adapter->class & I2C_CLASS_TV_ANALOG)
--		return i2c_probe(adapter, &addr_data, wm8739_attach);
-+	/* Initialize wm8739 */
+-	/* check for successful execution first */
+-	if (irb->scsw.cstat == 0x00 &&
+-	    irb->scsw.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))
+-		return dasd_era_none;
+-
+-	/* examine the 24 byte sense data */
+-	return dasd_era_recover;
+-
+-}				/* END dasd_9336_erp_examine */
+diff --git a/drivers/s390/block/dasd_9343_erp.c b/drivers/s390/block/dasd_9343_erp.c
+deleted file mode 100644
+index ddecb98..0000000
+--- a/drivers/s390/block/dasd_9343_erp.c
++++ /dev/null
+@@ -1,21 +0,0 @@
+-/*
+- * File...........: linux/drivers/s390/block/dasd_9345_erp.c
+- * Author(s)......: Holger Smolinski <Holger.Smolinski at de.ibm.com>
+- * Bugreports.to..: <Linux390 at de.ibm.com>
+- * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000
+- *
+- */
+-
+-#define PRINTK_HEADER "dasd_erp(9343)"
+-
+-#include "dasd_int.h"
+-
+-dasd_era_t
+-dasd_9343_erp_examine(struct dasd_ccw_req * cqr, struct irb * irb)
+-{
+-	if (irb->scsw.cstat == 0x00 &&
+-	    irb->scsw.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))
+-		return dasd_era_none;
+-
+-	return dasd_era_recover;
+-}
+diff --git a/drivers/s390/block/dasd_alias.c b/drivers/s390/block/dasd_alias.c
+new file mode 100644
+index 0000000..3a40bee
+--- /dev/null
++++ b/drivers/s390/block/dasd_alias.c
+@@ -0,0 +1,903 @@
++/*
++ * PAV alias management for the DASD ECKD discipline
++ *
++ * Copyright IBM Corporation, 2007
++ * Author(s): Stefan Weinhuber <wein at de.ibm.com>
++ */
++
++#include <linux/list.h>
++#include <asm/ebcdic.h>
++#include "dasd_int.h"
++#include "dasd_eckd.h"
++
++#ifdef PRINTK_HEADER
++#undef PRINTK_HEADER
++#endif				/* PRINTK_HEADER */
++#define PRINTK_HEADER "dasd(eckd):"
++
++
++/*
++ * General concept of alias management:
++ * - PAV and DASD alias management is specific to the eckd discipline.
++ * - A device is connected to an lcu as long as the device exists.
++ *   dasd_alias_make_device_known_to_lcu will be called wenn the
++ *   device is checked by the eckd discipline and
++ *   dasd_alias_disconnect_device_from_lcu will be called
++ *   before the device is deleted.
++ * - The dasd_alias_add_device / dasd_alias_remove_device
++ *   functions mark the point when a device is 'ready for service'.
++ * - A summary unit check is a rare occasion, but it is mandatory to
++ *   support it. It requires some complex recovery actions before the
++ *   devices can be used again (see dasd_alias_handle_summary_unit_check).
++ * - dasd_alias_get_start_dev will find an alias device that can be used
++ *   instead of the base device and does some (very simple) load balancing.
++ *   This is the function that gets called for each I/O, so when improving
++ *   something, this function should get faster or better, the rest has just
++ *   to be correct.
++ */
++
++
++static void summary_unit_check_handling_work(struct work_struct *);
++static void lcu_update_work(struct work_struct *);
++static int _schedule_lcu_update(struct alias_lcu *, struct dasd_device *);
++
++static struct alias_root aliastree = {
++	.serverlist = LIST_HEAD_INIT(aliastree.serverlist),
++	.lock = __SPIN_LOCK_UNLOCKED(aliastree.lock),
++};
++
++static struct alias_server *_find_server(struct dasd_uid *uid)
++{
++	struct alias_server *pos;
++	list_for_each_entry(pos, &aliastree.serverlist, server) {
++		if (!strncmp(pos->uid.vendor, uid->vendor,
++			     sizeof(uid->vendor))
++		    && !strncmp(pos->uid.serial, uid->serial,
++				sizeof(uid->serial)))
++			return pos;
++	};
++	return NULL;
++}
++
++static struct alias_lcu *_find_lcu(struct alias_server *server,
++				   struct dasd_uid *uid)
++{
++	struct alias_lcu *pos;
++	list_for_each_entry(pos, &server->lculist, lcu) {
++		if (pos->uid.ssid == uid->ssid)
++			return pos;
++	};
++	return NULL;
++}
++
++static struct alias_pav_group *_find_group(struct alias_lcu *lcu,
++					   struct dasd_uid *uid)
++{
++	struct alias_pav_group *pos;
++	__u8 search_unit_addr;
++
++	/* for hyper pav there is only one group */
++	if (lcu->pav == HYPER_PAV) {
++		if (list_empty(&lcu->grouplist))
++			return NULL;
++		else
++			return list_first_entry(&lcu->grouplist,
++						struct alias_pav_group, group);
++	}
++
++	/* for base pav we have to find the group that matches the base */
++	if (uid->type == UA_BASE_DEVICE)
++		search_unit_addr = uid->real_unit_addr;
++	else
++		search_unit_addr = uid->base_unit_addr;
++	list_for_each_entry(pos, &lcu->grouplist, group) {
++		if (pos->uid.base_unit_addr == search_unit_addr)
++			return pos;
++	};
++	return NULL;
++}
++
++static struct alias_server *_allocate_server(struct dasd_uid *uid)
++{
++	struct alias_server *server;
++
++	server = kzalloc(sizeof(*server), GFP_KERNEL);
++	if (!server)
++		return ERR_PTR(-ENOMEM);
++	memcpy(server->uid.vendor, uid->vendor, sizeof(uid->vendor));
++	memcpy(server->uid.serial, uid->serial, sizeof(uid->serial));
++	INIT_LIST_HEAD(&server->server);
++	INIT_LIST_HEAD(&server->lculist);
++	return server;
++}
++
++static void _free_server(struct alias_server *server)
++{
++	kfree(server);
++}
++
++static struct alias_lcu *_allocate_lcu(struct dasd_uid *uid)
++{
++	struct alias_lcu *lcu;
++
++	lcu = kzalloc(sizeof(*lcu), GFP_KERNEL);
++	if (!lcu)
++		return ERR_PTR(-ENOMEM);
++	lcu->uac = kzalloc(sizeof(*(lcu->uac)), GFP_KERNEL | GFP_DMA);
++	if (!lcu->uac)
++		goto out_err1;
++	lcu->rsu_cqr = kzalloc(sizeof(*lcu->rsu_cqr), GFP_KERNEL | GFP_DMA);
++	if (!lcu->rsu_cqr)
++		goto out_err2;
++	lcu->rsu_cqr->cpaddr = kzalloc(sizeof(struct ccw1),
++				       GFP_KERNEL | GFP_DMA);
++	if (!lcu->rsu_cqr->cpaddr)
++		goto out_err3;
++	lcu->rsu_cqr->data = kzalloc(16, GFP_KERNEL | GFP_DMA);
++	if (!lcu->rsu_cqr->data)
++		goto out_err4;
++
++	memcpy(lcu->uid.vendor, uid->vendor, sizeof(uid->vendor));
++	memcpy(lcu->uid.serial, uid->serial, sizeof(uid->serial));
++	lcu->uid.ssid = uid->ssid;
++	lcu->pav = NO_PAV;
++	lcu->flags = NEED_UAC_UPDATE | UPDATE_PENDING;
++	INIT_LIST_HEAD(&lcu->lcu);
++	INIT_LIST_HEAD(&lcu->inactive_devices);
++	INIT_LIST_HEAD(&lcu->active_devices);
++	INIT_LIST_HEAD(&lcu->grouplist);
++	INIT_WORK(&lcu->suc_data.worker, summary_unit_check_handling_work);
++	INIT_DELAYED_WORK(&lcu->ruac_data.dwork, lcu_update_work);
++	spin_lock_init(&lcu->lock);
++	return lcu;
++
++out_err4:
++	kfree(lcu->rsu_cqr->cpaddr);
++out_err3:
++	kfree(lcu->rsu_cqr);
++out_err2:
++	kfree(lcu->uac);
++out_err1:
++	kfree(lcu);
++	return ERR_PTR(-ENOMEM);
++}
++
++static void _free_lcu(struct alias_lcu *lcu)
++{
++	kfree(lcu->rsu_cqr->data);
++	kfree(lcu->rsu_cqr->cpaddr);
++	kfree(lcu->rsu_cqr);
++	kfree(lcu->uac);
++	kfree(lcu);
++}
++
++/*
++ * This is the function that will allocate all the server and lcu data,
++ * so this function must be called first for a new device.
++ * If the return value is 1, the lcu was already known before, if it
++ * is 0, this is a new lcu.
++ * Negative return code indicates that something went wrong (e.g. -ENOMEM)
++ */
++int dasd_alias_make_device_known_to_lcu(struct dasd_device *device)
++{
++	struct dasd_eckd_private *private;
++	unsigned long flags;
++	struct alias_server *server, *newserver;
++	struct alias_lcu *lcu, *newlcu;
++	int is_lcu_known;
++	struct dasd_uid *uid;
++
++	private = (struct dasd_eckd_private *) device->private;
++	uid = &private->uid;
++	spin_lock_irqsave(&aliastree.lock, flags);
++	is_lcu_known = 1;
++	server = _find_server(uid);
++	if (!server) {
++		spin_unlock_irqrestore(&aliastree.lock, flags);
++		newserver = _allocate_server(uid);
++		if (IS_ERR(newserver))
++			return PTR_ERR(newserver);
++		spin_lock_irqsave(&aliastree.lock, flags);
++		server = _find_server(uid);
++		if (!server) {
++			list_add(&newserver->server, &aliastree.serverlist);
++			server = newserver;
++			is_lcu_known = 0;
++		} else {
++			/* someone was faster */
++			_free_server(newserver);
++		}
++	}
++
++	lcu = _find_lcu(server, uid);
++	if (!lcu) {
++		spin_unlock_irqrestore(&aliastree.lock, flags);
++		newlcu = _allocate_lcu(uid);
++		if (IS_ERR(newlcu))
++			return PTR_ERR(lcu);
++		spin_lock_irqsave(&aliastree.lock, flags);
++		lcu = _find_lcu(server, uid);
++		if (!lcu) {
++			list_add(&newlcu->lcu, &server->lculist);
++			lcu = newlcu;
++			is_lcu_known = 0;
++		} else {
++			/* someone was faster */
++			_free_lcu(newlcu);
++		}
++		is_lcu_known = 0;
++	}
++	spin_lock(&lcu->lock);
++	list_add(&device->alias_list, &lcu->inactive_devices);
++	private->lcu = lcu;
++	spin_unlock(&lcu->lock);
++	spin_unlock_irqrestore(&aliastree.lock, flags);
++
++	return is_lcu_known;
++}
++
++/*
++ * This function removes a device from the scope of alias management.
++ * The complicated part is to make sure that it is not in use by
++ * any of the workers. If necessary cancel the work.
++ */
++void dasd_alias_disconnect_device_from_lcu(struct dasd_device *device)
++{
++	struct dasd_eckd_private *private;
++	unsigned long flags;
++	struct alias_lcu *lcu;
++	struct alias_server *server;
++	int was_pending;
++
++	private = (struct dasd_eckd_private *) device->private;
++	lcu = private->lcu;
++	spin_lock_irqsave(&lcu->lock, flags);
++	list_del_init(&device->alias_list);
++	/* make sure that the workers don't use this device */
++	if (device == lcu->suc_data.device) {
++		spin_unlock_irqrestore(&lcu->lock, flags);
++		cancel_work_sync(&lcu->suc_data.worker);
++		spin_lock_irqsave(&lcu->lock, flags);
++		if (device == lcu->suc_data.device)
++			lcu->suc_data.device = NULL;
++	}
++	was_pending = 0;
++	if (device == lcu->ruac_data.device) {
++		spin_unlock_irqrestore(&lcu->lock, flags);
++		was_pending = 1;
++		cancel_delayed_work_sync(&lcu->ruac_data.dwork);
++		spin_lock_irqsave(&lcu->lock, flags);
++		if (device == lcu->ruac_data.device)
++			lcu->ruac_data.device = NULL;
++	}
++	private->lcu = NULL;
++	spin_unlock_irqrestore(&lcu->lock, flags);
++
++	spin_lock_irqsave(&aliastree.lock, flags);
++	spin_lock(&lcu->lock);
++	if (list_empty(&lcu->grouplist) &&
++	    list_empty(&lcu->active_devices) &&
++	    list_empty(&lcu->inactive_devices)) {
++		list_del(&lcu->lcu);
++		spin_unlock(&lcu->lock);
++		_free_lcu(lcu);
++		lcu = NULL;
++	} else {
++		if (was_pending)
++			_schedule_lcu_update(lcu, NULL);
++		spin_unlock(&lcu->lock);
++	}
++	server = _find_server(&private->uid);
++	if (server && list_empty(&server->lculist)) {
++		list_del(&server->server);
++		_free_server(server);
++	}
++	spin_unlock_irqrestore(&aliastree.lock, flags);
++}
++
++/*
++ * This function assumes that the unit address configuration stored
++ * in the lcu is up to date and will update the device uid before
++ * adding it to a pav group.
++ */
++static int _add_device_to_lcu(struct alias_lcu *lcu,
++			      struct dasd_device *device)
++{
++
++	struct dasd_eckd_private *private;
++	struct alias_pav_group *group;
++	struct dasd_uid *uid;
++
++	private = (struct dasd_eckd_private *) device->private;
++	uid = &private->uid;
++	uid->type = lcu->uac->unit[uid->real_unit_addr].ua_type;
++	uid->base_unit_addr = lcu->uac->unit[uid->real_unit_addr].base_ua;
++	dasd_set_uid(device->cdev, &private->uid);
++
++	/* if we have no PAV anyway, we don't need to bother with PAV groups */
++	if (lcu->pav == NO_PAV) {
++		list_move(&device->alias_list, &lcu->active_devices);
++		return 0;
++	}
++
++	group = _find_group(lcu, uid);
++	if (!group) {
++		group = kzalloc(sizeof(*group), GFP_ATOMIC);
++		if (!group)
++			return -ENOMEM;
++		memcpy(group->uid.vendor, uid->vendor, sizeof(uid->vendor));
++		memcpy(group->uid.serial, uid->serial, sizeof(uid->serial));
++		group->uid.ssid = uid->ssid;
++		if (uid->type == UA_BASE_DEVICE)
++			group->uid.base_unit_addr = uid->real_unit_addr;
++		else
++			group->uid.base_unit_addr = uid->base_unit_addr;
++		INIT_LIST_HEAD(&group->group);
++		INIT_LIST_HEAD(&group->baselist);
++		INIT_LIST_HEAD(&group->aliaslist);
++		list_add(&group->group, &lcu->grouplist);
++	}
++	if (uid->type == UA_BASE_DEVICE)
++		list_move(&device->alias_list, &group->baselist);
++	else
++		list_move(&device->alias_list, &group->aliaslist);
++	private->pavgroup = group;
++	return 0;
++};
++
++static void _remove_device_from_lcu(struct alias_lcu *lcu,
++				    struct dasd_device *device)
++{
++	struct dasd_eckd_private *private;
++	struct alias_pav_group *group;
++
++	private = (struct dasd_eckd_private *) device->private;
++	list_move(&device->alias_list, &lcu->inactive_devices);
++	group = private->pavgroup;
++	if (!group)
++		return;
++	private->pavgroup = NULL;
++	if (list_empty(&group->baselist) && list_empty(&group->aliaslist)) {
++		list_del(&group->group);
++		kfree(group);
++		return;
++	}
++	if (group->next == device)
++		group->next = NULL;
++};
++
++static int read_unit_address_configuration(struct dasd_device *device,
++					   struct alias_lcu *lcu)
++{
++	struct dasd_psf_prssd_data *prssdp;
++	struct dasd_ccw_req *cqr;
++	struct ccw1 *ccw;
++	int rc;
++	unsigned long flags;
++
++	cqr = dasd_kmalloc_request("ECKD",
++				   1 /* PSF */	+ 1 /* RSSD */ ,
++				   (sizeof(struct dasd_psf_prssd_data)),
++				   device);
++	if (IS_ERR(cqr))
++		return PTR_ERR(cqr);
++	cqr->startdev = device;
++	cqr->memdev = device;
++	clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
++	cqr->retries = 10;
++	cqr->expires = 20 * HZ;
++
++	/* Prepare for Read Subsystem Data */
++	prssdp = (struct dasd_psf_prssd_data *) cqr->data;
++	memset(prssdp, 0, sizeof(struct dasd_psf_prssd_data));
++	prssdp->order = PSF_ORDER_PRSSD;
++	prssdp->suborder = 0x0e;	/* Read unit address configuration */
++	/* all other bytes of prssdp must be zero */
++
++	ccw = cqr->cpaddr;
++	ccw->cmd_code = DASD_ECKD_CCW_PSF;
++	ccw->count = sizeof(struct dasd_psf_prssd_data);
++	ccw->flags |= CCW_FLAG_CC;
++	ccw->cda = (__u32)(addr_t) prssdp;
++
++	/* Read Subsystem Data - feature codes */
++	memset(lcu->uac, 0, sizeof(*(lcu->uac)));
++
++	ccw++;
++	ccw->cmd_code = DASD_ECKD_CCW_RSSD;
++	ccw->count = sizeof(*(lcu->uac));
++	ccw->cda = (__u32)(addr_t) lcu->uac;
++
++	cqr->buildclk = get_clock();
++	cqr->status = DASD_CQR_FILLED;
++
++	/* need to unset flag here to detect race with summary unit check */
++	spin_lock_irqsave(&lcu->lock, flags);
++	lcu->flags &= ~NEED_UAC_UPDATE;
++	spin_unlock_irqrestore(&lcu->lock, flags);
++
++	do {
++		rc = dasd_sleep_on(cqr);
++	} while (rc && (cqr->retries > 0));
++	if (rc) {
++		spin_lock_irqsave(&lcu->lock, flags);
++		lcu->flags |= NEED_UAC_UPDATE;
++		spin_unlock_irqrestore(&lcu->lock, flags);
++	}
++	dasd_kfree_request(cqr, cqr->memdev);
++	return rc;
++}
++
++static int _lcu_update(struct dasd_device *refdev, struct alias_lcu *lcu)
++{
++	unsigned long flags;
++	struct alias_pav_group *pavgroup, *tempgroup;
++	struct dasd_device *device, *tempdev;
++	int i, rc;
++	struct dasd_eckd_private *private;
++
++	spin_lock_irqsave(&lcu->lock, flags);
++	list_for_each_entry_safe(pavgroup, tempgroup, &lcu->grouplist, group) {
++		list_for_each_entry_safe(device, tempdev, &pavgroup->baselist,
++					 alias_list) {
++			list_move(&device->alias_list, &lcu->active_devices);
++			private = (struct dasd_eckd_private *) device->private;
++			private->pavgroup = NULL;
++		}
++		list_for_each_entry_safe(device, tempdev, &pavgroup->aliaslist,
++					 alias_list) {
++			list_move(&device->alias_list, &lcu->active_devices);
++			private = (struct dasd_eckd_private *) device->private;
++			private->pavgroup = NULL;
++		}
++		list_del(&pavgroup->group);
++		kfree(pavgroup);
++	}
++	spin_unlock_irqrestore(&lcu->lock, flags);
++
++	rc = read_unit_address_configuration(refdev, lcu);
++	if (rc)
++		return rc;
++
++	spin_lock_irqsave(&lcu->lock, flags);
++	lcu->pav = NO_PAV;
++	for (i = 0; i < MAX_DEVICES_PER_LCU; ++i) {
++		switch (lcu->uac->unit[i].ua_type) {
++		case UA_BASE_PAV_ALIAS:
++			lcu->pav = BASE_PAV;
++			break;
++		case UA_HYPER_PAV_ALIAS:
++			lcu->pav = HYPER_PAV;
++			break;
++		}
++		if (lcu->pav != NO_PAV)
++			break;
++	}
++
++	list_for_each_entry_safe(device, tempdev, &lcu->active_devices,
++				 alias_list) {
++		_add_device_to_lcu(lcu, device);
++	}
++	spin_unlock_irqrestore(&lcu->lock, flags);
++	return 0;
++}
++
++static void lcu_update_work(struct work_struct *work)
++{
++	struct alias_lcu *lcu;
++	struct read_uac_work_data *ruac_data;
++	struct dasd_device *device;
++	unsigned long flags;
++	int rc;
++
++	ruac_data = container_of(work, struct read_uac_work_data, dwork.work);
++	lcu = container_of(ruac_data, struct alias_lcu, ruac_data);
++	device = ruac_data->device;
++	rc = _lcu_update(device, lcu);
++	/*
++	 * Need to check flags again, as there could have been another
++	 * prepare_update or a new device a new device while we were still
++	 * processing the data
++	 */
++	spin_lock_irqsave(&lcu->lock, flags);
++	if (rc || (lcu->flags & NEED_UAC_UPDATE)) {
++		DEV_MESSAGE(KERN_WARNING, device, "could not update"
++			    " alias data in lcu (rc = %d), retry later", rc);
++		schedule_delayed_work(&lcu->ruac_data.dwork, 30*HZ);
++	} else {
++		lcu->ruac_data.device = NULL;
++		lcu->flags &= ~UPDATE_PENDING;
++	}
++	spin_unlock_irqrestore(&lcu->lock, flags);
++}
++
++static int _schedule_lcu_update(struct alias_lcu *lcu,
++				struct dasd_device *device)
++{
++	struct dasd_device *usedev = NULL;
++	struct alias_pav_group *group;
++
++	lcu->flags |= NEED_UAC_UPDATE;
++	if (lcu->ruac_data.device) {
++		/* already scheduled or running */
++		return 0;
++	}
++	if (device && !list_empty(&device->alias_list))
++		usedev = device;
++
++	if (!usedev && !list_empty(&lcu->grouplist)) {
++		group = list_first_entry(&lcu->grouplist,
++					 struct alias_pav_group, group);
++		if (!list_empty(&group->baselist))
++			usedev = list_first_entry(&group->baselist,
++						  struct dasd_device,
++						  alias_list);
++		else if (!list_empty(&group->aliaslist))
++			usedev = list_first_entry(&group->aliaslist,
++						  struct dasd_device,
++						  alias_list);
++	}
++	if (!usedev && !list_empty(&lcu->active_devices)) {
++		usedev = list_first_entry(&lcu->active_devices,
++					  struct dasd_device, alias_list);
++	}
++	/*
++	 * if we haven't found a proper device yet, give up for now, the next
++	 * device that will be set active will trigger an lcu update
++	 */
++	if (!usedev)
++		return -EINVAL;
++	lcu->ruac_data.device = usedev;
++	schedule_delayed_work(&lcu->ruac_data.dwork, 0);
++	return 0;
++}
++
++int dasd_alias_add_device(struct dasd_device *device)
++{
++	struct dasd_eckd_private *private;
++	struct alias_lcu *lcu;
++	unsigned long flags;
++	int rc;
++
++	private = (struct dasd_eckd_private *) device->private;
++	lcu = private->lcu;
++	rc = 0;
++	spin_lock_irqsave(&lcu->lock, flags);
++	if (!(lcu->flags & UPDATE_PENDING)) {
++		rc = _add_device_to_lcu(lcu, device);
++		if (rc)
++			lcu->flags |= UPDATE_PENDING;
++	}
++	if (lcu->flags & UPDATE_PENDING) {
++		list_move(&device->alias_list, &lcu->active_devices);
++		_schedule_lcu_update(lcu, device);
++	}
++	spin_unlock_irqrestore(&lcu->lock, flags);
++	return rc;
++}
++
++int dasd_alias_remove_device(struct dasd_device *device)
++{
++	struct dasd_eckd_private *private;
++	struct alias_lcu *lcu;
++	unsigned long flags;
++
++	private = (struct dasd_eckd_private *) device->private;
++	lcu = private->lcu;
++	spin_lock_irqsave(&lcu->lock, flags);
++	_remove_device_from_lcu(lcu, device);
++	spin_unlock_irqrestore(&lcu->lock, flags);
++	return 0;
++}
++
++struct dasd_device *dasd_alias_get_start_dev(struct dasd_device *base_device)
++{
++
++	struct dasd_device *alias_device;
++	struct alias_pav_group *group;
++	struct alias_lcu *lcu;
++	struct dasd_eckd_private *private, *alias_priv;
++	unsigned long flags;
++
++	private = (struct dasd_eckd_private *) base_device->private;
++	group = private->pavgroup;
++	lcu = private->lcu;
++	if (!group || !lcu)
++		return NULL;
++	if (lcu->pav == NO_PAV ||
++	    lcu->flags & (NEED_UAC_UPDATE | UPDATE_PENDING))
++		return NULL;
 +
-+	/* reset */
-+	wm8739_write(client, R15, 0x00);
-+	/* filter setting, high path, offet clear */
-+	wm8739_write(client, R5, 0x000);
-+	/* ADC, OSC, Power Off mode Disable */
-+	wm8739_write(client, R6, 0x000);
-+	/* Digital Audio interface format:
-+	   Enable Master mode, 24 bit, MSB first/left justified */
-+	wm8739_write(client, R7, 0x049);
-+	/* sampling control: normal, 256fs, 48KHz sampling rate */
-+	wm8739_write(client, R8, 0x000);
-+	/* activate */
-+	wm8739_write(client, R9, 0x001);
-+	/* set volume/mute */
-+	wm8739_set_audio(client);
- 	return 0;
- }
- 
--static int wm8739_detach(struct i2c_client *client)
-+static int wm8739_remove(struct i2c_client *client)
- {
--	struct wm8739_state *state = i2c_get_clientdata(client);
--	int err;
--
--	err = i2c_detach_client(client);
--	if (err)
--		return err;
--
--	kfree(state);
--	kfree(client);
-+	kfree(i2c_get_clientdata(client));
- 	return 0;
- }
- 
--/* ----------------------------------------------------------------------- */
--
--/* i2c implementation */
--static struct i2c_driver i2c_driver = {
--	.driver = {
--		.name = "wm8739",
--	},
--	.id = I2C_DRIVERID_WM8739,
--	.attach_adapter = wm8739_probe,
--	.detach_client  = wm8739_detach,
-+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
-+	.name = "wm8739",
-+	.driverid = I2C_DRIVERID_WM8739,
- 	.command = wm8739_command,
-+	.probe = wm8739_probe,
-+	.remove = wm8739_remove,
- };
- 
--
--static int __init wm8739_init_module(void)
--{
--	return i2c_add_driver(&i2c_driver);
--}
--
--static void __exit wm8739_cleanup_module(void)
--{
--	i2c_del_driver(&i2c_driver);
--}
--
--module_init(wm8739_init_module);
--module_exit(wm8739_cleanup_module);
-diff --git a/drivers/media/video/wm8775.c b/drivers/media/video/wm8775.c
-index 9f7e894..869f9e7 100644
---- a/drivers/media/video/wm8775.c
-+++ b/drivers/media/video/wm8775.c
-@@ -34,6 +34,7 @@
- #include <linux/videodev.h>
- #include <media/v4l2-common.h>
- #include <media/v4l2-chip-ident.h>
-+#include <media/v4l2-i2c-drv-legacy.h>
- 
- MODULE_DESCRIPTION("wm8775 driver");
- MODULE_AUTHOR("Ulf Eklund, Hans Verkuil");
-@@ -44,6 +45,7 @@ static unsigned short normal_i2c[] = { 0x36 >> 1, I2C_CLIENT_END };
- 
- I2C_CLIENT_INSMOD;
- 
++	spin_lock_irqsave(&lcu->lock, flags);
++	alias_device = group->next;
++	if (!alias_device) {
++		if (list_empty(&group->aliaslist)) {
++			spin_unlock_irqrestore(&lcu->lock, flags);
++			return NULL;
++		} else {
++			alias_device = list_first_entry(&group->aliaslist,
++							struct dasd_device,
++							alias_list);
++		}
++	}
++	if (list_is_last(&alias_device->alias_list, &group->aliaslist))
++		group->next = list_first_entry(&group->aliaslist,
++					       struct dasd_device, alias_list);
++	else
++		group->next = list_first_entry(&alias_device->alias_list,
++					       struct dasd_device, alias_list);
++	spin_unlock_irqrestore(&lcu->lock, flags);
++	alias_priv = (struct dasd_eckd_private *) alias_device->private;
++	if ((alias_priv->count < private->count) && !alias_device->stopped)
++		return alias_device;
++	else
++		return NULL;
++}
 +
- /* ----------------------------------------------------------------------- */
- 
- enum {
-@@ -66,18 +68,15 @@ static int wm8775_write(struct i2c_client *client, int reg, u16 val)
- 		return -1;
- 	}
- 
--	for (i = 0; i < 3; i++) {
--		if (i2c_smbus_write_byte_data(client, (reg << 1) |
--					(val >> 8), val & 0xff) == 0) {
-+	for (i = 0; i < 3; i++)
-+		if (i2c_smbus_write_byte_data(client,
-+				(reg << 1) | (val >> 8), val & 0xff) == 0)
- 			return 0;
--		}
--	}
- 	v4l_err(client, "I2C: cannot write %03x to register R%d\n", val, reg);
- 	return -1;
- }
- 
--static int wm8775_command(struct i2c_client *client, unsigned int cmd,
--			  void *arg)
-+static int wm8775_command(struct i2c_client *client, unsigned cmd, void *arg)
- {
- 	struct wm8775_state *state = i2c_get_clientdata(client);
- 	struct v4l2_routing *route = arg;
-@@ -126,7 +125,8 @@ static int wm8775_command(struct i2c_client *client, unsigned int cmd,
- 		break;
- 
- 	case VIDIOC_G_CHIP_IDENT:
--		return v4l2_chip_ident_i2c_client(client, arg, V4L2_IDENT_WM8775, 0);
-+		return v4l2_chip_ident_i2c_client(client,
-+				arg, V4L2_IDENT_WM8775, 0);
- 
- 	case VIDIOC_LOG_STATUS:
- 		v4l_info(client, "Input: %d%s\n", state->input,
-@@ -159,105 +159,67 @@ static int wm8775_command(struct i2c_client *client, unsigned int cmd,
-  * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
-  */
- 
--static struct i2c_driver i2c_driver;
--
--static int wm8775_attach(struct i2c_adapter *adapter, int address, int kind)
-+static int wm8775_probe(struct i2c_client *client)
- {
--	struct i2c_client *client;
- 	struct wm8775_state *state;
- 
- 	/* Check if the adapter supports the needed features */
--	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
--		return 0;
--
--	client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
--	if (client == 0)
--		return -ENOMEM;
--
--	client->addr = address;
--	client->adapter = adapter;
--	client->driver = &i2c_driver;
--	snprintf(client->name, sizeof(client->name) - 1, "wm8775");
-+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
-+		return -EIO;
- 
--	v4l_info(client, "chip found @ 0x%x (%s)\n", address << 1, adapter->name);
-+	v4l_info(client, "chip found @ 0x%x (%s)\n",
-+			client->addr << 1, client->adapter->name);
- 
- 	state = kmalloc(sizeof(struct wm8775_state), GFP_KERNEL);
--	if (state == NULL) {
--		kfree(client);
-+	if (state == NULL)
- 		return -ENOMEM;
--	}
- 	state->input = 2;
- 	state->muted = 0;
- 	i2c_set_clientdata(client, state);
- 
--	/* initialize wm8775 */
--	wm8775_write(client, R23, 0x000);	/* RESET */
--	wm8775_write(client, R7, 0x000);	/* Disable zero cross detect timeout */
--	wm8775_write(client, R11, 0x021);	/* Left justified, 24-bit mode */
--	wm8775_write(client, R12, 0x102);	/* Master mode, clock ratio 256fs */
--	wm8775_write(client, R13, 0x000);	/* Powered up */
--	wm8775_write(client, R14, 0x1d4);	/* ADC gain +2.5dB, enable zero cross */
--	wm8775_write(client, R15, 0x1d4);	/* ADC gain +2.5dB, enable zero cross */
--	wm8775_write(client, R16, 0x1bf);	/* ALC Stereo, ALC target level -1dB FS */
--	/* max gain +8dB */
--	wm8775_write(client, R17, 0x185);	/* Enable gain control, use zero cross */
--	/* detection, ALC hold time 42.6 ms */
--	wm8775_write(client, R18, 0x0a2);	/* ALC gain ramp up delay 34 s, */
--	/* ALC gain ramp down delay 33 ms */
--	wm8775_write(client, R19, 0x005);	/* Enable noise gate, threshold -72dBfs */
--	wm8775_write(client, R20, 0x07a);	/* Transient window 4ms, lower PGA gain */
--	/* limit -1dB */
--	wm8775_write(client, R21, 0x102);	/* LRBOTH = 1, use input 2. */
--	i2c_attach_client(client);
--
-+	/* Initialize wm8775 */
++/*
++ * Summary unit check handling depends on the way alias devices
++ * are handled so it is done here rather then in dasd_eckd.c
++ */
++static int reset_summary_unit_check(struct alias_lcu *lcu,
++				    struct dasd_device *device,
++				    char reason)
++{
++	struct dasd_ccw_req *cqr;
++	int rc = 0;
 +
-+	/* RESET */
-+	wm8775_write(client, R23, 0x000);
-+	/* Disable zero cross detect timeout */
-+	wm8775_write(client, R7, 0x000);
-+	/* Left justified, 24-bit mode */
-+	wm8775_write(client, R11, 0x021);
-+	/* Master mode, clock ratio 256fs */
-+	wm8775_write(client, R12, 0x102);
-+	/* Powered up */
-+	wm8775_write(client, R13, 0x000);
-+	/* ADC gain +2.5dB, enable zero cross */
-+	wm8775_write(client, R14, 0x1d4);
-+	/* ADC gain +2.5dB, enable zero cross */
-+	wm8775_write(client, R15, 0x1d4);
-+	/* ALC Stereo, ALC target level -1dB FS max gain +8dB */
-+	wm8775_write(client, R16, 0x1bf);
-+	/* Enable gain control, use zero cross detection,
-+	   ALC hold time 42.6 ms */
-+	wm8775_write(client, R17, 0x185);
-+	/* ALC gain ramp up delay 34 s, ALC gain ramp down delay 33 ms */
-+	wm8775_write(client, R18, 0x0a2);
-+	/* Enable noise gate, threshold -72dBfs */
-+	wm8775_write(client, R19, 0x005);
-+	/* Transient window 4ms, lower PGA gain limit -1dB */
-+	wm8775_write(client, R20, 0x07a);
-+	/* LRBOTH = 1, use input 2. */
-+	wm8775_write(client, R21, 0x102);
- 	return 0;
- }
- 
--static int wm8775_probe(struct i2c_adapter *adapter)
-+static int wm8775_remove(struct i2c_client *client)
- {
--	if (adapter->class & I2C_CLASS_TV_ANALOG)
--		return i2c_probe(adapter, &addr_data, wm8775_attach);
-+	kfree(i2c_get_clientdata(client));
- 	return 0;
- }
- 
--static int wm8775_detach(struct i2c_client *client)
--{
--	struct wm8775_state *state = i2c_get_clientdata(client);
--	int err;
--
--	err = i2c_detach_client(client);
--	if (err) {
--		return err;
--	}
--	kfree(state);
--	kfree(client);
--
--	return 0;
--}
--
--/* ----------------------------------------------------------------------- */
--
--/* i2c implementation */
--static struct i2c_driver i2c_driver = {
--	.driver = {
--		.name = "wm8775",
--	},
--	.id             = I2C_DRIVERID_WM8775,
--	.attach_adapter = wm8775_probe,
--	.detach_client  = wm8775_detach,
--	.command        = wm8775_command,
-+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
-+	.name = "wm8775",
-+	.driverid = I2C_DRIVERID_WM8775,
-+	.command = wm8775_command,
-+	.probe = wm8775_probe,
-+	.remove = wm8775_remove,
- };
- 
--
--static int __init wm8775_init_module(void)
--{
--	return i2c_add_driver(&i2c_driver);
--}
--
--static void __exit wm8775_cleanup_module(void)
--{
--	i2c_del_driver(&i2c_driver);
--}
--
--module_init(wm8775_init_module);
--module_exit(wm8775_cleanup_module);
-diff --git a/drivers/media/video/zr364xx.c b/drivers/media/video/zr364xx.c
-index 6f18925..1fdbb46 100644
---- a/drivers/media/video/zr364xx.c
-+++ b/drivers/media/video/zr364xx.c
-@@ -749,7 +749,7 @@ static int zr364xx_mmap(struct file *file, struct vm_area_struct *vma)
- }
- 
- 
--static struct file_operations zr364xx_fops = {
-+static const struct file_operations zr364xx_fops = {
- 	.owner = THIS_MODULE,
- 	.open = zr364xx_open,
- 	.release = zr364xx_release,
-diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c
-index 52fb216..425f60c 100644
---- a/drivers/message/fusion/mptbase.c
-+++ b/drivers/message/fusion/mptbase.c
-@@ -2056,7 +2056,7 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
- 						ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
- 						    "mpt_upload:  alt_%s has cached_fw=%p \n",
- 						    ioc->name, ioc->alt_ioc->name, ioc->alt_ioc->cached_fw));
--						ioc->alt_ioc->cached_fw = NULL;
-+						ioc->cached_fw = NULL;
- 					}
- 				} else {
- 					printk(MYIOC_s_WARN_FMT
-@@ -2262,10 +2262,12 @@ mpt_adapter_disable(MPT_ADAPTER *ioc)
- 	int ret;
- 
- 	if (ioc->cached_fw != NULL) {
--		ddlprintk(ioc, printk(MYIOC_s_INFO_FMT
--		    "mpt_adapter_disable: Pushing FW onto adapter\n", ioc->name));
--		if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *)ioc->cached_fw, NO_SLEEP)) < 0) {
--			printk(MYIOC_s_WARN_FMT "firmware downloadboot failure (%d)!\n",
-+		ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: Pushing FW onto "
-+		    "adapter\n", __FUNCTION__, ioc->name));
-+		if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *)
-+		    ioc->cached_fw, CAN_SLEEP)) < 0) {
-+			printk(MYIOC_s_WARN_FMT
-+			    ": firmware downloadboot failure (%d)!\n",
- 			    ioc->name, ret);
- 		}
- 	}
-@@ -2303,13 +2305,7 @@ mpt_adapter_disable(MPT_ADAPTER *ioc)
- 		ioc->alloc_total -= sz;
- 	}
- 
--	if (ioc->cached_fw != NULL) {
--		sz = ioc->facts.FWImageSize;
--		pci_free_consistent(ioc->pcidev, sz,
--			ioc->cached_fw, ioc->cached_fw_dma);
--		ioc->cached_fw = NULL;
--		ioc->alloc_total -= sz;
--	}
-+	mpt_free_fw_memory(ioc);
- 
- 	kfree(ioc->spi_data.nvram);
- 	mpt_inactive_raid_list_free(ioc);
-@@ -3047,44 +3043,62 @@ SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
-  *
-  *	If memory has already been allocated, the same (cached) value
-  *	is returned.
-- */
--void
-+ *
-+ *	Return 0 if successfull, or non-zero for failure
-+ **/
-+int
- mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size)
- {
--	if (ioc->cached_fw)
--		return;  /* use already allocated memory */
--	if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
++	cqr = lcu->rsu_cqr;
++	strncpy((char *) &cqr->magic, "ECKD", 4);
++	ASCEBC((char *) &cqr->magic, 4);
++	cqr->cpaddr->cmd_code = DASD_ECKD_CCW_RSCK;
++	cqr->cpaddr->flags = 0 ;
++	cqr->cpaddr->count = 16;
++	cqr->cpaddr->cda = (__u32)(addr_t) cqr->data;
++	((char *)cqr->data)[0] = reason;
++
++	clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
++	cqr->retries = 255;	/* set retry counter to enable basic ERP */
++	cqr->startdev = device;
++	cqr->memdev = device;
++	cqr->block = NULL;
++	cqr->expires = 5 * HZ;
++	cqr->buildclk = get_clock();
++	cqr->status = DASD_CQR_FILLED;
++
++	rc = dasd_sleep_on_immediatly(cqr);
++	return rc;
++}
++
++static void _restart_all_base_devices_on_lcu(struct alias_lcu *lcu)
++{
++	struct alias_pav_group *pavgroup;
++	struct dasd_device *device;
++	struct dasd_eckd_private *private;
++
++	/* active and inactive list can contain alias as well as base devices */
++	list_for_each_entry(device, &lcu->active_devices, alias_list) {
++		private = (struct dasd_eckd_private *) device->private;
++		if (private->uid.type != UA_BASE_DEVICE)
++			continue;
++		dasd_schedule_block_bh(device->block);
++		dasd_schedule_device_bh(device);
++	}
++	list_for_each_entry(device, &lcu->inactive_devices, alias_list) {
++		private = (struct dasd_eckd_private *) device->private;
++		if (private->uid.type != UA_BASE_DEVICE)
++			continue;
++		dasd_schedule_block_bh(device->block);
++		dasd_schedule_device_bh(device);
++	}
++	list_for_each_entry(pavgroup, &lcu->grouplist, group) {
++		list_for_each_entry(device, &pavgroup->baselist, alias_list) {
++			dasd_schedule_block_bh(device->block);
++			dasd_schedule_device_bh(device);
++		}
++	}
++}
++
++static void flush_all_alias_devices_on_lcu(struct alias_lcu *lcu)
++{
++	struct alias_pav_group *pavgroup;
++	struct dasd_device *device, *temp;
++	struct dasd_eckd_private *private;
 +	int rc;
++	unsigned long flags;
++	LIST_HEAD(active);
 +
-+	if (ioc->cached_fw) {
-+		rc = 0;  /* use already allocated memory */
-+		goto out;
++	/*
++	 * Problem here ist that dasd_flush_device_queue may wait
++	 * for termination of a request to complete. We can't keep
++	 * the lcu lock during that time, so we must assume that
++	 * the lists may have changed.
++	 * Idea: first gather all active alias devices in a separate list,
++	 * then flush the first element of this list unlocked, and afterwards
++	 * check if it is still on the list before moving it to the
++	 * active_devices list.
++	 */
++
++	spin_lock_irqsave(&lcu->lock, flags);
++	list_for_each_entry_safe(device, temp, &lcu->active_devices,
++				 alias_list) {
++		private = (struct dasd_eckd_private *) device->private;
++		if (private->uid.type == UA_BASE_DEVICE)
++			continue;
++		list_move(&device->alias_list, &active);
 +	}
-+	else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
- 		ioc->cached_fw = ioc->alt_ioc->cached_fw;  /* use alt_ioc's memory */
- 		ioc->cached_fw_dma = ioc->alt_ioc->cached_fw_dma;
--		ioc->alloc_total += size;
--		ioc->alt_ioc->alloc_total -= size;
-+		rc = 0;
-+		goto out;
++
++	list_for_each_entry(pavgroup, &lcu->grouplist, group) {
++		list_splice_init(&pavgroup->aliaslist, &active);
 +	}
-+	ioc->cached_fw = pci_alloc_consistent(ioc->pcidev, size, &ioc->cached_fw_dma);
-+	if (!ioc->cached_fw) {
-+		printk(MYIOC_s_ERR_FMT "Unable to allocate memory for the cached firmware image!\n",
-+		    ioc->name);
-+		rc = -1;
- 	} else {
--		if ( (ioc->cached_fw = pci_alloc_consistent(ioc->pcidev, size, &ioc->cached_fw_dma) ) )
--			ioc->alloc_total += size;
-+		dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FW Image  @ %p[%p], sz=%d[%x] bytes\n",
-+		    ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, size, size));
-+		ioc->alloc_total += size;
-+		rc = 0;
- 	}
-+ out:
-+	return rc;
- }
++	while (!list_empty(&active)) {
++		device = list_first_entry(&active, struct dasd_device,
++					  alias_list);
++		spin_unlock_irqrestore(&lcu->lock, flags);
++		rc = dasd_flush_device_queue(device);
++		spin_lock_irqsave(&lcu->lock, flags);
++		/*
++		 * only move device around if it wasn't moved away while we
++		 * were waiting for the flush
++		 */
++		if (device == list_first_entry(&active,
++					       struct dasd_device, alias_list))
++			list_move(&device->alias_list, &lcu->active_devices);
++	}
++	spin_unlock_irqrestore(&lcu->lock, flags);
++}
 +
- /**
-  *	mpt_free_fw_memory - free firmware memory
-  *	@ioc: Pointer to MPT_ADAPTER structure
-  *
-  *	If alt_img is NULL, delete from ioc structure.
-  *	Else, delete a secondary image in same format.
-- */
-+ **/
- void
- mpt_free_fw_memory(MPT_ADAPTER *ioc)
- {
- 	int sz;
- 
-+	if (!ioc->cached_fw)
-+		return;
++/*
++ * This function is called in interrupt context, so the
++ * cdev lock for device is already locked!
++ */
++static void _stop_all_devices_on_lcu(struct alias_lcu *lcu,
++				     struct dasd_device *device)
++{
++	struct alias_pav_group *pavgroup;
++	struct dasd_device *pos;
 +
- 	sz = ioc->facts.FWImageSize;
--	dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "free_fw_memory: FW Image  @ %p[%p], sz=%d[%x] bytes\n",
--	    ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
-+	dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "free_fw_memory: FW Image  @ %p[%p], sz=%d[%x] bytes\n",
-+		 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
- 	pci_free_consistent(ioc->pcidev, sz, ioc->cached_fw, ioc->cached_fw_dma);
-+	ioc->alloc_total -= sz;
- 	ioc->cached_fw = NULL;
--
--	return;
- }
++	list_for_each_entry(pos, &lcu->active_devices, alias_list) {
++		if (pos != device)
++			spin_lock(get_ccwdev_lock(pos->cdev));
++		pos->stopped |= DASD_STOPPED_SU;
++		if (pos != device)
++			spin_unlock(get_ccwdev_lock(pos->cdev));
++	}
++	list_for_each_entry(pos, &lcu->inactive_devices, alias_list) {
++		if (pos != device)
++			spin_lock(get_ccwdev_lock(pos->cdev));
++		pos->stopped |= DASD_STOPPED_SU;
++		if (pos != device)
++			spin_unlock(get_ccwdev_lock(pos->cdev));
++	}
++	list_for_each_entry(pavgroup, &lcu->grouplist, group) {
++		list_for_each_entry(pos, &pavgroup->baselist, alias_list) {
++			if (pos != device)
++				spin_lock(get_ccwdev_lock(pos->cdev));
++			pos->stopped |= DASD_STOPPED_SU;
++			if (pos != device)
++				spin_unlock(get_ccwdev_lock(pos->cdev));
++		}
++		list_for_each_entry(pos, &pavgroup->aliaslist, alias_list) {
++			if (pos != device)
++				spin_lock(get_ccwdev_lock(pos->cdev));
++			pos->stopped |= DASD_STOPPED_SU;
++			if (pos != device)
++				spin_unlock(get_ccwdev_lock(pos->cdev));
++		}
++	}
++}
++
++static void _unstop_all_devices_on_lcu(struct alias_lcu *lcu)
++{
++	struct alias_pav_group *pavgroup;
++	struct dasd_device *device;
++	unsigned long flags;
++
++	list_for_each_entry(device, &lcu->active_devices, alias_list) {
++		spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
++		device->stopped &= ~DASD_STOPPED_SU;
++		spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
++	}
++
++	list_for_each_entry(device, &lcu->inactive_devices, alias_list) {
++		spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
++		device->stopped &= ~DASD_STOPPED_SU;
++		spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
++	}
++
++	list_for_each_entry(pavgroup, &lcu->grouplist, group) {
++		list_for_each_entry(device, &pavgroup->baselist, alias_list) {
++			spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
++			device->stopped &= ~DASD_STOPPED_SU;
++			spin_unlock_irqrestore(get_ccwdev_lock(device->cdev),
++					       flags);
++		}
++		list_for_each_entry(device, &pavgroup->aliaslist, alias_list) {
++			spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
++			device->stopped &= ~DASD_STOPPED_SU;
++			spin_unlock_irqrestore(get_ccwdev_lock(device->cdev),
++					       flags);
++		}
++	}
++}
++
++static void summary_unit_check_handling_work(struct work_struct *work)
++{
++	struct alias_lcu *lcu;
++	struct summary_unit_check_work_data *suc_data;
++	unsigned long flags;
++	struct dasd_device *device;
++
++	suc_data = container_of(work, struct summary_unit_check_work_data,
++				worker);
++	lcu = container_of(suc_data, struct alias_lcu, suc_data);
++	device = suc_data->device;
++
++	/* 1. flush alias devices */
++	flush_all_alias_devices_on_lcu(lcu);
++
++	/* 2. reset summary unit check */
++	spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
++	device->stopped &= ~(DASD_STOPPED_SU | DASD_STOPPED_PENDING);
++	spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
++	reset_summary_unit_check(lcu, device, suc_data->reason);
++
++	spin_lock_irqsave(&lcu->lock, flags);
++	_unstop_all_devices_on_lcu(lcu);
++	_restart_all_base_devices_on_lcu(lcu);
++	/* 3. read new alias configuration */
++	_schedule_lcu_update(lcu, device);
++	lcu->suc_data.device = NULL;
++	spin_unlock_irqrestore(&lcu->lock, flags);
++}
++
++/*
++ * note: this will be called from int handler context (cdev locked)
++ */
++void dasd_alias_handle_summary_unit_check(struct dasd_device *device,
++					  struct irb *irb)
++{
++	struct alias_lcu *lcu;
++	char reason;
++	struct dasd_eckd_private *private;
++
++	private = (struct dasd_eckd_private *) device->private;
++
++	reason = irb->ecw[8];
++	DEV_MESSAGE(KERN_WARNING, device, "%s %x",
++		    "eckd handle summary unit check: reason", reason);
++
++	lcu = private->lcu;
++	if (!lcu) {
++		DEV_MESSAGE(KERN_WARNING, device, "%s",
++			    "device not ready to handle summary"
++			    " unit check (no lcu structure)");
++		return;
++	}
++	spin_lock(&lcu->lock);
++	_stop_all_devices_on_lcu(lcu, device);
++	/* prepare for lcu_update */
++	private->lcu->flags |= NEED_UAC_UPDATE | UPDATE_PENDING;
++	/* If this device is about to be removed just return and wait for
++	 * the next interrupt on a different device
++	 */
++	if (list_empty(&device->alias_list)) {
++		DEV_MESSAGE(KERN_WARNING, device, "%s",
++			    "device is in offline processing,"
++			    " don't do summary unit check handling");
++		spin_unlock(&lcu->lock);
++		return;
++	}
++	if (lcu->suc_data.device) {
++		/* already scheduled or running */
++		DEV_MESSAGE(KERN_WARNING, device, "%s",
++			    "previous instance of summary unit check worker"
++			    " still pending");
++		spin_unlock(&lcu->lock);
++		return ;
++	}
++	lcu->suc_data.reason = reason;
++	lcu->suc_data.device = device;
++	spin_unlock(&lcu->lock);
++	schedule_work(&lcu->suc_data.worker);
++};
+diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c
+index 0c67258..f4fb402 100644
+--- a/drivers/s390/block/dasd_devmap.c
++++ b/drivers/s390/block/dasd_devmap.c
+@@ -49,22 +49,6 @@ struct dasd_devmap {
+ };
  
+ /*
+- * dasd_server_ssid_map contains a globally unique storage server subsystem ID.
+- * dasd_server_ssid_list contains the list of all subsystem IDs accessed by
+- * the DASD device driver.
+- */
+-struct dasd_server_ssid_map {
+-	struct list_head list;
+-	struct system_id {
+-		char vendor[4];
+-		char serial[15];
+-		__u16 ssid;
+-	} sid;
+-};
 -
- /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
- /**
-  *	mpt_do_upload - Construct and Send FWUpload request to MPT adapter port.
-@@ -3116,17 +3130,12 @@ mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
- 	if ((sz = ioc->facts.FWImageSize) == 0)
- 		return 0;
- 
--	mpt_alloc_fw_memory(ioc, sz);
-+	if (mpt_alloc_fw_memory(ioc, ioc->facts.FWImageSize) != 0)
-+		return -ENOMEM;
- 
- 	dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": FW Image  @ %p[%p], sz=%d[%x] bytes\n",
- 	    ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
- 
--	if (ioc->cached_fw == NULL) {
--		/* Major Failure.
--		 */
--		return -ENOMEM;
--	}
+-static struct list_head dasd_server_ssid_list;
 -
- 	prequest = (sleepFlag == NO_SLEEP) ? kzalloc(ioc->req_sz, GFP_ATOMIC) :
- 	    kzalloc(ioc->req_sz, GFP_KERNEL);
- 	if (!prequest) {
-@@ -3498,12 +3507,12 @@ KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag)
- static int
- mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
- {
--	MPT_ADAPTER	*iocp=NULL;
- 	u32 diag0val;
- 	u32 doorbell;
- 	int hard_reset_done = 0;
- 	int count = 0;
- 	u32 diag1val = 0;
-+	MpiFwHeader_t *cached_fw;	/* Pointer to FW */
- 
- 	/* Clear any existing interrupts */
- 	CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
-@@ -3635,22 +3644,24 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
- 		}
- 
- 		if (ioc->cached_fw)
--			iocp = ioc;
-+			cached_fw = (MpiFwHeader_t *)ioc->cached_fw;
- 		else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw)
--			iocp = ioc->alt_ioc;
--		if (iocp) {
-+			cached_fw = (MpiFwHeader_t *)ioc->alt_ioc->cached_fw;
-+		else
-+			cached_fw = NULL;
-+		if (cached_fw) {
- 			/* If the DownloadBoot operation fails, the
- 			 * IOC will be left unusable. This is a fatal error
- 			 * case.  _diag_reset will return < 0
- 			 */
- 			for (count = 0; count < 30; count ++) {
--				diag0val = CHIPREG_READ32(&iocp->chip->Diagnostic);
-+				diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
- 				if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
- 					break;
- 				}
- 
- 				dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "cached_fw: diag0val=%x count=%d\n",
--					iocp->name, diag0val, count));
-+					ioc->name, diag0val, count));
- 				/* wait 1 sec */
- 				if (sleepFlag == CAN_SLEEP) {
- 					msleep (1000);
-@@ -3658,8 +3669,7 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
- 					mdelay (1000);
- 				}
- 			}
--			if ((count = mpt_downloadboot(ioc,
--				(MpiFwHeader_t *)iocp->cached_fw, sleepFlag)) < 0) {
-+			if ((count = mpt_downloadboot(ioc, cached_fw, sleepFlag)) < 0) {
- 				printk(MYIOC_s_WARN_FMT
- 					"firmware downloadboot failure (%d)!\n", ioc->name, count);
- 			}
-diff --git a/drivers/message/fusion/mptbase.h b/drivers/message/fusion/mptbase.h
-index d7682e0..b49b706 100644
---- a/drivers/message/fusion/mptbase.h
-+++ b/drivers/message/fusion/mptbase.h
-@@ -907,7 +907,7 @@ extern u32	 mpt_GetIocState(MPT_ADAPTER *ioc, int cooked);
- extern void	 mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buf, int *size, int len, int showlan);
- extern int	 mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag);
- extern int	 mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *cfg);
--extern void	 mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size);
-+extern int	 mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size);
- extern void	 mpt_free_fw_memory(MPT_ADAPTER *ioc);
- extern int	 mpt_findImVolumes(MPT_ADAPTER *ioc);
- extern int	 mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode);
-diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c
-index e4c94f9..f77b329 100644
---- a/drivers/message/fusion/mptsas.c
-+++ b/drivers/message/fusion/mptsas.c
-@@ -1343,6 +1343,8 @@ static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
- 		smprep = (SmpPassthroughReply_t *)ioc->sas_mgmt.reply;
- 		memcpy(req->sense, smprep, sizeof(*smprep));
- 		req->sense_len = sizeof(*smprep);
-+		req->data_len = 0;
-+		rsp->data_len -= smprep->ResponseDataLength;
- 	} else {
- 		printk(MYIOC_s_ERR_FMT "%s: smp passthru reply failed to be returned\n",
- 		    ioc->name, __FUNCTION__);
-diff --git a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c
-index 626bb3c..5c614ec 100644
---- a/drivers/message/fusion/mptscsih.c
-+++ b/drivers/message/fusion/mptscsih.c
-@@ -111,7 +111,7 @@ int 		mptscsih_suspend(struct pci_dev *pdev, pm_message_t state);
- int 		mptscsih_resume(struct pci_dev *pdev);
- #endif
- 
--#define SNS_LEN(scp)	sizeof((scp)->sense_buffer)
-+#define SNS_LEN(scp)	SCSI_SENSE_BUFFERSIZE
- 
- /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
- /**
-diff --git a/drivers/message/i2o/i2o_scsi.c b/drivers/message/i2o/i2o_scsi.c
-index aa6fb94..1bcdbbb 100644
---- a/drivers/message/i2o/i2o_scsi.c
-+++ b/drivers/message/i2o/i2o_scsi.c
-@@ -370,7 +370,7 @@ static int i2o_scsi_reply(struct i2o_controller *c, u32 m,
- 	 */
- 	if (cmd->result)
- 		memcpy(cmd->sense_buffer, &msg->body[3],
--		       min(sizeof(cmd->sense_buffer), (size_t) 40));
-+		       min(SCSI_SENSE_BUFFERSIZE, 40));
- 
- 	/* only output error code if AdapterStatus is not HBA_SUCCESS */
- 	if ((error >> 8) & 0xff)
-diff --git a/drivers/mfd/ucb1x00-assabet.c b/drivers/mfd/ucb1x00-assabet.c
-index e325fa7..b7c8e78 100644
---- a/drivers/mfd/ucb1x00-assabet.c
-+++ b/drivers/mfd/ucb1x00-assabet.c
-@@ -20,7 +20,8 @@
- #include "ucb1x00.h"
- 
- #define UCB1X00_ATTR(name,input)\
--static ssize_t name##_show(struct class_device *dev, char *buf)	\
-+static ssize_t name##_show(struct device *dev, struct device_attribute *attr,
-+			   char *buf)	\
- {								\
- 	struct ucb1x00 *ucb = classdev_to_ucb1x00(dev);		\
- 	int val;						\
-@@ -29,7 +30,7 @@ static ssize_t name##_show(struct class_device *dev, char *buf)	\
- 	ucb1x00_adc_disable(ucb);				\
- 	return sprintf(buf, "%d\n", val);			\
- }								\
--static CLASS_DEVICE_ATTR(name,0444,name##_show,NULL)
-+static DEVICE_ATTR(name,0444,name##_show,NULL)
- 
- UCB1X00_ATTR(vbatt, UCB_ADC_INP_AD1);
- UCB1X00_ATTR(vcharger, UCB_ADC_INP_AD0);
-@@ -37,17 +38,17 @@ UCB1X00_ATTR(batt_temp, UCB_ADC_INP_AD2);
- 
- static int ucb1x00_assabet_add(struct ucb1x00_dev *dev)
- {
--	class_device_create_file(&dev->ucb->cdev, &class_device_attr_vbatt);
--	class_device_create_file(&dev->ucb->cdev, &class_device_attr_vcharger);
--	class_device_create_file(&dev->ucb->cdev, &class_device_attr_batt_temp);
-+	device_create_file(&dev->ucb->dev, &device_attr_vbatt);
-+	device_create_file(&dev->ucb->dev, &device_attr_vcharger);
-+	device_create_file(&dev->ucb->dev, &device_attr_batt_temp);
- 	return 0;
- }
- 
- static void ucb1x00_assabet_remove(struct ucb1x00_dev *dev)
- {
--	class_device_remove_file(&dev->ucb->cdev, &class_device_attr_batt_temp);
--	class_device_remove_file(&dev->ucb->cdev, &class_device_attr_vcharger);
--	class_device_remove_file(&dev->ucb->cdev, &class_device_attr_vbatt);
-+	device_remove_file(&dev->ucb->cdev, &device_attr_batt_temp);
-+	device_remove_file(&dev->ucb->cdev, &device_attr_vcharger);
-+	device_remove_file(&dev->ucb->cdev, &device_attr_vbatt);
- }
- 
- static struct ucb1x00_driver ucb1x00_assabet_driver = {
-diff --git a/drivers/mfd/ucb1x00-core.c b/drivers/mfd/ucb1x00-core.c
-index e03f1bc..f6b10dd 100644
---- a/drivers/mfd/ucb1x00-core.c
-+++ b/drivers/mfd/ucb1x00-core.c
-@@ -458,7 +458,7 @@ static int ucb1x00_detect_irq(struct ucb1x00 *ucb)
- 	return probe_irq_off(mask);
- }
- 
--static void ucb1x00_release(struct class_device *dev)
-+static void ucb1x00_release(struct device *dev)
- {
- 	struct ucb1x00 *ucb = classdev_to_ucb1x00(dev);
- 	kfree(ucb);
-@@ -466,7 +466,7 @@ static void ucb1x00_release(struct class_device *dev)
- 
- static struct class ucb1x00_class = {
- 	.name		= "ucb1x00",
--	.release	= ucb1x00_release,
-+	.dev_release	= ucb1x00_release,
- };
- 
- static int ucb1x00_probe(struct mcp *mcp)
-@@ -490,9 +490,9 @@ static int ucb1x00_probe(struct mcp *mcp)
- 		goto err_disable;
- 
- 
--	ucb->cdev.class = &ucb1x00_class;
--	ucb->cdev.dev = &mcp->attached_device;
--	strlcpy(ucb->cdev.class_id, "ucb1x00", sizeof(ucb->cdev.class_id));
-+	ucb->dev.class = &ucb1x00_class;
-+	ucb->dev.parent = &mcp->attached_device;
-+	strlcpy(ucb->dev.bus_id, "ucb1x00", sizeof(ucb->dev.bus_id));
- 
- 	spin_lock_init(&ucb->lock);
- 	spin_lock_init(&ucb->io_lock);
-@@ -517,7 +517,7 @@ static int ucb1x00_probe(struct mcp *mcp)
- 
- 	mcp_set_drvdata(mcp, ucb);
- 
--	ret = class_device_register(&ucb->cdev);
-+	ret = device_register(&ucb->dev);
- 	if (ret)
- 		goto err_irq;
- 
-@@ -554,7 +554,7 @@ static void ucb1x00_remove(struct mcp *mcp)
- 	mutex_unlock(&ucb1x00_mutex);
- 
- 	free_irq(ucb->irq, ucb);
--	class_device_unregister(&ucb->cdev);
-+	device_unregister(&ucb->dev);
+-/*
+  * Parameter parsing functions for dasd= parameter. The syntax is:
+  *   <devno>		: (0x)?[0-9a-fA-F]+
+  *   <busid>		: [0-0a-f]\.[0-9a-f]\.(0x)?[0-9a-fA-F]+
+@@ -721,8 +705,9 @@ dasd_ro_store(struct device *dev, struct device_attribute *attr,
+ 		devmap->features &= ~DASD_FEATURE_READONLY;
+ 	if (devmap->device)
+ 		devmap->device->features = devmap->features;
+-	if (devmap->device && devmap->device->gdp)
+-		set_disk_ro(devmap->device->gdp, val);
++	if (devmap->device && devmap->device->block
++	    && devmap->device->block->gdp)
++		set_disk_ro(devmap->device->block->gdp, val);
+ 	spin_unlock(&dasd_devmap_lock);
+ 	return count;
  }
+@@ -893,12 +878,16 @@ dasd_alias_show(struct device *dev, struct device_attribute *attr, char *buf)
  
- int ucb1x00_register_driver(struct ucb1x00_driver *drv)
-diff --git a/drivers/mfd/ucb1x00.h b/drivers/mfd/ucb1x00.h
-index ca8df80..a8ad8a0 100644
---- a/drivers/mfd/ucb1x00.h
-+++ b/drivers/mfd/ucb1x00.h
-@@ -120,7 +120,7 @@ struct ucb1x00 {
- 	u16			irq_fal_enbl;
- 	u16			irq_ris_enbl;
- 	struct ucb1x00_irq	irq_handler[16];
--	struct class_device	cdev;
-+	struct device		dev;
- 	struct list_head	node;
- 	struct list_head	devs;
- };
-@@ -144,7 +144,7 @@ struct ucb1x00_driver {
- 	int	(*resume)(struct ucb1x00_dev *dev);
- };
- 
--#define classdev_to_ucb1x00(cd)	container_of(cd, struct ucb1x00, cdev)
-+#define classdev_to_ucb1x00(cd)	container_of(cd, struct ucb1x00, dev)
- 
- int ucb1x00_register_driver(struct ucb1x00_driver *);
- void ucb1x00_unregister_driver(struct ucb1x00_driver *);
-diff --git a/drivers/misc/ibmasm/command.c b/drivers/misc/ibmasm/command.c
-index 6497872..1a0e797 100644
---- a/drivers/misc/ibmasm/command.c
-+++ b/drivers/misc/ibmasm/command.c
-@@ -26,11 +26,6 @@
- #include "lowlevel.h"
- 
- static void exec_next_command(struct service_processor *sp);
--static void free_command(struct kobject *kobj);
+ 	devmap = dasd_find_busid(dev->bus_id);
+ 	spin_lock(&dasd_devmap_lock);
+-	if (!IS_ERR(devmap))
+-		alias = devmap->uid.alias;
++	if (IS_ERR(devmap) || strlen(devmap->uid.vendor) == 0) {
++		spin_unlock(&dasd_devmap_lock);
++		return sprintf(buf, "0\n");
++	}
++	if (devmap->uid.type == UA_BASE_PAV_ALIAS ||
++	    devmap->uid.type == UA_HYPER_PAV_ALIAS)
++		alias = 1;
+ 	else
+ 		alias = 0;
+ 	spin_unlock(&dasd_devmap_lock);
 -
--static struct kobj_type ibmasm_cmd_kobj_type = {
--	.release = free_command,
--};
- 
- static atomic_t command_count = ATOMIC_INIT(0);
- 
-@@ -53,8 +48,7 @@ struct command *ibmasm_new_command(struct service_processor *sp, size_t buffer_s
- 	}
- 	cmd->buffer_size = buffer_size;
- 
--	kobject_init(&cmd->kobj);
--	cmd->kobj.ktype = &ibmasm_cmd_kobj_type;
-+	kref_init(&cmd->kref);
- 	cmd->lock = &sp->lock;
- 
- 	cmd->status = IBMASM_CMD_PENDING;
-@@ -67,9 +61,9 @@ struct command *ibmasm_new_command(struct service_processor *sp, size_t buffer_s
- 	return cmd;
+ 	return sprintf(buf, alias ? "1\n" : "0\n");
  }
  
--static void free_command(struct kobject *kobj)
-+void ibmasm_free_command(struct kref *kref)
- {
--	struct command *cmd = to_command(kobj);
-+	struct command *cmd = to_command(kref);
- 
- 	list_del(&cmd->queue_node);
- 	atomic_dec(&command_count);
-diff --git a/drivers/misc/ibmasm/ibmasm.h b/drivers/misc/ibmasm/ibmasm.h
-index de860bc..4d8a4e2 100644
---- a/drivers/misc/ibmasm/ibmasm.h
-+++ b/drivers/misc/ibmasm/ibmasm.h
-@@ -31,6 +31,7 @@
- #include <linux/slab.h>
- #include <linux/module.h>
- #include <linux/interrupt.h>
-+#include <linux/kref.h>
- #include <linux/device.h>
- #include <linux/input.h>
- 
-@@ -92,24 +93,25 @@ struct command {
- 	unsigned char		*buffer;
- 	size_t			buffer_size;
- 	int			status;
--	struct kobject		kobj;
-+	struct kref		kref;
- 	spinlock_t		*lock;
- };
--#define to_command(c) container_of(c, struct command, kobj)
-+#define to_command(c) container_of(c, struct command, kref)
- 
-+void ibmasm_free_command(struct kref *kref);
- static inline void command_put(struct command *cmd)
+@@ -930,19 +919,36 @@ static ssize_t
+ dasd_uid_show(struct device *dev, struct device_attribute *attr, char *buf)
  {
- 	unsigned long flags;
- 	spinlock_t *lock = cmd->lock;
+ 	struct dasd_devmap *devmap;
+-	char uid[UID_STRLEN];
++	char uid_string[UID_STRLEN];
++	char ua_string[3];
++	struct dasd_uid *uid;
  
- 	spin_lock_irqsave(lock, flags);
--	kobject_put(&cmd->kobj);
-+	kref_put(&cmd->kref, ibmasm_free_command);
- 	spin_unlock_irqrestore(lock, flags);
+ 	devmap = dasd_find_busid(dev->bus_id);
+ 	spin_lock(&dasd_devmap_lock);
+-	if (!IS_ERR(devmap) && strlen(devmap->uid.vendor) > 0)
+-		snprintf(uid, sizeof(uid), "%s.%s.%04x.%02x",
+-			 devmap->uid.vendor, devmap->uid.serial,
+-			 devmap->uid.ssid, devmap->uid.unit_addr);
+-	else
+-		uid[0] = 0;
++	if (IS_ERR(devmap) || strlen(devmap->uid.vendor) == 0) {
++		spin_unlock(&dasd_devmap_lock);
++		return sprintf(buf, "\n");
++	}
++	uid = &devmap->uid;
++	switch (uid->type) {
++	case UA_BASE_DEVICE:
++		sprintf(ua_string, "%02x", uid->real_unit_addr);
++		break;
++	case UA_BASE_PAV_ALIAS:
++		sprintf(ua_string, "%02x", uid->base_unit_addr);
++		break;
++	case UA_HYPER_PAV_ALIAS:
++		sprintf(ua_string, "xx");
++		break;
++	default:
++		/* should not happen, treat like base device */
++		sprintf(ua_string, "%02x", uid->real_unit_addr);
++		break;
++	}
++	snprintf(uid_string, sizeof(uid_string), "%s.%s.%04x.%s",
++		 uid->vendor, uid->serial, uid->ssid, ua_string);
+ 	spin_unlock(&dasd_devmap_lock);
+-
+-	return snprintf(buf, PAGE_SIZE, "%s\n", uid);
++	return snprintf(buf, PAGE_SIZE, "%s\n", uid_string);
  }
  
- static inline void command_get(struct command *cmd)
+ static DEVICE_ATTR(uid, 0444, dasd_uid_show, NULL);
+@@ -1040,39 +1046,16 @@ int
+ dasd_set_uid(struct ccw_device *cdev, struct dasd_uid *uid)
  {
--	kobject_get(&cmd->kobj);
-+	kref_get(&cmd->kref);
- }
- 
- 
-diff --git a/drivers/misc/tifm_7xx1.c b/drivers/misc/tifm_7xx1.c
-index 2d1b3df..54380da 100644
---- a/drivers/misc/tifm_7xx1.c
-+++ b/drivers/misc/tifm_7xx1.c
-@@ -149,7 +149,7 @@ static void tifm_7xx1_switch_media(struct work_struct *work)
- 	socket_change_set = fm->socket_change_set;
- 	fm->socket_change_set = 0;
+ 	struct dasd_devmap *devmap;
+-	struct dasd_server_ssid_map *srv, *tmp;
  
--	dev_dbg(fm->cdev.dev, "checking media set %x\n",
-+	dev_dbg(fm->dev.parent, "checking media set %x\n",
- 		socket_change_set);
+ 	devmap = dasd_find_busid(cdev->dev.bus_id);
+ 	if (IS_ERR(devmap))
+ 		return PTR_ERR(devmap);
  
- 	if (!socket_change_set) {
-@@ -164,7 +164,7 @@ static void tifm_7xx1_switch_media(struct work_struct *work)
- 		if (sock) {
- 			printk(KERN_INFO
- 			       "%s : demand removing card from socket %u:%u\n",
--			       fm->cdev.class_id, fm->id, cnt);
-+			       fm->dev.bus_id, fm->id, cnt);
- 			fm->sockets[cnt] = NULL;
- 			sock_addr = sock->addr;
- 			spin_unlock_irqrestore(&fm->lock, flags);
-diff --git a/drivers/misc/tifm_core.c b/drivers/misc/tifm_core.c
-index 8f77949..9754405 100644
---- a/drivers/misc/tifm_core.c
-+++ b/drivers/misc/tifm_core.c
-@@ -160,16 +160,16 @@ static struct bus_type tifm_bus_type = {
- 	.resume    = tifm_device_resume
- };
+-	/* generate entry for server_ssid_map */
+-	srv = (struct dasd_server_ssid_map *)
+-		kzalloc(sizeof(struct dasd_server_ssid_map), GFP_KERNEL);
+-	if (!srv)
+-		return -ENOMEM;
+-	strncpy(srv->sid.vendor, uid->vendor, sizeof(srv->sid.vendor) - 1);
+-	strncpy(srv->sid.serial, uid->serial, sizeof(srv->sid.serial) - 1);
+-	srv->sid.ssid = uid->ssid;
+-
+-	/* server is already contained ? */
+ 	spin_lock(&dasd_devmap_lock);
+ 	devmap->uid = *uid;
+-	list_for_each_entry(tmp, &dasd_server_ssid_list, list) {
+-		if (!memcmp(&srv->sid, &tmp->sid,
+-			    sizeof(struct system_id))) {
+-			kfree(srv);
+-			srv = NULL;
+-			break;
+-		}
+-	}
+-
+-	/* add servermap to serverlist */
+-	if (srv)
+-		list_add(&srv->list, &dasd_server_ssid_list);
+ 	spin_unlock(&dasd_devmap_lock);
  
--static void tifm_free(struct class_device *cdev)
-+static void tifm_free(struct device *dev)
- {
--	struct tifm_adapter *fm = container_of(cdev, struct tifm_adapter, cdev);
-+	struct tifm_adapter *fm = container_of(dev, struct tifm_adapter, dev);
+-	return (srv ? 1 : 0);
++	return 0;
+ }
+ EXPORT_SYMBOL_GPL(dasd_set_uid);
  
- 	kfree(fm);
+@@ -1138,9 +1121,6 @@ dasd_devmap_init(void)
+ 	dasd_max_devindex = 0;
+ 	for (i = 0; i < 256; i++)
+ 		INIT_LIST_HEAD(&dasd_hashlists[i]);
+-
+-	/* Initialize servermap structure. */
+-	INIT_LIST_HEAD(&dasd_server_ssid_list);
+ 	return 0;
  }
  
- static struct class tifm_adapter_class = {
- 	.name    = "tifm_adapter",
--	.release = tifm_free
-+	.dev_release = tifm_free
- };
+diff --git a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c
+index 571320a..d91df38 100644
+--- a/drivers/s390/block/dasd_diag.c
++++ b/drivers/s390/block/dasd_diag.c
+@@ -142,7 +142,7 @@ dasd_diag_erp(struct dasd_device *device)
+ 	int rc;
  
- struct tifm_adapter *tifm_alloc_adapter(unsigned int num_sockets,
-@@ -180,9 +180,9 @@ struct tifm_adapter *tifm_alloc_adapter(unsigned int num_sockets,
- 	fm = kzalloc(sizeof(struct tifm_adapter)
- 		     + sizeof(struct tifm_dev*) * num_sockets, GFP_KERNEL);
- 	if (fm) {
--		fm->cdev.class = &tifm_adapter_class;
--		fm->cdev.dev = dev;
--		class_device_initialize(&fm->cdev);
-+		fm->dev.class = &tifm_adapter_class;
-+		fm->dev.parent = dev;
-+		device_initialize(&fm->dev);
- 		spin_lock_init(&fm->lock);
- 		fm->num_sockets = num_sockets;
- 	}
-@@ -203,8 +203,8 @@ int tifm_add_adapter(struct tifm_adapter *fm)
+ 	mdsk_term_io(device);
+-	rc = mdsk_init_io(device, device->bp_block, 0, NULL);
++	rc = mdsk_init_io(device, device->block->bp_block, 0, NULL);
  	if (rc)
- 		return rc;
- 
--	snprintf(fm->cdev.class_id, BUS_ID_SIZE, "tifm%u", fm->id);
--	rc = class_device_add(&fm->cdev);
-+	snprintf(fm->dev.bus_id, BUS_ID_SIZE, "tifm%u", fm->id);
-+	rc = device_add(&fm->dev);
- 	if (rc) {
- 		spin_lock(&tifm_adapter_lock);
- 		idr_remove(&tifm_adapter_idr, fm->id);
-@@ -228,13 +228,13 @@ void tifm_remove_adapter(struct tifm_adapter *fm)
- 	spin_lock(&tifm_adapter_lock);
- 	idr_remove(&tifm_adapter_idr, fm->id);
- 	spin_unlock(&tifm_adapter_lock);
--	class_device_del(&fm->cdev);
-+	device_del(&fm->dev);
- }
- EXPORT_SYMBOL(tifm_remove_adapter);
+ 		DEV_MESSAGE(KERN_WARNING, device, "DIAG ERP unsuccessful, "
+ 			    "rc=%d", rc);
+@@ -158,11 +158,11 @@ dasd_start_diag(struct dasd_ccw_req * cqr)
+ 	struct dasd_diag_req *dreq;
+ 	int rc;
  
- void tifm_free_adapter(struct tifm_adapter *fm)
+-	device = cqr->device;
++	device = cqr->startdev;
+ 	if (cqr->retries < 0) {
+ 		DEV_MESSAGE(KERN_WARNING, device, "DIAG start_IO: request %p "
+ 			    "- no retry left)", cqr);
+-		cqr->status = DASD_CQR_FAILED;
++		cqr->status = DASD_CQR_ERROR;
+ 		return -EIO;
+ 	}
+ 	private = (struct dasd_diag_private *) device->private;
+@@ -184,7 +184,7 @@ dasd_start_diag(struct dasd_ccw_req * cqr)
+ 	switch (rc) {
+ 	case 0: /* Synchronous I/O finished successfully */
+ 		cqr->stopclk = get_clock();
+-		cqr->status = DASD_CQR_DONE;
++		cqr->status = DASD_CQR_SUCCESS;
+ 		/* Indicate to calling function that only a dasd_schedule_bh()
+ 		   and no timer is needed */
+                 rc = -EACCES;
+@@ -209,12 +209,12 @@ dasd_diag_term_IO(struct dasd_ccw_req * cqr)
  {
--	class_device_put(&fm->cdev);
-+	put_device(&fm->dev);
- }
- EXPORT_SYMBOL(tifm_free_adapter);
- 
-@@ -261,9 +261,9 @@ struct tifm_dev *tifm_alloc_device(struct tifm_adapter *fm, unsigned int id,
- 		sock->card_event = tifm_dummy_event;
- 		sock->data_event = tifm_dummy_event;
- 
--		sock->dev.parent = fm->cdev.dev;
-+		sock->dev.parent = fm->dev.parent;
- 		sock->dev.bus = &tifm_bus_type;
--		sock->dev.dma_mask = fm->cdev.dev->dma_mask;
-+		sock->dev.dma_mask = fm->dev.parent->dma_mask;
- 		sock->dev.release = tifm_free_device;
- 
- 		snprintf(sock->dev.bus_id, BUS_ID_SIZE,
-diff --git a/drivers/mmc/host/omap.c b/drivers/mmc/host/omap.c
-index 971e18b..c9dfeb1 100644
---- a/drivers/mmc/host/omap.c
-+++ b/drivers/mmc/host/omap.c
-@@ -25,6 +25,7 @@
- #include <linux/mmc/card.h>
- #include <linux/clk.h>
- #include <linux/scatterlist.h>
-+#include <linux/i2c/tps65010.h>
+ 	struct dasd_device *device;
  
- #include <asm/io.h>
- #include <asm/irq.h>
-@@ -35,7 +36,6 @@
- #include <asm/arch/dma.h>
- #include <asm/arch/mux.h>
- #include <asm/arch/fpga.h>
--#include <asm/arch/tps65010.h>
+-	device = cqr->device;
++	device = cqr->startdev;
+ 	mdsk_term_io(device);
+-	mdsk_init_io(device, device->bp_block, 0, NULL);
+-	cqr->status = DASD_CQR_CLEAR;
++	mdsk_init_io(device, device->block->bp_block, 0, NULL);
++	cqr->status = DASD_CQR_CLEAR_PENDING;
+ 	cqr->stopclk = get_clock();
+-	dasd_schedule_bh(device);
++	dasd_schedule_device_bh(device);
+ 	return 0;
+ }
  
- #define	OMAP_MMC_REG_CMD	0x00
- #define	OMAP_MMC_REG_ARGL	0x04
-diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c
-index 22ed96c..a0cee86 100644
---- a/drivers/mtd/mtdchar.c
-+++ b/drivers/mtd/mtdchar.c
-@@ -27,12 +27,10 @@ static void mtd_notify_add(struct mtd_info* mtd)
- 	if (!mtd)
+@@ -247,7 +247,7 @@ dasd_ext_handler(__u16 code)
  		return;
+ 	}
+ 	cqr = (struct dasd_ccw_req *) ip;
+-	device = (struct dasd_device *) cqr->device;
++	device = (struct dasd_device *) cqr->startdev;
+ 	if (strncmp(device->discipline->ebcname, (char *) &cqr->magic, 4)) {
+ 		DEV_MESSAGE(KERN_WARNING, device,
+ 			    " magic number of dasd_ccw_req 0x%08X doesn't"
+@@ -260,10 +260,10 @@ dasd_ext_handler(__u16 code)
+ 	spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
  
--	class_device_create(mtd_class, NULL, MKDEV(MTD_CHAR_MAJOR, mtd->index*2),
--			    NULL, "mtd%d", mtd->index);
-+	device_create(mtd_class, NULL, MKDEV(MTD_CHAR_MAJOR, mtd->index*2), "mtd%d", mtd->index);
- 
--	class_device_create(mtd_class, NULL,
--			    MKDEV(MTD_CHAR_MAJOR, mtd->index*2+1),
--			    NULL, "mtd%dro", mtd->index);
-+	device_create(mtd_class, NULL,
-+		      MKDEV(MTD_CHAR_MAJOR, mtd->index*2+1), "mtd%dro", mtd->index);
- }
- 
- static void mtd_notify_remove(struct mtd_info* mtd)
-@@ -40,8 +38,8 @@ static void mtd_notify_remove(struct mtd_info* mtd)
- 	if (!mtd)
+ 	/* Check for a pending clear operation */
+-	if (cqr->status == DASD_CQR_CLEAR) {
+-		cqr->status = DASD_CQR_QUEUED;
+-		dasd_clear_timer(device);
+-		dasd_schedule_bh(device);
++	if (cqr->status == DASD_CQR_CLEAR_PENDING) {
++		cqr->status = DASD_CQR_CLEARED;
++		dasd_device_clear_timer(device);
++		dasd_schedule_device_bh(device);
+ 		spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
  		return;
+ 	}
+@@ -272,11 +272,11 @@ dasd_ext_handler(__u16 code)
  
--	class_device_destroy(mtd_class, MKDEV(MTD_CHAR_MAJOR, mtd->index*2));
--	class_device_destroy(mtd_class, MKDEV(MTD_CHAR_MAJOR, mtd->index*2+1));
-+	device_destroy(mtd_class, MKDEV(MTD_CHAR_MAJOR, mtd->index*2));
-+	device_destroy(mtd_class, MKDEV(MTD_CHAR_MAJOR, mtd->index*2+1));
- }
+ 	expires = 0;
+ 	if (status == 0) {
+-		cqr->status = DASD_CQR_DONE;
++		cqr->status = DASD_CQR_SUCCESS;
+ 		/* Start first request on queue if possible -> fast_io. */
+ 		if (!list_empty(&device->ccw_queue)) {
+ 			next = list_entry(device->ccw_queue.next,
+-					  struct dasd_ccw_req, list);
++					  struct dasd_ccw_req, devlist);
+ 			if (next->status == DASD_CQR_QUEUED) {
+ 				rc = dasd_start_diag(next);
+ 				if (rc == 0)
+@@ -296,10 +296,10 @@ dasd_ext_handler(__u16 code)
+ 	}
  
- static struct mtd_notifier notifier = {
-diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c
-index 7d7758f..57772be 100644
---- a/drivers/net/ibmveth.c
-+++ b/drivers/net/ibmveth.c
-@@ -1179,13 +1179,15 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_
+ 	if (expires != 0)
+-		dasd_set_timer(device, expires);
++		dasd_device_set_timer(device, expires);
+ 	else
+-		dasd_clear_timer(device);
+-	dasd_schedule_bh(device);
++		dasd_device_clear_timer(device);
++	dasd_schedule_device_bh(device);
  
- 	for(i = 0; i<IbmVethNumBufferPools; i++) {
- 		struct kobject *kobj = &adapter->rx_buff_pool[i].kobj;
-+		int error;
+ 	spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
+ }
+@@ -309,6 +309,7 @@ dasd_ext_handler(__u16 code)
+ static int
+ dasd_diag_check_device(struct dasd_device *device)
+ {
++	struct dasd_block *block;
+ 	struct dasd_diag_private *private;
+ 	struct dasd_diag_characteristics *rdc_data;
+ 	struct dasd_diag_bio bio;
+@@ -328,6 +329,16 @@ dasd_diag_check_device(struct dasd_device *device)
+ 		ccw_device_get_id(device->cdev, &private->dev_id);
+ 		device->private = (void *) private;
+ 	}
++	block = dasd_alloc_block();
++	if (IS_ERR(block)) {
++		DEV_MESSAGE(KERN_WARNING, device, "%s",
++			    "could not allocate dasd block structure");
++		kfree(device->private);
++		return PTR_ERR(block);
++	}
++	device->block = block;
++	block->base = device;
 +
- 		ibmveth_init_buffer_pool(&adapter->rx_buff_pool[i], i,
- 					 pool_count[i], pool_size[i],
- 					 pool_active[i]);
--		kobj->parent = &dev->dev.kobj;
--		kobject_set_name(kobj, "pool%d", i);
--		kobj->ktype = &ktype_veth_pool;
--		kobject_register(kobj);
-+		error = kobject_init_and_add(kobj, &ktype_veth_pool,
-+					     &dev->dev.kobj, "pool%d", i);
-+		if (!error)
-+			kobject_uevent(kobj, KOBJ_ADD);
+ 	/* Read Device Characteristics */
+ 	rdc_data = (void *) &(private->rdc_data);
+ 	rdc_data->dev_nr = private->dev_id.devno;
+@@ -409,14 +420,14 @@ dasd_diag_check_device(struct dasd_device *device)
+ 		  sizeof(DASD_DIAG_CMS1)) == 0) {
+ 		/* get formatted blocksize from label block */
+ 		bsize = (unsigned int) label->block_size;
+-		device->blocks = (unsigned long) label->block_count;
++		block->blocks = (unsigned long) label->block_count;
+ 	} else
+-		device->blocks = end_block;
+-	device->bp_block = bsize;
+-	device->s2b_shift = 0;	/* bits to shift 512 to get a block */
++		block->blocks = end_block;
++	block->bp_block = bsize;
++	block->s2b_shift = 0;	/* bits to shift 512 to get a block */
+ 	for (sb = 512; sb < bsize; sb = sb << 1)
+-		device->s2b_shift++;
+-	rc = mdsk_init_io(device, device->bp_block, 0, NULL);
++		block->s2b_shift++;
++	rc = mdsk_init_io(device, block->bp_block, 0, NULL);
+ 	if (rc) {
+ 		DEV_MESSAGE(KERN_WARNING, device, "DIAG initialization "
+ 			"failed (rc=%d)", rc);
+@@ -424,9 +435,9 @@ dasd_diag_check_device(struct dasd_device *device)
+ 	} else {
+ 		DEV_MESSAGE(KERN_INFO, device,
+ 			    "(%ld B/blk): %ldkB",
+-			    (unsigned long) device->bp_block,
+-			    (unsigned long) (device->blocks <<
+-				device->s2b_shift) >> 1);
++			    (unsigned long) block->bp_block,
++			    (unsigned long) (block->blocks <<
++				block->s2b_shift) >> 1);
  	}
+ out:
+ 	free_page((long) label);
+@@ -436,22 +447,16 @@ out:
+ /* Fill in virtual disk geometry for device. Return zero on success, non-zero
+  * otherwise. */
+ static int
+-dasd_diag_fill_geometry(struct dasd_device *device, struct hd_geometry *geo)
++dasd_diag_fill_geometry(struct dasd_block *block, struct hd_geometry *geo)
+ {
+-	if (dasd_check_blocksize(device->bp_block) != 0)
++	if (dasd_check_blocksize(block->bp_block) != 0)
+ 		return -EINVAL;
+-	geo->cylinders = (device->blocks << device->s2b_shift) >> 10;
++	geo->cylinders = (block->blocks << block->s2b_shift) >> 10;
+ 	geo->heads = 16;
+-	geo->sectors = 128 >> device->s2b_shift;
++	geo->sectors = 128 >> block->s2b_shift;
+ 	return 0;
+ }
  
- 	ibmveth_debug_printk("adapter @ 0x%p\n", adapter);
-@@ -1234,7 +1236,7 @@ static int __devexit ibmveth_remove(struct vio_dev *dev)
- 	int i;
- 
- 	for(i = 0; i<IbmVethNumBufferPools; i++)
--		kobject_unregister(&adapter->rx_buff_pool[i].kobj);
-+		kobject_put(&adapter->rx_buff_pool[i].kobj);
- 
- 	unregister_netdev(netdev);
+-static dasd_era_t
+-dasd_diag_examine_error(struct dasd_ccw_req * cqr, struct irb * stat)
+-{
+-	return dasd_era_fatal;
+-}
+-
+ static dasd_erp_fn_t
+ dasd_diag_erp_action(struct dasd_ccw_req * cqr)
+ {
+@@ -466,8 +471,9 @@ dasd_diag_erp_postaction(struct dasd_ccw_req * cqr)
  
-diff --git a/drivers/net/iseries_veth.c b/drivers/net/iseries_veth.c
-index 97bd9dc..419861c 100644
---- a/drivers/net/iseries_veth.c
-+++ b/drivers/net/iseries_veth.c
-@@ -815,7 +815,7 @@ static int veth_init_connection(u8 rlp)
+ /* Create DASD request from block device request. Return pointer to new
+  * request on success, ERR_PTR otherwise. */
+-static struct dasd_ccw_req *
+-dasd_diag_build_cp(struct dasd_device * device, struct request *req)
++static struct dasd_ccw_req *dasd_diag_build_cp(struct dasd_device *memdev,
++					       struct dasd_block *block,
++					       struct request *req)
  {
- 	struct veth_lpar_connection *cnx;
- 	struct veth_msg *msgs;
--	int i, rc;
-+	int i;
+ 	struct dasd_ccw_req *cqr;
+ 	struct dasd_diag_req *dreq;
+@@ -486,17 +492,17 @@ dasd_diag_build_cp(struct dasd_device * device, struct request *req)
+ 		rw_cmd = MDSK_WRITE_REQ;
+ 	else
+ 		return ERR_PTR(-EINVAL);
+-	blksize = device->bp_block;
++	blksize = block->bp_block;
+ 	/* Calculate record id of first and last block. */
+-	first_rec = req->sector >> device->s2b_shift;
+-	last_rec = (req->sector + req->nr_sectors - 1) >> device->s2b_shift;
++	first_rec = req->sector >> block->s2b_shift;
++	last_rec = (req->sector + req->nr_sectors - 1) >> block->s2b_shift;
+ 	/* Check struct bio and count the number of blocks for the request. */
+ 	count = 0;
+ 	rq_for_each_segment(bv, req, iter) {
+ 		if (bv->bv_len & (blksize - 1))
+ 			/* Fba can only do full blocks. */
+ 			return ERR_PTR(-EINVAL);
+-		count += bv->bv_len >> (device->s2b_shift + 9);
++		count += bv->bv_len >> (block->s2b_shift + 9);
+ 	}
+ 	/* Paranoia. */
+ 	if (count != last_rec - first_rec + 1)
+@@ -505,7 +511,7 @@ dasd_diag_build_cp(struct dasd_device * device, struct request *req)
+ 	datasize = sizeof(struct dasd_diag_req) +
+ 		count*sizeof(struct dasd_diag_bio);
+ 	cqr = dasd_smalloc_request(dasd_diag_discipline.name, 0,
+-				   datasize, device);
++				   datasize, memdev);
+ 	if (IS_ERR(cqr))
+ 		return cqr;
  
- 	if ( (rlp == this_lp)
- 	     || ! HvLpConfig_doLpsCommunicateOnVirtualLan(this_lp, rlp) )
-@@ -844,11 +844,7 @@ static int veth_init_connection(u8 rlp)
+@@ -529,7 +535,9 @@ dasd_diag_build_cp(struct dasd_device * device, struct request *req)
+ 	cqr->buildclk = get_clock();
+ 	if (req->cmd_flags & REQ_FAILFAST)
+ 		set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags);
+-	cqr->device = device;
++	cqr->startdev = memdev;
++	cqr->memdev = memdev;
++	cqr->block = block;
+ 	cqr->expires = DIAG_TIMEOUT;
+ 	cqr->status = DASD_CQR_FILLED;
+ 	return cqr;
+@@ -543,10 +551,15 @@ dasd_diag_free_cp(struct dasd_ccw_req *cqr, struct request *req)
+ 	int status;
  
- 	/* This gets us 1 reference, which is held on behalf of the driver
- 	 * infrastructure. It's released at module unload. */
--	kobject_init(&cnx->kobject);
--	cnx->kobject.ktype = &veth_lpar_connection_ktype;
--	rc = kobject_set_name(&cnx->kobject, "cnx%.2d", rlp);
--	if (rc != 0)
--		return rc;
-+	kobject_init(&cnx->kobject, &veth_lpar_connection_ktype);
+ 	status = cqr->status == DASD_CQR_DONE;
+-	dasd_sfree_request(cqr, cqr->device);
++	dasd_sfree_request(cqr, cqr->memdev);
+ 	return status;
+ }
  
- 	msgs = kcalloc(VETH_NUMBUFFERS, sizeof(struct veth_msg), GFP_KERNEL);
- 	if (! msgs) {
-@@ -1087,11 +1083,8 @@ static struct net_device * __init veth_probe_one(int vlan,
- 		return NULL;
- 	}
++static void dasd_diag_handle_terminated_request(struct dasd_ccw_req *cqr)
++{
++	cqr->status = DASD_CQR_FILLED;
++};
++
+ /* Fill in IOCTL data for device. */
+ static int
+ dasd_diag_fill_info(struct dasd_device * device,
+@@ -583,7 +596,7 @@ static struct dasd_discipline dasd_diag_discipline = {
+ 	.fill_geometry = dasd_diag_fill_geometry,
+ 	.start_IO = dasd_start_diag,
+ 	.term_IO = dasd_diag_term_IO,
+-	.examine_error = dasd_diag_examine_error,
++	.handle_terminated_request = dasd_diag_handle_terminated_request,
+ 	.erp_action = dasd_diag_erp_action,
+ 	.erp_postaction = dasd_diag_erp_postaction,
+ 	.build_cp = dasd_diag_build_cp,
+diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c
+index 44adf84..61f1693 100644
+--- a/drivers/s390/block/dasd_eckd.c
++++ b/drivers/s390/block/dasd_eckd.c
+@@ -52,16 +52,6 @@ MODULE_LICENSE("GPL");
  
--	kobject_init(&port->kobject);
--	port->kobject.parent = &dev->dev.kobj;
--	port->kobject.ktype  = &veth_port_ktype;
--	kobject_set_name(&port->kobject, "veth_port");
--	if (0 != kobject_add(&port->kobject))
-+	kobject_init(&port->kobject, &veth_port_ktype);
-+	if (0 != kobject_add(&port->kobject, &dev->dev.kobj, "veth_port"))
- 		veth_error("Failed adding port for %s to sysfs.\n", dev->name);
+ static struct dasd_discipline dasd_eckd_discipline;
  
- 	veth_info("%s attached to iSeries vlan %d (LPAR map = 0x%.4X)\n",
-@@ -1711,9 +1704,9 @@ static int __init veth_module_init(void)
- 			continue;
+-struct dasd_eckd_private {
+-	struct dasd_eckd_characteristics rdc_data;
+-	struct dasd_eckd_confdata conf_data;
+-	struct dasd_eckd_path path_data;
+-	struct eckd_count count_area[5];
+-	int init_cqr_status;
+-	int uses_cdl;
+-	struct attrib_data_t attrib;	/* e.g. cache operations */
+-};
+-
+ /* The ccw bus type uses this table to find devices that it sends to
+  * dasd_eckd_probe */
+ static struct ccw_device_id dasd_eckd_ids[] = {
+@@ -188,7 +178,7 @@ check_XRC (struct ccw1         *de_ccw,
+ 	if (rc == -ENOSYS || rc == -EACCES)
+ 		rc = 0;
  
- 		kobj = &veth_cnx[i]->kobject;
--		kobj->parent = &veth_driver.driver.kobj;
- 		/* If the add failes, complain but otherwise continue */
--		if (0 != kobject_add(kobj))
-+		if (0 != driver_add_kobj(&veth_driver.driver, kobj,
-+					"cnx%.2d", veth_cnx[i]->remote_lp))
- 			veth_error("cnx %d: Failed adding to sysfs.\n", i);
- 	}
+-	de_ccw->count = sizeof (struct DE_eckd_data);
++	de_ccw->count = sizeof(struct DE_eckd_data);
+ 	de_ccw->flags |= CCW_FLAG_SLI;
+ 	return rc;
+ }
+@@ -208,7 +198,7 @@ define_extent(struct ccw1 * ccw, struct DE_eckd_data * data, int trk,
+ 	ccw->count = 16;
+ 	ccw->cda = (__u32) __pa(data);
  
-diff --git a/drivers/net/mlx4/fw.c b/drivers/net/mlx4/fw.c
-index 5064873..535a446 100644
---- a/drivers/net/mlx4/fw.c
-+++ b/drivers/net/mlx4/fw.c
-@@ -202,7 +202,7 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
- 	MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_EQ_OFFSET);
- 	dev_cap->reserved_eqs = 1 << (field & 0xf);
- 	MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_EQ_OFFSET);
--	dev_cap->max_eqs = 1 << (field & 0x7);
-+	dev_cap->max_eqs = 1 << (field & 0xf);
- 	MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_MTT_OFFSET);
- 	dev_cap->reserved_mtts = 1 << (field >> 4);
- 	MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_MRW_SZ_OFFSET);
-diff --git a/drivers/net/wan/cosa.c b/drivers/net/wan/cosa.c
-index ff37bf4..1d706ea 100644
---- a/drivers/net/wan/cosa.c
-+++ b/drivers/net/wan/cosa.c
-@@ -395,8 +395,7 @@ static int __init cosa_init(void)
- 		goto out_chrdev;
- 	}
- 	for (i=0; i<nr_cards; i++) {
--		class_device_create(cosa_class, NULL, MKDEV(cosa_major, i),
--				NULL, "cosa%d", i);
-+		device_create(cosa_class, NULL, MKDEV(cosa_major, i), "cosa%d", i);
- 	}
- 	err = 0;
- 	goto out;
-@@ -415,7 +414,7 @@ static void __exit cosa_exit(void)
- 	printk(KERN_INFO "Unloading the cosa module\n");
+-	memset(data, 0, sizeof (struct DE_eckd_data));
++	memset(data, 0, sizeof(struct DE_eckd_data));
+ 	switch (cmd) {
+ 	case DASD_ECKD_CCW_READ_HOME_ADDRESS:
+ 	case DASD_ECKD_CCW_READ_RECORD_ZERO:
+@@ -280,6 +270,132 @@ define_extent(struct ccw1 * ccw, struct DE_eckd_data * data, int trk,
+ 	return rc;
+ }
  
- 	for (i=0; i<nr_cards; i++)
--		class_device_destroy(cosa_class, MKDEV(cosa_major, i));
-+		device_destroy(cosa_class, MKDEV(cosa_major, i));
- 	class_destroy(cosa_class);
- 	for (cosa=cosa_cards; nr_cards--; cosa++) {
- 		/* Clean up the per-channel data */
-diff --git a/drivers/parisc/pdc_stable.c b/drivers/parisc/pdc_stable.c
-index ebb09e9..de34aa9 100644
---- a/drivers/parisc/pdc_stable.c
-+++ b/drivers/parisc/pdc_stable.c
-@@ -120,7 +120,7 @@ struct pdcspath_entry pdcspath_entry_##_name = { \
- };
++static int check_XRC_on_prefix(struct PFX_eckd_data *pfxdata,
++			       struct dasd_device  *device)
++{
++	struct dasd_eckd_private *private;
++	int rc;
++
++	private = (struct dasd_eckd_private *) device->private;
++	if (!private->rdc_data.facilities.XRC_supported)
++		return 0;
++
++	/* switch on System Time Stamp - needed for XRC Support */
++	pfxdata->define_extend.ga_extended |= 0x08; /* 'Time Stamp Valid'   */
++	pfxdata->define_extend.ga_extended |= 0x02; /* 'Extended Parameter' */
++	pfxdata->validity.time_stamp = 1;	    /* 'Time Stamp Valid'   */
++
++	rc = get_sync_clock(&pfxdata->define_extend.ep_sys_time);
++	/* Ignore return code if sync clock is switched off. */
++	if (rc == -ENOSYS || rc == -EACCES)
++		rc = 0;
++	return rc;
++}
++
++static int prefix(struct ccw1 *ccw, struct PFX_eckd_data *pfxdata, int trk,
++		  int totrk, int cmd, struct dasd_device *basedev,
++		  struct dasd_device *startdev)
++{
++	struct dasd_eckd_private *basepriv, *startpriv;
++	struct DE_eckd_data *data;
++	struct ch_t geo, beg, end;
++	int rc = 0;
++
++	basepriv = (struct dasd_eckd_private *) basedev->private;
++	startpriv = (struct dasd_eckd_private *) startdev->private;
++	data = &pfxdata->define_extend;
++
++	ccw->cmd_code = DASD_ECKD_CCW_PFX;
++	ccw->flags = 0;
++	ccw->count = sizeof(*pfxdata);
++	ccw->cda = (__u32) __pa(pfxdata);
++
++	memset(pfxdata, 0, sizeof(*pfxdata));
++	/* prefix data */
++	pfxdata->format = 0;
++	pfxdata->base_address = basepriv->conf_data.ned1.unit_addr;
++	pfxdata->base_lss = basepriv->conf_data.ned1.ID;
++	pfxdata->validity.define_extend = 1;
++
++	/* private uid is kept up to date, conf_data may be outdated */
++	if (startpriv->uid.type != UA_BASE_DEVICE) {
++		pfxdata->validity.verify_base = 1;
++		if (startpriv->uid.type == UA_HYPER_PAV_ALIAS)
++			pfxdata->validity.hyper_pav = 1;
++	}
++
++	/* define extend data (mostly)*/
++	switch (cmd) {
++	case DASD_ECKD_CCW_READ_HOME_ADDRESS:
++	case DASD_ECKD_CCW_READ_RECORD_ZERO:
++	case DASD_ECKD_CCW_READ:
++	case DASD_ECKD_CCW_READ_MT:
++	case DASD_ECKD_CCW_READ_CKD:
++	case DASD_ECKD_CCW_READ_CKD_MT:
++	case DASD_ECKD_CCW_READ_KD:
++	case DASD_ECKD_CCW_READ_KD_MT:
++	case DASD_ECKD_CCW_READ_COUNT:
++		data->mask.perm = 0x1;
++		data->attributes.operation = basepriv->attrib.operation;
++		break;
++	case DASD_ECKD_CCW_WRITE:
++	case DASD_ECKD_CCW_WRITE_MT:
++	case DASD_ECKD_CCW_WRITE_KD:
++	case DASD_ECKD_CCW_WRITE_KD_MT:
++		data->mask.perm = 0x02;
++		data->attributes.operation = basepriv->attrib.operation;
++		rc = check_XRC_on_prefix(pfxdata, basedev);
++		break;
++	case DASD_ECKD_CCW_WRITE_CKD:
++	case DASD_ECKD_CCW_WRITE_CKD_MT:
++		data->attributes.operation = DASD_BYPASS_CACHE;
++		rc = check_XRC_on_prefix(pfxdata, basedev);
++		break;
++	case DASD_ECKD_CCW_ERASE:
++	case DASD_ECKD_CCW_WRITE_HOME_ADDRESS:
++	case DASD_ECKD_CCW_WRITE_RECORD_ZERO:
++		data->mask.perm = 0x3;
++		data->mask.auth = 0x1;
++		data->attributes.operation = DASD_BYPASS_CACHE;
++		rc = check_XRC_on_prefix(pfxdata, basedev);
++		break;
++	default:
++		DEV_MESSAGE(KERN_ERR, basedev, "unknown opcode 0x%x", cmd);
++		break;
++	}
++
++	data->attributes.mode = 0x3;	/* ECKD */
++
++	if ((basepriv->rdc_data.cu_type == 0x2105 ||
++	     basepriv->rdc_data.cu_type == 0x2107 ||
++	     basepriv->rdc_data.cu_type == 0x1750)
++	    && !(basepriv->uses_cdl && trk < 2))
++		data->ga_extended |= 0x40; /* Regular Data Format Mode */
++
++	geo.cyl = basepriv->rdc_data.no_cyl;
++	geo.head = basepriv->rdc_data.trk_per_cyl;
++	beg.cyl = trk / geo.head;
++	beg.head = trk % geo.head;
++	end.cyl = totrk / geo.head;
++	end.head = totrk % geo.head;
++
++	/* check for sequential prestage - enhance cylinder range */
++	if (data->attributes.operation == DASD_SEQ_PRESTAGE ||
++	    data->attributes.operation == DASD_SEQ_ACCESS) {
++
++		if (end.cyl + basepriv->attrib.nr_cyl < geo.cyl)
++			end.cyl += basepriv->attrib.nr_cyl;
++		else
++			end.cyl = (geo.cyl - 1);
++	}
++
++	data->beg_ext.cyl = beg.cyl;
++	data->beg_ext.head = beg.head;
++	data->end_ext.cyl = end.cyl;
++	data->end_ext.head = end.head;
++	return rc;
++}
++
+ static void
+ locate_record(struct ccw1 *ccw, struct LO_eckd_data *data, int trk,
+ 	      int rec_on_trk, int no_rec, int cmd,
+@@ -300,7 +416,7 @@ locate_record(struct ccw1 *ccw, struct LO_eckd_data *data, int trk,
+ 	ccw->count = 16;
+ 	ccw->cda = (__u32) __pa(data);
  
- #define PDCS_ATTR(_name, _mode, _show, _store) \
--struct subsys_attribute pdcs_attr_##_name = { \
-+struct kobj_attribute pdcs_attr_##_name = { \
- 	.attr = {.name = __stringify(_name), .mode = _mode}, \
- 	.show = _show, \
- 	.store = _store, \
-@@ -523,15 +523,15 @@ static struct pdcspath_entry *pdcspath_entries[] = {
+-	memset(data, 0, sizeof (struct LO_eckd_data));
++	memset(data, 0, sizeof(struct LO_eckd_data));
+ 	sector = 0;
+ 	if (rec_on_trk) {
+ 		switch (private->rdc_data.dev_type) {
+@@ -441,12 +557,15 @@ dasd_eckd_generate_uid(struct dasd_device *device, struct dasd_uid *uid)
+ 	       sizeof(uid->serial) - 1);
+ 	EBCASC(uid->serial, sizeof(uid->serial) - 1);
+ 	uid->ssid = confdata->neq.subsystemID;
+-	if (confdata->ned2.sneq.flags == 0x40) {
+-		uid->alias = 1;
+-		uid->unit_addr = confdata->ned2.sneq.base_unit_addr;
+-	} else
+-		uid->unit_addr = confdata->ned1.unit_addr;
+-
++	uid->real_unit_addr = confdata->ned1.unit_addr;
++	if (confdata->ned2.sneq.flags == 0x40 &&
++	    confdata->ned2.sneq.format == 0x0001) {
++		uid->type = confdata->ned2.sneq.sua_flags;
++		if (uid->type == UA_BASE_PAV_ALIAS)
++			uid->base_unit_addr = confdata->ned2.sneq.base_unit_addr;
++	} else {
++		uid->type = UA_BASE_DEVICE;
++	}
+ 	return 0;
+ }
  
- /**
-  * pdcs_size_read - Stable Storage size output.
-- * @kset: An allocated and populated struct kset. We don't use it tho.
-  * @buf: The output buffer to write to.
-  */
--static ssize_t
--pdcs_size_read(struct kset *kset, char *buf)
-+static ssize_t pdcs_size_read(struct kobject *kobj,
-+			      struct kobj_attribute *attr,
-+			      char *buf)
- {
- 	char *out = buf;
+@@ -470,7 +589,9 @@ static struct dasd_ccw_req *dasd_eckd_build_rcd_lpm(struct dasd_device *device,
+ 	ccw->cda = (__u32)(addr_t)rcd_buffer;
+ 	ccw->count = ciw->count;
  
--	if (!kset || !buf)
-+	if (!buf)
- 		return -EINVAL;
+-	cqr->device = device;
++	cqr->startdev = device;
++	cqr->memdev = device;
++	cqr->block = NULL;
+ 	cqr->expires = 10*HZ;
+ 	cqr->lpm = lpm;
+ 	clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
+@@ -511,7 +632,7 @@ static int dasd_eckd_read_conf_lpm(struct dasd_device *device,
+ 	/*
+ 	 * on success we update the user input parms
+ 	 */
+-	dasd_sfree_request(cqr, cqr->device);
++	dasd_sfree_request(cqr, cqr->memdev);
+ 	if (ret)
+ 		goto out_error;
  
- 	/* show the size of the stable storage */
-@@ -542,17 +542,17 @@ pdcs_size_read(struct kset *kset, char *buf)
+@@ -557,19 +678,19 @@ dasd_eckd_read_conf(struct dasd_device *device)
+ 					"data retrieved");
+ 				continue;	/* no error */
+ 			}
+-			if (conf_len != sizeof (struct dasd_eckd_confdata)) {
++			if (conf_len != sizeof(struct dasd_eckd_confdata)) {
+ 				MESSAGE(KERN_WARNING,
+ 					"sizes of configuration data mismatch"
+ 					"%d (read) vs %ld (expected)",
+ 					conf_len,
+-					sizeof (struct dasd_eckd_confdata));
++					sizeof(struct dasd_eckd_confdata));
+ 				kfree(conf_data);
+ 				continue;	/* no error */
+ 			}
+ 			/* save first valid configuration data */
+ 			if (!conf_data_saved){
+ 				memcpy(&private->conf_data, conf_data,
+-				       sizeof (struct dasd_eckd_confdata));
++				       sizeof(struct dasd_eckd_confdata));
+ 				conf_data_saved++;
+ 			}
+ 			switch (((char *)conf_data)[242] & 0x07){
+@@ -586,39 +707,104 @@ dasd_eckd_read_conf(struct dasd_device *device)
+ 	return 0;
+ }
  
- /**
-  * pdcs_auto_read - Stable Storage autoboot/search flag output.
-- * @kset: An allocated and populated struct kset. We don't use it tho.
-  * @buf: The output buffer to write to.
-  * @knob: The PF_AUTOBOOT or PF_AUTOSEARCH flag
++static int dasd_eckd_read_features(struct dasd_device *device)
++{
++	struct dasd_psf_prssd_data *prssdp;
++	struct dasd_rssd_features *features;
++	struct dasd_ccw_req *cqr;
++	struct ccw1 *ccw;
++	int rc;
++	struct dasd_eckd_private *private;
++
++	private = (struct dasd_eckd_private *) device->private;
++	cqr = dasd_smalloc_request(dasd_eckd_discipline.name,
++				   1 /* PSF */	+ 1 /* RSSD */ ,
++				   (sizeof(struct dasd_psf_prssd_data) +
++				    sizeof(struct dasd_rssd_features)),
++				   device);
++	if (IS_ERR(cqr)) {
++		DEV_MESSAGE(KERN_WARNING, device, "%s",
++			    "Could not allocate initialization request");
++		return PTR_ERR(cqr);
++	}
++	cqr->startdev = device;
++	cqr->memdev = device;
++	cqr->block = NULL;
++	clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
++	cqr->retries = 5;
++	cqr->expires = 10 * HZ;
++
++	/* Prepare for Read Subsystem Data */
++	prssdp = (struct dasd_psf_prssd_data *) cqr->data;
++	memset(prssdp, 0, sizeof(struct dasd_psf_prssd_data));
++	prssdp->order = PSF_ORDER_PRSSD;
++	prssdp->suborder = 0x41;	/* Read Feature Codes */
++	/* all other bytes of prssdp must be zero */
++
++	ccw = cqr->cpaddr;
++	ccw->cmd_code = DASD_ECKD_CCW_PSF;
++	ccw->count = sizeof(struct dasd_psf_prssd_data);
++	ccw->flags |= CCW_FLAG_CC;
++	ccw->cda = (__u32)(addr_t) prssdp;
++
++	/* Read Subsystem Data - feature codes */
++	features = (struct dasd_rssd_features *) (prssdp + 1);
++	memset(features, 0, sizeof(struct dasd_rssd_features));
++
++	ccw++;
++	ccw->cmd_code = DASD_ECKD_CCW_RSSD;
++	ccw->count = sizeof(struct dasd_rssd_features);
++	ccw->cda = (__u32)(addr_t) features;
++
++	cqr->buildclk = get_clock();
++	cqr->status = DASD_CQR_FILLED;
++	rc = dasd_sleep_on(cqr);
++	if (rc == 0) {
++		prssdp = (struct dasd_psf_prssd_data *) cqr->data;
++		features = (struct dasd_rssd_features *) (prssdp + 1);
++		memcpy(&private->features, features,
++		       sizeof(struct dasd_rssd_features));
++	}
++	dasd_sfree_request(cqr, cqr->memdev);
++	return rc;
++}
++
++
+ /*
+  * Build CP for Perform Subsystem Function - SSC.
   */
--static ssize_t
--pdcs_auto_read(struct kset *kset, char *buf, int knob)
-+static ssize_t pdcs_auto_read(struct kobject *kobj,
-+			      struct kobj_attribute *attr,
-+			      char *buf, int knob)
+-static struct dasd_ccw_req *
+-dasd_eckd_build_psf_ssc(struct dasd_device *device)
++static struct dasd_ccw_req *dasd_eckd_build_psf_ssc(struct dasd_device *device)
  {
- 	char *out = buf;
- 	struct pdcspath_entry *pathentry;
+-       struct dasd_ccw_req *cqr;
+-       struct dasd_psf_ssc_data *psf_ssc_data;
+-       struct ccw1 *ccw;
++	struct dasd_ccw_req *cqr;
++	struct dasd_psf_ssc_data *psf_ssc_data;
++	struct ccw1 *ccw;
  
--	if (!kset || !buf)
-+	if (!buf)
- 		return -EINVAL;
+-       cqr = dasd_smalloc_request("ECKD", 1 /* PSF */ ,
++	cqr = dasd_smalloc_request("ECKD", 1 /* PSF */ ,
+ 				  sizeof(struct dasd_psf_ssc_data),
+ 				  device);
  
- 	/* Current flags are stored in primary boot path entry */
-@@ -568,40 +568,37 @@ pdcs_auto_read(struct kset *kset, char *buf, int knob)
+-       if (IS_ERR(cqr)) {
+-	       DEV_MESSAGE(KERN_WARNING, device, "%s",
++	if (IS_ERR(cqr)) {
++		DEV_MESSAGE(KERN_WARNING, device, "%s",
+ 			   "Could not allocate PSF-SSC request");
+-	       return cqr;
+-       }
+-       psf_ssc_data = (struct dasd_psf_ssc_data *)cqr->data;
+-       psf_ssc_data->order = PSF_ORDER_SSC;
+-       psf_ssc_data->suborder = 0x08;
+-
+-       ccw = cqr->cpaddr;
+-       ccw->cmd_code = DASD_ECKD_CCW_PSF;
+-       ccw->cda = (__u32)(addr_t)psf_ssc_data;
+-       ccw->count = 66;
+-
+-       cqr->device = device;
+-       cqr->expires = 10*HZ;
+-       cqr->buildclk = get_clock();
+-       cqr->status = DASD_CQR_FILLED;
+-       return cqr;
++		return cqr;
++	}
++	psf_ssc_data = (struct dasd_psf_ssc_data *)cqr->data;
++	psf_ssc_data->order = PSF_ORDER_SSC;
++	psf_ssc_data->suborder = 0x88;
++	psf_ssc_data->reserved[0] = 0x88;
++
++	ccw = cqr->cpaddr;
++	ccw->cmd_code = DASD_ECKD_CCW_PSF;
++	ccw->cda = (__u32)(addr_t)psf_ssc_data;
++	ccw->count = 66;
++
++	cqr->startdev = device;
++	cqr->memdev = device;
++	cqr->block = NULL;
++	cqr->expires = 10*HZ;
++	cqr->buildclk = get_clock();
++	cqr->status = DASD_CQR_FILLED;
++	return cqr;
+ }
  
- /**
-  * pdcs_autoboot_read - Stable Storage autoboot flag output.
-- * @kset: An allocated and populated struct kset. We don't use it tho.
-  * @buf: The output buffer to write to.
-  */
--static inline ssize_t
--pdcs_autoboot_read(struct kset *kset, char *buf)
-+static ssize_t pdcs_autoboot_read(struct kobject *kobj,
-+				  struct kobj_attribute *attr, char *buf)
+ /*
+@@ -629,28 +815,28 @@ dasd_eckd_build_psf_ssc(struct dasd_device *device)
+ static int
+ dasd_eckd_psf_ssc(struct dasd_device *device)
  {
--	return pdcs_auto_read(kset, buf, PF_AUTOBOOT);
-+	return pdcs_auto_read(kobj, attr, buf, PF_AUTOBOOT);
+-       struct dasd_ccw_req *cqr;
+-       int rc;
+-
+-       cqr = dasd_eckd_build_psf_ssc(device);
+-       if (IS_ERR(cqr))
+-	       return PTR_ERR(cqr);
+-
+-       rc = dasd_sleep_on(cqr);
+-       if (!rc)
+-	       /* trigger CIO to reprobe devices */
+-	       css_schedule_reprobe();
+-       dasd_sfree_request(cqr, cqr->device);
+-       return rc;
++	struct dasd_ccw_req *cqr;
++	int rc;
++
++	cqr = dasd_eckd_build_psf_ssc(device);
++	if (IS_ERR(cqr))
++		return PTR_ERR(cqr);
++
++	rc = dasd_sleep_on(cqr);
++	if (!rc)
++		/* trigger CIO to reprobe devices */
++		css_schedule_reprobe();
++	dasd_sfree_request(cqr, cqr->memdev);
++	return rc;
  }
  
- /**
-  * pdcs_autosearch_read - Stable Storage autoboot flag output.
-- * @kset: An allocated and populated struct kset. We don't use it tho.
-  * @buf: The output buffer to write to.
+ /*
+  * Valide storage server of current device.
   */
--static inline ssize_t
--pdcs_autosearch_read(struct kset *kset, char *buf)
-+static ssize_t pdcs_autosearch_read(struct kobject *kobj,
-+				    struct kobj_attribute *attr, char *buf)
+-static int
+-dasd_eckd_validate_server(struct dasd_device *device, struct dasd_uid *uid)
++static int dasd_eckd_validate_server(struct dasd_device *device)
  {
--	return pdcs_auto_read(kset, buf, PF_AUTOSEARCH);
-+	return pdcs_auto_read(kobj, attr, buf, PF_AUTOSEARCH);
- }
+ 	int rc;
++	struct dasd_eckd_private *private;
  
- /**
-  * pdcs_timer_read - Stable Storage timer count output (in seconds).
-- * @kset: An allocated and populated struct kset. We don't use it tho.
-  * @buf: The output buffer to write to.
-  *
-  * The value of the timer field correponds to a number of seconds in powers of 2.
-  */
--static ssize_t
--pdcs_timer_read(struct kset *kset, char *buf)
-+static ssize_t pdcs_timer_read(struct kobject *kobj,
-+			       struct kobj_attribute *attr, char *buf)
+ 	/* Currently PAV is the only reason to 'validate' server on LPAR */
+ 	if (dasd_nopav || MACHINE_IS_VM)
+@@ -659,9 +845,11 @@ dasd_eckd_validate_server(struct dasd_device *device, struct dasd_uid *uid)
+ 	rc = dasd_eckd_psf_ssc(device);
+ 	/* may be requested feature is not available on server,
+ 	 * therefore just report error and go ahead */
++	private = (struct dasd_eckd_private *) device->private;
+ 	DEV_MESSAGE(KERN_INFO, device,
+ 		    "PSF-SSC on storage subsystem %s.%s.%04x returned rc=%d",
+-		    uid->vendor, uid->serial, uid->ssid, rc);
++		    private->uid.vendor, private->uid.serial,
++		    private->uid.ssid, rc);
+ 	/* RE-Read Configuration Data */
+ 	return dasd_eckd_read_conf(device);
+ }
+@@ -674,9 +862,9 @@ static int
+ dasd_eckd_check_characteristics(struct dasd_device *device)
  {
- 	char *out = buf;
- 	struct pdcspath_entry *pathentry;
- 
--	if (!kset || !buf)
-+	if (!buf)
- 		return -EINVAL;
- 
- 	/* Current flags are stored in primary boot path entry */
-@@ -618,15 +615,14 @@ pdcs_timer_read(struct kset *kset, char *buf)
+ 	struct dasd_eckd_private *private;
+-	struct dasd_uid uid;
++	struct dasd_block *block;
+ 	void *rdc_data;
+-	int rc;
++	int is_known, rc;
  
- /**
-  * pdcs_osid_read - Stable Storage OS ID register output.
-- * @kset: An allocated and populated struct kset. We don't use it tho.
-  * @buf: The output buffer to write to.
-  */
--static ssize_t
--pdcs_osid_read(struct kset *kset, char *buf)
-+static ssize_t pdcs_osid_read(struct kobject *kobj,
-+			      struct kobj_attribute *attr, char *buf)
- {
- 	char *out = buf;
+ 	private = (struct dasd_eckd_private *) device->private;
+ 	if (private == NULL) {
+@@ -699,27 +887,54 @@ dasd_eckd_check_characteristics(struct dasd_device *device)
+ 	/* Read Configuration Data */
+ 	rc = dasd_eckd_read_conf(device);
+ 	if (rc)
+-		return rc;
++		goto out_err1;
  
--	if (!kset || !buf)
-+	if (!buf)
- 		return -EINVAL;
+ 	/* Generate device unique id and register in devmap */
+-	rc = dasd_eckd_generate_uid(device, &uid);
++	rc = dasd_eckd_generate_uid(device, &private->uid);
+ 	if (rc)
+-		return rc;
+-	rc = dasd_set_uid(device->cdev, &uid);
+-	if (rc == 1)	/* new server found */
+-		rc = dasd_eckd_validate_server(device, &uid);
++		goto out_err1;
++	dasd_set_uid(device->cdev, &private->uid);
++
++	if (private->uid.type == UA_BASE_DEVICE) {
++		block = dasd_alloc_block();
++		if (IS_ERR(block)) {
++			DEV_MESSAGE(KERN_WARNING, device, "%s",
++				    "could not allocate dasd block structure");
++			rc = PTR_ERR(block);
++			goto out_err1;
++		}
++		device->block = block;
++		block->base = device;
++	}
++
++	/* register lcu with alias handling, enable PAV if this is a new lcu */
++	is_known = dasd_alias_make_device_known_to_lcu(device);
++	if (is_known < 0) {
++		rc = is_known;
++		goto out_err2;
++	}
++	if (!is_known) {
++		/* new lcu found */
++		rc = dasd_eckd_validate_server(device); /* will switch pav on */
++		if (rc)
++			goto out_err3;
++	}
++
++	/* Read Feature Codes */
++	rc = dasd_eckd_read_features(device);
+ 	if (rc)
+-		return rc;
++		goto out_err3;
  
- 	out += sprintf(out, "%s dependent data (0x%.4x)\n",
-@@ -637,18 +633,17 @@ pdcs_osid_read(struct kset *kset, char *buf)
+ 	/* Read Device Characteristics */
+ 	rdc_data = (void *) &(private->rdc_data);
+ 	memset(rdc_data, 0, sizeof(rdc_data));
+ 	rc = dasd_generic_read_dev_chars(device, "ECKD", &rdc_data, 64);
+-	if (rc)
++	if (rc) {
+ 		DEV_MESSAGE(KERN_WARNING, device,
+ 			    "Read device characteristics returned "
+ 			    "rc=%d", rc);
+-
++		goto out_err3;
++	}
+ 	DEV_MESSAGE(KERN_INFO, device,
+ 		    "%04X/%02X(CU:%04X/%02X) Cyl:%d Head:%d Sec:%d",
+ 		    private->rdc_data.dev_type,
+@@ -729,9 +944,24 @@ dasd_eckd_check_characteristics(struct dasd_device *device)
+ 		    private->rdc_data.no_cyl,
+ 		    private->rdc_data.trk_per_cyl,
+ 		    private->rdc_data.sec_per_trk);
++	return 0;
++
++out_err3:
++	dasd_alias_disconnect_device_from_lcu(device);
++out_err2:
++	dasd_free_block(device->block);
++	device->block = NULL;
++out_err1:
++	kfree(device->private);
++	device->private = NULL;
+ 	return rc;
+ }
  
- /**
-  * pdcs_osdep1_read - Stable Storage OS-Dependent data area 1 output.
-- * @kset: An allocated and populated struct kset. We don't use it tho.
-  * @buf: The output buffer to write to.
-  *
-  * This can hold 16 bytes of OS-Dependent data.
-  */
--static ssize_t
--pdcs_osdep1_read(struct kset *kset, char *buf)
-+static ssize_t pdcs_osdep1_read(struct kobject *kobj,
-+				struct kobj_attribute *attr, char *buf)
++static void dasd_eckd_uncheck_device(struct dasd_device *device)
++{
++	dasd_alias_disconnect_device_from_lcu(device);
++}
++
+ static struct dasd_ccw_req *
+ dasd_eckd_analysis_ccw(struct dasd_device *device)
  {
- 	char *out = buf;
- 	u32 result[4];
+@@ -755,7 +985,7 @@ dasd_eckd_analysis_ccw(struct dasd_device *device)
+ 	/* Define extent for the first 3 tracks. */
+ 	define_extent(ccw++, cqr->data, 0, 2,
+ 		      DASD_ECKD_CCW_READ_COUNT, device);
+-	LO_data = cqr->data + sizeof (struct DE_eckd_data);
++	LO_data = cqr->data + sizeof(struct DE_eckd_data);
+ 	/* Locate record for the first 4 records on track 0. */
+ 	ccw[-1].flags |= CCW_FLAG_CC;
+ 	locate_record(ccw++, LO_data++, 0, 0, 4,
+@@ -783,7 +1013,9 @@ dasd_eckd_analysis_ccw(struct dasd_device *device)
+ 	ccw->count = 8;
+ 	ccw->cda = (__u32)(addr_t) count_data;
  
--	if (!kset || !buf)
-+	if (!buf)
- 		return -EINVAL;
+-	cqr->device = device;
++	cqr->block = NULL;
++	cqr->startdev = device;
++	cqr->memdev = device;
+ 	cqr->retries = 0;
+ 	cqr->buildclk = get_clock();
+ 	cqr->status = DASD_CQR_FILLED;
+@@ -803,7 +1035,7 @@ dasd_eckd_analysis_callback(struct dasd_ccw_req *init_cqr, void *data)
+ 	struct dasd_eckd_private *private;
+ 	struct dasd_device *device;
  
- 	if (pdc_stable_read(PDCS_ADDR_OSD1, &result, sizeof(result)) != PDC_OK)
-@@ -664,18 +659,17 @@ pdcs_osdep1_read(struct kset *kset, char *buf)
+-	device = init_cqr->device;
++	device = init_cqr->startdev;
+ 	private = (struct dasd_eckd_private *) device->private;
+ 	private->init_cqr_status = init_cqr->status;
+ 	dasd_sfree_request(init_cqr, device);
+@@ -811,13 +1043,13 @@ dasd_eckd_analysis_callback(struct dasd_ccw_req *init_cqr, void *data)
+ }
  
- /**
-  * pdcs_diagnostic_read - Stable Storage Diagnostic register output.
-- * @kset: An allocated and populated struct kset. We don't use it tho.
-  * @buf: The output buffer to write to.
-  *
-  * I have NFC how to interpret the content of that register ;-).
-  */
--static ssize_t
--pdcs_diagnostic_read(struct kset *kset, char *buf)
-+static ssize_t pdcs_diagnostic_read(struct kobject *kobj,
-+				    struct kobj_attribute *attr, char *buf)
+ static int
+-dasd_eckd_start_analysis(struct dasd_device *device)
++dasd_eckd_start_analysis(struct dasd_block *block)
  {
- 	char *out = buf;
- 	u32 result;
- 
--	if (!kset || !buf)
-+	if (!buf)
- 		return -EINVAL;
+ 	struct dasd_eckd_private *private;
+ 	struct dasd_ccw_req *init_cqr;
  
- 	/* get diagnostic */
-@@ -689,18 +683,17 @@ pdcs_diagnostic_read(struct kset *kset, char *buf)
+-	private = (struct dasd_eckd_private *) device->private;
+-	init_cqr = dasd_eckd_analysis_ccw(device);
++	private = (struct dasd_eckd_private *) block->base->private;
++	init_cqr = dasd_eckd_analysis_ccw(block->base);
+ 	if (IS_ERR(init_cqr))
+ 		return PTR_ERR(init_cqr);
+ 	init_cqr->callback = dasd_eckd_analysis_callback;
+@@ -828,13 +1060,15 @@ dasd_eckd_start_analysis(struct dasd_device *device)
+ }
  
- /**
-  * pdcs_fastsize_read - Stable Storage FastSize register output.
-- * @kset: An allocated and populated struct kset. We don't use it tho.
-  * @buf: The output buffer to write to.
-  *
-  * This register holds the amount of system RAM to be tested during boot sequence.
-  */
--static ssize_t
--pdcs_fastsize_read(struct kset *kset, char *buf)
-+static ssize_t pdcs_fastsize_read(struct kobject *kobj,
-+				  struct kobj_attribute *attr, char *buf)
+ static int
+-dasd_eckd_end_analysis(struct dasd_device *device)
++dasd_eckd_end_analysis(struct dasd_block *block)
  {
- 	char *out = buf;
- 	u32 result;
- 
--	if (!kset || !buf)
-+	if (!buf)
- 		return -EINVAL;
++	struct dasd_device *device;
+ 	struct dasd_eckd_private *private;
+ 	struct eckd_count *count_area;
+ 	unsigned int sb, blk_per_trk;
+ 	int status, i;
  
- 	/* get fast-size */
-@@ -718,13 +711,12 @@ pdcs_fastsize_read(struct kset *kset, char *buf)
++	device = block->base;
+ 	private = (struct dasd_eckd_private *) device->private;
+ 	status = private->init_cqr_status;
+ 	private->init_cqr_status = -1;
+@@ -846,7 +1080,7 @@ dasd_eckd_end_analysis(struct dasd_device *device)
  
- /**
-  * pdcs_osdep2_read - Stable Storage OS-Dependent data area 2 output.
-- * @kset: An allocated and populated struct kset. We don't use it tho.
-  * @buf: The output buffer to write to.
-  *
-  * This can hold pdcs_size - 224 bytes of OS-Dependent data, when available.
-  */
--static ssize_t
--pdcs_osdep2_read(struct kset *kset, char *buf)
-+static ssize_t pdcs_osdep2_read(struct kobject *kobj,
-+				struct kobj_attribute *attr, char *buf)
- {
- 	char *out = buf;
- 	unsigned long size;
-@@ -736,7 +728,7 @@ pdcs_osdep2_read(struct kset *kset, char *buf)
+ 	private->uses_cdl = 1;
+ 	/* Calculate number of blocks/records per track. */
+-	blk_per_trk = recs_per_track(&private->rdc_data, 0, device->bp_block);
++	blk_per_trk = recs_per_track(&private->rdc_data, 0, block->bp_block);
+ 	/* Check Track 0 for Compatible Disk Layout */
+ 	count_area = NULL;
+ 	for (i = 0; i < 3; i++) {
+@@ -876,56 +1110,65 @@ dasd_eckd_end_analysis(struct dasd_device *device)
+ 	if (count_area != NULL && count_area->kl == 0) {
+ 		/* we found notthing violating our disk layout */
+ 		if (dasd_check_blocksize(count_area->dl) == 0)
+-			device->bp_block = count_area->dl;
++			block->bp_block = count_area->dl;
+ 	}
+-	if (device->bp_block == 0) {
++	if (block->bp_block == 0) {
+ 		DEV_MESSAGE(KERN_WARNING, device, "%s",
+ 			    "Volume has incompatible disk layout");
+ 		return -EMEDIUMTYPE;
+ 	}
+-	device->s2b_shift = 0;	/* bits to shift 512 to get a block */
+-	for (sb = 512; sb < device->bp_block; sb = sb << 1)
+-		device->s2b_shift++;
++	block->s2b_shift = 0;	/* bits to shift 512 to get a block */
++	for (sb = 512; sb < block->bp_block; sb = sb << 1)
++		block->s2b_shift++;
  
- 	size = pdcs_size - 224;
+-	blk_per_trk = recs_per_track(&private->rdc_data, 0, device->bp_block);
+-	device->blocks = (private->rdc_data.no_cyl *
++	blk_per_trk = recs_per_track(&private->rdc_data, 0, block->bp_block);
++	block->blocks = (private->rdc_data.no_cyl *
+ 			  private->rdc_data.trk_per_cyl *
+ 			  blk_per_trk);
  
--	if (!kset || !buf)
-+	if (!buf)
- 		return -EINVAL;
+ 	DEV_MESSAGE(KERN_INFO, device,
+ 		    "(%dkB blks): %dkB at %dkB/trk %s",
+-		    (device->bp_block >> 10),
++		    (block->bp_block >> 10),
+ 		    ((private->rdc_data.no_cyl *
+ 		      private->rdc_data.trk_per_cyl *
+-		      blk_per_trk * (device->bp_block >> 9)) >> 1),
+-		    ((blk_per_trk * device->bp_block) >> 10),
++		      blk_per_trk * (block->bp_block >> 9)) >> 1),
++		    ((blk_per_trk * block->bp_block) >> 10),
+ 		    private->uses_cdl ?
+ 		    "compatible disk layout" : "linux disk layout");
  
- 	for (i=0; i<size; i+=4) {
-@@ -751,7 +743,6 @@ pdcs_osdep2_read(struct kset *kset, char *buf)
+ 	return 0;
+ }
  
- /**
-  * pdcs_auto_write - This function handles autoboot/search flag modifying.
-- * @kset: An allocated and populated struct kset. We don't use it tho.
-  * @buf: The input buffer to read from.
-  * @count: The number of bytes to be read.
-  * @knob: The PF_AUTOBOOT or PF_AUTOSEARCH flag
-@@ -760,8 +751,9 @@ pdcs_osdep2_read(struct kset *kset, char *buf)
-  * We expect a precise syntax:
-  *	\"n\" (n == 0 or 1) to toggle AutoBoot Off or On
-  */
--static ssize_t
--pdcs_auto_write(struct kset *kset, const char *buf, size_t count, int knob)
-+static ssize_t pdcs_auto_write(struct kobject *kobj,
-+			       struct kobj_attribute *attr, const char *buf,
-+			       size_t count, int knob)
+-static int
+-dasd_eckd_do_analysis(struct dasd_device *device)
++static int dasd_eckd_do_analysis(struct dasd_block *block)
  {
- 	struct pdcspath_entry *pathentry;
- 	unsigned char flags;
-@@ -771,7 +763,7 @@ pdcs_auto_write(struct kset *kset, const char *buf, size_t count, int knob)
- 	if (!capable(CAP_SYS_ADMIN))
- 		return -EACCES;
- 
--	if (!kset || !buf || !count)
-+	if (!buf || !count)
- 		return -EINVAL;
- 
- 	/* We'll use a local copy of buf */
-@@ -826,7 +818,6 @@ parse_error:
+ 	struct dasd_eckd_private *private;
  
- /**
-  * pdcs_autoboot_write - This function handles autoboot flag modifying.
-- * @kset: An allocated and populated struct kset. We don't use it tho.
-  * @buf: The input buffer to read from.
-  * @count: The number of bytes to be read.
-  *
-@@ -834,15 +825,15 @@ parse_error:
-  * We expect a precise syntax:
-  *	\"n\" (n == 0 or 1) to toggle AutoSearch Off or On
-  */
--static inline ssize_t
--pdcs_autoboot_write(struct kset *kset, const char *buf, size_t count)
-+static ssize_t pdcs_autoboot_write(struct kobject *kobj,
-+				   struct kobj_attribute *attr,
-+				   const char *buf, size_t count)
- {
--	return pdcs_auto_write(kset, buf, count, PF_AUTOBOOT);
-+	return pdcs_auto_write(kset, attr, buf, count, PF_AUTOBOOT);
+-	private = (struct dasd_eckd_private *) device->private;
++	private = (struct dasd_eckd_private *) block->base->private;
+ 	if (private->init_cqr_status < 0)
+-		return dasd_eckd_start_analysis(device);
++		return dasd_eckd_start_analysis(block);
+ 	else
+-		return dasd_eckd_end_analysis(device);
++		return dasd_eckd_end_analysis(block);
  }
  
- /**
-  * pdcs_autosearch_write - This function handles autosearch flag modifying.
-- * @kset: An allocated and populated struct kset. We don't use it tho.
-  * @buf: The input buffer to read from.
-  * @count: The number of bytes to be read.
-  *
-@@ -850,15 +841,15 @@ pdcs_autoboot_write(struct kset *kset, const char *buf, size_t count)
-  * We expect a precise syntax:
-  *	\"n\" (n == 0 or 1) to toggle AutoSearch Off or On
-  */
--static inline ssize_t
--pdcs_autosearch_write(struct kset *kset, const char *buf, size_t count)
-+static ssize_t pdcs_autosearch_write(struct kobject *kobj,
-+				     struct kobj_attribute *attr,
-+				     const char *buf, size_t count)
++static int dasd_eckd_ready_to_online(struct dasd_device *device)
++{
++	return dasd_alias_add_device(device);
++};
++
++static int dasd_eckd_online_to_ready(struct dasd_device *device)
++{
++	return dasd_alias_remove_device(device);
++};
++
+ static int
+-dasd_eckd_fill_geometry(struct dasd_device *device, struct hd_geometry *geo)
++dasd_eckd_fill_geometry(struct dasd_block *block, struct hd_geometry *geo)
  {
--	return pdcs_auto_write(kset, buf, count, PF_AUTOSEARCH);
-+	return pdcs_auto_write(kset, attr, buf, count, PF_AUTOSEARCH);
+ 	struct dasd_eckd_private *private;
+ 
+-	private = (struct dasd_eckd_private *) device->private;
+-	if (dasd_check_blocksize(device->bp_block) == 0) {
++	private = (struct dasd_eckd_private *) block->base->private;
++	if (dasd_check_blocksize(block->bp_block) == 0) {
+ 		geo->sectors = recs_per_track(&private->rdc_data,
+-					      0, device->bp_block);
++					      0, block->bp_block);
+ 	}
+ 	geo->cylinders = private->rdc_data.no_cyl;
+ 	geo->heads = private->rdc_data.trk_per_cyl;
+@@ -1037,7 +1280,7 @@ dasd_eckd_format_device(struct dasd_device * device,
+ 		locate_record(ccw++, (struct LO_eckd_data *) data,
+ 			      fdata->start_unit, 0, rpt + 1,
+ 			      DASD_ECKD_CCW_WRITE_RECORD_ZERO, device,
+-			      device->bp_block);
++			      device->block->bp_block);
+ 		data += sizeof(struct LO_eckd_data);
+ 		break;
+ 	case 0x04: /* Invalidate track. */
+@@ -1110,43 +1353,28 @@ dasd_eckd_format_device(struct dasd_device * device,
+ 			ccw++;
+ 		}
+ 	}
+-	fcp->device = device;
+-	fcp->retries = 2;	/* set retry counter to enable ERP */
++	fcp->startdev = device;
++	fcp->memdev = device;
++	clear_bit(DASD_CQR_FLAGS_USE_ERP, &fcp->flags);
++	fcp->retries = 5;	/* set retry counter to enable default ERP */
+ 	fcp->buildclk = get_clock();
+ 	fcp->status = DASD_CQR_FILLED;
+ 	return fcp;
  }
  
- /**
-  * pdcs_osdep1_write - Stable Storage OS-Dependent data area 1 input.
-- * @kset: An allocated and populated struct kset. We don't use it tho.
-  * @buf: The input buffer to read from.
-  * @count: The number of bytes to be read.
-  *
-@@ -866,15 +857,16 @@ pdcs_autosearch_write(struct kset *kset, const char *buf, size_t count)
-  * write approach. It's up to userspace to deal with it when constructing
-  * its input buffer.
-  */
--static ssize_t
--pdcs_osdep1_write(struct kset *kset, const char *buf, size_t count)
-+static ssize_t pdcs_osdep1_write(struct kobject *kobj,
-+				 struct kobj_attribute *attr,
-+				 const char *buf, size_t count)
+-static dasd_era_t
+-dasd_eckd_examine_error(struct dasd_ccw_req * cqr, struct irb * irb)
++static void dasd_eckd_handle_terminated_request(struct dasd_ccw_req *cqr)
  {
- 	u8 in[16];
- 
- 	if (!capable(CAP_SYS_ADMIN))
- 		return -EACCES;
- 
--	if (!kset || !buf || !count)
-+	if (!buf || !count)
- 		return -EINVAL;
- 
- 	if (unlikely(pdcs_osid != OS_ID_LINUX))
-@@ -895,7 +887,6 @@ pdcs_osdep1_write(struct kset *kset, const char *buf, size_t count)
+-	struct dasd_device *device = (struct dasd_device *) cqr->device;
+-	struct ccw_device *cdev = device->cdev;
+-
+-	if (irb->scsw.cstat == 0x00 &&
+-	    irb->scsw.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))
+-		return dasd_era_none;
+-
+-	switch (cdev->id.cu_type) {
+-	case 0x3990:
+-	case 0x2105:
+-	case 0x2107:
+-	case 0x1750:
+-		return dasd_3990_erp_examine(cqr, irb);
+-	case 0x9343:
+-		return dasd_9343_erp_examine(cqr, irb);
+-	case 0x3880:
+-	default:
+-		DEV_MESSAGE(KERN_WARNING, device, "%s",
+-			    "default (unknown CU type) - RECOVERABLE return");
+-		return dasd_era_recover;
++	cqr->status = DASD_CQR_FILLED;
++	if (cqr->block && (cqr->startdev != cqr->block->base)) {
++		dasd_eckd_reset_ccw_to_base_io(cqr);
++		cqr->startdev = cqr->block->base;
+ 	}
+-}
++};
  
- /**
-  * pdcs_osdep2_write - Stable Storage OS-Dependent data area 2 input.
-- * @kset: An allocated and populated struct kset. We don't use it tho.
-  * @buf: The input buffer to read from.
-  * @count: The number of bytes to be read.
-  *
-@@ -903,8 +894,9 @@ pdcs_osdep1_write(struct kset *kset, const char *buf, size_t count)
-  * byte-by-byte write approach. It's up to userspace to deal with it when
-  * constructing its input buffer.
-  */
--static ssize_t
--pdcs_osdep2_write(struct kset *kset, const char *buf, size_t count)
-+static ssize_t pdcs_osdep2_write(struct kobject *kobj,
-+				 struct kobj_attribute *attr,
-+				 const char *buf, size_t count)
+ static dasd_erp_fn_t
+ dasd_eckd_erp_action(struct dasd_ccw_req * cqr)
  {
- 	unsigned long size;
- 	unsigned short i;
-@@ -913,7 +905,7 @@ pdcs_osdep2_write(struct kset *kset, const char *buf, size_t count)
- 	if (!capable(CAP_SYS_ADMIN))
- 		return -EACCES;
- 
--	if (!kset || !buf || !count)
-+	if (!buf || !count)
- 		return -EINVAL;
- 
- 	if (unlikely(pdcs_size <= 224))
-@@ -951,21 +943,25 @@ static PDCS_ATTR(diagnostic, 0400, pdcs_diagnostic_read, NULL);
- static PDCS_ATTR(fastsize, 0400, pdcs_fastsize_read, NULL);
- static PDCS_ATTR(osdep2, 0600, pdcs_osdep2_read, pdcs_osdep2_write);
+-	struct dasd_device *device = (struct dasd_device *) cqr->device;
++	struct dasd_device *device = (struct dasd_device *) cqr->startdev;
+ 	struct ccw_device *cdev = device->cdev;
  
--static struct subsys_attribute *pdcs_subsys_attrs[] = {
--	&pdcs_attr_size,
--	&pdcs_attr_autoboot,
--	&pdcs_attr_autosearch,
--	&pdcs_attr_timer,
--	&pdcs_attr_osid,
--	&pdcs_attr_osdep1,
--	&pdcs_attr_diagnostic,
--	&pdcs_attr_fastsize,
--	&pdcs_attr_osdep2,
-+static struct attribute *pdcs_subsys_attrs[] = {
-+	&pdcs_attr_size.attr,
-+	&pdcs_attr_autoboot.attr,
-+	&pdcs_attr_autosearch.attr,
-+	&pdcs_attr_timer.attr,
-+	&pdcs_attr_osid.attr,
-+	&pdcs_attr_osdep1.attr,
-+	&pdcs_attr_diagnostic.attr,
-+	&pdcs_attr_fastsize.attr,
-+	&pdcs_attr_osdep2.attr,
- 	NULL,
- };
+ 	switch (cdev->id.cu_type) {
+@@ -1168,8 +1396,37 @@ dasd_eckd_erp_postaction(struct dasd_ccw_req * cqr)
+ 	return dasd_default_erp_postaction;
+ }
  
--static decl_subsys(paths, &ktype_pdcspath, NULL);
--static decl_subsys(stable, NULL, NULL);
-+static struct attribute_group pdcs_attr_group = {
-+	.attrs = pdcs_subsys_attrs,
+-static struct dasd_ccw_req *
+-dasd_eckd_build_cp(struct dasd_device * device, struct request *req)
++
++static void dasd_eckd_handle_unsolicited_interrupt(struct dasd_device *device,
++						   struct irb *irb)
++{
++	char mask;
++
++	/* first of all check for state change pending interrupt */
++	mask = DEV_STAT_ATTENTION | DEV_STAT_DEV_END | DEV_STAT_UNIT_EXCEP;
++	if ((irb->scsw.dstat & mask) == mask) {
++		dasd_generic_handle_state_change(device);
++		return;
++	}
++
++	/* summary unit check */
++	if ((irb->scsw.dstat & DEV_STAT_UNIT_CHECK) && irb->ecw[7] == 0x0D) {
++		dasd_alias_handle_summary_unit_check(device, irb);
++		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);
++
++	return;
 +};
 +
-+static struct kobject *stable_kobj;
-+static struct kset *paths_kset;
- 
- /**
-  * pdcs_register_pathentries - Prepares path entries kobjects for sysfs usage.
-@@ -995,12 +991,12 @@ pdcs_register_pathentries(void)
- 		if (err < 0)
- 			continue;
++static struct dasd_ccw_req *dasd_eckd_build_cp(struct dasd_device *startdev,
++					       struct dasd_block *block,
++					       struct request *req)
+ {
+ 	struct dasd_eckd_private *private;
+ 	unsigned long *idaws;
+@@ -1185,8 +1442,11 @@ dasd_eckd_build_cp(struct dasd_device * device, struct request *req)
+ 	sector_t first_trk, last_trk;
+ 	unsigned int first_offs, last_offs;
+ 	unsigned char cmd, rcmd;
++	int use_prefix;
++	struct dasd_device *basedev;
  
--		if ((err = kobject_set_name(&entry->kobj, "%s", entry->name)))
--			return err;
--		kobj_set_kset_s(entry, paths_subsys);
--		if ((err = kobject_register(&entry->kobj)))
-+		entry->kobj.kset = paths_kset;
-+		err = kobject_init_and_add(&entry->kobj, &ktype_pdcspath, NULL,
-+					   "%s", entry->name);
-+		if (err)
- 			return err;
--		
+-	private = (struct dasd_eckd_private *) device->private;
++	basedev = block->base;
++	private = (struct dasd_eckd_private *) basedev->private;
+ 	if (rq_data_dir(req) == READ)
+ 		cmd = DASD_ECKD_CCW_READ_MT;
+ 	else if (rq_data_dir(req) == WRITE)
+@@ -1194,13 +1454,13 @@ dasd_eckd_build_cp(struct dasd_device * device, struct request *req)
+ 	else
+ 		return ERR_PTR(-EINVAL);
+ 	/* Calculate number of blocks/records per track. */
+-	blksize = device->bp_block;
++	blksize = block->bp_block;
+ 	blk_per_trk = recs_per_track(&private->rdc_data, 0, blksize);
+ 	/* Calculate record id of first and last block. */
+-	first_rec = first_trk = req->sector >> device->s2b_shift;
++	first_rec = first_trk = req->sector >> block->s2b_shift;
+ 	first_offs = sector_div(first_trk, blk_per_trk);
+ 	last_rec = last_trk =
+-		(req->sector + req->nr_sectors - 1) >> device->s2b_shift;
++		(req->sector + req->nr_sectors - 1) >> block->s2b_shift;
+ 	last_offs = sector_div(last_trk, blk_per_trk);
+ 	/* Check struct bio and count the number of blocks for the request. */
+ 	count = 0;
+@@ -1209,20 +1469,33 @@ dasd_eckd_build_cp(struct dasd_device * device, struct request *req)
+ 		if (bv->bv_len & (blksize - 1))
+ 			/* Eckd can only do full blocks. */
+ 			return ERR_PTR(-EINVAL);
+-		count += bv->bv_len >> (device->s2b_shift + 9);
++		count += bv->bv_len >> (block->s2b_shift + 9);
+ #if defined(CONFIG_64BIT)
+ 		if (idal_is_needed (page_address(bv->bv_page), bv->bv_len))
+-			cidaw += bv->bv_len >> (device->s2b_shift + 9);
++			cidaw += bv->bv_len >> (block->s2b_shift + 9);
+ #endif
+ 	}
+ 	/* Paranoia. */
+ 	if (count != last_rec - first_rec + 1)
+ 		return ERR_PTR(-EINVAL);
+-	/* 1x define extent + 1x locate record + number of blocks */
+-	cplength = 2 + count;
+-	/* 1x define extent + 1x locate record + cidaws*sizeof(long) */
+-	datasize = sizeof(struct DE_eckd_data) + sizeof(struct LO_eckd_data) +
+-		cidaw * sizeof(unsigned long);
 +
- 		/* kobject is now registered */
- 		write_lock(&entry->rw_lock);
- 		entry->ready = 2;
-@@ -1012,6 +1008,7 @@ pdcs_register_pathentries(void)
- 		}
- 
- 		write_unlock(&entry->rw_lock);
-+		kobject_uevent(&entry->kobj, KOBJ_ADD);
++	/* use the prefix command if available */
++	use_prefix = private->features.feature[8] & 0x01;
++	if (use_prefix) {
++		/* 1x prefix + number of blocks */
++		cplength = 2 + count;
++		/* 1x prefix + cidaws*sizeof(long) */
++		datasize = sizeof(struct PFX_eckd_data) +
++			sizeof(struct LO_eckd_data) +
++			cidaw * sizeof(unsigned long);
++	} else {
++		/* 1x define extent + 1x locate record + number of blocks */
++		cplength = 2 + count;
++		/* 1x define extent + 1x locate record + cidaws*sizeof(long) */
++		datasize = sizeof(struct DE_eckd_data) +
++			sizeof(struct LO_eckd_data) +
++			cidaw * sizeof(unsigned long);
++	}
+ 	/* Find out the number of additional locate record ccws for cdl. */
+ 	if (private->uses_cdl && first_rec < 2*blk_per_trk) {
+ 		if (last_rec >= 2*blk_per_trk)
+@@ -1232,26 +1505,42 @@ dasd_eckd_build_cp(struct dasd_device * device, struct request *req)
  	}
- 	
- 	return 0;
-@@ -1029,7 +1026,7 @@ pdcs_unregister_pathentries(void)
- 	for (i = 0; (entry = pdcspath_entries[i]); i++) {
- 		read_lock(&entry->rw_lock);
- 		if (entry->ready >= 2)
--			kobject_unregister(&entry->kobj);
-+			kobject_put(&entry->kobj);
- 		read_unlock(&entry->rw_lock);
+ 	/* Allocate the ccw request. */
+ 	cqr = dasd_smalloc_request(dasd_eckd_discipline.name,
+-				   cplength, datasize, device);
++				   cplength, datasize, startdev);
+ 	if (IS_ERR(cqr))
+ 		return cqr;
+ 	ccw = cqr->cpaddr;
+-	/* First ccw is define extent. */
+-	if (define_extent(ccw++, cqr->data, first_trk,
+-			  last_trk, cmd, device) == -EAGAIN) {
+-		/* Clock not in sync and XRC is enabled. Try again later. */
+-		dasd_sfree_request(cqr, device);
+-		return ERR_PTR(-EAGAIN);
++	/* First ccw is define extent or prefix. */
++	if (use_prefix) {
++		if (prefix(ccw++, cqr->data, first_trk,
++			   last_trk, cmd, basedev, startdev) == -EAGAIN) {
++			/* Clock not in sync and XRC is enabled.
++			 * Try again later.
++			 */
++			dasd_sfree_request(cqr, startdev);
++			return ERR_PTR(-EAGAIN);
++		}
++		idaws = (unsigned long *) (cqr->data +
++					   sizeof(struct PFX_eckd_data));
++	} else {
++		if (define_extent(ccw++, cqr->data, first_trk,
++				  last_trk, cmd, startdev) == -EAGAIN) {
++			/* Clock not in sync and XRC is enabled.
++			 * Try again later.
++			 */
++			dasd_sfree_request(cqr, startdev);
++			return ERR_PTR(-EAGAIN);
++		}
++		idaws = (unsigned long *) (cqr->data +
++					   sizeof(struct DE_eckd_data));
  	}
- }
-@@ -1041,8 +1038,7 @@ pdcs_unregister_pathentries(void)
- static int __init
- pdc_stable_init(void)
- {
--	struct subsys_attribute *attr;
--	int i, rc = 0, error = 0;
-+	int rc = 0, error = 0;
- 	u32 result;
+ 	/* Build locate_record+read/write/ccws. */
+-	idaws = (unsigned long *) (cqr->data + sizeof(struct DE_eckd_data));
+ 	LO_data = (struct LO_eckd_data *) (idaws + cidaw);
+ 	recid = first_rec;
+ 	if (private->uses_cdl == 0 || recid > 2*blk_per_trk) {
+ 		/* Only standard blocks so there is just one locate record. */
+ 		ccw[-1].flags |= CCW_FLAG_CC;
+ 		locate_record(ccw++, LO_data++, first_trk, first_offs + 1,
+-			      last_rec - recid + 1, cmd, device, blksize);
++			      last_rec - recid + 1, cmd, basedev, blksize);
+ 	}
+ 	rq_for_each_segment(bv, req, iter) {
+ 		dst = page_address(bv->bv_page) + bv->bv_offset;
+@@ -1281,7 +1570,7 @@ dasd_eckd_build_cp(struct dasd_device * device, struct request *req)
+ 				ccw[-1].flags |= CCW_FLAG_CC;
+ 				locate_record(ccw++, LO_data++,
+ 					      trkid, recoffs + 1,
+-					      1, rcmd, device, count);
++					      1, rcmd, basedev, count);
+ 			}
+ 			/* Locate record for standard blocks ? */
+ 			if (private->uses_cdl && recid == 2*blk_per_trk) {
+@@ -1289,7 +1578,7 @@ dasd_eckd_build_cp(struct dasd_device * device, struct request *req)
+ 				locate_record(ccw++, LO_data++,
+ 					      trkid, recoffs + 1,
+ 					      last_rec - recid + 1,
+-					      cmd, device, count);
++					      cmd, basedev, count);
+ 			}
+ 			/* Read/write ccw. */
+ 			ccw[-1].flags |= CCW_FLAG_CC;
+@@ -1310,7 +1599,9 @@ dasd_eckd_build_cp(struct dasd_device * device, struct request *req)
+ 	}
+ 	if (req->cmd_flags & REQ_FAILFAST)
+ 		set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags);
+-	cqr->device = device;
++	cqr->startdev = startdev;
++	cqr->memdev = startdev;
++	cqr->block = block;
+ 	cqr->expires = 5 * 60 * HZ;	/* 5 minutes */
+ 	cqr->lpm = private->path_data.ppm;
+ 	cqr->retries = 256;
+@@ -1333,10 +1624,10 @@ dasd_eckd_free_cp(struct dasd_ccw_req *cqr, struct request *req)
  
- 	/* find the size of the stable storage */
-@@ -1062,21 +1058,24 @@ pdc_stable_init(void)
- 	/* the actual result is 16 bits away */
- 	pdcs_osid = (u16)(result >> 16);
+ 	if (!dasd_page_cache)
+ 		goto out;
+-	private = (struct dasd_eckd_private *) cqr->device->private;
+-	blksize = cqr->device->bp_block;
++	private = (struct dasd_eckd_private *) cqr->block->base->private;
++	blksize = cqr->block->bp_block;
+ 	blk_per_trk = recs_per_track(&private->rdc_data, 0, blksize);
+-	recid = req->sector >> cqr->device->s2b_shift;
++	recid = req->sector >> cqr->block->s2b_shift;
+ 	ccw = cqr->cpaddr;
+ 	/* Skip over define extent & locate record. */
+ 	ccw++;
+@@ -1367,10 +1658,71 @@ dasd_eckd_free_cp(struct dasd_ccw_req *cqr, struct request *req)
+ 	}
+ out:
+ 	status = cqr->status == DASD_CQR_DONE;
+-	dasd_sfree_request(cqr, cqr->device);
++	dasd_sfree_request(cqr, cqr->memdev);
+ 	return status;
+ }
  
--	/* For now we'll register the stable subsys within this driver */
--	if ((rc = firmware_register(&stable_subsys)))
-+	/* For now we'll register the directory at /sys/firmware/stable */
-+	stable_kobj = kobject_create_and_add("stable", firmware_kobj);
-+	if (!stable_kobj) {
-+		rc = -ENOMEM;
- 		goto fail_firmreg;
++/*
++ * Modify ccw chain in cqr so it can be started on a base device.
++ *
++ * Note that this is not enough to restart the cqr!
++ * Either reset cqr->startdev as well (summary unit check handling)
++ * or restart via separate cqr (as in ERP handling).
++ */
++void dasd_eckd_reset_ccw_to_base_io(struct dasd_ccw_req *cqr)
++{
++	struct ccw1 *ccw;
++	struct PFX_eckd_data *pfxdata;
++
++	ccw = cqr->cpaddr;
++	pfxdata = cqr->data;
++
++	if (ccw->cmd_code == DASD_ECKD_CCW_PFX) {
++		pfxdata->validity.verify_base = 0;
++		pfxdata->validity.hyper_pav = 0;
 +	}
++}
++
++#define DASD_ECKD_CHANQ_MAX_SIZE 4
++
++static struct dasd_ccw_req *dasd_eckd_build_alias_cp(struct dasd_device *base,
++						     struct dasd_block *block,
++						     struct request *req)
++{
++	struct dasd_eckd_private *private;
++	struct dasd_device *startdev;
++	unsigned long flags;
++	struct dasd_ccw_req *cqr;
++
++	startdev = dasd_alias_get_start_dev(base);
++	if (!startdev)
++		startdev = base;
++	private = (struct dasd_eckd_private *) startdev->private;
++	if (private->count >= DASD_ECKD_CHANQ_MAX_SIZE)
++		return ERR_PTR(-EBUSY);
++
++	spin_lock_irqsave(get_ccwdev_lock(startdev->cdev), flags);
++	private->count++;
++	cqr = dasd_eckd_build_cp(startdev, block, req);
++	if (IS_ERR(cqr))
++		private->count--;
++	spin_unlock_irqrestore(get_ccwdev_lock(startdev->cdev), flags);
++	return cqr;
++}
++
++static int dasd_eckd_free_alias_cp(struct dasd_ccw_req *cqr,
++				   struct request *req)
++{
++	struct dasd_eckd_private *private;
++	unsigned long flags;
++
++	spin_lock_irqsave(get_ccwdev_lock(cqr->memdev->cdev), flags);
++	private = (struct dasd_eckd_private *) cqr->memdev->private;
++	private->count--;
++	spin_unlock_irqrestore(get_ccwdev_lock(cqr->memdev->cdev), flags);
++	return dasd_eckd_free_cp(cqr, req);
++}
++
+ static int
+ dasd_eckd_fill_info(struct dasd_device * device,
+ 		    struct dasd_information2_t * info)
+@@ -1384,9 +1736,9 @@ dasd_eckd_fill_info(struct dasd_device * device,
+ 	info->characteristics_size = sizeof(struct dasd_eckd_characteristics);
+ 	memcpy(info->characteristics, &private->rdc_data,
+ 	       sizeof(struct dasd_eckd_characteristics));
+-	info->confdata_size = sizeof (struct dasd_eckd_confdata);
++	info->confdata_size = sizeof(struct dasd_eckd_confdata);
+ 	memcpy(info->configuration_data, &private->conf_data,
+-	       sizeof (struct dasd_eckd_confdata));
++	       sizeof(struct dasd_eckd_confdata));
+ 	return 0;
+ }
  
- 	/* Don't forget the root entries */
--	for (i = 0; (attr = pdcs_subsys_attrs[i]) && !error; i++)
--		if (attr->show)
--			error = subsys_create_file(&stable_subsys, attr);
--	
--	/* register the paths subsys as a subsystem of stable subsys */
--	kobj_set_kset_s(&paths_subsys, stable_subsys);
--	if ((rc = subsystem_register(&paths_subsys)))
--		goto fail_subsysreg;
-+	error = sysfs_create_group(stable_kobj, pdcs_attr_group);
+@@ -1419,7 +1771,8 @@ dasd_eckd_release(struct dasd_device *device)
+         cqr->cpaddr->flags |= CCW_FLAG_SLI;
+         cqr->cpaddr->count = 32;
+ 	cqr->cpaddr->cda = (__u32)(addr_t) cqr->data;
+-	cqr->device = device;
++	cqr->startdev = device;
++	cqr->memdev = device;
+ 	clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
+ 	set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags);
+ 	cqr->retries = 2;	/* set retry counter to enable basic ERP */
+@@ -1429,7 +1782,7 @@ dasd_eckd_release(struct dasd_device *device)
  
--	/* now we create all "files" for the paths subsys */
-+	/* register the paths kset as a child of the stable kset */
-+	paths_kset = kset_create_and_add("paths", NULL, stable_kobj);
-+	if (!paths_kset) {
-+		rc = -ENOMEM;
-+		goto fail_ksetreg;
-+	}
-+
-+	/* now we create all "files" for the paths kset */
- 	if ((rc = pdcs_register_pathentries()))
- 		goto fail_pdcsreg;
+ 	rc = dasd_sleep_on_immediatly(cqr);
  
-@@ -1084,10 +1083,10 @@ pdc_stable_init(void)
- 	
- fail_pdcsreg:
- 	pdcs_unregister_pathentries();
--	subsystem_unregister(&paths_subsys);
-+	kset_unregister(paths_kset);
- 	
--fail_subsysreg:
--	firmware_unregister(&stable_subsys);
-+fail_ksetreg:
-+	kobject_put(stable_kobj);
- 	
- fail_firmreg:
- 	printk(KERN_INFO PDCS_PREFIX " bailing out\n");
-@@ -1098,9 +1097,8 @@ static void __exit
- pdc_stable_exit(void)
- {
- 	pdcs_unregister_pathentries();
--	subsystem_unregister(&paths_subsys);
--
--	firmware_unregister(&stable_subsys);
-+	kset_unregister(paths_kset);
-+	kobject_put(stable_kobj);
+-	dasd_sfree_request(cqr, cqr->device);
++	dasd_sfree_request(cqr, cqr->memdev);
+ 	return rc;
  }
  
+@@ -1459,7 +1812,8 @@ dasd_eckd_reserve(struct dasd_device *device)
+         cqr->cpaddr->flags |= CCW_FLAG_SLI;
+         cqr->cpaddr->count = 32;
+ 	cqr->cpaddr->cda = (__u32)(addr_t) cqr->data;
+-	cqr->device = device;
++	cqr->startdev = device;
++	cqr->memdev = device;
+ 	clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
+ 	set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags);
+ 	cqr->retries = 2;	/* set retry counter to enable basic ERP */
+@@ -1469,7 +1823,7 @@ dasd_eckd_reserve(struct dasd_device *device)
+ 
+ 	rc = dasd_sleep_on_immediatly(cqr);
  
-diff --git a/drivers/pci/hotplug/acpiphp_ibm.c b/drivers/pci/hotplug/acpiphp_ibm.c
-index 47d26b6..750ebd7 100644
---- a/drivers/pci/hotplug/acpiphp_ibm.c
-+++ b/drivers/pci/hotplug/acpiphp_ibm.c
-@@ -429,7 +429,7 @@ static int __init ibm_acpiphp_init(void)
- 	int retval = 0;
- 	acpi_status status;
- 	struct acpi_device *device;
--	struct kobject *sysdir = &pci_hotplug_slots_subsys.kobj;
-+	struct kobject *sysdir = &pci_hotplug_slots_kset->kobj;
+-	dasd_sfree_request(cqr, cqr->device);
++	dasd_sfree_request(cqr, cqr->memdev);
+ 	return rc;
+ }
+ 
+@@ -1498,7 +1852,8 @@ dasd_eckd_steal_lock(struct dasd_device *device)
+         cqr->cpaddr->flags |= CCW_FLAG_SLI;
+         cqr->cpaddr->count = 32;
+ 	cqr->cpaddr->cda = (__u32)(addr_t) cqr->data;
+-	cqr->device = device;
++	cqr->startdev = device;
++	cqr->memdev = device;
+ 	clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
+ 	set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags);
+ 	cqr->retries = 2;	/* set retry counter to enable basic ERP */
+@@ -1508,7 +1863,7 @@ dasd_eckd_steal_lock(struct dasd_device *device)
  
- 	dbg("%s\n", __FUNCTION__);
+ 	rc = dasd_sleep_on_immediatly(cqr);
  
-@@ -476,7 +476,7 @@ init_return:
- static void __exit ibm_acpiphp_exit(void)
- {
- 	acpi_status status;
--	struct kobject *sysdir = &pci_hotplug_slots_subsys.kobj;
-+	struct kobject *sysdir = &pci_hotplug_slots_kset->kobj;
+-	dasd_sfree_request(cqr, cqr->device);
++	dasd_sfree_request(cqr, cqr->memdev);
+ 	return rc;
+ }
  
- 	dbg("%s\n", __FUNCTION__);
+@@ -1526,52 +1881,52 @@ dasd_eckd_performance(struct dasd_device *device, void __user *argp)
  
-diff --git a/drivers/pci/hotplug/pci_hotplug_core.c b/drivers/pci/hotplug/pci_hotplug_core.c
-index 01c351c..47bb0e1 100644
---- a/drivers/pci/hotplug/pci_hotplug_core.c
-+++ b/drivers/pci/hotplug/pci_hotplug_core.c
-@@ -61,7 +61,7 @@ static int debug;
+ 	cqr = dasd_smalloc_request(dasd_eckd_discipline.name,
+ 				   1 /* PSF */  + 1 /* RSSD */ ,
+-				   (sizeof (struct dasd_psf_prssd_data) +
+-				    sizeof (struct dasd_rssd_perf_stats_t)),
++				   (sizeof(struct dasd_psf_prssd_data) +
++				    sizeof(struct dasd_rssd_perf_stats_t)),
+ 				   device);
+ 	if (IS_ERR(cqr)) {
+ 		DEV_MESSAGE(KERN_WARNING, device, "%s",
+ 			    "Could not allocate initialization request");
+ 		return PTR_ERR(cqr);
+ 	}
+-	cqr->device = device;
++	cqr->startdev = device;
++	cqr->memdev = device;
+ 	cqr->retries = 0;
+ 	cqr->expires = 10 * HZ;
  
- static LIST_HEAD(pci_hotplug_slot_list);
+ 	/* Prepare for Read Subsystem Data */
+ 	prssdp = (struct dasd_psf_prssd_data *) cqr->data;
+-	memset(prssdp, 0, sizeof (struct dasd_psf_prssd_data));
++	memset(prssdp, 0, sizeof(struct dasd_psf_prssd_data));
+ 	prssdp->order = PSF_ORDER_PRSSD;
+-	prssdp->suborder = 0x01;	/* Perfomance Statistics */
++	prssdp->suborder = 0x01;	/* Performance Statistics */
+ 	prssdp->varies[1] = 0x01;	/* Perf Statistics for the Subsystem */
  
--struct kset pci_hotplug_slots_subsys;
-+struct kset *pci_hotplug_slots_kset;
+ 	ccw = cqr->cpaddr;
+ 	ccw->cmd_code = DASD_ECKD_CCW_PSF;
+-	ccw->count = sizeof (struct dasd_psf_prssd_data);
++	ccw->count = sizeof(struct dasd_psf_prssd_data);
+ 	ccw->flags |= CCW_FLAG_CC;
+ 	ccw->cda = (__u32)(addr_t) prssdp;
  
- static ssize_t hotplug_slot_attr_show(struct kobject *kobj,
- 		struct attribute *attr, char *buf)
-@@ -96,8 +96,6 @@ static struct kobj_type hotplug_slot_ktype = {
- 	.release = &hotplug_slot_release,
- };
+ 	/* Read Subsystem Data - Performance Statistics */
+ 	stats = (struct dasd_rssd_perf_stats_t *) (prssdp + 1);
+-	memset(stats, 0, sizeof (struct dasd_rssd_perf_stats_t));
++	memset(stats, 0, sizeof(struct dasd_rssd_perf_stats_t));
  
--decl_subsys_name(pci_hotplug_slots, slots, &hotplug_slot_ktype, NULL);
--
- /* these strings match up with the values in pci_bus_speed */
- static char *pci_bus_speed_strings[] = {
- 	"33 MHz PCI",		/* 0x00 */
-@@ -632,18 +630,19 @@ int pci_hp_register (struct hotplug_slot *slot)
- 		return -EINVAL;
- 	}
+ 	ccw++;
+ 	ccw->cmd_code = DASD_ECKD_CCW_RSSD;
+-	ccw->count = sizeof (struct dasd_rssd_perf_stats_t);
++	ccw->count = sizeof(struct dasd_rssd_perf_stats_t);
+ 	ccw->cda = (__u32)(addr_t) stats;
  
--	kobject_set_name(&slot->kobj, "%s", slot->name);
--	kobj_set_kset_s(slot, pci_hotplug_slots_subsys);
--
- 	/* this can fail if we have already registered a slot with the same name */
--	if (kobject_register(&slot->kobj)) {
--		err("Unable to register kobject");
-+	slot->kobj.kset = pci_hotplug_slots_kset;
-+	result = kobject_init_and_add(&slot->kobj, &hotplug_slot_ktype, NULL,
-+				      "%s", slot->name);
-+	if (result) {
-+		err("Unable to register kobject '%s'", slot->name);
- 		return -EINVAL;
+ 	cqr->buildclk = get_clock();
+ 	cqr->status = DASD_CQR_FILLED;
+ 	rc = dasd_sleep_on(cqr);
+ 	if (rc == 0) {
+-		/* Prepare for Read Subsystem Data */
+ 		prssdp = (struct dasd_psf_prssd_data *) cqr->data;
+ 		stats = (struct dasd_rssd_perf_stats_t *) (prssdp + 1);
+ 		if (copy_to_user(argp, stats,
+ 				 sizeof(struct dasd_rssd_perf_stats_t)))
+ 			rc = -EFAULT;
  	}
--		
-+
- 	list_add (&slot->slot_list, &pci_hotplug_slot_list);
- 
- 	result = fs_add_slot (slot);
-+	kobject_uevent(&slot->kobj, KOBJ_ADD);
- 	dbg ("Added slot %s to the list\n", slot->name);
- 	return result;
+-	dasd_sfree_request(cqr, cqr->device);
++	dasd_sfree_request(cqr, cqr->memdev);
+ 	return rc;
  }
-@@ -672,7 +671,7 @@ int pci_hp_deregister (struct hotplug_slot *slot)
  
- 	fs_remove_slot (slot);
- 	dbg ("Removed slot %s from the list\n", slot->name);
--	kobject_unregister(&slot->kobj);
-+	kobject_put(&slot->kobj);
- 	return 0;
+@@ -1594,7 +1949,7 @@ dasd_eckd_get_attrib(struct dasd_device *device, void __user *argp)
+ 
+ 	rc = 0;
+ 	if (copy_to_user(argp, (long *) &attrib,
+-			 sizeof (struct attrib_data_t)))
++			 sizeof(struct attrib_data_t)))
+ 		rc = -EFAULT;
+ 
+ 	return rc;
+@@ -1627,8 +1982,10 @@ dasd_eckd_set_attrib(struct dasd_device *device, void __user *argp)
  }
  
-@@ -700,11 +699,15 @@ int __must_check pci_hp_change_slot_info(struct hotplug_slot *slot,
- static int __init pci_hotplug_init (void)
+ static int
+-dasd_eckd_ioctl(struct dasd_device *device, unsigned int cmd, void __user *argp)
++dasd_eckd_ioctl(struct dasd_block *block, unsigned int cmd, void __user *argp)
  {
- 	int result;
-+	struct kset *pci_bus_kset;
- 
--	kobj_set_kset_s(&pci_hotplug_slots_subsys, pci_bus_type.subsys);
--	result = subsystem_register(&pci_hotplug_slots_subsys);
--	if (result) {
--		err("Register subsys with error %d\n", result);
-+	pci_bus_kset = bus_get_kset(&pci_bus_type);
++	struct dasd_device *device = block->base;
 +
-+	pci_hotplug_slots_kset = kset_create_and_add("slots", NULL,
-+						     &pci_bus_kset->kobj);
-+	if (!pci_hotplug_slots_kset) {
-+		result = -ENOMEM;
-+		err("Register subsys error\n");
- 		goto exit;
+ 	switch (cmd) {
+ 	case BIODASDGATTR:
+ 		return dasd_eckd_get_attrib(device, argp);
+@@ -1685,9 +2042,8 @@ dasd_eckd_dump_ccw_range(struct ccw1 *from, struct ccw1 *to, char *page)
+  * Print sense data and related channel program.
+  * Parts are printed because printk buffer is only 1024 bytes.
+  */
+-static void
+-dasd_eckd_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req,
+-		     struct irb *irb)
++static void dasd_eckd_dump_sense(struct dasd_device *device,
++				 struct dasd_ccw_req *req, struct irb *irb)
+ {
+ 	char *page;
+ 	struct ccw1 *first, *last, *fail, *from, *to;
+@@ -1743,37 +2099,40 @@ dasd_eckd_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req,
  	}
- 	result = cpci_hotplug_init(debug);
-@@ -715,9 +718,9 @@ static int __init pci_hotplug_init (void)
+ 	printk("%s", page);
  
- 	info (DRIVER_DESC " version: " DRIVER_VERSION "\n");
- 	goto exit;
--	
+-	/* dump the Channel Program (max 140 Bytes per line) */
+-	/* Count CCW and print first CCWs (maximum 1024 % 140 = 7) */
+-	first = req->cpaddr;
+-	for (last = first; last->flags & (CCW_FLAG_CC | CCW_FLAG_DC); last++);
+-	to = min(first + 6, last);
+-	len = sprintf(page,  KERN_ERR PRINTK_HEADER
+-		      " Related CP in req: %p\n", req);
+-	dasd_eckd_dump_ccw_range(first, to, page + len);
+-	printk("%s", page);
++	if (req) {
++		/* req == NULL for unsolicited interrupts */
++		/* dump the Channel Program (max 140 Bytes per line) */
++		/* Count CCW and print first CCWs (maximum 1024 % 140 = 7) */
++		first = req->cpaddr;
++		for (last = first; last->flags & (CCW_FLAG_CC | CCW_FLAG_DC); last++);
++		to = min(first + 6, last);
++		len = sprintf(page,  KERN_ERR PRINTK_HEADER
++			      " Related CP in req: %p\n", req);
++		dasd_eckd_dump_ccw_range(first, to, page + len);
++		printk("%s", page);
+ 
+-	/* print failing CCW area (maximum 4) */
+-	/* scsw->cda is either valid or zero  */
+-	len = 0;
+-	from = ++to;
+-	fail = (struct ccw1 *)(addr_t) irb->scsw.cpa; /* failing CCW */
+-	if (from <  fail - 2) {
+-		from = fail - 2;     /* there is a gap - print header */
+-		len += sprintf(page, KERN_ERR PRINTK_HEADER "......\n");
+-	}
+-	to = min(fail + 1, last);
+-	len += dasd_eckd_dump_ccw_range(from, to, page + len);
+-
+-	/* print last CCWs (maximum 2) */
+-	from = max(from, ++to);
+-	if (from < last - 1) {
+-		from = last - 1;     /* there is a gap - print header */
+-		len += sprintf(page + len, KERN_ERR PRINTK_HEADER "......\n");
++		/* print failing CCW area (maximum 4) */
++		/* scsw->cda is either valid or zero  */
++		len = 0;
++		from = ++to;
++		fail = (struct ccw1 *)(addr_t) irb->scsw.cpa; /* failing CCW */
++		if (from <  fail - 2) {
++			from = fail - 2;     /* there is a gap - print header */
++			len += sprintf(page, KERN_ERR PRINTK_HEADER "......\n");
++		}
++		to = min(fail + 1, last);
++		len += dasd_eckd_dump_ccw_range(from, to, page + len);
 +
- err_subsys:
--	subsystem_unregister(&pci_hotplug_slots_subsys);
-+	kset_unregister(pci_hotplug_slots_kset);
- exit:
- 	return result;
- }
-@@ -725,7 +728,7 @@ exit:
- static void __exit pci_hotplug_exit (void)
- {
- 	cpci_hotplug_exit();
--	subsystem_unregister(&pci_hotplug_slots_subsys);
-+	kset_unregister(pci_hotplug_slots_kset);
++		/* print last CCWs (maximum 2) */
++		from = max(from, ++to);
++		if (from < last - 1) {
++			from = last - 1;     /* there is a gap - print header */
++			len += sprintf(page + len, KERN_ERR PRINTK_HEADER "......\n");
++		}
++		len += dasd_eckd_dump_ccw_range(from, last, page + len);
++		if (len > 0)
++			printk("%s", page);
+ 	}
+-	len += dasd_eckd_dump_ccw_range(from, last, page + len);
+-	if (len > 0)
+-		printk("%s", page);
+ 	free_page((unsigned long) page);
  }
  
- module_init(pci_hotplug_init);
-@@ -737,7 +740,7 @@ MODULE_LICENSE("GPL");
- module_param(debug, bool, 0644);
- MODULE_PARM_DESC(debug, "Debugging mode enabled or not");
+@@ -1796,16 +2155,20 @@ static struct dasd_discipline dasd_eckd_discipline = {
+ 	.ebcname = "ECKD",
+ 	.max_blocks = 240,
+ 	.check_device = dasd_eckd_check_characteristics,
++	.uncheck_device = dasd_eckd_uncheck_device,
+ 	.do_analysis = dasd_eckd_do_analysis,
++	.ready_to_online = dasd_eckd_ready_to_online,
++	.online_to_ready = dasd_eckd_online_to_ready,
+ 	.fill_geometry = dasd_eckd_fill_geometry,
+ 	.start_IO = dasd_start_IO,
+ 	.term_IO = dasd_term_IO,
++	.handle_terminated_request = dasd_eckd_handle_terminated_request,
+ 	.format_device = dasd_eckd_format_device,
+-	.examine_error = dasd_eckd_examine_error,
+ 	.erp_action = dasd_eckd_erp_action,
+ 	.erp_postaction = dasd_eckd_erp_postaction,
+-	.build_cp = dasd_eckd_build_cp,
+-	.free_cp = dasd_eckd_free_cp,
++	.handle_unsolicited_interrupt = dasd_eckd_handle_unsolicited_interrupt,
++	.build_cp = dasd_eckd_build_alias_cp,
++	.free_cp = dasd_eckd_free_alias_cp,
+ 	.dump_sense = dasd_eckd_dump_sense,
+ 	.fill_info = dasd_eckd_fill_info,
+ 	.ioctl = dasd_eckd_ioctl,
+diff --git a/drivers/s390/block/dasd_eckd.h b/drivers/s390/block/dasd_eckd.h
+index 712ff16..fc2509c 100644
+--- a/drivers/s390/block/dasd_eckd.h
++++ b/drivers/s390/block/dasd_eckd.h
+@@ -39,6 +39,8 @@
+ #define DASD_ECKD_CCW_READ_CKD_MT	 0x9e
+ #define DASD_ECKD_CCW_WRITE_CKD_MT	 0x9d
+ #define DASD_ECKD_CCW_RESERVE		 0xB4
++#define DASD_ECKD_CCW_PFX		 0xE7
++#define DASD_ECKD_CCW_RSCK		 0xF9
  
--EXPORT_SYMBOL_GPL(pci_hotplug_slots_subsys);
-+EXPORT_SYMBOL_GPL(pci_hotplug_slots_kset);
- EXPORT_SYMBOL_GPL(pci_hp_register);
- EXPORT_SYMBOL_GPL(pci_hp_deregister);
- EXPORT_SYMBOL_GPL(pci_hp_change_slot_info);
-diff --git a/drivers/pci/hotplug/rpadlpar_sysfs.c b/drivers/pci/hotplug/rpadlpar_sysfs.c
-index a080fed..e32148a 100644
---- a/drivers/pci/hotplug/rpadlpar_sysfs.c
-+++ b/drivers/pci/hotplug/rpadlpar_sysfs.c
-@@ -23,44 +23,13 @@
+ /*
+  * Perform Subsystem Function / Sub-Orders
+@@ -137,6 +139,25 @@ struct LO_eckd_data {
+ 	__u16 length;
+ } __attribute__ ((packed));
  
- #define MAX_DRC_NAME_LEN 64
++/* Prefix data for format 0x00 and 0x01 */
++struct PFX_eckd_data {
++	unsigned char format;
++	struct {
++		unsigned char define_extend:1;
++		unsigned char time_stamp:1;
++		unsigned char verify_base:1;
++		unsigned char hyper_pav:1;
++		unsigned char reserved:4;
++	} __attribute__ ((packed)) validity;
++	__u8 base_address;
++	__u8 aux;
++	__u8 base_lss;
++	__u8 reserved[7];
++	struct DE_eckd_data define_extend;
++	struct LO_eckd_data locate_record;
++	__u8 LO_extended_data[4];
++} __attribute__ ((packed));
++
+ struct dasd_eckd_characteristics {
+ 	__u16 cu_type;
+ 	struct {
+@@ -254,7 +275,9 @@ struct dasd_eckd_confdata {
+ 		} __attribute__ ((packed)) ned;
+ 		struct {
+ 			unsigned char flags;            /* byte  0    */
+-			unsigned char res2[7];          /* byte  1- 7 */
++			unsigned char res1;		/* byte  1    */
++			__u16 format;			/* byte  2-3  */
++			unsigned char res2[4];		/* byte  4-7  */
+ 			unsigned char sua_flags;	/* byte  8    */
+ 			__u8 base_unit_addr;            /* byte  9    */
+ 			unsigned char res3[22];	        /* byte 10-31 */
+@@ -343,6 +366,11 @@ struct dasd_eckd_path {
+ 	__u8 npm;
+ };
  
--/* Store return code of dlpar operation in attribute struct */
--struct dlpar_io_attr {
--	int rc;
--	struct attribute attr;
--	ssize_t (*store)(struct dlpar_io_attr *dlpar_attr, const char *buf,
--		size_t nbytes);
--};
++struct dasd_rssd_features {
++	char feature[256];
++} __attribute__((packed));
++
++
+ /*
+  * Perform Subsystem Function - Prepare for Read Subsystem Data
+  */
+@@ -365,4 +393,99 @@ struct dasd_psf_ssc_data {
+ 	unsigned char reserved[59];
+ } __attribute__((packed));
  
--/* Common show callback for all attrs, display the return code
-- * of the dlpar op */
--static ssize_t
--dlpar_attr_show(struct kobject * kobj, struct attribute * attr, char * buf)
--{
--	struct dlpar_io_attr *dlpar_attr = container_of(attr,
--						struct dlpar_io_attr, attr);
--	return sprintf(buf, "%d\n", dlpar_attr->rc);
--}
--
--static ssize_t
--dlpar_attr_store(struct kobject * kobj, struct attribute * attr,
--		 const char *buf, size_t nbytes)
--{
--	struct dlpar_io_attr *dlpar_attr = container_of(attr,
--						struct dlpar_io_attr, attr);
--	return dlpar_attr->store ?
--		dlpar_attr->store(dlpar_attr, buf, nbytes) : -EIO;
--}
--
--static struct sysfs_ops dlpar_attr_sysfs_ops = {
--	.show = dlpar_attr_show,
--	.store = dlpar_attr_store,
--};
--
--static ssize_t add_slot_store(struct dlpar_io_attr *dlpar_attr,
--				const char *buf, size_t nbytes)
-+static ssize_t add_slot_store(struct kobject *kobj, struct kobj_attribute *attr,
-+			      const char *buf, size_t nbytes)
- {
- 	char drc_name[MAX_DRC_NAME_LEN];
- 	char *end;
-+	int rc;
++
++/*
++ * some structures and definitions for alias handling
++ */
++struct dasd_unit_address_configuration {
++	struct {
++		char ua_type;
++		char base_ua;
++	} unit[256];
++} __attribute__((packed));
++
++
++#define MAX_DEVICES_PER_LCU 256
++
++/* flags on the LCU  */
++#define NEED_UAC_UPDATE  0x01
++#define UPDATE_PENDING	0x02
++
++enum pavtype {NO_PAV, BASE_PAV, HYPER_PAV};
++
++
++struct alias_root {
++	struct list_head serverlist;
++	spinlock_t lock;
++};
++
++struct alias_server {
++	struct list_head server;
++	struct dasd_uid uid;
++	struct list_head lculist;
++};
++
++struct summary_unit_check_work_data {
++	char reason;
++	struct dasd_device *device;
++	struct work_struct worker;
++};
++
++struct read_uac_work_data {
++	struct dasd_device *device;
++	struct delayed_work dwork;
++};
++
++struct alias_lcu {
++	struct list_head lcu;
++	struct dasd_uid uid;
++	enum pavtype pav;
++	char flags;
++	spinlock_t lock;
++	struct list_head grouplist;
++	struct list_head active_devices;
++	struct list_head inactive_devices;
++	struct dasd_unit_address_configuration *uac;
++	struct summary_unit_check_work_data suc_data;
++	struct read_uac_work_data ruac_data;
++	struct dasd_ccw_req *rsu_cqr;
++};
++
++struct alias_pav_group {
++	struct list_head group;
++	struct dasd_uid uid;
++	struct alias_lcu *lcu;
++	struct list_head baselist;
++	struct list_head aliaslist;
++	struct dasd_device *next;
++};
++
++
++struct dasd_eckd_private {
++	struct dasd_eckd_characteristics rdc_data;
++	struct dasd_eckd_confdata conf_data;
++	struct dasd_eckd_path path_data;
++	struct eckd_count count_area[5];
++	int init_cqr_status;
++	int uses_cdl;
++	struct attrib_data_t attrib;	/* e.g. cache operations */
++	struct dasd_rssd_features features;
++
++	/* alias managemnet */
++	struct dasd_uid uid;
++	struct alias_pav_group *pavgroup;
++	struct alias_lcu *lcu;
++	int count;
++};
++
++
++
++int dasd_alias_make_device_known_to_lcu(struct dasd_device *);
++void dasd_alias_disconnect_device_from_lcu(struct dasd_device *);
++int dasd_alias_add_device(struct dasd_device *);
++int dasd_alias_remove_device(struct dasd_device *);
++struct dasd_device *dasd_alias_get_start_dev(struct dasd_device *);
++void dasd_alias_handle_summary_unit_check(struct dasd_device *, struct irb *);
++void dasd_eckd_reset_ccw_to_base_io(struct dasd_ccw_req *);
++
+ #endif				/* DASD_ECKD_H */
+diff --git a/drivers/s390/block/dasd_eer.c b/drivers/s390/block/dasd_eer.c
+index 0c081a6..6e53ab6 100644
+--- a/drivers/s390/block/dasd_eer.c
++++ b/drivers/s390/block/dasd_eer.c
+@@ -336,7 +336,7 @@ static void dasd_eer_write_snss_trigger(struct dasd_device *device,
+ 	unsigned long flags;
+ 	struct eerbuffer *eerb;
  
- 	if (nbytes >= MAX_DRC_NAME_LEN)
- 		return 0;
-@@ -72,15 +41,25 @@ static ssize_t add_slot_store(struct dlpar_io_attr *dlpar_attr,
- 		end = &drc_name[nbytes];
- 	*end = '\0';
+-	snss_rc = (cqr->status == DASD_CQR_FAILED) ? -EIO : 0;
++	snss_rc = (cqr->status == DASD_CQR_DONE) ? 0 : -EIO;
+ 	if (snss_rc)
+ 		data_size = 0;
+ 	else
+@@ -404,10 +404,11 @@ void dasd_eer_snss(struct dasd_device *device)
+ 		set_bit(DASD_FLAG_EER_SNSS, &device->flags);
+ 		return;
+ 	}
++	/* cdev is already locked, can't use dasd_add_request_head */
+ 	clear_bit(DASD_FLAG_EER_SNSS, &device->flags);
+ 	cqr->status = DASD_CQR_QUEUED;
+-	list_add(&cqr->list, &device->ccw_queue);
+-	dasd_schedule_bh(device);
++	list_add(&cqr->devlist, &device->ccw_queue);
++	dasd_schedule_device_bh(device);
+ }
  
--	dlpar_attr->rc = dlpar_add_slot(drc_name);
-+	rc = dlpar_add_slot(drc_name);
-+	if (rc)
-+		return rc;
+ /*
+@@ -415,7 +416,7 @@ void dasd_eer_snss(struct dasd_device *device)
+  */
+ static void dasd_eer_snss_cb(struct dasd_ccw_req *cqr, void *data)
+ {
+-        struct dasd_device *device = cqr->device;
++	struct dasd_device *device = cqr->startdev;
+ 	unsigned long flags;
  
- 	return nbytes;
+ 	dasd_eer_write(device, cqr, DASD_EER_STATECHANGE);
+@@ -458,7 +459,7 @@ int dasd_eer_enable(struct dasd_device *device)
+ 	if (!cqr)
+ 		return -ENOMEM;
+ 
+-	cqr->device = device;
++	cqr->startdev = device;
+ 	cqr->retries = 255;
+ 	cqr->expires = 10 * HZ;
+ 	clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
+diff --git a/drivers/s390/block/dasd_erp.c b/drivers/s390/block/dasd_erp.c
+index caa5d91..8f10000 100644
+--- a/drivers/s390/block/dasd_erp.c
++++ b/drivers/s390/block/dasd_erp.c
+@@ -46,6 +46,8 @@ dasd_alloc_erp_request(char *magic, int cplength, int datasize,
+ 	if (cqr == NULL)
+ 		return ERR_PTR(-ENOMEM);
+ 	memset(cqr, 0, sizeof(struct dasd_ccw_req));
++	INIT_LIST_HEAD(&cqr->devlist);
++	INIT_LIST_HEAD(&cqr->blocklist);
+ 	data = (char *) cqr + ((sizeof(struct dasd_ccw_req) + 7L) & -8L);
+ 	cqr->cpaddr = NULL;
+ 	if (cplength > 0) {
+@@ -66,7 +68,7 @@ dasd_alloc_erp_request(char *magic, int cplength, int datasize,
  }
  
--static ssize_t remove_slot_store(struct dlpar_io_attr *dlpar_attr,
--		 		const char *buf, size_t nbytes)
-+static ssize_t add_slot_show(struct kobject *kobj,
-+			     struct kobj_attribute *attr, char *buf)
-+{
-+	return sprintf(buf, "0\n");
-+}
-+
-+static ssize_t remove_slot_store(struct kobject *kobj,
-+				 struct kobj_attribute *attr,
-+				 const char *buf, size_t nbytes)
+ void
+-dasd_free_erp_request(struct dasd_ccw_req * cqr, struct dasd_device * device)
++dasd_free_erp_request(struct dasd_ccw_req *cqr, struct dasd_device * device)
  {
- 	char drc_name[MAX_DRC_NAME_LEN];
-+	int rc;
- 	char *end;
+ 	unsigned long flags;
  
- 	if (nbytes >= MAX_DRC_NAME_LEN)
-@@ -93,22 +72,24 @@ static ssize_t remove_slot_store(struct dlpar_io_attr *dlpar_attr,
- 		end = &drc_name[nbytes];
- 	*end = '\0';
+@@ -81,11 +83,11 @@ dasd_free_erp_request(struct dasd_ccw_req * cqr, struct dasd_device * device)
+  * dasd_default_erp_action just retries the current cqr
+  */
+ struct dasd_ccw_req *
+-dasd_default_erp_action(struct dasd_ccw_req * cqr)
++dasd_default_erp_action(struct dasd_ccw_req *cqr)
+ {
+ 	struct dasd_device *device;
  
--	dlpar_attr->rc = dlpar_remove_slot(drc_name);
-+	rc = dlpar_remove_slot(drc_name);
-+	if (rc)
-+		return rc;
+-	device = cqr->device;
++	device = cqr->startdev;
  
- 	return nbytes;
- }
+         /* just retry - there is nothing to save ... I got no sense data.... */
+         if (cqr->retries > 0) {
+@@ -93,12 +95,12 @@ dasd_default_erp_action(struct dasd_ccw_req * cqr)
+                              "default ERP called (%i retries left)",
+                              cqr->retries);
+ 		cqr->lpm    = LPM_ANYPATH;
+-		cqr->status = DASD_CQR_QUEUED;
++		cqr->status = DASD_CQR_FILLED;
+         } else {
+                 DEV_MESSAGE (KERN_WARNING, device, "%s",
+ 			     "default ERP called (NO retry left)");
+ 		cqr->status = DASD_CQR_FAILED;
+-		cqr->stopclk = get_clock ();
++		cqr->stopclk = get_clock();
+         }
+         return cqr;
+ }				/* end dasd_default_erp_action */
+@@ -117,15 +119,12 @@ dasd_default_erp_action(struct dasd_ccw_req * cqr)
+  * RETURN VALUES
+  *   cqr		pointer to the original CQR
+  */
+-struct dasd_ccw_req *
+-dasd_default_erp_postaction(struct dasd_ccw_req * cqr)
++struct dasd_ccw_req *dasd_default_erp_postaction(struct dasd_ccw_req *cqr)
+ {
+-	struct dasd_device *device;
+ 	int success;
  
--static struct dlpar_io_attr add_slot_attr = {
--	.rc = 0,
--	.attr = { .name = ADD_SLOT_ATTR_NAME, .mode = 0644, },
--	.store = add_slot_store,
--};
-+static ssize_t remove_slot_show(struct kobject *kobj,
-+				struct kobj_attribute *attr, char *buf)
-+{
-+	return sprintf(buf, "0\n");
-+}
+ 	BUG_ON(cqr->refers == NULL || cqr->function == NULL);
  
--static struct dlpar_io_attr remove_slot_attr = {
--	.rc = 0,
--	.attr = { .name = REMOVE_SLOT_ATTR_NAME, .mode = 0644},
--	.store = remove_slot_store,
--};
-+static struct kobj_attribute add_slot_attr =
-+	__ATTR(ADD_SLOT_ATTR_NAME, 0644, add_slot_show, add_slot_store);
-+
-+static struct kobj_attribute remove_slot_attr =
-+	__ATTR(REMOVE_SLOT_ATTR_NAME, 0644, remove_slot_show, remove_slot_store);
+-	device = cqr->device;
+ 	success = cqr->status == DASD_CQR_DONE;
  
- static struct attribute *default_attrs[] = {
- 	&add_slot_attr.attr,
-@@ -116,37 +97,29 @@ static struct attribute *default_attrs[] = {
- 	NULL,
- };
+ 	/* free all ERPs - but NOT the original cqr */
+@@ -133,10 +132,10 @@ dasd_default_erp_postaction(struct dasd_ccw_req * cqr)
+ 		struct dasd_ccw_req *refers;
  
--static void dlpar_io_release(struct kobject *kobj)
--{
--	/* noop */
--	return;
--}
--
--struct kobj_type ktype_dlpar_io = {
--	.release = dlpar_io_release,
--	.sysfs_ops = &dlpar_attr_sysfs_ops,
--	.default_attrs = default_attrs,
-+static struct attribute_group dlpar_attr_group = {
-+	.attrs = default_attrs,
- };
+ 		refers = cqr->refers;
+-		/* remove the request from the device queue */
+-		list_del(&cqr->list);
++		/* remove the request from the block queue */
++		list_del(&cqr->blocklist);
+ 		/* free the finished erp request */
+-		dasd_free_erp_request(cqr, device);
++		dasd_free_erp_request(cqr, cqr->memdev);
+ 		cqr = refers;
+ 	}
  
--struct kset dlpar_io_kset = {
--	.kobj = {.ktype = &ktype_dlpar_io,
--		 .parent = &pci_hotplug_slots_subsys.kobj},
--	.ktype = &ktype_dlpar_io,
--};
-+static struct kobject *dlpar_kobj;
+@@ -157,7 +156,7 @@ dasd_log_sense(struct dasd_ccw_req *cqr, struct irb *irb)
+ {
+ 	struct dasd_device *device;
  
- int dlpar_sysfs_init(void)
+-	device = cqr->device;
++	device = cqr->startdev;
+ 	/* dump sense data */
+ 	if (device->discipline && device->discipline->dump_sense)
+ 		device->discipline->dump_sense(device, cqr, irb);
+diff --git a/drivers/s390/block/dasd_fba.c b/drivers/s390/block/dasd_fba.c
+index 1d95822..d13ea05 100644
+--- a/drivers/s390/block/dasd_fba.c
++++ b/drivers/s390/block/dasd_fba.c
+@@ -117,6 +117,7 @@ locate_record(struct ccw1 * ccw, struct LO_fba_data *data, int rw,
+ static int
+ dasd_fba_check_characteristics(struct dasd_device *device)
  {
--	kobject_set_name(&dlpar_io_kset.kobj, DLPAR_KOBJ_NAME);
--	if (kset_register(&dlpar_io_kset)) {
--		printk(KERN_ERR "rpadlpar_io: cannot register kset for %s\n",
--				kobject_name(&dlpar_io_kset.kobj));
-+	int error;
++	struct dasd_block *block;
+ 	struct dasd_fba_private *private;
+ 	struct ccw_device *cdev = device->cdev;
+ 	void *rdc_data;
+@@ -133,6 +134,16 @@ dasd_fba_check_characteristics(struct dasd_device *device)
+ 		}
+ 		device->private = (void *) private;
+ 	}
++	block = dasd_alloc_block();
++	if (IS_ERR(block)) {
++		DEV_MESSAGE(KERN_WARNING, device, "%s",
++			    "could not allocate dasd block structure");
++		kfree(device->private);
++		return PTR_ERR(block);
++	}
++	device->block = block;
++	block->base = device;
 +
-+	dlpar_kobj = kobject_create_and_add(DLPAR_KOBJ_NAME,
-+					    &pci_hotplug_slots_kset->kobj);
-+	if (!dlpar_kobj)
- 		return -EINVAL;
--	}
- 
--	return 0;
-+	error = sysfs_create_group(dlpar_kobj, &dlpar_attr_group);
-+	if (error)
-+		kobject_put(dlpar_kobj);
-+	return error;
+ 	/* Read Device Characteristics */
+ 	rdc_data = (void *) &(private->rdc_data);
+ 	rc = dasd_generic_read_dev_chars(device, "FBA ", &rdc_data, 32);
+@@ -155,60 +166,37 @@ dasd_fba_check_characteristics(struct dasd_device *device)
+ 	return 0;
  }
  
- void dlpar_sysfs_exit(void)
+-static int
+-dasd_fba_do_analysis(struct dasd_device *device)
++static int dasd_fba_do_analysis(struct dasd_block *block)
  {
--	kset_unregister(&dlpar_io_kset);
-+	sysfs_remove_group(dlpar_kobj, &dlpar_attr_group);
-+	kobject_put(dlpar_kobj);
- }
-diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
-index 6d1a216..c4fa35d 100644
---- a/drivers/pci/pci-driver.c
-+++ b/drivers/pci/pci-driver.c
-@@ -1,6 +1,11 @@
- /*
-  * drivers/pci/pci-driver.c
-  *
-+ * (C) Copyright 2002-2004, 2007 Greg Kroah-Hartman <greg at kroah.com>
-+ * (C) Copyright 2007 Novell Inc.
-+ *
-+ * Released under the GPL v2 only.
-+ *
-  */
+ 	struct dasd_fba_private *private;
+ 	int sb, rc;
  
- #include <linux/pci.h>
-@@ -96,17 +101,21 @@ pci_create_newid_file(struct pci_driver *drv)
- {
- 	int error = 0;
- 	if (drv->probe != NULL)
--		error = sysfs_create_file(&drv->driver.kobj,
--					  &driver_attr_new_id.attr);
-+		error = driver_create_file(&drv->driver, &driver_attr_new_id);
- 	return error;
+-	private = (struct dasd_fba_private *) device->private;
++	private = (struct dasd_fba_private *) block->base->private;
+ 	rc = dasd_check_blocksize(private->rdc_data.blk_size);
+ 	if (rc) {
+-		DEV_MESSAGE(KERN_INFO, device, "unknown blocksize %d",
++		DEV_MESSAGE(KERN_INFO, block->base, "unknown blocksize %d",
+ 			    private->rdc_data.blk_size);
+ 		return rc;
+ 	}
+-	device->blocks = private->rdc_data.blk_bdsa;
+-	device->bp_block = private->rdc_data.blk_size;
+-	device->s2b_shift = 0;	/* bits to shift 512 to get a block */
++	block->blocks = private->rdc_data.blk_bdsa;
++	block->bp_block = private->rdc_data.blk_size;
++	block->s2b_shift = 0;	/* bits to shift 512 to get a block */
+ 	for (sb = 512; sb < private->rdc_data.blk_size; sb = sb << 1)
+-		device->s2b_shift++;
++		block->s2b_shift++;
+ 	return 0;
  }
  
-+static void pci_remove_newid_file(struct pci_driver *drv)
-+{
-+	driver_remove_file(&drv->driver, &driver_attr_new_id);
-+}
- #else /* !CONFIG_HOTPLUG */
- static inline void pci_free_dynids(struct pci_driver *drv) {}
- static inline int pci_create_newid_file(struct pci_driver *drv)
+-static int
+-dasd_fba_fill_geometry(struct dasd_device *device, struct hd_geometry *geo)
++static int dasd_fba_fill_geometry(struct dasd_block *block,
++				  struct hd_geometry *geo)
  {
+-	if (dasd_check_blocksize(device->bp_block) != 0)
++	if (dasd_check_blocksize(block->bp_block) != 0)
+ 		return -EINVAL;
+-	geo->cylinders = (device->blocks << device->s2b_shift) >> 10;
++	geo->cylinders = (block->blocks << block->s2b_shift) >> 10;
+ 	geo->heads = 16;
+-	geo->sectors = 128 >> device->s2b_shift;
++	geo->sectors = 128 >> block->s2b_shift;
  	return 0;
  }
-+static inline void pci_remove_newid_file(struct pci_driver *drv) {}
- #endif
- 
- /**
-@@ -352,50 +361,6 @@ static void pci_device_shutdown(struct device *dev)
- 		drv->shutdown(pci_dev);
- }
  
--#define kobj_to_pci_driver(obj) container_of(obj, struct device_driver, kobj)
--#define attr_to_driver_attribute(obj) container_of(obj, struct driver_attribute, attr)
--
--static ssize_t
--pci_driver_attr_show(struct kobject * kobj, struct attribute *attr, char *buf)
--{
--	struct device_driver *driver = kobj_to_pci_driver(kobj);
--	struct driver_attribute *dattr = attr_to_driver_attribute(attr);
--	ssize_t ret;
--
--	if (!get_driver(driver))
--		return -ENODEV;
--
--	ret = dattr->show ? dattr->show(driver, buf) : -EIO;
--
--	put_driver(driver);
--	return ret;
--}
--
--static ssize_t
--pci_driver_attr_store(struct kobject * kobj, struct attribute *attr,
--		      const char *buf, size_t count)
+-static dasd_era_t
+-dasd_fba_examine_error(struct dasd_ccw_req * cqr, struct irb * irb)
 -{
--	struct device_driver *driver = kobj_to_pci_driver(kobj);
--	struct driver_attribute *dattr = attr_to_driver_attribute(attr);
--	ssize_t ret;
--
--	if (!get_driver(driver))
--		return -ENODEV;
+-	struct dasd_device *device;
+-	struct ccw_device *cdev;
 -
--	ret = dattr->store ? dattr->store(driver, buf, count) : -EIO;
+-	device = (struct dasd_device *) cqr->device;
+-	if (irb->scsw.cstat == 0x00 &&
+-	    irb->scsw.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))
+-		return dasd_era_none;
 -
--	put_driver(driver);
--	return ret;
+-	cdev = device->cdev;
+-	switch (cdev->id.dev_type) {
+-	case 0x3370:
+-		return dasd_3370_erp_examine(cqr, irb);
+-	case 0x9336:
+-		return dasd_9336_erp_examine(cqr, irb);
+-	default:
+-		return dasd_era_recover;
+-	}
 -}
 -
--static struct sysfs_ops pci_driver_sysfs_ops = {
--	.show = pci_driver_attr_show,
--	.store = pci_driver_attr_store,
--};
--static struct kobj_type pci_driver_kobj_type = {
--	.sysfs_ops = &pci_driver_sysfs_ops,
--};
--
- /**
-  * __pci_register_driver - register a new pci driver
-  * @drv: the driver structure to register
-@@ -417,7 +382,6 @@ int __pci_register_driver(struct pci_driver *drv, struct module *owner,
- 	drv->driver.bus = &pci_bus_type;
- 	drv->driver.owner = owner;
- 	drv->driver.mod_name = mod_name;
--	drv->driver.kobj.ktype = &pci_driver_kobj_type;
- 
- 	spin_lock_init(&drv->dynids.lock);
- 	INIT_LIST_HEAD(&drv->dynids.list);
-@@ -447,6 +411,7 @@ int __pci_register_driver(struct pci_driver *drv, struct module *owner,
- void
- pci_unregister_driver(struct pci_driver *drv)
+ static dasd_erp_fn_t
+ dasd_fba_erp_action(struct dasd_ccw_req * cqr)
  {
-+	pci_remove_newid_file(drv);
- 	driver_unregister(&drv->driver);
- 	pci_free_dynids(drv);
- }
-diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
-index c5ca313..5fd5852 100644
---- a/drivers/pci/probe.c
-+++ b/drivers/pci/probe.c
-@@ -1210,16 +1210,19 @@ static void __init pci_sort_breadthfirst_klist(void)
- 	struct klist_node *n;
- 	struct device *dev;
- 	struct pci_dev *pdev;
-+	struct klist *device_klist;
- 
--	spin_lock(&pci_bus_type.klist_devices.k_lock);
--	list_for_each_safe(pos, tmp, &pci_bus_type.klist_devices.k_list) {
-+	device_klist = bus_get_device_klist(&pci_bus_type);
-+
-+	spin_lock(&device_klist->k_lock);
-+	list_for_each_safe(pos, tmp, &device_klist->k_list) {
- 		n = container_of(pos, struct klist_node, n_node);
- 		dev = container_of(n, struct device, knode_bus);
- 		pdev = to_pci_dev(dev);
- 		pci_insertion_sort_klist(pdev, &sorted_devices);
- 	}
--	list_splice(&sorted_devices, &pci_bus_type.klist_devices.k_list);
--	spin_unlock(&pci_bus_type.klist_devices.k_lock);
-+	list_splice(&sorted_devices, &device_klist->k_list);
-+	spin_unlock(&device_klist->k_lock);
- }
+@@ -221,13 +209,34 @@ dasd_fba_erp_postaction(struct dasd_ccw_req * cqr)
+ 	if (cqr->function == dasd_default_erp_action)
+ 		return dasd_default_erp_postaction;
  
- static void __init pci_insertion_sort_devices(struct pci_dev *a, struct list_head *list)
-diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c
-index 5cf89a9..15c18f5 100644
---- a/drivers/pcmcia/ds.c
-+++ b/drivers/pcmcia/ds.c
-@@ -312,8 +312,7 @@ pcmcia_create_newid_file(struct pcmcia_driver *drv)
- {
- 	int error = 0;
- 	if (drv->probe != NULL)
--		error = sysfs_create_file(&drv->drv.kobj,
--					  &driver_attr_new_id.attr);
-+		error = driver_create_file(&drv->drv, &driver_attr_new_id);
- 	return error;
+-	DEV_MESSAGE(KERN_WARNING, cqr->device, "unknown ERP action %p",
++	DEV_MESSAGE(KERN_WARNING, cqr->startdev, "unknown ERP action %p",
+ 		    cqr->function);
+ 	return NULL;
  }
  
-diff --git a/drivers/power/apm_power.c b/drivers/power/apm_power.c
-index bbf3ee1..7e29b90 100644
---- a/drivers/power/apm_power.c
-+++ b/drivers/power/apm_power.c
-@@ -13,6 +13,7 @@
- #include <linux/power_supply.h>
- #include <linux/apm-emulation.h>
- 
-+static DEFINE_MUTEX(apm_mutex);
- #define PSY_PROP(psy, prop, val) psy->get_property(psy, \
- 			 POWER_SUPPLY_PROP_##prop, val)
- 
-@@ -23,67 +24,86 @@
- 
- static struct power_supply *main_battery;
- 
--static void find_main_battery(void)
--{
--	struct device *dev;
--	struct power_supply *bat = NULL;
--	struct power_supply *max_charge_bat = NULL;
--	struct power_supply *max_energy_bat = NULL;
-+struct find_bat_param {
-+	struct power_supply *main;
-+	struct power_supply *bat;
-+	struct power_supply *max_charge_bat;
-+	struct power_supply *max_energy_bat;
- 	union power_supply_propval full;
--	int max_charge = 0;
--	int max_energy = 0;
-+	int max_charge;
-+	int max_energy;
-+};
- 
--	main_battery = NULL;
-+static int __find_main_battery(struct device *dev, void *data)
-+{
-+	struct find_bat_param *bp = (struct find_bat_param *)data;
- 
--	list_for_each_entry(dev, &power_supply_class->devices, node) {
--		bat = dev_get_drvdata(dev);
-+	bp->bat = dev_get_drvdata(dev);
- 
--		if (bat->use_for_apm) {
--			/* nice, we explicitly asked to report this battery. */
--			main_battery = bat;
--			return;
--		}
-+	if (bp->bat->use_for_apm) {
-+		/* nice, we explicitly asked to report this battery. */
-+		bp->main = bp->bat;
-+		return 1;
-+	}
- 
--		if (!PSY_PROP(bat, CHARGE_FULL_DESIGN, &full) ||
--				!PSY_PROP(bat, CHARGE_FULL, &full)) {
--			if (full.intval > max_charge) {
--				max_charge_bat = bat;
--				max_charge = full.intval;
--			}
--		} else if (!PSY_PROP(bat, ENERGY_FULL_DESIGN, &full) ||
--				!PSY_PROP(bat, ENERGY_FULL, &full)) {
--			if (full.intval > max_energy) {
--				max_energy_bat = bat;
--				max_energy = full.intval;
--			}
-+	if (!PSY_PROP(bp->bat, CHARGE_FULL_DESIGN, &bp->full) ||
-+			!PSY_PROP(bp->bat, CHARGE_FULL, &bp->full)) {
-+		if (bp->full.intval > bp->max_charge) {
-+			bp->max_charge_bat = bp->bat;
-+			bp->max_charge = bp->full.intval;
-+		}
-+	} else if (!PSY_PROP(bp->bat, ENERGY_FULL_DESIGN, &bp->full) ||
-+			!PSY_PROP(bp->bat, ENERGY_FULL, &bp->full)) {
-+		if (bp->full.intval > bp->max_energy) {
-+			bp->max_energy_bat = bp->bat;
-+			bp->max_energy = bp->full.intval;
- 		}
- 	}
-+	return 0;
-+}
-+
-+static void find_main_battery(void)
+-static struct dasd_ccw_req *
+-dasd_fba_build_cp(struct dasd_device * device, struct request *req)
++static void dasd_fba_handle_unsolicited_interrupt(struct dasd_device *device,
++						   struct irb *irb)
 +{
-+	struct find_bat_param bp;
-+	int error;
-+
-+	memset(&bp, 0, sizeof(struct find_bat_param));
-+	main_battery = NULL;
-+	bp.main = main_battery;
++	char mask;
 +
-+	error = class_for_each_device(power_supply_class, &bp,
-+				      __find_main_battery);
-+	if (error) {
-+		main_battery = bp.main;
++	/* first of all check for state change pending interrupt */
++	mask = DEV_STAT_ATTENTION | DEV_STAT_DEV_END | DEV_STAT_UNIT_EXCEP;
++	if ((irb->scsw.dstat & mask) == mask) {
++		dasd_generic_handle_state_change(device);
 +		return;
 +	}
++
++	/* check for unsolicited interrupts */
++	DEV_MESSAGE(KERN_DEBUG, device, "%s",
++		    "unsolicited interrupt received");
++	device->discipline->dump_sense(device, NULL, irb);
++	dasd_schedule_device_bh(device);
++	return;
++};
++
++static struct dasd_ccw_req *dasd_fba_build_cp(struct dasd_device * memdev,
++					      struct dasd_block *block,
++					      struct request *req)
+ {
+ 	struct dasd_fba_private *private;
+ 	unsigned long *idaws;
+@@ -242,17 +251,17 @@ dasd_fba_build_cp(struct dasd_device * device, struct request *req)
+ 	unsigned int blksize, off;
+ 	unsigned char cmd;
  
--	if ((max_energy_bat && max_charge_bat) &&
--			(max_energy_bat != max_charge_bat)) {
-+	if ((bp.max_energy_bat && bp.max_charge_bat) &&
-+			(bp.max_energy_bat != bp.max_charge_bat)) {
- 		/* try guess battery with more capacity */
--		if (!PSY_PROP(max_charge_bat, VOLTAGE_MAX_DESIGN, &full)) {
--			if (max_energy > max_charge * full.intval)
--				main_battery = max_energy_bat;
-+		if (!PSY_PROP(bp.max_charge_bat, VOLTAGE_MAX_DESIGN,
-+			      &bp.full)) {
-+			if (bp.max_energy > bp.max_charge * bp.full.intval)
-+				main_battery = bp.max_energy_bat;
- 			else
--				main_battery = max_charge_bat;
--		} else if (!PSY_PROP(max_energy_bat, VOLTAGE_MAX_DESIGN,
--								  &full)) {
--			if (max_charge > max_energy / full.intval)
--				main_battery = max_charge_bat;
-+				main_battery = bp.max_charge_bat;
-+		} else if (!PSY_PROP(bp.max_energy_bat, VOLTAGE_MAX_DESIGN,
-+								  &bp.full)) {
-+			if (bp.max_charge > bp.max_energy / bp.full.intval)
-+				main_battery = bp.max_charge_bat;
- 			else
--				main_battery = max_energy_bat;
-+				main_battery = bp.max_energy_bat;
- 		} else {
- 			/* give up, choice any */
--			main_battery = max_energy_bat;
-+			main_battery = bp.max_energy_bat;
- 		}
--	} else if (max_charge_bat) {
--		main_battery = max_charge_bat;
--	} else if (max_energy_bat) {
--		main_battery = max_energy_bat;
-+	} else if (bp.max_charge_bat) {
-+		main_battery = bp.max_charge_bat;
-+	} else if (bp.max_energy_bat) {
-+		main_battery = bp.max_energy_bat;
- 	} else {
- 		/* give up, try the last if any */
--		main_battery = bat;
-+		main_battery = bp.bat;
+-	private = (struct dasd_fba_private *) device->private;
++	private = (struct dasd_fba_private *) block->base->private;
+ 	if (rq_data_dir(req) == READ) {
+ 		cmd = DASD_FBA_CCW_READ;
+ 	} else if (rq_data_dir(req) == WRITE) {
+ 		cmd = DASD_FBA_CCW_WRITE;
+ 	} else
+ 		return ERR_PTR(-EINVAL);
+-	blksize = device->bp_block;
++	blksize = block->bp_block;
+ 	/* Calculate record id of first and last block. */
+-	first_rec = req->sector >> device->s2b_shift;
+-	last_rec = (req->sector + req->nr_sectors - 1) >> device->s2b_shift;
++	first_rec = req->sector >> block->s2b_shift;
++	last_rec = (req->sector + req->nr_sectors - 1) >> block->s2b_shift;
+ 	/* Check struct bio and count the number of blocks for the request. */
+ 	count = 0;
+ 	cidaw = 0;
+@@ -260,7 +269,7 @@ dasd_fba_build_cp(struct dasd_device * device, struct request *req)
+ 		if (bv->bv_len & (blksize - 1))
+ 			/* Fba can only do full blocks. */
+ 			return ERR_PTR(-EINVAL);
+-		count += bv->bv_len >> (device->s2b_shift + 9);
++		count += bv->bv_len >> (block->s2b_shift + 9);
+ #if defined(CONFIG_64BIT)
+ 		if (idal_is_needed (page_address(bv->bv_page), bv->bv_len))
+ 			cidaw += bv->bv_len / blksize;
+@@ -284,13 +293,13 @@ dasd_fba_build_cp(struct dasd_device * device, struct request *req)
  	}
- }
- 
-@@ -207,10 +227,10 @@ static void apm_battery_apm_get_power_status(struct apm_power_info *info)
- 	union power_supply_propval status;
- 	union power_supply_propval capacity, time_to_full, time_to_empty;
- 
--	down(&power_supply_class->sem);
-+	mutex_lock(&apm_mutex);
- 	find_main_battery();
- 	if (!main_battery) {
--		up(&power_supply_class->sem);
-+		mutex_unlock(&apm_mutex);
- 		return;
+ 	/* Allocate the ccw request. */
+ 	cqr = dasd_smalloc_request(dasd_fba_discipline.name,
+-				   cplength, datasize, device);
++				   cplength, datasize, memdev);
+ 	if (IS_ERR(cqr))
+ 		return cqr;
+ 	ccw = cqr->cpaddr;
+ 	/* First ccw is define extent. */
+ 	define_extent(ccw++, cqr->data, rq_data_dir(req),
+-		      device->bp_block, req->sector, req->nr_sectors);
++		      block->bp_block, req->sector, req->nr_sectors);
+ 	/* Build locate_record + read/write ccws. */
+ 	idaws = (unsigned long *) (cqr->data + sizeof(struct DE_fba_data));
+ 	LO_data = (struct LO_fba_data *) (idaws + cidaw);
+@@ -326,7 +335,7 @@ dasd_fba_build_cp(struct dasd_device * device, struct request *req)
+ 					ccw[-1].flags |= CCW_FLAG_CC;
+ 			}
+ 			ccw->cmd_code = cmd;
+-			ccw->count = device->bp_block;
++			ccw->count = block->bp_block;
+ 			if (idal_is_needed(dst, blksize)) {
+ 				ccw->cda = (__u32)(addr_t) idaws;
+ 				ccw->flags = CCW_FLAG_IDA;
+@@ -342,7 +351,9 @@ dasd_fba_build_cp(struct dasd_device * device, struct request *req)
  	}
+ 	if (req->cmd_flags & REQ_FAILFAST)
+ 		set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags);
+-	cqr->device = device;
++	cqr->startdev = memdev;
++	cqr->memdev = memdev;
++	cqr->block = block;
+ 	cqr->expires = 5 * 60 * HZ;	/* 5 minutes */
+ 	cqr->retries = 32;
+ 	cqr->buildclk = get_clock();
+@@ -363,8 +374,8 @@ dasd_fba_free_cp(struct dasd_ccw_req *cqr, struct request *req)
  
-@@ -278,7 +298,7 @@ static void apm_battery_apm_get_power_status(struct apm_power_info *info)
- 		}
+ 	if (!dasd_page_cache)
+ 		goto out;
+-	private = (struct dasd_fba_private *) cqr->device->private;
+-	blksize = cqr->device->bp_block;
++	private = (struct dasd_fba_private *) cqr->block->base->private;
++	blksize = cqr->block->bp_block;
+ 	ccw = cqr->cpaddr;
+ 	/* Skip over define extent & locate record. */
+ 	ccw++;
+@@ -394,10 +405,15 @@ dasd_fba_free_cp(struct dasd_ccw_req *cqr, struct request *req)
  	}
- 
--	up(&power_supply_class->sem);
-+	mutex_unlock(&apm_mutex);
+ out:
+ 	status = cqr->status == DASD_CQR_DONE;
+-	dasd_sfree_request(cqr, cqr->device);
++	dasd_sfree_request(cqr, cqr->memdev);
+ 	return status;
  }
  
- static int __init apm_battery_init(void)
-diff --git a/drivers/power/power_supply_core.c b/drivers/power/power_supply_core.c
-index a63b75c..03d6a38 100644
---- a/drivers/power/power_supply_core.c
-+++ b/drivers/power/power_supply_core.c
-@@ -20,28 +20,29 @@
- 
- struct class *power_supply_class;
- 
-+static int __power_supply_changed_work(struct device *dev, void *data)
++static void dasd_fba_handle_terminated_request(struct dasd_ccw_req *cqr)
 +{
-+	struct power_supply *psy = (struct power_supply *)data;
-+	struct power_supply *pst = dev_get_drvdata(dev);
-+	int i;
-+
-+	for (i = 0; i < psy->num_supplicants; i++)
-+		if (!strcmp(psy->supplied_to[i], pst->name)) {
-+			if (pst->external_power_changed)
-+				pst->external_power_changed(pst);
-+		}
-+	return 0;
-+}
++	cqr->status = DASD_CQR_FILLED;
++};
 +
- static void power_supply_changed_work(struct work_struct *work)
+ static int
+ dasd_fba_fill_info(struct dasd_device * device,
+ 		   struct dasd_information2_t * info)
+@@ -546,9 +562,10 @@ static struct dasd_discipline dasd_fba_discipline = {
+ 	.fill_geometry = dasd_fba_fill_geometry,
+ 	.start_IO = dasd_start_IO,
+ 	.term_IO = dasd_term_IO,
+-	.examine_error = dasd_fba_examine_error,
++	.handle_terminated_request = dasd_fba_handle_terminated_request,
+ 	.erp_action = dasd_fba_erp_action,
+ 	.erp_postaction = dasd_fba_erp_postaction,
++	.handle_unsolicited_interrupt = dasd_fba_handle_unsolicited_interrupt,
+ 	.build_cp = dasd_fba_build_cp,
+ 	.free_cp = dasd_fba_free_cp,
+ 	.dump_sense = dasd_fba_dump_sense,
+diff --git a/drivers/s390/block/dasd_genhd.c b/drivers/s390/block/dasd_genhd.c
+index 47ba446..aee6565 100644
+--- a/drivers/s390/block/dasd_genhd.c
++++ b/drivers/s390/block/dasd_genhd.c
+@@ -25,14 +25,15 @@
+ /*
+  * Allocate and register gendisk structure for device.
+  */
+-int
+-dasd_gendisk_alloc(struct dasd_device *device)
++int dasd_gendisk_alloc(struct dasd_block *block)
  {
- 	struct power_supply *psy = container_of(work, struct power_supply,
- 						changed_work);
--	int i;
+ 	struct gendisk *gdp;
++	struct dasd_device *base;
+ 	int len;
  
- 	dev_dbg(psy->dev, "%s\n", __FUNCTION__);
+ 	/* Make sure the minor for this device exists. */
+-	if (device->devindex >= DASD_PER_MAJOR)
++	base = block->base;
++	if (base->devindex >= DASD_PER_MAJOR)
+ 		return -EBUSY;
  
--	for (i = 0; i < psy->num_supplicants; i++) {
--		struct device *dev;
--
--		down(&power_supply_class->sem);
--		list_for_each_entry(dev, &power_supply_class->devices, node) {
--			struct power_supply *pst = dev_get_drvdata(dev);
--
--			if (!strcmp(psy->supplied_to[i], pst->name)) {
--				if (pst->external_power_changed)
--					pst->external_power_changed(pst);
--			}
--		}
--		up(&power_supply_class->sem);
--	}
-+	class_for_each_device(power_supply_class, psy,
-+			      __power_supply_changed_work);
+ 	gdp = alloc_disk(1 << DASD_PARTN_BITS);
+@@ -41,9 +42,9 @@ dasd_gendisk_alloc(struct dasd_device *device)
  
- 	power_supply_update_leds(psy);
+ 	/* Initialize gendisk structure. */
+ 	gdp->major = DASD_MAJOR;
+-	gdp->first_minor = device->devindex << DASD_PARTN_BITS;
++	gdp->first_minor = base->devindex << DASD_PARTN_BITS;
+ 	gdp->fops = &dasd_device_operations;
+-	gdp->driverfs_dev = &device->cdev->dev;
++	gdp->driverfs_dev = &base->cdev->dev;
  
-@@ -55,32 +56,35 @@ void power_supply_changed(struct power_supply *psy)
- 	schedule_work(&psy->changed_work);
+ 	/*
+ 	 * Set device name.
+@@ -53,53 +54,51 @@ dasd_gendisk_alloc(struct dasd_device *device)
+ 	 *   dasdaaaa - dasdzzzz : 456976 devices, added up = 475252
+ 	 */
+ 	len = sprintf(gdp->disk_name, "dasd");
+-	if (device->devindex > 25) {
+-	        if (device->devindex > 701) {
+-		        if (device->devindex > 18277)
++	if (base->devindex > 25) {
++		if (base->devindex > 701) {
++			if (base->devindex > 18277)
+ 			        len += sprintf(gdp->disk_name + len, "%c",
+-					       'a'+(((device->devindex-18278)
++					       'a'+(((base->devindex-18278)
+ 						     /17576)%26));
+ 			len += sprintf(gdp->disk_name + len, "%c",
+-				       'a'+(((device->devindex-702)/676)%26));
++				       'a'+(((base->devindex-702)/676)%26));
+ 		}
+ 		len += sprintf(gdp->disk_name + len, "%c",
+-			       'a'+(((device->devindex-26)/26)%26));
++			       'a'+(((base->devindex-26)/26)%26));
+ 	}
+-	len += sprintf(gdp->disk_name + len, "%c", 'a'+(device->devindex%26));
++	len += sprintf(gdp->disk_name + len, "%c", 'a'+(base->devindex%26));
+ 
+-	if (device->features & DASD_FEATURE_READONLY)
++	if (block->base->features & DASD_FEATURE_READONLY)
+ 		set_disk_ro(gdp, 1);
+-	gdp->private_data = device;
+-	gdp->queue = device->request_queue;
+-	device->gdp = gdp;
+-	set_capacity(device->gdp, 0);
+-	add_disk(device->gdp);
++	gdp->private_data = block;
++	gdp->queue = block->request_queue;
++	block->gdp = gdp;
++	set_capacity(block->gdp, 0);
++	add_disk(block->gdp);
+ 	return 0;
  }
  
--int power_supply_am_i_supplied(struct power_supply *psy)
-+static int __power_supply_am_i_supplied(struct device *dev, void *data)
+ /*
+  * Unregister and free gendisk structure for device.
+  */
+-void
+-dasd_gendisk_free(struct dasd_device *device)
++void dasd_gendisk_free(struct dasd_block *block)
  {
- 	union power_supply_propval ret = {0,};
--	struct device *dev;
--
--	down(&power_supply_class->sem);
--	list_for_each_entry(dev, &power_supply_class->devices, node) {
--		struct power_supply *epsy = dev_get_drvdata(dev);
--		int i;
--
--		for (i = 0; i < epsy->num_supplicants; i++) {
--			if (!strcmp(epsy->supplied_to[i], psy->name)) {
--				if (epsy->get_property(epsy,
--					  POWER_SUPPLY_PROP_ONLINE, &ret))
--					continue;
--				if (ret.intval)
--					goto out;
--			}
-+	struct power_supply *psy = (struct power_supply *)data;
-+	struct power_supply *epsy = dev_get_drvdata(dev);
-+	int i;
-+
-+	for (i = 0; i < epsy->num_supplicants; i++) {
-+		if (!strcmp(epsy->supplied_to[i], psy->name)) {
-+			if (epsy->get_property(epsy,
-+				  POWER_SUPPLY_PROP_ONLINE, &ret))
-+				continue;
-+			if (ret.intval)
-+				return ret.intval;
- 		}
+-	if (device->gdp) {
+-		del_gendisk(device->gdp);
+-		device->gdp->queue = NULL;
+-		put_disk(device->gdp);
+-		device->gdp = NULL;
++	if (block->gdp) {
++		del_gendisk(block->gdp);
++		block->gdp->queue = NULL;
++		put_disk(block->gdp);
++		block->gdp = NULL;
  	}
--out:
--	up(&power_supply_class->sem);
-+	return 0;
-+}
-+
-+int power_supply_am_i_supplied(struct power_supply *psy)
-+{
-+	int error;
-+
-+	error = class_for_each_device(power_supply_class, psy,
-+				      __power_supply_am_i_supplied);
+ }
  
--	dev_dbg(psy->dev, "%s %d\n", __FUNCTION__, ret.intval);
-+	dev_dbg(psy->dev, "%s %d\n", __FUNCTION__, error);
+ /*
+  * Trigger a partition detection.
+  */
+-int
+-dasd_scan_partitions(struct dasd_device * device)
++int dasd_scan_partitions(struct dasd_block *block)
+ {
+ 	struct block_device *bdev;
  
--	return ret.intval;
-+	return error;
+-	bdev = bdget_disk(device->gdp, 0);
++	bdev = bdget_disk(block->gdp, 0);
+ 	if (!bdev || blkdev_get(bdev, FMODE_READ, 1) < 0)
+ 		return -ENODEV;
+ 	/*
+@@ -117,7 +116,7 @@ dasd_scan_partitions(struct dasd_device * device)
+ 	 * is why the assignment to device->bdev is done AFTER
+ 	 * the BLKRRPART ioctl.
+ 	 */
+-	device->bdev = bdev;
++	block->bdev = bdev;
+ 	return 0;
  }
  
- int power_supply_register(struct device *parent, struct power_supply *psy)
-diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c
-index f1e00ff..7e3ad4f 100644
---- a/drivers/rtc/interface.c
-+++ b/drivers/rtc/interface.c
-@@ -251,20 +251,23 @@ void rtc_update_irq(struct rtc_device *rtc,
+@@ -125,8 +124,7 @@ dasd_scan_partitions(struct dasd_device * device)
+  * Remove all inodes in the system for a device, delete the
+  * partitions and make device unusable by setting its size to zero.
+  */
+-void
+-dasd_destroy_partitions(struct dasd_device * device)
++void dasd_destroy_partitions(struct dasd_block *block)
+ {
+ 	/* The two structs have 168/176 byte on 31/64 bit. */
+ 	struct blkpg_partition bpart;
+@@ -137,8 +135,8 @@ dasd_destroy_partitions(struct dasd_device * device)
+ 	 * Get the bdev pointer from the device structure and clear
+ 	 * device->bdev to lower the offline open_count limit again.
+ 	 */
+-	bdev = device->bdev;
+-	device->bdev = NULL;
++	bdev = block->bdev;
++	block->bdev = NULL;
+ 
+ 	/*
+ 	 * See fs/partition/check.c:delete_partition
+@@ -149,17 +147,16 @@ dasd_destroy_partitions(struct dasd_device * device)
+ 	memset(&barg, 0, sizeof(struct blkpg_ioctl_arg));
+ 	barg.data = (void __force __user *) &bpart;
+ 	barg.op = BLKPG_DEL_PARTITION;
+-	for (bpart.pno = device->gdp->minors - 1; bpart.pno > 0; bpart.pno--)
++	for (bpart.pno = block->gdp->minors - 1; bpart.pno > 0; bpart.pno--)
+ 		ioctl_by_bdev(bdev, BLKPG, (unsigned long) &barg);
+ 
+-	invalidate_partition(device->gdp, 0);
++	invalidate_partition(block->gdp, 0);
+ 	/* Matching blkdev_put to the blkdev_get in dasd_scan_partitions. */
+ 	blkdev_put(bdev);
+-	set_capacity(device->gdp, 0);
++	set_capacity(block->gdp, 0);
  }
- EXPORT_SYMBOL_GPL(rtc_update_irq);
  
-+static int __rtc_match(struct device *dev, void *data)
-+{
-+	char *name = (char *)data;
-+
-+	if (strncmp(dev->bus_id, name, BUS_ID_SIZE) == 0)
-+		return 1;
-+	return 0;
-+}
-+
- struct rtc_device *rtc_class_open(char *name)
+-int
+-dasd_gendisk_init(void)
++int dasd_gendisk_init(void)
  {
- 	struct device *dev;
- 	struct rtc_device *rtc = NULL;
- 
--	down(&rtc_class->sem);
--	list_for_each_entry(dev, &rtc_class->devices, node) {
--		if (strncmp(dev->bus_id, name, BUS_ID_SIZE) == 0) {
--			dev = get_device(dev);
--			if (dev)
--				rtc = to_rtc_device(dev);
--			break;
--		}
--	}
-+	dev = class_find_device(rtc_class, name, __rtc_match);
-+	if (dev)
-+		rtc = to_rtc_device(dev);
+ 	int rc;
  
- 	if (rtc) {
- 		if (!try_module_get(rtc->owner)) {
-@@ -272,7 +275,6 @@ struct rtc_device *rtc_class_open(char *name)
- 			rtc = NULL;
- 		}
- 	}
--	up(&rtc_class->sem);
+@@ -174,8 +171,7 @@ dasd_gendisk_init(void)
+ 	return 0;
+ }
  
- 	return rtc;
+-void
+-dasd_gendisk_exit(void)
++void dasd_gendisk_exit(void)
+ {
+ 	unregister_blkdev(DASD_MAJOR, "dasd");
  }
-diff --git a/drivers/rtc/rtc-ds1672.c b/drivers/rtc/rtc-ds1672.c
-index dfef163..e0900ca 100644
---- a/drivers/rtc/rtc-ds1672.c
-+++ b/drivers/rtc/rtc-ds1672.c
-@@ -16,7 +16,7 @@
- #define DRV_VERSION "0.3"
+diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h
+index d427dae..44b2984 100644
+--- a/drivers/s390/block/dasd_int.h
++++ b/drivers/s390/block/dasd_int.h
+@@ -64,13 +64,7 @@
+  * SECTION: Type definitions
+  */
+ struct dasd_device;
+-
+-typedef enum {
+-	dasd_era_fatal = -1,	/* no chance to recover		     */
+-	dasd_era_none = 0,	/* don't recover, everything alright */
+-	dasd_era_msg = 1,	/* don't recover, just report...     */
+-	dasd_era_recover = 2	/* recovery action recommended	     */
+-} dasd_era_t;
++struct dasd_block;
  
- /* Addresses to scan: none. This chip cannot be detected. */
--static unsigned short normal_i2c[] = { I2C_CLIENT_END };
-+static const unsigned short normal_i2c[] = { I2C_CLIENT_END };
+ /* BIT DEFINITIONS FOR SENSE DATA */
+ #define DASD_SENSE_BIT_0 0x80
+@@ -151,19 +145,22 @@ do { \
  
- /* Insmod parameters */
- I2C_CLIENT_INSMOD;
-diff --git a/drivers/rtc/rtc-isl1208.c b/drivers/rtc/rtc-isl1208.c
-index 1c74364..725b0c7 100644
---- a/drivers/rtc/rtc-isl1208.c
-+++ b/drivers/rtc/rtc-isl1208.c
-@@ -61,7 +61,7 @@
- /* i2c configuration */
- #define ISL1208_I2C_ADDR 0xde
+ struct dasd_ccw_req {
+ 	unsigned int magic;		/* Eye catcher */
+-        struct list_head list;		/* list_head for request queueing. */
++	struct list_head devlist;	/* for dasd_device request queue */
++	struct list_head blocklist;	/* for dasd_block request queue */
  
--static unsigned short normal_i2c[] = {
-+static const unsigned short normal_i2c[] = {
- 	ISL1208_I2C_ADDR>>1, I2C_CLIENT_END
- };
- I2C_CLIENT_INSMOD; /* defines addr_data */
-diff --git a/drivers/rtc/rtc-max6900.c b/drivers/rtc/rtc-max6900.c
-index a1cd448..7683412 100644
---- a/drivers/rtc/rtc-max6900.c
-+++ b/drivers/rtc/rtc-max6900.c
-@@ -54,7 +54,7 @@
+ 	/* Where to execute what... */
+-	struct dasd_device *device;	/* device the request is for */
++	struct dasd_block *block;	/* the originating block device */
++	struct dasd_device *memdev;	/* the device used to allocate this */
++	struct dasd_device *startdev;	/* device the request is started on */
+ 	struct ccw1 *cpaddr;		/* address of channel program */
+-	char status;	        	/* status of this request */
++	char status;			/* status of this request */
+ 	short retries;			/* A retry counter */
+ 	unsigned long flags;        	/* flags of this request */
  
- #define MAX6900_I2C_ADDR		0xa0
+ 	/* ... and how */
+ 	unsigned long starttime;	/* jiffies time of request start */
+ 	int expires;			/* expiration period in jiffies */
+-	char lpm;               	/* logical path mask */
++	char lpm;			/* logical path mask */
+ 	void *data;			/* pointer to data area */
  
--static unsigned short normal_i2c[] = {
-+static const unsigned short normal_i2c[] = {
- 	MAX6900_I2C_ADDR >> 1,
- 	I2C_CLIENT_END
+ 	/* these are important for recovering erroneous requests          */
+@@ -178,20 +175,27 @@ struct dasd_ccw_req {
+ 	unsigned long long endclk;	/* TOD-clock of request termination */
+ 
+         /* Callback that is called after reaching final status. */
+-        void (*callback)(struct dasd_ccw_req *, void *data);
+-        void *callback_data;
++	void (*callback)(struct dasd_ccw_req *, void *data);
++	void *callback_data;
  };
-diff --git a/drivers/rtc/rtc-pcf8563.c b/drivers/rtc/rtc-pcf8563.c
-index 0242d80..b3317fc 100644
---- a/drivers/rtc/rtc-pcf8563.c
-+++ b/drivers/rtc/rtc-pcf8563.c
-@@ -25,7 +25,7 @@
-  * located at 0x51 will pass the validation routine due to
-  * the way the registers are implemented.
-  */
--static unsigned short normal_i2c[] = { I2C_CLIENT_END };
-+static const unsigned short normal_i2c[] = { I2C_CLIENT_END };
  
- /* Module parameters */
- I2C_CLIENT_INSMOD;
-diff --git a/drivers/rtc/rtc-pcf8583.c b/drivers/rtc/rtc-pcf8583.c
-index 556d0e7..c973ba9 100644
---- a/drivers/rtc/rtc-pcf8583.c
-+++ b/drivers/rtc/rtc-pcf8583.c
-@@ -40,7 +40,7 @@ struct pcf8583 {
- #define CTRL_ALARM	0x02
- #define CTRL_TIMER	0x01
+ /*
+  * dasd_ccw_req -> status can be:
+  */
+-#define DASD_CQR_FILLED   0x00	/* request is ready to be processed */
+-#define DASD_CQR_QUEUED   0x01	/* request is queued to be processed */
+-#define DASD_CQR_IN_IO    0x02	/* request is currently in IO */
+-#define DASD_CQR_DONE     0x03	/* request is completed successfully */
+-#define DASD_CQR_ERROR    0x04	/* request is completed with error */
+-#define DASD_CQR_FAILED   0x05	/* request is finally failed */
+-#define DASD_CQR_CLEAR    0x06	/* request is clear pending */
++#define DASD_CQR_FILLED 	0x00	/* request is ready to be processed */
++#define DASD_CQR_DONE		0x01	/* request is completed successfully */
++#define DASD_CQR_NEED_ERP	0x02	/* request needs recovery action */
++#define DASD_CQR_IN_ERP 	0x03	/* request is in recovery */
++#define DASD_CQR_FAILED 	0x04	/* request is finally failed */
++#define DASD_CQR_TERMINATED	0x05	/* request was stopped by driver */
++
++#define DASD_CQR_QUEUED 	0x80	/* request is queued to be processed */
++#define DASD_CQR_IN_IO		0x81	/* request is currently in IO */
++#define DASD_CQR_ERROR		0x82	/* request is completed with error */
++#define DASD_CQR_CLEAR_PENDING	0x83	/* request is clear pending */
++#define DASD_CQR_CLEARED	0x84	/* request was cleared */
++#define DASD_CQR_SUCCESS	0x85	/* request was successfull */
++
  
--static unsigned short normal_i2c[] = { 0x50, I2C_CLIENT_END };
-+static const unsigned short normal_i2c[] = { 0x50, I2C_CLIENT_END };
+ /* per dasd_ccw_req flags */
+ #define DASD_CQR_FLAGS_USE_ERP   0	/* use ERP for this request */
+@@ -214,52 +218,71 @@ struct dasd_discipline {
  
- /* Module parameters */
- I2C_CLIENT_INSMOD;
-diff --git a/drivers/rtc/rtc-x1205.c b/drivers/rtc/rtc-x1205.c
-index b3fae35..b90fb18 100644
---- a/drivers/rtc/rtc-x1205.c
-+++ b/drivers/rtc/rtc-x1205.c
-@@ -32,7 +32,7 @@
-  * unknown chips, the user must explicitly set the probe parameter.
-  */
+ 	struct list_head list;	/* used for list of disciplines */
  
--static unsigned short normal_i2c[] = { I2C_CLIENT_END };
-+static const unsigned short normal_i2c[] = { I2C_CLIENT_END };
+-        /*
+-         * Device recognition functions. check_device is used to verify
+-         * the sense data and the information returned by read device
+-         * characteristics. It returns 0 if the discipline can be used
+-         * for the device in question.
+-         * do_analysis is used in the step from device state "basic" to
+-         * state "accept". It returns 0 if the device can be made ready,
+-         * it returns -EMEDIUMTYPE if the device can't be made ready or
+-         * -EAGAIN if do_analysis started a ccw that needs to complete
+-         * before the analysis may be repeated.
+-         */
+-        int (*check_device)(struct dasd_device *);
+-	int (*do_analysis) (struct dasd_device *);
+-
+-        /*
+-         * Device operation functions. build_cp creates a ccw chain for
+-         * a block device request, start_io starts the request and
+-         * term_IO cancels it (e.g. in case of a timeout). format_device
+-         * returns a ccw chain to be used to format the device.
+-         */
++	/*
++	 * Device recognition functions. check_device is used to verify
++	 * the sense data and the information returned by read device
++	 * characteristics. It returns 0 if the discipline can be used
++	 * for the device in question. uncheck_device is called during
++	 * device shutdown to deregister a device from its discipline.
++	 */
++	int (*check_device) (struct dasd_device *);
++	void (*uncheck_device) (struct dasd_device *);
++
++	/*
++	 * do_analysis is used in the step from device state "basic" to
++	 * state "accept". It returns 0 if the device can be made ready,
++	 * it returns -EMEDIUMTYPE if the device can't be made ready or
++	 * -EAGAIN if do_analysis started a ccw that needs to complete
++	 * before the analysis may be repeated.
++	 */
++	int (*do_analysis) (struct dasd_block *);
++
++	/*
++	 * Last things to do when a device is set online, and first things
++	 * when it is set offline.
++	 */
++	int (*ready_to_online) (struct dasd_device *);
++	int (*online_to_ready) (struct dasd_device *);
++
++	/*
++	 * Device operation functions. build_cp creates a ccw chain for
++	 * a block device request, start_io starts the request and
++	 * term_IO cancels it (e.g. in case of a timeout). format_device
++	 * returns a ccw chain to be used to format the device.
++	 * handle_terminated_request allows to examine a cqr and prepare
++	 * it for retry.
++	 */
+ 	struct dasd_ccw_req *(*build_cp) (struct dasd_device *,
++					  struct dasd_block *,
+ 					  struct request *);
+ 	int (*start_IO) (struct dasd_ccw_req *);
+ 	int (*term_IO) (struct dasd_ccw_req *);
++	void (*handle_terminated_request) (struct dasd_ccw_req *);
+ 	struct dasd_ccw_req *(*format_device) (struct dasd_device *,
+ 					       struct format_data_t *);
+ 	int (*free_cp) (struct dasd_ccw_req *, struct request *);
+-        /*
+-         * Error recovery functions. examine_error() returns a value that
+-         * indicates what to do for an error condition. If examine_error()
++
++	/*
++	 * Error recovery functions. examine_error() returns a value that
++	 * indicates what to do for an error condition. If examine_error()
+ 	 * returns 'dasd_era_recover' erp_action() is called to create a
+-         * special error recovery ccw. erp_postaction() is called after
+-         * an error recovery ccw has finished its execution. dump_sense
+-         * is called for every error condition to print the sense data
+-         * to the console.
+-         */
+-	dasd_era_t(*examine_error) (struct dasd_ccw_req *, struct irb *);
++	 * special error recovery ccw. erp_postaction() is called after
++	 * an error recovery ccw has finished its execution. dump_sense
++	 * is called for every error condition to print the sense data
++	 * to the console.
++	 */
+ 	dasd_erp_fn_t(*erp_action) (struct dasd_ccw_req *);
+ 	dasd_erp_fn_t(*erp_postaction) (struct dasd_ccw_req *);
+ 	void (*dump_sense) (struct dasd_device *, struct dasd_ccw_req *,
+ 			    struct irb *);
  
- /* Insmod parameters */
- I2C_CLIENT_INSMOD;
-diff --git a/drivers/s390/block/Makefile b/drivers/s390/block/Makefile
-index be9f22d..0a89e08 100644
---- a/drivers/s390/block/Makefile
-+++ b/drivers/s390/block/Makefile
-@@ -2,8 +2,8 @@
- # S/390 block devices
- #
++	void (*handle_unsolicited_interrupt) (struct dasd_device *,
++					      struct irb *);
++
+         /* i/o control functions. */
+-	int (*fill_geometry) (struct dasd_device *, struct hd_geometry *);
++	int (*fill_geometry) (struct dasd_block *, struct hd_geometry *);
+ 	int (*fill_info) (struct dasd_device *, struct dasd_information2_t *);
+-	int (*ioctl) (struct dasd_device *, unsigned int, void __user *);
++	int (*ioctl) (struct dasd_block *, unsigned int, void __user *);
+ };
  
--dasd_eckd_mod-objs := dasd_eckd.o dasd_3990_erp.o dasd_9343_erp.o
--dasd_fba_mod-objs  := dasd_fba.o dasd_3370_erp.o dasd_9336_erp.o
-+dasd_eckd_mod-objs := dasd_eckd.o dasd_3990_erp.o dasd_alias.o
-+dasd_fba_mod-objs  := dasd_fba.o
- dasd_diag_mod-objs := dasd_diag.o
- dasd_mod-objs      := dasd.o dasd_ioctl.o dasd_proc.o dasd_devmap.o \
- 			dasd_genhd.o dasd_erp.o
-diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
-index e6bfce6..1db15f3 100644
---- a/drivers/s390/block/dasd.c
-+++ b/drivers/s390/block/dasd.c
-@@ -48,13 +48,15 @@ MODULE_LICENSE("GPL");
+ extern struct dasd_discipline *dasd_diag_discipline_pointer;
+@@ -267,12 +290,18 @@ extern struct dasd_discipline *dasd_diag_discipline_pointer;
  /*
-  * SECTION: prototypes for static functions of dasd.c
+  * Unique identifier for dasd device.
   */
--static int  dasd_alloc_queue(struct dasd_device * device);
--static void dasd_setup_queue(struct dasd_device * device);
--static void dasd_free_queue(struct dasd_device * device);
--static void dasd_flush_request_queue(struct dasd_device *);
--static int dasd_flush_ccw_queue(struct dasd_device *, int);
--static void dasd_tasklet(struct dasd_device *);
-+static int  dasd_alloc_queue(struct dasd_block *);
-+static void dasd_setup_queue(struct dasd_block *);
-+static void dasd_free_queue(struct dasd_block *);
-+static void dasd_flush_request_queue(struct dasd_block *);
-+static int dasd_flush_block_queue(struct dasd_block *);
-+static void dasd_device_tasklet(struct dasd_device *);
-+static void dasd_block_tasklet(struct dasd_block *);
- static void do_kick_device(struct work_struct *);
-+static void dasd_return_cqr_cb(struct dasd_ccw_req *, void *);
++#define UA_NOT_CONFIGURED  0x00
++#define UA_BASE_DEVICE	   0x01
++#define UA_BASE_PAV_ALIAS  0x02
++#define UA_HYPER_PAV_ALIAS 0x03
++
+ struct dasd_uid {
+-	__u8 alias;
++	__u8 type;
+ 	char vendor[4];
+ 	char serial[15];
+ 	__u16 ssid;
+-	__u8 unit_addr;
++	__u8 real_unit_addr;
++	__u8 base_unit_addr;
+ };
  
  /*
-  * SECTION: Operations on the device structure.
-@@ -65,26 +67,23 @@ static wait_queue_head_t dasd_flush_wq;
- /*
-  * Allocate memory for a new device structure.
-  */
--struct dasd_device *
--dasd_alloc_device(void)
-+struct dasd_device *dasd_alloc_device(void)
- {
- 	struct dasd_device *device;
+@@ -293,14 +322,9 @@ struct dasd_uid {
  
--	device = kzalloc(sizeof (struct dasd_device), GFP_ATOMIC);
--	if (device == NULL)
-+	device = kzalloc(sizeof(struct dasd_device), GFP_ATOMIC);
-+	if (!device)
- 		return ERR_PTR(-ENOMEM);
--	/* open_count = 0 means device online but not in use */
--	atomic_set(&device->open_count, -1);
+ struct dasd_device {
+ 	/* Block device stuff. */
+-	struct gendisk *gdp;
+-	struct request_queue *request_queue;
+-	spinlock_t request_queue_lock;
+-	struct block_device *bdev;
++	struct dasd_block *block;
++
+         unsigned int devindex;
+-	unsigned long blocks;	   /* size of volume in blocks */
+-	unsigned int bp_block;	   /* bytes per block */
+-	unsigned int s2b_shift;	   /* log2 (bp_block/512) */
+ 	unsigned long flags;	   /* per device flags */
+ 	unsigned short features;   /* copy of devmap-features (read-only!) */
  
- 	/* Get two pages for normal block device operations. */
- 	device->ccw_mem = (void *) __get_free_pages(GFP_ATOMIC | GFP_DMA, 1);
--	if (device->ccw_mem == NULL) {
-+	if (!device->ccw_mem) {
- 		kfree(device);
- 		return ERR_PTR(-ENOMEM);
- 	}
- 	/* Get one page for error recovery. */
- 	device->erp_mem = (void *) get_zeroed_page(GFP_ATOMIC | GFP_DMA);
--	if (device->erp_mem == NULL) {
-+	if (!device->erp_mem) {
- 		free_pages((unsigned long) device->ccw_mem, 1);
- 		kfree(device);
- 		return ERR_PTR(-ENOMEM);
-@@ -93,10 +92,9 @@ dasd_alloc_device(void)
- 	dasd_init_chunklist(&device->ccw_chunks, device->ccw_mem, PAGE_SIZE*2);
- 	dasd_init_chunklist(&device->erp_chunks, device->erp_mem, PAGE_SIZE);
- 	spin_lock_init(&device->mem_lock);
--	spin_lock_init(&device->request_queue_lock);
--	atomic_set (&device->tasklet_scheduled, 0);
-+	atomic_set(&device->tasklet_scheduled, 0);
- 	tasklet_init(&device->tasklet,
--		     (void (*)(unsigned long)) dasd_tasklet,
-+		     (void (*)(unsigned long)) dasd_device_tasklet,
- 		     (unsigned long) device);
- 	INIT_LIST_HEAD(&device->ccw_queue);
- 	init_timer(&device->timer);
-@@ -110,8 +108,7 @@ dasd_alloc_device(void)
- /*
-  * Free memory of a device structure.
-  */
--void
--dasd_free_device(struct dasd_device *device)
-+void dasd_free_device(struct dasd_device *device)
- {
- 	kfree(device->private);
- 	free_page((unsigned long) device->erp_mem);
-@@ -120,10 +117,42 @@ dasd_free_device(struct dasd_device *device)
- }
+@@ -316,9 +340,8 @@ struct dasd_device {
+ 	int state, target;
+ 	int stopped;		/* device (ccw_device_start) was stopped */
  
- /*
-+ * Allocate memory for a new device structure.
-+ */
-+struct dasd_block *dasd_alloc_block(void)
-+{
-+	struct dasd_block *block;
+-	/* Open and reference count. */
++	/* reference count. */
+         atomic_t ref_count;
+-	atomic_t open_count;
+ 
+ 	/* ccw queue and memory for static ccw/erp buffers. */
+ 	struct list_head ccw_queue;
+@@ -337,20 +360,45 @@ struct dasd_device {
+ 
+ 	struct ccw_device *cdev;
+ 
++	/* hook for alias management */
++	struct list_head alias_list;
++};
 +
-+	block = kzalloc(sizeof(*block), GFP_ATOMIC);
-+	if (!block)
-+		return ERR_PTR(-ENOMEM);
-+	/* open_count = 0 means device online but not in use */
-+	atomic_set(&block->open_count, -1);
++struct dasd_block {
++	/* Block device stuff. */
++	struct gendisk *gdp;
++	struct request_queue *request_queue;
++	spinlock_t request_queue_lock;
++	struct block_device *bdev;
++	atomic_t open_count;
 +
-+	spin_lock_init(&block->request_queue_lock);
-+	atomic_set(&block->tasklet_scheduled, 0);
-+	tasklet_init(&block->tasklet,
-+		     (void (*)(unsigned long)) dasd_block_tasklet,
-+		     (unsigned long) block);
-+	INIT_LIST_HEAD(&block->ccw_queue);
-+	spin_lock_init(&block->queue_lock);
-+	init_timer(&block->timer);
++	unsigned long blocks;	   /* size of volume in blocks */
++	unsigned int bp_block;	   /* bytes per block */
++	unsigned int s2b_shift;	   /* log2 (bp_block/512) */
 +
-+	return block;
-+}
++	struct dasd_device *base;
++	struct list_head ccw_queue;
++	spinlock_t queue_lock;
 +
-+/*
-+ * Free memory of a device structure.
-+ */
-+void dasd_free_block(struct dasd_block *block)
-+{
-+	kfree(block);
-+}
++	atomic_t tasklet_scheduled;
++	struct tasklet_struct tasklet;
++	struct timer_list timer;
 +
-+/*
-  * Make a new device known to the system.
-  */
--static int
--dasd_state_new_to_known(struct dasd_device *device)
-+static int dasd_state_new_to_known(struct dasd_device *device)
- {
- 	int rc;
+ #ifdef CONFIG_DASD_PROFILE
+ 	struct dasd_profile_info_t profile;
+ #endif
+ };
  
-@@ -133,12 +162,13 @@ dasd_state_new_to_known(struct dasd_device *device)
- 	 */
- 	dasd_get_device(device);
++
++
+ /* reasons why device (ccw_device_start) was stopped */
+ #define DASD_STOPPED_NOT_ACC 1         /* not accessible */
+ #define DASD_STOPPED_QUIESCE 2         /* Quiesced */
+ #define DASD_STOPPED_PENDING 4         /* long busy */
+ #define DASD_STOPPED_DC_WAIT 8         /* disconnected, wait */
+-#define DASD_STOPPED_DC_EIO  16        /* disconnected, return -EIO */
++#define DASD_STOPPED_SU      16        /* summary unit check handling */
  
--	rc = dasd_alloc_queue(device);
--	if (rc) {
--		dasd_put_device(device);
--		return rc;
-+	if (device->block) {
-+		rc = dasd_alloc_queue(device->block);
-+		if (rc) {
-+			dasd_put_device(device);
-+			return rc;
-+		}
- 	}
--
- 	device->state = DASD_STATE_KNOWN;
- 	return 0;
- }
-@@ -146,21 +176,24 @@ dasd_state_new_to_known(struct dasd_device *device)
- /*
-  * Let the system forget about a device.
-  */
--static int
--dasd_state_known_to_new(struct dasd_device * device)
-+static int dasd_state_known_to_new(struct dasd_device *device)
- {
- 	/* Disable extended error reporting for this device. */
- 	dasd_eer_disable(device);
- 	/* Forget the discipline information. */
--	if (device->discipline)
-+	if (device->discipline) {
-+		if (device->discipline->uncheck_device)
-+			device->discipline->uncheck_device(device);
- 		module_put(device->discipline->owner);
-+	}
- 	device->discipline = NULL;
- 	if (device->base_discipline)
- 		module_put(device->base_discipline->owner);
- 	device->base_discipline = NULL;
- 	device->state = DASD_STATE_NEW;
+ /* per device flags */
+-#define DASD_FLAG_DSC_ERROR	2	/* return -EIO when disconnected */
+ #define DASD_FLAG_OFFLINE	3	/* device is in offline processing */
+ #define DASD_FLAG_EER_SNSS	4	/* A SNSS is required */
+ #define DASD_FLAG_EER_IN_USE	5	/* A SNSS request is running */
+@@ -489,6 +537,9 @@ dasd_kmalloc_set_cda(struct ccw1 *ccw, void *cda, struct dasd_device *device)
+ struct dasd_device *dasd_alloc_device(void);
+ void dasd_free_device(struct dasd_device *);
  
--	dasd_free_queue(device);
-+	if (device->block)
-+		dasd_free_queue(device->block);
++struct dasd_block *dasd_alloc_block(void);
++void dasd_free_block(struct dasd_block *);
++
+ void dasd_enable_device(struct dasd_device *);
+ void dasd_set_target_state(struct dasd_device *, int);
+ void dasd_kick_device(struct dasd_device *);
+@@ -497,18 +548,23 @@ void dasd_add_request_head(struct dasd_ccw_req *);
+ void dasd_add_request_tail(struct dasd_ccw_req *);
+ int  dasd_start_IO(struct dasd_ccw_req *);
+ int  dasd_term_IO(struct dasd_ccw_req *);
+-void dasd_schedule_bh(struct dasd_device *);
++void dasd_schedule_device_bh(struct dasd_device *);
++void dasd_schedule_block_bh(struct dasd_block *);
+ int  dasd_sleep_on(struct dasd_ccw_req *);
+ int  dasd_sleep_on_immediatly(struct dasd_ccw_req *);
+ int  dasd_sleep_on_interruptible(struct dasd_ccw_req *);
+-void dasd_set_timer(struct dasd_device *, int);
+-void dasd_clear_timer(struct dasd_device *);
++void dasd_device_set_timer(struct dasd_device *, int);
++void dasd_device_clear_timer(struct dasd_device *);
++void dasd_block_set_timer(struct dasd_block *, int);
++void dasd_block_clear_timer(struct dasd_block *);
+ int  dasd_cancel_req(struct dasd_ccw_req *);
++int dasd_flush_device_queue(struct dasd_device *);
+ int dasd_generic_probe (struct ccw_device *, struct dasd_discipline *);
+ void dasd_generic_remove (struct ccw_device *cdev);
+ int dasd_generic_set_online(struct ccw_device *, struct dasd_discipline *);
+ int dasd_generic_set_offline (struct ccw_device *cdev);
+ int dasd_generic_notify(struct ccw_device *, int);
++void dasd_generic_handle_state_change(struct dasd_device *);
  
- 	/* Give up reference we took in dasd_state_new_to_known. */
- 	dasd_put_device(device);
-@@ -170,19 +203,19 @@ dasd_state_known_to_new(struct dasd_device * device)
- /*
-  * Request the irq line for the device.
-  */
--static int
--dasd_state_known_to_basic(struct dasd_device * device)
-+static int dasd_state_known_to_basic(struct dasd_device *device)
- {
- 	int rc;
+ int dasd_generic_read_dev_chars(struct dasd_device *, char *, void **, int);
+ 
+@@ -542,10 +598,10 @@ int dasd_busid_known(char *);
+ /* externals in dasd_gendisk.c */
+ int  dasd_gendisk_init(void);
+ void dasd_gendisk_exit(void);
+-int dasd_gendisk_alloc(struct dasd_device *);
+-void dasd_gendisk_free(struct dasd_device *);
+-int dasd_scan_partitions(struct dasd_device *);
+-void dasd_destroy_partitions(struct dasd_device *);
++int dasd_gendisk_alloc(struct dasd_block *);
++void dasd_gendisk_free(struct dasd_block *);
++int dasd_scan_partitions(struct dasd_block *);
++void dasd_destroy_partitions(struct dasd_block *);
+ 
+ /* externals in dasd_ioctl.c */
+ int  dasd_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
+@@ -563,20 +619,9 @@ struct dasd_ccw_req *dasd_alloc_erp_request(char *, int, int,
+ void dasd_free_erp_request(struct dasd_ccw_req *, struct dasd_device *);
+ void dasd_log_sense(struct dasd_ccw_req *, struct irb *);
+ 
+-/* externals in dasd_3370_erp.c */
+-dasd_era_t dasd_3370_erp_examine(struct dasd_ccw_req *, struct irb *);
+-
+ /* externals in dasd_3990_erp.c */
+-dasd_era_t dasd_3990_erp_examine(struct dasd_ccw_req *, struct irb *);
+ struct dasd_ccw_req *dasd_3990_erp_action(struct dasd_ccw_req *);
  
- 	/* Allocate and register gendisk structure. */
--	rc = dasd_gendisk_alloc(device);
--	if (rc)
--		return rc;
+-/* externals in dasd_9336_erp.c */
+-dasd_era_t dasd_9336_erp_examine(struct dasd_ccw_req *, struct irb *);
 -
-+	if (device->block) {
-+		rc = dasd_gendisk_alloc(device->block);
-+		if (rc)
-+			return rc;
-+	}
- 	/* register 'device' debug area, used for all DBF_DEV_XXX calls */
--	device->debug_area = debug_register(device->cdev->dev.bus_id, 1, 2,
--					    8 * sizeof (long));
-+	device->debug_area = debug_register(device->cdev->dev.bus_id, 1, 1,
-+					    8 * sizeof(long));
- 	debug_register_view(device->debug_area, &debug_sprintf_view);
- 	debug_set_level(device->debug_area, DBF_WARNING);
- 	DBF_DEV_EVENT(DBF_EMERG, device, "%s", "debug area created");
-@@ -194,16 +227,17 @@ dasd_state_known_to_basic(struct dasd_device * device)
- /*
-  * Release the irq line for the device. Terminate any running i/o.
-  */
--static int
--dasd_state_basic_to_known(struct dasd_device * device)
-+static int dasd_state_basic_to_known(struct dasd_device *device)
- {
- 	int rc;
+-/* externals in dasd_9336_erp.c */
+-dasd_era_t dasd_9343_erp_examine(struct dasd_ccw_req *, struct irb *);
+-struct dasd_ccw_req *dasd_9343_erp_action(struct dasd_ccw_req *);
 -
--	dasd_gendisk_free(device);
--	rc = dasd_flush_ccw_queue(device, 1);
-+	if (device->block) {
-+		dasd_gendisk_free(device->block);
-+		dasd_block_clear_timer(device->block);
-+	}
-+	rc = dasd_flush_device_queue(device);
- 	if (rc)
- 		return rc;
--	dasd_clear_timer(device);
-+	dasd_device_clear_timer(device);
- 
- 	DBF_DEV_EVENT(DBF_EMERG, device, "%p debug area deleted", device);
- 	if (device->debug_area != NULL) {
-@@ -228,26 +262,32 @@ dasd_state_basic_to_known(struct dasd_device * device)
-  * In case the analysis returns an error, the device setup is stopped
-  * (a fake disk was already added to allow formatting).
-  */
--static int
--dasd_state_basic_to_ready(struct dasd_device * device)
-+static int dasd_state_basic_to_ready(struct dasd_device *device)
+ /* externals in dasd_eer.c */
+ #ifdef CONFIG_DASD_EER
+ int dasd_eer_init(void);
+diff --git a/drivers/s390/block/dasd_ioctl.c b/drivers/s390/block/dasd_ioctl.c
+index 672eb0a..91a6463 100644
+--- a/drivers/s390/block/dasd_ioctl.c
++++ b/drivers/s390/block/dasd_ioctl.c
+@@ -38,15 +38,15 @@ dasd_ioctl_api_version(void __user *argp)
+ static int
+ dasd_ioctl_enable(struct block_device *bdev)
  {
- 	int rc;
-+	struct dasd_block *block;
- 
- 	rc = 0;
--	if (device->discipline->do_analysis != NULL)
--		rc = device->discipline->do_analysis(device);
--	if (rc) {
--		if (rc != -EAGAIN)
--			device->state = DASD_STATE_UNFMT;
--		return rc;
--	}
-+	block = device->block;
- 	/* make disk known with correct capacity */
--	dasd_setup_queue(device);
--	set_capacity(device->gdp, device->blocks << device->s2b_shift);
--	device->state = DASD_STATE_READY;
--	rc = dasd_scan_partitions(device);
--	if (rc)
--		device->state = DASD_STATE_BASIC;
-+	if (block) {
-+		if (block->base->discipline->do_analysis != NULL)
-+			rc = block->base->discipline->do_analysis(block);
-+		if (rc) {
-+			if (rc != -EAGAIN)
-+				device->state = DASD_STATE_UNFMT;
-+			return rc;
-+		}
-+		dasd_setup_queue(block);
-+		set_capacity(block->gdp,
-+			     block->blocks << block->s2b_shift);
-+		device->state = DASD_STATE_READY;
-+		rc = dasd_scan_partitions(block);
-+		if (rc)
-+			device->state = DASD_STATE_BASIC;
-+	} else {
-+		device->state = DASD_STATE_READY;
-+	}
- 	return rc;
- }
+-	struct dasd_device *device = bdev->bd_disk->private_data;
++	struct dasd_block *block = bdev->bd_disk->private_data;
  
-@@ -256,28 +296,31 @@ dasd_state_basic_to_ready(struct dasd_device * device)
-  * Forget format information. Check if the target level is basic
-  * and if it is create fake disk for formatting.
-  */
--static int
--dasd_state_ready_to_basic(struct dasd_device * device)
-+static int dasd_state_ready_to_basic(struct dasd_device *device)
- {
- 	int rc;
+ 	if (!capable(CAP_SYS_ADMIN))
+ 		return -EACCES;
  
--	rc = dasd_flush_ccw_queue(device, 0);
--	if (rc)
--		return rc;
--	dasd_destroy_partitions(device);
--	dasd_flush_request_queue(device);
--	device->blocks = 0;
--	device->bp_block = 0;
--	device->s2b_shift = 0;
- 	device->state = DASD_STATE_BASIC;
-+	if (device->block) {
-+		struct dasd_block *block = device->block;
-+		rc = dasd_flush_block_queue(block);
-+		if (rc) {
-+			device->state = DASD_STATE_READY;
-+			return rc;
-+		}
-+		dasd_destroy_partitions(block);
-+		dasd_flush_request_queue(block);
-+		block->blocks = 0;
-+		block->bp_block = 0;
-+		block->s2b_shift = 0;
-+	}
+-	dasd_enable_device(device);
++	dasd_enable_device(block->base);
+ 	/* Formatting the dasd device can change the capacity. */
+ 	mutex_lock(&bdev->bd_mutex);
+-	i_size_write(bdev->bd_inode, (loff_t)get_capacity(device->gdp) << 9);
++	i_size_write(bdev->bd_inode, (loff_t)get_capacity(block->gdp) << 9);
+ 	mutex_unlock(&bdev->bd_mutex);
  	return 0;
  }
+@@ -58,7 +58,7 @@ dasd_ioctl_enable(struct block_device *bdev)
+ static int
+ dasd_ioctl_disable(struct block_device *bdev)
+ {
+-	struct dasd_device *device = bdev->bd_disk->private_data;
++	struct dasd_block *block = bdev->bd_disk->private_data;
  
+ 	if (!capable(CAP_SYS_ADMIN))
+ 		return -EACCES;
+@@ -71,7 +71,7 @@ dasd_ioctl_disable(struct block_device *bdev)
+ 	 * using the BIODASDFMT ioctl. Therefore the correct state for the
+ 	 * device is DASD_STATE_BASIC that allows to do basic i/o.
+ 	 */
+-	dasd_set_target_state(device, DASD_STATE_BASIC);
++	dasd_set_target_state(block->base, DASD_STATE_BASIC);
+ 	/*
+ 	 * Set i_size to zero, since read, write, etc. check against this
+ 	 * value.
+@@ -85,19 +85,19 @@ dasd_ioctl_disable(struct block_device *bdev)
  /*
-  * Back to basic.
+  * Quiesce device.
   */
 -static int
--dasd_state_unfmt_to_basic(struct dasd_device * device)
-+static int dasd_state_unfmt_to_basic(struct dasd_device *device)
- {
- 	device->state = DASD_STATE_BASIC;
- 	return 0;
-@@ -291,17 +334,31 @@ dasd_state_unfmt_to_basic(struct dasd_device * device)
- static int
- dasd_state_ready_to_online(struct dasd_device * device)
+-dasd_ioctl_quiesce(struct dasd_device *device)
++static int dasd_ioctl_quiesce(struct dasd_block *block)
  {
-+	int rc;
-+
-+	if (device->discipline->ready_to_online) {
-+		rc = device->discipline->ready_to_online(device);
-+		if (rc)
-+			return rc;
-+	}
- 	device->state = DASD_STATE_ONLINE;
--	dasd_schedule_bh(device);
-+	if (device->block)
-+		dasd_schedule_block_bh(device->block);
+ 	unsigned long flags;
++	struct dasd_device *base;
+ 
++	base = block->base;
+ 	if (!capable (CAP_SYS_ADMIN))
+ 		return -EACCES;
+ 
+-	DEV_MESSAGE (KERN_DEBUG, device, "%s",
+-		     "Quiesce IO on device");
+-	spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
+-	device->stopped |= DASD_STOPPED_QUIESCE;
+-	spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
++	DEV_MESSAGE(KERN_DEBUG, base, "%s", "Quiesce IO on device");
++	spin_lock_irqsave(get_ccwdev_lock(base->cdev), flags);
++	base->stopped |= DASD_STOPPED_QUIESCE;
++	spin_unlock_irqrestore(get_ccwdev_lock(base->cdev), flags);
  	return 0;
  }
  
+@@ -105,22 +105,21 @@ dasd_ioctl_quiesce(struct dasd_device *device)
  /*
-  * Stop the requeueing of requests again.
+  * Quiesce device.
   */
 -static int
--dasd_state_online_to_ready(struct dasd_device * device)
-+static int dasd_state_online_to_ready(struct dasd_device *device)
+-dasd_ioctl_resume(struct dasd_device *device)
++static int dasd_ioctl_resume(struct dasd_block *block)
  {
-+	int rc;
-+
-+	if (device->discipline->online_to_ready) {
-+		rc = device->discipline->online_to_ready(device);
-+		if (rc)
-+			return rc;
-+	}
- 	device->state = DASD_STATE_READY;
+ 	unsigned long flags;
++	struct dasd_device *base;
+ 
++	base = block->base;
+ 	if (!capable (CAP_SYS_ADMIN))
+ 		return -EACCES;
+ 
+-	DEV_MESSAGE (KERN_DEBUG, device, "%s",
+-		     "resume IO on device");
+-
+-	spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
+-	device->stopped &= ~DASD_STOPPED_QUIESCE;
+-	spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
++	DEV_MESSAGE(KERN_DEBUG, base, "%s", "resume IO on device");
++	spin_lock_irqsave(get_ccwdev_lock(base->cdev), flags);
++	base->stopped &= ~DASD_STOPPED_QUIESCE;
++	spin_unlock_irqrestore(get_ccwdev_lock(base->cdev), flags);
+ 
+-	dasd_schedule_bh (device);
++	dasd_schedule_block_bh(block);
  	return 0;
  }
-@@ -309,8 +366,7 @@ dasd_state_online_to_ready(struct dasd_device * device)
- /*
-  * Device startup state changes.
-  */
--static int
--dasd_increase_state(struct dasd_device *device)
-+static int dasd_increase_state(struct dasd_device *device)
- {
- 	int rc;
  
-@@ -345,8 +401,7 @@ dasd_increase_state(struct dasd_device *device)
- /*
-  * Device shutdown state changes.
+@@ -130,22 +129,23 @@ dasd_ioctl_resume(struct dasd_device *device)
+  * commands to format a single unit of the device. In terms of the ECKD
+  * devices this means CCWs are generated to format a single track.
   */
 -static int
--dasd_decrease_state(struct dasd_device *device)
-+static int dasd_decrease_state(struct dasd_device *device)
+-dasd_format(struct dasd_device * device, struct format_data_t * fdata)
++static int dasd_format(struct dasd_block *block, struct format_data_t *fdata)
  {
+ 	struct dasd_ccw_req *cqr;
++	struct dasd_device *base;
  	int rc;
  
-@@ -381,8 +436,7 @@ dasd_decrease_state(struct dasd_device *device)
- /*
-  * This is the main startup/shutdown routine.
-  */
--static void
--dasd_change_state(struct dasd_device *device)
-+static void dasd_change_state(struct dasd_device *device)
- {
-         int rc;
+-	if (device->discipline->format_device == NULL)
++	base = block->base;
++	if (base->discipline->format_device == NULL)
+ 		return -EPERM;
  
-@@ -409,17 +463,15 @@ dasd_change_state(struct dasd_device *device)
-  * dasd_kick_device will schedule a call do do_kick_device to the kernel
-  * event daemon.
-  */
--static void
--do_kick_device(struct work_struct *work)
-+static void do_kick_device(struct work_struct *work)
- {
- 	struct dasd_device *device = container_of(work, struct dasd_device, kick_work);
- 	dasd_change_state(device);
--	dasd_schedule_bh(device);
-+	dasd_schedule_device_bh(device);
- 	dasd_put_device(device);
- }
+-	if (device->state != DASD_STATE_BASIC) {
+-		DEV_MESSAGE(KERN_WARNING, device, "%s",
++	if (base->state != DASD_STATE_BASIC) {
++		DEV_MESSAGE(KERN_WARNING, base, "%s",
+ 			    "dasd_format: device is not disabled! ");
+ 		return -EBUSY;
+ 	}
  
--void
--dasd_kick_device(struct dasd_device *device)
-+void dasd_kick_device(struct dasd_device *device)
- {
- 	dasd_get_device(device);
- 	/* queue call to dasd_kick_device to the kernel event daemon. */
-@@ -429,8 +481,7 @@ dasd_kick_device(struct dasd_device *device)
- /*
-  * Set the target state for a device and starts the state change.
-  */
--void
--dasd_set_target_state(struct dasd_device *device, int target)
-+void dasd_set_target_state(struct dasd_device *device, int target)
- {
- 	/* If we are in probeonly mode stop at DASD_STATE_READY. */
- 	if (dasd_probeonly && target > DASD_STATE_READY)
-@@ -447,14 +498,12 @@ dasd_set_target_state(struct dasd_device *device, int target)
- /*
-  * Enable devices with device numbers in [from..to].
-  */
--static inline int
--_wait_for_device(struct dasd_device *device)
-+static inline int _wait_for_device(struct dasd_device *device)
- {
- 	return (device->state == device->target);
- }
+-	DBF_DEV_EVENT(DBF_NOTICE, device,
++	DBF_DEV_EVENT(DBF_NOTICE, base,
+ 		      "formatting units %d to %d (%d B blocks) flags %d",
+ 		      fdata->start_unit,
+ 		      fdata->stop_unit, fdata->blksize, fdata->intensity);
+@@ -156,20 +156,20 @@ dasd_format(struct dasd_device * device, struct format_data_t * fdata)
+ 	 * enabling the device later.
+ 	 */
+ 	if (fdata->start_unit == 0) {
+-		struct block_device *bdev = bdget_disk(device->gdp, 0);
++		struct block_device *bdev = bdget_disk(block->gdp, 0);
+ 		bdev->bd_inode->i_blkbits = blksize_bits(fdata->blksize);
+ 		bdput(bdev);
+ 	}
  
--void
--dasd_enable_device(struct dasd_device *device)
-+void dasd_enable_device(struct dasd_device *device)
+ 	while (fdata->start_unit <= fdata->stop_unit) {
+-		cqr = device->discipline->format_device(device, fdata);
++		cqr = base->discipline->format_device(base, fdata);
+ 		if (IS_ERR(cqr))
+ 			return PTR_ERR(cqr);
+ 		rc = dasd_sleep_on_interruptible(cqr);
+-		dasd_sfree_request(cqr, cqr->device);
++		dasd_sfree_request(cqr, cqr->memdev);
+ 		if (rc) {
+ 			if (rc != -ERESTARTSYS)
+-				DEV_MESSAGE(KERN_ERR, device,
++				DEV_MESSAGE(KERN_ERR, base,
+ 					    " Formatting of unit %d failed "
+ 					    "with rc = %d",
+ 					    fdata->start_unit, rc);
+@@ -186,7 +186,7 @@ dasd_format(struct dasd_device * device, struct format_data_t * fdata)
+ static int
+ dasd_ioctl_format(struct block_device *bdev, void __user *argp)
  {
- 	dasd_set_target_state(device, DASD_STATE_ONLINE);
- 	if (device->state <= DASD_STATE_KNOWN)
-@@ -475,20 +524,20 @@ unsigned int dasd_profile_level = DASD_PROFILE_OFF;
- /*
-  * Increments counter in global and local profiling structures.
-  */
--#define dasd_profile_counter(value, counter, device) \
-+#define dasd_profile_counter(value, counter, block) \
- { \
- 	int index; \
- 	for (index = 0; index < 31 && value >> (2+index); index++); \
- 	dasd_global_profile.counter[index]++; \
--	device->profile.counter[index]++; \
-+	block->profile.counter[index]++; \
- }
+-	struct dasd_device *device = bdev->bd_disk->private_data;
++	struct dasd_block *block = bdev->bd_disk->private_data;
+ 	struct format_data_t fdata;
  
- /*
-  * Add profiling information for cqr before execution.
-  */
--static void
--dasd_profile_start(struct dasd_device *device, struct dasd_ccw_req * cqr,
--		   struct request *req)
-+static void dasd_profile_start(struct dasd_block *block,
-+			       struct dasd_ccw_req *cqr,
-+			       struct request *req)
- {
- 	struct list_head *l;
- 	unsigned int counter;
-@@ -498,19 +547,19 @@ dasd_profile_start(struct dasd_device *device, struct dasd_ccw_req * cqr,
+ 	if (!capable(CAP_SYS_ADMIN))
+@@ -194,51 +194,47 @@ dasd_ioctl_format(struct block_device *bdev, void __user *argp)
+ 	if (!argp)
+ 		return -EINVAL;
  
- 	/* count the length of the chanq for statistics */
- 	counter = 0;
--	list_for_each(l, &device->ccw_queue)
-+	list_for_each(l, &block->ccw_queue)
- 		if (++counter >= 31)
- 			break;
- 	dasd_global_profile.dasd_io_nr_req[counter]++;
--	device->profile.dasd_io_nr_req[counter]++;
-+	block->profile.dasd_io_nr_req[counter]++;
+-	if (device->features & DASD_FEATURE_READONLY)
++	if (block->base->features & DASD_FEATURE_READONLY)
+ 		return -EROFS;
+ 	if (copy_from_user(&fdata, argp, sizeof(struct format_data_t)))
+ 		return -EFAULT;
+ 	if (bdev != bdev->bd_contains) {
+-		DEV_MESSAGE(KERN_WARNING, device, "%s",
++		DEV_MESSAGE(KERN_WARNING, block->base, "%s",
+ 			    "Cannot low-level format a partition");
+ 		return -EINVAL;
+ 	}
+-	return dasd_format(device, &fdata);
++	return dasd_format(block, &fdata);
  }
  
+ #ifdef CONFIG_DASD_PROFILE
  /*
-  * Add profiling information for cqr after execution.
+  * Reset device profile information
   */
--static void
--dasd_profile_end(struct dasd_device *device, struct dasd_ccw_req * cqr,
--		 struct request *req)
-+static void dasd_profile_end(struct dasd_block *block,
-+			     struct dasd_ccw_req *cqr,
-+			     struct request *req)
+-static int
+-dasd_ioctl_reset_profile(struct dasd_device *device)
++static int dasd_ioctl_reset_profile(struct dasd_block *block)
  {
- 	long strtime, irqtime, endtime, tottime;	/* in microseconds */
- 	long tottimeps, sectors;
-@@ -532,27 +581,27 @@ dasd_profile_end(struct dasd_device *device, struct dasd_ccw_req * cqr,
- 
- 	if (!dasd_global_profile.dasd_io_reqs)
- 		memset(&dasd_global_profile, 0,
--		       sizeof (struct dasd_profile_info_t));
-+		       sizeof(struct dasd_profile_info_t));
- 	dasd_global_profile.dasd_io_reqs++;
- 	dasd_global_profile.dasd_io_sects += sectors;
- 
--	if (!device->profile.dasd_io_reqs)
--		memset(&device->profile, 0,
--		       sizeof (struct dasd_profile_info_t));
--	device->profile.dasd_io_reqs++;
--	device->profile.dasd_io_sects += sectors;
-+	if (!block->profile.dasd_io_reqs)
-+		memset(&block->profile, 0,
-+		       sizeof(struct dasd_profile_info_t));
-+	block->profile.dasd_io_reqs++;
-+	block->profile.dasd_io_sects += sectors;
- 
--	dasd_profile_counter(sectors, dasd_io_secs, device);
--	dasd_profile_counter(tottime, dasd_io_times, device);
--	dasd_profile_counter(tottimeps, dasd_io_timps, device);
--	dasd_profile_counter(strtime, dasd_io_time1, device);
--	dasd_profile_counter(irqtime, dasd_io_time2, device);
--	dasd_profile_counter(irqtime / sectors, dasd_io_time2ps, device);
--	dasd_profile_counter(endtime, dasd_io_time3, device);
-+	dasd_profile_counter(sectors, dasd_io_secs, block);
-+	dasd_profile_counter(tottime, dasd_io_times, block);
-+	dasd_profile_counter(tottimeps, dasd_io_timps, block);
-+	dasd_profile_counter(strtime, dasd_io_time1, block);
-+	dasd_profile_counter(irqtime, dasd_io_time2, block);
-+	dasd_profile_counter(irqtime / sectors, dasd_io_time2ps, block);
-+	dasd_profile_counter(endtime, dasd_io_time3, block);
+-	memset(&device->profile, 0, sizeof (struct dasd_profile_info_t));
++	memset(&block->profile, 0, sizeof(struct dasd_profile_info_t));
+ 	return 0;
  }
- #else
--#define dasd_profile_start(device, cqr, req) do {} while (0)
--#define dasd_profile_end(device, cqr, req) do {} while (0)
-+#define dasd_profile_start(block, cqr, req) do {} while (0)
-+#define dasd_profile_end(block, cqr, req) do {} while (0)
- #endif				/* CONFIG_DASD_PROFILE */
  
  /*
-@@ -562,9 +611,9 @@ dasd_profile_end(struct dasd_device *device, struct dasd_ccw_req * cqr,
-  * memory and 2) dasd_smalloc_request uses the static ccw memory
-  * that gets allocated for each device.
+  * Return device profile information
   */
--struct dasd_ccw_req *
--dasd_kmalloc_request(char *magic, int cplength, int datasize,
--		   struct dasd_device * device)
-+struct dasd_ccw_req *dasd_kmalloc_request(char *magic, int cplength,
-+					  int datasize,
-+					  struct dasd_device *device)
+-static int
+-dasd_ioctl_read_profile(struct dasd_device *device, void __user *argp)
++static int dasd_ioctl_read_profile(struct dasd_block *block, void __user *argp)
  {
- 	struct dasd_ccw_req *cqr;
- 
-@@ -600,9 +649,9 @@ dasd_kmalloc_request(char *magic, int cplength, int datasize,
- 	return cqr;
+ 	if (dasd_profile_level == DASD_PROFILE_OFF)
+ 		return -EIO;
+-	if (copy_to_user(argp, &device->profile,
+-			 sizeof (struct dasd_profile_info_t)))
++	if (copy_to_user(argp, &block->profile,
++			 sizeof(struct dasd_profile_info_t)))
+ 		return -EFAULT;
+ 	return 0;
  }
- 
--struct dasd_ccw_req *
--dasd_smalloc_request(char *magic, int cplength, int datasize,
--		   struct dasd_device * device)
-+struct dasd_ccw_req *dasd_smalloc_request(char *magic, int cplength,
-+					  int datasize,
-+					  struct dasd_device *device)
- {
- 	unsigned long flags;
- 	struct dasd_ccw_req *cqr;
-@@ -649,8 +698,7 @@ dasd_smalloc_request(char *magic, int cplength, int datasize,
-  * idal lists that might have been created by dasd_set_cda and the
-  * struct dasd_ccw_req itself.
-  */
--void
--dasd_kfree_request(struct dasd_ccw_req * cqr, struct dasd_device * device)
-+void dasd_kfree_request(struct dasd_ccw_req *cqr, struct dasd_device *device)
+ #else
+-static int
+-dasd_ioctl_reset_profile(struct dasd_device *device)
++static int dasd_ioctl_reset_profile(struct dasd_block *block)
  {
- #ifdef CONFIG_64BIT
- 	struct ccw1 *ccw;
-@@ -667,8 +715,7 @@ dasd_kfree_request(struct dasd_ccw_req * cqr, struct dasd_device * device)
- 	dasd_put_device(device);
+ 	return -ENOSYS;
  }
  
--void
--dasd_sfree_request(struct dasd_ccw_req * cqr, struct dasd_device * device)
-+void dasd_sfree_request(struct dasd_ccw_req *cqr, struct dasd_device *device)
+-static int
+-dasd_ioctl_read_profile(struct dasd_device *device, void __user *argp)
++static int dasd_ioctl_read_profile(struct dasd_block *block, void __user *argp)
  {
- 	unsigned long flags;
- 
-@@ -681,14 +728,13 @@ dasd_sfree_request(struct dasd_ccw_req * cqr, struct dasd_device * device)
+ 	return -ENOSYS;
+ }
+@@ -247,87 +243,88 @@ dasd_ioctl_read_profile(struct dasd_device *device, void __user *argp)
  /*
-  * Check discipline magic in cqr.
+  * Return dasd information. Used for BIODASDINFO and BIODASDINFO2.
   */
--static inline int
--dasd_check_cqr(struct dasd_ccw_req *cqr)
-+static inline int dasd_check_cqr(struct dasd_ccw_req *cqr)
+-static int
+-dasd_ioctl_information(struct dasd_device *device,
+-		unsigned int cmd, void __user *argp)
++static int dasd_ioctl_information(struct dasd_block *block,
++				  unsigned int cmd, void __user *argp)
  {
- 	struct dasd_device *device;
+ 	struct dasd_information2_t *dasd_info;
+ 	unsigned long flags;
+ 	int rc;
++	struct dasd_device *base;
+ 	struct ccw_device *cdev;
+ 	struct ccw_dev_id dev_id;
  
- 	if (cqr == NULL)
+-	if (!device->discipline->fill_info)
++	base = block->base;
++	if (!base->discipline->fill_info)
  		return -EINVAL;
--	device = cqr->device;
-+	device = cqr->startdev;
- 	if (strncmp((char *) &cqr->magic, device->discipline->ebcname, 4)) {
- 		DEV_MESSAGE(KERN_WARNING, device,
- 			    " dasd_ccw_req 0x%08x magic doesn't match"
-@@ -706,8 +752,7 @@ dasd_check_cqr(struct dasd_ccw_req *cqr)
-  * ccw_device_clear can fail if the i/o subsystem
-  * is in a bad mood.
-  */
--int
--dasd_term_IO(struct dasd_ccw_req * cqr)
-+int dasd_term_IO(struct dasd_ccw_req *cqr)
- {
- 	struct dasd_device *device;
- 	int retries, rc;
-@@ -717,13 +762,13 @@ dasd_term_IO(struct dasd_ccw_req * cqr)
- 	if (rc)
- 		return rc;
- 	retries = 0;
--	device = (struct dasd_device *) cqr->device;
-+	device = (struct dasd_device *) cqr->startdev;
- 	while ((retries < 5) && (cqr->status == DASD_CQR_IN_IO)) {
- 		rc = ccw_device_clear(device->cdev, (long) cqr);
- 		switch (rc) {
- 		case 0:	/* termination successful */
- 			cqr->retries--;
--			cqr->status = DASD_CQR_CLEAR;
-+			cqr->status = DASD_CQR_CLEAR_PENDING;
- 			cqr->stopclk = get_clock();
- 			cqr->starttime = 0;
- 			DBF_DEV_EVENT(DBF_DEBUG, device,
-@@ -753,7 +798,7 @@ dasd_term_IO(struct dasd_ccw_req * cqr)
- 		}
- 		retries++;
- 	}
--	dasd_schedule_bh(device);
-+	dasd_schedule_device_bh(device);
- 	return rc;
- }
  
-@@ -761,8 +806,7 @@ dasd_term_IO(struct dasd_ccw_req * cqr)
-  * Start the i/o. This start_IO can fail if the channel is really busy.
-  * In that case set up a timer to start the request later.
-  */
--int
--dasd_start_IO(struct dasd_ccw_req * cqr)
-+int dasd_start_IO(struct dasd_ccw_req *cqr)
- {
- 	struct dasd_device *device;
- 	int rc;
-@@ -771,12 +815,12 @@ dasd_start_IO(struct dasd_ccw_req * cqr)
- 	rc = dasd_check_cqr(cqr);
- 	if (rc)
+ 	dasd_info = kzalloc(sizeof(struct dasd_information2_t), GFP_KERNEL);
+ 	if (dasd_info == NULL)
+ 		return -ENOMEM;
+ 
+-	rc = device->discipline->fill_info(device, dasd_info);
++	rc = base->discipline->fill_info(base, dasd_info);
+ 	if (rc) {
+ 		kfree(dasd_info);
  		return rc;
--	device = (struct dasd_device *) cqr->device;
-+	device = (struct dasd_device *) cqr->startdev;
- 	if (cqr->retries < 0) {
- 		DEV_MESSAGE(KERN_DEBUG, device,
- 			    "start_IO: request %p (%02x/%i) - no retry left.",
- 			    cqr, cqr->status, cqr->retries);
--		cqr->status = DASD_CQR_FAILED;
-+		cqr->status = DASD_CQR_ERROR;
- 		return -EIO;
  	}
- 	cqr->startclk = get_clock();
-@@ -833,8 +877,7 @@ dasd_start_IO(struct dasd_ccw_req * cqr)
-  * The head of the ccw queue will have status DASD_CQR_IN_IO for 1),
-  * DASD_CQR_QUEUED for 2) and 3).
-  */
--static void
--dasd_timeout_device(unsigned long ptr)
-+static void dasd_device_timeout(unsigned long ptr)
- {
- 	unsigned long flags;
- 	struct dasd_device *device;
-@@ -844,14 +887,13 @@ dasd_timeout_device(unsigned long ptr)
- 	/* re-activate request queue */
-         device->stopped &= ~DASD_STOPPED_PENDING;
- 	spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
--	dasd_schedule_bh(device);
-+	dasd_schedule_device_bh(device);
- }
  
- /*
-  * Setup timeout for a device in jiffies.
-  */
--void
--dasd_set_timer(struct dasd_device *device, int expires)
-+void dasd_device_set_timer(struct dasd_device *device, int expires)
- {
- 	if (expires == 0) {
- 		if (timer_pending(&device->timer))
-@@ -862,7 +904,7 @@ dasd_set_timer(struct dasd_device *device, int expires)
- 		if (mod_timer(&device->timer, jiffies + expires))
- 			return;
- 	}
--	device->timer.function = dasd_timeout_device;
-+	device->timer.function = dasd_device_timeout;
- 	device->timer.data = (unsigned long) device;
- 	device->timer.expires = jiffies + expires;
- 	add_timer(&device->timer);
-@@ -871,15 +913,14 @@ dasd_set_timer(struct dasd_device *device, int expires)
- /*
-  * Clear timeout for a device.
-  */
--void
--dasd_clear_timer(struct dasd_device *device)
-+void dasd_device_clear_timer(struct dasd_device *device)
- {
- 	if (timer_pending(&device->timer))
- 		del_timer(&device->timer);
- }
+-	cdev = device->cdev;
++	cdev = base->cdev;
+ 	ccw_device_get_id(cdev, &dev_id);
  
--static void
--dasd_handle_killed_request(struct ccw_device *cdev, unsigned long intparm)
-+static void dasd_handle_killed_request(struct ccw_device *cdev,
-+				       unsigned long intparm)
- {
- 	struct dasd_ccw_req *cqr;
- 	struct dasd_device *device;
-@@ -893,7 +934,7 @@ dasd_handle_killed_request(struct ccw_device *cdev, unsigned long intparm)
- 		return;
- 	}
+ 	dasd_info->devno = dev_id.devno;
+-	dasd_info->schid = _ccw_device_get_subchannel_number(device->cdev);
++	dasd_info->schid = _ccw_device_get_subchannel_number(base->cdev);
+ 	dasd_info->cu_type = cdev->id.cu_type;
+ 	dasd_info->cu_model = cdev->id.cu_model;
+ 	dasd_info->dev_type = cdev->id.dev_type;
+ 	dasd_info->dev_model = cdev->id.dev_model;
+-	dasd_info->status = device->state;
++	dasd_info->status = base->state;
+ 	/*
+ 	 * The open_count is increased for every opener, that includes
+ 	 * the blkdev_get in dasd_scan_partitions.
+ 	 * This must be hidden from user-space.
+ 	 */
+-	dasd_info->open_count = atomic_read(&device->open_count);
+-	if (!device->bdev)
++	dasd_info->open_count = atomic_read(&block->open_count);
++	if (!block->bdev)
+ 		dasd_info->open_count++;
  
--	device = (struct dasd_device *) cqr->device;
-+	device = (struct dasd_device *) cqr->startdev;
- 	if (device == NULL ||
- 	    device != dasd_device_from_cdev_locked(cdev) ||
- 	    strncmp(device->discipline->ebcname, (char *) &cqr->magic, 4)) {
-@@ -905,46 +946,32 @@ dasd_handle_killed_request(struct ccw_device *cdev, unsigned long intparm)
- 	/* Schedule request to be retried. */
- 	cqr->status = DASD_CQR_QUEUED;
+ 	/*
+ 	 * check if device is really formatted
+ 	 * LDL / CDL was returned by 'fill_info'
+ 	 */
+-	if ((device->state < DASD_STATE_READY) ||
+-	    (dasd_check_blocksize(device->bp_block)))
++	if ((base->state < DASD_STATE_READY) ||
++	    (dasd_check_blocksize(block->bp_block)))
+ 		dasd_info->format = DASD_FORMAT_NONE;
  
--	dasd_clear_timer(device);
--	dasd_schedule_bh(device);
-+	dasd_device_clear_timer(device);
-+	dasd_schedule_device_bh(device);
- 	dasd_put_device(device);
- }
+ 	dasd_info->features |=
+-		((device->features & DASD_FEATURE_READONLY) != 0);
++		((base->features & DASD_FEATURE_READONLY) != 0);
  
--static void
--dasd_handle_state_change_pending(struct dasd_device *device)
-+void dasd_generic_handle_state_change(struct dasd_device *device)
- {
--	struct dasd_ccw_req *cqr;
--	struct list_head *l, *n;
--
- 	/* First of all start sense subsystem status request. */
- 	dasd_eer_snss(device);
+-	if (device->discipline)
+-		memcpy(dasd_info->type, device->discipline->name, 4);
++	if (base->discipline)
++		memcpy(dasd_info->type, base->discipline->name, 4);
+ 	else
+ 		memcpy(dasd_info->type, "none", 4);
  
- 	device->stopped &= ~DASD_STOPPED_PENDING;
--
--        /* restart all 'running' IO on queue */
--	list_for_each_safe(l, n, &device->ccw_queue) {
--		cqr = list_entry(l, struct dasd_ccw_req, list);
--                if (cqr->status == DASD_CQR_IN_IO) {
--                        cqr->status = DASD_CQR_QUEUED;
--		}
--        }
--	dasd_clear_timer(device);
--	dasd_schedule_bh(device);
-+	dasd_schedule_device_bh(device);
-+	if (device->block)
-+		dasd_schedule_block_bh(device->block);
- }
+-	if (device->request_queue->request_fn) {
++	if (block->request_queue->request_fn) {
+ 		struct list_head *l;
+ #ifdef DASD_EXTENDED_PROFILING
+ 		{
+ 			struct list_head *l;
+-			spin_lock_irqsave(&device->lock, flags);
+-			list_for_each(l, &device->request_queue->queue_head)
++			spin_lock_irqsave(&block->lock, flags);
++			list_for_each(l, &block->request_queue->queue_head)
+ 				dasd_info->req_queue_len++;
+-			spin_unlock_irqrestore(&device->lock, flags);
++			spin_unlock_irqrestore(&block->lock, flags);
+ 		}
+ #endif				/* DASD_EXTENDED_PROFILING */
+-		spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
+-		list_for_each(l, &device->ccw_queue)
++		spin_lock_irqsave(get_ccwdev_lock(base->cdev), flags);
++		list_for_each(l, &base->ccw_queue)
+ 			dasd_info->chanq_len++;
+-		spin_unlock_irqrestore(get_ccwdev_lock(device->cdev),
++		spin_unlock_irqrestore(get_ccwdev_lock(base->cdev),
+ 				       flags);
+ 	}
  
- /*
-  * Interrupt handler for "normal" ssch-io based dasd devices.
-  */
--void
--dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
--		 struct irb *irb)
-+void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
-+		      struct irb *irb)
+ 	rc = 0;
+ 	if (copy_to_user(argp, dasd_info,
+ 			 ((cmd == (unsigned int) BIODASDINFO2) ?
+-			  sizeof (struct dasd_information2_t) :
+-			  sizeof (struct dasd_information_t))))
++			  sizeof(struct dasd_information2_t) :
++			  sizeof(struct dasd_information_t))))
+ 		rc = -EFAULT;
+ 	kfree(dasd_info);
+ 	return rc;
+@@ -339,7 +336,7 @@ dasd_ioctl_information(struct dasd_device *device,
+ static int
+ dasd_ioctl_set_ro(struct block_device *bdev, void __user *argp)
  {
- 	struct dasd_ccw_req *cqr, *next;
- 	struct dasd_device *device;
- 	unsigned long long now;
- 	int expires;
--	dasd_era_t era;
--	char mask;
+-	struct dasd_device *device =  bdev->bd_disk->private_data;
++	struct dasd_block *block =  bdev->bd_disk->private_data;
+ 	int intval;
  
- 	if (IS_ERR(irb)) {
- 		switch (PTR_ERR(irb)) {
-@@ -969,29 +996,25 @@ dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
- 		  cdev->dev.bus_id, ((irb->scsw.cstat<<8)|irb->scsw.dstat),
- 		  (unsigned int) intparm);
+ 	if (!capable(CAP_SYS_ADMIN))
+@@ -351,11 +348,10 @@ dasd_ioctl_set_ro(struct block_device *bdev, void __user *argp)
+ 		return -EFAULT;
  
--	/* first of all check for state change pending interrupt */
--	mask = DEV_STAT_ATTENTION | DEV_STAT_DEV_END | DEV_STAT_UNIT_EXCEP;
--	if ((irb->scsw.dstat & mask) == mask) {
-+	/* check for unsolicited interrupts */
-+	cqr = (struct dasd_ccw_req *) intparm;
-+	if (!cqr || ((irb->scsw.cc == 1) &&
-+		     (irb->scsw.fctl & SCSW_FCTL_START_FUNC) &&
-+		     (irb->scsw.stctl & SCSW_STCTL_STATUS_PEND)) ) {
-+		if (cqr && cqr->status == DASD_CQR_IN_IO)
-+			cqr->status = DASD_CQR_QUEUED;
- 		device = dasd_device_from_cdev_locked(cdev);
- 		if (!IS_ERR(device)) {
--			dasd_handle_state_change_pending(device);
-+			dasd_device_clear_timer(device);
-+			device->discipline->handle_unsolicited_interrupt(device,
-+									 irb);
- 			dasd_put_device(device);
- 		}
- 		return;
- 	}
+ 	set_disk_ro(bdev->bd_disk, intval);
+-	return dasd_set_feature(device->cdev, DASD_FEATURE_READONLY, intval);
++	return dasd_set_feature(block->base->cdev, DASD_FEATURE_READONLY, intval);
+ }
  
--	cqr = (struct dasd_ccw_req *) intparm;
--
--	/* check for unsolicited interrupts */
--	if (cqr == NULL) {
--		MESSAGE(KERN_DEBUG,
--			"unsolicited interrupt received: bus_id %s",
--			cdev->dev.bus_id);
--		return;
--	}
--
--	device = (struct dasd_device *) cqr->device;
--	if (device == NULL ||
-+	device = (struct dasd_device *) cqr->startdev;
-+	if (!device ||
- 	    strncmp(device->discipline->ebcname, (char *) &cqr->magic, 4)) {
- 		MESSAGE(KERN_DEBUG, "invalid device in request: bus_id %s",
- 			cdev->dev.bus_id);
-@@ -999,12 +1022,12 @@ dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
- 	}
+-static int
+-dasd_ioctl_readall_cmb(struct dasd_device *device, unsigned int cmd,
++static int dasd_ioctl_readall_cmb(struct dasd_block *block, unsigned int cmd,
+ 		unsigned long arg)
+ {
+ 	struct cmbdata __user *argp = (void __user *) arg;
+@@ -363,7 +359,7 @@ dasd_ioctl_readall_cmb(struct dasd_device *device, unsigned int cmd,
+ 	struct cmbdata data;
+ 	int ret;
  
- 	/* Check for clear pending */
--	if (cqr->status == DASD_CQR_CLEAR &&
-+	if (cqr->status == DASD_CQR_CLEAR_PENDING &&
- 	    irb->scsw.fctl & SCSW_FCTL_CLEAR_FUNC) {
--		cqr->status = DASD_CQR_QUEUED;
--		dasd_clear_timer(device);
-+		cqr->status = DASD_CQR_CLEARED;
-+		dasd_device_clear_timer(device);
- 		wake_up(&dasd_flush_wq);
--		dasd_schedule_bh(device);
-+		dasd_schedule_device_bh(device);
- 		return;
- 	}
+-	ret = cmf_readall(device->cdev, &data);
++	ret = cmf_readall(block->base->cdev, &data);
+ 	if (!ret && copy_to_user(argp, &data, min(size, sizeof(*argp))))
+ 		return -EFAULT;
+ 	return ret;
+@@ -374,10 +370,10 @@ dasd_ioctl(struct inode *inode, struct file *file,
+ 	   unsigned int cmd, unsigned long arg)
+ {
+ 	struct block_device *bdev = inode->i_bdev;
+-	struct dasd_device *device = bdev->bd_disk->private_data;
++	struct dasd_block *block = bdev->bd_disk->private_data;
+ 	void __user *argp = (void __user *)arg;
  
-@@ -1017,277 +1040,170 @@ dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
- 	}
- 	DBF_DEV_EVENT(DBF_DEBUG, device, "Int: CS/DS 0x%04x for cqr %p",
- 		      ((irb->scsw.cstat << 8) | irb->scsw.dstat), cqr);
--
-- 	/* Find out the appropriate era_action. */
--	if (irb->scsw.fctl & SCSW_FCTL_HALT_FUNC)
--		era = dasd_era_fatal;
--	else if (irb->scsw.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END) &&
--		 irb->scsw.cstat == 0 &&
--		 !irb->esw.esw0.erw.cons)
--		era = dasd_era_none;
--	else if (irb->esw.esw0.erw.cons)
--		era = device->discipline->examine_error(cqr, irb);
--	else
--		era = dasd_era_recover;
--
--	DBF_DEV_EVENT(DBF_DEBUG, device, "era_code %d", era);
-+	next = NULL;
- 	expires = 0;
--	if (era == dasd_era_none) {
--		cqr->status = DASD_CQR_DONE;
-+	if (irb->scsw.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END) &&
-+	    irb->scsw.cstat == 0 && !irb->esw.esw0.erw.cons) {
-+		/* request was completed successfully */
-+		cqr->status = DASD_CQR_SUCCESS;
- 		cqr->stopclk = now;
- 		/* Start first request on queue if possible -> fast_io. */
--		if (cqr->list.next != &device->ccw_queue) {
--			next = list_entry(cqr->list.next,
--					  struct dasd_ccw_req, list);
--			if ((next->status == DASD_CQR_QUEUED) &&
--			    (!device->stopped)) {
--				if (device->discipline->start_IO(next) == 0)
--					expires = next->expires;
--				else
--					DEV_MESSAGE(KERN_DEBUG, device, "%s",
--						    "Interrupt fastpath "
--						    "failed!");
--			}
-+		if (cqr->devlist.next != &device->ccw_queue) {
-+			next = list_entry(cqr->devlist.next,
-+					  struct dasd_ccw_req, devlist);
- 		}
--	} else {		/* error */
--		memcpy(&cqr->irb, irb, sizeof (struct irb));
-+	} else {  /* error */
-+		memcpy(&cqr->irb, irb, sizeof(struct irb));
- 		if (device->features & DASD_FEATURE_ERPLOG) {
--			/* dump sense data */
- 			dasd_log_sense(cqr, irb);
- 		}
--		switch (era) {
--		case dasd_era_fatal:
--			cqr->status = DASD_CQR_FAILED;
--			cqr->stopclk = now;
--			break;
--		case dasd_era_recover:
-+		/* If we have no sense data, or we just don't want complex ERP
-+		 * for this request, but if we have retries left, then just
-+		 * reset this request and retry it in the fastpath
-+		 */
-+		if (!(cqr->irb.esw.esw0.erw.cons &&
-+		      test_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags)) &&
-+		    cqr->retries > 0) {
-+			DEV_MESSAGE(KERN_DEBUG, device,
-+				    "default ERP in fastpath (%i retries left)",
-+				    cqr->retries);
-+			cqr->lpm    = LPM_ANYPATH;
-+			cqr->status = DASD_CQR_QUEUED;
-+			next = cqr;
-+		} else
- 			cqr->status = DASD_CQR_ERROR;
--			break;
--		default:
--			BUG();
--		}
-+	}
-+	if (next && (next->status == DASD_CQR_QUEUED) &&
-+	    (!device->stopped)) {
-+		if (device->discipline->start_IO(next) == 0)
-+			expires = next->expires;
-+		else
-+			DEV_MESSAGE(KERN_DEBUG, device, "%s",
-+				    "Interrupt fastpath "
-+				    "failed!");
- 	}
- 	if (expires != 0)
--		dasd_set_timer(device, expires);
-+		dasd_device_set_timer(device, expires);
+-	if (!device)
++	if (!block)
+                 return -ENODEV;
+ 
+ 	if ((_IOC_DIR(cmd) != _IOC_NONE) && !arg) {
+@@ -391,33 +387,33 @@ dasd_ioctl(struct inode *inode, struct file *file,
+ 	case BIODASDENABLE:
+ 		return dasd_ioctl_enable(bdev);
+ 	case BIODASDQUIESCE:
+-		return dasd_ioctl_quiesce(device);
++		return dasd_ioctl_quiesce(block);
+ 	case BIODASDRESUME:
+-		return dasd_ioctl_resume(device);
++		return dasd_ioctl_resume(block);
+ 	case BIODASDFMT:
+ 		return dasd_ioctl_format(bdev, argp);
+ 	case BIODASDINFO:
+-		return dasd_ioctl_information(device, cmd, argp);
++		return dasd_ioctl_information(block, cmd, argp);
+ 	case BIODASDINFO2:
+-		return dasd_ioctl_information(device, cmd, argp);
++		return dasd_ioctl_information(block, cmd, argp);
+ 	case BIODASDPRRD:
+-		return dasd_ioctl_read_profile(device, argp);
++		return dasd_ioctl_read_profile(block, argp);
+ 	case BIODASDPRRST:
+-		return dasd_ioctl_reset_profile(device);
++		return dasd_ioctl_reset_profile(block);
+ 	case BLKROSET:
+ 		return dasd_ioctl_set_ro(bdev, argp);
+ 	case DASDAPIVER:
+ 		return dasd_ioctl_api_version(argp);
+ 	case BIODASDCMFENABLE:
+-		return enable_cmf(device->cdev);
++		return enable_cmf(block->base->cdev);
+ 	case BIODASDCMFDISABLE:
+-		return disable_cmf(device->cdev);
++		return disable_cmf(block->base->cdev);
+ 	case BIODASDREADALLCMB:
+-		return dasd_ioctl_readall_cmb(device, cmd, arg);
++		return dasd_ioctl_readall_cmb(block, cmd, arg);
+ 	default:
+ 		/* if the discipline has an ioctl method try it. */
+-		if (device->discipline->ioctl) {
+-			int rval = device->discipline->ioctl(device, cmd, argp);
++		if (block->base->discipline->ioctl) {
++			int rval = block->base->discipline->ioctl(block, cmd, argp);
+ 			if (rval != -ENOIOCTLCMD)
+ 				return rval;
+ 		}
+diff --git a/drivers/s390/block/dasd_proc.c b/drivers/s390/block/dasd_proc.c
+index ac7e8ef..28a86f0 100644
+--- a/drivers/s390/block/dasd_proc.c
++++ b/drivers/s390/block/dasd_proc.c
+@@ -54,11 +54,16 @@ static int
+ dasd_devices_show(struct seq_file *m, void *v)
+ {
+ 	struct dasd_device *device;
++	struct dasd_block *block;
+ 	char *substr;
+ 
+ 	device = dasd_device_from_devindex((unsigned long) v - 1);
+ 	if (IS_ERR(device))
+ 		return 0;
++	if (device->block)
++		block = device->block;
++	else
++		return 0;
+ 	/* Print device number. */
+ 	seq_printf(m, "%s", device->cdev->dev.bus_id);
+ 	/* Print discipline string. */
+@@ -67,14 +72,14 @@ dasd_devices_show(struct seq_file *m, void *v)
  	else
--		dasd_clear_timer(device);
--	dasd_schedule_bh(device);
-+		dasd_device_clear_timer(device);
-+	dasd_schedule_device_bh(device);
+ 		seq_printf(m, "(none)");
+ 	/* Print kdev. */
+-	if (device->gdp)
++	if (block->gdp)
+ 		seq_printf(m, " at (%3d:%6d)",
+-			   device->gdp->major, device->gdp->first_minor);
++			   block->gdp->major, block->gdp->first_minor);
+ 	else
+ 		seq_printf(m, "  at (???:??????)");
+ 	/* Print device name. */
+-	if (device->gdp)
+-		seq_printf(m, " is %-8s", device->gdp->disk_name);
++	if (block->gdp)
++		seq_printf(m, " is %-8s", block->gdp->disk_name);
+ 	else
+ 		seq_printf(m, " is ????????");
+ 	/* Print devices features. */
+@@ -100,14 +105,14 @@ dasd_devices_show(struct seq_file *m, void *v)
+ 	case DASD_STATE_READY:
+ 	case DASD_STATE_ONLINE:
+ 		seq_printf(m, "active ");
+-		if (dasd_check_blocksize(device->bp_block))
++		if (dasd_check_blocksize(block->bp_block))
+ 			seq_printf(m, "n/f	 ");
+ 		else
+ 			seq_printf(m,
+ 				   "at blocksize: %d, %ld blocks, %ld MB",
+-				   device->bp_block, device->blocks,
+-				   ((device->bp_block >> 9) *
+-				    device->blocks) >> 11);
++				   block->bp_block, block->blocks,
++				   ((block->bp_block >> 9) *
++				    block->blocks) >> 11);
+ 		break;
+ 	default:
+ 		seq_printf(m, "no stat");
+@@ -137,7 +142,7 @@ static void dasd_devices_stop(struct seq_file *m, void *v)
+ {
  }
  
+-static struct seq_operations dasd_devices_seq_ops = {
++static const struct seq_operations dasd_devices_seq_ops = {
+ 	.start		= dasd_devices_start,
+ 	.next		= dasd_devices_next,
+ 	.stop		= dasd_devices_stop,
+diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c
+index 15a5789..7779bfc 100644
+--- a/drivers/s390/block/dcssblk.c
++++ b/drivers/s390/block/dcssblk.c
+@@ -82,7 +82,7 @@ struct dcssblk_dev_info {
+ 	struct request_queue *dcssblk_queue;
+ };
+ 
+-static struct list_head dcssblk_devices = LIST_HEAD_INIT(dcssblk_devices);
++static LIST_HEAD(dcssblk_devices);
+ static struct rw_semaphore dcssblk_devices_sem;
+ 
  /*
-- * posts the buffer_cache about a finalized request
-+ * If we have an error on a dasd_block layer request then we cancel
-+ * and return all further requests from the same dasd_block as well.
-  */
--static inline void
--dasd_end_request(struct request *req, int uptodate)
-+static void __dasd_device_recovery(struct dasd_device *device,
-+				   struct dasd_ccw_req *ref_cqr)
- {
--	if (end_that_request_first(req, uptodate, req->hard_nr_sectors))
--		BUG();
--	add_disk_randomness(req->rq_disk);
--	end_that_request_last(req, uptodate);
--}
-+	struct list_head *l, *n;
-+	struct dasd_ccw_req *cqr;
+diff --git a/drivers/s390/char/Makefile b/drivers/s390/char/Makefile
+index 130de19..7e73e39 100644
+--- a/drivers/s390/char/Makefile
++++ b/drivers/s390/char/Makefile
+@@ -3,7 +3,7 @@
+ #
  
--/*
-- * Process finished error recovery ccw.
-- */
--static inline void
--__dasd_process_erp(struct dasd_device *device, struct dasd_ccw_req *cqr)
--{
--	dasd_erp_fn_t erp_fn;
-+	/*
-+	 * only requeue request that came from the dasd_block layer
-+	 */
-+	if (!ref_cqr->block)
-+		return;
+ obj-y += ctrlchar.o keyboard.o defkeymap.o sclp.o sclp_rw.o sclp_quiesce.o \
+-	 sclp_info.o sclp_config.o sclp_chp.o
++	 sclp_cmd.o sclp_config.o sclp_cpi_sys.o
  
--	if (cqr->status == DASD_CQR_DONE)
--		DBF_DEV_EVENT(DBF_NOTICE, device, "%s", "ERP successful");
--	else
--		DEV_MESSAGE(KERN_ERR, device, "%s", "ERP unsuccessful");
--	erp_fn = device->discipline->erp_postaction(cqr);
--	erp_fn(cqr);
--}
-+	list_for_each_safe(l, n, &device->ccw_queue) {
-+		cqr = list_entry(l, struct dasd_ccw_req, devlist);
-+		if (cqr->status == DASD_CQR_QUEUED &&
-+		    ref_cqr->block == cqr->block) {
-+			cqr->status = DASD_CQR_CLEARED;
-+		}
-+	}
-+};
+ obj-$(CONFIG_TN3270) += raw3270.o
+ obj-$(CONFIG_TN3270_CONSOLE) += con3270.o
+diff --git a/drivers/s390/char/monwriter.c b/drivers/s390/char/monwriter.c
+index 20442fb..a86c053 100644
+--- a/drivers/s390/char/monwriter.c
++++ b/drivers/s390/char/monwriter.c
+@@ -295,7 +295,7 @@ module_init(mon_init);
+ module_exit(mon_exit);
+ 
+ module_param_named(max_bufs, mon_max_bufs, int, 0644);
+-MODULE_PARM_DESC(max_bufs, "Maximum number of sample monitor data buffers"
++MODULE_PARM_DESC(max_bufs, "Maximum number of sample monitor data buffers "
+ 		 "that can be active at one time");
+ 
+ MODULE_AUTHOR("Melissa Howland <Melissa.Howland at us.ibm.com>");
+diff --git a/drivers/s390/char/raw3270.c b/drivers/s390/char/raw3270.c
+index 8d1c64a..0d98f1f 100644
+--- a/drivers/s390/char/raw3270.c
++++ b/drivers/s390/char/raw3270.c
+@@ -66,7 +66,7 @@ struct raw3270 {
+ static DEFINE_MUTEX(raw3270_mutex);
+ 
+ /* List of 3270 devices. */
+-static struct list_head raw3270_devices = LIST_HEAD_INIT(raw3270_devices);
++static LIST_HEAD(raw3270_devices);
  
  /*
-- * Process ccw request queue.
-+ * Remove those ccw requests from the queue that need to be returned
-+ * to the upper layer.
-  */
--static void
--__dasd_process_ccw_queue(struct dasd_device * device,
--			 struct list_head *final_queue)
-+static void __dasd_device_process_ccw_queue(struct dasd_device *device,
-+					    struct list_head *final_queue)
+  * Flag to indicate if the driver has been registered. Some operations
+@@ -1210,7 +1210,7 @@ struct raw3270_notifier {
+ 	void (*notifier)(int, int);
+ };
+ 
+-static struct list_head raw3270_notifier = LIST_HEAD_INIT(raw3270_notifier);
++static LIST_HEAD(raw3270_notifier);
+ 
+ int raw3270_register_notifier(void (*notifier)(int, int))
  {
- 	struct list_head *l, *n;
- 	struct dasd_ccw_req *cqr;
--	dasd_erp_fn_t erp_fn;
+diff --git a/drivers/s390/char/sclp.h b/drivers/s390/char/sclp.h
+index c7318a1..aa8186d 100644
+--- a/drivers/s390/char/sclp.h
++++ b/drivers/s390/char/sclp.h
+@@ -56,8 +56,6 @@ typedef unsigned int sclp_cmdw_t;
+ #define SCLP_CMDW_READ_EVENT_DATA	0x00770005
+ #define SCLP_CMDW_WRITE_EVENT_DATA	0x00760005
+ #define SCLP_CMDW_WRITE_EVENT_MASK	0x00780005
+-#define SCLP_CMDW_READ_SCP_INFO		0x00020001
+-#define SCLP_CMDW_READ_SCP_INFO_FORCED	0x00120001
  
--restart:
- 	/* Process request with final status. */
- 	list_for_each_safe(l, n, &device->ccw_queue) {
--		cqr = list_entry(l, struct dasd_ccw_req, list);
-+		cqr = list_entry(l, struct dasd_ccw_req, devlist);
-+
- 		/* Stop list processing at the first non-final request. */
--		if (cqr->status != DASD_CQR_DONE &&
--		    cqr->status != DASD_CQR_FAILED &&
--		    cqr->status != DASD_CQR_ERROR)
-+		if (cqr->status == DASD_CQR_QUEUED ||
-+		    cqr->status == DASD_CQR_IN_IO ||
-+		    cqr->status == DASD_CQR_CLEAR_PENDING)
- 			break;
--		/*  Process requests with DASD_CQR_ERROR */
- 		if (cqr->status == DASD_CQR_ERROR) {
--			if (cqr->irb.scsw.fctl & SCSW_FCTL_HALT_FUNC) {
--				cqr->status = DASD_CQR_FAILED;
--				cqr->stopclk = get_clock();
--			} else {
--				if (cqr->irb.esw.esw0.erw.cons &&
--				    test_bit(DASD_CQR_FLAGS_USE_ERP,
--					     &cqr->flags)) {
--					erp_fn = device->discipline->
--						erp_action(cqr);
--					erp_fn(cqr);
--				} else
--					dasd_default_erp_action(cqr);
--			}
--			goto restart;
--		}
+ #define GDS_ID_MDSMU		0x1310
+ #define GDS_ID_MDSROUTEINFO	0x1311
+@@ -83,6 +81,8 @@ extern u64 sclp_facilities;
+ 
+ #define SCLP_HAS_CHP_INFO	(sclp_facilities & 0x8000000000000000ULL)
+ #define SCLP_HAS_CHP_RECONFIG	(sclp_facilities & 0x2000000000000000ULL)
++#define SCLP_HAS_CPU_INFO	(sclp_facilities & 0x0800000000000000ULL)
++#define SCLP_HAS_CPU_RECONFIG	(sclp_facilities & 0x0400000000000000ULL)
+ 
+ struct gds_subvector {
+ 	u8	length;
+diff --git a/drivers/s390/char/sclp_chp.c b/drivers/s390/char/sclp_chp.c
+deleted file mode 100644
+index c68f5e7..0000000
+--- a/drivers/s390/char/sclp_chp.c
++++ /dev/null
+@@ -1,200 +0,0 @@
+-/*
+- *  drivers/s390/char/sclp_chp.c
+- *
+- *    Copyright IBM Corp. 2007
+- *    Author(s): Peter Oberparleiter <peter.oberparleiter at de.ibm.com>
+- */
 -
--		/* First of all call extended error reporting. */
--		if (dasd_eer_enabled(device) &&
--		    cqr->status == DASD_CQR_FAILED) {
--			dasd_eer_write(device, cqr, DASD_EER_FATALERROR);
+-#include <linux/types.h>
+-#include <linux/gfp.h>
+-#include <linux/errno.h>
+-#include <linux/completion.h>
+-#include <asm/sclp.h>
+-#include <asm/chpid.h>
 -
--			/* restart request  */
--			cqr->status = DASD_CQR_QUEUED;
--			cqr->retries = 255;
--			device->stopped |= DASD_STOPPED_QUIESCE;
--			goto restart;
-+			__dasd_device_recovery(device, cqr);
- 		}
+-#include "sclp.h"
 -
--		/* Process finished ERP request. */
--		if (cqr->refers) {
--			__dasd_process_erp(device, cqr);
--			goto restart;
--		}
+-#define TAG	"sclp_chp: "
 -
- 		/* Rechain finished requests to final queue */
--		cqr->endclk = get_clock();
--		list_move_tail(&cqr->list, final_queue);
-+		list_move_tail(&cqr->devlist, final_queue);
- 	}
- }
- 
--static void
--dasd_end_request_cb(struct dasd_ccw_req * cqr, void *data)
+-#define SCLP_CMDW_CONFIGURE_CHANNEL_PATH	0x000f0001
+-#define SCLP_CMDW_DECONFIGURE_CHANNEL_PATH	0x000e0001
+-#define SCLP_CMDW_READ_CHANNEL_PATH_INFORMATION	0x00030001
+-
+-static inline sclp_cmdw_t get_configure_cmdw(struct chp_id chpid)
 -{
--	struct request *req;
--	struct dasd_device *device;
--	int status;
+-	return SCLP_CMDW_CONFIGURE_CHANNEL_PATH | chpid.id << 8;
+-}
 -
--	req = (struct request *) data;
--	device = cqr->device;
--	dasd_profile_end(device, cqr, req);
--	status = cqr->device->discipline->free_cp(cqr,req);
--	spin_lock_irq(&device->request_queue_lock);
--	dasd_end_request(req, status);
--	spin_unlock_irq(&device->request_queue_lock);
+-static inline sclp_cmdw_t get_deconfigure_cmdw(struct chp_id chpid)
+-{
+-	return SCLP_CMDW_DECONFIGURE_CHANNEL_PATH | chpid.id << 8;
 -}
 -
+-static void chp_callback(struct sclp_req *req, void *data)
+-{
+-	struct completion *completion = data;
 -
- /*
-- * Fetch requests from the block device queue.
-+ * the cqrs from the final queue are returned to the upper layer
-+ * by setting a dasd_block state and calling the callback function
-  */
--static void
--__dasd_process_blk_queue(struct dasd_device * device)
-+static void __dasd_device_process_final_queue(struct dasd_device *device,
-+					      struct list_head *final_queue)
- {
--	struct request_queue *queue;
--	struct request *req;
-+	struct list_head *l, *n;
- 	struct dasd_ccw_req *cqr;
--	int nr_queued;
+-	complete(completion);
+-}
 -
--	queue = device->request_queue;
--	/* No queue ? Then there is nothing to do. */
--	if (queue == NULL)
--		return;
+-struct chp_cfg_sccb {
+-	struct sccb_header header;
+-	u8 ccm;
+-	u8 reserved[6];
+-	u8 cssid;
+-} __attribute__((packed));
 -
--	/*
--	 * We requeue request from the block device queue to the ccw
--	 * queue only in two states. In state DASD_STATE_READY the
--	 * partition detection is done and we need to requeue requests
--	 * for that. State DASD_STATE_ONLINE is normal block device
--	 * operation.
--	 */
--	if (device->state != DASD_STATE_READY &&
--	    device->state != DASD_STATE_ONLINE)
--		return;
--	nr_queued = 0;
--	/* Now we try to fetch requests from the request queue */
--	list_for_each_entry(cqr, &device->ccw_queue, list)
--		if (cqr->status == DASD_CQR_QUEUED)
--			nr_queued++;
--	while (!blk_queue_plugged(queue) &&
--	       elv_next_request(queue) &&
--		nr_queued < DASD_CHANQ_MAX_SIZE) {
--		req = elv_next_request(queue);
- 
--		if (device->features & DASD_FEATURE_READONLY &&
--		    rq_data_dir(req) == WRITE) {
--			DBF_DEV_EVENT(DBF_ERR, device,
--				      "Rejecting write request %p",
--				      req);
--			blkdev_dequeue_request(req);
--			dasd_end_request(req, 0);
--			continue;
--		}
--		if (device->stopped & DASD_STOPPED_DC_EIO) {
--			blkdev_dequeue_request(req);
--			dasd_end_request(req, 0);
--			continue;
--		}
--		cqr = device->discipline->build_cp(device, req);
--		if (IS_ERR(cqr)) {
--			if (PTR_ERR(cqr) == -ENOMEM)
--				break;	/* terminate request queue loop */
--			if (PTR_ERR(cqr) == -EAGAIN) {
--				/*
--				 * The current request cannot be build right
--				 * now, we have to try later. If this request
--				 * is the head-of-queue we stop the device
--				 * for 1/2 second.
--				 */
--				if (!list_empty(&device->ccw_queue))
--					break;
--				device->stopped |= DASD_STOPPED_PENDING;
--				dasd_set_timer(device, HZ/2);
--				break;
--			}
--			DBF_DEV_EVENT(DBF_ERR, device,
--				      "CCW creation failed (rc=%ld) "
--				      "on request %p",
--				      PTR_ERR(cqr), req);
--			blkdev_dequeue_request(req);
--			dasd_end_request(req, 0);
--			continue;
-+	list_for_each_safe(l, n, final_queue) {
-+		cqr = list_entry(l, struct dasd_ccw_req, devlist);
-+		list_del_init(&cqr->devlist);
-+		if (cqr->block)
-+			spin_lock_bh(&cqr->block->queue_lock);
-+		switch (cqr->status) {
-+		case DASD_CQR_SUCCESS:
-+			cqr->status = DASD_CQR_DONE;
+-struct chp_cfg_data {
+-	struct chp_cfg_sccb sccb;
+-	struct sclp_req req;
+-	struct completion completion;
+-} __attribute__((packed));
+-
+-static int do_configure(sclp_cmdw_t cmd)
+-{
+-	struct chp_cfg_data *data;
+-	int rc;
+-
+-	if (!SCLP_HAS_CHP_RECONFIG)
+-		return -EOPNOTSUPP;
+-	/* Prepare sccb. */
+-	data = (struct chp_cfg_data *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
+-	if (!data)
+-		return -ENOMEM;
+-	data->sccb.header.length = sizeof(struct chp_cfg_sccb);
+-	data->req.command = cmd;
+-	data->req.sccb = &(data->sccb);
+-	data->req.status = SCLP_REQ_FILLED;
+-	data->req.callback = chp_callback;
+-	data->req.callback_data = &(data->completion);
+-	init_completion(&data->completion);
+-
+-	/* Perform sclp request. */
+-	rc = sclp_add_request(&(data->req));
+-	if (rc)
+-		goto out;
+-	wait_for_completion(&data->completion);
+-
+-	/* Check response .*/
+-	if (data->req.status != SCLP_REQ_DONE) {
+-		printk(KERN_WARNING TAG "configure channel-path request failed "
+-		       "(status=0x%02x)\n", data->req.status);
+-		rc = -EIO;
+-		goto out;
+-	}
+-	switch (data->sccb.header.response_code) {
+-	case 0x0020:
+-	case 0x0120:
+-	case 0x0440:
+-	case 0x0450:
+-		break;
+-	default:
+-		printk(KERN_WARNING TAG "configure channel-path failed "
+-		       "(cmd=0x%08x, response=0x%04x)\n", cmd,
+-		       data->sccb.header.response_code);
+-		rc = -EIO;
+-		break;
+-	}
+-out:
+-	free_page((unsigned long) data);
+-
+-	return rc;
+-}
+-
+-/**
+- * sclp_chp_configure - perform configure channel-path sclp command
+- * @chpid: channel-path ID
+- *
+- * Perform configure channel-path command sclp command for specified chpid.
+- * Return 0 after command successfully finished, non-zero otherwise.
+- */
+-int sclp_chp_configure(struct chp_id chpid)
+-{
+-	return do_configure(get_configure_cmdw(chpid));
+-}
+-
+-/**
+- * sclp_chp_deconfigure - perform deconfigure channel-path sclp command
+- * @chpid: channel-path ID
+- *
+- * Perform deconfigure channel-path command sclp command for specified chpid
+- * and wait for completion. On success return 0. Return non-zero otherwise.
+- */
+-int sclp_chp_deconfigure(struct chp_id chpid)
+-{
+-	return do_configure(get_deconfigure_cmdw(chpid));
+-}
+-
+-struct chp_info_sccb {
+-	struct sccb_header header;
+-	u8 recognized[SCLP_CHP_INFO_MASK_SIZE];
+-	u8 standby[SCLP_CHP_INFO_MASK_SIZE];
+-	u8 configured[SCLP_CHP_INFO_MASK_SIZE];
+-	u8 ccm;
+-	u8 reserved[6];
+-	u8 cssid;
+-} __attribute__((packed));
+-
+-struct chp_info_data {
+-	struct chp_info_sccb sccb;
+-	struct sclp_req req;
+-	struct completion completion;
+-} __attribute__((packed));
+-
+-/**
+- * sclp_chp_read_info - perform read channel-path information sclp command
+- * @info: resulting channel-path information data
+- *
+- * Perform read channel-path information sclp command and wait for completion.
+- * On success, store channel-path information in @info and return 0. Return
+- * non-zero otherwise.
+- */
+-int sclp_chp_read_info(struct sclp_chp_info *info)
+-{
+-	struct chp_info_data *data;
+-	int rc;
+-
+-	if (!SCLP_HAS_CHP_INFO)
+-		return -EOPNOTSUPP;
+-	/* Prepare sccb. */
+-	data = (struct chp_info_data *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
+-	if (!data)
+-		return -ENOMEM;
+-	data->sccb.header.length = sizeof(struct chp_info_sccb);
+-	data->req.command = SCLP_CMDW_READ_CHANNEL_PATH_INFORMATION;
+-	data->req.sccb = &(data->sccb);
+-	data->req.status = SCLP_REQ_FILLED;
+-	data->req.callback = chp_callback;
+-	data->req.callback_data = &(data->completion);
+-	init_completion(&data->completion);
+-
+-	/* Perform sclp request. */
+-	rc = sclp_add_request(&(data->req));
+-	if (rc)
+-		goto out;
+-	wait_for_completion(&data->completion);
+-
+-	/* Check response .*/
+-	if (data->req.status != SCLP_REQ_DONE) {
+-		printk(KERN_WARNING TAG "read channel-path info request failed "
+-		       "(status=0x%02x)\n", data->req.status);
+-		rc = -EIO;
+-		goto out;
+-	}
+-	if (data->sccb.header.response_code != 0x0010) {
+-		printk(KERN_WARNING TAG "read channel-path info failed "
+-		       "(response=0x%04x)\n", data->sccb.header.response_code);
+-		rc = -EIO;
+-		goto out;
+-	}
+-	memcpy(info->recognized, data->sccb.recognized,
+-	       SCLP_CHP_INFO_MASK_SIZE);
+-	memcpy(info->standby, data->sccb.standby,
+-	       SCLP_CHP_INFO_MASK_SIZE);
+-	memcpy(info->configured, data->sccb.configured,
+-	       SCLP_CHP_INFO_MASK_SIZE);
+-out:
+-	free_page((unsigned long) data);
+-
+-	return rc;
+-}
+diff --git a/drivers/s390/char/sclp_cmd.c b/drivers/s390/char/sclp_cmd.c
+new file mode 100644
+index 0000000..b5c2339
+--- /dev/null
++++ b/drivers/s390/char/sclp_cmd.c
+@@ -0,0 +1,398 @@
++/*
++ *  drivers/s390/char/sclp_cmd.c
++ *
++ *    Copyright IBM Corp. 2007
++ *    Author(s): Heiko Carstens <heiko.carstens at de.ibm.com>,
++ *		 Peter Oberparleiter <peter.oberparleiter at de.ibm.com>
++ */
++
++#include <linux/completion.h>
++#include <linux/init.h>
++#include <linux/errno.h>
++#include <linux/slab.h>
++#include <linux/string.h>
++#include <asm/chpid.h>
++#include <asm/sclp.h>
++#include "sclp.h"
++
++#define TAG	"sclp_cmd: "
++
++#define SCLP_CMDW_READ_SCP_INFO		0x00020001
++#define SCLP_CMDW_READ_SCP_INFO_FORCED	0x00120001
++
++struct read_info_sccb {
++	struct	sccb_header header;	/* 0-7 */
++	u16	rnmax;			/* 8-9 */
++	u8	rnsize;			/* 10 */
++	u8	_reserved0[24 - 11];	/* 11-15 */
++	u8	loadparm[8];		/* 24-31 */
++	u8	_reserved1[48 - 32];	/* 32-47 */
++	u64	facilities;		/* 48-55 */
++	u8	_reserved2[84 - 56];	/* 56-83 */
++	u8	fac84;			/* 84 */
++	u8	_reserved3[91 - 85];	/* 85-90 */
++	u8	flags;			/* 91 */
++	u8	_reserved4[100 - 92];	/* 92-99 */
++	u32	rnsize2;		/* 100-103 */
++	u64	rnmax2;			/* 104-111 */
++	u8	_reserved5[4096 - 112];	/* 112-4095 */
++} __attribute__((packed, aligned(PAGE_SIZE)));
++
++static struct read_info_sccb __initdata early_read_info_sccb;
++static int __initdata early_read_info_sccb_valid;
++
++u64 sclp_facilities;
++static u8 sclp_fac84;
++
++static int __init sclp_cmd_sync_early(sclp_cmdw_t cmd, void *sccb)
++{
++	int rc;
++
++	__ctl_set_bit(0, 9);
++	rc = sclp_service_call(cmd, sccb);
++	if (rc)
++		goto out;
++	__load_psw_mask(PSW_BASE_BITS | PSW_MASK_EXT |
++			PSW_MASK_WAIT | PSW_DEFAULT_KEY);
++	local_irq_disable();
++out:
++	/* Contents of the sccb might have changed. */
++	barrier();
++	__ctl_clear_bit(0, 9);
++	return rc;
++}
++
++void __init sclp_read_info_early(void)
++{
++	int rc;
++	int i;
++	struct read_info_sccb *sccb;
++	sclp_cmdw_t commands[] = {SCLP_CMDW_READ_SCP_INFO_FORCED,
++				  SCLP_CMDW_READ_SCP_INFO};
++
++	sccb = &early_read_info_sccb;
++	for (i = 0; i < ARRAY_SIZE(commands); i++) {
++		do {
++			memset(sccb, 0, sizeof(*sccb));
++			sccb->header.length = sizeof(*sccb);
++			sccb->header.control_mask[2] = 0x80;
++			rc = sclp_cmd_sync_early(commands[i], sccb);
++		} while (rc == -EBUSY);
++
++		if (rc)
 +			break;
-+		case DASD_CQR_ERROR:
-+			cqr->status = DASD_CQR_NEED_ERP;
++		if (sccb->header.response_code == 0x10) {
++			early_read_info_sccb_valid = 1;
 +			break;
-+		case DASD_CQR_CLEARED:
-+			cqr->status = DASD_CQR_TERMINATED;
++		}
++		if (sccb->header.response_code != 0x1f0)
 +			break;
-+		default:
-+			DEV_MESSAGE(KERN_ERR, device,
-+				    "wrong cqr status in __dasd_process_final_queue "
-+				    "for cqr %p, status %x",
-+				    cqr, cqr->status);
-+			BUG();
- 		}
--		cqr->callback = dasd_end_request_cb;
--		cqr->callback_data = (void *) req;
--		cqr->status = DASD_CQR_QUEUED;
--		blkdev_dequeue_request(req);
--		list_add_tail(&cqr->list, &device->ccw_queue);
--		dasd_profile_start(device, cqr, req);
--		nr_queued++;
-+		if (cqr->block)
-+			spin_unlock_bh(&cqr->block->queue_lock);
-+		if (cqr->callback != NULL)
-+			(cqr->callback)(cqr, cqr->callback_data);
- 	}
- }
- 
++	}
++}
 +
++void __init sclp_facilities_detect(void)
++{
++	if (!early_read_info_sccb_valid)
++		return;
++	sclp_facilities = early_read_info_sccb.facilities;
++	sclp_fac84 = early_read_info_sccb.fac84;
++}
 +
- /*
-  * Take a look at the first request on the ccw queue and check
-  * if it reached its expire time. If so, terminate the IO.
-  */
--static void
--__dasd_check_expire(struct dasd_device * device)
-+static void __dasd_device_check_expire(struct dasd_device *device)
- {
- 	struct dasd_ccw_req *cqr;
- 
- 	if (list_empty(&device->ccw_queue))
- 		return;
--	cqr = list_entry(device->ccw_queue.next, struct dasd_ccw_req, list);
-+	cqr = list_entry(device->ccw_queue.next, struct dasd_ccw_req, devlist);
- 	if ((cqr->status == DASD_CQR_IN_IO && cqr->expires != 0) &&
- 	    (time_after_eq(jiffies, cqr->expires + cqr->starttime))) {
- 		if (device->discipline->term_IO(cqr) != 0) {
- 			/* Hmpf, try again in 5 sec */
--			dasd_set_timer(device, 5*HZ);
- 			DEV_MESSAGE(KERN_ERR, device,
- 				    "internal error - timeout (%is) expired "
- 				    "for cqr %p, termination failed, "
- 				    "retrying in 5s",
- 				    (cqr->expires/HZ), cqr);
-+			cqr->expires += 5*HZ;
-+			dasd_device_set_timer(device, 5*HZ);
- 		} else {
- 			DEV_MESSAGE(KERN_ERR, device,
- 				    "internal error - timeout (%is) expired "
-@@ -1301,77 +1217,53 @@ __dasd_check_expire(struct dasd_device * device)
-  * Take a look at the first request on the ccw queue and check
-  * if it needs to be started.
-  */
--static void
--__dasd_start_head(struct dasd_device * device)
-+static void __dasd_device_start_head(struct dasd_device *device)
- {
- 	struct dasd_ccw_req *cqr;
- 	int rc;
++unsigned long long __init sclp_memory_detect(void)
++{
++	unsigned long long memsize;
++	struct read_info_sccb *sccb;
++
++	if (!early_read_info_sccb_valid)
++		return 0;
++	sccb = &early_read_info_sccb;
++	if (sccb->rnsize)
++		memsize = sccb->rnsize << 20;
++	else
++		memsize = sccb->rnsize2 << 20;
++	if (sccb->rnmax)
++		memsize *= sccb->rnmax;
++	else
++		memsize *= sccb->rnmax2;
++	return memsize;
++}
++
++/*
++ * This function will be called after sclp_memory_detect(), which gets called
++ * early from early.c code. Therefore the sccb should have valid contents.
++ */
++void __init sclp_get_ipl_info(struct sclp_ipl_info *info)
++{
++	struct read_info_sccb *sccb;
++
++	if (!early_read_info_sccb_valid)
++		return;
++	sccb = &early_read_info_sccb;
++	info->is_valid = 1;
++	if (sccb->flags & 0x2)
++		info->has_dump = 1;
++	memcpy(&info->loadparm, &sccb->loadparm, LOADPARM_LEN);
++}
++
++static void sclp_sync_callback(struct sclp_req *req, void *data)
++{
++	struct completion *completion = data;
++
++	complete(completion);
++}
++
++static int do_sync_request(sclp_cmdw_t cmd, void *sccb)
++{
++	struct completion completion;
++	struct sclp_req *request;
++	int rc;
++
++	request = kzalloc(sizeof(*request), GFP_KERNEL);
++	if (!request)
++		return -ENOMEM;
++	request->command = cmd;
++	request->sccb = sccb;
++	request->status = SCLP_REQ_FILLED;
++	request->callback = sclp_sync_callback;
++	request->callback_data = &completion;
++	init_completion(&completion);
++
++	/* Perform sclp request. */
++	rc = sclp_add_request(request);
++	if (rc)
++		goto out;
++	wait_for_completion(&completion);
++
++	/* Check response. */
++	if (request->status != SCLP_REQ_DONE) {
++		printk(KERN_WARNING TAG "sync request failed "
++		       "(cmd=0x%08x, status=0x%02x)\n", cmd, request->status);
++		rc = -EIO;
++	}
++out:
++	kfree(request);
++	return rc;
++}
++
++/*
++ * CPU configuration related functions.
++ */
++
++#define SCLP_CMDW_READ_CPU_INFO		0x00010001
++#define SCLP_CMDW_CONFIGURE_CPU		0x00110001
++#define SCLP_CMDW_DECONFIGURE_CPU	0x00100001
++
++struct read_cpu_info_sccb {
++	struct	sccb_header header;
++	u16	nr_configured;
++	u16	offset_configured;
++	u16	nr_standby;
++	u16	offset_standby;
++	u8	reserved[4096 - 16];
++} __attribute__((packed, aligned(PAGE_SIZE)));
++
++static void sclp_fill_cpu_info(struct sclp_cpu_info *info,
++			       struct read_cpu_info_sccb *sccb)
++{
++	char *page = (char *) sccb;
++
++	memset(info, 0, sizeof(*info));
++	info->configured = sccb->nr_configured;
++	info->standby = sccb->nr_standby;
++	info->combined = sccb->nr_configured + sccb->nr_standby;
++	info->has_cpu_type = sclp_fac84 & 0x1;
++	memcpy(&info->cpu, page + sccb->offset_configured,
++	       info->combined * sizeof(struct sclp_cpu_entry));
++}
++
++int sclp_get_cpu_info(struct sclp_cpu_info *info)
++{
++	int rc;
++	struct read_cpu_info_sccb *sccb;
++
++	if (!SCLP_HAS_CPU_INFO)
++		return -EOPNOTSUPP;
++	sccb = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
++	if (!sccb)
++		return -ENOMEM;
++	sccb->header.length = sizeof(*sccb);
++	rc = do_sync_request(SCLP_CMDW_READ_CPU_INFO, sccb);
++	if (rc)
++		goto out;
++	if (sccb->header.response_code != 0x0010) {
++		printk(KERN_WARNING TAG "readcpuinfo failed "
++		       "(response=0x%04x)\n", sccb->header.response_code);
++		rc = -EIO;
++		goto out;
++	}
++	sclp_fill_cpu_info(info, sccb);
++out:
++	free_page((unsigned long) sccb);
++	return rc;
++}
++
++struct cpu_configure_sccb {
++	struct sccb_header header;
++} __attribute__((packed, aligned(8)));
++
++static int do_cpu_configure(sclp_cmdw_t cmd)
++{
++	struct cpu_configure_sccb *sccb;
++	int rc;
++
++	if (!SCLP_HAS_CPU_RECONFIG)
++		return -EOPNOTSUPP;
++	/*
++	 * This is not going to cross a page boundary since we force
++	 * kmalloc to have a minimum alignment of 8 bytes on s390.
++	 */
++	sccb = kzalloc(sizeof(*sccb), GFP_KERNEL | GFP_DMA);
++	if (!sccb)
++		return -ENOMEM;
++	sccb->header.length = sizeof(*sccb);
++	rc = do_sync_request(cmd, sccb);
++	if (rc)
++		goto out;
++	switch (sccb->header.response_code) {
++	case 0x0020:
++	case 0x0120:
++		break;
++	default:
++		printk(KERN_WARNING TAG "configure cpu failed (cmd=0x%08x, "
++		       "response=0x%04x)\n", cmd, sccb->header.response_code);
++		rc = -EIO;
++		break;
++	}
++out:
++	kfree(sccb);
++	return rc;
++}
++
++int sclp_cpu_configure(u8 cpu)
++{
++	return do_cpu_configure(SCLP_CMDW_CONFIGURE_CPU | cpu << 8);
++}
++
++int sclp_cpu_deconfigure(u8 cpu)
++{
++	return do_cpu_configure(SCLP_CMDW_DECONFIGURE_CPU | cpu << 8);
++}
++
++/*
++ * Channel path configuration related functions.
++ */
++
++#define SCLP_CMDW_CONFIGURE_CHPATH		0x000f0001
++#define SCLP_CMDW_DECONFIGURE_CHPATH		0x000e0001
++#define SCLP_CMDW_READ_CHPATH_INFORMATION	0x00030001
++
++struct chp_cfg_sccb {
++	struct sccb_header header;
++	u8 ccm;
++	u8 reserved[6];
++	u8 cssid;
++} __attribute__((packed));
++
++static int do_chp_configure(sclp_cmdw_t cmd)
++{
++	struct chp_cfg_sccb *sccb;
++	int rc;
++
++	if (!SCLP_HAS_CHP_RECONFIG)
++		return -EOPNOTSUPP;
++	/* Prepare sccb. */
++	sccb = (struct chp_cfg_sccb *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
++	if (!sccb)
++		return -ENOMEM;
++	sccb->header.length = sizeof(*sccb);
++	rc = do_sync_request(cmd, sccb);
++	if (rc)
++		goto out;
++	switch (sccb->header.response_code) {
++	case 0x0020:
++	case 0x0120:
++	case 0x0440:
++	case 0x0450:
++		break;
++	default:
++		printk(KERN_WARNING TAG "configure channel-path failed "
++		       "(cmd=0x%08x, response=0x%04x)\n", cmd,
++		       sccb->header.response_code);
++		rc = -EIO;
++		break;
++	}
++out:
++	free_page((unsigned long) sccb);
++	return rc;
++}
++
++/**
++ * sclp_chp_configure - perform configure channel-path sclp command
++ * @chpid: channel-path ID
++ *
++ * Perform configure channel-path command sclp command for specified chpid.
++ * Return 0 after command successfully finished, non-zero otherwise.
++ */
++int sclp_chp_configure(struct chp_id chpid)
++{
++	return do_chp_configure(SCLP_CMDW_CONFIGURE_CHPATH | chpid.id << 8);
++}
++
++/**
++ * sclp_chp_deconfigure - perform deconfigure channel-path sclp command
++ * @chpid: channel-path ID
++ *
++ * Perform deconfigure channel-path command sclp command for specified chpid
++ * and wait for completion. On success return 0. Return non-zero otherwise.
++ */
++int sclp_chp_deconfigure(struct chp_id chpid)
++{
++	return do_chp_configure(SCLP_CMDW_DECONFIGURE_CHPATH | chpid.id << 8);
++}
++
++struct chp_info_sccb {
++	struct sccb_header header;
++	u8 recognized[SCLP_CHP_INFO_MASK_SIZE];
++	u8 standby[SCLP_CHP_INFO_MASK_SIZE];
++	u8 configured[SCLP_CHP_INFO_MASK_SIZE];
++	u8 ccm;
++	u8 reserved[6];
++	u8 cssid;
++} __attribute__((packed));
++
++/**
++ * sclp_chp_read_info - perform read channel-path information sclp command
++ * @info: resulting channel-path information data
++ *
++ * Perform read channel-path information sclp command and wait for completion.
++ * On success, store channel-path information in @info and return 0. Return
++ * non-zero otherwise.
++ */
++int sclp_chp_read_info(struct sclp_chp_info *info)
++{
++	struct chp_info_sccb *sccb;
++	int rc;
++
++	if (!SCLP_HAS_CHP_INFO)
++		return -EOPNOTSUPP;
++	/* Prepare sccb. */
++	sccb = (struct chp_info_sccb *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
++	if (!sccb)
++		return -ENOMEM;
++	sccb->header.length = sizeof(*sccb);
++	rc = do_sync_request(SCLP_CMDW_READ_CHPATH_INFORMATION, sccb);
++	if (rc)
++		goto out;
++	if (sccb->header.response_code != 0x0010) {
++		printk(KERN_WARNING TAG "read channel-path info failed "
++		       "(response=0x%04x)\n", sccb->header.response_code);
++		rc = -EIO;
++		goto out;
++	}
++	memcpy(info->recognized, sccb->recognized, SCLP_CHP_INFO_MASK_SIZE);
++	memcpy(info->standby, sccb->standby, SCLP_CHP_INFO_MASK_SIZE);
++	memcpy(info->configured, sccb->configured, SCLP_CHP_INFO_MASK_SIZE);
++out:
++	free_page((unsigned long) sccb);
++	return rc;
++}
+diff --git a/drivers/s390/char/sclp_config.c b/drivers/s390/char/sclp_config.c
+index 5322e5e..9dc77f1 100644
+--- a/drivers/s390/char/sclp_config.c
++++ b/drivers/s390/char/sclp_config.c
+@@ -29,12 +29,12 @@ static void sclp_cpu_capability_notify(struct work_struct *work)
+ 	struct sys_device *sysdev;
  
- 	if (list_empty(&device->ccw_queue))
- 		return;
--	cqr = list_entry(device->ccw_queue.next, struct dasd_ccw_req, list);
-+	cqr = list_entry(device->ccw_queue.next, struct dasd_ccw_req, devlist);
- 	if (cqr->status != DASD_CQR_QUEUED)
- 		return;
--	/* Non-temporary stop condition will trigger fail fast */
--	if (device->stopped & ~DASD_STOPPED_PENDING &&
--	    test_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags) &&
--	    (!dasd_eer_enabled(device))) {
--		cqr->status = DASD_CQR_FAILED;
--		dasd_schedule_bh(device);
-+	/* when device is stopped, return request to previous layer */
-+	if (device->stopped) {
-+		cqr->status = DASD_CQR_CLEARED;
-+		dasd_schedule_device_bh(device);
- 		return;
+ 	printk(KERN_WARNING TAG "cpu capability changed.\n");
+-	lock_cpu_hotplug();
++	get_online_cpus();
+ 	for_each_online_cpu(cpu) {
+ 		sysdev = get_cpu_sysdev(cpu);
+ 		kobject_uevent(&sysdev->kobj, KOBJ_CHANGE);
  	}
--	/* Don't try to start requests if device is stopped */
--	if (device->stopped)
--		return;
- 
- 	rc = device->discipline->start_IO(cqr);
- 	if (rc == 0)
--		dasd_set_timer(device, cqr->expires);
-+		dasd_device_set_timer(device, cqr->expires);
- 	else if (rc == -EACCES) {
--		dasd_schedule_bh(device);
-+		dasd_schedule_device_bh(device);
- 	} else
- 		/* Hmpf, try again in 1/2 sec */
--		dasd_set_timer(device, 50);
--}
--
--static inline int
--_wait_for_clear(struct dasd_ccw_req *cqr)
--{
--	return (cqr->status == DASD_CQR_QUEUED);
-+		dasd_device_set_timer(device, 50);
+-	unlock_cpu_hotplug();
++	put_online_cpus();
  }
  
+ static void sclp_conf_receiver_fn(struct evbuf_header *evbuf)
+diff --git a/drivers/s390/char/sclp_cpi.c b/drivers/s390/char/sclp_cpi.c
+index 82a13d9..5716487 100644
+--- a/drivers/s390/char/sclp_cpi.c
++++ b/drivers/s390/char/sclp_cpi.c
+@@ -1,255 +1,41 @@
  /*
-- * Remove all requests from the ccw queue (all = '1') or only block device
-- * requests in case all = '0'.
-- * Take care of the erp-chain (chained via cqr->refers) and remove either
-- * the whole erp-chain or none of the erp-requests.
-- * If a request is currently running, term_IO is called and the request
-- * is re-queued. Prior to removing the terminated request we need to wait
-- * for the clear-interrupt.
-- * In case termination is not possible we stop processing and just finishing
-- * the already moved requests.
-+ * Go through all request on the dasd_device request queue,
-+ * terminate them on the cdev if necessary, and return them to the
-+ * submitting layer via callback.
-+ * Note:
-+ * Make sure that all 'submitting layers' still exist when
-+ * this function is called!. In other words, when 'device' is a base
-+ * device then all block layer requests must have been removed before
-+ * via dasd_flush_block_queue.
+- * Author: Martin Peschke <mpeschke at de.ibm.com>
+- * Copyright (C) 2001 IBM Entwicklung GmbH, IBM Corporation
++ *  drivers/s390/char/sclp_cpi.c
++ *    SCLP control programm identification
+  *
+- * SCLP Control-Program Identification.
++ *    Copyright IBM Corp. 2001, 2007
++ *    Author(s): Martin Peschke <mpeschke at de.ibm.com>
++ *		 Michael Ernst <mernst at de.ibm.com>
   */
--static int
--dasd_flush_ccw_queue(struct dasd_device * device, int all)
-+int dasd_flush_device_queue(struct dasd_device *device)
- {
--	struct dasd_ccw_req *cqr, *orig, *n;
--	int rc, i;
--
-+	struct dasd_ccw_req *cqr, *n;
-+	int rc;
- 	struct list_head flush_queue;
  
- 	INIT_LIST_HEAD(&flush_queue);
- 	spin_lock_irq(get_ccwdev_lock(device->cdev));
- 	rc = 0;
--restart:
--	list_for_each_entry_safe(cqr, n, &device->ccw_queue, list) {
--		/* get original request of erp request-chain */
--		for (orig = cqr; orig->refers != NULL; orig = orig->refers);
+-#include <linux/version.h>
+ #include <linux/kmod.h>
+ #include <linux/module.h>
+ #include <linux/moduleparam.h>
+-#include <linux/init.h>
+-#include <linux/timer.h>
+-#include <linux/string.h>
+-#include <linux/err.h>
+-#include <linux/slab.h>
+-#include <asm/ebcdic.h>
+-#include <asm/semaphore.h>
 -
--		/* Flush all request or only block device requests? */
--		if (all == 0 && cqr->callback != dasd_end_request_cb &&
--		    orig->callback != dasd_end_request_cb) {
--			continue;
--		}
-+	list_for_each_entry_safe(cqr, n, &device->ccw_queue, devlist) {
- 		/* Check status and move request to flush_queue */
- 		switch (cqr->status) {
- 		case DASD_CQR_IN_IO:
-@@ -1387,90 +1279,60 @@ restart:
- 			}
- 			break;
- 		case DASD_CQR_QUEUED:
--		case DASD_CQR_ERROR:
--			/* set request to FAILED */
- 			cqr->stopclk = get_clock();
--			cqr->status = DASD_CQR_FAILED;
-+			cqr->status = DASD_CQR_CLEARED;
- 			break;
--		default: /* do not touch the others */
-+		default: /* no need to modify the others */
- 			break;
- 		}
--		/* Rechain request (including erp chain) */
--		for (i = 0; cqr != NULL; cqr = cqr->refers, i++) {
--			cqr->endclk = get_clock();
--			list_move_tail(&cqr->list, &flush_queue);
--		}
--		if (i > 1)
--			/* moved more than one request - need to restart */
--			goto restart;
-+		list_move_tail(&cqr->devlist, &flush_queue);
- 	}
+-#include "sclp.h"
+-#include "sclp_rw.h"
 -
- finished:
- 	spin_unlock_irq(get_ccwdev_lock(device->cdev));
--	/* Now call the callback function of flushed requests */
--restart_cb:
--	list_for_each_entry_safe(cqr, n, &flush_queue, list) {
--		if (cqr->status == DASD_CQR_CLEAR) {
--			/* wait for clear interrupt! */
--			wait_event(dasd_flush_wq, _wait_for_clear(cqr));
--			cqr->status = DASD_CQR_FAILED;
--		}
--		/* Process finished ERP request. */
--		if (cqr->refers) {
--			__dasd_process_erp(device, cqr);
--			/* restart list_for_xx loop since dasd_process_erp
--			 * might remove multiple elements */
--			goto restart_cb;
--		}
--		/* call the callback function */
--		cqr->endclk = get_clock();
--		if (cqr->callback != NULL)
--			(cqr->callback)(cqr, cqr->callback_data);
--	}
-+	/*
-+	 * After this point all requests must be in state CLEAR_PENDING,
-+	 * CLEARED, SUCCESS or ERROR. Now wait for CLEAR_PENDING to become
-+	 * one of the others.
-+	 */
-+	list_for_each_entry_safe(cqr, n, &flush_queue, devlist)
-+		wait_event(dasd_flush_wq,
-+			   (cqr->status != DASD_CQR_CLEAR_PENDING));
-+	/*
-+	 * Now set each request back to TERMINATED, DONE or NEED_ERP
-+	 * and call the callback function of flushed requests
-+	 */
-+	__dasd_device_process_final_queue(device, &flush_queue);
- 	return rc;
- }
- 
- /*
-  * Acquire the device lock and process queues for the device.
-  */
--static void
--dasd_tasklet(struct dasd_device * device)
-+static void dasd_device_tasklet(struct dasd_device *device)
- {
- 	struct list_head final_queue;
--	struct list_head *l, *n;
--	struct dasd_ccw_req *cqr;
- 
- 	atomic_set (&device->tasklet_scheduled, 0);
- 	INIT_LIST_HEAD(&final_queue);
- 	spin_lock_irq(get_ccwdev_lock(device->cdev));
- 	/* Check expire time of first request on the ccw queue. */
--	__dasd_check_expire(device);
--	/* Finish off requests on ccw queue */
--	__dasd_process_ccw_queue(device, &final_queue);
-+	__dasd_device_check_expire(device);
-+	/* find final requests on ccw queue */
-+	__dasd_device_process_ccw_queue(device, &final_queue);
- 	spin_unlock_irq(get_ccwdev_lock(device->cdev));
- 	/* Now call the callback function of requests with final status */
--	list_for_each_safe(l, n, &final_queue) {
--		cqr = list_entry(l, struct dasd_ccw_req, list);
--		list_del_init(&cqr->list);
--		if (cqr->callback != NULL)
--			(cqr->callback)(cqr, cqr->callback_data);
--	}
--	spin_lock_irq(&device->request_queue_lock);
--	spin_lock(get_ccwdev_lock(device->cdev));
--	/* Get new request from the block device request queue */
--	__dasd_process_blk_queue(device);
-+	__dasd_device_process_final_queue(device, &final_queue);
-+	spin_lock_irq(get_ccwdev_lock(device->cdev));
- 	/* Now check if the head of the ccw queue needs to be started. */
--	__dasd_start_head(device);
--	spin_unlock(get_ccwdev_lock(device->cdev));
--	spin_unlock_irq(&device->request_queue_lock);
-+	__dasd_device_start_head(device);
-+	spin_unlock_irq(get_ccwdev_lock(device->cdev));
- 	dasd_put_device(device);
- }
+-#define CPI_LENGTH_SYSTEM_TYPE	8
+-#define CPI_LENGTH_SYSTEM_NAME	8
+-#define CPI_LENGTH_SYSPLEX_NAME	8
+-
+-struct cpi_evbuf {
+-	struct evbuf_header header;
+-	u8	id_format;
+-	u8	reserved0;
+-	u8	system_type[CPI_LENGTH_SYSTEM_TYPE];
+-	u64	reserved1;
+-	u8	system_name[CPI_LENGTH_SYSTEM_NAME];
+-	u64	reserved2;
+-	u64	system_level;
+-	u64	reserved3;
+-	u8	sysplex_name[CPI_LENGTH_SYSPLEX_NAME];
+-	u8	reserved4[16];
+-} __attribute__((packed));
+-
+-struct cpi_sccb {
+-	struct sccb_header header;
+-	struct cpi_evbuf cpi_evbuf;
+-} __attribute__((packed));
+-
+-/* Event type structure for write message and write priority message */
+-static struct sclp_register sclp_cpi_event =
+-{
+-	.send_mask = EVTYP_CTLPROGIDENT_MASK
+-};
++#include <linux/version.h>
++#include "sclp_cpi_sys.h"
  
- /*
-  * Schedules a call to dasd_tasklet over the device tasklet.
-  */
--void
--dasd_schedule_bh(struct dasd_device * device)
-+void dasd_schedule_device_bh(struct dasd_device *device)
- {
- 	/* Protect against rescheduling. */
- 	if (atomic_cmpxchg (&device->tasklet_scheduled, 0, 1) != 0)
-@@ -1480,160 +1342,109 @@ dasd_schedule_bh(struct dasd_device * device)
- }
+ MODULE_LICENSE("GPL");
++MODULE_DESCRIPTION("Identify this operating system instance "
++		   "to the System z hardware");
++MODULE_AUTHOR("Martin Peschke <mpeschke at de.ibm.com>, "
++	      "Michael Ernst <mernst at de.ibm.com>");
  
- /*
-- * Queue a request to the head of the ccw_queue. Start the I/O if
-- * possible.
-+ * Queue a request to the head of the device ccw_queue.
-+ * Start the I/O if possible.
-  */
--void
--dasd_add_request_head(struct dasd_ccw_req *req)
-+void dasd_add_request_head(struct dasd_ccw_req *cqr)
- {
- 	struct dasd_device *device;
- 	unsigned long flags;
+-MODULE_AUTHOR(
+-	"Martin Peschke, IBM Deutschland Entwicklung GmbH "
+-	"<mpeschke at de.ibm.com>");
+-
+-MODULE_DESCRIPTION(
+-	"identify this operating system instance to the S/390 "
+-	"or zSeries hardware");
++static char *system_name = "";
++static char *sysplex_name = "";
  
--	device = req->device;
-+	device = cqr->startdev;
- 	spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
--	req->status = DASD_CQR_QUEUED;
--	req->device = device;
--	list_add(&req->list, &device->ccw_queue);
-+	cqr->status = DASD_CQR_QUEUED;
-+	list_add(&cqr->devlist, &device->ccw_queue);
- 	/* let the bh start the request to keep them in order */
--	dasd_schedule_bh(device);
-+	dasd_schedule_device_bh(device);
- 	spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
- }
+-static char *system_name = NULL;
+ module_param(system_name, charp, 0);
+ MODULE_PARM_DESC(system_name, "e.g. hostname - max. 8 characters");
+-
+-static char *sysplex_name = NULL;
+-#ifdef ALLOW_SYSPLEX_NAME
+ module_param(sysplex_name, charp, 0);
+ MODULE_PARM_DESC(sysplex_name, "if applicable - max. 8 characters");
+-#endif
+-
+-/* use default value for this field (as well as for system level) */
+-static char *system_type = "LINUX";
  
- /*
-- * Queue a request to the tail of the ccw_queue. Start the I/O if
-- * possible.
-+ * Queue a request to the tail of the device ccw_queue.
-+ * Start the I/O if possible.
-  */
--void
--dasd_add_request_tail(struct dasd_ccw_req *req)
-+void dasd_add_request_tail(struct dasd_ccw_req *cqr)
+-static int
+-cpi_check_parms(void)
++static int __init cpi_module_init(void)
  {
- 	struct dasd_device *device;
- 	unsigned long flags;
- 
--	device = req->device;
-+	device = cqr->startdev;
- 	spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
--	req->status = DASD_CQR_QUEUED;
--	req->device = device;
--	list_add_tail(&req->list, &device->ccw_queue);
-+	cqr->status = DASD_CQR_QUEUED;
-+	list_add_tail(&cqr->devlist, &device->ccw_queue);
- 	/* let the bh start the request to keep them in order */
--	dasd_schedule_bh(device);
-+	dasd_schedule_device_bh(device);
- 	spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
+-	/* reject if no system type specified */
+-	if (!system_type) {
+-		printk("cpi: bug: no system type specified\n");
+-		return -EINVAL;
+-	}
+-
+-	/* reject if system type larger than 8 characters */
+-	if (strlen(system_type) > CPI_LENGTH_SYSTEM_NAME) {
+-		printk("cpi: bug: system type has length of %li characters - "
+-		       "only %i characters supported\n",
+-		       strlen(system_type), CPI_LENGTH_SYSTEM_TYPE);
+-		return -EINVAL;
+-	}
+-
+-	/* reject if no system name specified */
+-	if (!system_name) {
+-		printk("cpi: no system name specified\n");
+-		return -EINVAL;
+-	}
+-
+-	/* reject if system name larger than 8 characters */
+-	if (strlen(system_name) > CPI_LENGTH_SYSTEM_NAME) {
+-		printk("cpi: system name has length of %li characters - "
+-		       "only %i characters supported\n",
+-		       strlen(system_name), CPI_LENGTH_SYSTEM_NAME);
+-		return -EINVAL;
+-	}
+-
+-	/* reject if specified sysplex name larger than 8 characters */
+-	if (sysplex_name && strlen(sysplex_name) > CPI_LENGTH_SYSPLEX_NAME) {
+-		printk("cpi: sysplex name has length of %li characters"
+-		       " - only %i characters supported\n",
+-		       strlen(sysplex_name), CPI_LENGTH_SYSPLEX_NAME);
+-		return -EINVAL;
+-	}
+-	return 0;
++	return sclp_cpi_set_data(system_name, sysplex_name, "LINUX",
++				 LINUX_VERSION_CODE);
  }
  
- /*
-- * Wakeup callback.
-+ * Wakeup helper for the 'sleep_on' functions.
-  */
 -static void
--dasd_wakeup_cb(struct dasd_ccw_req *cqr, void *data)
-+static void dasd_wakeup_cb(struct dasd_ccw_req *cqr, void *data)
- {
- 	wake_up((wait_queue_head_t *) data);
- }
- 
--static inline int
--_wait_for_wakeup(struct dasd_ccw_req *cqr)
-+static inline int _wait_for_wakeup(struct dasd_ccw_req *cqr)
- {
- 	struct dasd_device *device;
- 	int rc;
- 
--	device = cqr->device;
-+	device = cqr->startdev;
- 	spin_lock_irq(get_ccwdev_lock(device->cdev));
- 	rc = ((cqr->status == DASD_CQR_DONE ||
--	       cqr->status == DASD_CQR_FAILED) &&
--	      list_empty(&cqr->list));
-+	       cqr->status == DASD_CQR_NEED_ERP ||
-+	       cqr->status == DASD_CQR_TERMINATED) &&
-+	      list_empty(&cqr->devlist));
- 	spin_unlock_irq(get_ccwdev_lock(device->cdev));
- 	return rc;
- }
- 
- /*
-- * Attempts to start a special ccw queue and waits for its completion.
-+ * Queue a request to the tail of the device ccw_queue and wait for
-+ * it's completion.
-  */
--int
--dasd_sleep_on(struct dasd_ccw_req * cqr)
-+int dasd_sleep_on(struct dasd_ccw_req *cqr)
- {
- 	wait_queue_head_t wait_q;
- 	struct dasd_device *device;
- 	int rc;
- 
--	device = cqr->device;
--	spin_lock_irq(get_ccwdev_lock(device->cdev));
-+	device = cqr->startdev;
- 
- 	init_waitqueue_head (&wait_q);
- 	cqr->callback = dasd_wakeup_cb;
- 	cqr->callback_data = (void *) &wait_q;
--	cqr->status = DASD_CQR_QUEUED;
--	list_add_tail(&cqr->list, &device->ccw_queue);
+-cpi_callback(struct sclp_req *req, void *data)
+-{
+-	struct semaphore *sem;
 -
--	/* let the bh start the request to keep them in order */
--	dasd_schedule_bh(device);
+-	sem = (struct semaphore *) data;
+-	up(sem);
+-}
 -
--	spin_unlock_irq(get_ccwdev_lock(device->cdev));
+-static struct sclp_req *
+-cpi_prepare_req(void)
+-{
+-	struct sclp_req *req;
+-	struct cpi_sccb *sccb;
+-	struct cpi_evbuf *evb;
 -
-+	dasd_add_request_tail(cqr);
- 	wait_event(wait_q, _wait_for_wakeup(cqr));
- 
- 	/* Request status is either done or failed. */
--	rc = (cqr->status == DASD_CQR_FAILED) ? -EIO : 0;
-+	rc = (cqr->status == DASD_CQR_DONE) ? 0 : -EIO;
- 	return rc;
- }
- 
- /*
-- * Attempts to start a special ccw queue and wait interruptible
-- * for its completion.
-+ * Queue a request to the tail of the device ccw_queue and wait
-+ * interruptible for it's completion.
-  */
--int
--dasd_sleep_on_interruptible(struct dasd_ccw_req * cqr)
-+int dasd_sleep_on_interruptible(struct dasd_ccw_req *cqr)
- {
- 	wait_queue_head_t wait_q;
- 	struct dasd_device *device;
--	int rc, finished;
+-	req = kmalloc(sizeof(struct sclp_req), GFP_KERNEL);
+-	if (req == NULL)
+-		return ERR_PTR(-ENOMEM);
+-	sccb = (struct cpi_sccb *) __get_free_page(GFP_KERNEL | GFP_DMA);
+-	if (sccb == NULL) {
+-		kfree(req);
+-		return ERR_PTR(-ENOMEM);
+-	}
+-	memset(sccb, 0, sizeof(struct cpi_sccb));
 -
--	device = cqr->device;
--	spin_lock_irq(get_ccwdev_lock(device->cdev));
-+	int rc;
- 
-+	device = cqr->startdev;
- 	init_waitqueue_head (&wait_q);
- 	cqr->callback = dasd_wakeup_cb;
- 	cqr->callback_data = (void *) &wait_q;
--	cqr->status = DASD_CQR_QUEUED;
--	list_add_tail(&cqr->list, &device->ccw_queue);
+-	/* setup SCCB for Control-Program Identification */
+-	sccb->header.length = sizeof(struct cpi_sccb);
+-	sccb->cpi_evbuf.header.length = sizeof(struct cpi_evbuf);
+-	sccb->cpi_evbuf.header.type = 0x0B;
+-	evb = &sccb->cpi_evbuf;
 -
--	/* let the bh start the request to keep them in order */
--	dasd_schedule_bh(device);
--	spin_unlock_irq(get_ccwdev_lock(device->cdev));
+-	/* set system type */
+-	memset(evb->system_type, ' ', CPI_LENGTH_SYSTEM_TYPE);
+-	memcpy(evb->system_type, system_type, strlen(system_type));
+-	sclp_ascebc_str(evb->system_type, CPI_LENGTH_SYSTEM_TYPE);
+-	EBC_TOUPPER(evb->system_type, CPI_LENGTH_SYSTEM_TYPE);
 -
--	finished = 0;
--	while (!finished) {
--		rc = wait_event_interruptible(wait_q, _wait_for_wakeup(cqr));
--		if (rc != -ERESTARTSYS) {
--			/* Request is final (done or failed) */
--			rc = (cqr->status == DASD_CQR_DONE) ? 0 : -EIO;
--			break;
--		}
--		spin_lock_irq(get_ccwdev_lock(device->cdev));
--		switch (cqr->status) {
--		case DASD_CQR_IN_IO:
--                        /* terminate runnig cqr */
--			if (device->discipline->term_IO) {
--				cqr->retries = -1;
--				device->discipline->term_IO(cqr);
--				/* wait (non-interruptible) for final status
--				 * because signal ist still pending */
--				spin_unlock_irq(get_ccwdev_lock(device->cdev));
--				wait_event(wait_q, _wait_for_wakeup(cqr));
--				spin_lock_irq(get_ccwdev_lock(device->cdev));
--				rc = (cqr->status == DASD_CQR_DONE) ? 0 : -EIO;
--				finished = 1;
--			}
--			break;
--		case DASD_CQR_QUEUED:
--			/* request  */
--			list_del_init(&cqr->list);
--			rc = -EIO;
--			finished = 1;
--			break;
--		default:
--			/* cqr with 'non-interruptable' status - just wait */
--			break;
--		}
--		spin_unlock_irq(get_ccwdev_lock(device->cdev));
-+	dasd_add_request_tail(cqr);
-+	rc = wait_event_interruptible(wait_q, _wait_for_wakeup(cqr));
-+	if (rc == -ERESTARTSYS) {
-+		dasd_cancel_req(cqr);
-+		/* wait (non-interruptible) for final status */
-+		wait_event(wait_q, _wait_for_wakeup(cqr));
- 	}
-+	rc = (cqr->status == DASD_CQR_DONE) ? 0 : -EIO;
- 	return rc;
- }
- 
-@@ -1643,25 +1454,23 @@ dasd_sleep_on_interruptible(struct dasd_ccw_req * cqr)
-  * and be put back to status queued, before the special request is added
-  * to the head of the queue. Then the special request is waited on normally.
-  */
--static inline int
--_dasd_term_running_cqr(struct dasd_device *device)
-+static inline int _dasd_term_running_cqr(struct dasd_device *device)
- {
- 	struct dasd_ccw_req *cqr;
- 
- 	if (list_empty(&device->ccw_queue))
- 		return 0;
--	cqr = list_entry(device->ccw_queue.next, struct dasd_ccw_req, list);
-+	cqr = list_entry(device->ccw_queue.next, struct dasd_ccw_req, devlist);
- 	return device->discipline->term_IO(cqr);
- }
- 
--int
--dasd_sleep_on_immediatly(struct dasd_ccw_req * cqr)
-+int dasd_sleep_on_immediatly(struct dasd_ccw_req *cqr)
+-	/* set system name */
+-	memset(evb->system_name, ' ', CPI_LENGTH_SYSTEM_NAME);
+-	memcpy(evb->system_name, system_name, strlen(system_name));
+-	sclp_ascebc_str(evb->system_name, CPI_LENGTH_SYSTEM_NAME);
+-	EBC_TOUPPER(evb->system_name, CPI_LENGTH_SYSTEM_NAME);
+-
+-	/* set system level */
+-	evb->system_level = LINUX_VERSION_CODE;
+-
+-	/* set sysplex name */
+-	if (sysplex_name) {
+-		memset(evb->sysplex_name, ' ', CPI_LENGTH_SYSPLEX_NAME);
+-		memcpy(evb->sysplex_name, sysplex_name, strlen(sysplex_name));
+-		sclp_ascebc_str(evb->sysplex_name, CPI_LENGTH_SYSPLEX_NAME);
+-		EBC_TOUPPER(evb->sysplex_name, CPI_LENGTH_SYSPLEX_NAME);
+-	}
+-
+-	/* prepare request data structure presented to SCLP driver */
+-	req->command = SCLP_CMDW_WRITE_EVENT_DATA;
+-	req->sccb = sccb;
+-	req->status = SCLP_REQ_FILLED;
+-	req->callback = cpi_callback;
+-	return req;
+-}
+-
+-static void
+-cpi_free_req(struct sclp_req *req)
+-{
+-	free_page((unsigned long) req->sccb);
+-	kfree(req);
+-}
+-
+-static int __init
+-cpi_module_init(void)
+-{
+-	struct semaphore sem;
+-	struct sclp_req *req;
+-	int rc;
+-
+-	rc = cpi_check_parms();
+-	if (rc)
+-		return rc;
+-
+-	rc = sclp_register(&sclp_cpi_event);
+-	if (rc) {
+-		/* could not register sclp event. Die. */
+-		printk(KERN_WARNING "cpi: could not register to hardware "
+-		       "console.\n");
+-		return -EINVAL;
+-	}
+-	if (!(sclp_cpi_event.sclp_send_mask & EVTYP_CTLPROGIDENT_MASK)) {
+-		printk(KERN_WARNING "cpi: no control program identification "
+-		       "support\n");
+-		sclp_unregister(&sclp_cpi_event);
+-		return -EOPNOTSUPP;
+-	}
+-
+-	req = cpi_prepare_req();
+-	if (IS_ERR(req)) {
+-		printk(KERN_WARNING "cpi: couldn't allocate request\n");
+-		sclp_unregister(&sclp_cpi_event);
+-		return PTR_ERR(req);
+-	}
+-
+-	/* Prepare semaphore */
+-	sema_init(&sem, 0);
+-	req->callback_data = &sem;
+-	/* Add request to sclp queue */
+-	rc = sclp_add_request(req);
+-	if (rc) {
+-		printk(KERN_WARNING "cpi: could not start request\n");
+-		cpi_free_req(req);
+-		sclp_unregister(&sclp_cpi_event);
+-		return rc;
+-	}
+-	/* make "insmod" sleep until callback arrives */
+-	down(&sem);
+-
+-	rc = ((struct cpi_sccb *) req->sccb)->header.response_code;
+-	if (rc != 0x0020) {
+-		printk(KERN_WARNING "cpi: failed with response code 0x%x\n",
+-		       rc);
+-		rc = -ECOMM;
+-	} else
+-		rc = 0;
+-
+-	cpi_free_req(req);
+-	sclp_unregister(&sclp_cpi_event);
+-
+-	return rc;
+-}
+-
+-
+ static void __exit cpi_module_exit(void)
  {
- 	wait_queue_head_t wait_q;
- 	struct dasd_device *device;
- 	int rc;
- 
--	device = cqr->device;
-+	device = cqr->startdev;
- 	spin_lock_irq(get_ccwdev_lock(device->cdev));
- 	rc = _dasd_term_running_cqr(device);
- 	if (rc) {
-@@ -1673,17 +1482,17 @@ dasd_sleep_on_immediatly(struct dasd_ccw_req * cqr)
- 	cqr->callback = dasd_wakeup_cb;
- 	cqr->callback_data = (void *) &wait_q;
- 	cqr->status = DASD_CQR_QUEUED;
--	list_add(&cqr->list, &device->ccw_queue);
-+	list_add(&cqr->devlist, &device->ccw_queue);
- 
- 	/* let the bh start the request to keep them in order */
--	dasd_schedule_bh(device);
-+	dasd_schedule_device_bh(device);
- 
- 	spin_unlock_irq(get_ccwdev_lock(device->cdev));
- 
- 	wait_event(wait_q, _wait_for_wakeup(cqr));
- 
- 	/* Request status is either done or failed. */
--	rc = (cqr->status == DASD_CQR_FAILED) ? -EIO : 0;
-+	rc = (cqr->status == DASD_CQR_DONE) ? 0 : -EIO;
- 	return rc;
  }
  
-@@ -1692,11 +1501,14 @@ dasd_sleep_on_immediatly(struct dasd_ccw_req * cqr)
-  * This is useful to timeout requests. The request will be
-  * terminated if it is currently in i/o.
-  * Returns 1 if the request has been terminated.
-+ *	   0 if there was no need to terminate the request (not started yet)
-+ *	   negative error code if termination failed
-+ * Cancellation of a request is an asynchronous operation! The calling
-+ * function has to wait until the request is properly returned via callback.
-  */
--int
--dasd_cancel_req(struct dasd_ccw_req *cqr)
-+int dasd_cancel_req(struct dasd_ccw_req *cqr)
- {
--	struct dasd_device *device = cqr->device;
-+	struct dasd_device *device = cqr->startdev;
- 	unsigned long flags;
- 	int rc;
- 
-@@ -1704,74 +1516,453 @@ dasd_cancel_req(struct dasd_ccw_req *cqr)
- 	spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
- 	switch (cqr->status) {
- 	case DASD_CQR_QUEUED:
--		/* request was not started - just set to failed */
--		cqr->status = DASD_CQR_FAILED;
-+		/* request was not started - just set to cleared */
-+		cqr->status = DASD_CQR_CLEARED;
- 		break;
- 	case DASD_CQR_IN_IO:
- 		/* request in IO - terminate IO and release again */
--		if (device->discipline->term_IO(cqr) != 0)
--			/* what to do if unable to terminate ??????
--			   e.g. not _IN_IO */
--			cqr->status = DASD_CQR_FAILED;
--		cqr->stopclk = get_clock();
--		rc = 1;
-+		rc = device->discipline->term_IO(cqr);
-+		if (rc) {
-+			DEV_MESSAGE(KERN_ERR, device,
-+				    "dasd_cancel_req is unable "
-+				    " to terminate request %p, rc = %d",
-+				    cqr, rc);
-+		} else {
-+			cqr->stopclk = get_clock();
-+			rc = 1;
-+		}
- 		break;
--	case DASD_CQR_DONE:
--	case DASD_CQR_FAILED:
--		/* already finished - do nothing */
-+	default: /* already finished or clear pending - do nothing */
- 		break;
--	default:
--		DEV_MESSAGE(KERN_ALERT, device,
--			    "invalid status %02x in request",
--			    cqr->status);
-+	}
-+	spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
-+	dasd_schedule_device_bh(device);
-+	return rc;
+-
+-/* declare driver module init/cleanup functions */
+ module_init(cpi_module_init);
+ module_exit(cpi_module_exit);
+-
+diff --git a/drivers/s390/char/sclp_cpi_sys.c b/drivers/s390/char/sclp_cpi_sys.c
+new file mode 100644
+index 0000000..4161703
+--- /dev/null
++++ b/drivers/s390/char/sclp_cpi_sys.c
+@@ -0,0 +1,400 @@
++/*
++ *  drivers/s390/char/sclp_cpi_sys.c
++ *    SCLP control program identification sysfs interface
++ *
++ *    Copyright IBM Corp. 2001, 2007
++ *    Author(s): Martin Peschke <mpeschke at de.ibm.com>
++ *		 Michael Ernst <mernst at de.ibm.com>
++ */
++
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/stat.h>
++#include <linux/device.h>
++#include <linux/string.h>
++#include <linux/ctype.h>
++#include <linux/kmod.h>
++#include <linux/timer.h>
++#include <linux/err.h>
++#include <linux/slab.h>
++#include <linux/completion.h>
++#include <asm/ebcdic.h>
++#include <asm/sclp.h>
++#include "sclp.h"
++#include "sclp_rw.h"
++#include "sclp_cpi_sys.h"
++
++#define CPI_LENGTH_NAME 8
++#define CPI_LENGTH_LEVEL 16
++
++struct cpi_evbuf {
++	struct evbuf_header header;
++	u8	id_format;
++	u8	reserved0;
++	u8	system_type[CPI_LENGTH_NAME];
++	u64	reserved1;
++	u8	system_name[CPI_LENGTH_NAME];
++	u64	reserved2;
++	u64	system_level;
++	u64	reserved3;
++	u8	sysplex_name[CPI_LENGTH_NAME];
++	u8	reserved4[16];
++} __attribute__((packed));
++
++struct cpi_sccb {
++	struct sccb_header header;
++	struct cpi_evbuf cpi_evbuf;
++} __attribute__((packed));
++
++static struct sclp_register sclp_cpi_event = {
++	.send_mask = EVTYP_CTLPROGIDENT_MASK,
++};
++
++static char system_name[CPI_LENGTH_NAME + 1];
++static char sysplex_name[CPI_LENGTH_NAME + 1];
++static char system_type[CPI_LENGTH_NAME + 1];
++static u64 system_level;
++
++static void set_data(char *field, char *data)
++{
++	memset(field, ' ', CPI_LENGTH_NAME);
++	memcpy(field, data, strlen(data));
++	sclp_ascebc_str(field, CPI_LENGTH_NAME);
 +}
 +
++static void cpi_callback(struct sclp_req *req, void *data)
++{
++	struct completion *completion = data;
 +
-+/*
-+ * SECTION: Operations of the dasd_block layer.
-+ */
++	complete(completion);
++}
 +
-+/*
-+ * Timeout function for dasd_block. This is used when the block layer
-+ * is waiting for something that may not come reliably, (e.g. a state
-+ * change interrupt)
-+ */
-+static void dasd_block_timeout(unsigned long ptr)
++static struct sclp_req *cpi_prepare_req(void)
 +{
-+	unsigned long flags;
-+	struct dasd_block *block;
++	struct sclp_req *req;
++	struct cpi_sccb *sccb;
++	struct cpi_evbuf *evb;
 +
-+	block = (struct dasd_block *) ptr;
-+	spin_lock_irqsave(get_ccwdev_lock(block->base->cdev), flags);
-+	/* re-activate request queue */
-+	block->base->stopped &= ~DASD_STOPPED_PENDING;
-+	spin_unlock_irqrestore(get_ccwdev_lock(block->base->cdev), flags);
-+	dasd_schedule_block_bh(block);
++	req = kzalloc(sizeof(struct sclp_req), GFP_KERNEL);
++	if (!req)
++		return ERR_PTR(-ENOMEM);
++	sccb = (struct cpi_sccb *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
++	if (!sccb) {
++		kfree(req);
++		return ERR_PTR(-ENOMEM);
++	}
++
++	/* setup SCCB for Control-Program Identification */
++	sccb->header.length = sizeof(struct cpi_sccb);
++	sccb->cpi_evbuf.header.length = sizeof(struct cpi_evbuf);
++	sccb->cpi_evbuf.header.type = 0x0b;
++	evb = &sccb->cpi_evbuf;
++
++	/* set system type */
++	set_data(evb->system_type, system_type);
++
++	/* set system name */
++	set_data(evb->system_name, system_name);
++
++	/* set sytem level */
++	evb->system_level = system_level;
++
++	/* set sysplex name */
++	set_data(evb->sysplex_name, sysplex_name);
++
++	/* prepare request data structure presented to SCLP driver */
++	req->command = SCLP_CMDW_WRITE_EVENT_DATA;
++	req->sccb = sccb;
++	req->status = SCLP_REQ_FILLED;
++	req->callback = cpi_callback;
++	return req;
 +}
 +
-+/*
-+ * Setup timeout for a dasd_block in jiffies.
-+ */
-+void dasd_block_set_timer(struct dasd_block *block, int expires)
++static void cpi_free_req(struct sclp_req *req)
 +{
-+	if (expires == 0) {
-+		if (timer_pending(&block->timer))
-+			del_timer(&block->timer);
-+		return;
++	free_page((unsigned long) req->sccb);
++	kfree(req);
++}
++
++static int cpi_req(void)
++{
++	struct completion completion;
++	struct sclp_req *req;
++	int rc;
++	int response;
++
++	rc = sclp_register(&sclp_cpi_event);
++	if (rc) {
++		printk(KERN_WARNING "cpi: could not register "
++			"to hardware console.\n");
++		goto out;
 +	}
-+	if (timer_pending(&block->timer)) {
-+		if (mod_timer(&block->timer, jiffies + expires))
-+			return;
++	if (!(sclp_cpi_event.sclp_send_mask & EVTYP_CTLPROGIDENT_MASK)) {
++		printk(KERN_WARNING "cpi: no control program "
++			"identification support\n");
++		rc = -EOPNOTSUPP;
++		goto out_unregister;
 +	}
-+	block->timer.function = dasd_block_timeout;
-+	block->timer.data = (unsigned long) block;
-+	block->timer.expires = jiffies + expires;
-+	add_timer(&block->timer);
++
++	req = cpi_prepare_req();
++	if (IS_ERR(req)) {
++		printk(KERN_WARNING "cpi: could not allocate request\n");
++		rc = PTR_ERR(req);
++		goto out_unregister;
++	}
++
++	init_completion(&completion);
++	req->callback_data = &completion;
++
++	/* Add request to sclp queue */
++	rc = sclp_add_request(req);
++	if (rc) {
++		printk(KERN_WARNING "cpi: could not start request\n");
++		goto out_free_req;
++	}
++
++	wait_for_completion(&completion);
++
++	if (req->status != SCLP_REQ_DONE) {
++		printk(KERN_WARNING "cpi: request failed (status=0x%02x)\n",
++			req->status);
++		rc = -EIO;
++		goto out_free_req;
++	}
++
++	response = ((struct cpi_sccb *) req->sccb)->header.response_code;
++	if (response != 0x0020) {
++		printk(KERN_WARNING "cpi: failed with "
++			"response code 0x%x\n", response);
++		rc = -EIO;
++	}
++
++out_free_req:
++	cpi_free_req(req);
++
++out_unregister:
++	sclp_unregister(&sclp_cpi_event);
++
++out:
++	return rc;
 +}
 +
-+/*
-+ * Clear timeout for a dasd_block.
-+ */
-+void dasd_block_clear_timer(struct dasd_block *block)
++static int check_string(const char *attr, const char *str)
++{
++	size_t len;
++	size_t i;
++
++	len = strlen(str);
++
++	if ((len > 0) && (str[len - 1] == '\n'))
++		len--;
++
++	if (len > CPI_LENGTH_NAME)
++		return -EINVAL;
++
++	for (i = 0; i < len ; i++) {
++		if (isalpha(str[i]) || isdigit(str[i]) ||
++		    strchr("$@# ", str[i]))
++			continue;
++		return -EINVAL;
++	}
++
++	return 0;
++}
++
++static void set_string(char *attr, const char *value)
++{
++	size_t len;
++	size_t i;
++
++	len = strlen(value);
++
++	if ((len > 0) && (value[len - 1] == '\n'))
++		len--;
++
++	for (i = 0; i < CPI_LENGTH_NAME; i++) {
++		if (i < len)
++			attr[i] = toupper(value[i]);
++		else
++			attr[i] = ' ';
++	}
++}
++
++static ssize_t system_name_show(struct kobject *kobj,
++				struct kobj_attribute *attr, char *page)
++{
++	return snprintf(page, PAGE_SIZE, "%s\n", system_name);
++}
++
++static ssize_t system_name_store(struct kobject *kobj,
++				 struct kobj_attribute *attr,
++				 const char *buf,
++	size_t len)
++{
++	int rc;
++
++	rc = check_string("system_name", buf);
++	if (rc)
++		return rc;
++
++	set_string(system_name, buf);
++
++	return len;
++}
++
++static struct kobj_attribute system_name_attr =
++	__ATTR(system_name, 0644, system_name_show, system_name_store);
++
++static ssize_t sysplex_name_show(struct kobject *kobj,
++				 struct kobj_attribute *attr, char *page)
 +{
-+	if (timer_pending(&block->timer))
-+		del_timer(&block->timer);
++	return snprintf(page, PAGE_SIZE, "%s\n", sysplex_name);
 +}
 +
-+/*
-+ * posts the buffer_cache about a finalized request
-+ */
-+static inline void dasd_end_request(struct request *req, int uptodate)
++static ssize_t sysplex_name_store(struct kobject *kobj,
++				  struct kobj_attribute *attr,
++				  const char *buf,
++	size_t len)
 +{
-+	if (end_that_request_first(req, uptodate, req->hard_nr_sectors))
- 		BUG();
-+	add_disk_randomness(req->rq_disk);
-+	end_that_request_last(req, uptodate);
++	int rc;
++
++	rc = check_string("sysplex_name", buf);
++	if (rc)
++		return rc;
++
++	set_string(sysplex_name, buf);
++
++	return len;
 +}
 +
-+/*
-+ * Process finished error recovery ccw.
-+ */
-+static inline void __dasd_block_process_erp(struct dasd_block *block,
-+					    struct dasd_ccw_req *cqr)
++static struct kobj_attribute sysplex_name_attr =
++	__ATTR(sysplex_name, 0644, sysplex_name_show, sysplex_name_store);
++
++static ssize_t system_type_show(struct kobject *kobj,
++				struct kobj_attribute *attr, char *page)
 +{
-+	dasd_erp_fn_t erp_fn;
-+	struct dasd_device *device = block->base;
- 
-+	if (cqr->status == DASD_CQR_DONE)
-+		DBF_DEV_EVENT(DBF_NOTICE, device, "%s", "ERP successful");
-+	else
-+		DEV_MESSAGE(KERN_ERR, device, "%s", "ERP unsuccessful");
-+	erp_fn = device->discipline->erp_postaction(cqr);
-+	erp_fn(cqr);
++	return snprintf(page, PAGE_SIZE, "%s\n", system_type);
 +}
 +
-+/*
-+ * Fetch requests from the block device queue.
-+ */
-+static void __dasd_process_request_queue(struct dasd_block *block)
++static ssize_t system_type_store(struct kobject *kobj,
++				 struct kobj_attribute *attr,
++				 const char *buf,
++	size_t len)
 +{
-+	struct request_queue *queue;
-+	struct request *req;
-+	struct dasd_ccw_req *cqr;
-+	struct dasd_device *basedev;
-+	unsigned long flags;
-+	queue = block->request_queue;
-+	basedev = block->base;
-+	/* No queue ? Then there is nothing to do. */
-+	if (queue == NULL)
-+		return;
++	int rc;
 +
-+	/*
-+	 * We requeue request from the block device queue to the ccw
-+	 * queue only in two states. In state DASD_STATE_READY the
-+	 * partition detection is done and we need to requeue requests
-+	 * for that. State DASD_STATE_ONLINE is normal block device
-+	 * operation.
-+	 */
-+	if (basedev->state < DASD_STATE_READY)
-+		return;
-+	/* Now we try to fetch requests from the request queue */
-+	while (!blk_queue_plugged(queue) &&
-+	       elv_next_request(queue)) {
++	rc = check_string("system_type", buf);
++	if (rc)
++		return rc;
 +
-+		req = elv_next_request(queue);
++	set_string(system_type, buf);
 +
-+		if (basedev->features & DASD_FEATURE_READONLY &&
-+		    rq_data_dir(req) == WRITE) {
-+			DBF_DEV_EVENT(DBF_ERR, basedev,
-+				      "Rejecting write request %p",
-+				      req);
-+			blkdev_dequeue_request(req);
-+			dasd_end_request(req, 0);
-+			continue;
-+		}
-+		cqr = basedev->discipline->build_cp(basedev, block, req);
-+		if (IS_ERR(cqr)) {
-+			if (PTR_ERR(cqr) == -EBUSY)
-+				break;	/* normal end condition */
-+			if (PTR_ERR(cqr) == -ENOMEM)
-+				break;	/* terminate request queue loop */
-+			if (PTR_ERR(cqr) == -EAGAIN) {
-+				/*
-+				 * The current request cannot be build right
-+				 * now, we have to try later. If this request
-+				 * is the head-of-queue we stop the device
-+				 * for 1/2 second.
-+				 */
-+				if (!list_empty(&block->ccw_queue))
-+					break;
-+				spin_lock_irqsave(get_ccwdev_lock(basedev->cdev), flags);
-+				basedev->stopped |= DASD_STOPPED_PENDING;
-+				spin_unlock_irqrestore(get_ccwdev_lock(basedev->cdev), flags);
-+				dasd_block_set_timer(block, HZ/2);
-+				break;
-+			}
-+			DBF_DEV_EVENT(DBF_ERR, basedev,
-+				      "CCW creation failed (rc=%ld) "
-+				      "on request %p",
-+				      PTR_ERR(cqr), req);
-+			blkdev_dequeue_request(req);
-+			dasd_end_request(req, 0);
-+			continue;
-+		}
-+		/*
-+		 *  Note: callback is set to dasd_return_cqr_cb in
-+		 * __dasd_block_start_head to cover erp requests as well
-+		 */
-+		cqr->callback_data = (void *) req;
-+		cqr->status = DASD_CQR_FILLED;
-+		blkdev_dequeue_request(req);
-+		list_add_tail(&cqr->blocklist, &block->ccw_queue);
-+		dasd_profile_start(block, cqr, req);
-+	}
++	return len;
 +}
 +
-+static void __dasd_cleanup_cqr(struct dasd_ccw_req *cqr)
++static struct kobj_attribute system_type_attr =
++	__ATTR(system_type, 0644, system_type_show, system_type_store);
++
++static ssize_t system_level_show(struct kobject *kobj,
++				 struct kobj_attribute *attr, char *page)
 +{
-+	struct request *req;
-+	int status;
++	unsigned long long level = system_level;
 +
-+	req = (struct request *) cqr->callback_data;
-+	dasd_profile_end(cqr->block, cqr, req);
-+	status = cqr->memdev->discipline->free_cp(cqr, req);
-+	dasd_end_request(req, status);
++	return snprintf(page, PAGE_SIZE, "%#018llx\n", level);
 +}
 +
-+/*
-+ * Process ccw request queue.
-+ */
-+static void __dasd_process_block_ccw_queue(struct dasd_block *block,
-+					   struct list_head *final_queue)
++static ssize_t system_level_store(struct kobject *kobj,
++				  struct kobj_attribute *attr,
++				  const char *buf,
++	size_t len)
 +{
-+	struct list_head *l, *n;
-+	struct dasd_ccw_req *cqr;
-+	dasd_erp_fn_t erp_fn;
-+	unsigned long flags;
-+	struct dasd_device *base = block->base;
++	unsigned long long level;
++	char *endp;
 +
-+restart:
-+	/* Process request with final status. */
-+	list_for_each_safe(l, n, &block->ccw_queue) {
-+		cqr = list_entry(l, struct dasd_ccw_req, blocklist);
-+		if (cqr->status != DASD_CQR_DONE &&
-+		    cqr->status != DASD_CQR_FAILED &&
-+		    cqr->status != DASD_CQR_NEED_ERP &&
-+		    cqr->status != DASD_CQR_TERMINATED)
-+			continue;
++	level = simple_strtoull(buf, &endp, 16);
 +
-+		if (cqr->status == DASD_CQR_TERMINATED) {
-+			base->discipline->handle_terminated_request(cqr);
-+			goto restart;
-+		}
++	if (endp == buf)
++		return -EINVAL;
++	if (*endp == '\n')
++		endp++;
++	if (*endp)
++		return -EINVAL;
 +
-+		/*  Process requests that may be recovered */
-+		if (cqr->status == DASD_CQR_NEED_ERP) {
-+			if (cqr->irb.esw.esw0.erw.cons &&
-+			    test_bit(DASD_CQR_FLAGS_USE_ERP,
-+				     &cqr->flags)) {
-+				erp_fn = base->discipline->erp_action(cqr);
-+				erp_fn(cqr);
-+			}
-+			goto restart;
-+		}
++	system_level = level;
 +
-+		/* First of all call extended error reporting. */
-+		if (dasd_eer_enabled(base) &&
-+		    cqr->status == DASD_CQR_FAILED) {
-+			dasd_eer_write(base, cqr, DASD_EER_FATALERROR);
++	return len;
++}
 +
-+			/* restart request  */
-+			cqr->status = DASD_CQR_FILLED;
-+			cqr->retries = 255;
-+			spin_lock_irqsave(get_ccwdev_lock(base->cdev), flags);
-+			base->stopped |= DASD_STOPPED_QUIESCE;
-+			spin_unlock_irqrestore(get_ccwdev_lock(base->cdev),
-+					       flags);
-+			goto restart;
-+		}
++static struct kobj_attribute system_level_attr =
++	__ATTR(system_level, 0644, system_level_show, system_level_store);
 +
-+		/* Process finished ERP request. */
-+		if (cqr->refers) {
-+			__dasd_block_process_erp(block, cqr);
-+			goto restart;
-+		}
++static ssize_t set_store(struct kobject *kobj,
++			 struct kobj_attribute *attr,
++			 const char *buf, size_t len)
++{
++	int rc;
 +
-+		/* Rechain finished requests to final queue */
-+		cqr->endclk = get_clock();
-+		list_move_tail(&cqr->blocklist, final_queue);
-+	}
-+}
++	rc = cpi_req();
++	if (rc)
++		return rc;
 +
-+static void dasd_return_cqr_cb(struct dasd_ccw_req *cqr, void *data)
-+{
-+	dasd_schedule_block_bh(cqr->block);
++	return len;
 +}
 +
-+static void __dasd_block_start_head(struct dasd_block *block)
-+{
-+	struct dasd_ccw_req *cqr;
-+
-+	if (list_empty(&block->ccw_queue))
-+		return;
-+	/* We allways begin with the first requests on the queue, as some
-+	 * of previously started requests have to be enqueued on a
-+	 * dasd_device again for error recovery.
-+	 */
-+	list_for_each_entry(cqr, &block->ccw_queue, blocklist) {
-+		if (cqr->status != DASD_CQR_FILLED)
-+			continue;
-+		/* Non-temporary stop condition will trigger fail fast */
-+		if (block->base->stopped & ~DASD_STOPPED_PENDING &&
-+		    test_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags) &&
-+		    (!dasd_eer_enabled(block->base))) {
-+			cqr->status = DASD_CQR_FAILED;
-+			dasd_schedule_block_bh(block);
-+			continue;
-+		}
-+		/* Don't try to start requests if device is stopped */
-+		if (block->base->stopped)
-+			return;
++static struct kobj_attribute set_attr = __ATTR(set, 0200, NULL, set_store);
 +
-+		/* just a fail safe check, should not happen */
-+		if (!cqr->startdev)
-+			cqr->startdev = block->base;
++static struct attribute *cpi_attrs[] = {
++	&system_name_attr.attr,
++	&sysplex_name_attr.attr,
++	&system_type_attr.attr,
++	&system_level_attr.attr,
++	&set_attr.attr,
++	NULL,
++};
 +
-+		/* make sure that the requests we submit find their way back */
-+		cqr->callback = dasd_return_cqr_cb;
++static struct attribute_group cpi_attr_group = {
++	.attrs = cpi_attrs,
++};
 +
-+		dasd_add_request_tail(cqr);
-+	}
-+}
++static struct kset *cpi_kset;
 +
-+/*
-+ * Central dasd_block layer routine. Takes requests from the generic
-+ * block layer request queue, creates ccw requests, enqueues them on
-+ * a dasd_device and processes ccw requests that have been returned.
-+ */
-+static void dasd_block_tasklet(struct dasd_block *block)
++int sclp_cpi_set_data(const char *system, const char *sysplex, const char *type,
++		      const u64 level)
 +{
-+	struct list_head final_queue;
-+	struct list_head *l, *n;
-+	struct dasd_ccw_req *cqr;
++	int rc;
 +
-+	atomic_set(&block->tasklet_scheduled, 0);
-+	INIT_LIST_HEAD(&final_queue);
-+	spin_lock(&block->queue_lock);
-+	/* Finish off requests on ccw queue */
-+	__dasd_process_block_ccw_queue(block, &final_queue);
-+	spin_unlock(&block->queue_lock);
-+	/* Now call the callback function of requests with final status */
-+	spin_lock_irq(&block->request_queue_lock);
-+	list_for_each_safe(l, n, &final_queue) {
-+		cqr = list_entry(l, struct dasd_ccw_req, blocklist);
-+		list_del_init(&cqr->blocklist);
-+		__dasd_cleanup_cqr(cqr);
-+	}
-+	spin_lock(&block->queue_lock);
-+	/* Get new request from the block device request queue */
-+	__dasd_process_request_queue(block);
-+	/* Now check if the head of the ccw queue needs to be started. */
-+	__dasd_block_start_head(block);
-+	spin_unlock(&block->queue_lock);
-+	spin_unlock_irq(&block->request_queue_lock);
-+	dasd_put_device(block->base);
++	rc = check_string("system_name", system);
++	if (rc)
++		return rc;
++	rc = check_string("sysplex_name", sysplex);
++	if (rc)
++		return rc;
++	rc = check_string("system_type", type);
++	if (rc)
++		return rc;
++
++	set_string(system_name, system);
++	set_string(sysplex_name, sysplex);
++	set_string(system_type, type);
++	system_level = level;
++
++	return cpi_req();
 +}
++EXPORT_SYMBOL(sclp_cpi_set_data);
 +
-+static void _dasd_wake_block_flush_cb(struct dasd_ccw_req *cqr, void *data)
++static int __init cpi_init(void)
 +{
-+	wake_up(&dasd_flush_wq);
++	int rc;
++
++	cpi_kset = kset_create_and_add("cpi", NULL, firmware_kobj);
++	if (!cpi_kset)
++		return -ENOMEM;
++
++	rc = sysfs_create_group(&cpi_kset->kobj, &cpi_attr_group);
++	if (rc)
++		kset_unregister(cpi_kset);
++
++	return rc;
 +}
 +
++__initcall(cpi_init);
+diff --git a/drivers/s390/char/sclp_cpi_sys.h b/drivers/s390/char/sclp_cpi_sys.h
+new file mode 100644
+index 0000000..deef3e6
+--- /dev/null
++++ b/drivers/s390/char/sclp_cpi_sys.h
+@@ -0,0 +1,15 @@
 +/*
-+ * Go through all request on the dasd_block request queue, cancel them
-+ * on the respective dasd_device, and return them to the generic
-+ * block layer.
++ *  drivers/s390/char/sclp_cpi_sys.h
++ *    SCLP control program identification sysfs interface
++ *
++ *    Copyright IBM Corp. 2007
++ *    Author(s): Michael Ernst <mernst at de.ibm.com>
 + */
-+static int dasd_flush_block_queue(struct dasd_block *block)
-+{
-+	struct dasd_ccw_req *cqr, *n;
-+	int rc, i;
-+	struct list_head flush_queue;
 +
-+	INIT_LIST_HEAD(&flush_queue);
-+	spin_lock_bh(&block->queue_lock);
-+	rc = 0;
-+restart:
-+	list_for_each_entry_safe(cqr, n, &block->ccw_queue, blocklist) {
-+		/* if this request currently owned by a dasd_device cancel it */
-+		if (cqr->status >= DASD_CQR_QUEUED)
-+			rc = dasd_cancel_req(cqr);
-+		if (rc < 0)
-+			break;
-+		/* Rechain request (including erp chain) so it won't be
-+		 * touched by the dasd_block_tasklet anymore.
-+		 * Replace the callback so we notice when the request
-+		 * is returned from the dasd_device layer.
-+		 */
-+		cqr->callback = _dasd_wake_block_flush_cb;
-+		for (i = 0; cqr != NULL; cqr = cqr->refers, i++)
-+			list_move_tail(&cqr->blocklist, &flush_queue);
-+		if (i > 1)
-+			/* moved more than one request - need to restart */
-+			goto restart;
-+	}
-+	spin_unlock_bh(&block->queue_lock);
-+	/* Now call the callback function of flushed requests */
-+restart_cb:
-+	list_for_each_entry_safe(cqr, n, &flush_queue, blocklist) {
-+		wait_event(dasd_flush_wq, (cqr->status < DASD_CQR_QUEUED));
-+		/* Process finished ERP request. */
-+		if (cqr->refers) {
-+			__dasd_block_process_erp(block, cqr);
-+			/* restart list_for_xx loop since dasd_process_erp
-+			 * might remove multiple elements */
-+			goto restart_cb;
-+		}
-+		/* call the callback function */
-+		cqr->endclk = get_clock();
-+		list_del_init(&cqr->blocklist);
-+		__dasd_cleanup_cqr(cqr);
- 	}
--	spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
--	dasd_schedule_bh(device);
- 	return rc;
- }
- 
- /*
-- * SECTION: Block device operations (request queue, partitions, open, release).
-+ * Schedules a call to dasd_tasklet over the device tasklet.
-+ */
-+void dasd_schedule_block_bh(struct dasd_block *block)
-+{
-+	/* Protect against rescheduling. */
-+	if (atomic_cmpxchg(&block->tasklet_scheduled, 0, 1) != 0)
-+		return;
-+	/* life cycle of block is bound to it's base device */
-+	dasd_get_device(block->base);
-+	tasklet_hi_schedule(&block->tasklet);
-+}
++#ifndef __SCLP_CPI_SYS_H__
++#define __SCLP_CPI_SYS_H__
 +
++int sclp_cpi_set_data(const char *system, const char *sysplex,
++		      const char *type, u64 level);
 +
-+/*
-+ * SECTION: external block device operations
-+ * (request queue handling, open, release, etc.)
-  */
++#endif	 /* __SCLP_CPI_SYS_H__ */
+diff --git a/drivers/s390/char/sclp_info.c b/drivers/s390/char/sclp_info.c
+deleted file mode 100644
+index a1136e0..0000000
+--- a/drivers/s390/char/sclp_info.c
++++ /dev/null
+@@ -1,116 +0,0 @@
+-/*
+- *  drivers/s390/char/sclp_info.c
+- *
+- *    Copyright IBM Corp. 2007
+- *    Author(s): Heiko Carstens <heiko.carstens at de.ibm.com>
+- */
+-
+-#include <linux/init.h>
+-#include <linux/errno.h>
+-#include <linux/string.h>
+-#include <asm/sclp.h>
+-#include "sclp.h"
+-
+-struct sclp_readinfo_sccb {
+-	struct	sccb_header header;	/* 0-7 */
+-	u16	rnmax;			/* 8-9 */
+-	u8	rnsize;			/* 10 */
+-	u8	_reserved0[24 - 11];	/* 11-23 */
+-	u8	loadparm[8];		/* 24-31 */
+-	u8	_reserved1[48 - 32];	/* 32-47 */
+-	u64	facilities;		/* 48-55 */
+-	u8	_reserved2[91 - 56];	/* 56-90 */
+-	u8	flags;			/* 91 */
+-	u8	_reserved3[100 - 92];	/* 92-99 */
+-	u32	rnsize2;		/* 100-103 */
+-	u64	rnmax2;			/* 104-111 */
+-	u8	_reserved4[4096 - 112];	/* 112-4095 */
+-} __attribute__((packed, aligned(4096)));
+-
+-static struct sclp_readinfo_sccb __initdata early_readinfo_sccb;
+-static int __initdata early_readinfo_sccb_valid;
+-
+-u64 sclp_facilities;
+-
+-void __init sclp_readinfo_early(void)
+-{
+-	int ret;
+-	int i;
+-	struct sclp_readinfo_sccb *sccb;
+-	sclp_cmdw_t commands[] = {SCLP_CMDW_READ_SCP_INFO_FORCED,
+-				  SCLP_CMDW_READ_SCP_INFO};
+-
+-	/* Enable service signal subclass mask. */
+-	__ctl_set_bit(0, 9);
+-	sccb = &early_readinfo_sccb;
+-	for (i = 0; i < ARRAY_SIZE(commands); i++) {
+-		do {
+-			memset(sccb, 0, sizeof(*sccb));
+-			sccb->header.length = sizeof(*sccb);
+-			sccb->header.control_mask[2] = 0x80;
+-			ret = sclp_service_call(commands[i], sccb);
+-		} while (ret == -EBUSY);
+-
+-		if (ret)
+-			break;
+-		__load_psw_mask(PSW_BASE_BITS | PSW_MASK_EXT |
+-				PSW_MASK_WAIT | PSW_DEFAULT_KEY);
+-		local_irq_disable();
+-		/*
+-		 * Contents of the sccb might have changed
+-		 * therefore a barrier is needed.
+-		 */
+-		barrier();
+-		if (sccb->header.response_code == 0x10) {
+-			early_readinfo_sccb_valid = 1;
+-			break;
+-		}
+-		if (sccb->header.response_code != 0x1f0)
+-			break;
+-	}
+-	/* Disable service signal subclass mask again. */
+-	__ctl_clear_bit(0, 9);
+-}
+-
+-void __init sclp_facilities_detect(void)
+-{
+-	if (!early_readinfo_sccb_valid)
+-		return;
+-	sclp_facilities = early_readinfo_sccb.facilities;
+-}
+-
+-unsigned long long __init sclp_memory_detect(void)
+-{
+-	unsigned long long memsize;
+-	struct sclp_readinfo_sccb *sccb;
+-
+-	if (!early_readinfo_sccb_valid)
+-		return 0;
+-	sccb = &early_readinfo_sccb;
+-	if (sccb->rnsize)
+-		memsize = sccb->rnsize << 20;
+-	else
+-		memsize = sccb->rnsize2 << 20;
+-	if (sccb->rnmax)
+-		memsize *= sccb->rnmax;
+-	else
+-		memsize *= sccb->rnmax2;
+-	return memsize;
+-}
+-
+-/*
+- * This function will be called after sclp_memory_detect(), which gets called
+- * early from early.c code. Therefore the sccb should have valid contents.
+- */
+-void __init sclp_get_ipl_info(struct sclp_ipl_info *info)
+-{
+-	struct sclp_readinfo_sccb *sccb;
+-
+-	if (!early_readinfo_sccb_valid)
+-		return;
+-	sccb = &early_readinfo_sccb;
+-	info->is_valid = 1;
+-	if (sccb->flags & 0x2)
+-		info->has_dump = 1;
+-	memcpy(&info->loadparm, &sccb->loadparm, LOADPARM_LEN);
+-}
+diff --git a/drivers/s390/char/sclp_rw.c b/drivers/s390/char/sclp_rw.c
+index d6b06ab..ad7195d 100644
+--- a/drivers/s390/char/sclp_rw.c
++++ b/drivers/s390/char/sclp_rw.c
+@@ -76,7 +76,7 @@ sclp_make_buffer(void *page, unsigned short columns, unsigned short htab)
+ }
  
  /*
-  * Dasd request queue function. Called from ll_rw_blk.c
+- * Return a pointer to the orignal page that has been used to create
++ * Return a pointer to the original page that has been used to create
+  * the buffer.
   */
--static void
--do_dasd_request(struct request_queue * queue)
-+static void do_dasd_request(struct request_queue *queue)
+ void *
+diff --git a/drivers/s390/char/tape_3590.c b/drivers/s390/char/tape_3590.c
+index da25f8e..8246ef3 100644
+--- a/drivers/s390/char/tape_3590.c
++++ b/drivers/s390/char/tape_3590.c
+@@ -1495,7 +1495,7 @@ tape_3590_unit_check(struct tape_device *device, struct tape_request *request,
+ 			   device->cdev->dev.bus_id);
+ 		return tape_3590_erp_basic(device, request, irb, -EPERM);
+ 	case 0x8013:
+-		PRINT_WARN("(%s): Another host has priviliged access to the "
++		PRINT_WARN("(%s): Another host has privileged access to the "
+ 			   "tape device\n", device->cdev->dev.bus_id);
+ 		PRINT_WARN("(%s): To solve the problem unload the current "
+ 			   "cartridge!\n", device->cdev->dev.bus_id);
+diff --git a/drivers/s390/char/tape_block.c b/drivers/s390/char/tape_block.c
+index eeb92e2..ddc4a11 100644
+--- a/drivers/s390/char/tape_block.c
++++ b/drivers/s390/char/tape_block.c
+@@ -74,11 +74,10 @@ tapeblock_trigger_requeue(struct tape_device *device)
+  * Post finished request.
+  */
+ static void
+-tapeblock_end_request(struct request *req, int uptodate)
++tapeblock_end_request(struct request *req, int error)
  {
--	struct dasd_device *device;
-+	struct dasd_block *block;
- 
--	device = (struct dasd_device *) queue->queuedata;
--	spin_lock(get_ccwdev_lock(device->cdev));
-+	block = queue->queuedata;
-+	spin_lock(&block->queue_lock);
- 	/* Get new request from the block device request queue */
--	__dasd_process_blk_queue(device);
-+	__dasd_process_request_queue(block);
- 	/* Now check if the head of the ccw queue needs to be started. */
--	__dasd_start_head(device);
--	spin_unlock(get_ccwdev_lock(device->cdev));
-+	__dasd_block_start_head(block);
-+	spin_unlock(&block->queue_lock);
+-	if (end_that_request_first(req, uptodate, req->hard_nr_sectors))
++	if (__blk_end_request(req, error, blk_rq_bytes(req)))
+ 		BUG();
+-	end_that_request_last(req, uptodate);
  }
  
- /*
-  * Allocate and initialize request queue and default I/O scheduler.
-  */
--static int
--dasd_alloc_queue(struct dasd_device * device)
-+static int dasd_alloc_queue(struct dasd_block *block)
- {
- 	int rc;
+ static void
+@@ -91,7 +90,7 @@ __tapeblock_end_request(struct tape_request *ccw_req, void *data)
  
--	device->request_queue = blk_init_queue(do_dasd_request,
--					       &device->request_queue_lock);
--	if (device->request_queue == NULL)
-+	block->request_queue = blk_init_queue(do_dasd_request,
-+					       &block->request_queue_lock);
-+	if (block->request_queue == NULL)
- 		return -ENOMEM;
+ 	device = ccw_req->device;
+ 	req = (struct request *) data;
+-	tapeblock_end_request(req, ccw_req->rc == 0);
++	tapeblock_end_request(req, (ccw_req->rc == 0) ? 0 : -EIO);
+ 	if (ccw_req->rc == 0)
+ 		/* Update position. */
+ 		device->blk_data.block_position =
+@@ -119,7 +118,7 @@ tapeblock_start_request(struct tape_device *device, struct request *req)
+ 	ccw_req = device->discipline->bread(device, req);
+ 	if (IS_ERR(ccw_req)) {
+ 		DBF_EVENT(1, "TBLOCK: bread failed\n");
+-		tapeblock_end_request(req, 0);
++		tapeblock_end_request(req, -EIO);
+ 		return PTR_ERR(ccw_req);
+ 	}
+ 	ccw_req->callback = __tapeblock_end_request;
+@@ -132,7 +131,7 @@ tapeblock_start_request(struct tape_device *device, struct request *req)
+ 		 * Start/enqueueing failed. No retries in
+ 		 * this case.
+ 		 */
+-		tapeblock_end_request(req, 0);
++		tapeblock_end_request(req, -EIO);
+ 		device->discipline->free_bread(ccw_req);
+ 	}
  
--	device->request_queue->queuedata = device;
-+	block->request_queue->queuedata = block;
+@@ -177,7 +176,7 @@ tapeblock_requeue(struct work_struct *work) {
+ 		if (rq_data_dir(req) == WRITE) {
+ 			DBF_EVENT(1, "TBLOCK: Rejecting write request\n");
+ 			blkdev_dequeue_request(req);
+-			tapeblock_end_request(req, 0);
++			tapeblock_end_request(req, -EIO);
+ 			continue;
+ 		}
+ 		spin_unlock_irq(&device->blk_data.request_queue_lock);
+diff --git a/drivers/s390/char/tape_core.c b/drivers/s390/char/tape_core.c
+index 2fae633..7ad8cf1 100644
+--- a/drivers/s390/char/tape_core.c
++++ b/drivers/s390/char/tape_core.c
+@@ -37,7 +37,7 @@ static void tape_long_busy_timeout(unsigned long data);
+  * we can assign the devices to minor numbers of the same major
+  * The list is protected by the rwlock
+  */
+-static struct list_head tape_device_list = LIST_HEAD_INIT(tape_device_list);
++static LIST_HEAD(tape_device_list);
+ static DEFINE_RWLOCK(tape_device_lock);
  
--	elevator_exit(device->request_queue->elevator);
--	rc = elevator_init(device->request_queue, "deadline");
-+	elevator_exit(block->request_queue->elevator);
-+	rc = elevator_init(block->request_queue, "deadline");
- 	if (rc) {
--		blk_cleanup_queue(device->request_queue);
-+		blk_cleanup_queue(block->request_queue);
- 		return rc;
- 	}
- 	return 0;
-@@ -1780,79 +1971,76 @@ dasd_alloc_queue(struct dasd_device * device)
  /*
-  * Allocate and initialize request queue.
-  */
--static void
--dasd_setup_queue(struct dasd_device * device)
-+static void dasd_setup_queue(struct dasd_block *block)
+diff --git a/drivers/s390/char/tape_proc.c b/drivers/s390/char/tape_proc.c
+index cea49f0..c9b96d5 100644
+--- a/drivers/s390/char/tape_proc.c
++++ b/drivers/s390/char/tape_proc.c
+@@ -97,7 +97,7 @@ static void tape_proc_stop(struct seq_file *m, void *v)
  {
- 	int max;
+ }
  
--	blk_queue_hardsect_size(device->request_queue, device->bp_block);
--	max = device->discipline->max_blocks << device->s2b_shift;
--	blk_queue_max_sectors(device->request_queue, max);
--	blk_queue_max_phys_segments(device->request_queue, -1L);
--	blk_queue_max_hw_segments(device->request_queue, -1L);
--	blk_queue_max_segment_size(device->request_queue, -1L);
--	blk_queue_segment_boundary(device->request_queue, -1L);
--	blk_queue_ordered(device->request_queue, QUEUE_ORDERED_TAG, NULL);
-+	blk_queue_hardsect_size(block->request_queue, block->bp_block);
-+	max = block->base->discipline->max_blocks << block->s2b_shift;
-+	blk_queue_max_sectors(block->request_queue, max);
-+	blk_queue_max_phys_segments(block->request_queue, -1L);
-+	blk_queue_max_hw_segments(block->request_queue, -1L);
-+	blk_queue_max_segment_size(block->request_queue, -1L);
-+	blk_queue_segment_boundary(block->request_queue, -1L);
-+	blk_queue_ordered(block->request_queue, QUEUE_ORDERED_DRAIN, NULL);
+-static struct seq_operations tape_proc_seq = {
++static const struct seq_operations tape_proc_seq = {
+ 	.start		= tape_proc_start,
+ 	.next		= tape_proc_next,
+ 	.stop		= tape_proc_stop,
+diff --git a/drivers/s390/char/vmlogrdr.c b/drivers/s390/char/vmlogrdr.c
+index e0c4c50..d364e0b 100644
+--- a/drivers/s390/char/vmlogrdr.c
++++ b/drivers/s390/char/vmlogrdr.c
+@@ -683,7 +683,7 @@ static int vmlogrdr_register_driver(void)
+ 	/* Register with iucv driver */
+ 	ret = iucv_register(&vmlogrdr_iucv_handler, 1);
+ 	if (ret) {
+-		printk (KERN_ERR "vmlogrdr: failed to register with"
++		printk (KERN_ERR "vmlogrdr: failed to register with "
+ 			"iucv driver\n");
+ 		goto out;
+ 	}
+diff --git a/drivers/s390/char/vmur.c b/drivers/s390/char/vmur.c
+index d70a6e6..7689b50 100644
+--- a/drivers/s390/char/vmur.c
++++ b/drivers/s390/char/vmur.c
+@@ -759,7 +759,7 @@ static loff_t ur_llseek(struct file *file, loff_t offset, int whence)
+ 	return newpos;
+ }
+ 
+-static struct file_operations ur_fops = {
++static const struct file_operations ur_fops = {
+ 	.owner	 = THIS_MODULE,
+ 	.open	 = ur_open,
+ 	.release = ur_release,
+diff --git a/drivers/s390/char/zcore.c b/drivers/s390/char/zcore.c
+index 7073daf..f523501 100644
+--- a/drivers/s390/char/zcore.c
++++ b/drivers/s390/char/zcore.c
+@@ -470,7 +470,7 @@ static loff_t zcore_lseek(struct file *file, loff_t offset, int orig)
+ 	return rc;
  }
  
+-static struct file_operations zcore_fops = {
++static const struct file_operations zcore_fops = {
+ 	.owner		= THIS_MODULE,
+ 	.llseek		= zcore_lseek,
+ 	.read		= zcore_read,
+diff --git a/drivers/s390/cio/airq.c b/drivers/s390/cio/airq.c
+index 5287631..b7a07a8 100644
+--- a/drivers/s390/cio/airq.c
++++ b/drivers/s390/cio/airq.c
+@@ -1,12 +1,12 @@
  /*
-  * Deactivate and free request queue.
+  *  drivers/s390/cio/airq.c
+- *   S/390 common I/O routines -- support for adapter interruptions
++ *    Support for adapter interruptions
+  *
+- *    Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH,
+- *			      IBM Corporation
+- *    Author(s): Ingo Adlung (adlung at de.ibm.com)
+- *		 Cornelia Huck (cornelia.huck at de.ibm.com)
+- *		 Arnd Bergmann (arndb at de.ibm.com)
++ *    Copyright IBM Corp. 1999,2007
++ *    Author(s): Ingo Adlung <adlung at de.ibm.com>
++ *		 Cornelia Huck <cornelia.huck at de.ibm.com>
++ *		 Arnd Bergmann <arndb at de.ibm.com>
++ *		 Peter Oberparleiter <peter.oberparleiter at de.ibm.com>
   */
--static void
--dasd_free_queue(struct dasd_device * device)
-+static void dasd_free_queue(struct dasd_block *block)
+ 
+ #include <linux/init.h>
+@@ -14,72 +14,131 @@
+ #include <linux/slab.h>
+ #include <linux/rcupdate.h>
+ 
++#include <asm/airq.h>
++
++#include "cio.h"
+ #include "cio_debug.h"
+-#include "airq.h"
+ 
+-static adapter_int_handler_t adapter_handler;
++#define NR_AIRQS		32
++#define NR_AIRQS_PER_WORD	sizeof(unsigned long)
++#define NR_AIRQ_WORDS		(NR_AIRQS / NR_AIRQS_PER_WORD)
+ 
+-/*
+- * register for adapter interrupts
+- *
+- * With HiperSockets the zSeries architecture provides for
+- *  means of adapter interrups, pseudo I/O interrupts that are
+- *  not tied to an I/O subchannel, but to an adapter. However,
+- *  it doesn't disclose the info how to enable/disable them, but
+- *  to recognize them only. Perhaps we should consider them
+- *  being shared interrupts, and thus build a linked list
+- *  of adapter handlers ... to be evaluated ...
+- */
+-int
+-s390_register_adapter_interrupt (adapter_int_handler_t handler)
+-{
+-	int ret;
+-	char dbf_txt[15];
++union indicator_t {
++	unsigned long word[NR_AIRQ_WORDS];
++	unsigned char byte[NR_AIRQS];
++} __attribute__((packed));
+ 
+-	CIO_TRACE_EVENT (4, "rgaint");
++struct airq_t {
++	adapter_int_handler_t handler;
++	void *drv_data;
++};
+ 
+-	if (handler == NULL)
+-		ret = -EINVAL;
+-	else
+-		ret = (cmpxchg(&adapter_handler, NULL, handler) ? -EBUSY : 0);
+-	if (!ret)
+-		synchronize_sched();  /* Allow interrupts to complete. */
++static union indicator_t indicators;
++static struct airq_t *airqs[NR_AIRQS];
+ 
+-	sprintf (dbf_txt, "ret:%d", ret);
+-	CIO_TRACE_EVENT (4, dbf_txt);
++static int register_airq(struct airq_t *airq)
++{
++	int i;
+ 
+-	return ret;
++	for (i = 0; i < NR_AIRQS; i++)
++		if (!cmpxchg(&airqs[i], NULL, airq))
++			return i;
++	return -ENOMEM;
+ }
+ 
+-int
+-s390_unregister_adapter_interrupt (adapter_int_handler_t handler)
++/**
++ * s390_register_adapter_interrupt() - register adapter interrupt handler
++ * @handler: adapter handler to be registered
++ * @drv_data: driver data passed with each call to the handler
++ *
++ * Returns:
++ *  Pointer to the indicator to be used on success
++ *  ERR_PTR() if registration failed
++ */
++void *s390_register_adapter_interrupt(adapter_int_handler_t handler,
++				      void *drv_data)
  {
--	if (device->request_queue) {
--		blk_cleanup_queue(device->request_queue);
--		device->request_queue = NULL;
-+	if (block->request_queue) {
-+		blk_cleanup_queue(block->request_queue);
-+		block->request_queue = NULL;
++	struct airq_t *airq;
++	char dbf_txt[16];
+ 	int ret;
+-	char dbf_txt[15];
+ 
+-	CIO_TRACE_EVENT (4, "urgaint");
+-
+-	if (handler == NULL)
+-		ret = -EINVAL;
+-	else {
+-		adapter_handler = NULL;
+-		synchronize_sched();  /* Allow interrupts to complete. */
+-		ret = 0;
++	airq = kmalloc(sizeof(struct airq_t), GFP_KERNEL);
++	if (!airq) {
++		ret = -ENOMEM;
++		goto out;
  	}
+-	sprintf (dbf_txt, "ret:%d", ret);
+-	CIO_TRACE_EVENT (4, dbf_txt);
+-
+-	return ret;
++	airq->handler = handler;
++	airq->drv_data = drv_data;
++	ret = register_airq(airq);
++	if (ret < 0)
++		kfree(airq);
++out:
++	snprintf(dbf_txt, sizeof(dbf_txt), "rairq:%d", ret);
++	CIO_TRACE_EVENT(4, dbf_txt);
++	if (ret < 0)
++		return ERR_PTR(ret);
++	else
++		return &indicators.byte[ret];
  }
++EXPORT_SYMBOL(s390_register_adapter_interrupt);
  
- /*
-  * Flush request on the request queue.
-  */
--static void
--dasd_flush_request_queue(struct dasd_device * device)
-+static void dasd_flush_request_queue(struct dasd_block *block)
+-void
+-do_adapter_IO (void)
++/**
++ * s390_unregister_adapter_interrupt - unregister adapter interrupt handler
++ * @ind: indicator for which the handler is to be unregistered
++ */
++void s390_unregister_adapter_interrupt(void *ind)
  {
- 	struct request *req;
+-	CIO_TRACE_EVENT (6, "doaio");
++	struct airq_t *airq;
++	char dbf_txt[16];
++	int i;
  
--	if (!device->request_queue)
-+	if (!block->request_queue)
- 		return;
+-	if (adapter_handler)
+-		(*adapter_handler) ();
++	i = (int) ((addr_t) ind) - ((addr_t) &indicators.byte[0]);
++	snprintf(dbf_txt, sizeof(dbf_txt), "urairq:%d", i);
++	CIO_TRACE_EVENT(4, dbf_txt);
++	indicators.byte[i] = 0;
++	airq = xchg(&airqs[i], NULL);
++	/*
++	 * Allow interrupts to complete. This will ensure that the airq handle
++	 * is no longer referenced by any interrupt handler.
++	 */
++	synchronize_sched();
++	kfree(airq);
+ }
++EXPORT_SYMBOL(s390_unregister_adapter_interrupt);
++
++#define INDICATOR_MASK	(0xffUL << ((NR_AIRQS_PER_WORD - 1) * 8))
  
--	spin_lock_irq(&device->request_queue_lock);
--	while ((req = elv_next_request(device->request_queue))) {
-+	spin_lock_irq(&block->request_queue_lock);
-+	while ((req = elv_next_request(block->request_queue))) {
- 		blkdev_dequeue_request(req);
- 		dasd_end_request(req, 0);
- 	}
--	spin_unlock_irq(&device->request_queue_lock);
-+	spin_unlock_irq(&block->request_queue_lock);
+-EXPORT_SYMBOL (s390_register_adapter_interrupt);
+-EXPORT_SYMBOL (s390_unregister_adapter_interrupt);
++void do_adapter_IO(void)
++{
++	int w;
++	int i;
++	unsigned long word;
++	struct airq_t *airq;
++
++	/*
++	 * Access indicator array in word-sized chunks to minimize storage
++	 * fetch operations.
++	 */
++	for (w = 0; w < NR_AIRQ_WORDS; w++) {
++		word = indicators.word[w];
++		i = w * NR_AIRQS_PER_WORD;
++		/*
++		 * Check bytes within word for active indicators.
++		 */
++		while (word) {
++			if (word & INDICATOR_MASK) {
++				airq = airqs[i];
++				if (likely(airq))
++					airq->handler(&indicators.byte[i],
++						      airq->drv_data);
++				else
++					/*
++					 * Reset ill-behaved indicator.
++					 */
++					indicators.byte[i] = 0;
++			}
++			word <<= 8;
++			i++;
++		}
++	}
++}
+diff --git a/drivers/s390/cio/airq.h b/drivers/s390/cio/airq.h
+deleted file mode 100644
+index 7d6be3f..0000000
+--- a/drivers/s390/cio/airq.h
++++ /dev/null
+@@ -1,10 +0,0 @@
+-#ifndef S390_AINTERRUPT_H
+-#define S390_AINTERRUPT_H
+-
+-typedef	int (*adapter_int_handler_t)(void);
+-
+-extern int s390_register_adapter_interrupt(adapter_int_handler_t handler);
+-extern int s390_unregister_adapter_interrupt(adapter_int_handler_t handler);
+-extern void do_adapter_IO (void);
+-
+-#endif
+diff --git a/drivers/s390/cio/blacklist.c b/drivers/s390/cio/blacklist.c
+index bd5f16f..e8597ec 100644
+--- a/drivers/s390/cio/blacklist.c
++++ b/drivers/s390/cio/blacklist.c
+@@ -348,7 +348,7 @@ cio_ignore_write(struct file *file, const char __user *user_buf,
+ 	return user_len;
  }
  
--static int
--dasd_open(struct inode *inp, struct file *filp)
-+static int dasd_open(struct inode *inp, struct file *filp)
- {
- 	struct gendisk *disk = inp->i_bdev->bd_disk;
--	struct dasd_device *device = disk->private_data;
-+	struct dasd_block *block = disk->private_data;
-+	struct dasd_device *base = block->base;
- 	int rc;
+-static struct seq_operations cio_ignore_proc_seq_ops = {
++static const struct seq_operations cio_ignore_proc_seq_ops = {
+ 	.start = cio_ignore_proc_seq_start,
+ 	.stop  = cio_ignore_proc_seq_stop,
+ 	.next  = cio_ignore_proc_seq_next,
+diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c
+index 5baa517..3964056 100644
+--- a/drivers/s390/cio/ccwgroup.c
++++ b/drivers/s390/cio/ccwgroup.c
+@@ -35,8 +35,8 @@ ccwgroup_bus_match (struct device * dev, struct device_driver * drv)
+ 	struct ccwgroup_device *gdev;
+ 	struct ccwgroup_driver *gdrv;
  
--        atomic_inc(&device->open_count);
--	if (test_bit(DASD_FLAG_OFFLINE, &device->flags)) {
-+	atomic_inc(&block->open_count);
-+	if (test_bit(DASD_FLAG_OFFLINE, &base->flags)) {
- 		rc = -ENODEV;
- 		goto unlock;
- 	}
+-	gdev = container_of(dev, struct ccwgroup_device, dev);
+-	gdrv = container_of(drv, struct ccwgroup_driver, driver);
++	gdev = to_ccwgroupdev(dev);
++	gdrv = to_ccwgroupdrv(drv);
  
--	if (!try_module_get(device->discipline->owner)) {
-+	if (!try_module_get(base->discipline->owner)) {
- 		rc = -EINVAL;
- 		goto unlock;
- 	}
+ 	if (gdev->creator_id == gdrv->driver_id)
+ 		return 1;
+@@ -75,8 +75,10 @@ static void ccwgroup_ungroup_callback(struct device *dev)
+ 	struct ccwgroup_device *gdev = to_ccwgroupdev(dev);
  
- 	if (dasd_probeonly) {
--		DEV_MESSAGE(KERN_INFO, device, "%s",
-+		DEV_MESSAGE(KERN_INFO, base, "%s",
- 			    "No access to device due to probeonly mode");
- 		rc = -EPERM;
- 		goto out;
+ 	mutex_lock(&gdev->reg_mutex);
+-	__ccwgroup_remove_symlinks(gdev);
+-	device_unregister(dev);
++	if (device_is_registered(&gdev->dev)) {
++		__ccwgroup_remove_symlinks(gdev);
++		device_unregister(dev);
++	}
+ 	mutex_unlock(&gdev->reg_mutex);
+ }
+ 
+@@ -111,7 +113,7 @@ ccwgroup_release (struct device *dev)
+ 	gdev = to_ccwgroupdev(dev);
+ 
+ 	for (i = 0; i < gdev->count; i++) {
+-		gdev->cdev[i]->dev.driver_data = NULL;
++		dev_set_drvdata(&gdev->cdev[i]->dev, NULL);
+ 		put_device(&gdev->cdev[i]->dev);
+ 	}
+ 	kfree(gdev);
+@@ -196,11 +198,11 @@ int ccwgroup_create(struct device *root, unsigned int creator_id,
+ 			goto error;
+ 		}
+ 		/* Don't allow a device to belong to more than one group. */
+-		if (gdev->cdev[i]->dev.driver_data) {
++		if (dev_get_drvdata(&gdev->cdev[i]->dev)) {
+ 			rc = -EINVAL;
+ 			goto error;
+ 		}
+-		gdev->cdev[i]->dev.driver_data = gdev;
++		dev_set_drvdata(&gdev->cdev[i]->dev, gdev);
  	}
  
--	if (device->state <= DASD_STATE_BASIC) {
--		DBF_DEV_EVENT(DBF_ERR, device, " %s",
-+	if (base->state <= DASD_STATE_BASIC) {
-+		DBF_DEV_EVENT(DBF_ERR, base, " %s",
- 			      " Cannot open unrecognized device");
- 		rc = -ENODEV;
- 		goto out;
-@@ -1861,41 +2049,41 @@ dasd_open(struct inode *inp, struct file *filp)
- 	return 0;
+ 	gdev->creator_id = creator_id;
+@@ -234,8 +236,8 @@ int ccwgroup_create(struct device *root, unsigned int creator_id,
+ error:
+ 	for (i = 0; i < argc; i++)
+ 		if (gdev->cdev[i]) {
+-			if (gdev->cdev[i]->dev.driver_data == gdev)
+-				gdev->cdev[i]->dev.driver_data = NULL;
++			if (dev_get_drvdata(&gdev->cdev[i]->dev) == gdev)
++				dev_set_drvdata(&gdev->cdev[i]->dev, NULL);
+ 			put_device(&gdev->cdev[i]->dev);
+ 		}
+ 	mutex_unlock(&gdev->reg_mutex);
+@@ -408,6 +410,7 @@ int ccwgroup_driver_register(struct ccwgroup_driver *cdriver)
+ 	/* register our new driver with the core */
+ 	cdriver->driver.bus = &ccwgroup_bus_type;
+ 	cdriver->driver.name = cdriver->name;
++	cdriver->driver.owner = cdriver->owner;
  
- out:
--	module_put(device->discipline->owner);
-+	module_put(base->discipline->owner);
- unlock:
--	atomic_dec(&device->open_count);
-+	atomic_dec(&block->open_count);
- 	return rc;
+ 	return driver_register(&cdriver->driver);
  }
- 
--static int
--dasd_release(struct inode *inp, struct file *filp)
-+static int dasd_release(struct inode *inp, struct file *filp)
+@@ -463,8 +466,8 @@ __ccwgroup_get_gdev_by_cdev(struct ccw_device *cdev)
  {
- 	struct gendisk *disk = inp->i_bdev->bd_disk;
--	struct dasd_device *device = disk->private_data;
-+	struct dasd_block *block = disk->private_data;
+ 	struct ccwgroup_device *gdev;
  
--	atomic_dec(&device->open_count);
--	module_put(device->discipline->owner);
-+	atomic_dec(&block->open_count);
-+	module_put(block->base->discipline->owner);
- 	return 0;
+-	if (cdev->dev.driver_data) {
+-		gdev = (struct ccwgroup_device *)cdev->dev.driver_data;
++	gdev = dev_get_drvdata(&cdev->dev);
++	if (gdev) {
+ 		if (get_device(&gdev->dev)) {
+ 			mutex_lock(&gdev->reg_mutex);
+ 			if (device_is_registered(&gdev->dev))
+diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c
+index 597c0c7..e7ba16a 100644
+--- a/drivers/s390/cio/chsc.c
++++ b/drivers/s390/cio/chsc.c
+@@ -89,7 +89,8 @@ int chsc_get_ssd_info(struct subchannel_id schid, struct chsc_ssd_info *ssd)
+ 	/* Copy data */
+ 	ret = 0;
+ 	memset(ssd, 0, sizeof(struct chsc_ssd_info));
+-	if ((ssd_area->st != 0) && (ssd_area->st != 2))
++	if ((ssd_area->st != SUBCHANNEL_TYPE_IO) &&
++	    (ssd_area->st != SUBCHANNEL_TYPE_MSG))
+ 		goto out_free;
+ 	ssd->path_mask = ssd_area->path_mask;
+ 	ssd->fla_valid_mask = ssd_area->fla_valid_mask;
+@@ -132,20 +133,16 @@ static void terminate_internal_io(struct subchannel *sch)
+ 	device_set_intretry(sch);
+ 	/* Call handler. */
+ 	if (sch->driver && sch->driver->termination)
+-		sch->driver->termination(&sch->dev);
++		sch->driver->termination(sch);
  }
  
- /*
-  * Return disk geometry.
-  */
 -static int
--dasd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
-+static int dasd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
+-s390_subchannel_remove_chpid(struct device *dev, void *data)
++static int s390_subchannel_remove_chpid(struct subchannel *sch, void *data)
  {
--	struct dasd_device *device;
-+	struct dasd_block *block;
-+	struct dasd_device *base;
+ 	int j;
+ 	int mask;
+-	struct subchannel *sch;
+-	struct chp_id *chpid;
++	struct chp_id *chpid = data;
+ 	struct schib schib;
  
--	device = bdev->bd_disk->private_data;
--	if (!device)
-+	block = bdev->bd_disk->private_data;
-+	base = block->base;
-+	if (!block)
- 		return -ENODEV;
+-	sch = to_subchannel(dev);
+-	chpid = data;
+ 	for (j = 0; j < 8; j++) {
+ 		mask = 0x80 >> j;
+ 		if ((sch->schib.pmcw.pim & mask) &&
+@@ -158,7 +155,7 @@ s390_subchannel_remove_chpid(struct device *dev, void *data)
+ 	spin_lock_irq(sch->lock);
  
--	if (!device->discipline ||
--	    !device->discipline->fill_geometry)
-+	if (!base->discipline ||
-+	    !base->discipline->fill_geometry)
- 		return -EINVAL;
+ 	stsch(sch->schid, &schib);
+-	if (!schib.pmcw.dnv)
++	if (!css_sch_is_valid(&schib))
+ 		goto out_unreg;
+ 	memcpy(&sch->schib, &schib, sizeof(struct schib));
+ 	/* Check for single path devices. */
+@@ -172,12 +169,12 @@ s390_subchannel_remove_chpid(struct device *dev, void *data)
+ 			terminate_internal_io(sch);
+ 			/* Re-start path verification. */
+ 			if (sch->driver && sch->driver->verify)
+-				sch->driver->verify(&sch->dev);
++				sch->driver->verify(sch);
+ 		}
+ 	} else {
+ 		/* trigger path verification. */
+ 		if (sch->driver && sch->driver->verify)
+-			sch->driver->verify(&sch->dev);
++			sch->driver->verify(sch);
+ 		else if (sch->lpm == mask)
+ 			goto out_unreg;
+ 	}
+@@ -201,12 +198,10 @@ void chsc_chp_offline(struct chp_id chpid)
  
--	device->discipline->fill_geometry(device, geo);
--	geo->start = get_start_sect(bdev) >> device->s2b_shift;
-+	base->discipline->fill_geometry(block, geo);
-+	geo->start = get_start_sect(bdev) >> block->s2b_shift;
- 	return 0;
+ 	if (chp_get_status(chpid) <= 0)
+ 		return;
+-	bus_for_each_dev(&css_bus_type, NULL, &chpid,
+-			 s390_subchannel_remove_chpid);
++	for_each_subchannel_staged(s390_subchannel_remove_chpid, NULL, &chpid);
  }
  
-@@ -1909,6 +2097,9 @@ dasd_device_operations = {
- 	.getgeo		= dasd_getgeo,
- };
- 
-+/*******************************************************************************
-+ * end of block device operations
-+ */
- 
- static void
- dasd_exit(void)
-@@ -1937,9 +2128,8 @@ dasd_exit(void)
-  * Initial attempt at a probe function. this can be simplified once
-  * the other detection code is gone.
-  */
--int
--dasd_generic_probe (struct ccw_device *cdev,
--		    struct dasd_discipline *discipline)
-+int dasd_generic_probe(struct ccw_device *cdev,
-+		       struct dasd_discipline *discipline)
+-static int
+-s390_process_res_acc_new_sch(struct subchannel_id schid)
++static int s390_process_res_acc_new_sch(struct subchannel_id schid, void *data)
  {
- 	int ret;
- 
-@@ -1969,19 +2159,20 @@ dasd_generic_probe (struct ccw_device *cdev,
- 		ret = ccw_device_set_online(cdev);
- 	if (ret)
- 		printk(KERN_WARNING
--		       "dasd_generic_probe: could not initially online "
--		       "ccw-device %s\n", cdev->dev.bus_id);
--	return ret;
-+		       "dasd_generic_probe: could not initially "
-+		       "online ccw-device %s; return code: %d\n",
-+		       cdev->dev.bus_id, ret);
-+	return 0;
+ 	struct schib schib;
+ 	/*
+@@ -252,18 +247,10 @@ static int get_res_chpid_mask(struct chsc_ssd_info *ssd,
+ 	return 0;
  }
  
- /*
-  * This will one day be called from a global not_oper handler.
-  * It is also used by driver_unregister during module unload.
-  */
--void
--dasd_generic_remove (struct ccw_device *cdev)
-+void dasd_generic_remove(struct ccw_device *cdev)
+-static int
+-__s390_process_res_acc(struct subchannel_id schid, void *data)
++static int __s390_process_res_acc(struct subchannel *sch, void *data)
  {
- 	struct dasd_device *device;
-+	struct dasd_block *block;
+ 	int chp_mask, old_lpm;
+-	struct res_acc_data *res_data;
+-	struct subchannel *sch;
+-
+-	res_data = data;
+-	sch = get_subchannel_by_schid(schid);
+-	if (!sch)
+-		/* Check if a subchannel is newly available. */
+-		return s390_process_res_acc_new_sch(schid);
++	struct res_acc_data *res_data = data;
  
- 	cdev->handler = NULL;
+ 	spin_lock_irq(sch->lock);
+ 	chp_mask = get_res_chpid_mask(&sch->ssd_info, res_data);
+@@ -279,10 +266,10 @@ __s390_process_res_acc(struct subchannel_id schid, void *data)
+ 	if (!old_lpm && sch->lpm)
+ 		device_trigger_reprobe(sch);
+ 	else if (sch->driver && sch->driver->verify)
+-		sch->driver->verify(&sch->dev);
++		sch->driver->verify(sch);
+ out:
+ 	spin_unlock_irq(sch->lock);
+-	put_device(&sch->dev);
++
+ 	return 0;
+ }
  
-@@ -2001,7 +2192,15 @@ dasd_generic_remove (struct ccw_device *cdev)
+@@ -305,7 +292,8 @@ static void s390_process_res_acc (struct res_acc_data *res_data)
+ 	 * The more information we have (info), the less scanning
+ 	 * will we have to do.
  	 */
- 	dasd_set_target_state(device, DASD_STATE_NEW);
- 	/* dasd_delete_device destroys the device reference. */
-+	block = device->block;
-+	device->block = NULL;
- 	dasd_delete_device(device);
-+	/*
-+	 * life cycle of block is bound to device, so delete it after
-+	 * device was safely removed
-+	 */
-+	if (block)
-+		dasd_free_block(block);
+-	for_each_subchannel(__s390_process_res_acc, res_data);
++	for_each_subchannel_staged(__s390_process_res_acc,
++				   s390_process_res_acc_new_sch, res_data);
  }
  
- /*
-@@ -2009,10 +2208,8 @@ dasd_generic_remove (struct ccw_device *cdev)
-  * the device is detected for the first time and is supposed to be used
-  * or the user has started activation through sysfs.
-  */
--int
--dasd_generic_set_online (struct ccw_device *cdev,
--			 struct dasd_discipline *base_discipline)
--
-+int dasd_generic_set_online(struct ccw_device *cdev,
-+			    struct dasd_discipline *base_discipline)
- {
- 	struct dasd_discipline *discipline;
- 	struct dasd_device *device;
-@@ -2048,6 +2245,7 @@ dasd_generic_set_online (struct ccw_device *cdev,
- 	device->base_discipline = base_discipline;
- 	device->discipline = discipline;
- 
-+	/* check_device will allocate block device if necessary */
- 	rc = discipline->check_device(device);
- 	if (rc) {
- 		printk (KERN_WARNING
-@@ -2067,6 +2265,8 @@ dasd_generic_set_online (struct ccw_device *cdev,
- 			cdev->dev.bus_id);
- 		rc = -ENODEV;
- 		dasd_set_target_state(device, DASD_STATE_NEW);
-+		if (device->block)
-+			dasd_free_block(device->block);
- 		dasd_delete_device(device);
- 	} else
- 		pr_debug("dasd_generic device %s found\n",
-@@ -2081,10 +2281,10 @@ dasd_generic_set_online (struct ccw_device *cdev,
- 	return rc;
+ static int
+@@ -499,8 +487,7 @@ void chsc_process_crw(void)
+ 	} while (sei_area->flags & 0x80);
  }
  
--int
--dasd_generic_set_offline (struct ccw_device *cdev)
-+int dasd_generic_set_offline(struct ccw_device *cdev)
+-static int
+-__chp_add_new_sch(struct subchannel_id schid)
++static int __chp_add_new_sch(struct subchannel_id schid, void *data)
  {
- 	struct dasd_device *device;
-+	struct dasd_block *block;
- 	int max_count, open_count;
+ 	struct schib schib;
  
- 	device = dasd_device_from_cdev(cdev);
-@@ -2101,30 +2301,39 @@ dasd_generic_set_offline (struct ccw_device *cdev)
- 	 * the blkdev_get in dasd_scan_partitions. We are only interested
- 	 * in the other openers.
- 	 */
--	max_count = device->bdev ? 0 : -1;
--	open_count = (int) atomic_read(&device->open_count);
--	if (open_count > max_count) {
--		if (open_count > 0)
--			printk (KERN_WARNING "Can't offline dasd device with "
--				"open count = %i.\n",
--				open_count);
--		else
--			printk (KERN_WARNING "%s",
--				"Can't offline dasd device due to internal "
--				"use\n");
--		clear_bit(DASD_FLAG_OFFLINE, &device->flags);
--		dasd_put_device(device);
--		return -EBUSY;
-+	if (device->block) {
-+		struct dasd_block *block = device->block;
-+		max_count = block->bdev ? 0 : -1;
-+		open_count = (int) atomic_read(&block->open_count);
-+		if (open_count > max_count) {
-+			if (open_count > 0)
-+				printk(KERN_WARNING "Can't offline dasd "
-+				       "device with open count = %i.\n",
-+				       open_count);
-+			else
-+				printk(KERN_WARNING "%s",
-+				       "Can't offline dasd device due "
-+				       "to internal use\n");
-+			clear_bit(DASD_FLAG_OFFLINE, &device->flags);
-+			dasd_put_device(device);
-+			return -EBUSY;
-+		}
- 	}
- 	dasd_set_target_state(device, DASD_STATE_NEW);
- 	/* dasd_delete_device destroys the device reference. */
-+	block = device->block;
-+	device->block = NULL;
- 	dasd_delete_device(device);
--
-+	/*
-+	 * life cycle of block is bound to device, so delete it after
-+	 * device was safely removed
-+	 */
-+	if (block)
-+		dasd_free_block(block);
- 	return 0;
+@@ -514,45 +501,37 @@ __chp_add_new_sch(struct subchannel_id schid)
  }
  
--int
--dasd_generic_notify(struct ccw_device *cdev, int event)
-+int dasd_generic_notify(struct ccw_device *cdev, int event)
+ 
+-static int
+-__chp_add(struct subchannel_id schid, void *data)
++static int __chp_add(struct subchannel *sch, void *data)
  {
- 	struct dasd_device *device;
- 	struct dasd_ccw_req *cqr;
-@@ -2145,27 +2354,22 @@ dasd_generic_notify(struct ccw_device *cdev, int event)
- 		if (device->state < DASD_STATE_BASIC)
+ 	int i, mask;
+-	struct chp_id *chpid;
+-	struct subchannel *sch;
+-
+-	chpid = data;
+-	sch = get_subchannel_by_schid(schid);
+-	if (!sch)
+-		/* Check if the subchannel is now available. */
+-		return __chp_add_new_sch(schid);
++	struct chp_id *chpid = data;
++
+ 	spin_lock_irq(sch->lock);
+ 	for (i=0; i<8; i++) {
+ 		mask = 0x80 >> i;
+ 		if ((sch->schib.pmcw.pim & mask) &&
+-		    (sch->schib.pmcw.chpid[i] == chpid->id)) {
+-			if (stsch(sch->schid, &sch->schib) != 0) {
+-				/* Endgame. */
+-				spin_unlock_irq(sch->lock);
+-				return -ENXIO;
+-			}
++		    (sch->schib.pmcw.chpid[i] == chpid->id))
  			break;
- 		/* Device is active. We want to keep it. */
--		if (test_bit(DASD_FLAG_DSC_ERROR, &device->flags)) {
--			list_for_each_entry(cqr, &device->ccw_queue, list)
--				if (cqr->status == DASD_CQR_IN_IO)
--					cqr->status = DASD_CQR_FAILED;
--			device->stopped |= DASD_STOPPED_DC_EIO;
--		} else {
--			list_for_each_entry(cqr, &device->ccw_queue, list)
--				if (cqr->status == DASD_CQR_IN_IO) {
--					cqr->status = DASD_CQR_QUEUED;
--					cqr->retries++;
--				}
--			device->stopped |= DASD_STOPPED_DC_WAIT;
--			dasd_set_timer(device, 0);
 -		}
--		dasd_schedule_bh(device);
-+		list_for_each_entry(cqr, &device->ccw_queue, devlist)
-+			if (cqr->status == DASD_CQR_IN_IO) {
-+				cqr->status = DASD_CQR_QUEUED;
-+				cqr->retries++;
-+			}
-+		device->stopped |= DASD_STOPPED_DC_WAIT;
-+		dasd_device_clear_timer(device);
-+		dasd_schedule_device_bh(device);
- 		ret = 1;
- 		break;
- 	case CIO_OPER:
- 		/* FIXME: add a sanity check. */
--		device->stopped &= ~(DASD_STOPPED_DC_WAIT|DASD_STOPPED_DC_EIO);
--		dasd_schedule_bh(device);
-+		device->stopped &= ~DASD_STOPPED_DC_WAIT;
-+		dasd_schedule_device_bh(device);
-+		if (device->block)
-+			dasd_schedule_block_bh(device->block);
- 		ret = 1;
- 		break;
  	}
-@@ -2195,7 +2399,8 @@ static struct dasd_ccw_req *dasd_generic_build_rdc(struct dasd_device *device,
- 	ccw->cda = (__u32)(addr_t)rdc_buffer;
- 	ccw->count = rdc_buffer_size;
+ 	if (i==8) {
+ 		spin_unlock_irq(sch->lock);
+ 		return 0;
+ 	}
++	if (stsch(sch->schid, &sch->schib)) {
++		spin_unlock_irq(sch->lock);
++		css_schedule_eval(sch->schid);
++		return 0;
++	}
+ 	sch->lpm = ((sch->schib.pmcw.pim &
+ 		     sch->schib.pmcw.pam &
+ 		     sch->schib.pmcw.pom)
+ 		    | mask) & sch->opm;
  
--	cqr->device = device;
-+	cqr->startdev = device;
-+	cqr->memdev = device;
- 	cqr->expires = 10*HZ;
- 	clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
- 	cqr->retries = 2;
-@@ -2217,13 +2422,12 @@ int dasd_generic_read_dev_chars(struct dasd_device *device, char *magic,
- 		return PTR_ERR(cqr);
+ 	if (sch->driver && sch->driver->verify)
+-		sch->driver->verify(&sch->dev);
++		sch->driver->verify(sch);
  
- 	ret = dasd_sleep_on(cqr);
--	dasd_sfree_request(cqr, cqr->device);
-+	dasd_sfree_request(cqr, cqr->memdev);
- 	return ret;
+ 	spin_unlock_irq(sch->lock);
+-	put_device(&sch->dev);
++
+ 	return 0;
  }
- EXPORT_SYMBOL_GPL(dasd_generic_read_dev_chars);
- 
--static int __init
--dasd_init(void)
-+static int __init dasd_init(void)
- {
- 	int rc;
- 
-@@ -2231,7 +2435,7 @@ dasd_init(void)
- 	init_waitqueue_head(&dasd_flush_wq);
- 
- 	/* register 'common' DASD debug area, used for all DBF_XXX calls */
--	dasd_debug_area = debug_register("dasd", 1, 2, 8 * sizeof (long));
-+	dasd_debug_area = debug_register("dasd", 1, 1, 8 * sizeof(long));
- 	if (dasd_debug_area == NULL) {
- 		rc = -ENOMEM;
- 		goto failed;
-@@ -2277,15 +2481,18 @@ EXPORT_SYMBOL(dasd_diag_discipline_pointer);
- EXPORT_SYMBOL(dasd_add_request_head);
- EXPORT_SYMBOL(dasd_add_request_tail);
- EXPORT_SYMBOL(dasd_cancel_req);
--EXPORT_SYMBOL(dasd_clear_timer);
-+EXPORT_SYMBOL(dasd_device_clear_timer);
-+EXPORT_SYMBOL(dasd_block_clear_timer);
- EXPORT_SYMBOL(dasd_enable_device);
- EXPORT_SYMBOL(dasd_int_handler);
- EXPORT_SYMBOL(dasd_kfree_request);
- EXPORT_SYMBOL(dasd_kick_device);
- EXPORT_SYMBOL(dasd_kmalloc_request);
--EXPORT_SYMBOL(dasd_schedule_bh);
-+EXPORT_SYMBOL(dasd_schedule_device_bh);
-+EXPORT_SYMBOL(dasd_schedule_block_bh);
- EXPORT_SYMBOL(dasd_set_target_state);
--EXPORT_SYMBOL(dasd_set_timer);
-+EXPORT_SYMBOL(dasd_device_set_timer);
-+EXPORT_SYMBOL(dasd_block_set_timer);
- EXPORT_SYMBOL(dasd_sfree_request);
- EXPORT_SYMBOL(dasd_sleep_on);
- EXPORT_SYMBOL(dasd_sleep_on_immediatly);
-@@ -2299,4 +2506,7 @@ EXPORT_SYMBOL_GPL(dasd_generic_remove);
- EXPORT_SYMBOL_GPL(dasd_generic_notify);
- EXPORT_SYMBOL_GPL(dasd_generic_set_online);
- EXPORT_SYMBOL_GPL(dasd_generic_set_offline);
--
-+EXPORT_SYMBOL_GPL(dasd_generic_handle_state_change);
-+EXPORT_SYMBOL_GPL(dasd_flush_device_queue);
-+EXPORT_SYMBOL_GPL(dasd_alloc_block);
-+EXPORT_SYMBOL_GPL(dasd_free_block);
-diff --git a/drivers/s390/block/dasd_3370_erp.c b/drivers/s390/block/dasd_3370_erp.c
-deleted file mode 100644
-index 1ddab89..0000000
---- a/drivers/s390/block/dasd_3370_erp.c
-+++ /dev/null
-@@ -1,84 +0,0 @@
--/*
-- * File...........: linux/drivers/s390/block/dasd_3370_erp.c
-- * Author(s)......: Holger Smolinski <Holger.Smolinski at de.ibm.com>
-- * Bugreports.to..: <Linux390 at de.ibm.com>
-- * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000
-- *
-- */
--
--#define PRINTK_HEADER "dasd_erp(3370)"
--
--#include "dasd_int.h"
--
--
--/*
-- * DASD_3370_ERP_EXAMINE
-- *
-- * DESCRIPTION
-- *   Checks only for fatal/no/recover error.
-- *   A detailed examination of the sense data is done later outside
-- *   the interrupt handler.
-- *
-- *   The logic is based on the 'IBM 3880 Storage Control Reference' manual
-- *   'Chapter 7. 3370 Sense Data'.
-- *
-- * RETURN VALUES
-- *   dasd_era_none	no error
-- *   dasd_era_fatal	for all fatal (unrecoverable errors)
-- *   dasd_era_recover	for all others.
-- */
--dasd_era_t
--dasd_3370_erp_examine(struct dasd_ccw_req * cqr, struct irb * irb)
--{
--	char *sense = irb->ecw;
--
--	/* check for successful execution first */
--	if (irb->scsw.cstat == 0x00 &&
--	    irb->scsw.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))
--		return dasd_era_none;
--	if (sense[0] & 0x80) {	/* CMD reject */
--		return dasd_era_fatal;
--	}
--	if (sense[0] & 0x40) {	/* Drive offline */
--		return dasd_era_recover;
--	}
--	if (sense[0] & 0x20) {	/* Bus out parity */
--		return dasd_era_recover;
--	}
--	if (sense[0] & 0x10) {	/* equipment check */
--		if (sense[1] & 0x80) {
--			return dasd_era_fatal;
--		}
--		return dasd_era_recover;
--	}
--	if (sense[0] & 0x08) {	/* data check */
--		if (sense[1] & 0x80) {
--			return dasd_era_fatal;
--		}
--		return dasd_era_recover;
--	}
--	if (sense[0] & 0x04) {	/* overrun */
--		if (sense[1] & 0x80) {
--			return dasd_era_fatal;
--		}
--		return dasd_era_recover;
--	}
--	if (sense[1] & 0x40) {	/* invalid blocksize */
--		return dasd_era_fatal;
--	}
--	if (sense[1] & 0x04) {	/* file protected */
--		return dasd_era_recover;
--	}
--	if (sense[1] & 0x01) {	/* operation incomplete */
--		return dasd_era_recover;
--	}
--	if (sense[2] & 0x80) {	/* check data erroor */
--		return dasd_era_recover;
--	}
--	if (sense[2] & 0x10) {	/* Env. data present */
--		return dasd_era_recover;
--	}
--	/* examine the 24 byte sense data */
--	return dasd_era_recover;
--
--}				/* END dasd_3370_erp_examine */
-diff --git a/drivers/s390/block/dasd_3990_erp.c b/drivers/s390/block/dasd_3990_erp.c
-index 5b7385e..c361ab6 100644
---- a/drivers/s390/block/dasd_3990_erp.c
-+++ b/drivers/s390/block/dasd_3990_erp.c
-@@ -26,158 +26,6 @@ struct DCTL_data {
- 
- /*
-  *****************************************************************************
-- * SECTION ERP EXAMINATION
-- *****************************************************************************
-- */
--
--/*
-- * DASD_3990_ERP_EXAMINE_24
-- *
-- * DESCRIPTION
-- *   Checks only for fatal (unrecoverable) error.
-- *   A detailed examination of the sense data is done later outside
-- *   the interrupt handler.
-- *
-- *   Each bit configuration leading to an action code 2 (Exit with
-- *   programming error or unusual condition indication)
-- *   are handled as fatal errors.
-- *
-- *   All other configurations are handled as recoverable errors.
-- *
-- * RETURN VALUES
-- *   dasd_era_fatal	for all fatal (unrecoverable errors)
-- *   dasd_era_recover	for all others.
-- */
--static dasd_era_t
--dasd_3990_erp_examine_24(struct dasd_ccw_req * cqr, char *sense)
--{
--
--	struct dasd_device *device = cqr->device;
--
--	/* check for 'Command Reject' */
--	if ((sense[0] & SNS0_CMD_REJECT) &&
--	    (!(sense[2] & SNS2_ENV_DATA_PRESENT))) {
--
--		DEV_MESSAGE(KERN_ERR, device, "%s",
--			    "EXAMINE 24: Command Reject detected - "
--			    "fatal error");
--
--		return dasd_era_fatal;
--	}
--
--	/* check for 'Invalid Track Format' */
--	if ((sense[1] & SNS1_INV_TRACK_FORMAT) &&
--	    (!(sense[2] & SNS2_ENV_DATA_PRESENT))) {
--
--		DEV_MESSAGE(KERN_ERR, device, "%s",
--			    "EXAMINE 24: Invalid Track Format detected "
--			    "- fatal error");
--
--		return dasd_era_fatal;
--	}
--
--	/* check for 'No Record Found' */
--	if (sense[1] & SNS1_NO_REC_FOUND) {
--
--                /* FIXME: fatal error ?!? */
--		DEV_MESSAGE(KERN_ERR, device,
--			    "EXAMINE 24: No Record Found detected %s",
--                            device->state <= DASD_STATE_BASIC ?
--			    " " : "- fatal error");
--
--		return dasd_era_fatal;
--	}
--
--	/* return recoverable for all others */
--	return dasd_era_recover;
--}				/* END dasd_3990_erp_examine_24 */
--
--/*
-- * DASD_3990_ERP_EXAMINE_32
-- *
-- * DESCRIPTION
-- *   Checks only for fatal/no/recoverable error.
-- *   A detailed examination of the sense data is done later outside
-- *   the interrupt handler.
-- *
-- * RETURN VALUES
-- *   dasd_era_none	no error
-- *   dasd_era_fatal	for all fatal (unrecoverable errors)
-- *   dasd_era_recover	for recoverable others.
-- */
--static dasd_era_t
--dasd_3990_erp_examine_32(struct dasd_ccw_req * cqr, char *sense)
--{
--
--	struct dasd_device *device = cqr->device;
--
--	switch (sense[25]) {
--	case 0x00:
--		return dasd_era_none;
--
--	case 0x01:
--		DEV_MESSAGE(KERN_ERR, device, "%s", "EXAMINE 32: fatal error");
--
--		return dasd_era_fatal;
--
--	default:
--
--		return dasd_era_recover;
--	}
--
--}				/* end dasd_3990_erp_examine_32 */
--
--/*
-- * DASD_3990_ERP_EXAMINE
-- *
-- * DESCRIPTION
-- *   Checks only for fatal/no/recover error.
-- *   A detailed examination of the sense data is done later outside
-- *   the interrupt handler.
-- *
-- *   The logic is based on the 'IBM 3990 Storage Control  Reference' manual
-- *   'Chapter 7. Error Recovery Procedures'.
-- *
-- * RETURN VALUES
-- *   dasd_era_none	no error
-- *   dasd_era_fatal	for all fatal (unrecoverable errors)
-- *   dasd_era_recover	for all others.
-- */
--dasd_era_t
--dasd_3990_erp_examine(struct dasd_ccw_req * cqr, struct irb * irb)
--{
--
--	char *sense = irb->ecw;
--	dasd_era_t era = dasd_era_recover;
--	struct dasd_device *device = cqr->device;
--
--	/* check for successful execution first */
--	if (irb->scsw.cstat == 0x00 &&
--	    irb->scsw.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))
--		return dasd_era_none;
--
--	/* distinguish between 24 and 32 byte sense data */
--	if (sense[27] & DASD_SENSE_BIT_0) {
--
--		era = dasd_3990_erp_examine_24(cqr, sense);
--
--	} else {
--
--		era = dasd_3990_erp_examine_32(cqr, sense);
--
--	}
--
--	/* log the erp chain if fatal error occurred */
--	if ((era == dasd_era_fatal) && (device->state >= DASD_STATE_READY)) {
--		dasd_log_sense(cqr, irb);
--	}
--
--	return era;
--
--}				/* END dasd_3990_erp_examine */
--
--/*
-- *****************************************************************************
-  * SECTION ERP HANDLING
-  *****************************************************************************
-  */
-@@ -206,7 +54,7 @@ dasd_3990_erp_cleanup(struct dasd_ccw_req * erp, char final_status)
- {
- 	struct dasd_ccw_req *cqr = erp->refers;
- 
--	dasd_free_erp_request(erp, erp->device);
-+	dasd_free_erp_request(erp, erp->memdev);
- 	cqr->status = final_status;
- 	return cqr;
- 
-@@ -224,15 +72,17 @@ static void
- dasd_3990_erp_block_queue(struct dasd_ccw_req * erp, int expires)
- {
- 
--	struct dasd_device *device = erp->device;
-+	struct dasd_device *device = erp->startdev;
-+	unsigned long flags;
  
- 	DEV_MESSAGE(KERN_INFO, device,
- 		    "blocking request queue for %is", expires/HZ);
+@@ -564,7 +543,8 @@ void chsc_chp_online(struct chp_id chpid)
+ 	CIO_TRACE_EVENT(2, dbf_txt);
  
-+	spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
- 	device->stopped |= DASD_STOPPED_PENDING;
--	erp->status = DASD_CQR_QUEUED;
--
--	dasd_set_timer(device, expires);
-+	spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
-+	erp->status = DASD_CQR_FILLED;
-+	dasd_block_set_timer(device->block, expires);
+ 	if (chp_get_status(chpid) != 0)
+-		for_each_subchannel(__chp_add, &chpid);
++		for_each_subchannel_staged(__chp_add, __chp_add_new_sch,
++					   &chpid);
  }
  
- /*
-@@ -251,7 +101,7 @@ static struct dasd_ccw_req *
- dasd_3990_erp_int_req(struct dasd_ccw_req * erp)
- {
- 
--	struct dasd_device *device = erp->device;
-+	struct dasd_device *device = erp->startdev;
- 
- 	/* first time set initial retry counter and erp_function */
- 	/* and retry once without blocking queue		 */
-@@ -292,11 +142,14 @@ dasd_3990_erp_int_req(struct dasd_ccw_req * erp)
- static void
- dasd_3990_erp_alternate_path(struct dasd_ccw_req * erp)
- {
--	struct dasd_device *device = erp->device;
-+	struct dasd_device *device = erp->startdev;
- 	__u8 opm;
-+	unsigned long flags;
- 
- 	/* try alternate valid path */
-+	spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
- 	opm = ccw_device_get_path_mask(device->cdev);
-+	spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
- 	//FIXME: start with get_opm ?
- 	if (erp->lpm == 0)
- 		erp->lpm = LPM_ANYPATH & ~(erp->irb.esw.esw0.sublog.lpum);
-@@ -309,9 +162,8 @@ dasd_3990_erp_alternate_path(struct dasd_ccw_req * erp)
- 			    "try alternate lpm=%x (lpum=%x / opm=%x)",
- 			    erp->lpm, erp->irb.esw.esw0.sublog.lpum, opm);
- 
--		/* reset status to queued to handle the request again... */
--		if (erp->status > DASD_CQR_QUEUED)
--			erp->status = DASD_CQR_QUEUED;
-+		/* reset status to submit the request again... */
-+		erp->status = DASD_CQR_FILLED;
- 		erp->retries = 1;
- 	} else {
- 		DEV_MESSAGE(KERN_ERR, device,
-@@ -320,8 +172,7 @@ dasd_3990_erp_alternate_path(struct dasd_ccw_req * erp)
- 			    erp->irb.esw.esw0.sublog.lpum, opm);
- 
- 		/* post request with permanent error */
--		if (erp->status > DASD_CQR_QUEUED)
--			erp->status = DASD_CQR_FAILED;
-+		erp->status = DASD_CQR_FAILED;
+ static void __s390_subchannel_vary_chpid(struct subchannel *sch,
+@@ -589,7 +569,7 @@ static void __s390_subchannel_vary_chpid(struct subchannel *sch,
+ 			if (!old_lpm)
+ 				device_trigger_reprobe(sch);
+ 			else if (sch->driver && sch->driver->verify)
+-				sch->driver->verify(&sch->dev);
++				sch->driver->verify(sch);
+ 			break;
+ 		}
+ 		sch->opm &= ~mask;
+@@ -603,37 +583,29 @@ static void __s390_subchannel_vary_chpid(struct subchannel *sch,
+ 				terminate_internal_io(sch);
+ 				/* Re-start path verification. */
+ 				if (sch->driver && sch->driver->verify)
+-					sch->driver->verify(&sch->dev);
++					sch->driver->verify(sch);
+ 			}
+ 		} else if (!sch->lpm) {
+ 			if (device_trigger_verify(sch) != 0)
+ 				css_schedule_eval(sch->schid);
+ 		} else if (sch->driver && sch->driver->verify)
+-			sch->driver->verify(&sch->dev);
++			sch->driver->verify(sch);
+ 		break;
  	}
- }				/* end dasd_3990_erp_alternate_path */
+ 	spin_unlock_irqrestore(sch->lock, flags);
+ }
  
-@@ -344,14 +195,14 @@ static struct dasd_ccw_req *
- dasd_3990_erp_DCTL(struct dasd_ccw_req * erp, char modifier)
+-static int s390_subchannel_vary_chpid_off(struct device *dev, void *data)
++static int s390_subchannel_vary_chpid_off(struct subchannel *sch, void *data)
  {
+-	struct subchannel *sch;
+-	struct chp_id *chpid;
+-
+-	sch = to_subchannel(dev);
+-	chpid = data;
++	struct chp_id *chpid = data;
  
--	struct dasd_device *device = erp->device;
-+	struct dasd_device *device = erp->startdev;
- 	struct DCTL_data *DCTL_data;
- 	struct ccw1 *ccw;
- 	struct dasd_ccw_req *dctl_cqr;
- 
- 	dctl_cqr = dasd_alloc_erp_request((char *) &erp->magic, 1,
--					  sizeof (struct DCTL_data),
--					  erp->device);
-+					  sizeof(struct DCTL_data),
-+					  device);
- 	if (IS_ERR(dctl_cqr)) {
- 		DEV_MESSAGE(KERN_ERR, device, "%s",
- 			    "Unable to allocate DCTL-CQR");
-@@ -365,13 +216,14 @@ dasd_3990_erp_DCTL(struct dasd_ccw_req * erp, char modifier)
- 	DCTL_data->modifier = modifier;
+ 	__s390_subchannel_vary_chpid(sch, *chpid, 0);
+ 	return 0;
+ }
  
- 	ccw = dctl_cqr->cpaddr;
--	memset(ccw, 0, sizeof (struct ccw1));
-+	memset(ccw, 0, sizeof(struct ccw1));
- 	ccw->cmd_code = CCW_CMD_DCTL;
- 	ccw->count = 4;
- 	ccw->cda = (__u32)(addr_t) DCTL_data;
- 	dctl_cqr->function = dasd_3990_erp_DCTL;
- 	dctl_cqr->refers = erp;
--	dctl_cqr->device = erp->device;
-+	dctl_cqr->startdev = device;
-+	dctl_cqr->memdev = device;
- 	dctl_cqr->magic = erp->magic;
- 	dctl_cqr->expires = 5 * 60 * HZ;
- 	dctl_cqr->retries = 2;
-@@ -435,7 +287,7 @@ static struct dasd_ccw_req *
- dasd_3990_erp_action_4(struct dasd_ccw_req * erp, char *sense)
+-static int s390_subchannel_vary_chpid_on(struct device *dev, void *data)
++static int s390_subchannel_vary_chpid_on(struct subchannel *sch, void *data)
  {
+-	struct subchannel *sch;
+-	struct chp_id *chpid;
+-
+-	sch = to_subchannel(dev);
+-	chpid = data;
++	struct chp_id *chpid = data;
  
--	struct dasd_device *device = erp->device;
-+	struct dasd_device *device = erp->startdev;
- 
- 	/* first time set initial retry counter and erp_function    */
- 	/* and retry once without waiting for state change pending  */
-@@ -472,7 +324,7 @@ dasd_3990_erp_action_4(struct dasd_ccw_req * erp, char *sense)
- 				     "redriving request immediately, "
- 				     "%d retries left",
- 				     erp->retries);
--			erp->status = DASD_CQR_QUEUED;
-+			erp->status = DASD_CQR_FILLED;
- 		}
- 	}
- 
-@@ -530,7 +382,7 @@ static void
- dasd_3990_handle_env_data(struct dasd_ccw_req * erp, char *sense)
+ 	__s390_subchannel_vary_chpid(sch, *chpid, 1);
+ 	return 0;
+@@ -643,13 +615,7 @@ static int
+ __s390_vary_chpid_on(struct subchannel_id schid, void *data)
  {
+ 	struct schib schib;
+-	struct subchannel *sch;
  
--	struct dasd_device *device = erp->device;
-+	struct dasd_device *device = erp->startdev;
- 	char msg_format = (sense[7] & 0xF0);
- 	char msg_no = (sense[7] & 0x0F);
+-	sch = get_subchannel_by_schid(schid);
+-	if (sch) {
+-		put_device(&sch->dev);
+-		return 0;
+-	}
+ 	if (stsch_err(schid, &schib))
+ 		/* We're through */
+ 		return -ENXIO;
+@@ -669,12 +635,13 @@ int chsc_chp_vary(struct chp_id chpid, int on)
+ 	 * Redo PathVerification on the devices the chpid connects to
+ 	 */
  
-@@ -1157,7 +1009,7 @@ static struct dasd_ccw_req *
- dasd_3990_erp_com_rej(struct dasd_ccw_req * erp, char *sense)
- {
+-	bus_for_each_dev(&css_bus_type, NULL, &chpid, on ?
+-			 s390_subchannel_vary_chpid_on :
+-			 s390_subchannel_vary_chpid_off);
+ 	if (on)
+-		/* Scan for new devices on varied on path. */
+-		for_each_subchannel(__s390_vary_chpid_on, NULL);
++		for_each_subchannel_staged(s390_subchannel_vary_chpid_on,
++					   __s390_vary_chpid_on, &chpid);
++	else
++		for_each_subchannel_staged(s390_subchannel_vary_chpid_off,
++					   NULL, &chpid);
++
+ 	return 0;
+ }
  
--	struct dasd_device *device = erp->device;
-+	struct dasd_device *device = erp->startdev;
+@@ -1075,7 +1042,7 @@ chsc_determine_css_characteristics(void)
  
- 	erp->function = dasd_3990_erp_com_rej;
+ 	scsc_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
+ 	if (!scsc_area) {
+-		CIO_MSG_EVENT(0, "Was not able to determine available"
++		CIO_MSG_EVENT(0, "Was not able to determine available "
+ 			      "CHSCs due to no memory.\n");
+ 		return -ENOMEM;
+ 	}
+diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c
+index 4690534..60590a1 100644
+--- a/drivers/s390/cio/cio.c
++++ b/drivers/s390/cio/cio.c
+@@ -23,11 +23,12 @@
+ #include <asm/reset.h>
+ #include <asm/ipl.h>
+ #include <asm/chpid.h>
+-#include "airq.h"
++#include <asm/airq.h>
+ #include "cio.h"
+ #include "css.h"
+ #include "chsc.h"
+ #include "ioasm.h"
++#include "io_sch.h"
+ #include "blacklist.h"
+ #include "cio_debug.h"
+ #include "chp.h"
+@@ -56,39 +57,37 @@ __setup ("cio_msg=", cio_setup);
  
-@@ -1198,7 +1050,7 @@ static struct dasd_ccw_req *
- dasd_3990_erp_bus_out(struct dasd_ccw_req * erp)
+ /*
+  * Function: cio_debug_init
+- * Initializes three debug logs (under /proc/s390dbf) for common I/O:
+- * - cio_msg logs the messages which are printk'ed when CONFIG_DEBUG_IO is on
++ * Initializes three debug logs for common I/O:
++ * - cio_msg logs generic cio messages
+  * - cio_trace logs the calling of different functions
+- * - cio_crw logs the messages which are printk'ed when CONFIG_DEBUG_CRW is on
+- * debug levels depend on CONFIG_DEBUG_IO resp. CONFIG_DEBUG_CRW
++ * - cio_crw logs machine check related cio messages
+  */
+-static int __init
+-cio_debug_init (void)
++static int __init cio_debug_init(void)
  {
+-	cio_debug_msg_id = debug_register ("cio_msg", 16, 4, 16*sizeof (long));
++	cio_debug_msg_id = debug_register("cio_msg", 16, 1, 16 * sizeof(long));
+ 	if (!cio_debug_msg_id)
+ 		goto out_unregister;
+-	debug_register_view (cio_debug_msg_id, &debug_sprintf_view);
+-	debug_set_level (cio_debug_msg_id, 2);
+-	cio_debug_trace_id = debug_register ("cio_trace", 16, 4, 16);
++	debug_register_view(cio_debug_msg_id, &debug_sprintf_view);
++	debug_set_level(cio_debug_msg_id, 2);
++	cio_debug_trace_id = debug_register("cio_trace", 16, 1, 16);
+ 	if (!cio_debug_trace_id)
+ 		goto out_unregister;
+-	debug_register_view (cio_debug_trace_id, &debug_hex_ascii_view);
+-	debug_set_level (cio_debug_trace_id, 2);
+-	cio_debug_crw_id = debug_register ("cio_crw", 4, 4, 16*sizeof (long));
++	debug_register_view(cio_debug_trace_id, &debug_hex_ascii_view);
++	debug_set_level(cio_debug_trace_id, 2);
++	cio_debug_crw_id = debug_register("cio_crw", 16, 1, 16 * sizeof(long));
+ 	if (!cio_debug_crw_id)
+ 		goto out_unregister;
+-	debug_register_view (cio_debug_crw_id, &debug_sprintf_view);
+-	debug_set_level (cio_debug_crw_id, 2);
++	debug_register_view(cio_debug_crw_id, &debug_sprintf_view);
++	debug_set_level(cio_debug_crw_id, 4);
+ 	return 0;
  
--	struct dasd_device *device = erp->device;
-+	struct dasd_device *device = erp->startdev;
- 
- 	/* first time set initial retry counter and erp_function */
- 	/* and retry once without blocking queue		 */
-@@ -1237,7 +1089,7 @@ static struct dasd_ccw_req *
- dasd_3990_erp_equip_check(struct dasd_ccw_req * erp, char *sense)
+ out_unregister:
+ 	if (cio_debug_msg_id)
+-		debug_unregister (cio_debug_msg_id);
++		debug_unregister(cio_debug_msg_id);
+ 	if (cio_debug_trace_id)
+-		debug_unregister (cio_debug_trace_id);
++		debug_unregister(cio_debug_trace_id);
+ 	if (cio_debug_crw_id)
+-		debug_unregister (cio_debug_crw_id);
++		debug_unregister(cio_debug_crw_id);
+ 	printk(KERN_WARNING"cio: could not initialize debugging\n");
+ 	return -1;
+ }
+@@ -147,7 +146,7 @@ cio_tpi(void)
+ 	spin_lock(sch->lock);
+ 	memcpy (&sch->schib.scsw, &irb->scsw, sizeof (struct scsw));
+ 	if (sch->driver && sch->driver->irq)
+-		sch->driver->irq(&sch->dev);
++		sch->driver->irq(sch);
+ 	spin_unlock(sch->lock);
+ 	irq_exit ();
+ 	_local_bh_enable();
+@@ -184,33 +183,35 @@ cio_start_key (struct subchannel *sch,	/* subchannel structure */
  {
+ 	char dbf_txt[15];
+ 	int ccode;
++	struct orb *orb;
  
--	struct dasd_device *device = erp->device;
-+	struct dasd_device *device = erp->startdev;
+-	CIO_TRACE_EVENT (4, "stIO");
+-	CIO_TRACE_EVENT (4, sch->dev.bus_id);
++	CIO_TRACE_EVENT(4, "stIO");
++	CIO_TRACE_EVENT(4, sch->dev.bus_id);
  
- 	erp->function = dasd_3990_erp_equip_check;
++	orb = &to_io_private(sch)->orb;
+ 	/* sch is always under 2G. */
+-	sch->orb.intparm = (__u32)(unsigned long)sch;
+-	sch->orb.fmt = 1;
++	orb->intparm = (u32)(addr_t)sch;
++	orb->fmt = 1;
  
-@@ -1279,7 +1131,6 @@ dasd_3990_erp_equip_check(struct dasd_ccw_req * erp, char *sense)
+-	sch->orb.pfch = sch->options.prefetch == 0;
+-	sch->orb.spnd = sch->options.suspend;
+-	sch->orb.ssic = sch->options.suspend && sch->options.inter;
+-	sch->orb.lpm = (lpm != 0) ? lpm : sch->lpm;
++	orb->pfch = sch->options.prefetch == 0;
++	orb->spnd = sch->options.suspend;
++	orb->ssic = sch->options.suspend && sch->options.inter;
++	orb->lpm = (lpm != 0) ? lpm : sch->lpm;
+ #ifdef CONFIG_64BIT
+ 	/*
+ 	 * for 64 bit we always support 64 bit IDAWs with 4k page size only
+ 	 */
+-	sch->orb.c64 = 1;
+-	sch->orb.i2k = 0;
++	orb->c64 = 1;
++	orb->i2k = 0;
+ #endif
+-	sch->orb.key = key >> 4;
++	orb->key = key >> 4;
+ 	/* issue "Start Subchannel" */
+-	sch->orb.cpa = (__u32) __pa (cpa);
+-	ccode = ssch (sch->schid, &sch->orb);
++	orb->cpa = (__u32) __pa(cpa);
++	ccode = ssch(sch->schid, orb);
  
- 		erp = dasd_3990_erp_action_5(erp);
- 	}
--
- 	return erp;
+ 	/* process condition code */
+-	sprintf (dbf_txt, "ccode:%d", ccode);
+-	CIO_TRACE_EVENT (4, dbf_txt);
++	sprintf(dbf_txt, "ccode:%d", ccode);
++	CIO_TRACE_EVENT(4, dbf_txt);
  
- }				/* end dasd_3990_erp_equip_check */
-@@ -1299,7 +1150,7 @@ static struct dasd_ccw_req *
- dasd_3990_erp_data_check(struct dasd_ccw_req * erp, char *sense)
+ 	switch (ccode) {
+ 	case 0:
+@@ -405,8 +406,8 @@ cio_modify (struct subchannel *sch)
+ /*
+  * Enable subchannel.
+  */
+-int
+-cio_enable_subchannel (struct subchannel *sch, unsigned int isc)
++int cio_enable_subchannel(struct subchannel *sch, unsigned int isc,
++			  u32 intparm)
  {
+ 	char dbf_txt[15];
+ 	int ccode;
+@@ -425,7 +426,7 @@ cio_enable_subchannel (struct subchannel *sch, unsigned int isc)
+ 	for (retry = 5, ret = 0; retry > 0; retry--) {
+ 		sch->schib.pmcw.ena = 1;
+ 		sch->schib.pmcw.isc = isc;
+-		sch->schib.pmcw.intparm = (__u32)(unsigned long)sch;
++		sch->schib.pmcw.intparm = intparm;
+ 		ret = cio_modify(sch);
+ 		if (ret == -ENODEV)
+ 			break;
+@@ -567,7 +568,7 @@ cio_validate_subchannel (struct subchannel *sch, struct subchannel_id schid)
+ 	 */
+ 	if (sch->st != 0) {
+ 		CIO_DEBUG(KERN_INFO, 0,
+-			  "cio: Subchannel 0.%x.%04x reports "
++			  "Subchannel 0.%x.%04x reports "
+ 			  "non-I/O subchannel type %04X\n",
+ 			  sch->schid.ssid, sch->schid.sch_no, sch->st);
+ 		/* We stop here for non-io subchannels. */
+@@ -576,11 +577,11 @@ cio_validate_subchannel (struct subchannel *sch, struct subchannel_id schid)
+ 	}
  
--	struct dasd_device *device = erp->device;
-+	struct dasd_device *device = erp->startdev;
- 
- 	erp->function = dasd_3990_erp_data_check;
- 
-@@ -1358,7 +1209,7 @@ static struct dasd_ccw_req *
- dasd_3990_erp_overrun(struct dasd_ccw_req * erp, char *sense)
- {
+ 	/* Initialization for io subchannels. */
+-	if (!sch->schib.pmcw.dnv) {
+-		/* io subchannel but device number is invalid. */
++	if (!css_sch_is_valid(&sch->schib)) {
+ 		err = -ENODEV;
+ 		goto out;
+ 	}
++
+ 	/* Devno is valid. */
+ 	if (is_blacklisted (sch->schid.ssid, sch->schib.pmcw.dev)) {
+ 		/*
+@@ -600,7 +601,7 @@ cio_validate_subchannel (struct subchannel *sch, struct subchannel_id schid)
+ 	sch->lpm = sch->schib.pmcw.pam & sch->opm;
  
--	struct dasd_device *device = erp->device;
-+	struct dasd_device *device = erp->startdev;
+ 	CIO_DEBUG(KERN_INFO, 0,
+-		  "cio: Detected device %04x on subchannel 0.%x.%04X"
++		  "Detected device %04x on subchannel 0.%x.%04X"
+ 		  " - PIM = %02X, PAM = %02X, POM = %02X\n",
+ 		  sch->schib.pmcw.dev, sch->schid.ssid,
+ 		  sch->schid.sch_no, sch->schib.pmcw.pim,
+@@ -680,7 +681,7 @@ do_IRQ (struct pt_regs *regs)
+ 				sizeof (irb->scsw));
+ 			/* Call interrupt handler if there is one. */
+ 			if (sch->driver && sch->driver->irq)
+-				sch->driver->irq(&sch->dev);
++				sch->driver->irq(sch);
+ 		}
+ 		if (sch)
+ 			spin_unlock(sch->lock);
+@@ -698,8 +699,14 @@ do_IRQ (struct pt_regs *regs)
  
- 	erp->function = dasd_3990_erp_overrun;
+ #ifdef CONFIG_CCW_CONSOLE
+ static struct subchannel console_subchannel;
++static struct io_subchannel_private console_priv;
+ static int console_subchannel_in_use;
  
-@@ -1387,7 +1238,7 @@ static struct dasd_ccw_req *
- dasd_3990_erp_inv_format(struct dasd_ccw_req * erp, char *sense)
++void *cio_get_console_priv(void)
++{
++	return &console_priv;
++}
++
+ /*
+  * busy wait for the next interrupt on the console
+  */
+@@ -738,9 +745,9 @@ cio_test_for_console(struct subchannel_id schid, void *data)
  {
+ 	if (stsch_err(schid, &console_subchannel.schib) != 0)
+ 		return -ENXIO;
+-	if (console_subchannel.schib.pmcw.dnv &&
+-	    console_subchannel.schib.pmcw.dev ==
+-	    console_devno) {
++	if ((console_subchannel.schib.pmcw.st == SUBCHANNEL_TYPE_IO) &&
++	    console_subchannel.schib.pmcw.dnv &&
++	    (console_subchannel.schib.pmcw.dev == console_devno)) {
+ 		console_irq = schid.sch_no;
+ 		return 1; /* found */
+ 	}
+@@ -758,6 +765,7 @@ cio_get_console_sch_no(void)
+ 		/* VM provided us with the irq number of the console. */
+ 		schid.sch_no = console_irq;
+ 		if (stsch(schid, &console_subchannel.schib) != 0 ||
++		    (console_subchannel.schib.pmcw.st != SUBCHANNEL_TYPE_IO) ||
+ 		    !console_subchannel.schib.pmcw.dnv)
+ 			return -1;
+ 		console_devno = console_subchannel.schib.pmcw.dev;
+@@ -804,7 +812,7 @@ cio_probe_console(void)
+ 	ctl_set_bit(6, 24);
+ 	console_subchannel.schib.pmcw.isc = 7;
+ 	console_subchannel.schib.pmcw.intparm =
+-		(__u32)(unsigned long)&console_subchannel;
++		(u32)(addr_t)&console_subchannel;
+ 	ret = cio_modify(&console_subchannel);
+ 	if (ret) {
+ 		console_subchannel_in_use = 0;
+@@ -1022,7 +1030,7 @@ static int __reipl_subchannel_match(struct subchannel_id schid, void *data)
  
--	struct dasd_device *device = erp->device;
-+	struct dasd_device *device = erp->startdev;
+ 	if (stsch_reset(schid, &schib))
+ 		return -ENXIO;
+-	if (schib.pmcw.dnv &&
++	if ((schib.pmcw.st == SUBCHANNEL_TYPE_IO) && schib.pmcw.dnv &&
+ 	    (schib.pmcw.dev == match_id->devid.devno) &&
+ 	    (schid.ssid == match_id->devid.ssid)) {
+ 		match_id->schid = schid;
+@@ -1068,6 +1076,8 @@ int __init cio_get_iplinfo(struct cio_iplinfo *iplinfo)
+ 		return -ENODEV;
+ 	if (stsch(schid, &schib))
+ 		return -ENODEV;
++	if (schib.pmcw.st != SUBCHANNEL_TYPE_IO)
++		return -ENODEV;
+ 	if (!schib.pmcw.dnv)
+ 		return -ENODEV;
+ 	iplinfo->devno = schib.pmcw.dev;
+diff --git a/drivers/s390/cio/cio.h b/drivers/s390/cio/cio.h
+index 7446c39..52afa4c 100644
+--- a/drivers/s390/cio/cio.h
++++ b/drivers/s390/cio/cio.h
+@@ -11,32 +11,32 @@
+  * path management control word
+  */
+ struct pmcw {
+-	__u32 intparm;		/* interruption parameter */
+-	__u32 qf   : 1;		/* qdio facility */
+-	__u32 res0 : 1;		/* reserved zeros */
+-	__u32 isc  : 3;		/* interruption sublass */
+-	__u32 res5 : 3;		/* reserved zeros */
+-	__u32 ena  : 1;		/* enabled */
+-	__u32 lm   : 2;		/* limit mode */
+-	__u32 mme  : 2;		/* measurement-mode enable */
+-	__u32 mp   : 1;		/* multipath mode */
+-	__u32 tf   : 1;		/* timing facility */
+-	__u32 dnv  : 1;		/* device number valid */
+-	__u32 dev  : 16;	/* device number */
+-	__u8  lpm;		/* logical path mask */
+-	__u8  pnom;		/* path not operational mask */
+-	__u8  lpum;		/* last path used mask */
+-	__u8  pim;		/* path installed mask */
+-	__u16 mbi;		/* measurement-block index */
+-	__u8  pom;		/* path operational mask */
+-	__u8  pam;		/* path available mask */
+-	__u8  chpid[8];		/* CHPID 0-7 (if available) */
+-	__u32 unused1 : 8;	/* reserved zeros */
+-	__u32 st      : 3;	/* subchannel type */
+-	__u32 unused2 : 18;	/* reserved zeros */
+-	__u32 mbfc    : 1;      /* measurement block format control */
+-	__u32 xmwme   : 1;      /* extended measurement word mode enable */
+-	__u32 csense  : 1;	/* concurrent sense; can be enabled ...*/
++	u32 intparm;		/* interruption parameter */
++	u32 qf	 : 1;		/* qdio facility */
++	u32 res0 : 1;		/* reserved zeros */
++	u32 isc  : 3;		/* interruption sublass */
++	u32 res5 : 3;		/* reserved zeros */
++	u32 ena  : 1;		/* enabled */
++	u32 lm	 : 2;		/* limit mode */
++	u32 mme  : 2;		/* measurement-mode enable */
++	u32 mp	 : 1;		/* multipath mode */
++	u32 tf	 : 1;		/* timing facility */
++	u32 dnv  : 1;		/* device number valid */
++	u32 dev  : 16;		/* device number */
++	u8  lpm;		/* logical path mask */
++	u8  pnom;		/* path not operational mask */
++	u8  lpum;		/* last path used mask */
++	u8  pim;		/* path installed mask */
++	u16 mbi;		/* measurement-block index */
++	u8  pom;		/* path operational mask */
++	u8  pam;		/* path available mask */
++	u8  chpid[8];		/* CHPID 0-7 (if available) */
++	u32 unused1 : 8;	/* reserved zeros */
++	u32 st	    : 3;	/* subchannel type */
++	u32 unused2 : 18;	/* reserved zeros */
++	u32 mbfc    : 1;	/* measurement block format control */
++	u32 xmwme   : 1;	/* extended measurement word mode enable */
++	u32 csense  : 1;	/* concurrent sense; can be enabled ...*/
+ 				/*  ... per MSCH, however, if facility */
+ 				/*  ... is not installed, this results */
+ 				/*  ... in an operand exception.       */
+@@ -52,31 +52,6 @@ struct schib {
+ 	__u8 mda[4];		 /* model dependent area */
+ } __attribute__ ((packed,aligned(4)));
  
- 	erp->function = dasd_3990_erp_inv_format;
+-/*
+- * operation request block
+- */
+-struct orb {
+-	__u32 intparm;		/* interruption parameter */
+-	__u32 key  : 4; 	/* flags, like key, suspend control, etc. */
+-	__u32 spnd : 1; 	/* suspend control */
+-	__u32 res1 : 1; 	/* reserved */
+-	__u32 mod  : 1; 	/* modification control */
+-	__u32 sync : 1; 	/* synchronize control */
+-	__u32 fmt  : 1; 	/* format control */
+-	__u32 pfch : 1; 	/* prefetch control */
+-	__u32 isic : 1; 	/* initial-status-interruption control */
+-	__u32 alcc : 1; 	/* address-limit-checking control */
+-	__u32 ssic : 1; 	/* suppress-suspended-interr. control */
+-	__u32 res2 : 1; 	/* reserved */
+-	__u32 c64  : 1; 	/* IDAW/QDIO 64 bit control  */
+-	__u32 i2k  : 1; 	/* IDAW 2/4kB block size control */
+-	__u32 lpm  : 8; 	/* logical path mask */
+-	__u32 ils  : 1; 	/* incorrect length */
+-	__u32 zero : 6; 	/* reserved zeros */
+-	__u32 orbx : 1; 	/* ORB extension control */
+-	__u32 cpa;		/* channel program address */
+-}  __attribute__ ((packed,aligned(4)));
+-
+ /* subchannel data structure used by I/O subroutines */
+ struct subchannel {
+ 	struct subchannel_id schid;
+@@ -85,7 +60,7 @@ struct subchannel {
+ 	enum {
+ 		SUBCHANNEL_TYPE_IO = 0,
+ 		SUBCHANNEL_TYPE_CHSC = 1,
+-		SUBCHANNEL_TYPE_MESSAGE = 2,
++		SUBCHANNEL_TYPE_MSG = 2,
+ 		SUBCHANNEL_TYPE_ADM = 3,
+ 	} st;			/* subchannel type */
  
-@@ -1403,8 +1254,7 @@ dasd_3990_erp_inv_format(struct dasd_ccw_req * erp, char *sense)
+@@ -99,11 +74,10 @@ struct subchannel {
+ 	__u8 lpm;		/* logical path mask */
+ 	__u8 opm;               /* operational path mask */
+ 	struct schib schib;	/* subchannel information block */
+-	struct orb orb;		/* operation request block */
+-	struct ccw1 sense_ccw;	/* static ccw for sense command */
+ 	struct chsc_ssd_info ssd_info;	/* subchannel description */
+ 	struct device dev;	/* entry in device tree */
+ 	struct css_driver *driver;
++	void *private; /* private per subchannel type data */
+ } __attribute__ ((aligned(8)));
  
- 	} else {
- 		DEV_MESSAGE(KERN_ERR, device, "%s",
--			    "Invalid Track Format - Fatal error should have "
--			    "been handled within the interrupt handler");
-+			    "Invalid Track Format - Fatal error");
+ #define IO_INTERRUPT_TYPE	   0 /* I/O interrupt type */
+@@ -111,7 +85,7 @@ struct subchannel {
+ #define to_subchannel(n) container_of(n, struct subchannel, dev)
  
- 		erp = dasd_3990_erp_cleanup(erp, DASD_CQR_FAILED);
- 	}
-@@ -1428,7 +1278,7 @@ static struct dasd_ccw_req *
- dasd_3990_erp_EOC(struct dasd_ccw_req * default_erp, char *sense)
- {
+ extern int cio_validate_subchannel (struct subchannel *, struct subchannel_id);
+-extern int cio_enable_subchannel (struct subchannel *, unsigned int);
++extern int cio_enable_subchannel(struct subchannel *, unsigned int, u32);
+ extern int cio_disable_subchannel (struct subchannel *);
+ extern int cio_cancel (struct subchannel *);
+ extern int cio_clear (struct subchannel *);
+@@ -125,6 +99,7 @@ extern int cio_get_options (struct subchannel *);
+ extern int cio_modify (struct subchannel *);
  
--	struct dasd_device *device = default_erp->device;
-+	struct dasd_device *device = default_erp->startdev;
+ int cio_create_sch_lock(struct subchannel *);
++void do_adapter_IO(void);
  
- 	DEV_MESSAGE(KERN_ERR, device, "%s",
- 		    "End-of-Cylinder - must never happen");
-@@ -1453,7 +1303,7 @@ static struct dasd_ccw_req *
- dasd_3990_erp_env_data(struct dasd_ccw_req * erp, char *sense)
- {
+ /* Use with care. */
+ #ifdef CONFIG_CCW_CONSOLE
+@@ -133,10 +108,12 @@ extern void cio_release_console(void);
+ extern int cio_is_console(struct subchannel_id);
+ extern struct subchannel *cio_get_console_subchannel(void);
+ extern spinlock_t * cio_get_console_lock(void);
++extern void *cio_get_console_priv(void);
+ #else
+ #define cio_is_console(schid) 0
+ #define cio_get_console_subchannel() NULL
+-#define cio_get_console_lock() NULL;
++#define cio_get_console_lock() NULL
++#define cio_get_console_priv() NULL
+ #endif
  
--	struct dasd_device *device = erp->device;
-+	struct dasd_device *device = erp->startdev;
+ extern int cio_show_msg;
+diff --git a/drivers/s390/cio/cio_debug.h b/drivers/s390/cio/cio_debug.h
+index c9bf898..d7429ef 100644
+--- a/drivers/s390/cio/cio_debug.h
++++ b/drivers/s390/cio/cio_debug.h
+@@ -8,20 +8,19 @@ extern debug_info_t *cio_debug_msg_id;
+ extern debug_info_t *cio_debug_trace_id;
+ extern debug_info_t *cio_debug_crw_id;
  
- 	erp->function = dasd_3990_erp_env_data;
+-#define CIO_TRACE_EVENT(imp, txt) do { \
++#define CIO_TRACE_EVENT(imp, txt) do {				\
+ 		debug_text_event(cio_debug_trace_id, imp, txt); \
+ 	} while (0)
  
-@@ -1463,11 +1313,9 @@ dasd_3990_erp_env_data(struct dasd_ccw_req * erp, char *sense)
+-#define CIO_MSG_EVENT(imp, args...) do { \
+-		debug_sprintf_event(cio_debug_msg_id, imp , ##args); \
++#define CIO_MSG_EVENT(imp, args...) do {				\
++		debug_sprintf_event(cio_debug_msg_id, imp , ##args);	\
+ 	} while (0)
  
- 	/* don't retry on disabled interface */
- 	if (sense[7] != 0x0F) {
--
- 		erp = dasd_3990_erp_action_4(erp, sense);
- 	} else {
--
--		erp = dasd_3990_erp_cleanup(erp, DASD_CQR_IN_IO);
-+		erp->status = DASD_CQR_FILLED;
- 	}
+-#define CIO_CRW_EVENT(imp, args...) do { \
+-		debug_sprintf_event(cio_debug_crw_id, imp , ##args); \
++#define CIO_CRW_EVENT(imp, args...) do {				\
++		debug_sprintf_event(cio_debug_crw_id, imp , ##args);	\
+ 	} while (0)
  
- 	return erp;
-@@ -1490,11 +1338,10 @@ static struct dasd_ccw_req *
- dasd_3990_erp_no_rec(struct dasd_ccw_req * default_erp, char *sense)
+-static inline void
+-CIO_HEX_EVENT(int level, void *data, int length)
++static inline void CIO_HEX_EVENT(int level, void *data, int length)
  {
+ 	if (unlikely(!cio_debug_trace_id))
+ 		return;
+@@ -32,9 +31,10 @@ CIO_HEX_EVENT(int level, void *data, int length)
+ 	}
+ }
  
--	struct dasd_device *device = default_erp->device;
-+	struct dasd_device *device = default_erp->startdev;
- 
- 	DEV_MESSAGE(KERN_ERR, device, "%s",
--		    "No Record Found - Fatal error should "
--		    "have been handled within the interrupt handler");
-+		    "No Record Found - Fatal error ");
+-#define CIO_DEBUG(printk_level,event_level,msg...) ({ \
+-	if (cio_show_msg) printk(printk_level msg); \
+-	CIO_MSG_EVENT (event_level, msg); \
+-})
++#define CIO_DEBUG(printk_level, event_level, msg...) do {	\
++		if (cio_show_msg)				\
++			printk(printk_level "cio: " msg);	\
++		CIO_MSG_EVENT(event_level, msg);		\
++	} while (0)
  
- 	return dasd_3990_erp_cleanup(default_erp, DASD_CQR_FAILED);
+ #endif
+diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c
+index c3df2cd..3b45bbe 100644
+--- a/drivers/s390/cio/css.c
++++ b/drivers/s390/cio/css.c
+@@ -51,6 +51,62 @@ for_each_subchannel(int(*fn)(struct subchannel_id, void *), void *data)
+ 	return ret;
+ }
  
-@@ -1517,7 +1364,7 @@ static struct dasd_ccw_req *
- dasd_3990_erp_file_prot(struct dasd_ccw_req * erp)
++struct cb_data {
++	void *data;
++	struct idset *set;
++	int (*fn_known_sch)(struct subchannel *, void *);
++	int (*fn_unknown_sch)(struct subchannel_id, void *);
++};
++
++static int call_fn_known_sch(struct device *dev, void *data)
++{
++	struct subchannel *sch = to_subchannel(dev);
++	struct cb_data *cb = data;
++	int rc = 0;
++
++	idset_sch_del(cb->set, sch->schid);
++	if (cb->fn_known_sch)
++		rc = cb->fn_known_sch(sch, cb->data);
++	return rc;
++}
++
++static int call_fn_unknown_sch(struct subchannel_id schid, void *data)
++{
++	struct cb_data *cb = data;
++	int rc = 0;
++
++	if (idset_sch_contains(cb->set, schid))
++		rc = cb->fn_unknown_sch(schid, cb->data);
++	return rc;
++}
++
++int for_each_subchannel_staged(int (*fn_known)(struct subchannel *, void *),
++			       int (*fn_unknown)(struct subchannel_id,
++			       void *), void *data)
++{
++	struct cb_data cb;
++	int rc;
++
++	cb.set = idset_sch_new();
++	if (!cb.set)
++		return -ENOMEM;
++	idset_fill(cb.set);
++	cb.data = data;
++	cb.fn_known_sch = fn_known;
++	cb.fn_unknown_sch = fn_unknown;
++	/* Process registered subchannels. */
++	rc = bus_for_each_dev(&css_bus_type, NULL, &cb, call_fn_known_sch);
++	if (rc)
++		goto out;
++	/* Process unregistered subchannels. */
++	if (fn_unknown)
++		rc = for_each_subchannel(call_fn_unknown_sch, &cb);
++out:
++	idset_free(cb.set);
++
++	return rc;
++}
++
+ static struct subchannel *
+ css_alloc_subchannel(struct subchannel_id schid)
  {
+@@ -77,7 +133,7 @@ css_alloc_subchannel(struct subchannel_id schid)
+ 	 * This is fine even on 64bit since the subchannel is always located
+ 	 * under 2G.
+ 	 */
+-	sch->schib.pmcw.intparm = (__u32)(unsigned long)sch;
++	sch->schib.pmcw.intparm = (u32)(addr_t)sch;
+ 	ret = cio_modify(sch);
+ 	if (ret) {
+ 		kfree(sch->lock);
+@@ -237,11 +293,25 @@ get_subchannel_by_schid(struct subchannel_id schid)
+ 	return dev ? to_subchannel(dev) : NULL;
+ }
  
--	struct dasd_device *device = erp->device;
-+	struct dasd_device *device = erp->startdev;
++/**
++ * css_sch_is_valid() - check if a subchannel is valid
++ * @schib: subchannel information block for the subchannel
++ */
++int css_sch_is_valid(struct schib *schib)
++{
++	if ((schib->pmcw.st == SUBCHANNEL_TYPE_IO) && !schib->pmcw.dnv)
++		return 0;
++	return 1;
++}
++EXPORT_SYMBOL_GPL(css_sch_is_valid);
++
+ static int css_get_subchannel_status(struct subchannel *sch)
+ {
+ 	struct schib schib;
  
- 	DEV_MESSAGE(KERN_ERR, device, "%s", "File Protected");
+-	if (stsch(sch->schid, &schib) || !schib.pmcw.dnv)
++	if (stsch(sch->schid, &schib))
++		return CIO_GONE;
++	if (!css_sch_is_valid(&schib))
+ 		return CIO_GONE;
+ 	if (sch->schib.pmcw.dnv && (schib.pmcw.dev != sch->schib.pmcw.dev))
+ 		return CIO_REVALIDATE;
+@@ -293,7 +363,7 @@ static int css_evaluate_known_subchannel(struct subchannel *sch, int slow)
+ 		action = UNREGISTER;
+ 		if (sch->driver && sch->driver->notify) {
+ 			spin_unlock_irqrestore(sch->lock, flags);
+-			ret = sch->driver->notify(&sch->dev, event);
++			ret = sch->driver->notify(sch, event);
+ 			spin_lock_irqsave(sch->lock, flags);
+ 			if (ret)
+ 				action = NONE;
+@@ -349,7 +419,7 @@ static int css_evaluate_new_subchannel(struct subchannel_id schid, int slow)
+ 		/* Will be done on the slow path. */
+ 		return -EAGAIN;
+ 	}
+-	if (stsch_err(schid, &schib) || !schib.pmcw.dnv) {
++	if (stsch_err(schid, &schib) || !css_sch_is_valid(&schib)) {
+ 		/* Unusable - ignore. */
+ 		return 0;
+ 	}
+@@ -388,20 +458,56 @@ static int __init slow_subchannel_init(void)
+ 	return 0;
+ }
  
-@@ -1526,6 +1373,43 @@ dasd_3990_erp_file_prot(struct dasd_ccw_req * erp)
- }				/* end dasd_3990_erp_file_prot */
+-static void css_slow_path_func(struct work_struct *unused)
++static int slow_eval_known_fn(struct subchannel *sch, void *data)
+ {
+-	struct subchannel_id schid;
++	int eval;
++	int rc;
  
- /*
-+ * DASD_3990_ERP_INSPECT_ALIAS
-+ *
-+ * DESCRIPTION
-+ *   Checks if the original request was started on an alias device.
-+ *   If yes, it modifies the original and the erp request so that
-+ *   the erp request can be started on a base device.
-+ *
-+ * PARAMETER
-+ *   erp		pointer to the currently created default ERP
-+ *
-+ * RETURN VALUES
-+ *   erp		pointer to the modified ERP, or NULL
-+ */
+-	CIO_TRACE_EVENT(4, "slowpath");
+ 	spin_lock_irq(&slow_subchannel_lock);
+-	init_subchannel_id(&schid);
+-	while (idset_sch_get_first(slow_subchannel_set, &schid)) {
+-		idset_sch_del(slow_subchannel_set, schid);
+-		spin_unlock_irq(&slow_subchannel_lock);
+-		css_evaluate_subchannel(schid, 1);
+-		spin_lock_irq(&slow_subchannel_lock);
++	eval = idset_sch_contains(slow_subchannel_set, sch->schid);
++	idset_sch_del(slow_subchannel_set, sch->schid);
++	spin_unlock_irq(&slow_subchannel_lock);
++	if (eval) {
++		rc = css_evaluate_known_subchannel(sch, 1);
++		if (rc == -EAGAIN)
++			css_schedule_eval(sch->schid);
+ 	}
++	return 0;
++}
 +
-+static struct dasd_ccw_req *dasd_3990_erp_inspect_alias(
-+						struct dasd_ccw_req *erp)
++static int slow_eval_unknown_fn(struct subchannel_id schid, void *data)
 +{
-+	struct dasd_ccw_req *cqr = erp->refers;
++	int eval;
++	int rc = 0;
 +
-+	if (cqr->block &&
-+	    (cqr->block->base != cqr->startdev)) {
-+		if (cqr->startdev->features & DASD_FEATURE_ERPLOG) {
-+			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);
++	spin_lock_irq(&slow_subchannel_lock);
++	eval = idset_sch_contains(slow_subchannel_set, schid);
++	idset_sch_del(slow_subchannel_set, schid);
+ 	spin_unlock_irq(&slow_subchannel_lock);
++	if (eval) {
++		rc = css_evaluate_new_subchannel(schid, 1);
++		switch (rc) {
++		case -EAGAIN:
++			css_schedule_eval(schid);
++			rc = 0;
++			break;
++		case -ENXIO:
++		case -ENOMEM:
++		case -EIO:
++			/* These should abort looping */
++			break;
++		default:
++			rc = 0;
 +		}
-+		dasd_eckd_reset_ccw_to_base_io(cqr);
-+		erp->startdev = cqr->block->base;
-+		erp->function = dasd_3990_erp_inspect_alias;
-+		return erp;
-+	} else
-+		return NULL;
++	}
++	return rc;
 +}
 +
-+
-+/*
-  * DASD_3990_ERP_INSPECT_24
-  *
-  * DESCRIPTION
-@@ -1623,7 +1507,7 @@ static struct dasd_ccw_req *
- dasd_3990_erp_action_10_32(struct dasd_ccw_req * erp, char *sense)
++static void css_slow_path_func(struct work_struct *unused)
++{
++	CIO_TRACE_EVENT(4, "slowpath");
++	for_each_subchannel_staged(slow_eval_known_fn, slow_eval_unknown_fn,
++				   NULL);
+ }
+ 
+ static DECLARE_WORK(slow_path_work, css_slow_path_func);
+@@ -430,7 +536,6 @@ void css_schedule_eval_all(void)
+ /* Reprobe subchannel if unregistered. */
+ static int reprobe_subchannel(struct subchannel_id schid, void *data)
  {
+-	struct subchannel *sch;
+ 	int ret;
  
--	struct dasd_device *device = erp->device;
-+	struct dasd_device *device = erp->startdev;
+ 	CIO_MSG_EVENT(6, "cio: reprobe 0.%x.%04x\n",
+@@ -438,13 +543,6 @@ static int reprobe_subchannel(struct subchannel_id schid, void *data)
+ 	if (need_reprobe)
+ 		return -EAGAIN;
  
- 	erp->retries = 256;
- 	erp->function = dasd_3990_erp_action_10_32;
-@@ -1657,13 +1541,14 @@ static struct dasd_ccw_req *
- dasd_3990_erp_action_1B_32(struct dasd_ccw_req * default_erp, char *sense)
+-	sch = get_subchannel_by_schid(schid);
+-	if (sch) {
+-		/* Already known. */
+-		put_device(&sch->dev);
+-		return 0;
+-	}
+-
+ 	ret = css_probe_device(schid);
+ 	switch (ret) {
+ 	case 0:
+@@ -472,7 +570,7 @@ static void reprobe_all(struct work_struct *unused)
+ 	/* Make sure initial subchannel scan is done. */
+ 	wait_event(ccw_device_init_wq,
+ 		   atomic_read(&ccw_device_init_count) == 0);
+-	ret = for_each_subchannel(reprobe_subchannel, NULL);
++	ret = for_each_subchannel_staged(NULL, reprobe_subchannel, NULL);
+ 
+ 	CIO_MSG_EVENT(2, "reprobe done (rc=%d, need_reprobe=%d)\n", ret,
+ 		      need_reprobe);
+@@ -787,8 +885,8 @@ int sch_is_pseudo_sch(struct subchannel *sch)
+ static int
+ css_bus_match (struct device *dev, struct device_driver *drv)
  {
+-	struct subchannel *sch = container_of (dev, struct subchannel, dev);
+-	struct css_driver *driver = container_of (drv, struct css_driver, drv);
++	struct subchannel *sch = to_subchannel(dev);
++	struct css_driver *driver = to_cssdriver(drv);
  
--	struct dasd_device *device = default_erp->device;
-+	struct dasd_device *device = default_erp->startdev;
- 	__u32 cpa = 0;
- 	struct dasd_ccw_req *cqr;
- 	struct dasd_ccw_req *erp;
- 	struct DE_eckd_data *DE_data;
-+	struct PFX_eckd_data *PFX_data;
- 	char *LO_data;		/* LO_eckd_data_t */
--	struct ccw1 *ccw;
-+	struct ccw1 *ccw, *oldccw;
+ 	if (sch->st == driver->subchannel_type)
+ 		return 1;
+@@ -796,32 +894,36 @@ css_bus_match (struct device *dev, struct device_driver *drv)
+ 	return 0;
+ }
  
- 	DEV_MESSAGE(KERN_DEBUG, device, "%s",
- 		    "Write not finished because of unexpected condition");
-@@ -1702,8 +1587,8 @@ dasd_3990_erp_action_1B_32(struct dasd_ccw_req * default_erp, char *sense)
- 	/* Build new ERP request including DE/LO */
- 	erp = dasd_alloc_erp_request((char *) &cqr->magic,
- 				     2 + 1,/* DE/LO + TIC */
--				     sizeof (struct DE_eckd_data) +
--				     sizeof (struct LO_eckd_data), device);
-+				     sizeof(struct DE_eckd_data) +
-+				     sizeof(struct LO_eckd_data), device);
+-static int
+-css_probe (struct device *dev)
++static int css_probe(struct device *dev)
+ {
+ 	struct subchannel *sch;
++	int ret;
  
- 	if (IS_ERR(erp)) {
- 		DEV_MESSAGE(KERN_ERR, device, "%s", "Unable to allocate ERP");
-@@ -1712,10 +1597,16 @@ dasd_3990_erp_action_1B_32(struct dasd_ccw_req * default_erp, char *sense)
+ 	sch = to_subchannel(dev);
+-	sch->driver = container_of (dev->driver, struct css_driver, drv);
+-	return (sch->driver->probe ? sch->driver->probe(sch) : 0);
++	sch->driver = to_cssdriver(dev->driver);
++	ret = sch->driver->probe ? sch->driver->probe(sch) : 0;
++	if (ret)
++		sch->driver = NULL;
++	return ret;
+ }
  
- 	/* use original DE */
- 	DE_data = erp->data;
--	memcpy(DE_data, cqr->data, sizeof (struct DE_eckd_data));
-+	oldccw = cqr->cpaddr;
-+	if (oldccw->cmd_code == DASD_ECKD_CCW_PFX) {
-+		PFX_data = cqr->data;
-+		memcpy(DE_data, &PFX_data->define_extend,
-+		       sizeof(struct DE_eckd_data));
-+	} else
-+		memcpy(DE_data, cqr->data, sizeof(struct DE_eckd_data));
+-static int
+-css_remove (struct device *dev)
++static int css_remove(struct device *dev)
+ {
+ 	struct subchannel *sch;
++	int ret;
  
- 	/* create LO */
--	LO_data = erp->data + sizeof (struct DE_eckd_data);
-+	LO_data = erp->data + sizeof(struct DE_eckd_data);
+ 	sch = to_subchannel(dev);
+-	return (sch->driver->remove ? sch->driver->remove(sch) : 0);
++	ret = sch->driver->remove ? sch->driver->remove(sch) : 0;
++	sch->driver = NULL;
++	return ret;
+ }
  
- 	if ((sense[3] == 0x01) && (LO_data[1] & 0x01)) {
+-static void
+-css_shutdown (struct device *dev)
++static void css_shutdown(struct device *dev)
+ {
+ 	struct subchannel *sch;
  
-@@ -1748,7 +1639,7 @@ dasd_3990_erp_action_1B_32(struct dasd_ccw_req * default_erp, char *sense)
+ 	sch = to_subchannel(dev);
+-	if (sch->driver->shutdown)
++	if (sch->driver && sch->driver->shutdown)
+ 		sch->driver->shutdown(sch);
+ }
  
- 	/* create DE ccw */
- 	ccw = erp->cpaddr;
--	memset(ccw, 0, sizeof (struct ccw1));
-+	memset(ccw, 0, sizeof(struct ccw1));
- 	ccw->cmd_code = DASD_ECKD_CCW_DEFINE_EXTENT;
- 	ccw->flags = CCW_FLAG_CC;
- 	ccw->count = 16;
-@@ -1756,7 +1647,7 @@ dasd_3990_erp_action_1B_32(struct dasd_ccw_req * default_erp, char *sense)
+@@ -833,6 +935,34 @@ struct bus_type css_bus_type = {
+ 	.shutdown = css_shutdown,
+ };
  
- 	/* create LO ccw */
- 	ccw++;
--	memset(ccw, 0, sizeof (struct ccw1));
-+	memset(ccw, 0, sizeof(struct ccw1));
- 	ccw->cmd_code = DASD_ECKD_CCW_LOCATE_RECORD;
- 	ccw->flags = CCW_FLAG_CC;
- 	ccw->count = 16;
-@@ -1770,7 +1661,8 @@ dasd_3990_erp_action_1B_32(struct dasd_ccw_req * default_erp, char *sense)
- 	/* fill erp related fields */
- 	erp->function = dasd_3990_erp_action_1B_32;
- 	erp->refers = default_erp->refers;
--	erp->device = device;
-+	erp->startdev = device;
-+	erp->memdev = device;
- 	erp->magic = default_erp->magic;
- 	erp->expires = 0;
- 	erp->retries = 256;
-@@ -1803,7 +1695,7 @@ static struct dasd_ccw_req *
- dasd_3990_update_1B(struct dasd_ccw_req * previous_erp, char *sense)
- {
++/**
++ * css_driver_register - register a css driver
++ * @cdrv: css driver to register
++ *
++ * This is mainly a wrapper around driver_register that sets name
++ * and bus_type in the embedded struct device_driver correctly.
++ */
++int css_driver_register(struct css_driver *cdrv)
++{
++	cdrv->drv.name = cdrv->name;
++	cdrv->drv.bus = &css_bus_type;
++	cdrv->drv.owner = cdrv->owner;
++	return driver_register(&cdrv->drv);
++}
++EXPORT_SYMBOL_GPL(css_driver_register);
++
++/**
++ * css_driver_unregister - unregister a css driver
++ * @cdrv: css driver to unregister
++ *
++ * This is a wrapper around driver_unregister.
++ */
++void css_driver_unregister(struct css_driver *cdrv)
++{
++	driver_unregister(&cdrv->drv);
++}
++EXPORT_SYMBOL_GPL(css_driver_unregister);
++
+ subsys_initcall(init_channel_subsystem);
  
--	struct dasd_device *device = previous_erp->device;
-+	struct dasd_device *device = previous_erp->startdev;
- 	__u32 cpa = 0;
- 	struct dasd_ccw_req *cqr;
- 	struct dasd_ccw_req *erp;
-@@ -1827,7 +1719,7 @@ dasd_3990_update_1B(struct dasd_ccw_req * previous_erp, char *sense)
- 		DEV_MESSAGE(KERN_DEBUG, device, "%s",
- 			    "Imprecise ending is set - just retry");
+ MODULE_LICENSE("GPL");
+diff --git a/drivers/s390/cio/css.h b/drivers/s390/cio/css.h
+index 81215ef..b705545 100644
+--- a/drivers/s390/cio/css.h
++++ b/drivers/s390/cio/css.h
+@@ -58,64 +58,6 @@ struct pgid {
+ 	__u32 tod_high;		/* high word TOD clock */
+ } __attribute__ ((packed));
  
--		previous_erp->status = DASD_CQR_QUEUED;
-+		previous_erp->status = DASD_CQR_FILLED;
+-#define MAX_CIWS 8
+-
+-/*
+- * sense-id response buffer layout
+- */
+-struct senseid {
+-	/* common part */
+-	__u8  reserved;     	/* always 0x'FF' */
+-	__u16 cu_type;	     	/* control unit type */
+-	__u8  cu_model;     	/* control unit model */
+-	__u16 dev_type;     	/* device type */
+-	__u8  dev_model;    	/* device model */
+-	__u8  unused;	     	/* padding byte */
+-	/* extended part */
+-	struct ciw ciw[MAX_CIWS];	/* variable # of CIWs */
+-}  __attribute__ ((packed,aligned(4)));
+-
+-struct ccw_device_private {
+-	struct ccw_device *cdev;
+-	struct subchannel *sch;
+-	int state;		/* device state */
+-	atomic_t onoff;
+-	unsigned long registered;
+-	struct ccw_dev_id dev_id;	/* device id */
+-	struct subchannel_id schid;	/* subchannel number */
+-	__u8 imask;		/* lpm mask for SNID/SID/SPGID */
+-	int iretry;		/* retry counter SNID/SID/SPGID */
+-	struct {
+-		unsigned int fast:1;	/* post with "channel end" */
+-		unsigned int repall:1;	/* report every interrupt status */
+-		unsigned int pgroup:1;  /* do path grouping */
+-		unsigned int force:1;   /* allow forced online */
+-	} __attribute__ ((packed)) options;
+-	struct {
+-		unsigned int pgid_single:1; /* use single path for Set PGID */
+-		unsigned int esid:1;        /* Ext. SenseID supported by HW */
+-		unsigned int dosense:1;	    /* delayed SENSE required */
+-		unsigned int doverify:1;    /* delayed path verification */
+-		unsigned int donotify:1;    /* call notify function */
+-		unsigned int recog_done:1;  /* dev. recog. complete */
+-		unsigned int fake_irb:1;    /* deliver faked irb */
+-		unsigned int intretry:1;    /* retry internal operation */
+-	} __attribute__((packed)) flags;
+-	unsigned long intparm;	/* user interruption parameter */
+-	struct qdio_irq *qdio_data;
+-	struct irb irb;		/* device status */
+-	struct senseid senseid;	/* SenseID info */
+-	struct pgid pgid[8];	/* path group IDs per chpid*/
+-	struct ccw1 iccws[2];	/* ccws for SNID/SID/SPGID commands */
+-	struct work_struct kick_work;
+-	wait_queue_head_t wait_q;
+-	struct timer_list timer;
+-	void *cmb;			/* measurement information */
+-	struct list_head cmb_list;	/* list of measured devices */
+-	u64 cmb_start_time;		/* clock value of cmb reset */
+-	void *cmb_wait;			/* deferred cmb enable/disable */
+-};
+-
+ /*
+  * A css driver handles all subchannels of one type.
+  * Currently, we only care about I/O subchannels (type 0), these
+@@ -123,25 +65,35 @@ struct ccw_device_private {
+  */
+ struct subchannel;
+ struct css_driver {
++	struct module *owner;
+ 	unsigned int subchannel_type;
+ 	struct device_driver drv;
+-	void (*irq)(struct device *);
+-	int (*notify)(struct device *, int);
+-	void (*verify)(struct device *);
+-	void (*termination)(struct device *);
++	void (*irq)(struct subchannel *);
++	int (*notify)(struct subchannel *, int);
++	void (*verify)(struct subchannel *);
++	void (*termination)(struct subchannel *);
+ 	int (*probe)(struct subchannel *);
+ 	int (*remove)(struct subchannel *);
+ 	void (*shutdown)(struct subchannel *);
++	const char *name;
+ };
  
- 		return previous_erp;
- 	}
-@@ -1850,7 +1742,7 @@ dasd_3990_update_1B(struct dasd_ccw_req * previous_erp, char *sense)
- 	erp = previous_erp;
++#define to_cssdriver(n) container_of(n, struct css_driver, drv)
++
+ /*
+  * all css_drivers have the css_bus_type
+  */
+ extern struct bus_type css_bus_type;
  
- 	/* update the LO with the new returned sense data  */
--	LO_data = erp->data + sizeof (struct DE_eckd_data);
-+	LO_data = erp->data + sizeof(struct DE_eckd_data);
++extern int css_driver_register(struct css_driver *);
++extern void css_driver_unregister(struct css_driver *);
++
+ extern void css_sch_device_unregister(struct subchannel *);
+ extern struct subchannel * get_subchannel_by_schid(struct subchannel_id);
+ extern int css_init_done;
++int for_each_subchannel_staged(int (*fn_known)(struct subchannel *, void *),
++			       int (*fn_unknown)(struct subchannel_id,
++			       void *), void *data);
+ extern int for_each_subchannel(int(*fn)(struct subchannel_id, void *), void *);
+ extern void css_process_crw(int, int);
+ extern void css_reiterate_subchannels(void);
+@@ -188,6 +140,8 @@ void css_schedule_eval(struct subchannel_id schid);
+ void css_schedule_eval_all(void);
  
- 	if ((sense[3] == 0x01) && (LO_data[1] & 0x01)) {
+ int sch_is_pseudo_sch(struct subchannel *);
++struct schib;
++int css_sch_is_valid(struct schib *);
  
-@@ -1889,7 +1781,7 @@ dasd_3990_update_1B(struct dasd_ccw_req * previous_erp, char *sense)
- 	ccw++;			/* addr of TIC ccw */
- 	ccw->cda = cpa;
+ extern struct workqueue_struct *slow_path_wq;
  
--	erp->status = DASD_CQR_QUEUED;
-+	erp->status = DASD_CQR_FILLED;
+diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c
+index 74f6b53..d35dc3f 100644
+--- a/drivers/s390/cio/device.c
++++ b/drivers/s390/cio/device.c
+@@ -17,6 +17,7 @@
+ #include <linux/list.h>
+ #include <linux/device.h>
+ #include <linux/workqueue.h>
++#include <linux/timer.h>
  
- 	return erp;
+ #include <asm/ccwdev.h>
+ #include <asm/cio.h>
+@@ -28,6 +29,12 @@
+ #include "css.h"
+ #include "device.h"
+ #include "ioasm.h"
++#include "io_sch.h"
++
++static struct timer_list recovery_timer;
++static spinlock_t recovery_lock;
++static int recovery_phase;
++static const unsigned long recovery_delay[] = { 3, 30, 300 };
  
-@@ -1968,9 +1860,7 @@ dasd_3990_erp_compound_path(struct dasd_ccw_req * erp, char *sense)
- 			 * try further actions. */
+ /******************* bus type handling ***********************/
  
- 			erp->lpm = 0;
--
--			erp->status = DASD_CQR_ERROR;
--
-+			erp->status = DASD_CQR_NEED_ERP;
- 		}
- 	}
+@@ -115,19 +122,18 @@ static int ccw_uevent(struct device *dev, struct kobj_uevent_env *env)
  
-@@ -2047,7 +1937,7 @@ dasd_3990_erp_compound_config(struct dasd_ccw_req * erp, char *sense)
- 	if ((sense[25] & DASD_SENSE_BIT_1) && (sense[26] & DASD_SENSE_BIT_2)) {
+ struct bus_type ccw_bus_type;
  
- 		/* set to suspended duplex state then restart */
--		struct dasd_device *device = erp->device;
-+		struct dasd_device *device = erp->startdev;
+-static int io_subchannel_probe (struct subchannel *);
+-static int io_subchannel_remove (struct subchannel *);
+-static int io_subchannel_notify(struct device *, int);
+-static void io_subchannel_verify(struct device *);
+-static void io_subchannel_ioterm(struct device *);
++static void io_subchannel_irq(struct subchannel *);
++static int io_subchannel_probe(struct subchannel *);
++static int io_subchannel_remove(struct subchannel *);
++static int io_subchannel_notify(struct subchannel *, int);
++static void io_subchannel_verify(struct subchannel *);
++static void io_subchannel_ioterm(struct subchannel *);
+ static void io_subchannel_shutdown(struct subchannel *);
  
- 		DEV_MESSAGE(KERN_ERR, device, "%s",
- 			    "Set device to suspended duplex state should be "
-@@ -2081,28 +1971,26 @@ dasd_3990_erp_compound(struct dasd_ccw_req * erp, char *sense)
+ static struct css_driver io_subchannel_driver = {
++	.owner = THIS_MODULE,
+ 	.subchannel_type = SUBCHANNEL_TYPE_IO,
+-	.drv = {
+-		.name = "io_subchannel",
+-		.bus  = &css_bus_type,
+-	},
++	.name = "io_subchannel",
+ 	.irq = io_subchannel_irq,
+ 	.notify = io_subchannel_notify,
+ 	.verify = io_subchannel_verify,
+@@ -142,6 +148,8 @@ struct workqueue_struct *ccw_device_notify_work;
+ wait_queue_head_t ccw_device_init_wq;
+ atomic_t ccw_device_init_count;
+ 
++static void recovery_func(unsigned long data);
++
+ static int __init
+ init_ccw_bus_type (void)
  {
+@@ -149,6 +157,7 @@ init_ccw_bus_type (void)
  
- 	if ((erp->function == dasd_3990_erp_compound_retry) &&
--	    (erp->status == DASD_CQR_ERROR)) {
-+	    (erp->status == DASD_CQR_NEED_ERP)) {
+ 	init_waitqueue_head(&ccw_device_init_wq);
+ 	atomic_set(&ccw_device_init_count, 0);
++	setup_timer(&recovery_timer, recovery_func, 0);
  
- 		dasd_3990_erp_compound_path(erp, sense);
- 	}
+ 	ccw_device_work = create_singlethread_workqueue("cio");
+ 	if (!ccw_device_work)
+@@ -166,7 +175,8 @@ init_ccw_bus_type (void)
+ 	if ((ret = bus_register (&ccw_bus_type)))
+ 		goto out_err;
  
- 	if ((erp->function == dasd_3990_erp_compound_path) &&
--	    (erp->status == DASD_CQR_ERROR)) {
-+	    (erp->status == DASD_CQR_NEED_ERP)) {
+-	if ((ret = driver_register(&io_subchannel_driver.drv)))
++	ret = css_driver_register(&io_subchannel_driver);
++	if (ret)
+ 		goto out_err;
  
- 		erp = dasd_3990_erp_compound_code(erp, sense);
+ 	wait_event(ccw_device_init_wq,
+@@ -186,7 +196,7 @@ out_err:
+ static void __exit
+ cleanup_ccw_bus_type (void)
+ {
+-	driver_unregister(&io_subchannel_driver.drv);
++	css_driver_unregister(&io_subchannel_driver);
+ 	bus_unregister(&ccw_bus_type);
+ 	destroy_workqueue(ccw_device_notify_work);
+ 	destroy_workqueue(ccw_device_work);
+@@ -773,7 +783,7 @@ static void sch_attach_device(struct subchannel *sch,
+ {
+ 	css_update_ssd_info(sch);
+ 	spin_lock_irq(sch->lock);
+-	sch->dev.driver_data = cdev;
++	sch_set_cdev(sch, cdev);
+ 	cdev->private->schid = sch->schid;
+ 	cdev->ccwlock = sch->lock;
+ 	device_trigger_reprobe(sch);
+@@ -795,7 +805,7 @@ static void sch_attach_disconnected_device(struct subchannel *sch,
+ 		put_device(&other_sch->dev);
+ 		return;
  	}
- 
- 	if ((erp->function == dasd_3990_erp_compound_code) &&
--	    (erp->status == DASD_CQR_ERROR)) {
-+	    (erp->status == DASD_CQR_NEED_ERP)) {
- 
- 		dasd_3990_erp_compound_config(erp, sense);
+-	other_sch->dev.driver_data = NULL;
++	sch_set_cdev(other_sch, NULL);
+ 	/* No need to keep a subchannel without ccw device around. */
+ 	css_sch_device_unregister(other_sch);
+ 	put_device(&other_sch->dev);
+@@ -831,12 +841,12 @@ static void sch_create_and_recog_new_device(struct subchannel *sch)
+ 		return;
  	}
+ 	spin_lock_irq(sch->lock);
+-	sch->dev.driver_data = cdev;
++	sch_set_cdev(sch, cdev);
+ 	spin_unlock_irq(sch->lock);
+ 	/* Start recognition for the new ccw device. */
+ 	if (io_subchannel_recog(cdev, sch)) {
+ 		spin_lock_irq(sch->lock);
+-		sch->dev.driver_data = NULL;
++		sch_set_cdev(sch, NULL);
+ 		spin_unlock_irq(sch->lock);
+ 		if (cdev->dev.release)
+ 			cdev->dev.release(&cdev->dev);
+@@ -940,7 +950,7 @@ io_subchannel_register(struct work_struct *work)
+ 			      cdev->private->dev_id.devno, ret);
+ 		put_device(&cdev->dev);
+ 		spin_lock_irqsave(sch->lock, flags);
+-		sch->dev.driver_data = NULL;
++		sch_set_cdev(sch, NULL);
+ 		spin_unlock_irqrestore(sch->lock, flags);
+ 		kfree (cdev->private);
+ 		kfree (cdev);
+@@ -1022,7 +1032,7 @@ io_subchannel_recog(struct ccw_device *cdev, struct subchannel *sch)
+ 	int rc;
+ 	struct ccw_device_private *priv;
  
- 	/* if no compound action ERP specified, the request failed */
--	if (erp->status == DASD_CQR_ERROR) {
--
-+	if (erp->status == DASD_CQR_NEED_ERP)
- 		erp->status = DASD_CQR_FAILED;
--	}
+-	sch->dev.driver_data = cdev;
++	sch_set_cdev(sch, cdev);
+ 	sch->driver = &io_subchannel_driver;
+ 	cdev->ccwlock = sch->lock;
  
- 	return erp;
+@@ -1082,7 +1092,7 @@ static void ccw_device_move_to_sch(struct work_struct *work)
+ 	}
+ 	if (former_parent) {
+ 		spin_lock_irq(former_parent->lock);
+-		former_parent->dev.driver_data = NULL;
++		sch_set_cdev(former_parent, NULL);
+ 		spin_unlock_irq(former_parent->lock);
+ 		css_sch_device_unregister(former_parent);
+ 		/* Reset intparm to zeroes. */
+@@ -1096,6 +1106,18 @@ out:
+ 	put_device(&cdev->dev);
+ }
  
-@@ -2127,7 +2015,7 @@ static struct dasd_ccw_req *
- dasd_3990_erp_inspect_32(struct dasd_ccw_req * erp, char *sense)
++static void io_subchannel_irq(struct subchannel *sch)
++{
++	struct ccw_device *cdev;
++
++	cdev = sch_get_cdev(sch);
++
++	CIO_TRACE_EVENT(3, "IRQ");
++	CIO_TRACE_EVENT(3, sch->dev.bus_id);
++	if (cdev)
++		dev_fsm_event(cdev, DEV_EVENT_INTERRUPT);
++}
++
+ static int
+ io_subchannel_probe (struct subchannel *sch)
  {
+@@ -1104,13 +1126,13 @@ io_subchannel_probe (struct subchannel *sch)
+ 	unsigned long flags;
+ 	struct ccw_dev_id dev_id;
  
--	struct dasd_device *device = erp->device;
-+	struct dasd_device *device = erp->startdev;
- 
- 	erp->function = dasd_3990_erp_inspect_32;
- 
-@@ -2149,8 +2037,7 @@ dasd_3990_erp_inspect_32(struct dasd_ccw_req * erp, char *sense)
- 
- 		case 0x01:	/* fatal error */
- 			DEV_MESSAGE(KERN_ERR, device, "%s",
--				    "Fatal error should have been "
--				    "handled within the interrupt handler");
-+				    "Retry not recommended - Fatal error");
+-	if (sch->dev.driver_data) {
++	cdev = sch_get_cdev(sch);
++	if (cdev) {
+ 		/*
+ 		 * This subchannel already has an associated ccw_device.
+ 		 * Register it and exit. This happens for all early
+ 		 * device, e.g. the console.
+ 		 */
+-		cdev = sch->dev.driver_data;
+ 		cdev->dev.groups = ccwdev_attr_groups;
+ 		device_initialize(&cdev->dev);
+ 		ccw_device_register(cdev);
+@@ -1132,6 +1154,11 @@ io_subchannel_probe (struct subchannel *sch)
+ 	 */
+ 	dev_id.devno = sch->schib.pmcw.dev;
+ 	dev_id.ssid = sch->schid.ssid;
++	/* Allocate I/O subchannel private data. */
++	sch->private = kzalloc(sizeof(struct io_subchannel_private),
++			       GFP_KERNEL | GFP_DMA);
++	if (!sch->private)
++		return -ENOMEM;
+ 	cdev = get_disc_ccwdev_by_dev_id(&dev_id, NULL);
+ 	if (!cdev)
+ 		cdev = get_orphaned_ccwdev_by_dev_id(to_css(sch->dev.parent),
+@@ -1149,16 +1176,18 @@ io_subchannel_probe (struct subchannel *sch)
+ 		return 0;
+ 	}
+ 	cdev = io_subchannel_create_ccwdev(sch);
+-	if (IS_ERR(cdev))
++	if (IS_ERR(cdev)) {
++		kfree(sch->private);
+ 		return PTR_ERR(cdev);
+-
++	}
+ 	rc = io_subchannel_recog(cdev, sch);
+ 	if (rc) {
+ 		spin_lock_irqsave(sch->lock, flags);
+-		sch->dev.driver_data = NULL;
++		sch_set_cdev(sch, NULL);
+ 		spin_unlock_irqrestore(sch->lock, flags);
+ 		if (cdev->dev.release)
+ 			cdev->dev.release(&cdev->dev);
++		kfree(sch->private);
+ 	}
  
- 			erp = dasd_3990_erp_cleanup(erp, DASD_CQR_FAILED);
- 			break;
-@@ -2253,6 +2140,11 @@ dasd_3990_erp_inspect(struct dasd_ccw_req * erp)
- 	/* already set up new ERP !			      */
- 	char *sense = erp->refers->irb.ecw;
+ 	return rc;
+@@ -1170,25 +1199,25 @@ io_subchannel_remove (struct subchannel *sch)
+ 	struct ccw_device *cdev;
+ 	unsigned long flags;
  
-+	/* if this problem occured on an alias retry on base */
-+	erp_new = dasd_3990_erp_inspect_alias(erp);
-+	if (erp_new)
-+		return erp_new;
-+
- 	/* distinguish between 24 and 32 byte sense data */
- 	if (sense[27] & DASD_SENSE_BIT_0) {
+-	if (!sch->dev.driver_data)
++	cdev = sch_get_cdev(sch);
++	if (!cdev)
+ 		return 0;
+-	cdev = sch->dev.driver_data;
+ 	/* Set ccw device to not operational and drop reference. */
+ 	spin_lock_irqsave(cdev->ccwlock, flags);
+-	sch->dev.driver_data = NULL;
++	sch_set_cdev(sch, NULL);
+ 	cdev->private->state = DEV_STATE_NOT_OPER;
+ 	spin_unlock_irqrestore(cdev->ccwlock, flags);
+ 	ccw_device_unregister(cdev);
+ 	put_device(&cdev->dev);
++	kfree(sch->private);
+ 	return 0;
+ }
  
-@@ -2287,13 +2179,13 @@ static struct dasd_ccw_req *
- dasd_3990_erp_add_erp(struct dasd_ccw_req * cqr)
+-static int
+-io_subchannel_notify(struct device *dev, int event)
++static int io_subchannel_notify(struct subchannel *sch, int event)
  {
+ 	struct ccw_device *cdev;
  
--	struct dasd_device *device = cqr->device;
-+	struct dasd_device *device = cqr->startdev;
- 	struct ccw1 *ccw;
- 
- 	/* allocate additional request block */
- 	struct dasd_ccw_req *erp;
+-	cdev = dev->driver_data;
++	cdev = sch_get_cdev(sch);
+ 	if (!cdev)
+ 		return 0;
+ 	if (!cdev->drv)
+@@ -1198,22 +1227,20 @@ io_subchannel_notify(struct device *dev, int event)
+ 	return cdev->drv->notify ? cdev->drv->notify(cdev, event) : 0;
+ }
  
--	erp = dasd_alloc_erp_request((char *) &cqr->magic, 2, 0, cqr->device);
-+	erp = dasd_alloc_erp_request((char *) &cqr->magic, 2, 0, device);
- 	if (IS_ERR(erp)) {
-                 if (cqr->retries <= 0) {
- 		        DEV_MESSAGE(KERN_ERR, device, "%s",
-@@ -2305,7 +2197,7 @@ dasd_3990_erp_add_erp(struct dasd_ccw_req * cqr)
-                                      "Unable to allocate ERP request "
- 				     "(%i retries left)",
-                                      cqr->retries);
--			dasd_set_timer(device, (HZ << 3));
-+			dasd_block_set_timer(device->block, (HZ << 3));
-                 }
- 		return cqr;
- 	}
-@@ -2319,7 +2211,9 @@ dasd_3990_erp_add_erp(struct dasd_ccw_req * cqr)
- 	ccw->cda      = (long)(cqr->cpaddr);
- 	erp->function = dasd_3990_erp_add_erp;
- 	erp->refers   = cqr;
--	erp->device   = cqr->device;
-+	erp->startdev = device;
-+	erp->memdev   = device;
-+	erp->block    = cqr->block;
- 	erp->magic    = cqr->magic;
- 	erp->expires  = 0;
- 	erp->retries  = 256;
-@@ -2466,7 +2360,7 @@ static struct dasd_ccw_req *
- dasd_3990_erp_further_erp(struct dasd_ccw_req *erp)
+-static void
+-io_subchannel_verify(struct device *dev)
++static void io_subchannel_verify(struct subchannel *sch)
  {
+ 	struct ccw_device *cdev;
  
--	struct dasd_device *device = erp->device;
-+	struct dasd_device *device = erp->startdev;
- 	char *sense = erp->irb.ecw;
+-	cdev = dev->driver_data;
++	cdev = sch_get_cdev(sch);
+ 	if (cdev)
+ 		dev_fsm_event(cdev, DEV_EVENT_VERIFY);
+ }
  
- 	/* check for 24 byte sense ERP */
-@@ -2557,7 +2451,7 @@ dasd_3990_erp_handle_match_erp(struct dasd_ccw_req *erp_head,
- 			       struct dasd_ccw_req *erp)
+-static void
+-io_subchannel_ioterm(struct device *dev)
++static void io_subchannel_ioterm(struct subchannel *sch)
  {
+ 	struct ccw_device *cdev;
  
--	struct dasd_device *device = erp_head->device;
-+	struct dasd_device *device = erp_head->startdev;
- 	struct dasd_ccw_req *erp_done = erp_head;	/* finished req */
- 	struct dasd_ccw_req *erp_free = NULL;	/* req to be freed */
- 
-@@ -2569,13 +2463,13 @@ dasd_3990_erp_handle_match_erp(struct dasd_ccw_req *erp_head,
- 			      "original request was lost\n");
- 
- 		/* remove the request from the device queue */
--		list_del(&erp_done->list);
-+		list_del(&erp_done->blocklist);
- 
- 		erp_free = erp_done;
- 		erp_done = erp_done->refers;
- 
- 		/* free the finished erp request */
--		dasd_free_erp_request(erp_free, erp_free->device);
-+		dasd_free_erp_request(erp_free, erp_free->memdev);
- 
- 	}			/* end while */
- 
-@@ -2603,7 +2497,7 @@ dasd_3990_erp_handle_match_erp(struct dasd_ccw_req *erp_head,
- 				    erp->retries, erp);
+-	cdev = dev->driver_data;
++	cdev = sch_get_cdev(sch);
+ 	if (!cdev)
+ 		return;
+ 	/* Internal I/O will be retried by the interrupt handler. */
+@@ -1231,7 +1258,7 @@ io_subchannel_shutdown(struct subchannel *sch)
+ 	struct ccw_device *cdev;
+ 	int ret;
  
- 			/* handle the request again... */
--			erp->status = DASD_CQR_QUEUED;
-+			erp->status = DASD_CQR_FILLED;
- 		}
+-	cdev = sch->dev.driver_data;
++	cdev = sch_get_cdev(sch);
  
- 	} else {
-@@ -2620,7 +2514,7 @@ dasd_3990_erp_handle_match_erp(struct dasd_ccw_req *erp_head,
-  * DASD_3990_ERP_ACTION
-  *
-  * DESCRIPTION
-- *   controll routine for 3990 erp actions.
-+ *   control routine for 3990 erp actions.
-  *   Has to be called with the queue lock (namely the s390_irq_lock) acquired.
-  *
-  * PARAMETER
-@@ -2636,9 +2530,8 @@ dasd_3990_erp_handle_match_erp(struct dasd_ccw_req *erp_head,
- struct dasd_ccw_req *
- dasd_3990_erp_action(struct dasd_ccw_req * cqr)
+ 	if (cio_is_console(sch->schid))
+ 		return;
+@@ -1271,6 +1298,9 @@ ccw_device_console_enable (struct ccw_device *cdev, struct subchannel *sch)
  {
--
- 	struct dasd_ccw_req *erp = NULL;
--	struct dasd_device *device = cqr->device;
-+	struct dasd_device *device = cqr->startdev;
- 	struct dasd_ccw_req *temp_erp = NULL;
+ 	int rc;
  
- 	if (device->features & DASD_FEATURE_ERPLOG) {
-@@ -2704,10 +2597,11 @@ dasd_3990_erp_action(struct dasd_ccw_req * cqr)
- 		}
- 	}
++	/* Attach subchannel private data. */
++	sch->private = cio_get_console_priv();
++	memset(sch->private, 0, sizeof(struct io_subchannel_private));
+ 	/* Initialize the ccw_device structure. */
+ 	cdev->dev.parent= &sch->dev;
+ 	rc = io_subchannel_recog(cdev, sch);
+@@ -1456,6 +1486,7 @@ int ccw_driver_register(struct ccw_driver *cdriver)
  
--	/* enqueue added ERP request */
--	if (erp->status == DASD_CQR_FILLED) {
--		erp->status = DASD_CQR_QUEUED;
--		list_add(&erp->list, &device->ccw_queue);
-+	/* enqueue ERP request if it's a new one */
-+	if (list_empty(&erp->blocklist)) {
-+		cqr->status = DASD_CQR_IN_ERP;
-+		/* add erp request before the cqr */
-+		list_add_tail(&erp->blocklist, &cqr->blocklist);
- 	}
+ 	drv->bus = &ccw_bus_type;
+ 	drv->name = cdriver->name;
++	drv->owner = cdriver->owner;
  
- 	return erp;
-diff --git a/drivers/s390/block/dasd_9336_erp.c b/drivers/s390/block/dasd_9336_erp.c
-deleted file mode 100644
-index 6e08268..0000000
---- a/drivers/s390/block/dasd_9336_erp.c
-+++ /dev/null
-@@ -1,41 +0,0 @@
--/*
-- * File...........: linux/drivers/s390/block/dasd_9336_erp.c
-- * Author(s)......: Holger Smolinski <Holger.Smolinski at de.ibm.com>
-- * Bugreports.to..: <Linux390 at de.ibm.com>
-- * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000
-- *
-- */
--
--#define PRINTK_HEADER "dasd_erp(9336)"
--
--#include "dasd_int.h"
--
--
--/*
-- * DASD_9336_ERP_EXAMINE
-- *
-- * DESCRIPTION
-- *   Checks only for fatal/no/recover error.
-- *   A detailed examination of the sense data is done later outside
-- *   the interrupt handler.
-- *
-- *   The logic is based on the 'IBM 3880 Storage Control Reference' manual
-- *   'Chapter 7. 9336 Sense Data'.
-- *
-- * RETURN VALUES
-- *   dasd_era_none	no error
-- *   dasd_era_fatal	for all fatal (unrecoverable errors)
-- *   dasd_era_recover	for all others.
-- */
--dasd_era_t
--dasd_9336_erp_examine(struct dasd_ccw_req * cqr, struct irb * irb)
--{
--	/* check for successful execution first */
--	if (irb->scsw.cstat == 0x00 &&
--	    irb->scsw.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))
--		return dasd_era_none;
--
--	/* examine the 24 byte sense data */
--	return dasd_era_recover;
--
--}				/* END dasd_9336_erp_examine */
-diff --git a/drivers/s390/block/dasd_9343_erp.c b/drivers/s390/block/dasd_9343_erp.c
-deleted file mode 100644
-index ddecb98..0000000
---- a/drivers/s390/block/dasd_9343_erp.c
-+++ /dev/null
-@@ -1,21 +0,0 @@
--/*
-- * File...........: linux/drivers/s390/block/dasd_9345_erp.c
-- * Author(s)......: Holger Smolinski <Holger.Smolinski at de.ibm.com>
-- * Bugreports.to..: <Linux390 at de.ibm.com>
-- * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000
-- *
-- */
--
--#define PRINTK_HEADER "dasd_erp(9343)"
--
--#include "dasd_int.h"
--
--dasd_era_t
--dasd_9343_erp_examine(struct dasd_ccw_req * cqr, struct irb * irb)
--{
--	if (irb->scsw.cstat == 0x00 &&
--	    irb->scsw.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))
--		return dasd_era_none;
--
--	return dasd_era_recover;
--}
-diff --git a/drivers/s390/block/dasd_alias.c b/drivers/s390/block/dasd_alias.c
-new file mode 100644
-index 0000000..3a40bee
---- /dev/null
-+++ b/drivers/s390/block/dasd_alias.c
-@@ -0,0 +1,903 @@
-+/*
-+ * PAV alias management for the DASD ECKD discipline
-+ *
-+ * Copyright IBM Corporation, 2007
-+ * Author(s): Stefan Weinhuber <wein at de.ibm.com>
-+ */
-+
-+#include <linux/list.h>
-+#include <asm/ebcdic.h>
-+#include "dasd_int.h"
-+#include "dasd_eckd.h"
-+
-+#ifdef PRINTK_HEADER
-+#undef PRINTK_HEADER
-+#endif				/* PRINTK_HEADER */
-+#define PRINTK_HEADER "dasd(eckd):"
-+
-+
-+/*
-+ * General concept of alias management:
-+ * - PAV and DASD alias management is specific to the eckd discipline.
-+ * - A device is connected to an lcu as long as the device exists.
-+ *   dasd_alias_make_device_known_to_lcu will be called wenn the
-+ *   device is checked by the eckd discipline and
-+ *   dasd_alias_disconnect_device_from_lcu will be called
-+ *   before the device is deleted.
-+ * - The dasd_alias_add_device / dasd_alias_remove_device
-+ *   functions mark the point when a device is 'ready for service'.
-+ * - A summary unit check is a rare occasion, but it is mandatory to
-+ *   support it. It requires some complex recovery actions before the
-+ *   devices can be used again (see dasd_alias_handle_summary_unit_check).
-+ * - dasd_alias_get_start_dev will find an alias device that can be used
-+ *   instead of the base device and does some (very simple) load balancing.
-+ *   This is the function that gets called for each I/O, so when improving
-+ *   something, this function should get faster or better, the rest has just
-+ *   to be correct.
-+ */
-+
-+
-+static void summary_unit_check_handling_work(struct work_struct *);
-+static void lcu_update_work(struct work_struct *);
-+static int _schedule_lcu_update(struct alias_lcu *, struct dasd_device *);
-+
-+static struct alias_root aliastree = {
-+	.serverlist = LIST_HEAD_INIT(aliastree.serverlist),
-+	.lock = __SPIN_LOCK_UNLOCKED(aliastree.lock),
-+};
-+
-+static struct alias_server *_find_server(struct dasd_uid *uid)
-+{
-+	struct alias_server *pos;
-+	list_for_each_entry(pos, &aliastree.serverlist, server) {
-+		if (!strncmp(pos->uid.vendor, uid->vendor,
-+			     sizeof(uid->vendor))
-+		    && !strncmp(pos->uid.serial, uid->serial,
-+				sizeof(uid->serial)))
-+			return pos;
-+	};
-+	return NULL;
-+}
-+
-+static struct alias_lcu *_find_lcu(struct alias_server *server,
-+				   struct dasd_uid *uid)
-+{
-+	struct alias_lcu *pos;
-+	list_for_each_entry(pos, &server->lculist, lcu) {
-+		if (pos->uid.ssid == uid->ssid)
-+			return pos;
-+	};
-+	return NULL;
-+}
-+
-+static struct alias_pav_group *_find_group(struct alias_lcu *lcu,
-+					   struct dasd_uid *uid)
+ 	return driver_register(drv);
+ }
+@@ -1481,6 +1512,60 @@ ccw_device_get_subchannel_id(struct ccw_device *cdev)
+ 	return sch->schid;
+ }
+ 
++static int recovery_check(struct device *dev, void *data)
 +{
-+	struct alias_pav_group *pos;
-+	__u8 search_unit_addr;
++	struct ccw_device *cdev = to_ccwdev(dev);
++	int *redo = data;
 +
-+	/* for hyper pav there is only one group */
-+	if (lcu->pav == HYPER_PAV) {
-+		if (list_empty(&lcu->grouplist))
-+			return NULL;
-+		else
-+			return list_first_entry(&lcu->grouplist,
-+						struct alias_pav_group, group);
++	spin_lock_irq(cdev->ccwlock);
++	switch (cdev->private->state) {
++	case DEV_STATE_DISCONNECTED:
++		CIO_MSG_EVENT(3, "recovery: trigger 0.%x.%04x\n",
++			      cdev->private->dev_id.ssid,
++			      cdev->private->dev_id.devno);
++		dev_fsm_event(cdev, DEV_EVENT_VERIFY);
++		*redo = 1;
++		break;
++	case DEV_STATE_DISCONNECTED_SENSE_ID:
++		*redo = 1;
++		break;
 +	}
++	spin_unlock_irq(cdev->ccwlock);
 +
-+	/* for base pav we have to find the group that matches the base */
-+	if (uid->type == UA_BASE_DEVICE)
-+		search_unit_addr = uid->real_unit_addr;
-+	else
-+		search_unit_addr = uid->base_unit_addr;
-+	list_for_each_entry(pos, &lcu->grouplist, group) {
-+		if (pos->uid.base_unit_addr == search_unit_addr)
-+			return pos;
-+	};
-+	return NULL;
-+}
-+
-+static struct alias_server *_allocate_server(struct dasd_uid *uid)
-+{
-+	struct alias_server *server;
-+
-+	server = kzalloc(sizeof(*server), GFP_KERNEL);
-+	if (!server)
-+		return ERR_PTR(-ENOMEM);
-+	memcpy(server->uid.vendor, uid->vendor, sizeof(uid->vendor));
-+	memcpy(server->uid.serial, uid->serial, sizeof(uid->serial));
-+	INIT_LIST_HEAD(&server->server);
-+	INIT_LIST_HEAD(&server->lculist);
-+	return server;
-+}
-+
-+static void _free_server(struct alias_server *server)
-+{
-+	kfree(server);
-+}
-+
-+static struct alias_lcu *_allocate_lcu(struct dasd_uid *uid)
-+{
-+	struct alias_lcu *lcu;
-+
-+	lcu = kzalloc(sizeof(*lcu), GFP_KERNEL);
-+	if (!lcu)
-+		return ERR_PTR(-ENOMEM);
-+	lcu->uac = kzalloc(sizeof(*(lcu->uac)), GFP_KERNEL | GFP_DMA);
-+	if (!lcu->uac)
-+		goto out_err1;
-+	lcu->rsu_cqr = kzalloc(sizeof(*lcu->rsu_cqr), GFP_KERNEL | GFP_DMA);
-+	if (!lcu->rsu_cqr)
-+		goto out_err2;
-+	lcu->rsu_cqr->cpaddr = kzalloc(sizeof(struct ccw1),
-+				       GFP_KERNEL | GFP_DMA);
-+	if (!lcu->rsu_cqr->cpaddr)
-+		goto out_err3;
-+	lcu->rsu_cqr->data = kzalloc(16, GFP_KERNEL | GFP_DMA);
-+	if (!lcu->rsu_cqr->data)
-+		goto out_err4;
-+
-+	memcpy(lcu->uid.vendor, uid->vendor, sizeof(uid->vendor));
-+	memcpy(lcu->uid.serial, uid->serial, sizeof(uid->serial));
-+	lcu->uid.ssid = uid->ssid;
-+	lcu->pav = NO_PAV;
-+	lcu->flags = NEED_UAC_UPDATE | UPDATE_PENDING;
-+	INIT_LIST_HEAD(&lcu->lcu);
-+	INIT_LIST_HEAD(&lcu->inactive_devices);
-+	INIT_LIST_HEAD(&lcu->active_devices);
-+	INIT_LIST_HEAD(&lcu->grouplist);
-+	INIT_WORK(&lcu->suc_data.worker, summary_unit_check_handling_work);
-+	INIT_DELAYED_WORK(&lcu->ruac_data.dwork, lcu_update_work);
-+	spin_lock_init(&lcu->lock);
-+	return lcu;
-+
-+out_err4:
-+	kfree(lcu->rsu_cqr->cpaddr);
-+out_err3:
-+	kfree(lcu->rsu_cqr);
-+out_err2:
-+	kfree(lcu->uac);
-+out_err1:
-+	kfree(lcu);
-+	return ERR_PTR(-ENOMEM);
-+}
-+
-+static void _free_lcu(struct alias_lcu *lcu)
-+{
-+	kfree(lcu->rsu_cqr->data);
-+	kfree(lcu->rsu_cqr->cpaddr);
-+	kfree(lcu->rsu_cqr);
-+	kfree(lcu->uac);
-+	kfree(lcu);
++	return 0;
 +}
 +
-+/*
-+ * This is the function that will allocate all the server and lcu data,
-+ * so this function must be called first for a new device.
-+ * If the return value is 1, the lcu was already known before, if it
-+ * is 0, this is a new lcu.
-+ * Negative return code indicates that something went wrong (e.g. -ENOMEM)
-+ */
-+int dasd_alias_make_device_known_to_lcu(struct dasd_device *device)
++static void recovery_func(unsigned long data)
 +{
-+	struct dasd_eckd_private *private;
-+	unsigned long flags;
-+	struct alias_server *server, *newserver;
-+	struct alias_lcu *lcu, *newlcu;
-+	int is_lcu_known;
-+	struct dasd_uid *uid;
-+
-+	private = (struct dasd_eckd_private *) device->private;
-+	uid = &private->uid;
-+	spin_lock_irqsave(&aliastree.lock, flags);
-+	is_lcu_known = 1;
-+	server = _find_server(uid);
-+	if (!server) {
-+		spin_unlock_irqrestore(&aliastree.lock, flags);
-+		newserver = _allocate_server(uid);
-+		if (IS_ERR(newserver))
-+			return PTR_ERR(newserver);
-+		spin_lock_irqsave(&aliastree.lock, flags);
-+		server = _find_server(uid);
-+		if (!server) {
-+			list_add(&newserver->server, &aliastree.serverlist);
-+			server = newserver;
-+			is_lcu_known = 0;
-+		} else {
-+			/* someone was faster */
-+			_free_server(newserver);
-+		}
-+	}
++	int redo = 0;
 +
-+	lcu = _find_lcu(server, uid);
-+	if (!lcu) {
-+		spin_unlock_irqrestore(&aliastree.lock, flags);
-+		newlcu = _allocate_lcu(uid);
-+		if (IS_ERR(newlcu))
-+			return PTR_ERR(lcu);
-+		spin_lock_irqsave(&aliastree.lock, flags);
-+		lcu = _find_lcu(server, uid);
-+		if (!lcu) {
-+			list_add(&newlcu->lcu, &server->lculist);
-+			lcu = newlcu;
-+			is_lcu_known = 0;
-+		} else {
-+			/* someone was faster */
-+			_free_lcu(newlcu);
++	bus_for_each_dev(&ccw_bus_type, NULL, &redo, recovery_check);
++	if (redo) {
++		spin_lock_irq(&recovery_lock);
++		if (!timer_pending(&recovery_timer)) {
++			if (recovery_phase < ARRAY_SIZE(recovery_delay) - 1)
++				recovery_phase++;
++			mod_timer(&recovery_timer, jiffies +
++				  recovery_delay[recovery_phase] * HZ);
 +		}
-+		is_lcu_known = 0;
-+	}
-+	spin_lock(&lcu->lock);
-+	list_add(&device->alias_list, &lcu->inactive_devices);
-+	private->lcu = lcu;
-+	spin_unlock(&lcu->lock);
-+	spin_unlock_irqrestore(&aliastree.lock, flags);
-+
-+	return is_lcu_known;
-+}
-+
-+/*
-+ * This function removes a device from the scope of alias management.
-+ * The complicated part is to make sure that it is not in use by
-+ * any of the workers. If necessary cancel the work.
-+ */
-+void dasd_alias_disconnect_device_from_lcu(struct dasd_device *device)
-+{
-+	struct dasd_eckd_private *private;
-+	unsigned long flags;
-+	struct alias_lcu *lcu;
-+	struct alias_server *server;
-+	int was_pending;
-+
-+	private = (struct dasd_eckd_private *) device->private;
-+	lcu = private->lcu;
-+	spin_lock_irqsave(&lcu->lock, flags);
-+	list_del_init(&device->alias_list);
-+	/* make sure that the workers don't use this device */
-+	if (device == lcu->suc_data.device) {
-+		spin_unlock_irqrestore(&lcu->lock, flags);
-+		cancel_work_sync(&lcu->suc_data.worker);
-+		spin_lock_irqsave(&lcu->lock, flags);
-+		if (device == lcu->suc_data.device)
-+			lcu->suc_data.device = NULL;
-+	}
-+	was_pending = 0;
-+	if (device == lcu->ruac_data.device) {
-+		spin_unlock_irqrestore(&lcu->lock, flags);
-+		was_pending = 1;
-+		cancel_delayed_work_sync(&lcu->ruac_data.dwork);
-+		spin_lock_irqsave(&lcu->lock, flags);
-+		if (device == lcu->ruac_data.device)
-+			lcu->ruac_data.device = NULL;
-+	}
-+	private->lcu = NULL;
-+	spin_unlock_irqrestore(&lcu->lock, flags);
-+
-+	spin_lock_irqsave(&aliastree.lock, flags);
-+	spin_lock(&lcu->lock);
-+	if (list_empty(&lcu->grouplist) &&
-+	    list_empty(&lcu->active_devices) &&
-+	    list_empty(&lcu->inactive_devices)) {
-+		list_del(&lcu->lcu);
-+		spin_unlock(&lcu->lock);
-+		_free_lcu(lcu);
-+		lcu = NULL;
-+	} else {
-+		if (was_pending)
-+			_schedule_lcu_update(lcu, NULL);
-+		spin_unlock(&lcu->lock);
-+	}
-+	server = _find_server(&private->uid);
-+	if (server && list_empty(&server->lculist)) {
-+		list_del(&server->server);
-+		_free_server(server);
-+	}
-+	spin_unlock_irqrestore(&aliastree.lock, flags);
++		spin_unlock_irq(&recovery_lock);
++	} else
++		CIO_MSG_EVENT(2, "recovery: end\n");
 +}
 +
-+/*
-+ * This function assumes that the unit address configuration stored
-+ * in the lcu is up to date and will update the device uid before
-+ * adding it to a pav group.
-+ */
-+static int _add_device_to_lcu(struct alias_lcu *lcu,
-+			      struct dasd_device *device)
-+{
-+
-+	struct dasd_eckd_private *private;
-+	struct alias_pav_group *group;
-+	struct dasd_uid *uid;
-+
-+	private = (struct dasd_eckd_private *) device->private;
-+	uid = &private->uid;
-+	uid->type = lcu->uac->unit[uid->real_unit_addr].ua_type;
-+	uid->base_unit_addr = lcu->uac->unit[uid->real_unit_addr].base_ua;
-+	dasd_set_uid(device->cdev, &private->uid);
-+
-+	/* if we have no PAV anyway, we don't need to bother with PAV groups */
-+	if (lcu->pav == NO_PAV) {
-+		list_move(&device->alias_list, &lcu->active_devices);
-+		return 0;
-+	}
-+
-+	group = _find_group(lcu, uid);
-+	if (!group) {
-+		group = kzalloc(sizeof(*group), GFP_ATOMIC);
-+		if (!group)
-+			return -ENOMEM;
-+		memcpy(group->uid.vendor, uid->vendor, sizeof(uid->vendor));
-+		memcpy(group->uid.serial, uid->serial, sizeof(uid->serial));
-+		group->uid.ssid = uid->ssid;
-+		if (uid->type == UA_BASE_DEVICE)
-+			group->uid.base_unit_addr = uid->real_unit_addr;
-+		else
-+			group->uid.base_unit_addr = uid->base_unit_addr;
-+		INIT_LIST_HEAD(&group->group);
-+		INIT_LIST_HEAD(&group->baselist);
-+		INIT_LIST_HEAD(&group->aliaslist);
-+		list_add(&group->group, &lcu->grouplist);
-+	}
-+	if (uid->type == UA_BASE_DEVICE)
-+		list_move(&device->alias_list, &group->baselist);
-+	else
-+		list_move(&device->alias_list, &group->aliaslist);
-+	private->pavgroup = group;
-+	return 0;
-+};
-+
-+static void _remove_device_from_lcu(struct alias_lcu *lcu,
-+				    struct dasd_device *device)
-+{
-+	struct dasd_eckd_private *private;
-+	struct alias_pav_group *group;
-+
-+	private = (struct dasd_eckd_private *) device->private;
-+	list_move(&device->alias_list, &lcu->inactive_devices);
-+	group = private->pavgroup;
-+	if (!group)
-+		return;
-+	private->pavgroup = NULL;
-+	if (list_empty(&group->baselist) && list_empty(&group->aliaslist)) {
-+		list_del(&group->group);
-+		kfree(group);
-+		return;
-+	}
-+	if (group->next == device)
-+		group->next = NULL;
-+};
-+
-+static int read_unit_address_configuration(struct dasd_device *device,
-+					   struct alias_lcu *lcu)
++void ccw_device_schedule_recovery(void)
 +{
-+	struct dasd_psf_prssd_data *prssdp;
-+	struct dasd_ccw_req *cqr;
-+	struct ccw1 *ccw;
-+	int rc;
 +	unsigned long flags;
 +
-+	cqr = dasd_kmalloc_request("ECKD",
-+				   1 /* PSF */	+ 1 /* RSSD */ ,
-+				   (sizeof(struct dasd_psf_prssd_data)),
-+				   device);
-+	if (IS_ERR(cqr))
-+		return PTR_ERR(cqr);
-+	cqr->startdev = device;
-+	cqr->memdev = device;
-+	clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
-+	cqr->retries = 10;
-+	cqr->expires = 20 * HZ;
-+
-+	/* Prepare for Read Subsystem Data */
-+	prssdp = (struct dasd_psf_prssd_data *) cqr->data;
-+	memset(prssdp, 0, sizeof(struct dasd_psf_prssd_data));
-+	prssdp->order = PSF_ORDER_PRSSD;
-+	prssdp->suborder = 0x0e;	/* Read unit address configuration */
-+	/* all other bytes of prssdp must be zero */
-+
-+	ccw = cqr->cpaddr;
-+	ccw->cmd_code = DASD_ECKD_CCW_PSF;
-+	ccw->count = sizeof(struct dasd_psf_prssd_data);
-+	ccw->flags |= CCW_FLAG_CC;
-+	ccw->cda = (__u32)(addr_t) prssdp;
-+
-+	/* Read Subsystem Data - feature codes */
-+	memset(lcu->uac, 0, sizeof(*(lcu->uac)));
-+
-+	ccw++;
-+	ccw->cmd_code = DASD_ECKD_CCW_RSSD;
-+	ccw->count = sizeof(*(lcu->uac));
-+	ccw->cda = (__u32)(addr_t) lcu->uac;
-+
-+	cqr->buildclk = get_clock();
-+	cqr->status = DASD_CQR_FILLED;
-+
-+	/* need to unset flag here to detect race with summary unit check */
-+	spin_lock_irqsave(&lcu->lock, flags);
-+	lcu->flags &= ~NEED_UAC_UPDATE;
-+	spin_unlock_irqrestore(&lcu->lock, flags);
-+
-+	do {
-+		rc = dasd_sleep_on(cqr);
-+	} while (rc && (cqr->retries > 0));
-+	if (rc) {
-+		spin_lock_irqsave(&lcu->lock, flags);
-+		lcu->flags |= NEED_UAC_UPDATE;
-+		spin_unlock_irqrestore(&lcu->lock, flags);
++	CIO_MSG_EVENT(2, "recovery: schedule\n");
++	spin_lock_irqsave(&recovery_lock, flags);
++	if (!timer_pending(&recovery_timer) || (recovery_phase != 0)) {
++		recovery_phase = 0;
++		mod_timer(&recovery_timer, jiffies + recovery_delay[0] * HZ);
 +	}
-+	dasd_kfree_request(cqr, cqr->memdev);
-+	return rc;
++	spin_unlock_irqrestore(&recovery_lock, flags);
 +}
 +
-+static int _lcu_update(struct dasd_device *refdev, struct alias_lcu *lcu)
-+{
-+	unsigned long flags;
-+	struct alias_pav_group *pavgroup, *tempgroup;
-+	struct dasd_device *device, *tempdev;
-+	int i, rc;
-+	struct dasd_eckd_private *private;
-+
-+	spin_lock_irqsave(&lcu->lock, flags);
-+	list_for_each_entry_safe(pavgroup, tempgroup, &lcu->grouplist, group) {
-+		list_for_each_entry_safe(device, tempdev, &pavgroup->baselist,
-+					 alias_list) {
-+			list_move(&device->alias_list, &lcu->active_devices);
-+			private = (struct dasd_eckd_private *) device->private;
-+			private->pavgroup = NULL;
-+		}
-+		list_for_each_entry_safe(device, tempdev, &pavgroup->aliaslist,
-+					 alias_list) {
-+			list_move(&device->alias_list, &lcu->active_devices);
-+			private = (struct dasd_eckd_private *) device->private;
-+			private->pavgroup = NULL;
-+		}
-+		list_del(&pavgroup->group);
-+		kfree(pavgroup);
-+	}
-+	spin_unlock_irqrestore(&lcu->lock, flags);
+ MODULE_LICENSE("GPL");
+ EXPORT_SYMBOL(ccw_device_set_online);
+ EXPORT_SYMBOL(ccw_device_set_offline);
+diff --git a/drivers/s390/cio/device.h b/drivers/s390/cio/device.h
+index 0d40896..d40a2ff 100644
+--- a/drivers/s390/cio/device.h
++++ b/drivers/s390/cio/device.h
+@@ -5,6 +5,8 @@
+ #include <asm/atomic.h>
+ #include <linux/wait.h>
+ 
++#include "io_sch.h"
 +
-+	rc = read_unit_address_configuration(refdev, lcu);
-+	if (rc)
-+		return rc;
+ /*
+  * states of the device statemachine
+  */
+@@ -74,7 +76,6 @@ extern struct workqueue_struct *ccw_device_notify_work;
+ extern wait_queue_head_t ccw_device_init_wq;
+ extern atomic_t ccw_device_init_count;
+ 
+-void io_subchannel_irq (struct device *pdev);
+ void io_subchannel_recog_done(struct ccw_device *cdev);
+ 
+ int ccw_device_cancel_halt_clear(struct ccw_device *);
+@@ -87,6 +88,8 @@ int ccw_device_recognition(struct ccw_device *);
+ int ccw_device_online(struct ccw_device *);
+ int ccw_device_offline(struct ccw_device *);
+ 
++void ccw_device_schedule_recovery(void);
 +
-+	spin_lock_irqsave(&lcu->lock, flags);
-+	lcu->pav = NO_PAV;
-+	for (i = 0; i < MAX_DEVICES_PER_LCU; ++i) {
-+		switch (lcu->uac->unit[i].ua_type) {
-+		case UA_BASE_PAV_ALIAS:
-+			lcu->pav = BASE_PAV;
-+			break;
-+		case UA_HYPER_PAV_ALIAS:
-+			lcu->pav = HYPER_PAV;
-+			break;
-+		}
-+		if (lcu->pav != NO_PAV)
-+			break;
-+	}
+ /* Function prototypes for device status and basic sense stuff. */
+ void ccw_device_accumulate_irb(struct ccw_device *, struct irb *);
+ void ccw_device_accumulate_basic_sense(struct ccw_device *, struct irb *);
+diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c
+index bfad421..4b92c84 100644
+--- a/drivers/s390/cio/device_fsm.c
++++ b/drivers/s390/cio/device_fsm.c
+@@ -25,14 +25,16 @@
+ #include "ioasm.h"
+ #include "chp.h"
+ 
++static int timeout_log_enabled;
 +
-+	list_for_each_entry_safe(device, tempdev, &lcu->active_devices,
-+				 alias_list) {
-+		_add_device_to_lcu(lcu, device);
-+	}
-+	spin_unlock_irqrestore(&lcu->lock, flags);
-+	return 0;
+ int
+ device_is_online(struct subchannel *sch)
+ {
+ 	struct ccw_device *cdev;
+ 
+-	if (!sch->dev.driver_data)
++	cdev = sch_get_cdev(sch);
++	if (!cdev)
+ 		return 0;
+-	cdev = sch->dev.driver_data;
+ 	return (cdev->private->state == DEV_STATE_ONLINE);
+ }
+ 
+@@ -41,9 +43,9 @@ device_is_disconnected(struct subchannel *sch)
+ {
+ 	struct ccw_device *cdev;
+ 
+-	if (!sch->dev.driver_data)
++	cdev = sch_get_cdev(sch);
++	if (!cdev)
+ 		return 0;
+-	cdev = sch->dev.driver_data;
+ 	return (cdev->private->state == DEV_STATE_DISCONNECTED ||
+ 		cdev->private->state == DEV_STATE_DISCONNECTED_SENSE_ID);
+ }
+@@ -53,19 +55,21 @@ device_set_disconnected(struct subchannel *sch)
+ {
+ 	struct ccw_device *cdev;
+ 
+-	if (!sch->dev.driver_data)
++	cdev = sch_get_cdev(sch);
++	if (!cdev)
+ 		return;
+-	cdev = sch->dev.driver_data;
+ 	ccw_device_set_timeout(cdev, 0);
+ 	cdev->private->flags.fake_irb = 0;
+ 	cdev->private->state = DEV_STATE_DISCONNECTED;
++	if (cdev->online)
++		ccw_device_schedule_recovery();
+ }
+ 
+ void device_set_intretry(struct subchannel *sch)
+ {
+ 	struct ccw_device *cdev;
+ 
+-	cdev = sch->dev.driver_data;
++	cdev = sch_get_cdev(sch);
+ 	if (!cdev)
+ 		return;
+ 	cdev->private->flags.intretry = 1;
+@@ -75,13 +79,62 @@ int device_trigger_verify(struct subchannel *sch)
+ {
+ 	struct ccw_device *cdev;
+ 
+-	cdev = sch->dev.driver_data;
++	cdev = sch_get_cdev(sch);
+ 	if (!cdev || !cdev->online)
+ 		return -EINVAL;
+ 	dev_fsm_event(cdev, DEV_EVENT_VERIFY);
+ 	return 0;
+ }
+ 
++static int __init ccw_timeout_log_setup(char *unused)
++{
++	timeout_log_enabled = 1;
++	return 1;
 +}
 +
-+static void lcu_update_work(struct work_struct *work)
++__setup("ccw_timeout_log", ccw_timeout_log_setup);
++
++static void ccw_timeout_log(struct ccw_device *cdev)
 +{
-+	struct alias_lcu *lcu;
-+	struct read_uac_work_data *ruac_data;
-+	struct dasd_device *device;
-+	unsigned long flags;
-+	int rc;
++	struct schib schib;
++	struct subchannel *sch;
++	struct io_subchannel_private *private;
++	int cc;
 +
-+	ruac_data = container_of(work, struct read_uac_work_data, dwork.work);
-+	lcu = container_of(ruac_data, struct alias_lcu, ruac_data);
-+	device = ruac_data->device;
-+	rc = _lcu_update(device, lcu);
-+	/*
-+	 * Need to check flags again, as there could have been another
-+	 * prepare_update or a new device a new device while we were still
-+	 * processing the data
-+	 */
-+	spin_lock_irqsave(&lcu->lock, flags);
-+	if (rc || (lcu->flags & NEED_UAC_UPDATE)) {
-+		DEV_MESSAGE(KERN_WARNING, device, "could not update"
-+			    " alias data in lcu (rc = %d), retry later", rc);
-+		schedule_delayed_work(&lcu->ruac_data.dwork, 30*HZ);
-+	} else {
-+		lcu->ruac_data.device = NULL;
-+		lcu->flags &= ~UPDATE_PENDING;
-+	}
-+	spin_unlock_irqrestore(&lcu->lock, flags);
-+}
++	sch = to_subchannel(cdev->dev.parent);
++	private = to_io_private(sch);
++	cc = stsch(sch->schid, &schib);
 +
-+static int _schedule_lcu_update(struct alias_lcu *lcu,
-+				struct dasd_device *device)
-+{
-+	struct dasd_device *usedev = NULL;
-+	struct alias_pav_group *group;
++	printk(KERN_WARNING "cio: ccw device timeout occurred at %llx, "
++	       "device information:\n", get_clock());
++	printk(KERN_WARNING "cio: orb:\n");
++	print_hex_dump(KERN_WARNING, "cio:  ", DUMP_PREFIX_NONE, 16, 1,
++		       &private->orb, sizeof(private->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: subchannel lpm: %02x, opm: %02x, "
++	       "vpm: %02x\n", sch->lpm, sch->opm, sch->vpm);
 +
-+	lcu->flags |= NEED_UAC_UPDATE;
-+	if (lcu->ruac_data.device) {
-+		/* already scheduled or running */
-+		return 0;
-+	}
-+	if (device && !list_empty(&device->alias_list))
-+		usedev = device;
++	if ((void *)(addr_t)private->orb.cpa == &private->sense_ccw ||
++	    (void *)(addr_t)private->orb.cpa == cdev->private->iccws)
++		printk(KERN_WARNING "cio: last channel program (intern):\n");
++	else
++		printk(KERN_WARNING "cio: last channel program:\n");
 +
-+	if (!usedev && !list_empty(&lcu->grouplist)) {
-+		group = list_first_entry(&lcu->grouplist,
-+					 struct alias_pav_group, group);
-+		if (!list_empty(&group->baselist))
-+			usedev = list_first_entry(&group->baselist,
-+						  struct dasd_device,
-+						  alias_list);
-+		else if (!list_empty(&group->aliaslist))
-+			usedev = list_first_entry(&group->aliaslist,
-+						  struct dasd_device,
-+						  alias_list);
-+	}
-+	if (!usedev && !list_empty(&lcu->active_devices)) {
-+		usedev = list_first_entry(&lcu->active_devices,
-+					  struct dasd_device, alias_list);
-+	}
-+	/*
-+	 * if we haven't found a proper device yet, give up for now, the next
-+	 * device that will be set active will trigger an lcu update
-+	 */
-+	if (!usedev)
-+		return -EINVAL;
-+	lcu->ruac_data.device = usedev;
-+	schedule_delayed_work(&lcu->ruac_data.dwork, 0);
-+	return 0;
++	print_hex_dump(KERN_WARNING, "cio:  ", DUMP_PREFIX_NONE, 16, 1,
++		       (void *)(addr_t)private->orb.cpa,
++		       sizeof(struct ccw1), 0);
++	printk(KERN_WARNING "cio: ccw device state: %d\n",
++	       cdev->private->state);
++	printk(KERN_WARNING "cio: store subchannel returned: cc=%d\n", cc);
++	printk(KERN_WARNING "cio: schib:\n");
++	print_hex_dump(KERN_WARNING, "cio:  ", DUMP_PREFIX_NONE, 16, 1,
++		       &schib, sizeof(schib), 0);
++	printk(KERN_WARNING "cio: ccw device flags:\n");
++	print_hex_dump(KERN_WARNING, "cio:  ", DUMP_PREFIX_NONE, 16, 1,
++		       &cdev->private->flags, sizeof(cdev->private->flags), 0);
 +}
 +
-+int dasd_alias_add_device(struct dasd_device *device)
-+{
-+	struct dasd_eckd_private *private;
-+	struct alias_lcu *lcu;
-+	unsigned long flags;
-+	int rc;
+ /*
+  * Timeout function. It just triggers a DEV_EVENT_TIMEOUT.
+  */
+@@ -92,6 +145,8 @@ ccw_device_timeout(unsigned long data)
+ 
+ 	cdev = (struct ccw_device *) data;
+ 	spin_lock_irq(cdev->ccwlock);
++	if (timeout_log_enabled)
++		ccw_timeout_log(cdev);
+ 	dev_fsm_event(cdev, DEV_EVENT_TIMEOUT);
+ 	spin_unlock_irq(cdev->ccwlock);
+ }
+@@ -122,9 +177,9 @@ device_kill_pending_timer(struct subchannel *sch)
+ {
+ 	struct ccw_device *cdev;
+ 
+-	if (!sch->dev.driver_data)
++	cdev = sch_get_cdev(sch);
++	if (!cdev)
+ 		return;
+-	cdev = sch->dev.driver_data;
+ 	ccw_device_set_timeout(cdev, 0);
+ }
+ 
+@@ -268,7 +323,7 @@ ccw_device_recog_done(struct ccw_device *cdev, int state)
+ 	switch (state) {
+ 	case DEV_STATE_NOT_OPER:
+ 		CIO_DEBUG(KERN_WARNING, 2,
+-			  "cio: SenseID : unknown device %04x on subchannel "
++			  "SenseID : unknown device %04x on subchannel "
+ 			  "0.%x.%04x\n", cdev->private->dev_id.devno,
+ 			  sch->schid.ssid, sch->schid.sch_no);
+ 		break;
+@@ -294,7 +349,7 @@ ccw_device_recog_done(struct ccw_device *cdev, int state)
+ 		}
+ 		/* Issue device info message. */
+ 		CIO_DEBUG(KERN_INFO, 2,
+-			  "cio: SenseID : device 0.%x.%04x reports: "
++			  "SenseID : device 0.%x.%04x reports: "
+ 			  "CU  Type/Mod = %04X/%02X, Dev Type/Mod = "
+ 			  "%04X/%02X\n",
+ 			  cdev->private->dev_id.ssid,
+@@ -304,7 +359,7 @@ ccw_device_recog_done(struct ccw_device *cdev, int state)
+ 		break;
+ 	case DEV_STATE_BOXED:
+ 		CIO_DEBUG(KERN_WARNING, 2,
+-			  "cio: SenseID : boxed device %04x on subchannel "
++			  "SenseID : boxed device %04x on subchannel "
+ 			  "0.%x.%04x\n", cdev->private->dev_id.devno,
+ 			  sch->schid.ssid, sch->schid.sch_no);
+ 		break;
+@@ -349,7 +404,7 @@ ccw_device_oper_notify(struct work_struct *work)
+ 	sch = to_subchannel(cdev->dev.parent);
+ 	if (sch->driver && sch->driver->notify) {
+ 		spin_unlock_irqrestore(cdev->ccwlock, flags);
+-		ret = sch->driver->notify(&sch->dev, CIO_OPER);
++		ret = sch->driver->notify(sch, CIO_OPER);
+ 		spin_lock_irqsave(cdev->ccwlock, flags);
+ 	} else
+ 		ret = 0;
+@@ -389,7 +444,7 @@ ccw_device_done(struct ccw_device *cdev, int state)
+ 
+ 	if (state == DEV_STATE_BOXED)
+ 		CIO_DEBUG(KERN_WARNING, 2,
+-			  "cio: Boxed device %04x on subchannel %04x\n",
++			  "Boxed device %04x on subchannel %04x\n",
+ 			  cdev->private->dev_id.devno, sch->schid.sch_no);
+ 
+ 	if (cdev->private->flags.donotify) {
+@@ -500,7 +555,8 @@ ccw_device_recognition(struct ccw_device *cdev)
+ 	    (cdev->private->state != DEV_STATE_BOXED))
+ 		return -EINVAL;
+ 	sch = to_subchannel(cdev->dev.parent);
+-	ret = cio_enable_subchannel(sch, sch->schib.pmcw.isc);
++	ret = cio_enable_subchannel(sch, sch->schib.pmcw.isc,
++				    (u32)(addr_t)sch);
+ 	if (ret != 0)
+ 		/* Couldn't enable the subchannel for i/o. Sick device. */
+ 		return ret;
+@@ -587,9 +643,10 @@ ccw_device_verify_done(struct ccw_device *cdev, int err)
+ 	default:
+ 		/* Reset oper notify indication after verify error. */
+ 		cdev->private->flags.donotify = 0;
+-		if (cdev->online)
++		if (cdev->online) {
++			ccw_device_set_timeout(cdev, 0);
+ 			dev_fsm_event(cdev, DEV_EVENT_NOTOPER);
+-		else
++		} else
+ 			ccw_device_done(cdev, DEV_STATE_NOT_OPER);
+ 		break;
+ 	}
+@@ -610,7 +667,8 @@ ccw_device_online(struct ccw_device *cdev)
+ 	sch = to_subchannel(cdev->dev.parent);
+ 	if (css_init_done && !get_device(&cdev->dev))
+ 		return -ENODEV;
+-	ret = cio_enable_subchannel(sch, sch->schib.pmcw.isc);
++	ret = cio_enable_subchannel(sch, sch->schib.pmcw.isc,
++				    (u32)(addr_t)sch);
+ 	if (ret != 0) {
+ 		/* Couldn't enable the subchannel for i/o. Sick device. */
+ 		if (ret == -ENODEV)
+@@ -937,7 +995,7 @@ void device_kill_io(struct subchannel *sch)
+ 	int ret;
+ 	struct ccw_device *cdev;
+ 
+-	cdev = sch->dev.driver_data;
++	cdev = sch_get_cdev(sch);
+ 	ret = ccw_device_cancel_halt_clear(cdev);
+ 	if (ret == -EBUSY) {
+ 		ccw_device_set_timeout(cdev, 3*HZ);
+@@ -990,7 +1048,8 @@ ccw_device_start_id(struct ccw_device *cdev, enum dev_event dev_event)
+ 	struct subchannel *sch;
+ 
+ 	sch = to_subchannel(cdev->dev.parent);
+-	if (cio_enable_subchannel(sch, sch->schib.pmcw.isc) != 0)
++	if (cio_enable_subchannel(sch, sch->schib.pmcw.isc,
++				  (u32)(addr_t)sch) != 0)
+ 		/* Couldn't enable the subchannel for i/o. Sick device. */
+ 		return;
+ 
+@@ -1006,9 +1065,9 @@ device_trigger_reprobe(struct subchannel *sch)
+ {
+ 	struct ccw_device *cdev;
+ 
+-	if (!sch->dev.driver_data)
++	cdev = sch_get_cdev(sch);
++	if (!cdev)
+ 		return;
+-	cdev = sch->dev.driver_data;
+ 	if (cdev->private->state != DEV_STATE_DISCONNECTED)
+ 		return;
+ 
+@@ -1028,7 +1087,7 @@ device_trigger_reprobe(struct subchannel *sch)
+ 	sch->schib.pmcw.ena = 0;
+ 	if ((sch->lpm & (sch->lpm - 1)) != 0)
+ 		sch->schib.pmcw.mp = 1;
+-	sch->schib.pmcw.intparm = (__u32)(unsigned long)sch;
++	sch->schib.pmcw.intparm = (u32)(addr_t)sch;
+ 	/* We should also udate ssd info, but this has to wait. */
+ 	/* Check if this is another device which appeared on the same sch. */
+ 	if (sch->schib.pmcw.dev != cdev->private->dev_id.devno) {
+@@ -1223,21 +1282,4 @@ fsm_func_t *dev_jumptable[NR_DEV_STATES][NR_DEV_EVENTS] = {
+ 	},
+ };
+ 
+-/*
+- * io_subchannel_irq is called for "real" interrupts or for status
+- * pending conditions on msch.
+- */
+-void
+-io_subchannel_irq (struct device *pdev)
+-{
+-	struct ccw_device *cdev;
+-
+-	cdev = to_subchannel(pdev)->dev.driver_data;
+-
+-	CIO_TRACE_EVENT (3, "IRQ");
+-	CIO_TRACE_EVENT (3, pdev->bus_id);
+-	if (cdev)
+-		dev_fsm_event(cdev, DEV_EVENT_INTERRUPT);
+-}
+-
+ EXPORT_SYMBOL_GPL(ccw_device_set_timeout);
+diff --git a/drivers/s390/cio/device_id.c b/drivers/s390/cio/device_id.c
+index 156f3f9..918b8b8 100644
+--- a/drivers/s390/cio/device_id.c
++++ b/drivers/s390/cio/device_id.c
+@@ -24,6 +24,7 @@
+ #include "css.h"
+ #include "device.h"
+ #include "ioasm.h"
++#include "io_sch.h"
+ 
+ /*
+  * Input :
+@@ -219,11 +220,13 @@ ccw_device_check_sense_id(struct ccw_device *cdev)
+ 		return -EAGAIN;
+ 	}
+ 	if (irb->scsw.cc == 3) {
+-		if ((sch->orb.lpm &
+-		     sch->schib.pmcw.pim & sch->schib.pmcw.pam) != 0)
++		u8 lpm;
 +
-+	private = (struct dasd_eckd_private *) device->private;
-+	lcu = private->lcu;
-+	rc = 0;
-+	spin_lock_irqsave(&lcu->lock, flags);
-+	if (!(lcu->flags & UPDATE_PENDING)) {
-+		rc = _add_device_to_lcu(lcu, device);
-+		if (rc)
-+			lcu->flags |= UPDATE_PENDING;
-+	}
-+	if (lcu->flags & UPDATE_PENDING) {
-+		list_move(&device->alias_list, &lcu->active_devices);
-+		_schedule_lcu_update(lcu, device);
-+	}
-+	spin_unlock_irqrestore(&lcu->lock, flags);
-+	return rc;
-+}
++		lpm = to_io_private(sch)->orb.lpm;
++		if ((lpm & sch->schib.pmcw.pim & sch->schib.pmcw.pam) != 0)
+ 			CIO_MSG_EVENT(2, "SenseID : path %02X for device %04x "
+ 				      "on subchannel 0.%x.%04x is "
+-				      "'not operational'\n", sch->orb.lpm,
++				      "'not operational'\n", lpm,
+ 				      cdev->private->dev_id.devno,
+ 				      sch->schid.ssid, sch->schid.sch_no);
+ 		return -EACCES;
+diff --git a/drivers/s390/cio/device_ops.c b/drivers/s390/cio/device_ops.c
+index 7fd2dad..49b58eb 100644
+--- a/drivers/s390/cio/device_ops.c
++++ b/drivers/s390/cio/device_ops.c
+@@ -501,7 +501,7 @@ ccw_device_stlck(struct ccw_device *cdev)
+ 		return -ENOMEM;
+ 	}
+ 	spin_lock_irqsave(sch->lock, flags);
+-	ret = cio_enable_subchannel(sch, 3);
++	ret = cio_enable_subchannel(sch, 3, (u32)(addr_t)sch);
+ 	if (ret)
+ 		goto out_unlock;
+ 	/*
+diff --git a/drivers/s390/cio/device_pgid.c b/drivers/s390/cio/device_pgid.c
+index cb1879a..c52449a 100644
+--- a/drivers/s390/cio/device_pgid.c
++++ b/drivers/s390/cio/device_pgid.c
+@@ -22,6 +22,7 @@
+ #include "css.h"
+ #include "device.h"
+ #include "ioasm.h"
++#include "io_sch.h"
+ 
+ /*
+  * Helper function called from interrupt context to decide whether an
+@@ -155,10 +156,13 @@ __ccw_device_check_sense_pgid(struct ccw_device *cdev)
+ 		return -EAGAIN;
+ 	}
+ 	if (irb->scsw.cc == 3) {
++		u8 lpm;
 +
-+int dasd_alias_remove_device(struct dasd_device *device)
-+{
-+	struct dasd_eckd_private *private;
-+	struct alias_lcu *lcu;
-+	unsigned long flags;
++		lpm = to_io_private(sch)->orb.lpm;
+ 		CIO_MSG_EVENT(2, "SNID - Device %04x on Subchannel 0.%x.%04x,"
+ 			      " lpm %02X, became 'not operational'\n",
+ 			      cdev->private->dev_id.devno, sch->schid.ssid,
+-			      sch->schid.sch_no, sch->orb.lpm);
++			      sch->schid.sch_no, lpm);
+ 		return -EACCES;
+ 	}
+ 	i = 8 - ffs(cdev->private->imask);
+diff --git a/drivers/s390/cio/device_status.c b/drivers/s390/cio/device_status.c
+index aa96e67..ebe0848 100644
+--- a/drivers/s390/cio/device_status.c
++++ b/drivers/s390/cio/device_status.c
+@@ -20,6 +20,7 @@
+ #include "css.h"
+ #include "device.h"
+ #include "ioasm.h"
++#include "io_sch.h"
+ 
+ /*
+  * Check for any kind of channel or interface control check but don't
+@@ -310,6 +311,7 @@ int
+ ccw_device_do_sense(struct ccw_device *cdev, struct irb *irb)
+ {
+ 	struct subchannel *sch;
++	struct ccw1 *sense_ccw;
+ 
+ 	sch = to_subchannel(cdev->dev.parent);
+ 
+@@ -326,15 +328,16 @@ ccw_device_do_sense(struct ccw_device *cdev, struct irb *irb)
+ 	/*
+ 	 * We have ending status but no sense information. Do a basic sense.
+ 	 */
+-	sch->sense_ccw.cmd_code = CCW_CMD_BASIC_SENSE;
+-	sch->sense_ccw.cda = (__u32) __pa(cdev->private->irb.ecw);
+-	sch->sense_ccw.count = SENSE_MAX_COUNT;
+-	sch->sense_ccw.flags = CCW_FLAG_SLI;
++	sense_ccw = &to_io_private(sch)->sense_ccw;
++	sense_ccw->cmd_code = CCW_CMD_BASIC_SENSE;
++	sense_ccw->cda = (__u32) __pa(cdev->private->irb.ecw);
++	sense_ccw->count = SENSE_MAX_COUNT;
++	sense_ccw->flags = CCW_FLAG_SLI;
+ 
+ 	/* Reset internal retry indication. */
+ 	cdev->private->flags.intretry = 0;
+ 
+-	return cio_start (sch, &sch->sense_ccw, 0xff);
++	return cio_start(sch, sense_ccw, 0xff);
+ }
+ 
+ /*
+diff --git a/drivers/s390/cio/io_sch.h b/drivers/s390/cio/io_sch.h
+new file mode 100644
+index 0000000..8c61316
+--- /dev/null
++++ b/drivers/s390/cio/io_sch.h
+@@ -0,0 +1,163 @@
++#ifndef S390_IO_SCH_H
++#define S390_IO_SCH_H
 +
-+	private = (struct dasd_eckd_private *) device->private;
-+	lcu = private->lcu;
-+	spin_lock_irqsave(&lcu->lock, flags);
-+	_remove_device_from_lcu(lcu, device);
-+	spin_unlock_irqrestore(&lcu->lock, flags);
-+	return 0;
-+}
++#include "schid.h"
 +
-+struct dasd_device *dasd_alias_get_start_dev(struct dasd_device *base_device)
-+{
++/*
++ * operation request block
++ */
++struct orb {
++	u32 intparm;	/* interruption parameter */
++	u32 key  : 4;	/* flags, like key, suspend control, etc. */
++	u32 spnd : 1;	/* suspend control */
++	u32 res1 : 1;	/* reserved */
++	u32 mod  : 1;	/* modification control */
++	u32 sync : 1;	/* synchronize control */
++	u32 fmt  : 1;	/* format control */
++	u32 pfch : 1;	/* prefetch control */
++	u32 isic : 1;	/* initial-status-interruption control */
++	u32 alcc : 1;	/* address-limit-checking control */
++	u32 ssic : 1;	/* suppress-suspended-interr. control */
++	u32 res2 : 1;	/* reserved */
++	u32 c64  : 1;	/* IDAW/QDIO 64 bit control  */
++	u32 i2k  : 1;	/* IDAW 2/4kB block size control */
++	u32 lpm  : 8;	/* logical path mask */
++	u32 ils  : 1;	/* incorrect length */
++	u32 zero : 6;	/* reserved zeros */
++	u32 orbx : 1;	/* ORB extension control */
++	u32 cpa;	/* channel program address */
++}  __attribute__ ((packed, aligned(4)));
 +
-+	struct dasd_device *alias_device;
-+	struct alias_pav_group *group;
-+	struct alias_lcu *lcu;
-+	struct dasd_eckd_private *private, *alias_priv;
-+	unsigned long flags;
++struct io_subchannel_private {
++	struct orb orb;		/* operation request block */
++	struct ccw1 sense_ccw;	/* static ccw for sense command */
++} __attribute__ ((aligned(8)));
 +
-+	private = (struct dasd_eckd_private *) base_device->private;
-+	group = private->pavgroup;
-+	lcu = private->lcu;
-+	if (!group || !lcu)
-+		return NULL;
-+	if (lcu->pav == NO_PAV ||
-+	    lcu->flags & (NEED_UAC_UPDATE | UPDATE_PENDING))
-+		return NULL;
++#define to_io_private(n) ((struct io_subchannel_private *)n->private)
++#define sch_get_cdev(n) (dev_get_drvdata(&n->dev))
++#define sch_set_cdev(n, c) (dev_set_drvdata(&n->dev, c))
 +
-+	spin_lock_irqsave(&lcu->lock, flags);
-+	alias_device = group->next;
-+	if (!alias_device) {
-+		if (list_empty(&group->aliaslist)) {
-+			spin_unlock_irqrestore(&lcu->lock, flags);
-+			return NULL;
-+		} else {
-+			alias_device = list_first_entry(&group->aliaslist,
-+							struct dasd_device,
-+							alias_list);
-+		}
-+	}
-+	if (list_is_last(&alias_device->alias_list, &group->aliaslist))
-+		group->next = list_first_entry(&group->aliaslist,
-+					       struct dasd_device, alias_list);
-+	else
-+		group->next = list_first_entry(&alias_device->alias_list,
-+					       struct dasd_device, alias_list);
-+	spin_unlock_irqrestore(&lcu->lock, flags);
-+	alias_priv = (struct dasd_eckd_private *) alias_device->private;
-+	if ((alias_priv->count < private->count) && !alias_device->stopped)
-+		return alias_device;
-+	else
-+		return NULL;
-+}
++#define MAX_CIWS 8
 +
 +/*
-+ * Summary unit check handling depends on the way alias devices
-+ * are handled so it is done here rather then in dasd_eckd.c
++ * sense-id response buffer layout
 + */
-+static int reset_summary_unit_check(struct alias_lcu *lcu,
-+				    struct dasd_device *device,
-+				    char reason)
++struct senseid {
++	/* common part */
++	u8  reserved;	/* always 0x'FF' */
++	u16 cu_type;	/* control unit type */
++	u8  cu_model;	/* control unit model */
++	u16 dev_type;	/* device type */
++	u8  dev_model;	/* device model */
++	u8  unused;	/* padding byte */
++	/* extended part */
++	struct ciw ciw[MAX_CIWS];	/* variable # of CIWs */
++}  __attribute__ ((packed, aligned(4)));
++
++struct ccw_device_private {
++	struct ccw_device *cdev;
++	struct subchannel *sch;
++	int state;		/* device state */
++	atomic_t onoff;
++	unsigned long registered;
++	struct ccw_dev_id dev_id;	/* device id */
++	struct subchannel_id schid;	/* subchannel number */
++	u8 imask;		/* lpm mask for SNID/SID/SPGID */
++	int iretry;		/* retry counter SNID/SID/SPGID */
++	struct {
++		unsigned int fast:1;	/* post with "channel end" */
++		unsigned int repall:1;	/* report every interrupt status */
++		unsigned int pgroup:1;	/* do path grouping */
++		unsigned int force:1;	/* allow forced online */
++	} __attribute__ ((packed)) options;
++	struct {
++		unsigned int pgid_single:1; /* use single path for Set PGID */
++		unsigned int esid:1;	    /* Ext. SenseID supported by HW */
++		unsigned int dosense:1;	    /* delayed SENSE required */
++		unsigned int doverify:1;    /* delayed path verification */
++		unsigned int donotify:1;    /* call notify function */
++		unsigned int recog_done:1;  /* dev. recog. complete */
++		unsigned int fake_irb:1;    /* deliver faked irb */
++		unsigned int intretry:1;    /* retry internal operation */
++	} __attribute__((packed)) flags;
++	unsigned long intparm;	/* user interruption parameter */
++	struct qdio_irq *qdio_data;
++	struct irb irb;		/* device status */
++	struct senseid senseid;	/* SenseID info */
++	struct pgid pgid[8];	/* path group IDs per chpid*/
++	struct ccw1 iccws[2];	/* ccws for SNID/SID/SPGID commands */
++	struct work_struct kick_work;
++	wait_queue_head_t wait_q;
++	struct timer_list timer;
++	void *cmb;			/* measurement information */
++	struct list_head cmb_list;	/* list of measured devices */
++	u64 cmb_start_time;		/* clock value of cmb reset */
++	void *cmb_wait;			/* deferred cmb enable/disable */
++};
++
++static inline int ssch(struct subchannel_id schid, volatile struct orb *addr)
 +{
-+	struct dasd_ccw_req *cqr;
-+	int rc = 0;
++	register struct subchannel_id reg1 asm("1") = schid;
++	int ccode;
 +
-+	cqr = lcu->rsu_cqr;
-+	strncpy((char *) &cqr->magic, "ECKD", 4);
-+	ASCEBC((char *) &cqr->magic, 4);
-+	cqr->cpaddr->cmd_code = DASD_ECKD_CCW_RSCK;
-+	cqr->cpaddr->flags = 0 ;
-+	cqr->cpaddr->count = 16;
-+	cqr->cpaddr->cda = (__u32)(addr_t) cqr->data;
-+	((char *)cqr->data)[0] = reason;
++	asm volatile(
++		"	ssch	0(%2)\n"
++		"	ipm	%0\n"
++		"	srl	%0,28"
++		: "=d" (ccode) : "d" (reg1), "a" (addr), "m" (*addr) : "cc");
++	return ccode;
++}
 +
-+	clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
-+	cqr->retries = 255;	/* set retry counter to enable basic ERP */
-+	cqr->startdev = device;
-+	cqr->memdev = device;
-+	cqr->block = NULL;
-+	cqr->expires = 5 * HZ;
-+	cqr->buildclk = get_clock();
-+	cqr->status = DASD_CQR_FILLED;
++static inline int rsch(struct subchannel_id schid)
++{
++	register struct subchannel_id reg1 asm("1") = schid;
++	int ccode;
 +
-+	rc = dasd_sleep_on_immediatly(cqr);
-+	return rc;
++	asm volatile(
++		"	rsch\n"
++		"	ipm	%0\n"
++		"	srl	%0,28"
++		: "=d" (ccode) : "d" (reg1) : "cc");
++	return ccode;
 +}
 +
-+static void _restart_all_base_devices_on_lcu(struct alias_lcu *lcu)
++static inline int csch(struct subchannel_id schid)
 +{
-+	struct alias_pav_group *pavgroup;
-+	struct dasd_device *device;
-+	struct dasd_eckd_private *private;
++	register struct subchannel_id reg1 asm("1") = schid;
++	int ccode;
 +
-+	/* active and inactive list can contain alias as well as base devices */
-+	list_for_each_entry(device, &lcu->active_devices, alias_list) {
-+		private = (struct dasd_eckd_private *) device->private;
-+		if (private->uid.type != UA_BASE_DEVICE)
-+			continue;
-+		dasd_schedule_block_bh(device->block);
-+		dasd_schedule_device_bh(device);
-+	}
-+	list_for_each_entry(device, &lcu->inactive_devices, alias_list) {
-+		private = (struct dasd_eckd_private *) device->private;
-+		if (private->uid.type != UA_BASE_DEVICE)
-+			continue;
-+		dasd_schedule_block_bh(device->block);
-+		dasd_schedule_device_bh(device);
-+	}
-+	list_for_each_entry(pavgroup, &lcu->grouplist, group) {
-+		list_for_each_entry(device, &pavgroup->baselist, alias_list) {
-+			dasd_schedule_block_bh(device->block);
-+			dasd_schedule_device_bh(device);
-+		}
-+	}
++	asm volatile(
++		"	csch\n"
++		"	ipm	%0\n"
++		"	srl	%0,28"
++		: "=d" (ccode) : "d" (reg1) : "cc");
++	return ccode;
 +}
 +
-+static void flush_all_alias_devices_on_lcu(struct alias_lcu *lcu)
++static inline int hsch(struct subchannel_id schid)
 +{
-+	struct alias_pav_group *pavgroup;
-+	struct dasd_device *device, *temp;
-+	struct dasd_eckd_private *private;
-+	int rc;
-+	unsigned long flags;
-+	LIST_HEAD(active);
++	register struct subchannel_id reg1 asm("1") = schid;
++	int ccode;
 +
-+	/*
-+	 * Problem here ist that dasd_flush_device_queue may wait
-+	 * for termination of a request to complete. We can't keep
-+	 * the lcu lock during that time, so we must assume that
-+	 * the lists may have changed.
-+	 * Idea: first gather all active alias devices in a separate list,
-+	 * then flush the first element of this list unlocked, and afterwards
-+	 * check if it is still on the list before moving it to the
-+	 * active_devices list.
-+	 */
++	asm volatile(
++		"	hsch\n"
++		"	ipm	%0\n"
++		"	srl	%0,28"
++		: "=d" (ccode) : "d" (reg1) : "cc");
++	return ccode;
++}
 +
-+	spin_lock_irqsave(&lcu->lock, flags);
-+	list_for_each_entry_safe(device, temp, &lcu->active_devices,
-+				 alias_list) {
-+		private = (struct dasd_eckd_private *) device->private;
-+		if (private->uid.type == UA_BASE_DEVICE)
-+			continue;
-+		list_move(&device->alias_list, &active);
-+	}
++static inline int xsch(struct subchannel_id schid)
++{
++	register struct subchannel_id reg1 asm("1") = schid;
++	int ccode;
 +
-+	list_for_each_entry(pavgroup, &lcu->grouplist, group) {
-+		list_splice_init(&pavgroup->aliaslist, &active);
-+	}
-+	while (!list_empty(&active)) {
-+		device = list_first_entry(&active, struct dasd_device,
-+					  alias_list);
-+		spin_unlock_irqrestore(&lcu->lock, flags);
-+		rc = dasd_flush_device_queue(device);
-+		spin_lock_irqsave(&lcu->lock, flags);
-+		/*
-+		 * only move device around if it wasn't moved away while we
-+		 * were waiting for the flush
-+		 */
-+		if (device == list_first_entry(&active,
-+					       struct dasd_device, alias_list))
-+			list_move(&device->alias_list, &lcu->active_devices);
-+	}
-+	spin_unlock_irqrestore(&lcu->lock, flags);
++	asm volatile(
++		"	.insn	rre,0xb2760000,%1,0\n"
++		"	ipm	%0\n"
++		"	srl	%0,28"
++		: "=d" (ccode) : "d" (reg1) : "cc");
++	return ccode;
 +}
 +
-+/*
-+ * This function is called in interrupt context, so the
-+ * cdev lock for device is already locked!
-+ */
-+static void _stop_all_devices_on_lcu(struct alias_lcu *lcu,
-+				     struct dasd_device *device)
++#endif
+diff --git a/drivers/s390/cio/ioasm.h b/drivers/s390/cio/ioasm.h
+index 7153dd9..652ea36 100644
+--- a/drivers/s390/cio/ioasm.h
++++ b/drivers/s390/cio/ioasm.h
+@@ -109,72 +109,6 @@ static inline int tpi( volatile struct tpi_info *addr)
+ 	return ccode;
+ }
+ 
+-static inline int ssch(struct subchannel_id schid,
+-			   volatile struct orb *addr)
+-{
+-	register struct subchannel_id reg1 asm ("1") = schid;
+-	int ccode;
+-
+-	asm volatile(
+-		"	ssch	0(%2)\n"
+-		"	ipm	%0\n"
+-		"	srl	%0,28"
+-		: "=d" (ccode) : "d" (reg1), "a" (addr), "m" (*addr) : "cc");
+-	return ccode;
+-}
+-
+-static inline int rsch(struct subchannel_id schid)
+-{
+-	register struct subchannel_id reg1 asm ("1") = schid;
+-	int ccode;
+-
+-	asm volatile(
+-		"	rsch\n"
+-		"	ipm	%0\n"
+-		"	srl	%0,28"
+-		: "=d" (ccode) : "d" (reg1) : "cc");
+-	return ccode;
+-}
+-
+-static inline int csch(struct subchannel_id schid)
+-{
+-	register struct subchannel_id reg1 asm ("1") = schid;
+-	int ccode;
+-
+-	asm volatile(
+-		"	csch\n"
+-		"	ipm	%0\n"
+-		"	srl	%0,28"
+-		: "=d" (ccode) : "d" (reg1) : "cc");
+-	return ccode;
+-}
+-
+-static inline int hsch(struct subchannel_id schid)
+-{
+-	register struct subchannel_id reg1 asm ("1") = schid;
+-	int ccode;
+-
+-	asm volatile(
+-		"	hsch\n"
+-		"	ipm	%0\n"
+-		"	srl	%0,28"
+-		: "=d" (ccode) : "d" (reg1) : "cc");
+-	return ccode;
+-}
+-
+-static inline int xsch(struct subchannel_id schid)
+-{
+-	register struct subchannel_id reg1 asm ("1") = schid;
+-	int ccode;
+-
+-	asm volatile(
+-		"	.insn	rre,0xb2760000,%1,0\n"
+-		"	ipm	%0\n"
+-		"	srl	%0,28"
+-		: "=d" (ccode) : "d" (reg1) : "cc");
+-	return ccode;
+-}
+-
+ static inline int chsc(void *chsc_area)
+ {
+ 	typedef struct { char _[4096]; } addr_type;
+diff --git a/drivers/s390/cio/qdio.c b/drivers/s390/cio/qdio.c
+index 40a3208..e2a781b 100644
+--- a/drivers/s390/cio/qdio.c
++++ b/drivers/s390/cio/qdio.c
+@@ -48,11 +48,11 @@
+ #include <asm/debug.h>
+ #include <asm/s390_rdev.h>
+ #include <asm/qdio.h>
++#include <asm/airq.h>
+ 
+ #include "cio.h"
+ #include "css.h"
+ #include "device.h"
+-#include "airq.h"
+ #include "qdio.h"
+ #include "ioasm.h"
+ #include "chsc.h"
+@@ -96,7 +96,7 @@ static debug_info_t *qdio_dbf_slsb_in;
+ static volatile struct qdio_q *tiq_list=NULL; /* volatile as it could change
+ 						 during a while loop */
+ static DEFINE_SPINLOCK(ttiq_list_lock);
+-static int register_thinint_result;
++static void *tiqdio_ind;
+ static void tiqdio_tl(unsigned long);
+ static DECLARE_TASKLET(tiqdio_tasklet,tiqdio_tl,0);
+ 
+@@ -399,7 +399,7 @@ qdio_get_indicator(void)
+ {
+ 	int i;
+ 
+-	for (i=1;i<INDICATORS_PER_CACHELINE;i++)
++	for (i = 0; i < INDICATORS_PER_CACHELINE; i++)
+ 		if (!indicator_used[i]) {
+ 			indicator_used[i]=1;
+ 			return indicators+i;
+@@ -1408,8 +1408,7 @@ __tiqdio_inbound_processing(struct qdio_q *q, int spare_ind_was_set)
+ 	if (q->hydra_gives_outbound_pcis) {
+ 		if (!q->siga_sync_done_on_thinints) {
+ 			SYNC_MEMORY_ALL;
+-		} else if ((!q->siga_sync_done_on_outb_tis)&&
+-			 (q->hydra_gives_outbound_pcis)) {
++		} else if (!q->siga_sync_done_on_outb_tis) {
+ 			SYNC_MEMORY_ALL_OUTB;
+ 		}
+ 	} else {
+@@ -1911,8 +1910,7 @@ qdio_fill_thresholds(struct qdio_irq *irq_ptr,
+ 	}
+ }
+ 
+-static int
+-tiqdio_thinint_handler(void)
++static void tiqdio_thinint_handler(void *ind, void *drv_data)
+ {
+ 	QDIO_DBF_TEXT4(0,trace,"thin_int");
+ 
+@@ -1925,7 +1923,6 @@ tiqdio_thinint_handler(void)
+ 		tiqdio_clear_global_summary();
+ 
+ 	tiqdio_inbound_checks();
+-	return 0;
+ }
+ 
+ static void
+@@ -2445,7 +2442,7 @@ tiqdio_set_subchannel_ind(struct qdio_irq *irq_ptr, int reset_to_zero)
+ 		real_addr_dev_st_chg_ind=0;
+ 	} else {
+ 		real_addr_local_summary_bit=
+-			virt_to_phys((volatile void *)indicators);
++			virt_to_phys((volatile void *)tiqdio_ind);
+ 		real_addr_dev_st_chg_ind=
+ 			virt_to_phys((volatile void *)irq_ptr->dev_st_chg_ind);
+ 	}
+@@ -3740,23 +3737,25 @@ static void
+ tiqdio_register_thinints(void)
+ {
+ 	char dbf_text[20];
+-	register_thinint_result=
+-		s390_register_adapter_interrupt(&tiqdio_thinint_handler);
+-	if (register_thinint_result) {
+-		sprintf(dbf_text,"regthn%x",(register_thinint_result&0xff));
++
++	tiqdio_ind =
++		s390_register_adapter_interrupt(&tiqdio_thinint_handler, NULL);
++	if (IS_ERR(tiqdio_ind)) {
++		sprintf(dbf_text, "regthn%lx", PTR_ERR(tiqdio_ind));
+ 		QDIO_DBF_TEXT0(0,setup,dbf_text);
+ 		QDIO_PRINT_ERR("failed to register adapter handler " \
+-			       "(rc=%i).\nAdapter interrupts might " \
++			       "(rc=%li).\nAdapter interrupts might " \
+ 			       "not work. Continuing.\n",
+-			       register_thinint_result);
++			       PTR_ERR(tiqdio_ind));
++		tiqdio_ind = NULL;
+ 	}
+ }
+ 
+ static void
+ tiqdio_unregister_thinints(void)
+ {
+-	if (!register_thinint_result)
+-		s390_unregister_adapter_interrupt(&tiqdio_thinint_handler);
++	if (tiqdio_ind)
++		s390_unregister_adapter_interrupt(tiqdio_ind);
+ }
+ 
+ static int
+@@ -3768,8 +3767,8 @@ qdio_get_qdio_memory(void)
+ 	for (i=1;i<INDICATORS_PER_CACHELINE;i++)
+ 		indicator_used[i]=0;
+ 	indicators = kzalloc(sizeof(__u32)*(INDICATORS_PER_CACHELINE),
+-				   GFP_KERNEL);
+-       	if (!indicators)
++			     GFP_KERNEL);
++	if (!indicators)
+ 		return -ENOMEM;
+ 	return 0;
+ }
+@@ -3780,7 +3779,6 @@ qdio_release_qdio_memory(void)
+ 	kfree(indicators);
+ }
+ 
+-
+ static void
+ qdio_unregister_dbf_views(void)
+ {
+diff --git a/drivers/s390/cio/qdio.h b/drivers/s390/cio/qdio.h
+index 6d7aad1..37870e4 100644
+--- a/drivers/s390/cio/qdio.h
++++ b/drivers/s390/cio/qdio.h
+@@ -57,7 +57,7 @@
+ 					    of the queue to 0 */
+ 
+ #define QDIO_ESTABLISH_TIMEOUT (1*HZ)
+-#define QDIO_ACTIVATE_TIMEOUT ((5*HZ)>>10)
++#define QDIO_ACTIVATE_TIMEOUT (5*HZ)
+ #define QDIO_CLEANUP_CLEAR_TIMEOUT (20*HZ)
+ #define QDIO_CLEANUP_HALT_TIMEOUT (10*HZ)
+ #define QDIO_FORCE_CHECK_TIMEOUT (10*HZ)
+diff --git a/drivers/s390/net/claw.c b/drivers/s390/net/claw.c
+index 3561982..c307621 100644
+--- a/drivers/s390/net/claw.c
++++ b/drivers/s390/net/claw.c
+@@ -2416,7 +2416,7 @@ init_ccw_bk(struct net_device *dev)
+ 		    privptr->p_buff_pages_perwrite);
+ #endif
+                    if (p_buff==NULL) {
+-                        printk(KERN_INFO "%s:%s __get_free_pages"
++			printk(KERN_INFO "%s:%s __get_free_pages "
+ 			 	"for writes buf failed : get is for %d pages\n",
+ 				dev->name,
+ 				__FUNCTION__,
+diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c
+index 0fd663b..7bfe8d7 100644
+--- a/drivers/s390/net/lcs.c
++++ b/drivers/s390/net/lcs.c
+@@ -1115,7 +1115,7 @@ list_modified:
+ 			rc = lcs_send_setipm(card, ipm);
+ 			spin_lock_irqsave(&card->ipm_lock, flags);
+ 			if (rc) {
+-				PRINT_INFO("Adding multicast address failed."
++				PRINT_INFO("Adding multicast address failed. "
+ 					   "Table possibly full!\n");
+ 				/* store ipm in failed list -> will be added
+ 				 * to ipm_list again, so a retry will be done
+diff --git a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c
+index c7ea938..f3d893c 100644
+--- a/drivers/s390/net/netiucv.c
++++ b/drivers/s390/net/netiucv.c
+@@ -198,8 +198,7 @@ struct iucv_connection {
+ /**
+  * Linked list of all connection structs.
+  */
+-static struct list_head iucv_connection_list =
+-	LIST_HEAD_INIT(iucv_connection_list);
++static LIST_HEAD(iucv_connection_list);
+ static DEFINE_RWLOCK(iucv_connection_rwlock);
+ 
+ /**
+@@ -2089,6 +2088,11 @@ static struct attribute_group netiucv_drv_attr_group = {
+ 	.attrs = netiucv_drv_attrs,
+ };
+ 
++static struct attribute_group *netiucv_drv_attr_groups[] = {
++	&netiucv_drv_attr_group,
++	NULL,
++};
++
+ static void netiucv_banner(void)
+ {
+ 	PRINT_INFO("NETIUCV driver initialized\n");
+@@ -2113,7 +2117,6 @@ static void __exit netiucv_exit(void)
+ 		netiucv_unregister_device(dev);
+ 	}
+ 
+-	sysfs_remove_group(&netiucv_driver.kobj, &netiucv_drv_attr_group);
+ 	driver_unregister(&netiucv_driver);
+ 	iucv_unregister(&netiucv_handler, 1);
+ 	iucv_unregister_dbf_views();
+@@ -2133,6 +2136,7 @@ static int __init netiucv_init(void)
+ 	if (rc)
+ 		goto out_dbf;
+ 	IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
++	netiucv_driver.groups = netiucv_drv_attr_groups;
+ 	rc = driver_register(&netiucv_driver);
+ 	if (rc) {
+ 		PRINT_ERR("NETIUCV: failed to register driver.\n");
+@@ -2140,18 +2144,9 @@ static int __init netiucv_init(void)
+ 		goto out_iucv;
+ 	}
+ 
+-	rc = sysfs_create_group(&netiucv_driver.kobj, &netiucv_drv_attr_group);
+-	if (rc) {
+-		PRINT_ERR("NETIUCV: failed to add driver attributes.\n");
+-		IUCV_DBF_TEXT_(setup, 2,
+-			       "ret %d - netiucv_drv_attr_group\n", rc);
+-		goto out_driver;
+-	}
+ 	netiucv_banner();
+ 	return rc;
+ 
+-out_driver:
+-	driver_unregister(&netiucv_driver);
+ out_iucv:
+ 	iucv_unregister(&netiucv_handler, 1);
+ out_dbf:
+diff --git a/drivers/s390/net/qeth_proc.c b/drivers/s390/net/qeth_proc.c
+index f1ff165..46ecd03 100644
+--- a/drivers/s390/net/qeth_proc.c
++++ b/drivers/s390/net/qeth_proc.c
+@@ -146,7 +146,7 @@ qeth_procfile_seq_show(struct seq_file *s, void *it)
+ 	return 0;
+ }
+ 
+-static struct seq_operations qeth_procfile_seq_ops = {
++static const struct seq_operations qeth_procfile_seq_ops = {
+ 	.start = qeth_procfile_seq_start,
+ 	.stop  = qeth_procfile_seq_stop,
+ 	.next  = qeth_procfile_seq_next,
+@@ -264,7 +264,7 @@ qeth_perf_procfile_seq_show(struct seq_file *s, void *it)
+ 	return 0;
+ }
+ 
+-static struct seq_operations qeth_perf_procfile_seq_ops = {
++static const struct seq_operations qeth_perf_procfile_seq_ops = {
+ 	.start = qeth_procfile_seq_start,
+ 	.stop  = qeth_procfile_seq_stop,
+ 	.next  = qeth_procfile_seq_next,
+diff --git a/drivers/s390/net/smsgiucv.c b/drivers/s390/net/smsgiucv.c
+index 47bb47b..8735a41 100644
+--- a/drivers/s390/net/smsgiucv.c
++++ b/drivers/s390/net/smsgiucv.c
+@@ -42,7 +42,7 @@ MODULE_DESCRIPTION ("Linux for S/390 IUCV special message driver");
+ static struct iucv_path *smsg_path;
+ 
+ static DEFINE_SPINLOCK(smsg_list_lock);
+-static struct list_head smsg_list = LIST_HEAD_INIT(smsg_list);
++static LIST_HEAD(smsg_list);
+ 
+ static int smsg_path_pending(struct iucv_path *, u8 ipvmid[8], u8 ipuser[16]);
+ static void smsg_message_pending(struct iucv_path *, struct iucv_message *);
+diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c
+index 0011849..874b55e 100644
+--- a/drivers/s390/scsi/zfcp_aux.c
++++ b/drivers/s390/scsi/zfcp_aux.c
+@@ -844,8 +844,6 @@ zfcp_unit_enqueue(struct zfcp_port *port, fcp_lun_t fcp_lun)
+ 	unit->sysfs_device.release = zfcp_sysfs_unit_release;
+ 	dev_set_drvdata(&unit->sysfs_device, unit);
+ 
+-	init_waitqueue_head(&unit->scsi_scan_wq);
+-
+ 	/* mark unit unusable as long as sysfs registration is not complete */
+ 	atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &unit->status);
+ 
+diff --git a/drivers/s390/scsi/zfcp_ccw.c b/drivers/s390/scsi/zfcp_ccw.c
+index e01cbf1..edc5015 100644
+--- a/drivers/s390/scsi/zfcp_ccw.c
++++ b/drivers/s390/scsi/zfcp_ccw.c
+@@ -52,6 +52,9 @@ static struct ccw_driver zfcp_ccw_driver = {
+ 	.set_offline = zfcp_ccw_set_offline,
+ 	.notify      = zfcp_ccw_notify,
+ 	.shutdown    = zfcp_ccw_shutdown,
++	.driver = {
++		.groups = zfcp_driver_attr_groups,
++	},
+ };
+ 
+ MODULE_DEVICE_TABLE(ccw, zfcp_ccw_device_id);
+@@ -120,6 +123,9 @@ zfcp_ccw_remove(struct ccw_device *ccw_device)
+ 
+ 	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))
++				scsi_remove_device(unit->device);
+ 			zfcp_unit_dequeue(unit);
+ 		}
+ 		zfcp_port_dequeue(port);
+@@ -251,16 +257,7 @@ zfcp_ccw_notify(struct ccw_device *ccw_device, int event)
+ int __init
+ zfcp_ccw_register(void)
+ {
+-	int retval;
+-
+-	retval = ccw_driver_register(&zfcp_ccw_driver);
+-	if (retval)
+-		goto out;
+-	retval = zfcp_sysfs_driver_create_files(&zfcp_ccw_driver.driver);
+-	if (retval)
+-		ccw_driver_unregister(&zfcp_ccw_driver);
+- out:
+-	return retval;
++	return ccw_driver_register(&zfcp_ccw_driver);
+ }
+ 
+ /**
+diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c
+index ffa3bf7..701046c 100644
+--- a/drivers/s390/scsi/zfcp_dbf.c
++++ b/drivers/s390/scsi/zfcp_dbf.c
+@@ -161,12 +161,6 @@ void zfcp_hba_dbf_event_fsf_response(struct zfcp_fsf_req *fsf_req)
+ 		   (fsf_req->fsf_command == FSF_QTCB_OPEN_LUN)) {
+ 		strncpy(rec->tag2, "open", ZFCP_DBF_TAG_SIZE);
+ 		level = 4;
+-	} else if ((prot_status_qual->doubleword[0] != 0) ||
+-		   (prot_status_qual->doubleword[1] != 0) ||
+-		   (fsf_status_qual->doubleword[0] != 0) ||
+-		   (fsf_status_qual->doubleword[1] != 0)) {
+-		strncpy(rec->tag2, "qual", ZFCP_DBF_TAG_SIZE);
+-		level = 3;
+ 	} else {
+ 		strncpy(rec->tag2, "norm", ZFCP_DBF_TAG_SIZE);
+ 		level = 6;
+diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h
+index e268f79..9e9f6c1 100644
+--- a/drivers/s390/scsi/zfcp_def.h
++++ b/drivers/s390/scsi/zfcp_def.h
+@@ -118,7 +118,7 @@ zfcp_address_to_sg(void *address, struct scatterlist *list, unsigned int size)
+ 
+ #define ZFCP_SBAL_TIMEOUT               (5*HZ)
+ 
+-#define ZFCP_TYPE2_RECOVERY_TIME        (8*HZ)
++#define ZFCP_TYPE2_RECOVERY_TIME        8	/* seconds */
+ 
+ /* queue polling (values in microseconds) */
+ #define ZFCP_MAX_INPUT_THRESHOLD 	5000	/* FIXME: tune */
+@@ -139,7 +139,7 @@ zfcp_address_to_sg(void *address, struct scatterlist *list, unsigned int size)
+ #define ZFCP_STATUS_READS_RECOM		        FSF_STATUS_READS_RECOM
+ 
+ /* Do 1st retry in 1 second, then double the timeout for each following retry */
+-#define ZFCP_EXCHANGE_CONFIG_DATA_FIRST_SLEEP	100
++#define ZFCP_EXCHANGE_CONFIG_DATA_FIRST_SLEEP	1
+ #define ZFCP_EXCHANGE_CONFIG_DATA_RETRIES	7
+ 
+ /* timeout value for "default timer" for fsf requests */
+@@ -983,10 +983,6 @@ struct zfcp_unit {
+         struct scsi_device     *device;        /* scsi device struct pointer */
+ 	struct zfcp_erp_action erp_action;     /* pending error recovery */
+         atomic_t               erp_counter;
+-	wait_queue_head_t      scsi_scan_wq;   /* can be used to wait until
+-						  all scsi_scan_target
+-						  requests have been
+-						  completed. */
+ };
+ 
+ /* FSF request */
+@@ -1127,6 +1123,20 @@ zfcp_reqlist_find(struct zfcp_adapter *adapter, unsigned long req_id)
+ 	return NULL;
+ }
+ 
++static inline struct zfcp_fsf_req *
++zfcp_reqlist_find_safe(struct zfcp_adapter *adapter, struct zfcp_fsf_req *req)
 +{
-+	struct alias_pav_group *pavgroup;
-+	struct dasd_device *pos;
++	struct zfcp_fsf_req *request;
++	unsigned int idx;
 +
-+	list_for_each_entry(pos, &lcu->active_devices, alias_list) {
-+		if (pos != device)
-+			spin_lock(get_ccwdev_lock(pos->cdev));
-+		pos->stopped |= DASD_STOPPED_SU;
-+		if (pos != device)
-+			spin_unlock(get_ccwdev_lock(pos->cdev));
-+	}
-+	list_for_each_entry(pos, &lcu->inactive_devices, alias_list) {
-+		if (pos != device)
-+			spin_lock(get_ccwdev_lock(pos->cdev));
-+		pos->stopped |= DASD_STOPPED_SU;
-+		if (pos != device)
-+			spin_unlock(get_ccwdev_lock(pos->cdev));
-+	}
-+	list_for_each_entry(pavgroup, &lcu->grouplist, group) {
-+		list_for_each_entry(pos, &pavgroup->baselist, alias_list) {
-+			if (pos != device)
-+				spin_lock(get_ccwdev_lock(pos->cdev));
-+			pos->stopped |= DASD_STOPPED_SU;
-+			if (pos != device)
-+				spin_unlock(get_ccwdev_lock(pos->cdev));
-+		}
-+		list_for_each_entry(pos, &pavgroup->aliaslist, alias_list) {
-+			if (pos != device)
-+				spin_lock(get_ccwdev_lock(pos->cdev));
-+			pos->stopped |= DASD_STOPPED_SU;
-+			if (pos != device)
-+				spin_unlock(get_ccwdev_lock(pos->cdev));
-+		}
++	for (idx = 0; idx < REQUEST_LIST_SIZE; idx++) {
++		list_for_each_entry(request, &adapter->req_list[idx], list)
++			if (request == req)
++				return request;
 +	}
++	return NULL;
 +}
 +
-+static void _unstop_all_devices_on_lcu(struct alias_lcu *lcu)
-+{
-+	struct alias_pav_group *pavgroup;
-+	struct dasd_device *device;
-+	unsigned long flags;
+ /*
+  *  functions needed for reference/usage counting
+  */
+diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c
+index 07fa824..2dc8110 100644
+--- a/drivers/s390/scsi/zfcp_erp.c
++++ b/drivers/s390/scsi/zfcp_erp.c
+@@ -131,7 +131,7 @@ static void zfcp_close_qdio(struct zfcp_adapter *adapter)
+ 	debug_text_event(adapter->erp_dbf, 3, "qdio_down2a");
+ 	while (qdio_shutdown(adapter->ccw_device,
+ 			     QDIO_FLAG_CLEANUP_USING_CLEAR) == -EINPROGRESS)
+-		msleep(1000);
++		ssleep(1);
+ 	debug_text_event(adapter->erp_dbf, 3, "qdio_down2b");
+ 
+ 	/* cleanup used outbound sbals */
+@@ -456,7 +456,7 @@ zfcp_test_link(struct zfcp_port *port)
+ 
+ 	zfcp_port_get(port);
+ 	retval = zfcp_erp_adisc(port);
+-	if (retval != 0) {
++	if (retval != 0 && retval != -EBUSY) {
+ 		zfcp_port_put(port);
+ 		ZFCP_LOG_NORMAL("reopen needed for port 0x%016Lx "
+ 				"on adapter %s\n ", port->wwpn,
+@@ -846,7 +846,8 @@ zfcp_erp_strategy_check_fsfreq(struct zfcp_erp_action *erp_action)
+ 	if (erp_action->fsf_req) {
+ 		/* take lock to ensure that request is not deleted meanwhile */
+ 		spin_lock(&adapter->req_list_lock);
+-		if (zfcp_reqlist_find(adapter, erp_action->fsf_req->req_id)) {
++		if (zfcp_reqlist_find_safe(adapter, erp_action->fsf_req) &&
++		    erp_action->fsf_req->erp_action == erp_action) {
+ 			/* fsf_req still exists */
+ 			debug_text_event(adapter->erp_dbf, 3, "a_ca_req");
+ 			debug_event(adapter->erp_dbf, 3, &erp_action->fsf_req,
+@@ -1285,7 +1286,7 @@ zfcp_erp_strategy_do_action(struct zfcp_erp_action *erp_action)
+ 	 * note: no lock in subsequent strategy routines
+ 	 * (this allows these routine to call schedule, e.g.
+ 	 * kmalloc with such flags or qdio_initialize & friends)
+-	 * Note: in case of timeout, the seperate strategies will fail
++	 * Note: in case of timeout, the separate strategies will fail
+ 	 * anyhow. No need for a special action. Even worse, a nameserver
+ 	 * failure would not wake up waiting ports without the call.
+ 	 */
+@@ -1609,7 +1610,6 @@ static void zfcp_erp_scsi_scan(struct work_struct *work)
+ 	scsi_scan_target(&rport->dev, 0, rport->scsi_target_id,
+ 			 unit->scsi_lun, 0);
+ 	atomic_clear_mask(ZFCP_STATUS_UNIT_SCSI_WORK_PENDING, &unit->status);
+-	wake_up(&unit->scsi_scan_wq);
+ 	zfcp_unit_put(unit);
+ 	kfree(p);
+ }
+@@ -1900,7 +1900,7 @@ zfcp_erp_adapter_strategy(struct zfcp_erp_action *erp_action)
+ 		ZFCP_LOG_INFO("Waiting to allow the adapter %s "
+ 			      "to recover itself\n",
+ 			      zfcp_get_busid_by_adapter(adapter));
+-		msleep(jiffies_to_msecs(ZFCP_TYPE2_RECOVERY_TIME));
++		ssleep(ZFCP_TYPE2_RECOVERY_TIME);
+ 	}
+ 
+ 	return retval;
+@@ -2080,7 +2080,7 @@ zfcp_erp_adapter_strategy_open_qdio(struct zfcp_erp_action *erp_action)
+ 	debug_text_event(adapter->erp_dbf, 3, "qdio_down1a");
+ 	while (qdio_shutdown(adapter->ccw_device,
+ 			     QDIO_FLAG_CLEANUP_USING_CLEAR) == -EINPROGRESS)
+-		msleep(1000);
++		ssleep(1);
+ 	debug_text_event(adapter->erp_dbf, 3, "qdio_down1b");
+ 
+  failed_qdio_establish:
+@@ -2165,7 +2165,7 @@ zfcp_erp_adapter_strategy_open_fsf_xconfig(struct zfcp_erp_action *erp_action)
+ 		ZFCP_LOG_DEBUG("host connection still initialising... "
+ 			       "waiting and retrying...\n");
+ 		/* sleep a little bit before retry */
+-		msleep(jiffies_to_msecs(sleep));
++		ssleep(sleep);
+ 		sleep *= 2;
+ 	}
+ 
+diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h
+index 8534cf0..06b1079 100644
+--- a/drivers/s390/scsi/zfcp_ext.h
++++ b/drivers/s390/scsi/zfcp_ext.h
+@@ -27,8 +27,7 @@
+ extern struct zfcp_data zfcp_data;
+ 
+ /******************************** SYSFS  *************************************/
+-extern int  zfcp_sysfs_driver_create_files(struct device_driver *);
+-extern void zfcp_sysfs_driver_remove_files(struct device_driver *);
++extern struct attribute_group *zfcp_driver_attr_groups[];
+ extern int  zfcp_sysfs_adapter_create_files(struct device *);
+ extern void zfcp_sysfs_adapter_remove_files(struct device *);
+ extern int  zfcp_sysfs_port_create_files(struct device *, u32);
+diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c
+index ff866eb..e45f85f 100644
+--- a/drivers/s390/scsi/zfcp_fsf.c
++++ b/drivers/s390/scsi/zfcp_fsf.c
+@@ -502,7 +502,7 @@ zfcp_fsf_fsfstatus_qual_eval(struct zfcp_fsf_req *fsf_req)
+ 		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
+ 		break;
+ 	case FSF_SQ_NO_RECOM:
+-		ZFCP_LOG_NORMAL("bug: No recommendation could be given for a"
++		ZFCP_LOG_NORMAL("bug: No recommendation could be given for a "
+ 				"problem on the adapter %s "
+ 				"Stopping all operations on this adapter. ",
+ 				zfcp_get_busid_by_adapter(fsf_req->adapter));
+@@ -813,7 +813,7 @@ zfcp_fsf_status_read_port_closed(struct zfcp_fsf_req *fsf_req)
+ 	read_unlock_irqrestore(&zfcp_data.config_lock, flags);
+ 
+ 	if (!port || (port->d_id != (status_buffer->d_id & ZFCP_DID_MASK))) {
+-		ZFCP_LOG_NORMAL("bug: Reopen port indication received for"
++		ZFCP_LOG_NORMAL("bug: Reopen port indication received for "
+ 				"nonexisting port with d_id 0x%06x on "
+ 				"adapter %s. Ignored.\n",
+ 				status_buffer->d_id & ZFCP_DID_MASK,
+@@ -1116,6 +1116,10 @@ zfcp_fsf_abort_fcp_command(unsigned long old_req_id,
+ 		goto out;
+ 	}
+ 
++	if (unlikely(!atomic_test_mask(ZFCP_STATUS_COMMON_UNBLOCKED,
++			&unit->status)))
++		goto unit_blocked;
 +
-+	list_for_each_entry(device, &lcu->active_devices, alias_list) {
-+		spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
-+		device->stopped &= ~DASD_STOPPED_SU;
-+		spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
-+	}
+ 	sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
+         sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
+         sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
+@@ -1131,22 +1135,13 @@ zfcp_fsf_abort_fcp_command(unsigned long old_req_id,
+ 
+ 	zfcp_fsf_start_timer(fsf_req, ZFCP_SCSI_ER_TIMEOUT);
+ 	retval = zfcp_fsf_req_send(fsf_req);
+-	if (retval) {
+-		ZFCP_LOG_INFO("error: Failed to send abort command request "
+-			      "on adapter %s, port 0x%016Lx, unit 0x%016Lx\n",
+-			      zfcp_get_busid_by_adapter(adapter),
+-			      unit->port->wwpn, unit->fcp_lun);
++	if (!retval)
++		goto out;
 +
-+	list_for_each_entry(device, &lcu->inactive_devices, alias_list) {
-+		spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
-+		device->stopped &= ~DASD_STOPPED_SU;
-+		spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
++ unit_blocked:
+ 		zfcp_fsf_req_free(fsf_req);
+ 		fsf_req = NULL;
+-		goto out;
+-	}
+ 
+-	ZFCP_LOG_DEBUG("Abort FCP Command request initiated "
+-		       "(adapter%s, port d_id=0x%06x, "
+-		       "unit x%016Lx, old_req_id=0x%lx)\n",
+-		       zfcp_get_busid_by_adapter(adapter),
+-		       unit->port->d_id,
+-		       unit->fcp_lun, old_req_id);
+  out:
+ 	write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags);
+ 	return fsf_req;
+@@ -1164,8 +1159,8 @@ zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *new_fsf_req)
+ {
+ 	int retval = -EINVAL;
+ 	struct zfcp_unit *unit;
+-	unsigned char status_qual =
+-	    new_fsf_req->qtcb->header.fsf_status_qual.word[0];
++	union fsf_status_qual *fsf_stat_qual =
++		&new_fsf_req->qtcb->header.fsf_status_qual;
+ 
+ 	if (new_fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) {
+ 		/* do not set ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED */
+@@ -1178,7 +1173,7 @@ zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *new_fsf_req)
+ 	switch (new_fsf_req->qtcb->header.fsf_status) {
+ 
+ 	case FSF_PORT_HANDLE_NOT_VALID:
+-		if (status_qual >> 4 != status_qual % 0xf) {
++		if (fsf_stat_qual->word[0] != fsf_stat_qual->word[1]) {
+ 			debug_text_event(new_fsf_req->adapter->erp_dbf, 3,
+ 					 "fsf_s_phand_nv0");
+ 			/*
+@@ -1207,8 +1202,7 @@ zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *new_fsf_req)
+ 		break;
+ 
+ 	case FSF_LUN_HANDLE_NOT_VALID:
+-		if (status_qual >> 4 != status_qual % 0xf) {
+-			/* 2 */
++		if (fsf_stat_qual->word[0] != fsf_stat_qual->word[1]) {
+ 			debug_text_event(new_fsf_req->adapter->erp_dbf, 3,
+ 					 "fsf_s_lhand_nv0");
+ 			/*
+@@ -1674,6 +1668,12 @@ zfcp_fsf_send_els(struct zfcp_send_els *els)
+                 goto failed_req;
+ 	}
+ 
++	if (unlikely(!atomic_test_mask(ZFCP_STATUS_COMMON_UNBLOCKED,
++			&els->port->status))) {
++		ret = -EBUSY;
++		goto port_blocked;
 +	}
 +
-+	list_for_each_entry(pavgroup, &lcu->grouplist, group) {
-+		list_for_each_entry(device, &pavgroup->baselist, alias_list) {
-+			spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
-+			device->stopped &= ~DASD_STOPPED_SU;
-+			spin_unlock_irqrestore(get_ccwdev_lock(device->cdev),
-+					       flags);
-+		}
-+		list_for_each_entry(device, &pavgroup->aliaslist, alias_list) {
-+			spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
-+			device->stopped &= ~DASD_STOPPED_SU;
-+			spin_unlock_irqrestore(get_ccwdev_lock(device->cdev),
-+					       flags);
-+		}
+ 	sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
+         if (zfcp_use_one_sbal(els->req, els->req_count,
+                               els->resp, els->resp_count)){
+@@ -1755,6 +1755,7 @@ zfcp_fsf_send_els(struct zfcp_send_els *els)
+ 		       "0x%06x)\n", zfcp_get_busid_by_adapter(adapter), d_id);
+ 	goto out;
+ 
++ port_blocked:
+  failed_send:
+ 	zfcp_fsf_req_free(fsf_req);
+ 
+@@ -2280,7 +2281,7 @@ zfcp_fsf_exchange_port_data(struct zfcp_erp_action *erp_action)
+ 				     &lock_flags, &fsf_req);
+ 	if (retval) {
+ 		ZFCP_LOG_INFO("error: Out of resources. Could not create an "
+-			      "exchange port data request for"
++			      "exchange port data request for "
+ 			      "the adapter %s.\n",
+ 			      zfcp_get_busid_by_adapter(adapter));
+ 		write_unlock_irqrestore(&adapter->request_queue.queue_lock,
+@@ -2339,7 +2340,7 @@ zfcp_fsf_exchange_port_data_sync(struct zfcp_adapter *adapter,
+ 				0, NULL, &lock_flags, &fsf_req);
+ 	if (retval) {
+ 		ZFCP_LOG_INFO("error: Out of resources. Could not create an "
+-			      "exchange port data request for"
++			      "exchange port data request for "
+ 			      "the adapter %s.\n",
+ 			      zfcp_get_busid_by_adapter(adapter));
+ 		write_unlock_irqrestore(&adapter->request_queue.queue_lock,
+@@ -3592,6 +3593,12 @@ zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *adapter,
+ 		goto failed_req_create;
+ 	}
+ 
++	if (unlikely(!atomic_test_mask(ZFCP_STATUS_COMMON_UNBLOCKED,
++			&unit->status))) {
++		retval = -EBUSY;
++		goto unit_blocked;
 +	}
-+}
-+
-+static void summary_unit_check_handling_work(struct work_struct *work)
-+{
-+	struct alias_lcu *lcu;
-+	struct summary_unit_check_work_data *suc_data;
-+	unsigned long flags;
-+	struct dasd_device *device;
-+
-+	suc_data = container_of(work, struct summary_unit_check_work_data,
-+				worker);
-+	lcu = container_of(suc_data, struct alias_lcu, suc_data);
-+	device = suc_data->device;
-+
-+	/* 1. flush alias devices */
-+	flush_all_alias_devices_on_lcu(lcu);
-+
-+	/* 2. reset summary unit check */
-+	spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
-+	device->stopped &= ~(DASD_STOPPED_SU | DASD_STOPPED_PENDING);
-+	spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
-+	reset_summary_unit_check(lcu, device, suc_data->reason);
-+
-+	spin_lock_irqsave(&lcu->lock, flags);
-+	_unstop_all_devices_on_lcu(lcu);
-+	_restart_all_base_devices_on_lcu(lcu);
-+	/* 3. read new alias configuration */
-+	_schedule_lcu_update(lcu, device);
-+	lcu->suc_data.device = NULL;
-+	spin_unlock_irqrestore(&lcu->lock, flags);
-+}
-+
-+/*
-+ * note: this will be called from int handler context (cdev locked)
-+ */
-+void dasd_alias_handle_summary_unit_check(struct dasd_device *device,
-+					  struct irb *irb)
-+{
-+	struct alias_lcu *lcu;
-+	char reason;
-+	struct dasd_eckd_private *private;
 +
-+	private = (struct dasd_eckd_private *) device->private;
+ 	zfcp_unit_get(unit);
+ 	fsf_req->unit = unit;
+ 
+@@ -3732,6 +3739,7 @@ zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *adapter,
+  send_failed:
+  no_fit:
+  failed_scsi_cmnd:
++ unit_blocked:
+ 	zfcp_unit_put(unit);
+ 	zfcp_fsf_req_free(fsf_req);
+ 	fsf_req = NULL;
+@@ -3766,6 +3774,10 @@ zfcp_fsf_send_fcp_command_task_management(struct zfcp_adapter *adapter,
+ 		goto out;
+ 	}
+ 
++	if (unlikely(!atomic_test_mask(ZFCP_STATUS_COMMON_UNBLOCKED,
++			&unit->status)))
++		goto unit_blocked;
 +
-+	reason = irb->ecw[8];
-+	DEV_MESSAGE(KERN_WARNING, device, "%s %x",
-+		    "eckd handle summary unit check: reason", reason);
+ 	/*
+ 	 * Used to decide on proper handler in the return path,
+ 	 * could be either zfcp_fsf_send_fcp_command_task_handler or
+@@ -3799,25 +3811,13 @@ zfcp_fsf_send_fcp_command_task_management(struct zfcp_adapter *adapter,
+ 
+ 	zfcp_fsf_start_timer(fsf_req, ZFCP_SCSI_ER_TIMEOUT);
+ 	retval = zfcp_fsf_req_send(fsf_req);
+-	if (retval) {
+-		ZFCP_LOG_INFO("error: Could not send an FCP-command (task "
+-			      "management) on adapter %s, port 0x%016Lx for "
+-			      "unit LUN 0x%016Lx\n",
+-			      zfcp_get_busid_by_adapter(adapter),
+-			      unit->port->wwpn,
+-			      unit->fcp_lun);
+-		zfcp_fsf_req_free(fsf_req);
+-		fsf_req = NULL;
++	if (!retval)
+ 		goto out;
+-	}
+ 
+-	ZFCP_LOG_TRACE("Send FCP Command (task management function) initiated "
+-		       "(adapter %s, port 0x%016Lx, unit 0x%016Lx, "
+-		       "tm_flags=0x%x)\n",
+-		       zfcp_get_busid_by_adapter(adapter),
+-		       unit->port->wwpn,
+-		       unit->fcp_lun,
+-		       tm_flags);
++ unit_blocked:
++	zfcp_fsf_req_free(fsf_req);
++	fsf_req = NULL;
 +
-+	lcu = private->lcu;
-+	if (!lcu) {
-+		DEV_MESSAGE(KERN_WARNING, device, "%s",
-+			    "device not ready to handle summary"
-+			    " unit check (no lcu structure)");
-+		return;
-+	}
-+	spin_lock(&lcu->lock);
-+	_stop_all_devices_on_lcu(lcu, device);
-+	/* prepare for lcu_update */
-+	private->lcu->flags |= NEED_UAC_UPDATE | UPDATE_PENDING;
-+	/* If this device is about to be removed just return and wait for
-+	 * the next interrupt on a different device
-+	 */
-+	if (list_empty(&device->alias_list)) {
-+		DEV_MESSAGE(KERN_WARNING, device, "%s",
-+			    "device is in offline processing,"
-+			    " don't do summary unit check handling");
-+		spin_unlock(&lcu->lock);
-+		return;
-+	}
-+	if (lcu->suc_data.device) {
-+		/* already scheduled or running */
-+		DEV_MESSAGE(KERN_WARNING, device, "%s",
-+			    "previous instance of summary unit check worker"
-+			    " still pending");
-+		spin_unlock(&lcu->lock);
-+		return ;
-+	}
-+	lcu->suc_data.reason = reason;
-+	lcu->suc_data.device = device;
-+	spin_unlock(&lcu->lock);
-+	schedule_work(&lcu->suc_data.worker);
-+};
-diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c
-index 0c67258..f4fb402 100644
---- a/drivers/s390/block/dasd_devmap.c
-+++ b/drivers/s390/block/dasd_devmap.c
-@@ -49,22 +49,6 @@ struct dasd_devmap {
- };
+  out:
+ 	write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags);
+ 	return fsf_req;
+@@ -4725,7 +4725,7 @@ zfcp_fsf_req_create(struct zfcp_adapter *adapter, u32 fsf_cmd, int req_flags,
+ 	/* allocate new FSF request */
+ 	fsf_req = zfcp_fsf_req_alloc(pool, req_flags);
+ 	if (unlikely(NULL == fsf_req)) {
+-		ZFCP_LOG_DEBUG("error: Could not put an FSF request into"
++		ZFCP_LOG_DEBUG("error: Could not put an FSF request into "
+ 			       "the outbound (send) queue.\n");
+ 		ret = -ENOMEM;
+ 		goto failed_fsf_req;
+diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c
+index 51d92b1..22fdc17 100644
+--- a/drivers/s390/scsi/zfcp_qdio.c
++++ b/drivers/s390/scsi/zfcp_qdio.c
+@@ -529,7 +529,7 @@ zfcp_qdio_sbals_wipe(struct zfcp_fsf_req *fsf_req)
  
- /*
-- * dasd_server_ssid_map contains a globally unique storage server subsystem ID.
-- * dasd_server_ssid_list contains the list of all subsystem IDs accessed by
-- * the DASD device driver.
-- */
--struct dasd_server_ssid_map {
--	struct list_head list;
--	struct system_id {
--		char vendor[4];
--		char serial[15];
--		__u16 ssid;
--	} sid;
--};
--
--static struct list_head dasd_server_ssid_list;
--
--/*
-  * Parameter parsing functions for dasd= parameter. The syntax is:
-  *   <devno>		: (0x)?[0-9a-fA-F]+
-  *   <busid>		: [0-0a-f]\.[0-9a-f]\.(0x)?[0-9a-fA-F]+
-@@ -721,8 +705,9 @@ dasd_ro_store(struct device *dev, struct device_attribute *attr,
- 		devmap->features &= ~DASD_FEATURE_READONLY;
- 	if (devmap->device)
- 		devmap->device->features = devmap->features;
--	if (devmap->device && devmap->device->gdp)
--		set_disk_ro(devmap->device->gdp, val);
-+	if (devmap->device && devmap->device->block
-+	    && devmap->device->block->gdp)
-+		set_disk_ro(devmap->device->block->gdp, val);
- 	spin_unlock(&dasd_devmap_lock);
- 	return count;
- }
-@@ -893,12 +878,16 @@ dasd_alias_show(struct device *dev, struct device_attribute *attr, char *buf)
  
- 	devmap = dasd_find_busid(dev->bus_id);
- 	spin_lock(&dasd_devmap_lock);
--	if (!IS_ERR(devmap))
--		alias = devmap->uid.alias;
-+	if (IS_ERR(devmap) || strlen(devmap->uid.vendor) == 0) {
-+		spin_unlock(&dasd_devmap_lock);
-+		return sprintf(buf, "0\n");
-+	}
-+	if (devmap->uid.type == UA_BASE_PAV_ALIAS ||
-+	    devmap->uid.type == UA_HYPER_PAV_ALIAS)
-+		alias = 1;
- 	else
- 		alias = 0;
- 	spin_unlock(&dasd_devmap_lock);
+ /**
+- * zfcp_qdio_sbale_fill - set address and lenght in current SBALE
++ * zfcp_qdio_sbale_fill - set address and length in current SBALE
+  *	on request_queue
+  */
+ static void
+diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c
+index abae202..b9daf5c 100644
+--- a/drivers/s390/scsi/zfcp_scsi.c
++++ b/drivers/s390/scsi/zfcp_scsi.c
+@@ -51,7 +51,6 @@ struct zfcp_data zfcp_data = {
+ 		.queuecommand		= zfcp_scsi_queuecommand,
+ 		.eh_abort_handler	= zfcp_scsi_eh_abort_handler,
+ 		.eh_device_reset_handler = zfcp_scsi_eh_device_reset_handler,
+-		.eh_bus_reset_handler	= zfcp_scsi_eh_host_reset_handler,
+ 		.eh_host_reset_handler	= zfcp_scsi_eh_host_reset_handler,
+ 		.can_queue		= 4096,
+ 		.this_id		= -1,
+@@ -181,9 +180,6 @@ static void zfcp_scsi_slave_destroy(struct scsi_device *sdpnt)
+ 
+ 	if (unit) {
+ 		zfcp_erp_wait(unit->port->adapter);
+-		wait_event(unit->scsi_scan_wq,
+-			   atomic_test_mask(ZFCP_STATUS_UNIT_SCSI_WORK_PENDING,
+-					    &unit->status) == 0);
+ 		atomic_clear_mask(ZFCP_STATUS_UNIT_REGISTERED, &unit->status);
+ 		sdpnt->hostdata = NULL;
+ 		unit->device = NULL;
+@@ -262,8 +258,9 @@ zfcp_scsi_command_async(struct zfcp_adapter *adapter, struct zfcp_unit *unit,
+ 		goto out;
+ 	}
+ 
+-	if (unlikely(
+-	     !atomic_test_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &unit->status))) {
++	tmp = zfcp_fsf_send_fcp_command_task(adapter, unit, scpnt, use_timer,
++					     ZFCP_REQ_AUTO_CLEANUP);
++	if (unlikely(tmp == -EBUSY)) {
+ 		ZFCP_LOG_DEBUG("adapter %s not ready or unit 0x%016Lx "
+ 			       "on port 0x%016Lx in recovery\n",
+ 			       zfcp_get_busid_by_unit(unit),
+@@ -272,9 +269,6 @@ zfcp_scsi_command_async(struct zfcp_adapter *adapter, struct zfcp_unit *unit,
+ 		goto out;
+ 	}
+ 
+-	tmp = zfcp_fsf_send_fcp_command_task(adapter, unit, scpnt, use_timer,
+-					     ZFCP_REQ_AUTO_CLEANUP);
 -
- 	return sprintf(buf, alias ? "1\n" : "0\n");
+ 	if (unlikely(tmp < 0)) {
+ 		ZFCP_LOG_DEBUG("error: initiation of Send FCP Cmnd failed\n");
+ 		retval = SCSI_MLQUEUE_HOST_BUSY;
+@@ -459,7 +453,9 @@ zfcp_scsi_eh_device_reset_handler(struct scsi_cmnd *scpnt)
+ 		retval = SUCCESS;
+ 		goto out;
+ 	}
+-	ZFCP_LOG_NORMAL("resetting unit 0x%016Lx\n", unit->fcp_lun);
++	ZFCP_LOG_NORMAL("resetting unit 0x%016Lx on port 0x%016Lx, adapter %s\n",
++			unit->fcp_lun, unit->port->wwpn,
++			zfcp_get_busid_by_adapter(unit->port->adapter));
+ 
+ 	/*
+ 	 * If we do not know whether the unit supports 'logical unit reset'
+@@ -542,7 +538,7 @@ zfcp_task_management_function(struct zfcp_unit *unit, u8 tm_flags,
  }
  
-@@ -930,19 +919,36 @@ static ssize_t
- dasd_uid_show(struct device *dev, struct device_attribute *attr, char *buf)
+ /**
+- * zfcp_scsi_eh_host_reset_handler - handler for host and bus reset
++ * zfcp_scsi_eh_host_reset_handler - handler for host reset
+  */
+ static int zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *scpnt)
  {
- 	struct dasd_devmap *devmap;
--	char uid[UID_STRLEN];
-+	char uid_string[UID_STRLEN];
-+	char ua_string[3];
-+	struct dasd_uid *uid;
+@@ -552,8 +548,10 @@ static int zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *scpnt)
+ 	unit = (struct zfcp_unit*) scpnt->device->hostdata;
+ 	adapter = unit->port->adapter;
  
- 	devmap = dasd_find_busid(dev->bus_id);
- 	spin_lock(&dasd_devmap_lock);
--	if (!IS_ERR(devmap) && strlen(devmap->uid.vendor) > 0)
--		snprintf(uid, sizeof(uid), "%s.%s.%04x.%02x",
--			 devmap->uid.vendor, devmap->uid.serial,
--			 devmap->uid.ssid, devmap->uid.unit_addr);
--	else
--		uid[0] = 0;
-+	if (IS_ERR(devmap) || strlen(devmap->uid.vendor) == 0) {
-+		spin_unlock(&dasd_devmap_lock);
-+		return sprintf(buf, "\n");
-+	}
-+	uid = &devmap->uid;
-+	switch (uid->type) {
-+	case UA_BASE_DEVICE:
-+		sprintf(ua_string, "%02x", uid->real_unit_addr);
-+		break;
-+	case UA_BASE_PAV_ALIAS:
-+		sprintf(ua_string, "%02x", uid->base_unit_addr);
-+		break;
-+	case UA_HYPER_PAV_ALIAS:
-+		sprintf(ua_string, "xx");
-+		break;
-+	default:
-+		/* should not happen, treat like base device */
-+		sprintf(ua_string, "%02x", uid->real_unit_addr);
-+		break;
-+	}
-+	snprintf(uid_string, sizeof(uid_string), "%s.%s.%04x.%s",
-+		 uid->vendor, uid->serial, uid->ssid, ua_string);
- 	spin_unlock(&dasd_devmap_lock);
+-	ZFCP_LOG_NORMAL("host/bus reset because of problems with "
+-			"unit 0x%016Lx\n", unit->fcp_lun);
++	ZFCP_LOG_NORMAL("host reset because of problems with "
++		"unit 0x%016Lx on port 0x%016Lx, adapter %s\n",
++		unit->fcp_lun, unit->port->wwpn,
++		zfcp_get_busid_by_adapter(unit->port->adapter));
+ 
+ 	zfcp_erp_adapter_reopen(adapter, 0);
+ 	zfcp_erp_wait(adapter);
+diff --git a/drivers/s390/scsi/zfcp_sysfs_driver.c b/drivers/s390/scsi/zfcp_sysfs_driver.c
+index 005e62f..651edd5 100644
+--- a/drivers/s390/scsi/zfcp_sysfs_driver.c
++++ b/drivers/s390/scsi/zfcp_sysfs_driver.c
+@@ -98,28 +98,9 @@ static struct attribute_group zfcp_driver_attr_group = {
+ 	.attrs = zfcp_driver_attrs,
+ };
+ 
+-/**
+- * zfcp_sysfs_create_driver_files - create sysfs driver files
+- * @dev: pointer to belonging device
+- *
+- * Create all sysfs attributes of the zfcp device driver
+- */
+-int
+-zfcp_sysfs_driver_create_files(struct device_driver *drv)
+-{
+-	return sysfs_create_group(&drv->kobj, &zfcp_driver_attr_group);
+-}
 -
--	return snprintf(buf, PAGE_SIZE, "%s\n", uid);
-+	return snprintf(buf, PAGE_SIZE, "%s\n", uid_string);
- }
+-/**
+- * zfcp_sysfs_remove_driver_files - remove sysfs driver files
+- * @dev: pointer to belonging device
+- *
+- * Remove all sysfs attributes of the zfcp device driver
+- */
+-void
+-zfcp_sysfs_driver_remove_files(struct device_driver *drv)
+-{
+-	sysfs_remove_group(&drv->kobj, &zfcp_driver_attr_group);
+-}
++struct attribute_group *zfcp_driver_attr_groups[] = {
++	&zfcp_driver_attr_group,
++	NULL,
++};
  
- static DEVICE_ATTR(uid, 0444, dasd_uid_show, NULL);
-@@ -1040,39 +1046,16 @@ int
- dasd_set_uid(struct ccw_device *cdev, struct dasd_uid *uid)
- {
- 	struct dasd_devmap *devmap;
--	struct dasd_server_ssid_map *srv, *tmp;
+ #undef ZFCP_LOG_AREA
+diff --git a/drivers/scsi/.gitignore b/drivers/scsi/.gitignore
+index b385af3..c89ae9a 100644
+--- a/drivers/scsi/.gitignore
++++ b/drivers/scsi/.gitignore
+@@ -1,3 +1 @@
+ 53c700_d.h
+-53c7xx_d.h
+-53c7xx_u.h
+diff --git a/drivers/scsi/3w-9xxx.c b/drivers/scsi/3w-9xxx.c
+index afb262b..1c24483 100644
+--- a/drivers/scsi/3w-9xxx.c
++++ b/drivers/scsi/3w-9xxx.c
+@@ -2010,6 +2010,7 @@ static int __devinit twa_probe(struct pci_dev *pdev, const struct pci_device_id
+ 	}
  
- 	devmap = dasd_find_busid(cdev->dev.bus_id);
- 	if (IS_ERR(devmap))
- 		return PTR_ERR(devmap);
+ 	pci_set_master(pdev);
++	pci_try_set_mwi(pdev);
  
--	/* generate entry for server_ssid_map */
--	srv = (struct dasd_server_ssid_map *)
--		kzalloc(sizeof(struct dasd_server_ssid_map), GFP_KERNEL);
--	if (!srv)
--		return -ENOMEM;
--	strncpy(srv->sid.vendor, uid->vendor, sizeof(srv->sid.vendor) - 1);
--	strncpy(srv->sid.serial, uid->serial, sizeof(srv->sid.serial) - 1);
--	srv->sid.ssid = uid->ssid;
+ 	if (pci_set_dma_mask(pdev, DMA_64BIT_MASK)
+ 	    || pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK))
+diff --git a/drivers/scsi/53c700.c b/drivers/scsi/53c700.c
+index 71ff3fb..f4c4fe9 100644
+--- a/drivers/scsi/53c700.c
++++ b/drivers/scsi/53c700.c
+@@ -608,7 +608,8 @@ NCR_700_scsi_done(struct NCR_700_Host_Parameters *hostdata,
+ 			scsi_print_sense("53c700", SCp);
+ 
+ #endif
+-			dma_unmap_single(hostdata->dev, slot->dma_handle, sizeof(SCp->sense_buffer), DMA_FROM_DEVICE);
++			dma_unmap_single(hostdata->dev, slot->dma_handle,
++					 SCSI_SENSE_BUFFERSIZE, DMA_FROM_DEVICE);
+ 			/* restore the old result if the request sense was
+ 			 * successful */
+ 			if (result == 0)
+@@ -1010,7 +1011,7 @@ process_script_interrupt(__u32 dsps, __u32 dsp, struct scsi_cmnd *SCp,
+ 				cmnd[1] = (SCp->device->lun & 0x7) << 5;
+ 				cmnd[2] = 0;
+ 				cmnd[3] = 0;
+-				cmnd[4] = sizeof(SCp->sense_buffer);
++				cmnd[4] = SCSI_SENSE_BUFFERSIZE;
+ 				cmnd[5] = 0;
+ 				/* Here's a quiet hack: the
+ 				 * REQUEST_SENSE command is six bytes,
+@@ -1024,14 +1025,14 @@ process_script_interrupt(__u32 dsps, __u32 dsp, struct scsi_cmnd *SCp,
+ 				SCp->cmd_len = 6; /* command length for
+ 						   * REQUEST_SENSE */
+ 				slot->pCmd = dma_map_single(hostdata->dev, cmnd, MAX_COMMAND_SIZE, DMA_TO_DEVICE);
+-				slot->dma_handle = dma_map_single(hostdata->dev, SCp->sense_buffer, sizeof(SCp->sense_buffer), DMA_FROM_DEVICE);
+-				slot->SG[0].ins = bS_to_host(SCRIPT_MOVE_DATA_IN | sizeof(SCp->sense_buffer));
++				slot->dma_handle = dma_map_single(hostdata->dev, SCp->sense_buffer, SCSI_SENSE_BUFFERSIZE, DMA_FROM_DEVICE);
++				slot->SG[0].ins = bS_to_host(SCRIPT_MOVE_DATA_IN | SCSI_SENSE_BUFFERSIZE);
+ 				slot->SG[0].pAddr = bS_to_host(slot->dma_handle);
+ 				slot->SG[1].ins = bS_to_host(SCRIPT_RETURN);
+ 				slot->SG[1].pAddr = 0;
+ 				slot->resume_offset = hostdata->pScript;
+ 				dma_cache_sync(hostdata->dev, slot->SG, sizeof(slot->SG[0])*2, DMA_TO_DEVICE);
+-				dma_cache_sync(hostdata->dev, SCp->sense_buffer, sizeof(SCp->sense_buffer), DMA_FROM_DEVICE);
++				dma_cache_sync(hostdata->dev, SCp->sense_buffer, SCSI_SENSE_BUFFERSIZE, DMA_FROM_DEVICE);
+ 
+ 				/* queue the command for reissue */
+ 				slot->state = NCR_700_SLOT_QUEUED;
+diff --git a/drivers/scsi/BusLogic.c b/drivers/scsi/BusLogic.c
+index 49e1ffa..ead47c1 100644
+--- a/drivers/scsi/BusLogic.c
++++ b/drivers/scsi/BusLogic.c
+@@ -2947,7 +2947,7 @@ static int BusLogic_QueueCommand(struct scsi_cmnd *Command, void (*CompletionRou
+ 		}
+ 	}
+ 	memcpy(CCB->CDB, CDB, CDB_Length);
+-	CCB->SenseDataLength = sizeof(Command->sense_buffer);
++	CCB->SenseDataLength = SCSI_SENSE_BUFFERSIZE;
+ 	CCB->SenseDataPointer = pci_map_single(HostAdapter->PCI_Device, Command->sense_buffer, CCB->SenseDataLength, PCI_DMA_FROMDEVICE);
+ 	CCB->Command = Command;
+ 	Command->scsi_done = CompletionRoutine;
+diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
+index 184c7ae..3e161cd 100644
+--- a/drivers/scsi/Kconfig
++++ b/drivers/scsi/Kconfig
+@@ -341,7 +341,7 @@ config ISCSI_TCP
+ 	 The userspace component needed to initialize the driver, documentation,
+ 	 and sample configuration files can be found here:
+ 
+-	 http://linux-iscsi.sf.net
++	 http://open-iscsi.org
+ 
+ config SGIWD93_SCSI
+ 	tristate "SGI WD93C93 SCSI Driver"
+@@ -573,10 +573,10 @@ config SCSI_ARCMSR_AER
+ source "drivers/scsi/megaraid/Kconfig.megaraid"
+ 
+ config SCSI_HPTIOP
+-	tristate "HighPoint RocketRAID 3xxx Controller support"
++	tristate "HighPoint RocketRAID 3xxx/4xxx Controller support"
+ 	depends on SCSI && PCI
+ 	help
+-	  This option enables support for HighPoint RocketRAID 3xxx
++	  This option enables support for HighPoint RocketRAID 3xxx/4xxx
+ 	  controllers.
+ 
+ 	  To compile this driver as a module, choose M here; the module
+@@ -1288,17 +1288,6 @@ config SCSI_PAS16
+ 	  To compile this driver as a module, choose M here: the
+ 	  module will be called pas16.
+ 
+-config SCSI_PSI240I
+-	tristate "PSI240i support"
+-	depends on ISA && SCSI
+-	help
+-	  This is support for the PSI240i EIDE interface card which acts as a
+-	  SCSI host adapter.  Please read the SCSI-HOWTO, available from
+-	  <http://www.tldp.org/docs.html#howto>.
 -
--	/* server is already contained ? */
- 	spin_lock(&dasd_devmap_lock);
- 	devmap->uid = *uid;
--	list_for_each_entry(tmp, &dasd_server_ssid_list, list) {
--		if (!memcmp(&srv->sid, &tmp->sid,
--			    sizeof(struct system_id))) {
--			kfree(srv);
--			srv = NULL;
--			break;
--		}
--	}
+-	  To compile this driver as a module, choose M here: the
+-	  module will be called psi240i.
 -
--	/* add servermap to serverlist */
--	if (srv)
--		list_add(&srv->list, &dasd_server_ssid_list);
- 	spin_unlock(&dasd_devmap_lock);
- 
--	return (srv ? 1 : 0);
-+	return 0;
- }
- EXPORT_SYMBOL_GPL(dasd_set_uid);
+ config SCSI_QLOGIC_FAS
+ 	tristate "Qlogic FAS SCSI support"
+ 	depends on ISA && SCSI
+@@ -1359,21 +1348,6 @@ config SCSI_LPFC
+           This lpfc driver supports the Emulex LightPulse
+           Family of Fibre Channel PCI host adapters.
  
-@@ -1138,9 +1121,6 @@ dasd_devmap_init(void)
- 	dasd_max_devindex = 0;
- 	for (i = 0; i < 256; i++)
- 		INIT_LIST_HEAD(&dasd_hashlists[i]);
+-config SCSI_SEAGATE
+-	tristate "Seagate ST-02 and Future Domain TMC-8xx SCSI support"
+-	depends on X86 && ISA && SCSI
+-	select CHECK_SIGNATURE
+-	---help---
+-	  These are 8-bit SCSI controllers; the ST-01 is also supported by
+-	  this driver.  It is explained in section 3.9 of the SCSI-HOWTO,
+-	  available from <http://www.tldp.org/docs.html#howto>.  If it
+-	  doesn't work out of the box, you may have to change some macros at
+-	  compiletime, which are described in <file:drivers/scsi/seagate.c>.
 -
--	/* Initialize servermap structure. */
--	INIT_LIST_HEAD(&dasd_server_ssid_list);
- 	return 0;
+-	  To compile this driver as a module, choose M here: the
+-	  module will be called seagate.
+-
+-# definitely looks not 64bit safe:
+ config SCSI_SIM710
+ 	tristate "Simple 53c710 SCSI support (Compaq, NCR machines)"
+ 	depends on (EISA || MCA) && SCSI
+diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
+index 2e6129f..93e1428 100644
+--- a/drivers/scsi/Makefile
++++ b/drivers/scsi/Makefile
+@@ -16,9 +16,8 @@
+ 
+ CFLAGS_aha152x.o =   -DAHA152X_STAT -DAUTOCONF
+ CFLAGS_gdth.o    = # -DDEBUG_GDTH=2 -D__SERIAL__ -D__COM2__ -DGDTH_STATISTICS
+-CFLAGS_seagate.o =   -DARBITRATE -DPARITY -DSEAGATE_USE_ASM
+ 
+-subdir-$(CONFIG_PCMCIA)		+= pcmcia
++obj-$(CONFIG_PCMCIA)		+= pcmcia/
+ 
+ obj-$(CONFIG_SCSI)		+= scsi_mod.o
+ obj-$(CONFIG_SCSI_TGT)		+= scsi_tgt.o
+@@ -59,7 +58,6 @@ obj-$(CONFIG_MVME16x_SCSI)	+= 53c700.o	mvme16x_scsi.o
+ obj-$(CONFIG_BVME6000_SCSI)	+= 53c700.o	bvme6000_scsi.o
+ obj-$(CONFIG_SCSI_SIM710)	+= 53c700.o	sim710.o
+ obj-$(CONFIG_SCSI_ADVANSYS)	+= advansys.o
+-obj-$(CONFIG_SCSI_PSI240I)	+= psi240i.o
+ obj-$(CONFIG_SCSI_BUSLOGIC)	+= BusLogic.o
+ obj-$(CONFIG_SCSI_DPT_I2O)	+= dpt_i2o.o
+ obj-$(CONFIG_SCSI_U14_34F)	+= u14-34f.o
+@@ -90,7 +88,6 @@ obj-$(CONFIG_SCSI_QLA_FC)	+= qla2xxx/
+ obj-$(CONFIG_SCSI_QLA_ISCSI)	+= qla4xxx/
+ obj-$(CONFIG_SCSI_LPFC)		+= lpfc/
+ obj-$(CONFIG_SCSI_PAS16)	+= pas16.o
+-obj-$(CONFIG_SCSI_SEAGATE)	+= seagate.o
+ obj-$(CONFIG_SCSI_T128)		+= t128.o
+ obj-$(CONFIG_SCSI_DMX3191D)	+= dmx3191d.o
+ obj-$(CONFIG_SCSI_DTC3280)	+= dtc.o
+diff --git a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c
+index 2597209..eeddbd1 100644
+--- a/drivers/scsi/NCR5380.c
++++ b/drivers/scsi/NCR5380.c
+@@ -295,16 +295,16 @@ static __inline__ void initialize_SCp(Scsi_Cmnd * cmd)
+ 	 * various queues are valid.
+ 	 */
+ 
+-	if (cmd->use_sg) {
+-		cmd->SCp.buffer = (struct scatterlist *) cmd->request_buffer;
+-		cmd->SCp.buffers_residual = cmd->use_sg - 1;
++	if (scsi_bufflen(cmd)) {
++		cmd->SCp.buffer = scsi_sglist(cmd);
++		cmd->SCp.buffers_residual = scsi_sg_count(cmd) - 1;
+ 		cmd->SCp.ptr = sg_virt(cmd->SCp.buffer);
+ 		cmd->SCp.this_residual = cmd->SCp.buffer->length;
+ 	} else {
+ 		cmd->SCp.buffer = NULL;
+ 		cmd->SCp.buffers_residual = 0;
+-		cmd->SCp.ptr = (char *) cmd->request_buffer;
+-		cmd->SCp.this_residual = cmd->request_bufflen;
++		cmd->SCp.ptr = NULL;
++		cmd->SCp.this_residual = 0;
+ 	}
  }
  
-diff --git a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c
-index 571320a..d91df38 100644
---- a/drivers/s390/block/dasd_diag.c
-+++ b/drivers/s390/block/dasd_diag.c
-@@ -142,7 +142,7 @@ dasd_diag_erp(struct dasd_device *device)
- 	int rc;
+@@ -932,7 +932,7 @@ static int __devinit NCR5380_init(struct Scsi_Host *instance, int flags)
+  *	@instance: adapter to remove
+  */
  
- 	mdsk_term_io(device);
--	rc = mdsk_init_io(device, device->bp_block, 0, NULL);
-+	rc = mdsk_init_io(device, device->block->bp_block, 0, NULL);
- 	if (rc)
- 		DEV_MESSAGE(KERN_WARNING, device, "DIAG ERP unsuccessful, "
- 			    "rc=%d", rc);
-@@ -158,11 +158,11 @@ dasd_start_diag(struct dasd_ccw_req * cqr)
- 	struct dasd_diag_req *dreq;
- 	int rc;
+-static void __devexit NCR5380_exit(struct Scsi_Host *instance)
++static void NCR5380_exit(struct Scsi_Host *instance)
+ {
+ 	struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata;
  
--	device = cqr->device;
-+	device = cqr->startdev;
- 	if (cqr->retries < 0) {
- 		DEV_MESSAGE(KERN_WARNING, device, "DIAG start_IO: request %p "
- 			    "- no retry left)", cqr);
--		cqr->status = DASD_CQR_FAILED;
-+		cqr->status = DASD_CQR_ERROR;
- 		return -EIO;
+@@ -975,14 +975,14 @@ static int NCR5380_queue_command(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
+ 		case WRITE_6:
+ 		case WRITE_10:
+ 			hostdata->time_write[cmd->device->id] -= (jiffies - hostdata->timebase);
+-			hostdata->bytes_write[cmd->device->id] += cmd->request_bufflen;
++			hostdata->bytes_write[cmd->device->id] += scsi_bufflen(cmd);
+ 			hostdata->pendingw++;
+ 			break;
+ 		case READ:
+ 		case READ_6:
+ 		case READ_10:
+ 			hostdata->time_read[cmd->device->id] -= (jiffies - hostdata->timebase);
+-			hostdata->bytes_read[cmd->device->id] += cmd->request_bufflen;
++			hostdata->bytes_read[cmd->device->id] += scsi_bufflen(cmd);
+ 			hostdata->pendingr++;
+ 			break;
  	}
- 	private = (struct dasd_diag_private *) device->private;
-@@ -184,7 +184,7 @@ dasd_start_diag(struct dasd_ccw_req * cqr)
- 	switch (rc) {
- 	case 0: /* Synchronous I/O finished successfully */
- 		cqr->stopclk = get_clock();
--		cqr->status = DASD_CQR_DONE;
-+		cqr->status = DASD_CQR_SUCCESS;
- 		/* Indicate to calling function that only a dasd_schedule_bh()
- 		   and no timer is needed */
-                 rc = -EACCES;
-@@ -209,12 +209,12 @@ dasd_diag_term_IO(struct dasd_ccw_req * cqr)
- {
- 	struct dasd_device *device;
+@@ -1157,16 +1157,17 @@ static void NCR5380_main(struct work_struct *work)
+  *	Locks: takes the needed instance locks
+  */
  
--	device = cqr->device;
-+	device = cqr->startdev;
- 	mdsk_term_io(device);
--	mdsk_init_io(device, device->bp_block, 0, NULL);
--	cqr->status = DASD_CQR_CLEAR;
-+	mdsk_init_io(device, device->block->bp_block, 0, NULL);
-+	cqr->status = DASD_CQR_CLEAR_PENDING;
- 	cqr->stopclk = get_clock();
--	dasd_schedule_bh(device);
-+	dasd_schedule_device_bh(device);
- 	return 0;
- }
+-static irqreturn_t NCR5380_intr(int irq, void *dev_id) 
++static irqreturn_t NCR5380_intr(int dummy, void *dev_id)
+ {
+ 	NCR5380_local_declare();
+-	struct Scsi_Host *instance = (struct Scsi_Host *)dev_id;
++	struct Scsi_Host *instance = dev_id;
+ 	struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata;
+ 	int done;
+ 	unsigned char basr;
+ 	unsigned long flags;
  
-@@ -247,7 +247,7 @@ dasd_ext_handler(__u16 code)
- 		return;
- 	}
- 	cqr = (struct dasd_ccw_req *) ip;
--	device = (struct dasd_device *) cqr->device;
-+	device = (struct dasd_device *) cqr->startdev;
- 	if (strncmp(device->discipline->ebcname, (char *) &cqr->magic, 4)) {
- 		DEV_MESSAGE(KERN_WARNING, device,
- 			    " magic number of dasd_ccw_req 0x%08X doesn't"
-@@ -260,10 +260,10 @@ dasd_ext_handler(__u16 code)
- 	spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
+-	dprintk(NDEBUG_INTR, ("scsi : NCR5380 irq %d triggered\n", irq));
++	dprintk(NDEBUG_INTR, ("scsi : NCR5380 irq %d triggered\n",
++		instance->irq));
  
- 	/* Check for a pending clear operation */
--	if (cqr->status == DASD_CQR_CLEAR) {
--		cqr->status = DASD_CQR_QUEUED;
--		dasd_clear_timer(device);
--		dasd_schedule_bh(device);
-+	if (cqr->status == DASD_CQR_CLEAR_PENDING) {
-+		cqr->status = DASD_CQR_CLEARED;
-+		dasd_device_clear_timer(device);
-+		dasd_schedule_device_bh(device);
- 		spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
- 		return;
+ 	do {
+ 		done = 1;
+diff --git a/drivers/scsi/a2091.c b/drivers/scsi/a2091.c
+index b7c5385..23f27c9 100644
+--- a/drivers/scsi/a2091.c
++++ b/drivers/scsi/a2091.c
+@@ -73,18 +73,9 @@ static int dma_setup(struct scsi_cmnd *cmd, int dir_in)
  	}
-@@ -272,11 +272,11 @@ dasd_ext_handler(__u16 code)
  
- 	expires = 0;
- 	if (status == 0) {
--		cqr->status = DASD_CQR_DONE;
-+		cqr->status = DASD_CQR_SUCCESS;
- 		/* Start first request on queue if possible -> fast_io. */
- 		if (!list_empty(&device->ccw_queue)) {
- 			next = list_entry(device->ccw_queue.next,
--					  struct dasd_ccw_req, list);
-+					  struct dasd_ccw_req, devlist);
- 			if (next->status == DASD_CQR_QUEUED) {
- 				rc = dasd_start_diag(next);
- 				if (rc == 0)
-@@ -296,10 +296,10 @@ dasd_ext_handler(__u16 code)
+ 	if (!dir_in) {
+-	    /* copy to bounce buffer for a write */
+-	    if (cmd->use_sg)
+-#if 0
+-		panic ("scsi%ddma: incomplete s/g support",
+-		       instance->host_no);
+-#else
++		/* copy to bounce buffer for a write */
+ 		memcpy (HDATA(instance)->dma_bounce_buffer,
+ 			cmd->SCp.ptr, cmd->SCp.this_residual);
+-#endif
+-	    else
+-		memcpy (HDATA(instance)->dma_bounce_buffer,
+-			cmd->request_buffer, cmd->request_bufflen);
  	}
+     }
  
- 	if (expires != 0)
--		dasd_set_timer(device, expires);
-+		dasd_device_set_timer(device, expires);
- 	else
--		dasd_clear_timer(device);
--	dasd_schedule_bh(device);
-+		dasd_device_clear_timer(device);
-+	dasd_schedule_device_bh(device);
+@@ -144,30 +135,13 @@ static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt,
  
- 	spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
- }
-@@ -309,6 +309,7 @@ dasd_ext_handler(__u16 code)
- static int
- dasd_diag_check_device(struct dasd_device *device)
- {
-+	struct dasd_block *block;
- 	struct dasd_diag_private *private;
- 	struct dasd_diag_characteristics *rdc_data;
- 	struct dasd_diag_bio bio;
-@@ -328,6 +329,16 @@ dasd_diag_check_device(struct dasd_device *device)
- 		ccw_device_get_id(device->cdev, &private->dev_id);
- 		device->private = (void *) private;
- 	}
-+	block = dasd_alloc_block();
-+	if (IS_ERR(block)) {
-+		DEV_MESSAGE(KERN_WARNING, device, "%s",
-+			    "could not allocate dasd block structure");
-+		kfree(device->private);
-+		return PTR_ERR(block);
-+	}
-+	device->block = block;
-+	block->base = device;
-+
- 	/* Read Device Characteristics */
- 	rdc_data = (void *) &(private->rdc_data);
- 	rdc_data->dev_nr = private->dev_id.devno;
-@@ -409,14 +420,14 @@ dasd_diag_check_device(struct dasd_device *device)
- 		  sizeof(DASD_DIAG_CMS1)) == 0) {
- 		/* get formatted blocksize from label block */
- 		bsize = (unsigned int) label->block_size;
--		device->blocks = (unsigned long) label->block_count;
-+		block->blocks = (unsigned long) label->block_count;
- 	} else
--		device->blocks = end_block;
--	device->bp_block = bsize;
--	device->s2b_shift = 0;	/* bits to shift 512 to get a block */
-+		block->blocks = end_block;
-+	block->bp_block = bsize;
-+	block->s2b_shift = 0;	/* bits to shift 512 to get a block */
- 	for (sb = 512; sb < bsize; sb = sb << 1)
--		device->s2b_shift++;
--	rc = mdsk_init_io(device, device->bp_block, 0, NULL);
-+		block->s2b_shift++;
-+	rc = mdsk_init_io(device, block->bp_block, 0, NULL);
- 	if (rc) {
- 		DEV_MESSAGE(KERN_WARNING, device, "DIAG initialization "
- 			"failed (rc=%d)", rc);
-@@ -424,9 +435,9 @@ dasd_diag_check_device(struct dasd_device *device)
- 	} else {
- 		DEV_MESSAGE(KERN_INFO, device,
- 			    "(%ld B/blk): %ldkB",
--			    (unsigned long) device->bp_block,
--			    (unsigned long) (device->blocks <<
--				device->s2b_shift) >> 1);
-+			    (unsigned long) block->bp_block,
-+			    (unsigned long) (block->blocks <<
-+				block->s2b_shift) >> 1);
- 	}
- out:
- 	free_page((long) label);
-@@ -436,22 +447,16 @@ out:
- /* Fill in virtual disk geometry for device. Return zero on success, non-zero
-  * otherwise. */
- static int
--dasd_diag_fill_geometry(struct dasd_device *device, struct hd_geometry *geo)
-+dasd_diag_fill_geometry(struct dasd_block *block, struct hd_geometry *geo)
- {
--	if (dasd_check_blocksize(device->bp_block) != 0)
-+	if (dasd_check_blocksize(block->bp_block) != 0)
- 		return -EINVAL;
--	geo->cylinders = (device->blocks << device->s2b_shift) >> 10;
-+	geo->cylinders = (block->blocks << block->s2b_shift) >> 10;
- 	geo->heads = 16;
--	geo->sectors = 128 >> device->s2b_shift;
-+	geo->sectors = 128 >> block->s2b_shift;
- 	return 0;
+     /* copy from a bounce buffer, if necessary */
+     if (status && HDATA(instance)->dma_bounce_buffer) {
+-	if (SCpnt && SCpnt->use_sg) {
+-#if 0
+-	    panic ("scsi%d: incomplete s/g support",
+-		   instance->host_no);
+-#else
+-	    if( HDATA(instance)->dma_dir )
++	if( HDATA(instance)->dma_dir )
+ 		memcpy (SCpnt->SCp.ptr, 
+ 			HDATA(instance)->dma_bounce_buffer,
+ 			SCpnt->SCp.this_residual);
+-	    kfree (HDATA(instance)->dma_bounce_buffer);
+-	    HDATA(instance)->dma_bounce_buffer = NULL;
+-	    HDATA(instance)->dma_bounce_len = 0;
+-	    
+-#endif
+-	} else {
+-	    if (HDATA(instance)->dma_dir && SCpnt)
+-		memcpy (SCpnt->request_buffer,
+-			HDATA(instance)->dma_bounce_buffer,
+-			SCpnt->request_bufflen);
+-
+-	    kfree (HDATA(instance)->dma_bounce_buffer);
+-	    HDATA(instance)->dma_bounce_buffer = NULL;
+-	    HDATA(instance)->dma_bounce_len = 0;
+-	}
++	kfree (HDATA(instance)->dma_bounce_buffer);
++	HDATA(instance)->dma_bounce_buffer = NULL;
++	HDATA(instance)->dma_bounce_len = 0;
+     }
  }
  
--static dasd_era_t
--dasd_diag_examine_error(struct dasd_ccw_req * cqr, struct irb * stat)
--{
--	return dasd_era_fatal;
--}
--
- static dasd_erp_fn_t
- dasd_diag_erp_action(struct dasd_ccw_req * cqr)
- {
-@@ -466,8 +471,9 @@ dasd_diag_erp_postaction(struct dasd_ccw_req * cqr)
+diff --git a/drivers/scsi/a3000.c b/drivers/scsi/a3000.c
+index 796f1c4..d7255c8 100644
+--- a/drivers/scsi/a3000.c
++++ b/drivers/scsi/a3000.c
+@@ -70,12 +70,8 @@ static int dma_setup(struct scsi_cmnd *cmd, int dir_in)
  
- /* Create DASD request from block device request. Return pointer to new
-  * request on success, ERR_PTR otherwise. */
--static struct dasd_ccw_req *
--dasd_diag_build_cp(struct dasd_device * device, struct request *req)
-+static struct dasd_ccw_req *dasd_diag_build_cp(struct dasd_device *memdev,
-+					       struct dasd_block *block,
-+					       struct request *req)
- {
- 	struct dasd_ccw_req *cqr;
- 	struct dasd_diag_req *dreq;
-@@ -486,17 +492,17 @@ dasd_diag_build_cp(struct dasd_device * device, struct request *req)
- 		rw_cmd = MDSK_WRITE_REQ;
- 	else
- 		return ERR_PTR(-EINVAL);
--	blksize = device->bp_block;
-+	blksize = block->bp_block;
- 	/* Calculate record id of first and last block. */
--	first_rec = req->sector >> device->s2b_shift;
--	last_rec = (req->sector + req->nr_sectors - 1) >> device->s2b_shift;
-+	first_rec = req->sector >> block->s2b_shift;
-+	last_rec = (req->sector + req->nr_sectors - 1) >> block->s2b_shift;
- 	/* Check struct bio and count the number of blocks for the request. */
- 	count = 0;
- 	rq_for_each_segment(bv, req, iter) {
- 		if (bv->bv_len & (blksize - 1))
- 			/* Fba can only do full blocks. */
- 			return ERR_PTR(-EINVAL);
--		count += bv->bv_len >> (device->s2b_shift + 9);
-+		count += bv->bv_len >> (block->s2b_shift + 9);
+ 	if (!dir_in) {
+ 	    /* copy to bounce buffer for a write */
+-	    if (cmd->use_sg) {
+-		memcpy (HDATA(a3000_host)->dma_bounce_buffer,
+-			cmd->SCp.ptr, cmd->SCp.this_residual);
+-	    } else
+-		memcpy (HDATA(a3000_host)->dma_bounce_buffer,
+-			cmd->request_buffer, cmd->request_bufflen);
++	    memcpy (HDATA(a3000_host)->dma_bounce_buffer,
++		cmd->SCp.ptr, cmd->SCp.this_residual);
  	}
- 	/* Paranoia. */
- 	if (count != last_rec - first_rec + 1)
-@@ -505,7 +511,7 @@ dasd_diag_build_cp(struct dasd_device * device, struct request *req)
- 	datasize = sizeof(struct dasd_diag_req) +
- 		count*sizeof(struct dasd_diag_bio);
- 	cqr = dasd_smalloc_request(dasd_diag_discipline.name, 0,
--				   datasize, device);
-+				   datasize, memdev);
- 	if (IS_ERR(cqr))
- 		return cqr;
- 
-@@ -529,7 +535,9 @@ dasd_diag_build_cp(struct dasd_device * device, struct request *req)
- 	cqr->buildclk = get_clock();
- 	if (req->cmd_flags & REQ_FAILFAST)
- 		set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags);
--	cqr->device = device;
-+	cqr->startdev = memdev;
-+	cqr->memdev = memdev;
-+	cqr->block = block;
- 	cqr->expires = DIAG_TIMEOUT;
- 	cqr->status = DASD_CQR_FILLED;
- 	return cqr;
-@@ -543,10 +551,15 @@ dasd_diag_free_cp(struct dasd_ccw_req *cqr, struct request *req)
- 	int status;
- 
- 	status = cqr->status == DASD_CQR_DONE;
--	dasd_sfree_request(cqr, cqr->device);
-+	dasd_sfree_request(cqr, cqr->memdev);
- 	return status;
- }
- 
-+static void dasd_diag_handle_terminated_request(struct dasd_ccw_req *cqr)
-+{
-+	cqr->status = DASD_CQR_FILLED;
-+};
-+
- /* Fill in IOCTL data for device. */
- static int
- dasd_diag_fill_info(struct dasd_device * device,
-@@ -583,7 +596,7 @@ static struct dasd_discipline dasd_diag_discipline = {
- 	.fill_geometry = dasd_diag_fill_geometry,
- 	.start_IO = dasd_start_diag,
- 	.term_IO = dasd_diag_term_IO,
--	.examine_error = dasd_diag_examine_error,
-+	.handle_terminated_request = dasd_diag_handle_terminated_request,
- 	.erp_action = dasd_diag_erp_action,
- 	.erp_postaction = dasd_diag_erp_postaction,
- 	.build_cp = dasd_diag_build_cp,
-diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c
-index 44adf84..61f1693 100644
---- a/drivers/s390/block/dasd_eckd.c
-+++ b/drivers/s390/block/dasd_eckd.c
-@@ -52,16 +52,6 @@ MODULE_LICENSE("GPL");
  
- static struct dasd_discipline dasd_eckd_discipline;
+ 	addr = virt_to_bus(HDATA(a3000_host)->dma_bounce_buffer);
+@@ -146,7 +142,7 @@ static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt,
  
--struct dasd_eckd_private {
--	struct dasd_eckd_characteristics rdc_data;
--	struct dasd_eckd_confdata conf_data;
--	struct dasd_eckd_path path_data;
--	struct eckd_count count_area[5];
--	int init_cqr_status;
--	int uses_cdl;
--	struct attrib_data_t attrib;	/* e.g. cache operations */
--};
+     /* copy from a bounce buffer, if necessary */
+     if (status && HDATA(instance)->dma_bounce_buffer) {
+-	if (SCpnt && SCpnt->use_sg) {
++	if (SCpnt) {
+ 	    if (HDATA(instance)->dma_dir && SCpnt)
+ 		memcpy (SCpnt->SCp.ptr,
+ 			HDATA(instance)->dma_bounce_buffer,
+@@ -155,11 +151,6 @@ static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt,
+ 	    HDATA(instance)->dma_bounce_buffer = NULL;
+ 	    HDATA(instance)->dma_bounce_len = 0;
+ 	} else {
+-	    if (HDATA(instance)->dma_dir && SCpnt)
+-		memcpy (SCpnt->request_buffer,
+-			HDATA(instance)->dma_bounce_buffer,
+-			SCpnt->request_bufflen);
 -
- /* The ccw bus type uses this table to find devices that it sends to
-  * dasd_eckd_probe */
- static struct ccw_device_id dasd_eckd_ids[] = {
-@@ -188,7 +178,7 @@ check_XRC (struct ccw1         *de_ccw,
- 	if (rc == -ENOSYS || rc == -EACCES)
- 		rc = 0;
- 
--	de_ccw->count = sizeof (struct DE_eckd_data);
-+	de_ccw->count = sizeof(struct DE_eckd_data);
- 	de_ccw->flags |= CCW_FLAG_SLI;
- 	return rc;
- }
-@@ -208,7 +198,7 @@ define_extent(struct ccw1 * ccw, struct DE_eckd_data * data, int trk,
- 	ccw->count = 16;
- 	ccw->cda = (__u32) __pa(data);
- 
--	memset(data, 0, sizeof (struct DE_eckd_data));
-+	memset(data, 0, sizeof(struct DE_eckd_data));
- 	switch (cmd) {
- 	case DASD_ECKD_CCW_READ_HOME_ADDRESS:
- 	case DASD_ECKD_CCW_READ_RECORD_ZERO:
-@@ -280,6 +270,132 @@ define_extent(struct ccw1 * ccw, struct DE_eckd_data * data, int trk,
- 	return rc;
- }
+ 	    kfree (HDATA(instance)->dma_bounce_buffer);
+ 	    HDATA(instance)->dma_bounce_buffer = NULL;
+ 	    HDATA(instance)->dma_bounce_len = 0;
+diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c
+index a77ab8d..d7235f4 100644
+--- a/drivers/scsi/aacraid/aachba.c
++++ b/drivers/scsi/aacraid/aachba.c
+@@ -31,9 +31,9 @@
+ #include <linux/slab.h>
+ #include <linux/completion.h>
+ #include <linux/blkdev.h>
+-#include <linux/dma-mapping.h>
+ #include <asm/semaphore.h>
+ #include <asm/uaccess.h>
++#include <linux/highmem.h> /* For flush_kernel_dcache_page */
  
-+static int check_XRC_on_prefix(struct PFX_eckd_data *pfxdata,
-+			       struct dasd_device  *device)
-+{
-+	struct dasd_eckd_private *private;
-+	int rc;
-+
-+	private = (struct dasd_eckd_private *) device->private;
-+	if (!private->rdc_data.facilities.XRC_supported)
-+		return 0;
-+
-+	/* switch on System Time Stamp - needed for XRC Support */
-+	pfxdata->define_extend.ga_extended |= 0x08; /* 'Time Stamp Valid'   */
-+	pfxdata->define_extend.ga_extended |= 0x02; /* 'Extended Parameter' */
-+	pfxdata->validity.time_stamp = 1;	    /* 'Time Stamp Valid'   */
-+
-+	rc = get_sync_clock(&pfxdata->define_extend.ep_sys_time);
-+	/* Ignore return code if sync clock is switched off. */
-+	if (rc == -ENOSYS || rc == -EACCES)
-+		rc = 0;
-+	return rc;
-+}
-+
-+static int prefix(struct ccw1 *ccw, struct PFX_eckd_data *pfxdata, int trk,
-+		  int totrk, int cmd, struct dasd_device *basedev,
-+		  struct dasd_device *startdev)
-+{
-+	struct dasd_eckd_private *basepriv, *startpriv;
-+	struct DE_eckd_data *data;
-+	struct ch_t geo, beg, end;
-+	int rc = 0;
-+
-+	basepriv = (struct dasd_eckd_private *) basedev->private;
-+	startpriv = (struct dasd_eckd_private *) startdev->private;
-+	data = &pfxdata->define_extend;
-+
-+	ccw->cmd_code = DASD_ECKD_CCW_PFX;
-+	ccw->flags = 0;
-+	ccw->count = sizeof(*pfxdata);
-+	ccw->cda = (__u32) __pa(pfxdata);
-+
-+	memset(pfxdata, 0, sizeof(*pfxdata));
-+	/* prefix data */
-+	pfxdata->format = 0;
-+	pfxdata->base_address = basepriv->conf_data.ned1.unit_addr;
-+	pfxdata->base_lss = basepriv->conf_data.ned1.ID;
-+	pfxdata->validity.define_extend = 1;
-+
-+	/* private uid is kept up to date, conf_data may be outdated */
-+	if (startpriv->uid.type != UA_BASE_DEVICE) {
-+		pfxdata->validity.verify_base = 1;
-+		if (startpriv->uid.type == UA_HYPER_PAV_ALIAS)
-+			pfxdata->validity.hyper_pav = 1;
-+	}
-+
-+	/* define extend data (mostly)*/
-+	switch (cmd) {
-+	case DASD_ECKD_CCW_READ_HOME_ADDRESS:
-+	case DASD_ECKD_CCW_READ_RECORD_ZERO:
-+	case DASD_ECKD_CCW_READ:
-+	case DASD_ECKD_CCW_READ_MT:
-+	case DASD_ECKD_CCW_READ_CKD:
-+	case DASD_ECKD_CCW_READ_CKD_MT:
-+	case DASD_ECKD_CCW_READ_KD:
-+	case DASD_ECKD_CCW_READ_KD_MT:
-+	case DASD_ECKD_CCW_READ_COUNT:
-+		data->mask.perm = 0x1;
-+		data->attributes.operation = basepriv->attrib.operation;
-+		break;
-+	case DASD_ECKD_CCW_WRITE:
-+	case DASD_ECKD_CCW_WRITE_MT:
-+	case DASD_ECKD_CCW_WRITE_KD:
-+	case DASD_ECKD_CCW_WRITE_KD_MT:
-+		data->mask.perm = 0x02;
-+		data->attributes.operation = basepriv->attrib.operation;
-+		rc = check_XRC_on_prefix(pfxdata, basedev);
-+		break;
-+	case DASD_ECKD_CCW_WRITE_CKD:
-+	case DASD_ECKD_CCW_WRITE_CKD_MT:
-+		data->attributes.operation = DASD_BYPASS_CACHE;
-+		rc = check_XRC_on_prefix(pfxdata, basedev);
-+		break;
-+	case DASD_ECKD_CCW_ERASE:
-+	case DASD_ECKD_CCW_WRITE_HOME_ADDRESS:
-+	case DASD_ECKD_CCW_WRITE_RECORD_ZERO:
-+		data->mask.perm = 0x3;
-+		data->mask.auth = 0x1;
-+		data->attributes.operation = DASD_BYPASS_CACHE;
-+		rc = check_XRC_on_prefix(pfxdata, basedev);
-+		break;
-+	default:
-+		DEV_MESSAGE(KERN_ERR, basedev, "unknown opcode 0x%x", cmd);
-+		break;
-+	}
-+
-+	data->attributes.mode = 0x3;	/* ECKD */
-+
-+	if ((basepriv->rdc_data.cu_type == 0x2105 ||
-+	     basepriv->rdc_data.cu_type == 0x2107 ||
-+	     basepriv->rdc_data.cu_type == 0x1750)
-+	    && !(basepriv->uses_cdl && trk < 2))
-+		data->ga_extended |= 0x40; /* Regular Data Format Mode */
-+
-+	geo.cyl = basepriv->rdc_data.no_cyl;
-+	geo.head = basepriv->rdc_data.trk_per_cyl;
-+	beg.cyl = trk / geo.head;
-+	beg.head = trk % geo.head;
-+	end.cyl = totrk / geo.head;
-+	end.head = totrk % geo.head;
+ #include <scsi/scsi.h>
+ #include <scsi/scsi_cmnd.h>
+@@ -56,54 +56,54 @@
+ /*
+  *	Sense codes
+  */
+- 
+-#define SENCODE_NO_SENSE                        0x00
+-#define SENCODE_END_OF_DATA                     0x00
+-#define SENCODE_BECOMING_READY                  0x04
+-#define SENCODE_INIT_CMD_REQUIRED               0x04
+-#define SENCODE_PARAM_LIST_LENGTH_ERROR         0x1A
+-#define SENCODE_INVALID_COMMAND                 0x20
+-#define SENCODE_LBA_OUT_OF_RANGE                0x21
+-#define SENCODE_INVALID_CDB_FIELD               0x24
+-#define SENCODE_LUN_NOT_SUPPORTED               0x25
+-#define SENCODE_INVALID_PARAM_FIELD             0x26
+-#define SENCODE_PARAM_NOT_SUPPORTED             0x26
+-#define SENCODE_PARAM_VALUE_INVALID             0x26
+-#define SENCODE_RESET_OCCURRED                  0x29
+-#define SENCODE_LUN_NOT_SELF_CONFIGURED_YET     0x3E
+-#define SENCODE_INQUIRY_DATA_CHANGED            0x3F
+-#define SENCODE_SAVING_PARAMS_NOT_SUPPORTED     0x39
+-#define SENCODE_DIAGNOSTIC_FAILURE              0x40
+-#define SENCODE_INTERNAL_TARGET_FAILURE         0x44
+-#define SENCODE_INVALID_MESSAGE_ERROR           0x49
+-#define SENCODE_LUN_FAILED_SELF_CONFIG          0x4c
+-#define SENCODE_OVERLAPPED_COMMAND              0x4E
 +
-+	/* check for sequential prestage - enhance cylinder range */
-+	if (data->attributes.operation == DASD_SEQ_PRESTAGE ||
-+	    data->attributes.operation == DASD_SEQ_ACCESS) {
++#define SENCODE_NO_SENSE			0x00
++#define SENCODE_END_OF_DATA			0x00
++#define SENCODE_BECOMING_READY			0x04
++#define SENCODE_INIT_CMD_REQUIRED		0x04
++#define SENCODE_PARAM_LIST_LENGTH_ERROR		0x1A
++#define SENCODE_INVALID_COMMAND			0x20
++#define SENCODE_LBA_OUT_OF_RANGE		0x21
++#define SENCODE_INVALID_CDB_FIELD		0x24
++#define SENCODE_LUN_NOT_SUPPORTED		0x25
++#define SENCODE_INVALID_PARAM_FIELD		0x26
++#define SENCODE_PARAM_NOT_SUPPORTED		0x26
++#define SENCODE_PARAM_VALUE_INVALID		0x26
++#define SENCODE_RESET_OCCURRED			0x29
++#define SENCODE_LUN_NOT_SELF_CONFIGURED_YET	0x3E
++#define SENCODE_INQUIRY_DATA_CHANGED		0x3F
++#define SENCODE_SAVING_PARAMS_NOT_SUPPORTED	0x39
++#define SENCODE_DIAGNOSTIC_FAILURE		0x40
++#define SENCODE_INTERNAL_TARGET_FAILURE		0x44
++#define SENCODE_INVALID_MESSAGE_ERROR		0x49
++#define SENCODE_LUN_FAILED_SELF_CONFIG		0x4c
++#define SENCODE_OVERLAPPED_COMMAND		0x4E
+ 
+ /*
+  *	Additional sense codes
+  */
+- 
+-#define ASENCODE_NO_SENSE                       0x00
+-#define ASENCODE_END_OF_DATA                    0x05
+-#define ASENCODE_BECOMING_READY                 0x01
+-#define ASENCODE_INIT_CMD_REQUIRED              0x02
+-#define ASENCODE_PARAM_LIST_LENGTH_ERROR        0x00
+-#define ASENCODE_INVALID_COMMAND                0x00
+-#define ASENCODE_LBA_OUT_OF_RANGE               0x00
+-#define ASENCODE_INVALID_CDB_FIELD              0x00
+-#define ASENCODE_LUN_NOT_SUPPORTED              0x00
+-#define ASENCODE_INVALID_PARAM_FIELD            0x00
+-#define ASENCODE_PARAM_NOT_SUPPORTED            0x01
+-#define ASENCODE_PARAM_VALUE_INVALID            0x02
+-#define ASENCODE_RESET_OCCURRED                 0x00
+-#define ASENCODE_LUN_NOT_SELF_CONFIGURED_YET    0x00
+-#define ASENCODE_INQUIRY_DATA_CHANGED           0x03
+-#define ASENCODE_SAVING_PARAMS_NOT_SUPPORTED    0x00
+-#define ASENCODE_DIAGNOSTIC_FAILURE             0x80
+-#define ASENCODE_INTERNAL_TARGET_FAILURE        0x00
+-#define ASENCODE_INVALID_MESSAGE_ERROR          0x00
+-#define ASENCODE_LUN_FAILED_SELF_CONFIG         0x00
+-#define ASENCODE_OVERLAPPED_COMMAND             0x00
 +
-+		if (end.cyl + basepriv->attrib.nr_cyl < geo.cyl)
-+			end.cyl += basepriv->attrib.nr_cyl;
-+		else
-+			end.cyl = (geo.cyl - 1);
-+	}
++#define ASENCODE_NO_SENSE			0x00
++#define ASENCODE_END_OF_DATA			0x05
++#define ASENCODE_BECOMING_READY			0x01
++#define ASENCODE_INIT_CMD_REQUIRED		0x02
++#define ASENCODE_PARAM_LIST_LENGTH_ERROR	0x00
++#define ASENCODE_INVALID_COMMAND		0x00
++#define ASENCODE_LBA_OUT_OF_RANGE		0x00
++#define ASENCODE_INVALID_CDB_FIELD		0x00
++#define ASENCODE_LUN_NOT_SUPPORTED		0x00
++#define ASENCODE_INVALID_PARAM_FIELD		0x00
++#define ASENCODE_PARAM_NOT_SUPPORTED		0x01
++#define ASENCODE_PARAM_VALUE_INVALID		0x02
++#define ASENCODE_RESET_OCCURRED			0x00
++#define ASENCODE_LUN_NOT_SELF_CONFIGURED_YET	0x00
++#define ASENCODE_INQUIRY_DATA_CHANGED		0x03
++#define ASENCODE_SAVING_PARAMS_NOT_SUPPORTED	0x00
++#define ASENCODE_DIAGNOSTIC_FAILURE		0x80
++#define ASENCODE_INTERNAL_TARGET_FAILURE	0x00
++#define ASENCODE_INVALID_MESSAGE_ERROR		0x00
++#define ASENCODE_LUN_FAILED_SELF_CONFIG		0x00
++#define ASENCODE_OVERLAPPED_COMMAND		0x00
+ 
+ #define BYTE0(x) (unsigned char)(x)
+ #define BYTE1(x) (unsigned char)((x) >> 8)
+@@ -115,8 +115,8 @@
+  *----------------------------------------------------------------------------*/
+ /* SCSI inquiry data */
+ struct inquiry_data {
+-	u8 inqd_pdt;	/* Peripheral qualifier | Peripheral Device Type  */
+-	u8 inqd_dtq;	/* RMB | Device Type Qualifier  */
++	u8 inqd_pdt;	/* Peripheral qualifier | Peripheral Device Type */
++	u8 inqd_dtq;	/* RMB | Device Type Qualifier */
+ 	u8 inqd_ver;	/* ISO version | ECMA version | ANSI-approved version */
+ 	u8 inqd_rdf;	/* AENC | TrmIOP | Response data format */
+ 	u8 inqd_len;	/* Additional length (n-4) */
+@@ -130,7 +130,7 @@ struct inquiry_data {
+ /*
+  *              M O D U L E   G L O B A L S
+  */
+- 
 +
-+	data->beg_ext.cyl = beg.cyl;
-+	data->beg_ext.head = beg.head;
-+	data->end_ext.cyl = end.cyl;
-+	data->end_ext.head = end.head;
-+	return rc;
-+}
+ static unsigned long aac_build_sg(struct scsi_cmnd* scsicmd, struct sgmap* sgmap);
+ static unsigned long aac_build_sg64(struct scsi_cmnd* scsicmd, struct sgmap64* psg);
+ static unsigned long aac_build_sgraw(struct scsi_cmnd* scsicmd, struct sgmapraw* psg);
+@@ -141,9 +141,10 @@ static char *aac_get_status_string(u32 status);
+ 
+ /*
+  *	Non dasd selection is handled entirely in aachba now
+- */	
+- 
++ */
 +
- static void
- locate_record(struct ccw1 *ccw, struct LO_eckd_data *data, int trk,
- 	      int rec_on_trk, int no_rec, int cmd,
-@@ -300,7 +416,7 @@ locate_record(struct ccw1 *ccw, struct LO_eckd_data *data, int trk,
- 	ccw->count = 16;
- 	ccw->cda = (__u32) __pa(data);
+ static int nondasd = -1;
++static int aac_cache = 0;
+ static int dacmode = -1;
  
--	memset(data, 0, sizeof (struct LO_eckd_data));
-+	memset(data, 0, sizeof(struct LO_eckd_data));
- 	sector = 0;
- 	if (rec_on_trk) {
- 		switch (private->rdc_data.dev_type) {
-@@ -441,12 +557,15 @@ dasd_eckd_generate_uid(struct dasd_device *device, struct dasd_uid *uid)
- 	       sizeof(uid->serial) - 1);
- 	EBCASC(uid->serial, sizeof(uid->serial) - 1);
- 	uid->ssid = confdata->neq.subsystemID;
--	if (confdata->ned2.sneq.flags == 0x40) {
--		uid->alias = 1;
--		uid->unit_addr = confdata->ned2.sneq.base_unit_addr;
--	} else
--		uid->unit_addr = confdata->ned1.unit_addr;
--
-+	uid->real_unit_addr = confdata->ned1.unit_addr;
-+	if (confdata->ned2.sneq.flags == 0x40 &&
-+	    confdata->ned2.sneq.format == 0x0001) {
-+		uid->type = confdata->ned2.sneq.sua_flags;
-+		if (uid->type == UA_BASE_PAV_ALIAS)
-+			uid->base_unit_addr = confdata->ned2.sneq.base_unit_addr;
-+	} else {
-+		uid->type = UA_BASE_DEVICE;
-+	}
- 	return 0;
- }
+ int aac_commit = -1;
+@@ -152,6 +153,8 @@ int aif_timeout = 120;
  
-@@ -470,7 +589,9 @@ static struct dasd_ccw_req *dasd_eckd_build_rcd_lpm(struct dasd_device *device,
- 	ccw->cda = (__u32)(addr_t)rcd_buffer;
- 	ccw->count = ciw->count;
+ module_param(nondasd, int, S_IRUGO|S_IWUSR);
+ MODULE_PARM_DESC(nondasd, "Control scanning of hba for nondasd devices. 0=off, 1=on");
++module_param_named(cache, aac_cache, int, S_IRUGO|S_IWUSR);
++MODULE_PARM_DESC(cache, "Disable Queue Flush commands:\n\tbit 0 - Disable FUA in WRITE SCSI commands\n\tbit 1 - Disable SYNCHRONIZE_CACHE SCSI command\n\tbit 2 - Disable only if Battery not protecting Cache");
+ module_param(dacmode, int, S_IRUGO|S_IWUSR);
+ MODULE_PARM_DESC(dacmode, "Control whether dma addressing is using 64 bit DAC. 0=off, 1=on");
+ module_param_named(commit, aac_commit, int, S_IRUGO|S_IWUSR);
+@@ -179,7 +182,7 @@ MODULE_PARM_DESC(check_interval, "Interval in seconds between adapter health che
  
--	cqr->device = device;
-+	cqr->startdev = device;
-+	cqr->memdev = device;
-+	cqr->block = NULL;
- 	cqr->expires = 10*HZ;
- 	cqr->lpm = lpm;
- 	clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
-@@ -511,7 +632,7 @@ static int dasd_eckd_read_conf_lpm(struct dasd_device *device,
- 	/*
- 	 * on success we update the user input parms
- 	 */
--	dasd_sfree_request(cqr, cqr->device);
-+	dasd_sfree_request(cqr, cqr->memdev);
- 	if (ret)
- 		goto out_error;
+ int aac_check_reset = 1;
+ module_param_named(check_reset, aac_check_reset, int, S_IRUGO|S_IWUSR);
+-MODULE_PARM_DESC(aac_check_reset, "If adapter fails health check, reset the adapter.");
++MODULE_PARM_DESC(aac_check_reset, "If adapter fails health check, reset the adapter. a value of -1 forces the reset to adapters programmed to ignore it.");
  
-@@ -557,19 +678,19 @@ dasd_eckd_read_conf(struct dasd_device *device)
- 					"data retrieved");
- 				continue;	/* no error */
- 			}
--			if (conf_len != sizeof (struct dasd_eckd_confdata)) {
-+			if (conf_len != sizeof(struct dasd_eckd_confdata)) {
- 				MESSAGE(KERN_WARNING,
- 					"sizes of configuration data mismatch"
- 					"%d (read) vs %ld (expected)",
- 					conf_len,
--					sizeof (struct dasd_eckd_confdata));
-+					sizeof(struct dasd_eckd_confdata));
- 				kfree(conf_data);
- 				continue;	/* no error */
- 			}
- 			/* save first valid configuration data */
- 			if (!conf_data_saved){
- 				memcpy(&private->conf_data, conf_data,
--				       sizeof (struct dasd_eckd_confdata));
-+				       sizeof(struct dasd_eckd_confdata));
- 				conf_data_saved++;
- 			}
- 			switch (((char *)conf_data)[242] & 0x07){
-@@ -586,39 +707,104 @@ dasd_eckd_read_conf(struct dasd_device *device)
- 	return 0;
- }
+ int expose_physicals = -1;
+ module_param(expose_physicals, int, S_IRUGO|S_IWUSR);
+@@ -193,12 +196,12 @@ static inline int aac_valid_context(struct scsi_cmnd *scsicmd,
+ 		struct fib *fibptr) {
+ 	struct scsi_device *device;
  
-+static int dasd_eckd_read_features(struct dasd_device *device)
-+{
-+	struct dasd_psf_prssd_data *prssdp;
-+	struct dasd_rssd_features *features;
-+	struct dasd_ccw_req *cqr;
-+	struct ccw1 *ccw;
-+	int rc;
-+	struct dasd_eckd_private *private;
-+
-+	private = (struct dasd_eckd_private *) device->private;
-+	cqr = dasd_smalloc_request(dasd_eckd_discipline.name,
-+				   1 /* PSF */	+ 1 /* RSSD */ ,
-+				   (sizeof(struct dasd_psf_prssd_data) +
-+				    sizeof(struct dasd_rssd_features)),
-+				   device);
-+	if (IS_ERR(cqr)) {
-+		DEV_MESSAGE(KERN_WARNING, device, "%s",
-+			    "Could not allocate initialization request");
-+		return PTR_ERR(cqr);
-+	}
-+	cqr->startdev = device;
-+	cqr->memdev = device;
-+	cqr->block = NULL;
-+	clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
-+	cqr->retries = 5;
-+	cqr->expires = 10 * HZ;
-+
-+	/* Prepare for Read Subsystem Data */
-+	prssdp = (struct dasd_psf_prssd_data *) cqr->data;
-+	memset(prssdp, 0, sizeof(struct dasd_psf_prssd_data));
-+	prssdp->order = PSF_ORDER_PRSSD;
-+	prssdp->suborder = 0x41;	/* Read Feature Codes */
-+	/* all other bytes of prssdp must be zero */
-+
-+	ccw = cqr->cpaddr;
-+	ccw->cmd_code = DASD_ECKD_CCW_PSF;
-+	ccw->count = sizeof(struct dasd_psf_prssd_data);
-+	ccw->flags |= CCW_FLAG_CC;
-+	ccw->cda = (__u32)(addr_t) prssdp;
-+
-+	/* Read Subsystem Data - feature codes */
-+	features = (struct dasd_rssd_features *) (prssdp + 1);
-+	memset(features, 0, sizeof(struct dasd_rssd_features));
-+
-+	ccw++;
-+	ccw->cmd_code = DASD_ECKD_CCW_RSSD;
-+	ccw->count = sizeof(struct dasd_rssd_features);
-+	ccw->cda = (__u32)(addr_t) features;
-+
-+	cqr->buildclk = get_clock();
-+	cqr->status = DASD_CQR_FILLED;
-+	rc = dasd_sleep_on(cqr);
-+	if (rc == 0) {
-+		prssdp = (struct dasd_psf_prssd_data *) cqr->data;
-+		features = (struct dasd_rssd_features *) (prssdp + 1);
-+		memcpy(&private->features, features,
-+		       sizeof(struct dasd_rssd_features));
+-	if (unlikely(!scsicmd || !scsicmd->scsi_done )) {
++	if (unlikely(!scsicmd || !scsicmd->scsi_done)) {
+ 		dprintk((KERN_WARNING "aac_valid_context: scsi command corrupt\n"));
+-                aac_fib_complete(fibptr);
+-                aac_fib_free(fibptr);
+-                return 0;
+-        }
++		aac_fib_complete(fibptr);
++		aac_fib_free(fibptr);
++		return 0;
 +	}
-+	dasd_sfree_request(cqr, cqr->memdev);
-+	return rc;
-+}
+ 	scsicmd->SCp.phase = AAC_OWNER_MIDLEVEL;
+ 	device = scsicmd->device;
+ 	if (unlikely(!device || !scsi_device_online(device))) {
+@@ -240,7 +243,7 @@ int aac_get_config_status(struct aac_dev *dev, int commit_flag)
+ 			    FsaNormal,
+ 			    1, 1,
+ 			    NULL, NULL);
+-	if (status < 0 ) {
++	if (status < 0) {
+ 		printk(KERN_WARNING "aac_get_config_status: SendFIB failed.\n");
+ 	} else {
+ 		struct aac_get_config_status_resp *reply
+@@ -264,10 +267,10 @@ int aac_get_config_status(struct aac_dev *dev, int commit_flag)
+ 			struct aac_commit_config * dinfo;
+ 			aac_fib_init(fibptr);
+ 			dinfo = (struct aac_commit_config *) fib_data(fibptr);
+-	
 +
+ 			dinfo->command = cpu_to_le32(VM_ContainerConfig);
+ 			dinfo->type = cpu_to_le32(CT_COMMIT_CONFIG);
+-	
 +
- /*
-  * Build CP for Perform Subsystem Function - SSC.
-  */
--static struct dasd_ccw_req *
--dasd_eckd_build_psf_ssc(struct dasd_device *device)
-+static struct dasd_ccw_req *dasd_eckd_build_psf_ssc(struct dasd_device *device)
+ 			status = aac_fib_send(ContainerCommand,
+ 				    fibptr,
+ 				    sizeof (struct aac_commit_config),
+@@ -293,7 +296,7 @@ int aac_get_config_status(struct aac_dev *dev, int commit_flag)
+ int aac_get_containers(struct aac_dev *dev)
  {
--       struct dasd_ccw_req *cqr;
--       struct dasd_psf_ssc_data *psf_ssc_data;
--       struct ccw1 *ccw;
-+	struct dasd_ccw_req *cqr;
-+	struct dasd_psf_ssc_data *psf_ssc_data;
-+	struct ccw1 *ccw;
+ 	struct fsa_dev_info *fsa_dev_ptr;
+-	u32 index; 
++	u32 index;
+ 	int status = 0;
+ 	struct fib * fibptr;
+ 	struct aac_get_container_count *dinfo;
+@@ -363,6 +366,7 @@ static void aac_internal_transfer(struct scsi_cmnd *scsicmd, void *data, unsigne
+ 	if (buf && transfer_len > 0)
+ 		memcpy(buf + offset, data, transfer_len);
  
--       cqr = dasd_smalloc_request("ECKD", 1 /* PSF */ ,
-+	cqr = dasd_smalloc_request("ECKD", 1 /* PSF */ ,
- 				  sizeof(struct dasd_psf_ssc_data),
- 				  device);
++	flush_kernel_dcache_page(kmap_atomic_to_page(buf - sg->offset));
+ 	kunmap_atomic(buf - sg->offset, KM_IRQ0);
  
--       if (IS_ERR(cqr)) {
--	       DEV_MESSAGE(KERN_WARNING, device, "%s",
-+	if (IS_ERR(cqr)) {
-+		DEV_MESSAGE(KERN_WARNING, device, "%s",
- 			   "Could not allocate PSF-SSC request");
--	       return cqr;
--       }
--       psf_ssc_data = (struct dasd_psf_ssc_data *)cqr->data;
--       psf_ssc_data->order = PSF_ORDER_SSC;
--       psf_ssc_data->suborder = 0x08;
--
--       ccw = cqr->cpaddr;
--       ccw->cmd_code = DASD_ECKD_CCW_PSF;
--       ccw->cda = (__u32)(addr_t)psf_ssc_data;
--       ccw->count = 66;
--
--       cqr->device = device;
--       cqr->expires = 10*HZ;
--       cqr->buildclk = get_clock();
--       cqr->status = DASD_CQR_FILLED;
--       return cqr;
-+		return cqr;
-+	}
-+	psf_ssc_data = (struct dasd_psf_ssc_data *)cqr->data;
-+	psf_ssc_data->order = PSF_ORDER_SSC;
-+	psf_ssc_data->suborder = 0x88;
-+	psf_ssc_data->reserved[0] = 0x88;
-+
-+	ccw = cqr->cpaddr;
-+	ccw->cmd_code = DASD_ECKD_CCW_PSF;
-+	ccw->cda = (__u32)(addr_t)psf_ssc_data;
-+	ccw->count = 66;
-+
-+	cqr->startdev = device;
-+	cqr->memdev = device;
-+	cqr->block = NULL;
-+	cqr->expires = 10*HZ;
-+	cqr->buildclk = get_clock();
-+	cqr->status = DASD_CQR_FILLED;
-+	return cqr;
  }
+@@ -395,7 +399,7 @@ static void get_container_name_callback(void *context, struct fib * fibptr)
+ 			do {
+ 				*dp++ = (*sp) ? *sp++ : ' ';
+ 			} while (--count > 0);
+-			aac_internal_transfer(scsicmd, d, 
++			aac_internal_transfer(scsicmd, d,
+ 			  offsetof(struct inquiry_data, inqd_pid), sizeof(d));
+ 		}
+ 	}
+@@ -431,13 +435,13 @@ static int aac_get_container_name(struct scsi_cmnd * scsicmd)
+ 	dinfo->count = cpu_to_le32(sizeof(((struct aac_get_name_resp *)NULL)->data));
  
- /*
-@@ -629,28 +815,28 @@ dasd_eckd_build_psf_ssc(struct dasd_device *device)
- static int
- dasd_eckd_psf_ssc(struct dasd_device *device)
- {
--       struct dasd_ccw_req *cqr;
--       int rc;
--
--       cqr = dasd_eckd_build_psf_ssc(device);
--       if (IS_ERR(cqr))
--	       return PTR_ERR(cqr);
--
--       rc = dasd_sleep_on(cqr);
--       if (!rc)
--	       /* trigger CIO to reprobe devices */
--	       css_schedule_reprobe();
--       dasd_sfree_request(cqr, cqr->device);
--       return rc;
-+	struct dasd_ccw_req *cqr;
-+	int rc;
+ 	status = aac_fib_send(ContainerCommand,
+-		  cmd_fibcontext, 
++		  cmd_fibcontext,
+ 		  sizeof (struct aac_get_name),
+-		  FsaNormal, 
+-		  0, 1, 
+-		  (fib_callback) get_container_name_callback, 
++		  FsaNormal,
++		  0, 1,
++		  (fib_callback)get_container_name_callback,
+ 		  (void *) scsicmd);
+-	
 +
-+	cqr = dasd_eckd_build_psf_ssc(device);
-+	if (IS_ERR(cqr))
-+		return PTR_ERR(cqr);
+ 	/*
+ 	 *	Check that the command queued to the controller
+ 	 */
+@@ -445,7 +449,7 @@ static int aac_get_container_name(struct scsi_cmnd * scsicmd)
+ 		scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
+ 		return 0;
+ 	}
+-		
 +
-+	rc = dasd_sleep_on(cqr);
-+	if (!rc)
-+		/* trigger CIO to reprobe devices */
-+		css_schedule_reprobe();
-+	dasd_sfree_request(cqr, cqr->memdev);
-+	return rc;
- }
- 
- /*
-  * Valide storage server of current device.
+ 	printk(KERN_WARNING "aac_get_container_name: aac_fib_send failed with status: %d.\n", status);
+ 	aac_fib_complete(cmd_fibcontext);
+ 	aac_fib_free(cmd_fibcontext);
+@@ -652,42 +656,47 @@ struct scsi_inq {
+  *	@a:	string to copy from
+  *	@b:	string to copy to
+  *
+- * 	Copy a String from one location to another
++ *	Copy a String from one location to another
+  *	without copying \0
   */
--static int
--dasd_eckd_validate_server(struct dasd_device *device, struct dasd_uid *uid)
-+static int dasd_eckd_validate_server(struct dasd_device *device)
- {
- 	int rc;
-+	struct dasd_eckd_private *private;
  
- 	/* Currently PAV is the only reason to 'validate' server on LPAR */
- 	if (dasd_nopav || MACHINE_IS_VM)
-@@ -659,9 +845,11 @@ dasd_eckd_validate_server(struct dasd_device *device, struct dasd_uid *uid)
- 	rc = dasd_eckd_psf_ssc(device);
- 	/* may be requested feature is not available on server,
- 	 * therefore just report error and go ahead */
-+	private = (struct dasd_eckd_private *) device->private;
- 	DEV_MESSAGE(KERN_INFO, device,
- 		    "PSF-SSC on storage subsystem %s.%s.%04x returned rc=%d",
--		    uid->vendor, uid->serial, uid->ssid, rc);
-+		    private->uid.vendor, private->uid.serial,
-+		    private->uid.ssid, rc);
- 	/* RE-Read Configuration Data */
- 	return dasd_eckd_read_conf(device);
+ static void inqstrcpy(char *a, char *b)
+ {
+ 
+-	while(*a != (char)0) 
++	while (*a != (char)0)
+ 		*b++ = *a++;
  }
-@@ -674,9 +862,9 @@ static int
- dasd_eckd_check_characteristics(struct dasd_device *device)
- {
- 	struct dasd_eckd_private *private;
--	struct dasd_uid uid;
-+	struct dasd_block *block;
- 	void *rdc_data;
--	int rc;
-+	int is_known, rc;
  
- 	private = (struct dasd_eckd_private *) device->private;
- 	if (private == NULL) {
-@@ -699,27 +887,54 @@ dasd_eckd_check_characteristics(struct dasd_device *device)
- 	/* Read Configuration Data */
- 	rc = dasd_eckd_read_conf(device);
- 	if (rc)
--		return rc;
-+		goto out_err1;
+ static char *container_types[] = {
+-        "None",
+-        "Volume",
+-        "Mirror",
+-        "Stripe",
+-        "RAID5",
+-        "SSRW",
+-        "SSRO",
+-        "Morph",
+-        "Legacy",
+-        "RAID4",
+-        "RAID10",             
+-        "RAID00",             
+-        "V-MIRRORS",          
+-        "PSEUDO R4",          
++	"None",
++	"Volume",
++	"Mirror",
++	"Stripe",
++	"RAID5",
++	"SSRW",
++	"SSRO",
++	"Morph",
++	"Legacy",
++	"RAID4",
++	"RAID10",
++	"RAID00",
++	"V-MIRRORS",
++	"PSEUDO R4",
+ 	"RAID50",
+ 	"RAID5D",
+ 	"RAID5D0",
+ 	"RAID1E",
+ 	"RAID6",
+ 	"RAID60",
+-        "Unknown"
++	"Unknown"
+ };
  
- 	/* Generate device unique id and register in devmap */
--	rc = dasd_eckd_generate_uid(device, &uid);
-+	rc = dasd_eckd_generate_uid(device, &private->uid);
- 	if (rc)
--		return rc;
--	rc = dasd_set_uid(device->cdev, &uid);
--	if (rc == 1)	/* new server found */
--		rc = dasd_eckd_validate_server(device, &uid);
-+		goto out_err1;
-+	dasd_set_uid(device->cdev, &private->uid);
-+
-+	if (private->uid.type == UA_BASE_DEVICE) {
-+		block = dasd_alloc_block();
-+		if (IS_ERR(block)) {
-+			DEV_MESSAGE(KERN_WARNING, device, "%s",
-+				    "could not allocate dasd block structure");
-+			rc = PTR_ERR(block);
-+			goto out_err1;
+-
++char * get_container_type(unsigned tindex)
++{
++	if (tindex >= ARRAY_SIZE(container_types))
++		tindex = ARRAY_SIZE(container_types) - 1;
++	return container_types[tindex];
++}
+ 
+ /* Function: setinqstr
+  *
+@@ -707,16 +716,21 @@ static void setinqstr(struct aac_dev *dev, void *data, int tindex)
+ 
+ 	if (dev->supplement_adapter_info.AdapterTypeText[0]) {
+ 		char * cp = dev->supplement_adapter_info.AdapterTypeText;
+-		int c = sizeof(str->vid);
+-		while (*cp && *cp != ' ' && --c)
+-			++cp;
+-		c = *cp;
+-		*cp = '\0';
+-		inqstrcpy (dev->supplement_adapter_info.AdapterTypeText,
+-		  str->vid); 
+-		*cp = c;
+-		while (*cp && *cp != ' ')
+-			++cp;
++		int c;
++		if ((cp[0] == 'A') && (cp[1] == 'O') && (cp[2] == 'C'))
++			inqstrcpy("SMC", str->vid);
++		else {
++			c = sizeof(str->vid);
++			while (*cp && *cp != ' ' && --c)
++				++cp;
++			c = *cp;
++			*cp = '\0';
++			inqstrcpy (dev->supplement_adapter_info.AdapterTypeText,
++				   str->vid);
++			*cp = c;
++			while (*cp && *cp != ' ')
++				++cp;
 +		}
-+		device->block = block;
-+		block->base = device;
-+	}
-+
-+	/* register lcu with alias handling, enable PAV if this is a new lcu */
-+	is_known = dasd_alias_make_device_known_to_lcu(device);
-+	if (is_known < 0) {
-+		rc = is_known;
-+		goto out_err2;
-+	}
-+	if (!is_known) {
-+		/* new lcu found */
-+		rc = dasd_eckd_validate_server(device); /* will switch pav on */
-+		if (rc)
-+			goto out_err3;
-+	}
-+
-+	/* Read Feature Codes */
-+	rc = dasd_eckd_read_features(device);
- 	if (rc)
--		return rc;
-+		goto out_err3;
+ 		while (*cp == ' ')
+ 			++cp;
+ 		/* last six chars reserved for vol type */
+@@ -898,9 +912,8 @@ static int aac_bounds_32(struct aac_dev * dev, struct scsi_cmnd * cmd, u64 lba)
+ 			    ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0,
+ 			    0, 0);
+ 		memcpy(cmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
+-		  (sizeof(dev->fsa_dev[cid].sense_data) > sizeof(cmd->sense_buffer))
+-		    ? sizeof(cmd->sense_buffer)
+-		    : sizeof(dev->fsa_dev[cid].sense_data));
++		       min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data),
++			     SCSI_SENSE_BUFFERSIZE));
+ 		cmd->scsi_done(cmd);
+ 		return 1;
+ 	}
+@@ -981,7 +994,7 @@ static int aac_read_block(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u32
+ 	aac_fib_init(fib);
+ 	readcmd = (struct aac_read *) fib_data(fib);
+ 	readcmd->command = cpu_to_le32(VM_CtBlockRead);
+-	readcmd->cid = cpu_to_le16(scmd_id(cmd));
++	readcmd->cid = cpu_to_le32(scmd_id(cmd));
+ 	readcmd->block = cpu_to_le32((u32)(lba&0xffffffff));
+ 	readcmd->count = cpu_to_le32(count * 512);
  
- 	/* Read Device Characteristics */
- 	rdc_data = (void *) &(private->rdc_data);
- 	memset(rdc_data, 0, sizeof(rdc_data));
- 	rc = dasd_generic_read_dev_chars(device, "ECKD", &rdc_data, 64);
--	if (rc)
-+	if (rc) {
- 		DEV_MESSAGE(KERN_WARNING, device,
- 			    "Read device characteristics returned "
- 			    "rc=%d", rc);
--
-+		goto out_err3;
-+	}
- 	DEV_MESSAGE(KERN_INFO, device,
- 		    "%04X/%02X(CU:%04X/%02X) Cyl:%d Head:%d Sec:%d",
- 		    private->rdc_data.dev_type,
-@@ -729,9 +944,24 @@ dasd_eckd_check_characteristics(struct dasd_device *device)
- 		    private->rdc_data.no_cyl,
- 		    private->rdc_data.trk_per_cyl,
- 		    private->rdc_data.sec_per_trk);
-+	return 0;
-+
-+out_err3:
-+	dasd_alias_disconnect_device_from_lcu(device);
-+out_err2:
-+	dasd_free_block(device->block);
-+	device->block = NULL;
-+out_err1:
-+	kfree(device->private);
-+	device->private = NULL;
- 	return rc;
+@@ -1013,7 +1026,8 @@ static int aac_write_raw_io(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u
+ 	writecmd->block[1] = cpu_to_le32((u32)((lba&0xffffffff00000000LL)>>32));
+ 	writecmd->count = cpu_to_le32(count<<9);
+ 	writecmd->cid = cpu_to_le16(scmd_id(cmd));
+-	writecmd->flags = fua ?
++	writecmd->flags = (fua && ((aac_cache & 5) != 1) &&
++	  (((aac_cache & 5) != 5) || !fib->dev->cache_protected)) ?
+ 		cpu_to_le16(IO_TYPE_WRITE|IO_SUREWRITE) :
+ 		cpu_to_le16(IO_TYPE_WRITE);
+ 	writecmd->bpTotal = 0;
+@@ -1072,7 +1086,7 @@ static int aac_write_block(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u3
+ 	aac_fib_init(fib);
+ 	writecmd = (struct aac_write *) fib_data(fib);
+ 	writecmd->command = cpu_to_le32(VM_CtBlockWrite);
+-	writecmd->cid = cpu_to_le16(scmd_id(cmd));
++	writecmd->cid = cpu_to_le32(scmd_id(cmd));
+ 	writecmd->block = cpu_to_le32((u32)(lba&0xffffffff));
+ 	writecmd->count = cpu_to_le32(count * 512);
+ 	writecmd->sg.count = cpu_to_le32(1);
+@@ -1190,6 +1204,15 @@ static int aac_scsi_32(struct fib * fib, struct scsi_cmnd * cmd)
+ 				  (fib_callback) aac_srb_callback, (void *) cmd);
  }
  
-+static void dasd_eckd_uncheck_device(struct dasd_device *device)
++static int aac_scsi_32_64(struct fib * fib, struct scsi_cmnd * cmd)
 +{
-+	dasd_alias_disconnect_device_from_lcu(device);
++	if ((sizeof(dma_addr_t) > 4) &&
++	 (num_physpages > (0xFFFFFFFFULL >> PAGE_SHIFT)) &&
++	 (fib->dev->adapter_info.options & AAC_OPT_SGMAP_HOST64))
++		return FAILED;
++	return aac_scsi_32(fib, cmd);
 +}
 +
- static struct dasd_ccw_req *
- dasd_eckd_analysis_ccw(struct dasd_device *device)
+ int aac_get_adapter_info(struct aac_dev* dev)
  {
-@@ -755,7 +985,7 @@ dasd_eckd_analysis_ccw(struct dasd_device *device)
- 	/* Define extent for the first 3 tracks. */
- 	define_extent(ccw++, cqr->data, 0, 2,
- 		      DASD_ECKD_CCW_READ_COUNT, device);
--	LO_data = cqr->data + sizeof (struct DE_eckd_data);
-+	LO_data = cqr->data + sizeof(struct DE_eckd_data);
- 	/* Locate record for the first 4 records on track 0. */
- 	ccw[-1].flags |= CCW_FLAG_CC;
- 	locate_record(ccw++, LO_data++, 0, 0, 4,
-@@ -783,7 +1013,9 @@ dasd_eckd_analysis_ccw(struct dasd_device *device)
- 	ccw->count = 8;
- 	ccw->cda = (__u32)(addr_t) count_data;
+ 	struct fib* fibptr;
+@@ -1207,11 +1230,11 @@ int aac_get_adapter_info(struct aac_dev* dev)
+ 	memset(info,0,sizeof(*info));
  
--	cqr->device = device;
-+	cqr->block = NULL;
-+	cqr->startdev = device;
-+	cqr->memdev = device;
- 	cqr->retries = 0;
- 	cqr->buildclk = get_clock();
- 	cqr->status = DASD_CQR_FILLED;
-@@ -803,7 +1035,7 @@ dasd_eckd_analysis_callback(struct dasd_ccw_req *init_cqr, void *data)
- 	struct dasd_eckd_private *private;
- 	struct dasd_device *device;
+ 	rcode = aac_fib_send(RequestAdapterInfo,
+-			 fibptr, 
++			 fibptr,
+ 			 sizeof(*info),
+-			 FsaNormal, 
++			 FsaNormal,
+ 			 -1, 1, /* First `interrupt' command uses special wait */
+-			 NULL, 
++			 NULL,
+ 			 NULL);
  
--	device = init_cqr->device;
-+	device = init_cqr->startdev;
- 	private = (struct dasd_eckd_private *) device->private;
- 	private->init_cqr_status = init_cqr->status;
- 	dasd_sfree_request(init_cqr, device);
-@@ -811,13 +1043,13 @@ dasd_eckd_analysis_callback(struct dasd_ccw_req *init_cqr, void *data)
- }
+ 	if (rcode < 0) {
+@@ -1222,29 +1245,29 @@ int aac_get_adapter_info(struct aac_dev* dev)
+ 	memcpy(&dev->adapter_info, info, sizeof(*info));
  
- static int
--dasd_eckd_start_analysis(struct dasd_device *device)
-+dasd_eckd_start_analysis(struct dasd_block *block)
- {
- 	struct dasd_eckd_private *private;
- 	struct dasd_ccw_req *init_cqr;
+ 	if (dev->adapter_info.options & AAC_OPT_SUPPLEMENT_ADAPTER_INFO) {
+-		struct aac_supplement_adapter_info * info;
++		struct aac_supplement_adapter_info * sinfo;
  
--	private = (struct dasd_eckd_private *) device->private;
--	init_cqr = dasd_eckd_analysis_ccw(device);
-+	private = (struct dasd_eckd_private *) block->base->private;
-+	init_cqr = dasd_eckd_analysis_ccw(block->base);
- 	if (IS_ERR(init_cqr))
- 		return PTR_ERR(init_cqr);
- 	init_cqr->callback = dasd_eckd_analysis_callback;
-@@ -828,13 +1060,15 @@ dasd_eckd_start_analysis(struct dasd_device *device)
- }
+ 		aac_fib_init(fibptr);
  
- static int
--dasd_eckd_end_analysis(struct dasd_device *device)
-+dasd_eckd_end_analysis(struct dasd_block *block)
- {
-+	struct dasd_device *device;
- 	struct dasd_eckd_private *private;
- 	struct eckd_count *count_area;
- 	unsigned int sb, blk_per_trk;
- 	int status, i;
+-		info = (struct aac_supplement_adapter_info *) fib_data(fibptr);
++		sinfo = (struct aac_supplement_adapter_info *) fib_data(fibptr);
  
-+	device = block->base;
- 	private = (struct dasd_eckd_private *) device->private;
- 	status = private->init_cqr_status;
- 	private->init_cqr_status = -1;
-@@ -846,7 +1080,7 @@ dasd_eckd_end_analysis(struct dasd_device *device)
+-		memset(info,0,sizeof(*info));
++		memset(sinfo,0,sizeof(*sinfo));
  
- 	private->uses_cdl = 1;
- 	/* Calculate number of blocks/records per track. */
--	blk_per_trk = recs_per_track(&private->rdc_data, 0, device->bp_block);
-+	blk_per_trk = recs_per_track(&private->rdc_data, 0, block->bp_block);
- 	/* Check Track 0 for Compatible Disk Layout */
- 	count_area = NULL;
- 	for (i = 0; i < 3; i++) {
-@@ -876,56 +1110,65 @@ dasd_eckd_end_analysis(struct dasd_device *device)
- 	if (count_area != NULL && count_area->kl == 0) {
- 		/* we found notthing violating our disk layout */
- 		if (dasd_check_blocksize(count_area->dl) == 0)
--			device->bp_block = count_area->dl;
-+			block->bp_block = count_area->dl;
- 	}
--	if (device->bp_block == 0) {
-+	if (block->bp_block == 0) {
- 		DEV_MESSAGE(KERN_WARNING, device, "%s",
- 			    "Volume has incompatible disk layout");
- 		return -EMEDIUMTYPE;
+ 		rcode = aac_fib_send(RequestSupplementAdapterInfo,
+ 				 fibptr,
+-				 sizeof(*info),
++				 sizeof(*sinfo),
+ 				 FsaNormal,
+ 				 1, 1,
+ 				 NULL,
+ 				 NULL);
+ 
+ 		if (rcode >= 0)
+-			memcpy(&dev->supplement_adapter_info, info, sizeof(*info));
++			memcpy(&dev->supplement_adapter_info, sinfo, sizeof(*sinfo));
  	}
--	device->s2b_shift = 0;	/* bits to shift 512 to get a block */
--	for (sb = 512; sb < device->bp_block; sb = sb << 1)
--		device->s2b_shift++;
-+	block->s2b_shift = 0;	/* bits to shift 512 to get a block */
-+	for (sb = 512; sb < block->bp_block; sb = sb << 1)
-+		block->s2b_shift++;
  
--	blk_per_trk = recs_per_track(&private->rdc_data, 0, device->bp_block);
--	device->blocks = (private->rdc_data.no_cyl *
-+	blk_per_trk = recs_per_track(&private->rdc_data, 0, block->bp_block);
-+	block->blocks = (private->rdc_data.no_cyl *
- 			  private->rdc_data.trk_per_cyl *
- 			  blk_per_trk);
  
- 	DEV_MESSAGE(KERN_INFO, device,
- 		    "(%dkB blks): %dkB at %dkB/trk %s",
--		    (device->bp_block >> 10),
-+		    (block->bp_block >> 10),
- 		    ((private->rdc_data.no_cyl *
- 		      private->rdc_data.trk_per_cyl *
--		      blk_per_trk * (device->bp_block >> 9)) >> 1),
--		    ((blk_per_trk * device->bp_block) >> 10),
-+		      blk_per_trk * (block->bp_block >> 9)) >> 1),
-+		    ((blk_per_trk * block->bp_block) >> 10),
- 		    private->uses_cdl ?
- 		    "compatible disk layout" : "linux disk layout");
+-	/* 
+-	 * GetBusInfo 
++	/*
++	 * GetBusInfo
+ 	 */
  
- 	return 0;
- }
+ 	aac_fib_init(fibptr);
+@@ -1267,6 +1290,8 @@ int aac_get_adapter_info(struct aac_dev* dev)
+ 			 1, 1,
+ 			 NULL, NULL);
  
--static int
--dasd_eckd_do_analysis(struct dasd_device *device)
-+static int dasd_eckd_do_analysis(struct dasd_block *block)
- {
- 	struct dasd_eckd_private *private;
++	/* reasoned default */
++	dev->maximum_num_physicals = 16;
+ 	if (rcode >= 0 && le32_to_cpu(bus_info->Status) == ST_OK) {
+ 		dev->maximum_num_physicals = le32_to_cpu(bus_info->TargetsPerBus);
+ 		dev->maximum_num_channels = le32_to_cpu(bus_info->BusCount);
+@@ -1276,7 +1301,7 @@ int aac_get_adapter_info(struct aac_dev* dev)
+ 		char buffer[16];
+ 		tmp = le32_to_cpu(dev->adapter_info.kernelrev);
+ 		printk(KERN_INFO "%s%d: kernel %d.%d-%d[%d] %.*s\n",
+-			dev->name, 
++			dev->name,
+ 			dev->id,
+ 			tmp>>24,
+ 			(tmp>>16)&0xff,
+@@ -1305,19 +1330,21 @@ int aac_get_adapter_info(struct aac_dev* dev)
+ 			  (int)sizeof(dev->supplement_adapter_info.VpdInfo.Tsid),
+ 			  dev->supplement_adapter_info.VpdInfo.Tsid);
+ 		}
+-		if (!aac_check_reset ||
++		if (!aac_check_reset || ((aac_check_reset != 1) &&
+ 		  (dev->supplement_adapter_info.SupportedOptions2 &
+-		  le32_to_cpu(AAC_OPTION_IGNORE_RESET))) {
++		  AAC_OPTION_IGNORE_RESET))) {
+ 			printk(KERN_INFO "%s%d: Reset Adapter Ignored\n",
+ 			  dev->name, dev->id);
+ 		}
+ 	}
  
--	private = (struct dasd_eckd_private *) device->private;
-+	private = (struct dasd_eckd_private *) block->base->private;
- 	if (private->init_cqr_status < 0)
--		return dasd_eckd_start_analysis(device);
-+		return dasd_eckd_start_analysis(block);
- 	else
--		return dasd_eckd_end_analysis(device);
-+		return dasd_eckd_end_analysis(block);
- }
++	dev->cache_protected = 0;
++	dev->jbod = ((dev->supplement_adapter_info.FeatureBits &
++		AAC_FEATURE_JBOD) != 0);
+ 	dev->nondasd_support = 0;
+ 	dev->raid_scsi_mode = 0;
+-	if(dev->adapter_info.options & AAC_OPT_NONDASD){
++	if(dev->adapter_info.options & AAC_OPT_NONDASD)
+ 		dev->nondasd_support = 1;
+-	}
  
-+static int dasd_eckd_ready_to_online(struct dasd_device *device)
-+{
-+	return dasd_alias_add_device(device);
-+};
-+
-+static int dasd_eckd_online_to_ready(struct dasd_device *device)
-+{
-+	return dasd_alias_remove_device(device);
-+};
+ 	/*
+ 	 * If the firmware supports ROMB RAID/SCSI mode and we are currently
+@@ -1338,11 +1365,10 @@ int aac_get_adapter_info(struct aac_dev* dev)
+ 	if (dev->raid_scsi_mode != 0)
+ 		printk(KERN_INFO "%s%d: ROMB RAID/SCSI mode enabled\n",
+ 				dev->name, dev->id);
+-		
+-	if(nondasd != -1) {  
 +
- static int
--dasd_eckd_fill_geometry(struct dasd_device *device, struct hd_geometry *geo)
-+dasd_eckd_fill_geometry(struct dasd_block *block, struct hd_geometry *geo)
- {
- 	struct dasd_eckd_private *private;
++	if (nondasd != -1)
+ 		dev->nondasd_support = (nondasd!=0);
+-	}
+-	if(dev->nondasd_support != 0){
++	if(dev->nondasd_support != 0) {
+ 		printk(KERN_INFO "%s%d: Non-DASD support enabled.\n",dev->name, dev->id);
+ 	}
  
--	private = (struct dasd_eckd_private *) device->private;
--	if (dasd_check_blocksize(device->bp_block) == 0) {
-+	private = (struct dasd_eckd_private *) block->base->private;
-+	if (dasd_check_blocksize(block->bp_block) == 0) {
- 		geo->sectors = recs_per_track(&private->rdc_data,
--					      0, device->bp_block);
-+					      0, block->bp_block);
+@@ -1371,12 +1397,14 @@ int aac_get_adapter_info(struct aac_dev* dev)
+ 			rcode = -ENOMEM;
+ 		}
  	}
- 	geo->cylinders = private->rdc_data.no_cyl;
- 	geo->heads = private->rdc_data.trk_per_cyl;
-@@ -1037,7 +1280,7 @@ dasd_eckd_format_device(struct dasd_device * device,
- 		locate_record(ccw++, (struct LO_eckd_data *) data,
- 			      fdata->start_unit, 0, rpt + 1,
- 			      DASD_ECKD_CCW_WRITE_RECORD_ZERO, device,
--			      device->bp_block);
-+			      device->block->bp_block);
- 		data += sizeof(struct LO_eckd_data);
+-	/* 
++	/*
+ 	 * Deal with configuring for the individualized limits of each packet
+ 	 * interface.
+ 	 */
+ 	dev->a_ops.adapter_scsi = (dev->dac_support)
+-				? aac_scsi_64
++	  ? ((aac_get_driver_ident(dev->cardtype)->quirks & AAC_QUIRK_SCSI_32)
++				? aac_scsi_32_64
++				: aac_scsi_64)
+ 				: aac_scsi_32;
+ 	if (dev->raw_io_interface) {
+ 		dev->a_ops.adapter_bounds = (dev->raw_io_64)
+@@ -1393,8 +1421,8 @@ int aac_get_adapter_info(struct aac_dev* dev)
+ 		if (dev->dac_support) {
+ 			dev->a_ops.adapter_read = aac_read_block64;
+ 			dev->a_ops.adapter_write = aac_write_block64;
+-			/* 
+-			 * 38 scatter gather elements 
++			/*
++			 * 38 scatter gather elements
+ 			 */
+ 			dev->scsi_host_ptr->sg_tablesize =
+ 				(dev->max_fib_size -
+@@ -1498,9 +1526,8 @@ static void io_callback(void *context, struct fib * fibptr)
+ 				    ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0,
+ 				    0, 0);
+ 		memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
+-		  (sizeof(dev->fsa_dev[cid].sense_data) > sizeof(scsicmd->sense_buffer))
+-		    ? sizeof(scsicmd->sense_buffer)
+-		    : sizeof(dev->fsa_dev[cid].sense_data));
++		       min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data),
++			     SCSI_SENSE_BUFFERSIZE));
+ 	}
+ 	aac_fib_complete(fibptr);
+ 	aac_fib_free(fibptr);
+@@ -1524,7 +1551,7 @@ static int aac_read(struct scsi_cmnd * scsicmd)
+ 	case READ_6:
+ 		dprintk((KERN_DEBUG "aachba: received a read(6) command on id %d.\n", scmd_id(scsicmd)));
+ 
+-		lba = ((scsicmd->cmnd[1] & 0x1F) << 16) | 
++		lba = ((scsicmd->cmnd[1] & 0x1F) << 16) |
+ 			(scsicmd->cmnd[2] << 8) | scsicmd->cmnd[3];
+ 		count = scsicmd->cmnd[4];
+ 
+@@ -1534,32 +1561,32 @@ static int aac_read(struct scsi_cmnd * scsicmd)
+ 	case READ_16:
+ 		dprintk((KERN_DEBUG "aachba: received a read(16) command on id %d.\n", scmd_id(scsicmd)));
+ 
+-		lba = 	((u64)scsicmd->cmnd[2] << 56) |
+-		 	((u64)scsicmd->cmnd[3] << 48) |
++		lba =	((u64)scsicmd->cmnd[2] << 56) |
++			((u64)scsicmd->cmnd[3] << 48) |
+ 			((u64)scsicmd->cmnd[4] << 40) |
+ 			((u64)scsicmd->cmnd[5] << 32) |
+-			((u64)scsicmd->cmnd[6] << 24) | 
++			((u64)scsicmd->cmnd[6] << 24) |
+ 			(scsicmd->cmnd[7] << 16) |
+ 			(scsicmd->cmnd[8] << 8) | scsicmd->cmnd[9];
+-		count = (scsicmd->cmnd[10] << 24) | 
++		count = (scsicmd->cmnd[10] << 24) |
+ 			(scsicmd->cmnd[11] << 16) |
+ 			(scsicmd->cmnd[12] << 8) | scsicmd->cmnd[13];
  		break;
- 	case 0x04: /* Invalidate track. */
-@@ -1110,43 +1353,28 @@ dasd_eckd_format_device(struct dasd_device * device,
- 			ccw++;
- 		}
+ 	case READ_12:
+ 		dprintk((KERN_DEBUG "aachba: received a read(12) command on id %d.\n", scmd_id(scsicmd)));
+ 
+-		lba = ((u64)scsicmd->cmnd[2] << 24) | 
++		lba = ((u64)scsicmd->cmnd[2] << 24) |
+ 			(scsicmd->cmnd[3] << 16) |
+-		    	(scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5];
+-		count = (scsicmd->cmnd[6] << 24) | 
++			(scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5];
++		count = (scsicmd->cmnd[6] << 24) |
+ 			(scsicmd->cmnd[7] << 16) |
+-		      	(scsicmd->cmnd[8] << 8) | scsicmd->cmnd[9];
++			(scsicmd->cmnd[8] << 8) | scsicmd->cmnd[9];
+ 		break;
+ 	default:
+ 		dprintk((KERN_DEBUG "aachba: received a read(10) command on id %d.\n", scmd_id(scsicmd)));
+ 
+-		lba = ((u64)scsicmd->cmnd[2] << 24) | 
+-			(scsicmd->cmnd[3] << 16) | 
++		lba = ((u64)scsicmd->cmnd[2] << 24) |
++			(scsicmd->cmnd[3] << 16) |
+ 			(scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5];
+ 		count = (scsicmd->cmnd[7] << 8) | scsicmd->cmnd[8];
+ 		break;
+@@ -1584,7 +1611,7 @@ static int aac_read(struct scsi_cmnd * scsicmd)
+ 		scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
+ 		return 0;
  	}
--	fcp->device = device;
--	fcp->retries = 2;	/* set retry counter to enable ERP */
-+	fcp->startdev = device;
-+	fcp->memdev = device;
-+	clear_bit(DASD_CQR_FLAGS_USE_ERP, &fcp->flags);
-+	fcp->retries = 5;	/* set retry counter to enable default ERP */
- 	fcp->buildclk = get_clock();
- 	fcp->status = DASD_CQR_FILLED;
- 	return fcp;
- }
+-		
++
+ 	printk(KERN_WARNING "aac_read: aac_fib_send failed with status: %d.\n", status);
+ 	/*
+ 	 *	For some reason, the Fib didn't queue, return QUEUE_FULL
+@@ -1619,11 +1646,11 @@ static int aac_write(struct scsi_cmnd * scsicmd)
+ 	} else if (scsicmd->cmnd[0] == WRITE_16) { /* 16 byte command */
+ 		dprintk((KERN_DEBUG "aachba: received a write(16) command on id %d.\n", scmd_id(scsicmd)));
  
--static dasd_era_t
--dasd_eckd_examine_error(struct dasd_ccw_req * cqr, struct irb * irb)
-+static void dasd_eckd_handle_terminated_request(struct dasd_ccw_req *cqr)
- {
--	struct dasd_device *device = (struct dasd_device *) cqr->device;
--	struct ccw_device *cdev = device->cdev;
--
--	if (irb->scsw.cstat == 0x00 &&
--	    irb->scsw.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))
--		return dasd_era_none;
--
--	switch (cdev->id.cu_type) {
--	case 0x3990:
--	case 0x2105:
--	case 0x2107:
--	case 0x1750:
--		return dasd_3990_erp_examine(cqr, irb);
--	case 0x9343:
--		return dasd_9343_erp_examine(cqr, irb);
--	case 0x3880:
--	default:
--		DEV_MESSAGE(KERN_WARNING, device, "%s",
--			    "default (unknown CU type) - RECOVERABLE return");
--		return dasd_era_recover;
-+	cqr->status = DASD_CQR_FILLED;
-+	if (cqr->block && (cqr->startdev != cqr->block->base)) {
-+		dasd_eckd_reset_ccw_to_base_io(cqr);
-+		cqr->startdev = cqr->block->base;
+-		lba = 	((u64)scsicmd->cmnd[2] << 56) |
++		lba =	((u64)scsicmd->cmnd[2] << 56) |
+ 			((u64)scsicmd->cmnd[3] << 48) |
+ 			((u64)scsicmd->cmnd[4] << 40) |
+ 			((u64)scsicmd->cmnd[5] << 32) |
+-			((u64)scsicmd->cmnd[6] << 24) | 
++			((u64)scsicmd->cmnd[6] << 24) |
+ 			(scsicmd->cmnd[7] << 16) |
+ 			(scsicmd->cmnd[8] << 8) | scsicmd->cmnd[9];
+ 		count = (scsicmd->cmnd[10] << 24) | (scsicmd->cmnd[11] << 16) |
+@@ -1712,8 +1739,8 @@ static void synchronize_callback(void *context, struct fib *fibptr)
+ 				    ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0,
+ 				    0, 0);
+ 		memcpy(cmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
+-		  min(sizeof(dev->fsa_dev[cid].sense_data),
+-			  sizeof(cmd->sense_buffer)));
++		       min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data),
++			     SCSI_SENSE_BUFFERSIZE));
  	}
--}
-+};
  
- static dasd_erp_fn_t
- dasd_eckd_erp_action(struct dasd_ccw_req * cqr)
- {
--	struct dasd_device *device = (struct dasd_device *) cqr->device;
-+	struct dasd_device *device = (struct dasd_device *) cqr->startdev;
- 	struct ccw_device *cdev = device->cdev;
+ 	aac_fib_complete(fibptr);
+@@ -1798,7 +1825,7 @@ static int aac_synchronize(struct scsi_cmnd *scsicmd)
+ 	if (active)
+ 		return SCSI_MLQUEUE_DEVICE_BUSY;
  
- 	switch (cdev->id.cu_type) {
-@@ -1168,8 +1396,37 @@ dasd_eckd_erp_postaction(struct dasd_ccw_req * cqr)
- 	return dasd_default_erp_postaction;
- }
+-	aac = (struct aac_dev *)scsicmd->device->host->hostdata;
++	aac = (struct aac_dev *)sdev->host->hostdata;
+ 	if (aac->in_reset)
+ 		return SCSI_MLQUEUE_HOST_BUSY;
  
--static struct dasd_ccw_req *
--dasd_eckd_build_cp(struct dasd_device * device, struct request *req)
-+
-+static void dasd_eckd_handle_unsolicited_interrupt(struct dasd_device *device,
-+						   struct irb *irb)
-+{
-+	char mask;
-+
-+	/* first of all check for state change pending interrupt */
-+	mask = DEV_STAT_ATTENTION | DEV_STAT_DEV_END | DEV_STAT_UNIT_EXCEP;
-+	if ((irb->scsw.dstat & mask) == mask) {
-+		dasd_generic_handle_state_change(device);
-+		return;
-+	}
-+
-+	/* summary unit check */
-+	if ((irb->scsw.dstat & DEV_STAT_UNIT_CHECK) && irb->ecw[7] == 0x0D) {
-+		dasd_alias_handle_summary_unit_check(device, irb);
-+		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);
-+
-+	return;
-+};
+@@ -1850,14 +1877,14 @@ static int aac_synchronize(struct scsi_cmnd *scsicmd)
+  *	Emulate a SCSI command and queue the required request for the
+  *	aacraid firmware.
+  */
+- 
 +
-+static struct dasd_ccw_req *dasd_eckd_build_cp(struct dasd_device *startdev,
-+					       struct dasd_block *block,
-+					       struct request *req)
+ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
  {
- 	struct dasd_eckd_private *private;
- 	unsigned long *idaws;
-@@ -1185,8 +1442,11 @@ dasd_eckd_build_cp(struct dasd_device * device, struct request *req)
- 	sector_t first_trk, last_trk;
- 	unsigned int first_offs, last_offs;
- 	unsigned char cmd, rcmd;
-+	int use_prefix;
-+	struct dasd_device *basedev;
+ 	u32 cid;
+ 	struct Scsi_Host *host = scsicmd->device->host;
+ 	struct aac_dev *dev = (struct aac_dev *)host->hostdata;
+ 	struct fsa_dev_info *fsa_dev_ptr = dev->fsa_dev;
+-	
++
+ 	if (fsa_dev_ptr == NULL)
+ 		return -1;
+ 	/*
+@@ -1898,7 +1925,8 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
+ 				}
+ 			}
+ 		} else {  /* check for physical non-dasd devices */
+-			if ((dev->nondasd_support == 1) || expose_physicals) {
++			if (dev->nondasd_support || expose_physicals ||
++					dev->jbod) {
+ 				if (dev->in_reset)
+ 					return -1;
+ 				return aac_send_srb_fib(scsicmd);
+@@ -1913,7 +1941,7 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
+ 	 * else Command for the controller itself
+ 	 */
+ 	else if ((scsicmd->cmnd[0] != INQUIRY) &&	/* only INQUIRY & TUR cmnd supported for controller */
+-		(scsicmd->cmnd[0] != TEST_UNIT_READY)) 
++		(scsicmd->cmnd[0] != TEST_UNIT_READY))
+ 	{
+ 		dprintk((KERN_WARNING "Only INQUIRY & TUR command supported for controller, rcvd = 0x%x.\n", scsicmd->cmnd[0]));
+ 		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION;
+@@ -1922,9 +1950,8 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
+ 			    SENCODE_INVALID_COMMAND,
+ 			    ASENCODE_INVALID_COMMAND, 0, 0, 0, 0);
+ 		memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
+-		  (sizeof(dev->fsa_dev[cid].sense_data) > sizeof(scsicmd->sense_buffer))
+-		    ? sizeof(scsicmd->sense_buffer)
+-		    : sizeof(dev->fsa_dev[cid].sense_data));
++		       min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data),
++			     SCSI_SENSE_BUFFERSIZE));
+ 		scsicmd->scsi_done(scsicmd);
+ 		return 0;
+ 	}
+@@ -1939,7 +1966,7 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
+ 		dprintk((KERN_DEBUG "INQUIRY command, ID: %d.\n", cid));
+ 		memset(&inq_data, 0, sizeof (struct inquiry_data));
  
--	private = (struct dasd_eckd_private *) device->private;
-+	basedev = block->base;
-+	private = (struct dasd_eckd_private *) basedev->private;
- 	if (rq_data_dir(req) == READ)
- 		cmd = DASD_ECKD_CCW_READ_MT;
- 	else if (rq_data_dir(req) == WRITE)
-@@ -1194,13 +1454,13 @@ dasd_eckd_build_cp(struct dasd_device * device, struct request *req)
- 	else
- 		return ERR_PTR(-EINVAL);
- 	/* Calculate number of blocks/records per track. */
--	blksize = device->bp_block;
-+	blksize = block->bp_block;
- 	blk_per_trk = recs_per_track(&private->rdc_data, 0, blksize);
- 	/* Calculate record id of first and last block. */
--	first_rec = first_trk = req->sector >> device->s2b_shift;
-+	first_rec = first_trk = req->sector >> block->s2b_shift;
- 	first_offs = sector_div(first_trk, blk_per_trk);
- 	last_rec = last_trk =
--		(req->sector + req->nr_sectors - 1) >> device->s2b_shift;
-+		(req->sector + req->nr_sectors - 1) >> block->s2b_shift;
- 	last_offs = sector_div(last_trk, blk_per_trk);
- 	/* Check struct bio and count the number of blocks for the request. */
- 	count = 0;
-@@ -1209,20 +1469,33 @@ dasd_eckd_build_cp(struct dasd_device * device, struct request *req)
- 		if (bv->bv_len & (blksize - 1))
- 			/* Eckd can only do full blocks. */
- 			return ERR_PTR(-EINVAL);
--		count += bv->bv_len >> (device->s2b_shift + 9);
-+		count += bv->bv_len >> (block->s2b_shift + 9);
- #if defined(CONFIG_64BIT)
- 		if (idal_is_needed (page_address(bv->bv_page), bv->bv_len))
--			cidaw += bv->bv_len >> (device->s2b_shift + 9);
-+			cidaw += bv->bv_len >> (block->s2b_shift + 9);
- #endif
+-		if (scsicmd->cmnd[1] & 0x1 ) {
++		if (scsicmd->cmnd[1] & 0x1) {
+ 			char *arr = (char *)&inq_data;
+ 
+ 			/* EVPD bit set */
+@@ -1974,10 +2001,9 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
+ 				  ASENCODE_NO_SENSE, 0, 7, 2, 0);
+ 				memcpy(scsicmd->sense_buffer,
+ 				  &dev->fsa_dev[cid].sense_data,
+-				  (sizeof(dev->fsa_dev[cid].sense_data) >
+-				    sizeof(scsicmd->sense_buffer))
+-				       ? sizeof(scsicmd->sense_buffer)
+-				       : sizeof(dev->fsa_dev[cid].sense_data));
++				  min_t(size_t,
++					sizeof(dev->fsa_dev[cid].sense_data),
++					SCSI_SENSE_BUFFERSIZE));
+ 			}
+ 			scsicmd->scsi_done(scsicmd);
+ 			return 0;
+@@ -2092,7 +2118,7 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
+ 		mode_buf[2] = 0;	/* Device-specific param,
+ 					   bit 8: 0/1 = write enabled/protected
+ 					   bit 4: 0/1 = FUA enabled */
+-		if (dev->raw_io_interface)
++		if (dev->raw_io_interface && ((aac_cache & 5) != 1))
+ 			mode_buf[2] = 0x10;
+ 		mode_buf[3] = 0;	/* Block descriptor length */
+ 		if (((scsicmd->cmnd[2] & 0x3f) == 8) ||
+@@ -2100,7 +2126,8 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
+ 			mode_buf[0] = 6;
+ 			mode_buf[4] = 8;
+ 			mode_buf[5] = 1;
+-			mode_buf[6] = 0x04; /* WCE */
++			mode_buf[6] = ((aac_cache & 6) == 2)
++				? 0 : 0x04; /* WCE */
+ 			mode_buf_length = 7;
+ 			if (mode_buf_length > scsicmd->cmnd[4])
+ 				mode_buf_length = scsicmd->cmnd[4];
+@@ -2123,7 +2150,7 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
+ 		mode_buf[3] = 0;	/* Device-specific param,
+ 					   bit 8: 0/1 = write enabled/protected
+ 					   bit 4: 0/1 = FUA enabled */
+-		if (dev->raw_io_interface)
++		if (dev->raw_io_interface && ((aac_cache & 5) != 1))
+ 			mode_buf[3] = 0x10;
+ 		mode_buf[4] = 0;	/* reserved */
+ 		mode_buf[5] = 0;	/* reserved */
+@@ -2134,7 +2161,8 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
+ 			mode_buf[1] = 9;
+ 			mode_buf[8] = 8;
+ 			mode_buf[9] = 1;
+-			mode_buf[10] = 0x04; /* WCE */
++			mode_buf[10] = ((aac_cache & 6) == 2)
++				? 0 : 0x04; /* WCE */
+ 			mode_buf_length = 11;
+ 			if (mode_buf_length > scsicmd->cmnd[8])
+ 				mode_buf_length = scsicmd->cmnd[8];
+@@ -2179,7 +2207,7 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
+ 		return 0;
  	}
- 	/* Paranoia. */
- 	if (count != last_rec - first_rec + 1)
- 		return ERR_PTR(-EINVAL);
--	/* 1x define extent + 1x locate record + number of blocks */
--	cplength = 2 + count;
--	/* 1x define extent + 1x locate record + cidaws*sizeof(long) */
--	datasize = sizeof(struct DE_eckd_data) + sizeof(struct LO_eckd_data) +
--		cidaw * sizeof(unsigned long);
+ 
+-	switch (scsicmd->cmnd[0]) 
++	switch (scsicmd->cmnd[0])
+ 	{
+ 		case READ_6:
+ 		case READ_10:
+@@ -2192,11 +2220,11 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
+ 			 *	corresponds to a container. Needed to convert
+ 			 *	containers to /dev/sd device names
+ 			 */
+-			 
 +
-+	/* use the prefix command if available */
-+	use_prefix = private->features.feature[8] & 0x01;
-+	if (use_prefix) {
-+		/* 1x prefix + number of blocks */
-+		cplength = 2 + count;
-+		/* 1x prefix + cidaws*sizeof(long) */
-+		datasize = sizeof(struct PFX_eckd_data) +
-+			sizeof(struct LO_eckd_data) +
-+			cidaw * sizeof(unsigned long);
-+	} else {
-+		/* 1x define extent + 1x locate record + number of blocks */
-+		cplength = 2 + count;
-+		/* 1x define extent + 1x locate record + cidaws*sizeof(long) */
-+		datasize = sizeof(struct DE_eckd_data) +
-+			sizeof(struct LO_eckd_data) +
-+			cidaw * sizeof(unsigned long);
-+	}
- 	/* Find out the number of additional locate record ccws for cdl. */
- 	if (private->uses_cdl && first_rec < 2*blk_per_trk) {
- 		if (last_rec >= 2*blk_per_trk)
-@@ -1232,26 +1505,42 @@ dasd_eckd_build_cp(struct dasd_device * device, struct request *req)
- 	}
- 	/* Allocate the ccw request. */
- 	cqr = dasd_smalloc_request(dasd_eckd_discipline.name,
--				   cplength, datasize, device);
-+				   cplength, datasize, startdev);
- 	if (IS_ERR(cqr))
- 		return cqr;
- 	ccw = cqr->cpaddr;
--	/* First ccw is define extent. */
--	if (define_extent(ccw++, cqr->data, first_trk,
--			  last_trk, cmd, device) == -EAGAIN) {
--		/* Clock not in sync and XRC is enabled. Try again later. */
--		dasd_sfree_request(cqr, device);
--		return ERR_PTR(-EAGAIN);
-+	/* First ccw is define extent or prefix. */
-+	if (use_prefix) {
-+		if (prefix(ccw++, cqr->data, first_trk,
-+			   last_trk, cmd, basedev, startdev) == -EAGAIN) {
-+			/* Clock not in sync and XRC is enabled.
-+			 * Try again later.
-+			 */
-+			dasd_sfree_request(cqr, startdev);
-+			return ERR_PTR(-EAGAIN);
-+		}
-+		idaws = (unsigned long *) (cqr->data +
-+					   sizeof(struct PFX_eckd_data));
-+	} else {
-+		if (define_extent(ccw++, cqr->data, first_trk,
-+				  last_trk, cmd, startdev) == -EAGAIN) {
-+			/* Clock not in sync and XRC is enabled.
-+			 * Try again later.
-+			 */
-+			dasd_sfree_request(cqr, startdev);
-+			return ERR_PTR(-EAGAIN);
-+		}
-+		idaws = (unsigned long *) (cqr->data +
-+					   sizeof(struct DE_eckd_data));
+ 			if (scsicmd->request->rq_disk)
+ 				strlcpy(fsa_dev_ptr[cid].devname,
+ 				scsicmd->request->rq_disk->disk_name,
+-			  	min(sizeof(fsa_dev_ptr[cid].devname),
++				min(sizeof(fsa_dev_ptr[cid].devname),
+ 				sizeof(scsicmd->request->rq_disk->disk_name) + 1));
+ 
+ 			return aac_read(scsicmd);
+@@ -2210,9 +2238,16 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
+ 			return aac_write(scsicmd);
+ 
+ 		case SYNCHRONIZE_CACHE:
++			if (((aac_cache & 6) == 6) && dev->cache_protected) {
++				scsicmd->result = DID_OK << 16 |
++					COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
++				scsicmd->scsi_done(scsicmd);
++				return 0;
++			}
+ 			/* Issue FIB to tell Firmware to flush it's cache */
+-			return aac_synchronize(scsicmd);
+-			
++			if ((aac_cache & 6) != 2)
++				return aac_synchronize(scsicmd);
++			/* FALLTHRU */
+ 		default:
+ 			/*
+ 			 *	Unhandled commands
+@@ -2223,9 +2258,9 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
+ 				ILLEGAL_REQUEST, SENCODE_INVALID_COMMAND,
+ 				ASENCODE_INVALID_COMMAND, 0, 0, 0, 0);
+ 			memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
+-			  (sizeof(dev->fsa_dev[cid].sense_data) > sizeof(scsicmd->sense_buffer))
+-			    ? sizeof(scsicmd->sense_buffer)
+-			    : sizeof(dev->fsa_dev[cid].sense_data));
++				min_t(size_t,
++				      sizeof(dev->fsa_dev[cid].sense_data),
++				      SCSI_SENSE_BUFFERSIZE));
+ 			scsicmd->scsi_done(scsicmd);
+ 			return 0;
  	}
- 	/* Build locate_record+read/write/ccws. */
--	idaws = (unsigned long *) (cqr->data + sizeof(struct DE_eckd_data));
- 	LO_data = (struct LO_eckd_data *) (idaws + cidaw);
- 	recid = first_rec;
- 	if (private->uses_cdl == 0 || recid > 2*blk_per_trk) {
- 		/* Only standard blocks so there is just one locate record. */
- 		ccw[-1].flags |= CCW_FLAG_CC;
- 		locate_record(ccw++, LO_data++, first_trk, first_offs + 1,
--			      last_rec - recid + 1, cmd, device, blksize);
-+			      last_rec - recid + 1, cmd, basedev, blksize);
+@@ -2243,7 +2278,7 @@ static int query_disk(struct aac_dev *dev, void __user *arg)
+ 		return -EFAULT;
+ 	if (qd.cnum == -1)
+ 		qd.cnum = qd.id;
+-	else if ((qd.bus == -1) && (qd.id == -1) && (qd.lun == -1)) 
++	else if ((qd.bus == -1) && (qd.id == -1) && (qd.lun == -1))
+ 	{
+ 		if (qd.cnum < 0 || qd.cnum >= dev->maximum_num_containers)
+ 			return -EINVAL;
+@@ -2370,7 +2405,7 @@ static void aac_srb_callback(void *context, struct fib * fibptr)
+ 
+ 	scsicmd->sense_buffer[0] = '\0';  /* Initialize sense valid flag to false */
+ 	/*
+-	 *	Calculate resid for sg 
++	 *	Calculate resid for sg
+ 	 */
+ 
+ 	scsi_set_resid(scsicmd, scsi_bufflen(scsicmd)
+@@ -2385,10 +2420,8 @@ static void aac_srb_callback(void *context, struct fib * fibptr)
+ 	if (le32_to_cpu(srbreply->status) != ST_OK){
+ 		int len;
+ 		printk(KERN_WARNING "aac_srb_callback: srb failed, status = %d\n", le32_to_cpu(srbreply->status));
+-		len = (le32_to_cpu(srbreply->sense_data_size) > 
+-				sizeof(scsicmd->sense_buffer)) ?
+-				sizeof(scsicmd->sense_buffer) : 
+-				le32_to_cpu(srbreply->sense_data_size);
++		len = min_t(u32, le32_to_cpu(srbreply->sense_data_size),
++			    SCSI_SENSE_BUFFERSIZE);
+ 		scsicmd->result = DID_ERROR << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION;
+ 		memcpy(scsicmd->sense_buffer, srbreply->sense_data, len);
  	}
- 	rq_for_each_segment(bv, req, iter) {
- 		dst = page_address(bv->bv_page) + bv->bv_offset;
-@@ -1281,7 +1570,7 @@ dasd_eckd_build_cp(struct dasd_device * device, struct request *req)
- 				ccw[-1].flags |= CCW_FLAG_CC;
- 				locate_record(ccw++, LO_data++,
- 					      trkid, recoffs + 1,
--					      1, rcmd, device, count);
-+					      1, rcmd, basedev, count);
- 			}
- 			/* Locate record for standard blocks ? */
- 			if (private->uses_cdl && recid == 2*blk_per_trk) {
-@@ -1289,7 +1578,7 @@ dasd_eckd_build_cp(struct dasd_device * device, struct request *req)
- 				locate_record(ccw++, LO_data++,
- 					      trkid, recoffs + 1,
- 					      last_rec - recid + 1,
--					      cmd, device, count);
-+					      cmd, basedev, count);
- 			}
- 			/* Read/write ccw. */
- 			ccw[-1].flags |= CCW_FLAG_CC;
-@@ -1310,7 +1599,9 @@ dasd_eckd_build_cp(struct dasd_device * device, struct request *req)
+@@ -2412,7 +2445,7 @@ static void aac_srb_callback(void *context, struct fib * fibptr)
+ 		case  WRITE_12:
+ 		case  READ_16:
+ 		case  WRITE_16:
+-			if(le32_to_cpu(srbreply->data_xfer_length) < scsicmd->underflow ) {
++			if (le32_to_cpu(srbreply->data_xfer_length) < scsicmd->underflow) {
+ 				printk(KERN_WARNING"aacraid: SCSI CMD underflow\n");
+ 			} else {
+ 				printk(KERN_WARNING"aacraid: SCSI CMD Data Overrun\n");
+@@ -2481,26 +2514,23 @@ static void aac_srb_callback(void *context, struct fib * fibptr)
+ 		printk("aacraid: SRB ERROR(%u) %s scsi cmd 0x%x - scsi status 0x%x\n",
+ 			le32_to_cpu(srbreply->srb_status) & 0x3F,
+ 			aac_get_status_string(
+-				le32_to_cpu(srbreply->srb_status) & 0x3F), 
+-			scsicmd->cmnd[0], 
++				le32_to_cpu(srbreply->srb_status) & 0x3F),
++			scsicmd->cmnd[0],
+ 			le32_to_cpu(srbreply->scsi_status));
+ #endif
+ 		scsicmd->result = DID_ERROR << 16 | COMMAND_COMPLETE << 8;
+ 		break;
  	}
- 	if (req->cmd_flags & REQ_FAILFAST)
- 		set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags);
--	cqr->device = device;
-+	cqr->startdev = startdev;
-+	cqr->memdev = startdev;
-+	cqr->block = block;
- 	cqr->expires = 5 * 60 * HZ;	/* 5 minutes */
- 	cqr->lpm = private->path_data.ppm;
- 	cqr->retries = 256;
-@@ -1333,10 +1624,10 @@ dasd_eckd_free_cp(struct dasd_ccw_req *cqr, struct request *req)
- 
- 	if (!dasd_page_cache)
- 		goto out;
--	private = (struct dasd_eckd_private *) cqr->device->private;
--	blksize = cqr->device->bp_block;
-+	private = (struct dasd_eckd_private *) cqr->block->base->private;
-+	blksize = cqr->block->bp_block;
- 	blk_per_trk = recs_per_track(&private->rdc_data, 0, blksize);
--	recid = req->sector >> cqr->device->s2b_shift;
-+	recid = req->sector >> cqr->block->s2b_shift;
- 	ccw = cqr->cpaddr;
- 	/* Skip over define extent & locate record. */
- 	ccw++;
-@@ -1367,10 +1658,71 @@ dasd_eckd_free_cp(struct dasd_ccw_req *cqr, struct request *req)
+-	if (le32_to_cpu(srbreply->scsi_status) == 0x02 ){  // Check Condition
++	if (le32_to_cpu(srbreply->scsi_status) == SAM_STAT_CHECK_CONDITION) {
+ 		int len;
+ 		scsicmd->result |= SAM_STAT_CHECK_CONDITION;
+-		len = (le32_to_cpu(srbreply->sense_data_size) > 
+-				sizeof(scsicmd->sense_buffer)) ?
+-				sizeof(scsicmd->sense_buffer) :
+-				le32_to_cpu(srbreply->sense_data_size);
++		len = min_t(u32, le32_to_cpu(srbreply->sense_data_size),
++			    SCSI_SENSE_BUFFERSIZE);
+ #ifdef AAC_DETAILED_STATUS_INFO
+ 		printk(KERN_WARNING "aac_srb_callback: check condition, status = %d len=%d\n",
+ 					le32_to_cpu(srbreply->status), len);
+ #endif
+ 		memcpy(scsicmd->sense_buffer, srbreply->sense_data, len);
+-		
  	}
- out:
- 	status = cqr->status == DASD_CQR_DONE;
--	dasd_sfree_request(cqr, cqr->device);
-+	dasd_sfree_request(cqr, cqr->memdev);
- 	return status;
- }
+ 	/*
+ 	 * OR in the scsi status (already shifted up a bit)
+@@ -2517,7 +2547,7 @@ static void aac_srb_callback(void *context, struct fib * fibptr)
+  * aac_send_scb_fib
+  * @scsicmd: the scsi command block
+  *
+- * This routine will form a FIB and fill in the aac_srb from the 
++ * This routine will form a FIB and fill in the aac_srb from the
+  * scsicmd passed in.
+  */
  
-+/*
-+ * Modify ccw chain in cqr so it can be started on a base device.
-+ *
-+ * Note that this is not enough to restart the cqr!
-+ * Either reset cqr->startdev as well (summary unit check handling)
-+ * or restart via separate cqr (as in ERP handling).
-+ */
-+void dasd_eckd_reset_ccw_to_base_io(struct dasd_ccw_req *cqr)
-+{
-+	struct ccw1 *ccw;
-+	struct PFX_eckd_data *pfxdata;
-+
-+	ccw = cqr->cpaddr;
-+	pfxdata = cqr->data;
-+
-+	if (ccw->cmd_code == DASD_ECKD_CCW_PFX) {
-+		pfxdata->validity.verify_base = 0;
-+		pfxdata->validity.hyper_pav = 0;
-+	}
-+}
-+
-+#define DASD_ECKD_CHANQ_MAX_SIZE 4
-+
-+static struct dasd_ccw_req *dasd_eckd_build_alias_cp(struct dasd_device *base,
-+						     struct dasd_block *block,
-+						     struct request *req)
-+{
-+	struct dasd_eckd_private *private;
-+	struct dasd_device *startdev;
-+	unsigned long flags;
-+	struct dasd_ccw_req *cqr;
-+
-+	startdev = dasd_alias_get_start_dev(base);
-+	if (!startdev)
-+		startdev = base;
-+	private = (struct dasd_eckd_private *) startdev->private;
-+	if (private->count >= DASD_ECKD_CHANQ_MAX_SIZE)
-+		return ERR_PTR(-EBUSY);
+@@ -2731,7 +2761,7 @@ static struct aac_srb_status_info srb_status_info[] = {
+ 	{ SRB_STATUS_ERROR_RECOVERY,	"Error Recovery"},
+ 	{ SRB_STATUS_NOT_STARTED,	"Not Started"},
+ 	{ SRB_STATUS_NOT_IN_USE,	"Not In Use"},
+-    	{ SRB_STATUS_FORCE_ABORT,	"Force Abort"},
++	{ SRB_STATUS_FORCE_ABORT,	"Force Abort"},
+ 	{ SRB_STATUS_DOMAIN_VALIDATION_FAIL,"Domain Validation Failure"},
+ 	{ 0xff,				"Unknown Error"}
+ };
+diff --git a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h
+index 9abba8b..3195d29 100644
+--- a/drivers/scsi/aacraid/aacraid.h
++++ b/drivers/scsi/aacraid/aacraid.h
+@@ -1,4 +1,4 @@
+-#if (!defined(dprintk))
++#ifndef dprintk
+ # define dprintk(x)
+ #endif
+ /* eg: if (nblank(dprintk(x))) */
+@@ -12,7 +12,7 @@
+  *----------------------------------------------------------------------------*/
+ 
+ #ifndef AAC_DRIVER_BUILD
+-# define AAC_DRIVER_BUILD 2449
++# define AAC_DRIVER_BUILD 2455
+ # define AAC_DRIVER_BRANCH "-ms"
+ #endif
+ #define MAXIMUM_NUM_CONTAINERS	32
+@@ -50,9 +50,9 @@ struct diskparm
+ /*
+  *	Firmware constants
+  */
+- 
 +
-+	spin_lock_irqsave(get_ccwdev_lock(startdev->cdev), flags);
-+	private->count++;
-+	cqr = dasd_eckd_build_cp(startdev, block, req);
-+	if (IS_ERR(cqr))
-+		private->count--;
-+	spin_unlock_irqrestore(get_ccwdev_lock(startdev->cdev), flags);
-+	return cqr;
-+}
+ #define		CT_NONE			0
+-#define 	CT_OK        		218
++#define		CT_OK			218
+ #define		FT_FILESYS	8	/* ADAPTEC's "FSA"(tm) filesystem */
+ #define		FT_DRIVE	9	/* physical disk - addressable in scsi by bus/id/lun */
+ 
+@@ -107,12 +107,12 @@ struct user_sgentryraw {
+ 
+ struct sgmap {
+ 	__le32		count;
+-	struct sgentry	sg[1]; 
++	struct sgentry	sg[1];
+ };
+ 
+ struct user_sgmap {
+ 	u32		count;
+-	struct user_sgentry	sg[1]; 
++	struct user_sgentry	sg[1];
+ };
+ 
+ struct sgmap64 {
+@@ -137,18 +137,18 @@ struct user_sgmapraw {
+ 
+ struct creation_info
+ {
+-	u8 		buildnum;		/* e.g., 588 */
+-	u8 		usec;			/* e.g., 588 */
+-	u8	 	via;			/* e.g., 1 = FSU,
+-						 * 	 2 = API
++	u8		buildnum;		/* e.g., 588 */
++	u8		usec;			/* e.g., 588 */
++	u8		via;			/* e.g., 1 = FSU,
++						 *	 2 = API
+ 						 */
+-	u8	 	year;		 	/* e.g., 1997 = 97 */
++	u8		year;			/* e.g., 1997 = 97 */
+ 	__le32		date;			/*
+-						 * unsigned 	Month		:4;	// 1 - 12
+-						 * unsigned 	Day		:6;	// 1 - 32
+-						 * unsigned 	Hour		:6;	// 0 - 23
+-						 * unsigned 	Minute		:6;	// 0 - 60
+-						 * unsigned 	Second		:6;	// 0 - 60
++						 * unsigned	Month		:4;	// 1 - 12
++						 * unsigned	Day		:6;	// 1 - 32
++						 * unsigned	Hour		:6;	// 0 - 23
++						 * unsigned	Minute		:6;	// 0 - 60
++						 * unsigned	Second		:6;	// 0 - 60
+ 						 */
+ 	__le32		serial[2];			/* e.g., 0x1DEADB0BFAFAF001 */
+ };
+@@ -184,7 +184,7 @@ struct creation_info
+ /*
+  *	Set the queues on a 16 byte alignment
+  */
+- 
 +
-+static int dasd_eckd_free_alias_cp(struct dasd_ccw_req *cqr,
-+				   struct request *req)
-+{
-+	struct dasd_eckd_private *private;
-+	unsigned long flags;
+ #define QUEUE_ALIGNMENT		16
+ 
+ /*
+@@ -203,9 +203,9 @@ struct aac_entry {
+  *	The adapter assumes the ProducerIndex and ConsumerIndex are grouped
+  *	adjacently and in that order.
+  */
+- 
 +
-+	spin_lock_irqsave(get_ccwdev_lock(cqr->memdev->cdev), flags);
-+	private = (struct dasd_eckd_private *) cqr->memdev->private;
-+	private->count--;
-+	spin_unlock_irqrestore(get_ccwdev_lock(cqr->memdev->cdev), flags);
-+	return dasd_eckd_free_cp(cqr, req);
-+}
+ struct aac_qhdr {
+-	__le64 header_addr;/* Address to hand the adapter to access 
++	__le64 header_addr;/* Address to hand the adapter to access
+ 			      to this queue head */
+ 	__le32 *producer; /* The producer index for this queue (host address) */
+ 	__le32 *consumer; /* The consumer index for this queue (host address) */
+@@ -215,7 +215,7 @@ struct aac_qhdr {
+  *	Define all the events which the adapter would like to notify
+  *	the host of.
+  */
+- 
 +
- static int
- dasd_eckd_fill_info(struct dasd_device * device,
- 		    struct dasd_information2_t * info)
-@@ -1384,9 +1736,9 @@ dasd_eckd_fill_info(struct dasd_device * device,
- 	info->characteristics_size = sizeof(struct dasd_eckd_characteristics);
- 	memcpy(info->characteristics, &private->rdc_data,
- 	       sizeof(struct dasd_eckd_characteristics));
--	info->confdata_size = sizeof (struct dasd_eckd_confdata);
-+	info->confdata_size = sizeof(struct dasd_eckd_confdata);
- 	memcpy(info->configuration_data, &private->conf_data,
--	       sizeof (struct dasd_eckd_confdata));
-+	       sizeof(struct dasd_eckd_confdata));
- 	return 0;
- }
+ #define		HostNormCmdQue		1	/* Change in host normal priority command queue */
+ #define		HostHighCmdQue		2	/* Change in host high priority command queue */
+ #define		HostNormRespQue		3	/* Change in host normal priority response queue */
+@@ -286,17 +286,17 @@ struct aac_fibhdr {
+ 	u8 StructType;		/* Type FIB */
+ 	u8 Flags;		/* Flags for FIB */
+ 	__le16 Size;		/* Size of this FIB in bytes */
+-	__le16 SenderSize;	/* Size of the FIB in the sender 
++	__le16 SenderSize;	/* Size of the FIB in the sender
+ 				   (for response sizing) */
+ 	__le32 SenderFibAddress;  /* Host defined data in the FIB */
+-	__le32 ReceiverFibAddress;/* Logical address of this FIB for 
++	__le32 ReceiverFibAddress;/* Logical address of this FIB for
+ 				     the adapter */
+ 	u32 SenderData;		/* Place holder for the sender to store data */
+ 	union {
+ 		struct {
+-		    __le32 _ReceiverTimeStart; 	/* Timestamp for 
++		    __le32 _ReceiverTimeStart;	/* Timestamp for
+ 						   receipt of fib */
+-		    __le32 _ReceiverTimeDone;	/* Timestamp for 
++		    __le32 _ReceiverTimeDone;	/* Timestamp for
+ 						   completion of fib */
+ 		} _s;
+ 	} _u;
+@@ -311,7 +311,7 @@ struct hw_fib {
+  *	FIB commands
+  */
  
-@@ -1419,7 +1771,8 @@ dasd_eckd_release(struct dasd_device *device)
-         cqr->cpaddr->flags |= CCW_FLAG_SLI;
-         cqr->cpaddr->count = 32;
- 	cqr->cpaddr->cda = (__u32)(addr_t) cqr->data;
--	cqr->device = device;
-+	cqr->startdev = device;
-+	cqr->memdev = device;
- 	clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
- 	set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags);
- 	cqr->retries = 2;	/* set retry counter to enable basic ERP */
-@@ -1429,7 +1782,7 @@ dasd_eckd_release(struct dasd_device *device)
+-#define 	TestCommandResponse		1
++#define		TestCommandResponse		1
+ #define		TestAdapterCommand		2
+ /*
+  *	Lowlevel and comm commands
+@@ -350,10 +350,6 @@ struct hw_fib {
+ #define		ContainerCommand64		501
+ #define		ContainerRawIo			502
+ /*
+- *	Cluster Commands
+- */
+-#define		ClusterCommand	 		550
+-/*
+  *	Scsi Port commands (scsi passthrough)
+  */
+ #define		ScsiPortCommand			600
+@@ -375,19 +371,19 @@ struct hw_fib {
+  */
  
- 	rc = dasd_sleep_on_immediatly(cqr);
+ enum fib_xfer_state {
+-	HostOwned 			= (1<<0),
+-	AdapterOwned 			= (1<<1),
+-	FibInitialized 			= (1<<2),
+-	FibEmpty 			= (1<<3),
+-	AllocatedFromPool 		= (1<<4),
+-	SentFromHost 			= (1<<5),
+-	SentFromAdapter 		= (1<<6),
+-	ResponseExpected 		= (1<<7),
+-	NoResponseExpected 		= (1<<8),
+-	AdapterProcessed 		= (1<<9),
+-	HostProcessed 			= (1<<10),
+-	HighPriority 			= (1<<11),
+-	NormalPriority 			= (1<<12),
++	HostOwned			= (1<<0),
++	AdapterOwned			= (1<<1),
++	FibInitialized			= (1<<2),
++	FibEmpty			= (1<<3),
++	AllocatedFromPool		= (1<<4),
++	SentFromHost			= (1<<5),
++	SentFromAdapter			= (1<<6),
++	ResponseExpected		= (1<<7),
++	NoResponseExpected		= (1<<8),
++	AdapterProcessed		= (1<<9),
++	HostProcessed			= (1<<10),
++	HighPriority			= (1<<11),
++	NormalPriority			= (1<<12),
+ 	Async				= (1<<13),
+ 	AsyncIo				= (1<<13),	// rpbfix: remove with new regime
+ 	PageFileIo			= (1<<14),	// rpbfix: remove with new regime
+@@ -420,7 +416,7 @@ struct aac_init
+ 	__le32	AdapterFibAlign;
+ 	__le32	printfbuf;
+ 	__le32	printfbufsiz;
+-	__le32	HostPhysMemPages;   /* number of 4k pages of host 
++	__le32	HostPhysMemPages;   /* number of 4k pages of host
+ 				       physical memory */
+ 	__le32	HostElapsedSeconds; /* number of seconds since 1970. */
+ 	/*
+@@ -481,7 +477,7 @@ struct adapter_ops
  
--	dasd_sfree_request(cqr, cqr->device);
-+	dasd_sfree_request(cqr, cqr->memdev);
- 	return rc;
- }
+ struct aac_driver_ident
+ {
+-	int 	(*init)(struct aac_dev *dev);
++	int	(*init)(struct aac_dev *dev);
+ 	char *	name;
+ 	char *	vname;
+ 	char *	model;
+@@ -489,7 +485,7 @@ struct aac_driver_ident
+ 	int	quirks;
+ };
+ /*
+- * Some adapter firmware needs communication memory 
++ * Some adapter firmware needs communication memory
+  * below 2gig. This tells the init function to set the
+  * dma mask such that fib memory will be allocated where the
+  * adapter firmware can get to it.
+@@ -521,33 +517,39 @@ struct aac_driver_ident
+ #define AAC_QUIRK_17SG	0x0010
  
-@@ -1459,7 +1812,8 @@ dasd_eckd_reserve(struct dasd_device *device)
-         cqr->cpaddr->flags |= CCW_FLAG_SLI;
-         cqr->cpaddr->count = 32;
- 	cqr->cpaddr->cda = (__u32)(addr_t) cqr->data;
--	cqr->device = device;
-+	cqr->startdev = device;
-+	cqr->memdev = device;
- 	clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
- 	set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags);
- 	cqr->retries = 2;	/* set retry counter to enable basic ERP */
-@@ -1469,7 +1823,7 @@ dasd_eckd_reserve(struct dasd_device *device)
+ /*
++ *	Some adapter firmware does not support 64 bit scsi passthrough
++ * commands.
++ */
++#define AAC_QUIRK_SCSI_32	0x0020
++
++/*
+  *	The adapter interface specs all queues to be located in the same
+  *	physically contigous block. The host structure that defines the
+  *	commuication queues will assume they are each a separate physically
+  *	contigous memory region that will support them all being one big
+- *	contigous block. 
++ *	contigous block.
+  *	There is a command and response queue for each level and direction of
+  *	commuication. These regions are accessed by both the host and adapter.
+  */
+- 
++
+ struct aac_queue {
+-	u64		 	logical;	/*address we give the adapter */
++	u64			logical;	/*address we give the adapter */
+ 	struct aac_entry	*base;		/*system virtual address */
+-	struct aac_qhdr 	headers;       	/*producer,consumer q headers*/
+-	u32	 		entries;	/*Number of queue entries */
++	struct aac_qhdr		headers;	/*producer,consumer q headers*/
++	u32			entries;	/*Number of queue entries */
+ 	wait_queue_head_t	qfull;		/*Event to wait on if q full */
+ 	wait_queue_head_t	cmdready;	/*Cmd ready from the adapter */
+-                  /* This is only valid for adapter to host command queues. */ 
+-	spinlock_t	 	*lock;		/* Spinlock for this queue must take this lock before accessing the lock */
++		/* This is only valid for adapter to host command queues. */
++	spinlock_t		*lock;		/* Spinlock for this queue must take this lock before accessing the lock */
+ 	spinlock_t		lockdata;	/* Actual lock (used only on one side of the lock) */
+-	struct list_head 	cmdq;	   	/* A queue of FIBs which need to be prcessed by the FS thread. This is */
+-                                		/* only valid for command queues which receive entries from the adapter. */
++	struct list_head	cmdq;		/* A queue of FIBs which need to be prcessed by the FS thread. This is */
++						/* only valid for command queues which receive entries from the adapter. */
+ 	u32			numpending;	/* Number of entries on outstanding queue. */
+ 	struct aac_dev *	dev;		/* Back pointer to adapter structure */
+ };
  
- 	rc = dasd_sleep_on_immediatly(cqr);
+ /*
+- *	Message queues. The order here is important, see also the 
++ *	Message queues. The order here is important, see also the
+  *	queue type ordering
+  */
  
--	dasd_sfree_request(cqr, cqr->device);
-+	dasd_sfree_request(cqr, cqr->memdev);
- 	return rc;
- }
+@@ -559,12 +561,12 @@ struct aac_queue_block
+ /*
+  *	SaP1 Message Unit Registers
+  */
+- 
++
+ struct sa_drawbridge_CSR {
+-				/*	Offset 	|  Name */
++				/*	Offset	|  Name */
+ 	__le32	reserved[10];	/*	00h-27h |  Reserved */
+ 	u8	LUT_Offset;	/*	28h	|  Lookup Table Offset */
+-	u8	reserved1[3];	/* 	29h-2bh	|  Reserved */
++	u8	reserved1[3];	/*	29h-2bh	|  Reserved */
+ 	__le32	LUT_Data;	/*	2ch	|  Looup Table Data */
+ 	__le32	reserved2[26];	/*	30h-97h	|  Reserved */
+ 	__le16	PRICLEARIRQ;	/*	98h	|  Primary Clear Irq */
+@@ -583,8 +585,8 @@ struct sa_drawbridge_CSR {
+ 	__le32	MAILBOX5;	/*	bch	|  Scratchpad 5 */
+ 	__le32	MAILBOX6;	/*	c0h	|  Scratchpad 6 */
+ 	__le32	MAILBOX7;	/*	c4h	|  Scratchpad 7 */
+-	__le32	ROM_Setup_Data;	/*	c8h 	|  Rom Setup and Data */
+-	__le32	ROM_Control_Addr;/*	cch 	|  Rom Control and Address */
++	__le32	ROM_Setup_Data;	/*	c8h	|  Rom Setup and Data */
++	__le32	ROM_Control_Addr;/*	cch	|  Rom Control and Address */
+ 	__le32	reserved3[12];	/*	d0h-ffh	|  reserved */
+ 	__le32	LUT[64];	/*    100h-1ffh	|  Lookup Table Entries */
+ };
+@@ -597,7 +599,7 @@ struct sa_drawbridge_CSR {
+ #define Mailbox5	SaDbCSR.MAILBOX5
+ #define Mailbox6	SaDbCSR.MAILBOX6
+ #define Mailbox7	SaDbCSR.MAILBOX7
+-	
++
+ #define DoorbellReg_p SaDbCSR.PRISETIRQ
+ #define DoorbellReg_s SaDbCSR.SECSETIRQ
+ #define DoorbellClrReg_p SaDbCSR.PRICLEARIRQ
+@@ -611,19 +613,19 @@ struct sa_drawbridge_CSR {
+ #define DOORBELL_5	0x0020
+ #define DOORBELL_6	0x0040
  
-@@ -1498,7 +1852,8 @@ dasd_eckd_steal_lock(struct dasd_device *device)
-         cqr->cpaddr->flags |= CCW_FLAG_SLI;
-         cqr->cpaddr->count = 32;
- 	cqr->cpaddr->cda = (__u32)(addr_t) cqr->data;
--	cqr->device = device;
-+	cqr->startdev = device;
-+	cqr->memdev = device;
- 	clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
- 	set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags);
- 	cqr->retries = 2;	/* set retry counter to enable basic ERP */
-@@ -1508,7 +1863,7 @@ dasd_eckd_steal_lock(struct dasd_device *device)
+-	
++
+ #define PrintfReady	DOORBELL_5
+ #define PrintfDone	DOORBELL_5
+-	
++
+ struct sa_registers {
+ 	struct sa_drawbridge_CSR	SaDbCSR;			/* 98h - c4h */
+ };
+-	
++
  
- 	rc = dasd_sleep_on_immediatly(cqr);
+ #define Sa_MINIPORT_REVISION			1
  
--	dasd_sfree_request(cqr, cqr->device);
-+	dasd_sfree_request(cqr, cqr->memdev);
- 	return rc;
- }
+ #define sa_readw(AEP, CSR)		readl(&((AEP)->regs.sa->CSR))
+-#define sa_readl(AEP,  CSR)		readl(&((AEP)->regs.sa->CSR))
++#define sa_readl(AEP, CSR)		readl(&((AEP)->regs.sa->CSR))
+ #define sa_writew(AEP, CSR, value)	writew(value, &((AEP)->regs.sa->CSR))
+ #define sa_writel(AEP, CSR, value)	writel(value, &((AEP)->regs.sa->CSR))
  
-@@ -1526,52 +1881,52 @@ dasd_eckd_performance(struct dasd_device *device, void __user *argp)
+@@ -640,21 +642,21 @@ struct rx_mu_registers {
+ 	__le32	IMRx[2];    /*	1310h  | 10h | Inbound Message Registers */
+ 	__le32	OMRx[2];    /*	1318h  | 18h | Outbound Message Registers */
+ 	__le32	IDR;	    /*	1320h  | 20h | Inbound Doorbell Register */
+-	__le32	IISR;	    /*	1324h  | 24h | Inbound Interrupt 
++	__le32	IISR;	    /*	1324h  | 24h | Inbound Interrupt
+ 						Status Register */
+-	__le32	IIMR;	    /*	1328h  | 28h | Inbound Interrupt 
+-					 	Mask Register */
++	__le32	IIMR;	    /*	1328h  | 28h | Inbound Interrupt
++						Mask Register */
+ 	__le32	ODR;	    /*	132Ch  | 2Ch | Outbound Doorbell Register */
+-	__le32	OISR;	    /*	1330h  | 30h | Outbound Interrupt 
++	__le32	OISR;	    /*	1330h  | 30h | Outbound Interrupt
+ 						Status Register */
+-	__le32	OIMR;	    /*	1334h  | 34h | Outbound Interrupt 
++	__le32	OIMR;	    /*	1334h  | 34h | Outbound Interrupt
+ 						Mask Register */
+ 	__le32	reserved2;  /*	1338h  | 38h | Reserved */
+ 	__le32	reserved3;  /*	133Ch  | 3Ch | Reserved */
+ 	__le32	InboundQueue;/*	1340h  | 40h | Inbound Queue Port relative to firmware */
+ 	__le32	OutboundQueue;/*1344h  | 44h | Outbound Queue Port relative to firmware */
+-			    /* * Must access through ATU Inbound 
+-			     	 Translation Window */
++			    /* * Must access through ATU Inbound
++				 Translation Window */
+ };
  
- 	cqr = dasd_smalloc_request(dasd_eckd_discipline.name,
- 				   1 /* PSF */  + 1 /* RSSD */ ,
--				   (sizeof (struct dasd_psf_prssd_data) +
--				    sizeof (struct dasd_rssd_perf_stats_t)),
-+				   (sizeof(struct dasd_psf_prssd_data) +
-+				    sizeof(struct dasd_rssd_perf_stats_t)),
- 				   device);
- 	if (IS_ERR(cqr)) {
- 		DEV_MESSAGE(KERN_WARNING, device, "%s",
- 			    "Could not allocate initialization request");
- 		return PTR_ERR(cqr);
- 	}
--	cqr->device = device;
-+	cqr->startdev = device;
-+	cqr->memdev = device;
- 	cqr->retries = 0;
- 	cqr->expires = 10 * HZ;
+ struct rx_inbound {
+@@ -710,12 +712,12 @@ struct rkt_registers {
+ typedef void (*fib_callback)(void *ctxt, struct fib *fibctx);
  
- 	/* Prepare for Read Subsystem Data */
- 	prssdp = (struct dasd_psf_prssd_data *) cqr->data;
--	memset(prssdp, 0, sizeof (struct dasd_psf_prssd_data));
-+	memset(prssdp, 0, sizeof(struct dasd_psf_prssd_data));
- 	prssdp->order = PSF_ORDER_PRSSD;
--	prssdp->suborder = 0x01;	/* Perfomance Statistics */
-+	prssdp->suborder = 0x01;	/* Performance Statistics */
- 	prssdp->varies[1] = 0x01;	/* Perf Statistics for the Subsystem */
+ struct aac_fib_context {
+-	s16	 		type;		// used for verification of structure	
+-	s16	 		size;
++	s16			type;		// used for verification of structure
++	s16			size;
+ 	u32			unique;		// unique value representing this context
+ 	ulong			jiffies;	// used for cleanup - dmb changed to ulong
+ 	struct list_head	next;		// used to link context's into a linked list
+-	struct semaphore 	wait_sem;	// this is used to wait for the next fib to arrive.
++	struct semaphore	wait_sem;	// this is used to wait for the next fib to arrive.
+ 	int			wait;		// Set to true when thread is in WaitForSingleObject
+ 	unsigned long		count;		// total number of FIBs on FibList
+ 	struct list_head	fib_list;	// this holds fibs and their attachd hw_fibs
+@@ -734,9 +736,9 @@ struct sense_data {
+ 	u8 EOM:1;		/* End Of Medium - reserved for random access devices */
+ 	u8 filemark:1;		/* Filemark - reserved for random access devices */
  
- 	ccw = cqr->cpaddr;
- 	ccw->cmd_code = DASD_ECKD_CCW_PSF;
--	ccw->count = sizeof (struct dasd_psf_prssd_data);
-+	ccw->count = sizeof(struct dasd_psf_prssd_data);
- 	ccw->flags |= CCW_FLAG_CC;
- 	ccw->cda = (__u32)(addr_t) prssdp;
+-	u8 information[4];	/* for direct-access devices, contains the unsigned 
+-				 * logical block address or residue associated with 
+-				 * the sense key 
++	u8 information[4];	/* for direct-access devices, contains the unsigned
++				 * logical block address or residue associated with
++				 * the sense key
+ 				 */
+ 	u8 add_sense_len;	/* number of additional sense bytes to follow this field */
+ 	u8 cmnd_info[4];	/* not used */
+@@ -746,7 +748,7 @@ struct sense_data {
+ 	u8 bit_ptr:3;		/* indicates which byte of the CDB or parameter data
+ 				 * was in error
+ 				 */
+-	u8 BPV:1;		/* bit pointer valid (BPV): 1- indicates that 
++	u8 BPV:1;		/* bit pointer valid (BPV): 1- indicates that
+ 				 * the bit_ptr field has valid value
+ 				 */
+ 	u8 reserved2:2;
+@@ -780,24 +782,24 @@ struct fib {
+ 	/*
+ 	 *	The Adapter that this I/O is destined for.
+ 	 */
+-	struct aac_dev 		*dev;
++	struct aac_dev		*dev;
+ 	/*
+ 	 *	This is the event the sendfib routine will wait on if the
+ 	 *	caller did not pass one and this is synch io.
+ 	 */
+-	struct semaphore 	event_wait;
++	struct semaphore	event_wait;
+ 	spinlock_t		event_lock;
  
- 	/* Read Subsystem Data - Performance Statistics */
- 	stats = (struct dasd_rssd_perf_stats_t *) (prssdp + 1);
--	memset(stats, 0, sizeof (struct dasd_rssd_perf_stats_t));
-+	memset(stats, 0, sizeof(struct dasd_rssd_perf_stats_t));
+ 	u32			done;	/* gets set to 1 when fib is complete */
+-	fib_callback 		callback;
+-	void 			*callback_data;
++	fib_callback		callback;
++	void			*callback_data;
+ 	u32			flags; // u32 dmb was ulong
+ 	/*
+ 	 *	And for the internal issue/reply queues (we may be able
+ 	 *	to merge these two)
+ 	 */
+ 	struct list_head	fiblink;
+-	void 			*data;
++	void			*data;
+ 	struct hw_fib		*hw_fib_va;		/* Actual shared object */
+ 	dma_addr_t		hw_fib_pa;		/* physical address of hw_fib*/
+ };
+@@ -807,7 +809,7 @@ struct fib {
+  *
+  *	This is returned by the RequestAdapterInfo block
+  */
+- 
++
+ struct aac_adapter_info
+ {
+ 	__le32	platform;
+@@ -826,7 +828,7 @@ struct aac_adapter_info
+ 	__le32	biosrev;
+ 	__le32	biosbuild;
+ 	__le32	cluster;
+-	__le32	clusterchannelmask; 
++	__le32	clusterchannelmask;
+ 	__le32	serial[2];
+ 	__le32	battery;
+ 	__le32	options;
+@@ -863,9 +865,10 @@ struct aac_supplement_adapter_info
+ 	__le32	SupportedOptions2;
+ 	__le32	ReservedGrowth[1];
+ };
+-#define AAC_FEATURE_FALCON	0x00000010
+-#define AAC_OPTION_MU_RESET	0x00000001
+-#define AAC_OPTION_IGNORE_RESET	0x00000002
++#define AAC_FEATURE_FALCON	cpu_to_le32(0x00000010)
++#define AAC_FEATURE_JBOD	cpu_to_le32(0x08000000)
++#define AAC_OPTION_MU_RESET	cpu_to_le32(0x00000001)
++#define AAC_OPTION_IGNORE_RESET	cpu_to_le32(0x00000002)
+ #define AAC_SIS_VERSION_V3	3
+ #define AAC_SIS_SLOT_UNKNOWN	0xFF
  
- 	ccw++;
- 	ccw->cmd_code = DASD_ECKD_CCW_RSSD;
--	ccw->count = sizeof (struct dasd_rssd_perf_stats_t);
-+	ccw->count = sizeof(struct dasd_rssd_perf_stats_t);
- 	ccw->cda = (__u32)(addr_t) stats;
+@@ -916,13 +919,13 @@ struct aac_bus_info_response {
+ #define AAC_OPT_HOST_TIME_FIB		cpu_to_le32(1<<4)
+ #define AAC_OPT_RAID50			cpu_to_le32(1<<5)
+ #define AAC_OPT_4GB_WINDOW		cpu_to_le32(1<<6)
+-#define AAC_OPT_SCSI_UPGRADEABLE 	cpu_to_le32(1<<7)
++#define AAC_OPT_SCSI_UPGRADEABLE	cpu_to_le32(1<<7)
+ #define AAC_OPT_SOFT_ERR_REPORT		cpu_to_le32(1<<8)
+-#define AAC_OPT_SUPPORTED_RECONDITION 	cpu_to_le32(1<<9)
++#define AAC_OPT_SUPPORTED_RECONDITION	cpu_to_le32(1<<9)
+ #define AAC_OPT_SGMAP_HOST64		cpu_to_le32(1<<10)
+ #define AAC_OPT_ALARM			cpu_to_le32(1<<11)
+ #define AAC_OPT_NONDASD			cpu_to_le32(1<<12)
+-#define AAC_OPT_SCSI_MANAGED    	cpu_to_le32(1<<13)
++#define AAC_OPT_SCSI_MANAGED		cpu_to_le32(1<<13)
+ #define AAC_OPT_RAID_SCSI_MODE		cpu_to_le32(1<<14)
+ #define AAC_OPT_SUPPLEMENT_ADAPTER_INFO	cpu_to_le32(1<<16)
+ #define AAC_OPT_NEW_COMM		cpu_to_le32(1<<17)
+@@ -942,7 +945,7 @@ struct aac_dev
  
- 	cqr->buildclk = get_clock();
- 	cqr->status = DASD_CQR_FILLED;
- 	rc = dasd_sleep_on(cqr);
- 	if (rc == 0) {
--		/* Prepare for Read Subsystem Data */
- 		prssdp = (struct dasd_psf_prssd_data *) cqr->data;
- 		stats = (struct dasd_rssd_perf_stats_t *) (prssdp + 1);
- 		if (copy_to_user(argp, stats,
- 				 sizeof(struct dasd_rssd_perf_stats_t)))
- 			rc = -EFAULT;
- 	}
--	dasd_sfree_request(cqr, cqr->device);
-+	dasd_sfree_request(cqr, cqr->memdev);
- 	return rc;
- }
+ 	/*
+ 	 *	Map for 128 fib objects (64k)
+-	 */	
++	 */
+ 	dma_addr_t		hw_fib_pa;
+ 	struct hw_fib		*hw_fib_va;
+ 	struct hw_fib		*aif_base_va;
+@@ -953,24 +956,24 @@ struct aac_dev
  
-@@ -1594,7 +1949,7 @@ dasd_eckd_get_attrib(struct dasd_device *device, void __user *argp)
+ 	struct fib		*free_fib;
+ 	spinlock_t		fib_lock;
+-	
++
+ 	struct aac_queue_block *queues;
+ 	/*
+ 	 *	The user API will use an IOCTL to register itself to receive
+ 	 *	FIBs from the adapter.  The following list is used to keep
+ 	 *	track of all the threads that have requested these FIBs.  The
+-	 *	mutex is used to synchronize access to all data associated 
++	 *	mutex is used to synchronize access to all data associated
+ 	 *	with the adapter fibs.
+ 	 */
+ 	struct list_head	fib_list;
  
- 	rc = 0;
- 	if (copy_to_user(argp, (long *) &attrib,
--			 sizeof (struct attrib_data_t)))
-+			 sizeof(struct attrib_data_t)))
- 		rc = -EFAULT;
+ 	struct adapter_ops	a_ops;
+ 	unsigned long		fsrev;		/* Main driver's revision number */
+-	
++
+ 	unsigned		base_size;	/* Size of mapped in region */
+ 	struct aac_init		*init;		/* Holds initialization info to communicate with adapter */
+-	dma_addr_t		init_pa; 	/* Holds physical address of the init struct */
+-	
++	dma_addr_t		init_pa;	/* Holds physical address of the init struct */
++
+ 	struct pci_dev		*pdev;		/* Our PCI interface */
+ 	void *			printfbuf;	/* pointer to buffer used for printf's from the adapter */
+ 	void *			comm_addr;	/* Base address of Comm area */
+@@ -984,11 +987,11 @@ struct aac_dev
+ 	struct fsa_dev_info	*fsa_dev;
+ 	struct task_struct	*thread;
+ 	int			cardtype;
+-	
++
+ 	/*
+ 	 *	The following is the device specific extension.
+ 	 */
+-#if (!defined(AAC_MIN_FOOTPRINT_SIZE))
++#ifndef AAC_MIN_FOOTPRINT_SIZE
+ #	define AAC_MIN_FOOTPRINT_SIZE 8192
+ #endif
+ 	union
+@@ -1009,7 +1012,9 @@ struct aac_dev
+ 	/* These are in adapter info but they are in the io flow so
+ 	 * lets break them out so we don't have to do an AND to check them
+ 	 */
+-	u8			nondasd_support; 
++	u8			nondasd_support;
++	u8			jbod;
++	u8			cache_protected;
+ 	u8			dac_support;
+ 	u8			raid_scsi_mode;
+ 	u8			comm_interface;
+@@ -1066,18 +1071,19 @@ struct aac_dev
+ 	(dev)->a_ops.adapter_comm(dev, comm)
  
- 	return rc;
-@@ -1627,8 +1982,10 @@ dasd_eckd_set_attrib(struct dasd_device *device, void __user *argp)
- }
+ #define FIB_CONTEXT_FLAG_TIMED_OUT		(0x00000001)
++#define FIB_CONTEXT_FLAG			(0x00000002)
  
- static int
--dasd_eckd_ioctl(struct dasd_device *device, unsigned int cmd, void __user *argp)
-+dasd_eckd_ioctl(struct dasd_block *block, unsigned int cmd, void __user *argp)
- {
-+	struct dasd_device *device = block->base;
-+
- 	switch (cmd) {
- 	case BIODASDGATTR:
- 		return dasd_eckd_get_attrib(device, argp);
-@@ -1685,9 +2042,8 @@ dasd_eckd_dump_ccw_range(struct ccw1 *from, struct ccw1 *to, char *page)
-  * Print sense data and related channel program.
-  * Parts are printed because printk buffer is only 1024 bytes.
+ /*
+  *	Define the command values
   */
--static void
--dasd_eckd_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req,
--		     struct irb *irb)
-+static void dasd_eckd_dump_sense(struct dasd_device *device,
-+				 struct dasd_ccw_req *req, struct irb *irb)
+- 
++
+ #define		Null			0
+-#define 	GetAttributes		1
+-#define 	SetAttributes		2
+-#define 	Lookup			3
+-#define 	ReadLink		4
+-#define 	Read			5
+-#define 	Write			6
++#define		GetAttributes		1
++#define		SetAttributes		2
++#define		Lookup			3
++#define		ReadLink		4
++#define		Read			5
++#define		Write			6
+ #define		Create			7
+ #define		MakeDirectory		8
+ #define		SymbolicLink		9
+@@ -1173,19 +1179,19 @@ struct aac_dev
+ 
+ struct aac_read
  {
- 	char *page;
- 	struct ccw1 *first, *last, *fail, *from, *to;
-@@ -1743,37 +2099,40 @@ dasd_eckd_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req,
- 	}
- 	printk("%s", page);
+-	__le32	 	command;
+-	__le32 		cid;
+-	__le32 		block;
+-	__le32 		count;
++	__le32		command;
++	__le32		cid;
++	__le32		block;
++	__le32		count;
+ 	struct sgmap	sg;	// Must be last in struct because it is variable
+ };
  
--	/* dump the Channel Program (max 140 Bytes per line) */
--	/* Count CCW and print first CCWs (maximum 1024 % 140 = 7) */
--	first = req->cpaddr;
--	for (last = first; last->flags & (CCW_FLAG_CC | CCW_FLAG_DC); last++);
--	to = min(first + 6, last);
--	len = sprintf(page,  KERN_ERR PRINTK_HEADER
--		      " Related CP in req: %p\n", req);
--	dasd_eckd_dump_ccw_range(first, to, page + len);
--	printk("%s", page);
-+	if (req) {
-+		/* req == NULL for unsolicited interrupts */
-+		/* dump the Channel Program (max 140 Bytes per line) */
-+		/* Count CCW and print first CCWs (maximum 1024 % 140 = 7) */
-+		first = req->cpaddr;
-+		for (last = first; last->flags & (CCW_FLAG_CC | CCW_FLAG_DC); last++);
-+		to = min(first + 6, last);
-+		len = sprintf(page,  KERN_ERR PRINTK_HEADER
-+			      " Related CP in req: %p\n", req);
-+		dasd_eckd_dump_ccw_range(first, to, page + len);
-+		printk("%s", page);
+ struct aac_read64
+ {
+-	__le32	 	command;
+-	__le16 		cid;
+-	__le16 		sector_count;
+-	__le32 		block;
++	__le32		command;
++	__le16		cid;
++	__le16		sector_count;
++	__le32		block;
+ 	__le16		pad;
+ 	__le16		flags;
+ 	struct sgmap64	sg;	// Must be last in struct because it is variable
+@@ -1193,26 +1199,26 @@ struct aac_read64
  
--	/* print failing CCW area (maximum 4) */
--	/* scsw->cda is either valid or zero  */
--	len = 0;
--	from = ++to;
--	fail = (struct ccw1 *)(addr_t) irb->scsw.cpa; /* failing CCW */
--	if (from <  fail - 2) {
--		from = fail - 2;     /* there is a gap - print header */
--		len += sprintf(page, KERN_ERR PRINTK_HEADER "......\n");
--	}
--	to = min(fail + 1, last);
--	len += dasd_eckd_dump_ccw_range(from, to, page + len);
--
--	/* print last CCWs (maximum 2) */
--	from = max(from, ++to);
--	if (from < last - 1) {
--		from = last - 1;     /* there is a gap - print header */
--		len += sprintf(page + len, KERN_ERR PRINTK_HEADER "......\n");
-+		/* print failing CCW area (maximum 4) */
-+		/* scsw->cda is either valid or zero  */
-+		len = 0;
-+		from = ++to;
-+		fail = (struct ccw1 *)(addr_t) irb->scsw.cpa; /* failing CCW */
-+		if (from <  fail - 2) {
-+			from = fail - 2;     /* there is a gap - print header */
-+			len += sprintf(page, KERN_ERR PRINTK_HEADER "......\n");
-+		}
-+		to = min(fail + 1, last);
-+		len += dasd_eckd_dump_ccw_range(from, to, page + len);
-+
-+		/* print last CCWs (maximum 2) */
-+		from = max(from, ++to);
-+		if (from < last - 1) {
-+			from = last - 1;     /* there is a gap - print header */
-+			len += sprintf(page + len, KERN_ERR PRINTK_HEADER "......\n");
-+		}
-+		len += dasd_eckd_dump_ccw_range(from, last, page + len);
-+		if (len > 0)
-+			printk("%s", page);
- 	}
--	len += dasd_eckd_dump_ccw_range(from, last, page + len);
--	if (len > 0)
--		printk("%s", page);
- 	free_page((unsigned long) page);
- }
+ struct aac_read_reply
+ {
+-	__le32	 	status;
+-	__le32 		count;
++	__le32		status;
++	__le32		count;
+ };
  
-@@ -1796,16 +2155,20 @@ static struct dasd_discipline dasd_eckd_discipline = {
- 	.ebcname = "ECKD",
- 	.max_blocks = 240,
- 	.check_device = dasd_eckd_check_characteristics,
-+	.uncheck_device = dasd_eckd_uncheck_device,
- 	.do_analysis = dasd_eckd_do_analysis,
-+	.ready_to_online = dasd_eckd_ready_to_online,
-+	.online_to_ready = dasd_eckd_online_to_ready,
- 	.fill_geometry = dasd_eckd_fill_geometry,
- 	.start_IO = dasd_start_IO,
- 	.term_IO = dasd_term_IO,
-+	.handle_terminated_request = dasd_eckd_handle_terminated_request,
- 	.format_device = dasd_eckd_format_device,
--	.examine_error = dasd_eckd_examine_error,
- 	.erp_action = dasd_eckd_erp_action,
- 	.erp_postaction = dasd_eckd_erp_postaction,
--	.build_cp = dasd_eckd_build_cp,
--	.free_cp = dasd_eckd_free_cp,
-+	.handle_unsolicited_interrupt = dasd_eckd_handle_unsolicited_interrupt,
-+	.build_cp = dasd_eckd_build_alias_cp,
-+	.free_cp = dasd_eckd_free_alias_cp,
- 	.dump_sense = dasd_eckd_dump_sense,
- 	.fill_info = dasd_eckd_fill_info,
- 	.ioctl = dasd_eckd_ioctl,
-diff --git a/drivers/s390/block/dasd_eckd.h b/drivers/s390/block/dasd_eckd.h
-index 712ff16..fc2509c 100644
---- a/drivers/s390/block/dasd_eckd.h
-+++ b/drivers/s390/block/dasd_eckd.h
-@@ -39,6 +39,8 @@
- #define DASD_ECKD_CCW_READ_CKD_MT	 0x9e
- #define DASD_ECKD_CCW_WRITE_CKD_MT	 0x9d
- #define DASD_ECKD_CCW_RESERVE		 0xB4
-+#define DASD_ECKD_CCW_PFX		 0xE7
-+#define DASD_ECKD_CCW_RSCK		 0xF9
+ struct aac_write
+ {
+ 	__le32		command;
+-	__le32 		cid;
+-	__le32 		block;
+-	__le32 		count;
+-	__le32	 	stable;	// Not used
++	__le32		cid;
++	__le32		block;
++	__le32		count;
++	__le32		stable;	// Not used
+ 	struct sgmap	sg;	// Must be last in struct because it is variable
+ };
  
- /*
-  * Perform Subsystem Function / Sub-Orders
-@@ -137,6 +139,25 @@ struct LO_eckd_data {
- 	__u16 length;
- } __attribute__ ((packed));
+ struct aac_write64
+ {
+-	__le32	 	command;
+-	__le16 		cid;
+-	__le16 		sector_count;
+-	__le32 		block;
++	__le32		command;
++	__le16		cid;
++	__le16		sector_count;
++	__le32		block;
+ 	__le16		pad;
+ 	__le16		flags;
+ #define	IO_TYPE_WRITE 0x00000000
+@@ -1223,7 +1229,7 @@ struct aac_write64
+ struct aac_write_reply
+ {
+ 	__le32		status;
+-	__le32 		count;
++	__le32		count;
+ 	__le32		committed;
+ };
  
-+/* Prefix data for format 0x00 and 0x01 */
-+struct PFX_eckd_data {
-+	unsigned char format;
-+	struct {
-+		unsigned char define_extend:1;
-+		unsigned char time_stamp:1;
-+		unsigned char verify_base:1;
-+		unsigned char hyper_pav:1;
-+		unsigned char reserved:4;
-+	} __attribute__ ((packed)) validity;
-+	__u8 base_address;
-+	__u8 aux;
-+	__u8 base_lss;
-+	__u8 reserved[7];
-+	struct DE_eckd_data define_extend;
-+	struct LO_eckd_data locate_record;
-+	__u8 LO_extended_data[4];
-+} __attribute__ ((packed));
-+
- struct dasd_eckd_characteristics {
- 	__u16 cu_type;
- 	struct {
-@@ -254,7 +275,9 @@ struct dasd_eckd_confdata {
- 		} __attribute__ ((packed)) ned;
- 		struct {
- 			unsigned char flags;            /* byte  0    */
--			unsigned char res2[7];          /* byte  1- 7 */
-+			unsigned char res1;		/* byte  1    */
-+			__u16 format;			/* byte  2-3  */
-+			unsigned char res2[4];		/* byte  4-7  */
- 			unsigned char sua_flags;	/* byte  8    */
- 			__u8 base_unit_addr;            /* byte  9    */
- 			unsigned char res3[22];	        /* byte 10-31 */
-@@ -343,6 +366,11 @@ struct dasd_eckd_path {
- 	__u8 npm;
+@@ -1326,10 +1332,10 @@ struct aac_srb_reply
+ #define		SRB_NoDataXfer		 0x0000
+ #define		SRB_DisableDisconnect	 0x0004
+ #define		SRB_DisableSynchTransfer 0x0008
+-#define 	SRB_BypassFrozenQueue	 0x0010
++#define		SRB_BypassFrozenQueue	 0x0010
+ #define		SRB_DisableAutosense	 0x0020
+ #define		SRB_DataIn		 0x0040
+-#define 	SRB_DataOut		 0x0080
++#define		SRB_DataOut		 0x0080
+ 
+ /*
+  * SRB Functions - set in aac_srb->function
+@@ -1352,7 +1358,7 @@ struct aac_srb_reply
+ #define	SRBF_RemoveDevice	0x0016
+ #define	SRBF_DomainValidation	0x0017
+ 
+-/* 
++/*
+  * SRB SCSI Status - set in aac_srb->scsi_status
+  */
+ #define SRB_STATUS_PENDING                  0x00
+@@ -1511,17 +1517,17 @@ struct aac_get_container_count_resp {
+  */
+ 
+ struct aac_mntent {
+-	__le32    		oid;
++	__le32			oid;
+ 	u8			name[16];	/* if applicable */
+ 	struct creation_info	create_info;	/* if applicable */
+ 	__le32			capacity;
+-	__le32			vol;    	/* substrate structure */
+-	__le32			obj;	        /* FT_FILESYS, etc. */
+-	__le32			state;		/* unready for mounting, 
++	__le32			vol;		/* substrate structure */
++	__le32			obj;		/* FT_FILESYS, etc. */
++	__le32			state;		/* unready for mounting,
+ 						   readonly, etc. */
+-	union aac_contentinfo	fileinfo;	/* Info specific to content 
++	union aac_contentinfo	fileinfo;	/* Info specific to content
+ 						   manager (eg, filesystem) */
+-	__le32			altoid;		/* != oid <==> snapshot or 
++	__le32			altoid;		/* != oid <==> snapshot or
+ 						   broken mirror exists */
+ 	__le32			capacityhigh;
  };
+@@ -1538,7 +1544,7 @@ struct aac_query_mount {
  
-+struct dasd_rssd_features {
-+	char feature[256];
-+} __attribute__((packed));
+ struct aac_mount {
+ 	__le32		status;
+-	__le32	   	type;           /* should be same as that requested */
++	__le32		type;           /* should be same as that requested */
+ 	__le32		count;
+ 	struct aac_mntent mnt[1];
+ };
+@@ -1608,7 +1614,7 @@ struct aac_delete_disk {
+ 	u32	disknum;
+ 	u32	cnum;
+ };
+- 
 +
+ struct fib_ioctl
+ {
+ 	u32	fibctx;
+@@ -1622,10 +1628,10 @@ struct revision
+ 	__le32 version;
+ 	__le32 build;
+ };
+-	
 +
+ 
  /*
-  * Perform Subsystem Function - Prepare for Read Subsystem Data
+- * 	Ugly - non Linux like ioctl coding for back compat.
++ *	Ugly - non Linux like ioctl coding for back compat.
+  */
+ 
+ #define CTL_CODE(function, method) (                 \
+@@ -1633,7 +1639,7 @@ struct revision
+ )
+ 
+ /*
+- *	Define the method codes for how buffers are passed for I/O and FS 
++ *	Define the method codes for how buffers are passed for I/O and FS
+  *	controls
+  */
+ 
+@@ -1644,15 +1650,15 @@ struct revision
+  *	Filesystem ioctls
   */
-@@ -365,4 +393,99 @@ struct dasd_psf_ssc_data {
- 	unsigned char reserved[59];
- } __attribute__((packed));
  
+-#define FSACTL_SENDFIB                  	CTL_CODE(2050, METHOD_BUFFERED)
+-#define FSACTL_SEND_RAW_SRB               	CTL_CODE(2067, METHOD_BUFFERED)
++#define FSACTL_SENDFIB				CTL_CODE(2050, METHOD_BUFFERED)
++#define FSACTL_SEND_RAW_SRB			CTL_CODE(2067, METHOD_BUFFERED)
+ #define FSACTL_DELETE_DISK			0x163
+ #define FSACTL_QUERY_DISK			0x173
+ #define FSACTL_OPEN_GET_ADAPTER_FIB		CTL_CODE(2100, METHOD_BUFFERED)
+ #define FSACTL_GET_NEXT_ADAPTER_FIB		CTL_CODE(2101, METHOD_BUFFERED)
+ #define FSACTL_CLOSE_GET_ADAPTER_FIB		CTL_CODE(2102, METHOD_BUFFERED)
+ #define FSACTL_MINIPORT_REV_CHECK               CTL_CODE(2107, METHOD_BUFFERED)
+-#define FSACTL_GET_PCI_INFO               	CTL_CODE(2119, METHOD_BUFFERED)
++#define FSACTL_GET_PCI_INFO			CTL_CODE(2119, METHOD_BUFFERED)
+ #define FSACTL_FORCE_DELETE_DISK		CTL_CODE(2120, METHOD_NEITHER)
+ #define FSACTL_GET_CONTAINERS			2131
+ #define FSACTL_SEND_LARGE_FIB			CTL_CODE(2138, METHOD_BUFFERED)
+@@ -1661,7 +1667,7 @@ struct revision
+ struct aac_common
+ {
+ 	/*
+-	 *	If this value is set to 1 then interrupt moderation will occur 
++	 *	If this value is set to 1 then interrupt moderation will occur
+ 	 *	in the base commuication support.
+ 	 */
+ 	u32 irq_mod;
+@@ -1690,11 +1696,11 @@ extern struct aac_common aac_config;
+  *	The following macro is used when sending and receiving FIBs. It is
+  *	only used for debugging.
+  */
+- 
 +
-+/*
-+ * some structures and definitions for alias handling
+ #ifdef DBG
+ #define	FIB_COUNTER_INCREMENT(counter)		(counter)++
+ #else
+-#define	FIB_COUNTER_INCREMENT(counter)		
++#define	FIB_COUNTER_INCREMENT(counter)
+ #endif
+ 
+ /*
+@@ -1726,17 +1732,17 @@ extern struct aac_common aac_config;
+  *
+  *	The adapter reports is present state through the phase.  Only
+  *	a single phase should be ever be set.  Each phase can have multiple
+- *	phase status bits to provide more detailed information about the 
+- *	state of the board.  Care should be taken to ensure that any phase 
++ *	phase status bits to provide more detailed information about the
++ *	state of the board.  Care should be taken to ensure that any phase
+  *	status bits that are set when changing the phase are also valid
+  *	for the new phase or be cleared out.  Adapter software (monitor,
+- *	iflash, kernel) is responsible for properly maintining the phase 
++ *	iflash, kernel) is responsible for properly maintining the phase
+  *	status mailbox when it is running.
+- *											
+- *	MONKER_API Phases							
+  *
+- *	Phases are bit oriented.  It is NOT valid  to have multiple bits set						
+- */					
++ *	MONKER_API Phases
++ *
++ *	Phases are bit oriented.  It is NOT valid  to have multiple bits set
 + */
-+struct dasd_unit_address_configuration {
-+	struct {
-+		char ua_type;
-+		char base_ua;
-+	} unit[256];
-+} __attribute__((packed));
-+
-+
-+#define MAX_DEVICES_PER_LCU 256
-+
-+/* flags on the LCU  */
-+#define NEED_UAC_UPDATE  0x01
-+#define UPDATE_PENDING	0x02
-+
-+enum pavtype {NO_PAV, BASE_PAV, HYPER_PAV};
-+
-+
-+struct alias_root {
-+	struct list_head serverlist;
-+	spinlock_t lock;
-+};
-+
-+struct alias_server {
-+	struct list_head server;
-+	struct dasd_uid uid;
-+	struct list_head lculist;
-+};
-+
-+struct summary_unit_check_work_data {
-+	char reason;
-+	struct dasd_device *device;
-+	struct work_struct worker;
-+};
-+
-+struct read_uac_work_data {
-+	struct dasd_device *device;
-+	struct delayed_work dwork;
-+};
-+
-+struct alias_lcu {
-+	struct list_head lcu;
-+	struct dasd_uid uid;
-+	enum pavtype pav;
-+	char flags;
-+	spinlock_t lock;
-+	struct list_head grouplist;
-+	struct list_head active_devices;
-+	struct list_head inactive_devices;
-+	struct dasd_unit_address_configuration *uac;
-+	struct summary_unit_check_work_data suc_data;
-+	struct read_uac_work_data ruac_data;
-+	struct dasd_ccw_req *rsu_cqr;
-+};
-+
-+struct alias_pav_group {
-+	struct list_head group;
-+	struct dasd_uid uid;
-+	struct alias_lcu *lcu;
-+	struct list_head baselist;
-+	struct list_head aliaslist;
-+	struct dasd_device *next;
-+};
-+
-+
-+struct dasd_eckd_private {
-+	struct dasd_eckd_characteristics rdc_data;
-+	struct dasd_eckd_confdata conf_data;
-+	struct dasd_eckd_path path_data;
-+	struct eckd_count count_area[5];
-+	int init_cqr_status;
-+	int uses_cdl;
-+	struct attrib_data_t attrib;	/* e.g. cache operations */
-+	struct dasd_rssd_features features;
-+
-+	/* alias managemnet */
-+	struct dasd_uid uid;
-+	struct alias_pav_group *pavgroup;
-+	struct alias_lcu *lcu;
-+	int count;
-+};
-+
+ 
+ #define	SELF_TEST_FAILED		0x00000004
+ #define	MONITOR_PANIC			0x00000020
+@@ -1759,16 +1765,22 @@ extern struct aac_common aac_config;
+  *	For FIB communication, we need all of the following things
+  *	to send back to the user.
+  */
+- 
+-#define 	AifCmdEventNotify	1	/* Notify of event */
 +
++#define		AifCmdEventNotify	1	/* Notify of event */
+ #define			AifEnConfigChange	3	/* Adapter configuration change */
+ #define			AifEnContainerChange	4	/* Container configuration change */
+ #define			AifEnDeviceFailure	5	/* SCSI device failed */
++#define			AifEnEnclosureManagement 13	/* EM_DRIVE_* */
++#define				EM_DRIVE_INSERTION	31
++#define				EM_DRIVE_REMOVAL	32
++#define			AifEnBatteryEvent	14	/* Change in Battery State */
+ #define			AifEnAddContainer	15	/* A new array was created */
+ #define			AifEnDeleteContainer	16	/* A container was deleted */
+ #define			AifEnExpEvent		23	/* Firmware Event Log */
+ #define			AifExeFirmwarePanic	3	/* Firmware Event Panic */
+ #define			AifHighPriority		3	/* Highest Priority Event */
++#define			AifEnAddJBOD		30	/* JBOD created */
++#define			AifEnDeleteJBOD		31	/* JBOD deleted */
+ 
+ #define		AifCmdJobProgress	2	/* Progress report */
+ #define			AifJobCtrZero	101	/* Array Zero progress */
+@@ -1780,11 +1792,11 @@ extern struct aac_common aac_config;
+ #define			AifDenVolumeExtendComplete 201 /* A volume extend completed */
+ #define		AifReqJobList		100	/* Gets back complete job list */
+ #define		AifReqJobsForCtr	101	/* Gets back jobs for specific container */
+-#define		AifReqJobsForScsi	102	/* Gets back jobs for specific SCSI device */ 
+-#define		AifReqJobReport		103	/* Gets back a specific job report or list of them */ 
++#define		AifReqJobsForScsi	102	/* Gets back jobs for specific SCSI device */
++#define		AifReqJobReport		103	/* Gets back a specific job report or list of them */
+ #define		AifReqTerminateJob	104	/* Terminates job */
+ #define		AifReqSuspendJob	105	/* Suspends a job */
+-#define		AifReqResumeJob		106	/* Resumes a job */ 
++#define		AifReqResumeJob		106	/* Resumes a job */
+ #define		AifReqSendAPIReport	107	/* API generic report requests */
+ #define		AifReqAPIJobStart	108	/* Start a job from the API */
+ #define		AifReqAPIJobUpdate	109	/* Update a job report from the API */
+@@ -1803,8 +1815,8 @@ struct aac_aifcmd {
+ };
+ 
+ /**
+- * 	Convert capacity to cylinders
+- *  	accounting for the fact capacity could be a 64 bit value
++ *	Convert capacity to cylinders
++ *	accounting for the fact capacity could be a 64 bit value
+  *
+  */
+ static inline unsigned int cap_to_cyls(sector_t capacity, unsigned divisor)
+@@ -1861,6 +1873,7 @@ int aac_probe_container(struct aac_dev *dev, int cid);
+ int _aac_rx_init(struct aac_dev *dev);
+ int aac_rx_select_comm(struct aac_dev *dev, int comm);
+ int aac_rx_deliver_producer(struct fib * fib);
++char * get_container_type(unsigned type);
+ extern int numacb;
+ extern int acbsize;
+ extern char aac_driver_version[];
+diff --git a/drivers/scsi/aacraid/commctrl.c b/drivers/scsi/aacraid/commctrl.c
+index 1e6d7a9..851a7e5 100644
+--- a/drivers/scsi/aacraid/commctrl.c
++++ b/drivers/scsi/aacraid/commctrl.c
+@@ -48,13 +48,13 @@
+  *	ioctl_send_fib	-	send a FIB from userspace
+  *	@dev:	adapter is being processed
+  *	@arg:	arguments to the ioctl call
+- *	
++ *
+  *	This routine sends a fib to the adapter on behalf of a user level
+  *	program.
+  */
+ # define AAC_DEBUG_PREAMBLE	KERN_INFO
+ # define AAC_DEBUG_POSTAMBLE
+- 
 +
-+int dasd_alias_make_device_known_to_lcu(struct dasd_device *);
-+void dasd_alias_disconnect_device_from_lcu(struct dasd_device *);
-+int dasd_alias_add_device(struct dasd_device *);
-+int dasd_alias_remove_device(struct dasd_device *);
-+struct dasd_device *dasd_alias_get_start_dev(struct dasd_device *);
-+void dasd_alias_handle_summary_unit_check(struct dasd_device *, struct irb *);
-+void dasd_eckd_reset_ccw_to_base_io(struct dasd_ccw_req *);
+ static int ioctl_send_fib(struct aac_dev * dev, void __user *arg)
+ {
+ 	struct hw_fib * kfib;
+@@ -71,7 +71,7 @@ static int ioctl_send_fib(struct aac_dev * dev, void __user *arg)
+ 	if(fibptr == NULL) {
+ 		return -ENOMEM;
+ 	}
+-		
 +
- #endif				/* DASD_ECKD_H */
-diff --git a/drivers/s390/block/dasd_eer.c b/drivers/s390/block/dasd_eer.c
-index 0c081a6..6e53ab6 100644
---- a/drivers/s390/block/dasd_eer.c
-+++ b/drivers/s390/block/dasd_eer.c
-@@ -336,7 +336,7 @@ static void dasd_eer_write_snss_trigger(struct dasd_device *device,
- 	unsigned long flags;
- 	struct eerbuffer *eerb;
+ 	kfib = fibptr->hw_fib_va;
+ 	/*
+ 	 *	First copy in the header so that we can check the size field.
+@@ -109,7 +109,7 @@ static int ioctl_send_fib(struct aac_dev * dev, void __user *arg)
+ 	if (kfib->header.Command == cpu_to_le16(TakeABreakPt)) {
+ 		aac_adapter_interrupt(dev);
+ 		/*
+-		 * Since we didn't really send a fib, zero out the state to allow 
++		 * Since we didn't really send a fib, zero out the state to allow
+ 		 * cleanup code not to assert.
+ 		 */
+ 		kfib->header.XferState = 0;
+@@ -169,7 +169,7 @@ static int open_getadapter_fib(struct aac_dev * dev, void __user *arg)
  
--	snss_rc = (cqr->status == DASD_CQR_FAILED) ? -EIO : 0;
-+	snss_rc = (cqr->status == DASD_CQR_DONE) ? 0 : -EIO;
- 	if (snss_rc)
- 		data_size = 0;
- 	else
-@@ -404,10 +404,11 @@ void dasd_eer_snss(struct dasd_device *device)
- 		set_bit(DASD_FLAG_EER_SNSS, &device->flags);
- 		return;
+ 		fibctx->type = FSAFS_NTC_GET_ADAPTER_FIB_CONTEXT;
+ 		fibctx->size = sizeof(struct aac_fib_context);
+- 		/*
++		/*
+ 		 *	Yes yes, I know this could be an index, but we have a
+ 		 * better guarantee of uniqueness for the locked loop below.
+ 		 * Without the aid of a persistent history, this also helps
+@@ -189,7 +189,7 @@ static int open_getadapter_fib(struct aac_dev * dev, void __user *arg)
+ 		INIT_LIST_HEAD(&fibctx->fib_list);
+ 		fibctx->jiffies = jiffies/HZ;
+ 		/*
+-		 *	Now add this context onto the adapter's 
++		 *	Now add this context onto the adapter's
+ 		 *	AdapterFibContext list.
+ 		 */
+ 		spin_lock_irqsave(&dev->fib_lock, flags);
+@@ -207,12 +207,12 @@ static int open_getadapter_fib(struct aac_dev * dev, void __user *arg)
+ 		}
+ 		list_add_tail(&fibctx->next, &dev->fib_list);
+ 		spin_unlock_irqrestore(&dev->fib_lock, flags);
+-		if (copy_to_user(arg,  &fibctx->unique, 
++		if (copy_to_user(arg, &fibctx->unique,
+ 						sizeof(fibctx->unique))) {
+ 			status = -EFAULT;
+ 		} else {
+ 			status = 0;
+-		}	
++		}
  	}
-+	/* cdev is already locked, can't use dasd_add_request_head */
- 	clear_bit(DASD_FLAG_EER_SNSS, &device->flags);
- 	cqr->status = DASD_CQR_QUEUED;
--	list_add(&cqr->list, &device->ccw_queue);
--	dasd_schedule_bh(device);
-+	list_add(&cqr->devlist, &device->ccw_queue);
-+	dasd_schedule_device_bh(device);
+ 	return status;
  }
- 
- /*
-@@ -415,7 +416,7 @@ void dasd_eer_snss(struct dasd_device *device)
+@@ -221,8 +221,8 @@ static int open_getadapter_fib(struct aac_dev * dev, void __user *arg)
+  *	next_getadapter_fib	-	get the next fib
+  *	@dev: adapter to use
+  *	@arg: ioctl argument
+- *	
+- * 	This routine will get the next Fib, if available, from the AdapterFibContext
++ *
++ *	This routine will get the next Fib, if available, from the AdapterFibContext
+  *	passed in from the user.
   */
- static void dasd_eer_snss_cb(struct dasd_ccw_req *cqr, void *data)
- {
--        struct dasd_device *device = cqr->device;
-+	struct dasd_device *device = cqr->startdev;
- 	unsigned long flags;
  
- 	dasd_eer_write(device, cqr, DASD_EER_STATECHANGE);
-@@ -458,7 +459,7 @@ int dasd_eer_enable(struct dasd_device *device)
- 	if (!cqr)
- 		return -ENOMEM;
+@@ -234,7 +234,7 @@ static int next_getadapter_fib(struct aac_dev * dev, void __user *arg)
+ 	int status;
+ 	struct list_head * entry;
+ 	unsigned long flags;
+-	
++
+ 	if(copy_from_user((void *)&f, arg, sizeof(struct fib_ioctl)))
+ 		return -EFAULT;
+ 	/*
+@@ -243,6 +243,7 @@ static int next_getadapter_fib(struct aac_dev * dev, void __user *arg)
+ 	 *	Search the list of AdapterFibContext addresses on the adapter
+ 	 *	to be sure this is a valid address
+ 	 */
++	spin_lock_irqsave(&dev->fib_lock, flags);
+ 	entry = dev->fib_list.next;
+ 	fibctx = NULL;
  
--	cqr->device = device;
-+	cqr->startdev = device;
- 	cqr->retries = 255;
- 	cqr->expires = 10 * HZ;
- 	clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
-diff --git a/drivers/s390/block/dasd_erp.c b/drivers/s390/block/dasd_erp.c
-index caa5d91..8f10000 100644
---- a/drivers/s390/block/dasd_erp.c
-+++ b/drivers/s390/block/dasd_erp.c
-@@ -46,6 +46,8 @@ dasd_alloc_erp_request(char *magic, int cplength, int datasize,
- 	if (cqr == NULL)
- 		return ERR_PTR(-ENOMEM);
- 	memset(cqr, 0, sizeof(struct dasd_ccw_req));
-+	INIT_LIST_HEAD(&cqr->devlist);
-+	INIT_LIST_HEAD(&cqr->blocklist);
- 	data = (char *) cqr + ((sizeof(struct dasd_ccw_req) + 7L) & -8L);
- 	cqr->cpaddr = NULL;
- 	if (cplength > 0) {
-@@ -66,7 +68,7 @@ dasd_alloc_erp_request(char *magic, int cplength, int datasize,
- }
+@@ -251,37 +252,37 @@ static int next_getadapter_fib(struct aac_dev * dev, void __user *arg)
+ 		/*
+ 		 *	Extract the AdapterFibContext from the Input parameters.
+ 		 */
+-		if (fibctx->unique == f.fibctx) {   /* We found a winner */
++		if (fibctx->unique == f.fibctx) { /* We found a winner */
+ 			break;
+ 		}
+ 		entry = entry->next;
+ 		fibctx = NULL;
+ 	}
+ 	if (!fibctx) {
++		spin_unlock_irqrestore(&dev->fib_lock, flags);
+ 		dprintk ((KERN_INFO "Fib Context not found\n"));
+ 		return -EINVAL;
+ 	}
  
- void
--dasd_free_erp_request(struct dasd_ccw_req * cqr, struct dasd_device * device)
-+dasd_free_erp_request(struct dasd_ccw_req *cqr, struct dasd_device * device)
+ 	if((fibctx->type != FSAFS_NTC_GET_ADAPTER_FIB_CONTEXT) ||
+ 		 (fibctx->size != sizeof(struct aac_fib_context))) {
++		spin_unlock_irqrestore(&dev->fib_lock, flags);
+ 		dprintk ((KERN_INFO "Fib Context corrupt?\n"));
+ 		return -EINVAL;
+ 	}
+ 	status = 0;
+-	spin_lock_irqsave(&dev->fib_lock, flags);
+ 	/*
+ 	 *	If there are no fibs to send back, then either wait or return
+ 	 *	-EAGAIN
+ 	 */
+ return_fib:
+ 	if (!list_empty(&fibctx->fib_list)) {
+-		struct list_head * entry;
+ 		/*
+ 		 *	Pull the next fib from the fibs
+ 		 */
+ 		entry = fibctx->fib_list.next;
+ 		list_del(entry);
+-		
++
+ 		fib = list_entry(entry, struct fib, fiblink);
+ 		fibctx->count--;
+ 		spin_unlock_irqrestore(&dev->fib_lock, flags);
+@@ -289,7 +290,7 @@ return_fib:
+ 			kfree(fib->hw_fib_va);
+ 			kfree(fib);
+ 			return -EFAULT;
+-		}	
++		}
+ 		/*
+ 		 *	Free the space occupied by this copy of the fib.
+ 		 */
+@@ -318,7 +319,7 @@ return_fib:
+ 			}
+ 		} else {
+ 			status = -EAGAIN;
+-		}	
++		}
+ 	}
+ 	fibctx->jiffies = jiffies/HZ;
+ 	return status;
+@@ -327,7 +328,9 @@ return_fib:
+ int aac_close_fib_context(struct aac_dev * dev, struct aac_fib_context * fibctx)
  {
- 	unsigned long flags;
+ 	struct fib *fib;
++	unsigned long flags;
  
-@@ -81,11 +83,11 @@ dasd_free_erp_request(struct dasd_ccw_req * cqr, struct dasd_device * device)
-  * dasd_default_erp_action just retries the current cqr
++	spin_lock_irqsave(&dev->fib_lock, flags);
+ 	/*
+ 	 *	First free any FIBs that have not been consumed.
+ 	 */
+@@ -350,6 +353,7 @@ int aac_close_fib_context(struct aac_dev * dev, struct aac_fib_context * fibctx)
+ 	 *	Remove the Context from the AdapterFibContext List
+ 	 */
+ 	list_del(&fibctx->next);
++	spin_unlock_irqrestore(&dev->fib_lock, flags);
+ 	/*
+ 	 *	Invalidate context
+ 	 */
+@@ -368,7 +372,7 @@ int aac_close_fib_context(struct aac_dev * dev, struct aac_fib_context * fibctx)
+  *
+  *	This routine will close down the fibctx passed in from the user.
   */
- struct dasd_ccw_req *
--dasd_default_erp_action(struct dasd_ccw_req * cqr)
-+dasd_default_erp_action(struct dasd_ccw_req *cqr)
+- 
++
+ static int close_getadapter_fib(struct aac_dev * dev, void __user *arg)
  {
- 	struct dasd_device *device;
+ 	struct aac_fib_context *fibctx;
+@@ -415,8 +419,8 @@ static int close_getadapter_fib(struct aac_dev * dev, void __user *arg)
+  *	@arg: ioctl arguments
+  *
+  *	This routine returns the driver version.
+- *      Under Linux, there have been no version incompatibilities, so this is 
+- *      simple!
++ *	Under Linux, there have been no version incompatibilities, so this is
++ *	simple!
+  */
  
--	device = cqr->device;
-+	device = cqr->startdev;
+ static int check_revision(struct aac_dev *dev, void __user *arg)
+@@ -426,12 +430,12 @@ static int check_revision(struct aac_dev *dev, void __user *arg)
+ 	u32 version;
  
-         /* just retry - there is nothing to save ... I got no sense data.... */
-         if (cqr->retries > 0) {
-@@ -93,12 +95,12 @@ dasd_default_erp_action(struct dasd_ccw_req * cqr)
-                              "default ERP called (%i retries left)",
-                              cqr->retries);
- 		cqr->lpm    = LPM_ANYPATH;
--		cqr->status = DASD_CQR_QUEUED;
-+		cqr->status = DASD_CQR_FILLED;
-         } else {
-                 DEV_MESSAGE (KERN_WARNING, device, "%s",
- 			     "default ERP called (NO retry left)");
- 		cqr->status = DASD_CQR_FAILED;
--		cqr->stopclk = get_clock ();
-+		cqr->stopclk = get_clock();
-         }
-         return cqr;
- }				/* end dasd_default_erp_action */
-@@ -117,15 +119,12 @@ dasd_default_erp_action(struct dasd_ccw_req * cqr)
-  * RETURN VALUES
-  *   cqr		pointer to the original CQR
-  */
--struct dasd_ccw_req *
--dasd_default_erp_postaction(struct dasd_ccw_req * cqr)
-+struct dasd_ccw_req *dasd_default_erp_postaction(struct dasd_ccw_req *cqr)
- {
--	struct dasd_device *device;
- 	int success;
+ 	response.compat = 1;
+-	version = (simple_strtol(driver_version, 
++	version = (simple_strtol(driver_version,
+ 				&driver_version, 10) << 24) | 0x00000400;
+ 	version += simple_strtol(driver_version + 1, &driver_version, 10) << 16;
+ 	version += simple_strtol(driver_version + 1, NULL, 10);
+ 	response.version = cpu_to_le32(version);
+-#	if (defined(AAC_DRIVER_BUILD))
++#	ifdef AAC_DRIVER_BUILD
+ 		response.build = cpu_to_le32(AAC_DRIVER_BUILD);
+ #	else
+ 		response.build = cpu_to_le32(9999);
+@@ -464,7 +468,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
+ 	u32 data_dir;
+ 	void __user *sg_user[32];
+ 	void *sg_list[32];
+-	u32   sg_indx = 0;
++	u32 sg_indx = 0;
+ 	u32 byte_count = 0;
+ 	u32 actual_fibsize64, actual_fibsize = 0;
+ 	int i;
+@@ -475,7 +479,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
+ 		return -EBUSY;
+ 	}
+ 	if (!capable(CAP_SYS_ADMIN)){
+-		dprintk((KERN_DEBUG"aacraid: No permission to send raw srb\n")); 
++		dprintk((KERN_DEBUG"aacraid: No permission to send raw srb\n"));
+ 		return -EPERM;
+ 	}
+ 	/*
+@@ -490,7 +494,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
  
- 	BUG_ON(cqr->refers == NULL || cqr->function == NULL);
+ 	memset(sg_list, 0, sizeof(sg_list)); /* cleanup may take issue */
+ 	if(copy_from_user(&fibsize, &user_srb->count,sizeof(u32))){
+-		dprintk((KERN_DEBUG"aacraid: Could not copy data size from user\n")); 
++		dprintk((KERN_DEBUG"aacraid: Could not copy data size from user\n"));
+ 		rcode = -EFAULT;
+ 		goto cleanup;
+ 	}
+@@ -507,7 +511,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
+ 		goto cleanup;
+ 	}
+ 	if(copy_from_user(user_srbcmd, user_srb,fibsize)){
+-		dprintk((KERN_DEBUG"aacraid: Could not copy srb from user\n")); 
++		dprintk((KERN_DEBUG"aacraid: Could not copy srb from user\n"));
+ 		rcode = -EFAULT;
+ 		goto cleanup;
+ 	}
+@@ -518,15 +522,15 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
+ 	// Fix up srb for endian and force some values
  
--	device = cqr->device;
- 	success = cqr->status == DASD_CQR_DONE;
+ 	srbcmd->function = cpu_to_le32(SRBF_ExecuteScsi);	// Force this
+-	srbcmd->channel  = cpu_to_le32(user_srbcmd->channel);
++	srbcmd->channel	 = cpu_to_le32(user_srbcmd->channel);
+ 	srbcmd->id	 = cpu_to_le32(user_srbcmd->id);
+-	srbcmd->lun      = cpu_to_le32(user_srbcmd->lun);
+-	srbcmd->timeout  = cpu_to_le32(user_srbcmd->timeout);
+-	srbcmd->flags    = cpu_to_le32(flags);
++	srbcmd->lun	 = cpu_to_le32(user_srbcmd->lun);
++	srbcmd->timeout	 = cpu_to_le32(user_srbcmd->timeout);
++	srbcmd->flags	 = cpu_to_le32(flags);
+ 	srbcmd->retry_limit = 0; // Obsolete parameter
+ 	srbcmd->cdb_size = cpu_to_le32(user_srbcmd->cdb_size);
+ 	memcpy(srbcmd->cdb, user_srbcmd->cdb, sizeof(srbcmd->cdb));
+-	
++
+ 	switch (flags & (SRB_DataIn | SRB_DataOut)) {
+ 	case SRB_DataOut:
+ 		data_dir = DMA_TO_DEVICE;
+@@ -582,7 +586,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
+ 				void* p;
+ 				/* Does this really need to be GFP_DMA? */
+ 				p = kmalloc(upsg->sg[i].count,GFP_KERNEL|__GFP_DMA);
+-				if(p == 0) {
++				if(!p) {
+ 					dprintk((KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n",
+ 					  upsg->sg[i].count,i,upsg->count));
+ 					rcode = -ENOMEM;
+@@ -594,7 +598,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
+ 				sg_list[i] = p; // save so we can clean up later
+ 				sg_indx = i;
  
- 	/* free all ERPs - but NOT the original cqr */
-@@ -133,10 +132,10 @@ dasd_default_erp_postaction(struct dasd_ccw_req * cqr)
- 		struct dasd_ccw_req *refers;
+-				if( flags & SRB_DataOut ){
++				if (flags & SRB_DataOut) {
+ 					if(copy_from_user(p,sg_user[i],upsg->sg[i].count)){
+ 						dprintk((KERN_DEBUG"aacraid: Could not copy sg data from user\n"));
+ 						rcode = -EFAULT;
+@@ -626,7 +630,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
+ 				void* p;
+ 				/* Does this really need to be GFP_DMA? */
+ 				p = kmalloc(usg->sg[i].count,GFP_KERNEL|__GFP_DMA);
+-				if(p == 0) {
++				if(!p) {
+ 					kfree (usg);
+ 					dprintk((KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n",
+ 					  usg->sg[i].count,i,usg->count));
+@@ -637,7 +641,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
+ 				sg_list[i] = p; // save so we can clean up later
+ 				sg_indx = i;
  
- 		refers = cqr->refers;
--		/* remove the request from the device queue */
--		list_del(&cqr->list);
-+		/* remove the request from the block queue */
-+		list_del(&cqr->blocklist);
- 		/* free the finished erp request */
--		dasd_free_erp_request(cqr, device);
-+		dasd_free_erp_request(cqr, cqr->memdev);
- 		cqr = refers;
+-				if( flags & SRB_DataOut ){
++				if (flags & SRB_DataOut) {
+ 					if(copy_from_user(p,sg_user[i],upsg->sg[i].count)){
+ 						kfree (usg);
+ 						dprintk((KERN_DEBUG"aacraid: Could not copy sg data from user\n"));
+@@ -668,7 +672,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
+ 				void* p;
+ 				/* Does this really need to be GFP_DMA? */
+ 				p = kmalloc(usg->sg[i].count,GFP_KERNEL|__GFP_DMA);
+-				if(p == 0) {
++				if(!p) {
+ 					dprintk((KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n",
+ 					  usg->sg[i].count,i,usg->count));
+ 					rcode = -ENOMEM;
+@@ -680,7 +684,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
+ 				sg_list[i] = p; // save so we can clean up later
+ 				sg_indx = i;
+ 
+-				if( flags & SRB_DataOut ){
++				if (flags & SRB_DataOut) {
+ 					if(copy_from_user(p,sg_user[i],usg->sg[i].count)){
+ 						dprintk((KERN_DEBUG"aacraid: Could not copy sg data from user\n"));
+ 						rcode = -EFAULT;
+@@ -698,7 +702,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
+ 				dma_addr_t addr;
+ 				void* p;
+ 				p = kmalloc(upsg->sg[i].count, GFP_KERNEL);
+-				if(p == 0) {
++				if (!p) {
+ 					dprintk((KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n",
+ 					  upsg->sg[i].count, i, upsg->count));
+ 					rcode = -ENOMEM;
+@@ -708,7 +712,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
+ 				sg_list[i] = p; // save so we can clean up later
+ 				sg_indx = i;
+ 
+-				if( flags & SRB_DataOut ){
++				if (flags & SRB_DataOut) {
+ 					if(copy_from_user(p, sg_user[i],
+ 							upsg->sg[i].count)) {
+ 						dprintk((KERN_DEBUG"aacraid: Could not copy sg data from user\n"));
+@@ -734,19 +738,19 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
  	}
  
-@@ -157,7 +156,7 @@ dasd_log_sense(struct dasd_ccw_req *cqr, struct irb *irb)
- {
- 	struct dasd_device *device;
+ 	if (status != 0){
+-		dprintk((KERN_DEBUG"aacraid: Could not send raw srb fib to hba\n")); 
++		dprintk((KERN_DEBUG"aacraid: Could not send raw srb fib to hba\n"));
+ 		rcode = -ENXIO;
+ 		goto cleanup;
+ 	}
  
--	device = cqr->device;
-+	device = cqr->startdev;
- 	/* dump sense data */
- 	if (device->discipline && device->discipline->dump_sense)
- 		device->discipline->dump_sense(device, cqr, irb);
-diff --git a/drivers/s390/block/dasd_fba.c b/drivers/s390/block/dasd_fba.c
-index 1d95822..d13ea05 100644
---- a/drivers/s390/block/dasd_fba.c
-+++ b/drivers/s390/block/dasd_fba.c
-@@ -117,6 +117,7 @@ locate_record(struct ccw1 * ccw, struct LO_fba_data *data, int rw,
- static int
- dasd_fba_check_characteristics(struct dasd_device *device)
- {
-+	struct dasd_block *block;
- 	struct dasd_fba_private *private;
- 	struct ccw_device *cdev = device->cdev;
- 	void *rdc_data;
-@@ -133,6 +134,16 @@ dasd_fba_check_characteristics(struct dasd_device *device)
- 		}
- 		device->private = (void *) private;
+-	if( flags & SRB_DataIn ) {
++	if (flags & SRB_DataIn) {
+ 		for(i = 0 ; i <= sg_indx; i++){
+ 			byte_count = le32_to_cpu(
+ 			  (dev->adapter_info.options & AAC_OPT_SGMAP_HOST64)
+ 			      ? ((struct sgmap64*)&srbcmd->sg)->sg[i].count
+ 			      : srbcmd->sg.sg[i].count);
+ 			if(copy_to_user(sg_user[i], sg_list[i], byte_count)){
+-				dprintk((KERN_DEBUG"aacraid: Could not copy sg data to user\n")); 
++				dprintk((KERN_DEBUG"aacraid: Could not copy sg data to user\n"));
+ 				rcode = -EFAULT;
+ 				goto cleanup;
+ 
+@@ -756,7 +760,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
+ 
+ 	reply = (struct aac_srb_reply *) fib_data(srbfib);
+ 	if(copy_to_user(user_reply,reply,sizeof(struct aac_srb_reply))){
+-		dprintk((KERN_DEBUG"aacraid: Could not copy reply to user\n")); 
++		dprintk((KERN_DEBUG"aacraid: Could not copy reply to user\n"));
+ 		rcode = -EFAULT;
+ 		goto cleanup;
  	}
-+	block = dasd_alloc_block();
-+	if (IS_ERR(block)) {
-+		DEV_MESSAGE(KERN_WARNING, device, "%s",
-+			    "could not allocate dasd block structure");
-+		kfree(device->private);
-+		return PTR_ERR(block);
-+	}
-+	device->block = block;
-+	block->base = device;
-+
- 	/* Read Device Characteristics */
- 	rdc_data = (void *) &(private->rdc_data);
- 	rc = dasd_generic_read_dev_chars(device, "FBA ", &rdc_data, 32);
-@@ -155,60 +166,37 @@ dasd_fba_check_characteristics(struct dasd_device *device)
- 	return 0;
+@@ -775,34 +779,34 @@ cleanup:
  }
  
--static int
--dasd_fba_do_analysis(struct dasd_device *device)
-+static int dasd_fba_do_analysis(struct dasd_block *block)
+ struct aac_pci_info {
+-        u32 bus;
+-        u32 slot;
++	u32 bus;
++	u32 slot;
+ };
+ 
+ 
+ static int aac_get_pci_info(struct aac_dev* dev, void __user *arg)
  {
- 	struct dasd_fba_private *private;
- 	int sb, rc;
+-        struct aac_pci_info pci_info;
++	struct aac_pci_info pci_info;
  
--	private = (struct dasd_fba_private *) device->private;
-+	private = (struct dasd_fba_private *) block->base->private;
- 	rc = dasd_check_blocksize(private->rdc_data.blk_size);
- 	if (rc) {
--		DEV_MESSAGE(KERN_INFO, device, "unknown blocksize %d",
-+		DEV_MESSAGE(KERN_INFO, block->base, "unknown blocksize %d",
- 			    private->rdc_data.blk_size);
- 		return rc;
+ 	pci_info.bus = dev->pdev->bus->number;
+ 	pci_info.slot = PCI_SLOT(dev->pdev->devfn);
+ 
+-       if (copy_to_user(arg, &pci_info, sizeof(struct aac_pci_info))) {
+-               dprintk((KERN_DEBUG "aacraid: Could not copy pci info\n"));
+-               return -EFAULT;
++	if (copy_to_user(arg, &pci_info, sizeof(struct aac_pci_info))) {
++		dprintk((KERN_DEBUG "aacraid: Could not copy pci info\n"));
++		return -EFAULT;
  	}
--	device->blocks = private->rdc_data.blk_bdsa;
--	device->bp_block = private->rdc_data.blk_size;
--	device->s2b_shift = 0;	/* bits to shift 512 to get a block */
-+	block->blocks = private->rdc_data.blk_bdsa;
-+	block->bp_block = private->rdc_data.blk_size;
-+	block->s2b_shift = 0;	/* bits to shift 512 to get a block */
- 	for (sb = 512; sb < private->rdc_data.blk_size; sb = sb << 1)
--		device->s2b_shift++;
-+		block->s2b_shift++;
- 	return 0;
+-        return 0;
++	return 0;
  }
+- 
++
  
--static int
--dasd_fba_fill_geometry(struct dasd_device *device, struct hd_geometry *geo)
-+static int dasd_fba_fill_geometry(struct dasd_block *block,
-+				  struct hd_geometry *geo)
+ int aac_do_ioctl(struct aac_dev * dev, int cmd, void __user *arg)
  {
--	if (dasd_check_blocksize(device->bp_block) != 0)
-+	if (dasd_check_blocksize(block->bp_block) != 0)
- 		return -EINVAL;
--	geo->cylinders = (device->blocks << device->s2b_shift) >> 10;
-+	geo->cylinders = (block->blocks << block->s2b_shift) >> 10;
- 	geo->heads = 16;
--	geo->sectors = 128 >> device->s2b_shift;
-+	geo->sectors = 128 >> block->s2b_shift;
- 	return 0;
+ 	int status;
+-	
++
+ 	/*
+ 	 *	HBA gets first crack
+ 	 */
+-	 
++
+ 	status = aac_dev_ioctl(dev, cmd, arg);
+ 	if(status != -ENOTTY)
+ 		return status;
+@@ -832,7 +836,7 @@ int aac_do_ioctl(struct aac_dev * dev, int cmd, void __user *arg)
+ 		break;
+ 	default:
+ 		status = -ENOTTY;
+-	  	break;	
++		break;
+ 	}
+ 	return status;
  }
- 
--static dasd_era_t
--dasd_fba_examine_error(struct dasd_ccw_req * cqr, struct irb * irb)
--{
--	struct dasd_device *device;
--	struct ccw_device *cdev;
--
--	device = (struct dasd_device *) cqr->device;
--	if (irb->scsw.cstat == 0x00 &&
--	    irb->scsw.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))
--		return dasd_era_none;
--
--	cdev = device->cdev;
--	switch (cdev->id.dev_type) {
--	case 0x3370:
--		return dasd_3370_erp_examine(cqr, irb);
--	case 0x9336:
--		return dasd_9336_erp_examine(cqr, irb);
--	default:
--		return dasd_era_recover;
--	}
--}
--
- static dasd_erp_fn_t
- dasd_fba_erp_action(struct dasd_ccw_req * cqr)
+diff --git a/drivers/scsi/aacraid/comminit.c b/drivers/scsi/aacraid/comminit.c
+index 8736813..89cc8b7 100644
+--- a/drivers/scsi/aacraid/comminit.c
++++ b/drivers/scsi/aacraid/comminit.c
+@@ -301,10 +301,10 @@ struct aac_dev *aac_init_adapter(struct aac_dev *dev)
+ 	if ((!aac_adapter_sync_cmd(dev, GET_ADAPTER_PROPERTIES,
+ 		0, 0, 0, 0, 0, 0, status+0, status+1, status+2, NULL, NULL)) &&
+ 	 		(status[0] == 0x00000001)) {
+-		if (status[1] & AAC_OPT_NEW_COMM_64)
++		if (status[1] & le32_to_cpu(AAC_OPT_NEW_COMM_64))
+ 			dev->raw_io_64 = 1;
+ 		if (dev->a_ops.adapter_comm &&
+-		    (status[1] & AAC_OPT_NEW_COMM))
++		    (status[1] & le32_to_cpu(AAC_OPT_NEW_COMM)))
+ 			dev->comm_interface = AAC_COMM_MESSAGE;
+ 		if ((dev->comm_interface == AAC_COMM_MESSAGE) &&
+ 		    (status[2] > dev->base_size)) {
+diff --git a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c
+index abce48c..81b3692 100644
+--- a/drivers/scsi/aacraid/commsup.c
++++ b/drivers/scsi/aacraid/commsup.c
+@@ -56,7 +56,7 @@
+  *	Allocate and map the shared PCI space for the FIB blocks used to
+  *	talk to the Adaptec firmware.
+  */
+- 
++
+ static int fib_map_alloc(struct aac_dev *dev)
  {
-@@ -221,13 +209,34 @@ dasd_fba_erp_postaction(struct dasd_ccw_req * cqr)
- 	if (cqr->function == dasd_default_erp_action)
- 		return dasd_default_erp_postaction;
- 
--	DEV_MESSAGE(KERN_WARNING, cqr->device, "unknown ERP action %p",
-+	DEV_MESSAGE(KERN_WARNING, cqr->startdev, "unknown ERP action %p",
- 		    cqr->function);
- 	return NULL;
- }
+ 	dprintk((KERN_INFO
+@@ -109,14 +109,16 @@ int aac_fib_setup(struct aac_dev * dev)
+ 	}
+ 	if (i<0)
+ 		return -ENOMEM;
+-		
++
+ 	hw_fib = dev->hw_fib_va;
+ 	hw_fib_pa = dev->hw_fib_pa;
+ 	memset(hw_fib, 0, dev->max_fib_size * (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB));
+ 	/*
+ 	 *	Initialise the fibs
+ 	 */
+-	for (i = 0, fibptr = &dev->fibs[i]; i < (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB); i++, fibptr++) 
++	for (i = 0, fibptr = &dev->fibs[i];
++		i < (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB);
++		i++, fibptr++)
+ 	{
+ 		fibptr->dev = dev;
+ 		fibptr->hw_fib_va = hw_fib;
+@@ -148,13 +150,13 @@ int aac_fib_setup(struct aac_dev * dev)
+  *	Allocate a fib from the adapter fib pool. If the pool is empty we
+  *	return NULL.
+  */
+- 
++
+ struct fib *aac_fib_alloc(struct aac_dev *dev)
+ {
+ 	struct fib * fibptr;
+ 	unsigned long flags;
+ 	spin_lock_irqsave(&dev->fib_lock, flags);
+-	fibptr = dev->free_fib;	
++	fibptr = dev->free_fib;
+ 	if(!fibptr){
+ 		spin_unlock_irqrestore(&dev->fib_lock, flags);
+ 		return fibptr;
+@@ -171,6 +173,7 @@ struct fib *aac_fib_alloc(struct aac_dev *dev)
+ 	 *	each I/O
+ 	 */
+ 	fibptr->hw_fib_va->header.XferState = 0;
++	fibptr->flags = 0;
+ 	fibptr->callback = NULL;
+ 	fibptr->callback_data = NULL;
  
--static struct dasd_ccw_req *
--dasd_fba_build_cp(struct dasd_device * device, struct request *req)
-+static void dasd_fba_handle_unsolicited_interrupt(struct dasd_device *device,
-+						   struct irb *irb)
-+{
-+	char mask;
+@@ -183,7 +186,7 @@ struct fib *aac_fib_alloc(struct aac_dev *dev)
+  *
+  *	Frees up a fib and places it on the appropriate queue
+  */
+- 
 +
-+	/* first of all check for state change pending interrupt */
-+	mask = DEV_STAT_ATTENTION | DEV_STAT_DEV_END | DEV_STAT_UNIT_EXCEP;
-+	if ((irb->scsw.dstat & mask) == mask) {
-+		dasd_generic_handle_state_change(device);
-+		return;
-+	}
+ void aac_fib_free(struct fib *fibptr)
+ {
+ 	unsigned long flags;
+@@ -204,10 +207,10 @@ void aac_fib_free(struct fib *fibptr)
+ /**
+  *	aac_fib_init	-	initialise a fib
+  *	@fibptr: The fib to initialize
+- *	
++ *
+  *	Set up the generic fib fields ready for use
+  */
+- 
++
+ void aac_fib_init(struct fib *fibptr)
+ {
+ 	struct hw_fib *hw_fib = fibptr->hw_fib_va;
+@@ -227,12 +230,12 @@ void aac_fib_init(struct fib *fibptr)
+  *	Will deallocate and return to the free pool the FIB pointed to by the
+  *	caller.
+  */
+- 
++
+ static void fib_dealloc(struct fib * fibptr)
+ {
+ 	struct hw_fib *hw_fib = fibptr->hw_fib_va;
+ 	BUG_ON(hw_fib->header.StructType != FIB_MAGIC);
+-	hw_fib->header.XferState = 0;        
++	hw_fib->header.XferState = 0;
+ }
+ 
+ /*
+@@ -241,7 +244,7 @@ static void fib_dealloc(struct fib * fibptr)
+  *	these routines and are the only routines which have a knowledge of the
+  *	 how these queues are implemented.
+  */
+- 
 +
-+	/* check for unsolicited interrupts */
-+	DEV_MESSAGE(KERN_DEBUG, device, "%s",
-+		    "unsolicited interrupt received");
-+	device->discipline->dump_sense(device, NULL, irb);
-+	dasd_schedule_device_bh(device);
-+	return;
-+};
+ /**
+  *	aac_get_entry		-	get a queue entry
+  *	@dev: Adapter
+@@ -254,7 +257,7 @@ static void fib_dealloc(struct fib * fibptr)
+  *	is full(no free entries) than no entry is returned and the function returns 0 otherwise 1 is
+  *	returned.
+  */
+- 
 +
-+static struct dasd_ccw_req *dasd_fba_build_cp(struct dasd_device * memdev,
-+					      struct dasd_block *block,
-+					      struct request *req)
+ static int aac_get_entry (struct aac_dev * dev, u32 qid, struct aac_entry **entry, u32 * index, unsigned long *nonotify)
  {
- 	struct dasd_fba_private *private;
- 	unsigned long *idaws;
-@@ -242,17 +251,17 @@ dasd_fba_build_cp(struct dasd_device * device, struct request *req)
- 	unsigned int blksize, off;
- 	unsigned char cmd;
+ 	struct aac_queue * q;
+@@ -279,26 +282,27 @@ static int aac_get_entry (struct aac_dev * dev, u32 qid, struct aac_entry **entr
+ 				idx = ADAP_NORM_RESP_ENTRIES;
+ 		}
+ 		if (idx != le32_to_cpu(*(q->headers.consumer)))
+-			*nonotify = 1; 
++			*nonotify = 1;
+ 	}
  
--	private = (struct dasd_fba_private *) device->private;
-+	private = (struct dasd_fba_private *) block->base->private;
- 	if (rq_data_dir(req) == READ) {
- 		cmd = DASD_FBA_CCW_READ;
- 	} else if (rq_data_dir(req) == WRITE) {
- 		cmd = DASD_FBA_CCW_WRITE;
- 	} else
- 		return ERR_PTR(-EINVAL);
--	blksize = device->bp_block;
-+	blksize = block->bp_block;
- 	/* Calculate record id of first and last block. */
--	first_rec = req->sector >> device->s2b_shift;
--	last_rec = (req->sector + req->nr_sectors - 1) >> device->s2b_shift;
-+	first_rec = req->sector >> block->s2b_shift;
-+	last_rec = (req->sector + req->nr_sectors - 1) >> block->s2b_shift;
- 	/* Check struct bio and count the number of blocks for the request. */
- 	count = 0;
- 	cidaw = 0;
-@@ -260,7 +269,7 @@ dasd_fba_build_cp(struct dasd_device * device, struct request *req)
- 		if (bv->bv_len & (blksize - 1))
- 			/* Fba can only do full blocks. */
- 			return ERR_PTR(-EINVAL);
--		count += bv->bv_len >> (device->s2b_shift + 9);
-+		count += bv->bv_len >> (block->s2b_shift + 9);
- #if defined(CONFIG_64BIT)
- 		if (idal_is_needed (page_address(bv->bv_page), bv->bv_len))
- 			cidaw += bv->bv_len / blksize;
-@@ -284,13 +293,13 @@ dasd_fba_build_cp(struct dasd_device * device, struct request *req)
+ 	if (qid == AdapNormCmdQueue) {
+-	        if (*index >= ADAP_NORM_CMD_ENTRIES) 
++		if (*index >= ADAP_NORM_CMD_ENTRIES)
+ 			*index = 0; /* Wrap to front of the Producer Queue. */
+ 	} else {
+-		if (*index >= ADAP_NORM_RESP_ENTRIES) 
++		if (*index >= ADAP_NORM_RESP_ENTRIES)
+ 			*index = 0; /* Wrap to front of the Producer Queue. */
  	}
- 	/* Allocate the ccw request. */
- 	cqr = dasd_smalloc_request(dasd_fba_discipline.name,
--				   cplength, datasize, device);
-+				   cplength, datasize, memdev);
- 	if (IS_ERR(cqr))
- 		return cqr;
- 	ccw = cqr->cpaddr;
- 	/* First ccw is define extent. */
- 	define_extent(ccw++, cqr->data, rq_data_dir(req),
--		      device->bp_block, req->sector, req->nr_sectors);
-+		      block->bp_block, req->sector, req->nr_sectors);
- 	/* Build locate_record + read/write ccws. */
- 	idaws = (unsigned long *) (cqr->data + sizeof(struct DE_fba_data));
- 	LO_data = (struct LO_fba_data *) (idaws + cidaw);
-@@ -326,7 +335,7 @@ dasd_fba_build_cp(struct dasd_device * device, struct request *req)
- 					ccw[-1].flags |= CCW_FLAG_CC;
- 			}
- 			ccw->cmd_code = cmd;
--			ccw->count = device->bp_block;
-+			ccw->count = block->bp_block;
- 			if (idal_is_needed(dst, blksize)) {
- 				ccw->cda = (__u32)(addr_t) idaws;
- 				ccw->flags = CCW_FLAG_IDA;
-@@ -342,7 +351,9 @@ dasd_fba_build_cp(struct dasd_device * device, struct request *req)
+ 
+-        if ((*index + 1) == le32_to_cpu(*(q->headers.consumer))) { /* Queue is full */
++	/* Queue is full */
++	if ((*index + 1) == le32_to_cpu(*(q->headers.consumer))) {
+ 		printk(KERN_WARNING "Queue %d full, %u outstanding.\n",
+ 				qid, q->numpending);
+ 		return 0;
+ 	} else {
+-	        *entry = q->base + *index;
++		*entry = q->base + *index;
+ 		return 1;
  	}
- 	if (req->cmd_flags & REQ_FAILFAST)
- 		set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags);
--	cqr->device = device;
-+	cqr->startdev = memdev;
-+	cqr->memdev = memdev;
-+	cqr->block = block;
- 	cqr->expires = 5 * 60 * HZ;	/* 5 minutes */
- 	cqr->retries = 32;
- 	cqr->buildclk = get_clock();
-@@ -363,8 +374,8 @@ dasd_fba_free_cp(struct dasd_ccw_req *cqr, struct request *req)
+-}   
++}
  
- 	if (!dasd_page_cache)
- 		goto out;
--	private = (struct dasd_fba_private *) cqr->device->private;
--	blksize = cqr->device->bp_block;
-+	private = (struct dasd_fba_private *) cqr->block->base->private;
-+	blksize = cqr->block->bp_block;
- 	ccw = cqr->cpaddr;
- 	/* Skip over define extent & locate record. */
- 	ccw++;
-@@ -394,10 +405,15 @@ dasd_fba_free_cp(struct dasd_ccw_req *cqr, struct request *req)
+ /**
+  *	aac_queue_get		-	get the next free QE
+@@ -320,31 +324,29 @@ int aac_queue_get(struct aac_dev * dev, u32 * index, u32 qid, struct hw_fib * hw
+ {
+ 	struct aac_entry * entry = NULL;
+ 	int map = 0;
+-	    
++
+ 	if (qid == AdapNormCmdQueue) {
+ 		/*  if no entries wait for some if caller wants to */
+-        	while (!aac_get_entry(dev, qid, &entry, index, nonotify)) 
+-        	{
++		while (!aac_get_entry(dev, qid, &entry, index, nonotify)) {
+ 			printk(KERN_ERR "GetEntries failed\n");
+ 		}
+-	        /*
+-	         *	Setup queue entry with a command, status and fib mapped
+-	         */
+-	        entry->size = cpu_to_le32(le16_to_cpu(hw_fib->header.Size));
+-	        map = 1;
++		/*
++		 *	Setup queue entry with a command, status and fib mapped
++		 */
++		entry->size = cpu_to_le32(le16_to_cpu(hw_fib->header.Size));
++		map = 1;
+ 	} else {
+-	        while(!aac_get_entry(dev, qid, &entry, index, nonotify)) 
+-	        {
++		while (!aac_get_entry(dev, qid, &entry, index, nonotify)) {
+ 			/* if no entries wait for some if caller wants to */
+ 		}
+-        	/*
+-        	 *	Setup queue entry with command, status and fib mapped
+-        	 */
+-        	entry->size = cpu_to_le32(le16_to_cpu(hw_fib->header.Size));
+-        	entry->addr = hw_fib->header.SenderFibAddress;
+-     			/* Restore adapters pointer to the FIB */
++		/*
++		 *	Setup queue entry with command, status and fib mapped
++		 */
++		entry->size = cpu_to_le32(le16_to_cpu(hw_fib->header.Size));
++		entry->addr = hw_fib->header.SenderFibAddress;
++			/* Restore adapters pointer to the FIB */
+ 		hw_fib->header.ReceiverFibAddress = hw_fib->header.SenderFibAddress;	/* Let the adapter now where to find its data */
+-        	map = 0;
++		map = 0;
  	}
- out:
- 	status = cqr->status == DASD_CQR_DONE;
--	dasd_sfree_request(cqr, cqr->device);
-+	dasd_sfree_request(cqr, cqr->memdev);
- 	return status;
+ 	/*
+ 	 *	If MapFib is true than we need to map the Fib and put pointers
+@@ -356,8 +358,8 @@ int aac_queue_get(struct aac_dev * dev, u32 * index, u32 qid, struct hw_fib * hw
  }
  
-+static void dasd_fba_handle_terminated_request(struct dasd_ccw_req *cqr)
-+{
-+	cqr->status = DASD_CQR_FILLED;
-+};
-+
- static int
- dasd_fba_fill_info(struct dasd_device * device,
- 		   struct dasd_information2_t * info)
-@@ -546,9 +562,10 @@ static struct dasd_discipline dasd_fba_discipline = {
- 	.fill_geometry = dasd_fba_fill_geometry,
- 	.start_IO = dasd_start_IO,
- 	.term_IO = dasd_term_IO,
--	.examine_error = dasd_fba_examine_error,
-+	.handle_terminated_request = dasd_fba_handle_terminated_request,
- 	.erp_action = dasd_fba_erp_action,
- 	.erp_postaction = dasd_fba_erp_postaction,
-+	.handle_unsolicited_interrupt = dasd_fba_handle_unsolicited_interrupt,
- 	.build_cp = dasd_fba_build_cp,
- 	.free_cp = dasd_fba_free_cp,
- 	.dump_sense = dasd_fba_dump_sense,
-diff --git a/drivers/s390/block/dasd_genhd.c b/drivers/s390/block/dasd_genhd.c
-index 47ba446..aee6565 100644
---- a/drivers/s390/block/dasd_genhd.c
-+++ b/drivers/s390/block/dasd_genhd.c
-@@ -25,14 +25,15 @@
  /*
-  * Allocate and register gendisk structure for device.
+- *	Define the highest level of host to adapter communication routines. 
+- *	These routines will support host to adapter FS commuication. These 
++ *	Define the highest level of host to adapter communication routines.
++ *	These routines will support host to adapter FS commuication. These
+  *	routines have no knowledge of the commuication method used. This level
+  *	sends and receives FIBs. This level has no knowledge of how these FIBs
+  *	get passed back and forth.
+@@ -379,7 +381,7 @@ int aac_queue_get(struct aac_dev * dev, u32 * index, u32 qid, struct hw_fib * hw
+  *	an event to wait on must be supplied. This event will be set when a
+  *	response FIB is received from the adapter.
   */
--int
--dasd_gendisk_alloc(struct dasd_device *device)
-+int dasd_gendisk_alloc(struct dasd_block *block)
- {
- 	struct gendisk *gdp;
-+	struct dasd_device *base;
- 	int len;
- 
- 	/* Make sure the minor for this device exists. */
--	if (device->devindex >= DASD_PER_MAJOR)
-+	base = block->base;
-+	if (base->devindex >= DASD_PER_MAJOR)
+- 
++
+ int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size,
+ 		int priority, int wait, int reply, fib_callback callback,
+ 		void *callback_data)
+@@ -392,16 +394,17 @@ int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size,
+ 	if (!(hw_fib->header.XferState & cpu_to_le32(HostOwned)))
  		return -EBUSY;
+ 	/*
+-	 *	There are 5 cases with the wait and reponse requested flags. 
++	 *	There are 5 cases with the wait and reponse requested flags.
+ 	 *	The only invalid cases are if the caller requests to wait and
+ 	 *	does not request a response and if the caller does not want a
+ 	 *	response and the Fib is not allocated from pool. If a response
+ 	 *	is not requesed the Fib will just be deallocaed by the DPC
+ 	 *	routine when the response comes back from the adapter. No
+-	 *	further processing will be done besides deleting the Fib. We 
++	 *	further processing will be done besides deleting the Fib. We
+ 	 *	will have a debug mode where the adapter can notify the host
+ 	 *	it had a problem and the host can log that fact.
+ 	 */
++	fibptr->flags = 0;
+ 	if (wait && !reply) {
+ 		return -EINVAL;
+ 	} else if (!wait && reply) {
+@@ -413,7 +416,7 @@ int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size,
+ 	} else if (wait && reply) {
+ 		hw_fib->header.XferState |= cpu_to_le32(ResponseExpected);
+ 		FIB_COUNTER_INCREMENT(aac_config.NormalSent);
+-	} 
++	}
+ 	/*
+ 	 *	Map the fib into 32bits by using the fib number
+ 	 */
+@@ -436,7 +439,7 @@ int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size,
+ 	hw_fib->header.Size = cpu_to_le16(sizeof(struct aac_fibhdr) + size);
+ 	if (le16_to_cpu(hw_fib->header.Size) > le16_to_cpu(hw_fib->header.SenderSize)) {
+ 		return -EMSGSIZE;
+-	}                
++	}
+ 	/*
+ 	 *	Get a queue entry connect the FIB to it and send an notify
+ 	 *	the adapter a command is ready.
+@@ -450,10 +453,10 @@ int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size,
+ 	if (!wait) {
+ 		fibptr->callback = callback;
+ 		fibptr->callback_data = callback_data;
++		fibptr->flags = FIB_CONTEXT_FLAG;
+ 	}
  
- 	gdp = alloc_disk(1 << DASD_PARTN_BITS);
-@@ -41,9 +42,9 @@ dasd_gendisk_alloc(struct dasd_device *device)
+ 	fibptr->done = 0;
+-	fibptr->flags = 0;
  
- 	/* Initialize gendisk structure. */
- 	gdp->major = DASD_MAJOR;
--	gdp->first_minor = device->devindex << DASD_PARTN_BITS;
-+	gdp->first_minor = base->devindex << DASD_PARTN_BITS;
- 	gdp->fops = &dasd_device_operations;
--	gdp->driverfs_dev = &device->cdev->dev;
-+	gdp->driverfs_dev = &base->cdev->dev;
+ 	FIB_COUNTER_INCREMENT(aac_config.FibsSent);
+ 
+@@ -473,9 +476,9 @@ int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size,
+ 	aac_adapter_deliver(fibptr);
  
  	/*
- 	 * Set device name.
-@@ -53,53 +54,51 @@ dasd_gendisk_alloc(struct dasd_device *device)
- 	 *   dasdaaaa - dasdzzzz : 456976 devices, added up = 475252
+-	 *	If the caller wanted us to wait for response wait now. 
++	 *	If the caller wanted us to wait for response wait now.
  	 */
- 	len = sprintf(gdp->disk_name, "dasd");
--	if (device->devindex > 25) {
--	        if (device->devindex > 701) {
--		        if (device->devindex > 18277)
-+	if (base->devindex > 25) {
-+		if (base->devindex > 701) {
-+			if (base->devindex > 18277)
- 			        len += sprintf(gdp->disk_name + len, "%c",
--					       'a'+(((device->devindex-18278)
-+					       'a'+(((base->devindex-18278)
- 						     /17576)%26));
- 			len += sprintf(gdp->disk_name + len, "%c",
--				       'a'+(((device->devindex-702)/676)%26));
-+				       'a'+(((base->devindex-702)/676)%26));
+-    
++
+ 	if (wait) {
+ 		spin_unlock_irqrestore(&fibptr->event_lock, flags);
+ 		/* Only set for first known interruptable command */
+@@ -522,7 +525,7 @@ int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size,
  		}
- 		len += sprintf(gdp->disk_name + len, "%c",
--			       'a'+(((device->devindex-26)/26)%26));
-+			       'a'+(((base->devindex-26)/26)%26));
- 	}
--	len += sprintf(gdp->disk_name + len, "%c", 'a'+(device->devindex%26));
-+	len += sprintf(gdp->disk_name + len, "%c", 'a'+(base->devindex%26));
- 
--	if (device->features & DASD_FEATURE_READONLY)
-+	if (block->base->features & DASD_FEATURE_READONLY)
- 		set_disk_ro(gdp, 1);
--	gdp->private_data = device;
--	gdp->queue = device->request_queue;
--	device->gdp = gdp;
--	set_capacity(device->gdp, 0);
--	add_disk(device->gdp);
-+	gdp->private_data = block;
-+	gdp->queue = block->request_queue;
-+	block->gdp = gdp;
-+	set_capacity(block->gdp, 0);
-+	add_disk(block->gdp);
- 	return 0;
+ 		spin_unlock_irqrestore(&fibptr->event_lock, flags);
+ 		BUG_ON(fibptr->done == 0);
+-			
++
+ 		if(unlikely(fibptr->flags & FIB_CONTEXT_FLAG_TIMED_OUT))
+ 			return -ETIMEDOUT;
+ 		return 0;
+@@ -537,15 +540,15 @@ int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size,
+ 		return 0;
  }
  
- /*
-  * Unregister and free gendisk structure for device.
+-/** 
++/**
+  *	aac_consumer_get	-	get the top of the queue
+  *	@dev: Adapter
+  *	@q: Queue
+  *	@entry: Return entry
+  *
+  *	Will return a pointer to the entry on the top of the queue requested that
+- * 	we are a consumer of, and return the address of the queue entry. It does
+- *	not change the state of the queue. 
++ *	we are a consumer of, and return the address of the queue entry. It does
++ *	not change the state of the queue.
   */
--void
--dasd_gendisk_free(struct dasd_device *device)
-+void dasd_gendisk_free(struct dasd_block *block)
- {
--	if (device->gdp) {
--		del_gendisk(device->gdp);
--		device->gdp->queue = NULL;
--		put_disk(device->gdp);
--		device->gdp = NULL;
-+	if (block->gdp) {
-+		del_gendisk(block->gdp);
-+		block->gdp->queue = NULL;
-+		put_disk(block->gdp);
-+		block->gdp = NULL;
+ 
+ int aac_consumer_get(struct aac_dev * dev, struct aac_queue * q, struct aac_entry **entry)
+@@ -560,10 +563,10 @@ int aac_consumer_get(struct aac_dev * dev, struct aac_queue * q, struct aac_entr
+ 		 *	the end of the queue, else we just use the entry
+ 		 *	pointed to by the header index
+ 		 */
+-		if (le32_to_cpu(*q->headers.consumer) >= q->entries) 
+-			index = 0;		
++		if (le32_to_cpu(*q->headers.consumer) >= q->entries)
++			index = 0;
+ 		else
+-		        index = le32_to_cpu(*q->headers.consumer);
++			index = le32_to_cpu(*q->headers.consumer);
+ 		*entry = q->base + index;
+ 		status = 1;
  	}
- }
+@@ -587,12 +590,12 @@ void aac_consumer_free(struct aac_dev * dev, struct aac_queue *q, u32 qid)
  
- /*
-  * Trigger a partition detection.
-  */
--int
--dasd_scan_partitions(struct dasd_device * device)
-+int dasd_scan_partitions(struct dasd_block *block)
- {
- 	struct block_device *bdev;
+ 	if ((le32_to_cpu(*q->headers.producer)+1) == le32_to_cpu(*q->headers.consumer))
+ 		wasfull = 1;
+-        
++
+ 	if (le32_to_cpu(*q->headers.consumer) >= q->entries)
+ 		*q->headers.consumer = cpu_to_le32(1);
+ 	else
+ 		*q->headers.consumer = cpu_to_le32(le32_to_cpu(*q->headers.consumer)+1);
+-        
++
+ 	if (wasfull) {
+ 		switch (qid) {
  
--	bdev = bdget_disk(device->gdp, 0);
-+	bdev = bdget_disk(block->gdp, 0);
- 	if (!bdev || blkdev_get(bdev, FMODE_READ, 1) < 0)
- 		return -ENODEV;
+@@ -608,7 +611,7 @@ void aac_consumer_free(struct aac_dev * dev, struct aac_queue *q, u32 qid)
+ 		}
+ 		aac_adapter_notify(dev, notify);
+ 	}
+-}        
++}
+ 
+ /**
+  *	aac_fib_adapter_complete	-	complete adapter issued fib
+@@ -630,32 +633,32 @@ int aac_fib_adapter_complete(struct fib *fibptr, unsigned short size)
+ 	if (hw_fib->header.XferState == 0) {
+ 		if (dev->comm_interface == AAC_COMM_MESSAGE)
+ 			kfree (hw_fib);
+-        	return 0;
++		return 0;
+ 	}
  	/*
-@@ -117,7 +116,7 @@ dasd_scan_partitions(struct dasd_device * device)
- 	 * is why the assignment to device->bdev is done AFTER
- 	 * the BLKRRPART ioctl.
+ 	 *	If we plan to do anything check the structure type first.
+-	 */ 
+-	if ( hw_fib->header.StructType != FIB_MAGIC ) {
++	 */
++	if (hw_fib->header.StructType != FIB_MAGIC) {
+ 		if (dev->comm_interface == AAC_COMM_MESSAGE)
+ 			kfree (hw_fib);
+-        	return -EINVAL;
++		return -EINVAL;
+ 	}
+ 	/*
+ 	 *	This block handles the case where the adapter had sent us a
+ 	 *	command and we have finished processing the command. We
+-	 *	call completeFib when we are done processing the command 
+-	 *	and want to send a response back to the adapter. This will 
++	 *	call completeFib when we are done processing the command
++	 *	and want to send a response back to the adapter. This will
+ 	 *	send the completed cdb to the adapter.
  	 */
--	device->bdev = bdev;
-+	block->bdev = bdev;
+ 	if (hw_fib->header.XferState & cpu_to_le32(SentFromAdapter)) {
+ 		if (dev->comm_interface == AAC_COMM_MESSAGE) {
+ 			kfree (hw_fib);
+ 		} else {
+-	       		u32 index;
+-		        hw_fib->header.XferState |= cpu_to_le32(HostProcessed);
++			u32 index;
++			hw_fib->header.XferState |= cpu_to_le32(HostProcessed);
+ 			if (size) {
+ 				size += sizeof(struct aac_fibhdr);
+-				if (size > le16_to_cpu(hw_fib->header.SenderSize)) 
++				if (size > le16_to_cpu(hw_fib->header.SenderSize))
+ 					return -EMSGSIZE;
+ 				hw_fib->header.Size = cpu_to_le16(size);
+ 			}
+@@ -667,12 +670,11 @@ int aac_fib_adapter_complete(struct fib *fibptr, unsigned short size)
+ 			if (!(nointr & (int)aac_config.irq_mod))
+ 				aac_adapter_notify(dev, AdapNormRespQueue);
+ 		}
++	} else {
++		printk(KERN_WARNING "aac_fib_adapter_complete: "
++			"Unknown xferstate detected.\n");
++		BUG();
+ 	}
+-	else 
+-	{
+-        	printk(KERN_WARNING "aac_fib_adapter_complete: Unknown xferstate detected.\n");
+-        	BUG();
+-	}   
  	return 0;
  }
  
-@@ -125,8 +124,7 @@ dasd_scan_partitions(struct dasd_device * device)
-  * Remove all inodes in the system for a device, delete the
-  * partitions and make device unusable by setting its size to zero.
+@@ -682,7 +684,7 @@ int aac_fib_adapter_complete(struct fib *fibptr, unsigned short size)
+  *
+  *	Will do all necessary work to complete a FIB.
   */
--void
--dasd_destroy_partitions(struct dasd_device * device)
-+void dasd_destroy_partitions(struct dasd_block *block)
+- 
++
+ int aac_fib_complete(struct fib *fibptr)
  {
- 	/* The two structs have 168/176 byte on 31/64 bit. */
- 	struct blkpg_partition bpart;
-@@ -137,8 +135,8 @@ dasd_destroy_partitions(struct dasd_device * device)
- 	 * Get the bdev pointer from the device structure and clear
- 	 * device->bdev to lower the offline open_count limit again.
+ 	struct hw_fib * hw_fib = fibptr->hw_fib_va;
+@@ -692,15 +694,15 @@ int aac_fib_complete(struct fib *fibptr)
  	 */
--	bdev = device->bdev;
--	device->bdev = NULL;
-+	bdev = block->bdev;
-+	block->bdev = NULL;
  
+ 	if (hw_fib->header.XferState == 0)
+-        	return 0;
++		return 0;
  	/*
- 	 * See fs/partition/check.c:delete_partition
-@@ -149,17 +147,16 @@ dasd_destroy_partitions(struct dasd_device * device)
- 	memset(&barg, 0, sizeof(struct blkpg_ioctl_arg));
- 	barg.data = (void __force __user *) &bpart;
- 	barg.op = BLKPG_DEL_PARTITION;
--	for (bpart.pno = device->gdp->minors - 1; bpart.pno > 0; bpart.pno--)
-+	for (bpart.pno = block->gdp->minors - 1; bpart.pno > 0; bpart.pno--)
- 		ioctl_by_bdev(bdev, BLKPG, (unsigned long) &barg);
- 
--	invalidate_partition(device->gdp, 0);
-+	invalidate_partition(block->gdp, 0);
- 	/* Matching blkdev_put to the blkdev_get in dasd_scan_partitions. */
- 	blkdev_put(bdev);
--	set_capacity(device->gdp, 0);
-+	set_capacity(block->gdp, 0);
- }
- 
--int
--dasd_gendisk_init(void)
-+int dasd_gendisk_init(void)
- {
- 	int rc;
+ 	 *	If we plan to do anything check the structure type first.
+-	 */ 
++	 */
  
-@@ -174,8 +171,7 @@ dasd_gendisk_init(void)
+ 	if (hw_fib->header.StructType != FIB_MAGIC)
+-	        return -EINVAL;
++		return -EINVAL;
+ 	/*
+-	 *	This block completes a cdb which orginated on the host and we 
++	 *	This block completes a cdb which orginated on the host and we
+ 	 *	just need to deallocate the cdb or reinit it. At this point the
+ 	 *	command is complete that we had sent to the adapter and this
+ 	 *	cdb could be reused.
+@@ -721,7 +723,7 @@ int aac_fib_complete(struct fib *fibptr)
+ 		fib_dealloc(fibptr);
+ 	} else {
+ 		BUG();
+-	}   
++	}
  	return 0;
  }
  
--void
--dasd_gendisk_exit(void)
-+void dasd_gendisk_exit(void)
- {
- 	unregister_blkdev(DASD_MAJOR, "dasd");
+@@ -741,7 +743,7 @@ void aac_printf(struct aac_dev *dev, u32 val)
+ 	{
+ 		int length = val & 0xffff;
+ 		int level = (val >> 16) & 0xffff;
+-		
++
+ 		/*
+ 		 *	The size of the printfbuf is set in port.c
+ 		 *	There is no variable or define for it
+@@ -755,7 +757,7 @@ void aac_printf(struct aac_dev *dev, u32 val)
+ 		else
+ 			printk(KERN_INFO "%s:%s", dev->name, cp);
+ 	}
+-	memset(cp, 0,  256);
++	memset(cp, 0, 256);
  }
-diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h
-index d427dae..44b2984 100644
---- a/drivers/s390/block/dasd_int.h
-+++ b/drivers/s390/block/dasd_int.h
-@@ -64,13 +64,7 @@
-  * SECTION: Type definitions
-  */
- struct dasd_device;
--
--typedef enum {
--	dasd_era_fatal = -1,	/* no chance to recover		     */
--	dasd_era_none = 0,	/* don't recover, everything alright */
--	dasd_era_msg = 1,	/* don't recover, just report...     */
--	dasd_era_recover = 2	/* recovery action recommended	     */
--} dasd_era_t;
-+struct dasd_block;
- 
- /* BIT DEFINITIONS FOR SENSE DATA */
- #define DASD_SENSE_BIT_0 0x80
-@@ -151,19 +145,22 @@ do { \
  
- struct dasd_ccw_req {
- 	unsigned int magic;		/* Eye catcher */
--        struct list_head list;		/* list_head for request queueing. */
-+	struct list_head devlist;	/* for dasd_device request queue */
-+	struct list_head blocklist;	/* for dasd_block request queue */
  
- 	/* Where to execute what... */
--	struct dasd_device *device;	/* device the request is for */
-+	struct dasd_block *block;	/* the originating block device */
-+	struct dasd_device *memdev;	/* the device used to allocate this */
-+	struct dasd_device *startdev;	/* device the request is started on */
- 	struct ccw1 *cpaddr;		/* address of channel program */
--	char status;	        	/* status of this request */
-+	char status;			/* status of this request */
- 	short retries;			/* A retry counter */
- 	unsigned long flags;        	/* flags of this request */
+@@ -773,20 +775,20 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
+ {
+ 	struct hw_fib * hw_fib = fibptr->hw_fib_va;
+ 	struct aac_aifcmd * aifcmd = (struct aac_aifcmd *)hw_fib->data;
+-	u32 container;
++	u32 channel, id, lun, container;
+ 	struct scsi_device *device;
+ 	enum {
+ 		NOTHING,
+ 		DELETE,
+ 		ADD,
+ 		CHANGE
+-	} device_config_needed;
++	} device_config_needed = NOTHING;
  
- 	/* ... and how */
- 	unsigned long starttime;	/* jiffies time of request start */
- 	int expires;			/* expiration period in jiffies */
--	char lpm;               	/* logical path mask */
-+	char lpm;			/* logical path mask */
- 	void *data;			/* pointer to data area */
+ 	/* Sniff for container changes */
  
- 	/* these are important for recovering erroneous requests          */
-@@ -178,20 +175,27 @@ struct dasd_ccw_req {
- 	unsigned long long endclk;	/* TOD-clock of request termination */
+ 	if (!dev || !dev->fsa_dev)
+ 		return;
+-	container = (u32)-1;
++	container = channel = id = lun = (u32)-1;
  
-         /* Callback that is called after reaching final status. */
--        void (*callback)(struct dasd_ccw_req *, void *data);
--        void *callback_data;
-+	void (*callback)(struct dasd_ccw_req *, void *data);
-+	void *callback_data;
- };
+ 	/*
+ 	 *	We have set this up to try and minimize the number of
+@@ -796,13 +798,13 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
+ 	 */
+ 	switch (le32_to_cpu(aifcmd->command)) {
+ 	case AifCmdDriverNotify:
+-		switch (le32_to_cpu(((u32 *)aifcmd->data)[0])) {
++		switch (le32_to_cpu(((__le32 *)aifcmd->data)[0])) {
+ 		/*
+ 		 *	Morph or Expand complete
+ 		 */
+ 		case AifDenMorphComplete:
+ 		case AifDenVolumeExtendComplete:
+-			container = le32_to_cpu(((u32 *)aifcmd->data)[1]);
++			container = le32_to_cpu(((__le32 *)aifcmd->data)[1]);
+ 			if (container >= dev->maximum_num_containers)
+ 				break;
  
- /*
-  * dasd_ccw_req -> status can be:
-  */
--#define DASD_CQR_FILLED   0x00	/* request is ready to be processed */
--#define DASD_CQR_QUEUED   0x01	/* request is queued to be processed */
--#define DASD_CQR_IN_IO    0x02	/* request is currently in IO */
--#define DASD_CQR_DONE     0x03	/* request is completed successfully */
--#define DASD_CQR_ERROR    0x04	/* request is completed with error */
--#define DASD_CQR_FAILED   0x05	/* request is finally failed */
--#define DASD_CQR_CLEAR    0x06	/* request is clear pending */
-+#define DASD_CQR_FILLED 	0x00	/* request is ready to be processed */
-+#define DASD_CQR_DONE		0x01	/* request is completed successfully */
-+#define DASD_CQR_NEED_ERP	0x02	/* request needs recovery action */
-+#define DASD_CQR_IN_ERP 	0x03	/* request is in recovery */
-+#define DASD_CQR_FAILED 	0x04	/* request is finally failed */
-+#define DASD_CQR_TERMINATED	0x05	/* request was stopped by driver */
-+
-+#define DASD_CQR_QUEUED 	0x80	/* request is queued to be processed */
-+#define DASD_CQR_IN_IO		0x81	/* request is currently in IO */
-+#define DASD_CQR_ERROR		0x82	/* request is completed with error */
-+#define DASD_CQR_CLEAR_PENDING	0x83	/* request is clear pending */
-+#define DASD_CQR_CLEARED	0x84	/* request was cleared */
-+#define DASD_CQR_SUCCESS	0x85	/* request was successfull */
-+
+@@ -814,9 +816,9 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
+ 			 */
  
- /* per dasd_ccw_req flags */
- #define DASD_CQR_FLAGS_USE_ERP   0	/* use ERP for this request */
-@@ -214,52 +218,71 @@ struct dasd_discipline {
+ 			if ((dev != NULL) && (dev->scsi_host_ptr != NULL)) {
+-				device = scsi_device_lookup(dev->scsi_host_ptr, 
+-					CONTAINER_TO_CHANNEL(container), 
+-					CONTAINER_TO_ID(container), 
++				device = scsi_device_lookup(dev->scsi_host_ptr,
++					CONTAINER_TO_CHANNEL(container),
++					CONTAINER_TO_ID(container),
+ 					CONTAINER_TO_LUN(container));
+ 				if (device) {
+ 					dev->fsa_dev[container].config_needed = CHANGE;
+@@ -835,25 +837,29 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
+ 			if (container >= dev->maximum_num_containers)
+ 				break;
+ 			if ((dev->fsa_dev[container].config_waiting_on ==
+-			    le32_to_cpu(*(u32 *)aifcmd->data)) &&
++			    le32_to_cpu(*(__le32 *)aifcmd->data)) &&
+ 			 time_before(jiffies, dev->fsa_dev[container].config_waiting_stamp + AIF_SNIFF_TIMEOUT))
+ 				dev->fsa_dev[container].config_waiting_on = 0;
+ 		} else for (container = 0;
+ 		    container < dev->maximum_num_containers; ++container) {
+ 			if ((dev->fsa_dev[container].config_waiting_on ==
+-			    le32_to_cpu(*(u32 *)aifcmd->data)) &&
++			    le32_to_cpu(*(__le32 *)aifcmd->data)) &&
+ 			 time_before(jiffies, dev->fsa_dev[container].config_waiting_stamp + AIF_SNIFF_TIMEOUT))
+ 				dev->fsa_dev[container].config_waiting_on = 0;
+ 		}
+ 		break;
  
- 	struct list_head list;	/* used for list of disciplines */
+ 	case AifCmdEventNotify:
+-		switch (le32_to_cpu(((u32 *)aifcmd->data)[0])) {
++		switch (le32_to_cpu(((__le32 *)aifcmd->data)[0])) {
++		case AifEnBatteryEvent:
++			dev->cache_protected =
++				(((__le32 *)aifcmd->data)[1] == cpu_to_le32(3));
++			break;
+ 		/*
+ 		 *	Add an Array.
+ 		 */
+ 		case AifEnAddContainer:
+-			container = le32_to_cpu(((u32 *)aifcmd->data)[1]);
++			container = le32_to_cpu(((__le32 *)aifcmd->data)[1]);
+ 			if (container >= dev->maximum_num_containers)
+ 				break;
+ 			dev->fsa_dev[container].config_needed = ADD;
+@@ -866,7 +872,7 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
+ 		 *	Delete an Array.
+ 		 */
+ 		case AifEnDeleteContainer:
+-			container = le32_to_cpu(((u32 *)aifcmd->data)[1]);
++			container = le32_to_cpu(((__le32 *)aifcmd->data)[1]);
+ 			if (container >= dev->maximum_num_containers)
+ 				break;
+ 			dev->fsa_dev[container].config_needed = DELETE;
+@@ -880,7 +886,7 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
+ 		 * waiting on something else, setup to wait on a Config Change.
+ 		 */
+ 		case AifEnContainerChange:
+-			container = le32_to_cpu(((u32 *)aifcmd->data)[1]);
++			container = le32_to_cpu(((__le32 *)aifcmd->data)[1]);
+ 			if (container >= dev->maximum_num_containers)
+ 				break;
+ 			if (dev->fsa_dev[container].config_waiting_on &&
+@@ -895,6 +901,60 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
+ 		case AifEnConfigChange:
+ 			break;
  
--        /*
--         * Device recognition functions. check_device is used to verify
--         * the sense data and the information returned by read device
--         * characteristics. It returns 0 if the discipline can be used
--         * for the device in question.
--         * do_analysis is used in the step from device state "basic" to
--         * state "accept". It returns 0 if the device can be made ready,
--         * it returns -EMEDIUMTYPE if the device can't be made ready or
--         * -EAGAIN if do_analysis started a ccw that needs to complete
--         * before the analysis may be repeated.
--         */
--        int (*check_device)(struct dasd_device *);
--	int (*do_analysis) (struct dasd_device *);
--
--        /*
--         * Device operation functions. build_cp creates a ccw chain for
--         * a block device request, start_io starts the request and
--         * term_IO cancels it (e.g. in case of a timeout). format_device
--         * returns a ccw chain to be used to format the device.
--         */
-+	/*
-+	 * Device recognition functions. check_device is used to verify
-+	 * the sense data and the information returned by read device
-+	 * characteristics. It returns 0 if the discipline can be used
-+	 * for the device in question. uncheck_device is called during
-+	 * device shutdown to deregister a device from its discipline.
-+	 */
-+	int (*check_device) (struct dasd_device *);
-+	void (*uncheck_device) (struct dasd_device *);
-+
-+	/*
-+	 * do_analysis is used in the step from device state "basic" to
-+	 * state "accept". It returns 0 if the device can be made ready,
-+	 * it returns -EMEDIUMTYPE if the device can't be made ready or
-+	 * -EAGAIN if do_analysis started a ccw that needs to complete
-+	 * before the analysis may be repeated.
-+	 */
-+	int (*do_analysis) (struct dasd_block *);
-+
-+	/*
-+	 * Last things to do when a device is set online, and first things
-+	 * when it is set offline.
-+	 */
-+	int (*ready_to_online) (struct dasd_device *);
-+	int (*online_to_ready) (struct dasd_device *);
-+
-+	/*
-+	 * Device operation functions. build_cp creates a ccw chain for
-+	 * a block device request, start_io starts the request and
-+	 * term_IO cancels it (e.g. in case of a timeout). format_device
-+	 * returns a ccw chain to be used to format the device.
-+	 * handle_terminated_request allows to examine a cqr and prepare
-+	 * it for retry.
-+	 */
- 	struct dasd_ccw_req *(*build_cp) (struct dasd_device *,
-+					  struct dasd_block *,
- 					  struct request *);
- 	int (*start_IO) (struct dasd_ccw_req *);
- 	int (*term_IO) (struct dasd_ccw_req *);
-+	void (*handle_terminated_request) (struct dasd_ccw_req *);
- 	struct dasd_ccw_req *(*format_device) (struct dasd_device *,
- 					       struct format_data_t *);
- 	int (*free_cp) (struct dasd_ccw_req *, struct request *);
--        /*
--         * Error recovery functions. examine_error() returns a value that
--         * indicates what to do for an error condition. If examine_error()
++		case AifEnAddJBOD:
++		case AifEnDeleteJBOD:
++			container = le32_to_cpu(((__le32 *)aifcmd->data)[1]);
++			if ((container >> 28))
++				break;
++			channel = (container >> 24) & 0xF;
++			if (channel >= dev->maximum_num_channels)
++				break;
++			id = container & 0xFFFF;
++			if (id >= dev->maximum_num_physicals)
++				break;
++			lun = (container >> 16) & 0xFF;
++			channel = aac_phys_to_logical(channel);
++			device_config_needed =
++			  (((__le32 *)aifcmd->data)[0] ==
++			    cpu_to_le32(AifEnAddJBOD)) ? ADD : DELETE;
++			break;
 +
-+	/*
-+	 * Error recovery functions. examine_error() returns a value that
-+	 * indicates what to do for an error condition. If examine_error()
- 	 * returns 'dasd_era_recover' erp_action() is called to create a
--         * special error recovery ccw. erp_postaction() is called after
--         * an error recovery ccw has finished its execution. dump_sense
--         * is called for every error condition to print the sense data
--         * to the console.
--         */
--	dasd_era_t(*examine_error) (struct dasd_ccw_req *, struct irb *);
-+	 * special error recovery ccw. erp_postaction() is called after
-+	 * an error recovery ccw has finished its execution. dump_sense
-+	 * is called for every error condition to print the sense data
-+	 * to the console.
-+	 */
- 	dasd_erp_fn_t(*erp_action) (struct dasd_ccw_req *);
- 	dasd_erp_fn_t(*erp_postaction) (struct dasd_ccw_req *);
- 	void (*dump_sense) (struct dasd_device *, struct dasd_ccw_req *,
- 			    struct irb *);
++		case AifEnEnclosureManagement:
++			/*
++			 * If in JBOD mode, automatic exposure of new
++			 * physical target to be suppressed until configured.
++			 */
++			if (dev->jbod)
++				break;
++			switch (le32_to_cpu(((__le32 *)aifcmd->data)[3])) {
++			case EM_DRIVE_INSERTION:
++			case EM_DRIVE_REMOVAL:
++				container = le32_to_cpu(
++					((__le32 *)aifcmd->data)[2]);
++				if ((container >> 28))
++					break;
++				channel = (container >> 24) & 0xF;
++				if (channel >= dev->maximum_num_channels)
++					break;
++				id = container & 0xFFFF;
++				lun = (container >> 16) & 0xFF;
++				if (id >= dev->maximum_num_physicals) {
++					/* legacy dev_t ? */
++					if ((0x2000 <= id) || lun || channel ||
++					  ((channel = (id >> 7) & 0x3F) >=
++					  dev->maximum_num_channels))
++						break;
++					lun = (id >> 4) & 7;
++					id &= 0xF;
++				}
++				channel = aac_phys_to_logical(channel);
++				device_config_needed =
++				  (((__le32 *)aifcmd->data)[3]
++				    == cpu_to_le32(EM_DRIVE_INSERTION)) ?
++				  ADD : DELETE;
++				break;
++			}
++			break;
+ 		}
  
-+	void (*handle_unsolicited_interrupt) (struct dasd_device *,
-+					      struct irb *);
-+
-         /* i/o control functions. */
--	int (*fill_geometry) (struct dasd_device *, struct hd_geometry *);
-+	int (*fill_geometry) (struct dasd_block *, struct hd_geometry *);
- 	int (*fill_info) (struct dasd_device *, struct dasd_information2_t *);
--	int (*ioctl) (struct dasd_device *, unsigned int, void __user *);
-+	int (*ioctl) (struct dasd_block *, unsigned int, void __user *);
- };
+ 		/*
+@@ -905,13 +965,13 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
+ 			if (container >= dev->maximum_num_containers)
+ 				break;
+ 			if ((dev->fsa_dev[container].config_waiting_on ==
+-			    le32_to_cpu(*(u32 *)aifcmd->data)) &&
++			    le32_to_cpu(*(__le32 *)aifcmd->data)) &&
+ 			 time_before(jiffies, dev->fsa_dev[container].config_waiting_stamp + AIF_SNIFF_TIMEOUT))
+ 				dev->fsa_dev[container].config_waiting_on = 0;
+ 		} else for (container = 0;
+ 		    container < dev->maximum_num_containers; ++container) {
+ 			if ((dev->fsa_dev[container].config_waiting_on ==
+-			    le32_to_cpu(*(u32 *)aifcmd->data)) &&
++			    le32_to_cpu(*(__le32 *)aifcmd->data)) &&
+ 			 time_before(jiffies, dev->fsa_dev[container].config_waiting_stamp + AIF_SNIFF_TIMEOUT))
+ 				dev->fsa_dev[container].config_waiting_on = 0;
+ 		}
+@@ -926,9 +986,9 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
+ 		 * wait for a container change.
+ 		 */
  
- extern struct dasd_discipline *dasd_diag_discipline_pointer;
-@@ -267,12 +290,18 @@ extern struct dasd_discipline *dasd_diag_discipline_pointer;
- /*
-  * Unique identifier for dasd device.
-  */
-+#define UA_NOT_CONFIGURED  0x00
-+#define UA_BASE_DEVICE	   0x01
-+#define UA_BASE_PAV_ALIAS  0x02
-+#define UA_HYPER_PAV_ALIAS 0x03
-+
- struct dasd_uid {
--	__u8 alias;
-+	__u8 type;
- 	char vendor[4];
- 	char serial[15];
- 	__u16 ssid;
--	__u8 unit_addr;
-+	__u8 real_unit_addr;
-+	__u8 base_unit_addr;
- };
+-		if ((((u32 *)aifcmd->data)[1] == cpu_to_le32(AifJobCtrZero))
+-		 && ((((u32 *)aifcmd->data)[6] == ((u32 *)aifcmd->data)[5])
+-		  || (((u32 *)aifcmd->data)[4] == cpu_to_le32(AifJobStsSuccess)))) {
++		if (((__le32 *)aifcmd->data)[1] == cpu_to_le32(AifJobCtrZero) &&
++		    (((__le32 *)aifcmd->data)[6] == ((__le32 *)aifcmd->data)[5] ||
++		     ((__le32 *)aifcmd->data)[4] == cpu_to_le32(AifJobStsSuccess))) {
+ 			for (container = 0;
+ 			    container < dev->maximum_num_containers;
+ 			    ++container) {
+@@ -943,9 +1003,9 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
+ 					jiffies;
+ 			}
+ 		}
+-		if ((((u32 *)aifcmd->data)[1] == cpu_to_le32(AifJobCtrZero))
+-		 && (((u32 *)aifcmd->data)[6] == 0)
+-		 && (((u32 *)aifcmd->data)[4] == cpu_to_le32(AifJobStsRunning))) {
++		if (((__le32 *)aifcmd->data)[1] == cpu_to_le32(AifJobCtrZero) &&
++		    ((__le32 *)aifcmd->data)[6] == 0 &&
++		    ((__le32 *)aifcmd->data)[4] == cpu_to_le32(AifJobStsRunning)) {
+ 			for (container = 0;
+ 			    container < dev->maximum_num_containers;
+ 			    ++container) {
+@@ -963,7 +1023,7 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
+ 		break;
+ 	}
+ 
+-	device_config_needed = NOTHING;
++	if (device_config_needed == NOTHING)
+ 	for (container = 0; container < dev->maximum_num_containers;
+ 	    ++container) {
+ 		if ((dev->fsa_dev[container].config_waiting_on == 0) &&
+@@ -972,6 +1032,9 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
+ 			device_config_needed =
+ 				dev->fsa_dev[container].config_needed;
+ 			dev->fsa_dev[container].config_needed = NOTHING;
++			channel = CONTAINER_TO_CHANNEL(container);
++			id = CONTAINER_TO_ID(container);
++			lun = CONTAINER_TO_LUN(container);
+ 			break;
+ 		}
+ 	}
+@@ -995,34 +1058,56 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
+ 	/*
+ 	 * force reload of disk info via aac_probe_container
+ 	 */
+-	if ((device_config_needed == CHANGE)
+-	 && (dev->fsa_dev[container].valid == 1))
+-		dev->fsa_dev[container].valid = 2;
+-	if ((device_config_needed == CHANGE) ||
+-			(device_config_needed == ADD))
++	if ((channel == CONTAINER_CHANNEL) &&
++	  (device_config_needed != NOTHING)) {
++		if (dev->fsa_dev[container].valid == 1)
++			dev->fsa_dev[container].valid = 2;
+ 		aac_probe_container(dev, container);
+-	device = scsi_device_lookup(dev->scsi_host_ptr, 
+-		CONTAINER_TO_CHANNEL(container), 
+-		CONTAINER_TO_ID(container), 
+-		CONTAINER_TO_LUN(container));
++	}
++	device = scsi_device_lookup(dev->scsi_host_ptr, channel, id, lun);
+ 	if (device) {
+ 		switch (device_config_needed) {
+ 		case DELETE:
++			if (scsi_device_online(device)) {
++				scsi_device_set_state(device, SDEV_OFFLINE);
++				sdev_printk(KERN_INFO, device,
++					"Device offlined - %s\n",
++					(channel == CONTAINER_CHANNEL) ?
++						"array deleted" :
++						"enclosure services event");
++			}
++			break;
++		case ADD:
++			if (!scsi_device_online(device)) {
++				sdev_printk(KERN_INFO, device,
++					"Device online - %s\n",
++					(channel == CONTAINER_CHANNEL) ?
++						"array created" :
++						"enclosure services event");
++				scsi_device_set_state(device, SDEV_RUNNING);
++			}
++			/* FALLTHRU */
+ 		case CHANGE:
++			if ((channel == CONTAINER_CHANNEL)
++			 && (!dev->fsa_dev[container].valid)) {
++				if (!scsi_device_online(device))
++					break;
++				scsi_device_set_state(device, SDEV_OFFLINE);
++				sdev_printk(KERN_INFO, device,
++					"Device offlined - %s\n",
++					"array failed");
++				break;
++			}
+ 			scsi_rescan_device(&device->sdev_gendev);
  
- /*
-@@ -293,14 +322,9 @@ struct dasd_uid {
+ 		default:
+ 			break;
+ 		}
+ 		scsi_device_put(device);
++		device_config_needed = NOTHING;
+ 	}
+-	if (device_config_needed == ADD) {
+-		scsi_add_device(dev->scsi_host_ptr,
+-		  CONTAINER_TO_CHANNEL(container),
+-		  CONTAINER_TO_ID(container),
+-		  CONTAINER_TO_LUN(container));
+-	}
+-
++	if (device_config_needed == ADD)
++		scsi_add_device(dev->scsi_host_ptr, channel, id, lun);
+ }
  
- struct dasd_device {
- 	/* Block device stuff. */
--	struct gendisk *gdp;
--	struct request_queue *request_queue;
--	spinlock_t request_queue_lock;
--	struct block_device *bdev;
-+	struct dasd_block *block;
-+
-         unsigned int devindex;
--	unsigned long blocks;	   /* size of volume in blocks */
--	unsigned int bp_block;	   /* bytes per block */
--	unsigned int s2b_shift;	   /* log2 (bp_block/512) */
- 	unsigned long flags;	   /* per device flags */
- 	unsigned short features;   /* copy of devmap-features (read-only!) */
+ static int _aac_reset_adapter(struct aac_dev *aac, int forced)
+@@ -1099,7 +1184,8 @@ static int _aac_reset_adapter(struct aac_dev *aac, int forced)
+ 	free_irq(aac->pdev->irq, aac);
+ 	kfree(aac->fsa_dev);
+ 	aac->fsa_dev = NULL;
+-	if (aac_get_driver_ident(index)->quirks & AAC_QUIRK_31BIT) {
++	quirks = aac_get_driver_ident(index)->quirks;
++	if (quirks & AAC_QUIRK_31BIT) {
+ 		if (((retval = pci_set_dma_mask(aac->pdev, DMA_31BIT_MASK))) ||
+ 		  ((retval = pci_set_consistent_dma_mask(aac->pdev, DMA_31BIT_MASK))))
+ 			goto out;
+@@ -1110,7 +1196,7 @@ static int _aac_reset_adapter(struct aac_dev *aac, int forced)
+ 	}
+ 	if ((retval = (*(aac_get_driver_ident(index)->init))(aac)))
+ 		goto out;
+-	if (aac_get_driver_ident(index)->quirks & AAC_QUIRK_31BIT)
++	if (quirks & AAC_QUIRK_31BIT)
+ 		if ((retval = pci_set_dma_mask(aac->pdev, DMA_32BIT_MASK)))
+ 			goto out;
+ 	if (jafo) {
+@@ -1121,15 +1207,14 @@ static int _aac_reset_adapter(struct aac_dev *aac, int forced)
+ 		}
+ 	}
+ 	(void)aac_get_adapter_info(aac);
+-	quirks = aac_get_driver_ident(index)->quirks;
+ 	if ((quirks & AAC_QUIRK_34SG) && (host->sg_tablesize > 34)) {
+- 		host->sg_tablesize = 34;
+- 		host->max_sectors = (host->sg_tablesize * 8) + 112;
+- 	}
+- 	if ((quirks & AAC_QUIRK_17SG) && (host->sg_tablesize > 17)) {
+- 		host->sg_tablesize = 17;
+- 		host->max_sectors = (host->sg_tablesize * 8) + 112;
+- 	}
++		host->sg_tablesize = 34;
++		host->max_sectors = (host->sg_tablesize * 8) + 112;
++	}
++	if ((quirks & AAC_QUIRK_17SG) && (host->sg_tablesize > 17)) {
++		host->sg_tablesize = 17;
++		host->max_sectors = (host->sg_tablesize * 8) + 112;
++	}
+ 	aac_get_config_status(aac, 1);
+ 	aac_get_containers(aac);
+ 	/*
+@@ -1217,12 +1302,13 @@ int aac_reset_adapter(struct aac_dev * aac, int forced)
+ 	}
  
-@@ -316,9 +340,8 @@ struct dasd_device {
- 	int state, target;
- 	int stopped;		/* device (ccw_device_start) was stopped */
+ 	/* Quiesce build, flush cache, write through mode */
+-	aac_send_shutdown(aac);
++	if (forced < 2)
++		aac_send_shutdown(aac);
+ 	spin_lock_irqsave(host->host_lock, flagv);
+-	retval = _aac_reset_adapter(aac, forced);
++	retval = _aac_reset_adapter(aac, forced ? forced : ((aac_check_reset != 0) && (aac_check_reset != 1)));
+ 	spin_unlock_irqrestore(host->host_lock, flagv);
  
--	/* Open and reference count. */
-+	/* reference count. */
-         atomic_t ref_count;
--	atomic_t open_count;
+-	if (retval == -ENODEV) {
++	if ((forced < 2) && (retval == -ENODEV)) {
+ 		/* Unwind aac_send_shutdown() IOP_RESET unsupported/disabled */
+ 		struct fib * fibctx = aac_fib_alloc(aac);
+ 		if (fibctx) {
+@@ -1338,11 +1424,11 @@ int aac_check_health(struct aac_dev * aac)
+ 			fib->data = hw_fib->data;
+ 			aif = (struct aac_aifcmd *)hw_fib->data;
+ 			aif->command = cpu_to_le32(AifCmdEventNotify);
+-		 	aif->seqnum = cpu_to_le32(0xFFFFFFFF);
+-			aif->data[0] = AifEnExpEvent;
+-			aif->data[1] = AifExeFirmwarePanic;
+-			aif->data[2] = AifHighPriority;
+-			aif->data[3] = BlinkLED;
++			aif->seqnum = cpu_to_le32(0xFFFFFFFF);
++			((__le32 *)aif->data)[0] = cpu_to_le32(AifEnExpEvent);
++			((__le32 *)aif->data)[1] = cpu_to_le32(AifExeFirmwarePanic);
++			((__le32 *)aif->data)[2] = cpu_to_le32(AifHighPriority);
++			((__le32 *)aif->data)[3] = cpu_to_le32(BlinkLED);
  
- 	/* ccw queue and memory for static ccw/erp buffers. */
- 	struct list_head ccw_queue;
-@@ -337,20 +360,45 @@ struct dasd_device {
+ 			/*
+ 			 * Put the FIB onto the
+@@ -1372,14 +1458,14 @@ int aac_check_health(struct aac_dev * aac)
  
- 	struct ccw_device *cdev;
+ 	printk(KERN_ERR "%s: Host adapter BLINK LED 0x%x\n", aac->name, BlinkLED);
  
-+	/* hook for alias management */
-+	struct list_head alias_list;
-+};
-+
-+struct dasd_block {
-+	/* Block device stuff. */
-+	struct gendisk *gdp;
-+	struct request_queue *request_queue;
-+	spinlock_t request_queue_lock;
-+	struct block_device *bdev;
-+	atomic_t open_count;
-+
-+	unsigned long blocks;	   /* size of volume in blocks */
-+	unsigned int bp_block;	   /* bytes per block */
-+	unsigned int s2b_shift;	   /* log2 (bp_block/512) */
-+
-+	struct dasd_device *base;
-+	struct list_head ccw_queue;
-+	spinlock_t queue_lock;
-+
-+	atomic_t tasklet_scheduled;
-+	struct tasklet_struct tasklet;
-+	struct timer_list timer;
+-	if (!aac_check_reset ||
++	if (!aac_check_reset || ((aac_check_reset != 1) &&
+ 		(aac->supplement_adapter_info.SupportedOptions2 &
+-			le32_to_cpu(AAC_OPTION_IGNORE_RESET)))
++			AAC_OPTION_IGNORE_RESET)))
+ 		goto out;
+ 	host = aac->scsi_host_ptr;
+ 	if (aac->thread->pid != current->pid)
+ 		spin_lock_irqsave(host->host_lock, flagv);
+-	BlinkLED = _aac_reset_adapter(aac, 0);
++	BlinkLED = _aac_reset_adapter(aac, aac_check_reset != 1);
+ 	if (aac->thread->pid != current->pid)
+ 		spin_unlock_irqrestore(host->host_lock, flagv);
+ 	return BlinkLED;
+@@ -1399,7 +1485,7 @@ out:
+  *	until the queue is empty. When the queue is empty it will wait for
+  *	more FIBs.
+  */
+- 
 +
- #ifdef CONFIG_DASD_PROFILE
- 	struct dasd_profile_info_t profile;
- #endif
- };
+ int aac_command_thread(void *data)
+ {
+ 	struct aac_dev *dev = data;
+@@ -1425,30 +1511,29 @@ int aac_command_thread(void *data)
+ 	add_wait_queue(&dev->queues->queue[HostNormCmdQueue].cmdready, &wait);
+ 	set_current_state(TASK_INTERRUPTIBLE);
+ 	dprintk ((KERN_INFO "aac_command_thread start\n"));
+-	while(1) 
+-	{
++	while (1) {
+ 		spin_lock_irqsave(dev->queues->queue[HostNormCmdQueue].lock, flags);
+ 		while(!list_empty(&(dev->queues->queue[HostNormCmdQueue].cmdq))) {
+ 			struct list_head *entry;
+ 			struct aac_aifcmd * aifcmd;
  
+ 			set_current_state(TASK_RUNNING);
+-	
 +
+ 			entry = dev->queues->queue[HostNormCmdQueue].cmdq.next;
+ 			list_del(entry);
+-		
 +
- /* reasons why device (ccw_device_start) was stopped */
- #define DASD_STOPPED_NOT_ACC 1         /* not accessible */
- #define DASD_STOPPED_QUIESCE 2         /* Quiesced */
- #define DASD_STOPPED_PENDING 4         /* long busy */
- #define DASD_STOPPED_DC_WAIT 8         /* disconnected, wait */
--#define DASD_STOPPED_DC_EIO  16        /* disconnected, return -EIO */
-+#define DASD_STOPPED_SU      16        /* summary unit check handling */
- 
- /* per device flags */
--#define DASD_FLAG_DSC_ERROR	2	/* return -EIO when disconnected */
- #define DASD_FLAG_OFFLINE	3	/* device is in offline processing */
- #define DASD_FLAG_EER_SNSS	4	/* A SNSS is required */
- #define DASD_FLAG_EER_IN_USE	5	/* A SNSS request is running */
-@@ -489,6 +537,9 @@ dasd_kmalloc_set_cda(struct ccw1 *ccw, void *cda, struct dasd_device *device)
- struct dasd_device *dasd_alloc_device(void);
- void dasd_free_device(struct dasd_device *);
- 
-+struct dasd_block *dasd_alloc_block(void);
-+void dasd_free_block(struct dasd_block *);
+ 			spin_unlock_irqrestore(dev->queues->queue[HostNormCmdQueue].lock, flags);
+ 			fib = list_entry(entry, struct fib, fiblink);
+ 			/*
+-			 *	We will process the FIB here or pass it to a 
+-			 *	worker thread that is TBD. We Really can't 
++			 *	We will process the FIB here or pass it to a
++			 *	worker thread that is TBD. We Really can't
+ 			 *	do anything at this point since we don't have
+ 			 *	anything defined for this thread to do.
+ 			 */
+ 			hw_fib = fib->hw_fib_va;
+ 			memset(fib, 0, sizeof(struct fib));
+ 			fib->type = FSAFS_NTC_FIB_CONTEXT;
+-			fib->size = sizeof( struct fib );
++			fib->size = sizeof(struct fib);
+ 			fib->hw_fib_va = hw_fib;
+ 			fib->data = hw_fib->data;
+ 			fib->dev = dev;
+@@ -1462,20 +1547,19 @@ int aac_command_thread(void *data)
+ 				*(__le32 *)hw_fib->data = cpu_to_le32(ST_OK);
+ 				aac_fib_adapter_complete(fib, (u16)sizeof(u32));
+ 			} else {
+-				struct list_head *entry;
+ 				/* The u32 here is important and intended. We are using
+ 				   32bit wrapping time to fit the adapter field */
+-				   
 +
- void dasd_enable_device(struct dasd_device *);
- void dasd_set_target_state(struct dasd_device *, int);
- void dasd_kick_device(struct dasd_device *);
-@@ -497,18 +548,23 @@ void dasd_add_request_head(struct dasd_ccw_req *);
- void dasd_add_request_tail(struct dasd_ccw_req *);
- int  dasd_start_IO(struct dasd_ccw_req *);
- int  dasd_term_IO(struct dasd_ccw_req *);
--void dasd_schedule_bh(struct dasd_device *);
-+void dasd_schedule_device_bh(struct dasd_device *);
-+void dasd_schedule_block_bh(struct dasd_block *);
- int  dasd_sleep_on(struct dasd_ccw_req *);
- int  dasd_sleep_on_immediatly(struct dasd_ccw_req *);
- int  dasd_sleep_on_interruptible(struct dasd_ccw_req *);
--void dasd_set_timer(struct dasd_device *, int);
--void dasd_clear_timer(struct dasd_device *);
-+void dasd_device_set_timer(struct dasd_device *, int);
-+void dasd_device_clear_timer(struct dasd_device *);
-+void dasd_block_set_timer(struct dasd_block *, int);
-+void dasd_block_clear_timer(struct dasd_block *);
- int  dasd_cancel_req(struct dasd_ccw_req *);
-+int dasd_flush_device_queue(struct dasd_device *);
- int dasd_generic_probe (struct ccw_device *, struct dasd_discipline *);
- void dasd_generic_remove (struct ccw_device *cdev);
- int dasd_generic_set_online(struct ccw_device *, struct dasd_discipline *);
- int dasd_generic_set_offline (struct ccw_device *cdev);
- int dasd_generic_notify(struct ccw_device *, int);
-+void dasd_generic_handle_state_change(struct dasd_device *);
+ 				u32 time_now, time_last;
+ 				unsigned long flagv;
+ 				unsigned num;
+ 				struct hw_fib ** hw_fib_pool, ** hw_fib_p;
+ 				struct fib ** fib_pool, ** fib_p;
+-			
++
+ 				/* Sniff events */
+-				if ((aifcmd->command == 
++				if ((aifcmd->command ==
+ 				     cpu_to_le32(AifCmdEventNotify)) ||
+-				    (aifcmd->command == 
++				    (aifcmd->command ==
+ 				     cpu_to_le32(AifCmdJobProgress))) {
+ 					aac_handle_aif(dev, fib);
+ 				}
+@@ -1527,7 +1611,7 @@ int aac_command_thread(void *data)
+ 				spin_lock_irqsave(&dev->fib_lock, flagv);
+ 				entry = dev->fib_list.next;
+ 				/*
+-				 * For each Context that is on the 
++				 * For each Context that is on the
+ 				 * fibctxList, make a copy of the
+ 				 * fib, and then set the event to wake up the
+ 				 * thread that is waiting for it.
+@@ -1552,7 +1636,7 @@ int aac_command_thread(void *data)
+ 						 */
+ 						time_last = fibctx->jiffies;
+ 						/*
+-						 * Has it been > 2 minutes 
++						 * Has it been > 2 minutes
+ 						 * since the last read off
+ 						 * the queue?
+ 						 */
+@@ -1583,7 +1667,7 @@ int aac_command_thread(void *data)
+ 						 */
+ 						list_add_tail(&newfib->fiblink, &fibctx->fib_list);
+ 						fibctx->count++;
+-						/* 
++						/*
+ 						 * Set the event to wake up the
+ 						 * thread that is waiting.
+ 						 */
+@@ -1655,11 +1739,11 @@ int aac_command_thread(void *data)
+ 				struct fib *fibptr;
  
- int dasd_generic_read_dev_chars(struct dasd_device *, char *, void **, int);
+ 				if ((fibptr = aac_fib_alloc(dev))) {
+-					u32 * info;
++					__le32 *info;
  
-@@ -542,10 +598,10 @@ int dasd_busid_known(char *);
- /* externals in dasd_gendisk.c */
- int  dasd_gendisk_init(void);
- void dasd_gendisk_exit(void);
--int dasd_gendisk_alloc(struct dasd_device *);
--void dasd_gendisk_free(struct dasd_device *);
--int dasd_scan_partitions(struct dasd_device *);
--void dasd_destroy_partitions(struct dasd_device *);
-+int dasd_gendisk_alloc(struct dasd_block *);
-+void dasd_gendisk_free(struct dasd_block *);
-+int dasd_scan_partitions(struct dasd_block *);
-+void dasd_destroy_partitions(struct dasd_block *);
+ 					aac_fib_init(fibptr);
  
- /* externals in dasd_ioctl.c */
- int  dasd_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
-@@ -563,20 +619,9 @@ struct dasd_ccw_req *dasd_alloc_erp_request(char *, int, int,
- void dasd_free_erp_request(struct dasd_ccw_req *, struct dasd_device *);
- void dasd_log_sense(struct dasd_ccw_req *, struct irb *);
+-					info = (u32 *) fib_data(fibptr);
++					info = (__le32 *) fib_data(fibptr);
+ 					if (now.tv_usec > 500000)
+ 						++now.tv_sec;
  
--/* externals in dasd_3370_erp.c */
--dasd_era_t dasd_3370_erp_examine(struct dasd_ccw_req *, struct irb *);
--
- /* externals in dasd_3990_erp.c */
--dasd_era_t dasd_3990_erp_examine(struct dasd_ccw_req *, struct irb *);
- struct dasd_ccw_req *dasd_3990_erp_action(struct dasd_ccw_req *);
+diff --git a/drivers/scsi/aacraid/dpcsup.c b/drivers/scsi/aacraid/dpcsup.c
+index e6032ff..d1163de 100644
+--- a/drivers/scsi/aacraid/dpcsup.c
++++ b/drivers/scsi/aacraid/dpcsup.c
+@@ -120,6 +120,7 @@ unsigned int aac_response_normal(struct aac_queue * q)
+ 			 *	NOTE:  we cannot touch the fib after this
+ 			 *	    call, because it may have been deallocated.
+ 			 */
++			fib->flags = 0;
+ 			fib->callback(fib->callback_data, fib);
+ 		} else {
+ 			unsigned long flagv;
+@@ -229,11 +230,9 @@ unsigned int aac_command_normal(struct aac_queue *q)
+  *	all QE there are and wake up all the waiters before exiting.
+  */
  
--/* externals in dasd_9336_erp.c */
--dasd_era_t dasd_9336_erp_examine(struct dasd_ccw_req *, struct irb *);
--
--/* externals in dasd_9336_erp.c */
--dasd_era_t dasd_9343_erp_examine(struct dasd_ccw_req *, struct irb *);
--struct dasd_ccw_req *dasd_9343_erp_action(struct dasd_ccw_req *);
--
- /* externals in dasd_eer.c */
- #ifdef CONFIG_DASD_EER
- int dasd_eer_init(void);
-diff --git a/drivers/s390/block/dasd_ioctl.c b/drivers/s390/block/dasd_ioctl.c
-index 672eb0a..91a6463 100644
---- a/drivers/s390/block/dasd_ioctl.c
-+++ b/drivers/s390/block/dasd_ioctl.c
-@@ -38,15 +38,15 @@ dasd_ioctl_api_version(void __user *argp)
- static int
- dasd_ioctl_enable(struct block_device *bdev)
+-unsigned int aac_intr_normal(struct aac_dev * dev, u32 Index)
++unsigned int aac_intr_normal(struct aac_dev * dev, u32 index)
  {
--	struct dasd_device *device = bdev->bd_disk->private_data;
-+	struct dasd_block *block = bdev->bd_disk->private_data;
- 
- 	if (!capable(CAP_SYS_ADMIN))
- 		return -EACCES;
+-	u32 index = le32_to_cpu(Index);
+-
+-	dprintk((KERN_INFO "aac_intr_normal(%p,%x)\n", dev, Index));
++	dprintk((KERN_INFO "aac_intr_normal(%p,%x)\n", dev, index));
+ 	if ((index & 0x00000002L)) {
+ 		struct hw_fib * hw_fib;
+ 		struct fib * fib;
+@@ -301,7 +300,7 @@ unsigned int aac_intr_normal(struct aac_dev * dev, u32 Index)
  
--	dasd_enable_device(device);
-+	dasd_enable_device(block->base);
- 	/* Formatting the dasd device can change the capacity. */
- 	mutex_lock(&bdev->bd_mutex);
--	i_size_write(bdev->bd_inode, (loff_t)get_capacity(device->gdp) << 9);
-+	i_size_write(bdev->bd_inode, (loff_t)get_capacity(block->gdp) << 9);
- 	mutex_unlock(&bdev->bd_mutex);
- 	return 0;
- }
-@@ -58,7 +58,7 @@ dasd_ioctl_enable(struct block_device *bdev)
- static int
- dasd_ioctl_disable(struct block_device *bdev)
- {
--	struct dasd_device *device = bdev->bd_disk->private_data;
-+	struct dasd_block *block = bdev->bd_disk->private_data;
+ 		if (hwfib->header.Command == cpu_to_le16(NuFileSystem))
+ 		{
+-			u32 *pstatus = (u32 *)hwfib->data;
++			__le32 *pstatus = (__le32 *)hwfib->data;
+ 			if (*pstatus & cpu_to_le32(0xffff0000))
+ 				*pstatus = cpu_to_le32(ST_OK);
+ 		}
+@@ -315,6 +314,7 @@ unsigned int aac_intr_normal(struct aac_dev * dev, u32 Index)
+ 			 *	NOTE:  we cannot touch the fib after this
+ 			 *	    call, because it may have been deallocated.
+ 			 */
++			fib->flags = 0;
+ 			fib->callback(fib->callback_data, fib);
+ 		} else {
+ 			unsigned long flagv;
+diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c
+index 9dd331b..61be227 100644
+--- a/drivers/scsi/aacraid/linit.c
++++ b/drivers/scsi/aacraid/linit.c
+@@ -159,27 +159,27 @@ static struct pci_device_id aac_pci_tbl[] = {
+ MODULE_DEVICE_TABLE(pci, aac_pci_tbl);
  
- 	if (!capable(CAP_SYS_ADMIN))
- 		return -EACCES;
-@@ -71,7 +71,7 @@ dasd_ioctl_disable(struct block_device *bdev)
- 	 * using the BIODASDFMT ioctl. Therefore the correct state for the
- 	 * device is DASD_STATE_BASIC that allows to do basic i/o.
- 	 */
--	dasd_set_target_state(device, DASD_STATE_BASIC);
-+	dasd_set_target_state(block->base, DASD_STATE_BASIC);
- 	/*
- 	 * Set i_size to zero, since read, write, etc. check against this
- 	 * value.
-@@ -85,19 +85,19 @@ dasd_ioctl_disable(struct block_device *bdev)
  /*
-  * Quiesce device.
+- * dmb - For now we add the number of channels to this structure.  
++ * dmb - For now we add the number of channels to this structure.
+  * In the future we should add a fib that reports the number of channels
+  * for the card.  At that time we can remove the channels from here
   */
--static int
--dasd_ioctl_quiesce(struct dasd_device *device)
-+static int dasd_ioctl_quiesce(struct dasd_block *block)
- {
- 	unsigned long flags;
-+	struct dasd_device *base;
+ static struct aac_driver_ident aac_drivers[] = {
+-	{ aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* PERC 2/Si (Iguana/PERC2Si) */
+-	{ aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* PERC 3/Di (Opal/PERC3Di) */
+-	{ aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* PERC 3/Si (SlimFast/PERC3Si */
+-	{ aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* PERC 3/Di (Iguana FlipChip/PERC3DiF */
+-	{ aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* PERC 3/Di (Viper/PERC3DiV) */
+-	{ aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* PERC 3/Di (Lexus/PERC3DiL) */
+-	{ aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 1, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* PERC 3/Di (Jaguar/PERC3DiJ) */
+-	{ aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* PERC 3/Di (Dagger/PERC3DiD) */
+-	{ aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* PERC 3/Di (Boxster/PERC3DiB) */
+-	{ aac_rx_init, "aacraid",  "ADAPTEC ", "catapult        ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* catapult */
+-	{ aac_rx_init, "aacraid",  "ADAPTEC ", "tomcat          ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* tomcat */
+-	{ aac_rx_init, "aacraid",  "ADAPTEC ", "Adaptec 2120S   ", 1, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Adaptec 2120S (Crusader) */
+-	{ aac_rx_init, "aacraid",  "ADAPTEC ", "Adaptec 2200S   ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Adaptec 2200S (Vulcan) */
+-	{ aac_rx_init, "aacraid",  "ADAPTEC ", "Adaptec 2200S   ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Adaptec 2200S (Vulcan-2m) */
+-	{ aac_rx_init, "aacraid",  "Legend  ", "Legend S220     ", 1, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Legend S220 (Legend Crusader) */
+-	{ aac_rx_init, "aacraid",  "Legend  ", "Legend S230     ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Legend S230 (Legend Vulcan) */
++	{ aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* PERC 2/Si (Iguana/PERC2Si) */
++	{ aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* PERC 3/Di (Opal/PERC3Di) */
++	{ aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* PERC 3/Si (SlimFast/PERC3Si */
++	{ aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* PERC 3/Di (Iguana FlipChip/PERC3DiF */
++	{ aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* PERC 3/Di (Viper/PERC3DiV) */
++	{ aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* PERC 3/Di (Lexus/PERC3DiL) */
++	{ aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 1, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* PERC 3/Di (Jaguar/PERC3DiJ) */
++	{ aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* PERC 3/Di (Dagger/PERC3DiD) */
++	{ aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* PERC 3/Di (Boxster/PERC3DiB) */
++	{ aac_rx_init, "aacraid",  "ADAPTEC ", "catapult        ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* catapult */
++	{ aac_rx_init, "aacraid",  "ADAPTEC ", "tomcat          ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* tomcat */
++	{ aac_rx_init, "aacraid",  "ADAPTEC ", "Adaptec 2120S   ", 1, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* Adaptec 2120S (Crusader) */
++	{ aac_rx_init, "aacraid",  "ADAPTEC ", "Adaptec 2200S   ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* Adaptec 2200S (Vulcan) */
++	{ aac_rx_init, "aacraid",  "ADAPTEC ", "Adaptec 2200S   ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* Adaptec 2200S (Vulcan-2m) */
++	{ aac_rx_init, "aacraid",  "Legend  ", "Legend S220     ", 1, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* Legend S220 (Legend Crusader) */
++	{ aac_rx_init, "aacraid",  "Legend  ", "Legend S230     ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* Legend S230 (Legend Vulcan) */
  
-+	base = block->base;
- 	if (!capable (CAP_SYS_ADMIN))
- 		return -EACCES;
+ 	{ aac_rx_init, "aacraid",  "ADAPTEC ", "Adaptec 3230S   ", 2 }, /* Adaptec 3230S (Harrier) */
+ 	{ aac_rx_init, "aacraid",  "ADAPTEC ", "Adaptec 3240S   ", 2 }, /* Adaptec 3240S (Tornado) */
+@@ -224,8 +224,8 @@ static struct aac_driver_ident aac_drivers[] = {
+ 	{ aac_sa_init, "percraid", "DELL    ", "PERCRAID        ", 4, AAC_QUIRK_34SG }, /* Dell PERC2/QC */
+ 	{ aac_sa_init, "hpnraid",  "HP      ", "NetRAID         ", 4, AAC_QUIRK_34SG }, /* HP NetRAID-4M */
  
--	DEV_MESSAGE (KERN_DEBUG, device, "%s",
--		     "Quiesce IO on device");
--	spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
--	device->stopped |= DASD_STOPPED_QUIESCE;
--	spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
-+	DEV_MESSAGE(KERN_DEBUG, base, "%s", "Quiesce IO on device");
-+	spin_lock_irqsave(get_ccwdev_lock(base->cdev), flags);
-+	base->stopped |= DASD_STOPPED_QUIESCE;
-+	spin_unlock_irqrestore(get_ccwdev_lock(base->cdev), flags);
- 	return 0;
- }
+-	{ aac_rx_init, "aacraid",  "DELL    ", "RAID            ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Dell Catchall */
+-	{ aac_rx_init, "aacraid",  "Legend  ", "RAID            ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Legend Catchall */
++	{ aac_rx_init, "aacraid",  "DELL    ", "RAID            ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* Dell Catchall */
++	{ aac_rx_init, "aacraid",  "Legend  ", "RAID            ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* Legend Catchall */
+ 	{ aac_rx_init, "aacraid",  "ADAPTEC ", "RAID            ", 2 }, /* Adaptec Catch All */
+ 	{ aac_rkt_init, "aacraid", "ADAPTEC ", "RAID            ", 2 }, /* Adaptec Rocket Catch All */
+ 	{ aac_nark_init, "aacraid", "ADAPTEC ", "RAID            ", 2 } /* Adaptec NEMER/ARK Catch All */
+@@ -239,7 +239,7 @@ static struct aac_driver_ident aac_drivers[] = {
+  *	Queues a command for execution by the associated Host Adapter.
+  *
+  *	TODO: unify with aac_scsi_cmd().
+- */ 
++ */
  
-@@ -105,22 +105,21 @@ dasd_ioctl_quiesce(struct dasd_device *device)
- /*
-  * Quiesce device.
-  */
--static int
--dasd_ioctl_resume(struct dasd_device *device)
-+static int dasd_ioctl_resume(struct dasd_block *block)
+ static int aac_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
  {
- 	unsigned long flags;
-+	struct dasd_device *base;
- 
-+	base = block->base;
- 	if (!capable (CAP_SYS_ADMIN))
- 		return -EACCES;
- 
--	DEV_MESSAGE (KERN_DEBUG, device, "%s",
--		     "resume IO on device");
--
--	spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
--	device->stopped &= ~DASD_STOPPED_QUIESCE;
--	spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
-+	DEV_MESSAGE(KERN_DEBUG, base, "%s", "resume IO on device");
-+	spin_lock_irqsave(get_ccwdev_lock(base->cdev), flags);
-+	base->stopped &= ~DASD_STOPPED_QUIESCE;
-+	spin_unlock_irqrestore(get_ccwdev_lock(base->cdev), flags);
- 
--	dasd_schedule_bh (device);
-+	dasd_schedule_block_bh(block);
- 	return 0;
- }
+@@ -258,7 +258,7 @@ static int aac_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd
+ 	}
+ 	cmd->SCp.phase = AAC_OWNER_LOWLEVEL;
+ 	return (aac_scsi_cmd(cmd) ? FAILED : 0);
+-} 
++}
  
-@@ -130,22 +129,23 @@ dasd_ioctl_resume(struct dasd_device *device)
-  * commands to format a single unit of the device. In terms of the ECKD
-  * devices this means CCWs are generated to format a single track.
+ /**
+  *	aac_info		-	Returns the host adapter name
+@@ -292,21 +292,21 @@ struct aac_driver_ident* aac_get_driver_ident(int devtype)
+  *	@capacity: the sector capacity of the disk
+  *	@geom: geometry block to fill in
+  *
+- *	Return the Heads/Sectors/Cylinders BIOS Disk Parameters for Disk.  
+- *	The default disk geometry is 64 heads, 32 sectors, and the appropriate 
+- *	number of cylinders so as not to exceed drive capacity.  In order for 
++ *	Return the Heads/Sectors/Cylinders BIOS Disk Parameters for Disk.
++ *	The default disk geometry is 64 heads, 32 sectors, and the appropriate
++ *	number of cylinders so as not to exceed drive capacity.  In order for
+  *	disks equal to or larger than 1 GB to be addressable by the BIOS
+- *	without exceeding the BIOS limitation of 1024 cylinders, Extended 
+- *	Translation should be enabled.   With Extended Translation enabled, 
+- *	drives between 1 GB inclusive and 2 GB exclusive are given a disk 
+- *	geometry of 128 heads and 32 sectors, and drives above 2 GB inclusive 
+- *	are given a disk geometry of 255 heads and 63 sectors.  However, if 
+- *	the BIOS detects that the Extended Translation setting does not match 
+- *	the geometry in the partition table, then the translation inferred 
+- *	from the partition table will be used by the BIOS, and a warning may 
++ *	without exceeding the BIOS limitation of 1024 cylinders, Extended
++ *	Translation should be enabled.   With Extended Translation enabled,
++ *	drives between 1 GB inclusive and 2 GB exclusive are given a disk
++ *	geometry of 128 heads and 32 sectors, and drives above 2 GB inclusive
++ *	are given a disk geometry of 255 heads and 63 sectors.  However, if
++ *	the BIOS detects that the Extended Translation setting does not match
++ *	the geometry in the partition table, then the translation inferred
++ *	from the partition table will be used by the BIOS, and a warning may
+  *	be displayed.
   */
--static int
--dasd_format(struct dasd_device * device, struct format_data_t * fdata)
-+static int dasd_format(struct dasd_block *block, struct format_data_t *fdata)
+- 
++
+ static int aac_biosparm(struct scsi_device *sdev, struct block_device *bdev,
+ 			sector_t capacity, int *geom)
  {
- 	struct dasd_ccw_req *cqr;
-+	struct dasd_device *base;
- 	int rc;
- 
--	if (device->discipline->format_device == NULL)
-+	base = block->base;
-+	if (base->discipline->format_device == NULL)
- 		return -EPERM;
+@@ -333,10 +333,10 @@ static int aac_biosparm(struct scsi_device *sdev, struct block_device *bdev,
  
--	if (device->state != DASD_STATE_BASIC) {
--		DEV_MESSAGE(KERN_WARNING, device, "%s",
-+	if (base->state != DASD_STATE_BASIC) {
-+		DEV_MESSAGE(KERN_WARNING, base, "%s",
- 			    "dasd_format: device is not disabled! ");
- 		return -EBUSY;
- 	}
+ 	param->cylinders = cap_to_cyls(capacity, param->heads * param->sectors);
  
--	DBF_DEV_EVENT(DBF_NOTICE, device,
-+	DBF_DEV_EVENT(DBF_NOTICE, base,
- 		      "formatting units %d to %d (%d B blocks) flags %d",
- 		      fdata->start_unit,
- 		      fdata->stop_unit, fdata->blksize, fdata->intensity);
-@@ -156,20 +156,20 @@ dasd_format(struct dasd_device * device, struct format_data_t * fdata)
- 	 * enabling the device later.
+-	/* 
++	/*
+ 	 *	Read the first 1024 bytes from the disk device, if the boot
+ 	 *	sector partition table is valid, search for a partition table
+-	 *	entry whose end_head matches one of the standard geometry 
++	 *	entry whose end_head matches one of the standard geometry
+ 	 *	translations ( 64/32, 128/32, 255/63 ).
  	 */
- 	if (fdata->start_unit == 0) {
--		struct block_device *bdev = bdget_disk(device->gdp, 0);
-+		struct block_device *bdev = bdget_disk(block->gdp, 0);
- 		bdev->bd_inode->i_blkbits = blksize_bits(fdata->blksize);
- 		bdput(bdev);
- 	}
+ 	buf = scsi_bios_ptable(bdev);
+@@ -401,30 +401,44 @@ static int aac_biosparm(struct scsi_device *sdev, struct block_device *bdev,
  
- 	while (fdata->start_unit <= fdata->stop_unit) {
--		cqr = device->discipline->format_device(device, fdata);
-+		cqr = base->discipline->format_device(base, fdata);
- 		if (IS_ERR(cqr))
- 			return PTR_ERR(cqr);
- 		rc = dasd_sleep_on_interruptible(cqr);
--		dasd_sfree_request(cqr, cqr->device);
-+		dasd_sfree_request(cqr, cqr->memdev);
- 		if (rc) {
- 			if (rc != -ERESTARTSYS)
--				DEV_MESSAGE(KERN_ERR, device,
-+				DEV_MESSAGE(KERN_ERR, base,
- 					    " Formatting of unit %d failed "
- 					    "with rc = %d",
- 					    fdata->start_unit, rc);
-@@ -186,7 +186,7 @@ dasd_format(struct dasd_device * device, struct format_data_t * fdata)
- static int
- dasd_ioctl_format(struct block_device *bdev, void __user *argp)
+ static int aac_slave_configure(struct scsi_device *sdev)
  {
--	struct dasd_device *device = bdev->bd_disk->private_data;
-+	struct dasd_block *block = bdev->bd_disk->private_data;
- 	struct format_data_t fdata;
- 
- 	if (!capable(CAP_SYS_ADMIN))
-@@ -194,51 +194,47 @@ dasd_ioctl_format(struct block_device *bdev, void __user *argp)
- 	if (!argp)
- 		return -EINVAL;
- 
--	if (device->features & DASD_FEATURE_READONLY)
-+	if (block->base->features & DASD_FEATURE_READONLY)
- 		return -EROFS;
- 	if (copy_from_user(&fdata, argp, sizeof(struct format_data_t)))
- 		return -EFAULT;
- 	if (bdev != bdev->bd_contains) {
--		DEV_MESSAGE(KERN_WARNING, device, "%s",
-+		DEV_MESSAGE(KERN_WARNING, block->base, "%s",
- 			    "Cannot low-level format a partition");
- 		return -EINVAL;
++	struct aac_dev *aac = (struct aac_dev *)sdev->host->hostdata;
+ 	if ((sdev->type == TYPE_DISK) &&
+-			(sdev_channel(sdev) != CONTAINER_CHANNEL)) {
++			(sdev_channel(sdev) != CONTAINER_CHANNEL) &&
++			(!aac->jbod || sdev->inq_periph_qual) &&
++			(!aac->raid_scsi_mode || (sdev_channel(sdev) != 2))) {
+ 		if (expose_physicals == 0)
+ 			return -ENXIO;
+-		if (expose_physicals < 0) {
+-			struct aac_dev *aac =
+-				(struct aac_dev *)sdev->host->hostdata;
+-			if (!aac->raid_scsi_mode || (sdev_channel(sdev) != 2))
+-				sdev->no_uld_attach = 1;
+-		}
++		if (expose_physicals < 0)
++			sdev->no_uld_attach = 1;
  	}
--	return dasd_format(device, &fdata);
-+	return dasd_format(block, &fdata);
+ 	if (sdev->tagged_supported && (sdev->type == TYPE_DISK) &&
+-			(sdev_channel(sdev) == CONTAINER_CHANNEL)) {
++			(!aac->raid_scsi_mode || (sdev_channel(sdev) != 2)) &&
++			!sdev->no_uld_attach) {
+ 		struct scsi_device * dev;
+ 		struct Scsi_Host *host = sdev->host;
+ 		unsigned num_lsu = 0;
+ 		unsigned num_one = 0;
+ 		unsigned depth;
++		unsigned cid;
+ 
++		/*
++		 * Firmware has an individual device recovery time typically
++		 * of 35 seconds, give us a margin.
++		 */
++		if (sdev->timeout < (45 * HZ))
++			sdev->timeout = 45 * HZ;
++		for (cid = 0; cid < aac->maximum_num_containers; ++cid)
++			if (aac->fsa_dev[cid].valid)
++				++num_lsu;
+ 		__shost_for_each_device(dev, host) {
+ 			if (dev->tagged_supported && (dev->type == TYPE_DISK) &&
+-				(sdev_channel(dev) == CONTAINER_CHANNEL))
+-				++num_lsu;
+-			else
++					(!aac->raid_scsi_mode ||
++						(sdev_channel(sdev) != 2)) &&
++					!dev->no_uld_attach) {
++				if ((sdev_channel(dev) != CONTAINER_CHANNEL)
++				 || !aac->fsa_dev[sdev_id(dev)].valid)
++					++num_lsu;
++			} else
+ 				++num_one;
+ 		}
+ 		if (num_lsu == 0)
+@@ -481,9 +495,35 @@ static int aac_change_queue_depth(struct scsi_device *sdev, int depth)
+ 	return sdev->queue_depth;
  }
  
- #ifdef CONFIG_DASD_PROFILE
- /*
-  * Reset device profile information
-  */
--static int
--dasd_ioctl_reset_profile(struct dasd_device *device)
-+static int dasd_ioctl_reset_profile(struct dasd_block *block)
++static ssize_t aac_show_raid_level(struct device *dev, struct device_attribute *attr, char *buf)
++{
++	struct scsi_device * sdev = to_scsi_device(dev);
++	if (sdev_channel(sdev) != CONTAINER_CHANNEL)
++		return snprintf(buf, PAGE_SIZE, sdev->no_uld_attach
++		  ? "Hidden\n" : "JBOD");
++	return snprintf(buf, PAGE_SIZE, "%s\n",
++	  get_container_type(((struct aac_dev *)(sdev->host->hostdata))
++	    ->fsa_dev[sdev_id(sdev)].type));
++}
++
++static struct device_attribute aac_raid_level_attr = {
++	.attr = {
++		.name = "level",
++		.mode = S_IRUGO,
++	},
++	.show = aac_show_raid_level
++};
++
++static struct device_attribute *aac_dev_attrs[] = {
++	&aac_raid_level_attr,
++	NULL,
++};
++
+ static int aac_ioctl(struct scsi_device *sdev, int cmd, void __user * arg)
  {
--	memset(&device->profile, 0, sizeof (struct dasd_profile_info_t));
-+	memset(&block->profile, 0, sizeof(struct dasd_profile_info_t));
- 	return 0;
+ 	struct aac_dev *dev = (struct aac_dev *)sdev->host->hostdata;
++	if (!capable(CAP_SYS_RAWIO))
++		return -EPERM;
+ 	return aac_do_ioctl(dev, cmd, arg);
  }
  
- /*
-  * Return device profile information
+@@ -506,17 +546,33 @@ static int aac_eh_abort(struct scsi_cmnd* cmd)
+ 			break;
+ 	case INQUIRY:
+ 	case READ_CAPACITY:
+-	case TEST_UNIT_READY:
+ 		/* Mark associated FIB to not complete, eh handler does this */
+ 		for (count = 0; count < (host->can_queue + AAC_NUM_MGT_FIB); ++count) {
+ 			struct fib * fib = &aac->fibs[count];
+ 			if (fib->hw_fib_va->header.XferState &&
++			  (fib->flags & FIB_CONTEXT_FLAG) &&
+ 			  (fib->callback_data == cmd)) {
+ 				fib->flags |= FIB_CONTEXT_FLAG_TIMED_OUT;
+ 				cmd->SCp.phase = AAC_OWNER_ERROR_HANDLER;
+ 				ret = SUCCESS;
+ 			}
+ 		}
++		break;
++	case TEST_UNIT_READY:
++		/* Mark associated FIB to not complete, eh handler does this */
++		for (count = 0; count < (host->can_queue + AAC_NUM_MGT_FIB); ++count) {
++			struct scsi_cmnd * command;
++			struct fib * fib = &aac->fibs[count];
++			if ((fib->hw_fib_va->header.XferState & cpu_to_le32(Async | NoResponseExpected)) &&
++			  (fib->flags & FIB_CONTEXT_FLAG) &&
++			  ((command = fib->callback_data)) &&
++			  (command->device == cmd->device)) {
++				fib->flags |= FIB_CONTEXT_FLAG_TIMED_OUT;
++				command->SCp.phase = AAC_OWNER_ERROR_HANDLER;
++				if (command == cmd)
++					ret = SUCCESS;
++			}
++		}
+ 	}
+ 	return ret;
+ }
+@@ -539,12 +595,13 @@ static int aac_eh_reset(struct scsi_cmnd* cmd)
+ 	for (count = 0; count < (host->can_queue + AAC_NUM_MGT_FIB); ++count) {
+ 		struct fib * fib = &aac->fibs[count];
+ 		if (fib->hw_fib_va->header.XferState &&
++		  (fib->flags & FIB_CONTEXT_FLAG) &&
+ 		  (fib->callback_data == cmd)) {
+ 			fib->flags |= FIB_CONTEXT_FLAG_TIMED_OUT;
+ 			cmd->SCp.phase = AAC_OWNER_ERROR_HANDLER;
+ 		}
+ 	}
+-	printk(KERN_ERR "%s: Host adapter reset request. SCSI hang ?\n", 
++	printk(KERN_ERR "%s: Host adapter reset request. SCSI hang ?\n",
+ 					AAC_DRIVERNAME);
+ 
+ 	if ((count = aac_check_health(aac)))
+@@ -584,8 +641,11 @@ static int aac_eh_reset(struct scsi_cmnd* cmd)
+ 	 * support a register, instead of a commanded, reset.
+ 	 */
+ 	if ((aac->supplement_adapter_info.SupportedOptions2 &
+-	  le32_to_cpu(AAC_OPTION_MU_RESET|AAC_OPTION_IGNORE_RESET)) ==
+-	  le32_to_cpu(AAC_OPTION_MU_RESET))
++	   AAC_OPTION_MU_RESET) &&
++	  aac_check_reset &&
++	  ((aac_check_reset != 1) ||
++	   (aac->supplement_adapter_info.SupportedOptions2 &
++	    AAC_OPTION_IGNORE_RESET)))
+ 		aac_reset_adapter(aac, 2); /* Bypass wait for command quiesce */
+ 	return SUCCESS; /* Cause an immediate retry of the command with a ten second delay after successful tur */
+ }
+@@ -632,8 +692,8 @@ static int aac_cfg_open(struct inode *inode, struct file *file)
+  *	Bugs: Needs locking against parallel ioctls lower down
+  *	Bugs: Needs to handle hot plugging
   */
--static int
--dasd_ioctl_read_profile(struct dasd_device *device, void __user *argp)
-+static int dasd_ioctl_read_profile(struct dasd_block *block, void __user *argp)
+- 
+-static int aac_cfg_ioctl(struct inode *inode,  struct file *file,
++
++static int aac_cfg_ioctl(struct inode *inode, struct file *file,
+ 		unsigned int cmd, unsigned long arg)
  {
- 	if (dasd_profile_level == DASD_PROFILE_OFF)
- 		return -EIO;
--	if (copy_to_user(argp, &device->profile,
--			 sizeof (struct dasd_profile_info_t)))
-+	if (copy_to_user(argp, &block->profile,
-+			 sizeof(struct dasd_profile_info_t)))
- 		return -EFAULT;
- 	return 0;
- }
- #else
--static int
--dasd_ioctl_reset_profile(struct dasd_device *device)
-+static int dasd_ioctl_reset_profile(struct dasd_block *block)
+ 	if (!capable(CAP_SYS_RAWIO))
+@@ -646,7 +706,7 @@ static long aac_compat_do_ioctl(struct aac_dev *dev, unsigned cmd, unsigned long
  {
- 	return -ENOSYS;
- }
+ 	long ret;
+ 	lock_kernel();
+-	switch (cmd) { 
++	switch (cmd) {
+ 	case FSACTL_MINIPORT_REV_CHECK:
+ 	case FSACTL_SENDFIB:
+ 	case FSACTL_OPEN_GET_ADAPTER_FIB:
+@@ -656,14 +716,14 @@ static long aac_compat_do_ioctl(struct aac_dev *dev, unsigned cmd, unsigned long
+ 	case FSACTL_QUERY_DISK:
+ 	case FSACTL_DELETE_DISK:
+ 	case FSACTL_FORCE_DELETE_DISK:
+-	case FSACTL_GET_CONTAINERS: 
++	case FSACTL_GET_CONTAINERS:
+ 	case FSACTL_SEND_LARGE_FIB:
+ 		ret = aac_do_ioctl(dev, cmd, (void __user *)arg);
+ 		break;
  
--static int
--dasd_ioctl_read_profile(struct dasd_device *device, void __user *argp)
-+static int dasd_ioctl_read_profile(struct dasd_block *block, void __user *argp)
- {
- 	return -ENOSYS;
+ 	case FSACTL_GET_NEXT_ADAPTER_FIB: {
+ 		struct fib_ioctl __user *f;
+-		
++
+ 		f = compat_alloc_user_space(sizeof(*f));
+ 		ret = 0;
+ 		if (clear_user(f, sizeof(*f)))
+@@ -676,9 +736,9 @@ static long aac_compat_do_ioctl(struct aac_dev *dev, unsigned cmd, unsigned long
+ 	}
+ 
+ 	default:
+-		ret = -ENOIOCTLCMD; 
++		ret = -ENOIOCTLCMD;
+ 		break;
+-	} 
++	}
+ 	unlock_kernel();
+ 	return ret;
  }
-@@ -247,87 +243,88 @@ dasd_ioctl_read_profile(struct dasd_device *device, void __user *argp)
- /*
-  * Return dasd information. Used for BIODASDINFO and BIODASDINFO2.
-  */
--static int
--dasd_ioctl_information(struct dasd_device *device,
--		unsigned int cmd, void __user *argp)
-+static int dasd_ioctl_information(struct dasd_block *block,
-+				  unsigned int cmd, void __user *argp)
+@@ -735,6 +795,25 @@ static ssize_t aac_show_vendor(struct class_device *class_dev,
+ 	return len;
+ }
+ 
++static ssize_t aac_show_flags(struct class_device *class_dev, char *buf)
++{
++	int len = 0;
++	struct aac_dev *dev = (struct aac_dev*)class_to_shost(class_dev)->hostdata;
++
++	if (nblank(dprintk(x)))
++		len = snprintf(buf, PAGE_SIZE, "dprintk\n");
++#ifdef AAC_DETAILED_STATUS_INFO
++	len += snprintf(buf + len, PAGE_SIZE - len,
++			"AAC_DETAILED_STATUS_INFO\n");
++#endif
++	if (dev->raw_io_interface && dev->raw_io_64)
++		len += snprintf(buf + len, PAGE_SIZE - len,
++				"SAI_READ_CAPACITY_16\n");
++	if (dev->jbod)
++		len += snprintf(buf + len, PAGE_SIZE - len, "SUPPORTED_JBOD\n");
++	return len;
++}
++
+ static ssize_t aac_show_kernel_version(struct class_device *class_dev,
+ 		char *buf)
  {
- 	struct dasd_information2_t *dasd_info;
- 	unsigned long flags;
- 	int rc;
-+	struct dasd_device *base;
- 	struct ccw_device *cdev;
- 	struct ccw_dev_id dev_id;
+@@ -742,7 +821,7 @@ static ssize_t aac_show_kernel_version(struct class_device *class_dev,
+ 	int len, tmp;
+ 
+ 	tmp = le32_to_cpu(dev->adapter_info.kernelrev);
+-	len = snprintf(buf, PAGE_SIZE, "%d.%d-%d[%d]\n", 
++	len = snprintf(buf, PAGE_SIZE, "%d.%d-%d[%d]\n",
+ 	  tmp >> 24, (tmp >> 16) & 0xff, tmp & 0xff,
+ 	  le32_to_cpu(dev->adapter_info.kernelbuild));
+ 	return len;
+@@ -755,7 +834,7 @@ static ssize_t aac_show_monitor_version(struct class_device *class_dev,
+ 	int len, tmp;
+ 
+ 	tmp = le32_to_cpu(dev->adapter_info.monitorrev);
+-	len = snprintf(buf, PAGE_SIZE, "%d.%d-%d[%d]\n", 
++	len = snprintf(buf, PAGE_SIZE, "%d.%d-%d[%d]\n",
+ 	  tmp >> 24, (tmp >> 16) & 0xff, tmp & 0xff,
+ 	  le32_to_cpu(dev->adapter_info.monitorbuild));
+ 	return len;
+@@ -768,7 +847,7 @@ static ssize_t aac_show_bios_version(struct class_device *class_dev,
+ 	int len, tmp;
+ 
+ 	tmp = le32_to_cpu(dev->adapter_info.biosrev);
+-	len = snprintf(buf, PAGE_SIZE, "%d.%d-%d[%d]\n", 
++	len = snprintf(buf, PAGE_SIZE, "%d.%d-%d[%d]\n",
+ 	  tmp >> 24, (tmp >> 16) & 0xff, tmp & 0xff,
+ 	  le32_to_cpu(dev->adapter_info.biosbuild));
+ 	return len;
+@@ -844,6 +923,13 @@ static struct class_device_attribute aac_vendor = {
+ 	},
+ 	.show = aac_show_vendor,
+ };
++static struct class_device_attribute aac_flags = {
++	.attr = {
++		.name = "flags",
++		.mode = S_IRUGO,
++	},
++	.show = aac_show_flags,
++};
+ static struct class_device_attribute aac_kernel_version = {
+ 	.attr = {
+ 		.name = "hba_kernel_version",
+@@ -898,6 +984,7 @@ static struct class_device_attribute aac_reset = {
+ static struct class_device_attribute *aac_attrs[] = {
+ 	&aac_model,
+ 	&aac_vendor,
++	&aac_flags,
+ 	&aac_kernel_version,
+ 	&aac_monitor_version,
+ 	&aac_bios_version,
+@@ -928,21 +1015,22 @@ static struct scsi_host_template aac_driver_template = {
+ 	.compat_ioctl			= aac_compat_ioctl,
+ #endif
+ 	.queuecommand   		= aac_queuecommand,
+-	.bios_param     		= aac_biosparm,	
++	.bios_param     		= aac_biosparm,
+ 	.shost_attrs			= aac_attrs,
+ 	.slave_configure		= aac_slave_configure,
+ 	.change_queue_depth		= aac_change_queue_depth,
++	.sdev_attrs			= aac_dev_attrs,
+ 	.eh_abort_handler		= aac_eh_abort,
+ 	.eh_host_reset_handler		= aac_eh_reset,
+-	.can_queue      		= AAC_NUM_IO_FIB,	
++	.can_queue      		= AAC_NUM_IO_FIB,
+ 	.this_id        		= MAXIMUM_NUM_CONTAINERS,
+ 	.sg_tablesize   		= 16,
+ 	.max_sectors    		= 128,
+ #if (AAC_NUM_IO_FIB > 256)
+ 	.cmd_per_lun			= 256,
+-#else		
+-	.cmd_per_lun    		= AAC_NUM_IO_FIB, 
+-#endif	
++#else
++	.cmd_per_lun    		= AAC_NUM_IO_FIB,
++#endif
+ 	.use_clustering			= ENABLE_CLUSTERING,
+ 	.use_sg_chaining		= ENABLE_SG_CHAINING,
+ 	.emulated                       = 1,
+@@ -979,18 +1067,18 @@ static int __devinit aac_probe_one(struct pci_dev *pdev,
+ 		goto out;
+ 	error = -ENODEV;
+ 
+-	if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) || 
++	if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) ||
+ 			pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK))
+ 		goto out_disable_pdev;
+ 	/*
+ 	 * If the quirk31 bit is set, the adapter needs adapter
+ 	 * to driver communication memory to be allocated below 2gig
+ 	 */
+-	if (aac_drivers[index].quirks & AAC_QUIRK_31BIT) 
++	if (aac_drivers[index].quirks & AAC_QUIRK_31BIT)
+ 		if (pci_set_dma_mask(pdev, DMA_31BIT_MASK) ||
+ 				pci_set_consistent_dma_mask(pdev, DMA_31BIT_MASK))
+ 			goto out_disable_pdev;
+-	
++
+ 	pci_set_master(pdev);
  
--	if (!device->discipline->fill_info)
-+	base = block->base;
-+	if (!base->discipline->fill_info)
- 		return -EINVAL;
+ 	shost = scsi_host_alloc(&aac_driver_template, sizeof(struct aac_dev));
+@@ -1003,7 +1091,7 @@ static int __devinit aac_probe_one(struct pci_dev *pdev,
+ 	shost->max_cmd_len = 16;
  
- 	dasd_info = kzalloc(sizeof(struct dasd_information2_t), GFP_KERNEL);
- 	if (dasd_info == NULL)
- 		return -ENOMEM;
+ 	aac = (struct aac_dev *)shost->hostdata;
+-	aac->scsi_host_ptr = shost;	
++	aac->scsi_host_ptr = shost;
+ 	aac->pdev = pdev;
+ 	aac->name = aac_driver_template.name;
+ 	aac->id = shost->unique_id;
+@@ -1040,7 +1128,7 @@ static int __devinit aac_probe_one(struct pci_dev *pdev,
+ 	if (aac_drivers[index].quirks & AAC_QUIRK_31BIT)
+ 		if (pci_set_dma_mask(pdev, DMA_32BIT_MASK))
+ 			goto out_deinit;
+- 
++
+ 	aac->maximum_num_channels = aac_drivers[index].channels;
+ 	error = aac_get_adapter_info(aac);
+ 	if (error < 0)
+@@ -1049,7 +1137,7 @@ static int __devinit aac_probe_one(struct pci_dev *pdev,
+ 	/*
+  	 * Lets override negotiations and drop the maximum SG limit to 34
+  	 */
+- 	if ((aac_drivers[index].quirks & AAC_QUIRK_34SG) && 
++	if ((aac_drivers[index].quirks & AAC_QUIRK_34SG) &&
+ 			(aac->scsi_host_ptr->sg_tablesize > 34)) {
+  		aac->scsi_host_ptr->sg_tablesize = 34;
+  		aac->scsi_host_ptr->max_sectors
+@@ -1066,17 +1154,17 @@ static int __devinit aac_probe_one(struct pci_dev *pdev,
+ 	/*
+ 	 * Firware printf works only with older firmware.
+ 	 */
+-	if (aac_drivers[index].quirks & AAC_QUIRK_34SG) 
++	if (aac_drivers[index].quirks & AAC_QUIRK_34SG)
+ 		aac->printf_enabled = 1;
+ 	else
+ 		aac->printf_enabled = 0;
+- 
++
+  	/*
+ 	 * max channel will be the physical channels plus 1 virtual channel
+ 	 * all containers are on the virtual channel 0 (CONTAINER_CHANNEL)
+ 	 * physical channels are address by their actual physical number+1
+ 	 */
+-	if ((aac->nondasd_support == 1) || expose_physicals)
++	if (aac->nondasd_support || expose_physicals || aac->jbod)
+ 		shost->max_channel = aac->maximum_num_channels;
+ 	else
+ 		shost->max_channel = 0;
+@@ -1148,10 +1236,10 @@ static void __devexit aac_remove_one(struct pci_dev *pdev)
+ 	kfree(aac->queues);
  
--	rc = device->discipline->fill_info(device, dasd_info);
-+	rc = base->discipline->fill_info(base, dasd_info);
- 	if (rc) {
- 		kfree(dasd_info);
- 		return rc;
- 	}
+ 	aac_adapter_ioremap(aac, 0);
+-	
++
+ 	kfree(aac->fibs);
+ 	kfree(aac->fsa_dev);
+-	
++
+ 	list_del(&aac->entry);
+ 	scsi_host_put(shost);
+ 	pci_disable_device(pdev);
+@@ -1172,7 +1260,7 @@ static struct pci_driver aac_pci_driver = {
+ static int __init aac_init(void)
+ {
+ 	int error;
+-	
++
+ 	printk(KERN_INFO "Adaptec %s driver %s\n",
+ 	  AAC_DRIVERNAME, aac_driver_version);
  
--	cdev = device->cdev;
-+	cdev = base->cdev;
- 	ccw_device_get_id(cdev, &dev_id);
+diff --git a/drivers/scsi/aacraid/rx.c b/drivers/scsi/aacraid/rx.c
+index 73eef3d..a08bbf1 100644
+--- a/drivers/scsi/aacraid/rx.c
++++ b/drivers/scsi/aacraid/rx.c
+@@ -465,7 +465,7 @@ static int aac_rx_restart_adapter(struct aac_dev *dev, int bled)
+ 	u32 var;
  
- 	dasd_info->devno = dev_id.devno;
--	dasd_info->schid = _ccw_device_get_subchannel_number(device->cdev);
-+	dasd_info->schid = _ccw_device_get_subchannel_number(base->cdev);
- 	dasd_info->cu_type = cdev->id.cu_type;
- 	dasd_info->cu_model = cdev->id.cu_model;
- 	dasd_info->dev_type = cdev->id.dev_type;
- 	dasd_info->dev_model = cdev->id.dev_model;
--	dasd_info->status = device->state;
-+	dasd_info->status = base->state;
+ 	if (!(dev->supplement_adapter_info.SupportedOptions2 &
+-	  le32_to_cpu(AAC_OPTION_MU_RESET)) || (bled >= 0) || (bled == -2)) {
++	  AAC_OPTION_MU_RESET) || (bled >= 0) || (bled == -2)) {
+ 		if (bled)
+ 			printk(KERN_ERR "%s%d: adapter kernel panic'd %x.\n",
+ 				dev->name, dev->id, bled);
+@@ -549,7 +549,9 @@ int _aac_rx_init(struct aac_dev *dev)
+ 	dev->OIMR = status = rx_readb (dev, MUnit.OIMR);
+ 	if ((((status & 0x0c) != 0x0c) || aac_reset_devices || reset_devices) &&
+ 	  !aac_rx_restart_adapter(dev, 0))
+-		++restart;
++		/* Make sure the Hardware FIFO is empty */
++		while ((++restart < 512) &&
++		  (rx_readl(dev, MUnit.OutboundQueue) != 0xFFFFFFFFL));
  	/*
- 	 * The open_count is increased for every opener, that includes
- 	 * the blkdev_get in dasd_scan_partitions.
- 	 * This must be hidden from user-space.
+ 	 *	Check to see if the board panic'd while booting.
  	 */
--	dasd_info->open_count = atomic_read(&device->open_count);
--	if (!device->bdev)
-+	dasd_info->open_count = atomic_read(&block->open_count);
-+	if (!block->bdev)
- 		dasd_info->open_count++;
+diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c
+index 38a1ee2..374ed02 100644
+--- a/drivers/scsi/advansys.c
++++ b/drivers/scsi/advansys.c
+@@ -8233,7 +8233,7 @@ static void adv_isr_callback(ADV_DVC_VAR *adv_dvc_varp, ADV_SCSI_REQ_Q *scsiqp)
+ 			if (scsiqp->scsi_status == SAM_STAT_CHECK_CONDITION) {
+ 				ASC_DBG(2, "SAM_STAT_CHECK_CONDITION\n");
+ 				ASC_DBG_PRT_SENSE(2, scp->sense_buffer,
+-						  sizeof(scp->sense_buffer));
++						  SCSI_SENSE_BUFFERSIZE);
+ 				/*
+ 				 * Note: The 'status_byte()' macro used by
+ 				 * target drivers defined in scsi.h shifts the
+@@ -9136,7 +9136,7 @@ static void asc_isr_callback(ASC_DVC_VAR *asc_dvc_varp, ASC_QDONE_INFO *qdonep)
+ 	BUG_ON(asc_dvc_varp != &boardp->dvc_var.asc_dvc_var);
  
+ 	dma_unmap_single(boardp->dev, scp->SCp.dma_handle,
+-			sizeof(scp->sense_buffer), DMA_FROM_DEVICE);
++			 SCSI_SENSE_BUFFERSIZE, DMA_FROM_DEVICE);
  	/*
- 	 * check if device is really formatted
- 	 * LDL / CDL was returned by 'fill_info'
+ 	 * 'qdonep' contains the command's ending status.
  	 */
--	if ((device->state < DASD_STATE_READY) ||
--	    (dasd_check_blocksize(device->bp_block)))
-+	if ((base->state < DASD_STATE_READY) ||
-+	    (dasd_check_blocksize(block->bp_block)))
- 		dasd_info->format = DASD_FORMAT_NONE;
+@@ -9166,7 +9166,7 @@ static void asc_isr_callback(ASC_DVC_VAR *asc_dvc_varp, ASC_QDONE_INFO *qdonep)
+ 			if (qdonep->d3.scsi_stat == SAM_STAT_CHECK_CONDITION) {
+ 				ASC_DBG(2, "SAM_STAT_CHECK_CONDITION\n");
+ 				ASC_DBG_PRT_SENSE(2, scp->sense_buffer,
+-						  sizeof(scp->sense_buffer));
++						  SCSI_SENSE_BUFFERSIZE);
+ 				/*
+ 				 * Note: The 'status_byte()' macro used by
+ 				 * target drivers defined in scsi.h shifts the
+@@ -9881,9 +9881,9 @@ static __le32 advansys_get_sense_buffer_dma(struct scsi_cmnd *scp)
+ {
+ 	struct asc_board *board = shost_priv(scp->device->host);
+ 	scp->SCp.dma_handle = dma_map_single(board->dev, scp->sense_buffer,
+-				sizeof(scp->sense_buffer), DMA_FROM_DEVICE);
++					     SCSI_SENSE_BUFFERSIZE, DMA_FROM_DEVICE);
+ 	dma_cache_sync(board->dev, scp->sense_buffer,
+-				sizeof(scp->sense_buffer), DMA_FROM_DEVICE);
++		       SCSI_SENSE_BUFFERSIZE, DMA_FROM_DEVICE);
+ 	return cpu_to_le32(scp->SCp.dma_handle);
+ }
  
- 	dasd_info->features |=
--		((device->features & DASD_FEATURE_READONLY) != 0);
-+		((base->features & DASD_FEATURE_READONLY) != 0);
+@@ -9914,7 +9914,7 @@ static int asc_build_req(struct asc_board *boardp, struct scsi_cmnd *scp,
+ 	asc_scsi_q->q2.target_ix =
+ 	    ASC_TIDLUN_TO_IX(scp->device->id, scp->device->lun);
+ 	asc_scsi_q->q1.sense_addr = advansys_get_sense_buffer_dma(scp);
+-	asc_scsi_q->q1.sense_len = sizeof(scp->sense_buffer);
++	asc_scsi_q->q1.sense_len = SCSI_SENSE_BUFFERSIZE;
  
--	if (device->discipline)
--		memcpy(dasd_info->type, device->discipline->name, 4);
-+	if (base->discipline)
-+		memcpy(dasd_info->type, base->discipline->name, 4);
- 	else
- 		memcpy(dasd_info->type, "none", 4);
+ 	/*
+ 	 * If there are any outstanding requests for the current target,
+@@ -10173,7 +10173,7 @@ adv_build_req(struct asc_board *boardp, struct scsi_cmnd *scp,
+ 	scsiqp->target_lun = scp->device->lun;
  
--	if (device->request_queue->request_fn) {
-+	if (block->request_queue->request_fn) {
- 		struct list_head *l;
- #ifdef DASD_EXTENDED_PROFILING
- 		{
- 			struct list_head *l;
--			spin_lock_irqsave(&device->lock, flags);
--			list_for_each(l, &device->request_queue->queue_head)
-+			spin_lock_irqsave(&block->lock, flags);
-+			list_for_each(l, &block->request_queue->queue_head)
- 				dasd_info->req_queue_len++;
--			spin_unlock_irqrestore(&device->lock, flags);
-+			spin_unlock_irqrestore(&block->lock, flags);
- 		}
- #endif				/* DASD_EXTENDED_PROFILING */
--		spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
--		list_for_each(l, &device->ccw_queue)
-+		spin_lock_irqsave(get_ccwdev_lock(base->cdev), flags);
-+		list_for_each(l, &base->ccw_queue)
- 			dasd_info->chanq_len++;
--		spin_unlock_irqrestore(get_ccwdev_lock(device->cdev),
-+		spin_unlock_irqrestore(get_ccwdev_lock(base->cdev),
- 				       flags);
- 	}
+ 	scsiqp->sense_addr = cpu_to_le32(virt_to_bus(&scp->sense_buffer[0]));
+-	scsiqp->sense_len = sizeof(scp->sense_buffer);
++	scsiqp->sense_len = SCSI_SENSE_BUFFERSIZE;
  
- 	rc = 0;
- 	if (copy_to_user(argp, dasd_info,
- 			 ((cmd == (unsigned int) BIODASDINFO2) ?
--			  sizeof (struct dasd_information2_t) :
--			  sizeof (struct dasd_information_t))))
-+			  sizeof(struct dasd_information2_t) :
-+			  sizeof(struct dasd_information_t))))
- 		rc = -EFAULT;
- 	kfree(dasd_info);
- 	return rc;
-@@ -339,7 +336,7 @@ dasd_ioctl_information(struct dasd_device *device,
- static int
- dasd_ioctl_set_ro(struct block_device *bdev, void __user *argp)
- {
--	struct dasd_device *device =  bdev->bd_disk->private_data;
-+	struct dasd_block *block =  bdev->bd_disk->private_data;
- 	int intval;
+ 	/* Build ADV_SCSI_REQ_Q */
  
- 	if (!capable(CAP_SYS_ADMIN))
-@@ -351,11 +348,10 @@ dasd_ioctl_set_ro(struct block_device *bdev, void __user *argp)
- 		return -EFAULT;
+diff --git a/drivers/scsi/aha152x.c b/drivers/scsi/aha152x.c
+index ea8c699..6ccdc96 100644
+--- a/drivers/scsi/aha152x.c
++++ b/drivers/scsi/aha152x.c
+@@ -260,6 +260,7 @@
+ #include <scsi/scsi_dbg.h>
+ #include <scsi/scsi_host.h>
+ #include <scsi/scsi_transport_spi.h>
++#include <scsi/scsi_eh.h>
+ #include "aha152x.h"
  
- 	set_disk_ro(bdev->bd_disk, intval);
--	return dasd_set_feature(device->cdev, DASD_FEATURE_READONLY, intval);
-+	return dasd_set_feature(block->base->cdev, DASD_FEATURE_READONLY, intval);
- }
+ static LIST_HEAD(aha152x_host_list);
+@@ -558,9 +559,7 @@ struct aha152x_hostdata {
+ struct aha152x_scdata {
+ 	Scsi_Cmnd *next;	/* next sc in queue */
+ 	struct completion *done;/* semaphore to block on */
+-	unsigned char aha_orig_cmd_len;
+-	unsigned char aha_orig_cmnd[MAX_COMMAND_SIZE];
+-	int aha_orig_resid;
++	struct scsi_eh_save ses;
+ };
  
--static int
--dasd_ioctl_readall_cmb(struct dasd_device *device, unsigned int cmd,
-+static int dasd_ioctl_readall_cmb(struct dasd_block *block, unsigned int cmd,
- 		unsigned long arg)
- {
- 	struct cmbdata __user *argp = (void __user *) arg;
-@@ -363,7 +359,7 @@ dasd_ioctl_readall_cmb(struct dasd_device *device, unsigned int cmd,
- 	struct cmbdata data;
- 	int ret;
+ /* access macros for hostdata */
+@@ -1017,16 +1016,10 @@ static int aha152x_internal_queue(Scsi_Cmnd *SCpnt, struct completion *complete,
+ 	   SCp.buffers_residual : left buffers in list
+ 	   SCp.phase            : current state of the command */
  
--	ret = cmf_readall(device->cdev, &data);
-+	ret = cmf_readall(block->base->cdev, &data);
- 	if (!ret && copy_to_user(argp, &data, min(size, sizeof(*argp))))
- 		return -EFAULT;
- 	return ret;
-@@ -374,10 +370,10 @@ dasd_ioctl(struct inode *inode, struct file *file,
- 	   unsigned int cmd, unsigned long arg)
- {
- 	struct block_device *bdev = inode->i_bdev;
--	struct dasd_device *device = bdev->bd_disk->private_data;
-+	struct dasd_block *block = bdev->bd_disk->private_data;
- 	void __user *argp = (void __user *)arg;
+-	if ((phase & (check_condition|resetting)) || !scsi_sglist(SCpnt)) {
+-		if (phase & check_condition) {
+-			SCpnt->SCp.ptr           = SCpnt->sense_buffer;
+-			SCpnt->SCp.this_residual = sizeof(SCpnt->sense_buffer);
+-			scsi_set_resid(SCpnt, sizeof(SCpnt->sense_buffer));
+-		} else {
+-			SCpnt->SCp.ptr           = NULL;
+-			SCpnt->SCp.this_residual = 0;
+-			scsi_set_resid(SCpnt, 0);
+-		}
++	if ((phase & resetting) || !scsi_sglist(SCpnt)) {
++		SCpnt->SCp.ptr           = NULL;
++		SCpnt->SCp.this_residual = 0;
++		scsi_set_resid(SCpnt, 0);
+ 		SCpnt->SCp.buffer           = NULL;
+ 		SCpnt->SCp.buffers_residual = 0;
+ 	} else {
+@@ -1561,10 +1554,7 @@ static void busfree_run(struct Scsi_Host *shpnt)
+ 			}
+ #endif
  
--	if (!device)
-+	if (!block)
-                 return -ENODEV;
+-			/* restore old command */
+-			memcpy(cmd->cmnd, sc->aha_orig_cmnd, sizeof(cmd->cmnd));
+-			cmd->cmd_len = sc->aha_orig_cmd_len;
+-			scsi_set_resid(cmd, sc->aha_orig_resid);
++			scsi_eh_restore_cmnd(cmd, &sc->ses);
  
- 	if ((_IOC_DIR(cmd) != _IOC_NONE) && !arg) {
-@@ -391,33 +387,33 @@ dasd_ioctl(struct inode *inode, struct file *file,
- 	case BIODASDENABLE:
- 		return dasd_ioctl_enable(bdev);
- 	case BIODASDQUIESCE:
--		return dasd_ioctl_quiesce(device);
-+		return dasd_ioctl_quiesce(block);
- 	case BIODASDRESUME:
--		return dasd_ioctl_resume(device);
-+		return dasd_ioctl_resume(block);
- 	case BIODASDFMT:
- 		return dasd_ioctl_format(bdev, argp);
- 	case BIODASDINFO:
--		return dasd_ioctl_information(device, cmd, argp);
-+		return dasd_ioctl_information(block, cmd, argp);
- 	case BIODASDINFO2:
--		return dasd_ioctl_information(device, cmd, argp);
-+		return dasd_ioctl_information(block, cmd, argp);
- 	case BIODASDPRRD:
--		return dasd_ioctl_read_profile(device, argp);
-+		return dasd_ioctl_read_profile(block, argp);
- 	case BIODASDPRRST:
--		return dasd_ioctl_reset_profile(device);
-+		return dasd_ioctl_reset_profile(block);
- 	case BLKROSET:
- 		return dasd_ioctl_set_ro(bdev, argp);
- 	case DASDAPIVER:
- 		return dasd_ioctl_api_version(argp);
- 	case BIODASDCMFENABLE:
--		return enable_cmf(device->cdev);
-+		return enable_cmf(block->base->cdev);
- 	case BIODASDCMFDISABLE:
--		return disable_cmf(device->cdev);
-+		return disable_cmf(block->base->cdev);
- 	case BIODASDREADALLCMB:
--		return dasd_ioctl_readall_cmb(device, cmd, arg);
-+		return dasd_ioctl_readall_cmb(block, cmd, arg);
- 	default:
- 		/* if the discipline has an ioctl method try it. */
--		if (device->discipline->ioctl) {
--			int rval = device->discipline->ioctl(device, cmd, argp);
-+		if (block->base->discipline->ioctl) {
-+			int rval = block->base->discipline->ioctl(block, cmd, argp);
- 			if (rval != -ENOIOCTLCMD)
- 				return rval;
- 		}
-diff --git a/drivers/s390/block/dasd_proc.c b/drivers/s390/block/dasd_proc.c
-index ac7e8ef..28a86f0 100644
---- a/drivers/s390/block/dasd_proc.c
-+++ b/drivers/s390/block/dasd_proc.c
-@@ -54,11 +54,16 @@ static int
- dasd_devices_show(struct seq_file *m, void *v)
- {
- 	struct dasd_device *device;
-+	struct dasd_block *block;
- 	char *substr;
+ 			cmd->SCp.Status = SAM_STAT_CHECK_CONDITION;
  
- 	device = dasd_device_from_devindex((unsigned long) v - 1);
- 	if (IS_ERR(device))
- 		return 0;
-+	if (device->block)
-+		block = device->block;
-+	else
-+		return 0;
- 	/* Print device number. */
- 	seq_printf(m, "%s", device->cdev->dev.bus_id);
- 	/* Print discipline string. */
-@@ -67,14 +72,14 @@ dasd_devices_show(struct seq_file *m, void *v)
- 	else
- 		seq_printf(m, "(none)");
- 	/* Print kdev. */
--	if (device->gdp)
-+	if (block->gdp)
- 		seq_printf(m, " at (%3d:%6d)",
--			   device->gdp->major, device->gdp->first_minor);
-+			   block->gdp->major, block->gdp->first_minor);
- 	else
- 		seq_printf(m, "  at (???:??????)");
- 	/* Print device name. */
--	if (device->gdp)
--		seq_printf(m, " is %-8s", device->gdp->disk_name);
-+	if (block->gdp)
-+		seq_printf(m, " is %-8s", block->gdp->disk_name);
- 	else
- 		seq_printf(m, " is ????????");
- 	/* Print devices features. */
-@@ -100,14 +105,14 @@ dasd_devices_show(struct seq_file *m, void *v)
- 	case DASD_STATE_READY:
- 	case DASD_STATE_ONLINE:
- 		seq_printf(m, "active ");
--		if (dasd_check_blocksize(device->bp_block))
-+		if (dasd_check_blocksize(block->bp_block))
- 			seq_printf(m, "n/f	 ");
- 		else
- 			seq_printf(m,
- 				   "at blocksize: %d, %ld blocks, %ld MB",
--				   device->bp_block, device->blocks,
--				   ((device->bp_block >> 9) *
--				    device->blocks) >> 11);
-+				   block->bp_block, block->blocks,
-+				   ((block->bp_block >> 9) *
-+				    block->blocks) >> 11);
- 		break;
- 	default:
- 		seq_printf(m, "no stat");
-@@ -137,7 +142,7 @@ static void dasd_devices_stop(struct seq_file *m, void *v)
- {
- }
+@@ -1587,22 +1577,10 @@ static void busfree_run(struct Scsi_Host *shpnt)
+ 				DPRINTK(debug_eh, ERR_LEAD "requesting sense\n", CMDINFO(ptr));
+ #endif
  
--static struct seq_operations dasd_devices_seq_ops = {
-+static const struct seq_operations dasd_devices_seq_ops = {
- 	.start		= dasd_devices_start,
- 	.next		= dasd_devices_next,
- 	.stop		= dasd_devices_stop,
-diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c
-index 15a5789..7779bfc 100644
---- a/drivers/s390/block/dcssblk.c
-+++ b/drivers/s390/block/dcssblk.c
-@@ -82,7 +82,7 @@ struct dcssblk_dev_info {
- 	struct request_queue *dcssblk_queue;
- };
+-				/* save old command */
+ 				sc = SCDATA(ptr);
+ 				/* It was allocated in aha152x_internal_queue? */
+ 				BUG_ON(!sc);
+-				memcpy(sc->aha_orig_cmnd, ptr->cmnd,
+-				                            sizeof(ptr->cmnd));
+-				sc->aha_orig_cmd_len = ptr->cmd_len;
+-				sc->aha_orig_resid = scsi_get_resid(ptr);
+-
+-				ptr->cmnd[0]         = REQUEST_SENSE;
+-				ptr->cmnd[1]         = 0;
+-				ptr->cmnd[2]         = 0;
+-				ptr->cmnd[3]         = 0;
+-				ptr->cmnd[4]         = sizeof(ptr->sense_buffer);
+-				ptr->cmnd[5]         = 0;
+-				ptr->cmd_len         = 6;
++				scsi_eh_prep_cmnd(ptr, &sc->ses, NULL, 0, ~0);
  
--static struct list_head dcssblk_devices = LIST_HEAD_INIT(dcssblk_devices);
-+static LIST_HEAD(dcssblk_devices);
- static struct rw_semaphore dcssblk_devices_sem;
+ 				DO_UNLOCK(flags);
+ 				aha152x_internal_queue(ptr, NULL, check_condition, ptr->scsi_done);
+diff --git a/drivers/scsi/aha1542.c b/drivers/scsi/aha1542.c
+index bbcc2c5..190568e 100644
+--- a/drivers/scsi/aha1542.c
++++ b/drivers/scsi/aha1542.c
+@@ -51,15 +51,6 @@
+ #define SCSI_BUF_PA(address)	isa_virt_to_bus(address)
+ #define SCSI_SG_PA(sgent)	(isa_page_to_bus(sg_page((sgent))) + (sgent)->offset)
  
- /*
-diff --git a/drivers/s390/char/Makefile b/drivers/s390/char/Makefile
-index 130de19..7e73e39 100644
---- a/drivers/s390/char/Makefile
-+++ b/drivers/s390/char/Makefile
-@@ -3,7 +3,7 @@
- #
+-static void BAD_DMA(void *address, unsigned int length)
+-{
+-	printk(KERN_CRIT "buf vaddress %p paddress 0x%lx length %d\n",
+-	       address,
+-	       SCSI_BUF_PA(address),
+-	       length);
+-	panic("Buffer at physical address > 16Mb used for aha1542");
+-}
+-
+ static void BAD_SG_DMA(Scsi_Cmnd * SCpnt,
+ 		       struct scatterlist *sgp,
+ 		       int nseg,
+@@ -545,7 +536,7 @@ static void aha1542_intr_handle(struct Scsi_Host *shost, void *dev_id)
+ 		   we will still have it in the cdb when we come back */
+ 		if (ccb[mbo].tarstat == 2)
+ 			memcpy(SCtmp->sense_buffer, &ccb[mbo].cdb[ccb[mbo].cdblen],
+-			       sizeof(SCtmp->sense_buffer));
++			       SCSI_SENSE_BUFFERSIZE);
  
- obj-y += ctrlchar.o keyboard.o defkeymap.o sclp.o sclp_rw.o sclp_quiesce.o \
--	 sclp_info.o sclp_config.o sclp_chp.o
-+	 sclp_cmd.o sclp_config.o sclp_cpi_sys.o
  
- obj-$(CONFIG_TN3270) += raw3270.o
- obj-$(CONFIG_TN3270_CONSOLE) += con3270.o
-diff --git a/drivers/s390/char/monwriter.c b/drivers/s390/char/monwriter.c
-index 20442fb..a86c053 100644
---- a/drivers/s390/char/monwriter.c
-+++ b/drivers/s390/char/monwriter.c
-@@ -295,7 +295,7 @@ module_init(mon_init);
- module_exit(mon_exit);
+ 		/* is there mail :-) */
+@@ -597,8 +588,7 @@ static int aha1542_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
+ 	unchar target = SCpnt->device->id;
+ 	unchar lun = SCpnt->device->lun;
+ 	unsigned long flags;
+-	void *buff = SCpnt->request_buffer;
+-	int bufflen = SCpnt->request_bufflen;
++	int bufflen = scsi_bufflen(SCpnt);
+ 	int mbo;
+ 	struct mailbox *mb;
+ 	struct ccb *ccb;
+@@ -619,7 +609,7 @@ static int aha1542_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
+ #if 0
+ 		/* scsi_request_sense() provides a buffer of size 256,
+ 		   so there is no reason to expect equality */
+-		if (bufflen != sizeof(SCpnt->sense_buffer))
++		if (bufflen != SCSI_SENSE_BUFFERSIZE)
+ 			printk(KERN_CRIT "aha1542: Wrong buffer length supplied "
+ 			       "for request sense (%d)\n", bufflen);
+ #endif
+@@ -689,42 +679,29 @@ static int aha1542_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
  
- module_param_named(max_bufs, mon_max_bufs, int, 0644);
--MODULE_PARM_DESC(max_bufs, "Maximum number of sample monitor data buffers"
-+MODULE_PARM_DESC(max_bufs, "Maximum number of sample monitor data buffers "
- 		 "that can be active at one time");
+ 	memcpy(ccb[mbo].cdb, cmd, ccb[mbo].cdblen);
  
- MODULE_AUTHOR("Melissa Howland <Melissa.Howland at us.ibm.com>");
-diff --git a/drivers/s390/char/raw3270.c b/drivers/s390/char/raw3270.c
-index 8d1c64a..0d98f1f 100644
---- a/drivers/s390/char/raw3270.c
-+++ b/drivers/s390/char/raw3270.c
-@@ -66,7 +66,7 @@ struct raw3270 {
- static DEFINE_MUTEX(raw3270_mutex);
+-	if (SCpnt->use_sg) {
++	if (bufflen) {
+ 		struct scatterlist *sg;
+ 		struct chain *cptr;
+ #ifdef DEBUG
+ 		unsigned char *ptr;
+ #endif
+-		int i;
++		int i, sg_count = scsi_sg_count(SCpnt);
+ 		ccb[mbo].op = 2;	/* SCSI Initiator Command  w/scatter-gather */
+-		SCpnt->host_scribble = kmalloc(512, GFP_KERNEL | GFP_DMA);
++		SCpnt->host_scribble = kmalloc(sizeof(*cptr)*sg_count,
++		                                         GFP_KERNEL | GFP_DMA);
+ 		cptr = (struct chain *) SCpnt->host_scribble;
+ 		if (cptr == NULL) {
+ 			/* free the claimed mailbox slot */
+ 			HOSTDATA(SCpnt->device->host)->SCint[mbo] = NULL;
+ 			return SCSI_MLQUEUE_HOST_BUSY;
+ 		}
+-		scsi_for_each_sg(SCpnt, sg, SCpnt->use_sg, i) {
+-			if (sg->length == 0 || SCpnt->use_sg > 16 ||
+-			    (((int) sg->offset) & 1) || (sg->length & 1)) {
+-				unsigned char *ptr;
+-				printk(KERN_CRIT "Bad segment list supplied to aha1542.c (%d, %d)\n", SCpnt->use_sg, i);
+-				scsi_for_each_sg(SCpnt, sg, SCpnt->use_sg, i) {
+-					printk(KERN_CRIT "%d: %p %d\n", i,
+-					       sg_virt(sg), sg->length);
+-				};
+-				printk(KERN_CRIT "cptr %x: ", (unsigned int) cptr);
+-				ptr = (unsigned char *) &cptr[i];
+-				for (i = 0; i < 18; i++)
+-					printk("%02x ", ptr[i]);
+-				panic("Foooooooood fight!");
+-			};
++		scsi_for_each_sg(SCpnt, sg, sg_count, i) {
+ 			any2scsi(cptr[i].dataptr, SCSI_SG_PA(sg));
+ 			if (SCSI_SG_PA(sg) + sg->length - 1 > ISA_DMA_THRESHOLD)
+-				BAD_SG_DMA(SCpnt, sg, SCpnt->use_sg, i);
++				BAD_SG_DMA(SCpnt, scsi_sglist(SCpnt), sg_count, i);
+ 			any2scsi(cptr[i].datalen, sg->length);
+ 		};
+-		any2scsi(ccb[mbo].datalen, SCpnt->use_sg * sizeof(struct chain));
++		any2scsi(ccb[mbo].datalen, sg_count * sizeof(struct chain));
+ 		any2scsi(ccb[mbo].dataptr, SCSI_BUF_PA(cptr));
+ #ifdef DEBUG
+ 		printk("cptr %x: ", cptr);
+@@ -735,10 +712,8 @@ static int aha1542_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
+ 	} else {
+ 		ccb[mbo].op = 0;	/* SCSI Initiator Command */
+ 		SCpnt->host_scribble = NULL;
+-		any2scsi(ccb[mbo].datalen, bufflen);
+-		if (buff && SCSI_BUF_PA(buff + bufflen - 1) > ISA_DMA_THRESHOLD)
+-			BAD_DMA(buff, bufflen);
+-		any2scsi(ccb[mbo].dataptr, SCSI_BUF_PA(buff));
++		any2scsi(ccb[mbo].datalen, 0);
++		any2scsi(ccb[mbo].dataptr, 0);
+ 	};
+ 	ccb[mbo].idlun = (target & 7) << 5 | direction | (lun & 7);	/*SCSI Target Id */
+ 	ccb[mbo].rsalen = 16;
+diff --git a/drivers/scsi/aha1740.c b/drivers/scsi/aha1740.c
+index f6722fd..be58a0b 100644
+--- a/drivers/scsi/aha1740.c
++++ b/drivers/scsi/aha1740.c
+@@ -286,7 +286,7 @@ static irqreturn_t aha1740_intr_handle(int irq, void *dev_id)
+ 			   cdb when we come back */
+ 			if ( (adapstat & G2INTST_MASK) == G2INTST_CCBERROR ) {
+ 				memcpy(SCtmp->sense_buffer, ecbptr->sense, 
+-				       sizeof(SCtmp->sense_buffer));
++				       SCSI_SENSE_BUFFERSIZE);
+ 				errstatus = aha1740_makecode(ecbptr->sense,ecbptr->status);
+ 			} else
+ 				errstatus = 0;
+diff --git a/drivers/scsi/aic7xxx/Makefile b/drivers/scsi/aic7xxx/Makefile
+index 9a6ce19..e4f70c5 100644
+--- a/drivers/scsi/aic7xxx/Makefile
++++ b/drivers/scsi/aic7xxx/Makefile
+@@ -33,11 +33,10 @@ aic79xx-y					+= aic79xx_osm.o	\
+ 						   aic79xx_proc.o	\
+ 						   aic79xx_osm_pci.o
  
- /* List of 3270 devices. */
--static struct list_head raw3270_devices = LIST_HEAD_INIT(raw3270_devices);
-+static LIST_HEAD(raw3270_devices);
+-EXTRA_CFLAGS += -Idrivers/scsi
++ccflags-y += -Idrivers/scsi
+ ifdef WARNINGS_BECOME_ERRORS
+-EXTRA_CFLAGS += -Werror
++ccflags-y += -Werror
+ endif
+-#EXTRA_CFLAGS += -g
  
- /*
-  * Flag to indicate if the driver has been registered. Some operations
-@@ -1210,7 +1210,7 @@ struct raw3270_notifier {
- 	void (*notifier)(int, int);
- };
+ # Files generated that shall be removed upon make clean
+ clean-files := aic7xxx_seq.h aic7xxx_reg.h aic7xxx_reg_print.c
+@@ -46,53 +45,45 @@ clean-files += aic79xx_seq.h aic79xx_reg.h aic79xx_reg_print.c
+ # Dependencies for generated files need to be listed explicitly
  
--static struct list_head raw3270_notifier = LIST_HEAD_INIT(raw3270_notifier);
-+static LIST_HEAD(raw3270_notifier);
+ $(obj)/aic7xxx_core.o: $(obj)/aic7xxx_seq.h
++$(obj)/aic7xxx_core.o: $(obj)/aic7xxx_reg.h
+ $(obj)/aic79xx_core.o: $(obj)/aic79xx_seq.h
+-$(obj)/aic79xx_reg_print.c: $(src)/aic79xx_reg_print.c_shipped
+-$(obj)/aic7xxx_reg_print.c: $(src)/aic7xxx_reg_print.c_shipped
++$(obj)/aic79xx_core.o: $(obj)/aic79xx_reg.h
  
- int raw3270_register_notifier(void (*notifier)(int, int))
- {
-diff --git a/drivers/s390/char/sclp.h b/drivers/s390/char/sclp.h
-index c7318a1..aa8186d 100644
---- a/drivers/s390/char/sclp.h
-+++ b/drivers/s390/char/sclp.h
-@@ -56,8 +56,6 @@ typedef unsigned int sclp_cmdw_t;
- #define SCLP_CMDW_READ_EVENT_DATA	0x00770005
- #define SCLP_CMDW_WRITE_EVENT_DATA	0x00760005
- #define SCLP_CMDW_WRITE_EVENT_MASK	0x00780005
--#define SCLP_CMDW_READ_SCP_INFO		0x00020001
--#define SCLP_CMDW_READ_SCP_INFO_FORCED	0x00120001
+-$(addprefix $(obj)/,$(aic7xxx-y)): $(obj)/aic7xxx_reg.h
+-$(addprefix $(obj)/,$(aic79xx-y)): $(obj)/aic79xx_reg.h
++$(addprefix $(obj)/,$(aic7xxx-y)): $(obj)/aic7xxx_seq.h
++$(addprefix $(obj)/,$(aic79xx-y)): $(obj)/aic79xx_seq.h
  
- #define GDS_ID_MDSMU		0x1310
- #define GDS_ID_MDSROUTEINFO	0x1311
-@@ -83,6 +81,8 @@ extern u64 sclp_facilities;
+-aic7xxx-gen-$(CONFIG_AIC7XXX_BUILD_FIRMWARE)	:= $(obj)/aic7xxx_seq.h \
+-						   $(obj)/aic7xxx_reg.h
++aic7xxx-gen-$(CONFIG_AIC7XXX_BUILD_FIRMWARE)	:= $(obj)/aic7xxx_reg.h
+ aic7xxx-gen-$(CONFIG_AIC7XXX_REG_PRETTY_PRINT)	+= $(obj)/aic7xxx_reg_print.c
  
- #define SCLP_HAS_CHP_INFO	(sclp_facilities & 0x8000000000000000ULL)
- #define SCLP_HAS_CHP_RECONFIG	(sclp_facilities & 0x2000000000000000ULL)
-+#define SCLP_HAS_CPU_INFO	(sclp_facilities & 0x0800000000000000ULL)
-+#define SCLP_HAS_CPU_RECONFIG	(sclp_facilities & 0x0400000000000000ULL)
+ aicasm-7xxx-opts-$(CONFIG_AIC7XXX_REG_PRETTY_PRINT) := \
+ 	-p $(obj)/aic7xxx_reg_print.c -i aic7xxx_osm.h
  
- struct gds_subvector {
- 	u8	length;
-diff --git a/drivers/s390/char/sclp_chp.c b/drivers/s390/char/sclp_chp.c
-deleted file mode 100644
-index c68f5e7..0000000
---- a/drivers/s390/char/sclp_chp.c
-+++ /dev/null
-@@ -1,200 +0,0 @@
--/*
-- *  drivers/s390/char/sclp_chp.c
-- *
-- *    Copyright IBM Corp. 2007
-- *    Author(s): Peter Oberparleiter <peter.oberparleiter at de.ibm.com>
-- */
--
--#include <linux/types.h>
--#include <linux/gfp.h>
--#include <linux/errno.h>
--#include <linux/completion.h>
--#include <asm/sclp.h>
--#include <asm/chpid.h>
--
--#include "sclp.h"
--
--#define TAG	"sclp_chp: "
--
--#define SCLP_CMDW_CONFIGURE_CHANNEL_PATH	0x000f0001
--#define SCLP_CMDW_DECONFIGURE_CHANNEL_PATH	0x000e0001
--#define SCLP_CMDW_READ_CHANNEL_PATH_INFORMATION	0x00030001
--
--static inline sclp_cmdw_t get_configure_cmdw(struct chp_id chpid)
--{
--	return SCLP_CMDW_CONFIGURE_CHANNEL_PATH | chpid.id << 8;
--}
--
--static inline sclp_cmdw_t get_deconfigure_cmdw(struct chp_id chpid)
--{
--	return SCLP_CMDW_DECONFIGURE_CHANNEL_PATH | chpid.id << 8;
--}
--
--static void chp_callback(struct sclp_req *req, void *data)
--{
--	struct completion *completion = data;
--
--	complete(completion);
--}
--
--struct chp_cfg_sccb {
--	struct sccb_header header;
--	u8 ccm;
--	u8 reserved[6];
--	u8 cssid;
--} __attribute__((packed));
--
--struct chp_cfg_data {
--	struct chp_cfg_sccb sccb;
--	struct sclp_req req;
--	struct completion completion;
--} __attribute__((packed));
--
--static int do_configure(sclp_cmdw_t cmd)
--{
--	struct chp_cfg_data *data;
--	int rc;
--
--	if (!SCLP_HAS_CHP_RECONFIG)
--		return -EOPNOTSUPP;
--	/* Prepare sccb. */
--	data = (struct chp_cfg_data *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
--	if (!data)
--		return -ENOMEM;
--	data->sccb.header.length = sizeof(struct chp_cfg_sccb);
--	data->req.command = cmd;
--	data->req.sccb = &(data->sccb);
--	data->req.status = SCLP_REQ_FILLED;
--	data->req.callback = chp_callback;
--	data->req.callback_data = &(data->completion);
--	init_completion(&data->completion);
--
--	/* Perform sclp request. */
--	rc = sclp_add_request(&(data->req));
--	if (rc)
--		goto out;
--	wait_for_completion(&data->completion);
--
--	/* Check response .*/
--	if (data->req.status != SCLP_REQ_DONE) {
--		printk(KERN_WARNING TAG "configure channel-path request failed "
--		       "(status=0x%02x)\n", data->req.status);
--		rc = -EIO;
--		goto out;
--	}
--	switch (data->sccb.header.response_code) {
--	case 0x0020:
--	case 0x0120:
--	case 0x0440:
--	case 0x0450:
--		break;
--	default:
--		printk(KERN_WARNING TAG "configure channel-path failed "
--		       "(cmd=0x%08x, response=0x%04x)\n", cmd,
--		       data->sccb.header.response_code);
--		rc = -EIO;
--		break;
--	}
--out:
--	free_page((unsigned long) data);
--
--	return rc;
--}
--
--/**
-- * sclp_chp_configure - perform configure channel-path sclp command
-- * @chpid: channel-path ID
-- *
-- * Perform configure channel-path command sclp command for specified chpid.
-- * Return 0 after command successfully finished, non-zero otherwise.
-- */
--int sclp_chp_configure(struct chp_id chpid)
--{
--	return do_configure(get_configure_cmdw(chpid));
--}
--
--/**
-- * sclp_chp_deconfigure - perform deconfigure channel-path sclp command
-- * @chpid: channel-path ID
-- *
-- * Perform deconfigure channel-path command sclp command for specified chpid
-- * and wait for completion. On success return 0. Return non-zero otherwise.
-- */
--int sclp_chp_deconfigure(struct chp_id chpid)
--{
--	return do_configure(get_deconfigure_cmdw(chpid));
--}
--
--struct chp_info_sccb {
--	struct sccb_header header;
--	u8 recognized[SCLP_CHP_INFO_MASK_SIZE];
--	u8 standby[SCLP_CHP_INFO_MASK_SIZE];
--	u8 configured[SCLP_CHP_INFO_MASK_SIZE];
--	u8 ccm;
--	u8 reserved[6];
--	u8 cssid;
--} __attribute__((packed));
--
--struct chp_info_data {
--	struct chp_info_sccb sccb;
--	struct sclp_req req;
--	struct completion completion;
--} __attribute__((packed));
--
--/**
-- * sclp_chp_read_info - perform read channel-path information sclp command
-- * @info: resulting channel-path information data
-- *
-- * Perform read channel-path information sclp command and wait for completion.
-- * On success, store channel-path information in @info and return 0. Return
-- * non-zero otherwise.
-- */
--int sclp_chp_read_info(struct sclp_chp_info *info)
--{
--	struct chp_info_data *data;
--	int rc;
--
--	if (!SCLP_HAS_CHP_INFO)
--		return -EOPNOTSUPP;
--	/* Prepare sccb. */
--	data = (struct chp_info_data *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
--	if (!data)
--		return -ENOMEM;
--	data->sccb.header.length = sizeof(struct chp_info_sccb);
--	data->req.command = SCLP_CMDW_READ_CHANNEL_PATH_INFORMATION;
--	data->req.sccb = &(data->sccb);
--	data->req.status = SCLP_REQ_FILLED;
--	data->req.callback = chp_callback;
--	data->req.callback_data = &(data->completion);
--	init_completion(&data->completion);
--
--	/* Perform sclp request. */
--	rc = sclp_add_request(&(data->req));
--	if (rc)
--		goto out;
--	wait_for_completion(&data->completion);
--
--	/* Check response .*/
--	if (data->req.status != SCLP_REQ_DONE) {
--		printk(KERN_WARNING TAG "read channel-path info request failed "
--		       "(status=0x%02x)\n", data->req.status);
--		rc = -EIO;
--		goto out;
--	}
--	if (data->sccb.header.response_code != 0x0010) {
--		printk(KERN_WARNING TAG "read channel-path info failed "
--		       "(response=0x%04x)\n", data->sccb.header.response_code);
--		rc = -EIO;
--		goto out;
--	}
--	memcpy(info->recognized, data->sccb.recognized,
--	       SCLP_CHP_INFO_MASK_SIZE);
--	memcpy(info->standby, data->sccb.standby,
--	       SCLP_CHP_INFO_MASK_SIZE);
--	memcpy(info->configured, data->sccb.configured,
--	       SCLP_CHP_INFO_MASK_SIZE);
--out:
--	free_page((unsigned long) data);
--
--	return rc;
--}
-diff --git a/drivers/s390/char/sclp_cmd.c b/drivers/s390/char/sclp_cmd.c
-new file mode 100644
-index 0000000..b5c2339
---- /dev/null
-+++ b/drivers/s390/char/sclp_cmd.c
-@@ -0,0 +1,398 @@
-+/*
-+ *  drivers/s390/char/sclp_cmd.c
-+ *
-+ *    Copyright IBM Corp. 2007
-+ *    Author(s): Heiko Carstens <heiko.carstens at de.ibm.com>,
-+ *		 Peter Oberparleiter <peter.oberparleiter at de.ibm.com>
-+ */
-+
-+#include <linux/completion.h>
-+#include <linux/init.h>
-+#include <linux/errno.h>
-+#include <linux/slab.h>
-+#include <linux/string.h>
-+#include <asm/chpid.h>
-+#include <asm/sclp.h>
-+#include "sclp.h"
-+
-+#define TAG	"sclp_cmd: "
-+
-+#define SCLP_CMDW_READ_SCP_INFO		0x00020001
-+#define SCLP_CMDW_READ_SCP_INFO_FORCED	0x00120001
-+
-+struct read_info_sccb {
-+	struct	sccb_header header;	/* 0-7 */
-+	u16	rnmax;			/* 8-9 */
-+	u8	rnsize;			/* 10 */
-+	u8	_reserved0[24 - 11];	/* 11-15 */
-+	u8	loadparm[8];		/* 24-31 */
-+	u8	_reserved1[48 - 32];	/* 32-47 */
-+	u64	facilities;		/* 48-55 */
-+	u8	_reserved2[84 - 56];	/* 56-83 */
-+	u8	fac84;			/* 84 */
-+	u8	_reserved3[91 - 85];	/* 85-90 */
-+	u8	flags;			/* 91 */
-+	u8	_reserved4[100 - 92];	/* 92-99 */
-+	u32	rnsize2;		/* 100-103 */
-+	u64	rnmax2;			/* 104-111 */
-+	u8	_reserved5[4096 - 112];	/* 112-4095 */
-+} __attribute__((packed, aligned(PAGE_SIZE)));
-+
-+static struct read_info_sccb __initdata early_read_info_sccb;
-+static int __initdata early_read_info_sccb_valid;
-+
-+u64 sclp_facilities;
-+static u8 sclp_fac84;
-+
-+static int __init sclp_cmd_sync_early(sclp_cmdw_t cmd, void *sccb)
-+{
-+	int rc;
-+
-+	__ctl_set_bit(0, 9);
-+	rc = sclp_service_call(cmd, sccb);
-+	if (rc)
-+		goto out;
-+	__load_psw_mask(PSW_BASE_BITS | PSW_MASK_EXT |
-+			PSW_MASK_WAIT | PSW_DEFAULT_KEY);
-+	local_irq_disable();
-+out:
-+	/* Contents of the sccb might have changed. */
-+	barrier();
-+	__ctl_clear_bit(0, 9);
-+	return rc;
-+}
-+
-+void __init sclp_read_info_early(void)
-+{
-+	int rc;
-+	int i;
-+	struct read_info_sccb *sccb;
-+	sclp_cmdw_t commands[] = {SCLP_CMDW_READ_SCP_INFO_FORCED,
-+				  SCLP_CMDW_READ_SCP_INFO};
-+
-+	sccb = &early_read_info_sccb;
-+	for (i = 0; i < ARRAY_SIZE(commands); i++) {
-+		do {
-+			memset(sccb, 0, sizeof(*sccb));
-+			sccb->header.length = sizeof(*sccb);
-+			sccb->header.control_mask[2] = 0x80;
-+			rc = sclp_cmd_sync_early(commands[i], sccb);
-+		} while (rc == -EBUSY);
-+
-+		if (rc)
-+			break;
-+		if (sccb->header.response_code == 0x10) {
-+			early_read_info_sccb_valid = 1;
-+			break;
-+		}
-+		if (sccb->header.response_code != 0x1f0)
-+			break;
-+	}
-+}
+ ifeq ($(CONFIG_AIC7XXX_BUILD_FIRMWARE),y)
+-# Create a dependency chain in generated files
+-# to avoid concurrent invocations of the single
+-# rule that builds them all.
+-aic7xxx_seq.h: aic7xxx_reg.h
+-ifeq ($(CONFIG_AIC7XXX_REG_PRETTY_PRINT),y)
+-aic7xxx_reg.h: aic7xxx_reg_print.c
+-endif
+-$(aic7xxx-gen-y): $(src)/aic7xxx.seq $(src)/aic7xxx.reg $(obj)/aicasm/aicasm
++$(obj)/aic7xxx_seq.h: $(src)/aic7xxx.seq $(src)/aic7xxx.reg $(obj)/aicasm/aicasm
+ 	$(obj)/aicasm/aicasm -I$(src) -r $(obj)/aic7xxx_reg.h \
+ 			      $(aicasm-7xxx-opts-y) -o $(obj)/aic7xxx_seq.h \
+ 			      $(src)/aic7xxx.seq
 +
-+void __init sclp_facilities_detect(void)
-+{
-+	if (!early_read_info_sccb_valid)
-+		return;
-+	sclp_facilities = early_read_info_sccb.facilities;
-+	sclp_fac84 = early_read_info_sccb.fac84;
-+}
++$(aic7xxx-gen-y): $(obj)/aic7xxx_seq.h
++else
++$(obj)/aic7xxx_reg_print.c: $(src)/aic7xxx_reg_print.c_shipped
+ endif
+ 
+-aic79xx-gen-$(CONFIG_AIC79XX_BUILD_FIRMWARE)	:= $(obj)/aic79xx_seq.h \
+-						   $(obj)/aic79xx_reg.h
++aic79xx-gen-$(CONFIG_AIC79XX_BUILD_FIRMWARE)	:= $(obj)/aic79xx_reg.h
+ aic79xx-gen-$(CONFIG_AIC79XX_REG_PRETTY_PRINT)	+= $(obj)/aic79xx_reg_print.c
+ 
+ aicasm-79xx-opts-$(CONFIG_AIC79XX_REG_PRETTY_PRINT) := \
+ 	-p $(obj)/aic79xx_reg_print.c -i aic79xx_osm.h
+ 
+ ifeq ($(CONFIG_AIC79XX_BUILD_FIRMWARE),y)
+-# Create a dependency chain in generated files
+-# to avoid concurrent invocations of the single
+-# rule that builds them all.
+-aic79xx_seq.h: aic79xx_reg.h
+-ifeq ($(CONFIG_AIC79XX_REG_PRETTY_PRINT),y)
+-aic79xx_reg.h: aic79xx_reg_print.c
+-endif
+-$(aic79xx-gen-y): $(src)/aic79xx.seq $(src)/aic79xx.reg $(obj)/aicasm/aicasm
++$(obj)/aic79xx_seq.h: $(src)/aic79xx.seq $(src)/aic79xx.reg $(obj)/aicasm/aicasm
+ 	$(obj)/aicasm/aicasm -I$(src) -r $(obj)/aic79xx_reg.h \
+ 			      $(aicasm-79xx-opts-y) -o $(obj)/aic79xx_seq.h \
+ 			      $(src)/aic79xx.seq
 +
-+unsigned long long __init sclp_memory_detect(void)
-+{
-+	unsigned long long memsize;
-+	struct read_info_sccb *sccb;
++$(aic79xx-gen-y): $(obj)/aic79xx_seq.h
++else
++$(obj)/aic79xx_reg_print.c: $(src)/aic79xx_reg_print.c_shipped
+ endif
+ 
+ $(obj)/aicasm/aicasm: $(src)/aicasm/*.[chyl]
+diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c
+index 2d02040..0e4708f 100644
+--- a/drivers/scsi/aic7xxx/aic79xx_osm.c
++++ b/drivers/scsi/aic7xxx/aic79xx_osm.c
+@@ -1784,7 +1784,7 @@ ahd_linux_handle_scsi_status(struct ahd_softc *ahd,
+ 			if (scb->flags & SCB_SENSE) {
+ 				sense_size = min(sizeof(struct scsi_sense_data)
+ 					       - ahd_get_sense_residual(scb),
+-						 (u_long)sizeof(cmd->sense_buffer));
++						 (u_long)SCSI_SENSE_BUFFERSIZE);
+ 				sense_offset = 0;
+ 			} else {
+ 				/*
+@@ -1795,11 +1795,11 @@ ahd_linux_handle_scsi_status(struct ahd_softc *ahd,
+ 				    scb->sense_data;
+ 				sense_size = min_t(size_t,
+ 						scsi_4btoul(siu->sense_length),
+-						sizeof(cmd->sense_buffer));
++						SCSI_SENSE_BUFFERSIZE);
+ 				sense_offset = SIU_SENSE_OFFSET(siu);
+ 			}
+ 
+-			memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer));
++			memset(cmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
+ 			memcpy(cmd->sense_buffer,
+ 			       ahd_get_sense_buf(ahd, scb)
+ 			       + sense_offset, sense_size);
+diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c
+index 390b0fc..e310e41 100644
+--- a/drivers/scsi/aic7xxx/aic7xxx_osm.c
++++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c
+@@ -1801,12 +1801,12 @@ ahc_linux_handle_scsi_status(struct ahc_softc *ahc,
+ 
+ 			sense_size = min(sizeof(struct scsi_sense_data)
+ 				       - ahc_get_sense_residual(scb),
+-					 (u_long)sizeof(cmd->sense_buffer));
++					 (u_long)SCSI_SENSE_BUFFERSIZE);
+ 			memcpy(cmd->sense_buffer,
+ 			       ahc_get_sense_buf(ahc, scb), sense_size);
+-			if (sense_size < sizeof(cmd->sense_buffer))
++			if (sense_size < SCSI_SENSE_BUFFERSIZE)
+ 				memset(&cmd->sense_buffer[sense_size], 0,
+-				       sizeof(cmd->sense_buffer) - sense_size);
++				       SCSI_SENSE_BUFFERSIZE - sense_size);
+ 			cmd->result |= (DRIVER_SENSE << 24);
+ #ifdef AHC_DEBUG
+ 			if (ahc_debug & AHC_SHOW_SENSE) {
+diff --git a/drivers/scsi/aic7xxx_old.c b/drivers/scsi/aic7xxx_old.c
+index 8f8db5f..bcb0b87 100644
+--- a/drivers/scsi/aic7xxx_old.c
++++ b/drivers/scsi/aic7xxx_old.c
+@@ -2696,7 +2696,7 @@ aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
+   {
+     pci_unmap_single(p->pdev,
+                      le32_to_cpu(scb->sg_list[0].address),
+-                     sizeof(cmd->sense_buffer),
++                     SCSI_SENSE_BUFFERSIZE,
+                      PCI_DMA_FROMDEVICE);
+   }
+   if (scb->flags & SCB_RECOVERY_SCB)
+@@ -4267,13 +4267,13 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
+                        sizeof(generic_sense));
+ 
+                 scb->sense_cmd[1] = (cmd->device->lun << 5);
+-                scb->sense_cmd[4] = sizeof(cmd->sense_buffer);
++                scb->sense_cmd[4] = SCSI_SENSE_BUFFERSIZE;
+ 
+                 scb->sg_list[0].length = 
+-                  cpu_to_le32(sizeof(cmd->sense_buffer));
++                  cpu_to_le32(SCSI_SENSE_BUFFERSIZE);
+ 		scb->sg_list[0].address =
+                         cpu_to_le32(pci_map_single(p->pdev, cmd->sense_buffer,
+-                                                   sizeof(cmd->sense_buffer),
++                                                   SCSI_SENSE_BUFFERSIZE,
+                                                    PCI_DMA_FROMDEVICE));
+ 
+                 /*
+@@ -4296,7 +4296,7 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
+                 hscb->residual_data_count[2] = 0;
+ 
+                 scb->sg_count = hscb->SG_segment_count = 1;
+-                scb->sg_length = sizeof(cmd->sense_buffer);
++                scb->sg_length = SCSI_SENSE_BUFFERSIZE;
+                 scb->tag_action = 0;
+                 scb->flags |= SCB_SENSE;
+                 /*
+@@ -10293,7 +10293,6 @@ static int aic7xxx_queue(struct scsi_cmnd *cmd, void (*fn)(struct scsi_cmnd *))
+   aic7xxx_position(cmd) = scb->hscb->tag;
+   cmd->scsi_done = fn;
+   cmd->result = DID_OK;
+-  memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer));
+   aic7xxx_error(cmd) = DID_OK;
+   aic7xxx_status(cmd) = 0;
+   cmd->host_scribble = NULL;
+diff --git a/drivers/scsi/aic94xx/aic94xx_dev.c b/drivers/scsi/aic94xx/aic94xx_dev.c
+index 3dce618..72042ca 100644
+--- a/drivers/scsi/aic94xx/aic94xx_dev.c
++++ b/drivers/scsi/aic94xx/aic94xx_dev.c
+@@ -165,7 +165,7 @@ static int asd_init_target_ddb(struct domain_device *dev)
+ 	if (dev->port->oob_mode != SATA_OOB_MODE) {
+ 		flags |= OPEN_REQUIRED;
+ 		if ((dev->dev_type == SATA_DEV) ||
+-		    (dev->tproto & SAS_PROTO_STP)) {
++		    (dev->tproto & SAS_PROTOCOL_STP)) {
+ 			struct smp_resp *rps_resp = &dev->sata_dev.rps_resp;
+ 			if (rps_resp->frame_type == SMP_RESPONSE &&
+ 			    rps_resp->function == SMP_REPORT_PHY_SATA &&
+@@ -193,7 +193,7 @@ static int asd_init_target_ddb(struct domain_device *dev)
+ 	asd_ddbsite_write_byte(asd_ha, ddb, DDB_TARG_FLAGS, flags);
+ 
+ 	flags = 0;
+-	if (dev->tproto & SAS_PROTO_STP)
++	if (dev->tproto & SAS_PROTOCOL_STP)
+ 		flags |= STP_CL_POL_NO_TX;
+ 	asd_ddbsite_write_byte(asd_ha, ddb, DDB_TARG_FLAGS2, flags);
+ 
+@@ -201,7 +201,7 @@ static int asd_init_target_ddb(struct domain_device *dev)
+ 	asd_ddbsite_write_word(asd_ha, ddb, SEND_QUEUE_TAIL, 0xFFFF);
+ 	asd_ddbsite_write_word(asd_ha, ddb, SISTER_DDB, 0xFFFF);
+ 
+-	if (dev->dev_type == SATA_DEV || (dev->tproto & SAS_PROTO_STP)) {
++	if (dev->dev_type == SATA_DEV || (dev->tproto & SAS_PROTOCOL_STP)) {
+ 		i = asd_init_sata(dev);
+ 		if (i < 0) {
+ 			asd_free_ddb(asd_ha, ddb);
+diff --git a/drivers/scsi/aic94xx/aic94xx_dump.c b/drivers/scsi/aic94xx/aic94xx_dump.c
+index 6bd8e30..3d8c4ff 100644
+--- a/drivers/scsi/aic94xx/aic94xx_dump.c
++++ b/drivers/scsi/aic94xx/aic94xx_dump.c
+@@ -903,11 +903,11 @@ void asd_dump_frame_rcvd(struct asd_phy *phy,
+ 	int i;
+ 
+ 	switch ((dl->status_block[1] & 0x70) >> 3) {
+-	case SAS_PROTO_STP:
++	case SAS_PROTOCOL_STP:
+ 		ASD_DPRINTK("STP proto device-to-host FIS:\n");
+ 		break;
+ 	default:
+-	case SAS_PROTO_SSP:
++	case SAS_PROTOCOL_SSP:
+ 		ASD_DPRINTK("SAS proto IDENTIFY:\n");
+ 		break;
+ 	}
+diff --git a/drivers/scsi/aic94xx/aic94xx_hwi.c b/drivers/scsi/aic94xx/aic94xx_hwi.c
+index 0cd7eed..098b5f3 100644
+--- a/drivers/scsi/aic94xx/aic94xx_hwi.c
++++ b/drivers/scsi/aic94xx/aic94xx_hwi.c
+@@ -91,7 +91,7 @@ static int asd_init_phy(struct asd_phy *phy)
+ 
+ 	sas_phy->enabled = 1;
+ 	sas_phy->class = SAS;
+-	sas_phy->iproto = SAS_PROTO_ALL;
++	sas_phy->iproto = SAS_PROTOCOL_ALL;
+ 	sas_phy->tproto = 0;
+ 	sas_phy->type = PHY_TYPE_PHYSICAL;
+ 	sas_phy->role = PHY_ROLE_INITIATOR;
+diff --git a/drivers/scsi/aic94xx/aic94xx_hwi.h b/drivers/scsi/aic94xx/aic94xx_hwi.h
+index 491e5d8..150f670 100644
+--- a/drivers/scsi/aic94xx/aic94xx_hwi.h
++++ b/drivers/scsi/aic94xx/aic94xx_hwi.h
+@@ -72,6 +72,7 @@ struct flash_struct {
+ 	u8     manuf;
+ 	u8     dev_id;
+ 	u8     sec_prot;
++	u8     method;
+ 
+ 	u32    dir_offs;
+ };
+@@ -216,6 +217,8 @@ struct asd_ha_struct {
+ 	struct dma_pool  *scb_pool;
+ 
+ 	struct asd_seq_data  seq; /* sequencer related */
++	u32    bios_status;
++	const struct firmware *bios_image;
+ };
+ 
+ /* ---------- Common macros ---------- */
+diff --git a/drivers/scsi/aic94xx/aic94xx_init.c b/drivers/scsi/aic94xx/aic94xx_init.c
+index b70d6e7..5d761eb 100644
+--- a/drivers/scsi/aic94xx/aic94xx_init.c
++++ b/drivers/scsi/aic94xx/aic94xx_init.c
+@@ -29,6 +29,7 @@
+ #include <linux/kernel.h>
+ #include <linux/pci.h>
+ #include <linux/delay.h>
++#include <linux/firmware.h>
+ 
+ #include <scsi/scsi_host.h>
+ 
+@@ -36,6 +37,7 @@
+ #include "aic94xx_reg.h"
+ #include "aic94xx_hwi.h"
+ #include "aic94xx_seq.h"
++#include "aic94xx_sds.h"
+ 
+ /* The format is "version.release.patchlevel" */
+ #define ASD_DRIVER_VERSION "1.0.3"
+@@ -134,7 +136,7 @@ Err:
+ 	return err;
+ }
+ 
+-static void __devexit asd_unmap_memio(struct asd_ha_struct *asd_ha)
++static void asd_unmap_memio(struct asd_ha_struct *asd_ha)
+ {
+ 	struct asd_ha_addrspace *io_handle;
+ 
+@@ -171,7 +173,7 @@ static int __devinit asd_map_ioport(struct asd_ha_struct *asd_ha)
+ 	return err;
+ }
+ 
+-static void __devexit asd_unmap_ioport(struct asd_ha_struct *asd_ha)
++static void asd_unmap_ioport(struct asd_ha_struct *asd_ha)
+ {
+ 	pci_release_region(asd_ha->pcidev, PCI_IOBAR_OFFSET);
+ }
+@@ -208,7 +210,7 @@ Err:
+ 	return err;
+ }
+ 
+-static void __devexit asd_unmap_ha(struct asd_ha_struct *asd_ha)
++static void asd_unmap_ha(struct asd_ha_struct *asd_ha)
+ {
+ 	if (asd_ha->iospace)
+ 		asd_unmap_ioport(asd_ha);
+@@ -313,6 +315,181 @@ static ssize_t asd_show_dev_pcba_sn(struct device *dev,
+ }
+ static DEVICE_ATTR(pcba_sn, S_IRUGO, asd_show_dev_pcba_sn, NULL);
+ 
++#define FLASH_CMD_NONE      0x00
++#define FLASH_CMD_UPDATE    0x01
++#define FLASH_CMD_VERIFY    0x02
 +
-+	if (!early_read_info_sccb_valid)
-+		return 0;
-+	sccb = &early_read_info_sccb;
-+	if (sccb->rnsize)
-+		memsize = sccb->rnsize << 20;
-+	else
-+		memsize = sccb->rnsize2 << 20;
-+	if (sccb->rnmax)
-+		memsize *= sccb->rnmax;
-+	else
-+		memsize *= sccb->rnmax2;
-+	return memsize;
-+}
++struct flash_command {
++     u8      command[8];
++     int     code;
++};
 +
-+/*
-+ * This function will be called after sclp_memory_detect(), which gets called
-+ * early from early.c code. Therefore the sccb should have valid contents.
-+ */
-+void __init sclp_get_ipl_info(struct sclp_ipl_info *info)
++static struct flash_command flash_command_table[] =
 +{
-+	struct read_info_sccb *sccb;
++     {"verify",      FLASH_CMD_VERIFY},
++     {"update",      FLASH_CMD_UPDATE},
++     {"",            FLASH_CMD_NONE}      /* Last entry should be NULL. */
++};
 +
-+	if (!early_read_info_sccb_valid)
-+		return;
-+	sccb = &early_read_info_sccb;
-+	info->is_valid = 1;
-+	if (sccb->flags & 0x2)
-+		info->has_dump = 1;
-+	memcpy(&info->loadparm, &sccb->loadparm, LOADPARM_LEN);
-+}
++struct error_bios {
++     char    *reason;
++     int     err_code;
++};
 +
-+static void sclp_sync_callback(struct sclp_req *req, void *data)
++static struct error_bios flash_error_table[] =
 +{
-+	struct completion *completion = data;
-+
-+	complete(completion);
-+}
++     {"Failed to open bios image file",      FAIL_OPEN_BIOS_FILE},
++     {"PCI ID mismatch",                     FAIL_CHECK_PCI_ID},
++     {"Checksum mismatch",                   FAIL_CHECK_SUM},
++     {"Unknown Error",                       FAIL_UNKNOWN},
++     {"Failed to verify.",                   FAIL_VERIFY},
++     {"Failed to reset flash chip.",         FAIL_RESET_FLASH},
++     {"Failed to find flash chip type.",     FAIL_FIND_FLASH_ID},
++     {"Failed to erash flash chip.",         FAIL_ERASE_FLASH},
++     {"Failed to program flash chip.",       FAIL_WRITE_FLASH},
++     {"Flash in progress",                   FLASH_IN_PROGRESS},
++     {"Image file size Error",               FAIL_FILE_SIZE},
++     {"Input parameter error",               FAIL_PARAMETERS},
++     {"Out of memory",                       FAIL_OUT_MEMORY},
++     {"OK", 0}	/* Last entry err_code = 0. */
++};
 +
-+static int do_sync_request(sclp_cmdw_t cmd, void *sccb)
++static ssize_t asd_store_update_bios(struct device *dev,
++	struct device_attribute *attr,
++	const char *buf, size_t count)
 +{
-+	struct completion completion;
-+	struct sclp_req *request;
-+	int rc;
++	struct asd_ha_struct *asd_ha = dev_to_asd_ha(dev);
++	char *cmd_ptr, *filename_ptr;
++	struct bios_file_header header, *hdr_ptr;
++	int res, i;
++	u32 csum = 0;
++	int flash_command = FLASH_CMD_NONE;
++	int err = 0;
 +
-+	request = kzalloc(sizeof(*request), GFP_KERNEL);
-+	if (!request)
-+		return -ENOMEM;
-+	request->command = cmd;
-+	request->sccb = sccb;
-+	request->status = SCLP_REQ_FILLED;
-+	request->callback = sclp_sync_callback;
-+	request->callback_data = &completion;
-+	init_completion(&completion);
++	cmd_ptr = kzalloc(count*2, GFP_KERNEL);
 +
-+	/* Perform sclp request. */
-+	rc = sclp_add_request(request);
-+	if (rc)
++	if (!cmd_ptr) {
++		err = FAIL_OUT_MEMORY;
 +		goto out;
-+	wait_for_completion(&completion);
-+
-+	/* Check response. */
-+	if (request->status != SCLP_REQ_DONE) {
-+		printk(KERN_WARNING TAG "sync request failed "
-+		       "(cmd=0x%08x, status=0x%02x)\n", cmd, request->status);
-+		rc = -EIO;
 +	}
-+out:
-+	kfree(request);
-+	return rc;
-+}
 +
-+/*
-+ * CPU configuration related functions.
-+ */
-+
-+#define SCLP_CMDW_READ_CPU_INFO		0x00010001
-+#define SCLP_CMDW_CONFIGURE_CPU		0x00110001
-+#define SCLP_CMDW_DECONFIGURE_CPU	0x00100001
++	filename_ptr = cmd_ptr + count;
++	res = sscanf(buf, "%s %s", cmd_ptr, filename_ptr);
++	if (res != 2) {
++		err = FAIL_PARAMETERS;
++		goto out1;
++	}
 +
-+struct read_cpu_info_sccb {
-+	struct	sccb_header header;
-+	u16	nr_configured;
-+	u16	offset_configured;
-+	u16	nr_standby;
-+	u16	offset_standby;
-+	u8	reserved[4096 - 16];
-+} __attribute__((packed, aligned(PAGE_SIZE)));
++	for (i = 0; flash_command_table[i].code != FLASH_CMD_NONE; i++) {
++		if (!memcmp(flash_command_table[i].command,
++				 cmd_ptr, strlen(cmd_ptr))) {
++			flash_command = flash_command_table[i].code;
++			break;
++		}
++	}
++	if (flash_command == FLASH_CMD_NONE) {
++		err = FAIL_PARAMETERS;
++		goto out1;
++	}
 +
-+static void sclp_fill_cpu_info(struct sclp_cpu_info *info,
-+			       struct read_cpu_info_sccb *sccb)
-+{
-+	char *page = (char *) sccb;
++	if (asd_ha->bios_status == FLASH_IN_PROGRESS) {
++		err = FLASH_IN_PROGRESS;
++		goto out1;
++	}
++	err = request_firmware(&asd_ha->bios_image,
++				   filename_ptr,
++				   &asd_ha->pcidev->dev);
++	if (err) {
++		asd_printk("Failed to load bios image file %s, error %d\n",
++			   filename_ptr, err);
++		err = FAIL_OPEN_BIOS_FILE;
++		goto out1;
++	}
 +
-+	memset(info, 0, sizeof(*info));
-+	info->configured = sccb->nr_configured;
-+	info->standby = sccb->nr_standby;
-+	info->combined = sccb->nr_configured + sccb->nr_standby;
-+	info->has_cpu_type = sclp_fac84 & 0x1;
-+	memcpy(&info->cpu, page + sccb->offset_configured,
-+	       info->combined * sizeof(struct sclp_cpu_entry));
-+}
++	hdr_ptr = (struct bios_file_header *)asd_ha->bios_image->data;
 +
-+int sclp_get_cpu_info(struct sclp_cpu_info *info)
-+{
-+	int rc;
-+	struct read_cpu_info_sccb *sccb;
++	if ((hdr_ptr->contrl_id.vendor != asd_ha->pcidev->vendor ||
++		hdr_ptr->contrl_id.device != asd_ha->pcidev->device) &&
++		(hdr_ptr->contrl_id.sub_vendor != asd_ha->pcidev->vendor ||
++		hdr_ptr->contrl_id.sub_device != asd_ha->pcidev->device)) {
 +
-+	if (!SCLP_HAS_CPU_INFO)
-+		return -EOPNOTSUPP;
-+	sccb = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
-+	if (!sccb)
-+		return -ENOMEM;
-+	sccb->header.length = sizeof(*sccb);
-+	rc = do_sync_request(SCLP_CMDW_READ_CPU_INFO, sccb);
-+	if (rc)
-+		goto out;
-+	if (sccb->header.response_code != 0x0010) {
-+		printk(KERN_WARNING TAG "readcpuinfo failed "
-+		       "(response=0x%04x)\n", sccb->header.response_code);
-+		rc = -EIO;
-+		goto out;
++		ASD_DPRINTK("The PCI vendor or device id does not match\n");
++		ASD_DPRINTK("vendor=%x dev=%x sub_vendor=%x sub_dev=%x"
++		" pci vendor=%x pci dev=%x\n",
++		hdr_ptr->contrl_id.vendor,
++		hdr_ptr->contrl_id.device,
++		hdr_ptr->contrl_id.sub_vendor,
++		hdr_ptr->contrl_id.sub_device,
++		asd_ha->pcidev->vendor,
++		asd_ha->pcidev->device);
++		err = FAIL_CHECK_PCI_ID;
++		goto out2;
 +	}
-+	sclp_fill_cpu_info(info, sccb);
-+out:
-+	free_page((unsigned long) sccb);
-+	return rc;
-+}
 +
-+struct cpu_configure_sccb {
-+	struct sccb_header header;
-+} __attribute__((packed, aligned(8)));
++	if (hdr_ptr->filelen != asd_ha->bios_image->size) {
++		err = FAIL_FILE_SIZE;
++		goto out2;
++	}
 +
-+static int do_cpu_configure(sclp_cmdw_t cmd)
-+{
-+	struct cpu_configure_sccb *sccb;
-+	int rc;
++	/* calculate checksum */
++	for (i = 0; i < hdr_ptr->filelen; i++)
++		csum += asd_ha->bios_image->data[i];
 +
-+	if (!SCLP_HAS_CPU_RECONFIG)
-+		return -EOPNOTSUPP;
-+	/*
-+	 * This is not going to cross a page boundary since we force
-+	 * kmalloc to have a minimum alignment of 8 bytes on s390.
-+	 */
-+	sccb = kzalloc(sizeof(*sccb), GFP_KERNEL | GFP_DMA);
-+	if (!sccb)
-+		return -ENOMEM;
-+	sccb->header.length = sizeof(*sccb);
-+	rc = do_sync_request(cmd, sccb);
-+	if (rc)
-+		goto out;
-+	switch (sccb->header.response_code) {
-+	case 0x0020:
-+	case 0x0120:
-+		break;
-+	default:
-+		printk(KERN_WARNING TAG "configure cpu failed (cmd=0x%08x, "
-+		       "response=0x%04x)\n", cmd, sccb->header.response_code);
-+		rc = -EIO;
-+		break;
++	if ((csum & 0x0000ffff) != hdr_ptr->checksum) {
++		ASD_DPRINTK("BIOS file checksum mismatch\n");
++		err = FAIL_CHECK_SUM;
++		goto out2;
++	}
++	if (flash_command == FLASH_CMD_UPDATE) {
++		asd_ha->bios_status = FLASH_IN_PROGRESS;
++		err = asd_write_flash_seg(asd_ha,
++			&asd_ha->bios_image->data[sizeof(*hdr_ptr)],
++			0, hdr_ptr->filelen-sizeof(*hdr_ptr));
++		if (!err)
++			err = asd_verify_flash_seg(asd_ha,
++				&asd_ha->bios_image->data[sizeof(*hdr_ptr)],
++				0, hdr_ptr->filelen-sizeof(*hdr_ptr));
++	} else {
++		asd_ha->bios_status = FLASH_IN_PROGRESS;
++		err = asd_verify_flash_seg(asd_ha,
++			&asd_ha->bios_image->data[sizeof(header)],
++			0, hdr_ptr->filelen-sizeof(header));
 +	}
-+out:
-+	kfree(sccb);
-+	return rc;
-+}
 +
-+int sclp_cpu_configure(u8 cpu)
-+{
-+	return do_cpu_configure(SCLP_CMDW_CONFIGURE_CPU | cpu << 8);
-+}
++out2:
++	release_firmware(asd_ha->bios_image);
++out1:
++	kfree(cmd_ptr);
++out:
++	asd_ha->bios_status = err;
 +
-+int sclp_cpu_deconfigure(u8 cpu)
-+{
-+	return do_cpu_configure(SCLP_CMDW_DECONFIGURE_CPU | cpu << 8);
++	if (!err)
++		return count;
++	else
++		return -err;
 +}
 +
-+/*
-+ * Channel path configuration related functions.
-+ */
-+
-+#define SCLP_CMDW_CONFIGURE_CHPATH		0x000f0001
-+#define SCLP_CMDW_DECONFIGURE_CHPATH		0x000e0001
-+#define SCLP_CMDW_READ_CHPATH_INFORMATION	0x00030001
-+
-+struct chp_cfg_sccb {
-+	struct sccb_header header;
-+	u8 ccm;
-+	u8 reserved[6];
-+	u8 cssid;
-+} __attribute__((packed));
-+
-+static int do_chp_configure(sclp_cmdw_t cmd)
++static ssize_t asd_show_update_bios(struct device *dev,
++				    struct device_attribute *attr, char *buf)
 +{
-+	struct chp_cfg_sccb *sccb;
-+	int rc;
++	int i;
++	struct asd_ha_struct *asd_ha = dev_to_asd_ha(dev);
 +
-+	if (!SCLP_HAS_CHP_RECONFIG)
-+		return -EOPNOTSUPP;
-+	/* Prepare sccb. */
-+	sccb = (struct chp_cfg_sccb *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
-+	if (!sccb)
-+		return -ENOMEM;
-+	sccb->header.length = sizeof(*sccb);
-+	rc = do_sync_request(cmd, sccb);
-+	if (rc)
-+		goto out;
-+	switch (sccb->header.response_code) {
-+	case 0x0020:
-+	case 0x0120:
-+	case 0x0440:
-+	case 0x0450:
-+		break;
-+	default:
-+		printk(KERN_WARNING TAG "configure channel-path failed "
-+		       "(cmd=0x%08x, response=0x%04x)\n", cmd,
-+		       sccb->header.response_code);
-+		rc = -EIO;
-+		break;
++	for (i = 0; flash_error_table[i].err_code != 0; i++) {
++		if (flash_error_table[i].err_code == asd_ha->bios_status)
++			break;
 +	}
-+out:
-+	free_page((unsigned long) sccb);
-+	return rc;
-+}
-+
-+/**
-+ * sclp_chp_configure - perform configure channel-path sclp command
-+ * @chpid: channel-path ID
-+ *
-+ * Perform configure channel-path command sclp command for specified chpid.
-+ * Return 0 after command successfully finished, non-zero otherwise.
-+ */
-+int sclp_chp_configure(struct chp_id chpid)
-+{
-+	return do_chp_configure(SCLP_CMDW_CONFIGURE_CHPATH | chpid.id << 8);
-+}
++	if (asd_ha->bios_status != FLASH_IN_PROGRESS)
++		asd_ha->bios_status = FLASH_OK;
 +
-+/**
-+ * sclp_chp_deconfigure - perform deconfigure channel-path sclp command
-+ * @chpid: channel-path ID
-+ *
-+ * Perform deconfigure channel-path command sclp command for specified chpid
-+ * and wait for completion. On success return 0. Return non-zero otherwise.
-+ */
-+int sclp_chp_deconfigure(struct chp_id chpid)
-+{
-+	return do_chp_configure(SCLP_CMDW_DECONFIGURE_CHPATH | chpid.id << 8);
++	return snprintf(buf, PAGE_SIZE, "status=%x %s\n",
++			flash_error_table[i].err_code,
++			flash_error_table[i].reason);
 +}
 +
-+struct chp_info_sccb {
-+	struct sccb_header header;
-+	u8 recognized[SCLP_CHP_INFO_MASK_SIZE];
-+	u8 standby[SCLP_CHP_INFO_MASK_SIZE];
-+	u8 configured[SCLP_CHP_INFO_MASK_SIZE];
-+	u8 ccm;
-+	u8 reserved[6];
-+	u8 cssid;
-+} __attribute__((packed));
-+
-+/**
-+ * sclp_chp_read_info - perform read channel-path information sclp command
-+ * @info: resulting channel-path information data
-+ *
-+ * Perform read channel-path information sclp command and wait for completion.
-+ * On success, store channel-path information in @info and return 0. Return
-+ * non-zero otherwise.
-+ */
-+int sclp_chp_read_info(struct sclp_chp_info *info)
-+{
-+	struct chp_info_sccb *sccb;
-+	int rc;
++static DEVICE_ATTR(update_bios, S_IRUGO|S_IWUGO,
++	asd_show_update_bios, asd_store_update_bios);
 +
-+	if (!SCLP_HAS_CHP_INFO)
-+		return -EOPNOTSUPP;
-+	/* Prepare sccb. */
-+	sccb = (struct chp_info_sccb *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
-+	if (!sccb)
-+		return -ENOMEM;
-+	sccb->header.length = sizeof(*sccb);
-+	rc = do_sync_request(SCLP_CMDW_READ_CHPATH_INFORMATION, sccb);
-+	if (rc)
-+		goto out;
-+	if (sccb->header.response_code != 0x0010) {
-+		printk(KERN_WARNING TAG "read channel-path info failed "
-+		       "(response=0x%04x)\n", sccb->header.response_code);
-+		rc = -EIO;
-+		goto out;
-+	}
-+	memcpy(info->recognized, sccb->recognized, SCLP_CHP_INFO_MASK_SIZE);
-+	memcpy(info->standby, sccb->standby, SCLP_CHP_INFO_MASK_SIZE);
-+	memcpy(info->configured, sccb->configured, SCLP_CHP_INFO_MASK_SIZE);
-+out:
-+	free_page((unsigned long) sccb);
-+	return rc;
-+}
-diff --git a/drivers/s390/char/sclp_config.c b/drivers/s390/char/sclp_config.c
-index 5322e5e..9dc77f1 100644
---- a/drivers/s390/char/sclp_config.c
-+++ b/drivers/s390/char/sclp_config.c
-@@ -29,12 +29,12 @@ static void sclp_cpu_capability_notify(struct work_struct *work)
- 	struct sys_device *sysdev;
+ static int asd_create_dev_attrs(struct asd_ha_struct *asd_ha)
+ {
+ 	int err;
+@@ -328,9 +505,14 @@ static int asd_create_dev_attrs(struct asd_ha_struct *asd_ha)
+ 	err = device_create_file(&asd_ha->pcidev->dev, &dev_attr_pcba_sn);
+ 	if (err)
+ 		goto err_biosb;
++	err = device_create_file(&asd_ha->pcidev->dev, &dev_attr_update_bios);
++	if (err)
++		goto err_update_bios;
  
- 	printk(KERN_WARNING TAG "cpu capability changed.\n");
--	lock_cpu_hotplug();
-+	get_online_cpus();
- 	for_each_online_cpu(cpu) {
- 		sysdev = get_cpu_sysdev(cpu);
- 		kobject_uevent(&sysdev->kobj, KOBJ_CHANGE);
- 	}
--	unlock_cpu_hotplug();
-+	put_online_cpus();
+ 	return 0;
+ 
++err_update_bios:
++	device_remove_file(&asd_ha->pcidev->dev, &dev_attr_pcba_sn);
+ err_biosb:
+ 	device_remove_file(&asd_ha->pcidev->dev, &dev_attr_bios_build);
+ err_rev:
+@@ -343,6 +525,7 @@ static void asd_remove_dev_attrs(struct asd_ha_struct *asd_ha)
+ 	device_remove_file(&asd_ha->pcidev->dev, &dev_attr_revision);
+ 	device_remove_file(&asd_ha->pcidev->dev, &dev_attr_bios_build);
+ 	device_remove_file(&asd_ha->pcidev->dev, &dev_attr_pcba_sn);
++	device_remove_file(&asd_ha->pcidev->dev, &dev_attr_update_bios);
  }
  
- static void sclp_conf_receiver_fn(struct evbuf_header *evbuf)
-diff --git a/drivers/s390/char/sclp_cpi.c b/drivers/s390/char/sclp_cpi.c
-index 82a13d9..5716487 100644
---- a/drivers/s390/char/sclp_cpi.c
-+++ b/drivers/s390/char/sclp_cpi.c
-@@ -1,255 +1,41 @@
- /*
-- * Author: Martin Peschke <mpeschke at de.ibm.com>
-- * Copyright (C) 2001 IBM Entwicklung GmbH, IBM Corporation
-+ *  drivers/s390/char/sclp_cpi.c
-+ *    SCLP control programm identification
-  *
-- * SCLP Control-Program Identification.
-+ *    Copyright IBM Corp. 2001, 2007
-+ *    Author(s): Martin Peschke <mpeschke at de.ibm.com>
-+ *		 Michael Ernst <mernst at de.ibm.com>
-  */
+ /* The first entry, 0, is used for dynamic ids, the rest for devices
+@@ -589,6 +772,7 @@ static int __devinit asd_pci_probe(struct pci_dev *dev,
+ 	asd_ha->sas_ha.dev = &asd_ha->pcidev->dev;
+ 	asd_ha->sas_ha.lldd_ha = asd_ha;
  
--#include <linux/version.h>
- #include <linux/kmod.h>
- #include <linux/module.h>
- #include <linux/moduleparam.h>
--#include <linux/init.h>
--#include <linux/timer.h>
--#include <linux/string.h>
--#include <linux/err.h>
--#include <linux/slab.h>
--#include <asm/ebcdic.h>
--#include <asm/semaphore.h>
--
--#include "sclp.h"
--#include "sclp_rw.h"
--
--#define CPI_LENGTH_SYSTEM_TYPE	8
--#define CPI_LENGTH_SYSTEM_NAME	8
--#define CPI_LENGTH_SYSPLEX_NAME	8
--
--struct cpi_evbuf {
--	struct evbuf_header header;
--	u8	id_format;
--	u8	reserved0;
--	u8	system_type[CPI_LENGTH_SYSTEM_TYPE];
--	u64	reserved1;
--	u8	system_name[CPI_LENGTH_SYSTEM_NAME];
--	u64	reserved2;
--	u64	system_level;
--	u64	reserved3;
--	u8	sysplex_name[CPI_LENGTH_SYSPLEX_NAME];
--	u8	reserved4[16];
--} __attribute__((packed));
--
--struct cpi_sccb {
--	struct sccb_header header;
--	struct cpi_evbuf cpi_evbuf;
--} __attribute__((packed));
--
--/* Event type structure for write message and write priority message */
--static struct sclp_register sclp_cpi_event =
--{
--	.send_mask = EVTYP_CTLPROGIDENT_MASK
--};
-+#include <linux/version.h>
-+#include "sclp_cpi_sys.h"
++	asd_ha->bios_status = FLASH_OK;
+ 	asd_ha->name = asd_dev->name;
+ 	asd_printk("found %s, device %s\n", asd_ha->name, pci_name(dev));
  
- MODULE_LICENSE("GPL");
-+MODULE_DESCRIPTION("Identify this operating system instance "
-+		   "to the System z hardware");
-+MODULE_AUTHOR("Martin Peschke <mpeschke at de.ibm.com>, "
-+	      "Michael Ernst <mernst at de.ibm.com>");
+diff --git a/drivers/scsi/aic94xx/aic94xx_scb.c b/drivers/scsi/aic94xx/aic94xx_scb.c
+index db6ab1a..0febad4 100644
+--- a/drivers/scsi/aic94xx/aic94xx_scb.c
++++ b/drivers/scsi/aic94xx/aic94xx_scb.c
+@@ -788,12 +788,12 @@ void asd_build_control_phy(struct asd_ascb *ascb, int phy_id, u8 subfunc)
  
--MODULE_AUTHOR(
--	"Martin Peschke, IBM Deutschland Entwicklung GmbH "
--	"<mpeschke at de.ibm.com>");
--
--MODULE_DESCRIPTION(
--	"identify this operating system instance to the S/390 "
--	"or zSeries hardware");
-+static char *system_name = "";
-+static char *sysplex_name = "";
+ 		/* initiator port settings are in the hi nibble */
+ 		if (phy->sas_phy.role == PHY_ROLE_INITIATOR)
+-			control_phy->port_type = SAS_PROTO_ALL << 4;
++			control_phy->port_type = SAS_PROTOCOL_ALL << 4;
+ 		else if (phy->sas_phy.role == PHY_ROLE_TARGET)
+-			control_phy->port_type = SAS_PROTO_ALL;
++			control_phy->port_type = SAS_PROTOCOL_ALL;
+ 		else
+ 			control_phy->port_type =
+-				(SAS_PROTO_ALL << 4) | SAS_PROTO_ALL;
++				(SAS_PROTOCOL_ALL << 4) | SAS_PROTOCOL_ALL;
  
--static char *system_name = NULL;
- module_param(system_name, charp, 0);
- MODULE_PARM_DESC(system_name, "e.g. hostname - max. 8 characters");
--
--static char *sysplex_name = NULL;
--#ifdef ALLOW_SYSPLEX_NAME
- module_param(sysplex_name, charp, 0);
- MODULE_PARM_DESC(sysplex_name, "if applicable - max. 8 characters");
--#endif
--
--/* use default value for this field (as well as for system level) */
--static char *system_type = "LINUX";
+ 		/* link reset retries, this should be nominal */
+ 		control_phy->link_reset_retries = 10;
+diff --git a/drivers/scsi/aic94xx/aic94xx_sds.c b/drivers/scsi/aic94xx/aic94xx_sds.c
+index 06509bf..2a4c933 100644
+--- a/drivers/scsi/aic94xx/aic94xx_sds.c
++++ b/drivers/scsi/aic94xx/aic94xx_sds.c
+@@ -30,6 +30,7 @@
  
--static int
--cpi_check_parms(void)
-+static int __init cpi_module_init(void)
- {
--	/* reject if no system type specified */
--	if (!system_type) {
--		printk("cpi: bug: no system type specified\n");
--		return -EINVAL;
--	}
--
--	/* reject if system type larger than 8 characters */
--	if (strlen(system_type) > CPI_LENGTH_SYSTEM_NAME) {
--		printk("cpi: bug: system type has length of %li characters - "
--		       "only %i characters supported\n",
--		       strlen(system_type), CPI_LENGTH_SYSTEM_TYPE);
--		return -EINVAL;
--	}
--
--	/* reject if no system name specified */
--	if (!system_name) {
--		printk("cpi: no system name specified\n");
--		return -EINVAL;
--	}
--
--	/* reject if system name larger than 8 characters */
--	if (strlen(system_name) > CPI_LENGTH_SYSTEM_NAME) {
--		printk("cpi: system name has length of %li characters - "
--		       "only %i characters supported\n",
--		       strlen(system_name), CPI_LENGTH_SYSTEM_NAME);
--		return -EINVAL;
--	}
--
--	/* reject if specified sysplex name larger than 8 characters */
--	if (sysplex_name && strlen(sysplex_name) > CPI_LENGTH_SYSPLEX_NAME) {
--		printk("cpi: sysplex name has length of %li characters"
--		       " - only %i characters supported\n",
--		       strlen(sysplex_name), CPI_LENGTH_SYSPLEX_NAME);
--		return -EINVAL;
--	}
--	return 0;
-+	return sclp_cpi_set_data(system_name, sysplex_name, "LINUX",
-+				 LINUX_VERSION_CODE);
- }
+ #include "aic94xx.h"
+ #include "aic94xx_reg.h"
++#include "aic94xx_sds.h"
  
--static void
--cpi_callback(struct sclp_req *req, void *data)
--{
--	struct semaphore *sem;
--
--	sem = (struct semaphore *) data;
--	up(sem);
--}
--
--static struct sclp_req *
--cpi_prepare_req(void)
--{
--	struct sclp_req *req;
--	struct cpi_sccb *sccb;
--	struct cpi_evbuf *evb;
--
--	req = kmalloc(sizeof(struct sclp_req), GFP_KERNEL);
--	if (req == NULL)
--		return ERR_PTR(-ENOMEM);
--	sccb = (struct cpi_sccb *) __get_free_page(GFP_KERNEL | GFP_DMA);
--	if (sccb == NULL) {
--		kfree(req);
--		return ERR_PTR(-ENOMEM);
--	}
--	memset(sccb, 0, sizeof(struct cpi_sccb));
--
--	/* setup SCCB for Control-Program Identification */
--	sccb->header.length = sizeof(struct cpi_sccb);
--	sccb->cpi_evbuf.header.length = sizeof(struct cpi_evbuf);
--	sccb->cpi_evbuf.header.type = 0x0B;
--	evb = &sccb->cpi_evbuf;
--
--	/* set system type */
--	memset(evb->system_type, ' ', CPI_LENGTH_SYSTEM_TYPE);
--	memcpy(evb->system_type, system_type, strlen(system_type));
--	sclp_ascebc_str(evb->system_type, CPI_LENGTH_SYSTEM_TYPE);
--	EBC_TOUPPER(evb->system_type, CPI_LENGTH_SYSTEM_TYPE);
--
--	/* set system name */
--	memset(evb->system_name, ' ', CPI_LENGTH_SYSTEM_NAME);
--	memcpy(evb->system_name, system_name, strlen(system_name));
--	sclp_ascebc_str(evb->system_name, CPI_LENGTH_SYSTEM_NAME);
--	EBC_TOUPPER(evb->system_name, CPI_LENGTH_SYSTEM_NAME);
--
--	/* set system level */
--	evb->system_level = LINUX_VERSION_CODE;
--
--	/* set sysplex name */
--	if (sysplex_name) {
--		memset(evb->sysplex_name, ' ', CPI_LENGTH_SYSPLEX_NAME);
--		memcpy(evb->sysplex_name, sysplex_name, strlen(sysplex_name));
--		sclp_ascebc_str(evb->sysplex_name, CPI_LENGTH_SYSPLEX_NAME);
--		EBC_TOUPPER(evb->sysplex_name, CPI_LENGTH_SYSPLEX_NAME);
--	}
--
--	/* prepare request data structure presented to SCLP driver */
--	req->command = SCLP_CMDW_WRITE_EVENT_DATA;
--	req->sccb = sccb;
--	req->status = SCLP_REQ_FILLED;
--	req->callback = cpi_callback;
--	return req;
--}
--
--static void
--cpi_free_req(struct sclp_req *req)
--{
--	free_page((unsigned long) req->sccb);
--	kfree(req);
--}
--
--static int __init
--cpi_module_init(void)
--{
--	struct semaphore sem;
--	struct sclp_req *req;
--	int rc;
--
--	rc = cpi_check_parms();
--	if (rc)
--		return rc;
--
--	rc = sclp_register(&sclp_cpi_event);
--	if (rc) {
--		/* could not register sclp event. Die. */
--		printk(KERN_WARNING "cpi: could not register to hardware "
--		       "console.\n");
--		return -EINVAL;
--	}
--	if (!(sclp_cpi_event.sclp_send_mask & EVTYP_CTLPROGIDENT_MASK)) {
--		printk(KERN_WARNING "cpi: no control program identification "
--		       "support\n");
--		sclp_unregister(&sclp_cpi_event);
--		return -EOPNOTSUPP;
--	}
--
--	req = cpi_prepare_req();
--	if (IS_ERR(req)) {
--		printk(KERN_WARNING "cpi: couldn't allocate request\n");
--		sclp_unregister(&sclp_cpi_event);
--		return PTR_ERR(req);
--	}
--
--	/* Prepare semaphore */
--	sema_init(&sem, 0);
--	req->callback_data = &sem;
--	/* Add request to sclp queue */
--	rc = sclp_add_request(req);
--	if (rc) {
--		printk(KERN_WARNING "cpi: could not start request\n");
--		cpi_free_req(req);
--		sclp_unregister(&sclp_cpi_event);
--		return rc;
--	}
--	/* make "insmod" sleep until callback arrives */
--	down(&sem);
--
--	rc = ((struct cpi_sccb *) req->sccb)->header.response_code;
--	if (rc != 0x0020) {
--		printk(KERN_WARNING "cpi: failed with response code 0x%x\n",
--		       rc);
--		rc = -ECOMM;
--	} else
--		rc = 0;
--
--	cpi_free_req(req);
--	sclp_unregister(&sclp_cpi_event);
--
--	return rc;
--}
--
--
- static void __exit cpi_module_exit(void)
- {
- }
+ /* ---------- OCM stuff ---------- */
  
--
--/* declare driver module init/cleanup functions */
- module_init(cpi_module_init);
- module_exit(cpi_module_exit);
--
-diff --git a/drivers/s390/char/sclp_cpi_sys.c b/drivers/s390/char/sclp_cpi_sys.c
-new file mode 100644
-index 0000000..4161703
---- /dev/null
-+++ b/drivers/s390/char/sclp_cpi_sys.c
-@@ -0,0 +1,400 @@
-+/*
-+ *  drivers/s390/char/sclp_cpi_sys.c
-+ *    SCLP control program identification sysfs interface
-+ *
-+ *    Copyright IBM Corp. 2001, 2007
-+ *    Author(s): Martin Peschke <mpeschke at de.ibm.com>
-+ *		 Michael Ernst <mernst at de.ibm.com>
-+ */
+@@ -1083,3 +1084,391 @@ out:
+ 	kfree(flash_dir);
+ 	return err;
+ }
 +
-+#include <linux/kernel.h>
-+#include <linux/init.h>
-+#include <linux/stat.h>
-+#include <linux/device.h>
-+#include <linux/string.h>
-+#include <linux/ctype.h>
-+#include <linux/kmod.h>
-+#include <linux/timer.h>
-+#include <linux/err.h>
-+#include <linux/slab.h>
-+#include <linux/completion.h>
-+#include <asm/ebcdic.h>
-+#include <asm/sclp.h>
-+#include "sclp.h"
-+#include "sclp_rw.h"
-+#include "sclp_cpi_sys.h"
++/**
++ * asd_verify_flash_seg - verify data with flash memory
++ * @asd_ha: pointer to the host adapter structure
++ * @src: pointer to the source data to be verified
++ * @dest_offset: offset from flash memory
++ * @bytes_to_verify: total bytes to verify
++ */
++int asd_verify_flash_seg(struct asd_ha_struct *asd_ha,
++		void *src, u32 dest_offset, u32 bytes_to_verify)
++{
++	u8 *src_buf;
++	u8 flash_char;
++	int err;
++	u32 nv_offset, reg, i;
 +
-+#define CPI_LENGTH_NAME 8
-+#define CPI_LENGTH_LEVEL 16
++	reg = asd_ha->hw_prof.flash.bar;
++	src_buf = NULL;
 +
-+struct cpi_evbuf {
-+	struct evbuf_header header;
-+	u8	id_format;
-+	u8	reserved0;
-+	u8	system_type[CPI_LENGTH_NAME];
-+	u64	reserved1;
-+	u8	system_name[CPI_LENGTH_NAME];
-+	u64	reserved2;
-+	u64	system_level;
-+	u64	reserved3;
-+	u8	sysplex_name[CPI_LENGTH_NAME];
-+	u8	reserved4[16];
-+} __attribute__((packed));
++	err = FLASH_OK;
++	nv_offset = dest_offset;
++	src_buf = (u8 *)src;
++	for (i = 0; i < bytes_to_verify; i++) {
++		flash_char = asd_read_reg_byte(asd_ha, reg + nv_offset + i);
++		if (flash_char != src_buf[i]) {
++			err = FAIL_VERIFY;
++			break;
++		}
++	}
++	return err;
++}
 +
-+struct cpi_sccb {
-+	struct sccb_header header;
-+	struct cpi_evbuf cpi_evbuf;
-+} __attribute__((packed));
++/**
++ * asd_write_flash_seg - write data into flash memory
++ * @asd_ha: pointer to the host adapter structure
++ * @src: pointer to the source data to be written
++ * @dest_offset: offset from flash memory
++ * @bytes_to_write: total bytes to write
++ */
++int asd_write_flash_seg(struct asd_ha_struct *asd_ha,
++		void *src, u32 dest_offset, u32 bytes_to_write)
++{
++	u8 *src_buf;
++	u32 nv_offset, reg, i;
++	int err;
 +
-+static struct sclp_register sclp_cpi_event = {
-+	.send_mask = EVTYP_CTLPROGIDENT_MASK,
-+};
++	reg = asd_ha->hw_prof.flash.bar;
++	src_buf = NULL;
 +
-+static char system_name[CPI_LENGTH_NAME + 1];
-+static char sysplex_name[CPI_LENGTH_NAME + 1];
-+static char system_type[CPI_LENGTH_NAME + 1];
-+static u64 system_level;
++	err = asd_check_flash_type(asd_ha);
++	if (err) {
++		ASD_DPRINTK("couldn't find the type of flash. err=%d\n", err);
++		return err;
++	}
 +
-+static void set_data(char *field, char *data)
-+{
-+	memset(field, ' ', CPI_LENGTH_NAME);
-+	memcpy(field, data, strlen(data));
-+	sclp_ascebc_str(field, CPI_LENGTH_NAME);
-+}
++	nv_offset = dest_offset;
++	err = asd_erase_nv_sector(asd_ha, nv_offset, bytes_to_write);
++	if (err) {
++		ASD_DPRINTK("Erase failed at offset:0x%x\n",
++			nv_offset);
++		return err;
++	}
 +
-+static void cpi_callback(struct sclp_req *req, void *data)
-+{
-+	struct completion *completion = data;
++	err = asd_reset_flash(asd_ha);
++	if (err) {
++		ASD_DPRINTK("couldn't reset flash. err=%d\n", err);
++		return err;
++	}
 +
-+	complete(completion);
++	src_buf = (u8 *)src;
++	for (i = 0; i < bytes_to_write; i++) {
++		/* Setup program command sequence */
++		switch (asd_ha->hw_prof.flash.method) {
++		case FLASH_METHOD_A:
++		{
++			asd_write_reg_byte(asd_ha,
++					(reg + 0xAAA), 0xAA);
++			asd_write_reg_byte(asd_ha,
++					(reg + 0x555), 0x55);
++			asd_write_reg_byte(asd_ha,
++					(reg + 0xAAA), 0xA0);
++			asd_write_reg_byte(asd_ha,
++					(reg + nv_offset + i),
++					(*(src_buf + i)));
++			break;
++		}
++		case FLASH_METHOD_B:
++		{
++			asd_write_reg_byte(asd_ha,
++					(reg + 0x555), 0xAA);
++			asd_write_reg_byte(asd_ha,
++					(reg + 0x2AA), 0x55);
++			asd_write_reg_byte(asd_ha,
++					(reg + 0x555), 0xA0);
++			asd_write_reg_byte(asd_ha,
++					(reg + nv_offset + i),
++					(*(src_buf + i)));
++			break;
++		}
++		default:
++			break;
++		}
++		if (asd_chk_write_status(asd_ha,
++				(nv_offset + i), 0) != 0) {
++			ASD_DPRINTK("aicx: Write failed at offset:0x%x\n",
++				reg + nv_offset + i);
++			return FAIL_WRITE_FLASH;
++		}
++	}
++
++	err = asd_reset_flash(asd_ha);
++	if (err) {
++		ASD_DPRINTK("couldn't reset flash. err=%d\n", err);
++		return err;
++	}
++	return 0;
 +}
 +
-+static struct sclp_req *cpi_prepare_req(void)
++int asd_chk_write_status(struct asd_ha_struct *asd_ha,
++	 u32 sector_addr, u8 erase_flag)
 +{
-+	struct sclp_req *req;
-+	struct cpi_sccb *sccb;
-+	struct cpi_evbuf *evb;
-+
-+	req = kzalloc(sizeof(struct sclp_req), GFP_KERNEL);
-+	if (!req)
-+		return ERR_PTR(-ENOMEM);
-+	sccb = (struct cpi_sccb *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
-+	if (!sccb) {
-+		kfree(req);
-+		return ERR_PTR(-ENOMEM);
-+	}
++	u32 reg;
++	u32 loop_cnt;
++	u8  nv_data1, nv_data2;
++	u8  toggle_bit1;
 +
-+	/* setup SCCB for Control-Program Identification */
-+	sccb->header.length = sizeof(struct cpi_sccb);
-+	sccb->cpi_evbuf.header.length = sizeof(struct cpi_evbuf);
-+	sccb->cpi_evbuf.header.type = 0x0b;
-+	evb = &sccb->cpi_evbuf;
++	/*
++	 * Read from DQ2 requires sector address
++	 * while it's dont care for DQ6
++	 */
++	reg = asd_ha->hw_prof.flash.bar;
 +
-+	/* set system type */
-+	set_data(evb->system_type, system_type);
++	for (loop_cnt = 0; loop_cnt < 50000; loop_cnt++) {
++		nv_data1 = asd_read_reg_byte(asd_ha, reg);
++		nv_data2 = asd_read_reg_byte(asd_ha, reg);
 +
-+	/* set system name */
-+	set_data(evb->system_name, system_name);
++		toggle_bit1 = ((nv_data1 & FLASH_STATUS_BIT_MASK_DQ6)
++				 ^ (nv_data2 & FLASH_STATUS_BIT_MASK_DQ6));
 +
-+	/* set sytem level */
-+	evb->system_level = system_level;
++		if (toggle_bit1 == 0) {
++			return 0;
++		} else {
++			if (nv_data2 & FLASH_STATUS_BIT_MASK_DQ5) {
++				nv_data1 = asd_read_reg_byte(asd_ha,
++								reg);
++				nv_data2 = asd_read_reg_byte(asd_ha,
++								reg);
++				toggle_bit1 =
++				((nv_data1 & FLASH_STATUS_BIT_MASK_DQ6)
++				^ (nv_data2 & FLASH_STATUS_BIT_MASK_DQ6));
 +
-+	/* set sysplex name */
-+	set_data(evb->sysplex_name, sysplex_name);
++				if (toggle_bit1 == 0)
++					return 0;
++			}
++		}
 +
-+	/* prepare request data structure presented to SCLP driver */
-+	req->command = SCLP_CMDW_WRITE_EVENT_DATA;
-+	req->sccb = sccb;
-+	req->status = SCLP_REQ_FILLED;
-+	req->callback = cpi_callback;
-+	return req;
++		/*
++		 * ERASE is a sector-by-sector operation and requires
++		 * more time to finish while WRITE is byte-byte-byte
++		 * operation and takes lesser time to finish.
++		 *
++		 * For some strange reason a reduced ERASE delay gives different
++		 * behaviour across different spirit boards. Hence we set
++		 * a optimum balance of 50mus for ERASE which works well
++		 * across all boards.
++		 */
++		if (erase_flag) {
++			udelay(FLASH_STATUS_ERASE_DELAY_COUNT);
++		} else {
++			udelay(FLASH_STATUS_WRITE_DELAY_COUNT);
++		}
++	}
++	return -1;
 +}
 +
-+static void cpi_free_req(struct sclp_req *req)
++/**
++ * asd_hwi_erase_nv_sector - Erase the flash memory sectors.
++ * @asd_ha: pointer to the host adapter structure
++ * @flash_addr: pointer to offset from flash memory
++ * @size: total bytes to erase.
++ */
++int asd_erase_nv_sector(struct asd_ha_struct *asd_ha, u32 flash_addr, u32 size)
 +{
-+	free_page((unsigned long) req->sccb);
-+	kfree(req);
-+}
++	u32 reg;
++	u32 sector_addr;
 +
-+static int cpi_req(void)
-+{
-+	struct completion completion;
-+	struct sclp_req *req;
-+	int rc;
-+	int response;
++	reg = asd_ha->hw_prof.flash.bar;
 +
-+	rc = sclp_register(&sclp_cpi_event);
-+	if (rc) {
-+		printk(KERN_WARNING "cpi: could not register "
-+			"to hardware console.\n");
-+		goto out;
-+	}
-+	if (!(sclp_cpi_event.sclp_send_mask & EVTYP_CTLPROGIDENT_MASK)) {
-+		printk(KERN_WARNING "cpi: no control program "
-+			"identification support\n");
-+		rc = -EOPNOTSUPP;
-+		goto out_unregister;
-+	}
++	/* sector staring address */
++	sector_addr = flash_addr & FLASH_SECTOR_SIZE_MASK;
 +
-+	req = cpi_prepare_req();
-+	if (IS_ERR(req)) {
-+		printk(KERN_WARNING "cpi: could not allocate request\n");
-+		rc = PTR_ERR(req);
-+		goto out_unregister;
-+	}
++	/*
++	 * Erasing an flash sector needs to be done in six consecutive
++	 * write cyles.
++	 */
++	while (sector_addr < flash_addr+size) {
++		switch (asd_ha->hw_prof.flash.method) {
++		case FLASH_METHOD_A:
++			asd_write_reg_byte(asd_ha, (reg + 0xAAA), 0xAA);
++			asd_write_reg_byte(asd_ha, (reg + 0x555), 0x55);
++			asd_write_reg_byte(asd_ha, (reg + 0xAAA), 0x80);
++			asd_write_reg_byte(asd_ha, (reg + 0xAAA), 0xAA);
++			asd_write_reg_byte(asd_ha, (reg + 0x555), 0x55);
++			asd_write_reg_byte(asd_ha, (reg + sector_addr), 0x30);
++			break;
++		case FLASH_METHOD_B:
++			asd_write_reg_byte(asd_ha, (reg + 0x555), 0xAA);
++			asd_write_reg_byte(asd_ha, (reg + 0x2AA), 0x55);
++			asd_write_reg_byte(asd_ha, (reg + 0x555), 0x80);
++			asd_write_reg_byte(asd_ha, (reg + 0x555), 0xAA);
++			asd_write_reg_byte(asd_ha, (reg + 0x2AA), 0x55);
++			asd_write_reg_byte(asd_ha, (reg + sector_addr), 0x30);
++			break;
++		default:
++			break;
++		}
 +
-+	init_completion(&completion);
-+	req->callback_data = &completion;
++		if (asd_chk_write_status(asd_ha, sector_addr, 1) != 0)
++			return FAIL_ERASE_FLASH;
 +
-+	/* Add request to sclp queue */
-+	rc = sclp_add_request(req);
-+	if (rc) {
-+		printk(KERN_WARNING "cpi: could not start request\n");
-+		goto out_free_req;
++		sector_addr += FLASH_SECTOR_SIZE;
 +	}
 +
-+	wait_for_completion(&completion);
++	return 0;
++}
 +
-+	if (req->status != SCLP_REQ_DONE) {
-+		printk(KERN_WARNING "cpi: request failed (status=0x%02x)\n",
-+			req->status);
-+		rc = -EIO;
-+		goto out_free_req;
-+	}
++int asd_check_flash_type(struct asd_ha_struct *asd_ha)
++{
++	u8 manuf_id;
++	u8 dev_id;
++	u8 sec_prot;
++	u32 inc;
++	u32 reg;
++	int err;
 +
-+	response = ((struct cpi_sccb *) req->sccb)->header.response_code;
-+	if (response != 0x0020) {
-+		printk(KERN_WARNING "cpi: failed with "
-+			"response code 0x%x\n", response);
-+		rc = -EIO;
++	/* get Flash memory base address */
++	reg = asd_ha->hw_prof.flash.bar;
++
++	/* Determine flash info */
++	err = asd_reset_flash(asd_ha);
++	if (err) {
++		ASD_DPRINTK("couldn't reset flash. err=%d\n", err);
++		return err;
 +	}
 +
-+out_free_req:
-+	cpi_free_req(req);
++	asd_ha->hw_prof.flash.method = FLASH_METHOD_UNKNOWN;
++	asd_ha->hw_prof.flash.manuf = FLASH_MANUF_ID_UNKNOWN;
++	asd_ha->hw_prof.flash.dev_id = FLASH_DEV_ID_UNKNOWN;
 +
-+out_unregister:
-+	sclp_unregister(&sclp_cpi_event);
++	/* Get flash info. This would most likely be AMD Am29LV family flash.
++	 * First try the sequence for word mode.  It is the same as for
++	 * 008B (byte mode only), 160B (word mode) and 800D (word mode).
++	 */
++	inc = asd_ha->hw_prof.flash.wide ? 2 : 1;
++	asd_write_reg_byte(asd_ha, reg + 0xAAA, 0xAA);
++	asd_write_reg_byte(asd_ha, reg + 0x555, 0x55);
++	asd_write_reg_byte(asd_ha, reg + 0xAAA, 0x90);
++	manuf_id = asd_read_reg_byte(asd_ha, reg);
++	dev_id = asd_read_reg_byte(asd_ha, reg + inc);
++	sec_prot = asd_read_reg_byte(asd_ha, reg + inc + inc);
++	/* Get out of autoselect mode. */
++	err = asd_reset_flash(asd_ha);
++	if (err) {
++		ASD_DPRINTK("couldn't reset flash. err=%d\n", err);
++		return err;
++	}
++	ASD_DPRINTK("Flash MethodA manuf_id(0x%x) dev_id(0x%x) "
++		"sec_prot(0x%x)\n", manuf_id, dev_id, sec_prot);
++	err = asd_reset_flash(asd_ha);
++	if (err != 0)
++		return err;
 +
-+out:
-+	return rc;
-+}
++	switch (manuf_id) {
++	case FLASH_MANUF_ID_AMD:
++		switch (sec_prot) {
++		case FLASH_DEV_ID_AM29LV800DT:
++		case FLASH_DEV_ID_AM29LV640MT:
++		case FLASH_DEV_ID_AM29F800B:
++			asd_ha->hw_prof.flash.method = FLASH_METHOD_A;
++			break;
++		default:
++			break;
++		}
++		break;
++	case FLASH_MANUF_ID_ST:
++		switch (sec_prot) {
++		case FLASH_DEV_ID_STM29W800DT:
++		case FLASH_DEV_ID_STM29LV640:
++			asd_ha->hw_prof.flash.method = FLASH_METHOD_A;
++			break;
++		default:
++			break;
++		}
++		break;
++	case FLASH_MANUF_ID_FUJITSU:
++		switch (sec_prot) {
++		case FLASH_DEV_ID_MBM29LV800TE:
++		case FLASH_DEV_ID_MBM29DL800TA:
++			asd_ha->hw_prof.flash.method = FLASH_METHOD_A;
++			break;
++		}
++		break;
++	case FLASH_MANUF_ID_MACRONIX:
++		switch (sec_prot) {
++		case FLASH_DEV_ID_MX29LV800BT:
++			asd_ha->hw_prof.flash.method = FLASH_METHOD_A;
++			break;
++		}
++		break;
++	}
 +
-+static int check_string(const char *attr, const char *str)
-+{
-+	size_t len;
-+	size_t i;
++	if (asd_ha->hw_prof.flash.method == FLASH_METHOD_UNKNOWN) {
++		err = asd_reset_flash(asd_ha);
++		if (err) {
++			ASD_DPRINTK("couldn't reset flash. err=%d\n", err);
++			return err;
++		}
 +
-+	len = strlen(str);
++		/* Issue Unlock sequence for AM29LV008BT */
++		asd_write_reg_byte(asd_ha, (reg + 0x555), 0xAA);
++		asd_write_reg_byte(asd_ha, (reg + 0x2AA), 0x55);
++		asd_write_reg_byte(asd_ha, (reg + 0x555), 0x90);
++		manuf_id = asd_read_reg_byte(asd_ha, reg);
++		dev_id = asd_read_reg_byte(asd_ha, reg + inc);
++		sec_prot = asd_read_reg_byte(asd_ha, reg + inc + inc);
 +
-+	if ((len > 0) && (str[len - 1] == '\n'))
-+		len--;
++		ASD_DPRINTK("Flash MethodB manuf_id(0x%x) dev_id(0x%x) sec_prot"
++			"(0x%x)\n", manuf_id, dev_id, sec_prot);
 +
-+	if (len > CPI_LENGTH_NAME)
-+		return -EINVAL;
++		err = asd_reset_flash(asd_ha);
++		if (err != 0) {
++			ASD_DPRINTK("couldn't reset flash. err=%d\n", err);
++			return err;
++		}
 +
-+	for (i = 0; i < len ; i++) {
-+		if (isalpha(str[i]) || isdigit(str[i]) ||
-+		    strchr("$@# ", str[i]))
-+			continue;
-+		return -EINVAL;
++		switch (manuf_id) {
++		case FLASH_MANUF_ID_AMD:
++			switch (dev_id) {
++			case FLASH_DEV_ID_AM29LV008BT:
++				asd_ha->hw_prof.flash.method = FLASH_METHOD_B;
++				break;
++			default:
++				break;
++			}
++			break;
++		case FLASH_MANUF_ID_ST:
++			switch (dev_id) {
++			case FLASH_DEV_ID_STM29008:
++				asd_ha->hw_prof.flash.method = FLASH_METHOD_B;
++				break;
++			default:
++				break;
++			}
++			break;
++		case FLASH_MANUF_ID_FUJITSU:
++			switch (dev_id) {
++			case FLASH_DEV_ID_MBM29LV008TA:
++				asd_ha->hw_prof.flash.method = FLASH_METHOD_B;
++				break;
++			}
++			break;
++		case FLASH_MANUF_ID_INTEL:
++			switch (dev_id) {
++			case FLASH_DEV_ID_I28LV00TAT:
++				asd_ha->hw_prof.flash.method = FLASH_METHOD_B;
++				break;
++			}
++			break;
++		case FLASH_MANUF_ID_MACRONIX:
++			switch (dev_id) {
++			case FLASH_DEV_ID_I28LV00TAT:
++				asd_ha->hw_prof.flash.method = FLASH_METHOD_B;
++				break;
++			}
++			break;
++		default:
++			return FAIL_FIND_FLASH_ID;
++		}
 +	}
 +
++	if (asd_ha->hw_prof.flash.method == FLASH_METHOD_UNKNOWN)
++	      return FAIL_FIND_FLASH_ID;
++
++	asd_ha->hw_prof.flash.manuf = manuf_id;
++	asd_ha->hw_prof.flash.dev_id = dev_id;
++	asd_ha->hw_prof.flash.sec_prot = sec_prot;
 +	return 0;
 +}
+diff --git a/drivers/scsi/aic94xx/aic94xx_sds.h b/drivers/scsi/aic94xx/aic94xx_sds.h
+new file mode 100644
+index 0000000..bb9795a
+--- /dev/null
++++ b/drivers/scsi/aic94xx/aic94xx_sds.h
+@@ -0,0 +1,121 @@
++/*
++ * Aic94xx SAS/SATA driver hardware interface header file.
++ *
++ * Copyright (C) 2005 Adaptec, Inc.  All rights reserved.
++ * Copyright (C) 2005 Gilbert Wu <gilbert_wu at adaptec.com>
++ *
++ * This file is licensed under GPLv2.
++ *
++ * This file is part of the aic94xx driver.
++ *
++ * The aic94xx 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; version 2 of the
++ * License.
++ *
++ * The aic94xx 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 the aic94xx driver; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ *
++ */
++#ifndef _AIC94XX_SDS_H_
++#define _AIC94XX_SDS_H_
 +
-+static void set_string(char *attr, const char *value)
-+{
-+	size_t len;
-+	size_t i;
++enum {
++	FLASH_METHOD_UNKNOWN,
++	FLASH_METHOD_A,
++	FLASH_METHOD_B
++};
 +
-+	len = strlen(value);
++#define FLASH_MANUF_ID_AMD              0x01
++#define FLASH_MANUF_ID_ST               0x20
++#define FLASH_MANUF_ID_FUJITSU          0x04
++#define FLASH_MANUF_ID_MACRONIX         0xC2
++#define FLASH_MANUF_ID_INTEL            0x89
++#define FLASH_MANUF_ID_UNKNOWN          0xFF
 +
-+	if ((len > 0) && (value[len - 1] == '\n'))
-+		len--;
++#define FLASH_DEV_ID_AM29LV008BT        0x3E
++#define FLASH_DEV_ID_AM29LV800DT        0xDA
++#define FLASH_DEV_ID_STM29W800DT        0xD7
++#define FLASH_DEV_ID_STM29LV640         0xDE
++#define FLASH_DEV_ID_STM29008           0xEA
++#define FLASH_DEV_ID_MBM29LV800TE       0xDA
++#define FLASH_DEV_ID_MBM29DL800TA       0x4A
++#define FLASH_DEV_ID_MBM29LV008TA       0x3E
++#define FLASH_DEV_ID_AM29LV640MT        0x7E
++#define FLASH_DEV_ID_AM29F800B          0xD6
++#define FLASH_DEV_ID_MX29LV800BT        0xDA
++#define FLASH_DEV_ID_MX29LV008CT        0xDA
++#define FLASH_DEV_ID_I28LV00TAT         0x3E
++#define FLASH_DEV_ID_UNKNOWN            0xFF
 +
-+	for (i = 0; i < CPI_LENGTH_NAME; i++) {
-+		if (i < len)
-+			attr[i] = toupper(value[i]);
-+		else
-+			attr[i] = ' ';
-+	}
-+}
++/* status bit mask values */
++#define FLASH_STATUS_BIT_MASK_DQ6       0x40
++#define FLASH_STATUS_BIT_MASK_DQ5       0x20
++#define FLASH_STATUS_BIT_MASK_DQ2       0x04
 +
-+static ssize_t system_name_show(struct kobject *kobj,
-+				struct kobj_attribute *attr, char *page)
-+{
-+	return snprintf(page, PAGE_SIZE, "%s\n", system_name);
-+}
++/* minimum value in micro seconds needed for checking status */
++#define FLASH_STATUS_ERASE_DELAY_COUNT  50
++#define FLASH_STATUS_WRITE_DELAY_COUNT  25
 +
-+static ssize_t system_name_store(struct kobject *kobj,
-+				 struct kobj_attribute *attr,
-+				 const char *buf,
-+	size_t len)
-+{
-+	int rc;
++#define FLASH_SECTOR_SIZE               0x010000
++#define FLASH_SECTOR_SIZE_MASK          0xffff0000
 +
-+	rc = check_string("system_name", buf);
-+	if (rc)
-+		return rc;
++#define FLASH_OK                        0x000000
++#define FAIL_OPEN_BIOS_FILE             0x000100
++#define FAIL_CHECK_PCI_ID               0x000200
++#define FAIL_CHECK_SUM                  0x000300
++#define FAIL_UNKNOWN                    0x000400
++#define FAIL_VERIFY                     0x000500
++#define FAIL_RESET_FLASH                0x000600
++#define FAIL_FIND_FLASH_ID              0x000700
++#define FAIL_ERASE_FLASH                0x000800
++#define FAIL_WRITE_FLASH                0x000900
++#define FAIL_FILE_SIZE                  0x000a00
++#define FAIL_PARAMETERS                 0x000b00
++#define FAIL_OUT_MEMORY                 0x000c00
++#define FLASH_IN_PROGRESS               0x001000
 +
-+	set_string(system_name, buf);
++struct controller_id {
++	u32 vendor;     /* PCI Vendor ID */
++	u32 device;     /* PCI Device ID */
++	u32 sub_vendor; /* PCI Subvendor ID */
++	u32 sub_device; /* PCI Subdevice ID */
++};
 +
-+	return len;
-+}
++struct image_info {
++	u32 ImageId;       /* Identifies the image */
++	u32 ImageOffset;   /* Offset the beginning of the file */
++	u32 ImageLength;   /* length of the image */
++	u32 ImageChecksum; /* Image checksum */
++	u32 ImageVersion;  /* Version of the image, could be build number */
++};
 +
-+static struct kobj_attribute system_name_attr =
-+	__ATTR(system_name, 0644, system_name_show, system_name_store);
++struct bios_file_header {
++	u8 signature[32]; /* Signature/Cookie to identify the file */
++	u32 checksum;	  /*Entire file checksum with this field zero */
++	u32 antidote;	  /* Entire file checksum with this field 0xFFFFFFFF */
++	struct controller_id contrl_id; /*PCI id to identify the controller */
++	u32 filelen;      /*Length of the entire file*/
++	u32 chunk_num;	  /*The chunk/part number for multiple Image files */
++	u32 total_chunks; /*Total number of chunks/parts in the image file */
++	u32 num_images;   /* Number of images in the file */
++	u32 build_num;    /* Build number of this image */
++	struct image_info image_header;
++};
 +
-+static ssize_t sysplex_name_show(struct kobject *kobj,
-+				 struct kobj_attribute *attr, char *page)
-+{
-+	return snprintf(page, PAGE_SIZE, "%s\n", sysplex_name);
-+}
++int asd_verify_flash_seg(struct asd_ha_struct *asd_ha,
++		void *src, u32 dest_offset, u32 bytes_to_verify);
++int asd_write_flash_seg(struct asd_ha_struct *asd_ha,
++		void *src, u32 dest_offset, u32 bytes_to_write);
++int asd_chk_write_status(struct asd_ha_struct *asd_ha,
++		u32 sector_addr, u8 erase_flag);
++int asd_check_flash_type(struct asd_ha_struct *asd_ha);
++int asd_erase_nv_sector(struct asd_ha_struct *asd_ha,
++		u32 flash_addr, u32 size);
++#endif
+diff --git a/drivers/scsi/aic94xx/aic94xx_task.c b/drivers/scsi/aic94xx/aic94xx_task.c
+index ee0a98b..965d4bb 100644
+--- a/drivers/scsi/aic94xx/aic94xx_task.c
++++ b/drivers/scsi/aic94xx/aic94xx_task.c
+@@ -187,29 +187,13 @@ static void asd_get_response_tasklet(struct asd_ascb *ascb,
+ 	ts->buf_valid_size = 0;
+ 	edb = asd_ha->seq.edb_arr[edb_id + escb->edb_index];
+ 	r = edb->vaddr;
+-	if (task->task_proto == SAS_PROTO_SSP) {
++	if (task->task_proto == SAS_PROTOCOL_SSP) {
+ 		struct ssp_response_iu *iu =
+ 			r + 16 + sizeof(struct ssp_frame_hdr);
+ 
+ 		ts->residual = le32_to_cpu(*(__le32 *)r);
+-		ts->resp = SAS_TASK_COMPLETE;
+-		if (iu->datapres == 0)
+-			ts->stat = iu->status;
+-		else if (iu->datapres == 1)
+-			ts->stat = iu->resp_data[3];
+-		else if (iu->datapres == 2) {
+-			ts->stat = SAM_CHECK_COND;
+-			ts->buf_valid_size = min((u32) SAS_STATUS_BUF_SIZE,
+-					 be32_to_cpu(iu->sense_data_len));
+-			memcpy(ts->buf, iu->sense_data, ts->buf_valid_size);
+-			if (iu->status != SAM_CHECK_COND) {
+-				ASD_DPRINTK("device %llx sent sense data, but "
+-					    "stat(0x%x) is not CHECK_CONDITION"
+-					    "\n",
+-					    SAS_ADDR(task->dev->sas_addr),
+-					    iu->status);
+-			}
+-		}
 +
-+static ssize_t sysplex_name_store(struct kobject *kobj,
-+				  struct kobj_attribute *attr,
-+				  const char *buf,
-+	size_t len)
-+{
-+	int rc;
++		sas_ssp_task_response(&asd_ha->pcidev->dev, task, iu);
+ 	}  else {
+ 		struct ata_task_resp *resp = (void *) &ts->buf[0];
+ 
+@@ -341,14 +325,14 @@ Again:
+ 	}
+ 
+ 	switch (task->task_proto) {
+-	case SATA_PROTO:
+-	case SAS_PROTO_STP:
++	case SAS_PROTOCOL_SATA:
++	case SAS_PROTOCOL_STP:
+ 		asd_unbuild_ata_ascb(ascb);
+ 		break;
+-	case SAS_PROTO_SMP:
++	case SAS_PROTOCOL_SMP:
+ 		asd_unbuild_smp_ascb(ascb);
+ 		break;
+-	case SAS_PROTO_SSP:
++	case SAS_PROTOCOL_SSP:
+ 		asd_unbuild_ssp_ascb(ascb);
+ 	default:
+ 		break;
+@@ -586,17 +570,17 @@ int asd_execute_task(struct sas_task *task, const int num,
+ 	list_for_each_entry(a, &alist, list) {
+ 		t = a->uldd_task;
+ 		a->uldd_timer = 1;
+-		if (t->task_proto & SAS_PROTO_STP)
+-			t->task_proto = SAS_PROTO_STP;
++		if (t->task_proto & SAS_PROTOCOL_STP)
++			t->task_proto = SAS_PROTOCOL_STP;
+ 		switch (t->task_proto) {
+-		case SATA_PROTO:
+-		case SAS_PROTO_STP:
++		case SAS_PROTOCOL_SATA:
++		case SAS_PROTOCOL_STP:
+ 			res = asd_build_ata_ascb(a, t, gfp_flags);
+ 			break;
+-		case SAS_PROTO_SMP:
++		case SAS_PROTOCOL_SMP:
+ 			res = asd_build_smp_ascb(a, t, gfp_flags);
+ 			break;
+-		case SAS_PROTO_SSP:
++		case SAS_PROTOCOL_SSP:
+ 			res = asd_build_ssp_ascb(a, t, gfp_flags);
+ 			break;
+ 		default:
+@@ -633,14 +617,14 @@ out_err_unmap:
+ 			t->task_state_flags &= ~SAS_TASK_AT_INITIATOR;
+ 			spin_unlock_irqrestore(&t->task_state_lock, flags);
+ 			switch (t->task_proto) {
+-			case SATA_PROTO:
+-			case SAS_PROTO_STP:
++			case SAS_PROTOCOL_SATA:
++			case SAS_PROTOCOL_STP:
+ 				asd_unbuild_ata_ascb(a);
+ 				break;
+-			case SAS_PROTO_SMP:
++			case SAS_PROTOCOL_SMP:
+ 				asd_unbuild_smp_ascb(a);
+ 				break;
+-			case SAS_PROTO_SSP:
++			case SAS_PROTOCOL_SSP:
+ 				asd_unbuild_ssp_ascb(a);
+ 			default:
+ 				break;
+diff --git a/drivers/scsi/aic94xx/aic94xx_tmf.c b/drivers/scsi/aic94xx/aic94xx_tmf.c
+index c0d0b7d..87b2f6e 100644
+--- a/drivers/scsi/aic94xx/aic94xx_tmf.c
++++ b/drivers/scsi/aic94xx/aic94xx_tmf.c
+@@ -372,21 +372,21 @@ int asd_abort_task(struct sas_task *task)
+ 	scb->header.opcode = ABORT_TASK;
+ 
+ 	switch (task->task_proto) {
+-	case SATA_PROTO:
+-	case SAS_PROTO_STP:
++	case SAS_PROTOCOL_SATA:
++	case SAS_PROTOCOL_STP:
+ 		scb->abort_task.proto_conn_rate = (1 << 5); /* STP */
+ 		break;
+-	case SAS_PROTO_SSP:
++	case SAS_PROTOCOL_SSP:
+ 		scb->abort_task.proto_conn_rate  = (1 << 4); /* SSP */
+ 		scb->abort_task.proto_conn_rate |= task->dev->linkrate;
+ 		break;
+-	case SAS_PROTO_SMP:
++	case SAS_PROTOCOL_SMP:
+ 		break;
+ 	default:
+ 		break;
+ 	}
+ 
+-	if (task->task_proto == SAS_PROTO_SSP) {
++	if (task->task_proto == SAS_PROTOCOL_SSP) {
+ 		scb->abort_task.ssp_frame.frame_type = SSP_TASK;
+ 		memcpy(scb->abort_task.ssp_frame.hashed_dest_addr,
+ 		       task->dev->hashed_sas_addr, HASHED_SAS_ADDR_SIZE);
+@@ -512,7 +512,7 @@ static int asd_initiate_ssp_tmf(struct domain_device *dev, u8 *lun,
+ 	int res = 1;
+ 	struct scb *scb;
+ 
+-	if (!(dev->tproto & SAS_PROTO_SSP))
++	if (!(dev->tproto & SAS_PROTOCOL_SSP))
+ 		return TMF_RESP_FUNC_ESUPP;
+ 
+ 	ascb = asd_ascb_alloc_list(asd_ha, &res, GFP_KERNEL);
+diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c
+index d466a2d..d80dba9 100644
+--- a/drivers/scsi/arcmsr/arcmsr_hba.c
++++ b/drivers/scsi/arcmsr/arcmsr_hba.c
+@@ -634,9 +634,9 @@ static void arcmsr_report_sense_info(struct CommandControlBlock *ccb)
+ 	pcmd->result = DID_OK << 16;
+ 	if (sensebuffer) {
+ 		int sense_data_length =
+-			sizeof(struct SENSE_DATA) < sizeof(pcmd->sense_buffer)
+-			? sizeof(struct SENSE_DATA) : sizeof(pcmd->sense_buffer);
+-		memset(sensebuffer, 0, sizeof(pcmd->sense_buffer));
++			sizeof(struct SENSE_DATA) < SCSI_SENSE_BUFFERSIZE
++			? sizeof(struct SENSE_DATA) : SCSI_SENSE_BUFFERSIZE;
++		memset(sensebuffer, 0, SCSI_SENSE_BUFFERSIZE);
+ 		memcpy(sensebuffer, ccb->arcmsr_cdb.SenseData, sense_data_length);
+ 		sensebuffer->ErrorCode = SCSI_SENSE_CURRENT_ERRORS;
+ 		sensebuffer->Valid = 1;
+diff --git a/drivers/scsi/atari_NCR5380.c b/drivers/scsi/atari_NCR5380.c
+index a9680b5..93b61f1 100644
+--- a/drivers/scsi/atari_NCR5380.c
++++ b/drivers/scsi/atari_NCR5380.c
+@@ -511,9 +511,9 @@ static inline void initialize_SCp(Scsi_Cmnd *cmd)
+ 	 * various queues are valid.
+ 	 */
+ 
+-	if (cmd->use_sg) {
+-		cmd->SCp.buffer = (struct scatterlist *)cmd->request_buffer;
+-		cmd->SCp.buffers_residual = cmd->use_sg - 1;
++	if (scsi_bufflen(cmd)) {
++		cmd->SCp.buffer = scsi_sglist(cmd);
++		cmd->SCp.buffers_residual = scsi_sg_count(cmd) - 1;
+ 		cmd->SCp.ptr = sg_virt(cmd->SCp.buffer);
+ 		cmd->SCp.this_residual = cmd->SCp.buffer->length;
+ 		/* ++roman: Try to merge some scatter-buffers if they are at
+@@ -523,8 +523,8 @@ static inline void initialize_SCp(Scsi_Cmnd *cmd)
+ 	} else {
+ 		cmd->SCp.buffer = NULL;
+ 		cmd->SCp.buffers_residual = 0;
+-		cmd->SCp.ptr = (char *)cmd->request_buffer;
+-		cmd->SCp.this_residual = cmd->request_bufflen;
++		cmd->SCp.ptr = NULL;
++		cmd->SCp.this_residual = 0;
+ 	}
+ }
+ 
+@@ -936,21 +936,21 @@ static int NCR5380_queue_command(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
+ 	}
+ # endif
+ # ifdef NCR5380_STAT_LIMIT
+-	if (cmd->request_bufflen > NCR5380_STAT_LIMIT)
++	if (scsi_bufflen(cmd) > NCR5380_STAT_LIMIT)
+ # endif
+ 		switch (cmd->cmnd[0]) {
+ 		case WRITE:
+ 		case WRITE_6:
+ 		case WRITE_10:
+ 			hostdata->time_write[cmd->device->id] -= (jiffies - hostdata->timebase);
+-			hostdata->bytes_write[cmd->device->id] += cmd->request_bufflen;
++			hostdata->bytes_write[cmd->device->id] += scsi_bufflen(cmd);
+ 			hostdata->pendingw++;
+ 			break;
+ 		case READ:
+ 		case READ_6:
+ 		case READ_10:
+ 			hostdata->time_read[cmd->device->id] -= (jiffies - hostdata->timebase);
+-			hostdata->bytes_read[cmd->device->id] += cmd->request_bufflen;
++			hostdata->bytes_read[cmd->device->id] += scsi_bufflen(cmd);
+ 			hostdata->pendingr++;
+ 			break;
+ 		}
+@@ -1352,21 +1352,21 @@ static irqreturn_t NCR5380_intr(int irq, void *dev_id)
+ static void collect_stats(struct NCR5380_hostdata* hostdata, Scsi_Cmnd *cmd)
+ {
+ # ifdef NCR5380_STAT_LIMIT
+-	if (cmd->request_bufflen > NCR5380_STAT_LIMIT)
++	if (scsi_bufflen(cmd) > NCR5380_STAT_LIMIT)
+ # endif
+ 		switch (cmd->cmnd[0]) {
+ 		case WRITE:
+ 		case WRITE_6:
+ 		case WRITE_10:
+ 			hostdata->time_write[cmd->device->id] += (jiffies - hostdata->timebase);
+-			/*hostdata->bytes_write[cmd->device->id] += cmd->request_bufflen;*/
++			/*hostdata->bytes_write[cmd->device->id] += scsi_bufflen(cmd);*/
+ 			hostdata->pendingw--;
+ 			break;
+ 		case READ:
+ 		case READ_6:
+ 		case READ_10:
+ 			hostdata->time_read[cmd->device->id] += (jiffies - hostdata->timebase);
+-			/*hostdata->bytes_read[cmd->device->id] += cmd->request_bufflen;*/
++			/*hostdata->bytes_read[cmd->device->id] += scsi_bufflen(cmd);*/
+ 			hostdata->pendingr--;
+ 			break;
+ 		}
+@@ -1868,7 +1868,7 @@ static int do_abort(struct Scsi_Host *host)
+ 	 * the target sees, so we just handshake.
+ 	 */
+ 
+-	while (!(tmp = NCR5380_read(STATUS_REG)) & SR_REQ)
++	while (!((tmp = NCR5380_read(STATUS_REG)) & SR_REQ))
+ 		;
+ 
+ 	NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp));
+diff --git a/drivers/scsi/atp870u.c b/drivers/scsi/atp870u.c
+index fec58cc..db6de5e 100644
+--- a/drivers/scsi/atp870u.c
++++ b/drivers/scsi/atp870u.c
+@@ -471,18 +471,8 @@ go_42:
+ 			/*
+ 			 *	Complete the command
+ 			 */
+-			if (workreq->use_sg) {
+-				pci_unmap_sg(dev->pdev,
+-					(struct scatterlist *)workreq->request_buffer,
+-					workreq->use_sg,
+-					workreq->sc_data_direction);
+-			} else if (workreq->request_bufflen &&
+-					workreq->sc_data_direction != DMA_NONE) {
+-				pci_unmap_single(dev->pdev,
+-					workreq->SCp.dma_handle,
+-					workreq->request_bufflen,
+-					workreq->sc_data_direction);
+-			}			
++			scsi_dma_unmap(workreq);
++
+ 			spin_lock_irqsave(dev->host->host_lock, flags);
+ 			(*workreq->scsi_done) (workreq);
+ #ifdef ED_DBGP
+@@ -624,7 +614,7 @@ static int atp870u_queuecommand(struct scsi_cmnd * req_p,
+ 
+ 	c = scmd_channel(req_p);
+ 	req_p->sense_buffer[0]=0;
+-	req_p->resid = 0;
++	scsi_set_resid(req_p, 0);
+ 	if (scmd_channel(req_p) > 1) {
+ 		req_p->result = 0x00040000;
+ 		done(req_p);
+@@ -722,7 +712,6 @@ static void send_s870(struct atp_unit *dev,unsigned char c)
+ 	unsigned short int tmpcip, w;
+ 	unsigned long l, bttl = 0;
+ 	unsigned int workport;
+-	struct scatterlist *sgpnt;
+ 	unsigned long  sg_count;
+ 
+ 	if (dev->in_snd[c] != 0) {
+@@ -793,6 +782,8 @@ oktosend:
+ 	}
+ 	printk("\n");
+ #endif	
++	l = scsi_bufflen(workreq);
++
+ 	if (dev->dev_id == ATP885_DEVID) {
+ 		j = inb(dev->baseport + 0x29) & 0xfe;
+ 		outb(j, dev->baseport + 0x29);
+@@ -800,12 +791,11 @@ oktosend:
+ 	}
+ 	
+ 	if (workreq->cmnd[0] == READ_CAPACITY) {
+-		if (workreq->request_bufflen > 8) {
+-			workreq->request_bufflen = 0x08;
+-		}
++		if (l > 8)
++			l = 8;
+ 	}
+ 	if (workreq->cmnd[0] == 0x00) {
+-		workreq->request_bufflen = 0;
++		l = 0;
+ 	}
+ 
+ 	tmport = workport + 0x1b;
+@@ -852,40 +842,8 @@ oktosend:
+ #ifdef ED_DBGP	
+ 	printk("dev->id[%d][%d].devsp = %2x\n",c,target_id,dev->id[c][target_id].devsp);
+ #endif
+-	/*
+-	 *	Figure out the transfer size
+-	 */
+-	if (workreq->use_sg) {
+-#ifdef ED_DBGP
+-		printk("Using SGL\n");
+-#endif		
+-		l = 0;
+-		
+-		sgpnt = (struct scatterlist *) workreq->request_buffer;
+-		sg_count = pci_map_sg(dev->pdev, sgpnt, workreq->use_sg,
+-	   			workreq->sc_data_direction);		
+-		
+-		for (i = 0; i < workreq->use_sg; i++) {
+-			if (sgpnt[i].length == 0 || workreq->use_sg > ATP870U_SCATTER) {
+-				panic("Foooooooood fight!");
+-			}
+-			l += sgpnt[i].length;
+-		}
+-#ifdef ED_DBGP		
+-		printk( "send_s870: workreq->use_sg %d, sg_count %d l %8ld\n", workreq->use_sg, sg_count, l);
+-#endif
+-	} else if(workreq->request_bufflen && workreq->sc_data_direction != PCI_DMA_NONE) {
+-#ifdef ED_DBGP
+-		printk("Not using SGL\n");
+-#endif					
+-		workreq->SCp.dma_handle = pci_map_single(dev->pdev, workreq->request_buffer,
+-				workreq->request_bufflen,
+-				workreq->sc_data_direction);		
+-		l = workreq->request_bufflen;
+-#ifdef ED_DBGP		
+-		printk( "send_s870: workreq->use_sg %d, l %8ld\n", workreq->use_sg, l);
+-#endif
+-	} else l = 0;
++
++	sg_count = scsi_dma_map(workreq);
+ 	/*
+ 	 *	Write transfer size
+ 	 */
+@@ -938,16 +896,16 @@ oktosend:
+ 	 *	a linear chain.
+ 	 */
+ 
+-	if (workreq->use_sg) {
+-		sgpnt = (struct scatterlist *) workreq->request_buffer;
++	if (l) {
++		struct scatterlist *sgpnt;
+ 		i = 0;
+-		for (j = 0; j < workreq->use_sg; j++) {
+-			bttl = sg_dma_address(&sgpnt[j]);
+-			l=sg_dma_len(&sgpnt[j]);
++		scsi_for_each_sg(workreq, sgpnt, sg_count, j) {
++			bttl = sg_dma_address(sgpnt);
++			l=sg_dma_len(sgpnt);
+ #ifdef ED_DBGP		
+-		printk("1. bttl %x, l %x\n",bttl, l);
++			printk("1. bttl %x, l %x\n",bttl, l);
+ #endif			
+-		while (l > 0x10000) {
++			while (l > 0x10000) {
+ 				(((u16 *) (prd))[i + 3]) = 0x0000;
+ 				(((u16 *) (prd))[i + 2]) = 0x0000;
+ 				(((u32 *) (prd))[i >> 1]) = cpu_to_le32(bttl);
+@@ -965,32 +923,6 @@ oktosend:
+ 		printk("prd %4x %4x %4x %4x\n",(((unsigned short int *)prd)[0]),(((unsigned short int *)prd)[1]),(((unsigned short int *)prd)[2]),(((unsigned short int *)prd)[3]));
+ 		printk("2. bttl %x, l %x\n",bttl, l);
+ #endif			
+-	} else {
+-		/*
+-		 *	For a linear request write a chain of blocks
+-		 */        
+-		bttl = workreq->SCp.dma_handle;
+-		l = workreq->request_bufflen;
+-		i = 0;
+-#ifdef ED_DBGP		
+-		printk("3. bttl %x, l %x\n",bttl, l);
+-#endif			
+-		while (l > 0x10000) {
+-				(((u16 *) (prd))[i + 3]) = 0x0000;
+-				(((u16 *) (prd))[i + 2]) = 0x0000;
+-				(((u32 *) (prd))[i >> 1]) = cpu_to_le32(bttl);
+-				l -= 0x10000;
+-				bttl += 0x10000;
+-				i += 0x04;
+-			}
+-			(((u16 *) (prd))[i + 3]) = cpu_to_le16(0x8000);
+-			(((u16 *) (prd))[i + 2]) = cpu_to_le16(l);
+-			(((u32 *) (prd))[i >> 1]) = cpu_to_le32(bttl);		
+-#ifdef ED_DBGP		
+-		printk("prd %4x %4x %4x %4x\n",(((unsigned short int *)prd)[0]),(((unsigned short int *)prd)[1]),(((unsigned short int *)prd)[2]),(((unsigned short int *)prd)[3]));
+-		printk("4. bttl %x, l %x\n",bttl, l);
+-#endif			
+-		
+ 	}
+ 	tmpcip += 4;
+ #ifdef ED_DBGP		
+diff --git a/drivers/scsi/ch.c b/drivers/scsi/ch.c
+index 2311019..7aad154 100644
+--- a/drivers/scsi/ch.c
++++ b/drivers/scsi/ch.c
+@@ -21,6 +21,7 @@
+ #include <linux/compat.h>
+ #include <linux/chio.h>			/* here are all the ioctls */
+ #include <linux/mutex.h>
++#include <linux/idr.h>
+ 
+ #include <scsi/scsi.h>
+ #include <scsi/scsi_cmnd.h>
+@@ -33,6 +34,7 @@
+ 
+ #define CH_DT_MAX       16
+ #define CH_TYPES        8
++#define CH_MAX_DEVS     128
+ 
+ MODULE_DESCRIPTION("device driver for scsi media changer devices");
+ MODULE_AUTHOR("Gerd Knorr <kraxel at bytesex.org>");
+@@ -88,17 +90,6 @@ static const char * vendor_labels[CH_TYPES-4] = {
+ 
+ #define MAX_RETRIES   1
+ 
+-static int  ch_probe(struct device *);
+-static int  ch_remove(struct device *);
+-static int  ch_open(struct inode * inode, struct file * filp);
+-static int  ch_release(struct inode * inode, struct file * filp);
+-static int  ch_ioctl(struct inode * inode, struct file * filp,
+-		     unsigned int cmd, unsigned long arg);
+-#ifdef CONFIG_COMPAT
+-static long ch_ioctl_compat(struct file * filp,
+-			    unsigned int cmd, unsigned long arg);
+-#endif
+-
+ static struct class * ch_sysfs_class;
+ 
+ typedef struct {
+@@ -114,30 +105,8 @@ typedef struct {
+ 	struct mutex	    lock;
+ } scsi_changer;
+ 
+-static LIST_HEAD(ch_devlist);
+-static DEFINE_SPINLOCK(ch_devlist_lock);
+-static int ch_devcount;
+-
+-static struct scsi_driver ch_template =
+-{
+-	.owner     	= THIS_MODULE,
+-	.gendrv     	= {
+-		.name	= "ch",
+-		.probe  = ch_probe,
+-		.remove = ch_remove,
+-	},
+-};
+-
+-static const struct file_operations changer_fops =
+-{
+-	.owner        = THIS_MODULE,
+-	.open         = ch_open,
+-	.release      = ch_release,
+-	.ioctl        = ch_ioctl,
+-#ifdef CONFIG_COMPAT
+-	.compat_ioctl = ch_ioctl_compat,
+-#endif
+-};
++static DEFINE_IDR(ch_index_idr);
++static DEFINE_SPINLOCK(ch_index_lock);
+ 
+ static const struct {
+ 	unsigned char  sense;
+@@ -207,7 +176,7 @@ ch_do_scsi(scsi_changer *ch, unsigned char *cmd,
+ {
+ 	int errno, retries = 0, timeout, result;
+ 	struct scsi_sense_hdr sshdr;
+-	
 +
-+	rc = check_string("sysplex_name", buf);
-+	if (rc)
-+		return rc;
+ 	timeout = (cmd[0] == INITIALIZE_ELEMENT_STATUS)
+ 		? timeout_init : timeout_move;
+ 
+@@ -245,7 +214,7 @@ static int
+ ch_elem_to_typecode(scsi_changer *ch, u_int elem)
+ {
+ 	int i;
+-	
 +
-+	set_string(sysplex_name, buf);
+ 	for (i = 0; i < CH_TYPES; i++) {
+ 		if (elem >= ch->firsts[i]  &&
+ 		    elem <  ch->firsts[i] +
+@@ -261,15 +230,15 @@ ch_read_element_status(scsi_changer *ch, u_int elem, char *data)
+ 	u_char  cmd[12];
+ 	u_char  *buffer;
+ 	int     result;
+-	
 +
-+	return len;
-+}
+ 	buffer = kmalloc(512, GFP_KERNEL | GFP_DMA);
+ 	if(!buffer)
+ 		return -ENOMEM;
+-	
 +
-+static struct kobj_attribute sysplex_name_attr =
-+	__ATTR(sysplex_name, 0644, sysplex_name_show, sysplex_name_store);
+  retry:
+ 	memset(cmd,0,sizeof(cmd));
+ 	cmd[0] = READ_ELEMENT_STATUS;
+-	cmd[1] = (ch->device->lun << 5) | 
++	cmd[1] = (ch->device->lun << 5) |
+ 		(ch->voltags ? 0x10 : 0) |
+ 		ch_elem_to_typecode(ch,elem);
+ 	cmd[2] = (elem >> 8) & 0xff;
+@@ -296,7 +265,7 @@ ch_read_element_status(scsi_changer *ch, u_int elem, char *data)
+ 	return result;
+ }
+ 
+-static int 
++static int
+ ch_init_elem(scsi_changer *ch)
+ {
+ 	int err;
+@@ -322,7 +291,7 @@ ch_readconfig(scsi_changer *ch)
+ 	buffer = kzalloc(512, GFP_KERNEL | GFP_DMA);
+ 	if (!buffer)
+ 		return -ENOMEM;
+-	
 +
-+static ssize_t system_type_show(struct kobject *kobj,
-+				struct kobj_attribute *attr, char *page)
-+{
-+	return snprintf(page, PAGE_SIZE, "%s\n", system_type);
-+}
+ 	memset(cmd,0,sizeof(cmd));
+ 	cmd[0] = MODE_SENSE;
+ 	cmd[1] = ch->device->lun << 5;
+@@ -365,7 +334,7 @@ ch_readconfig(scsi_changer *ch)
+ 	} else {
+ 		vprintk("reading element address assigment page failed!\n");
+ 	}
+-	
 +
-+static ssize_t system_type_store(struct kobject *kobj,
-+				 struct kobj_attribute *attr,
-+				 const char *buf,
-+	size_t len)
-+{
-+	int rc;
+ 	/* vendor specific element types */
+ 	for (i = 0; i < 4; i++) {
+ 		if (0 == vendor_counts[i])
+@@ -443,7 +412,7 @@ static int
+ ch_position(scsi_changer *ch, u_int trans, u_int elem, int rotate)
+ {
+ 	u_char  cmd[10];
+-	
 +
-+	rc = check_string("system_type", buf);
-+	if (rc)
-+		return rc;
+ 	dprintk("position: 0x%x\n",elem);
+ 	if (0 == trans)
+ 		trans = ch->firsts[CHET_MT];
+@@ -462,7 +431,7 @@ static int
+ ch_move(scsi_changer *ch, u_int trans, u_int src, u_int dest, int rotate)
+ {
+ 	u_char  cmd[12];
+-	
 +
-+	set_string(system_type, buf);
+ 	dprintk("move: 0x%x => 0x%x\n",src,dest);
+ 	if (0 == trans)
+ 		trans = ch->firsts[CHET_MT];
+@@ -484,7 +453,7 @@ ch_exchange(scsi_changer *ch, u_int trans, u_int src,
+ 	    u_int dest1, u_int dest2, int rotate1, int rotate2)
+ {
+ 	u_char  cmd[12];
+-	
 +
-+	return len;
-+}
+ 	dprintk("exchange: 0x%x => 0x%x => 0x%x\n",
+ 		src,dest1,dest2);
+ 	if (0 == trans)
+@@ -501,7 +470,7 @@ ch_exchange(scsi_changer *ch, u_int trans, u_int src,
+ 	cmd[8]  = (dest2 >> 8) & 0xff;
+ 	cmd[9]  =  dest2       & 0xff;
+ 	cmd[10] = (rotate1 ? 1 : 0) | (rotate2 ? 2 : 0);
+-	
 +
-+static struct kobj_attribute system_type_attr =
-+	__ATTR(system_type, 0644, system_type_show, system_type_store);
+ 	return ch_do_scsi(ch, cmd, NULL,0, DMA_NONE);
+ }
+ 
+@@ -539,14 +508,14 @@ ch_set_voltag(scsi_changer *ch, u_int elem,
+ 		elem, tag);
+ 	memset(cmd,0,sizeof(cmd));
+ 	cmd[0]  = SEND_VOLUME_TAG;
+-	cmd[1] = (ch->device->lun << 5) | 
++	cmd[1] = (ch->device->lun << 5) |
+ 		ch_elem_to_typecode(ch,elem);
+ 	cmd[2] = (elem >> 8) & 0xff;
+ 	cmd[3] = elem        & 0xff;
+ 	cmd[5] = clear
+ 		? (alternate ? 0x0d : 0x0c)
+ 		: (alternate ? 0x0b : 0x0a);
+-	
 +
-+static ssize_t system_level_show(struct kobject *kobj,
-+				 struct kobj_attribute *attr, char *page)
-+{
-+	unsigned long long level = system_level;
+ 	cmd[9] = 255;
+ 
+ 	memcpy(buffer,tag,32);
+@@ -562,7 +531,7 @@ static int ch_gstatus(scsi_changer *ch, int type, unsigned char __user *dest)
+ 	int retval = 0;
+ 	u_char data[16];
+ 	unsigned int i;
+-	
 +
-+	return snprintf(page, PAGE_SIZE, "%#018llx\n", level);
-+}
+ 	mutex_lock(&ch->lock);
+ 	for (i = 0; i < ch->counts[type]; i++) {
+ 		if (0 != ch_read_element_status
+@@ -599,20 +568,17 @@ ch_release(struct inode *inode, struct file *file)
+ static int
+ ch_open(struct inode *inode, struct file *file)
+ {
+-	scsi_changer *tmp, *ch;
++	scsi_changer *ch;
+ 	int minor = iminor(inode);
+ 
+-	spin_lock(&ch_devlist_lock);
+-	ch = NULL;
+-	list_for_each_entry(tmp,&ch_devlist,list) {
+-		if (tmp->minor == minor)
+-			ch = tmp;
+-	}
++	spin_lock(&ch_index_lock);
++	ch = idr_find(&ch_index_idr, minor);
 +
-+static ssize_t system_level_store(struct kobject *kobj,
-+				  struct kobj_attribute *attr,
-+				  const char *buf,
-+	size_t len)
-+{
-+	unsigned long long level;
-+	char *endp;
+ 	if (NULL == ch || scsi_device_get(ch->device)) {
+-		spin_unlock(&ch_devlist_lock);
++		spin_unlock(&ch_index_lock);
+ 		return -ENXIO;
+ 	}
+-	spin_unlock(&ch_devlist_lock);
++	spin_unlock(&ch_index_lock);
+ 
+ 	file->private_data = ch;
+ 	return 0;
+@@ -626,24 +592,24 @@ ch_checkrange(scsi_changer *ch, unsigned int type, unsigned int unit)
+ 	return 0;
+ }
+ 
+-static int ch_ioctl(struct inode * inode, struct file * file,
++static long ch_ioctl(struct file *file,
+ 		    unsigned int cmd, unsigned long arg)
+ {
+ 	scsi_changer *ch = file->private_data;
+ 	int retval;
+ 	void __user *argp = (void __user *)arg;
+-	
 +
-+	level = simple_strtoull(buf, &endp, 16);
+ 	switch (cmd) {
+ 	case CHIOGPARAMS:
+ 	{
+ 		struct changer_params params;
+-		
 +
-+	if (endp == buf)
-+		return -EINVAL;
-+	if (*endp == '\n')
-+		endp++;
-+	if (*endp)
-+		return -EINVAL;
+ 		params.cp_curpicker = 0;
+ 		params.cp_npickers  = ch->counts[CHET_MT];
+ 		params.cp_nslots    = ch->counts[CHET_ST];
+ 		params.cp_nportals  = ch->counts[CHET_IE];
+ 		params.cp_ndrives   = ch->counts[CHET_DT];
+-		
 +
-+	system_level = level;
+ 		if (copy_to_user(argp, &params, sizeof(params)))
+ 			return -EFAULT;
+ 		return 0;
+@@ -673,11 +639,11 @@ static int ch_ioctl(struct inode * inode, struct file * file,
+ 			return -EFAULT;
+ 		return 0;
+ 	}
+-	
 +
-+	return len;
-+}
+ 	case CHIOPOSITION:
+ 	{
+ 		struct changer_position pos;
+-		
 +
-+static struct kobj_attribute system_level_attr =
-+	__ATTR(system_level, 0644, system_level_show, system_level_store);
+ 		if (copy_from_user(&pos, argp, sizeof (pos)))
+ 			return -EFAULT;
+ 
+@@ -692,7 +658,7 @@ static int ch_ioctl(struct inode * inode, struct file * file,
+ 		mutex_unlock(&ch->lock);
+ 		return retval;
+ 	}
+-	
 +
-+static ssize_t set_store(struct kobject *kobj,
-+			 struct kobj_attribute *attr,
-+			 const char *buf, size_t len)
-+{
-+	int rc;
+ 	case CHIOMOVE:
+ 	{
+ 		struct changer_move mv;
+@@ -705,7 +671,7 @@ static int ch_ioctl(struct inode * inode, struct file * file,
+ 			dprintk("CHIOMOVE: invalid parameter\n");
+ 			return -EBADSLT;
+ 		}
+-		
 +
-+	rc = cpi_req();
-+	if (rc)
-+		return rc;
+ 		mutex_lock(&ch->lock);
+ 		retval = ch_move(ch,0,
+ 				 ch->firsts[mv.cm_fromtype] + mv.cm_fromunit,
+@@ -718,7 +684,7 @@ static int ch_ioctl(struct inode * inode, struct file * file,
+ 	case CHIOEXCHANGE:
+ 	{
+ 		struct changer_exchange mv;
+-		
 +
-+	return len;
-+}
+ 		if (copy_from_user(&mv, argp, sizeof (mv)))
+ 			return -EFAULT;
+ 
+@@ -728,7 +694,7 @@ static int ch_ioctl(struct inode * inode, struct file * file,
+ 			dprintk("CHIOEXCHANGE: invalid parameter\n");
+ 			return -EBADSLT;
+ 		}
+-		
 +
-+static struct kobj_attribute set_attr = __ATTR(set, 0200, NULL, set_store);
+ 		mutex_lock(&ch->lock);
+ 		retval = ch_exchange
+ 			(ch,0,
+@@ -743,7 +709,7 @@ static int ch_ioctl(struct inode * inode, struct file * file,
+ 	case CHIOGSTATUS:
+ 	{
+ 		struct changer_element_status ces;
+-		
 +
-+static struct attribute *cpi_attrs[] = {
-+	&system_name_attr.attr,
-+	&sysplex_name_attr.attr,
-+	&system_type_attr.attr,
-+	&system_level_attr.attr,
-+	&set_attr.attr,
-+	NULL,
-+};
+ 		if (copy_from_user(&ces, argp, sizeof (ces)))
+ 			return -EFAULT;
+ 		if (ces.ces_type < 0 || ces.ces_type >= CH_TYPES)
+@@ -759,19 +725,19 @@ static int ch_ioctl(struct inode * inode, struct file * file,
+ 		u_char  *buffer;
+ 		unsigned int elem;
+ 		int     result,i;
+-		
 +
-+static struct attribute_group cpi_attr_group = {
-+	.attrs = cpi_attrs,
-+};
+ 		if (copy_from_user(&cge, argp, sizeof (cge)))
+ 			return -EFAULT;
+ 
+ 		if (0 != ch_checkrange(ch, cge.cge_type, cge.cge_unit))
+ 			return -EINVAL;
+ 		elem = ch->firsts[cge.cge_type] + cge.cge_unit;
+-		
 +
-+static struct kset *cpi_kset;
+ 		buffer = kmalloc(512, GFP_KERNEL | GFP_DMA);
+ 		if (!buffer)
+ 			return -ENOMEM;
+ 		mutex_lock(&ch->lock);
+-		
 +
-+int sclp_cpi_set_data(const char *system, const char *sysplex, const char *type,
-+		      const u64 level)
-+{
-+	int rc;
+ 	voltag_retry:
+ 		memset(cmd,0,sizeof(cmd));
+ 		cmd[0] = READ_ELEMENT_STATUS;
+@@ -782,7 +748,7 @@ static int ch_ioctl(struct inode * inode, struct file * file,
+ 		cmd[3] = elem        & 0xff;
+ 		cmd[5] = 1;
+ 		cmd[9] = 255;
+-		
 +
-+	rc = check_string("system_name", system);
-+	if (rc)
-+		return rc;
-+	rc = check_string("sysplex_name", sysplex);
-+	if (rc)
-+		return rc;
-+	rc = check_string("system_type", type);
-+	if (rc)
-+		return rc;
+ 		if (0 == (result = ch_do_scsi(ch, cmd, buffer, 256, DMA_FROM_DEVICE))) {
+ 			cge.cge_status = buffer[18];
+ 			cge.cge_flags = 0;
+@@ -822,7 +788,7 @@ static int ch_ioctl(struct inode * inode, struct file * file,
+ 		}
+ 		kfree(buffer);
+ 		mutex_unlock(&ch->lock);
+-		
 +
-+	set_string(system_name, system);
-+	set_string(sysplex_name, sysplex);
-+	set_string(system_type, type);
-+	system_level = level;
+ 		if (copy_to_user(argp, &cge, sizeof (cge)))
+ 			return -EFAULT;
+ 		return result;
+@@ -835,7 +801,7 @@ static int ch_ioctl(struct inode * inode, struct file * file,
+ 		mutex_unlock(&ch->lock);
+ 		return retval;
+ 	}
+-		
 +
-+	return cpi_req();
-+}
-+EXPORT_SYMBOL(sclp_cpi_set_data);
+ 	case CHIOSVOLTAG:
+ 	{
+ 		struct changer_set_voltag csv;
+@@ -876,7 +842,7 @@ static long ch_ioctl_compat(struct file * file,
+ 			    unsigned int cmd, unsigned long arg)
+ {
+ 	scsi_changer *ch = file->private_data;
+-	
 +
-+static int __init cpi_init(void)
-+{
-+	int rc;
+ 	switch (cmd) {
+ 	case CHIOGPARAMS:
+ 	case CHIOGVPARAMS:
+@@ -887,13 +853,12 @@ static long ch_ioctl_compat(struct file * file,
+ 	case CHIOINITELEM:
+ 	case CHIOSVOLTAG:
+ 		/* compatible */
+-		return ch_ioctl(NULL /* inode, unused */,
+-				file, cmd, arg);
++		return ch_ioctl(file, cmd, arg);
+ 	case CHIOGSTATUS32:
+ 	{
+ 		struct changer_element_status32 ces32;
+ 		unsigned char __user *data;
+-		
 +
-+	cpi_kset = kset_create_and_add("cpi", NULL, firmware_kobj);
-+	if (!cpi_kset)
-+		return -ENOMEM;
+ 		if (copy_from_user(&ces32, (void __user *)arg, sizeof (ces32)))
+ 			return -EFAULT;
+ 		if (ces32.ces_type < 0 || ces32.ces_type >= CH_TYPES)
+@@ -915,63 +880,100 @@ static long ch_ioctl_compat(struct file * file,
+ static int ch_probe(struct device *dev)
+ {
+ 	struct scsi_device *sd = to_scsi_device(dev);
++	struct class_device *class_dev;
++	int minor, ret = -ENOMEM;
+ 	scsi_changer *ch;
+-	
 +
-+	rc = sysfs_create_group(&cpi_kset->kobj, &cpi_attr_group);
-+	if (rc)
-+		kset_unregister(cpi_kset);
+ 	if (sd->type != TYPE_MEDIUM_CHANGER)
+ 		return -ENODEV;
+-    
 +
-+	return rc;
-+}
+ 	ch = kzalloc(sizeof(*ch), GFP_KERNEL);
+ 	if (NULL == ch)
+ 		return -ENOMEM;
+ 
+-	ch->minor = ch_devcount;
++	if (!idr_pre_get(&ch_index_idr, GFP_KERNEL))
++		goto free_ch;
 +
-+__initcall(cpi_init);
-diff --git a/drivers/s390/char/sclp_cpi_sys.h b/drivers/s390/char/sclp_cpi_sys.h
-new file mode 100644
-index 0000000..deef3e6
---- /dev/null
-+++ b/drivers/s390/char/sclp_cpi_sys.h
-@@ -0,0 +1,15 @@
-+/*
-+ *  drivers/s390/char/sclp_cpi_sys.h
-+ *    SCLP control program identification sysfs interface
-+ *
-+ *    Copyright IBM Corp. 2007
-+ *    Author(s): Michael Ernst <mernst at de.ibm.com>
-+ */
++	spin_lock(&ch_index_lock);
++	ret = idr_get_new(&ch_index_idr, ch, &minor);
++	spin_unlock(&ch_index_lock);
 +
-+#ifndef __SCLP_CPI_SYS_H__
-+#define __SCLP_CPI_SYS_H__
++	if (ret)
++		goto free_ch;
 +
-+int sclp_cpi_set_data(const char *system, const char *sysplex,
-+		      const char *type, u64 level);
++	if (minor > CH_MAX_DEVS) {
++		ret = -ENODEV;
++		goto remove_idr;
++	}
 +
-+#endif	 /* __SCLP_CPI_SYS_H__ */
-diff --git a/drivers/s390/char/sclp_info.c b/drivers/s390/char/sclp_info.c
-deleted file mode 100644
-index a1136e0..0000000
---- a/drivers/s390/char/sclp_info.c
-+++ /dev/null
-@@ -1,116 +0,0 @@
--/*
-- *  drivers/s390/char/sclp_info.c
-- *
-- *    Copyright IBM Corp. 2007
-- *    Author(s): Heiko Carstens <heiko.carstens at de.ibm.com>
-- */
--
--#include <linux/init.h>
--#include <linux/errno.h>
--#include <linux/string.h>
--#include <asm/sclp.h>
--#include "sclp.h"
--
--struct sclp_readinfo_sccb {
--	struct	sccb_header header;	/* 0-7 */
--	u16	rnmax;			/* 8-9 */
--	u8	rnsize;			/* 10 */
--	u8	_reserved0[24 - 11];	/* 11-23 */
--	u8	loadparm[8];		/* 24-31 */
--	u8	_reserved1[48 - 32];	/* 32-47 */
--	u64	facilities;		/* 48-55 */
--	u8	_reserved2[91 - 56];	/* 56-90 */
--	u8	flags;			/* 91 */
--	u8	_reserved3[100 - 92];	/* 92-99 */
--	u32	rnsize2;		/* 100-103 */
--	u64	rnmax2;			/* 104-111 */
--	u8	_reserved4[4096 - 112];	/* 112-4095 */
--} __attribute__((packed, aligned(4096)));
--
--static struct sclp_readinfo_sccb __initdata early_readinfo_sccb;
--static int __initdata early_readinfo_sccb_valid;
--
--u64 sclp_facilities;
--
--void __init sclp_readinfo_early(void)
--{
--	int ret;
--	int i;
--	struct sclp_readinfo_sccb *sccb;
--	sclp_cmdw_t commands[] = {SCLP_CMDW_READ_SCP_INFO_FORCED,
--				  SCLP_CMDW_READ_SCP_INFO};
--
--	/* Enable service signal subclass mask. */
--	__ctl_set_bit(0, 9);
--	sccb = &early_readinfo_sccb;
--	for (i = 0; i < ARRAY_SIZE(commands); i++) {
--		do {
--			memset(sccb, 0, sizeof(*sccb));
--			sccb->header.length = sizeof(*sccb);
--			sccb->header.control_mask[2] = 0x80;
--			ret = sclp_service_call(commands[i], sccb);
--		} while (ret == -EBUSY);
--
--		if (ret)
--			break;
--		__load_psw_mask(PSW_BASE_BITS | PSW_MASK_EXT |
--				PSW_MASK_WAIT | PSW_DEFAULT_KEY);
--		local_irq_disable();
--		/*
--		 * Contents of the sccb might have changed
--		 * therefore a barrier is needed.
--		 */
--		barrier();
--		if (sccb->header.response_code == 0x10) {
--			early_readinfo_sccb_valid = 1;
--			break;
--		}
--		if (sccb->header.response_code != 0x1f0)
--			break;
--	}
--	/* Disable service signal subclass mask again. */
--	__ctl_clear_bit(0, 9);
--}
--
--void __init sclp_facilities_detect(void)
--{
--	if (!early_readinfo_sccb_valid)
--		return;
--	sclp_facilities = early_readinfo_sccb.facilities;
--}
--
--unsigned long long __init sclp_memory_detect(void)
--{
--	unsigned long long memsize;
--	struct sclp_readinfo_sccb *sccb;
--
--	if (!early_readinfo_sccb_valid)
--		return 0;
--	sccb = &early_readinfo_sccb;
--	if (sccb->rnsize)
--		memsize = sccb->rnsize << 20;
--	else
--		memsize = sccb->rnsize2 << 20;
--	if (sccb->rnmax)
--		memsize *= sccb->rnmax;
--	else
--		memsize *= sccb->rnmax2;
--	return memsize;
--}
--
--/*
-- * This function will be called after sclp_memory_detect(), which gets called
-- * early from early.c code. Therefore the sccb should have valid contents.
-- */
--void __init sclp_get_ipl_info(struct sclp_ipl_info *info)
--{
--	struct sclp_readinfo_sccb *sccb;
--
--	if (!early_readinfo_sccb_valid)
--		return;
--	sccb = &early_readinfo_sccb;
--	info->is_valid = 1;
--	if (sccb->flags & 0x2)
--		info->has_dump = 1;
--	memcpy(&info->loadparm, &sccb->loadparm, LOADPARM_LEN);
--}
-diff --git a/drivers/s390/char/sclp_rw.c b/drivers/s390/char/sclp_rw.c
-index d6b06ab..ad7195d 100644
---- a/drivers/s390/char/sclp_rw.c
-+++ b/drivers/s390/char/sclp_rw.c
-@@ -76,7 +76,7 @@ sclp_make_buffer(void *page, unsigned short columns, unsigned short htab)
- }
- 
- /*
-- * Return a pointer to the orignal page that has been used to create
-+ * Return a pointer to the original page that has been used to create
-  * the buffer.
-  */
- void *
-diff --git a/drivers/s390/char/tape_3590.c b/drivers/s390/char/tape_3590.c
-index da25f8e..8246ef3 100644
---- a/drivers/s390/char/tape_3590.c
-+++ b/drivers/s390/char/tape_3590.c
-@@ -1495,7 +1495,7 @@ tape_3590_unit_check(struct tape_device *device, struct tape_request *request,
- 			   device->cdev->dev.bus_id);
- 		return tape_3590_erp_basic(device, request, irb, -EPERM);
- 	case 0x8013:
--		PRINT_WARN("(%s): Another host has priviliged access to the "
-+		PRINT_WARN("(%s): Another host has privileged access to the "
- 			   "tape device\n", device->cdev->dev.bus_id);
- 		PRINT_WARN("(%s): To solve the problem unload the current "
- 			   "cartridge!\n", device->cdev->dev.bus_id);
-diff --git a/drivers/s390/char/tape_core.c b/drivers/s390/char/tape_core.c
-index 2fae633..7ad8cf1 100644
---- a/drivers/s390/char/tape_core.c
-+++ b/drivers/s390/char/tape_core.c
-@@ -37,7 +37,7 @@ static void tape_long_busy_timeout(unsigned long data);
-  * we can assign the devices to minor numbers of the same major
-  * The list is protected by the rwlock
-  */
--static struct list_head tape_device_list = LIST_HEAD_INIT(tape_device_list);
-+static LIST_HEAD(tape_device_list);
- static DEFINE_RWLOCK(tape_device_lock);
- 
- /*
-diff --git a/drivers/s390/char/tape_proc.c b/drivers/s390/char/tape_proc.c
-index cea49f0..c9b96d5 100644
---- a/drivers/s390/char/tape_proc.c
-+++ b/drivers/s390/char/tape_proc.c
-@@ -97,7 +97,7 @@ static void tape_proc_stop(struct seq_file *m, void *v)
- {
- }
- 
--static struct seq_operations tape_proc_seq = {
-+static const struct seq_operations tape_proc_seq = {
- 	.start		= tape_proc_start,
- 	.next		= tape_proc_next,
- 	.stop		= tape_proc_stop,
-diff --git a/drivers/s390/char/vmlogrdr.c b/drivers/s390/char/vmlogrdr.c
-index e0c4c50..d364e0b 100644
---- a/drivers/s390/char/vmlogrdr.c
-+++ b/drivers/s390/char/vmlogrdr.c
-@@ -683,7 +683,7 @@ static int vmlogrdr_register_driver(void)
- 	/* Register with iucv driver */
- 	ret = iucv_register(&vmlogrdr_iucv_handler, 1);
- 	if (ret) {
--		printk (KERN_ERR "vmlogrdr: failed to register with"
-+		printk (KERN_ERR "vmlogrdr: failed to register with "
- 			"iucv driver\n");
- 		goto out;
- 	}
-diff --git a/drivers/s390/char/vmur.c b/drivers/s390/char/vmur.c
-index d70a6e6..7689b50 100644
---- a/drivers/s390/char/vmur.c
-+++ b/drivers/s390/char/vmur.c
-@@ -759,7 +759,7 @@ static loff_t ur_llseek(struct file *file, loff_t offset, int whence)
- 	return newpos;
- }
- 
--static struct file_operations ur_fops = {
-+static const struct file_operations ur_fops = {
- 	.owner	 = THIS_MODULE,
- 	.open	 = ur_open,
- 	.release = ur_release,
-diff --git a/drivers/s390/char/zcore.c b/drivers/s390/char/zcore.c
-index 7073daf..f523501 100644
---- a/drivers/s390/char/zcore.c
-+++ b/drivers/s390/char/zcore.c
-@@ -470,7 +470,7 @@ static loff_t zcore_lseek(struct file *file, loff_t offset, int orig)
- 	return rc;
- }
- 
--static struct file_operations zcore_fops = {
-+static const struct file_operations zcore_fops = {
- 	.owner		= THIS_MODULE,
- 	.llseek		= zcore_lseek,
- 	.read		= zcore_read,
-diff --git a/drivers/s390/cio/airq.c b/drivers/s390/cio/airq.c
-index 5287631..b7a07a8 100644
---- a/drivers/s390/cio/airq.c
-+++ b/drivers/s390/cio/airq.c
-@@ -1,12 +1,12 @@
- /*
-  *  drivers/s390/cio/airq.c
-- *   S/390 common I/O routines -- support for adapter interruptions
-+ *    Support for adapter interruptions
-  *
-- *    Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH,
-- *			      IBM Corporation
-- *    Author(s): Ingo Adlung (adlung at de.ibm.com)
-- *		 Cornelia Huck (cornelia.huck at de.ibm.com)
-- *		 Arnd Bergmann (arndb at de.ibm.com)
-+ *    Copyright IBM Corp. 1999,2007
-+ *    Author(s): Ingo Adlung <adlung at de.ibm.com>
-+ *		 Cornelia Huck <cornelia.huck at de.ibm.com>
-+ *		 Arnd Bergmann <arndb at de.ibm.com>
-+ *		 Peter Oberparleiter <peter.oberparleiter at de.ibm.com>
-  */
- 
- #include <linux/init.h>
-@@ -14,72 +14,131 @@
- #include <linux/slab.h>
- #include <linux/rcupdate.h>
- 
-+#include <asm/airq.h>
++	ch->minor = minor;
+ 	sprintf(ch->name,"ch%d",ch->minor);
 +
-+#include "cio.h"
- #include "cio_debug.h"
--#include "airq.h"
- 
--static adapter_int_handler_t adapter_handler;
-+#define NR_AIRQS		32
-+#define NR_AIRQS_PER_WORD	sizeof(unsigned long)
-+#define NR_AIRQ_WORDS		(NR_AIRQS / NR_AIRQS_PER_WORD)
- 
--/*
-- * register for adapter interrupts
-- *
-- * With HiperSockets the zSeries architecture provides for
-- *  means of adapter interrups, pseudo I/O interrupts that are
-- *  not tied to an I/O subchannel, but to an adapter. However,
-- *  it doesn't disclose the info how to enable/disable them, but
-- *  to recognize them only. Perhaps we should consider them
-- *  being shared interrupts, and thus build a linked list
-- *  of adapter handlers ... to be evaluated ...
-- */
--int
--s390_register_adapter_interrupt (adapter_int_handler_t handler)
--{
--	int ret;
--	char dbf_txt[15];
-+union indicator_t {
-+	unsigned long word[NR_AIRQ_WORDS];
-+	unsigned char byte[NR_AIRQS];
-+} __attribute__((packed));
- 
--	CIO_TRACE_EVENT (4, "rgaint");
-+struct airq_t {
-+	adapter_int_handler_t handler;
-+	void *drv_data;
-+};
- 
--	if (handler == NULL)
--		ret = -EINVAL;
--	else
--		ret = (cmpxchg(&adapter_handler, NULL, handler) ? -EBUSY : 0);
--	if (!ret)
--		synchronize_sched();  /* Allow interrupts to complete. */
-+static union indicator_t indicators;
-+static struct airq_t *airqs[NR_AIRQS];
- 
--	sprintf (dbf_txt, "ret:%d", ret);
--	CIO_TRACE_EVENT (4, dbf_txt);
-+static int register_airq(struct airq_t *airq)
-+{
-+	int i;
- 
--	return ret;
-+	for (i = 0; i < NR_AIRQS; i++)
-+		if (!cmpxchg(&airqs[i], NULL, airq))
-+			return i;
-+	return -ENOMEM;
- }
- 
--int
--s390_unregister_adapter_interrupt (adapter_int_handler_t handler)
-+/**
-+ * s390_register_adapter_interrupt() - register adapter interrupt handler
-+ * @handler: adapter handler to be registered
-+ * @drv_data: driver data passed with each call to the handler
-+ *
-+ * Returns:
-+ *  Pointer to the indicator to be used on success
-+ *  ERR_PTR() if registration failed
-+ */
-+void *s390_register_adapter_interrupt(adapter_int_handler_t handler,
-+				      void *drv_data)
- {
-+	struct airq_t *airq;
-+	char dbf_txt[16];
- 	int ret;
--	char dbf_txt[15];
- 
--	CIO_TRACE_EVENT (4, "urgaint");
--
--	if (handler == NULL)
--		ret = -EINVAL;
--	else {
--		adapter_handler = NULL;
--		synchronize_sched();  /* Allow interrupts to complete. */
--		ret = 0;
-+	airq = kmalloc(sizeof(struct airq_t), GFP_KERNEL);
-+	if (!airq) {
-+		ret = -ENOMEM;
-+		goto out;
- 	}
--	sprintf (dbf_txt, "ret:%d", ret);
--	CIO_TRACE_EVENT (4, dbf_txt);
--
--	return ret;
-+	airq->handler = handler;
-+	airq->drv_data = drv_data;
-+	ret = register_airq(airq);
-+	if (ret < 0)
-+		kfree(airq);
-+out:
-+	snprintf(dbf_txt, sizeof(dbf_txt), "rairq:%d", ret);
-+	CIO_TRACE_EVENT(4, dbf_txt);
-+	if (ret < 0)
-+		return ERR_PTR(ret);
-+	else
-+		return &indicators.byte[ret];
- }
-+EXPORT_SYMBOL(s390_register_adapter_interrupt);
- 
--void
--do_adapter_IO (void)
-+/**
-+ * s390_unregister_adapter_interrupt - unregister adapter interrupt handler
-+ * @ind: indicator for which the handler is to be unregistered
-+ */
-+void s390_unregister_adapter_interrupt(void *ind)
- {
--	CIO_TRACE_EVENT (6, "doaio");
-+	struct airq_t *airq;
-+	char dbf_txt[16];
-+	int i;
- 
--	if (adapter_handler)
--		(*adapter_handler) ();
-+	i = (int) ((addr_t) ind) - ((addr_t) &indicators.byte[0]);
-+	snprintf(dbf_txt, sizeof(dbf_txt), "urairq:%d", i);
-+	CIO_TRACE_EVENT(4, dbf_txt);
-+	indicators.byte[i] = 0;
-+	airq = xchg(&airqs[i], NULL);
-+	/*
-+	 * Allow interrupts to complete. This will ensure that the airq handle
-+	 * is no longer referenced by any interrupt handler.
-+	 */
-+	synchronize_sched();
-+	kfree(airq);
- }
-+EXPORT_SYMBOL(s390_unregister_adapter_interrupt);
++	class_dev = class_device_create(ch_sysfs_class, NULL,
++					MKDEV(SCSI_CHANGER_MAJOR, ch->minor),
++					dev, "s%s", ch->name);
++	if (IS_ERR(class_dev)) {
++		printk(KERN_WARNING "ch%d: class_device_create failed\n",
++		       ch->minor);
++		ret = PTR_ERR(class_dev);
++		goto remove_idr;
++	}
 +
-+#define INDICATOR_MASK	(0xffUL << ((NR_AIRQS_PER_WORD - 1) * 8))
+ 	mutex_init(&ch->lock);
+ 	ch->device = sd;
+ 	ch_readconfig(ch);
+ 	if (init)
+ 		ch_init_elem(ch);
  
--EXPORT_SYMBOL (s390_register_adapter_interrupt);
--EXPORT_SYMBOL (s390_unregister_adapter_interrupt);
-+void do_adapter_IO(void)
-+{
-+	int w;
-+	int i;
-+	unsigned long word;
-+	struct airq_t *airq;
-+
-+	/*
-+	 * Access indicator array in word-sized chunks to minimize storage
-+	 * fetch operations.
-+	 */
-+	for (w = 0; w < NR_AIRQ_WORDS; w++) {
-+		word = indicators.word[w];
-+		i = w * NR_AIRQS_PER_WORD;
-+		/*
-+		 * Check bytes within word for active indicators.
-+		 */
-+		while (word) {
-+			if (word & INDICATOR_MASK) {
-+				airq = airqs[i];
-+				if (likely(airq))
-+					airq->handler(&indicators.byte[i],
-+						      airq->drv_data);
-+				else
-+					/*
-+					 * Reset ill-behaved indicator.
-+					 */
-+					indicators.byte[i] = 0;
-+			}
-+			word <<= 8;
-+			i++;
-+		}
-+	}
-+}
-diff --git a/drivers/s390/cio/airq.h b/drivers/s390/cio/airq.h
-deleted file mode 100644
-index 7d6be3f..0000000
---- a/drivers/s390/cio/airq.h
-+++ /dev/null
-@@ -1,10 +0,0 @@
--#ifndef S390_AINTERRUPT_H
--#define S390_AINTERRUPT_H
--
--typedef	int (*adapter_int_handler_t)(void);
--
--extern int s390_register_adapter_interrupt(adapter_int_handler_t handler);
--extern int s390_unregister_adapter_interrupt(adapter_int_handler_t handler);
--extern void do_adapter_IO (void);
+-	class_device_create(ch_sysfs_class, NULL,
+-			    MKDEV(SCSI_CHANGER_MAJOR,ch->minor),
+-			    dev, "s%s", ch->name);
 -
--#endif
-diff --git a/drivers/s390/cio/blacklist.c b/drivers/s390/cio/blacklist.c
-index bd5f16f..e8597ec 100644
---- a/drivers/s390/cio/blacklist.c
-+++ b/drivers/s390/cio/blacklist.c
-@@ -348,7 +348,7 @@ cio_ignore_write(struct file *file, const char __user *user_buf,
- 	return user_len;
- }
- 
--static struct seq_operations cio_ignore_proc_seq_ops = {
-+static const struct seq_operations cio_ignore_proc_seq_ops = {
- 	.start = cio_ignore_proc_seq_start,
- 	.stop  = cio_ignore_proc_seq_stop,
- 	.next  = cio_ignore_proc_seq_next,
-diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c
-index 5baa517..3964056 100644
---- a/drivers/s390/cio/ccwgroup.c
-+++ b/drivers/s390/cio/ccwgroup.c
-@@ -35,8 +35,8 @@ ccwgroup_bus_match (struct device * dev, struct device_driver * drv)
- 	struct ccwgroup_device *gdev;
- 	struct ccwgroup_driver *gdrv;
- 
--	gdev = container_of(dev, struct ccwgroup_device, dev);
--	gdrv = container_of(drv, struct ccwgroup_driver, driver);
-+	gdev = to_ccwgroupdev(dev);
-+	gdrv = to_ccwgroupdrv(drv);
- 
- 	if (gdev->creator_id == gdrv->driver_id)
- 		return 1;
-@@ -75,8 +75,10 @@ static void ccwgroup_ungroup_callback(struct device *dev)
- 	struct ccwgroup_device *gdev = to_ccwgroupdev(dev);
- 
- 	mutex_lock(&gdev->reg_mutex);
--	__ccwgroup_remove_symlinks(gdev);
--	device_unregister(dev);
-+	if (device_is_registered(&gdev->dev)) {
-+		__ccwgroup_remove_symlinks(gdev);
-+		device_unregister(dev);
-+	}
- 	mutex_unlock(&gdev->reg_mutex);
++	dev_set_drvdata(dev, ch);
+ 	sdev_printk(KERN_INFO, sd, "Attached scsi changer %s\n", ch->name);
+-	
+-	spin_lock(&ch_devlist_lock);
+-	list_add_tail(&ch->list,&ch_devlist);
+-	ch_devcount++;
+-	spin_unlock(&ch_devlist_lock);
++
+ 	return 0;
++remove_idr:
++	idr_remove(&ch_index_idr, minor);
++free_ch:
++	kfree(ch);
++	return ret;
  }
  
-@@ -111,7 +113,7 @@ ccwgroup_release (struct device *dev)
- 	gdev = to_ccwgroupdev(dev);
- 
- 	for (i = 0; i < gdev->count; i++) {
--		gdev->cdev[i]->dev.driver_data = NULL;
-+		dev_set_drvdata(&gdev->cdev[i]->dev, NULL);
- 		put_device(&gdev->cdev[i]->dev);
- 	}
- 	kfree(gdev);
-@@ -196,11 +198,11 @@ int ccwgroup_create(struct device *root, unsigned int creator_id,
- 			goto error;
- 		}
- 		/* Don't allow a device to belong to more than one group. */
--		if (gdev->cdev[i]->dev.driver_data) {
-+		if (dev_get_drvdata(&gdev->cdev[i]->dev)) {
- 			rc = -EINVAL;
- 			goto error;
- 		}
--		gdev->cdev[i]->dev.driver_data = gdev;
-+		dev_set_drvdata(&gdev->cdev[i]->dev, gdev);
- 	}
+ static int ch_remove(struct device *dev)
+ {
+-	struct scsi_device *sd = to_scsi_device(dev);
+-	scsi_changer *tmp, *ch;
++	scsi_changer *ch = dev_get_drvdata(dev);
  
- 	gdev->creator_id = creator_id;
-@@ -234,8 +236,8 @@ int ccwgroup_create(struct device *root, unsigned int creator_id,
- error:
- 	for (i = 0; i < argc; i++)
- 		if (gdev->cdev[i]) {
--			if (gdev->cdev[i]->dev.driver_data == gdev)
--				gdev->cdev[i]->dev.driver_data = NULL;
-+			if (dev_get_drvdata(&gdev->cdev[i]->dev) == gdev)
-+				dev_set_drvdata(&gdev->cdev[i]->dev, NULL);
- 			put_device(&gdev->cdev[i]->dev);
- 		}
- 	mutex_unlock(&gdev->reg_mutex);
-@@ -408,6 +410,7 @@ int ccwgroup_driver_register(struct ccwgroup_driver *cdriver)
- 	/* register our new driver with the core */
- 	cdriver->driver.bus = &ccwgroup_bus_type;
- 	cdriver->driver.name = cdriver->name;
-+	cdriver->driver.owner = cdriver->owner;
+-	spin_lock(&ch_devlist_lock);
+-	ch = NULL;
+-	list_for_each_entry(tmp,&ch_devlist,list) {
+-		if (tmp->device == sd)
+-			ch = tmp;
+-	}
+-	BUG_ON(NULL == ch);
+-	list_del(&ch->list);
+-	spin_unlock(&ch_devlist_lock);
++	spin_lock(&ch_index_lock);
++	idr_remove(&ch_index_idr, ch->minor);
++	spin_unlock(&ch_index_lock);
  
- 	return driver_register(&cdriver->driver);
+ 	class_device_destroy(ch_sysfs_class,
+ 			     MKDEV(SCSI_CHANGER_MAJOR,ch->minor));
+ 	kfree(ch->dt);
+ 	kfree(ch);
+-	ch_devcount--;
+ 	return 0;
  }
-@@ -463,8 +466,8 @@ __ccwgroup_get_gdev_by_cdev(struct ccw_device *cdev)
- {
- 	struct ccwgroup_device *gdev;
  
--	if (cdev->dev.driver_data) {
--		gdev = (struct ccwgroup_device *)cdev->dev.driver_data;
-+	gdev = dev_get_drvdata(&cdev->dev);
-+	if (gdev) {
- 		if (get_device(&gdev->dev)) {
- 			mutex_lock(&gdev->reg_mutex);
- 			if (device_is_registered(&gdev->dev))
-diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c
-index 597c0c7..e7ba16a 100644
---- a/drivers/s390/cio/chsc.c
-+++ b/drivers/s390/cio/chsc.c
-@@ -89,7 +89,8 @@ int chsc_get_ssd_info(struct subchannel_id schid, struct chsc_ssd_info *ssd)
- 	/* Copy data */
- 	ret = 0;
- 	memset(ssd, 0, sizeof(struct chsc_ssd_info));
--	if ((ssd_area->st != 0) && (ssd_area->st != 2))
-+	if ((ssd_area->st != SUBCHANNEL_TYPE_IO) &&
-+	    (ssd_area->st != SUBCHANNEL_TYPE_MSG))
- 		goto out_free;
- 	ssd->path_mask = ssd_area->path_mask;
- 	ssd->fla_valid_mask = ssd_area->fla_valid_mask;
-@@ -132,20 +133,16 @@ static void terminate_internal_io(struct subchannel *sch)
- 	device_set_intretry(sch);
- 	/* Call handler. */
- 	if (sch->driver && sch->driver->termination)
--		sch->driver->termination(&sch->dev);
-+		sch->driver->termination(sch);
++static struct scsi_driver ch_template = {
++	.owner     	= THIS_MODULE,
++	.gendrv     	= {
++		.name	= "ch",
++		.probe  = ch_probe,
++		.remove = ch_remove,
++	},
++};
++
++static const struct file_operations changer_fops = {
++	.owner		= THIS_MODULE,
++	.open		= ch_open,
++	.release	= ch_release,
++	.unlocked_ioctl	= ch_ioctl,
++#ifdef CONFIG_COMPAT
++	.compat_ioctl	= ch_ioctl_compat,
++#endif
++};
++
+ static int __init init_ch_module(void)
+ {
+ 	int rc;
+-	
++
+ 	printk(KERN_INFO "SCSI Media Changer driver v" VERSION " \n");
+         ch_sysfs_class = class_create(THIS_MODULE, "scsi_changer");
+         if (IS_ERR(ch_sysfs_class)) {
+@@ -996,11 +998,12 @@ static int __init init_ch_module(void)
+ 	return rc;
  }
  
--static int
--s390_subchannel_remove_chpid(struct device *dev, void *data)
-+static int s390_subchannel_remove_chpid(struct subchannel *sch, void *data)
+-static void __exit exit_ch_module(void) 
++static void __exit exit_ch_module(void)
  {
- 	int j;
- 	int mask;
--	struct subchannel *sch;
--	struct chp_id *chpid;
-+	struct chp_id *chpid = data;
- 	struct schib schib;
+ 	scsi_unregister_driver(&ch_template.gendrv);
+ 	unregister_chrdev(SCSI_CHANGER_MAJOR, "ch");
+ 	class_destroy(ch_sysfs_class);
++	idr_destroy(&ch_index_idr);
+ }
  
--	sch = to_subchannel(dev);
--	chpid = data;
- 	for (j = 0; j < 8; j++) {
- 		mask = 0x80 >> j;
- 		if ((sch->schib.pmcw.pim & mask) &&
-@@ -158,7 +155,7 @@ s390_subchannel_remove_chpid(struct device *dev, void *data)
- 	spin_lock_irq(sch->lock);
+ module_init(init_ch_module);
+diff --git a/drivers/scsi/constants.c b/drivers/scsi/constants.c
+index 024553f..403a7f2 100644
+--- a/drivers/scsi/constants.c
++++ b/drivers/scsi/constants.c
+@@ -362,7 +362,6 @@ void scsi_print_command(struct scsi_cmnd *cmd)
+ EXPORT_SYMBOL(scsi_print_command);
  
- 	stsch(sch->schid, &schib);
--	if (!schib.pmcw.dnv)
-+	if (!css_sch_is_valid(&schib))
- 		goto out_unreg;
- 	memcpy(&sch->schib, &schib, sizeof(struct schib));
- 	/* Check for single path devices. */
-@@ -172,12 +169,12 @@ s390_subchannel_remove_chpid(struct device *dev, void *data)
- 			terminate_internal_io(sch);
- 			/* Re-start path verification. */
- 			if (sch->driver && sch->driver->verify)
--				sch->driver->verify(&sch->dev);
-+				sch->driver->verify(sch);
- 		}
+ /**
+- *
+  *	scsi_print_status - print scsi status description
+  *	@scsi_status: scsi status value
+  *
+@@ -1369,7 +1368,7 @@ EXPORT_SYMBOL(scsi_print_sense);
+ static const char * const hostbyte_table[]={
+ "DID_OK", "DID_NO_CONNECT", "DID_BUS_BUSY", "DID_TIME_OUT", "DID_BAD_TARGET",
+ "DID_ABORT", "DID_PARITY", "DID_ERROR", "DID_RESET", "DID_BAD_INTR",
+-"DID_PASSTHROUGH", "DID_SOFT_ERROR", "DID_IMM_RETRY"};
++"DID_PASSTHROUGH", "DID_SOFT_ERROR", "DID_IMM_RETRY", "DID_REQUEUE"};
+ #define NUM_HOSTBYTE_STRS ARRAY_SIZE(hostbyte_table)
+ 
+ static const char * const driverbyte_table[]={
+diff --git a/drivers/scsi/dc395x.c b/drivers/scsi/dc395x.c
+index a9def6e..f93c73c 100644
+--- a/drivers/scsi/dc395x.c
++++ b/drivers/scsi/dc395x.c
+@@ -1629,8 +1629,7 @@ static u8 start_scsi(struct AdapterCtlBlk* acb, struct DeviceCtlBlk* dcb,
+ 		DC395x_write8(acb, TRM_S1040_SCSI_FIFO, (dcb->target_lun << 5));
+ 		DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 0);
+ 		DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 0);
+-		DC395x_write8(acb, TRM_S1040_SCSI_FIFO,
+-			      sizeof(srb->cmd->sense_buffer));
++		DC395x_write8(acb, TRM_S1040_SCSI_FIFO, SCSI_SENSE_BUFFERSIZE);
+ 		DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 0);
  	} else {
- 		/* trigger path verification. */
- 		if (sch->driver && sch->driver->verify)
--			sch->driver->verify(&sch->dev);
-+			sch->driver->verify(sch);
- 		else if (sch->lpm == mask)
- 			goto out_unreg;
+ 		ptr = (u8 *)srb->cmd->cmnd;
+@@ -1915,8 +1914,7 @@ static void command_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
+ 		DC395x_write8(acb, TRM_S1040_SCSI_FIFO, (dcb->target_lun << 5));
+ 		DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 0);
+ 		DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 0);
+-		DC395x_write8(acb, TRM_S1040_SCSI_FIFO,
+-			      sizeof(srb->cmd->sense_buffer));
++		DC395x_write8(acb, TRM_S1040_SCSI_FIFO, SCSI_SENSE_BUFFERSIZE);
+ 		DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 0);
  	}
-@@ -201,12 +198,10 @@ void chsc_chp_offline(struct chp_id chpid)
+ 	srb->state |= SRB_COMMAND;
+@@ -3685,7 +3683,7 @@ static void request_sense(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
+ 	srb->target_status = 0;
  
- 	if (chp_get_status(chpid) <= 0)
- 		return;
--	bus_for_each_dev(&css_bus_type, NULL, &chpid,
--			 s390_subchannel_remove_chpid);
-+	for_each_subchannel_staged(s390_subchannel_remove_chpid, NULL, &chpid);
- }
+ 	/* KG: Can this prevent crap sense data ? */
+-	memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer));
++	memset(cmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
  
--static int
--s390_process_res_acc_new_sch(struct subchannel_id schid)
-+static int s390_process_res_acc_new_sch(struct subchannel_id schid, void *data)
- {
- 	struct schib schib;
- 	/*
-@@ -252,18 +247,10 @@ static int get_res_chpid_mask(struct chsc_ssd_info *ssd,
- 	return 0;
- }
+ 	/* Save some data */
+ 	srb->segment_x[DC395x_MAX_SG_LISTENTRY - 1].address =
+@@ -3694,15 +3692,15 @@ static void request_sense(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
+ 	    srb->segment_x[0].length;
+ 	srb->xferred = srb->total_xfer_length;
+ 	/* srb->segment_x : a one entry of S/G list table */
+-	srb->total_xfer_length = sizeof(cmd->sense_buffer);
+-	srb->segment_x[0].length = sizeof(cmd->sense_buffer);
++	srb->total_xfer_length = SCSI_SENSE_BUFFERSIZE;
++	srb->segment_x[0].length = SCSI_SENSE_BUFFERSIZE;
+ 	/* Map sense buffer */
+ 	srb->segment_x[0].address =
+ 	    pci_map_single(acb->dev, cmd->sense_buffer,
+-			   sizeof(cmd->sense_buffer), PCI_DMA_FROMDEVICE);
++			   SCSI_SENSE_BUFFERSIZE, PCI_DMA_FROMDEVICE);
+ 	dprintkdbg(DBG_SG, "request_sense: map buffer %p->%08x(%05x)\n",
+ 	       cmd->sense_buffer, srb->segment_x[0].address,
+-	       sizeof(cmd->sense_buffer));
++	       SCSI_SENSE_BUFFERSIZE);
+ 	srb->sg_count = 1;
+ 	srb->sg_index = 0;
  
--static int
--__s390_process_res_acc(struct subchannel_id schid, void *data)
-+static int __s390_process_res_acc(struct subchannel *sch, void *data)
- {
- 	int chp_mask, old_lpm;
--	struct res_acc_data *res_data;
--	struct subchannel *sch;
--
--	res_data = data;
--	sch = get_subchannel_by_schid(schid);
--	if (!sch)
--		/* Check if a subchannel is newly available. */
--		return s390_process_res_acc_new_sch(schid);
-+	struct res_acc_data *res_data = data;
+diff --git a/drivers/scsi/dpt_i2o.c b/drivers/scsi/dpt_i2o.c
+index b31d1c9..19cce12 100644
+--- a/drivers/scsi/dpt_i2o.c
++++ b/drivers/scsi/dpt_i2o.c
+@@ -2296,9 +2296,8 @@ static s32 adpt_i2o_to_scsi(void __iomem *reply, struct scsi_cmnd* cmd)
  
- 	spin_lock_irq(sch->lock);
- 	chp_mask = get_res_chpid_mask(&sch->ssd_info, res_data);
-@@ -279,10 +266,10 @@ __s390_process_res_acc(struct subchannel_id schid, void *data)
- 	if (!old_lpm && sch->lpm)
- 		device_trigger_reprobe(sch);
- 	else if (sch->driver && sch->driver->verify)
--		sch->driver->verify(&sch->dev);
-+		sch->driver->verify(sch);
- out:
- 	spin_unlock_irq(sch->lock);
--	put_device(&sch->dev);
-+
- 	return 0;
- }
+ 		// copy over the request sense data if it was a check
+ 		// condition status
+-		if(dev_status == 0x02 /*CHECK_CONDITION*/) {
+-			u32 len = sizeof(cmd->sense_buffer);
+-			len = (len > 40) ?  40 : len;
++		if (dev_status == SAM_STAT_CHECK_CONDITION) {
++			u32 len = min(SCSI_SENSE_BUFFERSIZE, 40);
+ 			// Copy over the sense data
+ 			memcpy_fromio(cmd->sense_buffer, (reply+28) , len);
+ 			if(cmd->sense_buffer[0] == 0x70 /* class 7 */ && 
+diff --git a/drivers/scsi/eata.c b/drivers/scsi/eata.c
+index 7ead521..05163ce 100644
+--- a/drivers/scsi/eata.c
++++ b/drivers/scsi/eata.c
+@@ -1623,9 +1623,9 @@ static void map_dma(unsigned int i, struct hostdata *ha)
+ 	if (SCpnt->sense_buffer)
+ 		cpp->sense_addr =
+ 		    H2DEV(pci_map_single(ha->pdev, SCpnt->sense_buffer,
+-			   sizeof SCpnt->sense_buffer, PCI_DMA_FROMDEVICE));
++			   SCSI_SENSE_BUFFERSIZE, PCI_DMA_FROMDEVICE));
  
-@@ -305,7 +292,8 @@ static void s390_process_res_acc (struct res_acc_data *res_data)
- 	 * The more information we have (info), the less scanning
- 	 * will we have to do.
- 	 */
--	for_each_subchannel(__s390_process_res_acc, res_data);
-+	for_each_subchannel_staged(__s390_process_res_acc,
-+				   s390_process_res_acc_new_sch, res_data);
- }
+-	cpp->sense_len = sizeof SCpnt->sense_buffer;
++	cpp->sense_len = SCSI_SENSE_BUFFERSIZE;
  
- static int
-@@ -499,8 +487,7 @@ void chsc_process_crw(void)
- 	} while (sei_area->flags & 0x80);
- }
+ 	count = scsi_dma_map(SCpnt);
+ 	BUG_ON(count < 0);
+diff --git a/drivers/scsi/eata_pio.c b/drivers/scsi/eata_pio.c
+index 982c509..b5a6092 100644
+--- a/drivers/scsi/eata_pio.c
++++ b/drivers/scsi/eata_pio.c
+@@ -369,7 +369,6 @@ static int eata_pio_queue(struct scsi_cmnd *cmd,
+ 	cp = &hd->ccb[y];
  
--static int
--__chp_add_new_sch(struct subchannel_id schid)
-+static int __chp_add_new_sch(struct subchannel_id schid, void *data)
- {
- 	struct schib schib;
+ 	memset(cp, 0, sizeof(struct eata_ccb));
+-	memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer));
  
-@@ -514,45 +501,37 @@ __chp_add_new_sch(struct subchannel_id schid)
- }
+ 	cp->status = USED;	/* claim free slot */
  
+@@ -385,7 +384,7 @@ static int eata_pio_queue(struct scsi_cmnd *cmd,
+ 		cp->DataIn = 0;	/* Input mode  */
  
--static int
--__chp_add(struct subchannel_id schid, void *data)
-+static int __chp_add(struct subchannel *sch, void *data)
- {
- 	int i, mask;
--	struct chp_id *chpid;
--	struct subchannel *sch;
+ 	cp->Interpret = (cmd->device->id == hd->hostid);
+-	cp->cp_datalen = cpu_to_be32(cmd->request_bufflen);
++	cp->cp_datalen = cpu_to_be32(scsi_bufflen(cmd));
+ 	cp->Auto_Req_Sen = 0;
+ 	cp->cp_reqDMA = 0;
+ 	cp->reqlen = 0;
+@@ -402,14 +401,14 @@ static int eata_pio_queue(struct scsi_cmnd *cmd,
+ 	cp->cmd = cmd;
+ 	cmd->host_scribble = (char *) &hd->ccb[y];
+ 
+-	if (cmd->use_sg == 0) {
++	if (!scsi_bufflen(cmd)) {
+ 		cmd->SCp.buffers_residual = 1;
+-		cmd->SCp.ptr = cmd->request_buffer;
+-		cmd->SCp.this_residual = cmd->request_bufflen;
++		cmd->SCp.ptr = NULL;
++		cmd->SCp.this_residual = 0;
+ 		cmd->SCp.buffer = NULL;
+ 	} else {
+-		cmd->SCp.buffer = cmd->request_buffer;
+-		cmd->SCp.buffers_residual = cmd->use_sg;
++		cmd->SCp.buffer = scsi_sglist(cmd);
++		cmd->SCp.buffers_residual = scsi_sg_count(cmd);
+ 		cmd->SCp.ptr = sg_virt(cmd->SCp.buffer);
+ 		cmd->SCp.this_residual = cmd->SCp.buffer->length;
+ 	}
+diff --git a/drivers/scsi/fd_mcs.c b/drivers/scsi/fd_mcs.c
+index 8335b60..85bd54c 100644
+--- a/drivers/scsi/fd_mcs.c
++++ b/drivers/scsi/fd_mcs.c
+@@ -1017,24 +1017,6 @@ static irqreturn_t fd_mcs_intr(int irq, void *dev_id)
+ 		printk(" ** IN DONE %d ** ", current_SC->SCp.have_data_in);
+ #endif
+ 
+-#if ERRORS_ONLY
+-		if (current_SC->cmnd[0] == REQUEST_SENSE && !current_SC->SCp.Status) {
+-			if ((unsigned char) (*((char *) current_SC->request_buffer + 2)) & 0x0f) {
+-				unsigned char key;
+-				unsigned char code;
+-				unsigned char qualifier;
 -
--	chpid = data;
--	sch = get_subchannel_by_schid(schid);
--	if (!sch)
--		/* Check if the subchannel is now available. */
--		return __chp_add_new_sch(schid);
-+	struct chp_id *chpid = data;
-+
- 	spin_lock_irq(sch->lock);
- 	for (i=0; i<8; i++) {
- 		mask = 0x80 >> i;
- 		if ((sch->schib.pmcw.pim & mask) &&
--		    (sch->schib.pmcw.chpid[i] == chpid->id)) {
--			if (stsch(sch->schid, &sch->schib) != 0) {
--				/* Endgame. */
--				spin_unlock_irq(sch->lock);
--				return -ENXIO;
+-				key = (unsigned char) (*((char *) current_SC->request_buffer + 2)) & 0x0f;
+-				code = (unsigned char) (*((char *) current_SC->request_buffer + 12));
+-				qualifier = (unsigned char) (*((char *) current_SC->request_buffer + 13));
+-
+-				if (key != UNIT_ATTENTION && !(key == NOT_READY && code == 0x04 && (!qualifier || qualifier == 0x02 || qualifier == 0x01))
+-				    && !(key == ILLEGAL_REQUEST && (code == 0x25 || code == 0x24 || !code)))
+-
+-					printk("fd_mcs: REQUEST SENSE " "Key = %x, Code = %x, Qualifier = %x\n", key, code, qualifier);
 -			}
-+		    (sch->schib.pmcw.chpid[i] == chpid->id))
- 			break;
 -		}
+-#endif
+ #if EVERY_ACCESS
+ 		printk("BEFORE MY_DONE. . .");
+ #endif
+@@ -1097,7 +1079,9 @@ static int fd_mcs_queue(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
+ 		panic("fd_mcs: fd_mcs_queue() NOT REENTRANT!\n");
  	}
- 	if (i==8) {
- 		spin_unlock_irq(sch->lock);
- 		return 0;
- 	}
-+	if (stsch(sch->schid, &sch->schib)) {
-+		spin_unlock_irq(sch->lock);
-+		css_schedule_eval(sch->schid);
-+		return 0;
-+	}
- 	sch->lpm = ((sch->schib.pmcw.pim &
- 		     sch->schib.pmcw.pam &
- 		     sch->schib.pmcw.pom)
- 		    | mask) & sch->opm;
- 
- 	if (sch->driver && sch->driver->verify)
--		sch->driver->verify(&sch->dev);
-+		sch->driver->verify(sch);
- 
- 	spin_unlock_irq(sch->lock);
--	put_device(&sch->dev);
-+
- 	return 0;
- }
+ #if EVERY_ACCESS
+-	printk("queue: target = %d cmnd = 0x%02x pieces = %d size = %u\n", SCpnt->target, *(unsigned char *) SCpnt->cmnd, SCpnt->use_sg, SCpnt->request_bufflen);
++	printk("queue: target = %d cmnd = 0x%02x pieces = %d size = %u\n",
++		SCpnt->target, *(unsigned char *) SCpnt->cmnd,
++		scsi_sg_count(SCpnt), scsi_bufflen(SCpnt));
+ #endif
  
-@@ -564,7 +543,8 @@ void chsc_chp_online(struct chp_id chpid)
- 	CIO_TRACE_EVENT(2, dbf_txt);
+ 	fd_mcs_make_bus_idle(shpnt);
+@@ -1107,14 +1091,14 @@ static int fd_mcs_queue(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
  
- 	if (chp_get_status(chpid) != 0)
--		for_each_subchannel(__chp_add, &chpid);
-+		for_each_subchannel_staged(__chp_add, __chp_add_new_sch,
-+					   &chpid);
- }
+ 	/* Initialize static data */
  
- static void __s390_subchannel_vary_chpid(struct subchannel *sch,
-@@ -589,7 +569,7 @@ static void __s390_subchannel_vary_chpid(struct subchannel *sch,
- 			if (!old_lpm)
- 				device_trigger_reprobe(sch);
- 			else if (sch->driver && sch->driver->verify)
--				sch->driver->verify(&sch->dev);
-+				sch->driver->verify(sch);
- 			break;
- 		}
- 		sch->opm &= ~mask;
-@@ -603,37 +583,29 @@ static void __s390_subchannel_vary_chpid(struct subchannel *sch,
- 				terminate_internal_io(sch);
- 				/* Re-start path verification. */
- 				if (sch->driver && sch->driver->verify)
--					sch->driver->verify(&sch->dev);
-+					sch->driver->verify(sch);
- 			}
- 		} else if (!sch->lpm) {
- 			if (device_trigger_verify(sch) != 0)
- 				css_schedule_eval(sch->schid);
- 		} else if (sch->driver && sch->driver->verify)
--			sch->driver->verify(&sch->dev);
-+			sch->driver->verify(sch);
+-	if (current_SC->use_sg) {
+-		current_SC->SCp.buffer = (struct scatterlist *) current_SC->request_buffer;
++	if (scsi_bufflen(current_SC)) {
++		current_SC->SCp.buffer = scsi_sglist(current_SC);
+ 		current_SC->SCp.ptr = sg_virt(current_SC->SCp.buffer);
+ 		current_SC->SCp.this_residual = current_SC->SCp.buffer->length;
+-		current_SC->SCp.buffers_residual = current_SC->use_sg - 1;
++		current_SC->SCp.buffers_residual = scsi_sg_count(current_SC) - 1;
+ 	} else {
+-		current_SC->SCp.ptr = (char *) current_SC->request_buffer;
+-		current_SC->SCp.this_residual = current_SC->request_bufflen;
++		current_SC->SCp.ptr = NULL;
++		current_SC->SCp.this_residual = 0;
+ 		current_SC->SCp.buffer = NULL;
+ 		current_SC->SCp.buffers_residual = 0;
+ 	}
+@@ -1166,7 +1150,9 @@ static void fd_mcs_print_info(Scsi_Cmnd * SCpnt)
  		break;
  	}
- 	spin_unlock_irqrestore(sch->lock, flags);
- }
  
--static int s390_subchannel_vary_chpid_off(struct device *dev, void *data)
-+static int s390_subchannel_vary_chpid_off(struct subchannel *sch, void *data)
- {
--	struct subchannel *sch;
--	struct chp_id *chpid;
--
--	sch = to_subchannel(dev);
--	chpid = data;
-+	struct chp_id *chpid = data;
+-	printk("(%d), target = %d cmnd = 0x%02x pieces = %d size = %u\n", SCpnt->SCp.phase, SCpnt->device->id, *(unsigned char *) SCpnt->cmnd, SCpnt->use_sg, SCpnt->request_bufflen);
++	printk("(%d), target = %d cmnd = 0x%02x pieces = %d size = %u\n",
++		SCpnt->SCp.phase, SCpnt->device->id, *(unsigned char *) SCpnt->cmnd,
++		scsi_sg_count(SCpnt), scsi_bufflen(SCpnt));
+ 	printk("sent_command = %d, have_data_in = %d, timeout = %d\n", SCpnt->SCp.sent_command, SCpnt->SCp.have_data_in, SCpnt->timeout);
+ #if DEBUG_RACE
+ 	printk("in_interrupt_flag = %d\n", in_interrupt_flag);
+diff --git a/drivers/scsi/gdth.c b/drivers/scsi/gdth.c
+index b253b8c..c825239 100644
+--- a/drivers/scsi/gdth.c
++++ b/drivers/scsi/gdth.c
+@@ -141,7 +141,7 @@
+ static void gdth_delay(int milliseconds);
+ static void gdth_eval_mapping(ulong32 size, ulong32 *cyls, int *heads, int *secs);
+ static irqreturn_t gdth_interrupt(int irq, void *dev_id);
+-static irqreturn_t __gdth_interrupt(gdth_ha_str *ha, int irq,
++static irqreturn_t __gdth_interrupt(gdth_ha_str *ha,
+                                     int gdth_from_wait, int* pIndex);
+ static int gdth_sync_event(gdth_ha_str *ha, int service, unchar index,
+                                                                Scsi_Cmnd *scp);
+@@ -165,7 +165,6 @@ static int gdth_internal_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp);
+ static int gdth_fill_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp, ushort hdrive);
  
- 	__s390_subchannel_vary_chpid(sch, *chpid, 0);
- 	return 0;
+ static void gdth_enable_int(gdth_ha_str *ha);
+-static unchar gdth_get_status(gdth_ha_str *ha, int irq);
+ static int gdth_test_busy(gdth_ha_str *ha);
+ static int gdth_get_cmd_index(gdth_ha_str *ha);
+ static void gdth_release_event(gdth_ha_str *ha);
+@@ -1334,14 +1333,12 @@ static void __init gdth_enable_int(gdth_ha_str *ha)
  }
  
--static int s390_subchannel_vary_chpid_on(struct device *dev, void *data)
-+static int s390_subchannel_vary_chpid_on(struct subchannel *sch, void *data)
- {
--	struct subchannel *sch;
--	struct chp_id *chpid;
--
--	sch = to_subchannel(dev);
--	chpid = data;
-+	struct chp_id *chpid = data;
- 
- 	__s390_subchannel_vary_chpid(sch, *chpid, 1);
- 	return 0;
-@@ -643,13 +615,7 @@ static int
- __s390_vary_chpid_on(struct subchannel_id schid, void *data)
+ /* return IStatus if interrupt was from this card else 0 */
+-static unchar gdth_get_status(gdth_ha_str *ha, int irq)
++static unchar gdth_get_status(gdth_ha_str *ha)
  {
- 	struct schib schib;
--	struct subchannel *sch;
- 
--	sch = get_subchannel_by_schid(schid);
--	if (sch) {
--		put_device(&sch->dev);
--		return 0;
--	}
- 	if (stsch_err(schid, &schib))
- 		/* We're through */
- 		return -ENXIO;
-@@ -669,12 +635,13 @@ int chsc_chp_vary(struct chp_id chpid, int on)
- 	 * Redo PathVerification on the devices the chpid connects to
- 	 */
+     unchar IStatus = 0;
  
--	bus_for_each_dev(&css_bus_type, NULL, &chpid, on ?
--			 s390_subchannel_vary_chpid_on :
--			 s390_subchannel_vary_chpid_off);
- 	if (on)
--		/* Scan for new devices on varied on path. */
--		for_each_subchannel(__s390_vary_chpid_on, NULL);
-+		for_each_subchannel_staged(s390_subchannel_vary_chpid_on,
-+					   __s390_vary_chpid_on, &chpid);
-+	else
-+		for_each_subchannel_staged(s390_subchannel_vary_chpid_off,
-+					   NULL, &chpid);
-+
- 	return 0;
- }
+-    TRACE(("gdth_get_status() irq %d ctr_count %d\n", irq, gdth_ctr_count));
++    TRACE(("gdth_get_status() irq %d ctr_count %d\n", ha->irq, gdth_ctr_count));
  
-@@ -1075,7 +1042,7 @@ chsc_determine_css_characteristics(void)
+-        if (ha->irq != (unchar)irq)             /* check IRQ */
+-            return false;
+         if (ha->type == GDT_EISA)
+             IStatus = inb((ushort)ha->bmic + EDOORREG);
+         else if (ha->type == GDT_ISA)
+@@ -1523,7 +1520,7 @@ static int gdth_wait(gdth_ha_str *ha, int index, ulong32 time)
+         return 1;                               /* no wait required */
  
- 	scsc_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
- 	if (!scsc_area) {
--		CIO_MSG_EVENT(0, "Was not able to determine available"
-+		CIO_MSG_EVENT(0, "Was not able to determine available "
- 			      "CHSCs due to no memory.\n");
- 		return -ENOMEM;
- 	}
-diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c
-index 4690534..60590a1 100644
---- a/drivers/s390/cio/cio.c
-+++ b/drivers/s390/cio/cio.c
-@@ -23,11 +23,12 @@
- #include <asm/reset.h>
- #include <asm/ipl.h>
- #include <asm/chpid.h>
--#include "airq.h"
-+#include <asm/airq.h>
- #include "cio.h"
- #include "css.h"
- #include "chsc.h"
- #include "ioasm.h"
-+#include "io_sch.h"
- #include "blacklist.h"
- #include "cio_debug.h"
- #include "chp.h"
-@@ -56,39 +57,37 @@ __setup ("cio_msg=", cio_setup);
+     do {
+-        __gdth_interrupt(ha, (int)ha->irq, true, &wait_index);
++	__gdth_interrupt(ha, true, &wait_index);
+         if (wait_index == index) {
+             answer_found = TRUE;
+             break;
+@@ -3036,7 +3033,7 @@ static void gdth_clear_events(void)
  
- /*
-  * Function: cio_debug_init
-- * Initializes three debug logs (under /proc/s390dbf) for common I/O:
-- * - cio_msg logs the messages which are printk'ed when CONFIG_DEBUG_IO is on
-+ * Initializes three debug logs for common I/O:
-+ * - cio_msg logs generic cio messages
-  * - cio_trace logs the calling of different functions
-- * - cio_crw logs the messages which are printk'ed when CONFIG_DEBUG_CRW is on
-- * debug levels depend on CONFIG_DEBUG_IO resp. CONFIG_DEBUG_CRW
-+ * - cio_crw logs machine check related cio messages
-  */
--static int __init
--cio_debug_init (void)
-+static int __init cio_debug_init(void)
- {
--	cio_debug_msg_id = debug_register ("cio_msg", 16, 4, 16*sizeof (long));
-+	cio_debug_msg_id = debug_register("cio_msg", 16, 1, 16 * sizeof(long));
- 	if (!cio_debug_msg_id)
- 		goto out_unregister;
--	debug_register_view (cio_debug_msg_id, &debug_sprintf_view);
--	debug_set_level (cio_debug_msg_id, 2);
--	cio_debug_trace_id = debug_register ("cio_trace", 16, 4, 16);
-+	debug_register_view(cio_debug_msg_id, &debug_sprintf_view);
-+	debug_set_level(cio_debug_msg_id, 2);
-+	cio_debug_trace_id = debug_register("cio_trace", 16, 1, 16);
- 	if (!cio_debug_trace_id)
- 		goto out_unregister;
--	debug_register_view (cio_debug_trace_id, &debug_hex_ascii_view);
--	debug_set_level (cio_debug_trace_id, 2);
--	cio_debug_crw_id = debug_register ("cio_crw", 4, 4, 16*sizeof (long));
-+	debug_register_view(cio_debug_trace_id, &debug_hex_ascii_view);
-+	debug_set_level(cio_debug_trace_id, 2);
-+	cio_debug_crw_id = debug_register("cio_crw", 16, 1, 16 * sizeof(long));
- 	if (!cio_debug_crw_id)
- 		goto out_unregister;
--	debug_register_view (cio_debug_crw_id, &debug_sprintf_view);
--	debug_set_level (cio_debug_crw_id, 2);
-+	debug_register_view(cio_debug_crw_id, &debug_sprintf_view);
-+	debug_set_level(cio_debug_crw_id, 4);
- 	return 0;
+ /* SCSI interface functions */
  
- out_unregister:
- 	if (cio_debug_msg_id)
--		debug_unregister (cio_debug_msg_id);
-+		debug_unregister(cio_debug_msg_id);
- 	if (cio_debug_trace_id)
--		debug_unregister (cio_debug_trace_id);
-+		debug_unregister(cio_debug_trace_id);
- 	if (cio_debug_crw_id)
--		debug_unregister (cio_debug_crw_id);
-+		debug_unregister(cio_debug_crw_id);
- 	printk(KERN_WARNING"cio: could not initialize debugging\n");
- 	return -1;
- }
-@@ -147,7 +146,7 @@ cio_tpi(void)
- 	spin_lock(sch->lock);
- 	memcpy (&sch->schib.scsw, &irb->scsw, sizeof (struct scsw));
- 	if (sch->driver && sch->driver->irq)
--		sch->driver->irq(&sch->dev);
-+		sch->driver->irq(sch);
- 	spin_unlock(sch->lock);
- 	irq_exit ();
- 	_local_bh_enable();
-@@ -184,33 +183,35 @@ cio_start_key (struct subchannel *sch,	/* subchannel structure */
+-static irqreturn_t __gdth_interrupt(gdth_ha_str *ha, int irq,
++static irqreturn_t __gdth_interrupt(gdth_ha_str *ha,
+                                     int gdth_from_wait, int* pIndex)
  {
- 	char dbf_txt[15];
- 	int ccode;
-+	struct orb *orb;
- 
--	CIO_TRACE_EVENT (4, "stIO");
--	CIO_TRACE_EVENT (4, sch->dev.bus_id);
-+	CIO_TRACE_EVENT(4, "stIO");
-+	CIO_TRACE_EVENT(4, sch->dev.bus_id);
+     gdt6m_dpram_str __iomem *dp6m_ptr = NULL;
+@@ -3054,7 +3051,7 @@ static irqreturn_t __gdth_interrupt(gdth_ha_str *ha, int irq,
+     int act_int_coal = 0;       
+ #endif
  
-+	orb = &to_io_private(sch)->orb;
- 	/* sch is always under 2G. */
--	sch->orb.intparm = (__u32)(unsigned long)sch;
--	sch->orb.fmt = 1;
-+	orb->intparm = (u32)(addr_t)sch;
-+	orb->fmt = 1;
+-    TRACE(("gdth_interrupt() IRQ %d\n",irq));
++    TRACE(("gdth_interrupt() IRQ %d\n", ha->irq));
  
--	sch->orb.pfch = sch->options.prefetch == 0;
--	sch->orb.spnd = sch->options.suspend;
--	sch->orb.ssic = sch->options.suspend && sch->options.inter;
--	sch->orb.lpm = (lpm != 0) ? lpm : sch->lpm;
-+	orb->pfch = sch->options.prefetch == 0;
-+	orb->spnd = sch->options.suspend;
-+	orb->ssic = sch->options.suspend && sch->options.inter;
-+	orb->lpm = (lpm != 0) ? lpm : sch->lpm;
- #ifdef CONFIG_64BIT
- 	/*
- 	 * for 64 bit we always support 64 bit IDAWs with 4k page size only
- 	 */
--	sch->orb.c64 = 1;
--	sch->orb.i2k = 0;
-+	orb->c64 = 1;
-+	orb->i2k = 0;
- #endif
--	sch->orb.key = key >> 4;
-+	orb->key = key >> 4;
- 	/* issue "Start Subchannel" */
--	sch->orb.cpa = (__u32) __pa (cpa);
--	ccode = ssch (sch->schid, &sch->orb);
-+	orb->cpa = (__u32) __pa(cpa);
-+	ccode = ssch(sch->schid, orb);
+     /* if polling and not from gdth_wait() -> return */
+     if (gdth_polling) {
+@@ -3067,7 +3064,8 @@ static irqreturn_t __gdth_interrupt(gdth_ha_str *ha, int irq,
+         spin_lock_irqsave(&ha->smp_lock, flags);
  
- 	/* process condition code */
--	sprintf (dbf_txt, "ccode:%d", ccode);
--	CIO_TRACE_EVENT (4, dbf_txt);
-+	sprintf(dbf_txt, "ccode:%d", ccode);
-+	CIO_TRACE_EVENT(4, dbf_txt);
+     /* search controller */
+-    if (0 == (IStatus = gdth_get_status(ha, irq))) {
++    IStatus = gdth_get_status(ha);
++    if (IStatus == 0) {
+         /* spurious interrupt */
+         if (!gdth_polling)
+             spin_unlock_irqrestore(&ha->smp_lock, flags);
+@@ -3294,9 +3292,9 @@ static irqreturn_t __gdth_interrupt(gdth_ha_str *ha, int irq,
  
- 	switch (ccode) {
- 	case 0:
-@@ -405,8 +406,8 @@ cio_modify (struct subchannel *sch)
- /*
-  * Enable subchannel.
-  */
--int
--cio_enable_subchannel (struct subchannel *sch, unsigned int isc)
-+int cio_enable_subchannel(struct subchannel *sch, unsigned int isc,
-+			  u32 intparm)
+ static irqreturn_t gdth_interrupt(int irq, void *dev_id)
  {
- 	char dbf_txt[15];
- 	int ccode;
-@@ -425,7 +426,7 @@ cio_enable_subchannel (struct subchannel *sch, unsigned int isc)
- 	for (retry = 5, ret = 0; retry > 0; retry--) {
- 		sch->schib.pmcw.ena = 1;
- 		sch->schib.pmcw.isc = isc;
--		sch->schib.pmcw.intparm = (__u32)(unsigned long)sch;
-+		sch->schib.pmcw.intparm = intparm;
- 		ret = cio_modify(sch);
- 		if (ret == -ENODEV)
- 			break;
-@@ -567,7 +568,7 @@ cio_validate_subchannel (struct subchannel *sch, struct subchannel_id schid)
- 	 */
- 	if (sch->st != 0) {
- 		CIO_DEBUG(KERN_INFO, 0,
--			  "cio: Subchannel 0.%x.%04x reports "
-+			  "Subchannel 0.%x.%04x reports "
- 			  "non-I/O subchannel type %04X\n",
- 			  sch->schid.ssid, sch->schid.sch_no, sch->st);
- 		/* We stop here for non-io subchannels. */
-@@ -576,11 +577,11 @@ cio_validate_subchannel (struct subchannel *sch, struct subchannel_id schid)
- 	}
+-	gdth_ha_str *ha = (gdth_ha_str *)dev_id;
++	gdth_ha_str *ha = dev_id;
  
- 	/* Initialization for io subchannels. */
--	if (!sch->schib.pmcw.dnv) {
--		/* io subchannel but device number is invalid. */
-+	if (!css_sch_is_valid(&sch->schib)) {
- 		err = -ENODEV;
- 		goto out;
- 	}
-+
- 	/* Devno is valid. */
- 	if (is_blacklisted (sch->schid.ssid, sch->schib.pmcw.dev)) {
- 		/*
-@@ -600,7 +601,7 @@ cio_validate_subchannel (struct subchannel *sch, struct subchannel_id schid)
- 	sch->lpm = sch->schib.pmcw.pam & sch->opm;
+-	return __gdth_interrupt(ha, irq, false, NULL);
++	return __gdth_interrupt(ha, false, NULL);
+ }
  
- 	CIO_DEBUG(KERN_INFO, 0,
--		  "cio: Detected device %04x on subchannel 0.%x.%04X"
-+		  "Detected device %04x on subchannel 0.%x.%04X"
- 		  " - PIM = %02X, PAM = %02X, POM = %02X\n",
- 		  sch->schib.pmcw.dev, sch->schid.ssid,
- 		  sch->schid.sch_no, sch->schib.pmcw.pim,
-@@ -680,7 +681,7 @@ do_IRQ (struct pt_regs *regs)
- 				sizeof (irb->scsw));
- 			/* Call interrupt handler if there is one. */
- 			if (sch->driver && sch->driver->irq)
--				sch->driver->irq(&sch->dev);
-+				sch->driver->irq(sch);
- 		}
- 		if (sch)
- 			spin_unlock(sch->lock);
-@@ -698,8 +699,14 @@ do_IRQ (struct pt_regs *regs)
+ static int gdth_sync_event(gdth_ha_str *ha, int service, unchar index,
+diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c
+index 24271a8..5ea1f98 100644
+--- a/drivers/scsi/hosts.c
++++ b/drivers/scsi/hosts.c
+@@ -54,8 +54,7 @@ static struct class shost_class = {
+ };
  
- #ifdef CONFIG_CCW_CONSOLE
- static struct subchannel console_subchannel;
-+static struct io_subchannel_private console_priv;
- static int console_subchannel_in_use;
+ /**
+- *	scsi_host_set_state - Take the given host through the host
+- *		state model.
++ *	scsi_host_set_state - Take the given host through the host state model.
+  *	@shost:	scsi host to change the state of.
+  *	@state:	state to change to.
+  *
+@@ -429,9 +428,17 @@ void scsi_unregister(struct Scsi_Host *shost)
+ }
+ EXPORT_SYMBOL(scsi_unregister);
  
-+void *cio_get_console_priv(void)
++static int __scsi_host_match(struct class_device *cdev, void *data)
 +{
-+	return &console_priv;
++	struct Scsi_Host *p;
++	unsigned short *hostnum = (unsigned short *)data;
++
++	p = class_to_shost(cdev);
++	return p->host_no == *hostnum;
 +}
 +
- /*
-  * busy wait for the next interrupt on the console
-  */
-@@ -738,9 +745,9 @@ cio_test_for_console(struct subchannel_id schid, void *data)
+ /**
+  * scsi_host_lookup - get a reference to a Scsi_Host by host no
+- *
+  * @hostnum:	host number to locate
+  *
+  * Return value:
+@@ -439,19 +446,12 @@ EXPORT_SYMBOL(scsi_unregister);
+  **/
+ struct Scsi_Host *scsi_host_lookup(unsigned short hostnum)
  {
- 	if (stsch_err(schid, &console_subchannel.schib) != 0)
- 		return -ENXIO;
--	if (console_subchannel.schib.pmcw.dnv &&
--	    console_subchannel.schib.pmcw.dev ==
--	    console_devno) {
-+	if ((console_subchannel.schib.pmcw.st == SUBCHANNEL_TYPE_IO) &&
-+	    console_subchannel.schib.pmcw.dnv &&
-+	    (console_subchannel.schib.pmcw.dev == console_devno)) {
- 		console_irq = schid.sch_no;
- 		return 1; /* found */
- 	}
-@@ -758,6 +765,7 @@ cio_get_console_sch_no(void)
- 		/* VM provided us with the irq number of the console. */
- 		schid.sch_no = console_irq;
- 		if (stsch(schid, &console_subchannel.schib) != 0 ||
-+		    (console_subchannel.schib.pmcw.st != SUBCHANNEL_TYPE_IO) ||
- 		    !console_subchannel.schib.pmcw.dnv)
- 			return -1;
- 		console_devno = console_subchannel.schib.pmcw.dev;
-@@ -804,7 +812,7 @@ cio_probe_console(void)
- 	ctl_set_bit(6, 24);
- 	console_subchannel.schib.pmcw.isc = 7;
- 	console_subchannel.schib.pmcw.intparm =
--		(__u32)(unsigned long)&console_subchannel;
-+		(u32)(addr_t)&console_subchannel;
- 	ret = cio_modify(&console_subchannel);
- 	if (ret) {
- 		console_subchannel_in_use = 0;
-@@ -1022,7 +1030,7 @@ static int __reipl_subchannel_match(struct subchannel_id schid, void *data)
- 
- 	if (stsch_reset(schid, &schib))
- 		return -ENXIO;
--	if (schib.pmcw.dnv &&
-+	if ((schib.pmcw.st == SUBCHANNEL_TYPE_IO) && schib.pmcw.dnv &&
- 	    (schib.pmcw.dev == match_id->devid.devno) &&
- 	    (schid.ssid == match_id->devid.ssid)) {
- 		match_id->schid = schid;
-@@ -1068,6 +1076,8 @@ int __init cio_get_iplinfo(struct cio_iplinfo *iplinfo)
- 		return -ENODEV;
- 	if (stsch(schid, &schib))
- 		return -ENODEV;
-+	if (schib.pmcw.st != SUBCHANNEL_TYPE_IO)
-+		return -ENODEV;
- 	if (!schib.pmcw.dnv)
- 		return -ENODEV;
- 	iplinfo->devno = schib.pmcw.dev;
-diff --git a/drivers/s390/cio/cio.h b/drivers/s390/cio/cio.h
-index 7446c39..52afa4c 100644
---- a/drivers/s390/cio/cio.h
-+++ b/drivers/s390/cio/cio.h
-@@ -11,32 +11,32 @@
-  * path management control word
-  */
- struct pmcw {
--	__u32 intparm;		/* interruption parameter */
--	__u32 qf   : 1;		/* qdio facility */
--	__u32 res0 : 1;		/* reserved zeros */
--	__u32 isc  : 3;		/* interruption sublass */
--	__u32 res5 : 3;		/* reserved zeros */
--	__u32 ena  : 1;		/* enabled */
--	__u32 lm   : 2;		/* limit mode */
--	__u32 mme  : 2;		/* measurement-mode enable */
--	__u32 mp   : 1;		/* multipath mode */
--	__u32 tf   : 1;		/* timing facility */
--	__u32 dnv  : 1;		/* device number valid */
--	__u32 dev  : 16;	/* device number */
--	__u8  lpm;		/* logical path mask */
--	__u8  pnom;		/* path not operational mask */
--	__u8  lpum;		/* last path used mask */
--	__u8  pim;		/* path installed mask */
--	__u16 mbi;		/* measurement-block index */
--	__u8  pom;		/* path operational mask */
--	__u8  pam;		/* path available mask */
--	__u8  chpid[8];		/* CHPID 0-7 (if available) */
--	__u32 unused1 : 8;	/* reserved zeros */
--	__u32 st      : 3;	/* subchannel type */
--	__u32 unused2 : 18;	/* reserved zeros */
--	__u32 mbfc    : 1;      /* measurement block format control */
--	__u32 xmwme   : 1;      /* extended measurement word mode enable */
--	__u32 csense  : 1;	/* concurrent sense; can be enabled ...*/
-+	u32 intparm;		/* interruption parameter */
-+	u32 qf	 : 1;		/* qdio facility */
-+	u32 res0 : 1;		/* reserved zeros */
-+	u32 isc  : 3;		/* interruption sublass */
-+	u32 res5 : 3;		/* reserved zeros */
-+	u32 ena  : 1;		/* enabled */
-+	u32 lm	 : 2;		/* limit mode */
-+	u32 mme  : 2;		/* measurement-mode enable */
-+	u32 mp	 : 1;		/* multipath mode */
-+	u32 tf	 : 1;		/* timing facility */
-+	u32 dnv  : 1;		/* device number valid */
-+	u32 dev  : 16;		/* device number */
-+	u8  lpm;		/* logical path mask */
-+	u8  pnom;		/* path not operational mask */
-+	u8  lpum;		/* last path used mask */
-+	u8  pim;		/* path installed mask */
-+	u16 mbi;		/* measurement-block index */
-+	u8  pom;		/* path operational mask */
-+	u8  pam;		/* path available mask */
-+	u8  chpid[8];		/* CHPID 0-7 (if available) */
-+	u32 unused1 : 8;	/* reserved zeros */
-+	u32 st	    : 3;	/* subchannel type */
-+	u32 unused2 : 18;	/* reserved zeros */
-+	u32 mbfc    : 1;	/* measurement block format control */
-+	u32 xmwme   : 1;	/* extended measurement word mode enable */
-+	u32 csense  : 1;	/* concurrent sense; can be enabled ...*/
- 				/*  ... per MSCH, however, if facility */
- 				/*  ... is not installed, this results */
- 				/*  ... in an operand exception.       */
-@@ -52,31 +52,6 @@ struct schib {
- 	__u8 mda[4];		 /* model dependent area */
- } __attribute__ ((packed,aligned(4)));
- 
--/*
-- * operation request block
-- */
--struct orb {
--	__u32 intparm;		/* interruption parameter */
--	__u32 key  : 4; 	/* flags, like key, suspend control, etc. */
--	__u32 spnd : 1; 	/* suspend control */
--	__u32 res1 : 1; 	/* reserved */
--	__u32 mod  : 1; 	/* modification control */
--	__u32 sync : 1; 	/* synchronize control */
--	__u32 fmt  : 1; 	/* format control */
--	__u32 pfch : 1; 	/* prefetch control */
--	__u32 isic : 1; 	/* initial-status-interruption control */
--	__u32 alcc : 1; 	/* address-limit-checking control */
--	__u32 ssic : 1; 	/* suppress-suspended-interr. control */
--	__u32 res2 : 1; 	/* reserved */
--	__u32 c64  : 1; 	/* IDAW/QDIO 64 bit control  */
--	__u32 i2k  : 1; 	/* IDAW 2/4kB block size control */
--	__u32 lpm  : 8; 	/* logical path mask */
--	__u32 ils  : 1; 	/* incorrect length */
--	__u32 zero : 6; 	/* reserved zeros */
--	__u32 orbx : 1; 	/* ORB extension control */
--	__u32 cpa;		/* channel program address */
--}  __attribute__ ((packed,aligned(4)));
--
- /* subchannel data structure used by I/O subroutines */
- struct subchannel {
- 	struct subchannel_id schid;
-@@ -85,7 +60,7 @@ struct subchannel {
- 	enum {
- 		SUBCHANNEL_TYPE_IO = 0,
- 		SUBCHANNEL_TYPE_CHSC = 1,
--		SUBCHANNEL_TYPE_MESSAGE = 2,
-+		SUBCHANNEL_TYPE_MSG = 2,
- 		SUBCHANNEL_TYPE_ADM = 3,
- 	} st;			/* subchannel type */
+-	struct class *class = &shost_class;
+ 	struct class_device *cdev;
+-	struct Scsi_Host *shost = ERR_PTR(-ENXIO), *p;
++	struct Scsi_Host *shost = ERR_PTR(-ENXIO);
  
-@@ -99,11 +74,10 @@ struct subchannel {
- 	__u8 lpm;		/* logical path mask */
- 	__u8 opm;               /* operational path mask */
- 	struct schib schib;	/* subchannel information block */
--	struct orb orb;		/* operation request block */
--	struct ccw1 sense_ccw;	/* static ccw for sense command */
- 	struct chsc_ssd_info ssd_info;	/* subchannel description */
- 	struct device dev;	/* entry in device tree */
- 	struct css_driver *driver;
-+	void *private; /* private per subchannel type data */
- } __attribute__ ((aligned(8)));
+-	down(&class->sem);
+-	list_for_each_entry(cdev, &class->children, node) {
+-		p = class_to_shost(cdev);
+-		if (p->host_no == hostnum) {
+-			shost = scsi_host_get(p);
+-			break;
+-		}
+-	}
+-	up(&class->sem);
++	cdev = class_find_child(&shost_class, &hostnum, __scsi_host_match);
++	if (cdev)
++		shost = scsi_host_get(class_to_shost(cdev));
  
- #define IO_INTERRUPT_TYPE	   0 /* I/O interrupt type */
-@@ -111,7 +85,7 @@ struct subchannel {
- #define to_subchannel(n) container_of(n, struct subchannel, dev)
+ 	return shost;
+ }
+diff --git a/drivers/scsi/hptiop.c b/drivers/scsi/hptiop.c
+index 0844331..e7b2f35 100644
+--- a/drivers/scsi/hptiop.c
++++ b/drivers/scsi/hptiop.c
+@@ -1,5 +1,5 @@
+ /*
+- * HighPoint RR3xxx controller driver for Linux
++ * HighPoint RR3xxx/4xxx controller driver for Linux
+  * Copyright (C) 2006-2007 HighPoint Technologies, Inc. All Rights Reserved.
+  *
+  * This program is free software; you can redistribute it and/or modify
+@@ -38,80 +38,84 @@
+ #include "hptiop.h"
  
- extern int cio_validate_subchannel (struct subchannel *, struct subchannel_id);
--extern int cio_enable_subchannel (struct subchannel *, unsigned int);
-+extern int cio_enable_subchannel(struct subchannel *, unsigned int, u32);
- extern int cio_disable_subchannel (struct subchannel *);
- extern int cio_cancel (struct subchannel *);
- extern int cio_clear (struct subchannel *);
-@@ -125,6 +99,7 @@ extern int cio_get_options (struct subchannel *);
- extern int cio_modify (struct subchannel *);
+ MODULE_AUTHOR("HighPoint Technologies, Inc.");
+-MODULE_DESCRIPTION("HighPoint RocketRAID 3xxx SATA Controller Driver");
++MODULE_DESCRIPTION("HighPoint RocketRAID 3xxx/4xxx Controller Driver");
  
- int cio_create_sch_lock(struct subchannel *);
-+void do_adapter_IO(void);
+ static char driver_name[] = "hptiop";
+-static const char driver_name_long[] = "RocketRAID 3xxx SATA Controller driver";
+-static const char driver_ver[] = "v1.2 (070830)";
+-
+-static void hptiop_host_request_callback(struct hptiop_hba *hba, u32 tag);
+-static void hptiop_iop_request_callback(struct hptiop_hba *hba, u32 tag);
++static const char driver_name_long[] = "RocketRAID 3xxx/4xxx Controller driver";
++static const char driver_ver[] = "v1.3 (071203)";
++
++static int iop_send_sync_msg(struct hptiop_hba *hba, u32 msg, u32 millisec);
++static void hptiop_finish_scsi_req(struct hptiop_hba *hba, u32 tag,
++				struct hpt_iop_request_scsi_command *req);
++static void hptiop_host_request_callback_itl(struct hptiop_hba *hba, u32 tag);
++static void hptiop_iop_request_callback_itl(struct hptiop_hba *hba, u32 tag);
+ static void hptiop_message_callback(struct hptiop_hba *hba, u32 msg);
  
- /* Use with care. */
- #ifdef CONFIG_CCW_CONSOLE
-@@ -133,10 +108,12 @@ extern void cio_release_console(void);
- extern int cio_is_console(struct subchannel_id);
- extern struct subchannel *cio_get_console_subchannel(void);
- extern spinlock_t * cio_get_console_lock(void);
-+extern void *cio_get_console_priv(void);
- #else
- #define cio_is_console(schid) 0
- #define cio_get_console_subchannel() NULL
--#define cio_get_console_lock() NULL;
-+#define cio_get_console_lock() NULL
-+#define cio_get_console_priv() NULL
- #endif
+-static inline void hptiop_pci_posting_flush(struct hpt_iopmu __iomem *iop)
+-{
+-	readl(&iop->outbound_intstatus);
+-}
+-
+-static int iop_wait_ready(struct hpt_iopmu __iomem *iop, u32 millisec)
++static int iop_wait_ready_itl(struct hptiop_hba *hba, u32 millisec)
+ {
+ 	u32 req = 0;
+ 	int i;
  
- extern int cio_show_msg;
-diff --git a/drivers/s390/cio/cio_debug.h b/drivers/s390/cio/cio_debug.h
-index c9bf898..d7429ef 100644
---- a/drivers/s390/cio/cio_debug.h
-+++ b/drivers/s390/cio/cio_debug.h
-@@ -8,20 +8,19 @@ extern debug_info_t *cio_debug_msg_id;
- extern debug_info_t *cio_debug_trace_id;
- extern debug_info_t *cio_debug_crw_id;
+ 	for (i = 0; i < millisec; i++) {
+-		req = readl(&iop->inbound_queue);
++		req = readl(&hba->u.itl.iop->inbound_queue);
+ 		if (req != IOPMU_QUEUE_EMPTY)
+ 			break;
+ 		msleep(1);
+ 	}
  
--#define CIO_TRACE_EVENT(imp, txt) do { \
-+#define CIO_TRACE_EVENT(imp, txt) do {				\
- 		debug_text_event(cio_debug_trace_id, imp, txt); \
- 	} while (0)
+ 	if (req != IOPMU_QUEUE_EMPTY) {
+-		writel(req, &iop->outbound_queue);
+-		hptiop_pci_posting_flush(iop);
++		writel(req, &hba->u.itl.iop->outbound_queue);
++		readl(&hba->u.itl.iop->outbound_intstatus);
+ 		return 0;
+ 	}
  
--#define CIO_MSG_EVENT(imp, args...) do { \
--		debug_sprintf_event(cio_debug_msg_id, imp , ##args); \
-+#define CIO_MSG_EVENT(imp, args...) do {				\
-+		debug_sprintf_event(cio_debug_msg_id, imp , ##args);	\
- 	} while (0)
+ 	return -1;
+ }
  
--#define CIO_CRW_EVENT(imp, args...) do { \
--		debug_sprintf_event(cio_debug_crw_id, imp , ##args); \
-+#define CIO_CRW_EVENT(imp, args...) do {				\
-+		debug_sprintf_event(cio_debug_crw_id, imp , ##args);	\
- 	} while (0)
+-static void hptiop_request_callback(struct hptiop_hba *hba, u32 tag)
++static int iop_wait_ready_mv(struct hptiop_hba *hba, u32 millisec)
++{
++	return iop_send_sync_msg(hba, IOPMU_INBOUND_MSG0_NOP, millisec);
++}
++
++static void hptiop_request_callback_itl(struct hptiop_hba *hba, u32 tag)
+ {
+ 	if (tag & IOPMU_QUEUE_ADDR_HOST_BIT)
+-		return hptiop_host_request_callback(hba,
++		hptiop_host_request_callback_itl(hba,
+ 				tag & ~IOPMU_QUEUE_ADDR_HOST_BIT);
+ 	else
+-		return hptiop_iop_request_callback(hba, tag);
++		hptiop_iop_request_callback_itl(hba, tag);
+ }
  
--static inline void
--CIO_HEX_EVENT(int level, void *data, int length)
-+static inline void CIO_HEX_EVENT(int level, void *data, int length)
+-static inline void hptiop_drain_outbound_queue(struct hptiop_hba *hba)
++static void hptiop_drain_outbound_queue_itl(struct hptiop_hba *hba)
  {
- 	if (unlikely(!cio_debug_trace_id))
- 		return;
-@@ -32,9 +31,10 @@ CIO_HEX_EVENT(int level, void *data, int length)
+ 	u32 req;
+ 
+-	while ((req = readl(&hba->iop->outbound_queue)) != IOPMU_QUEUE_EMPTY) {
++	while ((req = readl(&hba->u.itl.iop->outbound_queue)) !=
++						IOPMU_QUEUE_EMPTY) {
+ 
+ 		if (req & IOPMU_QUEUE_MASK_HOST_BITS)
+-			hptiop_request_callback(hba, req);
++			hptiop_request_callback_itl(hba, req);
+ 		else {
+ 			struct hpt_iop_request_header __iomem * p;
+ 
+ 			p = (struct hpt_iop_request_header __iomem *)
+-				((char __iomem *)hba->iop + req);
++				((char __iomem *)hba->u.itl.iop + req);
+ 
+ 			if (readl(&p->flags) & IOP_REQUEST_FLAG_SYNC_REQUEST) {
+ 				if (readl(&p->context))
+-					hptiop_request_callback(hba, req);
++					hptiop_request_callback_itl(hba, req);
+ 				else
+ 					writel(1, &p->context);
+ 			}
+ 			else
+-				hptiop_request_callback(hba, req);
++				hptiop_request_callback_itl(hba, req);
+ 		}
  	}
  }
  
--#define CIO_DEBUG(printk_level,event_level,msg...) ({ \
--	if (cio_show_msg) printk(printk_level msg); \
--	CIO_MSG_EVENT (event_level, msg); \
--})
-+#define CIO_DEBUG(printk_level, event_level, msg...) do {	\
-+		if (cio_show_msg)				\
-+			printk(printk_level "cio: " msg);	\
-+		CIO_MSG_EVENT(event_level, msg);		\
-+	} while (0)
+-static int __iop_intr(struct hptiop_hba *hba)
++static int iop_intr_itl(struct hptiop_hba *hba)
+ {
+-	struct hpt_iopmu __iomem *iop = hba->iop;
++	struct hpt_iopmu_itl __iomem *iop = hba->u.itl.iop;
+ 	u32 status;
+ 	int ret = 0;
  
- #endif
-diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c
-index c3df2cd..3b45bbe 100644
---- a/drivers/s390/cio/css.c
-+++ b/drivers/s390/cio/css.c
-@@ -51,6 +51,62 @@ for_each_subchannel(int(*fn)(struct subchannel_id, void *), void *data)
- 	return ret;
- }
+@@ -119,6 +123,7 @@ static int __iop_intr(struct hptiop_hba *hba)
  
-+struct cb_data {
-+	void *data;
-+	struct idset *set;
-+	int (*fn_known_sch)(struct subchannel *, void *);
-+	int (*fn_unknown_sch)(struct subchannel_id, void *);
-+};
+ 	if (status & IOPMU_OUTBOUND_INT_MSG0) {
+ 		u32 msg = readl(&iop->outbound_msgaddr0);
 +
-+static int call_fn_known_sch(struct device *dev, void *data)
-+{
-+	struct subchannel *sch = to_subchannel(dev);
-+	struct cb_data *cb = data;
-+	int rc = 0;
+ 		dprintk("received outbound msg %x\n", msg);
+ 		writel(IOPMU_OUTBOUND_INT_MSG0, &iop->outbound_intstatus);
+ 		hptiop_message_callback(hba, msg);
+@@ -126,31 +131,115 @@ static int __iop_intr(struct hptiop_hba *hba)
+ 	}
+ 
+ 	if (status & IOPMU_OUTBOUND_INT_POSTQUEUE) {
+-		hptiop_drain_outbound_queue(hba);
++		hptiop_drain_outbound_queue_itl(hba);
++		ret = 1;
++	}
 +
-+	idset_sch_del(cb->set, sch->schid);
-+	if (cb->fn_known_sch)
-+		rc = cb->fn_known_sch(sch, cb->data);
-+	return rc;
++	return ret;
 +}
 +
-+static int call_fn_unknown_sch(struct subchannel_id schid, void *data)
++static u64 mv_outbound_read(struct hpt_iopmu_mv __iomem *mu)
 +{
-+	struct cb_data *cb = data;
-+	int rc = 0;
++	u32 outbound_tail = readl(&mu->outbound_tail);
++	u32 outbound_head = readl(&mu->outbound_head);
 +
-+	if (idset_sch_contains(cb->set, schid))
-+		rc = cb->fn_unknown_sch(schid, cb->data);
-+	return rc;
++	if (outbound_tail != outbound_head) {
++		u64 p;
++
++		memcpy_fromio(&p, &mu->outbound_q[mu->outbound_tail], 8);
++		outbound_tail++;
++
++		if (outbound_tail == MVIOP_QUEUE_LEN)
++			outbound_tail = 0;
++		writel(outbound_tail, &mu->outbound_tail);
++		return p;
++	} else
++		return 0;
 +}
 +
-+int for_each_subchannel_staged(int (*fn_known)(struct subchannel *, void *),
-+			       int (*fn_unknown)(struct subchannel_id,
-+			       void *), void *data)
++static void mv_inbound_write(u64 p, struct hptiop_hba *hba)
 +{
-+	struct cb_data cb;
-+	int rc;
++	u32 inbound_head = readl(&hba->u.mv.mu->inbound_head);
++	u32 head = inbound_head + 1;
 +
-+	cb.set = idset_sch_new();
-+	if (!cb.set)
-+		return -ENOMEM;
-+	idset_fill(cb.set);
-+	cb.data = data;
-+	cb.fn_known_sch = fn_known;
-+	cb.fn_unknown_sch = fn_unknown;
-+	/* Process registered subchannels. */
-+	rc = bus_for_each_dev(&css_bus_type, NULL, &cb, call_fn_known_sch);
-+	if (rc)
-+		goto out;
-+	/* Process unregistered subchannels. */
-+	if (fn_unknown)
-+		rc = for_each_subchannel(call_fn_unknown_sch, &cb);
-+out:
-+	idset_free(cb.set);
++	if (head == MVIOP_QUEUE_LEN)
++		head = 0;
 +
-+	return rc;
++	memcpy_toio(&hba->u.mv.mu->inbound_q[inbound_head], &p, 8);
++	writel(head, &hba->u.mv.mu->inbound_head);
++	writel(MVIOP_MU_INBOUND_INT_POSTQUEUE,
++			&hba->u.mv.regs->inbound_doorbell);
 +}
 +
- static struct subchannel *
- css_alloc_subchannel(struct subchannel_id schid)
- {
-@@ -77,7 +133,7 @@ css_alloc_subchannel(struct subchannel_id schid)
- 	 * This is fine even on 64bit since the subchannel is always located
- 	 * under 2G.
- 	 */
--	sch->schib.pmcw.intparm = (__u32)(unsigned long)sch;
-+	sch->schib.pmcw.intparm = (u32)(addr_t)sch;
- 	ret = cio_modify(sch);
- 	if (ret) {
- 		kfree(sch->lock);
-@@ -237,11 +293,25 @@ get_subchannel_by_schid(struct subchannel_id schid)
- 	return dev ? to_subchannel(dev) : NULL;
- }
- 
-+/**
-+ * css_sch_is_valid() - check if a subchannel is valid
-+ * @schib: subchannel information block for the subchannel
-+ */
-+int css_sch_is_valid(struct schib *schib)
++static void hptiop_request_callback_mv(struct hptiop_hba *hba, u64 tag)
 +{
-+	if ((schib->pmcw.st == SUBCHANNEL_TYPE_IO) && !schib->pmcw.dnv)
-+		return 0;
-+	return 1;
++	u32 req_type = (tag >> 5) & 0x7;
++	struct hpt_iop_request_scsi_command *req;
++
++	dprintk("hptiop_request_callback_mv: tag=%llx\n", tag);
++
++	BUG_ON((tag & MVIOP_MU_QUEUE_REQUEST_RETURN_CONTEXT) == 0);
++
++	switch (req_type) {
++	case IOP_REQUEST_TYPE_GET_CONFIG:
++	case IOP_REQUEST_TYPE_SET_CONFIG:
++		hba->msg_done = 1;
++		break;
++
++	case IOP_REQUEST_TYPE_SCSI_COMMAND:
++		req = hba->reqs[tag >> 8].req_virt;
++		if (likely(tag & MVIOP_MU_QUEUE_REQUEST_RESULT_BIT))
++			req->header.result = cpu_to_le32(IOP_RESULT_SUCCESS);
++
++		hptiop_finish_scsi_req(hba, tag>>8, req);
++		break;
++
++	default:
++		break;
++	}
 +}
-+EXPORT_SYMBOL_GPL(css_sch_is_valid);
 +
- static int css_get_subchannel_status(struct subchannel *sch)
++static int iop_intr_mv(struct hptiop_hba *hba)
++{
++	u32 status;
++	int ret = 0;
++
++	status = readl(&hba->u.mv.regs->outbound_doorbell);
++	writel(~status, &hba->u.mv.regs->outbound_doorbell);
++
++	if (status & MVIOP_MU_OUTBOUND_INT_MSG) {
++		u32 msg;
++		msg = readl(&hba->u.mv.mu->outbound_msg);
++		dprintk("received outbound msg %x\n", msg);
++		hptiop_message_callback(hba, msg);
++		ret = 1;
++	}
++
++	if (status & MVIOP_MU_OUTBOUND_INT_POSTQUEUE) {
++		u64 tag;
++
++		while ((tag = mv_outbound_read(hba->u.mv.mu)))
++			hptiop_request_callback_mv(hba, tag);
+ 		ret = 1;
+ 	}
+ 
+ 	return ret;
+ }
+ 
+-static int iop_send_sync_request(struct hptiop_hba *hba,
++static int iop_send_sync_request_itl(struct hptiop_hba *hba,
+ 					void __iomem *_req, u32 millisec)
  {
- 	struct schib schib;
+ 	struct hpt_iop_request_header __iomem *req = _req;
+ 	u32 i;
  
--	if (stsch(sch->schid, &schib) || !schib.pmcw.dnv)
-+	if (stsch(sch->schid, &schib))
-+		return CIO_GONE;
-+	if (!css_sch_is_valid(&schib))
- 		return CIO_GONE;
- 	if (sch->schib.pmcw.dnv && (schib.pmcw.dev != sch->schib.pmcw.dev))
- 		return CIO_REVALIDATE;
-@@ -293,7 +363,7 @@ static int css_evaluate_known_subchannel(struct subchannel *sch, int slow)
- 		action = UNREGISTER;
- 		if (sch->driver && sch->driver->notify) {
- 			spin_unlock_irqrestore(sch->lock, flags);
--			ret = sch->driver->notify(&sch->dev, event);
-+			ret = sch->driver->notify(sch, event);
- 			spin_lock_irqsave(sch->lock, flags);
- 			if (ret)
- 				action = NONE;
-@@ -349,7 +419,7 @@ static int css_evaluate_new_subchannel(struct subchannel_id schid, int slow)
- 		/* Will be done on the slow path. */
- 		return -EAGAIN;
- 	}
--	if (stsch_err(schid, &schib) || !schib.pmcw.dnv) {
-+	if (stsch_err(schid, &schib) || !css_sch_is_valid(&schib)) {
- 		/* Unusable - ignore. */
- 		return 0;
- 	}
-@@ -388,20 +458,56 @@ static int __init slow_subchannel_init(void)
- 	return 0;
+-	writel(readl(&req->flags) | IOP_REQUEST_FLAG_SYNC_REQUEST,
+-			&req->flags);
+-
++	writel(readl(&req->flags) | IOP_REQUEST_FLAG_SYNC_REQUEST, &req->flags);
+ 	writel(0, &req->context);
+-
+-	writel((unsigned long)req - (unsigned long)hba->iop,
+-			&hba->iop->inbound_queue);
+-
+-	hptiop_pci_posting_flush(hba->iop);
++	writel((unsigned long)req - (unsigned long)hba->u.itl.iop,
++			&hba->u.itl.iop->inbound_queue);
++	readl(&hba->u.itl.iop->outbound_intstatus);
+ 
+ 	for (i = 0; i < millisec; i++) {
+-		__iop_intr(hba);
++		iop_intr_itl(hba);
+ 		if (readl(&req->context))
+ 			return 0;
+ 		msleep(1);
+@@ -159,19 +248,49 @@ static int iop_send_sync_request(struct hptiop_hba *hba,
+ 	return -1;
  }
  
--static void css_slow_path_func(struct work_struct *unused)
-+static int slow_eval_known_fn(struct subchannel *sch, void *data)
+-static int iop_send_sync_msg(struct hptiop_hba *hba, u32 msg, u32 millisec)
++static int iop_send_sync_request_mv(struct hptiop_hba *hba,
++					u32 size_bits, u32 millisec)
  {
--	struct subchannel_id schid;
-+	int eval;
-+	int rc;
++	struct hpt_iop_request_header *reqhdr = hba->u.mv.internal_req;
+ 	u32 i;
  
--	CIO_TRACE_EVENT(4, "slowpath");
- 	spin_lock_irq(&slow_subchannel_lock);
--	init_subchannel_id(&schid);
--	while (idset_sch_get_first(slow_subchannel_set, &schid)) {
--		idset_sch_del(slow_subchannel_set, schid);
--		spin_unlock_irq(&slow_subchannel_lock);
--		css_evaluate_subchannel(schid, 1);
--		spin_lock_irq(&slow_subchannel_lock);
-+	eval = idset_sch_contains(slow_subchannel_set, sch->schid);
-+	idset_sch_del(slow_subchannel_set, sch->schid);
-+	spin_unlock_irq(&slow_subchannel_lock);
-+	if (eval) {
-+		rc = css_evaluate_known_subchannel(sch, 1);
-+		if (rc == -EAGAIN)
-+			css_schedule_eval(sch->schid);
- 	}
-+	return 0;
+ 	hba->msg_done = 0;
++	reqhdr->flags |= cpu_to_le32(IOP_REQUEST_FLAG_SYNC_REQUEST);
++	mv_inbound_write(hba->u.mv.internal_req_phy |
++			MVIOP_MU_QUEUE_ADDR_HOST_BIT | size_bits, hba);
++
++	for (i = 0; i < millisec; i++) {
++		iop_intr_mv(hba);
++		if (hba->msg_done)
++			return 0;
++		msleep(1);
++	}
++	return -1;
 +}
 +
-+static int slow_eval_unknown_fn(struct subchannel_id schid, void *data)
++static void hptiop_post_msg_itl(struct hptiop_hba *hba, u32 msg)
 +{
-+	int eval;
-+	int rc = 0;
-+
-+	spin_lock_irq(&slow_subchannel_lock);
-+	eval = idset_sch_contains(slow_subchannel_set, schid);
-+	idset_sch_del(slow_subchannel_set, schid);
- 	spin_unlock_irq(&slow_subchannel_lock);
-+	if (eval) {
-+		rc = css_evaluate_new_subchannel(schid, 1);
-+		switch (rc) {
-+		case -EAGAIN:
-+			css_schedule_eval(schid);
-+			rc = 0;
-+			break;
-+		case -ENXIO:
-+		case -ENOMEM:
-+		case -EIO:
-+			/* These should abort looping */
-+			break;
-+		default:
-+			rc = 0;
-+		}
-+	}
-+	return rc;
++	writel(msg, &hba->u.itl.iop->inbound_msgaddr0);
++	readl(&hba->u.itl.iop->outbound_intstatus);
 +}
 +
-+static void css_slow_path_func(struct work_struct *unused)
++static void hptiop_post_msg_mv(struct hptiop_hba *hba, u32 msg)
 +{
-+	CIO_TRACE_EVENT(4, "slowpath");
-+	for_each_subchannel_staged(slow_eval_known_fn, slow_eval_unknown_fn,
-+				   NULL);
++	writel(msg, &hba->u.mv.mu->inbound_msg);
++	writel(MVIOP_MU_INBOUND_INT_MSG, &hba->u.mv.regs->inbound_doorbell);
++	readl(&hba->u.mv.regs->inbound_doorbell);
++}
+ 
+-	writel(msg, &hba->iop->inbound_msgaddr0);
++static int iop_send_sync_msg(struct hptiop_hba *hba, u32 msg, u32 millisec)
++{
++	u32 i;
+ 
+-	hptiop_pci_posting_flush(hba->iop);
++	hba->msg_done = 0;
++	hba->ops->post_msg(hba, msg);
+ 
+ 	for (i = 0; i < millisec; i++) {
+ 		spin_lock_irq(hba->host->host_lock);
+-		__iop_intr(hba);
++		hba->ops->iop_intr(hba);
+ 		spin_unlock_irq(hba->host->host_lock);
+ 		if (hba->msg_done)
+ 			break;
+@@ -181,46 +300,67 @@ static int iop_send_sync_msg(struct hptiop_hba *hba, u32 msg, u32 millisec)
+ 	return hba->msg_done? 0 : -1;
  }
  
- static DECLARE_WORK(slow_path_work, css_slow_path_func);
-@@ -430,7 +536,6 @@ void css_schedule_eval_all(void)
- /* Reprobe subchannel if unregistered. */
- static int reprobe_subchannel(struct subchannel_id schid, void *data)
+-static int iop_get_config(struct hptiop_hba *hba,
++static int iop_get_config_itl(struct hptiop_hba *hba,
+ 				struct hpt_iop_request_get_config *config)
  {
--	struct subchannel *sch;
- 	int ret;
+ 	u32 req32;
+ 	struct hpt_iop_request_get_config __iomem *req;
  
- 	CIO_MSG_EVENT(6, "cio: reprobe 0.%x.%04x\n",
-@@ -438,13 +543,6 @@ static int reprobe_subchannel(struct subchannel_id schid, void *data)
- 	if (need_reprobe)
- 		return -EAGAIN;
+-	req32 = readl(&hba->iop->inbound_queue);
++	req32 = readl(&hba->u.itl.iop->inbound_queue);
+ 	if (req32 == IOPMU_QUEUE_EMPTY)
+ 		return -1;
  
--	sch = get_subchannel_by_schid(schid);
--	if (sch) {
--		/* Already known. */
--		put_device(&sch->dev);
--		return 0;
--	}
--
- 	ret = css_probe_device(schid);
- 	switch (ret) {
- 	case 0:
-@@ -472,7 +570,7 @@ static void reprobe_all(struct work_struct *unused)
- 	/* Make sure initial subchannel scan is done. */
- 	wait_event(ccw_device_init_wq,
- 		   atomic_read(&ccw_device_init_count) == 0);
--	ret = for_each_subchannel(reprobe_subchannel, NULL);
-+	ret = for_each_subchannel_staged(NULL, reprobe_subchannel, NULL);
+ 	req = (struct hpt_iop_request_get_config __iomem *)
+-			((unsigned long)hba->iop + req32);
++			((unsigned long)hba->u.itl.iop + req32);
  
- 	CIO_MSG_EVENT(2, "reprobe done (rc=%d, need_reprobe=%d)\n", ret,
- 		      need_reprobe);
-@@ -787,8 +885,8 @@ int sch_is_pseudo_sch(struct subchannel *sch)
- static int
- css_bus_match (struct device *dev, struct device_driver *drv)
- {
--	struct subchannel *sch = container_of (dev, struct subchannel, dev);
--	struct css_driver *driver = container_of (drv, struct css_driver, drv);
-+	struct subchannel *sch = to_subchannel(dev);
-+	struct css_driver *driver = to_cssdriver(drv);
+ 	writel(0, &req->header.flags);
+ 	writel(IOP_REQUEST_TYPE_GET_CONFIG, &req->header.type);
+ 	writel(sizeof(struct hpt_iop_request_get_config), &req->header.size);
+ 	writel(IOP_RESULT_PENDING, &req->header.result);
  
- 	if (sch->st == driver->subchannel_type)
- 		return 1;
-@@ -796,32 +894,36 @@ css_bus_match (struct device *dev, struct device_driver *drv)
+-	if (iop_send_sync_request(hba, req, 20000)) {
++	if (iop_send_sync_request_itl(hba, req, 20000)) {
+ 		dprintk("Get config send cmd failed\n");
+ 		return -1;
+ 	}
+ 
+ 	memcpy_fromio(config, req, sizeof(*config));
+-	writel(req32, &hba->iop->outbound_queue);
++	writel(req32, &hba->u.itl.iop->outbound_queue);
++	return 0;
++}
++
++static int iop_get_config_mv(struct hptiop_hba *hba,
++				struct hpt_iop_request_get_config *config)
++{
++	struct hpt_iop_request_get_config *req = hba->u.mv.internal_req;
++
++	req->header.flags = cpu_to_le32(IOP_REQUEST_FLAG_OUTPUT_CONTEXT);
++	req->header.type = cpu_to_le32(IOP_REQUEST_TYPE_GET_CONFIG);
++	req->header.size =
++		cpu_to_le32(sizeof(struct hpt_iop_request_get_config));
++	req->header.result = cpu_to_le32(IOP_RESULT_PENDING);
++	req->header.context = cpu_to_le64(IOP_REQUEST_TYPE_GET_CONFIG<<5);
++
++	if (iop_send_sync_request_mv(hba, 0, 20000)) {
++		dprintk("Get config send cmd failed\n");
++		return -1;
++	}
++
++	memcpy(config, req, sizeof(struct hpt_iop_request_get_config));
  	return 0;
  }
  
--static int
--css_probe (struct device *dev)
-+static int css_probe(struct device *dev)
+-static int iop_set_config(struct hptiop_hba *hba,
++static int iop_set_config_itl(struct hptiop_hba *hba,
+ 				struct hpt_iop_request_set_config *config)
  {
- 	struct subchannel *sch;
-+	int ret;
+ 	u32 req32;
+ 	struct hpt_iop_request_set_config __iomem *req;
  
- 	sch = to_subchannel(dev);
--	sch->driver = container_of (dev->driver, struct css_driver, drv);
--	return (sch->driver->probe ? sch->driver->probe(sch) : 0);
-+	sch->driver = to_cssdriver(dev->driver);
-+	ret = sch->driver->probe ? sch->driver->probe(sch) : 0;
-+	if (ret)
-+		sch->driver = NULL;
-+	return ret;
- }
+-	req32 = readl(&hba->iop->inbound_queue);
++	req32 = readl(&hba->u.itl.iop->inbound_queue);
+ 	if (req32 == IOPMU_QUEUE_EMPTY)
+ 		return -1;
  
--static int
--css_remove (struct device *dev)
-+static int css_remove(struct device *dev)
- {
- 	struct subchannel *sch;
-+	int ret;
+ 	req = (struct hpt_iop_request_set_config __iomem *)
+-			((unsigned long)hba->iop + req32);
++			((unsigned long)hba->u.itl.iop + req32);
  
- 	sch = to_subchannel(dev);
--	return (sch->driver->remove ? sch->driver->remove(sch) : 0);
-+	ret = sch->driver->remove ? sch->driver->remove(sch) : 0;
-+	sch->driver = NULL;
-+	return ret;
- }
+ 	memcpy_toio((u8 __iomem *)req + sizeof(struct hpt_iop_request_header),
+ 		(u8 *)config + sizeof(struct hpt_iop_request_header),
+@@ -232,22 +372,52 @@ static int iop_set_config(struct hptiop_hba *hba,
+ 	writel(sizeof(struct hpt_iop_request_set_config), &req->header.size);
+ 	writel(IOP_RESULT_PENDING, &req->header.result);
  
--static void
--css_shutdown (struct device *dev)
-+static void css_shutdown(struct device *dev)
- {
- 	struct subchannel *sch;
+-	if (iop_send_sync_request(hba, req, 20000)) {
++	if (iop_send_sync_request_itl(hba, req, 20000)) {
+ 		dprintk("Set config send cmd failed\n");
+ 		return -1;
+ 	}
  
- 	sch = to_subchannel(dev);
--	if (sch->driver->shutdown)
-+	if (sch->driver && sch->driver->shutdown)
- 		sch->driver->shutdown(sch);
+-	writel(req32, &hba->iop->outbound_queue);
++	writel(req32, &hba->u.itl.iop->outbound_queue);
+ 	return 0;
  }
  
-@@ -833,6 +935,34 @@ struct bus_type css_bus_type = {
- 	.shutdown = css_shutdown,
- };
+-static int hptiop_initialize_iop(struct hptiop_hba *hba)
++static int iop_set_config_mv(struct hptiop_hba *hba,
++				struct hpt_iop_request_set_config *config)
+ {
+-	struct hpt_iopmu __iomem *iop = hba->iop;
++	struct hpt_iop_request_set_config *req = hba->u.mv.internal_req;
  
-+/**
-+ * css_driver_register - register a css driver
-+ * @cdrv: css driver to register
-+ *
-+ * This is mainly a wrapper around driver_register that sets name
-+ * and bus_type in the embedded struct device_driver correctly.
-+ */
-+int css_driver_register(struct css_driver *cdrv)
+-	/* enable interrupts */
++	memcpy(req, config, sizeof(struct hpt_iop_request_set_config));
++	req->header.flags = cpu_to_le32(IOP_REQUEST_FLAG_OUTPUT_CONTEXT);
++	req->header.type = cpu_to_le32(IOP_REQUEST_TYPE_SET_CONFIG);
++	req->header.size =
++		cpu_to_le32(sizeof(struct hpt_iop_request_set_config));
++	req->header.result = cpu_to_le32(IOP_RESULT_PENDING);
++	req->header.context = cpu_to_le64(IOP_REQUEST_TYPE_SET_CONFIG<<5);
++
++	if (iop_send_sync_request_mv(hba, 0, 20000)) {
++		dprintk("Set config send cmd failed\n");
++		return -1;
++	}
++
++	return 0;
++}
++
++static void hptiop_enable_intr_itl(struct hptiop_hba *hba)
 +{
-+	cdrv->drv.name = cdrv->name;
-+	cdrv->drv.bus = &css_bus_type;
-+	cdrv->drv.owner = cdrv->owner;
-+	return driver_register(&cdrv->drv);
+ 	writel(~(IOPMU_OUTBOUND_INT_POSTQUEUE | IOPMU_OUTBOUND_INT_MSG0),
+-			&iop->outbound_intmask);
++		&hba->u.itl.iop->outbound_intmask);
 +}
-+EXPORT_SYMBOL_GPL(css_driver_register);
 +
-+/**
-+ * css_driver_unregister - unregister a css driver
-+ * @cdrv: css driver to unregister
-+ *
-+ * This is a wrapper around driver_unregister.
-+ */
-+void css_driver_unregister(struct css_driver *cdrv)
++static void hptiop_enable_intr_mv(struct hptiop_hba *hba)
 +{
-+	driver_unregister(&cdrv->drv);
++	writel(MVIOP_MU_OUTBOUND_INT_POSTQUEUE | MVIOP_MU_OUTBOUND_INT_MSG,
++		&hba->u.mv.regs->outbound_intmask);
 +}
-+EXPORT_SYMBOL_GPL(css_driver_unregister);
 +
- subsys_initcall(init_channel_subsystem);
++static int hptiop_initialize_iop(struct hptiop_hba *hba)
++{
++	/* enable interrupts */
++	hba->ops->enable_intr(hba);
  
- MODULE_LICENSE("GPL");
-diff --git a/drivers/s390/cio/css.h b/drivers/s390/cio/css.h
-index 81215ef..b705545 100644
---- a/drivers/s390/cio/css.h
-+++ b/drivers/s390/cio/css.h
-@@ -58,64 +58,6 @@ struct pgid {
- 	__u32 tod_high;		/* high word TOD clock */
- } __attribute__ ((packed));
+ 	hba->initialized = 1;
  
--#define MAX_CIWS 8
--
--/*
-- * sense-id response buffer layout
-- */
--struct senseid {
--	/* common part */
--	__u8  reserved;     	/* always 0x'FF' */
--	__u16 cu_type;	     	/* control unit type */
--	__u8  cu_model;     	/* control unit model */
--	__u16 dev_type;     	/* device type */
--	__u8  dev_model;    	/* device model */
--	__u8  unused;	     	/* padding byte */
--	/* extended part */
--	struct ciw ciw[MAX_CIWS];	/* variable # of CIWs */
--}  __attribute__ ((packed,aligned(4)));
--
--struct ccw_device_private {
--	struct ccw_device *cdev;
--	struct subchannel *sch;
--	int state;		/* device state */
--	atomic_t onoff;
--	unsigned long registered;
--	struct ccw_dev_id dev_id;	/* device id */
--	struct subchannel_id schid;	/* subchannel number */
--	__u8 imask;		/* lpm mask for SNID/SID/SPGID */
--	int iretry;		/* retry counter SNID/SID/SPGID */
--	struct {
--		unsigned int fast:1;	/* post with "channel end" */
--		unsigned int repall:1;	/* report every interrupt status */
--		unsigned int pgroup:1;  /* do path grouping */
--		unsigned int force:1;   /* allow forced online */
--	} __attribute__ ((packed)) options;
--	struct {
--		unsigned int pgid_single:1; /* use single path for Set PGID */
--		unsigned int esid:1;        /* Ext. SenseID supported by HW */
--		unsigned int dosense:1;	    /* delayed SENSE required */
--		unsigned int doverify:1;    /* delayed path verification */
--		unsigned int donotify:1;    /* call notify function */
--		unsigned int recog_done:1;  /* dev. recog. complete */
--		unsigned int fake_irb:1;    /* deliver faked irb */
--		unsigned int intretry:1;    /* retry internal operation */
--	} __attribute__((packed)) flags;
--	unsigned long intparm;	/* user interruption parameter */
--	struct qdio_irq *qdio_data;
--	struct irb irb;		/* device status */
--	struct senseid senseid;	/* SenseID info */
--	struct pgid pgid[8];	/* path group IDs per chpid*/
--	struct ccw1 iccws[2];	/* ccws for SNID/SID/SPGID commands */
--	struct work_struct kick_work;
--	wait_queue_head_t wait_q;
--	struct timer_list timer;
--	void *cmb;			/* measurement information */
--	struct list_head cmb_list;	/* list of measured devices */
--	u64 cmb_start_time;		/* clock value of cmb reset */
--	void *cmb_wait;			/* deferred cmb enable/disable */
--};
--
- /*
-  * A css driver handles all subchannels of one type.
-  * Currently, we only care about I/O subchannels (type 0), these
-@@ -123,25 +65,35 @@ struct ccw_device_private {
-  */
- struct subchannel;
- struct css_driver {
-+	struct module *owner;
- 	unsigned int subchannel_type;
- 	struct device_driver drv;
--	void (*irq)(struct device *);
--	int (*notify)(struct device *, int);
--	void (*verify)(struct device *);
--	void (*termination)(struct device *);
-+	void (*irq)(struct subchannel *);
-+	int (*notify)(struct subchannel *, int);
-+	void (*verify)(struct subchannel *);
-+	void (*termination)(struct subchannel *);
- 	int (*probe)(struct subchannel *);
- 	int (*remove)(struct subchannel *);
- 	void (*shutdown)(struct subchannel *);
-+	const char *name;
- };
+@@ -261,37 +431,74 @@ static int hptiop_initialize_iop(struct hptiop_hba *hba)
+ 	return 0;
+ }
  
-+#define to_cssdriver(n) container_of(n, struct css_driver, drv)
+-static int hptiop_map_pci_bar(struct hptiop_hba *hba)
++static void __iomem *hptiop_map_pci_bar(struct hptiop_hba *hba, int index)
+ {
+ 	u32 mem_base_phy, length;
+ 	void __iomem *mem_base_virt;
 +
- /*
-  * all css_drivers have the css_bus_type
-  */
- extern struct bus_type css_bus_type;
+ 	struct pci_dev *pcidev = hba->pcidev;
  
-+extern int css_driver_register(struct css_driver *);
-+extern void css_driver_unregister(struct css_driver *);
+-	if (!(pci_resource_flags(pcidev, 0) & IORESOURCE_MEM)) {
 +
- extern void css_sch_device_unregister(struct subchannel *);
- extern struct subchannel * get_subchannel_by_schid(struct subchannel_id);
- extern int css_init_done;
-+int for_each_subchannel_staged(int (*fn_known)(struct subchannel *, void *),
-+			       int (*fn_unknown)(struct subchannel_id,
-+			       void *), void *data);
- extern int for_each_subchannel(int(*fn)(struct subchannel_id, void *), void *);
- extern void css_process_crw(int, int);
- extern void css_reiterate_subchannels(void);
-@@ -188,6 +140,8 @@ void css_schedule_eval(struct subchannel_id schid);
- void css_schedule_eval_all(void);
- 
- int sch_is_pseudo_sch(struct subchannel *);
-+struct schib;
-+int css_sch_is_valid(struct schib *);
- 
- extern struct workqueue_struct *slow_path_wq;
++	if (!(pci_resource_flags(pcidev, index) & IORESOURCE_MEM)) {
+ 		printk(KERN_ERR "scsi%d: pci resource invalid\n",
+ 				hba->host->host_no);
+-		return -1;
++		return 0;
+ 	}
  
-diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c
-index 74f6b53..d35dc3f 100644
---- a/drivers/s390/cio/device.c
-+++ b/drivers/s390/cio/device.c
-@@ -17,6 +17,7 @@
- #include <linux/list.h>
- #include <linux/device.h>
- #include <linux/workqueue.h>
-+#include <linux/timer.h>
+-	mem_base_phy = pci_resource_start(pcidev, 0);
+-	length = pci_resource_len(pcidev, 0);
++	mem_base_phy = pci_resource_start(pcidev, index);
++	length = pci_resource_len(pcidev, index);
+ 	mem_base_virt = ioremap(mem_base_phy, length);
  
- #include <asm/ccwdev.h>
- #include <asm/cio.h>
-@@ -28,6 +29,12 @@
- #include "css.h"
- #include "device.h"
- #include "ioasm.h"
-+#include "io_sch.h"
+ 	if (!mem_base_virt) {
+ 		printk(KERN_ERR "scsi%d: Fail to ioremap memory space\n",
+ 				hba->host->host_no);
++		return 0;
++	}
++	return mem_base_virt;
++}
 +
-+static struct timer_list recovery_timer;
-+static spinlock_t recovery_lock;
-+static int recovery_phase;
-+static const unsigned long recovery_delay[] = { 3, 30, 300 };
- 
- /******************* bus type handling ***********************/
- 
-@@ -115,19 +122,18 @@ static int ccw_uevent(struct device *dev, struct kobj_uevent_env *env)
- 
- struct bus_type ccw_bus_type;
- 
--static int io_subchannel_probe (struct subchannel *);
--static int io_subchannel_remove (struct subchannel *);
--static int io_subchannel_notify(struct device *, int);
--static void io_subchannel_verify(struct device *);
--static void io_subchannel_ioterm(struct device *);
-+static void io_subchannel_irq(struct subchannel *);
-+static int io_subchannel_probe(struct subchannel *);
-+static int io_subchannel_remove(struct subchannel *);
-+static int io_subchannel_notify(struct subchannel *, int);
-+static void io_subchannel_verify(struct subchannel *);
-+static void io_subchannel_ioterm(struct subchannel *);
- static void io_subchannel_shutdown(struct subchannel *);
- 
- static struct css_driver io_subchannel_driver = {
-+	.owner = THIS_MODULE,
- 	.subchannel_type = SUBCHANNEL_TYPE_IO,
--	.drv = {
--		.name = "io_subchannel",
--		.bus  = &css_bus_type,
--	},
-+	.name = "io_subchannel",
- 	.irq = io_subchannel_irq,
- 	.notify = io_subchannel_notify,
- 	.verify = io_subchannel_verify,
-@@ -142,6 +148,8 @@ struct workqueue_struct *ccw_device_notify_work;
- wait_queue_head_t ccw_device_init_wq;
- atomic_t ccw_device_init_count;
- 
-+static void recovery_func(unsigned long data);
++static int hptiop_map_pci_bar_itl(struct hptiop_hba *hba)
++{
++	hba->u.itl.iop = hptiop_map_pci_bar(hba, 0);
++	if (hba->u.itl.iop)
++		return 0;
++	else
++		return -1;
++}
 +
- static int __init
- init_ccw_bus_type (void)
- {
-@@ -149,6 +157,7 @@ init_ccw_bus_type (void)
- 
- 	init_waitqueue_head(&ccw_device_init_wq);
- 	atomic_set(&ccw_device_init_count, 0);
-+	setup_timer(&recovery_timer, recovery_func, 0);
- 
- 	ccw_device_work = create_singlethread_workqueue("cio");
- 	if (!ccw_device_work)
-@@ -166,7 +175,8 @@ init_ccw_bus_type (void)
- 	if ((ret = bus_register (&ccw_bus_type)))
- 		goto out_err;
- 
--	if ((ret = driver_register(&io_subchannel_driver.drv)))
-+	ret = css_driver_register(&io_subchannel_driver);
-+	if (ret)
- 		goto out_err;
- 
- 	wait_event(ccw_device_init_wq,
-@@ -186,7 +196,7 @@ out_err:
- static void __exit
- cleanup_ccw_bus_type (void)
- {
--	driver_unregister(&io_subchannel_driver.drv);
-+	css_driver_unregister(&io_subchannel_driver);
- 	bus_unregister(&ccw_bus_type);
- 	destroy_workqueue(ccw_device_notify_work);
- 	destroy_workqueue(ccw_device_work);
-@@ -773,7 +783,7 @@ static void sch_attach_device(struct subchannel *sch,
- {
- 	css_update_ssd_info(sch);
- 	spin_lock_irq(sch->lock);
--	sch->dev.driver_data = cdev;
-+	sch_set_cdev(sch, cdev);
- 	cdev->private->schid = sch->schid;
- 	cdev->ccwlock = sch->lock;
- 	device_trigger_reprobe(sch);
-@@ -795,7 +805,7 @@ static void sch_attach_disconnected_device(struct subchannel *sch,
- 		put_device(&other_sch->dev);
- 		return;
- 	}
--	other_sch->dev.driver_data = NULL;
-+	sch_set_cdev(other_sch, NULL);
- 	/* No need to keep a subchannel without ccw device around. */
- 	css_sch_device_unregister(other_sch);
- 	put_device(&other_sch->dev);
-@@ -831,12 +841,12 @@ static void sch_create_and_recog_new_device(struct subchannel *sch)
- 		return;
- 	}
- 	spin_lock_irq(sch->lock);
--	sch->dev.driver_data = cdev;
-+	sch_set_cdev(sch, cdev);
- 	spin_unlock_irq(sch->lock);
- 	/* Start recognition for the new ccw device. */
- 	if (io_subchannel_recog(cdev, sch)) {
- 		spin_lock_irq(sch->lock);
--		sch->dev.driver_data = NULL;
-+		sch_set_cdev(sch, NULL);
- 		spin_unlock_irq(sch->lock);
- 		if (cdev->dev.release)
- 			cdev->dev.release(&cdev->dev);
-@@ -940,7 +950,7 @@ io_subchannel_register(struct work_struct *work)
- 			      cdev->private->dev_id.devno, ret);
- 		put_device(&cdev->dev);
- 		spin_lock_irqsave(sch->lock, flags);
--		sch->dev.driver_data = NULL;
-+		sch_set_cdev(sch, NULL);
- 		spin_unlock_irqrestore(sch->lock, flags);
- 		kfree (cdev->private);
- 		kfree (cdev);
-@@ -1022,7 +1032,7 @@ io_subchannel_recog(struct ccw_device *cdev, struct subchannel *sch)
- 	int rc;
- 	struct ccw_device_private *priv;
- 
--	sch->dev.driver_data = cdev;
-+	sch_set_cdev(sch, cdev);
- 	sch->driver = &io_subchannel_driver;
- 	cdev->ccwlock = sch->lock;
- 
-@@ -1082,7 +1092,7 @@ static void ccw_device_move_to_sch(struct work_struct *work)
++static void hptiop_unmap_pci_bar_itl(struct hptiop_hba *hba)
++{
++	iounmap(hba->u.itl.iop);
++}
++
++static int hptiop_map_pci_bar_mv(struct hptiop_hba *hba)
++{
++	hba->u.mv.regs = hptiop_map_pci_bar(hba, 0);
++	if (hba->u.mv.regs == 0)
++		return -1;
++
++	hba->u.mv.mu = hptiop_map_pci_bar(hba, 2);
++	if (hba->u.mv.mu == 0) {
++		iounmap(hba->u.mv.regs);
+ 		return -1;
  	}
- 	if (former_parent) {
- 		spin_lock_irq(former_parent->lock);
--		former_parent->dev.driver_data = NULL;
-+		sch_set_cdev(former_parent, NULL);
- 		spin_unlock_irq(former_parent->lock);
- 		css_sch_device_unregister(former_parent);
- 		/* Reset intparm to zeroes. */
-@@ -1096,6 +1106,18 @@ out:
- 	put_device(&cdev->dev);
+ 
+-	hba->iop = mem_base_virt;
+-	dprintk("hptiop_map_pci_bar: iop=%p\n", hba->iop);
+ 	return 0;
  }
  
-+static void io_subchannel_irq(struct subchannel *sch)
++static void hptiop_unmap_pci_bar_mv(struct hptiop_hba *hba)
 +{
-+	struct ccw_device *cdev;
-+
-+	cdev = sch_get_cdev(sch);
-+
-+	CIO_TRACE_EVENT(3, "IRQ");
-+	CIO_TRACE_EVENT(3, sch->dev.bus_id);
-+	if (cdev)
-+		dev_fsm_event(cdev, DEV_EVENT_INTERRUPT);
++	iounmap(hba->u.mv.regs);
++	iounmap(hba->u.mv.mu);
 +}
 +
- static int
- io_subchannel_probe (struct subchannel *sch)
+ static void hptiop_message_callback(struct hptiop_hba *hba, u32 msg)
  {
-@@ -1104,13 +1126,13 @@ io_subchannel_probe (struct subchannel *sch)
- 	unsigned long flags;
- 	struct ccw_dev_id dev_id;
- 
--	if (sch->dev.driver_data) {
-+	cdev = sch_get_cdev(sch);
-+	if (cdev) {
- 		/*
- 		 * This subchannel already has an associated ccw_device.
- 		 * Register it and exit. This happens for all early
- 		 * device, e.g. the console.
- 		 */
--		cdev = sch->dev.driver_data;
- 		cdev->dev.groups = ccwdev_attr_groups;
- 		device_initialize(&cdev->dev);
- 		ccw_device_register(cdev);
-@@ -1132,6 +1154,11 @@ io_subchannel_probe (struct subchannel *sch)
- 	 */
- 	dev_id.devno = sch->schib.pmcw.dev;
- 	dev_id.ssid = sch->schid.ssid;
-+	/* Allocate I/O subchannel private data. */
-+	sch->private = kzalloc(sizeof(struct io_subchannel_private),
-+			       GFP_KERNEL | GFP_DMA);
-+	if (!sch->private)
-+		return -ENOMEM;
- 	cdev = get_disc_ccwdev_by_dev_id(&dev_id, NULL);
- 	if (!cdev)
- 		cdev = get_orphaned_ccwdev_by_dev_id(to_css(sch->dev.parent),
-@@ -1149,16 +1176,18 @@ io_subchannel_probe (struct subchannel *sch)
- 		return 0;
- 	}
- 	cdev = io_subchannel_create_ccwdev(sch);
--	if (IS_ERR(cdev))
-+	if (IS_ERR(cdev)) {
-+		kfree(sch->private);
- 		return PTR_ERR(cdev);
--
-+	}
- 	rc = io_subchannel_recog(cdev, sch);
- 	if (rc) {
- 		spin_lock_irqsave(sch->lock, flags);
--		sch->dev.driver_data = NULL;
-+		sch_set_cdev(sch, NULL);
- 		spin_unlock_irqrestore(sch->lock, flags);
- 		if (cdev->dev.release)
- 			cdev->dev.release(&cdev->dev);
-+		kfree(sch->private);
- 	}
+ 	dprintk("iop message 0x%x\n", msg);
  
- 	return rc;
-@@ -1170,25 +1199,25 @@ io_subchannel_remove (struct subchannel *sch)
- 	struct ccw_device *cdev;
- 	unsigned long flags;
++	if (msg == IOPMU_INBOUND_MSG0_NOP)
++		hba->msg_done = 1;
++
+ 	if (!hba->initialized)
+ 		return;
  
--	if (!sch->dev.driver_data)
-+	cdev = sch_get_cdev(sch);
-+	if (!cdev)
- 		return 0;
--	cdev = sch->dev.driver_data;
- 	/* Set ccw device to not operational and drop reference. */
- 	spin_lock_irqsave(cdev->ccwlock, flags);
--	sch->dev.driver_data = NULL;
-+	sch_set_cdev(sch, NULL);
- 	cdev->private->state = DEV_STATE_NOT_OPER;
- 	spin_unlock_irqrestore(cdev->ccwlock, flags);
- 	ccw_device_unregister(cdev);
- 	put_device(&cdev->dev);
-+	kfree(sch->private);
- 	return 0;
+@@ -303,7 +510,7 @@ static void hptiop_message_callback(struct hptiop_hba *hba, u32 msg)
+ 		hba->msg_done = 1;
  }
  
--static int
--io_subchannel_notify(struct device *dev, int event)
-+static int io_subchannel_notify(struct subchannel *sch, int event)
+-static inline struct hptiop_request *get_req(struct hptiop_hba *hba)
++static struct hptiop_request *get_req(struct hptiop_hba *hba)
  {
- 	struct ccw_device *cdev;
+ 	struct hptiop_request *ret;
  
--	cdev = dev->driver_data;
-+	cdev = sch_get_cdev(sch);
- 	if (!cdev)
- 		return 0;
- 	if (!cdev->drv)
-@@ -1198,22 +1227,20 @@ io_subchannel_notify(struct device *dev, int event)
- 	return cdev->drv->notify ? cdev->drv->notify(cdev, event) : 0;
+@@ -316,30 +523,19 @@ static inline struct hptiop_request *get_req(struct hptiop_hba *hba)
+ 	return ret;
  }
  
--static void
--io_subchannel_verify(struct device *dev)
-+static void io_subchannel_verify(struct subchannel *sch)
+-static inline void free_req(struct hptiop_hba *hba, struct hptiop_request *req)
++static void free_req(struct hptiop_hba *hba, struct hptiop_request *req)
  {
- 	struct ccw_device *cdev;
- 
--	cdev = dev->driver_data;
-+	cdev = sch_get_cdev(sch);
- 	if (cdev)
- 		dev_fsm_event(cdev, DEV_EVENT_VERIFY);
+ 	dprintk("free_req(%d, %p)\n", req->index, req);
+ 	req->next = hba->req_list;
+ 	hba->req_list = req;
  }
  
--static void
--io_subchannel_ioterm(struct device *dev)
-+static void io_subchannel_ioterm(struct subchannel *sch)
+-static void hptiop_host_request_callback(struct hptiop_hba *hba, u32 _tag)
++static void hptiop_finish_scsi_req(struct hptiop_hba *hba, u32 tag,
++				struct hpt_iop_request_scsi_command *req)
  {
- 	struct ccw_device *cdev;
+-	struct hpt_iop_request_scsi_command *req;
+ 	struct scsi_cmnd *scp;
+-	u32 tag;
+-
+-	if (hba->iopintf_v2) {
+-		tag = _tag & ~ IOPMU_QUEUE_REQUEST_RESULT_BIT;
+-		req = hba->reqs[tag].req_virt;
+-		if (likely(_tag & IOPMU_QUEUE_REQUEST_RESULT_BIT))
+-			req->header.result = IOP_RESULT_SUCCESS;
+-	} else {
+-		tag = _tag;
+-		req = hba->reqs[tag].req_virt;
+-	}
  
--	cdev = dev->driver_data;
-+	cdev = sch_get_cdev(sch);
- 	if (!cdev)
- 		return;
- 	/* Internal I/O will be retried by the interrupt handler. */
-@@ -1231,7 +1258,7 @@ io_subchannel_shutdown(struct subchannel *sch)
- 	struct ccw_device *cdev;
- 	int ret;
+-	dprintk("hptiop_host_request_callback: req=%p, type=%d, "
++	dprintk("hptiop_finish_scsi_req: req=%p, type=%d, "
+ 			"result=%d, context=0x%x tag=%d\n",
+ 			req, req->header.type, req->header.result,
+ 			req->header.context, tag);
+@@ -354,6 +550,8 @@ static void hptiop_host_request_callback(struct hptiop_hba *hba, u32 _tag)
  
--	cdev = sch->dev.driver_data;
-+	cdev = sch_get_cdev(sch);
+ 	switch (le32_to_cpu(req->header.result)) {
+ 	case IOP_RESULT_SUCCESS:
++		scsi_set_resid(scp,
++			scsi_bufflen(scp) - le32_to_cpu(req->dataxfer_length));
+ 		scp->result = (DID_OK<<16);
+ 		break;
+ 	case IOP_RESULT_BAD_TARGET:
+@@ -371,12 +569,12 @@ static void hptiop_host_request_callback(struct hptiop_hba *hba, u32 _tag)
+ 	case IOP_RESULT_INVALID_REQUEST:
+ 		scp->result = (DID_ABORT<<16);
+ 		break;
+-	case IOP_RESULT_MODE_SENSE_CHECK_CONDITION:
++	case IOP_RESULT_CHECK_CONDITION:
++		scsi_set_resid(scp,
++			scsi_bufflen(scp) - le32_to_cpu(req->dataxfer_length));
+ 		scp->result = SAM_STAT_CHECK_CONDITION;
+-		memset(&scp->sense_buffer,
+-				0, sizeof(scp->sense_buffer));
+ 		memcpy(&scp->sense_buffer, &req->sg_list,
+-				min(sizeof(scp->sense_buffer),
++				min_t(size_t, SCSI_SENSE_BUFFERSIZE,
+ 					le32_to_cpu(req->dataxfer_length)));
+ 		break;
  
- 	if (cio_is_console(sch->schid))
- 		return;
-@@ -1271,6 +1298,9 @@ ccw_device_console_enable (struct ccw_device *cdev, struct subchannel *sch)
- {
- 	int rc;
+@@ -391,15 +589,33 @@ static void hptiop_host_request_callback(struct hptiop_hba *hba, u32 _tag)
+ 	free_req(hba, &hba->reqs[tag]);
+ }
  
-+	/* Attach subchannel private data. */
-+	sch->private = cio_get_console_priv();
-+	memset(sch->private, 0, sizeof(struct io_subchannel_private));
- 	/* Initialize the ccw_device structure. */
- 	cdev->dev.parent= &sch->dev;
- 	rc = io_subchannel_recog(cdev, sch);
-@@ -1456,6 +1486,7 @@ int ccw_driver_register(struct ccw_driver *cdriver)
+-void hptiop_iop_request_callback(struct hptiop_hba *hba, u32 tag)
++static void hptiop_host_request_callback_itl(struct hptiop_hba *hba, u32 _tag)
++{
++	struct hpt_iop_request_scsi_command *req;
++	u32 tag;
++
++	if (hba->iopintf_v2) {
++		tag = _tag & ~IOPMU_QUEUE_REQUEST_RESULT_BIT;
++		req = hba->reqs[tag].req_virt;
++		if (likely(_tag & IOPMU_QUEUE_REQUEST_RESULT_BIT))
++			req->header.result = cpu_to_le32(IOP_RESULT_SUCCESS);
++	} else {
++		tag = _tag;
++		req = hba->reqs[tag].req_virt;
++	}
++
++	hptiop_finish_scsi_req(hba, tag, req);
++}
++
++void hptiop_iop_request_callback_itl(struct hptiop_hba *hba, u32 tag)
+ {
+ 	struct hpt_iop_request_header __iomem *req;
+ 	struct hpt_iop_request_ioctl_command __iomem *p;
+ 	struct hpt_ioctl_k *arg;
  
- 	drv->bus = &ccw_bus_type;
- 	drv->name = cdriver->name;
-+	drv->owner = cdriver->owner;
+ 	req = (struct hpt_iop_request_header __iomem *)
+-			((unsigned long)hba->iop + tag);
+-	dprintk("hptiop_iop_request_callback: req=%p, type=%d, "
++			((unsigned long)hba->u.itl.iop + tag);
++	dprintk("hptiop_iop_request_callback_itl: req=%p, type=%d, "
+ 			"result=%d, context=0x%x tag=%d\n",
+ 			req, readl(&req->type), readl(&req->result),
+ 			readl(&req->context), tag);
+@@ -427,7 +643,7 @@ void hptiop_iop_request_callback(struct hptiop_hba *hba, u32 tag)
+ 		arg->result = HPT_IOCTL_RESULT_FAILED;
  
- 	return driver_register(drv);
+ 	arg->done(arg);
+-	writel(tag, &hba->iop->outbound_queue);
++	writel(tag, &hba->u.itl.iop->outbound_queue);
  }
-@@ -1481,6 +1512,60 @@ ccw_device_get_subchannel_id(struct ccw_device *cdev)
- 	return sch->schid;
+ 
+ static irqreturn_t hptiop_intr(int irq, void *dev_id)
+@@ -437,7 +653,7 @@ static irqreturn_t hptiop_intr(int irq, void *dev_id)
+ 	unsigned long flags;
+ 
+ 	spin_lock_irqsave(hba->host->host_lock, flags);
+-	handled = __iop_intr(hba);
++	handled = hba->ops->iop_intr(hba);
+ 	spin_unlock_irqrestore(hba->host->host_lock, flags);
+ 
+ 	return handled;
+@@ -469,6 +685,57 @@ static int hptiop_buildsgl(struct scsi_cmnd *scp, struct hpt_iopsg *psg)
+ 	return HPT_SCP(scp)->sgcnt;
  }
  
-+static int recovery_check(struct device *dev, void *data)
++static void hptiop_post_req_itl(struct hptiop_hba *hba,
++					struct hptiop_request *_req)
 +{
-+	struct ccw_device *cdev = to_ccwdev(dev);
-+	int *redo = data;
++	struct hpt_iop_request_header *reqhdr = _req->req_virt;
 +
-+	spin_lock_irq(cdev->ccwlock);
-+	switch (cdev->private->state) {
-+	case DEV_STATE_DISCONNECTED:
-+		CIO_MSG_EVENT(3, "recovery: trigger 0.%x.%04x\n",
-+			      cdev->private->dev_id.ssid,
-+			      cdev->private->dev_id.devno);
-+		dev_fsm_event(cdev, DEV_EVENT_VERIFY);
-+		*redo = 1;
-+		break;
-+	case DEV_STATE_DISCONNECTED_SENSE_ID:
-+		*redo = 1;
-+		break;
-+	}
-+	spin_unlock_irq(cdev->ccwlock);
++	reqhdr->context = cpu_to_le32(IOPMU_QUEUE_ADDR_HOST_BIT |
++							(u32)_req->index);
++	reqhdr->context_hi32 = 0;
 +
-+	return 0;
++	if (hba->iopintf_v2) {
++		u32 size, size_bits;
++
++		size = le32_to_cpu(reqhdr->size);
++		if (size < 256)
++			size_bits = IOPMU_QUEUE_REQUEST_SIZE_BIT;
++		else if (size < 512)
++			size_bits = IOPMU_QUEUE_ADDR_HOST_BIT;
++		else
++			size_bits = IOPMU_QUEUE_REQUEST_SIZE_BIT |
++						IOPMU_QUEUE_ADDR_HOST_BIT;
++		writel(_req->req_shifted_phy | size_bits,
++			&hba->u.itl.iop->inbound_queue);
++	} else
++		writel(_req->req_shifted_phy | IOPMU_QUEUE_ADDR_HOST_BIT,
++					&hba->u.itl.iop->inbound_queue);
 +}
 +
-+static void recovery_func(unsigned long data)
++static void hptiop_post_req_mv(struct hptiop_hba *hba,
++					struct hptiop_request *_req)
 +{
-+	int redo = 0;
++	struct hpt_iop_request_header *reqhdr = _req->req_virt;
++	u32 size, size_bit;
 +
-+	bus_for_each_dev(&ccw_bus_type, NULL, &redo, recovery_check);
-+	if (redo) {
-+		spin_lock_irq(&recovery_lock);
-+		if (!timer_pending(&recovery_timer)) {
-+			if (recovery_phase < ARRAY_SIZE(recovery_delay) - 1)
-+				recovery_phase++;
-+			mod_timer(&recovery_timer, jiffies +
-+				  recovery_delay[recovery_phase] * HZ);
-+		}
-+		spin_unlock_irq(&recovery_lock);
-+	} else
-+		CIO_MSG_EVENT(2, "recovery: end\n");
++	reqhdr->context = cpu_to_le32(_req->index<<8 |
++					IOP_REQUEST_TYPE_SCSI_COMMAND<<5);
++	reqhdr->context_hi32 = 0;
++	size = le32_to_cpu(reqhdr->size);
++
++	if (size <= 256)
++		size_bit = 0;
++	else if (size <= 256*2)
++		size_bit = 1;
++	else if (size <= 256*3)
++		size_bit = 2;
++	else
++		size_bit = 3;
++
++	mv_inbound_write((_req->req_shifted_phy << 5) |
++		MVIOP_MU_QUEUE_ADDR_HOST_BIT | size_bit, hba);
 +}
 +
-+void ccw_device_schedule_recovery(void)
+ static int hptiop_queuecommand(struct scsi_cmnd *scp,
+ 				void (*done)(struct scsi_cmnd *))
+ {
+@@ -518,9 +785,6 @@ static int hptiop_queuecommand(struct scsi_cmnd *scp,
+ 	req->header.flags = cpu_to_le32(IOP_REQUEST_FLAG_OUTPUT_CONTEXT);
+ 	req->header.type = cpu_to_le32(IOP_REQUEST_TYPE_SCSI_COMMAND);
+ 	req->header.result = cpu_to_le32(IOP_RESULT_PENDING);
+-	req->header.context = cpu_to_le32(IOPMU_QUEUE_ADDR_HOST_BIT |
+-							(u32)_req->index);
+-	req->header.context_hi32 = 0;
+ 	req->dataxfer_length = cpu_to_le32(scsi_bufflen(scp));
+ 	req->channel = scp->device->channel;
+ 	req->target = scp->device->id;
+@@ -531,21 +795,7 @@ static int hptiop_queuecommand(struct scsi_cmnd *scp,
+ 				 + sg_count * sizeof(struct hpt_iopsg));
+ 
+ 	memcpy(req->cdb, scp->cmnd, sizeof(req->cdb));
+-
+-	if (hba->iopintf_v2) {
+-		u32 size_bits;
+-		if (req->header.size < 256)
+-			size_bits = IOPMU_QUEUE_REQUEST_SIZE_BIT;
+-		else if (req->header.size < 512)
+-			size_bits = IOPMU_QUEUE_ADDR_HOST_BIT;
+-		else
+-			size_bits = IOPMU_QUEUE_REQUEST_SIZE_BIT |
+-						IOPMU_QUEUE_ADDR_HOST_BIT;
+-		writel(_req->req_shifted_phy | size_bits, &hba->iop->inbound_queue);
+-	} else
+-		writel(_req->req_shifted_phy | IOPMU_QUEUE_ADDR_HOST_BIT,
+-					&hba->iop->inbound_queue);
+-
++	hba->ops->post_req(hba, _req);
+ 	return 0;
+ 
+ cmd_done:
+@@ -563,9 +813,7 @@ static int hptiop_reset_hba(struct hptiop_hba *hba)
+ {
+ 	if (atomic_xchg(&hba->resetting, 1) == 0) {
+ 		atomic_inc(&hba->reset_count);
+-		writel(IOPMU_INBOUND_MSG0_RESET,
+-				&hba->iop->inbound_msgaddr0);
+-		hptiop_pci_posting_flush(hba->iop);
++		hba->ops->post_msg(hba, IOPMU_INBOUND_MSG0_RESET);
+ 	}
+ 
+ 	wait_event_timeout(hba->reset_wq,
+@@ -601,8 +849,10 @@ static int hptiop_reset(struct scsi_cmnd *scp)
+ static int hptiop_adjust_disk_queue_depth(struct scsi_device *sdev,
+ 						int queue_depth)
+ {
+-	if(queue_depth > 256)
+-		queue_depth = 256;
++	struct hptiop_hba *hba = (struct hptiop_hba *)sdev->host->hostdata;
++
++	if (queue_depth > hba->max_requests)
++		queue_depth = hba->max_requests;
+ 	scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, queue_depth);
+ 	return queue_depth;
+ }
+@@ -663,6 +913,26 @@ static struct scsi_host_template driver_template = {
+ 	.change_queue_depth         = hptiop_adjust_disk_queue_depth,
+ };
+ 
++static int hptiop_internal_memalloc_mv(struct hptiop_hba *hba)
 +{
-+	unsigned long flags;
++	hba->u.mv.internal_req = dma_alloc_coherent(&hba->pcidev->dev,
++			0x800, &hba->u.mv.internal_req_phy, GFP_KERNEL);
++	if (hba->u.mv.internal_req)
++		return 0;
++	else
++		return -1;
++}
 +
-+	CIO_MSG_EVENT(2, "recovery: schedule\n");
-+	spin_lock_irqsave(&recovery_lock, flags);
-+	if (!timer_pending(&recovery_timer) || (recovery_phase != 0)) {
-+		recovery_phase = 0;
-+		mod_timer(&recovery_timer, jiffies + recovery_delay[0] * HZ);
-+	}
-+	spin_unlock_irqrestore(&recovery_lock, flags);
++static int hptiop_internal_memfree_mv(struct hptiop_hba *hba)
++{
++	if (hba->u.mv.internal_req) {
++		dma_free_coherent(&hba->pcidev->dev, 0x800,
++			hba->u.mv.internal_req, hba->u.mv.internal_req_phy);
++		return 0;
++	} else
++		return -1;
 +}
 +
- MODULE_LICENSE("GPL");
- EXPORT_SYMBOL(ccw_device_set_online);
- EXPORT_SYMBOL(ccw_device_set_offline);
-diff --git a/drivers/s390/cio/device.h b/drivers/s390/cio/device.h
-index 0d40896..d40a2ff 100644
---- a/drivers/s390/cio/device.h
-+++ b/drivers/s390/cio/device.h
-@@ -5,6 +5,8 @@
- #include <asm/atomic.h>
- #include <linux/wait.h>
+ static int __devinit hptiop_probe(struct pci_dev *pcidev,
+ 					const struct pci_device_id *id)
+ {
+@@ -708,6 +978,7 @@ static int __devinit hptiop_probe(struct pci_dev *pcidev,
  
-+#include "io_sch.h"
-+
- /*
-  * states of the device statemachine
-  */
-@@ -74,7 +76,6 @@ extern struct workqueue_struct *ccw_device_notify_work;
- extern wait_queue_head_t ccw_device_init_wq;
- extern atomic_t ccw_device_init_count;
+ 	hba = (struct hptiop_hba *)host->hostdata;
  
--void io_subchannel_irq (struct device *pdev);
- void io_subchannel_recog_done(struct ccw_device *cdev);
++	hba->ops = (struct hptiop_adapter_ops *)id->driver_data;
+ 	hba->pcidev = pcidev;
+ 	hba->host = host;
+ 	hba->initialized = 0;
+@@ -725,16 +996,24 @@ static int __devinit hptiop_probe(struct pci_dev *pcidev,
+ 	host->n_io_port = 0;
+ 	host->irq = pcidev->irq;
  
- int ccw_device_cancel_halt_clear(struct ccw_device *);
-@@ -87,6 +88,8 @@ int ccw_device_recognition(struct ccw_device *);
- int ccw_device_online(struct ccw_device *);
- int ccw_device_offline(struct ccw_device *);
+-	if (hptiop_map_pci_bar(hba))
++	if (hba->ops->map_pci_bar(hba))
+ 		goto free_scsi_host;
  
-+void ccw_device_schedule_recovery(void);
-+
- /* Function prototypes for device status and basic sense stuff. */
- void ccw_device_accumulate_irb(struct ccw_device *, struct irb *);
- void ccw_device_accumulate_basic_sense(struct ccw_device *, struct irb *);
-diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c
-index bfad421..4b92c84 100644
---- a/drivers/s390/cio/device_fsm.c
-+++ b/drivers/s390/cio/device_fsm.c
-@@ -25,14 +25,16 @@
- #include "ioasm.h"
- #include "chp.h"
+-	if (iop_wait_ready(hba->iop, 20000)) {
++	if (hba->ops->iop_wait_ready(hba, 20000)) {
+ 		printk(KERN_ERR "scsi%d: firmware not ready\n",
+ 				hba->host->host_no);
+ 		goto unmap_pci_bar;
+ 	}
  
-+static int timeout_log_enabled;
+-	if (iop_get_config(hba, &iop_config)) {
++	if (hba->ops->internal_memalloc) {
++		if (hba->ops->internal_memalloc(hba)) {
++			printk(KERN_ERR "scsi%d: internal_memalloc failed\n",
++				hba->host->host_no);
++			goto unmap_pci_bar;
++		}
++	}
 +
- int
- device_is_online(struct subchannel *sch)
- {
- 	struct ccw_device *cdev;
++	if (hba->ops->get_config(hba, &iop_config)) {
+ 		printk(KERN_ERR "scsi%d: get config failed\n",
+ 				hba->host->host_no);
+ 		goto unmap_pci_bar;
+@@ -770,7 +1049,7 @@ static int __devinit hptiop_probe(struct pci_dev *pcidev,
+ 	set_config.vbus_id = cpu_to_le16(host->host_no);
+ 	set_config.max_host_request_size = cpu_to_le16(req_size);
  
--	if (!sch->dev.driver_data)
-+	cdev = sch_get_cdev(sch);
-+	if (!cdev)
- 		return 0;
--	cdev = sch->dev.driver_data;
- 	return (cdev->private->state == DEV_STATE_ONLINE);
- }
+-	if (iop_set_config(hba, &set_config)) {
++	if (hba->ops->set_config(hba, &set_config)) {
+ 		printk(KERN_ERR "scsi%d: set config failed\n",
+ 				hba->host->host_no);
+ 		goto unmap_pci_bar;
+@@ -839,21 +1118,24 @@ static int __devinit hptiop_probe(struct pci_dev *pcidev,
  
-@@ -41,9 +43,9 @@ device_is_disconnected(struct subchannel *sch)
- {
- 	struct ccw_device *cdev;
+ free_request_mem:
+ 	dma_free_coherent(&hba->pcidev->dev,
+-			hba->req_size*hba->max_requests + 0x20,
++			hba->req_size * hba->max_requests + 0x20,
+ 			hba->dma_coherent, hba->dma_coherent_handle);
  
--	if (!sch->dev.driver_data)
-+	cdev = sch_get_cdev(sch);
-+	if (!cdev)
- 		return 0;
--	cdev = sch->dev.driver_data;
- 	return (cdev->private->state == DEV_STATE_DISCONNECTED ||
- 		cdev->private->state == DEV_STATE_DISCONNECTED_SENSE_ID);
- }
-@@ -53,19 +55,21 @@ device_set_disconnected(struct subchannel *sch)
- {
- 	struct ccw_device *cdev;
+ free_request_irq:
+ 	free_irq(hba->pcidev->irq, hba);
  
--	if (!sch->dev.driver_data)
-+	cdev = sch_get_cdev(sch);
-+	if (!cdev)
- 		return;
--	cdev = sch->dev.driver_data;
- 	ccw_device_set_timeout(cdev, 0);
- 	cdev->private->flags.fake_irb = 0;
- 	cdev->private->state = DEV_STATE_DISCONNECTED;
-+	if (cdev->online)
-+		ccw_device_schedule_recovery();
- }
+ unmap_pci_bar:
+-	iounmap(hba->iop);
++	if (hba->ops->internal_memfree)
++		hba->ops->internal_memfree(hba);
  
- void device_set_intretry(struct subchannel *sch)
- {
- 	struct ccw_device *cdev;
+-free_pci_regions:
+-	pci_release_regions(pcidev) ;
++	hba->ops->unmap_pci_bar(hba);
  
--	cdev = sch->dev.driver_data;
-+	cdev = sch_get_cdev(sch);
- 	if (!cdev)
- 		return;
- 	cdev->private->flags.intretry = 1;
-@@ -75,13 +79,62 @@ int device_trigger_verify(struct subchannel *sch)
+ free_scsi_host:
+ 	scsi_host_put(host);
+ 
++free_pci_regions:
++	pci_release_regions(pcidev);
++
+ disable_pci_device:
+ 	pci_disable_device(pcidev);
+ 
+@@ -865,8 +1147,6 @@ static void hptiop_shutdown(struct pci_dev *pcidev)
  {
- 	struct ccw_device *cdev;
+ 	struct Scsi_Host *host = pci_get_drvdata(pcidev);
+ 	struct hptiop_hba *hba = (struct hptiop_hba *)host->hostdata;
+-	struct hpt_iopmu __iomem *iop = hba->iop;
+-	u32    int_mask;
  
--	cdev = sch->dev.driver_data;
-+	cdev = sch_get_cdev(sch);
- 	if (!cdev || !cdev->online)
- 		return -EINVAL;
- 	dev_fsm_event(cdev, DEV_EVENT_VERIFY);
- 	return 0;
- }
+ 	dprintk("hptiop_shutdown(%p)\n", hba);
  
-+static int __init ccw_timeout_log_setup(char *unused)
-+{
-+	timeout_log_enabled = 1;
-+	return 1;
+@@ -876,11 +1156,24 @@ static void hptiop_shutdown(struct pci_dev *pcidev)
+ 					hba->host->host_no);
+ 
+ 	/* disable all outbound interrupts */
+-	int_mask = readl(&iop->outbound_intmask);
++	hba->ops->disable_intr(hba);
 +}
 +
-+__setup("ccw_timeout_log", ccw_timeout_log_setup);
-+
-+static void ccw_timeout_log(struct ccw_device *cdev)
++static void hptiop_disable_intr_itl(struct hptiop_hba *hba)
 +{
-+	struct schib schib;
-+	struct subchannel *sch;
-+	struct io_subchannel_private *private;
-+	int cc;
++	u32 int_mask;
 +
-+	sch = to_subchannel(cdev->dev.parent);
-+	private = to_io_private(sch);
-+	cc = stsch(sch->schid, &schib);
++	int_mask = readl(&hba->u.itl.iop->outbound_intmask);
+ 	writel(int_mask |
+ 		IOPMU_OUTBOUND_INT_MSG0 | IOPMU_OUTBOUND_INT_POSTQUEUE,
+-		&iop->outbound_intmask);
+-	hptiop_pci_posting_flush(iop);
++		&hba->u.itl.iop->outbound_intmask);
++	readl(&hba->u.itl.iop->outbound_intmask);
++}
 +
-+	printk(KERN_WARNING "cio: ccw device timeout occurred at %llx, "
-+	       "device information:\n", get_clock());
-+	printk(KERN_WARNING "cio: orb:\n");
-+	print_hex_dump(KERN_WARNING, "cio:  ", DUMP_PREFIX_NONE, 16, 1,
-+		       &private->orb, sizeof(private->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: subchannel lpm: %02x, opm: %02x, "
-+	       "vpm: %02x\n", sch->lpm, sch->opm, sch->vpm);
++static void hptiop_disable_intr_mv(struct hptiop_hba *hba)
++{
++	writel(0, &hba->u.mv.regs->outbound_intmask);
++	readl(&hba->u.mv.regs->outbound_intmask);
+ }
+ 
+ static void hptiop_remove(struct pci_dev *pcidev)
+@@ -901,7 +1194,10 @@ static void hptiop_remove(struct pci_dev *pcidev)
+ 			hba->dma_coherent,
+ 			hba->dma_coherent_handle);
+ 
+-	iounmap(hba->iop);
++	if (hba->ops->internal_memfree)
++		hba->ops->internal_memfree(hba);
 +
-+	if ((void *)(addr_t)private->orb.cpa == &private->sense_ccw ||
-+	    (void *)(addr_t)private->orb.cpa == cdev->private->iccws)
-+		printk(KERN_WARNING "cio: last channel program (intern):\n");
-+	else
-+		printk(KERN_WARNING "cio: last channel program:\n");
++	hba->ops->unmap_pci_bar(hba);
+ 
+ 	pci_release_regions(hba->pcidev);
+ 	pci_set_drvdata(hba->pcidev, NULL);
+@@ -910,11 +1206,50 @@ static void hptiop_remove(struct pci_dev *pcidev)
+ 	scsi_host_put(host);
+ }
+ 
++static struct hptiop_adapter_ops hptiop_itl_ops = {
++	.iop_wait_ready    = iop_wait_ready_itl,
++	.internal_memalloc = 0,
++	.internal_memfree  = 0,
++	.map_pci_bar       = hptiop_map_pci_bar_itl,
++	.unmap_pci_bar     = hptiop_unmap_pci_bar_itl,
++	.enable_intr       = hptiop_enable_intr_itl,
++	.disable_intr      = hptiop_disable_intr_itl,
++	.get_config        = iop_get_config_itl,
++	.set_config        = iop_set_config_itl,
++	.iop_intr          = iop_intr_itl,
++	.post_msg          = hptiop_post_msg_itl,
++	.post_req          = hptiop_post_req_itl,
++};
 +
-+	print_hex_dump(KERN_WARNING, "cio:  ", DUMP_PREFIX_NONE, 16, 1,
-+		       (void *)(addr_t)private->orb.cpa,
-+		       sizeof(struct ccw1), 0);
-+	printk(KERN_WARNING "cio: ccw device state: %d\n",
-+	       cdev->private->state);
-+	printk(KERN_WARNING "cio: store subchannel returned: cc=%d\n", cc);
-+	printk(KERN_WARNING "cio: schib:\n");
-+	print_hex_dump(KERN_WARNING, "cio:  ", DUMP_PREFIX_NONE, 16, 1,
-+		       &schib, sizeof(schib), 0);
-+	printk(KERN_WARNING "cio: ccw device flags:\n");
-+	print_hex_dump(KERN_WARNING, "cio:  ", DUMP_PREFIX_NONE, 16, 1,
-+		       &cdev->private->flags, sizeof(cdev->private->flags), 0);
-+}
++static struct hptiop_adapter_ops hptiop_mv_ops = {
++	.iop_wait_ready    = iop_wait_ready_mv,
++	.internal_memalloc = hptiop_internal_memalloc_mv,
++	.internal_memfree  = hptiop_internal_memfree_mv,
++	.map_pci_bar       = hptiop_map_pci_bar_mv,
++	.unmap_pci_bar     = hptiop_unmap_pci_bar_mv,
++	.enable_intr       = hptiop_enable_intr_mv,
++	.disable_intr      = hptiop_disable_intr_mv,
++	.get_config        = iop_get_config_mv,
++	.set_config        = iop_set_config_mv,
++	.iop_intr          = iop_intr_mv,
++	.post_msg          = hptiop_post_msg_mv,
++	.post_req          = hptiop_post_req_mv,
++};
 +
+ static struct pci_device_id hptiop_id_table[] = {
+-	{ PCI_VDEVICE(TTI, 0x3220) },
+-	{ PCI_VDEVICE(TTI, 0x3320) },
+-	{ PCI_VDEVICE(TTI, 0x3520) },
+-	{ PCI_VDEVICE(TTI, 0x4320) },
++	{ PCI_VDEVICE(TTI, 0x3220), (kernel_ulong_t)&hptiop_itl_ops },
++	{ PCI_VDEVICE(TTI, 0x3320), (kernel_ulong_t)&hptiop_itl_ops },
++	{ PCI_VDEVICE(TTI, 0x3520), (kernel_ulong_t)&hptiop_itl_ops },
++	{ PCI_VDEVICE(TTI, 0x4320), (kernel_ulong_t)&hptiop_itl_ops },
++	{ PCI_VDEVICE(TTI, 0x3510), (kernel_ulong_t)&hptiop_itl_ops },
++	{ PCI_VDEVICE(TTI, 0x3511), (kernel_ulong_t)&hptiop_itl_ops },
++	{ PCI_VDEVICE(TTI, 0x3521), (kernel_ulong_t)&hptiop_itl_ops },
++	{ PCI_VDEVICE(TTI, 0x3522), (kernel_ulong_t)&hptiop_itl_ops },
++	{ PCI_VDEVICE(TTI, 0x3410), (kernel_ulong_t)&hptiop_itl_ops },
++	{ PCI_VDEVICE(TTI, 0x3540), (kernel_ulong_t)&hptiop_itl_ops },
++	{ PCI_VDEVICE(TTI, 0x3120), (kernel_ulong_t)&hptiop_mv_ops },
++	{ PCI_VDEVICE(TTI, 0x3122), (kernel_ulong_t)&hptiop_mv_ops },
++	{ PCI_VDEVICE(TTI, 0x3020), (kernel_ulong_t)&hptiop_mv_ops },
+ 	{},
+ };
+ 
+diff --git a/drivers/scsi/hptiop.h b/drivers/scsi/hptiop.h
+index 2a5e46e..a0289f2 100644
+--- a/drivers/scsi/hptiop.h
++++ b/drivers/scsi/hptiop.h
+@@ -1,5 +1,5 @@
  /*
-  * Timeout function. It just triggers a DEV_EVENT_TIMEOUT.
-  */
-@@ -92,6 +145,8 @@ ccw_device_timeout(unsigned long data)
+- * HighPoint RR3xxx controller driver for Linux
++ * HighPoint RR3xxx/4xxx controller driver for Linux
+  * Copyright (C) 2006-2007 HighPoint Technologies, Inc. All Rights Reserved.
+  *
+  * This program is free software; you can redistribute it and/or modify
+@@ -18,8 +18,7 @@
+ #ifndef _HPTIOP_H_
+ #define _HPTIOP_H_
  
- 	cdev = (struct ccw_device *) data;
- 	spin_lock_irq(cdev->ccwlock);
-+	if (timeout_log_enabled)
-+		ccw_timeout_log(cdev);
- 	dev_fsm_event(cdev, DEV_EVENT_TIMEOUT);
- 	spin_unlock_irq(cdev->ccwlock);
- }
-@@ -122,9 +177,9 @@ device_kill_pending_timer(struct subchannel *sch)
- {
- 	struct ccw_device *cdev;
+-struct hpt_iopmu
+-{
++struct hpt_iopmu_itl {
+ 	__le32 resrved0[4];
+ 	__le32 inbound_msgaddr0;
+ 	__le32 inbound_msgaddr1;
+@@ -54,6 +53,40 @@ struct hpt_iopmu
+ #define IOPMU_INBOUND_INT_ERROR      8
+ #define IOPMU_INBOUND_INT_POSTQUEUE  0x10
  
--	if (!sch->dev.driver_data)
-+	cdev = sch_get_cdev(sch);
-+	if (!cdev)
- 		return;
--	cdev = sch->dev.driver_data;
- 	ccw_device_set_timeout(cdev, 0);
- }
++#define MVIOP_QUEUE_LEN  512
++
++struct hpt_iopmu_mv {
++	__le32 inbound_head;
++	__le32 inbound_tail;
++	__le32 outbound_head;
++	__le32 outbound_tail;
++	__le32 inbound_msg;
++	__le32 outbound_msg;
++	__le32 reserve[10];
++	__le64 inbound_q[MVIOP_QUEUE_LEN];
++	__le64 outbound_q[MVIOP_QUEUE_LEN];
++};
++
++struct hpt_iopmv_regs {
++	__le32 reserved[0x20400 / 4];
++	__le32 inbound_doorbell;
++	__le32 inbound_intmask;
++	__le32 outbound_doorbell;
++	__le32 outbound_intmask;
++};
++
++#define MVIOP_MU_QUEUE_ADDR_HOST_MASK   (~(0x1full))
++#define MVIOP_MU_QUEUE_ADDR_HOST_BIT    4
++
++#define MVIOP_MU_QUEUE_ADDR_IOP_HIGH32  0xffffffff
++#define MVIOP_MU_QUEUE_REQUEST_RESULT_BIT   1
++#define MVIOP_MU_QUEUE_REQUEST_RETURN_CONTEXT 2
++
++#define MVIOP_MU_INBOUND_INT_MSG        1
++#define MVIOP_MU_INBOUND_INT_POSTQUEUE  2
++#define MVIOP_MU_OUTBOUND_INT_MSG       1
++#define MVIOP_MU_OUTBOUND_INT_POSTQUEUE 2
++
+ enum hpt_iopmu_message {
+ 	/* host-to-iop messages */
+ 	IOPMU_INBOUND_MSG0_NOP = 0,
+@@ -72,8 +105,7 @@ enum hpt_iopmu_message {
+ 	IOPMU_OUTBOUND_MSG0_REVALIDATE_DEVICE_MAX = 0x3ff,
+ };
  
-@@ -268,7 +323,7 @@ ccw_device_recog_done(struct ccw_device *cdev, int state)
- 	switch (state) {
- 	case DEV_STATE_NOT_OPER:
- 		CIO_DEBUG(KERN_WARNING, 2,
--			  "cio: SenseID : unknown device %04x on subchannel "
-+			  "SenseID : unknown device %04x on subchannel "
- 			  "0.%x.%04x\n", cdev->private->dev_id.devno,
- 			  sch->schid.ssid, sch->schid.sch_no);
- 		break;
-@@ -294,7 +349,7 @@ ccw_device_recog_done(struct ccw_device *cdev, int state)
- 		}
- 		/* Issue device info message. */
- 		CIO_DEBUG(KERN_INFO, 2,
--			  "cio: SenseID : device 0.%x.%04x reports: "
-+			  "SenseID : device 0.%x.%04x reports: "
- 			  "CU  Type/Mod = %04X/%02X, Dev Type/Mod = "
- 			  "%04X/%02X\n",
- 			  cdev->private->dev_id.ssid,
-@@ -304,7 +359,7 @@ ccw_device_recog_done(struct ccw_device *cdev, int state)
- 		break;
- 	case DEV_STATE_BOXED:
- 		CIO_DEBUG(KERN_WARNING, 2,
--			  "cio: SenseID : boxed device %04x on subchannel "
-+			  "SenseID : boxed device %04x on subchannel "
- 			  "0.%x.%04x\n", cdev->private->dev_id.devno,
- 			  sch->schid.ssid, sch->schid.sch_no);
- 		break;
-@@ -349,7 +404,7 @@ ccw_device_oper_notify(struct work_struct *work)
- 	sch = to_subchannel(cdev->dev.parent);
- 	if (sch->driver && sch->driver->notify) {
- 		spin_unlock_irqrestore(cdev->ccwlock, flags);
--		ret = sch->driver->notify(&sch->dev, CIO_OPER);
-+		ret = sch->driver->notify(sch, CIO_OPER);
- 		spin_lock_irqsave(cdev->ccwlock, flags);
- 	} else
- 		ret = 0;
-@@ -389,7 +444,7 @@ ccw_device_done(struct ccw_device *cdev, int state)
+-struct hpt_iop_request_header
+-{
++struct hpt_iop_request_header {
+ 	__le32 size;
+ 	__le32 type;
+ 	__le32 flags;
+@@ -104,11 +136,10 @@ enum hpt_iop_result_type {
+ 	IOP_RESULT_RESET,
+ 	IOP_RESULT_INVALID_REQUEST,
+ 	IOP_RESULT_BAD_TARGET,
+-	IOP_RESULT_MODE_SENSE_CHECK_CONDITION,
++	IOP_RESULT_CHECK_CONDITION,
+ };
  
- 	if (state == DEV_STATE_BOXED)
- 		CIO_DEBUG(KERN_WARNING, 2,
--			  "cio: Boxed device %04x on subchannel %04x\n",
-+			  "Boxed device %04x on subchannel %04x\n",
- 			  cdev->private->dev_id.devno, sch->schid.sch_no);
+-struct hpt_iop_request_get_config
+-{
++struct hpt_iop_request_get_config {
+ 	struct hpt_iop_request_header header;
+ 	__le32 interface_version;
+ 	__le32 firmware_version;
+@@ -121,8 +152,7 @@ struct hpt_iop_request_get_config
+ 	__le32 sdram_size;
+ };
  
- 	if (cdev->private->flags.donotify) {
-@@ -500,7 +555,8 @@ ccw_device_recognition(struct ccw_device *cdev)
- 	    (cdev->private->state != DEV_STATE_BOXED))
- 		return -EINVAL;
- 	sch = to_subchannel(cdev->dev.parent);
--	ret = cio_enable_subchannel(sch, sch->schib.pmcw.isc);
-+	ret = cio_enable_subchannel(sch, sch->schib.pmcw.isc,
-+				    (u32)(addr_t)sch);
- 	if (ret != 0)
- 		/* Couldn't enable the subchannel for i/o. Sick device. */
- 		return ret;
-@@ -587,9 +643,10 @@ ccw_device_verify_done(struct ccw_device *cdev, int err)
- 	default:
- 		/* Reset oper notify indication after verify error. */
- 		cdev->private->flags.donotify = 0;
--		if (cdev->online)
-+		if (cdev->online) {
-+			ccw_device_set_timeout(cdev, 0);
- 			dev_fsm_event(cdev, DEV_EVENT_NOTOPER);
--		else
-+		} else
- 			ccw_device_done(cdev, DEV_STATE_NOT_OPER);
- 		break;
- 	}
-@@ -610,7 +667,8 @@ ccw_device_online(struct ccw_device *cdev)
- 	sch = to_subchannel(cdev->dev.parent);
- 	if (css_init_done && !get_device(&cdev->dev))
- 		return -ENODEV;
--	ret = cio_enable_subchannel(sch, sch->schib.pmcw.isc);
-+	ret = cio_enable_subchannel(sch, sch->schib.pmcw.isc,
-+				    (u32)(addr_t)sch);
- 	if (ret != 0) {
- 		/* Couldn't enable the subchannel for i/o. Sick device. */
- 		if (ret == -ENODEV)
-@@ -937,7 +995,7 @@ void device_kill_io(struct subchannel *sch)
- 	int ret;
- 	struct ccw_device *cdev;
+-struct hpt_iop_request_set_config
+-{
++struct hpt_iop_request_set_config {
+ 	struct hpt_iop_request_header header;
+ 	__le32 iop_id;
+ 	__le16 vbus_id;
+@@ -130,15 +160,13 @@ struct hpt_iop_request_set_config
+ 	__le32 reserve[6];
+ };
  
--	cdev = sch->dev.driver_data;
-+	cdev = sch_get_cdev(sch);
- 	ret = ccw_device_cancel_halt_clear(cdev);
- 	if (ret == -EBUSY) {
- 		ccw_device_set_timeout(cdev, 3*HZ);
-@@ -990,7 +1048,8 @@ ccw_device_start_id(struct ccw_device *cdev, enum dev_event dev_event)
- 	struct subchannel *sch;
+-struct hpt_iopsg
+-{
++struct hpt_iopsg {
+ 	__le32 size;
+ 	__le32 eot; /* non-zero: end of table */
+ 	__le64 pci_address;
+ };
  
- 	sch = to_subchannel(cdev->dev.parent);
--	if (cio_enable_subchannel(sch, sch->schib.pmcw.isc) != 0)
-+	if (cio_enable_subchannel(sch, sch->schib.pmcw.isc,
-+				  (u32)(addr_t)sch) != 0)
- 		/* Couldn't enable the subchannel for i/o. Sick device. */
- 		return;
+-struct hpt_iop_request_block_command
+-{
++struct hpt_iop_request_block_command {
+ 	struct hpt_iop_request_header header;
+ 	u8     channel;
+ 	u8     target;
+@@ -156,8 +184,7 @@ struct hpt_iop_request_block_command
+ #define IOP_BLOCK_COMMAND_FLUSH    4
+ #define IOP_BLOCK_COMMAND_SHUTDOWN 5
  
-@@ -1006,9 +1065,9 @@ device_trigger_reprobe(struct subchannel *sch)
- {
- 	struct ccw_device *cdev;
+-struct hpt_iop_request_scsi_command
+-{
++struct hpt_iop_request_scsi_command {
+ 	struct hpt_iop_request_header header;
+ 	u8     channel;
+ 	u8     target;
+@@ -168,8 +195,7 @@ struct hpt_iop_request_scsi_command
+ 	struct hpt_iopsg sg_list[1];
+ };
  
--	if (!sch->dev.driver_data)
-+	cdev = sch_get_cdev(sch);
-+	if (!cdev)
- 		return;
--	cdev = sch->dev.driver_data;
- 	if (cdev->private->state != DEV_STATE_DISCONNECTED)
- 		return;
+-struct hpt_iop_request_ioctl_command
+-{
++struct hpt_iop_request_ioctl_command {
+ 	struct hpt_iop_request_header header;
+ 	__le32 ioctl_code;
+ 	__le32 inbuf_size;
+@@ -182,11 +208,11 @@ struct hpt_iop_request_ioctl_command
+ #define HPTIOP_MAX_REQUESTS  256u
  
-@@ -1028,7 +1087,7 @@ device_trigger_reprobe(struct subchannel *sch)
- 	sch->schib.pmcw.ena = 0;
- 	if ((sch->lpm & (sch->lpm - 1)) != 0)
- 		sch->schib.pmcw.mp = 1;
--	sch->schib.pmcw.intparm = (__u32)(unsigned long)sch;
-+	sch->schib.pmcw.intparm = (u32)(addr_t)sch;
- 	/* We should also udate ssd info, but this has to wait. */
- 	/* Check if this is another device which appeared on the same sch. */
- 	if (sch->schib.pmcw.dev != cdev->private->dev_id.devno) {
-@@ -1223,21 +1282,4 @@ fsm_func_t *dev_jumptable[NR_DEV_STATES][NR_DEV_EVENTS] = {
- 	},
+ struct hptiop_request {
+-	struct hptiop_request * next;
+-	void *                  req_virt;
+-	u32                     req_shifted_phy;
+-	struct scsi_cmnd *      scp;
+-	int                     index;
++	struct hptiop_request *next;
++	void                  *req_virt;
++	u32                   req_shifted_phy;
++	struct scsi_cmnd      *scp;
++	int                   index;
+ };
+ 
+ struct hpt_scsi_pointer {
+@@ -198,9 +224,21 @@ struct hpt_scsi_pointer {
+ #define HPT_SCP(scp) ((struct hpt_scsi_pointer *)&(scp)->SCp)
+ 
+ struct hptiop_hba {
+-	struct hpt_iopmu __iomem * iop;
+-	struct Scsi_Host * host;
+-	struct pci_dev * pcidev;
++	struct hptiop_adapter_ops *ops;
++	union {
++		struct {
++			struct hpt_iopmu_itl __iomem *iop;
++		} itl;
++		struct {
++			struct hpt_iopmv_regs *regs;
++			struct hpt_iopmu_mv __iomem *mu;
++			void *internal_req;
++			dma_addr_t internal_req_phy;
++		} mv;
++	} u;
++
++	struct Scsi_Host *host;
++	struct pci_dev *pcidev;
+ 
+ 	/* IOP config info */
+ 	u32     interface_version;
+@@ -213,15 +251,15 @@ struct hptiop_hba {
+ 
+ 	u32     req_size; /* host-allocated request buffer size */
+ 
+-	int     iopintf_v2: 1;
+-	int     initialized: 1;
+-	int     msg_done: 1;
++	u32     iopintf_v2: 1;
++	u32     initialized: 1;
++	u32     msg_done: 1;
+ 
+ 	struct hptiop_request * req_list;
+ 	struct hptiop_request reqs[HPTIOP_MAX_REQUESTS];
+ 
+ 	/* used to free allocated dma area */
+-	void *      dma_coherent;
++	void        *dma_coherent;
+ 	dma_addr_t  dma_coherent_handle;
+ 
+ 	atomic_t    reset_count;
+@@ -231,19 +269,35 @@ struct hptiop_hba {
+ 	wait_queue_head_t ioctl_wq;
  };
  
--/*
-- * io_subchannel_irq is called for "real" interrupts or for status
-- * pending conditions on msch.
-- */
--void
--io_subchannel_irq (struct device *pdev)
+-struct hpt_ioctl_k
 -{
--	struct ccw_device *cdev;
--
--	cdev = to_subchannel(pdev)->dev.driver_data;
--
--	CIO_TRACE_EVENT (3, "IRQ");
--	CIO_TRACE_EVENT (3, pdev->bus_id);
--	if (cdev)
--		dev_fsm_event(cdev, DEV_EVENT_INTERRUPT);
--}
--
- EXPORT_SYMBOL_GPL(ccw_device_set_timeout);
-diff --git a/drivers/s390/cio/device_id.c b/drivers/s390/cio/device_id.c
-index 156f3f9..918b8b8 100644
---- a/drivers/s390/cio/device_id.c
-+++ b/drivers/s390/cio/device_id.c
-@@ -24,6 +24,7 @@
- #include "css.h"
- #include "device.h"
- #include "ioasm.h"
-+#include "io_sch.h"
- 
- /*
-  * Input :
-@@ -219,11 +220,13 @@ ccw_device_check_sense_id(struct ccw_device *cdev)
- 		return -EAGAIN;
- 	}
- 	if (irb->scsw.cc == 3) {
--		if ((sch->orb.lpm &
--		     sch->schib.pmcw.pim & sch->schib.pmcw.pam) != 0)
-+		u8 lpm;
-+
-+		lpm = to_io_private(sch)->orb.lpm;
-+		if ((lpm & sch->schib.pmcw.pim & sch->schib.pmcw.pam) != 0)
- 			CIO_MSG_EVENT(2, "SenseID : path %02X for device %04x "
- 				      "on subchannel 0.%x.%04x is "
--				      "'not operational'\n", sch->orb.lpm,
-+				      "'not operational'\n", lpm,
- 				      cdev->private->dev_id.devno,
- 				      sch->schid.ssid, sch->schid.sch_no);
- 		return -EACCES;
-diff --git a/drivers/s390/cio/device_ops.c b/drivers/s390/cio/device_ops.c
-index 7fd2dad..49b58eb 100644
---- a/drivers/s390/cio/device_ops.c
-+++ b/drivers/s390/cio/device_ops.c
-@@ -501,7 +501,7 @@ ccw_device_stlck(struct ccw_device *cdev)
- 		return -ENOMEM;
- 	}
- 	spin_lock_irqsave(sch->lock, flags);
--	ret = cio_enable_subchannel(sch, 3);
-+	ret = cio_enable_subchannel(sch, 3, (u32)(addr_t)sch);
- 	if (ret)
- 		goto out_unlock;
- 	/*
-diff --git a/drivers/s390/cio/device_pgid.c b/drivers/s390/cio/device_pgid.c
-index cb1879a..c52449a 100644
---- a/drivers/s390/cio/device_pgid.c
-+++ b/drivers/s390/cio/device_pgid.c
-@@ -22,6 +22,7 @@
- #include "css.h"
- #include "device.h"
- #include "ioasm.h"
-+#include "io_sch.h"
++struct hpt_ioctl_k {
+ 	struct hptiop_hba * hba;
+ 	u32    ioctl_code;
+ 	u32    inbuf_size;
+ 	u32    outbuf_size;
+-	void * inbuf;
+-	void * outbuf;
+-	u32  * bytes_returned;
++	void   *inbuf;
++	void   *outbuf;
++	u32    *bytes_returned;
+ 	void (*done)(struct hpt_ioctl_k *);
+ 	int    result; /* HPT_IOCTL_RESULT_ */
+ };
  
- /*
-  * Helper function called from interrupt context to decide whether an
-@@ -155,10 +156,13 @@ __ccw_device_check_sense_pgid(struct ccw_device *cdev)
- 		return -EAGAIN;
- 	}
- 	if (irb->scsw.cc == 3) {
-+		u8 lpm;
++struct hptiop_adapter_ops {
++	int  (*iop_wait_ready)(struct hptiop_hba *hba, u32 millisec);
++	int  (*internal_memalloc)(struct hptiop_hba *hba);
++	int  (*internal_memfree)(struct hptiop_hba *hba);
++	int  (*map_pci_bar)(struct hptiop_hba *hba);
++	void (*unmap_pci_bar)(struct hptiop_hba *hba);
++	void (*enable_intr)(struct hptiop_hba *hba);
++	void (*disable_intr)(struct hptiop_hba *hba);
++	int  (*get_config)(struct hptiop_hba *hba,
++				struct hpt_iop_request_get_config *config);
++	int  (*set_config)(struct hptiop_hba *hba,
++				struct hpt_iop_request_set_config *config);
++	int  (*iop_intr)(struct hptiop_hba *hba);
++	void (*post_msg)(struct hptiop_hba *hba, u32 msg);
++	void (*post_req)(struct hptiop_hba *hba, struct hptiop_request *_req);
++};
 +
-+		lpm = to_io_private(sch)->orb.lpm;
- 		CIO_MSG_EVENT(2, "SNID - Device %04x on Subchannel 0.%x.%04x,"
- 			      " lpm %02X, became 'not operational'\n",
- 			      cdev->private->dev_id.devno, sch->schid.ssid,
--			      sch->schid.sch_no, sch->orb.lpm);
-+			      sch->schid.sch_no, lpm);
- 		return -EACCES;
- 	}
- 	i = 8 - ffs(cdev->private->imask);
-diff --git a/drivers/s390/cio/device_status.c b/drivers/s390/cio/device_status.c
-index aa96e67..ebe0848 100644
---- a/drivers/s390/cio/device_status.c
-+++ b/drivers/s390/cio/device_status.c
-@@ -20,6 +20,7 @@
- #include "css.h"
- #include "device.h"
- #include "ioasm.h"
-+#include "io_sch.h"
+ #define HPT_IOCTL_RESULT_OK         0
+ #define HPT_IOCTL_RESULT_FAILED     (-1)
  
- /*
-  * Check for any kind of channel or interface control check but don't
-@@ -310,6 +311,7 @@ int
- ccw_device_do_sense(struct ccw_device *cdev, struct irb *irb)
- {
- 	struct subchannel *sch;
-+	struct ccw1 *sense_ccw;
+diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c
+index 5f2396c..3081901 100644
+--- a/drivers/scsi/ibmvscsi/ibmvscsi.c
++++ b/drivers/scsi/ibmvscsi/ibmvscsi.c
+@@ -629,6 +629,16 @@ static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct,
+ 		list_del(&evt_struct->list);
+ 		del_timer(&evt_struct->timer);
  
- 	sch = to_subchannel(cdev->dev.parent);
++		/* If send_crq returns H_CLOSED, return SCSI_MLQUEUE_HOST_BUSY.
++		 * Firmware will send a CRQ with a transport event (0xFF) to
++		 * tell this client what has happened to the transport.  This
++		 * will be handled in ibmvscsi_handle_crq()
++		 */
++		if (rc == H_CLOSED) {
++			dev_warn(hostdata->dev, "send warning. "
++			         "Receive queue closed, will retry.\n");
++			goto send_busy;
++		}
+ 		dev_err(hostdata->dev, "send error %d\n", rc);
+ 		atomic_inc(&hostdata->request_limit);
+ 		goto send_error;
+@@ -976,58 +986,74 @@ static int ibmvscsi_eh_abort_handler(struct scsi_cmnd *cmd)
+ 	int rsp_rc;
+ 	unsigned long flags;
+ 	u16 lun = lun_from_dev(cmd->device);
++	unsigned long wait_switch = 0;
  
-@@ -326,15 +328,16 @@ ccw_device_do_sense(struct ccw_device *cdev, struct irb *irb)
- 	/*
- 	 * We have ending status but no sense information. Do a basic sense.
+ 	/* First, find this command in our sent list so we can figure
+ 	 * out the correct tag
  	 */
--	sch->sense_ccw.cmd_code = CCW_CMD_BASIC_SENSE;
--	sch->sense_ccw.cda = (__u32) __pa(cdev->private->irb.ecw);
--	sch->sense_ccw.count = SENSE_MAX_COUNT;
--	sch->sense_ccw.flags = CCW_FLAG_SLI;
-+	sense_ccw = &to_io_private(sch)->sense_ccw;
-+	sense_ccw->cmd_code = CCW_CMD_BASIC_SENSE;
-+	sense_ccw->cda = (__u32) __pa(cdev->private->irb.ecw);
-+	sense_ccw->count = SENSE_MAX_COUNT;
-+	sense_ccw->flags = CCW_FLAG_SLI;
+ 	spin_lock_irqsave(hostdata->host->host_lock, flags);
+-	found_evt = NULL;
+-	list_for_each_entry(tmp_evt, &hostdata->sent, list) {
+-		if (tmp_evt->cmnd == cmd) {
+-			found_evt = tmp_evt;
+-			break;
++	wait_switch = jiffies + (init_timeout * HZ);
++	do {
++		found_evt = NULL;
++		list_for_each_entry(tmp_evt, &hostdata->sent, list) {
++			if (tmp_evt->cmnd == cmd) {
++				found_evt = tmp_evt;
++				break;
++			}
+ 		}
+-	}
  
- 	/* Reset internal retry indication. */
- 	cdev->private->flags.intretry = 0;
+-	if (!found_evt) {
+-		spin_unlock_irqrestore(hostdata->host->host_lock, flags);
+-		return SUCCESS;
+-	}
++		if (!found_evt) {
++			spin_unlock_irqrestore(hostdata->host->host_lock, flags);
++			return SUCCESS;
++		}
  
--	return cio_start (sch, &sch->sense_ccw, 0xff);
-+	return cio_start(sch, sense_ccw, 0xff);
- }
+-	evt = get_event_struct(&hostdata->pool);
+-	if (evt == NULL) {
+-		spin_unlock_irqrestore(hostdata->host->host_lock, flags);
+-		sdev_printk(KERN_ERR, cmd->device, "failed to allocate abort event\n");
+-		return FAILED;
+-	}
++		evt = get_event_struct(&hostdata->pool);
++		if (evt == NULL) {
++			spin_unlock_irqrestore(hostdata->host->host_lock, flags);
++			sdev_printk(KERN_ERR, cmd->device,
++				"failed to allocate abort event\n");
++			return FAILED;
++		}
+ 	
+-	init_event_struct(evt,
+-			  sync_completion,
+-			  VIOSRP_SRP_FORMAT,
+-			  init_timeout);
++		init_event_struct(evt,
++				  sync_completion,
++				  VIOSRP_SRP_FORMAT,
++				  init_timeout);
  
- /*
-diff --git a/drivers/s390/cio/io_sch.h b/drivers/s390/cio/io_sch.h
-new file mode 100644
-index 0000000..8c61316
---- /dev/null
-+++ b/drivers/s390/cio/io_sch.h
-@@ -0,0 +1,163 @@
-+#ifndef S390_IO_SCH_H
-+#define S390_IO_SCH_H
-+
-+#include "schid.h"
-+
-+/*
-+ * operation request block
-+ */
-+struct orb {
-+	u32 intparm;	/* interruption parameter */
-+	u32 key  : 4;	/* flags, like key, suspend control, etc. */
-+	u32 spnd : 1;	/* suspend control */
-+	u32 res1 : 1;	/* reserved */
-+	u32 mod  : 1;	/* modification control */
-+	u32 sync : 1;	/* synchronize control */
-+	u32 fmt  : 1;	/* format control */
-+	u32 pfch : 1;	/* prefetch control */
-+	u32 isic : 1;	/* initial-status-interruption control */
-+	u32 alcc : 1;	/* address-limit-checking control */
-+	u32 ssic : 1;	/* suppress-suspended-interr. control */
-+	u32 res2 : 1;	/* reserved */
-+	u32 c64  : 1;	/* IDAW/QDIO 64 bit control  */
-+	u32 i2k  : 1;	/* IDAW 2/4kB block size control */
-+	u32 lpm  : 8;	/* logical path mask */
-+	u32 ils  : 1;	/* incorrect length */
-+	u32 zero : 6;	/* reserved zeros */
-+	u32 orbx : 1;	/* ORB extension control */
-+	u32 cpa;	/* channel program address */
-+}  __attribute__ ((packed, aligned(4)));
-+
-+struct io_subchannel_private {
-+	struct orb orb;		/* operation request block */
-+	struct ccw1 sense_ccw;	/* static ccw for sense command */
-+} __attribute__ ((aligned(8)));
-+
-+#define to_io_private(n) ((struct io_subchannel_private *)n->private)
-+#define sch_get_cdev(n) (dev_get_drvdata(&n->dev))
-+#define sch_set_cdev(n, c) (dev_set_drvdata(&n->dev, c))
-+
-+#define MAX_CIWS 8
-+
-+/*
-+ * sense-id response buffer layout
-+ */
-+struct senseid {
-+	/* common part */
-+	u8  reserved;	/* always 0x'FF' */
-+	u16 cu_type;	/* control unit type */
-+	u8  cu_model;	/* control unit model */
-+	u16 dev_type;	/* device type */
-+	u8  dev_model;	/* device model */
-+	u8  unused;	/* padding byte */
-+	/* extended part */
-+	struct ciw ciw[MAX_CIWS];	/* variable # of CIWs */
-+}  __attribute__ ((packed, aligned(4)));
-+
-+struct ccw_device_private {
-+	struct ccw_device *cdev;
-+	struct subchannel *sch;
-+	int state;		/* device state */
-+	atomic_t onoff;
-+	unsigned long registered;
-+	struct ccw_dev_id dev_id;	/* device id */
-+	struct subchannel_id schid;	/* subchannel number */
-+	u8 imask;		/* lpm mask for SNID/SID/SPGID */
-+	int iretry;		/* retry counter SNID/SID/SPGID */
-+	struct {
-+		unsigned int fast:1;	/* post with "channel end" */
-+		unsigned int repall:1;	/* report every interrupt status */
-+		unsigned int pgroup:1;	/* do path grouping */
-+		unsigned int force:1;	/* allow forced online */
-+	} __attribute__ ((packed)) options;
-+	struct {
-+		unsigned int pgid_single:1; /* use single path for Set PGID */
-+		unsigned int esid:1;	    /* Ext. SenseID supported by HW */
-+		unsigned int dosense:1;	    /* delayed SENSE required */
-+		unsigned int doverify:1;    /* delayed path verification */
-+		unsigned int donotify:1;    /* call notify function */
-+		unsigned int recog_done:1;  /* dev. recog. complete */
-+		unsigned int fake_irb:1;    /* deliver faked irb */
-+		unsigned int intretry:1;    /* retry internal operation */
-+	} __attribute__((packed)) flags;
-+	unsigned long intparm;	/* user interruption parameter */
-+	struct qdio_irq *qdio_data;
-+	struct irb irb;		/* device status */
-+	struct senseid senseid;	/* SenseID info */
-+	struct pgid pgid[8];	/* path group IDs per chpid*/
-+	struct ccw1 iccws[2];	/* ccws for SNID/SID/SPGID commands */
-+	struct work_struct kick_work;
-+	wait_queue_head_t wait_q;
-+	struct timer_list timer;
-+	void *cmb;			/* measurement information */
-+	struct list_head cmb_list;	/* list of measured devices */
-+	u64 cmb_start_time;		/* clock value of cmb reset */
-+	void *cmb_wait;			/* deferred cmb enable/disable */
-+};
-+
-+static inline int ssch(struct subchannel_id schid, volatile struct orb *addr)
-+{
-+	register struct subchannel_id reg1 asm("1") = schid;
-+	int ccode;
-+
-+	asm volatile(
-+		"	ssch	0(%2)\n"
-+		"	ipm	%0\n"
-+		"	srl	%0,28"
-+		: "=d" (ccode) : "d" (reg1), "a" (addr), "m" (*addr) : "cc");
-+	return ccode;
-+}
-+
-+static inline int rsch(struct subchannel_id schid)
-+{
-+	register struct subchannel_id reg1 asm("1") = schid;
-+	int ccode;
-+
-+	asm volatile(
-+		"	rsch\n"
-+		"	ipm	%0\n"
-+		"	srl	%0,28"
-+		: "=d" (ccode) : "d" (reg1) : "cc");
-+	return ccode;
-+}
-+
-+static inline int csch(struct subchannel_id schid)
-+{
-+	register struct subchannel_id reg1 asm("1") = schid;
-+	int ccode;
+-	tsk_mgmt = &evt->iu.srp.tsk_mgmt;
++		tsk_mgmt = &evt->iu.srp.tsk_mgmt;
+ 	
+-	/* Set up an abort SRP command */
+-	memset(tsk_mgmt, 0x00, sizeof(*tsk_mgmt));
+-	tsk_mgmt->opcode = SRP_TSK_MGMT;
+-	tsk_mgmt->lun = ((u64) lun) << 48;
+-	tsk_mgmt->tsk_mgmt_func = SRP_TSK_ABORT_TASK;
+-	tsk_mgmt->task_tag = (u64) found_evt;
+-
+-	sdev_printk(KERN_INFO, cmd->device, "aborting command. lun 0x%lx, tag 0x%lx\n",
+-		    tsk_mgmt->lun, tsk_mgmt->task_tag);
+-
+-	evt->sync_srp = &srp_rsp;
+-	init_completion(&evt->comp);
+-	rsp_rc = ibmvscsi_send_srp_event(evt, hostdata, init_timeout * 2);
++		/* Set up an abort SRP command */
++		memset(tsk_mgmt, 0x00, sizeof(*tsk_mgmt));
++		tsk_mgmt->opcode = SRP_TSK_MGMT;
++		tsk_mgmt->lun = ((u64) lun) << 48;
++		tsk_mgmt->tsk_mgmt_func = SRP_TSK_ABORT_TASK;
++		tsk_mgmt->task_tag = (u64) found_evt;
 +
-+	asm volatile(
-+		"	csch\n"
-+		"	ipm	%0\n"
-+		"	srl	%0,28"
-+		: "=d" (ccode) : "d" (reg1) : "cc");
-+	return ccode;
-+}
++		evt->sync_srp = &srp_rsp;
 +
-+static inline int hsch(struct subchannel_id schid)
-+{
-+	register struct subchannel_id reg1 asm("1") = schid;
-+	int ccode;
++		init_completion(&evt->comp);
++		rsp_rc = ibmvscsi_send_srp_event(evt, hostdata, init_timeout * 2);
 +
-+	asm volatile(
-+		"	hsch\n"
-+		"	ipm	%0\n"
-+		"	srl	%0,28"
-+		: "=d" (ccode) : "d" (reg1) : "cc");
-+	return ccode;
-+}
++		if (rsp_rc != SCSI_MLQUEUE_HOST_BUSY)
++			break;
 +
-+static inline int xsch(struct subchannel_id schid)
-+{
-+	register struct subchannel_id reg1 asm("1") = schid;
-+	int ccode;
++		spin_unlock_irqrestore(hostdata->host->host_lock, flags);
++		msleep(10);
++		spin_lock_irqsave(hostdata->host->host_lock, flags);
++	} while (time_before(jiffies, wait_switch));
 +
-+	asm volatile(
-+		"	.insn	rre,0xb2760000,%1,0\n"
-+		"	ipm	%0\n"
-+		"	srl	%0,28"
-+		: "=d" (ccode) : "d" (reg1) : "cc");
-+	return ccode;
-+}
+ 	spin_unlock_irqrestore(hostdata->host->host_lock, flags);
 +
-+#endif
-diff --git a/drivers/s390/cio/ioasm.h b/drivers/s390/cio/ioasm.h
-index 7153dd9..652ea36 100644
---- a/drivers/s390/cio/ioasm.h
-+++ b/drivers/s390/cio/ioasm.h
-@@ -109,72 +109,6 @@ static inline int tpi( volatile struct tpi_info *addr)
- 	return ccode;
- }
- 
--static inline int ssch(struct subchannel_id schid,
--			   volatile struct orb *addr)
--{
--	register struct subchannel_id reg1 asm ("1") = schid;
--	int ccode;
--
--	asm volatile(
--		"	ssch	0(%2)\n"
--		"	ipm	%0\n"
--		"	srl	%0,28"
--		: "=d" (ccode) : "d" (reg1), "a" (addr), "m" (*addr) : "cc");
--	return ccode;
--}
--
--static inline int rsch(struct subchannel_id schid)
--{
--	register struct subchannel_id reg1 asm ("1") = schid;
--	int ccode;
--
--	asm volatile(
--		"	rsch\n"
--		"	ipm	%0\n"
--		"	srl	%0,28"
--		: "=d" (ccode) : "d" (reg1) : "cc");
--	return ccode;
--}
--
--static inline int csch(struct subchannel_id schid)
--{
--	register struct subchannel_id reg1 asm ("1") = schid;
--	int ccode;
--
--	asm volatile(
--		"	csch\n"
--		"	ipm	%0\n"
--		"	srl	%0,28"
--		: "=d" (ccode) : "d" (reg1) : "cc");
--	return ccode;
--}
--
--static inline int hsch(struct subchannel_id schid)
--{
--	register struct subchannel_id reg1 asm ("1") = schid;
--	int ccode;
--
--	asm volatile(
--		"	hsch\n"
--		"	ipm	%0\n"
--		"	srl	%0,28"
--		: "=d" (ccode) : "d" (reg1) : "cc");
--	return ccode;
--}
--
--static inline int xsch(struct subchannel_id schid)
--{
--	register struct subchannel_id reg1 asm ("1") = schid;
--	int ccode;
--
--	asm volatile(
--		"	.insn	rre,0xb2760000,%1,0\n"
--		"	ipm	%0\n"
--		"	srl	%0,28"
--		: "=d" (ccode) : "d" (reg1) : "cc");
--	return ccode;
--}
--
- static inline int chsc(void *chsc_area)
- {
- 	typedef struct { char _[4096]; } addr_type;
-diff --git a/drivers/s390/cio/qdio.c b/drivers/s390/cio/qdio.c
-index 40a3208..e2a781b 100644
---- a/drivers/s390/cio/qdio.c
-+++ b/drivers/s390/cio/qdio.c
-@@ -48,11 +48,11 @@
- #include <asm/debug.h>
- #include <asm/s390_rdev.h>
- #include <asm/qdio.h>
-+#include <asm/airq.h>
+ 	if (rsp_rc != 0) {
+ 		sdev_printk(KERN_ERR, cmd->device,
+ 			    "failed to send abort() event. rc=%d\n", rsp_rc);
+ 		return FAILED;
+ 	}
  
- #include "cio.h"
- #include "css.h"
- #include "device.h"
--#include "airq.h"
- #include "qdio.h"
- #include "ioasm.h"
- #include "chsc.h"
-@@ -96,7 +96,7 @@ static debug_info_t *qdio_dbf_slsb_in;
- static volatile struct qdio_q *tiq_list=NULL; /* volatile as it could change
- 						 during a while loop */
- static DEFINE_SPINLOCK(ttiq_list_lock);
--static int register_thinint_result;
-+static void *tiqdio_ind;
- static void tiqdio_tl(unsigned long);
- static DECLARE_TASKLET(tiqdio_tasklet,tiqdio_tl,0);
++	sdev_printk(KERN_INFO, cmd->device,
++                    "aborting command. lun 0x%lx, tag 0x%lx\n",
++		    (((u64) lun) << 48), (u64) found_evt);
++
+ 	wait_for_completion(&evt->comp);
  
-@@ -399,7 +399,7 @@ qdio_get_indicator(void)
- {
- 	int i;
+ 	/* make sure we got a good response */
+@@ -1099,41 +1125,56 @@ static int ibmvscsi_eh_device_reset_handler(struct scsi_cmnd *cmd)
+ 	int rsp_rc;
+ 	unsigned long flags;
+ 	u16 lun = lun_from_dev(cmd->device);
++	unsigned long wait_switch = 0;
  
--	for (i=1;i<INDICATORS_PER_CACHELINE;i++)
-+	for (i = 0; i < INDICATORS_PER_CACHELINE; i++)
- 		if (!indicator_used[i]) {
- 			indicator_used[i]=1;
- 			return indicators+i;
-@@ -1408,8 +1408,7 @@ __tiqdio_inbound_processing(struct qdio_q *q, int spare_ind_was_set)
- 	if (q->hydra_gives_outbound_pcis) {
- 		if (!q->siga_sync_done_on_thinints) {
- 			SYNC_MEMORY_ALL;
--		} else if ((!q->siga_sync_done_on_outb_tis)&&
--			 (q->hydra_gives_outbound_pcis)) {
-+		} else if (!q->siga_sync_done_on_outb_tis) {
- 			SYNC_MEMORY_ALL_OUTB;
- 		}
- 	} else {
-@@ -1911,8 +1910,7 @@ qdio_fill_thresholds(struct qdio_irq *irq_ptr,
- 	}
- }
+ 	spin_lock_irqsave(hostdata->host->host_lock, flags);
+-	evt = get_event_struct(&hostdata->pool);
+-	if (evt == NULL) {
+-		spin_unlock_irqrestore(hostdata->host->host_lock, flags);
+-		sdev_printk(KERN_ERR, cmd->device, "failed to allocate reset event\n");
+-		return FAILED;
+-	}
++	wait_switch = jiffies + (init_timeout * HZ);
++	do {
++		evt = get_event_struct(&hostdata->pool);
++		if (evt == NULL) {
++			spin_unlock_irqrestore(hostdata->host->host_lock, flags);
++			sdev_printk(KERN_ERR, cmd->device,
++				"failed to allocate reset event\n");
++			return FAILED;
++		}
+ 	
+-	init_event_struct(evt,
+-			  sync_completion,
+-			  VIOSRP_SRP_FORMAT,
+-			  init_timeout);
++		init_event_struct(evt,
++				  sync_completion,
++				  VIOSRP_SRP_FORMAT,
++				  init_timeout);
  
--static int
--tiqdio_thinint_handler(void)
-+static void tiqdio_thinint_handler(void *ind, void *drv_data)
- {
- 	QDIO_DBF_TEXT4(0,trace,"thin_int");
+-	tsk_mgmt = &evt->iu.srp.tsk_mgmt;
++		tsk_mgmt = &evt->iu.srp.tsk_mgmt;
  
-@@ -1925,7 +1923,6 @@ tiqdio_thinint_handler(void)
- 		tiqdio_clear_global_summary();
+-	/* Set up a lun reset SRP command */
+-	memset(tsk_mgmt, 0x00, sizeof(*tsk_mgmt));
+-	tsk_mgmt->opcode = SRP_TSK_MGMT;
+-	tsk_mgmt->lun = ((u64) lun) << 48;
+-	tsk_mgmt->tsk_mgmt_func = SRP_TSK_LUN_RESET;
++		/* Set up a lun reset SRP command */
++		memset(tsk_mgmt, 0x00, sizeof(*tsk_mgmt));
++		tsk_mgmt->opcode = SRP_TSK_MGMT;
++		tsk_mgmt->lun = ((u64) lun) << 48;
++		tsk_mgmt->tsk_mgmt_func = SRP_TSK_LUN_RESET;
  
- 	tiqdio_inbound_checks();
--	return 0;
- }
+-	sdev_printk(KERN_INFO, cmd->device, "resetting device. lun 0x%lx\n",
+-		    tsk_mgmt->lun);
++		evt->sync_srp = &srp_rsp;
++
++		init_completion(&evt->comp);
++		rsp_rc = ibmvscsi_send_srp_event(evt, hostdata, init_timeout * 2);
++
++		if (rsp_rc != SCSI_MLQUEUE_HOST_BUSY)
++			break;
++
++		spin_unlock_irqrestore(hostdata->host->host_lock, flags);
++		msleep(10);
++		spin_lock_irqsave(hostdata->host->host_lock, flags);
++	} while (time_before(jiffies, wait_switch));
  
- static void
-@@ -2445,7 +2442,7 @@ tiqdio_set_subchannel_ind(struct qdio_irq *irq_ptr, int reset_to_zero)
- 		real_addr_dev_st_chg_ind=0;
- 	} else {
- 		real_addr_local_summary_bit=
--			virt_to_phys((volatile void *)indicators);
-+			virt_to_phys((volatile void *)tiqdio_ind);
- 		real_addr_dev_st_chg_ind=
- 			virt_to_phys((volatile void *)irq_ptr->dev_st_chg_ind);
- 	}
-@@ -3740,23 +3737,25 @@ static void
- tiqdio_register_thinints(void)
- {
- 	char dbf_text[20];
--	register_thinint_result=
--		s390_register_adapter_interrupt(&tiqdio_thinint_handler);
--	if (register_thinint_result) {
--		sprintf(dbf_text,"regthn%x",(register_thinint_result&0xff));
+-	evt->sync_srp = &srp_rsp;
+-	init_completion(&evt->comp);
+-	rsp_rc = ibmvscsi_send_srp_event(evt, hostdata, init_timeout * 2);
+ 	spin_unlock_irqrestore(hostdata->host->host_lock, flags);
 +
-+	tiqdio_ind =
-+		s390_register_adapter_interrupt(&tiqdio_thinint_handler, NULL);
-+	if (IS_ERR(tiqdio_ind)) {
-+		sprintf(dbf_text, "regthn%lx", PTR_ERR(tiqdio_ind));
- 		QDIO_DBF_TEXT0(0,setup,dbf_text);
- 		QDIO_PRINT_ERR("failed to register adapter handler " \
--			       "(rc=%i).\nAdapter interrupts might " \
-+			       "(rc=%li).\nAdapter interrupts might " \
- 			       "not work. Continuing.\n",
--			       register_thinint_result);
-+			       PTR_ERR(tiqdio_ind));
-+		tiqdio_ind = NULL;
+ 	if (rsp_rc != 0) {
+ 		sdev_printk(KERN_ERR, cmd->device,
+ 			    "failed to send reset event. rc=%d\n", rsp_rc);
+ 		return FAILED;
  	}
- }
  
- static void
- tiqdio_unregister_thinints(void)
- {
--	if (!register_thinint_result)
--		s390_unregister_adapter_interrupt(&tiqdio_thinint_handler);
-+	if (tiqdio_ind)
-+		s390_unregister_adapter_interrupt(tiqdio_ind);
- }
++	sdev_printk(KERN_INFO, cmd->device, "resetting device. lun 0x%lx\n",
++		    (((u64) lun) << 48));
++
+ 	wait_for_completion(&evt->comp);
  
- static int
-@@ -3768,8 +3767,8 @@ qdio_get_qdio_memory(void)
- 	for (i=1;i<INDICATORS_PER_CACHELINE;i++)
- 		indicator_used[i]=0;
- 	indicators = kzalloc(sizeof(__u32)*(INDICATORS_PER_CACHELINE),
--				   GFP_KERNEL);
--       	if (!indicators)
-+			     GFP_KERNEL);
-+	if (!indicators)
- 		return -ENOMEM;
+ 	/* make sure we got a good response */
+@@ -1386,8 +1427,10 @@ static int ibmvscsi_slave_configure(struct scsi_device *sdev)
+ 	unsigned long lock_flags = 0;
+ 
+ 	spin_lock_irqsave(shost->host_lock, lock_flags);
+-	if (sdev->type == TYPE_DISK)
++	if (sdev->type == TYPE_DISK) {
+ 		sdev->allow_restart = 1;
++		sdev->timeout = 60 * HZ;
++	}
+ 	scsi_adjust_queue_depth(sdev, 0, shost->cmd_per_lun);
+ 	spin_unlock_irqrestore(shost->host_lock, lock_flags);
  	return 0;
- }
-@@ -3780,7 +3779,6 @@ qdio_release_qdio_memory(void)
- 	kfree(indicators);
- }
+diff --git a/drivers/scsi/ibmvscsi/ibmvstgt.c b/drivers/scsi/ibmvscsi/ibmvstgt.c
+index 82bcab6..d63f11e 100644
+--- a/drivers/scsi/ibmvscsi/ibmvstgt.c
++++ b/drivers/scsi/ibmvscsi/ibmvstgt.c
+@@ -292,7 +292,7 @@ static int ibmvstgt_cmd_done(struct scsi_cmnd *sc,
+ 	dprintk("%p %p %x %u\n", iue, target, vio_iu(iue)->srp.cmd.cdb[0],
+ 		cmd->usg_sg);
  
--
- static void
- qdio_unregister_dbf_views(void)
+-	if (sc->use_sg)
++	if (scsi_sg_count(sc))
+ 		err = srp_transfer_data(sc, &vio_iu(iue)->srp.cmd, ibmvstgt_rdma, 1, 1);
+ 
+ 	spin_lock_irqsave(&target->lock, flags);
+diff --git a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c
+index 9706de9..db8bc20 100644
+--- a/drivers/scsi/ide-scsi.c
++++ b/drivers/scsi/ide-scsi.c
+@@ -395,14 +395,12 @@ static int idescsi_expiry(ide_drive_t *drive)
+ static ide_startstop_t idescsi_pc_intr (ide_drive_t *drive)
  {
-diff --git a/drivers/s390/cio/qdio.h b/drivers/s390/cio/qdio.h
-index 6d7aad1..37870e4 100644
---- a/drivers/s390/cio/qdio.h
-+++ b/drivers/s390/cio/qdio.h
-@@ -57,7 +57,7 @@
- 					    of the queue to 0 */
+ 	idescsi_scsi_t *scsi = drive_to_idescsi(drive);
+-	idescsi_pc_t *pc=scsi->pc;
++	ide_hwif_t *hwif = drive->hwif;
++	idescsi_pc_t *pc = scsi->pc;
+ 	struct request *rq = pc->rq;
+-	atapi_bcount_t bcount;
+-	atapi_status_t status;
+-	atapi_ireason_t ireason;
+-	atapi_feature_t feature;
+-
+ 	unsigned int temp;
++	u16 bcount;
++	u8 stat, ireason;
  
- #define QDIO_ESTABLISH_TIMEOUT (1*HZ)
--#define QDIO_ACTIVATE_TIMEOUT ((5*HZ)>>10)
-+#define QDIO_ACTIVATE_TIMEOUT (5*HZ)
- #define QDIO_CLEANUP_CLEAR_TIMEOUT (20*HZ)
- #define QDIO_CLEANUP_HALT_TIMEOUT (10*HZ)
- #define QDIO_FORCE_CHECK_TIMEOUT (10*HZ)
-diff --git a/drivers/s390/net/claw.c b/drivers/s390/net/claw.c
-index 3561982..c307621 100644
---- a/drivers/s390/net/claw.c
-+++ b/drivers/s390/net/claw.c
-@@ -2416,7 +2416,7 @@ init_ccw_bk(struct net_device *dev)
- 		    privptr->p_buff_pages_perwrite);
- #endif
-                    if (p_buff==NULL) {
--                        printk(KERN_INFO "%s:%s __get_free_pages"
-+			printk(KERN_INFO "%s:%s __get_free_pages "
- 			 	"for writes buf failed : get is for %d pages\n",
- 				dev->name,
- 				__FUNCTION__,
-diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c
-index 0fd663b..7bfe8d7 100644
---- a/drivers/s390/net/lcs.c
-+++ b/drivers/s390/net/lcs.c
-@@ -1115,7 +1115,7 @@ list_modified:
- 			rc = lcs_send_setipm(card, ipm);
- 			spin_lock_irqsave(&card->ipm_lock, flags);
- 			if (rc) {
--				PRINT_INFO("Adding multicast address failed."
-+				PRINT_INFO("Adding multicast address failed. "
- 					   "Table possibly full!\n");
- 				/* store ipm in failed list -> will be added
- 				 * to ipm_list again, so a retry will be done
-diff --git a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c
-index c7ea938..f3d893c 100644
---- a/drivers/s390/net/netiucv.c
-+++ b/drivers/s390/net/netiucv.c
-@@ -198,8 +198,7 @@ struct iucv_connection {
- /**
-  * Linked list of all connection structs.
-  */
--static struct list_head iucv_connection_list =
--	LIST_HEAD_INIT(iucv_connection_list);
-+static LIST_HEAD(iucv_connection_list);
- static DEFINE_RWLOCK(iucv_connection_rwlock);
+ #if IDESCSI_DEBUG_LOG
+ 	printk (KERN_INFO "ide-scsi: Reached idescsi_pc_intr interrupt handler\n");
+@@ -425,30 +423,29 @@ static ide_startstop_t idescsi_pc_intr (ide_drive_t *drive)
+ 		(void) HWIF(drive)->ide_dma_end(drive);
+ 	}
  
- /**
-@@ -2089,6 +2088,11 @@ static struct attribute_group netiucv_drv_attr_group = {
- 	.attrs = netiucv_drv_attrs,
- };
+-	feature.all = 0;
+ 	/* Clear the interrupt */
+-	status.all = HWIF(drive)->INB(IDE_STATUS_REG);
++	stat = drive->hwif->INB(IDE_STATUS_REG);
  
-+static struct attribute_group *netiucv_drv_attr_groups[] = {
-+	&netiucv_drv_attr_group,
-+	NULL,
-+};
-+
- static void netiucv_banner(void)
- {
- 	PRINT_INFO("NETIUCV driver initialized\n");
-@@ -2113,7 +2117,6 @@ static void __exit netiucv_exit(void)
- 		netiucv_unregister_device(dev);
+-	if (!status.b.drq) {
++	if ((stat & DRQ_STAT) == 0) {
+ 		/* No more interrupts */
+ 		if (test_bit(IDESCSI_LOG_CMD, &scsi->log))
+ 			printk (KERN_INFO "Packet command completed, %d bytes transferred\n", pc->actually_transferred);
+ 		local_irq_enable_in_hardirq();
+-		if (status.b.check)
++		if (stat & ERR_STAT)
+ 			rq->errors++;
+ 		idescsi_end_request (drive, 1, 0);
+ 		return ide_stopped;
  	}
+-	bcount.b.low	= HWIF(drive)->INB(IDE_BCOUNTL_REG);
+-	bcount.b.high	= HWIF(drive)->INB(IDE_BCOUNTH_REG);
+-	ireason.all	= HWIF(drive)->INB(IDE_IREASON_REG);
++	bcount = (hwif->INB(IDE_BCOUNTH_REG) << 8) |
++		  hwif->INB(IDE_BCOUNTL_REG);
++	ireason = hwif->INB(IDE_IREASON_REG);
  
--	sysfs_remove_group(&netiucv_driver.kobj, &netiucv_drv_attr_group);
- 	driver_unregister(&netiucv_driver);
- 	iucv_unregister(&netiucv_handler, 1);
- 	iucv_unregister_dbf_views();
-@@ -2133,6 +2136,7 @@ static int __init netiucv_init(void)
- 	if (rc)
- 		goto out_dbf;
- 	IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
-+	netiucv_driver.groups = netiucv_drv_attr_groups;
- 	rc = driver_register(&netiucv_driver);
- 	if (rc) {
- 		PRINT_ERR("NETIUCV: failed to register driver.\n");
-@@ -2140,18 +2144,9 @@ static int __init netiucv_init(void)
- 		goto out_iucv;
+-	if (ireason.b.cod) {
++	if (ireason & CD) {
+ 		printk(KERN_ERR "ide-scsi: CoD != 0 in idescsi_pc_intr\n");
+ 		return ide_do_reset (drive);
+ 	}
+-	if (ireason.b.io) {
+-		temp = pc->actually_transferred + bcount.all;
++	if (ireason & IO) {
++		temp = pc->actually_transferred + bcount;
+ 		if (temp > pc->request_transfer) {
+ 			if (temp > pc->buffer_size) {
+ 				printk(KERN_ERR "ide-scsi: The scsi wants to "
+@@ -461,11 +458,13 @@ static ide_startstop_t idescsi_pc_intr (ide_drive_t *drive)
+ 						idescsi_input_buffers(drive, pc, temp);
+ 					else
+ 						drive->hwif->atapi_input_bytes(drive, pc->current_position, temp);
+-					printk(KERN_ERR "ide-scsi: transferred %d of %d bytes\n", temp, bcount.all);
++					printk(KERN_ERR "ide-scsi: transferred"
++							" %d of %d bytes\n",
++							temp, bcount);
+ 				}
+ 				pc->actually_transferred += temp;
+ 				pc->current_position += temp;
+-				idescsi_discard_data(drive, bcount.all - temp);
++				idescsi_discard_data(drive, bcount - temp);
+ 				ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc), idescsi_expiry);
+ 				return ide_started;
+ 			}
+@@ -474,22 +473,24 @@ static ide_startstop_t idescsi_pc_intr (ide_drive_t *drive)
+ #endif /* IDESCSI_DEBUG_LOG */
+ 		}
+ 	}
+-	if (ireason.b.io) {
++	if (ireason & IO) {
+ 		clear_bit(PC_WRITING, &pc->flags);
+ 		if (pc->sg)
+-			idescsi_input_buffers(drive, pc, bcount.all);
++			idescsi_input_buffers(drive, pc, bcount);
+ 		else
+-			HWIF(drive)->atapi_input_bytes(drive, pc->current_position, bcount.all);
++			hwif->atapi_input_bytes(drive, pc->current_position,
++						bcount);
+ 	} else {
+ 		set_bit(PC_WRITING, &pc->flags);
+ 		if (pc->sg)
+-			idescsi_output_buffers (drive, pc, bcount.all);
++			idescsi_output_buffers(drive, pc, bcount);
+ 		else
+-			HWIF(drive)->atapi_output_bytes(drive, pc->current_position, bcount.all);
++			hwif->atapi_output_bytes(drive, pc->current_position,
++						 bcount);
  	}
+ 	/* Update the current position */
+-	pc->actually_transferred += bcount.all;
+-	pc->current_position += bcount.all;
++	pc->actually_transferred += bcount;
++	pc->current_position += bcount;
  
--	rc = sysfs_create_group(&netiucv_driver.kobj, &netiucv_drv_attr_group);
--	if (rc) {
--		PRINT_ERR("NETIUCV: failed to add driver attributes.\n");
--		IUCV_DBF_TEXT_(setup, 2,
--			       "ret %d - netiucv_drv_attr_group\n", rc);
--		goto out_driver;
--	}
- 	netiucv_banner();
- 	return rc;
+ 	/* And set the interrupt handler again */
+ 	ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc), idescsi_expiry);
+@@ -501,16 +502,16 @@ static ide_startstop_t idescsi_transfer_pc(ide_drive_t *drive)
+ 	ide_hwif_t *hwif = drive->hwif;
+ 	idescsi_scsi_t *scsi = drive_to_idescsi(drive);
+ 	idescsi_pc_t *pc = scsi->pc;
+-	atapi_ireason_t ireason;
+ 	ide_startstop_t startstop;
++	u8 ireason;
  
--out_driver:
--	driver_unregister(&netiucv_driver);
- out_iucv:
- 	iucv_unregister(&netiucv_handler, 1);
- out_dbf:
-diff --git a/drivers/s390/net/qeth_proc.c b/drivers/s390/net/qeth_proc.c
-index f1ff165..46ecd03 100644
---- a/drivers/s390/net/qeth_proc.c
-+++ b/drivers/s390/net/qeth_proc.c
-@@ -146,7 +146,7 @@ qeth_procfile_seq_show(struct seq_file *s, void *it)
- 	return 0;
- }
+ 	if (ide_wait_stat(&startstop,drive,DRQ_STAT,BUSY_STAT,WAIT_READY)) {
+ 		printk(KERN_ERR "ide-scsi: Strange, packet command "
+ 			"initiated yet DRQ isn't asserted\n");
+ 		return startstop;
+ 	}
+-	ireason.all	= HWIF(drive)->INB(IDE_IREASON_REG);
+-	if (!ireason.b.cod || ireason.b.io) {
++	ireason = hwif->INB(IDE_IREASON_REG);
++	if ((ireason & CD) == 0 || (ireason & IO)) {
+ 		printk(KERN_ERR "ide-scsi: (IO,CoD) != (0,1) while "
+ 				"issuing a packet command\n");
+ 		return ide_do_reset (drive);
+@@ -573,30 +574,26 @@ static ide_startstop_t idescsi_issue_pc (ide_drive_t *drive, idescsi_pc_t *pc)
+ {
+ 	idescsi_scsi_t *scsi = drive_to_idescsi(drive);
+ 	ide_hwif_t *hwif = drive->hwif;
+-	atapi_feature_t feature;
+-	atapi_bcount_t bcount;
++	u16 bcount;
++	u8 dma = 0;
  
--static struct seq_operations qeth_procfile_seq_ops = {
-+static const struct seq_operations qeth_procfile_seq_ops = {
- 	.start = qeth_procfile_seq_start,
- 	.stop  = qeth_procfile_seq_stop,
- 	.next  = qeth_procfile_seq_next,
-@@ -264,7 +264,7 @@ qeth_perf_procfile_seq_show(struct seq_file *s, void *it)
- 	return 0;
- }
+ 	scsi->pc=pc;							/* Set the current packet command */
+ 	pc->actually_transferred=0;					/* We haven't transferred any data yet */
+ 	pc->current_position=pc->buffer;
+-	bcount.all = min(pc->request_transfer, 63 * 1024);		/* Request to transfer the entire buffer at once */
++	/* Request to transfer the entire buffer at once */
++	bcount = min(pc->request_transfer, 63 * 1024);
  
--static struct seq_operations qeth_perf_procfile_seq_ops = {
-+static const struct seq_operations qeth_perf_procfile_seq_ops = {
- 	.start = qeth_procfile_seq_start,
- 	.stop  = qeth_procfile_seq_stop,
- 	.next  = qeth_procfile_seq_next,
-diff --git a/drivers/s390/net/smsgiucv.c b/drivers/s390/net/smsgiucv.c
-index 47bb47b..8735a41 100644
---- a/drivers/s390/net/smsgiucv.c
-+++ b/drivers/s390/net/smsgiucv.c
-@@ -42,7 +42,7 @@ MODULE_DESCRIPTION ("Linux for S/390 IUCV special message driver");
- static struct iucv_path *smsg_path;
+-	feature.all = 0;
+ 	if (drive->using_dma && !idescsi_map_sg(drive, pc)) {
+ 		hwif->sg_mapped = 1;
+-		feature.b.dma = !hwif->dma_setup(drive);
++		dma = !hwif->dma_setup(drive);
+ 		hwif->sg_mapped = 0;
+ 	}
  
- static DEFINE_SPINLOCK(smsg_list_lock);
--static struct list_head smsg_list = LIST_HEAD_INIT(smsg_list);
-+static LIST_HEAD(smsg_list);
+ 	SELECT_DRIVE(drive);
+-	if (IDE_CONTROL_REG)
+-		HWIF(drive)->OUTB(drive->ctl, IDE_CONTROL_REG);
  
- static int smsg_path_pending(struct iucv_path *, u8 ipvmid[8], u8 ipuser[16]);
- static void smsg_message_pending(struct iucv_path *, struct iucv_message *);
-diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c
-index 0011849..874b55e 100644
---- a/drivers/s390/scsi/zfcp_aux.c
-+++ b/drivers/s390/scsi/zfcp_aux.c
-@@ -844,8 +844,6 @@ zfcp_unit_enqueue(struct zfcp_port *port, fcp_lun_t fcp_lun)
- 	unit->sysfs_device.release = zfcp_sysfs_unit_release;
- 	dev_set_drvdata(&unit->sysfs_device, unit);
+-	HWIF(drive)->OUTB(feature.all, IDE_FEATURE_REG);
+-	HWIF(drive)->OUTB(bcount.b.high, IDE_BCOUNTH_REG);
+-	HWIF(drive)->OUTB(bcount.b.low, IDE_BCOUNTL_REG);
++	ide_pktcmd_tf_load(drive, IDE_TFLAG_NO_SELECT_MASK, bcount, dma);
  
--	init_waitqueue_head(&unit->scsi_scan_wq);
--
- 	/* mark unit unusable as long as sysfs registration is not complete */
- 	atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &unit->status);
+-	if (feature.b.dma)
++	if (dma)
+ 		set_bit(PC_DMA_OK, &pc->flags);
  
-diff --git a/drivers/s390/scsi/zfcp_ccw.c b/drivers/s390/scsi/zfcp_ccw.c
-index e01cbf1..edc5015 100644
---- a/drivers/s390/scsi/zfcp_ccw.c
-+++ b/drivers/s390/scsi/zfcp_ccw.c
-@@ -52,6 +52,9 @@ static struct ccw_driver zfcp_ccw_driver = {
- 	.set_offline = zfcp_ccw_set_offline,
- 	.notify      = zfcp_ccw_notify,
- 	.shutdown    = zfcp_ccw_shutdown,
-+	.driver = {
-+		.groups = zfcp_driver_attr_groups,
-+	},
- };
+ 	if (test_bit(IDESCSI_DRQ_INTERRUPT, &scsi->flags)) {
+@@ -922,8 +919,8 @@ static int idescsi_eh_reset (struct scsi_cmnd *cmd)
+ 	}
+ 
+ 	/* kill current request */
+-	blkdev_dequeue_request(req);
+-	end_that_request_last(req, 0);
++	if (__blk_end_request(req, -EIO, 0))
++		BUG();
+ 	if (blk_sense_request(req))
+ 		kfree(scsi->pc->buffer);
+ 	kfree(scsi->pc);
+@@ -932,8 +929,8 @@ static int idescsi_eh_reset (struct scsi_cmnd *cmd)
  
- MODULE_DEVICE_TABLE(ccw, zfcp_ccw_device_id);
-@@ -120,6 +123,9 @@ zfcp_ccw_remove(struct ccw_device *ccw_device)
+ 	/* now nuke the drive queue */
+ 	while ((req = elv_next_request(drive->queue))) {
+-		blkdev_dequeue_request(req);
+-		end_that_request_last(req, 0);
++		if (__blk_end_request(req, -EIO, 0))
++			BUG();
+ 	}
  
- 	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))
-+				scsi_remove_device(unit->device);
- 			zfcp_unit_dequeue(unit);
+ 	HWGROUP(drive)->rq = NULL;
+diff --git a/drivers/scsi/imm.c b/drivers/scsi/imm.c
+index a3d0c6b..f97d172 100644
+--- a/drivers/scsi/imm.c
++++ b/drivers/scsi/imm.c
+@@ -837,19 +837,16 @@ static int imm_engine(imm_struct *dev, struct scsi_cmnd *cmd)
+ 
+ 		/* Phase 4 - Setup scatter/gather buffers */
+ 	case 4:
+-		if (cmd->use_sg) {
+-			/* if many buffers are available, start filling the first */
+-			cmd->SCp.buffer =
+-			    (struct scatterlist *) cmd->request_buffer;
++		if (scsi_bufflen(cmd)) {
++			cmd->SCp.buffer = scsi_sglist(cmd);
+ 			cmd->SCp.this_residual = cmd->SCp.buffer->length;
+ 			cmd->SCp.ptr = sg_virt(cmd->SCp.buffer);
+ 		} else {
+-			/* else fill the only available buffer */
+ 			cmd->SCp.buffer = NULL;
+-			cmd->SCp.this_residual = cmd->request_bufflen;
+-			cmd->SCp.ptr = cmd->request_buffer;
++			cmd->SCp.this_residual = 0;
++			cmd->SCp.ptr = NULL;
  		}
- 		zfcp_port_dequeue(port);
-@@ -251,16 +257,7 @@ zfcp_ccw_notify(struct ccw_device *ccw_device, int event)
- int __init
- zfcp_ccw_register(void)
- {
--	int retval;
--
--	retval = ccw_driver_register(&zfcp_ccw_driver);
--	if (retval)
--		goto out;
--	retval = zfcp_sysfs_driver_create_files(&zfcp_ccw_driver.driver);
--	if (retval)
--		ccw_driver_unregister(&zfcp_ccw_driver);
-- out:
--	return retval;
-+	return ccw_driver_register(&zfcp_ccw_driver);
- }
+-		cmd->SCp.buffers_residual = cmd->use_sg - 1;
++		cmd->SCp.buffers_residual = scsi_sg_count(cmd) - 1;
+ 		cmd->SCp.phase++;
+ 		if (cmd->SCp.this_residual & 0x01)
+ 			cmd->SCp.this_residual++;
+diff --git a/drivers/scsi/in2000.c b/drivers/scsi/in2000.c
+index c8b452f..8053b1e 100644
+--- a/drivers/scsi/in2000.c
++++ b/drivers/scsi/in2000.c
+@@ -369,16 +369,16 @@ static int in2000_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
+  *  - SCp.phase records this command's SRCID_ER bit setting
+  */
  
- /**
-diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c
-index ffa3bf7..701046c 100644
---- a/drivers/s390/scsi/zfcp_dbf.c
-+++ b/drivers/s390/scsi/zfcp_dbf.c
-@@ -161,12 +161,6 @@ void zfcp_hba_dbf_event_fsf_response(struct zfcp_fsf_req *fsf_req)
- 		   (fsf_req->fsf_command == FSF_QTCB_OPEN_LUN)) {
- 		strncpy(rec->tag2, "open", ZFCP_DBF_TAG_SIZE);
- 		level = 4;
--	} else if ((prot_status_qual->doubleword[0] != 0) ||
--		   (prot_status_qual->doubleword[1] != 0) ||
--		   (fsf_status_qual->doubleword[0] != 0) ||
--		   (fsf_status_qual->doubleword[1] != 0)) {
--		strncpy(rec->tag2, "qual", ZFCP_DBF_TAG_SIZE);
--		level = 3;
+-	if (cmd->use_sg) {
+-		cmd->SCp.buffer = (struct scatterlist *) cmd->request_buffer;
+-		cmd->SCp.buffers_residual = cmd->use_sg - 1;
++	if (scsi_bufflen(cmd)) {
++		cmd->SCp.buffer = scsi_sglist(cmd);
++		cmd->SCp.buffers_residual = scsi_sg_count(cmd) - 1;
+ 		cmd->SCp.ptr = sg_virt(cmd->SCp.buffer);
+ 		cmd->SCp.this_residual = cmd->SCp.buffer->length;
  	} else {
- 		strncpy(rec->tag2, "norm", ZFCP_DBF_TAG_SIZE);
- 		level = 6;
-diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h
-index e268f79..9e9f6c1 100644
---- a/drivers/s390/scsi/zfcp_def.h
-+++ b/drivers/s390/scsi/zfcp_def.h
-@@ -118,7 +118,7 @@ zfcp_address_to_sg(void *address, struct scatterlist *list, unsigned int size)
+ 		cmd->SCp.buffer = NULL;
+ 		cmd->SCp.buffers_residual = 0;
+-		cmd->SCp.ptr = (char *) cmd->request_buffer;
+-		cmd->SCp.this_residual = cmd->request_bufflen;
++		cmd->SCp.ptr = NULL;
++		cmd->SCp.this_residual = 0;
+ 	}
+ 	cmd->SCp.have_data_in = 0;
  
- #define ZFCP_SBAL_TIMEOUT               (5*HZ)
+diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c
+index 0841df0..73270ff 100644
+--- a/drivers/scsi/ipr.c
++++ b/drivers/scsi/ipr.c
+@@ -84,7 +84,7 @@
+ /*
+  *   Global Data
+  */
+-static struct list_head ipr_ioa_head = LIST_HEAD_INIT(ipr_ioa_head);
++static LIST_HEAD(ipr_ioa_head);
+ static unsigned int ipr_log_level = IPR_DEFAULT_LOG_LEVEL;
+ static unsigned int ipr_max_speed = 1;
+ static int ipr_testmode = 0;
+@@ -5142,6 +5142,7 @@ static void ipr_build_ata_ioadl(struct ipr_cmnd *ipr_cmd,
+ 	struct ipr_ioadl_desc *last_ioadl = NULL;
+ 	int len = qc->nbytes + qc->pad_len;
+ 	struct scatterlist *sg;
++	unsigned int si;
  
--#define ZFCP_TYPE2_RECOVERY_TIME        (8*HZ)
-+#define ZFCP_TYPE2_RECOVERY_TIME        8	/* seconds */
+ 	if (len == 0)
+ 		return;
+@@ -5159,7 +5160,7 @@ static void ipr_build_ata_ioadl(struct ipr_cmnd *ipr_cmd,
+ 			cpu_to_be32(sizeof(struct ipr_ioadl_desc) * ipr_cmd->dma_use_sg);
+ 	}
  
- /* queue polling (values in microseconds) */
- #define ZFCP_MAX_INPUT_THRESHOLD 	5000	/* FIXME: tune */
-@@ -139,7 +139,7 @@ zfcp_address_to_sg(void *address, struct scatterlist *list, unsigned int size)
- #define ZFCP_STATUS_READS_RECOM		        FSF_STATUS_READS_RECOM
+-	ata_for_each_sg(sg, qc) {
++	for_each_sg(qc->sg, sg, qc->n_elem, si) {
+ 		ioadl->flags_and_data_len = cpu_to_be32(ioadl_flags | sg_dma_len(sg));
+ 		ioadl->address = cpu_to_be32(sg_dma_address(sg));
  
- /* Do 1st retry in 1 second, then double the timeout for each following retry */
--#define ZFCP_EXCHANGE_CONFIG_DATA_FIRST_SLEEP	100
-+#define ZFCP_EXCHANGE_CONFIG_DATA_FIRST_SLEEP	1
- #define ZFCP_EXCHANGE_CONFIG_DATA_RETRIES	7
+@@ -5222,12 +5223,12 @@ static unsigned int ipr_qc_issue(struct ata_queued_cmd *qc)
+ 		regs->flags |= IPR_ATA_FLAG_XFER_TYPE_DMA;
+ 		break;
  
- /* timeout value for "default timer" for fsf requests */
-@@ -983,10 +983,6 @@ struct zfcp_unit {
-         struct scsi_device     *device;        /* scsi device struct pointer */
- 	struct zfcp_erp_action erp_action;     /* pending error recovery */
-         atomic_t               erp_counter;
--	wait_queue_head_t      scsi_scan_wq;   /* can be used to wait until
--						  all scsi_scan_target
--						  requests have been
--						  completed. */
- };
+-	case ATA_PROT_ATAPI:
+-	case ATA_PROT_ATAPI_NODATA:
++	case ATAPI_PROT_PIO:
++	case ATAPI_PROT_NODATA:
+ 		regs->flags |= IPR_ATA_FLAG_PACKET_CMD;
+ 		break;
  
- /* FSF request */
-@@ -1127,6 +1123,20 @@ zfcp_reqlist_find(struct zfcp_adapter *adapter, unsigned long req_id)
- 	return NULL;
- }
+-	case ATA_PROT_ATAPI_DMA:
++	case ATAPI_PROT_DMA:
+ 		regs->flags |= IPR_ATA_FLAG_PACKET_CMD;
+ 		regs->flags |= IPR_ATA_FLAG_XFER_TYPE_DMA;
+ 		break;
+diff --git a/drivers/scsi/ips.c b/drivers/scsi/ips.c
+index 5c5a9b2..7505cca 100644
+--- a/drivers/scsi/ips.c
++++ b/drivers/scsi/ips.c
+@@ -389,17 +389,17 @@ static struct  pci_device_id  ips_pci_table[] = {
+ MODULE_DEVICE_TABLE( pci, ips_pci_table );
  
-+static inline struct zfcp_fsf_req *
-+zfcp_reqlist_find_safe(struct zfcp_adapter *adapter, struct zfcp_fsf_req *req)
-+{
-+	struct zfcp_fsf_req *request;
-+	unsigned int idx;
+ static char ips_hot_plug_name[] = "ips";
+-   
 +
-+	for (idx = 0; idx < REQUEST_LIST_SIZE; idx++) {
-+		list_for_each_entry(request, &adapter->req_list[idx], list)
-+			if (request == req)
-+				return request;
-+	}
-+	return NULL;
-+}
+ static int __devinit  ips_insert_device(struct pci_dev *pci_dev, const struct pci_device_id *ent);
+ static void __devexit ips_remove_device(struct pci_dev *pci_dev);
+-   
++
+ static struct pci_driver ips_pci_driver = {
+ 	.name		= ips_hot_plug_name,
+ 	.id_table	= ips_pci_table,
+ 	.probe		= ips_insert_device,
+ 	.remove		= __devexit_p(ips_remove_device),
+ };
+-           
 +
- /*
-  *  functions needed for reference/usage counting
-  */
-diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c
-index 07fa824..2dc8110 100644
---- a/drivers/s390/scsi/zfcp_erp.c
-+++ b/drivers/s390/scsi/zfcp_erp.c
-@@ -131,7 +131,7 @@ static void zfcp_close_qdio(struct zfcp_adapter *adapter)
- 	debug_text_event(adapter->erp_dbf, 3, "qdio_down2a");
- 	while (qdio_shutdown(adapter->ccw_device,
- 			     QDIO_FLAG_CLEANUP_USING_CLEAR) == -EINPROGRESS)
--		msleep(1000);
-+		ssleep(1);
- 	debug_text_event(adapter->erp_dbf, 3, "qdio_down2b");
  
- 	/* cleanup used outbound sbals */
-@@ -456,7 +456,7 @@ zfcp_test_link(struct zfcp_port *port)
+ /*
+  * Necessary forward function protoypes
+@@ -587,7 +587,7 @@ static void
+ ips_setup_funclist(ips_ha_t * ha)
+ {
  
- 	zfcp_port_get(port);
- 	retval = zfcp_erp_adisc(port);
--	if (retval != 0) {
-+	if (retval != 0 && retval != -EBUSY) {
- 		zfcp_port_put(port);
- 		ZFCP_LOG_NORMAL("reopen needed for port 0x%016Lx "
- 				"on adapter %s\n ", port->wwpn,
-@@ -846,7 +846,8 @@ zfcp_erp_strategy_check_fsfreq(struct zfcp_erp_action *erp_action)
- 	if (erp_action->fsf_req) {
- 		/* take lock to ensure that request is not deleted meanwhile */
- 		spin_lock(&adapter->req_list_lock);
--		if (zfcp_reqlist_find(adapter, erp_action->fsf_req->req_id)) {
-+		if (zfcp_reqlist_find_safe(adapter, erp_action->fsf_req) &&
-+		    erp_action->fsf_req->erp_action == erp_action) {
- 			/* fsf_req still exists */
- 			debug_text_event(adapter->erp_dbf, 3, "a_ca_req");
- 			debug_event(adapter->erp_dbf, 3, &erp_action->fsf_req,
-@@ -1285,7 +1286,7 @@ zfcp_erp_strategy_do_action(struct zfcp_erp_action *erp_action)
- 	 * note: no lock in subsequent strategy routines
- 	 * (this allows these routine to call schedule, e.g.
- 	 * kmalloc with such flags or qdio_initialize & friends)
--	 * Note: in case of timeout, the seperate strategies will fail
-+	 * Note: in case of timeout, the separate strategies will fail
- 	 * anyhow. No need for a special action. Even worse, a nameserver
- 	 * failure would not wake up waiting ports without the call.
+-	/*                                
++	/*
+ 	 * Setup Functions
  	 */
-@@ -1609,7 +1610,6 @@ static void zfcp_erp_scsi_scan(struct work_struct *work)
- 	scsi_scan_target(&rport->dev, 0, rport->scsi_target_id,
- 			 unit->scsi_lun, 0);
- 	atomic_clear_mask(ZFCP_STATUS_UNIT_SCSI_WORK_PENDING, &unit->status);
--	wake_up(&unit->scsi_scan_wq);
- 	zfcp_unit_put(unit);
- 	kfree(p);
- }
-@@ -1900,7 +1900,7 @@ zfcp_erp_adapter_strategy(struct zfcp_erp_action *erp_action)
- 		ZFCP_LOG_INFO("Waiting to allow the adapter %s "
- 			      "to recover itself\n",
- 			      zfcp_get_busid_by_adapter(adapter));
--		msleep(jiffies_to_msecs(ZFCP_TYPE2_RECOVERY_TIME));
-+		ssleep(ZFCP_TYPE2_RECOVERY_TIME);
- 	}
+ 	if (IPS_IS_MORPHEUS(ha) || IPS_IS_MARCO(ha)) {
+@@ -702,12 +702,8 @@ ips_release(struct Scsi_Host *sh)
+ 	/* free extra memory */
+ 	ips_free(ha);
  
- 	return retval;
-@@ -2080,7 +2080,7 @@ zfcp_erp_adapter_strategy_open_qdio(struct zfcp_erp_action *erp_action)
- 	debug_text_event(adapter->erp_dbf, 3, "qdio_down1a");
- 	while (qdio_shutdown(adapter->ccw_device,
- 			     QDIO_FLAG_CLEANUP_USING_CLEAR) == -EINPROGRESS)
--		msleep(1000);
-+		ssleep(1);
- 	debug_text_event(adapter->erp_dbf, 3, "qdio_down1b");
+-	/* Free I/O Region */
+-	if (ha->io_addr)
+-		release_region(ha->io_addr, ha->io_len);
+-
+ 	/* free IRQ */
+-	free_irq(ha->irq, ha);
++	free_irq(ha->pcidev->irq, ha);
  
-  failed_qdio_establish:
-@@ -2165,7 +2165,7 @@ zfcp_erp_adapter_strategy_open_fsf_xconfig(struct zfcp_erp_action *erp_action)
- 		ZFCP_LOG_DEBUG("host connection still initialising... "
- 			       "waiting and retrying...\n");
- 		/* sleep a little bit before retry */
--		msleep(jiffies_to_msecs(sleep));
-+		ssleep(sleep);
- 		sleep *= 2;
- 	}
+ 	scsi_host_put(sh);
  
-diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h
-index 8534cf0..06b1079 100644
---- a/drivers/s390/scsi/zfcp_ext.h
-+++ b/drivers/s390/scsi/zfcp_ext.h
-@@ -27,8 +27,7 @@
- extern struct zfcp_data zfcp_data;
+@@ -1637,7 +1633,7 @@ ips_make_passthru(ips_ha_t *ha, struct scsi_cmnd *SC, ips_scb_t *scb, int intr)
+ 				return (IPS_FAILURE);
+ 			}
  
- /******************************** SYSFS  *************************************/
--extern int  zfcp_sysfs_driver_create_files(struct device_driver *);
--extern void zfcp_sysfs_driver_remove_files(struct device_driver *);
-+extern struct attribute_group *zfcp_driver_attr_groups[];
- extern int  zfcp_sysfs_adapter_create_files(struct device *);
- extern void zfcp_sysfs_adapter_remove_files(struct device *);
- extern int  zfcp_sysfs_port_create_files(struct device *, u32);
-diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c
-index ff866eb..e45f85f 100644
---- a/drivers/s390/scsi/zfcp_fsf.c
-+++ b/drivers/s390/scsi/zfcp_fsf.c
-@@ -502,7 +502,7 @@ zfcp_fsf_fsfstatus_qual_eval(struct zfcp_fsf_req *fsf_req)
- 		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
- 		break;
- 	case FSF_SQ_NO_RECOM:
--		ZFCP_LOG_NORMAL("bug: No recommendation could be given for a"
-+		ZFCP_LOG_NORMAL("bug: No recommendation could be given for a "
- 				"problem on the adapter %s "
- 				"Stopping all operations on this adapter. ",
- 				zfcp_get_busid_by_adapter(fsf_req->adapter));
-@@ -813,7 +813,7 @@ zfcp_fsf_status_read_port_closed(struct zfcp_fsf_req *fsf_req)
- 	read_unlock_irqrestore(&zfcp_data.config_lock, flags);
+-			if (ha->device_id == IPS_DEVICEID_COPPERHEAD &&
++			if (ha->pcidev->device == IPS_DEVICEID_COPPERHEAD &&
+ 			    pt->CoppCP.cmd.flashfw.op_code ==
+ 			    IPS_CMD_RW_BIOSFW) {
+ 				ret = ips_flash_copperhead(ha, pt, scb);
+@@ -2021,7 +2017,7 @@ ips_cleanup_passthru(ips_ha_t * ha, ips_scb_t * scb)
+ 	pt->ExtendedStatus = scb->extended_status;
+ 	pt->AdapterType = ha->ad_type;
  
- 	if (!port || (port->d_id != (status_buffer->d_id & ZFCP_DID_MASK))) {
--		ZFCP_LOG_NORMAL("bug: Reopen port indication received for"
-+		ZFCP_LOG_NORMAL("bug: Reopen port indication received for "
- 				"nonexisting port with d_id 0x%06x on "
- 				"adapter %s. Ignored.\n",
- 				status_buffer->d_id & ZFCP_DID_MASK,
-@@ -1116,6 +1116,10 @@ zfcp_fsf_abort_fcp_command(unsigned long old_req_id,
- 		goto out;
+-	if (ha->device_id == IPS_DEVICEID_COPPERHEAD &&
++	if (ha->pcidev->device == IPS_DEVICEID_COPPERHEAD &&
+ 	    (scb->cmd.flashfw.op_code == IPS_CMD_DOWNLOAD ||
+ 	     scb->cmd.flashfw.op_code == IPS_CMD_RW_BIOSFW))
+ 		ips_free_flash_copperhead(ha);
+@@ -2075,13 +2071,13 @@ ips_host_info(ips_ha_t * ha, char *ptr, off_t offset, int len)
+ 			  ha->mem_ptr);
  	}
  
-+	if (unlikely(!atomic_test_mask(ZFCP_STATUS_COMMON_UNBLOCKED,
-+			&unit->status)))
-+		goto unit_blocked;
-+
- 	sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
-         sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
-         sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
-@@ -1131,22 +1135,13 @@ zfcp_fsf_abort_fcp_command(unsigned long old_req_id,
+-	copy_info(&info, "\tIRQ number                        : %d\n", ha->irq);
++	copy_info(&info, "\tIRQ number                        : %d\n", ha->pcidev->irq);
  
- 	zfcp_fsf_start_timer(fsf_req, ZFCP_SCSI_ER_TIMEOUT);
- 	retval = zfcp_fsf_req_send(fsf_req);
--	if (retval) {
--		ZFCP_LOG_INFO("error: Failed to send abort command request "
--			      "on adapter %s, port 0x%016Lx, unit 0x%016Lx\n",
--			      zfcp_get_busid_by_adapter(adapter),
--			      unit->port->wwpn, unit->fcp_lun);
-+	if (!retval)
-+		goto out;
-+
-+ unit_blocked:
- 		zfcp_fsf_req_free(fsf_req);
- 		fsf_req = NULL;
--		goto out;
--	}
+     /* For the Next 3 lines Check for Binary 0 at the end and don't include it if it's there. */
+     /* That keeps everything happy for "text" operations on the proc file.                    */
  
--	ZFCP_LOG_DEBUG("Abort FCP Command request initiated "
--		       "(adapter%s, port d_id=0x%06x, "
--		       "unit x%016Lx, old_req_id=0x%lx)\n",
--		       zfcp_get_busid_by_adapter(adapter),
--		       unit->port->d_id,
--		       unit->fcp_lun, old_req_id);
-  out:
- 	write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags);
- 	return fsf_req;
-@@ -1164,8 +1159,8 @@ zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *new_fsf_req)
+ 	if (le32_to_cpu(ha->nvram->signature) == IPS_NVRAM_P5_SIG) {
+-        if (ha->nvram->bios_low[3] == 0) { 
++	if (ha->nvram->bios_low[3] == 0) {
+             copy_info(&info,
+ 			          "\tBIOS Version                      : %c%c%c%c%c%c%c\n",
+ 			          ha->nvram->bios_high[0], ha->nvram->bios_high[1],
+@@ -2232,31 +2228,31 @@ ips_identify_controller(ips_ha_t * ha)
  {
- 	int retval = -EINVAL;
- 	struct zfcp_unit *unit;
--	unsigned char status_qual =
--	    new_fsf_req->qtcb->header.fsf_status_qual.word[0];
-+	union fsf_status_qual *fsf_stat_qual =
-+		&new_fsf_req->qtcb->header.fsf_status_qual;
+ 	METHOD_TRACE("ips_identify_controller", 1);
  
- 	if (new_fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) {
- 		/* do not set ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED */
-@@ -1178,7 +1173,7 @@ zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *new_fsf_req)
- 	switch (new_fsf_req->qtcb->header.fsf_status) {
+-	switch (ha->device_id) {
++	switch (ha->pcidev->device) {
+ 	case IPS_DEVICEID_COPPERHEAD:
+-		if (ha->revision_id <= IPS_REVID_SERVERAID) {
++		if (ha->pcidev->revision <= IPS_REVID_SERVERAID) {
+ 			ha->ad_type = IPS_ADTYPE_SERVERAID;
+-		} else if (ha->revision_id == IPS_REVID_SERVERAID2) {
++		} else if (ha->pcidev->revision == IPS_REVID_SERVERAID2) {
+ 			ha->ad_type = IPS_ADTYPE_SERVERAID2;
+-		} else if (ha->revision_id == IPS_REVID_NAVAJO) {
++		} else if (ha->pcidev->revision == IPS_REVID_NAVAJO) {
+ 			ha->ad_type = IPS_ADTYPE_NAVAJO;
+-		} else if ((ha->revision_id == IPS_REVID_SERVERAID2)
++		} else if ((ha->pcidev->revision == IPS_REVID_SERVERAID2)
+ 			   && (ha->slot_num == 0)) {
+ 			ha->ad_type = IPS_ADTYPE_KIOWA;
+-		} else if ((ha->revision_id >= IPS_REVID_CLARINETP1) &&
+-			   (ha->revision_id <= IPS_REVID_CLARINETP3)) {
++		} else if ((ha->pcidev->revision >= IPS_REVID_CLARINETP1) &&
++			   (ha->pcidev->revision <= IPS_REVID_CLARINETP3)) {
+ 			if (ha->enq->ucMaxPhysicalDevices == 15)
+ 				ha->ad_type = IPS_ADTYPE_SERVERAID3L;
+ 			else
+ 				ha->ad_type = IPS_ADTYPE_SERVERAID3;
+-		} else if ((ha->revision_id >= IPS_REVID_TROMBONE32) &&
+-			   (ha->revision_id <= IPS_REVID_TROMBONE64)) {
++		} else if ((ha->pcidev->revision >= IPS_REVID_TROMBONE32) &&
++			   (ha->pcidev->revision <= IPS_REVID_TROMBONE64)) {
+ 			ha->ad_type = IPS_ADTYPE_SERVERAID4H;
+ 		}
+ 		break;
  
- 	case FSF_PORT_HANDLE_NOT_VALID:
--		if (status_qual >> 4 != status_qual % 0xf) {
-+		if (fsf_stat_qual->word[0] != fsf_stat_qual->word[1]) {
- 			debug_text_event(new_fsf_req->adapter->erp_dbf, 3,
- 					 "fsf_s_phand_nv0");
- 			/*
-@@ -1207,8 +1202,7 @@ zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *new_fsf_req)
+ 	case IPS_DEVICEID_MORPHEUS:
+-		switch (ha->subdevice_id) {
++		switch (ha->pcidev->subsystem_device) {
+ 		case IPS_SUBDEVICEID_4L:
+ 			ha->ad_type = IPS_ADTYPE_SERVERAID4L;
+ 			break;
+@@ -2285,7 +2281,7 @@ ips_identify_controller(ips_ha_t * ha)
  		break;
  
- 	case FSF_LUN_HANDLE_NOT_VALID:
--		if (status_qual >> 4 != status_qual % 0xf) {
--			/* 2 */
-+		if (fsf_stat_qual->word[0] != fsf_stat_qual->word[1]) {
- 			debug_text_event(new_fsf_req->adapter->erp_dbf, 3,
- 					 "fsf_s_lhand_nv0");
- 			/*
-@@ -1674,6 +1668,12 @@ zfcp_fsf_send_els(struct zfcp_send_els *els)
-                 goto failed_req;
- 	}
+ 	case IPS_DEVICEID_MARCO:
+-		switch (ha->subdevice_id) {
++		switch (ha->pcidev->subsystem_device) {
+ 		case IPS_SUBDEVICEID_6M:
+ 			ha->ad_type = IPS_ADTYPE_SERVERAID6M;
+ 			break;
+@@ -2332,20 +2328,20 @@ ips_get_bios_version(ips_ha_t * ha, int intr)
  
-+	if (unlikely(!atomic_test_mask(ZFCP_STATUS_COMMON_UNBLOCKED,
-+			&els->port->status))) {
-+		ret = -EBUSY;
-+		goto port_blocked;
-+	}
-+
- 	sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
-         if (zfcp_use_one_sbal(els->req, els->req_count,
-                               els->resp, els->resp_count)){
-@@ -1755,6 +1755,7 @@ zfcp_fsf_send_els(struct zfcp_send_els *els)
- 		       "0x%06x)\n", zfcp_get_busid_by_adapter(adapter), d_id);
- 	goto out;
+ 	strncpy(ha->bios_version, "       ?", 8);
  
-+ port_blocked:
-  failed_send:
- 	zfcp_fsf_req_free(fsf_req);
+-	if (ha->device_id == IPS_DEVICEID_COPPERHEAD) {
++	if (ha->pcidev->device == IPS_DEVICEID_COPPERHEAD) {
+ 		if (IPS_USE_MEMIO(ha)) {
+ 			/* Memory Mapped I/O */
  
-@@ -2280,7 +2281,7 @@ zfcp_fsf_exchange_port_data(struct zfcp_erp_action *erp_action)
- 				     &lock_flags, &fsf_req);
- 	if (retval) {
- 		ZFCP_LOG_INFO("error: Out of resources. Could not create an "
--			      "exchange port data request for"
-+			      "exchange port data request for "
- 			      "the adapter %s.\n",
- 			      zfcp_get_busid_by_adapter(adapter));
- 		write_unlock_irqrestore(&adapter->request_queue.queue_lock,
-@@ -2339,7 +2340,7 @@ zfcp_fsf_exchange_port_data_sync(struct zfcp_adapter *adapter,
- 				0, NULL, &lock_flags, &fsf_req);
- 	if (retval) {
- 		ZFCP_LOG_INFO("error: Out of resources. Could not create an "
--			      "exchange port data request for"
-+			      "exchange port data request for "
- 			      "the adapter %s.\n",
- 			      zfcp_get_busid_by_adapter(adapter));
- 		write_unlock_irqrestore(&adapter->request_queue.queue_lock,
-@@ -3592,6 +3593,12 @@ zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *adapter,
- 		goto failed_req_create;
- 	}
+ 			/* test 1st byte */
+ 			writel(0, ha->mem_ptr + IPS_REG_FLAP);
+-			if (ha->revision_id == IPS_REVID_TROMBONE64)
++			if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
+ 				udelay(25);	/* 25 us */
  
-+	if (unlikely(!atomic_test_mask(ZFCP_STATUS_COMMON_UNBLOCKED,
-+			&unit->status))) {
-+		retval = -EBUSY;
-+		goto unit_blocked;
-+	}
-+
- 	zfcp_unit_get(unit);
- 	fsf_req->unit = unit;
+ 			if (readb(ha->mem_ptr + IPS_REG_FLDP) != 0x55)
+ 				return;
  
-@@ -3732,6 +3739,7 @@ zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *adapter,
-  send_failed:
-  no_fit:
-  failed_scsi_cmnd:
-+ unit_blocked:
- 	zfcp_unit_put(unit);
- 	zfcp_fsf_req_free(fsf_req);
- 	fsf_req = NULL;
-@@ -3766,6 +3774,10 @@ zfcp_fsf_send_fcp_command_task_management(struct zfcp_adapter *adapter,
- 		goto out;
- 	}
+ 			writel(1, ha->mem_ptr + IPS_REG_FLAP);
+-			if (ha->revision_id == IPS_REVID_TROMBONE64)
++			if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
+ 				udelay(25);	/* 25 us */
  
-+	if (unlikely(!atomic_test_mask(ZFCP_STATUS_COMMON_UNBLOCKED,
-+			&unit->status)))
-+		goto unit_blocked;
-+
- 	/*
- 	 * Used to decide on proper handler in the return path,
- 	 * could be either zfcp_fsf_send_fcp_command_task_handler or
-@@ -3799,25 +3811,13 @@ zfcp_fsf_send_fcp_command_task_management(struct zfcp_adapter *adapter,
+ 			if (readb(ha->mem_ptr + IPS_REG_FLDP) != 0xAA)
+@@ -2353,20 +2349,20 @@ ips_get_bios_version(ips_ha_t * ha, int intr)
  
- 	zfcp_fsf_start_timer(fsf_req, ZFCP_SCSI_ER_TIMEOUT);
- 	retval = zfcp_fsf_req_send(fsf_req);
--	if (retval) {
--		ZFCP_LOG_INFO("error: Could not send an FCP-command (task "
--			      "management) on adapter %s, port 0x%016Lx for "
--			      "unit LUN 0x%016Lx\n",
--			      zfcp_get_busid_by_adapter(adapter),
--			      unit->port->wwpn,
--			      unit->fcp_lun);
--		zfcp_fsf_req_free(fsf_req);
--		fsf_req = NULL;
-+	if (!retval)
- 		goto out;
--	}
+ 			/* Get Major version */
+ 			writel(0x1FF, ha->mem_ptr + IPS_REG_FLAP);
+-			if (ha->revision_id == IPS_REVID_TROMBONE64)
++			if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
+ 				udelay(25);	/* 25 us */
  
--	ZFCP_LOG_TRACE("Send FCP Command (task management function) initiated "
--		       "(adapter %s, port 0x%016Lx, unit 0x%016Lx, "
--		       "tm_flags=0x%x)\n",
--		       zfcp_get_busid_by_adapter(adapter),
--		       unit->port->wwpn,
--		       unit->fcp_lun,
--		       tm_flags);
-+ unit_blocked:
-+	zfcp_fsf_req_free(fsf_req);
-+	fsf_req = NULL;
-+
-  out:
- 	write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags);
- 	return fsf_req;
-@@ -4725,7 +4725,7 @@ zfcp_fsf_req_create(struct zfcp_adapter *adapter, u32 fsf_cmd, int req_flags,
- 	/* allocate new FSF request */
- 	fsf_req = zfcp_fsf_req_alloc(pool, req_flags);
- 	if (unlikely(NULL == fsf_req)) {
--		ZFCP_LOG_DEBUG("error: Could not put an FSF request into"
-+		ZFCP_LOG_DEBUG("error: Could not put an FSF request into "
- 			       "the outbound (send) queue.\n");
- 		ret = -ENOMEM;
- 		goto failed_fsf_req;
-diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c
-index 51d92b1..22fdc17 100644
---- a/drivers/s390/scsi/zfcp_qdio.c
-+++ b/drivers/s390/scsi/zfcp_qdio.c
-@@ -529,7 +529,7 @@ zfcp_qdio_sbals_wipe(struct zfcp_fsf_req *fsf_req)
+ 			major = readb(ha->mem_ptr + IPS_REG_FLDP);
  
+ 			/* Get Minor version */
+ 			writel(0x1FE, ha->mem_ptr + IPS_REG_FLAP);
+-			if (ha->revision_id == IPS_REVID_TROMBONE64)
++			if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
+ 				udelay(25);	/* 25 us */
+ 			minor = readb(ha->mem_ptr + IPS_REG_FLDP);
  
- /**
-- * zfcp_qdio_sbale_fill - set address and lenght in current SBALE
-+ * zfcp_qdio_sbale_fill - set address and length in current SBALE
-  *	on request_queue
-  */
- static void
-diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c
-index abae202..b9daf5c 100644
---- a/drivers/s390/scsi/zfcp_scsi.c
-+++ b/drivers/s390/scsi/zfcp_scsi.c
-@@ -51,7 +51,6 @@ struct zfcp_data zfcp_data = {
- 		.queuecommand		= zfcp_scsi_queuecommand,
- 		.eh_abort_handler	= zfcp_scsi_eh_abort_handler,
- 		.eh_device_reset_handler = zfcp_scsi_eh_device_reset_handler,
--		.eh_bus_reset_handler	= zfcp_scsi_eh_host_reset_handler,
- 		.eh_host_reset_handler	= zfcp_scsi_eh_host_reset_handler,
- 		.can_queue		= 4096,
- 		.this_id		= -1,
-@@ -181,9 +180,6 @@ static void zfcp_scsi_slave_destroy(struct scsi_device *sdpnt)
+ 			/* Get SubMinor version */
+ 			writel(0x1FD, ha->mem_ptr + IPS_REG_FLAP);
+-			if (ha->revision_id == IPS_REVID_TROMBONE64)
++			if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
+ 				udelay(25);	/* 25 us */
+ 			subminor = readb(ha->mem_ptr + IPS_REG_FLDP);
  
- 	if (unit) {
- 		zfcp_erp_wait(unit->port->adapter);
--		wait_event(unit->scsi_scan_wq,
--			   atomic_test_mask(ZFCP_STATUS_UNIT_SCSI_WORK_PENDING,
--					    &unit->status) == 0);
- 		atomic_clear_mask(ZFCP_STATUS_UNIT_REGISTERED, &unit->status);
- 		sdpnt->hostdata = NULL;
- 		unit->device = NULL;
-@@ -262,8 +258,9 @@ zfcp_scsi_command_async(struct zfcp_adapter *adapter, struct zfcp_unit *unit,
- 		goto out;
- 	}
+@@ -2375,14 +2371,14 @@ ips_get_bios_version(ips_ha_t * ha, int intr)
  
--	if (unlikely(
--	     !atomic_test_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &unit->status))) {
-+	tmp = zfcp_fsf_send_fcp_command_task(adapter, unit, scpnt, use_timer,
-+					     ZFCP_REQ_AUTO_CLEANUP);
-+	if (unlikely(tmp == -EBUSY)) {
- 		ZFCP_LOG_DEBUG("adapter %s not ready or unit 0x%016Lx "
- 			       "on port 0x%016Lx in recovery\n",
- 			       zfcp_get_busid_by_unit(unit),
-@@ -272,9 +269,6 @@ zfcp_scsi_command_async(struct zfcp_adapter *adapter, struct zfcp_unit *unit,
- 		goto out;
- 	}
+ 			/* test 1st byte */
+ 			outl(0, ha->io_addr + IPS_REG_FLAP);
+-			if (ha->revision_id == IPS_REVID_TROMBONE64)
++			if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
+ 				udelay(25);	/* 25 us */
  
--	tmp = zfcp_fsf_send_fcp_command_task(adapter, unit, scpnt, use_timer,
--					     ZFCP_REQ_AUTO_CLEANUP);
--
- 	if (unlikely(tmp < 0)) {
- 		ZFCP_LOG_DEBUG("error: initiation of Send FCP Cmnd failed\n");
- 		retval = SCSI_MLQUEUE_HOST_BUSY;
-@@ -459,7 +453,9 @@ zfcp_scsi_eh_device_reset_handler(struct scsi_cmnd *scpnt)
- 		retval = SUCCESS;
- 		goto out;
- 	}
--	ZFCP_LOG_NORMAL("resetting unit 0x%016Lx\n", unit->fcp_lun);
-+	ZFCP_LOG_NORMAL("resetting unit 0x%016Lx on port 0x%016Lx, adapter %s\n",
-+			unit->fcp_lun, unit->port->wwpn,
-+			zfcp_get_busid_by_adapter(unit->port->adapter));
+ 			if (inb(ha->io_addr + IPS_REG_FLDP) != 0x55)
+ 				return;
  
- 	/*
- 	 * If we do not know whether the unit supports 'logical unit reset'
-@@ -542,7 +538,7 @@ zfcp_task_management_function(struct zfcp_unit *unit, u8 tm_flags,
- }
+ 			outl(cpu_to_le32(1), ha->io_addr + IPS_REG_FLAP);
+-			if (ha->revision_id == IPS_REVID_TROMBONE64)
++			if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
+ 				udelay(25);	/* 25 us */
  
- /**
-- * zfcp_scsi_eh_host_reset_handler - handler for host and bus reset
-+ * zfcp_scsi_eh_host_reset_handler - handler for host reset
-  */
- static int zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *scpnt)
- {
-@@ -552,8 +548,10 @@ static int zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *scpnt)
- 	unit = (struct zfcp_unit*) scpnt->device->hostdata;
- 	adapter = unit->port->adapter;
+ 			if (inb(ha->io_addr + IPS_REG_FLDP) != 0xAA)
+@@ -2390,21 +2386,21 @@ ips_get_bios_version(ips_ha_t * ha, int intr)
  
--	ZFCP_LOG_NORMAL("host/bus reset because of problems with "
--			"unit 0x%016Lx\n", unit->fcp_lun);
-+	ZFCP_LOG_NORMAL("host reset because of problems with "
-+		"unit 0x%016Lx on port 0x%016Lx, adapter %s\n",
-+		unit->fcp_lun, unit->port->wwpn,
-+		zfcp_get_busid_by_adapter(unit->port->adapter));
+ 			/* Get Major version */
+ 			outl(cpu_to_le32(0x1FF), ha->io_addr + IPS_REG_FLAP);
+-			if (ha->revision_id == IPS_REVID_TROMBONE64)
++			if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
+ 				udelay(25);	/* 25 us */
  
- 	zfcp_erp_adapter_reopen(adapter, 0);
- 	zfcp_erp_wait(adapter);
-diff --git a/drivers/s390/scsi/zfcp_sysfs_driver.c b/drivers/s390/scsi/zfcp_sysfs_driver.c
-index 005e62f..651edd5 100644
---- a/drivers/s390/scsi/zfcp_sysfs_driver.c
-+++ b/drivers/s390/scsi/zfcp_sysfs_driver.c
-@@ -98,28 +98,9 @@ static struct attribute_group zfcp_driver_attr_group = {
- 	.attrs = zfcp_driver_attrs,
- };
+ 			major = inb(ha->io_addr + IPS_REG_FLDP);
  
--/**
-- * zfcp_sysfs_create_driver_files - create sysfs driver files
-- * @dev: pointer to belonging device
-- *
-- * Create all sysfs attributes of the zfcp device driver
-- */
--int
--zfcp_sysfs_driver_create_files(struct device_driver *drv)
--{
--	return sysfs_create_group(&drv->kobj, &zfcp_driver_attr_group);
--}
--
--/**
-- * zfcp_sysfs_remove_driver_files - remove sysfs driver files
-- * @dev: pointer to belonging device
-- *
-- * Remove all sysfs attributes of the zfcp device driver
-- */
--void
--zfcp_sysfs_driver_remove_files(struct device_driver *drv)
--{
--	sysfs_remove_group(&drv->kobj, &zfcp_driver_attr_group);
--}
-+struct attribute_group *zfcp_driver_attr_groups[] = {
-+	&zfcp_driver_attr_group,
-+	NULL,
-+};
+ 			/* Get Minor version */
+ 			outl(cpu_to_le32(0x1FE), ha->io_addr + IPS_REG_FLAP);
+-			if (ha->revision_id == IPS_REVID_TROMBONE64)
++			if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
+ 				udelay(25);	/* 25 us */
  
- #undef ZFCP_LOG_AREA
-diff --git a/drivers/scsi/.gitignore b/drivers/scsi/.gitignore
-index b385af3..c89ae9a 100644
---- a/drivers/scsi/.gitignore
-+++ b/drivers/scsi/.gitignore
-@@ -1,3 +1 @@
- 53c700_d.h
--53c7xx_d.h
--53c7xx_u.h
-diff --git a/drivers/scsi/3w-9xxx.c b/drivers/scsi/3w-9xxx.c
-index afb262b..1c24483 100644
---- a/drivers/scsi/3w-9xxx.c
-+++ b/drivers/scsi/3w-9xxx.c
-@@ -2010,6 +2010,7 @@ static int __devinit twa_probe(struct pci_dev *pdev, const struct pci_device_id
- 	}
+ 			minor = inb(ha->io_addr + IPS_REG_FLDP);
  
- 	pci_set_master(pdev);
-+	pci_try_set_mwi(pdev);
+ 			/* Get SubMinor version */
+ 			outl(cpu_to_le32(0x1FD), ha->io_addr + IPS_REG_FLAP);
+-			if (ha->revision_id == IPS_REVID_TROMBONE64)
++			if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
+ 				udelay(25);	/* 25 us */
  
- 	if (pci_set_dma_mask(pdev, DMA_64BIT_MASK)
- 	    || pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK))
-diff --git a/drivers/scsi/53c700.c b/drivers/scsi/53c700.c
-index 71ff3fb..f4c4fe9 100644
---- a/drivers/scsi/53c700.c
-+++ b/drivers/scsi/53c700.c
-@@ -608,7 +608,8 @@ NCR_700_scsi_done(struct NCR_700_Host_Parameters *hostdata,
- 			scsi_print_sense("53c700", SCp);
+ 			subminor = inb(ha->io_addr + IPS_REG_FLDP);
+@@ -2740,8 +2736,6 @@ ips_next(ips_ha_t * ha, int intr)
+ 		SC->result = DID_OK;
+ 		SC->host_scribble = NULL;
  
- #endif
--			dma_unmap_single(hostdata->dev, slot->dma_handle, sizeof(SCp->sense_buffer), DMA_FROM_DEVICE);
-+			dma_unmap_single(hostdata->dev, slot->dma_handle,
-+					 SCSI_SENSE_BUFFERSIZE, DMA_FROM_DEVICE);
- 			/* restore the old result if the request sense was
- 			 * successful */
- 			if (result == 0)
-@@ -1010,7 +1011,7 @@ process_script_interrupt(__u32 dsps, __u32 dsp, struct scsi_cmnd *SCp,
- 				cmnd[1] = (SCp->device->lun & 0x7) << 5;
- 				cmnd[2] = 0;
- 				cmnd[3] = 0;
--				cmnd[4] = sizeof(SCp->sense_buffer);
-+				cmnd[4] = SCSI_SENSE_BUFFERSIZE;
- 				cmnd[5] = 0;
- 				/* Here's a quiet hack: the
- 				 * REQUEST_SENSE command is six bytes,
-@@ -1024,14 +1025,14 @@ process_script_interrupt(__u32 dsps, __u32 dsp, struct scsi_cmnd *SCp,
- 				SCp->cmd_len = 6; /* command length for
- 						   * REQUEST_SENSE */
- 				slot->pCmd = dma_map_single(hostdata->dev, cmnd, MAX_COMMAND_SIZE, DMA_TO_DEVICE);
--				slot->dma_handle = dma_map_single(hostdata->dev, SCp->sense_buffer, sizeof(SCp->sense_buffer), DMA_FROM_DEVICE);
--				slot->SG[0].ins = bS_to_host(SCRIPT_MOVE_DATA_IN | sizeof(SCp->sense_buffer));
-+				slot->dma_handle = dma_map_single(hostdata->dev, SCp->sense_buffer, SCSI_SENSE_BUFFERSIZE, DMA_FROM_DEVICE);
-+				slot->SG[0].ins = bS_to_host(SCRIPT_MOVE_DATA_IN | SCSI_SENSE_BUFFERSIZE);
- 				slot->SG[0].pAddr = bS_to_host(slot->dma_handle);
- 				slot->SG[1].ins = bS_to_host(SCRIPT_RETURN);
- 				slot->SG[1].pAddr = 0;
- 				slot->resume_offset = hostdata->pScript;
- 				dma_cache_sync(hostdata->dev, slot->SG, sizeof(slot->SG[0])*2, DMA_TO_DEVICE);
--				dma_cache_sync(hostdata->dev, SCp->sense_buffer, sizeof(SCp->sense_buffer), DMA_FROM_DEVICE);
-+				dma_cache_sync(hostdata->dev, SCp->sense_buffer, SCSI_SENSE_BUFFERSIZE, DMA_FROM_DEVICE);
+-		memset(SC->sense_buffer, 0, sizeof (SC->sense_buffer));
+-
+ 		scb->target_id = SC->device->id;
+ 		scb->lun = SC->device->lun;
+ 		scb->bus = SC->device->channel;
+@@ -2780,10 +2774,11 @@ ips_next(ips_ha_t * ha, int intr)
+ 		scb->dcdb.cmd_attribute =
+ 		    ips_command_direction[scb->scsi_cmd->cmnd[0]];
  
- 				/* queue the command for reissue */
- 				slot->state = NCR_700_SLOT_QUEUED;
-diff --git a/drivers/scsi/BusLogic.c b/drivers/scsi/BusLogic.c
-index 49e1ffa..ead47c1 100644
---- a/drivers/scsi/BusLogic.c
-+++ b/drivers/scsi/BusLogic.c
-@@ -2947,7 +2947,7 @@ static int BusLogic_QueueCommand(struct scsi_cmnd *Command, void (*CompletionRou
+-        /* Allow a WRITE BUFFER Command to Have no Data */
+-        /* This is Used by Tape Flash Utilites          */
+-        if ((scb->scsi_cmd->cmnd[0] == WRITE_BUFFER) && (scb->data_len == 0)) 
+-            scb->dcdb.cmd_attribute = 0;                  
++		/* Allow a WRITE BUFFER Command to Have no Data */
++		/* This is Used by Tape Flash Utilites          */
++		if ((scb->scsi_cmd->cmnd[0] == WRITE_BUFFER) &&
++				(scb->data_len == 0))
++			scb->dcdb.cmd_attribute = 0;
+ 
+ 		if (!(scb->dcdb.cmd_attribute & 0x3))
+ 			scb->dcdb.transfer_length = 0;
+@@ -3404,7 +3399,7 @@ ips_map_status(ips_ha_t * ha, ips_scb_t * scb, ips_stat_t * sp)
+ 
+ 				/* Restrict access to physical DASD */
+ 				if (scb->scsi_cmd->cmnd[0] == INQUIRY) {
+-				    ips_scmd_buf_read(scb->scsi_cmd, 
++				    ips_scmd_buf_read(scb->scsi_cmd,
+                                       &inquiryData, sizeof (inquiryData));
+  				    if ((inquiryData.DeviceType & 0x1f) == TYPE_DISK) {
+ 				        errcode = DID_TIME_OUT;
+@@ -3438,13 +3433,11 @@ ips_map_status(ips_ha_t * ha, ips_scb_t * scb, ips_stat_t * sp)
+ 					    (IPS_DCDB_TABLE_TAPE *) & scb->dcdb;
+ 					memcpy(scb->scsi_cmd->sense_buffer,
+ 					       tapeDCDB->sense_info,
+-					       sizeof (scb->scsi_cmd->
+-						       sense_buffer));
++					       SCSI_SENSE_BUFFERSIZE);
+ 				} else {
+ 					memcpy(scb->scsi_cmd->sense_buffer,
+ 					       scb->dcdb.sense_info,
+-					       sizeof (scb->scsi_cmd->
+-						       sense_buffer));
++					       SCSI_SENSE_BUFFERSIZE);
+ 				}
+ 				device_error = 2;	/* check condition */
+ 			}
+@@ -3824,7 +3817,6 @@ ips_send_cmd(ips_ha_t * ha, ips_scb_t * scb)
+ 			/* attempted, a Check Condition occurred, and Sense   */
+ 			/* Data indicating an Invalid CDB OpCode is returned. */
+ 			sp = (char *) scb->scsi_cmd->sense_buffer;
+-			memset(sp, 0, sizeof (scb->scsi_cmd->sense_buffer));
+ 
+ 			sp[0] = 0x70;	/* Error Code               */
+ 			sp[2] = ILLEGAL_REQUEST;	/* Sense Key 5 Illegal Req. */
+@@ -4090,10 +4082,10 @@ ips_chkstatus(ips_ha_t * ha, IPS_STATUS * pstatus)
+ 			scb->scsi_cmd->result = errcode << 16;
+ 		} else {	/* bus == 0 */
+ 			/* restrict access to physical drives */
+-			if (scb->scsi_cmd->cmnd[0] == INQUIRY) { 
+-			    ips_scmd_buf_read(scb->scsi_cmd, 
++			if (scb->scsi_cmd->cmnd[0] == INQUIRY) {
++			    ips_scmd_buf_read(scb->scsi_cmd,
+                                   &inquiryData, sizeof (inquiryData));
+-			    if ((inquiryData.DeviceType & 0x1f) == TYPE_DISK) 
++			    if ((inquiryData.DeviceType & 0x1f) == TYPE_DISK)
+ 			        scb->scsi_cmd->result = DID_TIME_OUT << 16;
+ 			}
+ 		}		/* else */
+@@ -4393,8 +4385,6 @@ ips_free(ips_ha_t * ha)
+ 			ha->mem_ptr = NULL;
  		}
+ 
+-		if (ha->mem_addr)
+-			release_mem_region(ha->mem_addr, ha->mem_len);
+ 		ha->mem_addr = 0;
+ 
  	}
- 	memcpy(CCB->CDB, CDB, CDB_Length);
--	CCB->SenseDataLength = sizeof(Command->sense_buffer);
-+	CCB->SenseDataLength = SCSI_SENSE_BUFFERSIZE;
- 	CCB->SenseDataPointer = pci_map_single(HostAdapter->PCI_Device, Command->sense_buffer, CCB->SenseDataLength, PCI_DMA_FROMDEVICE);
- 	CCB->Command = Command;
- 	Command->scsi_done = CompletionRoutine;
-diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
-index 184c7ae..3e161cd 100644
---- a/drivers/scsi/Kconfig
-+++ b/drivers/scsi/Kconfig
-@@ -341,7 +341,7 @@ config ISCSI_TCP
- 	 The userspace component needed to initialize the driver, documentation,
- 	 and sample configuration files can be found here:
+@@ -4661,8 +4651,8 @@ ips_isinit_morpheus(ips_ha_t * ha)
+ 	uint32_t bits;
  
--	 http://linux-iscsi.sf.net
-+	 http://open-iscsi.org
+ 	METHOD_TRACE("ips_is_init_morpheus", 1);
+-   
+-	if (ips_isintr_morpheus(ha)) 
++
++	if (ips_isintr_morpheus(ha))
+ 	    ips_flush_and_reset(ha);
  
- config SGIWD93_SCSI
- 	tristate "SGI WD93C93 SCSI Driver"
-@@ -573,10 +573,10 @@ config SCSI_ARCMSR_AER
- source "drivers/scsi/megaraid/Kconfig.megaraid"
+ 	post = readl(ha->mem_ptr + IPS_REG_I960_MSG0);
+@@ -4686,7 +4676,7 @@ ips_isinit_morpheus(ips_ha_t * ha)
+ /*   state ( was trying to INIT and an interrupt was already pending ) ...  */
+ /*                                                                          */
+ /****************************************************************************/
+-static void 
++static void
+ ips_flush_and_reset(ips_ha_t *ha)
+ {
+ 	ips_scb_t *scb;
+@@ -4718,9 +4708,9 @@ ips_flush_and_reset(ips_ha_t *ha)
+ 	    if (ret == IPS_SUCCESS) {
+ 	        time = 60 * IPS_ONE_SEC;	              /* Max Wait time is 60 seconds */
+ 	        done = 0;
+-	            
++
+ 	        while ((time > 0) && (!done)) {
+-	           done = ips_poll_for_flush_complete(ha); 	   
++		   done = ips_poll_for_flush_complete(ha);
+ 	           /* This may look evil, but it's only done during extremely rare start-up conditions ! */
+ 	           udelay(1000);
+ 	           time--;
+@@ -4749,17 +4739,17 @@ static int
+ ips_poll_for_flush_complete(ips_ha_t * ha)
+ {
+ 	IPS_STATUS cstatus;
+-    
++
+ 	while (TRUE) {
+ 	    cstatus.value = (*ha->func.statupd) (ha);
  
- config SCSI_HPTIOP
--	tristate "HighPoint RocketRAID 3xxx Controller support"
-+	tristate "HighPoint RocketRAID 3xxx/4xxx Controller support"
- 	depends on SCSI && PCI
- 	help
--	  This option enables support for HighPoint RocketRAID 3xxx
-+	  This option enables support for HighPoint RocketRAID 3xxx/4xxx
- 	  controllers.
+ 	    if (cstatus.value == 0xffffffff)      /* If No Interrupt to process */
+ 			break;
+-            
++
+ 	    /* Success is when we see the Flush Command ID */
+-	    if (cstatus.fields.command_id == IPS_MAX_CMDS ) 
++	    if (cstatus.fields.command_id == IPS_MAX_CMDS)
+ 	        return 1;
+-	 }	
++	 }
  
- 	  To compile this driver as a module, choose M here; the module
-@@ -1288,17 +1288,6 @@ config SCSI_PAS16
- 	  To compile this driver as a module, choose M here: the
- 	  module will be called pas16.
+ 	return 0;
+ }
+@@ -4903,7 +4893,7 @@ ips_init_copperhead(ips_ha_t * ha)
+ 	/* Enable busmastering */
+ 	outb(IPS_BIT_EBM, ha->io_addr + IPS_REG_SCPR);
  
--config SCSI_PSI240I
--	tristate "PSI240i support"
--	depends on ISA && SCSI
--	help
--	  This is support for the PSI240i EIDE interface card which acts as a
--	  SCSI host adapter.  Please read the SCSI-HOWTO, available from
--	  <http://www.tldp.org/docs.html#howto>.
--
--	  To compile this driver as a module, choose M here: the
--	  module will be called psi240i.
--
- config SCSI_QLOGIC_FAS
- 	tristate "Qlogic FAS SCSI support"
- 	depends on ISA && SCSI
-@@ -1359,21 +1348,6 @@ config SCSI_LPFC
-           This lpfc driver supports the Emulex LightPulse
-           Family of Fibre Channel PCI host adapters.
+-	if (ha->revision_id == IPS_REVID_TROMBONE64)
++	if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
+ 		/* fix for anaconda64 */
+ 		outl(0, ha->io_addr + IPS_REG_NDAE);
  
--config SCSI_SEAGATE
--	tristate "Seagate ST-02 and Future Domain TMC-8xx SCSI support"
--	depends on X86 && ISA && SCSI
--	select CHECK_SIGNATURE
--	---help---
--	  These are 8-bit SCSI controllers; the ST-01 is also supported by
--	  this driver.  It is explained in section 3.9 of the SCSI-HOWTO,
--	  available from <http://www.tldp.org/docs.html#howto>.  If it
--	  doesn't work out of the box, you may have to change some macros at
--	  compiletime, which are described in <file:drivers/scsi/seagate.c>.
--
--	  To compile this driver as a module, choose M here: the
--	  module will be called seagate.
--
--# definitely looks not 64bit safe:
- config SCSI_SIM710
- 	tristate "Simple 53c710 SCSI support (Compaq, NCR machines)"
- 	depends on (EISA || MCA) && SCSI
-diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
-index 2e6129f..93e1428 100644
---- a/drivers/scsi/Makefile
-+++ b/drivers/scsi/Makefile
-@@ -16,9 +16,8 @@
+@@ -4997,7 +4987,7 @@ ips_init_copperhead_memio(ips_ha_t * ha)
+ 	/* Enable busmastering */
+ 	writeb(IPS_BIT_EBM, ha->mem_ptr + IPS_REG_SCPR);
+ 
+-	if (ha->revision_id == IPS_REVID_TROMBONE64)
++	if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
+ 		/* fix for anaconda64 */
+ 		writel(0, ha->mem_ptr + IPS_REG_NDAE);
+ 
+@@ -5142,7 +5132,7 @@ ips_reset_copperhead(ips_ha_t * ha)
+ 	METHOD_TRACE("ips_reset_copperhead", 1);
  
- CFLAGS_aha152x.o =   -DAHA152X_STAT -DAUTOCONF
- CFLAGS_gdth.o    = # -DDEBUG_GDTH=2 -D__SERIAL__ -D__COM2__ -DGDTH_STATISTICS
--CFLAGS_seagate.o =   -DARBITRATE -DPARITY -DSEAGATE_USE_ASM
+ 	DEBUG_VAR(1, "(%s%d) ips_reset_copperhead: io addr: %x, irq: %d",
+-		  ips_name, ha->host_num, ha->io_addr, ha->irq);
++		  ips_name, ha->host_num, ha->io_addr, ha->pcidev->irq);
  
--subdir-$(CONFIG_PCMCIA)		+= pcmcia
-+obj-$(CONFIG_PCMCIA)		+= pcmcia/
+ 	reset_counter = 0;
  
- obj-$(CONFIG_SCSI)		+= scsi_mod.o
- obj-$(CONFIG_SCSI_TGT)		+= scsi_tgt.o
-@@ -59,7 +58,6 @@ obj-$(CONFIG_MVME16x_SCSI)	+= 53c700.o	mvme16x_scsi.o
- obj-$(CONFIG_BVME6000_SCSI)	+= 53c700.o	bvme6000_scsi.o
- obj-$(CONFIG_SCSI_SIM710)	+= 53c700.o	sim710.o
- obj-$(CONFIG_SCSI_ADVANSYS)	+= advansys.o
--obj-$(CONFIG_SCSI_PSI240I)	+= psi240i.o
- obj-$(CONFIG_SCSI_BUSLOGIC)	+= BusLogic.o
- obj-$(CONFIG_SCSI_DPT_I2O)	+= dpt_i2o.o
- obj-$(CONFIG_SCSI_U14_34F)	+= u14-34f.o
-@@ -90,7 +88,6 @@ obj-$(CONFIG_SCSI_QLA_FC)	+= qla2xxx/
- obj-$(CONFIG_SCSI_QLA_ISCSI)	+= qla4xxx/
- obj-$(CONFIG_SCSI_LPFC)		+= lpfc/
- obj-$(CONFIG_SCSI_PAS16)	+= pas16.o
--obj-$(CONFIG_SCSI_SEAGATE)	+= seagate.o
- obj-$(CONFIG_SCSI_T128)		+= t128.o
- obj-$(CONFIG_SCSI_DMX3191D)	+= dmx3191d.o
- obj-$(CONFIG_SCSI_DTC3280)	+= dtc.o
-diff --git a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c
-index 2597209..eeddbd1 100644
---- a/drivers/scsi/NCR5380.c
-+++ b/drivers/scsi/NCR5380.c
-@@ -295,16 +295,16 @@ static __inline__ void initialize_SCp(Scsi_Cmnd * cmd)
- 	 * various queues are valid.
- 	 */
+@@ -5187,7 +5177,7 @@ ips_reset_copperhead_memio(ips_ha_t * ha)
+ 	METHOD_TRACE("ips_reset_copperhead_memio", 1);
  
--	if (cmd->use_sg) {
--		cmd->SCp.buffer = (struct scatterlist *) cmd->request_buffer;
--		cmd->SCp.buffers_residual = cmd->use_sg - 1;
-+	if (scsi_bufflen(cmd)) {
-+		cmd->SCp.buffer = scsi_sglist(cmd);
-+		cmd->SCp.buffers_residual = scsi_sg_count(cmd) - 1;
- 		cmd->SCp.ptr = sg_virt(cmd->SCp.buffer);
- 		cmd->SCp.this_residual = cmd->SCp.buffer->length;
- 	} else {
- 		cmd->SCp.buffer = NULL;
- 		cmd->SCp.buffers_residual = 0;
--		cmd->SCp.ptr = (char *) cmd->request_buffer;
--		cmd->SCp.this_residual = cmd->request_bufflen;
-+		cmd->SCp.ptr = NULL;
-+		cmd->SCp.this_residual = 0;
- 	}
- }
+ 	DEBUG_VAR(1, "(%s%d) ips_reset_copperhead_memio: mem addr: %x, irq: %d",
+-		  ips_name, ha->host_num, ha->mem_addr, ha->irq);
++		  ips_name, ha->host_num, ha->mem_addr, ha->pcidev->irq);
  
-@@ -932,7 +932,7 @@ static int __devinit NCR5380_init(struct Scsi_Host *instance, int flags)
-  *	@instance: adapter to remove
-  */
+ 	reset_counter = 0;
  
--static void __devexit NCR5380_exit(struct Scsi_Host *instance)
-+static void NCR5380_exit(struct Scsi_Host *instance)
- {
- 	struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata;
+@@ -5233,7 +5223,7 @@ ips_reset_morpheus(ips_ha_t * ha)
+ 	METHOD_TRACE("ips_reset_morpheus", 1);
  
-@@ -975,14 +975,14 @@ static int NCR5380_queue_command(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
- 		case WRITE_6:
- 		case WRITE_10:
- 			hostdata->time_write[cmd->device->id] -= (jiffies - hostdata->timebase);
--			hostdata->bytes_write[cmd->device->id] += cmd->request_bufflen;
-+			hostdata->bytes_write[cmd->device->id] += scsi_bufflen(cmd);
- 			hostdata->pendingw++;
- 			break;
- 		case READ:
- 		case READ_6:
- 		case READ_10:
- 			hostdata->time_read[cmd->device->id] -= (jiffies - hostdata->timebase);
--			hostdata->bytes_read[cmd->device->id] += cmd->request_bufflen;
-+			hostdata->bytes_read[cmd->device->id] += scsi_bufflen(cmd);
- 			hostdata->pendingr++;
- 			break;
- 	}
-@@ -1157,16 +1157,17 @@ static void NCR5380_main(struct work_struct *work)
-  *	Locks: takes the needed instance locks
-  */
+ 	DEBUG_VAR(1, "(%s%d) ips_reset_morpheus: mem addr: %x, irq: %d",
+-		  ips_name, ha->host_num, ha->mem_addr, ha->irq);
++		  ips_name, ha->host_num, ha->mem_addr, ha->pcidev->irq);
  
--static irqreturn_t NCR5380_intr(int irq, void *dev_id) 
-+static irqreturn_t NCR5380_intr(int dummy, void *dev_id)
- {
- 	NCR5380_local_declare();
--	struct Scsi_Host *instance = (struct Scsi_Host *)dev_id;
-+	struct Scsi_Host *instance = dev_id;
- 	struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata;
- 	int done;
- 	unsigned char basr;
- 	unsigned long flags;
+ 	reset_counter = 0;
  
--	dprintk(NDEBUG_INTR, ("scsi : NCR5380 irq %d triggered\n", irq));
-+	dprintk(NDEBUG_INTR, ("scsi : NCR5380 irq %d triggered\n",
-+		instance->irq));
+@@ -5920,7 +5910,7 @@ ips_read_config(ips_ha_t * ha, int intr)
  
- 	do {
- 		done = 1;
-diff --git a/drivers/scsi/a2091.c b/drivers/scsi/a2091.c
-index b7c5385..23f27c9 100644
---- a/drivers/scsi/a2091.c
-+++ b/drivers/scsi/a2091.c
-@@ -73,18 +73,9 @@ static int dma_setup(struct scsi_cmnd *cmd, int dir_in)
+ 		return (0);
  	}
+-	
++
+ 	memcpy(ha->conf, ha->ioctl_data, sizeof(*ha->conf));
+ 	return (1);
+ }
+@@ -5959,7 +5949,7 @@ ips_readwrite_page5(ips_ha_t * ha, int write, int intr)
+ 	scb->cmd.nvram.buffer_addr = ha->ioctl_busaddr;
+ 	if (write)
+ 		memcpy(ha->ioctl_data, ha->nvram, sizeof(*ha->nvram));
+-	
++
+ 	/* issue the command */
+ 	if (((ret =
+ 	      ips_send_wait(ha, scb, ips_cmd_timeout, intr)) == IPS_FAILURE)
+@@ -6196,32 +6186,32 @@ ips_erase_bios(ips_ha_t * ha)
  
- 	if (!dir_in) {
--	    /* copy to bounce buffer for a write */
--	    if (cmd->use_sg)
--#if 0
--		panic ("scsi%ddma: incomplete s/g support",
--		       instance->host_no);
--#else
-+		/* copy to bounce buffer for a write */
- 		memcpy (HDATA(instance)->dma_bounce_buffer,
- 			cmd->SCp.ptr, cmd->SCp.this_residual);
--#endif
--	    else
--		memcpy (HDATA(instance)->dma_bounce_buffer,
--			cmd->request_buffer, cmd->request_bufflen);
- 	}
-     }
+ 	/* Clear the status register */
+ 	outl(0, ha->io_addr + IPS_REG_FLAP);
+-	if (ha->revision_id == IPS_REVID_TROMBONE64)
++	if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
+ 		udelay(25);	/* 25 us */
  
-@@ -144,30 +135,13 @@ static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt,
+ 	outb(0x50, ha->io_addr + IPS_REG_FLDP);
+-	if (ha->revision_id == IPS_REVID_TROMBONE64)
++	if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
+ 		udelay(25);	/* 25 us */
  
-     /* copy from a bounce buffer, if necessary */
-     if (status && HDATA(instance)->dma_bounce_buffer) {
--	if (SCpnt && SCpnt->use_sg) {
--#if 0
--	    panic ("scsi%d: incomplete s/g support",
--		   instance->host_no);
--#else
--	    if( HDATA(instance)->dma_dir )
-+	if( HDATA(instance)->dma_dir )
- 		memcpy (SCpnt->SCp.ptr, 
- 			HDATA(instance)->dma_bounce_buffer,
- 			SCpnt->SCp.this_residual);
--	    kfree (HDATA(instance)->dma_bounce_buffer);
--	    HDATA(instance)->dma_bounce_buffer = NULL;
--	    HDATA(instance)->dma_bounce_len = 0;
--	    
--#endif
--	} else {
--	    if (HDATA(instance)->dma_dir && SCpnt)
--		memcpy (SCpnt->request_buffer,
--			HDATA(instance)->dma_bounce_buffer,
--			SCpnt->request_bufflen);
--
--	    kfree (HDATA(instance)->dma_bounce_buffer);
--	    HDATA(instance)->dma_bounce_buffer = NULL;
--	    HDATA(instance)->dma_bounce_len = 0;
--	}
-+	kfree (HDATA(instance)->dma_bounce_buffer);
-+	HDATA(instance)->dma_bounce_buffer = NULL;
-+	HDATA(instance)->dma_bounce_len = 0;
-     }
- }
+ 	/* Erase Setup */
+ 	outb(0x20, ha->io_addr + IPS_REG_FLDP);
+-	if (ha->revision_id == IPS_REVID_TROMBONE64)
++	if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
+ 		udelay(25);	/* 25 us */
  
-diff --git a/drivers/scsi/a3000.c b/drivers/scsi/a3000.c
-index 796f1c4..d7255c8 100644
---- a/drivers/scsi/a3000.c
-+++ b/drivers/scsi/a3000.c
-@@ -70,12 +70,8 @@ static int dma_setup(struct scsi_cmnd *cmd, int dir_in)
+ 	/* Erase Confirm */
+ 	outb(0xD0, ha->io_addr + IPS_REG_FLDP);
+-	if (ha->revision_id == IPS_REVID_TROMBONE64)
++	if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
+ 		udelay(25);	/* 25 us */
  
- 	if (!dir_in) {
- 	    /* copy to bounce buffer for a write */
--	    if (cmd->use_sg) {
--		memcpy (HDATA(a3000_host)->dma_bounce_buffer,
--			cmd->SCp.ptr, cmd->SCp.this_residual);
--	    } else
--		memcpy (HDATA(a3000_host)->dma_bounce_buffer,
--			cmd->request_buffer, cmd->request_bufflen);
-+	    memcpy (HDATA(a3000_host)->dma_bounce_buffer,
-+		cmd->SCp.ptr, cmd->SCp.this_residual);
- 	}
+ 	/* Erase Status */
+ 	outb(0x70, ha->io_addr + IPS_REG_FLDP);
+-	if (ha->revision_id == IPS_REVID_TROMBONE64)
++	if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
+ 		udelay(25);	/* 25 us */
  
- 	addr = virt_to_bus(HDATA(a3000_host)->dma_bounce_buffer);
-@@ -146,7 +142,7 @@ static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt,
+ 	timeout = 80000;	/* 80 seconds */
  
-     /* copy from a bounce buffer, if necessary */
-     if (status && HDATA(instance)->dma_bounce_buffer) {
--	if (SCpnt && SCpnt->use_sg) {
-+	if (SCpnt) {
- 	    if (HDATA(instance)->dma_dir && SCpnt)
- 		memcpy (SCpnt->SCp.ptr,
- 			HDATA(instance)->dma_bounce_buffer,
-@@ -155,11 +151,6 @@ static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt,
- 	    HDATA(instance)->dma_bounce_buffer = NULL;
- 	    HDATA(instance)->dma_bounce_len = 0;
- 	} else {
--	    if (HDATA(instance)->dma_dir && SCpnt)
--		memcpy (SCpnt->request_buffer,
--			HDATA(instance)->dma_bounce_buffer,
--			SCpnt->request_bufflen);
--
- 	    kfree (HDATA(instance)->dma_bounce_buffer);
- 	    HDATA(instance)->dma_bounce_buffer = NULL;
- 	    HDATA(instance)->dma_bounce_len = 0;
-diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c
-index a77ab8d..d7235f4 100644
---- a/drivers/scsi/aacraid/aachba.c
-+++ b/drivers/scsi/aacraid/aachba.c
-@@ -31,9 +31,9 @@
- #include <linux/slab.h>
- #include <linux/completion.h>
- #include <linux/blkdev.h>
--#include <linux/dma-mapping.h>
- #include <asm/semaphore.h>
- #include <asm/uaccess.h>
-+#include <linux/highmem.h> /* For flush_kernel_dcache_page */
+ 	while (timeout > 0) {
+-		if (ha->revision_id == IPS_REVID_TROMBONE64) {
++		if (ha->pcidev->revision == IPS_REVID_TROMBONE64) {
+ 			outl(0, ha->io_addr + IPS_REG_FLAP);
+ 			udelay(25);	/* 25 us */
+ 		}
+@@ -6241,13 +6231,13 @@ ips_erase_bios(ips_ha_t * ha)
  
- #include <scsi/scsi.h>
- #include <scsi/scsi_cmnd.h>
-@@ -56,54 +56,54 @@
- /*
-  *	Sense codes
-  */
-- 
--#define SENCODE_NO_SENSE                        0x00
--#define SENCODE_END_OF_DATA                     0x00
--#define SENCODE_BECOMING_READY                  0x04
--#define SENCODE_INIT_CMD_REQUIRED               0x04
--#define SENCODE_PARAM_LIST_LENGTH_ERROR         0x1A
--#define SENCODE_INVALID_COMMAND                 0x20
--#define SENCODE_LBA_OUT_OF_RANGE                0x21
--#define SENCODE_INVALID_CDB_FIELD               0x24
--#define SENCODE_LUN_NOT_SUPPORTED               0x25
--#define SENCODE_INVALID_PARAM_FIELD             0x26
--#define SENCODE_PARAM_NOT_SUPPORTED             0x26
--#define SENCODE_PARAM_VALUE_INVALID             0x26
--#define SENCODE_RESET_OCCURRED                  0x29
--#define SENCODE_LUN_NOT_SELF_CONFIGURED_YET     0x3E
--#define SENCODE_INQUIRY_DATA_CHANGED            0x3F
--#define SENCODE_SAVING_PARAMS_NOT_SUPPORTED     0x39
--#define SENCODE_DIAGNOSTIC_FAILURE              0x40
--#define SENCODE_INTERNAL_TARGET_FAILURE         0x44
--#define SENCODE_INVALID_MESSAGE_ERROR           0x49
--#define SENCODE_LUN_FAILED_SELF_CONFIG          0x4c
--#define SENCODE_OVERLAPPED_COMMAND              0x4E
-+
-+#define SENCODE_NO_SENSE			0x00
-+#define SENCODE_END_OF_DATA			0x00
-+#define SENCODE_BECOMING_READY			0x04
-+#define SENCODE_INIT_CMD_REQUIRED		0x04
-+#define SENCODE_PARAM_LIST_LENGTH_ERROR		0x1A
-+#define SENCODE_INVALID_COMMAND			0x20
-+#define SENCODE_LBA_OUT_OF_RANGE		0x21
-+#define SENCODE_INVALID_CDB_FIELD		0x24
-+#define SENCODE_LUN_NOT_SUPPORTED		0x25
-+#define SENCODE_INVALID_PARAM_FIELD		0x26
-+#define SENCODE_PARAM_NOT_SUPPORTED		0x26
-+#define SENCODE_PARAM_VALUE_INVALID		0x26
-+#define SENCODE_RESET_OCCURRED			0x29
-+#define SENCODE_LUN_NOT_SELF_CONFIGURED_YET	0x3E
-+#define SENCODE_INQUIRY_DATA_CHANGED		0x3F
-+#define SENCODE_SAVING_PARAMS_NOT_SUPPORTED	0x39
-+#define SENCODE_DIAGNOSTIC_FAILURE		0x40
-+#define SENCODE_INTERNAL_TARGET_FAILURE		0x44
-+#define SENCODE_INVALID_MESSAGE_ERROR		0x49
-+#define SENCODE_LUN_FAILED_SELF_CONFIG		0x4c
-+#define SENCODE_OVERLAPPED_COMMAND		0x4E
+ 		/* try to suspend the erase */
+ 		outb(0xB0, ha->io_addr + IPS_REG_FLDP);
+-		if (ha->revision_id == IPS_REVID_TROMBONE64)
++		if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
+ 			udelay(25);	/* 25 us */
  
- /*
-  *	Additional sense codes
-  */
-- 
--#define ASENCODE_NO_SENSE                       0x00
--#define ASENCODE_END_OF_DATA                    0x05
--#define ASENCODE_BECOMING_READY                 0x01
--#define ASENCODE_INIT_CMD_REQUIRED              0x02
--#define ASENCODE_PARAM_LIST_LENGTH_ERROR        0x00
--#define ASENCODE_INVALID_COMMAND                0x00
--#define ASENCODE_LBA_OUT_OF_RANGE               0x00
--#define ASENCODE_INVALID_CDB_FIELD              0x00
--#define ASENCODE_LUN_NOT_SUPPORTED              0x00
--#define ASENCODE_INVALID_PARAM_FIELD            0x00
--#define ASENCODE_PARAM_NOT_SUPPORTED            0x01
--#define ASENCODE_PARAM_VALUE_INVALID            0x02
--#define ASENCODE_RESET_OCCURRED                 0x00
--#define ASENCODE_LUN_NOT_SELF_CONFIGURED_YET    0x00
--#define ASENCODE_INQUIRY_DATA_CHANGED           0x03
--#define ASENCODE_SAVING_PARAMS_NOT_SUPPORTED    0x00
--#define ASENCODE_DIAGNOSTIC_FAILURE             0x80
--#define ASENCODE_INTERNAL_TARGET_FAILURE        0x00
--#define ASENCODE_INVALID_MESSAGE_ERROR          0x00
--#define ASENCODE_LUN_FAILED_SELF_CONFIG         0x00
--#define ASENCODE_OVERLAPPED_COMMAND             0x00
-+
-+#define ASENCODE_NO_SENSE			0x00
-+#define ASENCODE_END_OF_DATA			0x05
-+#define ASENCODE_BECOMING_READY			0x01
-+#define ASENCODE_INIT_CMD_REQUIRED		0x02
-+#define ASENCODE_PARAM_LIST_LENGTH_ERROR	0x00
-+#define ASENCODE_INVALID_COMMAND		0x00
-+#define ASENCODE_LBA_OUT_OF_RANGE		0x00
-+#define ASENCODE_INVALID_CDB_FIELD		0x00
-+#define ASENCODE_LUN_NOT_SUPPORTED		0x00
-+#define ASENCODE_INVALID_PARAM_FIELD		0x00
-+#define ASENCODE_PARAM_NOT_SUPPORTED		0x01
-+#define ASENCODE_PARAM_VALUE_INVALID		0x02
-+#define ASENCODE_RESET_OCCURRED			0x00
-+#define ASENCODE_LUN_NOT_SELF_CONFIGURED_YET	0x00
-+#define ASENCODE_INQUIRY_DATA_CHANGED		0x03
-+#define ASENCODE_SAVING_PARAMS_NOT_SUPPORTED	0x00
-+#define ASENCODE_DIAGNOSTIC_FAILURE		0x80
-+#define ASENCODE_INTERNAL_TARGET_FAILURE	0x00
-+#define ASENCODE_INVALID_MESSAGE_ERROR		0x00
-+#define ASENCODE_LUN_FAILED_SELF_CONFIG		0x00
-+#define ASENCODE_OVERLAPPED_COMMAND		0x00
+ 		/* wait for 10 seconds */
+ 		timeout = 10000;
+ 		while (timeout > 0) {
+-			if (ha->revision_id == IPS_REVID_TROMBONE64) {
++			if (ha->pcidev->revision == IPS_REVID_TROMBONE64) {
+ 				outl(0, ha->io_addr + IPS_REG_FLAP);
+ 				udelay(25);	/* 25 us */
+ 			}
+@@ -6277,12 +6267,12 @@ ips_erase_bios(ips_ha_t * ha)
+ 	/* Otherwise, we were successful */
+ 	/* clear status */
+ 	outb(0x50, ha->io_addr + IPS_REG_FLDP);
+-	if (ha->revision_id == IPS_REVID_TROMBONE64)
++	if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
+ 		udelay(25);	/* 25 us */
  
- #define BYTE0(x) (unsigned char)(x)
- #define BYTE1(x) (unsigned char)((x) >> 8)
-@@ -115,8 +115,8 @@
-  *----------------------------------------------------------------------------*/
- /* SCSI inquiry data */
- struct inquiry_data {
--	u8 inqd_pdt;	/* Peripheral qualifier | Peripheral Device Type  */
--	u8 inqd_dtq;	/* RMB | Device Type Qualifier  */
-+	u8 inqd_pdt;	/* Peripheral qualifier | Peripheral Device Type */
-+	u8 inqd_dtq;	/* RMB | Device Type Qualifier */
- 	u8 inqd_ver;	/* ISO version | ECMA version | ANSI-approved version */
- 	u8 inqd_rdf;	/* AENC | TrmIOP | Response data format */
- 	u8 inqd_len;	/* Additional length (n-4) */
-@@ -130,7 +130,7 @@ struct inquiry_data {
- /*
-  *              M O D U L E   G L O B A L S
-  */
-- 
-+
- static unsigned long aac_build_sg(struct scsi_cmnd* scsicmd, struct sgmap* sgmap);
- static unsigned long aac_build_sg64(struct scsi_cmnd* scsicmd, struct sgmap64* psg);
- static unsigned long aac_build_sgraw(struct scsi_cmnd* scsicmd, struct sgmapraw* psg);
-@@ -141,9 +141,10 @@ static char *aac_get_status_string(u32 status);
+ 	/* enable reads */
+ 	outb(0xFF, ha->io_addr + IPS_REG_FLDP);
+-	if (ha->revision_id == IPS_REVID_TROMBONE64)
++	if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
+ 		udelay(25);	/* 25 us */
  
- /*
-  *	Non dasd selection is handled entirely in aachba now
-- */	
-- 
-+ */
-+
- static int nondasd = -1;
-+static int aac_cache = 0;
- static int dacmode = -1;
+ 	return (0);
+@@ -6308,32 +6298,32 @@ ips_erase_bios_memio(ips_ha_t * ha)
  
- int aac_commit = -1;
-@@ -152,6 +153,8 @@ int aif_timeout = 120;
+ 	/* Clear the status register */
+ 	writel(0, ha->mem_ptr + IPS_REG_FLAP);
+-	if (ha->revision_id == IPS_REVID_TROMBONE64)
++	if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
+ 		udelay(25);	/* 25 us */
  
- module_param(nondasd, int, S_IRUGO|S_IWUSR);
- MODULE_PARM_DESC(nondasd, "Control scanning of hba for nondasd devices. 0=off, 1=on");
-+module_param_named(cache, aac_cache, int, S_IRUGO|S_IWUSR);
-+MODULE_PARM_DESC(cache, "Disable Queue Flush commands:\n\tbit 0 - Disable FUA in WRITE SCSI commands\n\tbit 1 - Disable SYNCHRONIZE_CACHE SCSI command\n\tbit 2 - Disable only if Battery not protecting Cache");
- module_param(dacmode, int, S_IRUGO|S_IWUSR);
- MODULE_PARM_DESC(dacmode, "Control whether dma addressing is using 64 bit DAC. 0=off, 1=on");
- module_param_named(commit, aac_commit, int, S_IRUGO|S_IWUSR);
-@@ -179,7 +182,7 @@ MODULE_PARM_DESC(check_interval, "Interval in seconds between adapter health che
+ 	writeb(0x50, ha->mem_ptr + IPS_REG_FLDP);
+-	if (ha->revision_id == IPS_REVID_TROMBONE64)
++	if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
+ 		udelay(25);	/* 25 us */
  
- int aac_check_reset = 1;
- module_param_named(check_reset, aac_check_reset, int, S_IRUGO|S_IWUSR);
--MODULE_PARM_DESC(aac_check_reset, "If adapter fails health check, reset the adapter.");
-+MODULE_PARM_DESC(aac_check_reset, "If adapter fails health check, reset the adapter. a value of -1 forces the reset to adapters programmed to ignore it.");
+ 	/* Erase Setup */
+ 	writeb(0x20, ha->mem_ptr + IPS_REG_FLDP);
+-	if (ha->revision_id == IPS_REVID_TROMBONE64)
++	if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
+ 		udelay(25);	/* 25 us */
  
- int expose_physicals = -1;
- module_param(expose_physicals, int, S_IRUGO|S_IWUSR);
-@@ -193,12 +196,12 @@ static inline int aac_valid_context(struct scsi_cmnd *scsicmd,
- 		struct fib *fibptr) {
- 	struct scsi_device *device;
+ 	/* Erase Confirm */
+ 	writeb(0xD0, ha->mem_ptr + IPS_REG_FLDP);
+-	if (ha->revision_id == IPS_REVID_TROMBONE64)
++	if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
+ 		udelay(25);	/* 25 us */
  
--	if (unlikely(!scsicmd || !scsicmd->scsi_done )) {
-+	if (unlikely(!scsicmd || !scsicmd->scsi_done)) {
- 		dprintk((KERN_WARNING "aac_valid_context: scsi command corrupt\n"));
--                aac_fib_complete(fibptr);
--                aac_fib_free(fibptr);
--                return 0;
--        }
-+		aac_fib_complete(fibptr);
-+		aac_fib_free(fibptr);
-+		return 0;
-+	}
- 	scsicmd->SCp.phase = AAC_OWNER_MIDLEVEL;
- 	device = scsicmd->device;
- 	if (unlikely(!device || !scsi_device_online(device))) {
-@@ -240,7 +243,7 @@ int aac_get_config_status(struct aac_dev *dev, int commit_flag)
- 			    FsaNormal,
- 			    1, 1,
- 			    NULL, NULL);
--	if (status < 0 ) {
-+	if (status < 0) {
- 		printk(KERN_WARNING "aac_get_config_status: SendFIB failed.\n");
- 	} else {
- 		struct aac_get_config_status_resp *reply
-@@ -264,10 +267,10 @@ int aac_get_config_status(struct aac_dev *dev, int commit_flag)
- 			struct aac_commit_config * dinfo;
- 			aac_fib_init(fibptr);
- 			dinfo = (struct aac_commit_config *) fib_data(fibptr);
--	
-+
- 			dinfo->command = cpu_to_le32(VM_ContainerConfig);
- 			dinfo->type = cpu_to_le32(CT_COMMIT_CONFIG);
--	
-+
- 			status = aac_fib_send(ContainerCommand,
- 				    fibptr,
- 				    sizeof (struct aac_commit_config),
-@@ -293,7 +296,7 @@ int aac_get_config_status(struct aac_dev *dev, int commit_flag)
- int aac_get_containers(struct aac_dev *dev)
- {
- 	struct fsa_dev_info *fsa_dev_ptr;
--	u32 index; 
-+	u32 index;
- 	int status = 0;
- 	struct fib * fibptr;
- 	struct aac_get_container_count *dinfo;
-@@ -363,6 +366,7 @@ static void aac_internal_transfer(struct scsi_cmnd *scsicmd, void *data, unsigne
- 	if (buf && transfer_len > 0)
- 		memcpy(buf + offset, data, transfer_len);
+ 	/* Erase Status */
+ 	writeb(0x70, ha->mem_ptr + IPS_REG_FLDP);
+-	if (ha->revision_id == IPS_REVID_TROMBONE64)
++	if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
+ 		udelay(25);	/* 25 us */
  
-+	flush_kernel_dcache_page(kmap_atomic_to_page(buf - sg->offset));
- 	kunmap_atomic(buf - sg->offset, KM_IRQ0);
+ 	timeout = 80000;	/* 80 seconds */
  
- }
-@@ -395,7 +399,7 @@ static void get_container_name_callback(void *context, struct fib * fibptr)
- 			do {
- 				*dp++ = (*sp) ? *sp++ : ' ';
- 			} while (--count > 0);
--			aac_internal_transfer(scsicmd, d, 
-+			aac_internal_transfer(scsicmd, d,
- 			  offsetof(struct inquiry_data, inqd_pid), sizeof(d));
+ 	while (timeout > 0) {
+-		if (ha->revision_id == IPS_REVID_TROMBONE64) {
++		if (ha->pcidev->revision == IPS_REVID_TROMBONE64) {
+ 			writel(0, ha->mem_ptr + IPS_REG_FLAP);
+ 			udelay(25);	/* 25 us */
  		}
- 	}
-@@ -431,13 +435,13 @@ static int aac_get_container_name(struct scsi_cmnd * scsicmd)
- 	dinfo->count = cpu_to_le32(sizeof(((struct aac_get_name_resp *)NULL)->data));
+@@ -6353,13 +6343,13 @@ ips_erase_bios_memio(ips_ha_t * ha)
  
- 	status = aac_fib_send(ContainerCommand,
--		  cmd_fibcontext, 
-+		  cmd_fibcontext,
- 		  sizeof (struct aac_get_name),
--		  FsaNormal, 
--		  0, 1, 
--		  (fib_callback) get_container_name_callback, 
-+		  FsaNormal,
-+		  0, 1,
-+		  (fib_callback)get_container_name_callback,
- 		  (void *) scsicmd);
--	
-+
- 	/*
- 	 *	Check that the command queued to the controller
- 	 */
-@@ -445,7 +449,7 @@ static int aac_get_container_name(struct scsi_cmnd * scsicmd)
- 		scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
- 		return 0;
- 	}
--		
-+
- 	printk(KERN_WARNING "aac_get_container_name: aac_fib_send failed with status: %d.\n", status);
- 	aac_fib_complete(cmd_fibcontext);
- 	aac_fib_free(cmd_fibcontext);
-@@ -652,42 +656,47 @@ struct scsi_inq {
-  *	@a:	string to copy from
-  *	@b:	string to copy to
-  *
-- * 	Copy a String from one location to another
-+ *	Copy a String from one location to another
-  *	without copying \0
-  */
+ 		/* try to suspend the erase */
+ 		writeb(0xB0, ha->mem_ptr + IPS_REG_FLDP);
+-		if (ha->revision_id == IPS_REVID_TROMBONE64)
++		if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
+ 			udelay(25);	/* 25 us */
  
- static void inqstrcpy(char *a, char *b)
- {
+ 		/* wait for 10 seconds */
+ 		timeout = 10000;
+ 		while (timeout > 0) {
+-			if (ha->revision_id == IPS_REVID_TROMBONE64) {
++			if (ha->pcidev->revision == IPS_REVID_TROMBONE64) {
+ 				writel(0, ha->mem_ptr + IPS_REG_FLAP);
+ 				udelay(25);	/* 25 us */
+ 			}
+@@ -6389,12 +6379,12 @@ ips_erase_bios_memio(ips_ha_t * ha)
+ 	/* Otherwise, we were successful */
+ 	/* clear status */
+ 	writeb(0x50, ha->mem_ptr + IPS_REG_FLDP);
+-	if (ha->revision_id == IPS_REVID_TROMBONE64)
++	if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
+ 		udelay(25);	/* 25 us */
  
--	while(*a != (char)0) 
-+	while (*a != (char)0)
- 		*b++ = *a++;
- }
+ 	/* enable reads */
+ 	writeb(0xFF, ha->mem_ptr + IPS_REG_FLDP);
+-	if (ha->revision_id == IPS_REVID_TROMBONE64)
++	if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
+ 		udelay(25);	/* 25 us */
  
- static char *container_types[] = {
--        "None",
--        "Volume",
--        "Mirror",
--        "Stripe",
--        "RAID5",
--        "SSRW",
--        "SSRO",
--        "Morph",
--        "Legacy",
--        "RAID4",
--        "RAID10",             
--        "RAID00",             
--        "V-MIRRORS",          
--        "PSEUDO R4",          
-+	"None",
-+	"Volume",
-+	"Mirror",
-+	"Stripe",
-+	"RAID5",
-+	"SSRW",
-+	"SSRO",
-+	"Morph",
-+	"Legacy",
-+	"RAID4",
-+	"RAID10",
-+	"RAID00",
-+	"V-MIRRORS",
-+	"PSEUDO R4",
- 	"RAID50",
- 	"RAID5D",
- 	"RAID5D0",
- 	"RAID1E",
- 	"RAID6",
- 	"RAID60",
--        "Unknown"
-+	"Unknown"
- };
+ 	return (0);
+@@ -6423,21 +6413,21 @@ ips_program_bios(ips_ha_t * ha, char *buffer, uint32_t buffersize,
+ 	for (i = 0; i < buffersize; i++) {
+ 		/* write a byte */
+ 		outl(cpu_to_le32(i + offset), ha->io_addr + IPS_REG_FLAP);
+-		if (ha->revision_id == IPS_REVID_TROMBONE64)
++		if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
+ 			udelay(25);	/* 25 us */
  
--
-+char * get_container_type(unsigned tindex)
-+{
-+	if (tindex >= ARRAY_SIZE(container_types))
-+		tindex = ARRAY_SIZE(container_types) - 1;
-+	return container_types[tindex];
-+}
+ 		outb(0x40, ha->io_addr + IPS_REG_FLDP);
+-		if (ha->revision_id == IPS_REVID_TROMBONE64)
++		if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
+ 			udelay(25);	/* 25 us */
  
- /* Function: setinqstr
-  *
-@@ -707,16 +716,21 @@ static void setinqstr(struct aac_dev *dev, void *data, int tindex)
+ 		outb(buffer[i], ha->io_addr + IPS_REG_FLDP);
+-		if (ha->revision_id == IPS_REVID_TROMBONE64)
++		if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
+ 			udelay(25);	/* 25 us */
  
- 	if (dev->supplement_adapter_info.AdapterTypeText[0]) {
- 		char * cp = dev->supplement_adapter_info.AdapterTypeText;
--		int c = sizeof(str->vid);
--		while (*cp && *cp != ' ' && --c)
--			++cp;
--		c = *cp;
--		*cp = '\0';
--		inqstrcpy (dev->supplement_adapter_info.AdapterTypeText,
--		  str->vid); 
--		*cp = c;
--		while (*cp && *cp != ' ')
--			++cp;
-+		int c;
-+		if ((cp[0] == 'A') && (cp[1] == 'O') && (cp[2] == 'C'))
-+			inqstrcpy("SMC", str->vid);
-+		else {
-+			c = sizeof(str->vid);
-+			while (*cp && *cp != ' ' && --c)
-+				++cp;
-+			c = *cp;
-+			*cp = '\0';
-+			inqstrcpy (dev->supplement_adapter_info.AdapterTypeText,
-+				   str->vid);
-+			*cp = c;
-+			while (*cp && *cp != ' ')
-+				++cp;
-+		}
- 		while (*cp == ' ')
- 			++cp;
- 		/* last six chars reserved for vol type */
-@@ -898,9 +912,8 @@ static int aac_bounds_32(struct aac_dev * dev, struct scsi_cmnd * cmd, u64 lba)
- 			    ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0,
- 			    0, 0);
- 		memcpy(cmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
--		  (sizeof(dev->fsa_dev[cid].sense_data) > sizeof(cmd->sense_buffer))
--		    ? sizeof(cmd->sense_buffer)
--		    : sizeof(dev->fsa_dev[cid].sense_data));
-+		       min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data),
-+			     SCSI_SENSE_BUFFERSIZE));
- 		cmd->scsi_done(cmd);
- 		return 1;
- 	}
-@@ -981,7 +994,7 @@ static int aac_read_block(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u32
- 	aac_fib_init(fib);
- 	readcmd = (struct aac_read *) fib_data(fib);
- 	readcmd->command = cpu_to_le32(VM_CtBlockRead);
--	readcmd->cid = cpu_to_le16(scmd_id(cmd));
-+	readcmd->cid = cpu_to_le32(scmd_id(cmd));
- 	readcmd->block = cpu_to_le32((u32)(lba&0xffffffff));
- 	readcmd->count = cpu_to_le32(count * 512);
+ 		/* wait up to one second */
+ 		timeout = 1000;
+ 		while (timeout > 0) {
+-			if (ha->revision_id == IPS_REVID_TROMBONE64) {
++			if (ha->pcidev->revision == IPS_REVID_TROMBONE64) {
+ 				outl(0, ha->io_addr + IPS_REG_FLAP);
+ 				udelay(25);	/* 25 us */
+ 			}
+@@ -6454,11 +6444,11 @@ ips_program_bios(ips_ha_t * ha, char *buffer, uint32_t buffersize,
+ 		if (timeout == 0) {
+ 			/* timeout error */
+ 			outl(0, ha->io_addr + IPS_REG_FLAP);
+-			if (ha->revision_id == IPS_REVID_TROMBONE64)
++			if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
+ 				udelay(25);	/* 25 us */
  
-@@ -1013,7 +1026,8 @@ static int aac_write_raw_io(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u
- 	writecmd->block[1] = cpu_to_le32((u32)((lba&0xffffffff00000000LL)>>32));
- 	writecmd->count = cpu_to_le32(count<<9);
- 	writecmd->cid = cpu_to_le16(scmd_id(cmd));
--	writecmd->flags = fua ?
-+	writecmd->flags = (fua && ((aac_cache & 5) != 1) &&
-+	  (((aac_cache & 5) != 5) || !fib->dev->cache_protected)) ?
- 		cpu_to_le16(IO_TYPE_WRITE|IO_SUREWRITE) :
- 		cpu_to_le16(IO_TYPE_WRITE);
- 	writecmd->bpTotal = 0;
-@@ -1072,7 +1086,7 @@ static int aac_write_block(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u3
- 	aac_fib_init(fib);
- 	writecmd = (struct aac_write *) fib_data(fib);
- 	writecmd->command = cpu_to_le32(VM_CtBlockWrite);
--	writecmd->cid = cpu_to_le16(scmd_id(cmd));
-+	writecmd->cid = cpu_to_le32(scmd_id(cmd));
- 	writecmd->block = cpu_to_le32((u32)(lba&0xffffffff));
- 	writecmd->count = cpu_to_le32(count * 512);
- 	writecmd->sg.count = cpu_to_le32(1);
-@@ -1190,6 +1204,15 @@ static int aac_scsi_32(struct fib * fib, struct scsi_cmnd * cmd)
- 				  (fib_callback) aac_srb_callback, (void *) cmd);
- }
+ 			outb(0xFF, ha->io_addr + IPS_REG_FLDP);
+-			if (ha->revision_id == IPS_REVID_TROMBONE64)
++			if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
+ 				udelay(25);	/* 25 us */
  
-+static int aac_scsi_32_64(struct fib * fib, struct scsi_cmnd * cmd)
-+{
-+	if ((sizeof(dma_addr_t) > 4) &&
-+	 (num_physpages > (0xFFFFFFFFULL >> PAGE_SHIFT)) &&
-+	 (fib->dev->adapter_info.options & AAC_OPT_SGMAP_HOST64))
-+		return FAILED;
-+	return aac_scsi_32(fib, cmd);
-+}
-+
- int aac_get_adapter_info(struct aac_dev* dev)
- {
- 	struct fib* fibptr;
-@@ -1207,11 +1230,11 @@ int aac_get_adapter_info(struct aac_dev* dev)
- 	memset(info,0,sizeof(*info));
+ 			return (1);
+@@ -6468,11 +6458,11 @@ ips_program_bios(ips_ha_t * ha, char *buffer, uint32_t buffersize,
+ 		if (status & 0x18) {
+ 			/* programming error */
+ 			outl(0, ha->io_addr + IPS_REG_FLAP);
+-			if (ha->revision_id == IPS_REVID_TROMBONE64)
++			if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
+ 				udelay(25);	/* 25 us */
  
- 	rcode = aac_fib_send(RequestAdapterInfo,
--			 fibptr, 
-+			 fibptr,
- 			 sizeof(*info),
--			 FsaNormal, 
-+			 FsaNormal,
- 			 -1, 1, /* First `interrupt' command uses special wait */
--			 NULL, 
-+			 NULL,
- 			 NULL);
+ 			outb(0xFF, ha->io_addr + IPS_REG_FLDP);
+-			if (ha->revision_id == IPS_REVID_TROMBONE64)
++			if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
+ 				udelay(25);	/* 25 us */
  
- 	if (rcode < 0) {
-@@ -1222,29 +1245,29 @@ int aac_get_adapter_info(struct aac_dev* dev)
- 	memcpy(&dev->adapter_info, info, sizeof(*info));
+ 			return (1);
+@@ -6481,11 +6471,11 @@ ips_program_bios(ips_ha_t * ha, char *buffer, uint32_t buffersize,
  
- 	if (dev->adapter_info.options & AAC_OPT_SUPPLEMENT_ADAPTER_INFO) {
--		struct aac_supplement_adapter_info * info;
-+		struct aac_supplement_adapter_info * sinfo;
+ 	/* Enable reading */
+ 	outl(0, ha->io_addr + IPS_REG_FLAP);
+-	if (ha->revision_id == IPS_REVID_TROMBONE64)
++	if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
+ 		udelay(25);	/* 25 us */
  
- 		aac_fib_init(fibptr);
+ 	outb(0xFF, ha->io_addr + IPS_REG_FLDP);
+-	if (ha->revision_id == IPS_REVID_TROMBONE64)
++	if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
+ 		udelay(25);	/* 25 us */
  
--		info = (struct aac_supplement_adapter_info *) fib_data(fibptr);
-+		sinfo = (struct aac_supplement_adapter_info *) fib_data(fibptr);
+ 	return (0);
+@@ -6514,21 +6504,21 @@ ips_program_bios_memio(ips_ha_t * ha, char *buffer, uint32_t buffersize,
+ 	for (i = 0; i < buffersize; i++) {
+ 		/* write a byte */
+ 		writel(i + offset, ha->mem_ptr + IPS_REG_FLAP);
+-		if (ha->revision_id == IPS_REVID_TROMBONE64)
++		if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
+ 			udelay(25);	/* 25 us */
  
--		memset(info,0,sizeof(*info));
-+		memset(sinfo,0,sizeof(*sinfo));
+ 		writeb(0x40, ha->mem_ptr + IPS_REG_FLDP);
+-		if (ha->revision_id == IPS_REVID_TROMBONE64)
++		if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
+ 			udelay(25);	/* 25 us */
  
- 		rcode = aac_fib_send(RequestSupplementAdapterInfo,
- 				 fibptr,
--				 sizeof(*info),
-+				 sizeof(*sinfo),
- 				 FsaNormal,
- 				 1, 1,
- 				 NULL,
- 				 NULL);
+ 		writeb(buffer[i], ha->mem_ptr + IPS_REG_FLDP);
+-		if (ha->revision_id == IPS_REVID_TROMBONE64)
++		if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
+ 			udelay(25);	/* 25 us */
  
- 		if (rcode >= 0)
--			memcpy(&dev->supplement_adapter_info, info, sizeof(*info));
-+			memcpy(&dev->supplement_adapter_info, sinfo, sizeof(*sinfo));
- 	}
+ 		/* wait up to one second */
+ 		timeout = 1000;
+ 		while (timeout > 0) {
+-			if (ha->revision_id == IPS_REVID_TROMBONE64) {
++			if (ha->pcidev->revision == IPS_REVID_TROMBONE64) {
+ 				writel(0, ha->mem_ptr + IPS_REG_FLAP);
+ 				udelay(25);	/* 25 us */
+ 			}
+@@ -6545,11 +6535,11 @@ ips_program_bios_memio(ips_ha_t * ha, char *buffer, uint32_t buffersize,
+ 		if (timeout == 0) {
+ 			/* timeout error */
+ 			writel(0, ha->mem_ptr + IPS_REG_FLAP);
+-			if (ha->revision_id == IPS_REVID_TROMBONE64)
++			if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
+ 				udelay(25);	/* 25 us */
  
+ 			writeb(0xFF, ha->mem_ptr + IPS_REG_FLDP);
+-			if (ha->revision_id == IPS_REVID_TROMBONE64)
++			if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
+ 				udelay(25);	/* 25 us */
  
--	/* 
--	 * GetBusInfo 
-+	/*
-+	 * GetBusInfo
- 	 */
+ 			return (1);
+@@ -6559,11 +6549,11 @@ ips_program_bios_memio(ips_ha_t * ha, char *buffer, uint32_t buffersize,
+ 		if (status & 0x18) {
+ 			/* programming error */
+ 			writel(0, ha->mem_ptr + IPS_REG_FLAP);
+-			if (ha->revision_id == IPS_REVID_TROMBONE64)
++			if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
+ 				udelay(25);	/* 25 us */
  
- 	aac_fib_init(fibptr);
-@@ -1267,6 +1290,8 @@ int aac_get_adapter_info(struct aac_dev* dev)
- 			 1, 1,
- 			 NULL, NULL);
+ 			writeb(0xFF, ha->mem_ptr + IPS_REG_FLDP);
+-			if (ha->revision_id == IPS_REVID_TROMBONE64)
++			if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
+ 				udelay(25);	/* 25 us */
  
-+	/* reasoned default */
-+	dev->maximum_num_physicals = 16;
- 	if (rcode >= 0 && le32_to_cpu(bus_info->Status) == ST_OK) {
- 		dev->maximum_num_physicals = le32_to_cpu(bus_info->TargetsPerBus);
- 		dev->maximum_num_channels = le32_to_cpu(bus_info->BusCount);
-@@ -1276,7 +1301,7 @@ int aac_get_adapter_info(struct aac_dev* dev)
- 		char buffer[16];
- 		tmp = le32_to_cpu(dev->adapter_info.kernelrev);
- 		printk(KERN_INFO "%s%d: kernel %d.%d-%d[%d] %.*s\n",
--			dev->name, 
-+			dev->name,
- 			dev->id,
- 			tmp>>24,
- 			(tmp>>16)&0xff,
-@@ -1305,19 +1330,21 @@ int aac_get_adapter_info(struct aac_dev* dev)
- 			  (int)sizeof(dev->supplement_adapter_info.VpdInfo.Tsid),
- 			  dev->supplement_adapter_info.VpdInfo.Tsid);
- 		}
--		if (!aac_check_reset ||
-+		if (!aac_check_reset || ((aac_check_reset != 1) &&
- 		  (dev->supplement_adapter_info.SupportedOptions2 &
--		  le32_to_cpu(AAC_OPTION_IGNORE_RESET))) {
-+		  AAC_OPTION_IGNORE_RESET))) {
- 			printk(KERN_INFO "%s%d: Reset Adapter Ignored\n",
- 			  dev->name, dev->id);
- 		}
- 	}
+ 			return (1);
+@@ -6572,11 +6562,11 @@ ips_program_bios_memio(ips_ha_t * ha, char *buffer, uint32_t buffersize,
  
-+	dev->cache_protected = 0;
-+	dev->jbod = ((dev->supplement_adapter_info.FeatureBits &
-+		AAC_FEATURE_JBOD) != 0);
- 	dev->nondasd_support = 0;
- 	dev->raid_scsi_mode = 0;
--	if(dev->adapter_info.options & AAC_OPT_NONDASD){
-+	if(dev->adapter_info.options & AAC_OPT_NONDASD)
- 		dev->nondasd_support = 1;
--	}
+ 	/* Enable reading */
+ 	writel(0, ha->mem_ptr + IPS_REG_FLAP);
+-	if (ha->revision_id == IPS_REVID_TROMBONE64)
++	if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
+ 		udelay(25);	/* 25 us */
  
- 	/*
- 	 * If the firmware supports ROMB RAID/SCSI mode and we are currently
-@@ -1338,11 +1365,10 @@ int aac_get_adapter_info(struct aac_dev* dev)
- 	if (dev->raid_scsi_mode != 0)
- 		printk(KERN_INFO "%s%d: ROMB RAID/SCSI mode enabled\n",
- 				dev->name, dev->id);
--		
--	if(nondasd != -1) {  
-+
-+	if (nondasd != -1)
- 		dev->nondasd_support = (nondasd!=0);
--	}
--	if(dev->nondasd_support != 0){
-+	if(dev->nondasd_support != 0) {
- 		printk(KERN_INFO "%s%d: Non-DASD support enabled.\n",dev->name, dev->id);
- 	}
+ 	writeb(0xFF, ha->mem_ptr + IPS_REG_FLDP);
+-	if (ha->revision_id == IPS_REVID_TROMBONE64)
++	if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
+ 		udelay(25);	/* 25 us */
  
-@@ -1371,12 +1397,14 @@ int aac_get_adapter_info(struct aac_dev* dev)
- 			rcode = -ENOMEM;
- 		}
+ 	return (0);
+@@ -6601,14 +6591,14 @@ ips_verify_bios(ips_ha_t * ha, char *buffer, uint32_t buffersize,
+ 
+ 	/* test 1st byte */
+ 	outl(0, ha->io_addr + IPS_REG_FLAP);
+-	if (ha->revision_id == IPS_REVID_TROMBONE64)
++	if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
+ 		udelay(25);	/* 25 us */
+ 
+ 	if (inb(ha->io_addr + IPS_REG_FLDP) != 0x55)
+ 		return (1);
+ 
+ 	outl(cpu_to_le32(1), ha->io_addr + IPS_REG_FLAP);
+-	if (ha->revision_id == IPS_REVID_TROMBONE64)
++	if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
+ 		udelay(25);	/* 25 us */
+ 	if (inb(ha->io_addr + IPS_REG_FLDP) != 0xAA)
+ 		return (1);
+@@ -6617,7 +6607,7 @@ ips_verify_bios(ips_ha_t * ha, char *buffer, uint32_t buffersize,
+ 	for (i = 2; i < buffersize; i++) {
+ 
+ 		outl(cpu_to_le32(i + offset), ha->io_addr + IPS_REG_FLAP);
+-		if (ha->revision_id == IPS_REVID_TROMBONE64)
++		if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
+ 			udelay(25);	/* 25 us */
+ 
+ 		checksum = (uint8_t) checksum + inb(ha->io_addr + IPS_REG_FLDP);
+@@ -6650,14 +6640,14 @@ ips_verify_bios_memio(ips_ha_t * ha, char *buffer, uint32_t buffersize,
+ 
+ 	/* test 1st byte */
+ 	writel(0, ha->mem_ptr + IPS_REG_FLAP);
+-	if (ha->revision_id == IPS_REVID_TROMBONE64)
++	if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
+ 		udelay(25);	/* 25 us */
+ 
+ 	if (readb(ha->mem_ptr + IPS_REG_FLDP) != 0x55)
+ 		return (1);
+ 
+ 	writel(1, ha->mem_ptr + IPS_REG_FLAP);
+-	if (ha->revision_id == IPS_REVID_TROMBONE64)
++	if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
+ 		udelay(25);	/* 25 us */
+ 	if (readb(ha->mem_ptr + IPS_REG_FLDP) != 0xAA)
+ 		return (1);
+@@ -6666,7 +6656,7 @@ ips_verify_bios_memio(ips_ha_t * ha, char *buffer, uint32_t buffersize,
+ 	for (i = 2; i < buffersize; i++) {
+ 
+ 		writel(i + offset, ha->mem_ptr + IPS_REG_FLAP);
+-		if (ha->revision_id == IPS_REVID_TROMBONE64)
++		if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
+ 			udelay(25);	/* 25 us */
+ 
+ 		checksum =
+@@ -6837,24 +6827,18 @@ ips_register_scsi(int index)
  	}
--	/* 
-+	/*
- 	 * Deal with configuring for the individualized limits of each packet
- 	 * interface.
- 	 */
- 	dev->a_ops.adapter_scsi = (dev->dac_support)
--				? aac_scsi_64
-+	  ? ((aac_get_driver_ident(dev->cardtype)->quirks & AAC_QUIRK_SCSI_32)
-+				? aac_scsi_32_64
-+				: aac_scsi_64)
- 				: aac_scsi_32;
- 	if (dev->raw_io_interface) {
- 		dev->a_ops.adapter_bounds = (dev->raw_io_64)
-@@ -1393,8 +1421,8 @@ int aac_get_adapter_info(struct aac_dev* dev)
- 		if (dev->dac_support) {
- 			dev->a_ops.adapter_read = aac_read_block64;
- 			dev->a_ops.adapter_write = aac_write_block64;
--			/* 
--			 * 38 scatter gather elements 
-+			/*
-+			 * 38 scatter gather elements
- 			 */
- 			dev->scsi_host_ptr->sg_tablesize =
- 				(dev->max_fib_size -
-@@ -1498,9 +1526,8 @@ static void io_callback(void *context, struct fib * fibptr)
- 				    ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0,
- 				    0, 0);
- 		memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
--		  (sizeof(dev->fsa_dev[cid].sense_data) > sizeof(scsicmd->sense_buffer))
--		    ? sizeof(scsicmd->sense_buffer)
--		    : sizeof(dev->fsa_dev[cid].sense_data));
-+		       min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data),
-+			     SCSI_SENSE_BUFFERSIZE));
+ 	ha = IPS_HA(sh);
+ 	memcpy(ha, oldha, sizeof (ips_ha_t));
+-	free_irq(oldha->irq, oldha);
++	free_irq(oldha->pcidev->irq, oldha);
+ 	/* Install the interrupt handler with the new ha */
+-	if (request_irq(ha->irq, do_ipsintr, IRQF_SHARED, ips_name, ha)) {
++	if (request_irq(ha->pcidev->irq, do_ipsintr, IRQF_SHARED, ips_name, ha)) {
+ 		IPS_PRINTK(KERN_WARNING, ha->pcidev,
+ 			   "Unable to install interrupt handler\n");
+-		scsi_host_put(sh);
+-		return -1;
++		goto err_out_sh;
  	}
- 	aac_fib_complete(fibptr);
- 	aac_fib_free(fibptr);
-@@ -1524,7 +1551,7 @@ static int aac_read(struct scsi_cmnd * scsicmd)
- 	case READ_6:
- 		dprintk((KERN_DEBUG "aachba: received a read(6) command on id %d.\n", scmd_id(scsicmd)));
  
--		lba = ((scsicmd->cmnd[1] & 0x1F) << 16) | 
-+		lba = ((scsicmd->cmnd[1] & 0x1F) << 16) |
- 			(scsicmd->cmnd[2] << 8) | scsicmd->cmnd[3];
- 		count = scsicmd->cmnd[4];
+ 	kfree(oldha);
+-	ips_sh[index] = sh;
+-	ips_ha[index] = ha;
  
-@@ -1534,32 +1561,32 @@ static int aac_read(struct scsi_cmnd * scsicmd)
- 	case READ_16:
- 		dprintk((KERN_DEBUG "aachba: received a read(16) command on id %d.\n", scmd_id(scsicmd)));
+ 	/* Store away needed values for later use */
+-	sh->io_port = ha->io_addr;
+-	sh->n_io_port = ha->io_addr ? 255 : 0;
+ 	sh->unique_id = (ha->io_addr) ? ha->io_addr : ha->mem_addr;
+-	sh->irq = ha->irq;
+ 	sh->sg_tablesize = sh->hostt->sg_tablesize;
+ 	sh->can_queue = sh->hostt->can_queue;
+ 	sh->cmd_per_lun = sh->hostt->cmd_per_lun;
+@@ -6867,10 +6851,21 @@ ips_register_scsi(int index)
+ 	sh->max_channel = ha->nbus - 1;
+ 	sh->can_queue = ha->max_cmds - 1;
  
--		lba = 	((u64)scsicmd->cmnd[2] << 56) |
--		 	((u64)scsicmd->cmnd[3] << 48) |
-+		lba =	((u64)scsicmd->cmnd[2] << 56) |
-+			((u64)scsicmd->cmnd[3] << 48) |
- 			((u64)scsicmd->cmnd[4] << 40) |
- 			((u64)scsicmd->cmnd[5] << 32) |
--			((u64)scsicmd->cmnd[6] << 24) | 
-+			((u64)scsicmd->cmnd[6] << 24) |
- 			(scsicmd->cmnd[7] << 16) |
- 			(scsicmd->cmnd[8] << 8) | scsicmd->cmnd[9];
--		count = (scsicmd->cmnd[10] << 24) | 
-+		count = (scsicmd->cmnd[10] << 24) |
- 			(scsicmd->cmnd[11] << 16) |
- 			(scsicmd->cmnd[12] << 8) | scsicmd->cmnd[13];
- 		break;
- 	case READ_12:
- 		dprintk((KERN_DEBUG "aachba: received a read(12) command on id %d.\n", scmd_id(scsicmd)));
+-	scsi_add_host(sh, NULL);
++	if (scsi_add_host(sh, &ha->pcidev->dev))
++		goto err_out;
++
++	ips_sh[index] = sh;
++	ips_ha[index] = ha;
++
+ 	scsi_scan_host(sh);
  
--		lba = ((u64)scsicmd->cmnd[2] << 24) | 
-+		lba = ((u64)scsicmd->cmnd[2] << 24) |
- 			(scsicmd->cmnd[3] << 16) |
--		    	(scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5];
--		count = (scsicmd->cmnd[6] << 24) | 
-+			(scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5];
-+		count = (scsicmd->cmnd[6] << 24) |
- 			(scsicmd->cmnd[7] << 16) |
--		      	(scsicmd->cmnd[8] << 8) | scsicmd->cmnd[9];
-+			(scsicmd->cmnd[8] << 8) | scsicmd->cmnd[9];
- 		break;
- 	default:
- 		dprintk((KERN_DEBUG "aachba: received a read(10) command on id %d.\n", scmd_id(scsicmd)));
+ 	return 0;
++
++err_out:
++	free_irq(ha->pcidev->irq, ha);
++err_out_sh:
++	scsi_host_put(sh);
++	return -1;
+ }
  
--		lba = ((u64)scsicmd->cmnd[2] << 24) | 
--			(scsicmd->cmnd[3] << 16) | 
-+		lba = ((u64)scsicmd->cmnd[2] << 24) |
-+			(scsicmd->cmnd[3] << 16) |
- 			(scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5];
- 		count = (scsicmd->cmnd[7] << 8) | scsicmd->cmnd[8];
- 		break;
-@@ -1584,7 +1611,7 @@ static int aac_read(struct scsi_cmnd * scsicmd)
- 		scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
- 		return 0;
- 	}
--		
+ /*---------------------------------------------------------------------------*/
+@@ -6882,20 +6877,14 @@ ips_register_scsi(int index)
+ static void __devexit
+ ips_remove_device(struct pci_dev *pci_dev)
+ {
+-	int i;
+-	struct Scsi_Host *sh;
+-	ips_ha_t *ha;
++	struct Scsi_Host *sh = pci_get_drvdata(pci_dev);
+ 
+-	for (i = 0; i < IPS_MAX_ADAPTERS; i++) {
+-		ha = ips_ha[i];
+-		if (ha) {
+-			if ((pci_dev->bus->number == ha->pcidev->bus->number) &&
+-			    (pci_dev->devfn == ha->pcidev->devfn)) {
+-				sh = ips_sh[i];
+-				ips_release(sh);
+-			}
+-		}
+-	}
++	pci_set_drvdata(pci_dev, NULL);
 +
- 	printk(KERN_WARNING "aac_read: aac_fib_send failed with status: %d.\n", status);
- 	/*
- 	 *	For some reason, the Fib didn't queue, return QUEUE_FULL
-@@ -1619,11 +1646,11 @@ static int aac_write(struct scsi_cmnd * scsicmd)
- 	} else if (scsicmd->cmnd[0] == WRITE_16) { /* 16 byte command */
- 		dprintk((KERN_DEBUG "aachba: received a write(16) command on id %d.\n", scmd_id(scsicmd)));
++	ips_release(sh);
++
++	pci_release_regions(pci_dev);
++	pci_disable_device(pci_dev);
+ }
  
--		lba = 	((u64)scsicmd->cmnd[2] << 56) |
-+		lba =	((u64)scsicmd->cmnd[2] << 56) |
- 			((u64)scsicmd->cmnd[3] << 48) |
- 			((u64)scsicmd->cmnd[4] << 40) |
- 			((u64)scsicmd->cmnd[5] << 32) |
--			((u64)scsicmd->cmnd[6] << 24) | 
-+			((u64)scsicmd->cmnd[6] << 24) |
- 			(scsicmd->cmnd[7] << 16) |
- 			(scsicmd->cmnd[8] << 8) | scsicmd->cmnd[9];
- 		count = (scsicmd->cmnd[10] << 24) | (scsicmd->cmnd[11] << 16) |
-@@ -1712,8 +1739,8 @@ static void synchronize_callback(void *context, struct fib *fibptr)
- 				    ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0,
- 				    0, 0);
- 		memcpy(cmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
--		  min(sizeof(dev->fsa_dev[cid].sense_data),
--			  sizeof(cmd->sense_buffer)));
-+		       min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data),
-+			     SCSI_SENSE_BUFFERSIZE));
- 	}
+ /****************************************************************************/
+@@ -6949,12 +6938,17 @@ module_exit(ips_module_exit);
+ static int __devinit
+ ips_insert_device(struct pci_dev *pci_dev, const struct pci_device_id *ent)
+ {
+-	int uninitialized_var(index);
++	int index = -1;
+ 	int rc;
  
- 	aac_fib_complete(fibptr);
-@@ -1798,7 +1825,7 @@ static int aac_synchronize(struct scsi_cmnd *scsicmd)
- 	if (active)
- 		return SCSI_MLQUEUE_DEVICE_BUSY;
+ 	METHOD_TRACE("ips_insert_device", 1);
+-	if (pci_enable_device(pci_dev))
+-		return -1;
++	rc = pci_enable_device(pci_dev);
++	if (rc)
++		return rc;
++
++	rc = pci_request_regions(pci_dev, "ips");
++	if (rc)
++		goto err_out;
  
--	aac = (struct aac_dev *)scsicmd->device->host->hostdata;
-+	aac = (struct aac_dev *)sdev->host->hostdata;
- 	if (aac->in_reset)
- 		return SCSI_MLQUEUE_HOST_BUSY;
+ 	rc = ips_init_phase1(pci_dev, &index);
+ 	if (rc == SUCCESS)
+@@ -6970,6 +6964,19 @@ ips_insert_device(struct pci_dev *pci_dev, const struct pci_device_id *ent)
+ 		ips_num_controllers++;
  
-@@ -1850,14 +1877,14 @@ static int aac_synchronize(struct scsi_cmnd *scsicmd)
-  *	Emulate a SCSI command and queue the required request for the
-  *	aacraid firmware.
-  */
-- 
+ 	ips_next_controller = ips_num_controllers;
 +
- int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
- {
- 	u32 cid;
- 	struct Scsi_Host *host = scsicmd->device->host;
- 	struct aac_dev *dev = (struct aac_dev *)host->hostdata;
- 	struct fsa_dev_info *fsa_dev_ptr = dev->fsa_dev;
--	
++	if (rc < 0) {
++		rc = -ENODEV;
++		goto err_out_regions;
++	}
 +
- 	if (fsa_dev_ptr == NULL)
++	pci_set_drvdata(pci_dev, ips_sh[index]);
++	return 0;
++
++err_out_regions:
++	pci_release_regions(pci_dev);
++err_out:
++	pci_disable_device(pci_dev);
+ 	return rc;
+ }
+ 
+@@ -6992,8 +6999,6 @@ ips_init_phase1(struct pci_dev *pci_dev, int *indexPtr)
+ 	uint32_t mem_len;
+ 	uint8_t bus;
+ 	uint8_t func;
+-	uint8_t irq;
+-	uint16_t subdevice_id;
+ 	int j;
+ 	int index;
+ 	dma_addr_t dma_address;
+@@ -7004,7 +7009,7 @@ ips_init_phase1(struct pci_dev *pci_dev, int *indexPtr)
+ 	METHOD_TRACE("ips_init_phase1", 1);
+ 	index = IPS_MAX_ADAPTERS;
+ 	for (j = 0; j < IPS_MAX_ADAPTERS; j++) {
+-		if (ips_ha[j] == 0) {
++		if (ips_ha[j] == NULL) {
+ 			index = j;
+ 			break;
+ 		}
+@@ -7014,7 +7019,6 @@ ips_init_phase1(struct pci_dev *pci_dev, int *indexPtr)
  		return -1;
- 	/*
-@@ -1898,7 +1925,8 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
- 				}
- 			}
- 		} else {  /* check for physical non-dasd devices */
--			if ((dev->nondasd_support == 1) || expose_physicals) {
-+			if (dev->nondasd_support || expose_physicals ||
-+					dev->jbod) {
- 				if (dev->in_reset)
- 					return -1;
- 				return aac_send_srb_fib(scsicmd);
-@@ -1913,7 +1941,7 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
- 	 * else Command for the controller itself
- 	 */
- 	else if ((scsicmd->cmnd[0] != INQUIRY) &&	/* only INQUIRY & TUR cmnd supported for controller */
--		(scsicmd->cmnd[0] != TEST_UNIT_READY)) 
-+		(scsicmd->cmnd[0] != TEST_UNIT_READY))
- 	{
- 		dprintk((KERN_WARNING "Only INQUIRY & TUR command supported for controller, rcvd = 0x%x.\n", scsicmd->cmnd[0]));
- 		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION;
-@@ -1922,9 +1950,8 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
- 			    SENCODE_INVALID_COMMAND,
- 			    ASENCODE_INVALID_COMMAND, 0, 0, 0, 0);
- 		memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
--		  (sizeof(dev->fsa_dev[cid].sense_data) > sizeof(scsicmd->sense_buffer))
--		    ? sizeof(scsicmd->sense_buffer)
--		    : sizeof(dev->fsa_dev[cid].sense_data));
-+		       min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data),
-+			     SCSI_SENSE_BUFFERSIZE));
- 		scsicmd->scsi_done(scsicmd);
- 		return 0;
- 	}
-@@ -1939,7 +1966,7 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
- 		dprintk((KERN_DEBUG "INQUIRY command, ID: %d.\n", cid));
- 		memset(&inq_data, 0, sizeof (struct inquiry_data));
  
--		if (scsicmd->cmnd[1] & 0x1 ) {
-+		if (scsicmd->cmnd[1] & 0x1) {
- 			char *arr = (char *)&inq_data;
+ 	/* stuff that we get in dev */
+-	irq = pci_dev->irq;
+ 	bus = pci_dev->bus->number;
+ 	func = pci_dev->devfn;
  
- 			/* EVPD bit set */
-@@ -1974,10 +2001,9 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
- 				  ASENCODE_NO_SENSE, 0, 7, 2, 0);
- 				memcpy(scsicmd->sense_buffer,
- 				  &dev->fsa_dev[cid].sense_data,
--				  (sizeof(dev->fsa_dev[cid].sense_data) >
--				    sizeof(scsicmd->sense_buffer))
--				       ? sizeof(scsicmd->sense_buffer)
--				       : sizeof(dev->fsa_dev[cid].sense_data));
-+				  min_t(size_t,
-+					sizeof(dev->fsa_dev[cid].sense_data),
-+					SCSI_SENSE_BUFFERSIZE));
- 			}
- 			scsicmd->scsi_done(scsicmd);
- 			return 0;
-@@ -2092,7 +2118,7 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
- 		mode_buf[2] = 0;	/* Device-specific param,
- 					   bit 8: 0/1 = write enabled/protected
- 					   bit 4: 0/1 = FUA enabled */
--		if (dev->raw_io_interface)
-+		if (dev->raw_io_interface && ((aac_cache & 5) != 1))
- 			mode_buf[2] = 0x10;
- 		mode_buf[3] = 0;	/* Block descriptor length */
- 		if (((scsicmd->cmnd[2] & 0x3f) == 8) ||
-@@ -2100,7 +2126,8 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
- 			mode_buf[0] = 6;
- 			mode_buf[4] = 8;
- 			mode_buf[5] = 1;
--			mode_buf[6] = 0x04; /* WCE */
-+			mode_buf[6] = ((aac_cache & 6) == 2)
-+				? 0 : 0x04; /* WCE */
- 			mode_buf_length = 7;
- 			if (mode_buf_length > scsicmd->cmnd[4])
- 				mode_buf_length = scsicmd->cmnd[4];
-@@ -2123,7 +2150,7 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
- 		mode_buf[3] = 0;	/* Device-specific param,
- 					   bit 8: 0/1 = write enabled/protected
- 					   bit 4: 0/1 = FUA enabled */
--		if (dev->raw_io_interface)
-+		if (dev->raw_io_interface && ((aac_cache & 5) != 1))
- 			mode_buf[3] = 0x10;
- 		mode_buf[4] = 0;	/* reserved */
- 		mode_buf[5] = 0;	/* reserved */
-@@ -2134,7 +2161,8 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
- 			mode_buf[1] = 9;
- 			mode_buf[8] = 8;
- 			mode_buf[9] = 1;
--			mode_buf[10] = 0x04; /* WCE */
-+			mode_buf[10] = ((aac_cache & 6) == 2)
-+				? 0 : 0x04; /* WCE */
- 			mode_buf_length = 11;
- 			if (mode_buf_length > scsicmd->cmnd[8])
- 				mode_buf_length = scsicmd->cmnd[8];
-@@ -2179,7 +2207,7 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
- 		return 0;
+@@ -7042,34 +7046,17 @@ ips_init_phase1(struct pci_dev *pci_dev, int *indexPtr)
+ 		uint32_t base;
+ 		uint32_t offs;
+ 
+-		if (!request_mem_region(mem_addr, mem_len, "ips")) {
+-			IPS_PRINTK(KERN_WARNING, pci_dev,
+-				   "Couldn't allocate IO Memory space %x len %d.\n",
+-				   mem_addr, mem_len);
+-			return -1;
+-		}
+-
+ 		base = mem_addr & PAGE_MASK;
+ 		offs = mem_addr - base;
+ 		ioremap_ptr = ioremap(base, PAGE_SIZE);
++		if (!ioremap_ptr)
++			return -1;
+ 		mem_ptr = ioremap_ptr + offs;
+ 	} else {
+ 		ioremap_ptr = NULL;
+ 		mem_ptr = NULL;
  	}
  
--	switch (scsicmd->cmnd[0]) 
-+	switch (scsicmd->cmnd[0])
- 	{
- 		case READ_6:
- 		case READ_10:
-@@ -2192,11 +2220,11 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
- 			 *	corresponds to a container. Needed to convert
- 			 *	containers to /dev/sd device names
- 			 */
--			 
-+
- 			if (scsicmd->request->rq_disk)
- 				strlcpy(fsa_dev_ptr[cid].devname,
- 				scsicmd->request->rq_disk->disk_name,
--			  	min(sizeof(fsa_dev_ptr[cid].devname),
-+				min(sizeof(fsa_dev_ptr[cid].devname),
- 				sizeof(scsicmd->request->rq_disk->disk_name) + 1));
+-	/* setup I/O mapped area (if applicable) */
+-	if (io_addr) {
+-		if (!request_region(io_addr, io_len, "ips")) {
+-			IPS_PRINTK(KERN_WARNING, pci_dev,
+-				   "Couldn't allocate IO space %x len %d.\n",
+-				   io_addr, io_len);
+-			return -1;
+-		}
+-	}
+-
+-	subdevice_id = pci_dev->subsystem_device;
+-
+ 	/* found a controller */
+ 	ha = kzalloc(sizeof (ips_ha_t), GFP_KERNEL);
+ 	if (ha == NULL) {
+@@ -7078,13 +7065,11 @@ ips_init_phase1(struct pci_dev *pci_dev, int *indexPtr)
+ 		return -1;
+ 	}
  
- 			return aac_read(scsicmd);
-@@ -2210,9 +2238,16 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
- 			return aac_write(scsicmd);
+-
+ 	ips_sh[index] = NULL;
+ 	ips_ha[index] = ha;
+ 	ha->active = 1;
  
- 		case SYNCHRONIZE_CACHE:
-+			if (((aac_cache & 6) == 6) && dev->cache_protected) {
-+				scsicmd->result = DID_OK << 16 |
-+					COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
-+				scsicmd->scsi_done(scsicmd);
-+				return 0;
-+			}
- 			/* Issue FIB to tell Firmware to flush it's cache */
--			return aac_synchronize(scsicmd);
--			
-+			if ((aac_cache & 6) != 2)
-+				return aac_synchronize(scsicmd);
-+			/* FALLTHRU */
- 		default:
- 			/*
- 			 *	Unhandled commands
-@@ -2223,9 +2258,9 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
- 				ILLEGAL_REQUEST, SENCODE_INVALID_COMMAND,
- 				ASENCODE_INVALID_COMMAND, 0, 0, 0, 0);
- 			memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
--			  (sizeof(dev->fsa_dev[cid].sense_data) > sizeof(scsicmd->sense_buffer))
--			    ? sizeof(scsicmd->sense_buffer)
--			    : sizeof(dev->fsa_dev[cid].sense_data));
-+				min_t(size_t,
-+				      sizeof(dev->fsa_dev[cid].sense_data),
-+				      SCSI_SENSE_BUFFERSIZE));
- 			scsicmd->scsi_done(scsicmd);
- 			return 0;
- 	}
-@@ -2243,7 +2278,7 @@ static int query_disk(struct aac_dev *dev, void __user *arg)
- 		return -EFAULT;
- 	if (qd.cnum == -1)
- 		qd.cnum = qd.id;
--	else if ((qd.bus == -1) && (qd.id == -1) && (qd.lun == -1)) 
-+	else if ((qd.bus == -1) && (qd.id == -1) && (qd.lun == -1))
- 	{
- 		if (qd.cnum < 0 || qd.cnum >= dev->maximum_num_containers)
- 			return -EINVAL;
-@@ -2370,7 +2405,7 @@ static void aac_srb_callback(void *context, struct fib * fibptr)
+ 	/* Store info in HA structure */
+-	ha->irq = irq;
+ 	ha->io_addr = io_addr;
+ 	ha->io_len = io_len;
+ 	ha->mem_addr = mem_addr;
+@@ -7092,10 +7077,7 @@ ips_init_phase1(struct pci_dev *pci_dev, int *indexPtr)
+ 	ha->mem_ptr = mem_ptr;
+ 	ha->ioremap_ptr = ioremap_ptr;
+ 	ha->host_num = (uint32_t) index;
+-	ha->revision_id = pci_dev->revision;
+ 	ha->slot_num = PCI_SLOT(pci_dev->devfn);
+-	ha->device_id = pci_dev->device;
+-	ha->subdevice_id = subdevice_id;
+ 	ha->pcidev = pci_dev;
  
- 	scsicmd->sense_buffer[0] = '\0';  /* Initialize sense valid flag to false */
  	/*
--	 *	Calculate resid for sg 
-+	 *	Calculate resid for sg
- 	 */
+@@ -7240,7 +7222,7 @@ ips_init_phase2(int index)
+ 	}
  
- 	scsi_set_resid(scsicmd, scsi_bufflen(scsicmd)
-@@ -2385,10 +2420,8 @@ static void aac_srb_callback(void *context, struct fib * fibptr)
- 	if (le32_to_cpu(srbreply->status) != ST_OK){
- 		int len;
- 		printk(KERN_WARNING "aac_srb_callback: srb failed, status = %d\n", le32_to_cpu(srbreply->status));
--		len = (le32_to_cpu(srbreply->sense_data_size) > 
--				sizeof(scsicmd->sense_buffer)) ?
--				sizeof(scsicmd->sense_buffer) : 
--				le32_to_cpu(srbreply->sense_data_size);
-+		len = min_t(u32, le32_to_cpu(srbreply->sense_data_size),
-+			    SCSI_SENSE_BUFFERSIZE);
- 		scsicmd->result = DID_ERROR << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION;
- 		memcpy(scsicmd->sense_buffer, srbreply->sense_data, len);
+ 	/* Install the interrupt handler */
+-	if (request_irq(ha->irq, do_ipsintr, IRQF_SHARED, ips_name, ha)) {
++	if (request_irq(ha->pcidev->irq, do_ipsintr, IRQF_SHARED, ips_name, ha)) {
+ 		IPS_PRINTK(KERN_WARNING, ha->pcidev,
+ 			   "Unable to install interrupt handler\n");
+ 		return ips_abort_init(ha, index);
+@@ -7253,14 +7235,14 @@ ips_init_phase2(int index)
+ 	if (!ips_allocatescbs(ha)) {
+ 		IPS_PRINTK(KERN_WARNING, ha->pcidev,
+ 			   "Unable to allocate a CCB\n");
+-		free_irq(ha->irq, ha);
++		free_irq(ha->pcidev->irq, ha);
+ 		return ips_abort_init(ha, index);
  	}
-@@ -2412,7 +2445,7 @@ static void aac_srb_callback(void *context, struct fib * fibptr)
- 		case  WRITE_12:
- 		case  READ_16:
- 		case  WRITE_16:
--			if(le32_to_cpu(srbreply->data_xfer_length) < scsicmd->underflow ) {
-+			if (le32_to_cpu(srbreply->data_xfer_length) < scsicmd->underflow) {
- 				printk(KERN_WARNING"aacraid: SCSI CMD underflow\n");
- 			} else {
- 				printk(KERN_WARNING"aacraid: SCSI CMD Data Overrun\n");
-@@ -2481,26 +2514,23 @@ static void aac_srb_callback(void *context, struct fib * fibptr)
- 		printk("aacraid: SRB ERROR(%u) %s scsi cmd 0x%x - scsi status 0x%x\n",
- 			le32_to_cpu(srbreply->srb_status) & 0x3F,
- 			aac_get_status_string(
--				le32_to_cpu(srbreply->srb_status) & 0x3F), 
--			scsicmd->cmnd[0], 
-+				le32_to_cpu(srbreply->srb_status) & 0x3F),
-+			scsicmd->cmnd[0],
- 			le32_to_cpu(srbreply->scsi_status));
- #endif
- 		scsicmd->result = DID_ERROR << 16 | COMMAND_COMPLETE << 8;
- 		break;
+ 
+ 	if (!ips_hainit(ha)) {
+ 		IPS_PRINTK(KERN_WARNING, ha->pcidev,
+ 			   "Unable to initialize controller\n");
+-		free_irq(ha->irq, ha);
++		free_irq(ha->pcidev->irq, ha);
+ 		return ips_abort_init(ha, index);
  	}
--	if (le32_to_cpu(srbreply->scsi_status) == 0x02 ){  // Check Condition
-+	if (le32_to_cpu(srbreply->scsi_status) == SAM_STAT_CHECK_CONDITION) {
- 		int len;
- 		scsicmd->result |= SAM_STAT_CHECK_CONDITION;
--		len = (le32_to_cpu(srbreply->sense_data_size) > 
--				sizeof(scsicmd->sense_buffer)) ?
--				sizeof(scsicmd->sense_buffer) :
--				le32_to_cpu(srbreply->sense_data_size);
-+		len = min_t(u32, le32_to_cpu(srbreply->sense_data_size),
-+			    SCSI_SENSE_BUFFERSIZE);
- #ifdef AAC_DETAILED_STATUS_INFO
- 		printk(KERN_WARNING "aac_srb_callback: check condition, status = %d len=%d\n",
- 					le32_to_cpu(srbreply->status), len);
- #endif
- 		memcpy(scsicmd->sense_buffer, srbreply->sense_data, len);
--		
+ 	/* Free the temporary SCB */
+@@ -7270,7 +7252,7 @@ ips_init_phase2(int index)
+ 	if (!ips_allocatescbs(ha)) {
+ 		IPS_PRINTK(KERN_WARNING, ha->pcidev,
+ 			   "Unable to allocate CCBs\n");
+-		free_irq(ha->irq, ha);
++		free_irq(ha->pcidev->irq, ha);
+ 		return ips_abort_init(ha, index);
  	}
- 	/*
- 	 * OR in the scsi status (already shifted up a bit)
-@@ -2517,7 +2547,7 @@ static void aac_srb_callback(void *context, struct fib * fibptr)
-  * aac_send_scb_fib
-  * @scsicmd: the scsi command block
-  *
-- * This routine will form a FIB and fill in the aac_srb from the 
-+ * This routine will form a FIB and fill in the aac_srb from the
-  * scsicmd passed in.
-  */
- 
-@@ -2731,7 +2761,7 @@ static struct aac_srb_status_info srb_status_info[] = {
- 	{ SRB_STATUS_ERROR_RECOVERY,	"Error Recovery"},
- 	{ SRB_STATUS_NOT_STARTED,	"Not Started"},
- 	{ SRB_STATUS_NOT_IN_USE,	"Not In Use"},
--    	{ SRB_STATUS_FORCE_ABORT,	"Force Abort"},
-+	{ SRB_STATUS_FORCE_ABORT,	"Force Abort"},
- 	{ SRB_STATUS_DOMAIN_VALIDATION_FAIL,"Domain Validation Failure"},
- 	{ 0xff,				"Unknown Error"}
- };
-diff --git a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h
-index 9abba8b..3195d29 100644
---- a/drivers/scsi/aacraid/aacraid.h
-+++ b/drivers/scsi/aacraid/aacraid.h
-@@ -1,4 +1,4 @@
--#if (!defined(dprintk))
-+#ifndef dprintk
- # define dprintk(x)
- #endif
- /* eg: if (nblank(dprintk(x))) */
-@@ -12,7 +12,7 @@
-  *----------------------------------------------------------------------------*/
  
- #ifndef AAC_DRIVER_BUILD
--# define AAC_DRIVER_BUILD 2449
-+# define AAC_DRIVER_BUILD 2455
- # define AAC_DRIVER_BRANCH "-ms"
- #endif
- #define MAXIMUM_NUM_CONTAINERS	32
-@@ -50,9 +50,9 @@ struct diskparm
- /*
-  *	Firmware constants
-  */
-- 
+diff --git a/drivers/scsi/ips.h b/drivers/scsi/ips.h
+index 3bcbd9f..e0657b6 100644
+--- a/drivers/scsi/ips.h
++++ b/drivers/scsi/ips.h
+@@ -60,14 +60,14 @@
+     */
+    #define IPS_HA(x)                   ((ips_ha_t *) x->hostdata)
+    #define IPS_COMMAND_ID(ha, scb)     (int) (scb - ha->scbs)
+-   #define IPS_IS_TROMBONE(ha)         (((ha->device_id == IPS_DEVICEID_COPPERHEAD) && \
+-                                         (ha->revision_id >= IPS_REVID_TROMBONE32) && \
+-                                         (ha->revision_id <= IPS_REVID_TROMBONE64)) ? 1 : 0)
+-   #define IPS_IS_CLARINET(ha)         (((ha->device_id == IPS_DEVICEID_COPPERHEAD) && \
+-                                         (ha->revision_id >= IPS_REVID_CLARINETP1) && \
+-                                         (ha->revision_id <= IPS_REVID_CLARINETP3)) ? 1 : 0)
+-   #define IPS_IS_MORPHEUS(ha)         (ha->device_id == IPS_DEVICEID_MORPHEUS)
+-   #define IPS_IS_MARCO(ha)            (ha->device_id == IPS_DEVICEID_MARCO)
++   #define IPS_IS_TROMBONE(ha)         (((ha->pcidev->device == IPS_DEVICEID_COPPERHEAD) && \
++                                         (ha->pcidev->revision >= IPS_REVID_TROMBONE32) && \
++                                         (ha->pcidev->revision <= IPS_REVID_TROMBONE64)) ? 1 : 0)
++   #define IPS_IS_CLARINET(ha)         (((ha->pcidev->device == IPS_DEVICEID_COPPERHEAD) && \
++                                         (ha->pcidev->revision >= IPS_REVID_CLARINETP1) && \
++                                         (ha->pcidev->revision <= IPS_REVID_CLARINETP3)) ? 1 : 0)
++   #define IPS_IS_MORPHEUS(ha)         (ha->pcidev->device == IPS_DEVICEID_MORPHEUS)
++   #define IPS_IS_MARCO(ha)            (ha->pcidev->device == IPS_DEVICEID_MARCO)
+    #define IPS_USE_I2O_DELIVER(ha)     ((IPS_IS_MORPHEUS(ha) || \
+                                          (IPS_IS_TROMBONE(ha) && \
+                                           (ips_force_i2o))) ? 1 : 0)
+@@ -92,7 +92,7 @@
+    #ifndef min
+       #define min(x,y) ((x) < (y) ? x : y)
+    #endif
+-   
 +
- #define		CT_NONE			0
--#define 	CT_OK        		218
-+#define		CT_OK			218
- #define		FT_FILESYS	8	/* ADAPTEC's "FSA"(tm) filesystem */
- #define		FT_DRIVE	9	/* physical disk - addressable in scsi by bus/id/lun */
- 
-@@ -107,12 +107,12 @@ struct user_sgentryraw {
+    #ifndef __iomem       /* For clean compiles in earlier kernels without __iomem annotations */
+       #define __iomem
+    #endif
+@@ -171,7 +171,7 @@
+    #define IPS_CMD_DOWNLOAD             0x20
+    #define IPS_CMD_RW_BIOSFW            0x22
+    #define IPS_CMD_GET_VERSION_INFO     0xC6
+-   #define IPS_CMD_RESET_CHANNEL        0x1A  
++   #define IPS_CMD_RESET_CHANNEL        0x1A
  
- struct sgmap {
- 	__le32		count;
--	struct sgentry	sg[1]; 
-+	struct sgentry	sg[1];
- };
+    /*
+     * Adapter Equates
+@@ -458,7 +458,7 @@ typedef struct {
+    uint32_t reserved3;
+    uint32_t buffer_addr;
+    uint32_t reserved4;
+-} IPS_IOCTL_CMD, *PIPS_IOCTL_CMD; 
++} IPS_IOCTL_CMD, *PIPS_IOCTL_CMD;
  
- struct user_sgmap {
- 	u32		count;
--	struct user_sgentry	sg[1]; 
-+	struct user_sgentry	sg[1];
- };
+ typedef struct {
+    uint8_t  op_code;
+@@ -552,7 +552,7 @@ typedef struct {
+    uint32_t cccr;
+ } IPS_NVRAM_CMD, *PIPS_NVRAM_CMD;
  
- struct sgmap64 {
-@@ -137,18 +137,18 @@ struct user_sgmapraw {
+-typedef struct 
++typedef struct
+ {
+     uint8_t  op_code;
+     uint8_t  command_id;
+@@ -650,7 +650,7 @@ typedef struct {
+    uint8_t   device_address;
+    uint8_t   cmd_attribute;
+    uint8_t   cdb_length;
+-   uint8_t   reserved_for_LUN; 	 
++   uint8_t   reserved_for_LUN;
+    uint32_t  transfer_length;
+    uint32_t  buffer_pointer;
+    uint16_t  sg_count;
+@@ -790,7 +790,7 @@ typedef struct {
+                                              /* SubSystem Parameter[4]      */
+ #define  IPS_GET_VERSION_SUPPORT 0x00018000  /* Mask for Versioning Support */
  
- struct creation_info
+-typedef struct 
++typedef struct
  {
--	u8 		buildnum;		/* e.g., 588 */
--	u8 		usec;			/* e.g., 588 */
--	u8	 	via;			/* e.g., 1 = FSU,
--						 * 	 2 = API
-+	u8		buildnum;		/* e.g., 588 */
-+	u8		usec;			/* e.g., 588 */
-+	u8		via;			/* e.g., 1 = FSU,
-+						 *	 2 = API
- 						 */
--	u8	 	year;		 	/* e.g., 1997 = 97 */
-+	u8		year;			/* e.g., 1997 = 97 */
- 	__le32		date;			/*
--						 * unsigned 	Month		:4;	// 1 - 12
--						 * unsigned 	Day		:6;	// 1 - 32
--						 * unsigned 	Hour		:6;	// 0 - 23
--						 * unsigned 	Minute		:6;	// 0 - 60
--						 * unsigned 	Second		:6;	// 0 - 60
-+						 * unsigned	Month		:4;	// 1 - 12
-+						 * unsigned	Day		:6;	// 1 - 32
-+						 * unsigned	Hour		:6;	// 0 - 23
-+						 * unsigned	Minute		:6;	// 0 - 60
-+						 * unsigned	Second		:6;	// 0 - 60
- 						 */
- 	__le32		serial[2];			/* e.g., 0x1DEADB0BFAFAF001 */
- };
-@@ -184,7 +184,7 @@ struct creation_info
- /*
-  *	Set the queues on a 16 byte alignment
-  */
-- 
+    uint32_t  revision;
+    uint8_t   bootBlkVersion[32];
+@@ -1034,7 +1034,6 @@ typedef struct ips_ha {
+    uint8_t            ha_id[IPS_MAX_CHANNELS+1];
+    uint32_t           dcdb_active[IPS_MAX_CHANNELS];
+    uint32_t           io_addr;            /* Base I/O address           */
+-   uint8_t            irq;                /* IRQ for adapter            */
+    uint8_t            ntargets;           /* Number of targets          */
+    uint8_t            nbus;               /* Number of buses            */
+    uint8_t            nlun;               /* Number of Luns             */
+@@ -1066,10 +1065,7 @@ typedef struct ips_ha {
+    int                ioctl_reset;        /* IOCTL Requested Reset Flag */
+    uint16_t           reset_count;        /* number of resets           */
+    time_t             last_ffdc;          /* last time we sent ffdc info*/
+-   uint8_t            revision_id;        /* Revision level             */
+-   uint16_t           device_id;          /* PCI device ID              */
+    uint8_t            slot_num;           /* PCI Slot Number            */
+-   uint16_t           subdevice_id;       /* Subsystem device ID        */
+    int                ioctl_len;          /* size of ioctl buffer       */
+    dma_addr_t         ioctl_busaddr;      /* dma address of ioctl buffer*/
+    uint8_t            bios_version[8];    /* BIOS Revision              */
+diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c
+index 57ce225..e5be5fd 100644
+--- a/drivers/scsi/iscsi_tcp.c
++++ b/drivers/scsi/iscsi_tcp.c
+@@ -48,7 +48,7 @@ MODULE_AUTHOR("Dmitry Yusupov <dmitry_yus at yahoo.com>, "
+ 	      "Alex Aizman <itn780 at yahoo.com>");
+ MODULE_DESCRIPTION("iSCSI/TCP data-path");
+ MODULE_LICENSE("GPL");
+-/* #define DEBUG_TCP */
++#undef DEBUG_TCP
+ #define DEBUG_ASSERT
+ 
+ #ifdef DEBUG_TCP
+@@ -67,115 +67,429 @@ MODULE_LICENSE("GPL");
+ static unsigned int iscsi_max_lun = 512;
+ module_param_named(max_lun, iscsi_max_lun, uint, S_IRUGO);
+ 
++static int iscsi_tcp_hdr_recv_done(struct iscsi_tcp_conn *tcp_conn,
++				   struct iscsi_segment *segment);
 +
- #define QUEUE_ALIGNMENT		16
++/*
++ * Scatterlist handling: inside the iscsi_segment, we
++ * remember an index into the scatterlist, and set data/size
++ * to the current scatterlist entry. For highmem pages, we
++ * kmap as needed.
++ *
++ * Note that the page is unmapped when we return from
++ * TCP's data_ready handler, so we may end up mapping and
++ * unmapping the same page repeatedly. The whole reason
++ * for this is that we shouldn't keep the page mapped
++ * outside the softirq.
++ */
++
++/**
++ * iscsi_tcp_segment_init_sg - init indicated scatterlist entry
++ * @segment: the buffer object
++ * @sg: scatterlist
++ * @offset: byte offset into that sg entry
++ *
++ * This function sets up the segment so that subsequent
++ * data is copied to the indicated sg entry, at the given
++ * offset.
++ */
+ static inline void
+-iscsi_buf_init_iov(struct iscsi_buf *ibuf, char *vbuf, int size)
++iscsi_tcp_segment_init_sg(struct iscsi_segment *segment,
++			  struct scatterlist *sg, unsigned int offset)
+ {
+-	sg_init_one(&ibuf->sg, vbuf, size);
+-	ibuf->sent = 0;
+-	ibuf->use_sendmsg = 1;
++	segment->sg = sg;
++	segment->sg_offset = offset;
++	segment->size = min(sg->length - offset,
++			    segment->total_size - segment->total_copied);
++	segment->data = NULL;
+ }
  
- /*
-@@ -203,9 +203,9 @@ struct aac_entry {
-  *	The adapter assumes the ProducerIndex and ConsumerIndex are grouped
-  *	adjacently and in that order.
-  */
-- 
++/**
++ * iscsi_tcp_segment_map - map the current S/G page
++ * @segment: iscsi_segment
++ * @recv: 1 if called from recv path
++ *
++ * We only need to possibly kmap data if scatter lists are being used,
++ * because the iscsi passthrough and internal IO paths will never use high
++ * mem pages.
++ */
+ static inline void
+-iscsi_buf_init_sg(struct iscsi_buf *ibuf, struct scatterlist *sg)
++iscsi_tcp_segment_map(struct iscsi_segment *segment, int recv)
+ {
+-	sg_init_table(&ibuf->sg, 1);
+-	sg_set_page(&ibuf->sg, sg_page(sg), sg->length, sg->offset);
++	struct scatterlist *sg;
 +
- struct aac_qhdr {
--	__le64 header_addr;/* Address to hand the adapter to access 
-+	__le64 header_addr;/* Address to hand the adapter to access
- 			      to this queue head */
- 	__le32 *producer; /* The producer index for this queue (host address) */
- 	__le32 *consumer; /* The consumer index for this queue (host address) */
-@@ -215,7 +215,7 @@ struct aac_qhdr {
-  *	Define all the events which the adapter would like to notify
-  *	the host of.
-  */
-- 
++	if (segment->data != NULL || !segment->sg)
++		return;
 +
- #define		HostNormCmdQue		1	/* Change in host normal priority command queue */
- #define		HostHighCmdQue		2	/* Change in host high priority command queue */
- #define		HostNormRespQue		3	/* Change in host normal priority response queue */
-@@ -286,17 +286,17 @@ struct aac_fibhdr {
- 	u8 StructType;		/* Type FIB */
- 	u8 Flags;		/* Flags for FIB */
- 	__le16 Size;		/* Size of this FIB in bytes */
--	__le16 SenderSize;	/* Size of the FIB in the sender 
-+	__le16 SenderSize;	/* Size of the FIB in the sender
- 				   (for response sizing) */
- 	__le32 SenderFibAddress;  /* Host defined data in the FIB */
--	__le32 ReceiverFibAddress;/* Logical address of this FIB for 
-+	__le32 ReceiverFibAddress;/* Logical address of this FIB for
- 				     the adapter */
- 	u32 SenderData;		/* Place holder for the sender to store data */
- 	union {
- 		struct {
--		    __le32 _ReceiverTimeStart; 	/* Timestamp for 
-+		    __le32 _ReceiverTimeStart;	/* Timestamp for
- 						   receipt of fib */
--		    __le32 _ReceiverTimeDone;	/* Timestamp for 
-+		    __le32 _ReceiverTimeDone;	/* Timestamp for
- 						   completion of fib */
- 		} _s;
- 	} _u;
-@@ -311,7 +311,7 @@ struct hw_fib {
-  *	FIB commands
-  */
++	sg = segment->sg;
++	BUG_ON(segment->sg_mapped);
++	BUG_ON(sg->length == 0);
++
+ 	/*
+-	 * Fastpath: sg element fits into single page
++	 * If the page count is greater than one it is ok to send
++	 * to the network layer's zero copy send path. If not we
++	 * have to go the slow sendmsg path. We always map for the
++	 * recv path.
+ 	 */
+-	if (sg->length + sg->offset <= PAGE_SIZE && !PageSlab(sg_page(sg)))
+-		ibuf->use_sendmsg = 0;
+-	else
+-		ibuf->use_sendmsg = 1;
+-	ibuf->sent = 0;
++	if (page_count(sg_page(sg)) >= 1 && !recv)
++		return;
++
++	debug_tcp("iscsi_tcp_segment_map %s %p\n", recv ? "recv" : "xmit",
++		  segment);
++	segment->sg_mapped = kmap_atomic(sg_page(sg), KM_SOFTIRQ0);
++	segment->data = segment->sg_mapped + sg->offset + segment->sg_offset;
+ }
  
--#define 	TestCommandResponse		1
-+#define		TestCommandResponse		1
- #define		TestAdapterCommand		2
- /*
-  *	Lowlevel and comm commands
-@@ -350,10 +350,6 @@ struct hw_fib {
- #define		ContainerCommand64		501
- #define		ContainerRawIo			502
- /*
-- *	Cluster Commands
-- */
--#define		ClusterCommand	 		550
--/*
-  *	Scsi Port commands (scsi passthrough)
-  */
- #define		ScsiPortCommand			600
-@@ -375,19 +371,19 @@ struct hw_fib {
-  */
+-static inline int
+-iscsi_buf_left(struct iscsi_buf *ibuf)
++static inline void
++iscsi_tcp_segment_unmap(struct iscsi_segment *segment)
+ {
+-	int rc;
++	debug_tcp("iscsi_tcp_segment_unmap %p\n", segment);
  
- enum fib_xfer_state {
--	HostOwned 			= (1<<0),
--	AdapterOwned 			= (1<<1),
--	FibInitialized 			= (1<<2),
--	FibEmpty 			= (1<<3),
--	AllocatedFromPool 		= (1<<4),
--	SentFromHost 			= (1<<5),
--	SentFromAdapter 		= (1<<6),
--	ResponseExpected 		= (1<<7),
--	NoResponseExpected 		= (1<<8),
--	AdapterProcessed 		= (1<<9),
--	HostProcessed 			= (1<<10),
--	HighPriority 			= (1<<11),
--	NormalPriority 			= (1<<12),
-+	HostOwned			= (1<<0),
-+	AdapterOwned			= (1<<1),
-+	FibInitialized			= (1<<2),
-+	FibEmpty			= (1<<3),
-+	AllocatedFromPool		= (1<<4),
-+	SentFromHost			= (1<<5),
-+	SentFromAdapter			= (1<<6),
-+	ResponseExpected		= (1<<7),
-+	NoResponseExpected		= (1<<8),
-+	AdapterProcessed		= (1<<9),
-+	HostProcessed			= (1<<10),
-+	HighPriority			= (1<<11),
-+	NormalPriority			= (1<<12),
- 	Async				= (1<<13),
- 	AsyncIo				= (1<<13),	// rpbfix: remove with new regime
- 	PageFileIo			= (1<<14),	// rpbfix: remove with new regime
-@@ -420,7 +416,7 @@ struct aac_init
- 	__le32	AdapterFibAlign;
- 	__le32	printfbuf;
- 	__le32	printfbufsiz;
--	__le32	HostPhysMemPages;   /* number of 4k pages of host 
-+	__le32	HostPhysMemPages;   /* number of 4k pages of host
- 				       physical memory */
- 	__le32	HostElapsedSeconds; /* number of seconds since 1970. */
- 	/*
-@@ -481,7 +477,7 @@ struct adapter_ops
+-	rc = ibuf->sg.length - ibuf->sent;
+-	BUG_ON(rc < 0);
+-	return rc;
++	if (segment->sg_mapped) {
++		debug_tcp("iscsi_tcp_segment_unmap valid\n");
++		kunmap_atomic(segment->sg_mapped, KM_SOFTIRQ0);
++		segment->sg_mapped = NULL;
++		segment->data = NULL;
++	}
+ }
  
- struct aac_driver_ident
++/*
++ * Splice the digest buffer into the buffer
++ */
+ static inline void
+-iscsi_hdr_digest(struct iscsi_conn *conn, struct iscsi_buf *buf,
+-		 u8* crc)
++iscsi_tcp_segment_splice_digest(struct iscsi_segment *segment, void *digest)
  {
--	int 	(*init)(struct aac_dev *dev);
-+	int	(*init)(struct aac_dev *dev);
- 	char *	name;
- 	char *	vname;
- 	char *	model;
-@@ -489,7 +485,7 @@ struct aac_driver_ident
- 	int	quirks;
- };
- /*
-- * Some adapter firmware needs communication memory 
-+ * Some adapter firmware needs communication memory
-  * below 2gig. This tells the init function to set the
-  * dma mask such that fib memory will be allocated where the
-  * adapter firmware can get to it.
-@@ -521,33 +517,39 @@ struct aac_driver_ident
- #define AAC_QUIRK_17SG	0x0010
+-	struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
+-
+-	crypto_hash_digest(&tcp_conn->tx_hash, &buf->sg, buf->sg.length, crc);
+-	buf->sg.length += sizeof(u32);
++	segment->data = digest;
++	segment->digest_len = ISCSI_DIGEST_SIZE;
++	segment->total_size += ISCSI_DIGEST_SIZE;
++	segment->size = ISCSI_DIGEST_SIZE;
++	segment->copied = 0;
++	segment->sg = NULL;
++	segment->hash = NULL;
+ }
  
- /*
-+ *	Some adapter firmware does not support 64 bit scsi passthrough
-+ * commands.
++/**
++ * iscsi_tcp_segment_done - check whether the segment is complete
++ * @segment: iscsi segment to check
++ * @recv: set to one of this is called from the recv path
++ * @copied: number of bytes copied
++ *
++ * Check if we're done receiving this segment. If the receive
++ * buffer is full but we expect more data, move on to the
++ * next entry in the scatterlist.
++ *
++ * If the amount of data we received isn't a multiple of 4,
++ * we will transparently receive the pad bytes, too.
++ *
++ * This function must be re-entrant.
++ */
+ static inline int
+-iscsi_hdr_extract(struct iscsi_tcp_conn *tcp_conn)
++iscsi_tcp_segment_done(struct iscsi_segment *segment, int recv, unsigned copied)
+ {
+-	struct sk_buff *skb = tcp_conn->in.skb;
+-
+-	tcp_conn->in.zero_copy_hdr = 0;
++	static unsigned char padbuf[ISCSI_PAD_LEN];
++	struct scatterlist sg;
++	unsigned int pad;
+ 
+-	if (tcp_conn->in.copy >= tcp_conn->hdr_size &&
+-	    tcp_conn->in_progress == IN_PROGRESS_WAIT_HEADER) {
++	debug_tcp("copied %u %u size %u %s\n", segment->copied, copied,
++		  segment->size, recv ? "recv" : "xmit");
++	if (segment->hash && copied) {
+ 		/*
+-		 * Zero-copy PDU Header: using connection context
+-		 * to store header pointer.
++		 * If a segment is kmapd we must unmap it before sending
++		 * to the crypto layer since that will try to kmap it again.
+ 		 */
+-		if (skb_shinfo(skb)->frag_list == NULL &&
+-		    !skb_shinfo(skb)->nr_frags) {
+-			tcp_conn->in.hdr = (struct iscsi_hdr *)
+-				((char*)skb->data + tcp_conn->in.offset);
+-			tcp_conn->in.zero_copy_hdr = 1;
++		iscsi_tcp_segment_unmap(segment);
++
++		if (!segment->data) {
++			sg_init_table(&sg, 1);
++			sg_set_page(&sg, sg_page(segment->sg), copied,
++				    segment->copied + segment->sg_offset +
++							segment->sg->offset);
++		} else
++			sg_init_one(&sg, segment->data + segment->copied,
++				    copied);
++		crypto_hash_update(segment->hash, &sg, copied);
++	}
++
++	segment->copied += copied;
++	if (segment->copied < segment->size) {
++		iscsi_tcp_segment_map(segment, recv);
++		return 0;
++	}
++
++	segment->total_copied += segment->copied;
++	segment->copied = 0;
++	segment->size = 0;
++
++	/* Unmap the current scatterlist page, if there is one. */
++	iscsi_tcp_segment_unmap(segment);
++
++	/* Do we have more scatterlist entries? */
++	debug_tcp("total copied %u total size %u\n", segment->total_copied,
++		   segment->total_size);
++	if (segment->total_copied < segment->total_size) {
++		/* Proceed to the next entry in the scatterlist. */
++		iscsi_tcp_segment_init_sg(segment, sg_next(segment->sg),
++					  0);
++		iscsi_tcp_segment_map(segment, recv);
++		BUG_ON(segment->size == 0);
++		return 0;
++	}
++
++	/* Do we need to handle padding? */
++	pad = iscsi_padding(segment->total_copied);
++	if (pad != 0) {
++		debug_tcp("consume %d pad bytes\n", pad);
++		segment->total_size += pad;
++		segment->size = pad;
++		segment->data = padbuf;
++		return 0;
++	}
++
++	/*
++	 * Set us up for transferring the data digest. hdr digest
++	 * is completely handled in hdr done function.
++	 */
++	if (segment->hash) {
++		crypto_hash_final(segment->hash, segment->digest);
++		iscsi_tcp_segment_splice_digest(segment,
++				 recv ? segment->recv_digest : segment->digest);
++		return 0;
++	}
++
++	return 1;
++}
++
++/**
++ * iscsi_tcp_xmit_segment - transmit segment
++ * @tcp_conn: the iSCSI TCP connection
++ * @segment: the buffer to transmnit
++ *
++ * This function transmits as much of the buffer as
++ * the network layer will accept, and returns the number of
++ * bytes transmitted.
++ *
++ * If CRC hashing is enabled, the function will compute the
++ * hash as it goes. When the entire segment has been transmitted,
++ * it will retrieve the hash value and send it as well.
 + */
-+#define AAC_QUIRK_SCSI_32	0x0020
++static int
++iscsi_tcp_xmit_segment(struct iscsi_tcp_conn *tcp_conn,
++		       struct iscsi_segment *segment)
++{
++	struct socket *sk = tcp_conn->sock;
++	unsigned int copied = 0;
++	int r = 0;
 +
-+/*
-  *	The adapter interface specs all queues to be located in the same
-  *	physically contigous block. The host structure that defines the
-  *	commuication queues will assume they are each a separate physically
-  *	contigous memory region that will support them all being one big
-- *	contigous block. 
-+ *	contigous block.
-  *	There is a command and response queue for each level and direction of
-  *	commuication. These regions are accessed by both the host and adapter.
-  */
-- 
++	while (!iscsi_tcp_segment_done(segment, 0, r)) {
++		struct scatterlist *sg;
++		unsigned int offset, copy;
++		int flags = 0;
 +
- struct aac_queue {
--	u64		 	logical;	/*address we give the adapter */
-+	u64			logical;	/*address we give the adapter */
- 	struct aac_entry	*base;		/*system virtual address */
--	struct aac_qhdr 	headers;       	/*producer,consumer q headers*/
--	u32	 		entries;	/*Number of queue entries */
-+	struct aac_qhdr		headers;	/*producer,consumer q headers*/
-+	u32			entries;	/*Number of queue entries */
- 	wait_queue_head_t	qfull;		/*Event to wait on if q full */
- 	wait_queue_head_t	cmdready;	/*Cmd ready from the adapter */
--                  /* This is only valid for adapter to host command queues. */ 
--	spinlock_t	 	*lock;		/* Spinlock for this queue must take this lock before accessing the lock */
-+		/* This is only valid for adapter to host command queues. */
-+	spinlock_t		*lock;		/* Spinlock for this queue must take this lock before accessing the lock */
- 	spinlock_t		lockdata;	/* Actual lock (used only on one side of the lock) */
--	struct list_head 	cmdq;	   	/* A queue of FIBs which need to be prcessed by the FS thread. This is */
--                                		/* only valid for command queues which receive entries from the adapter. */
-+	struct list_head	cmdq;		/* A queue of FIBs which need to be prcessed by the FS thread. This is */
-+						/* only valid for command queues which receive entries from the adapter. */
- 	u32			numpending;	/* Number of entries on outstanding queue. */
- 	struct aac_dev *	dev;		/* Back pointer to adapter structure */
- };
- 
- /*
-- *	Message queues. The order here is important, see also the 
-+ *	Message queues. The order here is important, see also the
-  *	queue type ordering
-  */
- 
-@@ -559,12 +561,12 @@ struct aac_queue_block
- /*
-  *	SaP1 Message Unit Registers
-  */
-- 
++		r = 0;
++		offset = segment->copied;
++		copy = segment->size - offset;
 +
- struct sa_drawbridge_CSR {
--				/*	Offset 	|  Name */
-+				/*	Offset	|  Name */
- 	__le32	reserved[10];	/*	00h-27h |  Reserved */
- 	u8	LUT_Offset;	/*	28h	|  Lookup Table Offset */
--	u8	reserved1[3];	/* 	29h-2bh	|  Reserved */
-+	u8	reserved1[3];	/*	29h-2bh	|  Reserved */
- 	__le32	LUT_Data;	/*	2ch	|  Looup Table Data */
- 	__le32	reserved2[26];	/*	30h-97h	|  Reserved */
- 	__le16	PRICLEARIRQ;	/*	98h	|  Primary Clear Irq */
-@@ -583,8 +585,8 @@ struct sa_drawbridge_CSR {
- 	__le32	MAILBOX5;	/*	bch	|  Scratchpad 5 */
- 	__le32	MAILBOX6;	/*	c0h	|  Scratchpad 6 */
- 	__le32	MAILBOX7;	/*	c4h	|  Scratchpad 7 */
--	__le32	ROM_Setup_Data;	/*	c8h 	|  Rom Setup and Data */
--	__le32	ROM_Control_Addr;/*	cch 	|  Rom Control and Address */
-+	__le32	ROM_Setup_Data;	/*	c8h	|  Rom Setup and Data */
-+	__le32	ROM_Control_Addr;/*	cch	|  Rom Control and Address */
- 	__le32	reserved3[12];	/*	d0h-ffh	|  reserved */
- 	__le32	LUT[64];	/*    100h-1ffh	|  Lookup Table Entries */
- };
-@@ -597,7 +599,7 @@ struct sa_drawbridge_CSR {
- #define Mailbox5	SaDbCSR.MAILBOX5
- #define Mailbox6	SaDbCSR.MAILBOX6
- #define Mailbox7	SaDbCSR.MAILBOX7
--	
++		if (segment->total_copied + segment->size < segment->total_size)
++			flags |= MSG_MORE;
 +
- #define DoorbellReg_p SaDbCSR.PRISETIRQ
- #define DoorbellReg_s SaDbCSR.SECSETIRQ
- #define DoorbellClrReg_p SaDbCSR.PRICLEARIRQ
-@@ -611,19 +613,19 @@ struct sa_drawbridge_CSR {
- #define DOORBELL_5	0x0020
- #define DOORBELL_6	0x0040
++		/* Use sendpage if we can; else fall back to sendmsg */
++		if (!segment->data) {
++			sg = segment->sg;
++			offset += segment->sg_offset + sg->offset;
++			r = tcp_conn->sendpage(sk, sg_page(sg), offset, copy,
++					       flags);
+ 		} else {
+-			/* ignoring return code since we checked
+-			 * in.copy before */
+-			skb_copy_bits(skb, tcp_conn->in.offset,
+-				&tcp_conn->hdr, tcp_conn->hdr_size);
+-			tcp_conn->in.hdr = &tcp_conn->hdr;
++			struct msghdr msg = { .msg_flags = flags };
++			struct kvec iov = {
++				.iov_base = segment->data + offset,
++				.iov_len = copy
++			};
++
++			r = kernel_sendmsg(sk, &msg, &iov, 1, copy);
+ 		}
+-		tcp_conn->in.offset += tcp_conn->hdr_size;
+-		tcp_conn->in.copy -= tcp_conn->hdr_size;
+-	} else {
+-		int hdr_remains;
+-		int copylen;
  
--	
+-		/*
+-		 * PDU header scattered across SKB's,
+-		 * copying it... This'll happen quite rarely.
+-		 */
++		if (r < 0) {
++			iscsi_tcp_segment_unmap(segment);
++			if (copied || r == -EAGAIN)
++				break;
++			return r;
++		}
++		copied += r;
++	}
++	return copied;
++}
 +
- #define PrintfReady	DOORBELL_5
- #define PrintfDone	DOORBELL_5
--	
++/**
++ * iscsi_tcp_segment_recv - copy data to segment
++ * @tcp_conn: the iSCSI TCP connection
++ * @segment: the buffer to copy to
++ * @ptr: data pointer
++ * @len: amount of data available
++ *
++ * This function copies up to @len bytes to the
++ * given buffer, and returns the number of bytes
++ * consumed, which can actually be less than @len.
++ *
++ * If hash digest is enabled, the function will update the
++ * hash while copying.
++ * Combining these two operations doesn't buy us a lot (yet),
++ * but in the future we could implement combined copy+crc,
++ * just way we do for network layer checksums.
++ */
++static int
++iscsi_tcp_segment_recv(struct iscsi_tcp_conn *tcp_conn,
++		       struct iscsi_segment *segment, const void *ptr,
++		       unsigned int len)
++{
++	unsigned int copy = 0, copied = 0;
 +
- struct sa_registers {
- 	struct sa_drawbridge_CSR	SaDbCSR;			/* 98h - c4h */
- };
--	
++	while (!iscsi_tcp_segment_done(segment, 1, copy)) {
++		if (copied == len) {
++			debug_tcp("iscsi_tcp_segment_recv copied %d bytes\n",
++				  len);
++			break;
++		}
 +
++		copy = min(len - copied, segment->size - segment->copied);
++		debug_tcp("iscsi_tcp_segment_recv copying %d\n", copy);
++		memcpy(segment->data + segment->copied, ptr + copied, copy);
++		copied += copy;
++	}
++	return copied;
++}
  
- #define Sa_MINIPORT_REVISION			1
- 
- #define sa_readw(AEP, CSR)		readl(&((AEP)->regs.sa->CSR))
--#define sa_readl(AEP,  CSR)		readl(&((AEP)->regs.sa->CSR))
-+#define sa_readl(AEP, CSR)		readl(&((AEP)->regs.sa->CSR))
- #define sa_writew(AEP, CSR, value)	writew(value, &((AEP)->regs.sa->CSR))
- #define sa_writel(AEP, CSR, value)	writel(value, &((AEP)->regs.sa->CSR))
- 
-@@ -640,21 +642,21 @@ struct rx_mu_registers {
- 	__le32	IMRx[2];    /*	1310h  | 10h | Inbound Message Registers */
- 	__le32	OMRx[2];    /*	1318h  | 18h | Outbound Message Registers */
- 	__le32	IDR;	    /*	1320h  | 20h | Inbound Doorbell Register */
--	__le32	IISR;	    /*	1324h  | 24h | Inbound Interrupt 
-+	__le32	IISR;	    /*	1324h  | 24h | Inbound Interrupt
- 						Status Register */
--	__le32	IIMR;	    /*	1328h  | 28h | Inbound Interrupt 
--					 	Mask Register */
-+	__le32	IIMR;	    /*	1328h  | 28h | Inbound Interrupt
-+						Mask Register */
- 	__le32	ODR;	    /*	132Ch  | 2Ch | Outbound Doorbell Register */
--	__le32	OISR;	    /*	1330h  | 30h | Outbound Interrupt 
-+	__le32	OISR;	    /*	1330h  | 30h | Outbound Interrupt
- 						Status Register */
--	__le32	OIMR;	    /*	1334h  | 34h | Outbound Interrupt 
-+	__le32	OIMR;	    /*	1334h  | 34h | Outbound Interrupt
- 						Mask Register */
- 	__le32	reserved2;  /*	1338h  | 38h | Reserved */
- 	__le32	reserved3;  /*	133Ch  | 3Ch | Reserved */
- 	__le32	InboundQueue;/*	1340h  | 40h | Inbound Queue Port relative to firmware */
- 	__le32	OutboundQueue;/*1344h  | 44h | Outbound Queue Port relative to firmware */
--			    /* * Must access through ATU Inbound 
--			     	 Translation Window */
-+			    /* * Must access through ATU Inbound
-+				 Translation Window */
- };
+-		if (tcp_conn->in_progress == IN_PROGRESS_WAIT_HEADER)
+-			tcp_conn->in.hdr_offset = 0;
++static inline void
++iscsi_tcp_dgst_header(struct hash_desc *hash, const void *hdr, size_t hdrlen,
++		      unsigned char digest[ISCSI_DIGEST_SIZE])
++{
++	struct scatterlist sg;
  
- struct rx_inbound {
-@@ -710,12 +712,12 @@ struct rkt_registers {
- typedef void (*fib_callback)(void *ctxt, struct fib *fibctx);
+-		hdr_remains = tcp_conn->hdr_size - tcp_conn->in.hdr_offset;
+-		BUG_ON(hdr_remains <= 0);
++	sg_init_one(&sg, hdr, hdrlen);
++	crypto_hash_digest(hash, &sg, hdrlen, digest);
++}
  
- struct aac_fib_context {
--	s16	 		type;		// used for verification of structure	
--	s16	 		size;
-+	s16			type;		// used for verification of structure
-+	s16			size;
- 	u32			unique;		// unique value representing this context
- 	ulong			jiffies;	// used for cleanup - dmb changed to ulong
- 	struct list_head	next;		// used to link context's into a linked list
--	struct semaphore 	wait_sem;	// this is used to wait for the next fib to arrive.
-+	struct semaphore	wait_sem;	// this is used to wait for the next fib to arrive.
- 	int			wait;		// Set to true when thread is in WaitForSingleObject
- 	unsigned long		count;		// total number of FIBs on FibList
- 	struct list_head	fib_list;	// this holds fibs and their attachd hw_fibs
-@@ -734,9 +736,9 @@ struct sense_data {
- 	u8 EOM:1;		/* End Of Medium - reserved for random access devices */
- 	u8 filemark:1;		/* Filemark - reserved for random access devices */
+-		copylen = min(tcp_conn->in.copy, hdr_remains);
+-		skb_copy_bits(skb, tcp_conn->in.offset,
+-			(char*)&tcp_conn->hdr + tcp_conn->in.hdr_offset,
+-			copylen);
++static inline int
++iscsi_tcp_dgst_verify(struct iscsi_tcp_conn *tcp_conn,
++		      struct iscsi_segment *segment)
++{
++	if (!segment->digest_len)
++		return 1;
  
--	u8 information[4];	/* for direct-access devices, contains the unsigned 
--				 * logical block address or residue associated with 
--				 * the sense key 
-+	u8 information[4];	/* for direct-access devices, contains the unsigned
-+				 * logical block address or residue associated with
-+				 * the sense key
- 				 */
- 	u8 add_sense_len;	/* number of additional sense bytes to follow this field */
- 	u8 cmnd_info[4];	/* not used */
-@@ -746,7 +748,7 @@ struct sense_data {
- 	u8 bit_ptr:3;		/* indicates which byte of the CDB or parameter data
- 				 * was in error
- 				 */
--	u8 BPV:1;		/* bit pointer valid (BPV): 1- indicates that 
-+	u8 BPV:1;		/* bit pointer valid (BPV): 1- indicates that
- 				 * the bit_ptr field has valid value
- 				 */
- 	u8 reserved2:2;
-@@ -780,24 +782,24 @@ struct fib {
- 	/*
- 	 *	The Adapter that this I/O is destined for.
- 	 */
--	struct aac_dev 		*dev;
-+	struct aac_dev		*dev;
- 	/*
- 	 *	This is the event the sendfib routine will wait on if the
- 	 *	caller did not pass one and this is synch io.
- 	 */
--	struct semaphore 	event_wait;
-+	struct semaphore	event_wait;
- 	spinlock_t		event_lock;
+-		debug_tcp("PDU gather offset %d bytes %d in.offset %d "
+-		       "in.copy %d\n", tcp_conn->in.hdr_offset, copylen,
+-		       tcp_conn->in.offset, tcp_conn->in.copy);
++	if (memcmp(segment->recv_digest, segment->digest,
++		   segment->digest_len)) {
++		debug_scsi("digest mismatch\n");
++		return 0;
++	}
  
- 	u32			done;	/* gets set to 1 when fib is complete */
--	fib_callback 		callback;
--	void 			*callback_data;
-+	fib_callback		callback;
-+	void			*callback_data;
- 	u32			flags; // u32 dmb was ulong
- 	/*
- 	 *	And for the internal issue/reply queues (we may be able
- 	 *	to merge these two)
- 	 */
- 	struct list_head	fiblink;
--	void 			*data;
-+	void			*data;
- 	struct hw_fib		*hw_fib_va;		/* Actual shared object */
- 	dma_addr_t		hw_fib_pa;		/* physical address of hw_fib*/
- };
-@@ -807,7 +809,7 @@ struct fib {
-  *
-  *	This is returned by the RequestAdapterInfo block
-  */
-- 
+-		tcp_conn->in.offset += copylen;
+-		tcp_conn->in.copy -= copylen;
+-		if (copylen < hdr_remains)  {
+-			tcp_conn->in_progress = IN_PROGRESS_HEADER_GATHER;
+-			tcp_conn->in.hdr_offset += copylen;
+-		        return -EAGAIN;
++	return 1;
++}
 +
- struct aac_adapter_info
- {
- 	__le32	platform;
-@@ -826,7 +828,7 @@ struct aac_adapter_info
- 	__le32	biosrev;
- 	__le32	biosbuild;
- 	__le32	cluster;
--	__le32	clusterchannelmask; 
-+	__le32	clusterchannelmask;
- 	__le32	serial[2];
- 	__le32	battery;
- 	__le32	options;
-@@ -863,9 +865,10 @@ struct aac_supplement_adapter_info
- 	__le32	SupportedOptions2;
- 	__le32	ReservedGrowth[1];
- };
--#define AAC_FEATURE_FALCON	0x00000010
--#define AAC_OPTION_MU_RESET	0x00000001
--#define AAC_OPTION_IGNORE_RESET	0x00000002
-+#define AAC_FEATURE_FALCON	cpu_to_le32(0x00000010)
-+#define AAC_FEATURE_JBOD	cpu_to_le32(0x08000000)
-+#define AAC_OPTION_MU_RESET	cpu_to_le32(0x00000001)
-+#define AAC_OPTION_IGNORE_RESET	cpu_to_le32(0x00000002)
- #define AAC_SIS_VERSION_V3	3
- #define AAC_SIS_SLOT_UNKNOWN	0xFF
- 
-@@ -916,13 +919,13 @@ struct aac_bus_info_response {
- #define AAC_OPT_HOST_TIME_FIB		cpu_to_le32(1<<4)
- #define AAC_OPT_RAID50			cpu_to_le32(1<<5)
- #define AAC_OPT_4GB_WINDOW		cpu_to_le32(1<<6)
--#define AAC_OPT_SCSI_UPGRADEABLE 	cpu_to_le32(1<<7)
-+#define AAC_OPT_SCSI_UPGRADEABLE	cpu_to_le32(1<<7)
- #define AAC_OPT_SOFT_ERR_REPORT		cpu_to_le32(1<<8)
--#define AAC_OPT_SUPPORTED_RECONDITION 	cpu_to_le32(1<<9)
-+#define AAC_OPT_SUPPORTED_RECONDITION	cpu_to_le32(1<<9)
- #define AAC_OPT_SGMAP_HOST64		cpu_to_le32(1<<10)
- #define AAC_OPT_ALARM			cpu_to_le32(1<<11)
- #define AAC_OPT_NONDASD			cpu_to_le32(1<<12)
--#define AAC_OPT_SCSI_MANAGED    	cpu_to_le32(1<<13)
-+#define AAC_OPT_SCSI_MANAGED		cpu_to_le32(1<<13)
- #define AAC_OPT_RAID_SCSI_MODE		cpu_to_le32(1<<14)
- #define AAC_OPT_SUPPLEMENT_ADAPTER_INFO	cpu_to_le32(1<<16)
- #define AAC_OPT_NEW_COMM		cpu_to_le32(1<<17)
-@@ -942,7 +945,7 @@ struct aac_dev
- 
- 	/*
- 	 *	Map for 128 fib objects (64k)
--	 */	
-+	 */
- 	dma_addr_t		hw_fib_pa;
- 	struct hw_fib		*hw_fib_va;
- 	struct hw_fib		*aif_base_va;
-@@ -953,24 +956,24 @@ struct aac_dev
- 
- 	struct fib		*free_fib;
- 	spinlock_t		fib_lock;
--	
++/*
++ * Helper function to set up segment buffer
++ */
++static inline void
++__iscsi_segment_init(struct iscsi_segment *segment, size_t size,
++		     iscsi_segment_done_fn_t *done, struct hash_desc *hash)
++{
++	memset(segment, 0, sizeof(*segment));
++	segment->total_size = size;
++	segment->done = done;
 +
- 	struct aac_queue_block *queues;
- 	/*
- 	 *	The user API will use an IOCTL to register itself to receive
- 	 *	FIBs from the adapter.  The following list is used to keep
- 	 *	track of all the threads that have requested these FIBs.  The
--	 *	mutex is used to synchronize access to all data associated 
-+	 *	mutex is used to synchronize access to all data associated
- 	 *	with the adapter fibs.
- 	 */
- 	struct list_head	fib_list;
- 
- 	struct adapter_ops	a_ops;
- 	unsigned long		fsrev;		/* Main driver's revision number */
--	
++	if (hash) {
++		segment->hash = hash;
++		crypto_hash_init(hash);
++	}
++}
 +
- 	unsigned		base_size;	/* Size of mapped in region */
- 	struct aac_init		*init;		/* Holds initialization info to communicate with adapter */
--	dma_addr_t		init_pa; 	/* Holds physical address of the init struct */
--	
-+	dma_addr_t		init_pa;	/* Holds physical address of the init struct */
++static inline void
++iscsi_segment_init_linear(struct iscsi_segment *segment, void *data,
++			  size_t size, iscsi_segment_done_fn_t *done,
++			  struct hash_desc *hash)
++{
++	__iscsi_segment_init(segment, size, done, hash);
++	segment->data = data;
++	segment->size = size;
++}
 +
- 	struct pci_dev		*pdev;		/* Our PCI interface */
- 	void *			printfbuf;	/* pointer to buffer used for printf's from the adapter */
- 	void *			comm_addr;	/* Base address of Comm area */
-@@ -984,11 +987,11 @@ struct aac_dev
- 	struct fsa_dev_info	*fsa_dev;
- 	struct task_struct	*thread;
- 	int			cardtype;
--	
++static inline int
++iscsi_segment_seek_sg(struct iscsi_segment *segment,
++		      struct scatterlist *sg_list, unsigned int sg_count,
++		      unsigned int offset, size_t size,
++		      iscsi_segment_done_fn_t *done, struct hash_desc *hash)
++{
++	struct scatterlist *sg;
++	unsigned int i;
 +
- 	/*
- 	 *	The following is the device specific extension.
- 	 */
--#if (!defined(AAC_MIN_FOOTPRINT_SIZE))
-+#ifndef AAC_MIN_FOOTPRINT_SIZE
- #	define AAC_MIN_FOOTPRINT_SIZE 8192
- #endif
- 	union
-@@ -1009,7 +1012,9 @@ struct aac_dev
- 	/* These are in adapter info but they are in the io flow so
- 	 * lets break them out so we don't have to do an AND to check them
- 	 */
--	u8			nondasd_support; 
-+	u8			nondasd_support;
-+	u8			jbod;
-+	u8			cache_protected;
- 	u8			dac_support;
- 	u8			raid_scsi_mode;
- 	u8			comm_interface;
-@@ -1066,18 +1071,19 @@ struct aac_dev
- 	(dev)->a_ops.adapter_comm(dev, comm)
++	debug_scsi("iscsi_segment_seek_sg offset %u size %llu\n",
++		  offset, size);
++	__iscsi_segment_init(segment, size, done, hash);
++	for_each_sg(sg_list, sg, sg_count, i) {
++		debug_scsi("sg %d, len %u offset %u\n", i, sg->length,
++			   sg->offset);
++		if (offset < sg->length) {
++			iscsi_tcp_segment_init_sg(segment, sg, offset);
++			return 0;
+ 		}
+-		tcp_conn->in.hdr = &tcp_conn->hdr;
+-		tcp_conn->discontiguous_hdr_cnt++;
+-	        tcp_conn->in_progress = IN_PROGRESS_WAIT_HEADER;
++		offset -= sg->length;
+ 	}
  
- #define FIB_CONTEXT_FLAG_TIMED_OUT		(0x00000001)
-+#define FIB_CONTEXT_FLAG			(0x00000002)
++	return ISCSI_ERR_DATA_OFFSET;
++}
++
++/**
++ * iscsi_tcp_hdr_recv_prep - prep segment for hdr reception
++ * @tcp_conn: iscsi connection to prep for
++ *
++ * This function always passes NULL for the hash argument, because when this
++ * function is called we do not yet know the final size of the header and want
++ * to delay the digest processing until we know that.
++ */
++static void
++iscsi_tcp_hdr_recv_prep(struct iscsi_tcp_conn *tcp_conn)
++{
++	debug_tcp("iscsi_tcp_hdr_recv_prep(%p%s)\n", tcp_conn,
++		  tcp_conn->iscsi_conn->hdrdgst_en ? ", digest enabled" : "");
++	iscsi_segment_init_linear(&tcp_conn->in.segment,
++				tcp_conn->in.hdr_buf, sizeof(struct iscsi_hdr),
++				iscsi_tcp_hdr_recv_done, NULL);
++}
++
++/*
++ * Handle incoming reply to any other type of command
++ */
++static int
++iscsi_tcp_data_recv_done(struct iscsi_tcp_conn *tcp_conn,
++			 struct iscsi_segment *segment)
++{
++	struct iscsi_conn *conn = tcp_conn->iscsi_conn;
++	int rc = 0;
++
++	if (!iscsi_tcp_dgst_verify(tcp_conn, segment))
++		return ISCSI_ERR_DATA_DGST;
++
++	rc = iscsi_complete_pdu(conn, tcp_conn->in.hdr,
++			conn->data, tcp_conn->in.datalen);
++	if (rc)
++		return rc;
++
++	iscsi_tcp_hdr_recv_prep(tcp_conn);
+ 	return 0;
+ }
  
++static void
++iscsi_tcp_data_recv_prep(struct iscsi_tcp_conn *tcp_conn)
++{
++	struct iscsi_conn *conn = tcp_conn->iscsi_conn;
++	struct hash_desc *rx_hash = NULL;
++
++	if (conn->datadgst_en)
++		rx_hash = &tcp_conn->rx_hash;
++
++	iscsi_segment_init_linear(&tcp_conn->in.segment,
++				conn->data, tcp_conn->in.datalen,
++				iscsi_tcp_data_recv_done, rx_hash);
++}
++
  /*
-  *	Define the command values
+  * must be called with session lock
   */
-- 
-+
- #define		Null			0
--#define 	GetAttributes		1
--#define 	SetAttributes		2
--#define 	Lookup			3
--#define 	ReadLink		4
--#define 	Read			5
--#define 	Write			6
-+#define		GetAttributes		1
-+#define		SetAttributes		2
-+#define		Lookup			3
-+#define		ReadLink		4
-+#define		Read			5
-+#define		Write			6
- #define		Create			7
- #define		MakeDirectory		8
- #define		SymbolicLink		9
-@@ -1173,19 +1179,19 @@ struct aac_dev
- 
- struct aac_read
+@@ -184,7 +498,6 @@ iscsi_tcp_cleanup_ctask(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
  {
--	__le32	 	command;
--	__le32 		cid;
--	__le32 		block;
--	__le32 		count;
-+	__le32		command;
-+	__le32		cid;
-+	__le32		block;
-+	__le32		count;
- 	struct sgmap	sg;	// Must be last in struct because it is variable
- };
+ 	struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
+ 	struct iscsi_r2t_info *r2t;
+-	struct scsi_cmnd *sc;
  
- struct aac_read64
- {
--	__le32	 	command;
--	__le16 		cid;
--	__le16 		sector_count;
--	__le32 		block;
-+	__le32		command;
-+	__le16		cid;
-+	__le16		sector_count;
-+	__le32		block;
- 	__le16		pad;
- 	__le16		flags;
- 	struct sgmap64	sg;	// Must be last in struct because it is variable
-@@ -1193,26 +1199,26 @@ struct aac_read64
+ 	/* flush ctask's r2t queues */
+ 	while (__kfifo_get(tcp_ctask->r2tqueue, (void*)&r2t, sizeof(void*))) {
+@@ -193,12 +506,12 @@ iscsi_tcp_cleanup_ctask(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
+ 		debug_scsi("iscsi_tcp_cleanup_ctask pending r2t dropped\n");
+ 	}
  
- struct aac_read_reply
- {
--	__le32	 	status;
--	__le32 		count;
-+	__le32		status;
-+	__le32		count;
- };
+-	sc = ctask->sc;
+-	if (unlikely(!sc))
+-		return;
+-
+-	tcp_ctask->xmstate = XMSTATE_VALUE_IDLE;
+-	tcp_ctask->r2t = NULL;
++	r2t = tcp_ctask->r2t;
++	if (r2t != NULL) {
++		__kfifo_put(tcp_ctask->r2tpool.queue, (void*)&r2t,
++			    sizeof(void*));
++		tcp_ctask->r2t = NULL;
++	}
+ }
  
- struct aac_write
- {
- 	__le32		command;
--	__le32 		cid;
--	__le32 		block;
--	__le32 		count;
--	__le32	 	stable;	// Not used
-+	__le32		cid;
-+	__le32		block;
-+	__le32		count;
-+	__le32		stable;	// Not used
- 	struct sgmap	sg;	// Must be last in struct because it is variable
- };
+ /**
+@@ -217,11 +530,6 @@ iscsi_data_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
+ 	int datasn = be32_to_cpu(rhdr->datasn);
  
- struct aac_write64
- {
--	__le32	 	command;
--	__le16 		cid;
--	__le16 		sector_count;
--	__le32 		block;
-+	__le32		command;
-+	__le16		cid;
-+	__le16		sector_count;
-+	__le32		block;
- 	__le16		pad;
- 	__le16		flags;
- #define	IO_TYPE_WRITE 0x00000000
-@@ -1223,7 +1229,7 @@ struct aac_write64
- struct aac_write_reply
+ 	iscsi_update_cmdsn(session, (struct iscsi_nopin*)rhdr);
+-	/*
+-	 * setup Data-In byte counter (gets decremented..)
+-	 */
+-	ctask->data_count = tcp_conn->in.datalen;
+-
+ 	if (tcp_conn->in.datalen == 0)
+ 		return 0;
+ 
+@@ -242,22 +550,20 @@ iscsi_data_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
+ 	}
+ 
+ 	if (rhdr->flags & ISCSI_FLAG_DATA_STATUS) {
++		sc->result = (DID_OK << 16) | rhdr->cmd_status;
+ 		conn->exp_statsn = be32_to_cpu(rhdr->statsn) + 1;
+-		if (rhdr->flags & ISCSI_FLAG_DATA_UNDERFLOW) {
++		if (rhdr->flags & (ISCSI_FLAG_DATA_UNDERFLOW |
++		                   ISCSI_FLAG_DATA_OVERFLOW)) {
+ 			int res_count = be32_to_cpu(rhdr->residual_count);
+ 
+ 			if (res_count > 0 &&
+-			    res_count <= scsi_bufflen(sc)) {
++			    (rhdr->flags & ISCSI_FLAG_CMD_OVERFLOW ||
++			     res_count <= scsi_bufflen(sc)))
+ 				scsi_set_resid(sc, res_count);
+-				sc->result = (DID_OK << 16) | rhdr->cmd_status;
+-			} else
++			else
+ 				sc->result = (DID_BAD_TARGET << 16) |
+ 					rhdr->cmd_status;
+-		} else if (rhdr->flags & ISCSI_FLAG_DATA_OVERFLOW) {
+-			scsi_set_resid(sc, be32_to_cpu(rhdr->residual_count));
+-			sc->result = (DID_OK << 16) | rhdr->cmd_status;
+-		} else
+-			sc->result = (DID_OK << 16) | rhdr->cmd_status;
++		}
+ 	}
+ 
+ 	conn->datain_pdus_cnt++;
+@@ -281,9 +587,6 @@ iscsi_solicit_data_init(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask,
+ 			struct iscsi_r2t_info *r2t)
  {
- 	__le32		status;
--	__le32 		count;
-+	__le32		count;
- 	__le32		committed;
- };
+ 	struct iscsi_data *hdr;
+-	struct scsi_cmnd *sc = ctask->sc;
+-	int i, sg_count = 0;
+-	struct scatterlist *sg;
  
-@@ -1326,10 +1332,10 @@ struct aac_srb_reply
- #define		SRB_NoDataXfer		 0x0000
- #define		SRB_DisableDisconnect	 0x0004
- #define		SRB_DisableSynchTransfer 0x0008
--#define 	SRB_BypassFrozenQueue	 0x0010
-+#define		SRB_BypassFrozenQueue	 0x0010
- #define		SRB_DisableAutosense	 0x0020
- #define		SRB_DataIn		 0x0040
--#define 	SRB_DataOut		 0x0080
-+#define		SRB_DataOut		 0x0080
+ 	hdr = &r2t->dtask.hdr;
+ 	memset(hdr, 0, sizeof(struct iscsi_data));
+@@ -307,34 +610,6 @@ iscsi_solicit_data_init(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask,
+ 	conn->dataout_pdus_cnt++;
  
- /*
-  * SRB Functions - set in aac_srb->function
-@@ -1352,7 +1358,7 @@ struct aac_srb_reply
- #define	SRBF_RemoveDevice	0x0016
- #define	SRBF_DomainValidation	0x0017
+ 	r2t->sent = 0;
+-
+-	iscsi_buf_init_iov(&r2t->headbuf, (char*)hdr,
+-			   sizeof(struct iscsi_hdr));
+-
+-	sg = scsi_sglist(sc);
+-	r2t->sg = NULL;
+-	for (i = 0; i < scsi_sg_count(sc); i++, sg += 1) {
+-		/* FIXME: prefetch ? */
+-		if (sg_count + sg->length > r2t->data_offset) {
+-			int page_offset;
+-
+-			/* sg page found! */
+-
+-			/* offset within this page */
+-			page_offset = r2t->data_offset - sg_count;
+-
+-			/* fill in this buffer */
+-			iscsi_buf_init_sg(&r2t->sendbuf, sg);
+-			r2t->sendbuf.sg.offset += page_offset;
+-			r2t->sendbuf.sg.length -= page_offset;
+-
+-			/* xmit logic will continue with next one */
+-			r2t->sg = sg + 1;
+-			break;
+-		}
+-		sg_count += sg->length;
+-	}
+-	BUG_ON(r2t->sg == NULL);
+ }
  
--/* 
-+/*
-  * SRB SCSI Status - set in aac_srb->scsi_status
-  */
- #define SRB_STATUS_PENDING                  0x00
-@@ -1511,17 +1517,17 @@ struct aac_get_container_count_resp {
-  */
+ /**
+@@ -366,14 +641,11 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
+ 	}
  
- struct aac_mntent {
--	__le32    		oid;
-+	__le32			oid;
- 	u8			name[16];	/* if applicable */
- 	struct creation_info	create_info;	/* if applicable */
- 	__le32			capacity;
--	__le32			vol;    	/* substrate structure */
--	__le32			obj;	        /* FT_FILESYS, etc. */
--	__le32			state;		/* unready for mounting, 
-+	__le32			vol;		/* substrate structure */
-+	__le32			obj;		/* FT_FILESYS, etc. */
-+	__le32			state;		/* unready for mounting,
- 						   readonly, etc. */
--	union aac_contentinfo	fileinfo;	/* Info specific to content 
-+	union aac_contentinfo	fileinfo;	/* Info specific to content
- 						   manager (eg, filesystem) */
--	__le32			altoid;		/* != oid <==> snapshot or 
-+	__le32			altoid;		/* != oid <==> snapshot or
- 						   broken mirror exists */
- 	__le32			capacityhigh;
- };
-@@ -1538,7 +1544,7 @@ struct aac_query_mount {
+ 	/* fill-in new R2T associated with the task */
+-	spin_lock(&session->lock);
+ 	iscsi_update_cmdsn(session, (struct iscsi_nopin*)rhdr);
  
- struct aac_mount {
- 	__le32		status;
--	__le32	   	type;           /* should be same as that requested */
-+	__le32		type;           /* should be same as that requested */
- 	__le32		count;
- 	struct aac_mntent mnt[1];
- };
-@@ -1608,7 +1614,7 @@ struct aac_delete_disk {
- 	u32	disknum;
- 	u32	cnum;
- };
-- 
-+
- struct fib_ioctl
- {
- 	u32	fibctx;
-@@ -1622,10 +1628,10 @@ struct revision
- 	__le32 version;
- 	__le32 build;
- };
--	
-+
+-	if (!ctask->sc || ctask->mtask ||
+-	     session->state != ISCSI_STATE_LOGGED_IN) {
++	if (!ctask->sc || session->state != ISCSI_STATE_LOGGED_IN) {
+ 		printk(KERN_INFO "iscsi_tcp: dropping R2T itt %d in "
+ 		       "recovery...\n", ctask->itt);
+-		spin_unlock(&session->lock);
+ 		return 0;
+ 	}
  
- /*
-- * 	Ugly - non Linux like ioctl coding for back compat.
-+ *	Ugly - non Linux like ioctl coding for back compat.
-  */
+@@ -384,7 +656,8 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
+ 	r2t->data_length = be32_to_cpu(rhdr->data_length);
+ 	if (r2t->data_length == 0) {
+ 		printk(KERN_ERR "iscsi_tcp: invalid R2T with zero data len\n");
+-		spin_unlock(&session->lock);
++		__kfifo_put(tcp_ctask->r2tpool.queue, (void*)&r2t,
++			    sizeof(void*));
+ 		return ISCSI_ERR_DATALEN;
+ 	}
  
- #define CTL_CODE(function, method) (                 \
-@@ -1633,7 +1639,7 @@ struct revision
- )
+@@ -395,10 +668,11 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
  
- /*
-- *	Define the method codes for how buffers are passed for I/O and FS 
-+ *	Define the method codes for how buffers are passed for I/O and FS
-  *	controls
-  */
+ 	r2t->data_offset = be32_to_cpu(rhdr->data_offset);
+ 	if (r2t->data_offset + r2t->data_length > scsi_bufflen(ctask->sc)) {
+-		spin_unlock(&session->lock);
+ 		printk(KERN_ERR "iscsi_tcp: invalid R2T with data len %u at "
+ 		       "offset %u and total length %d\n", r2t->data_length,
+ 		       r2t->data_offset, scsi_bufflen(ctask->sc));
++		__kfifo_put(tcp_ctask->r2tpool.queue, (void*)&r2t,
++			    sizeof(void*));
+ 		return ISCSI_ERR_DATALEN;
+ 	}
  
-@@ -1644,15 +1650,15 @@ struct revision
-  *	Filesystem ioctls
-  */
+@@ -409,26 +683,55 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
  
--#define FSACTL_SENDFIB                  	CTL_CODE(2050, METHOD_BUFFERED)
--#define FSACTL_SEND_RAW_SRB               	CTL_CODE(2067, METHOD_BUFFERED)
-+#define FSACTL_SENDFIB				CTL_CODE(2050, METHOD_BUFFERED)
-+#define FSACTL_SEND_RAW_SRB			CTL_CODE(2067, METHOD_BUFFERED)
- #define FSACTL_DELETE_DISK			0x163
- #define FSACTL_QUERY_DISK			0x173
- #define FSACTL_OPEN_GET_ADAPTER_FIB		CTL_CODE(2100, METHOD_BUFFERED)
- #define FSACTL_GET_NEXT_ADAPTER_FIB		CTL_CODE(2101, METHOD_BUFFERED)
- #define FSACTL_CLOSE_GET_ADAPTER_FIB		CTL_CODE(2102, METHOD_BUFFERED)
- #define FSACTL_MINIPORT_REV_CHECK               CTL_CODE(2107, METHOD_BUFFERED)
--#define FSACTL_GET_PCI_INFO               	CTL_CODE(2119, METHOD_BUFFERED)
-+#define FSACTL_GET_PCI_INFO			CTL_CODE(2119, METHOD_BUFFERED)
- #define FSACTL_FORCE_DELETE_DISK		CTL_CODE(2120, METHOD_NEITHER)
- #define FSACTL_GET_CONTAINERS			2131
- #define FSACTL_SEND_LARGE_FIB			CTL_CODE(2138, METHOD_BUFFERED)
-@@ -1661,7 +1667,7 @@ struct revision
- struct aac_common
- {
- 	/*
--	 *	If this value is set to 1 then interrupt moderation will occur 
-+	 *	If this value is set to 1 then interrupt moderation will occur
- 	 *	in the base commuication support.
- 	 */
- 	u32 irq_mod;
-@@ -1690,11 +1696,11 @@ extern struct aac_common aac_config;
-  *	The following macro is used when sending and receiving FIBs. It is
-  *	only used for debugging.
-  */
-- 
-+
- #ifdef DBG
- #define	FIB_COUNTER_INCREMENT(counter)		(counter)++
- #else
--#define	FIB_COUNTER_INCREMENT(counter)		
-+#define	FIB_COUNTER_INCREMENT(counter)
- #endif
+ 	tcp_ctask->exp_datasn = r2tsn + 1;
+ 	__kfifo_put(tcp_ctask->r2tqueue, (void*)&r2t, sizeof(void*));
+-	set_bit(XMSTATE_BIT_SOL_HDR_INIT, &tcp_ctask->xmstate);
+-	list_move_tail(&ctask->running, &conn->xmitqueue);
+-
+-	scsi_queue_work(session->host, &conn->xmitwork);
+ 	conn->r2t_pdus_cnt++;
+-	spin_unlock(&session->lock);
  
- /*
-@@ -1726,17 +1732,17 @@ extern struct aac_common aac_config;
-  *
-  *	The adapter reports is present state through the phase.  Only
-  *	a single phase should be ever be set.  Each phase can have multiple
-- *	phase status bits to provide more detailed information about the 
-- *	state of the board.  Care should be taken to ensure that any phase 
-+ *	phase status bits to provide more detailed information about the
-+ *	state of the board.  Care should be taken to ensure that any phase
-  *	status bits that are set when changing the phase are also valid
-  *	for the new phase or be cleared out.  Adapter software (monitor,
-- *	iflash, kernel) is responsible for properly maintining the phase 
-+ *	iflash, kernel) is responsible for properly maintining the phase
-  *	status mailbox when it is running.
-- *											
-- *	MONKER_API Phases							
-  *
-- *	Phases are bit oriented.  It is NOT valid  to have multiple bits set						
-- */					
-+ *	MONKER_API Phases
++	iscsi_requeue_ctask(ctask);
+ 	return 0;
+ }
+ 
++/*
++ * Handle incoming reply to DataIn command
++ */
+ static int
+-iscsi_tcp_hdr_recv(struct iscsi_conn *conn)
++iscsi_tcp_process_data_in(struct iscsi_tcp_conn *tcp_conn,
++			  struct iscsi_segment *segment)
++{
++	struct iscsi_conn *conn = tcp_conn->iscsi_conn;
++	struct iscsi_hdr *hdr = tcp_conn->in.hdr;
++	int rc;
++
++	if (!iscsi_tcp_dgst_verify(tcp_conn, segment))
++		return ISCSI_ERR_DATA_DGST;
++
++	/* check for non-exceptional status */
++	if (hdr->flags & ISCSI_FLAG_DATA_STATUS) {
++		rc = iscsi_complete_pdu(conn, tcp_conn->in.hdr, NULL, 0);
++		if (rc)
++			return rc;
++	}
++
++	iscsi_tcp_hdr_recv_prep(tcp_conn);
++	return 0;
++}
++
++/**
++ * iscsi_tcp_hdr_dissect - process PDU header
++ * @conn: iSCSI connection
++ * @hdr: PDU header
 + *
-+ *	Phases are bit oriented.  It is NOT valid  to have multiple bits set
++ * This function analyzes the header of the PDU received,
++ * and performs several sanity checks. If the PDU is accompanied
++ * by data, the receive buffer is set up to copy the incoming data
++ * to the correct location.
 + */
++static int
++iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
+ {
+ 	int rc = 0, opcode, ahslen;
+-	struct iscsi_hdr *hdr;
+ 	struct iscsi_session *session = conn->session;
+ 	struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
+-	uint32_t cdgst, rdgst = 0, itt;
+-
+-	hdr = tcp_conn->in.hdr;
++	struct iscsi_cmd_task *ctask;
++	uint32_t itt;
+ 
+ 	/* verify PDU length */
+ 	tcp_conn->in.datalen = ntoh24(hdr->dlength);
+@@ -437,78 +740,73 @@ iscsi_tcp_hdr_recv(struct iscsi_conn *conn)
+ 		       tcp_conn->in.datalen, conn->max_recv_dlength);
+ 		return ISCSI_ERR_DATALEN;
+ 	}
+-	tcp_conn->data_copied = 0;
+ 
+-	/* read AHS */
++	/* Additional header segments. So far, we don't
++	 * process additional headers.
++	 */
+ 	ahslen = hdr->hlength << 2;
+-	tcp_conn->in.offset += ahslen;
+-	tcp_conn->in.copy -= ahslen;
+-	if (tcp_conn->in.copy < 0) {
+-		printk(KERN_ERR "iscsi_tcp: can't handle AHS with length "
+-		       "%d bytes\n", ahslen);
+-		return ISCSI_ERR_AHSLEN;
+-	}
+-
+-	/* calculate read padding */
+-	tcp_conn->in.padding = tcp_conn->in.datalen & (ISCSI_PAD_LEN-1);
+-	if (tcp_conn->in.padding) {
+-		tcp_conn->in.padding = ISCSI_PAD_LEN - tcp_conn->in.padding;
+-		debug_scsi("read padding %d bytes\n", tcp_conn->in.padding);
+-	}
+-
+-	if (conn->hdrdgst_en) {
+-		struct scatterlist sg;
+-
+-		sg_init_one(&sg, (u8 *)hdr,
+-			    sizeof(struct iscsi_hdr) + ahslen);
+-		crypto_hash_digest(&tcp_conn->rx_hash, &sg, sg.length,
+-				   (u8 *)&cdgst);
+-		rdgst = *(uint32_t*)((char*)hdr + sizeof(struct iscsi_hdr) +
+-				     ahslen);
+-		if (cdgst != rdgst) {
+-			printk(KERN_ERR "iscsi_tcp: hdrdgst error "
+-			       "recv 0x%x calc 0x%x\n", rdgst, cdgst);
+-			return ISCSI_ERR_HDR_DGST;
+-		}
+-	}
  
- #define	SELF_TEST_FAILED		0x00000004
- #define	MONITOR_PANIC			0x00000020
-@@ -1759,16 +1765,22 @@ extern struct aac_common aac_config;
-  *	For FIB communication, we need all of the following things
-  *	to send back to the user.
-  */
-- 
--#define 	AifCmdEventNotify	1	/* Notify of event */
-+
-+#define		AifCmdEventNotify	1	/* Notify of event */
- #define			AifEnConfigChange	3	/* Adapter configuration change */
- #define			AifEnContainerChange	4	/* Container configuration change */
- #define			AifEnDeviceFailure	5	/* SCSI device failed */
-+#define			AifEnEnclosureManagement 13	/* EM_DRIVE_* */
-+#define				EM_DRIVE_INSERTION	31
-+#define				EM_DRIVE_REMOVAL	32
-+#define			AifEnBatteryEvent	14	/* Change in Battery State */
- #define			AifEnAddContainer	15	/* A new array was created */
- #define			AifEnDeleteContainer	16	/* A container was deleted */
- #define			AifEnExpEvent		23	/* Firmware Event Log */
- #define			AifExeFirmwarePanic	3	/* Firmware Event Panic */
- #define			AifHighPriority		3	/* Highest Priority Event */
-+#define			AifEnAddJBOD		30	/* JBOD created */
-+#define			AifEnDeleteJBOD		31	/* JBOD deleted */
+ 	opcode = hdr->opcode & ISCSI_OPCODE_MASK;
+ 	/* verify itt (itt encoding: age+cid+itt) */
+ 	rc = iscsi_verify_itt(conn, hdr, &itt);
+-	if (rc == ISCSI_ERR_NO_SCSI_CMD) {
+-		tcp_conn->in.datalen = 0; /* force drop */
+-		return 0;
+-	} else if (rc)
++	if (rc)
+ 		return rc;
  
- #define		AifCmdJobProgress	2	/* Progress report */
- #define			AifJobCtrZero	101	/* Array Zero progress */
-@@ -1780,11 +1792,11 @@ extern struct aac_common aac_config;
- #define			AifDenVolumeExtendComplete 201 /* A volume extend completed */
- #define		AifReqJobList		100	/* Gets back complete job list */
- #define		AifReqJobsForCtr	101	/* Gets back jobs for specific container */
--#define		AifReqJobsForScsi	102	/* Gets back jobs for specific SCSI device */ 
--#define		AifReqJobReport		103	/* Gets back a specific job report or list of them */ 
-+#define		AifReqJobsForScsi	102	/* Gets back jobs for specific SCSI device */
-+#define		AifReqJobReport		103	/* Gets back a specific job report or list of them */
- #define		AifReqTerminateJob	104	/* Terminates job */
- #define		AifReqSuspendJob	105	/* Suspends a job */
--#define		AifReqResumeJob		106	/* Resumes a job */ 
-+#define		AifReqResumeJob		106	/* Resumes a job */
- #define		AifReqSendAPIReport	107	/* API generic report requests */
- #define		AifReqAPIJobStart	108	/* Start a job from the API */
- #define		AifReqAPIJobUpdate	109	/* Update a job report from the API */
-@@ -1803,8 +1815,8 @@ struct aac_aifcmd {
- };
+-	debug_tcp("opcode 0x%x offset %d copy %d ahslen %d datalen %d\n",
+-		  opcode, tcp_conn->in.offset, tcp_conn->in.copy,
+-		  ahslen, tcp_conn->in.datalen);
++	debug_tcp("opcode 0x%x ahslen %d datalen %d\n",
++		  opcode, ahslen, tcp_conn->in.datalen);
  
- /**
-- * 	Convert capacity to cylinders
-- *  	accounting for the fact capacity could be a 64 bit value
-+ *	Convert capacity to cylinders
-+ *	accounting for the fact capacity could be a 64 bit value
-  *
-  */
- static inline unsigned int cap_to_cyls(sector_t capacity, unsigned divisor)
-@@ -1861,6 +1873,7 @@ int aac_probe_container(struct aac_dev *dev, int cid);
- int _aac_rx_init(struct aac_dev *dev);
- int aac_rx_select_comm(struct aac_dev *dev, int comm);
- int aac_rx_deliver_producer(struct fib * fib);
-+char * get_container_type(unsigned type);
- extern int numacb;
- extern int acbsize;
- extern char aac_driver_version[];
-diff --git a/drivers/scsi/aacraid/commctrl.c b/drivers/scsi/aacraid/commctrl.c
-index 1e6d7a9..851a7e5 100644
---- a/drivers/scsi/aacraid/commctrl.c
-+++ b/drivers/scsi/aacraid/commctrl.c
-@@ -48,13 +48,13 @@
-  *	ioctl_send_fib	-	send a FIB from userspace
-  *	@dev:	adapter is being processed
-  *	@arg:	arguments to the ioctl call
-- *	
-+ *
-  *	This routine sends a fib to the adapter on behalf of a user level
-  *	program.
-  */
- # define AAC_DEBUG_PREAMBLE	KERN_INFO
- # define AAC_DEBUG_POSTAMBLE
-- 
+ 	switch(opcode) {
+ 	case ISCSI_OP_SCSI_DATA_IN:
+-		tcp_conn->in.ctask = session->cmds[itt];
+-		rc = iscsi_data_rsp(conn, tcp_conn->in.ctask);
++		ctask = session->cmds[itt];
++		spin_lock(&conn->session->lock);
++		rc = iscsi_data_rsp(conn, ctask);
++		spin_unlock(&conn->session->lock);
+ 		if (rc)
+ 			return rc;
++		if (tcp_conn->in.datalen) {
++			struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
++			struct hash_desc *rx_hash = NULL;
 +
- static int ioctl_send_fib(struct aac_dev * dev, void __user *arg)
- {
- 	struct hw_fib * kfib;
-@@ -71,7 +71,7 @@ static int ioctl_send_fib(struct aac_dev * dev, void __user *arg)
- 	if(fibptr == NULL) {
- 		return -ENOMEM;
- 	}
--		
++			/*
++			 * Setup copy of Data-In into the Scsi_Cmnd
++			 * Scatterlist case:
++			 * We set up the iscsi_segment to point to the next
++			 * scatterlist entry to copy to. As we go along,
++			 * we move on to the next scatterlist entry and
++			 * update the digest per-entry.
++			 */
++			if (conn->datadgst_en)
++				rx_hash = &tcp_conn->rx_hash;
 +
- 	kfib = fibptr->hw_fib_va;
- 	/*
- 	 *	First copy in the header so that we can check the size field.
-@@ -109,7 +109,7 @@ static int ioctl_send_fib(struct aac_dev * dev, void __user *arg)
- 	if (kfib->header.Command == cpu_to_le16(TakeABreakPt)) {
- 		aac_adapter_interrupt(dev);
- 		/*
--		 * Since we didn't really send a fib, zero out the state to allow 
-+		 * Since we didn't really send a fib, zero out the state to allow
- 		 * cleanup code not to assert.
- 		 */
- 		kfib->header.XferState = 0;
-@@ -169,7 +169,7 @@ static int open_getadapter_fib(struct aac_dev * dev, void __user *arg)
- 
- 		fibctx->type = FSAFS_NTC_GET_ADAPTER_FIB_CONTEXT;
- 		fibctx->size = sizeof(struct aac_fib_context);
-- 		/*
-+		/*
- 		 *	Yes yes, I know this could be an index, but we have a
- 		 * better guarantee of uniqueness for the locked loop below.
- 		 * Without the aid of a persistent history, this also helps
-@@ -189,7 +189,7 @@ static int open_getadapter_fib(struct aac_dev * dev, void __user *arg)
- 		INIT_LIST_HEAD(&fibctx->fib_list);
- 		fibctx->jiffies = jiffies/HZ;
- 		/*
--		 *	Now add this context onto the adapter's 
-+		 *	Now add this context onto the adapter's
- 		 *	AdapterFibContext list.
++			debug_tcp("iscsi_tcp_begin_data_in(%p, offset=%d, "
++				  "datalen=%d)\n", tcp_conn,
++				  tcp_ctask->data_offset,
++				  tcp_conn->in.datalen);
++			return iscsi_segment_seek_sg(&tcp_conn->in.segment,
++						     scsi_sglist(ctask->sc),
++						     scsi_sg_count(ctask->sc),
++						     tcp_ctask->data_offset,
++						     tcp_conn->in.datalen,
++						     iscsi_tcp_process_data_in,
++						     rx_hash);
++		}
+ 		/* fall through */
+ 	case ISCSI_OP_SCSI_CMD_RSP:
+-		tcp_conn->in.ctask = session->cmds[itt];
+-		if (tcp_conn->in.datalen)
+-			goto copy_hdr;
+-
+-		spin_lock(&session->lock);
+-		rc = __iscsi_complete_pdu(conn, hdr, NULL, 0);
+-		spin_unlock(&session->lock);
++		if (tcp_conn->in.datalen) {
++			iscsi_tcp_data_recv_prep(tcp_conn);
++			return 0;
++		}
++		rc = iscsi_complete_pdu(conn, hdr, NULL, 0);
+ 		break;
+ 	case ISCSI_OP_R2T:
+-		tcp_conn->in.ctask = session->cmds[itt];
++		ctask = session->cmds[itt];
+ 		if (ahslen)
+ 			rc = ISCSI_ERR_AHSLEN;
+-		else if (tcp_conn->in.ctask->sc->sc_data_direction ==
+-								DMA_TO_DEVICE)
+-			rc = iscsi_r2t_rsp(conn, tcp_conn->in.ctask);
+-		else
++		else if (ctask->sc->sc_data_direction == DMA_TO_DEVICE) {
++			spin_lock(&session->lock);
++			rc = iscsi_r2t_rsp(conn, ctask);
++			spin_unlock(&session->lock);
++		} else
+ 			rc = ISCSI_ERR_PROTO;
+ 		break;
+ 	case ISCSI_OP_LOGIN_RSP:
+@@ -520,8 +818,7 @@ iscsi_tcp_hdr_recv(struct iscsi_conn *conn)
+ 		 * than 8K, but there are no targets that currently do this.
+ 		 * For now we fail until we find a vendor that needs it
  		 */
- 		spin_lock_irqsave(&dev->fib_lock, flags);
-@@ -207,12 +207,12 @@ static int open_getadapter_fib(struct aac_dev * dev, void __user *arg)
+-		if (ISCSI_DEF_MAX_RECV_SEG_LEN <
+-		    tcp_conn->in.datalen) {
++		if (ISCSI_DEF_MAX_RECV_SEG_LEN < tcp_conn->in.datalen) {
+ 			printk(KERN_ERR "iscsi_tcp: received buffer of len %u "
+ 			      "but conn buffer is only %u (opcode %0x)\n",
+ 			      tcp_conn->in.datalen,
+@@ -530,8 +827,13 @@ iscsi_tcp_hdr_recv(struct iscsi_conn *conn)
+ 			break;
  		}
- 		list_add_tail(&fibctx->next, &dev->fib_list);
- 		spin_unlock_irqrestore(&dev->fib_lock, flags);
--		if (copy_to_user(arg,  &fibctx->unique, 
-+		if (copy_to_user(arg, &fibctx->unique,
- 						sizeof(fibctx->unique))) {
- 			status = -EFAULT;
- 		} else {
- 			status = 0;
--		}	
+ 
+-		if (tcp_conn->in.datalen)
+-			goto copy_hdr;
++		/* If there's data coming in with the response,
++		 * receive it to the connection's buffer.
++		 */
++		if (tcp_conn->in.datalen) {
++			iscsi_tcp_data_recv_prep(tcp_conn);
++			return 0;
 +		}
+ 	/* fall through */
+ 	case ISCSI_OP_LOGOUT_RSP:
+ 	case ISCSI_OP_NOOP_IN:
+@@ -543,461 +845,161 @@ iscsi_tcp_hdr_recv(struct iscsi_conn *conn)
+ 		break;
  	}
- 	return status;
+ 
+-	return rc;
+-
+-copy_hdr:
+-	/*
+-	 * if we did zero copy for the header but we will need multiple
+-	 * skbs to complete the command then we have to copy the header
+-	 * for later use
+-	 */
+-	if (tcp_conn->in.zero_copy_hdr && tcp_conn->in.copy <=
+-	   (tcp_conn->in.datalen + tcp_conn->in.padding +
+-	    (conn->datadgst_en ? 4 : 0))) {
+-		debug_tcp("Copying header for later use. in.copy %d in.datalen"
+-			  " %d\n", tcp_conn->in.copy, tcp_conn->in.datalen);
+-		memcpy(&tcp_conn->hdr, tcp_conn->in.hdr,
+-		       sizeof(struct iscsi_hdr));
+-		tcp_conn->in.hdr = &tcp_conn->hdr;
+-		tcp_conn->in.zero_copy_hdr = 0;
+-	}
+-	return 0;
+-}
+-
+-/**
+- * iscsi_ctask_copy - copy skb bits to the destanation cmd task
+- * @conn: iscsi tcp connection
+- * @ctask: scsi command task
+- * @buf: buffer to copy to
+- * @buf_size: size of buffer
+- * @offset: offset within the buffer
+- *
+- * Notes:
+- *	The function calls skb_copy_bits() and updates per-connection and
+- *	per-cmd byte counters.
+- *
+- *	Read counters (in bytes):
+- *
+- *	conn->in.offset		offset within in progress SKB
+- *	conn->in.copy		left to copy from in progress SKB
+- *				including padding
+- *	conn->in.copied		copied already from in progress SKB
+- *	conn->data_copied	copied already from in progress buffer
+- *	ctask->sent		total bytes sent up to the MidLayer
+- *	ctask->data_count	left to copy from in progress Data-In
+- *	buf_left		left to copy from in progress buffer
+- **/
+-static inline int
+-iscsi_ctask_copy(struct iscsi_tcp_conn *tcp_conn, struct iscsi_cmd_task *ctask,
+-		void *buf, int buf_size, int offset)
+-{
+-	struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
+-	int buf_left = buf_size - (tcp_conn->data_copied + offset);
+-	unsigned size = min(tcp_conn->in.copy, buf_left);
+-	int rc;
+-
+-	size = min(size, ctask->data_count);
+-
+-	debug_tcp("ctask_copy %d bytes at offset %d copied %d\n",
+-	       size, tcp_conn->in.offset, tcp_conn->in.copied);
+-
+-	BUG_ON(size <= 0);
+-	BUG_ON(tcp_ctask->sent + size > scsi_bufflen(ctask->sc));
+-
+-	rc = skb_copy_bits(tcp_conn->in.skb, tcp_conn->in.offset,
+-			   (char*)buf + (offset + tcp_conn->data_copied), size);
+-	/* must fit into skb->len */
+-	BUG_ON(rc);
+-
+-	tcp_conn->in.offset += size;
+-	tcp_conn->in.copy -= size;
+-	tcp_conn->in.copied += size;
+-	tcp_conn->data_copied += size;
+-	tcp_ctask->sent += size;
+-	ctask->data_count -= size;
+-
+-	BUG_ON(tcp_conn->in.copy < 0);
+-	BUG_ON(ctask->data_count < 0);
+-
+-	if (buf_size != (tcp_conn->data_copied + offset)) {
+-		if (!ctask->data_count) {
+-			BUG_ON(buf_size - tcp_conn->data_copied < 0);
+-			/* done with this PDU */
+-			return buf_size - tcp_conn->data_copied;
+-		}
+-		return -EAGAIN;
++	if (rc == 0) {
++		/* Anything that comes with data should have
++		 * been handled above. */
++		if (tcp_conn->in.datalen)
++			return ISCSI_ERR_PROTO;
++		iscsi_tcp_hdr_recv_prep(tcp_conn);
+ 	}
+ 
+-	/* done with this buffer or with both - PDU and buffer */
+-	tcp_conn->data_copied = 0;
+-	return 0;
++	return rc;
  }
-@@ -221,8 +221,8 @@ static int open_getadapter_fib(struct aac_dev * dev, void __user *arg)
-  *	next_getadapter_fib	-	get the next fib
-  *	@dev: adapter to use
-  *	@arg: ioctl argument
-- *	
-- * 	This routine will get the next Fib, if available, from the AdapterFibContext
-+ *
-+ *	This routine will get the next Fib, if available, from the AdapterFibContext
-  *	passed in from the user.
-  */
  
-@@ -234,7 +234,7 @@ static int next_getadapter_fib(struct aac_dev * dev, void __user *arg)
- 	int status;
- 	struct list_head * entry;
- 	unsigned long flags;
--	
+ /**
+- * iscsi_tcp_copy - copy skb bits to the destanation buffer
+- * @conn: iscsi tcp connection
++ * iscsi_tcp_hdr_recv_done - process PDU header
+  *
+- * Notes:
+- *	The function calls skb_copy_bits() and updates per-connection
+- *	byte counters.
+- **/
+-static inline int
+-iscsi_tcp_copy(struct iscsi_conn *conn, int buf_size)
+-{
+-	struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
+-	int buf_left = buf_size - tcp_conn->data_copied;
+-	int size = min(tcp_conn->in.copy, buf_left);
+-	int rc;
+-
+-	debug_tcp("tcp_copy %d bytes at offset %d copied %d\n",
+-	       size, tcp_conn->in.offset, tcp_conn->data_copied);
+-	BUG_ON(size <= 0);
+-
+-	rc = skb_copy_bits(tcp_conn->in.skb, tcp_conn->in.offset,
+-			   (char*)conn->data + tcp_conn->data_copied, size);
+-	BUG_ON(rc);
+-
+-	tcp_conn->in.offset += size;
+-	tcp_conn->in.copy -= size;
+-	tcp_conn->in.copied += size;
+-	tcp_conn->data_copied += size;
+-
+-	if (buf_size != tcp_conn->data_copied)
+-		return -EAGAIN;
+-
+-	return 0;
+-}
+-
+-static inline void
+-partial_sg_digest_update(struct hash_desc *desc, struct scatterlist *sg,
+-			 int offset, int length)
+-{
+-	struct scatterlist temp;
+-
+-	sg_init_table(&temp, 1);
+-	sg_set_page(&temp, sg_page(sg), length, offset);
+-	crypto_hash_update(desc, &temp, length);
+-}
+-
+-static void
+-iscsi_recv_digest_update(struct iscsi_tcp_conn *tcp_conn, char* buf, int len)
+-{
+-	struct scatterlist tmp;
+-
+-	sg_init_one(&tmp, buf, len);
+-	crypto_hash_update(&tcp_conn->rx_hash, &tmp, len);
+-}
+-
+-static int iscsi_scsi_data_in(struct iscsi_conn *conn)
++ * This is the callback invoked when the PDU header has
++ * been received. If the header is followed by additional
++ * header segments, we go back for more data.
++ */
++static int
++iscsi_tcp_hdr_recv_done(struct iscsi_tcp_conn *tcp_conn,
++			struct iscsi_segment *segment)
+ {
+-	struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
+-	struct iscsi_cmd_task *ctask = tcp_conn->in.ctask;
+-	struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
+-	struct scsi_cmnd *sc = ctask->sc;
+-	struct scatterlist *sg;
+-	int i, offset, rc = 0;
+-
+-	BUG_ON((void*)ctask != sc->SCp.ptr);
+-
+-	offset = tcp_ctask->data_offset;
+-	sg = scsi_sglist(sc);
+-
+-	if (tcp_ctask->data_offset)
+-		for (i = 0; i < tcp_ctask->sg_count; i++)
+-			offset -= sg[i].length;
+-	/* we've passed through partial sg*/
+-	if (offset < 0)
+-		offset = 0;
+-
+-	for (i = tcp_ctask->sg_count; i < scsi_sg_count(sc); i++) {
+-		char *dest;
+-
+-		dest = kmap_atomic(sg_page(&sg[i]), KM_SOFTIRQ0);
+-		rc = iscsi_ctask_copy(tcp_conn, ctask, dest + sg[i].offset,
+-				      sg[i].length, offset);
+-		kunmap_atomic(dest, KM_SOFTIRQ0);
+-		if (rc == -EAGAIN)
+-			/* continue with the next SKB/PDU */
+-			return rc;
+-		if (!rc) {
+-			if (conn->datadgst_en) {
+-				if (!offset)
+-					crypto_hash_update(
+-							&tcp_conn->rx_hash,
+-							&sg[i], sg[i].length);
+-				else
+-					partial_sg_digest_update(
+-							&tcp_conn->rx_hash,
+-							&sg[i],
+-							sg[i].offset + offset,
+-							sg[i].length - offset);
+-			}
+-			offset = 0;
+-			tcp_ctask->sg_count++;
+-		}
+-
+-		if (!ctask->data_count) {
+-			if (rc && conn->datadgst_en)
+-				/*
+-				 * data-in is complete, but buffer not...
+-				 */
+-				partial_sg_digest_update(&tcp_conn->rx_hash,
+-							 &sg[i],
+-							 sg[i].offset,
+-							 sg[i].length-rc);
+-			rc = 0;
+-			break;
+-		}
+-
+-		if (!tcp_conn->in.copy)
+-			return -EAGAIN;
+-	}
+-	BUG_ON(ctask->data_count);
++	struct iscsi_conn *conn = tcp_conn->iscsi_conn;
++	struct iscsi_hdr *hdr;
+ 
+-	/* check for non-exceptional status */
+-	if (tcp_conn->in.hdr->flags & ISCSI_FLAG_DATA_STATUS) {
+-		debug_scsi("done [sc %lx res %d itt 0x%x flags 0x%x]\n",
+-			   (long)sc, sc->result, ctask->itt,
+-			   tcp_conn->in.hdr->flags);
+-		spin_lock(&conn->session->lock);
+-		__iscsi_complete_pdu(conn, tcp_conn->in.hdr, NULL, 0);
+-		spin_unlock(&conn->session->lock);
++	/* Check if there are additional header segments
++	 * *prior* to computing the digest, because we
++	 * may need to go back to the caller for more.
++	 */
++	hdr = (struct iscsi_hdr *) tcp_conn->in.hdr_buf;
++	if (segment->copied == sizeof(struct iscsi_hdr) && hdr->hlength) {
++		/* Bump the header length - the caller will
++		 * just loop around and get the AHS for us, and
++		 * call again. */
++		unsigned int ahslen = hdr->hlength << 2;
 +
- 	if(copy_from_user((void *)&f, arg, sizeof(struct fib_ioctl)))
- 		return -EFAULT;
- 	/*
-@@ -243,6 +243,7 @@ static int next_getadapter_fib(struct aac_dev * dev, void __user *arg)
- 	 *	Search the list of AdapterFibContext addresses on the adapter
- 	 *	to be sure this is a valid address
- 	 */
-+	spin_lock_irqsave(&dev->fib_lock, flags);
- 	entry = dev->fib_list.next;
- 	fibctx = NULL;
++		/* Make sure we don't overflow */
++		if (sizeof(*hdr) + ahslen > sizeof(tcp_conn->in.hdr_buf))
++			return ISCSI_ERR_AHSLEN;
++
++		segment->total_size += ahslen;
++		segment->size += ahslen;
++		return 0;
+ 	}
  
-@@ -251,37 +252,37 @@ static int next_getadapter_fib(struct aac_dev * dev, void __user *arg)
- 		/*
- 		 *	Extract the AdapterFibContext from the Input parameters.
- 		 */
--		if (fibctx->unique == f.fibctx) {   /* We found a winner */
-+		if (fibctx->unique == f.fibctx) { /* We found a winner */
- 			break;
+-	return rc;
+-}
+-
+-static int
+-iscsi_data_recv(struct iscsi_conn *conn)
+-{
+-	struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
+-	int rc = 0, opcode;
+-
+-	opcode = tcp_conn->in.hdr->opcode & ISCSI_OPCODE_MASK;
+-	switch (opcode) {
+-	case ISCSI_OP_SCSI_DATA_IN:
+-		rc = iscsi_scsi_data_in(conn);
+-		break;
+-	case ISCSI_OP_SCSI_CMD_RSP:
+-	case ISCSI_OP_TEXT_RSP:
+-	case ISCSI_OP_LOGIN_RSP:
+-	case ISCSI_OP_ASYNC_EVENT:
+-	case ISCSI_OP_REJECT:
+-		/*
+-		 * Collect data segment to the connection's data
+-		 * placeholder
+-		 */
+-		if (iscsi_tcp_copy(conn, tcp_conn->in.datalen)) {
+-			rc = -EAGAIN;
+-			goto exit;
++	/* We're done processing the header. See if we're doing
++	 * header digests; if so, set up the recv_digest buffer
++	 * and go back for more. */
++	if (conn->hdrdgst_en) {
++		if (segment->digest_len == 0) {
++			iscsi_tcp_segment_splice_digest(segment,
++							segment->recv_digest);
++			return 0;
  		}
- 		entry = entry->next;
- 		fibctx = NULL;
- 	}
- 	if (!fibctx) {
-+		spin_unlock_irqrestore(&dev->fib_lock, flags);
- 		dprintk ((KERN_INFO "Fib Context not found\n"));
- 		return -EINVAL;
- 	}
++		iscsi_tcp_dgst_header(&tcp_conn->rx_hash, hdr,
++				      segment->total_copied - ISCSI_DIGEST_SIZE,
++				      segment->digest);
  
- 	if((fibctx->type != FSAFS_NTC_GET_ADAPTER_FIB_CONTEXT) ||
- 		 (fibctx->size != sizeof(struct aac_fib_context))) {
-+		spin_unlock_irqrestore(&dev->fib_lock, flags);
- 		dprintk ((KERN_INFO "Fib Context corrupt?\n"));
- 		return -EINVAL;
+-		rc = iscsi_complete_pdu(conn, tcp_conn->in.hdr, conn->data,
+-					tcp_conn->in.datalen);
+-		if (!rc && conn->datadgst_en && opcode != ISCSI_OP_LOGIN_RSP)
+-			iscsi_recv_digest_update(tcp_conn, conn->data,
+-			  			tcp_conn->in.datalen);
+-		break;
+-	default:
+-		BUG_ON(1);
++		if (!iscsi_tcp_dgst_verify(tcp_conn, segment))
++			return ISCSI_ERR_HDR_DGST;
  	}
- 	status = 0;
--	spin_lock_irqsave(&dev->fib_lock, flags);
- 	/*
- 	 *	If there are no fibs to send back, then either wait or return
- 	 *	-EAGAIN
- 	 */
- return_fib:
- 	if (!list_empty(&fibctx->fib_list)) {
--		struct list_head * entry;
- 		/*
- 		 *	Pull the next fib from the fibs
- 		 */
- 		entry = fibctx->fib_list.next;
- 		list_del(entry);
--		
+-exit:
+-	return rc;
 +
- 		fib = list_entry(entry, struct fib, fiblink);
- 		fibctx->count--;
- 		spin_unlock_irqrestore(&dev->fib_lock, flags);
-@@ -289,7 +290,7 @@ return_fib:
- 			kfree(fib->hw_fib_va);
- 			kfree(fib);
- 			return -EFAULT;
--		}	
-+		}
- 		/*
- 		 *	Free the space occupied by this copy of the fib.
- 		 */
-@@ -318,7 +319,7 @@ return_fib:
- 			}
- 		} else {
- 			status = -EAGAIN;
--		}	
-+		}
- 	}
- 	fibctx->jiffies = jiffies/HZ;
- 	return status;
-@@ -327,7 +328,9 @@ return_fib:
- int aac_close_fib_context(struct aac_dev * dev, struct aac_fib_context * fibctx)
- {
- 	struct fib *fib;
-+	unsigned long flags;
++	tcp_conn->in.hdr = hdr;
++	return iscsi_tcp_hdr_dissect(conn, hdr);
+ }
  
-+	spin_lock_irqsave(&dev->fib_lock, flags);
- 	/*
- 	 *	First free any FIBs that have not been consumed.
- 	 */
-@@ -350,6 +353,7 @@ int aac_close_fib_context(struct aac_dev * dev, struct aac_fib_context * fibctx)
- 	 *	Remove the Context from the AdapterFibContext List
- 	 */
- 	list_del(&fibctx->next);
-+	spin_unlock_irqrestore(&dev->fib_lock, flags);
- 	/*
- 	 *	Invalidate context
- 	 */
-@@ -368,7 +372,7 @@ int aac_close_fib_context(struct aac_dev * dev, struct aac_fib_context * fibctx)
-  *
-  *	This routine will close down the fibctx passed in from the user.
-  */
-- 
-+
- static int close_getadapter_fib(struct aac_dev * dev, void __user *arg)
+ /**
+- * iscsi_tcp_data_recv - TCP receive in sendfile fashion
++ * iscsi_tcp_recv - TCP receive in sendfile fashion
+  * @rd_desc: read descriptor
+  * @skb: socket buffer
+  * @offset: offset in skb
+  * @len: skb->len - offset
+  **/
+ static int
+-iscsi_tcp_data_recv(read_descriptor_t *rd_desc, struct sk_buff *skb,
+-		unsigned int offset, size_t len)
++iscsi_tcp_recv(read_descriptor_t *rd_desc, struct sk_buff *skb,
++	       unsigned int offset, size_t len)
  {
- 	struct aac_fib_context *fibctx;
-@@ -415,8 +419,8 @@ static int close_getadapter_fib(struct aac_dev * dev, void __user *arg)
-  *	@arg: ioctl arguments
-  *
-  *	This routine returns the driver version.
-- *      Under Linux, there have been no version incompatibilities, so this is 
-- *      simple!
-+ *	Under Linux, there have been no version incompatibilities, so this is
-+ *	simple!
-  */
+-	int rc;
+ 	struct iscsi_conn *conn = rd_desc->arg.data;
+ 	struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
+-	int processed;
+-	char pad[ISCSI_PAD_LEN];
+-	struct scatterlist sg;
+-
+-	/*
+-	 * Save current SKB and its offset in the corresponding
+-	 * connection context.
+-	 */
+-	tcp_conn->in.copy = skb->len - offset;
+-	tcp_conn->in.offset = offset;
+-	tcp_conn->in.skb = skb;
+-	tcp_conn->in.len = tcp_conn->in.copy;
+-	BUG_ON(tcp_conn->in.copy <= 0);
+-	debug_tcp("in %d bytes\n", tcp_conn->in.copy);
++	struct iscsi_segment *segment = &tcp_conn->in.segment;
++	struct skb_seq_state seq;
++	unsigned int consumed = 0;
++	int rc = 0;
  
- static int check_revision(struct aac_dev *dev, void __user *arg)
-@@ -426,12 +430,12 @@ static int check_revision(struct aac_dev *dev, void __user *arg)
- 	u32 version;
+-more:
+-	tcp_conn->in.copied = 0;
+-	rc = 0;
++	debug_tcp("in %d bytes\n", skb->len - offset);
  
- 	response.compat = 1;
--	version = (simple_strtol(driver_version, 
-+	version = (simple_strtol(driver_version,
- 				&driver_version, 10) << 24) | 0x00000400;
- 	version += simple_strtol(driver_version + 1, &driver_version, 10) << 16;
- 	version += simple_strtol(driver_version + 1, NULL, 10);
- 	response.version = cpu_to_le32(version);
--#	if (defined(AAC_DRIVER_BUILD))
-+#	ifdef AAC_DRIVER_BUILD
- 		response.build = cpu_to_le32(AAC_DRIVER_BUILD);
- #	else
- 		response.build = cpu_to_le32(9999);
-@@ -464,7 +468,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
- 	u32 data_dir;
- 	void __user *sg_user[32];
- 	void *sg_list[32];
--	u32   sg_indx = 0;
-+	u32 sg_indx = 0;
- 	u32 byte_count = 0;
- 	u32 actual_fibsize64, actual_fibsize = 0;
- 	int i;
-@@ -475,7 +479,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
- 		return -EBUSY;
- 	}
- 	if (!capable(CAP_SYS_ADMIN)){
--		dprintk((KERN_DEBUG"aacraid: No permission to send raw srb\n")); 
-+		dprintk((KERN_DEBUG"aacraid: No permission to send raw srb\n"));
- 		return -EPERM;
+ 	if (unlikely(conn->suspend_rx)) {
+ 		debug_tcp("conn %d Rx suspended!\n", conn->id);
+ 		return 0;
  	}
- 	/*
-@@ -490,7 +494,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
  
- 	memset(sg_list, 0, sizeof(sg_list)); /* cleanup may take issue */
- 	if(copy_from_user(&fibsize, &user_srb->count,sizeof(u32))){
--		dprintk((KERN_DEBUG"aacraid: Could not copy data size from user\n")); 
-+		dprintk((KERN_DEBUG"aacraid: Could not copy data size from user\n"));
- 		rcode = -EFAULT;
- 		goto cleanup;
- 	}
-@@ -507,7 +511,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
- 		goto cleanup;
- 	}
- 	if(copy_from_user(user_srbcmd, user_srb,fibsize)){
--		dprintk((KERN_DEBUG"aacraid: Could not copy srb from user\n")); 
-+		dprintk((KERN_DEBUG"aacraid: Could not copy srb from user\n"));
- 		rcode = -EFAULT;
- 		goto cleanup;
- 	}
-@@ -518,15 +522,15 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
- 	// Fix up srb for endian and force some values
+-	if (tcp_conn->in_progress == IN_PROGRESS_WAIT_HEADER ||
+-	    tcp_conn->in_progress == IN_PROGRESS_HEADER_GATHER) {
+-		rc = iscsi_hdr_extract(tcp_conn);
+-		if (rc) {
+-		       if (rc == -EAGAIN)
+-				goto nomore;
+-		       else {
+-				iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
+-				return 0;
+-		       }
+-		}
++	skb_prepare_seq_read(skb, offset, skb->len, &seq);
++	while (1) {
++		unsigned int avail;
++		const u8 *ptr;
  
- 	srbcmd->function = cpu_to_le32(SRBF_ExecuteScsi);	// Force this
--	srbcmd->channel  = cpu_to_le32(user_srbcmd->channel);
-+	srbcmd->channel	 = cpu_to_le32(user_srbcmd->channel);
- 	srbcmd->id	 = cpu_to_le32(user_srbcmd->id);
--	srbcmd->lun      = cpu_to_le32(user_srbcmd->lun);
--	srbcmd->timeout  = cpu_to_le32(user_srbcmd->timeout);
--	srbcmd->flags    = cpu_to_le32(flags);
-+	srbcmd->lun	 = cpu_to_le32(user_srbcmd->lun);
-+	srbcmd->timeout	 = cpu_to_le32(user_srbcmd->timeout);
-+	srbcmd->flags	 = cpu_to_le32(flags);
- 	srbcmd->retry_limit = 0; // Obsolete parameter
- 	srbcmd->cdb_size = cpu_to_le32(user_srbcmd->cdb_size);
- 	memcpy(srbcmd->cdb, user_srbcmd->cdb, sizeof(srbcmd->cdb));
--	
+-		/*
+-		 * Verify and process incoming PDU header.
+-		 */
+-		rc = iscsi_tcp_hdr_recv(conn);
+-		if (!rc && tcp_conn->in.datalen) {
+-			if (conn->datadgst_en)
+-				crypto_hash_init(&tcp_conn->rx_hash);
+-			tcp_conn->in_progress = IN_PROGRESS_DATA_RECV;
+-		} else if (rc) {
+-			iscsi_conn_failure(conn, rc);
+-			return 0;
++		avail = skb_seq_read(consumed, &ptr, &seq);
++		if (avail == 0) {
++			debug_tcp("no more data avail. Consumed %d\n",
++				  consumed);
++			break;
+ 		}
+-	}
+-
+-	if (tcp_conn->in_progress == IN_PROGRESS_DDIGEST_RECV &&
+-	    tcp_conn->in.copy) {
+-		uint32_t recv_digest;
+-
+-		debug_tcp("extra data_recv offset %d copy %d\n",
+-			  tcp_conn->in.offset, tcp_conn->in.copy);
+-
+-		if (!tcp_conn->data_copied) {
+-			if (tcp_conn->in.padding) {
+-				debug_tcp("padding -> %d\n",
+-					  tcp_conn->in.padding);
+-				memset(pad, 0, tcp_conn->in.padding);
+-				sg_init_one(&sg, pad, tcp_conn->in.padding);
+-				crypto_hash_update(&tcp_conn->rx_hash,
+-						   &sg, sg.length);
++		BUG_ON(segment->copied >= segment->size);
 +
- 	switch (flags & (SRB_DataIn | SRB_DataOut)) {
- 	case SRB_DataOut:
- 		data_dir = DMA_TO_DEVICE;
-@@ -582,7 +586,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
- 				void* p;
- 				/* Does this really need to be GFP_DMA? */
- 				p = kmalloc(upsg->sg[i].count,GFP_KERNEL|__GFP_DMA);
--				if(p == 0) {
-+				if(!p) {
- 					dprintk((KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n",
- 					  upsg->sg[i].count,i,upsg->count));
- 					rcode = -ENOMEM;
-@@ -594,7 +598,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
- 				sg_list[i] = p; // save so we can clean up later
- 				sg_indx = i;
- 
--				if( flags & SRB_DataOut ){
-+				if (flags & SRB_DataOut) {
- 					if(copy_from_user(p,sg_user[i],upsg->sg[i].count)){
- 						dprintk((KERN_DEBUG"aacraid: Could not copy sg data from user\n"));
- 						rcode = -EFAULT;
-@@ -626,7 +630,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
- 				void* p;
- 				/* Does this really need to be GFP_DMA? */
- 				p = kmalloc(usg->sg[i].count,GFP_KERNEL|__GFP_DMA);
--				if(p == 0) {
-+				if(!p) {
- 					kfree (usg);
- 					dprintk((KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n",
- 					  usg->sg[i].count,i,usg->count));
-@@ -637,7 +641,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
- 				sg_list[i] = p; // save so we can clean up later
- 				sg_indx = i;
++		debug_tcp("skb %p ptr=%p avail=%u\n", skb, ptr, avail);
++		rc = iscsi_tcp_segment_recv(tcp_conn, segment, ptr, avail);
++		BUG_ON(rc == 0);
++		consumed += rc;
++
++		if (segment->total_copied >= segment->total_size) {
++			debug_tcp("segment done\n");
++			rc = segment->done(tcp_conn, segment);
++			if (rc != 0) {
++				skb_abort_seq_read(&seq);
++				goto error;
+ 			}
+-			crypto_hash_final(&tcp_conn->rx_hash,
+-					  (u8 *) &tcp_conn->in.datadgst);
+-			debug_tcp("rx digest 0x%x\n", tcp_conn->in.datadgst);
+-		}
  
--				if( flags & SRB_DataOut ){
-+				if (flags & SRB_DataOut) {
- 					if(copy_from_user(p,sg_user[i],upsg->sg[i].count)){
- 						kfree (usg);
- 						dprintk((KERN_DEBUG"aacraid: Could not copy sg data from user\n"));
-@@ -668,7 +672,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
- 				void* p;
- 				/* Does this really need to be GFP_DMA? */
- 				p = kmalloc(usg->sg[i].count,GFP_KERNEL|__GFP_DMA);
--				if(p == 0) {
-+				if(!p) {
- 					dprintk((KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n",
- 					  usg->sg[i].count,i,usg->count));
- 					rcode = -ENOMEM;
-@@ -680,7 +684,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
- 				sg_list[i] = p; // save so we can clean up later
- 				sg_indx = i;
+-		rc = iscsi_tcp_copy(conn, sizeof(uint32_t));
+-		if (rc) {
+-			if (rc == -EAGAIN)
+-				goto again;
+-			iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
+-			return 0;
+-		}
+-
+-		memcpy(&recv_digest, conn->data, sizeof(uint32_t));
+-		if (recv_digest != tcp_conn->in.datadgst) {
+-			debug_tcp("iscsi_tcp: data digest error!"
+-				  "0x%x != 0x%x\n", recv_digest,
+-				  tcp_conn->in.datadgst);
+-			iscsi_conn_failure(conn, ISCSI_ERR_DATA_DGST);
+-			return 0;
+-		} else {
+-			debug_tcp("iscsi_tcp: data digest match!"
+-				  "0x%x == 0x%x\n", recv_digest,
+-				  tcp_conn->in.datadgst);
+-			tcp_conn->in_progress = IN_PROGRESS_WAIT_HEADER;
++			/* The done() functions sets up the
++			 * next segment. */
+ 		}
+ 	}
++	skb_abort_seq_read(&seq);
++	conn->rxdata_octets += consumed;
++	return consumed;
  
--				if( flags & SRB_DataOut ){
-+				if (flags & SRB_DataOut) {
- 					if(copy_from_user(p,sg_user[i],usg->sg[i].count)){
- 						dprintk((KERN_DEBUG"aacraid: Could not copy sg data from user\n"));
- 						rcode = -EFAULT;
-@@ -698,7 +702,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
- 				dma_addr_t addr;
- 				void* p;
- 				p = kmalloc(upsg->sg[i].count, GFP_KERNEL);
--				if(p == 0) {
-+				if (!p) {
- 					dprintk((KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n",
- 					  upsg->sg[i].count, i, upsg->count));
- 					rcode = -ENOMEM;
-@@ -708,7 +712,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
- 				sg_list[i] = p; // save so we can clean up later
- 				sg_indx = i;
+-	if (tcp_conn->in_progress == IN_PROGRESS_DATA_RECV &&
+-	    tcp_conn->in.copy) {
+-		debug_tcp("data_recv offset %d copy %d\n",
+-		       tcp_conn->in.offset, tcp_conn->in.copy);
+-
+-		rc = iscsi_data_recv(conn);
+-		if (rc) {
+-			if (rc == -EAGAIN)
+-				goto again;
+-			iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
+-			return 0;
+-		}
+-
+-		if (tcp_conn->in.padding)
+-			tcp_conn->in_progress = IN_PROGRESS_PAD_RECV;
+-		else if (conn->datadgst_en)
+-			tcp_conn->in_progress = IN_PROGRESS_DDIGEST_RECV;
+-		else
+-			tcp_conn->in_progress = IN_PROGRESS_WAIT_HEADER;
+-		tcp_conn->data_copied = 0;
+-	}
+-
+-	if (tcp_conn->in_progress == IN_PROGRESS_PAD_RECV &&
+-	    tcp_conn->in.copy) {
+-		int copylen = min(tcp_conn->in.padding - tcp_conn->data_copied,
+-				  tcp_conn->in.copy);
+-
+-		tcp_conn->in.copy -= copylen;
+-		tcp_conn->in.offset += copylen;
+-		tcp_conn->data_copied += copylen;
+-
+-		if (tcp_conn->data_copied != tcp_conn->in.padding)
+-			tcp_conn->in_progress = IN_PROGRESS_PAD_RECV;
+-		else if (conn->datadgst_en)
+-			tcp_conn->in_progress = IN_PROGRESS_DDIGEST_RECV;
+-		else
+-			tcp_conn->in_progress = IN_PROGRESS_WAIT_HEADER;
+-		tcp_conn->data_copied = 0;
+-	}
+-
+-	debug_tcp("f, processed %d from out of %d padding %d\n",
+-	       tcp_conn->in.offset - offset, (int)len, tcp_conn->in.padding);
+-	BUG_ON(tcp_conn->in.offset - offset > len);
+-
+-	if (tcp_conn->in.offset - offset != len) {
+-		debug_tcp("continue to process %d bytes\n",
+-		       (int)len - (tcp_conn->in.offset - offset));
+-		goto more;
+-	}
+-
+-nomore:
+-	processed = tcp_conn->in.offset - offset;
+-	BUG_ON(processed == 0);
+-	return processed;
+-
+-again:
+-	processed = tcp_conn->in.offset - offset;
+-	debug_tcp("c, processed %d from out of %d rd_desc_cnt %d\n",
+-	          processed, (int)len, (int)rd_desc->count);
+-	BUG_ON(processed == 0);
+-	BUG_ON(processed > len);
+-
+-	conn->rxdata_octets += processed;
+-	return processed;
++error:
++	debug_tcp("Error receiving PDU, errno=%d\n", rc);
++	iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
++	return 0;
+ }
  
--				if( flags & SRB_DataOut ){
-+				if (flags & SRB_DataOut) {
- 					if(copy_from_user(p, sg_user[i],
- 							upsg->sg[i].count)) {
- 						dprintk((KERN_DEBUG"aacraid: Could not copy sg data from user\n"));
-@@ -734,19 +738,19 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
- 	}
+ static void
+ iscsi_tcp_data_ready(struct sock *sk, int flag)
+ {
+ 	struct iscsi_conn *conn = sk->sk_user_data;
++	struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
+ 	read_descriptor_t rd_desc;
  
- 	if (status != 0){
--		dprintk((KERN_DEBUG"aacraid: Could not send raw srb fib to hba\n")); 
-+		dprintk((KERN_DEBUG"aacraid: Could not send raw srb fib to hba\n"));
- 		rcode = -ENXIO;
- 		goto cleanup;
- 	}
+ 	read_lock(&sk->sk_callback_lock);
  
--	if( flags & SRB_DataIn ) {
-+	if (flags & SRB_DataIn) {
- 		for(i = 0 ; i <= sg_indx; i++){
- 			byte_count = le32_to_cpu(
- 			  (dev->adapter_info.options & AAC_OPT_SGMAP_HOST64)
- 			      ? ((struct sgmap64*)&srbcmd->sg)->sg[i].count
- 			      : srbcmd->sg.sg[i].count);
- 			if(copy_to_user(sg_user[i], sg_list[i], byte_count)){
--				dprintk((KERN_DEBUG"aacraid: Could not copy sg data to user\n")); 
-+				dprintk((KERN_DEBUG"aacraid: Could not copy sg data to user\n"));
- 				rcode = -EFAULT;
- 				goto cleanup;
+ 	/*
+-	 * Use rd_desc to pass 'conn' to iscsi_tcp_data_recv.
++	 * Use rd_desc to pass 'conn' to iscsi_tcp_recv.
+ 	 * We set count to 1 because we want the network layer to
+-	 * hand us all the skbs that are available. iscsi_tcp_data_recv
++	 * hand us all the skbs that are available. iscsi_tcp_recv
+ 	 * handled pdus that cross buffers or pdus that still need data.
+ 	 */
+ 	rd_desc.arg.data = conn;
+ 	rd_desc.count = 1;
+-	tcp_read_sock(sk, &rd_desc, iscsi_tcp_data_recv);
++	tcp_read_sock(sk, &rd_desc, iscsi_tcp_recv);
  
-@@ -756,7 +760,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
+ 	read_unlock(&sk->sk_callback_lock);
++
++	/* If we had to (atomically) map a highmem page,
++	 * unmap it now. */
++	iscsi_tcp_segment_unmap(&tcp_conn->in.segment);
+ }
  
- 	reply = (struct aac_srb_reply *) fib_data(srbfib);
- 	if(copy_to_user(user_reply,reply,sizeof(struct aac_srb_reply))){
--		dprintk((KERN_DEBUG"aacraid: Could not copy reply to user\n")); 
-+		dprintk((KERN_DEBUG"aacraid: Could not copy reply to user\n"));
- 		rcode = -EFAULT;
- 		goto cleanup;
- 	}
-@@ -775,34 +779,34 @@ cleanup:
+ static void
+@@ -1077,121 +1079,173 @@ iscsi_conn_restore_callbacks(struct iscsi_tcp_conn *tcp_conn)
  }
  
- struct aac_pci_info {
--        u32 bus;
--        u32 slot;
-+	u32 bus;
-+	u32 slot;
- };
+ /**
+- * iscsi_send - generic send routine
+- * @sk: kernel's socket
+- * @buf: buffer to write from
+- * @size: actual size to write
+- * @flags: socket's flags
+- */
+-static inline int
+-iscsi_send(struct iscsi_conn *conn, struct iscsi_buf *buf, int size, int flags)
++ * iscsi_xmit - TCP transmit
++ **/
++static int
++iscsi_xmit(struct iscsi_conn *conn)
+ {
+ 	struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
+-	struct socket *sk = tcp_conn->sock;
+-	int offset = buf->sg.offset + buf->sent, res;
++	struct iscsi_segment *segment = &tcp_conn->out.segment;
++	unsigned int consumed = 0;
++	int rc = 0;
  
+-	/*
+-	 * if we got use_sg=0 or are sending something we kmallocd
+-	 * then we did not have to do kmap (kmap returns page_address)
+-	 *
+-	 * if we got use_sg > 0, but had to drop down, we do not
+-	 * set clustering so this should only happen for that
+-	 * slab case.
+-	 */
+-	if (buf->use_sendmsg)
+-		res = sock_no_sendpage(sk, sg_page(&buf->sg), offset, size, flags);
+-	else
+-		res = tcp_conn->sendpage(sk, sg_page(&buf->sg), offset, size, flags);
+-
+-	if (res >= 0) {
+-		conn->txdata_octets += res;
+-		buf->sent += res;
+-		return res;
++	while (1) {
++		rc = iscsi_tcp_xmit_segment(tcp_conn, segment);
++		if (rc < 0)
++			goto error;
++		if (rc == 0)
++			break;
++
++		consumed += rc;
++
++		if (segment->total_copied >= segment->total_size) {
++			if (segment->done != NULL) {
++				rc = segment->done(tcp_conn, segment);
++				if (rc < 0)
++					goto error;
++			}
++		}
+ 	}
  
- static int aac_get_pci_info(struct aac_dev* dev, void __user *arg)
+-	tcp_conn->sendpage_failures_cnt++;
+-	if (res == -EAGAIN)
+-		res = -ENOBUFS;
+-	else
+-		iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
+-	return res;
++	debug_tcp("xmit %d bytes\n", consumed);
++
++	conn->txdata_octets += consumed;
++	return consumed;
++
++error:
++	/* Transmit error. We could initiate error recovery
++	 * here. */
++	debug_tcp("Error sending PDU, errno=%d\n", rc);
++	iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
++	return rc;
+ }
+ 
+ /**
+- * iscsi_sendhdr - send PDU Header via tcp_sendpage()
+- * @conn: iscsi connection
+- * @buf: buffer to write from
+- * @datalen: lenght of data to be sent after the header
+- *
+- * Notes:
+- *	(Tx, Fast Path)
+- **/
++ * iscsi_tcp_xmit_qlen - return the number of bytes queued for xmit
++ */
+ static inline int
+-iscsi_sendhdr(struct iscsi_conn *conn, struct iscsi_buf *buf, int datalen)
++iscsi_tcp_xmit_qlen(struct iscsi_conn *conn)
  {
--        struct aac_pci_info pci_info;
-+	struct aac_pci_info pci_info;
+-	int flags = 0; /* MSG_DONTWAIT; */
+-	int res, size;
+-
+-	size = buf->sg.length - buf->sent;
+-	BUG_ON(buf->sent + size > buf->sg.length);
+-	if (buf->sent + size != buf->sg.length || datalen)
+-		flags |= MSG_MORE;
+-
+-	res = iscsi_send(conn, buf, size, flags);
+-	debug_tcp("sendhdr %d bytes, sent %d res %d\n", size, buf->sent, res);
+-	if (res >= 0) {
+-		if (size != res)
+-			return -EAGAIN;
+-		return 0;
+-	}
++	struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
++	struct iscsi_segment *segment = &tcp_conn->out.segment;
  
- 	pci_info.bus = dev->pdev->bus->number;
- 	pci_info.slot = PCI_SLOT(dev->pdev->devfn);
+-	return res;
++	return segment->total_copied - segment->total_size;
+ }
  
--       if (copy_to_user(arg, &pci_info, sizeof(struct aac_pci_info))) {
--               dprintk((KERN_DEBUG "aacraid: Could not copy pci info\n"));
--               return -EFAULT;
-+	if (copy_to_user(arg, &pci_info, sizeof(struct aac_pci_info))) {
-+		dprintk((KERN_DEBUG "aacraid: Could not copy pci info\n"));
-+		return -EFAULT;
+-/**
+- * iscsi_sendpage - send one page of iSCSI Data-Out.
+- * @conn: iscsi connection
+- * @buf: buffer to write from
+- * @count: remaining data
+- * @sent: number of bytes sent
+- *
+- * Notes:
+- *	(Tx, Fast Path)
+- **/
+ static inline int
+-iscsi_sendpage(struct iscsi_conn *conn, struct iscsi_buf *buf,
+-	       int *count, int *sent)
++iscsi_tcp_flush(struct iscsi_conn *conn)
+ {
+-	int flags = 0; /* MSG_DONTWAIT; */
+-	int res, size;
+-
+-	size = buf->sg.length - buf->sent;
+-	BUG_ON(buf->sent + size > buf->sg.length);
+-	if (size > *count)
+-		size = *count;
+-	if (buf->sent + size != buf->sg.length || *count != size)
+-		flags |= MSG_MORE;
+-
+-	res = iscsi_send(conn, buf, size, flags);
+-	debug_tcp("sendpage: %d bytes, sent %d left %d sent %d res %d\n",
+-		  size, buf->sent, *count, *sent, res);
+-	if (res >= 0) {
+-		*count -= res;
+-		*sent += res;
+-		if (size != res)
++	int rc;
++
++	while (iscsi_tcp_xmit_qlen(conn)) {
++		rc = iscsi_xmit(conn);
++		if (rc == 0)
+ 			return -EAGAIN;
+-		return 0;
++		if (rc < 0)
++			return rc;
  	}
--        return 0;
+ 
+-	return res;
 +	return 0;
  }
-- 
-+
  
- int aac_do_ioctl(struct aac_dev * dev, int cmd, void __user *arg)
+-static inline void
+-iscsi_data_digest_init(struct iscsi_tcp_conn *tcp_conn,
+-		      struct iscsi_tcp_cmd_task *tcp_ctask)
++/*
++ * This is called when we're done sending the header.
++ * Simply copy the data_segment to the send segment, and return.
++ */
++static int
++iscsi_tcp_send_hdr_done(struct iscsi_tcp_conn *tcp_conn,
++			struct iscsi_segment *segment)
++{
++	tcp_conn->out.segment = tcp_conn->out.data_segment;
++	debug_tcp("Header done. Next segment size %u total_size %u\n",
++		  tcp_conn->out.segment.size, tcp_conn->out.segment.total_size);
++	return 0;
++}
++
++static void
++iscsi_tcp_send_hdr_prep(struct iscsi_conn *conn, void *hdr, size_t hdrlen)
  {
- 	int status;
--	
+-	crypto_hash_init(&tcp_conn->tx_hash);
+-	tcp_ctask->digest_count = 4;
++	struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
 +
- 	/*
- 	 *	HBA gets first crack
- 	 */
--	 
++	debug_tcp("%s(%p%s)\n", __FUNCTION__, tcp_conn,
++			conn->hdrdgst_en? ", digest enabled" : "");
 +
- 	status = aac_dev_ioctl(dev, cmd, arg);
- 	if(status != -ENOTTY)
- 		return status;
-@@ -832,7 +836,7 @@ int aac_do_ioctl(struct aac_dev * dev, int cmd, void __user *arg)
- 		break;
- 	default:
- 		status = -ENOTTY;
--	  	break;	
-+		break;
- 	}
- 	return status;
- }
-diff --git a/drivers/scsi/aacraid/comminit.c b/drivers/scsi/aacraid/comminit.c
-index 8736813..89cc8b7 100644
---- a/drivers/scsi/aacraid/comminit.c
-+++ b/drivers/scsi/aacraid/comminit.c
-@@ -301,10 +301,10 @@ struct aac_dev *aac_init_adapter(struct aac_dev *dev)
- 	if ((!aac_adapter_sync_cmd(dev, GET_ADAPTER_PROPERTIES,
- 		0, 0, 0, 0, 0, 0, status+0, status+1, status+2, NULL, NULL)) &&
- 	 		(status[0] == 0x00000001)) {
--		if (status[1] & AAC_OPT_NEW_COMM_64)
-+		if (status[1] & le32_to_cpu(AAC_OPT_NEW_COMM_64))
- 			dev->raw_io_64 = 1;
- 		if (dev->a_ops.adapter_comm &&
--		    (status[1] & AAC_OPT_NEW_COMM))
-+		    (status[1] & le32_to_cpu(AAC_OPT_NEW_COMM)))
- 			dev->comm_interface = AAC_COMM_MESSAGE;
- 		if ((dev->comm_interface == AAC_COMM_MESSAGE) &&
- 		    (status[2] > dev->base_size)) {
-diff --git a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c
-index abce48c..81b3692 100644
---- a/drivers/scsi/aacraid/commsup.c
-+++ b/drivers/scsi/aacraid/commsup.c
-@@ -56,7 +56,7 @@
-  *	Allocate and map the shared PCI space for the FIB blocks used to
-  *	talk to the Adaptec firmware.
-  */
-- 
++	/* Clear the data segment - needs to be filled in by the
++	 * caller using iscsi_tcp_send_data_prep() */
++	memset(&tcp_conn->out.data_segment, 0, sizeof(struct iscsi_segment));
 +
- static int fib_map_alloc(struct aac_dev *dev)
- {
- 	dprintk((KERN_INFO
-@@ -109,14 +109,16 @@ int aac_fib_setup(struct aac_dev * dev)
- 	}
- 	if (i<0)
- 		return -ENOMEM;
--		
++	/* If header digest is enabled, compute the CRC and
++	 * place the digest into the same buffer. We make
++	 * sure that both iscsi_tcp_ctask and mtask have
++	 * sufficient room.
++	 */
++	if (conn->hdrdgst_en) {
++		iscsi_tcp_dgst_header(&tcp_conn->tx_hash, hdr, hdrlen,
++				      hdr + hdrlen);
++		hdrlen += ISCSI_DIGEST_SIZE;
++	}
 +
- 	hw_fib = dev->hw_fib_va;
- 	hw_fib_pa = dev->hw_fib_pa;
- 	memset(hw_fib, 0, dev->max_fib_size * (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB));
- 	/*
- 	 *	Initialise the fibs
- 	 */
--	for (i = 0, fibptr = &dev->fibs[i]; i < (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB); i++, fibptr++) 
-+	for (i = 0, fibptr = &dev->fibs[i];
-+		i < (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB);
-+		i++, fibptr++)
- 	{
- 		fibptr->dev = dev;
- 		fibptr->hw_fib_va = hw_fib;
-@@ -148,13 +150,13 @@ int aac_fib_setup(struct aac_dev * dev)
-  *	Allocate a fib from the adapter fib pool. If the pool is empty we
-  *	return NULL.
-  */
-- 
++	/* Remember header pointer for later, when we need
++	 * to decide whether there's a payload to go along
++	 * with the header. */
++	tcp_conn->out.hdr = hdr;
 +
- struct fib *aac_fib_alloc(struct aac_dev *dev)
- {
- 	struct fib * fibptr;
- 	unsigned long flags;
- 	spin_lock_irqsave(&dev->fib_lock, flags);
--	fibptr = dev->free_fib;	
-+	fibptr = dev->free_fib;
- 	if(!fibptr){
- 		spin_unlock_irqrestore(&dev->fib_lock, flags);
- 		return fibptr;
-@@ -171,6 +173,7 @@ struct fib *aac_fib_alloc(struct aac_dev *dev)
- 	 *	each I/O
- 	 */
- 	fibptr->hw_fib_va->header.XferState = 0;
-+	fibptr->flags = 0;
- 	fibptr->callback = NULL;
- 	fibptr->callback_data = NULL;
- 
-@@ -183,7 +186,7 @@ struct fib *aac_fib_alloc(struct aac_dev *dev)
-  *
-  *	Frees up a fib and places it on the appropriate queue
-  */
-- 
++	iscsi_segment_init_linear(&tcp_conn->out.segment, hdr, hdrlen,
++				iscsi_tcp_send_hdr_done, NULL);
++}
 +
- void aac_fib_free(struct fib *fibptr)
- {
- 	unsigned long flags;
-@@ -204,10 +207,10 @@ void aac_fib_free(struct fib *fibptr)
- /**
-  *	aac_fib_init	-	initialise a fib
-  *	@fibptr: The fib to initialize
-- *	
-+ *
-  *	Set up the generic fib fields ready for use
-  */
-- 
++/*
++ * Prepare the send buffer for the payload data.
++ * Padding and checksumming will all be taken care
++ * of by the iscsi_segment routines.
++ */
++static int
++iscsi_tcp_send_data_prep(struct iscsi_conn *conn, struct scatterlist *sg,
++			 unsigned int count, unsigned int offset,
++			 unsigned int len)
++{
++	struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
++	struct hash_desc *tx_hash = NULL;
++	unsigned int hdr_spec_len;
 +
- void aac_fib_init(struct fib *fibptr)
- {
- 	struct hw_fib *hw_fib = fibptr->hw_fib_va;
-@@ -227,12 +230,12 @@ void aac_fib_init(struct fib *fibptr)
-  *	Will deallocate and return to the free pool the FIB pointed to by the
-  *	caller.
-  */
-- 
++	debug_tcp("%s(%p, offset=%d, datalen=%d%s)\n", __FUNCTION__,
++			tcp_conn, offset, len,
++			conn->datadgst_en? ", digest enabled" : "");
 +
- static void fib_dealloc(struct fib * fibptr)
- {
- 	struct hw_fib *hw_fib = fibptr->hw_fib_va;
- 	BUG_ON(hw_fib->header.StructType != FIB_MAGIC);
--	hw_fib->header.XferState = 0;        
-+	hw_fib->header.XferState = 0;
++	/* Make sure the datalen matches what the caller
++	   said he would send. */
++	hdr_spec_len = ntoh24(tcp_conn->out.hdr->dlength);
++	WARN_ON(iscsi_padded(len) != iscsi_padded(hdr_spec_len));
++
++	if (conn->datadgst_en)
++		tx_hash = &tcp_conn->tx_hash;
++
++	return iscsi_segment_seek_sg(&tcp_conn->out.data_segment,
++				   sg, count, offset, len,
++				   NULL, tx_hash);
++}
++
++static void
++iscsi_tcp_send_linear_data_prepare(struct iscsi_conn *conn, void *data,
++				   size_t len)
++{
++	struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
++	struct hash_desc *tx_hash = NULL;
++	unsigned int hdr_spec_len;
++
++	debug_tcp("%s(%p, datalen=%d%s)\n", __FUNCTION__, tcp_conn, len,
++		  conn->datadgst_en? ", digest enabled" : "");
++
++	/* Make sure the datalen matches what the caller
++	   said he would send. */
++	hdr_spec_len = ntoh24(tcp_conn->out.hdr->dlength);
++	WARN_ON(iscsi_padded(len) != iscsi_padded(hdr_spec_len));
++
++	if (conn->datadgst_en)
++		tx_hash = &tcp_conn->tx_hash;
++
++	iscsi_segment_init_linear(&tcp_conn->out.data_segment,
++				data, len, NULL, tx_hash);
  }
  
- /*
-@@ -241,7 +244,7 @@ static void fib_dealloc(struct fib * fibptr)
-  *	these routines and are the only routines which have a knowledge of the
-  *	 how these queues are implemented.
-  */
-- 
-+
  /**
-  *	aac_get_entry		-	get a queue entry
-  *	@dev: Adapter
-@@ -254,7 +257,7 @@ static void fib_dealloc(struct fib * fibptr)
-  *	is full(no free entries) than no entry is returned and the function returns 0 otherwise 1 is
-  *	returned.
-  */
-- 
-+
- static int aac_get_entry (struct aac_dev * dev, u32 qid, struct aac_entry **entry, u32 * index, unsigned long *nonotify)
+@@ -1207,12 +1261,17 @@ iscsi_data_digest_init(struct iscsi_tcp_conn *tcp_conn,
+  *
+  *	Called under connection lock.
+  **/
+-static void
++static int
+ iscsi_solicit_data_cont(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask,
+-			struct iscsi_r2t_info *r2t, int left)
++			struct iscsi_r2t_info *r2t)
  {
- 	struct aac_queue * q;
-@@ -279,26 +282,27 @@ static int aac_get_entry (struct aac_dev * dev, u32 qid, struct aac_entry **entr
- 				idx = ADAP_NORM_RESP_ENTRIES;
- 		}
- 		if (idx != le32_to_cpu(*(q->headers.consumer)))
--			*nonotify = 1; 
-+			*nonotify = 1;
- 	}
+ 	struct iscsi_data *hdr;
+-	int new_offset;
++	int new_offset, left;
++
++	BUG_ON(r2t->data_length - r2t->sent < 0);
++	left = r2t->data_length - r2t->sent;
++	if (left == 0)
++		return 0;
  
- 	if (qid == AdapNormCmdQueue) {
--	        if (*index >= ADAP_NORM_CMD_ENTRIES) 
-+		if (*index >= ADAP_NORM_CMD_ENTRIES)
- 			*index = 0; /* Wrap to front of the Producer Queue. */
- 	} else {
--		if (*index >= ADAP_NORM_RESP_ENTRIES) 
-+		if (*index >= ADAP_NORM_RESP_ENTRIES)
- 			*index = 0; /* Wrap to front of the Producer Queue. */
+ 	hdr = &r2t->dtask.hdr;
+ 	memset(hdr, 0, sizeof(struct iscsi_data));
+@@ -1233,43 +1292,46 @@ iscsi_solicit_data_cont(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask,
+ 		r2t->data_count = left;
+ 		hdr->flags = ISCSI_FLAG_CMD_FINAL;
  	}
+-	conn->dataout_pdus_cnt++;
+-
+-	iscsi_buf_init_iov(&r2t->headbuf, (char*)hdr,
+-			   sizeof(struct iscsi_hdr));
+-
+-	if (iscsi_buf_left(&r2t->sendbuf))
+-		return;
+-
+-	iscsi_buf_init_sg(&r2t->sendbuf, r2t->sg);
+-	r2t->sg += 1;
+-}
  
--        if ((*index + 1) == le32_to_cpu(*(q->headers.consumer))) { /* Queue is full */
-+	/* Queue is full */
-+	if ((*index + 1) == le32_to_cpu(*(q->headers.consumer))) {
- 		printk(KERN_WARNING "Queue %d full, %u outstanding.\n",
- 				qid, q->numpending);
- 		return 0;
- 	} else {
--	        *entry = q->base + *index;
-+		*entry = q->base + *index;
- 		return 1;
- 	}
--}   
-+}
+-static void iscsi_set_padding(struct iscsi_tcp_cmd_task *tcp_ctask,
+-			      unsigned long len)
+-{
+-	tcp_ctask->pad_count = len & (ISCSI_PAD_LEN - 1);
+-	if (!tcp_ctask->pad_count)
+-		return;
+-
+-	tcp_ctask->pad_count = ISCSI_PAD_LEN - tcp_ctask->pad_count;
+-	debug_scsi("write padding %d bytes\n", tcp_ctask->pad_count);
+-	set_bit(XMSTATE_BIT_W_PAD, &tcp_ctask->xmstate);
++	conn->dataout_pdus_cnt++;
++	return 1;
+ }
  
  /**
-  *	aac_queue_get		-	get the next free QE
-@@ -320,31 +324,29 @@ int aac_queue_get(struct aac_dev * dev, u32 * index, u32 qid, struct hw_fib * hw
+- * iscsi_tcp_cmd_init - Initialize iSCSI SCSI_READ or SCSI_WRITE commands
++ * iscsi_tcp_ctask - Initialize iSCSI SCSI_READ or SCSI_WRITE commands
+  * @conn: iscsi connection
+  * @ctask: scsi command task
+  * @sc: scsi command
+  **/
+-static void
+-iscsi_tcp_cmd_init(struct iscsi_cmd_task *ctask)
++static int
++iscsi_tcp_ctask_init(struct iscsi_cmd_task *ctask)
  {
- 	struct aac_entry * entry = NULL;
- 	int map = 0;
--	    
-+
- 	if (qid == AdapNormCmdQueue) {
- 		/*  if no entries wait for some if caller wants to */
--        	while (!aac_get_entry(dev, qid, &entry, index, nonotify)) 
--        	{
-+		while (!aac_get_entry(dev, qid, &entry, index, nonotify)) {
- 			printk(KERN_ERR "GetEntries failed\n");
- 		}
--	        /*
--	         *	Setup queue entry with a command, status and fib mapped
--	         */
--	        entry->size = cpu_to_le32(le16_to_cpu(hw_fib->header.Size));
--	        map = 1;
-+		/*
-+		 *	Setup queue entry with a command, status and fib mapped
-+		 */
-+		entry->size = cpu_to_le32(le16_to_cpu(hw_fib->header.Size));
-+		map = 1;
- 	} else {
--	        while(!aac_get_entry(dev, qid, &entry, index, nonotify)) 
--	        {
-+		while (!aac_get_entry(dev, qid, &entry, index, nonotify)) {
- 			/* if no entries wait for some if caller wants to */
- 		}
--        	/*
--        	 *	Setup queue entry with command, status and fib mapped
--        	 */
--        	entry->size = cpu_to_le32(le16_to_cpu(hw_fib->header.Size));
--        	entry->addr = hw_fib->header.SenderFibAddress;
--     			/* Restore adapters pointer to the FIB */
-+		/*
-+		 *	Setup queue entry with command, status and fib mapped
-+		 */
-+		entry->size = cpu_to_le32(le16_to_cpu(hw_fib->header.Size));
-+		entry->addr = hw_fib->header.SenderFibAddress;
-+			/* Restore adapters pointer to the FIB */
- 		hw_fib->header.ReceiverFibAddress = hw_fib->header.SenderFibAddress;	/* Let the adapter now where to find its data */
--        	map = 0;
-+		map = 0;
- 	}
- 	/*
- 	 *	If MapFib is true than we need to map the Fib and put pointers
-@@ -356,8 +358,8 @@ int aac_queue_get(struct aac_dev * dev, u32 * index, u32 qid, struct hw_fib * hw
- }
+ 	struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
++	struct iscsi_conn *conn = ctask->conn;
++	struct scsi_cmnd *sc = ctask->sc;
++	int err;
  
- /*
-- *	Define the highest level of host to adapter communication routines. 
-- *	These routines will support host to adapter FS commuication. These 
-+ *	Define the highest level of host to adapter communication routines.
-+ *	These routines will support host to adapter FS commuication. These
-  *	routines have no knowledge of the commuication method used. This level
-  *	sends and receives FIBs. This level has no knowledge of how these FIBs
-  *	get passed back and forth.
-@@ -379,7 +381,7 @@ int aac_queue_get(struct aac_dev * dev, u32 * index, u32 qid, struct hw_fib * hw
-  *	an event to wait on must be supplied. This event will be set when a
-  *	response FIB is received from the adapter.
-  */
-- 
+ 	BUG_ON(__kfifo_len(tcp_ctask->r2tqueue));
+-	tcp_ctask->xmstate = 1 << XMSTATE_BIT_CMD_HDR_INIT;
++	tcp_ctask->sent = 0;
++	tcp_ctask->exp_datasn = 0;
 +
- int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size,
- 		int priority, int wait, int reply, fib_callback callback,
- 		void *callback_data)
-@@ -392,16 +394,17 @@ int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size,
- 	if (!(hw_fib->header.XferState & cpu_to_le32(HostOwned)))
- 		return -EBUSY;
- 	/*
--	 *	There are 5 cases with the wait and reponse requested flags. 
-+	 *	There are 5 cases with the wait and reponse requested flags.
- 	 *	The only invalid cases are if the caller requests to wait and
- 	 *	does not request a response and if the caller does not want a
- 	 *	response and the Fib is not allocated from pool. If a response
- 	 *	is not requesed the Fib will just be deallocaed by the DPC
- 	 *	routine when the response comes back from the adapter. No
--	 *	further processing will be done besides deleting the Fib. We 
-+	 *	further processing will be done besides deleting the Fib. We
- 	 *	will have a debug mode where the adapter can notify the host
- 	 *	it had a problem and the host can log that fact.
- 	 */
-+	fibptr->flags = 0;
- 	if (wait && !reply) {
- 		return -EINVAL;
- 	} else if (!wait && reply) {
-@@ -413,7 +416,7 @@ int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size,
- 	} else if (wait && reply) {
- 		hw_fib->header.XferState |= cpu_to_le32(ResponseExpected);
- 		FIB_COUNTER_INCREMENT(aac_config.NormalSent);
--	} 
-+	}
- 	/*
- 	 *	Map the fib into 32bits by using the fib number
- 	 */
-@@ -436,7 +439,7 @@ int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size,
- 	hw_fib->header.Size = cpu_to_le16(sizeof(struct aac_fibhdr) + size);
- 	if (le16_to_cpu(hw_fib->header.Size) > le16_to_cpu(hw_fib->header.SenderSize)) {
- 		return -EMSGSIZE;
--	}                
-+	}
- 	/*
- 	 *	Get a queue entry connect the FIB to it and send an notify
- 	 *	the adapter a command is ready.
-@@ -450,10 +453,10 @@ int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size,
- 	if (!wait) {
- 		fibptr->callback = callback;
- 		fibptr->callback_data = callback_data;
-+		fibptr->flags = FIB_CONTEXT_FLAG;
- 	}
++	/* Prepare PDU, optionally w/ immediate data */
++	debug_scsi("ctask deq [cid %d itt 0x%x imm %d unsol %d]\n",
++		    conn->id, ctask->itt, ctask->imm_count,
++		    ctask->unsol_count);
++	iscsi_tcp_send_hdr_prep(conn, ctask->hdr, ctask->hdr_len);
++
++	if (!ctask->imm_count)
++		return 0;
++
++	/* If we have immediate data, attach a payload */
++	err = iscsi_tcp_send_data_prep(conn, scsi_sglist(sc), scsi_sg_count(sc),
++				       0, ctask->imm_count);
++	if (err)
++		return err;
++	tcp_ctask->sent += ctask->imm_count;
++	ctask->imm_count = 0;
++	return 0;
+ }
  
- 	fibptr->done = 0;
--	fibptr->flags = 0;
+ /**
+@@ -1281,484 +1343,130 @@ iscsi_tcp_cmd_init(struct iscsi_cmd_task *ctask)
+  *	The function can return -EAGAIN in which case caller must
+  *	call it again later, or recover. '0' return code means successful
+  *	xmit.
+- *
+- *	Management xmit state machine consists of these states:
+- *		XMSTATE_BIT_IMM_HDR_INIT - calculate digest of PDU Header
+- *		XMSTATE_BIT_IMM_HDR      - PDU Header xmit in progress
+- *		XMSTATE_BIT_IMM_DATA     - PDU Data xmit in progress
+- *		XMSTATE_VALUE_IDLE       - management PDU is done
+  **/
+ static int
+ iscsi_tcp_mtask_xmit(struct iscsi_conn *conn, struct iscsi_mgmt_task *mtask)
+ {
+-	struct iscsi_tcp_mgmt_task *tcp_mtask = mtask->dd_data;
+ 	int rc;
  
- 	FIB_COUNTER_INCREMENT(aac_config.FibsSent);
+-	debug_scsi("mtask deq [cid %d state %x itt 0x%x]\n",
+-		conn->id, tcp_mtask->xmstate, mtask->itt);
+-
+-	if (test_bit(XMSTATE_BIT_IMM_HDR_INIT, &tcp_mtask->xmstate)) {
+-		iscsi_buf_init_iov(&tcp_mtask->headbuf, (char*)mtask->hdr,
+-				   sizeof(struct iscsi_hdr));
+-
+-		if (mtask->data_count) {
+-			set_bit(XMSTATE_BIT_IMM_DATA, &tcp_mtask->xmstate);
+-			iscsi_buf_init_iov(&tcp_mtask->sendbuf,
+-					   (char*)mtask->data,
+-					   mtask->data_count);
+-		}
+-
+-		if (conn->c_stage != ISCSI_CONN_INITIAL_STAGE &&
+-		    conn->stop_stage != STOP_CONN_RECOVER &&
+-		    conn->hdrdgst_en)
+-			iscsi_hdr_digest(conn, &tcp_mtask->headbuf,
+-					(u8*)tcp_mtask->hdrext);
+-
+-		tcp_mtask->sent = 0;
+-		clear_bit(XMSTATE_BIT_IMM_HDR_INIT, &tcp_mtask->xmstate);
+-		set_bit(XMSTATE_BIT_IMM_HDR, &tcp_mtask->xmstate);
+-	}
+-
+-	if (test_bit(XMSTATE_BIT_IMM_HDR, &tcp_mtask->xmstate)) {
+-		rc = iscsi_sendhdr(conn, &tcp_mtask->headbuf,
+-				   mtask->data_count);
+-		if (rc)
+-			return rc;
+-		clear_bit(XMSTATE_BIT_IMM_HDR, &tcp_mtask->xmstate);
+-	}
+-
+-	if (test_and_clear_bit(XMSTATE_BIT_IMM_DATA, &tcp_mtask->xmstate)) {
+-		BUG_ON(!mtask->data_count);
+-		/* FIXME: implement.
+-		 * Virtual buffer could be spreaded across multiple pages...
+-		 */
+-		do {
+-			int rc;
+-
+-			rc = iscsi_sendpage(conn, &tcp_mtask->sendbuf,
+-					&mtask->data_count, &tcp_mtask->sent);
+-			if (rc) {
+-				set_bit(XMSTATE_BIT_IMM_DATA, &tcp_mtask->xmstate);
+-				return rc;
+-			}
+-		} while (mtask->data_count);
+-	}
++	/* Flush any pending data first. */
++	rc = iscsi_tcp_flush(conn);
++	if (rc < 0)
++		return rc;
  
-@@ -473,9 +476,9 @@ int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size,
- 	aac_adapter_deliver(fibptr);
+-	BUG_ON(tcp_mtask->xmstate != XMSTATE_VALUE_IDLE);
+ 	if (mtask->hdr->itt == RESERVED_ITT) {
+ 		struct iscsi_session *session = conn->session;
  
- 	/*
--	 *	If the caller wanted us to wait for response wait now. 
-+	 *	If the caller wanted us to wait for response wait now.
- 	 */
--    
-+
- 	if (wait) {
- 		spin_unlock_irqrestore(&fibptr->event_lock, flags);
- 		/* Only set for first known interruptable command */
-@@ -522,7 +525,7 @@ int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size,
- 		}
- 		spin_unlock_irqrestore(&fibptr->event_lock, flags);
- 		BUG_ON(fibptr->done == 0);
--			
+ 		spin_lock_bh(&session->lock);
+-		list_del(&conn->mtask->running);
+-		__kfifo_put(session->mgmtpool.queue, (void*)&conn->mtask,
+-			    sizeof(void*));
++		iscsi_free_mgmt_task(conn, mtask);
+ 		spin_unlock_bh(&session->lock);
+ 	}
 +
- 		if(unlikely(fibptr->flags & FIB_CONTEXT_FLAG_TIMED_OUT))
- 			return -ETIMEDOUT;
- 		return 0;
-@@ -537,15 +540,15 @@ int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size,
- 		return 0;
+ 	return 0;
  }
  
--/** 
-+/**
-  *	aac_consumer_get	-	get the top of the queue
-  *	@dev: Adapter
-  *	@q: Queue
-  *	@entry: Return entry
-  *
-  *	Will return a pointer to the entry on the top of the queue requested that
-- * 	we are a consumer of, and return the address of the queue entry. It does
-- *	not change the state of the queue. 
-+ *	we are a consumer of, and return the address of the queue entry. It does
-+ *	not change the state of the queue.
-  */
++/*
++ * iscsi_tcp_ctask_xmit - xmit normal PDU task
++ * @conn: iscsi connection
++ * @ctask: iscsi command task
++ *
++ * We're expected to return 0 when everything was transmitted succesfully,
++ * -EAGAIN if there's still data in the queue, or != 0 for any other kind
++ * of error.
++ */
+ static int
+-iscsi_send_cmd_hdr(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
++iscsi_tcp_ctask_xmit(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
+ {
+-	struct scsi_cmnd *sc = ctask->sc;
+ 	struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
++	struct scsi_cmnd *sc = ctask->sc;
+ 	int rc = 0;
+ 
+-	if (test_bit(XMSTATE_BIT_CMD_HDR_INIT, &tcp_ctask->xmstate)) {
+-		tcp_ctask->sent = 0;
+-		tcp_ctask->sg_count = 0;
+-		tcp_ctask->exp_datasn = 0;
+-
+-		if (sc->sc_data_direction == DMA_TO_DEVICE) {
+-			struct scatterlist *sg = scsi_sglist(sc);
+-
+-			iscsi_buf_init_sg(&tcp_ctask->sendbuf, sg);
+-			tcp_ctask->sg = sg + 1;
+-			tcp_ctask->bad_sg = sg + scsi_sg_count(sc);
+-
+-			debug_scsi("cmd [itt 0x%x total %d imm_data %d "
+-				   "unsol count %d, unsol offset %d]\n",
+-				   ctask->itt, scsi_bufflen(sc),
+-				   ctask->imm_count, ctask->unsol_count,
+-				   ctask->unsol_offset);
+-		}
+-
+-		iscsi_buf_init_iov(&tcp_ctask->headbuf, (char*)ctask->hdr,
+-				  sizeof(struct iscsi_hdr));
+-
+-		if (conn->hdrdgst_en)
+-			iscsi_hdr_digest(conn, &tcp_ctask->headbuf,
+-					 (u8*)tcp_ctask->hdrext);
+-		clear_bit(XMSTATE_BIT_CMD_HDR_INIT, &tcp_ctask->xmstate);
+-		set_bit(XMSTATE_BIT_CMD_HDR_XMIT, &tcp_ctask->xmstate);
+-	}
+-
+-	if (test_bit(XMSTATE_BIT_CMD_HDR_XMIT, &tcp_ctask->xmstate)) {
+-		rc = iscsi_sendhdr(conn, &tcp_ctask->headbuf, ctask->imm_count);
+-		if (rc)
+-			return rc;
+-		clear_bit(XMSTATE_BIT_CMD_HDR_XMIT, &tcp_ctask->xmstate);
+-
+-		if (sc->sc_data_direction != DMA_TO_DEVICE)
+-			return 0;
+-
+-		if (ctask->imm_count) {
+-			set_bit(XMSTATE_BIT_IMM_DATA, &tcp_ctask->xmstate);
+-			iscsi_set_padding(tcp_ctask, ctask->imm_count);
+-
+-			if (ctask->conn->datadgst_en) {
+-				iscsi_data_digest_init(ctask->conn->dd_data,
+-						       tcp_ctask);
+-				tcp_ctask->immdigest = 0;
+-			}
+-		}
+-
+-		if (ctask->unsol_count) {
+-			set_bit(XMSTATE_BIT_UNS_HDR, &tcp_ctask->xmstate);
+-			set_bit(XMSTATE_BIT_UNS_INIT, &tcp_ctask->xmstate);
+-		}
+-	}
+-	return rc;
+-}
+-
+-static int
+-iscsi_send_padding(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
+-{
+-	struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
+-	struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
+-	int sent = 0, rc;
+-
+-	if (test_bit(XMSTATE_BIT_W_PAD, &tcp_ctask->xmstate)) {
+-		iscsi_buf_init_iov(&tcp_ctask->sendbuf, (char*)&tcp_ctask->pad,
+-				   tcp_ctask->pad_count);
+-		if (conn->datadgst_en)
+-			crypto_hash_update(&tcp_conn->tx_hash,
+-					   &tcp_ctask->sendbuf.sg,
+-					   tcp_ctask->sendbuf.sg.length);
+-	} else if (!test_bit(XMSTATE_BIT_W_RESEND_PAD, &tcp_ctask->xmstate))
+-		return 0;
+-
+-	clear_bit(XMSTATE_BIT_W_PAD, &tcp_ctask->xmstate);
+-	clear_bit(XMSTATE_BIT_W_RESEND_PAD, &tcp_ctask->xmstate);
+-	debug_scsi("sending %d pad bytes for itt 0x%x\n",
+-		   tcp_ctask->pad_count, ctask->itt);
+-	rc = iscsi_sendpage(conn, &tcp_ctask->sendbuf, &tcp_ctask->pad_count,
+-			   &sent);
+-	if (rc) {
+-		debug_scsi("padding send failed %d\n", rc);
+-		set_bit(XMSTATE_BIT_W_RESEND_PAD, &tcp_ctask->xmstate);
+-	}
+-	return rc;
+-}
+-
+-static int
+-iscsi_send_digest(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask,
+-			struct iscsi_buf *buf, uint32_t *digest)
+-{
+-	struct iscsi_tcp_cmd_task *tcp_ctask;
+-	struct iscsi_tcp_conn *tcp_conn;
+-	int rc, sent = 0;
+-
+-	if (!conn->datadgst_en)
+-		return 0;
+-
+-	tcp_ctask = ctask->dd_data;
+-	tcp_conn = conn->dd_data;
+-
+-	if (!test_bit(XMSTATE_BIT_W_RESEND_DATA_DIGEST, &tcp_ctask->xmstate)) {
+-		crypto_hash_final(&tcp_conn->tx_hash, (u8*)digest);
+-		iscsi_buf_init_iov(buf, (char*)digest, 4);
+-	}
+-	clear_bit(XMSTATE_BIT_W_RESEND_DATA_DIGEST, &tcp_ctask->xmstate);
+-
+-	rc = iscsi_sendpage(conn, buf, &tcp_ctask->digest_count, &sent);
+-	if (!rc)
+-		debug_scsi("sent digest 0x%x for itt 0x%x\n", *digest,
+-			  ctask->itt);
+-	else {
+-		debug_scsi("sending digest 0x%x failed for itt 0x%x!\n",
+-			  *digest, ctask->itt);
+-		set_bit(XMSTATE_BIT_W_RESEND_DATA_DIGEST, &tcp_ctask->xmstate);
+-	}
+-	return rc;
+-}
+-
+-static int
+-iscsi_send_data(struct iscsi_cmd_task *ctask, struct iscsi_buf *sendbuf,
+-		struct scatterlist **sg, int *sent, int *count,
+-		struct iscsi_buf *digestbuf, uint32_t *digest)
+-{
+-	struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
+-	struct iscsi_conn *conn = ctask->conn;
+-	struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
+-	int rc, buf_sent, offset;
+-
+-	while (*count) {
+-		buf_sent = 0;
+-		offset = sendbuf->sent;
+-
+-		rc = iscsi_sendpage(conn, sendbuf, count, &buf_sent);
+-		*sent = *sent + buf_sent;
+-		if (buf_sent && conn->datadgst_en)
+-			partial_sg_digest_update(&tcp_conn->tx_hash,
+-				&sendbuf->sg, sendbuf->sg.offset + offset,
+-				buf_sent);
+-		if (!iscsi_buf_left(sendbuf) && *sg != tcp_ctask->bad_sg) {
+-			iscsi_buf_init_sg(sendbuf, *sg);
+-			*sg = *sg + 1;
+-		}
+-
+-		if (rc)
+-			return rc;
+-	}
+-
+-	rc = iscsi_send_padding(conn, ctask);
+-	if (rc)
++flush:
++	/* Flush any pending data first. */
++	rc = iscsi_tcp_flush(conn);
++	if (rc < 0)
+ 		return rc;
+ 
+-	return iscsi_send_digest(conn, ctask, digestbuf, digest);
+-}
+-
+-static int
+-iscsi_send_unsol_hdr(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
+-{
+-	struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
+-	struct iscsi_data_task *dtask;
+-	int rc;
+-
+-	set_bit(XMSTATE_BIT_UNS_DATA, &tcp_ctask->xmstate);
+-	if (test_bit(XMSTATE_BIT_UNS_INIT, &tcp_ctask->xmstate)) {
+-		dtask = &tcp_ctask->unsol_dtask;
+-
+-		iscsi_prep_unsolicit_data_pdu(ctask, &dtask->hdr);
+-		iscsi_buf_init_iov(&tcp_ctask->headbuf, (char*)&dtask->hdr,
+-				   sizeof(struct iscsi_hdr));
+-		if (conn->hdrdgst_en)
+-			iscsi_hdr_digest(conn, &tcp_ctask->headbuf,
+-					(u8*)dtask->hdrext);
+-
+-		clear_bit(XMSTATE_BIT_UNS_INIT, &tcp_ctask->xmstate);
+-		iscsi_set_padding(tcp_ctask, ctask->data_count);
+-	}
+-
+-	rc = iscsi_sendhdr(conn, &tcp_ctask->headbuf, ctask->data_count);
+-	if (rc) {
+-		clear_bit(XMSTATE_BIT_UNS_DATA, &tcp_ctask->xmstate);
+-		set_bit(XMSTATE_BIT_UNS_HDR, &tcp_ctask->xmstate);
+-		return rc;
+-	}
++	/* Are we done already? */
++	if (sc->sc_data_direction != DMA_TO_DEVICE)
++		return 0;
+ 
+-	if (conn->datadgst_en) {
+-		dtask = &tcp_ctask->unsol_dtask;
+-		iscsi_data_digest_init(ctask->conn->dd_data, tcp_ctask);
+-		dtask->digest = 0;
+-	}
++	if (ctask->unsol_count != 0) {
++		struct iscsi_data *hdr = &tcp_ctask->unsol_dtask.hdr;
+ 
+-	debug_scsi("uns dout [itt 0x%x dlen %d sent %d]\n",
+-		   ctask->itt, ctask->unsol_count, tcp_ctask->sent);
+-	return 0;
+-}
++		/* Prepare a header for the unsolicited PDU.
++		 * The amount of data we want to send will be
++		 * in ctask->data_count.
++		 * FIXME: return the data count instead.
++		 */
++		iscsi_prep_unsolicit_data_pdu(ctask, hdr);
+ 
+-static int
+-iscsi_send_unsol_pdu(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
+-{
+-	struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
+-	int rc;
++		debug_tcp("unsol dout [itt 0x%x doff %d dlen %d]\n",
++				ctask->itt, tcp_ctask->sent, ctask->data_count);
+ 
+-	if (test_and_clear_bit(XMSTATE_BIT_UNS_HDR, &tcp_ctask->xmstate)) {
+-		BUG_ON(!ctask->unsol_count);
+-send_hdr:
+-		rc = iscsi_send_unsol_hdr(conn, ctask);
++		iscsi_tcp_send_hdr_prep(conn, hdr, sizeof(*hdr));
++		rc = iscsi_tcp_send_data_prep(conn, scsi_sglist(sc),
++					      scsi_sg_count(sc),
++					      tcp_ctask->sent,
++					      ctask->data_count);
+ 		if (rc)
+-			return rc;
+-	}
+-
+-	if (test_bit(XMSTATE_BIT_UNS_DATA, &tcp_ctask->xmstate)) {
+-		struct iscsi_data_task *dtask = &tcp_ctask->unsol_dtask;
+-		int start = tcp_ctask->sent;
++			goto fail;
++		tcp_ctask->sent += ctask->data_count;
++		ctask->unsol_count -= ctask->data_count;
++		goto flush;
++	} else {
++		struct iscsi_session *session = conn->session;
++		struct iscsi_r2t_info *r2t;
  
- int aac_consumer_get(struct aac_dev * dev, struct aac_queue * q, struct aac_entry **entry)
-@@ -560,10 +563,10 @@ int aac_consumer_get(struct aac_dev * dev, struct aac_queue * q, struct aac_entr
- 		 *	the end of the queue, else we just use the entry
- 		 *	pointed to by the header index
+-		rc = iscsi_send_data(ctask, &tcp_ctask->sendbuf, &tcp_ctask->sg,
+-				     &tcp_ctask->sent, &ctask->data_count,
+-				     &dtask->digestbuf, &dtask->digest);
+-		ctask->unsol_count -= tcp_ctask->sent - start;
+-		if (rc)
+-			return rc;
+-		clear_bit(XMSTATE_BIT_UNS_DATA, &tcp_ctask->xmstate);
+-		/*
+-		 * Done with the Data-Out. Next, check if we need
+-		 * to send another unsolicited Data-Out.
++		/* All unsolicited PDUs sent. Check for solicited PDUs.
  		 */
--		if (le32_to_cpu(*q->headers.consumer) >= q->entries) 
--			index = 0;		
-+		if (le32_to_cpu(*q->headers.consumer) >= q->entries)
-+			index = 0;
- 		else
--		        index = le32_to_cpu(*q->headers.consumer);
-+			index = le32_to_cpu(*q->headers.consumer);
- 		*entry = q->base + index;
- 		status = 1;
- 	}
-@@ -587,12 +590,12 @@ void aac_consumer_free(struct aac_dev * dev, struct aac_queue *q, u32 qid)
- 
- 	if ((le32_to_cpu(*q->headers.producer)+1) == le32_to_cpu(*q->headers.consumer))
- 		wasfull = 1;
--        
-+
- 	if (le32_to_cpu(*q->headers.consumer) >= q->entries)
- 		*q->headers.consumer = cpu_to_le32(1);
- 	else
- 		*q->headers.consumer = cpu_to_le32(le32_to_cpu(*q->headers.consumer)+1);
--        
+-		if (ctask->unsol_count) {
+-			debug_scsi("sending more uns\n");
+-			set_bit(XMSTATE_BIT_UNS_INIT, &tcp_ctask->xmstate);
+-			goto send_hdr;
++		spin_lock_bh(&session->lock);
++		r2t = tcp_ctask->r2t;
++		if (r2t != NULL) {
++			/* Continue with this R2T? */
++			if (!iscsi_solicit_data_cont(conn, ctask, r2t)) {
++				debug_scsi("  done with r2t %p\n", r2t);
 +
- 	if (wasfull) {
- 		switch (qid) {
++				__kfifo_put(tcp_ctask->r2tpool.queue,
++					    (void*)&r2t, sizeof(void*));
++				tcp_ctask->r2t = r2t = NULL;
++			}
+ 		}
+-	}
+-	return 0;
+-}
+-
+-static int iscsi_send_sol_pdu(struct iscsi_conn *conn,
+-			      struct iscsi_cmd_task *ctask)
+-{
+-	struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
+-	struct iscsi_session *session = conn->session;
+-	struct iscsi_r2t_info *r2t;
+-	struct iscsi_data_task *dtask;
+-	int left, rc;
  
-@@ -608,7 +611,7 @@ void aac_consumer_free(struct aac_dev * dev, struct aac_queue *q, u32 qid)
+-	if (test_bit(XMSTATE_BIT_SOL_HDR_INIT, &tcp_ctask->xmstate)) {
+-		if (!tcp_ctask->r2t) {
+-			spin_lock_bh(&session->lock);
++		if (r2t == NULL) {
+ 			__kfifo_get(tcp_ctask->r2tqueue, (void*)&tcp_ctask->r2t,
+ 				    sizeof(void*));
+-			spin_unlock_bh(&session->lock);
++			r2t = tcp_ctask->r2t;
  		}
- 		aac_adapter_notify(dev, notify);
- 	}
--}        
-+}
+-send_hdr:
+-		r2t = tcp_ctask->r2t;
+-		dtask = &r2t->dtask;
+-
+-		if (conn->hdrdgst_en)
+-			iscsi_hdr_digest(conn, &r2t->headbuf,
+-					(u8*)dtask->hdrext);
+-		clear_bit(XMSTATE_BIT_SOL_HDR_INIT, &tcp_ctask->xmstate);
+-		set_bit(XMSTATE_BIT_SOL_HDR, &tcp_ctask->xmstate);
+-	}
+-
+-	if (test_bit(XMSTATE_BIT_SOL_HDR, &tcp_ctask->xmstate)) {
+-		r2t = tcp_ctask->r2t;
+-		dtask = &r2t->dtask;
+-
+-		rc = iscsi_sendhdr(conn, &r2t->headbuf, r2t->data_count);
+-		if (rc)
+-			return rc;
+-		clear_bit(XMSTATE_BIT_SOL_HDR, &tcp_ctask->xmstate);
+-		set_bit(XMSTATE_BIT_SOL_DATA, &tcp_ctask->xmstate);
++		spin_unlock_bh(&session->lock);
  
- /**
-  *	aac_fib_adapter_complete	-	complete adapter issued fib
-@@ -630,32 +633,32 @@ int aac_fib_adapter_complete(struct fib *fibptr, unsigned short size)
- 	if (hw_fib->header.XferState == 0) {
- 		if (dev->comm_interface == AAC_COMM_MESSAGE)
- 			kfree (hw_fib);
--        	return 0;
-+		return 0;
- 	}
- 	/*
- 	 *	If we plan to do anything check the structure type first.
--	 */ 
--	if ( hw_fib->header.StructType != FIB_MAGIC ) {
-+	 */
-+	if (hw_fib->header.StructType != FIB_MAGIC) {
- 		if (dev->comm_interface == AAC_COMM_MESSAGE)
- 			kfree (hw_fib);
--        	return -EINVAL;
-+		return -EINVAL;
- 	}
- 	/*
- 	 *	This block handles the case where the adapter had sent us a
- 	 *	command and we have finished processing the command. We
--	 *	call completeFib when we are done processing the command 
--	 *	and want to send a response back to the adapter. This will 
-+	 *	call completeFib when we are done processing the command
-+	 *	and want to send a response back to the adapter. This will
- 	 *	send the completed cdb to the adapter.
- 	 */
- 	if (hw_fib->header.XferState & cpu_to_le32(SentFromAdapter)) {
- 		if (dev->comm_interface == AAC_COMM_MESSAGE) {
- 			kfree (hw_fib);
- 		} else {
--	       		u32 index;
--		        hw_fib->header.XferState |= cpu_to_le32(HostProcessed);
-+			u32 index;
-+			hw_fib->header.XferState |= cpu_to_le32(HostProcessed);
- 			if (size) {
- 				size += sizeof(struct aac_fibhdr);
--				if (size > le16_to_cpu(hw_fib->header.SenderSize)) 
-+				if (size > le16_to_cpu(hw_fib->header.SenderSize))
- 					return -EMSGSIZE;
- 				hw_fib->header.Size = cpu_to_le16(size);
- 			}
-@@ -667,12 +670,11 @@ int aac_fib_adapter_complete(struct fib *fibptr, unsigned short size)
- 			if (!(nointr & (int)aac_config.irq_mod))
- 				aac_adapter_notify(dev, AdapNormRespQueue);
+-		if (conn->datadgst_en) {
+-			iscsi_data_digest_init(conn->dd_data, tcp_ctask);
+-			dtask->digest = 0;
++		/* Waiting for more R2Ts to arrive. */
++		if (r2t == NULL) {
++			debug_tcp("no R2Ts yet\n");
++			return 0;
  		}
-+	} else {
-+		printk(KERN_WARNING "aac_fib_adapter_complete: "
-+			"Unknown xferstate detected.\n");
-+		BUG();
- 	}
--	else 
--	{
--        	printk(KERN_WARNING "aac_fib_adapter_complete: Unknown xferstate detected.\n");
--        	BUG();
--	}   
- 	return 0;
- }
  
-@@ -682,7 +684,7 @@ int aac_fib_adapter_complete(struct fib *fibptr, unsigned short size)
-  *
-  *	Will do all necessary work to complete a FIB.
-  */
-- 
-+
- int aac_fib_complete(struct fib *fibptr)
- {
- 	struct hw_fib * hw_fib = fibptr->hw_fib_va;
-@@ -692,15 +694,15 @@ int aac_fib_complete(struct fib *fibptr)
- 	 */
+-		iscsi_set_padding(tcp_ctask, r2t->data_count);
+-		debug_scsi("sol dout [dsn %d itt 0x%x dlen %d sent %d]\n",
+-			r2t->solicit_datasn - 1, ctask->itt, r2t->data_count,
+-			r2t->sent);
+-	}
++		debug_scsi("sol dout %p [dsn %d itt 0x%x doff %d dlen %d]\n",
++			r2t, r2t->solicit_datasn - 1, ctask->itt,
++			r2t->data_offset + r2t->sent, r2t->data_count);
  
- 	if (hw_fib->header.XferState == 0)
--        	return 0;
-+		return 0;
- 	/*
- 	 *	If we plan to do anything check the structure type first.
--	 */ 
-+	 */
+-	if (test_bit(XMSTATE_BIT_SOL_DATA, &tcp_ctask->xmstate)) {
+-		r2t = tcp_ctask->r2t;
+-		dtask = &r2t->dtask;
++		iscsi_tcp_send_hdr_prep(conn, &r2t->dtask.hdr,
++					sizeof(struct iscsi_hdr));
  
- 	if (hw_fib->header.StructType != FIB_MAGIC)
--	        return -EINVAL;
-+		return -EINVAL;
- 	/*
--	 *	This block completes a cdb which orginated on the host and we 
-+	 *	This block completes a cdb which orginated on the host and we
- 	 *	just need to deallocate the cdb or reinit it. At this point the
- 	 *	command is complete that we had sent to the adapter and this
- 	 *	cdb could be reused.
-@@ -721,7 +723,7 @@ int aac_fib_complete(struct fib *fibptr)
- 		fib_dealloc(fibptr);
- 	} else {
- 		BUG();
--	}   
-+	}
+-		rc = iscsi_send_data(ctask, &r2t->sendbuf, &r2t->sg,
+-				     &r2t->sent, &r2t->data_count,
+-				     &dtask->digestbuf, &dtask->digest);
++		rc = iscsi_tcp_send_data_prep(conn, scsi_sglist(sc),
++					      scsi_sg_count(sc),
++					      r2t->data_offset + r2t->sent,
++					      r2t->data_count);
+ 		if (rc)
+-			return rc;
+-		clear_bit(XMSTATE_BIT_SOL_DATA, &tcp_ctask->xmstate);
+-
+-		/*
+-		 * Done with this Data-Out. Next, check if we have
+-		 * to send another Data-Out for this R2T.
+-		 */
+-		BUG_ON(r2t->data_length - r2t->sent < 0);
+-		left = r2t->data_length - r2t->sent;
+-		if (left) {
+-			iscsi_solicit_data_cont(conn, ctask, r2t, left);
+-			goto send_hdr;
+-		}
+-
+-		/*
+-		 * Done with this R2T. Check if there are more
+-		 * outstanding R2Ts ready to be processed.
+-		 */
+-		spin_lock_bh(&session->lock);
+-		tcp_ctask->r2t = NULL;
+-		__kfifo_put(tcp_ctask->r2tpool.queue, (void*)&r2t,
+-			    sizeof(void*));
+-		if (__kfifo_get(tcp_ctask->r2tqueue, (void*)&r2t,
+-				sizeof(void*))) {
+-			tcp_ctask->r2t = r2t;
+-			spin_unlock_bh(&session->lock);
+-			goto send_hdr;
+-		}
+-		spin_unlock_bh(&session->lock);
++			goto fail;
++		tcp_ctask->sent += r2t->data_count;
++		r2t->sent += r2t->data_count;
++		goto flush;
+ 	}
  	return 0;
+-}
+-
+-/**
+- * iscsi_tcp_ctask_xmit - xmit normal PDU task
+- * @conn: iscsi connection
+- * @ctask: iscsi command task
+- *
+- * Notes:
+- *	The function can return -EAGAIN in which case caller must
+- *	call it again later, or recover. '0' return code means successful
+- *	xmit.
+- *	The function is devided to logical helpers (above) for the different
+- *	xmit stages.
+- *
+- *iscsi_send_cmd_hdr()
+- *	XMSTATE_BIT_CMD_HDR_INIT - prepare Header and Data buffers Calculate
+- *	                           Header Digest
+- *	XMSTATE_BIT_CMD_HDR_XMIT - Transmit header in progress
+- *
+- *iscsi_send_padding
+- *	XMSTATE_BIT_W_PAD        - Prepare and send pading
+- *	XMSTATE_BIT_W_RESEND_PAD - retry send pading
+- *
+- *iscsi_send_digest
+- *	XMSTATE_BIT_W_RESEND_DATA_DIGEST - Finalize and send Data Digest
+- *	XMSTATE_BIT_W_RESEND_DATA_DIGEST - retry sending digest
+- *
+- *iscsi_send_unsol_hdr
+- *	XMSTATE_BIT_UNS_INIT     - prepare un-solicit data header and digest
+- *	XMSTATE_BIT_UNS_HDR      - send un-solicit header
+- *
+- *iscsi_send_unsol_pdu
+- *	XMSTATE_BIT_UNS_DATA     - send un-solicit data in progress
+- *
+- *iscsi_send_sol_pdu
+- *	XMSTATE_BIT_SOL_HDR_INIT - solicit data header and digest initialize
+- *	XMSTATE_BIT_SOL_HDR      - send solicit header
+- *	XMSTATE_BIT_SOL_DATA     - send solicit data
+- *
+- *iscsi_tcp_ctask_xmit
+- *	XMSTATE_BIT_IMM_DATA     - xmit managment data (??)
+- **/
+-static int
+-iscsi_tcp_ctask_xmit(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
+-{
+-	struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
+-	int rc = 0;
+-
+-	debug_scsi("ctask deq [cid %d xmstate %x itt 0x%x]\n",
+-		conn->id, tcp_ctask->xmstate, ctask->itt);
+-
+-	rc = iscsi_send_cmd_hdr(conn, ctask);
+-	if (rc)
+-		return rc;
+-	if (ctask->sc->sc_data_direction != DMA_TO_DEVICE)
+-		return 0;
+-
+-	if (test_bit(XMSTATE_BIT_IMM_DATA, &tcp_ctask->xmstate)) {
+-		rc = iscsi_send_data(ctask, &tcp_ctask->sendbuf, &tcp_ctask->sg,
+-				     &tcp_ctask->sent, &ctask->imm_count,
+-				     &tcp_ctask->immbuf, &tcp_ctask->immdigest);
+-		if (rc)
+-			return rc;
+-		clear_bit(XMSTATE_BIT_IMM_DATA, &tcp_ctask->xmstate);
+-	}
+-
+-	rc = iscsi_send_unsol_pdu(conn, ctask);
+-	if (rc)
+-		return rc;
+-
+-	rc = iscsi_send_sol_pdu(conn, ctask);
+-	if (rc)
+-		return rc;
+-
+-	return rc;
++fail:
++	iscsi_conn_failure(conn, rc);
++	return -EIO;
  }
  
-@@ -741,7 +743,7 @@ void aac_printf(struct aac_dev *dev, u32 val)
- 	{
- 		int length = val & 0xffff;
- 		int level = (val >> 16) & 0xffff;
--		
-+
- 		/*
- 		 *	The size of the printfbuf is set in port.c
- 		 *	There is no variable or define for it
-@@ -755,7 +757,7 @@ void aac_printf(struct aac_dev *dev, u32 val)
- 		else
- 			printk(KERN_INFO "%s:%s", dev->name, cp);
- 	}
--	memset(cp, 0,  256);
-+	memset(cp, 0, 256);
- }
+ static struct iscsi_cls_conn *
+@@ -1784,9 +1492,6 @@ iscsi_tcp_conn_create(struct iscsi_cls_session *cls_session, uint32_t conn_idx)
  
+ 	conn->dd_data = tcp_conn;
+ 	tcp_conn->iscsi_conn = conn;
+-	tcp_conn->in_progress = IN_PROGRESS_WAIT_HEADER;
+-	/* initial operational parameters */
+-	tcp_conn->hdr_size = sizeof(struct iscsi_hdr);
  
-@@ -773,20 +775,20 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
+ 	tcp_conn->tx_hash.tfm = crypto_alloc_hash("crc32c", 0,
+ 						  CRYPTO_ALG_ASYNC);
+@@ -1863,11 +1568,9 @@ static void
+ iscsi_tcp_conn_stop(struct iscsi_cls_conn *cls_conn, int flag)
  {
- 	struct hw_fib * hw_fib = fibptr->hw_fib_va;
- 	struct aac_aifcmd * aifcmd = (struct aac_aifcmd *)hw_fib->data;
--	u32 container;
-+	u32 channel, id, lun, container;
- 	struct scsi_device *device;
- 	enum {
- 		NOTHING,
- 		DELETE,
- 		ADD,
- 		CHANGE
--	} device_config_needed;
-+	} device_config_needed = NOTHING;
- 
- 	/* Sniff for container changes */
+ 	struct iscsi_conn *conn = cls_conn->dd_data;
+-	struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
  
- 	if (!dev || !dev->fsa_dev)
- 		return;
--	container = (u32)-1;
-+	container = channel = id = lun = (u32)-1;
+ 	iscsi_conn_stop(cls_conn, flag);
+ 	iscsi_tcp_release_conn(conn);
+-	tcp_conn->hdr_size = sizeof(struct iscsi_hdr);
+ }
  
+ static int iscsi_tcp_get_addr(struct iscsi_conn *conn, struct socket *sock,
+@@ -1967,7 +1670,7 @@ iscsi_tcp_conn_bind(struct iscsi_cls_session *cls_session,
  	/*
- 	 *	We have set this up to try and minimize the number of
-@@ -796,13 +798,13 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
+ 	 * set receive state machine into initial state
  	 */
- 	switch (le32_to_cpu(aifcmd->command)) {
- 	case AifCmdDriverNotify:
--		switch (le32_to_cpu(((u32 *)aifcmd->data)[0])) {
-+		switch (le32_to_cpu(((__le32 *)aifcmd->data)[0])) {
- 		/*
- 		 *	Morph or Expand complete
- 		 */
- 		case AifDenMorphComplete:
- 		case AifDenVolumeExtendComplete:
--			container = le32_to_cpu(((u32 *)aifcmd->data)[1]);
-+			container = le32_to_cpu(((__le32 *)aifcmd->data)[1]);
- 			if (container >= dev->maximum_num_containers)
- 				break;
- 
-@@ -814,9 +816,9 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
- 			 */
- 
- 			if ((dev != NULL) && (dev->scsi_host_ptr != NULL)) {
--				device = scsi_device_lookup(dev->scsi_host_ptr, 
--					CONTAINER_TO_CHANNEL(container), 
--					CONTAINER_TO_ID(container), 
-+				device = scsi_device_lookup(dev->scsi_host_ptr,
-+					CONTAINER_TO_CHANNEL(container),
-+					CONTAINER_TO_ID(container),
- 					CONTAINER_TO_LUN(container));
- 				if (device) {
- 					dev->fsa_dev[container].config_needed = CHANGE;
-@@ -835,25 +837,29 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
- 			if (container >= dev->maximum_num_containers)
- 				break;
- 			if ((dev->fsa_dev[container].config_waiting_on ==
--			    le32_to_cpu(*(u32 *)aifcmd->data)) &&
-+			    le32_to_cpu(*(__le32 *)aifcmd->data)) &&
- 			 time_before(jiffies, dev->fsa_dev[container].config_waiting_stamp + AIF_SNIFF_TIMEOUT))
- 				dev->fsa_dev[container].config_waiting_on = 0;
- 		} else for (container = 0;
- 		    container < dev->maximum_num_containers; ++container) {
- 			if ((dev->fsa_dev[container].config_waiting_on ==
--			    le32_to_cpu(*(u32 *)aifcmd->data)) &&
-+			    le32_to_cpu(*(__le32 *)aifcmd->data)) &&
- 			 time_before(jiffies, dev->fsa_dev[container].config_waiting_stamp + AIF_SNIFF_TIMEOUT))
- 				dev->fsa_dev[container].config_waiting_on = 0;
- 		}
- 		break;
+-	tcp_conn->in_progress = IN_PROGRESS_WAIT_HEADER;
++	iscsi_tcp_hdr_recv_prep(tcp_conn);
+ 	return 0;
  
- 	case AifCmdEventNotify:
--		switch (le32_to_cpu(((u32 *)aifcmd->data)[0])) {
-+		switch (le32_to_cpu(((__le32 *)aifcmd->data)[0])) {
-+		case AifEnBatteryEvent:
-+			dev->cache_protected =
-+				(((__le32 *)aifcmd->data)[1] == cpu_to_le32(3));
-+			break;
- 		/*
- 		 *	Add an Array.
- 		 */
- 		case AifEnAddContainer:
--			container = le32_to_cpu(((u32 *)aifcmd->data)[1]);
-+			container = le32_to_cpu(((__le32 *)aifcmd->data)[1]);
- 			if (container >= dev->maximum_num_containers)
- 				break;
- 			dev->fsa_dev[container].config_needed = ADD;
-@@ -866,7 +872,7 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
- 		 *	Delete an Array.
- 		 */
- 		case AifEnDeleteContainer:
--			container = le32_to_cpu(((u32 *)aifcmd->data)[1]);
-+			container = le32_to_cpu(((__le32 *)aifcmd->data)[1]);
- 			if (container >= dev->maximum_num_containers)
- 				break;
- 			dev->fsa_dev[container].config_needed = DELETE;
-@@ -880,7 +886,7 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
- 		 * waiting on something else, setup to wait on a Config Change.
- 		 */
- 		case AifEnContainerChange:
--			container = le32_to_cpu(((u32 *)aifcmd->data)[1]);
-+			container = le32_to_cpu(((__le32 *)aifcmd->data)[1]);
- 			if (container >= dev->maximum_num_containers)
- 				break;
- 			if (dev->fsa_dev[container].config_waiting_on &&
-@@ -895,6 +901,60 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
- 		case AifEnConfigChange:
- 			break;
+ free_socket:
+@@ -1977,10 +1680,17 @@ free_socket:
  
-+		case AifEnAddJBOD:
-+		case AifEnDeleteJBOD:
-+			container = le32_to_cpu(((__le32 *)aifcmd->data)[1]);
-+			if ((container >> 28))
-+				break;
-+			channel = (container >> 24) & 0xF;
-+			if (channel >= dev->maximum_num_channels)
-+				break;
-+			id = container & 0xFFFF;
-+			if (id >= dev->maximum_num_physicals)
-+				break;
-+			lun = (container >> 16) & 0xFF;
-+			channel = aac_phys_to_logical(channel);
-+			device_config_needed =
-+			  (((__le32 *)aifcmd->data)[0] ==
-+			    cpu_to_le32(AifEnAddJBOD)) ? ADD : DELETE;
-+			break;
+ /* called with host lock */
+ static void
+-iscsi_tcp_mgmt_init(struct iscsi_conn *conn, struct iscsi_mgmt_task *mtask)
++iscsi_tcp_mtask_init(struct iscsi_conn *conn, struct iscsi_mgmt_task *mtask)
+ {
+-	struct iscsi_tcp_mgmt_task *tcp_mtask = mtask->dd_data;
+-	tcp_mtask->xmstate = 1 << XMSTATE_BIT_IMM_HDR_INIT;
++	debug_scsi("mtask deq [cid %d itt 0x%x]\n", conn->id, mtask->itt);
 +
-+		case AifEnEnclosureManagement:
-+			/*
-+			 * If in JBOD mode, automatic exposure of new
-+			 * physical target to be suppressed until configured.
-+			 */
-+			if (dev->jbod)
-+				break;
-+			switch (le32_to_cpu(((__le32 *)aifcmd->data)[3])) {
-+			case EM_DRIVE_INSERTION:
-+			case EM_DRIVE_REMOVAL:
-+				container = le32_to_cpu(
-+					((__le32 *)aifcmd->data)[2]);
-+				if ((container >> 28))
-+					break;
-+				channel = (container >> 24) & 0xF;
-+				if (channel >= dev->maximum_num_channels)
-+					break;
-+				id = container & 0xFFFF;
-+				lun = (container >> 16) & 0xFF;
-+				if (id >= dev->maximum_num_physicals) {
-+					/* legacy dev_t ? */
-+					if ((0x2000 <= id) || lun || channel ||
-+					  ((channel = (id >> 7) & 0x3F) >=
-+					  dev->maximum_num_channels))
-+						break;
-+					lun = (id >> 4) & 7;
-+					id &= 0xF;
-+				}
-+				channel = aac_phys_to_logical(channel);
-+				device_config_needed =
-+				  (((__le32 *)aifcmd->data)[3]
-+				    == cpu_to_le32(EM_DRIVE_INSERTION)) ?
-+				  ADD : DELETE;
-+				break;
-+			}
-+			break;
- 		}
++	/* Prepare PDU, optionally w/ immediate data */
++	iscsi_tcp_send_hdr_prep(conn, mtask->hdr, sizeof(*mtask->hdr));
++
++	/* If we have immediate data, attach a payload */
++	if (mtask->data_count)
++		iscsi_tcp_send_linear_data_prepare(conn, mtask->data,
++						   mtask->data_count);
+ }
  
- 		/*
-@@ -905,13 +965,13 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
- 			if (container >= dev->maximum_num_containers)
- 				break;
- 			if ((dev->fsa_dev[container].config_waiting_on ==
--			    le32_to_cpu(*(u32 *)aifcmd->data)) &&
-+			    le32_to_cpu(*(__le32 *)aifcmd->data)) &&
- 			 time_before(jiffies, dev->fsa_dev[container].config_waiting_stamp + AIF_SNIFF_TIMEOUT))
- 				dev->fsa_dev[container].config_waiting_on = 0;
- 		} else for (container = 0;
- 		    container < dev->maximum_num_containers; ++container) {
- 			if ((dev->fsa_dev[container].config_waiting_on ==
--			    le32_to_cpu(*(u32 *)aifcmd->data)) &&
-+			    le32_to_cpu(*(__le32 *)aifcmd->data)) &&
- 			 time_before(jiffies, dev->fsa_dev[container].config_waiting_stamp + AIF_SNIFF_TIMEOUT))
- 				dev->fsa_dev[container].config_waiting_on = 0;
- 		}
-@@ -926,9 +986,9 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
- 		 * wait for a container change.
+ static int
+@@ -2003,8 +1713,7 @@ iscsi_r2tpool_alloc(struct iscsi_session *session)
  		 */
  
--		if ((((u32 *)aifcmd->data)[1] == cpu_to_le32(AifJobCtrZero))
--		 && ((((u32 *)aifcmd->data)[6] == ((u32 *)aifcmd->data)[5])
--		  || (((u32 *)aifcmd->data)[4] == cpu_to_le32(AifJobStsSuccess)))) {
-+		if (((__le32 *)aifcmd->data)[1] == cpu_to_le32(AifJobCtrZero) &&
-+		    (((__le32 *)aifcmd->data)[6] == ((__le32 *)aifcmd->data)[5] ||
-+		     ((__le32 *)aifcmd->data)[4] == cpu_to_le32(AifJobStsSuccess))) {
- 			for (container = 0;
- 			    container < dev->maximum_num_containers;
- 			    ++container) {
-@@ -943,9 +1003,9 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
- 					jiffies;
- 			}
+ 		/* R2T pool */
+-		if (iscsi_pool_init(&tcp_ctask->r2tpool, session->max_r2t * 4,
+-				    (void***)&tcp_ctask->r2ts,
++		if (iscsi_pool_init(&tcp_ctask->r2tpool, session->max_r2t * 4, NULL,
+ 				    sizeof(struct iscsi_r2t_info))) {
+ 			goto r2t_alloc_fail;
  		}
--		if ((((u32 *)aifcmd->data)[1] == cpu_to_le32(AifJobCtrZero))
--		 && (((u32 *)aifcmd->data)[6] == 0)
--		 && (((u32 *)aifcmd->data)[4] == cpu_to_le32(AifJobStsRunning))) {
-+		if (((__le32 *)aifcmd->data)[1] == cpu_to_le32(AifJobCtrZero) &&
-+		    ((__le32 *)aifcmd->data)[6] == 0 &&
-+		    ((__le32 *)aifcmd->data)[4] == cpu_to_le32(AifJobStsRunning)) {
- 			for (container = 0;
- 			    container < dev->maximum_num_containers;
- 			    ++container) {
-@@ -963,7 +1023,7 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
- 		break;
- 	}
- 
--	device_config_needed = NOTHING;
-+	if (device_config_needed == NOTHING)
- 	for (container = 0; container < dev->maximum_num_containers;
- 	    ++container) {
- 		if ((dev->fsa_dev[container].config_waiting_on == 0) &&
-@@ -972,6 +1032,9 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
- 			device_config_needed =
- 				dev->fsa_dev[container].config_needed;
- 			dev->fsa_dev[container].config_needed = NOTHING;
-+			channel = CONTAINER_TO_CHANNEL(container);
-+			id = CONTAINER_TO_ID(container);
-+			lun = CONTAINER_TO_LUN(container);
- 			break;
+@@ -2013,8 +1722,7 @@ iscsi_r2tpool_alloc(struct iscsi_session *session)
+ 		tcp_ctask->r2tqueue = kfifo_alloc(
+ 		      session->max_r2t * 4 * sizeof(void*), GFP_KERNEL, NULL);
+ 		if (tcp_ctask->r2tqueue == ERR_PTR(-ENOMEM)) {
+-			iscsi_pool_free(&tcp_ctask->r2tpool,
+-					(void**)tcp_ctask->r2ts);
++			iscsi_pool_free(&tcp_ctask->r2tpool);
+ 			goto r2t_alloc_fail;
  		}
  	}
-@@ -995,34 +1058,56 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
- 	/*
- 	 * force reload of disk info via aac_probe_container
- 	 */
--	if ((device_config_needed == CHANGE)
--	 && (dev->fsa_dev[container].valid == 1))
--		dev->fsa_dev[container].valid = 2;
--	if ((device_config_needed == CHANGE) ||
--			(device_config_needed == ADD))
-+	if ((channel == CONTAINER_CHANNEL) &&
-+	  (device_config_needed != NOTHING)) {
-+		if (dev->fsa_dev[container].valid == 1)
-+			dev->fsa_dev[container].valid = 2;
- 		aac_probe_container(dev, container);
--	device = scsi_device_lookup(dev->scsi_host_ptr, 
--		CONTAINER_TO_CHANNEL(container), 
--		CONTAINER_TO_ID(container), 
--		CONTAINER_TO_LUN(container));
-+	}
-+	device = scsi_device_lookup(dev->scsi_host_ptr, channel, id, lun);
- 	if (device) {
- 		switch (device_config_needed) {
- 		case DELETE:
-+			if (scsi_device_online(device)) {
-+				scsi_device_set_state(device, SDEV_OFFLINE);
-+				sdev_printk(KERN_INFO, device,
-+					"Device offlined - %s\n",
-+					(channel == CONTAINER_CHANNEL) ?
-+						"array deleted" :
-+						"enclosure services event");
-+			}
-+			break;
-+		case ADD:
-+			if (!scsi_device_online(device)) {
-+				sdev_printk(KERN_INFO, device,
-+					"Device online - %s\n",
-+					(channel == CONTAINER_CHANNEL) ?
-+						"array created" :
-+						"enclosure services event");
-+				scsi_device_set_state(device, SDEV_RUNNING);
-+			}
-+			/* FALLTHRU */
- 		case CHANGE:
-+			if ((channel == CONTAINER_CHANNEL)
-+			 && (!dev->fsa_dev[container].valid)) {
-+				if (!scsi_device_online(device))
-+					break;
-+				scsi_device_set_state(device, SDEV_OFFLINE);
-+				sdev_printk(KERN_INFO, device,
-+					"Device offlined - %s\n",
-+					"array failed");
-+				break;
-+			}
- 			scsi_rescan_device(&device->sdev_gendev);
+@@ -2027,8 +1735,7 @@ r2t_alloc_fail:
+ 		struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
  
- 		default:
- 			break;
- 		}
- 		scsi_device_put(device);
-+		device_config_needed = NOTHING;
+ 		kfifo_free(tcp_ctask->r2tqueue);
+-		iscsi_pool_free(&tcp_ctask->r2tpool,
+-				(void**)tcp_ctask->r2ts);
++		iscsi_pool_free(&tcp_ctask->r2tpool);
  	}
--	if (device_config_needed == ADD) {
--		scsi_add_device(dev->scsi_host_ptr,
--		  CONTAINER_TO_CHANNEL(container),
--		  CONTAINER_TO_ID(container),
--		  CONTAINER_TO_LUN(container));
--	}
--
-+	if (device_config_needed == ADD)
-+		scsi_add_device(dev->scsi_host_ptr, channel, id, lun);
+ 	return -ENOMEM;
  }
+@@ -2043,8 +1750,7 @@ iscsi_r2tpool_free(struct iscsi_session *session)
+ 		struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
  
- static int _aac_reset_adapter(struct aac_dev *aac, int forced)
-@@ -1099,7 +1184,8 @@ static int _aac_reset_adapter(struct aac_dev *aac, int forced)
- 	free_irq(aac->pdev->irq, aac);
- 	kfree(aac->fsa_dev);
- 	aac->fsa_dev = NULL;
--	if (aac_get_driver_ident(index)->quirks & AAC_QUIRK_31BIT) {
-+	quirks = aac_get_driver_ident(index)->quirks;
-+	if (quirks & AAC_QUIRK_31BIT) {
- 		if (((retval = pci_set_dma_mask(aac->pdev, DMA_31BIT_MASK))) ||
- 		  ((retval = pci_set_consistent_dma_mask(aac->pdev, DMA_31BIT_MASK))))
- 			goto out;
-@@ -1110,7 +1196,7 @@ static int _aac_reset_adapter(struct aac_dev *aac, int forced)
- 	}
- 	if ((retval = (*(aac_get_driver_ident(index)->init))(aac)))
- 		goto out;
--	if (aac_get_driver_ident(index)->quirks & AAC_QUIRK_31BIT)
-+	if (quirks & AAC_QUIRK_31BIT)
- 		if ((retval = pci_set_dma_mask(aac->pdev, DMA_32BIT_MASK)))
- 			goto out;
- 	if (jafo) {
-@@ -1121,15 +1207,14 @@ static int _aac_reset_adapter(struct aac_dev *aac, int forced)
- 		}
+ 		kfifo_free(tcp_ctask->r2tqueue);
+-		iscsi_pool_free(&tcp_ctask->r2tpool,
+-				(void**)tcp_ctask->r2ts);
++		iscsi_pool_free(&tcp_ctask->r2tpool);
  	}
- 	(void)aac_get_adapter_info(aac);
--	quirks = aac_get_driver_ident(index)->quirks;
- 	if ((quirks & AAC_QUIRK_34SG) && (host->sg_tablesize > 34)) {
-- 		host->sg_tablesize = 34;
-- 		host->max_sectors = (host->sg_tablesize * 8) + 112;
-- 	}
-- 	if ((quirks & AAC_QUIRK_17SG) && (host->sg_tablesize > 17)) {
-- 		host->sg_tablesize = 17;
-- 		host->max_sectors = (host->sg_tablesize * 8) + 112;
-- 	}
-+		host->sg_tablesize = 34;
-+		host->max_sectors = (host->sg_tablesize * 8) + 112;
-+	}
-+	if ((quirks & AAC_QUIRK_17SG) && (host->sg_tablesize > 17)) {
-+		host->sg_tablesize = 17;
-+		host->max_sectors = (host->sg_tablesize * 8) + 112;
-+	}
- 	aac_get_config_status(aac, 1);
- 	aac_get_containers(aac);
- 	/*
-@@ -1217,12 +1302,13 @@ int aac_reset_adapter(struct aac_dev * aac, int forced)
+ }
+ 
+@@ -2060,9 +1766,6 @@ iscsi_conn_set_param(struct iscsi_cls_conn *cls_conn, enum iscsi_param param,
+ 	switch(param) {
+ 	case ISCSI_PARAM_HDRDGST_EN:
+ 		iscsi_set_param(cls_conn, param, buf, buflen);
+-		tcp_conn->hdr_size = sizeof(struct iscsi_hdr);
+-		if (conn->hdrdgst_en)
+-			tcp_conn->hdr_size += sizeof(__u32);
+ 		break;
+ 	case ISCSI_PARAM_DATADGST_EN:
+ 		iscsi_set_param(cls_conn, param, buf, buflen);
+@@ -2071,12 +1774,12 @@ iscsi_conn_set_param(struct iscsi_cls_conn *cls_conn, enum iscsi_param param,
+ 		break;
+ 	case ISCSI_PARAM_MAX_R2T:
+ 		sscanf(buf, "%d", &value);
+-		if (session->max_r2t == roundup_pow_of_two(value))
++		if (value <= 0 || !is_power_of_2(value))
++			return -EINVAL;
++		if (session->max_r2t == value)
+ 			break;
+ 		iscsi_r2tpool_free(session);
+ 		iscsi_set_param(cls_conn, param, buf, buflen);
+-		if (session->max_r2t & (session->max_r2t - 1))
+-			session->max_r2t = roundup_pow_of_two(session->max_r2t);
+ 		if (iscsi_r2tpool_alloc(session))
+ 			return -ENOMEM;
+ 		break;
+@@ -2183,14 +1886,15 @@ iscsi_tcp_session_create(struct iscsi_transport *iscsit,
+ 		struct iscsi_cmd_task *ctask = session->cmds[cmd_i];
+ 		struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
+ 
+-		ctask->hdr = &tcp_ctask->hdr;
++		ctask->hdr = &tcp_ctask->hdr.cmd_hdr;
++		ctask->hdr_max = sizeof(tcp_ctask->hdr) - ISCSI_DIGEST_SIZE;
  	}
  
- 	/* Quiesce build, flush cache, write through mode */
--	aac_send_shutdown(aac);
-+	if (forced < 2)
-+		aac_send_shutdown(aac);
- 	spin_lock_irqsave(host->host_lock, flagv);
--	retval = _aac_reset_adapter(aac, forced);
-+	retval = _aac_reset_adapter(aac, forced ? forced : ((aac_check_reset != 0) && (aac_check_reset != 1)));
- 	spin_unlock_irqrestore(host->host_lock, flagv);
+ 	for (cmd_i = 0; cmd_i < session->mgmtpool_max; cmd_i++) {
+ 		struct iscsi_mgmt_task *mtask = session->mgmt_cmds[cmd_i];
+ 		struct iscsi_tcp_mgmt_task *tcp_mtask = mtask->dd_data;
  
--	if (retval == -ENODEV) {
-+	if ((forced < 2) && (retval == -ENODEV)) {
- 		/* Unwind aac_send_shutdown() IOP_RESET unsupported/disabled */
- 		struct fib * fibctx = aac_fib_alloc(aac);
- 		if (fibctx) {
-@@ -1338,11 +1424,11 @@ int aac_check_health(struct aac_dev * aac)
- 			fib->data = hw_fib->data;
- 			aif = (struct aac_aifcmd *)hw_fib->data;
- 			aif->command = cpu_to_le32(AifCmdEventNotify);
--		 	aif->seqnum = cpu_to_le32(0xFFFFFFFF);
--			aif->data[0] = AifEnExpEvent;
--			aif->data[1] = AifExeFirmwarePanic;
--			aif->data[2] = AifHighPriority;
--			aif->data[3] = BlinkLED;
-+			aif->seqnum = cpu_to_le32(0xFFFFFFFF);
-+			((__le32 *)aif->data)[0] = cpu_to_le32(AifEnExpEvent);
-+			((__le32 *)aif->data)[1] = cpu_to_le32(AifExeFirmwarePanic);
-+			((__le32 *)aif->data)[2] = cpu_to_le32(AifHighPriority);
-+			((__le32 *)aif->data)[3] = cpu_to_le32(BlinkLED);
+-		mtask->hdr = &tcp_mtask->hdr;
++		mtask->hdr = (struct iscsi_hdr *) &tcp_mtask->hdr;
+ 	}
  
- 			/*
- 			 * Put the FIB onto the
-@@ -1372,14 +1458,14 @@ int aac_check_health(struct aac_dev * aac)
+ 	if (iscsi_r2tpool_alloc(class_to_transport_session(cls_session)))
+@@ -2222,12 +1926,14 @@ static struct scsi_host_template iscsi_sht = {
+ 	.queuecommand           = iscsi_queuecommand,
+ 	.change_queue_depth	= iscsi_change_queue_depth,
+ 	.can_queue		= ISCSI_DEF_XMIT_CMDS_MAX - 1,
+-	.sg_tablesize		= ISCSI_SG_TABLESIZE,
++	.sg_tablesize		= 4096,
+ 	.max_sectors		= 0xFFFF,
+ 	.cmd_per_lun		= ISCSI_DEF_CMD_PER_LUN,
+ 	.eh_abort_handler       = iscsi_eh_abort,
++	.eh_device_reset_handler= iscsi_eh_device_reset,
+ 	.eh_host_reset_handler	= iscsi_eh_host_reset,
+ 	.use_clustering         = DISABLE_CLUSTERING,
++	.use_sg_chaining	= ENABLE_SG_CHAINING,
+ 	.slave_configure        = iscsi_tcp_slave_configure,
+ 	.proc_name		= "iscsi_tcp",
+ 	.this_id		= -1,
+@@ -2257,14 +1963,17 @@ static struct iscsi_transport iscsi_tcp_transport = {
+ 				  ISCSI_PERSISTENT_ADDRESS |
+ 				  ISCSI_TARGET_NAME | ISCSI_TPGT |
+ 				  ISCSI_USERNAME | ISCSI_PASSWORD |
+-				  ISCSI_USERNAME_IN | ISCSI_PASSWORD_IN,
++				  ISCSI_USERNAME_IN | ISCSI_PASSWORD_IN |
++				  ISCSI_FAST_ABORT | ISCSI_ABORT_TMO |
++				  ISCSI_LU_RESET_TMO |
++				  ISCSI_PING_TMO | ISCSI_RECV_TMO,
+ 	.host_param_mask	= ISCSI_HOST_HWADDRESS | ISCSI_HOST_IPADDRESS |
+ 				  ISCSI_HOST_INITIATOR_NAME |
+ 				  ISCSI_HOST_NETDEV_NAME,
+ 	.host_template		= &iscsi_sht,
+ 	.conndata_size		= sizeof(struct iscsi_conn),
+ 	.max_conn		= 1,
+-	.max_cmd_len		= ISCSI_TCP_MAX_CMD_LEN,
++	.max_cmd_len		= 16,
+ 	/* session management */
+ 	.create_session		= iscsi_tcp_session_create,
+ 	.destroy_session	= iscsi_tcp_session_destroy,
+@@ -2283,8 +1992,8 @@ static struct iscsi_transport iscsi_tcp_transport = {
+ 	/* IO */
+ 	.send_pdu		= iscsi_conn_send_pdu,
+ 	.get_stats		= iscsi_conn_get_stats,
+-	.init_cmd_task		= iscsi_tcp_cmd_init,
+-	.init_mgmt_task		= iscsi_tcp_mgmt_init,
++	.init_cmd_task		= iscsi_tcp_ctask_init,
++	.init_mgmt_task		= iscsi_tcp_mtask_init,
+ 	.xmit_cmd_task		= iscsi_tcp_ctask_xmit,
+ 	.xmit_mgmt_task		= iscsi_tcp_mtask_xmit,
+ 	.cleanup_cmd_task	= iscsi_tcp_cleanup_ctask,
+diff --git a/drivers/scsi/iscsi_tcp.h b/drivers/scsi/iscsi_tcp.h
+index 68c36cc..ed0b991 100644
+--- a/drivers/scsi/iscsi_tcp.h
++++ b/drivers/scsi/iscsi_tcp.h
+@@ -24,71 +24,61 @@
  
- 	printk(KERN_ERR "%s: Host adapter BLINK LED 0x%x\n", aac->name, BlinkLED);
+ #include <scsi/libiscsi.h>
  
--	if (!aac_check_reset ||
-+	if (!aac_check_reset || ((aac_check_reset != 1) &&
- 		(aac->supplement_adapter_info.SupportedOptions2 &
--			le32_to_cpu(AAC_OPTION_IGNORE_RESET)))
-+			AAC_OPTION_IGNORE_RESET)))
- 		goto out;
- 	host = aac->scsi_host_ptr;
- 	if (aac->thread->pid != current->pid)
- 		spin_lock_irqsave(host->host_lock, flagv);
--	BlinkLED = _aac_reset_adapter(aac, 0);
-+	BlinkLED = _aac_reset_adapter(aac, aac_check_reset != 1);
- 	if (aac->thread->pid != current->pid)
- 		spin_unlock_irqrestore(host->host_lock, flagv);
- 	return BlinkLED;
-@@ -1399,7 +1485,7 @@ out:
-  *	until the queue is empty. When the queue is empty it will wait for
-  *	more FIBs.
-  */
-- 
+-/* Socket's Receive state machine */
+-#define IN_PROGRESS_WAIT_HEADER		0x0
+-#define IN_PROGRESS_HEADER_GATHER	0x1
+-#define IN_PROGRESS_DATA_RECV		0x2
+-#define IN_PROGRESS_DDIGEST_RECV	0x3
+-#define IN_PROGRESS_PAD_RECV		0x4
+-
+-/* xmit state machine */
+-#define XMSTATE_VALUE_IDLE			0
+-#define XMSTATE_BIT_CMD_HDR_INIT		0
+-#define XMSTATE_BIT_CMD_HDR_XMIT		1
+-#define XMSTATE_BIT_IMM_HDR			2
+-#define XMSTATE_BIT_IMM_DATA			3
+-#define XMSTATE_BIT_UNS_INIT			4
+-#define XMSTATE_BIT_UNS_HDR			5
+-#define XMSTATE_BIT_UNS_DATA			6
+-#define XMSTATE_BIT_SOL_HDR			7
+-#define XMSTATE_BIT_SOL_DATA			8
+-#define XMSTATE_BIT_W_PAD			9
+-#define XMSTATE_BIT_W_RESEND_PAD		10
+-#define XMSTATE_BIT_W_RESEND_DATA_DIGEST	11
+-#define XMSTATE_BIT_IMM_HDR_INIT		12
+-#define XMSTATE_BIT_SOL_HDR_INIT		13
+-
+-#define ISCSI_PAD_LEN			4
+-#define ISCSI_SG_TABLESIZE		SG_ALL
+-#define ISCSI_TCP_MAX_CMD_LEN		16
+-
+ struct crypto_hash;
+ struct socket;
++struct iscsi_tcp_conn;
++struct iscsi_segment;
 +
- int aac_command_thread(void *data)
- {
- 	struct aac_dev *dev = data;
-@@ -1425,30 +1511,29 @@ int aac_command_thread(void *data)
- 	add_wait_queue(&dev->queues->queue[HostNormCmdQueue].cmdready, &wait);
- 	set_current_state(TASK_INTERRUPTIBLE);
- 	dprintk ((KERN_INFO "aac_command_thread start\n"));
--	while(1) 
--	{
-+	while (1) {
- 		spin_lock_irqsave(dev->queues->queue[HostNormCmdQueue].lock, flags);
- 		while(!list_empty(&(dev->queues->queue[HostNormCmdQueue].cmdq))) {
- 			struct list_head *entry;
- 			struct aac_aifcmd * aifcmd;
- 
- 			set_current_state(TASK_RUNNING);
--	
++typedef int iscsi_segment_done_fn_t(struct iscsi_tcp_conn *,
++				    struct iscsi_segment *);
 +
- 			entry = dev->queues->queue[HostNormCmdQueue].cmdq.next;
- 			list_del(entry);
--		
++struct iscsi_segment {
++	unsigned char		*data;
++	unsigned int		size;
++	unsigned int		copied;
++	unsigned int		total_size;
++	unsigned int		total_copied;
 +
- 			spin_unlock_irqrestore(dev->queues->queue[HostNormCmdQueue].lock, flags);
- 			fib = list_entry(entry, struct fib, fiblink);
- 			/*
--			 *	We will process the FIB here or pass it to a 
--			 *	worker thread that is TBD. We Really can't 
-+			 *	We will process the FIB here or pass it to a
-+			 *	worker thread that is TBD. We Really can't
- 			 *	do anything at this point since we don't have
- 			 *	anything defined for this thread to do.
- 			 */
- 			hw_fib = fib->hw_fib_va;
- 			memset(fib, 0, sizeof(struct fib));
- 			fib->type = FSAFS_NTC_FIB_CONTEXT;
--			fib->size = sizeof( struct fib );
-+			fib->size = sizeof(struct fib);
- 			fib->hw_fib_va = hw_fib;
- 			fib->data = hw_fib->data;
- 			fib->dev = dev;
-@@ -1462,20 +1547,19 @@ int aac_command_thread(void *data)
- 				*(__le32 *)hw_fib->data = cpu_to_le32(ST_OK);
- 				aac_fib_adapter_complete(fib, (u16)sizeof(u32));
- 			} else {
--				struct list_head *entry;
- 				/* The u32 here is important and intended. We are using
- 				   32bit wrapping time to fit the adapter field */
--				   
++	struct hash_desc	*hash;
++	unsigned char		recv_digest[ISCSI_DIGEST_SIZE];
++	unsigned char		digest[ISCSI_DIGEST_SIZE];
++	unsigned int		digest_len;
 +
- 				u32 time_now, time_last;
- 				unsigned long flagv;
- 				unsigned num;
- 				struct hw_fib ** hw_fib_pool, ** hw_fib_p;
- 				struct fib ** fib_pool, ** fib_p;
--			
++	struct scatterlist	*sg;
++	void			*sg_mapped;
++	unsigned int		sg_offset;
++
++	iscsi_segment_done_fn_t	*done;
++};
+ 
+ /* Socket connection recieve helper */
+ struct iscsi_tcp_recv {
+ 	struct iscsi_hdr	*hdr;
+-	struct sk_buff		*skb;
+-	int			offset;
+-	int			len;
+-	int			hdr_offset;
+-	int			copy;
+-	int			copied;
+-	int			padding;
+-	struct iscsi_cmd_task	*ctask;		/* current cmd in progress */
++	struct iscsi_segment	segment;
 +
- 				/* Sniff events */
--				if ((aifcmd->command == 
-+				if ((aifcmd->command ==
- 				     cpu_to_le32(AifCmdEventNotify)) ||
--				    (aifcmd->command == 
-+				    (aifcmd->command ==
- 				     cpu_to_le32(AifCmdJobProgress))) {
- 					aac_handle_aif(dev, fib);
- 				}
-@@ -1527,7 +1611,7 @@ int aac_command_thread(void *data)
- 				spin_lock_irqsave(&dev->fib_lock, flagv);
- 				entry = dev->fib_list.next;
- 				/*
--				 * For each Context that is on the 
-+				 * For each Context that is on the
- 				 * fibctxList, make a copy of the
- 				 * fib, and then set the event to wake up the
- 				 * thread that is waiting for it.
-@@ -1552,7 +1636,7 @@ int aac_command_thread(void *data)
- 						 */
- 						time_last = fibctx->jiffies;
- 						/*
--						 * Has it been > 2 minutes 
-+						 * Has it been > 2 minutes
- 						 * since the last read off
- 						 * the queue?
- 						 */
-@@ -1583,7 +1667,7 @@ int aac_command_thread(void *data)
- 						 */
- 						list_add_tail(&newfib->fiblink, &fibctx->fib_list);
- 						fibctx->count++;
--						/* 
-+						/*
- 						 * Set the event to wake up the
- 						 * thread that is waiting.
- 						 */
-@@ -1655,11 +1739,11 @@ int aac_command_thread(void *data)
- 				struct fib *fibptr;
++	/* Allocate buffer for BHS + AHS */
++	uint32_t		hdr_buf[64];
  
- 				if ((fibptr = aac_fib_alloc(dev))) {
--					u32 * info;
-+					__le32 *info;
+ 	/* copied and flipped values */
+ 	int			datalen;
+-	int			datadgst;
+-	char			zero_copy_hdr;
++};
++
++/* Socket connection send helper */
++struct iscsi_tcp_send {
++	struct iscsi_hdr	*hdr;
++	struct iscsi_segment	segment;
++	struct iscsi_segment	data_segment;
+ };
  
- 					aac_fib_init(fibptr);
+ struct iscsi_tcp_conn {
+ 	struct iscsi_conn	*iscsi_conn;
+ 	struct socket		*sock;
+-	struct iscsi_hdr	hdr;		/* header placeholder */
+-	char			hdrext[4*sizeof(__u16) +
+-				    sizeof(__u32)];
+-	int			data_copied;
+ 	int			stop_stage;	/* conn_stop() flag: *
+ 						 * stop to recover,  *
+ 						 * stop to terminate */
+-	/* iSCSI connection-wide sequencing */
+-	int			hdr_size;	/* PDU header size */
+-
+ 	/* control data */
+ 	struct iscsi_tcp_recv	in;		/* TCP receive context */
+-	int			in_progress;	/* connection state machine */
++	struct iscsi_tcp_send	out;		/* TCP send context */
  
--					info = (u32 *) fib_data(fibptr);
-+					info = (__le32 *) fib_data(fibptr);
- 					if (now.tv_usec > 500000)
- 						++now.tv_sec;
+ 	/* old values for socket callbacks */
+ 	void			(*old_data_ready)(struct sock *, int);
+@@ -103,29 +93,19 @@ struct iscsi_tcp_conn {
+ 	uint32_t		sendpage_failures_cnt;
+ 	uint32_t		discontiguous_hdr_cnt;
  
-diff --git a/drivers/scsi/aacraid/dpcsup.c b/drivers/scsi/aacraid/dpcsup.c
-index e6032ff..d1163de 100644
---- a/drivers/scsi/aacraid/dpcsup.c
-+++ b/drivers/scsi/aacraid/dpcsup.c
-@@ -120,6 +120,7 @@ unsigned int aac_response_normal(struct aac_queue * q)
- 			 *	NOTE:  we cannot touch the fib after this
- 			 *	    call, because it may have been deallocated.
- 			 */
-+			fib->flags = 0;
- 			fib->callback(fib->callback_data, fib);
- 		} else {
- 			unsigned long flagv;
-@@ -229,11 +230,9 @@ unsigned int aac_command_normal(struct aac_queue *q)
-  *	all QE there are and wake up all the waiters before exiting.
-  */
+-	ssize_t (*sendpage)(struct socket *, struct page *, int, size_t, int);
+-};
++	int			error;
  
--unsigned int aac_intr_normal(struct aac_dev * dev, u32 Index)
-+unsigned int aac_intr_normal(struct aac_dev * dev, u32 index)
- {
--	u32 index = le32_to_cpu(Index);
--
--	dprintk((KERN_INFO "aac_intr_normal(%p,%x)\n", dev, Index));
-+	dprintk((KERN_INFO "aac_intr_normal(%p,%x)\n", dev, index));
- 	if ((index & 0x00000002L)) {
- 		struct hw_fib * hw_fib;
- 		struct fib * fib;
-@@ -301,7 +300,7 @@ unsigned int aac_intr_normal(struct aac_dev * dev, u32 Index)
+-struct iscsi_buf {
+-	struct scatterlist	sg;
+-	unsigned int		sent;
+-	char			use_sendmsg;
++	ssize_t (*sendpage)(struct socket *, struct page *, int, size_t, int);
+ };
  
- 		if (hwfib->header.Command == cpu_to_le16(NuFileSystem))
- 		{
--			u32 *pstatus = (u32 *)hwfib->data;
-+			__le32 *pstatus = (__le32 *)hwfib->data;
- 			if (*pstatus & cpu_to_le32(0xffff0000))
- 				*pstatus = cpu_to_le32(ST_OK);
- 		}
-@@ -315,6 +314,7 @@ unsigned int aac_intr_normal(struct aac_dev * dev, u32 Index)
- 			 *	NOTE:  we cannot touch the fib after this
- 			 *	    call, because it may have been deallocated.
- 			 */
-+			fib->flags = 0;
- 			fib->callback(fib->callback_data, fib);
- 		} else {
- 			unsigned long flagv;
-diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c
-index 9dd331b..61be227 100644
---- a/drivers/scsi/aacraid/linit.c
-+++ b/drivers/scsi/aacraid/linit.c
-@@ -159,27 +159,27 @@ static struct pci_device_id aac_pci_tbl[] = {
- MODULE_DEVICE_TABLE(pci, aac_pci_tbl);
+ struct iscsi_data_task {
+ 	struct iscsi_data	hdr;			/* PDU */
+-	char			hdrext[sizeof(__u32)];	/* Header-Digest */
+-	struct iscsi_buf	digestbuf;		/* digest buffer */
+-	uint32_t		digest;			/* data digest */
++	char			hdrext[ISCSI_DIGEST_SIZE];/* Header-Digest */
+ };
  
- /*
-- * dmb - For now we add the number of channels to this structure.  
-+ * dmb - For now we add the number of channels to this structure.
-  * In the future we should add a fib that reports the number of channels
-  * for the card.  At that time we can remove the channels from here
-  */
- static struct aac_driver_ident aac_drivers[] = {
--	{ aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* PERC 2/Si (Iguana/PERC2Si) */
--	{ aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* PERC 3/Di (Opal/PERC3Di) */
--	{ aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* PERC 3/Si (SlimFast/PERC3Si */
--	{ aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* PERC 3/Di (Iguana FlipChip/PERC3DiF */
--	{ aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* PERC 3/Di (Viper/PERC3DiV) */
--	{ aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* PERC 3/Di (Lexus/PERC3DiL) */
--	{ aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 1, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* PERC 3/Di (Jaguar/PERC3DiJ) */
--	{ aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* PERC 3/Di (Dagger/PERC3DiD) */
--	{ aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* PERC 3/Di (Boxster/PERC3DiB) */
--	{ aac_rx_init, "aacraid",  "ADAPTEC ", "catapult        ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* catapult */
--	{ aac_rx_init, "aacraid",  "ADAPTEC ", "tomcat          ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* tomcat */
--	{ aac_rx_init, "aacraid",  "ADAPTEC ", "Adaptec 2120S   ", 1, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Adaptec 2120S (Crusader) */
--	{ aac_rx_init, "aacraid",  "ADAPTEC ", "Adaptec 2200S   ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Adaptec 2200S (Vulcan) */
--	{ aac_rx_init, "aacraid",  "ADAPTEC ", "Adaptec 2200S   ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Adaptec 2200S (Vulcan-2m) */
--	{ aac_rx_init, "aacraid",  "Legend  ", "Legend S220     ", 1, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Legend S220 (Legend Crusader) */
--	{ aac_rx_init, "aacraid",  "Legend  ", "Legend S230     ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Legend S230 (Legend Vulcan) */
-+	{ aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* PERC 2/Si (Iguana/PERC2Si) */
-+	{ aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* PERC 3/Di (Opal/PERC3Di) */
-+	{ aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* PERC 3/Si (SlimFast/PERC3Si */
-+	{ aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* PERC 3/Di (Iguana FlipChip/PERC3DiF */
-+	{ aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* PERC 3/Di (Viper/PERC3DiV) */
-+	{ aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* PERC 3/Di (Lexus/PERC3DiL) */
-+	{ aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 1, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* PERC 3/Di (Jaguar/PERC3DiJ) */
-+	{ aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* PERC 3/Di (Dagger/PERC3DiD) */
-+	{ aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* PERC 3/Di (Boxster/PERC3DiB) */
-+	{ aac_rx_init, "aacraid",  "ADAPTEC ", "catapult        ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* catapult */
-+	{ aac_rx_init, "aacraid",  "ADAPTEC ", "tomcat          ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* tomcat */
-+	{ aac_rx_init, "aacraid",  "ADAPTEC ", "Adaptec 2120S   ", 1, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* Adaptec 2120S (Crusader) */
-+	{ aac_rx_init, "aacraid",  "ADAPTEC ", "Adaptec 2200S   ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* Adaptec 2200S (Vulcan) */
-+	{ aac_rx_init, "aacraid",  "ADAPTEC ", "Adaptec 2200S   ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* Adaptec 2200S (Vulcan-2m) */
-+	{ aac_rx_init, "aacraid",  "Legend  ", "Legend S220     ", 1, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* Legend S220 (Legend Crusader) */
-+	{ aac_rx_init, "aacraid",  "Legend  ", "Legend S230     ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* Legend S230 (Legend Vulcan) */
+ struct iscsi_tcp_mgmt_task {
+ 	struct iscsi_hdr	hdr;
+-	char			hdrext[sizeof(__u32)]; /* Header-Digest */
+-	unsigned long		xmstate;	/* mgmt xmit progress */
+-	struct iscsi_buf	headbuf;	/* header buffer */
+-	struct iscsi_buf	sendbuf;	/* in progress buffer */
+-	int			sent;
++	char			hdrext[ISCSI_DIGEST_SIZE]; /* Header-Digest */
+ };
  
- 	{ aac_rx_init, "aacraid",  "ADAPTEC ", "Adaptec 3230S   ", 2 }, /* Adaptec 3230S (Harrier) */
- 	{ aac_rx_init, "aacraid",  "ADAPTEC ", "Adaptec 3240S   ", 2 }, /* Adaptec 3240S (Tornado) */
-@@ -224,8 +224,8 @@ static struct aac_driver_ident aac_drivers[] = {
- 	{ aac_sa_init, "percraid", "DELL    ", "PERCRAID        ", 4, AAC_QUIRK_34SG }, /* Dell PERC2/QC */
- 	{ aac_sa_init, "hpnraid",  "HP      ", "NetRAID         ", 4, AAC_QUIRK_34SG }, /* HP NetRAID-4M */
+ struct iscsi_r2t_info {
+@@ -133,38 +113,26 @@ struct iscsi_r2t_info {
+ 	__be32			exp_statsn;	/* copied from R2T */
+ 	uint32_t		data_length;	/* copied from R2T */
+ 	uint32_t		data_offset;	/* copied from R2T */
+-	struct iscsi_buf	headbuf;	/* Data-Out Header Buffer */
+-	struct iscsi_buf	sendbuf;	/* Data-Out in progress buffer*/
+ 	int			sent;		/* R2T sequence progress */
+ 	int			data_count;	/* DATA-Out payload progress */
+-	struct scatterlist	*sg;		/* per-R2T SG list */
+ 	int			solicit_datasn;
+-	struct iscsi_data_task   dtask;        /* which data task */
++	struct iscsi_data_task	dtask;		/* Data-Out header buf */
+ };
  
--	{ aac_rx_init, "aacraid",  "DELL    ", "RAID            ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Dell Catchall */
--	{ aac_rx_init, "aacraid",  "Legend  ", "RAID            ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Legend Catchall */
-+	{ aac_rx_init, "aacraid",  "DELL    ", "RAID            ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* Dell Catchall */
-+	{ aac_rx_init, "aacraid",  "Legend  ", "RAID            ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* Legend Catchall */
- 	{ aac_rx_init, "aacraid",  "ADAPTEC ", "RAID            ", 2 }, /* Adaptec Catch All */
- 	{ aac_rkt_init, "aacraid", "ADAPTEC ", "RAID            ", 2 }, /* Adaptec Rocket Catch All */
- 	{ aac_nark_init, "aacraid", "ADAPTEC ", "RAID            ", 2 } /* Adaptec NEMER/ARK Catch All */
-@@ -239,7 +239,7 @@ static struct aac_driver_ident aac_drivers[] = {
-  *	Queues a command for execution by the associated Host Adapter.
-  *
-  *	TODO: unify with aac_scsi_cmd().
-- */ 
-+ */
+ struct iscsi_tcp_cmd_task {
+-	struct iscsi_cmd	hdr;
+-	char			hdrext[4*sizeof(__u16)+	/* AHS */
+-				    sizeof(__u32)];	/* HeaderDigest */
+-	char			pad[ISCSI_PAD_LEN];
+-	int			pad_count;		/* padded bytes */
+-	struct iscsi_buf	headbuf;		/* header buf (xmit) */
+-	struct iscsi_buf	sendbuf;		/* in progress buffer*/
+-	unsigned long		xmstate;		/* xmit xtate machine */
++	struct iscsi_hdr_buff {
++		struct iscsi_cmd	cmd_hdr;
++		char			hdrextbuf[ISCSI_MAX_AHS_SIZE +
++		                                  ISCSI_DIGEST_SIZE];
++	} hdr;
++
+ 	int			sent;
+-	struct scatterlist	*sg;			/* per-cmd SG list  */
+-	struct scatterlist	*bad_sg;		/* assert statement */
+-	int			sg_count;		/* SG's to process  */
+-	uint32_t		exp_datasn;		/* expected target's R2TSN/DataSN */
++	uint32_t		exp_datasn;	/* expected target's R2TSN/DataSN */
+ 	int			data_offset;
+-	struct iscsi_r2t_info	*r2t;			/* in progress R2T    */
+-	struct iscsi_queue	r2tpool;
++	struct iscsi_r2t_info	*r2t;		/* in progress R2T    */
++	struct iscsi_pool	r2tpool;
+ 	struct kfifo		*r2tqueue;
+-	struct iscsi_r2t_info	**r2ts;
+-	int			digest_count;
+-	uint32_t		immdigest;		/* for imm data */
+-	struct iscsi_buf	immbuf;			/* for imm data digest */
+-	struct iscsi_data_task	unsol_dtask;	/* unsol data task */
++	struct iscsi_data_task	unsol_dtask;	/* Data-Out header buf */
+ };
  
- static int aac_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
- {
-@@ -258,7 +258,7 @@ static int aac_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd
+ #endif /* ISCSI_H */
+diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
+index 8b57af5..553168a 100644
+--- a/drivers/scsi/libiscsi.c
++++ b/drivers/scsi/libiscsi.c
+@@ -24,6 +24,7 @@
+ #include <linux/types.h>
+ #include <linux/kfifo.h>
+ #include <linux/delay.h>
++#include <linux/log2.h>
+ #include <asm/unaligned.h>
+ #include <net/tcp.h>
+ #include <scsi/scsi_cmnd.h>
+@@ -86,7 +87,7 @@ iscsi_update_cmdsn(struct iscsi_session *session, struct iscsi_nopin *hdr)
+ 		 * xmit thread
+ 		 */
+ 		if (!list_empty(&session->leadconn->xmitqueue) ||
+-		    __kfifo_len(session->leadconn->mgmtqueue))
++		    !list_empty(&session->leadconn->mgmtqueue))
+ 			scsi_queue_work(session->host,
+ 					&session->leadconn->xmitwork);
  	}
- 	cmd->SCp.phase = AAC_OWNER_LOWLEVEL;
- 	return (aac_scsi_cmd(cmd) ? FAILED : 0);
--} 
-+}
+@@ -122,6 +123,20 @@ void iscsi_prep_unsolicit_data_pdu(struct iscsi_cmd_task *ctask,
+ }
+ EXPORT_SYMBOL_GPL(iscsi_prep_unsolicit_data_pdu);
  
++static int iscsi_add_hdr(struct iscsi_cmd_task *ctask, unsigned len)
++{
++	unsigned exp_len = ctask->hdr_len + len;
++
++	if (exp_len > ctask->hdr_max) {
++		WARN_ON(1);
++		return -EINVAL;
++	}
++
++	WARN_ON(len & (ISCSI_PAD_LEN - 1)); /* caller must pad the AHS */
++	ctask->hdr_len = exp_len;
++	return 0;
++}
++
  /**
-  *	aac_info		-	Returns the host adapter name
-@@ -292,21 +292,21 @@ struct aac_driver_ident* aac_get_driver_ident(int devtype)
-  *	@capacity: the sector capacity of the disk
-  *	@geom: geometry block to fill in
-  *
-- *	Return the Heads/Sectors/Cylinders BIOS Disk Parameters for Disk.  
-- *	The default disk geometry is 64 heads, 32 sectors, and the appropriate 
-- *	number of cylinders so as not to exceed drive capacity.  In order for 
-+ *	Return the Heads/Sectors/Cylinders BIOS Disk Parameters for Disk.
-+ *	The default disk geometry is 64 heads, 32 sectors, and the appropriate
-+ *	number of cylinders so as not to exceed drive capacity.  In order for
-  *	disks equal to or larger than 1 GB to be addressable by the BIOS
-- *	without exceeding the BIOS limitation of 1024 cylinders, Extended 
-- *	Translation should be enabled.   With Extended Translation enabled, 
-- *	drives between 1 GB inclusive and 2 GB exclusive are given a disk 
-- *	geometry of 128 heads and 32 sectors, and drives above 2 GB inclusive 
-- *	are given a disk geometry of 255 heads and 63 sectors.  However, if 
-- *	the BIOS detects that the Extended Translation setting does not match 
-- *	the geometry in the partition table, then the translation inferred 
-- *	from the partition table will be used by the BIOS, and a warning may 
-+ *	without exceeding the BIOS limitation of 1024 cylinders, Extended
-+ *	Translation should be enabled.   With Extended Translation enabled,
-+ *	drives between 1 GB inclusive and 2 GB exclusive are given a disk
-+ *	geometry of 128 heads and 32 sectors, and drives above 2 GB inclusive
-+ *	are given a disk geometry of 255 heads and 63 sectors.  However, if
-+ *	the BIOS detects that the Extended Translation setting does not match
-+ *	the geometry in the partition table, then the translation inferred
-+ *	from the partition table will be used by the BIOS, and a warning may
-  *	be displayed.
+  * iscsi_prep_scsi_cmd_pdu - prep iscsi scsi cmd pdu
+  * @ctask: iscsi cmd task
+@@ -129,27 +144,32 @@ EXPORT_SYMBOL_GPL(iscsi_prep_unsolicit_data_pdu);
+  * Prep basic iSCSI PDU fields for a scsi cmd pdu. The LLD should set
+  * fields like dlength or final based on how much data it sends
   */
-- 
-+
- static int aac_biosparm(struct scsi_device *sdev, struct block_device *bdev,
- 			sector_t capacity, int *geom)
+-static void iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask)
++static int iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask)
  {
-@@ -333,10 +333,10 @@ static int aac_biosparm(struct scsi_device *sdev, struct block_device *bdev,
+ 	struct iscsi_conn *conn = ctask->conn;
+ 	struct iscsi_session *session = conn->session;
+ 	struct iscsi_cmd *hdr = ctask->hdr;
+ 	struct scsi_cmnd *sc = ctask->sc;
++	unsigned hdrlength;
++	int rc;
  
- 	param->cylinders = cap_to_cyls(capacity, param->heads * param->sectors);
+-        hdr->opcode = ISCSI_OP_SCSI_CMD;
+-        hdr->flags = ISCSI_ATTR_SIMPLE;
+-        int_to_scsilun(sc->device->lun, (struct scsi_lun *)hdr->lun);
+-        hdr->itt = build_itt(ctask->itt, conn->id, session->age);
+-        hdr->data_length = cpu_to_be32(scsi_bufflen(sc));
+-        hdr->cmdsn = cpu_to_be32(session->cmdsn);
+-        session->cmdsn++;
+-        hdr->exp_statsn = cpu_to_be32(conn->exp_statsn);
+-        memcpy(hdr->cdb, sc->cmnd, sc->cmd_len);
++	ctask->hdr_len = 0;
++	rc = iscsi_add_hdr(ctask, sizeof(*hdr));
++	if (rc)
++		return rc;
++	hdr->opcode = ISCSI_OP_SCSI_CMD;
++	hdr->flags = ISCSI_ATTR_SIMPLE;
++	int_to_scsilun(sc->device->lun, (struct scsi_lun *)hdr->lun);
++	hdr->itt = build_itt(ctask->itt, conn->id, session->age);
++	hdr->data_length = cpu_to_be32(scsi_bufflen(sc));
++	hdr->cmdsn = cpu_to_be32(session->cmdsn);
++	session->cmdsn++;
++	hdr->exp_statsn = cpu_to_be32(conn->exp_statsn);
++	memcpy(hdr->cdb, sc->cmnd, sc->cmd_len);
+ 	if (sc->cmd_len < MAX_COMMAND_SIZE)
+ 		memset(&hdr->cdb[sc->cmd_len], 0,
+ 			MAX_COMMAND_SIZE - sc->cmd_len);
  
--	/* 
-+	/*
- 	 *	Read the first 1024 bytes from the disk device, if the boot
- 	 *	sector partition table is valid, search for a partition table
--	 *	entry whose end_head matches one of the standard geometry 
-+	 *	entry whose end_head matches one of the standard geometry
- 	 *	translations ( 64/32, 128/32, 255/63 ).
- 	 */
- 	buf = scsi_bios_ptable(bdev);
-@@ -401,30 +401,44 @@ static int aac_biosparm(struct scsi_device *sdev, struct block_device *bdev,
+-	ctask->data_count = 0;
+ 	ctask->imm_count = 0;
+ 	if (sc->sc_data_direction == DMA_TO_DEVICE) {
+ 		hdr->flags |= ISCSI_FLAG_CMD_WRITE;
+@@ -178,9 +198,9 @@ static void iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask)
+ 			else
+ 				ctask->imm_count = min(scsi_bufflen(sc),
+ 							conn->max_xmit_dlength);
+-			hton24(ctask->hdr->dlength, ctask->imm_count);
++			hton24(hdr->dlength, ctask->imm_count);
+ 		} else
+-			zero_data(ctask->hdr->dlength);
++			zero_data(hdr->dlength);
  
- static int aac_slave_configure(struct scsi_device *sdev)
- {
-+	struct aac_dev *aac = (struct aac_dev *)sdev->host->hostdata;
- 	if ((sdev->type == TYPE_DISK) &&
--			(sdev_channel(sdev) != CONTAINER_CHANNEL)) {
-+			(sdev_channel(sdev) != CONTAINER_CHANNEL) &&
-+			(!aac->jbod || sdev->inq_periph_qual) &&
-+			(!aac->raid_scsi_mode || (sdev_channel(sdev) != 2))) {
- 		if (expose_physicals == 0)
- 			return -ENXIO;
--		if (expose_physicals < 0) {
--			struct aac_dev *aac =
--				(struct aac_dev *)sdev->host->hostdata;
--			if (!aac->raid_scsi_mode || (sdev_channel(sdev) != 2))
--				sdev->no_uld_attach = 1;
--		}
-+		if (expose_physicals < 0)
-+			sdev->no_uld_attach = 1;
- 	}
- 	if (sdev->tagged_supported && (sdev->type == TYPE_DISK) &&
--			(sdev_channel(sdev) == CONTAINER_CHANNEL)) {
-+			(!aac->raid_scsi_mode || (sdev_channel(sdev) != 2)) &&
-+			!sdev->no_uld_attach) {
- 		struct scsi_device * dev;
- 		struct Scsi_Host *host = sdev->host;
- 		unsigned num_lsu = 0;
- 		unsigned num_one = 0;
- 		unsigned depth;
-+		unsigned cid;
+ 		if (!session->initial_r2t_en) {
+ 			ctask->unsol_count = min((session->first_burst),
+@@ -190,7 +210,7 @@ static void iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask)
  
-+		/*
-+		 * Firmware has an individual device recovery time typically
-+		 * of 35 seconds, give us a margin.
-+		 */
-+		if (sdev->timeout < (45 * HZ))
-+			sdev->timeout = 45 * HZ;
-+		for (cid = 0; cid < aac->maximum_num_containers; ++cid)
-+			if (aac->fsa_dev[cid].valid)
-+				++num_lsu;
- 		__shost_for_each_device(dev, host) {
- 			if (dev->tagged_supported && (dev->type == TYPE_DISK) &&
--				(sdev_channel(dev) == CONTAINER_CHANNEL))
--				++num_lsu;
--			else
-+					(!aac->raid_scsi_mode ||
-+						(sdev_channel(sdev) != 2)) &&
-+					!dev->no_uld_attach) {
-+				if ((sdev_channel(dev) != CONTAINER_CHANNEL)
-+				 || !aac->fsa_dev[sdev_id(dev)].valid)
-+					++num_lsu;
-+			} else
- 				++num_one;
- 		}
- 		if (num_lsu == 0)
-@@ -481,9 +495,35 @@ static int aac_change_queue_depth(struct scsi_device *sdev, int depth)
- 	return sdev->queue_depth;
- }
+ 		if (!ctask->unsol_count)
+ 			/* No unsolicit Data-Out's */
+-			ctask->hdr->flags |= ISCSI_FLAG_CMD_FINAL;
++			hdr->flags |= ISCSI_FLAG_CMD_FINAL;
+ 	} else {
+ 		hdr->flags |= ISCSI_FLAG_CMD_FINAL;
+ 		zero_data(hdr->dlength);
+@@ -199,13 +219,25 @@ static void iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask)
+ 			hdr->flags |= ISCSI_FLAG_CMD_READ;
+ 	}
  
-+static ssize_t aac_show_raid_level(struct device *dev, struct device_attribute *attr, char *buf)
-+{
-+	struct scsi_device * sdev = to_scsi_device(dev);
-+	if (sdev_channel(sdev) != CONTAINER_CHANNEL)
-+		return snprintf(buf, PAGE_SIZE, sdev->no_uld_attach
-+		  ? "Hidden\n" : "JBOD");
-+	return snprintf(buf, PAGE_SIZE, "%s\n",
-+	  get_container_type(((struct aac_dev *)(sdev->host->hostdata))
-+	    ->fsa_dev[sdev_id(sdev)].type));
-+}
+-	conn->scsicmd_pdus_cnt++;
++	/* calculate size of additional header segments (AHSs) */
++	hdrlength = ctask->hdr_len - sizeof(*hdr);
 +
-+static struct device_attribute aac_raid_level_attr = {
-+	.attr = {
-+		.name = "level",
-+		.mode = S_IRUGO,
-+	},
-+	.show = aac_show_raid_level
-+};
++	WARN_ON(hdrlength & (ISCSI_PAD_LEN-1));
++	hdrlength /= ISCSI_PAD_LEN;
 +
-+static struct device_attribute *aac_dev_attrs[] = {
-+	&aac_raid_level_attr,
-+	NULL,
-+};
++	WARN_ON(hdrlength >= 256);
++	hdr->hlength = hdrlength & 0xFF;
 +
- static int aac_ioctl(struct scsi_device *sdev, int cmd, void __user * arg)
- {
- 	struct aac_dev *dev = (struct aac_dev *)sdev->host->hostdata;
-+	if (!capable(CAP_SYS_RAWIO))
-+		return -EPERM;
- 	return aac_do_ioctl(dev, cmd, arg);
- }
++	if (conn->session->tt->init_cmd_task(conn->ctask))
++		return EIO;
  
-@@ -506,17 +546,33 @@ static int aac_eh_abort(struct scsi_cmnd* cmd)
- 			break;
- 	case INQUIRY:
- 	case READ_CAPACITY:
--	case TEST_UNIT_READY:
- 		/* Mark associated FIB to not complete, eh handler does this */
- 		for (count = 0; count < (host->can_queue + AAC_NUM_MGT_FIB); ++count) {
- 			struct fib * fib = &aac->fibs[count];
- 			if (fib->hw_fib_va->header.XferState &&
-+			  (fib->flags & FIB_CONTEXT_FLAG) &&
- 			  (fib->callback_data == cmd)) {
- 				fib->flags |= FIB_CONTEXT_FLAG_TIMED_OUT;
- 				cmd->SCp.phase = AAC_OWNER_ERROR_HANDLER;
- 				ret = SUCCESS;
- 			}
- 		}
-+		break;
-+	case TEST_UNIT_READY:
-+		/* Mark associated FIB to not complete, eh handler does this */
-+		for (count = 0; count < (host->can_queue + AAC_NUM_MGT_FIB); ++count) {
-+			struct scsi_cmnd * command;
-+			struct fib * fib = &aac->fibs[count];
-+			if ((fib->hw_fib_va->header.XferState & cpu_to_le32(Async | NoResponseExpected)) &&
-+			  (fib->flags & FIB_CONTEXT_FLAG) &&
-+			  ((command = fib->callback_data)) &&
-+			  (command->device == cmd->device)) {
-+				fib->flags |= FIB_CONTEXT_FLAG_TIMED_OUT;
-+				command->SCp.phase = AAC_OWNER_ERROR_HANDLER;
-+				if (command == cmd)
-+					ret = SUCCESS;
-+			}
-+		}
- 	}
- 	return ret;
+-        debug_scsi("iscsi prep [%s cid %d sc %p cdb 0x%x itt 0x%x len %d "
++	conn->scsicmd_pdus_cnt++;
++	debug_scsi("iscsi prep [%s cid %d sc %p cdb 0x%x itt 0x%x len %d "
+ 		"cmdsn %d win %d]\n",
+-                sc->sc_data_direction == DMA_TO_DEVICE ? "write" : "read",
++		sc->sc_data_direction == DMA_TO_DEVICE ? "write" : "read",
+ 		conn->id, sc, sc->cmnd[0], ctask->itt, scsi_bufflen(sc),
+-                session->cmdsn, session->max_cmdsn - session->exp_cmdsn + 1);
++		session->cmdsn, session->max_cmdsn - session->exp_cmdsn + 1);
++	return 0;
  }
-@@ -539,12 +595,13 @@ static int aac_eh_reset(struct scsi_cmnd* cmd)
- 	for (count = 0; count < (host->can_queue + AAC_NUM_MGT_FIB); ++count) {
- 		struct fib * fib = &aac->fibs[count];
- 		if (fib->hw_fib_va->header.XferState &&
-+		  (fib->flags & FIB_CONTEXT_FLAG) &&
- 		  (fib->callback_data == cmd)) {
- 			fib->flags |= FIB_CONTEXT_FLAG_TIMED_OUT;
- 			cmd->SCp.phase = AAC_OWNER_ERROR_HANDLER;
- 		}
- 	}
--	printk(KERN_ERR "%s: Host adapter reset request. SCSI hang ?\n", 
-+	printk(KERN_ERR "%s: Host adapter reset request. SCSI hang ?\n",
- 					AAC_DRIVERNAME);
  
- 	if ((count = aac_check_health(aac)))
-@@ -584,8 +641,11 @@ static int aac_eh_reset(struct scsi_cmnd* cmd)
- 	 * support a register, instead of a commanded, reset.
- 	 */
- 	if ((aac->supplement_adapter_info.SupportedOptions2 &
--	  le32_to_cpu(AAC_OPTION_MU_RESET|AAC_OPTION_IGNORE_RESET)) ==
--	  le32_to_cpu(AAC_OPTION_MU_RESET))
-+	   AAC_OPTION_MU_RESET) &&
-+	  aac_check_reset &&
-+	  ((aac_check_reset != 1) ||
-+	   (aac->supplement_adapter_info.SupportedOptions2 &
-+	    AAC_OPTION_IGNORE_RESET)))
- 		aac_reset_adapter(aac, 2); /* Bypass wait for command quiesce */
- 	return SUCCESS; /* Cause an immediate retry of the command with a ten second delay after successful tur */
- }
-@@ -632,8 +692,8 @@ static int aac_cfg_open(struct inode *inode, struct file *file)
-  *	Bugs: Needs locking against parallel ioctls lower down
-  *	Bugs: Needs to handle hot plugging
+ /**
+@@ -218,13 +250,16 @@ static void iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask)
   */
-- 
--static int aac_cfg_ioctl(struct inode *inode,  struct file *file,
-+
-+static int aac_cfg_ioctl(struct inode *inode, struct file *file,
- 		unsigned int cmd, unsigned long arg)
- {
- 	if (!capable(CAP_SYS_RAWIO))
-@@ -646,7 +706,7 @@ static long aac_compat_do_ioctl(struct aac_dev *dev, unsigned cmd, unsigned long
+ static void iscsi_complete_command(struct iscsi_cmd_task *ctask)
  {
- 	long ret;
- 	lock_kernel();
--	switch (cmd) { 
-+	switch (cmd) {
- 	case FSACTL_MINIPORT_REV_CHECK:
- 	case FSACTL_SENDFIB:
- 	case FSACTL_OPEN_GET_ADAPTER_FIB:
-@@ -656,14 +716,14 @@ static long aac_compat_do_ioctl(struct aac_dev *dev, unsigned cmd, unsigned long
- 	case FSACTL_QUERY_DISK:
- 	case FSACTL_DELETE_DISK:
- 	case FSACTL_FORCE_DELETE_DISK:
--	case FSACTL_GET_CONTAINERS: 
-+	case FSACTL_GET_CONTAINERS:
- 	case FSACTL_SEND_LARGE_FIB:
- 		ret = aac_do_ioctl(dev, cmd, (void __user *)arg);
- 		break;
- 
- 	case FSACTL_GET_NEXT_ADAPTER_FIB: {
- 		struct fib_ioctl __user *f;
--		
-+
- 		f = compat_alloc_user_space(sizeof(*f));
- 		ret = 0;
- 		if (clear_user(f, sizeof(*f)))
-@@ -676,9 +736,9 @@ static long aac_compat_do_ioctl(struct aac_dev *dev, unsigned cmd, unsigned long
- 	}
+-	struct iscsi_session *session = ctask->conn->session;
++	struct iscsi_conn *conn = ctask->conn;
++	struct iscsi_session *session = conn->session;
+ 	struct scsi_cmnd *sc = ctask->sc;
  
- 	default:
--		ret = -ENOIOCTLCMD; 
-+		ret = -ENOIOCTLCMD;
- 		break;
--	} 
-+	}
- 	unlock_kernel();
- 	return ret;
- }
-@@ -735,6 +795,25 @@ static ssize_t aac_show_vendor(struct class_device *class_dev,
- 	return len;
+ 	ctask->state = ISCSI_TASK_COMPLETED;
+ 	ctask->sc = NULL;
+ 	/* SCSI eh reuses commands to verify us */
+ 	sc->SCp.ptr = NULL;
++	if (conn->ctask == ctask)
++		conn->ctask = NULL;
+ 	list_del_init(&ctask->running);
+ 	__kfifo_put(session->cmdpool.queue, (void*)&ctask, sizeof(void*));
+ 	sc->scsi_done(sc);
+@@ -241,6 +276,112 @@ static void __iscsi_put_ctask(struct iscsi_cmd_task *ctask)
+ 		iscsi_complete_command(ctask);
  }
  
-+static ssize_t aac_show_flags(struct class_device *class_dev, char *buf)
++/*
++ * session lock must be held
++ */
++static void fail_command(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask,
++			 int err)
 +{
-+	int len = 0;
-+	struct aac_dev *dev = (struct aac_dev*)class_to_shost(class_dev)->hostdata;
++	struct scsi_cmnd *sc;
 +
-+	if (nblank(dprintk(x)))
-+		len = snprintf(buf, PAGE_SIZE, "dprintk\n");
-+#ifdef AAC_DETAILED_STATUS_INFO
-+	len += snprintf(buf + len, PAGE_SIZE - len,
-+			"AAC_DETAILED_STATUS_INFO\n");
-+#endif
-+	if (dev->raw_io_interface && dev->raw_io_64)
-+		len += snprintf(buf + len, PAGE_SIZE - len,
-+				"SAI_READ_CAPACITY_16\n");
-+	if (dev->jbod)
-+		len += snprintf(buf + len, PAGE_SIZE - len, "SUPPORTED_JBOD\n");
-+	return len;
++	sc = ctask->sc;
++	if (!sc)
++		return;
++
++	if (ctask->state == ISCSI_TASK_PENDING)
++		/*
++		 * cmd never made it to the xmit thread, so we should not count
++		 * the cmd in the sequencing
++		 */
++		conn->session->queued_cmdsn--;
++	else
++		conn->session->tt->cleanup_cmd_task(conn, ctask);
++
++	sc->result = err;
++	scsi_set_resid(sc, scsi_bufflen(sc));
++	if (conn->ctask == ctask)
++		conn->ctask = NULL;
++	/* release ref from queuecommand */
++	__iscsi_put_ctask(ctask);
 +}
 +
- static ssize_t aac_show_kernel_version(struct class_device *class_dev,
- 		char *buf)
- {
-@@ -742,7 +821,7 @@ static ssize_t aac_show_kernel_version(struct class_device *class_dev,
- 	int len, tmp;
- 
- 	tmp = le32_to_cpu(dev->adapter_info.kernelrev);
--	len = snprintf(buf, PAGE_SIZE, "%d.%d-%d[%d]\n", 
-+	len = snprintf(buf, PAGE_SIZE, "%d.%d-%d[%d]\n",
- 	  tmp >> 24, (tmp >> 16) & 0xff, tmp & 0xff,
- 	  le32_to_cpu(dev->adapter_info.kernelbuild));
- 	return len;
-@@ -755,7 +834,7 @@ static ssize_t aac_show_monitor_version(struct class_device *class_dev,
- 	int len, tmp;
- 
- 	tmp = le32_to_cpu(dev->adapter_info.monitorrev);
--	len = snprintf(buf, PAGE_SIZE, "%d.%d-%d[%d]\n", 
-+	len = snprintf(buf, PAGE_SIZE, "%d.%d-%d[%d]\n",
- 	  tmp >> 24, (tmp >> 16) & 0xff, tmp & 0xff,
- 	  le32_to_cpu(dev->adapter_info.monitorbuild));
- 	return len;
-@@ -768,7 +847,7 @@ static ssize_t aac_show_bios_version(struct class_device *class_dev,
- 	int len, tmp;
- 
- 	tmp = le32_to_cpu(dev->adapter_info.biosrev);
--	len = snprintf(buf, PAGE_SIZE, "%d.%d-%d[%d]\n", 
-+	len = snprintf(buf, PAGE_SIZE, "%d.%d-%d[%d]\n",
- 	  tmp >> 24, (tmp >> 16) & 0xff, tmp & 0xff,
- 	  le32_to_cpu(dev->adapter_info.biosbuild));
- 	return len;
-@@ -844,6 +923,13 @@ static struct class_device_attribute aac_vendor = {
- 	},
- 	.show = aac_show_vendor,
- };
-+static struct class_device_attribute aac_flags = {
-+	.attr = {
-+		.name = "flags",
-+		.mode = S_IRUGO,
-+	},
-+	.show = aac_show_flags,
-+};
- static struct class_device_attribute aac_kernel_version = {
- 	.attr = {
- 		.name = "hba_kernel_version",
-@@ -898,6 +984,7 @@ static struct class_device_attribute aac_reset = {
- static struct class_device_attribute *aac_attrs[] = {
- 	&aac_model,
- 	&aac_vendor,
-+	&aac_flags,
- 	&aac_kernel_version,
- 	&aac_monitor_version,
- 	&aac_bios_version,
-@@ -928,21 +1015,22 @@ static struct scsi_host_template aac_driver_template = {
- 	.compat_ioctl			= aac_compat_ioctl,
- #endif
- 	.queuecommand   		= aac_queuecommand,
--	.bios_param     		= aac_biosparm,	
-+	.bios_param     		= aac_biosparm,
- 	.shost_attrs			= aac_attrs,
- 	.slave_configure		= aac_slave_configure,
- 	.change_queue_depth		= aac_change_queue_depth,
-+	.sdev_attrs			= aac_dev_attrs,
- 	.eh_abort_handler		= aac_eh_abort,
- 	.eh_host_reset_handler		= aac_eh_reset,
--	.can_queue      		= AAC_NUM_IO_FIB,	
-+	.can_queue      		= AAC_NUM_IO_FIB,
- 	.this_id        		= MAXIMUM_NUM_CONTAINERS,
- 	.sg_tablesize   		= 16,
- 	.max_sectors    		= 128,
- #if (AAC_NUM_IO_FIB > 256)
- 	.cmd_per_lun			= 256,
--#else		
--	.cmd_per_lun    		= AAC_NUM_IO_FIB, 
--#endif	
-+#else
-+	.cmd_per_lun    		= AAC_NUM_IO_FIB,
-+#endif
- 	.use_clustering			= ENABLE_CLUSTERING,
- 	.use_sg_chaining		= ENABLE_SG_CHAINING,
- 	.emulated                       = 1,
-@@ -979,18 +1067,18 @@ static int __devinit aac_probe_one(struct pci_dev *pdev,
- 		goto out;
- 	error = -ENODEV;
- 
--	if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) || 
-+	if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) ||
- 			pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK))
- 		goto out_disable_pdev;
- 	/*
- 	 * If the quirk31 bit is set, the adapter needs adapter
- 	 * to driver communication memory to be allocated below 2gig
- 	 */
--	if (aac_drivers[index].quirks & AAC_QUIRK_31BIT) 
-+	if (aac_drivers[index].quirks & AAC_QUIRK_31BIT)
- 		if (pci_set_dma_mask(pdev, DMA_31BIT_MASK) ||
- 				pci_set_consistent_dma_mask(pdev, DMA_31BIT_MASK))
- 			goto out_disable_pdev;
--	
++/**
++ * iscsi_free_mgmt_task - return mgmt task back to pool
++ * @conn: iscsi connection
++ * @mtask: mtask
++ *
++ * Must be called with session lock.
++ */
++void iscsi_free_mgmt_task(struct iscsi_conn *conn,
++			  struct iscsi_mgmt_task *mtask)
++{
++	list_del_init(&mtask->running);
++	if (conn->login_mtask == mtask)
++		return;
 +
- 	pci_set_master(pdev);
- 
- 	shost = scsi_host_alloc(&aac_driver_template, sizeof(struct aac_dev));
-@@ -1003,7 +1091,7 @@ static int __devinit aac_probe_one(struct pci_dev *pdev,
- 	shost->max_cmd_len = 16;
- 
- 	aac = (struct aac_dev *)shost->hostdata;
--	aac->scsi_host_ptr = shost;	
-+	aac->scsi_host_ptr = shost;
- 	aac->pdev = pdev;
- 	aac->name = aac_driver_template.name;
- 	aac->id = shost->unique_id;
-@@ -1040,7 +1128,7 @@ static int __devinit aac_probe_one(struct pci_dev *pdev,
- 	if (aac_drivers[index].quirks & AAC_QUIRK_31BIT)
- 		if (pci_set_dma_mask(pdev, DMA_32BIT_MASK))
- 			goto out_deinit;
-- 
++	if (conn->ping_mtask == mtask)
++		conn->ping_mtask = NULL;
++	__kfifo_put(conn->session->mgmtpool.queue,
++		    (void*)&mtask, sizeof(void*));
++}
++EXPORT_SYMBOL_GPL(iscsi_free_mgmt_task);
 +
- 	aac->maximum_num_channels = aac_drivers[index].channels;
- 	error = aac_get_adapter_info(aac);
- 	if (error < 0)
-@@ -1049,7 +1137,7 @@ static int __devinit aac_probe_one(struct pci_dev *pdev,
- 	/*
-  	 * Lets override negotiations and drop the maximum SG limit to 34
-  	 */
-- 	if ((aac_drivers[index].quirks & AAC_QUIRK_34SG) && 
-+	if ((aac_drivers[index].quirks & AAC_QUIRK_34SG) &&
- 			(aac->scsi_host_ptr->sg_tablesize > 34)) {
-  		aac->scsi_host_ptr->sg_tablesize = 34;
-  		aac->scsi_host_ptr->max_sectors
-@@ -1066,17 +1154,17 @@ static int __devinit aac_probe_one(struct pci_dev *pdev,
- 	/*
- 	 * Firware printf works only with older firmware.
- 	 */
--	if (aac_drivers[index].quirks & AAC_QUIRK_34SG) 
-+	if (aac_drivers[index].quirks & AAC_QUIRK_34SG)
- 		aac->printf_enabled = 1;
- 	else
- 		aac->printf_enabled = 0;
-- 
++static struct iscsi_mgmt_task *
++__iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
++		      char *data, uint32_t data_size)
++{
++	struct iscsi_session *session = conn->session;
++	struct iscsi_mgmt_task *mtask;
 +
-  	/*
- 	 * max channel will be the physical channels plus 1 virtual channel
- 	 * all containers are on the virtual channel 0 (CONTAINER_CHANNEL)
- 	 * physical channels are address by their actual physical number+1
- 	 */
--	if ((aac->nondasd_support == 1) || expose_physicals)
-+	if (aac->nondasd_support || expose_physicals || aac->jbod)
- 		shost->max_channel = aac->maximum_num_channels;
- 	else
- 		shost->max_channel = 0;
-@@ -1148,10 +1236,10 @@ static void __devexit aac_remove_one(struct pci_dev *pdev)
- 	kfree(aac->queues);
- 
- 	aac_adapter_ioremap(aac, 0);
--	
++	if (session->state == ISCSI_STATE_TERMINATE)
++		return NULL;
 +
- 	kfree(aac->fibs);
- 	kfree(aac->fsa_dev);
--	
++	if (hdr->opcode == (ISCSI_OP_LOGIN | ISCSI_OP_IMMEDIATE) ||
++	    hdr->opcode == (ISCSI_OP_TEXT | ISCSI_OP_IMMEDIATE))
++		/*
++		 * Login and Text are sent serially, in
++		 * request-followed-by-response sequence.
++		 * Same mtask can be used. Same ITT must be used.
++		 * Note that login_mtask is preallocated at conn_create().
++		 */
++		mtask = conn->login_mtask;
++	else {
++		BUG_ON(conn->c_stage == ISCSI_CONN_INITIAL_STAGE);
++		BUG_ON(conn->c_stage == ISCSI_CONN_STOPPED);
 +
- 	list_del(&aac->entry);
- 	scsi_host_put(shost);
- 	pci_disable_device(pdev);
-@@ -1172,7 +1260,7 @@ static struct pci_driver aac_pci_driver = {
- static int __init aac_init(void)
- {
- 	int error;
--	
++		if (!__kfifo_get(session->mgmtpool.queue,
++				 (void*)&mtask, sizeof(void*)))
++			return NULL;
++	}
 +
- 	printk(KERN_INFO "Adaptec %s driver %s\n",
- 	  AAC_DRIVERNAME, aac_driver_version);
- 
-diff --git a/drivers/scsi/aacraid/rx.c b/drivers/scsi/aacraid/rx.c
-index 73eef3d..a08bbf1 100644
---- a/drivers/scsi/aacraid/rx.c
-+++ b/drivers/scsi/aacraid/rx.c
-@@ -465,7 +465,7 @@ static int aac_rx_restart_adapter(struct aac_dev *dev, int bled)
- 	u32 var;
- 
- 	if (!(dev->supplement_adapter_info.SupportedOptions2 &
--	  le32_to_cpu(AAC_OPTION_MU_RESET)) || (bled >= 0) || (bled == -2)) {
-+	  AAC_OPTION_MU_RESET) || (bled >= 0) || (bled == -2)) {
- 		if (bled)
- 			printk(KERN_ERR "%s%d: adapter kernel panic'd %x.\n",
- 				dev->name, dev->id, bled);
-@@ -549,7 +549,9 @@ int _aac_rx_init(struct aac_dev *dev)
- 	dev->OIMR = status = rx_readb (dev, MUnit.OIMR);
- 	if ((((status & 0x0c) != 0x0c) || aac_reset_devices || reset_devices) &&
- 	  !aac_rx_restart_adapter(dev, 0))
--		++restart;
-+		/* Make sure the Hardware FIFO is empty */
-+		while ((++restart < 512) &&
-+		  (rx_readl(dev, MUnit.OutboundQueue) != 0xFFFFFFFFL));
- 	/*
- 	 *	Check to see if the board panic'd while booting.
- 	 */
-diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c
-index 38a1ee2..374ed02 100644
---- a/drivers/scsi/advansys.c
-+++ b/drivers/scsi/advansys.c
-@@ -8233,7 +8233,7 @@ static void adv_isr_callback(ADV_DVC_VAR *adv_dvc_varp, ADV_SCSI_REQ_Q *scsiqp)
- 			if (scsiqp->scsi_status == SAM_STAT_CHECK_CONDITION) {
- 				ASC_DBG(2, "SAM_STAT_CHECK_CONDITION\n");
- 				ASC_DBG_PRT_SENSE(2, scp->sense_buffer,
--						  sizeof(scp->sense_buffer));
-+						  SCSI_SENSE_BUFFERSIZE);
- 				/*
- 				 * Note: The 'status_byte()' macro used by
- 				 * target drivers defined in scsi.h shifts the
-@@ -9136,7 +9136,7 @@ static void asc_isr_callback(ASC_DVC_VAR *asc_dvc_varp, ASC_QDONE_INFO *qdonep)
- 	BUG_ON(asc_dvc_varp != &boardp->dvc_var.asc_dvc_var);
- 
- 	dma_unmap_single(boardp->dev, scp->SCp.dma_handle,
--			sizeof(scp->sense_buffer), DMA_FROM_DEVICE);
-+			 SCSI_SENSE_BUFFERSIZE, DMA_FROM_DEVICE);
- 	/*
- 	 * 'qdonep' contains the command's ending status.
- 	 */
-@@ -9166,7 +9166,7 @@ static void asc_isr_callback(ASC_DVC_VAR *asc_dvc_varp, ASC_QDONE_INFO *qdonep)
- 			if (qdonep->d3.scsi_stat == SAM_STAT_CHECK_CONDITION) {
- 				ASC_DBG(2, "SAM_STAT_CHECK_CONDITION\n");
- 				ASC_DBG_PRT_SENSE(2, scp->sense_buffer,
--						  sizeof(scp->sense_buffer));
-+						  SCSI_SENSE_BUFFERSIZE);
- 				/*
- 				 * Note: The 'status_byte()' macro used by
- 				 * target drivers defined in scsi.h shifts the
-@@ -9881,9 +9881,9 @@ static __le32 advansys_get_sense_buffer_dma(struct scsi_cmnd *scp)
- {
- 	struct asc_board *board = shost_priv(scp->device->host);
- 	scp->SCp.dma_handle = dma_map_single(board->dev, scp->sense_buffer,
--				sizeof(scp->sense_buffer), DMA_FROM_DEVICE);
-+					     SCSI_SENSE_BUFFERSIZE, DMA_FROM_DEVICE);
- 	dma_cache_sync(board->dev, scp->sense_buffer,
--				sizeof(scp->sense_buffer), DMA_FROM_DEVICE);
-+		       SCSI_SENSE_BUFFERSIZE, DMA_FROM_DEVICE);
- 	return cpu_to_le32(scp->SCp.dma_handle);
- }
- 
-@@ -9914,7 +9914,7 @@ static int asc_build_req(struct asc_board *boardp, struct scsi_cmnd *scp,
- 	asc_scsi_q->q2.target_ix =
- 	    ASC_TIDLUN_TO_IX(scp->device->id, scp->device->lun);
- 	asc_scsi_q->q1.sense_addr = advansys_get_sense_buffer_dma(scp);
--	asc_scsi_q->q1.sense_len = sizeof(scp->sense_buffer);
-+	asc_scsi_q->q1.sense_len = SCSI_SENSE_BUFFERSIZE;
++	if (data_size) {
++		memcpy(mtask->data, data, data_size);
++		mtask->data_count = data_size;
++	} else
++		mtask->data_count = 0;
++
++	memcpy(mtask->hdr, hdr, sizeof(struct iscsi_hdr));
++	INIT_LIST_HEAD(&mtask->running);
++	list_add_tail(&mtask->running, &conn->mgmtqueue);
++	return mtask;
++}
++
++int iscsi_conn_send_pdu(struct iscsi_cls_conn *cls_conn, struct iscsi_hdr *hdr,
++			char *data, uint32_t data_size)
++{
++	struct iscsi_conn *conn = cls_conn->dd_data;
++	struct iscsi_session *session = conn->session;
++	int err = 0;
++
++	spin_lock_bh(&session->lock);
++	if (!__iscsi_conn_send_pdu(conn, hdr, data, data_size))
++		err = -EPERM;
++	spin_unlock_bh(&session->lock);
++	scsi_queue_work(session->host, &conn->xmitwork);
++	return err;
++}
++EXPORT_SYMBOL_GPL(iscsi_conn_send_pdu);
++
+ /**
+  * iscsi_cmd_rsp - SCSI Command Response processing
+  * @conn: iscsi connection
+@@ -291,17 +432,19 @@ invalid_datalen:
+ 			   min_t(uint16_t, senselen, SCSI_SENSE_BUFFERSIZE));
+ 	}
  
- 	/*
- 	 * If there are any outstanding requests for the current target,
-@@ -10173,7 +10173,7 @@ adv_build_req(struct asc_board *boardp, struct scsi_cmnd *scp,
- 	scsiqp->target_lun = scp->device->lun;
+-	if (rhdr->flags & ISCSI_FLAG_CMD_UNDERFLOW) {
++	if (rhdr->flags & (ISCSI_FLAG_CMD_UNDERFLOW |
++	                   ISCSI_FLAG_CMD_OVERFLOW)) {
+ 		int res_count = be32_to_cpu(rhdr->residual_count);
  
- 	scsiqp->sense_addr = cpu_to_le32(virt_to_bus(&scp->sense_buffer[0]));
--	scsiqp->sense_len = sizeof(scp->sense_buffer);
-+	scsiqp->sense_len = SCSI_SENSE_BUFFERSIZE;
+-		if (res_count > 0 && res_count <= scsi_bufflen(sc))
++		if (res_count > 0 &&
++		    (rhdr->flags & ISCSI_FLAG_CMD_OVERFLOW ||
++		     res_count <= scsi_bufflen(sc)))
+ 			scsi_set_resid(sc, res_count);
+ 		else
+ 			sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status;
+-	} else if (rhdr->flags & ISCSI_FLAG_CMD_BIDI_UNDERFLOW)
++	} else if (rhdr->flags & (ISCSI_FLAG_CMD_BIDI_UNDERFLOW |
++	                          ISCSI_FLAG_CMD_BIDI_OVERFLOW))
+ 		sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status;
+-	else if (rhdr->flags & ISCSI_FLAG_CMD_OVERFLOW)
+-		scsi_set_resid(sc, be32_to_cpu(rhdr->residual_count));
  
- 	/* Build ADV_SCSI_REQ_Q */
+ out:
+ 	debug_scsi("done [sc %lx res %d itt 0x%x]\n",
+@@ -318,18 +461,51 @@ static void iscsi_tmf_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
+ 	conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1;
+ 	conn->tmfrsp_pdus_cnt++;
  
-diff --git a/drivers/scsi/aha152x.c b/drivers/scsi/aha152x.c
-index ea8c699..6ccdc96 100644
---- a/drivers/scsi/aha152x.c
-+++ b/drivers/scsi/aha152x.c
-@@ -260,6 +260,7 @@
- #include <scsi/scsi_dbg.h>
- #include <scsi/scsi_host.h>
- #include <scsi/scsi_transport_spi.h>
-+#include <scsi/scsi_eh.h>
- #include "aha152x.h"
+-	if (conn->tmabort_state != TMABORT_INITIAL)
++	if (conn->tmf_state != TMF_QUEUED)
+ 		return;
  
- static LIST_HEAD(aha152x_host_list);
-@@ -558,9 +559,7 @@ struct aha152x_hostdata {
- struct aha152x_scdata {
- 	Scsi_Cmnd *next;	/* next sc in queue */
- 	struct completion *done;/* semaphore to block on */
--	unsigned char aha_orig_cmd_len;
--	unsigned char aha_orig_cmnd[MAX_COMMAND_SIZE];
--	int aha_orig_resid;
-+	struct scsi_eh_save ses;
- };
+ 	if (tmf->response == ISCSI_TMF_RSP_COMPLETE)
+-		conn->tmabort_state = TMABORT_SUCCESS;
++		conn->tmf_state = TMF_SUCCESS;
+ 	else if (tmf->response == ISCSI_TMF_RSP_NO_TASK)
+-		conn->tmabort_state = TMABORT_NOT_FOUND;
++		conn->tmf_state = TMF_NOT_FOUND;
+ 	else
+-		conn->tmabort_state = TMABORT_FAILED;
++		conn->tmf_state = TMF_FAILED;
+ 	wake_up(&conn->ehwait);
+ }
  
- /* access macros for hostdata */
-@@ -1017,16 +1016,10 @@ static int aha152x_internal_queue(Scsi_Cmnd *SCpnt, struct completion *complete,
- 	   SCp.buffers_residual : left buffers in list
- 	   SCp.phase            : current state of the command */
++static void iscsi_send_nopout(struct iscsi_conn *conn, struct iscsi_nopin *rhdr)
++{
++        struct iscsi_nopout hdr;
++	struct iscsi_mgmt_task *mtask;
++
++	if (!rhdr && conn->ping_mtask)
++		return;
++
++	memset(&hdr, 0, sizeof(struct iscsi_nopout));
++	hdr.opcode = ISCSI_OP_NOOP_OUT | ISCSI_OP_IMMEDIATE;
++	hdr.flags = ISCSI_FLAG_CMD_FINAL;
++
++	if (rhdr) {
++		memcpy(hdr.lun, rhdr->lun, 8);
++		hdr.ttt = rhdr->ttt;
++		hdr.itt = RESERVED_ITT;
++	} else
++		hdr.ttt = RESERVED_ITT;
++
++	mtask = __iscsi_conn_send_pdu(conn, (struct iscsi_hdr *)&hdr, NULL, 0);
++	if (!mtask) {
++		printk(KERN_ERR "Could not send nopout\n");
++		return;
++	}
++
++	/* only track our nops */
++	if (!rhdr) {
++		conn->ping_mtask = mtask;
++		conn->last_ping = jiffies;
++	}
++	scsi_queue_work(conn->session->host, &conn->xmitwork);
++}
++
+ static int iscsi_handle_reject(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
+ 			       char *data, int datalen)
+ {
+@@ -374,6 +550,7 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
+ 	struct iscsi_mgmt_task *mtask;
+ 	uint32_t itt;
  
--	if ((phase & (check_condition|resetting)) || !scsi_sglist(SCpnt)) {
--		if (phase & check_condition) {
--			SCpnt->SCp.ptr           = SCpnt->sense_buffer;
--			SCpnt->SCp.this_residual = sizeof(SCpnt->sense_buffer);
--			scsi_set_resid(SCpnt, sizeof(SCpnt->sense_buffer));
--		} else {
--			SCpnt->SCp.ptr           = NULL;
--			SCpnt->SCp.this_residual = 0;
--			scsi_set_resid(SCpnt, 0);
--		}
-+	if ((phase & resetting) || !scsi_sglist(SCpnt)) {
-+		SCpnt->SCp.ptr           = NULL;
-+		SCpnt->SCp.this_residual = 0;
-+		scsi_set_resid(SCpnt, 0);
- 		SCpnt->SCp.buffer           = NULL;
- 		SCpnt->SCp.buffers_residual = 0;
- 	} else {
-@@ -1561,10 +1554,7 @@ static void busfree_run(struct Scsi_Host *shpnt)
++	conn->last_recv = jiffies;
+ 	if (hdr->itt != RESERVED_ITT)
+ 		itt = get_itt(hdr->itt);
+ 	else
+@@ -429,10 +606,7 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
+ 			 */
+ 			if (iscsi_recv_pdu(conn->cls_conn, hdr, data, datalen))
+ 				rc = ISCSI_ERR_CONN_FAILED;
+-			list_del(&mtask->running);
+-			if (conn->login_mtask != mtask)
+-				__kfifo_put(session->mgmtpool.queue,
+-					    (void*)&mtask, sizeof(void*));
++			iscsi_free_mgmt_task(conn, mtask);
+ 			break;
+ 		case ISCSI_OP_SCSI_TMFUNC_RSP:
+ 			if (datalen) {
+@@ -441,20 +615,26 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
  			}
- #endif
  
--			/* restore old command */
--			memcpy(cmd->cmnd, sc->aha_orig_cmnd, sizeof(cmd->cmnd));
--			cmd->cmd_len = sc->aha_orig_cmd_len;
--			scsi_set_resid(cmd, sc->aha_orig_resid);
-+			scsi_eh_restore_cmnd(cmd, &sc->ses);
+ 			iscsi_tmf_rsp(conn, hdr);
++			iscsi_free_mgmt_task(conn, mtask);
+ 			break;
+ 		case ISCSI_OP_NOOP_IN:
+-			if (hdr->ttt != cpu_to_be32(ISCSI_RESERVED_TAG) || datalen) {
++			if (hdr->ttt != cpu_to_be32(ISCSI_RESERVED_TAG) ||
++			    datalen) {
+ 				rc = ISCSI_ERR_PROTO;
+ 				break;
+ 			}
+ 			conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1;
  
- 			cmd->SCp.Status = SAM_STAT_CHECK_CONDITION;
+-			if (iscsi_recv_pdu(conn->cls_conn, hdr, data, datalen))
+-				rc = ISCSI_ERR_CONN_FAILED;
+-			list_del(&mtask->running);
+-			if (conn->login_mtask != mtask)
+-				__kfifo_put(session->mgmtpool.queue,
+-					    (void*)&mtask, sizeof(void*));
++			if (conn->ping_mtask != mtask) {
++				/*
++				 * If this is not in response to one of our
++				 * nops then it must be from userspace.
++				 */
++				if (iscsi_recv_pdu(conn->cls_conn, hdr, data,
++						   datalen))
++					rc = ISCSI_ERR_CONN_FAILED;
++			}
++			iscsi_free_mgmt_task(conn, mtask);
+ 			break;
+ 		default:
+ 			rc = ISCSI_ERR_BAD_OPCODE;
+@@ -473,8 +653,7 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
+ 			if (hdr->ttt == cpu_to_be32(ISCSI_RESERVED_TAG))
+ 				break;
  
-@@ -1587,22 +1577,10 @@ static void busfree_run(struct Scsi_Host *shpnt)
- 				DPRINTK(debug_eh, ERR_LEAD "requesting sense\n", CMDINFO(ptr));
- #endif
+-			if (iscsi_recv_pdu(conn->cls_conn, hdr, NULL, 0))
+-				rc = ISCSI_ERR_CONN_FAILED;
++			iscsi_send_nopout(conn, (struct iscsi_nopin*)hdr);
+ 			break;
+ 		case ISCSI_OP_REJECT:
+ 			rc = iscsi_handle_reject(conn, hdr, data, datalen);
+@@ -609,20 +788,19 @@ static void iscsi_prep_mtask(struct iscsi_conn *conn,
+ 		session->tt->init_mgmt_task(conn, mtask);
  
--				/* save old command */
- 				sc = SCDATA(ptr);
- 				/* It was allocated in aha152x_internal_queue? */
- 				BUG_ON(!sc);
--				memcpy(sc->aha_orig_cmnd, ptr->cmnd,
--				                            sizeof(ptr->cmnd));
--				sc->aha_orig_cmd_len = ptr->cmd_len;
--				sc->aha_orig_resid = scsi_get_resid(ptr);
--
--				ptr->cmnd[0]         = REQUEST_SENSE;
--				ptr->cmnd[1]         = 0;
--				ptr->cmnd[2]         = 0;
--				ptr->cmnd[3]         = 0;
--				ptr->cmnd[4]         = sizeof(ptr->sense_buffer);
--				ptr->cmnd[5]         = 0;
--				ptr->cmd_len         = 6;
-+				scsi_eh_prep_cmnd(ptr, &sc->ses, NULL, 0, ~0);
+ 	debug_scsi("mgmtpdu [op 0x%x hdr->itt 0x%x datalen %d]\n",
+-		   hdr->opcode, hdr->itt, mtask->data_count);
++		   hdr->opcode & ISCSI_OPCODE_MASK, hdr->itt,
++		   mtask->data_count);
+ }
  
- 				DO_UNLOCK(flags);
- 				aha152x_internal_queue(ptr, NULL, check_condition, ptr->scsi_done);
-diff --git a/drivers/scsi/aha1542.c b/drivers/scsi/aha1542.c
-index bbcc2c5..190568e 100644
---- a/drivers/scsi/aha1542.c
-+++ b/drivers/scsi/aha1542.c
-@@ -51,15 +51,6 @@
- #define SCSI_BUF_PA(address)	isa_virt_to_bus(address)
- #define SCSI_SG_PA(sgent)	(isa_page_to_bus(sg_page((sgent))) + (sgent)->offset)
+ static int iscsi_xmit_mtask(struct iscsi_conn *conn)
+ {
+ 	struct iscsi_hdr *hdr = conn->mtask->hdr;
+-	int rc, was_logout = 0;
++	int rc;
  
--static void BAD_DMA(void *address, unsigned int length)
--{
--	printk(KERN_CRIT "buf vaddress %p paddress 0x%lx length %d\n",
--	       address,
--	       SCSI_BUF_PA(address),
--	       length);
--	panic("Buffer at physical address > 16Mb used for aha1542");
--}
++	if ((hdr->opcode & ISCSI_OPCODE_MASK) == ISCSI_OP_LOGOUT)
++		conn->session->state = ISCSI_STATE_LOGGING_OUT;
+ 	spin_unlock_bh(&conn->session->lock);
+-	if ((hdr->opcode & ISCSI_OPCODE_MASK) == ISCSI_OP_LOGOUT) {
+-		conn->session->state = ISCSI_STATE_IN_RECOVERY;
+-		iscsi_block_session(session_to_cls(conn->session));
+-		was_logout = 1;
+-	}
++
+ 	rc = conn->session->tt->xmit_mgmt_task(conn, conn->mtask);
+ 	spin_lock_bh(&conn->session->lock);
+ 	if (rc)
+@@ -630,11 +808,6 @@ static int iscsi_xmit_mtask(struct iscsi_conn *conn)
+ 
+ 	/* done with this in-progress mtask */
+ 	conn->mtask = NULL;
 -
- static void BAD_SG_DMA(Scsi_Cmnd * SCpnt,
- 		       struct scatterlist *sgp,
- 		       int nseg,
-@@ -545,7 +536,7 @@ static void aha1542_intr_handle(struct Scsi_Host *shost, void *dev_id)
- 		   we will still have it in the cdb when we come back */
- 		if (ccb[mbo].tarstat == 2)
- 			memcpy(SCtmp->sense_buffer, &ccb[mbo].cdb[ccb[mbo].cdblen],
--			       sizeof(SCtmp->sense_buffer));
-+			       SCSI_SENSE_BUFFERSIZE);
+-	if (was_logout) {
+-		set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
+-		return -ENODATA;
+-	}
+ 	return 0;
+ }
  
+@@ -658,21 +831,13 @@ static int iscsi_check_cmdsn_window_closed(struct iscsi_conn *conn)
+ static int iscsi_xmit_ctask(struct iscsi_conn *conn)
+ {
+ 	struct iscsi_cmd_task *ctask = conn->ctask;
+-	int rc = 0;
+-
+-	/*
+-	 * serialize with TMF AbortTask
+-	 */
+-	if (ctask->state == ISCSI_TASK_ABORTING)
+-		goto done;
++	int rc;
  
- 		/* is there mail :-) */
-@@ -597,8 +588,7 @@ static int aha1542_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
- 	unchar target = SCpnt->device->id;
- 	unchar lun = SCpnt->device->lun;
- 	unsigned long flags;
--	void *buff = SCpnt->request_buffer;
--	int bufflen = SCpnt->request_bufflen;
-+	int bufflen = scsi_bufflen(SCpnt);
- 	int mbo;
- 	struct mailbox *mb;
- 	struct ccb *ccb;
-@@ -619,7 +609,7 @@ static int aha1542_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
- #if 0
- 		/* scsi_request_sense() provides a buffer of size 256,
- 		   so there is no reason to expect equality */
--		if (bufflen != sizeof(SCpnt->sense_buffer))
-+		if (bufflen != SCSI_SENSE_BUFFERSIZE)
- 			printk(KERN_CRIT "aha1542: Wrong buffer length supplied "
- 			       "for request sense (%d)\n", bufflen);
- #endif
-@@ -689,42 +679,29 @@ static int aha1542_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
+ 	__iscsi_get_ctask(ctask);
+ 	spin_unlock_bh(&conn->session->lock);
+ 	rc = conn->session->tt->xmit_cmd_task(conn, ctask);
+ 	spin_lock_bh(&conn->session->lock);
+ 	__iscsi_put_ctask(ctask);
+-
+-done:
+ 	if (!rc)
+ 		/* done with this ctask */
+ 		conn->ctask = NULL;
+@@ -680,6 +845,22 @@ done:
+ }
  
- 	memcpy(ccb[mbo].cdb, cmd, ccb[mbo].cdblen);
+ /**
++ * iscsi_requeue_ctask - requeue ctask to run from session workqueue
++ * @ctask: ctask to requeue
++ *
++ * LLDs that need to run a ctask from the session workqueue should call
++ * this. The session lock must be held.
++ */
++void iscsi_requeue_ctask(struct iscsi_cmd_task *ctask)
++{
++	struct iscsi_conn *conn = ctask->conn;
++
++	list_move_tail(&ctask->running, &conn->requeue);
++	scsi_queue_work(conn->session->host, &conn->xmitwork);
++}
++EXPORT_SYMBOL_GPL(iscsi_requeue_ctask);
++
++/**
+  * iscsi_data_xmit - xmit any command into the scheduled connection
+  * @conn: iscsi connection
+  *
+@@ -717,36 +898,40 @@ static int iscsi_data_xmit(struct iscsi_conn *conn)
+ 	 * overflow us with nop-ins
+ 	 */
+ check_mgmt:
+-	while (__kfifo_get(conn->mgmtqueue, (void*)&conn->mtask,
+-			   sizeof(void*))) {
++	while (!list_empty(&conn->mgmtqueue)) {
++		conn->mtask = list_entry(conn->mgmtqueue.next,
++					 struct iscsi_mgmt_task, running);
++		if (conn->session->state == ISCSI_STATE_LOGGING_OUT) {
++			iscsi_free_mgmt_task(conn, conn->mtask);
++			conn->mtask = NULL;
++			continue;
++		}
++
+ 		iscsi_prep_mtask(conn, conn->mtask);
+-		list_add_tail(&conn->mtask->running, &conn->mgmt_run_list);
++		list_move_tail(conn->mgmtqueue.next, &conn->mgmt_run_list);
+ 		rc = iscsi_xmit_mtask(conn);
+ 		if (rc)
+ 			goto again;
+ 	}
  
--	if (SCpnt->use_sg) {
-+	if (bufflen) {
- 		struct scatterlist *sg;
- 		struct chain *cptr;
- #ifdef DEBUG
- 		unsigned char *ptr;
- #endif
--		int i;
-+		int i, sg_count = scsi_sg_count(SCpnt);
- 		ccb[mbo].op = 2;	/* SCSI Initiator Command  w/scatter-gather */
--		SCpnt->host_scribble = kmalloc(512, GFP_KERNEL | GFP_DMA);
-+		SCpnt->host_scribble = kmalloc(sizeof(*cptr)*sg_count,
-+		                                         GFP_KERNEL | GFP_DMA);
- 		cptr = (struct chain *) SCpnt->host_scribble;
- 		if (cptr == NULL) {
- 			/* free the claimed mailbox slot */
- 			HOSTDATA(SCpnt->device->host)->SCint[mbo] = NULL;
- 			return SCSI_MLQUEUE_HOST_BUSY;
+-	/* process command queue */
++	/* process pending command queue */
+ 	while (!list_empty(&conn->xmitqueue)) {
+-		/*
+-		 * iscsi tcp may readd the task to the xmitqueue to send
+-		 * write data
+-		 */
++		if (conn->tmf_state == TMF_QUEUED)
++			break;
++
+ 		conn->ctask = list_entry(conn->xmitqueue.next,
+ 					 struct iscsi_cmd_task, running);
+-		switch (conn->ctask->state) {
+-		case ISCSI_TASK_ABORTING:
+-			break;
+-		case ISCSI_TASK_PENDING:
+-			iscsi_prep_scsi_cmd_pdu(conn->ctask);
+-			conn->session->tt->init_cmd_task(conn->ctask);
+-			/* fall through */
+-		default:
+-			conn->ctask->state = ISCSI_TASK_RUNNING;
+-			break;
++		if (conn->session->state == ISCSI_STATE_LOGGING_OUT) {
++			fail_command(conn, conn->ctask, DID_IMM_RETRY << 16);
++			continue;
++		}
++		if (iscsi_prep_scsi_cmd_pdu(conn->ctask)) {
++			fail_command(conn, conn->ctask, DID_ABORT << 16);
++			continue;
  		}
--		scsi_for_each_sg(SCpnt, sg, SCpnt->use_sg, i) {
--			if (sg->length == 0 || SCpnt->use_sg > 16 ||
--			    (((int) sg->offset) & 1) || (sg->length & 1)) {
--				unsigned char *ptr;
--				printk(KERN_CRIT "Bad segment list supplied to aha1542.c (%d, %d)\n", SCpnt->use_sg, i);
--				scsi_for_each_sg(SCpnt, sg, SCpnt->use_sg, i) {
--					printk(KERN_CRIT "%d: %p %d\n", i,
--					       sg_virt(sg), sg->length);
--				};
--				printk(KERN_CRIT "cptr %x: ", (unsigned int) cptr);
--				ptr = (unsigned char *) &cptr[i];
--				for (i = 0; i < 18; i++)
--					printk("%02x ", ptr[i]);
--				panic("Foooooooood fight!");
--			};
-+		scsi_for_each_sg(SCpnt, sg, sg_count, i) {
- 			any2scsi(cptr[i].dataptr, SCSI_SG_PA(sg));
- 			if (SCSI_SG_PA(sg) + sg->length - 1 > ISA_DMA_THRESHOLD)
--				BAD_SG_DMA(SCpnt, sg, SCpnt->use_sg, i);
-+				BAD_SG_DMA(SCpnt, scsi_sglist(SCpnt), sg_count, i);
- 			any2scsi(cptr[i].datalen, sg->length);
- 		};
--		any2scsi(ccb[mbo].datalen, SCpnt->use_sg * sizeof(struct chain));
-+		any2scsi(ccb[mbo].datalen, sg_count * sizeof(struct chain));
- 		any2scsi(ccb[mbo].dataptr, SCSI_BUF_PA(cptr));
- #ifdef DEBUG
- 		printk("cptr %x: ", cptr);
-@@ -735,10 +712,8 @@ static int aha1542_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
- 	} else {
- 		ccb[mbo].op = 0;	/* SCSI Initiator Command */
- 		SCpnt->host_scribble = NULL;
--		any2scsi(ccb[mbo].datalen, bufflen);
--		if (buff && SCSI_BUF_PA(buff + bufflen - 1) > ISA_DMA_THRESHOLD)
--			BAD_DMA(buff, bufflen);
--		any2scsi(ccb[mbo].dataptr, SCSI_BUF_PA(buff));
-+		any2scsi(ccb[mbo].datalen, 0);
-+		any2scsi(ccb[mbo].dataptr, 0);
- 	};
- 	ccb[mbo].idlun = (target & 7) << 5 | direction | (lun & 7);	/*SCSI Target Id */
- 	ccb[mbo].rsalen = 16;
-diff --git a/drivers/scsi/aha1740.c b/drivers/scsi/aha1740.c
-index f6722fd..be58a0b 100644
---- a/drivers/scsi/aha1740.c
-+++ b/drivers/scsi/aha1740.c
-@@ -286,7 +286,7 @@ static irqreturn_t aha1740_intr_handle(int irq, void *dev_id)
- 			   cdb when we come back */
- 			if ( (adapstat & G2INTST_MASK) == G2INTST_CCBERROR ) {
- 				memcpy(SCtmp->sense_buffer, ecbptr->sense, 
--				       sizeof(SCtmp->sense_buffer));
-+				       SCSI_SENSE_BUFFERSIZE);
- 				errstatus = aha1740_makecode(ecbptr->sense,ecbptr->status);
- 			} else
- 				errstatus = 0;
-diff --git a/drivers/scsi/aic7xxx/Makefile b/drivers/scsi/aic7xxx/Makefile
-index 9a6ce19..e4f70c5 100644
---- a/drivers/scsi/aic7xxx/Makefile
-+++ b/drivers/scsi/aic7xxx/Makefile
-@@ -33,11 +33,10 @@ aic79xx-y					+= aic79xx_osm.o	\
- 						   aic79xx_proc.o	\
- 						   aic79xx_osm_pci.o
- 
--EXTRA_CFLAGS += -Idrivers/scsi
-+ccflags-y += -Idrivers/scsi
- ifdef WARNINGS_BECOME_ERRORS
--EXTRA_CFLAGS += -Werror
-+ccflags-y += -Werror
- endif
--#EXTRA_CFLAGS += -g
+-		list_move_tail(conn->xmitqueue.next, &conn->run_list);
  
- # Files generated that shall be removed upon make clean
- clean-files := aic7xxx_seq.h aic7xxx_reg.h aic7xxx_reg_print.c
-@@ -46,53 +45,45 @@ clean-files += aic79xx_seq.h aic79xx_reg.h aic79xx_reg_print.c
- # Dependencies for generated files need to be listed explicitly
++		conn->ctask->state = ISCSI_TASK_RUNNING;
++		list_move_tail(conn->xmitqueue.next, &conn->run_list);
+ 		rc = iscsi_xmit_ctask(conn);
+ 		if (rc)
+ 			goto again;
+@@ -755,7 +940,28 @@ check_mgmt:
+ 		 * we need to check the mgmt queue for nops that need to
+ 		 * be sent to aviod starvation
+ 		 */
+-		if (__kfifo_len(conn->mgmtqueue))
++		if (!list_empty(&conn->mgmtqueue))
++			goto check_mgmt;
++	}
++
++	while (!list_empty(&conn->requeue)) {
++		if (conn->session->fast_abort && conn->tmf_state != TMF_INITIAL)
++			break;
++
++		/*
++		 * we always do fastlogout - conn stop code will clean up.
++		 */
++		if (conn->session->state == ISCSI_STATE_LOGGING_OUT)
++			break;
++
++		conn->ctask = list_entry(conn->requeue.next,
++					 struct iscsi_cmd_task, running);
++		conn->ctask->state = ISCSI_TASK_RUNNING;
++		list_move_tail(conn->requeue.next, &conn->run_list);
++		rc = iscsi_xmit_ctask(conn);
++		if (rc)
++			goto again;
++		if (!list_empty(&conn->mgmtqueue))
+ 			goto check_mgmt;
+ 	}
+ 	spin_unlock_bh(&conn->session->lock);
+@@ -790,6 +996,7 @@ enum {
+ 	FAILURE_SESSION_TERMINATE,
+ 	FAILURE_SESSION_IN_RECOVERY,
+ 	FAILURE_SESSION_RECOVERY_TIMEOUT,
++	FAILURE_SESSION_LOGGING_OUT,
+ };
  
- $(obj)/aic7xxx_core.o: $(obj)/aic7xxx_seq.h
-+$(obj)/aic7xxx_core.o: $(obj)/aic7xxx_reg.h
- $(obj)/aic79xx_core.o: $(obj)/aic79xx_seq.h
--$(obj)/aic79xx_reg_print.c: $(src)/aic79xx_reg_print.c_shipped
--$(obj)/aic7xxx_reg_print.c: $(src)/aic7xxx_reg_print.c_shipped
-+$(obj)/aic79xx_core.o: $(obj)/aic79xx_reg.h
+ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
+@@ -805,8 +1012,9 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
+ 	sc->SCp.ptr = NULL;
  
--$(addprefix $(obj)/,$(aic7xxx-y)): $(obj)/aic7xxx_reg.h
--$(addprefix $(obj)/,$(aic79xx-y)): $(obj)/aic79xx_reg.h
-+$(addprefix $(obj)/,$(aic7xxx-y)): $(obj)/aic7xxx_seq.h
-+$(addprefix $(obj)/,$(aic79xx-y)): $(obj)/aic79xx_seq.h
+ 	host = sc->device->host;
+-	session = iscsi_hostdata(host->hostdata);
++	spin_unlock(host->host_lock);
  
--aic7xxx-gen-$(CONFIG_AIC7XXX_BUILD_FIRMWARE)	:= $(obj)/aic7xxx_seq.h \
--						   $(obj)/aic7xxx_reg.h
-+aic7xxx-gen-$(CONFIG_AIC7XXX_BUILD_FIRMWARE)	:= $(obj)/aic7xxx_reg.h
- aic7xxx-gen-$(CONFIG_AIC7XXX_REG_PRETTY_PRINT)	+= $(obj)/aic7xxx_reg_print.c
++	session = iscsi_hostdata(host->hostdata);
+ 	spin_lock(&session->lock);
  
- aicasm-7xxx-opts-$(CONFIG_AIC7XXX_REG_PRETTY_PRINT) := \
- 	-p $(obj)/aic7xxx_reg_print.c -i aic7xxx_osm.h
+ 	/*
+@@ -822,17 +1030,22 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
+ 		 * be entering our queuecommand while a block is starting
+ 		 * up because the block code is not locked)
+ 		 */
+-		if (session->state == ISCSI_STATE_IN_RECOVERY) {
++		switch (session->state) {
++		case ISCSI_STATE_IN_RECOVERY:
+ 			reason = FAILURE_SESSION_IN_RECOVERY;
+ 			goto reject;
+-		}
+-
+-		if (session->state == ISCSI_STATE_RECOVERY_FAILED)
++		case ISCSI_STATE_LOGGING_OUT:
++			reason = FAILURE_SESSION_LOGGING_OUT;
++			goto reject;
++		case ISCSI_STATE_RECOVERY_FAILED:
+ 			reason = FAILURE_SESSION_RECOVERY_TIMEOUT;
+-		else if (session->state == ISCSI_STATE_TERMINATE)
++			break;
++		case ISCSI_STATE_TERMINATE:
+ 			reason = FAILURE_SESSION_TERMINATE;
+-		else
++			break;
++		default:
+ 			reason = FAILURE_SESSION_FREED;
++		}
+ 		goto fault;
+ 	}
  
- ifeq ($(CONFIG_AIC7XXX_BUILD_FIRMWARE),y)
--# Create a dependency chain in generated files
--# to avoid concurrent invocations of the single
--# rule that builds them all.
--aic7xxx_seq.h: aic7xxx_reg.h
--ifeq ($(CONFIG_AIC7XXX_REG_PRETTY_PRINT),y)
--aic7xxx_reg.h: aic7xxx_reg_print.c
--endif
--$(aic7xxx-gen-y): $(src)/aic7xxx.seq $(src)/aic7xxx.reg $(obj)/aicasm/aicasm
-+$(obj)/aic7xxx_seq.h: $(src)/aic7xxx.seq $(src)/aic7xxx.reg $(obj)/aicasm/aicasm
- 	$(obj)/aicasm/aicasm -I$(src) -r $(obj)/aic7xxx_reg.h \
- 			      $(aicasm-7xxx-opts-y) -o $(obj)/aic7xxx_seq.h \
- 			      $(src)/aic7xxx.seq
-+
-+$(aic7xxx-gen-y): $(obj)/aic7xxx_seq.h
-+else
-+$(obj)/aic7xxx_reg_print.c: $(src)/aic7xxx_reg_print.c_shipped
- endif
+@@ -859,7 +1072,6 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
  
--aic79xx-gen-$(CONFIG_AIC79XX_BUILD_FIRMWARE)	:= $(obj)/aic79xx_seq.h \
--						   $(obj)/aic79xx_reg.h
-+aic79xx-gen-$(CONFIG_AIC79XX_BUILD_FIRMWARE)	:= $(obj)/aic79xx_reg.h
- aic79xx-gen-$(CONFIG_AIC79XX_REG_PRETTY_PRINT)	+= $(obj)/aic79xx_reg_print.c
+ 	atomic_set(&ctask->refcount, 1);
+ 	ctask->state = ISCSI_TASK_PENDING;
+-	ctask->mtask = NULL;
+ 	ctask->conn = conn;
+ 	ctask->sc = sc;
+ 	INIT_LIST_HEAD(&ctask->running);
+@@ -868,11 +1080,13 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
+ 	spin_unlock(&session->lock);
  
- aicasm-79xx-opts-$(CONFIG_AIC79XX_REG_PRETTY_PRINT) := \
- 	-p $(obj)/aic79xx_reg_print.c -i aic79xx_osm.h
+ 	scsi_queue_work(host, &conn->xmitwork);
++	spin_lock(host->host_lock);
+ 	return 0;
  
- ifeq ($(CONFIG_AIC79XX_BUILD_FIRMWARE),y)
--# Create a dependency chain in generated files
--# to avoid concurrent invocations of the single
--# rule that builds them all.
--aic79xx_seq.h: aic79xx_reg.h
--ifeq ($(CONFIG_AIC79XX_REG_PRETTY_PRINT),y)
--aic79xx_reg.h: aic79xx_reg_print.c
--endif
--$(aic79xx-gen-y): $(src)/aic79xx.seq $(src)/aic79xx.reg $(obj)/aicasm/aicasm
-+$(obj)/aic79xx_seq.h: $(src)/aic79xx.seq $(src)/aic79xx.reg $(obj)/aicasm/aicasm
- 	$(obj)/aicasm/aicasm -I$(src) -r $(obj)/aic79xx_reg.h \
- 			      $(aicasm-79xx-opts-y) -o $(obj)/aic79xx_seq.h \
- 			      $(src)/aic79xx.seq
-+
-+$(aic79xx-gen-y): $(obj)/aic79xx_seq.h
-+else
-+$(obj)/aic79xx_reg_print.c: $(src)/aic79xx_reg_print.c_shipped
- endif
+ reject:
+ 	spin_unlock(&session->lock);
+ 	debug_scsi("cmd 0x%x rejected (%d)\n", sc->cmnd[0], reason);
++	spin_lock(host->host_lock);
+ 	return SCSI_MLQUEUE_HOST_BUSY;
  
- $(obj)/aicasm/aicasm: $(src)/aicasm/*.[chyl]
-diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c
-index 2d02040..0e4708f 100644
---- a/drivers/scsi/aic7xxx/aic79xx_osm.c
-+++ b/drivers/scsi/aic7xxx/aic79xx_osm.c
-@@ -1784,7 +1784,7 @@ ahd_linux_handle_scsi_status(struct ahd_softc *ahd,
- 			if (scb->flags & SCB_SENSE) {
- 				sense_size = min(sizeof(struct scsi_sense_data)
- 					       - ahd_get_sense_residual(scb),
--						 (u_long)sizeof(cmd->sense_buffer));
-+						 (u_long)SCSI_SENSE_BUFFERSIZE);
- 				sense_offset = 0;
- 			} else {
- 				/*
-@@ -1795,11 +1795,11 @@ ahd_linux_handle_scsi_status(struct ahd_softc *ahd,
- 				    scb->sense_data;
- 				sense_size = min_t(size_t,
- 						scsi_4btoul(siu->sense_length),
--						sizeof(cmd->sense_buffer));
-+						SCSI_SENSE_BUFFERSIZE);
- 				sense_offset = SIU_SENSE_OFFSET(siu);
- 			}
+ fault:
+@@ -882,6 +1096,7 @@ fault:
+ 	sc->result = (DID_NO_CONNECT << 16);
+ 	scsi_set_resid(sc, scsi_bufflen(sc));
+ 	sc->scsi_done(sc);
++	spin_lock(host->host_lock);
+ 	return 0;
+ }
+ EXPORT_SYMBOL_GPL(iscsi_queuecommand);
+@@ -895,72 +1110,15 @@ int iscsi_change_queue_depth(struct scsi_device *sdev, int depth)
+ }
+ EXPORT_SYMBOL_GPL(iscsi_change_queue_depth);
  
--			memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer));
-+			memset(cmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
- 			memcpy(cmd->sense_buffer,
- 			       ahd_get_sense_buf(ahd, scb)
- 			       + sense_offset, sense_size);
-diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c
-index 390b0fc..e310e41 100644
---- a/drivers/scsi/aic7xxx/aic7xxx_osm.c
-+++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c
-@@ -1801,12 +1801,12 @@ ahc_linux_handle_scsi_status(struct ahc_softc *ahc,
+-static struct iscsi_mgmt_task *
+-__iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
+-		      char *data, uint32_t data_size)
+-{
+-	struct iscsi_session *session = conn->session;
+-	struct iscsi_mgmt_task *mtask;
+-
+-	if (session->state == ISCSI_STATE_TERMINATE)
+-		return NULL;
+-
+-	if (hdr->opcode == (ISCSI_OP_LOGIN | ISCSI_OP_IMMEDIATE) ||
+-	    hdr->opcode == (ISCSI_OP_TEXT | ISCSI_OP_IMMEDIATE))
+-		/*
+-		 * Login and Text are sent serially, in
+-		 * request-followed-by-response sequence.
+-		 * Same mtask can be used. Same ITT must be used.
+-		 * Note that login_mtask is preallocated at conn_create().
+-		 */
+-		mtask = conn->login_mtask;
+-	else {
+-		BUG_ON(conn->c_stage == ISCSI_CONN_INITIAL_STAGE);
+-		BUG_ON(conn->c_stage == ISCSI_CONN_STOPPED);
+-
+-		if (!__kfifo_get(session->mgmtpool.queue,
+-				 (void*)&mtask, sizeof(void*)))
+-			return NULL;
+-	}
+-
+-	if (data_size) {
+-		memcpy(mtask->data, data, data_size);
+-		mtask->data_count = data_size;
+-	} else
+-		mtask->data_count = 0;
+-
+-	INIT_LIST_HEAD(&mtask->running);
+-	memcpy(mtask->hdr, hdr, sizeof(struct iscsi_hdr));
+-	__kfifo_put(conn->mgmtqueue, (void*)&mtask, sizeof(void*));
+-	return mtask;
+-}
+-
+-int iscsi_conn_send_pdu(struct iscsi_cls_conn *cls_conn, struct iscsi_hdr *hdr,
+-			char *data, uint32_t data_size)
+-{
+-	struct iscsi_conn *conn = cls_conn->dd_data;
+-	struct iscsi_session *session = conn->session;
+-	int err = 0;
+-
+-	spin_lock_bh(&session->lock);
+-	if (!__iscsi_conn_send_pdu(conn, hdr, data, data_size))
+-		err = -EPERM;
+-	spin_unlock_bh(&session->lock);
+-	scsi_queue_work(session->host, &conn->xmitwork);
+-	return err;
+-}
+-EXPORT_SYMBOL_GPL(iscsi_conn_send_pdu);
+-
+ void iscsi_session_recovery_timedout(struct iscsi_cls_session *cls_session)
+ {
+ 	struct iscsi_session *session = class_to_transport_session(cls_session);
+-	struct iscsi_conn *conn = session->leadconn;
  
- 			sense_size = min(sizeof(struct scsi_sense_data)
- 				       - ahc_get_sense_residual(scb),
--					 (u_long)sizeof(cmd->sense_buffer));
-+					 (u_long)SCSI_SENSE_BUFFERSIZE);
- 			memcpy(cmd->sense_buffer,
- 			       ahc_get_sense_buf(ahc, scb), sense_size);
--			if (sense_size < sizeof(cmd->sense_buffer))
-+			if (sense_size < SCSI_SENSE_BUFFERSIZE)
- 				memset(&cmd->sense_buffer[sense_size], 0,
--				       sizeof(cmd->sense_buffer) - sense_size);
-+				       SCSI_SENSE_BUFFERSIZE - sense_size);
- 			cmd->result |= (DRIVER_SENSE << 24);
- #ifdef AHC_DEBUG
- 			if (ahc_debug & AHC_SHOW_SENSE) {
-diff --git a/drivers/scsi/aic7xxx_old.c b/drivers/scsi/aic7xxx_old.c
-index 8f8db5f..bcb0b87 100644
---- a/drivers/scsi/aic7xxx_old.c
-+++ b/drivers/scsi/aic7xxx_old.c
-@@ -2696,7 +2696,7 @@ aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
-   {
-     pci_unmap_single(p->pdev,
-                      le32_to_cpu(scb->sg_list[0].address),
--                     sizeof(cmd->sense_buffer),
-+                     SCSI_SENSE_BUFFERSIZE,
-                      PCI_DMA_FROMDEVICE);
-   }
-   if (scb->flags & SCB_RECOVERY_SCB)
-@@ -4267,13 +4267,13 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
-                        sizeof(generic_sense));
+ 	spin_lock_bh(&session->lock);
+ 	if (session->state != ISCSI_STATE_LOGGED_IN) {
+ 		session->state = ISCSI_STATE_RECOVERY_FAILED;
+-		if (conn)
+-			wake_up(&conn->ehwait);
++		if (session->leadconn)
++			wake_up(&session->leadconn->ehwait);
+ 	}
+ 	spin_unlock_bh(&session->lock);
+ }
+@@ -971,30 +1129,25 @@ int iscsi_eh_host_reset(struct scsi_cmnd *sc)
+ 	struct Scsi_Host *host = sc->device->host;
+ 	struct iscsi_session *session = iscsi_hostdata(host->hostdata);
+ 	struct iscsi_conn *conn = session->leadconn;
+-	int fail_session = 0;
  
-                 scb->sense_cmd[1] = (cmd->device->lun << 5);
--                scb->sense_cmd[4] = sizeof(cmd->sense_buffer);
-+                scb->sense_cmd[4] = SCSI_SENSE_BUFFERSIZE;
++	mutex_lock(&session->eh_mutex);
+ 	spin_lock_bh(&session->lock);
+ 	if (session->state == ISCSI_STATE_TERMINATE) {
+ failed:
+ 		debug_scsi("failing host reset: session terminated "
+ 			   "[CID %d age %d]\n", conn->id, session->age);
+ 		spin_unlock_bh(&session->lock);
++		mutex_unlock(&session->eh_mutex);
+ 		return FAILED;
+ 	}
  
-                 scb->sg_list[0].length = 
--                  cpu_to_le32(sizeof(cmd->sense_buffer));
-+                  cpu_to_le32(SCSI_SENSE_BUFFERSIZE);
- 		scb->sg_list[0].address =
-                         cpu_to_le32(pci_map_single(p->pdev, cmd->sense_buffer,
--                                                   sizeof(cmd->sense_buffer),
-+                                                   SCSI_SENSE_BUFFERSIZE,
-                                                    PCI_DMA_FROMDEVICE));
+-	if (sc->SCp.phase == session->age) {
+-		debug_scsi("failing connection CID %d due to SCSI host reset\n",
+-			   conn->id);
+-		fail_session = 1;
+-	}
+ 	spin_unlock_bh(&session->lock);
+-
++	mutex_unlock(&session->eh_mutex);
+ 	/*
+ 	 * we drop the lock here but the leadconn cannot be destoyed while
+ 	 * we are in the scsi eh
+ 	 */
+-	if (fail_session)
+-		iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
++	iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
  
-                 /*
-@@ -4296,7 +4296,7 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
-                 hscb->residual_data_count[2] = 0;
+ 	debug_scsi("iscsi_eh_host_reset wait for relogin\n");
+ 	wait_event_interruptible(conn->ehwait,
+@@ -1004,73 +1157,56 @@ failed:
+ 	if (signal_pending(current))
+ 		flush_signals(current);
  
-                 scb->sg_count = hscb->SG_segment_count = 1;
--                scb->sg_length = sizeof(cmd->sense_buffer);
-+                scb->sg_length = SCSI_SENSE_BUFFERSIZE;
-                 scb->tag_action = 0;
-                 scb->flags |= SCB_SENSE;
-                 /*
-@@ -10293,7 +10293,6 @@ static int aic7xxx_queue(struct scsi_cmnd *cmd, void (*fn)(struct scsi_cmnd *))
-   aic7xxx_position(cmd) = scb->hscb->tag;
-   cmd->scsi_done = fn;
-   cmd->result = DID_OK;
--  memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer));
-   aic7xxx_error(cmd) = DID_OK;
-   aic7xxx_status(cmd) = 0;
-   cmd->host_scribble = NULL;
-diff --git a/drivers/scsi/aic94xx/aic94xx_dev.c b/drivers/scsi/aic94xx/aic94xx_dev.c
-index 3dce618..72042ca 100644
---- a/drivers/scsi/aic94xx/aic94xx_dev.c
-+++ b/drivers/scsi/aic94xx/aic94xx_dev.c
-@@ -165,7 +165,7 @@ static int asd_init_target_ddb(struct domain_device *dev)
- 	if (dev->port->oob_mode != SATA_OOB_MODE) {
- 		flags |= OPEN_REQUIRED;
- 		if ((dev->dev_type == SATA_DEV) ||
--		    (dev->tproto & SAS_PROTO_STP)) {
-+		    (dev->tproto & SAS_PROTOCOL_STP)) {
- 			struct smp_resp *rps_resp = &dev->sata_dev.rps_resp;
- 			if (rps_resp->frame_type == SMP_RESPONSE &&
- 			    rps_resp->function == SMP_REPORT_PHY_SATA &&
-@@ -193,7 +193,7 @@ static int asd_init_target_ddb(struct domain_device *dev)
- 	asd_ddbsite_write_byte(asd_ha, ddb, DDB_TARG_FLAGS, flags);
++	mutex_lock(&session->eh_mutex);
+ 	spin_lock_bh(&session->lock);
+ 	if (session->state == ISCSI_STATE_LOGGED_IN)
+ 		printk(KERN_INFO "iscsi: host reset succeeded\n");
+ 	else
+ 		goto failed;
+ 	spin_unlock_bh(&session->lock);
+-
++	mutex_unlock(&session->eh_mutex);
+ 	return SUCCESS;
+ }
+ EXPORT_SYMBOL_GPL(iscsi_eh_host_reset);
  
- 	flags = 0;
--	if (dev->tproto & SAS_PROTO_STP)
-+	if (dev->tproto & SAS_PROTOCOL_STP)
- 		flags |= STP_CL_POL_NO_TX;
- 	asd_ddbsite_write_byte(asd_ha, ddb, DDB_TARG_FLAGS2, flags);
+-static void iscsi_tmabort_timedout(unsigned long data)
++static void iscsi_tmf_timedout(unsigned long data)
+ {
+-	struct iscsi_cmd_task *ctask = (struct iscsi_cmd_task *)data;
+-	struct iscsi_conn *conn = ctask->conn;
++	struct iscsi_conn *conn = (struct iscsi_conn *)data;
+ 	struct iscsi_session *session = conn->session;
  
-@@ -201,7 +201,7 @@ static int asd_init_target_ddb(struct domain_device *dev)
- 	asd_ddbsite_write_word(asd_ha, ddb, SEND_QUEUE_TAIL, 0xFFFF);
- 	asd_ddbsite_write_word(asd_ha, ddb, SISTER_DDB, 0xFFFF);
+ 	spin_lock(&session->lock);
+-	if (conn->tmabort_state == TMABORT_INITIAL) {
+-		conn->tmabort_state = TMABORT_TIMEDOUT;
+-		debug_scsi("tmabort timedout [sc %p itt 0x%x]\n",
+-			ctask->sc, ctask->itt);
++	if (conn->tmf_state == TMF_QUEUED) {
++		conn->tmf_state = TMF_TIMEDOUT;
++		debug_scsi("tmf timedout\n");
+ 		/* unblock eh_abort() */
+ 		wake_up(&conn->ehwait);
+ 	}
+ 	spin_unlock(&session->lock);
+ }
  
--	if (dev->dev_type == SATA_DEV || (dev->tproto & SAS_PROTO_STP)) {
-+	if (dev->dev_type == SATA_DEV || (dev->tproto & SAS_PROTOCOL_STP)) {
- 		i = asd_init_sata(dev);
- 		if (i < 0) {
- 			asd_free_ddb(asd_ha, ddb);
-diff --git a/drivers/scsi/aic94xx/aic94xx_dump.c b/drivers/scsi/aic94xx/aic94xx_dump.c
-index 6bd8e30..3d8c4ff 100644
---- a/drivers/scsi/aic94xx/aic94xx_dump.c
-+++ b/drivers/scsi/aic94xx/aic94xx_dump.c
-@@ -903,11 +903,11 @@ void asd_dump_frame_rcvd(struct asd_phy *phy,
- 	int i;
+-static int iscsi_exec_abort_task(struct scsi_cmnd *sc,
+-				 struct iscsi_cmd_task *ctask)
++static int iscsi_exec_task_mgmt_fn(struct iscsi_conn *conn,
++				   struct iscsi_tm *hdr, int age,
++				   int timeout)
+ {
+-	struct iscsi_conn *conn = ctask->conn;
+ 	struct iscsi_session *session = conn->session;
+-	struct iscsi_tm *hdr = &conn->tmhdr;
+-
+-	/*
+-	 * ctask timed out but session is OK requests must be serialized.
+-	 */
+-	memset(hdr, 0, sizeof(struct iscsi_tm));
+-	hdr->opcode = ISCSI_OP_SCSI_TMFUNC | ISCSI_OP_IMMEDIATE;
+-	hdr->flags = ISCSI_TM_FUNC_ABORT_TASK;
+-	hdr->flags |= ISCSI_FLAG_CMD_FINAL;
+-	memcpy(hdr->lun, ctask->hdr->lun, sizeof(hdr->lun));
+-	hdr->rtt = ctask->hdr->itt;
+-	hdr->refcmdsn = ctask->hdr->cmdsn;
++	struct iscsi_mgmt_task *mtask;
  
- 	switch ((dl->status_block[1] & 0x70) >> 3) {
--	case SAS_PROTO_STP:
-+	case SAS_PROTOCOL_STP:
- 		ASD_DPRINTK("STP proto device-to-host FIS:\n");
- 		break;
- 	default:
--	case SAS_PROTO_SSP:
-+	case SAS_PROTOCOL_SSP:
- 		ASD_DPRINTK("SAS proto IDENTIFY:\n");
- 		break;
+-	ctask->mtask = __iscsi_conn_send_pdu(conn, (struct iscsi_hdr *)hdr,
+-					    NULL, 0);
+-	if (!ctask->mtask) {
++	mtask = __iscsi_conn_send_pdu(conn, (struct iscsi_hdr *)hdr,
++				      NULL, 0);
++	if (!mtask) {
+ 		spin_unlock_bh(&session->lock);
+ 		iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
+-		spin_lock_bh(&session->lock)
+-		debug_scsi("abort sent failure [itt 0x%x]\n", ctask->itt);
++		spin_lock_bh(&session->lock);
++		debug_scsi("tmf exec failure\n");
+ 		return -EPERM;
  	}
-diff --git a/drivers/scsi/aic94xx/aic94xx_hwi.c b/drivers/scsi/aic94xx/aic94xx_hwi.c
-index 0cd7eed..098b5f3 100644
---- a/drivers/scsi/aic94xx/aic94xx_hwi.c
-+++ b/drivers/scsi/aic94xx/aic94xx_hwi.c
-@@ -91,7 +91,7 @@ static int asd_init_phy(struct asd_phy *phy)
- 
- 	sas_phy->enabled = 1;
- 	sas_phy->class = SAS;
--	sas_phy->iproto = SAS_PROTO_ALL;
-+	sas_phy->iproto = SAS_PROTOCOL_ALL;
- 	sas_phy->tproto = 0;
- 	sas_phy->type = PHY_TYPE_PHYSICAL;
- 	sas_phy->role = PHY_ROLE_INITIATOR;
-diff --git a/drivers/scsi/aic94xx/aic94xx_hwi.h b/drivers/scsi/aic94xx/aic94xx_hwi.h
-index 491e5d8..150f670 100644
---- a/drivers/scsi/aic94xx/aic94xx_hwi.h
-+++ b/drivers/scsi/aic94xx/aic94xx_hwi.h
-@@ -72,6 +72,7 @@ struct flash_struct {
- 	u8     manuf;
- 	u8     dev_id;
- 	u8     sec_prot;
-+	u8     method;
+-	ctask->state = ISCSI_TASK_ABORTING;
++	conn->tmfcmd_pdus_cnt++;
++	conn->tmf_timer.expires = timeout * HZ + jiffies;
++	conn->tmf_timer.function = iscsi_tmf_timedout;
++	conn->tmf_timer.data = (unsigned long)conn;
++	add_timer(&conn->tmf_timer);
++	debug_scsi("tmf set timeout\n");
  
- 	u32    dir_offs;
- };
-@@ -216,6 +217,8 @@ struct asd_ha_struct {
- 	struct dma_pool  *scb_pool;
+-	debug_scsi("abort sent [itt 0x%x]\n", ctask->itt);
+-
+-	if (conn->tmabort_state == TMABORT_INITIAL) {
+-		conn->tmfcmd_pdus_cnt++;
+-		conn->tmabort_timer.expires = 20*HZ + jiffies;
+-		conn->tmabort_timer.function = iscsi_tmabort_timedout;
+-		conn->tmabort_timer.data = (unsigned long)ctask;
+-		add_timer(&conn->tmabort_timer);
+-		debug_scsi("abort set timeout [itt 0x%x]\n", ctask->itt);
+-	}
+ 	spin_unlock_bh(&session->lock);
+ 	mutex_unlock(&session->eh_mutex);
+ 	scsi_queue_work(session->host, &conn->xmitwork);
+@@ -1078,113 +1214,197 @@ static int iscsi_exec_abort_task(struct scsi_cmnd *sc,
+ 	/*
+ 	 * block eh thread until:
+ 	 *
+-	 * 1) abort response
+-	 * 2) abort timeout
++	 * 1) tmf response
++	 * 2) tmf timeout
+ 	 * 3) session is terminated or restarted or userspace has
+ 	 * given up on recovery
+ 	 */
+-	wait_event_interruptible(conn->ehwait,
+-				 sc->SCp.phase != session->age ||
++	wait_event_interruptible(conn->ehwait, age != session->age ||
+ 				 session->state != ISCSI_STATE_LOGGED_IN ||
+-				 conn->tmabort_state != TMABORT_INITIAL);
++				 conn->tmf_state != TMF_QUEUED);
+ 	if (signal_pending(current))
+ 		flush_signals(current);
+-	del_timer_sync(&conn->tmabort_timer);
++	del_timer_sync(&conn->tmf_timer);
++
+ 	mutex_lock(&session->eh_mutex);
+ 	spin_lock_bh(&session->lock);
++	/* if the session drops it will clean up the mtask */
++	if (age != session->age ||
++	    session->state != ISCSI_STATE_LOGGED_IN)
++		return -ENOTCONN;
+ 	return 0;
+ }
  
- 	struct asd_seq_data  seq; /* sequencer related */
-+	u32    bios_status;
-+	const struct firmware *bios_image;
- };
+ /*
+- * session lock must be held
++ * Fail commands. session lock held and recv side suspended and xmit
++ * thread flushed
+  */
+-static struct iscsi_mgmt_task *
+-iscsi_remove_mgmt_task(struct kfifo *fifo, uint32_t itt)
++static void fail_all_commands(struct iscsi_conn *conn, unsigned lun)
+ {
+-	int i, nr_tasks = __kfifo_len(fifo) / sizeof(void*);
+-	struct iscsi_mgmt_task *task;
++	struct iscsi_cmd_task *ctask, *tmp;
  
- /* ---------- Common macros ---------- */
-diff --git a/drivers/scsi/aic94xx/aic94xx_init.c b/drivers/scsi/aic94xx/aic94xx_init.c
-index b70d6e7..5d761eb 100644
---- a/drivers/scsi/aic94xx/aic94xx_init.c
-+++ b/drivers/scsi/aic94xx/aic94xx_init.c
-@@ -29,6 +29,7 @@
- #include <linux/kernel.h>
- #include <linux/pci.h>
- #include <linux/delay.h>
-+#include <linux/firmware.h>
+-	debug_scsi("searching %d tasks\n", nr_tasks);
++	if (conn->ctask && (conn->ctask->sc->device->lun == lun || lun == -1))
++		conn->ctask = NULL;
  
- #include <scsi/scsi_host.h>
+-	for (i = 0; i < nr_tasks; i++) {
+-		__kfifo_get(fifo, (void*)&task, sizeof(void*));
+-		debug_scsi("check task %u\n", task->itt);
++	/* flush pending */
++	list_for_each_entry_safe(ctask, tmp, &conn->xmitqueue, running) {
++		if (lun == ctask->sc->device->lun || lun == -1) {
++			debug_scsi("failing pending sc %p itt 0x%x\n",
++				   ctask->sc, ctask->itt);
++			fail_command(conn, ctask, DID_BUS_BUSY << 16);
++		}
++	}
  
-@@ -36,6 +37,7 @@
- #include "aic94xx_reg.h"
- #include "aic94xx_hwi.h"
- #include "aic94xx_seq.h"
-+#include "aic94xx_sds.h"
+-		if (task->itt == itt) {
+-			debug_scsi("matched task\n");
+-			return task;
++	list_for_each_entry_safe(ctask, tmp, &conn->requeue, running) {
++		if (lun == ctask->sc->device->lun || lun == -1) {
++			debug_scsi("failing requeued sc %p itt 0x%x\n",
++				   ctask->sc, ctask->itt);
++			fail_command(conn, ctask, DID_BUS_BUSY << 16);
+ 		}
++	}
  
- /* The format is "version.release.patchlevel" */
- #define ASD_DRIVER_VERSION "1.0.3"
-@@ -134,7 +136,7 @@ Err:
- 	return err;
+-		__kfifo_put(fifo, (void*)&task, sizeof(void*));
++	/* fail all other running */
++	list_for_each_entry_safe(ctask, tmp, &conn->run_list, running) {
++		if (lun == ctask->sc->device->lun || lun == -1) {
++			debug_scsi("failing in progress sc %p itt 0x%x\n",
++				   ctask->sc, ctask->itt);
++			fail_command(conn, ctask, DID_BUS_BUSY << 16);
++		}
+ 	}
+-	return NULL;
  }
  
--static void __devexit asd_unmap_memio(struct asd_ha_struct *asd_ha)
-+static void asd_unmap_memio(struct asd_ha_struct *asd_ha)
+-static int iscsi_ctask_mtask_cleanup(struct iscsi_cmd_task *ctask)
++static void iscsi_suspend_tx(struct iscsi_conn *conn)
  {
- 	struct asd_ha_addrspace *io_handle;
+-	struct iscsi_conn *conn = ctask->conn;
+-	struct iscsi_session *session = conn->session;
+-
+-	if (!ctask->mtask)
+-		return -EINVAL;
++	set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
++	scsi_flush_work(conn->session->host);
++}
  
-@@ -171,7 +173,7 @@ static int __devinit asd_map_ioport(struct asd_ha_struct *asd_ha)
- 	return err;
+-	if (!iscsi_remove_mgmt_task(conn->mgmtqueue, ctask->mtask->itt))
+-		list_del(&ctask->mtask->running);
+-	__kfifo_put(session->mgmtpool.queue, (void*)&ctask->mtask,
+-		    sizeof(void*));
+-	ctask->mtask = NULL;
+-	return 0;
++static void iscsi_start_tx(struct iscsi_conn *conn)
++{
++	clear_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
++	scsi_queue_work(conn->session->host, &conn->xmitwork);
  }
  
--static void __devexit asd_unmap_ioport(struct asd_ha_struct *asd_ha)
-+static void asd_unmap_ioport(struct asd_ha_struct *asd_ha)
+-/*
+- * session lock must be held
+- */
+-static void fail_command(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask,
+-			 int err)
++static enum scsi_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *scmd)
  {
- 	pci_release_region(asd_ha->pcidev, PCI_IOBAR_OFFSET);
- }
-@@ -208,7 +210,7 @@ Err:
- 	return err;
- }
+-	struct scsi_cmnd *sc;
++	struct iscsi_cls_session *cls_session;
++	struct iscsi_session *session;
++	struct iscsi_conn *conn;
++	enum scsi_eh_timer_return rc = EH_NOT_HANDLED;
  
--static void __devexit asd_unmap_ha(struct asd_ha_struct *asd_ha)
-+static void asd_unmap_ha(struct asd_ha_struct *asd_ha)
- {
- 	if (asd_ha->iospace)
- 		asd_unmap_ioport(asd_ha);
-@@ -313,6 +315,181 @@ static ssize_t asd_show_dev_pcba_sn(struct device *dev,
- }
- static DEVICE_ATTR(pcba_sn, S_IRUGO, asd_show_dev_pcba_sn, NULL);
+-	sc = ctask->sc;
+-	if (!sc)
+-		return;
++	cls_session = starget_to_session(scsi_target(scmd->device));
++	session = class_to_transport_session(cls_session);
  
-+#define FLASH_CMD_NONE      0x00
-+#define FLASH_CMD_UPDATE    0x01
-+#define FLASH_CMD_VERIFY    0x02
-+
-+struct flash_command {
-+     u8      command[8];
-+     int     code;
-+};
-+
-+static struct flash_command flash_command_table[] =
-+{
-+     {"verify",      FLASH_CMD_VERIFY},
-+     {"update",      FLASH_CMD_UPDATE},
-+     {"",            FLASH_CMD_NONE}      /* Last entry should be NULL. */
-+};
-+
-+struct error_bios {
-+     char    *reason;
-+     int     err_code;
-+};
-+
-+static struct error_bios flash_error_table[] =
-+{
-+     {"Failed to open bios image file",      FAIL_OPEN_BIOS_FILE},
-+     {"PCI ID mismatch",                     FAIL_CHECK_PCI_ID},
-+     {"Checksum mismatch",                   FAIL_CHECK_SUM},
-+     {"Unknown Error",                       FAIL_UNKNOWN},
-+     {"Failed to verify.",                   FAIL_VERIFY},
-+     {"Failed to reset flash chip.",         FAIL_RESET_FLASH},
-+     {"Failed to find flash chip type.",     FAIL_FIND_FLASH_ID},
-+     {"Failed to erash flash chip.",         FAIL_ERASE_FLASH},
-+     {"Failed to program flash chip.",       FAIL_WRITE_FLASH},
-+     {"Flash in progress",                   FLASH_IN_PROGRESS},
-+     {"Image file size Error",               FAIL_FILE_SIZE},
-+     {"Input parameter error",               FAIL_PARAMETERS},
-+     {"Out of memory",                       FAIL_OUT_MEMORY},
-+     {"OK", 0}	/* Last entry err_code = 0. */
-+};
-+
-+static ssize_t asd_store_update_bios(struct device *dev,
-+	struct device_attribute *attr,
-+	const char *buf, size_t count)
-+{
-+	struct asd_ha_struct *asd_ha = dev_to_asd_ha(dev);
-+	char *cmd_ptr, *filename_ptr;
-+	struct bios_file_header header, *hdr_ptr;
-+	int res, i;
-+	u32 csum = 0;
-+	int flash_command = FLASH_CMD_NONE;
-+	int err = 0;
-+
-+	cmd_ptr = kzalloc(count*2, GFP_KERNEL);
-+
-+	if (!cmd_ptr) {
-+		err = FAIL_OUT_MEMORY;
-+		goto out;
-+	}
-+
-+	filename_ptr = cmd_ptr + count;
-+	res = sscanf(buf, "%s %s", cmd_ptr, filename_ptr);
-+	if (res != 2) {
-+		err = FAIL_PARAMETERS;
-+		goto out1;
-+	}
-+
-+	for (i = 0; flash_command_table[i].code != FLASH_CMD_NONE; i++) {
-+		if (!memcmp(flash_command_table[i].command,
-+				 cmd_ptr, strlen(cmd_ptr))) {
-+			flash_command = flash_command_table[i].code;
-+			break;
-+		}
-+	}
-+	if (flash_command == FLASH_CMD_NONE) {
-+		err = FAIL_PARAMETERS;
-+		goto out1;
-+	}
+-	if (ctask->state == ISCSI_TASK_PENDING)
++	debug_scsi("scsi cmd %p timedout\n", scmd);
 +
-+	if (asd_ha->bios_status == FLASH_IN_PROGRESS) {
-+		err = FLASH_IN_PROGRESS;
-+		goto out1;
++	spin_lock(&session->lock);
++	if (session->state != ISCSI_STATE_LOGGED_IN) {
+ 		/*
+-		 * cmd never made it to the xmit thread, so we should not count
+-		 * the cmd in the sequencing
++		 * We are probably in the middle of iscsi recovery so let
++		 * that complete and handle the error.
+ 		 */
+-		conn->session->queued_cmdsn--;
+-	else
+-		conn->session->tt->cleanup_cmd_task(conn, ctask);
+-	iscsi_ctask_mtask_cleanup(ctask);
++		rc = EH_RESET_TIMER;
++		goto done;
 +	}
-+	err = request_firmware(&asd_ha->bios_image,
-+				   filename_ptr,
-+				   &asd_ha->pcidev->dev);
-+	if (err) {
-+		asd_printk("Failed to load bios image file %s, error %d\n",
-+			   filename_ptr, err);
-+		err = FAIL_OPEN_BIOS_FILE;
-+		goto out1;
+ 
+-	sc->result = err;
+-	scsi_set_resid(sc, scsi_bufflen(sc));
+-	if (conn->ctask == ctask)
+-		conn->ctask = NULL;
+-	/* release ref from queuecommand */
+-	__iscsi_put_ctask(ctask);
++	conn = session->leadconn;
++	if (!conn) {
++		/* In the middle of shuting down */
++		rc = EH_RESET_TIMER;
++		goto done;
 +	}
 +
-+	hdr_ptr = (struct bios_file_header *)asd_ha->bios_image->data;
++	if (!conn->recv_timeout && !conn->ping_timeout)
++		goto done;
++	/*
++	 * if the ping timedout then we are in the middle of cleaning up
++	 * and can let the iscsi eh handle it
++	 */
++	if (time_before_eq(conn->last_recv + (conn->recv_timeout * HZ) +
++			    (conn->ping_timeout * HZ), jiffies))
++		rc = 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;
++	/* if in the middle of checking the transport then give us more time */
++	if (conn->ping_mtask)
++		rc = EH_RESET_TIMER;
++done:
++	spin_unlock(&session->lock);
++	debug_scsi("return %s\n", rc == EH_RESET_TIMER ? "timer reset" : "nh");
++	return rc;
+ }
+ 
+-static void iscsi_suspend_tx(struct iscsi_conn *conn)
++static void iscsi_check_transport_timeouts(unsigned long data)
+ {
+-	set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
+-	scsi_flush_work(conn->session->host);
++	struct iscsi_conn *conn = (struct iscsi_conn *)data;
++	struct iscsi_session *session = conn->session;
++	unsigned long timeout, next_timeout = 0, last_recv;
 +
-+	if ((hdr_ptr->contrl_id.vendor != asd_ha->pcidev->vendor ||
-+		hdr_ptr->contrl_id.device != asd_ha->pcidev->device) &&
-+		(hdr_ptr->contrl_id.sub_vendor != asd_ha->pcidev->vendor ||
-+		hdr_ptr->contrl_id.sub_device != asd_ha->pcidev->device)) {
++	spin_lock(&session->lock);
++	if (session->state != ISCSI_STATE_LOGGED_IN)
++		goto done;
 +
-+		ASD_DPRINTK("The PCI vendor or device id does not match\n");
-+		ASD_DPRINTK("vendor=%x dev=%x sub_vendor=%x sub_dev=%x"
-+		" pci vendor=%x pci dev=%x\n",
-+		hdr_ptr->contrl_id.vendor,
-+		hdr_ptr->contrl_id.device,
-+		hdr_ptr->contrl_id.sub_vendor,
-+		hdr_ptr->contrl_id.sub_device,
-+		asd_ha->pcidev->vendor,
-+		asd_ha->pcidev->device);
-+		err = FAIL_CHECK_PCI_ID;
-+		goto out2;
-+	}
++	timeout = conn->recv_timeout;
++	if (!timeout)
++		goto done;
 +
-+	if (hdr_ptr->filelen != asd_ha->bios_image->size) {
-+		err = FAIL_FILE_SIZE;
-+		goto out2;
++	timeout *= HZ;
++	last_recv = conn->last_recv;
++	if (time_before_eq(last_recv + timeout + (conn->ping_timeout * HZ),
++			   jiffies)) {
++		printk(KERN_ERR "ping timeout of %d secs expired, "
++		       "last rx %lu, last ping %lu, now %lu\n",
++		       conn->ping_timeout, last_recv,
++		       conn->last_ping, jiffies);
++		spin_unlock(&session->lock);
++		iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
++		return;
 +	}
 +
-+	/* calculate checksum */
-+	for (i = 0; i < hdr_ptr->filelen; i++)
-+		csum += asd_ha->bios_image->data[i];
-+
-+	if ((csum & 0x0000ffff) != hdr_ptr->checksum) {
-+		ASD_DPRINTK("BIOS file checksum mismatch\n");
-+		err = FAIL_CHECK_SUM;
-+		goto out2;
-+	}
-+	if (flash_command == FLASH_CMD_UPDATE) {
-+		asd_ha->bios_status = FLASH_IN_PROGRESS;
-+		err = asd_write_flash_seg(asd_ha,
-+			&asd_ha->bios_image->data[sizeof(*hdr_ptr)],
-+			0, hdr_ptr->filelen-sizeof(*hdr_ptr));
-+		if (!err)
-+			err = asd_verify_flash_seg(asd_ha,
-+				&asd_ha->bios_image->data[sizeof(*hdr_ptr)],
-+				0, hdr_ptr->filelen-sizeof(*hdr_ptr));
++	if (time_before_eq(last_recv + timeout, jiffies)) {
++		if (time_before_eq(conn->last_ping, last_recv)) {
++			/* send a ping to try to provoke some traffic */
++			debug_scsi("Sending nopout as ping on conn %p\n", conn);
++			iscsi_send_nopout(conn, NULL);
++		}
++		next_timeout = last_recv + timeout + (conn->ping_timeout * HZ);
 +	} else {
-+		asd_ha->bios_status = FLASH_IN_PROGRESS;
-+		err = asd_verify_flash_seg(asd_ha,
-+			&asd_ha->bios_image->data[sizeof(header)],
-+			0, hdr_ptr->filelen-sizeof(header));
++		next_timeout = last_recv + timeout;
 +	}
 +
-+out2:
-+	release_firmware(asd_ha->bios_image);
-+out1:
-+	kfree(cmd_ptr);
-+out:
-+	asd_ha->bios_status = err;
-+
-+	if (!err)
-+		return count;
-+	else
-+		return -err;
-+}
-+
-+static ssize_t asd_show_update_bios(struct device *dev,
-+				    struct device_attribute *attr, char *buf)
-+{
-+	int i;
-+	struct asd_ha_struct *asd_ha = dev_to_asd_ha(dev);
-+
-+	for (i = 0; flash_error_table[i].err_code != 0; i++) {
-+		if (flash_error_table[i].err_code == asd_ha->bios_status)
-+			break;
++	if (next_timeout) {
++		debug_scsi("Setting next tmo %lu\n", next_timeout);
++		mod_timer(&conn->transport_timer, next_timeout);
 +	}
-+	if (asd_ha->bios_status != FLASH_IN_PROGRESS)
-+		asd_ha->bios_status = FLASH_OK;
-+
-+	return snprintf(buf, PAGE_SIZE, "status=%x %s\n",
-+			flash_error_table[i].err_code,
-+			flash_error_table[i].reason);
-+}
-+
-+static DEVICE_ATTR(update_bios, S_IRUGO|S_IWUGO,
-+	asd_show_update_bios, asd_store_update_bios);
-+
- static int asd_create_dev_attrs(struct asd_ha_struct *asd_ha)
- {
- 	int err;
-@@ -328,9 +505,14 @@ static int asd_create_dev_attrs(struct asd_ha_struct *asd_ha)
- 	err = device_create_file(&asd_ha->pcidev->dev, &dev_attr_pcba_sn);
- 	if (err)
- 		goto err_biosb;
-+	err = device_create_file(&asd_ha->pcidev->dev, &dev_attr_update_bios);
-+	if (err)
-+		goto err_update_bios;
- 
- 	return 0;
- 
-+err_update_bios:
-+	device_remove_file(&asd_ha->pcidev->dev, &dev_attr_pcba_sn);
- err_biosb:
- 	device_remove_file(&asd_ha->pcidev->dev, &dev_attr_bios_build);
- err_rev:
-@@ -343,6 +525,7 @@ static void asd_remove_dev_attrs(struct asd_ha_struct *asd_ha)
- 	device_remove_file(&asd_ha->pcidev->dev, &dev_attr_revision);
- 	device_remove_file(&asd_ha->pcidev->dev, &dev_attr_bios_build);
- 	device_remove_file(&asd_ha->pcidev->dev, &dev_attr_pcba_sn);
-+	device_remove_file(&asd_ha->pcidev->dev, &dev_attr_update_bios);
++done:
++	spin_unlock(&session->lock);
  }
  
- /* The first entry, 0, is used for dynamic ids, the rest for devices
-@@ -589,6 +772,7 @@ static int __devinit asd_pci_probe(struct pci_dev *dev,
- 	asd_ha->sas_ha.dev = &asd_ha->pcidev->dev;
- 	asd_ha->sas_ha.lldd_ha = asd_ha;
- 
-+	asd_ha->bios_status = FLASH_OK;
- 	asd_ha->name = asd_dev->name;
- 	asd_printk("found %s, device %s\n", asd_ha->name, pci_name(dev));
- 
-diff --git a/drivers/scsi/aic94xx/aic94xx_scb.c b/drivers/scsi/aic94xx/aic94xx_scb.c
-index db6ab1a..0febad4 100644
---- a/drivers/scsi/aic94xx/aic94xx_scb.c
-+++ b/drivers/scsi/aic94xx/aic94xx_scb.c
-@@ -788,12 +788,12 @@ void asd_build_control_phy(struct asd_ascb *ascb, int phy_id, u8 subfunc)
- 
- 		/* initiator port settings are in the hi nibble */
- 		if (phy->sas_phy.role == PHY_ROLE_INITIATOR)
--			control_phy->port_type = SAS_PROTO_ALL << 4;
-+			control_phy->port_type = SAS_PROTOCOL_ALL << 4;
- 		else if (phy->sas_phy.role == PHY_ROLE_TARGET)
--			control_phy->port_type = SAS_PROTO_ALL;
-+			control_phy->port_type = SAS_PROTOCOL_ALL;
- 		else
- 			control_phy->port_type =
--				(SAS_PROTO_ALL << 4) | SAS_PROTO_ALL;
-+				(SAS_PROTOCOL_ALL << 4) | SAS_PROTOCOL_ALL;
- 
- 		/* link reset retries, this should be nominal */
- 		control_phy->link_reset_retries = 10;
-diff --git a/drivers/scsi/aic94xx/aic94xx_sds.c b/drivers/scsi/aic94xx/aic94xx_sds.c
-index 06509bf..2a4c933 100644
---- a/drivers/scsi/aic94xx/aic94xx_sds.c
-+++ b/drivers/scsi/aic94xx/aic94xx_sds.c
-@@ -30,6 +30,7 @@
+-static void iscsi_start_tx(struct iscsi_conn *conn)
++static void iscsi_prep_abort_task_pdu(struct iscsi_cmd_task *ctask,
++				      struct iscsi_tm *hdr)
+ {
+-	clear_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
+-	scsi_queue_work(conn->session->host, &conn->xmitwork);
++	memset(hdr, 0, sizeof(*hdr));
++	hdr->opcode = ISCSI_OP_SCSI_TMFUNC | ISCSI_OP_IMMEDIATE;
++	hdr->flags = ISCSI_TM_FUNC_ABORT_TASK & ISCSI_FLAG_TM_FUNC_MASK;
++	hdr->flags |= ISCSI_FLAG_CMD_FINAL;
++	memcpy(hdr->lun, ctask->hdr->lun, sizeof(hdr->lun));
++	hdr->rtt = ctask->hdr->itt;
++	hdr->refcmdsn = ctask->hdr->cmdsn;
+ }
  
- #include "aic94xx.h"
- #include "aic94xx_reg.h"
-+#include "aic94xx_sds.h"
+ int iscsi_eh_abort(struct scsi_cmnd *sc)
+ {
+ 	struct Scsi_Host *host = sc->device->host;
+ 	struct iscsi_session *session = iscsi_hostdata(host->hostdata);
+-	struct iscsi_cmd_task *ctask;
+ 	struct iscsi_conn *conn;
+-	int rc;
++	struct iscsi_cmd_task *ctask;
++	struct iscsi_tm *hdr;
++	int rc, age;
  
- /* ---------- OCM stuff ---------- */
+ 	mutex_lock(&session->eh_mutex);
+ 	spin_lock_bh(&session->lock);
+@@ -1199,19 +1419,23 @@ int iscsi_eh_abort(struct scsi_cmnd *sc)
+ 		return SUCCESS;
+ 	}
  
-@@ -1083,3 +1084,391 @@ out:
- 	kfree(flash_dir);
- 	return err;
- }
-+
-+/**
-+ * asd_verify_flash_seg - verify data with flash memory
-+ * @asd_ha: pointer to the host adapter structure
-+ * @src: pointer to the source data to be verified
-+ * @dest_offset: offset from flash memory
-+ * @bytes_to_verify: total bytes to verify
-+ */
-+int asd_verify_flash_seg(struct asd_ha_struct *asd_ha,
-+		void *src, u32 dest_offset, u32 bytes_to_verify)
-+{
-+	u8 *src_buf;
-+	u8 flash_char;
-+	int err;
-+	u32 nv_offset, reg, i;
-+
-+	reg = asd_ha->hw_prof.flash.bar;
-+	src_buf = NULL;
-+
-+	err = FLASH_OK;
-+	nv_offset = dest_offset;
-+	src_buf = (u8 *)src;
-+	for (i = 0; i < bytes_to_verify; i++) {
-+		flash_char = asd_read_reg_byte(asd_ha, reg + nv_offset + i);
-+		if (flash_char != src_buf[i]) {
-+			err = FAIL_VERIFY;
-+			break;
-+		}
-+	}
-+	return err;
-+}
-+
-+/**
-+ * asd_write_flash_seg - write data into flash memory
-+ * @asd_ha: pointer to the host adapter structure
-+ * @src: pointer to the source data to be written
-+ * @dest_offset: offset from flash memory
-+ * @bytes_to_write: total bytes to write
-+ */
-+int asd_write_flash_seg(struct asd_ha_struct *asd_ha,
-+		void *src, u32 dest_offset, u32 bytes_to_write)
-+{
-+	u8 *src_buf;
-+	u32 nv_offset, reg, i;
-+	int err;
-+
-+	reg = asd_ha->hw_prof.flash.bar;
-+	src_buf = NULL;
-+
-+	err = asd_check_flash_type(asd_ha);
-+	if (err) {
-+		ASD_DPRINTK("couldn't find the type of flash. err=%d\n", err);
-+		return err;
+-	ctask = (struct iscsi_cmd_task *)sc->SCp.ptr;
+-	conn = ctask->conn;
+-
+-	conn->eh_abort_cnt++;
+-	debug_scsi("aborting [sc %p itt 0x%x]\n", sc, ctask->itt);
+-
+ 	/*
+ 	 * If we are not logged in or we have started a new session
+ 	 * then let the host reset code handle this
+ 	 */
+-	if (session->state != ISCSI_STATE_LOGGED_IN ||
+-	    sc->SCp.phase != session->age)
+-		goto failed;
++	if (!session->leadconn || session->state != ISCSI_STATE_LOGGED_IN ||
++	    sc->SCp.phase != session->age) {
++		spin_unlock_bh(&session->lock);
++		mutex_unlock(&session->eh_mutex);
++		return FAILED;
 +	}
 +
-+	nv_offset = dest_offset;
-+	err = asd_erase_nv_sector(asd_ha, nv_offset, bytes_to_write);
-+	if (err) {
-+		ASD_DPRINTK("Erase failed at offset:0x%x\n",
-+			nv_offset);
-+		return err;
-+	}
++	conn = session->leadconn;
++	conn->eh_abort_cnt++;
++	age = session->age;
 +
-+	err = asd_reset_flash(asd_ha);
-+	if (err) {
-+		ASD_DPRINTK("couldn't reset flash. err=%d\n", err);
-+		return err;
-+	}
++	ctask = (struct iscsi_cmd_task *)sc->SCp.ptr;
++	debug_scsi("aborting [sc %p itt 0x%x]\n", sc, ctask->itt);
+ 
+ 	/* ctask completed before time out */
+ 	if (!ctask->sc) {
+@@ -1219,27 +1443,26 @@ int iscsi_eh_abort(struct scsi_cmnd *sc)
+ 		goto success;
+ 	}
+ 
+-	/* what should we do here ? */
+-	if (conn->ctask == ctask) {
+-		printk(KERN_INFO "iscsi: sc %p itt 0x%x partially sent. "
+-		       "Failing abort\n", sc, ctask->itt);
+-		goto failed;
+-	}
+-
+ 	if (ctask->state == ISCSI_TASK_PENDING) {
+ 		fail_command(conn, ctask, DID_ABORT << 16);
+ 		goto success;
+ 	}
+ 
+-	conn->tmabort_state = TMABORT_INITIAL;
+-	rc = iscsi_exec_abort_task(sc, ctask);
+-	if (rc || sc->SCp.phase != session->age ||
+-	    session->state != ISCSI_STATE_LOGGED_IN)
++	/* only have one tmf outstanding at a time */
++	if (conn->tmf_state != TMF_INITIAL)
++		goto failed;
++	conn->tmf_state = TMF_QUEUED;
 +
-+	src_buf = (u8 *)src;
-+	for (i = 0; i < bytes_to_write; i++) {
-+		/* Setup program command sequence */
-+		switch (asd_ha->hw_prof.flash.method) {
-+		case FLASH_METHOD_A:
-+		{
-+			asd_write_reg_byte(asd_ha,
-+					(reg + 0xAAA), 0xAA);
-+			asd_write_reg_byte(asd_ha,
-+					(reg + 0x555), 0x55);
-+			asd_write_reg_byte(asd_ha,
-+					(reg + 0xAAA), 0xA0);
-+			asd_write_reg_byte(asd_ha,
-+					(reg + nv_offset + i),
-+					(*(src_buf + i)));
-+			break;
-+		}
-+		case FLASH_METHOD_B:
-+		{
-+			asd_write_reg_byte(asd_ha,
-+					(reg + 0x555), 0xAA);
-+			asd_write_reg_byte(asd_ha,
-+					(reg + 0x2AA), 0x55);
-+			asd_write_reg_byte(asd_ha,
-+					(reg + 0x555), 0xA0);
-+			asd_write_reg_byte(asd_ha,
-+					(reg + nv_offset + i),
-+					(*(src_buf + i)));
-+			break;
-+		}
-+		default:
-+			break;
-+		}
-+		if (asd_chk_write_status(asd_ha,
-+				(nv_offset + i), 0) != 0) {
-+			ASD_DPRINTK("aicx: Write failed at offset:0x%x\n",
-+				reg + nv_offset + i);
-+			return FAIL_WRITE_FLASH;
-+		}
-+	}
++	hdr = &conn->tmhdr;
++	iscsi_prep_abort_task_pdu(ctask, hdr);
 +
-+	err = asd_reset_flash(asd_ha);
-+	if (err) {
-+		ASD_DPRINTK("couldn't reset flash. err=%d\n", err);
-+		return err;
++	if (iscsi_exec_task_mgmt_fn(conn, hdr, age, session->abort_timeout)) {
++		rc = FAILED;
+ 		goto failed;
+-	iscsi_ctask_mtask_cleanup(ctask);
 +	}
-+	return 0;
-+}
-+
-+int asd_chk_write_status(struct asd_ha_struct *asd_ha,
-+	 u32 sector_addr, u8 erase_flag)
+ 
+-	switch (conn->tmabort_state) {
+-	case TMABORT_SUCCESS:
++	switch (conn->tmf_state) {
++	case TMF_SUCCESS:
+ 		spin_unlock_bh(&session->lock);
+ 		iscsi_suspend_tx(conn);
+ 		/*
+@@ -1248,22 +1471,26 @@ int iscsi_eh_abort(struct scsi_cmnd *sc)
+ 		write_lock_bh(conn->recv_lock);
+ 		spin_lock(&session->lock);
+ 		fail_command(conn, ctask, DID_ABORT << 16);
++		conn->tmf_state = TMF_INITIAL;
+ 		spin_unlock(&session->lock);
+ 		write_unlock_bh(conn->recv_lock);
+ 		iscsi_start_tx(conn);
+ 		goto success_unlocked;
+-	case TMABORT_NOT_FOUND:
+-		if (!ctask->sc) {
++	case TMF_TIMEDOUT:
++		spin_unlock_bh(&session->lock);
++		iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
++		goto failed_unlocked;
++	case TMF_NOT_FOUND:
++		if (!sc->SCp.ptr) {
++			conn->tmf_state = TMF_INITIAL;
+ 			/* ctask completed before tmf abort response */
+ 			debug_scsi("sc completed while abort in progress\n");
+ 			goto success;
+ 		}
+ 		/* fall through */
+ 	default:
+-		/* timedout or failed */
+-		spin_unlock_bh(&session->lock);
+-		iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
+-		goto failed_unlocked;
++		conn->tmf_state = TMF_INITIAL;
++		goto failed;
+ 	}
+ 
+ success:
+@@ -1276,65 +1503,152 @@ success_unlocked:
+ failed:
+ 	spin_unlock_bh(&session->lock);
+ failed_unlocked:
+-	debug_scsi("abort failed [sc %lx itt 0x%x]\n", (long)sc, ctask->itt);
++	debug_scsi("abort failed [sc %p itt 0x%x]\n", sc,
++		    ctask ? ctask->itt : 0);
+ 	mutex_unlock(&session->eh_mutex);
+ 	return FAILED;
+ }
+ EXPORT_SYMBOL_GPL(iscsi_eh_abort);
+ 
++static void iscsi_prep_lun_reset_pdu(struct scsi_cmnd *sc, struct iscsi_tm *hdr)
 +{
-+	u32 reg;
-+	u32 loop_cnt;
-+	u8  nv_data1, nv_data2;
-+	u8  toggle_bit1;
-+
-+	/*
-+	 * Read from DQ2 requires sector address
-+	 * while it's dont care for DQ6
-+	 */
-+	reg = asd_ha->hw_prof.flash.bar;
-+
-+	for (loop_cnt = 0; loop_cnt < 50000; loop_cnt++) {
-+		nv_data1 = asd_read_reg_byte(asd_ha, reg);
-+		nv_data2 = asd_read_reg_byte(asd_ha, reg);
-+
-+		toggle_bit1 = ((nv_data1 & FLASH_STATUS_BIT_MASK_DQ6)
-+				 ^ (nv_data2 & FLASH_STATUS_BIT_MASK_DQ6));
-+
-+		if (toggle_bit1 == 0) {
-+			return 0;
-+		} else {
-+			if (nv_data2 & FLASH_STATUS_BIT_MASK_DQ5) {
-+				nv_data1 = asd_read_reg_byte(asd_ha,
-+								reg);
-+				nv_data2 = asd_read_reg_byte(asd_ha,
-+								reg);
-+				toggle_bit1 =
-+				((nv_data1 & FLASH_STATUS_BIT_MASK_DQ6)
-+				^ (nv_data2 & FLASH_STATUS_BIT_MASK_DQ6));
-+
-+				if (toggle_bit1 == 0)
-+					return 0;
-+			}
-+		}
-+
-+		/*
-+		 * ERASE is a sector-by-sector operation and requires
-+		 * more time to finish while WRITE is byte-byte-byte
-+		 * operation and takes lesser time to finish.
-+		 *
-+		 * For some strange reason a reduced ERASE delay gives different
-+		 * behaviour across different spirit boards. Hence we set
-+		 * a optimum balance of 50mus for ERASE which works well
-+		 * across all boards.
-+		 */
-+		if (erase_flag) {
-+			udelay(FLASH_STATUS_ERASE_DELAY_COUNT);
-+		} else {
-+			udelay(FLASH_STATUS_WRITE_DELAY_COUNT);
-+		}
-+	}
-+	return -1;
++	memset(hdr, 0, sizeof(*hdr));
++	hdr->opcode = ISCSI_OP_SCSI_TMFUNC | ISCSI_OP_IMMEDIATE;
++	hdr->flags = ISCSI_TM_FUNC_LOGICAL_UNIT_RESET & ISCSI_FLAG_TM_FUNC_MASK;
++	hdr->flags |= ISCSI_FLAG_CMD_FINAL;
++	int_to_scsilun(sc->device->lun, (struct scsi_lun *)hdr->lun);
++	hdr->rtt = RESERVED_ITT;
 +}
 +
-+/**
-+ * asd_hwi_erase_nv_sector - Erase the flash memory sectors.
-+ * @asd_ha: pointer to the host adapter structure
-+ * @flash_addr: pointer to offset from flash memory
-+ * @size: total bytes to erase.
-+ */
-+int asd_erase_nv_sector(struct asd_ha_struct *asd_ha, u32 flash_addr, u32 size)
++int iscsi_eh_device_reset(struct scsi_cmnd *sc)
 +{
-+	u32 reg;
-+	u32 sector_addr;
-+
-+	reg = asd_ha->hw_prof.flash.bar;
++	struct Scsi_Host *host = sc->device->host;
++	struct iscsi_session *session = iscsi_hostdata(host->hostdata);
++	struct iscsi_conn *conn;
++	struct iscsi_tm *hdr;
++	int rc = FAILED;
 +
-+	/* sector staring address */
-+	sector_addr = flash_addr & FLASH_SECTOR_SIZE_MASK;
++	debug_scsi("LU Reset [sc %p lun %u]\n", sc, sc->device->lun);
 +
++	mutex_lock(&session->eh_mutex);
++	spin_lock_bh(&session->lock);
 +	/*
-+	 * Erasing an flash sector needs to be done in six consecutive
-+	 * write cyles.
-+	 */
-+	while (sector_addr < flash_addr+size) {
-+		switch (asd_ha->hw_prof.flash.method) {
-+		case FLASH_METHOD_A:
-+			asd_write_reg_byte(asd_ha, (reg + 0xAAA), 0xAA);
-+			asd_write_reg_byte(asd_ha, (reg + 0x555), 0x55);
-+			asd_write_reg_byte(asd_ha, (reg + 0xAAA), 0x80);
-+			asd_write_reg_byte(asd_ha, (reg + 0xAAA), 0xAA);
-+			asd_write_reg_byte(asd_ha, (reg + 0x555), 0x55);
-+			asd_write_reg_byte(asd_ha, (reg + sector_addr), 0x30);
-+			break;
-+		case FLASH_METHOD_B:
-+			asd_write_reg_byte(asd_ha, (reg + 0x555), 0xAA);
-+			asd_write_reg_byte(asd_ha, (reg + 0x2AA), 0x55);
-+			asd_write_reg_byte(asd_ha, (reg + 0x555), 0x80);
-+			asd_write_reg_byte(asd_ha, (reg + 0x555), 0xAA);
-+			asd_write_reg_byte(asd_ha, (reg + 0x2AA), 0x55);
-+			asd_write_reg_byte(asd_ha, (reg + sector_addr), 0x30);
-+			break;
-+		default:
-+			break;
-+		}
-+
-+		if (asd_chk_write_status(asd_ha, sector_addr, 1) != 0)
-+			return FAIL_ERASE_FLASH;
-+
-+		sector_addr += FLASH_SECTOR_SIZE;
-+	}
-+
-+	return 0;
-+}
-+
-+int asd_check_flash_type(struct asd_ha_struct *asd_ha)
-+{
-+	u8 manuf_id;
-+	u8 dev_id;
-+	u8 sec_prot;
-+	u32 inc;
-+	u32 reg;
-+	int err;
-+
-+	/* get Flash memory base address */
-+	reg = asd_ha->hw_prof.flash.bar;
-+
-+	/* Determine flash info */
-+	err = asd_reset_flash(asd_ha);
-+	if (err) {
-+		ASD_DPRINTK("couldn't reset flash. err=%d\n", err);
-+		return err;
-+	}
-+
-+	asd_ha->hw_prof.flash.method = FLASH_METHOD_UNKNOWN;
-+	asd_ha->hw_prof.flash.manuf = FLASH_MANUF_ID_UNKNOWN;
-+	asd_ha->hw_prof.flash.dev_id = FLASH_DEV_ID_UNKNOWN;
-+
-+	/* Get flash info. This would most likely be AMD Am29LV family flash.
-+	 * First try the sequence for word mode.  It is the same as for
-+	 * 008B (byte mode only), 160B (word mode) and 800D (word mode).
++	 * Just check if we are not logged in. We cannot check for
++	 * the phase because the reset could come from a ioctl.
 +	 */
-+	inc = asd_ha->hw_prof.flash.wide ? 2 : 1;
-+	asd_write_reg_byte(asd_ha, reg + 0xAAA, 0xAA);
-+	asd_write_reg_byte(asd_ha, reg + 0x555, 0x55);
-+	asd_write_reg_byte(asd_ha, reg + 0xAAA, 0x90);
-+	manuf_id = asd_read_reg_byte(asd_ha, reg);
-+	dev_id = asd_read_reg_byte(asd_ha, reg + inc);
-+	sec_prot = asd_read_reg_byte(asd_ha, reg + inc + inc);
-+	/* Get out of autoselect mode. */
-+	err = asd_reset_flash(asd_ha);
-+	if (err) {
-+		ASD_DPRINTK("couldn't reset flash. err=%d\n", err);
-+		return err;
-+	}
-+	ASD_DPRINTK("Flash MethodA manuf_id(0x%x) dev_id(0x%x) "
-+		"sec_prot(0x%x)\n", manuf_id, dev_id, sec_prot);
-+	err = asd_reset_flash(asd_ha);
-+	if (err != 0)
-+		return err;
-+
-+	switch (manuf_id) {
-+	case FLASH_MANUF_ID_AMD:
-+		switch (sec_prot) {
-+		case FLASH_DEV_ID_AM29LV800DT:
-+		case FLASH_DEV_ID_AM29LV640MT:
-+		case FLASH_DEV_ID_AM29F800B:
-+			asd_ha->hw_prof.flash.method = FLASH_METHOD_A;
-+			break;
-+		default:
-+			break;
-+		}
-+		break;
-+	case FLASH_MANUF_ID_ST:
-+		switch (sec_prot) {
-+		case FLASH_DEV_ID_STM29W800DT:
-+		case FLASH_DEV_ID_STM29LV640:
-+			asd_ha->hw_prof.flash.method = FLASH_METHOD_A;
-+			break;
-+		default:
-+			break;
-+		}
-+		break;
-+	case FLASH_MANUF_ID_FUJITSU:
-+		switch (sec_prot) {
-+		case FLASH_DEV_ID_MBM29LV800TE:
-+		case FLASH_DEV_ID_MBM29DL800TA:
-+			asd_ha->hw_prof.flash.method = FLASH_METHOD_A;
-+			break;
-+		}
-+		break;
-+	case FLASH_MANUF_ID_MACRONIX:
-+		switch (sec_prot) {
-+		case FLASH_DEV_ID_MX29LV800BT:
-+			asd_ha->hw_prof.flash.method = FLASH_METHOD_A;
-+			break;
-+		}
-+		break;
-+	}
-+
-+	if (asd_ha->hw_prof.flash.method == FLASH_METHOD_UNKNOWN) {
-+		err = asd_reset_flash(asd_ha);
-+		if (err) {
-+			ASD_DPRINTK("couldn't reset flash. err=%d\n", err);
-+			return err;
-+		}
-+
-+		/* Issue Unlock sequence for AM29LV008BT */
-+		asd_write_reg_byte(asd_ha, (reg + 0x555), 0xAA);
-+		asd_write_reg_byte(asd_ha, (reg + 0x2AA), 0x55);
-+		asd_write_reg_byte(asd_ha, (reg + 0x555), 0x90);
-+		manuf_id = asd_read_reg_byte(asd_ha, reg);
-+		dev_id = asd_read_reg_byte(asd_ha, reg + inc);
-+		sec_prot = asd_read_reg_byte(asd_ha, reg + inc + inc);
-+
-+		ASD_DPRINTK("Flash MethodB manuf_id(0x%x) dev_id(0x%x) sec_prot"
-+			"(0x%x)\n", manuf_id, dev_id, sec_prot);
-+
-+		err = asd_reset_flash(asd_ha);
-+		if (err != 0) {
-+			ASD_DPRINTK("couldn't reset flash. err=%d\n", err);
-+			return err;
-+		}
-+
-+		switch (manuf_id) {
-+		case FLASH_MANUF_ID_AMD:
-+			switch (dev_id) {
-+			case FLASH_DEV_ID_AM29LV008BT:
-+				asd_ha->hw_prof.flash.method = FLASH_METHOD_B;
-+				break;
-+			default:
-+				break;
-+			}
-+			break;
-+		case FLASH_MANUF_ID_ST:
-+			switch (dev_id) {
-+			case FLASH_DEV_ID_STM29008:
-+				asd_ha->hw_prof.flash.method = FLASH_METHOD_B;
-+				break;
-+			default:
-+				break;
-+			}
-+			break;
-+		case FLASH_MANUF_ID_FUJITSU:
-+			switch (dev_id) {
-+			case FLASH_DEV_ID_MBM29LV008TA:
-+				asd_ha->hw_prof.flash.method = FLASH_METHOD_B;
-+				break;
-+			}
-+			break;
-+		case FLASH_MANUF_ID_INTEL:
-+			switch (dev_id) {
-+			case FLASH_DEV_ID_I28LV00TAT:
-+				asd_ha->hw_prof.flash.method = FLASH_METHOD_B;
-+				break;
-+			}
-+			break;
-+		case FLASH_MANUF_ID_MACRONIX:
-+			switch (dev_id) {
-+			case FLASH_DEV_ID_I28LV00TAT:
-+				asd_ha->hw_prof.flash.method = FLASH_METHOD_B;
-+				break;
-+			}
-+			break;
-+		default:
-+			return FAIL_FIND_FLASH_ID;
-+		}
-+	}
-+
-+	if (asd_ha->hw_prof.flash.method == FLASH_METHOD_UNKNOWN)
-+	      return FAIL_FIND_FLASH_ID;
-+
-+	asd_ha->hw_prof.flash.manuf = manuf_id;
-+	asd_ha->hw_prof.flash.dev_id = dev_id;
-+	asd_ha->hw_prof.flash.sec_prot = sec_prot;
-+	return 0;
-+}
-diff --git a/drivers/scsi/aic94xx/aic94xx_sds.h b/drivers/scsi/aic94xx/aic94xx_sds.h
-new file mode 100644
-index 0000000..bb9795a
---- /dev/null
-+++ b/drivers/scsi/aic94xx/aic94xx_sds.h
-@@ -0,0 +1,121 @@
-+/*
-+ * Aic94xx SAS/SATA driver hardware interface header file.
-+ *
-+ * Copyright (C) 2005 Adaptec, Inc.  All rights reserved.
-+ * Copyright (C) 2005 Gilbert Wu <gilbert_wu at adaptec.com>
-+ *
-+ * This file is licensed under GPLv2.
-+ *
-+ * This file is part of the aic94xx driver.
-+ *
-+ * The aic94xx 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; version 2 of the
-+ * License.
-+ *
-+ * The aic94xx 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 the aic94xx driver; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
-+ *
-+ */
-+#ifndef _AIC94XX_SDS_H_
-+#define _AIC94XX_SDS_H_
-+
-+enum {
-+	FLASH_METHOD_UNKNOWN,
-+	FLASH_METHOD_A,
-+	FLASH_METHOD_B
-+};
-+
-+#define FLASH_MANUF_ID_AMD              0x01
-+#define FLASH_MANUF_ID_ST               0x20
-+#define FLASH_MANUF_ID_FUJITSU          0x04
-+#define FLASH_MANUF_ID_MACRONIX         0xC2
-+#define FLASH_MANUF_ID_INTEL            0x89
-+#define FLASH_MANUF_ID_UNKNOWN          0xFF
-+
-+#define FLASH_DEV_ID_AM29LV008BT        0x3E
-+#define FLASH_DEV_ID_AM29LV800DT        0xDA
-+#define FLASH_DEV_ID_STM29W800DT        0xD7
-+#define FLASH_DEV_ID_STM29LV640         0xDE
-+#define FLASH_DEV_ID_STM29008           0xEA
-+#define FLASH_DEV_ID_MBM29LV800TE       0xDA
-+#define FLASH_DEV_ID_MBM29DL800TA       0x4A
-+#define FLASH_DEV_ID_MBM29LV008TA       0x3E
-+#define FLASH_DEV_ID_AM29LV640MT        0x7E
-+#define FLASH_DEV_ID_AM29F800B          0xD6
-+#define FLASH_DEV_ID_MX29LV800BT        0xDA
-+#define FLASH_DEV_ID_MX29LV008CT        0xDA
-+#define FLASH_DEV_ID_I28LV00TAT         0x3E
-+#define FLASH_DEV_ID_UNKNOWN            0xFF
++	if (!session->leadconn || session->state != ISCSI_STATE_LOGGED_IN)
++		goto unlock;
++	conn = session->leadconn;
 +
-+/* status bit mask values */
-+#define FLASH_STATUS_BIT_MASK_DQ6       0x40
-+#define FLASH_STATUS_BIT_MASK_DQ5       0x20
-+#define FLASH_STATUS_BIT_MASK_DQ2       0x04
++	/* only have one tmf outstanding at a time */
++	if (conn->tmf_state != TMF_INITIAL)
++		goto unlock;
++	conn->tmf_state = TMF_QUEUED;
 +
-+/* minimum value in micro seconds needed for checking status */
-+#define FLASH_STATUS_ERASE_DELAY_COUNT  50
-+#define FLASH_STATUS_WRITE_DELAY_COUNT  25
++	hdr = &conn->tmhdr;
++	iscsi_prep_lun_reset_pdu(sc, hdr);
 +
-+#define FLASH_SECTOR_SIZE               0x010000
-+#define FLASH_SECTOR_SIZE_MASK          0xffff0000
++	if (iscsi_exec_task_mgmt_fn(conn, hdr, session->age,
++				    session->lu_reset_timeout)) {
++		rc = FAILED;
++		goto unlock;
++	}
 +
-+#define FLASH_OK                        0x000000
-+#define FAIL_OPEN_BIOS_FILE             0x000100
-+#define FAIL_CHECK_PCI_ID               0x000200
-+#define FAIL_CHECK_SUM                  0x000300
-+#define FAIL_UNKNOWN                    0x000400
-+#define FAIL_VERIFY                     0x000500
-+#define FAIL_RESET_FLASH                0x000600
-+#define FAIL_FIND_FLASH_ID              0x000700
-+#define FAIL_ERASE_FLASH                0x000800
-+#define FAIL_WRITE_FLASH                0x000900
-+#define FAIL_FILE_SIZE                  0x000a00
-+#define FAIL_PARAMETERS                 0x000b00
-+#define FAIL_OUT_MEMORY                 0x000c00
-+#define FLASH_IN_PROGRESS               0x001000
++	switch (conn->tmf_state) {
++	case TMF_SUCCESS:
++		break;
++	case TMF_TIMEDOUT:
++		spin_unlock_bh(&session->lock);
++		iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
++		goto done;
++	default:
++		conn->tmf_state = TMF_INITIAL;
++		goto unlock;
++	}
 +
-+struct controller_id {
-+	u32 vendor;     /* PCI Vendor ID */
-+	u32 device;     /* PCI Device ID */
-+	u32 sub_vendor; /* PCI Subvendor ID */
-+	u32 sub_device; /* PCI Subdevice ID */
-+};
++	rc = SUCCESS;
++	spin_unlock_bh(&session->lock);
 +
-+struct image_info {
-+	u32 ImageId;       /* Identifies the image */
-+	u32 ImageOffset;   /* Offset the beginning of the file */
-+	u32 ImageLength;   /* length of the image */
-+	u32 ImageChecksum; /* Image checksum */
-+	u32 ImageVersion;  /* Version of the image, could be build number */
-+};
++	iscsi_suspend_tx(conn);
++	/* need to grab the recv lock then session lock */
++	write_lock_bh(conn->recv_lock);
++	spin_lock(&session->lock);
++	fail_all_commands(conn, sc->device->lun);
++	conn->tmf_state = TMF_INITIAL;
++	spin_unlock(&session->lock);
++	write_unlock_bh(conn->recv_lock);
 +
-+struct bios_file_header {
-+	u8 signature[32]; /* Signature/Cookie to identify the file */
-+	u32 checksum;	  /*Entire file checksum with this field zero */
-+	u32 antidote;	  /* Entire file checksum with this field 0xFFFFFFFF */
-+	struct controller_id contrl_id; /*PCI id to identify the controller */
-+	u32 filelen;      /*Length of the entire file*/
-+	u32 chunk_num;	  /*The chunk/part number for multiple Image files */
-+	u32 total_chunks; /*Total number of chunks/parts in the image file */
-+	u32 num_images;   /* Number of images in the file */
-+	u32 build_num;    /* Build number of this image */
-+	struct image_info image_header;
-+};
++	iscsi_start_tx(conn);
++	goto done;
 +
-+int asd_verify_flash_seg(struct asd_ha_struct *asd_ha,
-+		void *src, u32 dest_offset, u32 bytes_to_verify);
-+int asd_write_flash_seg(struct asd_ha_struct *asd_ha,
-+		void *src, u32 dest_offset, u32 bytes_to_write);
-+int asd_chk_write_status(struct asd_ha_struct *asd_ha,
-+		u32 sector_addr, u8 erase_flag);
-+int asd_check_flash_type(struct asd_ha_struct *asd_ha);
-+int asd_erase_nv_sector(struct asd_ha_struct *asd_ha,
-+		u32 flash_addr, u32 size);
-+#endif
-diff --git a/drivers/scsi/aic94xx/aic94xx_task.c b/drivers/scsi/aic94xx/aic94xx_task.c
-index ee0a98b..965d4bb 100644
---- a/drivers/scsi/aic94xx/aic94xx_task.c
-+++ b/drivers/scsi/aic94xx/aic94xx_task.c
-@@ -187,29 +187,13 @@ static void asd_get_response_tasklet(struct asd_ascb *ascb,
- 	ts->buf_valid_size = 0;
- 	edb = asd_ha->seq.edb_arr[edb_id + escb->edb_index];
- 	r = edb->vaddr;
--	if (task->task_proto == SAS_PROTO_SSP) {
-+	if (task->task_proto == SAS_PROTOCOL_SSP) {
- 		struct ssp_response_iu *iu =
- 			r + 16 + sizeof(struct ssp_frame_hdr);
++unlock:
++	spin_unlock_bh(&session->lock);
++done:
++	debug_scsi("iscsi_eh_device_reset %s\n",
++		  rc == SUCCESS ? "SUCCESS" : "FAILED");
++	mutex_unlock(&session->eh_mutex);
++	return rc;
++}
++EXPORT_SYMBOL_GPL(iscsi_eh_device_reset);
++
++/*
++ * Pre-allocate a pool of @max items of @item_size. By default, the pool
++ * should be accessed via kfifo_{get,put} on q->queue.
++ * Optionally, the caller can obtain the array of object pointers
++ * by passing in a non-NULL @items pointer
++ */
+ int
+-iscsi_pool_init(struct iscsi_queue *q, int max, void ***items, int item_size)
++iscsi_pool_init(struct iscsi_pool *q, int max, void ***items, int item_size)
+ {
+-	int i;
++	int i, num_arrays = 1;
  
- 		ts->residual = le32_to_cpu(*(__le32 *)r);
--		ts->resp = SAS_TASK_COMPLETE;
--		if (iu->datapres == 0)
--			ts->stat = iu->status;
--		else if (iu->datapres == 1)
--			ts->stat = iu->resp_data[3];
--		else if (iu->datapres == 2) {
--			ts->stat = SAM_CHECK_COND;
--			ts->buf_valid_size = min((u32) SAS_STATUS_BUF_SIZE,
--					 be32_to_cpu(iu->sense_data_len));
--			memcpy(ts->buf, iu->sense_data, ts->buf_valid_size);
--			if (iu->status != SAM_CHECK_COND) {
--				ASD_DPRINTK("device %llx sent sense data, but "
--					    "stat(0x%x) is not CHECK_CONDITION"
--					    "\n",
--					    SAS_ADDR(task->dev->sas_addr),
--					    iu->status);
--			}
--		}
+-	*items = kmalloc(max * sizeof(void*), GFP_KERNEL);
+-	if (*items == NULL)
+-		return -ENOMEM;
++	memset(q, 0, sizeof(*q));
+ 
+ 	q->max = max;
+-	q->pool = kmalloc(max * sizeof(void*), GFP_KERNEL);
+-	if (q->pool == NULL) {
+-		kfree(*items);
+-		return -ENOMEM;
+-	}
 +
-+		sas_ssp_task_response(&asd_ha->pcidev->dev, task, iu);
- 	}  else {
- 		struct ata_task_resp *resp = (void *) &ts->buf[0];
++	/* If the user passed an items pointer, he wants a copy of
++	 * the array. */
++	if (items)
++		num_arrays++;
++	q->pool = kzalloc(num_arrays * max * sizeof(void*), GFP_KERNEL);
++	if (q->pool == NULL)
++		goto enomem;
  
-@@ -341,14 +325,14 @@ Again:
+ 	q->queue = kfifo_init((void*)q->pool, max * sizeof(void*),
+ 			      GFP_KERNEL, NULL);
+-	if (q->queue == ERR_PTR(-ENOMEM)) {
+-		kfree(q->pool);
+-		kfree(*items);
+-		return -ENOMEM;
+-	}
++	if (q->queue == ERR_PTR(-ENOMEM))
++		goto enomem;
+ 
+ 	for (i = 0; i < max; i++) {
+-		q->pool[i] = kmalloc(item_size, GFP_KERNEL);
++		q->pool[i] = kzalloc(item_size, GFP_KERNEL);
+ 		if (q->pool[i] == NULL) {
+-			int j;
+-
+-			for (j = 0; j < i; j++)
+-				kfree(q->pool[j]);
+-
+-			kfifo_free(q->queue);
+-			kfree(q->pool);
+-			kfree(*items);
+-			return -ENOMEM;
++			q->max = i;
++			goto enomem;
+ 		}
+-		memset(q->pool[i], 0, item_size);
+-		(*items)[i] = q->pool[i];
+ 		__kfifo_put(q->queue, (void*)&q->pool[i], sizeof(void*));
  	}
++
++	if (items) {
++		*items = q->pool + max;
++		memcpy(*items, q->pool, max * sizeof(void *));
++	}
++
+ 	return 0;
++
++enomem:
++	iscsi_pool_free(q);
++	return -ENOMEM;
+ }
+ EXPORT_SYMBOL_GPL(iscsi_pool_init);
  
- 	switch (task->task_proto) {
--	case SATA_PROTO:
--	case SAS_PROTO_STP:
-+	case SAS_PROTOCOL_SATA:
-+	case SAS_PROTOCOL_STP:
- 		asd_unbuild_ata_ascb(ascb);
- 		break;
--	case SAS_PROTO_SMP:
-+	case SAS_PROTOCOL_SMP:
- 		asd_unbuild_smp_ascb(ascb);
- 		break;
--	case SAS_PROTO_SSP:
-+	case SAS_PROTOCOL_SSP:
- 		asd_unbuild_ssp_ascb(ascb);
- 	default:
- 		break;
-@@ -586,17 +570,17 @@ int asd_execute_task(struct sas_task *task, const int num,
- 	list_for_each_entry(a, &alist, list) {
- 		t = a->uldd_task;
- 		a->uldd_timer = 1;
--		if (t->task_proto & SAS_PROTO_STP)
--			t->task_proto = SAS_PROTO_STP;
-+		if (t->task_proto & SAS_PROTOCOL_STP)
-+			t->task_proto = SAS_PROTOCOL_STP;
- 		switch (t->task_proto) {
--		case SATA_PROTO:
--		case SAS_PROTO_STP:
-+		case SAS_PROTOCOL_SATA:
-+		case SAS_PROTOCOL_STP:
- 			res = asd_build_ata_ascb(a, t, gfp_flags);
- 			break;
--		case SAS_PROTO_SMP:
-+		case SAS_PROTOCOL_SMP:
- 			res = asd_build_smp_ascb(a, t, gfp_flags);
- 			break;
--		case SAS_PROTO_SSP:
-+		case SAS_PROTOCOL_SSP:
- 			res = asd_build_ssp_ascb(a, t, gfp_flags);
- 			break;
- 		default:
-@@ -633,14 +617,14 @@ out_err_unmap:
- 			t->task_state_flags &= ~SAS_TASK_AT_INITIATOR;
- 			spin_unlock_irqrestore(&t->task_state_lock, flags);
- 			switch (t->task_proto) {
--			case SATA_PROTO:
--			case SAS_PROTO_STP:
-+			case SAS_PROTOCOL_SATA:
-+			case SAS_PROTOCOL_STP:
- 				asd_unbuild_ata_ascb(a);
- 				break;
--			case SAS_PROTO_SMP:
-+			case SAS_PROTOCOL_SMP:
- 				asd_unbuild_smp_ascb(a);
- 				break;
--			case SAS_PROTO_SSP:
-+			case SAS_PROTOCOL_SSP:
- 				asd_unbuild_ssp_ascb(a);
- 			default:
- 				break;
-diff --git a/drivers/scsi/aic94xx/aic94xx_tmf.c b/drivers/scsi/aic94xx/aic94xx_tmf.c
-index c0d0b7d..87b2f6e 100644
---- a/drivers/scsi/aic94xx/aic94xx_tmf.c
-+++ b/drivers/scsi/aic94xx/aic94xx_tmf.c
-@@ -372,21 +372,21 @@ int asd_abort_task(struct sas_task *task)
- 	scb->header.opcode = ABORT_TASK;
+-void iscsi_pool_free(struct iscsi_queue *q, void **items)
++void iscsi_pool_free(struct iscsi_pool *q)
+ {
+ 	int i;
  
- 	switch (task->task_proto) {
--	case SATA_PROTO:
--	case SAS_PROTO_STP:
-+	case SAS_PROTOCOL_SATA:
-+	case SAS_PROTOCOL_STP:
- 		scb->abort_task.proto_conn_rate = (1 << 5); /* STP */
- 		break;
--	case SAS_PROTO_SSP:
-+	case SAS_PROTOCOL_SSP:
- 		scb->abort_task.proto_conn_rate  = (1 << 4); /* SSP */
- 		scb->abort_task.proto_conn_rate |= task->dev->linkrate;
- 		break;
--	case SAS_PROTO_SMP:
-+	case SAS_PROTOCOL_SMP:
- 		break;
- 	default:
- 		break;
+ 	for (i = 0; i < q->max; i++)
+-		kfree(items[i]);
+-	kfree(q->pool);
+-	kfree(items);
++		kfree(q->pool[i]);
++	if (q->pool)
++		kfree(q->pool);
+ }
+ EXPORT_SYMBOL_GPL(iscsi_pool_free);
+ 
+@@ -1387,7 +1701,7 @@ iscsi_session_setup(struct iscsi_transport *iscsit,
+ 		qdepth = ISCSI_DEF_CMD_PER_LUN;
  	}
  
--	if (task->task_proto == SAS_PROTO_SSP) {
-+	if (task->task_proto == SAS_PROTOCOL_SSP) {
- 		scb->abort_task.ssp_frame.frame_type = SSP_TASK;
- 		memcpy(scb->abort_task.ssp_frame.hashed_dest_addr,
- 		       task->dev->hashed_sas_addr, HASHED_SAS_ADDR_SIZE);
-@@ -512,7 +512,7 @@ static int asd_initiate_ssp_tmf(struct domain_device *dev, u8 *lun,
- 	int res = 1;
- 	struct scb *scb;
+-	if (cmds_max < 2 || (cmds_max & (cmds_max - 1)) ||
++	if (!is_power_of_2(cmds_max) ||
+ 	    cmds_max >= ISCSI_MGMT_ITT_OFFSET) {
+ 		if (cmds_max != 0)
+ 			printk(KERN_ERR "iscsi: invalid can_queue of %d. "
+@@ -1411,12 +1725,16 @@ iscsi_session_setup(struct iscsi_transport *iscsit,
+ 	shost->max_cmd_len = iscsit->max_cmd_len;
+ 	shost->transportt = scsit;
+ 	shost->transportt->create_work_queue = 1;
++	shost->transportt->eh_timed_out = iscsi_eh_cmd_timed_out;
+ 	*hostno = shost->host_no;
  
--	if (!(dev->tproto & SAS_PROTO_SSP))
-+	if (!(dev->tproto & SAS_PROTOCOL_SSP))
- 		return TMF_RESP_FUNC_ESUPP;
+ 	session = iscsi_hostdata(shost->hostdata);
+ 	memset(session, 0, sizeof(struct iscsi_session));
+ 	session->host = shost;
+ 	session->state = ISCSI_STATE_FREE;
++	session->fast_abort = 1;
++	session->lu_reset_timeout = 15;
++	session->abort_timeout = 10;
+ 	session->mgmtpool_max = ISCSI_MGMT_CMDS_MAX;
+ 	session->cmds_max = cmds_max;
+ 	session->queued_cmdsn = session->cmdsn = initial_cmdsn;
+@@ -1479,9 +1797,9 @@ module_put:
+ cls_session_fail:
+ 	scsi_remove_host(shost);
+ add_host_fail:
+-	iscsi_pool_free(&session->mgmtpool, (void**)session->mgmt_cmds);
++	iscsi_pool_free(&session->mgmtpool);
+ mgmtpool_alloc_fail:
+-	iscsi_pool_free(&session->cmdpool, (void**)session->cmds);
++	iscsi_pool_free(&session->cmdpool);
+ cmdpool_alloc_fail:
+ 	scsi_host_put(shost);
+ 	return NULL;
+@@ -1501,11 +1819,11 @@ void iscsi_session_teardown(struct iscsi_cls_session *cls_session)
+ 	struct iscsi_session *session = iscsi_hostdata(shost->hostdata);
+ 	struct module *owner = cls_session->transport->owner;
  
- 	ascb = asd_ascb_alloc_list(asd_ha, &res, GFP_KERNEL);
-diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c
-index d466a2d..d80dba9 100644
---- a/drivers/scsi/arcmsr/arcmsr_hba.c
-+++ b/drivers/scsi/arcmsr/arcmsr_hba.c
-@@ -634,9 +634,9 @@ static void arcmsr_report_sense_info(struct CommandControlBlock *ccb)
- 	pcmd->result = DID_OK << 16;
- 	if (sensebuffer) {
- 		int sense_data_length =
--			sizeof(struct SENSE_DATA) < sizeof(pcmd->sense_buffer)
--			? sizeof(struct SENSE_DATA) : sizeof(pcmd->sense_buffer);
--		memset(sensebuffer, 0, sizeof(pcmd->sense_buffer));
-+			sizeof(struct SENSE_DATA) < SCSI_SENSE_BUFFERSIZE
-+			? sizeof(struct SENSE_DATA) : SCSI_SENSE_BUFFERSIZE;
-+		memset(sensebuffer, 0, SCSI_SENSE_BUFFERSIZE);
- 		memcpy(sensebuffer, ccb->arcmsr_cdb.SenseData, sense_data_length);
- 		sensebuffer->ErrorCode = SCSI_SENSE_CURRENT_ERRORS;
- 		sensebuffer->Valid = 1;
-diff --git a/drivers/scsi/atari_NCR5380.c b/drivers/scsi/atari_NCR5380.c
-index a9680b5..93b61f1 100644
---- a/drivers/scsi/atari_NCR5380.c
-+++ b/drivers/scsi/atari_NCR5380.c
-@@ -511,9 +511,9 @@ static inline void initialize_SCp(Scsi_Cmnd *cmd)
- 	 * various queues are valid.
- 	 */
+-	iscsi_unblock_session(cls_session);
++	iscsi_remove_session(cls_session);
+ 	scsi_remove_host(shost);
  
--	if (cmd->use_sg) {
--		cmd->SCp.buffer = (struct scatterlist *)cmd->request_buffer;
--		cmd->SCp.buffers_residual = cmd->use_sg - 1;
-+	if (scsi_bufflen(cmd)) {
-+		cmd->SCp.buffer = scsi_sglist(cmd);
-+		cmd->SCp.buffers_residual = scsi_sg_count(cmd) - 1;
- 		cmd->SCp.ptr = sg_virt(cmd->SCp.buffer);
- 		cmd->SCp.this_residual = cmd->SCp.buffer->length;
- 		/* ++roman: Try to merge some scatter-buffers if they are at
-@@ -523,8 +523,8 @@ static inline void initialize_SCp(Scsi_Cmnd *cmd)
- 	} else {
- 		cmd->SCp.buffer = NULL;
- 		cmd->SCp.buffers_residual = 0;
--		cmd->SCp.ptr = (char *)cmd->request_buffer;
--		cmd->SCp.this_residual = cmd->request_bufflen;
-+		cmd->SCp.ptr = NULL;
-+		cmd->SCp.this_residual = 0;
- 	}
+-	iscsi_pool_free(&session->mgmtpool, (void**)session->mgmt_cmds);
+-	iscsi_pool_free(&session->cmdpool, (void**)session->cmds);
++	iscsi_pool_free(&session->mgmtpool);
++	iscsi_pool_free(&session->cmdpool);
+ 
+ 	kfree(session->password);
+ 	kfree(session->password_in);
+@@ -1516,7 +1834,7 @@ void iscsi_session_teardown(struct iscsi_cls_session *cls_session)
+ 	kfree(session->hwaddress);
+ 	kfree(session->initiatorname);
+ 
+-	iscsi_destroy_session(cls_session);
++	iscsi_free_session(cls_session);
+ 	scsi_host_put(shost);
+ 	module_put(owner);
  }
+@@ -1546,17 +1864,17 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, uint32_t conn_idx)
+ 	conn->c_stage = ISCSI_CONN_INITIAL_STAGE;
+ 	conn->id = conn_idx;
+ 	conn->exp_statsn = 0;
+-	conn->tmabort_state = TMABORT_INITIAL;
++	conn->tmf_state = TMF_INITIAL;
++
++	init_timer(&conn->transport_timer);
++	conn->transport_timer.data = (unsigned long)conn;
++	conn->transport_timer.function = iscsi_check_transport_timeouts;
++
+ 	INIT_LIST_HEAD(&conn->run_list);
+ 	INIT_LIST_HEAD(&conn->mgmt_run_list);
++	INIT_LIST_HEAD(&conn->mgmtqueue);
+ 	INIT_LIST_HEAD(&conn->xmitqueue);
+-
+-	/* initialize general immediate & non-immediate PDU commands queue */
+-	conn->mgmtqueue = kfifo_alloc(session->mgmtpool_max * sizeof(void*),
+-			                GFP_KERNEL, NULL);
+-	if (conn->mgmtqueue == ERR_PTR(-ENOMEM))
+-		goto mgmtqueue_alloc_fail;
+-
++	INIT_LIST_HEAD(&conn->requeue);
+ 	INIT_WORK(&conn->xmitwork, iscsi_xmitworker);
  
-@@ -936,21 +936,21 @@ static int NCR5380_queue_command(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
- 	}
- # endif
- # ifdef NCR5380_STAT_LIMIT
--	if (cmd->request_bufflen > NCR5380_STAT_LIMIT)
-+	if (scsi_bufflen(cmd) > NCR5380_STAT_LIMIT)
- # endif
- 		switch (cmd->cmnd[0]) {
- 		case WRITE:
- 		case WRITE_6:
- 		case WRITE_10:
- 			hostdata->time_write[cmd->device->id] -= (jiffies - hostdata->timebase);
--			hostdata->bytes_write[cmd->device->id] += cmd->request_bufflen;
-+			hostdata->bytes_write[cmd->device->id] += scsi_bufflen(cmd);
- 			hostdata->pendingw++;
- 			break;
- 		case READ:
- 		case READ_6:
- 		case READ_10:
- 			hostdata->time_read[cmd->device->id] -= (jiffies - hostdata->timebase);
--			hostdata->bytes_read[cmd->device->id] += cmd->request_bufflen;
-+			hostdata->bytes_read[cmd->device->id] += scsi_bufflen(cmd);
- 			hostdata->pendingr++;
- 			break;
- 		}
-@@ -1352,21 +1352,21 @@ static irqreturn_t NCR5380_intr(int irq, void *dev_id)
- static void collect_stats(struct NCR5380_hostdata* hostdata, Scsi_Cmnd *cmd)
- {
- # ifdef NCR5380_STAT_LIMIT
--	if (cmd->request_bufflen > NCR5380_STAT_LIMIT)
-+	if (scsi_bufflen(cmd) > NCR5380_STAT_LIMIT)
- # endif
- 		switch (cmd->cmnd[0]) {
- 		case WRITE:
- 		case WRITE_6:
- 		case WRITE_10:
- 			hostdata->time_write[cmd->device->id] += (jiffies - hostdata->timebase);
--			/*hostdata->bytes_write[cmd->device->id] += cmd->request_bufflen;*/
-+			/*hostdata->bytes_write[cmd->device->id] += scsi_bufflen(cmd);*/
- 			hostdata->pendingw--;
- 			break;
- 		case READ:
- 		case READ_6:
- 		case READ_10:
- 			hostdata->time_read[cmd->device->id] += (jiffies - hostdata->timebase);
--			/*hostdata->bytes_read[cmd->device->id] += cmd->request_bufflen;*/
-+			/*hostdata->bytes_read[cmd->device->id] += scsi_bufflen(cmd);*/
- 			hostdata->pendingr--;
- 			break;
- 		}
-@@ -1868,7 +1868,7 @@ static int do_abort(struct Scsi_Host *host)
- 	 * the target sees, so we just handshake.
- 	 */
+ 	/* allocate login_mtask used for the login/text sequences */
+@@ -1574,7 +1892,7 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, uint32_t conn_idx)
+ 		goto login_mtask_data_alloc_fail;
+ 	conn->login_mtask->data = conn->data = data;
  
--	while (!(tmp = NCR5380_read(STATUS_REG)) & SR_REQ)
-+	while (!((tmp = NCR5380_read(STATUS_REG)) & SR_REQ))
- 		;
+-	init_timer(&conn->tmabort_timer);
++	init_timer(&conn->tmf_timer);
+ 	init_waitqueue_head(&conn->ehwait);
  
- 	NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp));
-diff --git a/drivers/scsi/atp870u.c b/drivers/scsi/atp870u.c
-index fec58cc..db6de5e 100644
---- a/drivers/scsi/atp870u.c
-+++ b/drivers/scsi/atp870u.c
-@@ -471,18 +471,8 @@ go_42:
- 			/*
- 			 *	Complete the command
- 			 */
--			if (workreq->use_sg) {
--				pci_unmap_sg(dev->pdev,
--					(struct scatterlist *)workreq->request_buffer,
--					workreq->use_sg,
--					workreq->sc_data_direction);
--			} else if (workreq->request_bufflen &&
--					workreq->sc_data_direction != DMA_NONE) {
--				pci_unmap_single(dev->pdev,
--					workreq->SCp.dma_handle,
--					workreq->request_bufflen,
--					workreq->sc_data_direction);
--			}			
-+			scsi_dma_unmap(workreq);
+ 	return cls_conn;
+@@ -1583,8 +1901,6 @@ login_mtask_data_alloc_fail:
+ 	__kfifo_put(session->mgmtpool.queue, (void*)&conn->login_mtask,
+ 		    sizeof(void*));
+ login_mtask_alloc_fail:
+-	kfifo_free(conn->mgmtqueue);
+-mgmtqueue_alloc_fail:
+ 	iscsi_destroy_conn(cls_conn);
+ 	return NULL;
+ }
+@@ -1603,8 +1919,9 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn)
+ 	struct iscsi_session *session = conn->session;
+ 	unsigned long flags;
+ 
++	del_timer_sync(&conn->transport_timer);
 +
- 			spin_lock_irqsave(dev->host->host_lock, flags);
- 			(*workreq->scsi_done) (workreq);
- #ifdef ED_DBGP
-@@ -624,7 +614,7 @@ static int atp870u_queuecommand(struct scsi_cmnd * req_p,
+ 	spin_lock_bh(&session->lock);
+-	set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
+ 	conn->c_stage = ISCSI_CONN_CLEANUP_WAIT;
+ 	if (session->leadconn == conn) {
+ 		/*
+@@ -1637,7 +1954,7 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn)
+ 	}
  
- 	c = scmd_channel(req_p);
- 	req_p->sense_buffer[0]=0;
--	req_p->resid = 0;
-+	scsi_set_resid(req_p, 0);
- 	if (scmd_channel(req_p) > 1) {
- 		req_p->result = 0x00040000;
- 		done(req_p);
-@@ -722,7 +712,6 @@ static void send_s870(struct atp_unit *dev,unsigned char c)
- 	unsigned short int tmpcip, w;
- 	unsigned long l, bttl = 0;
- 	unsigned int workport;
--	struct scatterlist *sgpnt;
- 	unsigned long  sg_count;
+ 	/* flush queued up work because we free the connection below */
+-	scsi_flush_work(session->host);
++	iscsi_suspend_tx(conn);
  
- 	if (dev->in_snd[c] != 0) {
-@@ -793,6 +782,8 @@ oktosend:
+ 	spin_lock_bh(&session->lock);
+ 	kfree(conn->data);
+@@ -1648,8 +1965,6 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn)
+ 		session->leadconn = NULL;
+ 	spin_unlock_bh(&session->lock);
+ 
+-	kfifo_free(conn->mgmtqueue);
+-
+ 	iscsi_destroy_conn(cls_conn);
+ }
+ EXPORT_SYMBOL_GPL(iscsi_conn_teardown);
+@@ -1672,11 +1987,29 @@ int iscsi_conn_start(struct iscsi_cls_conn *cls_conn)
+ 		return -EINVAL;
  	}
- 	printk("\n");
- #endif	
-+	l = scsi_bufflen(workreq);
+ 
++	if (conn->ping_timeout && !conn->recv_timeout) {
++		printk(KERN_ERR "iscsi: invalid recv timeout of zero "
++		      "Using 5 seconds\n.");
++		conn->recv_timeout = 5;
++	}
 +
- 	if (dev->dev_id == ATP885_DEVID) {
- 		j = inb(dev->baseport + 0x29) & 0xfe;
- 		outb(j, dev->baseport + 0x29);
-@@ -800,12 +791,11 @@ oktosend:
- 	}
- 	
- 	if (workreq->cmnd[0] == READ_CAPACITY) {
--		if (workreq->request_bufflen > 8) {
--			workreq->request_bufflen = 0x08;
--		}
-+		if (l > 8)
-+			l = 8;
++	if (conn->recv_timeout && !conn->ping_timeout) {
++		printk(KERN_ERR "iscsi: invalid ping timeout of zero "
++		      "Using 5 seconds.\n");
++		conn->ping_timeout = 5;
++	}
++
+ 	spin_lock_bh(&session->lock);
+ 	conn->c_stage = ISCSI_CONN_STARTED;
+ 	session->state = ISCSI_STATE_LOGGED_IN;
+ 	session->queued_cmdsn = session->cmdsn;
+ 
++	conn->last_recv = jiffies;
++	conn->last_ping = jiffies;
++	if (conn->recv_timeout && conn->ping_timeout)
++		mod_timer(&conn->transport_timer,
++			  jiffies + (conn->recv_timeout * HZ));
++
+ 	switch(conn->stop_stage) {
+ 	case STOP_CONN_RECOVER:
+ 		/*
+@@ -1684,7 +2017,7 @@ int iscsi_conn_start(struct iscsi_cls_conn *cls_conn)
+ 		 * commands after successful recovery
+ 		 */
+ 		conn->stop_stage = 0;
+-		conn->tmabort_state = TMABORT_INITIAL;
++		conn->tmf_state = TMF_INITIAL;
+ 		session->age++;
+ 		spin_unlock_bh(&session->lock);
+ 
+@@ -1709,55 +2042,27 @@ flush_control_queues(struct iscsi_session *session, struct iscsi_conn *conn)
+ 	struct iscsi_mgmt_task *mtask, *tmp;
+ 
+ 	/* handle pending */
+-	while (__kfifo_get(conn->mgmtqueue, (void*)&mtask, sizeof(void*))) {
+-		if (mtask == conn->login_mtask)
+-			continue;
++	list_for_each_entry_safe(mtask, tmp, &conn->mgmtqueue, running) {
+ 		debug_scsi("flushing pending mgmt task itt 0x%x\n", mtask->itt);
+-		__kfifo_put(session->mgmtpool.queue, (void*)&mtask,
+-			    sizeof(void*));
++		iscsi_free_mgmt_task(conn, mtask);
  	}
- 	if (workreq->cmnd[0] == 0x00) {
--		workreq->request_bufflen = 0;
-+		l = 0;
+ 
+ 	/* handle running */
+ 	list_for_each_entry_safe(mtask, tmp, &conn->mgmt_run_list, running) {
+ 		debug_scsi("flushing running mgmt task itt 0x%x\n", mtask->itt);
+-		list_del(&mtask->running);
+-
+-		if (mtask == conn->login_mtask)
+-			continue;
+-		__kfifo_put(session->mgmtpool.queue, (void*)&mtask,
+-			   sizeof(void*));
++		iscsi_free_mgmt_task(conn, mtask);
  	}
  
- 	tmport = workport + 0x1b;
-@@ -852,40 +842,8 @@ oktosend:
- #ifdef ED_DBGP	
- 	printk("dev->id[%d][%d].devsp = %2x\n",c,target_id,dev->id[c][target_id].devsp);
- #endif
--	/*
--	 *	Figure out the transfer size
--	 */
--	if (workreq->use_sg) {
--#ifdef ED_DBGP
--		printk("Using SGL\n");
--#endif		
--		l = 0;
--		
--		sgpnt = (struct scatterlist *) workreq->request_buffer;
--		sg_count = pci_map_sg(dev->pdev, sgpnt, workreq->use_sg,
--	   			workreq->sc_data_direction);		
--		
--		for (i = 0; i < workreq->use_sg; i++) {
--			if (sgpnt[i].length == 0 || workreq->use_sg > ATP870U_SCATTER) {
--				panic("Foooooooood fight!");
--			}
--			l += sgpnt[i].length;
--		}
--#ifdef ED_DBGP		
--		printk( "send_s870: workreq->use_sg %d, sg_count %d l %8ld\n", workreq->use_sg, sg_count, l);
--#endif
--	} else if(workreq->request_bufflen && workreq->sc_data_direction != PCI_DMA_NONE) {
--#ifdef ED_DBGP
--		printk("Not using SGL\n");
--#endif					
--		workreq->SCp.dma_handle = pci_map_single(dev->pdev, workreq->request_buffer,
--				workreq->request_bufflen,
--				workreq->sc_data_direction);		
--		l = workreq->request_bufflen;
--#ifdef ED_DBGP		
--		printk( "send_s870: workreq->use_sg %d, l %8ld\n", workreq->use_sg, l);
--#endif
--	} else l = 0;
+ 	conn->mtask = NULL;
+ }
+ 
+-/* Fail commands. Mutex and session lock held and recv side suspended */
+-static void fail_all_commands(struct iscsi_conn *conn)
+-{
+-	struct iscsi_cmd_task *ctask, *tmp;
+-
+-	/* flush pending */
+-	list_for_each_entry_safe(ctask, tmp, &conn->xmitqueue, running) {
+-		debug_scsi("failing pending sc %p itt 0x%x\n", ctask->sc,
+-			   ctask->itt);
+-		fail_command(conn, ctask, DID_BUS_BUSY << 16);
+-	}
+-
+-	/* fail all other running */
+-	list_for_each_entry_safe(ctask, tmp, &conn->run_list, running) {
+-		debug_scsi("failing in progress sc %p itt 0x%x\n",
+-			   ctask->sc, ctask->itt);
+-		fail_command(conn, ctask, DID_BUS_BUSY << 16);
+-	}
+-
+-	conn->ctask = NULL;
+-}
+-
+ static void iscsi_start_session_recovery(struct iscsi_session *session,
+ 					 struct iscsi_conn *conn, int flag)
+ {
+ 	int old_stop_stage;
+ 
++	del_timer_sync(&conn->transport_timer);
 +
-+	sg_count = scsi_dma_map(workreq);
- 	/*
- 	 *	Write transfer size
- 	 */
-@@ -938,16 +896,16 @@ oktosend:
- 	 *	a linear chain.
+ 	mutex_lock(&session->eh_mutex);
+ 	spin_lock_bh(&session->lock);
+ 	if (conn->stop_stage == STOP_CONN_TERM) {
+@@ -1818,7 +2123,7 @@ static void iscsi_start_session_recovery(struct iscsi_session *session,
+ 	 * flush queues.
  	 */
+ 	spin_lock_bh(&session->lock);
+-	fail_all_commands(conn);
++	fail_all_commands(conn, -1);
+ 	flush_control_queues(session, conn);
+ 	spin_unlock_bh(&session->lock);
+ 	mutex_unlock(&session->eh_mutex);
+@@ -1869,6 +2174,21 @@ int iscsi_set_param(struct iscsi_cls_conn *cls_conn,
+ 	uint32_t value;
  
--	if (workreq->use_sg) {
--		sgpnt = (struct scatterlist *) workreq->request_buffer;
-+	if (l) {
-+		struct scatterlist *sgpnt;
- 		i = 0;
--		for (j = 0; j < workreq->use_sg; j++) {
--			bttl = sg_dma_address(&sgpnt[j]);
--			l=sg_dma_len(&sgpnt[j]);
-+		scsi_for_each_sg(workreq, sgpnt, sg_count, j) {
-+			bttl = sg_dma_address(sgpnt);
-+			l=sg_dma_len(sgpnt);
- #ifdef ED_DBGP		
--		printk("1. bttl %x, l %x\n",bttl, l);
-+			printk("1. bttl %x, l %x\n",bttl, l);
- #endif			
--		while (l > 0x10000) {
-+			while (l > 0x10000) {
- 				(((u16 *) (prd))[i + 3]) = 0x0000;
- 				(((u16 *) (prd))[i + 2]) = 0x0000;
- 				(((u32 *) (prd))[i >> 1]) = cpu_to_le32(bttl);
-@@ -965,32 +923,6 @@ oktosend:
- 		printk("prd %4x %4x %4x %4x\n",(((unsigned short int *)prd)[0]),(((unsigned short int *)prd)[1]),(((unsigned short int *)prd)[2]),(((unsigned short int *)prd)[3]));
- 		printk("2. bttl %x, l %x\n",bttl, l);
- #endif			
--	} else {
--		/*
--		 *	For a linear request write a chain of blocks
--		 */        
--		bttl = workreq->SCp.dma_handle;
--		l = workreq->request_bufflen;
--		i = 0;
--#ifdef ED_DBGP		
--		printk("3. bttl %x, l %x\n",bttl, l);
--#endif			
--		while (l > 0x10000) {
--				(((u16 *) (prd))[i + 3]) = 0x0000;
--				(((u16 *) (prd))[i + 2]) = 0x0000;
--				(((u32 *) (prd))[i >> 1]) = cpu_to_le32(bttl);
--				l -= 0x10000;
--				bttl += 0x10000;
--				i += 0x04;
--			}
--			(((u16 *) (prd))[i + 3]) = cpu_to_le16(0x8000);
--			(((u16 *) (prd))[i + 2]) = cpu_to_le16(l);
--			(((u32 *) (prd))[i >> 1]) = cpu_to_le32(bttl);		
--#ifdef ED_DBGP		
--		printk("prd %4x %4x %4x %4x\n",(((unsigned short int *)prd)[0]),(((unsigned short int *)prd)[1]),(((unsigned short int *)prd)[2]),(((unsigned short int *)prd)[3]));
--		printk("4. bttl %x, l %x\n",bttl, l);
--#endif			
--		
- 	}
- 	tmpcip += 4;
- #ifdef ED_DBGP		
-diff --git a/drivers/scsi/ch.c b/drivers/scsi/ch.c
-index 2311019..7aad154 100644
---- a/drivers/scsi/ch.c
-+++ b/drivers/scsi/ch.c
-@@ -21,6 +21,7 @@
- #include <linux/compat.h>
- #include <linux/chio.h>			/* here are all the ioctls */
- #include <linux/mutex.h>
-+#include <linux/idr.h>
+ 	switch(param) {
++	case ISCSI_PARAM_FAST_ABORT:
++		sscanf(buf, "%d", &session->fast_abort);
++		break;
++	case ISCSI_PARAM_ABORT_TMO:
++		sscanf(buf, "%d", &session->abort_timeout);
++		break;
++	case ISCSI_PARAM_LU_RESET_TMO:
++		sscanf(buf, "%d", &session->lu_reset_timeout);
++		break;
++	case ISCSI_PARAM_PING_TMO:
++		sscanf(buf, "%d", &conn->ping_timeout);
++		break;
++	case ISCSI_PARAM_RECV_TMO:
++		sscanf(buf, "%d", &conn->recv_timeout);
++		break;
+ 	case ISCSI_PARAM_MAX_RECV_DLENGTH:
+ 		sscanf(buf, "%d", &conn->max_recv_dlength);
+ 		break;
+@@ -1983,6 +2303,15 @@ int iscsi_session_get_param(struct iscsi_cls_session *cls_session,
+ 	int len;
  
- #include <scsi/scsi.h>
- #include <scsi/scsi_cmnd.h>
-@@ -33,6 +34,7 @@
+ 	switch(param) {
++	case ISCSI_PARAM_FAST_ABORT:
++		len = sprintf(buf, "%d\n", session->fast_abort);
++		break;
++	case ISCSI_PARAM_ABORT_TMO:
++		len = sprintf(buf, "%d\n", session->abort_timeout);
++		break;
++	case ISCSI_PARAM_LU_RESET_TMO:
++		len = sprintf(buf, "%d\n", session->lu_reset_timeout);
++		break;
+ 	case ISCSI_PARAM_INITIAL_R2T_EN:
+ 		len = sprintf(buf, "%d\n", session->initial_r2t_en);
+ 		break;
+@@ -2040,6 +2369,12 @@ int iscsi_conn_get_param(struct iscsi_cls_conn *cls_conn,
+ 	int len;
  
- #define CH_DT_MAX       16
- #define CH_TYPES        8
-+#define CH_MAX_DEVS     128
+ 	switch(param) {
++	case ISCSI_PARAM_PING_TMO:
++		len = sprintf(buf, "%u\n", conn->ping_timeout);
++		break;
++	case ISCSI_PARAM_RECV_TMO:
++		len = sprintf(buf, "%u\n", conn->recv_timeout);
++		break;
+ 	case ISCSI_PARAM_MAX_RECV_DLENGTH:
+ 		len = sprintf(buf, "%u\n", conn->max_recv_dlength);
+ 		break;
+diff --git a/drivers/scsi/libsas/Kconfig b/drivers/scsi/libsas/Kconfig
+index c01a40d..18f33cd 100644
+--- a/drivers/scsi/libsas/Kconfig
++++ b/drivers/scsi/libsas/Kconfig
+@@ -38,6 +38,15 @@ config SCSI_SAS_ATA
+ 		Builds in ATA support into libsas.  Will necessitate
+ 		the loading of libata along with libsas.
  
- MODULE_DESCRIPTION("device driver for scsi media changer devices");
- MODULE_AUTHOR("Gerd Knorr <kraxel at bytesex.org>");
-@@ -88,17 +90,6 @@ static const char * vendor_labels[CH_TYPES-4] = {
++config SCSI_SAS_HOST_SMP
++	bool "Support for SMP interpretation for SAS hosts"
++	default y
++	depends on SCSI_SAS_LIBSAS
++	help
++		Allows sas hosts to receive SMP frames.  Selecting this
++		option builds an SMP interpreter into libsas.  Say
++		N here if you want to save the few kb this consumes.
++
+ config SCSI_SAS_LIBSAS_DEBUG
+ 	bool "Compile the SAS Domain Transport Attributes in debug mode"
+ 	default y
+diff --git a/drivers/scsi/libsas/Makefile b/drivers/scsi/libsas/Makefile
+index fd387b9..1ad1323 100644
+--- a/drivers/scsi/libsas/Makefile
++++ b/drivers/scsi/libsas/Makefile
+@@ -33,5 +33,7 @@ libsas-y +=  sas_init.o     \
+ 		sas_dump.o     \
+ 		sas_discover.o \
+ 		sas_expander.o \
+-		sas_scsi_host.o
++		sas_scsi_host.o \
++		sas_task.o
+ libsas-$(CONFIG_SCSI_SAS_ATA) +=	sas_ata.o
++libsas-$(CONFIG_SCSI_SAS_HOST_SMP) +=	sas_host_smp.o
+\ No newline at end of file
+diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c
+index 0829b55..0996f86 100644
+--- a/drivers/scsi/libsas/sas_ata.c
++++ b/drivers/scsi/libsas/sas_ata.c
+@@ -158,8 +158,8 @@ static unsigned int sas_ata_qc_issue(struct ata_queued_cmd *qc)
+ 	struct Scsi_Host *host = sas_ha->core.shost;
+ 	struct sas_internal *i = to_sas_internal(host->transportt);
+ 	struct scatterlist *sg;
+-	unsigned int num = 0;
+ 	unsigned int xfer = 0;
++	unsigned int si;
  
- #define MAX_RETRIES   1
+ 	task = sas_alloc_task(GFP_ATOMIC);
+ 	if (!task)
+@@ -176,22 +176,20 @@ static unsigned int sas_ata_qc_issue(struct ata_queued_cmd *qc)
  
--static int  ch_probe(struct device *);
--static int  ch_remove(struct device *);
--static int  ch_open(struct inode * inode, struct file * filp);
--static int  ch_release(struct inode * inode, struct file * filp);
--static int  ch_ioctl(struct inode * inode, struct file * filp,
--		     unsigned int cmd, unsigned long arg);
--#ifdef CONFIG_COMPAT
--static long ch_ioctl_compat(struct file * filp,
--			    unsigned int cmd, unsigned long arg);
--#endif
--
- static struct class * ch_sysfs_class;
+ 	ata_tf_to_fis(&qc->tf, 1, 0, (u8*)&task->ata_task.fis);
+ 	task->uldd_task = qc;
+-	if (is_atapi_taskfile(&qc->tf)) {
++	if (ata_is_atapi(qc->tf.protocol)) {
+ 		memcpy(task->ata_task.atapi_packet, qc->cdb, qc->dev->cdb_len);
+ 		task->total_xfer_len = qc->nbytes + qc->pad_len;
+ 		task->num_scatter = qc->pad_len ? qc->n_elem + 1 : qc->n_elem;
+ 	} else {
+-		ata_for_each_sg(sg, qc) {
+-			num++;
++		for_each_sg(qc->sg, sg, qc->n_elem, si)
+ 			xfer += sg->length;
+-		}
+ 
+ 		task->total_xfer_len = xfer;
+-		task->num_scatter = num;
++		task->num_scatter = si;
+ 	}
+ 
+ 	task->data_dir = qc->dma_dir;
+-	task->scatter = qc->__sg;
++	task->scatter = qc->sg;
+ 	task->ata_task.retry_count = 1;
+ 	task->task_state_flags = SAS_TASK_STATE_PENDING;
+ 	qc->lldd_task = task;
+@@ -200,7 +198,7 @@ static unsigned int sas_ata_qc_issue(struct ata_queued_cmd *qc)
+ 	case ATA_PROT_NCQ:
+ 		task->ata_task.use_ncq = 1;
+ 		/* fall through */
+-	case ATA_PROT_ATAPI_DMA:
++	case ATAPI_PROT_DMA:
+ 	case ATA_PROT_DMA:
+ 		task->ata_task.dma_xfer = 1;
+ 		break;
+@@ -500,7 +498,7 @@ static int sas_execute_task(struct sas_task *task, void *buffer, int size,
+ 			goto ex_err;
+ 		}
+ 		wait_for_completion(&task->completion);
+-		res = -ETASK;
++		res = -ECOMM;
+ 		if (task->task_state_flags & SAS_TASK_STATE_ABORTED) {
+ 			int res2;
+ 			SAS_DPRINTK("task aborted, flags:0x%x\n",
+diff --git a/drivers/scsi/libsas/sas_discover.c b/drivers/scsi/libsas/sas_discover.c
+index 5f3a0d7..31b9af2 100644
+--- a/drivers/scsi/libsas/sas_discover.c
++++ b/drivers/scsi/libsas/sas_discover.c
+@@ -98,7 +98,7 @@ static int sas_get_port_device(struct asd_sas_port *port)
+ 			dev->dev_type = SATA_PM;
+ 		else
+ 			dev->dev_type = SATA_DEV;
+-		dev->tproto = SATA_PROTO;
++		dev->tproto = SAS_PROTOCOL_SATA;
+ 	} else {
+ 		struct sas_identify_frame *id =
+ 			(struct sas_identify_frame *) dev->frame_rcvd;
+diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c
+index 8727436..aefd865 100644
+--- a/drivers/scsi/libsas/sas_expander.c
++++ b/drivers/scsi/libsas/sas_expander.c
+@@ -96,7 +96,7 @@ static int smp_execute_task(struct domain_device *dev, void *req, int req_size,
+ 		}
+ 
+ 		wait_for_completion(&task->completion);
+-		res = -ETASK;
++		res = -ECOMM;
+ 		if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) {
+ 			SAS_DPRINTK("smp task timed out or aborted\n");
+ 			i->dft->lldd_abort_task(task);
+@@ -109,6 +109,16 @@ static int smp_execute_task(struct domain_device *dev, void *req, int req_size,
+ 		    task->task_status.stat == SAM_GOOD) {
+ 			res = 0;
+ 			break;
++		} if (task->task_status.resp == SAS_TASK_COMPLETE &&
++		      task->task_status.stat == SAS_DATA_UNDERRUN) {
++			/* no error, but return the number of bytes of
++			 * underrun */
++			res = task->task_status.residual;
++			break;
++		} if (task->task_status.resp == SAS_TASK_COMPLETE &&
++		      task->task_status.stat == SAS_DATA_OVERRUN) {
++			res = -EMSGSIZE;
++			break;
+ 		} else {
+ 			SAS_DPRINTK("%s: task to dev %016llx response: 0x%x "
+ 				    "status 0x%x\n", __FUNCTION__,
+@@ -656,9 +666,9 @@ static struct domain_device *sas_ex_discover_end_dev(
+ 	sas_ex_get_linkrate(parent, child, phy);
+ 
+ #ifdef CONFIG_SCSI_SAS_ATA
+-	if ((phy->attached_tproto & SAS_PROTO_STP) || phy->attached_sata_dev) {
++	if ((phy->attached_tproto & SAS_PROTOCOL_STP) || phy->attached_sata_dev) {
+ 		child->dev_type = SATA_DEV;
+-		if (phy->attached_tproto & SAS_PROTO_STP)
++		if (phy->attached_tproto & SAS_PROTOCOL_STP)
+ 			child->tproto = phy->attached_tproto;
+ 		if (phy->attached_sata_dev)
+ 			child->tproto |= SATA_DEV;
+@@ -695,7 +705,7 @@ static struct domain_device *sas_ex_discover_end_dev(
+ 		}
+ 	} else
+ #endif
+-	  if (phy->attached_tproto & SAS_PROTO_SSP) {
++	  if (phy->attached_tproto & SAS_PROTOCOL_SSP) {
+ 		child->dev_type = SAS_END_DEV;
+ 		rphy = sas_end_device_alloc(phy->port);
+ 		/* FIXME: error handling */
+@@ -1896,11 +1906,9 @@ int sas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
+ 	}
+ 
+ 	/* no rphy means no smp target support (ie aic94xx host) */
+-	if (!rphy) {
+-		printk("%s: can we send a smp request to a host?\n",
+-		       __FUNCTION__);
+-		return -EINVAL;
+-	}
++	if (!rphy)
++		return sas_smp_host_handler(shost, req, rsp);
++
+ 	type = rphy->identify.device_type;
  
- typedef struct {
-@@ -114,30 +105,8 @@ typedef struct {
- 	struct mutex	    lock;
- } scsi_changer;
+ 	if (type != SAS_EDGE_EXPANDER_DEVICE &&
+@@ -1926,6 +1934,15 @@ int sas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
  
--static LIST_HEAD(ch_devlist);
--static DEFINE_SPINLOCK(ch_devlist_lock);
--static int ch_devcount;
--
--static struct scsi_driver ch_template =
--{
--	.owner     	= THIS_MODULE,
--	.gendrv     	= {
--		.name	= "ch",
--		.probe  = ch_probe,
--		.remove = ch_remove,
--	},
--};
--
--static const struct file_operations changer_fops =
--{
--	.owner        = THIS_MODULE,
--	.open         = ch_open,
--	.release      = ch_release,
--	.ioctl        = ch_ioctl,
--#ifdef CONFIG_COMPAT
--	.compat_ioctl = ch_ioctl_compat,
--#endif
--};
-+static DEFINE_IDR(ch_index_idr);
-+static DEFINE_SPINLOCK(ch_index_lock);
+ 	ret = smp_execute_task(dev, bio_data(req->bio), req->data_len,
+ 			       bio_data(rsp->bio), rsp->data_len);
++	if (ret > 0) {
++		/* positive number is the untransferred residual */
++		rsp->data_len = ret;
++		req->data_len = 0;
++		ret = 0;
++	} else if (ret == 0) {
++		rsp->data_len = 0;
++		req->data_len = 0;
++	}
  
- static const struct {
- 	unsigned char  sense;
-@@ -207,7 +176,7 @@ ch_do_scsi(scsi_changer *ch, unsigned char *cmd,
- {
- 	int errno, retries = 0, timeout, result;
- 	struct scsi_sense_hdr sshdr;
--	
+ 	return ret;
+ }
+diff --git a/drivers/scsi/libsas/sas_host_smp.c b/drivers/scsi/libsas/sas_host_smp.c
+new file mode 100644
+index 0000000..16f9312
+--- /dev/null
++++ b/drivers/scsi/libsas/sas_host_smp.c
+@@ -0,0 +1,274 @@
++/*
++ * Serial Attached SCSI (SAS) Expander discovery and configuration
++ *
++ * Copyright (C) 2007 James E.J. Bottomley
++ *		<James.Bottomley at HansenPartnership.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; version 2 only.
++ */
++#include <linux/scatterlist.h>
++#include <linux/blkdev.h>
 +
- 	timeout = (cmd[0] == INITIALIZE_ELEMENT_STATUS)
- 		? timeout_init : timeout_move;
- 
-@@ -245,7 +214,7 @@ static int
- ch_elem_to_typecode(scsi_changer *ch, u_int elem)
- {
- 	int i;
--	
++#include "sas_internal.h"
 +
- 	for (i = 0; i < CH_TYPES; i++) {
- 		if (elem >= ch->firsts[i]  &&
- 		    elem <  ch->firsts[i] +
-@@ -261,15 +230,15 @@ ch_read_element_status(scsi_changer *ch, u_int elem, char *data)
- 	u_char  cmd[12];
- 	u_char  *buffer;
- 	int     result;
--	
++#include <scsi/scsi_transport.h>
++#include <scsi/scsi_transport_sas.h>
++#include "../scsi_sas_internal.h"
 +
- 	buffer = kmalloc(512, GFP_KERNEL | GFP_DMA);
- 	if(!buffer)
- 		return -ENOMEM;
--	
++static void sas_host_smp_discover(struct sas_ha_struct *sas_ha, u8 *resp_data,
++				  u8 phy_id)
++{
++	struct sas_phy *phy;
++	struct sas_rphy *rphy;
 +
-  retry:
- 	memset(cmd,0,sizeof(cmd));
- 	cmd[0] = READ_ELEMENT_STATUS;
--	cmd[1] = (ch->device->lun << 5) | 
-+	cmd[1] = (ch->device->lun << 5) |
- 		(ch->voltags ? 0x10 : 0) |
- 		ch_elem_to_typecode(ch,elem);
- 	cmd[2] = (elem >> 8) & 0xff;
-@@ -296,7 +265,7 @@ ch_read_element_status(scsi_changer *ch, u_int elem, char *data)
- 	return result;
- }
- 
--static int 
-+static int
- ch_init_elem(scsi_changer *ch)
- {
- 	int err;
-@@ -322,7 +291,7 @@ ch_readconfig(scsi_changer *ch)
- 	buffer = kzalloc(512, GFP_KERNEL | GFP_DMA);
- 	if (!buffer)
- 		return -ENOMEM;
--	
++	if (phy_id >= sas_ha->num_phys) {
++		resp_data[2] = SMP_RESP_NO_PHY;
++		return;
++	}
++	resp_data[2] = SMP_RESP_FUNC_ACC;
 +
- 	memset(cmd,0,sizeof(cmd));
- 	cmd[0] = MODE_SENSE;
- 	cmd[1] = ch->device->lun << 5;
-@@ -365,7 +334,7 @@ ch_readconfig(scsi_changer *ch)
- 	} else {
- 		vprintk("reading element address assigment page failed!\n");
- 	}
--	
++	phy = sas_ha->sas_phy[phy_id]->phy;
++	resp_data[9] = phy_id;
++	resp_data[13] = phy->negotiated_linkrate;
++	memcpy(resp_data + 16, sas_ha->sas_addr, SAS_ADDR_SIZE);
++	memcpy(resp_data + 24, sas_ha->sas_phy[phy_id]->attached_sas_addr,
++	       SAS_ADDR_SIZE);
++	resp_data[40] = (phy->minimum_linkrate << 4) |
++		phy->minimum_linkrate_hw;
++	resp_data[41] = (phy->maximum_linkrate << 4) |
++		phy->maximum_linkrate_hw;
 +
- 	/* vendor specific element types */
- 	for (i = 0; i < 4; i++) {
- 		if (0 == vendor_counts[i])
-@@ -443,7 +412,7 @@ static int
- ch_position(scsi_changer *ch, u_int trans, u_int elem, int rotate)
- {
- 	u_char  cmd[10];
--	
++	if (!sas_ha->sas_phy[phy_id]->port ||
++	    !sas_ha->sas_phy[phy_id]->port->port_dev)
++		return;
 +
- 	dprintk("position: 0x%x\n",elem);
- 	if (0 == trans)
- 		trans = ch->firsts[CHET_MT];
-@@ -462,7 +431,7 @@ static int
- ch_move(scsi_changer *ch, u_int trans, u_int src, u_int dest, int rotate)
- {
- 	u_char  cmd[12];
--	
++	rphy = sas_ha->sas_phy[phy_id]->port->port_dev->rphy;
++	resp_data[12] = rphy->identify.device_type << 4;
++	resp_data[14] = rphy->identify.initiator_port_protocols;
++	resp_data[15] = rphy->identify.target_port_protocols;
++}
 +
- 	dprintk("move: 0x%x => 0x%x\n",src,dest);
- 	if (0 == trans)
- 		trans = ch->firsts[CHET_MT];
-@@ -484,7 +453,7 @@ ch_exchange(scsi_changer *ch, u_int trans, u_int src,
- 	    u_int dest1, u_int dest2, int rotate1, int rotate2)
- {
- 	u_char  cmd[12];
--	
++static void sas_report_phy_sata(struct sas_ha_struct *sas_ha, u8 *resp_data,
++				u8 phy_id)
++{
++	struct sas_rphy *rphy;
++	struct dev_to_host_fis *fis;
++	int i;
 +
- 	dprintk("exchange: 0x%x => 0x%x => 0x%x\n",
- 		src,dest1,dest2);
- 	if (0 == trans)
-@@ -501,7 +470,7 @@ ch_exchange(scsi_changer *ch, u_int trans, u_int src,
- 	cmd[8]  = (dest2 >> 8) & 0xff;
- 	cmd[9]  =  dest2       & 0xff;
- 	cmd[10] = (rotate1 ? 1 : 0) | (rotate2 ? 2 : 0);
--	
++	if (phy_id >= sas_ha->num_phys) {
++		resp_data[2] = SMP_RESP_NO_PHY;
++		return;
++	}
 +
- 	return ch_do_scsi(ch, cmd, NULL,0, DMA_NONE);
- }
- 
-@@ -539,14 +508,14 @@ ch_set_voltag(scsi_changer *ch, u_int elem,
- 		elem, tag);
- 	memset(cmd,0,sizeof(cmd));
- 	cmd[0]  = SEND_VOLUME_TAG;
--	cmd[1] = (ch->device->lun << 5) | 
-+	cmd[1] = (ch->device->lun << 5) |
- 		ch_elem_to_typecode(ch,elem);
- 	cmd[2] = (elem >> 8) & 0xff;
- 	cmd[3] = elem        & 0xff;
- 	cmd[5] = clear
- 		? (alternate ? 0x0d : 0x0c)
- 		: (alternate ? 0x0b : 0x0a);
--	
++	resp_data[2] = SMP_RESP_PHY_NO_SATA;
 +
- 	cmd[9] = 255;
- 
- 	memcpy(buffer,tag,32);
-@@ -562,7 +531,7 @@ static int ch_gstatus(scsi_changer *ch, int type, unsigned char __user *dest)
- 	int retval = 0;
- 	u_char data[16];
- 	unsigned int i;
--	
++	if (!sas_ha->sas_phy[phy_id]->port)
++		return;
 +
- 	mutex_lock(&ch->lock);
- 	for (i = 0; i < ch->counts[type]; i++) {
- 		if (0 != ch_read_element_status
-@@ -599,20 +568,17 @@ ch_release(struct inode *inode, struct file *file)
- static int
- ch_open(struct inode *inode, struct file *file)
- {
--	scsi_changer *tmp, *ch;
-+	scsi_changer *ch;
- 	int minor = iminor(inode);
- 
--	spin_lock(&ch_devlist_lock);
--	ch = NULL;
--	list_for_each_entry(tmp,&ch_devlist,list) {
--		if (tmp->minor == minor)
--			ch = tmp;
--	}
-+	spin_lock(&ch_index_lock);
-+	ch = idr_find(&ch_index_idr, minor);
++	rphy = sas_ha->sas_phy[phy_id]->port->port_dev->rphy;
++	fis = (struct dev_to_host_fis *)
++		sas_ha->sas_phy[phy_id]->port->port_dev->frame_rcvd;
++	if (rphy->identify.target_port_protocols != SAS_PROTOCOL_SATA)
++		return;
 +
- 	if (NULL == ch || scsi_device_get(ch->device)) {
--		spin_unlock(&ch_devlist_lock);
-+		spin_unlock(&ch_index_lock);
- 		return -ENXIO;
- 	}
--	spin_unlock(&ch_devlist_lock);
-+	spin_unlock(&ch_index_lock);
- 
- 	file->private_data = ch;
- 	return 0;
-@@ -626,24 +592,24 @@ ch_checkrange(scsi_changer *ch, unsigned int type, unsigned int unit)
- 	return 0;
- }
- 
--static int ch_ioctl(struct inode * inode, struct file * file,
-+static long ch_ioctl(struct file *file,
- 		    unsigned int cmd, unsigned long arg)
- {
- 	scsi_changer *ch = file->private_data;
- 	int retval;
- 	void __user *argp = (void __user *)arg;
--	
++	resp_data[2] = SMP_RESP_FUNC_ACC;
++	resp_data[9] = phy_id;
++	memcpy(resp_data + 16, sas_ha->sas_phy[phy_id]->attached_sas_addr,
++	       SAS_ADDR_SIZE);
 +
- 	switch (cmd) {
- 	case CHIOGPARAMS:
- 	{
- 		struct changer_params params;
--		
++	/* check to see if we have a valid d2h fis */
++	if (fis->fis_type != 0x34)
++		return;
 +
- 		params.cp_curpicker = 0;
- 		params.cp_npickers  = ch->counts[CHET_MT];
- 		params.cp_nslots    = ch->counts[CHET_ST];
- 		params.cp_nportals  = ch->counts[CHET_IE];
- 		params.cp_ndrives   = ch->counts[CHET_DT];
--		
++	/* the d2h fis is required by the standard to be in LE format */
++	for (i = 0; i < 20; i += 4) {
++		u8 *dst = resp_data + 24 + i, *src =
++			&sas_ha->sas_phy[phy_id]->port->port_dev->frame_rcvd[i];
++		dst[0] = src[3];
++		dst[1] = src[2];
++		dst[2] = src[1];
++		dst[3] = src[0];
++	}
++}
 +
- 		if (copy_to_user(argp, &params, sizeof(params)))
- 			return -EFAULT;
- 		return 0;
-@@ -673,11 +639,11 @@ static int ch_ioctl(struct inode * inode, struct file * file,
- 			return -EFAULT;
- 		return 0;
- 	}
--	
++static void sas_phy_control(struct sas_ha_struct *sas_ha, u8 phy_id,
++			    u8 phy_op, enum sas_linkrate min,
++			    enum sas_linkrate max, u8 *resp_data)
++{
++	struct sas_internal *i =
++		to_sas_internal(sas_ha->core.shost->transportt);
++	struct sas_phy_linkrates rates;
 +
- 	case CHIOPOSITION:
- 	{
- 		struct changer_position pos;
--		
++	if (phy_id >= sas_ha->num_phys) {
++		resp_data[2] = SMP_RESP_NO_PHY;
++		return;
++	}
++	switch (phy_op) {
++	case PHY_FUNC_NOP:
++	case PHY_FUNC_LINK_RESET:
++	case PHY_FUNC_HARD_RESET:
++	case PHY_FUNC_DISABLE:
++	case PHY_FUNC_CLEAR_ERROR_LOG:
++	case PHY_FUNC_CLEAR_AFFIL:
++	case PHY_FUNC_TX_SATA_PS_SIGNAL:
++		break;
 +
- 		if (copy_from_user(&pos, argp, sizeof (pos)))
- 			return -EFAULT;
- 
-@@ -692,7 +658,7 @@ static int ch_ioctl(struct inode * inode, struct file * file,
- 		mutex_unlock(&ch->lock);
- 		return retval;
- 	}
--	
++	default:
++		resp_data[2] = SMP_RESP_PHY_UNK_OP;
++		return;
++	}
 +
- 	case CHIOMOVE:
- 	{
- 		struct changer_move mv;
-@@ -705,7 +671,7 @@ static int ch_ioctl(struct inode * inode, struct file * file,
- 			dprintk("CHIOMOVE: invalid parameter\n");
- 			return -EBADSLT;
- 		}
--		
++	rates.minimum_linkrate = min;
++	rates.maximum_linkrate = max;
 +
- 		mutex_lock(&ch->lock);
- 		retval = ch_move(ch,0,
- 				 ch->firsts[mv.cm_fromtype] + mv.cm_fromunit,
-@@ -718,7 +684,7 @@ static int ch_ioctl(struct inode * inode, struct file * file,
- 	case CHIOEXCHANGE:
- 	{
- 		struct changer_exchange mv;
--		
++	if (i->dft->lldd_control_phy(sas_ha->sas_phy[phy_id], phy_op, &rates))
++		resp_data[2] = SMP_RESP_FUNC_FAILED;
++	else
++		resp_data[2] = SMP_RESP_FUNC_ACC;
++}
 +
- 		if (copy_from_user(&mv, argp, sizeof (mv)))
- 			return -EFAULT;
- 
-@@ -728,7 +694,7 @@ static int ch_ioctl(struct inode * inode, struct file * file,
- 			dprintk("CHIOEXCHANGE: invalid parameter\n");
- 			return -EBADSLT;
- 		}
--		
++int sas_smp_host_handler(struct Scsi_Host *shost, struct request *req,
++			 struct request *rsp)
++{
++	u8 *req_data = NULL, *resp_data = NULL, *buf;
++	struct sas_ha_struct *sas_ha = SHOST_TO_SAS_HA(shost);
++	int error = -EINVAL, resp_data_len = rsp->data_len;
 +
- 		mutex_lock(&ch->lock);
- 		retval = ch_exchange
- 			(ch,0,
-@@ -743,7 +709,7 @@ static int ch_ioctl(struct inode * inode, struct file * file,
- 	case CHIOGSTATUS:
- 	{
- 		struct changer_element_status ces;
--		
++	/* eight is the minimum size for request and response frames */
++	if (req->data_len < 8 || rsp->data_len < 8)
++		goto out;
 +
- 		if (copy_from_user(&ces, argp, sizeof (ces)))
- 			return -EFAULT;
- 		if (ces.ces_type < 0 || ces.ces_type >= CH_TYPES)
-@@ -759,19 +725,19 @@ static int ch_ioctl(struct inode * inode, struct file * file,
- 		u_char  *buffer;
- 		unsigned int elem;
- 		int     result,i;
--		
++	if (bio_offset(req->bio) + req->data_len > PAGE_SIZE ||
++	    bio_offset(rsp->bio) + rsp->data_len > PAGE_SIZE) {
++		shost_printk(KERN_ERR, shost,
++			"SMP request/response frame crosses page boundary");
++		goto out;
++	}
 +
- 		if (copy_from_user(&cge, argp, sizeof (cge)))
- 			return -EFAULT;
- 
- 		if (0 != ch_checkrange(ch, cge.cge_type, cge.cge_unit))
- 			return -EINVAL;
- 		elem = ch->firsts[cge.cge_type] + cge.cge_unit;
--		
++	req_data = kzalloc(req->data_len, GFP_KERNEL);
 +
- 		buffer = kmalloc(512, GFP_KERNEL | GFP_DMA);
- 		if (!buffer)
- 			return -ENOMEM;
- 		mutex_lock(&ch->lock);
--		
++	/* make sure frame can always be built ... we copy
++	 * back only the requested length */
++	resp_data = kzalloc(max(rsp->data_len, 128U), GFP_KERNEL);
 +
- 	voltag_retry:
- 		memset(cmd,0,sizeof(cmd));
- 		cmd[0] = READ_ELEMENT_STATUS;
-@@ -782,7 +748,7 @@ static int ch_ioctl(struct inode * inode, struct file * file,
- 		cmd[3] = elem        & 0xff;
- 		cmd[5] = 1;
- 		cmd[9] = 255;
--		
++	if (!req_data || !resp_data) {
++		error = -ENOMEM;
++		goto out;
++	}
 +
- 		if (0 == (result = ch_do_scsi(ch, cmd, buffer, 256, DMA_FROM_DEVICE))) {
- 			cge.cge_status = buffer[18];
- 			cge.cge_flags = 0;
-@@ -822,7 +788,7 @@ static int ch_ioctl(struct inode * inode, struct file * file,
- 		}
- 		kfree(buffer);
- 		mutex_unlock(&ch->lock);
--		
++	local_irq_disable();
++	buf = kmap_atomic(bio_page(req->bio), KM_USER0) + bio_offset(req->bio);
++	memcpy(req_data, buf, req->data_len);
++	kunmap_atomic(buf - bio_offset(req->bio), KM_USER0);
++	local_irq_enable();
 +
- 		if (copy_to_user(argp, &cge, sizeof (cge)))
- 			return -EFAULT;
- 		return result;
-@@ -835,7 +801,7 @@ static int ch_ioctl(struct inode * inode, struct file * file,
- 		mutex_unlock(&ch->lock);
- 		return retval;
- 	}
--		
++	if (req_data[0] != SMP_REQUEST)
++		goto out;
 +
- 	case CHIOSVOLTAG:
- 	{
- 		struct changer_set_voltag csv;
-@@ -876,7 +842,7 @@ static long ch_ioctl_compat(struct file * file,
- 			    unsigned int cmd, unsigned long arg)
- {
- 	scsi_changer *ch = file->private_data;
--	
++	/* always succeeds ... even if we can't process the request
++	 * the result is in the response frame */
++	error = 0;
 +
- 	switch (cmd) {
- 	case CHIOGPARAMS:
- 	case CHIOGVPARAMS:
-@@ -887,13 +853,12 @@ static long ch_ioctl_compat(struct file * file,
- 	case CHIOINITELEM:
- 	case CHIOSVOLTAG:
- 		/* compatible */
--		return ch_ioctl(NULL /* inode, unused */,
--				file, cmd, arg);
-+		return ch_ioctl(file, cmd, arg);
- 	case CHIOGSTATUS32:
- 	{
- 		struct changer_element_status32 ces32;
- 		unsigned char __user *data;
--		
++	/* set up default don't know response */
++	resp_data[0] = SMP_RESPONSE;
++	resp_data[1] = req_data[1];
++	resp_data[2] = SMP_RESP_FUNC_UNK;
 +
- 		if (copy_from_user(&ces32, (void __user *)arg, sizeof (ces32)))
- 			return -EFAULT;
- 		if (ces32.ces_type < 0 || ces32.ces_type >= CH_TYPES)
-@@ -915,63 +880,100 @@ static long ch_ioctl_compat(struct file * file,
- static int ch_probe(struct device *dev)
- {
- 	struct scsi_device *sd = to_scsi_device(dev);
-+	struct class_device *class_dev;
-+	int minor, ret = -ENOMEM;
- 	scsi_changer *ch;
--	
++	switch (req_data[1]) {
++	case SMP_REPORT_GENERAL:
++		req->data_len -= 8;
++		resp_data_len -= 32;
++		resp_data[2] = SMP_RESP_FUNC_ACC;
++		resp_data[9] = sas_ha->num_phys;
++		break;
 +
- 	if (sd->type != TYPE_MEDIUM_CHANGER)
- 		return -ENODEV;
--    
++	case SMP_REPORT_MANUF_INFO:
++		req->data_len -= 8;
++		resp_data_len -= 64;
++		resp_data[2] = SMP_RESP_FUNC_ACC;
++		memcpy(resp_data + 12, shost->hostt->name,
++		       SAS_EXPANDER_VENDOR_ID_LEN);
++		memcpy(resp_data + 20, "libsas virt phy",
++		       SAS_EXPANDER_PRODUCT_ID_LEN);
++		break;
 +
- 	ch = kzalloc(sizeof(*ch), GFP_KERNEL);
- 	if (NULL == ch)
- 		return -ENOMEM;
- 
--	ch->minor = ch_devcount;
-+	if (!idr_pre_get(&ch_index_idr, GFP_KERNEL))
-+		goto free_ch;
++	case SMP_READ_GPIO_REG:
++		/* FIXME: need GPIO support in the transport class */
++		break;
 +
-+	spin_lock(&ch_index_lock);
-+	ret = idr_get_new(&ch_index_idr, ch, &minor);
-+	spin_unlock(&ch_index_lock);
++	case SMP_DISCOVER:
++		req->data_len =- 16;
++		if (req->data_len < 0) {
++			req->data_len = 0;
++			error = -EINVAL;
++			goto out;
++		}
++		resp_data_len -= 56;
++		sas_host_smp_discover(sas_ha, resp_data, req_data[9]);
++		break;
 +
-+	if (ret)
-+		goto free_ch;
++	case SMP_REPORT_PHY_ERR_LOG:
++		/* FIXME: could implement this with additional
++		 * libsas callbacks providing the HW supports it */
++		break;
 +
-+	if (minor > CH_MAX_DEVS) {
-+		ret = -ENODEV;
-+		goto remove_idr;
-+	}
++	case SMP_REPORT_PHY_SATA:
++		req->data_len =- 16;
++		if (req->data_len < 0) {
++			req->data_len = 0;
++			error = -EINVAL;
++			goto out;
++		}
++		resp_data_len -= 60;
++		sas_report_phy_sata(sas_ha, resp_data, req_data[9]);
++		break;
 +
-+	ch->minor = minor;
- 	sprintf(ch->name,"ch%d",ch->minor);
++	case SMP_REPORT_ROUTE_INFO:
++		/* Can't implement; hosts have no routes */
++		break;
 +
-+	class_dev = class_device_create(ch_sysfs_class, NULL,
-+					MKDEV(SCSI_CHANGER_MAJOR, ch->minor),
-+					dev, "s%s", ch->name);
-+	if (IS_ERR(class_dev)) {
-+		printk(KERN_WARNING "ch%d: class_device_create failed\n",
-+		       ch->minor);
-+		ret = PTR_ERR(class_dev);
-+		goto remove_idr;
++	case SMP_WRITE_GPIO_REG:
++		/* FIXME: need GPIO support in the transport class */
++		break;
++
++	case SMP_CONF_ROUTE_INFO:
++		/* Can't implement; hosts have no routes */
++		break;
++
++	case SMP_PHY_CONTROL:
++		req->data_len =- 44;
++		if (req->data_len < 0) {
++			req->data_len = 0;
++			error = -EINVAL;
++			goto out;
++		}
++		resp_data_len -= 8;
++		sas_phy_control(sas_ha, req_data[9], req_data[10],
++				req_data[32] >> 4, req_data[33] >> 4,
++				resp_data);
++		break;
++
++	case SMP_PHY_TEST_FUNCTION:
++		/* FIXME: should this be implemented? */
++		break;
++
++	default:
++		/* probably a 2.0 function */
++		break;
 +	}
 +
- 	mutex_init(&ch->lock);
- 	ch->device = sd;
- 	ch_readconfig(ch);
- 	if (init)
- 		ch_init_elem(ch);
- 
--	class_device_create(ch_sysfs_class, NULL,
--			    MKDEV(SCSI_CHANGER_MAJOR,ch->minor),
--			    dev, "s%s", ch->name);
--
-+	dev_set_drvdata(dev, ch);
- 	sdev_printk(KERN_INFO, sd, "Attached scsi changer %s\n", ch->name);
--	
--	spin_lock(&ch_devlist_lock);
--	list_add_tail(&ch->list,&ch_devlist);
--	ch_devcount++;
--	spin_unlock(&ch_devlist_lock);
++	local_irq_disable();
++	buf = kmap_atomic(bio_page(rsp->bio), KM_USER0) + bio_offset(rsp->bio);
++	memcpy(buf, resp_data, rsp->data_len);
++	flush_kernel_dcache_page(bio_page(rsp->bio));
++	kunmap_atomic(buf - bio_offset(rsp->bio), KM_USER0);
++	local_irq_enable();
++	rsp->data_len = resp_data_len;
 +
- 	return 0;
-+remove_idr:
-+	idr_remove(&ch_index_idr, minor);
-+free_ch:
-+	kfree(ch);
-+	return ret;
- }
++ out:
++	kfree(req_data);
++	kfree(resp_data);
++	return error;
++}
+diff --git a/drivers/scsi/libsas/sas_internal.h b/drivers/scsi/libsas/sas_internal.h
+index 2b8213b..b4f9368 100644
+--- a/drivers/scsi/libsas/sas_internal.h
++++ b/drivers/scsi/libsas/sas_internal.h
+@@ -45,7 +45,7 @@
+ void sas_scsi_recover_host(struct Scsi_Host *shost);
  
- static int ch_remove(struct device *dev)
- {
--	struct scsi_device *sd = to_scsi_device(dev);
--	scsi_changer *tmp, *ch;
-+	scsi_changer *ch = dev_get_drvdata(dev);
+ int sas_show_class(enum sas_class class, char *buf);
+-int sas_show_proto(enum sas_proto proto, char *buf);
++int sas_show_proto(enum sas_protocol proto, char *buf);
+ int sas_show_linkrate(enum sas_linkrate linkrate, char *buf);
+ int sas_show_oob_mode(enum sas_oob_mode oob_mode, char *buf);
  
--	spin_lock(&ch_devlist_lock);
--	ch = NULL;
--	list_for_each_entry(tmp,&ch_devlist,list) {
--		if (tmp->device == sd)
--			ch = tmp;
--	}
--	BUG_ON(NULL == ch);
--	list_del(&ch->list);
--	spin_unlock(&ch_devlist_lock);
-+	spin_lock(&ch_index_lock);
-+	idr_remove(&ch_index_idr, ch->minor);
-+	spin_unlock(&ch_index_lock);
+@@ -80,6 +80,20 @@ struct domain_device *sas_find_dev_by_rphy(struct sas_rphy *rphy);
  
- 	class_device_destroy(ch_sysfs_class,
- 			     MKDEV(SCSI_CHANGER_MAJOR,ch->minor));
- 	kfree(ch->dt);
- 	kfree(ch);
--	ch_devcount--;
- 	return 0;
- }
+ void sas_hae_reset(struct work_struct *work);
  
-+static struct scsi_driver ch_template = {
-+	.owner     	= THIS_MODULE,
-+	.gendrv     	= {
-+		.name	= "ch",
-+		.probe  = ch_probe,
-+		.remove = ch_remove,
-+	},
-+};
-+
-+static const struct file_operations changer_fops = {
-+	.owner		= THIS_MODULE,
-+	.open		= ch_open,
-+	.release	= ch_release,
-+	.unlocked_ioctl	= ch_ioctl,
-+#ifdef CONFIG_COMPAT
-+	.compat_ioctl	= ch_ioctl_compat,
++#ifdef CONFIG_SCSI_SAS_HOST_SMP
++extern int sas_smp_host_handler(struct Scsi_Host *shost, struct request *req,
++				struct request *rsp);
++#else
++static inline int sas_smp_host_handler(struct Scsi_Host *shost,
++				       struct request *req,
++				       struct request *rsp)
++{
++	shost_printk(KERN_ERR, shost,
++		"Cannot send SMP to a sas host (not enabled in CONFIG)\n");
++	return -EINVAL;
++}
 +#endif
-+};
 +
- static int __init init_ch_module(void)
- {
- 	int rc;
--	
-+
- 	printk(KERN_INFO "SCSI Media Changer driver v" VERSION " \n");
-         ch_sysfs_class = class_create(THIS_MODULE, "scsi_changer");
-         if (IS_ERR(ch_sysfs_class)) {
-@@ -996,11 +998,12 @@ static int __init init_ch_module(void)
- 	return rc;
- }
+ static inline void sas_queue_event(int event, spinlock_t *lock,
+ 				   unsigned long *pending,
+ 				   struct work_struct *work,
+diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c
+index 7663841..f869fba 100644
+--- a/drivers/scsi/libsas/sas_scsi_host.c
++++ b/drivers/scsi/libsas/sas_scsi_host.c
+@@ -108,7 +108,7 @@ static void sas_scsi_task_done(struct sas_task *task)
+ 			break;
+ 		case SAM_CHECK_COND:
+ 			memcpy(sc->sense_buffer, ts->buf,
+-			       max(SCSI_SENSE_BUFFERSIZE, ts->buf_valid_size));
++			       min(SCSI_SENSE_BUFFERSIZE, ts->buf_valid_size));
+ 			stat = SAM_CHECK_COND;
+ 			break;
+ 		default:
+@@ -148,7 +148,6 @@ static struct sas_task *sas_create_task(struct scsi_cmnd *cmd,
+ 	if (!task)
+ 		return NULL;
  
--static void __exit exit_ch_module(void) 
-+static void __exit exit_ch_module(void)
+-	*(u32 *)cmd->sense_buffer = 0;
+ 	task->uldd_task = cmd;
+ 	ASSIGN_SAS_TASK(cmd, task);
+ 
+@@ -200,6 +199,10 @@ int sas_queue_up(struct sas_task *task)
+  */
+ int sas_queuecommand(struct scsi_cmnd *cmd,
+ 		     void (*scsi_done)(struct scsi_cmnd *))
++	__releases(host->host_lock)
++	__acquires(dev->sata_dev.ap->lock)
++	__releases(dev->sata_dev.ap->lock)
++	__acquires(host->host_lock)
  {
- 	scsi_unregister_driver(&ch_template.gendrv);
- 	unregister_chrdev(SCSI_CHANGER_MAJOR, "ch");
- 	class_destroy(ch_sysfs_class);
-+	idr_destroy(&ch_index_idr);
+ 	int res = 0;
+ 	struct domain_device *dev = cmd_to_domain_dev(cmd);
+@@ -410,7 +413,7 @@ static int sas_recover_I_T(struct domain_device *dev)
  }
  
- module_init(init_ch_module);
-diff --git a/drivers/scsi/constants.c b/drivers/scsi/constants.c
-index 024553f..403a7f2 100644
---- a/drivers/scsi/constants.c
-+++ b/drivers/scsi/constants.c
-@@ -362,7 +362,6 @@ void scsi_print_command(struct scsi_cmnd *cmd)
- EXPORT_SYMBOL(scsi_print_command);
- 
- /**
-- *
-  *	scsi_print_status - print scsi status description
-  *	@scsi_status: scsi status value
-  *
-@@ -1369,7 +1368,7 @@ EXPORT_SYMBOL(scsi_print_sense);
- static const char * const hostbyte_table[]={
- "DID_OK", "DID_NO_CONNECT", "DID_BUS_BUSY", "DID_TIME_OUT", "DID_BAD_TARGET",
- "DID_ABORT", "DID_PARITY", "DID_ERROR", "DID_RESET", "DID_BAD_INTR",
--"DID_PASSTHROUGH", "DID_SOFT_ERROR", "DID_IMM_RETRY"};
-+"DID_PASSTHROUGH", "DID_SOFT_ERROR", "DID_IMM_RETRY", "DID_REQUEUE"};
- #define NUM_HOSTBYTE_STRS ARRAY_SIZE(hostbyte_table)
- 
- static const char * const driverbyte_table[]={
-diff --git a/drivers/scsi/dc395x.c b/drivers/scsi/dc395x.c
-index a9def6e..f93c73c 100644
---- a/drivers/scsi/dc395x.c
-+++ b/drivers/scsi/dc395x.c
-@@ -1629,8 +1629,7 @@ static u8 start_scsi(struct AdapterCtlBlk* acb, struct DeviceCtlBlk* dcb,
- 		DC395x_write8(acb, TRM_S1040_SCSI_FIFO, (dcb->target_lun << 5));
- 		DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 0);
- 		DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 0);
--		DC395x_write8(acb, TRM_S1040_SCSI_FIFO,
--			      sizeof(srb->cmd->sense_buffer));
-+		DC395x_write8(acb, TRM_S1040_SCSI_FIFO, SCSI_SENSE_BUFFERSIZE);
- 		DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 0);
- 	} else {
- 		ptr = (u8 *)srb->cmd->cmnd;
-@@ -1915,8 +1914,7 @@ static void command_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
- 		DC395x_write8(acb, TRM_S1040_SCSI_FIFO, (dcb->target_lun << 5));
- 		DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 0);
- 		DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 0);
--		DC395x_write8(acb, TRM_S1040_SCSI_FIFO,
--			      sizeof(srb->cmd->sense_buffer));
-+		DC395x_write8(acb, TRM_S1040_SCSI_FIFO, SCSI_SENSE_BUFFERSIZE);
- 		DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 0);
- 	}
- 	srb->state |= SRB_COMMAND;
-@@ -3685,7 +3683,7 @@ static void request_sense(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
- 	srb->target_status = 0;
- 
- 	/* KG: Can this prevent crap sense data ? */
--	memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer));
-+	memset(cmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
- 
- 	/* Save some data */
- 	srb->segment_x[DC395x_MAX_SG_LISTENTRY - 1].address =
-@@ -3694,15 +3692,15 @@ static void request_sense(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
- 	    srb->segment_x[0].length;
- 	srb->xferred = srb->total_xfer_length;
- 	/* srb->segment_x : a one entry of S/G list table */
--	srb->total_xfer_length = sizeof(cmd->sense_buffer);
--	srb->segment_x[0].length = sizeof(cmd->sense_buffer);
-+	srb->total_xfer_length = SCSI_SENSE_BUFFERSIZE;
-+	srb->segment_x[0].length = SCSI_SENSE_BUFFERSIZE;
- 	/* Map sense buffer */
- 	srb->segment_x[0].address =
- 	    pci_map_single(acb->dev, cmd->sense_buffer,
--			   sizeof(cmd->sense_buffer), PCI_DMA_FROMDEVICE);
-+			   SCSI_SENSE_BUFFERSIZE, PCI_DMA_FROMDEVICE);
- 	dprintkdbg(DBG_SG, "request_sense: map buffer %p->%08x(%05x)\n",
- 	       cmd->sense_buffer, srb->segment_x[0].address,
--	       sizeof(cmd->sense_buffer));
-+	       SCSI_SENSE_BUFFERSIZE);
- 	srb->sg_count = 1;
- 	srb->sg_index = 0;
- 
-diff --git a/drivers/scsi/dpt_i2o.c b/drivers/scsi/dpt_i2o.c
-index b31d1c9..19cce12 100644
---- a/drivers/scsi/dpt_i2o.c
-+++ b/drivers/scsi/dpt_i2o.c
-@@ -2296,9 +2296,8 @@ static s32 adpt_i2o_to_scsi(void __iomem *reply, struct scsi_cmnd* cmd)
- 
- 		// copy over the request sense data if it was a check
- 		// condition status
--		if(dev_status == 0x02 /*CHECK_CONDITION*/) {
--			u32 len = sizeof(cmd->sense_buffer);
--			len = (len > 40) ?  40 : len;
-+		if (dev_status == SAM_STAT_CHECK_CONDITION) {
-+			u32 len = min(SCSI_SENSE_BUFFERSIZE, 40);
- 			// Copy over the sense data
- 			memcpy_fromio(cmd->sense_buffer, (reply+28) , len);
- 			if(cmd->sense_buffer[0] == 0x70 /* class 7 */ && 
-diff --git a/drivers/scsi/eata.c b/drivers/scsi/eata.c
-index 7ead521..05163ce 100644
---- a/drivers/scsi/eata.c
-+++ b/drivers/scsi/eata.c
-@@ -1623,9 +1623,9 @@ static void map_dma(unsigned int i, struct hostdata *ha)
- 	if (SCpnt->sense_buffer)
- 		cpp->sense_addr =
- 		    H2DEV(pci_map_single(ha->pdev, SCpnt->sense_buffer,
--			   sizeof SCpnt->sense_buffer, PCI_DMA_FROMDEVICE));
-+			   SCSI_SENSE_BUFFERSIZE, PCI_DMA_FROMDEVICE));
- 
--	cpp->sense_len = sizeof SCpnt->sense_buffer;
-+	cpp->sense_len = SCSI_SENSE_BUFFERSIZE;
- 
- 	count = scsi_dma_map(SCpnt);
- 	BUG_ON(count < 0);
-diff --git a/drivers/scsi/eata_pio.c b/drivers/scsi/eata_pio.c
-index 982c509..b5a6092 100644
---- a/drivers/scsi/eata_pio.c
-+++ b/drivers/scsi/eata_pio.c
-@@ -369,7 +369,6 @@ static int eata_pio_queue(struct scsi_cmnd *cmd,
- 	cp = &hd->ccb[y];
+ /* Find the sas_phy that's attached to this device */
+-struct sas_phy *find_local_sas_phy(struct domain_device *dev)
++static struct sas_phy *find_local_sas_phy(struct domain_device *dev)
+ {
+ 	struct domain_device *pdev = dev->parent;
+ 	struct ex_phy *exphy = NULL;
+@@ -464,7 +467,7 @@ int sas_eh_bus_reset_handler(struct scsi_cmnd *cmd)
+ 	res = sas_phy_reset(phy, 1);
+ 	if (res)
+ 		SAS_DPRINTK("Bus reset of %s failed 0x%x\n",
+-			    phy->dev.kobj.k_name,
++			    kobject_name(&phy->dev.kobj),
+ 			    res);
+ 	if (res == TMF_RESP_FUNC_SUCC || res == TMF_RESP_FUNC_COMPLETE)
+ 		return SUCCESS;
+diff --git a/drivers/scsi/libsas/sas_task.c b/drivers/scsi/libsas/sas_task.c
+new file mode 100644
+index 0000000..594524d
+--- /dev/null
++++ b/drivers/scsi/libsas/sas_task.c
+@@ -0,0 +1,36 @@
++#include <linux/kernel.h>
++#include <scsi/sas.h>
++#include <scsi/libsas.h>
++
++/* fill task_status_struct based on SSP response frame */
++void sas_ssp_task_response(struct device *dev, struct sas_task *task,
++			   struct ssp_response_iu *iu)
++{
++	struct task_status_struct *tstat = &task->task_status;
++
++	tstat->resp = SAS_TASK_COMPLETE;
++
++	if (iu->datapres == 0)
++		tstat->stat = iu->status;
++	else if (iu->datapres == 1)
++		tstat->stat = iu->resp_data[3];
++	else if (iu->datapres == 2) {
++		tstat->stat = SAM_CHECK_COND;
++		tstat->buf_valid_size =
++			min_t(int, SAS_STATUS_BUF_SIZE,
++			      be32_to_cpu(iu->sense_data_len));
++		memcpy(tstat->buf, iu->sense_data, tstat->buf_valid_size);
++
++		if (iu->status != SAM_CHECK_COND)
++			dev_printk(KERN_WARNING, dev,
++				   "dev %llx sent sense data, but "
++				   "stat(%x) is not CHECK CONDITION\n",
++				   SAS_ADDR(task->dev->sas_addr),
++				   iu->status);
++	}
++	else
++		/* when datapres contains corrupt/unknown value... */
++		tstat->stat = SAM_CHECK_COND;
++}
++EXPORT_SYMBOL_GPL(sas_ssp_task_response);
++
+diff --git a/drivers/scsi/libsrp.c b/drivers/scsi/libsrp.c
+index 2ad0a27..5cff020 100644
+--- a/drivers/scsi/libsrp.c
++++ b/drivers/scsi/libsrp.c
+@@ -192,18 +192,18 @@ static int srp_direct_data(struct scsi_cmnd *sc, struct srp_direct_buf *md,
  
- 	memset(cp, 0, sizeof(struct eata_ccb));
--	memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer));
+ 	if (dma_map) {
+ 		iue = (struct iu_entry *) sc->SCp.ptr;
+-		sg = sc->request_buffer;
++		sg = scsi_sglist(sc);
  
- 	cp->status = USED;	/* claim free slot */
+-		dprintk("%p %u %u %d\n", iue, sc->request_bufflen,
+-			md->len, sc->use_sg);
++		dprintk("%p %u %u %d\n", iue, scsi_bufflen(sc),
++			md->len, scsi_sg_count(sc));
  
-@@ -385,7 +384,7 @@ static int eata_pio_queue(struct scsi_cmnd *cmd,
- 		cp->DataIn = 0;	/* Input mode  */
+-		nsg = dma_map_sg(iue->target->dev, sg, sc->use_sg,
++		nsg = dma_map_sg(iue->target->dev, sg, scsi_sg_count(sc),
+ 				 DMA_BIDIRECTIONAL);
+ 		if (!nsg) {
+-			printk("fail to map %p %d\n", iue, sc->use_sg);
++			printk("fail to map %p %d\n", iue, scsi_sg_count(sc));
+ 			return 0;
+ 		}
+-		len = min(sc->request_bufflen, md->len);
++		len = min(scsi_bufflen(sc), md->len);
+ 	} else
+ 		len = md->len;
  
- 	cp->Interpret = (cmd->device->id == hd->hostid);
--	cp->cp_datalen = cpu_to_be32(cmd->request_bufflen);
-+	cp->cp_datalen = cpu_to_be32(scsi_bufflen(cmd));
- 	cp->Auto_Req_Sen = 0;
- 	cp->cp_reqDMA = 0;
- 	cp->reqlen = 0;
-@@ -402,14 +401,14 @@ static int eata_pio_queue(struct scsi_cmnd *cmd,
- 	cp->cmd = cmd;
- 	cmd->host_scribble = (char *) &hd->ccb[y];
+@@ -229,10 +229,10 @@ static int srp_indirect_data(struct scsi_cmnd *sc, struct srp_cmd *cmd,
  
--	if (cmd->use_sg == 0) {
-+	if (!scsi_bufflen(cmd)) {
- 		cmd->SCp.buffers_residual = 1;
--		cmd->SCp.ptr = cmd->request_buffer;
--		cmd->SCp.this_residual = cmd->request_bufflen;
-+		cmd->SCp.ptr = NULL;
-+		cmd->SCp.this_residual = 0;
- 		cmd->SCp.buffer = NULL;
- 	} else {
--		cmd->SCp.buffer = cmd->request_buffer;
--		cmd->SCp.buffers_residual = cmd->use_sg;
-+		cmd->SCp.buffer = scsi_sglist(cmd);
-+		cmd->SCp.buffers_residual = scsi_sg_count(cmd);
- 		cmd->SCp.ptr = sg_virt(cmd->SCp.buffer);
- 		cmd->SCp.this_residual = cmd->SCp.buffer->length;
- 	}
-diff --git a/drivers/scsi/fd_mcs.c b/drivers/scsi/fd_mcs.c
-index 8335b60..85bd54c 100644
---- a/drivers/scsi/fd_mcs.c
-+++ b/drivers/scsi/fd_mcs.c
-@@ -1017,24 +1017,6 @@ static irqreturn_t fd_mcs_intr(int irq, void *dev_id)
- 		printk(" ** IN DONE %d ** ", current_SC->SCp.have_data_in);
- #endif
+ 	if (dma_map || ext_desc) {
+ 		iue = (struct iu_entry *) sc->SCp.ptr;
+-		sg = sc->request_buffer;
++		sg = scsi_sglist(sc);
  
--#if ERRORS_ONLY
--		if (current_SC->cmnd[0] == REQUEST_SENSE && !current_SC->SCp.Status) {
--			if ((unsigned char) (*((char *) current_SC->request_buffer + 2)) & 0x0f) {
--				unsigned char key;
--				unsigned char code;
--				unsigned char qualifier;
--
--				key = (unsigned char) (*((char *) current_SC->request_buffer + 2)) & 0x0f;
--				code = (unsigned char) (*((char *) current_SC->request_buffer + 12));
--				qualifier = (unsigned char) (*((char *) current_SC->request_buffer + 13));
--
--				if (key != UNIT_ATTENTION && !(key == NOT_READY && code == 0x04 && (!qualifier || qualifier == 0x02 || qualifier == 0x01))
--				    && !(key == ILLEGAL_REQUEST && (code == 0x25 || code == 0x24 || !code)))
--
--					printk("fd_mcs: REQUEST SENSE " "Key = %x, Code = %x, Qualifier = %x\n", key, code, qualifier);
--			}
--		}
--#endif
- #if EVERY_ACCESS
- 		printk("BEFORE MY_DONE. . .");
- #endif
-@@ -1097,7 +1079,9 @@ static int fd_mcs_queue(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
- 		panic("fd_mcs: fd_mcs_queue() NOT REENTRANT!\n");
- 	}
- #if EVERY_ACCESS
--	printk("queue: target = %d cmnd = 0x%02x pieces = %d size = %u\n", SCpnt->target, *(unsigned char *) SCpnt->cmnd, SCpnt->use_sg, SCpnt->request_bufflen);
-+	printk("queue: target = %d cmnd = 0x%02x pieces = %d size = %u\n",
-+		SCpnt->target, *(unsigned char *) SCpnt->cmnd,
-+		scsi_sg_count(SCpnt), scsi_bufflen(SCpnt));
- #endif
+ 		dprintk("%p %u %u %d %d\n",
+-			iue, sc->request_bufflen, id->len,
++			iue, scsi_bufflen(sc), id->len,
+ 			cmd->data_in_desc_cnt, cmd->data_out_desc_cnt);
+ 	}
  
- 	fd_mcs_make_bus_idle(shpnt);
-@@ -1107,14 +1091,14 @@ static int fd_mcs_queue(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
+@@ -268,13 +268,14 @@ static int srp_indirect_data(struct scsi_cmnd *sc, struct srp_cmd *cmd,
  
- 	/* Initialize static data */
+ rdma:
+ 	if (dma_map) {
+-		nsg = dma_map_sg(iue->target->dev, sg, sc->use_sg, DMA_BIDIRECTIONAL);
++		nsg = dma_map_sg(iue->target->dev, sg, scsi_sg_count(sc),
++				 DMA_BIDIRECTIONAL);
+ 		if (!nsg) {
+-			eprintk("fail to map %p %d\n", iue, sc->use_sg);
++			eprintk("fail to map %p %d\n", iue, scsi_sg_count(sc));
+ 			err = -EIO;
+ 			goto free_mem;
+ 		}
+-		len = min(sc->request_bufflen, id->len);
++		len = min(scsi_bufflen(sc), id->len);
+ 	} else
+ 		len = id->len;
  
--	if (current_SC->use_sg) {
--		current_SC->SCp.buffer = (struct scatterlist *) current_SC->request_buffer;
-+	if (scsi_bufflen(current_SC)) {
-+		current_SC->SCp.buffer = scsi_sglist(current_SC);
- 		current_SC->SCp.ptr = sg_virt(current_SC->SCp.buffer);
- 		current_SC->SCp.this_residual = current_SC->SCp.buffer->length;
--		current_SC->SCp.buffers_residual = current_SC->use_sg - 1;
-+		current_SC->SCp.buffers_residual = scsi_sg_count(current_SC) - 1;
- 	} else {
--		current_SC->SCp.ptr = (char *) current_SC->request_buffer;
--		current_SC->SCp.this_residual = current_SC->request_bufflen;
-+		current_SC->SCp.ptr = NULL;
-+		current_SC->SCp.this_residual = 0;
- 		current_SC->SCp.buffer = NULL;
- 		current_SC->SCp.buffers_residual = 0;
- 	}
-@@ -1166,7 +1150,9 @@ static void fd_mcs_print_info(Scsi_Cmnd * SCpnt)
- 		break;
- 	}
+diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h
+index ba3ecab..f26b953 100644
+--- a/drivers/scsi/lpfc/lpfc.h
++++ b/drivers/scsi/lpfc/lpfc.h
+@@ -29,7 +29,8 @@ struct lpfc_sli2_slim;
+ #define LPFC_MAX_NS_RETRY	3	/* Number of retry attempts to contact
+ 					   the NameServer  before giving up. */
+ #define LPFC_CMD_PER_LUN	3	/* max outstanding cmds per lun */
+-#define LPFC_SG_SEG_CNT		64	/* sg element count per scsi cmnd */
++#define LPFC_DEFAULT_SG_SEG_CNT	64	/* sg element count per scsi cmnd */
++#define LPFC_MAX_SG_SEG_CNT	256	/* sg element count per scsi cmnd */
+ #define LPFC_IOCB_LIST_CNT	2250	/* list of IOCBs for fast-path usage. */
+ #define LPFC_Q_RAMP_UP_INTERVAL 120     /* lun q_depth ramp up interval */
  
--	printk("(%d), target = %d cmnd = 0x%02x pieces = %d size = %u\n", SCpnt->SCp.phase, SCpnt->device->id, *(unsigned char *) SCpnt->cmnd, SCpnt->use_sg, SCpnt->request_bufflen);
-+	printk("(%d), target = %d cmnd = 0x%02x pieces = %d size = %u\n",
-+		SCpnt->SCp.phase, SCpnt->device->id, *(unsigned char *) SCpnt->cmnd,
-+		scsi_sg_count(SCpnt), scsi_bufflen(SCpnt));
- 	printk("sent_command = %d, have_data_in = %d, timeout = %d\n", SCpnt->SCp.sent_command, SCpnt->SCp.have_data_in, SCpnt->timeout);
- #if DEBUG_RACE
- 	printk("in_interrupt_flag = %d\n", in_interrupt_flag);
-diff --git a/drivers/scsi/gdth.c b/drivers/scsi/gdth.c
-index b253b8c..c825239 100644
---- a/drivers/scsi/gdth.c
-+++ b/drivers/scsi/gdth.c
-@@ -141,7 +141,7 @@
- static void gdth_delay(int milliseconds);
- static void gdth_eval_mapping(ulong32 size, ulong32 *cyls, int *heads, int *secs);
- static irqreturn_t gdth_interrupt(int irq, void *dev_id);
--static irqreturn_t __gdth_interrupt(gdth_ha_str *ha, int irq,
-+static irqreturn_t __gdth_interrupt(gdth_ha_str *ha,
-                                     int gdth_from_wait, int* pIndex);
- static int gdth_sync_event(gdth_ha_str *ha, int service, unchar index,
-                                                                Scsi_Cmnd *scp);
-@@ -165,7 +165,6 @@ static int gdth_internal_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp);
- static int gdth_fill_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp, ushort hdrive);
+@@ -68,6 +69,7 @@ struct lpfc_dmabuf {
+ 	struct list_head list;
+ 	void *virt;		/* virtual address ptr */
+ 	dma_addr_t phys;	/* mapped address */
++	uint32_t   buffer_tag;	/* used for tagged queue ring */
+ };
  
- static void gdth_enable_int(gdth_ha_str *ha);
--static unchar gdth_get_status(gdth_ha_str *ha, int irq);
- static int gdth_test_busy(gdth_ha_str *ha);
- static int gdth_get_cmd_index(gdth_ha_str *ha);
- static void gdth_release_event(gdth_ha_str *ha);
-@@ -1334,14 +1333,12 @@ static void __init gdth_enable_int(gdth_ha_str *ha)
- }
+ struct lpfc_dma_pool {
+@@ -272,10 +274,16 @@ struct lpfc_vport {
+ #define FC_ABORT_DISCOVERY      0x8000	 /* we want to abort discovery */
+ #define FC_NDISC_ACTIVE         0x10000	 /* NPort discovery active */
+ #define FC_BYPASSED_MODE        0x20000	 /* NPort is in bypassed mode */
+-#define FC_RFF_NOT_SUPPORTED    0x40000	 /* RFF_ID was rejected by switch */
+ #define FC_VPORT_NEEDS_REG_VPI	0x80000  /* Needs to have its vpi registered */
+ #define FC_RSCN_DEFERRED	0x100000 /* A deferred RSCN being processed */
  
- /* return IStatus if interrupt was from this card else 0 */
--static unchar gdth_get_status(gdth_ha_str *ha, int irq)
-+static unchar gdth_get_status(gdth_ha_str *ha)
- {
-     unchar IStatus = 0;
++	uint32_t ct_flags;
++#define FC_CT_RFF_ID		0x1	 /* RFF_ID accepted by switch */
++#define FC_CT_RNN_ID		0x2	 /* RNN_ID accepted by switch */
++#define FC_CT_RSNN_NN		0x4	 /* RSNN_NN accepted by switch */
++#define FC_CT_RSPN_ID		0x8	 /* RSPN_ID accepted by switch */
++#define FC_CT_RFT_ID		0x10	 /* RFT_ID accepted by switch */
++
+ 	struct list_head fc_nodes;
  
--    TRACE(("gdth_get_status() irq %d ctr_count %d\n", irq, gdth_ctr_count));
-+    TRACE(("gdth_get_status() irq %d ctr_count %d\n", ha->irq, gdth_ctr_count));
+ 	/* Keep counters for the number of entries in each list. */
+@@ -344,6 +352,7 @@ struct lpfc_vport {
+ 	uint32_t cfg_discovery_threads;
+ 	uint32_t cfg_log_verbose;
+ 	uint32_t cfg_max_luns;
++	uint32_t cfg_enable_da_id;
  
--        if (ha->irq != (unchar)irq)             /* check IRQ */
--            return false;
-         if (ha->type == GDT_EISA)
-             IStatus = inb((ushort)ha->bmic + EDOORREG);
-         else if (ha->type == GDT_ISA)
-@@ -1523,7 +1520,7 @@ static int gdth_wait(gdth_ha_str *ha, int index, ulong32 time)
-         return 1;                               /* no wait required */
+ 	uint32_t dev_loss_tmo_changed;
  
-     do {
--        __gdth_interrupt(ha, (int)ha->irq, true, &wait_index);
-+	__gdth_interrupt(ha, true, &wait_index);
-         if (wait_index == index) {
-             answer_found = TRUE;
-             break;
-@@ -3036,7 +3033,7 @@ static void gdth_clear_events(void)
+@@ -360,6 +369,7 @@ struct lpfc_vport {
  
- /* SCSI interface functions */
+ struct hbq_s {
+ 	uint16_t entry_count;	  /* Current number of HBQ slots */
++	uint16_t buffer_count;	  /* Current number of buffers posted */
+ 	uint32_t next_hbqPutIdx;  /* Index to next HBQ slot to use */
+ 	uint32_t hbqPutIdx;	  /* HBQ slot to use */
+ 	uint32_t local_hbqGetIdx; /* Local copy of Get index from Port */
+@@ -377,6 +387,11 @@ struct hbq_s {
+ #define LPFC_ELS_HBQ	0
+ #define LPFC_EXTRA_HBQ	1
  
--static irqreturn_t __gdth_interrupt(gdth_ha_str *ha, int irq,
-+static irqreturn_t __gdth_interrupt(gdth_ha_str *ha,
-                                     int gdth_from_wait, int* pIndex)
- {
-     gdt6m_dpram_str __iomem *dp6m_ptr = NULL;
-@@ -3054,7 +3051,7 @@ static irqreturn_t __gdth_interrupt(gdth_ha_str *ha, int irq,
-     int act_int_coal = 0;       
- #endif
++enum hba_temp_state {
++	HBA_NORMAL_TEMP,
++	HBA_OVER_TEMP
++};
++
+ struct lpfc_hba {
+ 	struct lpfc_sli sli;
+ 	uint32_t sli_rev;		/* SLI2 or SLI3 */
+@@ -457,7 +472,8 @@ struct lpfc_hba {
+ 	uint64_t cfg_soft_wwnn;
+ 	uint64_t cfg_soft_wwpn;
+ 	uint32_t cfg_hba_queue_depth;
+-
++	uint32_t cfg_enable_hba_reset;
++	uint32_t cfg_enable_hba_heartbeat;
  
--    TRACE(("gdth_interrupt() IRQ %d\n",irq));
-+    TRACE(("gdth_interrupt() IRQ %d\n", ha->irq));
+ 	lpfc_vpd_t vpd;		/* vital product data */
  
-     /* if polling and not from gdth_wait() -> return */
-     if (gdth_polling) {
-@@ -3067,7 +3064,8 @@ static irqreturn_t __gdth_interrupt(gdth_ha_str *ha, int irq,
-         spin_lock_irqsave(&ha->smp_lock, flags);
+@@ -544,8 +560,7 @@ struct lpfc_hba {
+ 	struct list_head port_list;
+ 	struct lpfc_vport *pport;	/* physical lpfc_vport pointer */
+ 	uint16_t max_vpi;		/* Maximum virtual nports */
+-#define LPFC_MAX_VPI 100		/* Max number of VPI supported */
+-#define LPFC_MAX_VPORTS (LPFC_MAX_VPI+1)/* Max number of VPorts supported */
++#define LPFC_MAX_VPI 0xFFFF		/* Max number of VPI supported */
+ 	unsigned long *vpi_bmask;	/* vpi allocation table */
  
-     /* search controller */
--    if (0 == (IStatus = gdth_get_status(ha, irq))) {
-+    IStatus = gdth_get_status(ha);
-+    if (IStatus == 0) {
-         /* spurious interrupt */
-         if (!gdth_polling)
-             spin_unlock_irqrestore(&ha->smp_lock, flags);
-@@ -3294,9 +3292,9 @@ static irqreturn_t __gdth_interrupt(gdth_ha_str *ha, int irq,
+ 	/* Data structure used by fabric iocb scheduler */
+@@ -563,16 +578,30 @@ struct lpfc_hba {
+ 	struct dentry *hba_debugfs_root;
+ 	atomic_t debugfs_vport_count;
+ 	struct dentry *debug_hbqinfo;
+-	struct dentry *debug_dumpslim;
++	struct dentry *debug_dumpHostSlim;
++	struct dentry *debug_dumpHBASlim;
+ 	struct dentry *debug_slow_ring_trc;
+ 	struct lpfc_debugfs_trc *slow_ring_trc;
+ 	atomic_t slow_ring_trc_cnt;
+ #endif
  
- static irqreturn_t gdth_interrupt(int irq, void *dev_id)
- {
--	gdth_ha_str *ha = (gdth_ha_str *)dev_id;
-+	gdth_ha_str *ha = dev_id;
++	/* Used for deferred freeing of ELS data buffers */
++	struct list_head elsbuf;
++	int elsbuf_cnt;
++	int elsbuf_prev_cnt;
++
++	uint8_t temp_sensor_support;
+ 	/* Fields used for heart beat. */
+ 	unsigned long last_completion_time;
+ 	struct timer_list hb_tmofunc;
+ 	uint8_t hb_outstanding;
++	/*
++	 * Following bit will be set for all buffer tags which are not
++	 * associated with any HBQ.
++	 */
++#define QUE_BUFTAG_BIT  (1<<31)
++	uint32_t buffer_tag_count;
++	enum hba_temp_state over_temp_state;
+ };
  
--	return __gdth_interrupt(ha, irq, false, NULL);
-+	return __gdth_interrupt(ha, false, NULL);
+ static inline struct Scsi_Host *
+@@ -598,5 +627,15 @@ lpfc_is_link_up(struct lpfc_hba *phba)
+ 		phba->link_state == LPFC_HBA_READY;
  }
  
- static int gdth_sync_event(gdth_ha_str *ha, int service, unchar index,
-diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c
-index 24271a8..5ea1f98 100644
---- a/drivers/scsi/hosts.c
-+++ b/drivers/scsi/hosts.c
-@@ -54,8 +54,7 @@ static struct class shost_class = {
- };
+-#define FC_REG_DUMP_EVENT	0x10	/* Register for Dump events */
++#define FC_REG_DUMP_EVENT		0x10	/* Register for Dump events */
++#define FC_REG_TEMPERATURE_EVENT	0x20    /* Register for temperature
++						   event */
  
- /**
-- *	scsi_host_set_state - Take the given host through the host
-- *		state model.
-+ *	scsi_host_set_state - Take the given host through the host state model.
-  *	@shost:	scsi host to change the state of.
-  *	@state:	state to change to.
-  *
-@@ -429,9 +428,17 @@ void scsi_unregister(struct Scsi_Host *shost)
++struct temp_event {
++	uint32_t event_type;
++	uint32_t event_code;
++	uint32_t data;
++};
++#define LPFC_CRIT_TEMP		0x1
++#define LPFC_THRESHOLD_TEMP	0x2
++#define LPFC_NORMAL_TEMP	0x3
+diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c
+index 80a1121..4bae4a2 100644
+--- a/drivers/scsi/lpfc/lpfc_attr.c
++++ b/drivers/scsi/lpfc/lpfc_attr.c
+@@ -1,7 +1,7 @@
+ /*******************************************************************
+  * This file is part of the Emulex Linux Device Driver for         *
+  * Fibre Channel Host Bus Adapters.                                *
+- * Copyright (C) 2004-2007 Emulex.  All rights reserved.           *
++ * Copyright (C) 2004-2008 Emulex.  All rights reserved.           *
+  * EMULEX and SLI are trademarks of Emulex.                        *
+  * www.emulex.com                                                  *
+  * Portions Copyright (C) 2004-2005 Christoph Hellwig              *
+@@ -45,6 +45,10 @@
+ #define LPFC_MIN_DEVLOSS_TMO 1
+ #define LPFC_MAX_DEVLOSS_TMO 255
+ 
++#define LPFC_MAX_LINK_SPEED 8
++#define LPFC_LINK_SPEED_BITMAP 0x00000117
++#define LPFC_LINK_SPEED_STRING "0, 1, 2, 4, 8"
++
+ static void
+ lpfc_jedec_to_ascii(int incr, char hdw[])
+ {
+@@ -86,6 +90,15 @@ lpfc_serialnum_show(struct class_device *cdev, char *buf)
  }
- EXPORT_SYMBOL(scsi_unregister);
  
-+static int __scsi_host_match(struct class_device *cdev, void *data)
+ static ssize_t
++lpfc_temp_sensor_show(struct class_device *cdev, char *buf)
 +{
-+	struct Scsi_Host *p;
-+	unsigned short *hostnum = (unsigned short *)data;
-+
-+	p = class_to_shost(cdev);
-+	return p->host_no == *hostnum;
++	struct Scsi_Host *shost = class_to_shost(cdev);
++	struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
++	struct lpfc_hba   *phba = vport->phba;
++	return snprintf(buf, PAGE_SIZE, "%d\n",phba->temp_sensor_support);
 +}
 +
- /**
-  * scsi_host_lookup - get a reference to a Scsi_Host by host no
-- *
-  * @hostnum:	host number to locate
-  *
-  * Return value:
-@@ -439,19 +446,12 @@ EXPORT_SYMBOL(scsi_unregister);
-  **/
- struct Scsi_Host *scsi_host_lookup(unsigned short hostnum)
++static ssize_t
+ lpfc_modeldesc_show(struct class_device *cdev, char *buf)
  {
--	struct class *class = &shost_class;
- 	struct class_device *cdev;
--	struct Scsi_Host *shost = ERR_PTR(-ENXIO), *p;
-+	struct Scsi_Host *shost = ERR_PTR(-ENXIO);
+ 	struct Scsi_Host  *shost = class_to_shost(cdev);
+@@ -178,12 +191,9 @@ lpfc_state_show(struct class_device *cdev, char *buf)
+ 	case LPFC_LINK_UP:
+ 	case LPFC_CLEAR_LA:
+ 	case LPFC_HBA_READY:
+-		len += snprintf(buf + len, PAGE_SIZE-len, "Link Up - \n");
++		len += snprintf(buf + len, PAGE_SIZE-len, "Link Up - ");
  
--	down(&class->sem);
--	list_for_each_entry(cdev, &class->children, node) {
--		p = class_to_shost(cdev);
--		if (p->host_no == hostnum) {
--			shost = scsi_host_get(p);
+ 		switch (vport->port_state) {
+-			len += snprintf(buf + len, PAGE_SIZE-len,
+-					"initializing\n");
 -			break;
--		}
--	}
--	up(&class->sem);
-+	cdev = class_find_child(&shost_class, &hostnum, __scsi_host_match);
-+	if (cdev)
-+		shost = scsi_host_get(class_to_shost(cdev));
- 
- 	return shost;
- }
-diff --git a/drivers/scsi/hptiop.c b/drivers/scsi/hptiop.c
-index 0844331..e7b2f35 100644
---- a/drivers/scsi/hptiop.c
-+++ b/drivers/scsi/hptiop.c
-@@ -1,5 +1,5 @@
- /*
-- * HighPoint RR3xxx controller driver for Linux
-+ * HighPoint RR3xxx/4xxx controller driver for Linux
-  * Copyright (C) 2006-2007 HighPoint Technologies, Inc. All Rights Reserved.
-  *
-  * This program is free software; you can redistribute it and/or modify
-@@ -38,80 +38,84 @@
- #include "hptiop.h"
- 
- MODULE_AUTHOR("HighPoint Technologies, Inc.");
--MODULE_DESCRIPTION("HighPoint RocketRAID 3xxx SATA Controller Driver");
-+MODULE_DESCRIPTION("HighPoint RocketRAID 3xxx/4xxx Controller Driver");
- 
- static char driver_name[] = "hptiop";
--static const char driver_name_long[] = "RocketRAID 3xxx SATA Controller driver";
--static const char driver_ver[] = "v1.2 (070830)";
--
--static void hptiop_host_request_callback(struct hptiop_hba *hba, u32 tag);
--static void hptiop_iop_request_callback(struct hptiop_hba *hba, u32 tag);
-+static const char driver_name_long[] = "RocketRAID 3xxx/4xxx Controller driver";
-+static const char driver_ver[] = "v1.3 (071203)";
-+
-+static int iop_send_sync_msg(struct hptiop_hba *hba, u32 msg, u32 millisec);
-+static void hptiop_finish_scsi_req(struct hptiop_hba *hba, u32 tag,
-+				struct hpt_iop_request_scsi_command *req);
-+static void hptiop_host_request_callback_itl(struct hptiop_hba *hba, u32 tag);
-+static void hptiop_iop_request_callback_itl(struct hptiop_hba *hba, u32 tag);
- static void hptiop_message_callback(struct hptiop_hba *hba, u32 msg);
+ 		case LPFC_LOCAL_CFG_LINK:
+ 			len += snprintf(buf + len, PAGE_SIZE-len,
+ 					"Configuring Link\n");
+@@ -252,8 +262,7 @@ lpfc_issue_lip(struct Scsi_Host *shost)
+ 	int mbxstatus = MBXERR_ERROR;
  
--static inline void hptiop_pci_posting_flush(struct hpt_iopmu __iomem *iop)
--{
--	readl(&iop->outbound_intstatus);
--}
--
--static int iop_wait_ready(struct hpt_iopmu __iomem *iop, u32 millisec)
-+static int iop_wait_ready_itl(struct hptiop_hba *hba, u32 millisec)
- {
- 	u32 req = 0;
- 	int i;
+ 	if ((vport->fc_flag & FC_OFFLINE_MODE) ||
+-	    (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO) ||
+-	    (vport->port_state != LPFC_VPORT_READY))
++	    (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO))
+ 		return -EPERM;
  
- 	for (i = 0; i < millisec; i++) {
--		req = readl(&iop->inbound_queue);
-+		req = readl(&hba->u.itl.iop->inbound_queue);
- 		if (req != IOPMU_QUEUE_EMPTY)
- 			break;
- 		msleep(1);
- 	}
+ 	pmboxq = mempool_alloc(phba->mbox_mem_pool,GFP_KERNEL);
+@@ -305,12 +314,14 @@ lpfc_do_offline(struct lpfc_hba *phba, uint32_t type)
  
- 	if (req != IOPMU_QUEUE_EMPTY) {
--		writel(req, &iop->outbound_queue);
--		hptiop_pci_posting_flush(iop);
-+		writel(req, &hba->u.itl.iop->outbound_queue);
-+		readl(&hba->u.itl.iop->outbound_intstatus);
- 		return 0;
- 	}
+ 	psli = &phba->sli;
  
- 	return -1;
- }
++	/* Wait a little for things to settle down, but not
++	 * long enough for dev loss timeout to expire.
++	 */
+ 	for (i = 0; i < psli->num_rings; i++) {
+ 		pring = &psli->ring[i];
+-		/* The linkdown event takes 30 seconds to timeout. */
+ 		while (pring->txcmplq_cnt) {
+ 			msleep(10);
+-			if (cnt++ > 3000) {
++			if (cnt++ > 500) {  /* 5 secs */
+ 				lpfc_printf_log(phba,
+ 					KERN_WARNING, LOG_INIT,
+ 					"0466 Outstanding IO when "
+@@ -336,6 +347,9 @@ lpfc_selective_reset(struct lpfc_hba *phba)
+ 	struct completion online_compl;
+ 	int status = 0;
  
--static void hptiop_request_callback(struct hptiop_hba *hba, u32 tag)
-+static int iop_wait_ready_mv(struct hptiop_hba *hba, u32 millisec)
-+{
-+	return iop_send_sync_msg(hba, IOPMU_INBOUND_MSG0_NOP, millisec);
-+}
++	if (!phba->cfg_enable_hba_reset)
++		return -EIO;
 +
-+static void hptiop_request_callback_itl(struct hptiop_hba *hba, u32 tag)
- {
- 	if (tag & IOPMU_QUEUE_ADDR_HOST_BIT)
--		return hptiop_host_request_callback(hba,
-+		hptiop_host_request_callback_itl(hba,
- 				tag & ~IOPMU_QUEUE_ADDR_HOST_BIT);
- 	else
--		return hptiop_iop_request_callback(hba, tag);
-+		hptiop_iop_request_callback_itl(hba, tag);
- }
+ 	status = lpfc_do_offline(phba, LPFC_EVT_OFFLINE);
  
--static inline void hptiop_drain_outbound_queue(struct hptiop_hba *hba)
-+static void hptiop_drain_outbound_queue_itl(struct hptiop_hba *hba)
- {
- 	u32 req;
+ 	if (status != 0)
+@@ -409,6 +423,8 @@ lpfc_board_mode_store(struct class_device *cdev, const char *buf, size_t count)
+ 	struct completion online_compl;
+ 	int status=0;
  
--	while ((req = readl(&hba->iop->outbound_queue)) != IOPMU_QUEUE_EMPTY) {
-+	while ((req = readl(&hba->u.itl.iop->outbound_queue)) !=
-+						IOPMU_QUEUE_EMPTY) {
++	if (!phba->cfg_enable_hba_reset)
++		return -EACCES;
+ 	init_completion(&online_compl);
  
- 		if (req & IOPMU_QUEUE_MASK_HOST_BITS)
--			hptiop_request_callback(hba, req);
-+			hptiop_request_callback_itl(hba, req);
- 		else {
- 			struct hpt_iop_request_header __iomem * p;
+ 	if(strncmp(buf, "online", sizeof("online") - 1) == 0) {
+@@ -908,6 +924,8 @@ static CLASS_DEVICE_ATTR(used_rpi, S_IRUGO, lpfc_used_rpi_show, NULL);
+ static CLASS_DEVICE_ATTR(max_xri, S_IRUGO, lpfc_max_xri_show, NULL);
+ static CLASS_DEVICE_ATTR(used_xri, S_IRUGO, lpfc_used_xri_show, NULL);
+ static CLASS_DEVICE_ATTR(npiv_info, S_IRUGO, lpfc_npiv_info_show, NULL);
++static CLASS_DEVICE_ATTR(lpfc_temp_sensor, S_IRUGO, lpfc_temp_sensor_show,
++			 NULL);
  
- 			p = (struct hpt_iop_request_header __iomem *)
--				((char __iomem *)hba->iop + req);
-+				((char __iomem *)hba->u.itl.iop + req);
  
- 			if (readl(&p->flags) & IOP_REQUEST_FLAG_SYNC_REQUEST) {
- 				if (readl(&p->context))
--					hptiop_request_callback(hba, req);
-+					hptiop_request_callback_itl(hba, req);
- 				else
- 					writel(1, &p->context);
- 			}
- 			else
--				hptiop_request_callback(hba, req);
-+				hptiop_request_callback_itl(hba, req);
- 		}
- 	}
- }
+ static char *lpfc_soft_wwn_key = "C99G71SL8032A";
+@@ -971,6 +989,14 @@ lpfc_soft_wwpn_store(struct class_device *cdev, const char *buf, size_t count)
+ 	unsigned int i, j, cnt=count;
+ 	u8 wwpn[8];
  
--static int __iop_intr(struct hptiop_hba *hba)
-+static int iop_intr_itl(struct hptiop_hba *hba)
- {
--	struct hpt_iopmu __iomem *iop = hba->iop;
-+	struct hpt_iopmu_itl __iomem *iop = hba->u.itl.iop;
- 	u32 status;
- 	int ret = 0;
++	if (!phba->cfg_enable_hba_reset)
++		return -EACCES;
++	spin_lock_irq(&phba->hbalock);
++	if (phba->over_temp_state == HBA_OVER_TEMP) {
++		spin_unlock_irq(&phba->hbalock);
++		return -EACCES;
++	}
++	spin_unlock_irq(&phba->hbalock);
+ 	/* count may include a LF at end of string */
+ 	if (buf[cnt-1] == '\n')
+ 		cnt--;
+@@ -1102,7 +1128,13 @@ MODULE_PARM_DESC(lpfc_sli_mode, "SLI mode selector:"
+ 		 " 2 - select SLI-2 even on SLI-3 capable HBAs,"
+ 		 " 3 - select SLI-3");
  
-@@ -119,6 +123,7 @@ static int __iop_intr(struct hptiop_hba *hba)
+-LPFC_ATTR_R(enable_npiv, 0, 0, 1, "Enable NPIV functionality");
++int lpfc_enable_npiv = 0;
++module_param(lpfc_enable_npiv, int, 0);
++MODULE_PARM_DESC(lpfc_enable_npiv, "Enable NPIV functionality");
++lpfc_param_show(enable_npiv);
++lpfc_param_init(enable_npiv, 0, 0, 1);
++static CLASS_DEVICE_ATTR(lpfc_enable_npiv, S_IRUGO,
++			 lpfc_enable_npiv_show, NULL);
  
- 	if (status & IOPMU_OUTBOUND_INT_MSG0) {
- 		u32 msg = readl(&iop->outbound_msgaddr0);
-+
- 		dprintk("received outbound msg %x\n", msg);
- 		writel(IOPMU_OUTBOUND_INT_MSG0, &iop->outbound_intstatus);
- 		hptiop_message_callback(hba, msg);
-@@ -126,31 +131,115 @@ static int __iop_intr(struct hptiop_hba *hba)
- 	}
+ /*
+ # lpfc_nodev_tmo: If set, it will hold all I/O errors on devices that disappear
+@@ -1248,6 +1280,13 @@ LPFC_VPORT_ATTR_HEX_RW(log_verbose, 0x0, 0x0, 0xffff,
+ 		       "Verbose logging bit-mask");
  
- 	if (status & IOPMU_OUTBOUND_INT_POSTQUEUE) {
--		hptiop_drain_outbound_queue(hba);
-+		hptiop_drain_outbound_queue_itl(hba);
-+		ret = 1;
-+	}
+ /*
++# lpfc_enable_da_id: This turns on the DA_ID CT command that deregisters
++# objects that have been registered with the nameserver after login.
++*/
++LPFC_VPORT_ATTR_R(enable_da_id, 0, 0, 1,
++		  "Deregister nameserver objects before LOGO");
 +
-+	return ret;
++/*
+ # lun_queue_depth:  This parameter is used to limit the number of outstanding
+ # commands per FCP LUN. Value range is [1,128]. Default value is 30.
+ */
+@@ -1369,7 +1408,33 @@ LPFC_VPORT_ATTR_R(scan_down, 1, 0, 1,
+ # Set loop mode if you want to run as an NL_Port. Value range is [0,0x6].
+ # Default value is 0.
+ */
+-LPFC_ATTR_RW(topology, 0, 0, 6, "Select Fibre Channel topology");
++static int
++lpfc_topology_set(struct lpfc_hba *phba, int val)
++{
++	int err;
++	uint32_t prev_val;
++	if (val >= 0 && val <= 6) {
++		prev_val = phba->cfg_topology;
++		phba->cfg_topology = val;
++		err = lpfc_issue_lip(lpfc_shost_from_vport(phba->pport));
++		if (err)
++			phba->cfg_topology = prev_val;
++		return err;
++	}
++	lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
++		"%d:0467 lpfc_topology attribute cannot be set to %d, "
++		"allowed range is [0, 6]\n",
++		phba->brd_no, val);
++	return -EINVAL;
 +}
-+
-+static u64 mv_outbound_read(struct hpt_iopmu_mv __iomem *mu)
++static int lpfc_topology = 0;
++module_param(lpfc_topology, int, 0);
++MODULE_PARM_DESC(lpfc_topology, "Select Fibre Channel topology");
++lpfc_param_show(topology)
++lpfc_param_init(topology, 0, 0, 6)
++lpfc_param_store(topology)
++static CLASS_DEVICE_ATTR(lpfc_topology, S_IRUGO | S_IWUSR,
++		lpfc_topology_show, lpfc_topology_store);
+ 
+ /*
+ # lpfc_link_speed: Link speed selection for initializing the Fibre Channel
+@@ -1381,7 +1446,59 @@ LPFC_ATTR_RW(topology, 0, 0, 6, "Select Fibre Channel topology");
+ #       8  = 8 Gigabaud
+ # Value range is [0,8]. Default value is 0.
+ */
+-LPFC_ATTR_R(link_speed, 0, 0, 8, "Select link speed");
++static int
++lpfc_link_speed_set(struct lpfc_hba *phba, int val)
 +{
-+	u32 outbound_tail = readl(&mu->outbound_tail);
-+	u32 outbound_head = readl(&mu->outbound_head);
++	int err;
++	uint32_t prev_val;
 +
-+	if (outbound_tail != outbound_head) {
-+		u64 p;
++	if (((val == LINK_SPEED_1G) && !(phba->lmt & LMT_1Gb)) ||
++		((val == LINK_SPEED_2G) && !(phba->lmt & LMT_2Gb)) ||
++		((val == LINK_SPEED_4G) && !(phba->lmt & LMT_4Gb)) ||
++		((val == LINK_SPEED_8G) && !(phba->lmt & LMT_8Gb)) ||
++		((val == LINK_SPEED_10G) && !(phba->lmt & LMT_10Gb)))
++		return -EINVAL;
 +
-+		memcpy_fromio(&p, &mu->outbound_q[mu->outbound_tail], 8);
-+		outbound_tail++;
++	if ((val >= 0 && val <= LPFC_MAX_LINK_SPEED)
++		&& (LPFC_LINK_SPEED_BITMAP & (1 << val))) {
++		prev_val = phba->cfg_link_speed;
++		phba->cfg_link_speed = val;
++		err = lpfc_issue_lip(lpfc_shost_from_vport(phba->pport));
++		if (err)
++			phba->cfg_link_speed = prev_val;
++		return err;
++	}
 +
-+		if (outbound_tail == MVIOP_QUEUE_LEN)
-+			outbound_tail = 0;
-+		writel(outbound_tail, &mu->outbound_tail);
-+		return p;
-+	} else
-+		return 0;
++	lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
++		"%d:0469 lpfc_link_speed attribute cannot be set to %d, "
++		"allowed range is [0, 8]\n",
++		phba->brd_no, val);
++	return -EINVAL;
 +}
 +
-+static void mv_inbound_write(u64 p, struct hptiop_hba *hba)
++static int lpfc_link_speed = 0;
++module_param(lpfc_link_speed, int, 0);
++MODULE_PARM_DESC(lpfc_link_speed, "Select link speed");
++lpfc_param_show(link_speed)
++static int
++lpfc_link_speed_init(struct lpfc_hba *phba, int val)
 +{
-+	u32 inbound_head = readl(&hba->u.mv.mu->inbound_head);
-+	u32 head = inbound_head + 1;
-+
-+	if (head == MVIOP_QUEUE_LEN)
-+		head = 0;
-+
-+	memcpy_toio(&hba->u.mv.mu->inbound_q[inbound_head], &p, 8);
-+	writel(head, &hba->u.mv.mu->inbound_head);
-+	writel(MVIOP_MU_INBOUND_INT_POSTQUEUE,
-+			&hba->u.mv.regs->inbound_doorbell);
++	if ((val >= 0 && val <= LPFC_MAX_LINK_SPEED)
++		&& (LPFC_LINK_SPEED_BITMAP & (1 << val))) {
++		phba->cfg_link_speed = val;
++		return 0;
++	}
++	lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
++			"0454 lpfc_link_speed attribute cannot "
++			"be set to %d, allowed values are "
++			"["LPFC_LINK_SPEED_STRING"]\n", val);
++	phba->cfg_link_speed = 0;
++	return -EINVAL;
 +}
 +
-+static void hptiop_request_callback_mv(struct hptiop_hba *hba, u64 tag)
-+{
-+	u32 req_type = (tag >> 5) & 0x7;
-+	struct hpt_iop_request_scsi_command *req;
-+
-+	dprintk("hptiop_request_callback_mv: tag=%llx\n", tag);
-+
-+	BUG_ON((tag & MVIOP_MU_QUEUE_REQUEST_RETURN_CONTEXT) == 0);
-+
-+	switch (req_type) {
-+	case IOP_REQUEST_TYPE_GET_CONFIG:
-+	case IOP_REQUEST_TYPE_SET_CONFIG:
-+		hba->msg_done = 1;
-+		break;
-+
-+	case IOP_REQUEST_TYPE_SCSI_COMMAND:
-+		req = hba->reqs[tag >> 8].req_virt;
-+		if (likely(tag & MVIOP_MU_QUEUE_REQUEST_RESULT_BIT))
-+			req->header.result = cpu_to_le32(IOP_RESULT_SUCCESS);
-+
-+		hptiop_finish_scsi_req(hba, tag>>8, req);
-+		break;
++lpfc_param_store(link_speed)
++static CLASS_DEVICE_ATTR(lpfc_link_speed, S_IRUGO | S_IWUSR,
++		lpfc_link_speed_show, lpfc_link_speed_store);
+ 
+ /*
+ # lpfc_fcp_class:  Determines FC class to use for the FCP protocol.
+@@ -1479,7 +1596,30 @@ LPFC_ATTR_RW(poll_tmo, 10, 1, 255,
+ */
+ LPFC_ATTR_R(use_msi, 0, 0, 1, "Use Message Signaled Interrupts, if possible");
+ 
++/*
++# lpfc_enable_hba_reset: Allow or prevent HBA resets to the hardware.
++#       0  = HBA resets disabled
++#       1  = HBA resets enabled (default)
++# Value range is [0,1]. Default value is 1.
++*/
++LPFC_ATTR_R(enable_hba_reset, 1, 0, 1, "Enable HBA resets from the driver.");
 +
-+	default:
-+		break;
++/*
++# lpfc_enable_hba_heartbeat: Enable HBA heartbeat timer..
++#       0  = HBA Heartbeat disabled
++#       1  = HBA Heartbeat enabled (default)
++# Value range is [0,1]. Default value is 1.
++*/
++LPFC_ATTR_R(enable_hba_heartbeat, 1, 0, 1, "Enable HBA Heartbeat.");
+ 
++/*
++ * lpfc_sg_seg_cnt: Initial Maximum DMA Segment Count
++ * This value can be set to values between 64 and 256. The default value is
++ * 64, but may be increased to allow for larger Max I/O sizes. The scsi layer
++ * will be allowed to request I/Os of sizes up to (MAX_SEG_COUNT * SEG_SIZE).
++ */
++LPFC_ATTR_R(sg_seg_cnt, LPFC_DEFAULT_SG_SEG_CNT, LPFC_DEFAULT_SG_SEG_CNT,
++	    LPFC_MAX_SG_SEG_CNT, "Max Scatter Gather Segment Count");
+ 
+ struct class_device_attribute *lpfc_hba_attrs[] = {
+ 	&class_device_attr_info,
+@@ -1494,6 +1634,7 @@ struct class_device_attribute *lpfc_hba_attrs[] = {
+ 	&class_device_attr_state,
+ 	&class_device_attr_num_discovered_ports,
+ 	&class_device_attr_lpfc_drvr_version,
++	&class_device_attr_lpfc_temp_sensor,
+ 	&class_device_attr_lpfc_log_verbose,
+ 	&class_device_attr_lpfc_lun_queue_depth,
+ 	&class_device_attr_lpfc_hba_queue_depth,
+@@ -1530,6 +1671,9 @@ struct class_device_attribute *lpfc_hba_attrs[] = {
+ 	&class_device_attr_lpfc_soft_wwnn,
+ 	&class_device_attr_lpfc_soft_wwpn,
+ 	&class_device_attr_lpfc_soft_wwn_enable,
++	&class_device_attr_lpfc_enable_hba_reset,
++	&class_device_attr_lpfc_enable_hba_heartbeat,
++	&class_device_attr_lpfc_sg_seg_cnt,
+ 	NULL,
+ };
+ 
+@@ -1552,6 +1696,7 @@ struct class_device_attribute *lpfc_vport_attrs[] = {
+ 	&class_device_attr_lpfc_max_luns,
+ 	&class_device_attr_nport_evt_cnt,
+ 	&class_device_attr_npiv_info,
++	&class_device_attr_lpfc_enable_da_id,
+ 	NULL,
+ };
+ 
+@@ -1727,13 +1872,18 @@ sysfs_mbox_read(struct kobject *kobj, struct bin_attribute *bin_attr,
+ 
+ 	spin_lock_irq(&phba->hbalock);
+ 
++	if (phba->over_temp_state == HBA_OVER_TEMP) {
++		sysfs_mbox_idle(phba);
++		spin_unlock_irq(&phba->hbalock);
++		return  -EACCES;
 +	}
-+}
 +
-+static int iop_intr_mv(struct hptiop_hba *hba)
-+{
-+	u32 status;
-+	int ret = 0;
+ 	if (off == 0 &&
+ 	    phba->sysfs_mbox.state  == SMBOX_WRITING &&
+ 	    phba->sysfs_mbox.offset >= 2 * sizeof(uint32_t)) {
+ 
+ 		switch (phba->sysfs_mbox.mbox->mb.mbxCommand) {
+ 			/* Offline only */
+-		case MBX_WRITE_NV:
+ 		case MBX_INIT_LINK:
+ 		case MBX_DOWN_LINK:
+ 		case MBX_CONFIG_LINK:
+@@ -1744,9 +1894,7 @@ sysfs_mbox_read(struct kobject *kobj, struct bin_attribute *bin_attr,
+ 		case MBX_DUMP_CONTEXT:
+ 		case MBX_RUN_DIAGS:
+ 		case MBX_RESTART:
+-		case MBX_FLASH_WR_ULA:
+ 		case MBX_SET_MASK:
+-		case MBX_SET_SLIM:
+ 		case MBX_SET_DEBUG:
+ 			if (!(vport->fc_flag & FC_OFFLINE_MODE)) {
+ 				printk(KERN_WARNING "mbox_read:Command 0x%x "
+@@ -1756,6 +1904,8 @@ sysfs_mbox_read(struct kobject *kobj, struct bin_attribute *bin_attr,
+ 				spin_unlock_irq(&phba->hbalock);
+ 				return -EPERM;
+ 			}
++		case MBX_WRITE_NV:
++		case MBX_WRITE_VPARMS:
+ 		case MBX_LOAD_SM:
+ 		case MBX_READ_NV:
+ 		case MBX_READ_CONFIG:
+@@ -1772,6 +1922,8 @@ sysfs_mbox_read(struct kobject *kobj, struct bin_attribute *bin_attr,
+ 		case MBX_LOAD_EXP_ROM:
+ 		case MBX_BEACON:
+ 		case MBX_DEL_LD_ENTRY:
++		case MBX_SET_VARIABLE:
++		case MBX_WRITE_WWN:
+ 			break;
+ 		case MBX_READ_SPARM64:
+ 		case MBX_READ_LA:
+@@ -1793,6 +1945,17 @@ sysfs_mbox_read(struct kobject *kobj, struct bin_attribute *bin_attr,
+ 			return -EPERM;
+ 		}
+ 
++		/* If HBA encountered an error attention, allow only DUMP
++		 * mailbox command until the HBA is restarted.
++		 */
++		if ((phba->pport->stopped) &&
++			(phba->sysfs_mbox.mbox->mb.mbxCommand
++				!= MBX_DUMP_MEMORY)) {
++			sysfs_mbox_idle(phba);
++			spin_unlock_irq(&phba->hbalock);
++			return -EPERM;
++		}
 +
-+	status = readl(&hba->u.mv.regs->outbound_doorbell);
-+	writel(~status, &hba->u.mv.regs->outbound_doorbell);
+ 		phba->sysfs_mbox.mbox->vport = vport;
+ 
+ 		if (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO) {
+@@ -1993,7 +2156,8 @@ lpfc_get_host_speed(struct Scsi_Host *shost)
+ 				fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN;
+ 			break;
+ 		}
+-	}
++	} else
++		fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN;
+ 
+ 	spin_unlock_irq(shost->host_lock);
+ }
+@@ -2013,7 +2177,7 @@ lpfc_get_host_fabric_name (struct Scsi_Host *shost)
+ 		node_name = wwn_to_u64(phba->fc_fabparam.nodeName.u.wwn);
+ 	else
+ 		/* fabric is local port if there is no F/FL_Port */
+-		node_name = wwn_to_u64(vport->fc_nodename.u.wwn);
++		node_name = 0;
+ 
+ 	spin_unlock_irq(shost->host_lock);
+ 
+@@ -2337,8 +2501,6 @@ struct fc_function_template lpfc_transport_functions = {
+ 	.dev_loss_tmo_callbk = lpfc_dev_loss_tmo_callbk,
+ 	.terminate_rport_io = lpfc_terminate_rport_io,
+ 
+-	.vport_create = lpfc_vport_create,
+-	.vport_delete = lpfc_vport_delete,
+ 	.dd_fcvport_size = sizeof(struct lpfc_vport *),
+ };
+ 
+@@ -2414,21 +2576,23 @@ lpfc_get_cfgparam(struct lpfc_hba *phba)
+ 	lpfc_poll_tmo_init(phba, lpfc_poll_tmo);
+ 	lpfc_enable_npiv_init(phba, lpfc_enable_npiv);
+ 	lpfc_use_msi_init(phba, lpfc_use_msi);
++	lpfc_enable_hba_reset_init(phba, lpfc_enable_hba_reset);
++	lpfc_enable_hba_heartbeat_init(phba, lpfc_enable_hba_heartbeat);
+ 	phba->cfg_poll = lpfc_poll;
+ 	phba->cfg_soft_wwnn = 0L;
+ 	phba->cfg_soft_wwpn = 0L;
+-	/*
+-	 * The total number of segments is the configuration value plus 2
+-	 * since the IOCB need a command and response bde.
+-	 */
+-	phba->cfg_sg_seg_cnt = LPFC_SG_SEG_CNT + 2;
++	lpfc_sg_seg_cnt_init(phba, lpfc_sg_seg_cnt);
++	/* Also reinitialize the host templates with new values. */
++	lpfc_vport_template.sg_tablesize = phba->cfg_sg_seg_cnt;
++	lpfc_template.sg_tablesize = phba->cfg_sg_seg_cnt;
+ 	/*
+ 	 * Since the sg_tablesize is module parameter, the sg_dma_buf_size
+-	 * used to create the sg_dma_buf_pool must be dynamically calculated
++	 * used to create the sg_dma_buf_pool must be dynamically calculated.
++	 * 2 segments are added since the IOCB needs a command and response bde.
+ 	 */
+ 	phba->cfg_sg_dma_buf_size = sizeof(struct fcp_cmnd) +
+ 			sizeof(struct fcp_rsp) +
+-			(phba->cfg_sg_seg_cnt * sizeof(struct ulp_bde64));
++			((phba->cfg_sg_seg_cnt + 2) * sizeof(struct ulp_bde64));
+ 	lpfc_hba_queue_depth_init(phba, lpfc_hba_queue_depth);
+ 	return;
+ }
+@@ -2448,5 +2612,6 @@ lpfc_get_vport_cfgparam(struct lpfc_vport *vport)
+ 	lpfc_discovery_threads_init(vport, lpfc_discovery_threads);
+ 	lpfc_max_luns_init(vport, lpfc_max_luns);
+ 	lpfc_scan_down_init(vport, lpfc_scan_down);
++	lpfc_enable_da_id_init(vport, lpfc_enable_da_id);
+ 	return;
+ }
+diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h
+index a599e15..50fcb7c 100644
+--- a/drivers/scsi/lpfc/lpfc_crtn.h
++++ b/drivers/scsi/lpfc/lpfc_crtn.h
+@@ -23,6 +23,8 @@ typedef int (*node_filter)(struct lpfc_nodelist *ndlp, void *param);
+ struct fc_rport;
+ void lpfc_dump_mem(struct lpfc_hba *, LPFC_MBOXQ_t *, uint16_t);
+ void lpfc_read_nv(struct lpfc_hba *, LPFC_MBOXQ_t *);
++void lpfc_config_async(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t);
 +
-+	if (status & MVIOP_MU_OUTBOUND_INT_MSG) {
-+		u32 msg;
-+		msg = readl(&hba->u.mv.mu->outbound_msg);
-+		dprintk("received outbound msg %x\n", msg);
-+		hptiop_message_callback(hba, msg);
-+		ret = 1;
-+	}
+ void lpfc_heart_beat(struct lpfc_hba *, LPFC_MBOXQ_t *);
+ int lpfc_read_la(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb,
+ 		 struct lpfc_dmabuf *mp);
+@@ -43,9 +45,9 @@ void lpfc_init_link(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t, uint32_t);
+ struct lpfc_vport *lpfc_find_vport_by_did(struct lpfc_hba *, uint32_t);
+ void lpfc_cleanup_rpis(struct lpfc_vport *vport, int remove);
+ int lpfc_linkdown(struct lpfc_hba *);
++void lpfc_port_link_failure(struct lpfc_vport *);
+ void lpfc_mbx_cmpl_read_la(struct lpfc_hba *, LPFC_MBOXQ_t *);
+ 
+-void lpfc_mbx_cmpl_clear_la(struct lpfc_hba *, LPFC_MBOXQ_t *);
+ void lpfc_mbx_cmpl_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
+ void lpfc_mbx_cmpl_dflt_rpi(struct lpfc_hba *, LPFC_MBOXQ_t *);
+ void lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
+@@ -66,15 +68,15 @@ int lpfc_check_sli_ndlp(struct lpfc_hba *, struct lpfc_sli_ring *,
+ void lpfc_nlp_init(struct lpfc_vport *, struct lpfc_nodelist *, uint32_t);
+ struct lpfc_nodelist *lpfc_nlp_get(struct lpfc_nodelist *);
+ int  lpfc_nlp_put(struct lpfc_nodelist *);
++int  lpfc_nlp_not_used(struct lpfc_nodelist *ndlp);
+ struct lpfc_nodelist *lpfc_setup_disc_node(struct lpfc_vport *, uint32_t);
+ void lpfc_disc_list_loopmap(struct lpfc_vport *);
+ void lpfc_disc_start(struct lpfc_vport *);
+-void lpfc_disc_flush_list(struct lpfc_vport *);
+ void lpfc_cleanup_discovery_resources(struct lpfc_vport *);
++void lpfc_cleanup(struct lpfc_vport *);
+ void lpfc_disc_timeout(unsigned long);
+ 
+ struct lpfc_nodelist *__lpfc_findnode_rpi(struct lpfc_vport *, uint16_t);
+-struct lpfc_nodelist *lpfc_findnode_rpi(struct lpfc_vport *, uint16_t);
+ 
+ void lpfc_worker_wake_up(struct lpfc_hba *);
+ int lpfc_workq_post_event(struct lpfc_hba *, void *, void *, uint32_t);
+@@ -82,17 +84,17 @@ int lpfc_do_work(void *);
+ int lpfc_disc_state_machine(struct lpfc_vport *, struct lpfc_nodelist *, void *,
+ 			    uint32_t);
+ 
+-void lpfc_register_new_vport(struct lpfc_hba *, struct lpfc_vport *,
+-			struct lpfc_nodelist *);
+ void lpfc_do_scr_ns_plogi(struct lpfc_hba *, struct lpfc_vport *);
+ int lpfc_check_sparm(struct lpfc_vport *, struct lpfc_nodelist *,
+ 		     struct serv_parm *, uint32_t);
+ int lpfc_els_abort(struct lpfc_hba *, struct lpfc_nodelist *);
++void lpfc_more_plogi(struct lpfc_vport *);
++void lpfc_more_adisc(struct lpfc_vport *);
++void lpfc_end_rscn(struct lpfc_vport *);
+ int lpfc_els_chk_latt(struct lpfc_vport *);
+ int lpfc_els_abort_flogi(struct lpfc_hba *);
+ int lpfc_initial_flogi(struct lpfc_vport *);
+ int lpfc_initial_fdisc(struct lpfc_vport *);
+-int lpfc_issue_els_fdisc(struct lpfc_vport *, struct lpfc_nodelist *, uint8_t);
+ int lpfc_issue_els_plogi(struct lpfc_vport *, uint32_t, uint8_t);
+ int lpfc_issue_els_prli(struct lpfc_vport *, struct lpfc_nodelist *, uint8_t);
+ int lpfc_issue_els_adisc(struct lpfc_vport *, struct lpfc_nodelist *, uint8_t);
+@@ -112,7 +114,6 @@ int lpfc_els_rsp_prli_acc(struct lpfc_vport *, struct lpfc_iocbq *,
+ void lpfc_cancel_retry_delay_tmo(struct lpfc_vport *, struct lpfc_nodelist *);
+ void lpfc_els_retry_delay(unsigned long);
+ void lpfc_els_retry_delay_handler(struct lpfc_nodelist *);
+-void lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *);
+ void lpfc_els_unsol_event(struct lpfc_hba *, struct lpfc_sli_ring *,
+ 			  struct lpfc_iocbq *);
+ int lpfc_els_handle_rscn(struct lpfc_vport *);
+@@ -124,7 +125,6 @@ int lpfc_els_disc_adisc(struct lpfc_vport *);
+ int lpfc_els_disc_plogi(struct lpfc_vport *);
+ void lpfc_els_timeout(unsigned long);
+ void lpfc_els_timeout_handler(struct lpfc_vport *);
+-void lpfc_hb_timeout(unsigned long);
+ void lpfc_hb_timeout_handler(struct lpfc_hba *);
+ 
+ void lpfc_ct_unsol_event(struct lpfc_hba *, struct lpfc_sli_ring *,
+@@ -142,7 +142,6 @@ void lpfc_hba_init(struct lpfc_hba *, uint32_t *);
+ int lpfc_post_buffer(struct lpfc_hba *, struct lpfc_sli_ring *, int, int);
+ void lpfc_decode_firmware_rev(struct lpfc_hba *, char *, int);
+ int lpfc_online(struct lpfc_hba *);
+-void lpfc_block_mgmt_io(struct lpfc_hba *);
+ void lpfc_unblock_mgmt_io(struct lpfc_hba *);
+ void lpfc_offline_prep(struct lpfc_hba *);
+ void lpfc_offline(struct lpfc_hba *);
+@@ -165,7 +164,6 @@ int lpfc_mbox_tmo_val(struct lpfc_hba *, int);
+ 
+ void lpfc_config_hbq(struct lpfc_hba *, uint32_t, struct lpfc_hbq_init *,
+ 	uint32_t , LPFC_MBOXQ_t *);
+-struct lpfc_hbq_entry * lpfc_sli_next_hbq_slot(struct lpfc_hba *, uint32_t);
+ struct hbq_dmabuf *lpfc_els_hbq_alloc(struct lpfc_hba *);
+ void lpfc_els_hbq_free(struct lpfc_hba *, struct hbq_dmabuf *);
+ 
+@@ -178,7 +176,6 @@ void lpfc_poll_start_timer(struct lpfc_hba * phba);
+ void lpfc_sli_poll_fcp_ring(struct lpfc_hba * hba);
+ struct lpfc_iocbq * lpfc_sli_get_iocbq(struct lpfc_hba *);
+ void lpfc_sli_release_iocbq(struct lpfc_hba * phba, struct lpfc_iocbq * iocb);
+-void __lpfc_sli_release_iocbq(struct lpfc_hba * phba, struct lpfc_iocbq * iocb);
+ uint16_t lpfc_sli_next_iotag(struct lpfc_hba * phba, struct lpfc_iocbq * iocb);
+ 
+ void lpfc_reset_barrier(struct lpfc_hba * phba);
+@@ -204,11 +201,14 @@ int lpfc_sli_ringpostbuf_put(struct lpfc_hba *, struct lpfc_sli_ring *,
+ struct lpfc_dmabuf *lpfc_sli_ringpostbuf_get(struct lpfc_hba *,
+ 					     struct lpfc_sli_ring *,
+ 					     dma_addr_t);
 +
-+	if (status & MVIOP_MU_OUTBOUND_INT_POSTQUEUE) {
-+		u64 tag;
++uint32_t lpfc_sli_get_buffer_tag(struct lpfc_hba *);
++struct lpfc_dmabuf * lpfc_sli_ring_taggedbuf_get(struct lpfc_hba *,
++			struct lpfc_sli_ring *, uint32_t );
 +
-+		while ((tag = mv_outbound_read(hba->u.mv.mu)))
-+			hptiop_request_callback_mv(hba, tag);
- 		ret = 1;
- 	}
+ int lpfc_sli_hbq_count(void);
+-int lpfc_sli_hbqbuf_init_hbqs(struct lpfc_hba *, uint32_t);
+ int lpfc_sli_hbqbuf_add_hbqs(struct lpfc_hba *, uint32_t);
+ void lpfc_sli_hbqbuf_free_all(struct lpfc_hba *);
+-struct hbq_dmabuf *lpfc_sli_hbqbuf_find(struct lpfc_hba *, uint32_t);
+ int lpfc_sli_hbq_size(void);
+ int lpfc_sli_issue_abort_iotag(struct lpfc_hba *, struct lpfc_sli_ring *,
+ 			       struct lpfc_iocbq *);
+@@ -219,9 +219,6 @@ int lpfc_sli_abort_iocb(struct lpfc_vport *, struct lpfc_sli_ring *, uint16_t,
+ void lpfc_mbox_timeout(unsigned long);
+ void lpfc_mbox_timeout_handler(struct lpfc_hba *);
+ 
+-struct lpfc_nodelist *__lpfc_find_node(struct lpfc_vport *, node_filter,
+-				       void *);
+-struct lpfc_nodelist *lpfc_find_node(struct lpfc_vport *, node_filter, void *);
+ struct lpfc_nodelist *lpfc_findnode_did(struct lpfc_vport *, uint32_t);
+ struct lpfc_nodelist *lpfc_findnode_wwpn(struct lpfc_vport *,
+ 					 struct lpfc_name *);
+@@ -260,6 +257,7 @@ extern struct scsi_host_template lpfc_vport_template;
+ extern struct fc_function_template lpfc_transport_functions;
+ extern struct fc_function_template lpfc_vport_transport_functions;
+ extern int lpfc_sli_mode;
++extern int lpfc_enable_npiv;
+ 
+ int  lpfc_vport_symbolic_node_name(struct lpfc_vport *, char *, size_t);
+ void lpfc_terminate_rport_io(struct fc_rport *);
+@@ -281,11 +279,8 @@ extern void lpfc_debugfs_slow_ring_trc(struct lpfc_hba *, char *, uint32_t,
+ extern struct lpfc_hbq_init *lpfc_hbq_defs[];
+ 
+ /* Interface exported by fabric iocb scheduler */
+-int lpfc_issue_fabric_iocb(struct lpfc_hba *, struct lpfc_iocbq *);
+-void lpfc_fabric_abort_vport(struct lpfc_vport *);
+ void lpfc_fabric_abort_nport(struct lpfc_nodelist *);
+ void lpfc_fabric_abort_hba(struct lpfc_hba *);
+-void lpfc_fabric_abort_flogi(struct lpfc_hba *);
+ void lpfc_fabric_block_timeout(unsigned long);
+ void lpfc_unblock_fabric_iocbs(struct lpfc_hba *);
+ void lpfc_adjust_queue_depth(struct lpfc_hba *);
+diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c
+index c701e4d..92441ce 100644
+--- a/drivers/scsi/lpfc/lpfc_ct.c
++++ b/drivers/scsi/lpfc/lpfc_ct.c
+@@ -19,7 +19,7 @@
+  *******************************************************************/
  
- 	return ret;
- }
+ /*
+- * Fibre Channel SCSI LAN Device Driver CT support
++ * Fibre Channel SCSI LAN Device Driver CT support: FC Generic Services FC-GS
+  */
  
--static int iop_send_sync_request(struct hptiop_hba *hba,
-+static int iop_send_sync_request_itl(struct hptiop_hba *hba,
- 					void __iomem *_req, u32 millisec)
- {
- 	struct hpt_iop_request_header __iomem *req = _req;
- 	u32 i;
+ #include <linux/blkdev.h>
+@@ -57,45 +57,27 @@
  
--	writel(readl(&req->flags) | IOP_REQUEST_FLAG_SYNC_REQUEST,
--			&req->flags);
--
-+	writel(readl(&req->flags) | IOP_REQUEST_FLAG_SYNC_REQUEST, &req->flags);
- 	writel(0, &req->context);
+ static char *lpfc_release_version = LPFC_DRIVER_VERSION;
+ 
+-/*
+- * lpfc_ct_unsol_event
+- */
+ static void
+-lpfc_ct_unsol_buffer(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq,
+-		     struct lpfc_dmabuf *mp, uint32_t size)
++lpfc_ct_ignore_hbq_buffer(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq,
++			  struct lpfc_dmabuf *mp, uint32_t size)
+ {
+ 	if (!mp) {
+-		printk(KERN_ERR "%s (%d): Unsolited CT, no buffer, "
+-		       "piocbq = %p, status = x%x, mp = %p, size = %d\n",
+-		       __FUNCTION__, __LINE__,
+-		       piocbq, piocbq->iocb.ulpStatus, mp, size);
++		lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
++				"0146 Ignoring unsolicted CT No HBQ "
++				"status = x%x\n",
++				piocbq->iocb.ulpStatus);
+ 	}
 -
--	writel((unsigned long)req - (unsigned long)hba->iop,
--			&hba->iop->inbound_queue);
+-	printk(KERN_ERR "%s (%d): Ignoring unsolicted CT piocbq = %p, "
+-	       "buffer = %p, size = %d, status = x%x\n",
+-	       __FUNCTION__, __LINE__,
+-	       piocbq, mp, size,
+-	       piocbq->iocb.ulpStatus);
 -
--	hptiop_pci_posting_flush(hba->iop);
-+	writel((unsigned long)req - (unsigned long)hba->u.itl.iop,
-+			&hba->u.itl.iop->inbound_queue);
-+	readl(&hba->u.itl.iop->outbound_intstatus);
- 
- 	for (i = 0; i < millisec; i++) {
--		__iop_intr(hba);
-+		iop_intr_itl(hba);
- 		if (readl(&req->context))
- 			return 0;
- 		msleep(1);
-@@ -159,19 +248,49 @@ static int iop_send_sync_request(struct hptiop_hba *hba,
- 	return -1;
++	lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
++			"0145 Ignoring unsolicted CT HBQ Size:%d "
++			"status = x%x\n",
++			size, piocbq->iocb.ulpStatus);
  }
  
--static int iop_send_sync_msg(struct hptiop_hba *hba, u32 msg, u32 millisec)
-+static int iop_send_sync_request_mv(struct hptiop_hba *hba,
-+					u32 size_bits, u32 millisec)
+ static void
+-lpfc_ct_ignore_hbq_buffer(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq,
+-			  struct lpfc_dmabuf *mp, uint32_t size)
++lpfc_ct_unsol_buffer(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq,
++		     struct lpfc_dmabuf *mp, uint32_t size)
  {
-+	struct hpt_iop_request_header *reqhdr = hba->u.mv.internal_req;
- 	u32 i;
- 
- 	hba->msg_done = 0;
-+	reqhdr->flags |= cpu_to_le32(IOP_REQUEST_FLAG_SYNC_REQUEST);
-+	mv_inbound_write(hba->u.mv.internal_req_phy |
-+			MVIOP_MU_QUEUE_ADDR_HOST_BIT | size_bits, hba);
-+
-+	for (i = 0; i < millisec; i++) {
-+		iop_intr_mv(hba);
-+		if (hba->msg_done)
-+			return 0;
-+		msleep(1);
-+	}
-+	return -1;
-+}
-+
-+static void hptiop_post_msg_itl(struct hptiop_hba *hba, u32 msg)
-+{
-+	writel(msg, &hba->u.itl.iop->inbound_msgaddr0);
-+	readl(&hba->u.itl.iop->outbound_intstatus);
-+}
-+
-+static void hptiop_post_msg_mv(struct hptiop_hba *hba, u32 msg)
-+{
-+	writel(msg, &hba->u.mv.mu->inbound_msg);
-+	writel(MVIOP_MU_INBOUND_INT_MSG, &hba->u.mv.regs->inbound_doorbell);
-+	readl(&hba->u.mv.regs->inbound_doorbell);
-+}
+-	if (!mp) {
+-		printk(KERN_ERR "%s (%d): Unsolited CT, no "
+-		       "HBQ buffer, piocbq = %p, status = x%x\n",
+-		       __FUNCTION__, __LINE__,
+-		       piocbq, piocbq->iocb.ulpStatus);
+-	} else {
+-		lpfc_ct_unsol_buffer(phba, piocbq, mp, size);
+-		printk(KERN_ERR "%s (%d): Ignoring unsolicted CT "
+-		       "piocbq = %p, buffer = %p, size = %d, "
+-		       "status = x%x\n",
+-		       __FUNCTION__, __LINE__,
+-		       piocbq, mp, size, piocbq->iocb.ulpStatus);
+-	}
++	lpfc_ct_ignore_hbq_buffer(phba, piocbq, mp, size);
+ }
  
--	writel(msg, &hba->iop->inbound_msgaddr0);
-+static int iop_send_sync_msg(struct hptiop_hba *hba, u32 msg, u32 millisec)
-+{
-+	u32 i;
+ void
+@@ -109,11 +91,8 @@ lpfc_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
+ 	struct lpfc_iocbq *iocbq;
+ 	dma_addr_t paddr;
+ 	uint32_t size;
+-	struct lpfc_dmabuf *bdeBuf1 = piocbq->context2;
+-	struct lpfc_dmabuf *bdeBuf2 = piocbq->context3;
+-
+-	piocbq->context2 = NULL;
+-	piocbq->context3 = NULL;
++	struct list_head head;
++	struct lpfc_dmabuf *bdeBuf;
  
--	hptiop_pci_posting_flush(hba->iop);
-+	hba->msg_done = 0;
-+	hba->ops->post_msg(hba, msg);
+ 	if (unlikely(icmd->ulpStatus == IOSTAT_NEED_BUFFER)) {
+ 		lpfc_sli_hbqbuf_add_hbqs(phba, LPFC_ELS_HBQ);
+@@ -122,7 +101,7 @@ lpfc_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
+ 		/* Not enough posted buffers; Try posting more buffers */
+ 		phba->fc_stat.NoRcvBuf++;
+ 		if (!(phba->sli3_options & LPFC_SLI3_HBQ_ENABLED))
+-			lpfc_post_buffer(phba, pring, 0, 1);
++			lpfc_post_buffer(phba, pring, 2, 1);
+ 		return;
+ 	}
  
- 	for (i = 0; i < millisec; i++) {
- 		spin_lock_irq(hba->host->host_lock);
--		__iop_intr(hba);
-+		hba->ops->iop_intr(hba);
- 		spin_unlock_irq(hba->host->host_lock);
- 		if (hba->msg_done)
- 			break;
-@@ -181,46 +300,67 @@ static int iop_send_sync_msg(struct hptiop_hba *hba, u32 msg, u32 millisec)
- 	return hba->msg_done? 0 : -1;
- }
+@@ -133,38 +112,34 @@ lpfc_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
+ 		return;
  
--static int iop_get_config(struct hptiop_hba *hba,
-+static int iop_get_config_itl(struct hptiop_hba *hba,
- 				struct hpt_iop_request_get_config *config)
- {
- 	u32 req32;
- 	struct hpt_iop_request_get_config __iomem *req;
+ 	if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) {
+-		list_for_each_entry(iocbq, &piocbq->list, list) {
++		INIT_LIST_HEAD(&head);
++		list_add_tail(&head, &piocbq->list);
++		list_for_each_entry(iocbq, &head, list) {
+ 			icmd = &iocbq->iocb;
+-			if (icmd->ulpBdeCount == 0) {
+-				printk(KERN_ERR "%s (%d): Unsolited CT, no "
+-				       "BDE, iocbq = %p, status = x%x\n",
+-				       __FUNCTION__, __LINE__,
+-				       iocbq, iocbq->iocb.ulpStatus);
++			if (icmd->ulpBdeCount == 0)
+ 				continue;
+-			}
+-
++			bdeBuf = iocbq->context2;
++			iocbq->context2 = NULL;
+ 			size  = icmd->un.cont64[0].tus.f.bdeSize;
+-			lpfc_ct_ignore_hbq_buffer(phba, piocbq, bdeBuf1, size);
+-			lpfc_in_buf_free(phba, bdeBuf1);
++			lpfc_ct_unsol_buffer(phba, piocbq, bdeBuf, size);
++			lpfc_in_buf_free(phba, bdeBuf);
+ 			if (icmd->ulpBdeCount == 2) {
+-				lpfc_ct_ignore_hbq_buffer(phba, piocbq, bdeBuf2,
+-							  size);
+-				lpfc_in_buf_free(phba, bdeBuf2);
++				bdeBuf = iocbq->context3;
++				iocbq->context3 = NULL;
++				size  = icmd->unsli3.rcvsli3.bde2.tus.f.bdeSize;
++				lpfc_ct_unsol_buffer(phba, piocbq, bdeBuf,
++						     size);
++				lpfc_in_buf_free(phba, bdeBuf);
+ 			}
+ 		}
++		list_del(&head);
+ 	} else {
+ 		struct lpfc_iocbq  *next;
  
--	req32 = readl(&hba->iop->inbound_queue);
-+	req32 = readl(&hba->u.itl.iop->inbound_queue);
- 	if (req32 == IOPMU_QUEUE_EMPTY)
- 		return -1;
+ 		list_for_each_entry_safe(iocbq, next, &piocbq->list, list) {
+ 			icmd = &iocbq->iocb;
+-			if (icmd->ulpBdeCount == 0) {
+-				printk(KERN_ERR "%s (%d): Unsolited CT, no "
+-				       "BDE, iocbq = %p, status = x%x\n",
+-				       __FUNCTION__, __LINE__,
+-				       iocbq, iocbq->iocb.ulpStatus);
+-				continue;
+-			}
+-
++			if (icmd->ulpBdeCount == 0)
++				lpfc_ct_unsol_buffer(phba, piocbq, NULL, 0);
+ 			for (i = 0; i < icmd->ulpBdeCount; i++) {
+ 				paddr = getPaddr(icmd->un.cont64[i].addrHigh,
+ 						 icmd->un.cont64[i].addrLow);
+@@ -176,6 +151,7 @@ lpfc_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
+ 			}
+ 			list_del(&iocbq->list);
+ 			lpfc_sli_release_iocbq(phba, iocbq);
++			lpfc_post_buffer(phba, pring, i, 1);
+ 		}
+ 	}
+ }
+@@ -203,7 +179,7 @@ lpfc_alloc_ct_rsp(struct lpfc_hba *phba, int cmdcode, struct ulp_bde64 *bpl,
+ 	struct lpfc_dmabuf *mp;
+ 	int cnt, i = 0;
  
- 	req = (struct hpt_iop_request_get_config __iomem *)
--			((unsigned long)hba->iop + req32);
-+			((unsigned long)hba->u.itl.iop + req32);
+-	/* We get chucks of FCELSSIZE */
++	/* We get chunks of FCELSSIZE */
+ 	cnt = size > FCELSSIZE ? FCELSSIZE: size;
  
- 	writel(0, &req->header.flags);
- 	writel(IOP_REQUEST_TYPE_GET_CONFIG, &req->header.type);
- 	writel(sizeof(struct hpt_iop_request_get_config), &req->header.size);
- 	writel(IOP_RESULT_PENDING, &req->header.result);
+ 	while (size) {
+@@ -426,6 +402,7 @@ lpfc_ns_rsp(struct lpfc_vport *vport, struct lpfc_dmabuf *mp, uint32_t Size)
  
--	if (iop_send_sync_request(hba, req, 20000)) {
-+	if (iop_send_sync_request_itl(hba, req, 20000)) {
- 		dprintk("Get config send cmd failed\n");
- 		return -1;
- 	}
+ 	lpfc_set_disctmo(vport);
+ 	vport->num_disc_nodes = 0;
++	vport->fc_ns_retry = 0;
  
- 	memcpy_fromio(config, req, sizeof(*config));
--	writel(req32, &hba->iop->outbound_queue);
-+	writel(req32, &hba->u.itl.iop->outbound_queue);
-+	return 0;
-+}
-+
-+static int iop_get_config_mv(struct hptiop_hba *hba,
-+				struct hpt_iop_request_get_config *config)
-+{
-+	struct hpt_iop_request_get_config *req = hba->u.mv.internal_req;
-+
-+	req->header.flags = cpu_to_le32(IOP_REQUEST_FLAG_OUTPUT_CONTEXT);
-+	req->header.type = cpu_to_le32(IOP_REQUEST_TYPE_GET_CONFIG);
-+	req->header.size =
-+		cpu_to_le32(sizeof(struct hpt_iop_request_get_config));
-+	req->header.result = cpu_to_le32(IOP_RESULT_PENDING);
-+	req->header.context = cpu_to_le64(IOP_REQUEST_TYPE_GET_CONFIG<<5);
-+
-+	if (iop_send_sync_request_mv(hba, 0, 20000)) {
-+		dprintk("Get config send cmd failed\n");
-+		return -1;
-+	}
-+
-+	memcpy(config, req, sizeof(struct hpt_iop_request_get_config));
- 	return 0;
- }
  
--static int iop_set_config(struct hptiop_hba *hba,
-+static int iop_set_config_itl(struct hptiop_hba *hba,
- 				struct hpt_iop_request_set_config *config)
- {
- 	u32 req32;
- 	struct hpt_iop_request_set_config __iomem *req;
+ 	list_add_tail(&head, &mp->list);
+@@ -458,7 +435,7 @@ lpfc_ns_rsp(struct lpfc_vport *vport, struct lpfc_dmabuf *mp, uint32_t Size)
+ 			    ((lpfc_find_vport_by_did(phba, Did) == NULL) ||
+ 			     vport->cfg_peer_port_login)) {
+ 				if ((vport->port_type != LPFC_NPIV_PORT) ||
+-				    (vport->fc_flag & FC_RFF_NOT_SUPPORTED) ||
++				    (!(vport->ct_flags & FC_CT_RFF_ID)) ||
+ 				    (!vport->cfg_restrict_login)) {
+ 					ndlp = lpfc_setup_disc_node(vport, Did);
+ 					if (ndlp) {
+@@ -506,7 +483,17 @@ lpfc_ns_rsp(struct lpfc_vport *vport, struct lpfc_dmabuf *mp, uint32_t Size)
+ 						Did, vport->fc_flag,
+ 						vport->fc_rscn_id_cnt);
  
--	req32 = readl(&hba->iop->inbound_queue);
-+	req32 = readl(&hba->u.itl.iop->inbound_queue);
- 	if (req32 == IOPMU_QUEUE_EMPTY)
- 		return -1;
+-						if (lpfc_ns_cmd(vport,
++						/* This NPortID was previously
++						 * a FCP target, * Don't even
++						 * bother to send GFF_ID.
++						 */
++						ndlp = lpfc_findnode_did(vport,
++							Did);
++						if (ndlp && (ndlp->nlp_type &
++							NLP_FCP_TARGET))
++							lpfc_setup_disc_node
++								(vport, Did);
++						else if (lpfc_ns_cmd(vport,
+ 							SLI_CTNS_GFF_ID,
+ 							0, Did) == 0)
+ 							vport->num_disc_nodes++;
+@@ -554,7 +541,7 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+ 	struct lpfc_dmabuf *outp;
+ 	struct lpfc_sli_ct_request *CTrsp;
+ 	struct lpfc_nodelist *ndlp;
+-	int rc;
++	int rc, retry;
  
- 	req = (struct hpt_iop_request_set_config __iomem *)
--			((unsigned long)hba->iop + req32);
-+			((unsigned long)hba->u.itl.iop + req32);
+ 	/* First save ndlp, before we overwrite it */
+ 	ndlp = cmdiocb->context_un.ndlp;
+@@ -574,7 +561,6 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+ 	if (vport->load_flag & FC_UNLOADING)
+ 		goto out;
  
- 	memcpy_toio((u8 __iomem *)req + sizeof(struct hpt_iop_request_header),
- 		(u8 *)config + sizeof(struct hpt_iop_request_header),
-@@ -232,22 +372,52 @@ static int iop_set_config(struct hptiop_hba *hba,
- 	writel(sizeof(struct hpt_iop_request_set_config), &req->header.size);
- 	writel(IOP_RESULT_PENDING, &req->header.result);
+-
+ 	if (lpfc_els_chk_latt(vport) || lpfc_error_lost_link(irsp)) {
+ 		lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
+ 				 "0216 Link event during NS query\n");
+@@ -585,14 +571,35 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+ 	if (irsp->ulpStatus) {
+ 		/* Check for retry */
+ 		if (vport->fc_ns_retry < LPFC_MAX_NS_RETRY) {
+-			if ((irsp->ulpStatus != IOSTAT_LOCAL_REJECT) ||
+-				(irsp->un.ulpWord[4] != IOERR_NO_RESOURCES))
++			retry = 1;
++			if (irsp->ulpStatus == IOSTAT_LOCAL_REJECT) {
++				switch (irsp->un.ulpWord[4]) {
++				case IOERR_NO_RESOURCES:
++					/* We don't increment the retry
++					 * count for this case.
++					 */
++					break;
++				case IOERR_LINK_DOWN:
++				case IOERR_SLI_ABORTED:
++				case IOERR_SLI_DOWN:
++					retry = 0;
++					break;
++				default:
++					vport->fc_ns_retry++;
++				}
++			}
++			else
+ 				vport->fc_ns_retry++;
+-			/* CT command is being retried */
+-			rc = lpfc_ns_cmd(vport, SLI_CTNS_GID_FT,
++
++			if (retry) {
++				/* CT command is being retried */
++				rc = lpfc_ns_cmd(vport, SLI_CTNS_GID_FT,
+ 					 vport->fc_ns_retry, 0);
+-			if (rc == 0)
+-				goto out;
++				if (rc == 0) {
++					/* success */
++					goto out;
++				}
++			}
+ 		}
+ 		lpfc_vport_set_state(vport, FC_VPORT_FAILED);
+ 		lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+@@ -698,7 +705,7 @@ lpfc_cmpl_ct_cmd_gff_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+ 	struct lpfc_dmabuf *inp = (struct lpfc_dmabuf *) cmdiocb->context1;
+ 	struct lpfc_dmabuf *outp = (struct lpfc_dmabuf *) cmdiocb->context2;
+ 	struct lpfc_sli_ct_request *CTrsp;
+-	int did;
++	int did, rc, retry;
+ 	uint8_t fbits;
+ 	struct lpfc_nodelist *ndlp;
  
--	if (iop_send_sync_request(hba, req, 20000)) {
-+	if (iop_send_sync_request_itl(hba, req, 20000)) {
- 		dprintk("Set config send cmd failed\n");
- 		return -1;
+@@ -729,6 +736,39 @@ lpfc_cmpl_ct_cmd_gff_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+ 		}
  	}
+ 	else {
++		/* Check for retry */
++		if (cmdiocb->retry < LPFC_MAX_NS_RETRY) {
++			retry = 1;
++			if (irsp->ulpStatus == IOSTAT_LOCAL_REJECT) {
++				switch (irsp->un.ulpWord[4]) {
++				case IOERR_NO_RESOURCES:
++					/* We don't increment the retry
++					 * count for this case.
++					 */
++					break;
++				case IOERR_LINK_DOWN:
++				case IOERR_SLI_ABORTED:
++				case IOERR_SLI_DOWN:
++					retry = 0;
++					break;
++				default:
++					cmdiocb->retry++;
++				}
++			}
++			else
++				cmdiocb->retry++;
++
++			if (retry) {
++				/* CT command is being retried */
++				rc = lpfc_ns_cmd(vport, SLI_CTNS_GFF_ID,
++					 cmdiocb->retry, did);
++				if (rc == 0) {
++					/* success */
++					lpfc_ct_free_iocb(phba, cmdiocb);
++					return;
++				}
++			}
++		}
+ 		lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
+ 				 "0267 NameServer GFF Rsp "
+ 				 "x%x Error (%d %d) Data: x%x x%x\n",
+@@ -778,8 +818,8 @@ out:
  
--	writel(req32, &hba->iop->outbound_queue);
-+	writel(req32, &hba->u.itl.iop->outbound_queue);
- 	return 0;
- }
  
--static int hptiop_initialize_iop(struct hptiop_hba *hba)
-+static int iop_set_config_mv(struct hptiop_hba *hba,
-+				struct hpt_iop_request_set_config *config)
+ static void
+-lpfc_cmpl_ct_cmd_rft_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+-			struct lpfc_iocbq *rspiocb)
++lpfc_cmpl_ct(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
++	     struct lpfc_iocbq *rspiocb)
  {
--	struct hpt_iopmu __iomem *iop = hba->iop;
-+	struct hpt_iop_request_set_config *req = hba->u.mv.internal_req;
+ 	struct lpfc_vport *vport = cmdiocb->vport;
+ 	struct lpfc_dmabuf *inp;
+@@ -809,7 +849,7 @@ lpfc_cmpl_ct_cmd_rft_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
  
--	/* enable interrupts */
-+	memcpy(req, config, sizeof(struct hpt_iop_request_set_config));
-+	req->header.flags = cpu_to_le32(IOP_REQUEST_FLAG_OUTPUT_CONTEXT);
-+	req->header.type = cpu_to_le32(IOP_REQUEST_TYPE_SET_CONFIG);
-+	req->header.size =
-+		cpu_to_le32(sizeof(struct hpt_iop_request_set_config));
-+	req->header.result = cpu_to_le32(IOP_RESULT_PENDING);
-+	req->header.context = cpu_to_le64(IOP_REQUEST_TYPE_SET_CONFIG<<5);
+ 	/* RFT request completes status <ulpStatus> CmdRsp <CmdRsp> */
+ 	lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
+-			 "0209 RFT request completes, latt %d, "
++			 "0209 CT Request completes, latt %d, "
+ 			 "ulpStatus x%x CmdRsp x%x, Context x%x, Tag x%x\n",
+ 			 latt, irsp->ulpStatus,
+ 			 CTrsp->CommandResponse.bits.CmdRsp,
+@@ -848,10 +888,44 @@ out:
+ }
+ 
+ static void
++lpfc_cmpl_ct_cmd_rft_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
++			struct lpfc_iocbq *rspiocb)
++{
++	IOCB_t *irsp = &rspiocb->iocb;
++	struct lpfc_vport *vport = cmdiocb->vport;
 +
-+	if (iop_send_sync_request_mv(hba, 0, 20000)) {
-+		dprintk("Set config send cmd failed\n");
-+		return -1;
-+	}
++	if (irsp->ulpStatus == IOSTAT_SUCCESS) {
++		struct lpfc_dmabuf *outp;
++		struct lpfc_sli_ct_request *CTrsp;
 +
-+	return 0;
++		outp = (struct lpfc_dmabuf *) cmdiocb->context2;
++		CTrsp = (struct lpfc_sli_ct_request *) outp->virt;
++		if (CTrsp->CommandResponse.bits.CmdRsp ==
++		    be16_to_cpu(SLI_CT_RESPONSE_FS_ACC))
++			vport->ct_flags |= FC_CT_RFT_ID;
++	}
++	lpfc_cmpl_ct(phba, cmdiocb, rspiocb);
++	return;
 +}
 +
-+static void hptiop_enable_intr_itl(struct hptiop_hba *hba)
-+{
- 	writel(~(IOPMU_OUTBOUND_INT_POSTQUEUE | IOPMU_OUTBOUND_INT_MSG0),
--			&iop->outbound_intmask);
-+		&hba->u.itl.iop->outbound_intmask);
-+}
++static void
+ lpfc_cmpl_ct_cmd_rnn_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+ 			struct lpfc_iocbq *rspiocb)
+ {
+-	lpfc_cmpl_ct_cmd_rft_id(phba, cmdiocb, rspiocb);
++	IOCB_t *irsp = &rspiocb->iocb;
++	struct lpfc_vport *vport = cmdiocb->vport;
 +
-+static void hptiop_enable_intr_mv(struct hptiop_hba *hba)
-+{
-+	writel(MVIOP_MU_OUTBOUND_INT_POSTQUEUE | MVIOP_MU_OUTBOUND_INT_MSG,
-+		&hba->u.mv.regs->outbound_intmask);
-+}
++	if (irsp->ulpStatus == IOSTAT_SUCCESS) {
++		struct lpfc_dmabuf *outp;
++		struct lpfc_sli_ct_request *CTrsp;
 +
-+static int hptiop_initialize_iop(struct hptiop_hba *hba)
-+{
-+	/* enable interrupts */
-+	hba->ops->enable_intr(hba);
- 
- 	hba->initialized = 1;
- 
-@@ -261,37 +431,74 @@ static int hptiop_initialize_iop(struct hptiop_hba *hba)
- 	return 0;
++		outp = (struct lpfc_dmabuf *) cmdiocb->context2;
++		CTrsp = (struct lpfc_sli_ct_request *) outp->virt;
++		if (CTrsp->CommandResponse.bits.CmdRsp ==
++		    be16_to_cpu(SLI_CT_RESPONSE_FS_ACC))
++			vport->ct_flags |= FC_CT_RNN_ID;
++	}
++	lpfc_cmpl_ct(phba, cmdiocb, rspiocb);
+ 	return;
  }
  
--static int hptiop_map_pci_bar(struct hptiop_hba *hba)
-+static void __iomem *hptiop_map_pci_bar(struct hptiop_hba *hba, int index)
+@@ -859,7 +933,20 @@ static void
+ lpfc_cmpl_ct_cmd_rspn_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+ 			 struct lpfc_iocbq *rspiocb)
  {
- 	u32 mem_base_phy, length;
- 	void __iomem *mem_base_virt;
+-	lpfc_cmpl_ct_cmd_rft_id(phba, cmdiocb, rspiocb);
++	IOCB_t *irsp = &rspiocb->iocb;
++	struct lpfc_vport *vport = cmdiocb->vport;
 +
- 	struct pci_dev *pcidev = hba->pcidev;
- 
--	if (!(pci_resource_flags(pcidev, 0) & IORESOURCE_MEM)) {
++	if (irsp->ulpStatus == IOSTAT_SUCCESS) {
++		struct lpfc_dmabuf *outp;
++		struct lpfc_sli_ct_request *CTrsp;
 +
-+	if (!(pci_resource_flags(pcidev, index) & IORESOURCE_MEM)) {
- 		printk(KERN_ERR "scsi%d: pci resource invalid\n",
- 				hba->host->host_no);
--		return -1;
-+		return 0;
- 	}
- 
--	mem_base_phy = pci_resource_start(pcidev, 0);
--	length = pci_resource_len(pcidev, 0);
-+	mem_base_phy = pci_resource_start(pcidev, index);
-+	length = pci_resource_len(pcidev, index);
- 	mem_base_virt = ioremap(mem_base_phy, length);
- 
- 	if (!mem_base_virt) {
- 		printk(KERN_ERR "scsi%d: Fail to ioremap memory space\n",
- 				hba->host->host_no);
-+		return 0;
++		outp = (struct lpfc_dmabuf *) cmdiocb->context2;
++		CTrsp = (struct lpfc_sli_ct_request *) outp->virt;
++		if (CTrsp->CommandResponse.bits.CmdRsp ==
++		    be16_to_cpu(SLI_CT_RESPONSE_FS_ACC))
++			vport->ct_flags |= FC_CT_RSPN_ID;
 +	}
-+	return mem_base_virt;
-+}
++	lpfc_cmpl_ct(phba, cmdiocb, rspiocb);
+ 	return;
+ }
+ 
+@@ -867,7 +954,32 @@ static void
+ lpfc_cmpl_ct_cmd_rsnn_nn(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+ 			 struct lpfc_iocbq *rspiocb)
+ {
+-	lpfc_cmpl_ct_cmd_rft_id(phba, cmdiocb, rspiocb);
++	IOCB_t *irsp = &rspiocb->iocb;
++	struct lpfc_vport *vport = cmdiocb->vport;
 +
-+static int hptiop_map_pci_bar_itl(struct hptiop_hba *hba)
-+{
-+	hba->u.itl.iop = hptiop_map_pci_bar(hba, 0);
-+	if (hba->u.itl.iop)
-+		return 0;
-+	else
-+		return -1;
-+}
++	if (irsp->ulpStatus == IOSTAT_SUCCESS) {
++		struct lpfc_dmabuf *outp;
++		struct lpfc_sli_ct_request *CTrsp;
 +
-+static void hptiop_unmap_pci_bar_itl(struct hptiop_hba *hba)
-+{
-+	iounmap(hba->u.itl.iop);
++		outp = (struct lpfc_dmabuf *) cmdiocb->context2;
++		CTrsp = (struct lpfc_sli_ct_request *) outp->virt;
++		if (CTrsp->CommandResponse.bits.CmdRsp ==
++		    be16_to_cpu(SLI_CT_RESPONSE_FS_ACC))
++			vport->ct_flags |= FC_CT_RSNN_NN;
++	}
++	lpfc_cmpl_ct(phba, cmdiocb, rspiocb);
++	return;
 +}
 +
-+static int hptiop_map_pci_bar_mv(struct hptiop_hba *hba)
-+{
-+	hba->u.mv.regs = hptiop_map_pci_bar(hba, 0);
-+	if (hba->u.mv.regs == 0)
-+		return -1;
-+
-+	hba->u.mv.mu = hptiop_map_pci_bar(hba, 2);
-+	if (hba->u.mv.mu == 0) {
-+		iounmap(hba->u.mv.regs);
- 		return -1;
- 	}
- 
--	hba->iop = mem_base_virt;
--	dprintk("hptiop_map_pci_bar: iop=%p\n", hba->iop);
- 	return 0;
- }
- 
-+static void hptiop_unmap_pci_bar_mv(struct hptiop_hba *hba)
++static void
++lpfc_cmpl_ct_cmd_da_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
++ struct lpfc_iocbq *rspiocb)
 +{
-+	iounmap(hba->u.mv.regs);
-+	iounmap(hba->u.mv.mu);
-+}
-+
- static void hptiop_message_callback(struct hptiop_hba *hba, u32 msg)
- {
- 	dprintk("iop message 0x%x\n", msg);
- 
-+	if (msg == IOPMU_INBOUND_MSG0_NOP)
-+		hba->msg_done = 1;
++	struct lpfc_vport *vport = cmdiocb->vport;
 +
- 	if (!hba->initialized)
- 		return;
- 
-@@ -303,7 +510,7 @@ static void hptiop_message_callback(struct hptiop_hba *hba, u32 msg)
- 		hba->msg_done = 1;
++	/* even if it fails we will act as though it succeeded. */
++	vport->ct_flags = 0;
++	lpfc_cmpl_ct(phba, cmdiocb, rspiocb);
+ 	return;
  }
  
--static inline struct hptiop_request *get_req(struct hptiop_hba *hba)
-+static struct hptiop_request *get_req(struct hptiop_hba *hba)
- {
- 	struct hptiop_request *ret;
+@@ -878,10 +990,17 @@ lpfc_cmpl_ct_cmd_rff_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+ 	IOCB_t *irsp = &rspiocb->iocb;
+ 	struct lpfc_vport *vport = cmdiocb->vport;
  
-@@ -316,30 +523,19 @@ static inline struct hptiop_request *get_req(struct hptiop_hba *hba)
- 	return ret;
- }
+-	if (irsp->ulpStatus != IOSTAT_SUCCESS)
+-	    vport->fc_flag |= FC_RFF_NOT_SUPPORTED;
++	if (irsp->ulpStatus == IOSTAT_SUCCESS) {
++		struct lpfc_dmabuf *outp;
++		struct lpfc_sli_ct_request *CTrsp;
  
--static inline void free_req(struct hptiop_hba *hba, struct hptiop_request *req)
-+static void free_req(struct hptiop_hba *hba, struct hptiop_request *req)
- {
- 	dprintk("free_req(%d, %p)\n", req->index, req);
- 	req->next = hba->req_list;
- 	hba->req_list = req;
+-	lpfc_cmpl_ct_cmd_rft_id(phba, cmdiocb, rspiocb);
++		outp = (struct lpfc_dmabuf *) cmdiocb->context2;
++		CTrsp = (struct lpfc_sli_ct_request *) outp->virt;
++		if (CTrsp->CommandResponse.bits.CmdRsp ==
++		    be16_to_cpu(SLI_CT_RESPONSE_FS_ACC))
++			vport->ct_flags |= FC_CT_RFF_ID;
++	}
++	lpfc_cmpl_ct(phba, cmdiocb, rspiocb);
+ 	return;
  }
  
--static void hptiop_host_request_callback(struct hptiop_hba *hba, u32 _tag)
-+static void hptiop_finish_scsi_req(struct hptiop_hba *hba, u32 tag,
-+				struct hpt_iop_request_scsi_command *req)
- {
--	struct hpt_iop_request_scsi_command *req;
- 	struct scsi_cmnd *scp;
--	u32 tag;
--
--	if (hba->iopintf_v2) {
--		tag = _tag & ~ IOPMU_QUEUE_REQUEST_RESULT_BIT;
--		req = hba->reqs[tag].req_virt;
--		if (likely(_tag & IOPMU_QUEUE_REQUEST_RESULT_BIT))
--			req->header.result = IOP_RESULT_SUCCESS;
--	} else {
--		tag = _tag;
--		req = hba->reqs[tag].req_virt;
--	}
+@@ -1001,6 +1120,8 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode,
+ 		bpl->tus.f.bdeSize = RSPN_REQUEST_SZ;
+ 	else if (cmdcode == SLI_CTNS_RSNN_NN)
+ 		bpl->tus.f.bdeSize = RSNN_REQUEST_SZ;
++	else if (cmdcode == SLI_CTNS_DA_ID)
++		bpl->tus.f.bdeSize = DA_ID_REQUEST_SZ;
+ 	else if (cmdcode == SLI_CTNS_RFF_ID)
+ 		bpl->tus.f.bdeSize = RFF_REQUEST_SZ;
+ 	else
+@@ -1029,31 +1150,34 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode,
+ 	case SLI_CTNS_GFF_ID:
+ 		CtReq->CommandResponse.bits.CmdRsp =
+ 			be16_to_cpu(SLI_CTNS_GFF_ID);
+-		CtReq->un.gff.PortId = be32_to_cpu(context);
++		CtReq->un.gff.PortId = cpu_to_be32(context);
+ 		cmpl = lpfc_cmpl_ct_cmd_gff_id;
+ 		break;
  
--	dprintk("hptiop_host_request_callback: req=%p, type=%d, "
-+	dprintk("hptiop_finish_scsi_req: req=%p, type=%d, "
- 			"result=%d, context=0x%x tag=%d\n",
- 			req, req->header.type, req->header.result,
- 			req->header.context, tag);
-@@ -354,6 +550,8 @@ static void hptiop_host_request_callback(struct hptiop_hba *hba, u32 _tag)
+ 	case SLI_CTNS_RFT_ID:
++		vport->ct_flags &= ~FC_CT_RFT_ID;
+ 		CtReq->CommandResponse.bits.CmdRsp =
+ 		    be16_to_cpu(SLI_CTNS_RFT_ID);
+-		CtReq->un.rft.PortId = be32_to_cpu(vport->fc_myDID);
++		CtReq->un.rft.PortId = cpu_to_be32(vport->fc_myDID);
+ 		CtReq->un.rft.fcpReg = 1;
+ 		cmpl = lpfc_cmpl_ct_cmd_rft_id;
+ 		break;
  
- 	switch (le32_to_cpu(req->header.result)) {
- 	case IOP_RESULT_SUCCESS:
-+		scsi_set_resid(scp,
-+			scsi_bufflen(scp) - le32_to_cpu(req->dataxfer_length));
- 		scp->result = (DID_OK<<16);
+ 	case SLI_CTNS_RNN_ID:
++		vport->ct_flags &= ~FC_CT_RNN_ID;
+ 		CtReq->CommandResponse.bits.CmdRsp =
+ 		    be16_to_cpu(SLI_CTNS_RNN_ID);
+-		CtReq->un.rnn.PortId = be32_to_cpu(vport->fc_myDID);
++		CtReq->un.rnn.PortId = cpu_to_be32(vport->fc_myDID);
+ 		memcpy(CtReq->un.rnn.wwnn,  &vport->fc_nodename,
+ 		       sizeof (struct lpfc_name));
+ 		cmpl = lpfc_cmpl_ct_cmd_rnn_id;
  		break;
- 	case IOP_RESULT_BAD_TARGET:
-@@ -371,12 +569,12 @@ static void hptiop_host_request_callback(struct hptiop_hba *hba, u32 _tag)
- 	case IOP_RESULT_INVALID_REQUEST:
- 		scp->result = (DID_ABORT<<16);
+ 
+ 	case SLI_CTNS_RSPN_ID:
++		vport->ct_flags &= ~FC_CT_RSPN_ID;
+ 		CtReq->CommandResponse.bits.CmdRsp =
+ 		    be16_to_cpu(SLI_CTNS_RSPN_ID);
+-		CtReq->un.rspn.PortId = be32_to_cpu(vport->fc_myDID);
++		CtReq->un.rspn.PortId = cpu_to_be32(vport->fc_myDID);
+ 		size = sizeof(CtReq->un.rspn.symbname);
+ 		CtReq->un.rspn.len =
+ 			lpfc_vport_symbolic_port_name(vport,
+@@ -1061,6 +1185,7 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode,
+ 		cmpl = lpfc_cmpl_ct_cmd_rspn_id;
  		break;
--	case IOP_RESULT_MODE_SENSE_CHECK_CONDITION:
-+	case IOP_RESULT_CHECK_CONDITION:
-+		scsi_set_resid(scp,
-+			scsi_bufflen(scp) - le32_to_cpu(req->dataxfer_length));
- 		scp->result = SAM_STAT_CHECK_CONDITION;
--		memset(&scp->sense_buffer,
--				0, sizeof(scp->sense_buffer));
- 		memcpy(&scp->sense_buffer, &req->sg_list,
--				min(sizeof(scp->sense_buffer),
-+				min_t(size_t, SCSI_SENSE_BUFFERSIZE,
- 					le32_to_cpu(req->dataxfer_length)));
+ 	case SLI_CTNS_RSNN_NN:
++		vport->ct_flags &= ~FC_CT_RSNN_NN;
+ 		CtReq->CommandResponse.bits.CmdRsp =
+ 		    be16_to_cpu(SLI_CTNS_RSNN_NN);
+ 		memcpy(CtReq->un.rsnn.wwnn, &vport->fc_nodename,
+@@ -1071,11 +1196,18 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode,
+ 			CtReq->un.rsnn.symbname, size);
+ 		cmpl = lpfc_cmpl_ct_cmd_rsnn_nn;
  		break;
++	case SLI_CTNS_DA_ID:
++		/* Implement DA_ID Nameserver request */
++		CtReq->CommandResponse.bits.CmdRsp =
++			be16_to_cpu(SLI_CTNS_DA_ID);
++		CtReq->un.da_id.port_id = cpu_to_be32(vport->fc_myDID);
++		cmpl = lpfc_cmpl_ct_cmd_da_id;
++		break;
+ 	case SLI_CTNS_RFF_ID:
+-		vport->fc_flag &= ~FC_RFF_NOT_SUPPORTED;
++		vport->ct_flags &= ~FC_CT_RFF_ID;
+ 		CtReq->CommandResponse.bits.CmdRsp =
+ 		    be16_to_cpu(SLI_CTNS_RFF_ID);
+-		CtReq->un.rff.PortId = be32_to_cpu(vport->fc_myDID);;
++		CtReq->un.rff.PortId = cpu_to_be32(vport->fc_myDID);;
+ 		CtReq->un.rff.fbits = FC4_FEATURE_INIT;
+ 		CtReq->un.rff.type_code = FC_FCP_DATA;
+ 		cmpl = lpfc_cmpl_ct_cmd_rff_id;
+diff --git a/drivers/scsi/lpfc/lpfc_debugfs.c b/drivers/scsi/lpfc/lpfc_debugfs.c
+index d6a98bc..783d1ee 100644
+--- a/drivers/scsi/lpfc/lpfc_debugfs.c
++++ b/drivers/scsi/lpfc/lpfc_debugfs.c
+@@ -43,6 +43,7 @@
+ #include "lpfc_crtn.h"
+ #include "lpfc_vport.h"
+ #include "lpfc_version.h"
++#include "lpfc_compat.h"
+ #include "lpfc_debugfs.h"
  
-@@ -391,15 +589,33 @@ static void hptiop_host_request_callback(struct hptiop_hba *hba, u32 _tag)
- 	free_req(hba, &hba->reqs[tag]);
- }
- 
--void hptiop_iop_request_callback(struct hptiop_hba *hba, u32 tag)
-+static void hptiop_host_request_callback_itl(struct hptiop_hba *hba, u32 _tag)
-+{
-+	struct hpt_iop_request_scsi_command *req;
-+	u32 tag;
-+
-+	if (hba->iopintf_v2) {
-+		tag = _tag & ~IOPMU_QUEUE_REQUEST_RESULT_BIT;
-+		req = hba->reqs[tag].req_virt;
-+		if (likely(_tag & IOPMU_QUEUE_REQUEST_RESULT_BIT))
-+			req->header.result = cpu_to_le32(IOP_RESULT_SUCCESS);
-+	} else {
-+		tag = _tag;
-+		req = hba->reqs[tag].req_virt;
-+	}
-+
-+	hptiop_finish_scsi_req(hba, tag, req);
-+}
-+
-+void hptiop_iop_request_callback_itl(struct hptiop_hba *hba, u32 tag)
- {
- 	struct hpt_iop_request_header __iomem *req;
- 	struct hpt_iop_request_ioctl_command __iomem *p;
- 	struct hpt_ioctl_k *arg;
- 
- 	req = (struct hpt_iop_request_header __iomem *)
--			((unsigned long)hba->iop + tag);
--	dprintk("hptiop_iop_request_callback: req=%p, type=%d, "
-+			((unsigned long)hba->u.itl.iop + tag);
-+	dprintk("hptiop_iop_request_callback_itl: req=%p, type=%d, "
- 			"result=%d, context=0x%x tag=%d\n",
- 			req, readl(&req->type), readl(&req->result),
- 			readl(&req->context), tag);
-@@ -427,7 +643,7 @@ void hptiop_iop_request_callback(struct hptiop_hba *hba, u32 tag)
- 		arg->result = HPT_IOCTL_RESULT_FAILED;
- 
- 	arg->done(arg);
--	writel(tag, &hba->iop->outbound_queue);
-+	writel(tag, &hba->u.itl.iop->outbound_queue);
- }
+ #ifdef CONFIG_LPFC_DEBUG_FS
+@@ -75,18 +76,18 @@ module_param(lpfc_debugfs_enable, int, 0);
+ MODULE_PARM_DESC(lpfc_debugfs_enable, "Enable debugfs services");
  
- static irqreturn_t hptiop_intr(int irq, void *dev_id)
-@@ -437,7 +653,7 @@ static irqreturn_t hptiop_intr(int irq, void *dev_id)
- 	unsigned long flags;
+ /* This MUST be a power of 2 */
+-static int lpfc_debugfs_max_disc_trc = 0;
++static int lpfc_debugfs_max_disc_trc;
+ module_param(lpfc_debugfs_max_disc_trc, int, 0);
+ MODULE_PARM_DESC(lpfc_debugfs_max_disc_trc,
+ 	"Set debugfs discovery trace depth");
  
- 	spin_lock_irqsave(hba->host->host_lock, flags);
--	handled = __iop_intr(hba);
-+	handled = hba->ops->iop_intr(hba);
- 	spin_unlock_irqrestore(hba->host->host_lock, flags);
+ /* This MUST be a power of 2 */
+-static int lpfc_debugfs_max_slow_ring_trc = 0;
++static int lpfc_debugfs_max_slow_ring_trc;
+ module_param(lpfc_debugfs_max_slow_ring_trc, int, 0);
+ MODULE_PARM_DESC(lpfc_debugfs_max_slow_ring_trc,
+ 	"Set debugfs slow ring trace depth");
  
- 	return handled;
-@@ -469,6 +685,57 @@ static int hptiop_buildsgl(struct scsi_cmnd *scp, struct hpt_iopsg *psg)
- 	return HPT_SCP(scp)->sgcnt;
- }
+-static int lpfc_debugfs_mask_disc_trc = 0;
++int lpfc_debugfs_mask_disc_trc;
+ module_param(lpfc_debugfs_mask_disc_trc, int, 0);
+ MODULE_PARM_DESC(lpfc_debugfs_mask_disc_trc,
+ 	"Set debugfs discovery trace mask");
+@@ -100,8 +101,11 @@ MODULE_PARM_DESC(lpfc_debugfs_mask_disc_trc,
+ #define LPFC_NODELIST_SIZE 8192
+ #define LPFC_NODELIST_ENTRY_SIZE 120
  
-+static void hptiop_post_req_itl(struct hptiop_hba *hba,
-+					struct hptiop_request *_req)
-+{
-+	struct hpt_iop_request_header *reqhdr = _req->req_virt;
-+
-+	reqhdr->context = cpu_to_le32(IOPMU_QUEUE_ADDR_HOST_BIT |
-+							(u32)_req->index);
-+	reqhdr->context_hi32 = 0;
-+
-+	if (hba->iopintf_v2) {
-+		u32 size, size_bits;
-+
-+		size = le32_to_cpu(reqhdr->size);
-+		if (size < 256)
-+			size_bits = IOPMU_QUEUE_REQUEST_SIZE_BIT;
-+		else if (size < 512)
-+			size_bits = IOPMU_QUEUE_ADDR_HOST_BIT;
-+		else
-+			size_bits = IOPMU_QUEUE_REQUEST_SIZE_BIT |
-+						IOPMU_QUEUE_ADDR_HOST_BIT;
-+		writel(_req->req_shifted_phy | size_bits,
-+			&hba->u.itl.iop->inbound_queue);
-+	} else
-+		writel(_req->req_shifted_phy | IOPMU_QUEUE_ADDR_HOST_BIT,
-+					&hba->u.itl.iop->inbound_queue);
-+}
-+
-+static void hptiop_post_req_mv(struct hptiop_hba *hba,
-+					struct hptiop_request *_req)
-+{
-+	struct hpt_iop_request_header *reqhdr = _req->req_virt;
-+	u32 size, size_bit;
-+
-+	reqhdr->context = cpu_to_le32(_req->index<<8 |
-+					IOP_REQUEST_TYPE_SCSI_COMMAND<<5);
-+	reqhdr->context_hi32 = 0;
-+	size = le32_to_cpu(reqhdr->size);
-+
-+	if (size <= 256)
-+		size_bit = 0;
-+	else if (size <= 256*2)
-+		size_bit = 1;
-+	else if (size <= 256*3)
-+		size_bit = 2;
-+	else
-+		size_bit = 3;
-+
-+	mv_inbound_write((_req->req_shifted_phy << 5) |
-+		MVIOP_MU_QUEUE_ADDR_HOST_BIT | size_bit, hba);
-+}
+-/* dumpslim output buffer size */
+-#define LPFC_DUMPSLIM_SIZE 4096
++/* dumpHBASlim output buffer size */
++#define LPFC_DUMPHBASLIM_SIZE 4096
 +
- static int hptiop_queuecommand(struct scsi_cmnd *scp,
- 				void (*done)(struct scsi_cmnd *))
- {
-@@ -518,9 +785,6 @@ static int hptiop_queuecommand(struct scsi_cmnd *scp,
- 	req->header.flags = cpu_to_le32(IOP_REQUEST_FLAG_OUTPUT_CONTEXT);
- 	req->header.type = cpu_to_le32(IOP_REQUEST_TYPE_SCSI_COMMAND);
- 	req->header.result = cpu_to_le32(IOP_RESULT_PENDING);
--	req->header.context = cpu_to_le32(IOPMU_QUEUE_ADDR_HOST_BIT |
--							(u32)_req->index);
--	req->header.context_hi32 = 0;
- 	req->dataxfer_length = cpu_to_le32(scsi_bufflen(scp));
- 	req->channel = scp->device->channel;
- 	req->target = scp->device->id;
-@@ -531,21 +795,7 @@ static int hptiop_queuecommand(struct scsi_cmnd *scp,
- 				 + sg_count * sizeof(struct hpt_iopsg));
++/* dumpHostSlim output buffer size */
++#define LPFC_DUMPHOSTSLIM_SIZE 4096
  
- 	memcpy(req->cdb, scp->cmnd, sizeof(req->cdb));
--
--	if (hba->iopintf_v2) {
--		u32 size_bits;
--		if (req->header.size < 256)
--			size_bits = IOPMU_QUEUE_REQUEST_SIZE_BIT;
--		else if (req->header.size < 512)
--			size_bits = IOPMU_QUEUE_ADDR_HOST_BIT;
--		else
--			size_bits = IOPMU_QUEUE_REQUEST_SIZE_BIT |
--						IOPMU_QUEUE_ADDR_HOST_BIT;
--		writel(_req->req_shifted_phy | size_bits, &hba->iop->inbound_queue);
--	} else
--		writel(_req->req_shifted_phy | IOPMU_QUEUE_ADDR_HOST_BIT,
--					&hba->iop->inbound_queue);
--
-+	hba->ops->post_req(hba, _req);
- 	return 0;
+ /* hbqinfo output buffer size */
+ #define LPFC_HBQINFO_SIZE 8192
+@@ -243,16 +247,17 @@ lpfc_debugfs_hbqinfo_data(struct lpfc_hba *phba, char *buf, int size)
+ 	raw_index = phba->hbq_get[i];
+ 	getidx = le32_to_cpu(raw_index);
+ 	len +=  snprintf(buf+len, size-len,
+-		"entrys:%d Put:%d nPut:%d localGet:%d hbaGet:%d\n",
+-		hbqs->entry_count, hbqs->hbqPutIdx, hbqs->next_hbqPutIdx,
+-		hbqs->local_hbqGetIdx, getidx);
++		"entrys:%d bufcnt:%d Put:%d nPut:%d localGet:%d hbaGet:%d\n",
++		hbqs->entry_count, hbqs->buffer_count, hbqs->hbqPutIdx,
++		hbqs->next_hbqPutIdx, hbqs->local_hbqGetIdx, getidx);
  
- cmd_done:
-@@ -563,9 +813,7 @@ static int hptiop_reset_hba(struct hptiop_hba *hba)
- {
- 	if (atomic_xchg(&hba->resetting, 1) == 0) {
- 		atomic_inc(&hba->reset_count);
--		writel(IOPMU_INBOUND_MSG0_RESET,
--				&hba->iop->inbound_msgaddr0);
--		hptiop_pci_posting_flush(hba->iop);
-+		hba->ops->post_msg(hba, IOPMU_INBOUND_MSG0_RESET);
- 	}
+ 	hbqe = (struct lpfc_hbq_entry *) phba->hbqs[i].hbq_virt;
+ 	for (j=0; j<hbqs->entry_count; j++) {
+ 		len +=  snprintf(buf+len, size-len,
+ 			"%03d: %08x %04x %05x ", j,
+-			hbqe->bde.addrLow, hbqe->bde.tus.w, hbqe->buffer_tag);
+-
++			le32_to_cpu(hbqe->bde.addrLow),
++			le32_to_cpu(hbqe->bde.tus.w),
++			le32_to_cpu(hbqe->buffer_tag));
+ 		i = 0;
+ 		found = 0;
  
- 	wait_event_timeout(hba->reset_wq,
-@@ -601,8 +849,10 @@ static int hptiop_reset(struct scsi_cmnd *scp)
- static int hptiop_adjust_disk_queue_depth(struct scsi_device *sdev,
- 						int queue_depth)
- {
--	if(queue_depth > 256)
--		queue_depth = 256;
-+	struct hptiop_hba *hba = (struct hptiop_hba *)sdev->host->hostdata;
-+
-+	if (queue_depth > hba->max_requests)
-+		queue_depth = hba->max_requests;
- 	scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, queue_depth);
- 	return queue_depth;
+@@ -276,7 +281,7 @@ lpfc_debugfs_hbqinfo_data(struct lpfc_hba *phba, char *buf, int size)
+ 		list_for_each_entry(d_buf, &hbqs->hbq_buffer_list, list) {
+ 			hbq_buf = container_of(d_buf, struct hbq_dmabuf, dbuf);
+ 			phys = ((uint64_t)hbq_buf->dbuf.phys & 0xffffffff);
+-			if (phys == hbqe->bde.addrLow) {
++			if (phys == le32_to_cpu(hbqe->bde.addrLow)) {
+ 				len +=  snprintf(buf+len, size-len,
+ 					"Buf%d: %p %06x\n", i,
+ 					hbq_buf->dbuf.virt, hbq_buf->tag);
+@@ -297,18 +302,58 @@ skipit:
+ 	return len;
  }
-@@ -663,6 +913,26 @@ static struct scsi_host_template driver_template = {
- 	.change_queue_depth         = hptiop_adjust_disk_queue_depth,
- };
  
-+static int hptiop_internal_memalloc_mv(struct hptiop_hba *hba)
++static int lpfc_debugfs_last_hba_slim_off;
++
++static int
++lpfc_debugfs_dumpHBASlim_data(struct lpfc_hba *phba, char *buf, int size)
 +{
-+	hba->u.mv.internal_req = dma_alloc_coherent(&hba->pcidev->dev,
-+			0x800, &hba->u.mv.internal_req_phy, GFP_KERNEL);
-+	if (hba->u.mv.internal_req)
-+		return 0;
-+	else
-+		return -1;
++	int len = 0;
++	int i, off;
++	uint32_t *ptr;
++	char buffer[1024];
++
++	off = 0;
++	spin_lock_irq(&phba->hbalock);
++
++	len +=  snprintf(buf+len, size-len, "HBA SLIM\n");
++	lpfc_memcpy_from_slim(buffer,
++		((uint8_t *)phba->MBslimaddr) + lpfc_debugfs_last_hba_slim_off,
++		1024);
++
++	ptr = (uint32_t *)&buffer[0];
++	off = lpfc_debugfs_last_hba_slim_off;
++
++	/* Set it up for the next time */
++	lpfc_debugfs_last_hba_slim_off += 1024;
++	if (lpfc_debugfs_last_hba_slim_off >= 4096)
++		lpfc_debugfs_last_hba_slim_off = 0;
++
++	i = 1024;
++	while (i > 0) {
++		len +=  snprintf(buf+len, size-len,
++		"%08x: %08x %08x %08x %08x %08x %08x %08x %08x\n",
++		off, *ptr, *(ptr+1), *(ptr+2), *(ptr+3), *(ptr+4),
++		*(ptr+5), *(ptr+6), *(ptr+7));
++		ptr += 8;
++		i -= (8 * sizeof(uint32_t));
++		off += (8 * sizeof(uint32_t));
++	}
++
++	spin_unlock_irq(&phba->hbalock);
++	return len;
 +}
 +
-+static int hptiop_internal_memfree_mv(struct hptiop_hba *hba)
+ static int
+-lpfc_debugfs_dumpslim_data(struct lpfc_hba *phba, char *buf, int size)
++lpfc_debugfs_dumpHostSlim_data(struct lpfc_hba *phba, char *buf, int size)
+ {
+ 	int len = 0;
+-	int cnt, i, off;
++	int i, off;
+ 	uint32_t word0, word1, word2, word3;
+ 	uint32_t *ptr;
+ 	struct lpfc_pgp *pgpp;
+ 	struct lpfc_sli *psli = &phba->sli;
+ 	struct lpfc_sli_ring *pring;
+ 
+-	cnt = LPFC_DUMPSLIM_SIZE;
+ 	off = 0;
+ 	spin_lock_irq(&phba->hbalock);
+ 
+@@ -620,7 +665,34 @@ out:
+ }
+ 
+ static int
+-lpfc_debugfs_dumpslim_open(struct inode *inode, struct file *file)
++lpfc_debugfs_dumpHBASlim_open(struct inode *inode, struct file *file)
 +{
-+	if (hba->u.mv.internal_req) {
-+		dma_free_coherent(&hba->pcidev->dev, 0x800,
-+			hba->u.mv.internal_req, hba->u.mv.internal_req_phy);
-+		return 0;
-+	} else
-+		return -1;
++	struct lpfc_hba *phba = inode->i_private;
++	struct lpfc_debug *debug;
++	int rc = -ENOMEM;
++
++	debug = kmalloc(sizeof(*debug), GFP_KERNEL);
++	if (!debug)
++		goto out;
++
++	/* Round to page boundry */
++	debug->buffer = kmalloc(LPFC_DUMPHBASLIM_SIZE, GFP_KERNEL);
++	if (!debug->buffer) {
++		kfree(debug);
++		goto out;
++	}
++
++	debug->len = lpfc_debugfs_dumpHBASlim_data(phba, debug->buffer,
++		LPFC_DUMPHBASLIM_SIZE);
++	file->private_data = debug;
++
++	rc = 0;
++out:
++	return rc;
 +}
 +
- static int __devinit hptiop_probe(struct pci_dev *pcidev,
- 					const struct pci_device_id *id)
++static int
++lpfc_debugfs_dumpHostSlim_open(struct inode *inode, struct file *file)
  {
-@@ -708,6 +978,7 @@ static int __devinit hptiop_probe(struct pci_dev *pcidev,
+ 	struct lpfc_hba *phba = inode->i_private;
+ 	struct lpfc_debug *debug;
+@@ -631,14 +703,14 @@ lpfc_debugfs_dumpslim_open(struct inode *inode, struct file *file)
+ 		goto out;
  
- 	hba = (struct hptiop_hba *)host->hostdata;
+ 	/* Round to page boundry */
+-	debug->buffer = kmalloc(LPFC_DUMPSLIM_SIZE, GFP_KERNEL);
++	debug->buffer = kmalloc(LPFC_DUMPHOSTSLIM_SIZE, GFP_KERNEL);
+ 	if (!debug->buffer) {
+ 		kfree(debug);
+ 		goto out;
+ 	}
  
-+	hba->ops = (struct hptiop_adapter_ops *)id->driver_data;
- 	hba->pcidev = pcidev;
- 	hba->host = host;
- 	hba->initialized = 0;
-@@ -725,16 +996,24 @@ static int __devinit hptiop_probe(struct pci_dev *pcidev,
- 	host->n_io_port = 0;
- 	host->irq = pcidev->irq;
+-	debug->len = lpfc_debugfs_dumpslim_data(phba, debug->buffer,
+-		LPFC_DUMPSLIM_SIZE);
++	debug->len = lpfc_debugfs_dumpHostSlim_data(phba, debug->buffer,
++		LPFC_DUMPHOSTSLIM_SIZE);
+ 	file->private_data = debug;
  
--	if (hptiop_map_pci_bar(hba))
-+	if (hba->ops->map_pci_bar(hba))
- 		goto free_scsi_host;
+ 	rc = 0;
+@@ -741,10 +813,19 @@ static struct file_operations lpfc_debugfs_op_hbqinfo = {
+ 	.release =      lpfc_debugfs_release,
+ };
  
--	if (iop_wait_ready(hba->iop, 20000)) {
-+	if (hba->ops->iop_wait_ready(hba, 20000)) {
- 		printk(KERN_ERR "scsi%d: firmware not ready\n",
- 				hba->host->host_no);
- 		goto unmap_pci_bar;
- 	}
+-#undef lpfc_debugfs_op_dumpslim
+-static struct file_operations lpfc_debugfs_op_dumpslim = {
++#undef lpfc_debugfs_op_dumpHBASlim
++static struct file_operations lpfc_debugfs_op_dumpHBASlim = {
++	.owner =        THIS_MODULE,
++	.open =         lpfc_debugfs_dumpHBASlim_open,
++	.llseek =       lpfc_debugfs_lseek,
++	.read =         lpfc_debugfs_read,
++	.release =      lpfc_debugfs_release,
++};
++
++#undef lpfc_debugfs_op_dumpHostSlim
++static struct file_operations lpfc_debugfs_op_dumpHostSlim = {
+ 	.owner =        THIS_MODULE,
+-	.open =         lpfc_debugfs_dumpslim_open,
++	.open =         lpfc_debugfs_dumpHostSlim_open,
+ 	.llseek =       lpfc_debugfs_lseek,
+ 	.read =         lpfc_debugfs_read,
+ 	.release =      lpfc_debugfs_release,
+@@ -812,15 +893,27 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport)
+ 			goto debug_failed;
+ 		}
  
--	if (iop_get_config(hba, &iop_config)) {
-+	if (hba->ops->internal_memalloc) {
-+		if (hba->ops->internal_memalloc(hba)) {
-+			printk(KERN_ERR "scsi%d: internal_memalloc failed\n",
-+				hba->host->host_no);
-+			goto unmap_pci_bar;
+-		/* Setup dumpslim */
+-		snprintf(name, sizeof(name), "dumpslim");
+-		phba->debug_dumpslim =
++		/* Setup dumpHBASlim */
++		snprintf(name, sizeof(name), "dumpHBASlim");
++		phba->debug_dumpHBASlim =
++			debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR,
++				 phba->hba_debugfs_root,
++				 phba, &lpfc_debugfs_op_dumpHBASlim);
++		if (!phba->debug_dumpHBASlim) {
++			lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
++				"0409 Cannot create debugfs dumpHBASlim\n");
++			goto debug_failed;
 +		}
-+	}
 +
-+	if (hba->ops->get_config(hba, &iop_config)) {
- 		printk(KERN_ERR "scsi%d: get config failed\n",
- 				hba->host->host_no);
- 		goto unmap_pci_bar;
-@@ -770,7 +1049,7 @@ static int __devinit hptiop_probe(struct pci_dev *pcidev,
- 	set_config.vbus_id = cpu_to_le16(host->host_no);
- 	set_config.max_host_request_size = cpu_to_le16(req_size);
++		/* Setup dumpHostSlim */
++		snprintf(name, sizeof(name), "dumpHostSlim");
++		phba->debug_dumpHostSlim =
+ 			debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR,
+ 				 phba->hba_debugfs_root,
+-				 phba, &lpfc_debugfs_op_dumpslim);
+-		if (!phba->debug_dumpslim) {
++				 phba, &lpfc_debugfs_op_dumpHostSlim);
++		if (!phba->debug_dumpHostSlim) {
+ 			lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
+-				"0409 Cannot create debugfs dumpslim\n");
++				"0409 Cannot create debugfs dumpHostSlim\n");
+ 			goto debug_failed;
+ 		}
  
--	if (iop_set_config(hba, &set_config)) {
-+	if (hba->ops->set_config(hba, &set_config)) {
- 		printk(KERN_ERR "scsi%d: set config failed\n",
- 				hba->host->host_no);
- 		goto unmap_pci_bar;
-@@ -839,21 +1118,24 @@ static int __devinit hptiop_probe(struct pci_dev *pcidev,
+@@ -970,9 +1063,13 @@ lpfc_debugfs_terminate(struct lpfc_vport *vport)
+ 			debugfs_remove(phba->debug_hbqinfo); /* hbqinfo */
+ 			phba->debug_hbqinfo = NULL;
+ 		}
+-		if (phba->debug_dumpslim) {
+-			debugfs_remove(phba->debug_dumpslim); /* dumpslim */
+-			phba->debug_dumpslim = NULL;
++		if (phba->debug_dumpHBASlim) {
++			debugfs_remove(phba->debug_dumpHBASlim); /* HBASlim */
++			phba->debug_dumpHBASlim = NULL;
++		}
++		if (phba->debug_dumpHostSlim) {
++			debugfs_remove(phba->debug_dumpHostSlim); /* HostSlim */
++			phba->debug_dumpHostSlim = NULL;
+ 		}
+ 		if (phba->slow_ring_trc) {
+ 			kfree(phba->slow_ring_trc);
+diff --git a/drivers/scsi/lpfc/lpfc_disc.h b/drivers/scsi/lpfc/lpfc_disc.h
+index aacac9a..cfe81c5 100644
+--- a/drivers/scsi/lpfc/lpfc_disc.h
++++ b/drivers/scsi/lpfc/lpfc_disc.h
+@@ -36,7 +36,6 @@ enum lpfc_work_type {
+ 	LPFC_EVT_WARM_START,
+ 	LPFC_EVT_KILL,
+ 	LPFC_EVT_ELS_RETRY,
+-	LPFC_EVT_DEV_LOSS_DELAY,
+ 	LPFC_EVT_DEV_LOSS,
+ };
  
- free_request_mem:
- 	dma_free_coherent(&hba->pcidev->dev,
--			hba->req_size*hba->max_requests + 0x20,
-+			hba->req_size * hba->max_requests + 0x20,
- 			hba->dma_coherent, hba->dma_coherent_handle);
+@@ -92,6 +91,7 @@ struct lpfc_nodelist {
+ #define NLP_LOGO_SND       0x100	/* sent LOGO request for this entry */
+ #define NLP_RNID_SND       0x400	/* sent RNID request for this entry */
+ #define NLP_ELS_SND_MASK   0x7e0	/* sent ELS request for this entry */
++#define NLP_DEFER_RM       0x10000	/* Remove this ndlp if no longer used */
+ #define NLP_DELAY_TMO      0x20000	/* delay timeout is running for node */
+ #define NLP_NPR_2B_DISC    0x40000	/* node is included in num_disc_nodes */
+ #define NLP_RCV_PLOGI      0x80000	/* Rcv'ed PLOGI from remote system */
+diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c
+index 8085900..c6b739d 100644
+--- a/drivers/scsi/lpfc/lpfc_els.c
++++ b/drivers/scsi/lpfc/lpfc_els.c
+@@ -18,7 +18,7 @@
+  * more details, a copy of which can be found in the file COPYING  *
+  * included with this package.                                     *
+  *******************************************************************/
+-
++/* See Fibre Channel protocol T11 FC-LS for details */
+ #include <linux/blkdev.h>
+ #include <linux/pci.h>
+ #include <linux/interrupt.h>
+@@ -42,6 +42,14 @@ static int lpfc_els_retry(struct lpfc_hba *, struct lpfc_iocbq *,
+ 			  struct lpfc_iocbq *);
+ static void lpfc_cmpl_fabric_iocb(struct lpfc_hba *, struct lpfc_iocbq *,
+ 			struct lpfc_iocbq *);
++static void lpfc_fabric_abort_vport(struct lpfc_vport *vport);
++static int lpfc_issue_els_fdisc(struct lpfc_vport *vport,
++				struct lpfc_nodelist *ndlp, uint8_t retry);
++static int lpfc_issue_fabric_iocb(struct lpfc_hba *phba,
++				  struct lpfc_iocbq *iocb);
++static void lpfc_register_new_vport(struct lpfc_hba *phba,
++				    struct lpfc_vport *vport,
++				    struct lpfc_nodelist *ndlp);
  
- free_request_irq:
- 	free_irq(hba->pcidev->irq, hba);
+ static int lpfc_max_els_tries = 3;
  
- unmap_pci_bar:
--	iounmap(hba->iop);
-+	if (hba->ops->internal_memfree)
-+		hba->ops->internal_memfree(hba);
+@@ -109,14 +117,11 @@ lpfc_prep_els_iocb(struct lpfc_vport *vport, uint8_t expectRsp,
  
--free_pci_regions:
--	pci_release_regions(pcidev) ;
-+	hba->ops->unmap_pci_bar(hba);
+ 	/* fill in BDEs for command */
+ 	/* Allocate buffer for command payload */
+-	if (((pcmd = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL)) == 0) ||
+-	    ((pcmd->virt = lpfc_mbuf_alloc(phba,
+-					   MEM_PRI, &(pcmd->phys))) == 0)) {
+-		kfree(pcmd);
+-
+-		lpfc_sli_release_iocbq(phba, elsiocb);
+-		return NULL;
+-	}
++	pcmd = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
++	if (pcmd)
++		pcmd->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &pcmd->phys);
++	if (!pcmd || !pcmd->virt)
++		goto els_iocb_free_pcmb_exit;
  
- free_scsi_host:
- 	scsi_host_put(host);
+ 	INIT_LIST_HEAD(&pcmd->list);
  
-+free_pci_regions:
-+	pci_release_regions(pcidev);
-+
- disable_pci_device:
- 	pci_disable_device(pcidev);
+@@ -126,13 +131,8 @@ lpfc_prep_els_iocb(struct lpfc_vport *vport, uint8_t expectRsp,
+ 		if (prsp)
+ 			prsp->virt = lpfc_mbuf_alloc(phba, MEM_PRI,
+ 						     &prsp->phys);
+-		if (prsp == 0 || prsp->virt == 0) {
+-			kfree(prsp);
+-			lpfc_mbuf_free(phba, pcmd->virt, pcmd->phys);
+-			kfree(pcmd);
+-			lpfc_sli_release_iocbq(phba, elsiocb);
+-			return NULL;
+-		}
++		if (!prsp || !prsp->virt)
++			goto els_iocb_free_prsp_exit;
+ 		INIT_LIST_HEAD(&prsp->list);
+ 	} else {
+ 		prsp = NULL;
+@@ -143,15 +143,8 @@ lpfc_prep_els_iocb(struct lpfc_vport *vport, uint8_t expectRsp,
+ 	if (pbuflist)
+ 		pbuflist->virt = lpfc_mbuf_alloc(phba, MEM_PRI,
+ 						 &pbuflist->phys);
+-	if (pbuflist == 0 || pbuflist->virt == 0) {
+-		lpfc_sli_release_iocbq(phba, elsiocb);
+-		lpfc_mbuf_free(phba, pcmd->virt, pcmd->phys);
+-		lpfc_mbuf_free(phba, prsp->virt, prsp->phys);
+-		kfree(pcmd);
+-		kfree(prsp);
+-		kfree(pbuflist);
+-		return NULL;
+-	}
++	if (!pbuflist || !pbuflist->virt)
++		goto els_iocb_free_pbuf_exit;
  
-@@ -865,8 +1147,6 @@ static void hptiop_shutdown(struct pci_dev *pcidev)
- {
- 	struct Scsi_Host *host = pci_get_drvdata(pcidev);
- 	struct hptiop_hba *hba = (struct hptiop_hba *)host->hostdata;
--	struct hpt_iopmu __iomem *iop = hba->iop;
--	u32    int_mask;
+ 	INIT_LIST_HEAD(&pbuflist->list);
  
- 	dprintk("hptiop_shutdown(%p)\n", hba);
+@@ -196,7 +189,10 @@ lpfc_prep_els_iocb(struct lpfc_vport *vport, uint8_t expectRsp,
+ 		bpl->tus.w = le32_to_cpu(bpl->tus.w);
+ 	}
  
-@@ -876,11 +1156,24 @@ static void hptiop_shutdown(struct pci_dev *pcidev)
- 					hba->host->host_no);
++	/* prevent preparing iocb with NULL ndlp reference */
+ 	elsiocb->context1 = lpfc_nlp_get(ndlp);
++	if (!elsiocb->context1)
++		goto els_iocb_free_pbuf_exit;
+ 	elsiocb->context2 = pcmd;
+ 	elsiocb->context3 = pbuflist;
+ 	elsiocb->retry = retry;
+@@ -222,8 +218,20 @@ lpfc_prep_els_iocb(struct lpfc_vport *vport, uint8_t expectRsp,
+ 				 cmdSize);
+ 	}
+ 	return elsiocb;
+-}
  
- 	/* disable all outbound interrupts */
--	int_mask = readl(&iop->outbound_intmask);
-+	hba->ops->disable_intr(hba);
-+}
++els_iocb_free_pbuf_exit:
++	lpfc_mbuf_free(phba, prsp->virt, prsp->phys);
++	kfree(pbuflist);
 +
-+static void hptiop_disable_intr_itl(struct hptiop_hba *hba)
-+{
-+	u32 int_mask;
++els_iocb_free_prsp_exit:
++	lpfc_mbuf_free(phba, pcmd->virt, pcmd->phys);
++	kfree(prsp);
 +
-+	int_mask = readl(&hba->u.itl.iop->outbound_intmask);
- 	writel(int_mask |
- 		IOPMU_OUTBOUND_INT_MSG0 | IOPMU_OUTBOUND_INT_POSTQUEUE,
--		&iop->outbound_intmask);
--	hptiop_pci_posting_flush(iop);
-+		&hba->u.itl.iop->outbound_intmask);
-+	readl(&hba->u.itl.iop->outbound_intmask);
++els_iocb_free_pcmb_exit:
++	kfree(pcmd);
++	lpfc_sli_release_iocbq(phba, elsiocb);
++	return NULL;
 +}
-+
-+static void hptiop_disable_intr_mv(struct hptiop_hba *hba)
-+{
-+	writel(0, &hba->u.mv.regs->outbound_intmask);
-+	readl(&hba->u.mv.regs->outbound_intmask);
- }
- 
- static void hptiop_remove(struct pci_dev *pcidev)
-@@ -901,7 +1194,10 @@ static void hptiop_remove(struct pci_dev *pcidev)
- 			hba->dma_coherent,
- 			hba->dma_coherent_handle);
- 
--	iounmap(hba->iop);
-+	if (hba->ops->internal_memfree)
-+		hba->ops->internal_memfree(hba);
-+
-+	hba->ops->unmap_pci_bar(hba);
  
- 	pci_release_regions(hba->pcidev);
- 	pci_set_drvdata(hba->pcidev, NULL);
-@@ -910,11 +1206,50 @@ static void hptiop_remove(struct pci_dev *pcidev)
- 	scsi_host_put(host);
- }
+ static int
+ lpfc_issue_fabric_reglogin(struct lpfc_vport *vport)
+@@ -234,40 +242,53 @@ lpfc_issue_fabric_reglogin(struct lpfc_vport *vport)
+ 	struct lpfc_nodelist *ndlp;
+ 	struct serv_parm *sp;
+ 	int rc;
++	int err = 0;
  
-+static struct hptiop_adapter_ops hptiop_itl_ops = {
-+	.iop_wait_ready    = iop_wait_ready_itl,
-+	.internal_memalloc = 0,
-+	.internal_memfree  = 0,
-+	.map_pci_bar       = hptiop_map_pci_bar_itl,
-+	.unmap_pci_bar     = hptiop_unmap_pci_bar_itl,
-+	.enable_intr       = hptiop_enable_intr_itl,
-+	.disable_intr      = hptiop_disable_intr_itl,
-+	.get_config        = iop_get_config_itl,
-+	.set_config        = iop_set_config_itl,
-+	.iop_intr          = iop_intr_itl,
-+	.post_msg          = hptiop_post_msg_itl,
-+	.post_req          = hptiop_post_req_itl,
-+};
-+
-+static struct hptiop_adapter_ops hptiop_mv_ops = {
-+	.iop_wait_ready    = iop_wait_ready_mv,
-+	.internal_memalloc = hptiop_internal_memalloc_mv,
-+	.internal_memfree  = hptiop_internal_memfree_mv,
-+	.map_pci_bar       = hptiop_map_pci_bar_mv,
-+	.unmap_pci_bar     = hptiop_unmap_pci_bar_mv,
-+	.enable_intr       = hptiop_enable_intr_mv,
-+	.disable_intr      = hptiop_disable_intr_mv,
-+	.get_config        = iop_get_config_mv,
-+	.set_config        = iop_set_config_mv,
-+	.iop_intr          = iop_intr_mv,
-+	.post_msg          = hptiop_post_msg_mv,
-+	.post_req          = hptiop_post_req_mv,
-+};
-+
- static struct pci_device_id hptiop_id_table[] = {
--	{ PCI_VDEVICE(TTI, 0x3220) },
--	{ PCI_VDEVICE(TTI, 0x3320) },
--	{ PCI_VDEVICE(TTI, 0x3520) },
--	{ PCI_VDEVICE(TTI, 0x4320) },
-+	{ PCI_VDEVICE(TTI, 0x3220), (kernel_ulong_t)&hptiop_itl_ops },
-+	{ PCI_VDEVICE(TTI, 0x3320), (kernel_ulong_t)&hptiop_itl_ops },
-+	{ PCI_VDEVICE(TTI, 0x3520), (kernel_ulong_t)&hptiop_itl_ops },
-+	{ PCI_VDEVICE(TTI, 0x4320), (kernel_ulong_t)&hptiop_itl_ops },
-+	{ PCI_VDEVICE(TTI, 0x3510), (kernel_ulong_t)&hptiop_itl_ops },
-+	{ PCI_VDEVICE(TTI, 0x3511), (kernel_ulong_t)&hptiop_itl_ops },
-+	{ PCI_VDEVICE(TTI, 0x3521), (kernel_ulong_t)&hptiop_itl_ops },
-+	{ PCI_VDEVICE(TTI, 0x3522), (kernel_ulong_t)&hptiop_itl_ops },
-+	{ PCI_VDEVICE(TTI, 0x3410), (kernel_ulong_t)&hptiop_itl_ops },
-+	{ PCI_VDEVICE(TTI, 0x3540), (kernel_ulong_t)&hptiop_itl_ops },
-+	{ PCI_VDEVICE(TTI, 0x3120), (kernel_ulong_t)&hptiop_mv_ops },
-+	{ PCI_VDEVICE(TTI, 0x3122), (kernel_ulong_t)&hptiop_mv_ops },
-+	{ PCI_VDEVICE(TTI, 0x3020), (kernel_ulong_t)&hptiop_mv_ops },
- 	{},
- };
+ 	sp = &phba->fc_fabparam;
+ 	ndlp = lpfc_findnode_did(vport, Fabric_DID);
+-	if (!ndlp)
++	if (!ndlp) {
++		err = 1;
+ 		goto fail;
++	}
  
-diff --git a/drivers/scsi/hptiop.h b/drivers/scsi/hptiop.h
-index 2a5e46e..a0289f2 100644
---- a/drivers/scsi/hptiop.h
-+++ b/drivers/scsi/hptiop.h
-@@ -1,5 +1,5 @@
- /*
-- * HighPoint RR3xxx controller driver for Linux
-+ * HighPoint RR3xxx/4xxx controller driver for Linux
-  * Copyright (C) 2006-2007 HighPoint Technologies, Inc. All Rights Reserved.
-  *
-  * This program is free software; you can redistribute it and/or modify
-@@ -18,8 +18,7 @@
- #ifndef _HPTIOP_H_
- #define _HPTIOP_H_
+ 	mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+-	if (!mbox)
++	if (!mbox) {
++		err = 2;
+ 		goto fail;
++	}
  
--struct hpt_iopmu
--{
-+struct hpt_iopmu_itl {
- 	__le32 resrved0[4];
- 	__le32 inbound_msgaddr0;
- 	__le32 inbound_msgaddr1;
-@@ -54,6 +53,40 @@ struct hpt_iopmu
- #define IOPMU_INBOUND_INT_ERROR      8
- #define IOPMU_INBOUND_INT_POSTQUEUE  0x10
+ 	vport->port_state = LPFC_FABRIC_CFG_LINK;
+ 	lpfc_config_link(phba, mbox);
+ 	mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+ 	mbox->vport = vport;
  
-+#define MVIOP_QUEUE_LEN  512
-+
-+struct hpt_iopmu_mv {
-+	__le32 inbound_head;
-+	__le32 inbound_tail;
-+	__le32 outbound_head;
-+	__le32 outbound_tail;
-+	__le32 inbound_msg;
-+	__le32 outbound_msg;
-+	__le32 reserve[10];
-+	__le64 inbound_q[MVIOP_QUEUE_LEN];
-+	__le64 outbound_q[MVIOP_QUEUE_LEN];
-+};
-+
-+struct hpt_iopmv_regs {
-+	__le32 reserved[0x20400 / 4];
-+	__le32 inbound_doorbell;
-+	__le32 inbound_intmask;
-+	__le32 outbound_doorbell;
-+	__le32 outbound_intmask;
-+};
-+
-+#define MVIOP_MU_QUEUE_ADDR_HOST_MASK   (~(0x1full))
-+#define MVIOP_MU_QUEUE_ADDR_HOST_BIT    4
-+
-+#define MVIOP_MU_QUEUE_ADDR_IOP_HIGH32  0xffffffff
-+#define MVIOP_MU_QUEUE_REQUEST_RESULT_BIT   1
-+#define MVIOP_MU_QUEUE_REQUEST_RETURN_CONTEXT 2
-+
-+#define MVIOP_MU_INBOUND_INT_MSG        1
-+#define MVIOP_MU_INBOUND_INT_POSTQUEUE  2
-+#define MVIOP_MU_OUTBOUND_INT_MSG       1
-+#define MVIOP_MU_OUTBOUND_INT_POSTQUEUE 2
-+
- enum hpt_iopmu_message {
- 	/* host-to-iop messages */
- 	IOPMU_INBOUND_MSG0_NOP = 0,
-@@ -72,8 +105,7 @@ enum hpt_iopmu_message {
- 	IOPMU_OUTBOUND_MSG0_REVALIDATE_DEVICE_MAX = 0x3ff,
- };
+-	rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT | MBX_STOP_IOCB);
+-	if (rc == MBX_NOT_FINISHED)
++	rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
++	if (rc == MBX_NOT_FINISHED) {
++		err = 3;
+ 		goto fail_free_mbox;
++	}
  
--struct hpt_iop_request_header
--{
-+struct hpt_iop_request_header {
- 	__le32 size;
- 	__le32 type;
- 	__le32 flags;
-@@ -104,11 +136,10 @@ enum hpt_iop_result_type {
- 	IOP_RESULT_RESET,
- 	IOP_RESULT_INVALID_REQUEST,
- 	IOP_RESULT_BAD_TARGET,
--	IOP_RESULT_MODE_SENSE_CHECK_CONDITION,
-+	IOP_RESULT_CHECK_CONDITION,
- };
+ 	mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+-	if (!mbox)
++	if (!mbox) {
++		err = 4;
+ 		goto fail;
++	}
+ 	rc = lpfc_reg_login(phba, vport->vpi, Fabric_DID, (uint8_t *)sp, mbox,
+ 			    0);
+-	if (rc)
++	if (rc) {
++		err = 5;
+ 		goto fail_free_mbox;
++	}
  
--struct hpt_iop_request_get_config
--{
-+struct hpt_iop_request_get_config {
- 	struct hpt_iop_request_header header;
- 	__le32 interface_version;
- 	__le32 firmware_version;
-@@ -121,8 +152,7 @@ struct hpt_iop_request_get_config
- 	__le32 sdram_size;
- };
+ 	mbox->mbox_cmpl = lpfc_mbx_cmpl_fabric_reg_login;
+ 	mbox->vport = vport;
+ 	mbox->context2 = lpfc_nlp_get(ndlp);
  
--struct hpt_iop_request_set_config
--{
-+struct hpt_iop_request_set_config {
- 	struct hpt_iop_request_header header;
- 	__le32 iop_id;
- 	__le16 vbus_id;
-@@ -130,15 +160,13 @@ struct hpt_iop_request_set_config
- 	__le32 reserve[6];
- };
+-	rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT | MBX_STOP_IOCB);
+-	if (rc == MBX_NOT_FINISHED)
++	rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
++	if (rc == MBX_NOT_FINISHED) {
++		err = 6;
+ 		goto fail_issue_reg_login;
++	}
  
--struct hpt_iopsg
--{
-+struct hpt_iopsg {
- 	__le32 size;
- 	__le32 eot; /* non-zero: end of table */
- 	__le64 pci_address;
- };
+ 	return 0;
  
--struct hpt_iop_request_block_command
--{
-+struct hpt_iop_request_block_command {
- 	struct hpt_iop_request_header header;
- 	u8     channel;
- 	u8     target;
-@@ -156,8 +184,7 @@ struct hpt_iop_request_block_command
- #define IOP_BLOCK_COMMAND_FLUSH    4
- #define IOP_BLOCK_COMMAND_SHUTDOWN 5
+@@ -282,7 +303,7 @@ fail_free_mbox:
+ fail:
+ 	lpfc_vport_set_state(vport, FC_VPORT_FAILED);
+ 	lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+-		"0249 Cannot issue Register Fabric login\n");
++		"0249 Cannot issue Register Fabric login: Err %d\n", err);
+ 	return -ENXIO;
+ }
  
--struct hpt_iop_request_scsi_command
--{
-+struct hpt_iop_request_scsi_command {
- 	struct hpt_iop_request_header header;
- 	u8     channel;
- 	u8     target;
-@@ -168,8 +195,7 @@ struct hpt_iop_request_scsi_command
- 	struct hpt_iopsg sg_list[1];
- };
+@@ -370,11 +391,12 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ 		}
+ 		if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) {
+ 			lpfc_mbx_unreg_vpi(vport);
++			spin_lock_irq(shost->host_lock);
+ 			vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
++			spin_unlock_irq(shost->host_lock);
+ 		}
+ 	}
  
--struct hpt_iop_request_ioctl_command
--{
-+struct hpt_iop_request_ioctl_command {
- 	struct hpt_iop_request_header header;
- 	__le32 ioctl_code;
- 	__le32 inbuf_size;
-@@ -182,11 +208,11 @@ struct hpt_iop_request_ioctl_command
- #define HPTIOP_MAX_REQUESTS  256u
+-	ndlp->nlp_sid = irsp->un.ulpWord[4] & Mask_DID;
+ 	lpfc_nlp_set_state(vport, ndlp, NLP_STE_REG_LOGIN_ISSUE);
  
- struct hptiop_request {
--	struct hptiop_request * next;
--	void *                  req_virt;
--	u32                     req_shifted_phy;
--	struct scsi_cmnd *      scp;
--	int                     index;
-+	struct hptiop_request *next;
-+	void                  *req_virt;
-+	u32                   req_shifted_phy;
-+	struct scsi_cmnd      *scp;
-+	int                   index;
- };
+ 	if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED &&
+@@ -429,8 +451,7 @@ lpfc_cmpl_els_flogi_nport(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
  
- struct hpt_scsi_pointer {
-@@ -198,9 +224,21 @@ struct hpt_scsi_pointer {
- #define HPT_SCP(scp) ((struct hpt_scsi_pointer *)&(scp)->SCp)
+ 		mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+ 		mbox->vport = vport;
+-		rc = lpfc_sli_issue_mbox(phba, mbox,
+-					 MBX_NOWAIT | MBX_STOP_IOCB);
++		rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
+ 		if (rc == MBX_NOT_FINISHED) {
+ 			mempool_free(mbox, phba->mbox_mem_pool);
+ 			goto fail;
+@@ -463,6 +484,9 @@ lpfc_cmpl_els_flogi_nport(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ 		lpfc_nlp_put(ndlp);
+ 	}
  
- struct hptiop_hba {
--	struct hpt_iopmu __iomem * iop;
--	struct Scsi_Host * host;
--	struct pci_dev * pcidev;
-+	struct hptiop_adapter_ops *ops;
-+	union {
-+		struct {
-+			struct hpt_iopmu_itl __iomem *iop;
-+		} itl;
-+		struct {
-+			struct hpt_iopmv_regs *regs;
-+			struct hpt_iopmu_mv __iomem *mu;
-+			void *internal_req;
-+			dma_addr_t internal_req_phy;
-+		} mv;
-+	} u;
++	/* If we are pt2pt with another NPort, force NPIV off! */
++	phba->sli3_options &= ~LPFC_SLI3_NPIV_ENABLED;
 +
-+	struct Scsi_Host *host;
-+	struct pci_dev *pcidev;
+ 	spin_lock_irq(shost->host_lock);
+ 	vport->fc_flag |= FC_PT2PT;
+ 	spin_unlock_irq(shost->host_lock);
+@@ -488,6 +512,9 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
  
- 	/* IOP config info */
- 	u32     interface_version;
-@@ -213,15 +251,15 @@ struct hptiop_hba {
+ 	/* Check to see if link went down during discovery */
+ 	if (lpfc_els_chk_latt(vport)) {
++		/* One additional decrement on node reference count to
++		 * trigger the release of the node
++		 */
+ 		lpfc_nlp_put(ndlp);
+ 		goto out;
+ 	}
+@@ -562,8 +589,13 @@ flogifail:
  
- 	u32     req_size; /* host-allocated request buffer size */
+ 		/* Start discovery */
+ 		lpfc_disc_start(vport);
++	} else if (((irsp->ulpStatus != IOSTAT_LOCAL_REJECT) ||
++			((irsp->un.ulpWord[4] != IOERR_SLI_ABORTED) &&
++			(irsp->un.ulpWord[4] != IOERR_SLI_DOWN))) &&
++			(phba->link_state != LPFC_CLEAR_LA)) {
++		/* If FLOGI failed enable link interrupt. */
++		lpfc_issue_clear_la(phba, vport);
+ 	}
+-
+ out:
+ 	lpfc_els_free_iocb(phba, cmdiocb);
+ }
+@@ -685,6 +717,9 @@ lpfc_initial_flogi(struct lpfc_vport *vport)
+ 	struct lpfc_hba *phba = vport->phba;
+ 	struct lpfc_nodelist *ndlp;
  
--	int     iopintf_v2: 1;
--	int     initialized: 1;
--	int     msg_done: 1;
-+	u32     iopintf_v2: 1;
-+	u32     initialized: 1;
-+	u32     msg_done: 1;
++	vport->port_state = LPFC_FLOGI;
++	lpfc_set_disctmo(vport);
++
+ 	/* First look for the Fabric ndlp */
+ 	ndlp = lpfc_findnode_did(vport, Fabric_DID);
+ 	if (!ndlp) {
+@@ -696,7 +731,11 @@ lpfc_initial_flogi(struct lpfc_vport *vport)
+ 	} else {
+ 		lpfc_dequeue_node(vport, ndlp);
+ 	}
++
+ 	if (lpfc_issue_els_flogi(vport, ndlp, 0)) {
++		/* This decrement of reference count to node shall kick off
++		 * the release of the node.
++		 */
+ 		lpfc_nlp_put(ndlp);
+ 	}
+ 	return 1;
+@@ -720,11 +759,16 @@ lpfc_initial_fdisc(struct lpfc_vport *vport)
+ 		lpfc_dequeue_node(vport, ndlp);
+ 	}
+ 	if (lpfc_issue_els_fdisc(vport, ndlp, 0)) {
++		/* decrement node reference count to trigger the release of
++		 * the node.
++		 */
+ 		lpfc_nlp_put(ndlp);
++		return 0;
+ 	}
+ 	return 1;
+ }
+-static void
++
++void
+ lpfc_more_plogi(struct lpfc_vport *vport)
+ {
+ 	int sentplogi;
+@@ -752,6 +796,8 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp,
+ {
+ 	struct lpfc_vport    *vport = ndlp->vport;
+ 	struct lpfc_nodelist *new_ndlp;
++	struct lpfc_rport_data *rdata;
++	struct fc_rport *rport;
+ 	struct serv_parm *sp;
+ 	uint8_t  name[sizeof(struct lpfc_name)];
+ 	uint32_t rc;
+@@ -788,11 +834,34 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp,
+ 	lpfc_unreg_rpi(vport, new_ndlp);
+ 	new_ndlp->nlp_DID = ndlp->nlp_DID;
+ 	new_ndlp->nlp_prev_state = ndlp->nlp_prev_state;
++
++	if (ndlp->nlp_flag & NLP_NPR_2B_DISC)
++		new_ndlp->nlp_flag |= NLP_NPR_2B_DISC;
++	ndlp->nlp_flag &= ~NLP_NPR_2B_DISC;
++
+ 	lpfc_nlp_set_state(vport, new_ndlp, ndlp->nlp_state);
  
- 	struct hptiop_request * req_list;
- 	struct hptiop_request reqs[HPTIOP_MAX_REQUESTS];
+ 	/* Move this back to NPR state */
+-	if (memcmp(&ndlp->nlp_portname, name, sizeof(struct lpfc_name)) == 0)
++	if (memcmp(&ndlp->nlp_portname, name, sizeof(struct lpfc_name)) == 0) {
++		/* The new_ndlp is replacing ndlp totally, so we need
++		 * to put ndlp on UNUSED list and try to free it.
++		 */
++
++		/* Fix up the rport accordingly */
++		rport =  ndlp->rport;
++		if (rport) {
++			rdata = rport->dd_data;
++			if (rdata->pnode == ndlp) {
++				lpfc_nlp_put(ndlp);
++				ndlp->rport = NULL;
++				rdata->pnode = lpfc_nlp_get(new_ndlp);
++				new_ndlp->rport = rport;
++			}
++			new_ndlp->nlp_type = ndlp->nlp_type;
++		}
++
+ 		lpfc_drop_node(vport, ndlp);
++	}
+ 	else {
+ 		lpfc_unreg_rpi(vport, ndlp);
+ 		ndlp->nlp_DID = 0; /* Two ndlps cannot have the same did */
+@@ -801,6 +870,27 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp,
+ 	return new_ndlp;
+ }
  
- 	/* used to free allocated dma area */
--	void *      dma_coherent;
-+	void        *dma_coherent;
- 	dma_addr_t  dma_coherent_handle;
++void
++lpfc_end_rscn(struct lpfc_vport *vport)
++{
++	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
++
++	if (vport->fc_flag & FC_RSCN_MODE) {
++		/*
++		 * Check to see if more RSCNs came in while we were
++		 * processing this one.
++		 */
++		if (vport->fc_rscn_id_cnt ||
++		    (vport->fc_flag & FC_RSCN_DISCOVERY) != 0)
++			lpfc_els_handle_rscn(vport);
++		else {
++			spin_lock_irq(shost->host_lock);
++			vport->fc_flag &= ~FC_RSCN_MODE;
++			spin_unlock_irq(shost->host_lock);
++		}
++	}
++}
++
+ static void
+ lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+ 		    struct lpfc_iocbq *rspiocb)
+@@ -871,13 +961,6 @@ lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+ 			goto out;
+ 		}
+ 		/* PLOGI failed */
+-		if (ndlp->nlp_DID == NameServer_DID) {
+-			lpfc_vport_set_state(vport, FC_VPORT_FAILED);
+-			lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+-					 "0250 Nameserver login error: "
+-					 "0x%x / 0x%x\n",
+-					 irsp->ulpStatus, irsp->un.ulpWord[4]);
+-		}
+ 		/* Do not call DSM for lpfc_els_abort'ed ELS cmds */
+ 		if (lpfc_error_lost_link(irsp)) {
+ 			rc = NLP_STE_FREED_NODE;
+@@ -905,20 +988,7 @@ lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+ 			spin_unlock_irq(shost->host_lock);
  
- 	atomic_t    reset_count;
-@@ -231,19 +269,35 @@ struct hptiop_hba {
- 	wait_queue_head_t ioctl_wq;
- };
+ 			lpfc_can_disctmo(vport);
+-			if (vport->fc_flag & FC_RSCN_MODE) {
+-				/*
+-				 * Check to see if more RSCNs came in while
+-				 * we were processing this one.
+-				 */
+-				if ((vport->fc_rscn_id_cnt == 0) &&
+-				    (!(vport->fc_flag & FC_RSCN_DISCOVERY))) {
+-					spin_lock_irq(shost->host_lock);
+-					vport->fc_flag &= ~FC_RSCN_MODE;
+-					spin_unlock_irq(shost->host_lock);
+-				} else {
+-					lpfc_els_handle_rscn(vport);
+-				}
+-			}
++			lpfc_end_rscn(vport);
+ 		}
+ 	}
  
--struct hpt_ioctl_k
--{
-+struct hpt_ioctl_k {
- 	struct hptiop_hba * hba;
- 	u32    ioctl_code;
- 	u32    inbuf_size;
- 	u32    outbuf_size;
--	void * inbuf;
--	void * outbuf;
--	u32  * bytes_returned;
-+	void   *inbuf;
-+	void   *outbuf;
-+	u32    *bytes_returned;
- 	void (*done)(struct hpt_ioctl_k *);
- 	int    result; /* HPT_IOCTL_RESULT_ */
- };
+@@ -933,6 +1003,7 @@ lpfc_issue_els_plogi(struct lpfc_vport *vport, uint32_t did, uint8_t retry)
+ 	struct lpfc_hba  *phba = vport->phba;
+ 	struct serv_parm *sp;
+ 	IOCB_t *icmd;
++	struct lpfc_nodelist *ndlp;
+ 	struct lpfc_iocbq *elsiocb;
+ 	struct lpfc_sli_ring *pring;
+ 	struct lpfc_sli *psli;
+@@ -943,8 +1014,11 @@ lpfc_issue_els_plogi(struct lpfc_vport *vport, uint32_t did, uint8_t retry)
+ 	psli = &phba->sli;
+ 	pring = &psli->ring[LPFC_ELS_RING];	/* ELS ring */
  
-+struct hptiop_adapter_ops {
-+	int  (*iop_wait_ready)(struct hptiop_hba *hba, u32 millisec);
-+	int  (*internal_memalloc)(struct hptiop_hba *hba);
-+	int  (*internal_memfree)(struct hptiop_hba *hba);
-+	int  (*map_pci_bar)(struct hptiop_hba *hba);
-+	void (*unmap_pci_bar)(struct hptiop_hba *hba);
-+	void (*enable_intr)(struct hptiop_hba *hba);
-+	void (*disable_intr)(struct hptiop_hba *hba);
-+	int  (*get_config)(struct hptiop_hba *hba,
-+				struct hpt_iop_request_get_config *config);
-+	int  (*set_config)(struct hptiop_hba *hba,
-+				struct hpt_iop_request_set_config *config);
-+	int  (*iop_intr)(struct hptiop_hba *hba);
-+	void (*post_msg)(struct hptiop_hba *hba, u32 msg);
-+	void (*post_req)(struct hptiop_hba *hba, struct hptiop_request *_req);
-+};
++	ndlp = lpfc_findnode_did(vport, did);
++	/* If ndlp if not NULL, we will bump the reference count on it */
 +
- #define HPT_IOCTL_RESULT_OK         0
- #define HPT_IOCTL_RESULT_FAILED     (-1)
- 
-diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c
-index 5f2396c..3081901 100644
---- a/drivers/scsi/ibmvscsi/ibmvscsi.c
-+++ b/drivers/scsi/ibmvscsi/ibmvscsi.c
-@@ -629,6 +629,16 @@ static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct,
- 		list_del(&evt_struct->list);
- 		del_timer(&evt_struct->timer);
+ 	cmdsize = (sizeof(uint32_t) + sizeof(struct serv_parm));
+-	elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, NULL, did,
++	elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp, did,
+ 				     ELS_CMD_PLOGI);
+ 	if (!elsiocb)
+ 		return 1;
+@@ -1109,7 +1183,7 @@ lpfc_issue_els_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ 	return 0;
+ }
  
-+		/* If send_crq returns H_CLOSED, return SCSI_MLQUEUE_HOST_BUSY.
-+		 * Firmware will send a CRQ with a transport event (0xFF) to
-+		 * tell this client what has happened to the transport.  This
-+		 * will be handled in ibmvscsi_handle_crq()
-+		 */
-+		if (rc == H_CLOSED) {
-+			dev_warn(hostdata->dev, "send warning. "
-+			         "Receive queue closed, will retry.\n");
-+			goto send_busy;
-+		}
- 		dev_err(hostdata->dev, "send error %d\n", rc);
- 		atomic_inc(&hostdata->request_limit);
- 		goto send_error;
-@@ -976,58 +986,74 @@ static int ibmvscsi_eh_abort_handler(struct scsi_cmnd *cmd)
- 	int rsp_rc;
- 	unsigned long flags;
- 	u16 lun = lun_from_dev(cmd->device);
-+	unsigned long wait_switch = 0;
+-static void
++void
+ lpfc_more_adisc(struct lpfc_vport *vport)
+ {
+ 	int sentadisc;
+@@ -1134,8 +1208,6 @@ lpfc_more_adisc(struct lpfc_vport *vport)
+ static void
+ lpfc_rscn_disc(struct lpfc_vport *vport)
+ {
+-	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+-
+ 	lpfc_can_disctmo(vport);
  
- 	/* First, find this command in our sent list so we can figure
- 	 * out the correct tag
- 	 */
- 	spin_lock_irqsave(hostdata->host->host_lock, flags);
--	found_evt = NULL;
--	list_for_each_entry(tmp_evt, &hostdata->sent, list) {
--		if (tmp_evt->cmnd == cmd) {
--			found_evt = tmp_evt;
--			break;
-+	wait_switch = jiffies + (init_timeout * HZ);
-+	do {
-+		found_evt = NULL;
-+		list_for_each_entry(tmp_evt, &hostdata->sent, list) {
-+			if (tmp_evt->cmnd == cmd) {
-+				found_evt = tmp_evt;
-+				break;
-+			}
- 		}
--	}
+ 	/* RSCN discovery */
+@@ -1144,19 +1216,7 @@ lpfc_rscn_disc(struct lpfc_vport *vport)
+ 		if (lpfc_els_disc_plogi(vport))
+ 			return;
  
--	if (!found_evt) {
--		spin_unlock_irqrestore(hostdata->host->host_lock, flags);
--		return SUCCESS;
+-	if (vport->fc_flag & FC_RSCN_MODE) {
+-		/* Check to see if more RSCNs came in while we were
+-		 * processing this one.
+-		 */
+-		if ((vport->fc_rscn_id_cnt == 0) &&
+-		    (!(vport->fc_flag & FC_RSCN_DISCOVERY))) {
+-			spin_lock_irq(shost->host_lock);
+-			vport->fc_flag &= ~FC_RSCN_MODE;
+-			spin_unlock_irq(shost->host_lock);
+-		} else {
+-			lpfc_els_handle_rscn(vport);
+-		}
 -	}
-+		if (!found_evt) {
-+			spin_unlock_irqrestore(hostdata->host->host_lock, flags);
-+			return SUCCESS;
-+		}
++	lpfc_end_rscn(vport);
+ }
  
--	evt = get_event_struct(&hostdata->pool);
--	if (evt == NULL) {
--		spin_unlock_irqrestore(hostdata->host->host_lock, flags);
--		sdev_printk(KERN_ERR, cmd->device, "failed to allocate abort event\n");
--		return FAILED;
--	}
-+		evt = get_event_struct(&hostdata->pool);
-+		if (evt == NULL) {
-+			spin_unlock_irqrestore(hostdata->host->host_lock, flags);
-+			sdev_printk(KERN_ERR, cmd->device,
-+				"failed to allocate abort event\n");
-+			return FAILED;
-+		}
- 	
--	init_event_struct(evt,
--			  sync_completion,
--			  VIOSRP_SRP_FORMAT,
--			  init_timeout);
-+		init_event_struct(evt,
-+				  sync_completion,
-+				  VIOSRP_SRP_FORMAT,
-+				  init_timeout);
+ static void
+@@ -1413,6 +1473,13 @@ lpfc_issue_els_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ 	psli = &phba->sli;
+ 	pring = &psli->ring[LPFC_ELS_RING];
  
--	tsk_mgmt = &evt->iu.srp.tsk_mgmt;
-+		tsk_mgmt = &evt->iu.srp.tsk_mgmt;
- 	
--	/* Set up an abort SRP command */
--	memset(tsk_mgmt, 0x00, sizeof(*tsk_mgmt));
--	tsk_mgmt->opcode = SRP_TSK_MGMT;
--	tsk_mgmt->lun = ((u64) lun) << 48;
--	tsk_mgmt->tsk_mgmt_func = SRP_TSK_ABORT_TASK;
--	tsk_mgmt->task_tag = (u64) found_evt;
++	spin_lock_irq(shost->host_lock);
++	if (ndlp->nlp_flag & NLP_LOGO_SND) {
++		spin_unlock_irq(shost->host_lock);
++		return 0;
++	}
++	spin_unlock_irq(shost->host_lock);
++
+ 	cmdsize = (2 * sizeof(uint32_t)) + sizeof(struct lpfc_name);
+ 	elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp,
+ 				     ndlp->nlp_DID, ELS_CMD_LOGO);
+@@ -1499,6 +1566,9 @@ lpfc_issue_els_scr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry)
+ 				     ndlp->nlp_DID, ELS_CMD_SCR);
+ 
+ 	if (!elsiocb) {
++		/* This will trigger the release of the node just
++		 * allocated
++		 */
+ 		lpfc_nlp_put(ndlp);
+ 		return 1;
+ 	}
+@@ -1520,10 +1590,17 @@ lpfc_issue_els_scr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry)
+ 	phba->fc_stat.elsXmitSCR++;
+ 	elsiocb->iocb_cmpl = lpfc_cmpl_els_cmd;
+ 	if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
++		/* The additional lpfc_nlp_put will cause the following
++		 * lpfc_els_free_iocb routine to trigger the rlease of
++		 * the node.
++		 */
+ 		lpfc_nlp_put(ndlp);
+ 		lpfc_els_free_iocb(phba, elsiocb);
+ 		return 1;
+ 	}
++	/* This will cause the callback-function lpfc_cmpl_els_cmd to
++	 * trigger the release of node.
++	 */
+ 	lpfc_nlp_put(ndlp);
+ 	return 0;
+ }
+@@ -1555,6 +1632,9 @@ lpfc_issue_els_farpr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry)
+ 	elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp,
+ 				     ndlp->nlp_DID, ELS_CMD_RNID);
+ 	if (!elsiocb) {
++		/* This will trigger the release of the node just
++		 * allocated
++		 */
+ 		lpfc_nlp_put(ndlp);
+ 		return 1;
+ 	}
+@@ -1591,35 +1671,21 @@ lpfc_issue_els_farpr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry)
+ 	phba->fc_stat.elsXmitFARPR++;
+ 	elsiocb->iocb_cmpl = lpfc_cmpl_els_cmd;
+ 	if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
++		/* The additional lpfc_nlp_put will cause the following
++		 * lpfc_els_free_iocb routine to trigger the release of
++		 * the node.
++		 */
+ 		lpfc_nlp_put(ndlp);
+ 		lpfc_els_free_iocb(phba, elsiocb);
+ 		return 1;
+ 	}
++	/* This will cause the callback-function lpfc_cmpl_els_cmd to
++	 * trigger the release of the node.
++	 */
+ 	lpfc_nlp_put(ndlp);
+ 	return 0;
+ }
+ 
+-static void
+-lpfc_end_rscn(struct lpfc_vport *vport)
+-{
+-	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
 -
--	sdev_printk(KERN_INFO, cmd->device, "aborting command. lun 0x%lx, tag 0x%lx\n",
--		    tsk_mgmt->lun, tsk_mgmt->task_tag);
+-	if (vport->fc_flag & FC_RSCN_MODE) {
+-		/*
+-		 * Check to see if more RSCNs came in while we were
+-		 * processing this one.
+-		 */
+-		if (vport->fc_rscn_id_cnt ||
+-		    (vport->fc_flag & FC_RSCN_DISCOVERY) != 0)
+-			lpfc_els_handle_rscn(vport);
+-		else {
+-			spin_lock_irq(shost->host_lock);
+-			vport->fc_flag &= ~FC_RSCN_MODE;
+-			spin_unlock_irq(shost->host_lock);
+-		}
+-	}
+-}
 -
--	evt->sync_srp = &srp_rsp;
--	init_completion(&evt->comp);
--	rsp_rc = ibmvscsi_send_srp_event(evt, hostdata, init_timeout * 2);
-+		/* Set up an abort SRP command */
-+		memset(tsk_mgmt, 0x00, sizeof(*tsk_mgmt));
-+		tsk_mgmt->opcode = SRP_TSK_MGMT;
-+		tsk_mgmt->lun = ((u64) lun) << 48;
-+		tsk_mgmt->tsk_mgmt_func = SRP_TSK_ABORT_TASK;
-+		tsk_mgmt->task_tag = (u64) found_evt;
-+
-+		evt->sync_srp = &srp_rsp;
-+
-+		init_completion(&evt->comp);
-+		rsp_rc = ibmvscsi_send_srp_event(evt, hostdata, init_timeout * 2);
-+
-+		if (rsp_rc != SCSI_MLQUEUE_HOST_BUSY)
-+			break;
-+
-+		spin_unlock_irqrestore(hostdata->host->host_lock, flags);
-+		msleep(10);
-+		spin_lock_irqsave(hostdata->host->host_lock, flags);
-+	} while (time_before(jiffies, wait_switch));
-+
- 	spin_unlock_irqrestore(hostdata->host->host_lock, flags);
-+
- 	if (rsp_rc != 0) {
- 		sdev_printk(KERN_ERR, cmd->device,
- 			    "failed to send abort() event. rc=%d\n", rsp_rc);
- 		return FAILED;
+ void
+ lpfc_cancel_retry_delay_tmo(struct lpfc_vport *vport, struct lpfc_nodelist *nlp)
+ {
+@@ -1675,7 +1741,10 @@ lpfc_els_retry_delay(unsigned long ptr)
+ 		return;
  	}
  
-+	sdev_printk(KERN_INFO, cmd->device,
-+                    "aborting command. lun 0x%lx, tag 0x%lx\n",
-+		    (((u64) lun) << 48), (u64) found_evt);
-+
- 	wait_for_completion(&evt->comp);
+-	evtp->evt_arg1  = ndlp;
++	/* We need to hold the node by incrementing the reference
++	 * count until the queued work is done
++	 */
++	evtp->evt_arg1  = lpfc_nlp_get(ndlp);
+ 	evtp->evt       = LPFC_EVT_ELS_RETRY;
+ 	list_add_tail(&evtp->evt_listp, &phba->work_list);
+ 	if (phba->work_wait)
+@@ -1759,6 +1828,7 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+ 	uint32_t *elscmd;
+ 	struct ls_rjt stat;
+ 	int retry = 0, maxretry = lpfc_max_els_tries, delay = 0;
++	int logerr = 0;
+ 	uint32_t cmd = 0;
+ 	uint32_t did;
  
- 	/* make sure we got a good response */
-@@ -1099,41 +1125,56 @@ static int ibmvscsi_eh_device_reset_handler(struct scsi_cmnd *cmd)
- 	int rsp_rc;
- 	unsigned long flags;
- 	u16 lun = lun_from_dev(cmd->device);
-+	unsigned long wait_switch = 0;
+@@ -1815,6 +1885,7 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+ 			break;
  
- 	spin_lock_irqsave(hostdata->host->host_lock, flags);
--	evt = get_event_struct(&hostdata->pool);
--	if (evt == NULL) {
--		spin_unlock_irqrestore(hostdata->host->host_lock, flags);
--		sdev_printk(KERN_ERR, cmd->device, "failed to allocate reset event\n");
--		return FAILED;
--	}
-+	wait_switch = jiffies + (init_timeout * HZ);
-+	do {
-+		evt = get_event_struct(&hostdata->pool);
-+		if (evt == NULL) {
-+			spin_unlock_irqrestore(hostdata->host->host_lock, flags);
-+			sdev_printk(KERN_ERR, cmd->device,
-+				"failed to allocate reset event\n");
-+			return FAILED;
-+		}
- 	
--	init_event_struct(evt,
--			  sync_completion,
--			  VIOSRP_SRP_FORMAT,
--			  init_timeout);
-+		init_event_struct(evt,
-+				  sync_completion,
-+				  VIOSRP_SRP_FORMAT,
-+				  init_timeout);
+ 		case IOERR_NO_RESOURCES:
++			logerr = 1; /* HBA out of resources */
+ 			retry = 1;
+ 			if (cmdiocb->retry > 100)
+ 				delay = 100;
+@@ -1843,6 +1914,7 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
  
--	tsk_mgmt = &evt->iu.srp.tsk_mgmt;
-+		tsk_mgmt = &evt->iu.srp.tsk_mgmt;
+ 	case IOSTAT_NPORT_BSY:
+ 	case IOSTAT_FABRIC_BSY:
++		logerr = 1; /* Fabric / Remote NPort out of resources */
+ 		retry = 1;
+ 		break;
  
--	/* Set up a lun reset SRP command */
--	memset(tsk_mgmt, 0x00, sizeof(*tsk_mgmt));
--	tsk_mgmt->opcode = SRP_TSK_MGMT;
--	tsk_mgmt->lun = ((u64) lun) << 48;
--	tsk_mgmt->tsk_mgmt_func = SRP_TSK_LUN_RESET;
-+		/* Set up a lun reset SRP command */
-+		memset(tsk_mgmt, 0x00, sizeof(*tsk_mgmt));
-+		tsk_mgmt->opcode = SRP_TSK_MGMT;
-+		tsk_mgmt->lun = ((u64) lun) << 48;
-+		tsk_mgmt->tsk_mgmt_func = SRP_TSK_LUN_RESET;
+@@ -1923,6 +1995,15 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+ 	if (did == FDMI_DID)
+ 		retry = 1;
  
--	sdev_printk(KERN_INFO, cmd->device, "resetting device. lun 0x%lx\n",
--		    tsk_mgmt->lun);
-+		evt->sync_srp = &srp_rsp;
++	if ((cmd == ELS_CMD_FLOGI) &&
++	    (phba->fc_topology != TOPOLOGY_LOOP)) {
++		/* FLOGI retry policy */
++		retry = 1;
++		maxretry = 48;
++		if (cmdiocb->retry >= 32)
++			delay = 1000;
++	}
 +
-+		init_completion(&evt->comp);
-+		rsp_rc = ibmvscsi_send_srp_event(evt, hostdata, init_timeout * 2);
+ 	if ((++cmdiocb->retry) >= maxretry) {
+ 		phba->fc_stat.elsRetryExceeded++;
+ 		retry = 0;
+@@ -2006,11 +2087,46 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+ 		}
+ 	}
+ 	/* No retry ELS command <elsCmd> to remote NPORT <did> */
+-	lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
++	if (logerr) {
++		lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
++			 "0137 No retry ELS command x%x to remote "
++			 "NPORT x%x: Out of Resources: Error:x%x/%x\n",
++			 cmd, did, irsp->ulpStatus,
++			 irsp->un.ulpWord[4]);
++	}
++	else {
++		lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
+ 			 "0108 No retry ELS command x%x to remote "
+ 			 "NPORT x%x Retried:%d Error:x%x/%x\n",
+ 			 cmd, did, cmdiocb->retry, irsp->ulpStatus,
+ 			 irsp->un.ulpWord[4]);
++	}
++	return 0;
++}
 +
-+		if (rsp_rc != SCSI_MLQUEUE_HOST_BUSY)
-+			break;
++static int
++lpfc_els_free_data(struct lpfc_hba *phba, struct lpfc_dmabuf *buf_ptr1)
++{
++	struct lpfc_dmabuf *buf_ptr;
 +
-+		spin_unlock_irqrestore(hostdata->host->host_lock, flags);
-+		msleep(10);
-+		spin_lock_irqsave(hostdata->host->host_lock, flags);
-+	} while (time_before(jiffies, wait_switch));
++	/* Free the response before processing the command.  */
++	if (!list_empty(&buf_ptr1->list)) {
++		list_remove_head(&buf_ptr1->list, buf_ptr,
++				 struct lpfc_dmabuf,
++				 list);
++		lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys);
++		kfree(buf_ptr);
++	}
++	lpfc_mbuf_free(phba, buf_ptr1->virt, buf_ptr1->phys);
++	kfree(buf_ptr1);
++	return 0;
++}
++
++static int
++lpfc_els_free_bpl(struct lpfc_hba *phba, struct lpfc_dmabuf *buf_ptr)
++{
++	lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys);
++	kfree(buf_ptr);
+ 	return 0;
+ }
  
--	evt->sync_srp = &srp_rsp;
--	init_completion(&evt->comp);
--	rsp_rc = ibmvscsi_send_srp_event(evt, hostdata, init_timeout * 2);
- 	spin_unlock_irqrestore(hostdata->host->host_lock, flags);
+@@ -2018,30 +2134,63 @@ int
+ lpfc_els_free_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *elsiocb)
+ {
+ 	struct lpfc_dmabuf *buf_ptr, *buf_ptr1;
++	struct lpfc_nodelist *ndlp;
+ 
+-	if (elsiocb->context1) {
+-		lpfc_nlp_put(elsiocb->context1);
++	ndlp = (struct lpfc_nodelist *)elsiocb->context1;
++	if (ndlp) {
++		if (ndlp->nlp_flag & NLP_DEFER_RM) {
++			lpfc_nlp_put(ndlp);
 +
- 	if (rsp_rc != 0) {
- 		sdev_printk(KERN_ERR, cmd->device,
- 			    "failed to send reset event. rc=%d\n", rsp_rc);
- 		return FAILED;
++			/* If the ndlp is not being used by another discovery
++			 * thread, free it.
++			 */
++			if (!lpfc_nlp_not_used(ndlp)) {
++				/* If ndlp is being used by another discovery
++				 * thread, just clear NLP_DEFER_RM
++				 */
++				ndlp->nlp_flag &= ~NLP_DEFER_RM;
++			}
++		}
++		else
++			lpfc_nlp_put(ndlp);
+ 		elsiocb->context1 = NULL;
+ 	}
+ 	/* context2  = cmd,  context2->next = rsp, context3 = bpl */
+ 	if (elsiocb->context2) {
+-		buf_ptr1 = (struct lpfc_dmabuf *) elsiocb->context2;
+-		/* Free the response before processing the command.  */
+-		if (!list_empty(&buf_ptr1->list)) {
+-			list_remove_head(&buf_ptr1->list, buf_ptr,
+-					 struct lpfc_dmabuf,
+-					 list);
+-			lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys);
+-			kfree(buf_ptr);
++		if (elsiocb->iocb_flag & LPFC_DELAY_MEM_FREE) {
++			/* Firmware could still be in progress of DMAing
++			 * payload, so don't free data buffer till after
++			 * a hbeat.
++			 */
++			elsiocb->iocb_flag &= ~LPFC_DELAY_MEM_FREE;
++			buf_ptr = elsiocb->context2;
++			elsiocb->context2 = NULL;
++			if (buf_ptr) {
++				buf_ptr1 = NULL;
++				spin_lock_irq(&phba->hbalock);
++				if (!list_empty(&buf_ptr->list)) {
++					list_remove_head(&buf_ptr->list,
++						buf_ptr1, struct lpfc_dmabuf,
++						list);
++					INIT_LIST_HEAD(&buf_ptr1->list);
++					list_add_tail(&buf_ptr1->list,
++						&phba->elsbuf);
++					phba->elsbuf_cnt++;
++				}
++				INIT_LIST_HEAD(&buf_ptr->list);
++				list_add_tail(&buf_ptr->list, &phba->elsbuf);
++				phba->elsbuf_cnt++;
++				spin_unlock_irq(&phba->hbalock);
++			}
++		} else {
++			buf_ptr1 = (struct lpfc_dmabuf *) elsiocb->context2;
++			lpfc_els_free_data(phba, buf_ptr1);
+ 		}
+-		lpfc_mbuf_free(phba, buf_ptr1->virt, buf_ptr1->phys);
+-		kfree(buf_ptr1);
  	}
  
-+	sdev_printk(KERN_INFO, cmd->device, "resetting device. lun 0x%lx\n",
-+		    (((u64) lun) << 48));
+ 	if (elsiocb->context3) {
+ 		buf_ptr = (struct lpfc_dmabuf *) elsiocb->context3;
+-		lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys);
+-		kfree(buf_ptr);
++		lpfc_els_free_bpl(phba, buf_ptr);
+ 	}
+ 	lpfc_sli_release_iocbq(phba, elsiocb);
+ 	return 0;
+@@ -2065,15 +2214,20 @@ lpfc_cmpl_els_logo_acc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+ 			 "Data: x%x x%x x%x\n",
+ 			 ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state,
+ 			 ndlp->nlp_rpi);
+-	switch (ndlp->nlp_state) {
+-	case NLP_STE_UNUSED_NODE:	/* node is just allocated */
+-		lpfc_drop_node(vport, ndlp);
+-		break;
+-	case NLP_STE_NPR_NODE:		/* NPort Recovery mode */
+-		lpfc_unreg_rpi(vport, ndlp);
+-		break;
+-	default:
+-		break;
 +
- 	wait_for_completion(&evt->comp);
- 
- 	/* make sure we got a good response */
-@@ -1386,8 +1427,10 @@ static int ibmvscsi_slave_configure(struct scsi_device *sdev)
- 	unsigned long lock_flags = 0;
- 
- 	spin_lock_irqsave(shost->host_lock, lock_flags);
--	if (sdev->type == TYPE_DISK)
-+	if (sdev->type == TYPE_DISK) {
- 		sdev->allow_restart = 1;
-+		sdev->timeout = 60 * HZ;
++	if (ndlp->nlp_state == NLP_STE_NPR_NODE) {
++		/* NPort Recovery mode or node is just allocated */
++		if (!lpfc_nlp_not_used(ndlp)) {
++			/* If the ndlp is being used by another discovery
++			 * thread, just unregister the RPI.
++			 */
++			lpfc_unreg_rpi(vport, ndlp);
++		} else {
++			/* Indicate the node has already released, should
++			 * not reference to it from within lpfc_els_free_iocb.
++			 */
++			cmdiocb->context1 = NULL;
++		}
+ 	}
+ 	lpfc_els_free_iocb(phba, cmdiocb);
+ 	return;
+@@ -2089,7 +2243,14 @@ lpfc_mbx_cmpl_dflt_rpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
+ 	lpfc_mbuf_free(phba, mp->virt, mp->phys);
+ 	kfree(mp);
+ 	mempool_free(pmb, phba->mbox_mem_pool);
+-	lpfc_nlp_put(ndlp);
++	if (ndlp) {
++		lpfc_nlp_put(ndlp);
++		/* This is the end of the default RPI cleanup logic for this
++		 * ndlp. If no other discovery threads are using this ndlp.
++		 * we should free all resources associated with it.
++		 */
++		lpfc_nlp_not_used(ndlp);
 +	}
- 	scsi_adjust_queue_depth(sdev, 0, shost->cmd_per_lun);
- 	spin_unlock_irqrestore(shost->host_lock, lock_flags);
- 	return 0;
-diff --git a/drivers/scsi/ibmvscsi/ibmvstgt.c b/drivers/scsi/ibmvscsi/ibmvstgt.c
-index 82bcab6..d63f11e 100644
---- a/drivers/scsi/ibmvscsi/ibmvstgt.c
-+++ b/drivers/scsi/ibmvscsi/ibmvstgt.c
-@@ -292,7 +292,7 @@ static int ibmvstgt_cmd_done(struct scsi_cmnd *sc,
- 	dprintk("%p %p %x %u\n", iue, target, vio_iu(iue)->srp.cmd.cdb[0],
- 		cmd->usg_sg);
- 
--	if (sc->use_sg)
-+	if (scsi_sg_count(sc))
- 		err = srp_transfer_data(sc, &vio_iu(iue)->srp.cmd, ibmvstgt_rdma, 1, 1);
+ 	return;
+ }
  
- 	spin_lock_irqsave(&target->lock, flags);
-diff --git a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c
-index 9706de9..02e9189 100644
---- a/drivers/scsi/ide-scsi.c
-+++ b/drivers/scsi/ide-scsi.c
-@@ -395,14 +395,12 @@ static int idescsi_expiry(ide_drive_t *drive)
- static ide_startstop_t idescsi_pc_intr (ide_drive_t *drive)
- {
- 	idescsi_scsi_t *scsi = drive_to_idescsi(drive);
--	idescsi_pc_t *pc=scsi->pc;
-+	ide_hwif_t *hwif = drive->hwif;
-+	idescsi_pc_t *pc = scsi->pc;
- 	struct request *rq = pc->rq;
--	atapi_bcount_t bcount;
--	atapi_status_t status;
--	atapi_ireason_t ireason;
--	atapi_feature_t feature;
--
- 	unsigned int temp;
-+	u16 bcount;
-+	u8 stat, ireason;
+@@ -2100,15 +2261,29 @@ lpfc_cmpl_els_rsp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+ 	struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) cmdiocb->context1;
+ 	struct lpfc_vport *vport = ndlp ? ndlp->vport : NULL;
+ 	struct Scsi_Host  *shost = vport ? lpfc_shost_from_vport(vport) : NULL;
+-	IOCB_t *irsp;
++	IOCB_t  *irsp;
++	uint8_t *pcmd;
+ 	LPFC_MBOXQ_t *mbox = NULL;
+ 	struct lpfc_dmabuf *mp = NULL;
++	uint32_t ls_rjt = 0;
  
- #if IDESCSI_DEBUG_LOG
- 	printk (KERN_INFO "ide-scsi: Reached idescsi_pc_intr interrupt handler\n");
-@@ -425,30 +423,29 @@ static ide_startstop_t idescsi_pc_intr (ide_drive_t *drive)
- 		(void) HWIF(drive)->ide_dma_end(drive);
- 	}
+ 	irsp = &rspiocb->iocb;
  
--	feature.all = 0;
- 	/* Clear the interrupt */
--	status.all = HWIF(drive)->INB(IDE_STATUS_REG);
-+	stat = drive->hwif->INB(IDE_STATUS_REG);
+ 	if (cmdiocb->context_un.mbox)
+ 		mbox = cmdiocb->context_un.mbox;
  
--	if (!status.b.drq) {
-+	if ((stat & DRQ_STAT) == 0) {
- 		/* No more interrupts */
- 		if (test_bit(IDESCSI_LOG_CMD, &scsi->log))
- 			printk (KERN_INFO "Packet command completed, %d bytes transferred\n", pc->actually_transferred);
- 		local_irq_enable_in_hardirq();
--		if (status.b.check)
-+		if (stat & ERR_STAT)
- 			rq->errors++;
- 		idescsi_end_request (drive, 1, 0);
- 		return ide_stopped;
++	/* First determine if this is a LS_RJT cmpl. Note, this callback
++	 * function can have cmdiocb->contest1 (ndlp) field set to NULL.
++	 */
++	pcmd = (uint8_t *) (((struct lpfc_dmabuf *) cmdiocb->context2)->virt);
++	if (ndlp && (*((uint32_t *) (pcmd)) == ELS_CMD_LS_RJT)) {
++		/* A LS_RJT associated with Default RPI cleanup has its own
++		 * seperate code path.
++		 */
++		if (!(ndlp->nlp_flag & NLP_RM_DFLT_RPI))
++			ls_rjt = 1;
++	}
++
+ 	/* Check to see if link went down during discovery */
+ 	if (!ndlp || lpfc_els_chk_latt(vport)) {
+ 		if (mbox) {
+@@ -2119,6 +2294,15 @@ lpfc_cmpl_els_rsp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+ 			}
+ 			mempool_free(mbox, phba->mbox_mem_pool);
+ 		}
++		if (ndlp && (ndlp->nlp_flag & NLP_RM_DFLT_RPI))
++			if (lpfc_nlp_not_used(ndlp)) {
++				ndlp = NULL;
++				/* Indicate the node has already released,
++				 * should not reference to it from within
++				 * the routine lpfc_els_free_iocb.
++				 */
++				cmdiocb->context1 = NULL;
++			}
+ 		goto out;
  	}
--	bcount.b.low	= HWIF(drive)->INB(IDE_BCOUNTL_REG);
--	bcount.b.high	= HWIF(drive)->INB(IDE_BCOUNTH_REG);
--	ireason.all	= HWIF(drive)->INB(IDE_IREASON_REG);
-+	bcount = (hwif->INB(IDE_BCOUNTH_REG) << 8) |
-+		  hwif->INB(IDE_BCOUNTL_REG);
-+	ireason = hwif->INB(IDE_IREASON_REG);
  
--	if (ireason.b.cod) {
-+	if (ireason & CD) {
- 		printk(KERN_ERR "ide-scsi: CoD != 0 in idescsi_pc_intr\n");
- 		return ide_do_reset (drive);
- 	}
--	if (ireason.b.io) {
--		temp = pc->actually_transferred + bcount.all;
-+	if (ireason & IO) {
-+		temp = pc->actually_transferred + bcount;
- 		if (temp > pc->request_transfer) {
- 			if (temp > pc->buffer_size) {
- 				printk(KERN_ERR "ide-scsi: The scsi wants to "
-@@ -461,11 +458,13 @@ static ide_startstop_t idescsi_pc_intr (ide_drive_t *drive)
- 						idescsi_input_buffers(drive, pc, temp);
- 					else
- 						drive->hwif->atapi_input_bytes(drive, pc->current_position, temp);
--					printk(KERN_ERR "ide-scsi: transferred %d of %d bytes\n", temp, bcount.all);
-+					printk(KERN_ERR "ide-scsi: transferred"
-+							" %d of %d bytes\n",
-+							temp, bcount);
- 				}
- 				pc->actually_transferred += temp;
- 				pc->current_position += temp;
--				idescsi_discard_data(drive, bcount.all - temp);
-+				idescsi_discard_data(drive, bcount - temp);
- 				ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc), idescsi_expiry);
- 				return ide_started;
+@@ -2150,20 +2334,39 @@ lpfc_cmpl_els_rsp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+ 				lpfc_nlp_set_state(vport, ndlp,
+ 					   NLP_STE_REG_LOGIN_ISSUE);
+ 			}
+-			if (lpfc_sli_issue_mbox(phba, mbox,
+-						(MBX_NOWAIT | MBX_STOP_IOCB))
++			if (lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT)
+ 			    != MBX_NOT_FINISHED) {
+ 				goto out;
+ 			}
+-			lpfc_nlp_put(ndlp);
+-			/* NOTE: we should have messages for unsuccessful
+-			   reglogin */
++
++			/* ELS rsp: Cannot issue reg_login for <NPortid> */
++			lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
++				"0138 ELS rsp: Cannot issue reg_login for x%x "
++				"Data: x%x x%x x%x\n",
++				ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state,
++				ndlp->nlp_rpi);
++
++			if (lpfc_nlp_not_used(ndlp)) {
++				ndlp = NULL;
++				/* Indicate node has already been released,
++				 * should not reference to it from within
++				 * the routine lpfc_els_free_iocb.
++				 */
++				cmdiocb->context1 = NULL;
++			}
+ 		} else {
+ 			/* Do not drop node for lpfc_els_abort'ed ELS cmds */
+ 			if (!lpfc_error_lost_link(irsp) &&
+ 			    ndlp->nlp_flag & NLP_ACC_REGLOGIN) {
+-				lpfc_drop_node(vport, ndlp);
+-				ndlp = NULL;
++				if (lpfc_nlp_not_used(ndlp)) {
++					ndlp = NULL;
++					/* Indicate node has already been
++					 * released, should not reference
++					 * to it from within the routine
++					 * lpfc_els_free_iocb.
++					 */
++					cmdiocb->context1 = NULL;
++				}
  			}
-@@ -474,22 +473,24 @@ static ide_startstop_t idescsi_pc_intr (ide_drive_t *drive)
- #endif /* IDESCSI_DEBUG_LOG */
  		}
+ 		mp = (struct lpfc_dmabuf *) mbox->context1;
+@@ -2178,7 +2381,21 @@ out:
+ 		spin_lock_irq(shost->host_lock);
+ 		ndlp->nlp_flag &= ~(NLP_ACC_REGLOGIN | NLP_RM_DFLT_RPI);
+ 		spin_unlock_irq(shost->host_lock);
++
++		/* If the node is not being used by another discovery thread,
++		 * and we are sending a reject, we are done with it.
++		 * Release driver reference count here and free associated
++		 * resources.
++		 */
++		if (ls_rjt)
++			if (lpfc_nlp_not_used(ndlp))
++				/* Indicate node has already been released,
++				 * should not reference to it from within
++				 * the routine lpfc_els_free_iocb.
++				 */
++				cmdiocb->context1 = NULL;
  	}
--	if (ireason.b.io) {
-+	if (ireason & IO) {
- 		clear_bit(PC_WRITING, &pc->flags);
- 		if (pc->sg)
--			idescsi_input_buffers(drive, pc, bcount.all);
-+			idescsi_input_buffers(drive, pc, bcount);
- 		else
--			HWIF(drive)->atapi_input_bytes(drive, pc->current_position, bcount.all);
-+			hwif->atapi_input_bytes(drive, pc->current_position,
-+						bcount);
- 	} else {
- 		set_bit(PC_WRITING, &pc->flags);
- 		if (pc->sg)
--			idescsi_output_buffers (drive, pc, bcount.all);
-+			idescsi_output_buffers(drive, pc, bcount);
- 		else
--			HWIF(drive)->atapi_output_bytes(drive, pc->current_position, bcount.all);
-+			hwif->atapi_output_bytes(drive, pc->current_position,
-+						 bcount);
- 	}
- 	/* Update the current position */
--	pc->actually_transferred += bcount.all;
--	pc->current_position += bcount.all;
-+	pc->actually_transferred += bcount;
-+	pc->current_position += bcount;
- 
- 	/* And set the interrupt handler again */
- 	ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc), idescsi_expiry);
-@@ -501,16 +502,16 @@ static ide_startstop_t idescsi_transfer_pc(ide_drive_t *drive)
- 	ide_hwif_t *hwif = drive->hwif;
- 	idescsi_scsi_t *scsi = drive_to_idescsi(drive);
- 	idescsi_pc_t *pc = scsi->pc;
--	atapi_ireason_t ireason;
- 	ide_startstop_t startstop;
-+	u8 ireason;
++
+ 	lpfc_els_free_iocb(phba, cmdiocb);
+ 	return;
+ }
+@@ -2349,14 +2566,6 @@ lpfc_els_rsp_reject(struct lpfc_vport *vport, uint32_t rejectError,
+ 	elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp;
+ 	rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0);
  
- 	if (ide_wait_stat(&startstop,drive,DRQ_STAT,BUSY_STAT,WAIT_READY)) {
- 		printk(KERN_ERR "ide-scsi: Strange, packet command "
- 			"initiated yet DRQ isn't asserted\n");
- 		return startstop;
+-	/* If the node is in the UNUSED state, and we are sending
+-	 * a reject, we are done with it.  Release driver reference
+-	 * count here.  The outstanding els will release its reference on
+-	 * completion and the node can be freed then.
+-	 */
+-	if (ndlp->nlp_state == NLP_STE_UNUSED_NODE)
+-		lpfc_nlp_put(ndlp);
+-
+ 	if (rc == IOCB_ERROR) {
+ 		lpfc_els_free_iocb(phba, elsiocb);
+ 		return 1;
+@@ -2642,7 +2851,10 @@ lpfc_els_disc_plogi(struct lpfc_vport *vport)
+ 			}
+ 		}
  	}
--	ireason.all	= HWIF(drive)->INB(IDE_IREASON_REG);
--	if (!ireason.b.cod || ireason.b.io) {
-+	ireason = hwif->INB(IDE_IREASON_REG);
-+	if ((ireason & CD) == 0 || (ireason & IO)) {
- 		printk(KERN_ERR "ide-scsi: (IO,CoD) != (0,1) while "
- 				"issuing a packet command\n");
- 		return ide_do_reset (drive);
-@@ -573,30 +574,26 @@ static ide_startstop_t idescsi_issue_pc (ide_drive_t *drive, idescsi_pc_t *pc)
- {
- 	idescsi_scsi_t *scsi = drive_to_idescsi(drive);
- 	ide_hwif_t *hwif = drive->hwif;
--	atapi_feature_t feature;
--	atapi_bcount_t bcount;
-+	u16 bcount;
-+	u8 dma = 0;
+-	if (sentplogi == 0) {
++	if (sentplogi) {
++		lpfc_set_disctmo(vport);
++	}
++	else {
+ 		spin_lock_irq(shost->host_lock);
+ 		vport->fc_flag &= ~FC_NLP_MORE;
+ 		spin_unlock_irq(shost->host_lock);
+@@ -2830,10 +3042,10 @@ lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
+ 			"RCV RSCN defer:  did:x%x/ste:x%x flg:x%x",
+ 			ndlp->nlp_DID, vport->port_state, ndlp->nlp_flag);
  
- 	scsi->pc=pc;							/* Set the current packet command */
- 	pc->actually_transferred=0;					/* We haven't transferred any data yet */
- 	pc->current_position=pc->buffer;
--	bcount.all = min(pc->request_transfer, 63 * 1024);		/* Request to transfer the entire buffer at once */
-+	/* Request to transfer the entire buffer at once */
-+	bcount = min(pc->request_transfer, 63 * 1024);
++		spin_lock_irq(shost->host_lock);
+ 		vport->fc_flag |= FC_RSCN_DEFERRED;
+ 		if ((rscn_cnt < FC_MAX_HOLD_RSCN) &&
+ 		    !(vport->fc_flag & FC_RSCN_DISCOVERY)) {
+-			spin_lock_irq(shost->host_lock);
+ 			vport->fc_flag |= FC_RSCN_MODE;
+ 			spin_unlock_irq(shost->host_lock);
+ 			if (rscn_cnt) {
+@@ -2862,7 +3074,6 @@ lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
+ 					 vport->fc_rscn_id_cnt, vport->fc_flag,
+ 					 vport->port_state);
+ 		} else {
+-			spin_lock_irq(shost->host_lock);
+ 			vport->fc_flag |= FC_RSCN_DISCOVERY;
+ 			spin_unlock_irq(shost->host_lock);
+ 			/* ReDiscovery RSCN */
+@@ -2877,7 +3088,9 @@ lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
  
--	feature.all = 0;
- 	if (drive->using_dma && !idescsi_map_sg(drive, pc)) {
- 		hwif->sg_mapped = 1;
--		feature.b.dma = !hwif->dma_setup(drive);
-+		dma = !hwif->dma_setup(drive);
- 		hwif->sg_mapped = 0;
+ 		/* send RECOVERY event for ALL nodes that match RSCN payload */
+ 		lpfc_rscn_recovery_check(vport);
++		spin_lock_irq(shost->host_lock);
+ 		vport->fc_flag &= ~FC_RSCN_DEFERRED;
++		spin_unlock_irq(shost->host_lock);
+ 		return 0;
  	}
  
- 	SELECT_DRIVE(drive);
--	if (IDE_CONTROL_REG)
--		HWIF(drive)->OUTB(drive->ctl, IDE_CONTROL_REG);
+@@ -2929,6 +3142,8 @@ lpfc_els_handle_rscn(struct lpfc_vport *vport)
  
--	HWIF(drive)->OUTB(feature.all, IDE_FEATURE_REG);
--	HWIF(drive)->OUTB(bcount.b.high, IDE_BCOUNTH_REG);
--	HWIF(drive)->OUTB(bcount.b.low, IDE_BCOUNTL_REG);
-+	ide_pktcmd_tf_load(drive, IDE_TFLAG_NO_SELECT_MASK, bcount, dma);
+ 	/* To process RSCN, first compare RSCN data with NameServer */
+ 	vport->fc_ns_retry = 0;
++	vport->num_disc_nodes = 0;
++
+ 	ndlp = lpfc_findnode_did(vport, NameServer_DID);
+ 	if (ndlp && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) {
+ 		/* Good ndlp, issue CT Request to NameServer */
+@@ -3022,8 +3237,7 @@ lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
+ 			mbox->mb.un.varInitLnk.lipsr_AL_PA = 0;
+ 			mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+ 			mbox->vport = vport;
+-			rc = lpfc_sli_issue_mbox
+-				(phba, mbox, (MBX_NOWAIT | MBX_STOP_IOCB));
++			rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
+ 			lpfc_set_loopback_flag(phba);
+ 			if (rc == MBX_NOT_FINISHED) {
+ 				mempool_free(mbox, phba->mbox_mem_pool);
+@@ -3140,7 +3354,10 @@ lpfc_els_rsp_rps_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
+ 	elsiocb = lpfc_prep_els_iocb(phba->pport, 0, cmdsize,
+ 				     lpfc_max_els_tries, ndlp,
+ 				     ndlp->nlp_DID, ELS_CMD_ACC);
++
++	/* Decrement the ndlp reference count from previous mbox command */
+ 	lpfc_nlp_put(ndlp);
++
+ 	if (!elsiocb)
+ 		return;
  
--	if (feature.b.dma)
-+	if (dma)
- 		set_bit(PC_DMA_OK, &pc->flags);
+@@ -3160,13 +3377,13 @@ lpfc_els_rsp_rps_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
+ 		status |= 0x4;
  
- 	if (test_bit(IDESCSI_DRQ_INTERRUPT, &scsi->flags)) {
-diff --git a/drivers/scsi/imm.c b/drivers/scsi/imm.c
-index a3d0c6b..f97d172 100644
---- a/drivers/scsi/imm.c
-+++ b/drivers/scsi/imm.c
-@@ -837,19 +837,16 @@ static int imm_engine(imm_struct *dev, struct scsi_cmnd *cmd)
+ 	rps_rsp->rsvd1 = 0;
+-	rps_rsp->portStatus = be16_to_cpu(status);
+-	rps_rsp->linkFailureCnt = be32_to_cpu(mb->un.varRdLnk.linkFailureCnt);
+-	rps_rsp->lossSyncCnt = be32_to_cpu(mb->un.varRdLnk.lossSyncCnt);
+-	rps_rsp->lossSignalCnt = be32_to_cpu(mb->un.varRdLnk.lossSignalCnt);
+-	rps_rsp->primSeqErrCnt = be32_to_cpu(mb->un.varRdLnk.primSeqErrCnt);
+-	rps_rsp->invalidXmitWord = be32_to_cpu(mb->un.varRdLnk.invalidXmitWord);
+-	rps_rsp->crcCnt = be32_to_cpu(mb->un.varRdLnk.crcCnt);
++	rps_rsp->portStatus = cpu_to_be16(status);
++	rps_rsp->linkFailureCnt = cpu_to_be32(mb->un.varRdLnk.linkFailureCnt);
++	rps_rsp->lossSyncCnt = cpu_to_be32(mb->un.varRdLnk.lossSyncCnt);
++	rps_rsp->lossSignalCnt = cpu_to_be32(mb->un.varRdLnk.lossSignalCnt);
++	rps_rsp->primSeqErrCnt = cpu_to_be32(mb->un.varRdLnk.primSeqErrCnt);
++	rps_rsp->invalidXmitWord = cpu_to_be32(mb->un.varRdLnk.invalidXmitWord);
++	rps_rsp->crcCnt = cpu_to_be32(mb->un.varRdLnk.crcCnt);
+ 	/* Xmit ELS RPS ACC response tag <ulpIoTag> */
+ 	lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_ELS,
+ 			 "0118 Xmit ELS RPS ACC response tag x%x xri x%x, "
+@@ -3223,11 +3440,13 @@ lpfc_els_rcv_rps(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
+ 			mbox->context2 = lpfc_nlp_get(ndlp);
+ 			mbox->vport = vport;
+ 			mbox->mbox_cmpl = lpfc_els_rsp_rps_acc;
+-			if (lpfc_sli_issue_mbox (phba, mbox,
+-			    (MBX_NOWAIT | MBX_STOP_IOCB)) != MBX_NOT_FINISHED)
++			if (lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT)
++				!= MBX_NOT_FINISHED)
+ 				/* Mbox completion will send ELS Response */
+ 				return 0;
+-
++			/* Decrement reference count used for the failed mbox
++			 * command.
++			 */
+ 			lpfc_nlp_put(ndlp);
+ 			mempool_free(mbox, phba->mbox_mem_pool);
+ 		}
+@@ -3461,6 +3680,7 @@ lpfc_els_rcv_fan(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
+ 					 * other NLP_FABRIC logins
+ 					 */
+ 					lpfc_drop_node(vport, ndlp);
++
+ 				} else if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) {
+ 					/* Fail outstanding I/O now since this
+ 					 * device is marked for PLOGI
+@@ -3469,8 +3689,6 @@ lpfc_els_rcv_fan(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
+ 				}
+ 			}
  
- 		/* Phase 4 - Setup scatter/gather buffers */
- 	case 4:
--		if (cmd->use_sg) {
--			/* if many buffers are available, start filling the first */
--			cmd->SCp.buffer =
--			    (struct scatterlist *) cmd->request_buffer;
-+		if (scsi_bufflen(cmd)) {
-+			cmd->SCp.buffer = scsi_sglist(cmd);
- 			cmd->SCp.this_residual = cmd->SCp.buffer->length;
- 			cmd->SCp.ptr = sg_virt(cmd->SCp.buffer);
- 		} else {
--			/* else fill the only available buffer */
- 			cmd->SCp.buffer = NULL;
--			cmd->SCp.this_residual = cmd->request_bufflen;
--			cmd->SCp.ptr = cmd->request_buffer;
-+			cmd->SCp.this_residual = 0;
-+			cmd->SCp.ptr = NULL;
+-			vport->port_state = LPFC_FLOGI;
+-			lpfc_set_disctmo(vport);
+ 			lpfc_initial_flogi(vport);
+ 			return 0;
  		}
--		cmd->SCp.buffers_residual = cmd->use_sg - 1;
-+		cmd->SCp.buffers_residual = scsi_sg_count(cmd) - 1;
- 		cmd->SCp.phase++;
- 		if (cmd->SCp.this_residual & 0x01)
- 			cmd->SCp.this_residual++;
-diff --git a/drivers/scsi/in2000.c b/drivers/scsi/in2000.c
-index c8b452f..8053b1e 100644
---- a/drivers/scsi/in2000.c
-+++ b/drivers/scsi/in2000.c
-@@ -369,16 +369,16 @@ static int in2000_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
-  *  - SCp.phase records this command's SRCID_ER bit setting
-  */
+@@ -3711,6 +3929,7 @@ static void
+ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
+ 		      struct lpfc_vport *vport, struct lpfc_iocbq *elsiocb)
+ {
++	struct Scsi_Host  *shost;
+ 	struct lpfc_nodelist *ndlp;
+ 	struct ls_rjt stat;
+ 	uint32_t *payload;
+@@ -3750,11 +3969,19 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
+ 			goto dropit;
  
--	if (cmd->use_sg) {
--		cmd->SCp.buffer = (struct scatterlist *) cmd->request_buffer;
--		cmd->SCp.buffers_residual = cmd->use_sg - 1;
-+	if (scsi_bufflen(cmd)) {
-+		cmd->SCp.buffer = scsi_sglist(cmd);
-+		cmd->SCp.buffers_residual = scsi_sg_count(cmd) - 1;
- 		cmd->SCp.ptr = sg_virt(cmd->SCp.buffer);
- 		cmd->SCp.this_residual = cmd->SCp.buffer->length;
- 	} else {
- 		cmd->SCp.buffer = NULL;
- 		cmd->SCp.buffers_residual = 0;
--		cmd->SCp.ptr = (char *) cmd->request_buffer;
--		cmd->SCp.this_residual = cmd->request_bufflen;
-+		cmd->SCp.ptr = NULL;
-+		cmd->SCp.this_residual = 0;
+ 		lpfc_nlp_init(vport, ndlp, did);
++		lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
+ 		newnode = 1;
+ 		if ((did & Fabric_DID_MASK) == Fabric_DID_MASK) {
+ 			ndlp->nlp_type |= NLP_FABRIC;
+ 		}
+-		lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE);
++	}
++	else {
++		if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) {
++			/* This is simular to the new node path */
++			lpfc_nlp_get(ndlp);
++			lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
++			newnode = 1;
++		}
  	}
- 	cmd->SCp.have_data_in = 0;
  
-diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c
-index 0841df0..73270ff 100644
---- a/drivers/scsi/ipr.c
-+++ b/drivers/scsi/ipr.c
-@@ -84,7 +84,7 @@
- /*
-  *   Global Data
-  */
--static struct list_head ipr_ioa_head = LIST_HEAD_INIT(ipr_ioa_head);
-+static LIST_HEAD(ipr_ioa_head);
- static unsigned int ipr_log_level = IPR_DEFAULT_LOG_LEVEL;
- static unsigned int ipr_max_speed = 1;
- static int ipr_testmode = 0;
-@@ -5142,6 +5142,7 @@ static void ipr_build_ata_ioadl(struct ipr_cmnd *ipr_cmd,
- 	struct ipr_ioadl_desc *last_ioadl = NULL;
- 	int len = qc->nbytes + qc->pad_len;
- 	struct scatterlist *sg;
-+	unsigned int si;
+ 	phba->fc_stat.elsRcvFrame++;
+@@ -3783,6 +4010,12 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
+ 			rjt_err = LSRJT_UNABLE_TPC;
+ 			break;
+ 		}
++
++		shost = lpfc_shost_from_vport(vport);
++		spin_lock_irq(shost->host_lock);
++		ndlp->nlp_flag &= ~NLP_TARGET_REMOVE;
++		spin_unlock_irq(shost->host_lock);
++
+ 		lpfc_disc_state_machine(vport, ndlp, elsiocb,
+ 					NLP_EVT_RCV_PLOGI);
  
- 	if (len == 0)
- 		return;
-@@ -5159,7 +5160,7 @@ static void ipr_build_ata_ioadl(struct ipr_cmnd *ipr_cmd,
- 			cpu_to_be32(sizeof(struct ipr_ioadl_desc) * ipr_cmd->dma_use_sg);
+@@ -3795,7 +4028,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
+ 		phba->fc_stat.elsRcvFLOGI++;
+ 		lpfc_els_rcv_flogi(vport, elsiocb, ndlp);
+ 		if (newnode)
+-			lpfc_drop_node(vport, ndlp);
++			lpfc_nlp_put(ndlp);
+ 		break;
+ 	case ELS_CMD_LOGO:
+ 		lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
+@@ -3825,7 +4058,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
+ 		phba->fc_stat.elsRcvRSCN++;
+ 		lpfc_els_rcv_rscn(vport, elsiocb, ndlp);
+ 		if (newnode)
+-			lpfc_drop_node(vport, ndlp);
++			lpfc_nlp_put(ndlp);
+ 		break;
+ 	case ELS_CMD_ADISC:
+ 		lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
+@@ -3897,7 +4130,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
+ 		phba->fc_stat.elsRcvLIRR++;
+ 		lpfc_els_rcv_lirr(vport, elsiocb, ndlp);
+ 		if (newnode)
+-			lpfc_drop_node(vport, ndlp);
++			lpfc_nlp_put(ndlp);
+ 		break;
+ 	case ELS_CMD_RPS:
+ 		lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
+@@ -3907,7 +4140,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
+ 		phba->fc_stat.elsRcvRPS++;
+ 		lpfc_els_rcv_rps(vport, elsiocb, ndlp);
+ 		if (newnode)
+-			lpfc_drop_node(vport, ndlp);
++			lpfc_nlp_put(ndlp);
+ 		break;
+ 	case ELS_CMD_RPL:
+ 		lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
+@@ -3917,7 +4150,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
+ 		phba->fc_stat.elsRcvRPL++;
+ 		lpfc_els_rcv_rpl(vport, elsiocb, ndlp);
+ 		if (newnode)
+-			lpfc_drop_node(vport, ndlp);
++			lpfc_nlp_put(ndlp);
+ 		break;
+ 	case ELS_CMD_RNID:
+ 		lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
+@@ -3927,7 +4160,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
+ 		phba->fc_stat.elsRcvRNID++;
+ 		lpfc_els_rcv_rnid(vport, elsiocb, ndlp);
+ 		if (newnode)
+-			lpfc_drop_node(vport, ndlp);
++			lpfc_nlp_put(ndlp);
+ 		break;
+ 	default:
+ 		lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
+@@ -3942,7 +4175,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
+ 				 "0115 Unknown ELS command x%x "
+ 				 "received from NPORT x%x\n", cmd, did);
+ 		if (newnode)
+-			lpfc_drop_node(vport, ndlp);
++			lpfc_nlp_put(ndlp);
+ 		break;
  	}
  
--	ata_for_each_sg(sg, qc) {
-+	for_each_sg(qc->sg, sg, qc->n_elem, si) {
- 		ioadl->flags_and_data_len = cpu_to_be32(ioadl_flags | sg_dma_len(sg));
- 		ioadl->address = cpu_to_be32(sg_dma_address(sg));
- 
-@@ -5222,12 +5223,12 @@ static unsigned int ipr_qc_issue(struct ata_queued_cmd *qc)
- 		regs->flags |= IPR_ATA_FLAG_XFER_TYPE_DMA;
- 		break;
+@@ -3958,10 +4191,11 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
+ 	return;
  
--	case ATA_PROT_ATAPI:
--	case ATA_PROT_ATAPI_NODATA:
-+	case ATAPI_PROT_PIO:
-+	case ATAPI_PROT_NODATA:
- 		regs->flags |= IPR_ATA_FLAG_PACKET_CMD;
- 		break;
+ dropit:
+-	lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
++	if (vport && !(vport->load_flag & FC_UNLOADING))
++		lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
+ 			"(%d):0111 Dropping received ELS cmd "
+ 			"Data: x%x x%x x%x\n",
+-			vport ? vport->vpi : 0xffff, icmd->ulpStatus,
++			vport->vpi, icmd->ulpStatus,
+ 			icmd->un.ulpWord[4], icmd->ulpTimeout);
+ 	phba->fc_stat.elsRcvDrop++;
+ }
+@@ -4114,8 +4348,9 @@ lpfc_cmpl_reg_new_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
+ 	struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) pmb->context2;
+ 	MAILBOX_t *mb = &pmb->mb;
  
--	case ATA_PROT_ATAPI_DMA:
-+	case ATAPI_PROT_DMA:
- 		regs->flags |= IPR_ATA_FLAG_PACKET_CMD;
- 		regs->flags |= IPR_ATA_FLAG_XFER_TYPE_DMA;
- 		break;
-diff --git a/drivers/scsi/ips.c b/drivers/scsi/ips.c
-index 5c5a9b2..7505cca 100644
---- a/drivers/scsi/ips.c
-+++ b/drivers/scsi/ips.c
-@@ -389,17 +389,17 @@ static struct  pci_device_id  ips_pci_table[] = {
- MODULE_DEVICE_TABLE( pci, ips_pci_table );
++	spin_lock_irq(shost->host_lock);
+ 	vport->fc_flag &= ~FC_VPORT_NEEDS_REG_VPI;
+-	lpfc_nlp_put(ndlp);
++	spin_unlock_irq(shost->host_lock);
  
- static char ips_hot_plug_name[] = "ips";
--   
-+
- static int __devinit  ips_insert_device(struct pci_dev *pci_dev, const struct pci_device_id *ent);
- static void __devexit ips_remove_device(struct pci_dev *pci_dev);
--   
+ 	if (mb->mbxStatus) {
+ 		lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX,
+@@ -4135,7 +4370,9 @@ lpfc_cmpl_reg_new_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
+ 		default:
+ 			/* Try to recover from this error */
+ 			lpfc_mbx_unreg_vpi(vport);
++			spin_lock_irq(shost->host_lock);
+ 			vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
++			spin_unlock_irq(shost->host_lock);
+ 			lpfc_initial_fdisc(vport);
+ 			break;
+ 		}
+@@ -4146,14 +4383,21 @@ lpfc_cmpl_reg_new_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
+ 		else
+ 			lpfc_do_scr_ns_plogi(phba, vport);
+ 	}
 +
- static struct pci_driver ips_pci_driver = {
- 	.name		= ips_hot_plug_name,
- 	.id_table	= ips_pci_table,
- 	.probe		= ips_insert_device,
- 	.remove		= __devexit_p(ips_remove_device),
- };
--           
++	/* Now, we decrement the ndlp reference count held for this
++	 * callback function
++	 */
++	lpfc_nlp_put(ndlp);
 +
+ 	mempool_free(pmb, phba->mbox_mem_pool);
+ 	return;
+ }
  
- /*
-  * Necessary forward function protoypes
-@@ -587,7 +587,7 @@ static void
- ips_setup_funclist(ips_ha_t * ha)
+-void
++static void
+ lpfc_register_new_vport(struct lpfc_hba *phba, struct lpfc_vport *vport,
+ 			struct lpfc_nodelist *ndlp)
  {
++	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+ 	LPFC_MBOXQ_t *mbox;
  
--	/*                                
-+	/*
- 	 * Setup Functions
- 	 */
- 	if (IPS_IS_MORPHEUS(ha) || IPS_IS_MARCO(ha)) {
-@@ -702,12 +702,8 @@ ips_release(struct Scsi_Host *sh)
- 	/* free extra memory */
- 	ips_free(ha);
+ 	mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+@@ -4162,25 +4406,31 @@ lpfc_register_new_vport(struct lpfc_hba *phba, struct lpfc_vport *vport,
+ 		mbox->vport = vport;
+ 		mbox->context2 = lpfc_nlp_get(ndlp);
+ 		mbox->mbox_cmpl = lpfc_cmpl_reg_new_vport;
+-		if (lpfc_sli_issue_mbox(phba, mbox,
+-					MBX_NOWAIT | MBX_STOP_IOCB)
++		if (lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT)
+ 		    == MBX_NOT_FINISHED) {
++			/* mailbox command not success, decrement ndlp
++			 * reference count for this command
++			 */
++			lpfc_nlp_put(ndlp);
+ 			mempool_free(mbox, phba->mbox_mem_pool);
+-			vport->fc_flag &= ~FC_VPORT_NEEDS_REG_VPI;
  
--	/* Free I/O Region */
--	if (ha->io_addr)
--		release_region(ha->io_addr, ha->io_len);
+-			lpfc_vport_set_state(vport, FC_VPORT_FAILED);
+ 			lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX,
+ 				"0253 Register VPI: Can't send mbox\n");
++			goto mbox_err_exit;
+ 		}
+ 	} else {
+-		lpfc_vport_set_state(vport, FC_VPORT_FAILED);
 -
- 	/* free IRQ */
--	free_irq(ha->irq, ha);
-+	free_irq(ha->pcidev->irq, ha);
- 
- 	scsi_host_put(sh);
+ 		lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX,
+ 				 "0254 Register VPI: no memory\n");
+-
+-		vport->fc_flag &= ~FC_VPORT_NEEDS_REG_VPI;
+-		lpfc_nlp_put(ndlp);
++		goto mbox_err_exit;
+ 	}
++	return;
++
++mbox_err_exit:
++	lpfc_vport_set_state(vport, FC_VPORT_FAILED);
++	spin_lock_irq(shost->host_lock);
++	vport->fc_flag &= ~FC_VPORT_NEEDS_REG_VPI;
++	spin_unlock_irq(shost->host_lock);
++	return;
+ }
  
-@@ -1637,7 +1633,7 @@ ips_make_passthru(ips_ha_t *ha, struct scsi_cmnd *SC, ips_scb_t *scb, int intr)
- 				return (IPS_FAILURE);
+ static void
+@@ -4251,7 +4501,9 @@ lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+ 				lpfc_unreg_rpi(vport, np);
  			}
+ 			lpfc_mbx_unreg_vpi(vport);
++			spin_lock_irq(shost->host_lock);
+ 			vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
++			spin_unlock_irq(shost->host_lock);
+ 		}
  
--			if (ha->device_id == IPS_DEVICEID_COPPERHEAD &&
-+			if (ha->pcidev->device == IPS_DEVICEID_COPPERHEAD &&
- 			    pt->CoppCP.cmd.flashfw.op_code ==
- 			    IPS_CMD_RW_BIOSFW) {
- 				ret = ips_flash_copperhead(ha, pt, scb);
-@@ -2021,7 +2017,7 @@ ips_cleanup_passthru(ips_ha_t * ha, ips_scb_t * scb)
- 	pt->ExtendedStatus = scb->extended_status;
- 	pt->AdapterType = ha->ad_type;
+ 		if (vport->fc_flag & FC_VPORT_NEEDS_REG_VPI)
+@@ -4259,14 +4511,15 @@ lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+ 		else
+ 			lpfc_do_scr_ns_plogi(phba, vport);
  
--	if (ha->device_id == IPS_DEVICEID_COPPERHEAD &&
-+	if (ha->pcidev->device == IPS_DEVICEID_COPPERHEAD &&
- 	    (scb->cmd.flashfw.op_code == IPS_CMD_DOWNLOAD ||
- 	     scb->cmd.flashfw.op_code == IPS_CMD_RW_BIOSFW))
- 		ips_free_flash_copperhead(ha);
-@@ -2075,13 +2071,13 @@ ips_host_info(ips_ha_t * ha, char *ptr, off_t offset, int len)
- 			  ha->mem_ptr);
+-		lpfc_nlp_put(ndlp); /* Free Fabric ndlp for vports */
++		/* Unconditionaly kick off releasing fabric node for vports */
++		lpfc_nlp_put(ndlp);
  	}
  
--	copy_info(&info, "\tIRQ number                        : %d\n", ha->irq);
-+	copy_info(&info, "\tIRQ number                        : %d\n", ha->pcidev->irq);
- 
-     /* For the Next 3 lines Check for Binary 0 at the end and don't include it if it's there. */
-     /* That keeps everything happy for "text" operations on the proc file.                    */
+ out:
+ 	lpfc_els_free_iocb(phba, cmdiocb);
+ }
  
- 	if (le32_to_cpu(ha->nvram->signature) == IPS_NVRAM_P5_SIG) {
--        if (ha->nvram->bios_low[3] == 0) { 
-+	if (ha->nvram->bios_low[3] == 0) {
-             copy_info(&info,
- 			          "\tBIOS Version                      : %c%c%c%c%c%c%c\n",
- 			          ha->nvram->bios_high[0], ha->nvram->bios_high[1],
-@@ -2232,31 +2228,31 @@ ips_identify_controller(ips_ha_t * ha)
+-int
++static int
+ lpfc_issue_els_fdisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ 		     uint8_t retry)
  {
- 	METHOD_TRACE("ips_identify_controller", 1);
- 
--	switch (ha->device_id) {
-+	switch (ha->pcidev->device) {
- 	case IPS_DEVICEID_COPPERHEAD:
--		if (ha->revision_id <= IPS_REVID_SERVERAID) {
-+		if (ha->pcidev->revision <= IPS_REVID_SERVERAID) {
- 			ha->ad_type = IPS_ADTYPE_SERVERAID;
--		} else if (ha->revision_id == IPS_REVID_SERVERAID2) {
-+		} else if (ha->pcidev->revision == IPS_REVID_SERVERAID2) {
- 			ha->ad_type = IPS_ADTYPE_SERVERAID2;
--		} else if (ha->revision_id == IPS_REVID_NAVAJO) {
-+		} else if (ha->pcidev->revision == IPS_REVID_NAVAJO) {
- 			ha->ad_type = IPS_ADTYPE_NAVAJO;
--		} else if ((ha->revision_id == IPS_REVID_SERVERAID2)
-+		} else if ((ha->pcidev->revision == IPS_REVID_SERVERAID2)
- 			   && (ha->slot_num == 0)) {
- 			ha->ad_type = IPS_ADTYPE_KIOWA;
--		} else if ((ha->revision_id >= IPS_REVID_CLARINETP1) &&
--			   (ha->revision_id <= IPS_REVID_CLARINETP3)) {
-+		} else if ((ha->pcidev->revision >= IPS_REVID_CLARINETP1) &&
-+			   (ha->pcidev->revision <= IPS_REVID_CLARINETP3)) {
- 			if (ha->enq->ucMaxPhysicalDevices == 15)
- 				ha->ad_type = IPS_ADTYPE_SERVERAID3L;
- 			else
- 				ha->ad_type = IPS_ADTYPE_SERVERAID3;
--		} else if ((ha->revision_id >= IPS_REVID_TROMBONE32) &&
--			   (ha->revision_id <= IPS_REVID_TROMBONE64)) {
-+		} else if ((ha->pcidev->revision >= IPS_REVID_TROMBONE32) &&
-+			   (ha->pcidev->revision <= IPS_REVID_TROMBONE64)) {
- 			ha->ad_type = IPS_ADTYPE_SERVERAID4H;
- 		}
- 		break;
+@@ -4539,7 +4792,7 @@ lpfc_cmpl_fabric_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+ 	}
+ }
  
- 	case IPS_DEVICEID_MORPHEUS:
--		switch (ha->subdevice_id) {
-+		switch (ha->pcidev->subsystem_device) {
- 		case IPS_SUBDEVICEID_4L:
- 			ha->ad_type = IPS_ADTYPE_SERVERAID4L;
- 			break;
-@@ -2285,7 +2281,7 @@ ips_identify_controller(ips_ha_t * ha)
- 		break;
+-int
++static int
+ lpfc_issue_fabric_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *iocb)
+ {
+ 	unsigned long iflags;
+@@ -4583,7 +4836,7 @@ lpfc_issue_fabric_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *iocb)
+ }
  
- 	case IPS_DEVICEID_MARCO:
--		switch (ha->subdevice_id) {
-+		switch (ha->pcidev->subsystem_device) {
- 		case IPS_SUBDEVICEID_6M:
- 			ha->ad_type = IPS_ADTYPE_SERVERAID6M;
- 			break;
-@@ -2332,20 +2328,20 @@ ips_get_bios_version(ips_ha_t * ha, int intr)
  
- 	strncpy(ha->bios_version, "       ?", 8);
+-void lpfc_fabric_abort_vport(struct lpfc_vport *vport)
++static void lpfc_fabric_abort_vport(struct lpfc_vport *vport)
+ {
+ 	LIST_HEAD(completions);
+ 	struct lpfc_hba  *phba = vport->phba;
+@@ -4663,6 +4916,7 @@ void lpfc_fabric_abort_hba(struct lpfc_hba *phba)
+ }
  
--	if (ha->device_id == IPS_DEVICEID_COPPERHEAD) {
-+	if (ha->pcidev->device == IPS_DEVICEID_COPPERHEAD) {
- 		if (IPS_USE_MEMIO(ha)) {
- 			/* Memory Mapped I/O */
  
- 			/* test 1st byte */
- 			writel(0, ha->mem_ptr + IPS_REG_FLAP);
--			if (ha->revision_id == IPS_REVID_TROMBONE64)
-+			if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
- 				udelay(25);	/* 25 us */
++#if 0
+ void lpfc_fabric_abort_flogi(struct lpfc_hba *phba)
+ {
+ 	LIST_HEAD(completions);
+@@ -4693,5 +4947,6 @@ void lpfc_fabric_abort_flogi(struct lpfc_hba *phba)
+ 		(piocb->iocb_cmpl) (phba, piocb, piocb);
+ 	}
+ }
++#endif  /*  0  */
  
- 			if (readb(ha->mem_ptr + IPS_REG_FLDP) != 0x55)
- 				return;
  
- 			writel(1, ha->mem_ptr + IPS_REG_FLAP);
--			if (ha->revision_id == IPS_REVID_TROMBONE64)
-+			if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
- 				udelay(25);	/* 25 us */
+diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c
+index c81c2b3..dc042bd 100644
+--- a/drivers/scsi/lpfc/lpfc_hbadisc.c
++++ b/drivers/scsi/lpfc/lpfc_hbadisc.c
+@@ -57,6 +57,7 @@ static uint8_t lpfcAlpaArray[] = {
+ };
  
- 			if (readb(ha->mem_ptr + IPS_REG_FLDP) != 0xAA)
-@@ -2353,20 +2349,20 @@ ips_get_bios_version(ips_ha_t * ha, int intr)
+ static void lpfc_disc_timeout_handler(struct lpfc_vport *);
++static void lpfc_disc_flush_list(struct lpfc_vport *vport);
  
- 			/* Get Major version */
- 			writel(0x1FF, ha->mem_ptr + IPS_REG_FLAP);
--			if (ha->revision_id == IPS_REVID_TROMBONE64)
-+			if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
- 				udelay(25);	/* 25 us */
+ void
+ lpfc_terminate_rport_io(struct fc_rport *rport)
+@@ -107,20 +108,14 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport)
+ 	struct lpfc_nodelist * ndlp;
+ 	struct lpfc_vport *vport;
+ 	struct lpfc_hba   *phba;
+-	struct completion devloss_compl;
+ 	struct lpfc_work_evt *evtp;
++	int  put_node;
++	int  put_rport;
  
- 			major = readb(ha->mem_ptr + IPS_REG_FLDP);
+ 	rdata = rport->dd_data;
+ 	ndlp = rdata->pnode;
+-
+-	if (!ndlp) {
+-		if (rport->scsi_target_id != -1) {
+-			printk(KERN_ERR "Cannot find remote node"
+-				" for rport in dev_loss_tmo_callbk x%x\n",
+-				rport->port_id);
+-		}
++	if (!ndlp)
+ 		return;
+-	}
  
- 			/* Get Minor version */
- 			writel(0x1FE, ha->mem_ptr + IPS_REG_FLAP);
--			if (ha->revision_id == IPS_REVID_TROMBONE64)
-+			if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
- 				udelay(25);	/* 25 us */
- 			minor = readb(ha->mem_ptr + IPS_REG_FLDP);
+ 	vport = ndlp->vport;
+ 	phba  = vport->phba;
+@@ -129,15 +124,35 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport)
+ 		"rport devlosscb: sid:x%x did:x%x flg:x%x",
+ 		ndlp->nlp_sid, ndlp->nlp_DID, ndlp->nlp_flag);
  
- 			/* Get SubMinor version */
- 			writel(0x1FD, ha->mem_ptr + IPS_REG_FLAP);
--			if (ha->revision_id == IPS_REVID_TROMBONE64)
-+			if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
- 				udelay(25);	/* 25 us */
- 			subminor = readb(ha->mem_ptr + IPS_REG_FLDP);
+-	init_completion(&devloss_compl);
++	/* Don't defer this if we are in the process of deleting the vport
++	 * or unloading the driver. The unload will cleanup the node
++	 * appropriately we just need to cleanup the ndlp rport info here.
++	 */
++	if (vport->load_flag & FC_UNLOADING) {
++		put_node = rdata->pnode != NULL;
++		put_rport = ndlp->rport != NULL;
++		rdata->pnode = NULL;
++		ndlp->rport = NULL;
++		if (put_node)
++			lpfc_nlp_put(ndlp);
++		if (put_rport)
++			put_device(&rport->dev);
++		return;
++	}
++
++	if (ndlp->nlp_state == NLP_STE_MAPPED_NODE)
++		return;
++
+ 	evtp = &ndlp->dev_loss_evt;
  
-@@ -2375,14 +2371,14 @@ ips_get_bios_version(ips_ha_t * ha, int intr)
+ 	if (!list_empty(&evtp->evt_listp))
+ 		return;
  
- 			/* test 1st byte */
- 			outl(0, ha->io_addr + IPS_REG_FLAP);
--			if (ha->revision_id == IPS_REVID_TROMBONE64)
-+			if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
- 				udelay(25);	/* 25 us */
+ 	spin_lock_irq(&phba->hbalock);
+-	evtp->evt_arg1  = ndlp;
+-	evtp->evt_arg2  = &devloss_compl;
++	/* We need to hold the node by incrementing the reference
++	 * count until this queued work is done
++	 */
++	evtp->evt_arg1  = lpfc_nlp_get(ndlp);
+ 	evtp->evt       = LPFC_EVT_DEV_LOSS;
+ 	list_add_tail(&evtp->evt_listp, &phba->work_list);
+ 	if (phba->work_wait)
+@@ -145,8 +160,6 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport)
  
- 			if (inb(ha->io_addr + IPS_REG_FLDP) != 0x55)
- 				return;
+ 	spin_unlock_irq(&phba->hbalock);
  
- 			outl(cpu_to_le32(1), ha->io_addr + IPS_REG_FLAP);
--			if (ha->revision_id == IPS_REVID_TROMBONE64)
-+			if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
- 				udelay(25);	/* 25 us */
+-	wait_for_completion(&devloss_compl);
+-
+ 	return;
+ }
  
- 			if (inb(ha->io_addr + IPS_REG_FLDP) != 0xAA)
-@@ -2390,21 +2386,21 @@ ips_get_bios_version(ips_ha_t * ha, int intr)
+@@ -154,7 +167,7 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport)
+  * This function is called from the worker thread when dev_loss_tmo
+  * expire.
+  */
+-void
++static void
+ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp)
+ {
+ 	struct lpfc_rport_data *rdata;
+@@ -162,6 +175,8 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp)
+ 	struct lpfc_vport *vport;
+ 	struct lpfc_hba   *phba;
+ 	uint8_t *name;
++	int  put_node;
++	int  put_rport;
+ 	int warn_on = 0;
  
- 			/* Get Major version */
- 			outl(cpu_to_le32(0x1FF), ha->io_addr + IPS_REG_FLAP);
--			if (ha->revision_id == IPS_REVID_TROMBONE64)
-+			if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
- 				udelay(25);	/* 25 us */
+ 	rport = ndlp->rport;
+@@ -178,14 +193,32 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp)
+ 		"rport devlosstmo:did:x%x type:x%x id:x%x",
+ 		ndlp->nlp_DID, ndlp->nlp_type, rport->scsi_target_id);
  
- 			major = inb(ha->io_addr + IPS_REG_FLDP);
+-	if (!(vport->load_flag & FC_UNLOADING) &&
+-	    ndlp->nlp_state == NLP_STE_MAPPED_NODE)
++	/* Don't defer this if we are in the process of deleting the vport
++	 * or unloading the driver. The unload will cleanup the node
++	 * appropriately we just need to cleanup the ndlp rport info here.
++	 */
++	if (vport->load_flag & FC_UNLOADING) {
++		if (ndlp->nlp_sid != NLP_NO_SID) {
++			/* flush the target */
++			lpfc_sli_abort_iocb(vport,
++					&phba->sli.ring[phba->sli.fcp_ring],
++					ndlp->nlp_sid, 0, LPFC_CTX_TGT);
++		}
++		put_node = rdata->pnode != NULL;
++		put_rport = ndlp->rport != NULL;
++		rdata->pnode = NULL;
++		ndlp->rport = NULL;
++		if (put_node)
++			lpfc_nlp_put(ndlp);
++		if (put_rport)
++			put_device(&rport->dev);
+ 		return;
++	}
  
- 			/* Get Minor version */
- 			outl(cpu_to_le32(0x1FE), ha->io_addr + IPS_REG_FLAP);
--			if (ha->revision_id == IPS_REVID_TROMBONE64)
-+			if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
- 				udelay(25);	/* 25 us */
+-	if (ndlp->nlp_type & NLP_FABRIC) {
+-		int  put_node;
+-		int  put_rport;
++	if (ndlp->nlp_state == NLP_STE_MAPPED_NODE)
++		return;
  
- 			minor = inb(ha->io_addr + IPS_REG_FLDP);
++	if (ndlp->nlp_type & NLP_FABRIC) {
+ 		/* We will clean up these Nodes in linkup */
+ 		put_node = rdata->pnode != NULL;
+ 		put_rport = ndlp->rport != NULL;
+@@ -227,23 +260,20 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp)
+ 				 ndlp->nlp_state, ndlp->nlp_rpi);
+ 	}
  
- 			/* Get SubMinor version */
- 			outl(cpu_to_le32(0x1FD), ha->io_addr + IPS_REG_FLAP);
--			if (ha->revision_id == IPS_REVID_TROMBONE64)
-+			if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
- 				udelay(25);	/* 25 us */
++	put_node = rdata->pnode != NULL;
++	put_rport = ndlp->rport != NULL;
++	rdata->pnode = NULL;
++	ndlp->rport = NULL;
++	if (put_node)
++		lpfc_nlp_put(ndlp);
++	if (put_rport)
++		put_device(&rport->dev);
++
+ 	if (!(vport->load_flag & FC_UNLOADING) &&
+ 	    !(ndlp->nlp_flag & NLP_DELAY_TMO) &&
+ 	    !(ndlp->nlp_flag & NLP_NPR_2B_DISC) &&
+-	    (ndlp->nlp_state != NLP_STE_UNMAPPED_NODE))
++	    (ndlp->nlp_state != NLP_STE_UNMAPPED_NODE)) {
+ 		lpfc_disc_state_machine(vport, ndlp, NULL, NLP_EVT_DEVICE_RM);
+-	else {
+-		int  put_node;
+-		int  put_rport;
+-
+-		put_node = rdata->pnode != NULL;
+-		put_rport = ndlp->rport != NULL;
+-		rdata->pnode = NULL;
+-		ndlp->rport = NULL;
+-		if (put_node)
+-			lpfc_nlp_put(ndlp);
+-		if (put_rport)
+-			put_device(&rport->dev);
+ 	}
+ }
  
- 			subminor = inb(ha->io_addr + IPS_REG_FLDP);
-@@ -2740,8 +2736,6 @@ ips_next(ips_ha_t * ha, int intr)
- 		SC->result = DID_OK;
- 		SC->host_scribble = NULL;
+@@ -260,7 +290,6 @@ lpfc_work_list_done(struct lpfc_hba *phba)
+ {
+ 	struct lpfc_work_evt  *evtp = NULL;
+ 	struct lpfc_nodelist  *ndlp;
+-	struct lpfc_vport     *vport;
+ 	int free_evt;
  
--		memset(SC->sense_buffer, 0, sizeof (SC->sense_buffer));
+ 	spin_lock_irq(&phba->hbalock);
+@@ -270,35 +299,22 @@ lpfc_work_list_done(struct lpfc_hba *phba)
+ 		spin_unlock_irq(&phba->hbalock);
+ 		free_evt = 1;
+ 		switch (evtp->evt) {
+-		case LPFC_EVT_DEV_LOSS_DELAY:
+-			free_evt = 0; /* evt is part of ndlp */
+-			ndlp = (struct lpfc_nodelist *) (evtp->evt_arg1);
+-			vport = ndlp->vport;
+-			if (!vport)
+-				break;
 -
- 		scb->target_id = SC->device->id;
- 		scb->lun = SC->device->lun;
- 		scb->bus = SC->device->channel;
-@@ -2780,10 +2774,11 @@ ips_next(ips_ha_t * ha, int intr)
- 		scb->dcdb.cmd_attribute =
- 		    ips_command_direction[scb->scsi_cmd->cmnd[0]];
+-			lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_RPORT,
+-				"rport devlossdly:did:x%x flg:x%x",
+-				ndlp->nlp_DID, ndlp->nlp_flag, 0);
+-
+-			if (!(vport->load_flag & FC_UNLOADING) &&
+-			    !(ndlp->nlp_flag & NLP_DELAY_TMO) &&
+-			    !(ndlp->nlp_flag & NLP_NPR_2B_DISC)) {
+-				lpfc_disc_state_machine(vport, ndlp, NULL,
+-					NLP_EVT_DEVICE_RM);
+-			}
+-			break;
+ 		case LPFC_EVT_ELS_RETRY:
+ 			ndlp = (struct lpfc_nodelist *) (evtp->evt_arg1);
+ 			lpfc_els_retry_delay_handler(ndlp);
+ 			free_evt = 0; /* evt is part of ndlp */
++			/* decrement the node reference count held
++			 * for this queued work
++			 */
++			lpfc_nlp_put(ndlp);
+ 			break;
+ 		case LPFC_EVT_DEV_LOSS:
+ 			ndlp = (struct lpfc_nodelist *)(evtp->evt_arg1);
+-			lpfc_nlp_get(ndlp);
+ 			lpfc_dev_loss_tmo_handler(ndlp);
+ 			free_evt = 0;
+-			complete((struct completion *)(evtp->evt_arg2));
++			/* decrement the node reference count held for
++			 * this queued work
++			 */
+ 			lpfc_nlp_put(ndlp);
+ 			break;
+ 		case LPFC_EVT_ONLINE:
+@@ -373,7 +389,7 @@ lpfc_work_done(struct lpfc_hba *phba)
+ 		lpfc_handle_latt(phba);
+ 	vports = lpfc_create_vport_work_array(phba);
+ 	if (vports != NULL)
+-		for(i = 0; i < LPFC_MAX_VPORTS; i++) {
++		for(i = 0; i <= phba->max_vpi; i++) {
+ 			/*
+ 			 * We could have no vports in array if unloading, so if
+ 			 * this happens then just use the pport
+@@ -405,14 +421,14 @@ lpfc_work_done(struct lpfc_hba *phba)
+ 			vport->work_port_events &= ~work_port_events;
+ 			spin_unlock_irq(&vport->work_port_lock);
+ 		}
+-	lpfc_destroy_vport_work_array(vports);
++	lpfc_destroy_vport_work_array(phba, vports);
  
--        /* Allow a WRITE BUFFER Command to Have no Data */
--        /* This is Used by Tape Flash Utilites          */
--        if ((scb->scsi_cmd->cmnd[0] == WRITE_BUFFER) && (scb->data_len == 0)) 
--            scb->dcdb.cmd_attribute = 0;                  
-+		/* Allow a WRITE BUFFER Command to Have no Data */
-+		/* This is Used by Tape Flash Utilites          */
-+		if ((scb->scsi_cmd->cmnd[0] == WRITE_BUFFER) &&
-+				(scb->data_len == 0))
-+			scb->dcdb.cmd_attribute = 0;
+ 	pring = &phba->sli.ring[LPFC_ELS_RING];
+ 	status = (ha_copy & (HA_RXMASK  << (4*LPFC_ELS_RING)));
+ 	status >>= (4*LPFC_ELS_RING);
+ 	if ((status & HA_RXMASK)
+ 		|| (pring->flag & LPFC_DEFERRED_RING_EVENT)) {
+-		if (pring->flag & LPFC_STOP_IOCB_MASK) {
++		if (pring->flag & LPFC_STOP_IOCB_EVENT) {
+ 			pring->flag |= LPFC_DEFERRED_RING_EVENT;
+ 		} else {
+ 			lpfc_sli_handle_slow_ring_event(phba, pring,
+@@ -544,6 +560,7 @@ lpfc_workq_post_event(struct lpfc_hba *phba, void *arg1, void *arg2,
+ void
+ lpfc_cleanup_rpis(struct lpfc_vport *vport, int remove)
+ {
++	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+ 	struct lpfc_hba  *phba = vport->phba;
+ 	struct lpfc_nodelist *ndlp, *next_ndlp;
+ 	int  rc;
+@@ -552,7 +569,9 @@ lpfc_cleanup_rpis(struct lpfc_vport *vport, int remove)
+ 		if (ndlp->nlp_state == NLP_STE_UNUSED_NODE)
+ 			continue;
  
- 		if (!(scb->dcdb.cmd_attribute & 0x3))
- 			scb->dcdb.transfer_length = 0;
-@@ -3404,7 +3399,7 @@ ips_map_status(ips_ha_t * ha, ips_scb_t * scb, ips_stat_t * sp)
+-		if (phba->sli3_options & LPFC_SLI3_VPORT_TEARDOWN)
++		if ((phba->sli3_options & LPFC_SLI3_VPORT_TEARDOWN) ||
++			((vport->port_type == LPFC_NPIV_PORT) &&
++			(ndlp->nlp_DID == NameServer_DID)))
+ 			lpfc_unreg_rpi(vport, ndlp);
  
- 				/* Restrict access to physical DASD */
- 				if (scb->scsi_cmd->cmnd[0] == INQUIRY) {
--				    ips_scmd_buf_read(scb->scsi_cmd, 
-+				    ips_scmd_buf_read(scb->scsi_cmd,
-                                       &inquiryData, sizeof (inquiryData));
-  				    if ((inquiryData.DeviceType & 0x1f) == TYPE_DISK) {
- 				        errcode = DID_TIME_OUT;
-@@ -3438,13 +3433,11 @@ ips_map_status(ips_ha_t * ha, ips_scb_t * scb, ips_stat_t * sp)
- 					    (IPS_DCDB_TABLE_TAPE *) & scb->dcdb;
- 					memcpy(scb->scsi_cmd->sense_buffer,
- 					       tapeDCDB->sense_info,
--					       sizeof (scb->scsi_cmd->
--						       sense_buffer));
-+					       SCSI_SENSE_BUFFERSIZE);
- 				} else {
- 					memcpy(scb->scsi_cmd->sense_buffer,
- 					       scb->dcdb.sense_info,
--					       sizeof (scb->scsi_cmd->
--						       sense_buffer));
-+					       SCSI_SENSE_BUFFERSIZE);
- 				}
- 				device_error = 2;	/* check condition */
- 			}
-@@ -3824,7 +3817,6 @@ ips_send_cmd(ips_ha_t * ha, ips_scb_t * scb)
- 			/* attempted, a Check Condition occurred, and Sense   */
- 			/* Data indicating an Invalid CDB OpCode is returned. */
- 			sp = (char *) scb->scsi_cmd->sense_buffer;
--			memset(sp, 0, sizeof (scb->scsi_cmd->sense_buffer));
+ 		/* Leave Fabric nodes alone on link down */
+@@ -565,14 +584,30 @@ lpfc_cleanup_rpis(struct lpfc_vport *vport, int remove)
+ 	}
+ 	if (phba->sli3_options & LPFC_SLI3_VPORT_TEARDOWN) {
+ 		lpfc_mbx_unreg_vpi(vport);
++		spin_lock_irq(shost->host_lock);
+ 		vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
++		spin_unlock_irq(shost->host_lock);
+ 	}
+ }
  
- 			sp[0] = 0x70;	/* Error Code               */
- 			sp[2] = ILLEGAL_REQUEST;	/* Sense Key 5 Illegal Req. */
-@@ -4090,10 +4082,10 @@ ips_chkstatus(ips_ha_t * ha, IPS_STATUS * pstatus)
- 			scb->scsi_cmd->result = errcode << 16;
- 		} else {	/* bus == 0 */
- 			/* restrict access to physical drives */
--			if (scb->scsi_cmd->cmnd[0] == INQUIRY) { 
--			    ips_scmd_buf_read(scb->scsi_cmd, 
-+			if (scb->scsi_cmd->cmnd[0] == INQUIRY) {
-+			    ips_scmd_buf_read(scb->scsi_cmd,
-                                   &inquiryData, sizeof (inquiryData));
--			    if ((inquiryData.DeviceType & 0x1f) == TYPE_DISK) 
-+			    if ((inquiryData.DeviceType & 0x1f) == TYPE_DISK)
- 			        scb->scsi_cmd->result = DID_TIME_OUT << 16;
- 			}
- 		}		/* else */
-@@ -4393,8 +4385,6 @@ ips_free(ips_ha_t * ha)
- 			ha->mem_ptr = NULL;
- 		}
++void
++lpfc_port_link_failure(struct lpfc_vport *vport)
++{
++	/* Cleanup any outstanding RSCN activity */
++	lpfc_els_flush_rscn(vport);
++
++	/* Cleanup any outstanding ELS commands */
++	lpfc_els_flush_cmd(vport);
++
++	lpfc_cleanup_rpis(vport, 0);
++
++	/* Turn off discovery timer if its running */
++	lpfc_can_disctmo(vport);
++}
++
+ static void
+ lpfc_linkdown_port(struct lpfc_vport *vport)
+ {
+-	struct lpfc_nodelist *ndlp, *next_ndlp;
+ 	struct Scsi_Host  *shost = lpfc_shost_from_vport(vport);
  
--		if (ha->mem_addr)
--			release_mem_region(ha->mem_addr, ha->mem_len);
- 		ha->mem_addr = 0;
+ 	fc_host_post_event(shost, fc_get_event_number(), FCH_EVT_LINKDOWN, 0);
+@@ -581,21 +616,8 @@ lpfc_linkdown_port(struct lpfc_vport *vport)
+ 		"Link Down:       state:x%x rtry:x%x flg:x%x",
+ 		vport->port_state, vport->fc_ns_retry, vport->fc_flag);
  
- 	}
-@@ -4661,8 +4651,8 @@ ips_isinit_morpheus(ips_ha_t * ha)
- 	uint32_t bits;
+-	/* Cleanup any outstanding RSCN activity */
+-	lpfc_els_flush_rscn(vport);
+-
+-	/* Cleanup any outstanding ELS commands */
+-	lpfc_els_flush_cmd(vport);
++	lpfc_port_link_failure(vport);
  
- 	METHOD_TRACE("ips_is_init_morpheus", 1);
--   
--	if (ips_isintr_morpheus(ha)) 
-+
-+	if (ips_isintr_morpheus(ha))
- 	    ips_flush_and_reset(ha);
+-	lpfc_cleanup_rpis(vport, 0);
+-
+-	/* free any ndlp's on unused list */
+-	list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp)
+-		if (ndlp->nlp_state == NLP_STE_UNUSED_NODE)
+-			lpfc_drop_node(vport, ndlp);
+-
+-	/* Turn off discovery timer if its running */
+-	lpfc_can_disctmo(vport);
+ }
  
- 	post = readl(ha->mem_ptr + IPS_REG_I960_MSG0);
-@@ -4686,7 +4676,7 @@ ips_isinit_morpheus(ips_ha_t * ha)
- /*   state ( was trying to INIT and an interrupt was already pending ) ...  */
- /*                                                                          */
- /****************************************************************************/
--static void 
-+static void
- ips_flush_and_reset(ips_ha_t *ha)
- {
- 	ips_scb_t *scb;
-@@ -4718,9 +4708,9 @@ ips_flush_and_reset(ips_ha_t *ha)
- 	    if (ret == IPS_SUCCESS) {
- 	        time = 60 * IPS_ONE_SEC;	              /* Max Wait time is 60 seconds */
- 	        done = 0;
--	            
-+
- 	        while ((time > 0) && (!done)) {
--	           done = ips_poll_for_flush_complete(ha); 	   
-+		   done = ips_poll_for_flush_complete(ha);
- 	           /* This may look evil, but it's only done during extremely rare start-up conditions ! */
- 	           udelay(1000);
- 	           time--;
-@@ -4749,17 +4739,17 @@ static int
- ips_poll_for_flush_complete(ips_ha_t * ha)
+ int
+@@ -618,18 +640,18 @@ lpfc_linkdown(struct lpfc_hba *phba)
+ 	spin_unlock_irq(&phba->hbalock);
+ 	vports = lpfc_create_vport_work_array(phba);
+ 	if (vports != NULL)
+-		for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++) {
++		for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) {
+ 			/* Issue a LINK DOWN event to all nodes */
+ 			lpfc_linkdown_port(vports[i]);
+ 		}
+-	lpfc_destroy_vport_work_array(vports);
++	lpfc_destroy_vport_work_array(phba, vports);
+ 	/* Clean up any firmware default rpi's */
+ 	mb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+ 	if (mb) {
+ 		lpfc_unreg_did(phba, 0xffff, 0xffffffff, mb);
+ 		mb->vport = vport;
+ 		mb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+-		if (lpfc_sli_issue_mbox(phba, mb, (MBX_NOWAIT | MBX_STOP_IOCB))
++		if (lpfc_sli_issue_mbox(phba, mb, MBX_NOWAIT)
+ 		    == MBX_NOT_FINISHED) {
+ 			mempool_free(mb, phba->mbox_mem_pool);
+ 		}
+@@ -643,8 +665,7 @@ lpfc_linkdown(struct lpfc_hba *phba)
+ 			lpfc_config_link(phba, mb);
+ 			mb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+ 			mb->vport = vport;
+-			if (lpfc_sli_issue_mbox(phba, mb,
+-						(MBX_NOWAIT | MBX_STOP_IOCB))
++			if (lpfc_sli_issue_mbox(phba, mb, MBX_NOWAIT)
+ 			    == MBX_NOT_FINISHED) {
+ 				mempool_free(mb, phba->mbox_mem_pool);
+ 			}
+@@ -686,7 +707,6 @@ static void
+ lpfc_linkup_port(struct lpfc_vport *vport)
  {
- 	IPS_STATUS cstatus;
--    
-+
- 	while (TRUE) {
- 	    cstatus.value = (*ha->func.statupd) (ha);
+ 	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+-	struct lpfc_nodelist *ndlp, *next_ndlp;
+ 	struct lpfc_hba  *phba = vport->phba;
  
- 	    if (cstatus.value == 0xffffffff)      /* If No Interrupt to process */
- 			break;
--            
-+
- 	    /* Success is when we see the Flush Command ID */
--	    if (cstatus.fields.command_id == IPS_MAX_CMDS ) 
-+	    if (cstatus.fields.command_id == IPS_MAX_CMDS)
- 	        return 1;
--	 }	
-+	 }
+ 	if ((vport->load_flag & FC_UNLOADING) != 0)
+@@ -713,11 +733,6 @@ lpfc_linkup_port(struct lpfc_vport *vport)
+ 	if (vport->fc_flag & FC_LBIT)
+ 		lpfc_linkup_cleanup_nodes(vport);
  
- 	return 0;
+-				/* free any ndlp's in unused state */
+-	list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes,
+-				 nlp_listp)
+-		if (ndlp->nlp_state == NLP_STE_UNUSED_NODE)
+-			lpfc_drop_node(vport, ndlp);
  }
-@@ -4903,7 +4893,7 @@ ips_init_copperhead(ips_ha_t * ha)
- 	/* Enable busmastering */
- 	outb(IPS_BIT_EBM, ha->io_addr + IPS_REG_SCPR);
  
--	if (ha->revision_id == IPS_REVID_TROMBONE64)
-+	if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
- 		/* fix for anaconda64 */
- 		outl(0, ha->io_addr + IPS_REG_NDAE);
+ static int
+@@ -734,9 +749,9 @@ lpfc_linkup(struct lpfc_hba *phba)
  
-@@ -4997,7 +4987,7 @@ ips_init_copperhead_memio(ips_ha_t * ha)
- 	/* Enable busmastering */
- 	writeb(IPS_BIT_EBM, ha->mem_ptr + IPS_REG_SCPR);
+ 	vports = lpfc_create_vport_work_array(phba);
+ 	if (vports != NULL)
+-		for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++)
++		for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++)
+ 			lpfc_linkup_port(vports[i]);
+-	lpfc_destroy_vport_work_array(vports);
++	lpfc_destroy_vport_work_array(phba, vports);
+ 	if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED)
+ 		lpfc_issue_clear_la(phba, phba->pport);
  
--	if (ha->revision_id == IPS_REVID_TROMBONE64)
-+	if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
- 		/* fix for anaconda64 */
- 		writel(0, ha->mem_ptr + IPS_REG_NDAE);
+@@ -749,7 +764,7 @@ lpfc_linkup(struct lpfc_hba *phba)
+  * as the completion routine when the command is
+  * handed off to the SLI layer.
+  */
+-void
++static void
+ lpfc_mbx_cmpl_clear_la(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
+ {
+ 	struct lpfc_vport *vport = pmb->vport;
+@@ -852,8 +867,6 @@ lpfc_mbx_cmpl_local_config_link(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
+ 	 * LPFC_FLOGI while waiting for FLOGI cmpl
+ 	 */
+ 	if (vport->port_state != LPFC_FLOGI) {
+-		vport->port_state = LPFC_FLOGI;
+-		lpfc_set_disctmo(vport);
+ 		lpfc_initial_flogi(vport);
+ 	}
+ 	return;
+@@ -1022,8 +1035,7 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, READ_LA_VAR *la)
+ 		lpfc_read_sparam(phba, sparam_mbox, 0);
+ 		sparam_mbox->vport = vport;
+ 		sparam_mbox->mbox_cmpl = lpfc_mbx_cmpl_read_sparam;
+-		rc = lpfc_sli_issue_mbox(phba, sparam_mbox,
+-				    (MBX_NOWAIT | MBX_STOP_IOCB));
++		rc = lpfc_sli_issue_mbox(phba, sparam_mbox, MBX_NOWAIT);
+ 		if (rc == MBX_NOT_FINISHED) {
+ 			mp = (struct lpfc_dmabuf *) sparam_mbox->context1;
+ 			lpfc_mbuf_free(phba, mp->virt, mp->phys);
+@@ -1040,8 +1052,7 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, READ_LA_VAR *la)
+ 		lpfc_config_link(phba, cfglink_mbox);
+ 		cfglink_mbox->vport = vport;
+ 		cfglink_mbox->mbox_cmpl = lpfc_mbx_cmpl_local_config_link;
+-		rc = lpfc_sli_issue_mbox(phba, cfglink_mbox,
+-				    (MBX_NOWAIT | MBX_STOP_IOCB));
++		rc = lpfc_sli_issue_mbox(phba, cfglink_mbox, MBX_NOWAIT);
+ 		if (rc != MBX_NOT_FINISHED)
+ 			return;
+ 		mempool_free(cfglink_mbox, phba->mbox_mem_pool);
+@@ -1174,6 +1185,9 @@ lpfc_mbx_cmpl_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
+ 	lpfc_mbuf_free(phba, mp->virt, mp->phys);
+ 	kfree(mp);
+ 	mempool_free(pmb, phba->mbox_mem_pool);
++	/* decrement the node reference count held for this callback
++	 * function.
++	 */
+ 	lpfc_nlp_put(ndlp);
  
-@@ -5142,7 +5132,7 @@ ips_reset_copperhead(ips_ha_t * ha)
- 	METHOD_TRACE("ips_reset_copperhead", 1);
+ 	return;
+@@ -1219,7 +1233,7 @@ lpfc_mbx_unreg_vpi(struct lpfc_vport *vport)
+ 	lpfc_unreg_vpi(phba, vport->vpi, mbox);
+ 	mbox->vport = vport;
+ 	mbox->mbox_cmpl = lpfc_mbx_cmpl_unreg_vpi;
+-	rc = lpfc_sli_issue_mbox(phba, mbox, (MBX_NOWAIT | MBX_STOP_IOCB));
++	rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
+ 	if (rc == MBX_NOT_FINISHED) {
+ 		lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX | LOG_VPORT,
+ 				 "1800 Could not issue unreg_vpi\n");
+@@ -1319,7 +1333,7 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
+ 		vports = lpfc_create_vport_work_array(phba);
+ 		if (vports != NULL)
+ 			for(i = 0;
+-			    i < LPFC_MAX_VPORTS && vports[i] != NULL;
++			    i <= phba->max_vpi && vports[i] != NULL;
+ 			    i++) {
+ 				if (vports[i]->port_type == LPFC_PHYSICAL_PORT)
+ 					continue;
+@@ -1335,7 +1349,7 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
+ 							"Fabric support\n");
+ 				}
+ 			}
+-		lpfc_destroy_vport_work_array(vports);
++		lpfc_destroy_vport_work_array(phba, vports);
+ 		lpfc_do_scr_ns_plogi(phba, vport);
+ 	}
  
- 	DEBUG_VAR(1, "(%s%d) ips_reset_copperhead: io addr: %x, irq: %d",
--		  ips_name, ha->host_num, ha->io_addr, ha->irq);
-+		  ips_name, ha->host_num, ha->io_addr, ha->pcidev->irq);
+@@ -1361,11 +1375,16 @@ lpfc_mbx_cmpl_ns_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
  
- 	reset_counter = 0;
+ 	if (mb->mbxStatus) {
+ out:
++		/* decrement the node reference count held for this
++		 * callback function.
++		 */
+ 		lpfc_nlp_put(ndlp);
+ 		lpfc_mbuf_free(phba, mp->virt, mp->phys);
+ 		kfree(mp);
+ 		mempool_free(pmb, phba->mbox_mem_pool);
+-		lpfc_drop_node(vport, ndlp);
++
++		/* If no other thread is using the ndlp, free it */
++		lpfc_nlp_not_used(ndlp);
  
-@@ -5187,7 +5177,7 @@ ips_reset_copperhead_memio(ips_ha_t * ha)
- 	METHOD_TRACE("ips_reset_copperhead_memio", 1);
+ 		if (phba->fc_topology == TOPOLOGY_LOOP) {
+ 			/*
+@@ -1410,6 +1429,9 @@ out:
+ 		goto out;
+ 	}
  
- 	DEBUG_VAR(1, "(%s%d) ips_reset_copperhead_memio: mem addr: %x, irq: %d",
--		  ips_name, ha->host_num, ha->mem_addr, ha->irq);
-+		  ips_name, ha->host_num, ha->mem_addr, ha->pcidev->irq);
++	/* decrement the node reference count held for this
++	 * callback function.
++	 */
+ 	lpfc_nlp_put(ndlp);
+ 	lpfc_mbuf_free(phba, mp->virt, mp->phys);
+ 	kfree(mp);
+@@ -1656,8 +1678,18 @@ lpfc_dequeue_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
+ void
+ lpfc_drop_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
+ {
++	/*
++	 * Use of lpfc_drop_node and UNUSED list: lpfc_drop_node should
++	 * be used if we wish to issue the "last" lpfc_nlp_put() to remove
++	 * the ndlp from the vport. The ndlp marked as UNUSED on the list
++	 * until ALL other outstanding threads have completed. We check
++	 * that the ndlp not already in the UNUSED state before we proceed.
++	 */
++	if (ndlp->nlp_state == NLP_STE_UNUSED_NODE)
++		return;
+ 	lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE);
+ 	lpfc_nlp_put(ndlp);
++	return;
+ }
  
- 	reset_counter = 0;
+ /*
+@@ -1868,8 +1900,7 @@ lpfc_unreg_rpi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
+ 			lpfc_unreg_login(phba, vport->vpi, ndlp->nlp_rpi, mbox);
+ 			mbox->vport = vport;
+ 			mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+-			rc = lpfc_sli_issue_mbox(phba, mbox,
+-						 (MBX_NOWAIT | MBX_STOP_IOCB));
++			rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
+ 			if (rc == MBX_NOT_FINISHED)
+ 				mempool_free(mbox, phba->mbox_mem_pool);
+ 		}
+@@ -1892,8 +1923,8 @@ lpfc_unreg_all_rpis(struct lpfc_vport *vport)
+ 		lpfc_unreg_login(phba, vport->vpi, 0xffff, mbox);
+ 		mbox->vport = vport;
+ 		mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+-		rc = lpfc_sli_issue_mbox(phba, mbox,
+-					 (MBX_NOWAIT | MBX_STOP_IOCB));
++		mbox->context1 = NULL;
++		rc = lpfc_sli_issue_mbox_wait(phba, mbox, LPFC_MBOX_TMO);
+ 		if (rc == MBX_NOT_FINISHED) {
+ 			mempool_free(mbox, phba->mbox_mem_pool);
+ 		}
+@@ -1912,8 +1943,8 @@ lpfc_unreg_default_rpis(struct lpfc_vport *vport)
+ 		lpfc_unreg_did(phba, vport->vpi, 0xffffffff, mbox);
+ 		mbox->vport = vport;
+ 		mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+-		rc = lpfc_sli_issue_mbox(phba, mbox,
+-					 (MBX_NOWAIT | MBX_STOP_IOCB));
++		mbox->context1 = NULL;
++		rc = lpfc_sli_issue_mbox_wait(phba, mbox, LPFC_MBOX_TMO);
+ 		if (rc == MBX_NOT_FINISHED) {
+ 			lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX | LOG_VPORT,
+ 					 "1815 Could not issue "
+@@ -1981,11 +2012,6 @@ lpfc_cleanup_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
+ 	if (!list_empty(&ndlp->dev_loss_evt.evt_listp))
+ 		list_del_init(&ndlp->dev_loss_evt.evt_listp);
  
-@@ -5233,7 +5223,7 @@ ips_reset_morpheus(ips_ha_t * ha)
- 	METHOD_TRACE("ips_reset_morpheus", 1);
+-	if (!list_empty(&ndlp->dev_loss_evt.evt_listp)) {
+-		list_del_init(&ndlp->dev_loss_evt.evt_listp);
+-		complete((struct completion *)(ndlp->dev_loss_evt.evt_arg2));
+-	}
+-
+ 	lpfc_unreg_rpi(vport, ndlp);
  
- 	DEBUG_VAR(1, "(%s%d) ips_reset_morpheus: mem addr: %x, irq: %d",
--		  ips_name, ha->host_num, ha->mem_addr, ha->irq);
-+		  ips_name, ha->host_num, ha->mem_addr, ha->pcidev->irq);
+ 	return 0;
+@@ -1999,12 +2025,39 @@ lpfc_cleanup_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
+ static void
+ lpfc_nlp_remove(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
+ {
++	struct lpfc_hba  *phba = vport->phba;
+ 	struct lpfc_rport_data *rdata;
++	LPFC_MBOXQ_t *mbox;
++	int rc;
  
- 	reset_counter = 0;
+ 	if (ndlp->nlp_flag & NLP_DELAY_TMO) {
+ 		lpfc_cancel_retry_delay_tmo(vport, ndlp);
+ 	}
  
-@@ -5920,7 +5910,7 @@ ips_read_config(ips_ha_t * ha, int intr)
++	if (ndlp->nlp_flag & NLP_DEFER_RM && !ndlp->nlp_rpi) {
++		/* For this case we need to cleanup the default rpi
++		 * allocated by the firmware.
++		 */
++		if ((mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL))
++			!= NULL) {
++			rc = lpfc_reg_login(phba, vport->vpi, ndlp->nlp_DID,
++			    (uint8_t *) &vport->fc_sparam, mbox, 0);
++			if (rc) {
++				mempool_free(mbox, phba->mbox_mem_pool);
++			}
++			else {
++				mbox->mbox_flag |= LPFC_MBX_IMED_UNREG;
++				mbox->mbox_cmpl = lpfc_mbx_cmpl_dflt_rpi;
++				mbox->vport = vport;
++				mbox->context2 = NULL;
++				rc =lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
++				if (rc == MBX_NOT_FINISHED) {
++					mempool_free(mbox, phba->mbox_mem_pool);
++				}
++			}
++		}
++	}
++
+ 	lpfc_cleanup_node(vport, ndlp);
  
- 		return (0);
+ 	/*
+@@ -2132,6 +2185,12 @@ lpfc_setup_disc_node(struct lpfc_vport *vport, uint32_t did)
  	}
--	
+ 	if (vport->fc_flag & FC_RSCN_MODE) {
+ 		if (lpfc_rscn_payload_check(vport, did)) {
++			/* If we've already recieved a PLOGI from this NPort
++			 * we don't need to try to discover it again.
++			 */
++			if (ndlp->nlp_flag & NLP_RCV_PLOGI)
++				return NULL;
 +
- 	memcpy(ha->conf, ha->ioctl_data, sizeof(*ha->conf));
- 	return (1);
+ 			spin_lock_irq(shost->host_lock);
+ 			ndlp->nlp_flag |= NLP_NPR_2B_DISC;
+ 			spin_unlock_irq(shost->host_lock);
+@@ -2144,8 +2203,13 @@ lpfc_setup_disc_node(struct lpfc_vport *vport, uint32_t did)
+ 		} else
+ 			ndlp = NULL;
+ 	} else {
++		/* If we've already recieved a PLOGI from this NPort,
++		 * or we are already in the process of discovery on it,
++		 * we don't need to try to discover it again.
++		 */
+ 		if (ndlp->nlp_state == NLP_STE_ADISC_ISSUE ||
+-		    ndlp->nlp_state == NLP_STE_PLOGI_ISSUE)
++		    ndlp->nlp_state == NLP_STE_PLOGI_ISSUE ||
++		    ndlp->nlp_flag & NLP_RCV_PLOGI)
+ 			return NULL;
+ 		lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
+ 		spin_lock_irq(shost->host_lock);
+@@ -2220,8 +2284,7 @@ lpfc_issue_clear_la(struct lpfc_hba *phba, struct lpfc_vport *vport)
+ 		lpfc_clear_la(phba, mbox);
+ 		mbox->mbox_cmpl = lpfc_mbx_cmpl_clear_la;
+ 		mbox->vport = vport;
+-		rc = lpfc_sli_issue_mbox(phba, mbox, (MBX_NOWAIT |
+-						      MBX_STOP_IOCB));
++		rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
+ 		if (rc == MBX_NOT_FINISHED) {
+ 			mempool_free(mbox, phba->mbox_mem_pool);
+ 			lpfc_disc_flush_list(vport);
+@@ -2244,8 +2307,7 @@ lpfc_issue_reg_vpi(struct lpfc_hba *phba, struct lpfc_vport *vport)
+ 		lpfc_reg_vpi(phba, vport->vpi, vport->fc_myDID, regvpimbox);
+ 		regvpimbox->mbox_cmpl = lpfc_mbx_cmpl_reg_vpi;
+ 		regvpimbox->vport = vport;
+-		if (lpfc_sli_issue_mbox(phba, regvpimbox,
+-					(MBX_NOWAIT | MBX_STOP_IOCB))
++		if (lpfc_sli_issue_mbox(phba, regvpimbox, MBX_NOWAIT)
+ 					== MBX_NOT_FINISHED) {
+ 			mempool_free(regvpimbox, phba->mbox_mem_pool);
+ 		}
+@@ -2414,7 +2476,7 @@ lpfc_free_tx(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
+ 	}
  }
-@@ -5959,7 +5949,7 @@ ips_readwrite_page5(ips_ha_t * ha, int write, int intr)
- 	scb->cmd.nvram.buffer_addr = ha->ioctl_busaddr;
- 	if (write)
- 		memcpy(ha->ioctl_data, ha->nvram, sizeof(*ha->nvram));
--	
-+
- 	/* issue the command */
- 	if (((ret =
- 	      ips_send_wait(ha, scb, ips_cmd_timeout, intr)) == IPS_FAILURE)
-@@ -6196,32 +6186,32 @@ ips_erase_bios(ips_ha_t * ha)
- 
- 	/* Clear the status register */
- 	outl(0, ha->io_addr + IPS_REG_FLAP);
--	if (ha->revision_id == IPS_REVID_TROMBONE64)
-+	if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
- 		udelay(25);	/* 25 us */
- 
- 	outb(0x50, ha->io_addr + IPS_REG_FLDP);
--	if (ha->revision_id == IPS_REVID_TROMBONE64)
-+	if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
- 		udelay(25);	/* 25 us */
- 
- 	/* Erase Setup */
- 	outb(0x20, ha->io_addr + IPS_REG_FLDP);
--	if (ha->revision_id == IPS_REVID_TROMBONE64)
-+	if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
- 		udelay(25);	/* 25 us */
  
- 	/* Erase Confirm */
- 	outb(0xD0, ha->io_addr + IPS_REG_FLDP);
--	if (ha->revision_id == IPS_REVID_TROMBONE64)
-+	if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
- 		udelay(25);	/* 25 us */
+-void
++static void
+ lpfc_disc_flush_list(struct lpfc_vport *vport)
+ {
+ 	struct lpfc_nodelist *ndlp, *next_ndlp;
+@@ -2426,7 +2488,6 @@ lpfc_disc_flush_list(struct lpfc_vport *vport)
+ 			if (ndlp->nlp_state == NLP_STE_PLOGI_ISSUE ||
+ 			    ndlp->nlp_state == NLP_STE_ADISC_ISSUE) {
+ 				lpfc_free_tx(phba, ndlp);
+-				lpfc_nlp_put(ndlp);
+ 			}
+ 		}
+ 	}
+@@ -2516,6 +2577,7 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport)
+ 			if (ndlp->nlp_type & NLP_FABRIC) {
+ 				/* Clean up the ndlp on Fabric connections */
+ 				lpfc_drop_node(vport, ndlp);
++
+ 			} else if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) {
+ 				/* Fail outstanding IO now since device
+ 				 * is marked for PLOGI.
+@@ -2524,9 +2586,8 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport)
+ 			}
+ 		}
+ 		if (vport->port_state != LPFC_FLOGI) {
+-			vport->port_state = LPFC_FLOGI;
+-			lpfc_set_disctmo(vport);
+ 			lpfc_initial_flogi(vport);
++			return;
+ 		}
+ 		break;
  
- 	/* Erase Status */
- 	outb(0x70, ha->io_addr + IPS_REG_FLDP);
--	if (ha->revision_id == IPS_REVID_TROMBONE64)
-+	if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
- 		udelay(25);	/* 25 us */
+@@ -2536,7 +2597,7 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport)
+ 		/* Initial FLOGI timeout */
+ 		lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
+ 				 "0222 Initial %s timeout\n",
+-				 vport->vpi ? "FLOGI" : "FDISC");
++				 vport->vpi ? "FDISC" : "FLOGI");
  
- 	timeout = 80000;	/* 80 seconds */
+ 		/* Assume no Fabric and go on with discovery.
+ 		 * Check for outstanding ELS FLOGI to abort.
+@@ -2558,10 +2619,10 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport)
+ 		/* Next look for NameServer ndlp */
+ 		ndlp = lpfc_findnode_did(vport, NameServer_DID);
+ 		if (ndlp)
+-			lpfc_nlp_put(ndlp);
+-		/* Start discovery */
+-		lpfc_disc_start(vport);
+-		break;
++			lpfc_els_abort(phba, ndlp);
++
++		/* ReStart discovery */
++		goto restart_disc;
  
- 	while (timeout > 0) {
--		if (ha->revision_id == IPS_REVID_TROMBONE64) {
-+		if (ha->pcidev->revision == IPS_REVID_TROMBONE64) {
- 			outl(0, ha->io_addr + IPS_REG_FLAP);
- 			udelay(25);	/* 25 us */
+ 	case LPFC_NS_QRY:
+ 	/* Check for wait for NameServer Rsp timeout */
+@@ -2580,6 +2641,7 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport)
  		}
-@@ -6241,13 +6231,13 @@ ips_erase_bios(ips_ha_t * ha)
- 
- 		/* try to suspend the erase */
- 		outb(0xB0, ha->io_addr + IPS_REG_FLDP);
--		if (ha->revision_id == IPS_REVID_TROMBONE64)
-+		if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
- 			udelay(25);	/* 25 us */
+ 		vport->fc_ns_retry = 0;
  
- 		/* wait for 10 seconds */
- 		timeout = 10000;
- 		while (timeout > 0) {
--			if (ha->revision_id == IPS_REVID_TROMBONE64) {
-+			if (ha->pcidev->revision == IPS_REVID_TROMBONE64) {
- 				outl(0, ha->io_addr + IPS_REG_FLAP);
- 				udelay(25);	/* 25 us */
- 			}
-@@ -6277,12 +6267,12 @@ ips_erase_bios(ips_ha_t * ha)
- 	/* Otherwise, we were successful */
- 	/* clear status */
- 	outb(0x50, ha->io_addr + IPS_REG_FLDP);
--	if (ha->revision_id == IPS_REVID_TROMBONE64)
-+	if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
- 		udelay(25);	/* 25 us */
++restart_disc:
+ 		/*
+ 		 * Discovery is over.
+ 		 * set port_state to PORT_READY if SLI2.
+@@ -2608,8 +2670,7 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport)
+ 		initlinkmbox->mb.un.varInitLnk.lipsr_AL_PA = 0;
+ 		initlinkmbox->vport = vport;
+ 		initlinkmbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+-		rc = lpfc_sli_issue_mbox(phba, initlinkmbox,
+-					 (MBX_NOWAIT | MBX_STOP_IOCB));
++		rc = lpfc_sli_issue_mbox(phba, initlinkmbox, MBX_NOWAIT);
+ 		lpfc_set_loopback_flag(phba);
+ 		if (rc == MBX_NOT_FINISHED)
+ 			mempool_free(initlinkmbox, phba->mbox_mem_pool);
+@@ -2664,12 +2725,14 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport)
+ 		clrlaerr = 1;
+ 		break;
  
- 	/* enable reads */
- 	outb(0xFF, ha->io_addr + IPS_REG_FLDP);
--	if (ha->revision_id == IPS_REVID_TROMBONE64)
-+	if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
- 		udelay(25);	/* 25 us */
++	case LPFC_LINK_UP:
++		lpfc_issue_clear_la(phba, vport);
++		/* Drop thru */
+ 	case LPFC_LINK_UNKNOWN:
+ 	case LPFC_WARM_START:
+ 	case LPFC_INIT_START:
+ 	case LPFC_INIT_MBX_CMDS:
+ 	case LPFC_LINK_DOWN:
+-	case LPFC_LINK_UP:
+ 	case LPFC_HBA_ERROR:
+ 		lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
+ 				 "0230 Unexpected timeout, hba link "
+@@ -2723,7 +2786,9 @@ lpfc_mbx_cmpl_fdmi_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
+ 	else
+ 		mod_timer(&vport->fc_fdmitmo, jiffies + HZ * 60);
  
- 	return (0);
-@@ -6308,32 +6298,32 @@ ips_erase_bios_memio(ips_ha_t * ha)
+-				/* Mailbox took a reference to the node */
++	/* decrement the node reference count held for this callback
++	 * function.
++	 */
+ 	lpfc_nlp_put(ndlp);
+ 	lpfc_mbuf_free(phba, mp->virt, mp->phys);
+ 	kfree(mp);
+@@ -2747,19 +2812,19 @@ lpfc_filter_by_wwpn(struct lpfc_nodelist *ndlp, void *param)
+ 		      sizeof(ndlp->nlp_portname)) == 0;
+ }
  
- 	/* Clear the status register */
- 	writel(0, ha->mem_ptr + IPS_REG_FLAP);
--	if (ha->revision_id == IPS_REVID_TROMBONE64)
-+	if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
- 		udelay(25);	/* 25 us */
+-struct lpfc_nodelist *
++static struct lpfc_nodelist *
+ __lpfc_find_node(struct lpfc_vport *vport, node_filter filter, void *param)
+ {
+ 	struct lpfc_nodelist *ndlp;
  
- 	writeb(0x50, ha->mem_ptr + IPS_REG_FLDP);
--	if (ha->revision_id == IPS_REVID_TROMBONE64)
-+	if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
- 		udelay(25);	/* 25 us */
+ 	list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) {
+-		if (ndlp->nlp_state != NLP_STE_UNUSED_NODE &&
+-		    filter(ndlp, param))
++		if (filter(ndlp, param))
+ 			return ndlp;
+ 	}
+ 	return NULL;
+ }
  
- 	/* Erase Setup */
- 	writeb(0x20, ha->mem_ptr + IPS_REG_FLDP);
--	if (ha->revision_id == IPS_REVID_TROMBONE64)
-+	if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
- 		udelay(25);	/* 25 us */
++#if 0
+ /*
+  * Search node lists for a remote port matching filter criteria
+  * Caller needs to hold host_lock before calling this routine.
+@@ -2775,6 +2840,7 @@ lpfc_find_node(struct lpfc_vport *vport, node_filter filter, void *param)
+ 	spin_unlock_irq(shost->host_lock);
+ 	return ndlp;
+ }
++#endif  /*  0  */
  
- 	/* Erase Confirm */
- 	writeb(0xD0, ha->mem_ptr + IPS_REG_FLDP);
--	if (ha->revision_id == IPS_REVID_TROMBONE64)
-+	if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
- 		udelay(25);	/* 25 us */
+ /*
+  * This routine looks up the ndlp lists for the given RPI. If rpi found it
+@@ -2786,6 +2852,7 @@ __lpfc_findnode_rpi(struct lpfc_vport *vport, uint16_t rpi)
+ 	return __lpfc_find_node(vport, lpfc_filter_by_rpi, &rpi);
+ }
  
- 	/* Erase Status */
- 	writeb(0x70, ha->mem_ptr + IPS_REG_FLDP);
--	if (ha->revision_id == IPS_REVID_TROMBONE64)
-+	if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
- 		udelay(25);	/* 25 us */
++#if 0
+ struct lpfc_nodelist *
+ lpfc_findnode_rpi(struct lpfc_vport *vport, uint16_t rpi)
+ {
+@@ -2797,6 +2864,7 @@ lpfc_findnode_rpi(struct lpfc_vport *vport, uint16_t rpi)
+ 	spin_unlock_irq(shost->host_lock);
+ 	return ndlp;
+ }
++#endif  /*  0  */
  
- 	timeout = 80000;	/* 80 seconds */
+ /*
+  * This routine looks up the ndlp lists for the given WWPN. If WWPN found it
+@@ -2837,6 +2905,9 @@ lpfc_nlp_init(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ 	return;
+ }
  
- 	while (timeout > 0) {
--		if (ha->revision_id == IPS_REVID_TROMBONE64) {
-+		if (ha->pcidev->revision == IPS_REVID_TROMBONE64) {
- 			writel(0, ha->mem_ptr + IPS_REG_FLAP);
- 			udelay(25);	/* 25 us */
- 		}
-@@ -6353,13 +6343,13 @@ ips_erase_bios_memio(ips_ha_t * ha)
++/* This routine releases all resources associated with a specifc NPort's ndlp
++ * and mempool_free's the nodelist.
++ */
+ static void
+ lpfc_nlp_release(struct kref *kref)
+ {
+@@ -2851,16 +2922,57 @@ lpfc_nlp_release(struct kref *kref)
+ 	mempool_free(ndlp, ndlp->vport->phba->nlp_mem_pool);
+ }
  
- 		/* try to suspend the erase */
- 		writeb(0xB0, ha->mem_ptr + IPS_REG_FLDP);
--		if (ha->revision_id == IPS_REVID_TROMBONE64)
-+		if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
- 			udelay(25);	/* 25 us */
++/* This routine bumps the reference count for a ndlp structure to ensure
++ * that one discovery thread won't free a ndlp while another discovery thread
++ * is using it.
++ */
+ struct lpfc_nodelist *
+ lpfc_nlp_get(struct lpfc_nodelist *ndlp)
+ {
+-	if (ndlp)
++	if (ndlp) {
++		lpfc_debugfs_disc_trc(ndlp->vport, LPFC_DISC_TRC_NODE,
++			"node get:        did:x%x flg:x%x refcnt:x%x",
++			ndlp->nlp_DID, ndlp->nlp_flag,
++			atomic_read(&ndlp->kref.refcount));
+ 		kref_get(&ndlp->kref);
++	}
+ 	return ndlp;
+ }
  
- 		/* wait for 10 seconds */
- 		timeout = 10000;
- 		while (timeout > 0) {
--			if (ha->revision_id == IPS_REVID_TROMBONE64) {
-+			if (ha->pcidev->revision == IPS_REVID_TROMBONE64) {
- 				writel(0, ha->mem_ptr + IPS_REG_FLAP);
- 				udelay(25);	/* 25 us */
- 			}
-@@ -6389,12 +6379,12 @@ ips_erase_bios_memio(ips_ha_t * ha)
- 	/* Otherwise, we were successful */
- 	/* clear status */
- 	writeb(0x50, ha->mem_ptr + IPS_REG_FLDP);
--	if (ha->revision_id == IPS_REVID_TROMBONE64)
-+	if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
- 		udelay(25);	/* 25 us */
++
++/* This routine decrements the reference count for a ndlp structure. If the
++ * count goes to 0, this indicates the the associated nodelist should be freed.
++ */
+ int
+ lpfc_nlp_put(struct lpfc_nodelist *ndlp)
+ {
++	if (ndlp) {
++		lpfc_debugfs_disc_trc(ndlp->vport, LPFC_DISC_TRC_NODE,
++		"node put:        did:x%x flg:x%x refcnt:x%x",
++			ndlp->nlp_DID, ndlp->nlp_flag,
++			atomic_read(&ndlp->kref.refcount));
++	}
+ 	return ndlp ? kref_put(&ndlp->kref, lpfc_nlp_release) : 0;
+ }
++
++/* This routine free's the specified nodelist if it is not in use
++ * by any other discovery thread. This routine returns 1 if the ndlp
++ * is not being used by anyone and has been freed. A return value of
++ * 0 indicates it is being used by another discovery thread and the
++ * refcount is left unchanged.
++ */
++int
++lpfc_nlp_not_used(struct lpfc_nodelist *ndlp)
++{
++	lpfc_debugfs_disc_trc(ndlp->vport, LPFC_DISC_TRC_NODE,
++		"node not used:   did:x%x flg:x%x refcnt:x%x",
++		ndlp->nlp_DID, ndlp->nlp_flag,
++		atomic_read(&ndlp->kref.refcount));
++
++	if (atomic_read(&ndlp->kref.refcount) == 1) {
++		lpfc_nlp_put(ndlp);
++		return 1;
++	}
++	return 0;
++}
++
+diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h
+index 451accd..041f83e 100644
+--- a/drivers/scsi/lpfc/lpfc_hw.h
++++ b/drivers/scsi/lpfc/lpfc_hw.h
+@@ -139,6 +139,9 @@ struct lpfc_sli_ct_request {
+ 			uint8_t len;
+ 			uint8_t symbname[255];
+ 		} rsnn;
++		struct da_id { /* For DA_ID requests */
++			uint32_t port_id;
++		} da_id;
+ 		struct rspn {	/* For RSPN_ID requests */
+ 			uint32_t PortId;
+ 			uint8_t len;
+@@ -150,11 +153,7 @@ struct lpfc_sli_ct_request {
+ 		struct gff_acc {
+ 			uint8_t fbits[128];
+ 		} gff_acc;
+-#ifdef __BIG_ENDIAN_BITFIELD
+ #define FCP_TYPE_FEATURE_OFFSET 7
+-#else	/*  __LITTLE_ENDIAN_BITFIELD */
+-#define FCP_TYPE_FEATURE_OFFSET 4
+-#endif
+ 		struct rff {
+ 			uint32_t PortId;
+ 			uint8_t reserved[2];
+@@ -177,6 +176,8 @@ struct lpfc_sli_ct_request {
+ 			   sizeof(struct rnn))
+ #define  RSNN_REQUEST_SZ  (offsetof(struct lpfc_sli_ct_request, un) + \
+ 			   sizeof(struct rsnn))
++#define DA_ID_REQUEST_SZ (offsetof(struct lpfc_sli_ct_request, un) + \
++			  sizeof(struct da_id))
+ #define  RSPN_REQUEST_SZ  (offsetof(struct lpfc_sli_ct_request, un) + \
+ 			   sizeof(struct rspn))
  
- 	/* enable reads */
- 	writeb(0xFF, ha->mem_ptr + IPS_REG_FLDP);
--	if (ha->revision_id == IPS_REVID_TROMBONE64)
-+	if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
- 		udelay(25);	/* 25 us */
+@@ -1228,7 +1229,8 @@ typedef struct {		/* FireFly BIU registers */
+ #define HS_FFER3       0x20000000	/* Bit 29 */
+ #define HS_FFER2       0x40000000	/* Bit 30 */
+ #define HS_FFER1       0x80000000	/* Bit 31 */
+-#define HS_FFERM       0xFF000000	/* Mask for error bits 31:24 */
++#define HS_CRIT_TEMP   0x00000100	/* Bit 8  */
++#define HS_FFERM       0xFF000100	/* Mask for error bits 31:24 and 8 */
  
- 	return (0);
-@@ -6423,21 +6413,21 @@ ips_program_bios(ips_ha_t * ha, char *buffer, uint32_t buffersize,
- 	for (i = 0; i < buffersize; i++) {
- 		/* write a byte */
- 		outl(cpu_to_le32(i + offset), ha->io_addr + IPS_REG_FLAP);
--		if (ha->revision_id == IPS_REVID_TROMBONE64)
-+		if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
- 			udelay(25);	/* 25 us */
+ /* Host Control Register */
  
- 		outb(0x40, ha->io_addr + IPS_REG_FLDP);
--		if (ha->revision_id == IPS_REVID_TROMBONE64)
-+		if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
- 			udelay(25);	/* 25 us */
+@@ -1277,12 +1279,14 @@ typedef struct {		/* FireFly BIU registers */
+ #define MBX_DEL_LD_ENTRY    0x1D
+ #define MBX_RUN_PROGRAM     0x1E
+ #define MBX_SET_MASK        0x20
+-#define MBX_SET_SLIM        0x21
++#define MBX_SET_VARIABLE    0x21
+ #define MBX_UNREG_D_ID      0x23
+ #define MBX_KILL_BOARD      0x24
+ #define MBX_CONFIG_FARP     0x25
+ #define MBX_BEACON          0x2A
+ #define MBX_HEARTBEAT       0x31
++#define MBX_WRITE_VPARMS    0x32
++#define MBX_ASYNCEVT_ENABLE 0x33
  
- 		outb(buffer[i], ha->io_addr + IPS_REG_FLDP);
--		if (ha->revision_id == IPS_REVID_TROMBONE64)
-+		if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
- 			udelay(25);	/* 25 us */
+ #define MBX_CONFIG_HBQ	    0x7C
+ #define MBX_LOAD_AREA       0x81
+@@ -1297,7 +1301,7 @@ typedef struct {		/* FireFly BIU registers */
+ #define MBX_REG_VNPID	    0x96
+ #define MBX_UNREG_VNPID	    0x97
  
- 		/* wait up to one second */
- 		timeout = 1000;
- 		while (timeout > 0) {
--			if (ha->revision_id == IPS_REVID_TROMBONE64) {
-+			if (ha->pcidev->revision == IPS_REVID_TROMBONE64) {
- 				outl(0, ha->io_addr + IPS_REG_FLAP);
- 				udelay(25);	/* 25 us */
- 			}
-@@ -6454,11 +6444,11 @@ ips_program_bios(ips_ha_t * ha, char *buffer, uint32_t buffersize,
- 		if (timeout == 0) {
- 			/* timeout error */
- 			outl(0, ha->io_addr + IPS_REG_FLAP);
--			if (ha->revision_id == IPS_REVID_TROMBONE64)
-+			if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
- 				udelay(25);	/* 25 us */
+-#define MBX_FLASH_WR_ULA    0x98
++#define MBX_WRITE_WWN       0x98
+ #define MBX_SET_DEBUG       0x99
+ #define MBX_LOAD_EXP_ROM    0x9C
  
- 			outb(0xFF, ha->io_addr + IPS_REG_FLDP);
--			if (ha->revision_id == IPS_REVID_TROMBONE64)
-+			if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
- 				udelay(25);	/* 25 us */
+@@ -1344,6 +1348,7 @@ typedef struct {		/* FireFly BIU registers */
  
- 			return (1);
-@@ -6468,11 +6458,11 @@ ips_program_bios(ips_ha_t * ha, char *buffer, uint32_t buffersize,
- 		if (status & 0x18) {
- 			/* programming error */
- 			outl(0, ha->io_addr + IPS_REG_FLAP);
--			if (ha->revision_id == IPS_REVID_TROMBONE64)
-+			if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
- 				udelay(25);	/* 25 us */
+ /*  SLI_2 IOCB Command Set */
  
- 			outb(0xFF, ha->io_addr + IPS_REG_FLDP);
--			if (ha->revision_id == IPS_REVID_TROMBONE64)
-+			if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
- 				udelay(25);	/* 25 us */
++#define CMD_ASYNC_STATUS        0x7C
+ #define CMD_RCV_SEQUENCE64_CX   0x81
+ #define CMD_XMIT_SEQUENCE64_CR  0x82
+ #define CMD_XMIT_SEQUENCE64_CX  0x83
+@@ -1368,6 +1373,7 @@ typedef struct {		/* FireFly BIU registers */
+ #define CMD_FCP_TRECEIVE64_CX   0xA1
+ #define CMD_FCP_TRSP64_CX       0xA3
  
- 			return (1);
-@@ -6481,11 +6471,11 @@ ips_program_bios(ips_ha_t * ha, char *buffer, uint32_t buffersize,
++#define CMD_QUE_XRI64_CX	0xB3
+ #define CMD_IOCB_RCV_SEQ64_CX	0xB5
+ #define CMD_IOCB_RCV_ELS64_CX	0xB7
+ #define CMD_IOCB_RCV_CONT64_CX	0xBB
+@@ -1406,6 +1412,8 @@ typedef struct {		/* FireFly BIU registers */
+ #define MBX_BUSY                   0xffffff /* Attempted cmd to busy Mailbox */
+ #define MBX_TIMEOUT                0xfffffe /* time-out expired waiting for */
  
- 	/* Enable reading */
- 	outl(0, ha->io_addr + IPS_REG_FLAP);
--	if (ha->revision_id == IPS_REVID_TROMBONE64)
-+	if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
- 		udelay(25);	/* 25 us */
++#define TEMPERATURE_OFFSET 0xB0	/* Slim offset for critical temperature event */
++
+ /*
+  *    Begin Structure Definitions for Mailbox Commands
+  */
+@@ -2606,6 +2614,18 @@ typedef struct {
+ 	uint32_t IPAddress;
+ } CONFIG_FARP_VAR;
  
- 	outb(0xFF, ha->io_addr + IPS_REG_FLDP);
--	if (ha->revision_id == IPS_REVID_TROMBONE64)
-+	if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
- 		udelay(25);	/* 25 us */
++/* Structure for MB Command MBX_ASYNCEVT_ENABLE (0x33) */
++
++typedef struct {
++#ifdef __BIG_ENDIAN_BITFIELD
++	uint32_t rsvd:30;
++	uint32_t ring:2;	/* Ring for ASYNC_EVENT iocb Bits 0-1*/
++#else /*  __LITTLE_ENDIAN */
++	uint32_t ring:2;	/* Ring for ASYNC_EVENT iocb Bits 0-1*/
++	uint32_t rsvd:30;
++#endif
++} ASYNCEVT_ENABLE_VAR;
++
+ /* Union of all Mailbox Command types */
+ #define MAILBOX_CMD_WSIZE	32
+ #define MAILBOX_CMD_SIZE	(MAILBOX_CMD_WSIZE * sizeof(uint32_t))
+@@ -2645,6 +2665,7 @@ typedef union {
+ 	CONFIG_PORT_VAR varCfgPort;	/* cmd = 0x88 (CONFIG_PORT)  */
+ 	REG_VPI_VAR varRegVpi;		/* cmd = 0x96 (REG_VPI) */
+ 	UNREG_VPI_VAR varUnregVpi;	/* cmd = 0x97 (UNREG_VPI) */
++	ASYNCEVT_ENABLE_VAR varCfgAsyncEvent; /*cmd = x33 (CONFIG_ASYNC) */
+ } MAILVARIANTS;
  
- 	return (0);
-@@ -6514,21 +6504,21 @@ ips_program_bios_memio(ips_ha_t * ha, char *buffer, uint32_t buffersize,
- 	for (i = 0; i < buffersize; i++) {
- 		/* write a byte */
- 		writel(i + offset, ha->mem_ptr + IPS_REG_FLAP);
--		if (ha->revision_id == IPS_REVID_TROMBONE64)
-+		if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
- 			udelay(25);	/* 25 us */
+ /*
+@@ -2973,6 +2994,34 @@ typedef struct {
+ #endif
+ } RCV_ELS_REQ64;
  
- 		writeb(0x40, ha->mem_ptr + IPS_REG_FLDP);
--		if (ha->revision_id == IPS_REVID_TROMBONE64)
-+		if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
- 			udelay(25);	/* 25 us */
++/* IOCB Command template for RCV_SEQ64 */
++struct rcv_seq64 {
++	struct ulp_bde64 elsReq;
++	uint32_t hbq_1;
++	uint32_t parmRo;
++#ifdef __BIG_ENDIAN_BITFIELD
++	uint32_t rctl:8;
++	uint32_t type:8;
++	uint32_t dfctl:8;
++	uint32_t ls:1;
++	uint32_t fs:1;
++	uint32_t rsvd2:3;
++	uint32_t si:1;
++	uint32_t bc:1;
++	uint32_t rsvd3:1;
++#else	/*  __LITTLE_ENDIAN_BITFIELD */
++	uint32_t rsvd3:1;
++	uint32_t bc:1;
++	uint32_t si:1;
++	uint32_t rsvd2:3;
++	uint32_t fs:1;
++	uint32_t ls:1;
++	uint32_t dfctl:8;
++	uint32_t type:8;
++	uint32_t rctl:8;
++#endif
++};
++
+ /* IOCB Command template for all 64 bit FCP Initiator commands */
+ typedef struct {
+ 	ULP_BDL bdl;
+@@ -2987,6 +3036,21 @@ typedef struct {
+ 	uint32_t fcpt_Length;	/* transfer ready for IWRITE */
+ } FCPT_FIELDS64;
  
- 		writeb(buffer[i], ha->mem_ptr + IPS_REG_FLDP);
--		if (ha->revision_id == IPS_REVID_TROMBONE64)
-+		if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
- 			udelay(25);	/* 25 us */
++/* IOCB Command template for Async Status iocb commands */
++typedef struct {
++	uint32_t rsvd[4];
++	uint32_t param;
++#ifdef __BIG_ENDIAN_BITFIELD
++	uint16_t evt_code;		/* High order bits word 5 */
++	uint16_t sub_ctxt_tag;		/* Low  order bits word 5 */
++#else   /*  __LITTLE_ENDIAN_BITFIELD */
++	uint16_t sub_ctxt_tag;		/* High order bits word 5 */
++	uint16_t evt_code;		/* Low  order bits word 5 */
++#endif
++} ASYNCSTAT_FIELDS;
++#define ASYNC_TEMP_WARN		0x100
++#define ASYNC_TEMP_SAFE		0x101
++
+ /* IOCB Command template for CMD_IOCB_RCV_ELS64_CX (0xB7)
+    or CMD_IOCB_RCV_SEQ64_CX (0xB5) */
  
- 		/* wait up to one second */
- 		timeout = 1000;
- 		while (timeout > 0) {
--			if (ha->revision_id == IPS_REVID_TROMBONE64) {
-+			if (ha->pcidev->revision == IPS_REVID_TROMBONE64) {
- 				writel(0, ha->mem_ptr + IPS_REG_FLAP);
- 				udelay(25);	/* 25 us */
- 			}
-@@ -6545,11 +6535,11 @@ ips_program_bios_memio(ips_ha_t * ha, char *buffer, uint32_t buffersize,
- 		if (timeout == 0) {
- 			/* timeout error */
- 			writel(0, ha->mem_ptr + IPS_REG_FLAP);
--			if (ha->revision_id == IPS_REVID_TROMBONE64)
-+			if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
- 				udelay(25);	/* 25 us */
+@@ -3004,7 +3068,26 @@ struct rcv_sli3 {
+ 	struct ulp_bde64 bde2;
+ };
  
- 			writeb(0xFF, ha->mem_ptr + IPS_REG_FLDP);
--			if (ha->revision_id == IPS_REVID_TROMBONE64)
-+			if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
- 				udelay(25);	/* 25 us */
++/* Structure used for a single HBQ entry */
++struct lpfc_hbq_entry {
++	struct ulp_bde64 bde;
++	uint32_t buffer_tag;
++};
  
- 			return (1);
-@@ -6559,11 +6549,11 @@ ips_program_bios_memio(ips_ha_t * ha, char *buffer, uint32_t buffersize,
- 		if (status & 0x18) {
- 			/* programming error */
- 			writel(0, ha->mem_ptr + IPS_REG_FLAP);
--			if (ha->revision_id == IPS_REVID_TROMBONE64)
-+			if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
- 				udelay(25);	/* 25 us */
++/* IOCB Command template for QUE_XRI64_CX (0xB3) command */
++typedef struct {
++	struct lpfc_hbq_entry   buff;
++	uint32_t                rsvd;
++	uint32_t		rsvd1;
++} QUE_XRI64_CX_FIELDS;
++
++struct que_xri64cx_ext_fields {
++	uint32_t	iotag64_low;
++	uint32_t	iotag64_high;
++	uint32_t	ebde_count;
++	uint32_t	rsvd;
++	struct lpfc_hbq_entry	buff[5];
++};
  
- 			writeb(0xFF, ha->mem_ptr + IPS_REG_FLDP);
--			if (ha->revision_id == IPS_REVID_TROMBONE64)
-+			if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
- 				udelay(25);	/* 25 us */
+ typedef struct _IOCB {	/* IOCB structure */
+ 	union {
+@@ -3028,6 +3111,9 @@ typedef struct _IOCB {	/* IOCB structure */
+ 		XMT_SEQ_FIELDS64 xseq64;	/* XMIT / BCAST cmd */
+ 		FCPI_FIELDS64 fcpi64;	/* FCP 64 bit Initiator template */
+ 		FCPT_FIELDS64 fcpt64;	/* FCP 64 bit target template */
++		ASYNCSTAT_FIELDS asyncstat; /* async_status iocb */
++		QUE_XRI64_CX_FIELDS quexri64cx; /* que_xri64_cx fields */
++		struct rcv_seq64 rcvseq64;	/* RCV_SEQ64 and RCV_CONT64 */
  
- 			return (1);
-@@ -6572,11 +6562,11 @@ ips_program_bios_memio(ips_ha_t * ha, char *buffer, uint32_t buffersize,
+ 		uint32_t ulpWord[IOCB_WORD_SZ - 2];	/* generic 6 'words' */
+ 	} un;
+@@ -3085,6 +3171,10 @@ typedef struct _IOCB {	/* IOCB structure */
  
- 	/* Enable reading */
- 	writel(0, ha->mem_ptr + IPS_REG_FLAP);
--	if (ha->revision_id == IPS_REVID_TROMBONE64)
-+	if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
- 		udelay(25);	/* 25 us */
+ 	union {
+ 		struct rcv_sli3 rcvsli3; /* words 8 - 15 */
++
++		/* words 8-31 used for que_xri_cx iocb */
++		struct que_xri64cx_ext_fields que_xri64cx_ext_words;
++
+ 		uint32_t sli3Words[24]; /* 96 extra bytes for SLI-3 */
+ 	} unsli3;
  
- 	writeb(0xFF, ha->mem_ptr + IPS_REG_FLDP);
--	if (ha->revision_id == IPS_REVID_TROMBONE64)
-+	if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
- 		udelay(25);	/* 25 us */
+@@ -3124,12 +3214,6 @@ typedef struct _IOCB {	/* IOCB structure */
  
- 	return (0);
-@@ -6601,14 +6591,14 @@ ips_verify_bios(ips_ha_t * ha, char *buffer, uint32_t buffersize,
+ } IOCB_t;
  
- 	/* test 1st byte */
- 	outl(0, ha->io_addr + IPS_REG_FLAP);
--	if (ha->revision_id == IPS_REVID_TROMBONE64)
-+	if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
- 		udelay(25);	/* 25 us */
+-/* Structure used for a single HBQ entry */
+-struct lpfc_hbq_entry {
+-	struct ulp_bde64 bde;
+-	uint32_t buffer_tag;
+-};
+-
  
- 	if (inb(ha->io_addr + IPS_REG_FLDP) != 0x55)
- 		return (1);
+ #define SLI1_SLIM_SIZE   (4 * 1024)
  
- 	outl(cpu_to_le32(1), ha->io_addr + IPS_REG_FLAP);
--	if (ha->revision_id == IPS_REVID_TROMBONE64)
-+	if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
- 		udelay(25);	/* 25 us */
- 	if (inb(ha->io_addr + IPS_REG_FLDP) != 0xAA)
- 		return (1);
-@@ -6617,7 +6607,7 @@ ips_verify_bios(ips_ha_t * ha, char *buffer, uint32_t buffersize,
- 	for (i = 2; i < buffersize; i++) {
+@@ -3172,6 +3256,8 @@ lpfc_is_LC_HBA(unsigned short device)
+ 	    (device == PCI_DEVICE_ID_BSMB) ||
+ 	    (device == PCI_DEVICE_ID_ZMID) ||
+ 	    (device == PCI_DEVICE_ID_ZSMB) ||
++	    (device == PCI_DEVICE_ID_SAT_MID) ||
++	    (device == PCI_DEVICE_ID_SAT_SMB) ||
+ 	    (device == PCI_DEVICE_ID_RFLY))
+ 		return 1;
+ 	else
+diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c
+index ecebdfa..3205f74 100644
+--- a/drivers/scsi/lpfc/lpfc_init.c
++++ b/drivers/scsi/lpfc/lpfc_init.c
+@@ -212,6 +212,18 @@ out_free_mbox:
+ 	return 0;
+ }
  
- 		outl(cpu_to_le32(i + offset), ha->io_addr + IPS_REG_FLAP);
--		if (ha->revision_id == IPS_REVID_TROMBONE64)
-+		if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
- 			udelay(25);	/* 25 us */
++/* Completion handler for config async event mailbox command. */
++static void
++lpfc_config_async_cmpl(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmboxq)
++{
++	if (pmboxq->mb.mbxStatus == MBX_SUCCESS)
++		phba->temp_sensor_support = 1;
++	else
++		phba->temp_sensor_support = 0;
++	mempool_free(pmboxq, phba->mbox_mem_pool);
++	return;
++}
++
+ /************************************************************************/
+ /*                                                                      */
+ /*    lpfc_config_port_post                                             */
+@@ -234,6 +246,15 @@ lpfc_config_port_post(struct lpfc_hba *phba)
+ 	int i, j;
+ 	int rc;
  
- 		checksum = (uint8_t) checksum + inb(ha->io_addr + IPS_REG_FLDP);
-@@ -6650,14 +6640,14 @@ ips_verify_bios_memio(ips_ha_t * ha, char *buffer, uint32_t buffersize,
++	spin_lock_irq(&phba->hbalock);
++	/*
++	 * If the Config port completed correctly the HBA is not
++	 * over heated any more.
++	 */
++	if (phba->over_temp_state == HBA_OVER_TEMP)
++		phba->over_temp_state = HBA_NORMAL_TEMP;
++	spin_unlock_irq(&phba->hbalock);
++
+ 	pmb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+ 	if (!pmb) {
+ 		phba->link_state = LPFC_HBA_ERROR;
+@@ -343,7 +364,7 @@ lpfc_config_port_post(struct lpfc_hba *phba)
  
- 	/* test 1st byte */
- 	writel(0, ha->mem_ptr + IPS_REG_FLAP);
--	if (ha->revision_id == IPS_REVID_TROMBONE64)
-+	if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
- 		udelay(25);	/* 25 us */
+ 	phba->link_state = LPFC_LINK_DOWN;
  
- 	if (readb(ha->mem_ptr + IPS_REG_FLDP) != 0x55)
- 		return (1);
+-	/* Only process IOCBs on ring 0 till hba_state is READY */
++	/* Only process IOCBs on ELS ring till hba_state is READY */
+ 	if (psli->ring[psli->extra_ring].cmdringaddr)
+ 		psli->ring[psli->extra_ring].flag |= LPFC_STOP_IOCB_EVENT;
+ 	if (psli->ring[psli->fcp_ring].cmdringaddr)
+@@ -409,7 +430,21 @@ lpfc_config_port_post(struct lpfc_hba *phba)
+ 		return -EIO;
+ 	}
+ 	/* MBOX buffer will be freed in mbox compl */
++	pmb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
++	lpfc_config_async(phba, pmb, LPFC_ELS_RING);
++	pmb->mbox_cmpl = lpfc_config_async_cmpl;
++	pmb->vport = phba->pport;
++	rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT);
  
- 	writel(1, ha->mem_ptr + IPS_REG_FLAP);
--	if (ha->revision_id == IPS_REVID_TROMBONE64)
-+	if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
- 		udelay(25);	/* 25 us */
- 	if (readb(ha->mem_ptr + IPS_REG_FLDP) != 0xAA)
- 		return (1);
-@@ -6666,7 +6656,7 @@ ips_verify_bios_memio(ips_ha_t * ha, char *buffer, uint32_t buffersize,
- 	for (i = 2; i < buffersize; i++) {
++	if ((rc != MBX_BUSY) && (rc != MBX_SUCCESS)) {
++		lpfc_printf_log(phba,
++				KERN_ERR,
++				LOG_INIT,
++				"0456 Adapter failed to issue "
++				"ASYNCEVT_ENABLE mbox status x%x \n.",
++				rc);
++		mempool_free(pmb, phba->mbox_mem_pool);
++	}
+ 	return (0);
+ }
  
- 		writel(i + offset, ha->mem_ptr + IPS_REG_FLAP);
--		if (ha->revision_id == IPS_REVID_TROMBONE64)
-+		if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
- 			udelay(25);	/* 25 us */
+@@ -449,6 +484,9 @@ lpfc_hba_down_post(struct lpfc_hba *phba)
+ 	struct lpfc_sli *psli = &phba->sli;
+ 	struct lpfc_sli_ring *pring;
+ 	struct lpfc_dmabuf *mp, *next_mp;
++	struct lpfc_iocbq *iocb;
++	IOCB_t *cmd = NULL;
++	LIST_HEAD(completions);
+ 	int i;
  
- 		checksum =
-@@ -6837,24 +6827,18 @@ ips_register_scsi(int index)
- 	}
- 	ha = IPS_HA(sh);
- 	memcpy(ha, oldha, sizeof (ips_ha_t));
--	free_irq(oldha->irq, oldha);
-+	free_irq(oldha->pcidev->irq, oldha);
- 	/* Install the interrupt handler with the new ha */
--	if (request_irq(ha->irq, do_ipsintr, IRQF_SHARED, ips_name, ha)) {
-+	if (request_irq(ha->pcidev->irq, do_ipsintr, IRQF_SHARED, ips_name, ha)) {
- 		IPS_PRINTK(KERN_WARNING, ha->pcidev,
- 			   "Unable to install interrupt handler\n");
--		scsi_host_put(sh);
--		return -1;
-+		goto err_out_sh;
+ 	if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED)
+@@ -464,16 +502,42 @@ lpfc_hba_down_post(struct lpfc_hba *phba)
+ 		}
  	}
  
- 	kfree(oldha);
--	ips_sh[index] = sh;
--	ips_ha[index] = ha;
- 
- 	/* Store away needed values for later use */
--	sh->io_port = ha->io_addr;
--	sh->n_io_port = ha->io_addr ? 255 : 0;
- 	sh->unique_id = (ha->io_addr) ? ha->io_addr : ha->mem_addr;
--	sh->irq = ha->irq;
- 	sh->sg_tablesize = sh->hostt->sg_tablesize;
- 	sh->can_queue = sh->hostt->can_queue;
- 	sh->cmd_per_lun = sh->hostt->cmd_per_lun;
-@@ -6867,10 +6851,21 @@ ips_register_scsi(int index)
- 	sh->max_channel = ha->nbus - 1;
- 	sh->can_queue = ha->max_cmds - 1;
- 
--	scsi_add_host(sh, NULL);
-+	if (scsi_add_host(sh, &ha->pcidev->dev))
-+		goto err_out;
++	spin_lock_irq(&phba->hbalock);
+ 	for (i = 0; i < psli->num_rings; i++) {
+ 		pring = &psli->ring[i];
 +
-+	ips_sh[index] = sh;
-+	ips_ha[index] = ha;
++		/* At this point in time the HBA is either reset or DOA. Either
++		 * way, nothing should be on txcmplq as it will NEVER complete.
++		 */
++		list_splice_init(&pring->txcmplq, &completions);
++		pring->txcmplq_cnt = 0;
++		spin_unlock_irq(&phba->hbalock);
 +
- 	scsi_scan_host(sh);
++		while (!list_empty(&completions)) {
++			iocb = list_get_first(&completions, struct lpfc_iocbq,
++				list);
++			cmd = &iocb->iocb;
++			list_del_init(&iocb->list);
++
++			if (!iocb->iocb_cmpl)
++				lpfc_sli_release_iocbq(phba, iocb);
++			else {
++				cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
++				cmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
++				(iocb->iocb_cmpl) (phba, iocb, iocb);
++			}
++		}
++
+ 		lpfc_sli_abort_iocb_ring(phba, pring);
++		spin_lock_irq(&phba->hbalock);
+ 	}
++	spin_unlock_irq(&phba->hbalock);
  
  	return 0;
-+
-+err_out:
-+	free_irq(ha->pcidev->irq, ha);
-+err_out_sh:
-+	scsi_host_put(sh);
-+	return -1;
  }
  
- /*---------------------------------------------------------------------------*/
-@@ -6882,20 +6877,14 @@ ips_register_scsi(int index)
- static void __devexit
- ips_remove_device(struct pci_dev *pci_dev)
+ /* HBA heart beat timeout handler */
+-void
++static void
+ lpfc_hb_timeout(unsigned long ptr)
  {
--	int i;
--	struct Scsi_Host *sh;
--	ips_ha_t *ha;
-+	struct Scsi_Host *sh = pci_get_drvdata(pci_dev);
- 
--	for (i = 0; i < IPS_MAX_ADAPTERS; i++) {
--		ha = ips_ha[i];
--		if (ha) {
--			if ((pci_dev->bus->number == ha->pcidev->bus->number) &&
--			    (pci_dev->devfn == ha->pcidev->devfn)) {
--				sh = ips_sh[i];
--				ips_release(sh);
--			}
--		}
--	}
-+	pci_set_drvdata(pci_dev, NULL);
-+
-+	ips_release(sh);
-+
-+	pci_release_regions(pci_dev);
-+	pci_disable_device(pci_dev);
- }
- 
- /****************************************************************************/
-@@ -6949,12 +6938,17 @@ module_exit(ips_module_exit);
- static int __devinit
- ips_insert_device(struct pci_dev *pci_dev, const struct pci_device_id *ent)
+ 	struct lpfc_hba *phba;
+@@ -512,8 +576,10 @@ void
+ lpfc_hb_timeout_handler(struct lpfc_hba *phba)
  {
--	int uninitialized_var(index);
-+	int index = -1;
- 	int rc;
+ 	LPFC_MBOXQ_t *pmboxq;
++	struct lpfc_dmabuf *buf_ptr;
+ 	int retval;
+ 	struct lpfc_sli *psli = &phba->sli;
++	LIST_HEAD(completions);
  
- 	METHOD_TRACE("ips_insert_device", 1);
--	if (pci_enable_device(pci_dev))
--		return -1;
-+	rc = pci_enable_device(pci_dev);
-+	if (rc)
-+		return rc;
+ 	if ((phba->link_state == LPFC_HBA_ERROR) ||
+ 		(phba->pport->load_flag & FC_UNLOADING) ||
+@@ -540,49 +606,88 @@ lpfc_hb_timeout_handler(struct lpfc_hba *phba)
+ 	}
+ 	spin_unlock_irq(&phba->pport->work_port_lock);
+ 
+-	/* If there is no heart beat outstanding, issue a heartbeat command */
+-	if (!phba->hb_outstanding) {
+-		pmboxq = mempool_alloc(phba->mbox_mem_pool,GFP_KERNEL);
+-		if (!pmboxq) {
+-			mod_timer(&phba->hb_tmofunc,
+-				jiffies + HZ * LPFC_HB_MBOX_INTERVAL);
+-			return;
++	if (phba->elsbuf_cnt &&
++		(phba->elsbuf_cnt == phba->elsbuf_prev_cnt)) {
++		spin_lock_irq(&phba->hbalock);
++		list_splice_init(&phba->elsbuf, &completions);
++		phba->elsbuf_cnt = 0;
++		phba->elsbuf_prev_cnt = 0;
++		spin_unlock_irq(&phba->hbalock);
 +
-+	rc = pci_request_regions(pci_dev, "ips");
-+	if (rc)
-+		goto err_out;
++		while (!list_empty(&completions)) {
++			list_remove_head(&completions, buf_ptr,
++				struct lpfc_dmabuf, list);
++			lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys);
++			kfree(buf_ptr);
+ 		}
++	}
++	phba->elsbuf_prev_cnt = phba->elsbuf_cnt;
  
- 	rc = ips_init_phase1(pci_dev, &index);
- 	if (rc == SUCCESS)
-@@ -6970,6 +6964,19 @@ ips_insert_device(struct pci_dev *pci_dev, const struct pci_device_id *ent)
- 		ips_num_controllers++;
+-		lpfc_heart_beat(phba, pmboxq);
+-		pmboxq->mbox_cmpl = lpfc_hb_mbox_cmpl;
+-		pmboxq->vport = phba->pport;
+-		retval = lpfc_sli_issue_mbox(phba, pmboxq, MBX_NOWAIT);
++	/* If there is no heart beat outstanding, issue a heartbeat command */
++	if (phba->cfg_enable_hba_heartbeat) {
++		if (!phba->hb_outstanding) {
++			pmboxq = mempool_alloc(phba->mbox_mem_pool,GFP_KERNEL);
++			if (!pmboxq) {
++				mod_timer(&phba->hb_tmofunc,
++					  jiffies + HZ * LPFC_HB_MBOX_INTERVAL);
++				return;
++			}
  
- 	ips_next_controller = ips_num_controllers;
+-		if (retval != MBX_BUSY && retval != MBX_SUCCESS) {
+-			mempool_free(pmboxq, phba->mbox_mem_pool);
++			lpfc_heart_beat(phba, pmboxq);
++			pmboxq->mbox_cmpl = lpfc_hb_mbox_cmpl;
++			pmboxq->vport = phba->pport;
++			retval = lpfc_sli_issue_mbox(phba, pmboxq, MBX_NOWAIT);
 +
-+	if (rc < 0) {
-+		rc = -ENODEV;
-+		goto err_out_regions;
-+	}
++			if (retval != MBX_BUSY && retval != MBX_SUCCESS) {
++				mempool_free(pmboxq, phba->mbox_mem_pool);
++				mod_timer(&phba->hb_tmofunc,
++					  jiffies + HZ * LPFC_HB_MBOX_INTERVAL);
++				return;
++			}
+ 			mod_timer(&phba->hb_tmofunc,
+-				jiffies + HZ * LPFC_HB_MBOX_INTERVAL);
++				  jiffies + HZ * LPFC_HB_MBOX_TIMEOUT);
++			phba->hb_outstanding = 1;
+ 			return;
++		} else {
++			/*
++			* If heart beat timeout called with hb_outstanding set
++			* we need to take the HBA offline.
++			*/
++			lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
++					"0459 Adapter heartbeat failure, "
++					"taking this port offline.\n");
 +
-+	pci_set_drvdata(pci_dev, ips_sh[index]);
-+	return 0;
++			spin_lock_irq(&phba->hbalock);
++			psli->sli_flag &= ~LPFC_SLI2_ACTIVE;
++			spin_unlock_irq(&phba->hbalock);
 +
-+err_out_regions:
-+	pci_release_regions(pci_dev);
-+err_out:
-+	pci_disable_device(pci_dev);
- 	return rc;
- }
- 
-@@ -6992,8 +6999,6 @@ ips_init_phase1(struct pci_dev *pci_dev, int *indexPtr)
- 	uint32_t mem_len;
- 	uint8_t bus;
- 	uint8_t func;
--	uint8_t irq;
--	uint16_t subdevice_id;
- 	int j;
- 	int index;
- 	dma_addr_t dma_address;
-@@ -7004,7 +7009,7 @@ ips_init_phase1(struct pci_dev *pci_dev, int *indexPtr)
- 	METHOD_TRACE("ips_init_phase1", 1);
- 	index = IPS_MAX_ADAPTERS;
- 	for (j = 0; j < IPS_MAX_ADAPTERS; j++) {
--		if (ips_ha[j] == 0) {
-+		if (ips_ha[j] == NULL) {
- 			index = j;
- 			break;
++			lpfc_offline_prep(phba);
++			lpfc_offline(phba);
++			lpfc_unblock_mgmt_io(phba);
++			phba->link_state = LPFC_HBA_ERROR;
++			lpfc_hba_down_post(phba);
  		}
-@@ -7014,7 +7019,6 @@ ips_init_phase1(struct pci_dev *pci_dev, int *indexPtr)
- 		return -1;
- 
- 	/* stuff that we get in dev */
--	irq = pci_dev->irq;
- 	bus = pci_dev->bus->number;
- 	func = pci_dev->devfn;
- 
-@@ -7042,34 +7046,17 @@ ips_init_phase1(struct pci_dev *pci_dev, int *indexPtr)
- 		uint32_t base;
- 		uint32_t offs;
+-		mod_timer(&phba->hb_tmofunc,
+-			jiffies + HZ * LPFC_HB_MBOX_TIMEOUT);
+-		phba->hb_outstanding = 1;
+-		return;
+-	} else {
+-		/*
+-		 * If heart beat timeout called with hb_outstanding set we
+-		 * need to take the HBA offline.
+-		 */
+-		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+-				"0459 Adapter heartbeat failure, taking "
+-				"this port offline.\n");
++	}
++}
  
--		if (!request_mem_region(mem_addr, mem_len, "ips")) {
--			IPS_PRINTK(KERN_WARNING, pci_dev,
--				   "Couldn't allocate IO Memory space %x len %d.\n",
--				   mem_addr, mem_len);
--			return -1;
--		}
--
- 		base = mem_addr & PAGE_MASK;
- 		offs = mem_addr - base;
- 		ioremap_ptr = ioremap(base, PAGE_SIZE);
-+		if (!ioremap_ptr)
-+			return -1;
- 		mem_ptr = ioremap_ptr + offs;
- 	} else {
- 		ioremap_ptr = NULL;
- 		mem_ptr = NULL;
- 	}
+-		spin_lock_irq(&phba->hbalock);
+-		psli->sli_flag &= ~LPFC_SLI2_ACTIVE;
+-		spin_unlock_irq(&phba->hbalock);
++static void
++lpfc_offline_eratt(struct lpfc_hba *phba)
++{
++	struct lpfc_sli   *psli = &phba->sli;
  
--	/* setup I/O mapped area (if applicable) */
--	if (io_addr) {
--		if (!request_region(io_addr, io_len, "ips")) {
--			IPS_PRINTK(KERN_WARNING, pci_dev,
--				   "Couldn't allocate IO space %x len %d.\n",
--				   io_addr, io_len);
--			return -1;
--		}
+-		lpfc_offline_prep(phba);
+-		lpfc_offline(phba);
+-		lpfc_unblock_mgmt_io(phba);
+-		phba->link_state = LPFC_HBA_ERROR;
+-		lpfc_hba_down_post(phba);
 -	}
--
--	subdevice_id = pci_dev->subsystem_device;
--
- 	/* found a controller */
- 	ha = kzalloc(sizeof (ips_ha_t), GFP_KERNEL);
- 	if (ha == NULL) {
-@@ -7078,13 +7065,11 @@ ips_init_phase1(struct pci_dev *pci_dev, int *indexPtr)
- 		return -1;
- 	}
++	spin_lock_irq(&phba->hbalock);
++	psli->sli_flag &= ~LPFC_SLI2_ACTIVE;
++	spin_unlock_irq(&phba->hbalock);
++	lpfc_offline_prep(phba);
++
++	lpfc_offline(phba);
++	lpfc_reset_barrier(phba);
++	lpfc_sli_brdreset(phba);
++	lpfc_hba_down_post(phba);
++	lpfc_sli_brdready(phba, HS_MBRDY);
++	lpfc_unblock_mgmt_io(phba);
++	phba->link_state = LPFC_HBA_ERROR;
++	return;
+ }
  
--
- 	ips_sh[index] = NULL;
- 	ips_ha[index] = ha;
- 	ha->active = 1;
+ /************************************************************************/
+@@ -601,6 +706,8 @@ lpfc_handle_eratt(struct lpfc_hba *phba)
+ 	struct lpfc_sli_ring  *pring;
+ 	struct lpfc_vport **vports;
+ 	uint32_t event_data;
++	unsigned long temperature;
++	struct temp_event temp_event_data;
+ 	struct Scsi_Host  *shost;
+ 	int i;
  
- 	/* Store info in HA structure */
--	ha->irq = irq;
- 	ha->io_addr = io_addr;
- 	ha->io_len = io_len;
- 	ha->mem_addr = mem_addr;
-@@ -7092,10 +7077,7 @@ ips_init_phase1(struct pci_dev *pci_dev, int *indexPtr)
- 	ha->mem_ptr = mem_ptr;
- 	ha->ioremap_ptr = ioremap_ptr;
- 	ha->host_num = (uint32_t) index;
--	ha->revision_id = pci_dev->revision;
- 	ha->slot_num = PCI_SLOT(pci_dev->devfn);
--	ha->device_id = pci_dev->device;
--	ha->subdevice_id = subdevice_id;
- 	ha->pcidev = pci_dev;
+@@ -608,6 +715,9 @@ lpfc_handle_eratt(struct lpfc_hba *phba)
+ 	 * since we cannot communicate with the pci card anyway. */
+ 	if (pci_channel_offline(phba->pcidev))
+ 		return;
++	/* If resets are disabled then leave the HBA alone and return */
++	if (!phba->cfg_enable_hba_reset)
++		return;
  
- 	/*
-@@ -7240,7 +7222,7 @@ ips_init_phase2(int index)
- 	}
+ 	if (phba->work_hs & HS_FFER6 ||
+ 	    phba->work_hs & HS_FFER5) {
+@@ -620,14 +730,14 @@ lpfc_handle_eratt(struct lpfc_hba *phba)
+ 		vports = lpfc_create_vport_work_array(phba);
+ 		if (vports != NULL)
+ 			for(i = 0;
+-			    i < LPFC_MAX_VPORTS && vports[i] != NULL;
++			    i <= phba->max_vpi && vports[i] != NULL;
+ 			    i++){
+ 				shost = lpfc_shost_from_vport(vports[i]);
+ 				spin_lock_irq(shost->host_lock);
+ 				vports[i]->fc_flag |= FC_ESTABLISH_LINK;
+ 				spin_unlock_irq(shost->host_lock);
+ 			}
+-		lpfc_destroy_vport_work_array(vports);
++		lpfc_destroy_vport_work_array(phba, vports);
+ 		spin_lock_irq(&phba->hbalock);
+ 		psli->sli_flag &= ~LPFC_SLI2_ACTIVE;
+ 		spin_unlock_irq(&phba->hbalock);
+@@ -655,6 +765,31 @@ lpfc_handle_eratt(struct lpfc_hba *phba)
+ 			return;
+ 		}
+ 		lpfc_unblock_mgmt_io(phba);
++	} else if (phba->work_hs & HS_CRIT_TEMP) {
++		temperature = readl(phba->MBslimaddr + TEMPERATURE_OFFSET);
++		temp_event_data.event_type = FC_REG_TEMPERATURE_EVENT;
++		temp_event_data.event_code = LPFC_CRIT_TEMP;
++		temp_event_data.data = (uint32_t)temperature;
++
++		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
++				"0459 Adapter maximum temperature exceeded "
++				"(%ld), taking this port offline "
++				"Data: x%x x%x x%x\n",
++				temperature, phba->work_hs,
++				phba->work_status[0], phba->work_status[1]);
++
++		shost = lpfc_shost_from_vport(phba->pport);
++		fc_host_post_vendor_event(shost, fc_get_event_number(),
++					  sizeof(temp_event_data),
++					  (char *) &temp_event_data,
++					  SCSI_NL_VID_TYPE_PCI
++					  | PCI_VENDOR_ID_EMULEX);
++
++		spin_lock_irq(&phba->hbalock);
++		phba->over_temp_state = HBA_OVER_TEMP;
++		spin_unlock_irq(&phba->hbalock);
++		lpfc_offline_eratt(phba);
++
+ 	} else {
+ 		/* The if clause above forces this code path when the status
+ 		 * failure is a value other than FFER6.  Do not call the offline
+@@ -672,14 +807,7 @@ lpfc_handle_eratt(struct lpfc_hba *phba)
+ 				sizeof(event_data), (char *) &event_data,
+ 				SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_EMULEX);
  
- 	/* Install the interrupt handler */
--	if (request_irq(ha->irq, do_ipsintr, IRQF_SHARED, ips_name, ha)) {
-+	if (request_irq(ha->pcidev->irq, do_ipsintr, IRQF_SHARED, ips_name, ha)) {
- 		IPS_PRINTK(KERN_WARNING, ha->pcidev,
- 			   "Unable to install interrupt handler\n");
- 		return ips_abort_init(ha, index);
-@@ -7253,14 +7235,14 @@ ips_init_phase2(int index)
- 	if (!ips_allocatescbs(ha)) {
- 		IPS_PRINTK(KERN_WARNING, ha->pcidev,
- 			   "Unable to allocate a CCB\n");
--		free_irq(ha->irq, ha);
-+		free_irq(ha->pcidev->irq, ha);
- 		return ips_abort_init(ha, index);
+-		spin_lock_irq(&phba->hbalock);
+-		psli->sli_flag &= ~LPFC_SLI2_ACTIVE;
+-		spin_unlock_irq(&phba->hbalock);
+-		lpfc_offline_prep(phba);
+-		lpfc_offline(phba);
+-		lpfc_unblock_mgmt_io(phba);
+-		phba->link_state = LPFC_HBA_ERROR;
+-		lpfc_hba_down_post(phba);
++		lpfc_offline_eratt(phba);
  	}
+ }
  
- 	if (!ips_hainit(ha)) {
- 		IPS_PRINTK(KERN_WARNING, ha->pcidev,
- 			   "Unable to initialize controller\n");
--		free_irq(ha->irq, ha);
-+		free_irq(ha->pcidev->irq, ha);
- 		return ips_abort_init(ha, index);
- 	}
- 	/* Free the temporary SCB */
-@@ -7270,7 +7252,7 @@ ips_init_phase2(int index)
- 	if (!ips_allocatescbs(ha)) {
- 		IPS_PRINTK(KERN_WARNING, ha->pcidev,
- 			   "Unable to allocate CCBs\n");
--		free_irq(ha->irq, ha);
-+		free_irq(ha->pcidev->irq, ha);
- 		return ips_abort_init(ha, index);
- 	}
+@@ -699,21 +827,25 @@ lpfc_handle_latt(struct lpfc_hba *phba)
+ 	LPFC_MBOXQ_t *pmb;
+ 	volatile uint32_t control;
+ 	struct lpfc_dmabuf *mp;
+-	int rc = -ENOMEM;
++	int rc = 0;
  
-diff --git a/drivers/scsi/ips.h b/drivers/scsi/ips.h
-index 3bcbd9f..e0657b6 100644
---- a/drivers/scsi/ips.h
-+++ b/drivers/scsi/ips.h
-@@ -60,14 +60,14 @@
-     */
-    #define IPS_HA(x)                   ((ips_ha_t *) x->hostdata)
-    #define IPS_COMMAND_ID(ha, scb)     (int) (scb - ha->scbs)
--   #define IPS_IS_TROMBONE(ha)         (((ha->device_id == IPS_DEVICEID_COPPERHEAD) && \
--                                         (ha->revision_id >= IPS_REVID_TROMBONE32) && \
--                                         (ha->revision_id <= IPS_REVID_TROMBONE64)) ? 1 : 0)
--   #define IPS_IS_CLARINET(ha)         (((ha->device_id == IPS_DEVICEID_COPPERHEAD) && \
--                                         (ha->revision_id >= IPS_REVID_CLARINETP1) && \
--                                         (ha->revision_id <= IPS_REVID_CLARINETP3)) ? 1 : 0)
--   #define IPS_IS_MORPHEUS(ha)         (ha->device_id == IPS_DEVICEID_MORPHEUS)
--   #define IPS_IS_MARCO(ha)            (ha->device_id == IPS_DEVICEID_MARCO)
-+   #define IPS_IS_TROMBONE(ha)         (((ha->pcidev->device == IPS_DEVICEID_COPPERHEAD) && \
-+                                         (ha->pcidev->revision >= IPS_REVID_TROMBONE32) && \
-+                                         (ha->pcidev->revision <= IPS_REVID_TROMBONE64)) ? 1 : 0)
-+   #define IPS_IS_CLARINET(ha)         (((ha->pcidev->device == IPS_DEVICEID_COPPERHEAD) && \
-+                                         (ha->pcidev->revision >= IPS_REVID_CLARINETP1) && \
-+                                         (ha->pcidev->revision <= IPS_REVID_CLARINETP3)) ? 1 : 0)
-+   #define IPS_IS_MORPHEUS(ha)         (ha->pcidev->device == IPS_DEVICEID_MORPHEUS)
-+   #define IPS_IS_MARCO(ha)            (ha->pcidev->device == IPS_DEVICEID_MARCO)
-    #define IPS_USE_I2O_DELIVER(ha)     ((IPS_IS_MORPHEUS(ha) || \
-                                          (IPS_IS_TROMBONE(ha) && \
-                                           (ips_force_i2o))) ? 1 : 0)
-@@ -92,7 +92,7 @@
-    #ifndef min
-       #define min(x,y) ((x) < (y) ? x : y)
-    #endif
--   
-+
-    #ifndef __iomem       /* For clean compiles in earlier kernels without __iomem annotations */
-       #define __iomem
-    #endif
-@@ -171,7 +171,7 @@
-    #define IPS_CMD_DOWNLOAD             0x20
-    #define IPS_CMD_RW_BIOSFW            0x22
-    #define IPS_CMD_GET_VERSION_INFO     0xC6
--   #define IPS_CMD_RESET_CHANNEL        0x1A  
-+   #define IPS_CMD_RESET_CHANNEL        0x1A
+ 	pmb = (LPFC_MBOXQ_t *)mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+-	if (!pmb)
++	if (!pmb) {
++		rc = 1;
+ 		goto lpfc_handle_latt_err_exit;
++	}
  
-    /*
-     * Adapter Equates
-@@ -458,7 +458,7 @@ typedef struct {
-    uint32_t reserved3;
-    uint32_t buffer_addr;
-    uint32_t reserved4;
--} IPS_IOCTL_CMD, *PIPS_IOCTL_CMD; 
-+} IPS_IOCTL_CMD, *PIPS_IOCTL_CMD;
+ 	mp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
+-	if (!mp)
++	if (!mp) {
++		rc = 2;
+ 		goto lpfc_handle_latt_free_pmb;
++	}
  
- typedef struct {
-    uint8_t  op_code;
-@@ -552,7 +552,7 @@ typedef struct {
-    uint32_t cccr;
- } IPS_NVRAM_CMD, *PIPS_NVRAM_CMD;
+ 	mp->virt = lpfc_mbuf_alloc(phba, 0, &mp->phys);
+-	if (!mp->virt)
++	if (!mp->virt) {
++		rc = 3;
+ 		goto lpfc_handle_latt_free_mp;
+-
+-	rc = -EIO;
++	}
  
--typedef struct 
-+typedef struct
- {
-     uint8_t  op_code;
-     uint8_t  command_id;
-@@ -650,7 +650,7 @@ typedef struct {
-    uint8_t   device_address;
-    uint8_t   cmd_attribute;
-    uint8_t   cdb_length;
--   uint8_t   reserved_for_LUN; 	 
-+   uint8_t   reserved_for_LUN;
-    uint32_t  transfer_length;
-    uint32_t  buffer_pointer;
-    uint16_t  sg_count;
-@@ -790,7 +790,7 @@ typedef struct {
-                                              /* SubSystem Parameter[4]      */
- #define  IPS_GET_VERSION_SUPPORT 0x00018000  /* Mask for Versioning Support */
+ 	/* Cleanup any outstanding ELS commands */
+ 	lpfc_els_flush_all_cmd(phba);
+@@ -722,9 +854,11 @@ lpfc_handle_latt(struct lpfc_hba *phba)
+ 	lpfc_read_la(phba, pmb, mp);
+ 	pmb->mbox_cmpl = lpfc_mbx_cmpl_read_la;
+ 	pmb->vport = vport;
+-	rc = lpfc_sli_issue_mbox (phba, pmb, (MBX_NOWAIT | MBX_STOP_IOCB));
+-	if (rc == MBX_NOT_FINISHED)
++	rc = lpfc_sli_issue_mbox (phba, pmb, MBX_NOWAIT);
++	if (rc == MBX_NOT_FINISHED) {
++		rc = 4;
+ 		goto lpfc_handle_latt_free_mbuf;
++	}
  
--typedef struct 
-+typedef struct
- {
-    uint32_t  revision;
-    uint8_t   bootBlkVersion[32];
-@@ -1034,7 +1034,6 @@ typedef struct ips_ha {
-    uint8_t            ha_id[IPS_MAX_CHANNELS+1];
-    uint32_t           dcdb_active[IPS_MAX_CHANNELS];
-    uint32_t           io_addr;            /* Base I/O address           */
--   uint8_t            irq;                /* IRQ for adapter            */
-    uint8_t            ntargets;           /* Number of targets          */
-    uint8_t            nbus;               /* Number of buses            */
-    uint8_t            nlun;               /* Number of Luns             */
-@@ -1066,10 +1065,7 @@ typedef struct ips_ha {
-    int                ioctl_reset;        /* IOCTL Requested Reset Flag */
-    uint16_t           reset_count;        /* number of resets           */
-    time_t             last_ffdc;          /* last time we sent ffdc info*/
--   uint8_t            revision_id;        /* Revision level             */
--   uint16_t           device_id;          /* PCI device ID              */
-    uint8_t            slot_num;           /* PCI Slot Number            */
--   uint16_t           subdevice_id;       /* Subsystem device ID        */
-    int                ioctl_len;          /* size of ioctl buffer       */
-    dma_addr_t         ioctl_busaddr;      /* dma address of ioctl buffer*/
-    uint8_t            bios_version[8];    /* BIOS Revision              */
-diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c
-index 57ce225..e5be5fd 100644
---- a/drivers/scsi/iscsi_tcp.c
-+++ b/drivers/scsi/iscsi_tcp.c
-@@ -48,7 +48,7 @@ MODULE_AUTHOR("Dmitry Yusupov <dmitry_yus at yahoo.com>, "
- 	      "Alex Aizman <itn780 at yahoo.com>");
- MODULE_DESCRIPTION("iSCSI/TCP data-path");
- MODULE_LICENSE("GPL");
--/* #define DEBUG_TCP */
-+#undef DEBUG_TCP
- #define DEBUG_ASSERT
+ 	/* Clear Link Attention in HA REG */
+ 	spin_lock_irq(&phba->hbalock);
+@@ -756,10 +890,8 @@ lpfc_handle_latt_err_exit:
+ 	lpfc_linkdown(phba);
+ 	phba->link_state = LPFC_HBA_ERROR;
  
- #ifdef DEBUG_TCP
-@@ -67,115 +67,429 @@ MODULE_LICENSE("GPL");
- static unsigned int iscsi_max_lun = 512;
- module_param_named(max_lun, iscsi_max_lun, uint, S_IRUGO);
+-	/* The other case is an error from issue_mbox */
+-	if (rc == -ENOMEM)
+-		lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX,
+-			        "0300 READ_LA: no buffers\n");
++	lpfc_printf_log(phba, KERN_ERR, LOG_MBOX,
++		     "0300 LATT: Cannot issue READ_LA: Data:%d\n", rc);
  
-+static int iscsi_tcp_hdr_recv_done(struct iscsi_tcp_conn *tcp_conn,
-+				   struct iscsi_segment *segment);
-+
-+/*
-+ * Scatterlist handling: inside the iscsi_segment, we
-+ * remember an index into the scatterlist, and set data/size
-+ * to the current scatterlist entry. For highmem pages, we
-+ * kmap as needed.
-+ *
-+ * Note that the page is unmapped when we return from
-+ * TCP's data_ready handler, so we may end up mapping and
-+ * unmapping the same page repeatedly. The whole reason
-+ * for this is that we shouldn't keep the page mapped
-+ * outside the softirq.
-+ */
-+
-+/**
-+ * iscsi_tcp_segment_init_sg - init indicated scatterlist entry
-+ * @segment: the buffer object
-+ * @sg: scatterlist
-+ * @offset: byte offset into that sg entry
-+ *
-+ * This function sets up the segment so that subsequent
-+ * data is copied to the indicated sg entry, at the given
-+ * offset.
-+ */
- static inline void
--iscsi_buf_init_iov(struct iscsi_buf *ibuf, char *vbuf, int size)
-+iscsi_tcp_segment_init_sg(struct iscsi_segment *segment,
-+			  struct scatterlist *sg, unsigned int offset)
- {
--	sg_init_one(&ibuf->sg, vbuf, size);
--	ibuf->sent = 0;
--	ibuf->use_sendmsg = 1;
-+	segment->sg = sg;
-+	segment->sg_offset = offset;
-+	segment->size = min(sg->length - offset,
-+			    segment->total_size - segment->total_copied);
-+	segment->data = NULL;
+ 	return;
+ }
+@@ -1088,9 +1220,8 @@ lpfc_post_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, int cnt,
+ 		/* Allocate buffer to post */
+ 		mp1 = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL);
+ 		if (mp1)
+-		    mp1->virt = lpfc_mbuf_alloc(phba, MEM_PRI,
+-						&mp1->phys);
+-		if (mp1 == 0 || mp1->virt == 0) {
++		    mp1->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &mp1->phys);
++		if (!mp1 || !mp1->virt) {
+ 			kfree(mp1);
+ 			lpfc_sli_release_iocbq(phba, iocb);
+ 			pring->missbufcnt = cnt;
+@@ -1104,7 +1235,7 @@ lpfc_post_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, int cnt,
+ 			if (mp2)
+ 				mp2->virt = lpfc_mbuf_alloc(phba, MEM_PRI,
+ 							    &mp2->phys);
+-			if (mp2 == 0 || mp2->virt == 0) {
++			if (!mp2 || !mp2->virt) {
+ 				kfree(mp2);
+ 				lpfc_mbuf_free(phba, mp1->virt, mp1->phys);
+ 				kfree(mp1);
+@@ -1280,15 +1411,39 @@ lpfc_hba_init(struct lpfc_hba *phba, uint32_t *hbainit)
+ 	kfree(HashWorking);
  }
  
-+/**
-+ * iscsi_tcp_segment_map - map the current S/G page
-+ * @segment: iscsi_segment
-+ * @recv: 1 if called from recv path
-+ *
-+ * We only need to possibly kmap data if scatter lists are being used,
-+ * because the iscsi passthrough and internal IO paths will never use high
-+ * mem pages.
-+ */
- static inline void
--iscsi_buf_init_sg(struct iscsi_buf *ibuf, struct scatterlist *sg)
-+iscsi_tcp_segment_map(struct iscsi_segment *segment, int recv)
+-static void
++void
+ lpfc_cleanup(struct lpfc_vport *vport)
  {
--	sg_init_table(&ibuf->sg, 1);
--	sg_set_page(&ibuf->sg, sg_page(sg), sg->length, sg->offset);
-+	struct scatterlist *sg;
++	struct lpfc_hba   *phba = vport->phba;
+ 	struct lpfc_nodelist *ndlp, *next_ndlp;
++	int i = 0;
+ 
+-	/* clean up phba - lpfc specific */
+-	lpfc_can_disctmo(vport);
+-	list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp)
+-		lpfc_nlp_put(ndlp);
++	if (phba->link_state > LPFC_LINK_DOWN)
++		lpfc_port_link_failure(vport);
 +
-+	if (segment->data != NULL || !segment->sg)
-+		return;
++	list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) {
++		if (ndlp->nlp_type & NLP_FABRIC)
++			lpfc_disc_state_machine(vport, ndlp, NULL,
++					NLP_EVT_DEVICE_RECOVERY);
++		lpfc_disc_state_machine(vport, ndlp, NULL,
++					     NLP_EVT_DEVICE_RM);
++	}
 +
-+	sg = segment->sg;
-+	BUG_ON(segment->sg_mapped);
-+	BUG_ON(sg->length == 0);
++	/* At this point, ALL ndlp's should be gone
++	 * because of the previous NLP_EVT_DEVICE_RM.
++	 * Lets wait for this to happen, if needed.
++	 */
++	while (!list_empty(&vport->fc_nodes)) {
 +
- 	/*
--	 * Fastpath: sg element fits into single page
-+	 * If the page count is greater than one it is ok to send
-+	 * to the network layer's zero copy send path. If not we
-+	 * have to go the slow sendmsg path. We always map for the
-+	 * recv path.
- 	 */
--	if (sg->length + sg->offset <= PAGE_SIZE && !PageSlab(sg_page(sg)))
--		ibuf->use_sendmsg = 0;
--	else
--		ibuf->use_sendmsg = 1;
--	ibuf->sent = 0;
-+	if (page_count(sg_page(sg)) >= 1 && !recv)
-+		return;
++		if (i++ > 3000) {
++			lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
++				"0233 Nodelist not empty\n");
++			break;
++		}
 +
-+	debug_tcp("iscsi_tcp_segment_map %s %p\n", recv ? "recv" : "xmit",
-+		  segment);
-+	segment->sg_mapped = kmap_atomic(sg_page(sg), KM_SOFTIRQ0);
-+	segment->data = segment->sg_mapped + sg->offset + segment->sg_offset;
++		/* Wait for any activity on ndlps to settle */
++		msleep(10);
++	}
+ 	return;
  }
  
--static inline int
--iscsi_buf_left(struct iscsi_buf *ibuf)
-+static inline void
-+iscsi_tcp_segment_unmap(struct iscsi_segment *segment)
- {
--	int rc;
-+	debug_tcp("iscsi_tcp_segment_unmap %p\n", segment);
+@@ -1307,14 +1462,14 @@ lpfc_establish_link_tmo(unsigned long ptr)
+ 			phba->pport->fc_flag, phba->pport->port_state);
+ 	vports = lpfc_create_vport_work_array(phba);
+ 	if (vports != NULL)
+-		for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++) {
++		for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) {
+ 			struct Scsi_Host *shost;
+ 			shost = lpfc_shost_from_vport(vports[i]);
+ 			spin_lock_irqsave(shost->host_lock, iflag);
+ 			vports[i]->fc_flag &= ~FC_ESTABLISH_LINK;
+ 			spin_unlock_irqrestore(shost->host_lock, iflag);
+ 		}
+-	lpfc_destroy_vport_work_array(vports);
++	lpfc_destroy_vport_work_array(phba, vports);
+ }
  
--	rc = ibuf->sg.length - ibuf->sent;
--	BUG_ON(rc < 0);
--	return rc;
-+	if (segment->sg_mapped) {
-+		debug_tcp("iscsi_tcp_segment_unmap valid\n");
-+		kunmap_atomic(segment->sg_mapped, KM_SOFTIRQ0);
-+		segment->sg_mapped = NULL;
-+		segment->data = NULL;
-+	}
+ void
+@@ -1339,6 +1494,16 @@ lpfc_stop_phba_timers(struct lpfc_hba *phba)
+ 	return;
  }
  
-+/*
-+ * Splice the digest buffer into the buffer
-+ */
- static inline void
--iscsi_hdr_digest(struct iscsi_conn *conn, struct iscsi_buf *buf,
--		 u8* crc)
-+iscsi_tcp_segment_splice_digest(struct iscsi_segment *segment, void *digest)
++static void
++lpfc_block_mgmt_io(struct lpfc_hba * phba)
++{
++	unsigned long iflag;
++
++	spin_lock_irqsave(&phba->hbalock, iflag);
++	phba->sli.sli_flag |= LPFC_BLOCK_MGMT_IO;
++	spin_unlock_irqrestore(&phba->hbalock, iflag);
++}
++
+ int
+ lpfc_online(struct lpfc_hba *phba)
  {
--	struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
--
--	crypto_hash_digest(&tcp_conn->tx_hash, &buf->sg, buf->sg.length, crc);
--	buf->sg.length += sizeof(u32);
-+	segment->data = digest;
-+	segment->digest_len = ISCSI_DIGEST_SIZE;
-+	segment->total_size += ISCSI_DIGEST_SIZE;
-+	segment->size = ISCSI_DIGEST_SIZE;
-+	segment->copied = 0;
-+	segment->sg = NULL;
-+	segment->hash = NULL;
+@@ -1369,7 +1534,7 @@ lpfc_online(struct lpfc_hba *phba)
+ 
+ 	vports = lpfc_create_vport_work_array(phba);
+ 	if (vports != NULL)
+-		for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++) {
++		for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) {
+ 			struct Scsi_Host *shost;
+ 			shost = lpfc_shost_from_vport(vports[i]);
+ 			spin_lock_irq(shost->host_lock);
+@@ -1378,23 +1543,13 @@ lpfc_online(struct lpfc_hba *phba)
+ 				vports[i]->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
+ 			spin_unlock_irq(shost->host_lock);
+ 		}
+-		lpfc_destroy_vport_work_array(vports);
++		lpfc_destroy_vport_work_array(phba, vports);
+ 
+ 	lpfc_unblock_mgmt_io(phba);
+ 	return 0;
  }
  
-+/**
-+ * iscsi_tcp_segment_done - check whether the segment is complete
-+ * @segment: iscsi segment to check
-+ * @recv: set to one of this is called from the recv path
-+ * @copied: number of bytes copied
-+ *
-+ * Check if we're done receiving this segment. If the receive
-+ * buffer is full but we expect more data, move on to the
-+ * next entry in the scatterlist.
-+ *
-+ * If the amount of data we received isn't a multiple of 4,
-+ * we will transparently receive the pad bytes, too.
-+ *
-+ * This function must be re-entrant.
-+ */
- static inline int
--iscsi_hdr_extract(struct iscsi_tcp_conn *tcp_conn)
-+iscsi_tcp_segment_done(struct iscsi_segment *segment, int recv, unsigned copied)
- {
--	struct sk_buff *skb = tcp_conn->in.skb;
+ void
+-lpfc_block_mgmt_io(struct lpfc_hba * phba)
+-{
+-	unsigned long iflag;
 -
--	tcp_conn->in.zero_copy_hdr = 0;
-+	static unsigned char padbuf[ISCSI_PAD_LEN];
-+	struct scatterlist sg;
-+	unsigned int pad;
+-	spin_lock_irqsave(&phba->hbalock, iflag);
+-	phba->sli.sli_flag |= LPFC_BLOCK_MGMT_IO;
+-	spin_unlock_irqrestore(&phba->hbalock, iflag);
+-}
+-
+-void
+ lpfc_unblock_mgmt_io(struct lpfc_hba * phba)
+ {
+ 	unsigned long iflag;
+@@ -1409,6 +1564,8 @@ lpfc_offline_prep(struct lpfc_hba * phba)
+ {
+ 	struct lpfc_vport *vport = phba->pport;
+ 	struct lpfc_nodelist  *ndlp, *next_ndlp;
++	struct lpfc_vport **vports;
++	int i;
  
--	if (tcp_conn->in.copy >= tcp_conn->hdr_size &&
--	    tcp_conn->in_progress == IN_PROGRESS_WAIT_HEADER) {
-+	debug_tcp("copied %u %u size %u %s\n", segment->copied, copied,
-+		  segment->size, recv ? "recv" : "xmit");
-+	if (segment->hash && copied) {
- 		/*
--		 * Zero-copy PDU Header: using connection context
--		 * to store header pointer.
-+		 * If a segment is kmapd we must unmap it before sending
-+		 * to the crypto layer since that will try to kmap it again.
- 		 */
--		if (skb_shinfo(skb)->frag_list == NULL &&
--		    !skb_shinfo(skb)->nr_frags) {
--			tcp_conn->in.hdr = (struct iscsi_hdr *)
--				((char*)skb->data + tcp_conn->in.offset);
--			tcp_conn->in.zero_copy_hdr = 1;
-+		iscsi_tcp_segment_unmap(segment);
-+
-+		if (!segment->data) {
-+			sg_init_table(&sg, 1);
-+			sg_set_page(&sg, sg_page(segment->sg), copied,
-+				    segment->copied + segment->sg_offset +
-+							segment->sg->offset);
-+		} else
-+			sg_init_one(&sg, segment->data + segment->copied,
-+				    copied);
-+		crypto_hash_update(segment->hash, &sg, copied);
-+	}
-+
-+	segment->copied += copied;
-+	if (segment->copied < segment->size) {
-+		iscsi_tcp_segment_map(segment, recv);
-+		return 0;
-+	}
-+
-+	segment->total_copied += segment->copied;
-+	segment->copied = 0;
-+	segment->size = 0;
-+
-+	/* Unmap the current scatterlist page, if there is one. */
-+	iscsi_tcp_segment_unmap(segment);
+ 	if (vport->fc_flag & FC_OFFLINE_MODE)
+ 		return;
+@@ -1417,10 +1574,34 @@ lpfc_offline_prep(struct lpfc_hba * phba)
+ 
+ 	lpfc_linkdown(phba);
+ 
+-	/* Issue an unreg_login to all nodes */
+-	list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp)
+-		if (ndlp->nlp_state != NLP_STE_UNUSED_NODE)
+-			lpfc_unreg_rpi(vport, ndlp);
++	/* Issue an unreg_login to all nodes on all vports */
++	vports = lpfc_create_vport_work_array(phba);
++	if (vports != NULL) {
++		for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) {
++			struct Scsi_Host *shost;
 +
-+	/* Do we have more scatterlist entries? */
-+	debug_tcp("total copied %u total size %u\n", segment->total_copied,
-+		   segment->total_size);
-+	if (segment->total_copied < segment->total_size) {
-+		/* Proceed to the next entry in the scatterlist. */
-+		iscsi_tcp_segment_init_sg(segment, sg_next(segment->sg),
-+					  0);
-+		iscsi_tcp_segment_map(segment, recv);
-+		BUG_ON(segment->size == 0);
-+		return 0;
++			if (vports[i]->load_flag & FC_UNLOADING)
++				continue;
++			shost =	lpfc_shost_from_vport(vports[i]);
++			list_for_each_entry_safe(ndlp, next_ndlp,
++						 &vports[i]->fc_nodes,
++						 nlp_listp) {
++				if (ndlp->nlp_state == NLP_STE_UNUSED_NODE)
++					continue;
++				if (ndlp->nlp_type & NLP_FABRIC) {
++					lpfc_disc_state_machine(vports[i], ndlp,
++						NULL, NLP_EVT_DEVICE_RECOVERY);
++					lpfc_disc_state_machine(vports[i], ndlp,
++						NULL, NLP_EVT_DEVICE_RM);
++				}
++				spin_lock_irq(shost->host_lock);
++				ndlp->nlp_flag &= ~NLP_NPR_ADISC;
++				spin_unlock_irq(shost->host_lock);
++				lpfc_unreg_rpi(vports[i], ndlp);
++			}
++		}
 +	}
-+
-+	/* Do we need to handle padding? */
-+	pad = iscsi_padding(segment->total_copied);
-+	if (pad != 0) {
-+		debug_tcp("consume %d pad bytes\n", pad);
-+		segment->total_size += pad;
-+		segment->size = pad;
-+		segment->data = padbuf;
-+		return 0;
++	lpfc_destroy_vport_work_array(phba, vports);
+ 
+ 	lpfc_sli_flush_mbox_queue(phba);
+ }
+@@ -1439,9 +1620,9 @@ lpfc_offline(struct lpfc_hba *phba)
+ 	lpfc_stop_phba_timers(phba);
+ 	vports = lpfc_create_vport_work_array(phba);
+ 	if (vports != NULL)
+-		for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++)
++		for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++)
+ 			lpfc_stop_vport_timers(vports[i]);
+-	lpfc_destroy_vport_work_array(vports);
++	lpfc_destroy_vport_work_array(phba, vports);
+ 	lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
+ 			"0460 Bring Adapter offline\n");
+ 	/* Bring down the SLI Layer and cleanup.  The HBA is offline
+@@ -1452,15 +1633,14 @@ lpfc_offline(struct lpfc_hba *phba)
+ 	spin_unlock_irq(&phba->hbalock);
+ 	vports = lpfc_create_vport_work_array(phba);
+ 	if (vports != NULL)
+-		for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++) {
++		for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) {
+ 			shost = lpfc_shost_from_vport(vports[i]);
+-			lpfc_cleanup(vports[i]);
+ 			spin_lock_irq(shost->host_lock);
+ 			vports[i]->work_port_events = 0;
+ 			vports[i]->fc_flag |= FC_OFFLINE_MODE;
+ 			spin_unlock_irq(shost->host_lock);
+ 		}
+-	lpfc_destroy_vport_work_array(vports);
++	lpfc_destroy_vport_work_array(phba, vports);
+ }
+ 
+ /******************************************************************************
+@@ -1674,6 +1854,8 @@ void lpfc_host_attrib_init(struct Scsi_Host *shost)
+ 	fc_host_supported_speeds(shost) = 0;
+ 	if (phba->lmt & LMT_10Gb)
+ 		fc_host_supported_speeds(shost) |= FC_PORTSPEED_10GBIT;
++	if (phba->lmt & LMT_8Gb)
++		fc_host_supported_speeds(shost) |= FC_PORTSPEED_8GBIT;
+ 	if (phba->lmt & LMT_4Gb)
+ 		fc_host_supported_speeds(shost) |= FC_PORTSPEED_4GBIT;
+ 	if (phba->lmt & LMT_2Gb)
+@@ -1707,13 +1889,14 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
+ 	struct Scsi_Host  *shost = NULL;
+ 	void *ptr;
+ 	unsigned long bar0map_len, bar2map_len;
+-	int error = -ENODEV;
++	int error = -ENODEV, retval;
+ 	int  i, hbq_count;
+ 	uint16_t iotag;
++	int bars = pci_select_bars(pdev, IORESOURCE_MEM);
+ 
+-	if (pci_enable_device(pdev))
++	if (pci_enable_device_bars(pdev, bars))
+ 		goto out;
+-	if (pci_request_regions(pdev, LPFC_DRIVER_NAME))
++	if (pci_request_selected_regions(pdev, bars, LPFC_DRIVER_NAME))
+ 		goto out_disable_device;
+ 
+ 	phba = kzalloc(sizeof (struct lpfc_hba), GFP_KERNEL);
+@@ -1823,9 +2006,11 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
+ 	lpfc_sli_setup(phba);
+ 	lpfc_sli_queue_setup(phba);
+ 
+-	error = lpfc_mem_alloc(phba);
+-	if (error)
++	retval = lpfc_mem_alloc(phba);
++	if (retval) {
++		error = retval;
+ 		goto out_free_hbqslimp;
 +	}
+ 
+ 	/* Initialize and populate the iocb list per host.  */
+ 	INIT_LIST_HEAD(&phba->lpfc_iocb_list);
+@@ -1880,6 +2065,9 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
+ 	/* Initialize list of fabric iocbs */
+ 	INIT_LIST_HEAD(&phba->fabric_iocb_list);
+ 
++	/* Initialize list to save ELS buffers */
++	INIT_LIST_HEAD(&phba->elsbuf);
 +
-+	/*
-+	 * Set us up for transferring the data digest. hdr digest
-+	 * is completely handled in hdr done function.
-+	 */
-+	if (segment->hash) {
-+		crypto_hash_final(segment->hash, segment->digest);
-+		iscsi_tcp_segment_splice_digest(segment,
-+				 recv ? segment->recv_digest : segment->digest);
-+		return 0;
+ 	vport = lpfc_create_port(phba, phba->brd_no, &phba->pcidev->dev);
+ 	if (!vport)
+ 		goto out_kthread_stop;
+@@ -1891,8 +2079,8 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
+ 	pci_set_drvdata(pdev, shost);
+ 
+ 	if (phba->cfg_use_msi) {
+-		error = pci_enable_msi(phba->pcidev);
+-		if (!error)
++		retval = pci_enable_msi(phba->pcidev);
++		if (!retval)
+ 			phba->using_msi = 1;
+ 		else
+ 			lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+@@ -1900,11 +2088,12 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
+ 					"with IRQ\n");
+ 	}
+ 
+-	error =	request_irq(phba->pcidev->irq, lpfc_intr_handler, IRQF_SHARED,
++	retval = request_irq(phba->pcidev->irq, lpfc_intr_handler, IRQF_SHARED,
+ 			    LPFC_DRIVER_NAME, phba);
+-	if (error) {
++	if (retval) {
+ 		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ 			"0451 Enable interrupt handler failed\n");
++		error = retval;
+ 		goto out_disable_msi;
+ 	}
+ 
+@@ -1914,11 +2103,15 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
+ 	phba->HSregaddr = phba->ctrl_regs_memmap_p + HS_REG_OFFSET;
+ 	phba->HCregaddr = phba->ctrl_regs_memmap_p + HC_REG_OFFSET;
+ 
+-	if (lpfc_alloc_sysfs_attr(vport))
++	if (lpfc_alloc_sysfs_attr(vport)) {
++		error = -ENOMEM;
+ 		goto out_free_irq;
 +	}
-+
-+	return 1;
-+}
-+
-+/**
-+ * iscsi_tcp_xmit_segment - transmit segment
-+ * @tcp_conn: the iSCSI TCP connection
-+ * @segment: the buffer to transmnit
-+ *
-+ * This function transmits as much of the buffer as
-+ * the network layer will accept, and returns the number of
-+ * bytes transmitted.
-+ *
-+ * If CRC hashing is enabled, the function will compute the
-+ * hash as it goes. When the entire segment has been transmitted,
-+ * it will retrieve the hash value and send it as well.
-+ */
-+static int
-+iscsi_tcp_xmit_segment(struct iscsi_tcp_conn *tcp_conn,
-+		       struct iscsi_segment *segment)
-+{
-+	struct socket *sk = tcp_conn->sock;
-+	unsigned int copied = 0;
-+	int r = 0;
-+
-+	while (!iscsi_tcp_segment_done(segment, 0, r)) {
-+		struct scatterlist *sg;
-+		unsigned int offset, copy;
-+		int flags = 0;
-+
-+		r = 0;
-+		offset = segment->copied;
-+		copy = segment->size - offset;
-+
-+		if (segment->total_copied + segment->size < segment->total_size)
-+			flags |= MSG_MORE;
-+
-+		/* Use sendpage if we can; else fall back to sendmsg */
-+		if (!segment->data) {
-+			sg = segment->sg;
-+			offset += segment->sg_offset + sg->offset;
-+			r = tcp_conn->sendpage(sk, sg_page(sg), offset, copy,
-+					       flags);
- 		} else {
--			/* ignoring return code since we checked
--			 * in.copy before */
--			skb_copy_bits(skb, tcp_conn->in.offset,
--				&tcp_conn->hdr, tcp_conn->hdr_size);
--			tcp_conn->in.hdr = &tcp_conn->hdr;
-+			struct msghdr msg = { .msg_flags = flags };
-+			struct kvec iov = {
-+				.iov_base = segment->data + offset,
-+				.iov_len = copy
-+			};
-+
-+			r = kernel_sendmsg(sk, &msg, &iov, 1, copy);
- 		}
--		tcp_conn->in.offset += tcp_conn->hdr_size;
--		tcp_conn->in.copy -= tcp_conn->hdr_size;
--	} else {
--		int hdr_remains;
--		int copylen;
  
--		/*
--		 * PDU header scattered across SKB's,
--		 * copying it... This'll happen quite rarely.
--		 */
-+		if (r < 0) {
-+			iscsi_tcp_segment_unmap(segment);
-+			if (copied || r == -EAGAIN)
-+				break;
-+			return r;
-+		}
-+		copied += r;
+-	if (lpfc_sli_hba_setup(phba))
++	if (lpfc_sli_hba_setup(phba)) {
++		error = -ENODEV;
+ 		goto out_remove_device;
 +	}
-+	return copied;
-+}
+ 
+ 	/*
+ 	 * hba setup may have changed the hba_queue_depth so we need to adjust
+@@ -1975,7 +2168,7 @@ out_idr_remove:
+ out_free_phba:
+ 	kfree(phba);
+ out_release_regions:
+-	pci_release_regions(pdev);
++	pci_release_selected_regions(pdev, bars);
+ out_disable_device:
+ 	pci_disable_device(pdev);
+ out:
+@@ -1991,6 +2184,8 @@ lpfc_pci_remove_one(struct pci_dev *pdev)
+ 	struct Scsi_Host  *shost = pci_get_drvdata(pdev);
+ 	struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ 	struct lpfc_hba   *phba = vport->phba;
++	int bars = pci_select_bars(pdev, IORESOURCE_MEM);
 +
-+/**
-+ * iscsi_tcp_segment_recv - copy data to segment
-+ * @tcp_conn: the iSCSI TCP connection
-+ * @segment: the buffer to copy to
-+ * @ptr: data pointer
-+ * @len: amount of data available
-+ *
-+ * This function copies up to @len bytes to the
-+ * given buffer, and returns the number of bytes
-+ * consumed, which can actually be less than @len.
-+ *
-+ * If hash digest is enabled, the function will update the
-+ * hash while copying.
-+ * Combining these two operations doesn't buy us a lot (yet),
-+ * but in the future we could implement combined copy+crc,
-+ * just way we do for network layer checksums.
-+ */
-+static int
-+iscsi_tcp_segment_recv(struct iscsi_tcp_conn *tcp_conn,
-+		       struct iscsi_segment *segment, const void *ptr,
-+		       unsigned int len)
-+{
-+	unsigned int copy = 0, copied = 0;
+ 	spin_lock_irq(&phba->hbalock);
+ 	vport->load_flag |= FC_UNLOADING;
+ 	spin_unlock_irq(&phba->hbalock);
+@@ -1998,8 +2193,12 @@ lpfc_pci_remove_one(struct pci_dev *pdev)
+ 	kfree(vport->vname);
+ 	lpfc_free_sysfs_attr(vport);
+ 
++	kthread_stop(phba->worker_thread);
 +
-+	while (!iscsi_tcp_segment_done(segment, 1, copy)) {
-+		if (copied == len) {
-+			debug_tcp("iscsi_tcp_segment_recv copied %d bytes\n",
-+				  len);
-+			break;
-+		}
+ 	fc_remove_host(shost);
+ 	scsi_remove_host(shost);
++	lpfc_cleanup(vport);
 +
-+		copy = min(len - copied, segment->size - segment->copied);
-+		debug_tcp("iscsi_tcp_segment_recv copying %d\n", copy);
-+		memcpy(segment->data + segment->copied, ptr + copied, copy);
-+		copied += copy;
-+	}
-+	return copied;
-+}
+ 	/*
+ 	 * Bring down the SLI Layer. This step disable all interrupts,
+ 	 * clears the rings, discards all mailbox commands, and resets
+@@ -2014,9 +2213,6 @@ lpfc_pci_remove_one(struct pci_dev *pdev)
+ 	spin_unlock_irq(&phba->hbalock);
  
--		if (tcp_conn->in_progress == IN_PROGRESS_WAIT_HEADER)
--			tcp_conn->in.hdr_offset = 0;
-+static inline void
-+iscsi_tcp_dgst_header(struct hash_desc *hash, const void *hdr, size_t hdrlen,
-+		      unsigned char digest[ISCSI_DIGEST_SIZE])
-+{
-+	struct scatterlist sg;
+ 	lpfc_debugfs_terminate(vport);
+-	lpfc_cleanup(vport);
+-
+-	kthread_stop(phba->worker_thread);
  
--		hdr_remains = tcp_conn->hdr_size - tcp_conn->in.hdr_offset;
--		BUG_ON(hdr_remains <= 0);
-+	sg_init_one(&sg, hdr, hdrlen);
-+	crypto_hash_digest(hash, &sg, hdrlen, digest);
-+}
+ 	/* Release the irq reservation */
+ 	free_irq(phba->pcidev->irq, phba);
+@@ -2048,7 +2244,7 @@ lpfc_pci_remove_one(struct pci_dev *pdev)
  
--		copylen = min(tcp_conn->in.copy, hdr_remains);
--		skb_copy_bits(skb, tcp_conn->in.offset,
--			(char*)&tcp_conn->hdr + tcp_conn->in.hdr_offset,
--			copylen);
-+static inline int
-+iscsi_tcp_dgst_verify(struct iscsi_tcp_conn *tcp_conn,
-+		      struct iscsi_segment *segment)
-+{
-+	if (!segment->digest_len)
-+		return 1;
+ 	kfree(phba);
  
--		debug_tcp("PDU gather offset %d bytes %d in.offset %d "
--		       "in.copy %d\n", tcp_conn->in.hdr_offset, copylen,
--		       tcp_conn->in.offset, tcp_conn->in.copy);
-+	if (memcmp(segment->recv_digest, segment->digest,
-+		   segment->digest_len)) {
-+		debug_scsi("digest mismatch\n");
-+		return 0;
+-	pci_release_regions(pdev);
++	pci_release_selected_regions(pdev, bars);
+ 	pci_disable_device(pdev);
+ }
+ 
+@@ -2239,12 +2435,22 @@ lpfc_init(void)
+ 	printk(LPFC_MODULE_DESC "\n");
+ 	printk(LPFC_COPYRIGHT "\n");
+ 
++	if (lpfc_enable_npiv) {
++		lpfc_transport_functions.vport_create = lpfc_vport_create;
++		lpfc_transport_functions.vport_delete = lpfc_vport_delete;
++	}
+ 	lpfc_transport_template =
+ 				fc_attach_transport(&lpfc_transport_functions);
+-	lpfc_vport_transport_template =
+-			fc_attach_transport(&lpfc_vport_transport_functions);
+-	if (!lpfc_transport_template || !lpfc_vport_transport_template)
++	if (lpfc_transport_template == NULL)
+ 		return -ENOMEM;
++	if (lpfc_enable_npiv) {
++		lpfc_vport_transport_template =
++			fc_attach_transport(&lpfc_vport_transport_functions);
++		if (lpfc_vport_transport_template == NULL) {
++			fc_release_transport(lpfc_transport_template);
++			return -ENOMEM;
++		}
 +	}
+ 	error = pci_register_driver(&lpfc_driver);
+ 	if (error) {
+ 		fc_release_transport(lpfc_transport_template);
+@@ -2259,7 +2465,8 @@ lpfc_exit(void)
+ {
+ 	pci_unregister_driver(&lpfc_driver);
+ 	fc_release_transport(lpfc_transport_template);
+-	fc_release_transport(lpfc_vport_transport_template);
++	if (lpfc_enable_npiv)
++		fc_release_transport(lpfc_vport_transport_template);
+ }
  
--		tcp_conn->in.offset += copylen;
--		tcp_conn->in.copy -= copylen;
--		if (copylen < hdr_remains)  {
--			tcp_conn->in_progress = IN_PROGRESS_HEADER_GATHER;
--			tcp_conn->in.hdr_offset += copylen;
--		        return -EAGAIN;
-+	return 1;
-+}
-+
-+/*
-+ * Helper function to set up segment buffer
-+ */
-+static inline void
-+__iscsi_segment_init(struct iscsi_segment *segment, size_t size,
-+		     iscsi_segment_done_fn_t *done, struct hash_desc *hash)
+ module_init(lpfc_init);
+diff --git a/drivers/scsi/lpfc/lpfc_logmsg.h b/drivers/scsi/lpfc/lpfc_logmsg.h
+index 626e4d8..c5841d7 100644
+--- a/drivers/scsi/lpfc/lpfc_logmsg.h
++++ b/drivers/scsi/lpfc/lpfc_logmsg.h
+@@ -26,6 +26,7 @@
+ #define LOG_IP                        0x20	/* IP traffic history */
+ #define LOG_FCP                       0x40	/* FCP traffic history */
+ #define LOG_NODE                      0x80	/* Node table events */
++#define LOG_TEMP                      0x100	/* Temperature sensor events */
+ #define LOG_MISC                      0x400	/* Miscellaneous events */
+ #define LOG_SLI                       0x800	/* SLI events */
+ #define LOG_FCP_ERROR                 0x1000	/* log errors, not underruns */
+diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c
+index a592733..dfc63f6 100644
+--- a/drivers/scsi/lpfc/lpfc_mbox.c
++++ b/drivers/scsi/lpfc/lpfc_mbox.c
+@@ -82,6 +82,24 @@ lpfc_read_nv(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
+ }
+ 
+ /**********************************************/
++/*  lpfc_config_async  Issue a                */
++/*  MBX_ASYNC_EVT_ENABLE mailbox command      */
++/**********************************************/
++void
++lpfc_config_async(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb,
++		uint32_t ring)
 +{
-+	memset(segment, 0, sizeof(*segment));
-+	segment->total_size = size;
-+	segment->done = done;
-+
-+	if (hash) {
-+		segment->hash = hash;
-+		crypto_hash_init(hash);
-+	}
-+}
++	MAILBOX_t *mb;
 +
-+static inline void
-+iscsi_segment_init_linear(struct iscsi_segment *segment, void *data,
-+			  size_t size, iscsi_segment_done_fn_t *done,
-+			  struct hash_desc *hash)
-+{
-+	__iscsi_segment_init(segment, size, done, hash);
-+	segment->data = data;
-+	segment->size = size;
++	mb = &pmb->mb;
++	memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
++	mb->mbxCommand = MBX_ASYNCEVT_ENABLE;
++	mb->un.varCfgAsyncEvent.ring = ring;
++	mb->mbxOwner = OWN_HOST;
++	return;
 +}
 +
-+static inline int
-+iscsi_segment_seek_sg(struct iscsi_segment *segment,
-+		      struct scatterlist *sg_list, unsigned int sg_count,
-+		      unsigned int offset, size_t size,
-+		      iscsi_segment_done_fn_t *done, struct hash_desc *hash)
-+{
-+	struct scatterlist *sg;
-+	unsigned int i;
-+
-+	debug_scsi("iscsi_segment_seek_sg offset %u size %llu\n",
-+		  offset, size);
-+	__iscsi_segment_init(segment, size, done, hash);
-+	for_each_sg(sg_list, sg, sg_count, i) {
-+		debug_scsi("sg %d, len %u offset %u\n", i, sg->length,
-+			   sg->offset);
-+		if (offset < sg->length) {
-+			iscsi_tcp_segment_init_sg(segment, sg, offset);
-+			return 0;
- 		}
--		tcp_conn->in.hdr = &tcp_conn->hdr;
--		tcp_conn->discontiguous_hdr_cnt++;
--	        tcp_conn->in_progress = IN_PROGRESS_WAIT_HEADER;
-+		offset -= sg->length;
++/**********************************************/
+ /*  lpfc_heart_beat  Issue a HEART_BEAT       */
+ /*                mailbox command             */
+ /**********************************************/
+@@ -270,8 +288,10 @@ lpfc_read_sparam(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb, int vpi)
+ 
+ 	/* Get a buffer to hold the HBAs Service Parameters */
+ 
+-	if (((mp = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL)) == 0) ||
+-	    ((mp->virt = lpfc_mbuf_alloc(phba, 0, &(mp->phys))) == 0)) {
++	mp = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL);
++	if (mp)
++		mp->virt = lpfc_mbuf_alloc(phba, 0, &mp->phys);
++	if (!mp || !mp->virt) {
+ 		kfree(mp);
+ 		mb->mbxCommand = MBX_READ_SPARM64;
+ 		/* READ_SPARAM: no buffers */
+@@ -369,8 +389,10 @@ lpfc_reg_login(struct lpfc_hba *phba, uint16_t vpi, uint32_t did,
+ 	mb->mbxOwner = OWN_HOST;
+ 
+ 	/* Get a buffer to hold NPorts Service Parameters */
+-	if (((mp = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL)) == NULL) ||
+-	    ((mp->virt = lpfc_mbuf_alloc(phba, 0, &(mp->phys))) == 0)) {
++	mp = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL);
++	if (mp)
++		mp->virt = lpfc_mbuf_alloc(phba, 0, &mp->phys);
++	if (!mp || !mp->virt) {
+ 		kfree(mp);
+ 		mb->mbxCommand = MBX_REG_LOGIN64;
+ 		/* REG_LOGIN: no buffers */
+@@ -874,7 +896,7 @@ lpfc_mbox_tmo_val(struct lpfc_hba *phba, int cmd)
+ 	case MBX_DOWN_LOAD:	/* 0x1C */
+ 	case MBX_DEL_LD_ENTRY:	/* 0x1D */
+ 	case MBX_LOAD_AREA:	/* 0x81 */
+-	case MBX_FLASH_WR_ULA:  /* 0x98 */
++	case MBX_WRITE_WWN:     /* 0x98 */
+ 	case MBX_LOAD_EXP_ROM:	/* 0x9C */
+ 		return LPFC_MBOX_TMO_FLASH_CMD;
  	}
+diff --git a/drivers/scsi/lpfc/lpfc_mem.c b/drivers/scsi/lpfc/lpfc_mem.c
+index 43c3b8a..6dc5ab8 100644
+--- a/drivers/scsi/lpfc/lpfc_mem.c
++++ b/drivers/scsi/lpfc/lpfc_mem.c
+@@ -98,6 +98,7 @@ lpfc_mem_alloc(struct lpfc_hba * phba)
  
-+	return ISCSI_ERR_DATA_OFFSET;
-+}
+  fail_free_hbq_pool:
+ 	lpfc_sli_hbqbuf_free_all(phba);
++	pci_pool_destroy(phba->lpfc_hbq_pool);
+  fail_free_nlp_mem_pool:
+ 	mempool_destroy(phba->nlp_mem_pool);
+ 	phba->nlp_mem_pool = NULL;
+diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c
+index 880af0c..4a0e340 100644
+--- a/drivers/scsi/lpfc/lpfc_nportdisc.c
++++ b/drivers/scsi/lpfc/lpfc_nportdisc.c
+@@ -287,6 +287,24 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ 	pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
+ 	lp = (uint32_t *) pcmd->virt;
+ 	sp = (struct serv_parm *) ((uint8_t *) lp + sizeof (uint32_t));
++	if (wwn_to_u64(sp->portName.u.wwn) == 0) {
++		lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
++				 "0140 PLOGI Reject: invalid nname\n");
++		stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
++		stat.un.b.lsRjtRsnCodeExp = LSEXP_INVALID_PNAME;
++		lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp,
++			NULL);
++		return 0;
++	}
++	if (wwn_to_u64(sp->nodeName.u.wwn) == 0) {
++		lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
++				 "0141 PLOGI Reject: invalid pname\n");
++		stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
++		stat.un.b.lsRjtRsnCodeExp = LSEXP_INVALID_NNAME;
++		lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp,
++			NULL);
++		return 0;
++	}
+ 	if ((lpfc_check_sparm(vport, ndlp, sp, CLASS3) == 0)) {
+ 		/* Reject this request because invalid parameters */
+ 		stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
+@@ -343,8 +361,7 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ 		lpfc_config_link(phba, mbox);
+ 		mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+ 		mbox->vport = vport;
+-		rc = lpfc_sli_issue_mbox
+-			(phba, mbox, (MBX_NOWAIT | MBX_STOP_IOCB));
++		rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
+ 		if (rc == MBX_NOT_FINISHED) {
+ 			mempool_free(mbox, phba->mbox_mem_pool);
+ 			goto out;
+@@ -407,6 +424,61 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ 			ndlp, mbox);
+ 		return 1;
+ 	}
 +
-+/**
-+ * iscsi_tcp_hdr_recv_prep - prep segment for hdr reception
-+ * @tcp_conn: iscsi connection to prep for
-+ *
-+ * This function always passes NULL for the hash argument, because when this
-+ * function is called we do not yet know the final size of the header and want
-+ * to delay the digest processing until we know that.
-+ */
-+static void
-+iscsi_tcp_hdr_recv_prep(struct iscsi_tcp_conn *tcp_conn)
-+{
-+	debug_tcp("iscsi_tcp_hdr_recv_prep(%p%s)\n", tcp_conn,
-+		  tcp_conn->iscsi_conn->hdrdgst_en ? ", digest enabled" : "");
-+	iscsi_segment_init_linear(&tcp_conn->in.segment,
-+				tcp_conn->in.hdr_buf, sizeof(struct iscsi_hdr),
-+				iscsi_tcp_hdr_recv_done, NULL);
-+}
++	/* If the remote NPort logs into us, before we can initiate
++	 * discovery to them, cleanup the NPort from discovery accordingly.
++	 */
++	if (ndlp->nlp_state == NLP_STE_NPR_NODE) {
++		spin_lock_irq(shost->host_lock);
++		ndlp->nlp_flag &= ~NLP_DELAY_TMO;
++		spin_unlock_irq(shost->host_lock);
++		del_timer_sync(&ndlp->nlp_delayfunc);
++		ndlp->nlp_last_elscmd = 0;
 +
-+/*
-+ * Handle incoming reply to any other type of command
-+ */
-+static int
-+iscsi_tcp_data_recv_done(struct iscsi_tcp_conn *tcp_conn,
-+			 struct iscsi_segment *segment)
-+{
-+	struct iscsi_conn *conn = tcp_conn->iscsi_conn;
-+	int rc = 0;
++		if (!list_empty(&ndlp->els_retry_evt.evt_listp))
++			list_del_init(&ndlp->els_retry_evt.evt_listp);
 +
-+	if (!iscsi_tcp_dgst_verify(tcp_conn, segment))
-+		return ISCSI_ERR_DATA_DGST;
++		if (ndlp->nlp_flag & NLP_NPR_2B_DISC) {
++			spin_lock_irq(shost->host_lock);
++			ndlp->nlp_flag &= ~NLP_NPR_2B_DISC;
++			spin_unlock_irq(shost->host_lock);
 +
-+	rc = iscsi_complete_pdu(conn, tcp_conn->in.hdr,
-+			conn->data, tcp_conn->in.datalen);
-+	if (rc)
-+		return rc;
++			if ((ndlp->nlp_flag & NLP_ADISC_SND) &&
++				(vport->num_disc_nodes)) {
++				/* Check to see if there are more
++				 * ADISCs to be sent
++				 */
++				lpfc_more_adisc(vport);
 +
-+	iscsi_tcp_hdr_recv_prep(tcp_conn);
- 	return 0;
- }
- 
-+static void
-+iscsi_tcp_data_recv_prep(struct iscsi_tcp_conn *tcp_conn)
-+{
-+	struct iscsi_conn *conn = tcp_conn->iscsi_conn;
-+	struct hash_desc *rx_hash = NULL;
++				if ((vport->num_disc_nodes == 0) &&
++					(vport->fc_npr_cnt))
++					lpfc_els_disc_plogi(vport);
 +
-+	if (conn->datadgst_en)
-+		rx_hash = &tcp_conn->rx_hash;
++				if (vport->num_disc_nodes == 0) {
++					spin_lock_irq(shost->host_lock);
++					vport->fc_flag &= ~FC_NDISC_ACTIVE;
++					spin_unlock_irq(shost->host_lock);
++					lpfc_can_disctmo(vport);
++					lpfc_end_rscn(vport);
++				}
++			}
++			else if (vport->num_disc_nodes) {
++				/* Check to see if there are more
++				 * PLOGIs to be sent
++				 */
++				lpfc_more_plogi(vport);
 +
-+	iscsi_segment_init_linear(&tcp_conn->in.segment,
-+				conn->data, tcp_conn->in.datalen,
-+				iscsi_tcp_data_recv_done, rx_hash);
-+}
++				if (vport->num_disc_nodes == 0) {
++					spin_lock_irq(shost->host_lock);
++					vport->fc_flag &= ~FC_NDISC_ACTIVE;
++					spin_unlock_irq(shost->host_lock);
++					lpfc_can_disctmo(vport);
++					lpfc_end_rscn(vport);
++				}
++			}
++		}
++	}
 +
- /*
-  * must be called with session lock
-  */
-@@ -184,7 +498,6 @@ iscsi_tcp_cleanup_ctask(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
- {
- 	struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
- 	struct iscsi_r2t_info *r2t;
--	struct scsi_cmnd *sc;
+ 	lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, ndlp, mbox);
+ 	return 1;
  
- 	/* flush ctask's r2t queues */
- 	while (__kfifo_get(tcp_ctask->r2tqueue, (void*)&r2t, sizeof(void*))) {
-@@ -193,12 +506,12 @@ iscsi_tcp_cleanup_ctask(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
- 		debug_scsi("iscsi_tcp_cleanup_ctask pending r2t dropped\n");
+@@ -501,12 +573,9 @@ lpfc_rcv_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ 		spin_unlock_irq(shost->host_lock);
+ 
+ 		ndlp->nlp_last_elscmd = ELS_CMD_PLOGI;
+-		ndlp->nlp_prev_state = ndlp->nlp_state;
+-		lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
+-	} else {
+-		ndlp->nlp_prev_state = ndlp->nlp_state;
+-		lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE);
  	}
++	ndlp->nlp_prev_state = ndlp->nlp_state;
++	lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
  
--	sc = ctask->sc;
--	if (unlikely(!sc))
--		return;
--
--	tcp_ctask->xmstate = XMSTATE_VALUE_IDLE;
--	tcp_ctask->r2t = NULL;
-+	r2t = tcp_ctask->r2t;
-+	if (r2t != NULL) {
-+		__kfifo_put(tcp_ctask->r2tpool.queue, (void*)&r2t,
-+			    sizeof(void*));
-+		tcp_ctask->r2t = NULL;
-+	}
+ 	spin_lock_irq(shost->host_lock);
+ 	ndlp->nlp_flag &= ~NLP_NPR_ADISC;
+@@ -594,6 +663,25 @@ lpfc_disc_illegal(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ 	return ndlp->nlp_state;
  }
  
- /**
-@@ -217,11 +530,6 @@ iscsi_data_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
- 	int datasn = be32_to_cpu(rhdr->datasn);
- 
- 	iscsi_update_cmdsn(session, (struct iscsi_nopin*)rhdr);
--	/*
--	 * setup Data-In byte counter (gets decremented..)
--	 */
--	ctask->data_count = tcp_conn->in.datalen;
--
- 	if (tcp_conn->in.datalen == 0)
- 		return 0;
- 
-@@ -242,22 +550,20 @@ iscsi_data_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
- 	}
++static uint32_t
++lpfc_cmpl_plogi_illegal(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
++		  void *arg, uint32_t evt)
++{
++	/* This transition is only legal if we previously
++	 * rcv'ed a PLOGI. Since we don't want 2 discovery threads
++	 * working on the same NPortID, do nothing for this thread
++	 * to stop it.
++	 */
++	if (!(ndlp->nlp_flag & NLP_RCV_PLOGI)) {
++		lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
++			 "0253 Illegal State Transition: node x%x "
++			 "event x%x, state x%x Data: x%x x%x\n",
++			 ndlp->nlp_DID, evt, ndlp->nlp_state, ndlp->nlp_rpi,
++			 ndlp->nlp_flag);
++	}
++	return ndlp->nlp_state;
++}
++
+ /* Start of Discovery State Machine routines */
  
- 	if (rhdr->flags & ISCSI_FLAG_DATA_STATUS) {
-+		sc->result = (DID_OK << 16) | rhdr->cmd_status;
- 		conn->exp_statsn = be32_to_cpu(rhdr->statsn) + 1;
--		if (rhdr->flags & ISCSI_FLAG_DATA_UNDERFLOW) {
-+		if (rhdr->flags & (ISCSI_FLAG_DATA_UNDERFLOW |
-+		                   ISCSI_FLAG_DATA_OVERFLOW)) {
- 			int res_count = be32_to_cpu(rhdr->residual_count);
+ static uint32_t
+@@ -605,11 +693,8 @@ lpfc_rcv_plogi_unused_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ 	cmdiocb = (struct lpfc_iocbq *) arg;
  
- 			if (res_count > 0 &&
--			    res_count <= scsi_bufflen(sc)) {
-+			    (rhdr->flags & ISCSI_FLAG_CMD_OVERFLOW ||
-+			     res_count <= scsi_bufflen(sc)))
- 				scsi_set_resid(sc, res_count);
--				sc->result = (DID_OK << 16) | rhdr->cmd_status;
--			} else
-+			else
- 				sc->result = (DID_BAD_TARGET << 16) |
- 					rhdr->cmd_status;
--		} else if (rhdr->flags & ISCSI_FLAG_DATA_OVERFLOW) {
--			scsi_set_resid(sc, be32_to_cpu(rhdr->residual_count));
--			sc->result = (DID_OK << 16) | rhdr->cmd_status;
--		} else
--			sc->result = (DID_OK << 16) | rhdr->cmd_status;
-+		}
+ 	if (lpfc_rcv_plogi(vport, ndlp, cmdiocb)) {
+-		ndlp->nlp_prev_state = NLP_STE_UNUSED_NODE;
+-		lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE);
+ 		return ndlp->nlp_state;
  	}
+-	lpfc_drop_node(vport, ndlp);
+ 	return NLP_STE_FREED_NODE;
+ }
  
- 	conn->datain_pdus_cnt++;
-@@ -281,9 +587,6 @@ iscsi_solicit_data_init(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask,
- 			struct iscsi_r2t_info *r2t)
+@@ -618,7 +703,6 @@ lpfc_rcv_els_unused_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ 			 void *arg, uint32_t evt)
  {
- 	struct iscsi_data *hdr;
--	struct scsi_cmnd *sc = ctask->sc;
--	int i, sg_count = 0;
--	struct scatterlist *sg;
- 
- 	hdr = &r2t->dtask.hdr;
- 	memset(hdr, 0, sizeof(struct iscsi_data));
-@@ -307,34 +610,6 @@ iscsi_solicit_data_init(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask,
- 	conn->dataout_pdus_cnt++;
- 
- 	r2t->sent = 0;
--
--	iscsi_buf_init_iov(&r2t->headbuf, (char*)hdr,
--			   sizeof(struct iscsi_hdr));
--
--	sg = scsi_sglist(sc);
--	r2t->sg = NULL;
--	for (i = 0; i < scsi_sg_count(sc); i++, sg += 1) {
--		/* FIXME: prefetch ? */
--		if (sg_count + sg->length > r2t->data_offset) {
--			int page_offset;
--
--			/* sg page found! */
--
--			/* offset within this page */
--			page_offset = r2t->data_offset - sg_count;
--
--			/* fill in this buffer */
--			iscsi_buf_init_sg(&r2t->sendbuf, sg);
--			r2t->sendbuf.sg.offset += page_offset;
--			r2t->sendbuf.sg.length -= page_offset;
--
--			/* xmit logic will continue with next one */
--			r2t->sg = sg + 1;
--			break;
--		}
--		sg_count += sg->length;
--	}
--	BUG_ON(r2t->sg == NULL);
+ 	lpfc_issue_els_logo(vport, ndlp, 0);
+-	lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE);
+ 	return ndlp->nlp_state;
  }
  
- /**
-@@ -366,14 +641,11 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
- 	}
- 
- 	/* fill-in new R2T associated with the task */
--	spin_lock(&session->lock);
- 	iscsi_update_cmdsn(session, (struct iscsi_nopin*)rhdr);
+@@ -633,7 +717,6 @@ lpfc_rcv_logo_unused_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ 	ndlp->nlp_flag |= NLP_LOGO_ACC;
+ 	spin_unlock_irq(shost->host_lock);
+ 	lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL);
+-	lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE);
  
--	if (!ctask->sc || ctask->mtask ||
--	     session->state != ISCSI_STATE_LOGGED_IN) {
-+	if (!ctask->sc || session->state != ISCSI_STATE_LOGGED_IN) {
- 		printk(KERN_INFO "iscsi_tcp: dropping R2T itt %d in "
- 		       "recovery...\n", ctask->itt);
--		spin_unlock(&session->lock);
- 		return 0;
- 	}
+ 	return ndlp->nlp_state;
+ }
+@@ -642,7 +725,6 @@ static uint32_t
+ lpfc_cmpl_logo_unused_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ 			   void *arg, uint32_t evt)
+ {
+-	lpfc_drop_node(vport, ndlp);
+ 	return NLP_STE_FREED_NODE;
+ }
  
-@@ -384,7 +656,8 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
- 	r2t->data_length = be32_to_cpu(rhdr->data_length);
- 	if (r2t->data_length == 0) {
- 		printk(KERN_ERR "iscsi_tcp: invalid R2T with zero data len\n");
--		spin_unlock(&session->lock);
-+		__kfifo_put(tcp_ctask->r2tpool.queue, (void*)&r2t,
-+			    sizeof(void*));
- 		return ISCSI_ERR_DATALEN;
- 	}
+@@ -650,7 +732,6 @@ static uint32_t
+ lpfc_device_rm_unused_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ 			   void *arg, uint32_t evt)
+ {
+-	lpfc_drop_node(vport, ndlp);
+ 	return NLP_STE_FREED_NODE;
+ }
  
-@@ -395,10 +668,11 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
+@@ -752,6 +833,7 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport,
+ 			    uint32_t evt)
+ {
+ 	struct lpfc_hba    *phba = vport->phba;
++	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+ 	struct lpfc_iocbq  *cmdiocb, *rspiocb;
+ 	struct lpfc_dmabuf *pcmd, *prsp, *mp;
+ 	uint32_t *lp;
+@@ -778,6 +860,12 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport,
  
- 	r2t->data_offset = be32_to_cpu(rhdr->data_offset);
- 	if (r2t->data_offset + r2t->data_length > scsi_bufflen(ctask->sc)) {
--		spin_unlock(&session->lock);
- 		printk(KERN_ERR "iscsi_tcp: invalid R2T with data len %u at "
- 		       "offset %u and total length %d\n", r2t->data_length,
- 		       r2t->data_offset, scsi_bufflen(ctask->sc));
-+		__kfifo_put(tcp_ctask->r2tpool.queue, (void*)&r2t,
-+			    sizeof(void*));
- 		return ISCSI_ERR_DATALEN;
+ 	lp = (uint32_t *) prsp->virt;
+ 	sp = (struct serv_parm *) ((uint8_t *) lp + sizeof (uint32_t));
++	if (wwn_to_u64(sp->portName.u.wwn) == 0 ||
++	    wwn_to_u64(sp->nodeName.u.wwn) == 0) {
++		lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
++				 "0142 PLOGI RSP: Invalid WWN.\n");
++		goto out;
++	}
+ 	if (!lpfc_check_sparm(vport, ndlp, sp, CLASS3))
+ 		goto out;
+ 	/* PLOGI chkparm OK */
+@@ -828,13 +916,15 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport,
+ 		}
+ 		mbox->context2 = lpfc_nlp_get(ndlp);
+ 		mbox->vport = vport;
+-		if (lpfc_sli_issue_mbox(phba, mbox,
+-					(MBX_NOWAIT | MBX_STOP_IOCB))
++		if (lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT)
+ 		    != MBX_NOT_FINISHED) {
+ 			lpfc_nlp_set_state(vport, ndlp,
+ 					   NLP_STE_REG_LOGIN_ISSUE);
+ 			return ndlp->nlp_state;
+ 		}
++		/* decrement node reference count to the failed mbox
++		 * command
++		 */
+ 		lpfc_nlp_put(ndlp);
+ 		mp = (struct lpfc_dmabuf *) mbox->context1;
+ 		lpfc_mbuf_free(phba, mp->virt, mp->phys);
+@@ -864,13 +954,27 @@ out:
+ 				 "0261 Cannot Register NameServer login\n");
  	}
  
-@@ -409,26 +683,55 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
- 
- 	tcp_ctask->exp_datasn = r2tsn + 1;
- 	__kfifo_put(tcp_ctask->r2tqueue, (void*)&r2t, sizeof(void*));
--	set_bit(XMSTATE_BIT_SOL_HDR_INIT, &tcp_ctask->xmstate);
--	list_move_tail(&ctask->running, &conn->xmitqueue);
--
--	scsi_queue_work(session->host, &conn->xmitwork);
- 	conn->r2t_pdus_cnt++;
--	spin_unlock(&session->lock);
- 
-+	iscsi_requeue_ctask(ctask);
- 	return 0;
+-	/* Free this node since the driver cannot login or has the wrong
+-	   sparm */
+-	lpfc_drop_node(vport, ndlp);
++	spin_lock_irq(shost->host_lock);
++	ndlp->nlp_flag |= NLP_DEFER_RM;
++	spin_unlock_irq(shost->host_lock);
+ 	return NLP_STE_FREED_NODE;
  }
  
-+/*
-+ * Handle incoming reply to DataIn command
-+ */
- static int
--iscsi_tcp_hdr_recv(struct iscsi_conn *conn)
-+iscsi_tcp_process_data_in(struct iscsi_tcp_conn *tcp_conn,
-+			  struct iscsi_segment *segment)
+ static uint32_t
++lpfc_cmpl_logo_plogi_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
++			   void *arg, uint32_t evt)
 +{
-+	struct iscsi_conn *conn = tcp_conn->iscsi_conn;
-+	struct iscsi_hdr *hdr = tcp_conn->in.hdr;
-+	int rc;
-+
-+	if (!iscsi_tcp_dgst_verify(tcp_conn, segment))
-+		return ISCSI_ERR_DATA_DGST;
-+
-+	/* check for non-exceptional status */
-+	if (hdr->flags & ISCSI_FLAG_DATA_STATUS) {
-+		rc = iscsi_complete_pdu(conn, tcp_conn->in.hdr, NULL, 0);
-+		if (rc)
-+			return rc;
-+	}
++	return ndlp->nlp_state;
++}
 +
-+	iscsi_tcp_hdr_recv_prep(tcp_conn);
-+	return 0;
++static uint32_t
++lpfc_cmpl_reglogin_plogi_issue(struct lpfc_vport *vport,
++	struct lpfc_nodelist *ndlp, void *arg, uint32_t evt)
++{
++	return ndlp->nlp_state;
 +}
 +
-+/**
-+ * iscsi_tcp_hdr_dissect - process PDU header
-+ * @conn: iSCSI connection
-+ * @hdr: PDU header
-+ *
-+ * This function analyzes the header of the PDU received,
-+ * and performs several sanity checks. If the PDU is accompanied
-+ * by data, the receive buffer is set up to copy the incoming data
-+ * to the correct location.
-+ */
-+static int
-+iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
++static uint32_t
+ lpfc_device_rm_plogi_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ 			   void *arg, uint32_t evt)
  {
- 	int rc = 0, opcode, ahslen;
--	struct iscsi_hdr *hdr;
- 	struct iscsi_session *session = conn->session;
- 	struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
--	uint32_t cdgst, rdgst = 0, itt;
--
--	hdr = tcp_conn->in.hdr;
-+	struct iscsi_cmd_task *ctask;
-+	uint32_t itt;
+@@ -1137,7 +1241,7 @@ lpfc_rcv_logo_reglogin_issue(struct lpfc_vport *vport,
+ 		   (ndlp == (struct lpfc_nodelist *) mb->context2)) {
+ 			mp = (struct lpfc_dmabuf *) (mb->context1);
+ 			if (mp) {
+-				lpfc_mbuf_free(phba, mp->virt, mp->phys);
++				__lpfc_mbuf_free(phba, mp->virt, mp->phys);
+ 				kfree(mp);
+ 			}
+ 			lpfc_nlp_put(ndlp);
+@@ -1197,8 +1301,8 @@ lpfc_cmpl_reglogin_reglogin_issue(struct lpfc_vport *vport,
+ 		 * retry discovery.
+ 		 */
+ 		if (mb->mbxStatus == MBXERR_RPI_FULL) {
+-			ndlp->nlp_prev_state = NLP_STE_UNUSED_NODE;
+-			lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE);
++			ndlp->nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE;
++			lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
+ 			return ndlp->nlp_state;
+ 		}
  
- 	/* verify PDU length */
- 	tcp_conn->in.datalen = ntoh24(hdr->dlength);
-@@ -437,78 +740,73 @@ iscsi_tcp_hdr_recv(struct iscsi_conn *conn)
- 		       tcp_conn->in.datalen, conn->max_recv_dlength);
- 		return ISCSI_ERR_DATALEN;
+@@ -1378,7 +1482,7 @@ out:
+ 		lpfc_issue_els_logo(vport, ndlp, 0);
+ 
+ 		ndlp->nlp_prev_state = NLP_STE_PRLI_ISSUE;
+-		lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE);
++		lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
+ 		return ndlp->nlp_state;
  	}
--	tcp_conn->data_copied = 0;
  
--	/* read AHS */
-+	/* Additional header segments. So far, we don't
-+	 * process additional headers.
-+	 */
- 	ahslen = hdr->hlength << 2;
--	tcp_conn->in.offset += ahslen;
--	tcp_conn->in.copy -= ahslen;
--	if (tcp_conn->in.copy < 0) {
--		printk(KERN_ERR "iscsi_tcp: can't handle AHS with length "
--		       "%d bytes\n", ahslen);
--		return ISCSI_ERR_AHSLEN;
--	}
--
--	/* calculate read padding */
--	tcp_conn->in.padding = tcp_conn->in.datalen & (ISCSI_PAD_LEN-1);
--	if (tcp_conn->in.padding) {
--		tcp_conn->in.padding = ISCSI_PAD_LEN - tcp_conn->in.padding;
--		debug_scsi("read padding %d bytes\n", tcp_conn->in.padding);
--	}
--
--	if (conn->hdrdgst_en) {
--		struct scatterlist sg;
--
--		sg_init_one(&sg, (u8 *)hdr,
--			    sizeof(struct iscsi_hdr) + ahslen);
--		crypto_hash_digest(&tcp_conn->rx_hash, &sg, sg.length,
--				   (u8 *)&cdgst);
--		rdgst = *(uint32_t*)((char*)hdr + sizeof(struct iscsi_hdr) +
--				     ahslen);
--		if (cdgst != rdgst) {
--			printk(KERN_ERR "iscsi_tcp: hdrdgst error "
--			       "recv 0x%x calc 0x%x\n", rdgst, cdgst);
--			return ISCSI_ERR_HDR_DGST;
--		}
--	}
+@@ -1753,7 +1857,7 @@ lpfc_cmpl_plogi_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
  
- 	opcode = hdr->opcode & ISCSI_OPCODE_MASK;
- 	/* verify itt (itt encoding: age+cid+itt) */
- 	rc = iscsi_verify_itt(conn, hdr, &itt);
--	if (rc == ISCSI_ERR_NO_SCSI_CMD) {
--		tcp_conn->in.datalen = 0; /* force drop */
--		return 0;
--	} else if (rc)
-+	if (rc)
- 		return rc;
+ 	irsp = &rspiocb->iocb;
+ 	if (irsp->ulpStatus) {
+-		lpfc_drop_node(vport, ndlp);
++		ndlp->nlp_flag |= NLP_DEFER_RM;
+ 		return NLP_STE_FREED_NODE;
+ 	}
+ 	return ndlp->nlp_state;
+@@ -1942,9 +2046,9 @@ static uint32_t (*lpfc_disc_action[NLP_STE_MAX_STATE * NLP_EVT_MAX_EVENT])
+ 	lpfc_rcv_els_plogi_issue,	/* RCV_PRLO        */
+ 	lpfc_cmpl_plogi_plogi_issue,	/* CMPL_PLOGI      */
+ 	lpfc_disc_illegal,		/* CMPL_PRLI       */
+-	lpfc_disc_illegal,		/* CMPL_LOGO       */
++	lpfc_cmpl_logo_plogi_issue,	/* CMPL_LOGO       */
+ 	lpfc_disc_illegal,		/* CMPL_ADISC      */
+-	lpfc_disc_illegal,		/* CMPL_REG_LOGIN  */
++	lpfc_cmpl_reglogin_plogi_issue,/* CMPL_REG_LOGIN  */
+ 	lpfc_device_rm_plogi_issue,	/* DEVICE_RM       */
+ 	lpfc_device_recov_plogi_issue,	/* DEVICE_RECOVERY */
  
--	debug_tcp("opcode 0x%x offset %d copy %d ahslen %d datalen %d\n",
--		  opcode, tcp_conn->in.offset, tcp_conn->in.copy,
--		  ahslen, tcp_conn->in.datalen);
-+	debug_tcp("opcode 0x%x ahslen %d datalen %d\n",
-+		  opcode, ahslen, tcp_conn->in.datalen);
+@@ -1968,7 +2072,7 @@ static uint32_t (*lpfc_disc_action[NLP_STE_MAX_STATE * NLP_EVT_MAX_EVENT])
+ 	lpfc_rcv_padisc_reglogin_issue,	/* RCV_ADISC       */
+ 	lpfc_rcv_padisc_reglogin_issue,	/* RCV_PDISC       */
+ 	lpfc_rcv_prlo_reglogin_issue,	/* RCV_PRLO        */
+-	lpfc_disc_illegal,		/* CMPL_PLOGI      */
++	lpfc_cmpl_plogi_illegal,	/* CMPL_PLOGI      */
+ 	lpfc_disc_illegal,		/* CMPL_PRLI       */
+ 	lpfc_disc_illegal,		/* CMPL_LOGO       */
+ 	lpfc_disc_illegal,		/* CMPL_ADISC      */
+@@ -1982,7 +2086,7 @@ static uint32_t (*lpfc_disc_action[NLP_STE_MAX_STATE * NLP_EVT_MAX_EVENT])
+ 	lpfc_rcv_padisc_prli_issue,	/* RCV_ADISC       */
+ 	lpfc_rcv_padisc_prli_issue,	/* RCV_PDISC       */
+ 	lpfc_rcv_prlo_prli_issue,	/* RCV_PRLO        */
+-	lpfc_disc_illegal,		/* CMPL_PLOGI      */
++	lpfc_cmpl_plogi_illegal,	/* CMPL_PLOGI      */
+ 	lpfc_cmpl_prli_prli_issue,	/* CMPL_PRLI       */
+ 	lpfc_disc_illegal,		/* CMPL_LOGO       */
+ 	lpfc_disc_illegal,		/* CMPL_ADISC      */
+diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c
+index 4e46045..6483c62 100644
+--- a/drivers/scsi/lpfc/lpfc_scsi.c
++++ b/drivers/scsi/lpfc/lpfc_scsi.c
+@@ -130,7 +130,7 @@ lpfc_ramp_down_queue_handler(struct lpfc_hba *phba)
  
- 	switch(opcode) {
- 	case ISCSI_OP_SCSI_DATA_IN:
--		tcp_conn->in.ctask = session->cmds[itt];
--		rc = iscsi_data_rsp(conn, tcp_conn->in.ctask);
-+		ctask = session->cmds[itt];
-+		spin_lock(&conn->session->lock);
-+		rc = iscsi_data_rsp(conn, ctask);
-+		spin_unlock(&conn->session->lock);
- 		if (rc)
- 			return rc;
-+		if (tcp_conn->in.datalen) {
-+			struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
-+			struct hash_desc *rx_hash = NULL;
-+
-+			/*
-+			 * Setup copy of Data-In into the Scsi_Cmnd
-+			 * Scatterlist case:
-+			 * We set up the iscsi_segment to point to the next
-+			 * scatterlist entry to copy to. As we go along,
-+			 * we move on to the next scatterlist entry and
-+			 * update the digest per-entry.
-+			 */
-+			if (conn->datadgst_en)
-+				rx_hash = &tcp_conn->rx_hash;
-+
-+			debug_tcp("iscsi_tcp_begin_data_in(%p, offset=%d, "
-+				  "datalen=%d)\n", tcp_conn,
-+				  tcp_ctask->data_offset,
-+				  tcp_conn->in.datalen);
-+			return iscsi_segment_seek_sg(&tcp_conn->in.segment,
-+						     scsi_sglist(ctask->sc),
-+						     scsi_sg_count(ctask->sc),
-+						     tcp_ctask->data_offset,
-+						     tcp_conn->in.datalen,
-+						     iscsi_tcp_process_data_in,
-+						     rx_hash);
-+		}
- 		/* fall through */
- 	case ISCSI_OP_SCSI_CMD_RSP:
--		tcp_conn->in.ctask = session->cmds[itt];
--		if (tcp_conn->in.datalen)
--			goto copy_hdr;
--
--		spin_lock(&session->lock);
--		rc = __iscsi_complete_pdu(conn, hdr, NULL, 0);
--		spin_unlock(&session->lock);
-+		if (tcp_conn->in.datalen) {
-+			iscsi_tcp_data_recv_prep(tcp_conn);
-+			return 0;
-+		}
-+		rc = iscsi_complete_pdu(conn, hdr, NULL, 0);
- 		break;
- 	case ISCSI_OP_R2T:
--		tcp_conn->in.ctask = session->cmds[itt];
-+		ctask = session->cmds[itt];
- 		if (ahslen)
- 			rc = ISCSI_ERR_AHSLEN;
--		else if (tcp_conn->in.ctask->sc->sc_data_direction ==
--								DMA_TO_DEVICE)
--			rc = iscsi_r2t_rsp(conn, tcp_conn->in.ctask);
--		else
-+		else if (ctask->sc->sc_data_direction == DMA_TO_DEVICE) {
-+			spin_lock(&session->lock);
-+			rc = iscsi_r2t_rsp(conn, ctask);
-+			spin_unlock(&session->lock);
-+		} else
- 			rc = ISCSI_ERR_PROTO;
- 		break;
- 	case ISCSI_OP_LOGIN_RSP:
-@@ -520,8 +818,7 @@ iscsi_tcp_hdr_recv(struct iscsi_conn *conn)
- 		 * than 8K, but there are no targets that currently do this.
- 		 * For now we fail until we find a vendor that needs it
- 		 */
--		if (ISCSI_DEF_MAX_RECV_SEG_LEN <
--		    tcp_conn->in.datalen) {
-+		if (ISCSI_DEF_MAX_RECV_SEG_LEN < tcp_conn->in.datalen) {
- 			printk(KERN_ERR "iscsi_tcp: received buffer of len %u "
- 			      "but conn buffer is only %u (opcode %0x)\n",
- 			      tcp_conn->in.datalen,
-@@ -530,8 +827,13 @@ iscsi_tcp_hdr_recv(struct iscsi_conn *conn)
- 			break;
+ 	vports = lpfc_create_vport_work_array(phba);
+ 	if (vports != NULL)
+-		for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++) {
++		for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) {
+ 			shost = lpfc_shost_from_vport(vports[i]);
+ 			shost_for_each_device(sdev, shost) {
+ 				new_queue_depth =
+@@ -151,7 +151,7 @@ lpfc_ramp_down_queue_handler(struct lpfc_hba *phba)
+ 							new_queue_depth);
+ 			}
  		}
+-	lpfc_destroy_vport_work_array(vports);
++	lpfc_destroy_vport_work_array(phba, vports);
+ 	atomic_set(&phba->num_rsrc_err, 0);
+ 	atomic_set(&phba->num_cmd_success, 0);
+ }
+@@ -166,7 +166,7 @@ lpfc_ramp_up_queue_handler(struct lpfc_hba *phba)
  
--		if (tcp_conn->in.datalen)
--			goto copy_hdr;
-+		/* If there's data coming in with the response,
-+		 * receive it to the connection's buffer.
+ 	vports = lpfc_create_vport_work_array(phba);
+ 	if (vports != NULL)
+-		for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++) {
++		for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) {
+ 			shost = lpfc_shost_from_vport(vports[i]);
+ 			shost_for_each_device(sdev, shost) {
+ 				if (sdev->ordered_tags)
+@@ -179,7 +179,7 @@ lpfc_ramp_up_queue_handler(struct lpfc_hba *phba)
+ 							sdev->queue_depth+1);
+ 			}
+ 		}
+-	lpfc_destroy_vport_work_array(vports);
++	lpfc_destroy_vport_work_array(phba, vports);
+ 	atomic_set(&phba->num_rsrc_err, 0);
+ 	atomic_set(&phba->num_cmd_success, 0);
+ }
+@@ -380,7 +380,7 @@ lpfc_scsi_prep_dma_buf(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd)
+ 		(num_bde * sizeof (struct ulp_bde64));
+ 	iocb_cmd->ulpBdeCount = 1;
+ 	iocb_cmd->ulpLe = 1;
+-	fcp_cmnd->fcpDl = be32_to_cpu(scsi_bufflen(scsi_cmnd));
++	fcp_cmnd->fcpDl = cpu_to_be32(scsi_bufflen(scsi_cmnd));
+ 	return 0;
+ }
+ 
+@@ -542,6 +542,7 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
+ 	int result;
+ 	struct scsi_device *sdev, *tmp_sdev;
+ 	int depth = 0;
++	unsigned long flags;
+ 
+ 	lpfc_cmd->result = pIocbOut->iocb.un.ulpWord[4];
+ 	lpfc_cmd->status = pIocbOut->iocb.ulpStatus;
+@@ -608,6 +609,15 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
+ 	cmd->scsi_done(cmd);
+ 
+ 	if (phba->cfg_poll & ENABLE_FCP_RING_POLLING) {
++		/*
++		 * If there is a thread waiting for command completion
++		 * wake up the thread.
 +		 */
-+		if (tcp_conn->in.datalen) {
-+			iscsi_tcp_data_recv_prep(tcp_conn);
-+			return 0;
-+		}
- 	/* fall through */
- 	case ISCSI_OP_LOGOUT_RSP:
- 	case ISCSI_OP_NOOP_IN:
-@@ -543,461 +845,161 @@ iscsi_tcp_hdr_recv(struct iscsi_conn *conn)
- 		break;
++		spin_lock_irqsave(sdev->host->host_lock, flags);
++		lpfc_cmd->pCmd = NULL;
++		if (lpfc_cmd->waitq)
++			wake_up(lpfc_cmd->waitq);
++		spin_unlock_irqrestore(sdev->host->host_lock, flags);
+ 		lpfc_release_scsi_buf(phba, lpfc_cmd);
+ 		return;
+ 	}
+@@ -669,6 +679,16 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
+ 		}
  	}
  
--	return rc;
--
--copy_hdr:
--	/*
--	 * if we did zero copy for the header but we will need multiple
--	 * skbs to complete the command then we have to copy the header
--	 * for later use
--	 */
--	if (tcp_conn->in.zero_copy_hdr && tcp_conn->in.copy <=
--	   (tcp_conn->in.datalen + tcp_conn->in.padding +
--	    (conn->datadgst_en ? 4 : 0))) {
--		debug_tcp("Copying header for later use. in.copy %d in.datalen"
--			  " %d\n", tcp_conn->in.copy, tcp_conn->in.datalen);
--		memcpy(&tcp_conn->hdr, tcp_conn->in.hdr,
--		       sizeof(struct iscsi_hdr));
--		tcp_conn->in.hdr = &tcp_conn->hdr;
--		tcp_conn->in.zero_copy_hdr = 0;
++	/*
++	 * If there is a thread waiting for command completion
++	 * wake up the thread.
++	 */
++	spin_lock_irqsave(sdev->host->host_lock, flags);
++	lpfc_cmd->pCmd = NULL;
++	if (lpfc_cmd->waitq)
++		wake_up(lpfc_cmd->waitq);
++	spin_unlock_irqrestore(sdev->host->host_lock, flags);
++
+ 	lpfc_release_scsi_buf(phba, lpfc_cmd);
+ }
+ 
+@@ -743,6 +763,8 @@ lpfc_scsi_prep_cmnd(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd,
+ 	piocbq->iocb.ulpContext = pnode->nlp_rpi;
+ 	if (pnode->nlp_fcp_info & NLP_FCP_2_DEVICE)
+ 		piocbq->iocb.ulpFCP2Rcvy = 1;
++	else
++		piocbq->iocb.ulpFCP2Rcvy = 0;
+ 
+ 	piocbq->iocb.ulpClass = (pnode->nlp_fcp_info & 0x0f);
+ 	piocbq->context1  = lpfc_cmd;
+@@ -1018,8 +1040,8 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd)
+ 	struct lpfc_iocbq *abtsiocb;
+ 	struct lpfc_scsi_buf *lpfc_cmd;
+ 	IOCB_t *cmd, *icmd;
+-	unsigned int loop_count = 0;
+ 	int ret = SUCCESS;
++	DECLARE_WAIT_QUEUE_HEAD_ONSTACK(waitq);
+ 
+ 	lpfc_block_error_handler(cmnd);
+ 	lpfc_cmd = (struct lpfc_scsi_buf *)cmnd->host_scribble;
+@@ -1074,17 +1096,15 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd)
+ 	if (phba->cfg_poll & DISABLE_FCP_RING_INT)
+ 		lpfc_sli_poll_fcp_ring (phba);
+ 
++	lpfc_cmd->waitq = &waitq;
+ 	/* Wait for abort to complete */
+-	while (lpfc_cmd->pCmd == cmnd)
+-	{
+-		if (phba->cfg_poll & DISABLE_FCP_RING_INT)
+-			lpfc_sli_poll_fcp_ring (phba);
++	wait_event_timeout(waitq,
++			  (lpfc_cmd->pCmd != cmnd),
++			   (2*vport->cfg_devloss_tmo*HZ));
+ 
+-		schedule_timeout_uninterruptible(LPFC_ABORT_WAIT * HZ);
+-		if (++loop_count
+-		    > (2 * vport->cfg_devloss_tmo)/LPFC_ABORT_WAIT)
+-			break;
 -	}
--	return 0;
--}
--
--/**
-- * iscsi_ctask_copy - copy skb bits to the destanation cmd task
-- * @conn: iscsi tcp connection
-- * @ctask: scsi command task
-- * @buf: buffer to copy to
-- * @buf_size: size of buffer
-- * @offset: offset within the buffer
-- *
-- * Notes:
-- *	The function calls skb_copy_bits() and updates per-connection and
-- *	per-cmd byte counters.
-- *
-- *	Read counters (in bytes):
-- *
-- *	conn->in.offset		offset within in progress SKB
-- *	conn->in.copy		left to copy from in progress SKB
-- *				including padding
-- *	conn->in.copied		copied already from in progress SKB
-- *	conn->data_copied	copied already from in progress buffer
-- *	ctask->sent		total bytes sent up to the MidLayer
-- *	ctask->data_count	left to copy from in progress Data-In
-- *	buf_left		left to copy from in progress buffer
-- **/
--static inline int
--iscsi_ctask_copy(struct iscsi_tcp_conn *tcp_conn, struct iscsi_cmd_task *ctask,
--		void *buf, int buf_size, int offset)
--{
--	struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
--	int buf_left = buf_size - (tcp_conn->data_copied + offset);
--	unsigned size = min(tcp_conn->in.copy, buf_left);
--	int rc;
--
--	size = min(size, ctask->data_count);
--
--	debug_tcp("ctask_copy %d bytes at offset %d copied %d\n",
--	       size, tcp_conn->in.offset, tcp_conn->in.copied);
--
--	BUG_ON(size <= 0);
--	BUG_ON(tcp_ctask->sent + size > scsi_bufflen(ctask->sc));
--
--	rc = skb_copy_bits(tcp_conn->in.skb, tcp_conn->in.offset,
--			   (char*)buf + (offset + tcp_conn->data_copied), size);
--	/* must fit into skb->len */
--	BUG_ON(rc);
--
--	tcp_conn->in.offset += size;
--	tcp_conn->in.copy -= size;
--	tcp_conn->in.copied += size;
--	tcp_conn->data_copied += size;
--	tcp_ctask->sent += size;
--	ctask->data_count -= size;
--
--	BUG_ON(tcp_conn->in.copy < 0);
--	BUG_ON(ctask->data_count < 0);
--
--	if (buf_size != (tcp_conn->data_copied + offset)) {
--		if (!ctask->data_count) {
--			BUG_ON(buf_size - tcp_conn->data_copied < 0);
--			/* done with this PDU */
--			return buf_size - tcp_conn->data_copied;
--		}
--		return -EAGAIN;
-+	if (rc == 0) {
-+		/* Anything that comes with data should have
-+		 * been handled above. */
-+		if (tcp_conn->in.datalen)
-+			return ISCSI_ERR_PROTO;
-+		iscsi_tcp_hdr_recv_prep(tcp_conn);
- 	}
++	spin_lock_irq(shost->host_lock);
++	lpfc_cmd->waitq = NULL;
++	spin_unlock_irq(shost->host_lock);
  
--	/* done with this buffer or with both - PDU and buffer */
--	tcp_conn->data_copied = 0;
--	return 0;
-+	return rc;
+ 	if (lpfc_cmd->pCmd == cmnd) {
+ 		ret = FAILED;
+@@ -1438,7 +1458,7 @@ struct scsi_host_template lpfc_template = {
+ 	.slave_destroy		= lpfc_slave_destroy,
+ 	.scan_finished		= lpfc_scan_finished,
+ 	.this_id		= -1,
+-	.sg_tablesize		= LPFC_SG_SEG_CNT,
++	.sg_tablesize		= LPFC_DEFAULT_SG_SEG_CNT,
+ 	.use_sg_chaining	= ENABLE_SG_CHAINING,
+ 	.cmd_per_lun		= LPFC_CMD_PER_LUN,
+ 	.use_clustering		= ENABLE_CLUSTERING,
+@@ -1459,7 +1479,7 @@ struct scsi_host_template lpfc_vport_template = {
+ 	.slave_destroy		= lpfc_slave_destroy,
+ 	.scan_finished		= lpfc_scan_finished,
+ 	.this_id		= -1,
+-	.sg_tablesize		= LPFC_SG_SEG_CNT,
++	.sg_tablesize		= LPFC_DEFAULT_SG_SEG_CNT,
+ 	.cmd_per_lun		= LPFC_CMD_PER_LUN,
+ 	.use_clustering		= ENABLE_CLUSTERING,
+ 	.use_sg_chaining	= ENABLE_SG_CHAINING,
+diff --git a/drivers/scsi/lpfc/lpfc_scsi.h b/drivers/scsi/lpfc/lpfc_scsi.h
+index 31787bb..daba923 100644
+--- a/drivers/scsi/lpfc/lpfc_scsi.h
++++ b/drivers/scsi/lpfc/lpfc_scsi.h
+@@ -138,6 +138,7 @@ struct lpfc_scsi_buf {
+ 	 * Iotag is in here
+ 	 */
+ 	struct lpfc_iocbq cur_iocbq;
++	wait_queue_head_t *waitq;
+ };
+ 
+ #define LPFC_SCSI_DMA_EXT_SIZE 264
+diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c
+index ce348c5..fdd01e3 100644
+--- a/drivers/scsi/lpfc/lpfc_sli.c
++++ b/drivers/scsi/lpfc/lpfc_sli.c
+@@ -106,7 +106,7 @@ lpfc_sli_get_iocbq(struct lpfc_hba *phba)
+ 	return iocbq;
  }
  
- /**
-- * iscsi_tcp_copy - copy skb bits to the destanation buffer
-- * @conn: iscsi tcp connection
-+ * iscsi_tcp_hdr_recv_done - process PDU header
-  *
-- * Notes:
-- *	The function calls skb_copy_bits() and updates per-connection
-- *	byte counters.
-- **/
--static inline int
--iscsi_tcp_copy(struct iscsi_conn *conn, int buf_size)
--{
--	struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
--	int buf_left = buf_size - tcp_conn->data_copied;
--	int size = min(tcp_conn->in.copy, buf_left);
--	int rc;
--
--	debug_tcp("tcp_copy %d bytes at offset %d copied %d\n",
--	       size, tcp_conn->in.offset, tcp_conn->data_copied);
--	BUG_ON(size <= 0);
--
--	rc = skb_copy_bits(tcp_conn->in.skb, tcp_conn->in.offset,
--			   (char*)conn->data + tcp_conn->data_copied, size);
--	BUG_ON(rc);
--
--	tcp_conn->in.offset += size;
--	tcp_conn->in.copy -= size;
--	tcp_conn->in.copied += size;
--	tcp_conn->data_copied += size;
--
--	if (buf_size != tcp_conn->data_copied)
--		return -EAGAIN;
--
--	return 0;
--}
--
--static inline void
--partial_sg_digest_update(struct hash_desc *desc, struct scatterlist *sg,
--			 int offset, int length)
--{
--	struct scatterlist temp;
--
--	sg_init_table(&temp, 1);
--	sg_set_page(&temp, sg_page(sg), length, offset);
--	crypto_hash_update(desc, &temp, length);
--}
--
+-void
++static void
+ __lpfc_sli_release_iocbq(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq)
+ {
+ 	size_t start_clean = offsetof(struct lpfc_iocbq, iocb);
+@@ -199,6 +199,7 @@ lpfc_sli_iocb_cmd_type(uint8_t iocb_cmnd)
+ 	case CMD_RCV_ELS_REQ_CX:
+ 	case CMD_RCV_SEQUENCE64_CX:
+ 	case CMD_RCV_ELS_REQ64_CX:
++	case CMD_ASYNC_STATUS:
+ 	case CMD_IOCB_RCV_SEQ64_CX:
+ 	case CMD_IOCB_RCV_ELS64_CX:
+ 	case CMD_IOCB_RCV_CONT64_CX:
+@@ -473,8 +474,7 @@ lpfc_sli_resume_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
+ 	if (pring->txq_cnt &&
+ 	    lpfc_is_link_up(phba) &&
+ 	    (pring->ringno != phba->sli.fcp_ring ||
+-	     phba->sli.sli_flag & LPFC_PROCESS_LA) &&
+-	    !(pring->flag & LPFC_STOP_IOCB_MBX)) {
++	     phba->sli.sli_flag & LPFC_PROCESS_LA)) {
+ 
+ 		while ((iocb = lpfc_sli_next_iocb_slot(phba, pring)) &&
+ 		       (nextiocb = lpfc_sli_ringtx_get(phba, pring)))
+@@ -489,32 +489,7 @@ lpfc_sli_resume_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
+ 	return;
+ }
+ 
+-/* lpfc_sli_turn_on_ring is only called by lpfc_sli_handle_mb_event below */
 -static void
--iscsi_recv_digest_update(struct iscsi_tcp_conn *tcp_conn, char* buf, int len)
+-lpfc_sli_turn_on_ring(struct lpfc_hba *phba, int ringno)
 -{
--	struct scatterlist tmp;
--
--	sg_init_one(&tmp, buf, len);
--	crypto_hash_update(&tcp_conn->rx_hash, &tmp, len);
--}
--
--static int iscsi_scsi_data_in(struct iscsi_conn *conn)
-+ * This is the callback invoked when the PDU header has
-+ * been received. If the header is followed by additional
-+ * header segments, we go back for more data.
-+ */
-+static int
-+iscsi_tcp_hdr_recv_done(struct iscsi_tcp_conn *tcp_conn,
-+			struct iscsi_segment *segment)
- {
--	struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
--	struct iscsi_cmd_task *ctask = tcp_conn->in.ctask;
--	struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
--	struct scsi_cmnd *sc = ctask->sc;
--	struct scatterlist *sg;
--	int i, offset, rc = 0;
--
--	BUG_ON((void*)ctask != sc->SCp.ptr);
--
--	offset = tcp_ctask->data_offset;
--	sg = scsi_sglist(sc);
--
--	if (tcp_ctask->data_offset)
--		for (i = 0; i < tcp_ctask->sg_count; i++)
--			offset -= sg[i].length;
--	/* we've passed through partial sg*/
--	if (offset < 0)
--		offset = 0;
--
--	for (i = tcp_ctask->sg_count; i < scsi_sg_count(sc); i++) {
--		char *dest;
--
--		dest = kmap_atomic(sg_page(&sg[i]), KM_SOFTIRQ0);
--		rc = iscsi_ctask_copy(tcp_conn, ctask, dest + sg[i].offset,
--				      sg[i].length, offset);
--		kunmap_atomic(dest, KM_SOFTIRQ0);
--		if (rc == -EAGAIN)
--			/* continue with the next SKB/PDU */
--			return rc;
--		if (!rc) {
--			if (conn->datadgst_en) {
--				if (!offset)
--					crypto_hash_update(
--							&tcp_conn->rx_hash,
--							&sg[i], sg[i].length);
--				else
--					partial_sg_digest_update(
--							&tcp_conn->rx_hash,
--							&sg[i],
--							sg[i].offset + offset,
--							sg[i].length - offset);
--			}
--			offset = 0;
--			tcp_ctask->sg_count++;
--		}
+-	struct lpfc_pgp *pgp = (phba->sli_rev == 3) ?
+-		&phba->slim2p->mbx.us.s3_pgp.port[ringno] :
+-		&phba->slim2p->mbx.us.s2.port[ringno];
+-	unsigned long iflags;
 -
--		if (!ctask->data_count) {
--			if (rc && conn->datadgst_en)
--				/*
--				 * data-in is complete, but buffer not...
--				 */
--				partial_sg_digest_update(&tcp_conn->rx_hash,
--							 &sg[i],
--							 sg[i].offset,
--							 sg[i].length-rc);
--			rc = 0;
--			break;
+-	/* If the ring is active, flag it */
+-	spin_lock_irqsave(&phba->hbalock, iflags);
+-	if (phba->sli.ring[ringno].cmdringaddr) {
+-		if (phba->sli.ring[ringno].flag & LPFC_STOP_IOCB_MBX) {
+-			phba->sli.ring[ringno].flag &= ~LPFC_STOP_IOCB_MBX;
+-			/*
+-			 * Force update of the local copy of cmdGetInx
+-			 */
+-			phba->sli.ring[ringno].local_getidx
+-				= le32_to_cpu(pgp->cmdGetInx);
+-			lpfc_sli_resume_iocb(phba, &phba->sli.ring[ringno]);
 -		}
--
--		if (!tcp_conn->in.copy)
--			return -EAGAIN;
 -	}
--	BUG_ON(ctask->data_count);
-+	struct iscsi_conn *conn = tcp_conn->iscsi_conn;
-+	struct iscsi_hdr *hdr;
- 
--	/* check for non-exceptional status */
--	if (tcp_conn->in.hdr->flags & ISCSI_FLAG_DATA_STATUS) {
--		debug_scsi("done [sc %lx res %d itt 0x%x flags 0x%x]\n",
--			   (long)sc, sc->result, ctask->itt,
--			   tcp_conn->in.hdr->flags);
--		spin_lock(&conn->session->lock);
--		__iscsi_complete_pdu(conn, tcp_conn->in.hdr, NULL, 0);
--		spin_unlock(&conn->session->lock);
-+	/* Check if there are additional header segments
-+	 * *prior* to computing the digest, because we
-+	 * may need to go back to the caller for more.
-+	 */
-+	hdr = (struct iscsi_hdr *) tcp_conn->in.hdr_buf;
-+	if (segment->copied == sizeof(struct iscsi_hdr) && hdr->hlength) {
-+		/* Bump the header length - the caller will
-+		 * just loop around and get the AHS for us, and
-+		 * call again. */
-+		unsigned int ahslen = hdr->hlength << 2;
-+
-+		/* Make sure we don't overflow */
-+		if (sizeof(*hdr) + ahslen > sizeof(tcp_conn->in.hdr_buf))
-+			return ISCSI_ERR_AHSLEN;
-+
-+		segment->total_size += ahslen;
-+		segment->size += ahslen;
-+		return 0;
- 	}
- 
--	return rc;
+-	spin_unlock_irqrestore(&phba->hbalock, iflags);
 -}
 -
--static int
--iscsi_data_recv(struct iscsi_conn *conn)
--{
--	struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
--	int rc = 0, opcode;
--
--	opcode = tcp_conn->in.hdr->opcode & ISCSI_OPCODE_MASK;
--	switch (opcode) {
--	case ISCSI_OP_SCSI_DATA_IN:
--		rc = iscsi_scsi_data_in(conn);
--		break;
--	case ISCSI_OP_SCSI_CMD_RSP:
--	case ISCSI_OP_TEXT_RSP:
--	case ISCSI_OP_LOGIN_RSP:
--	case ISCSI_OP_ASYNC_EVENT:
--	case ISCSI_OP_REJECT:
--		/*
--		 * Collect data segment to the connection's data
--		 * placeholder
--		 */
--		if (iscsi_tcp_copy(conn, tcp_conn->in.datalen)) {
--			rc = -EAGAIN;
--			goto exit;
-+	/* We're done processing the header. See if we're doing
-+	 * header digests; if so, set up the recv_digest buffer
-+	 * and go back for more. */
-+	if (conn->hdrdgst_en) {
-+		if (segment->digest_len == 0) {
-+			iscsi_tcp_segment_splice_digest(segment,
-+							segment->recv_digest);
-+			return 0;
+-struct lpfc_hbq_entry *
++static struct lpfc_hbq_entry *
+ lpfc_sli_next_hbq_slot(struct lpfc_hba *phba, uint32_t hbqno)
+ {
+ 	struct hbq_s *hbqp = &phba->hbqs[hbqno];
+@@ -565,6 +540,7 @@ lpfc_sli_hbqbuf_free_all(struct lpfc_hba *phba)
+ 			list_del(&hbq_buf->dbuf.list);
+ 			(phba->hbqs[i].hbq_free_buffer)(phba, hbq_buf);
  		}
-+		iscsi_tcp_dgst_header(&tcp_conn->rx_hash, hdr,
-+				      segment->total_copied - ISCSI_DIGEST_SIZE,
-+				      segment->digest);
++		phba->hbqs[i].buffer_count = 0;
+ 	}
+ }
  
--		rc = iscsi_complete_pdu(conn, tcp_conn->in.hdr, conn->data,
--					tcp_conn->in.datalen);
--		if (!rc && conn->datadgst_en && opcode != ISCSI_OP_LOGIN_RSP)
--			iscsi_recv_digest_update(tcp_conn, conn->data,
--			  			tcp_conn->in.datalen);
--		break;
--	default:
--		BUG_ON(1);
-+		if (!iscsi_tcp_dgst_verify(tcp_conn, segment))
-+			return ISCSI_ERR_HDR_DGST;
+@@ -633,8 +609,8 @@ lpfc_sli_hbqbuf_fill_hbqs(struct lpfc_hba *phba, uint32_t hbqno, uint32_t count)
+ 		return 0;
  	}
--exit:
--	return rc;
-+
-+	tcp_conn->in.hdr = hdr;
-+	return iscsi_tcp_hdr_dissect(conn, hdr);
+ 
+-	start = lpfc_hbq_defs[hbqno]->buffer_count;
+-	end = count + lpfc_hbq_defs[hbqno]->buffer_count;
++	start = phba->hbqs[hbqno].buffer_count;
++	end = count + start;
+ 	if (end > lpfc_hbq_defs[hbqno]->entry_count) {
+ 		end = lpfc_hbq_defs[hbqno]->entry_count;
+ 	}
+@@ -646,7 +622,7 @@ lpfc_sli_hbqbuf_fill_hbqs(struct lpfc_hba *phba, uint32_t hbqno, uint32_t count)
+ 			return 1;
+ 		hbq_buffer->tag = (i | (hbqno << 16));
+ 		if (lpfc_sli_hbq_to_firmware(phba, hbqno, hbq_buffer))
+-			lpfc_hbq_defs[hbqno]->buffer_count++;
++			phba->hbqs[hbqno].buffer_count++;
+ 		else
+ 			(phba->hbqs[hbqno].hbq_free_buffer)(phba, hbq_buffer);
+ 	}
+@@ -660,14 +636,14 @@ lpfc_sli_hbqbuf_add_hbqs(struct lpfc_hba *phba, uint32_t qno)
+ 					 lpfc_hbq_defs[qno]->add_count));
  }
  
- /**
-- * iscsi_tcp_data_recv - TCP receive in sendfile fashion
-+ * iscsi_tcp_recv - TCP receive in sendfile fashion
-  * @rd_desc: read descriptor
-  * @skb: socket buffer
-  * @offset: offset in skb
-  * @len: skb->len - offset
-  **/
- static int
--iscsi_tcp_data_recv(read_descriptor_t *rd_desc, struct sk_buff *skb,
--		unsigned int offset, size_t len)
-+iscsi_tcp_recv(read_descriptor_t *rd_desc, struct sk_buff *skb,
-+	       unsigned int offset, size_t len)
+-int
++static int
+ lpfc_sli_hbqbuf_init_hbqs(struct lpfc_hba *phba, uint32_t qno)
  {
--	int rc;
- 	struct iscsi_conn *conn = rd_desc->arg.data;
- 	struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
--	int processed;
--	char pad[ISCSI_PAD_LEN];
--	struct scatterlist sg;
--
--	/*
--	 * Save current SKB and its offset in the corresponding
--	 * connection context.
--	 */
--	tcp_conn->in.copy = skb->len - offset;
--	tcp_conn->in.offset = offset;
--	tcp_conn->in.skb = skb;
--	tcp_conn->in.len = tcp_conn->in.copy;
--	BUG_ON(tcp_conn->in.copy <= 0);
--	debug_tcp("in %d bytes\n", tcp_conn->in.copy);
-+	struct iscsi_segment *segment = &tcp_conn->in.segment;
-+	struct skb_seq_state seq;
-+	unsigned int consumed = 0;
-+	int rc = 0;
- 
--more:
--	tcp_conn->in.copied = 0;
--	rc = 0;
-+	debug_tcp("in %d bytes\n", skb->len - offset);
+ 	return(lpfc_sli_hbqbuf_fill_hbqs(phba, qno,
+ 					 lpfc_hbq_defs[qno]->init_count));
+ }
  
- 	if (unlikely(conn->suspend_rx)) {
- 		debug_tcp("conn %d Rx suspended!\n", conn->id);
- 		return 0;
+-struct hbq_dmabuf *
++static struct hbq_dmabuf *
+ lpfc_sli_hbqbuf_find(struct lpfc_hba *phba, uint32_t tag)
+ {
+ 	struct lpfc_dmabuf *d_buf;
+@@ -686,7 +662,7 @@ lpfc_sli_hbqbuf_find(struct lpfc_hba *phba, uint32_t tag)
  	}
+ 	lpfc_printf_log(phba, KERN_ERR, LOG_SLI | LOG_VPORT,
+ 			"1803 Bad hbq tag. Data: x%x x%x\n",
+-			tag, lpfc_hbq_defs[tag >> 16]->buffer_count);
++			tag, phba->hbqs[tag >> 16].buffer_count);
+ 	return NULL;
+ }
  
--	if (tcp_conn->in_progress == IN_PROGRESS_WAIT_HEADER ||
--	    tcp_conn->in_progress == IN_PROGRESS_HEADER_GATHER) {
--		rc = iscsi_hdr_extract(tcp_conn);
--		if (rc) {
--		       if (rc == -EAGAIN)
--				goto nomore;
--		       else {
--				iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
--				return 0;
--		       }
--		}
-+	skb_prepare_seq_read(skb, offset, skb->len, &seq);
-+	while (1) {
-+		unsigned int avail;
-+		const u8 *ptr;
+@@ -712,6 +688,7 @@ lpfc_sli_chk_mbx_command(uint8_t mbxCommand)
+ 	case MBX_LOAD_SM:
+ 	case MBX_READ_NV:
+ 	case MBX_WRITE_NV:
++	case MBX_WRITE_VPARMS:
+ 	case MBX_RUN_BIU_DIAG:
+ 	case MBX_INIT_LINK:
+ 	case MBX_DOWN_LINK:
+@@ -739,7 +716,7 @@ lpfc_sli_chk_mbx_command(uint8_t mbxCommand)
+ 	case MBX_DEL_LD_ENTRY:
+ 	case MBX_RUN_PROGRAM:
+ 	case MBX_SET_MASK:
+-	case MBX_SET_SLIM:
++	case MBX_SET_VARIABLE:
+ 	case MBX_UNREG_D_ID:
+ 	case MBX_KILL_BOARD:
+ 	case MBX_CONFIG_FARP:
+@@ -751,9 +728,10 @@ lpfc_sli_chk_mbx_command(uint8_t mbxCommand)
+ 	case MBX_READ_RPI64:
+ 	case MBX_REG_LOGIN64:
+ 	case MBX_READ_LA64:
+-	case MBX_FLASH_WR_ULA:
++	case MBX_WRITE_WWN:
+ 	case MBX_SET_DEBUG:
+ 	case MBX_LOAD_EXP_ROM:
++	case MBX_ASYNCEVT_ENABLE:
+ 	case MBX_REG_VPI:
+ 	case MBX_UNREG_VPI:
+ 	case MBX_HEARTBEAT:
+@@ -953,6 +931,17 @@ lpfc_sli_replace_hbqbuff(struct lpfc_hba *phba, uint32_t tag)
+ 	return &new_hbq_entry->dbuf;
+ }
  
--		/*
--		 * Verify and process incoming PDU header.
--		 */
--		rc = iscsi_tcp_hdr_recv(conn);
--		if (!rc && tcp_conn->in.datalen) {
--			if (conn->datadgst_en)
--				crypto_hash_init(&tcp_conn->rx_hash);
--			tcp_conn->in_progress = IN_PROGRESS_DATA_RECV;
--		} else if (rc) {
--			iscsi_conn_failure(conn, rc);
--			return 0;
-+		avail = skb_seq_read(consumed, &ptr, &seq);
-+		if (avail == 0) {
-+			debug_tcp("no more data avail. Consumed %d\n",
-+				  consumed);
-+			break;
- 		}
--	}
--
--	if (tcp_conn->in_progress == IN_PROGRESS_DDIGEST_RECV &&
--	    tcp_conn->in.copy) {
--		uint32_t recv_digest;
--
--		debug_tcp("extra data_recv offset %d copy %d\n",
--			  tcp_conn->in.offset, tcp_conn->in.copy);
--
--		if (!tcp_conn->data_copied) {
--			if (tcp_conn->in.padding) {
--				debug_tcp("padding -> %d\n",
--					  tcp_conn->in.padding);
--				memset(pad, 0, tcp_conn->in.padding);
--				sg_init_one(&sg, pad, tcp_conn->in.padding);
--				crypto_hash_update(&tcp_conn->rx_hash,
--						   &sg, sg.length);
-+		BUG_ON(segment->copied >= segment->size);
++static struct lpfc_dmabuf *
++lpfc_sli_get_buff(struct lpfc_hba *phba,
++			struct lpfc_sli_ring *pring,
++			uint32_t tag)
++{
++	if (tag & QUE_BUFTAG_BIT)
++		return lpfc_sli_ring_taggedbuf_get(phba, pring, tag);
++	else
++		return lpfc_sli_replace_hbqbuff(phba, tag);
++}
 +
-+		debug_tcp("skb %p ptr=%p avail=%u\n", skb, ptr, avail);
-+		rc = iscsi_tcp_segment_recv(tcp_conn, segment, ptr, avail);
-+		BUG_ON(rc == 0);
-+		consumed += rc;
+ static int
+ lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
+ 			    struct lpfc_iocbq *saveq)
+@@ -961,19 +950,112 @@ lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
+ 	WORD5            * w5p;
+ 	uint32_t           Rctl, Type;
+ 	uint32_t           match, i;
++	struct lpfc_iocbq *iocbq;
+ 
+ 	match = 0;
+ 	irsp = &(saveq->iocb);
+-	if ((irsp->ulpCommand == CMD_RCV_ELS_REQ64_CX)
+-	    || (irsp->ulpCommand == CMD_RCV_ELS_REQ_CX)
+-	    || (irsp->ulpCommand == CMD_IOCB_RCV_ELS64_CX)
+-	    || (irsp->ulpCommand == CMD_IOCB_RCV_CONT64_CX)) {
 +
-+		if (segment->total_copied >= segment->total_size) {
-+			debug_tcp("segment done\n");
-+			rc = segment->done(tcp_conn, segment);
-+			if (rc != 0) {
-+				skb_abort_seq_read(&seq);
-+				goto error;
- 			}
--			crypto_hash_final(&tcp_conn->rx_hash,
--					  (u8 *) &tcp_conn->in.datadgst);
--			debug_tcp("rx digest 0x%x\n", tcp_conn->in.datadgst);
--		}
++	if (irsp->ulpStatus == IOSTAT_NEED_BUFFER)
++		return 1;
++	if (irsp->ulpCommand == CMD_ASYNC_STATUS) {
++		if (pring->lpfc_sli_rcv_async_status)
++			pring->lpfc_sli_rcv_async_status(phba, pring, saveq);
++		else
++			lpfc_printf_log(phba,
++					KERN_WARNING,
++					LOG_SLI,
++					"0316 Ring %d handler: unexpected "
++					"ASYNC_STATUS iocb received evt_code "
++					"0x%x\n",
++					pring->ringno,
++					irsp->un.asyncstat.evt_code);
++		return 1;
++	}
++
++	if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) {
++		if (irsp->ulpBdeCount != 0) {
++			saveq->context2 = lpfc_sli_get_buff(phba, pring,
++						irsp->un.ulpWord[3]);
++			if (!saveq->context2)
++				lpfc_printf_log(phba,
++					KERN_ERR,
++					LOG_SLI,
++					"0341 Ring %d Cannot find buffer for "
++					"an unsolicited iocb. tag 0x%x\n",
++					pring->ringno,
++					irsp->un.ulpWord[3]);
++		}
++		if (irsp->ulpBdeCount == 2) {
++			saveq->context3 = lpfc_sli_get_buff(phba, pring,
++						irsp->unsli3.sli3Words[7]);
++			if (!saveq->context3)
++				lpfc_printf_log(phba,
++					KERN_ERR,
++					LOG_SLI,
++					"0342 Ring %d Cannot find buffer for an"
++					" unsolicited iocb. tag 0x%x\n",
++					pring->ringno,
++					irsp->unsli3.sli3Words[7]);
++		}
++		list_for_each_entry(iocbq, &saveq->list, list) {
++			irsp = &(iocbq->iocb);
++			if (irsp->ulpBdeCount != 0) {
++				iocbq->context2 = lpfc_sli_get_buff(phba, pring,
++							irsp->un.ulpWord[3]);
++				if (!iocbq->context2)
++					lpfc_printf_log(phba,
++						KERN_ERR,
++						LOG_SLI,
++						"0343 Ring %d Cannot find "
++						"buffer for an unsolicited iocb"
++						". tag 0x%x\n", pring->ringno,
++						irsp->un.ulpWord[3]);
++			}
++			if (irsp->ulpBdeCount == 2) {
++				iocbq->context3 = lpfc_sli_get_buff(phba, pring,
++						irsp->unsli3.sli3Words[7]);
++				if (!iocbq->context3)
++					lpfc_printf_log(phba,
++						KERN_ERR,
++						LOG_SLI,
++						"0344 Ring %d Cannot find "
++						"buffer for an unsolicited "
++						"iocb. tag 0x%x\n",
++						pring->ringno,
++						irsp->unsli3.sli3Words[7]);
++			}
++		}
++	}
++	if (irsp->ulpBdeCount != 0 &&
++	    (irsp->ulpCommand == CMD_IOCB_RCV_CONT64_CX ||
++	     irsp->ulpStatus == IOSTAT_INTERMED_RSP)) {
++		int found = 0;
++
++		/* search continue save q for same XRI */
++		list_for_each_entry(iocbq, &pring->iocb_continue_saveq, clist) {
++			if (iocbq->iocb.ulpContext == saveq->iocb.ulpContext) {
++				list_add_tail(&saveq->list, &iocbq->list);
++				found = 1;
++				break;
++			}
++		}
++		if (!found)
++			list_add_tail(&saveq->clist,
++				      &pring->iocb_continue_saveq);
++		if (saveq->iocb.ulpStatus != IOSTAT_INTERMED_RSP) {
++			list_del_init(&iocbq->clist);
++			saveq = iocbq;
++			irsp = &(saveq->iocb);
++		} else
++			return 0;
++	}
++	if ((irsp->ulpCommand == CMD_RCV_ELS_REQ64_CX) ||
++	    (irsp->ulpCommand == CMD_RCV_ELS_REQ_CX) ||
++	    (irsp->ulpCommand == CMD_IOCB_RCV_ELS64_CX)) {
+ 		Rctl = FC_ELS_REQ;
+ 		Type = FC_ELS_DATA;
+ 	} else {
+-		w5p =
+-		    (WORD5 *) & (saveq->iocb.un.
+-				 ulpWord[5]);
++		w5p = (WORD5 *)&(saveq->iocb.un.ulpWord[5]);
+ 		Rctl = w5p->hcsw.Rctl;
+ 		Type = w5p->hcsw.Type;
  
--		rc = iscsi_tcp_copy(conn, sizeof(uint32_t));
--		if (rc) {
--			if (rc == -EAGAIN)
--				goto again;
--			iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
--			return 0;
--		}
--
--		memcpy(&recv_digest, conn->data, sizeof(uint32_t));
--		if (recv_digest != tcp_conn->in.datadgst) {
--			debug_tcp("iscsi_tcp: data digest error!"
--				  "0x%x != 0x%x\n", recv_digest,
--				  tcp_conn->in.datadgst);
--			iscsi_conn_failure(conn, ISCSI_ERR_DATA_DGST);
--			return 0;
--		} else {
--			debug_tcp("iscsi_tcp: data digest match!"
--				  "0x%x == 0x%x\n", recv_digest,
--				  tcp_conn->in.datadgst);
--			tcp_conn->in_progress = IN_PROGRESS_WAIT_HEADER;
-+			/* The done() functions sets up the
-+			 * next segment. */
+@@ -988,15 +1070,6 @@ lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
  		}
  	}
-+	skb_abort_seq_read(&seq);
-+	conn->rxdata_octets += consumed;
-+	return consumed;
  
--	if (tcp_conn->in_progress == IN_PROGRESS_DATA_RECV &&
--	    tcp_conn->in.copy) {
--		debug_tcp("data_recv offset %d copy %d\n",
--		       tcp_conn->in.offset, tcp_conn->in.copy);
--
--		rc = iscsi_data_recv(conn);
--		if (rc) {
--			if (rc == -EAGAIN)
--				goto again;
--			iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
--			return 0;
--		}
--
--		if (tcp_conn->in.padding)
--			tcp_conn->in_progress = IN_PROGRESS_PAD_RECV;
--		else if (conn->datadgst_en)
--			tcp_conn->in_progress = IN_PROGRESS_DDIGEST_RECV;
--		else
--			tcp_conn->in_progress = IN_PROGRESS_WAIT_HEADER;
--		tcp_conn->data_copied = 0;
--	}
--
--	if (tcp_conn->in_progress == IN_PROGRESS_PAD_RECV &&
--	    tcp_conn->in.copy) {
--		int copylen = min(tcp_conn->in.padding - tcp_conn->data_copied,
--				  tcp_conn->in.copy);
--
--		tcp_conn->in.copy -= copylen;
--		tcp_conn->in.offset += copylen;
--		tcp_conn->data_copied += copylen;
--
--		if (tcp_conn->data_copied != tcp_conn->in.padding)
--			tcp_conn->in_progress = IN_PROGRESS_PAD_RECV;
--		else if (conn->datadgst_en)
--			tcp_conn->in_progress = IN_PROGRESS_DDIGEST_RECV;
--		else
--			tcp_conn->in_progress = IN_PROGRESS_WAIT_HEADER;
--		tcp_conn->data_copied = 0;
--	}
--
--	debug_tcp("f, processed %d from out of %d padding %d\n",
--	       tcp_conn->in.offset - offset, (int)len, tcp_conn->in.padding);
--	BUG_ON(tcp_conn->in.offset - offset > len);
--
--	if (tcp_conn->in.offset - offset != len) {
--		debug_tcp("continue to process %d bytes\n",
--		       (int)len - (tcp_conn->in.offset - offset));
--		goto more;
+-	if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) {
+-		if (irsp->ulpBdeCount != 0)
+-			saveq->context2 = lpfc_sli_replace_hbqbuff(phba,
+-						irsp->un.ulpWord[3]);
+-		if (irsp->ulpBdeCount == 2)
+-			saveq->context3 = lpfc_sli_replace_hbqbuff(phba,
+-						irsp->unsli3.sli3Words[7]);
 -	}
 -
--nomore:
--	processed = tcp_conn->in.offset - offset;
--	BUG_ON(processed == 0);
--	return processed;
--
--again:
--	processed = tcp_conn->in.offset - offset;
--	debug_tcp("c, processed %d from out of %d rd_desc_cnt %d\n",
--	          processed, (int)len, (int)rd_desc->count);
--	BUG_ON(processed == 0);
--	BUG_ON(processed > len);
--
--	conn->rxdata_octets += processed;
--	return processed;
-+error:
-+	debug_tcp("Error receiving PDU, errno=%d\n", rc);
-+	iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
-+	return 0;
- }
+ 	/* unSolicited Responses */
+ 	if (pring->prt[0].profile) {
+ 		if (pring->prt[0].lpfc_sli_rcv_unsol_event)
+@@ -1006,12 +1079,9 @@ lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
+ 	} else {
+ 		/* We must search, based on rctl / type
+ 		   for the right routine */
+-		for (i = 0; i < pring->num_mask;
+-		     i++) {
+-			if ((pring->prt[i].rctl ==
+-			     Rctl)
+-			    && (pring->prt[i].
+-				type == Type)) {
++		for (i = 0; i < pring->num_mask; i++) {
++			if ((pring->prt[i].rctl == Rctl)
++			    && (pring->prt[i].type == Type)) {
+ 				if (pring->prt[i].lpfc_sli_rcv_unsol_event)
+ 					(pring->prt[i].lpfc_sli_rcv_unsol_event)
+ 							(phba, pring, saveq);
+@@ -1084,6 +1154,12 @@ lpfc_sli_process_sol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
+ 						IOSTAT_LOCAL_REJECT;
+ 					saveq->iocb.un.ulpWord[4] =
+ 						IOERR_SLI_ABORTED;
++
++					/* Firmware could still be in progress
++					 * of DMAing payload, so don't free data
++					 * buffer till after a hbeat.
++					 */
++					saveq->iocb_flag |= LPFC_DELAY_MEM_FREE;
+ 				}
+ 			}
+ 			(cmdiocbp->iocb_cmpl) (phba, cmdiocbp, saveq);
+@@ -1572,12 +1648,7 @@ lpfc_sli_handle_slow_ring_event(struct lpfc_hba *phba,
  
- static void
- iscsi_tcp_data_ready(struct sock *sk, int flag)
- {
- 	struct iscsi_conn *conn = sk->sk_user_data;
-+	struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
- 	read_descriptor_t rd_desc;
+ 		writel(pring->rspidx, &phba->host_gp[pring->ringno].rspGetInx);
  
- 	read_lock(&sk->sk_callback_lock);
+-		if (list_empty(&(pring->iocb_continueq))) {
+-			list_add(&rspiocbp->list, &(pring->iocb_continueq));
+-		} else {
+-			list_add_tail(&rspiocbp->list,
+-				      &(pring->iocb_continueq));
+-		}
++		list_add_tail(&rspiocbp->list, &(pring->iocb_continueq));
+ 
+ 		pring->iocb_continueq_cnt++;
+ 		if (irsp->ulpLe) {
+@@ -1642,17 +1713,17 @@ lpfc_sli_handle_slow_ring_event(struct lpfc_hba *phba,
+ 			iocb_cmd_type = irsp->ulpCommand & CMD_IOCB_MASK;
+ 			type = lpfc_sli_iocb_cmd_type(iocb_cmd_type);
+ 			if (type == LPFC_SOL_IOCB) {
+-				spin_unlock_irqrestore(&phba->hbalock,
+-						       iflag);
++				spin_unlock_irqrestore(&phba->hbalock, iflag);
+ 				rc = lpfc_sli_process_sol_iocb(phba, pring,
+ 							       saveq);
+ 				spin_lock_irqsave(&phba->hbalock, iflag);
+ 			} else if (type == LPFC_UNSOL_IOCB) {
+-				spin_unlock_irqrestore(&phba->hbalock,
+-						       iflag);
++				spin_unlock_irqrestore(&phba->hbalock, iflag);
+ 				rc = lpfc_sli_process_unsol_iocb(phba, pring,
+ 								 saveq);
+ 				spin_lock_irqsave(&phba->hbalock, iflag);
++				if (!rc)
++					free_saveq = 0;
+ 			} else if (type == LPFC_ABORT_IOCB) {
+ 				if ((irsp->ulpCommand != CMD_XRI_ABORTED_CX) &&
+ 				    ((cmdiocbp =
+@@ -1921,8 +1992,8 @@ lpfc_sli_brdkill(struct lpfc_hba *phba)
+ 			"0329 Kill HBA Data: x%x x%x\n",
+ 			phba->pport->port_state, psli->sli_flag);
+ 
+-	if ((pmb = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool,
+-						  GFP_KERNEL)) == 0)
++	pmb = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
++	if (!pmb)
+ 		return 1;
+ 
+ 	/* Disable the error attention */
+@@ -2113,7 +2184,10 @@ lpfc_sli_chipset_init(struct lpfc_hba *phba)
+ 			   <status> */
+ 			lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ 					"0436 Adapter failed to init, "
+-					"timeout, status reg x%x\n", status);
++					"timeout, status reg x%x, "
++					"FW Data: A8 x%x AC x%x\n", status,
++					readl(phba->MBslimaddr + 0xa8),
++					readl(phba->MBslimaddr + 0xac));
+ 			phba->link_state = LPFC_HBA_ERROR;
+ 			return -ETIMEDOUT;
+ 		}
+@@ -2125,7 +2199,10 @@ lpfc_sli_chipset_init(struct lpfc_hba *phba)
+ 			   <status> */
+ 			lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ 					"0437 Adapter failed to init, "
+-					"chipset, status reg x%x\n", status);
++					"chipset, status reg x%x, "
++					"FW Data: A8 x%x AC x%x\n", status,
++					readl(phba->MBslimaddr + 0xa8),
++					readl(phba->MBslimaddr + 0xac));
+ 			phba->link_state = LPFC_HBA_ERROR;
+ 			return -EIO;
+ 		}
+@@ -2153,7 +2230,10 @@ lpfc_sli_chipset_init(struct lpfc_hba *phba)
+ 		/* Adapter failed to init, chipset, status reg <status> */
+ 		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ 				"0438 Adapter failed to init, chipset, "
+-				"status reg x%x\n", status);
++				"status reg x%x, "
++				"FW Data: A8 x%x AC x%x\n", status,
++				readl(phba->MBslimaddr + 0xa8),
++				readl(phba->MBslimaddr + 0xac));
+ 		phba->link_state = LPFC_HBA_ERROR;
+ 		return -EIO;
+ 	}
+@@ -2485,11 +2565,16 @@ lpfc_mbox_timeout_handler(struct lpfc_hba *phba)
+ 	lpfc_sli_abort_iocb_ring(phba, pring);
  
+ 	lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
+-			"0316 Resetting board due to mailbox timeout\n");
++			"0345 Resetting board due to mailbox timeout\n");
  	/*
--	 * Use rd_desc to pass 'conn' to iscsi_tcp_data_recv.
-+	 * Use rd_desc to pass 'conn' to iscsi_tcp_recv.
- 	 * We set count to 1 because we want the network layer to
--	 * hand us all the skbs that are available. iscsi_tcp_data_recv
-+	 * hand us all the skbs that are available. iscsi_tcp_recv
- 	 * handled pdus that cross buffers or pdus that still need data.
+ 	 * lpfc_offline calls lpfc_sli_hba_down which will clean up
+ 	 * on oustanding mailbox commands.
  	 */
- 	rd_desc.arg.data = conn;
- 	rd_desc.count = 1;
--	tcp_read_sock(sk, &rd_desc, iscsi_tcp_data_recv);
-+	tcp_read_sock(sk, &rd_desc, iscsi_tcp_recv);
- 
- 	read_unlock(&sk->sk_callback_lock);
-+
-+	/* If we had to (atomically) map a highmem page,
-+	 * unmap it now. */
-+	iscsi_tcp_segment_unmap(&tcp_conn->in.segment);
- }
++	/* If resets are disabled then set error state and return. */
++	if (!phba->cfg_enable_hba_reset) {
++		phba->link_state = LPFC_HBA_ERROR;
++		return;
++	}
+ 	lpfc_offline_prep(phba);
+ 	lpfc_offline(phba);
+ 	lpfc_sli_brdrestart(phba);
+@@ -2507,6 +2592,7 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag)
+ 	uint32_t status, evtctr;
+ 	uint32_t ha_copy;
+ 	int i;
++	unsigned long timeout;
+ 	unsigned long drvr_flag = 0;
+ 	volatile uint32_t word0, ldata;
+ 	void __iomem *to_slim;
+@@ -2519,7 +2605,7 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag)
+ 					"1806 Mbox x%x failed. No vport\n",
+ 					pmbox->mb.mbxCommand);
+ 			dump_stack();
+-			return MBXERR_ERROR;
++			return MBX_NOT_FINISHED;
+ 		}
+ 	}
  
- static void
-@@ -1077,121 +1079,173 @@ iscsi_conn_restore_callbacks(struct iscsi_tcp_conn *tcp_conn)
- }
+@@ -2571,21 +2657,6 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag)
+ 			return MBX_NOT_FINISHED;
+ 		}
  
- /**
-- * iscsi_send - generic send routine
-- * @sk: kernel's socket
-- * @buf: buffer to write from
-- * @size: actual size to write
-- * @flags: socket's flags
-- */
--static inline int
--iscsi_send(struct iscsi_conn *conn, struct iscsi_buf *buf, int size, int flags)
-+ * iscsi_xmit - TCP transmit
-+ **/
-+static int
-+iscsi_xmit(struct iscsi_conn *conn)
- {
- 	struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
--	struct socket *sk = tcp_conn->sock;
--	int offset = buf->sg.offset + buf->sent, res;
-+	struct iscsi_segment *segment = &tcp_conn->out.segment;
-+	unsigned int consumed = 0;
-+	int rc = 0;
+-		/* Handle STOP IOCB processing flag. This is only meaningful
+-		 * if we are not polling for mbox completion.
+-		 */
+-		if (flag & MBX_STOP_IOCB) {
+-			flag &= ~MBX_STOP_IOCB;
+-			/* Now flag each ring */
+-			for (i = 0; i < psli->num_rings; i++) {
+-				/* If the ring is active, flag it */
+-				if (psli->ring[i].cmdringaddr) {
+-					psli->ring[i].flag |=
+-					    LPFC_STOP_IOCB_MBX;
+-				}
+-			}
+-		}
+-
+ 		/* Another mailbox command is still being processed, queue this
+ 		 * command to be processed later.
+ 		 */
+@@ -2620,23 +2691,6 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag)
+ 		return MBX_BUSY;
+ 	}
  
--	/*
--	 * if we got use_sg=0 or are sending something we kmallocd
--	 * then we did not have to do kmap (kmap returns page_address)
--	 *
--	 * if we got use_sg > 0, but had to drop down, we do not
--	 * set clustering so this should only happen for that
--	 * slab case.
+-	/* Handle STOP IOCB processing flag. This is only meaningful
+-	 * if we are not polling for mbox completion.
 -	 */
--	if (buf->use_sendmsg)
--		res = sock_no_sendpage(sk, sg_page(&buf->sg), offset, size, flags);
--	else
--		res = tcp_conn->sendpage(sk, sg_page(&buf->sg), offset, size, flags);
+-	if (flag & MBX_STOP_IOCB) {
+-		flag &= ~MBX_STOP_IOCB;
+-		if (flag == MBX_NOWAIT) {
+-			/* Now flag each ring */
+-			for (i = 0; i < psli->num_rings; i++) {
+-				/* If the ring is active, flag it */
+-				if (psli->ring[i].cmdringaddr) {
+-					psli->ring[i].flag |=
+-					    LPFC_STOP_IOCB_MBX;
+-				}
+-			}
+-		}
+-	}
 -
--	if (res >= 0) {
--		conn->txdata_octets += res;
--		buf->sent += res;
--		return res;
-+	while (1) {
-+		rc = iscsi_tcp_xmit_segment(tcp_conn, segment);
-+		if (rc < 0)
-+			goto error;
-+		if (rc == 0)
-+			break;
-+
-+		consumed += rc;
-+
-+		if (segment->total_copied >= segment->total_size) {
-+			if (segment->done != NULL) {
-+				rc = segment->done(tcp_conn, segment);
-+				if (rc < 0)
-+					goto error;
-+			}
-+		}
+ 	psli->sli_flag |= LPFC_SLI_MBOX_ACTIVE;
+ 
+ 	/* If we are not polling, we MUST be in SLI2 mode */
+@@ -2714,18 +2768,24 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag)
  	}
  
--	tcp_conn->sendpage_failures_cnt++;
--	if (res == -EAGAIN)
--		res = -ENOBUFS;
--	else
--		iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
--	return res;
-+	debug_tcp("xmit %d bytes\n", consumed);
-+
-+	conn->txdata_octets += consumed;
-+	return consumed;
+ 	wmb();
+-	/* interrupt board to doit right away */
+-	writel(CA_MBATT, phba->CAregaddr);
+-	readl(phba->CAregaddr); /* flush */
+ 
+ 	switch (flag) {
+ 	case MBX_NOWAIT:
+-		/* Don't wait for it to finish, just return */
++		/* Set up reference to mailbox command */
+ 		psli->mbox_active = pmbox;
++		/* Interrupt board to do it */
++		writel(CA_MBATT, phba->CAregaddr);
++		readl(phba->CAregaddr); /* flush */
++		/* Don't wait for it to finish, just return */
+ 		break;
+ 
+ 	case MBX_POLL:
++		/* Set up null reference to mailbox command */
+ 		psli->mbox_active = NULL;
++		/* Interrupt board to do it */
++		writel(CA_MBATT, phba->CAregaddr);
++		readl(phba->CAregaddr); /* flush */
 +
-+error:
-+	/* Transmit error. We could initiate error recovery
-+	 * here. */
-+	debug_tcp("Error sending PDU, errno=%d\n", rc);
-+	iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
-+	return rc;
- }
+ 		if (psli->sli_flag & LPFC_SLI2_ACTIVE) {
+ 			/* First read mbox status word */
+ 			word0 = *((volatile uint32_t *)&phba->slim2p->mbx);
+@@ -2737,15 +2797,15 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag)
  
- /**
-- * iscsi_sendhdr - send PDU Header via tcp_sendpage()
-- * @conn: iscsi connection
-- * @buf: buffer to write from
-- * @datalen: lenght of data to be sent after the header
-- *
-- * Notes:
-- *	(Tx, Fast Path)
-- **/
-+ * iscsi_tcp_xmit_qlen - return the number of bytes queued for xmit
-+ */
- static inline int
--iscsi_sendhdr(struct iscsi_conn *conn, struct iscsi_buf *buf, int datalen)
-+iscsi_tcp_xmit_qlen(struct iscsi_conn *conn)
- {
--	int flags = 0; /* MSG_DONTWAIT; */
--	int res, size;
+ 		/* Read the HBA Host Attention Register */
+ 		ha_copy = readl(phba->HAregaddr);
 -
--	size = buf->sg.length - buf->sent;
--	BUG_ON(buf->sent + size > buf->sg.length);
--	if (buf->sent + size != buf->sg.length || datalen)
--		flags |= MSG_MORE;
+-		i = lpfc_mbox_tmo_val(phba, mb->mbxCommand);
+-		i *= 1000; /* Convert to ms */
 -
--	res = iscsi_send(conn, buf, size, flags);
--	debug_tcp("sendhdr %d bytes, sent %d res %d\n", size, buf->sent, res);
--	if (res >= 0) {
--		if (size != res)
--			return -EAGAIN;
--		return 0;
--	}
-+	struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
-+	struct iscsi_segment *segment = &tcp_conn->out.segment;
- 
--	return res;
-+	return segment->total_copied - segment->total_size;
- }
++		timeout = msecs_to_jiffies(lpfc_mbox_tmo_val(phba,
++							     mb->mbxCommand) *
++					   1000) + jiffies;
++		i = 0;
+ 		/* Wait for command to complete */
+ 		while (((word0 & OWN_CHIP) == OWN_CHIP) ||
+ 		       (!(ha_copy & HA_MBATT) &&
+ 			(phba->link_state > LPFC_WARM_START))) {
+-			if (i-- <= 0) {
++			if (time_after(jiffies, timeout)) {
+ 				psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
+ 				spin_unlock_irqrestore(&phba->hbalock,
+ 						       drvr_flag);
+@@ -2758,12 +2818,12 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag)
+ 			    && (evtctr != psli->slistat.mbox_event))
+ 				break;
  
--/**
-- * iscsi_sendpage - send one page of iSCSI Data-Out.
-- * @conn: iscsi connection
-- * @buf: buffer to write from
-- * @count: remaining data
-- * @sent: number of bytes sent
-- *
-- * Notes:
-- *	(Tx, Fast Path)
-- **/
- static inline int
--iscsi_sendpage(struct iscsi_conn *conn, struct iscsi_buf *buf,
--	       int *count, int *sent)
-+iscsi_tcp_flush(struct iscsi_conn *conn)
- {
--	int flags = 0; /* MSG_DONTWAIT; */
--	int res, size;
+-			spin_unlock_irqrestore(&phba->hbalock,
+-					       drvr_flag);
 -
--	size = buf->sg.length - buf->sent;
--	BUG_ON(buf->sent + size > buf->sg.length);
--	if (size > *count)
--		size = *count;
--	if (buf->sent + size != buf->sg.length || *count != size)
--		flags |= MSG_MORE;
+-			msleep(1);
 -
--	res = iscsi_send(conn, buf, size, flags);
--	debug_tcp("sendpage: %d bytes, sent %d left %d sent %d res %d\n",
--		  size, buf->sent, *count, *sent, res);
--	if (res >= 0) {
--		*count -= res;
--		*sent += res;
--		if (size != res)
-+	int rc;
-+
-+	while (iscsi_tcp_xmit_qlen(conn)) {
-+		rc = iscsi_xmit(conn);
-+		if (rc == 0)
- 			return -EAGAIN;
--		return 0;
-+		if (rc < 0)
-+			return rc;
- 	}
+-			spin_lock_irqsave(&phba->hbalock, drvr_flag);
++			if (i++ > 10) {
++				spin_unlock_irqrestore(&phba->hbalock,
++						       drvr_flag);
++				msleep(1);
++				spin_lock_irqsave(&phba->hbalock, drvr_flag);
++			}
  
--	return res;
-+	return 0;
+ 			if (psli->sli_flag & LPFC_SLI2_ACTIVE) {
+ 				/* First copy command data */
+@@ -2848,7 +2908,7 @@ lpfc_sli_next_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
+ /*
+  * Lockless version of lpfc_sli_issue_iocb.
+  */
+-int
++static int
+ __lpfc_sli_issue_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
+ 		    struct lpfc_iocbq *piocb, uint32_t flag)
+ {
+@@ -2879,9 +2939,9 @@ __lpfc_sli_issue_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
+ 
+ 	/*
+ 	 * Check to see if we are blocking IOCB processing because of a
+-	 * outstanding mbox command.
++	 * outstanding event.
+ 	 */
+-	if (unlikely(pring->flag & LPFC_STOP_IOCB_MBX))
++	if (unlikely(pring->flag & LPFC_STOP_IOCB_EVENT))
+ 		goto iocb_busy;
+ 
+ 	if (unlikely(phba->link_state == LPFC_LINK_DOWN)) {
+@@ -2993,6 +3053,61 @@ lpfc_extra_ring_setup( struct lpfc_hba *phba)
+ 	return 0;
  }
  
--static inline void
--iscsi_data_digest_init(struct iscsi_tcp_conn *tcp_conn,
--		      struct iscsi_tcp_cmd_task *tcp_ctask)
-+/*
-+ * This is called when we're done sending the header.
-+ * Simply copy the data_segment to the send segment, and return.
-+ */
-+static int
-+iscsi_tcp_send_hdr_done(struct iscsi_tcp_conn *tcp_conn,
-+			struct iscsi_segment *segment)
-+{
-+	tcp_conn->out.segment = tcp_conn->out.data_segment;
-+	debug_tcp("Header done. Next segment size %u total_size %u\n",
-+		  tcp_conn->out.segment.size, tcp_conn->out.segment.total_size);
-+	return 0;
-+}
-+
 +static void
-+iscsi_tcp_send_hdr_prep(struct iscsi_conn *conn, void *hdr, size_t hdrlen)
- {
--	crypto_hash_init(&tcp_conn->tx_hash);
--	tcp_ctask->digest_count = 4;
-+	struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
-+
-+	debug_tcp("%s(%p%s)\n", __FUNCTION__, tcp_conn,
-+			conn->hdrdgst_en? ", digest enabled" : "");
++lpfc_sli_async_event_handler(struct lpfc_hba * phba,
++	struct lpfc_sli_ring * pring, struct lpfc_iocbq * iocbq)
++{
++	IOCB_t *icmd;
++	uint16_t evt_code;
++	uint16_t temp;
++	struct temp_event temp_event_data;
++	struct Scsi_Host *shost;
 +
-+	/* Clear the data segment - needs to be filled in by the
-+	 * caller using iscsi_tcp_send_data_prep() */
-+	memset(&tcp_conn->out.data_segment, 0, sizeof(struct iscsi_segment));
++	icmd = &iocbq->iocb;
++	evt_code = icmd->un.asyncstat.evt_code;
++	temp = icmd->ulpContext;
 +
-+	/* If header digest is enabled, compute the CRC and
-+	 * place the digest into the same buffer. We make
-+	 * sure that both iscsi_tcp_ctask and mtask have
-+	 * sufficient room.
-+	 */
-+	if (conn->hdrdgst_en) {
-+		iscsi_tcp_dgst_header(&tcp_conn->tx_hash, hdr, hdrlen,
-+				      hdr + hdrlen);
-+		hdrlen += ISCSI_DIGEST_SIZE;
++	if ((evt_code != ASYNC_TEMP_WARN) &&
++		(evt_code != ASYNC_TEMP_SAFE)) {
++		lpfc_printf_log(phba,
++			KERN_ERR,
++			LOG_SLI,
++			"0346 Ring %d handler: unexpected ASYNC_STATUS"
++			" evt_code 0x%x\n",
++			pring->ringno,
++			icmd->un.asyncstat.evt_code);
++		return;
++	}
++	temp_event_data.data = (uint32_t)temp;
++	temp_event_data.event_type = FC_REG_TEMPERATURE_EVENT;
++	if (evt_code == ASYNC_TEMP_WARN) {
++		temp_event_data.event_code = LPFC_THRESHOLD_TEMP;
++		lpfc_printf_log(phba,
++				KERN_ERR,
++				LOG_TEMP,
++				"0347 Adapter is very hot, please take "
++				"corrective action. temperature : %d Celsius\n",
++				temp);
++	}
++	if (evt_code == ASYNC_TEMP_SAFE) {
++		temp_event_data.event_code = LPFC_NORMAL_TEMP;
++		lpfc_printf_log(phba,
++				KERN_ERR,
++				LOG_TEMP,
++				"0340 Adapter temperature is OK now. "
++				"temperature : %d Celsius\n",
++				temp);
 +	}
 +
-+	/* Remember header pointer for later, when we need
-+	 * to decide whether there's a payload to go along
-+	 * with the header. */
-+	tcp_conn->out.hdr = hdr;
++	/* Send temperature change event to applications */
++	shost = lpfc_shost_from_vport(phba->pport);
++	fc_host_post_vendor_event(shost, fc_get_event_number(),
++		sizeof(temp_event_data), (char *) &temp_event_data,
++		SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_EMULEX);
 +
-+	iscsi_segment_init_linear(&tcp_conn->out.segment, hdr, hdrlen,
-+				iscsi_tcp_send_hdr_done, NULL);
 +}
 +
-+/*
-+ * Prepare the send buffer for the payload data.
-+ * Padding and checksumming will all be taken care
-+ * of by the iscsi_segment routines.
-+ */
-+static int
-+iscsi_tcp_send_data_prep(struct iscsi_conn *conn, struct scatterlist *sg,
-+			 unsigned int count, unsigned int offset,
-+			 unsigned int len)
-+{
-+	struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
-+	struct hash_desc *tx_hash = NULL;
-+	unsigned int hdr_spec_len;
-+
-+	debug_tcp("%s(%p, offset=%d, datalen=%d%s)\n", __FUNCTION__,
-+			tcp_conn, offset, len,
-+			conn->datadgst_en? ", digest enabled" : "");
 +
-+	/* Make sure the datalen matches what the caller
-+	   said he would send. */
-+	hdr_spec_len = ntoh24(tcp_conn->out.hdr->dlength);
-+	WARN_ON(iscsi_padded(len) != iscsi_padded(hdr_spec_len));
+ int
+ lpfc_sli_setup(struct lpfc_hba *phba)
+ {
+@@ -3059,6 +3174,8 @@ lpfc_sli_setup(struct lpfc_hba *phba)
+ 			pring->fast_iotag = 0;
+ 			pring->iotag_ctr = 0;
+ 			pring->iotag_max = 4096;
++			pring->lpfc_sli_rcv_async_status =
++				lpfc_sli_async_event_handler;
+ 			pring->num_mask = 4;
+ 			pring->prt[0].profile = 0;	/* Mask 0 */
+ 			pring->prt[0].rctl = FC_ELS_REQ;
+@@ -3123,6 +3240,7 @@ lpfc_sli_queue_setup(struct lpfc_hba *phba)
+ 		INIT_LIST_HEAD(&pring->txq);
+ 		INIT_LIST_HEAD(&pring->txcmplq);
+ 		INIT_LIST_HEAD(&pring->iocb_continueq);
++		INIT_LIST_HEAD(&pring->iocb_continue_saveq);
+ 		INIT_LIST_HEAD(&pring->postbufq);
+ 	}
+ 	spin_unlock_irq(&phba->hbalock);
+@@ -3193,6 +3311,7 @@ lpfc_sli_hba_down(struct lpfc_hba *phba)
+ 	LIST_HEAD(completions);
+ 	struct lpfc_sli *psli = &phba->sli;
+ 	struct lpfc_sli_ring *pring;
++	struct lpfc_dmabuf *buf_ptr;
+ 	LPFC_MBOXQ_t *pmb;
+ 	struct lpfc_iocbq *iocb;
+ 	IOCB_t *cmd = NULL;
+@@ -3232,6 +3351,19 @@ lpfc_sli_hba_down(struct lpfc_hba *phba)
+ 		}
+ 	}
+ 
++	spin_lock_irqsave(&phba->hbalock, flags);
++	list_splice_init(&phba->elsbuf, &completions);
++	phba->elsbuf_cnt = 0;
++	phba->elsbuf_prev_cnt = 0;
++	spin_unlock_irqrestore(&phba->hbalock, flags);
 +
-+	if (conn->datadgst_en)
-+		tx_hash = &tcp_conn->tx_hash;
++	while (!list_empty(&completions)) {
++		list_remove_head(&completions, buf_ptr,
++			struct lpfc_dmabuf, list);
++		lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys);
++		kfree(buf_ptr);
++	}
 +
-+	return iscsi_segment_seek_sg(&tcp_conn->out.data_segment,
-+				   sg, count, offset, len,
-+				   NULL, tx_hash);
+ 	/* Return any active mbox cmds */
+ 	del_timer_sync(&psli->mbox_tmo);
+ 	spin_lock_irqsave(&phba->hbalock, flags);
+@@ -3294,6 +3426,47 @@ lpfc_sli_ringpostbuf_put(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
+ 	return 0;
+ }
+ 
++uint32_t
++lpfc_sli_get_buffer_tag(struct lpfc_hba *phba)
++{
++	spin_lock_irq(&phba->hbalock);
++	phba->buffer_tag_count++;
++	/*
++	 * Always set the QUE_BUFTAG_BIT to distiguish between
++	 * a tag assigned by HBQ.
++	 */
++	phba->buffer_tag_count |= QUE_BUFTAG_BIT;
++	spin_unlock_irq(&phba->hbalock);
++	return phba->buffer_tag_count;
 +}
 +
-+static void
-+iscsi_tcp_send_linear_data_prepare(struct iscsi_conn *conn, void *data,
-+				   size_t len)
++struct lpfc_dmabuf *
++lpfc_sli_ring_taggedbuf_get(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
++			uint32_t tag)
 +{
-+	struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
-+	struct hash_desc *tx_hash = NULL;
-+	unsigned int hdr_spec_len;
-+
-+	debug_tcp("%s(%p, datalen=%d%s)\n", __FUNCTION__, tcp_conn, len,
-+		  conn->datadgst_en? ", digest enabled" : "");
-+
-+	/* Make sure the datalen matches what the caller
-+	   said he would send. */
-+	hdr_spec_len = ntoh24(tcp_conn->out.hdr->dlength);
-+	WARN_ON(iscsi_padded(len) != iscsi_padded(hdr_spec_len));
++	struct lpfc_dmabuf *mp, *next_mp;
++	struct list_head *slp = &pring->postbufq;
 +
-+	if (conn->datadgst_en)
-+		tx_hash = &tcp_conn->tx_hash;
++	/* Search postbufq, from the begining, looking for a match on tag */
++	spin_lock_irq(&phba->hbalock);
++	list_for_each_entry_safe(mp, next_mp, &pring->postbufq, list) {
++		if (mp->buffer_tag == tag) {
++			list_del_init(&mp->list);
++			pring->postbufq_cnt--;
++			spin_unlock_irq(&phba->hbalock);
++			return mp;
++		}
++	}
 +
-+	iscsi_segment_init_linear(&tcp_conn->out.data_segment,
-+				data, len, NULL, tx_hash);
- }
- 
- /**
-@@ -1207,12 +1261,17 @@ iscsi_data_digest_init(struct iscsi_tcp_conn *tcp_conn,
-  *
-  *	Called under connection lock.
-  **/
--static void
-+static int
- iscsi_solicit_data_cont(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask,
--			struct iscsi_r2t_info *r2t, int left)
-+			struct iscsi_r2t_info *r2t)
- {
- 	struct iscsi_data *hdr;
--	int new_offset;
-+	int new_offset, left;
++	spin_unlock_irq(&phba->hbalock);
++	lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
++			"0410 Cannot find virtual addr for buffer tag on "
++			"ring %d Data x%lx x%p x%p x%x\n",
++			pring->ringno, (unsigned long) tag,
++			slp->next, slp->prev, pring->postbufq_cnt);
 +
-+	BUG_ON(r2t->data_length - r2t->sent < 0);
-+	left = r2t->data_length - r2t->sent;
-+	if (left == 0)
-+		return 0;
- 
- 	hdr = &r2t->dtask.hdr;
- 	memset(hdr, 0, sizeof(struct iscsi_data));
-@@ -1233,43 +1292,46 @@ iscsi_solicit_data_cont(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask,
- 		r2t->data_count = left;
- 		hdr->flags = ISCSI_FLAG_CMD_FINAL;
- 	}
--	conn->dataout_pdus_cnt++;
--
--	iscsi_buf_init_iov(&r2t->headbuf, (char*)hdr,
--			   sizeof(struct iscsi_hdr));
--
--	if (iscsi_buf_left(&r2t->sendbuf))
--		return;
--
--	iscsi_buf_init_sg(&r2t->sendbuf, r2t->sg);
--	r2t->sg += 1;
--}
- 
--static void iscsi_set_padding(struct iscsi_tcp_cmd_task *tcp_ctask,
--			      unsigned long len)
--{
--	tcp_ctask->pad_count = len & (ISCSI_PAD_LEN - 1);
--	if (!tcp_ctask->pad_count)
--		return;
--
--	tcp_ctask->pad_count = ISCSI_PAD_LEN - tcp_ctask->pad_count;
--	debug_scsi("write padding %d bytes\n", tcp_ctask->pad_count);
--	set_bit(XMSTATE_BIT_W_PAD, &tcp_ctask->xmstate);
-+	conn->dataout_pdus_cnt++;
-+	return 1;
- }
++	return NULL;
++}
  
- /**
-- * iscsi_tcp_cmd_init - Initialize iSCSI SCSI_READ or SCSI_WRITE commands
-+ * iscsi_tcp_ctask - Initialize iSCSI SCSI_READ or SCSI_WRITE commands
-  * @conn: iscsi connection
-  * @ctask: scsi command task
-  * @sc: scsi command
-  **/
--static void
--iscsi_tcp_cmd_init(struct iscsi_cmd_task *ctask)
-+static int
-+iscsi_tcp_ctask_init(struct iscsi_cmd_task *ctask)
- {
- 	struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
-+	struct iscsi_conn *conn = ctask->conn;
-+	struct scsi_cmnd *sc = ctask->sc;
-+	int err;
+ struct lpfc_dmabuf *
+ lpfc_sli_ringpostbuf_get(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
+@@ -3361,6 +3534,12 @@ lpfc_sli_abort_els_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+ 			pring->txcmplq_cnt--;
+ 			spin_unlock_irq(&phba->hbalock);
  
- 	BUG_ON(__kfifo_len(tcp_ctask->r2tqueue));
--	tcp_ctask->xmstate = 1 << XMSTATE_BIT_CMD_HDR_INIT;
-+	tcp_ctask->sent = 0;
-+	tcp_ctask->exp_datasn = 0;
-+
-+	/* Prepare PDU, optionally w/ immediate data */
-+	debug_scsi("ctask deq [cid %d itt 0x%x imm %d unsol %d]\n",
-+		    conn->id, ctask->itt, ctask->imm_count,
-+		    ctask->unsol_count);
-+	iscsi_tcp_send_hdr_prep(conn, ctask->hdr, ctask->hdr_len);
-+
-+	if (!ctask->imm_count)
-+		return 0;
++			/* Firmware could still be in progress of DMAing
++			 * payload, so don't free data buffer till after
++			 * a hbeat.
++			 */
++			abort_iocb->iocb_flag |= LPFC_DELAY_MEM_FREE;
 +
-+	/* If we have immediate data, attach a payload */
-+	err = iscsi_tcp_send_data_prep(conn, scsi_sglist(sc), scsi_sg_count(sc),
-+				       0, ctask->imm_count);
-+	if (err)
-+		return err;
-+	tcp_ctask->sent += ctask->imm_count;
-+	ctask->imm_count = 0;
-+	return 0;
- }
- 
- /**
-@@ -1281,484 +1343,130 @@ iscsi_tcp_cmd_init(struct iscsi_cmd_task *ctask)
-  *	The function can return -EAGAIN in which case caller must
-  *	call it again later, or recover. '0' return code means successful
-  *	xmit.
-- *
-- *	Management xmit state machine consists of these states:
-- *		XMSTATE_BIT_IMM_HDR_INIT - calculate digest of PDU Header
-- *		XMSTATE_BIT_IMM_HDR      - PDU Header xmit in progress
-- *		XMSTATE_BIT_IMM_DATA     - PDU Data xmit in progress
-- *		XMSTATE_VALUE_IDLE       - management PDU is done
-  **/
- static int
- iscsi_tcp_mtask_xmit(struct iscsi_conn *conn, struct iscsi_mgmt_task *mtask)
- {
--	struct iscsi_tcp_mgmt_task *tcp_mtask = mtask->dd_data;
- 	int rc;
- 
--	debug_scsi("mtask deq [cid %d state %x itt 0x%x]\n",
--		conn->id, tcp_mtask->xmstate, mtask->itt);
--
--	if (test_bit(XMSTATE_BIT_IMM_HDR_INIT, &tcp_mtask->xmstate)) {
--		iscsi_buf_init_iov(&tcp_mtask->headbuf, (char*)mtask->hdr,
--				   sizeof(struct iscsi_hdr));
--
--		if (mtask->data_count) {
--			set_bit(XMSTATE_BIT_IMM_DATA, &tcp_mtask->xmstate);
--			iscsi_buf_init_iov(&tcp_mtask->sendbuf,
--					   (char*)mtask->data,
--					   mtask->data_count);
--		}
--
--		if (conn->c_stage != ISCSI_CONN_INITIAL_STAGE &&
--		    conn->stop_stage != STOP_CONN_RECOVER &&
--		    conn->hdrdgst_en)
--			iscsi_hdr_digest(conn, &tcp_mtask->headbuf,
--					(u8*)tcp_mtask->hdrext);
--
--		tcp_mtask->sent = 0;
--		clear_bit(XMSTATE_BIT_IMM_HDR_INIT, &tcp_mtask->xmstate);
--		set_bit(XMSTATE_BIT_IMM_HDR, &tcp_mtask->xmstate);
--	}
--
--	if (test_bit(XMSTATE_BIT_IMM_HDR, &tcp_mtask->xmstate)) {
--		rc = iscsi_sendhdr(conn, &tcp_mtask->headbuf,
--				   mtask->data_count);
--		if (rc)
--			return rc;
--		clear_bit(XMSTATE_BIT_IMM_HDR, &tcp_mtask->xmstate);
--	}
--
--	if (test_and_clear_bit(XMSTATE_BIT_IMM_DATA, &tcp_mtask->xmstate)) {
--		BUG_ON(!mtask->data_count);
--		/* FIXME: implement.
--		 * Virtual buffer could be spreaded across multiple pages...
--		 */
--		do {
--			int rc;
--
--			rc = iscsi_sendpage(conn, &tcp_mtask->sendbuf,
--					&mtask->data_count, &tcp_mtask->sent);
--			if (rc) {
--				set_bit(XMSTATE_BIT_IMM_DATA, &tcp_mtask->xmstate);
--				return rc;
--			}
--		} while (mtask->data_count);
--	}
-+	/* Flush any pending data first. */
-+	rc = iscsi_tcp_flush(conn);
-+	if (rc < 0)
-+		return rc;
+ 			abort_iocb->iocb_flag &= ~LPFC_DRIVER_ABORTED;
+ 			abort_iocb->iocb.ulpStatus = IOSTAT_LOCAL_REJECT;
+ 			abort_iocb->iocb.un.ulpWord[4] = IOERR_SLI_ABORTED;
+@@ -3699,7 +3878,7 @@ lpfc_sli_issue_mbox_wait(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq,
+ 	unsigned long flag;
  
--	BUG_ON(tcp_mtask->xmstate != XMSTATE_VALUE_IDLE);
- 	if (mtask->hdr->itt == RESERVED_ITT) {
- 		struct iscsi_session *session = conn->session;
+ 	/* The caller must leave context1 empty. */
+-	if (pmboxq->context1 != 0)
++	if (pmboxq->context1)
+ 		return MBX_NOT_FINISHED;
  
- 		spin_lock_bh(&session->lock);
--		list_del(&conn->mtask->running);
--		__kfifo_put(session->mgmtpool.queue, (void*)&conn->mtask,
--			    sizeof(void*));
-+		iscsi_free_mgmt_task(conn, mtask);
- 		spin_unlock_bh(&session->lock);
- 	}
-+
- 	return 0;
- }
+ 	/* setup wake call as IOCB callback */
+@@ -3771,7 +3950,6 @@ lpfc_intr_handler(int irq, void *dev_id)
+ 	uint32_t ha_copy;
+ 	uint32_t work_ha_copy;
+ 	unsigned long status;
+-	int i;
+ 	uint32_t control;
  
-+/*
-+ * iscsi_tcp_ctask_xmit - xmit normal PDU task
-+ * @conn: iscsi connection
-+ * @ctask: iscsi command task
-+ *
-+ * We're expected to return 0 when everything was transmitted succesfully,
-+ * -EAGAIN if there's still data in the queue, or != 0 for any other kind
-+ * of error.
-+ */
- static int
--iscsi_send_cmd_hdr(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
-+iscsi_tcp_ctask_xmit(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
- {
--	struct scsi_cmnd *sc = ctask->sc;
- 	struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
-+	struct scsi_cmnd *sc = ctask->sc;
- 	int rc = 0;
+ 	MAILBOX_t *mbox, *pmbox;
+@@ -3888,7 +4066,6 @@ lpfc_intr_handler(int irq, void *dev_id)
+ 		}
  
--	if (test_bit(XMSTATE_BIT_CMD_HDR_INIT, &tcp_ctask->xmstate)) {
--		tcp_ctask->sent = 0;
--		tcp_ctask->sg_count = 0;
--		tcp_ctask->exp_datasn = 0;
--
--		if (sc->sc_data_direction == DMA_TO_DEVICE) {
--			struct scatterlist *sg = scsi_sglist(sc);
--
--			iscsi_buf_init_sg(&tcp_ctask->sendbuf, sg);
--			tcp_ctask->sg = sg + 1;
--			tcp_ctask->bad_sg = sg + scsi_sg_count(sc);
--
--			debug_scsi("cmd [itt 0x%x total %d imm_data %d "
--				   "unsol count %d, unsol offset %d]\n",
--				   ctask->itt, scsi_bufflen(sc),
--				   ctask->imm_count, ctask->unsol_count,
--				   ctask->unsol_offset);
--		}
--
--		iscsi_buf_init_iov(&tcp_ctask->headbuf, (char*)ctask->hdr,
--				  sizeof(struct iscsi_hdr));
--
--		if (conn->hdrdgst_en)
--			iscsi_hdr_digest(conn, &tcp_ctask->headbuf,
--					 (u8*)tcp_ctask->hdrext);
--		clear_bit(XMSTATE_BIT_CMD_HDR_INIT, &tcp_ctask->xmstate);
--		set_bit(XMSTATE_BIT_CMD_HDR_XMIT, &tcp_ctask->xmstate);
--	}
--
--	if (test_bit(XMSTATE_BIT_CMD_HDR_XMIT, &tcp_ctask->xmstate)) {
--		rc = iscsi_sendhdr(conn, &tcp_ctask->headbuf, ctask->imm_count);
--		if (rc)
--			return rc;
--		clear_bit(XMSTATE_BIT_CMD_HDR_XMIT, &tcp_ctask->xmstate);
--
--		if (sc->sc_data_direction != DMA_TO_DEVICE)
--			return 0;
--
--		if (ctask->imm_count) {
--			set_bit(XMSTATE_BIT_IMM_DATA, &tcp_ctask->xmstate);
--			iscsi_set_padding(tcp_ctask, ctask->imm_count);
--
--			if (ctask->conn->datadgst_en) {
--				iscsi_data_digest_init(ctask->conn->dd_data,
--						       tcp_ctask);
--				tcp_ctask->immdigest = 0;
+ 		if (work_ha_copy & HA_ERATT) {
+-			phba->link_state = LPFC_HBA_ERROR;
+ 			/*
+ 			 * There was a link/board error.  Read the
+ 			 * status register to retrieve the error event
+@@ -3920,7 +4097,7 @@ lpfc_intr_handler(int irq, void *dev_id)
+ 				 * Stray Mailbox Interrupt, mbxCommand <cmd>
+ 				 * mbxStatus <status>
+ 				 */
+-				lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX |
++				lpfc_printf_log(phba, KERN_ERR, LOG_MBOX |
+ 						LOG_SLI,
+ 						"(%d):0304 Stray Mailbox "
+ 						"Interrupt mbxCommand x%x "
+@@ -3928,51 +4105,60 @@ lpfc_intr_handler(int irq, void *dev_id)
+ 						(vport ? vport->vpi : 0),
+ 						pmbox->mbxCommand,
+ 						pmbox->mbxStatus);
 -			}
--		}
--
--		if (ctask->unsol_count) {
--			set_bit(XMSTATE_BIT_UNS_HDR, &tcp_ctask->xmstate);
--			set_bit(XMSTATE_BIT_UNS_INIT, &tcp_ctask->xmstate);
--		}
--	}
--	return rc;
--}
--
--static int
--iscsi_send_padding(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
--{
--	struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
--	struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
--	int sent = 0, rc;
--
--	if (test_bit(XMSTATE_BIT_W_PAD, &tcp_ctask->xmstate)) {
--		iscsi_buf_init_iov(&tcp_ctask->sendbuf, (char*)&tcp_ctask->pad,
--				   tcp_ctask->pad_count);
--		if (conn->datadgst_en)
--			crypto_hash_update(&tcp_conn->tx_hash,
--					   &tcp_ctask->sendbuf.sg,
--					   tcp_ctask->sendbuf.sg.length);
--	} else if (!test_bit(XMSTATE_BIT_W_RESEND_PAD, &tcp_ctask->xmstate))
--		return 0;
--
--	clear_bit(XMSTATE_BIT_W_PAD, &tcp_ctask->xmstate);
--	clear_bit(XMSTATE_BIT_W_RESEND_PAD, &tcp_ctask->xmstate);
--	debug_scsi("sending %d pad bytes for itt 0x%x\n",
--		   tcp_ctask->pad_count, ctask->itt);
--	rc = iscsi_sendpage(conn, &tcp_ctask->sendbuf, &tcp_ctask->pad_count,
--			   &sent);
--	if (rc) {
--		debug_scsi("padding send failed %d\n", rc);
--		set_bit(XMSTATE_BIT_W_RESEND_PAD, &tcp_ctask->xmstate);
--	}
--	return rc;
--}
--
--static int
--iscsi_send_digest(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask,
--			struct iscsi_buf *buf, uint32_t *digest)
--{
--	struct iscsi_tcp_cmd_task *tcp_ctask;
--	struct iscsi_tcp_conn *tcp_conn;
--	int rc, sent = 0;
--
--	if (!conn->datadgst_en)
--		return 0;
--
--	tcp_ctask = ctask->dd_data;
--	tcp_conn = conn->dd_data;
--
--	if (!test_bit(XMSTATE_BIT_W_RESEND_DATA_DIGEST, &tcp_ctask->xmstate)) {
--		crypto_hash_final(&tcp_conn->tx_hash, (u8*)digest);
--		iscsi_buf_init_iov(buf, (char*)digest, 4);
--	}
--	clear_bit(XMSTATE_BIT_W_RESEND_DATA_DIGEST, &tcp_ctask->xmstate);
--
--	rc = iscsi_sendpage(conn, buf, &tcp_ctask->digest_count, &sent);
--	if (!rc)
--		debug_scsi("sent digest 0x%x for itt 0x%x\n", *digest,
--			  ctask->itt);
--	else {
--		debug_scsi("sending digest 0x%x failed for itt 0x%x!\n",
--			  *digest, ctask->itt);
--		set_bit(XMSTATE_BIT_W_RESEND_DATA_DIGEST, &tcp_ctask->xmstate);
--	}
--	return rc;
--}
--
--static int
--iscsi_send_data(struct iscsi_cmd_task *ctask, struct iscsi_buf *sendbuf,
--		struct scatterlist **sg, int *sent, int *count,
--		struct iscsi_buf *digestbuf, uint32_t *digest)
--{
--	struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
--	struct iscsi_conn *conn = ctask->conn;
--	struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
--	int rc, buf_sent, offset;
--
--	while (*count) {
--		buf_sent = 0;
--		offset = sendbuf->sent;
--
--		rc = iscsi_sendpage(conn, sendbuf, count, &buf_sent);
--		*sent = *sent + buf_sent;
--		if (buf_sent && conn->datadgst_en)
--			partial_sg_digest_update(&tcp_conn->tx_hash,
--				&sendbuf->sg, sendbuf->sg.offset + offset,
--				buf_sent);
--		if (!iscsi_buf_left(sendbuf) && *sg != tcp_ctask->bad_sg) {
--			iscsi_buf_init_sg(sendbuf, *sg);
--			*sg = *sg + 1;
--		}
--
--		if (rc)
--			return rc;
--	}
+-			phba->last_completion_time = jiffies;
+-			del_timer_sync(&phba->sli.mbox_tmo);
 -
--	rc = iscsi_send_padding(conn, ctask);
--	if (rc)
-+flush:
-+	/* Flush any pending data first. */
-+	rc = iscsi_tcp_flush(conn);
-+	if (rc < 0)
- 		return rc;
+-			phba->sli.mbox_active = NULL;
+-			if (pmb->mbox_cmpl) {
+-				lpfc_sli_pcimem_bcopy(mbox, pmbox,
+-						      MAILBOX_CMD_SIZE);
+-			}
+-			if (pmb->mbox_flag & LPFC_MBX_IMED_UNREG) {
+-				pmb->mbox_flag &= ~LPFC_MBX_IMED_UNREG;
++				/* clear mailbox attention bit */
++				work_ha_copy &= ~HA_MBATT;
++			} else {
++				phba->last_completion_time = jiffies;
++				del_timer(&phba->sli.mbox_tmo);
  
--	return iscsi_send_digest(conn, ctask, digestbuf, digest);
--}
--
--static int
--iscsi_send_unsol_hdr(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
--{
--	struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
--	struct iscsi_data_task *dtask;
--	int rc;
--
--	set_bit(XMSTATE_BIT_UNS_DATA, &tcp_ctask->xmstate);
--	if (test_bit(XMSTATE_BIT_UNS_INIT, &tcp_ctask->xmstate)) {
--		dtask = &tcp_ctask->unsol_dtask;
--
--		iscsi_prep_unsolicit_data_pdu(ctask, &dtask->hdr);
--		iscsi_buf_init_iov(&tcp_ctask->headbuf, (char*)&dtask->hdr,
--				   sizeof(struct iscsi_hdr));
--		if (conn->hdrdgst_en)
--			iscsi_hdr_digest(conn, &tcp_ctask->headbuf,
--					(u8*)dtask->hdrext);
+-				lpfc_debugfs_disc_trc(vport,
+-					LPFC_DISC_TRC_MBOX_VPORT,
+-					"MBOX dflt rpi: : status:x%x rpi:x%x",
+-					(uint32_t)pmbox->mbxStatus,
+-					pmbox->un.varWords[0], 0);
 -
--		clear_bit(XMSTATE_BIT_UNS_INIT, &tcp_ctask->xmstate);
--		iscsi_set_padding(tcp_ctask, ctask->data_count);
--	}
+-				if ( !pmbox->mbxStatus) {
+-					mp = (struct lpfc_dmabuf *)
+-						(pmb->context1);
+-					ndlp = (struct lpfc_nodelist *)
+-						pmb->context2;
 -
--	rc = iscsi_sendhdr(conn, &tcp_ctask->headbuf, ctask->data_count);
--	if (rc) {
--		clear_bit(XMSTATE_BIT_UNS_DATA, &tcp_ctask->xmstate);
--		set_bit(XMSTATE_BIT_UNS_HDR, &tcp_ctask->xmstate);
--		return rc;
--	}
-+	/* Are we done already? */
-+	if (sc->sc_data_direction != DMA_TO_DEVICE)
-+		return 0;
+-					/* Reg_LOGIN of dflt RPI was successful.
+-					 * new lets get rid of the RPI using the
+-					 * same mbox buffer.
+-					 */
+-					lpfc_unreg_login(phba, vport->vpi,
+-						pmbox->un.varWords[0], pmb);
+-					pmb->mbox_cmpl = lpfc_mbx_cmpl_dflt_rpi;
+-					pmb->context1 = mp;
+-					pmb->context2 = ndlp;
+-					pmb->vport = vport;
+-					spin_lock(&phba->hbalock);
+-					phba->sli.sli_flag &=
+-						~LPFC_SLI_MBOX_ACTIVE;
+-					spin_unlock(&phba->hbalock);
+-					goto send_current_mbox;
++				phba->sli.mbox_active = NULL;
++				if (pmb->mbox_cmpl) {
++					lpfc_sli_pcimem_bcopy(mbox, pmbox,
++							MAILBOX_CMD_SIZE);
++				}
++				if (pmb->mbox_flag & LPFC_MBX_IMED_UNREG) {
++					pmb->mbox_flag &= ~LPFC_MBX_IMED_UNREG;
++
++					lpfc_debugfs_disc_trc(vport,
++						LPFC_DISC_TRC_MBOX_VPORT,
++						"MBOX dflt rpi: : "
++						"status:x%x rpi:x%x",
++						(uint32_t)pmbox->mbxStatus,
++						pmbox->un.varWords[0], 0);
++
++					if (!pmbox->mbxStatus) {
++						mp = (struct lpfc_dmabuf *)
++							(pmb->context1);
++						ndlp = (struct lpfc_nodelist *)
++							pmb->context2;
++
++						/* Reg_LOGIN of dflt RPI was
++						 * successful. new lets get
++						 * rid of the RPI using the
++						 * same mbox buffer.
++						 */
++						lpfc_unreg_login(phba,
++							vport->vpi,
++							pmbox->un.varWords[0],
++							pmb);
++						pmb->mbox_cmpl =
++							lpfc_mbx_cmpl_dflt_rpi;
++						pmb->context1 = mp;
++						pmb->context2 = ndlp;
++						pmb->vport = vport;
++						spin_lock(&phba->hbalock);
++						phba->sli.sli_flag &=
++							~LPFC_SLI_MBOX_ACTIVE;
++						spin_unlock(&phba->hbalock);
++						goto send_current_mbox;
++					}
+ 				}
++				spin_lock(&phba->pport->work_port_lock);
++				phba->pport->work_port_events &=
++					~WORKER_MBOX_TMO;
++				spin_unlock(&phba->pport->work_port_lock);
++				lpfc_mbox_cmpl_put(phba, pmb);
+ 			}
+-			spin_lock(&phba->pport->work_port_lock);
+-			phba->pport->work_port_events &= ~WORKER_MBOX_TMO;
+-			spin_unlock(&phba->pport->work_port_lock);
+-			lpfc_mbox_cmpl_put(phba, pmb);
+ 		}
+ 		if ((work_ha_copy & HA_MBATT) &&
+ 		    (phba->sli.mbox_active == NULL)) {
+@@ -3990,10 +4176,6 @@ send_current_mbox:
+ 					lpfc_mbox_cmpl_put(phba, pmb);
+ 					goto send_next_mbox;
+ 				}
+-			} else {
+-				/* Turn on IOCB processing */
+-				for (i = 0; i < phba->sli.num_rings; i++)
+-					lpfc_sli_turn_on_ring(phba, i);
+ 			}
+ 
+ 		}
+diff --git a/drivers/scsi/lpfc/lpfc_sli.h b/drivers/scsi/lpfc/lpfc_sli.h
+index 51b2b6b..7249fd2 100644
+--- a/drivers/scsi/lpfc/lpfc_sli.h
++++ b/drivers/scsi/lpfc/lpfc_sli.h
+@@ -33,6 +33,7 @@ typedef enum _lpfc_ctx_cmd {
+ struct lpfc_iocbq {
+ 	/* lpfc_iocbqs are used in double linked lists */
+ 	struct list_head list;
++	struct list_head clist;
+ 	uint16_t iotag;         /* pre-assigned IO tag */
+ 	uint16_t rsvd1;
  
--	if (conn->datadgst_en) {
--		dtask = &tcp_ctask->unsol_dtask;
--		iscsi_data_digest_init(ctask->conn->dd_data, tcp_ctask);
--		dtask->digest = 0;
--	}
-+	if (ctask->unsol_count != 0) {
-+		struct iscsi_data *hdr = &tcp_ctask->unsol_dtask.hdr;
+@@ -44,6 +45,7 @@ struct lpfc_iocbq {
+ #define LPFC_IO_FCP		4	/* FCP command -- iocbq in scsi_buf */
+ #define LPFC_DRIVER_ABORTED	8	/* driver aborted this request */
+ #define LPFC_IO_FABRIC		0x10	/* Iocb send using fabric scheduler */
++#define LPFC_DELAY_MEM_FREE	0x20    /* Defer free'ing of FC data */
  
--	debug_scsi("uns dout [itt 0x%x dlen %d sent %d]\n",
--		   ctask->itt, ctask->unsol_count, tcp_ctask->sent);
--	return 0;
--}
-+		/* Prepare a header for the unsolicited PDU.
-+		 * The amount of data we want to send will be
-+		 * in ctask->data_count.
-+		 * FIXME: return the data count instead.
-+		 */
-+		iscsi_prep_unsolicit_data_pdu(ctask, hdr);
+ 	uint8_t abort_count;
+ 	uint8_t rsvd2;
+@@ -92,8 +94,6 @@ typedef struct lpfcMboxq {
+ #define MBX_POLL        1	/* poll mailbox till command done, then
+ 				   return */
+ #define MBX_NOWAIT      2	/* issue command then return immediately */
+-#define MBX_STOP_IOCB   4	/* Stop iocb processing till mbox cmds
+-				   complete */
  
--static int
--iscsi_send_unsol_pdu(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
--{
--	struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
--	int rc;
-+		debug_tcp("unsol dout [itt 0x%x doff %d dlen %d]\n",
-+				ctask->itt, tcp_ctask->sent, ctask->data_count);
+ #define LPFC_MAX_RING_MASK  4	/* max num of rctl/type masks allowed per
+ 				   ring */
+@@ -129,9 +129,7 @@ struct lpfc_sli_ring {
+ 	uint16_t flag;		/* ring flags */
+ #define LPFC_DEFERRED_RING_EVENT 0x001	/* Deferred processing a ring event */
+ #define LPFC_CALL_RING_AVAILABLE 0x002	/* indicates cmd was full */
+-#define LPFC_STOP_IOCB_MBX       0x010	/* Stop processing IOCB cmds mbox */
+ #define LPFC_STOP_IOCB_EVENT     0x020	/* Stop processing IOCB cmds event */
+-#define LPFC_STOP_IOCB_MASK      0x030	/* Stop processing IOCB cmds mask */
+ 	uint16_t abtsiotag;	/* tracks next iotag to use for ABTS */
  
--	if (test_and_clear_bit(XMSTATE_BIT_UNS_HDR, &tcp_ctask->xmstate)) {
--		BUG_ON(!ctask->unsol_count);
--send_hdr:
--		rc = iscsi_send_unsol_hdr(conn, ctask);
-+		iscsi_tcp_send_hdr_prep(conn, hdr, sizeof(*hdr));
-+		rc = iscsi_tcp_send_data_prep(conn, scsi_sglist(sc),
-+					      scsi_sg_count(sc),
-+					      tcp_ctask->sent,
-+					      ctask->data_count);
- 		if (rc)
--			return rc;
--	}
--
--	if (test_bit(XMSTATE_BIT_UNS_DATA, &tcp_ctask->xmstate)) {
--		struct iscsi_data_task *dtask = &tcp_ctask->unsol_dtask;
--		int start = tcp_ctask->sent;
-+			goto fail;
-+		tcp_ctask->sent += ctask->data_count;
-+		ctask->unsol_count -= ctask->data_count;
-+		goto flush;
-+	} else {
-+		struct iscsi_session *session = conn->session;
-+		struct iscsi_r2t_info *r2t;
+ 	uint32_t local_getidx;   /* last available cmd index (from cmdGetInx) */
+@@ -163,9 +161,12 @@ struct lpfc_sli_ring {
+ 	struct list_head iocb_continueq;
+ 	uint16_t iocb_continueq_cnt;	/* current length of queue */
+ 	uint16_t iocb_continueq_max;	/* max length */
++	struct list_head iocb_continue_saveq;
  
--		rc = iscsi_send_data(ctask, &tcp_ctask->sendbuf, &tcp_ctask->sg,
--				     &tcp_ctask->sent, &ctask->data_count,
--				     &dtask->digestbuf, &dtask->digest);
--		ctask->unsol_count -= tcp_ctask->sent - start;
--		if (rc)
--			return rc;
--		clear_bit(XMSTATE_BIT_UNS_DATA, &tcp_ctask->xmstate);
--		/*
--		 * Done with the Data-Out. Next, check if we need
--		 * to send another unsolicited Data-Out.
-+		/* All unsolicited PDUs sent. Check for solicited PDUs.
- 		 */
--		if (ctask->unsol_count) {
--			debug_scsi("sending more uns\n");
--			set_bit(XMSTATE_BIT_UNS_INIT, &tcp_ctask->xmstate);
--			goto send_hdr;
-+		spin_lock_bh(&session->lock);
-+		r2t = tcp_ctask->r2t;
-+		if (r2t != NULL) {
-+			/* Continue with this R2T? */
-+			if (!iscsi_solicit_data_cont(conn, ctask, r2t)) {
-+				debug_scsi("  done with r2t %p\n", r2t);
-+
-+				__kfifo_put(tcp_ctask->r2tpool.queue,
-+					    (void*)&r2t, sizeof(void*));
-+				tcp_ctask->r2t = r2t = NULL;
-+			}
- 		}
--	}
--	return 0;
--}
--
--static int iscsi_send_sol_pdu(struct iscsi_conn *conn,
--			      struct iscsi_cmd_task *ctask)
--{
--	struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
--	struct iscsi_session *session = conn->session;
--	struct iscsi_r2t_info *r2t;
--	struct iscsi_data_task *dtask;
--	int left, rc;
+ 	struct lpfc_sli_ring_mask prt[LPFC_MAX_RING_MASK];
+ 	uint32_t num_mask;	/* number of mask entries in prt array */
++	void (*lpfc_sli_rcv_async_status) (struct lpfc_hba *,
++		struct lpfc_sli_ring *, struct lpfc_iocbq *);
  
--	if (test_bit(XMSTATE_BIT_SOL_HDR_INIT, &tcp_ctask->xmstate)) {
--		if (!tcp_ctask->r2t) {
--			spin_lock_bh(&session->lock);
-+		if (r2t == NULL) {
- 			__kfifo_get(tcp_ctask->r2tqueue, (void*)&tcp_ctask->r2t,
- 				    sizeof(void*));
--			spin_unlock_bh(&session->lock);
-+			r2t = tcp_ctask->r2t;
- 		}
--send_hdr:
--		r2t = tcp_ctask->r2t;
--		dtask = &r2t->dtask;
--
--		if (conn->hdrdgst_en)
--			iscsi_hdr_digest(conn, &r2t->headbuf,
--					(u8*)dtask->hdrext);
--		clear_bit(XMSTATE_BIT_SOL_HDR_INIT, &tcp_ctask->xmstate);
--		set_bit(XMSTATE_BIT_SOL_HDR, &tcp_ctask->xmstate);
--	}
+ 	struct lpfc_sli_ring_stat stats;	/* SLI statistical info */
+ 
+@@ -199,9 +200,6 @@ struct lpfc_hbq_init {
+ 	uint32_t add_count;	/* number to allocate when starved */
+ } ;
+ 
+-#define LPFC_MAX_HBQ 16
 -
--	if (test_bit(XMSTATE_BIT_SOL_HDR, &tcp_ctask->xmstate)) {
--		r2t = tcp_ctask->r2t;
--		dtask = &r2t->dtask;
 -
--		rc = iscsi_sendhdr(conn, &r2t->headbuf, r2t->data_count);
--		if (rc)
--			return rc;
--		clear_bit(XMSTATE_BIT_SOL_HDR, &tcp_ctask->xmstate);
--		set_bit(XMSTATE_BIT_SOL_DATA, &tcp_ctask->xmstate);
-+		spin_unlock_bh(&session->lock);
+ /* Structure used to hold SLI statistical counters and info */
+ struct lpfc_sli_stat {
+ 	uint64_t mbox_stat_err;  /* Mbox cmds completed status error */
+diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h
+index 0081f49..4b633d3 100644
+--- a/drivers/scsi/lpfc/lpfc_version.h
++++ b/drivers/scsi/lpfc/lpfc_version.h
+@@ -1,7 +1,7 @@
+ /*******************************************************************
+  * This file is part of the Emulex Linux Device Driver for         *
+  * Fibre Channel Host Bus Adapters.                                *
+- * Copyright (C) 2004-2007 Emulex.  All rights reserved.           *
++ * Copyright (C) 2004-2008 Emulex.  All rights reserved.           *
+  * EMULEX and SLI are trademarks of Emulex.                        *
+  * www.emulex.com                                                  *
+  *                                                                 *
+@@ -18,10 +18,10 @@
+  * included with this package.                                     *
+  *******************************************************************/
  
--		if (conn->datadgst_en) {
--			iscsi_data_digest_init(conn->dd_data, tcp_ctask);
--			dtask->digest = 0;
-+		/* Waiting for more R2Ts to arrive. */
-+		if (r2t == NULL) {
-+			debug_tcp("no R2Ts yet\n");
-+			return 0;
- 		}
+-#define LPFC_DRIVER_VERSION "8.2.2"
++#define LPFC_DRIVER_VERSION "8.2.4"
  
--		iscsi_set_padding(tcp_ctask, r2t->data_count);
--		debug_scsi("sol dout [dsn %d itt 0x%x dlen %d sent %d]\n",
--			r2t->solicit_datasn - 1, ctask->itt, r2t->data_count,
--			r2t->sent);
--	}
-+		debug_scsi("sol dout %p [dsn %d itt 0x%x doff %d dlen %d]\n",
-+			r2t, r2t->solicit_datasn - 1, ctask->itt,
-+			r2t->data_offset + r2t->sent, r2t->data_count);
+ #define LPFC_DRIVER_NAME "lpfc"
  
--	if (test_bit(XMSTATE_BIT_SOL_DATA, &tcp_ctask->xmstate)) {
--		r2t = tcp_ctask->r2t;
--		dtask = &r2t->dtask;
-+		iscsi_tcp_send_hdr_prep(conn, &r2t->dtask.hdr,
-+					sizeof(struct iscsi_hdr));
+ #define LPFC_MODULE_DESC "Emulex LightPulse Fibre Channel SCSI driver " \
+ 		LPFC_DRIVER_VERSION
+-#define LPFC_COPYRIGHT "Copyright(c) 2004-2007 Emulex.  All rights reserved."
++#define LPFC_COPYRIGHT "Copyright(c) 2004-2008 Emulex.  All rights reserved."
+diff --git a/drivers/scsi/lpfc/lpfc_vport.c b/drivers/scsi/lpfc/lpfc_vport.c
+index dcb415e..9fad766 100644
+--- a/drivers/scsi/lpfc/lpfc_vport.c
++++ b/drivers/scsi/lpfc/lpfc_vport.c
+@@ -125,15 +125,26 @@ lpfc_vport_sparm(struct lpfc_hba *phba, struct lpfc_vport *vport)
+ 	pmb->vport = vport;
+ 	rc = lpfc_sli_issue_mbox_wait(phba, pmb, phba->fc_ratov * 2);
+ 	if (rc != MBX_SUCCESS) {
+-		lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT | LOG_VPORT,
+-				 "1818 VPort failed init, mbxCmd x%x "
+-				 "READ_SPARM mbxStatus x%x, rc = x%x\n",
+-				 mb->mbxCommand, mb->mbxStatus, rc);
+-		lpfc_mbuf_free(phba, mp->virt, mp->phys);
+-		kfree(mp);
+-		if (rc != MBX_TIMEOUT)
+-			mempool_free(pmb, phba->mbox_mem_pool);
+-		return -EIO;
++		if (signal_pending(current)) {
++			lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT | LOG_VPORT,
++					 "1830 Signal aborted mbxCmd x%x\n",
++					 mb->mbxCommand);
++			lpfc_mbuf_free(phba, mp->virt, mp->phys);
++			kfree(mp);
++			if (rc != MBX_TIMEOUT)
++				mempool_free(pmb, phba->mbox_mem_pool);
++			return -EINTR;
++		} else {
++			lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT | LOG_VPORT,
++					 "1818 VPort failed init, mbxCmd x%x "
++					 "READ_SPARM mbxStatus x%x, rc = x%x\n",
++					 mb->mbxCommand, mb->mbxStatus, rc);
++			lpfc_mbuf_free(phba, mp->virt, mp->phys);
++			kfree(mp);
++			if (rc != MBX_TIMEOUT)
++				mempool_free(pmb, phba->mbox_mem_pool);
++			return -EIO;
++		}
+ 	}
  
--		rc = iscsi_send_data(ctask, &r2t->sendbuf, &r2t->sg,
--				     &r2t->sent, &r2t->data_count,
--				     &dtask->digestbuf, &dtask->digest);
-+		rc = iscsi_tcp_send_data_prep(conn, scsi_sglist(sc),
-+					      scsi_sg_count(sc),
-+					      r2t->data_offset + r2t->sent,
-+					      r2t->data_count);
- 		if (rc)
--			return rc;
--		clear_bit(XMSTATE_BIT_SOL_DATA, &tcp_ctask->xmstate);
--
--		/*
--		 * Done with this Data-Out. Next, check if we have
--		 * to send another Data-Out for this R2T.
--		 */
--		BUG_ON(r2t->data_length - r2t->sent < 0);
--		left = r2t->data_length - r2t->sent;
--		if (left) {
--			iscsi_solicit_data_cont(conn, ctask, r2t, left);
--			goto send_hdr;
--		}
--
--		/*
--		 * Done with this R2T. Check if there are more
--		 * outstanding R2Ts ready to be processed.
--		 */
--		spin_lock_bh(&session->lock);
--		tcp_ctask->r2t = NULL;
--		__kfifo_put(tcp_ctask->r2tpool.queue, (void*)&r2t,
--			    sizeof(void*));
--		if (__kfifo_get(tcp_ctask->r2tqueue, (void*)&r2t,
--				sizeof(void*))) {
--			tcp_ctask->r2t = r2t;
--			spin_unlock_bh(&session->lock);
--			goto send_hdr;
--		}
--		spin_unlock_bh(&session->lock);
-+			goto fail;
-+		tcp_ctask->sent += r2t->data_count;
-+		r2t->sent += r2t->data_count;
-+		goto flush;
+ 	memcpy(&vport->fc_sparam, mp->virt, sizeof (struct serv_parm));
+@@ -204,6 +215,7 @@ lpfc_vport_create(struct fc_vport *fc_vport, bool disable)
+ 	int instance;
+ 	int vpi;
+ 	int rc = VPORT_ERROR;
++	int status;
+ 
+ 	if ((phba->sli_rev < 3) ||
+ 		!(phba->sli3_options & LPFC_SLI3_NPIV_ENABLED)) {
+@@ -248,13 +260,19 @@ lpfc_vport_create(struct fc_vport *fc_vport, bool disable)
+ 	vport->vpi = vpi;
+ 	lpfc_debugfs_initialize(vport);
+ 
+-	if (lpfc_vport_sparm(phba, vport)) {
+-		lpfc_printf_vlog(vport, KERN_ERR, LOG_VPORT,
+-				 "1813 Create VPORT failed. "
+-				 "Cannot get sparam\n");
++	if ((status = lpfc_vport_sparm(phba, vport))) {
++		if (status == -EINTR) {
++			lpfc_printf_vlog(vport, KERN_ERR, LOG_VPORT,
++					 "1831 Create VPORT Interrupted.\n");
++			rc = VPORT_ERROR;
++		} else {
++			lpfc_printf_vlog(vport, KERN_ERR, LOG_VPORT,
++					 "1813 Create VPORT failed. "
++					 "Cannot get sparam\n");
++			rc = VPORT_NORESOURCES;
++		}
+ 		lpfc_free_vpi(phba, vpi);
+ 		destroy_port(vport);
+-		rc = VPORT_NORESOURCES;
+ 		goto error_out;
  	}
- 	return 0;
--}
--
--/**
-- * iscsi_tcp_ctask_xmit - xmit normal PDU task
-- * @conn: iscsi connection
-- * @ctask: iscsi command task
-- *
-- * Notes:
-- *	The function can return -EAGAIN in which case caller must
-- *	call it again later, or recover. '0' return code means successful
-- *	xmit.
-- *	The function is devided to logical helpers (above) for the different
-- *	xmit stages.
-- *
-- *iscsi_send_cmd_hdr()
-- *	XMSTATE_BIT_CMD_HDR_INIT - prepare Header and Data buffers Calculate
-- *	                           Header Digest
-- *	XMSTATE_BIT_CMD_HDR_XMIT - Transmit header in progress
-- *
-- *iscsi_send_padding
-- *	XMSTATE_BIT_W_PAD        - Prepare and send pading
-- *	XMSTATE_BIT_W_RESEND_PAD - retry send pading
-- *
-- *iscsi_send_digest
-- *	XMSTATE_BIT_W_RESEND_DATA_DIGEST - Finalize and send Data Digest
-- *	XMSTATE_BIT_W_RESEND_DATA_DIGEST - retry sending digest
-- *
-- *iscsi_send_unsol_hdr
-- *	XMSTATE_BIT_UNS_INIT     - prepare un-solicit data header and digest
-- *	XMSTATE_BIT_UNS_HDR      - send un-solicit header
-- *
-- *iscsi_send_unsol_pdu
-- *	XMSTATE_BIT_UNS_DATA     - send un-solicit data in progress
-- *
-- *iscsi_send_sol_pdu
-- *	XMSTATE_BIT_SOL_HDR_INIT - solicit data header and digest initialize
-- *	XMSTATE_BIT_SOL_HDR      - send solicit header
-- *	XMSTATE_BIT_SOL_DATA     - send solicit data
-- *
-- *iscsi_tcp_ctask_xmit
-- *	XMSTATE_BIT_IMM_DATA     - xmit managment data (??)
-- **/
--static int
--iscsi_tcp_ctask_xmit(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
--{
--	struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
--	int rc = 0;
--
--	debug_scsi("ctask deq [cid %d xmstate %x itt 0x%x]\n",
--		conn->id, tcp_ctask->xmstate, ctask->itt);
--
--	rc = iscsi_send_cmd_hdr(conn, ctask);
--	if (rc)
--		return rc;
--	if (ctask->sc->sc_data_direction != DMA_TO_DEVICE)
--		return 0;
+ 
+@@ -427,7 +445,6 @@ int
+ lpfc_vport_delete(struct fc_vport *fc_vport)
+ {
+ 	struct lpfc_nodelist *ndlp = NULL;
+-	struct lpfc_nodelist *next_ndlp;
+ 	struct Scsi_Host *shost = (struct Scsi_Host *) fc_vport->shost;
+ 	struct lpfc_vport *vport = *(struct lpfc_vport **)fc_vport->dd_data;
+ 	struct lpfc_hba   *phba = vport->phba;
+@@ -482,8 +499,18 @@ lpfc_vport_delete(struct fc_vport *fc_vport)
+ 
+ 	ndlp = lpfc_findnode_did(phba->pport, Fabric_DID);
+ 	if (ndlp && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE &&
+-		phba->link_state >= LPFC_LINK_UP) {
 -
--	if (test_bit(XMSTATE_BIT_IMM_DATA, &tcp_ctask->xmstate)) {
--		rc = iscsi_send_data(ctask, &tcp_ctask->sendbuf, &tcp_ctask->sg,
--				     &tcp_ctask->sent, &ctask->imm_count,
--				     &tcp_ctask->immbuf, &tcp_ctask->immdigest);
--		if (rc)
--			return rc;
--		clear_bit(XMSTATE_BIT_IMM_DATA, &tcp_ctask->xmstate);
++	    phba->link_state >= LPFC_LINK_UP) {
++		if (vport->cfg_enable_da_id) {
++			timeout = msecs_to_jiffies(phba->fc_ratov * 2000);
++			if (!lpfc_ns_cmd(vport, SLI_CTNS_DA_ID, 0, 0))
++				while (vport->ct_flags && timeout)
++					timeout = schedule_timeout(timeout);
++			else
++				lpfc_printf_log(vport->phba, KERN_WARNING,
++						LOG_VPORT,
++						"1829 CT command failed to "
++						"delete objects on fabric. \n");
++		}
+ 		/* First look for the Fabric ndlp */
+ 		ndlp = lpfc_findnode_did(vport, Fabric_DID);
+ 		if (!ndlp) {
+@@ -503,23 +530,20 @@ lpfc_vport_delete(struct fc_vport *fc_vport)
+ 	}
+ 
+ skip_logo:
++	lpfc_cleanup(vport);
+ 	lpfc_sli_host_down(vport);
+ 
+-	list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) {
+-		lpfc_disc_state_machine(vport, ndlp, NULL,
+-					     NLP_EVT_DEVICE_RECOVERY);
+-		lpfc_disc_state_machine(vport, ndlp, NULL,
+-					     NLP_EVT_DEVICE_RM);
 -	}
 -
--	rc = iscsi_send_unsol_pdu(conn, ctask);
--	if (rc)
--		return rc;
--
--	rc = iscsi_send_sol_pdu(conn, ctask);
--	if (rc)
--		return rc;
+ 	lpfc_stop_vport_timers(vport);
+ 	lpfc_unreg_all_rpis(vport);
+-	lpfc_unreg_default_rpis(vport);
+-	/*
+-	 * Completion of unreg_vpi (lpfc_mbx_cmpl_unreg_vpi) does the
+-	 * scsi_host_put() to release the vport.
+-	 */
+-	lpfc_mbx_unreg_vpi(vport);
++
++	if (!(phba->pport->load_flag & FC_UNLOADING)) {
++		lpfc_unreg_default_rpis(vport);
++		/*
++		 * Completion of unreg_vpi (lpfc_mbx_cmpl_unreg_vpi)
++		 * does the scsi_host_put() to release the vport.
++		 */
++		lpfc_mbx_unreg_vpi(vport);
++	}
+ 
+ 	lpfc_free_vpi(phba, vport->vpi);
+ 	vport->work_port_events = 0;
+@@ -532,16 +556,13 @@ skip_logo:
+ 	return VPORT_OK;
+ }
+ 
+-EXPORT_SYMBOL(lpfc_vport_create);
+-EXPORT_SYMBOL(lpfc_vport_delete);
 -
--	return rc;
-+fail:
-+	iscsi_conn_failure(conn, rc);
-+	return -EIO;
+ struct lpfc_vport **
+ lpfc_create_vport_work_array(struct lpfc_hba *phba)
+ {
+ 	struct lpfc_vport *port_iterator;
+ 	struct lpfc_vport **vports;
+ 	int index = 0;
+-	vports = kzalloc(LPFC_MAX_VPORTS * sizeof(struct lpfc_vport *),
++	vports = kzalloc((phba->max_vpi + 1) * sizeof(struct lpfc_vport *),
+ 			 GFP_KERNEL);
+ 	if (vports == NULL)
+ 		return NULL;
+@@ -560,12 +581,12 @@ lpfc_create_vport_work_array(struct lpfc_hba *phba)
  }
  
- static struct iscsi_cls_conn *
-@@ -1784,9 +1492,6 @@ iscsi_tcp_conn_create(struct iscsi_cls_session *cls_session, uint32_t conn_idx)
+ void
+-lpfc_destroy_vport_work_array(struct lpfc_vport **vports)
++lpfc_destroy_vport_work_array(struct lpfc_hba *phba, struct lpfc_vport **vports)
+ {
+ 	int i;
+ 	if (vports == NULL)
+ 		return;
+-	for (i=0; vports[i] != NULL && i < LPFC_MAX_VPORTS; i++)
++	for (i=0; vports[i] != NULL && i <= phba->max_vpi; i++)
+ 		scsi_host_put(lpfc_shost_from_vport(vports[i]));
+ 	kfree(vports);
+ }
+diff --git a/drivers/scsi/lpfc/lpfc_vport.h b/drivers/scsi/lpfc/lpfc_vport.h
+index 91da177..96c4453 100644
+--- a/drivers/scsi/lpfc/lpfc_vport.h
++++ b/drivers/scsi/lpfc/lpfc_vport.h
+@@ -89,7 +89,7 @@ int lpfc_vport_delete(struct fc_vport *);
+ int lpfc_vport_getinfo(struct Scsi_Host *, struct vport_info *);
+ int lpfc_vport_tgt_remove(struct Scsi_Host *, uint, uint);
+ struct lpfc_vport **lpfc_create_vport_work_array(struct lpfc_hba *);
+-void lpfc_destroy_vport_work_array(struct lpfc_vport **);
++void lpfc_destroy_vport_work_array(struct lpfc_hba *, struct lpfc_vport **);
  
- 	conn->dd_data = tcp_conn;
- 	tcp_conn->iscsi_conn = conn;
--	tcp_conn->in_progress = IN_PROGRESS_WAIT_HEADER;
--	/* initial operational parameters */
--	tcp_conn->hdr_size = sizeof(struct iscsi_hdr);
+ /*
+  *  queuecommand  VPORT-specific return codes. Specified in  the host byte code.
+diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c
+index 66c6520..765c24d 100644
+--- a/drivers/scsi/megaraid.c
++++ b/drivers/scsi/megaraid.c
+@@ -4889,7 +4889,7 @@ __megaraid_shutdown(adapter_t *adapter)
+ 		mdelay(1000);
+ }
  
- 	tcp_conn->tx_hash.tfm = crypto_alloc_hash("crc32c", 0,
- 						  CRYPTO_ALG_ASYNC);
-@@ -1863,11 +1568,9 @@ static void
- iscsi_tcp_conn_stop(struct iscsi_cls_conn *cls_conn, int flag)
+-static void
++static void __devexit
+ megaraid_remove_one(struct pci_dev *pdev)
  {
- 	struct iscsi_conn *conn = cls_conn->dd_data;
--	struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
+ 	struct Scsi_Host *host = pci_get_drvdata(pdev);
+diff --git a/drivers/scsi/megaraid/megaraid_mbox.c b/drivers/scsi/megaraid/megaraid_mbox.c
+index c892310..24e32e4 100644
+--- a/drivers/scsi/megaraid/megaraid_mbox.c
++++ b/drivers/scsi/megaraid/megaraid_mbox.c
+@@ -300,7 +300,7 @@ static struct pci_device_id pci_id_table_g[] =  {
+ MODULE_DEVICE_TABLE(pci, pci_id_table_g);
  
- 	iscsi_conn_stop(cls_conn, flag);
- 	iscsi_tcp_release_conn(conn);
--	tcp_conn->hdr_size = sizeof(struct iscsi_hdr);
+ 
+-static struct pci_driver megaraid_pci_driver_g = {
++static struct pci_driver megaraid_pci_driver = {
+ 	.name		= "megaraid",
+ 	.id_table	= pci_id_table_g,
+ 	.probe		= megaraid_probe_one,
+@@ -394,7 +394,7 @@ megaraid_init(void)
+ 
+ 
+ 	// register as a PCI hot-plug driver module
+-	rval = pci_register_driver(&megaraid_pci_driver_g);
++	rval = pci_register_driver(&megaraid_pci_driver);
+ 	if (rval < 0) {
+ 		con_log(CL_ANN, (KERN_WARNING
+ 			"megaraid: could not register hotplug support.\n"));
+@@ -415,7 +415,7 @@ megaraid_exit(void)
+ 	con_log(CL_DLEVEL1, (KERN_NOTICE "megaraid: unloading framework\n"));
+ 
+ 	// unregister as PCI hotplug driver
+-	pci_unregister_driver(&megaraid_pci_driver_g);
++	pci_unregister_driver(&megaraid_pci_driver);
+ 
+ 	return;
  }
+diff --git a/drivers/scsi/megaraid/megaraid_sas.c b/drivers/scsi/megaraid/megaraid_sas.c
+index e3c5c52..d7ec921 100644
+--- a/drivers/scsi/megaraid/megaraid_sas.c
++++ b/drivers/scsi/megaraid/megaraid_sas.c
+@@ -2,7 +2,7 @@
+  *
+  *		Linux MegaRAID driver for SAS based RAID controllers
+  *
+- * Copyright (c) 2003-2005  LSI Logic Corporation.
++ * Copyright (c) 2003-2005  LSI Corporation.
+  *
+  *	   This program is free software; you can redistribute it and/or
+  *	   modify it under the terms of the GNU General Public License
+@@ -10,7 +10,7 @@
+  *	   2 of the License, or (at your option) any later version.
+  *
+  * FILE		: megaraid_sas.c
+- * Version	: v00.00.03.10-rc5
++ * Version	: v00.00.03.16-rc1
+  *
+  * Authors:
+  *	(email-id : megaraidlinux at lsi.com)
+@@ -31,6 +31,7 @@
+ #include <linux/moduleparam.h>
+ #include <linux/module.h>
+ #include <linux/spinlock.h>
++#include <linux/mutex.h>
+ #include <linux/interrupt.h>
+ #include <linux/delay.h>
+ #include <linux/uio.h>
+@@ -46,10 +47,18 @@
+ #include <scsi/scsi_host.h>
+ #include "megaraid_sas.h"
  
- static int iscsi_tcp_get_addr(struct iscsi_conn *conn, struct socket *sock,
-@@ -1967,7 +1670,7 @@ iscsi_tcp_conn_bind(struct iscsi_cls_session *cls_session,
- 	/*
- 	 * set receive state machine into initial state
- 	 */
--	tcp_conn->in_progress = IN_PROGRESS_WAIT_HEADER;
-+	iscsi_tcp_hdr_recv_prep(tcp_conn);
- 	return 0;
++/*
++ * poll_mode_io:1- schedule complete completion from q cmd
++ */
++static unsigned int poll_mode_io;
++module_param_named(poll_mode_io, poll_mode_io, int, 0);
++MODULE_PARM_DESC(poll_mode_io,
++	"Complete cmds from IO path, (default=0)");
++
+ MODULE_LICENSE("GPL");
+ MODULE_VERSION(MEGASAS_VERSION);
+ MODULE_AUTHOR("megaraidlinux at lsi.com");
+-MODULE_DESCRIPTION("LSI Logic MegaRAID SAS Driver");
++MODULE_DESCRIPTION("LSI MegaRAID SAS Driver");
  
- free_socket:
-@@ -1977,10 +1680,17 @@ free_socket:
+ /*
+  * PCI ID table for all supported controllers
+@@ -76,6 +85,10 @@ static DEFINE_MUTEX(megasas_async_queue_mutex);
  
- /* called with host lock */
- static void
--iscsi_tcp_mgmt_init(struct iscsi_conn *conn, struct iscsi_mgmt_task *mtask)
-+iscsi_tcp_mtask_init(struct iscsi_conn *conn, struct iscsi_mgmt_task *mtask)
- {
--	struct iscsi_tcp_mgmt_task *tcp_mtask = mtask->dd_data;
--	tcp_mtask->xmstate = 1 << XMSTATE_BIT_IMM_HDR_INIT;
-+	debug_scsi("mtask deq [cid %d itt 0x%x]\n", conn->id, mtask->itt);
+ static u32 megasas_dbg_lvl;
+ 
++static void
++megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd,
++		     u8 alt_status);
 +
-+	/* Prepare PDU, optionally w/ immediate data */
-+	iscsi_tcp_send_hdr_prep(conn, mtask->hdr, sizeof(*mtask->hdr));
+ /**
+  * megasas_get_cmd -	Get a command from the free pool
+  * @instance:		Adapter soft state
+@@ -855,6 +868,12 @@ megasas_queue_command(struct scsi_cmnd *scmd, void (*done) (struct scsi_cmnd *))
+ 	atomic_inc(&instance->fw_outstanding);
+ 
+ 	instance->instancet->fire_cmd(cmd->frame_phys_addr ,cmd->frame_count-1,instance->reg_set);
++	/*
++	 * Check if we have pend cmds to be completed
++	 */
++	if (poll_mode_io && atomic_read(&instance->fw_outstanding))
++		tasklet_schedule(&instance->isr_tasklet);
 +
-+	/* If we have immediate data, attach a payload */
-+	if (mtask->data_count)
-+		iscsi_tcp_send_linear_data_prepare(conn, mtask->data,
-+						   mtask->data_count);
- }
  
- static int
-@@ -2003,8 +1713,7 @@ iscsi_r2tpool_alloc(struct iscsi_session *session)
- 		 */
+ 	return 0;
  
- 		/* R2T pool */
--		if (iscsi_pool_init(&tcp_ctask->r2tpool, session->max_r2t * 4,
--				    (void***)&tcp_ctask->r2ts,
-+		if (iscsi_pool_init(&tcp_ctask->r2tpool, session->max_r2t * 4, NULL,
- 				    sizeof(struct iscsi_r2t_info))) {
- 			goto r2t_alloc_fail;
- 		}
-@@ -2013,8 +1722,7 @@ iscsi_r2tpool_alloc(struct iscsi_session *session)
- 		tcp_ctask->r2tqueue = kfifo_alloc(
- 		      session->max_r2t * 4 * sizeof(void*), GFP_KERNEL, NULL);
- 		if (tcp_ctask->r2tqueue == ERR_PTR(-ENOMEM)) {
--			iscsi_pool_free(&tcp_ctask->r2tpool,
--					(void**)tcp_ctask->r2ts);
-+			iscsi_pool_free(&tcp_ctask->r2tpool);
- 			goto r2t_alloc_fail;
+@@ -886,6 +905,64 @@ static int megasas_slave_configure(struct scsi_device *sdev)
+ }
+ 
+ /**
++ * megasas_complete_cmd_dpc	 -	Returns FW's controller structure
++ * @instance_addr:			Address of adapter soft state
++ *
++ * Tasklet to complete cmds
++ */
++static void megasas_complete_cmd_dpc(unsigned long instance_addr)
++{
++	u32 producer;
++	u32 consumer;
++	u32 context;
++	struct megasas_cmd *cmd;
++	struct megasas_instance *instance =
++				(struct megasas_instance *)instance_addr;
++	unsigned long flags;
++
++	/* If we have already declared adapter dead, donot complete cmds */
++	if (instance->hw_crit_error)
++		return;
++
++	spin_lock_irqsave(&instance->completion_lock, flags);
++
++	producer = *instance->producer;
++	consumer = *instance->consumer;
++
++	while (consumer != producer) {
++		context = instance->reply_queue[consumer];
++
++		cmd = instance->cmd_list[context];
++
++		megasas_complete_cmd(instance, cmd, DID_OK);
++
++		consumer++;
++		if (consumer == (instance->max_fw_cmds + 1)) {
++			consumer = 0;
++		}
++	}
++
++	*instance->consumer = producer;
++
++	spin_unlock_irqrestore(&instance->completion_lock, flags);
++
++	/*
++	 * Check if we can restore can_queue
++	 */
++	if (instance->flag & MEGASAS_FW_BUSY
++		&& time_after(jiffies, instance->last_time + 5 * HZ)
++		&& atomic_read(&instance->fw_outstanding) < 17) {
++
++		spin_lock_irqsave(instance->host->host_lock, flags);
++		instance->flag &= ~MEGASAS_FW_BUSY;
++		instance->host->can_queue =
++				instance->max_fw_cmds - MEGASAS_INT_CMDS;
++
++		spin_unlock_irqrestore(instance->host->host_lock, flags);
++	}
++}
++
++/**
+  * megasas_wait_for_outstanding -	Wait for all outstanding cmds
+  * @instance:				Adapter soft state
+  *
+@@ -908,6 +985,11 @@ static int megasas_wait_for_outstanding(struct megasas_instance *instance)
+ 		if (!(i % MEGASAS_RESET_NOTICE_INTERVAL)) {
+ 			printk(KERN_NOTICE "megasas: [%2d]waiting for %d "
+ 			       "commands to complete\n",i,outstanding);
++			/*
++			 * Call cmd completion routine. Cmd to be
++			 * be completed directly without depending on isr.
++			 */
++			megasas_complete_cmd_dpc((unsigned long)instance);
  		}
- 	}
-@@ -2027,8 +1735,7 @@ r2t_alloc_fail:
- 		struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
  
- 		kfifo_free(tcp_ctask->r2tqueue);
--		iscsi_pool_free(&tcp_ctask->r2tpool,
--				(void**)tcp_ctask->r2ts);
-+		iscsi_pool_free(&tcp_ctask->r2tpool);
- 	}
- 	return -ENOMEM;
- }
-@@ -2043,8 +1750,7 @@ iscsi_r2tpool_free(struct iscsi_session *session)
- 		struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
+ 		msleep(1000);
+@@ -1100,7 +1182,7 @@ megasas_service_aen(struct megasas_instance *instance, struct megasas_cmd *cmd)
+ static struct scsi_host_template megasas_template = {
  
- 		kfifo_free(tcp_ctask->r2tqueue);
--		iscsi_pool_free(&tcp_ctask->r2tpool,
--				(void**)tcp_ctask->r2ts);
-+		iscsi_pool_free(&tcp_ctask->r2tpool);
- 	}
+ 	.module = THIS_MODULE,
+-	.name = "LSI Logic SAS based MegaRAID driver",
++	.name = "LSI SAS based MegaRAID driver",
+ 	.proc_name = "megaraid_sas",
+ 	.slave_configure = megasas_slave_configure,
+ 	.queuecommand = megasas_queue_command,
+@@ -1749,57 +1831,119 @@ megasas_get_ctrl_info(struct megasas_instance *instance,
  }
  
-@@ -2060,9 +1766,6 @@ iscsi_conn_set_param(struct iscsi_cls_conn *cls_conn, enum iscsi_param param,
- 	switch(param) {
- 	case ISCSI_PARAM_HDRDGST_EN:
- 		iscsi_set_param(cls_conn, param, buf, buflen);
--		tcp_conn->hdr_size = sizeof(struct iscsi_hdr);
--		if (conn->hdrdgst_en)
--			tcp_conn->hdr_size += sizeof(__u32);
- 		break;
- 	case ISCSI_PARAM_DATADGST_EN:
- 		iscsi_set_param(cls_conn, param, buf, buflen);
-@@ -2071,12 +1774,12 @@ iscsi_conn_set_param(struct iscsi_cls_conn *cls_conn, enum iscsi_param param,
- 		break;
- 	case ISCSI_PARAM_MAX_R2T:
- 		sscanf(buf, "%d", &value);
--		if (session->max_r2t == roundup_pow_of_two(value))
-+		if (value <= 0 || !is_power_of_2(value))
-+			return -EINVAL;
-+		if (session->max_r2t == value)
- 			break;
- 		iscsi_r2tpool_free(session);
- 		iscsi_set_param(cls_conn, param, buf, buflen);
--		if (session->max_r2t & (session->max_r2t - 1))
--			session->max_r2t = roundup_pow_of_two(session->max_r2t);
- 		if (iscsi_r2tpool_alloc(session))
- 			return -ENOMEM;
- 		break;
-@@ -2183,14 +1886,15 @@ iscsi_tcp_session_create(struct iscsi_transport *iscsit,
- 		struct iscsi_cmd_task *ctask = session->cmds[cmd_i];
- 		struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
+ /**
+- * megasas_complete_cmd_dpc	 -	Returns FW's controller structure
+- * @instance_addr:			Address of adapter soft state
++ * megasas_issue_init_mfi -	Initializes the FW
++ * @instance:		Adapter soft state
+  *
+- * Tasklet to complete cmds
++ * Issues the INIT MFI cmd
+  */
+-static void megasas_complete_cmd_dpc(unsigned long instance_addr)
++static int
++megasas_issue_init_mfi(struct megasas_instance *instance)
+ {
+-	u32 producer;
+-	u32 consumer;
+ 	u32 context;
++
+ 	struct megasas_cmd *cmd;
+-	struct megasas_instance *instance = (struct megasas_instance *)instance_addr;
+-	unsigned long flags;
  
--		ctask->hdr = &tcp_ctask->hdr;
-+		ctask->hdr = &tcp_ctask->hdr.cmd_hdr;
-+		ctask->hdr_max = sizeof(tcp_ctask->hdr) - ISCSI_DIGEST_SIZE;
- 	}
+-	/* If we have already declared adapter dead, donot complete cmds */
+-	if (instance->hw_crit_error)
+-		return;
++	struct megasas_init_frame *init_frame;
++	struct megasas_init_queue_info *initq_info;
++	dma_addr_t init_frame_h;
++	dma_addr_t initq_info_h;
  
- 	for (cmd_i = 0; cmd_i < session->mgmtpool_max; cmd_i++) {
- 		struct iscsi_mgmt_task *mtask = session->mgmt_cmds[cmd_i];
- 		struct iscsi_tcp_mgmt_task *tcp_mtask = mtask->dd_data;
+-	producer = *instance->producer;
+-	consumer = *instance->consumer;
++	/*
++	 * Prepare a init frame. Note the init frame points to queue info
++	 * structure. Each frame has SGL allocated after first 64 bytes. For
++	 * this frame - since we don't need any SGL - we use SGL's space as
++	 * queue info structure
++	 *
++	 * We will not get a NULL command below. We just created the pool.
++	 */
++	cmd = megasas_get_cmd(instance);
  
--		mtask->hdr = &tcp_mtask->hdr;
-+		mtask->hdr = (struct iscsi_hdr *) &tcp_mtask->hdr;
- 	}
+-	while (consumer != producer) {
+-		context = instance->reply_queue[consumer];
++	init_frame = (struct megasas_init_frame *)cmd->frame;
++	initq_info = (struct megasas_init_queue_info *)
++		((unsigned long)init_frame + 64);
  
- 	if (iscsi_r2tpool_alloc(class_to_transport_session(cls_session)))
-@@ -2222,12 +1926,14 @@ static struct scsi_host_template iscsi_sht = {
- 	.queuecommand           = iscsi_queuecommand,
- 	.change_queue_depth	= iscsi_change_queue_depth,
- 	.can_queue		= ISCSI_DEF_XMIT_CMDS_MAX - 1,
--	.sg_tablesize		= ISCSI_SG_TABLESIZE,
-+	.sg_tablesize		= 4096,
- 	.max_sectors		= 0xFFFF,
- 	.cmd_per_lun		= ISCSI_DEF_CMD_PER_LUN,
- 	.eh_abort_handler       = iscsi_eh_abort,
-+	.eh_device_reset_handler= iscsi_eh_device_reset,
- 	.eh_host_reset_handler	= iscsi_eh_host_reset,
- 	.use_clustering         = DISABLE_CLUSTERING,
-+	.use_sg_chaining	= ENABLE_SG_CHAINING,
- 	.slave_configure        = iscsi_tcp_slave_configure,
- 	.proc_name		= "iscsi_tcp",
- 	.this_id		= -1,
-@@ -2257,14 +1963,17 @@ static struct iscsi_transport iscsi_tcp_transport = {
- 				  ISCSI_PERSISTENT_ADDRESS |
- 				  ISCSI_TARGET_NAME | ISCSI_TPGT |
- 				  ISCSI_USERNAME | ISCSI_PASSWORD |
--				  ISCSI_USERNAME_IN | ISCSI_PASSWORD_IN,
-+				  ISCSI_USERNAME_IN | ISCSI_PASSWORD_IN |
-+				  ISCSI_FAST_ABORT | ISCSI_ABORT_TMO |
-+				  ISCSI_LU_RESET_TMO |
-+				  ISCSI_PING_TMO | ISCSI_RECV_TMO,
- 	.host_param_mask	= ISCSI_HOST_HWADDRESS | ISCSI_HOST_IPADDRESS |
- 				  ISCSI_HOST_INITIATOR_NAME |
- 				  ISCSI_HOST_NETDEV_NAME,
- 	.host_template		= &iscsi_sht,
- 	.conndata_size		= sizeof(struct iscsi_conn),
- 	.max_conn		= 1,
--	.max_cmd_len		= ISCSI_TCP_MAX_CMD_LEN,
-+	.max_cmd_len		= 16,
- 	/* session management */
- 	.create_session		= iscsi_tcp_session_create,
- 	.destroy_session	= iscsi_tcp_session_destroy,
-@@ -2283,8 +1992,8 @@ static struct iscsi_transport iscsi_tcp_transport = {
- 	/* IO */
- 	.send_pdu		= iscsi_conn_send_pdu,
- 	.get_stats		= iscsi_conn_get_stats,
--	.init_cmd_task		= iscsi_tcp_cmd_init,
--	.init_mgmt_task		= iscsi_tcp_mgmt_init,
-+	.init_cmd_task		= iscsi_tcp_ctask_init,
-+	.init_mgmt_task		= iscsi_tcp_mtask_init,
- 	.xmit_cmd_task		= iscsi_tcp_ctask_xmit,
- 	.xmit_mgmt_task		= iscsi_tcp_mtask_xmit,
- 	.cleanup_cmd_task	= iscsi_tcp_cleanup_ctask,
-diff --git a/drivers/scsi/iscsi_tcp.h b/drivers/scsi/iscsi_tcp.h
-index 68c36cc..ed0b991 100644
---- a/drivers/scsi/iscsi_tcp.h
-+++ b/drivers/scsi/iscsi_tcp.h
-@@ -24,71 +24,61 @@
+-		cmd = instance->cmd_list[context];
++	init_frame_h = cmd->frame_phys_addr;
++	initq_info_h = init_frame_h + 64;
  
- #include <scsi/libiscsi.h>
+-		megasas_complete_cmd(instance, cmd, DID_OK);
++	context = init_frame->context;
++	memset(init_frame, 0, MEGAMFI_FRAME_SIZE);
++	memset(initq_info, 0, sizeof(struct megasas_init_queue_info));
++	init_frame->context = context;
  
--/* Socket's Receive state machine */
--#define IN_PROGRESS_WAIT_HEADER		0x0
--#define IN_PROGRESS_HEADER_GATHER	0x1
--#define IN_PROGRESS_DATA_RECV		0x2
--#define IN_PROGRESS_DDIGEST_RECV	0x3
--#define IN_PROGRESS_PAD_RECV		0x4
--
--/* xmit state machine */
--#define XMSTATE_VALUE_IDLE			0
--#define XMSTATE_BIT_CMD_HDR_INIT		0
--#define XMSTATE_BIT_CMD_HDR_XMIT		1
--#define XMSTATE_BIT_IMM_HDR			2
--#define XMSTATE_BIT_IMM_DATA			3
--#define XMSTATE_BIT_UNS_INIT			4
--#define XMSTATE_BIT_UNS_HDR			5
--#define XMSTATE_BIT_UNS_DATA			6
--#define XMSTATE_BIT_SOL_HDR			7
--#define XMSTATE_BIT_SOL_DATA			8
--#define XMSTATE_BIT_W_PAD			9
--#define XMSTATE_BIT_W_RESEND_PAD		10
--#define XMSTATE_BIT_W_RESEND_DATA_DIGEST	11
--#define XMSTATE_BIT_IMM_HDR_INIT		12
--#define XMSTATE_BIT_SOL_HDR_INIT		13
--
--#define ISCSI_PAD_LEN			4
--#define ISCSI_SG_TABLESIZE		SG_ALL
--#define ISCSI_TCP_MAX_CMD_LEN		16
--
- struct crypto_hash;
- struct socket;
-+struct iscsi_tcp_conn;
-+struct iscsi_segment;
+-		consumer++;
+-		if (consumer == (instance->max_fw_cmds + 1)) {
+-			consumer = 0;
+-		}
+-	}
++	initq_info->reply_queue_entries = instance->max_fw_cmds + 1;
++	initq_info->reply_queue_start_phys_addr_lo = instance->reply_queue_h;
+ 
+-	*instance->consumer = producer;
++	initq_info->producer_index_phys_addr_lo = instance->producer_h;
++	initq_info->consumer_index_phys_addr_lo = instance->consumer_h;
 +
-+typedef int iscsi_segment_done_fn_t(struct iscsi_tcp_conn *,
-+				    struct iscsi_segment *);
++	init_frame->cmd = MFI_CMD_INIT;
++	init_frame->cmd_status = 0xFF;
++	init_frame->queue_info_new_phys_addr_lo = initq_info_h;
 +
-+struct iscsi_segment {
-+	unsigned char		*data;
-+	unsigned int		size;
-+	unsigned int		copied;
-+	unsigned int		total_size;
-+	unsigned int		total_copied;
++	init_frame->data_xfer_len = sizeof(struct megasas_init_queue_info);
+ 
+ 	/*
+-	 * Check if we can restore can_queue
++	 * disable the intr before firing the init frame to FW
+ 	 */
+-	if (instance->flag & MEGASAS_FW_BUSY
+-		&& time_after(jiffies, instance->last_time + 5 * HZ)
+-		&& atomic_read(&instance->fw_outstanding) < 17) {
++	instance->instancet->disable_intr(instance->reg_set);
+ 
+-		spin_lock_irqsave(instance->host->host_lock, flags);
+-		instance->flag &= ~MEGASAS_FW_BUSY;
+-		instance->host->can_queue =
+-				instance->max_fw_cmds - MEGASAS_INT_CMDS;
++	/*
++	 * Issue the init frame in polled mode
++	 */
+ 
+-		spin_unlock_irqrestore(instance->host->host_lock, flags);
++	if (megasas_issue_polled(instance, cmd)) {
++		printk(KERN_ERR "megasas: Failed to init firmware\n");
++		megasas_return_cmd(instance, cmd);
++		goto fail_fw_init;
+ 	}
+ 
++	megasas_return_cmd(instance, cmd);
 +
-+	struct hash_desc	*hash;
-+	unsigned char		recv_digest[ISCSI_DIGEST_SIZE];
-+	unsigned char		digest[ISCSI_DIGEST_SIZE];
-+	unsigned int		digest_len;
++	return 0;
++
++fail_fw_init:
++	return -EINVAL;
++}
++
++/**
++ * megasas_start_timer - Initializes a timer object
++ * @instance:		Adapter soft state
++ * @timer:		timer object to be initialized
++ * @fn:			timer function
++ * @interval:		time interval between timer function call
++ */
++static inline void
++megasas_start_timer(struct megasas_instance *instance,
++			struct timer_list *timer,
++			void *fn, unsigned long interval)
++{
++	init_timer(timer);
++	timer->expires = jiffies + interval;
++	timer->data = (unsigned long)instance;
++	timer->function = fn;
++	add_timer(timer);
++}
++
++/**
++ * megasas_io_completion_timer - Timer fn
++ * @instance_addr:	Address of adapter soft state
++ *
++ * Schedules tasklet for cmd completion
++ * if poll_mode_io is set
++ */
++static void
++megasas_io_completion_timer(unsigned long instance_addr)
++{
++	struct megasas_instance *instance =
++			(struct megasas_instance *)instance_addr;
 +
-+	struct scatterlist	*sg;
-+	void			*sg_mapped;
-+	unsigned int		sg_offset;
++	if (atomic_read(&instance->fw_outstanding))
++		tasklet_schedule(&instance->isr_tasklet);
 +
-+	iscsi_segment_done_fn_t	*done;
-+};
++	/* Restart timer */
++	if (poll_mode_io)
++		mod_timer(&instance->io_completion_timer,
++			jiffies + MEGASAS_COMPLETION_TIMER_INTERVAL);
+ }
  
- /* Socket connection recieve helper */
- struct iscsi_tcp_recv {
- 	struct iscsi_hdr	*hdr;
--	struct sk_buff		*skb;
--	int			offset;
--	int			len;
--	int			hdr_offset;
--	int			copy;
--	int			copied;
--	int			padding;
--	struct iscsi_cmd_task	*ctask;		/* current cmd in progress */
-+	struct iscsi_segment	segment;
-+
-+	/* Allocate buffer for BHS + AHS */
-+	uint32_t		hdr_buf[64];
+ /**
+@@ -1814,22 +1958,15 @@ static int megasas_init_mfi(struct megasas_instance *instance)
+ 	u32 reply_q_sz;
+ 	u32 max_sectors_1;
+ 	u32 max_sectors_2;
++	u32 tmp_sectors;
+ 	struct megasas_register_set __iomem *reg_set;
+-
+-	struct megasas_cmd *cmd;
+ 	struct megasas_ctrl_info *ctrl_info;
+-
+-	struct megasas_init_frame *init_frame;
+-	struct megasas_init_queue_info *initq_info;
+-	dma_addr_t init_frame_h;
+-	dma_addr_t initq_info_h;
+-
+ 	/*
+ 	 * Map the message registers
+ 	 */
+ 	instance->base_addr = pci_resource_start(instance->pdev, 0);
  
- 	/* copied and flipped values */
- 	int			datalen;
--	int			datadgst;
--	char			zero_copy_hdr;
-+};
-+
-+/* Socket connection send helper */
-+struct iscsi_tcp_send {
-+	struct iscsi_hdr	*hdr;
-+	struct iscsi_segment	segment;
-+	struct iscsi_segment	data_segment;
- };
+-	if (pci_request_regions(instance->pdev, "megasas: LSI Logic")) {
++	if (pci_request_regions(instance->pdev, "megasas: LSI")) {
+ 		printk(KERN_DEBUG "megasas: IO memory region busy!\n");
+ 		return -EBUSY;
+ 	}
+@@ -1900,52 +2037,8 @@ static int megasas_init_mfi(struct megasas_instance *instance)
+ 		goto fail_reply_queue;
+ 	}
  
- struct iscsi_tcp_conn {
- 	struct iscsi_conn	*iscsi_conn;
- 	struct socket		*sock;
--	struct iscsi_hdr	hdr;		/* header placeholder */
--	char			hdrext[4*sizeof(__u16) +
--				    sizeof(__u32)];
--	int			data_copied;
- 	int			stop_stage;	/* conn_stop() flag: *
- 						 * stop to recover,  *
- 						 * stop to terminate */
--	/* iSCSI connection-wide sequencing */
--	int			hdr_size;	/* PDU header size */
+-	/*
+-	 * Prepare a init frame. Note the init frame points to queue info
+-	 * structure. Each frame has SGL allocated after first 64 bytes. For
+-	 * this frame - since we don't need any SGL - we use SGL's space as
+-	 * queue info structure
+-	 *
+-	 * We will not get a NULL command below. We just created the pool.
+-	 */
+-	cmd = megasas_get_cmd(instance);
 -
- 	/* control data */
- 	struct iscsi_tcp_recv	in;		/* TCP receive context */
--	int			in_progress;	/* connection state machine */
-+	struct iscsi_tcp_send	out;		/* TCP send context */
+-	init_frame = (struct megasas_init_frame *)cmd->frame;
+-	initq_info = (struct megasas_init_queue_info *)
+-	    ((unsigned long)init_frame + 64);
+-
+-	init_frame_h = cmd->frame_phys_addr;
+-	initq_info_h = init_frame_h + 64;
+-
+-	memset(init_frame, 0, MEGAMFI_FRAME_SIZE);
+-	memset(initq_info, 0, sizeof(struct megasas_init_queue_info));
+-
+-	initq_info->reply_queue_entries = instance->max_fw_cmds + 1;
+-	initq_info->reply_queue_start_phys_addr_lo = instance->reply_queue_h;
+-
+-	initq_info->producer_index_phys_addr_lo = instance->producer_h;
+-	initq_info->consumer_index_phys_addr_lo = instance->consumer_h;
+-
+-	init_frame->cmd = MFI_CMD_INIT;
+-	init_frame->cmd_status = 0xFF;
+-	init_frame->queue_info_new_phys_addr_lo = initq_info_h;
+-
+-	init_frame->data_xfer_len = sizeof(struct megasas_init_queue_info);
+-
+-	/*
+-	 * disable the intr before firing the init frame to FW
+-	 */
+-	instance->instancet->disable_intr(instance->reg_set);
+-
+-	/*
+-	 * Issue the init frame in polled mode
+-	 */
+-	if (megasas_issue_polled(instance, cmd)) {
+-		printk(KERN_DEBUG "megasas: Failed to init firmware\n");
++	if (megasas_issue_init_mfi(instance))
+ 		goto fail_fw_init;
+-	}
+-
+-	megasas_return_cmd(instance, cmd);
  
- 	/* old values for socket callbacks */
- 	void			(*old_data_ready)(struct sock *, int);
-@@ -103,29 +93,19 @@ struct iscsi_tcp_conn {
- 	uint32_t		sendpage_failures_cnt;
- 	uint32_t		discontiguous_hdr_cnt;
+ 	ctrl_info = kmalloc(sizeof(struct megasas_ctrl_info), GFP_KERNEL);
  
--	ssize_t (*sendpage)(struct socket *, struct page *, int, size_t, int);
--};
-+	int			error;
+@@ -1958,17 +2051,20 @@ static int megasas_init_mfi(struct megasas_instance *instance)
+ 	 * Note that older firmwares ( < FW ver 30) didn't report information
+ 	 * to calculate max_sectors_1. So the number ended up as zero always.
+ 	 */
++	tmp_sectors = 0;
+ 	if (ctrl_info && !megasas_get_ctrl_info(instance, ctrl_info)) {
  
--struct iscsi_buf {
--	struct scatterlist	sg;
--	unsigned int		sent;
--	char			use_sendmsg;
-+	ssize_t (*sendpage)(struct socket *, struct page *, int, size_t, int);
- };
+ 		max_sectors_1 = (1 << ctrl_info->stripe_sz_ops.min) *
+ 		    ctrl_info->max_strips_per_io;
+ 		max_sectors_2 = ctrl_info->max_request_size;
  
- struct iscsi_data_task {
- 	struct iscsi_data	hdr;			/* PDU */
--	char			hdrext[sizeof(__u32)];	/* Header-Digest */
--	struct iscsi_buf	digestbuf;		/* digest buffer */
--	uint32_t		digest;			/* data digest */
-+	char			hdrext[ISCSI_DIGEST_SIZE];/* Header-Digest */
- };
+-		instance->max_sectors_per_req = (max_sectors_1 < max_sectors_2)
+-		    ? max_sectors_1 : max_sectors_2;
+-	} else
+-		instance->max_sectors_per_req = instance->max_num_sge *
+-		    PAGE_SIZE / 512;
++		tmp_sectors = min_t(u32, max_sectors_1 , max_sectors_2);
++	}
++
++	instance->max_sectors_per_req = instance->max_num_sge *
++						PAGE_SIZE / 512;
++	if (tmp_sectors && (instance->max_sectors_per_req > tmp_sectors))
++		instance->max_sectors_per_req = tmp_sectors;
  
- struct iscsi_tcp_mgmt_task {
- 	struct iscsi_hdr	hdr;
--	char			hdrext[sizeof(__u32)]; /* Header-Digest */
--	unsigned long		xmstate;	/* mgmt xmit progress */
--	struct iscsi_buf	headbuf;	/* header buffer */
--	struct iscsi_buf	sendbuf;	/* in progress buffer */
--	int			sent;
-+	char			hdrext[ISCSI_DIGEST_SIZE]; /* Header-Digest */
- };
+ 	kfree(ctrl_info);
  
- struct iscsi_r2t_info {
-@@ -133,38 +113,26 @@ struct iscsi_r2t_info {
- 	__be32			exp_statsn;	/* copied from R2T */
- 	uint32_t		data_length;	/* copied from R2T */
- 	uint32_t		data_offset;	/* copied from R2T */
--	struct iscsi_buf	headbuf;	/* Data-Out Header Buffer */
--	struct iscsi_buf	sendbuf;	/* Data-Out in progress buffer*/
- 	int			sent;		/* R2T sequence progress */
- 	int			data_count;	/* DATA-Out payload progress */
--	struct scatterlist	*sg;		/* per-R2T SG list */
- 	int			solicit_datasn;
--	struct iscsi_data_task   dtask;        /* which data task */
-+	struct iscsi_data_task	dtask;		/* Data-Out header buf */
- };
+@@ -1976,12 +2072,17 @@ static int megasas_init_mfi(struct megasas_instance *instance)
+ 	* Setup tasklet for cmd completion
+ 	*/
  
- struct iscsi_tcp_cmd_task {
--	struct iscsi_cmd	hdr;
--	char			hdrext[4*sizeof(__u16)+	/* AHS */
--				    sizeof(__u32)];	/* HeaderDigest */
--	char			pad[ISCSI_PAD_LEN];
--	int			pad_count;		/* padded bytes */
--	struct iscsi_buf	headbuf;		/* header buf (xmit) */
--	struct iscsi_buf	sendbuf;		/* in progress buffer*/
--	unsigned long		xmstate;		/* xmit xtate machine */
-+	struct iscsi_hdr_buff {
-+		struct iscsi_cmd	cmd_hdr;
-+		char			hdrextbuf[ISCSI_MAX_AHS_SIZE +
-+		                                  ISCSI_DIGEST_SIZE];
-+	} hdr;
+-        tasklet_init(&instance->isr_tasklet, megasas_complete_cmd_dpc,
+-                        (unsigned long)instance);
++	tasklet_init(&instance->isr_tasklet, megasas_complete_cmd_dpc,
++		(unsigned long)instance);
 +
- 	int			sent;
--	struct scatterlist	*sg;			/* per-cmd SG list  */
--	struct scatterlist	*bad_sg;		/* assert statement */
--	int			sg_count;		/* SG's to process  */
--	uint32_t		exp_datasn;		/* expected target's R2TSN/DataSN */
-+	uint32_t		exp_datasn;	/* expected target's R2TSN/DataSN */
- 	int			data_offset;
--	struct iscsi_r2t_info	*r2t;			/* in progress R2T    */
--	struct iscsi_queue	r2tpool;
-+	struct iscsi_r2t_info	*r2t;		/* in progress R2T    */
-+	struct iscsi_pool	r2tpool;
- 	struct kfifo		*r2tqueue;
--	struct iscsi_r2t_info	**r2ts;
--	int			digest_count;
--	uint32_t		immdigest;		/* for imm data */
--	struct iscsi_buf	immbuf;			/* for imm data digest */
--	struct iscsi_data_task	unsol_dtask;	/* unsol data task */
-+	struct iscsi_data_task	unsol_dtask;	/* Data-Out header buf */
- };
++	/* Initialize the cmd completion timer */
++	if (poll_mode_io)
++		megasas_start_timer(instance, &instance->io_completion_timer,
++				megasas_io_completion_timer,
++				MEGASAS_COMPLETION_TIMER_INTERVAL);
+ 	return 0;
  
- #endif /* ISCSI_H */
-diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
-index 8b57af5..553168a 100644
---- a/drivers/scsi/libiscsi.c
-+++ b/drivers/scsi/libiscsi.c
-@@ -24,6 +24,7 @@
- #include <linux/types.h>
- #include <linux/kfifo.h>
- #include <linux/delay.h>
-+#include <linux/log2.h>
- #include <asm/unaligned.h>
- #include <net/tcp.h>
- #include <scsi/scsi_cmnd.h>
-@@ -86,7 +87,7 @@ iscsi_update_cmdsn(struct iscsi_session *session, struct iscsi_nopin *hdr)
- 		 * xmit thread
- 		 */
- 		if (!list_empty(&session->leadconn->xmitqueue) ||
--		    __kfifo_len(session->leadconn->mgmtqueue))
-+		    !list_empty(&session->leadconn->mgmtqueue))
- 			scsi_queue_work(session->host,
- 					&session->leadconn->xmitwork);
- 	}
-@@ -122,6 +123,20 @@ void iscsi_prep_unsolicit_data_pdu(struct iscsi_cmd_task *ctask,
+       fail_fw_init:
+-	megasas_return_cmd(instance, cmd);
+ 
+ 	pci_free_consistent(instance->pdev, reply_q_sz,
+ 			    instance->reply_queue, instance->reply_queue_h);
+@@ -2263,6 +2364,28 @@ static int megasas_io_attach(struct megasas_instance *instance)
+ 	return 0;
  }
- EXPORT_SYMBOL_GPL(iscsi_prep_unsolicit_data_pdu);
  
-+static int iscsi_add_hdr(struct iscsi_cmd_task *ctask, unsigned len)
++static int
++megasas_set_dma_mask(struct pci_dev *pdev)
 +{
-+	unsigned exp_len = ctask->hdr_len + len;
++	/*
++	 * All our contollers are capable of performing 64-bit DMA
++	 */
++	if (IS_DMA64) {
++		if (pci_set_dma_mask(pdev, DMA_64BIT_MASK) != 0) {
 +
-+	if (exp_len > ctask->hdr_max) {
-+		WARN_ON(1);
-+		return -EINVAL;
++			if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) != 0)
++				goto fail_set_dma_mask;
++		}
++	} else {
++		if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) != 0)
++			goto fail_set_dma_mask;
 +	}
-+
-+	WARN_ON(len & (ISCSI_PAD_LEN - 1)); /* caller must pad the AHS */
-+	ctask->hdr_len = exp_len;
 +	return 0;
++
++fail_set_dma_mask:
++	return 1;
 +}
 +
  /**
-  * iscsi_prep_scsi_cmd_pdu - prep iscsi scsi cmd pdu
-  * @ctask: iscsi cmd task
-@@ -129,27 +144,32 @@ EXPORT_SYMBOL_GPL(iscsi_prep_unsolicit_data_pdu);
-  * Prep basic iSCSI PDU fields for a scsi cmd pdu. The LLD should set
-  * fields like dlength or final based on how much data it sends
-  */
--static void iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask)
-+static int iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask)
- {
- 	struct iscsi_conn *conn = ctask->conn;
- 	struct iscsi_session *session = conn->session;
- 	struct iscsi_cmd *hdr = ctask->hdr;
- 	struct scsi_cmnd *sc = ctask->sc;
-+	unsigned hdrlength;
-+	int rc;
- 
--        hdr->opcode = ISCSI_OP_SCSI_CMD;
--        hdr->flags = ISCSI_ATTR_SIMPLE;
--        int_to_scsilun(sc->device->lun, (struct scsi_lun *)hdr->lun);
--        hdr->itt = build_itt(ctask->itt, conn->id, session->age);
--        hdr->data_length = cpu_to_be32(scsi_bufflen(sc));
--        hdr->cmdsn = cpu_to_be32(session->cmdsn);
--        session->cmdsn++;
--        hdr->exp_statsn = cpu_to_be32(conn->exp_statsn);
--        memcpy(hdr->cdb, sc->cmnd, sc->cmd_len);
-+	ctask->hdr_len = 0;
-+	rc = iscsi_add_hdr(ctask, sizeof(*hdr));
-+	if (rc)
-+		return rc;
-+	hdr->opcode = ISCSI_OP_SCSI_CMD;
-+	hdr->flags = ISCSI_ATTR_SIMPLE;
-+	int_to_scsilun(sc->device->lun, (struct scsi_lun *)hdr->lun);
-+	hdr->itt = build_itt(ctask->itt, conn->id, session->age);
-+	hdr->data_length = cpu_to_be32(scsi_bufflen(sc));
-+	hdr->cmdsn = cpu_to_be32(session->cmdsn);
-+	session->cmdsn++;
-+	hdr->exp_statsn = cpu_to_be32(conn->exp_statsn);
-+	memcpy(hdr->cdb, sc->cmnd, sc->cmd_len);
- 	if (sc->cmd_len < MAX_COMMAND_SIZE)
- 		memset(&hdr->cdb[sc->cmd_len], 0,
- 			MAX_COMMAND_SIZE - sc->cmd_len);
+  * megasas_probe_one -	PCI hotplug entry point
+  * @pdev:		PCI device structure
+@@ -2296,19 +2419,8 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
  
--	ctask->data_count = 0;
- 	ctask->imm_count = 0;
- 	if (sc->sc_data_direction == DMA_TO_DEVICE) {
- 		hdr->flags |= ISCSI_FLAG_CMD_WRITE;
-@@ -178,9 +198,9 @@ static void iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask)
- 			else
- 				ctask->imm_count = min(scsi_bufflen(sc),
- 							conn->max_xmit_dlength);
--			hton24(ctask->hdr->dlength, ctask->imm_count);
-+			hton24(hdr->dlength, ctask->imm_count);
- 		} else
--			zero_data(ctask->hdr->dlength);
-+			zero_data(hdr->dlength);
+ 	pci_set_master(pdev);
  
- 		if (!session->initial_r2t_en) {
- 			ctask->unsol_count = min((session->first_burst),
-@@ -190,7 +210,7 @@ static void iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask)
+-	/*
+-	 * All our contollers are capable of performing 64-bit DMA
+-	 */
+-	if (IS_DMA64) {
+-		if (pci_set_dma_mask(pdev, DMA_64BIT_MASK) != 0) {
+-
+-			if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) != 0)
+-				goto fail_set_dma_mask;
+-		}
+-	} else {
+-		if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) != 0)
+-			goto fail_set_dma_mask;
+-	}
++	if (megasas_set_dma_mask(pdev))
++		goto fail_set_dma_mask;
  
- 		if (!ctask->unsol_count)
- 			/* No unsolicit Data-Out's */
--			ctask->hdr->flags |= ISCSI_FLAG_CMD_FINAL;
-+			hdr->flags |= ISCSI_FLAG_CMD_FINAL;
- 	} else {
- 		hdr->flags |= ISCSI_FLAG_CMD_FINAL;
- 		zero_data(hdr->dlength);
-@@ -199,13 +219,25 @@ static void iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask)
- 			hdr->flags |= ISCSI_FLAG_CMD_READ;
- 	}
+ 	host = scsi_host_alloc(&megasas_template,
+ 			       sizeof(struct megasas_instance));
+@@ -2357,8 +2469,9 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
+ 	init_waitqueue_head(&instance->abort_cmd_wait_q);
  
--	conn->scsicmd_pdus_cnt++;
-+	/* calculate size of additional header segments (AHSs) */
-+	hdrlength = ctask->hdr_len - sizeof(*hdr);
-+
-+	WARN_ON(hdrlength & (ISCSI_PAD_LEN-1));
-+	hdrlength /= ISCSI_PAD_LEN;
-+
-+	WARN_ON(hdrlength >= 256);
-+	hdr->hlength = hdrlength & 0xFF;
-+
-+	if (conn->session->tt->init_cmd_task(conn->ctask))
-+		return EIO;
+ 	spin_lock_init(&instance->cmd_pool_lock);
++	spin_lock_init(&instance->completion_lock);
  
--        debug_scsi("iscsi prep [%s cid %d sc %p cdb 0x%x itt 0x%x len %d "
-+	conn->scsicmd_pdus_cnt++;
-+	debug_scsi("iscsi prep [%s cid %d sc %p cdb 0x%x itt 0x%x len %d "
- 		"cmdsn %d win %d]\n",
--                sc->sc_data_direction == DMA_TO_DEVICE ? "write" : "read",
-+		sc->sc_data_direction == DMA_TO_DEVICE ? "write" : "read",
- 		conn->id, sc, sc->cmnd[0], ctask->itt, scsi_bufflen(sc),
--                session->cmdsn, session->max_cmdsn - session->exp_cmdsn + 1);
-+		session->cmdsn, session->max_cmdsn - session->exp_cmdsn + 1);
-+	return 0;
- }
+-	sema_init(&instance->aen_mutex, 1);
++	mutex_init(&instance->aen_mutex);
+ 	sema_init(&instance->ioctl_sem, MEGASAS_INT_CMDS);
  
+ 	/*
+@@ -2490,8 +2603,10 @@ static void megasas_flush_cache(struct megasas_instance *instance)
  /**
-@@ -218,13 +250,16 @@ static void iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask)
+  * megasas_shutdown_controller -	Instructs FW to shutdown the controller
+  * @instance:				Adapter soft state
++ * @opcode:				Shutdown/Hibernate
   */
- static void iscsi_complete_command(struct iscsi_cmd_task *ctask)
+-static void megasas_shutdown_controller(struct megasas_instance *instance)
++static void megasas_shutdown_controller(struct megasas_instance *instance,
++					u32 opcode)
  {
--	struct iscsi_session *session = ctask->conn->session;
-+	struct iscsi_conn *conn = ctask->conn;
-+	struct iscsi_session *session = conn->session;
- 	struct scsi_cmnd *sc = ctask->sc;
+ 	struct megasas_cmd *cmd;
+ 	struct megasas_dcmd_frame *dcmd;
+@@ -2514,7 +2629,7 @@ static void megasas_shutdown_controller(struct megasas_instance *instance)
+ 	dcmd->flags = MFI_FRAME_DIR_NONE;
+ 	dcmd->timeout = 0;
+ 	dcmd->data_xfer_len = 0;
+-	dcmd->opcode = MR_DCMD_CTRL_SHUTDOWN;
++	dcmd->opcode = opcode;
  
- 	ctask->state = ISCSI_TASK_COMPLETED;
- 	ctask->sc = NULL;
- 	/* SCSI eh reuses commands to verify us */
- 	sc->SCp.ptr = NULL;
-+	if (conn->ctask == ctask)
-+		conn->ctask = NULL;
- 	list_del_init(&ctask->running);
- 	__kfifo_put(session->cmdpool.queue, (void*)&ctask, sizeof(void*));
- 	sc->scsi_done(sc);
-@@ -241,6 +276,112 @@ static void __iscsi_put_ctask(struct iscsi_cmd_task *ctask)
- 		iscsi_complete_command(ctask);
+ 	megasas_issue_blocked_cmd(instance, cmd);
+ 
+@@ -2524,6 +2639,139 @@ static void megasas_shutdown_controller(struct megasas_instance *instance)
  }
  
-+/*
-+ * session lock must be held
+ /**
++ * megasas_suspend -	driver suspend entry point
++ * @pdev:		PCI device structure
++ * @state:		PCI power state to suspend routine
 + */
-+static void fail_command(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask,
-+			 int err)
++static int __devinit
++megasas_suspend(struct pci_dev *pdev, pm_message_t state)
 +{
-+	struct scsi_cmnd *sc;
++	struct Scsi_Host *host;
++	struct megasas_instance *instance;
 +
-+	sc = ctask->sc;
-+	if (!sc)
-+		return;
++	instance = pci_get_drvdata(pdev);
++	host = instance->host;
 +
-+	if (ctask->state == ISCSI_TASK_PENDING)
-+		/*
-+		 * cmd never made it to the xmit thread, so we should not count
-+		 * the cmd in the sequencing
-+		 */
-+		conn->session->queued_cmdsn--;
-+	else
-+		conn->session->tt->cleanup_cmd_task(conn, ctask);
++	if (poll_mode_io)
++		del_timer_sync(&instance->io_completion_timer);
 +
-+	sc->result = err;
-+	scsi_set_resid(sc, scsi_bufflen(sc));
-+	if (conn->ctask == ctask)
-+		conn->ctask = NULL;
-+	/* release ref from queuecommand */
-+	__iscsi_put_ctask(ctask);
++	megasas_flush_cache(instance);
++	megasas_shutdown_controller(instance, MR_DCMD_HIBERNATE_SHUTDOWN);
++	tasklet_kill(&instance->isr_tasklet);
++
++	pci_set_drvdata(instance->pdev, instance);
++	instance->instancet->disable_intr(instance->reg_set);
++	free_irq(instance->pdev->irq, instance);
++
++	pci_save_state(pdev);
++	pci_disable_device(pdev);
++
++	pci_set_power_state(pdev, pci_choose_state(pdev, state));
++
++	return 0;
 +}
 +
 +/**
-+ * iscsi_free_mgmt_task - return mgmt task back to pool
-+ * @conn: iscsi connection
-+ * @mtask: mtask
-+ *
-+ * Must be called with session lock.
++ * megasas_resume-      driver resume entry point
++ * @pdev:               PCI device structure
 + */
-+void iscsi_free_mgmt_task(struct iscsi_conn *conn,
-+			  struct iscsi_mgmt_task *mtask)
++static int __devinit
++megasas_resume(struct pci_dev *pdev)
 +{
-+	list_del_init(&mtask->running);
-+	if (conn->login_mtask == mtask)
-+		return;
++	int rval;
++	struct Scsi_Host *host;
++	struct megasas_instance *instance;
 +
-+	if (conn->ping_mtask == mtask)
-+		conn->ping_mtask = NULL;
-+	__kfifo_put(conn->session->mgmtpool.queue,
-+		    (void*)&mtask, sizeof(void*));
-+}
-+EXPORT_SYMBOL_GPL(iscsi_free_mgmt_task);
++	instance = pci_get_drvdata(pdev);
++	host = instance->host;
++	pci_set_power_state(pdev, PCI_D0);
++	pci_enable_wake(pdev, PCI_D0, 0);
++	pci_restore_state(pdev);
 +
-+static struct iscsi_mgmt_task *
-+__iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
-+		      char *data, uint32_t data_size)
-+{
-+	struct iscsi_session *session = conn->session;
-+	struct iscsi_mgmt_task *mtask;
++	/*
++	 * PCI prepping: enable device set bus mastering and dma mask
++	 */
++	rval = pci_enable_device(pdev);
 +
-+	if (session->state == ISCSI_STATE_TERMINATE)
-+		return NULL;
++	if (rval) {
++		printk(KERN_ERR "megasas: Enable device failed\n");
++		return rval;
++	}
 +
-+	if (hdr->opcode == (ISCSI_OP_LOGIN | ISCSI_OP_IMMEDIATE) ||
-+	    hdr->opcode == (ISCSI_OP_TEXT | ISCSI_OP_IMMEDIATE))
-+		/*
-+		 * Login and Text are sent serially, in
-+		 * request-followed-by-response sequence.
-+		 * Same mtask can be used. Same ITT must be used.
-+		 * Note that login_mtask is preallocated at conn_create().
-+		 */
-+		mtask = conn->login_mtask;
-+	else {
-+		BUG_ON(conn->c_stage == ISCSI_CONN_INITIAL_STAGE);
-+		BUG_ON(conn->c_stage == ISCSI_CONN_STOPPED);
++	pci_set_master(pdev);
 +
-+		if (!__kfifo_get(session->mgmtpool.queue,
-+				 (void*)&mtask, sizeof(void*)))
-+			return NULL;
++	if (megasas_set_dma_mask(pdev))
++		goto fail_set_dma_mask;
++
++	/*
++	 * Initialize MFI Firmware
++	 */
++
++	*instance->producer = 0;
++	*instance->consumer = 0;
++
++	atomic_set(&instance->fw_outstanding, 0);
++
++	/*
++	 * We expect the FW state to be READY
++	 */
++	if (megasas_transition_to_ready(instance))
++		goto fail_ready_state;
++
++	if (megasas_issue_init_mfi(instance))
++		goto fail_init_mfi;
++
++	tasklet_init(&instance->isr_tasklet, megasas_complete_cmd_dpc,
++			(unsigned long)instance);
++
++	/*
++	 * Register IRQ
++	 */
++	if (request_irq(pdev->irq, megasas_isr, IRQF_SHARED,
++		"megasas", instance)) {
++		printk(KERN_ERR "megasas: Failed to register IRQ\n");
++		goto fail_irq;
 +	}
 +
-+	if (data_size) {
-+		memcpy(mtask->data, data, data_size);
-+		mtask->data_count = data_size;
-+	} else
-+		mtask->data_count = 0;
++	instance->instancet->enable_intr(instance->reg_set);
 +
-+	memcpy(mtask->hdr, hdr, sizeof(struct iscsi_hdr));
-+	INIT_LIST_HEAD(&mtask->running);
-+	list_add_tail(&mtask->running, &conn->mgmtqueue);
-+	return mtask;
-+}
++	/*
++	 * Initiate AEN (Asynchronous Event Notification)
++	 */
++	if (megasas_start_aen(instance))
++		printk(KERN_ERR "megasas: Start AEN failed\n");
 +
-+int iscsi_conn_send_pdu(struct iscsi_cls_conn *cls_conn, struct iscsi_hdr *hdr,
-+			char *data, uint32_t data_size)
-+{
-+	struct iscsi_conn *conn = cls_conn->dd_data;
-+	struct iscsi_session *session = conn->session;
-+	int err = 0;
++	/* Initialize the cmd completion timer */
++	if (poll_mode_io)
++		megasas_start_timer(instance, &instance->io_completion_timer,
++				megasas_io_completion_timer,
++				MEGASAS_COMPLETION_TIMER_INTERVAL);
++	return 0;
 +
-+	spin_lock_bh(&session->lock);
-+	if (!__iscsi_conn_send_pdu(conn, hdr, data, data_size))
-+		err = -EPERM;
-+	spin_unlock_bh(&session->lock);
-+	scsi_queue_work(session->host, &conn->xmitwork);
-+	return err;
++fail_irq:
++fail_init_mfi:
++	if (instance->evt_detail)
++		pci_free_consistent(pdev, sizeof(struct megasas_evt_detail),
++				instance->evt_detail,
++				instance->evt_detail_h);
++
++	if (instance->producer)
++		pci_free_consistent(pdev, sizeof(u32), instance->producer,
++				instance->producer_h);
++	if (instance->consumer)
++		pci_free_consistent(pdev, sizeof(u32), instance->consumer,
++				instance->consumer_h);
++	scsi_host_put(host);
++
++fail_set_dma_mask:
++fail_ready_state:
++
++	pci_disable_device(pdev);
++
++	return -ENODEV;
 +}
-+EXPORT_SYMBOL_GPL(iscsi_conn_send_pdu);
 +
- /**
-  * iscsi_cmd_rsp - SCSI Command Response processing
-  * @conn: iscsi connection
-@@ -291,17 +432,19 @@ invalid_datalen:
- 			   min_t(uint16_t, senselen, SCSI_SENSE_BUFFERSIZE));
- 	}
++/**
+  * megasas_detach_one -	PCI hot"un"plug entry point
+  * @pdev:		PCI device structure
+  */
+@@ -2536,9 +2784,12 @@ static void megasas_detach_one(struct pci_dev *pdev)
+ 	instance = pci_get_drvdata(pdev);
+ 	host = instance->host;
  
--	if (rhdr->flags & ISCSI_FLAG_CMD_UNDERFLOW) {
-+	if (rhdr->flags & (ISCSI_FLAG_CMD_UNDERFLOW |
-+	                   ISCSI_FLAG_CMD_OVERFLOW)) {
- 		int res_count = be32_to_cpu(rhdr->residual_count);
++	if (poll_mode_io)
++		del_timer_sync(&instance->io_completion_timer);
++
+ 	scsi_remove_host(instance->host);
+ 	megasas_flush_cache(instance);
+-	megasas_shutdown_controller(instance);
++	megasas_shutdown_controller(instance, MR_DCMD_CTRL_SHUTDOWN);
+ 	tasklet_kill(&instance->isr_tasklet);
  
--		if (res_count > 0 && res_count <= scsi_bufflen(sc))
-+		if (res_count > 0 &&
-+		    (rhdr->flags & ISCSI_FLAG_CMD_OVERFLOW ||
-+		     res_count <= scsi_bufflen(sc)))
- 			scsi_set_resid(sc, res_count);
- 		else
- 			sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status;
--	} else if (rhdr->flags & ISCSI_FLAG_CMD_BIDI_UNDERFLOW)
-+	} else if (rhdr->flags & (ISCSI_FLAG_CMD_BIDI_UNDERFLOW |
-+	                          ISCSI_FLAG_CMD_BIDI_OVERFLOW))
- 		sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status;
--	else if (rhdr->flags & ISCSI_FLAG_CMD_OVERFLOW)
--		scsi_set_resid(sc, be32_to_cpu(rhdr->residual_count));
+ 	/*
+@@ -2660,6 +2911,7 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance,
+ 	void *sense = NULL;
+ 	dma_addr_t sense_handle;
+ 	u32 *sense_ptr;
++	unsigned long *sense_buff;
  
- out:
- 	debug_scsi("done [sc %lx res %d itt 0x%x]\n",
-@@ -318,18 +461,51 @@ static void iscsi_tmf_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
- 	conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1;
- 	conn->tmfrsp_pdus_cnt++;
+ 	memset(kbuff_arr, 0, sizeof(kbuff_arr));
  
--	if (conn->tmabort_state != TMABORT_INITIAL)
-+	if (conn->tmf_state != TMF_QUEUED)
- 		return;
+@@ -2764,14 +3016,16 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance,
+ 	 */
+ 	if (ioc->sense_len) {
+ 		/*
+-		 * sense_ptr points to the location that has the user
++		 * sense_buff points to the location that has the user
+ 		 * sense buffer address
+ 		 */
+-		sense_ptr = (u32 *) ((unsigned long)ioc->frame.raw +
+-				     ioc->sense_off);
++		sense_buff = (unsigned long *) ((unsigned long)ioc->frame.raw +
++								ioc->sense_off);
  
- 	if (tmf->response == ISCSI_TMF_RSP_COMPLETE)
--		conn->tmabort_state = TMABORT_SUCCESS;
-+		conn->tmf_state = TMF_SUCCESS;
- 	else if (tmf->response == ISCSI_TMF_RSP_NO_TASK)
--		conn->tmabort_state = TMABORT_NOT_FOUND;
-+		conn->tmf_state = TMF_NOT_FOUND;
- 	else
--		conn->tmabort_state = TMABORT_FAILED;
-+		conn->tmf_state = TMF_FAILED;
- 	wake_up(&conn->ehwait);
+-		if (copy_to_user((void __user *)((unsigned long)(*sense_ptr)),
+-				 sense, ioc->sense_len)) {
++		if (copy_to_user((void __user *)(unsigned long)(*sense_buff),
++				sense, ioc->sense_len)) {
++			printk(KERN_ERR "megasas: Failed to copy out to user "
++					"sense data\n");
+ 			error = -EFAULT;
+ 			goto out;
+ 		}
+@@ -2874,10 +3128,10 @@ static int megasas_mgmt_ioctl_aen(struct file *file, unsigned long arg)
+ 	if (!instance)
+ 		return -ENODEV;
+ 
+-	down(&instance->aen_mutex);
++	mutex_lock(&instance->aen_mutex);
+ 	error = megasas_register_aen(instance, aen.seq_num,
+ 				     aen.class_locale_word);
+-	up(&instance->aen_mutex);
++	mutex_unlock(&instance->aen_mutex);
+ 	return error;
  }
  
-+static void iscsi_send_nopout(struct iscsi_conn *conn, struct iscsi_nopin *rhdr)
+@@ -2977,6 +3231,8 @@ static struct pci_driver megasas_pci_driver = {
+ 	.id_table = megasas_pci_table,
+ 	.probe = megasas_probe_one,
+ 	.remove = __devexit_p(megasas_detach_one),
++	.suspend = megasas_suspend,
++	.resume = megasas_resume,
+ 	.shutdown = megasas_shutdown,
+ };
+ 
+@@ -3004,7 +3260,7 @@ static DRIVER_ATTR(release_date, S_IRUGO, megasas_sysfs_show_release_date,
+ static ssize_t
+ megasas_sysfs_show_dbg_lvl(struct device_driver *dd, char *buf)
+ {
+-	return sprintf(buf,"%u",megasas_dbg_lvl);
++	return sprintf(buf, "%u\n", megasas_dbg_lvl);
+ }
+ 
+ static ssize_t
+@@ -3019,7 +3275,65 @@ megasas_sysfs_set_dbg_lvl(struct device_driver *dd, const char *buf, size_t coun
+ }
+ 
+ static DRIVER_ATTR(dbg_lvl, S_IRUGO|S_IWUGO, megasas_sysfs_show_dbg_lvl,
+-		   megasas_sysfs_set_dbg_lvl);
++		megasas_sysfs_set_dbg_lvl);
++
++static ssize_t
++megasas_sysfs_show_poll_mode_io(struct device_driver *dd, char *buf)
 +{
-+        struct iscsi_nopout hdr;
-+	struct iscsi_mgmt_task *mtask;
++	return sprintf(buf, "%u\n", poll_mode_io);
++}
 +
-+	if (!rhdr && conn->ping_mtask)
-+		return;
++static ssize_t
++megasas_sysfs_set_poll_mode_io(struct device_driver *dd,
++				const char *buf, size_t count)
++{
++	int retval = count;
++	int tmp = poll_mode_io;
++	int i;
++	struct megasas_instance *instance;
 +
-+	memset(&hdr, 0, sizeof(struct iscsi_nopout));
-+	hdr.opcode = ISCSI_OP_NOOP_OUT | ISCSI_OP_IMMEDIATE;
-+	hdr.flags = ISCSI_FLAG_CMD_FINAL;
++	if (sscanf(buf, "%u", &poll_mode_io) < 1) {
++		printk(KERN_ERR "megasas: could not set poll_mode_io\n");
++		retval = -EINVAL;
++	}
 +
-+	if (rhdr) {
-+		memcpy(hdr.lun, rhdr->lun, 8);
-+		hdr.ttt = rhdr->ttt;
-+		hdr.itt = RESERVED_ITT;
-+	} else
-+		hdr.ttt = RESERVED_ITT;
++	/*
++	 * Check if poll_mode_io is already set or is same as previous value
++	 */
++	if ((tmp && poll_mode_io) || (tmp == poll_mode_io))
++		goto out;
 +
-+	mtask = __iscsi_conn_send_pdu(conn, (struct iscsi_hdr *)&hdr, NULL, 0);
-+	if (!mtask) {
-+		printk(KERN_ERR "Could not send nopout\n");
-+		return;
++	if (poll_mode_io) {
++		/*
++		 * Start timers for all adapters
++		 */
++		for (i = 0; i < megasas_mgmt_info.max_index; i++) {
++			instance = megasas_mgmt_info.instance[i];
++			if (instance) {
++				megasas_start_timer(instance,
++					&instance->io_completion_timer,
++					megasas_io_completion_timer,
++					MEGASAS_COMPLETION_TIMER_INTERVAL);
++			}
++		}
++	} else {
++		/*
++		 * Delete timers for all adapters
++		 */
++		for (i = 0; i < megasas_mgmt_info.max_index; i++) {
++			instance = megasas_mgmt_info.instance[i];
++			if (instance)
++				del_timer_sync(&instance->io_completion_timer);
++		}
 +	}
 +
-+	/* only track our nops */
-+	if (!rhdr) {
-+		conn->ping_mtask = mtask;
-+		conn->last_ping = jiffies;
-+	}
-+	scsi_queue_work(conn->session->host, &conn->xmitwork);
++out:
++	return retval;
 +}
 +
- static int iscsi_handle_reject(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
- 			       char *data, int datalen)
++static DRIVER_ATTR(poll_mode_io, S_IRUGO|S_IWUGO,
++		megasas_sysfs_show_poll_mode_io,
++		megasas_sysfs_set_poll_mode_io);
+ 
+ /**
+  * megasas_init - Driver load entry point
+@@ -3070,8 +3384,16 @@ static int __init megasas_init(void)
+ 				  &driver_attr_dbg_lvl);
+ 	if (rval)
+ 		goto err_dcf_dbg_lvl;
++	rval = driver_create_file(&megasas_pci_driver.driver,
++				  &driver_attr_poll_mode_io);
++	if (rval)
++		goto err_dcf_poll_mode_io;
+ 
+ 	return rval;
++
++err_dcf_poll_mode_io:
++	driver_remove_file(&megasas_pci_driver.driver,
++			   &driver_attr_dbg_lvl);
+ err_dcf_dbg_lvl:
+ 	driver_remove_file(&megasas_pci_driver.driver,
+ 			   &driver_attr_release_date);
+@@ -3090,6 +3412,8 @@ err_pcidrv:
+ static void __exit megasas_exit(void)
  {
-@@ -374,6 +550,7 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
- 	struct iscsi_mgmt_task *mtask;
- 	uint32_t itt;
+ 	driver_remove_file(&megasas_pci_driver.driver,
++			   &driver_attr_poll_mode_io);
++	driver_remove_file(&megasas_pci_driver.driver,
+ 			   &driver_attr_dbg_lvl);
+ 	driver_remove_file(&megasas_pci_driver.driver,
+ 			   &driver_attr_release_date);
+diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h
+index 4dffc91..6466bdf 100644
+--- a/drivers/scsi/megaraid/megaraid_sas.h
++++ b/drivers/scsi/megaraid/megaraid_sas.h
+@@ -2,7 +2,7 @@
+  *
+  *		Linux MegaRAID driver for SAS based RAID controllers
+  *
+- * Copyright (c) 2003-2005  LSI Logic Corporation.
++ * Copyright (c) 2003-2005  LSI Corporation.
+  *
+  *		This program is free software; you can redistribute it and/or
+  *		modify it under the terms of the GNU General Public License
+@@ -18,9 +18,9 @@
+ /*
+  * MegaRAID SAS Driver meta data
+  */
+-#define MEGASAS_VERSION				"00.00.03.10-rc5"
+-#define MEGASAS_RELDATE				"May 17, 2007"
+-#define MEGASAS_EXT_VERSION			"Thu May 17 10:09:32 PDT 2007"
++#define MEGASAS_VERSION				"00.00.03.16-rc1"
++#define MEGASAS_RELDATE				"Nov. 07, 2007"
++#define MEGASAS_EXT_VERSION			"Thu. Nov. 07 10:09:32 PDT 2007"
  
-+	conn->last_recv = jiffies;
- 	if (hdr->itt != RESERVED_ITT)
- 		itt = get_itt(hdr->itt);
- 	else
-@@ -429,10 +606,7 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
- 			 */
- 			if (iscsi_recv_pdu(conn->cls_conn, hdr, data, datalen))
- 				rc = ISCSI_ERR_CONN_FAILED;
--			list_del(&mtask->running);
--			if (conn->login_mtask != mtask)
--				__kfifo_put(session->mgmtpool.queue,
--					    (void*)&mtask, sizeof(void*));
-+			iscsi_free_mgmt_task(conn, mtask);
- 			break;
- 		case ISCSI_OP_SCSI_TMFUNC_RSP:
- 			if (datalen) {
-@@ -441,20 +615,26 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
- 			}
+ /*
+  * Device IDs
+@@ -117,6 +117,7 @@
+ #define MR_FLUSH_DISK_CACHE			0x02
  
- 			iscsi_tmf_rsp(conn, hdr);
-+			iscsi_free_mgmt_task(conn, mtask);
- 			break;
- 		case ISCSI_OP_NOOP_IN:
--			if (hdr->ttt != cpu_to_be32(ISCSI_RESERVED_TAG) || datalen) {
-+			if (hdr->ttt != cpu_to_be32(ISCSI_RESERVED_TAG) ||
-+			    datalen) {
- 				rc = ISCSI_ERR_PROTO;
- 				break;
- 			}
- 			conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1;
+ #define MR_DCMD_CTRL_SHUTDOWN			0x01050000
++#define MR_DCMD_HIBERNATE_SHUTDOWN		0x01060000
+ #define MR_ENABLE_DRIVE_SPINDOWN		0x01
  
--			if (iscsi_recv_pdu(conn->cls_conn, hdr, data, datalen))
--				rc = ISCSI_ERR_CONN_FAILED;
--			list_del(&mtask->running);
--			if (conn->login_mtask != mtask)
--				__kfifo_put(session->mgmtpool.queue,
--					    (void*)&mtask, sizeof(void*));
-+			if (conn->ping_mtask != mtask) {
-+				/*
-+				 * If this is not in response to one of our
-+				 * nops then it must be from userspace.
-+				 */
-+				if (iscsi_recv_pdu(conn->cls_conn, hdr, data,
-+						   datalen))
-+					rc = ISCSI_ERR_CONN_FAILED;
-+			}
-+			iscsi_free_mgmt_task(conn, mtask);
- 			break;
- 		default:
- 			rc = ISCSI_ERR_BAD_OPCODE;
-@@ -473,8 +653,7 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
- 			if (hdr->ttt == cpu_to_be32(ISCSI_RESERVED_TAG))
- 				break;
+ #define MR_DCMD_CTRL_EVENT_GET_INFO		0x01040100
+@@ -570,7 +571,8 @@ struct megasas_ctrl_info {
+ #define IS_DMA64				(sizeof(dma_addr_t) == 8)
  
--			if (iscsi_recv_pdu(conn->cls_conn, hdr, NULL, 0))
--				rc = ISCSI_ERR_CONN_FAILED;
-+			iscsi_send_nopout(conn, (struct iscsi_nopin*)hdr);
- 			break;
- 		case ISCSI_OP_REJECT:
- 			rc = iscsi_handle_reject(conn, hdr, data, datalen);
-@@ -609,20 +788,19 @@ static void iscsi_prep_mtask(struct iscsi_conn *conn,
- 		session->tt->init_mgmt_task(conn, mtask);
+ #define MFI_OB_INTR_STATUS_MASK			0x00000002
+-#define MFI_POLL_TIMEOUT_SECS			10
++#define MFI_POLL_TIMEOUT_SECS			60
++#define MEGASAS_COMPLETION_TIMER_INTERVAL      (HZ/10)
  
- 	debug_scsi("mgmtpdu [op 0x%x hdr->itt 0x%x datalen %d]\n",
--		   hdr->opcode, hdr->itt, mtask->data_count);
-+		   hdr->opcode & ISCSI_OPCODE_MASK, hdr->itt,
-+		   mtask->data_count);
- }
+ #define MFI_REPLY_1078_MESSAGE_INTERRUPT	0x80000000
  
- static int iscsi_xmit_mtask(struct iscsi_conn *conn)
- {
- 	struct iscsi_hdr *hdr = conn->mtask->hdr;
--	int rc, was_logout = 0;
-+	int rc;
+@@ -1083,13 +1085,15 @@ struct megasas_instance {
+ 	struct megasas_cmd **cmd_list;
+ 	struct list_head cmd_pool;
+ 	spinlock_t cmd_pool_lock;
++	/* used to synch producer, consumer ptrs in dpc */
++	spinlock_t completion_lock;
+ 	struct dma_pool *frame_dma_pool;
+ 	struct dma_pool *sense_dma_pool;
  
-+	if ((hdr->opcode & ISCSI_OPCODE_MASK) == ISCSI_OP_LOGOUT)
-+		conn->session->state = ISCSI_STATE_LOGGING_OUT;
- 	spin_unlock_bh(&conn->session->lock);
--	if ((hdr->opcode & ISCSI_OPCODE_MASK) == ISCSI_OP_LOGOUT) {
--		conn->session->state = ISCSI_STATE_IN_RECOVERY;
--		iscsi_block_session(session_to_cls(conn->session));
--		was_logout = 1;
--	}
+ 	struct megasas_evt_detail *evt_detail;
+ 	dma_addr_t evt_detail_h;
+ 	struct megasas_cmd *aen_cmd;
+-	struct semaphore aen_mutex;
++	struct mutex aen_mutex;
+ 	struct semaphore ioctl_sem;
+ 
+ 	struct Scsi_Host *host;
+@@ -1108,6 +1112,8 @@ struct megasas_instance {
+ 
+ 	u8 flag;
+ 	unsigned long last_time;
 +
- 	rc = conn->session->tt->xmit_mgmt_task(conn, conn->mtask);
- 	spin_lock_bh(&conn->session->lock);
- 	if (rc)
-@@ -630,11 +808,6 @@ static int iscsi_xmit_mtask(struct iscsi_conn *conn)
++	struct timer_list io_completion_timer;
+ };
+ 
+ #define MEGASAS_IS_LOGICAL(scp)						\
+diff --git a/drivers/scsi/ncr53c8xx.c b/drivers/scsi/ncr53c8xx.c
+index 016c462..c02771a 100644
+--- a/drivers/scsi/ncr53c8xx.c
++++ b/drivers/scsi/ncr53c8xx.c
+@@ -4963,7 +4963,8 @@ void ncr_complete (struct ncb *np, struct ccb *cp)
+ 		**	Copy back sense data to caller's buffer.
+ 		*/
+ 		memcpy(cmd->sense_buffer, cp->sense_buf,
+-		       min(sizeof(cmd->sense_buffer), sizeof(cp->sense_buf)));
++		       min_t(size_t, SCSI_SENSE_BUFFERSIZE,
++			     sizeof(cp->sense_buf)));
  
- 	/* done with this in-progress mtask */
- 	conn->mtask = NULL;
--
--	if (was_logout) {
--		set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
--		return -ENODATA;
--	}
- 	return 0;
- }
+ 		if (DEBUG_FLAGS & (DEBUG_RESULT|DEBUG_TINY)) {
+ 			u_char * p = (u_char*) & cmd->sense_buffer;
+diff --git a/drivers/scsi/pcmcia/Kconfig b/drivers/scsi/pcmcia/Kconfig
+index fa481b5..53857c6 100644
+--- a/drivers/scsi/pcmcia/Kconfig
++++ b/drivers/scsi/pcmcia/Kconfig
+@@ -6,7 +6,8 @@ menuconfig SCSI_LOWLEVEL_PCMCIA
+ 	bool "PCMCIA SCSI adapter support"
+ 	depends on SCSI!=n && PCMCIA!=n
  
-@@ -658,21 +831,13 @@ static int iscsi_check_cmdsn_window_closed(struct iscsi_conn *conn)
- static int iscsi_xmit_ctask(struct iscsi_conn *conn)
- {
- 	struct iscsi_cmd_task *ctask = conn->ctask;
--	int rc = 0;
--
--	/*
--	 * serialize with TMF AbortTask
--	 */
--	if (ctask->state == ISCSI_TASK_ABORTING)
--		goto done;
-+	int rc;
+-if SCSI_LOWLEVEL_PCMCIA && SCSI && PCMCIA
++# drivers have problems when build in, so require modules
++if SCSI_LOWLEVEL_PCMCIA && SCSI && PCMCIA && m
  
- 	__iscsi_get_ctask(ctask);
- 	spin_unlock_bh(&conn->session->lock);
- 	rc = conn->session->tt->xmit_cmd_task(conn, ctask);
- 	spin_lock_bh(&conn->session->lock);
- 	__iscsi_put_ctask(ctask);
--
--done:
- 	if (!rc)
- 		/* done with this ctask */
- 		conn->ctask = NULL;
-@@ -680,6 +845,22 @@ done:
- }
+ config PCMCIA_AHA152X
+ 	tristate "Adaptec AHA152X PCMCIA support"
+diff --git a/drivers/scsi/pcmcia/nsp_cs.c b/drivers/scsi/pcmcia/nsp_cs.c
+index a45d89b..5082ca3 100644
+--- a/drivers/scsi/pcmcia/nsp_cs.c
++++ b/drivers/scsi/pcmcia/nsp_cs.c
+@@ -135,6 +135,11 @@ static nsp_hw_data nsp_data_base; /* attach <-> detect glue */
  
- /**
-+ * iscsi_requeue_ctask - requeue ctask to run from session workqueue
-+ * @ctask: ctask to requeue
-+ *
-+ * LLDs that need to run a ctask from the session workqueue should call
-+ * this. The session lock must be held.
-+ */
-+void iscsi_requeue_ctask(struct iscsi_cmd_task *ctask)
+ #define NSP_DEBUG_BUF_LEN		150
+ 
++static inline void nsp_inc_resid(struct scsi_cmnd *SCpnt, int residInc)
 +{
-+	struct iscsi_conn *conn = ctask->conn;
-+
-+	list_move_tail(&ctask->running, &conn->requeue);
-+	scsi_queue_work(conn->session->host, &conn->xmitwork);
++	scsi_set_resid(SCpnt, scsi_get_resid(SCpnt) + residInc);
 +}
-+EXPORT_SYMBOL_GPL(iscsi_requeue_ctask);
-+
-+/**
-  * iscsi_data_xmit - xmit any command into the scheduled connection
-  * @conn: iscsi connection
-  *
-@@ -717,36 +898,40 @@ static int iscsi_data_xmit(struct iscsi_conn *conn)
- 	 * overflow us with nop-ins
- 	 */
- check_mgmt:
--	while (__kfifo_get(conn->mgmtqueue, (void*)&conn->mtask,
--			   sizeof(void*))) {
-+	while (!list_empty(&conn->mgmtqueue)) {
-+		conn->mtask = list_entry(conn->mgmtqueue.next,
-+					 struct iscsi_mgmt_task, running);
-+		if (conn->session->state == ISCSI_STATE_LOGGING_OUT) {
-+			iscsi_free_mgmt_task(conn, conn->mtask);
-+			conn->mtask = NULL;
-+			continue;
-+		}
 +
- 		iscsi_prep_mtask(conn, conn->mtask);
--		list_add_tail(&conn->mtask->running, &conn->mgmt_run_list);
-+		list_move_tail(conn->mgmtqueue.next, &conn->mgmt_run_list);
- 		rc = iscsi_xmit_mtask(conn);
- 		if (rc)
- 			goto again;
- 	}
+ static void nsp_cs_message(const char *func, int line, char *type, char *fmt, ...)
+ {
+ 	va_list args;
+@@ -192,8 +197,10 @@ static int nsp_queuecommand(struct scsi_cmnd *SCpnt,
+ #endif
+ 	nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
  
--	/* process command queue */
-+	/* process pending command queue */
- 	while (!list_empty(&conn->xmitqueue)) {
--		/*
--		 * iscsi tcp may readd the task to the xmitqueue to send
--		 * write data
--		 */
-+		if (conn->tmf_state == TMF_QUEUED)
-+			break;
-+
- 		conn->ctask = list_entry(conn->xmitqueue.next,
- 					 struct iscsi_cmd_task, running);
--		switch (conn->ctask->state) {
--		case ISCSI_TASK_ABORTING:
--			break;
--		case ISCSI_TASK_PENDING:
--			iscsi_prep_scsi_cmd_pdu(conn->ctask);
--			conn->session->tt->init_cmd_task(conn->ctask);
--			/* fall through */
--		default:
--			conn->ctask->state = ISCSI_TASK_RUNNING;
--			break;
-+		if (conn->session->state == ISCSI_STATE_LOGGING_OUT) {
-+			fail_command(conn, conn->ctask, DID_IMM_RETRY << 16);
-+			continue;
-+		}
-+		if (iscsi_prep_scsi_cmd_pdu(conn->ctask)) {
-+			fail_command(conn, conn->ctask, DID_ABORT << 16);
-+			continue;
- 		}
--		list_move_tail(conn->xmitqueue.next, &conn->run_list);
+-	nsp_dbg(NSP_DEBUG_QUEUECOMMAND, "SCpnt=0x%p target=%d lun=%d buff=0x%p bufflen=%d use_sg=%d",
+-		   SCpnt, target, SCpnt->device->lun, SCpnt->request_buffer, SCpnt->request_bufflen, SCpnt->use_sg);
++	nsp_dbg(NSP_DEBUG_QUEUECOMMAND,
++		"SCpnt=0x%p target=%d lun=%d sglist=0x%p bufflen=%d sg_count=%d",
++		SCpnt, target, SCpnt->device->lun, scsi_sglist(SCpnt),
++		scsi_bufflen(SCpnt), scsi_sg_count(SCpnt));
+ 	//nsp_dbg(NSP_DEBUG_QUEUECOMMAND, "before CurrentSC=0x%p", data->CurrentSC);
  
-+		conn->ctask->state = ISCSI_TASK_RUNNING;
-+		list_move_tail(conn->xmitqueue.next, &conn->run_list);
- 		rc = iscsi_xmit_ctask(conn);
- 		if (rc)
- 			goto again;
-@@ -755,7 +940,28 @@ check_mgmt:
- 		 * we need to check the mgmt queue for nops that need to
- 		 * be sent to aviod starvation
- 		 */
--		if (__kfifo_len(conn->mgmtqueue))
-+		if (!list_empty(&conn->mgmtqueue))
-+			goto check_mgmt;
-+	}
-+
-+	while (!list_empty(&conn->requeue)) {
-+		if (conn->session->fast_abort && conn->tmf_state != TMF_INITIAL)
-+			break;
-+
-+		/*
-+		 * we always do fastlogout - conn stop code will clean up.
-+		 */
-+		if (conn->session->state == ISCSI_STATE_LOGGING_OUT)
-+			break;
-+
-+		conn->ctask = list_entry(conn->requeue.next,
-+					 struct iscsi_cmd_task, running);
-+		conn->ctask->state = ISCSI_TASK_RUNNING;
-+		list_move_tail(conn->requeue.next, &conn->run_list);
-+		rc = iscsi_xmit_ctask(conn);
-+		if (rc)
-+			goto again;
-+		if (!list_empty(&conn->mgmtqueue))
- 			goto check_mgmt;
+ 	SCpnt->scsi_done	= done;
+@@ -225,7 +232,7 @@ static int nsp_queuecommand(struct scsi_cmnd *SCpnt,
+ 	SCpnt->SCp.have_data_in = IO_UNKNOWN;
+ 	SCpnt->SCp.sent_command = 0;
+ 	SCpnt->SCp.phase	= PH_UNDETERMINED;
+-	SCpnt->resid	        = SCpnt->request_bufflen;
++	scsi_set_resid(SCpnt, scsi_bufflen(SCpnt));
+ 
+ 	/* setup scratch area
+ 	   SCp.ptr		: buffer pointer
+@@ -233,14 +240,14 @@ static int nsp_queuecommand(struct scsi_cmnd *SCpnt,
+ 	   SCp.buffer		: next buffer
+ 	   SCp.buffers_residual : left buffers in list
+ 	   SCp.phase		: current state of the command */
+-	if (SCpnt->use_sg) {
+-		SCpnt->SCp.buffer	    = (struct scatterlist *) SCpnt->request_buffer;
++	if (scsi_bufflen(SCpnt)) {
++		SCpnt->SCp.buffer	    = scsi_sglist(SCpnt);
+ 		SCpnt->SCp.ptr		    = BUFFER_ADDR;
+ 		SCpnt->SCp.this_residual    = SCpnt->SCp.buffer->length;
+-		SCpnt->SCp.buffers_residual = SCpnt->use_sg - 1;
++		SCpnt->SCp.buffers_residual = scsi_sg_count(SCpnt) - 1;
+ 	} else {
+-		SCpnt->SCp.ptr		    = (char *) SCpnt->request_buffer;
+-		SCpnt->SCp.this_residual    = SCpnt->request_bufflen;
++		SCpnt->SCp.ptr		    = NULL;
++		SCpnt->SCp.this_residual    = 0;
+ 		SCpnt->SCp.buffer	    = NULL;
+ 		SCpnt->SCp.buffers_residual = 0;
  	}
- 	spin_unlock_bh(&conn->session->lock);
-@@ -790,6 +996,7 @@ enum {
- 	FAILURE_SESSION_TERMINATE,
- 	FAILURE_SESSION_IN_RECOVERY,
- 	FAILURE_SESSION_RECOVERY_TIMEOUT,
-+	FAILURE_SESSION_LOGGING_OUT,
- };
+@@ -721,7 +728,9 @@ static void nsp_pio_read(struct scsi_cmnd *SCpnt)
+ 	ocount = data->FifoCount;
  
- int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
-@@ -805,8 +1012,9 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
- 	sc->SCp.ptr = NULL;
+ 	nsp_dbg(NSP_DEBUG_DATA_IO, "in SCpnt=0x%p resid=%d ocount=%d ptr=0x%p this_residual=%d buffers=0x%p nbuf=%d",
+-		SCpnt, SCpnt->resid, ocount, SCpnt->SCp.ptr, SCpnt->SCp.this_residual, SCpnt->SCp.buffer, SCpnt->SCp.buffers_residual);
++		SCpnt, scsi_get_resid(SCpnt), ocount, SCpnt->SCp.ptr,
++		SCpnt->SCp.this_residual, SCpnt->SCp.buffer,
++		SCpnt->SCp.buffers_residual);
  
- 	host = sc->device->host;
--	session = iscsi_hostdata(host->hostdata);
-+	spin_unlock(host->host_lock);
+ 	time_out = 1000;
  
-+	session = iscsi_hostdata(host->hostdata);
- 	spin_lock(&session->lock);
+@@ -771,7 +780,7 @@ static void nsp_pio_read(struct scsi_cmnd *SCpnt)
+ 			return;
+ 		}
  
- 	/*
-@@ -822,17 +1030,22 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
- 		 * be entering our queuecommand while a block is starting
- 		 * up because the block code is not locked)
- 		 */
--		if (session->state == ISCSI_STATE_IN_RECOVERY) {
-+		switch (session->state) {
-+		case ISCSI_STATE_IN_RECOVERY:
- 			reason = FAILURE_SESSION_IN_RECOVERY;
- 			goto reject;
--		}
--
--		if (session->state == ISCSI_STATE_RECOVERY_FAILED)
-+		case ISCSI_STATE_LOGGING_OUT:
-+			reason = FAILURE_SESSION_LOGGING_OUT;
-+			goto reject;
-+		case ISCSI_STATE_RECOVERY_FAILED:
- 			reason = FAILURE_SESSION_RECOVERY_TIMEOUT;
--		else if (session->state == ISCSI_STATE_TERMINATE)
-+			break;
-+		case ISCSI_STATE_TERMINATE:
- 			reason = FAILURE_SESSION_TERMINATE;
--		else
-+			break;
-+		default:
- 			reason = FAILURE_SESSION_FREED;
-+		}
- 		goto fault;
+-		SCpnt->resid	       	 -= res;
++		nsp_inc_resid(SCpnt, -res);
+ 		SCpnt->SCp.ptr		 += res;
+ 		SCpnt->SCp.this_residual -= res;
+ 		ocount			 += res;
+@@ -795,10 +804,12 @@ static void nsp_pio_read(struct scsi_cmnd *SCpnt)
+ 
+ 	if (time_out == 0) {
+ 		nsp_msg(KERN_DEBUG, "pio read timeout resid=%d this_residual=%d buffers_residual=%d",
+-			SCpnt->resid, SCpnt->SCp.this_residual, SCpnt->SCp.buffers_residual);
++			scsi_get_resid(SCpnt), SCpnt->SCp.this_residual,
++			SCpnt->SCp.buffers_residual);
  	}
+ 	nsp_dbg(NSP_DEBUG_DATA_IO, "read ocount=0x%x", ocount);
+-	nsp_dbg(NSP_DEBUG_DATA_IO, "r cmd=%d resid=0x%x\n", data->CmdId, SCpnt->resid);
++	nsp_dbg(NSP_DEBUG_DATA_IO, "r cmd=%d resid=0x%x\n", data->CmdId,
++	                                                scsi_get_resid(SCpnt));
+ }
  
-@@ -859,7 +1072,6 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
+ /*
+@@ -816,7 +827,9 @@ static void nsp_pio_write(struct scsi_cmnd *SCpnt)
+ 	ocount	 = data->FifoCount;
  
- 	atomic_set(&ctask->refcount, 1);
- 	ctask->state = ISCSI_TASK_PENDING;
--	ctask->mtask = NULL;
- 	ctask->conn = conn;
- 	ctask->sc = sc;
- 	INIT_LIST_HEAD(&ctask->running);
-@@ -868,11 +1080,13 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
- 	spin_unlock(&session->lock);
+ 	nsp_dbg(NSP_DEBUG_DATA_IO, "in fifocount=%d ptr=0x%p this_residual=%d buffers=0x%p nbuf=%d resid=0x%x",
+-		data->FifoCount, SCpnt->SCp.ptr, SCpnt->SCp.this_residual, SCpnt->SCp.buffer, SCpnt->SCp.buffers_residual, SCpnt->resid);
++		data->FifoCount, SCpnt->SCp.ptr, SCpnt->SCp.this_residual,
++		SCpnt->SCp.buffer, SCpnt->SCp.buffers_residual,
++		scsi_get_resid(SCpnt));
  
- 	scsi_queue_work(host, &conn->xmitwork);
-+	spin_lock(host->host_lock);
- 	return 0;
+ 	time_out = 1000;
  
- reject:
- 	spin_unlock(&session->lock);
- 	debug_scsi("cmd 0x%x rejected (%d)\n", sc->cmnd[0], reason);
-+	spin_lock(host->host_lock);
- 	return SCSI_MLQUEUE_HOST_BUSY;
+@@ -830,7 +843,7 @@ static void nsp_pio_write(struct scsi_cmnd *SCpnt)
  
- fault:
-@@ -882,6 +1096,7 @@ fault:
- 	sc->result = (DID_NO_CONNECT << 16);
- 	scsi_set_resid(sc, scsi_bufflen(sc));
- 	sc->scsi_done(sc);
-+	spin_lock(host->host_lock);
- 	return 0;
- }
- EXPORT_SYMBOL_GPL(iscsi_queuecommand);
-@@ -895,72 +1110,15 @@ int iscsi_change_queue_depth(struct scsi_device *sdev, int depth)
+ 			nsp_dbg(NSP_DEBUG_DATA_IO, "phase changed stat=0x%x, res=%d\n", stat, res);
+ 			/* Put back pointer */
+-			SCpnt->resid	       	 += res;
++			nsp_inc_resid(SCpnt, res);
+ 			SCpnt->SCp.ptr		 -= res;
+ 			SCpnt->SCp.this_residual += res;
+ 			ocount			 -= res;
+@@ -866,7 +879,7 @@ static void nsp_pio_write(struct scsi_cmnd *SCpnt)
+ 			break;
+ 		}
+ 
+-		SCpnt->resid	       	 -= res;
++		nsp_inc_resid(SCpnt, -res);
+ 		SCpnt->SCp.ptr		 += res;
+ 		SCpnt->SCp.this_residual -= res;
+ 		ocount			 += res;
+@@ -886,10 +899,12 @@ static void nsp_pio_write(struct scsi_cmnd *SCpnt)
+ 	data->FifoCount = ocount;
+ 
+ 	if (time_out == 0) {
+-		nsp_msg(KERN_DEBUG, "pio write timeout resid=0x%x", SCpnt->resid);
++		nsp_msg(KERN_DEBUG, "pio write timeout resid=0x%x",
++		                                        scsi_get_resid(SCpnt));
+ 	}
+ 	nsp_dbg(NSP_DEBUG_DATA_IO, "write ocount=0x%x", ocount);
+-	nsp_dbg(NSP_DEBUG_DATA_IO, "w cmd=%d resid=0x%x\n", data->CmdId, SCpnt->resid);
++	nsp_dbg(NSP_DEBUG_DATA_IO, "w cmd=%d resid=0x%x\n", data->CmdId,
++	                                                scsi_get_resid(SCpnt));
  }
- EXPORT_SYMBOL_GPL(iscsi_change_queue_depth);
+ #undef RFIFO_CRIT
+ #undef WFIFO_CRIT
+@@ -911,9 +926,8 @@ static int nsp_nexus(struct scsi_cmnd *SCpnt)
+ 	nsp_index_write(base, SYNCREG,	sync->SyncRegister);
+ 	nsp_index_write(base, ACKWIDTH, sync->AckWidth);
  
--static struct iscsi_mgmt_task *
--__iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
--		      char *data, uint32_t data_size)
+-	if (SCpnt->use_sg    == 0        ||
+-	    SCpnt->resid % 4 != 0        ||
+-	    SCpnt->resid     <= PAGE_SIZE ) {
++	if (scsi_get_resid(SCpnt) % 4 != 0 ||
++	    scsi_get_resid(SCpnt) <= PAGE_SIZE ) {
+ 		data->TransferMode = MODE_IO8;
+ 	} else if (nsp_burst_mode == BURST_MEM32) {
+ 		data->TransferMode = MODE_MEM32;
+diff --git a/drivers/scsi/ppa.c b/drivers/scsi/ppa.c
+index 67ee51a..f655ae3 100644
+--- a/drivers/scsi/ppa.c
++++ b/drivers/scsi/ppa.c
+@@ -750,18 +750,16 @@ static int ppa_engine(ppa_struct *dev, struct scsi_cmnd *cmd)
+ 		cmd->SCp.phase++;
+ 
+ 	case 4:		/* Phase 4 - Setup scatter/gather buffers */
+-		if (cmd->use_sg) {
+-			/* if many buffers are available, start filling the first */
+-			cmd->SCp.buffer = (struct scatterlist *) cmd->request_buffer;
++		if (scsi_bufflen(cmd)) {
++			cmd->SCp.buffer = scsi_sglist(cmd);
+ 			cmd->SCp.this_residual = cmd->SCp.buffer->length;
+ 			cmd->SCp.ptr = sg_virt(cmd->SCp.buffer);
+ 		} else {
+-			/* else fill the only available buffer */
+ 			cmd->SCp.buffer = NULL;
+-			cmd->SCp.this_residual = cmd->request_bufflen;
+-			cmd->SCp.ptr = cmd->request_buffer;
++			cmd->SCp.this_residual = 0;
++			cmd->SCp.ptr = NULL;
+ 		}
+-		cmd->SCp.buffers_residual = cmd->use_sg - 1;
++		cmd->SCp.buffers_residual = scsi_sg_count(cmd) - 1;
+ 		cmd->SCp.phase++;
+ 
+ 	case 5:		/* Phase 5 - Data transfer stage */
+diff --git a/drivers/scsi/psi240i.c b/drivers/scsi/psi240i.c
+deleted file mode 100644
+index 899e89d..0000000
+--- a/drivers/scsi/psi240i.c
++++ /dev/null
+@@ -1,689 +0,0 @@
+-/*+M*************************************************************************
+- * Perceptive Solutions, Inc. PSI-240I device driver proc support for Linux.
+- *
+- * Copyright (c) 1997 Perceptive Solutions, 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, or (at your option)
+- * any later version.
+- *
+- * This program is distributed in the hope that it will be useful,
+- * but WITHOUT ANY WARRANTY; without even the implied warranty of
+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See 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, 675 Mass Ave, Cambridge, MA 02139, USA.
+- *
+- *
+- *	File Name:		psi240i.c
+- *
+- *	Description:	SCSI driver for the PSI240I EIDE interface card.
+- *
+- *-M*************************************************************************/
+-
+-#include <linux/module.h>
+-
+-#include <linux/blkdev.h>
+-#include <linux/kernel.h>
+-#include <linux/types.h>
+-#include <linux/string.h>
+-#include <linux/ioport.h>
+-#include <linux/delay.h>
+-#include <linux/interrupt.h>
+-#include <linux/proc_fs.h>
+-#include <linux/spinlock.h>
+-#include <linux/stat.h>
+-
+-#include <asm/dma.h>
+-#include <asm/system.h>
+-#include <asm/io.h>
+-#include "scsi.h"
+-#include <scsi/scsi_host.h>
+-
+-#include "psi240i.h"
+-#include "psi_chip.h"
+-
+-//#define DEBUG 1
+-
+-#ifdef DEBUG
+-#define DEB(x) x
+-#else
+-#define DEB(x)
+-#endif
+-
+-#define MAXBOARDS 6	/* Increase this and the sizes of the arrays below, if you need more. */
+-
+-#define	PORT_DATA				0
+-#define	PORT_ERROR				1
+-#define	PORT_SECTOR_COUNT		2
+-#define	PORT_LBA_0				3
+-#define	PORT_LBA_8				4
+-#define	PORT_LBA_16				5
+-#define	PORT_LBA_24				6
+-#define	PORT_STAT_CMD			7
+-#define	PORT_SEL_FAIL			8
+-#define	PORT_IRQ_STATUS			9
+-#define	PORT_ADDRESS			10
+-#define	PORT_FAIL				11
+-#define	PORT_ALT_STAT		   	12
+-
+-typedef struct
+-	{
+-	UCHAR		   	device;				// device code
+-	UCHAR			byte6;				// device select register image
+-	UCHAR			spigot;				// spigot number
+-	UCHAR			expectingIRQ;		// flag for expecting and interrupt
+-	USHORT			sectors;			// number of sectors per track
+-	USHORT			heads;				// number of heads
+-	USHORT			cylinders;			// number of cylinders for this device
+-	USHORT			spareword;			// placeholder
+-	ULONG			blocks;				// number of blocks on device
+-	}	OUR_DEVICE, *POUR_DEVICE;
+-
+-typedef struct
+-	{
+-	USHORT		 ports[13];
+-	OUR_DEVICE	 device[8];
+-	struct scsi_cmnd *pSCmnd;
+-	IDE_STRUCT	 ide;
+-	ULONG		 startSector;
+-	USHORT		 sectorCount;
+-	struct scsi_cmnd *SCpnt;
+-	VOID		*buffer;
+-	USHORT		 expectingIRQ;
+-	}	ADAPTER240I, *PADAPTER240I;
+-
+-#define HOSTDATA(host) ((PADAPTER240I)&host->hostdata)
+-
+-static struct	Scsi_Host *PsiHost[6] = {NULL,};  /* One for each IRQ level (10-15) */
+-static			IDENTIFY_DATA	identifyData;
+-static			SETUP			ChipSetup;
+-
+-static	USHORT	portAddr[6] = {CHIP_ADRS_0, CHIP_ADRS_1, CHIP_ADRS_2, CHIP_ADRS_3, CHIP_ADRS_4, CHIP_ADRS_5};
+-
+-/****************************************************************
+- *	Name:	WriteData	:LOCAL
+- *
+- *	Description:	Write data to device.
+- *
+- *	Parameters:		padapter - Pointer adapter data structure.
+- *
+- *	Returns:		TRUE if drive does not assert DRQ in time.
+- *
+- ****************************************************************/
+-static int WriteData (PADAPTER240I padapter)
+-	{
+-	ULONG	timer;
+-	USHORT *pports = padapter->ports;
+-
+-	timer = jiffies + TIMEOUT_DRQ;								// calculate the timeout value
+-	do  {
+-		if ( inb_p (pports[PORT_STAT_CMD]) & IDE_STATUS_DRQ )
+-			{
+-			outsw (pports[PORT_DATA], padapter->buffer, (USHORT)padapter->ide.ide.ide[2] * 256);
+-			return 0;
+-			}
+-		}	while ( time_after(timer, jiffies) );									// test for timeout
+-
+-	padapter->ide.ide.ides.cmd = 0;									// null out the command byte
+-	return 1;
+-	}
+-/****************************************************************
+- *	Name:	IdeCmd	:LOCAL
+- *
+- *	Description:	Process a queued command from the SCSI manager.
+- *
+- *	Parameters:		padapter - Pointer adapter data structure.
+- *
+- *	Returns:		Zero if no error or status register contents on error.
+- *
+- ****************************************************************/
+-static UCHAR IdeCmd (PADAPTER240I padapter)
+-	{
+-	ULONG	timer;
+-	USHORT *pports = padapter->ports;
+-	UCHAR	status;
+-
+-	outb_p (padapter->ide.ide.ides.spigot, pports[PORT_SEL_FAIL]);	// select the spigot
+-	outb_p (padapter->ide.ide.ide[6], pports[PORT_LBA_24]);			// select the drive
+-	timer = jiffies + TIMEOUT_READY;							// calculate the timeout value
+-	do  {
+-		status = inb_p (padapter->ports[PORT_STAT_CMD]);
+-		if ( status & IDE_STATUS_DRDY )
+-			{
+-			outb_p (padapter->ide.ide.ide[2], pports[PORT_SECTOR_COUNT]);
+-			outb_p (padapter->ide.ide.ide[3], pports[PORT_LBA_0]);
+-			outb_p (padapter->ide.ide.ide[4], pports[PORT_LBA_8]);
+-			outb_p (padapter->ide.ide.ide[5], pports[PORT_LBA_16]);
+-			padapter->expectingIRQ = 1;
+-			outb_p (padapter->ide.ide.ide[7], pports[PORT_STAT_CMD]);
+-
+-			if ( padapter->ide.ide.ides.cmd == IDE_CMD_WRITE_MULTIPLE )
+-				return (WriteData (padapter));
+-
+-			return 0;
+-			}
+-		}	while ( time_after(timer, jiffies) );									// test for timeout
+-
+-	padapter->ide.ide.ides.cmd = 0;									// null out the command byte
+-	return status;
+-	}
+-/****************************************************************
+- *	Name:	SetupTransfer	:LOCAL
+- *
+- *	Description:	Setup a data transfer command.
+- *
+- *	Parameters:		padapter - Pointer adapter data structure.
+- *					drive	 - Drive/head register upper nibble only.
+- *
+- *	Returns:		TRUE if no data to transfer.
+- *
+- ****************************************************************/
+-static int SetupTransfer (PADAPTER240I padapter, UCHAR drive)
+-	{
+-	if ( padapter->sectorCount )
+-		{
+-		*(ULONG *)padapter->ide.ide.ides.lba = padapter->startSector;
+-		padapter->ide.ide.ide[6] |= drive;
+-		padapter->ide.ide.ides.sectors = ( padapter->sectorCount > SECTORSXFER ) ? SECTORSXFER : padapter->sectorCount;
+-		padapter->sectorCount -= padapter->ide.ide.ides.sectors;	// bump the start and count for next xfer
+-		padapter->startSector += padapter->ide.ide.ides.sectors;
+-		return 0;
+-		}
+-	else
+-		{
+-		padapter->ide.ide.ides.cmd = 0;								// null out the command byte
+-		padapter->SCpnt = NULL;
+-		return 1;
+-		}
+-	}
+-/****************************************************************
+- *	Name:	DecodeError	:LOCAL
+- *
+- *	Description:	Decode and process device errors.
+- *
+- *	Parameters:		pshost - Pointer to host data block.
+- *					status - Status register code.
+- *
+- *	Returns:		The driver status code.
+- *
+- ****************************************************************/
+-static ULONG DecodeError (struct Scsi_Host *pshost, UCHAR status)
+-	{
+-	PADAPTER240I	padapter = HOSTDATA(pshost);
+-	UCHAR			error;
+-
+-	padapter->expectingIRQ = 0;
+-	padapter->SCpnt = NULL;
+-	if ( status & IDE_STATUS_WRITE_FAULT )
+-		{
+-		return DID_PARITY << 16;
+-		}
+-	if ( status & IDE_STATUS_BUSY )
+-		return DID_BUS_BUSY << 16;
+-
+-	error = inb_p (padapter->ports[PORT_ERROR]);
+-	DEB(printk ("\npsi240i error register: %x", error));
+-	switch ( error )
+-		{
+-		case IDE_ERROR_AMNF:
+-		case IDE_ERROR_TKONF:
+-		case IDE_ERROR_ABRT:
+-		case IDE_ERROR_IDFN:
+-		case IDE_ERROR_UNC:
+-		case IDE_ERROR_BBK:
+-		default:
+-			return DID_ERROR << 16;
+-		}
+-	return DID_ERROR << 16;
+-	}
+-/****************************************************************
+- *	Name:	Irq_Handler	:LOCAL
+- *
+- *	Description:	Interrupt handler.
+- *
+- *	Parameters:		irq		- Hardware IRQ number.
+- *					dev_id	-
+- *
+- *	Returns:		TRUE if drive is not ready in time.
+- *
+- ****************************************************************/
+-static void Irq_Handler (int irq, void *dev_id)
+-	{
+-	struct Scsi_Host *shost;	// Pointer to host data block
+-	PADAPTER240I padapter;		// Pointer to adapter control structure
+-	USHORT *pports;			// I/O port array
+-	struct scsi_cmnd *SCpnt;
+-	UCHAR status;
+-	int z;
+-
+-	DEB(printk ("\npsi240i received interrupt\n"));
+-
+-	shost = PsiHost[irq - 10];
+-	if ( !shost )
+-		panic ("Splunge!");
+-
+-	padapter = HOSTDATA(shost);
+-	pports = padapter->ports;
+-	SCpnt = padapter->SCpnt;
+-
+-	if ( !padapter->expectingIRQ )
+-		{
+-		DEB(printk ("\npsi240i Unsolicited interrupt\n"));
+-		return;
+-		}
+-	padapter->expectingIRQ = 0;
+-
+-	status = inb_p (padapter->ports[PORT_STAT_CMD]);			// read the device status
+-	if ( status & (IDE_STATUS_ERROR | IDE_STATUS_WRITE_FAULT) )
+-		goto irqerror;
+-
+-	DEB(printk ("\npsi240i processing interrupt"));
+-	switch ( padapter->ide.ide.ides.cmd )							// decide how to handle the interrupt
+-		{
+-		case IDE_CMD_READ_MULTIPLE:
+-			if ( status & IDE_STATUS_DRQ )
+-				{
+-				insw (pports[PORT_DATA], padapter->buffer, (USHORT)padapter->ide.ide.ides.sectors * 256);
+-				padapter->buffer += padapter->ide.ide.ides.sectors * 512;
+-				if ( SetupTransfer (padapter, padapter->ide.ide.ide[6] & 0xF0) )
+-					{
+-					SCpnt->result = DID_OK << 16;
+-					padapter->SCpnt = NULL;
+-					SCpnt->scsi_done (SCpnt);
+-					return;
+-					}
+-				if ( !(status = IdeCmd (padapter)) )
+-					return;
+-				}
+-			break;
+-
+-		case IDE_CMD_WRITE_MULTIPLE:
+-			padapter->buffer += padapter->ide.ide.ides.sectors * 512;
+-			if ( SetupTransfer (padapter, padapter->ide.ide.ide[6] & 0xF0) )
+-				{
+-				SCpnt->result = DID_OK << 16;
+-				padapter->SCpnt = NULL;
+-				SCpnt->scsi_done (SCpnt);
+-				return;
+-				}
+-			if ( !(status = IdeCmd (padapter)) )
+-				return;
+-			break;
+-
+-		case IDE_COMMAND_IDENTIFY:
+-			{
+-			PINQUIRYDATA	pinquiryData  = SCpnt->request_buffer;
+-
+-			if ( status & IDE_STATUS_DRQ )
+-				{
+-				insw (pports[PORT_DATA], &identifyData, sizeof (identifyData) >> 1);
+-
+-				memset (pinquiryData, 0, SCpnt->request_bufflen);		// Zero INQUIRY data structure.
+-				pinquiryData->DeviceType = 0;
+-				pinquiryData->Versions = 2;
+-				pinquiryData->AdditionalLength = 35 - 4;
+-
+-				// Fill in vendor identification fields.
+-				for ( z = 0;  z < 8;  z += 2 )
+-					{
+-					pinquiryData->VendorId[z]	  = ((UCHAR *)identifyData.ModelNumber)[z + 1];
+-					pinquiryData->VendorId[z + 1] = ((UCHAR *)identifyData.ModelNumber)[z];
+-					}
+-
+-				// Initialize unused portion of product id.
+-				for ( z = 0;  z < 4;  z++ )
+-					pinquiryData->ProductId[12 + z] = ' ';
+-
+-				// Move firmware revision from IDENTIFY data to
+-				// product revision in INQUIRY data.
+-				for ( z = 0;  z < 4;  z += 2 )
+-					{
+-					pinquiryData->ProductRevisionLevel[z]	 = ((UCHAR *)identifyData.FirmwareRevision)[z + 1];
+-					pinquiryData->ProductRevisionLevel[z + 1] = ((UCHAR *)identifyData.FirmwareRevision)[z];
+-					}
+-
+-				SCpnt->result = DID_OK << 16;
+-				padapter->SCpnt = NULL;
+-				SCpnt->scsi_done (SCpnt);
+-				return;
+-				}
+-			break;
+-			}
+-
+-		default:
+-			SCpnt->result = DID_OK << 16;
+-			padapter->SCpnt = NULL;
+-			SCpnt->scsi_done (SCpnt);
+-			return;
+-		}
+-
+-irqerror:;
+-	DEB(printk ("\npsi240i error  Device Status: %X\n", status));
+-	SCpnt->result = DecodeError (shost, status);
+-	SCpnt->scsi_done (SCpnt);
+-	}
+-
+-static irqreturn_t do_Irq_Handler (int irq, void *dev_id)
 -{
--	struct iscsi_session *session = conn->session;
--	struct iscsi_mgmt_task *mtask;
+-	unsigned long flags;
+-	struct Scsi_Host *dev = dev_id;
+-	
+-	spin_lock_irqsave(dev->host_lock, flags);
+-	Irq_Handler(irq, dev_id);
+-	spin_unlock_irqrestore(dev->host_lock, flags);
+-	return IRQ_HANDLED;
+-}
 -
--	if (session->state == ISCSI_STATE_TERMINATE)
--		return NULL;
+-/****************************************************************
+- *	Name:	Psi240i_QueueCommand
+- *
+- *	Description:	Process a queued command from the SCSI manager.
+- *
+- *	Parameters:		SCpnt - Pointer to SCSI command structure.
+- *					done  - Pointer to done function to call.
+- *
+- *	Returns:		Status code.
+- *
+- ****************************************************************/
+-static int Psi240i_QueueCommand(struct scsi_cmnd *SCpnt,
+-				void (*done)(struct scsi_cmnd *))
+-	{
+-	UCHAR *cdb = (UCHAR *)SCpnt->cmnd;
+-	// Pointer to SCSI CDB
+-	PADAPTER240I padapter = HOSTDATA (SCpnt->device->host);
+-	// Pointer to adapter control structure
+-	POUR_DEVICE pdev = &padapter->device [SCpnt->device->id];
+-	// Pointer to device information
+-	UCHAR rc;
+-	// command return code
 -
--	if (hdr->opcode == (ISCSI_OP_LOGIN | ISCSI_OP_IMMEDIATE) ||
--	    hdr->opcode == (ISCSI_OP_TEXT | ISCSI_OP_IMMEDIATE))
--		/*
--		 * Login and Text are sent serially, in
--		 * request-followed-by-response sequence.
--		 * Same mtask can be used. Same ITT must be used.
--		 * Note that login_mtask is preallocated at conn_create().
--		 */
--		mtask = conn->login_mtask;
--	else {
--		BUG_ON(conn->c_stage == ISCSI_CONN_INITIAL_STAGE);
--		BUG_ON(conn->c_stage == ISCSI_CONN_STOPPED);
+-	SCpnt->scsi_done = done;
+-	padapter->ide.ide.ides.spigot = pdev->spigot;
+-	padapter->buffer = SCpnt->request_buffer;
+-	if (done)
+-		{
+-		if ( !pdev->device )
+-			{
+-			SCpnt->result = DID_BAD_TARGET << 16;
+-			done (SCpnt);
+-			return 0;
+-			}
+-		}
+-	else
+-		{
+-		printk("psi240i_queuecommand: %02X: done can't be NULL\n", *cdb);
+-		return 0;
+-		}
+-
+-	switch ( *cdb )
+-		{
+-		case SCSIOP_INQUIRY:   					// inquiry CDB
+-			{
+-			padapter->ide.ide.ide[6] = pdev->byte6;
+-			padapter->ide.ide.ides.cmd = IDE_COMMAND_IDENTIFY;
+-			break;
+-			}
+-
+-		case SCSIOP_TEST_UNIT_READY:			// test unit ready CDB
+-			SCpnt->result = DID_OK << 16;
+-			done (SCpnt);
+-			return 0;
+-
+-		case SCSIOP_READ_CAPACITY:			  	// read capctiy CDB
+-			{
+-			PREAD_CAPACITY_DATA	pdata = (PREAD_CAPACITY_DATA)SCpnt->request_buffer;
+-
+-			pdata->blksiz = 0x20000;
+-			XANY2SCSI ((UCHAR *)&pdata->blks, pdev->blocks);
+-			SCpnt->result = DID_OK << 16;
+-			done (SCpnt);
+-			return 0;
+-			}
+-
+-		case SCSIOP_VERIFY:						// verify CDB
+-			*(ULONG *)padapter->ide.ide.ides.lba = XSCSI2LONG (&cdb[2]);
+-			padapter->ide.ide.ide[6] |= pdev->byte6;
+-			padapter->ide.ide.ide[2] = (UCHAR)((USHORT)cdb[8] | ((USHORT)cdb[7] << 8));
+-			padapter->ide.ide.ides.cmd = IDE_COMMAND_VERIFY;
+-			break;
+-
+-		case SCSIOP_READ:						// read10 CDB
+-			padapter->startSector = XSCSI2LONG (&cdb[2]);
+-			padapter->sectorCount = (USHORT)cdb[8] | ((USHORT)cdb[7] << 8);
+-			SetupTransfer (padapter, pdev->byte6);
+-			padapter->ide.ide.ides.cmd = IDE_CMD_READ_MULTIPLE;
+-			break;
+-
+-		case SCSIOP_READ6:						// read6  CDB
+-			padapter->startSector = SCSI2LONG (&cdb[1]);
+-			padapter->sectorCount = cdb[4];
+-			SetupTransfer (padapter, pdev->byte6);
+-			padapter->ide.ide.ides.cmd = IDE_CMD_READ_MULTIPLE;
+-			break;
+-
+-		case SCSIOP_WRITE:						// write10 CDB
+-			padapter->startSector = XSCSI2LONG (&cdb[2]);
+-			padapter->sectorCount = (USHORT)cdb[8] | ((USHORT)cdb[7] << 8);
+-			SetupTransfer (padapter, pdev->byte6);
+-			padapter->ide.ide.ides.cmd = IDE_CMD_WRITE_MULTIPLE;
+-			break;
+-		case SCSIOP_WRITE6:						// write6  CDB
+-			padapter->startSector = SCSI2LONG (&cdb[1]);
+-			padapter->sectorCount = cdb[4];
+-			SetupTransfer (padapter, pdev->byte6);
+-			padapter->ide.ide.ides.cmd = IDE_CMD_WRITE_MULTIPLE;
+-			break;
+-
+-		default:
+-			DEB (printk ("psi240i_queuecommand: Unsupported command %02X\n", *cdb));
+-			SCpnt->result = DID_ERROR << 16;
+-			done (SCpnt);
+-			return 0;
+-		}
+-
+-	padapter->SCpnt = SCpnt;  									// Save this command data
+-
+-	rc = IdeCmd (padapter);
+-	if ( rc )
+-		{
+-		padapter->expectingIRQ = 0;
+-		DEB (printk ("psi240i_queuecommand: %02X, %02X: Device failed to respond for command\n", *cdb, padapter->ide.ide.ides.cmd));
+-		SCpnt->result = DID_ERROR << 16;
+-		done (SCpnt);
+-		return 0;
+-		}
+-	DEB (printk("psi240i_queuecommand: %02X, %02X now waiting for interrupt ", *cdb, padapter->ide.ide.ides.cmd));
+-	return 0;
+-	}
+-
+-/***************************************************************************
+- *	Name:			ReadChipMemory
+- *
+- *	Description:	Read information from controller memory.
+- *
+- *	Parameters:		psetup	- Pointer to memory image of setup information.
+- *					base	- base address of memory.
+- *					length	- lenght of data space in bytes.
+- *					port	- I/O address of data port.
+- *
+- *	Returns:		Nothing.
+- *
+- **************************************************************************/
+-static void ReadChipMemory (void *pdata, USHORT base, USHORT length, USHORT port)
+-	{
+-	USHORT	z, zz;
+-	UCHAR	*pd = (UCHAR *)pdata;
+-	outb_p (SEL_NONE, port + REG_SEL_FAIL);				// setup data port
+-	zz = 0;
+-	while ( zz < length )
+-		{
+-		outw_p (base, port + REG_ADDRESS);				// setup address
+-
+-		for ( z = 0;  z < 8;  z++ )
+-			{
+-			if ( (zz + z) < length )
+-			*pd++ = inb_p (port + z);	// read data byte
+-			}
+-		zz += 8;
+-		base += 8;
+-		}
+-	}
+-/****************************************************************
+- *	Name:	Psi240i_Detect
+- *
+- *	Description:	Detect and initialize our boards.
+- *
+- *	Parameters:		tpnt - Pointer to SCSI host template structure.
+- *
+- *	Returns:		Number of adapters found.
+- *
+- ****************************************************************/
+-static int Psi240i_Detect (struct scsi_host_template *tpnt)
+-	{
+-	int					board;
+-	int					count = 0;
+-	int					unit;
+-	int					z;
+-	USHORT				port, port_range = 16;
+-	CHIP_CONFIG_N		chipConfig;
+-	CHIP_DEVICE_N		chipDevice[8];
+-	struct Scsi_Host   *pshost;
+-
+-	for ( board = 0;  board < MAXBOARDS;  board++ )					// scan for I/O ports
+-		{
+-		pshost = NULL;
+-		port = portAddr[board];								// get base address to test
+-		if ( !request_region (port, port_range, "psi240i") )
+-			continue;
+-		if ( inb_p (port + REG_FAIL) != CHIP_ID )			// do the first test for likley hood that it is us
+-			goto host_init_failure;
+-		outb_p (SEL_NONE, port + REG_SEL_FAIL);				// setup EEPROM/RAM access
+-		outw (0, port + REG_ADDRESS);						// setup EEPROM address zero
+-		if ( inb_p (port) != 0x55 )							// test 1st byte
+-			goto host_init_failure;									//   nope
+-		if ( inb_p (port + 1) != 0xAA )						// test 2nd byte
+-			goto host_init_failure;								//   nope
+-
+-		// at this point our board is found and can be accessed.  Now we need to initialize
+-		// our informatation and register with the kernel.
+-
+-
+-		ReadChipMemory (&chipConfig, CHIP_CONFIG, sizeof (chipConfig), port);
+-		ReadChipMemory (&chipDevice, CHIP_DEVICE, sizeof (chipDevice), port);
+-		ReadChipMemory (&ChipSetup, CHIP_EEPROM_DATA, sizeof (ChipSetup), port);
+-
+-		if ( !chipConfig.numDrives )						// if no devices on this board
+-			goto host_init_failure;
+-
+-		pshost = scsi_register (tpnt, sizeof(ADAPTER240I));
+-		if(pshost == NULL)
+-			goto host_init_failure;	
+-
+-		PsiHost[chipConfig.irq - 10] = pshost;
+-		pshost->unique_id = port;
+-		pshost->io_port = port;
+-		pshost->n_io_port = 16;  /* Number of bytes of I/O space used */
+-		pshost->irq = chipConfig.irq;
+-
+-		for ( z = 0;  z < 11;  z++ )						// build regester address array
+-			HOSTDATA(pshost)->ports[z] = port + z;
+-		HOSTDATA(pshost)->ports[11] = port + REG_FAIL;
+-		HOSTDATA(pshost)->ports[12] = port + REG_ALT_STAT;
+-		DEB (printk ("\nPorts ="));
+-		DEB (for (z=0;z<13;z++) printk(" %#04X",HOSTDATA(pshost)->ports[z]););
+-
+-		for ( z = 0;  z < chipConfig.numDrives;  ++z )
+-			{
+-			unit = chipDevice[z].channel & 0x0F;
+-			HOSTDATA(pshost)->device[unit].device	 = ChipSetup.setupDevice[unit].device;
+-			HOSTDATA(pshost)->device[unit].byte6	 = (UCHAR)(((unit & 1) << 4) | 0xE0);
+-			HOSTDATA(pshost)->device[unit].spigot	 = (UCHAR)(1 << (unit >> 1));
+-			HOSTDATA(pshost)->device[unit].sectors	 = ChipSetup.setupDevice[unit].sectors;
+-			HOSTDATA(pshost)->device[unit].heads	 = ChipSetup.setupDevice[unit].heads;
+-			HOSTDATA(pshost)->device[unit].cylinders = ChipSetup.setupDevice[unit].cylinders;
+-			HOSTDATA(pshost)->device[unit].blocks	 = ChipSetup.setupDevice[unit].blocks;
+-			DEB (printk ("\nHOSTDATA->device    = %X", HOSTDATA(pshost)->device[unit].device));
+-			DEB (printk ("\n          byte6     = %X", HOSTDATA(pshost)->device[unit].byte6));
+-			DEB (printk ("\n          spigot    = %X", HOSTDATA(pshost)->device[unit].spigot));
+-			DEB (printk ("\n          sectors   = %X", HOSTDATA(pshost)->device[unit].sectors));
+-			DEB (printk ("\n          heads     = %X", HOSTDATA(pshost)->device[unit].heads));
+-			DEB (printk ("\n          cylinders = %X", HOSTDATA(pshost)->device[unit].cylinders));
+-			DEB (printk ("\n          blocks    = %lX", HOSTDATA(pshost)->device[unit].blocks));
+-			}
 -
--		if (!__kfifo_get(session->mgmtpool.queue,
--				 (void*)&mtask, sizeof(void*)))
--			return NULL;
--	}
+-		if ( request_irq (chipConfig.irq, do_Irq_Handler, 0, "psi240i", pshost) == 0 ) 
+-			{
+-			printk("\nPSI-240I EIDE CONTROLLER: at I/O = %x  IRQ = %d\n", port, chipConfig.irq);
+-		        printk("(C) 1997 Perceptive Solutions, Inc. All rights reserved\n\n");
+-		        count++;
+-		        continue;
+-			}
 -
--	if (data_size) {
--		memcpy(mtask->data, data, data_size);
--		mtask->data_count = data_size;
--	} else
--		mtask->data_count = 0;
+-		printk ("Unable to allocate IRQ for PSI-240I controller.\n");
+-           
+-host_init_failure:
+-		
+-		release_region (port, port_range);
+-		if (pshost)
+-			scsi_unregister (pshost);
 -
--	INIT_LIST_HEAD(&mtask->running);
--	memcpy(mtask->hdr, hdr, sizeof(struct iscsi_hdr));
--	__kfifo_put(conn->mgmtqueue, (void*)&mtask, sizeof(void*));
--	return mtask;
--}
+-		}
+-	return count;
+-	}
 -
--int iscsi_conn_send_pdu(struct iscsi_cls_conn *cls_conn, struct iscsi_hdr *hdr,
--			char *data, uint32_t data_size)
+-static int Psi240i_Release(struct Scsi_Host *shost)
 -{
--	struct iscsi_conn *conn = cls_conn->dd_data;
--	struct iscsi_session *session = conn->session;
--	int err = 0;
--
--	spin_lock_bh(&session->lock);
--	if (!__iscsi_conn_send_pdu(conn, hdr, data, data_size))
--		err = -EPERM;
--	spin_unlock_bh(&session->lock);
--	scsi_queue_work(session->host, &conn->xmitwork);
--	return err;
+-	if (shost->irq)
+-		free_irq(shost->irq, NULL);
+-	if (shost->io_port && shost->n_io_port)
+-		release_region(shost->io_port, shost->n_io_port);
+-	scsi_unregister(shost);
+-	return 0;
 -}
--EXPORT_SYMBOL_GPL(iscsi_conn_send_pdu);
 -
- void iscsi_session_recovery_timedout(struct iscsi_cls_session *cls_session)
- {
- 	struct iscsi_session *session = class_to_transport_session(cls_session);
--	struct iscsi_conn *conn = session->leadconn;
- 
- 	spin_lock_bh(&session->lock);
- 	if (session->state != ISCSI_STATE_LOGGED_IN) {
- 		session->state = ISCSI_STATE_RECOVERY_FAILED;
--		if (conn)
--			wake_up(&conn->ehwait);
-+		if (session->leadconn)
-+			wake_up(&session->leadconn->ehwait);
- 	}
- 	spin_unlock_bh(&session->lock);
- }
-@@ -971,30 +1129,25 @@ int iscsi_eh_host_reset(struct scsi_cmnd *sc)
- 	struct Scsi_Host *host = sc->device->host;
- 	struct iscsi_session *session = iscsi_hostdata(host->hostdata);
- 	struct iscsi_conn *conn = session->leadconn;
--	int fail_session = 0;
- 
-+	mutex_lock(&session->eh_mutex);
- 	spin_lock_bh(&session->lock);
- 	if (session->state == ISCSI_STATE_TERMINATE) {
- failed:
- 		debug_scsi("failing host reset: session terminated "
- 			   "[CID %d age %d]\n", conn->id, session->age);
- 		spin_unlock_bh(&session->lock);
-+		mutex_unlock(&session->eh_mutex);
- 		return FAILED;
- 	}
- 
--	if (sc->SCp.phase == session->age) {
--		debug_scsi("failing connection CID %d due to SCSI host reset\n",
--			   conn->id);
--		fail_session = 1;
+-/****************************************************************
+- *	Name:	Psi240i_BiosParam
+- *
+- *	Description:	Process the biosparam request from the SCSI manager to
+- *					return C/H/S data.
+- *
+- *	Parameters:		disk - Pointer to SCSI disk structure.
+- *					dev	 - Major/minor number from kernel.
+- *					geom - Pointer to integer array to place geometry data.
+- *
+- *	Returns:		zero.
+- *
+- ****************************************************************/
+-static int Psi240i_BiosParam (struct scsi_device *sdev, struct block_device *dev,
+-		sector_t capacity, int geom[])
+-	{
+-	POUR_DEVICE	pdev;
+-
+-	pdev = &(HOSTDATA(sdev->host)->device[sdev_id(sdev)]);
+-
+-	geom[0] = pdev->heads;
+-	geom[1] = pdev->sectors;
+-	geom[2] = pdev->cylinders;
+-	return 0;
 -	}
- 	spin_unlock_bh(&session->lock);
 -
-+	mutex_unlock(&session->eh_mutex);
- 	/*
- 	 * we drop the lock here but the leadconn cannot be destoyed while
- 	 * we are in the scsi eh
- 	 */
--	if (fail_session)
--		iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
-+	iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
- 
- 	debug_scsi("iscsi_eh_host_reset wait for relogin\n");
- 	wait_event_interruptible(conn->ehwait,
-@@ -1004,73 +1157,56 @@ failed:
- 	if (signal_pending(current))
- 		flush_signals(current);
- 
-+	mutex_lock(&session->eh_mutex);
- 	spin_lock_bh(&session->lock);
- 	if (session->state == ISCSI_STATE_LOGGED_IN)
- 		printk(KERN_INFO "iscsi: host reset succeeded\n");
- 	else
- 		goto failed;
- 	spin_unlock_bh(&session->lock);
+-MODULE_LICENSE("GPL");
 -
-+	mutex_unlock(&session->eh_mutex);
- 	return SUCCESS;
- }
- EXPORT_SYMBOL_GPL(iscsi_eh_host_reset);
- 
--static void iscsi_tmabort_timedout(unsigned long data)
-+static void iscsi_tmf_timedout(unsigned long data)
- {
--	struct iscsi_cmd_task *ctask = (struct iscsi_cmd_task *)data;
--	struct iscsi_conn *conn = ctask->conn;
-+	struct iscsi_conn *conn = (struct iscsi_conn *)data;
- 	struct iscsi_session *session = conn->session;
- 
- 	spin_lock(&session->lock);
--	if (conn->tmabort_state == TMABORT_INITIAL) {
--		conn->tmabort_state = TMABORT_TIMEDOUT;
--		debug_scsi("tmabort timedout [sc %p itt 0x%x]\n",
--			ctask->sc, ctask->itt);
-+	if (conn->tmf_state == TMF_QUEUED) {
-+		conn->tmf_state = TMF_TIMEDOUT;
-+		debug_scsi("tmf timedout\n");
- 		/* unblock eh_abort() */
- 		wake_up(&conn->ehwait);
- 	}
- 	spin_unlock(&session->lock);
- }
- 
--static int iscsi_exec_abort_task(struct scsi_cmnd *sc,
--				 struct iscsi_cmd_task *ctask)
-+static int iscsi_exec_task_mgmt_fn(struct iscsi_conn *conn,
-+				   struct iscsi_tm *hdr, int age,
-+				   int timeout)
- {
--	struct iscsi_conn *conn = ctask->conn;
- 	struct iscsi_session *session = conn->session;
--	struct iscsi_tm *hdr = &conn->tmhdr;
+-static struct scsi_host_template driver_template = {
+-	.proc_name		= "psi240i", 
+-	.name			= "PSI-240I EIDE Disk Controller",
+-	.detect			= Psi240i_Detect,
+-	.release		= Psi240i_Release,
+-	.queuecommand		= Psi240i_QueueCommand,
+-	.bios_param	  	= Psi240i_BiosParam,
+-	.can_queue	  	= 1,
+-	.this_id	  	= -1,
+-	.sg_tablesize	  	= SG_NONE,
+-	.cmd_per_lun	  	= 1, 
+-	.use_clustering		= DISABLE_CLUSTERING,
+-};
+-#include "scsi_module.c"
+diff --git a/drivers/scsi/psi240i.h b/drivers/scsi/psi240i.h
+deleted file mode 100644
+index 21ebb92..0000000
+--- a/drivers/scsi/psi240i.h
++++ /dev/null
+@@ -1,315 +0,0 @@
+-/*+M*************************************************************************
+- * Perceptive Solutions, Inc. PSI-240I device driver proc support for Linux.
+- *
+- * Copyright (c) 1997 Perceptive Solutions, 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, or (at your option)
+- * any later version.
+- *
+- * This program is distributed in the hope that it will be useful,
+- * but WITHOUT ANY WARRANTY; without even the implied warranty of
+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See 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, 675 Mass Ave, Cambridge, MA 02139, USA.
+- *
+- *
+- *	File Name:		psi240i.h
+- *
+- *	Description:	Header file for the SCSI driver for the PSI240I
+- *					EIDE interface card.
+- *
+- *-M*************************************************************************/
+-#ifndef _PSI240I_H
+-#define _PSI240I_H
 -
--	/*
--	 * ctask timed out but session is OK requests must be serialized.
--	 */
--	memset(hdr, 0, sizeof(struct iscsi_tm));
--	hdr->opcode = ISCSI_OP_SCSI_TMFUNC | ISCSI_OP_IMMEDIATE;
--	hdr->flags = ISCSI_TM_FUNC_ABORT_TASK;
--	hdr->flags |= ISCSI_FLAG_CMD_FINAL;
--	memcpy(hdr->lun, ctask->hdr->lun, sizeof(hdr->lun));
--	hdr->rtt = ctask->hdr->itt;
--	hdr->refcmdsn = ctask->hdr->cmdsn;
-+	struct iscsi_mgmt_task *mtask;
- 
--	ctask->mtask = __iscsi_conn_send_pdu(conn, (struct iscsi_hdr *)hdr,
--					    NULL, 0);
--	if (!ctask->mtask) {
-+	mtask = __iscsi_conn_send_pdu(conn, (struct iscsi_hdr *)hdr,
-+				      NULL, 0);
-+	if (!mtask) {
- 		spin_unlock_bh(&session->lock);
- 		iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
--		spin_lock_bh(&session->lock)
--		debug_scsi("abort sent failure [itt 0x%x]\n", ctask->itt);
-+		spin_lock_bh(&session->lock);
-+		debug_scsi("tmf exec failure\n");
- 		return -EPERM;
- 	}
--	ctask->state = ISCSI_TASK_ABORTING;
-+	conn->tmfcmd_pdus_cnt++;
-+	conn->tmf_timer.expires = timeout * HZ + jiffies;
-+	conn->tmf_timer.function = iscsi_tmf_timedout;
-+	conn->tmf_timer.data = (unsigned long)conn;
-+	add_timer(&conn->tmf_timer);
-+	debug_scsi("tmf set timeout\n");
- 
--	debug_scsi("abort sent [itt 0x%x]\n", ctask->itt);
+-#include <linux/types.h>
 -
--	if (conn->tmabort_state == TMABORT_INITIAL) {
--		conn->tmfcmd_pdus_cnt++;
--		conn->tmabort_timer.expires = 20*HZ + jiffies;
--		conn->tmabort_timer.function = iscsi_tmabort_timedout;
--		conn->tmabort_timer.data = (unsigned long)ctask;
--		add_timer(&conn->tmabort_timer);
--		debug_scsi("abort set timeout [itt 0x%x]\n", ctask->itt);
--	}
- 	spin_unlock_bh(&session->lock);
- 	mutex_unlock(&session->eh_mutex);
- 	scsi_queue_work(session->host, &conn->xmitwork);
-@@ -1078,113 +1214,197 @@ static int iscsi_exec_abort_task(struct scsi_cmnd *sc,
- 	/*
- 	 * block eh thread until:
- 	 *
--	 * 1) abort response
--	 * 2) abort timeout
-+	 * 1) tmf response
-+	 * 2) tmf timeout
- 	 * 3) session is terminated or restarted or userspace has
- 	 * given up on recovery
- 	 */
--	wait_event_interruptible(conn->ehwait,
--				 sc->SCp.phase != session->age ||
-+	wait_event_interruptible(conn->ehwait, age != session->age ||
- 				 session->state != ISCSI_STATE_LOGGED_IN ||
--				 conn->tmabort_state != TMABORT_INITIAL);
-+				 conn->tmf_state != TMF_QUEUED);
- 	if (signal_pending(current))
- 		flush_signals(current);
--	del_timer_sync(&conn->tmabort_timer);
-+	del_timer_sync(&conn->tmf_timer);
-+
- 	mutex_lock(&session->eh_mutex);
- 	spin_lock_bh(&session->lock);
-+	/* if the session drops it will clean up the mtask */
-+	if (age != session->age ||
-+	    session->state != ISCSI_STATE_LOGGED_IN)
-+		return -ENOTCONN;
- 	return 0;
- }
- 
- /*
-- * session lock must be held
-+ * Fail commands. session lock held and recv side suspended and xmit
-+ * thread flushed
-  */
--static struct iscsi_mgmt_task *
--iscsi_remove_mgmt_task(struct kfifo *fifo, uint32_t itt)
-+static void fail_all_commands(struct iscsi_conn *conn, unsigned lun)
- {
--	int i, nr_tasks = __kfifo_len(fifo) / sizeof(void*);
--	struct iscsi_mgmt_task *task;
-+	struct iscsi_cmd_task *ctask, *tmp;
- 
--	debug_scsi("searching %d tasks\n", nr_tasks);
-+	if (conn->ctask && (conn->ctask->sc->device->lun == lun || lun == -1))
-+		conn->ctask = NULL;
- 
--	for (i = 0; i < nr_tasks; i++) {
--		__kfifo_get(fifo, (void*)&task, sizeof(void*));
--		debug_scsi("check task %u\n", task->itt);
-+	/* flush pending */
-+	list_for_each_entry_safe(ctask, tmp, &conn->xmitqueue, running) {
-+		if (lun == ctask->sc->device->lun || lun == -1) {
-+			debug_scsi("failing pending sc %p itt 0x%x\n",
-+				   ctask->sc, ctask->itt);
-+			fail_command(conn, ctask, DID_BUS_BUSY << 16);
-+		}
-+	}
- 
--		if (task->itt == itt) {
--			debug_scsi("matched task\n");
--			return task;
-+	list_for_each_entry_safe(ctask, tmp, &conn->requeue, running) {
-+		if (lun == ctask->sc->device->lun || lun == -1) {
-+			debug_scsi("failing requeued sc %p itt 0x%x\n",
-+				   ctask->sc, ctask->itt);
-+			fail_command(conn, ctask, DID_BUS_BUSY << 16);
- 		}
-+	}
- 
--		__kfifo_put(fifo, (void*)&task, sizeof(void*));
-+	/* fail all other running */
-+	list_for_each_entry_safe(ctask, tmp, &conn->run_list, running) {
-+		if (lun == ctask->sc->device->lun || lun == -1) {
-+			debug_scsi("failing in progress sc %p itt 0x%x\n",
-+				   ctask->sc, ctask->itt);
-+			fail_command(conn, ctask, DID_BUS_BUSY << 16);
-+		}
- 	}
--	return NULL;
- }
- 
--static int iscsi_ctask_mtask_cleanup(struct iscsi_cmd_task *ctask)
-+static void iscsi_suspend_tx(struct iscsi_conn *conn)
- {
--	struct iscsi_conn *conn = ctask->conn;
--	struct iscsi_session *session = conn->session;
+-#ifndef	PSI_EIDE_SCSIOP
+-#define	PSI_EIDE_SCSIOP	1
 -
--	if (!ctask->mtask)
--		return -EINVAL;
-+	set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
-+	scsi_flush_work(conn->session->host);
-+}
- 
--	if (!iscsi_remove_mgmt_task(conn->mgmtqueue, ctask->mtask->itt))
--		list_del(&ctask->mtask->running);
--	__kfifo_put(session->mgmtpool.queue, (void*)&ctask->mtask,
--		    sizeof(void*));
--	ctask->mtask = NULL;
--	return 0;
-+static void iscsi_start_tx(struct iscsi_conn *conn)
-+{
-+	clear_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
-+	scsi_queue_work(conn->session->host, &conn->xmitwork);
- }
- 
--/*
-- * session lock must be held
-- */
--static void fail_command(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask,
--			 int err)
-+static enum scsi_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *scmd)
- {
--	struct scsi_cmnd *sc;
-+	struct iscsi_cls_session *cls_session;
-+	struct iscsi_session *session;
-+	struct iscsi_conn *conn;
-+	enum scsi_eh_timer_return rc = EH_NOT_HANDLED;
- 
--	sc = ctask->sc;
--	if (!sc)
--		return;
-+	cls_session = starget_to_session(scsi_target(scmd->device));
-+	session = class_to_transport_session(cls_session);
- 
--	if (ctask->state == ISCSI_TASK_PENDING)
-+	debug_scsi("scsi cmd %p timedout\n", scmd);
-+
-+	spin_lock(&session->lock);
-+	if (session->state != ISCSI_STATE_LOGGED_IN) {
- 		/*
--		 * cmd never made it to the xmit thread, so we should not count
--		 * the cmd in the sequencing
-+		 * We are probably in the middle of iscsi recovery so let
-+		 * that complete and handle the error.
- 		 */
--		conn->session->queued_cmdsn--;
--	else
--		conn->session->tt->cleanup_cmd_task(conn, ctask);
--	iscsi_ctask_mtask_cleanup(ctask);
-+		rc = EH_RESET_TIMER;
-+		goto done;
-+	}
- 
--	sc->result = err;
--	scsi_set_resid(sc, scsi_bufflen(sc));
--	if (conn->ctask == ctask)
--		conn->ctask = NULL;
--	/* release ref from queuecommand */
--	__iscsi_put_ctask(ctask);
-+	conn = session->leadconn;
-+	if (!conn) {
-+		/* In the middle of shuting down */
-+		rc = EH_RESET_TIMER;
-+		goto done;
-+	}
-+
-+	if (!conn->recv_timeout && !conn->ping_timeout)
-+		goto done;
-+	/*
-+	 * if the ping timedout then we are in the middle of cleaning up
-+	 * and can let the iscsi eh handle it
-+	 */
-+	if (time_before_eq(conn->last_recv + (conn->recv_timeout * HZ) +
-+			    (conn->ping_timeout * HZ), jiffies))
-+		rc = 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;
-+	/* if in the middle of checking the transport then give us more time */
-+	if (conn->ping_mtask)
-+		rc = EH_RESET_TIMER;
-+done:
-+	spin_unlock(&session->lock);
-+	debug_scsi("return %s\n", rc == EH_RESET_TIMER ? "timer reset" : "nh");
-+	return rc;
- }
- 
--static void iscsi_suspend_tx(struct iscsi_conn *conn)
-+static void iscsi_check_transport_timeouts(unsigned long data)
- {
--	set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
--	scsi_flush_work(conn->session->host);
-+	struct iscsi_conn *conn = (struct iscsi_conn *)data;
-+	struct iscsi_session *session = conn->session;
-+	unsigned long timeout, next_timeout = 0, last_recv;
-+
-+	spin_lock(&session->lock);
-+	if (session->state != ISCSI_STATE_LOGGED_IN)
-+		goto done;
-+
-+	timeout = conn->recv_timeout;
-+	if (!timeout)
-+		goto done;
-+
-+	timeout *= HZ;
-+	last_recv = conn->last_recv;
-+	if (time_before_eq(last_recv + timeout + (conn->ping_timeout * HZ),
-+			   jiffies)) {
-+		printk(KERN_ERR "ping timeout of %d secs expired, "
-+		       "last rx %lu, last ping %lu, now %lu\n",
-+		       conn->ping_timeout, last_recv,
-+		       conn->last_ping, jiffies);
-+		spin_unlock(&session->lock);
-+		iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
-+		return;
-+	}
-+
-+	if (time_before_eq(last_recv + timeout, jiffies)) {
-+		if (time_before_eq(conn->last_ping, last_recv)) {
-+			/* send a ping to try to provoke some traffic */
-+			debug_scsi("Sending nopout as ping on conn %p\n", conn);
-+			iscsi_send_nopout(conn, NULL);
-+		}
-+		next_timeout = last_recv + timeout + (conn->ping_timeout * HZ);
-+	} else {
-+		next_timeout = last_recv + timeout;
-+	}
-+
-+	if (next_timeout) {
-+		debug_scsi("Setting next tmo %lu\n", next_timeout);
-+		mod_timer(&conn->transport_timer, next_timeout);
-+	}
-+done:
-+	spin_unlock(&session->lock);
- }
- 
--static void iscsi_start_tx(struct iscsi_conn *conn)
-+static void iscsi_prep_abort_task_pdu(struct iscsi_cmd_task *ctask,
-+				      struct iscsi_tm *hdr)
- {
--	clear_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
--	scsi_queue_work(conn->session->host, &conn->xmitwork);
-+	memset(hdr, 0, sizeof(*hdr));
-+	hdr->opcode = ISCSI_OP_SCSI_TMFUNC | ISCSI_OP_IMMEDIATE;
-+	hdr->flags = ISCSI_TM_FUNC_ABORT_TASK & ISCSI_FLAG_TM_FUNC_MASK;
-+	hdr->flags |= ISCSI_FLAG_CMD_FINAL;
-+	memcpy(hdr->lun, ctask->hdr->lun, sizeof(hdr->lun));
-+	hdr->rtt = ctask->hdr->itt;
-+	hdr->refcmdsn = ctask->hdr->cmdsn;
- }
- 
- int iscsi_eh_abort(struct scsi_cmnd *sc)
- {
- 	struct Scsi_Host *host = sc->device->host;
- 	struct iscsi_session *session = iscsi_hostdata(host->hostdata);
--	struct iscsi_cmd_task *ctask;
- 	struct iscsi_conn *conn;
--	int rc;
-+	struct iscsi_cmd_task *ctask;
-+	struct iscsi_tm *hdr;
-+	int rc, age;
- 
- 	mutex_lock(&session->eh_mutex);
- 	spin_lock_bh(&session->lock);
-@@ -1199,19 +1419,23 @@ int iscsi_eh_abort(struct scsi_cmnd *sc)
- 		return SUCCESS;
- 	}
- 
--	ctask = (struct iscsi_cmd_task *)sc->SCp.ptr;
--	conn = ctask->conn;
+-/************************************************/
+-/*		Some defines that we like 				*/
+-/************************************************/
+-#define	CHAR		char
+-#define	UCHAR		unsigned char
+-#define	SHORT		short
+-#define	USHORT		unsigned short
+-#define	BOOL		unsigned short
+-#define	LONG		long
+-#define	ULONG		unsigned long
+-#define	VOID		void
 -
--	conn->eh_abort_cnt++;
--	debug_scsi("aborting [sc %p itt 0x%x]\n", sc, ctask->itt);
+-/************************************************/
+-/*		Timeout konstants		 				*/
+-/************************************************/
+-#define	TIMEOUT_READY				10		// 100 mSec
+-#define	TIMEOUT_DRQ					40		// 400 mSec
 -
- 	/*
- 	 * If we are not logged in or we have started a new session
- 	 * then let the host reset code handle this
- 	 */
--	if (session->state != ISCSI_STATE_LOGGED_IN ||
--	    sc->SCp.phase != session->age)
--		goto failed;
-+	if (!session->leadconn || session->state != ISCSI_STATE_LOGGED_IN ||
-+	    sc->SCp.phase != session->age) {
-+		spin_unlock_bh(&session->lock);
-+		mutex_unlock(&session->eh_mutex);
-+		return FAILED;
-+	}
-+
-+	conn = session->leadconn;
-+	conn->eh_abort_cnt++;
-+	age = session->age;
-+
-+	ctask = (struct iscsi_cmd_task *)sc->SCp.ptr;
-+	debug_scsi("aborting [sc %p itt 0x%x]\n", sc, ctask->itt);
- 
- 	/* ctask completed before time out */
- 	if (!ctask->sc) {
-@@ -1219,27 +1443,26 @@ int iscsi_eh_abort(struct scsi_cmnd *sc)
- 		goto success;
- 	}
- 
--	/* what should we do here ? */
--	if (conn->ctask == ctask) {
--		printk(KERN_INFO "iscsi: sc %p itt 0x%x partially sent. "
--		       "Failing abort\n", sc, ctask->itt);
--		goto failed;
--	}
+-/************************************************/
+-/*		Misc. macros			 				*/
+-/************************************************/
+-#define ANY2SCSI(up, p)					\
+-((UCHAR *)up)[0] = (((ULONG)(p)) >> 8);	\
+-((UCHAR *)up)[1] = ((ULONG)(p));
 -
- 	if (ctask->state == ISCSI_TASK_PENDING) {
- 		fail_command(conn, ctask, DID_ABORT << 16);
- 		goto success;
- 	}
- 
--	conn->tmabort_state = TMABORT_INITIAL;
--	rc = iscsi_exec_abort_task(sc, ctask);
--	if (rc || sc->SCp.phase != session->age ||
--	    session->state != ISCSI_STATE_LOGGED_IN)
-+	/* only have one tmf outstanding at a time */
-+	if (conn->tmf_state != TMF_INITIAL)
-+		goto failed;
-+	conn->tmf_state = TMF_QUEUED;
-+
-+	hdr = &conn->tmhdr;
-+	iscsi_prep_abort_task_pdu(ctask, hdr);
-+
-+	if (iscsi_exec_task_mgmt_fn(conn, hdr, age, session->abort_timeout)) {
-+		rc = FAILED;
- 		goto failed;
--	iscsi_ctask_mtask_cleanup(ctask);
-+	}
- 
--	switch (conn->tmabort_state) {
--	case TMABORT_SUCCESS:
-+	switch (conn->tmf_state) {
-+	case TMF_SUCCESS:
- 		spin_unlock_bh(&session->lock);
- 		iscsi_suspend_tx(conn);
- 		/*
-@@ -1248,22 +1471,26 @@ int iscsi_eh_abort(struct scsi_cmnd *sc)
- 		write_lock_bh(conn->recv_lock);
- 		spin_lock(&session->lock);
- 		fail_command(conn, ctask, DID_ABORT << 16);
-+		conn->tmf_state = TMF_INITIAL;
- 		spin_unlock(&session->lock);
- 		write_unlock_bh(conn->recv_lock);
- 		iscsi_start_tx(conn);
- 		goto success_unlocked;
--	case TMABORT_NOT_FOUND:
--		if (!ctask->sc) {
-+	case TMF_TIMEDOUT:
-+		spin_unlock_bh(&session->lock);
-+		iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
-+		goto failed_unlocked;
-+	case TMF_NOT_FOUND:
-+		if (!sc->SCp.ptr) {
-+			conn->tmf_state = TMF_INITIAL;
- 			/* ctask completed before tmf abort response */
- 			debug_scsi("sc completed while abort in progress\n");
- 			goto success;
- 		}
- 		/* fall through */
- 	default:
--		/* timedout or failed */
--		spin_unlock_bh(&session->lock);
--		iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
--		goto failed_unlocked;
-+		conn->tmf_state = TMF_INITIAL;
-+		goto failed;
- 	}
- 
- success:
-@@ -1276,65 +1503,152 @@ success_unlocked:
- failed:
- 	spin_unlock_bh(&session->lock);
- failed_unlocked:
--	debug_scsi("abort failed [sc %lx itt 0x%x]\n", (long)sc, ctask->itt);
-+	debug_scsi("abort failed [sc %p itt 0x%x]\n", sc,
-+		    ctask ? ctask->itt : 0);
- 	mutex_unlock(&session->eh_mutex);
- 	return FAILED;
- }
- EXPORT_SYMBOL_GPL(iscsi_eh_abort);
- 
-+static void iscsi_prep_lun_reset_pdu(struct scsi_cmnd *sc, struct iscsi_tm *hdr)
-+{
-+	memset(hdr, 0, sizeof(*hdr));
-+	hdr->opcode = ISCSI_OP_SCSI_TMFUNC | ISCSI_OP_IMMEDIATE;
-+	hdr->flags = ISCSI_TM_FUNC_LOGICAL_UNIT_RESET & ISCSI_FLAG_TM_FUNC_MASK;
-+	hdr->flags |= ISCSI_FLAG_CMD_FINAL;
-+	int_to_scsilun(sc->device->lun, (struct scsi_lun *)hdr->lun);
-+	hdr->rtt = RESERVED_ITT;
-+}
-+
-+int iscsi_eh_device_reset(struct scsi_cmnd *sc)
-+{
-+	struct Scsi_Host *host = sc->device->host;
-+	struct iscsi_session *session = iscsi_hostdata(host->hostdata);
-+	struct iscsi_conn *conn;
-+	struct iscsi_tm *hdr;
-+	int rc = FAILED;
-+
-+	debug_scsi("LU Reset [sc %p lun %u]\n", sc, sc->device->lun);
-+
-+	mutex_lock(&session->eh_mutex);
-+	spin_lock_bh(&session->lock);
-+	/*
-+	 * Just check if we are not logged in. We cannot check for
-+	 * the phase because the reset could come from a ioctl.
-+	 */
-+	if (!session->leadconn || session->state != ISCSI_STATE_LOGGED_IN)
-+		goto unlock;
-+	conn = session->leadconn;
-+
-+	/* only have one tmf outstanding at a time */
-+	if (conn->tmf_state != TMF_INITIAL)
-+		goto unlock;
-+	conn->tmf_state = TMF_QUEUED;
-+
-+	hdr = &conn->tmhdr;
-+	iscsi_prep_lun_reset_pdu(sc, hdr);
-+
-+	if (iscsi_exec_task_mgmt_fn(conn, hdr, session->age,
-+				    session->lu_reset_timeout)) {
-+		rc = FAILED;
-+		goto unlock;
-+	}
-+
-+	switch (conn->tmf_state) {
-+	case TMF_SUCCESS:
-+		break;
-+	case TMF_TIMEDOUT:
-+		spin_unlock_bh(&session->lock);
-+		iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
-+		goto done;
-+	default:
-+		conn->tmf_state = TMF_INITIAL;
-+		goto unlock;
-+	}
-+
-+	rc = SUCCESS;
-+	spin_unlock_bh(&session->lock);
-+
-+	iscsi_suspend_tx(conn);
-+	/* need to grab the recv lock then session lock */
-+	write_lock_bh(conn->recv_lock);
-+	spin_lock(&session->lock);
-+	fail_all_commands(conn, sc->device->lun);
-+	conn->tmf_state = TMF_INITIAL;
-+	spin_unlock(&session->lock);
-+	write_unlock_bh(conn->recv_lock);
-+
-+	iscsi_start_tx(conn);
-+	goto done;
-+
-+unlock:
-+	spin_unlock_bh(&session->lock);
-+done:
-+	debug_scsi("iscsi_eh_device_reset %s\n",
-+		  rc == SUCCESS ? "SUCCESS" : "FAILED");
-+	mutex_unlock(&session->eh_mutex);
-+	return rc;
-+}
-+EXPORT_SYMBOL_GPL(iscsi_eh_device_reset);
-+
-+/*
-+ * Pre-allocate a pool of @max items of @item_size. By default, the pool
-+ * should be accessed via kfifo_{get,put} on q->queue.
-+ * Optionally, the caller can obtain the array of object pointers
-+ * by passing in a non-NULL @items pointer
-+ */
- int
--iscsi_pool_init(struct iscsi_queue *q, int max, void ***items, int item_size)
-+iscsi_pool_init(struct iscsi_pool *q, int max, void ***items, int item_size)
- {
--	int i;
-+	int i, num_arrays = 1;
- 
--	*items = kmalloc(max * sizeof(void*), GFP_KERNEL);
--	if (*items == NULL)
--		return -ENOMEM;
-+	memset(q, 0, sizeof(*q));
- 
- 	q->max = max;
--	q->pool = kmalloc(max * sizeof(void*), GFP_KERNEL);
--	if (q->pool == NULL) {
--		kfree(*items);
--		return -ENOMEM;
--	}
-+
-+	/* If the user passed an items pointer, he wants a copy of
-+	 * the array. */
-+	if (items)
-+		num_arrays++;
-+	q->pool = kzalloc(num_arrays * max * sizeof(void*), GFP_KERNEL);
-+	if (q->pool == NULL)
-+		goto enomem;
- 
- 	q->queue = kfifo_init((void*)q->pool, max * sizeof(void*),
- 			      GFP_KERNEL, NULL);
--	if (q->queue == ERR_PTR(-ENOMEM)) {
--		kfree(q->pool);
--		kfree(*items);
--		return -ENOMEM;
--	}
-+	if (q->queue == ERR_PTR(-ENOMEM))
-+		goto enomem;
- 
- 	for (i = 0; i < max; i++) {
--		q->pool[i] = kmalloc(item_size, GFP_KERNEL);
-+		q->pool[i] = kzalloc(item_size, GFP_KERNEL);
- 		if (q->pool[i] == NULL) {
--			int j;
+-#define SCSI2LONG(up)					\
+-( (((long)*(((UCHAR *)up))) << 16)		\
+-+ (((long)(((UCHAR *)up)[1])) << 8)		\
+-+ ((long)(((UCHAR *)up)[2])) )
 -
--			for (j = 0; j < i; j++)
--				kfree(q->pool[j]);
+-#define XANY2SCSI(up, p)				\
+-((UCHAR *)up)[0] = ((long)(p)) >> 24;	\
+-((UCHAR *)up)[1] = ((long)(p)) >> 16;	\
+-((UCHAR *)up)[2] = ((long)(p)) >> 8;	\
+-((UCHAR *)up)[3] = ((long)(p));
 -
--			kfifo_free(q->queue);
--			kfree(q->pool);
--			kfree(*items);
--			return -ENOMEM;
-+			q->max = i;
-+			goto enomem;
- 		}
--		memset(q->pool[i], 0, item_size);
--		(*items)[i] = q->pool[i];
- 		__kfifo_put(q->queue, (void*)&q->pool[i], sizeof(void*));
- 	}
-+
-+	if (items) {
-+		*items = q->pool + max;
-+		memcpy(*items, q->pool, max * sizeof(void *));
-+	}
-+
- 	return 0;
-+
-+enomem:
-+	iscsi_pool_free(q);
-+	return -ENOMEM;
- }
- EXPORT_SYMBOL_GPL(iscsi_pool_init);
- 
--void iscsi_pool_free(struct iscsi_queue *q, void **items)
-+void iscsi_pool_free(struct iscsi_pool *q)
- {
- 	int i;
- 
- 	for (i = 0; i < q->max; i++)
--		kfree(items[i]);
--	kfree(q->pool);
--	kfree(items);
-+		kfree(q->pool[i]);
-+	if (q->pool)
-+		kfree(q->pool);
- }
- EXPORT_SYMBOL_GPL(iscsi_pool_free);
- 
-@@ -1387,7 +1701,7 @@ iscsi_session_setup(struct iscsi_transport *iscsit,
- 		qdepth = ISCSI_DEF_CMD_PER_LUN;
- 	}
- 
--	if (cmds_max < 2 || (cmds_max & (cmds_max - 1)) ||
-+	if (!is_power_of_2(cmds_max) ||
- 	    cmds_max >= ISCSI_MGMT_ITT_OFFSET) {
- 		if (cmds_max != 0)
- 			printk(KERN_ERR "iscsi: invalid can_queue of %d. "
-@@ -1411,12 +1725,16 @@ iscsi_session_setup(struct iscsi_transport *iscsit,
- 	shost->max_cmd_len = iscsit->max_cmd_len;
- 	shost->transportt = scsit;
- 	shost->transportt->create_work_queue = 1;
-+	shost->transportt->eh_timed_out = iscsi_eh_cmd_timed_out;
- 	*hostno = shost->host_no;
- 
- 	session = iscsi_hostdata(shost->hostdata);
- 	memset(session, 0, sizeof(struct iscsi_session));
- 	session->host = shost;
- 	session->state = ISCSI_STATE_FREE;
-+	session->fast_abort = 1;
-+	session->lu_reset_timeout = 15;
-+	session->abort_timeout = 10;
- 	session->mgmtpool_max = ISCSI_MGMT_CMDS_MAX;
- 	session->cmds_max = cmds_max;
- 	session->queued_cmdsn = session->cmdsn = initial_cmdsn;
-@@ -1479,9 +1797,9 @@ module_put:
- cls_session_fail:
- 	scsi_remove_host(shost);
- add_host_fail:
--	iscsi_pool_free(&session->mgmtpool, (void**)session->mgmt_cmds);
-+	iscsi_pool_free(&session->mgmtpool);
- mgmtpool_alloc_fail:
--	iscsi_pool_free(&session->cmdpool, (void**)session->cmds);
-+	iscsi_pool_free(&session->cmdpool);
- cmdpool_alloc_fail:
- 	scsi_host_put(shost);
- 	return NULL;
-@@ -1501,11 +1819,11 @@ void iscsi_session_teardown(struct iscsi_cls_session *cls_session)
- 	struct iscsi_session *session = iscsi_hostdata(shost->hostdata);
- 	struct module *owner = cls_session->transport->owner;
- 
--	iscsi_unblock_session(cls_session);
-+	iscsi_remove_session(cls_session);
- 	scsi_remove_host(shost);
- 
--	iscsi_pool_free(&session->mgmtpool, (void**)session->mgmt_cmds);
--	iscsi_pool_free(&session->cmdpool, (void**)session->cmds);
-+	iscsi_pool_free(&session->mgmtpool);
-+	iscsi_pool_free(&session->cmdpool);
- 
- 	kfree(session->password);
- 	kfree(session->password_in);
-@@ -1516,7 +1834,7 @@ void iscsi_session_teardown(struct iscsi_cls_session *cls_session)
- 	kfree(session->hwaddress);
- 	kfree(session->initiatorname);
- 
--	iscsi_destroy_session(cls_session);
-+	iscsi_free_session(cls_session);
- 	scsi_host_put(shost);
- 	module_put(owner);
- }
-@@ -1546,17 +1864,17 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, uint32_t conn_idx)
- 	conn->c_stage = ISCSI_CONN_INITIAL_STAGE;
- 	conn->id = conn_idx;
- 	conn->exp_statsn = 0;
--	conn->tmabort_state = TMABORT_INITIAL;
-+	conn->tmf_state = TMF_INITIAL;
-+
-+	init_timer(&conn->transport_timer);
-+	conn->transport_timer.data = (unsigned long)conn;
-+	conn->transport_timer.function = iscsi_check_transport_timeouts;
-+
- 	INIT_LIST_HEAD(&conn->run_list);
- 	INIT_LIST_HEAD(&conn->mgmt_run_list);
-+	INIT_LIST_HEAD(&conn->mgmtqueue);
- 	INIT_LIST_HEAD(&conn->xmitqueue);
+-#define XSCSI2LONG(up)					\
+-( (((long)(((UCHAR *)up)[0])) << 24)	\
+-+ (((long)(((UCHAR *)up)[1])) << 16)	\
+-+ (((long)(((UCHAR *)up)[2])) <<  8)	\
+-+ ((long)(((UCHAR *)up)[3])) )
 -
--	/* initialize general immediate & non-immediate PDU commands queue */
--	conn->mgmtqueue = kfifo_alloc(session->mgmtpool_max * sizeof(void*),
--			                GFP_KERNEL, NULL);
--	if (conn->mgmtqueue == ERR_PTR(-ENOMEM))
--		goto mgmtqueue_alloc_fail;
+-/************************************************/
+-/*		SCSI CDB operation codes 				*/
+-/************************************************/
+-#define SCSIOP_TEST_UNIT_READY		0x00
+-#define SCSIOP_REZERO_UNIT			0x01
+-#define SCSIOP_REWIND				0x01
+-#define SCSIOP_REQUEST_BLOCK_ADDR	0x02
+-#define SCSIOP_REQUEST_SENSE		0x03
+-#define SCSIOP_FORMAT_UNIT			0x04
+-#define SCSIOP_READ_BLOCK_LIMITS	0x05
+-#define SCSIOP_REASSIGN_BLOCKS		0x07
+-#define SCSIOP_READ6				0x08
+-#define SCSIOP_RECEIVE				0x08
+-#define SCSIOP_WRITE6				0x0A
+-#define SCSIOP_PRINT				0x0A
+-#define SCSIOP_SEND					0x0A
+-#define SCSIOP_SEEK6				0x0B
+-#define SCSIOP_TRACK_SELECT			0x0B
+-#define SCSIOP_SLEW_PRINT			0x0B
+-#define SCSIOP_SEEK_BLOCK			0x0C
+-#define SCSIOP_PARTITION			0x0D
+-#define SCSIOP_READ_REVERSE			0x0F
+-#define SCSIOP_WRITE_FILEMARKS		0x10
+-#define SCSIOP_FLUSH_BUFFER			0x10
+-#define SCSIOP_SPACE				0x11
+-#define SCSIOP_INQUIRY				0x12
+-#define SCSIOP_VERIFY6				0x13
+-#define SCSIOP_RECOVER_BUF_DATA		0x14
+-#define SCSIOP_MODE_SELECT			0x15
+-#define SCSIOP_RESERVE_UNIT			0x16
+-#define SCSIOP_RELEASE_UNIT			0x17
+-#define SCSIOP_COPY					0x18
+-#define SCSIOP_ERASE				0x19
+-#define SCSIOP_MODE_SENSE			0x1A
+-#define SCSIOP_START_STOP_UNIT		0x1B
+-#define SCSIOP_STOP_PRINT			0x1B
+-#define SCSIOP_LOAD_UNLOAD			0x1B
+-#define SCSIOP_RECEIVE_DIAGNOSTIC	0x1C
+-#define SCSIOP_SEND_DIAGNOSTIC		0x1D
+-#define SCSIOP_MEDIUM_REMOVAL		0x1E
+-#define SCSIOP_READ_CAPACITY		0x25
+-#define SCSIOP_READ					0x28
+-#define SCSIOP_WRITE				0x2A
+-#define SCSIOP_SEEK					0x2B
+-#define SCSIOP_LOCATE				0x2B
+-#define SCSIOP_WRITE_VERIFY			0x2E
+-#define SCSIOP_VERIFY				0x2F
+-#define SCSIOP_SEARCH_DATA_HIGH		0x30
+-#define SCSIOP_SEARCH_DATA_EQUAL	0x31
+-#define SCSIOP_SEARCH_DATA_LOW		0x32
+-#define SCSIOP_SET_LIMITS			0x33
+-#define SCSIOP_READ_POSITION		0x34
+-#define SCSIOP_SYNCHRONIZE_CACHE	0x35
+-#define SCSIOP_COMPARE				0x39
+-#define SCSIOP_COPY_COMPARE			0x3A
+-#define SCSIOP_WRITE_DATA_BUFF		0x3B
+-#define SCSIOP_READ_DATA_BUFF		0x3C
+-#define SCSIOP_CHANGE_DEFINITION	0x40
+-#define SCSIOP_READ_SUB_CHANNEL		0x42
+-#define SCSIOP_READ_TOC				0x43
+-#define SCSIOP_READ_HEADER			0x44
+-#define SCSIOP_PLAY_AUDIO			0x45
+-#define SCSIOP_PLAY_AUDIO_MSF		0x47
+-#define SCSIOP_PLAY_TRACK_INDEX		0x48
+-#define SCSIOP_PLAY_TRACK_RELATIVE	0x49
+-#define SCSIOP_PAUSE_RESUME			0x4B
+-#define SCSIOP_LOG_SELECT			0x4C
+-#define SCSIOP_LOG_SENSE			0x4D
+-#define SCSIOP_MODE_SELECT10		0x55
+-#define SCSIOP_MODE_SENSE10			0x5A
+-#define SCSIOP_LOAD_UNLOAD_SLOT		0xA6
+-#define SCSIOP_MECHANISM_STATUS		0xBD
+-#define SCSIOP_READ_CD				0xBE
+-
+-// IDE command definitions
+-#define IDE_COMMAND_ATAPI_RESET		0x08
+-#define IDE_COMMAND_READ			0x20
+-#define IDE_COMMAND_WRITE			0x30
+-#define IDE_COMMAND_RECALIBRATE		0x10
+-#define IDE_COMMAND_SEEK			0x70
+-#define IDE_COMMAND_SET_PARAMETERS	0x91
+-#define IDE_COMMAND_VERIFY			0x40
+-#define IDE_COMMAND_ATAPI_PACKET	0xA0
+-#define IDE_COMMAND_ATAPI_IDENTIFY	0xA1
+-#define	IDE_CMD_READ_MULTIPLE		0xC4
+-#define	IDE_CMD_WRITE_MULTIPLE		0xC5
+-#define	IDE_CMD_SET_MULTIPLE		0xC6
+-#define IDE_COMMAND_WRITE_DMA		0xCA
+-#define IDE_COMMAND_READ_DMA		0xC8
+-#define IDE_COMMAND_IDENTIFY		0xEC
 -
-+	INIT_LIST_HEAD(&conn->requeue);
- 	INIT_WORK(&conn->xmitwork, iscsi_xmitworker);
- 
- 	/* allocate login_mtask used for the login/text sequences */
-@@ -1574,7 +1892,7 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, uint32_t conn_idx)
- 		goto login_mtask_data_alloc_fail;
- 	conn->login_mtask->data = conn->data = data;
- 
--	init_timer(&conn->tmabort_timer);
-+	init_timer(&conn->tmf_timer);
- 	init_waitqueue_head(&conn->ehwait);
- 
- 	return cls_conn;
-@@ -1583,8 +1901,6 @@ login_mtask_data_alloc_fail:
- 	__kfifo_put(session->mgmtpool.queue, (void*)&conn->login_mtask,
- 		    sizeof(void*));
- login_mtask_alloc_fail:
--	kfifo_free(conn->mgmtqueue);
--mgmtqueue_alloc_fail:
- 	iscsi_destroy_conn(cls_conn);
- 	return NULL;
- }
-@@ -1603,8 +1919,9 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn)
- 	struct iscsi_session *session = conn->session;
- 	unsigned long flags;
- 
-+	del_timer_sync(&conn->transport_timer);
-+
- 	spin_lock_bh(&session->lock);
--	set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
- 	conn->c_stage = ISCSI_CONN_CLEANUP_WAIT;
- 	if (session->leadconn == conn) {
- 		/*
-@@ -1637,7 +1954,7 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn)
- 	}
- 
- 	/* flush queued up work because we free the connection below */
--	scsi_flush_work(session->host);
-+	iscsi_suspend_tx(conn);
- 
- 	spin_lock_bh(&session->lock);
- 	kfree(conn->data);
-@@ -1648,8 +1965,6 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn)
- 		session->leadconn = NULL;
- 	spin_unlock_bh(&session->lock);
- 
--	kfifo_free(conn->mgmtqueue);
+-// IDE status definitions
+-#define IDE_STATUS_ERROR			0x01
+-#define IDE_STATUS_INDEX			0x02
+-#define IDE_STATUS_CORRECTED_ERROR	0x04
+-#define IDE_STATUS_DRQ				0x08
+-#define IDE_STATUS_DSC				0x10
+-#define	IDE_STATUS_WRITE_FAULT		0x20
+-#define IDE_STATUS_DRDY				0x40
+-#define IDE_STATUS_BUSY				0x80
 -
- 	iscsi_destroy_conn(cls_conn);
- }
- EXPORT_SYMBOL_GPL(iscsi_conn_teardown);
-@@ -1672,11 +1987,29 @@ int iscsi_conn_start(struct iscsi_cls_conn *cls_conn)
- 		return -EINVAL;
- 	}
- 
-+	if (conn->ping_timeout && !conn->recv_timeout) {
-+		printk(KERN_ERR "iscsi: invalid recv timeout of zero "
-+		      "Using 5 seconds\n.");
-+		conn->recv_timeout = 5;
-+	}
-+
-+	if (conn->recv_timeout && !conn->ping_timeout) {
-+		printk(KERN_ERR "iscsi: invalid ping timeout of zero "
-+		      "Using 5 seconds.\n");
-+		conn->ping_timeout = 5;
-+	}
-+
- 	spin_lock_bh(&session->lock);
- 	conn->c_stage = ISCSI_CONN_STARTED;
- 	session->state = ISCSI_STATE_LOGGED_IN;
- 	session->queued_cmdsn = session->cmdsn;
- 
-+	conn->last_recv = jiffies;
-+	conn->last_ping = jiffies;
-+	if (conn->recv_timeout && conn->ping_timeout)
-+		mod_timer(&conn->transport_timer,
-+			  jiffies + (conn->recv_timeout * HZ));
-+
- 	switch(conn->stop_stage) {
- 	case STOP_CONN_RECOVER:
- 		/*
-@@ -1684,7 +2017,7 @@ int iscsi_conn_start(struct iscsi_cls_conn *cls_conn)
- 		 * commands after successful recovery
- 		 */
- 		conn->stop_stage = 0;
--		conn->tmabort_state = TMABORT_INITIAL;
-+		conn->tmf_state = TMF_INITIAL;
- 		session->age++;
- 		spin_unlock_bh(&session->lock);
- 
-@@ -1709,55 +2042,27 @@ flush_control_queues(struct iscsi_session *session, struct iscsi_conn *conn)
- 	struct iscsi_mgmt_task *mtask, *tmp;
- 
- 	/* handle pending */
--	while (__kfifo_get(conn->mgmtqueue, (void*)&mtask, sizeof(void*))) {
--		if (mtask == conn->login_mtask)
--			continue;
-+	list_for_each_entry_safe(mtask, tmp, &conn->mgmtqueue, running) {
- 		debug_scsi("flushing pending mgmt task itt 0x%x\n", mtask->itt);
--		__kfifo_put(session->mgmtpool.queue, (void*)&mtask,
--			    sizeof(void*));
-+		iscsi_free_mgmt_task(conn, mtask);
- 	}
- 
- 	/* handle running */
- 	list_for_each_entry_safe(mtask, tmp, &conn->mgmt_run_list, running) {
- 		debug_scsi("flushing running mgmt task itt 0x%x\n", mtask->itt);
--		list_del(&mtask->running);
+-// IDE error definitions
+-#define	IDE_ERROR_AMNF				0x01
+-#define	IDE_ERROR_TKONF				0x02
+-#define	IDE_ERROR_ABRT				0x04
+-#define	IDE_ERROR_MCR				0x08
+-#define	IDE_ERROR_IDFN				0x10
+-#define	IDE_ERROR_MC				0x20
+-#define	IDE_ERROR_UNC				0x40
+-#define	IDE_ERROR_BBK				0x80
 -
--		if (mtask == conn->login_mtask)
--			continue;
--		__kfifo_put(session->mgmtpool.queue, (void*)&mtask,
--			   sizeof(void*));
-+		iscsi_free_mgmt_task(conn, mtask);
- 	}
- 
- 	conn->mtask = NULL;
- }
- 
--/* Fail commands. Mutex and session lock held and recv side suspended */
--static void fail_all_commands(struct iscsi_conn *conn)
--{
--	struct iscsi_cmd_task *ctask, *tmp;
+-//	IDE interface structure
+-typedef struct _IDE_STRUCT
+-	{
+-	union
+-		{
+-		UCHAR	ide[9];
+-		struct
+-			{
+-			USHORT	data;
+-			UCHAR	sectors;
+-			UCHAR	lba[4];
+-			UCHAR	cmd;
+-			UCHAR	spigot;
+-			}	ides;
+-		} ide;
+-	}	IDE_STRUCT;
 -
--	/* flush pending */
--	list_for_each_entry_safe(ctask, tmp, &conn->xmitqueue, running) {
--		debug_scsi("failing pending sc %p itt 0x%x\n", ctask->sc,
--			   ctask->itt);
--		fail_command(conn, ctask, DID_BUS_BUSY << 16);
--	}
+-// SCSI read capacity structure
+-typedef	struct _READ_CAPACITY_DATA
+-	{
+-	ULONG blks;				/* total blocks (converted to little endian) */
+-	ULONG blksiz;			/* size of each (converted to little endian) */
+-	}	READ_CAPACITY_DATA, *PREAD_CAPACITY_DATA;
 -
--	/* fail all other running */
--	list_for_each_entry_safe(ctask, tmp, &conn->run_list, running) {
--		debug_scsi("failing in progress sc %p itt 0x%x\n",
--			   ctask->sc, ctask->itt);
--		fail_command(conn, ctask, DID_BUS_BUSY << 16);
--	}
+-// SCSI inquiry data
+-#ifndef HOSTS_C
 -
--	conn->ctask = NULL;
--}
+-typedef struct _INQUIRYDATA
+-	{
+-	UCHAR DeviceType			:5;
+-	UCHAR DeviceTypeQualifier	:3;
+-	UCHAR DeviceTypeModifier	:7;
+-	UCHAR RemovableMedia		:1;
+-    UCHAR Versions;
+-    UCHAR ResponseDataFormat;
+-    UCHAR AdditionalLength;
+-    UCHAR Reserved[2];
+-	UCHAR SoftReset				:1;
+-	UCHAR CommandQueue			:1;
+-	UCHAR Reserved2				:1;
+-	UCHAR LinkedCommands		:1;
+-	UCHAR Synchronous			:1;
+-	UCHAR Wide16Bit				:1;
+-	UCHAR Wide32Bit				:1;
+-	UCHAR RelativeAddressing	:1;
+-    UCHAR VendorId[8];
+-    UCHAR ProductId[16];
+-    UCHAR ProductRevisionLevel[4];
+-    UCHAR VendorSpecific[20];
+-    UCHAR Reserved3[40];
+-	}	INQUIRYDATA, *PINQUIRYDATA;
+-#endif
 -
- static void iscsi_start_session_recovery(struct iscsi_session *session,
- 					 struct iscsi_conn *conn, int flag)
- {
- 	int old_stop_stage;
- 
-+	del_timer_sync(&conn->transport_timer);
-+
- 	mutex_lock(&session->eh_mutex);
- 	spin_lock_bh(&session->lock);
- 	if (conn->stop_stage == STOP_CONN_TERM) {
-@@ -1818,7 +2123,7 @@ static void iscsi_start_session_recovery(struct iscsi_session *session,
- 	 * flush queues.
- 	 */
- 	spin_lock_bh(&session->lock);
--	fail_all_commands(conn);
-+	fail_all_commands(conn, -1);
- 	flush_control_queues(session, conn);
- 	spin_unlock_bh(&session->lock);
- 	mutex_unlock(&session->eh_mutex);
-@@ -1869,6 +2174,21 @@ int iscsi_set_param(struct iscsi_cls_conn *cls_conn,
- 	uint32_t value;
- 
- 	switch(param) {
-+	case ISCSI_PARAM_FAST_ABORT:
-+		sscanf(buf, "%d", &session->fast_abort);
-+		break;
-+	case ISCSI_PARAM_ABORT_TMO:
-+		sscanf(buf, "%d", &session->abort_timeout);
-+		break;
-+	case ISCSI_PARAM_LU_RESET_TMO:
-+		sscanf(buf, "%d", &session->lu_reset_timeout);
-+		break;
-+	case ISCSI_PARAM_PING_TMO:
-+		sscanf(buf, "%d", &conn->ping_timeout);
-+		break;
-+	case ISCSI_PARAM_RECV_TMO:
-+		sscanf(buf, "%d", &conn->recv_timeout);
-+		break;
- 	case ISCSI_PARAM_MAX_RECV_DLENGTH:
- 		sscanf(buf, "%d", &conn->max_recv_dlength);
- 		break;
-@@ -1983,6 +2303,15 @@ int iscsi_session_get_param(struct iscsi_cls_session *cls_session,
- 	int len;
- 
- 	switch(param) {
-+	case ISCSI_PARAM_FAST_ABORT:
-+		len = sprintf(buf, "%d\n", session->fast_abort);
-+		break;
-+	case ISCSI_PARAM_ABORT_TMO:
-+		len = sprintf(buf, "%d\n", session->abort_timeout);
-+		break;
-+	case ISCSI_PARAM_LU_RESET_TMO:
-+		len = sprintf(buf, "%d\n", session->lu_reset_timeout);
-+		break;
- 	case ISCSI_PARAM_INITIAL_R2T_EN:
- 		len = sprintf(buf, "%d\n", session->initial_r2t_en);
- 		break;
-@@ -2040,6 +2369,12 @@ int iscsi_conn_get_param(struct iscsi_cls_conn *cls_conn,
- 	int len;
- 
- 	switch(param) {
-+	case ISCSI_PARAM_PING_TMO:
-+		len = sprintf(buf, "%u\n", conn->ping_timeout);
-+		break;
-+	case ISCSI_PARAM_RECV_TMO:
-+		len = sprintf(buf, "%u\n", conn->recv_timeout);
-+		break;
- 	case ISCSI_PARAM_MAX_RECV_DLENGTH:
- 		len = sprintf(buf, "%u\n", conn->max_recv_dlength);
- 		break;
-diff --git a/drivers/scsi/libsas/Kconfig b/drivers/scsi/libsas/Kconfig
-index c01a40d..18f33cd 100644
---- a/drivers/scsi/libsas/Kconfig
-+++ b/drivers/scsi/libsas/Kconfig
-@@ -38,6 +38,15 @@ config SCSI_SAS_ATA
- 		Builds in ATA support into libsas.  Will necessitate
- 		the loading of libata along with libsas.
- 
-+config SCSI_SAS_HOST_SMP
-+	bool "Support for SMP interpretation for SAS hosts"
-+	default y
-+	depends on SCSI_SAS_LIBSAS
-+	help
-+		Allows sas hosts to receive SMP frames.  Selecting this
-+		option builds an SMP interpreter into libsas.  Say
-+		N here if you want to save the few kb this consumes.
-+
- config SCSI_SAS_LIBSAS_DEBUG
- 	bool "Compile the SAS Domain Transport Attributes in debug mode"
- 	default y
-diff --git a/drivers/scsi/libsas/Makefile b/drivers/scsi/libsas/Makefile
-index fd387b9..1ad1323 100644
---- a/drivers/scsi/libsas/Makefile
-+++ b/drivers/scsi/libsas/Makefile
-@@ -33,5 +33,7 @@ libsas-y +=  sas_init.o     \
- 		sas_dump.o     \
- 		sas_discover.o \
- 		sas_expander.o \
--		sas_scsi_host.o
-+		sas_scsi_host.o \
-+		sas_task.o
- libsas-$(CONFIG_SCSI_SAS_ATA) +=	sas_ata.o
-+libsas-$(CONFIG_SCSI_SAS_HOST_SMP) +=	sas_host_smp.o
-\ No newline at end of file
-diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c
-index 0829b55..0996f86 100644
---- a/drivers/scsi/libsas/sas_ata.c
-+++ b/drivers/scsi/libsas/sas_ata.c
-@@ -158,8 +158,8 @@ static unsigned int sas_ata_qc_issue(struct ata_queued_cmd *qc)
- 	struct Scsi_Host *host = sas_ha->core.shost;
- 	struct sas_internal *i = to_sas_internal(host->transportt);
- 	struct scatterlist *sg;
--	unsigned int num = 0;
- 	unsigned int xfer = 0;
-+	unsigned int si;
- 
- 	task = sas_alloc_task(GFP_ATOMIC);
- 	if (!task)
-@@ -176,22 +176,20 @@ static unsigned int sas_ata_qc_issue(struct ata_queued_cmd *qc)
- 
- 	ata_tf_to_fis(&qc->tf, 1, 0, (u8*)&task->ata_task.fis);
- 	task->uldd_task = qc;
--	if (is_atapi_taskfile(&qc->tf)) {
-+	if (ata_is_atapi(qc->tf.protocol)) {
- 		memcpy(task->ata_task.atapi_packet, qc->cdb, qc->dev->cdb_len);
- 		task->total_xfer_len = qc->nbytes + qc->pad_len;
- 		task->num_scatter = qc->pad_len ? qc->n_elem + 1 : qc->n_elem;
- 	} else {
--		ata_for_each_sg(sg, qc) {
--			num++;
-+		for_each_sg(qc->sg, sg, qc->n_elem, si)
- 			xfer += sg->length;
--		}
- 
- 		task->total_xfer_len = xfer;
--		task->num_scatter = num;
-+		task->num_scatter = si;
- 	}
- 
- 	task->data_dir = qc->dma_dir;
--	task->scatter = qc->__sg;
-+	task->scatter = qc->sg;
- 	task->ata_task.retry_count = 1;
- 	task->task_state_flags = SAS_TASK_STATE_PENDING;
- 	qc->lldd_task = task;
-@@ -200,7 +198,7 @@ static unsigned int sas_ata_qc_issue(struct ata_queued_cmd *qc)
- 	case ATA_PROT_NCQ:
- 		task->ata_task.use_ncq = 1;
- 		/* fall through */
--	case ATA_PROT_ATAPI_DMA:
-+	case ATAPI_PROT_DMA:
- 	case ATA_PROT_DMA:
- 		task->ata_task.dma_xfer = 1;
- 		break;
-@@ -500,7 +498,7 @@ static int sas_execute_task(struct sas_task *task, void *buffer, int size,
- 			goto ex_err;
- 		}
- 		wait_for_completion(&task->completion);
--		res = -ETASK;
-+		res = -ECOMM;
- 		if (task->task_state_flags & SAS_TASK_STATE_ABORTED) {
- 			int res2;
- 			SAS_DPRINTK("task aborted, flags:0x%x\n",
-diff --git a/drivers/scsi/libsas/sas_discover.c b/drivers/scsi/libsas/sas_discover.c
-index 5f3a0d7..31b9af2 100644
---- a/drivers/scsi/libsas/sas_discover.c
-+++ b/drivers/scsi/libsas/sas_discover.c
-@@ -98,7 +98,7 @@ static int sas_get_port_device(struct asd_sas_port *port)
- 			dev->dev_type = SATA_PM;
- 		else
- 			dev->dev_type = SATA_DEV;
--		dev->tproto = SATA_PROTO;
-+		dev->tproto = SAS_PROTOCOL_SATA;
- 	} else {
- 		struct sas_identify_frame *id =
- 			(struct sas_identify_frame *) dev->frame_rcvd;
-diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c
-index 8727436..aefd865 100644
---- a/drivers/scsi/libsas/sas_expander.c
-+++ b/drivers/scsi/libsas/sas_expander.c
-@@ -96,7 +96,7 @@ static int smp_execute_task(struct domain_device *dev, void *req, int req_size,
- 		}
- 
- 		wait_for_completion(&task->completion);
--		res = -ETASK;
-+		res = -ECOMM;
- 		if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) {
- 			SAS_DPRINTK("smp task timed out or aborted\n");
- 			i->dft->lldd_abort_task(task);
-@@ -109,6 +109,16 @@ static int smp_execute_task(struct domain_device *dev, void *req, int req_size,
- 		    task->task_status.stat == SAM_GOOD) {
- 			res = 0;
- 			break;
-+		} if (task->task_status.resp == SAS_TASK_COMPLETE &&
-+		      task->task_status.stat == SAS_DATA_UNDERRUN) {
-+			/* no error, but return the number of bytes of
-+			 * underrun */
-+			res = task->task_status.residual;
-+			break;
-+		} if (task->task_status.resp == SAS_TASK_COMPLETE &&
-+		      task->task_status.stat == SAS_DATA_OVERRUN) {
-+			res = -EMSGSIZE;
-+			break;
- 		} else {
- 			SAS_DPRINTK("%s: task to dev %016llx response: 0x%x "
- 				    "status 0x%x\n", __FUNCTION__,
-@@ -656,9 +666,9 @@ static struct domain_device *sas_ex_discover_end_dev(
- 	sas_ex_get_linkrate(parent, child, phy);
- 
- #ifdef CONFIG_SCSI_SAS_ATA
--	if ((phy->attached_tproto & SAS_PROTO_STP) || phy->attached_sata_dev) {
-+	if ((phy->attached_tproto & SAS_PROTOCOL_STP) || phy->attached_sata_dev) {
- 		child->dev_type = SATA_DEV;
--		if (phy->attached_tproto & SAS_PROTO_STP)
-+		if (phy->attached_tproto & SAS_PROTOCOL_STP)
- 			child->tproto = phy->attached_tproto;
- 		if (phy->attached_sata_dev)
- 			child->tproto |= SATA_DEV;
-@@ -695,7 +705,7 @@ static struct domain_device *sas_ex_discover_end_dev(
- 		}
- 	} else
- #endif
--	  if (phy->attached_tproto & SAS_PROTO_SSP) {
-+	  if (phy->attached_tproto & SAS_PROTOCOL_SSP) {
- 		child->dev_type = SAS_END_DEV;
- 		rphy = sas_end_device_alloc(phy->port);
- 		/* FIXME: error handling */
-@@ -1896,11 +1906,9 @@ int sas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
- 	}
- 
- 	/* no rphy means no smp target support (ie aic94xx host) */
--	if (!rphy) {
--		printk("%s: can we send a smp request to a host?\n",
--		       __FUNCTION__);
--		return -EINVAL;
--	}
-+	if (!rphy)
-+		return sas_smp_host_handler(shost, req, rsp);
-+
- 	type = rphy->identify.device_type;
- 
- 	if (type != SAS_EDGE_EXPANDER_DEVICE &&
-@@ -1926,6 +1934,15 @@ int sas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
- 
- 	ret = smp_execute_task(dev, bio_data(req->bio), req->data_len,
- 			       bio_data(rsp->bio), rsp->data_len);
-+	if (ret > 0) {
-+		/* positive number is the untransferred residual */
-+		rsp->data_len = ret;
-+		req->data_len = 0;
-+		ret = 0;
-+	} else if (ret == 0) {
-+		rsp->data_len = 0;
-+		req->data_len = 0;
-+	}
- 
- 	return ret;
- }
-diff --git a/drivers/scsi/libsas/sas_host_smp.c b/drivers/scsi/libsas/sas_host_smp.c
-new file mode 100644
-index 0000000..16f9312
---- /dev/null
-+++ b/drivers/scsi/libsas/sas_host_smp.c
-@@ -0,0 +1,274 @@
-+/*
-+ * Serial Attached SCSI (SAS) Expander discovery and configuration
-+ *
-+ * Copyright (C) 2007 James E.J. Bottomley
-+ *		<James.Bottomley at HansenPartnership.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; version 2 only.
-+ */
-+#include <linux/scatterlist.h>
-+#include <linux/blkdev.h>
-+
-+#include "sas_internal.h"
-+
-+#include <scsi/scsi_transport.h>
-+#include <scsi/scsi_transport_sas.h>
-+#include "../scsi_sas_internal.h"
-+
-+static void sas_host_smp_discover(struct sas_ha_struct *sas_ha, u8 *resp_data,
-+				  u8 phy_id)
-+{
-+	struct sas_phy *phy;
-+	struct sas_rphy *rphy;
-+
-+	if (phy_id >= sas_ha->num_phys) {
-+		resp_data[2] = SMP_RESP_NO_PHY;
-+		return;
-+	}
-+	resp_data[2] = SMP_RESP_FUNC_ACC;
-+
-+	phy = sas_ha->sas_phy[phy_id]->phy;
-+	resp_data[9] = phy_id;
-+	resp_data[13] = phy->negotiated_linkrate;
-+	memcpy(resp_data + 16, sas_ha->sas_addr, SAS_ADDR_SIZE);
-+	memcpy(resp_data + 24, sas_ha->sas_phy[phy_id]->attached_sas_addr,
-+	       SAS_ADDR_SIZE);
-+	resp_data[40] = (phy->minimum_linkrate << 4) |
-+		phy->minimum_linkrate_hw;
-+	resp_data[41] = (phy->maximum_linkrate << 4) |
-+		phy->maximum_linkrate_hw;
-+
-+	if (!sas_ha->sas_phy[phy_id]->port ||
-+	    !sas_ha->sas_phy[phy_id]->port->port_dev)
-+		return;
-+
-+	rphy = sas_ha->sas_phy[phy_id]->port->port_dev->rphy;
-+	resp_data[12] = rphy->identify.device_type << 4;
-+	resp_data[14] = rphy->identify.initiator_port_protocols;
-+	resp_data[15] = rphy->identify.target_port_protocols;
-+}
-+
-+static void sas_report_phy_sata(struct sas_ha_struct *sas_ha, u8 *resp_data,
-+				u8 phy_id)
-+{
-+	struct sas_rphy *rphy;
-+	struct dev_to_host_fis *fis;
-+	int i;
-+
-+	if (phy_id >= sas_ha->num_phys) {
-+		resp_data[2] = SMP_RESP_NO_PHY;
-+		return;
-+	}
-+
-+	resp_data[2] = SMP_RESP_PHY_NO_SATA;
-+
-+	if (!sas_ha->sas_phy[phy_id]->port)
-+		return;
-+
-+	rphy = sas_ha->sas_phy[phy_id]->port->port_dev->rphy;
-+	fis = (struct dev_to_host_fis *)
-+		sas_ha->sas_phy[phy_id]->port->port_dev->frame_rcvd;
-+	if (rphy->identify.target_port_protocols != SAS_PROTOCOL_SATA)
-+		return;
-+
-+	resp_data[2] = SMP_RESP_FUNC_ACC;
-+	resp_data[9] = phy_id;
-+	memcpy(resp_data + 16, sas_ha->sas_phy[phy_id]->attached_sas_addr,
-+	       SAS_ADDR_SIZE);
-+
-+	/* check to see if we have a valid d2h fis */
-+	if (fis->fis_type != 0x34)
-+		return;
-+
-+	/* the d2h fis is required by the standard to be in LE format */
-+	for (i = 0; i < 20; i += 4) {
-+		u8 *dst = resp_data + 24 + i, *src =
-+			&sas_ha->sas_phy[phy_id]->port->port_dev->frame_rcvd[i];
-+		dst[0] = src[3];
-+		dst[1] = src[2];
-+		dst[2] = src[1];
-+		dst[3] = src[0];
-+	}
-+}
-+
-+static void sas_phy_control(struct sas_ha_struct *sas_ha, u8 phy_id,
-+			    u8 phy_op, enum sas_linkrate min,
-+			    enum sas_linkrate max, u8 *resp_data)
-+{
-+	struct sas_internal *i =
-+		to_sas_internal(sas_ha->core.shost->transportt);
-+	struct sas_phy_linkrates rates;
-+
-+	if (phy_id >= sas_ha->num_phys) {
-+		resp_data[2] = SMP_RESP_NO_PHY;
-+		return;
-+	}
-+	switch (phy_op) {
-+	case PHY_FUNC_NOP:
-+	case PHY_FUNC_LINK_RESET:
-+	case PHY_FUNC_HARD_RESET:
-+	case PHY_FUNC_DISABLE:
-+	case PHY_FUNC_CLEAR_ERROR_LOG:
-+	case PHY_FUNC_CLEAR_AFFIL:
-+	case PHY_FUNC_TX_SATA_PS_SIGNAL:
-+		break;
-+
-+	default:
-+		resp_data[2] = SMP_RESP_PHY_UNK_OP;
-+		return;
-+	}
-+
-+	rates.minimum_linkrate = min;
-+	rates.maximum_linkrate = max;
-+
-+	if (i->dft->lldd_control_phy(sas_ha->sas_phy[phy_id], phy_op, &rates))
-+		resp_data[2] = SMP_RESP_FUNC_FAILED;
-+	else
-+		resp_data[2] = SMP_RESP_FUNC_ACC;
-+}
-+
-+int sas_smp_host_handler(struct Scsi_Host *shost, struct request *req,
-+			 struct request *rsp)
-+{
-+	u8 *req_data = NULL, *resp_data = NULL, *buf;
-+	struct sas_ha_struct *sas_ha = SHOST_TO_SAS_HA(shost);
-+	int error = -EINVAL, resp_data_len = rsp->data_len;
-+
-+	/* eight is the minimum size for request and response frames */
-+	if (req->data_len < 8 || rsp->data_len < 8)
-+		goto out;
-+
-+	if (bio_offset(req->bio) + req->data_len > PAGE_SIZE ||
-+	    bio_offset(rsp->bio) + rsp->data_len > PAGE_SIZE) {
-+		shost_printk(KERN_ERR, shost,
-+			"SMP request/response frame crosses page boundary");
-+		goto out;
-+	}
-+
-+	req_data = kzalloc(req->data_len, GFP_KERNEL);
-+
-+	/* make sure frame can always be built ... we copy
-+	 * back only the requested length */
-+	resp_data = kzalloc(max(rsp->data_len, 128U), GFP_KERNEL);
-+
-+	if (!req_data || !resp_data) {
-+		error = -ENOMEM;
-+		goto out;
-+	}
-+
-+	local_irq_disable();
-+	buf = kmap_atomic(bio_page(req->bio), KM_USER0) + bio_offset(req->bio);
-+	memcpy(req_data, buf, req->data_len);
-+	kunmap_atomic(buf - bio_offset(req->bio), KM_USER0);
-+	local_irq_enable();
-+
-+	if (req_data[0] != SMP_REQUEST)
-+		goto out;
-+
-+	/* always succeeds ... even if we can't process the request
-+	 * the result is in the response frame */
-+	error = 0;
-+
-+	/* set up default don't know response */
-+	resp_data[0] = SMP_RESPONSE;
-+	resp_data[1] = req_data[1];
-+	resp_data[2] = SMP_RESP_FUNC_UNK;
-+
-+	switch (req_data[1]) {
-+	case SMP_REPORT_GENERAL:
-+		req->data_len -= 8;
-+		resp_data_len -= 32;
-+		resp_data[2] = SMP_RESP_FUNC_ACC;
-+		resp_data[9] = sas_ha->num_phys;
-+		break;
-+
-+	case SMP_REPORT_MANUF_INFO:
-+		req->data_len -= 8;
-+		resp_data_len -= 64;
-+		resp_data[2] = SMP_RESP_FUNC_ACC;
-+		memcpy(resp_data + 12, shost->hostt->name,
-+		       SAS_EXPANDER_VENDOR_ID_LEN);
-+		memcpy(resp_data + 20, "libsas virt phy",
-+		       SAS_EXPANDER_PRODUCT_ID_LEN);
-+		break;
-+
-+	case SMP_READ_GPIO_REG:
-+		/* FIXME: need GPIO support in the transport class */
-+		break;
-+
-+	case SMP_DISCOVER:
-+		req->data_len =- 16;
-+		if (req->data_len < 0) {
-+			req->data_len = 0;
-+			error = -EINVAL;
-+			goto out;
-+		}
-+		resp_data_len -= 56;
-+		sas_host_smp_discover(sas_ha, resp_data, req_data[9]);
-+		break;
-+
-+	case SMP_REPORT_PHY_ERR_LOG:
-+		/* FIXME: could implement this with additional
-+		 * libsas callbacks providing the HW supports it */
-+		break;
-+
-+	case SMP_REPORT_PHY_SATA:
-+		req->data_len =- 16;
-+		if (req->data_len < 0) {
-+			req->data_len = 0;
-+			error = -EINVAL;
-+			goto out;
-+		}
-+		resp_data_len -= 60;
-+		sas_report_phy_sata(sas_ha, resp_data, req_data[9]);
-+		break;
-+
-+	case SMP_REPORT_ROUTE_INFO:
-+		/* Can't implement; hosts have no routes */
-+		break;
-+
-+	case SMP_WRITE_GPIO_REG:
-+		/* FIXME: need GPIO support in the transport class */
-+		break;
-+
-+	case SMP_CONF_ROUTE_INFO:
-+		/* Can't implement; hosts have no routes */
-+		break;
-+
-+	case SMP_PHY_CONTROL:
-+		req->data_len =- 44;
-+		if (req->data_len < 0) {
-+			req->data_len = 0;
-+			error = -EINVAL;
-+			goto out;
-+		}
-+		resp_data_len -= 8;
-+		sas_phy_control(sas_ha, req_data[9], req_data[10],
-+				req_data[32] >> 4, req_data[33] >> 4,
-+				resp_data);
-+		break;
-+
-+	case SMP_PHY_TEST_FUNCTION:
-+		/* FIXME: should this be implemented? */
-+		break;
-+
-+	default:
-+		/* probably a 2.0 function */
-+		break;
-+	}
-+
-+	local_irq_disable();
-+	buf = kmap_atomic(bio_page(rsp->bio), KM_USER0) + bio_offset(rsp->bio);
-+	memcpy(buf, resp_data, rsp->data_len);
-+	flush_kernel_dcache_page(bio_page(rsp->bio));
-+	kunmap_atomic(buf - bio_offset(rsp->bio), KM_USER0);
-+	local_irq_enable();
-+	rsp->data_len = resp_data_len;
-+
-+ out:
-+	kfree(req_data);
-+	kfree(resp_data);
-+	return error;
-+}
-diff --git a/drivers/scsi/libsas/sas_internal.h b/drivers/scsi/libsas/sas_internal.h
-index 2b8213b..b4f9368 100644
---- a/drivers/scsi/libsas/sas_internal.h
-+++ b/drivers/scsi/libsas/sas_internal.h
-@@ -45,7 +45,7 @@
- void sas_scsi_recover_host(struct Scsi_Host *shost);
- 
- int sas_show_class(enum sas_class class, char *buf);
--int sas_show_proto(enum sas_proto proto, char *buf);
-+int sas_show_proto(enum sas_protocol proto, char *buf);
- int sas_show_linkrate(enum sas_linkrate linkrate, char *buf);
- int sas_show_oob_mode(enum sas_oob_mode oob_mode, char *buf);
- 
-@@ -80,6 +80,20 @@ struct domain_device *sas_find_dev_by_rphy(struct sas_rphy *rphy);
- 
- void sas_hae_reset(struct work_struct *work);
- 
-+#ifdef CONFIG_SCSI_SAS_HOST_SMP
-+extern int sas_smp_host_handler(struct Scsi_Host *shost, struct request *req,
-+				struct request *rsp);
-+#else
-+static inline int sas_smp_host_handler(struct Scsi_Host *shost,
-+				       struct request *req,
-+				       struct request *rsp)
-+{
-+	shost_printk(KERN_ERR, shost,
-+		"Cannot send SMP to a sas host (not enabled in CONFIG)\n");
-+	return -EINVAL;
-+}
-+#endif
-+
- static inline void sas_queue_event(int event, spinlock_t *lock,
- 				   unsigned long *pending,
- 				   struct work_struct *work,
-diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c
-index 7663841..f869fba 100644
---- a/drivers/scsi/libsas/sas_scsi_host.c
-+++ b/drivers/scsi/libsas/sas_scsi_host.c
-@@ -108,7 +108,7 @@ static void sas_scsi_task_done(struct sas_task *task)
- 			break;
- 		case SAM_CHECK_COND:
- 			memcpy(sc->sense_buffer, ts->buf,
--			       max(SCSI_SENSE_BUFFERSIZE, ts->buf_valid_size));
-+			       min(SCSI_SENSE_BUFFERSIZE, ts->buf_valid_size));
- 			stat = SAM_CHECK_COND;
- 			break;
- 		default:
-@@ -148,7 +148,6 @@ static struct sas_task *sas_create_task(struct scsi_cmnd *cmd,
- 	if (!task)
- 		return NULL;
- 
--	*(u32 *)cmd->sense_buffer = 0;
- 	task->uldd_task = cmd;
- 	ASSIGN_SAS_TASK(cmd, task);
- 
-@@ -200,6 +199,10 @@ int sas_queue_up(struct sas_task *task)
-  */
- int sas_queuecommand(struct scsi_cmnd *cmd,
- 		     void (*scsi_done)(struct scsi_cmnd *))
-+	__releases(host->host_lock)
-+	__acquires(dev->sata_dev.ap->lock)
-+	__releases(dev->sata_dev.ap->lock)
-+	__acquires(host->host_lock)
- {
- 	int res = 0;
- 	struct domain_device *dev = cmd_to_domain_dev(cmd);
-@@ -410,7 +413,7 @@ static int sas_recover_I_T(struct domain_device *dev)
- }
- 
- /* Find the sas_phy that's attached to this device */
--struct sas_phy *find_local_sas_phy(struct domain_device *dev)
-+static struct sas_phy *find_local_sas_phy(struct domain_device *dev)
- {
- 	struct domain_device *pdev = dev->parent;
- 	struct ex_phy *exphy = NULL;
-@@ -464,7 +467,7 @@ int sas_eh_bus_reset_handler(struct scsi_cmnd *cmd)
- 	res = sas_phy_reset(phy, 1);
- 	if (res)
- 		SAS_DPRINTK("Bus reset of %s failed 0x%x\n",
--			    phy->dev.kobj.k_name,
-+			    kobject_name(&phy->dev.kobj),
- 			    res);
- 	if (res == TMF_RESP_FUNC_SUCC || res == TMF_RESP_FUNC_COMPLETE)
- 		return SUCCESS;
-diff --git a/drivers/scsi/libsas/sas_task.c b/drivers/scsi/libsas/sas_task.c
-new file mode 100644
-index 0000000..594524d
---- /dev/null
-+++ b/drivers/scsi/libsas/sas_task.c
-@@ -0,0 +1,36 @@
-+#include <linux/kernel.h>
-+#include <scsi/sas.h>
-+#include <scsi/libsas.h>
-+
-+/* fill task_status_struct based on SSP response frame */
-+void sas_ssp_task_response(struct device *dev, struct sas_task *task,
-+			   struct ssp_response_iu *iu)
-+{
-+	struct task_status_struct *tstat = &task->task_status;
-+
-+	tstat->resp = SAS_TASK_COMPLETE;
-+
-+	if (iu->datapres == 0)
-+		tstat->stat = iu->status;
-+	else if (iu->datapres == 1)
-+		tstat->stat = iu->resp_data[3];
-+	else if (iu->datapres == 2) {
-+		tstat->stat = SAM_CHECK_COND;
-+		tstat->buf_valid_size =
-+			min_t(int, SAS_STATUS_BUF_SIZE,
-+			      be32_to_cpu(iu->sense_data_len));
-+		memcpy(tstat->buf, iu->sense_data, tstat->buf_valid_size);
-+
-+		if (iu->status != SAM_CHECK_COND)
-+			dev_printk(KERN_WARNING, dev,
-+				   "dev %llx sent sense data, but "
-+				   "stat(%x) is not CHECK CONDITION\n",
-+				   SAS_ADDR(task->dev->sas_addr),
-+				   iu->status);
-+	}
-+	else
-+		/* when datapres contains corrupt/unknown value... */
-+		tstat->stat = SAM_CHECK_COND;
-+}
-+EXPORT_SYMBOL_GPL(sas_ssp_task_response);
-+
-diff --git a/drivers/scsi/libsrp.c b/drivers/scsi/libsrp.c
-index 2ad0a27..5cff020 100644
---- a/drivers/scsi/libsrp.c
-+++ b/drivers/scsi/libsrp.c
-@@ -192,18 +192,18 @@ static int srp_direct_data(struct scsi_cmnd *sc, struct srp_direct_buf *md,
- 
- 	if (dma_map) {
- 		iue = (struct iu_entry *) sc->SCp.ptr;
--		sg = sc->request_buffer;
-+		sg = scsi_sglist(sc);
- 
--		dprintk("%p %u %u %d\n", iue, sc->request_bufflen,
--			md->len, sc->use_sg);
-+		dprintk("%p %u %u %d\n", iue, scsi_bufflen(sc),
-+			md->len, scsi_sg_count(sc));
- 
--		nsg = dma_map_sg(iue->target->dev, sg, sc->use_sg,
-+		nsg = dma_map_sg(iue->target->dev, sg, scsi_sg_count(sc),
- 				 DMA_BIDIRECTIONAL);
- 		if (!nsg) {
--			printk("fail to map %p %d\n", iue, sc->use_sg);
-+			printk("fail to map %p %d\n", iue, scsi_sg_count(sc));
- 			return 0;
- 		}
--		len = min(sc->request_bufflen, md->len);
-+		len = min(scsi_bufflen(sc), md->len);
- 	} else
- 		len = md->len;
- 
-@@ -229,10 +229,10 @@ static int srp_indirect_data(struct scsi_cmnd *sc, struct srp_cmd *cmd,
- 
- 	if (dma_map || ext_desc) {
- 		iue = (struct iu_entry *) sc->SCp.ptr;
--		sg = sc->request_buffer;
-+		sg = scsi_sglist(sc);
- 
- 		dprintk("%p %u %u %d %d\n",
--			iue, sc->request_bufflen, id->len,
-+			iue, scsi_bufflen(sc), id->len,
- 			cmd->data_in_desc_cnt, cmd->data_out_desc_cnt);
- 	}
- 
-@@ -268,13 +268,14 @@ static int srp_indirect_data(struct scsi_cmnd *sc, struct srp_cmd *cmd,
- 
- rdma:
- 	if (dma_map) {
--		nsg = dma_map_sg(iue->target->dev, sg, sc->use_sg, DMA_BIDIRECTIONAL);
-+		nsg = dma_map_sg(iue->target->dev, sg, scsi_sg_count(sc),
-+				 DMA_BIDIRECTIONAL);
- 		if (!nsg) {
--			eprintk("fail to map %p %d\n", iue, sc->use_sg);
-+			eprintk("fail to map %p %d\n", iue, scsi_sg_count(sc));
- 			err = -EIO;
- 			goto free_mem;
- 		}
--		len = min(sc->request_bufflen, id->len);
-+		len = min(scsi_bufflen(sc), id->len);
- 	} else
- 		len = id->len;
- 
-diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h
-index ba3ecab..f26b953 100644
---- a/drivers/scsi/lpfc/lpfc.h
-+++ b/drivers/scsi/lpfc/lpfc.h
-@@ -29,7 +29,8 @@ struct lpfc_sli2_slim;
- #define LPFC_MAX_NS_RETRY	3	/* Number of retry attempts to contact
- 					   the NameServer  before giving up. */
- #define LPFC_CMD_PER_LUN	3	/* max outstanding cmds per lun */
--#define LPFC_SG_SEG_CNT		64	/* sg element count per scsi cmnd */
-+#define LPFC_DEFAULT_SG_SEG_CNT	64	/* sg element count per scsi cmnd */
-+#define LPFC_MAX_SG_SEG_CNT	256	/* sg element count per scsi cmnd */
- #define LPFC_IOCB_LIST_CNT	2250	/* list of IOCBs for fast-path usage. */
- #define LPFC_Q_RAMP_UP_INTERVAL 120     /* lun q_depth ramp up interval */
- 
-@@ -68,6 +69,7 @@ struct lpfc_dmabuf {
- 	struct list_head list;
- 	void *virt;		/* virtual address ptr */
- 	dma_addr_t phys;	/* mapped address */
-+	uint32_t   buffer_tag;	/* used for tagged queue ring */
- };
- 
- struct lpfc_dma_pool {
-@@ -272,10 +274,16 @@ struct lpfc_vport {
- #define FC_ABORT_DISCOVERY      0x8000	 /* we want to abort discovery */
- #define FC_NDISC_ACTIVE         0x10000	 /* NPort discovery active */
- #define FC_BYPASSED_MODE        0x20000	 /* NPort is in bypassed mode */
--#define FC_RFF_NOT_SUPPORTED    0x40000	 /* RFF_ID was rejected by switch */
- #define FC_VPORT_NEEDS_REG_VPI	0x80000  /* Needs to have its vpi registered */
- #define FC_RSCN_DEFERRED	0x100000 /* A deferred RSCN being processed */
- 
-+	uint32_t ct_flags;
-+#define FC_CT_RFF_ID		0x1	 /* RFF_ID accepted by switch */
-+#define FC_CT_RNN_ID		0x2	 /* RNN_ID accepted by switch */
-+#define FC_CT_RSNN_NN		0x4	 /* RSNN_NN accepted by switch */
-+#define FC_CT_RSPN_ID		0x8	 /* RSPN_ID accepted by switch */
-+#define FC_CT_RFT_ID		0x10	 /* RFT_ID accepted by switch */
-+
- 	struct list_head fc_nodes;
- 
- 	/* Keep counters for the number of entries in each list. */
-@@ -344,6 +352,7 @@ struct lpfc_vport {
- 	uint32_t cfg_discovery_threads;
- 	uint32_t cfg_log_verbose;
- 	uint32_t cfg_max_luns;
-+	uint32_t cfg_enable_da_id;
- 
- 	uint32_t dev_loss_tmo_changed;
- 
-@@ -360,6 +369,7 @@ struct lpfc_vport {
- 
- struct hbq_s {
- 	uint16_t entry_count;	  /* Current number of HBQ slots */
-+	uint16_t buffer_count;	  /* Current number of buffers posted */
- 	uint32_t next_hbqPutIdx;  /* Index to next HBQ slot to use */
- 	uint32_t hbqPutIdx;	  /* HBQ slot to use */
- 	uint32_t local_hbqGetIdx; /* Local copy of Get index from Port */
-@@ -377,6 +387,11 @@ struct hbq_s {
- #define LPFC_ELS_HBQ	0
- #define LPFC_EXTRA_HBQ	1
- 
-+enum hba_temp_state {
-+	HBA_NORMAL_TEMP,
-+	HBA_OVER_TEMP
-+};
-+
- struct lpfc_hba {
- 	struct lpfc_sli sli;
- 	uint32_t sli_rev;		/* SLI2 or SLI3 */
-@@ -457,7 +472,8 @@ struct lpfc_hba {
- 	uint64_t cfg_soft_wwnn;
- 	uint64_t cfg_soft_wwpn;
- 	uint32_t cfg_hba_queue_depth;
+-// IDE IDENTIFY data
+-typedef struct _IDENTIFY_DATA
+-	{
+-    USHORT GeneralConfiguration;            // 00
+-    USHORT NumberOfCylinders;               // 02
+-    USHORT Reserved1;                       // 04
+-    USHORT NumberOfHeads;                   // 06
+-    USHORT UnformattedBytesPerTrack;        // 08
+-    USHORT UnformattedBytesPerSector;       // 0A
+-    USHORT SectorsPerTrack;                 // 0C
+-    USHORT VendorUnique1[3];                // 0E
+-    USHORT SerialNumber[10];                // 14
+-    USHORT BufferType;                      // 28
+-    USHORT BufferSectorSize;                // 2A
+-    USHORT NumberOfEccBytes;                // 2C
+-    USHORT FirmwareRevision[4];             // 2E
+-    USHORT ModelNumber[20];                 // 36
+-    UCHAR  MaximumBlockTransfer;            // 5E
+-    UCHAR  VendorUnique2;                   // 5F
+-    USHORT DoubleWordIo;                    // 60
+-    USHORT Capabilities;                    // 62
+-    USHORT Reserved2;                       // 64
+-    UCHAR  VendorUnique3;                   // 66
+-    UCHAR  PioCycleTimingMode;              // 67
+-    UCHAR  VendorUnique4;                   // 68
+-    UCHAR  DmaCycleTimingMode;              // 69
+-    USHORT TranslationFieldsValid:1;        // 6A
+-    USHORT Reserved3:15;
+-    USHORT NumberOfCurrentCylinders;        // 6C
+-    USHORT NumberOfCurrentHeads;            // 6E
+-    USHORT CurrentSectorsPerTrack;          // 70
+-    ULONG  CurrentSectorCapacity;           // 72
+-    USHORT Reserved4[197];                  // 76
+-	}	IDENTIFY_DATA, *PIDENTIFY_DATA;
 -
-+	uint32_t cfg_enable_hba_reset;
-+	uint32_t cfg_enable_hba_heartbeat;
- 
- 	lpfc_vpd_t vpd;		/* vital product data */
- 
-@@ -544,8 +560,7 @@ struct lpfc_hba {
- 	struct list_head port_list;
- 	struct lpfc_vport *pport;	/* physical lpfc_vport pointer */
- 	uint16_t max_vpi;		/* Maximum virtual nports */
--#define LPFC_MAX_VPI 100		/* Max number of VPI supported */
--#define LPFC_MAX_VPORTS (LPFC_MAX_VPI+1)/* Max number of VPorts supported */
-+#define LPFC_MAX_VPI 0xFFFF		/* Max number of VPI supported */
- 	unsigned long *vpi_bmask;	/* vpi allocation table */
- 
- 	/* Data structure used by fabric iocb scheduler */
-@@ -563,16 +578,30 @@ struct lpfc_hba {
- 	struct dentry *hba_debugfs_root;
- 	atomic_t debugfs_vport_count;
- 	struct dentry *debug_hbqinfo;
--	struct dentry *debug_dumpslim;
-+	struct dentry *debug_dumpHostSlim;
-+	struct dentry *debug_dumpHBASlim;
- 	struct dentry *debug_slow_ring_trc;
- 	struct lpfc_debugfs_trc *slow_ring_trc;
- 	atomic_t slow_ring_trc_cnt;
- #endif
+-// Identify data without the Reserved4.
+-typedef struct _IDENTIFY_DATA2 {
+-    USHORT GeneralConfiguration;            // 00
+-    USHORT NumberOfCylinders;               // 02
+-    USHORT Reserved1;                       // 04
+-    USHORT NumberOfHeads;                   // 06
+-    USHORT UnformattedBytesPerTrack;        // 08
+-    USHORT UnformattedBytesPerSector;       // 0A
+-    USHORT SectorsPerTrack;                 // 0C
+-    USHORT VendorUnique1[3];                // 0E
+-    USHORT SerialNumber[10];                // 14
+-    USHORT BufferType;                      // 28
+-    USHORT BufferSectorSize;                // 2A
+-    USHORT NumberOfEccBytes;                // 2C
+-    USHORT FirmwareRevision[4];             // 2E
+-    USHORT ModelNumber[20];                 // 36
+-    UCHAR  MaximumBlockTransfer;            // 5E
+-    UCHAR  VendorUnique2;                   // 5F
+-    USHORT DoubleWordIo;                    // 60
+-    USHORT Capabilities;                    // 62
+-    USHORT Reserved2;                       // 64
+-    UCHAR  VendorUnique3;                   // 66
+-    UCHAR  PioCycleTimingMode;              // 67
+-    UCHAR  VendorUnique4;                   // 68
+-    UCHAR  DmaCycleTimingMode;              // 69
+-	USHORT TranslationFieldsValid:1;     	// 6A
+-    USHORT Reserved3:15;
+-    USHORT NumberOfCurrentCylinders;        // 6C
+-    USHORT NumberOfCurrentHeads;            // 6E
+-    USHORT CurrentSectorsPerTrack;          // 70
+-    ULONG  CurrentSectorCapacity;           // 72
+-	}	IDENTIFY_DATA2, *PIDENTIFY_DATA2;
+-
+-#endif	// PSI_EIDE_SCSIOP
+-
+-// function prototypes
+-int Psi240i_Command(struct scsi_cmnd *SCpnt);
+-int Psi240i_Abort(struct scsi_cmnd *SCpnt);
+-int Psi240i_Reset(struct scsi_cmnd *SCpnt, unsigned int flags);
+-#endif
+diff --git a/drivers/scsi/psi_chip.h b/drivers/scsi/psi_chip.h
+deleted file mode 100644
+index 224cf8f..0000000
+--- a/drivers/scsi/psi_chip.h
++++ /dev/null
+@@ -1,195 +0,0 @@
+-/*+M*************************************************************************
+- * Perceptive Solutions, Inc. PSI-240I device driver proc support for Linux.
+- *
+- * Copyright (c) 1997 Perceptive Solutions, 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, or (at your option)
+- * any later version.
+- *
+- * This program is distributed in the hope that it will be useful,
+- * but WITHOUT ANY WARRANTY; without even the implied warranty of
+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See 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, 675 Mass Ave, Cambridge, MA 02139, USA.
+- *
+- *
+- *	File Name:	psi_chip.h
+- *
+- *	Description:	This file contains the interface defines and
+- *					error codes.
+- *
+- *-M*************************************************************************/
+-#ifndef PSI_CHIP
+-#define PSI_CHIP
+-
+-/************************************************/
+-/*		Misc konstants							*/
+-/************************************************/
+-#define	CHIP_MAXDRIVES			8
+-
+-/************************************************/
+-/*		Chip I/O addresses						*/
+-/************************************************/
+-#define	CHIP_ADRS_0				0x0130
+-#define	CHIP_ADRS_1				0x0150
+-#define	CHIP_ADRS_2				0x0190
+-#define	CHIP_ADRS_3				0x0210
+-#define	CHIP_ADRS_4				0x0230
+-#define	CHIP_ADRS_5				0x0250
+-
+-/************************************************/
+-/*		EEPROM locations		*/
+-/************************************************/
+-#define	CHIP_EEPROM_BIOS		0x0000		// BIOS base address
+-#define	CHIP_EEPROM_DATA		0x2000	   	// SETUP data base address
+-#define	CHIP_EEPROM_FACTORY		0x2400	   	// FACTORY data base address
+-#define	CHIP_EEPROM_SETUP		0x3000	   	// SETUP PROGRAM base address
+-
+-#define	CHIP_EEPROM_SIZE		32768U	   	// size of the entire EEPROM
+-#define	CHIP_EEPROM_BIOS_SIZE	8192	   	// size of the BIOS in bytes
+-#define	CHIP_EEPROM_DATA_SIZE	4096	   	// size of factory, setup, log data block in bytes
+-#define	CHIP_EEPROM_SETUP_SIZE	20480U	   	// size of the setup program in bytes
+-
+-/************************************************/
+-/*		Chip Interrupts							*/
+-/************************************************/
+-#define	CHIP_IRQ_10				0x72
+-#define	CHIP_IRQ_11				0x73
+-#define	CHIP_IRQ_12				0x74
+-
+-/************************************************/
+-/*		Chip Setup addresses		*/
+-/************************************************/
+-#define	CHIP_SETUP_BASE			0x0000C000L
+-
+-/************************************************/
+-/*		Chip Register address offsets	*/
+-/************************************************/
+-#define	REG_DATA				0x00
+-#define	REG_ERROR				0x01
+-#define	REG_SECTOR_COUNT		0x02
+-#define	REG_LBA_0				0x03
+-#define	REG_LBA_8				0x04
+-#define	REG_LBA_16				0x05
+-#define	REG_LBA_24				0x06
+-#define	REG_STAT_CMD			0x07
+-#define	REG_SEL_FAIL			0x08
+-#define	REG_IRQ_STATUS			0x09
+-#define	REG_ADDRESS				0x0A
+-#define	REG_FAIL				0x0C
+-#define	REG_ALT_STAT		   	0x0E
+-#define	REG_DRIVE_ADRS			0x0F
+-
+-/************************************************/
+-/*		Chip RAM locations		*/
+-/************************************************/
+-#define	CHIP_DEVICE				0x8000
+-#define	CHIP_DEVICE_0			0x8000
+-#define CHIP_DEVICE_1			0x8008
+-#define	CHIP_DEVICE_2			0x8010
+-#define	CHIP_DEVICE_3			0x8018
+-#define	CHIP_DEVICE_4			0x8020
+-#define	CHIP_DEVICE_5			0x8028
+-#define	CHIP_DEVICE_6			0x8030
+-#define	CHIP_DEVICE_7			0x8038
+-typedef struct
+-	{
+-	UCHAR	channel;		// channel of this device (0-8).
+-	UCHAR	spt;			// Sectors Per Track.
+-	ULONG	spc;			// Sectors Per Cylinder.
+-	}	CHIP_DEVICE_N;
+-
+-#define	CHIP_CONFIG				0x8100		// address of boards configuration.
+-typedef struct
+-	{
+-	UCHAR		irq;			// interrupt request channel number
+-	UCHAR		numDrives;		// Number of accessible drives
+-	UCHAR		fastFormat;	 	// Boolean for fast format enable
+-	}	CHIP_CONFIG_N;
+-
+-#define	CHIP_MAP				0x8108 		// eight byte device type map.
+-
+-
+-#define	CHIP_RAID				0x8120 		// array of RAID signature structures and LBA
+-#define	CHIP_RAID_1				0x8120
+-#define CHIP_RAID_2				0x8130
+-#define	CHIP_RAID_3				0x8140
+-#define	CHIP_RAID_4				0x8150
+-
+-/************************************************/
+-/*		Chip Register Masks		*/
+-/************************************************/
+-#define	CHIP_ID					0x7B
+-#define	SEL_RAM					0x8000
+-#define	MASK_FAIL				0x80
+-
+-/************************************************/
+-/*		Chip cable select bits		*/
+-/************************************************/
+-#define	SECTORSXFER				8
+-
+-/************************************************/
+-/*		Chip cable select bits		*/
+-/************************************************/
+-#define	SEL_NONE				0x00
+-#define	SEL_1					0x01
+-#define	SEL_2					0x02
+-#define	SEL_3					0x04
+-#define	SEL_4					0x08
+-
+-/************************************************/
+-/*		Programmable Interrupt Controller*/
+-/************************************************/
+-#define	PIC1					0x20		// first 8259 base port address
+-#define	PIC2					0xA0		// second 8259 base port address
+-#define	INT_OCW1				1			// Operation Control Word 1: IRQ mask
+-#define	EOI						0x20		// non-specific end-of-interrupt
+-
+-/************************************************/
+-/*		Device/Geometry controls				*/
+-/************************************************/
+-#define GEOMETRY_NONE		 	0x0			// No device
+-#define GEOMETRY_AUTO			0x1			// Geometry set automatically
+-#define GEOMETRY_USER		 	0x2			// User supplied geometry
+-
+-#define	DEVICE_NONE				0x0			// No device present
+-#define	DEVICE_INACTIVE			0x1			// device present but not registered active
+-#define	DEVICE_ATAPI			0x2			// ATAPI device (CD_ROM, Tape, Etc...)
+-#define	DEVICE_DASD_NONLBA		0x3			// Non LBA incompatible device
+-#define	DEVICE_DASD_LBA			0x4			// LBA compatible device
+-
+-/************************************************/
+-/*		Setup Structure Definitions	*/
+-/************************************************/
+-typedef struct							// device setup parameters
+-	{
+-	UCHAR			geometryControl;	// geometry control flags
+-	UCHAR		   	device;				// device code
+-	USHORT			sectors;			// number of sectors per track
+-	USHORT			heads;				// number of heads
+-	USHORT			cylinders;			// number of cylinders for this device
+-	ULONG			blocks;				// number of blocks on device
+-	USHORT			spare1;
+-	USHORT			spare2;
+-	} SETUP_DEVICE, *PSETUP_DEVICE;
+-
+-typedef struct		// master setup structure
+-	{
+-	USHORT 			startupDelay;
+-	USHORT 			promptBIOS;
+-	USHORT 			fastFormat;
+-	USHORT			spare2;
+-	USHORT			spare3;
+-	USHORT			spare4;
+-	USHORT			spare5;
+-	USHORT			spare6;
+-	SETUP_DEVICE	setupDevice[8];
+-	}	SETUP, *PSETUP;
+-
+-#endif
+-
+diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c
+index 2886407..c94906a 100644
+--- a/drivers/scsi/qla1280.c
++++ b/drivers/scsi/qla1280.c
+@@ -528,7 +528,7 @@ __setup("qla1280=", qla1280_setup);
+ #define	CMD_CDBLEN(Cmnd)	Cmnd->cmd_len
+ #define	CMD_CDBP(Cmnd)		Cmnd->cmnd
+ #define	CMD_SNSP(Cmnd)		Cmnd->sense_buffer
+-#define	CMD_SNSLEN(Cmnd)	sizeof(Cmnd->sense_buffer)
++#define	CMD_SNSLEN(Cmnd)	SCSI_SENSE_BUFFERSIZE
+ #define	CMD_RESULT(Cmnd)	Cmnd->result
+ #define	CMD_HANDLE(Cmnd)	Cmnd->host_scribble
+ #define CMD_REQUEST(Cmnd)	Cmnd->request->cmd
+@@ -3715,7 +3715,7 @@ qla1280_status_entry(struct scsi_qla_host *ha, struct response *pkt,
+ 			} else
+ 				sense_sz = 0;
+ 			memset(cmd->sense_buffer + sense_sz, 0,
+-			       sizeof(cmd->sense_buffer) - sense_sz);
++			       SCSI_SENSE_BUFFERSIZE - sense_sz);
  
-+	/* Used for deferred freeing of ELS data buffers */
-+	struct list_head elsbuf;
-+	int elsbuf_cnt;
-+	int elsbuf_prev_cnt;
-+
-+	uint8_t temp_sensor_support;
- 	/* Fields used for heart beat. */
- 	unsigned long last_completion_time;
- 	struct timer_list hb_tmofunc;
- 	uint8_t hb_outstanding;
-+	/*
-+	 * Following bit will be set for all buffer tags which are not
-+	 * associated with any HBQ.
-+	 */
-+#define QUE_BUFTAG_BIT  (1<<31)
-+	uint32_t buffer_tag_count;
-+	enum hba_temp_state over_temp_state;
- };
+ 			dprintk(2, "qla1280_status_entry: Check "
+ 				"condition Sense data, b %i, t %i, "
+diff --git a/drivers/scsi/qla2xxx/Makefile b/drivers/scsi/qla2xxx/Makefile
+index 71ddb5d..c51fd1f 100644
+--- a/drivers/scsi/qla2xxx/Makefile
++++ b/drivers/scsi/qla2xxx/Makefile
+@@ -1,4 +1,4 @@
+ qla2xxx-y := qla_os.o qla_init.o qla_mbx.o qla_iocb.o qla_isr.o qla_gs.o \
+-		qla_dbg.o qla_sup.o qla_attr.o qla_mid.o
++		qla_dbg.o qla_sup.o qla_attr.o qla_mid.o qla_dfs.o
  
- static inline struct Scsi_Host *
-@@ -598,5 +627,15 @@ lpfc_is_link_up(struct lpfc_hba *phba)
- 		phba->link_state == LPFC_HBA_READY;
- }
+ obj-$(CONFIG_SCSI_QLA_FC) += qla2xxx.o
+diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c
+index fb388b8..adf9732 100644
+--- a/drivers/scsi/qla2xxx/qla_attr.c
++++ b/drivers/scsi/qla2xxx/qla_attr.c
+@@ -9,7 +9,7 @@
+ #include <linux/kthread.h>
+ #include <linux/vmalloc.h>
  
--#define FC_REG_DUMP_EVENT	0x10	/* Register for Dump events */
-+#define FC_REG_DUMP_EVENT		0x10	/* Register for Dump events */
-+#define FC_REG_TEMPERATURE_EVENT	0x20    /* Register for temperature
-+						   event */
+-int qla24xx_vport_disable(struct fc_vport *, bool);
++static int qla24xx_vport_disable(struct fc_vport *, bool);
  
-+struct temp_event {
-+	uint32_t event_type;
-+	uint32_t event_code;
-+	uint32_t data;
-+};
-+#define LPFC_CRIT_TEMP		0x1
-+#define LPFC_THRESHOLD_TEMP	0x2
-+#define LPFC_NORMAL_TEMP	0x3
-diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c
-index 80a1121..4bae4a2 100644
---- a/drivers/scsi/lpfc/lpfc_attr.c
-+++ b/drivers/scsi/lpfc/lpfc_attr.c
-@@ -1,7 +1,7 @@
- /*******************************************************************
-  * This file is part of the Emulex Linux Device Driver for         *
-  * Fibre Channel Host Bus Adapters.                                *
-- * Copyright (C) 2004-2007 Emulex.  All rights reserved.           *
-+ * Copyright (C) 2004-2008 Emulex.  All rights reserved.           *
-  * EMULEX and SLI are trademarks of Emulex.                        *
-  * www.emulex.com                                                  *
-  * Portions Copyright (C) 2004-2005 Christoph Hellwig              *
-@@ -45,6 +45,10 @@
- #define LPFC_MIN_DEVLOSS_TMO 1
- #define LPFC_MAX_DEVLOSS_TMO 255
+ /* SYSFS attributes --------------------------------------------------------- */
  
-+#define LPFC_MAX_LINK_SPEED 8
-+#define LPFC_LINK_SPEED_BITMAP 0x00000117
-+#define LPFC_LINK_SPEED_STRING "0, 1, 2, 4, 8"
-+
- static void
- lpfc_jedec_to_ascii(int incr, char hdw[])
+@@ -958,7 +958,7 @@ qla2x00_issue_lip(struct Scsi_Host *shost)
  {
-@@ -86,6 +90,15 @@ lpfc_serialnum_show(struct class_device *cdev, char *buf)
+ 	scsi_qla_host_t *ha = shost_priv(shost);
+ 
+-	set_bit(LOOP_RESET_NEEDED, &ha->dpc_flags);
++	qla2x00_loop_reset(ha);
+ 	return 0;
  }
  
- static ssize_t
-+lpfc_temp_sensor_show(struct class_device *cdev, char *buf)
-+{
-+	struct Scsi_Host *shost = class_to_shost(cdev);
-+	struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
-+	struct lpfc_hba   *phba = vport->phba;
-+	return snprintf(buf, PAGE_SIZE, "%d\n",phba->temp_sensor_support);
-+}
-+
-+static ssize_t
- lpfc_modeldesc_show(struct class_device *cdev, char *buf)
+@@ -967,35 +967,51 @@ qla2x00_get_fc_host_stats(struct Scsi_Host *shost)
  {
- 	struct Scsi_Host  *shost = class_to_shost(cdev);
-@@ -178,12 +191,9 @@ lpfc_state_show(struct class_device *cdev, char *buf)
- 	case LPFC_LINK_UP:
- 	case LPFC_CLEAR_LA:
- 	case LPFC_HBA_READY:
--		len += snprintf(buf + len, PAGE_SIZE-len, "Link Up - \n");
-+		len += snprintf(buf + len, PAGE_SIZE-len, "Link Up - ");
- 
- 		switch (vport->port_state) {
--			len += snprintf(buf + len, PAGE_SIZE-len,
--					"initializing\n");
--			break;
- 		case LPFC_LOCAL_CFG_LINK:
- 			len += snprintf(buf + len, PAGE_SIZE-len,
- 					"Configuring Link\n");
-@@ -252,8 +262,7 @@ lpfc_issue_lip(struct Scsi_Host *shost)
- 	int mbxstatus = MBXERR_ERROR;
- 
- 	if ((vport->fc_flag & FC_OFFLINE_MODE) ||
--	    (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO) ||
--	    (vport->port_state != LPFC_VPORT_READY))
-+	    (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO))
- 		return -EPERM;
- 
- 	pmboxq = mempool_alloc(phba->mbox_mem_pool,GFP_KERNEL);
-@@ -305,12 +314,14 @@ lpfc_do_offline(struct lpfc_hba *phba, uint32_t type)
- 
- 	psli = &phba->sli;
- 
-+	/* Wait a little for things to settle down, but not
-+	 * long enough for dev loss timeout to expire.
-+	 */
- 	for (i = 0; i < psli->num_rings; i++) {
- 		pring = &psli->ring[i];
--		/* The linkdown event takes 30 seconds to timeout. */
- 		while (pring->txcmplq_cnt) {
- 			msleep(10);
--			if (cnt++ > 3000) {
-+			if (cnt++ > 500) {  /* 5 secs */
- 				lpfc_printf_log(phba,
- 					KERN_WARNING, LOG_INIT,
- 					"0466 Outstanding IO when "
-@@ -336,6 +347,9 @@ lpfc_selective_reset(struct lpfc_hba *phba)
- 	struct completion online_compl;
- 	int status = 0;
- 
-+	if (!phba->cfg_enable_hba_reset)
-+		return -EIO;
-+
- 	status = lpfc_do_offline(phba, LPFC_EVT_OFFLINE);
- 
- 	if (status != 0)
-@@ -409,6 +423,8 @@ lpfc_board_mode_store(struct class_device *cdev, const char *buf, size_t count)
- 	struct completion online_compl;
- 	int status=0;
- 
-+	if (!phba->cfg_enable_hba_reset)
-+		return -EACCES;
- 	init_completion(&online_compl);
- 
- 	if(strncmp(buf, "online", sizeof("online") - 1) == 0) {
-@@ -908,6 +924,8 @@ static CLASS_DEVICE_ATTR(used_rpi, S_IRUGO, lpfc_used_rpi_show, NULL);
- static CLASS_DEVICE_ATTR(max_xri, S_IRUGO, lpfc_max_xri_show, NULL);
- static CLASS_DEVICE_ATTR(used_xri, S_IRUGO, lpfc_used_xri_show, NULL);
- static CLASS_DEVICE_ATTR(npiv_info, S_IRUGO, lpfc_npiv_info_show, NULL);
-+static CLASS_DEVICE_ATTR(lpfc_temp_sensor, S_IRUGO, lpfc_temp_sensor_show,
-+			 NULL);
- 
- 
- static char *lpfc_soft_wwn_key = "C99G71SL8032A";
-@@ -971,6 +989,14 @@ lpfc_soft_wwpn_store(struct class_device *cdev, const char *buf, size_t count)
- 	unsigned int i, j, cnt=count;
- 	u8 wwpn[8];
- 
-+	if (!phba->cfg_enable_hba_reset)
-+		return -EACCES;
-+	spin_lock_irq(&phba->hbalock);
-+	if (phba->over_temp_state == HBA_OVER_TEMP) {
-+		spin_unlock_irq(&phba->hbalock);
-+		return -EACCES;
-+	}
-+	spin_unlock_irq(&phba->hbalock);
- 	/* count may include a LF at end of string */
- 	if (buf[cnt-1] == '\n')
- 		cnt--;
-@@ -1102,7 +1128,13 @@ MODULE_PARM_DESC(lpfc_sli_mode, "SLI mode selector:"
- 		 " 2 - select SLI-2 even on SLI-3 capable HBAs,"
- 		 " 3 - select SLI-3");
- 
--LPFC_ATTR_R(enable_npiv, 0, 0, 1, "Enable NPIV functionality");
-+int lpfc_enable_npiv = 0;
-+module_param(lpfc_enable_npiv, int, 0);
-+MODULE_PARM_DESC(lpfc_enable_npiv, "Enable NPIV functionality");
-+lpfc_param_show(enable_npiv);
-+lpfc_param_init(enable_npiv, 0, 0, 1);
-+static CLASS_DEVICE_ATTR(lpfc_enable_npiv, S_IRUGO,
-+			 lpfc_enable_npiv_show, NULL);
- 
- /*
- # lpfc_nodev_tmo: If set, it will hold all I/O errors on devices that disappear
-@@ -1248,6 +1280,13 @@ LPFC_VPORT_ATTR_HEX_RW(log_verbose, 0x0, 0x0, 0xffff,
- 		       "Verbose logging bit-mask");
+ 	scsi_qla_host_t *ha = shost_priv(shost);
+ 	int rval;
+-	uint16_t mb_stat[1];
+-	link_stat_t stat_buf;
++	struct link_statistics *stats;
++	dma_addr_t stats_dma;
+ 	struct fc_host_statistics *pfc_host_stat;
  
- /*
-+# lpfc_enable_da_id: This turns on the DA_ID CT command that deregisters
-+# objects that have been registered with the nameserver after login.
-+*/
-+LPFC_VPORT_ATTR_R(enable_da_id, 0, 0, 1,
-+		  "Deregister nameserver objects before LOGO");
-+
-+/*
- # lun_queue_depth:  This parameter is used to limit the number of outstanding
- # commands per FCP LUN. Value range is [1,128]. Default value is 30.
- */
-@@ -1369,7 +1408,33 @@ LPFC_VPORT_ATTR_R(scan_down, 1, 0, 1,
- # Set loop mode if you want to run as an NL_Port. Value range is [0,0x6].
- # Default value is 0.
- */
--LPFC_ATTR_RW(topology, 0, 0, 6, "Select Fibre Channel topology");
-+static int
-+lpfc_topology_set(struct lpfc_hba *phba, int val)
-+{
-+	int err;
-+	uint32_t prev_val;
-+	if (val >= 0 && val <= 6) {
-+		prev_val = phba->cfg_topology;
-+		phba->cfg_topology = val;
-+		err = lpfc_issue_lip(lpfc_shost_from_vport(phba->pport));
-+		if (err)
-+			phba->cfg_topology = prev_val;
-+		return err;
-+	}
-+	lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
-+		"%d:0467 lpfc_topology attribute cannot be set to %d, "
-+		"allowed range is [0, 6]\n",
-+		phba->brd_no, val);
-+	return -EINVAL;
-+}
-+static int lpfc_topology = 0;
-+module_param(lpfc_topology, int, 0);
-+MODULE_PARM_DESC(lpfc_topology, "Select Fibre Channel topology");
-+lpfc_param_show(topology)
-+lpfc_param_init(topology, 0, 0, 6)
-+lpfc_param_store(topology)
-+static CLASS_DEVICE_ATTR(lpfc_topology, S_IRUGO | S_IWUSR,
-+		lpfc_topology_show, lpfc_topology_store);
+-	rval = QLA_FUNCTION_FAILED;
+ 	pfc_host_stat = &ha->fc_host_stat;
+ 	memset(pfc_host_stat, -1, sizeof(struct fc_host_statistics));
  
- /*
- # lpfc_link_speed: Link speed selection for initializing the Fibre Channel
-@@ -1381,7 +1446,59 @@ LPFC_ATTR_RW(topology, 0, 0, 6, "Select Fibre Channel topology");
- #       8  = 8 Gigabaud
- # Value range is [0,8]. Default value is 0.
- */
--LPFC_ATTR_R(link_speed, 0, 0, 8, "Select link speed");
-+static int
-+lpfc_link_speed_set(struct lpfc_hba *phba, int val)
-+{
-+	int err;
-+	uint32_t prev_val;
-+
-+	if (((val == LINK_SPEED_1G) && !(phba->lmt & LMT_1Gb)) ||
-+		((val == LINK_SPEED_2G) && !(phba->lmt & LMT_2Gb)) ||
-+		((val == LINK_SPEED_4G) && !(phba->lmt & LMT_4Gb)) ||
-+		((val == LINK_SPEED_8G) && !(phba->lmt & LMT_8Gb)) ||
-+		((val == LINK_SPEED_10G) && !(phba->lmt & LMT_10Gb)))
-+		return -EINVAL;
-+
-+	if ((val >= 0 && val <= LPFC_MAX_LINK_SPEED)
-+		&& (LPFC_LINK_SPEED_BITMAP & (1 << val))) {
-+		prev_val = phba->cfg_link_speed;
-+		phba->cfg_link_speed = val;
-+		err = lpfc_issue_lip(lpfc_shost_from_vport(phba->pport));
-+		if (err)
-+			phba->cfg_link_speed = prev_val;
-+		return err;
-+	}
-+
-+	lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
-+		"%d:0469 lpfc_link_speed attribute cannot be set to %d, "
-+		"allowed range is [0, 8]\n",
-+		phba->brd_no, val);
-+	return -EINVAL;
-+}
-+
-+static int lpfc_link_speed = 0;
-+module_param(lpfc_link_speed, int, 0);
-+MODULE_PARM_DESC(lpfc_link_speed, "Select link speed");
-+lpfc_param_show(link_speed)
-+static int
-+lpfc_link_speed_init(struct lpfc_hba *phba, int val)
-+{
-+	if ((val >= 0 && val <= LPFC_MAX_LINK_SPEED)
-+		&& (LPFC_LINK_SPEED_BITMAP & (1 << val))) {
-+		phba->cfg_link_speed = val;
-+		return 0;
++	stats = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &stats_dma);
++	if (stats == NULL) {
++		DEBUG2_3_11(printk("%s(%ld): Failed to allocate memory.\n",
++		    __func__, ha->host_no));
++		goto done;
 +	}
-+	lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
-+			"0454 lpfc_link_speed attribute cannot "
-+			"be set to %d, allowed values are "
-+			"["LPFC_LINK_SPEED_STRING"]\n", val);
-+	phba->cfg_link_speed = 0;
-+	return -EINVAL;
-+}
++	memset(stats, 0, DMA_POOL_SIZE);
 +
-+lpfc_param_store(link_speed)
-+static CLASS_DEVICE_ATTR(lpfc_link_speed, S_IRUGO | S_IWUSR,
-+		lpfc_link_speed_show, lpfc_link_speed_store);
- 
- /*
- # lpfc_fcp_class:  Determines FC class to use for the FCP protocol.
-@@ -1479,7 +1596,30 @@ LPFC_ATTR_RW(poll_tmo, 10, 1, 255,
- */
- LPFC_ATTR_R(use_msi, 0, 0, 1, "Use Message Signaled Interrupts, if possible");
++	rval = QLA_FUNCTION_FAILED;
+ 	if (IS_FWI2_CAPABLE(ha)) {
+-		rval = qla24xx_get_isp_stats(ha, (uint32_t *)&stat_buf,
+-		    sizeof(stat_buf) / 4, mb_stat);
++		rval = qla24xx_get_isp_stats(ha, stats, stats_dma);
+ 	} else if (atomic_read(&ha->loop_state) == LOOP_READY &&
+ 		    !test_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags) &&
+ 		    !test_bit(ISP_ABORT_NEEDED, &ha->dpc_flags) &&
+ 		    !ha->dpc_active) {
+ 		/* Must be in a 'READY' state for statistics retrieval. */
+-		rval = qla2x00_get_link_status(ha, ha->loop_id, &stat_buf,
+-		    mb_stat);
++		rval = qla2x00_get_link_status(ha, ha->loop_id, stats,
++		    stats_dma);
+ 	}
  
-+/*
-+# lpfc_enable_hba_reset: Allow or prevent HBA resets to the hardware.
-+#       0  = HBA resets disabled
-+#       1  = HBA resets enabled (default)
-+# Value range is [0,1]. Default value is 1.
-+*/
-+LPFC_ATTR_R(enable_hba_reset, 1, 0, 1, "Enable HBA resets from the driver.");
+ 	if (rval != QLA_SUCCESS)
+-		goto done;
++		goto done_free;
 +
-+/*
-+# lpfc_enable_hba_heartbeat: Enable HBA heartbeat timer..
-+#       0  = HBA Heartbeat disabled
-+#       1  = HBA Heartbeat enabled (default)
-+# Value range is [0,1]. Default value is 1.
-+*/
-+LPFC_ATTR_R(enable_hba_heartbeat, 1, 0, 1, "Enable HBA Heartbeat.");
- 
-+/*
-+ * lpfc_sg_seg_cnt: Initial Maximum DMA Segment Count
-+ * This value can be set to values between 64 and 256. The default value is
-+ * 64, but may be increased to allow for larger Max I/O sizes. The scsi layer
-+ * will be allowed to request I/Os of sizes up to (MAX_SEG_COUNT * SEG_SIZE).
-+ */
-+LPFC_ATTR_R(sg_seg_cnt, LPFC_DEFAULT_SG_SEG_CNT, LPFC_DEFAULT_SG_SEG_CNT,
-+	    LPFC_MAX_SG_SEG_CNT, "Max Scatter Gather Segment Count");
- 
- struct class_device_attribute *lpfc_hba_attrs[] = {
- 	&class_device_attr_info,
-@@ -1494,6 +1634,7 @@ struct class_device_attribute *lpfc_hba_attrs[] = {
- 	&class_device_attr_state,
- 	&class_device_attr_num_discovered_ports,
- 	&class_device_attr_lpfc_drvr_version,
-+	&class_device_attr_lpfc_temp_sensor,
- 	&class_device_attr_lpfc_log_verbose,
- 	&class_device_attr_lpfc_lun_queue_depth,
- 	&class_device_attr_lpfc_hba_queue_depth,
-@@ -1530,6 +1671,9 @@ struct class_device_attribute *lpfc_hba_attrs[] = {
- 	&class_device_attr_lpfc_soft_wwnn,
- 	&class_device_attr_lpfc_soft_wwpn,
- 	&class_device_attr_lpfc_soft_wwn_enable,
-+	&class_device_attr_lpfc_enable_hba_reset,
-+	&class_device_attr_lpfc_enable_hba_heartbeat,
-+	&class_device_attr_lpfc_sg_seg_cnt,
- 	NULL,
- };
- 
-@@ -1552,6 +1696,7 @@ struct class_device_attribute *lpfc_vport_attrs[] = {
- 	&class_device_attr_lpfc_max_luns,
- 	&class_device_attr_nport_evt_cnt,
- 	&class_device_attr_npiv_info,
-+	&class_device_attr_lpfc_enable_da_id,
- 	NULL,
- };
- 
-@@ -1727,13 +1872,18 @@ sysfs_mbox_read(struct kobject *kobj, struct bin_attribute *bin_attr,
- 
- 	spin_lock_irq(&phba->hbalock);
- 
-+	if (phba->over_temp_state == HBA_OVER_TEMP) {
-+		sysfs_mbox_idle(phba);
-+		spin_unlock_irq(&phba->hbalock);
-+		return  -EACCES;
++	pfc_host_stat->link_failure_count = stats->link_fail_cnt;
++	pfc_host_stat->loss_of_sync_count = stats->loss_sync_cnt;
++	pfc_host_stat->loss_of_signal_count = stats->loss_sig_cnt;
++	pfc_host_stat->prim_seq_protocol_err_count = stats->prim_seq_err_cnt;
++	pfc_host_stat->invalid_tx_word_count = stats->inval_xmit_word_cnt;
++	pfc_host_stat->invalid_crc_count = stats->inval_crc_cnt;
++	if (IS_FWI2_CAPABLE(ha)) {
++		pfc_host_stat->tx_frames = stats->tx_frames;
++		pfc_host_stat->rx_frames = stats->rx_frames;
++		pfc_host_stat->dumped_frames = stats->dumped_frames;
++		pfc_host_stat->nos_count = stats->nos_rcvd;
 +	}
-+
- 	if (off == 0 &&
- 	    phba->sysfs_mbox.state  == SMBOX_WRITING &&
- 	    phba->sysfs_mbox.offset >= 2 * sizeof(uint32_t)) {
- 
- 		switch (phba->sysfs_mbox.mbox->mb.mbxCommand) {
- 			/* Offline only */
--		case MBX_WRITE_NV:
- 		case MBX_INIT_LINK:
- 		case MBX_DOWN_LINK:
- 		case MBX_CONFIG_LINK:
-@@ -1744,9 +1894,7 @@ sysfs_mbox_read(struct kobject *kobj, struct bin_attribute *bin_attr,
- 		case MBX_DUMP_CONTEXT:
- 		case MBX_RUN_DIAGS:
- 		case MBX_RESTART:
--		case MBX_FLASH_WR_ULA:
- 		case MBX_SET_MASK:
--		case MBX_SET_SLIM:
- 		case MBX_SET_DEBUG:
- 			if (!(vport->fc_flag & FC_OFFLINE_MODE)) {
- 				printk(KERN_WARNING "mbox_read:Command 0x%x "
-@@ -1756,6 +1904,8 @@ sysfs_mbox_read(struct kobject *kobj, struct bin_attribute *bin_attr,
- 				spin_unlock_irq(&phba->hbalock);
- 				return -EPERM;
- 			}
-+		case MBX_WRITE_NV:
-+		case MBX_WRITE_VPARMS:
- 		case MBX_LOAD_SM:
- 		case MBX_READ_NV:
- 		case MBX_READ_CONFIG:
-@@ -1772,6 +1922,8 @@ sysfs_mbox_read(struct kobject *kobj, struct bin_attribute *bin_attr,
- 		case MBX_LOAD_EXP_ROM:
- 		case MBX_BEACON:
- 		case MBX_DEL_LD_ENTRY:
-+		case MBX_SET_VARIABLE:
-+		case MBX_WRITE_WWN:
- 			break;
- 		case MBX_READ_SPARM64:
- 		case MBX_READ_LA:
-@@ -1793,6 +1945,17 @@ sysfs_mbox_read(struct kobject *kobj, struct bin_attribute *bin_attr,
- 			return -EPERM;
- 		}
- 
-+		/* If HBA encountered an error attention, allow only DUMP
-+		 * mailbox command until the HBA is restarted.
-+		 */
-+		if ((phba->pport->stopped) &&
-+			(phba->sysfs_mbox.mbox->mb.mbxCommand
-+				!= MBX_DUMP_MEMORY)) {
-+			sysfs_mbox_idle(phba);
-+			spin_unlock_irq(&phba->hbalock);
-+			return -EPERM;
-+		}
-+
- 		phba->sysfs_mbox.mbox->vport = vport;
- 
- 		if (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO) {
-@@ -1993,7 +2156,8 @@ lpfc_get_host_speed(struct Scsi_Host *shost)
- 				fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN;
- 			break;
- 		}
--	}
-+	} else
-+		fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN;
- 
- 	spin_unlock_irq(shost->host_lock);
- }
-@@ -2013,7 +2177,7 @@ lpfc_get_host_fabric_name (struct Scsi_Host *shost)
- 		node_name = wwn_to_u64(phba->fc_fabparam.nodeName.u.wwn);
- 	else
- 		/* fabric is local port if there is no F/FL_Port */
--		node_name = wwn_to_u64(vport->fc_nodename.u.wwn);
-+		node_name = 0;
- 
- 	spin_unlock_irq(shost->host_lock);
- 
-@@ -2337,8 +2501,6 @@ struct fc_function_template lpfc_transport_functions = {
- 	.dev_loss_tmo_callbk = lpfc_dev_loss_tmo_callbk,
- 	.terminate_rport_io = lpfc_terminate_rport_io,
- 
--	.vport_create = lpfc_vport_create,
--	.vport_delete = lpfc_vport_delete,
- 	.dd_fcvport_size = sizeof(struct lpfc_vport *),
- };
- 
-@@ -2414,21 +2576,23 @@ lpfc_get_cfgparam(struct lpfc_hba *phba)
- 	lpfc_poll_tmo_init(phba, lpfc_poll_tmo);
- 	lpfc_enable_npiv_init(phba, lpfc_enable_npiv);
- 	lpfc_use_msi_init(phba, lpfc_use_msi);
-+	lpfc_enable_hba_reset_init(phba, lpfc_enable_hba_reset);
-+	lpfc_enable_hba_heartbeat_init(phba, lpfc_enable_hba_heartbeat);
- 	phba->cfg_poll = lpfc_poll;
- 	phba->cfg_soft_wwnn = 0L;
- 	phba->cfg_soft_wwpn = 0L;
--	/*
--	 * The total number of segments is the configuration value plus 2
--	 * since the IOCB need a command and response bde.
--	 */
--	phba->cfg_sg_seg_cnt = LPFC_SG_SEG_CNT + 2;
-+	lpfc_sg_seg_cnt_init(phba, lpfc_sg_seg_cnt);
-+	/* Also reinitialize the host templates with new values. */
-+	lpfc_vport_template.sg_tablesize = phba->cfg_sg_seg_cnt;
-+	lpfc_template.sg_tablesize = phba->cfg_sg_seg_cnt;
- 	/*
- 	 * Since the sg_tablesize is module parameter, the sg_dma_buf_size
--	 * used to create the sg_dma_buf_pool must be dynamically calculated
-+	 * used to create the sg_dma_buf_pool must be dynamically calculated.
-+	 * 2 segments are added since the IOCB needs a command and response bde.
- 	 */
- 	phba->cfg_sg_dma_buf_size = sizeof(struct fcp_cmnd) +
- 			sizeof(struct fcp_rsp) +
--			(phba->cfg_sg_seg_cnt * sizeof(struct ulp_bde64));
-+			((phba->cfg_sg_seg_cnt + 2) * sizeof(struct ulp_bde64));
- 	lpfc_hba_queue_depth_init(phba, lpfc_hba_queue_depth);
- 	return;
- }
-@@ -2448,5 +2612,6 @@ lpfc_get_vport_cfgparam(struct lpfc_vport *vport)
- 	lpfc_discovery_threads_init(vport, lpfc_discovery_threads);
- 	lpfc_max_luns_init(vport, lpfc_max_luns);
- 	lpfc_scan_down_init(vport, lpfc_scan_down);
-+	lpfc_enable_da_id_init(vport, lpfc_enable_da_id);
- 	return;
- }
-diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h
-index a599e15..50fcb7c 100644
---- a/drivers/scsi/lpfc/lpfc_crtn.h
-+++ b/drivers/scsi/lpfc/lpfc_crtn.h
-@@ -23,6 +23,8 @@ typedef int (*node_filter)(struct lpfc_nodelist *ndlp, void *param);
- struct fc_rport;
- void lpfc_dump_mem(struct lpfc_hba *, LPFC_MBOXQ_t *, uint16_t);
- void lpfc_read_nv(struct lpfc_hba *, LPFC_MBOXQ_t *);
-+void lpfc_config_async(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t);
-+
- void lpfc_heart_beat(struct lpfc_hba *, LPFC_MBOXQ_t *);
- int lpfc_read_la(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb,
- 		 struct lpfc_dmabuf *mp);
-@@ -43,9 +45,9 @@ void lpfc_init_link(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t, uint32_t);
- struct lpfc_vport *lpfc_find_vport_by_did(struct lpfc_hba *, uint32_t);
- void lpfc_cleanup_rpis(struct lpfc_vport *vport, int remove);
- int lpfc_linkdown(struct lpfc_hba *);
-+void lpfc_port_link_failure(struct lpfc_vport *);
- void lpfc_mbx_cmpl_read_la(struct lpfc_hba *, LPFC_MBOXQ_t *);
- 
--void lpfc_mbx_cmpl_clear_la(struct lpfc_hba *, LPFC_MBOXQ_t *);
- void lpfc_mbx_cmpl_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
- void lpfc_mbx_cmpl_dflt_rpi(struct lpfc_hba *, LPFC_MBOXQ_t *);
- void lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
-@@ -66,15 +68,15 @@ int lpfc_check_sli_ndlp(struct lpfc_hba *, struct lpfc_sli_ring *,
- void lpfc_nlp_init(struct lpfc_vport *, struct lpfc_nodelist *, uint32_t);
- struct lpfc_nodelist *lpfc_nlp_get(struct lpfc_nodelist *);
- int  lpfc_nlp_put(struct lpfc_nodelist *);
-+int  lpfc_nlp_not_used(struct lpfc_nodelist *ndlp);
- struct lpfc_nodelist *lpfc_setup_disc_node(struct lpfc_vport *, uint32_t);
- void lpfc_disc_list_loopmap(struct lpfc_vport *);
- void lpfc_disc_start(struct lpfc_vport *);
--void lpfc_disc_flush_list(struct lpfc_vport *);
- void lpfc_cleanup_discovery_resources(struct lpfc_vport *);
-+void lpfc_cleanup(struct lpfc_vport *);
- void lpfc_disc_timeout(unsigned long);
- 
- struct lpfc_nodelist *__lpfc_findnode_rpi(struct lpfc_vport *, uint16_t);
--struct lpfc_nodelist *lpfc_findnode_rpi(struct lpfc_vport *, uint16_t);
- 
- void lpfc_worker_wake_up(struct lpfc_hba *);
- int lpfc_workq_post_event(struct lpfc_hba *, void *, void *, uint32_t);
-@@ -82,17 +84,17 @@ int lpfc_do_work(void *);
- int lpfc_disc_state_machine(struct lpfc_vport *, struct lpfc_nodelist *, void *,
- 			    uint32_t);
- 
--void lpfc_register_new_vport(struct lpfc_hba *, struct lpfc_vport *,
--			struct lpfc_nodelist *);
- void lpfc_do_scr_ns_plogi(struct lpfc_hba *, struct lpfc_vport *);
- int lpfc_check_sparm(struct lpfc_vport *, struct lpfc_nodelist *,
- 		     struct serv_parm *, uint32_t);
- int lpfc_els_abort(struct lpfc_hba *, struct lpfc_nodelist *);
-+void lpfc_more_plogi(struct lpfc_vport *);
-+void lpfc_more_adisc(struct lpfc_vport *);
-+void lpfc_end_rscn(struct lpfc_vport *);
- int lpfc_els_chk_latt(struct lpfc_vport *);
- int lpfc_els_abort_flogi(struct lpfc_hba *);
- int lpfc_initial_flogi(struct lpfc_vport *);
- int lpfc_initial_fdisc(struct lpfc_vport *);
--int lpfc_issue_els_fdisc(struct lpfc_vport *, struct lpfc_nodelist *, uint8_t);
- int lpfc_issue_els_plogi(struct lpfc_vport *, uint32_t, uint8_t);
- int lpfc_issue_els_prli(struct lpfc_vport *, struct lpfc_nodelist *, uint8_t);
- int lpfc_issue_els_adisc(struct lpfc_vport *, struct lpfc_nodelist *, uint8_t);
-@@ -112,7 +114,6 @@ int lpfc_els_rsp_prli_acc(struct lpfc_vport *, struct lpfc_iocbq *,
- void lpfc_cancel_retry_delay_tmo(struct lpfc_vport *, struct lpfc_nodelist *);
- void lpfc_els_retry_delay(unsigned long);
- void lpfc_els_retry_delay_handler(struct lpfc_nodelist *);
--void lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *);
- void lpfc_els_unsol_event(struct lpfc_hba *, struct lpfc_sli_ring *,
- 			  struct lpfc_iocbq *);
- int lpfc_els_handle_rscn(struct lpfc_vport *);
-@@ -124,7 +125,6 @@ int lpfc_els_disc_adisc(struct lpfc_vport *);
- int lpfc_els_disc_plogi(struct lpfc_vport *);
- void lpfc_els_timeout(unsigned long);
- void lpfc_els_timeout_handler(struct lpfc_vport *);
--void lpfc_hb_timeout(unsigned long);
- void lpfc_hb_timeout_handler(struct lpfc_hba *);
- 
- void lpfc_ct_unsol_event(struct lpfc_hba *, struct lpfc_sli_ring *,
-@@ -142,7 +142,6 @@ void lpfc_hba_init(struct lpfc_hba *, uint32_t *);
- int lpfc_post_buffer(struct lpfc_hba *, struct lpfc_sli_ring *, int, int);
- void lpfc_decode_firmware_rev(struct lpfc_hba *, char *, int);
- int lpfc_online(struct lpfc_hba *);
--void lpfc_block_mgmt_io(struct lpfc_hba *);
- void lpfc_unblock_mgmt_io(struct lpfc_hba *);
- void lpfc_offline_prep(struct lpfc_hba *);
- void lpfc_offline(struct lpfc_hba *);
-@@ -165,7 +164,6 @@ int lpfc_mbox_tmo_val(struct lpfc_hba *, int);
- 
- void lpfc_config_hbq(struct lpfc_hba *, uint32_t, struct lpfc_hbq_init *,
- 	uint32_t , LPFC_MBOXQ_t *);
--struct lpfc_hbq_entry * lpfc_sli_next_hbq_slot(struct lpfc_hba *, uint32_t);
- struct hbq_dmabuf *lpfc_els_hbq_alloc(struct lpfc_hba *);
- void lpfc_els_hbq_free(struct lpfc_hba *, struct hbq_dmabuf *);
- 
-@@ -178,7 +176,6 @@ void lpfc_poll_start_timer(struct lpfc_hba * phba);
- void lpfc_sli_poll_fcp_ring(struct lpfc_hba * hba);
- struct lpfc_iocbq * lpfc_sli_get_iocbq(struct lpfc_hba *);
- void lpfc_sli_release_iocbq(struct lpfc_hba * phba, struct lpfc_iocbq * iocb);
--void __lpfc_sli_release_iocbq(struct lpfc_hba * phba, struct lpfc_iocbq * iocb);
- uint16_t lpfc_sli_next_iotag(struct lpfc_hba * phba, struct lpfc_iocbq * iocb);
- 
- void lpfc_reset_barrier(struct lpfc_hba * phba);
-@@ -204,11 +201,14 @@ int lpfc_sli_ringpostbuf_put(struct lpfc_hba *, struct lpfc_sli_ring *,
- struct lpfc_dmabuf *lpfc_sli_ringpostbuf_get(struct lpfc_hba *,
- 					     struct lpfc_sli_ring *,
- 					     dma_addr_t);
-+
-+uint32_t lpfc_sli_get_buffer_tag(struct lpfc_hba *);
-+struct lpfc_dmabuf * lpfc_sli_ring_taggedbuf_get(struct lpfc_hba *,
-+			struct lpfc_sli_ring *, uint32_t );
-+
- int lpfc_sli_hbq_count(void);
--int lpfc_sli_hbqbuf_init_hbqs(struct lpfc_hba *, uint32_t);
- int lpfc_sli_hbqbuf_add_hbqs(struct lpfc_hba *, uint32_t);
- void lpfc_sli_hbqbuf_free_all(struct lpfc_hba *);
--struct hbq_dmabuf *lpfc_sli_hbqbuf_find(struct lpfc_hba *, uint32_t);
- int lpfc_sli_hbq_size(void);
- int lpfc_sli_issue_abort_iotag(struct lpfc_hba *, struct lpfc_sli_ring *,
- 			       struct lpfc_iocbq *);
-@@ -219,9 +219,6 @@ int lpfc_sli_abort_iocb(struct lpfc_vport *, struct lpfc_sli_ring *, uint16_t,
- void lpfc_mbox_timeout(unsigned long);
- void lpfc_mbox_timeout_handler(struct lpfc_hba *);
- 
--struct lpfc_nodelist *__lpfc_find_node(struct lpfc_vport *, node_filter,
--				       void *);
--struct lpfc_nodelist *lpfc_find_node(struct lpfc_vport *, node_filter, void *);
- struct lpfc_nodelist *lpfc_findnode_did(struct lpfc_vport *, uint32_t);
- struct lpfc_nodelist *lpfc_findnode_wwpn(struct lpfc_vport *,
- 					 struct lpfc_name *);
-@@ -260,6 +257,7 @@ extern struct scsi_host_template lpfc_vport_template;
- extern struct fc_function_template lpfc_transport_functions;
- extern struct fc_function_template lpfc_vport_transport_functions;
- extern int lpfc_sli_mode;
-+extern int lpfc_enable_npiv;
- 
- int  lpfc_vport_symbolic_node_name(struct lpfc_vport *, char *, size_t);
- void lpfc_terminate_rport_io(struct fc_rport *);
-@@ -281,11 +279,8 @@ extern void lpfc_debugfs_slow_ring_trc(struct lpfc_hba *, char *, uint32_t,
- extern struct lpfc_hbq_init *lpfc_hbq_defs[];
- 
- /* Interface exported by fabric iocb scheduler */
--int lpfc_issue_fabric_iocb(struct lpfc_hba *, struct lpfc_iocbq *);
--void lpfc_fabric_abort_vport(struct lpfc_vport *);
- void lpfc_fabric_abort_nport(struct lpfc_nodelist *);
- void lpfc_fabric_abort_hba(struct lpfc_hba *);
--void lpfc_fabric_abort_flogi(struct lpfc_hba *);
- void lpfc_fabric_block_timeout(unsigned long);
- void lpfc_unblock_fabric_iocbs(struct lpfc_hba *);
- void lpfc_adjust_queue_depth(struct lpfc_hba *);
-diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c
-index c701e4d..92441ce 100644
---- a/drivers/scsi/lpfc/lpfc_ct.c
-+++ b/drivers/scsi/lpfc/lpfc_ct.c
-@@ -19,7 +19,7 @@
-  *******************************************************************/
- 
- /*
-- * Fibre Channel SCSI LAN Device Driver CT support
-+ * Fibre Channel SCSI LAN Device Driver CT support: FC Generic Services FC-GS
-  */
- 
- #include <linux/blkdev.h>
-@@ -57,45 +57,27 @@
- 
- static char *lpfc_release_version = LPFC_DRIVER_VERSION;
- 
--/*
-- * lpfc_ct_unsol_event
-- */
- static void
--lpfc_ct_unsol_buffer(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq,
--		     struct lpfc_dmabuf *mp, uint32_t size)
-+lpfc_ct_ignore_hbq_buffer(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq,
-+			  struct lpfc_dmabuf *mp, uint32_t size)
- {
- 	if (!mp) {
--		printk(KERN_ERR "%s (%d): Unsolited CT, no buffer, "
--		       "piocbq = %p, status = x%x, mp = %p, size = %d\n",
--		       __FUNCTION__, __LINE__,
--		       piocbq, piocbq->iocb.ulpStatus, mp, size);
-+		lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
-+				"0146 Ignoring unsolicted CT No HBQ "
-+				"status = x%x\n",
-+				piocbq->iocb.ulpStatus);
- 	}
--
--	printk(KERN_ERR "%s (%d): Ignoring unsolicted CT piocbq = %p, "
--	       "buffer = %p, size = %d, status = x%x\n",
--	       __FUNCTION__, __LINE__,
--	       piocbq, mp, size,
--	       piocbq->iocb.ulpStatus);
--
-+	lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
-+			"0145 Ignoring unsolicted CT HBQ Size:%d "
-+			"status = x%x\n",
-+			size, piocbq->iocb.ulpStatus);
+ 
+-	pfc_host_stat->link_failure_count = stat_buf.link_fail_cnt;
+-	pfc_host_stat->loss_of_sync_count = stat_buf.loss_sync_cnt;
+-	pfc_host_stat->loss_of_signal_count = stat_buf.loss_sig_cnt;
+-	pfc_host_stat->prim_seq_protocol_err_count = stat_buf.prim_seq_err_cnt;
+-	pfc_host_stat->invalid_tx_word_count = stat_buf.inval_xmit_word_cnt;
+-	pfc_host_stat->invalid_crc_count = stat_buf.inval_crc_cnt;
++done_free:
++        dma_pool_free(ha->s_dma_pool, stats, stats_dma);
+ done:
+ 	return pfc_host_stat;
+ }
+@@ -1113,7 +1129,7 @@ vport_create_failed_2:
+ 	return FC_VPORT_FAILED;
  }
  
- static void
--lpfc_ct_ignore_hbq_buffer(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq,
--			  struct lpfc_dmabuf *mp, uint32_t size)
-+lpfc_ct_unsol_buffer(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq,
-+		     struct lpfc_dmabuf *mp, uint32_t size)
+-int
++static int
+ qla24xx_vport_delete(struct fc_vport *fc_vport)
  {
--	if (!mp) {
--		printk(KERN_ERR "%s (%d): Unsolited CT, no "
--		       "HBQ buffer, piocbq = %p, status = x%x\n",
--		       __FUNCTION__, __LINE__,
--		       piocbq, piocbq->iocb.ulpStatus);
--	} else {
--		lpfc_ct_unsol_buffer(phba, piocbq, mp, size);
--		printk(KERN_ERR "%s (%d): Ignoring unsolicted CT "
--		       "piocbq = %p, buffer = %p, size = %d, "
--		       "status = x%x\n",
--		       __FUNCTION__, __LINE__,
--		       piocbq, mp, size, piocbq->iocb.ulpStatus);
--	}
-+	lpfc_ct_ignore_hbq_buffer(phba, piocbq, mp, size);
- }
+ 	scsi_qla_host_t *ha = shost_priv(fc_vport->shost);
+@@ -1124,7 +1140,7 @@ qla24xx_vport_delete(struct fc_vport *fc_vport)
  
- void
-@@ -109,11 +91,8 @@ lpfc_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
- 	struct lpfc_iocbq *iocbq;
- 	dma_addr_t paddr;
- 	uint32_t size;
--	struct lpfc_dmabuf *bdeBuf1 = piocbq->context2;
--	struct lpfc_dmabuf *bdeBuf2 = piocbq->context3;
--
--	piocbq->context2 = NULL;
--	piocbq->context3 = NULL;
-+	struct list_head head;
-+	struct lpfc_dmabuf *bdeBuf;
+ 	down(&ha->vport_sem);
+ 	ha->cur_vport_count--;
+-	clear_bit(vha->vp_idx, (unsigned long *)ha->vp_idx_map);
++	clear_bit(vha->vp_idx, ha->vp_idx_map);
+ 	up(&ha->vport_sem);
  
- 	if (unlikely(icmd->ulpStatus == IOSTAT_NEED_BUFFER)) {
- 		lpfc_sli_hbqbuf_add_hbqs(phba, LPFC_ELS_HBQ);
-@@ -122,7 +101,7 @@ lpfc_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
- 		/* Not enough posted buffers; Try posting more buffers */
- 		phba->fc_stat.NoRcvBuf++;
- 		if (!(phba->sli3_options & LPFC_SLI3_HBQ_ENABLED))
--			lpfc_post_buffer(phba, pring, 0, 1);
-+			lpfc_post_buffer(phba, pring, 2, 1);
- 		return;
- 	}
+ 	kfree(vha->node_name);
+@@ -1146,7 +1162,7 @@ qla24xx_vport_delete(struct fc_vport *fc_vport)
+ 	return 0;
+ }
  
-@@ -133,38 +112,34 @@ lpfc_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
- 		return;
+-int
++static int
+ qla24xx_vport_disable(struct fc_vport *fc_vport, bool disable)
+ {
+ 	scsi_qla_host_t *vha = fc_vport->dd_data;
+diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c
+index eaa04da..d88e98c 100644
+--- a/drivers/scsi/qla2xxx/qla_dbg.c
++++ b/drivers/scsi/qla2xxx/qla_dbg.c
+@@ -1051,6 +1051,7 @@ qla25xx_fw_dump(scsi_qla_host_t *ha, int hardware_locked)
+ 	struct qla25xx_fw_dump *fw;
+ 	uint32_t	ext_mem_cnt;
+ 	void		*nxt;
++	struct qla2xxx_fce_chain *fcec;
  
- 	if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) {
--		list_for_each_entry(iocbq, &piocbq->list, list) {
-+		INIT_LIST_HEAD(&head);
-+		list_add_tail(&head, &piocbq->list);
-+		list_for_each_entry(iocbq, &head, list) {
- 			icmd = &iocbq->iocb;
--			if (icmd->ulpBdeCount == 0) {
--				printk(KERN_ERR "%s (%d): Unsolited CT, no "
--				       "BDE, iocbq = %p, status = x%x\n",
--				       __FUNCTION__, __LINE__,
--				       iocbq, iocbq->iocb.ulpStatus);
-+			if (icmd->ulpBdeCount == 0)
- 				continue;
--			}
--
-+			bdeBuf = iocbq->context2;
-+			iocbq->context2 = NULL;
- 			size  = icmd->un.cont64[0].tus.f.bdeSize;
--			lpfc_ct_ignore_hbq_buffer(phba, piocbq, bdeBuf1, size);
--			lpfc_in_buf_free(phba, bdeBuf1);
-+			lpfc_ct_unsol_buffer(phba, piocbq, bdeBuf, size);
-+			lpfc_in_buf_free(phba, bdeBuf);
- 			if (icmd->ulpBdeCount == 2) {
--				lpfc_ct_ignore_hbq_buffer(phba, piocbq, bdeBuf2,
--							  size);
--				lpfc_in_buf_free(phba, bdeBuf2);
-+				bdeBuf = iocbq->context3;
-+				iocbq->context3 = NULL;
-+				size  = icmd->unsli3.rcvsli3.bde2.tus.f.bdeSize;
-+				lpfc_ct_unsol_buffer(phba, piocbq, bdeBuf,
-+						     size);
-+				lpfc_in_buf_free(phba, bdeBuf);
- 			}
- 		}
-+		list_del(&head);
- 	} else {
- 		struct lpfc_iocbq  *next;
+ 	risc_address = ext_mem_cnt = 0;
+ 	flags = 0;
+@@ -1321,10 +1322,31 @@ qla25xx_fw_dump(scsi_qla_host_t *ha, int hardware_locked)
+ 	if (rval != QLA_SUCCESS)
+ 		goto qla25xx_fw_dump_failed_0;
  
- 		list_for_each_entry_safe(iocbq, next, &piocbq->list, list) {
- 			icmd = &iocbq->iocb;
--			if (icmd->ulpBdeCount == 0) {
--				printk(KERN_ERR "%s (%d): Unsolited CT, no "
--				       "BDE, iocbq = %p, status = x%x\n",
--				       __FUNCTION__, __LINE__,
--				       iocbq, iocbq->iocb.ulpStatus);
--				continue;
--			}
--
-+			if (icmd->ulpBdeCount == 0)
-+				lpfc_ct_unsol_buffer(phba, piocbq, NULL, 0);
- 			for (i = 0; i < icmd->ulpBdeCount; i++) {
- 				paddr = getPaddr(icmd->un.cont64[i].addrHigh,
- 						 icmd->un.cont64[i].addrLow);
-@@ -176,6 +151,7 @@ lpfc_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
- 			}
- 			list_del(&iocbq->list);
- 			lpfc_sli_release_iocbq(phba, iocbq);
-+			lpfc_post_buffer(phba, pring, i, 1);
- 		}
- 	}
++	/* Fibre Channel Trace Buffer. */
+ 	nxt = qla2xxx_copy_queues(ha, nxt);
+ 	if (ha->eft)
+ 		memcpy(nxt, ha->eft, ntohl(ha->fw_dump->eft_size));
+ 
++	/* Fibre Channel Event Buffer. */
++	if (!ha->fce)
++		goto qla25xx_fw_dump_failed_0;
++
++	ha->fw_dump->version |= __constant_htonl(DUMP_CHAIN_VARIANT);
++
++	fcec = nxt + ntohl(ha->fw_dump->eft_size);
++	fcec->type = __constant_htonl(DUMP_CHAIN_FCE | DUMP_CHAIN_LAST);
++	fcec->chain_size = htonl(sizeof(struct qla2xxx_fce_chain) +
++	    fce_calc_size(ha->fce_bufs));
++	fcec->size = htonl(fce_calc_size(ha->fce_bufs));
++	fcec->addr_l = htonl(LSD(ha->fce_dma));
++	fcec->addr_h = htonl(MSD(ha->fce_dma));
++
++	iter_reg = fcec->eregs;
++	for (cnt = 0; cnt < 8; cnt++)
++		*iter_reg++ = htonl(ha->fce_mb[cnt]);
++
++	memcpy(iter_reg, ha->fce, ntohl(fcec->size));
++
+ qla25xx_fw_dump_failed_0:
+ 	if (rval != QLA_SUCCESS) {
+ 		qla_printk(KERN_WARNING, ha,
+@@ -1428,21 +1450,6 @@ qla2x00_print_scsi_cmd(struct scsi_cmnd * cmd)
+ 	printk("  sp flags=0x%x\n", sp->flags);
  }
-@@ -203,7 +179,7 @@ lpfc_alloc_ct_rsp(struct lpfc_hba *phba, int cmdcode, struct ulp_bde64 *bpl,
- 	struct lpfc_dmabuf *mp;
- 	int cnt, i = 0;
  
--	/* We get chucks of FCELSSIZE */
-+	/* We get chunks of FCELSSIZE */
- 	cnt = size > FCELSSIZE ? FCELSSIZE: size;
+-void
+-qla2x00_dump_pkt(void *pkt)
+-{
+-	uint32_t i;
+-	uint8_t *data = (uint8_t *) pkt;
+-
+-	for (i = 0; i < 64; i++) {
+-		if (!(i % 4))
+-			printk("\n%02x: ", i);
+-
+-		printk("%02x ", data[i]);
+-	}
+-	printk("\n");
+-}
+-
+ #if defined(QL_DEBUG_ROUTINES)
+ /*
+  * qla2x00_formatted_dump_buffer
+diff --git a/drivers/scsi/qla2xxx/qla_dbg.h b/drivers/scsi/qla2xxx/qla_dbg.h
+index a50ecf0..524598a 100644
+--- a/drivers/scsi/qla2xxx/qla_dbg.h
++++ b/drivers/scsi/qla2xxx/qla_dbg.h
+@@ -256,6 +256,25 @@ struct qla25xx_fw_dump {
+ #define EFT_BYTES_PER_BUFFER	0x4000
+ #define EFT_SIZE		((EFT_BYTES_PER_BUFFER) * (EFT_NUM_BUFFERS))
  
- 	while (size) {
-@@ -426,6 +402,7 @@ lpfc_ns_rsp(struct lpfc_vport *vport, struct lpfc_dmabuf *mp, uint32_t Size)
++#define FCE_NUM_BUFFERS		64
++#define FCE_BYTES_PER_BUFFER	0x400
++#define FCE_SIZE		((FCE_BYTES_PER_BUFFER) * (FCE_NUM_BUFFERS))
++#define fce_calc_size(b)	((FCE_BYTES_PER_BUFFER) * (b))
++
++struct qla2xxx_fce_chain {
++	uint32_t type;
++	uint32_t chain_size;
++
++	uint32_t size;
++	uint32_t addr_l;
++	uint32_t addr_h;
++	uint32_t eregs[8];
++};
++
++#define DUMP_CHAIN_VARIANT	0x80000000
++#define DUMP_CHAIN_FCE		0x7FFFFAF0
++#define DUMP_CHAIN_LAST		0x80000000
++
+ struct qla2xxx_fw_dump {
+ 	uint8_t signature[4];
+ 	uint32_t version;
+diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
+index 04e8cbc..6f129da 100644
+--- a/drivers/scsi/qla2xxx/qla_def.h
++++ b/drivers/scsi/qla2xxx/qla_def.h
+@@ -623,9 +623,6 @@ typedef struct {
+ #define MBC_GET_LINK_PRIV_STATS		0x6d	/* Get link & private data. */
+ #define MBC_SET_VENDOR_ID		0x76	/* Set Vendor ID. */
  
- 	lpfc_set_disctmo(vport);
- 	vport->num_disc_nodes = 0;
-+	vport->fc_ns_retry = 0;
+-#define TC_ENABLE			4
+-#define TC_DISABLE			5
+-
+ /* Firmware return data sizes */
+ #define FCAL_MAP_SIZE	128
  
+@@ -862,14 +859,20 @@ typedef struct {
+ #define GLSO_SEND_RPS	BIT_0
+ #define GLSO_USE_DID	BIT_3
  
- 	list_add_tail(&head, &mp->list);
-@@ -458,7 +435,7 @@ lpfc_ns_rsp(struct lpfc_vport *vport, struct lpfc_dmabuf *mp, uint32_t Size)
- 			    ((lpfc_find_vport_by_did(phba, Did) == NULL) ||
- 			     vport->cfg_peer_port_login)) {
- 				if ((vport->port_type != LPFC_NPIV_PORT) ||
--				    (vport->fc_flag & FC_RFF_NOT_SUPPORTED) ||
-+				    (!(vport->ct_flags & FC_CT_RFF_ID)) ||
- 				    (!vport->cfg_restrict_login)) {
- 					ndlp = lpfc_setup_disc_node(vport, Did);
- 					if (ndlp) {
-@@ -506,7 +483,17 @@ lpfc_ns_rsp(struct lpfc_vport *vport, struct lpfc_dmabuf *mp, uint32_t Size)
- 						Did, vport->fc_flag,
- 						vport->fc_rscn_id_cnt);
+-typedef struct {
+-	uint32_t	link_fail_cnt;
+-	uint32_t	loss_sync_cnt;
+-	uint32_t	loss_sig_cnt;
+-	uint32_t	prim_seq_err_cnt;
+-	uint32_t	inval_xmit_word_cnt;
+-	uint32_t	inval_crc_cnt;
+-} link_stat_t;
++struct link_statistics {
++	uint32_t link_fail_cnt;
++	uint32_t loss_sync_cnt;
++	uint32_t loss_sig_cnt;
++	uint32_t prim_seq_err_cnt;
++	uint32_t inval_xmit_word_cnt;
++	uint32_t inval_crc_cnt;
++	uint32_t unused1[0x1b];
++	uint32_t tx_frames;
++	uint32_t rx_frames;
++	uint32_t dumped_frames;
++	uint32_t unused2[2];
++	uint32_t nos_rcvd;
++};
  
--						if (lpfc_ns_cmd(vport,
-+						/* This NPortID was previously
-+						 * a FCP target, * Don't even
-+						 * bother to send GFF_ID.
-+						 */
-+						ndlp = lpfc_findnode_did(vport,
-+							Did);
-+						if (ndlp && (ndlp->nlp_type &
-+							NLP_FCP_TARGET))
-+							lpfc_setup_disc_node
-+								(vport, Did);
-+						else if (lpfc_ns_cmd(vport,
- 							SLI_CTNS_GFF_ID,
- 							0, Did) == 0)
- 							vport->num_disc_nodes++;
-@@ -554,7 +541,7 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
- 	struct lpfc_dmabuf *outp;
- 	struct lpfc_sli_ct_request *CTrsp;
- 	struct lpfc_nodelist *ndlp;
--	int rc;
-+	int rc, retry;
+ /*
+  * NVRAM Command values.
+@@ -2116,14 +2119,6 @@ struct qla_msix_entry {
  
- 	/* First save ndlp, before we overwrite it */
- 	ndlp = cmdiocb->context_un.ndlp;
-@@ -574,7 +561,6 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
- 	if (vport->load_flag & FC_UNLOADING)
- 		goto out;
+ #define	WATCH_INTERVAL		1       /* number of seconds */
  
+-/* NPIV */
+-#define MAX_MULTI_ID_LOOP                     126
+-#define MAX_MULTI_ID_FABRIC                    64
+-#define MAX_NUM_VPORT_LOOP                      (MAX_MULTI_ID_LOOP - 1)
+-#define MAX_NUM_VPORT_FABRIC                    (MAX_MULTI_ID_FABRIC - 1)
+-#define MAX_NUM_VHBA_LOOP                       (MAX_MULTI_ID_LOOP - 1)
+-#define MAX_NUM_VHBA_FABRIC                     (MAX_MULTI_ID_FABRIC - 1)
 -
- 	if (lpfc_els_chk_latt(vport) || lpfc_error_lost_link(irsp)) {
- 		lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
- 				 "0216 Link event during NS query\n");
-@@ -585,14 +571,35 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
- 	if (irsp->ulpStatus) {
- 		/* Check for retry */
- 		if (vport->fc_ns_retry < LPFC_MAX_NS_RETRY) {
--			if ((irsp->ulpStatus != IOSTAT_LOCAL_REJECT) ||
--				(irsp->un.ulpWord[4] != IOERR_NO_RESOURCES))
-+			retry = 1;
-+			if (irsp->ulpStatus == IOSTAT_LOCAL_REJECT) {
-+				switch (irsp->un.ulpWord[4]) {
-+				case IOERR_NO_RESOURCES:
-+					/* We don't increment the retry
-+					 * count for this case.
-+					 */
-+					break;
-+				case IOERR_LINK_DOWN:
-+				case IOERR_SLI_ABORTED:
-+				case IOERR_SLI_DOWN:
-+					retry = 0;
-+					break;
-+				default:
-+					vport->fc_ns_retry++;
-+				}
-+			}
-+			else
- 				vport->fc_ns_retry++;
--			/* CT command is being retried */
--			rc = lpfc_ns_cmd(vport, SLI_CTNS_GID_FT,
-+
-+			if (retry) {
-+				/* CT command is being retried */
-+				rc = lpfc_ns_cmd(vport, SLI_CTNS_GID_FT,
- 					 vport->fc_ns_retry, 0);
--			if (rc == 0)
--				goto out;
-+				if (rc == 0) {
-+					/* success */
-+					goto out;
-+				}
-+			}
- 		}
- 		lpfc_vport_set_state(vport, FC_VPORT_FAILED);
- 		lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
-@@ -698,7 +705,7 @@ lpfc_cmpl_ct_cmd_gff_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
- 	struct lpfc_dmabuf *inp = (struct lpfc_dmabuf *) cmdiocb->context1;
- 	struct lpfc_dmabuf *outp = (struct lpfc_dmabuf *) cmdiocb->context2;
- 	struct lpfc_sli_ct_request *CTrsp;
--	int did;
-+	int did, rc, retry;
- 	uint8_t fbits;
- 	struct lpfc_nodelist *ndlp;
+ /*
+  * Linux Host Adapter structure
+  */
+@@ -2161,6 +2156,7 @@ typedef struct scsi_qla_host {
+ 		uint32_t	gpsc_supported		:1;
+ 		uint32_t        vsan_enabled            :1;
+ 		uint32_t	npiv_supported		:1;
++		uint32_t	fce_enabled		:1;
+ 	} flags;
  
-@@ -729,6 +736,39 @@ lpfc_cmpl_ct_cmd_gff_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
- 		}
- 	}
- 	else {
-+		/* Check for retry */
-+		if (cmdiocb->retry < LPFC_MAX_NS_RETRY) {
-+			retry = 1;
-+			if (irsp->ulpStatus == IOSTAT_LOCAL_REJECT) {
-+				switch (irsp->un.ulpWord[4]) {
-+				case IOERR_NO_RESOURCES:
-+					/* We don't increment the retry
-+					 * count for this case.
-+					 */
-+					break;
-+				case IOERR_LINK_DOWN:
-+				case IOERR_SLI_ABORTED:
-+				case IOERR_SLI_DOWN:
-+					retry = 0;
-+					break;
-+				default:
-+					cmdiocb->retry++;
-+				}
-+			}
-+			else
-+				cmdiocb->retry++;
-+
-+			if (retry) {
-+				/* CT command is being retried */
-+				rc = lpfc_ns_cmd(vport, SLI_CTNS_GFF_ID,
-+					 cmdiocb->retry, did);
-+				if (rc == 0) {
-+					/* success */
-+					lpfc_ct_free_iocb(phba, cmdiocb);
-+					return;
-+				}
-+			}
-+		}
- 		lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
- 				 "0267 NameServer GFF Rsp "
- 				 "x%x Error (%d %d) Data: x%x x%x\n",
-@@ -778,8 +818,8 @@ out:
+ 	atomic_t	loop_state;
+@@ -2273,8 +2269,7 @@ typedef struct scsi_qla_host {
  
+ 	int		bars;
+ 	device_reg_t __iomem *iobase;		/* Base I/O address */
+-	unsigned long	pio_address;
+-	unsigned long	pio_length;
++	resource_size_t pio_address;
+ #define MIN_IOBASE_LEN		0x100
  
- static void
--lpfc_cmpl_ct_cmd_rft_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
--			struct lpfc_iocbq *rspiocb)
-+lpfc_cmpl_ct(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
-+	     struct lpfc_iocbq *rspiocb)
- {
- 	struct lpfc_vport *vport = cmdiocb->vport;
- 	struct lpfc_dmabuf *inp;
-@@ -809,7 +849,7 @@ lpfc_cmpl_ct_cmd_rft_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+ 	/* ISP ring lock, rings, and indexes */
+@@ -2416,9 +2411,9 @@ typedef struct scsi_qla_host {
+ #define MBX_INTR_WAIT	2
+ #define MBX_UPDATE_FLASH_ACTIVE	3
  
- 	/* RFT request completes status <ulpStatus> CmdRsp <CmdRsp> */
- 	lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
--			 "0209 RFT request completes, latt %d, "
-+			 "0209 CT Request completes, latt %d, "
- 			 "ulpStatus x%x CmdRsp x%x, Context x%x, Tag x%x\n",
- 			 latt, irsp->ulpStatus,
- 			 CTrsp->CommandResponse.bits.CmdRsp,
-@@ -848,10 +888,44 @@ out:
- }
+-	struct semaphore mbx_cmd_sem;	/* Serialialize mbx access */
+ 	struct semaphore vport_sem;	/* Virtual port synchronization */
+-	struct semaphore mbx_intr_sem;  /* Used for completion notification */
++	struct completion mbx_cmd_comp;	/* Serialize mbx access */
++	struct completion mbx_intr_comp;  /* Used for completion notification */
  
- static void
-+lpfc_cmpl_ct_cmd_rft_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
-+			struct lpfc_iocbq *rspiocb)
+ 	uint32_t	mbx_flags;
+ #define  MBX_IN_PROGRESS	BIT_0
+@@ -2455,6 +2450,15 @@ typedef struct scsi_qla_host {
+ 	dma_addr_t	eft_dma;
+ 	void		*eft;
+ 
++	struct dentry *dfs_dir;
++	struct dentry *dfs_fce;
++	dma_addr_t	fce_dma;
++	void		*fce;
++	uint32_t	fce_bufs;
++	uint16_t	fce_mb[8];
++	uint64_t	fce_wr, fce_rd;
++	struct mutex	fce_mutex;
++
+ 	uint8_t		host_str[16];
+ 	uint32_t	pci_attr;
+ 	uint16_t	chip_revision;
+@@ -2507,7 +2511,7 @@ typedef struct scsi_qla_host {
+ 
+ 	struct list_head	vp_list;	/* list of VP */
+ 	struct fc_vport	*fc_vport;	/* holds fc_vport * for each vport */
+-	uint8_t		vp_idx_map[16];
++	unsigned long	vp_idx_map[(MAX_MULTI_ID_FABRIC / 8) / sizeof(unsigned long)];
+ 	uint16_t        num_vhosts;	/* number of vports created */
+ 	uint16_t        num_vsans;	/* number of vsan created */
+ 	uint16_t        vp_idx;		/* vport ID */
+diff --git a/drivers/scsi/qla2xxx/qla_dfs.c b/drivers/scsi/qla2xxx/qla_dfs.c
+new file mode 100644
+index 0000000..1479c60
+--- /dev/null
++++ b/drivers/scsi/qla2xxx/qla_dfs.c
+@@ -0,0 +1,175 @@
++/*
++ * QLogic Fibre Channel HBA Driver
++ * Copyright (c)  2003-2005 QLogic Corporation
++ *
++ * See LICENSE.qla2xxx for copyright and licensing details.
++ */
++#include "qla_def.h"
++
++#include <linux/debugfs.h>
++#include <linux/seq_file.h>
++
++static struct dentry *qla2x00_dfs_root;
++static atomic_t qla2x00_dfs_root_count;
++
++static int
++qla2x00_dfs_fce_show(struct seq_file *s, void *unused)
 +{
-+	IOCB_t *irsp = &rspiocb->iocb;
-+	struct lpfc_vport *vport = cmdiocb->vport;
++	scsi_qla_host_t *ha = s->private;
++	uint32_t cnt;
++	uint32_t *fce;
++	uint64_t fce_start;
 +
-+	if (irsp->ulpStatus == IOSTAT_SUCCESS) {
-+		struct lpfc_dmabuf *outp;
-+		struct lpfc_sli_ct_request *CTrsp;
++	mutex_lock(&ha->fce_mutex);
 +
-+		outp = (struct lpfc_dmabuf *) cmdiocb->context2;
-+		CTrsp = (struct lpfc_sli_ct_request *) outp->virt;
-+		if (CTrsp->CommandResponse.bits.CmdRsp ==
-+		    be16_to_cpu(SLI_CT_RESPONSE_FS_ACC))
-+			vport->ct_flags |= FC_CT_RFT_ID;
++	seq_printf(s, "FCE Trace Buffer\n");
++	seq_printf(s, "In Pointer = %llx\n\n", ha->fce_wr);
++	seq_printf(s, "Base = %llx\n\n", (unsigned long long) ha->fce_dma);
++	seq_printf(s, "FCE Enable Registers\n");
++	seq_printf(s, "%08x %08x %08x %08x %08x %08x\n",
++	    ha->fce_mb[0], ha->fce_mb[2], ha->fce_mb[3], ha->fce_mb[4],
++	    ha->fce_mb[5], ha->fce_mb[6]);
++
++	fce = (uint32_t *) ha->fce;
++	fce_start = (unsigned long long) ha->fce_dma;
++	for (cnt = 0; cnt < fce_calc_size(ha->fce_bufs) / 4; cnt++) {
++		if (cnt % 8 == 0)
++			seq_printf(s, "\n%llx: ",
++			    (unsigned long long)((cnt * 4) + fce_start));
++		else
++			seq_printf(s, " ");
++		seq_printf(s, "%08x", *fce++);
 +	}
-+	lpfc_cmpl_ct(phba, cmdiocb, rspiocb);
-+	return;
++
++	seq_printf(s, "\nEnd\n");
++
++	mutex_unlock(&ha->fce_mutex);
++
++	return 0;
 +}
 +
-+static void
- lpfc_cmpl_ct_cmd_rnn_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
- 			struct lpfc_iocbq *rspiocb)
- {
--	lpfc_cmpl_ct_cmd_rft_id(phba, cmdiocb, rspiocb);
-+	IOCB_t *irsp = &rspiocb->iocb;
-+	struct lpfc_vport *vport = cmdiocb->vport;
++static int
++qla2x00_dfs_fce_open(struct inode *inode, struct file *file)
++{
++	scsi_qla_host_t *ha = inode->i_private;
++	int rval;
 +
-+	if (irsp->ulpStatus == IOSTAT_SUCCESS) {
-+		struct lpfc_dmabuf *outp;
-+		struct lpfc_sli_ct_request *CTrsp;
++	if (!ha->flags.fce_enabled)
++		goto out;
 +
-+		outp = (struct lpfc_dmabuf *) cmdiocb->context2;
-+		CTrsp = (struct lpfc_sli_ct_request *) outp->virt;
-+		if (CTrsp->CommandResponse.bits.CmdRsp ==
-+		    be16_to_cpu(SLI_CT_RESPONSE_FS_ACC))
-+			vport->ct_flags |= FC_CT_RNN_ID;
++	mutex_lock(&ha->fce_mutex);
++
++	/* Pause tracing to flush FCE buffers. */
++	rval = qla2x00_disable_fce_trace(ha, &ha->fce_wr, &ha->fce_rd);
++	if (rval)
++		qla_printk(KERN_WARNING, ha,
++		    "DebugFS: Unable to disable FCE (%d).\n", rval);
++
++	ha->flags.fce_enabled = 0;
++
++	mutex_unlock(&ha->fce_mutex);
++out:
++	return single_open(file, qla2x00_dfs_fce_show, ha);
++}
++
++static int
++qla2x00_dfs_fce_release(struct inode *inode, struct file *file)
++{
++	scsi_qla_host_t *ha = inode->i_private;
++	int rval;
++
++	if (ha->flags.fce_enabled)
++		goto out;
++
++	mutex_lock(&ha->fce_mutex);
++
++	/* Re-enable FCE tracing. */
++	ha->flags.fce_enabled = 1;
++	memset(ha->fce, 0, fce_calc_size(ha->fce_bufs));
++	rval = qla2x00_enable_fce_trace(ha, ha->fce_dma, ha->fce_bufs,
++	    ha->fce_mb, &ha->fce_bufs);
++	if (rval) {
++		qla_printk(KERN_WARNING, ha,
++		    "DebugFS: Unable to reinitialize FCE (%d).\n", rval);
++		ha->flags.fce_enabled = 0;
 +	}
-+	lpfc_cmpl_ct(phba, cmdiocb, rspiocb);
- 	return;
- }
- 
-@@ -859,7 +933,20 @@ static void
- lpfc_cmpl_ct_cmd_rspn_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
- 			 struct lpfc_iocbq *rspiocb)
- {
--	lpfc_cmpl_ct_cmd_rft_id(phba, cmdiocb, rspiocb);
-+	IOCB_t *irsp = &rspiocb->iocb;
-+	struct lpfc_vport *vport = cmdiocb->vport;
 +
-+	if (irsp->ulpStatus == IOSTAT_SUCCESS) {
-+		struct lpfc_dmabuf *outp;
-+		struct lpfc_sli_ct_request *CTrsp;
++	mutex_unlock(&ha->fce_mutex);
++out:
++	return single_release(inode, file);
++}
 +
-+		outp = (struct lpfc_dmabuf *) cmdiocb->context2;
-+		CTrsp = (struct lpfc_sli_ct_request *) outp->virt;
-+		if (CTrsp->CommandResponse.bits.CmdRsp ==
-+		    be16_to_cpu(SLI_CT_RESPONSE_FS_ACC))
-+			vport->ct_flags |= FC_CT_RSPN_ID;
++static const struct file_operations dfs_fce_ops = {
++	.open		= qla2x00_dfs_fce_open,
++	.read		= seq_read,
++	.llseek		= seq_lseek,
++	.release	= qla2x00_dfs_fce_release,
++};
++
++int
++qla2x00_dfs_setup(scsi_qla_host_t *ha)
++{
++	if (!IS_QLA25XX(ha))
++		goto out;
++	if (!ha->fce)
++		goto out;
++
++	if (qla2x00_dfs_root)
++		goto create_dir;
++
++	atomic_set(&qla2x00_dfs_root_count, 0);
++	qla2x00_dfs_root = debugfs_create_dir(QLA2XXX_DRIVER_NAME, NULL);
++	if (!qla2x00_dfs_root) {
++		qla_printk(KERN_NOTICE, ha,
++		    "DebugFS: Unable to create root directory.\n");
++		goto out;
 +	}
-+	lpfc_cmpl_ct(phba, cmdiocb, rspiocb);
- 	return;
- }
- 
-@@ -867,7 +954,32 @@ static void
- lpfc_cmpl_ct_cmd_rsnn_nn(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
- 			 struct lpfc_iocbq *rspiocb)
- {
--	lpfc_cmpl_ct_cmd_rft_id(phba, cmdiocb, rspiocb);
-+	IOCB_t *irsp = &rspiocb->iocb;
-+	struct lpfc_vport *vport = cmdiocb->vport;
 +
-+	if (irsp->ulpStatus == IOSTAT_SUCCESS) {
-+		struct lpfc_dmabuf *outp;
-+		struct lpfc_sli_ct_request *CTrsp;
++create_dir:
++	if (ha->dfs_dir)
++		goto create_nodes;
 +
-+		outp = (struct lpfc_dmabuf *) cmdiocb->context2;
-+		CTrsp = (struct lpfc_sli_ct_request *) outp->virt;
-+		if (CTrsp->CommandResponse.bits.CmdRsp ==
-+		    be16_to_cpu(SLI_CT_RESPONSE_FS_ACC))
-+			vport->ct_flags |= FC_CT_RSNN_NN;
++	mutex_init(&ha->fce_mutex);
++	ha->dfs_dir = debugfs_create_dir(ha->host_str, qla2x00_dfs_root);
++	if (!ha->dfs_dir) {
++		qla_printk(KERN_NOTICE, ha,
++		    "DebugFS: Unable to create ha directory.\n");
++		goto out;
 +	}
-+	lpfc_cmpl_ct(phba, cmdiocb, rspiocb);
-+	return;
++
++	atomic_inc(&qla2x00_dfs_root_count);
++
++create_nodes:
++	ha->dfs_fce = debugfs_create_file("fce", S_IRUSR, ha->dfs_dir, ha,
++	    &dfs_fce_ops);
++	if (!ha->dfs_fce) {
++		qla_printk(KERN_NOTICE, ha,
++		    "DebugFS: Unable to fce node.\n");
++		goto out;
++	}
++out:
++	return 0;
 +}
 +
-+static void
-+lpfc_cmpl_ct_cmd_da_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
-+ struct lpfc_iocbq *rspiocb)
++int
++qla2x00_dfs_remove(scsi_qla_host_t *ha)
 +{
-+	struct lpfc_vport *vport = cmdiocb->vport;
++	if (ha->dfs_fce) {
++		debugfs_remove(ha->dfs_fce);
++		ha->dfs_fce = NULL;
++	}
 +
-+	/* even if it fails we will act as though it succeeded. */
-+	vport->ct_flags = 0;
-+	lpfc_cmpl_ct(phba, cmdiocb, rspiocb);
- 	return;
- }
++	if (ha->dfs_dir) {
++		debugfs_remove(ha->dfs_dir);
++		ha->dfs_dir = NULL;
++		atomic_dec(&qla2x00_dfs_root_count);
++	}
++
++	if (atomic_read(&qla2x00_dfs_root_count) == 0 &&
++	    qla2x00_dfs_root) {
++		debugfs_remove(qla2x00_dfs_root);
++		qla2x00_dfs_root = NULL;
++	}
++
++	return 0;
++}
+diff --git a/drivers/scsi/qla2xxx/qla_fw.h b/drivers/scsi/qla2xxx/qla_fw.h
+index 25364b1..9337e13 100644
+--- a/drivers/scsi/qla2xxx/qla_fw.h
++++ b/drivers/scsi/qla2xxx/qla_fw.h
+@@ -952,9 +952,31 @@ struct device_reg_24xx {
+ 	uint32_t iobase_sdata;
+ };
  
-@@ -878,10 +990,17 @@ lpfc_cmpl_ct_cmd_rff_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
- 	IOCB_t *irsp = &rspiocb->iocb;
- 	struct lpfc_vport *vport = cmdiocb->vport;
++/* Trace Control *************************************************************/
++
++#define TC_AEN_DISABLE		0
++
++#define TC_EFT_ENABLE		4
++#define TC_EFT_DISABLE		5
++
++#define TC_FCE_ENABLE		8
++#define TC_FCE_OPTIONS		0
++#define TC_FCE_DEFAULT_RX_SIZE	2112
++#define TC_FCE_DEFAULT_TX_SIZE	2112
++#define TC_FCE_DISABLE		9
++#define TC_FCE_DISABLE_TRACE	BIT_0
++
+ /* MID Support ***************************************************************/
  
--	if (irsp->ulpStatus != IOSTAT_SUCCESS)
--	    vport->fc_flag |= FC_RFF_NOT_SUPPORTED;
-+	if (irsp->ulpStatus == IOSTAT_SUCCESS) {
-+		struct lpfc_dmabuf *outp;
-+		struct lpfc_sli_ct_request *CTrsp;
+-#define MAX_MID_VPS	125
++#define MIN_MULTI_ID_FABRIC	64	/* Must be power-of-2. */
++#define MAX_MULTI_ID_FABRIC	256	/* ... */
++
++#define for_each_mapped_vp_idx(_ha, _idx)		\
++	for (_idx = find_next_bit((_ha)->vp_idx_map,	\
++		(_ha)->max_npiv_vports + 1, 1);		\
++	    _idx <= (_ha)->max_npiv_vports;		\
++	    _idx = find_next_bit((_ha)->vp_idx_map,	\
++		(_ha)->max_npiv_vports + 1, _idx + 1))	\
  
--	lpfc_cmpl_ct_cmd_rft_id(phba, cmdiocb, rspiocb);
-+		outp = (struct lpfc_dmabuf *) cmdiocb->context2;
-+		CTrsp = (struct lpfc_sli_ct_request *) outp->virt;
-+		if (CTrsp->CommandResponse.bits.CmdRsp ==
-+		    be16_to_cpu(SLI_CT_RESPONSE_FS_ACC))
-+			vport->ct_flags |= FC_CT_RFF_ID;
-+	}
-+	lpfc_cmpl_ct(phba, cmdiocb, rspiocb);
- 	return;
- }
+ struct mid_conf_entry_24xx {
+ 	uint16_t reserved_1;
+@@ -982,7 +1004,7 @@ struct mid_init_cb_24xx {
+ 	uint16_t count;
+ 	uint16_t options;
  
-@@ -1001,6 +1120,8 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode,
- 		bpl->tus.f.bdeSize = RSPN_REQUEST_SZ;
- 	else if (cmdcode == SLI_CTNS_RSNN_NN)
- 		bpl->tus.f.bdeSize = RSNN_REQUEST_SZ;
-+	else if (cmdcode == SLI_CTNS_DA_ID)
-+		bpl->tus.f.bdeSize = DA_ID_REQUEST_SZ;
- 	else if (cmdcode == SLI_CTNS_RFF_ID)
- 		bpl->tus.f.bdeSize = RFF_REQUEST_SZ;
- 	else
-@@ -1029,31 +1150,34 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode,
- 	case SLI_CTNS_GFF_ID:
- 		CtReq->CommandResponse.bits.CmdRsp =
- 			be16_to_cpu(SLI_CTNS_GFF_ID);
--		CtReq->un.gff.PortId = be32_to_cpu(context);
-+		CtReq->un.gff.PortId = cpu_to_be32(context);
- 		cmpl = lpfc_cmpl_ct_cmd_gff_id;
- 		break;
+-	struct mid_conf_entry_24xx entries[MAX_MID_VPS];
++	struct mid_conf_entry_24xx entries[MAX_MULTI_ID_FABRIC];
+ };
  
- 	case SLI_CTNS_RFT_ID:
-+		vport->ct_flags &= ~FC_CT_RFT_ID;
- 		CtReq->CommandResponse.bits.CmdRsp =
- 		    be16_to_cpu(SLI_CTNS_RFT_ID);
--		CtReq->un.rft.PortId = be32_to_cpu(vport->fc_myDID);
-+		CtReq->un.rft.PortId = cpu_to_be32(vport->fc_myDID);
- 		CtReq->un.rft.fcpReg = 1;
- 		cmpl = lpfc_cmpl_ct_cmd_rft_id;
- 		break;
  
- 	case SLI_CTNS_RNN_ID:
-+		vport->ct_flags &= ~FC_CT_RNN_ID;
- 		CtReq->CommandResponse.bits.CmdRsp =
- 		    be16_to_cpu(SLI_CTNS_RNN_ID);
--		CtReq->un.rnn.PortId = be32_to_cpu(vport->fc_myDID);
-+		CtReq->un.rnn.PortId = cpu_to_be32(vport->fc_myDID);
- 		memcpy(CtReq->un.rnn.wwnn,  &vport->fc_nodename,
- 		       sizeof (struct lpfc_name));
- 		cmpl = lpfc_cmpl_ct_cmd_rnn_id;
- 		break;
+@@ -1002,10 +1024,6 @@ struct mid_db_entry_24xx {
+ 	uint8_t reserved_1;
+ };
  
- 	case SLI_CTNS_RSPN_ID:
-+		vport->ct_flags &= ~FC_CT_RSPN_ID;
- 		CtReq->CommandResponse.bits.CmdRsp =
- 		    be16_to_cpu(SLI_CTNS_RSPN_ID);
--		CtReq->un.rspn.PortId = be32_to_cpu(vport->fc_myDID);
-+		CtReq->un.rspn.PortId = cpu_to_be32(vport->fc_myDID);
- 		size = sizeof(CtReq->un.rspn.symbname);
- 		CtReq->un.rspn.len =
- 			lpfc_vport_symbolic_port_name(vport,
-@@ -1061,6 +1185,7 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode,
- 		cmpl = lpfc_cmpl_ct_cmd_rspn_id;
- 		break;
- 	case SLI_CTNS_RSNN_NN:
-+		vport->ct_flags &= ~FC_CT_RSNN_NN;
- 		CtReq->CommandResponse.bits.CmdRsp =
- 		    be16_to_cpu(SLI_CTNS_RSNN_NN);
- 		memcpy(CtReq->un.rsnn.wwnn, &vport->fc_nodename,
-@@ -1071,11 +1196,18 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode,
- 			CtReq->un.rsnn.symbname, size);
- 		cmpl = lpfc_cmpl_ct_cmd_rsnn_nn;
- 		break;
-+	case SLI_CTNS_DA_ID:
-+		/* Implement DA_ID Nameserver request */
-+		CtReq->CommandResponse.bits.CmdRsp =
-+			be16_to_cpu(SLI_CTNS_DA_ID);
-+		CtReq->un.da_id.port_id = cpu_to_be32(vport->fc_myDID);
-+		cmpl = lpfc_cmpl_ct_cmd_da_id;
-+		break;
- 	case SLI_CTNS_RFF_ID:
--		vport->fc_flag &= ~FC_RFF_NOT_SUPPORTED;
-+		vport->ct_flags &= ~FC_CT_RFF_ID;
- 		CtReq->CommandResponse.bits.CmdRsp =
- 		    be16_to_cpu(SLI_CTNS_RFF_ID);
--		CtReq->un.rff.PortId = be32_to_cpu(vport->fc_myDID);;
-+		CtReq->un.rff.PortId = cpu_to_be32(vport->fc_myDID);;
- 		CtReq->un.rff.fbits = FC4_FEATURE_INIT;
- 		CtReq->un.rff.type_code = FC_FCP_DATA;
- 		cmpl = lpfc_cmpl_ct_cmd_rff_id;
-diff --git a/drivers/scsi/lpfc/lpfc_debugfs.c b/drivers/scsi/lpfc/lpfc_debugfs.c
-index d6a98bc..783d1ee 100644
---- a/drivers/scsi/lpfc/lpfc_debugfs.c
-+++ b/drivers/scsi/lpfc/lpfc_debugfs.c
-@@ -43,6 +43,7 @@
- #include "lpfc_crtn.h"
- #include "lpfc_vport.h"
- #include "lpfc_version.h"
-+#include "lpfc_compat.h"
- #include "lpfc_debugfs.h"
+-struct mid_db_24xx {
+-	struct mid_db_entry_24xx entries[MAX_MID_VPS];
+-};
+-
+  /*
+  * Virtual Fabric ID type definition.
+  */
+diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
+index 09cb2a9..ba35fc2 100644
+--- a/drivers/scsi/qla2xxx/qla_gbl.h
++++ b/drivers/scsi/qla2xxx/qla_gbl.h
+@@ -65,33 +65,25 @@ extern int ql2xextended_error_logging;
+ extern int ql2xqfullrampup;
+ extern int num_hosts;
  
- #ifdef CONFIG_LPFC_DEBUG_FS
-@@ -75,18 +76,18 @@ module_param(lpfc_debugfs_enable, int, 0);
- MODULE_PARM_DESC(lpfc_debugfs_enable, "Enable debugfs services");
++extern int qla2x00_loop_reset(scsi_qla_host_t *);
++
+ /*
+  * Global Functions in qla_mid.c source file.
+  */
+-extern struct scsi_host_template qla2x00_driver_template;
+ extern struct scsi_host_template qla24xx_driver_template;
+ extern struct scsi_transport_template *qla2xxx_transport_vport_template;
+-extern uint8_t qla2x00_mem_alloc(scsi_qla_host_t *);
+ extern void qla2x00_timer(scsi_qla_host_t *);
+ extern void qla2x00_start_timer(scsi_qla_host_t *, void *, unsigned long);
+-extern void qla2x00_stop_timer(scsi_qla_host_t *);
+-extern uint32_t qla24xx_allocate_vp_id(scsi_qla_host_t *);
+ extern void qla24xx_deallocate_vp_id(scsi_qla_host_t *);
+ extern int qla24xx_disable_vp (scsi_qla_host_t *);
+ extern int qla24xx_enable_vp (scsi_qla_host_t *);
+-extern void qla2x00_mem_free(scsi_qla_host_t *);
+ extern int qla24xx_control_vp(scsi_qla_host_t *, int );
+ extern int qla24xx_modify_vp_config(scsi_qla_host_t *);
+ extern int qla2x00_send_change_request(scsi_qla_host_t *, uint16_t, uint16_t);
+ extern void qla2x00_vp_stop_timer(scsi_qla_host_t *);
+ extern int qla24xx_configure_vhba (scsi_qla_host_t *);
+-extern int qla24xx_get_vp_entry(scsi_qla_host_t *, uint16_t, int);
+-extern int qla24xx_get_vp_database(scsi_qla_host_t *, uint16_t);
+-extern int qla2x00_do_dpc_vp(scsi_qla_host_t *);
+ extern void qla24xx_report_id_acquisition(scsi_qla_host_t *,
+     struct vp_rpt_id_entry_24xx *);
+-extern scsi_qla_host_t * qla24xx_find_vhost_by_name(scsi_qla_host_t *,
+-    uint8_t *);
+ extern void qla2x00_do_dpc_all_vps(scsi_qla_host_t *);
+ extern int qla24xx_vport_create_req_sanity_check(struct fc_vport *);
+ extern scsi_qla_host_t * qla24xx_create_vhost(struct fc_vport *);
+@@ -103,8 +95,6 @@ extern char *qla2x00_get_fw_version_str(struct scsi_qla_host *, char *);
+ extern void qla2x00_mark_device_lost(scsi_qla_host_t *, fc_port_t *, int, int);
+ extern void qla2x00_mark_all_devices_lost(scsi_qla_host_t *, int);
  
- /* This MUST be a power of 2 */
--static int lpfc_debugfs_max_disc_trc = 0;
-+static int lpfc_debugfs_max_disc_trc;
- module_param(lpfc_debugfs_max_disc_trc, int, 0);
- MODULE_PARM_DESC(lpfc_debugfs_max_disc_trc,
- 	"Set debugfs discovery trace depth");
+-extern int qla2x00_down_timeout(struct semaphore *, unsigned long);
+-
+ extern struct fw_blob *qla2x00_request_firmware(scsi_qla_host_t *);
  
- /* This MUST be a power of 2 */
--static int lpfc_debugfs_max_slow_ring_trc = 0;
-+static int lpfc_debugfs_max_slow_ring_trc;
- module_param(lpfc_debugfs_max_slow_ring_trc, int, 0);
- MODULE_PARM_DESC(lpfc_debugfs_max_slow_ring_trc,
- 	"Set debugfs slow ring trace depth");
+ extern int qla2x00_wait_for_hba_online(scsi_qla_host_t *);
+@@ -113,7 +103,6 @@ extern void qla2xxx_wake_dpc(scsi_qla_host_t *);
+ extern void qla2x00_alert_all_vps(scsi_qla_host_t *, uint16_t *);
+ extern void qla2x00_async_event(scsi_qla_host_t *, uint16_t *);
+ extern void qla2x00_vp_abort_isp(scsi_qla_host_t *);
+-extern int qla24xx_vport_delete(struct fc_vport *);
  
--static int lpfc_debugfs_mask_disc_trc = 0;
-+int lpfc_debugfs_mask_disc_trc;
- module_param(lpfc_debugfs_mask_disc_trc, int, 0);
- MODULE_PARM_DESC(lpfc_debugfs_mask_disc_trc,
- 	"Set debugfs discovery trace mask");
-@@ -100,8 +101,11 @@ MODULE_PARM_DESC(lpfc_debugfs_mask_disc_trc,
- #define LPFC_NODELIST_SIZE 8192
- #define LPFC_NODELIST_ENTRY_SIZE 120
+ /*
+  * Global Function Prototypes in qla_iocb.c source file.
+@@ -222,21 +211,16 @@ extern int
+ qla2x00_get_fcal_position_map(scsi_qla_host_t *ha, char *pos_map);
+ 
+ extern int
+-qla2x00_get_link_status(scsi_qla_host_t *, uint16_t, link_stat_t *,
+-    uint16_t *);
++qla2x00_get_link_status(scsi_qla_host_t *, uint16_t, struct link_statistics *,
++    dma_addr_t);
+ 
+ extern int
+-qla24xx_get_isp_stats(scsi_qla_host_t *, uint32_t *, uint32_t, uint16_t *);
++qla24xx_get_isp_stats(scsi_qla_host_t *, struct link_statistics *,
++    dma_addr_t);
+ 
+ extern int qla24xx_abort_command(scsi_qla_host_t *, srb_t *);
+ extern int qla24xx_abort_target(fc_port_t *);
+ 
+-extern int qla2x00_system_error(scsi_qla_host_t *);
+-
+-extern int
+-qla2x00_get_serdes_params(scsi_qla_host_t *, uint16_t *, uint16_t *,
+-    uint16_t *);
+-
+ extern int
+ qla2x00_set_serdes_params(scsi_qla_host_t *, uint16_t, uint16_t, uint16_t);
+ 
+@@ -244,13 +228,19 @@ extern int
+ qla2x00_stop_firmware(scsi_qla_host_t *);
+ 
+ extern int
+-qla2x00_trace_control(scsi_qla_host_t *, uint16_t, dma_addr_t, uint16_t);
++qla2x00_enable_eft_trace(scsi_qla_host_t *, dma_addr_t, uint16_t);
++extern int
++qla2x00_disable_eft_trace(scsi_qla_host_t *);
+ 
+ extern int
+-qla2x00_read_sfp(scsi_qla_host_t *, dma_addr_t, uint16_t, uint16_t, uint16_t);
++qla2x00_enable_fce_trace(scsi_qla_host_t *, dma_addr_t, uint16_t , uint16_t *,
++    uint32_t *);
+ 
+ extern int
+-qla2x00_get_idma_speed(scsi_qla_host_t *, uint16_t, uint16_t *, uint16_t *);
++qla2x00_disable_fce_trace(scsi_qla_host_t *, uint64_t *, uint64_t *);
++
++extern int
++qla2x00_read_sfp(scsi_qla_host_t *, dma_addr_t, uint16_t, uint16_t, uint16_t);
+ 
+ extern int
+ qla2x00_set_idma_speed(scsi_qla_host_t *, uint16_t, uint16_t, uint16_t *);
+@@ -270,11 +260,7 @@ extern void qla2x00_free_irqs(scsi_qla_host_t *);
+ /*
+  * Global Function Prototypes in qla_sup.c source file.
+  */
+-extern void qla2x00_lock_nvram_access(scsi_qla_host_t *);
+-extern void qla2x00_unlock_nvram_access(scsi_qla_host_t *);
+ extern void qla2x00_release_nvram_protection(scsi_qla_host_t *);
+-extern uint16_t qla2x00_get_nvram_word(scsi_qla_host_t *, uint32_t);
+-extern void qla2x00_write_nvram_word(scsi_qla_host_t *, uint32_t, uint16_t);
+ extern uint32_t *qla24xx_read_flash_data(scsi_qla_host_t *, uint32_t *,
+     uint32_t, uint32_t);
+ extern uint8_t *qla2x00_read_nvram_data(scsi_qla_host_t *, uint8_t *, uint32_t,
+@@ -321,7 +307,6 @@ extern void qla25xx_fw_dump(scsi_qla_host_t *, int);
+ extern void qla2x00_dump_regs(scsi_qla_host_t *);
+ extern void qla2x00_dump_buffer(uint8_t *, uint32_t);
+ extern void qla2x00_print_scsi_cmd(struct scsi_cmnd *);
+-extern void qla2x00_dump_pkt(void *);
  
--/* dumpslim output buffer size */
--#define LPFC_DUMPSLIM_SIZE 4096
-+/* dumpHBASlim output buffer size */
-+#define LPFC_DUMPHBASLIM_SIZE 4096
+ /*
+  * Global Function Prototypes in qla_gs.c source file.
+@@ -356,4 +341,10 @@ extern void qla2x00_free_sysfs_attr(scsi_qla_host_t *);
+ extern void qla2x00_init_host_attr(scsi_qla_host_t *);
+ extern void qla2x00_alloc_sysfs_attr(scsi_qla_host_t *);
+ extern void qla2x00_free_sysfs_attr(scsi_qla_host_t *);
 +
-+/* dumpHostSlim output buffer size */
-+#define LPFC_DUMPHOSTSLIM_SIZE 4096
++/*
++ * Global Function Prototypes in qla_dfs.c source file.
++ */
++extern int qla2x00_dfs_setup(scsi_qla_host_t *);
++extern int qla2x00_dfs_remove(scsi_qla_host_t *);
+ #endif /* _QLA_GBL_H */
+diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
+index 191dafd..d0633ca 100644
+--- a/drivers/scsi/qla2xxx/qla_init.c
++++ b/drivers/scsi/qla2xxx/qla_init.c
+@@ -732,9 +732,9 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *ha)
+ {
+ 	int rval;
+ 	uint32_t dump_size, fixed_size, mem_size, req_q_size, rsp_q_size,
+-	    eft_size;
+-	dma_addr_t eft_dma;
+-	void *eft;
++	    eft_size, fce_size;
++	dma_addr_t tc_dma;
++	void *tc;
  
- /* hbqinfo output buffer size */
- #define LPFC_HBQINFO_SIZE 8192
-@@ -243,16 +247,17 @@ lpfc_debugfs_hbqinfo_data(struct lpfc_hba *phba, char *buf, int size)
- 	raw_index = phba->hbq_get[i];
- 	getidx = le32_to_cpu(raw_index);
- 	len +=  snprintf(buf+len, size-len,
--		"entrys:%d Put:%d nPut:%d localGet:%d hbaGet:%d\n",
--		hbqs->entry_count, hbqs->hbqPutIdx, hbqs->next_hbqPutIdx,
--		hbqs->local_hbqGetIdx, getidx);
-+		"entrys:%d bufcnt:%d Put:%d nPut:%d localGet:%d hbaGet:%d\n",
-+		hbqs->entry_count, hbqs->buffer_count, hbqs->hbqPutIdx,
-+		hbqs->next_hbqPutIdx, hbqs->local_hbqGetIdx, getidx);
+ 	if (ha->fw_dump) {
+ 		qla_printk(KERN_WARNING, ha,
+@@ -743,7 +743,7 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *ha)
+ 	}
  
- 	hbqe = (struct lpfc_hbq_entry *) phba->hbqs[i].hbq_virt;
- 	for (j=0; j<hbqs->entry_count; j++) {
- 		len +=  snprintf(buf+len, size-len,
- 			"%03d: %08x %04x %05x ", j,
--			hbqe->bde.addrLow, hbqe->bde.tus.w, hbqe->buffer_tag);
--
-+			le32_to_cpu(hbqe->bde.addrLow),
-+			le32_to_cpu(hbqe->bde.tus.w),
-+			le32_to_cpu(hbqe->buffer_tag));
- 		i = 0;
- 		found = 0;
+ 	ha->fw_dumped = 0;
+-	fixed_size = mem_size = eft_size = 0;
++	fixed_size = mem_size = eft_size = fce_size = 0;
+ 	if (IS_QLA2100(ha) || IS_QLA2200(ha)) {
+ 		fixed_size = sizeof(struct qla2100_fw_dump);
+ 	} else if (IS_QLA23XX(ha)) {
+@@ -758,21 +758,21 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *ha)
+ 		    sizeof(uint32_t);
  
-@@ -276,7 +281,7 @@ lpfc_debugfs_hbqinfo_data(struct lpfc_hba *phba, char *buf, int size)
- 		list_for_each_entry(d_buf, &hbqs->hbq_buffer_list, list) {
- 			hbq_buf = container_of(d_buf, struct hbq_dmabuf, dbuf);
- 			phys = ((uint64_t)hbq_buf->dbuf.phys & 0xffffffff);
--			if (phys == hbqe->bde.addrLow) {
-+			if (phys == le32_to_cpu(hbqe->bde.addrLow)) {
- 				len +=  snprintf(buf+len, size-len,
- 					"Buf%d: %p %06x\n", i,
- 					hbq_buf->dbuf.virt, hbq_buf->tag);
-@@ -297,18 +302,58 @@ skipit:
- 	return len;
- }
+ 		/* Allocate memory for Extended Trace Buffer. */
+-		eft = dma_alloc_coherent(&ha->pdev->dev, EFT_SIZE, &eft_dma,
++		tc = dma_alloc_coherent(&ha->pdev->dev, EFT_SIZE, &tc_dma,
+ 		    GFP_KERNEL);
+-		if (!eft) {
++		if (!tc) {
+ 			qla_printk(KERN_WARNING, ha, "Unable to allocate "
+ 			    "(%d KB) for EFT.\n", EFT_SIZE / 1024);
+ 			goto cont_alloc;
+ 		}
  
-+static int lpfc_debugfs_last_hba_slim_off;
+-		rval = qla2x00_trace_control(ha, TC_ENABLE, eft_dma,
+-		    EFT_NUM_BUFFERS);
++		memset(tc, 0, EFT_SIZE);
++		rval = qla2x00_enable_eft_trace(ha, tc_dma, EFT_NUM_BUFFERS);
+ 		if (rval) {
+ 			qla_printk(KERN_WARNING, ha, "Unable to initialize "
+ 			    "EFT (%d).\n", rval);
+-			dma_free_coherent(&ha->pdev->dev, EFT_SIZE, eft,
+-			    eft_dma);
++			dma_free_coherent(&ha->pdev->dev, EFT_SIZE, tc,
++			    tc_dma);
+ 			goto cont_alloc;
+ 		}
+ 
+@@ -780,9 +780,40 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *ha)
+ 		    EFT_SIZE / 1024);
+ 
+ 		eft_size = EFT_SIZE;
+-		memset(eft, 0, eft_size);
+-		ha->eft_dma = eft_dma;
+-		ha->eft = eft;
++		ha->eft_dma = tc_dma;
++		ha->eft = tc;
 +
-+static int
-+lpfc_debugfs_dumpHBASlim_data(struct lpfc_hba *phba, char *buf, int size)
-+{
-+	int len = 0;
-+	int i, off;
-+	uint32_t *ptr;
-+	char buffer[1024];
++		/* Allocate memory for Fibre Channel Event Buffer. */
++		if (!IS_QLA25XX(ha))
++			goto cont_alloc;
 +
-+	off = 0;
-+	spin_lock_irq(&phba->hbalock);
++		tc = dma_alloc_coherent(&ha->pdev->dev, FCE_SIZE, &tc_dma,
++		    GFP_KERNEL);
++		if (!tc) {
++			qla_printk(KERN_WARNING, ha, "Unable to allocate "
++			    "(%d KB) for FCE.\n", FCE_SIZE / 1024);
++			goto cont_alloc;
++		}
 +
-+	len +=  snprintf(buf+len, size-len, "HBA SLIM\n");
-+	lpfc_memcpy_from_slim(buffer,
-+		((uint8_t *)phba->MBslimaddr) + lpfc_debugfs_last_hba_slim_off,
-+		1024);
++		memset(tc, 0, FCE_SIZE);
++		rval = qla2x00_enable_fce_trace(ha, tc_dma, FCE_NUM_BUFFERS,
++		    ha->fce_mb, &ha->fce_bufs);
++		if (rval) {
++			qla_printk(KERN_WARNING, ha, "Unable to initialize "
++			    "FCE (%d).\n", rval);
++			dma_free_coherent(&ha->pdev->dev, FCE_SIZE, tc,
++			    tc_dma);
++			ha->flags.fce_enabled = 0;
++			goto cont_alloc;
++		}
 +
-+	ptr = (uint32_t *)&buffer[0];
-+	off = lpfc_debugfs_last_hba_slim_off;
++		qla_printk(KERN_INFO, ha, "Allocated (%d KB) for FCE...\n",
++		    FCE_SIZE / 1024);
 +
-+	/* Set it up for the next time */
-+	lpfc_debugfs_last_hba_slim_off += 1024;
-+	if (lpfc_debugfs_last_hba_slim_off >= 4096)
-+		lpfc_debugfs_last_hba_slim_off = 0;
++		fce_size = sizeof(struct qla2xxx_fce_chain) + EFT_SIZE;
++		ha->flags.fce_enabled = 1;
++		ha->fce_dma = tc_dma;
++		ha->fce = tc;
+ 	}
+ cont_alloc:
+ 	req_q_size = ha->request_q_length * sizeof(request_t);
+@@ -790,7 +821,7 @@ cont_alloc:
+ 
+ 	dump_size = offsetof(struct qla2xxx_fw_dump, isp);
+ 	dump_size += fixed_size + mem_size + req_q_size + rsp_q_size +
+-	    eft_size;
++	    eft_size + fce_size;
+ 
+ 	ha->fw_dump = vmalloc(dump_size);
+ 	if (!ha->fw_dump) {
+@@ -922,9 +953,9 @@ qla2x00_setup_chip(scsi_qla_host_t *ha)
+ 					ha->flags.npiv_supported = 1;
+ 					if ((!ha->max_npiv_vports) ||
+ 					    ((ha->max_npiv_vports + 1) %
+-					    MAX_MULTI_ID_FABRIC))
++					    MIN_MULTI_ID_FABRIC))
+ 						ha->max_npiv_vports =
+-						    MAX_NUM_VPORT_FABRIC;
++						    MIN_MULTI_ID_FABRIC - 1;
+ 				}
+ 
+ 				if (ql2xallocfwdump)
+@@ -1162,7 +1193,10 @@ qla2x00_init_rings(scsi_qla_host_t *ha)
+ 
+ 	DEBUG(printk("scsi(%ld): Issue init firmware.\n", ha->host_no));
+ 
+-	mid_init_cb->count = ha->max_npiv_vports;
++	if (ha->flags.npiv_supported)
++		mid_init_cb->count = cpu_to_le16(ha->max_npiv_vports);
 +
-+	i = 1024;
-+	while (i > 0) {
-+		len +=  snprintf(buf+len, size-len,
-+		"%08x: %08x %08x %08x %08x %08x %08x %08x %08x\n",
-+		off, *ptr, *(ptr+1), *(ptr+2), *(ptr+3), *(ptr+4),
-+		*(ptr+5), *(ptr+6), *(ptr+7));
-+		ptr += 8;
-+		i -= (8 * sizeof(uint32_t));
-+		off += (8 * sizeof(uint32_t));
-+	}
++	mid_init_cb->options = __constant_cpu_to_le16(BIT_1);
+ 
+ 	rval = qla2x00_init_firmware(ha, ha->init_cb_size);
+ 	if (rval) {
+@@ -2566,14 +2600,7 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *ha, struct list_head *new_fcports)
+ 
+ 		/* Bypass virtual ports of the same host. */
+ 		if (pha->num_vhosts) {
+-			vp_index = find_next_bit(
+-			    (unsigned long *)pha->vp_idx_map,
+-			    MAX_MULTI_ID_FABRIC + 1, 1);
+-
+-			for (;vp_index <= MAX_MULTI_ID_FABRIC;
+-			    vp_index = find_next_bit(
+-			    (unsigned long *)pha->vp_idx_map,
+-			    MAX_MULTI_ID_FABRIC + 1, vp_index + 1)) {
++			for_each_mapped_vp_idx(pha, vp_index) {
+ 				empty_vp_index = 1;
+ 				found_vp = 0;
+ 				list_for_each_entry(vha, &pha->vp_list,
+@@ -2592,7 +2619,8 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *ha, struct list_head *new_fcports)
+ 				    new_fcport->d_id.b24 == vha->d_id.b24)
+ 					break;
+ 			}
+-			if (vp_index <= MAX_MULTI_ID_FABRIC)
 +
-+	spin_unlock_irq(&phba->hbalock);
-+	return len;
-+}
++			if (vp_index <= pha->max_npiv_vports)
+ 				continue;
+ 		}
+ 
+@@ -3245,7 +3273,7 @@ qla2x00_abort_isp(scsi_qla_host_t *ha)
+ 			clear_bit(ISP_ABORT_RETRY, &ha->dpc_flags);
+ 
+ 			if (ha->eft) {
+-				rval = qla2x00_trace_control(ha, TC_ENABLE,
++				rval = qla2x00_enable_eft_trace(ha,
+ 				    ha->eft_dma, EFT_NUM_BUFFERS);
+ 				if (rval) {
+ 					qla_printk(KERN_WARNING, ha,
+@@ -3253,6 +3281,21 @@ qla2x00_abort_isp(scsi_qla_host_t *ha)
+ 					    "(%d).\n", rval);
+ 				}
+ 			}
 +
- static int
--lpfc_debugfs_dumpslim_data(struct lpfc_hba *phba, char *buf, int size)
-+lpfc_debugfs_dumpHostSlim_data(struct lpfc_hba *phba, char *buf, int size)
- {
- 	int len = 0;
--	int cnt, i, off;
-+	int i, off;
- 	uint32_t word0, word1, word2, word3;
- 	uint32_t *ptr;
- 	struct lpfc_pgp *pgpp;
- 	struct lpfc_sli *psli = &phba->sli;
- 	struct lpfc_sli_ring *pring;
++			if (ha->fce) {
++				ha->flags.fce_enabled = 1;
++				memset(ha->fce, 0,
++				    fce_calc_size(ha->fce_bufs));
++				rval = qla2x00_enable_fce_trace(ha,
++				    ha->fce_dma, ha->fce_bufs, ha->fce_mb,
++				    &ha->fce_bufs);
++				if (rval) {
++					qla_printk(KERN_WARNING, ha,
++					    "Unable to reinitialize FCE "
++					    "(%d).\n", rval);
++					ha->flags.fce_enabled = 0;
++				}
++			}
+ 		} else {	/* failed the ISP abort */
+ 			ha->flags.online = 1;
+ 			if (test_bit(ISP_ABORT_RETRY, &ha->dpc_flags)) {
+diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
+index 1104bd2..642a0c3 100644
+--- a/drivers/scsi/qla2xxx/qla_isr.c
++++ b/drivers/scsi/qla2xxx/qla_isr.c
+@@ -104,7 +104,7 @@ qla2100_intr_handler(int irq, void *dev_id)
+ 	if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) &&
+ 	    (status & MBX_INTERRUPT) && ha->flags.mbox_int) {
+ 		set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
+-		up(&ha->mbx_intr_sem);
++		complete(&ha->mbx_intr_comp);
+ 	}
  
--	cnt = LPFC_DUMPSLIM_SIZE;
- 	off = 0;
- 	spin_lock_irq(&phba->hbalock);
+ 	return (IRQ_HANDLED);
+@@ -216,7 +216,7 @@ qla2300_intr_handler(int irq, void *dev_id)
+ 	if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) &&
+ 	    (status & MBX_INTERRUPT) && ha->flags.mbox_int) {
+ 		set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
+-		up(&ha->mbx_intr_sem);
++		complete(&ha->mbx_intr_comp);
+ 	}
  
-@@ -620,7 +665,34 @@ out:
+ 	return (IRQ_HANDLED);
+@@ -347,10 +347,6 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
+ 		break;
+ 
+ 	case MBA_SYSTEM_ERR:		/* System Error */
+-		mb[1] = RD_MAILBOX_REG(ha, reg, 1);
+-		mb[2] = RD_MAILBOX_REG(ha, reg, 2);
+-		mb[3] = RD_MAILBOX_REG(ha, reg, 3);
+-
+ 		qla_printk(KERN_INFO, ha,
+ 		    "ISP System Error - mbx1=%xh mbx2=%xh mbx3=%xh.\n",
+ 		    mb[1], mb[2], mb[3]);
+@@ -579,12 +575,15 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
+ 		/* Check if the Vport has issued a SCR */
+ 		if (ha->parent && test_bit(VP_SCR_NEEDED, &ha->vp_flags))
+ 			break;
++		/* Only handle SCNs for our Vport index. */
++		if (ha->flags.npiv_supported && ha->vp_idx != mb[3])
++			break;
+ 
+ 		DEBUG2(printk("scsi(%ld): Asynchronous RSCR UPDATE.\n",
+ 		    ha->host_no));
+ 		DEBUG(printk(KERN_INFO
+-		    "scsi(%ld): RSCN database changed -- %04x %04x.\n",
+-		    ha->host_no, mb[1], mb[2]));
++		    "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];
+ 		host_pid = (ha->d_id.b.domain << 16) | (ha->d_id.b.area << 8) |
+@@ -823,6 +822,35 @@ qla2x00_process_response_queue(struct scsi_qla_host *ha)
+ 	WRT_REG_WORD(ISP_RSP_Q_OUT(ha, reg), ha->rsp_ring_index);
  }
  
- static int
--lpfc_debugfs_dumpslim_open(struct inode *inode, struct file *file)
-+lpfc_debugfs_dumpHBASlim_open(struct inode *inode, struct file *file)
++static inline void
++qla2x00_handle_sense(srb_t *sp, uint8_t *sense_data, uint32_t sense_len)
 +{
-+	struct lpfc_hba *phba = inode->i_private;
-+	struct lpfc_debug *debug;
-+	int rc = -ENOMEM;
-+
-+	debug = kmalloc(sizeof(*debug), GFP_KERNEL);
-+	if (!debug)
-+		goto out;
++	struct scsi_cmnd *cp = sp->cmd;
 +
-+	/* Round to page boundry */
-+	debug->buffer = kmalloc(LPFC_DUMPHBASLIM_SIZE, GFP_KERNEL);
-+	if (!debug->buffer) {
-+		kfree(debug);
-+		goto out;
-+	}
++	if (sense_len >= SCSI_SENSE_BUFFERSIZE)
++		sense_len = SCSI_SENSE_BUFFERSIZE;
 +
-+	debug->len = lpfc_debugfs_dumpHBASlim_data(phba, debug->buffer,
-+		LPFC_DUMPHBASLIM_SIZE);
-+	file->private_data = debug;
++	CMD_ACTUAL_SNSLEN(cp) = sense_len;
++	sp->request_sense_length = sense_len;
++	sp->request_sense_ptr = cp->sense_buffer;
++	if (sp->request_sense_length > 32)
++		sense_len = 32;
 +
-+	rc = 0;
-+out:
-+	return rc;
-+}
++	memcpy(cp->sense_buffer, sense_data, sense_len);
 +
-+static int
-+lpfc_debugfs_dumpHostSlim_open(struct inode *inode, struct file *file)
- {
- 	struct lpfc_hba *phba = inode->i_private;
- 	struct lpfc_debug *debug;
-@@ -631,14 +703,14 @@ lpfc_debugfs_dumpslim_open(struct inode *inode, struct file *file)
- 		goto out;
- 
- 	/* Round to page boundry */
--	debug->buffer = kmalloc(LPFC_DUMPSLIM_SIZE, GFP_KERNEL);
-+	debug->buffer = kmalloc(LPFC_DUMPHOSTSLIM_SIZE, GFP_KERNEL);
- 	if (!debug->buffer) {
- 		kfree(debug);
- 		goto out;
- 	}
- 
--	debug->len = lpfc_debugfs_dumpslim_data(phba, debug->buffer,
--		LPFC_DUMPSLIM_SIZE);
-+	debug->len = lpfc_debugfs_dumpHostSlim_data(phba, debug->buffer,
-+		LPFC_DUMPHOSTSLIM_SIZE);
- 	file->private_data = debug;
- 
- 	rc = 0;
-@@ -741,10 +813,19 @@ static struct file_operations lpfc_debugfs_op_hbqinfo = {
- 	.release =      lpfc_debugfs_release,
- };
- 
--#undef lpfc_debugfs_op_dumpslim
--static struct file_operations lpfc_debugfs_op_dumpslim = {
-+#undef lpfc_debugfs_op_dumpHBASlim
-+static struct file_operations lpfc_debugfs_op_dumpHBASlim = {
-+	.owner =        THIS_MODULE,
-+	.open =         lpfc_debugfs_dumpHBASlim_open,
-+	.llseek =       lpfc_debugfs_lseek,
-+	.read =         lpfc_debugfs_read,
-+	.release =      lpfc_debugfs_release,
-+};
++	sp->request_sense_ptr += sense_len;
++	sp->request_sense_length -= sense_len;
++	if (sp->request_sense_length != 0)
++		sp->ha->status_srb = sp;
 +
-+#undef lpfc_debugfs_op_dumpHostSlim
-+static struct file_operations lpfc_debugfs_op_dumpHostSlim = {
- 	.owner =        THIS_MODULE,
--	.open =         lpfc_debugfs_dumpslim_open,
-+	.open =         lpfc_debugfs_dumpHostSlim_open,
- 	.llseek =       lpfc_debugfs_lseek,
- 	.read =         lpfc_debugfs_read,
- 	.release =      lpfc_debugfs_release,
-@@ -812,15 +893,27 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport)
- 			goto debug_failed;
- 		}
- 
--		/* Setup dumpslim */
--		snprintf(name, sizeof(name), "dumpslim");
--		phba->debug_dumpslim =
-+		/* Setup dumpHBASlim */
-+		snprintf(name, sizeof(name), "dumpHBASlim");
-+		phba->debug_dumpHBASlim =
-+			debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR,
-+				 phba->hba_debugfs_root,
-+				 phba, &lpfc_debugfs_op_dumpHBASlim);
-+		if (!phba->debug_dumpHBASlim) {
-+			lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
-+				"0409 Cannot create debugfs dumpHBASlim\n");
-+			goto debug_failed;
-+		}
++	DEBUG5(printk("%s(): Check condition Sense data, scsi(%ld:%d:%d:%d) "
++	    "cmd=%p pid=%ld\n", __func__, sp->ha->host_no, cp->device->channel,
++	    cp->device->id, cp->device->lun, cp, cp->serial_number));
++	if (sense_len)
++		DEBUG5(qla2x00_dump_buffer(cp->sense_buffer,
++		    CMD_ACTUAL_SNSLEN(cp)));
++}
 +
-+		/* Setup dumpHostSlim */
-+		snprintf(name, sizeof(name), "dumpHostSlim");
-+		phba->debug_dumpHostSlim =
- 			debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR,
- 				 phba->hba_debugfs_root,
--				 phba, &lpfc_debugfs_op_dumpslim);
--		if (!phba->debug_dumpslim) {
-+				 phba, &lpfc_debugfs_op_dumpHostSlim);
-+		if (!phba->debug_dumpHostSlim) {
- 			lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
--				"0409 Cannot create debugfs dumpslim\n");
-+				"0409 Cannot create debugfs dumpHostSlim\n");
- 			goto debug_failed;
- 		}
- 
-@@ -970,9 +1063,13 @@ lpfc_debugfs_terminate(struct lpfc_vport *vport)
- 			debugfs_remove(phba->debug_hbqinfo); /* hbqinfo */
- 			phba->debug_hbqinfo = NULL;
- 		}
--		if (phba->debug_dumpslim) {
--			debugfs_remove(phba->debug_dumpslim); /* dumpslim */
--			phba->debug_dumpslim = NULL;
-+		if (phba->debug_dumpHBASlim) {
-+			debugfs_remove(phba->debug_dumpHBASlim); /* HBASlim */
-+			phba->debug_dumpHBASlim = NULL;
-+		}
-+		if (phba->debug_dumpHostSlim) {
-+			debugfs_remove(phba->debug_dumpHostSlim); /* HostSlim */
-+			phba->debug_dumpHostSlim = NULL;
- 		}
- 		if (phba->slow_ring_trc) {
- 			kfree(phba->slow_ring_trc);
-diff --git a/drivers/scsi/lpfc/lpfc_disc.h b/drivers/scsi/lpfc/lpfc_disc.h
-index aacac9a..cfe81c5 100644
---- a/drivers/scsi/lpfc/lpfc_disc.h
-+++ b/drivers/scsi/lpfc/lpfc_disc.h
-@@ -36,7 +36,6 @@ enum lpfc_work_type {
- 	LPFC_EVT_WARM_START,
- 	LPFC_EVT_KILL,
- 	LPFC_EVT_ELS_RETRY,
--	LPFC_EVT_DEV_LOSS_DELAY,
- 	LPFC_EVT_DEV_LOSS,
- };
+ /**
+  * qla2x00_status_entry() - Process a Status IOCB entry.
+  * @ha: SCSI driver HA context
+@@ -977,36 +1005,11 @@ qla2x00_status_entry(scsi_qla_host_t *ha, void *pkt)
+ 		if (lscsi_status != SS_CHECK_CONDITION)
+ 			break;
  
-@@ -92,6 +91,7 @@ struct lpfc_nodelist {
- #define NLP_LOGO_SND       0x100	/* sent LOGO request for this entry */
- #define NLP_RNID_SND       0x400	/* sent RNID request for this entry */
- #define NLP_ELS_SND_MASK   0x7e0	/* sent ELS request for this entry */
-+#define NLP_DEFER_RM       0x10000	/* Remove this ndlp if no longer used */
- #define NLP_DELAY_TMO      0x20000	/* delay timeout is running for node */
- #define NLP_NPR_2B_DISC    0x40000	/* node is included in num_disc_nodes */
- #define NLP_RCV_PLOGI      0x80000	/* Rcv'ed PLOGI from remote system */
-diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c
-index 8085900..c6b739d 100644
---- a/drivers/scsi/lpfc/lpfc_els.c
-+++ b/drivers/scsi/lpfc/lpfc_els.c
-@@ -18,7 +18,7 @@
-  * more details, a copy of which can be found in the file COPYING  *
-  * included with this package.                                     *
-  *******************************************************************/
+-		/* Copy Sense Data into sense buffer. */
+-		memset(cp->sense_buffer, 0, sizeof(cp->sense_buffer));
 -
-+/* See Fibre Channel protocol T11 FC-LS for details */
- #include <linux/blkdev.h>
- #include <linux/pci.h>
- #include <linux/interrupt.h>
-@@ -42,6 +42,14 @@ static int lpfc_els_retry(struct lpfc_hba *, struct lpfc_iocbq *,
- 			  struct lpfc_iocbq *);
- static void lpfc_cmpl_fabric_iocb(struct lpfc_hba *, struct lpfc_iocbq *,
- 			struct lpfc_iocbq *);
-+static void lpfc_fabric_abort_vport(struct lpfc_vport *vport);
-+static int lpfc_issue_els_fdisc(struct lpfc_vport *vport,
-+				struct lpfc_nodelist *ndlp, uint8_t retry);
-+static int lpfc_issue_fabric_iocb(struct lpfc_hba *phba,
-+				  struct lpfc_iocbq *iocb);
-+static void lpfc_register_new_vport(struct lpfc_hba *phba,
-+				    struct lpfc_vport *vport,
-+				    struct lpfc_nodelist *ndlp);
++		memset(cp->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
+ 		if (!(scsi_status & SS_SENSE_LEN_VALID))
+ 			break;
  
- static int lpfc_max_els_tries = 3;
+-		if (sense_len >= sizeof(cp->sense_buffer))
+-			sense_len = sizeof(cp->sense_buffer);
+-
+-		CMD_ACTUAL_SNSLEN(cp) = sense_len;
+-		sp->request_sense_length = sense_len;
+-		sp->request_sense_ptr = cp->sense_buffer;
+-
+-		if (sp->request_sense_length > 32)
+-			sense_len = 32;
+-
+-		memcpy(cp->sense_buffer, sense_data, sense_len);
+-
+-		sp->request_sense_ptr += sense_len;
+-		sp->request_sense_length -= sense_len;
+-		if (sp->request_sense_length != 0)
+-			ha->status_srb = sp;
+-
+-		DEBUG5(printk("%s(): Check condition Sense data, "
+-		    "scsi(%ld:%d:%d:%d) cmd=%p pid=%ld\n", __func__,
+-		    ha->host_no, cp->device->channel, cp->device->id,
+-		    cp->device->lun, cp, cp->serial_number));
+-		if (sense_len)
+-			DEBUG5(qla2x00_dump_buffer(cp->sense_buffer,
+-			    CMD_ACTUAL_SNSLEN(cp)));
++		qla2x00_handle_sense(sp, sense_data, sense_len);
+ 		break;
  
-@@ -109,14 +117,11 @@ lpfc_prep_els_iocb(struct lpfc_vport *vport, uint8_t expectRsp,
+ 	case CS_DATA_UNDERRUN:
+@@ -1061,34 +1064,11 @@ qla2x00_status_entry(scsi_qla_host_t *ha, void *pkt)
+ 			if (lscsi_status != SS_CHECK_CONDITION)
+ 				break;
  
- 	/* fill in BDEs for command */
- 	/* Allocate buffer for command payload */
--	if (((pcmd = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL)) == 0) ||
--	    ((pcmd->virt = lpfc_mbuf_alloc(phba,
--					   MEM_PRI, &(pcmd->phys))) == 0)) {
--		kfree(pcmd);
+-			/* Copy Sense Data into sense buffer */
+-			memset(cp->sense_buffer, 0, sizeof(cp->sense_buffer));
 -
--		lpfc_sli_release_iocbq(phba, elsiocb);
--		return NULL;
--	}
-+	pcmd = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
-+	if (pcmd)
-+		pcmd->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &pcmd->phys);
-+	if (!pcmd || !pcmd->virt)
-+		goto els_iocb_free_pcmb_exit;
++			memset(cp->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
+ 			if (!(scsi_status & SS_SENSE_LEN_VALID))
+ 				break;
  
- 	INIT_LIST_HEAD(&pcmd->list);
+-			if (sense_len >= sizeof(cp->sense_buffer))
+-				sense_len = sizeof(cp->sense_buffer);
+-
+-			CMD_ACTUAL_SNSLEN(cp) = sense_len;
+-			sp->request_sense_length = sense_len;
+-			sp->request_sense_ptr = cp->sense_buffer;
+-
+-			if (sp->request_sense_length > 32)
+-				sense_len = 32;
+-
+-			memcpy(cp->sense_buffer, sense_data, sense_len);
+-
+-			sp->request_sense_ptr += sense_len;
+-			sp->request_sense_length -= sense_len;
+-			if (sp->request_sense_length != 0)
+-				ha->status_srb = sp;
+-
+-			DEBUG5(printk("%s(): Check condition Sense data, "
+-			    "scsi(%ld:%d:%d:%d) cmd=%p pid=%ld\n",
+-			    __func__, ha->host_no, cp->device->channel,
+-			    cp->device->id, cp->device->lun, cp,
+-			    cp->serial_number));
++			qla2x00_handle_sense(sp, sense_data, sense_len);
  
-@@ -126,13 +131,8 @@ lpfc_prep_els_iocb(struct lpfc_vport *vport, uint8_t expectRsp,
- 		if (prsp)
- 			prsp->virt = lpfc_mbuf_alloc(phba, MEM_PRI,
- 						     &prsp->phys);
--		if (prsp == 0 || prsp->virt == 0) {
--			kfree(prsp);
--			lpfc_mbuf_free(phba, pcmd->virt, pcmd->phys);
--			kfree(pcmd);
--			lpfc_sli_release_iocbq(phba, elsiocb);
--			return NULL;
--		}
-+		if (!prsp || !prsp->virt)
-+			goto els_iocb_free_prsp_exit;
- 		INIT_LIST_HEAD(&prsp->list);
- 	} else {
- 		prsp = NULL;
-@@ -143,15 +143,8 @@ lpfc_prep_els_iocb(struct lpfc_vport *vport, uint8_t expectRsp,
- 	if (pbuflist)
- 		pbuflist->virt = lpfc_mbuf_alloc(phba, MEM_PRI,
- 						 &pbuflist->phys);
--	if (pbuflist == 0 || pbuflist->virt == 0) {
--		lpfc_sli_release_iocbq(phba, elsiocb);
--		lpfc_mbuf_free(phba, pcmd->virt, pcmd->phys);
--		lpfc_mbuf_free(phba, prsp->virt, prsp->phys);
--		kfree(pcmd);
--		kfree(prsp);
--		kfree(pbuflist);
--		return NULL;
--	}
-+	if (!pbuflist || !pbuflist->virt)
-+		goto els_iocb_free_pbuf_exit;
+ 			/*
+ 			 * In case of a Underrun condition, set both the lscsi
+@@ -1108,10 +1088,6 @@ qla2x00_status_entry(scsi_qla_host_t *ha, void *pkt)
  
- 	INIT_LIST_HEAD(&pbuflist->list);
+ 				cp->result = DID_ERROR << 16 | lscsi_status;
+ 			}
+-
+-			if (sense_len)
+-				DEBUG5(qla2x00_dump_buffer(cp->sense_buffer,
+-				    CMD_ACTUAL_SNSLEN(cp)));
+ 		} else {
+ 			/*
+ 			 * If RISC reports underrun and target does not report
+@@ -1621,7 +1597,7 @@ qla24xx_intr_handler(int irq, void *dev_id)
+ 	if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) &&
+ 	    (status & MBX_INTERRUPT) && ha->flags.mbox_int) {
+ 		set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
+-		up(&ha->mbx_intr_sem);
++		complete(&ha->mbx_intr_comp);
+ 	}
  
-@@ -196,7 +189,10 @@ lpfc_prep_els_iocb(struct lpfc_vport *vport, uint8_t expectRsp,
- 		bpl->tus.w = le32_to_cpu(bpl->tus.w);
+ 	return IRQ_HANDLED;
+@@ -1758,7 +1734,7 @@ qla24xx_msix_default(int irq, void *dev_id)
+ 	if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) &&
+ 	    (status & MBX_INTERRUPT) && ha->flags.mbox_int) {
+ 		set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
+-		up(&ha->mbx_intr_sem);
++		complete(&ha->mbx_intr_comp);
  	}
  
-+	/* prevent preparing iocb with NULL ndlp reference */
- 	elsiocb->context1 = lpfc_nlp_get(ndlp);
-+	if (!elsiocb->context1)
-+		goto els_iocb_free_pbuf_exit;
- 	elsiocb->context2 = pcmd;
- 	elsiocb->context3 = pbuflist;
- 	elsiocb->retry = retry;
-@@ -222,8 +218,20 @@ lpfc_prep_els_iocb(struct lpfc_vport *vport, uint8_t expectRsp,
- 				 cmdSize);
+ 	return IRQ_HANDLED;
+@@ -1853,6 +1829,18 @@ qla2x00_request_irqs(scsi_qla_host_t *ha)
+ 		goto skip_msix;
  	}
- 	return elsiocb;
--}
  
-+els_iocb_free_pbuf_exit:
-+	lpfc_mbuf_free(phba, prsp->virt, prsp->phys);
-+	kfree(pbuflist);
++	if (ha->pdev->subsystem_vendor == PCI_VENDOR_ID_HP &&
++	    (ha->pdev->subsystem_device == 0x7040 ||
++		ha->pdev->subsystem_device == 0x7041 ||
++		ha->pdev->subsystem_device == 0x1705)) {
++		DEBUG2(qla_printk(KERN_WARNING, ha,
++		    "MSI-X: Unsupported ISP2432 SSVID/SSDID (0x%X, 0x%X).\n",
++		    ha->pdev->subsystem_vendor,
++		    ha->pdev->subsystem_device));
 +
-+els_iocb_free_prsp_exit:
-+	lpfc_mbuf_free(phba, pcmd->virt, pcmd->phys);
-+	kfree(prsp);
++		goto skip_msi;
++	}
 +
-+els_iocb_free_pcmb_exit:
-+	kfree(pcmd);
-+	lpfc_sli_release_iocbq(phba, elsiocb);
-+	return NULL;
-+}
+ 	ret = qla24xx_enable_msix(ha);
+ 	if (!ret) {
+ 		DEBUG2(qla_printk(KERN_INFO, ha,
+diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
+index ccd662a..0c10c0b 100644
+--- a/drivers/scsi/qla2xxx/qla_mbx.c
++++ b/drivers/scsi/qla2xxx/qla_mbx.c
+@@ -8,19 +8,6 @@
  
- static int
- lpfc_issue_fabric_reglogin(struct lpfc_vport *vport)
-@@ -234,40 +242,53 @@ lpfc_issue_fabric_reglogin(struct lpfc_vport *vport)
- 	struct lpfc_nodelist *ndlp;
- 	struct serv_parm *sp;
- 	int rc;
-+	int err = 0;
+ #include <linux/delay.h>
  
- 	sp = &phba->fc_fabparam;
- 	ndlp = lpfc_findnode_did(vport, Fabric_DID);
--	if (!ndlp)
-+	if (!ndlp) {
-+		err = 1;
- 		goto fail;
-+	}
+-static void
+-qla2x00_mbx_sem_timeout(unsigned long data)
+-{
+-	struct semaphore	*sem_ptr = (struct semaphore *)data;
+-
+-	DEBUG11(printk("qla2x00_sem_timeout: entered.\n"));
+-
+-	if (sem_ptr != NULL) {
+-		up(sem_ptr);
+-	}
+-
+-	DEBUG11(printk("qla2x00_mbx_sem_timeout: exiting.\n"));
+-}
  
- 	mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
--	if (!mbox)
-+	if (!mbox) {
-+		err = 2;
- 		goto fail;
-+	}
+ /*
+  * qla2x00_mailbox_command
+@@ -47,7 +34,6 @@ qla2x00_mailbox_command(scsi_qla_host_t *pvha, mbx_cmd_t *mcp)
+ 	int		rval;
+ 	unsigned long    flags = 0;
+ 	device_reg_t __iomem *reg;
+-	struct timer_list	tmp_intr_timer;
+ 	uint8_t		abort_active;
+ 	uint8_t		io_lock_on;
+ 	uint16_t	command;
+@@ -72,7 +58,8 @@ qla2x00_mailbox_command(scsi_qla_host_t *pvha, mbx_cmd_t *mcp)
+ 	 * non ISP abort time.
+ 	 */
+ 	if (!abort_active) {
+-		if (qla2x00_down_timeout(&ha->mbx_cmd_sem, mcp->tov * HZ)) {
++		if (!wait_for_completion_timeout(&ha->mbx_cmd_comp,
++		    mcp->tov * HZ)) {
+ 			/* Timeout occurred. Return error. */
+ 			DEBUG2_3_11(printk("%s(%ld): cmd access timeout. "
+ 			    "Exiting.\n", __func__, ha->host_no));
+@@ -135,22 +122,6 @@ qla2x00_mailbox_command(scsi_qla_host_t *pvha, mbx_cmd_t *mcp)
+ 	/* Wait for mbx cmd completion until timeout */
  
- 	vport->port_state = LPFC_FABRIC_CFG_LINK;
- 	lpfc_config_link(phba, mbox);
- 	mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
- 	mbox->vport = vport;
+ 	if (!abort_active && io_lock_on) {
+-		/* sleep on completion semaphore */
+-		DEBUG11(printk("%s(%ld): INTERRUPT MODE. Initializing timer.\n",
+-		    __func__, ha->host_no));
+-
+-		init_timer(&tmp_intr_timer);
+-		tmp_intr_timer.data = (unsigned long)&ha->mbx_intr_sem;
+-		tmp_intr_timer.expires = jiffies + mcp->tov * HZ;
+-		tmp_intr_timer.function =
+-		    (void (*)(unsigned long))qla2x00_mbx_sem_timeout;
+-
+-		DEBUG11(printk("%s(%ld): Adding timer.\n", __func__,
+-		    ha->host_no));
+-		add_timer(&tmp_intr_timer);
+-
+-		DEBUG11(printk("%s(%ld): going to unlock & sleep. "
+-		    "time=0x%lx.\n", __func__, ha->host_no, jiffies));
  
--	rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT | MBX_STOP_IOCB);
--	if (rc == MBX_NOT_FINISHED)
-+	rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
-+	if (rc == MBX_NOT_FINISHED) {
-+		err = 3;
- 		goto fail_free_mbox;
-+	}
+ 		set_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags);
  
- 	mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
--	if (!mbox)
-+	if (!mbox) {
-+		err = 4;
- 		goto fail;
-+	}
- 	rc = lpfc_reg_login(phba, vport->vpi, Fabric_DID, (uint8_t *)sp, mbox,
- 			    0);
--	if (rc)
-+	if (rc) {
-+		err = 5;
- 		goto fail_free_mbox;
-+	}
+@@ -160,17 +131,10 @@ qla2x00_mailbox_command(scsi_qla_host_t *pvha, mbx_cmd_t *mcp)
+ 			WRT_REG_WORD(&reg->isp.hccr, HCCR_SET_HOST_INT);
+ 		spin_unlock_irqrestore(&ha->hardware_lock, flags);
  
- 	mbox->mbox_cmpl = lpfc_mbx_cmpl_fabric_reg_login;
- 	mbox->vport = vport;
- 	mbox->context2 = lpfc_nlp_get(ndlp);
+-		/* Wait for either the timer to expire
+-		 * or the mbox completion interrupt
+-		 */
+-		down(&ha->mbx_intr_sem);
++		wait_for_completion_timeout(&ha->mbx_intr_comp, mcp->tov * HZ);
  
--	rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT | MBX_STOP_IOCB);
--	if (rc == MBX_NOT_FINISHED)
-+	rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
-+	if (rc == MBX_NOT_FINISHED) {
-+		err = 6;
- 		goto fail_issue_reg_login;
-+	}
+-		DEBUG11(printk("%s(%ld): waking up. time=0x%lx\n", __func__,
+-		    ha->host_no, jiffies));
+ 		clear_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags);
  
- 	return 0;
+-		/* delete the timer */
+-		del_timer(&tmp_intr_timer);
+ 	} else {
+ 		DEBUG3_11(printk("%s(%ld): cmd=%x POLLING MODE.\n", __func__,
+ 		    ha->host_no, command));
+@@ -299,7 +263,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *pvha, mbx_cmd_t *mcp)
  
-@@ -282,7 +303,7 @@ fail_free_mbox:
- fail:
- 	lpfc_vport_set_state(vport, FC_VPORT_FAILED);
- 	lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
--		"0249 Cannot issue Register Fabric login\n");
-+		"0249 Cannot issue Register Fabric login: Err %d\n", err);
- 	return -ENXIO;
- }
+ 	/* Allow next mbx cmd to come in. */
+ 	if (!abort_active)
+-		up(&ha->mbx_cmd_sem);
++		complete(&ha->mbx_cmd_comp);
  
-@@ -370,11 +391,12 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
- 		}
- 		if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) {
- 			lpfc_mbx_unreg_vpi(vport);
-+			spin_lock_irq(shost->host_lock);
- 			vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
-+			spin_unlock_irq(shost->host_lock);
- 		}
- 	}
+ 	if (rval) {
+ 		DEBUG2_3_11(printk("%s(%ld): **** FAILED. mbx0=%x, mbx1=%x, "
+@@ -905,7 +869,7 @@ qla2x00_get_adapter_id(scsi_qla_host_t *ha, uint16_t *id, uint8_t *al_pa,
  
--	ndlp->nlp_sid = irsp->un.ulpWord[4] & Mask_DID;
- 	lpfc_nlp_set_state(vport, ndlp, NLP_STE_REG_LOGIN_ISSUE);
+ 	mcp->mb[0] = MBC_GET_ADAPTER_LOOP_ID;
+ 	mcp->mb[9] = ha->vp_idx;
+-	mcp->out_mb = MBX_0;
++	mcp->out_mb = MBX_9|MBX_0;
+ 	mcp->in_mb = MBX_9|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0;
+ 	mcp->tov = 30;
+ 	mcp->flags = 0;
+@@ -1016,7 +980,7 @@ qla2x00_init_firmware(scsi_qla_host_t *ha, uint16_t size)
+ 	DEBUG11(printk("qla2x00_init_firmware(%ld): entered.\n",
+ 	    ha->host_no));
  
- 	if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED &&
-@@ -429,8 +451,7 @@ lpfc_cmpl_els_flogi_nport(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+-	if (ha->flags.npiv_supported)
++	if (ha->fw_attributes & BIT_2)
+ 		mcp->mb[0] = MBC_MID_INITIALIZE_FIRMWARE;
+ 	else
+ 		mcp->mb[0] = MBC_INITIALIZE_FIRMWARE;
+@@ -2042,29 +2006,20 @@ qla2x00_get_fcal_position_map(scsi_qla_host_t *ha, char *pos_map)
+  */
+ int
+ qla2x00_get_link_status(scsi_qla_host_t *ha, uint16_t loop_id,
+-    link_stat_t *ret_buf, uint16_t *status)
++    struct link_statistics *stats, dma_addr_t stats_dma)
+ {
+ 	int rval;
+ 	mbx_cmd_t mc;
+ 	mbx_cmd_t *mcp = &mc;
+-	link_stat_t *stat_buf;
+-	dma_addr_t stat_buf_dma;
++	uint32_t *siter, *diter, dwords;
  
- 		mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
- 		mbox->vport = vport;
--		rc = lpfc_sli_issue_mbox(phba, mbox,
--					 MBX_NOWAIT | MBX_STOP_IOCB);
-+		rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
- 		if (rc == MBX_NOT_FINISHED) {
- 			mempool_free(mbox, phba->mbox_mem_pool);
- 			goto fail;
-@@ -463,6 +484,9 @@ lpfc_cmpl_els_flogi_nport(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
- 		lpfc_nlp_put(ndlp);
+ 	DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
+ 
+-	stat_buf = dma_pool_alloc(ha->s_dma_pool, GFP_ATOMIC, &stat_buf_dma);
+-	if (stat_buf == NULL) {
+-		DEBUG2_3_11(printk("%s(%ld): Failed to allocate memory.\n",
+-		    __func__, ha->host_no));
+-		return BIT_0;
+-	}
+-	memset(stat_buf, 0, sizeof(link_stat_t));
+-
+ 	mcp->mb[0] = MBC_GET_LINK_STATUS;
+-	mcp->mb[2] = MSW(stat_buf_dma);
+-	mcp->mb[3] = LSW(stat_buf_dma);
+-	mcp->mb[6] = MSW(MSD(stat_buf_dma));
+-	mcp->mb[7] = LSW(MSD(stat_buf_dma));
++	mcp->mb[2] = MSW(stats_dma);
++	mcp->mb[3] = LSW(stats_dma);
++	mcp->mb[6] = MSW(MSD(stats_dma));
++	mcp->mb[7] = LSW(MSD(stats_dma));
+ 	mcp->out_mb = MBX_7|MBX_6|MBX_3|MBX_2|MBX_0;
+ 	mcp->in_mb = MBX_0;
+ 	if (IS_FWI2_CAPABLE(ha)) {
+@@ -2089,78 +2044,43 @@ qla2x00_get_link_status(scsi_qla_host_t *ha, uint16_t loop_id,
+ 		if (mcp->mb[0] != MBS_COMMAND_COMPLETE) {
+ 			DEBUG2_3_11(printk("%s(%ld): cmd failed. mbx0=%x.\n",
+ 			    __func__, ha->host_no, mcp->mb[0]));
+-			status[0] = mcp->mb[0];
+-			rval = BIT_1;
++			rval = QLA_FUNCTION_FAILED;
+ 		} else {
+-			/* copy over data -- firmware data is LE. */
+-			ret_buf->link_fail_cnt =
+-			    le32_to_cpu(stat_buf->link_fail_cnt);
+-			ret_buf->loss_sync_cnt =
+-			    le32_to_cpu(stat_buf->loss_sync_cnt);
+-			ret_buf->loss_sig_cnt =
+-			    le32_to_cpu(stat_buf->loss_sig_cnt);
+-			ret_buf->prim_seq_err_cnt =
+-			    le32_to_cpu(stat_buf->prim_seq_err_cnt);
+-			ret_buf->inval_xmit_word_cnt =
+-			    le32_to_cpu(stat_buf->inval_xmit_word_cnt);
+-			ret_buf->inval_crc_cnt =
+-			    le32_to_cpu(stat_buf->inval_crc_cnt);
+-
+-			DEBUG11(printk("%s(%ld): stat dump: fail_cnt=%d "
+-			    "loss_sync=%d loss_sig=%d seq_err=%d "
+-			    "inval_xmt_word=%d inval_crc=%d.\n", __func__,
+-			    ha->host_no, stat_buf->link_fail_cnt,
+-			    stat_buf->loss_sync_cnt, stat_buf->loss_sig_cnt,
+-			    stat_buf->prim_seq_err_cnt,
+-			    stat_buf->inval_xmit_word_cnt,
+-			    stat_buf->inval_crc_cnt));
++			/* Copy over data -- firmware data is LE. */
++			dwords = offsetof(struct link_statistics, unused1) / 4;
++			siter = diter = &stats->link_fail_cnt;
++			while (dwords--)
++				*diter++ = le32_to_cpu(*siter++);
+ 		}
+ 	} else {
+ 		/* Failed. */
+ 		DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", __func__,
+ 		    ha->host_no, rval));
+-		rval = BIT_1;
  	}
  
-+	/* If we are pt2pt with another NPort, force NPIV off! */
-+	phba->sli3_options &= ~LPFC_SLI3_NPIV_ENABLED;
-+
- 	spin_lock_irq(shost->host_lock);
- 	vport->fc_flag |= FC_PT2PT;
- 	spin_unlock_irq(shost->host_lock);
-@@ -488,6 +512,9 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+-	dma_pool_free(ha->s_dma_pool, stat_buf, stat_buf_dma);
+-
+ 	return rval;
+ }
  
- 	/* Check to see if link went down during discovery */
- 	if (lpfc_els_chk_latt(vport)) {
-+		/* One additional decrement on node reference count to
-+		 * trigger the release of the node
-+		 */
- 		lpfc_nlp_put(ndlp);
- 		goto out;
+ int
+-qla24xx_get_isp_stats(scsi_qla_host_t *ha, uint32_t *dwbuf, uint32_t dwords,
+-    uint16_t *status)
++qla24xx_get_isp_stats(scsi_qla_host_t *ha, struct link_statistics *stats,
++    dma_addr_t stats_dma)
+ {
+ 	int rval;
+ 	mbx_cmd_t mc;
+ 	mbx_cmd_t *mcp = &mc;
+-	uint32_t *sbuf, *siter;
+-	dma_addr_t sbuf_dma;
++	uint32_t *siter, *diter, dwords;
+ 
+ 	DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
+ 
+-	if (dwords > (DMA_POOL_SIZE / 4)) {
+-		DEBUG2_3_11(printk("%s(%ld): Unabled to retrieve %d DWORDs "
+-		    "(max %d).\n", __func__, ha->host_no, dwords,
+-		    DMA_POOL_SIZE / 4));
+-		return BIT_0;
+-	}
+-	sbuf = dma_pool_alloc(ha->s_dma_pool, GFP_ATOMIC, &sbuf_dma);
+-	if (sbuf == NULL) {
+-		DEBUG2_3_11(printk("%s(%ld): Failed to allocate memory.\n",
+-		    __func__, ha->host_no));
+-		return BIT_0;
+-	}
+-	memset(sbuf, 0, DMA_POOL_SIZE);
+-
+ 	mcp->mb[0] = MBC_GET_LINK_PRIV_STATS;
+-	mcp->mb[2] = MSW(sbuf_dma);
+-	mcp->mb[3] = LSW(sbuf_dma);
+-	mcp->mb[6] = MSW(MSD(sbuf_dma));
+-	mcp->mb[7] = LSW(MSD(sbuf_dma));
+-	mcp->mb[8] = dwords;
++	mcp->mb[2] = MSW(stats_dma);
++	mcp->mb[3] = LSW(stats_dma);
++	mcp->mb[6] = MSW(MSD(stats_dma));
++	mcp->mb[7] = LSW(MSD(stats_dma));
++	mcp->mb[8] = sizeof(struct link_statistics) / 4;
++	mcp->mb[9] = ha->vp_idx;
+ 	mcp->mb[10] = 0;
+-	mcp->out_mb = MBX_10|MBX_8|MBX_7|MBX_6|MBX_3|MBX_2|MBX_0;
++	mcp->out_mb = MBX_10|MBX_9|MBX_8|MBX_7|MBX_6|MBX_3|MBX_2|MBX_0;
+ 	mcp->in_mb = MBX_2|MBX_1|MBX_0;
+ 	mcp->tov = 30;
+ 	mcp->flags = IOCTL_CMD;
+@@ -2170,23 +2090,20 @@ qla24xx_get_isp_stats(scsi_qla_host_t *ha, uint32_t *dwbuf, uint32_t dwords,
+ 		if (mcp->mb[0] != MBS_COMMAND_COMPLETE) {
+ 			DEBUG2_3_11(printk("%s(%ld): cmd failed. mbx0=%x.\n",
+ 			    __func__, ha->host_no, mcp->mb[0]));
+-			status[0] = mcp->mb[0];
+-			rval = BIT_1;
++			rval = QLA_FUNCTION_FAILED;
+ 		} else {
+ 			/* Copy over data -- firmware data is LE. */
+-			siter = sbuf;
++			dwords = sizeof(struct link_statistics) / 4;
++			siter = diter = &stats->link_fail_cnt;
+ 			while (dwords--)
+-				*dwbuf++ = le32_to_cpu(*siter++);
++				*diter++ = le32_to_cpu(*siter++);
+ 		}
+ 	} else {
+ 		/* Failed. */
+ 		DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", __func__,
+ 		    ha->host_no, rval));
+-		rval = BIT_1;
  	}
-@@ -562,8 +589,13 @@ flogifail:
  
- 		/* Start discovery */
- 		lpfc_disc_start(vport);
-+	} else if (((irsp->ulpStatus != IOSTAT_LOCAL_REJECT) ||
-+			((irsp->un.ulpWord[4] != IOERR_SLI_ABORTED) &&
-+			(irsp->un.ulpWord[4] != IOERR_SLI_DOWN))) &&
-+			(phba->link_state != LPFC_CLEAR_LA)) {
-+		/* If FLOGI failed enable link interrupt. */
-+		lpfc_issue_clear_la(phba, vport);
- 	}
+-	dma_pool_free(ha->s_dma_pool, sbuf, sbuf_dma);
 -
- out:
- 	lpfc_els_free_iocb(phba, cmdiocb);
+ 	return rval;
  }
-@@ -685,6 +717,9 @@ lpfc_initial_flogi(struct lpfc_vport *vport)
- 	struct lpfc_hba *phba = vport->phba;
- 	struct lpfc_nodelist *ndlp;
  
-+	vport->port_state = LPFC_FLOGI;
-+	lpfc_set_disctmo(vport);
-+
- 	/* First look for the Fabric ndlp */
- 	ndlp = lpfc_findnode_did(vport, Fabric_DID);
- 	if (!ndlp) {
-@@ -696,7 +731,11 @@ lpfc_initial_flogi(struct lpfc_vport *vport)
- 	} else {
- 		lpfc_dequeue_node(vport, ndlp);
- 	}
-+
- 	if (lpfc_issue_els_flogi(vport, ndlp, 0)) {
-+		/* This decrement of reference count to node shall kick off
-+		 * the release of the node.
-+		 */
- 		lpfc_nlp_put(ndlp);
- 	}
- 	return 1;
-@@ -720,11 +759,16 @@ lpfc_initial_fdisc(struct lpfc_vport *vport)
- 		lpfc_dequeue_node(vport, ndlp);
- 	}
- 	if (lpfc_issue_els_fdisc(vport, ndlp, 0)) {
-+		/* decrement node reference count to trigger the release of
-+		 * the node.
-+		 */
- 		lpfc_nlp_put(ndlp);
-+		return 0;
- 	}
- 	return 1;
+@@ -2331,6 +2248,8 @@ atarget_done:
+ 	return rval;
  }
--static void
-+
-+void
- lpfc_more_plogi(struct lpfc_vport *vport)
- {
- 	int sentplogi;
-@@ -752,6 +796,8 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp,
- {
- 	struct lpfc_vport    *vport = ndlp->vport;
- 	struct lpfc_nodelist *new_ndlp;
-+	struct lpfc_rport_data *rdata;
-+	struct fc_rport *rport;
- 	struct serv_parm *sp;
- 	uint8_t  name[sizeof(struct lpfc_name)];
- 	uint32_t rc;
-@@ -788,11 +834,34 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp,
- 	lpfc_unreg_rpi(vport, new_ndlp);
- 	new_ndlp->nlp_DID = ndlp->nlp_DID;
- 	new_ndlp->nlp_prev_state = ndlp->nlp_prev_state;
-+
-+	if (ndlp->nlp_flag & NLP_NPR_2B_DISC)
-+		new_ndlp->nlp_flag |= NLP_NPR_2B_DISC;
-+	ndlp->nlp_flag &= ~NLP_NPR_2B_DISC;
-+
- 	lpfc_nlp_set_state(vport, new_ndlp, ndlp->nlp_state);
  
- 	/* Move this back to NPR state */
--	if (memcmp(&ndlp->nlp_portname, name, sizeof(struct lpfc_name)) == 0)
-+	if (memcmp(&ndlp->nlp_portname, name, sizeof(struct lpfc_name)) == 0) {
-+		/* The new_ndlp is replacing ndlp totally, so we need
-+		 * to put ndlp on UNUSED list and try to free it.
-+		 */
-+
-+		/* Fix up the rport accordingly */
-+		rport =  ndlp->rport;
-+		if (rport) {
-+			rdata = rport->dd_data;
-+			if (rdata->pnode == ndlp) {
-+				lpfc_nlp_put(ndlp);
-+				ndlp->rport = NULL;
-+				rdata->pnode = lpfc_nlp_get(new_ndlp);
-+				new_ndlp->rport = rport;
-+			}
-+			new_ndlp->nlp_type = ndlp->nlp_type;
-+		}
++#if 0
 +
- 		lpfc_drop_node(vport, ndlp);
-+	}
- 	else {
- 		lpfc_unreg_rpi(vport, ndlp);
- 		ndlp->nlp_DID = 0; /* Two ndlps cannot have the same did */
-@@ -801,6 +870,27 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp,
- 	return new_ndlp;
+ int
+ qla2x00_system_error(scsi_qla_host_t *ha)
+ {
+@@ -2360,47 +2279,7 @@ qla2x00_system_error(scsi_qla_host_t *ha)
+ 	return rval;
  }
  
-+void
-+lpfc_end_rscn(struct lpfc_vport *vport)
-+{
-+	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
-+
-+	if (vport->fc_flag & FC_RSCN_MODE) {
-+		/*
-+		 * Check to see if more RSCNs came in while we were
-+		 * processing this one.
-+		 */
-+		if (vport->fc_rscn_id_cnt ||
-+		    (vport->fc_flag & FC_RSCN_DISCOVERY) != 0)
-+			lpfc_els_handle_rscn(vport);
-+		else {
-+			spin_lock_irq(shost->host_lock);
-+			vport->fc_flag &= ~FC_RSCN_MODE;
-+			spin_unlock_irq(shost->host_lock);
-+		}
-+	}
-+}
-+
- static void
- lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
- 		    struct lpfc_iocbq *rspiocb)
-@@ -871,13 +961,6 @@ lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
- 			goto out;
- 		}
- 		/* PLOGI failed */
--		if (ndlp->nlp_DID == NameServer_DID) {
--			lpfc_vport_set_state(vport, FC_VPORT_FAILED);
--			lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
--					 "0250 Nameserver login error: "
--					 "0x%x / 0x%x\n",
--					 irsp->ulpStatus, irsp->un.ulpWord[4]);
--		}
- 		/* Do not call DSM for lpfc_els_abort'ed ELS cmds */
- 		if (lpfc_error_lost_link(irsp)) {
- 			rc = NLP_STE_FREED_NODE;
-@@ -905,20 +988,7 @@ lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
- 			spin_unlock_irq(shost->host_lock);
- 
- 			lpfc_can_disctmo(vport);
--			if (vport->fc_flag & FC_RSCN_MODE) {
--				/*
--				 * Check to see if more RSCNs came in while
--				 * we were processing this one.
--				 */
--				if ((vport->fc_rscn_id_cnt == 0) &&
--				    (!(vport->fc_flag & FC_RSCN_DISCOVERY))) {
--					spin_lock_irq(shost->host_lock);
--					vport->fc_flag &= ~FC_RSCN_MODE;
--					spin_unlock_irq(shost->host_lock);
--				} else {
--					lpfc_els_handle_rscn(vport);
--				}
--			}
-+			lpfc_end_rscn(vport);
- 		}
- 	}
- 
-@@ -933,6 +1003,7 @@ lpfc_issue_els_plogi(struct lpfc_vport *vport, uint32_t did, uint8_t retry)
- 	struct lpfc_hba  *phba = vport->phba;
- 	struct serv_parm *sp;
- 	IOCB_t *icmd;
-+	struct lpfc_nodelist *ndlp;
- 	struct lpfc_iocbq *elsiocb;
- 	struct lpfc_sli_ring *pring;
- 	struct lpfc_sli *psli;
-@@ -943,8 +1014,11 @@ lpfc_issue_els_plogi(struct lpfc_vport *vport, uint32_t did, uint8_t retry)
- 	psli = &phba->sli;
- 	pring = &psli->ring[LPFC_ELS_RING];	/* ELS ring */
+-/**
+- * qla2x00_get_serdes_params() -
+- * @ha: HA context
+- *
+- * Returns
+- */
+-int
+-qla2x00_get_serdes_params(scsi_qla_host_t *ha, uint16_t *sw_em_1g,
+-    uint16_t *sw_em_2g, uint16_t *sw_em_4g)
+-{
+-	int rval;
+-	mbx_cmd_t mc;
+-	mbx_cmd_t *mcp = &mc;
+-
+-	DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
+-
+-	mcp->mb[0] = MBC_SERDES_PARAMS;
+-	mcp->mb[1] = 0;
+-	mcp->out_mb = MBX_1|MBX_0;
+-	mcp->in_mb = MBX_4|MBX_3|MBX_2|MBX_0;
+-	mcp->tov = 30;
+-	mcp->flags = 0;
+-	rval = qla2x00_mailbox_command(ha, mcp);
+-
+-	if (rval != QLA_SUCCESS) {
+-		/*EMPTY*/
+-		DEBUG2_3_11(printk("%s(%ld): failed=%x (%x).\n", __func__,
+-		    ha->host_no, rval, mcp->mb[0]));
+-	} else {
+-		DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no));
+-
+-		if (sw_em_1g)
+-			*sw_em_1g = mcp->mb[2];
+-		if (sw_em_2g)
+-			*sw_em_2g = mcp->mb[3];
+-		if (sw_em_4g)
+-			*sw_em_4g = mcp->mb[4];
+-	}
+-
+-	return rval;
+-}
++#endif  /*  0  */
  
-+	ndlp = lpfc_findnode_did(vport, did);
-+	/* If ndlp if not NULL, we will bump the reference count on it */
-+
- 	cmdsize = (sizeof(uint32_t) + sizeof(struct serv_parm));
--	elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, NULL, did,
-+	elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp, did,
- 				     ELS_CMD_PLOGI);
- 	if (!elsiocb)
- 		return 1;
-@@ -1109,7 +1183,7 @@ lpfc_issue_els_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
- 	return 0;
+ /**
+  * qla2x00_set_serdes_params() -
+@@ -2471,7 +2350,7 @@ qla2x00_stop_firmware(scsi_qla_host_t *ha)
  }
  
--static void
-+void
- lpfc_more_adisc(struct lpfc_vport *vport)
- {
- 	int sentadisc;
-@@ -1134,8 +1208,6 @@ lpfc_more_adisc(struct lpfc_vport *vport)
- static void
- lpfc_rscn_disc(struct lpfc_vport *vport)
+ int
+-qla2x00_trace_control(scsi_qla_host_t *ha, uint16_t ctrl, dma_addr_t eft_dma,
++qla2x00_enable_eft_trace(scsi_qla_host_t *ha, dma_addr_t eft_dma,
+     uint16_t buffers)
  {
--	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
--
- 	lpfc_can_disctmo(vport);
- 
- 	/* RSCN discovery */
-@@ -1144,19 +1216,7 @@ lpfc_rscn_disc(struct lpfc_vport *vport)
- 		if (lpfc_els_disc_plogi(vport))
- 			return;
+ 	int rval;
+@@ -2484,22 +2363,18 @@ qla2x00_trace_control(scsi_qla_host_t *ha, uint16_t ctrl, dma_addr_t eft_dma,
+ 	DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
  
--	if (vport->fc_flag & FC_RSCN_MODE) {
--		/* Check to see if more RSCNs came in while we were
--		 * processing this one.
--		 */
--		if ((vport->fc_rscn_id_cnt == 0) &&
--		    (!(vport->fc_flag & FC_RSCN_DISCOVERY))) {
--			spin_lock_irq(shost->host_lock);
--			vport->fc_flag &= ~FC_RSCN_MODE;
--			spin_unlock_irq(shost->host_lock);
--		} else {
--			lpfc_els_handle_rscn(vport);
--		}
+ 	mcp->mb[0] = MBC_TRACE_CONTROL;
+-	mcp->mb[1] = ctrl;
+-	mcp->out_mb = MBX_1|MBX_0;
++	mcp->mb[1] = TC_EFT_ENABLE;
++	mcp->mb[2] = LSW(eft_dma);
++	mcp->mb[3] = MSW(eft_dma);
++	mcp->mb[4] = LSW(MSD(eft_dma));
++	mcp->mb[5] = MSW(MSD(eft_dma));
++	mcp->mb[6] = buffers;
++	mcp->mb[7] = TC_AEN_DISABLE;
++	mcp->out_mb = MBX_7|MBX_6|MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0;
+ 	mcp->in_mb = MBX_1|MBX_0;
+-	if (ctrl == TC_ENABLE) {
+-		mcp->mb[2] = LSW(eft_dma);
+-		mcp->mb[3] = MSW(eft_dma);
+-		mcp->mb[4] = LSW(MSD(eft_dma));
+-		mcp->mb[5] = MSW(MSD(eft_dma));
+-		mcp->mb[6] = buffers;
+-		mcp->mb[7] = 0;
+-		mcp->out_mb |= MBX_7|MBX_6|MBX_5|MBX_4|MBX_3|MBX_2;
 -	}
-+	lpfc_end_rscn(vport);
+ 	mcp->tov = 30;
+ 	mcp->flags = 0;
+ 	rval = qla2x00_mailbox_command(ha, mcp);
+-
+ 	if (rval != QLA_SUCCESS) {
+ 		DEBUG2_3_11(printk("%s(%ld): failed=%x mb[0]=%x mb[1]=%x.\n",
+ 		    __func__, ha->host_no, rval, mcp->mb[0], mcp->mb[1]));
+@@ -2511,8 +2386,7 @@ qla2x00_trace_control(scsi_qla_host_t *ha, uint16_t ctrl, dma_addr_t eft_dma,
  }
  
- static void
-@@ -1413,6 +1473,13 @@ lpfc_issue_els_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
- 	psli = &phba->sli;
- 	pring = &psli->ring[LPFC_ELS_RING];
+ int
+-qla2x00_read_sfp(scsi_qla_host_t *ha, dma_addr_t sfp_dma, uint16_t addr,
+-    uint16_t off, uint16_t count)
++qla2x00_disable_eft_trace(scsi_qla_host_t *ha)
+ {
+ 	int rval;
+ 	mbx_cmd_t mc;
+@@ -2523,24 +2397,16 @@ qla2x00_read_sfp(scsi_qla_host_t *ha, dma_addr_t sfp_dma, uint16_t addr,
  
-+	spin_lock_irq(shost->host_lock);
-+	if (ndlp->nlp_flag & NLP_LOGO_SND) {
-+		spin_unlock_irq(shost->host_lock);
-+		return 0;
-+	}
-+	spin_unlock_irq(shost->host_lock);
-+
- 	cmdsize = (2 * sizeof(uint32_t)) + sizeof(struct lpfc_name);
- 	elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp,
- 				     ndlp->nlp_DID, ELS_CMD_LOGO);
-@@ -1499,6 +1566,9 @@ lpfc_issue_els_scr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry)
- 				     ndlp->nlp_DID, ELS_CMD_SCR);
+ 	DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
  
- 	if (!elsiocb) {
-+		/* This will trigger the release of the node just
-+		 * allocated
-+		 */
- 		lpfc_nlp_put(ndlp);
- 		return 1;
- 	}
-@@ -1520,10 +1590,17 @@ lpfc_issue_els_scr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry)
- 	phba->fc_stat.elsXmitSCR++;
- 	elsiocb->iocb_cmpl = lpfc_cmpl_els_cmd;
- 	if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
-+		/* The additional lpfc_nlp_put will cause the following
-+		 * lpfc_els_free_iocb routine to trigger the rlease of
-+		 * the node.
-+		 */
- 		lpfc_nlp_put(ndlp);
- 		lpfc_els_free_iocb(phba, elsiocb);
- 		return 1;
- 	}
-+	/* This will cause the callback-function lpfc_cmpl_els_cmd to
-+	 * trigger the release of node.
-+	 */
- 	lpfc_nlp_put(ndlp);
- 	return 0;
- }
-@@ -1555,6 +1632,9 @@ lpfc_issue_els_farpr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry)
- 	elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp,
- 				     ndlp->nlp_DID, ELS_CMD_RNID);
- 	if (!elsiocb) {
-+		/* This will trigger the release of the node just
-+		 * allocated
-+		 */
- 		lpfc_nlp_put(ndlp);
- 		return 1;
- 	}
-@@ -1591,35 +1671,21 @@ lpfc_issue_els_farpr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry)
- 	phba->fc_stat.elsXmitFARPR++;
- 	elsiocb->iocb_cmpl = lpfc_cmpl_els_cmd;
- 	if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
-+		/* The additional lpfc_nlp_put will cause the following
-+		 * lpfc_els_free_iocb routine to trigger the release of
-+		 * the node.
-+		 */
- 		lpfc_nlp_put(ndlp);
- 		lpfc_els_free_iocb(phba, elsiocb);
- 		return 1;
+-	mcp->mb[0] = MBC_READ_SFP;
+-	mcp->mb[1] = addr;
+-	mcp->mb[2] = MSW(sfp_dma);
+-	mcp->mb[3] = LSW(sfp_dma);
+-	mcp->mb[6] = MSW(MSD(sfp_dma));
+-	mcp->mb[7] = LSW(MSD(sfp_dma));
+-	mcp->mb[8] = count;
+-	mcp->mb[9] = off;
+-	mcp->mb[10] = 0;
+-	mcp->out_mb = MBX_10|MBX_9|MBX_8|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0;
+-	mcp->in_mb = MBX_0;
++	mcp->mb[0] = MBC_TRACE_CONTROL;
++	mcp->mb[1] = TC_EFT_DISABLE;
++	mcp->out_mb = MBX_1|MBX_0;
++	mcp->in_mb = MBX_1|MBX_0;
+ 	mcp->tov = 30;
+ 	mcp->flags = 0;
+ 	rval = qla2x00_mailbox_command(ha, mcp);
+-
+ 	if (rval != QLA_SUCCESS) {
+-		DEBUG2_3_11(printk("%s(%ld): failed=%x (%x).\n", __func__,
+-		    ha->host_no, rval, mcp->mb[0]));
++		DEBUG2_3_11(printk("%s(%ld): failed=%x mb[0]=%x mb[1]=%x.\n",
++		    __func__, ha->host_no, rval, mcp->mb[0], mcp->mb[1]));
+ 	} else {
+ 		DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no));
  	}
-+	/* This will cause the callback-function lpfc_cmpl_els_cmd to
-+	 * trigger the release of the node.
-+	 */
- 	lpfc_nlp_put(ndlp);
- 	return 0;
+@@ -2549,176 +2415,168 @@ qla2x00_read_sfp(scsi_qla_host_t *ha, dma_addr_t sfp_dma, uint16_t addr,
  }
  
--static void
--lpfc_end_rscn(struct lpfc_vport *vport)
--{
--	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+ int
+-qla2x00_get_idma_speed(scsi_qla_host_t *ha, uint16_t loop_id,
+-    uint16_t *port_speed, uint16_t *mb)
++qla2x00_enable_fce_trace(scsi_qla_host_t *ha, dma_addr_t fce_dma,
++    uint16_t buffers, uint16_t *mb, uint32_t *dwords)
+ {
+ 	int rval;
+ 	mbx_cmd_t mc;
+ 	mbx_cmd_t *mcp = &mc;
+ 
+-	if (!IS_IIDMA_CAPABLE(ha))
++	if (!IS_QLA25XX(ha))
+ 		return QLA_FUNCTION_FAILED;
+ 
+ 	DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
+ 
+-	mcp->mb[0] = MBC_PORT_PARAMS;
+-	mcp->mb[1] = loop_id;
+-	mcp->mb[2] = mcp->mb[3] = mcp->mb[4] = mcp->mb[5] = 0;
+-	mcp->out_mb = MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0;
+-	mcp->in_mb = MBX_5|MBX_4|MBX_3|MBX_1|MBX_0;
++	mcp->mb[0] = MBC_TRACE_CONTROL;
++	mcp->mb[1] = TC_FCE_ENABLE;
++	mcp->mb[2] = LSW(fce_dma);
++	mcp->mb[3] = MSW(fce_dma);
++	mcp->mb[4] = LSW(MSD(fce_dma));
++	mcp->mb[5] = MSW(MSD(fce_dma));
++	mcp->mb[6] = buffers;
++	mcp->mb[7] = TC_AEN_DISABLE;
++	mcp->mb[8] = 0;
++	mcp->mb[9] = TC_FCE_DEFAULT_RX_SIZE;
++	mcp->mb[10] = TC_FCE_DEFAULT_TX_SIZE;
++	mcp->out_mb = MBX_10|MBX_9|MBX_8|MBX_7|MBX_6|MBX_5|MBX_4|MBX_3|MBX_2|
++	    MBX_1|MBX_0;
++	mcp->in_mb = MBX_6|MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0;
+ 	mcp->tov = 30;
+ 	mcp->flags = 0;
+ 	rval = qla2x00_mailbox_command(ha, mcp);
 -
--	if (vport->fc_flag & FC_RSCN_MODE) {
--		/*
--		 * Check to see if more RSCNs came in while we were
--		 * processing this one.
--		 */
--		if (vport->fc_rscn_id_cnt ||
--		    (vport->fc_flag & FC_RSCN_DISCOVERY) != 0)
--			lpfc_els_handle_rscn(vport);
--		else {
--			spin_lock_irq(shost->host_lock);
--			vport->fc_flag &= ~FC_RSCN_MODE;
--			spin_unlock_irq(shost->host_lock);
--		}
+-	/* Return mailbox statuses. */
+-	if (mb != NULL) {
+-		mb[0] = mcp->mb[0];
+-		mb[1] = mcp->mb[1];
+-		mb[3] = mcp->mb[3];
+-		mb[4] = mcp->mb[4];
+-		mb[5] = mcp->mb[5];
 -	}
--}
 -
- void
- lpfc_cancel_retry_delay_tmo(struct lpfc_vport *vport, struct lpfc_nodelist *nlp)
- {
-@@ -1675,7 +1741,10 @@ lpfc_els_retry_delay(unsigned long ptr)
- 		return;
+ 	if (rval != QLA_SUCCESS) {
+-		DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", __func__,
+-		    ha->host_no, rval));
++		DEBUG2_3_11(printk("%s(%ld): failed=%x mb[0]=%x mb[1]=%x.\n",
++		    __func__, ha->host_no, rval, mcp->mb[0], mcp->mb[1]));
+ 	} else {
+ 		DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no));
+-		if (port_speed)
+-			*port_speed = mcp->mb[3];
++
++		if (mb)
++			memcpy(mb, mcp->mb, 8 * sizeof(*mb));
++		if (dwords)
++			*dwords = mcp->mb[6];
  	}
  
--	evtp->evt_arg1  = ndlp;
-+	/* We need to hold the node by incrementing the reference
-+	 * count until the queued work is done
-+	 */
-+	evtp->evt_arg1  = lpfc_nlp_get(ndlp);
- 	evtp->evt       = LPFC_EVT_ELS_RETRY;
- 	list_add_tail(&evtp->evt_listp, &phba->work_list);
- 	if (phba->work_wait)
-@@ -1759,6 +1828,7 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
- 	uint32_t *elscmd;
- 	struct ls_rjt stat;
- 	int retry = 0, maxretry = lpfc_max_els_tries, delay = 0;
-+	int logerr = 0;
- 	uint32_t cmd = 0;
- 	uint32_t did;
- 
-@@ -1815,6 +1885,7 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
- 			break;
+ 	return rval;
+ }
  
- 		case IOERR_NO_RESOURCES:
-+			logerr = 1; /* HBA out of resources */
- 			retry = 1;
- 			if (cmdiocb->retry > 100)
- 				delay = 100;
-@@ -1843,6 +1914,7 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+ int
+-qla2x00_set_idma_speed(scsi_qla_host_t *ha, uint16_t loop_id,
+-    uint16_t port_speed, uint16_t *mb)
++qla2x00_disable_fce_trace(scsi_qla_host_t *ha, uint64_t *wr, uint64_t *rd)
+ {
+ 	int rval;
+ 	mbx_cmd_t mc;
+ 	mbx_cmd_t *mcp = &mc;
  
- 	case IOSTAT_NPORT_BSY:
- 	case IOSTAT_FABRIC_BSY:
-+		logerr = 1; /* Fabric / Remote NPort out of resources */
- 		retry = 1;
- 		break;
+-	if (!IS_IIDMA_CAPABLE(ha))
++	if (!IS_FWI2_CAPABLE(ha))
+ 		return QLA_FUNCTION_FAILED;
  
-@@ -1923,6 +1995,15 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
- 	if (did == FDMI_DID)
- 		retry = 1;
+ 	DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
  
-+	if ((cmd == ELS_CMD_FLOGI) &&
-+	    (phba->fc_topology != TOPOLOGY_LOOP)) {
-+		/* FLOGI retry policy */
-+		retry = 1;
-+		maxretry = 48;
-+		if (cmdiocb->retry >= 32)
-+			delay = 1000;
-+	}
+-	mcp->mb[0] = MBC_PORT_PARAMS;
+-	mcp->mb[1] = loop_id;
+-	mcp->mb[2] = BIT_0;
+-	mcp->mb[3] = port_speed & (BIT_2|BIT_1|BIT_0);
+-	mcp->mb[4] = mcp->mb[5] = 0;
+-	mcp->out_mb = MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0;
+-	mcp->in_mb = MBX_5|MBX_4|MBX_3|MBX_1|MBX_0;
++	mcp->mb[0] = MBC_TRACE_CONTROL;
++	mcp->mb[1] = TC_FCE_DISABLE;
++	mcp->mb[2] = TC_FCE_DISABLE_TRACE;
++	mcp->out_mb = MBX_2|MBX_1|MBX_0;
++	mcp->in_mb = MBX_9|MBX_8|MBX_7|MBX_6|MBX_5|MBX_4|MBX_3|MBX_2|
++	    MBX_1|MBX_0;
+ 	mcp->tov = 30;
+ 	mcp->flags = 0;
+ 	rval = qla2x00_mailbox_command(ha, mcp);
+-
+-	/* Return mailbox statuses. */
+-	if (mb != NULL) {
+-		mb[0] = mcp->mb[0];
+-		mb[1] = mcp->mb[1];
+-		mb[3] = mcp->mb[3];
+-		mb[4] = mcp->mb[4];
+-		mb[5] = mcp->mb[5];
+-	}
+-
+ 	if (rval != QLA_SUCCESS) {
+-		DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", __func__,
+-		    ha->host_no, rval));
++		DEBUG2_3_11(printk("%s(%ld): failed=%x mb[0]=%x mb[1]=%x.\n",
++		    __func__, ha->host_no, rval, mcp->mb[0], mcp->mb[1]));
+ 	} else {
+ 		DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no));
 +
- 	if ((++cmdiocb->retry) >= maxretry) {
- 		phba->fc_stat.elsRetryExceeded++;
- 		retry = 0;
-@@ -2006,11 +2087,46 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
- 		}
++		if (wr)
++			*wr = (uint64_t) mcp->mb[5] << 48 |
++			    (uint64_t) mcp->mb[4] << 32 |
++			    (uint64_t) mcp->mb[3] << 16 |
++			    (uint64_t) mcp->mb[2];
++		if (rd)
++			*rd = (uint64_t) mcp->mb[9] << 48 |
++			    (uint64_t) mcp->mb[8] << 32 |
++			    (uint64_t) mcp->mb[7] << 16 |
++			    (uint64_t) mcp->mb[6];
  	}
- 	/* No retry ELS command <elsCmd> to remote NPORT <did> */
--	lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
-+	if (logerr) {
-+		lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
-+			 "0137 No retry ELS command x%x to remote "
-+			 "NPORT x%x: Out of Resources: Error:x%x/%x\n",
-+			 cmd, did, irsp->ulpStatus,
-+			 irsp->un.ulpWord[4]);
-+	}
-+	else {
-+		lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
- 			 "0108 No retry ELS command x%x to remote "
- 			 "NPORT x%x Retried:%d Error:x%x/%x\n",
- 			 cmd, did, cmdiocb->retry, irsp->ulpStatus,
- 			 irsp->un.ulpWord[4]);
-+	}
-+	return 0;
-+}
-+
-+static int
-+lpfc_els_free_data(struct lpfc_hba *phba, struct lpfc_dmabuf *buf_ptr1)
-+{
-+	struct lpfc_dmabuf *buf_ptr;
-+
-+	/* Free the response before processing the command.  */
-+	if (!list_empty(&buf_ptr1->list)) {
-+		list_remove_head(&buf_ptr1->list, buf_ptr,
-+				 struct lpfc_dmabuf,
-+				 list);
-+		lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys);
-+		kfree(buf_ptr);
-+	}
-+	lpfc_mbuf_free(phba, buf_ptr1->virt, buf_ptr1->phys);
-+	kfree(buf_ptr1);
-+	return 0;
-+}
-+
-+static int
-+lpfc_els_free_bpl(struct lpfc_hba *phba, struct lpfc_dmabuf *buf_ptr)
-+{
-+	lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys);
-+	kfree(buf_ptr);
- 	return 0;
+ 
+ 	return rval;
  }
  
-@@ -2018,30 +2134,63 @@ int
- lpfc_els_free_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *elsiocb)
+-/*
+- * qla24xx_get_vp_database
+- *	Get the VP's database for all configured ports.
+- *
+- * Input:
+- *	ha = adapter block pointer.
+- *	size = size of initialization control block.
+- *
+- * Returns:
+- *	qla2x00 local function return status code.
+- *
+- * Context:
+- *	Kernel context.
+- */
+ int
+-qla24xx_get_vp_database(scsi_qla_host_t *ha, uint16_t size)
++qla2x00_read_sfp(scsi_qla_host_t *ha, dma_addr_t sfp_dma, uint16_t addr,
++    uint16_t off, uint16_t count)
  {
- 	struct lpfc_dmabuf *buf_ptr, *buf_ptr1;
-+	struct lpfc_nodelist *ndlp;
+ 	int rval;
+ 	mbx_cmd_t mc;
+ 	mbx_cmd_t *mcp = &mc;
  
--	if (elsiocb->context1) {
--		lpfc_nlp_put(elsiocb->context1);
-+	ndlp = (struct lpfc_nodelist *)elsiocb->context1;
-+	if (ndlp) {
-+		if (ndlp->nlp_flag & NLP_DEFER_RM) {
-+			lpfc_nlp_put(ndlp);
-+
-+			/* If the ndlp is not being used by another discovery
-+			 * thread, free it.
-+			 */
-+			if (!lpfc_nlp_not_used(ndlp)) {
-+				/* If ndlp is being used by another discovery
-+				 * thread, just clear NLP_DEFER_RM
-+				 */
-+				ndlp->nlp_flag &= ~NLP_DEFER_RM;
-+			}
-+		}
-+		else
-+			lpfc_nlp_put(ndlp);
- 		elsiocb->context1 = NULL;
- 	}
- 	/* context2  = cmd,  context2->next = rsp, context3 = bpl */
- 	if (elsiocb->context2) {
--		buf_ptr1 = (struct lpfc_dmabuf *) elsiocb->context2;
--		/* Free the response before processing the command.  */
--		if (!list_empty(&buf_ptr1->list)) {
--			list_remove_head(&buf_ptr1->list, buf_ptr,
--					 struct lpfc_dmabuf,
--					 list);
--			lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys);
--			kfree(buf_ptr);
-+		if (elsiocb->iocb_flag & LPFC_DELAY_MEM_FREE) {
-+			/* Firmware could still be in progress of DMAing
-+			 * payload, so don't free data buffer till after
-+			 * a hbeat.
-+			 */
-+			elsiocb->iocb_flag &= ~LPFC_DELAY_MEM_FREE;
-+			buf_ptr = elsiocb->context2;
-+			elsiocb->context2 = NULL;
-+			if (buf_ptr) {
-+				buf_ptr1 = NULL;
-+				spin_lock_irq(&phba->hbalock);
-+				if (!list_empty(&buf_ptr->list)) {
-+					list_remove_head(&buf_ptr->list,
-+						buf_ptr1, struct lpfc_dmabuf,
-+						list);
-+					INIT_LIST_HEAD(&buf_ptr1->list);
-+					list_add_tail(&buf_ptr1->list,
-+						&phba->elsbuf);
-+					phba->elsbuf_cnt++;
-+				}
-+				INIT_LIST_HEAD(&buf_ptr->list);
-+				list_add_tail(&buf_ptr->list, &phba->elsbuf);
-+				phba->elsbuf_cnt++;
-+				spin_unlock_irq(&phba->hbalock);
-+			}
-+		} else {
-+			buf_ptr1 = (struct lpfc_dmabuf *) elsiocb->context2;
-+			lpfc_els_free_data(phba, buf_ptr1);
- 		}
--		lpfc_mbuf_free(phba, buf_ptr1->virt, buf_ptr1->phys);
--		kfree(buf_ptr1);
- 	}
+-	DEBUG11(printk("scsi(%ld):%s - entered.\n",
+-	    ha->host_no, __func__));
++	if (!IS_FWI2_CAPABLE(ha))
++		return QLA_FUNCTION_FAILED;
  
- 	if (elsiocb->context3) {
- 		buf_ptr = (struct lpfc_dmabuf *) elsiocb->context3;
--		lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys);
--		kfree(buf_ptr);
-+		lpfc_els_free_bpl(phba, buf_ptr);
- 	}
- 	lpfc_sli_release_iocbq(phba, elsiocb);
- 	return 0;
-@@ -2065,15 +2214,20 @@ lpfc_cmpl_els_logo_acc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
- 			 "Data: x%x x%x x%x\n",
- 			 ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state,
- 			 ndlp->nlp_rpi);
--	switch (ndlp->nlp_state) {
--	case NLP_STE_UNUSED_NODE:	/* node is just allocated */
--		lpfc_drop_node(vport, ndlp);
--		break;
--	case NLP_STE_NPR_NODE:		/* NPort Recovery mode */
--		lpfc_unreg_rpi(vport, ndlp);
--		break;
--	default:
--		break;
+-	mcp->mb[0] = MBC_MID_GET_VP_DATABASE;
+-	mcp->mb[2] = MSW(ha->init_cb_dma);
+-	mcp->mb[3] = LSW(ha->init_cb_dma);
+-	mcp->mb[4] = 0;
+-	mcp->mb[5] = 0;
+-	mcp->mb[6] = MSW(MSD(ha->init_cb_dma));
+-	mcp->mb[7] = LSW(MSD(ha->init_cb_dma));
+-	mcp->out_mb = MBX_7|MBX_6|MBX_3|MBX_2|MBX_0;
+-	mcp->in_mb = MBX_1|MBX_0;
+-	mcp->buf_size = size;
+-	mcp->flags = MBX_DMA_OUT;
+-	mcp->tov = MBX_TOV_SECONDS;
++	DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
 +
-+	if (ndlp->nlp_state == NLP_STE_NPR_NODE) {
-+		/* NPort Recovery mode or node is just allocated */
-+		if (!lpfc_nlp_not_used(ndlp)) {
-+			/* If the ndlp is being used by another discovery
-+			 * thread, just unregister the RPI.
-+			 */
-+			lpfc_unreg_rpi(vport, ndlp);
-+		} else {
-+			/* Indicate the node has already released, should
-+			 * not reference to it from within lpfc_els_free_iocb.
-+			 */
-+			cmdiocb->context1 = NULL;
-+		}
++	mcp->mb[0] = MBC_READ_SFP;
++	mcp->mb[1] = addr;
++	mcp->mb[2] = MSW(sfp_dma);
++	mcp->mb[3] = LSW(sfp_dma);
++	mcp->mb[6] = MSW(MSD(sfp_dma));
++	mcp->mb[7] = LSW(MSD(sfp_dma));
++	mcp->mb[8] = count;
++	mcp->mb[9] = off;
++	mcp->mb[10] = 0;
++	mcp->out_mb = MBX_10|MBX_9|MBX_8|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0;
++	mcp->in_mb = MBX_0;
++	mcp->tov = 30;
++	mcp->flags = 0;
+ 	rval = qla2x00_mailbox_command(ha, mcp);
+ 
+ 	if (rval != QLA_SUCCESS) {
+-		/*EMPTY*/
+-		DEBUG2_3_11(printk("%s(%ld): failed=%x "
+-		    "mb0=%x.\n",
+-		    __func__, ha->host_no, rval, mcp->mb[0]));
++		DEBUG2_3_11(printk("%s(%ld): failed=%x (%x).\n", __func__,
++		    ha->host_no, rval, mcp->mb[0]));
+ 	} else {
+-		/*EMPTY*/
+-		DEBUG11(printk("%s(%ld): done.\n",
+-		    __func__, ha->host_no));
++		DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no));
  	}
- 	lpfc_els_free_iocb(phba, cmdiocb);
- 	return;
-@@ -2089,7 +2243,14 @@ lpfc_mbx_cmpl_dflt_rpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
- 	lpfc_mbuf_free(phba, mp->virt, mp->phys);
- 	kfree(mp);
- 	mempool_free(pmb, phba->mbox_mem_pool);
--	lpfc_nlp_put(ndlp);
-+	if (ndlp) {
-+		lpfc_nlp_put(ndlp);
-+		/* This is the end of the default RPI cleanup logic for this
-+		 * ndlp. If no other discovery threads are using this ndlp.
-+		 * we should free all resources associated with it.
-+		 */
-+		lpfc_nlp_not_used(ndlp);
-+	}
- 	return;
+ 
+ 	return rval;
  }
  
-@@ -2100,15 +2261,29 @@ lpfc_cmpl_els_rsp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
- 	struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) cmdiocb->context1;
- 	struct lpfc_vport *vport = ndlp ? ndlp->vport : NULL;
- 	struct Scsi_Host  *shost = vport ? lpfc_shost_from_vport(vport) : NULL;
--	IOCB_t *irsp;
-+	IOCB_t  *irsp;
-+	uint8_t *pcmd;
- 	LPFC_MBOXQ_t *mbox = NULL;
- 	struct lpfc_dmabuf *mp = NULL;
-+	uint32_t ls_rjt = 0;
+ int
+-qla24xx_get_vp_entry(scsi_qla_host_t *ha, uint16_t size, int vp_id)
++qla2x00_set_idma_speed(scsi_qla_host_t *ha, uint16_t loop_id,
++    uint16_t port_speed, uint16_t *mb)
+ {
+ 	int rval;
+ 	mbx_cmd_t mc;
+ 	mbx_cmd_t *mcp = &mc;
  
- 	irsp = &rspiocb->iocb;
++	if (!IS_IIDMA_CAPABLE(ha))
++		return QLA_FUNCTION_FAILED;
++
+ 	DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
  
- 	if (cmdiocb->context_un.mbox)
- 		mbox = cmdiocb->context_un.mbox;
+-	mcp->mb[0] = MBC_MID_GET_VP_ENTRY;
+-	mcp->mb[2] = MSW(ha->init_cb_dma);
+-	mcp->mb[3] = LSW(ha->init_cb_dma);
+-	mcp->mb[4] = 0;
+-	mcp->mb[5] = 0;
+-	mcp->mb[6] = MSW(MSD(ha->init_cb_dma));
+-	mcp->mb[7] = LSW(MSD(ha->init_cb_dma));
+-	mcp->mb[9] = vp_id;
+-	mcp->out_mb = MBX_9|MBX_7|MBX_6|MBX_3|MBX_2|MBX_0;
+-	mcp->in_mb = MBX_0;
+-	mcp->buf_size = size;
+-	mcp->flags = MBX_DMA_OUT;
++	mcp->mb[0] = MBC_PORT_PARAMS;
++	mcp->mb[1] = loop_id;
++	mcp->mb[2] = BIT_0;
++	mcp->mb[3] = port_speed & (BIT_2|BIT_1|BIT_0);
++	mcp->mb[4] = mcp->mb[5] = 0;
++	mcp->out_mb = MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0;
++	mcp->in_mb = MBX_5|MBX_4|MBX_3|MBX_1|MBX_0;
+ 	mcp->tov = 30;
++	mcp->flags = 0;
+ 	rval = qla2x00_mailbox_command(ha, mcp);
  
-+	/* First determine if this is a LS_RJT cmpl. Note, this callback
-+	 * function can have cmdiocb->contest1 (ndlp) field set to NULL.
-+	 */
-+	pcmd = (uint8_t *) (((struct lpfc_dmabuf *) cmdiocb->context2)->virt);
-+	if (ndlp && (*((uint32_t *) (pcmd)) == ELS_CMD_LS_RJT)) {
-+		/* A LS_RJT associated with Default RPI cleanup has its own
-+		 * seperate code path.
-+		 */
-+		if (!(ndlp->nlp_flag & NLP_RM_DFLT_RPI))
-+			ls_rjt = 1;
++	/* Return mailbox statuses. */
++	if (mb != NULL) {
++		mb[0] = mcp->mb[0];
++		mb[1] = mcp->mb[1];
++		mb[3] = mcp->mb[3];
++		mb[4] = mcp->mb[4];
++		mb[5] = mcp->mb[5];
 +	}
 +
- 	/* Check to see if link went down during discovery */
- 	if (!ndlp || lpfc_els_chk_latt(vport)) {
- 		if (mbox) {
-@@ -2119,6 +2294,15 @@ lpfc_cmpl_els_rsp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
- 			}
- 			mempool_free(mbox, phba->mbox_mem_pool);
- 		}
-+		if (ndlp && (ndlp->nlp_flag & NLP_RM_DFLT_RPI))
-+			if (lpfc_nlp_not_used(ndlp)) {
-+				ndlp = NULL;
-+				/* Indicate the node has already released,
-+				 * should not reference to it from within
-+				 * the routine lpfc_els_free_iocb.
-+				 */
-+				cmdiocb->context1 = NULL;
-+			}
- 		goto out;
+ 	if (rval != QLA_SUCCESS) {
+-		/*EMPTY*/
+-		DEBUG2_3_11(printk("qla24xx_get_vp_entry(%ld): failed=%x "
+-		    "mb0=%x.\n",
+-		    ha->host_no, rval, mcp->mb[0]));
++		DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", __func__,
++		    ha->host_no, rval));
+ 	} else {
+-		/*EMPTY*/
+-		DEBUG11(printk("qla24xx_get_vp_entry(%ld): done.\n",
+-		    ha->host_no));
++		DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no));
  	}
  
-@@ -2150,20 +2334,39 @@ lpfc_cmpl_els_rsp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
- 				lpfc_nlp_set_state(vport, ndlp,
- 					   NLP_STE_REG_LOGIN_ISSUE);
- 			}
--			if (lpfc_sli_issue_mbox(phba, mbox,
--						(MBX_NOWAIT | MBX_STOP_IOCB))
-+			if (lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT)
- 			    != MBX_NOT_FINISHED) {
- 				goto out;
- 			}
--			lpfc_nlp_put(ndlp);
--			/* NOTE: we should have messages for unsuccessful
--			   reglogin */
-+
-+			/* ELS rsp: Cannot issue reg_login for <NPortid> */
-+			lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
-+				"0138 ELS rsp: Cannot issue reg_login for x%x "
-+				"Data: x%x x%x x%x\n",
-+				ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state,
-+				ndlp->nlp_rpi);
-+
-+			if (lpfc_nlp_not_used(ndlp)) {
-+				ndlp = NULL;
-+				/* Indicate node has already been released,
-+				 * should not reference to it from within
-+				 * the routine lpfc_els_free_iocb.
-+				 */
-+				cmdiocb->context1 = NULL;
-+			}
- 		} else {
- 			/* Do not drop node for lpfc_els_abort'ed ELS cmds */
- 			if (!lpfc_error_lost_link(irsp) &&
- 			    ndlp->nlp_flag & NLP_ACC_REGLOGIN) {
--				lpfc_drop_node(vport, ndlp);
--				ndlp = NULL;
-+				if (lpfc_nlp_not_used(ndlp)) {
-+					ndlp = NULL;
-+					/* Indicate node has already been
-+					 * released, should not reference
-+					 * to it from within the routine
-+					 * lpfc_els_free_iocb.
-+					 */
-+					cmdiocb->context1 = NULL;
-+				}
- 			}
- 		}
- 		mp = (struct lpfc_dmabuf *) mbox->context1;
-@@ -2178,7 +2381,21 @@ out:
- 		spin_lock_irq(shost->host_lock);
- 		ndlp->nlp_flag &= ~(NLP_ACC_REGLOGIN | NLP_RM_DFLT_RPI);
- 		spin_unlock_irq(shost->host_lock);
-+
-+		/* If the node is not being used by another discovery thread,
-+		 * and we are sending a reject, we are done with it.
-+		 * Release driver reference count here and free associated
-+		 * resources.
-+		 */
-+		if (ls_rjt)
-+			if (lpfc_nlp_not_used(ndlp))
-+				/* Indicate node has already been released,
-+				 * should not reference to it from within
-+				 * the routine lpfc_els_free_iocb.
-+				 */
-+				cmdiocb->context1 = NULL;
- 	}
-+
- 	lpfc_els_free_iocb(phba, cmdiocb);
- 	return;
- }
-@@ -2349,14 +2566,6 @@ lpfc_els_rsp_reject(struct lpfc_vport *vport, uint32_t rejectError,
- 	elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp;
- 	rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0);
+ 	return rval;
+@@ -2873,7 +2731,7 @@ qla24xx_control_vp(scsi_qla_host_t *vha, int cmd)
+ 	DEBUG11(printk("%s(%ld): entered. Enabling index %d\n", __func__,
+ 	    ha->host_no, vp_index));
  
--	/* If the node is in the UNUSED state, and we are sending
--	 * a reject, we are done with it.  Release driver reference
--	 * count here.  The outstanding els will release its reference on
--	 * completion and the node can be freed then.
--	 */
--	if (ndlp->nlp_state == NLP_STE_UNUSED_NODE)
--		lpfc_nlp_put(ndlp);
--
- 	if (rc == IOCB_ERROR) {
- 		lpfc_els_free_iocb(phba, elsiocb);
- 		return 1;
-@@ -2642,7 +2851,10 @@ lpfc_els_disc_plogi(struct lpfc_vport *vport)
- 			}
- 		}
+-	if (vp_index == 0 || vp_index >= MAX_MULTI_ID_LOOP)
++	if (vp_index == 0 || vp_index >= ha->max_npiv_vports)
+ 		return QLA_PARAMETER_ERROR;
+ 
+ 	vce = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &vce_dma);
+diff --git a/drivers/scsi/qla2xxx/qla_mid.c b/drivers/scsi/qla2xxx/qla_mid.c
+index 821ee74..cf784cd 100644
+--- a/drivers/scsi/qla2xxx/qla_mid.c
++++ b/drivers/scsi/qla2xxx/qla_mid.c
+@@ -39,7 +39,7 @@ qla2x00_vp_stop_timer(scsi_qla_host_t *vha)
  	}
--	if (sentplogi == 0) {
-+	if (sentplogi) {
-+		lpfc_set_disctmo(vport);
-+	}
-+	else {
- 		spin_lock_irq(shost->host_lock);
- 		vport->fc_flag &= ~FC_NLP_MORE;
- 		spin_unlock_irq(shost->host_lock);
-@@ -2830,10 +3042,10 @@ lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
- 			"RCV RSCN defer:  did:x%x/ste:x%x flg:x%x",
- 			ndlp->nlp_DID, vport->port_state, ndlp->nlp_flag);
+ }
  
-+		spin_lock_irq(shost->host_lock);
- 		vport->fc_flag |= FC_RSCN_DEFERRED;
- 		if ((rscn_cnt < FC_MAX_HOLD_RSCN) &&
- 		    !(vport->fc_flag & FC_RSCN_DISCOVERY)) {
--			spin_lock_irq(shost->host_lock);
- 			vport->fc_flag |= FC_RSCN_MODE;
- 			spin_unlock_irq(shost->host_lock);
- 			if (rscn_cnt) {
-@@ -2862,7 +3074,6 @@ lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
- 					 vport->fc_rscn_id_cnt, vport->fc_flag,
- 					 vport->port_state);
- 		} else {
--			spin_lock_irq(shost->host_lock);
- 			vport->fc_flag |= FC_RSCN_DISCOVERY;
- 			spin_unlock_irq(shost->host_lock);
- 			/* ReDiscovery RSCN */
-@@ -2877,7 +3088,9 @@ lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
+-uint32_t
++static uint32_t
+ qla24xx_allocate_vp_id(scsi_qla_host_t *vha)
+ {
+ 	uint32_t vp_id;
+@@ -47,16 +47,15 @@ qla24xx_allocate_vp_id(scsi_qla_host_t *vha)
  
- 		/* send RECOVERY event for ALL nodes that match RSCN payload */
- 		lpfc_rscn_recovery_check(vport);
-+		spin_lock_irq(shost->host_lock);
- 		vport->fc_flag &= ~FC_RSCN_DEFERRED;
-+		spin_unlock_irq(shost->host_lock);
- 		return 0;
+ 	/* Find an empty slot and assign an vp_id */
+ 	down(&ha->vport_sem);
+-	vp_id = find_first_zero_bit((unsigned long *)ha->vp_idx_map,
+-				MAX_MULTI_ID_FABRIC);
+-	if (vp_id > MAX_MULTI_ID_FABRIC) {
+-		DEBUG15(printk ("vp_id %d is bigger than MAX_MULTI_ID_FABRID\n",
+-		    vp_id));
++	vp_id = find_first_zero_bit(ha->vp_idx_map, ha->max_npiv_vports + 1);
++	if (vp_id > ha->max_npiv_vports) {
++		DEBUG15(printk ("vp_id %d is bigger than max-supported %d.\n",
++		    vp_id, ha->max_npiv_vports));
+ 		up(&ha->vport_sem);
+ 		return vp_id;
  	}
  
-@@ -2929,6 +3142,8 @@ lpfc_els_handle_rscn(struct lpfc_vport *vport)
+-	set_bit(vp_id, (unsigned long *)ha->vp_idx_map);
++	set_bit(vp_id, ha->vp_idx_map);
+ 	ha->num_vhosts++;
+ 	vha->vp_idx = vp_id;
+ 	list_add_tail(&vha->vp_list, &ha->vp_list);
+@@ -73,12 +72,12 @@ qla24xx_deallocate_vp_id(scsi_qla_host_t *vha)
+ 	down(&ha->vport_sem);
+ 	vp_id = vha->vp_idx;
+ 	ha->num_vhosts--;
+-	clear_bit(vp_id, (unsigned long *)ha->vp_idx_map);
++	clear_bit(vp_id, ha->vp_idx_map);
+ 	list_del(&vha->vp_list);
+ 	up(&ha->vport_sem);
+ }
  
- 	/* To process RSCN, first compare RSCN data with NameServer */
- 	vport->fc_ns_retry = 0;
-+	vport->num_disc_nodes = 0;
-+
- 	ndlp = lpfc_findnode_did(vport, NameServer_DID);
- 	if (ndlp && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) {
- 		/* Good ndlp, issue CT Request to NameServer */
-@@ -3022,8 +3237,7 @@ lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
- 			mbox->mb.un.varInitLnk.lipsr_AL_PA = 0;
- 			mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
- 			mbox->vport = vport;
--			rc = lpfc_sli_issue_mbox
--				(phba, mbox, (MBX_NOWAIT | MBX_STOP_IOCB));
-+			rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
- 			lpfc_set_loopback_flag(phba);
- 			if (rc == MBX_NOT_FINISHED) {
- 				mempool_free(mbox, phba->mbox_mem_pool);
-@@ -3140,7 +3354,10 @@ lpfc_els_rsp_rps_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
- 	elsiocb = lpfc_prep_els_iocb(phba->pport, 0, cmdsize,
- 				     lpfc_max_els_tries, ndlp,
- 				     ndlp->nlp_DID, ELS_CMD_ACC);
-+
-+	/* Decrement the ndlp reference count from previous mbox command */
- 	lpfc_nlp_put(ndlp);
-+
- 	if (!elsiocb)
+-scsi_qla_host_t *
++static scsi_qla_host_t *
+ qla24xx_find_vhost_by_name(scsi_qla_host_t *ha, uint8_t *port_name)
+ {
+ 	scsi_qla_host_t *vha;
+@@ -216,11 +215,7 @@ qla2x00_alert_all_vps(scsi_qla_host_t *ha, uint16_t *mb)
+ 	if (ha->parent)
  		return;
  
-@@ -3160,13 +3377,13 @@ lpfc_els_rsp_rps_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
- 		status |= 0x4;
+-	i = find_next_bit((unsigned long *)ha->vp_idx_map,
+-	    MAX_MULTI_ID_FABRIC + 1, 1);
+-	for (;i <= MAX_MULTI_ID_FABRIC;
+-	    i = find_next_bit((unsigned long *)ha->vp_idx_map,
+-	    MAX_MULTI_ID_FABRIC + 1, i + 1)) {
++	for_each_mapped_vp_idx(ha, i) {
+ 		vp_idx_matched = 0;
  
- 	rps_rsp->rsvd1 = 0;
--	rps_rsp->portStatus = be16_to_cpu(status);
--	rps_rsp->linkFailureCnt = be32_to_cpu(mb->un.varRdLnk.linkFailureCnt);
--	rps_rsp->lossSyncCnt = be32_to_cpu(mb->un.varRdLnk.lossSyncCnt);
--	rps_rsp->lossSignalCnt = be32_to_cpu(mb->un.varRdLnk.lossSignalCnt);
--	rps_rsp->primSeqErrCnt = be32_to_cpu(mb->un.varRdLnk.primSeqErrCnt);
--	rps_rsp->invalidXmitWord = be32_to_cpu(mb->un.varRdLnk.invalidXmitWord);
--	rps_rsp->crcCnt = be32_to_cpu(mb->un.varRdLnk.crcCnt);
-+	rps_rsp->portStatus = cpu_to_be16(status);
-+	rps_rsp->linkFailureCnt = cpu_to_be32(mb->un.varRdLnk.linkFailureCnt);
-+	rps_rsp->lossSyncCnt = cpu_to_be32(mb->un.varRdLnk.lossSyncCnt);
-+	rps_rsp->lossSignalCnt = cpu_to_be32(mb->un.varRdLnk.lossSignalCnt);
-+	rps_rsp->primSeqErrCnt = cpu_to_be32(mb->un.varRdLnk.primSeqErrCnt);
-+	rps_rsp->invalidXmitWord = cpu_to_be32(mb->un.varRdLnk.invalidXmitWord);
-+	rps_rsp->crcCnt = cpu_to_be32(mb->un.varRdLnk.crcCnt);
- 	/* Xmit ELS RPS ACC response tag <ulpIoTag> */
- 	lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_ELS,
- 			 "0118 Xmit ELS RPS ACC response tag x%x xri x%x, "
-@@ -3223,11 +3440,13 @@ lpfc_els_rcv_rps(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
- 			mbox->context2 = lpfc_nlp_get(ndlp);
- 			mbox->vport = vport;
- 			mbox->mbox_cmpl = lpfc_els_rsp_rps_acc;
--			if (lpfc_sli_issue_mbox (phba, mbox,
--			    (MBX_NOWAIT | MBX_STOP_IOCB)) != MBX_NOT_FINISHED)
-+			if (lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT)
-+				!= MBX_NOT_FINISHED)
- 				/* Mbox completion will send ELS Response */
- 				return 0;
--
-+			/* Decrement reference count used for the failed mbox
-+			 * command.
-+			 */
- 			lpfc_nlp_put(ndlp);
- 			mempool_free(mbox, phba->mbox_mem_pool);
- 		}
-@@ -3461,6 +3680,7 @@ lpfc_els_rcv_fan(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
- 					 * other NLP_FABRIC logins
- 					 */
- 					lpfc_drop_node(vport, ndlp);
-+
- 				} else if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) {
- 					/* Fail outstanding I/O now since this
- 					 * device is marked for PLOGI
-@@ -3469,8 +3689,6 @@ lpfc_els_rcv_fan(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
- 				}
- 			}
+ 		list_for_each_entry(vha, &ha->vp_list, vp_list) {
+@@ -270,7 +265,7 @@ qla2x00_vp_abort_isp(scsi_qla_host_t *vha)
+ 	qla24xx_enable_vp(vha);
+ }
  
--			vport->port_state = LPFC_FLOGI;
--			lpfc_set_disctmo(vport);
- 			lpfc_initial_flogi(vport);
- 			return 0;
- 		}
-@@ -3711,6 +3929,7 @@ static void
- lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
- 		      struct lpfc_vport *vport, struct lpfc_iocbq *elsiocb)
+-int
++static int
+ qla2x00_do_dpc_vp(scsi_qla_host_t *vha)
  {
-+	struct Scsi_Host  *shost;
- 	struct lpfc_nodelist *ndlp;
- 	struct ls_rjt stat;
- 	uint32_t *payload;
-@@ -3750,11 +3969,19 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
- 			goto dropit;
+ 	if (test_and_clear_bit(VP_IDX_ACQUIRED, &vha->vp_flags)) {
+@@ -311,11 +306,7 @@ qla2x00_do_dpc_all_vps(scsi_qla_host_t *ha)
  
- 		lpfc_nlp_init(vport, ndlp, did);
-+		lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
- 		newnode = 1;
- 		if ((did & Fabric_DID_MASK) == Fabric_DID_MASK) {
- 			ndlp->nlp_type |= NLP_FABRIC;
- 		}
--		lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE);
-+	}
-+	else {
-+		if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) {
-+			/* This is simular to the new node path */
-+			lpfc_nlp_get(ndlp);
-+			lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
-+			newnode = 1;
-+		}
- 	}
+ 	clear_bit(VP_DPC_NEEDED, &ha->dpc_flags);
  
- 	phba->fc_stat.elsRcvFrame++;
-@@ -3783,6 +4010,12 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
- 			rjt_err = LSRJT_UNABLE_TPC;
- 			break;
- 		}
-+
-+		shost = lpfc_shost_from_vport(vport);
-+		spin_lock_irq(shost->host_lock);
-+		ndlp->nlp_flag &= ~NLP_TARGET_REMOVE;
-+		spin_unlock_irq(shost->host_lock);
-+
- 		lpfc_disc_state_machine(vport, ndlp, elsiocb,
- 					NLP_EVT_RCV_PLOGI);
+-	i = find_next_bit((unsigned long *)ha->vp_idx_map,
+-	    MAX_MULTI_ID_FABRIC + 1, 1);
+-	for (;i <= MAX_MULTI_ID_FABRIC;
+-	    i = find_next_bit((unsigned long *)ha->vp_idx_map,
+-	    MAX_MULTI_ID_FABRIC + 1, i + 1)) {
++	for_each_mapped_vp_idx(ha, i) {
+ 		vp_idx_matched = 0;
  
-@@ -3795,7 +4028,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
- 		phba->fc_stat.elsRcvFLOGI++;
- 		lpfc_els_rcv_flogi(vport, elsiocb, ndlp);
- 		if (newnode)
--			lpfc_drop_node(vport, ndlp);
-+			lpfc_nlp_put(ndlp);
- 		break;
- 	case ELS_CMD_LOGO:
- 		lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
-@@ -3825,7 +4058,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
- 		phba->fc_stat.elsRcvRSCN++;
- 		lpfc_els_rcv_rscn(vport, elsiocb, ndlp);
- 		if (newnode)
--			lpfc_drop_node(vport, ndlp);
-+			lpfc_nlp_put(ndlp);
- 		break;
- 	case ELS_CMD_ADISC:
- 		lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
-@@ -3897,7 +4130,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
- 		phba->fc_stat.elsRcvLIRR++;
- 		lpfc_els_rcv_lirr(vport, elsiocb, ndlp);
- 		if (newnode)
--			lpfc_drop_node(vport, ndlp);
-+			lpfc_nlp_put(ndlp);
- 		break;
- 	case ELS_CMD_RPS:
- 		lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
-@@ -3907,7 +4140,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
- 		phba->fc_stat.elsRcvRPS++;
- 		lpfc_els_rcv_rps(vport, elsiocb, ndlp);
- 		if (newnode)
--			lpfc_drop_node(vport, ndlp);
-+			lpfc_nlp_put(ndlp);
- 		break;
- 	case ELS_CMD_RPL:
- 		lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
-@@ -3917,7 +4150,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
- 		phba->fc_stat.elsRcvRPL++;
- 		lpfc_els_rcv_rpl(vport, elsiocb, ndlp);
- 		if (newnode)
--			lpfc_drop_node(vport, ndlp);
-+			lpfc_nlp_put(ndlp);
- 		break;
- 	case ELS_CMD_RNID:
- 		lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
-@@ -3927,7 +4160,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
- 		phba->fc_stat.elsRcvRNID++;
- 		lpfc_els_rcv_rnid(vport, elsiocb, ndlp);
- 		if (newnode)
--			lpfc_drop_node(vport, ndlp);
-+			lpfc_nlp_put(ndlp);
- 		break;
- 	default:
- 		lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
-@@ -3942,7 +4175,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
- 				 "0115 Unknown ELS command x%x "
- 				 "received from NPORT x%x\n", cmd, did);
- 		if (newnode)
--			lpfc_drop_node(vport, ndlp);
-+			lpfc_nlp_put(ndlp);
- 		break;
+ 		list_for_each_entry(vha, &ha->vp_list, vp_list) {
+@@ -350,15 +341,17 @@ qla24xx_vport_create_req_sanity_check(struct fc_vport *fc_vport)
+ 
+ 	/* Check up unique WWPN */
+ 	u64_to_wwn(fc_vport->port_name, port_name);
++	if (!memcmp(port_name, ha->port_name, WWN_SIZE))
++		return VPCERR_BAD_WWN;
+ 	vha = qla24xx_find_vhost_by_name(ha, port_name);
+ 	if (vha)
+ 		return VPCERR_BAD_WWN;
+ 
+ 	/* Check up max-npiv-supports */
+ 	if (ha->num_vhosts > ha->max_npiv_vports) {
+-		DEBUG15(printk("scsi(%ld): num_vhosts %d is bigger than "
+-		    "max_npv_vports %d.\n", ha->host_no,
+-		    (uint16_t) ha->num_vhosts, (int) ha->max_npiv_vports));
++		DEBUG15(printk("scsi(%ld): num_vhosts %ud is bigger than "
++		    "max_npv_vports %ud.\n", ha->host_no,
++		    ha->num_vhosts, ha->max_npiv_vports));
+ 		return VPCERR_UNSUPPORTED;
+ 	}
+ 	return 0;
+@@ -412,8 +405,9 @@ qla24xx_create_vhost(struct fc_vport *fc_vport)
  	}
+ 	vha->mgmt_svr_loop_id = 10 + vha->vp_idx;
  
-@@ -3958,10 +4191,11 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
- 	return;
+-	init_MUTEX(&vha->mbx_cmd_sem);
+-	init_MUTEX_LOCKED(&vha->mbx_intr_sem);
++	init_completion(&vha->mbx_cmd_comp);
++	complete(&vha->mbx_cmd_comp);
++	init_completion(&vha->mbx_intr_comp);
  
- dropit:
--	lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
-+	if (vport && !(vport->load_flag & FC_UNLOADING))
-+		lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
- 			"(%d):0111 Dropping received ELS cmd "
- 			"Data: x%x x%x x%x\n",
--			vport ? vport->vpi : 0xffff, icmd->ulpStatus,
-+			vport->vpi, icmd->ulpStatus,
- 			icmd->un.ulpWord[4], icmd->ulpTimeout);
- 	phba->fc_stat.elsRcvDrop++;
- }
-@@ -4114,8 +4348,9 @@ lpfc_cmpl_reg_new_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
- 	struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) pmb->context2;
- 	MAILBOX_t *mb = &pmb->mb;
+ 	INIT_LIST_HEAD(&vha->list);
+ 	INIT_LIST_HEAD(&vha->fcports);
+@@ -450,7 +444,7 @@ qla24xx_create_vhost(struct fc_vport *fc_vport)
+ 	num_hosts++;
  
-+	spin_lock_irq(shost->host_lock);
- 	vport->fc_flag &= ~FC_VPORT_NEEDS_REG_VPI;
--	lpfc_nlp_put(ndlp);
-+	spin_unlock_irq(shost->host_lock);
+ 	down(&ha->vport_sem);
+-	set_bit(vha->vp_idx, (unsigned long *)ha->vp_idx_map);
++	set_bit(vha->vp_idx, ha->vp_idx_map);
+ 	ha->cur_vport_count++;
+ 	up(&ha->vport_sem);
  
- 	if (mb->mbxStatus) {
- 		lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX,
-@@ -4135,7 +4370,9 @@ lpfc_cmpl_reg_new_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
- 		default:
- 			/* Try to recover from this error */
- 			lpfc_mbx_unreg_vpi(vport);
-+			spin_lock_irq(shost->host_lock);
- 			vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
-+			spin_unlock_irq(shost->host_lock);
- 			lpfc_initial_fdisc(vport);
- 			break;
- 		}
-@@ -4146,14 +4383,21 @@ lpfc_cmpl_reg_new_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
- 		else
- 			lpfc_do_scr_ns_plogi(phba, vport);
- 	}
-+
-+	/* Now, we decrement the ndlp reference count held for this
-+	 * callback function
-+	 */
-+	lpfc_nlp_put(ndlp);
-+
- 	mempool_free(pmb, phba->mbox_mem_pool);
- 	return;
+diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
+index 8ecc047..aba1e6d 100644
+--- a/drivers/scsi/qla2xxx/qla_os.c
++++ b/drivers/scsi/qla2xxx/qla_os.c
+@@ -105,13 +105,12 @@ static int qla2xxx_eh_abort(struct scsi_cmnd *);
+ static int qla2xxx_eh_device_reset(struct scsi_cmnd *);
+ static int qla2xxx_eh_bus_reset(struct scsi_cmnd *);
+ static int qla2xxx_eh_host_reset(struct scsi_cmnd *);
+-static int qla2x00_loop_reset(scsi_qla_host_t *ha);
+ static int qla2x00_device_reset(scsi_qla_host_t *, fc_port_t *);
+ 
+ static int qla2x00_change_queue_depth(struct scsi_device *, int);
+ static int qla2x00_change_queue_type(struct scsi_device *, int);
+ 
+-struct scsi_host_template qla2x00_driver_template = {
++static struct scsi_host_template qla2x00_driver_template = {
+ 	.module			= THIS_MODULE,
+ 	.name			= QLA2XXX_DRIVER_NAME,
+ 	.queuecommand		= qla2x00_queuecommand,
+@@ -179,13 +178,6 @@ struct scsi_transport_template *qla2xxx_transport_vport_template = NULL;
+  * Timer routines
+  */
+ 
+-void qla2x00_timer(scsi_qla_host_t *);
+-
+-__inline__ void qla2x00_start_timer(scsi_qla_host_t *,
+-    void *, unsigned long);
+-static __inline__ void qla2x00_restart_timer(scsi_qla_host_t *, unsigned long);
+-__inline__ void qla2x00_stop_timer(scsi_qla_host_t *);
+-
+ __inline__ void
+ qla2x00_start_timer(scsi_qla_host_t *ha, void *func, unsigned long interval)
+ {
+@@ -203,7 +195,7 @@ qla2x00_restart_timer(scsi_qla_host_t *ha, unsigned long interval)
+ 	mod_timer(&ha->timer, jiffies + interval * HZ);
  }
  
--void
-+static void
- lpfc_register_new_vport(struct lpfc_hba *phba, struct lpfc_vport *vport,
- 			struct lpfc_nodelist *ndlp)
+-__inline__ void
++static __inline__ void
+ qla2x00_stop_timer(scsi_qla_host_t *ha)
  {
-+	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
- 	LPFC_MBOXQ_t *mbox;
+ 	del_timer_sync(&ha->timer);
+@@ -214,12 +206,11 @@ static int qla2x00_do_dpc(void *data);
  
- 	mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
-@@ -4162,25 +4406,31 @@ lpfc_register_new_vport(struct lpfc_hba *phba, struct lpfc_vport *vport,
- 		mbox->vport = vport;
- 		mbox->context2 = lpfc_nlp_get(ndlp);
- 		mbox->mbox_cmpl = lpfc_cmpl_reg_new_vport;
--		if (lpfc_sli_issue_mbox(phba, mbox,
--					MBX_NOWAIT | MBX_STOP_IOCB)
-+		if (lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT)
- 		    == MBX_NOT_FINISHED) {
-+			/* mailbox command not success, decrement ndlp
-+			 * reference count for this command
-+			 */
-+			lpfc_nlp_put(ndlp);
- 			mempool_free(mbox, phba->mbox_mem_pool);
--			vport->fc_flag &= ~FC_VPORT_NEEDS_REG_VPI;
+ static void qla2x00_rst_aen(scsi_qla_host_t *);
  
--			lpfc_vport_set_state(vport, FC_VPORT_FAILED);
- 			lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX,
- 				"0253 Register VPI: Can't send mbox\n");
-+			goto mbox_err_exit;
- 		}
- 	} else {
--		lpfc_vport_set_state(vport, FC_VPORT_FAILED);
--
- 		lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX,
- 				 "0254 Register VPI: no memory\n");
+-uint8_t qla2x00_mem_alloc(scsi_qla_host_t *);
+-void qla2x00_mem_free(scsi_qla_host_t *ha);
++static uint8_t qla2x00_mem_alloc(scsi_qla_host_t *);
++static void qla2x00_mem_free(scsi_qla_host_t *ha);
+ static int qla2x00_allocate_sp_pool( scsi_qla_host_t *ha);
+ static void qla2x00_free_sp_pool(scsi_qla_host_t *ha);
+ static void qla2x00_sp_free_dma(scsi_qla_host_t *, srb_t *);
+-void qla2x00_sp_compl(scsi_qla_host_t *ha, srb_t *);
+ 
+ /* -------------------------------------------------------------------------- */
+ 
+@@ -1060,7 +1051,7 @@ eh_host_reset_lock:
+ * Returns:
+ *      0 = success
+ */
+-static int
++int
+ qla2x00_loop_reset(scsi_qla_host_t *ha)
+ {
+ 	int ret;
+@@ -1479,8 +1470,7 @@ qla2x00_set_isp_flags(scsi_qla_host_t *ha)
+ static int
+ qla2x00_iospace_config(scsi_qla_host_t *ha)
+ {
+-	unsigned long	pio, pio_len, pio_flags;
+-	unsigned long	mmio, mmio_len, mmio_flags;
++	resource_size_t pio;
+ 
+ 	if (pci_request_selected_regions(ha->pdev, ha->bars,
+ 	    QLA2XXX_DRIVER_NAME)) {
+@@ -1495,10 +1485,8 @@ qla2x00_iospace_config(scsi_qla_host_t *ha)
+ 
+ 	/* We only need PIO for Flash operations on ISP2312 v2 chips. */
+ 	pio = pci_resource_start(ha->pdev, 0);
+-	pio_len = pci_resource_len(ha->pdev, 0);
+-	pio_flags = pci_resource_flags(ha->pdev, 0);
+-	if (pio_flags & IORESOURCE_IO) {
+-		if (pio_len < MIN_IOBASE_LEN) {
++	if (pci_resource_flags(ha->pdev, 0) & IORESOURCE_IO) {
++		if (pci_resource_len(ha->pdev, 0) < MIN_IOBASE_LEN) {
+ 			qla_printk(KERN_WARNING, ha,
+ 			    "Invalid PCI I/O region size (%s)...\n",
+ 				pci_name(ha->pdev));
+@@ -1511,28 +1499,23 @@ qla2x00_iospace_config(scsi_qla_host_t *ha)
+ 		pio = 0;
+ 	}
+ 	ha->pio_address = pio;
+-	ha->pio_length = pio_len;
+ 
+ skip_pio:
+ 	/* Use MMIO operations for all accesses. */
+-	mmio = pci_resource_start(ha->pdev, 1);
+-	mmio_len = pci_resource_len(ha->pdev, 1);
+-	mmio_flags = pci_resource_flags(ha->pdev, 1);
 -
--		vport->fc_flag &= ~FC_VPORT_NEEDS_REG_VPI;
--		lpfc_nlp_put(ndlp);
-+		goto mbox_err_exit;
+-	if (!(mmio_flags & IORESOURCE_MEM)) {
++	if (!(pci_resource_flags(ha->pdev, 1) & IORESOURCE_MEM)) {
+ 		qla_printk(KERN_ERR, ha,
+-		    "region #0 not an MMIO resource (%s), aborting\n",
++		    "region #1 not an MMIO resource (%s), aborting\n",
+ 		    pci_name(ha->pdev));
+ 		goto iospace_error_exit;
  	}
-+	return;
+-	if (mmio_len < MIN_IOBASE_LEN) {
++	if (pci_resource_len(ha->pdev, 1) < MIN_IOBASE_LEN) {
+ 		qla_printk(KERN_ERR, ha,
+ 		    "Invalid PCI mem region size (%s), aborting\n",
+ 			pci_name(ha->pdev));
+ 		goto iospace_error_exit;
+ 	}
+ 
+-	ha->iobase = ioremap(mmio, MIN_IOBASE_LEN);
++	ha->iobase = ioremap(pci_resource_start(ha->pdev, 1), MIN_IOBASE_LEN);
+ 	if (!ha->iobase) {
+ 		qla_printk(KERN_ERR, ha,
+ 		    "cannot remap MMIO (%s), aborting\n", pci_name(ha->pdev));
+@@ -1701,9 +1684,10 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
+ 	/* load the F/W, read paramaters, and init the H/W */
+ 	ha->instance = num_hosts;
+ 
+-	init_MUTEX(&ha->mbx_cmd_sem);
+ 	init_MUTEX(&ha->vport_sem);
+-	init_MUTEX_LOCKED(&ha->mbx_intr_sem);
++	init_completion(&ha->mbx_cmd_comp);
++	complete(&ha->mbx_cmd_comp);
++	init_completion(&ha->mbx_intr_comp);
+ 
+ 	INIT_LIST_HEAD(&ha->list);
+ 	INIT_LIST_HEAD(&ha->fcports);
+@@ -1807,6 +1791,8 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
+ 
+ 	qla2x00_init_host_attr(ha);
+ 
++	qla2x00_dfs_setup(ha);
 +
-+mbox_err_exit:
-+	lpfc_vport_set_state(vport, FC_VPORT_FAILED);
-+	spin_lock_irq(shost->host_lock);
-+	vport->fc_flag &= ~FC_VPORT_NEEDS_REG_VPI;
-+	spin_unlock_irq(shost->host_lock);
-+	return;
- }
+ 	qla_printk(KERN_INFO, ha, "\n"
+ 	    " QLogic Fibre Channel HBA Driver: %s\n"
+ 	    "  QLogic %s - %s\n"
+@@ -1838,6 +1824,8 @@ qla2x00_remove_one(struct pci_dev *pdev)
  
- static void
-@@ -4251,7 +4501,9 @@ lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
- 				lpfc_unreg_rpi(vport, np);
- 			}
- 			lpfc_mbx_unreg_vpi(vport);
-+			spin_lock_irq(shost->host_lock);
- 			vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
-+			spin_unlock_irq(shost->host_lock);
- 		}
+ 	ha = pci_get_drvdata(pdev);
  
- 		if (vport->fc_flag & FC_VPORT_NEEDS_REG_VPI)
-@@ -4259,14 +4511,15 @@ lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
- 		else
- 			lpfc_do_scr_ns_plogi(phba, vport);
++	qla2x00_dfs_remove(ha);
++
+ 	qla2x00_free_sysfs_attr(ha);
  
--		lpfc_nlp_put(ndlp); /* Free Fabric ndlp for vports */
-+		/* Unconditionaly kick off releasing fabric node for vports */
-+		lpfc_nlp_put(ndlp);
+ 	fc_remove_host(ha->host);
+@@ -1871,8 +1859,11 @@ qla2x00_free_device(scsi_qla_host_t *ha)
+ 		kthread_stop(t);
  	}
  
- out:
- 	lpfc_els_free_iocb(phba, cmdiocb);
- }
++	if (ha->flags.fce_enabled)
++		qla2x00_disable_fce_trace(ha, NULL, NULL);
++
+ 	if (ha->eft)
+-		qla2x00_trace_control(ha, TC_DISABLE, 0, 0);
++		qla2x00_disable_eft_trace(ha);
  
--int
-+static int
- lpfc_issue_els_fdisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
- 		     uint8_t retry)
+ 	ha->flags.online = 0;
+ 
+@@ -2016,7 +2007,7 @@ qla2x00_mark_all_devices_lost(scsi_qla_host_t *ha, int defer)
+ *      0  = success.
+ *      1  = failure.
+ */
+-uint8_t
++static uint8_t
+ qla2x00_mem_alloc(scsi_qla_host_t *ha)
  {
-@@ -4539,7 +4792,7 @@ lpfc_cmpl_fabric_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
- 	}
+ 	char	name[16];
+@@ -2213,7 +2204,7 @@ qla2x00_mem_alloc(scsi_qla_host_t *ha)
+ * Input:
+ *      ha = adapter block pointer.
+ */
+-void
++static void
+ qla2x00_mem_free(scsi_qla_host_t *ha)
+ {
+ 	struct list_head	*fcpl, *fcptemp;
+@@ -2228,6 +2219,10 @@ qla2x00_mem_free(scsi_qla_host_t *ha)
+ 	/* free sp pool */
+ 	qla2x00_free_sp_pool(ha);
+ 
++	if (ha->fce)
++		dma_free_coherent(&ha->pdev->dev, FCE_SIZE, ha->fce,
++		    ha->fce_dma);
++
+ 	if (ha->fw_dump) {
+ 		if (ha->eft)
+ 			dma_free_coherent(&ha->pdev->dev,
+@@ -2748,23 +2743,6 @@ qla2x00_timer(scsi_qla_host_t *ha)
+ 	qla2x00_restart_timer(ha, WATCH_INTERVAL);
  }
  
+-/* XXX(hch): crude hack to emulate a down_timeout() */
 -int
-+static int
- lpfc_issue_fabric_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *iocb)
+-qla2x00_down_timeout(struct semaphore *sema, unsigned long timeout)
+-{
+-	const unsigned int step = 100; /* msecs */
+-	unsigned int iterations = jiffies_to_msecs(timeout)/100;
+-
+-	do {
+-		if (!down_trylock(sema))
+-			return 0;
+-		if (msleep_interruptible(step))
+-			break;
+-	} while (--iterations > 0);
+-
+-	return -ETIMEDOUT;
+-}
+-
+ /* Firmware interface routines. */
+ 
+ #define FW_BLOBS	6
+diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c
+index ad2fa01..b68fb73 100644
+--- a/drivers/scsi/qla2xxx/qla_sup.c
++++ b/drivers/scsi/qla2xxx/qla_sup.c
+@@ -22,7 +22,7 @@ static void qla2x00_nv_write(scsi_qla_host_t *, uint16_t);
+  * qla2x00_lock_nvram_access() -
+  * @ha: HA context
+  */
+-void
++static void
+ qla2x00_lock_nvram_access(scsi_qla_host_t *ha)
  {
- 	unsigned long iflags;
-@@ -4583,7 +4836,7 @@ lpfc_issue_fabric_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *iocb)
- }
+ 	uint16_t data;
+@@ -55,7 +55,7 @@ qla2x00_lock_nvram_access(scsi_qla_host_t *ha)
+  * qla2x00_unlock_nvram_access() -
+  * @ha: HA context
+  */
+-void
++static void
+ qla2x00_unlock_nvram_access(scsi_qla_host_t *ha)
+ {
+ 	struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
+@@ -74,7 +74,7 @@ qla2x00_unlock_nvram_access(scsi_qla_host_t *ha)
+  *
+  * Returns the word read from nvram @addr.
+  */
+-uint16_t
++static uint16_t
+ qla2x00_get_nvram_word(scsi_qla_host_t *ha, uint32_t addr)
+ {
+ 	uint16_t	data;
+@@ -93,7 +93,7 @@ qla2x00_get_nvram_word(scsi_qla_host_t *ha, uint32_t addr)
+  * @addr: Address in NVRAM to write
+  * @data: word to program
+  */
+-void
++static void
+ qla2x00_write_nvram_word(scsi_qla_host_t *ha, uint32_t addr, uint16_t data)
+ {
+ 	int count;
+@@ -550,7 +550,7 @@ qla24xx_write_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr,
+ 	int ret;
+ 	uint32_t liter, miter;
+ 	uint32_t sec_mask, rest_addr, conf_addr;
+-	uint32_t fdata, findex ;
++	uint32_t fdata, findex, cnt;
+ 	uint8_t	man_id, flash_id;
+ 	struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
+ 	dma_addr_t optrom_dma;
+@@ -690,8 +690,14 @@ qla24xx_write_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr,
+ 			    0xff0000) | ((fdata >> 16) & 0xff));
+ 	}
  
+-	/* Enable flash write-protection. */
++	/* Enable flash write-protection and wait for completion. */
+ 	qla24xx_write_flash_dword(ha, flash_conf_to_access_addr(0x101), 0x9c);
++	for (cnt = 300; cnt &&
++	    qla24xx_read_flash_dword(ha,
++		    flash_conf_to_access_addr(0x005)) & BIT_0;
++	    cnt--) {
++		udelay(10);
++	}
  
--void lpfc_fabric_abort_vport(struct lpfc_vport *vport)
-+static void lpfc_fabric_abort_vport(struct lpfc_vport *vport)
- {
- 	LIST_HEAD(completions);
- 	struct lpfc_hba  *phba = vport->phba;
-@@ -4663,6 +4916,7 @@ void lpfc_fabric_abort_hba(struct lpfc_hba *phba)
- }
+ 	/* Disable flash write. */
+ 	WRT_REG_DWORD(&reg->ctrl_status,
+diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h
+index ae6f7a2..2c2f6b4 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.00-k5"
++#define QLA2XXX_VERSION      "8.02.00-k7"
  
+ #define QLA_DRIVER_MAJOR_VER	8
+ #define QLA_DRIVER_MINOR_VER	2
+diff --git a/drivers/scsi/qla4xxx/ql4_init.c b/drivers/scsi/qla4xxx/ql4_init.c
+index d692c71..cbe0a17 100644
+--- a/drivers/scsi/qla4xxx/ql4_init.c
++++ b/drivers/scsi/qla4xxx/ql4_init.c
+@@ -5,6 +5,7 @@
+  * See LICENSE.qla4xxx for copyright and licensing details.
+  */
  
-+#if 0
- void lpfc_fabric_abort_flogi(struct lpfc_hba *phba)
- {
- 	LIST_HEAD(completions);
-@@ -4693,5 +4947,6 @@ void lpfc_fabric_abort_flogi(struct lpfc_hba *phba)
- 		(piocb->iocb_cmpl) (phba, piocb, piocb);
- 	}
- }
-+#endif  /*  0  */
++#include <scsi/iscsi_if.h>
+ #include "ql4_def.h"
+ #include "ql4_glbl.h"
+ #include "ql4_dbg.h"
+@@ -1305,7 +1306,8 @@ int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha,
+ 		atomic_set(&ddb_entry->relogin_timer, 0);
+ 		clear_bit(DF_RELOGIN, &ddb_entry->flags);
+ 		clear_bit(DF_NO_RELOGIN, &ddb_entry->flags);
+-		iscsi_if_create_session_done(ddb_entry->conn);
++		iscsi_session_event(ddb_entry->sess,
++				    ISCSI_KEVENT_CREATE_SESSION);
+ 		/*
+ 		 * Change the lun state to READY in case the lun TIMEOUT before
+ 		 * the device came back.
+diff --git a/drivers/scsi/qla4xxx/ql4_isr.c b/drivers/scsi/qla4xxx/ql4_isr.c
+index 4a154be..0f029d0 100644
+--- a/drivers/scsi/qla4xxx/ql4_isr.c
++++ b/drivers/scsi/qla4xxx/ql4_isr.c
+@@ -123,15 +123,14 @@ static void qla4xxx_status_entry(struct scsi_qla_host *ha,
+ 			break;
  
+ 		/* Copy Sense Data into sense buffer. */
+-		memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer));
++		memset(cmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
  
-diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c
-index c81c2b3..dc042bd 100644
---- a/drivers/scsi/lpfc/lpfc_hbadisc.c
-+++ b/drivers/scsi/lpfc/lpfc_hbadisc.c
-@@ -57,6 +57,7 @@ static uint8_t lpfcAlpaArray[] = {
- };
+ 		sensebytecnt = le16_to_cpu(sts_entry->senseDataByteCnt);
+ 		if (sensebytecnt == 0)
+ 			break;
  
- static void lpfc_disc_timeout_handler(struct lpfc_vport *);
-+static void lpfc_disc_flush_list(struct lpfc_vport *vport);
+ 		memcpy(cmd->sense_buffer, sts_entry->senseData,
+-		       min(sensebytecnt,
+-			   (uint16_t) sizeof(cmd->sense_buffer)));
++		       min_t(uint16_t, sensebytecnt, SCSI_SENSE_BUFFERSIZE));
  
- void
- lpfc_terminate_rport_io(struct fc_rport *rport)
-@@ -107,20 +108,14 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport)
- 	struct lpfc_nodelist * ndlp;
- 	struct lpfc_vport *vport;
- 	struct lpfc_hba   *phba;
--	struct completion devloss_compl;
- 	struct lpfc_work_evt *evtp;
-+	int  put_node;
-+	int  put_rport;
+ 		DEBUG2(printk("scsi%ld:%d:%d:%d: %s: sense key = %x, "
+ 			      "ASC/ASCQ = %02x/%02x\n", ha->host_no,
+@@ -208,8 +207,7 @@ static void qla4xxx_status_entry(struct scsi_qla_host *ha,
+ 				break;
  
- 	rdata = rport->dd_data;
- 	ndlp = rdata->pnode;
--
--	if (!ndlp) {
--		if (rport->scsi_target_id != -1) {
--			printk(KERN_ERR "Cannot find remote node"
--				" for rport in dev_loss_tmo_callbk x%x\n",
--				rport->port_id);
--		}
-+	if (!ndlp)
- 		return;
--	}
+ 			/* Copy Sense Data into sense buffer. */
+-			memset(cmd->sense_buffer, 0,
+-			       sizeof(cmd->sense_buffer));
++			memset(cmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
  
- 	vport = ndlp->vport;
- 	phba  = vport->phba;
-@@ -129,15 +124,35 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport)
- 		"rport devlosscb: sid:x%x did:x%x flg:x%x",
- 		ndlp->nlp_sid, ndlp->nlp_DID, ndlp->nlp_flag);
+ 			sensebytecnt =
+ 				le16_to_cpu(sts_entry->senseDataByteCnt);
+@@ -217,8 +215,7 @@ static void qla4xxx_status_entry(struct scsi_qla_host *ha,
+ 				break;
  
--	init_completion(&devloss_compl);
-+	/* Don't defer this if we are in the process of deleting the vport
-+	 * or unloading the driver. The unload will cleanup the node
-+	 * appropriately we just need to cleanup the ndlp rport info here.
-+	 */
-+	if (vport->load_flag & FC_UNLOADING) {
-+		put_node = rdata->pnode != NULL;
-+		put_rport = ndlp->rport != NULL;
-+		rdata->pnode = NULL;
-+		ndlp->rport = NULL;
-+		if (put_node)
-+			lpfc_nlp_put(ndlp);
-+		if (put_rport)
-+			put_device(&rport->dev);
-+		return;
-+	}
-+
-+	if (ndlp->nlp_state == NLP_STE_MAPPED_NODE)
-+		return;
-+
- 	evtp = &ndlp->dev_loss_evt;
+ 			memcpy(cmd->sense_buffer, sts_entry->senseData,
+-			       min(sensebytecnt,
+-				   (uint16_t) sizeof(cmd->sense_buffer)));
++			       min_t(uint16_t, sensebytecnt, SCSI_SENSE_BUFFERSIZE));
  
- 	if (!list_empty(&evtp->evt_listp))
+ 			DEBUG2(printk("scsi%ld:%d:%d:%d: %s: sense key = %x, "
+ 				      "ASC/ASCQ = %02x/%02x\n", ha->host_no,
+diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c
+index 89460d2..f55b9f7 100644
+--- a/drivers/scsi/qla4xxx/ql4_os.c
++++ b/drivers/scsi/qla4xxx/ql4_os.c
+@@ -298,8 +298,7 @@ void qla4xxx_destroy_sess(struct ddb_entry *ddb_entry)
  		return;
  
- 	spin_lock_irq(&phba->hbalock);
--	evtp->evt_arg1  = ndlp;
--	evtp->evt_arg2  = &devloss_compl;
-+	/* We need to hold the node by incrementing the reference
-+	 * count until this queued work is done
-+	 */
-+	evtp->evt_arg1  = lpfc_nlp_get(ndlp);
- 	evtp->evt       = LPFC_EVT_DEV_LOSS;
- 	list_add_tail(&evtp->evt_listp, &phba->work_list);
- 	if (phba->work_wait)
-@@ -145,8 +160,6 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport)
- 
- 	spin_unlock_irq(&phba->hbalock);
+ 	if (ddb_entry->conn) {
+-		iscsi_if_destroy_session_done(ddb_entry->conn);
+-		iscsi_destroy_conn(ddb_entry->conn);
++		atomic_set(&ddb_entry->state, DDB_STATE_DEAD);
+ 		iscsi_remove_session(ddb_entry->sess);
+ 	}
+ 	iscsi_free_session(ddb_entry->sess);
+@@ -309,6 +308,7 @@ int qla4xxx_add_sess(struct ddb_entry *ddb_entry)
+ {
+ 	int err;
  
--	wait_for_completion(&devloss_compl);
++	ddb_entry->sess->recovery_tmo = ddb_entry->ha->port_down_retry_count;
+ 	err = iscsi_add_session(ddb_entry->sess, ddb_entry->fw_ddb_index);
+ 	if (err) {
+ 		DEBUG2(printk(KERN_ERR "Could not add session.\n"));
+@@ -321,9 +321,6 @@ int qla4xxx_add_sess(struct ddb_entry *ddb_entry)
+ 		DEBUG2(printk(KERN_ERR "Could not add connection.\n"));
+ 		return -ENOMEM;
+ 	}
 -
- 	return;
+-	ddb_entry->sess->recovery_tmo = ddb_entry->ha->port_down_retry_count;
+-	iscsi_if_create_session_done(ddb_entry->conn);
+ 	return 0;
  }
  
-@@ -154,7 +167,7 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport)
-  * This function is called from the worker thread when dev_loss_tmo
-  * expire.
-  */
--void
-+static void
- lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp)
+diff --git a/drivers/scsi/qlogicpti.c b/drivers/scsi/qlogicpti.c
+index 7a2e798..65455ab 100644
+--- a/drivers/scsi/qlogicpti.c
++++ b/drivers/scsi/qlogicpti.c
+@@ -871,11 +871,12 @@ static inline int load_cmd(struct scsi_cmnd *Cmnd, struct Command_Entry *cmd,
+ 	struct scatterlist *sg, *s;
+ 	int i, n;
+ 
+-	if (Cmnd->use_sg) {
++	if (scsi_bufflen(Cmnd)) {
+ 		int sg_count;
+ 
+-		sg = (struct scatterlist *) Cmnd->request_buffer;
+-		sg_count = sbus_map_sg(qpti->sdev, sg, Cmnd->use_sg, Cmnd->sc_data_direction);
++		sg = scsi_sglist(Cmnd);
++		sg_count = sbus_map_sg(qpti->sdev, sg, scsi_sg_count(Cmnd),
++		                                      Cmnd->sc_data_direction);
+ 
+ 		ds = cmd->dataseg;
+ 		cmd->segment_cnt = sg_count;
+@@ -914,16 +915,6 @@ static inline int load_cmd(struct scsi_cmnd *Cmnd, struct Command_Entry *cmd,
+ 			}
+ 			sg_count -= n;
+ 		}
+-	} else if (Cmnd->request_bufflen) {
+-		Cmnd->SCp.ptr = (char *)(unsigned long)
+-			sbus_map_single(qpti->sdev,
+-					Cmnd->request_buffer,
+-					Cmnd->request_bufflen,
+-					Cmnd->sc_data_direction);
+-
+-		cmd->dataseg[0].d_base = (u32) ((unsigned long)Cmnd->SCp.ptr);
+-		cmd->dataseg[0].d_count = Cmnd->request_bufflen;
+-		cmd->segment_cnt = 1;
+ 	} else {
+ 		cmd->dataseg[0].d_base = 0;
+ 		cmd->dataseg[0].d_count = 0;
+@@ -1151,7 +1142,7 @@ static struct scsi_cmnd *qlogicpti_intr_handler(struct qlogicpti *qpti)
+ 
+ 		if (sts->state_flags & SF_GOT_SENSE)
+ 			memcpy(Cmnd->sense_buffer, sts->req_sense_data,
+-			       sizeof(Cmnd->sense_buffer));
++			       SCSI_SENSE_BUFFERSIZE);
+ 
+ 		if (sts->hdr.entry_type == ENTRY_STATUS)
+ 			Cmnd->result =
+@@ -1159,17 +1150,11 @@ static struct scsi_cmnd *qlogicpti_intr_handler(struct qlogicpti *qpti)
+ 		else
+ 			Cmnd->result = DID_ERROR << 16;
+ 
+-		if (Cmnd->use_sg) {
++		if (scsi_bufflen(Cmnd))
+ 			sbus_unmap_sg(qpti->sdev,
+-				      (struct scatterlist *)Cmnd->request_buffer,
+-				      Cmnd->use_sg,
++				      scsi_sglist(Cmnd), scsi_sg_count(Cmnd),
+ 				      Cmnd->sc_data_direction);
+-		} else if (Cmnd->request_bufflen) {
+-			sbus_unmap_single(qpti->sdev,
+-					  (__u32)((unsigned long)Cmnd->SCp.ptr),
+-					  Cmnd->request_bufflen,
+-					  Cmnd->sc_data_direction);
+-		}
++
+ 		qpti->cmd_count[Cmnd->device->id]--;
+ 		sbus_writew(out_ptr, qpti->qregs + MBOX5);
+ 		Cmnd->host_scribble = (unsigned char *) done_queue;
+diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
+index 0fb1709..1a9fba6 100644
+--- a/drivers/scsi/scsi.c
++++ b/drivers/scsi/scsi.c
+@@ -122,6 +122,11 @@ static const char *const scsi_device_types[] = {
+ 	"Automation/Drive ",
+ };
+ 
++/**
++ * scsi_device_type - Return 17 char string indicating device type.
++ * @type: type number to look up
++ */
++
+ const char * scsi_device_type(unsigned type)
  {
- 	struct lpfc_rport_data *rdata;
-@@ -162,6 +175,8 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp)
- 	struct lpfc_vport *vport;
- 	struct lpfc_hba   *phba;
- 	uint8_t *name;
-+	int  put_node;
-+	int  put_rport;
- 	int warn_on = 0;
+ 	if (type == 0x1e)
+@@ -136,32 +141,45 @@ const char * scsi_device_type(unsigned type)
+ EXPORT_SYMBOL(scsi_device_type);
  
- 	rport = ndlp->rport;
-@@ -178,14 +193,32 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp)
- 		"rport devlosstmo:did:x%x type:x%x id:x%x",
- 		ndlp->nlp_DID, ndlp->nlp_type, rport->scsi_target_id);
+ struct scsi_host_cmd_pool {
+-	struct kmem_cache	*slab;
+-	unsigned int	users;
+-	char		*name;
+-	unsigned int	slab_flags;
+-	gfp_t		gfp_mask;
++	struct kmem_cache	*cmd_slab;
++	struct kmem_cache	*sense_slab;
++	unsigned int		users;
++	char			*cmd_name;
++	char			*sense_name;
++	unsigned int		slab_flags;
++	gfp_t			gfp_mask;
+ };
  
--	if (!(vport->load_flag & FC_UNLOADING) &&
--	    ndlp->nlp_state == NLP_STE_MAPPED_NODE)
-+	/* Don't defer this if we are in the process of deleting the vport
-+	 * or unloading the driver. The unload will cleanup the node
-+	 * appropriately we just need to cleanup the ndlp rport info here.
-+	 */
-+	if (vport->load_flag & FC_UNLOADING) {
-+		if (ndlp->nlp_sid != NLP_NO_SID) {
-+			/* flush the target */
-+			lpfc_sli_abort_iocb(vport,
-+					&phba->sli.ring[phba->sli.fcp_ring],
-+					ndlp->nlp_sid, 0, LPFC_CTX_TGT);
-+		}
-+		put_node = rdata->pnode != NULL;
-+		put_rport = ndlp->rport != NULL;
-+		rdata->pnode = NULL;
-+		ndlp->rport = NULL;
-+		if (put_node)
-+			lpfc_nlp_put(ndlp);
-+		if (put_rport)
-+			put_device(&rport->dev);
- 		return;
-+	}
+ static struct scsi_host_cmd_pool scsi_cmd_pool = {
+-	.name		= "scsi_cmd_cache",
++	.cmd_name	= "scsi_cmd_cache",
++	.sense_name	= "scsi_sense_cache",
+ 	.slab_flags	= SLAB_HWCACHE_ALIGN,
+ };
+ 
+ static struct scsi_host_cmd_pool scsi_cmd_dma_pool = {
+-	.name		= "scsi_cmd_cache(DMA)",
++	.cmd_name	= "scsi_cmd_cache(DMA)",
++	.sense_name	= "scsi_sense_cache(DMA)",
+ 	.slab_flags	= SLAB_HWCACHE_ALIGN|SLAB_CACHE_DMA,
+ 	.gfp_mask	= __GFP_DMA,
+ };
  
--	if (ndlp->nlp_type & NLP_FABRIC) {
--		int  put_node;
--		int  put_rport;
-+	if (ndlp->nlp_state == NLP_STE_MAPPED_NODE)
-+		return;
+ static DEFINE_MUTEX(host_cmd_pool_mutex);
  
-+	if (ndlp->nlp_type & NLP_FABRIC) {
- 		/* We will clean up these Nodes in linkup */
- 		put_node = rdata->pnode != NULL;
- 		put_rport = ndlp->rport != NULL;
-@@ -227,23 +260,20 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp)
- 				 ndlp->nlp_state, ndlp->nlp_rpi);
- 	}
++/**
++ * __scsi_get_command - Allocate a struct scsi_cmnd
++ * @shost: host to transmit command
++ * @gfp_mask: allocation mask
++ *
++ * Description: allocate a struct scsi_cmd from host's slab, recycling from the
++ *              host's free_list if necessary.
++ */
+ struct scsi_cmnd *__scsi_get_command(struct Scsi_Host *shost, gfp_t gfp_mask)
+ {
+ 	struct scsi_cmnd *cmd;
++	unsigned char *buf;
  
-+	put_node = rdata->pnode != NULL;
-+	put_rport = ndlp->rport != NULL;
-+	rdata->pnode = NULL;
-+	ndlp->rport = NULL;
-+	if (put_node)
-+		lpfc_nlp_put(ndlp);
-+	if (put_rport)
-+		put_device(&rport->dev);
+-	cmd = kmem_cache_alloc(shost->cmd_pool->slab,
+-			gfp_mask | shost->cmd_pool->gfp_mask);
++	cmd = kmem_cache_alloc(shost->cmd_pool->cmd_slab,
++			       gfp_mask | shost->cmd_pool->gfp_mask);
+ 
+ 	if (unlikely(!cmd)) {
+ 		unsigned long flags;
+@@ -173,19 +191,32 @@ struct scsi_cmnd *__scsi_get_command(struct Scsi_Host *shost, gfp_t gfp_mask)
+ 			list_del_init(&cmd->list);
+ 		}
+ 		spin_unlock_irqrestore(&shost->free_list_lock, flags);
 +
- 	if (!(vport->load_flag & FC_UNLOADING) &&
- 	    !(ndlp->nlp_flag & NLP_DELAY_TMO) &&
- 	    !(ndlp->nlp_flag & NLP_NPR_2B_DISC) &&
--	    (ndlp->nlp_state != NLP_STE_UNMAPPED_NODE))
-+	    (ndlp->nlp_state != NLP_STE_UNMAPPED_NODE)) {
- 		lpfc_disc_state_machine(vport, ndlp, NULL, NLP_EVT_DEVICE_RM);
--	else {
--		int  put_node;
--		int  put_rport;
--
--		put_node = rdata->pnode != NULL;
--		put_rport = ndlp->rport != NULL;
--		rdata->pnode = NULL;
--		ndlp->rport = NULL;
--		if (put_node)
--			lpfc_nlp_put(ndlp);
--		if (put_rport)
--			put_device(&rport->dev);
++		if (cmd) {
++			buf = cmd->sense_buffer;
++			memset(cmd, 0, sizeof(*cmd));
++			cmd->sense_buffer = buf;
++		}
++	} else {
++		buf = kmem_cache_alloc(shost->cmd_pool->sense_slab,
++				       gfp_mask | shost->cmd_pool->gfp_mask);
++		if (likely(buf)) {
++			memset(cmd, 0, sizeof(*cmd));
++			cmd->sense_buffer = buf;
++		} else {
++			kmem_cache_free(shost->cmd_pool->cmd_slab, cmd);
++			cmd = NULL;
++		}
  	}
+ 
+ 	return cmd;
  }
+ EXPORT_SYMBOL_GPL(__scsi_get_command);
  
-@@ -260,7 +290,6 @@ lpfc_work_list_done(struct lpfc_hba *phba)
- {
- 	struct lpfc_work_evt  *evtp = NULL;
- 	struct lpfc_nodelist  *ndlp;
--	struct lpfc_vport     *vport;
- 	int free_evt;
+-/*
+- * Function:	scsi_get_command()
+- *
+- * Purpose:	Allocate and setup a scsi command block
+- *
+- * Arguments:	dev	- parent scsi device
+- *		gfp_mask- allocator flags
++/**
++ * scsi_get_command - Allocate and setup a scsi command block
++ * @dev: parent scsi device
++ * @gfp_mask: allocator flags
+  *
+  * Returns:	The allocated scsi command structure.
+  */
+@@ -202,7 +233,6 @@ struct scsi_cmnd *scsi_get_command(struct scsi_device *dev, gfp_t gfp_mask)
+ 	if (likely(cmd != NULL)) {
+ 		unsigned long flags;
  
- 	spin_lock_irq(&phba->hbalock);
-@@ -270,35 +299,22 @@ lpfc_work_list_done(struct lpfc_hba *phba)
- 		spin_unlock_irq(&phba->hbalock);
- 		free_evt = 1;
- 		switch (evtp->evt) {
--		case LPFC_EVT_DEV_LOSS_DELAY:
--			free_evt = 0; /* evt is part of ndlp */
--			ndlp = (struct lpfc_nodelist *) (evtp->evt_arg1);
--			vport = ndlp->vport;
--			if (!vport)
--				break;
--
--			lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_RPORT,
--				"rport devlossdly:did:x%x flg:x%x",
--				ndlp->nlp_DID, ndlp->nlp_flag, 0);
--
--			if (!(vport->load_flag & FC_UNLOADING) &&
--			    !(ndlp->nlp_flag & NLP_DELAY_TMO) &&
--			    !(ndlp->nlp_flag & NLP_NPR_2B_DISC)) {
--				lpfc_disc_state_machine(vport, ndlp, NULL,
--					NLP_EVT_DEVICE_RM);
--			}
--			break;
- 		case LPFC_EVT_ELS_RETRY:
- 			ndlp = (struct lpfc_nodelist *) (evtp->evt_arg1);
- 			lpfc_els_retry_delay_handler(ndlp);
- 			free_evt = 0; /* evt is part of ndlp */
-+			/* decrement the node reference count held
-+			 * for this queued work
-+			 */
-+			lpfc_nlp_put(ndlp);
- 			break;
- 		case LPFC_EVT_DEV_LOSS:
- 			ndlp = (struct lpfc_nodelist *)(evtp->evt_arg1);
--			lpfc_nlp_get(ndlp);
- 			lpfc_dev_loss_tmo_handler(ndlp);
- 			free_evt = 0;
--			complete((struct completion *)(evtp->evt_arg2));
-+			/* decrement the node reference count held for
-+			 * this queued work
-+			 */
- 			lpfc_nlp_put(ndlp);
- 			break;
- 		case LPFC_EVT_ONLINE:
-@@ -373,7 +389,7 @@ lpfc_work_done(struct lpfc_hba *phba)
- 		lpfc_handle_latt(phba);
- 	vports = lpfc_create_vport_work_array(phba);
- 	if (vports != NULL)
--		for(i = 0; i < LPFC_MAX_VPORTS; i++) {
-+		for(i = 0; i <= phba->max_vpi; i++) {
- 			/*
- 			 * We could have no vports in array if unloading, so if
- 			 * this happens then just use the pport
-@@ -405,14 +421,14 @@ lpfc_work_done(struct lpfc_hba *phba)
- 			vport->work_port_events &= ~work_port_events;
- 			spin_unlock_irq(&vport->work_port_lock);
- 		}
--	lpfc_destroy_vport_work_array(vports);
-+	lpfc_destroy_vport_work_array(phba, vports);
+-		memset(cmd, 0, sizeof(*cmd));
+ 		cmd->device = dev;
+ 		init_timer(&cmd->eh_timeout);
+ 		INIT_LIST_HEAD(&cmd->list);
+@@ -217,6 +247,12 @@ struct scsi_cmnd *scsi_get_command(struct scsi_device *dev, gfp_t gfp_mask)
+ }
+ EXPORT_SYMBOL(scsi_get_command);
  
- 	pring = &phba->sli.ring[LPFC_ELS_RING];
- 	status = (ha_copy & (HA_RXMASK  << (4*LPFC_ELS_RING)));
- 	status >>= (4*LPFC_ELS_RING);
- 	if ((status & HA_RXMASK)
- 		|| (pring->flag & LPFC_DEFERRED_RING_EVENT)) {
--		if (pring->flag & LPFC_STOP_IOCB_MASK) {
-+		if (pring->flag & LPFC_STOP_IOCB_EVENT) {
- 			pring->flag |= LPFC_DEFERRED_RING_EVENT;
- 		} else {
- 			lpfc_sli_handle_slow_ring_event(phba, pring,
-@@ -544,6 +560,7 @@ lpfc_workq_post_event(struct lpfc_hba *phba, void *arg1, void *arg2,
- void
- lpfc_cleanup_rpis(struct lpfc_vport *vport, int remove)
++/**
++ * __scsi_put_command - Free a struct scsi_cmnd
++ * @shost: dev->host
++ * @cmd: Command to free
++ * @dev: parent scsi device
++ */
+ void __scsi_put_command(struct Scsi_Host *shost, struct scsi_cmnd *cmd,
+ 			struct device *dev)
  {
-+	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
- 	struct lpfc_hba  *phba = vport->phba;
- 	struct lpfc_nodelist *ndlp, *next_ndlp;
- 	int  rc;
-@@ -552,7 +569,9 @@ lpfc_cleanup_rpis(struct lpfc_vport *vport, int remove)
- 		if (ndlp->nlp_state == NLP_STE_UNUSED_NODE)
- 			continue;
+@@ -230,19 +266,19 @@ void __scsi_put_command(struct Scsi_Host *shost, struct scsi_cmnd *cmd,
+ 	}
+ 	spin_unlock_irqrestore(&shost->free_list_lock, flags);
  
--		if (phba->sli3_options & LPFC_SLI3_VPORT_TEARDOWN)
-+		if ((phba->sli3_options & LPFC_SLI3_VPORT_TEARDOWN) ||
-+			((vport->port_type == LPFC_NPIV_PORT) &&
-+			(ndlp->nlp_DID == NameServer_DID)))
- 			lpfc_unreg_rpi(vport, ndlp);
+-	if (likely(cmd != NULL))
+-		kmem_cache_free(shost->cmd_pool->slab, cmd);
++	if (likely(cmd != NULL)) {
++		kmem_cache_free(shost->cmd_pool->sense_slab,
++				cmd->sense_buffer);
++		kmem_cache_free(shost->cmd_pool->cmd_slab, cmd);
++	}
  
- 		/* Leave Fabric nodes alone on link down */
-@@ -565,14 +584,30 @@ lpfc_cleanup_rpis(struct lpfc_vport *vport, int remove)
- 	}
- 	if (phba->sli3_options & LPFC_SLI3_VPORT_TEARDOWN) {
- 		lpfc_mbx_unreg_vpi(vport);
-+		spin_lock_irq(shost->host_lock);
- 		vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
-+		spin_unlock_irq(shost->host_lock);
- 	}
+ 	put_device(dev);
  }
+ EXPORT_SYMBOL(__scsi_put_command);
  
-+void
-+lpfc_port_link_failure(struct lpfc_vport *vport)
-+{
-+	/* Cleanup any outstanding RSCN activity */
-+	lpfc_els_flush_rscn(vport);
-+
-+	/* Cleanup any outstanding ELS commands */
-+	lpfc_els_flush_cmd(vport);
+-/*
+- * Function:	scsi_put_command()
+- *
+- * Purpose:	Free a scsi command block
+- *
+- * Arguments:	cmd	- command block to free
++/**
++ * scsi_put_command - Free a scsi command block
++ * @cmd: command block to free
+  *
+  * Returns:	Nothing.
+  *
+@@ -263,12 +299,13 @@ void scsi_put_command(struct scsi_cmnd *cmd)
+ }
+ EXPORT_SYMBOL(scsi_put_command);
+ 
+-/*
+- * Function:	scsi_setup_command_freelist()
+- *
+- * Purpose:	Setup the command freelist for a scsi host.
++/**
++ * scsi_setup_command_freelist - Setup the command freelist for a scsi host.
++ * @shost: host to allocate the freelist for.
+  *
+- * Arguments:	shost	- host to allocate the freelist for.
++ * Description: The command freelist protects against system-wide out of memory
++ * deadlock by preallocating one SCSI command structure for each host, so the
++ * system can always write to a swap file on a device associated with that host.
+  *
+  * Returns:	Nothing.
+  */
+@@ -282,16 +319,24 @@ int scsi_setup_command_freelist(struct Scsi_Host *shost)
+ 
+ 	/*
+ 	 * Select a command slab for this host and create it if not
+-	 * yet existant.
++	 * yet existent.
+ 	 */
+ 	mutex_lock(&host_cmd_pool_mutex);
+ 	pool = (shost->unchecked_isa_dma ? &scsi_cmd_dma_pool : &scsi_cmd_pool);
+ 	if (!pool->users) {
+-		pool->slab = kmem_cache_create(pool->name,
+-				sizeof(struct scsi_cmnd), 0,
+-				pool->slab_flags, NULL);
+-		if (!pool->slab)
++		pool->cmd_slab = kmem_cache_create(pool->cmd_name,
++						   sizeof(struct scsi_cmnd), 0,
++						   pool->slab_flags, NULL);
++		if (!pool->cmd_slab)
++			goto fail;
 +
-+	lpfc_cleanup_rpis(vport, 0);
++		pool->sense_slab = kmem_cache_create(pool->sense_name,
++						     SCSI_SENSE_BUFFERSIZE, 0,
++						     pool->slab_flags, NULL);
++		if (!pool->sense_slab) {
++			kmem_cache_destroy(pool->cmd_slab);
+ 			goto fail;
++		}
+ 	}
+ 
+ 	pool->users++;
+@@ -301,29 +346,36 @@ int scsi_setup_command_freelist(struct Scsi_Host *shost)
+ 	/*
+ 	 * Get one backup command for this host.
+ 	 */
+-	cmd = kmem_cache_alloc(shost->cmd_pool->slab,
+-			GFP_KERNEL | shost->cmd_pool->gfp_mask);
++	cmd = kmem_cache_alloc(shost->cmd_pool->cmd_slab,
++			       GFP_KERNEL | shost->cmd_pool->gfp_mask);
+ 	if (!cmd)
+ 		goto fail2;
+-	list_add(&cmd->list, &shost->free_list);		
 +
-+	/* Turn off discovery timer if its running */
-+	lpfc_can_disctmo(vport);
-+}
++	cmd->sense_buffer = kmem_cache_alloc(shost->cmd_pool->sense_slab,
++					     GFP_KERNEL |
++					     shost->cmd_pool->gfp_mask);
++	if (!cmd->sense_buffer)
++		goto fail2;
 +
- static void
- lpfc_linkdown_port(struct lpfc_vport *vport)
- {
--	struct lpfc_nodelist *ndlp, *next_ndlp;
- 	struct Scsi_Host  *shost = lpfc_shost_from_vport(vport);
- 
- 	fc_host_post_event(shost, fc_get_event_number(), FCH_EVT_LINKDOWN, 0);
-@@ -581,21 +616,8 @@ lpfc_linkdown_port(struct lpfc_vport *vport)
- 		"Link Down:       state:x%x rtry:x%x flg:x%x",
- 		vport->port_state, vport->fc_ns_retry, vport->fc_flag);
- 
--	/* Cleanup any outstanding RSCN activity */
--	lpfc_els_flush_rscn(vport);
--
--	/* Cleanup any outstanding ELS commands */
--	lpfc_els_flush_cmd(vport);
-+	lpfc_port_link_failure(vport);
++	list_add(&cmd->list, &shost->free_list);
+ 	return 0;
  
--	lpfc_cleanup_rpis(vport, 0);
--
--	/* free any ndlp's on unused list */
--	list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp)
--		if (ndlp->nlp_state == NLP_STE_UNUSED_NODE)
--			lpfc_drop_node(vport, ndlp);
+  fail2:
+-	if (!--pool->users)
+-		kmem_cache_destroy(pool->slab);
+-	return -ENOMEM;
++	if (cmd)
++		kmem_cache_free(shost->cmd_pool->cmd_slab, cmd);
++	mutex_lock(&host_cmd_pool_mutex);
++	if (!--pool->users) {
++		kmem_cache_destroy(pool->cmd_slab);
++		kmem_cache_destroy(pool->sense_slab);
++	}
+  fail:
+ 	mutex_unlock(&host_cmd_pool_mutex);
+ 	return -ENOMEM;
 -
--	/* Turn off discovery timer if its running */
--	lpfc_can_disctmo(vport);
  }
  
- int
-@@ -618,18 +640,18 @@ lpfc_linkdown(struct lpfc_hba *phba)
- 	spin_unlock_irq(&phba->hbalock);
- 	vports = lpfc_create_vport_work_array(phba);
- 	if (vports != NULL)
--		for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++) {
-+		for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) {
- 			/* Issue a LINK DOWN event to all nodes */
- 			lpfc_linkdown_port(vports[i]);
- 		}
--	lpfc_destroy_vport_work_array(vports);
-+	lpfc_destroy_vport_work_array(phba, vports);
- 	/* Clean up any firmware default rpi's */
- 	mb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
- 	if (mb) {
- 		lpfc_unreg_did(phba, 0xffff, 0xffffffff, mb);
- 		mb->vport = vport;
- 		mb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
--		if (lpfc_sli_issue_mbox(phba, mb, (MBX_NOWAIT | MBX_STOP_IOCB))
-+		if (lpfc_sli_issue_mbox(phba, mb, MBX_NOWAIT)
- 		    == MBX_NOT_FINISHED) {
- 			mempool_free(mb, phba->mbox_mem_pool);
- 		}
-@@ -643,8 +665,7 @@ lpfc_linkdown(struct lpfc_hba *phba)
- 			lpfc_config_link(phba, mb);
- 			mb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
- 			mb->vport = vport;
--			if (lpfc_sli_issue_mbox(phba, mb,
--						(MBX_NOWAIT | MBX_STOP_IOCB))
-+			if (lpfc_sli_issue_mbox(phba, mb, MBX_NOWAIT)
- 			    == MBX_NOT_FINISHED) {
- 				mempool_free(mb, phba->mbox_mem_pool);
- 			}
-@@ -686,7 +707,6 @@ static void
- lpfc_linkup_port(struct lpfc_vport *vport)
+-/*
+- * Function:	scsi_destroy_command_freelist()
+- *
+- * Purpose:	Release the command freelist for a scsi host.
+- *
+- * Arguments:	shost	- host that's freelist is going to be destroyed
++/**
++ * scsi_destroy_command_freelist - Release the command freelist for a scsi host.
++ * @shost: host whose freelist is going to be destroyed
+  */
+ void scsi_destroy_command_freelist(struct Scsi_Host *shost)
  {
- 	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
--	struct lpfc_nodelist *ndlp, *next_ndlp;
- 	struct lpfc_hba  *phba = vport->phba;
+@@ -332,12 +384,16 @@ void scsi_destroy_command_freelist(struct Scsi_Host *shost)
  
- 	if ((vport->load_flag & FC_UNLOADING) != 0)
-@@ -713,11 +733,6 @@ lpfc_linkup_port(struct lpfc_vport *vport)
- 	if (vport->fc_flag & FC_LBIT)
- 		lpfc_linkup_cleanup_nodes(vport);
+ 		cmd = list_entry(shost->free_list.next, struct scsi_cmnd, list);
+ 		list_del_init(&cmd->list);
+-		kmem_cache_free(shost->cmd_pool->slab, cmd);
++		kmem_cache_free(shost->cmd_pool->sense_slab,
++				cmd->sense_buffer);
++		kmem_cache_free(shost->cmd_pool->cmd_slab, cmd);
+ 	}
  
--				/* free any ndlp's in unused state */
--	list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes,
--				 nlp_listp)
--		if (ndlp->nlp_state == NLP_STE_UNUSED_NODE)
--			lpfc_drop_node(vport, ndlp);
+ 	mutex_lock(&host_cmd_pool_mutex);
+-	if (!--shost->cmd_pool->users)
+-		kmem_cache_destroy(shost->cmd_pool->slab);
++	if (!--shost->cmd_pool->users) {
++		kmem_cache_destroy(shost->cmd_pool->cmd_slab);
++		kmem_cache_destroy(shost->cmd_pool->sense_slab);
++	}
+ 	mutex_unlock(&host_cmd_pool_mutex);
  }
  
- static int
-@@ -734,9 +749,9 @@ lpfc_linkup(struct lpfc_hba *phba)
+@@ -441,8 +497,12 @@ void scsi_log_completion(struct scsi_cmnd *cmd, int disposition)
+ }
+ #endif
  
- 	vports = lpfc_create_vport_work_array(phba);
- 	if (vports != NULL)
--		for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++)
-+		for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++)
- 			lpfc_linkup_port(vports[i]);
--	lpfc_destroy_vport_work_array(vports);
-+	lpfc_destroy_vport_work_array(phba, vports);
- 	if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED)
- 		lpfc_issue_clear_la(phba, phba->pport);
+-/* 
+- * Assign a serial number to the request for error recovery
++/**
++ * scsi_cmd_get_serial - Assign a serial number to a command
++ * @host: the scsi host
++ * @cmd: command to assign serial number to
++ *
++ * Description: a serial number identifies a request for error recovery
+  * and debugging purposes.  Protected by the Host_Lock of host.
+  */
+ static inline void scsi_cmd_get_serial(struct Scsi_Host *host, struct scsi_cmnd *cmd)
+@@ -452,14 +512,12 @@ static inline void scsi_cmd_get_serial(struct Scsi_Host *host, struct scsi_cmnd
+ 		cmd->serial_number = host->cmd_serial_number++;
+ }
  
-@@ -749,7 +764,7 @@ lpfc_linkup(struct lpfc_hba *phba)
-  * as the completion routine when the command is
-  * handed off to the SLI layer.
+-/*
+- * Function:    scsi_dispatch_command
+- *
+- * Purpose:     Dispatch a command to the low-level driver.
+- *
+- * Arguments:   cmd - command block we are dispatching.
++/**
++ * scsi_dispatch_command - Dispatch a command to the low-level driver.
++ * @cmd: command block we are dispatching.
+  *
+- * Notes:
++ * Return: nonzero return request was rejected and device's queue needs to be
++ * plugged.
   */
--void
-+static void
- lpfc_mbx_cmpl_clear_la(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
+ int scsi_dispatch_cmd(struct scsi_cmnd *cmd)
  {
- 	struct lpfc_vport *vport = pmb->vport;
-@@ -852,8 +867,6 @@ lpfc_mbx_cmpl_local_config_link(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
- 	 * LPFC_FLOGI while waiting for FLOGI cmpl
- 	 */
- 	if (vport->port_state != LPFC_FLOGI) {
--		vport->port_state = LPFC_FLOGI;
--		lpfc_set_disctmo(vport);
- 		lpfc_initial_flogi(vport);
- 	}
- 	return;
-@@ -1022,8 +1035,7 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, READ_LA_VAR *la)
- 		lpfc_read_sparam(phba, sparam_mbox, 0);
- 		sparam_mbox->vport = vport;
- 		sparam_mbox->mbox_cmpl = lpfc_mbx_cmpl_read_sparam;
--		rc = lpfc_sli_issue_mbox(phba, sparam_mbox,
--				    (MBX_NOWAIT | MBX_STOP_IOCB));
-+		rc = lpfc_sli_issue_mbox(phba, sparam_mbox, MBX_NOWAIT);
- 		if (rc == MBX_NOT_FINISHED) {
- 			mp = (struct lpfc_dmabuf *) sparam_mbox->context1;
- 			lpfc_mbuf_free(phba, mp->virt, mp->phys);
-@@ -1040,8 +1052,7 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, READ_LA_VAR *la)
- 		lpfc_config_link(phba, cfglink_mbox);
- 		cfglink_mbox->vport = vport;
- 		cfglink_mbox->mbox_cmpl = lpfc_mbx_cmpl_local_config_link;
--		rc = lpfc_sli_issue_mbox(phba, cfglink_mbox,
--				    (MBX_NOWAIT | MBX_STOP_IOCB));
-+		rc = lpfc_sli_issue_mbox(phba, cfglink_mbox, MBX_NOWAIT);
- 		if (rc != MBX_NOT_FINISHED)
- 			return;
- 		mempool_free(cfglink_mbox, phba->mbox_mem_pool);
-@@ -1174,6 +1185,9 @@ lpfc_mbx_cmpl_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
- 	lpfc_mbuf_free(phba, mp->virt, mp->phys);
- 	kfree(mp);
- 	mempool_free(pmb, phba->mbox_mem_pool);
-+	/* decrement the node reference count held for this callback
-+	 * function.
-+	 */
- 	lpfc_nlp_put(ndlp);
- 
- 	return;
-@@ -1219,7 +1233,7 @@ lpfc_mbx_unreg_vpi(struct lpfc_vport *vport)
- 	lpfc_unreg_vpi(phba, vport->vpi, mbox);
- 	mbox->vport = vport;
- 	mbox->mbox_cmpl = lpfc_mbx_cmpl_unreg_vpi;
--	rc = lpfc_sli_issue_mbox(phba, mbox, (MBX_NOWAIT | MBX_STOP_IOCB));
-+	rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
- 	if (rc == MBX_NOT_FINISHED) {
- 		lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX | LOG_VPORT,
- 				 "1800 Could not issue unreg_vpi\n");
-@@ -1319,7 +1333,7 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
- 		vports = lpfc_create_vport_work_array(phba);
- 		if (vports != NULL)
- 			for(i = 0;
--			    i < LPFC_MAX_VPORTS && vports[i] != NULL;
-+			    i <= phba->max_vpi && vports[i] != NULL;
- 			    i++) {
- 				if (vports[i]->port_type == LPFC_PHYSICAL_PORT)
- 					continue;
-@@ -1335,7 +1349,7 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
- 							"Fabric support\n");
- 				}
- 			}
--		lpfc_destroy_vport_work_array(vports);
-+		lpfc_destroy_vport_work_array(phba, vports);
- 		lpfc_do_scr_ns_plogi(phba, vport);
- 	}
- 
-@@ -1361,11 +1375,16 @@ lpfc_mbx_cmpl_ns_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
- 
- 	if (mb->mbxStatus) {
- out:
-+		/* decrement the node reference count held for this
-+		 * callback function.
-+		 */
- 		lpfc_nlp_put(ndlp);
- 		lpfc_mbuf_free(phba, mp->virt, mp->phys);
- 		kfree(mp);
- 		mempool_free(pmb, phba->mbox_mem_pool);
--		lpfc_drop_node(vport, ndlp);
-+
-+		/* If no other thread is using the ndlp, free it */
-+		lpfc_nlp_not_used(ndlp);
- 
- 		if (phba->fc_topology == TOPOLOGY_LOOP) {
- 			/*
-@@ -1410,6 +1429,9 @@ out:
- 		goto out;
- 	}
+@@ -585,7 +643,7 @@ int scsi_dispatch_cmd(struct scsi_cmnd *cmd)
  
-+	/* decrement the node reference count held for this
-+	 * callback function.
-+	 */
- 	lpfc_nlp_put(ndlp);
- 	lpfc_mbuf_free(phba, mp->virt, mp->phys);
- 	kfree(mp);
-@@ -1656,8 +1678,18 @@ lpfc_dequeue_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
- void
- lpfc_drop_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
+ /**
+  * scsi_req_abort_cmd -- Request command recovery for the specified command
+- * cmd: pointer to the SCSI command of interest
++ * @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
+@@ -606,9 +664,9 @@ EXPORT_SYMBOL(scsi_req_abort_cmd);
+  * @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.
+  *
+- * This function is the mid-level's (SCSI Core) interrupt routine, which
+- * regains ownership of the SCSI command (de facto) from a LLDD, and enqueues
+- * the command to the done queue for further processing.
++ * Description: This function is the mid-level's (SCSI Core) interrupt routine,
++ * which regains ownership of the SCSI command (de facto) from a LLDD, and
++ * enqueues the command to the done queue for further processing.
+  *
+  * This is the producer of the done queue who enqueues at the tail.
+  *
+@@ -617,7 +675,7 @@ EXPORT_SYMBOL(scsi_req_abort_cmd);
+ static void scsi_done(struct scsi_cmnd *cmd)
  {
-+	/*
-+	 * Use of lpfc_drop_node and UNUSED list: lpfc_drop_node should
-+	 * be used if we wish to issue the "last" lpfc_nlp_put() to remove
-+	 * the ndlp from the vport. The ndlp marked as UNUSED on the list
-+	 * until ALL other outstanding threads have completed. We check
-+	 * that the ndlp not already in the UNUSED state before we proceed.
-+	 */
-+	if (ndlp->nlp_state == NLP_STE_UNUSED_NODE)
-+		return;
- 	lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE);
- 	lpfc_nlp_put(ndlp);
-+	return;
+ 	/*
+-	 * We don't have to worry about this one timing out any more.
++	 * 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
+@@ -660,10 +718,11 @@ static struct scsi_driver *scsi_cmd_to_driver(struct scsi_cmnd *cmd)
+ 	return *(struct scsi_driver **)cmd->request->rq_disk->private_data;
  }
  
- /*
-@@ -1868,8 +1900,7 @@ lpfc_unreg_rpi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
- 			lpfc_unreg_login(phba, vport->vpi, ndlp->nlp_rpi, mbox);
- 			mbox->vport = vport;
- 			mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
--			rc = lpfc_sli_issue_mbox(phba, mbox,
--						 (MBX_NOWAIT | MBX_STOP_IOCB));
-+			rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
- 			if (rc == MBX_NOT_FINISHED)
- 				mempool_free(mbox, phba->mbox_mem_pool);
- 		}
-@@ -1892,8 +1923,8 @@ lpfc_unreg_all_rpis(struct lpfc_vport *vport)
- 		lpfc_unreg_login(phba, vport->vpi, 0xffff, mbox);
- 		mbox->vport = vport;
- 		mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
--		rc = lpfc_sli_issue_mbox(phba, mbox,
--					 (MBX_NOWAIT | MBX_STOP_IOCB));
-+		mbox->context1 = NULL;
-+		rc = lpfc_sli_issue_mbox_wait(phba, mbox, LPFC_MBOX_TMO);
- 		if (rc == MBX_NOT_FINISHED) {
- 			mempool_free(mbox, phba->mbox_mem_pool);
- 		}
-@@ -1912,8 +1943,8 @@ lpfc_unreg_default_rpis(struct lpfc_vport *vport)
- 		lpfc_unreg_did(phba, vport->vpi, 0xffffffff, mbox);
- 		mbox->vport = vport;
- 		mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
--		rc = lpfc_sli_issue_mbox(phba, mbox,
--					 (MBX_NOWAIT | MBX_STOP_IOCB));
-+		mbox->context1 = NULL;
-+		rc = lpfc_sli_issue_mbox_wait(phba, mbox, LPFC_MBOX_TMO);
- 		if (rc == MBX_NOT_FINISHED) {
- 			lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX | LOG_VPORT,
- 					 "1815 Could not issue "
-@@ -1981,11 +2012,6 @@ lpfc_cleanup_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
- 	if (!list_empty(&ndlp->dev_loss_evt.evt_listp))
- 		list_del_init(&ndlp->dev_loss_evt.evt_listp);
+-/*
+- * Function:    scsi_finish_command
++/**
++ * scsi_finish_command - cleanup and pass command back to upper layer
++ * @cmd: the command
+  *
+- * Purpose:     Pass command off to upper layer for finishing of I/O
++ * Description: Pass command off to upper layer for finishing of I/O
+  *              request, waking processes that are waiting on results,
+  *              etc.
+  */
+@@ -708,18 +767,14 @@ void scsi_finish_command(struct scsi_cmnd *cmd)
+ }
+ EXPORT_SYMBOL(scsi_finish_command);
  
--	if (!list_empty(&ndlp->dev_loss_evt.evt_listp)) {
--		list_del_init(&ndlp->dev_loss_evt.evt_listp);
--		complete((struct completion *)(ndlp->dev_loss_evt.evt_arg2));
--	}
--
- 	lpfc_unreg_rpi(vport, ndlp);
+-/*
+- * Function:	scsi_adjust_queue_depth()
+- *
+- * Purpose:	Allow low level drivers to tell us to change the queue depth
+- * 		on a specific SCSI device
+- *
+- * Arguments:	sdev	- SCSI Device in question
+- * 		tagged	- Do we use tagged queueing (non-0) or do we treat
+- * 			  this device as an untagged device (0)
+- * 		tags	- Number of tags allowed if tagged queueing enabled,
+- * 			  or number of commands the low level driver can
+- * 			  queue up in non-tagged mode (as per cmd_per_lun).
++/**
++ * scsi_adjust_queue_depth - Let low level drivers change a device's queue depth
++ * @sdev: SCSI Device in question
++ * @tagged: Do we use tagged queueing (non-0) or do we treat
++ *          this device as an untagged device (0)
++ * @tags: Number of tags allowed if tagged queueing enabled,
++ *        or number of commands the low level driver can
++ *        queue up in non-tagged mode (as per cmd_per_lun).
+  *
+  * Returns:	Nothing
+  *
+@@ -742,8 +797,8 @@ void scsi_adjust_queue_depth(struct scsi_device *sdev, int tagged, int tags)
  
- 	return 0;
-@@ -1999,12 +2025,39 @@ lpfc_cleanup_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
- static void
- lpfc_nlp_remove(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
- {
-+	struct lpfc_hba  *phba = vport->phba;
- 	struct lpfc_rport_data *rdata;
-+	LPFC_MBOXQ_t *mbox;
-+	int rc;
+ 	spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
  
- 	if (ndlp->nlp_flag & NLP_DELAY_TMO) {
- 		lpfc_cancel_retry_delay_tmo(vport, ndlp);
- 	}
+-	/* Check to see if the queue is managed by the block layer
+-	 * if it is, and we fail to adjust the depth, exit */
++	/* Check to see if the queue is managed by the block layer.
++	 * If it is, and we fail to adjust the depth, exit. */
+ 	if (blk_queue_tagged(sdev->request_queue) &&
+ 	    blk_queue_resize_tags(sdev->request_queue, tags) != 0)
+ 		goto out;
+@@ -772,20 +827,17 @@ void scsi_adjust_queue_depth(struct scsi_device *sdev, int tagged, int tags)
+ }
+ EXPORT_SYMBOL(scsi_adjust_queue_depth);
  
-+	if (ndlp->nlp_flag & NLP_DEFER_RM && !ndlp->nlp_rpi) {
-+		/* For this case we need to cleanup the default rpi
-+		 * allocated by the firmware.
-+		 */
-+		if ((mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL))
-+			!= NULL) {
-+			rc = lpfc_reg_login(phba, vport->vpi, ndlp->nlp_DID,
-+			    (uint8_t *) &vport->fc_sparam, mbox, 0);
-+			if (rc) {
-+				mempool_free(mbox, phba->mbox_mem_pool);
-+			}
-+			else {
-+				mbox->mbox_flag |= LPFC_MBX_IMED_UNREG;
-+				mbox->mbox_cmpl = lpfc_mbx_cmpl_dflt_rpi;
-+				mbox->vport = vport;
-+				mbox->context2 = NULL;
-+				rc =lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
-+				if (rc == MBX_NOT_FINISHED) {
-+					mempool_free(mbox, phba->mbox_mem_pool);
-+				}
-+			}
-+		}
-+	}
-+
- 	lpfc_cleanup_node(vport, ndlp);
+-/*
+- * Function:	scsi_track_queue_full()
++/**
++ * scsi_track_queue_full - track QUEUE_FULL events to adjust queue depth
++ * @sdev: SCSI Device in question
++ * @depth: Current number of outstanding SCSI commands on this device,
++ *         not counting the one returned as QUEUE_FULL.
+  *
+- * Purpose:	This function will track successive QUEUE_FULL events on a
++ * Description:	This function will track successive QUEUE_FULL events on a
+  * 		specific SCSI device to determine if and when there is a
+  * 		need to adjust the queue depth on the device.
+  *
+- * Arguments:	sdev	- SCSI Device in question
+- * 		depth	- Current number of outstanding SCSI commands on
+- * 			  this device, not counting the one returned as
+- * 			  QUEUE_FULL.
+- *
+- * Returns:	0 - No change needed
+- * 		>0 - Adjust queue depth to this new depth
++ * Returns:	0 - No change needed, >0 - Adjust queue depth to this new depth,
+  * 		-1 - Drop back to untagged operation using host->cmd_per_lun
+  * 			as the untagged command depth
+  *
+@@ -824,10 +876,10 @@ int scsi_track_queue_full(struct scsi_device *sdev, int depth)
+ EXPORT_SYMBOL(scsi_track_queue_full);
  
- 	/*
-@@ -2132,6 +2185,12 @@ lpfc_setup_disc_node(struct lpfc_vport *vport, uint32_t did)
- 	}
- 	if (vport->fc_flag & FC_RSCN_MODE) {
- 		if (lpfc_rscn_payload_check(vport, did)) {
-+			/* If we've already recieved a PLOGI from this NPort
-+			 * we don't need to try to discover it again.
-+			 */
-+			if (ndlp->nlp_flag & NLP_RCV_PLOGI)
-+				return NULL;
-+
- 			spin_lock_irq(shost->host_lock);
- 			ndlp->nlp_flag |= NLP_NPR_2B_DISC;
- 			spin_unlock_irq(shost->host_lock);
-@@ -2144,8 +2203,13 @@ lpfc_setup_disc_node(struct lpfc_vport *vport, uint32_t did)
- 		} else
- 			ndlp = NULL;
- 	} else {
-+		/* If we've already recieved a PLOGI from this NPort,
-+		 * or we are already in the process of discovery on it,
-+		 * we don't need to try to discover it again.
-+		 */
- 		if (ndlp->nlp_state == NLP_STE_ADISC_ISSUE ||
--		    ndlp->nlp_state == NLP_STE_PLOGI_ISSUE)
-+		    ndlp->nlp_state == NLP_STE_PLOGI_ISSUE ||
-+		    ndlp->nlp_flag & NLP_RCV_PLOGI)
- 			return NULL;
- 		lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
- 		spin_lock_irq(shost->host_lock);
-@@ -2220,8 +2284,7 @@ lpfc_issue_clear_la(struct lpfc_hba *phba, struct lpfc_vport *vport)
- 		lpfc_clear_la(phba, mbox);
- 		mbox->mbox_cmpl = lpfc_mbx_cmpl_clear_la;
- 		mbox->vport = vport;
--		rc = lpfc_sli_issue_mbox(phba, mbox, (MBX_NOWAIT |
--						      MBX_STOP_IOCB));
-+		rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
- 		if (rc == MBX_NOT_FINISHED) {
- 			mempool_free(mbox, phba->mbox_mem_pool);
- 			lpfc_disc_flush_list(vport);
-@@ -2244,8 +2307,7 @@ lpfc_issue_reg_vpi(struct lpfc_hba *phba, struct lpfc_vport *vport)
- 		lpfc_reg_vpi(phba, vport->vpi, vport->fc_myDID, regvpimbox);
- 		regvpimbox->mbox_cmpl = lpfc_mbx_cmpl_reg_vpi;
- 		regvpimbox->vport = vport;
--		if (lpfc_sli_issue_mbox(phba, regvpimbox,
--					(MBX_NOWAIT | MBX_STOP_IOCB))
-+		if (lpfc_sli_issue_mbox(phba, regvpimbox, MBX_NOWAIT)
- 					== MBX_NOT_FINISHED) {
- 			mempool_free(regvpimbox, phba->mbox_mem_pool);
- 		}
-@@ -2414,7 +2476,7 @@ lpfc_free_tx(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
- 	}
+ /**
+- * scsi_device_get  -  get an addition reference to a scsi_device
++ * scsi_device_get  -  get an additional reference to a scsi_device
+  * @sdev:	device to get a reference to
+  *
+- * Gets a reference to the scsi_device and increments the use count
++ * Description: Gets a reference to the scsi_device and increments the use count
+  * of the underlying LLDD module.  You must hold host_lock of the
+  * parent Scsi_Host or already have a reference when calling this.
+  */
+@@ -849,8 +901,8 @@ EXPORT_SYMBOL(scsi_device_get);
+  * scsi_device_put  -  release a reference to a scsi_device
+  * @sdev:	device to release a reference on.
+  *
+- * Release a reference to the scsi_device and decrements the use count
+- * of the underlying LLDD module.  The device is freed once the last
++ * Description: Release a reference to the scsi_device and decrements the use
++ * count of the underlying LLDD module.  The device is freed once the last
+  * user vanishes.
+  */
+ void scsi_device_put(struct scsi_device *sdev)
+@@ -867,7 +919,7 @@ void scsi_device_put(struct scsi_device *sdev)
  }
+ EXPORT_SYMBOL(scsi_device_put);
  
--void
-+static void
- lpfc_disc_flush_list(struct lpfc_vport *vport)
+-/* helper for shost_for_each_device, thus not documented */
++/* helper for shost_for_each_device, see that for documentation */
+ struct scsi_device *__scsi_iterate_devices(struct Scsi_Host *shost,
+ 					   struct scsi_device *prev)
  {
- 	struct lpfc_nodelist *ndlp, *next_ndlp;
-@@ -2426,7 +2488,6 @@ lpfc_disc_flush_list(struct lpfc_vport *vport)
- 			if (ndlp->nlp_state == NLP_STE_PLOGI_ISSUE ||
- 			    ndlp->nlp_state == NLP_STE_ADISC_ISSUE) {
- 				lpfc_free_tx(phba, ndlp);
--				lpfc_nlp_put(ndlp);
- 			}
- 		}
- 	}
-@@ -2516,6 +2577,7 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport)
- 			if (ndlp->nlp_type & NLP_FABRIC) {
- 				/* Clean up the ndlp on Fabric connections */
- 				lpfc_drop_node(vport, ndlp);
-+
- 			} else if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) {
- 				/* Fail outstanding IO now since device
- 				 * is marked for PLOGI.
-@@ -2524,9 +2586,8 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport)
- 			}
- 		}
- 		if (vport->port_state != LPFC_FLOGI) {
--			vport->port_state = LPFC_FLOGI;
--			lpfc_set_disctmo(vport);
- 			lpfc_initial_flogi(vport);
-+			return;
- 		}
- 		break;
+@@ -895,6 +947,8 @@ EXPORT_SYMBOL(__scsi_iterate_devices);
+ /**
+  * starget_for_each_device  -  helper to walk all devices of a target
+  * @starget:	target whose devices we want to iterate over.
++ * @data:	Opaque passed to each function call.
++ * @fn:		Function to call on each device
+  *
+  * This traverses over each device of @starget.  The devices have
+  * a reference that must be released by scsi_host_put when breaking
+@@ -946,13 +1000,13 @@ EXPORT_SYMBOL(__starget_for_each_device);
+  * @starget:	SCSI target pointer
+  * @lun:	SCSI Logical Unit Number
+  *
+- * Looks up the scsi_device with the specified @lun for a give
+- * @starget. The returned scsi_device does not have an additional
++ * Description: Looks up the scsi_device with the specified @lun for a given
++ * @starget.  The returned scsi_device does not have an additional
+  * reference.  You must hold the host's host_lock over this call and
+  * any access to the returned scsi_device.
+  *
+- * Note:  The only reason why drivers would want to use this is because
+- * they're need to access the device list in irq context.  Otherwise you
++ * Note:  The only reason why drivers should use this is because
++ * they need to access the device list in irq context.  Otherwise you
+  * really want to use scsi_device_lookup_by_target instead.
+  **/
+ struct scsi_device *__scsi_device_lookup_by_target(struct scsi_target *starget,
+@@ -974,9 +1028,9 @@ EXPORT_SYMBOL(__scsi_device_lookup_by_target);
+  * @starget:	SCSI target pointer
+  * @lun:	SCSI Logical Unit Number
+  *
+- * Looks up the scsi_device with the specified @channel, @id, @lun for a
+- * give host.  The returned scsi_device has an additional reference that
+- * needs to be release with scsi_host_put once you're done with it.
++ * Description: Looks up the scsi_device with the specified @channel, @id, @lun
++ * for a given host.  The returned scsi_device has an additional reference that
++ * needs to be released with scsi_device_put once you're done with it.
+  **/
+ struct scsi_device *scsi_device_lookup_by_target(struct scsi_target *starget,
+ 						 uint lun)
+@@ -996,19 +1050,19 @@ struct scsi_device *scsi_device_lookup_by_target(struct scsi_target *starget,
+ EXPORT_SYMBOL(scsi_device_lookup_by_target);
  
-@@ -2536,7 +2597,7 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport)
- 		/* Initial FLOGI timeout */
- 		lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
- 				 "0222 Initial %s timeout\n",
--				 vport->vpi ? "FLOGI" : "FDISC");
-+				 vport->vpi ? "FDISC" : "FLOGI");
+ /**
+- * scsi_device_lookup - find a device given the host (UNLOCKED)
++ * __scsi_device_lookup - find a device given the host (UNLOCKED)
+  * @shost:	SCSI host pointer
+  * @channel:	SCSI channel (zero if only one channel)
+- * @pun:	SCSI target number (physical unit number)
++ * @id:		SCSI target number (physical unit number)
+  * @lun:	SCSI Logical Unit Number
+  *
+- * Looks up the scsi_device with the specified @channel, @id, @lun for a
+- * give host. The returned scsi_device does not have an additional reference.
+- * You must hold the host's host_lock over this call and any access to the
+- * returned scsi_device.
++ * Description: Looks up the scsi_device with the specified @channel, @id, @lun
++ * for a given host. The returned scsi_device does not have an additional
++ * reference.  You must hold the host's host_lock over this call and any access
++ * to the returned scsi_device.
+  *
+  * Note:  The only reason why drivers would want to use this is because
+- * they're need to access the device list in irq context.  Otherwise you
++ * they need to access the device list in irq context.  Otherwise you
+  * really want to use scsi_device_lookup instead.
+  **/
+ struct scsi_device *__scsi_device_lookup(struct Scsi_Host *shost,
+@@ -1033,9 +1087,9 @@ EXPORT_SYMBOL(__scsi_device_lookup);
+  * @id:		SCSI target number (physical unit number)
+  * @lun:	SCSI Logical Unit Number
+  *
+- * Looks up the scsi_device with the specified @channel, @id, @lun for a
+- * give host.  The returned scsi_device has an additional reference that
+- * needs to be release with scsi_host_put once you're done with it.
++ * Description: Looks up the scsi_device with the specified @channel, @id, @lun
++ * for a given host.  The returned scsi_device has an additional reference that
++ * needs to be released with scsi_device_put once you're done with it.
+  **/
+ struct scsi_device *scsi_device_lookup(struct Scsi_Host *shost,
+ 		uint channel, uint id, uint lun)
+diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
+index 46cae5a..82c06f0 100644
+--- a/drivers/scsi/scsi_debug.c
++++ b/drivers/scsi/scsi_debug.c
+@@ -329,7 +329,7 @@ int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done)
+ 	if (done == NULL)
+ 		return 0;	/* assume mid level reprocessing command */
  
- 		/* Assume no Fabric and go on with discovery.
- 		 * Check for outstanding ELS FLOGI to abort.
-@@ -2558,10 +2619,10 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport)
- 		/* Next look for NameServer ndlp */
- 		ndlp = lpfc_findnode_did(vport, NameServer_DID);
- 		if (ndlp)
--			lpfc_nlp_put(ndlp);
--		/* Start discovery */
--		lpfc_disc_start(vport);
--		break;
-+			lpfc_els_abort(phba, ndlp);
-+
-+		/* ReStart discovery */
-+		goto restart_disc;
+-	SCpnt->resid = 0;
++	scsi_set_resid(SCpnt, 0);
+ 	if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmd) {
+ 		printk(KERN_INFO "scsi_debug: cmd ");
+ 		for (k = 0, len = SCpnt->cmd_len; k < len; ++k)
+@@ -603,26 +603,16 @@ static int fill_from_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr,
+ 	void * kaddr_off;
+ 	struct scatterlist * sg;
  
- 	case LPFC_NS_QRY:
- 	/* Check for wait for NameServer Rsp timeout */
-@@ -2580,6 +2641,7 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport)
+-	if (0 == scp->request_bufflen)
++	if (0 == scsi_bufflen(scp))
+ 		return 0;
+-	if (NULL == scp->request_buffer)
++	if (NULL == scsi_sglist(scp))
+ 		return (DID_ERROR << 16);
+ 	if (! ((scp->sc_data_direction == DMA_BIDIRECTIONAL) ||
+ 	      (scp->sc_data_direction == DMA_FROM_DEVICE)))
+ 		return (DID_ERROR << 16);
+-	if (0 == scp->use_sg) {
+-		req_len = scp->request_bufflen;
+-		act_len = (req_len < arr_len) ? req_len : arr_len;
+-		memcpy(scp->request_buffer, arr, act_len);
+-		if (scp->resid)
+-			scp->resid -= act_len;
+-		else
+-			scp->resid = req_len - act_len;
+-		return 0;
+-	}
+ 	active = 1;
+ 	req_len = act_len = 0;
+-	scsi_for_each_sg(scp, sg, scp->use_sg, k) {
++	scsi_for_each_sg(scp, sg, scsi_sg_count(scp), k) {
+ 		if (active) {
+ 			kaddr = (unsigned char *)
+ 				kmap_atomic(sg_page(sg), KM_USER0);
+@@ -640,10 +630,10 @@ static int fill_from_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr,
  		}
- 		vport->fc_ns_retry = 0;
- 
-+restart_disc:
- 		/*
- 		 * Discovery is over.
- 		 * set port_state to PORT_READY if SLI2.
-@@ -2608,8 +2670,7 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport)
- 		initlinkmbox->mb.un.varInitLnk.lipsr_AL_PA = 0;
- 		initlinkmbox->vport = vport;
- 		initlinkmbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
--		rc = lpfc_sli_issue_mbox(phba, initlinkmbox,
--					 (MBX_NOWAIT | MBX_STOP_IOCB));
-+		rc = lpfc_sli_issue_mbox(phba, initlinkmbox, MBX_NOWAIT);
- 		lpfc_set_loopback_flag(phba);
- 		if (rc == MBX_NOT_FINISHED)
- 			mempool_free(initlinkmbox, phba->mbox_mem_pool);
-@@ -2664,12 +2725,14 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport)
- 		clrlaerr = 1;
- 		break;
- 
-+	case LPFC_LINK_UP:
-+		lpfc_issue_clear_la(phba, vport);
-+		/* Drop thru */
- 	case LPFC_LINK_UNKNOWN:
- 	case LPFC_WARM_START:
- 	case LPFC_INIT_START:
- 	case LPFC_INIT_MBX_CMDS:
- 	case LPFC_LINK_DOWN:
--	case LPFC_LINK_UP:
- 	case LPFC_HBA_ERROR:
- 		lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
- 				 "0230 Unexpected timeout, hba link "
-@@ -2723,7 +2786,9 @@ lpfc_mbx_cmpl_fdmi_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
+ 		req_len += sg->length;
+ 	}
+-	if (scp->resid)
+-		scp->resid -= act_len;
++	if (scsi_get_resid(scp))
++		scsi_set_resid(scp, scsi_get_resid(scp) - act_len);
  	else
- 		mod_timer(&vport->fc_fdmitmo, jiffies + HZ * 60);
- 
--				/* Mailbox took a reference to the node */
-+	/* decrement the node reference count held for this callback
-+	 * function.
-+	 */
- 	lpfc_nlp_put(ndlp);
- 	lpfc_mbuf_free(phba, mp->virt, mp->phys);
- 	kfree(mp);
-@@ -2747,19 +2812,19 @@ lpfc_filter_by_wwpn(struct lpfc_nodelist *ndlp, void *param)
- 		      sizeof(ndlp->nlp_portname)) == 0;
+-		scp->resid = req_len - act_len;
++		scsi_set_resid(scp, req_len - act_len);
+ 	return 0;
  }
  
--struct lpfc_nodelist *
-+static struct lpfc_nodelist *
- __lpfc_find_node(struct lpfc_vport *vport, node_filter filter, void *param)
- {
- 	struct lpfc_nodelist *ndlp;
+@@ -656,22 +646,15 @@ static int fetch_to_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr,
+ 	void * kaddr_off;
+ 	struct scatterlist * sg;
  
- 	list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) {
--		if (ndlp->nlp_state != NLP_STE_UNUSED_NODE &&
--		    filter(ndlp, param))
-+		if (filter(ndlp, param))
- 			return ndlp;
- 	}
- 	return NULL;
+-	if (0 == scp->request_bufflen)
++	if (0 == scsi_bufflen(scp))
+ 		return 0;
+-	if (NULL == scp->request_buffer)
++	if (NULL == scsi_sglist(scp))
+ 		return -1;
+ 	if (! ((scp->sc_data_direction == DMA_BIDIRECTIONAL) ||
+ 	      (scp->sc_data_direction == DMA_TO_DEVICE)))
+ 		return -1;
+-	if (0 == scp->use_sg) {
+-		req_len = scp->request_bufflen;
+-		len = (req_len < max_arr_len) ? req_len : max_arr_len;
+-		memcpy(arr, scp->request_buffer, len);
+-		return len;
+-	}
+-	sg = scsi_sglist(scp);
+ 	req_len = fin = 0;
+-	for (k = 0; k < scp->use_sg; ++k, sg = sg_next(sg)) {
++	scsi_for_each_sg(scp, sg, scsi_sg_count(scp), k) {
+ 		kaddr = (unsigned char *)kmap_atomic(sg_page(sg), KM_USER0);
+ 		if (NULL == kaddr)
+ 			return -1;
+diff --git a/drivers/scsi/scsi_devinfo.c b/drivers/scsi/scsi_devinfo.c
+index 348cc5a..b8de041 100644
+--- a/drivers/scsi/scsi_devinfo.c
++++ b/drivers/scsi/scsi_devinfo.c
+@@ -276,11 +276,12 @@ static void scsi_strcpy_devinfo(char *name, char *to, size_t to_length,
  }
  
-+#if 0
- /*
-  * Search node lists for a remote port matching filter criteria
-  * Caller needs to hold host_lock before calling this routine.
-@@ -2775,6 +2840,7 @@ lpfc_find_node(struct lpfc_vport *vport, node_filter filter, void *param)
- 	spin_unlock_irq(shost->host_lock);
- 	return ndlp;
+ /**
+- * scsi_dev_info_list_add: add one dev_info list entry.
++ * scsi_dev_info_list_add - add one dev_info list entry.
++ * @compatible: if true, null terminate short strings.  Otherwise space pad.
+  * @vendor:	vendor string
+  * @model:	model (product) string
+  * @strflags:	integer string
+- * @flag:	if strflags NULL, use this flag value
++ * @flags:	if strflags NULL, use this flag value
+  *
+  * Description:
+  * 	Create and add one dev_info entry for @vendor, @model, @strflags or
+@@ -322,8 +323,7 @@ static int scsi_dev_info_list_add(int compatible, char *vendor, char *model,
  }
-+#endif  /*  0  */
  
- /*
-  * This routine looks up the ndlp lists for the given RPI. If rpi found it
-@@ -2786,6 +2852,7 @@ __lpfc_findnode_rpi(struct lpfc_vport *vport, uint16_t rpi)
- 	return __lpfc_find_node(vport, lpfc_filter_by_rpi, &rpi);
+ /**
+- * scsi_dev_info_list_add_str: parse dev_list and add to the
+- * scsi_dev_info_list.
++ * scsi_dev_info_list_add_str - parse dev_list and add to the scsi_dev_info_list.
+  * @dev_list:	string of device flags to add
+  *
+  * Description:
+@@ -374,15 +374,15 @@ static int scsi_dev_info_list_add_str(char *dev_list)
  }
  
-+#if 0
- struct lpfc_nodelist *
- lpfc_findnode_rpi(struct lpfc_vport *vport, uint16_t rpi)
- {
-@@ -2797,6 +2864,7 @@ lpfc_findnode_rpi(struct lpfc_vport *vport, uint16_t rpi)
- 	spin_unlock_irq(shost->host_lock);
- 	return ndlp;
+ /**
+- * get_device_flags - get device specific flags from the dynamic device
+- * list. Called during scan time.
++ * get_device_flags - get device specific flags from the dynamic device list.
++ * @sdev:       &scsi_device to get flags for
+  * @vendor:	vendor name
+  * @model:	model name
+  *
+  * Description:
+  *     Search the scsi_dev_info_list for an entry matching @vendor and
+  *     @model, if found, return the matching flags value, else return
+- *     the host or global default settings.
++ *     the host or global default settings.  Called during scan time.
+  **/
+ int scsi_get_device_flags(struct scsi_device *sdev,
+ 			  const unsigned char *vendor,
+@@ -483,13 +483,11 @@ stop_output:
  }
-+#endif  /*  0  */
  
- /*
-  * This routine looks up the ndlp lists for the given WWPN. If WWPN found it
-@@ -2837,6 +2905,9 @@ lpfc_nlp_init(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
- 	return;
- }
+ /* 
+- * proc_scsi_dev_info_write: allow additions to the scsi_dev_info_list via
+- * /proc.
++ * proc_scsi_dev_info_write - allow additions to scsi_dev_info_list via /proc.
+  *
+- * Use: echo "vendor:model:flag" > /proc/scsi/device_info
+- *
+- * To add a black/white list entry for vendor and model with an integer
+- * value of flag to the scsi device info list.
++ * Description: Adds a black/white list entry for vendor and model with an
++ * integer value of flag to the scsi device info list.
++ * To use, echo "vendor:model:flag" > /proc/scsi/device_info
+  */
+ static int proc_scsi_devinfo_write(struct file *file, const char __user *buf,
+ 				   unsigned long length, void *data)
+@@ -532,8 +530,7 @@ MODULE_PARM_DESC(default_dev_flags,
+ 		 "scsi default device flag integer value");
  
-+/* This routine releases all resources associated with a specifc NPort's ndlp
-+ * and mempool_free's the nodelist.
-+ */
- static void
- lpfc_nlp_release(struct kref *kref)
+ /**
+- * scsi_dev_info_list_delete: called from scsi.c:exit_scsi to remove
+- * 	the scsi_dev_info_list.
++ * scsi_dev_info_list_delete - called from scsi.c:exit_scsi to remove the scsi_dev_info_list.
+  **/
+ void scsi_exit_devinfo(void)
  {
-@@ -2851,16 +2922,57 @@ lpfc_nlp_release(struct kref *kref)
- 	mempool_free(ndlp, ndlp->vport->phba->nlp_mem_pool);
+@@ -552,13 +549,12 @@ void scsi_exit_devinfo(void)
  }
  
-+/* This routine bumps the reference count for a ndlp structure to ensure
-+ * that one discovery thread won't free a ndlp while another discovery thread
-+ * is using it.
+ /**
+- * scsi_dev_list_init: set up the dynamic device list.
+- * @dev_list:	string of device flags to add
++ * scsi_init_devinfo - set up the dynamic device list.
+  *
+  * Description:
+- * 	Add command line @dev_list entries, then add
++ * 	Add command line entries from scsi_dev_flags, then add
+  * 	scsi_static_device_list entries to the scsi device info list.
+- **/
 + */
- struct lpfc_nodelist *
- lpfc_nlp_get(struct lpfc_nodelist *ndlp)
+ int __init scsi_init_devinfo(void)
  {
--	if (ndlp)
-+	if (ndlp) {
-+		lpfc_debugfs_disc_trc(ndlp->vport, LPFC_DISC_TRC_NODE,
-+			"node get:        did:x%x flg:x%x refcnt:x%x",
-+			ndlp->nlp_DID, ndlp->nlp_flag,
-+			atomic_read(&ndlp->kref.refcount));
- 		kref_get(&ndlp->kref);
-+	}
- 	return ndlp;
- }
- 
-+
-+/* This routine decrements the reference count for a ndlp structure. If the
-+ * count goes to 0, this indicates the the associated nodelist should be freed.
+ #ifdef CONFIG_SCSI_PROC_FS
+diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
+index ebaca4c..547e85a 100644
+--- a/drivers/scsi/scsi_error.c
++++ b/drivers/scsi/scsi_error.c
+@@ -62,7 +62,7 @@ void scsi_eh_wakeup(struct Scsi_Host *shost)
+  * @shost:	SCSI host to invoke error handling on.
+  *
+  * Schedule SCSI EH without scmd.
+- **/
 + */
- int
- lpfc_nlp_put(struct lpfc_nodelist *ndlp)
+ void scsi_schedule_eh(struct Scsi_Host *shost)
  {
-+	if (ndlp) {
-+		lpfc_debugfs_disc_trc(ndlp->vport, LPFC_DISC_TRC_NODE,
-+		"node put:        did:x%x flg:x%x refcnt:x%x",
-+			ndlp->nlp_DID, ndlp->nlp_flag,
-+			atomic_read(&ndlp->kref.refcount));
-+	}
- 	return ndlp ? kref_put(&ndlp->kref, lpfc_nlp_release) : 0;
- }
-+
-+/* This routine free's the specified nodelist if it is not in use
-+ * by any other discovery thread. This routine returns 1 if the ndlp
-+ * is not being used by anyone and has been freed. A return value of
-+ * 0 indicates it is being used by another discovery thread and the
-+ * refcount is left unchanged.
+ 	unsigned long flags;
+@@ -86,7 +86,7 @@ EXPORT_SYMBOL_GPL(scsi_schedule_eh);
+  *
+  * Return value:
+  *	0 on failure.
+- **/
 + */
-+int
-+lpfc_nlp_not_used(struct lpfc_nodelist *ndlp)
-+{
-+	lpfc_debugfs_disc_trc(ndlp->vport, LPFC_DISC_TRC_NODE,
-+		"node not used:   did:x%x flg:x%x refcnt:x%x",
-+		ndlp->nlp_DID, ndlp->nlp_flag,
-+		atomic_read(&ndlp->kref.refcount));
-+
-+	if (atomic_read(&ndlp->kref.refcount) == 1) {
-+		lpfc_nlp_put(ndlp);
-+		return 1;
-+	}
-+	return 0;
-+}
-+
-diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h
-index 451accd..041f83e 100644
---- a/drivers/scsi/lpfc/lpfc_hw.h
-+++ b/drivers/scsi/lpfc/lpfc_hw.h
-@@ -139,6 +139,9 @@ struct lpfc_sli_ct_request {
- 			uint8_t len;
- 			uint8_t symbname[255];
- 		} rsnn;
-+		struct da_id { /* For DA_ID requests */
-+			uint32_t port_id;
-+		} da_id;
- 		struct rspn {	/* For RSPN_ID requests */
- 			uint32_t PortId;
- 			uint8_t len;
-@@ -150,11 +153,7 @@ struct lpfc_sli_ct_request {
- 		struct gff_acc {
- 			uint8_t fbits[128];
- 		} gff_acc;
--#ifdef __BIG_ENDIAN_BITFIELD
- #define FCP_TYPE_FEATURE_OFFSET 7
--#else	/*  __LITTLE_ENDIAN_BITFIELD */
--#define FCP_TYPE_FEATURE_OFFSET 4
--#endif
- 		struct rff {
- 			uint32_t PortId;
- 			uint8_t reserved[2];
-@@ -177,6 +176,8 @@ struct lpfc_sli_ct_request {
- 			   sizeof(struct rnn))
- #define  RSNN_REQUEST_SZ  (offsetof(struct lpfc_sli_ct_request, un) + \
- 			   sizeof(struct rsnn))
-+#define DA_ID_REQUEST_SZ (offsetof(struct lpfc_sli_ct_request, un) + \
-+			  sizeof(struct da_id))
- #define  RSPN_REQUEST_SZ  (offsetof(struct lpfc_sli_ct_request, un) + \
- 			   sizeof(struct rspn))
- 
-@@ -1228,7 +1229,8 @@ typedef struct {		/* FireFly BIU registers */
- #define HS_FFER3       0x20000000	/* Bit 29 */
- #define HS_FFER2       0x40000000	/* Bit 30 */
- #define HS_FFER1       0x80000000	/* Bit 31 */
--#define HS_FFERM       0xFF000000	/* Mask for error bits 31:24 */
-+#define HS_CRIT_TEMP   0x00000100	/* Bit 8  */
-+#define HS_FFERM       0xFF000100	/* Mask for error bits 31:24 and 8 */
- 
- /* Host Control Register */
- 
-@@ -1277,12 +1279,14 @@ typedef struct {		/* FireFly BIU registers */
- #define MBX_DEL_LD_ENTRY    0x1D
- #define MBX_RUN_PROGRAM     0x1E
- #define MBX_SET_MASK        0x20
--#define MBX_SET_SLIM        0x21
-+#define MBX_SET_VARIABLE    0x21
- #define MBX_UNREG_D_ID      0x23
- #define MBX_KILL_BOARD      0x24
- #define MBX_CONFIG_FARP     0x25
- #define MBX_BEACON          0x2A
- #define MBX_HEARTBEAT       0x31
-+#define MBX_WRITE_VPARMS    0x32
-+#define MBX_ASYNCEVT_ENABLE 0x33
- 
- #define MBX_CONFIG_HBQ	    0x7C
- #define MBX_LOAD_AREA       0x81
-@@ -1297,7 +1301,7 @@ typedef struct {		/* FireFly BIU registers */
- #define MBX_REG_VNPID	    0x96
- #define MBX_UNREG_VNPID	    0x97
- 
--#define MBX_FLASH_WR_ULA    0x98
-+#define MBX_WRITE_WWN       0x98
- #define MBX_SET_DEBUG       0x99
- #define MBX_LOAD_EXP_ROM    0x9C
- 
-@@ -1344,6 +1348,7 @@ typedef struct {		/* FireFly BIU registers */
- 
- /*  SLI_2 IOCB Command Set */
- 
-+#define CMD_ASYNC_STATUS        0x7C
- #define CMD_RCV_SEQUENCE64_CX   0x81
- #define CMD_XMIT_SEQUENCE64_CR  0x82
- #define CMD_XMIT_SEQUENCE64_CX  0x83
-@@ -1368,6 +1373,7 @@ typedef struct {		/* FireFly BIU registers */
- #define CMD_FCP_TRECEIVE64_CX   0xA1
- #define CMD_FCP_TRSP64_CX       0xA3
- 
-+#define CMD_QUE_XRI64_CX	0xB3
- #define CMD_IOCB_RCV_SEQ64_CX	0xB5
- #define CMD_IOCB_RCV_ELS64_CX	0xB7
- #define CMD_IOCB_RCV_CONT64_CX	0xBB
-@@ -1406,6 +1412,8 @@ typedef struct {		/* FireFly BIU registers */
- #define MBX_BUSY                   0xffffff /* Attempted cmd to busy Mailbox */
- #define MBX_TIMEOUT                0xfffffe /* time-out expired waiting for */
- 
-+#define TEMPERATURE_OFFSET 0xB0	/* Slim offset for critical temperature event */
-+
- /*
-  *    Begin Structure Definitions for Mailbox Commands
-  */
-@@ -2606,6 +2614,18 @@ typedef struct {
- 	uint32_t IPAddress;
- } CONFIG_FARP_VAR;
- 
-+/* Structure for MB Command MBX_ASYNCEVT_ENABLE (0x33) */
-+
-+typedef struct {
-+#ifdef __BIG_ENDIAN_BITFIELD
-+	uint32_t rsvd:30;
-+	uint32_t ring:2;	/* Ring for ASYNC_EVENT iocb Bits 0-1*/
-+#else /*  __LITTLE_ENDIAN */
-+	uint32_t ring:2;	/* Ring for ASYNC_EVENT iocb Bits 0-1*/
-+	uint32_t rsvd:30;
-+#endif
-+} ASYNCEVT_ENABLE_VAR;
-+
- /* Union of all Mailbox Command types */
- #define MAILBOX_CMD_WSIZE	32
- #define MAILBOX_CMD_SIZE	(MAILBOX_CMD_WSIZE * sizeof(uint32_t))
-@@ -2645,6 +2665,7 @@ typedef union {
- 	CONFIG_PORT_VAR varCfgPort;	/* cmd = 0x88 (CONFIG_PORT)  */
- 	REG_VPI_VAR varRegVpi;		/* cmd = 0x96 (REG_VPI) */
- 	UNREG_VPI_VAR varUnregVpi;	/* cmd = 0x97 (UNREG_VPI) */
-+	ASYNCEVT_ENABLE_VAR varCfgAsyncEvent; /*cmd = x33 (CONFIG_ASYNC) */
- } MAILVARIANTS;
- 
- /*
-@@ -2973,6 +2994,34 @@ typedef struct {
- #endif
- } RCV_ELS_REQ64;
- 
-+/* IOCB Command template for RCV_SEQ64 */
-+struct rcv_seq64 {
-+	struct ulp_bde64 elsReq;
-+	uint32_t hbq_1;
-+	uint32_t parmRo;
-+#ifdef __BIG_ENDIAN_BITFIELD
-+	uint32_t rctl:8;
-+	uint32_t type:8;
-+	uint32_t dfctl:8;
-+	uint32_t ls:1;
-+	uint32_t fs:1;
-+	uint32_t rsvd2:3;
-+	uint32_t si:1;
-+	uint32_t bc:1;
-+	uint32_t rsvd3:1;
-+#else	/*  __LITTLE_ENDIAN_BITFIELD */
-+	uint32_t rsvd3:1;
-+	uint32_t bc:1;
-+	uint32_t si:1;
-+	uint32_t rsvd2:3;
-+	uint32_t fs:1;
-+	uint32_t ls:1;
-+	uint32_t dfctl:8;
-+	uint32_t type:8;
-+	uint32_t rctl:8;
-+#endif
-+};
-+
- /* IOCB Command template for all 64 bit FCP Initiator commands */
- typedef struct {
- 	ULP_BDL bdl;
-@@ -2987,6 +3036,21 @@ typedef struct {
- 	uint32_t fcpt_Length;	/* transfer ready for IWRITE */
- } FCPT_FIELDS64;
- 
-+/* IOCB Command template for Async Status iocb commands */
-+typedef struct {
-+	uint32_t rsvd[4];
-+	uint32_t param;
-+#ifdef __BIG_ENDIAN_BITFIELD
-+	uint16_t evt_code;		/* High order bits word 5 */
-+	uint16_t sub_ctxt_tag;		/* Low  order bits word 5 */
-+#else   /*  __LITTLE_ENDIAN_BITFIELD */
-+	uint16_t sub_ctxt_tag;		/* High order bits word 5 */
-+	uint16_t evt_code;		/* Low  order bits word 5 */
-+#endif
-+} ASYNCSTAT_FIELDS;
-+#define ASYNC_TEMP_WARN		0x100
-+#define ASYNC_TEMP_SAFE		0x101
-+
- /* IOCB Command template for CMD_IOCB_RCV_ELS64_CX (0xB7)
-    or CMD_IOCB_RCV_SEQ64_CX (0xB5) */
- 
-@@ -3004,7 +3068,26 @@ struct rcv_sli3 {
- 	struct ulp_bde64 bde2;
- };
- 
-+/* Structure used for a single HBQ entry */
-+struct lpfc_hbq_entry {
-+	struct ulp_bde64 bde;
-+	uint32_t buffer_tag;
-+};
- 
-+/* IOCB Command template for QUE_XRI64_CX (0xB3) command */
-+typedef struct {
-+	struct lpfc_hbq_entry   buff;
-+	uint32_t                rsvd;
-+	uint32_t		rsvd1;
-+} QUE_XRI64_CX_FIELDS;
-+
-+struct que_xri64cx_ext_fields {
-+	uint32_t	iotag64_low;
-+	uint32_t	iotag64_high;
-+	uint32_t	ebde_count;
-+	uint32_t	rsvd;
-+	struct lpfc_hbq_entry	buff[5];
-+};
- 
- typedef struct _IOCB {	/* IOCB structure */
- 	union {
-@@ -3028,6 +3111,9 @@ typedef struct _IOCB {	/* IOCB structure */
- 		XMT_SEQ_FIELDS64 xseq64;	/* XMIT / BCAST cmd */
- 		FCPI_FIELDS64 fcpi64;	/* FCP 64 bit Initiator template */
- 		FCPT_FIELDS64 fcpt64;	/* FCP 64 bit target template */
-+		ASYNCSTAT_FIELDS asyncstat; /* async_status iocb */
-+		QUE_XRI64_CX_FIELDS quexri64cx; /* que_xri64_cx fields */
-+		struct rcv_seq64 rcvseq64;	/* RCV_SEQ64 and RCV_CONT64 */
+ int scsi_eh_scmd_add(struct scsi_cmnd *scmd, int eh_flag)
+ {
+ 	struct Scsi_Host *shost = scmd->device->host;
+@@ -121,7 +121,7 @@ int scsi_eh_scmd_add(struct scsi_cmnd *scmd, int eh_flag)
+  *    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 *))
+ {
+@@ -155,7 +155,7 @@ void scsi_add_timer(struct scsi_cmnd *scmd, int timeout,
+  * 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;
+@@ -181,7 +181,7 @@ int scsi_delete_timer(struct scsi_cmnd *scmd)
+  *     only in that the normal completion handling might run, but if the
+  *     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 scsi_eh_timer_return (* eh_timed_out)(struct scsi_cmnd *);
+@@ -224,7 +224,7 @@ void scsi_times_out(struct scsi_cmnd *scmd)
+  *
+  * Return value:
+  *     0 when dev was taken offline by error recovery. 1 OK to proceed.
+- **/
++ */
+ int scsi_block_when_processing_errors(struct scsi_device *sdev)
+ {
+ 	int online;
+@@ -245,7 +245,7 @@ EXPORT_SYMBOL(scsi_block_when_processing_errors);
+  * scsi_eh_prt_fail_stats - Log info on failures.
+  * @shost:	scsi host being recovered.
+  * @work_q:	Queue of scsi cmds to process.
+- **/
++ */
+ static inline void scsi_eh_prt_fail_stats(struct Scsi_Host *shost,
+ 					  struct list_head *work_q)
+ {
+@@ -295,7 +295,7 @@ static inline void scsi_eh_prt_fail_stats(struct Scsi_Host *shost,
+  * Notes:
+  *	When a deferred error is detected the current command has
+  *	not been executed and needs retrying.
+- **/
++ */
+ static int scsi_check_sense(struct scsi_cmnd *scmd)
+ {
+ 	struct scsi_sense_hdr sshdr;
+@@ -398,7 +398,7 @@ static int scsi_check_sense(struct scsi_cmnd *scmd)
+  *    queued during error recovery.  the main difference here is that we
+  *    don't allow for the possibility of retries here, and we are a lot
+  *    more restrictive about what we consider acceptable.
+- **/
++ */
+ static int scsi_eh_completed_normally(struct scsi_cmnd *scmd)
+ {
+ 	/*
+@@ -452,7 +452,7 @@ static int scsi_eh_completed_normally(struct scsi_cmnd *scmd)
+ /**
+  * scsi_eh_done - Completion function for error handling.
+  * @scmd:	Cmd that is done.
+- **/
++ */
+ static void scsi_eh_done(struct scsi_cmnd *scmd)
+ {
+ 	struct completion     *eh_action;
+@@ -469,7 +469,7 @@ static void scsi_eh_done(struct scsi_cmnd *scmd)
+ /**
+  * scsi_try_host_reset - ask host adapter to reset itself
+  * @scmd:	SCSI cmd to send hsot reset.
+- **/
++ */
+ static int scsi_try_host_reset(struct scsi_cmnd *scmd)
+ {
+ 	unsigned long flags;
+@@ -498,7 +498,7 @@ static int scsi_try_host_reset(struct scsi_cmnd *scmd)
+ /**
+  * scsi_try_bus_reset - ask host to perform a bus reset
+  * @scmd:	SCSI cmd to send bus reset.
+- **/
++ */
+ static int scsi_try_bus_reset(struct scsi_cmnd *scmd)
+ {
+ 	unsigned long flags;
+@@ -533,7 +533,7 @@ static int scsi_try_bus_reset(struct scsi_cmnd *scmd)
+  *    unreliable for a given host, then the host itself needs to put a
+  *    timer on it, and set the host back to a consistent state prior to
+  *    returning.
+- **/
++ */
+ static int scsi_try_bus_device_reset(struct scsi_cmnd *scmd)
+ {
+ 	int rtn;
+@@ -568,7 +568,7 @@ static int __scsi_try_to_abort_cmd(struct scsi_cmnd *scmd)
+  *    author of the low-level driver wishes this operation to be timed,
+  *    they can provide this facility themselves.  helper functions in
+  *    scsi_error.c can be supplied to make this easier to do.
+- **/
++ */
+ static int scsi_try_to_abort_cmd(struct scsi_cmnd *scmd)
+ {
+ 	/*
+@@ -601,7 +601,7 @@ static void scsi_abort_eh_cmnd(struct scsi_cmnd *scmd)
+  * sent must be one that does not transfer any data.  If @sense_bytes != 0
+  * @cmnd is ignored and this functions sets up a REQUEST_SENSE command
+  * and cmnd buffers to read @sense_bytes into @scmd->sense_buffer.
+- **/
++ */
+ void scsi_eh_prep_cmnd(struct scsi_cmnd *scmd, struct scsi_eh_save *ses,
+ 			unsigned char *cmnd, int cmnd_size, unsigned sense_bytes)
+ {
+@@ -625,7 +625,7 @@ void scsi_eh_prep_cmnd(struct scsi_cmnd *scmd, struct scsi_eh_save *ses,
  
- 		uint32_t ulpWord[IOCB_WORD_SZ - 2];	/* generic 6 'words' */
- 	} un;
-@@ -3085,6 +3171,10 @@ typedef struct _IOCB {	/* IOCB structure */
+ 	if (sense_bytes) {
+ 		scmd->request_bufflen = min_t(unsigned,
+-		                       sizeof(scmd->sense_buffer), sense_bytes);
++		                       SCSI_SENSE_BUFFERSIZE, sense_bytes);
+ 		sg_init_one(&ses->sense_sgl, scmd->sense_buffer,
+ 		                                       scmd->request_bufflen);
+ 		scmd->request_buffer = &ses->sense_sgl;
+@@ -657,7 +657,7 @@ void scsi_eh_prep_cmnd(struct scsi_cmnd *scmd, struct scsi_eh_save *ses,
+ 	 * Zero the sense buffer.  The scsi spec mandates that any
+ 	 * untransferred sense data should be interpreted as being zero.
+ 	 */
+-	memset(scmd->sense_buffer, 0, sizeof(scmd->sense_buffer));
++	memset(scmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
+ }
+ EXPORT_SYMBOL(scsi_eh_prep_cmnd);
  
- 	union {
- 		struct rcv_sli3 rcvsli3; /* words 8 - 15 */
-+
-+		/* words 8-31 used for que_xri_cx iocb */
-+		struct que_xri64cx_ext_fields que_xri64cx_ext_words;
-+
- 		uint32_t sli3Words[24]; /* 96 extra bytes for SLI-3 */
- 	} unsli3;
+@@ -667,7 +667,7 @@ EXPORT_SYMBOL(scsi_eh_prep_cmnd);
+  * @ses:        saved information from a coresponding call to scsi_prep_eh_cmnd
+  *
+  * Undo any damage done by above scsi_prep_eh_cmnd().
+- **/
++ */
+ void scsi_eh_restore_cmnd(struct scsi_cmnd* scmd, struct scsi_eh_save *ses)
+ {
+ 	/*
+@@ -697,7 +697,7 @@ EXPORT_SYMBOL(scsi_eh_restore_cmnd);
+  *
+  * Return value:
+  *    SUCCESS or FAILED or NEEDS_RETRY
+- **/
++ */
+ static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, unsigned char *cmnd,
+ 			     int cmnd_size, int timeout, unsigned sense_bytes)
+ {
+@@ -765,7 +765,7 @@ static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, unsigned char *cmnd,
+  *    Some hosts automatically obtain this information, others require
+  *    that we obtain it on our own. This function will *not* return until
+  *    the command either times out, or it completes.
+- **/
++ */
+ static int scsi_request_sense(struct scsi_cmnd *scmd)
+ {
+ 	return scsi_send_eh_cmnd(scmd, NULL, 0, SENSE_TIMEOUT, ~0);
+@@ -779,10 +779,10 @@ static int scsi_request_sense(struct scsi_cmnd *scmd)
+  * Notes:
+  *    We don't want to use the normal command completion while we are are
+  *    still handling errors - it may cause other commands to be queued,
+- *    and that would disturb what we are doing.  thus we really want to
++ *    and that would disturb what we are doing.  Thus we really want to
+  *    keep a list of pending commands for final completion, and once we
+  *    are ready to leave error handling we handle completion for real.
+- **/
++ */
+ void scsi_eh_finish_cmd(struct scsi_cmnd *scmd, struct list_head *done_q)
+ {
+ 	scmd->device->host->host_failed--;
+@@ -794,7 +794,7 @@ EXPORT_SYMBOL(scsi_eh_finish_cmd);
+ /**
+  * scsi_eh_get_sense - Get device sense data.
+  * @work_q:	Queue of commands to process.
+- * @done_q:	Queue of proccessed commands..
++ * @done_q:	Queue of processed commands.
+  *
+  * Description:
+  *    See if we need to request sense information.  if so, then get it
+@@ -802,7 +802,7 @@ EXPORT_SYMBOL(scsi_eh_finish_cmd);
+  *
+  * Notes:
+  *    This has the unfortunate side effect that if a shost adapter does
+- *    not automatically request sense information, that we end up shutting
++ *    not automatically request sense information, we end up shutting
+  *    it down before we request it.
+  *
+  *    All drivers should request sense information internally these days,
+@@ -810,7 +810,7 @@ EXPORT_SYMBOL(scsi_eh_finish_cmd);
+  *
+  *    XXX: Long term this code should go away, but that needs an audit of
+  *         all LLDDs first.
+- **/
++ */
+ int scsi_eh_get_sense(struct list_head *work_q,
+ 		      struct list_head *done_q)
+ {
+@@ -858,11 +858,11 @@ EXPORT_SYMBOL_GPL(scsi_eh_get_sense);
  
-@@ -3124,12 +3214,6 @@ typedef struct _IOCB {	/* IOCB structure */
+ /**
+  * scsi_eh_tur - Send TUR to device.
+- * @scmd:	Scsi cmd to send TUR
++ * @scmd:	&scsi_cmnd to send TUR
+  *
+  * Return value:
+  *    0 - Device is ready. 1 - Device NOT ready.
+- **/
++ */
+ static int scsi_eh_tur(struct scsi_cmnd *scmd)
+ {
+ 	static unsigned char tur_command[6] = {TEST_UNIT_READY, 0, 0, 0, 0, 0};
+@@ -887,17 +887,17 @@ retry_tur:
+ }
  
- } IOCB_t;
+ /**
+- * scsi_eh_abort_cmds - abort canceled commands.
+- * @shost:	scsi host being recovered.
+- * @eh_done_q:	list_head for processed commands.
++ * scsi_eh_abort_cmds - abort pending commands.
++ * @work_q:	&list_head for pending commands.
++ * @done_q:	&list_head for processed commands.
+  *
+  * Decription:
+  *    Try and see whether or not it makes sense to try and abort the
+- *    running command.  this only works out to be the case if we have one
+- *    command that has timed out.  if the command simply failed, it makes
++ *    running command.  This only works out to be the case if we have one
++ *    command that has timed out.  If the command simply failed, it makes
+  *    no sense to try and abort the command, since as far as the shost
+  *    adapter is concerned, it isn't running.
+- **/
++ */
+ static int scsi_eh_abort_cmds(struct list_head *work_q,
+ 			      struct list_head *done_q)
+ {
+@@ -931,11 +931,11 @@ static int scsi_eh_abort_cmds(struct list_head *work_q,
  
--/* Structure used for a single HBQ entry */
--struct lpfc_hbq_entry {
--	struct ulp_bde64 bde;
--	uint32_t buffer_tag;
--};
--
+ /**
+  * scsi_eh_try_stu - Send START_UNIT to device.
+- * @scmd:	Scsi cmd to send START_UNIT
++ * @scmd:	&scsi_cmnd to send START_UNIT
+  *
+  * Return value:
+  *    0 - Device is ready. 1 - Device NOT ready.
+- **/
++ */
+ static int scsi_eh_try_stu(struct scsi_cmnd *scmd)
+ {
+ 	static unsigned char stu_command[6] = {START_STOP, 0, 0, 0, 1, 0};
+@@ -956,13 +956,14 @@ static int scsi_eh_try_stu(struct scsi_cmnd *scmd)
  
- #define SLI1_SLIM_SIZE   (4 * 1024)
+  /**
+  * scsi_eh_stu - send START_UNIT if needed
+- * @shost:	scsi host being recovered.
+- * @eh_done_q:	list_head for processed commands.
++ * @shost:	&scsi host being recovered.
++ * @work_q:     &list_head for pending commands.
++ * @done_q:	&list_head for processed commands.
+  *
+  * Notes:
+  *    If commands are failing due to not ready, initializing command required,
+  *	try revalidating the device, which will end up sending a start unit. 
+- **/
++ */
+ static int scsi_eh_stu(struct Scsi_Host *shost,
+ 			      struct list_head *work_q,
+ 			      struct list_head *done_q)
+@@ -1008,14 +1009,15 @@ static int scsi_eh_stu(struct Scsi_Host *shost,
+ /**
+  * scsi_eh_bus_device_reset - send bdr if needed
+  * @shost:	scsi host being recovered.
+- * @eh_done_q:	list_head for processed commands.
++ * @work_q:     &list_head for pending commands.
++ * @done_q:	&list_head for processed commands.
+  *
+  * Notes:
+- *    Try a bus device reset.  still, look to see whether we have multiple
++ *    Try a bus device reset.  Still, look to see whether we have multiple
+  *    devices that are jammed or not - if we have multiple devices, it
+  *    makes no sense to try bus_device_reset - we really would need to try
+  *    a bus_reset instead. 
+- **/
++ */
+ static int scsi_eh_bus_device_reset(struct Scsi_Host *shost,
+ 				    struct list_head *work_q,
+ 				    struct list_head *done_q)
+@@ -1063,9 +1065,10 @@ static int scsi_eh_bus_device_reset(struct Scsi_Host *shost,
  
-@@ -3172,6 +3256,8 @@ lpfc_is_LC_HBA(unsigned short device)
- 	    (device == PCI_DEVICE_ID_BSMB) ||
- 	    (device == PCI_DEVICE_ID_ZMID) ||
- 	    (device == PCI_DEVICE_ID_ZSMB) ||
-+	    (device == PCI_DEVICE_ID_SAT_MID) ||
-+	    (device == PCI_DEVICE_ID_SAT_SMB) ||
- 	    (device == PCI_DEVICE_ID_RFLY))
- 		return 1;
- 	else
-diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c
-index ecebdfa..3205f74 100644
---- a/drivers/scsi/lpfc/lpfc_init.c
-+++ b/drivers/scsi/lpfc/lpfc_init.c
-@@ -212,6 +212,18 @@ out_free_mbox:
- 	return 0;
+ /**
+  * scsi_eh_bus_reset - send a bus reset 
+- * @shost:	scsi host being recovered.
+- * @eh_done_q:	list_head for processed commands.
+- **/
++ * @shost:	&scsi host being recovered.
++ * @work_q:     &list_head for pending commands.
++ * @done_q:	&list_head for processed commands.
++ */
+ static int scsi_eh_bus_reset(struct Scsi_Host *shost,
+ 			     struct list_head *work_q,
+ 			     struct list_head *done_q)
+@@ -1122,7 +1125,7 @@ static int scsi_eh_bus_reset(struct Scsi_Host *shost,
+  * scsi_eh_host_reset - send a host reset 
+  * @work_q:	list_head for processed commands.
+  * @done_q:	list_head for processed commands.
+- **/
++ */
+ static int scsi_eh_host_reset(struct list_head *work_q,
+ 			      struct list_head *done_q)
+ {
+@@ -1157,8 +1160,7 @@ static int scsi_eh_host_reset(struct list_head *work_q,
+  * scsi_eh_offline_sdevs - offline scsi devices that fail to recover
+  * @work_q:	list_head for processed commands.
+  * @done_q:	list_head for processed commands.
+- *
+- **/
++ */
+ static void scsi_eh_offline_sdevs(struct list_head *work_q,
+ 				  struct list_head *done_q)
+ {
+@@ -1191,7 +1193,7 @@ static void scsi_eh_offline_sdevs(struct list_head *work_q,
+  *    is woken.  In cases where the error code indicates an error that
+  *    doesn't require the error handler read (i.e. we don't need to
+  *    abort/reset), this function should return SUCCESS.
+- **/
++ */
+ int scsi_decide_disposition(struct scsi_cmnd *scmd)
+ {
+ 	int rtn;
+@@ -1372,7 +1374,7 @@ int scsi_decide_disposition(struct scsi_cmnd *scmd)
+  *
+  *	If scsi_allocate_request() fails for what ever reason, we
+  *	completely forget to lock the door.
+- **/
++ */
+ static void scsi_eh_lock_door(struct scsi_device *sdev)
+ {
+ 	unsigned char cmnd[MAX_COMMAND_SIZE];
+@@ -1396,7 +1398,7 @@ static void scsi_eh_lock_door(struct scsi_device *sdev)
+  * Notes:
+  *    When we entered the error handler, we blocked all further i/o to
+  *    this device.  we need to 'reverse' this process.
+- **/
++ */
+ static void scsi_restart_operations(struct Scsi_Host *shost)
+ {
+ 	struct scsi_device *sdev;
+@@ -1440,9 +1442,9 @@ static void scsi_restart_operations(struct Scsi_Host *shost)
+ /**
+  * scsi_eh_ready_devs - check device ready state and recover if not.
+  * @shost: 	host to be recovered.
+- * @eh_done_q:	list_head for processed commands.
+- *
+- **/
++ * @work_q:     &list_head for pending commands.
++ * @done_q:	&list_head for processed commands.
++ */
+ void scsi_eh_ready_devs(struct Scsi_Host *shost,
+ 			struct list_head *work_q,
+ 			struct list_head *done_q)
+@@ -1458,8 +1460,7 @@ EXPORT_SYMBOL_GPL(scsi_eh_ready_devs);
+ /**
+  * scsi_eh_flush_done_q - finish processed commands or retry them.
+  * @done_q:	list_head of processed commands.
+- *
+- **/
++ */
+ void scsi_eh_flush_done_q(struct list_head *done_q)
+ {
+ 	struct scsi_cmnd *scmd, *next;
+@@ -1513,7 +1514,7 @@ EXPORT_SYMBOL(scsi_eh_flush_done_q);
+  *    scsi_finish_cmd() called for it.  we do all of the retry stuff
+  *    here, so when we restart the host after we return it should have an
+  *    empty queue.
+- **/
++ */
+ static void scsi_unjam_host(struct Scsi_Host *shost)
+ {
+ 	unsigned long flags;
+@@ -1540,7 +1541,7 @@ static void scsi_unjam_host(struct Scsi_Host *shost)
+  * Notes:
+  *    This is the main error handling loop.  This is run as a kernel thread
+  *    for every SCSI host and handles all error handling activity.
+- **/
++ */
+ int scsi_error_handler(void *data)
+ {
+ 	struct Scsi_Host *shost = data;
+@@ -1769,7 +1770,7 @@ EXPORT_SYMBOL(scsi_reset_provider);
+  *
+  * Return value:
+  *	1 if valid sense data information found, else 0;
+- **/
++ */
+ int scsi_normalize_sense(const u8 *sense_buffer, int sb_len,
+                          struct scsi_sense_hdr *sshdr)
+ {
+@@ -1819,14 +1820,12 @@ int scsi_command_normalize_sense(struct scsi_cmnd *cmd,
+ 				 struct scsi_sense_hdr *sshdr)
+ {
+ 	return scsi_normalize_sense(cmd->sense_buffer,
+-			sizeof(cmd->sense_buffer), sshdr);
++			SCSI_SENSE_BUFFERSIZE, sshdr);
  }
+ EXPORT_SYMBOL(scsi_command_normalize_sense);
  
-+/* Completion handler for config async event mailbox command. */
-+static void
-+lpfc_config_async_cmpl(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmboxq)
-+{
-+	if (pmboxq->mb.mbxStatus == MBX_SUCCESS)
-+		phba->temp_sensor_support = 1;
-+	else
-+		phba->temp_sensor_support = 0;
-+	mempool_free(pmboxq, phba->mbox_mem_pool);
-+	return;
-+}
-+
- /************************************************************************/
- /*                                                                      */
- /*    lpfc_config_port_post                                             */
-@@ -234,6 +246,15 @@ lpfc_config_port_post(struct lpfc_hba *phba)
- 	int i, j;
- 	int rc;
+ /**
+- * scsi_sense_desc_find - search for a given descriptor type in
+- *			descriptor sense data format.
+- *
++ * scsi_sense_desc_find - search for a given descriptor type in	descriptor sense data format.
+  * @sense_buffer:	byte array of descriptor format sense data
+  * @sb_len:		number of valid bytes in sense_buffer
+  * @desc_type:		value of descriptor type to find
+@@ -1837,7 +1836,7 @@ EXPORT_SYMBOL(scsi_command_normalize_sense);
+  *
+  * Return value:
+  *	pointer to start of (first) descriptor if found else NULL
+- **/
++ */
+ const u8 * scsi_sense_desc_find(const u8 * sense_buffer, int sb_len,
+ 				int desc_type)
+ {
+@@ -1865,9 +1864,7 @@ const u8 * scsi_sense_desc_find(const u8 * sense_buffer, int sb_len,
+ EXPORT_SYMBOL(scsi_sense_desc_find);
  
-+	spin_lock_irq(&phba->hbalock);
-+	/*
-+	 * If the Config port completed correctly the HBA is not
-+	 * over heated any more.
-+	 */
-+	if (phba->over_temp_state == HBA_OVER_TEMP)
-+		phba->over_temp_state = HBA_NORMAL_TEMP;
-+	spin_unlock_irq(&phba->hbalock);
-+
- 	pmb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
- 	if (!pmb) {
- 		phba->link_state = LPFC_HBA_ERROR;
-@@ -343,7 +364,7 @@ lpfc_config_port_post(struct lpfc_hba *phba)
+ /**
+- * scsi_get_sense_info_fld - attempts to get information field from
+- *			sense data (either fixed or descriptor format)
+- *
++ * scsi_get_sense_info_fld - get information field from sense data (either fixed or descriptor format)
+  * @sense_buffer:	byte array of sense data
+  * @sb_len:		number of valid bytes in sense_buffer
+  * @info_out:		pointer to 64 integer where 8 or 4 byte information
+@@ -1875,7 +1872,7 @@ EXPORT_SYMBOL(scsi_sense_desc_find);
+  *
+  * Return value:
+  *	1 if information field found, 0 if not found.
+- **/
++ */
+ int scsi_get_sense_info_fld(const u8 * sense_buffer, int sb_len,
+ 			    u64 * info_out)
+ {
+diff --git a/drivers/scsi/scsi_ioctl.c b/drivers/scsi/scsi_ioctl.c
+index 32293f4..28b19ef 100644
+--- a/drivers/scsi/scsi_ioctl.c
++++ b/drivers/scsi/scsi_ioctl.c
+@@ -174,10 +174,15 @@ static int scsi_ioctl_get_pci(struct scsi_device *sdev, void __user *arg)
+ }
  
- 	phba->link_state = LPFC_LINK_DOWN;
  
--	/* Only process IOCBs on ring 0 till hba_state is READY */
-+	/* Only process IOCBs on ELS ring till hba_state is READY */
- 	if (psli->ring[psli->extra_ring].cmdringaddr)
- 		psli->ring[psli->extra_ring].flag |= LPFC_STOP_IOCB_EVENT;
- 	if (psli->ring[psli->fcp_ring].cmdringaddr)
-@@ -409,7 +430,21 @@ lpfc_config_port_post(struct lpfc_hba *phba)
- 		return -EIO;
- 	}
- 	/* MBOX buffer will be freed in mbox compl */
-+	pmb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
-+	lpfc_config_async(phba, pmb, LPFC_ELS_RING);
-+	pmb->mbox_cmpl = lpfc_config_async_cmpl;
-+	pmb->vport = phba->pport;
-+	rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT);
+-/*
+- * the scsi_ioctl() function differs from most ioctls in that it does
+- * not take a major/minor number as the dev field.  Rather, it takes
+- * a pointer to a scsi_devices[] element, a structure. 
++/**
++ * scsi_ioctl - Dispatch ioctl to scsi device
++ * @sdev: scsi device receiving ioctl
++ * @cmd: which ioctl is it
++ * @arg: data associated with ioctl
++ *
++ * Description: The scsi_ioctl() function differs from most ioctls in that it
++ * does not take a major/minor number as the dev field.  Rather, it takes
++ * a pointer to a &struct scsi_device.
+  */
+ int scsi_ioctl(struct scsi_device *sdev, int cmd, void __user *arg)
+ {
+@@ -239,7 +244,7 @@ int scsi_ioctl(struct scsi_device *sdev, int cmd, void __user *arg)
+ 		return scsi_set_medium_removal(sdev, SCSI_REMOVAL_ALLOW);
+ 	case SCSI_IOCTL_TEST_UNIT_READY:
+ 		return scsi_test_unit_ready(sdev, IOCTL_NORMAL_TIMEOUT,
+-					    NORMAL_RETRIES);
++					    NORMAL_RETRIES, NULL);
+ 	case SCSI_IOCTL_START_UNIT:
+ 		scsi_cmd[0] = START_STOP;
+ 		scsi_cmd[1] = 0;
+@@ -264,9 +269,12 @@ int scsi_ioctl(struct scsi_device *sdev, int cmd, void __user *arg)
+ }
+ EXPORT_SYMBOL(scsi_ioctl);
  
-+	if ((rc != MBX_BUSY) && (rc != MBX_SUCCESS)) {
-+		lpfc_printf_log(phba,
-+				KERN_ERR,
-+				LOG_INIT,
-+				"0456 Adapter failed to issue "
-+				"ASYNCEVT_ENABLE mbox status x%x \n.",
-+				rc);
-+		mempool_free(pmb, phba->mbox_mem_pool);
-+	}
- 	return (0);
+-/*
+- * the scsi_nonblock_ioctl() function is designed for ioctls which may
+- * be executed even if the device is in recovery.
++/**
++ * scsi_nonblock_ioctl() - Handle SG_SCSI_RESET
++ * @sdev: scsi device receiving ioctl
++ * @cmd: Must be SC_SCSI_RESET
++ * @arg: pointer to int containing SG_SCSI_RESET_{DEVICE,BUS,HOST}
++ * @filp: either NULL or a &struct file which must have the O_NONBLOCK flag.
+  */
+ int scsi_nonblockable_ioctl(struct scsi_device *sdev, int cmd,
+ 			    void __user *arg, struct file *filp)
+@@ -276,7 +284,7 @@ int scsi_nonblockable_ioctl(struct scsi_device *sdev, int cmd,
+ 	/* The first set of iocts may be executed even if we're doing
+ 	 * error processing, as long as the device was opened
+ 	 * non-blocking */
+-	if (filp && filp->f_flags & O_NONBLOCK) {
++	if (filp && (filp->f_flags & O_NONBLOCK)) {
+ 		if (scsi_host_in_recovery(sdev->host))
+ 			return -ENODEV;
+ 	} else if (!scsi_block_when_processing_errors(sdev))
+diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
+index a9ac5b1..7c4c889 100644
+--- a/drivers/scsi/scsi_lib.c
++++ b/drivers/scsi/scsi_lib.c
+@@ -175,7 +175,7 @@ int scsi_queue_insert(struct scsi_cmnd *cmd, int reason)
+  *
+  * returns the req->errors value which is the scsi_cmnd result
+  * field.
+- **/
++ */
+ int scsi_execute(struct scsi_device *sdev, const unsigned char *cmd,
+ 		 int data_direction, void *buffer, unsigned bufflen,
+ 		 unsigned char *sense, int timeout, int retries, int flags)
+@@ -274,7 +274,7 @@ static void scsi_bi_endio(struct bio *bio, int error)
+ /**
+  * scsi_req_map_sg - map a scatterlist into a request
+  * @rq:		request to fill
+- * @sg:		scatterlist
++ * @sgl:	scatterlist
+  * @nsegs:	number of elements
+  * @bufflen:	len of buffer
+  * @gfp:	memory allocation flags
+@@ -365,14 +365,16 @@ free_bios:
+  * @sdev:	scsi device
+  * @cmd:	scsi command
+  * @cmd_len:	length of scsi cdb
+- * @data_direction: data direction
++ * @data_direction: DMA_TO_DEVICE, DMA_FROM_DEVICE, or DMA_NONE
+  * @buffer:	data buffer (this can be a kernel buffer or scatterlist)
+  * @bufflen:	len of buffer
+  * @use_sg:	if buffer is a scatterlist this is the number of elements
+  * @timeout:	request timeout in seconds
+  * @retries:	number of times to retry request
+- * @flags:	or into request flags
+- **/
++ * @privdata:	data passed to done()
++ * @done:	callback function when done
++ * @gfp:	memory allocation flags
++ */
+ int scsi_execute_async(struct scsi_device *sdev, const unsigned char *cmd,
+ 		       int cmd_len, int data_direction, void *buffer, unsigned bufflen,
+ 		       int use_sg, int timeout, int retries, void *privdata,
+@@ -439,7 +441,7 @@ static void scsi_init_cmd_errh(struct scsi_cmnd *cmd)
+ {
+ 	cmd->serial_number = 0;
+ 	cmd->resid = 0;
+-	memset(cmd->sense_buffer, 0, sizeof cmd->sense_buffer);
++	memset(cmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
+ 	if (cmd->cmd_len == 0)
+ 		cmd->cmd_len = COMMAND_SIZE(cmd->cmnd[0]);
  }
+@@ -524,7 +526,7 @@ static void scsi_run_queue(struct request_queue *q)
+ 	struct Scsi_Host *shost = sdev->host;
+ 	unsigned long flags;
  
-@@ -449,6 +484,9 @@ lpfc_hba_down_post(struct lpfc_hba *phba)
- 	struct lpfc_sli *psli = &phba->sli;
- 	struct lpfc_sli_ring *pring;
- 	struct lpfc_dmabuf *mp, *next_mp;
-+	struct lpfc_iocbq *iocb;
-+	IOCB_t *cmd = NULL;
-+	LIST_HEAD(completions);
- 	int i;
+-	if (sdev->single_lun)
++	if (scsi_target(sdev)->single_lun)
+ 		scsi_single_lun_run(sdev);
  
- 	if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED)
-@@ -464,16 +502,42 @@ lpfc_hba_down_post(struct lpfc_hba *phba)
- 		}
- 	}
+ 	spin_lock_irqsave(shost->host_lock, flags);
+@@ -632,7 +634,7 @@ void scsi_run_host_queues(struct Scsi_Host *shost)
+  *		of upper level post-processing and scsi_io_completion).
+  *
+  * Arguments:   cmd	 - command that is complete.
+- *              uptodate - 1 if I/O indicates success, <= 0 for I/O error.
++ *              error    - 0 if I/O indicates success, < 0 for I/O error.
+  *              bytes    - number of bytes of completed I/O
+  *		requeue  - indicates whether we should requeue leftovers.
+  *
+@@ -647,26 +649,25 @@ void scsi_run_host_queues(struct Scsi_Host *shost)
+  *		at some point during this call.
+  * Notes:	If cmd was requeued, upon return it will be a stale pointer.
+  */
+-static struct scsi_cmnd *scsi_end_request(struct scsi_cmnd *cmd, int uptodate,
++static struct scsi_cmnd *scsi_end_request(struct scsi_cmnd *cmd, int error,
+ 					  int bytes, int requeue)
+ {
+ 	struct request_queue *q = cmd->device->request_queue;
+ 	struct request *req = cmd->request;
+-	unsigned long flags;
  
-+	spin_lock_irq(&phba->hbalock);
- 	for (i = 0; i < psli->num_rings; i++) {
- 		pring = &psli->ring[i];
-+
-+		/* At this point in time the HBA is either reset or DOA. Either
-+		 * way, nothing should be on txcmplq as it will NEVER complete.
-+		 */
-+		list_splice_init(&pring->txcmplq, &completions);
-+		pring->txcmplq_cnt = 0;
-+		spin_unlock_irq(&phba->hbalock);
-+
-+		while (!list_empty(&completions)) {
-+			iocb = list_get_first(&completions, struct lpfc_iocbq,
-+				list);
-+			cmd = &iocb->iocb;
-+			list_del_init(&iocb->list);
-+
-+			if (!iocb->iocb_cmpl)
-+				lpfc_sli_release_iocbq(phba, iocb);
-+			else {
-+				cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
-+				cmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
-+				(iocb->iocb_cmpl) (phba, iocb, iocb);
-+			}
-+		}
-+
- 		lpfc_sli_abort_iocb_ring(phba, pring);
-+		spin_lock_irq(&phba->hbalock);
+ 	/*
+ 	 * If there are blocks left over at the end, set up the command
+ 	 * to queue the remainder of them.
+ 	 */
+-	if (end_that_request_chunk(req, uptodate, bytes)) {
++	if (blk_end_request(req, error, bytes)) {
+ 		int leftover = (req->hard_nr_sectors << 9);
+ 
+ 		if (blk_pc_request(req))
+ 			leftover = req->data_len;
+ 
+ 		/* kill remainder if no retrys */
+-		if (!uptodate && blk_noretry_request(req))
+-			end_that_request_chunk(req, 0, leftover);
++		if (error && blk_noretry_request(req))
++			blk_end_request(req, error, leftover);
+ 		else {
+ 			if (requeue) {
+ 				/*
+@@ -681,14 +682,6 @@ static struct scsi_cmnd *scsi_end_request(struct scsi_cmnd *cmd, int uptodate,
+ 		}
  	}
-+	spin_unlock_irq(&phba->hbalock);
  
- 	return 0;
+-	add_disk_randomness(req->rq_disk);
+-
+-	spin_lock_irqsave(q->queue_lock, flags);
+-	if (blk_rq_tagged(req))
+-		blk_queue_end_tag(q, req);
+-	end_that_request_last(req, uptodate);
+-	spin_unlock_irqrestore(q->queue_lock, flags);
+-
+ 	/*
+ 	 * This will goose the queue request function at the end, so we don't
+ 	 * need to worry about launching another command.
+@@ -737,138 +730,43 @@ static inline unsigned int scsi_sgtable_index(unsigned short nents)
+ 	return index;
  }
  
- /* HBA heart beat timeout handler */
--void
-+static void
- lpfc_hb_timeout(unsigned long ptr)
- {
- 	struct lpfc_hba *phba;
-@@ -512,8 +576,10 @@ void
- lpfc_hb_timeout_handler(struct lpfc_hba *phba)
+-struct scatterlist *scsi_alloc_sgtable(struct scsi_cmnd *cmd, gfp_t gfp_mask)
++static void scsi_sg_free(struct scatterlist *sgl, unsigned int nents)
  {
- 	LPFC_MBOXQ_t *pmboxq;
-+	struct lpfc_dmabuf *buf_ptr;
- 	int retval;
- 	struct lpfc_sli *psli = &phba->sli;
-+	LIST_HEAD(completions);
- 
- 	if ((phba->link_state == LPFC_HBA_ERROR) ||
- 		(phba->pport->load_flag & FC_UNLOADING) ||
-@@ -540,49 +606,88 @@ lpfc_hb_timeout_handler(struct lpfc_hba *phba)
- 	}
- 	spin_unlock_irq(&phba->pport->work_port_lock);
+ 	struct scsi_host_sg_pool *sgp;
+-	struct scatterlist *sgl, *prev, *ret;
+-	unsigned int index;
+-	int this, left;
+-
+-	BUG_ON(!cmd->use_sg);
+-
+-	left = cmd->use_sg;
+-	ret = prev = NULL;
+-	do {
+-		this = left;
+-		if (this > SCSI_MAX_SG_SEGMENTS) {
+-			this = SCSI_MAX_SG_SEGMENTS - 1;
+-			index = SG_MEMPOOL_NR - 1;
+-		} else
+-			index = scsi_sgtable_index(this);
  
--	/* If there is no heart beat outstanding, issue a heartbeat command */
--	if (!phba->hb_outstanding) {
--		pmboxq = mempool_alloc(phba->mbox_mem_pool,GFP_KERNEL);
--		if (!pmboxq) {
--			mod_timer(&phba->hb_tmofunc,
--				jiffies + HZ * LPFC_HB_MBOX_INTERVAL);
--			return;
-+	if (phba->elsbuf_cnt &&
-+		(phba->elsbuf_cnt == phba->elsbuf_prev_cnt)) {
-+		spin_lock_irq(&phba->hbalock);
-+		list_splice_init(&phba->elsbuf, &completions);
-+		phba->elsbuf_cnt = 0;
-+		phba->elsbuf_prev_cnt = 0;
-+		spin_unlock_irq(&phba->hbalock);
-+
-+		while (!list_empty(&completions)) {
-+			list_remove_head(&completions, buf_ptr,
-+				struct lpfc_dmabuf, list);
-+			lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys);
-+			kfree(buf_ptr);
- 		}
-+	}
-+	phba->elsbuf_prev_cnt = phba->elsbuf_cnt;
+-		left -= this;
+-
+-		sgp = scsi_sg_pools + index;
+-
+-		sgl = mempool_alloc(sgp->pool, gfp_mask);
+-		if (unlikely(!sgl))
+-			goto enomem;
++	sgp = scsi_sg_pools + scsi_sgtable_index(nents);
++	mempool_free(sgl, sgp->pool);
++}
  
--		lpfc_heart_beat(phba, pmboxq);
--		pmboxq->mbox_cmpl = lpfc_hb_mbox_cmpl;
--		pmboxq->vport = phba->pport;
--		retval = lpfc_sli_issue_mbox(phba, pmboxq, MBX_NOWAIT);
-+	/* If there is no heart beat outstanding, issue a heartbeat command */
-+	if (phba->cfg_enable_hba_heartbeat) {
-+		if (!phba->hb_outstanding) {
-+			pmboxq = mempool_alloc(phba->mbox_mem_pool,GFP_KERNEL);
-+			if (!pmboxq) {
-+				mod_timer(&phba->hb_tmofunc,
-+					  jiffies + HZ * LPFC_HB_MBOX_INTERVAL);
-+				return;
-+			}
+-		sg_init_table(sgl, sgp->size);
++static struct scatterlist *scsi_sg_alloc(unsigned int nents, gfp_t gfp_mask)
++{
++	struct scsi_host_sg_pool *sgp;
  
--		if (retval != MBX_BUSY && retval != MBX_SUCCESS) {
--			mempool_free(pmboxq, phba->mbox_mem_pool);
-+			lpfc_heart_beat(phba, pmboxq);
-+			pmboxq->mbox_cmpl = lpfc_hb_mbox_cmpl;
-+			pmboxq->vport = phba->pport;
-+			retval = lpfc_sli_issue_mbox(phba, pmboxq, MBX_NOWAIT);
-+
-+			if (retval != MBX_BUSY && retval != MBX_SUCCESS) {
-+				mempool_free(pmboxq, phba->mbox_mem_pool);
-+				mod_timer(&phba->hb_tmofunc,
-+					  jiffies + HZ * LPFC_HB_MBOX_INTERVAL);
-+				return;
-+			}
- 			mod_timer(&phba->hb_tmofunc,
--				jiffies + HZ * LPFC_HB_MBOX_INTERVAL);
-+				  jiffies + HZ * LPFC_HB_MBOX_TIMEOUT);
-+			phba->hb_outstanding = 1;
- 			return;
-+		} else {
-+			/*
-+			* If heart beat timeout called with hb_outstanding set
-+			* we need to take the HBA offline.
-+			*/
-+			lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
-+					"0459 Adapter heartbeat failure, "
-+					"taking this port offline.\n");
-+
-+			spin_lock_irq(&phba->hbalock);
-+			psli->sli_flag &= ~LPFC_SLI2_ACTIVE;
-+			spin_unlock_irq(&phba->hbalock);
-+
-+			lpfc_offline_prep(phba);
-+			lpfc_offline(phba);
-+			lpfc_unblock_mgmt_io(phba);
-+			phba->link_state = LPFC_HBA_ERROR;
-+			lpfc_hba_down_post(phba);
- 		}
--		mod_timer(&phba->hb_tmofunc,
--			jiffies + HZ * LPFC_HB_MBOX_TIMEOUT);
--		phba->hb_outstanding = 1;
--		return;
--	} else {
 -		/*
--		 * If heart beat timeout called with hb_outstanding set we
--		 * need to take the HBA offline.
+-		 * first loop through, set initial index and return value
 -		 */
--		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
--				"0459 Adapter heartbeat failure, taking "
--				"this port offline.\n");
-+	}
+-		if (!ret)
+-			ret = sgl;
++	sgp = scsi_sg_pools + scsi_sgtable_index(nents);
++	return mempool_alloc(sgp->pool, gfp_mask);
 +}
  
--		spin_lock_irq(&phba->hbalock);
--		psli->sli_flag &= ~LPFC_SLI2_ACTIVE;
--		spin_unlock_irq(&phba->hbalock);
-+static void
-+lpfc_offline_eratt(struct lpfc_hba *phba)
+-		/*
+-		 * chain previous sglist, if any. we know the previous
+-		 * sglist must be the biggest one, or we would not have
+-		 * ended up doing another loop.
+-		 */
+-		if (prev)
+-			sg_chain(prev, SCSI_MAX_SG_SEGMENTS, sgl);
++int scsi_alloc_sgtable(struct scsi_cmnd *cmd, gfp_t gfp_mask)
 +{
-+	struct lpfc_sli   *psli = &phba->sli;
++	int ret;
  
--		lpfc_offline_prep(phba);
--		lpfc_offline(phba);
--		lpfc_unblock_mgmt_io(phba);
--		phba->link_state = LPFC_HBA_ERROR;
--		lpfc_hba_down_post(phba);
+-		/*
+-		 * if we have nothing left, mark the last segment as
+-		 * end-of-list
+-		 */
+-		if (!left)
+-			sg_mark_end(&sgl[this - 1]);
++	BUG_ON(!cmd->use_sg);
+ 
+-		/*
+-		 * don't allow subsequent mempool allocs to sleep, it would
+-		 * violate the mempool principle.
+-		 */
+-		gfp_mask &= ~__GFP_WAIT;
+-		gfp_mask |= __GFP_HIGH;
+-		prev = sgl;
+-	} while (left);
++	ret = __sg_alloc_table(&cmd->sg_table, cmd->use_sg,
++			       SCSI_MAX_SG_SEGMENTS, gfp_mask, scsi_sg_alloc);
++	if (unlikely(ret))
++		__sg_free_table(&cmd->sg_table, SCSI_MAX_SG_SEGMENTS,
++				scsi_sg_free);
+ 
+-	/*
+-	 * ->use_sg may get modified after dma mapping has potentially
+-	 * shrunk the number of segments, so keep a copy of it for free.
+-	 */
+-	cmd->__use_sg = cmd->use_sg;
++	cmd->request_buffer = cmd->sg_table.sgl;
+ 	return ret;
+-enomem:
+-	if (ret) {
+-		/*
+-		 * Free entries chained off ret. Since we were trying to
+-		 * allocate another sglist, we know that all entries are of
+-		 * the max size.
+-		 */
+-		sgp = scsi_sg_pools + SG_MEMPOOL_NR - 1;
+-		prev = ret;
+-		ret = &ret[SCSI_MAX_SG_SEGMENTS - 1];
+-
+-		while ((sgl = sg_chain_ptr(ret)) != NULL) {
+-			ret = &sgl[SCSI_MAX_SG_SEGMENTS - 1];
+-			mempool_free(sgl, sgp->pool);
+-		}
+-
+-		mempool_free(prev, sgp->pool);
 -	}
-+	spin_lock_irq(&phba->hbalock);
-+	psli->sli_flag &= ~LPFC_SLI2_ACTIVE;
-+	spin_unlock_irq(&phba->hbalock);
-+	lpfc_offline_prep(phba);
-+
-+	lpfc_offline(phba);
-+	lpfc_reset_barrier(phba);
-+	lpfc_sli_brdreset(phba);
-+	lpfc_hba_down_post(phba);
-+	lpfc_sli_brdready(phba, HS_MBRDY);
-+	lpfc_unblock_mgmt_io(phba);
-+	phba->link_state = LPFC_HBA_ERROR;
-+	return;
+-	return NULL;
  }
  
- /************************************************************************/
-@@ -601,6 +706,8 @@ lpfc_handle_eratt(struct lpfc_hba *phba)
- 	struct lpfc_sli_ring  *pring;
- 	struct lpfc_vport **vports;
- 	uint32_t event_data;
-+	unsigned long temperature;
-+	struct temp_event temp_event_data;
- 	struct Scsi_Host  *shost;
- 	int i;
+ EXPORT_SYMBOL(scsi_alloc_sgtable);
  
-@@ -608,6 +715,9 @@ lpfc_handle_eratt(struct lpfc_hba *phba)
- 	 * since we cannot communicate with the pci card anyway. */
- 	if (pci_channel_offline(phba->pcidev))
+ void scsi_free_sgtable(struct scsi_cmnd *cmd)
+ {
+-	struct scatterlist *sgl = cmd->request_buffer;
+-	struct scsi_host_sg_pool *sgp;
+-
+-	/*
+-	 * if this is the biggest size sglist, check if we have
+-	 * chained parts we need to free
+-	 */
+-	if (cmd->__use_sg > SCSI_MAX_SG_SEGMENTS) {
+-		unsigned short this, left;
+-		struct scatterlist *next;
+-		unsigned int index;
+-
+-		left = cmd->__use_sg - (SCSI_MAX_SG_SEGMENTS - 1);
+-		next = sg_chain_ptr(&sgl[SCSI_MAX_SG_SEGMENTS - 1]);
+-		while (left && next) {
+-			sgl = next;
+-			this = left;
+-			if (this > SCSI_MAX_SG_SEGMENTS) {
+-				this = SCSI_MAX_SG_SEGMENTS - 1;
+-				index = SG_MEMPOOL_NR - 1;
+-			} else
+-				index = scsi_sgtable_index(this);
+-
+-			left -= this;
+-
+-			sgp = scsi_sg_pools + index;
+-
+-			if (left)
+-				next = sg_chain_ptr(&sgl[sgp->size - 1]);
+-
+-			mempool_free(sgl, sgp->pool);
+-		}
+-
+-		/*
+-		 * Restore original, will be freed below
+-		 */
+-		sgl = cmd->request_buffer;
+-		sgp = scsi_sg_pools + SG_MEMPOOL_NR - 1;
+-	} else
+-		sgp = scsi_sg_pools + scsi_sgtable_index(cmd->__use_sg);
+-
+-	mempool_free(sgl, sgp->pool);
++	__sg_free_table(&cmd->sg_table, SCSI_MAX_SG_SEGMENTS, scsi_sg_free);
+ }
+ 
+ EXPORT_SYMBOL(scsi_free_sgtable);
+@@ -985,7 +883,7 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
+ 	 * are leftovers and there is some kind of error
+ 	 * (result != 0), retry the rest.
+ 	 */
+-	if (scsi_end_request(cmd, 1, good_bytes, result == 0) == NULL)
++	if (scsi_end_request(cmd, 0, good_bytes, result == 0) == NULL)
  		return;
-+	/* If resets are disabled then leave the HBA alone and return */
-+	if (!phba->cfg_enable_hba_reset)
-+		return;
  
- 	if (phba->work_hs & HS_FFER6 ||
- 	    phba->work_hs & HS_FFER5) {
-@@ -620,14 +730,14 @@ lpfc_handle_eratt(struct lpfc_hba *phba)
- 		vports = lpfc_create_vport_work_array(phba);
- 		if (vports != NULL)
- 			for(i = 0;
--			    i < LPFC_MAX_VPORTS && vports[i] != NULL;
-+			    i <= phba->max_vpi && vports[i] != NULL;
- 			    i++){
- 				shost = lpfc_shost_from_vport(vports[i]);
- 				spin_lock_irq(shost->host_lock);
- 				vports[i]->fc_flag |= FC_ESTABLISH_LINK;
- 				spin_unlock_irq(shost->host_lock);
+ 	/* good_bytes = 0, or (inclusive) there were leftovers and
+@@ -999,7 +897,7 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
+ 				 * and quietly refuse further access.
+ 				 */
+ 				cmd->device->changed = 1;
+-				scsi_end_request(cmd, 0, this_count, 1);
++				scsi_end_request(cmd, -EIO, this_count, 1);
+ 				return;
+ 			} else {
+ 				/* Must have been a power glitch, or a
+@@ -1031,7 +929,7 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
+ 				scsi_requeue_command(q, cmd);
+ 				return;
+ 			} else {
+-				scsi_end_request(cmd, 0, this_count, 1);
++				scsi_end_request(cmd, -EIO, this_count, 1);
+ 				return;
  			}
--		lpfc_destroy_vport_work_array(vports);
-+		lpfc_destroy_vport_work_array(phba, vports);
- 		spin_lock_irq(&phba->hbalock);
- 		psli->sli_flag &= ~LPFC_SLI2_ACTIVE;
- 		spin_unlock_irq(&phba->hbalock);
-@@ -655,6 +765,31 @@ lpfc_handle_eratt(struct lpfc_hba *phba)
+ 			break;
+@@ -1059,7 +957,7 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
+ 							 "Device not ready",
+ 							 &sshdr);
+ 
+-			scsi_end_request(cmd, 0, this_count, 1);
++			scsi_end_request(cmd, -EIO, this_count, 1);
+ 			return;
+ 		case VOLUME_OVERFLOW:
+ 			if (!(req->cmd_flags & REQ_QUIET)) {
+@@ -1069,7 +967,7 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
+ 				scsi_print_sense("", cmd);
+ 			}
+ 			/* See SSC3rXX or current. */
+-			scsi_end_request(cmd, 0, this_count, 1);
++			scsi_end_request(cmd, -EIO, this_count, 1);
  			return;
+ 		default:
+ 			break;
+@@ -1090,7 +988,7 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
+ 				scsi_print_sense("", cmd);
  		}
- 		lpfc_unblock_mgmt_io(phba);
-+	} else if (phba->work_hs & HS_CRIT_TEMP) {
-+		temperature = readl(phba->MBslimaddr + TEMPERATURE_OFFSET);
-+		temp_event_data.event_type = FC_REG_TEMPERATURE_EVENT;
-+		temp_event_data.event_code = LPFC_CRIT_TEMP;
-+		temp_event_data.data = (uint32_t)temperature;
-+
-+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
-+				"0459 Adapter maximum temperature exceeded "
-+				"(%ld), taking this port offline "
-+				"Data: x%x x%x x%x\n",
-+				temperature, phba->work_hs,
-+				phba->work_status[0], phba->work_status[1]);
-+
-+		shost = lpfc_shost_from_vport(phba->pport);
-+		fc_host_post_vendor_event(shost, fc_get_event_number(),
-+					  sizeof(temp_event_data),
-+					  (char *) &temp_event_data,
-+					  SCSI_NL_VID_TYPE_PCI
-+					  | PCI_VENDOR_ID_EMULEX);
-+
-+		spin_lock_irq(&phba->hbalock);
-+		phba->over_temp_state = HBA_OVER_TEMP;
-+		spin_unlock_irq(&phba->hbalock);
-+		lpfc_offline_eratt(phba);
-+
- 	} else {
- 		/* The if clause above forces this code path when the status
- 		 * failure is a value other than FFER6.  Do not call the offline
-@@ -672,14 +807,7 @@ lpfc_handle_eratt(struct lpfc_hba *phba)
- 				sizeof(event_data), (char *) &event_data,
- 				SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_EMULEX);
- 
--		spin_lock_irq(&phba->hbalock);
--		psli->sli_flag &= ~LPFC_SLI2_ACTIVE;
--		spin_unlock_irq(&phba->hbalock);
--		lpfc_offline_prep(phba);
--		lpfc_offline(phba);
--		lpfc_unblock_mgmt_io(phba);
--		phba->link_state = LPFC_HBA_ERROR;
--		lpfc_hba_down_post(phba);
-+		lpfc_offline_eratt(phba);
  	}
+-	scsi_end_request(cmd, 0, this_count, !result);
++	scsi_end_request(cmd, -EIO, this_count, !result);
  }
  
-@@ -699,21 +827,25 @@ lpfc_handle_latt(struct lpfc_hba *phba)
- 	LPFC_MBOXQ_t *pmb;
- 	volatile uint32_t control;
- 	struct lpfc_dmabuf *mp;
--	int rc = -ENOMEM;
-+	int rc = 0;
- 
- 	pmb = (LPFC_MBOXQ_t *)mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
--	if (!pmb)
-+	if (!pmb) {
-+		rc = 1;
- 		goto lpfc_handle_latt_err_exit;
-+	}
- 
- 	mp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
--	if (!mp)
-+	if (!mp) {
-+		rc = 2;
- 		goto lpfc_handle_latt_free_pmb;
-+	}
- 
- 	mp->virt = lpfc_mbuf_alloc(phba, 0, &mp->phys);
--	if (!mp->virt)
-+	if (!mp->virt) {
-+		rc = 3;
- 		goto lpfc_handle_latt_free_mp;
+ /*
+@@ -1102,7 +1000,6 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
+  *
+  * Returns:     0 on success
+  *		BLKPREP_DEFER if the failure is retryable
+- *		BLKPREP_KILL if the failure is fatal
+  */
+ static int scsi_init_io(struct scsi_cmnd *cmd)
+ {
+@@ -1119,8 +1016,7 @@ static int scsi_init_io(struct scsi_cmnd *cmd)
+ 	/*
+ 	 * If sg table allocation fails, requeue request later.
+ 	 */
+-	cmd->request_buffer = scsi_alloc_sgtable(cmd, GFP_ATOMIC);
+-	if (unlikely(!cmd->request_buffer)) {
++	if (unlikely(scsi_alloc_sgtable(cmd, GFP_ATOMIC))) {
+ 		scsi_unprep_request(req);
+ 		return BLKPREP_DEFER;
+ 	}
+@@ -1136,17 +1032,9 @@ static int scsi_init_io(struct scsi_cmnd *cmd)
+ 	 * each segment.
+ 	 */
+ 	count = blk_rq_map_sg(req->q, req, cmd->request_buffer);
+-	if (likely(count <= cmd->use_sg)) {
+-		cmd->use_sg = count;
+-		return BLKPREP_OK;
+-	}
 -
--	rc = -EIO;
-+	}
- 
- 	/* Cleanup any outstanding ELS commands */
- 	lpfc_els_flush_all_cmd(phba);
-@@ -722,9 +854,11 @@ lpfc_handle_latt(struct lpfc_hba *phba)
- 	lpfc_read_la(phba, pmb, mp);
- 	pmb->mbox_cmpl = lpfc_mbx_cmpl_read_la;
- 	pmb->vport = vport;
--	rc = lpfc_sli_issue_mbox (phba, pmb, (MBX_NOWAIT | MBX_STOP_IOCB));
--	if (rc == MBX_NOT_FINISHED)
-+	rc = lpfc_sli_issue_mbox (phba, pmb, MBX_NOWAIT);
-+	if (rc == MBX_NOT_FINISHED) {
-+		rc = 4;
- 		goto lpfc_handle_latt_free_mbuf;
-+	}
- 
- 	/* Clear Link Attention in HA REG */
- 	spin_lock_irq(&phba->hbalock);
-@@ -756,10 +890,8 @@ lpfc_handle_latt_err_exit:
- 	lpfc_linkdown(phba);
- 	phba->link_state = LPFC_HBA_ERROR;
- 
--	/* The other case is an error from issue_mbox */
--	if (rc == -ENOMEM)
--		lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX,
--			        "0300 READ_LA: no buffers\n");
-+	lpfc_printf_log(phba, KERN_ERR, LOG_MBOX,
-+		     "0300 LATT: Cannot issue READ_LA: Data:%d\n", rc);
- 
- 	return;
- }
-@@ -1088,9 +1220,8 @@ lpfc_post_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, int cnt,
- 		/* Allocate buffer to post */
- 		mp1 = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL);
- 		if (mp1)
--		    mp1->virt = lpfc_mbuf_alloc(phba, MEM_PRI,
--						&mp1->phys);
--		if (mp1 == 0 || mp1->virt == 0) {
-+		    mp1->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &mp1->phys);
-+		if (!mp1 || !mp1->virt) {
- 			kfree(mp1);
- 			lpfc_sli_release_iocbq(phba, iocb);
- 			pring->missbufcnt = cnt;
-@@ -1104,7 +1235,7 @@ lpfc_post_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, int cnt,
- 			if (mp2)
- 				mp2->virt = lpfc_mbuf_alloc(phba, MEM_PRI,
- 							    &mp2->phys);
--			if (mp2 == 0 || mp2->virt == 0) {
-+			if (!mp2 || !mp2->virt) {
- 				kfree(mp2);
- 				lpfc_mbuf_free(phba, mp1->virt, mp1->phys);
- 				kfree(mp1);
-@@ -1280,15 +1411,39 @@ lpfc_hba_init(struct lpfc_hba *phba, uint32_t *hbainit)
- 	kfree(HashWorking);
+-	printk(KERN_ERR "Incorrect number of segments after building list\n");
+-	printk(KERN_ERR "counted %d, received %d\n", count, cmd->use_sg);
+-	printk(KERN_ERR "req nr_sec %lu, cur_nr_sec %u\n", req->nr_sectors,
+-			req->current_nr_sectors);
+-
+-	return BLKPREP_KILL;
++	BUG_ON(count > cmd->use_sg);
++	cmd->use_sg = count;
++	return BLKPREP_OK;
  }
  
--static void
-+void
- lpfc_cleanup(struct lpfc_vport *vport)
- {
-+	struct lpfc_hba   *phba = vport->phba;
- 	struct lpfc_nodelist *ndlp, *next_ndlp;
-+	int i = 0;
+ static struct scsi_cmnd *scsi_get_cmd_from_req(struct scsi_device *sdev,
+@@ -1557,7 +1445,7 @@ static void scsi_request_fn(struct request_queue *q)
  
--	/* clean up phba - lpfc specific */
--	lpfc_can_disctmo(vport);
--	list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp)
--		lpfc_nlp_put(ndlp);
-+	if (phba->link_state > LPFC_LINK_DOWN)
-+		lpfc_port_link_failure(vport);
-+
-+	list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) {
-+		if (ndlp->nlp_type & NLP_FABRIC)
-+			lpfc_disc_state_machine(vport, ndlp, NULL,
-+					NLP_EVT_DEVICE_RECOVERY);
-+		lpfc_disc_state_machine(vport, ndlp, NULL,
-+					     NLP_EVT_DEVICE_RM);
-+	}
+ 		if (!scsi_host_queue_ready(q, shost, sdev))
+ 			goto not_ready;
+-		if (sdev->single_lun) {
++		if (scsi_target(sdev)->single_lun) {
+ 			if (scsi_target(sdev)->starget_sdev_user &&
+ 			    scsi_target(sdev)->starget_sdev_user != sdev)
+ 				goto not_ready;
+@@ -1675,6 +1563,14 @@ struct request_queue *__scsi_alloc_queue(struct Scsi_Host *shost,
+ 
+ 	if (!shost->use_clustering)
+ 		clear_bit(QUEUE_FLAG_CLUSTER, &q->queue_flags);
 +
-+	/* At this point, ALL ndlp's should be gone
-+	 * because of the previous NLP_EVT_DEVICE_RM.
-+	 * Lets wait for this to happen, if needed.
++	/*
++	 * set a reasonable default alignment on word boundaries: the
++	 * host and device may alter it using
++	 * blk_queue_update_dma_alignment() later.
 +	 */
-+	while (!list_empty(&vport->fc_nodes)) {
-+
-+		if (i++ > 3000) {
-+			lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
-+				"0233 Nodelist not empty\n");
-+			break;
-+		}
++	blk_queue_dma_alignment(q, 0x03);
 +
-+		/* Wait for any activity on ndlps to settle */
-+		msleep(10);
-+	}
- 	return;
- }
- 
-@@ -1307,14 +1462,14 @@ lpfc_establish_link_tmo(unsigned long ptr)
- 			phba->pport->fc_flag, phba->pport->port_state);
- 	vports = lpfc_create_vport_work_array(phba);
- 	if (vports != NULL)
--		for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++) {
-+		for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) {
- 			struct Scsi_Host *shost;
- 			shost = lpfc_shost_from_vport(vports[i]);
- 			spin_lock_irqsave(shost->host_lock, iflag);
- 			vports[i]->fc_flag &= ~FC_ESTABLISH_LINK;
- 			spin_unlock_irqrestore(shost->host_lock, iflag);
- 		}
--	lpfc_destroy_vport_work_array(vports);
-+	lpfc_destroy_vport_work_array(phba, vports);
+ 	return q;
  }
+ EXPORT_SYMBOL(__scsi_alloc_queue);
+@@ -1804,7 +1700,7 @@ void scsi_exit_queue(void)
+  *	@timeout: command timeout
+  *	@retries: number of retries before failing
+  *	@data: returns a structure abstracting the mode header data
+- *	@sense: place to put sense data (or NULL if no sense to be collected).
++ *	@sshdr: place to put sense data (or NULL if no sense to be collected).
+  *		must be SCSI_SENSE_BUFFERSIZE big.
+  *
+  *	Returns zero if successful; negative error number or scsi
+@@ -1871,8 +1767,7 @@ scsi_mode_select(struct scsi_device *sdev, int pf, int sp, int modepage,
+ EXPORT_SYMBOL_GPL(scsi_mode_select);
  
- void
-@@ -1339,6 +1494,16 @@ lpfc_stop_phba_timers(struct lpfc_hba *phba)
- 	return;
+ /**
+- *	scsi_mode_sense - issue a mode sense, falling back from 10 to 
+- *		six bytes if necessary.
++ *	scsi_mode_sense - issue a mode sense, falling back from 10 to six bytes if necessary.
+  *	@sdev:	SCSI device to be queried
+  *	@dbd:	set if mode sense will allow block descriptors to be returned
+  *	@modepage: mode page being requested
+@@ -1881,13 +1776,13 @@ EXPORT_SYMBOL_GPL(scsi_mode_select);
+  *	@timeout: command timeout
+  *	@retries: number of retries before failing
+  *	@data: returns a structure abstracting the mode header data
+- *	@sense: place to put sense data (or NULL if no sense to be collected).
++ *	@sshdr: place to put sense data (or NULL if no sense to be collected).
+  *		must be SCSI_SENSE_BUFFERSIZE big.
+  *
+  *	Returns zero if unsuccessful, or the header offset (either 4
+  *	or 8 depending on whether a six or ten byte command was
+  *	issued) if successful.
+- **/
++ */
+ int
+ scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage,
+ 		  unsigned char *buffer, int len, int timeout, int retries,
+@@ -1981,40 +1876,69 @@ scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage,
  }
+ EXPORT_SYMBOL(scsi_mode_sense);
  
-+static void
-+lpfc_block_mgmt_io(struct lpfc_hba * phba)
-+{
-+	unsigned long iflag;
-+
-+	spin_lock_irqsave(&phba->hbalock, iflag);
-+	phba->sli.sli_flag |= LPFC_BLOCK_MGMT_IO;
-+	spin_unlock_irqrestore(&phba->hbalock, iflag);
-+}
-+
++/**
++ *	scsi_test_unit_ready - test if unit is ready
++ *	@sdev:	scsi device to change the state of.
++ *	@timeout: command timeout
++ *	@retries: number of retries before failing
++ *	@sshdr_external: Optional pointer to struct scsi_sense_hdr for
++ *		returning sense. Make sure that this is cleared before passing
++ *		in.
++ *
++ *	Returns zero if unsuccessful or an error if TUR failed.  For
++ *	removable media, a return of NOT_READY or UNIT_ATTENTION is
++ *	translated to success, with the ->changed flag updated.
++ **/
  int
- lpfc_online(struct lpfc_hba *phba)
+-scsi_test_unit_ready(struct scsi_device *sdev, int timeout, int retries)
++scsi_test_unit_ready(struct scsi_device *sdev, int timeout, int retries,
++		     struct scsi_sense_hdr *sshdr_external)
  {
-@@ -1369,7 +1534,7 @@ lpfc_online(struct lpfc_hba *phba)
+ 	char cmd[] = {
+ 		TEST_UNIT_READY, 0, 0, 0, 0, 0,
+ 	};
+-	struct scsi_sense_hdr sshdr;
++	struct scsi_sense_hdr *sshdr;
+ 	int result;
+-	
+-	result = scsi_execute_req(sdev, cmd, DMA_NONE, NULL, 0, &sshdr,
+-				  timeout, retries);
++
++	if (!sshdr_external)
++		sshdr = kzalloc(sizeof(*sshdr), GFP_KERNEL);
++	else
++		sshdr = sshdr_external;
++
++	/* try to eat the UNIT_ATTENTION if there are enough retries */
++	do {
++		result = scsi_execute_req(sdev, cmd, DMA_NONE, NULL, 0, sshdr,
++					  timeout, retries);
++	} while ((driver_byte(result) & DRIVER_SENSE) &&
++		 sshdr && sshdr->sense_key == UNIT_ATTENTION &&
++		 --retries);
++
++	if (!sshdr)
++		/* could not allocate sense buffer, so can't process it */
++		return result;
  
- 	vports = lpfc_create_vport_work_array(phba);
- 	if (vports != NULL)
--		for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++) {
-+		for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) {
- 			struct Scsi_Host *shost;
- 			shost = lpfc_shost_from_vport(vports[i]);
- 			spin_lock_irq(shost->host_lock);
-@@ -1378,23 +1543,13 @@ lpfc_online(struct lpfc_hba *phba)
- 				vports[i]->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
- 			spin_unlock_irq(shost->host_lock);
- 		}
--		lpfc_destroy_vport_work_array(vports);
-+		lpfc_destroy_vport_work_array(phba, vports);
+ 	if ((driver_byte(result) & DRIVER_SENSE) && sdev->removable) {
  
- 	lpfc_unblock_mgmt_io(phba);
- 	return 0;
+-		if ((scsi_sense_valid(&sshdr)) &&
+-		    ((sshdr.sense_key == UNIT_ATTENTION) ||
+-		     (sshdr.sense_key == NOT_READY))) {
++		if ((scsi_sense_valid(sshdr)) &&
++		    ((sshdr->sense_key == UNIT_ATTENTION) ||
++		     (sshdr->sense_key == NOT_READY))) {
+ 			sdev->changed = 1;
+ 			result = 0;
+ 		}
+ 	}
++	if (!sshdr_external)
++		kfree(sshdr);
+ 	return result;
  }
+ EXPORT_SYMBOL(scsi_test_unit_ready);
  
- void
--lpfc_block_mgmt_io(struct lpfc_hba * phba)
--{
--	unsigned long iflag;
--
--	spin_lock_irqsave(&phba->hbalock, iflag);
--	phba->sli.sli_flag |= LPFC_BLOCK_MGMT_IO;
--	spin_unlock_irqrestore(&phba->hbalock, iflag);
--}
--
--void
- lpfc_unblock_mgmt_io(struct lpfc_hba * phba)
+ /**
+- *	scsi_device_set_state - Take the given device through the device
+- *		state model.
++ *	scsi_device_set_state - Take the given device through the device state model.
+  *	@sdev:	scsi device to change the state of.
+  *	@state:	state to change to.
+  *
+  *	Returns zero if unsuccessful or an error if the requested 
+  *	transition is illegal.
+- **/
++ */
+ int
+ scsi_device_set_state(struct scsi_device *sdev, enum scsi_device_state state)
  {
- 	unsigned long iflag;
-@@ -1409,6 +1564,8 @@ lpfc_offline_prep(struct lpfc_hba * phba)
+@@ -2264,7 +2188,7 @@ EXPORT_SYMBOL_GPL(sdev_evt_send_simple);
+  *	Must be called with user context, may sleep.
+  *
+  *	Returns zero if unsuccessful or an error if not.
+- **/
++ */
+ int
+ scsi_device_quiesce(struct scsi_device *sdev)
  {
- 	struct lpfc_vport *vport = phba->pport;
- 	struct lpfc_nodelist  *ndlp, *next_ndlp;
-+	struct lpfc_vport **vports;
-+	int i;
- 
- 	if (vport->fc_flag & FC_OFFLINE_MODE)
- 		return;
-@@ -1417,10 +1574,34 @@ lpfc_offline_prep(struct lpfc_hba * phba)
- 
- 	lpfc_linkdown(phba);
- 
--	/* Issue an unreg_login to all nodes */
--	list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp)
--		if (ndlp->nlp_state != NLP_STE_UNUSED_NODE)
--			lpfc_unreg_rpi(vport, ndlp);
-+	/* Issue an unreg_login to all nodes on all vports */
-+	vports = lpfc_create_vport_work_array(phba);
-+	if (vports != NULL) {
-+		for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) {
-+			struct Scsi_Host *shost;
-+
-+			if (vports[i]->load_flag & FC_UNLOADING)
-+				continue;
-+			shost =	lpfc_shost_from_vport(vports[i]);
-+			list_for_each_entry_safe(ndlp, next_ndlp,
-+						 &vports[i]->fc_nodes,
-+						 nlp_listp) {
-+				if (ndlp->nlp_state == NLP_STE_UNUSED_NODE)
-+					continue;
-+				if (ndlp->nlp_type & NLP_FABRIC) {
-+					lpfc_disc_state_machine(vports[i], ndlp,
-+						NULL, NLP_EVT_DEVICE_RECOVERY);
-+					lpfc_disc_state_machine(vports[i], ndlp,
-+						NULL, NLP_EVT_DEVICE_RM);
-+				}
-+				spin_lock_irq(shost->host_lock);
-+				ndlp->nlp_flag &= ~NLP_NPR_ADISC;
-+				spin_unlock_irq(shost->host_lock);
-+				lpfc_unreg_rpi(vports[i], ndlp);
-+			}
-+		}
-+	}
-+	lpfc_destroy_vport_work_array(phba, vports);
- 
- 	lpfc_sli_flush_mbox_queue(phba);
- }
-@@ -1439,9 +1620,9 @@ lpfc_offline(struct lpfc_hba *phba)
- 	lpfc_stop_phba_timers(phba);
- 	vports = lpfc_create_vport_work_array(phba);
- 	if (vports != NULL)
--		for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++)
-+		for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++)
- 			lpfc_stop_vport_timers(vports[i]);
--	lpfc_destroy_vport_work_array(vports);
-+	lpfc_destroy_vport_work_array(phba, vports);
- 	lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
- 			"0460 Bring Adapter offline\n");
- 	/* Bring down the SLI Layer and cleanup.  The HBA is offline
-@@ -1452,15 +1633,14 @@ lpfc_offline(struct lpfc_hba *phba)
- 	spin_unlock_irq(&phba->hbalock);
- 	vports = lpfc_create_vport_work_array(phba);
- 	if (vports != NULL)
--		for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++) {
-+		for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) {
- 			shost = lpfc_shost_from_vport(vports[i]);
--			lpfc_cleanup(vports[i]);
- 			spin_lock_irq(shost->host_lock);
- 			vports[i]->work_port_events = 0;
- 			vports[i]->fc_flag |= FC_OFFLINE_MODE;
- 			spin_unlock_irq(shost->host_lock);
- 		}
--	lpfc_destroy_vport_work_array(vports);
-+	lpfc_destroy_vport_work_array(phba, vports);
- }
- 
- /******************************************************************************
-@@ -1674,6 +1854,8 @@ void lpfc_host_attrib_init(struct Scsi_Host *shost)
- 	fc_host_supported_speeds(shost) = 0;
- 	if (phba->lmt & LMT_10Gb)
- 		fc_host_supported_speeds(shost) |= FC_PORTSPEED_10GBIT;
-+	if (phba->lmt & LMT_8Gb)
-+		fc_host_supported_speeds(shost) |= FC_PORTSPEED_8GBIT;
- 	if (phba->lmt & LMT_4Gb)
- 		fc_host_supported_speeds(shost) |= FC_PORTSPEED_4GBIT;
- 	if (phba->lmt & LMT_2Gb)
-@@ -1707,13 +1889,14 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
- 	struct Scsi_Host  *shost = NULL;
- 	void *ptr;
- 	unsigned long bar0map_len, bar2map_len;
--	int error = -ENODEV;
-+	int error = -ENODEV, retval;
- 	int  i, hbq_count;
- 	uint16_t iotag;
-+	int bars = pci_select_bars(pdev, IORESOURCE_MEM);
- 
--	if (pci_enable_device(pdev))
-+	if (pci_enable_device_bars(pdev, bars))
- 		goto out;
--	if (pci_request_regions(pdev, LPFC_DRIVER_NAME))
-+	if (pci_request_selected_regions(pdev, bars, LPFC_DRIVER_NAME))
- 		goto out_disable_device;
- 
- 	phba = kzalloc(sizeof (struct lpfc_hba), GFP_KERNEL);
-@@ -1823,9 +2006,11 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
- 	lpfc_sli_setup(phba);
- 	lpfc_sli_queue_setup(phba);
- 
--	error = lpfc_mem_alloc(phba);
--	if (error)
-+	retval = lpfc_mem_alloc(phba);
-+	if (retval) {
-+		error = retval;
- 		goto out_free_hbqslimp;
-+	}
- 
- 	/* Initialize and populate the iocb list per host.  */
- 	INIT_LIST_HEAD(&phba->lpfc_iocb_list);
-@@ -1880,6 +2065,9 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
- 	/* Initialize list of fabric iocbs */
- 	INIT_LIST_HEAD(&phba->fabric_iocb_list);
- 
-+	/* Initialize list to save ELS buffers */
-+	INIT_LIST_HEAD(&phba->elsbuf);
-+
- 	vport = lpfc_create_port(phba, phba->brd_no, &phba->pcidev->dev);
- 	if (!vport)
- 		goto out_kthread_stop;
-@@ -1891,8 +2079,8 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
- 	pci_set_drvdata(pdev, shost);
- 
- 	if (phba->cfg_use_msi) {
--		error = pci_enable_msi(phba->pcidev);
--		if (!error)
-+		retval = pci_enable_msi(phba->pcidev);
-+		if (!retval)
- 			phba->using_msi = 1;
- 		else
- 			lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
-@@ -1900,11 +2088,12 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
- 					"with IRQ\n");
- 	}
+@@ -2289,7 +2213,7 @@ EXPORT_SYMBOL(scsi_device_quiesce);
+  *	queues.
+  *
+  *	Must be called with user context, may sleep.
+- **/
++ */
+ void
+ scsi_device_resume(struct scsi_device *sdev)
+ {
+@@ -2326,8 +2250,7 @@ scsi_target_resume(struct scsi_target *starget)
+ EXPORT_SYMBOL(scsi_target_resume);
  
--	error =	request_irq(phba->pcidev->irq, lpfc_intr_handler, IRQF_SHARED,
-+	retval = request_irq(phba->pcidev->irq, lpfc_intr_handler, IRQF_SHARED,
- 			    LPFC_DRIVER_NAME, phba);
--	if (error) {
-+	if (retval) {
- 		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- 			"0451 Enable interrupt handler failed\n");
-+		error = retval;
- 		goto out_disable_msi;
- 	}
+ /**
+- * scsi_internal_device_block - internal function to put a device
+- *				temporarily into the SDEV_BLOCK state
++ * scsi_internal_device_block - internal function to put a device temporarily into the SDEV_BLOCK state
+  * @sdev:	device to block
+  *
+  * Block request made by scsi lld's to temporarily stop all
+@@ -2342,7 +2265,7 @@ EXPORT_SYMBOL(scsi_target_resume);
+  *	state, all commands are deferred until the scsi lld reenables
+  *	the device with scsi_device_unblock or device_block_tmo fires.
+  *	This routine assumes the host_lock is held on entry.
+- **/
++ */
+ int
+ scsi_internal_device_block(struct scsi_device *sdev)
+ {
+@@ -2382,7 +2305,7 @@ EXPORT_SYMBOL_GPL(scsi_internal_device_block);
+  *	(which must be a legal transition) allowing the midlayer to
+  *	goose the queue for this device.  This routine assumes the 
+  *	host_lock is held upon entry.
+- **/
++ */
+ int
+ scsi_internal_device_unblock(struct scsi_device *sdev)
+ {
+@@ -2460,7 +2383,7 @@ EXPORT_SYMBOL_GPL(scsi_target_unblock);
  
-@@ -1914,11 +2103,15 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
- 	phba->HSregaddr = phba->ctrl_regs_memmap_p + HS_REG_OFFSET;
- 	phba->HCregaddr = phba->ctrl_regs_memmap_p + HC_REG_OFFSET;
+ /**
+  * scsi_kmap_atomic_sg - find and atomically map an sg-elemnt
+- * @sg:		scatter-gather list
++ * @sgl:	scatter-gather list
+  * @sg_count:	number of segments in sg
+  * @offset:	offset in bytes into sg, on return offset into the mapped area
+  * @len:	bytes to map, on return number of bytes mapped
+@@ -2509,8 +2432,7 @@ void *scsi_kmap_atomic_sg(struct scatterlist *sgl, int sg_count,
+ EXPORT_SYMBOL(scsi_kmap_atomic_sg);
  
--	if (lpfc_alloc_sysfs_attr(vport))
-+	if (lpfc_alloc_sysfs_attr(vport)) {
-+		error = -ENOMEM;
- 		goto out_free_irq;
-+	}
+ /**
+- * scsi_kunmap_atomic_sg - atomically unmap a virtual address, previously
+- *			   mapped with scsi_kmap_atomic_sg
++ * scsi_kunmap_atomic_sg - atomically unmap a virtual address, previously mapped with scsi_kmap_atomic_sg
+  * @virt:	virtual address to be unmapped
+  */
+ void scsi_kunmap_atomic_sg(void *virt)
+diff --git a/drivers/scsi/scsi_netlink.c b/drivers/scsi/scsi_netlink.c
+index 40579ed..3e15918 100644
+--- a/drivers/scsi/scsi_netlink.c
++++ b/drivers/scsi/scsi_netlink.c
+@@ -32,11 +32,12 @@ EXPORT_SYMBOL_GPL(scsi_nl_sock);
  
--	if (lpfc_sli_hba_setup(phba))
-+	if (lpfc_sli_hba_setup(phba)) {
-+		error = -ENODEV;
- 		goto out_remove_device;
-+	}
  
- 	/*
- 	 * hba setup may have changed the hba_queue_depth so we need to adjust
-@@ -1975,7 +2168,7 @@ out_idr_remove:
- out_free_phba:
- 	kfree(phba);
- out_release_regions:
--	pci_release_regions(pdev);
-+	pci_release_selected_regions(pdev, bars);
- out_disable_device:
- 	pci_disable_device(pdev);
- out:
-@@ -1991,6 +2184,8 @@ lpfc_pci_remove_one(struct pci_dev *pdev)
- 	struct Scsi_Host  *shost = pci_get_drvdata(pdev);
- 	struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
- 	struct lpfc_hba   *phba = vport->phba;
-+	int bars = pci_select_bars(pdev, IORESOURCE_MEM);
-+
- 	spin_lock_irq(&phba->hbalock);
- 	vport->load_flag |= FC_UNLOADING;
- 	spin_unlock_irq(&phba->hbalock);
-@@ -1998,8 +2193,12 @@ lpfc_pci_remove_one(struct pci_dev *pdev)
- 	kfree(vport->vname);
- 	lpfc_free_sysfs_attr(vport);
+ /**
+- * scsi_nl_rcv_msg -
+- *    Receive message handler. Extracts message from a receive buffer.
++ * scsi_nl_rcv_msg - Receive message handler.
++ * @skb:		socket receive buffer
++ *
++ * Description: Extracts message from a receive buffer.
+  *    Validates message header and calls appropriate transport message handler
+  *
+- * @skb:		socket receive buffer
+  *
+  **/
+ static void
+@@ -99,9 +100,7 @@ next_msg:
  
-+	kthread_stop(phba->worker_thread);
-+
- 	fc_remove_host(shost);
- 	scsi_remove_host(shost);
-+	lpfc_cleanup(vport);
-+
- 	/*
- 	 * Bring down the SLI Layer. This step disable all interrupts,
- 	 * clears the rings, discards all mailbox commands, and resets
-@@ -2014,9 +2213,6 @@ lpfc_pci_remove_one(struct pci_dev *pdev)
- 	spin_unlock_irq(&phba->hbalock);
  
- 	lpfc_debugfs_terminate(vport);
--	lpfc_cleanup(vport);
--
--	kthread_stop(phba->worker_thread);
+ /**
+- * scsi_nl_rcv_event -
+- *    Event handler for a netlink socket.
+- *
++ * scsi_nl_rcv_event - Event handler for a netlink socket.
+  * @this:		event notifier block
+  * @event:		event type
+  * @ptr:		event payload
+@@ -129,9 +128,7 @@ static struct notifier_block scsi_netlink_notifier = {
  
- 	/* Release the irq reservation */
- 	free_irq(phba->pcidev->irq, phba);
-@@ -2048,7 +2244,7 @@ lpfc_pci_remove_one(struct pci_dev *pdev)
  
- 	kfree(phba);
+ /**
+- * scsi_netlink_init -
+- *    Called by SCSI subsystem to intialize the SCSI transport netlink
+- *    interface
++ * scsi_netlink_init - Called by SCSI subsystem to intialize the SCSI transport netlink interface
+  *
+  **/
+ void
+@@ -160,9 +157,7 @@ scsi_netlink_init(void)
  
--	pci_release_regions(pdev);
-+	pci_release_selected_regions(pdev, bars);
- 	pci_disable_device(pdev);
- }
  
-@@ -2239,12 +2435,22 @@ lpfc_init(void)
- 	printk(LPFC_MODULE_DESC "\n");
- 	printk(LPFC_COPYRIGHT "\n");
+ /**
+- * scsi_netlink_exit -
+- *    Called by SCSI subsystem to disable the SCSI transport netlink
+- *    interface
++ * scsi_netlink_exit - Called by SCSI subsystem to disable the SCSI transport netlink interface
+  *
+  **/
+ void
+diff --git a/drivers/scsi/scsi_proc.c b/drivers/scsi/scsi_proc.c
+index bb6f051..ed39515 100644
+--- a/drivers/scsi/scsi_proc.c
++++ b/drivers/scsi/scsi_proc.c
+@@ -45,6 +45,16 @@ static struct proc_dir_entry *proc_scsi;
+ /* Protect sht->present and sht->proc_dir */
+ static DEFINE_MUTEX(global_host_template_mutex);
  
-+	if (lpfc_enable_npiv) {
-+		lpfc_transport_functions.vport_create = lpfc_vport_create;
-+		lpfc_transport_functions.vport_delete = lpfc_vport_delete;
-+	}
- 	lpfc_transport_template =
- 				fc_attach_transport(&lpfc_transport_functions);
--	lpfc_vport_transport_template =
--			fc_attach_transport(&lpfc_vport_transport_functions);
--	if (!lpfc_transport_template || !lpfc_vport_transport_template)
-+	if (lpfc_transport_template == NULL)
- 		return -ENOMEM;
-+	if (lpfc_enable_npiv) {
-+		lpfc_vport_transport_template =
-+			fc_attach_transport(&lpfc_vport_transport_functions);
-+		if (lpfc_vport_transport_template == NULL) {
-+			fc_release_transport(lpfc_transport_template);
-+			return -ENOMEM;
-+		}
-+	}
- 	error = pci_register_driver(&lpfc_driver);
- 	if (error) {
- 		fc_release_transport(lpfc_transport_template);
-@@ -2259,7 +2465,8 @@ lpfc_exit(void)
++/**
++ * proc_scsi_read - handle read from /proc by calling host's proc_info() command
++ * @buffer: passed to proc_info
++ * @start: passed to proc_info
++ * @offset: passed to proc_info
++ * @length: passed to proc_info
++ * @eof: returns whether length read was less than requested
++ * @data: pointer to a &struct Scsi_Host
++ */
++
+ static int proc_scsi_read(char *buffer, char **start, off_t offset,
+ 			  int length, int *eof, void *data)
  {
- 	pci_unregister_driver(&lpfc_driver);
- 	fc_release_transport(lpfc_transport_template);
--	fc_release_transport(lpfc_vport_transport_template);
-+	if (lpfc_enable_npiv)
-+		fc_release_transport(lpfc_vport_transport_template);
+@@ -57,6 +67,13 @@ static int proc_scsi_read(char *buffer, char **start, off_t offset,
+ 	return n;
  }
  
- module_init(lpfc_init);
-diff --git a/drivers/scsi/lpfc/lpfc_logmsg.h b/drivers/scsi/lpfc/lpfc_logmsg.h
-index 626e4d8..c5841d7 100644
---- a/drivers/scsi/lpfc/lpfc_logmsg.h
-+++ b/drivers/scsi/lpfc/lpfc_logmsg.h
-@@ -26,6 +26,7 @@
- #define LOG_IP                        0x20	/* IP traffic history */
- #define LOG_FCP                       0x40	/* FCP traffic history */
- #define LOG_NODE                      0x80	/* Node table events */
-+#define LOG_TEMP                      0x100	/* Temperature sensor events */
- #define LOG_MISC                      0x400	/* Miscellaneous events */
- #define LOG_SLI                       0x800	/* SLI events */
- #define LOG_FCP_ERROR                 0x1000	/* log errors, not underruns */
-diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c
-index a592733..dfc63f6 100644
---- a/drivers/scsi/lpfc/lpfc_mbox.c
-+++ b/drivers/scsi/lpfc/lpfc_mbox.c
-@@ -82,6 +82,24 @@ lpfc_read_nv(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
++/**
++ * proc_scsi_write_proc - Handle write to /proc by calling host's proc_info()
++ * @file: not used
++ * @buf: source of data to write.
++ * @count: number of bytes (at most PROC_BLOCK_SIZE) to write.
++ * @data: pointer to &struct Scsi_Host
++ */
+ static int proc_scsi_write_proc(struct file *file, const char __user *buf,
+                            unsigned long count, void *data)
+ {
+@@ -80,6 +97,13 @@ out:
+ 	return ret;
  }
  
- /**********************************************/
-+/*  lpfc_config_async  Issue a                */
-+/*  MBX_ASYNC_EVT_ENABLE mailbox command      */
-+/**********************************************/
-+void
-+lpfc_config_async(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb,
-+		uint32_t ring)
-+{
-+	MAILBOX_t *mb;
-+
-+	mb = &pmb->mb;
-+	memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
-+	mb->mbxCommand = MBX_ASYNCEVT_ENABLE;
-+	mb->un.varCfgAsyncEvent.ring = ring;
-+	mb->mbxOwner = OWN_HOST;
-+	return;
-+}
++/**
++ * scsi_proc_hostdir_add - Create directory in /proc for a scsi host
++ * @sht: owner of this directory
++ *
++ * Sets sht->proc_dir to the new directory.
++ */
 +
-+/**********************************************/
- /*  lpfc_heart_beat  Issue a HEART_BEAT       */
- /*                mailbox command             */
- /**********************************************/
-@@ -270,8 +288,10 @@ lpfc_read_sparam(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb, int vpi)
- 
- 	/* Get a buffer to hold the HBAs Service Parameters */
- 
--	if (((mp = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL)) == 0) ||
--	    ((mp->virt = lpfc_mbuf_alloc(phba, 0, &(mp->phys))) == 0)) {
-+	mp = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL);
-+	if (mp)
-+		mp->virt = lpfc_mbuf_alloc(phba, 0, &mp->phys);
-+	if (!mp || !mp->virt) {
- 		kfree(mp);
- 		mb->mbxCommand = MBX_READ_SPARM64;
- 		/* READ_SPARAM: no buffers */
-@@ -369,8 +389,10 @@ lpfc_reg_login(struct lpfc_hba *phba, uint16_t vpi, uint32_t did,
- 	mb->mbxOwner = OWN_HOST;
+ void scsi_proc_hostdir_add(struct scsi_host_template *sht)
+ {
+ 	if (!sht->proc_info)
+@@ -97,6 +121,10 @@ void scsi_proc_hostdir_add(struct scsi_host_template *sht)
+ 	mutex_unlock(&global_host_template_mutex);
+ }
  
- 	/* Get a buffer to hold NPorts Service Parameters */
--	if (((mp = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL)) == NULL) ||
--	    ((mp->virt = lpfc_mbuf_alloc(phba, 0, &(mp->phys))) == 0)) {
-+	mp = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL);
-+	if (mp)
-+		mp->virt = lpfc_mbuf_alloc(phba, 0, &mp->phys);
-+	if (!mp || !mp->virt) {
- 		kfree(mp);
- 		mb->mbxCommand = MBX_REG_LOGIN64;
- 		/* REG_LOGIN: no buffers */
-@@ -874,7 +896,7 @@ lpfc_mbox_tmo_val(struct lpfc_hba *phba, int cmd)
- 	case MBX_DOWN_LOAD:	/* 0x1C */
- 	case MBX_DEL_LD_ENTRY:	/* 0x1D */
- 	case MBX_LOAD_AREA:	/* 0x81 */
--	case MBX_FLASH_WR_ULA:  /* 0x98 */
-+	case MBX_WRITE_WWN:     /* 0x98 */
- 	case MBX_LOAD_EXP_ROM:	/* 0x9C */
- 		return LPFC_MBOX_TMO_FLASH_CMD;
- 	}
-diff --git a/drivers/scsi/lpfc/lpfc_mem.c b/drivers/scsi/lpfc/lpfc_mem.c
-index 43c3b8a..6dc5ab8 100644
---- a/drivers/scsi/lpfc/lpfc_mem.c
-+++ b/drivers/scsi/lpfc/lpfc_mem.c
-@@ -98,6 +98,7 @@ lpfc_mem_alloc(struct lpfc_hba * phba)
++/**
++ * scsi_proc_hostdir_rm - remove directory in /proc for a scsi host
++ * @sht: owner of directory
++ */
+ void scsi_proc_hostdir_rm(struct scsi_host_template *sht)
+ {
+ 	if (!sht->proc_info)
+@@ -110,6 +138,11 @@ void scsi_proc_hostdir_rm(struct scsi_host_template *sht)
+ 	mutex_unlock(&global_host_template_mutex);
+ }
  
-  fail_free_hbq_pool:
- 	lpfc_sli_hbqbuf_free_all(phba);
-+	pci_pool_destroy(phba->lpfc_hbq_pool);
-  fail_free_nlp_mem_pool:
- 	mempool_destroy(phba->nlp_mem_pool);
- 	phba->nlp_mem_pool = NULL;
-diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c
-index 880af0c..4a0e340 100644
---- a/drivers/scsi/lpfc/lpfc_nportdisc.c
-+++ b/drivers/scsi/lpfc/lpfc_nportdisc.c
-@@ -287,6 +287,24 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
- 	pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
- 	lp = (uint32_t *) pcmd->virt;
- 	sp = (struct serv_parm *) ((uint8_t *) lp + sizeof (uint32_t));
-+	if (wwn_to_u64(sp->portName.u.wwn) == 0) {
-+		lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
-+				 "0140 PLOGI Reject: invalid nname\n");
-+		stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
-+		stat.un.b.lsRjtRsnCodeExp = LSEXP_INVALID_PNAME;
-+		lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp,
-+			NULL);
-+		return 0;
-+	}
-+	if (wwn_to_u64(sp->nodeName.u.wwn) == 0) {
-+		lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
-+				 "0141 PLOGI Reject: invalid pname\n");
-+		stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
-+		stat.un.b.lsRjtRsnCodeExp = LSEXP_INVALID_NNAME;
-+		lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp,
-+			NULL);
-+		return 0;
-+	}
- 	if ((lpfc_check_sparm(vport, ndlp, sp, CLASS3) == 0)) {
- 		/* Reject this request because invalid parameters */
- 		stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
-@@ -343,8 +361,7 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
- 		lpfc_config_link(phba, mbox);
- 		mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
- 		mbox->vport = vport;
--		rc = lpfc_sli_issue_mbox
--			(phba, mbox, (MBX_NOWAIT | MBX_STOP_IOCB));
-+		rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
- 		if (rc == MBX_NOT_FINISHED) {
- 			mempool_free(mbox, phba->mbox_mem_pool);
- 			goto out;
-@@ -407,6 +424,61 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
- 			ndlp, mbox);
- 		return 1;
- 	}
-+
-+	/* If the remote NPort logs into us, before we can initiate
-+	 * discovery to them, cleanup the NPort from discovery accordingly.
-+	 */
-+	if (ndlp->nlp_state == NLP_STE_NPR_NODE) {
-+		spin_lock_irq(shost->host_lock);
-+		ndlp->nlp_flag &= ~NLP_DELAY_TMO;
-+		spin_unlock_irq(shost->host_lock);
-+		del_timer_sync(&ndlp->nlp_delayfunc);
-+		ndlp->nlp_last_elscmd = 0;
-+
-+		if (!list_empty(&ndlp->els_retry_evt.evt_listp))
-+			list_del_init(&ndlp->els_retry_evt.evt_listp);
-+
-+		if (ndlp->nlp_flag & NLP_NPR_2B_DISC) {
-+			spin_lock_irq(shost->host_lock);
-+			ndlp->nlp_flag &= ~NLP_NPR_2B_DISC;
-+			spin_unlock_irq(shost->host_lock);
-+
-+			if ((ndlp->nlp_flag & NLP_ADISC_SND) &&
-+				(vport->num_disc_nodes)) {
-+				/* Check to see if there are more
-+				 * ADISCs to be sent
-+				 */
-+				lpfc_more_adisc(vport);
-+
-+				if ((vport->num_disc_nodes == 0) &&
-+					(vport->fc_npr_cnt))
-+					lpfc_els_disc_plogi(vport);
-+
-+				if (vport->num_disc_nodes == 0) {
-+					spin_lock_irq(shost->host_lock);
-+					vport->fc_flag &= ~FC_NDISC_ACTIVE;
-+					spin_unlock_irq(shost->host_lock);
-+					lpfc_can_disctmo(vport);
-+					lpfc_end_rscn(vport);
-+				}
-+			}
-+			else if (vport->num_disc_nodes) {
-+				/* Check to see if there are more
-+				 * PLOGIs to be sent
-+				 */
-+				lpfc_more_plogi(vport);
-+
-+				if (vport->num_disc_nodes == 0) {
-+					spin_lock_irq(shost->host_lock);
-+					vport->fc_flag &= ~FC_NDISC_ACTIVE;
-+					spin_unlock_irq(shost->host_lock);
-+					lpfc_can_disctmo(vport);
-+					lpfc_end_rscn(vport);
-+				}
-+			}
-+		}
-+	}
 +
- 	lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, ndlp, mbox);
- 	return 1;
- 
-@@ -501,12 +573,9 @@ lpfc_rcv_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
- 		spin_unlock_irq(shost->host_lock);
- 
- 		ndlp->nlp_last_elscmd = ELS_CMD_PLOGI;
--		ndlp->nlp_prev_state = ndlp->nlp_state;
--		lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
--	} else {
--		ndlp->nlp_prev_state = ndlp->nlp_state;
--		lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE);
- 	}
-+	ndlp->nlp_prev_state = ndlp->nlp_state;
-+	lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
++/**
++ * scsi_proc_host_add - Add entry for this host to appropriate /proc dir
++ * @shost: host to add
++ */
+ void scsi_proc_host_add(struct Scsi_Host *shost)
+ {
+ 	struct scsi_host_template *sht = shost->hostt;
+@@ -133,6 +166,10 @@ void scsi_proc_host_add(struct Scsi_Host *shost)
+ 	p->owner = sht->module;
+ }
  
- 	spin_lock_irq(shost->host_lock);
- 	ndlp->nlp_flag &= ~NLP_NPR_ADISC;
-@@ -594,6 +663,25 @@ lpfc_disc_illegal(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
- 	return ndlp->nlp_state;
++/**
++ * scsi_proc_host_rm - remove this host's entry from /proc
++ * @shost: which host
++ */
+ void scsi_proc_host_rm(struct Scsi_Host *shost)
+ {
+ 	char name[10];
+@@ -143,7 +180,14 @@ void scsi_proc_host_rm(struct Scsi_Host *shost)
+ 	sprintf(name,"%d", shost->host_no);
+ 	remove_proc_entry(name, shost->hostt->proc_dir);
+ }
+-
++/**
++ * proc_print_scsidevice - return data about this host
++ * @dev: A scsi device
++ * @data: &struct seq_file to output to.
++ *
++ * Description: prints Host, Channel, Id, Lun, Vendor, Model, Rev, Type,
++ * and revision.
++ */
+ static int proc_print_scsidevice(struct device *dev, void *data)
+ {
+ 	struct scsi_device *sdev = to_scsi_device(dev);
+@@ -189,6 +233,21 @@ static int proc_print_scsidevice(struct device *dev, void *data)
+ 	return 0;
  }
  
-+static uint32_t
-+lpfc_cmpl_plogi_illegal(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
-+		  void *arg, uint32_t evt)
-+{
-+	/* This transition is only legal if we previously
-+	 * rcv'ed a PLOGI. Since we don't want 2 discovery threads
-+	 * working on the same NPortID, do nothing for this thread
-+	 * to stop it.
-+	 */
-+	if (!(ndlp->nlp_flag & NLP_RCV_PLOGI)) {
-+		lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
-+			 "0253 Illegal State Transition: node x%x "
-+			 "event x%x, state x%x Data: x%x x%x\n",
-+			 ndlp->nlp_DID, evt, ndlp->nlp_state, ndlp->nlp_rpi,
-+			 ndlp->nlp_flag);
-+	}
-+	return ndlp->nlp_state;
-+}
++/**
++ * scsi_add_single_device - Respond to user request to probe for/add device
++ * @host: user-supplied decimal integer
++ * @channel: user-supplied decimal integer
++ * @id: user-supplied decimal integer
++ * @lun: user-supplied decimal integer
++ *
++ * Description: called by writing "scsi add-single-device" to /proc/scsi/scsi.
++ *
++ * does scsi_host_lookup() and either user_scan() if that transport
++ * type supports it, or else scsi_scan_host_selected()
++ *
++ * Note: this seems to be aimed exclusively at SCSI parallel busses.
++ */
 +
- /* Start of Discovery State Machine routines */
- 
- static uint32_t
-@@ -605,11 +693,8 @@ lpfc_rcv_plogi_unused_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
- 	cmdiocb = (struct lpfc_iocbq *) arg;
- 
- 	if (lpfc_rcv_plogi(vport, ndlp, cmdiocb)) {
--		ndlp->nlp_prev_state = NLP_STE_UNUSED_NODE;
--		lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE);
- 		return ndlp->nlp_state;
- 	}
--	lpfc_drop_node(vport, ndlp);
- 	return NLP_STE_FREED_NODE;
+ static int scsi_add_single_device(uint host, uint channel, uint id, uint lun)
+ {
+ 	struct Scsi_Host *shost;
+@@ -206,6 +265,16 @@ static int scsi_add_single_device(uint host, uint channel, uint id, uint lun)
+ 	return error;
  }
  
-@@ -618,7 +703,6 @@ lpfc_rcv_els_unused_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
- 			 void *arg, uint32_t evt)
++/**
++ * scsi_remove_single_device - Respond to user request to remove a device
++ * @host: user-supplied decimal integer
++ * @channel: user-supplied decimal integer
++ * @id: user-supplied decimal integer
++ * @lun: user-supplied decimal integer
++ *
++ * Description: called by writing "scsi remove-single-device" to
++ * /proc/scsi/scsi.  Does a scsi_device_lookup() and scsi_remove_device()
++ */
+ static int scsi_remove_single_device(uint host, uint channel, uint id, uint lun)
  {
- 	lpfc_issue_els_logo(vport, ndlp, 0);
--	lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE);
- 	return ndlp->nlp_state;
+ 	struct scsi_device *sdev;
+@@ -226,6 +295,25 @@ static int scsi_remove_single_device(uint host, uint channel, uint id, uint lun)
+ 	return error;
  }
  
-@@ -633,7 +717,6 @@ lpfc_rcv_logo_unused_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
- 	ndlp->nlp_flag |= NLP_LOGO_ACC;
- 	spin_unlock_irq(shost->host_lock);
- 	lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL);
--	lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE);
- 
- 	return ndlp->nlp_state;
- }
-@@ -642,7 +725,6 @@ static uint32_t
- lpfc_cmpl_logo_unused_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
- 			   void *arg, uint32_t evt)
++/**
++ * proc_scsi_write - handle writes to /proc/scsi/scsi
++ * @file: not used
++ * @buf: buffer to write
++ * @length: length of buf, at most PAGE_SIZE
++ * @ppos: not used
++ *
++ * Description: this provides a legacy mechanism to add or remove devices by
++ * Host, Channel, ID, and Lun.  To use,
++ * "echo 'scsi add-single-device 0 1 2 3' > /proc/scsi/scsi" or
++ * "echo 'scsi remove-single-device 0 1 2 3' > /proc/scsi/scsi" with
++ * "0 1 2 3" replaced by the Host, Channel, Id, and Lun.
++ *
++ * Note: this seems to be aimed at parallel SCSI. Most modern busses (USB,
++ * SATA, Firewire, Fibre Channel, etc) dynamically assign these values to
++ * provide a unique identifier and nothing more.
++ */
++
++
+ static ssize_t proc_scsi_write(struct file *file, const char __user *buf,
+ 			       size_t length, loff_t *ppos)
  {
--	lpfc_drop_node(vport, ndlp);
- 	return NLP_STE_FREED_NODE;
+@@ -291,6 +379,11 @@ static ssize_t proc_scsi_write(struct file *file, const char __user *buf,
+ 	return err;
  }
  
-@@ -650,7 +732,6 @@ static uint32_t
- lpfc_device_rm_unused_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
- 			   void *arg, uint32_t evt)
++/**
++ * proc_scsi_show - show contents of /proc/scsi/scsi (attached devices)
++ * @s: output goes here
++ * @p: not used
++ */
+ static int proc_scsi_show(struct seq_file *s, void *p)
  {
--	lpfc_drop_node(vport, ndlp);
- 	return NLP_STE_FREED_NODE;
+ 	seq_printf(s, "Attached devices:\n");
+@@ -298,10 +391,17 @@ static int proc_scsi_show(struct seq_file *s, void *p)
+ 	return 0;
  }
  
-@@ -752,6 +833,7 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport,
- 			    uint32_t evt)
++/**
++ * proc_scsi_open - glue function
++ * @inode: not used
++ * @file: passed to single_open()
++ *
++ * Associates proc_scsi_show with this file
++ */
+ static int proc_scsi_open(struct inode *inode, struct file *file)
  {
- 	struct lpfc_hba    *phba = vport->phba;
-+	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
- 	struct lpfc_iocbq  *cmdiocb, *rspiocb;
- 	struct lpfc_dmabuf *pcmd, *prsp, *mp;
- 	uint32_t *lp;
-@@ -778,6 +860,12 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport,
- 
- 	lp = (uint32_t *) prsp->virt;
- 	sp = (struct serv_parm *) ((uint8_t *) lp + sizeof (uint32_t));
-+	if (wwn_to_u64(sp->portName.u.wwn) == 0 ||
-+	    wwn_to_u64(sp->nodeName.u.wwn) == 0) {
-+		lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
-+				 "0142 PLOGI RSP: Invalid WWN.\n");
-+		goto out;
-+	}
- 	if (!lpfc_check_sparm(vport, ndlp, sp, CLASS3))
- 		goto out;
- 	/* PLOGI chkparm OK */
-@@ -828,13 +916,15 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport,
- 		}
- 		mbox->context2 = lpfc_nlp_get(ndlp);
- 		mbox->vport = vport;
--		if (lpfc_sli_issue_mbox(phba, mbox,
--					(MBX_NOWAIT | MBX_STOP_IOCB))
-+		if (lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT)
- 		    != MBX_NOT_FINISHED) {
- 			lpfc_nlp_set_state(vport, ndlp,
- 					   NLP_STE_REG_LOGIN_ISSUE);
- 			return ndlp->nlp_state;
- 		}
-+		/* decrement node reference count to the failed mbox
-+		 * command
-+		 */
- 		lpfc_nlp_put(ndlp);
- 		mp = (struct lpfc_dmabuf *) mbox->context1;
- 		lpfc_mbuf_free(phba, mp->virt, mp->phys);
-@@ -864,13 +954,27 @@ out:
- 				 "0261 Cannot Register NameServer login\n");
- 	}
+ 	/*
+-	 * We don't really needs this for the write case but it doesn't
++	 * We don't really need this for the write case but it doesn't
+ 	 * harm either.
+ 	 */
+ 	return single_open(file, proc_scsi_show, NULL);
+@@ -315,6 +415,9 @@ static const struct file_operations proc_scsi_operations = {
+ 	.release	= single_release,
+ };
  
--	/* Free this node since the driver cannot login or has the wrong
--	   sparm */
--	lpfc_drop_node(vport, ndlp);
-+	spin_lock_irq(shost->host_lock);
-+	ndlp->nlp_flag |= NLP_DEFER_RM;
-+	spin_unlock_irq(shost->host_lock);
- 	return NLP_STE_FREED_NODE;
++/**
++ * scsi_init_procfs - create scsi and scsi/scsi in procfs
++ */
+ int __init scsi_init_procfs(void)
+ {
+ 	struct proc_dir_entry *pde;
+@@ -336,6 +439,9 @@ err1:
+ 	return -ENOMEM;
  }
  
- static uint32_t
-+lpfc_cmpl_logo_plogi_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
-+			   void *arg, uint32_t evt)
-+{
-+	return ndlp->nlp_state;
-+}
-+
-+static uint32_t
-+lpfc_cmpl_reglogin_plogi_issue(struct lpfc_vport *vport,
-+	struct lpfc_nodelist *ndlp, void *arg, uint32_t evt)
-+{
-+	return ndlp->nlp_state;
-+}
-+
-+static uint32_t
- lpfc_device_rm_plogi_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
- 			   void *arg, uint32_t evt)
++/**
++ * scsi_exit_procfs - Remove scsi/scsi and scsi from procfs
++ */
+ void scsi_exit_procfs(void)
  {
-@@ -1137,7 +1241,7 @@ lpfc_rcv_logo_reglogin_issue(struct lpfc_vport *vport,
- 		   (ndlp == (struct lpfc_nodelist *) mb->context2)) {
- 			mp = (struct lpfc_dmabuf *) (mb->context1);
- 			if (mp) {
--				lpfc_mbuf_free(phba, mp->virt, mp->phys);
-+				__lpfc_mbuf_free(phba, mp->virt, mp->phys);
- 				kfree(mp);
- 			}
- 			lpfc_nlp_put(ndlp);
-@@ -1197,8 +1301,8 @@ lpfc_cmpl_reglogin_reglogin_issue(struct lpfc_vport *vport,
- 		 * retry discovery.
- 		 */
- 		if (mb->mbxStatus == MBXERR_RPI_FULL) {
--			ndlp->nlp_prev_state = NLP_STE_UNUSED_NODE;
--			lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE);
-+			ndlp->nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE;
-+			lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
- 			return ndlp->nlp_state;
- 		}
+ 	remove_proc_entry("scsi/scsi", NULL);
+diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
+index 40ea71c..1dc165a 100644
+--- a/drivers/scsi/scsi_scan.c
++++ b/drivers/scsi/scsi_scan.c
+@@ -221,6 +221,9 @@ static void scsi_unlock_floptical(struct scsi_device *sdev,
  
-@@ -1378,7 +1482,7 @@ out:
- 		lpfc_issue_els_logo(vport, ndlp, 0);
+ /**
+  * scsi_alloc_sdev - allocate and setup a scsi_Device
++ * @starget: which target to allocate a &scsi_device for
++ * @lun: which lun
++ * @hostdata: usually NULL and set by ->slave_alloc instead
+  *
+  * Description:
+  *     Allocate, initialize for io, and return a pointer to a scsi_Device.
+@@ -472,7 +475,6 @@ static void scsi_target_reap_usercontext(struct work_struct *work)
  
- 		ndlp->nlp_prev_state = NLP_STE_PRLI_ISSUE;
--		lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE);
-+		lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
- 		return ndlp->nlp_state;
- 	}
+ /**
+  * scsi_target_reap - check to see if target is in use and destroy if not
+- *
+  * @starget: target to be checked
+  *
+  * This is used after removing a LUN or doing a last put of the target
+@@ -863,7 +865,7 @@ static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result,
+ 		sdev->no_start_on_add = 1;
  
-@@ -1753,7 +1857,7 @@ lpfc_cmpl_plogi_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ 	if (*bflags & BLIST_SINGLELUN)
+-		sdev->single_lun = 1;
++		scsi_target(sdev)->single_lun = 1;
  
- 	irsp = &rspiocb->iocb;
- 	if (irsp->ulpStatus) {
--		lpfc_drop_node(vport, ndlp);
-+		ndlp->nlp_flag |= NLP_DEFER_RM;
- 		return NLP_STE_FREED_NODE;
- 	}
- 	return ndlp->nlp_state;
-@@ -1942,9 +2046,9 @@ static uint32_t (*lpfc_disc_action[NLP_STE_MAX_STATE * NLP_EVT_MAX_EVENT])
- 	lpfc_rcv_els_plogi_issue,	/* RCV_PRLO        */
- 	lpfc_cmpl_plogi_plogi_issue,	/* CMPL_PLOGI      */
- 	lpfc_disc_illegal,		/* CMPL_PRLI       */
--	lpfc_disc_illegal,		/* CMPL_LOGO       */
-+	lpfc_cmpl_logo_plogi_issue,	/* CMPL_LOGO       */
- 	lpfc_disc_illegal,		/* CMPL_ADISC      */
--	lpfc_disc_illegal,		/* CMPL_REG_LOGIN  */
-+	lpfc_cmpl_reglogin_plogi_issue,/* CMPL_REG_LOGIN  */
- 	lpfc_device_rm_plogi_issue,	/* DEVICE_RM       */
- 	lpfc_device_recov_plogi_issue,	/* DEVICE_RECOVERY */
+ 	sdev->use_10_for_rw = 1;
  
-@@ -1968,7 +2072,7 @@ static uint32_t (*lpfc_disc_action[NLP_STE_MAX_STATE * NLP_EVT_MAX_EVENT])
- 	lpfc_rcv_padisc_reglogin_issue,	/* RCV_ADISC       */
- 	lpfc_rcv_padisc_reglogin_issue,	/* RCV_PDISC       */
- 	lpfc_rcv_prlo_reglogin_issue,	/* RCV_PRLO        */
--	lpfc_disc_illegal,		/* CMPL_PLOGI      */
-+	lpfc_cmpl_plogi_illegal,	/* CMPL_PLOGI      */
- 	lpfc_disc_illegal,		/* CMPL_PRLI       */
- 	lpfc_disc_illegal,		/* CMPL_LOGO       */
- 	lpfc_disc_illegal,		/* CMPL_ADISC      */
-@@ -1982,7 +2086,7 @@ static uint32_t (*lpfc_disc_action[NLP_STE_MAX_STATE * NLP_EVT_MAX_EVENT])
- 	lpfc_rcv_padisc_prli_issue,	/* RCV_ADISC       */
- 	lpfc_rcv_padisc_prli_issue,	/* RCV_PDISC       */
- 	lpfc_rcv_prlo_prli_issue,	/* RCV_PRLO        */
--	lpfc_disc_illegal,		/* CMPL_PLOGI      */
-+	lpfc_cmpl_plogi_illegal,	/* CMPL_PLOGI      */
- 	lpfc_cmpl_prli_prli_issue,	/* CMPL_PRLI       */
- 	lpfc_disc_illegal,		/* CMPL_LOGO       */
- 	lpfc_disc_illegal,		/* CMPL_ADISC      */
-diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c
-index 4e46045..6483c62 100644
---- a/drivers/scsi/lpfc/lpfc_scsi.c
-+++ b/drivers/scsi/lpfc/lpfc_scsi.c
-@@ -130,7 +130,7 @@ lpfc_ramp_down_queue_handler(struct lpfc_hba *phba)
+@@ -928,8 +930,7 @@ static inline void scsi_destroy_sdev(struct scsi_device *sdev)
  
- 	vports = lpfc_create_vport_work_array(phba);
- 	if (vports != NULL)
--		for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++) {
-+		for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) {
- 			shost = lpfc_shost_from_vport(vports[i]);
- 			shost_for_each_device(sdev, shost) {
- 				new_queue_depth =
-@@ -151,7 +151,7 @@ lpfc_ramp_down_queue_handler(struct lpfc_hba *phba)
- 							new_queue_depth);
- 			}
- 		}
--	lpfc_destroy_vport_work_array(vports);
-+	lpfc_destroy_vport_work_array(phba, vports);
- 	atomic_set(&phba->num_rsrc_err, 0);
- 	atomic_set(&phba->num_cmd_success, 0);
- }
-@@ -166,7 +166,7 @@ lpfc_ramp_up_queue_handler(struct lpfc_hba *phba)
+ #ifdef CONFIG_SCSI_LOGGING
+ /** 
+- * scsi_inq_str - print INQUIRY data from min to max index,
+- * strip trailing whitespace
++ * scsi_inq_str - print INQUIRY data from min to max index, strip trailing whitespace
+  * @buf:   Output buffer with at least end-first+1 bytes of space
+  * @inq:   Inquiry buffer (input)
+  * @first: Offset of string into inq
+@@ -957,9 +958,10 @@ static unsigned char *scsi_inq_str(unsigned char *buf, unsigned char *inq,
+  * scsi_probe_and_add_lun - probe a LUN, if a LUN is found add it
+  * @starget:	pointer to target device structure
+  * @lun:	LUN of target device
+- * @sdevscan:	probe the LUN corresponding to this scsi_device
+- * @sdevnew:	store the value of any new scsi_device allocated
+  * @bflagsp:	store bflags here if not NULL
++ * @sdevp:	probe the LUN corresponding to this scsi_device
++ * @rescan:     if nonzero skip some code only needed on first scan
++ * @hostdata:	passed to scsi_alloc_sdev()
+  *
+  * Description:
+  *     Call scsi_probe_lun, if a LUN with an attached device is found,
+@@ -1110,6 +1112,8 @@ static int scsi_probe_and_add_lun(struct scsi_target *starget,
+  * scsi_sequential_lun_scan - sequentially scan a SCSI target
+  * @starget:	pointer to target structure to scan
+  * @bflags:	black/white list flag for LUN 0
++ * @scsi_level: Which version of the standard does this device adhere to
++ * @rescan:     passed to scsi_probe_add_lun()
+  *
+  * Description:
+  *     Generally, scan from LUN 1 (LUN 0 is assumed to already have been
+@@ -1220,7 +1224,7 @@ EXPORT_SYMBOL(scsilun_to_int);
  
- 	vports = lpfc_create_vport_work_array(phba);
- 	if (vports != NULL)
--		for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++) {
-+		for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) {
- 			shost = lpfc_shost_from_vport(vports[i]);
- 			shost_for_each_device(sdev, shost) {
- 				if (sdev->ordered_tags)
-@@ -179,7 +179,7 @@ lpfc_ramp_up_queue_handler(struct lpfc_hba *phba)
- 							sdev->queue_depth+1);
- 			}
- 		}
--	lpfc_destroy_vport_work_array(vports);
-+	lpfc_destroy_vport_work_array(phba, vports);
- 	atomic_set(&phba->num_rsrc_err, 0);
- 	atomic_set(&phba->num_cmd_success, 0);
- }
-@@ -380,7 +380,7 @@ lpfc_scsi_prep_dma_buf(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd)
- 		(num_bde * sizeof (struct ulp_bde64));
- 	iocb_cmd->ulpBdeCount = 1;
- 	iocb_cmd->ulpLe = 1;
--	fcp_cmnd->fcpDl = be32_to_cpu(scsi_bufflen(scsi_cmnd));
-+	fcp_cmnd->fcpDl = cpu_to_be32(scsi_bufflen(scsi_cmnd));
- 	return 0;
- }
+ /**
+  * int_to_scsilun: reverts an int into a scsi_lun
+- * @int:        integer to be reverted
++ * @lun:        integer to be reverted
+  * @scsilun:	struct scsi_lun to be set.
+  *
+  * Description:
+@@ -1252,18 +1256,22 @@ EXPORT_SYMBOL(int_to_scsilun);
  
-@@ -542,6 +542,7 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
- 	int result;
- 	struct scsi_device *sdev, *tmp_sdev;
- 	int depth = 0;
-+	unsigned long flags;
+ /**
+  * scsi_report_lun_scan - Scan using SCSI REPORT LUN results
+- * @sdevscan:	scan the host, channel, and id of this scsi_device
++ * @starget: which target
++ * @bflags: Zero or a mix of BLIST_NOLUN, BLIST_REPORTLUN2, or BLIST_NOREPORTLUN
++ * @rescan: nonzero if we can skip code only needed on first scan
+  *
+  * Description:
+- *     If @sdevscan is for a SCSI-3 or up device, send a REPORT LUN
+- *     command, and scan the resulting list of LUNs by calling
+- *     scsi_probe_and_add_lun.
++ *   Fast scanning for modern (SCSI-3) devices by sending a REPORT LUN command.
++ *   Scan the resulting list of LUNs by calling scsi_probe_and_add_lun.
+  *
+- *     Modifies sdevscan->lun.
++ *   If BLINK_REPORTLUN2 is set, scan a target that supports more than 8
++ *   LUNs even if it's older than SCSI-3.
++ *   If BLIST_NOREPORTLUN is set, return 1 always.
++ *   If BLIST_NOLUN is set, return 0 always.
+  *
+  * Return:
+  *     0: scan completed (or no memory, so further scanning is futile)
+- *     1: no report lun scan, or not configured
++ *     1: could not scan with REPORT LUN
+  **/
+ static int scsi_report_lun_scan(struct scsi_target *starget, int bflags,
+ 				int rescan)
+@@ -1481,6 +1489,7 @@ struct scsi_device *__scsi_add_device(struct Scsi_Host *shost, uint channel,
+ 	if (scsi_host_scan_allowed(shost))
+ 		scsi_probe_and_add_lun(starget, lun, NULL, &sdev, 1, hostdata);
+ 	mutex_unlock(&shost->scan_mutex);
++	transport_configure_device(&starget->dev);
+ 	scsi_target_reap(starget);
+ 	put_device(&starget->dev);
  
- 	lpfc_cmd->result = pIocbOut->iocb.un.ulpWord[4];
- 	lpfc_cmd->status = pIocbOut->iocb.ulpStatus;
-@@ -608,6 +609,15 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
- 	cmd->scsi_done(cmd);
+@@ -1561,6 +1570,7 @@ static void __scsi_scan_target(struct device *parent, unsigned int channel,
+  out_reap:
+ 	/* now determine if the target has any children at all
+ 	 * and if not, nuke it */
++	transport_configure_device(&starget->dev);
+ 	scsi_target_reap(starget);
  
- 	if (phba->cfg_poll & ENABLE_FCP_RING_POLLING) {
-+		/*
-+		 * If there is a thread waiting for command completion
-+		 * wake up the thread.
-+		 */
-+		spin_lock_irqsave(sdev->host->host_lock, flags);
-+		lpfc_cmd->pCmd = NULL;
-+		if (lpfc_cmd->waitq)
-+			wake_up(lpfc_cmd->waitq);
-+		spin_unlock_irqrestore(sdev->host->host_lock, flags);
- 		lpfc_release_scsi_buf(phba, lpfc_cmd);
- 		return;
- 	}
-@@ -669,6 +679,16 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
- 		}
+ 	put_device(&starget->dev);
+diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
+index 00b3866..ed83cdb 100644
+--- a/drivers/scsi/scsi_sysfs.c
++++ b/drivers/scsi/scsi_sysfs.c
+@@ -1018,6 +1018,7 @@ int scsi_sysfs_add_host(struct Scsi_Host *shost)
  	}
  
-+	/*
-+	 * If there is a thread waiting for command completion
-+	 * wake up the thread.
-+	 */
-+	spin_lock_irqsave(sdev->host->host_lock, flags);
-+	lpfc_cmd->pCmd = NULL;
-+	if (lpfc_cmd->waitq)
-+		wake_up(lpfc_cmd->waitq);
-+	spin_unlock_irqrestore(sdev->host->host_lock, flags);
-+
- 	lpfc_release_scsi_buf(phba, lpfc_cmd);
+ 	transport_register_device(&shost->shost_gendev);
++	transport_configure_device(&shost->shost_gendev);
+ 	return 0;
  }
  
-@@ -743,6 +763,8 @@ lpfc_scsi_prep_cmnd(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd,
- 	piocbq->iocb.ulpContext = pnode->nlp_rpi;
- 	if (pnode->nlp_fcp_info & NLP_FCP_2_DEVICE)
- 		piocbq->iocb.ulpFCP2Rcvy = 1;
-+	else
-+		piocbq->iocb.ulpFCP2Rcvy = 0;
+diff --git a/drivers/scsi/scsi_tgt_if.c b/drivers/scsi/scsi_tgt_if.c
+index 9815a1a..d2557db 100644
+--- a/drivers/scsi/scsi_tgt_if.c
++++ b/drivers/scsi/scsi_tgt_if.c
+@@ -112,7 +112,7 @@ int scsi_tgt_uspace_send_cmd(struct scsi_cmnd *cmd, u64 itn_id,
+ 	memset(&ev, 0, sizeof(ev));
+ 	ev.p.cmd_req.host_no = shost->host_no;
+ 	ev.p.cmd_req.itn_id = itn_id;
+-	ev.p.cmd_req.data_len = cmd->request_bufflen;
++	ev.p.cmd_req.data_len = scsi_bufflen(cmd);
+ 	memcpy(ev.p.cmd_req.scb, cmd->cmnd, sizeof(ev.p.cmd_req.scb));
+ 	memcpy(ev.p.cmd_req.lun, lun, sizeof(ev.p.cmd_req.lun));
+ 	ev.p.cmd_req.attribute = cmd->tag;
+diff --git a/drivers/scsi/scsi_tgt_lib.c b/drivers/scsi/scsi_tgt_lib.c
+index a91761c..01e03f3 100644
+--- a/drivers/scsi/scsi_tgt_lib.c
++++ b/drivers/scsi/scsi_tgt_lib.c
+@@ -180,7 +180,7 @@ static void scsi_tgt_cmd_destroy(struct work_struct *work)
+ 		container_of(work, struct scsi_tgt_cmd, work);
+ 	struct scsi_cmnd *cmd = tcmd->rq->special;
  
- 	piocbq->iocb.ulpClass = (pnode->nlp_fcp_info & 0x0f);
- 	piocbq->context1  = lpfc_cmd;
-@@ -1018,8 +1040,8 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd)
- 	struct lpfc_iocbq *abtsiocb;
- 	struct lpfc_scsi_buf *lpfc_cmd;
- 	IOCB_t *cmd, *icmd;
--	unsigned int loop_count = 0;
- 	int ret = SUCCESS;
-+	DECLARE_WAIT_QUEUE_HEAD_ONSTACK(waitq);
+-	dprintk("cmd %p %d %lu\n", cmd, cmd->sc_data_direction,
++	dprintk("cmd %p %d %u\n", cmd, cmd->sc_data_direction,
+ 		rq_data_dir(cmd->request));
+ 	scsi_unmap_user_pages(tcmd);
+ 	scsi_host_put_command(scsi_tgt_cmd_to_host(cmd), cmd);
+@@ -327,11 +327,11 @@ static void scsi_tgt_cmd_done(struct scsi_cmnd *cmd)
+ {
+ 	struct scsi_tgt_cmd *tcmd = cmd->request->end_io_data;
  
- 	lpfc_block_error_handler(cmnd);
- 	lpfc_cmd = (struct lpfc_scsi_buf *)cmnd->host_scribble;
-@@ -1074,17 +1096,15 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd)
- 	if (phba->cfg_poll & DISABLE_FCP_RING_INT)
- 		lpfc_sli_poll_fcp_ring (phba);
+-	dprintk("cmd %p %lu\n", cmd, rq_data_dir(cmd->request));
++	dprintk("cmd %p %u\n", cmd, rq_data_dir(cmd->request));
  
-+	lpfc_cmd->waitq = &waitq;
- 	/* Wait for abort to complete */
--	while (lpfc_cmd->pCmd == cmnd)
--	{
--		if (phba->cfg_poll & DISABLE_FCP_RING_INT)
--			lpfc_sli_poll_fcp_ring (phba);
-+	wait_event_timeout(waitq,
-+			  (lpfc_cmd->pCmd != cmnd),
-+			   (2*vport->cfg_devloss_tmo*HZ));
+ 	scsi_tgt_uspace_send_status(cmd, tcmd->itn_id, tcmd->tag);
  
--		schedule_timeout_uninterruptible(LPFC_ABORT_WAIT * HZ);
--		if (++loop_count
--		    > (2 * vport->cfg_devloss_tmo)/LPFC_ABORT_WAIT)
--			break;
--	}
-+	spin_lock_irq(shost->host_lock);
-+	lpfc_cmd->waitq = NULL;
-+	spin_unlock_irq(shost->host_lock);
+-	if (cmd->request_buffer)
++	if (scsi_sglist(cmd))
+ 		scsi_free_sgtable(cmd);
  
- 	if (lpfc_cmd->pCmd == cmnd) {
- 		ret = FAILED;
-@@ -1438,7 +1458,7 @@ struct scsi_host_template lpfc_template = {
- 	.slave_destroy		= lpfc_slave_destroy,
- 	.scan_finished		= lpfc_scan_finished,
- 	.this_id		= -1,
--	.sg_tablesize		= LPFC_SG_SEG_CNT,
-+	.sg_tablesize		= LPFC_DEFAULT_SG_SEG_CNT,
- 	.use_sg_chaining	= ENABLE_SG_CHAINING,
- 	.cmd_per_lun		= LPFC_CMD_PER_LUN,
- 	.use_clustering		= ENABLE_CLUSTERING,
-@@ -1459,7 +1479,7 @@ struct scsi_host_template lpfc_vport_template = {
- 	.slave_destroy		= lpfc_slave_destroy,
- 	.scan_finished		= lpfc_scan_finished,
- 	.this_id		= -1,
--	.sg_tablesize		= LPFC_SG_SEG_CNT,
-+	.sg_tablesize		= LPFC_DEFAULT_SG_SEG_CNT,
- 	.cmd_per_lun		= LPFC_CMD_PER_LUN,
- 	.use_clustering		= ENABLE_CLUSTERING,
- 	.use_sg_chaining	= ENABLE_SG_CHAINING,
-diff --git a/drivers/scsi/lpfc/lpfc_scsi.h b/drivers/scsi/lpfc/lpfc_scsi.h
-index 31787bb..daba923 100644
---- a/drivers/scsi/lpfc/lpfc_scsi.h
-+++ b/drivers/scsi/lpfc/lpfc_scsi.h
-@@ -138,6 +138,7 @@ struct lpfc_scsi_buf {
- 	 * Iotag is in here
- 	 */
- 	struct lpfc_iocbq cur_iocbq;
-+	wait_queue_head_t *waitq;
- };
+ 	queue_work(scsi_tgtd, &tcmd->work);
+@@ -342,7 +342,7 @@ static int scsi_tgt_transfer_response(struct scsi_cmnd *cmd)
+ 	struct Scsi_Host *shost = scsi_tgt_cmd_to_host(cmd);
+ 	int err;
  
- #define LPFC_SCSI_DMA_EXT_SIZE 264
-diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c
-index ce348c5..fdd01e3 100644
---- a/drivers/scsi/lpfc/lpfc_sli.c
-+++ b/drivers/scsi/lpfc/lpfc_sli.c
-@@ -106,7 +106,7 @@ lpfc_sli_get_iocbq(struct lpfc_hba *phba)
- 	return iocbq;
- }
+-	dprintk("cmd %p %lu\n", cmd, rq_data_dir(cmd->request));
++	dprintk("cmd %p %u\n", cmd, rq_data_dir(cmd->request));
  
--void
-+static void
- __lpfc_sli_release_iocbq(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq)
- {
- 	size_t start_clean = offsetof(struct lpfc_iocbq, iocb);
-@@ -199,6 +199,7 @@ lpfc_sli_iocb_cmd_type(uint8_t iocb_cmnd)
- 	case CMD_RCV_ELS_REQ_CX:
- 	case CMD_RCV_SEQUENCE64_CX:
- 	case CMD_RCV_ELS_REQ64_CX:
-+	case CMD_ASYNC_STATUS:
- 	case CMD_IOCB_RCV_SEQ64_CX:
- 	case CMD_IOCB_RCV_ELS64_CX:
- 	case CMD_IOCB_RCV_CONT64_CX:
-@@ -473,8 +474,7 @@ lpfc_sli_resume_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
- 	if (pring->txq_cnt &&
- 	    lpfc_is_link_up(phba) &&
- 	    (pring->ringno != phba->sli.fcp_ring ||
--	     phba->sli.sli_flag & LPFC_PROCESS_LA) &&
--	    !(pring->flag & LPFC_STOP_IOCB_MBX)) {
-+	     phba->sli.sli_flag & LPFC_PROCESS_LA)) {
+ 	err = shost->hostt->transfer_response(cmd, scsi_tgt_cmd_done);
+ 	switch (err) {
+@@ -359,22 +359,17 @@ static int scsi_tgt_init_cmd(struct scsi_cmnd *cmd, gfp_t gfp_mask)
+ 	int count;
  
- 		while ((iocb = lpfc_sli_next_iocb_slot(phba, pring)) &&
- 		       (nextiocb = lpfc_sli_ringtx_get(phba, pring)))
-@@ -489,32 +489,7 @@ lpfc_sli_resume_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
- 	return;
- }
+ 	cmd->use_sg = rq->nr_phys_segments;
+-	cmd->request_buffer = scsi_alloc_sgtable(cmd, gfp_mask);
+-	if (!cmd->request_buffer)
++	if (scsi_alloc_sgtable(cmd, gfp_mask))
+ 		return -ENOMEM;
  
--/* lpfc_sli_turn_on_ring is only called by lpfc_sli_handle_mb_event below */
--static void
--lpfc_sli_turn_on_ring(struct lpfc_hba *phba, int ringno)
--{
--	struct lpfc_pgp *pgp = (phba->sli_rev == 3) ?
--		&phba->slim2p->mbx.us.s3_pgp.port[ringno] :
--		&phba->slim2p->mbx.us.s2.port[ringno];
--	unsigned long iflags;
--
--	/* If the ring is active, flag it */
--	spin_lock_irqsave(&phba->hbalock, iflags);
--	if (phba->sli.ring[ringno].cmdringaddr) {
--		if (phba->sli.ring[ringno].flag & LPFC_STOP_IOCB_MBX) {
--			phba->sli.ring[ringno].flag &= ~LPFC_STOP_IOCB_MBX;
--			/*
--			 * Force update of the local copy of cmdGetInx
--			 */
--			phba->sli.ring[ringno].local_getidx
--				= le32_to_cpu(pgp->cmdGetInx);
--			lpfc_sli_resume_iocb(phba, &phba->sli.ring[ringno]);
--		}
+ 	cmd->request_bufflen = rq->data_len;
+ 
+-	dprintk("cmd %p cnt %d %lu\n", cmd, cmd->use_sg, rq_data_dir(rq));
+-	count = blk_rq_map_sg(rq->q, rq, cmd->request_buffer);
+-	if (likely(count <= cmd->use_sg)) {
+-		cmd->use_sg = count;
+-		return 0;
 -	}
--	spin_unlock_irqrestore(&phba->hbalock, iflags);
--}
 -
--struct lpfc_hbq_entry *
-+static struct lpfc_hbq_entry *
- lpfc_sli_next_hbq_slot(struct lpfc_hba *phba, uint32_t hbqno)
- {
- 	struct hbq_s *hbqp = &phba->hbqs[hbqno];
-@@ -565,6 +540,7 @@ lpfc_sli_hbqbuf_free_all(struct lpfc_hba *phba)
- 			list_del(&hbq_buf->dbuf.list);
- 			(phba->hbqs[i].hbq_free_buffer)(phba, hbq_buf);
- 		}
-+		phba->hbqs[i].buffer_count = 0;
- 	}
+-	eprintk("cmd %p cnt %d\n", cmd, cmd->use_sg);
+-	scsi_free_sgtable(cmd);
+-	return -EINVAL;
++	dprintk("cmd %p cnt %d %lu\n", cmd, scsi_sg_count(cmd),
++		rq_data_dir(rq));
++	count = blk_rq_map_sg(rq->q, rq, scsi_sglist(cmd));
++	BUG_ON(count > cmd->use_sg);
++	cmd->use_sg = count;
++	return 0;
  }
  
-@@ -633,8 +609,8 @@ lpfc_sli_hbqbuf_fill_hbqs(struct lpfc_hba *phba, uint32_t hbqno, uint32_t count)
- 		return 0;
- 	}
+ /* TODO: test this crap and replace bio_map_user with new interface maybe */
+@@ -496,8 +491,8 @@ int scsi_tgt_kspace_exec(int host_no, u64 itn_id, int result, u64 tag,
+ 	}
+ 	cmd = rq->special;
+ 
+-	dprintk("cmd %p scb %x result %d len %d bufflen %u %lu %x\n",
+-		cmd, cmd->cmnd[0], result, len, cmd->request_bufflen,
++	dprintk("cmd %p scb %x result %d len %d bufflen %u %u %x\n",
++		cmd, cmd->cmnd[0], result, len, scsi_bufflen(cmd),
+ 		rq_data_dir(rq), cmd->cmnd[0]);
+ 
+ 	if (result == TASK_ABORTED) {
+@@ -617,7 +612,7 @@ int scsi_tgt_kspace_it_nexus_rsp(int host_no, u64 itn_id, int result)
+ 	struct Scsi_Host *shost;
+ 	int err = -EINVAL;
  
--	start = lpfc_hbq_defs[hbqno]->buffer_count;
--	end = count + lpfc_hbq_defs[hbqno]->buffer_count;
-+	start = phba->hbqs[hbqno].buffer_count;
-+	end = count + start;
- 	if (end > lpfc_hbq_defs[hbqno]->entry_count) {
- 		end = lpfc_hbq_defs[hbqno]->entry_count;
- 	}
-@@ -646,7 +622,7 @@ lpfc_sli_hbqbuf_fill_hbqs(struct lpfc_hba *phba, uint32_t hbqno, uint32_t count)
- 			return 1;
- 		hbq_buffer->tag = (i | (hbqno << 16));
- 		if (lpfc_sli_hbq_to_firmware(phba, hbqno, hbq_buffer))
--			lpfc_hbq_defs[hbqno]->buffer_count++;
-+			phba->hbqs[hbqno].buffer_count++;
- 		else
- 			(phba->hbqs[hbqno].hbq_free_buffer)(phba, hbq_buffer);
- 	}
-@@ -660,14 +636,14 @@ lpfc_sli_hbqbuf_add_hbqs(struct lpfc_hba *phba, uint32_t qno)
- 					 lpfc_hbq_defs[qno]->add_count));
- }
+-	dprintk("%d %d %llx\n", host_no, result, (unsigned long long) mid);
++	dprintk("%d %d%llx\n", host_no, result, (unsigned long long)itn_id);
  
--int
-+static int
- lpfc_sli_hbqbuf_init_hbqs(struct lpfc_hba *phba, uint32_t qno)
- {
- 	return(lpfc_sli_hbqbuf_fill_hbqs(phba, qno,
- 					 lpfc_hbq_defs[qno]->init_count));
- }
+ 	shost = scsi_host_lookup(host_no);
+ 	if (IS_ERR(shost)) {
+diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c
+index 7a7cfe5..b1119da 100644
+--- a/drivers/scsi/scsi_transport_fc.c
++++ b/drivers/scsi/scsi_transport_fc.c
+@@ -481,9 +481,9 @@ MODULE_PARM_DESC(dev_loss_tmo,
+ 		 " exceeded, the scsi target is removed. Value should be"
+ 		 " between 1 and SCSI_DEVICE_BLOCK_MAX_TIMEOUT.");
  
--struct hbq_dmabuf *
-+static struct hbq_dmabuf *
- lpfc_sli_hbqbuf_find(struct lpfc_hba *phba, uint32_t tag)
- {
- 	struct lpfc_dmabuf *d_buf;
-@@ -686,7 +662,7 @@ lpfc_sli_hbqbuf_find(struct lpfc_hba *phba, uint32_t tag)
- 	}
- 	lpfc_printf_log(phba, KERN_ERR, LOG_SLI | LOG_VPORT,
- 			"1803 Bad hbq tag. Data: x%x x%x\n",
--			tag, lpfc_hbq_defs[tag >> 16]->buffer_count);
-+			tag, phba->hbqs[tag >> 16].buffer_count);
- 	return NULL;
- }
+-/**
++/*
+  * Netlink Infrastructure
+- **/
++ */
  
-@@ -712,6 +688,7 @@ lpfc_sli_chk_mbx_command(uint8_t mbxCommand)
- 	case MBX_LOAD_SM:
- 	case MBX_READ_NV:
- 	case MBX_WRITE_NV:
-+	case MBX_WRITE_VPARMS:
- 	case MBX_RUN_BIU_DIAG:
- 	case MBX_INIT_LINK:
- 	case MBX_DOWN_LINK:
-@@ -739,7 +716,7 @@ lpfc_sli_chk_mbx_command(uint8_t mbxCommand)
- 	case MBX_DEL_LD_ENTRY:
- 	case MBX_RUN_PROGRAM:
- 	case MBX_SET_MASK:
--	case MBX_SET_SLIM:
-+	case MBX_SET_VARIABLE:
- 	case MBX_UNREG_D_ID:
- 	case MBX_KILL_BOARD:
- 	case MBX_CONFIG_FARP:
-@@ -751,9 +728,10 @@ lpfc_sli_chk_mbx_command(uint8_t mbxCommand)
- 	case MBX_READ_RPI64:
- 	case MBX_REG_LOGIN64:
- 	case MBX_READ_LA64:
--	case MBX_FLASH_WR_ULA:
-+	case MBX_WRITE_WWN:
- 	case MBX_SET_DEBUG:
- 	case MBX_LOAD_EXP_ROM:
-+	case MBX_ASYNCEVT_ENABLE:
- 	case MBX_REG_VPI:
- 	case MBX_UNREG_VPI:
- 	case MBX_HEARTBEAT:
-@@ -953,6 +931,17 @@ lpfc_sli_replace_hbqbuff(struct lpfc_hba *phba, uint32_t tag)
- 	return &new_hbq_entry->dbuf;
- }
+ static atomic_t fc_event_seq;
  
-+static struct lpfc_dmabuf *
-+lpfc_sli_get_buff(struct lpfc_hba *phba,
-+			struct lpfc_sli_ring *pring,
-+			uint32_t tag)
-+{
-+	if (tag & QUE_BUFTAG_BIT)
-+		return lpfc_sli_ring_taggedbuf_get(phba, pring, tag);
-+	else
-+		return lpfc_sli_replace_hbqbuff(phba, tag);
-+}
-+
- static int
- lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
- 			    struct lpfc_iocbq *saveq)
-@@ -961,19 +950,112 @@ lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
- 	WORD5            * w5p;
- 	uint32_t           Rctl, Type;
- 	uint32_t           match, i;
-+	struct lpfc_iocbq *iocbq;
+@@ -491,10 +491,10 @@ static atomic_t fc_event_seq;
+  * fc_get_event_number - Obtain the next sequential FC event number
+  *
+  * Notes:
+- *   We could have inline'd this, but it would have required fc_event_seq to
++ *   We could have inlined this, but it would have required fc_event_seq to
+  *   be exposed. For now, live with the subroutine call.
+  *   Atomic used to avoid lock/unlock...
+- **/
++ */
+ u32
+ fc_get_event_number(void)
+ {
+@@ -505,7 +505,6 @@ EXPORT_SYMBOL(fc_get_event_number);
  
- 	match = 0;
- 	irsp = &(saveq->iocb);
--	if ((irsp->ulpCommand == CMD_RCV_ELS_REQ64_CX)
--	    || (irsp->ulpCommand == CMD_RCV_ELS_REQ_CX)
--	    || (irsp->ulpCommand == CMD_IOCB_RCV_ELS64_CX)
--	    || (irsp->ulpCommand == CMD_IOCB_RCV_CONT64_CX)) {
-+
-+	if (irsp->ulpStatus == IOSTAT_NEED_BUFFER)
-+		return 1;
-+	if (irsp->ulpCommand == CMD_ASYNC_STATUS) {
-+		if (pring->lpfc_sli_rcv_async_status)
-+			pring->lpfc_sli_rcv_async_status(phba, pring, saveq);
-+		else
-+			lpfc_printf_log(phba,
-+					KERN_WARNING,
-+					LOG_SLI,
-+					"0316 Ring %d handler: unexpected "
-+					"ASYNC_STATUS iocb received evt_code "
-+					"0x%x\n",
-+					pring->ringno,
-+					irsp->un.asyncstat.evt_code);
-+		return 1;
-+	}
-+
-+	if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) {
-+		if (irsp->ulpBdeCount != 0) {
-+			saveq->context2 = lpfc_sli_get_buff(phba, pring,
-+						irsp->un.ulpWord[3]);
-+			if (!saveq->context2)
-+				lpfc_printf_log(phba,
-+					KERN_ERR,
-+					LOG_SLI,
-+					"0341 Ring %d Cannot find buffer for "
-+					"an unsolicited iocb. tag 0x%x\n",
-+					pring->ringno,
-+					irsp->un.ulpWord[3]);
-+		}
-+		if (irsp->ulpBdeCount == 2) {
-+			saveq->context3 = lpfc_sli_get_buff(phba, pring,
-+						irsp->unsli3.sli3Words[7]);
-+			if (!saveq->context3)
-+				lpfc_printf_log(phba,
-+					KERN_ERR,
-+					LOG_SLI,
-+					"0342 Ring %d Cannot find buffer for an"
-+					" unsolicited iocb. tag 0x%x\n",
-+					pring->ringno,
-+					irsp->unsli3.sli3Words[7]);
-+		}
-+		list_for_each_entry(iocbq, &saveq->list, list) {
-+			irsp = &(iocbq->iocb);
-+			if (irsp->ulpBdeCount != 0) {
-+				iocbq->context2 = lpfc_sli_get_buff(phba, pring,
-+							irsp->un.ulpWord[3]);
-+				if (!iocbq->context2)
-+					lpfc_printf_log(phba,
-+						KERN_ERR,
-+						LOG_SLI,
-+						"0343 Ring %d Cannot find "
-+						"buffer for an unsolicited iocb"
-+						". tag 0x%x\n", pring->ringno,
-+						irsp->un.ulpWord[3]);
-+			}
-+			if (irsp->ulpBdeCount == 2) {
-+				iocbq->context3 = lpfc_sli_get_buff(phba, pring,
-+						irsp->unsli3.sli3Words[7]);
-+				if (!iocbq->context3)
-+					lpfc_printf_log(phba,
-+						KERN_ERR,
-+						LOG_SLI,
-+						"0344 Ring %d Cannot find "
-+						"buffer for an unsolicited "
-+						"iocb. tag 0x%x\n",
-+						pring->ringno,
-+						irsp->unsli3.sli3Words[7]);
-+			}
-+		}
-+	}
-+	if (irsp->ulpBdeCount != 0 &&
-+	    (irsp->ulpCommand == CMD_IOCB_RCV_CONT64_CX ||
-+	     irsp->ulpStatus == IOSTAT_INTERMED_RSP)) {
-+		int found = 0;
-+
-+		/* search continue save q for same XRI */
-+		list_for_each_entry(iocbq, &pring->iocb_continue_saveq, clist) {
-+			if (iocbq->iocb.ulpContext == saveq->iocb.ulpContext) {
-+				list_add_tail(&saveq->list, &iocbq->list);
-+				found = 1;
-+				break;
-+			}
-+		}
-+		if (!found)
-+			list_add_tail(&saveq->clist,
-+				      &pring->iocb_continue_saveq);
-+		if (saveq->iocb.ulpStatus != IOSTAT_INTERMED_RSP) {
-+			list_del_init(&iocbq->clist);
-+			saveq = iocbq;
-+			irsp = &(saveq->iocb);
-+		} else
-+			return 0;
-+	}
-+	if ((irsp->ulpCommand == CMD_RCV_ELS_REQ64_CX) ||
-+	    (irsp->ulpCommand == CMD_RCV_ELS_REQ_CX) ||
-+	    (irsp->ulpCommand == CMD_IOCB_RCV_ELS64_CX)) {
- 		Rctl = FC_ELS_REQ;
- 		Type = FC_ELS_DATA;
- 	} else {
--		w5p =
--		    (WORD5 *) & (saveq->iocb.un.
--				 ulpWord[5]);
-+		w5p = (WORD5 *)&(saveq->iocb.un.ulpWord[5]);
- 		Rctl = w5p->hcsw.Rctl;
- 		Type = w5p->hcsw.Type;
+ /**
+  * fc_host_post_event - called to post an even on an fc_host.
+- *
+  * @shost:		host the event occurred on
+  * @event_number:	fc event number obtained from get_fc_event_number()
+  * @event_code:		fc_host event being posted
+@@ -513,7 +512,7 @@ EXPORT_SYMBOL(fc_get_event_number);
+  *
+  * Notes:
+  *	This routine assumes no locks are held on entry.
+- **/
++ */
+ void
+ fc_host_post_event(struct Scsi_Host *shost, u32 event_number,
+ 		enum fc_host_event_code event_code, u32 event_data)
+@@ -579,17 +578,16 @@ EXPORT_SYMBOL(fc_host_post_event);
  
-@@ -988,15 +1070,6 @@ lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
- 		}
- 	}
  
--	if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) {
--		if (irsp->ulpBdeCount != 0)
--			saveq->context2 = lpfc_sli_replace_hbqbuff(phba,
--						irsp->un.ulpWord[3]);
--		if (irsp->ulpBdeCount == 2)
--			saveq->context3 = lpfc_sli_replace_hbqbuff(phba,
--						irsp->unsli3.sli3Words[7]);
--	}
--
- 	/* unSolicited Responses */
- 	if (pring->prt[0].profile) {
- 		if (pring->prt[0].lpfc_sli_rcv_unsol_event)
-@@ -1006,12 +1079,9 @@ lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
- 	} else {
- 		/* We must search, based on rctl / type
- 		   for the right routine */
--		for (i = 0; i < pring->num_mask;
--		     i++) {
--			if ((pring->prt[i].rctl ==
--			     Rctl)
--			    && (pring->prt[i].
--				type == Type)) {
-+		for (i = 0; i < pring->num_mask; i++) {
-+			if ((pring->prt[i].rctl == Rctl)
-+			    && (pring->prt[i].type == Type)) {
- 				if (pring->prt[i].lpfc_sli_rcv_unsol_event)
- 					(pring->prt[i].lpfc_sli_rcv_unsol_event)
- 							(phba, pring, saveq);
-@@ -1084,6 +1154,12 @@ lpfc_sli_process_sol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
- 						IOSTAT_LOCAL_REJECT;
- 					saveq->iocb.un.ulpWord[4] =
- 						IOERR_SLI_ABORTED;
-+
-+					/* Firmware could still be in progress
-+					 * of DMAing payload, so don't free data
-+					 * buffer till after a hbeat.
-+					 */
-+					saveq->iocb_flag |= LPFC_DELAY_MEM_FREE;
- 				}
- 			}
- 			(cmdiocbp->iocb_cmpl) (phba, cmdiocbp, saveq);
-@@ -1572,12 +1648,7 @@ lpfc_sli_handle_slow_ring_event(struct lpfc_hba *phba,
+ /**
+- * fc_host_post_vendor_event - called to post a vendor unique event on
+- *                             a fc_host
+- *
++ * fc_host_post_vendor_event - called to post a vendor unique event on an fc_host
+  * @shost:		host the event occurred on
+  * @event_number:	fc event number obtained from get_fc_event_number()
+  * @data_len:		amount, in bytes, of vendor unique data
+  * @data_buf:		pointer to vendor unique data
++ * @vendor_id:          Vendor id
+  *
+  * Notes:
+  *	This routine assumes no locks are held on entry.
+- **/
++ */
+ void
+ fc_host_post_vendor_event(struct Scsi_Host *shost, u32 event_number,
+ 		u32 data_len, char * data_buf, u64 vendor_id)
+@@ -1900,7 +1898,6 @@ static int fc_vport_match(struct attribute_container *cont,
  
- 		writel(pring->rspidx, &phba->host_gp[pring->ringno].rspGetInx);
+ /**
+  * fc_timed_out - FC Transport I/O timeout intercept handler
+- *
+  * @scmd:	The SCSI command which timed out
+  *
+  * This routine protects against error handlers getting invoked while a
+@@ -1920,7 +1917,7 @@ static int fc_vport_match(struct attribute_container *cont,
+  *
+  * Notes:
+  *	This routine assumes no locks are held on entry.
+- **/
++ */
+ static enum scsi_eh_timer_return
+ fc_timed_out(struct scsi_cmnd *scmd)
+ {
+@@ -2133,7 +2130,7 @@ EXPORT_SYMBOL(fc_release_transport);
+  * 	1 - work queued for execution
+  *	0 - work is already queued
+  *	-EINVAL - work queue doesn't exist
+- **/
++ */
+ static int
+ fc_queue_work(struct Scsi_Host *shost, struct work_struct *work)
+ {
+@@ -2152,7 +2149,7 @@ fc_queue_work(struct Scsi_Host *shost, struct work_struct *work)
+ /**
+  * fc_flush_work - Flush a fc_host's workqueue.
+  * @shost:	Pointer to Scsi_Host bound to fc_host.
+- **/
++ */
+ static void
+ fc_flush_work(struct Scsi_Host *shost)
+ {
+@@ -2175,7 +2172,7 @@ fc_flush_work(struct Scsi_Host *shost)
+  *
+  * Return value:
+  * 	1 on success / 0 already queued / < 0 for error
+- **/
++ */
+ static int
+ fc_queue_devloss_work(struct Scsi_Host *shost, struct delayed_work *work,
+ 				unsigned long delay)
+@@ -2195,7 +2192,7 @@ fc_queue_devloss_work(struct Scsi_Host *shost, struct delayed_work *work,
+ /**
+  * fc_flush_devloss - Flush a fc_host's devloss workqueue.
+  * @shost:	Pointer to Scsi_Host bound to fc_host.
+- **/
++ */
+ static void
+ fc_flush_devloss(struct Scsi_Host *shost)
+ {
+@@ -2212,21 +2209,20 @@ fc_flush_devloss(struct Scsi_Host *shost)
  
--		if (list_empty(&(pring->iocb_continueq))) {
--			list_add(&rspiocbp->list, &(pring->iocb_continueq));
--		} else {
--			list_add_tail(&rspiocbp->list,
--				      &(pring->iocb_continueq));
--		}
-+		list_add_tail(&rspiocbp->list, &(pring->iocb_continueq));
  
- 		pring->iocb_continueq_cnt++;
- 		if (irsp->ulpLe) {
-@@ -1642,17 +1713,17 @@ lpfc_sli_handle_slow_ring_event(struct lpfc_hba *phba,
- 			iocb_cmd_type = irsp->ulpCommand & CMD_IOCB_MASK;
- 			type = lpfc_sli_iocb_cmd_type(iocb_cmd_type);
- 			if (type == LPFC_SOL_IOCB) {
--				spin_unlock_irqrestore(&phba->hbalock,
--						       iflag);
-+				spin_unlock_irqrestore(&phba->hbalock, iflag);
- 				rc = lpfc_sli_process_sol_iocb(phba, pring,
- 							       saveq);
- 				spin_lock_irqsave(&phba->hbalock, iflag);
- 			} else if (type == LPFC_UNSOL_IOCB) {
--				spin_unlock_irqrestore(&phba->hbalock,
--						       iflag);
-+				spin_unlock_irqrestore(&phba->hbalock, iflag);
- 				rc = lpfc_sli_process_unsol_iocb(phba, pring,
- 								 saveq);
- 				spin_lock_irqsave(&phba->hbalock, iflag);
-+				if (!rc)
-+					free_saveq = 0;
- 			} else if (type == LPFC_ABORT_IOCB) {
- 				if ((irsp->ulpCommand != CMD_XRI_ABORTED_CX) &&
- 				    ((cmdiocbp =
-@@ -1921,8 +1992,8 @@ lpfc_sli_brdkill(struct lpfc_hba *phba)
- 			"0329 Kill HBA Data: x%x x%x\n",
- 			phba->pport->port_state, psli->sli_flag);
+ /**
+- * fc_remove_host - called to terminate any fc_transport-related elements
+- *                  for a scsi host.
+- * @rport:	remote port to be unblocked.
++ * fc_remove_host - called to terminate any fc_transport-related elements for a scsi host.
++ * @shost:	Which &Scsi_Host
+  *
+  * This routine is expected to be called immediately preceeding the
+  * a driver's call to scsi_remove_host().
+  *
+  * WARNING: A driver utilizing the fc_transport, which fails to call
+- *   this routine prior to scsi_remote_host(), will leave dangling
++ *   this routine prior to scsi_remove_host(), will leave dangling
+  *   objects in /sys/class/fc_remote_ports. Access to any of these
+  *   objects can result in a system crash !!!
+  *
+  * Notes:
+  *	This routine assumes no locks are held on entry.
+- **/
++ */
+ void
+ fc_remove_host(struct Scsi_Host *shost)
+ {
+@@ -2281,10 +2277,10 @@ EXPORT_SYMBOL(fc_remove_host);
  
--	if ((pmb = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool,
--						  GFP_KERNEL)) == 0)
-+	pmb = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
-+	if (!pmb)
- 		return 1;
+ /**
+  * fc_starget_delete - called to delete the scsi decendents of an rport
+- *                  (target and all sdevs)
+- *
+  * @work:	remote port to be operated on.
+- **/
++ *
++ * Deletes target and all sdevs.
++ */
+ static void
+ fc_starget_delete(struct work_struct *work)
+ {
+@@ -2303,9 +2299,8 @@ fc_starget_delete(struct work_struct *work)
  
- 	/* Disable the error attention */
-@@ -2113,7 +2184,10 @@ lpfc_sli_chipset_init(struct lpfc_hba *phba)
- 			   <status> */
- 			lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- 					"0436 Adapter failed to init, "
--					"timeout, status reg x%x\n", status);
-+					"timeout, status reg x%x, "
-+					"FW Data: A8 x%x AC x%x\n", status,
-+					readl(phba->MBslimaddr + 0xa8),
-+					readl(phba->MBslimaddr + 0xac));
- 			phba->link_state = LPFC_HBA_ERROR;
- 			return -ETIMEDOUT;
- 		}
-@@ -2125,7 +2199,10 @@ lpfc_sli_chipset_init(struct lpfc_hba *phba)
- 			   <status> */
- 			lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- 					"0437 Adapter failed to init, "
--					"chipset, status reg x%x\n", status);
-+					"chipset, status reg x%x, "
-+					"FW Data: A8 x%x AC x%x\n", status,
-+					readl(phba->MBslimaddr + 0xa8),
-+					readl(phba->MBslimaddr + 0xac));
- 			phba->link_state = LPFC_HBA_ERROR;
- 			return -EIO;
- 		}
-@@ -2153,7 +2230,10 @@ lpfc_sli_chipset_init(struct lpfc_hba *phba)
- 		/* Adapter failed to init, chipset, status reg <status> */
- 		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- 				"0438 Adapter failed to init, chipset, "
--				"status reg x%x\n", status);
-+				"status reg x%x, "
-+				"FW Data: A8 x%x AC x%x\n", status,
-+				readl(phba->MBslimaddr + 0xa8),
-+				readl(phba->MBslimaddr + 0xac));
- 		phba->link_state = LPFC_HBA_ERROR;
- 		return -EIO;
- 	}
-@@ -2485,11 +2565,16 @@ lpfc_mbox_timeout_handler(struct lpfc_hba *phba)
- 	lpfc_sli_abort_iocb_ring(phba, pring);
+ /**
+  * fc_rport_final_delete - finish rport termination and delete it.
+- *
+  * @work:	remote port to be deleted.
+- **/
++ */
+ static void
+ fc_rport_final_delete(struct work_struct *work)
+ {
+@@ -2375,7 +2370,7 @@ fc_rport_final_delete(struct work_struct *work)
+  *
+  * Notes:
+  *	This routine assumes no locks are held on entry.
+- **/
++ */
+ static struct fc_rport *
+ fc_rport_create(struct Scsi_Host *shost, int channel,
+ 	struct fc_rport_identifiers  *ids)
+@@ -2462,8 +2457,7 @@ delete_rport:
+ }
  
- 	lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
--			"0316 Resetting board due to mailbox timeout\n");
-+			"0345 Resetting board due to mailbox timeout\n");
- 	/*
- 	 * lpfc_offline calls lpfc_sli_hba_down which will clean up
- 	 * on oustanding mailbox commands.
- 	 */
-+	/* If resets are disabled then set error state and return. */
-+	if (!phba->cfg_enable_hba_reset) {
-+		phba->link_state = LPFC_HBA_ERROR;
-+		return;
-+	}
- 	lpfc_offline_prep(phba);
- 	lpfc_offline(phba);
- 	lpfc_sli_brdrestart(phba);
-@@ -2507,6 +2592,7 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag)
- 	uint32_t status, evtctr;
- 	uint32_t ha_copy;
- 	int i;
-+	unsigned long timeout;
- 	unsigned long drvr_flag = 0;
- 	volatile uint32_t word0, ldata;
- 	void __iomem *to_slim;
-@@ -2519,7 +2605,7 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag)
- 					"1806 Mbox x%x failed. No vport\n",
- 					pmbox->mb.mbxCommand);
- 			dump_stack();
--			return MBXERR_ERROR;
-+			return MBX_NOT_FINISHED;
- 		}
- 	}
+ /**
+- * fc_remote_port_add - notifies the fc transport of the existence
+- *		of a remote FC port.
++ * fc_remote_port_add - notify fc transport of the existence of a remote FC port.
+  * @shost:	scsi host the remote port is connected to.
+  * @channel:	Channel on shost port connected to.
+  * @ids:	The world wide names, fc address, and FC4 port
+@@ -2499,7 +2493,7 @@ delete_rport:
+  *
+  * Notes:
+  *	This routine assumes no locks are held on entry.
+- **/
++ */
+ struct fc_rport *
+ fc_remote_port_add(struct Scsi_Host *shost, int channel,
+ 	struct fc_rport_identifiers  *ids)
+@@ -2683,19 +2677,18 @@ EXPORT_SYMBOL(fc_remote_port_add);
  
-@@ -2571,21 +2657,6 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag)
- 			return MBX_NOT_FINISHED;
- 		}
  
--		/* Handle STOP IOCB processing flag. This is only meaningful
--		 * if we are not polling for mbox completion.
--		 */
--		if (flag & MBX_STOP_IOCB) {
--			flag &= ~MBX_STOP_IOCB;
--			/* Now flag each ring */
--			for (i = 0; i < psli->num_rings; i++) {
--				/* If the ring is active, flag it */
--				if (psli->ring[i].cmdringaddr) {
--					psli->ring[i].flag |=
--					    LPFC_STOP_IOCB_MBX;
--				}
--			}
--		}
--
- 		/* Another mailbox command is still being processed, queue this
- 		 * command to be processed later.
- 		 */
-@@ -2620,23 +2691,6 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag)
- 		return MBX_BUSY;
- 	}
+ /**
+- * fc_remote_port_delete - notifies the fc transport that a remote
+- *		port is no longer in existence.
++ * fc_remote_port_delete - notifies the fc transport that a remote port is no longer in existence.
+  * @rport:	The remote port that no longer exists
+  *
+  * The LLDD calls this routine to notify the transport that a remote
+  * port is no longer part of the topology. Note: Although a port
+  * may no longer be part of the topology, it may persist in the remote
+  * ports displayed by the fc_host. We do this under 2 conditions:
+- * - If the port was a scsi target, we delay its deletion by "blocking" it.
++ * 1) If the port was a scsi target, we delay its deletion by "blocking" it.
+  *   This allows the port to temporarily disappear, then reappear without
+  *   disrupting the SCSI device tree attached to it. During the "blocked"
+  *   period the port will still exist.
+- * - If the port was a scsi target and disappears for longer than we
++ * 2) If the port was a scsi target and disappears for longer than we
+  *   expect, we'll delete the port and the tear down the SCSI device tree
+  *   attached to it. However, we want to semi-persist the target id assigned
+  *   to that port if it eventually does exist. The port structure will
+@@ -2709,7 +2702,8 @@ EXPORT_SYMBOL(fc_remote_port_add);
+  * temporary blocked state. From the LLDD's perspective, the rport no
+  * longer exists. From the SCSI midlayer's perspective, the SCSI target
+  * exists, but all sdevs on it are blocked from further I/O. The following
+- * is then expected:
++ * is then expected.
++ *
+  *   If the remote port does not return (signaled by a LLDD call to
+  *   fc_remote_port_add()) within the dev_loss_tmo timeout, then the
+  *   scsi target is removed - killing all outstanding i/o and removing the
+@@ -2731,7 +2725,7 @@ EXPORT_SYMBOL(fc_remote_port_add);
+  *
+  * Notes:
+  *	This routine assumes no locks are held on entry.
+- **/
++ */
+ void
+ fc_remote_port_delete(struct fc_rport  *rport)
+ {
+@@ -2792,12 +2786,12 @@ fc_remote_port_delete(struct fc_rport  *rport)
+ EXPORT_SYMBOL(fc_remote_port_delete);
  
--	/* Handle STOP IOCB processing flag. This is only meaningful
--	 * if we are not polling for mbox completion.
--	 */
--	if (flag & MBX_STOP_IOCB) {
--		flag &= ~MBX_STOP_IOCB;
--		if (flag == MBX_NOWAIT) {
--			/* Now flag each ring */
--			for (i = 0; i < psli->num_rings; i++) {
--				/* If the ring is active, flag it */
--				if (psli->ring[i].cmdringaddr) {
--					psli->ring[i].flag |=
--					    LPFC_STOP_IOCB_MBX;
--				}
--			}
--		}
--	}
--
- 	psli->sli_flag |= LPFC_SLI_MBOX_ACTIVE;
+ /**
+- * fc_remote_port_rolechg - notifies the fc transport that the roles
+- *		on a remote may have changed.
++ * fc_remote_port_rolechg - notifies the fc transport that the roles on a remote may have changed.
+  * @rport:	The remote port that changed.
++ * @roles:      New roles for this port.
+  *
+- * The LLDD calls this routine to notify the transport that the roles
+- * on a remote port may have changed. The largest effect of this is
++ * Description: The LLDD calls this routine to notify the transport that the
++ * roles on a remote port may have changed. The largest effect of this is
+  * if a port now becomes a FCP Target, it must be allocated a
+  * scsi target id.  If the port is no longer a FCP target, any
+  * scsi target id value assigned to it will persist in case the
+@@ -2810,7 +2804,7 @@ EXPORT_SYMBOL(fc_remote_port_delete);
+  *
+  * Notes:
+  *	This routine assumes no locks are held on entry.
+- **/
++ */
+ void
+ fc_remote_port_rolechg(struct fc_rport  *rport, u32 roles)
+ {
+@@ -2875,12 +2869,12 @@ fc_remote_port_rolechg(struct fc_rport  *rport, u32 roles)
+ EXPORT_SYMBOL(fc_remote_port_rolechg);
  
- 	/* If we are not polling, we MUST be in SLI2 mode */
-@@ -2714,18 +2768,24 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag)
- 	}
+ /**
+- * fc_timeout_deleted_rport - Timeout handler for a deleted remote port,
+- * 			which we blocked, and has now failed to return
+- * 			in the allotted time.
+- *
++ * fc_timeout_deleted_rport - Timeout handler for a deleted remote port.
+  * @work:	rport target that failed to reappear in the allotted time.
+- **/
++ *
++ * Description: An attempt to delete a remote port blocks, and if it fails
++ *              to return in the allotted time this gets called.
++ */
+ static void
+ fc_timeout_deleted_rport(struct work_struct *work)
+ {
+@@ -2984,14 +2978,12 @@ fc_timeout_deleted_rport(struct work_struct *work)
+ }
  
- 	wmb();
--	/* interrupt board to doit right away */
--	writel(CA_MBATT, phba->CAregaddr);
--	readl(phba->CAregaddr); /* flush */
+ /**
+- * fc_timeout_fail_rport_io - Timeout handler for a fast io failing on a
+- *                       disconnected SCSI target.
+- *
++ * fc_timeout_fail_rport_io - Timeout handler for a fast io failing on a disconnected SCSI target.
+  * @work:	rport to terminate io on.
+  *
+  * Notes: Only requests the failure of the io, not that all are flushed
+  *    prior to returning.
+- **/
++ */
+ static void
+ fc_timeout_fail_rport_io(struct work_struct *work)
+ {
+@@ -3008,9 +3000,8 @@ fc_timeout_fail_rport_io(struct work_struct *work)
  
- 	switch (flag) {
- 	case MBX_NOWAIT:
--		/* Don't wait for it to finish, just return */
-+		/* Set up reference to mailbox command */
- 		psli->mbox_active = pmbox;
-+		/* Interrupt board to do it */
-+		writel(CA_MBATT, phba->CAregaddr);
-+		readl(phba->CAregaddr); /* flush */
-+		/* Don't wait for it to finish, just return */
- 		break;
+ /**
+  * fc_scsi_scan_rport - called to perform a scsi scan on a remote port.
+- *
+  * @work:	remote port to be scanned.
+- **/
++ */
+ static void
+ fc_scsi_scan_rport(struct work_struct *work)
+ {
+@@ -3047,7 +3038,7 @@ fc_scsi_scan_rport(struct work_struct *work)
+  *
+  * Notes:
+  *	This routine assumes no locks are held on entry.
+- **/
++ */
+ static int
+ fc_vport_create(struct Scsi_Host *shost, int channel, struct device *pdev,
+ 	struct fc_vport_identifiers  *ids, struct fc_vport **ret_vport)
+@@ -3172,7 +3163,7 @@ delete_vport:
+  *
+  * Notes:
+  *	This routine assumes no locks are held on entry.
+- **/
++ */
+ int
+ fc_vport_terminate(struct fc_vport *vport)
+ {
+@@ -3232,9 +3223,8 @@ EXPORT_SYMBOL(fc_vport_terminate);
  
- 	case MBX_POLL:
-+		/* Set up null reference to mailbox command */
- 		psli->mbox_active = NULL;
-+		/* Interrupt board to do it */
-+		writel(CA_MBATT, phba->CAregaddr);
-+		readl(phba->CAregaddr); /* flush */
-+
- 		if (psli->sli_flag & LPFC_SLI2_ACTIVE) {
- 			/* First read mbox status word */
- 			word0 = *((volatile uint32_t *)&phba->slim2p->mbx);
-@@ -2737,15 +2797,15 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag)
+ /**
+  * fc_vport_sched_delete - workq-based delete request for a vport
+- *
+  * @work:	vport to be deleted.
+- **/
++ */
+ static void
+ fc_vport_sched_delete(struct work_struct *work)
+ {
+diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c
+index 5428d15..ef0e742 100644
+--- a/drivers/scsi/scsi_transport_iscsi.c
++++ b/drivers/scsi/scsi_transport_iscsi.c
+@@ -30,10 +30,10 @@
+ #include <scsi/scsi_transport_iscsi.h>
+ #include <scsi/iscsi_if.h>
  
- 		/* Read the HBA Host Attention Register */
- 		ha_copy = readl(phba->HAregaddr);
--
--		i = lpfc_mbox_tmo_val(phba, mb->mbxCommand);
--		i *= 1000; /* Convert to ms */
--
-+		timeout = msecs_to_jiffies(lpfc_mbox_tmo_val(phba,
-+							     mb->mbxCommand) *
-+					   1000) + jiffies;
-+		i = 0;
- 		/* Wait for command to complete */
- 		while (((word0 & OWN_CHIP) == OWN_CHIP) ||
- 		       (!(ha_copy & HA_MBATT) &&
- 			(phba->link_state > LPFC_WARM_START))) {
--			if (i-- <= 0) {
-+			if (time_after(jiffies, timeout)) {
- 				psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
- 				spin_unlock_irqrestore(&phba->hbalock,
- 						       drvr_flag);
-@@ -2758,12 +2818,12 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag)
- 			    && (evtctr != psli->slistat.mbox_event))
- 				break;
+-#define ISCSI_SESSION_ATTRS 15
++#define ISCSI_SESSION_ATTRS 18
+ #define ISCSI_CONN_ATTRS 11
+ #define ISCSI_HOST_ATTRS 4
+-#define ISCSI_TRANSPORT_VERSION "2.0-724"
++#define ISCSI_TRANSPORT_VERSION "2.0-867"
  
--			spin_unlock_irqrestore(&phba->hbalock,
--					       drvr_flag);
--
--			msleep(1);
--
--			spin_lock_irqsave(&phba->hbalock, drvr_flag);
-+			if (i++ > 10) {
-+				spin_unlock_irqrestore(&phba->hbalock,
-+						       drvr_flag);
-+				msleep(1);
-+				spin_lock_irqsave(&phba->hbalock, drvr_flag);
-+			}
+ struct iscsi_internal {
+ 	int daemon_pid;
+@@ -50,6 +50,7 @@ struct iscsi_internal {
+ };
+ 
+ static atomic_t iscsi_session_nr; /* sysfs session id for next new session */
++static struct workqueue_struct *iscsi_eh_timer_workq;
  
- 			if (psli->sli_flag & LPFC_SLI2_ACTIVE) {
- 				/* First copy command data */
-@@ -2848,7 +2908,7 @@ lpfc_sli_next_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
  /*
-  * Lockless version of lpfc_sli_issue_iocb.
-  */
--int
-+static int
- __lpfc_sli_issue_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
- 		    struct lpfc_iocbq *piocb, uint32_t flag)
+  * list of registered transports and lock that must
+@@ -115,6 +116,8 @@ static struct attribute_group iscsi_transport_group = {
+ 	.attrs = iscsi_transport_attrs,
+ };
+ 
++
++
+ static int iscsi_setup_host(struct transport_container *tc, struct device *dev,
+ 			    struct class_device *cdev)
  {
-@@ -2879,9 +2939,9 @@ __lpfc_sli_issue_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
+@@ -124,13 +127,30 @@ static int iscsi_setup_host(struct transport_container *tc, struct device *dev,
+ 	memset(ihost, 0, sizeof(*ihost));
+ 	INIT_LIST_HEAD(&ihost->sessions);
+ 	mutex_init(&ihost->mutex);
++
++	snprintf(ihost->unbind_workq_name, KOBJ_NAME_LEN, "iscsi_unbind_%d",
++		shost->host_no);
++	ihost->unbind_workq = create_singlethread_workqueue(
++						ihost->unbind_workq_name);
++	if (!ihost->unbind_workq)
++		return -ENOMEM;
++	return 0;
++}
++
++static int iscsi_remove_host(struct transport_container *tc, struct device *dev,
++			     struct class_device *cdev)
++{
++	struct Scsi_Host *shost = dev_to_shost(dev);
++	struct iscsi_host *ihost = shost->shost_data;
++
++	destroy_workqueue(ihost->unbind_workq);
+ 	return 0;
+ }
  
- 	/*
- 	 * Check to see if we are blocking IOCB processing because of a
--	 * outstanding mbox command.
-+	 * outstanding event.
- 	 */
--	if (unlikely(pring->flag & LPFC_STOP_IOCB_MBX))
-+	if (unlikely(pring->flag & LPFC_STOP_IOCB_EVENT))
- 		goto iocb_busy;
+ static DECLARE_TRANSPORT_CLASS(iscsi_host_class,
+ 			       "iscsi_host",
+ 			       iscsi_setup_host,
+-			       NULL,
++			       iscsi_remove_host,
+ 			       NULL);
  
- 	if (unlikely(phba->link_state == LPFC_LINK_DOWN)) {
-@@ -2993,6 +3053,61 @@ lpfc_extra_ring_setup( struct lpfc_hba *phba)
- 	return 0;
+ static DECLARE_TRANSPORT_CLASS(iscsi_session_class,
+@@ -252,7 +272,7 @@ static void session_recovery_timedout(struct work_struct *work)
+ void iscsi_unblock_session(struct iscsi_cls_session *session)
+ {
+ 	if (!cancel_delayed_work(&session->recovery_work))
+-		flush_scheduled_work();
++		flush_workqueue(iscsi_eh_timer_workq);
+ 	scsi_target_unblock(&session->dev);
+ }
+ EXPORT_SYMBOL_GPL(iscsi_unblock_session);
+@@ -260,11 +280,40 @@ EXPORT_SYMBOL_GPL(iscsi_unblock_session);
+ void iscsi_block_session(struct iscsi_cls_session *session)
+ {
+ 	scsi_target_block(&session->dev);
+-	schedule_delayed_work(&session->recovery_work,
+-			     session->recovery_tmo * HZ);
++	queue_delayed_work(iscsi_eh_timer_workq, &session->recovery_work,
++			   session->recovery_tmo * HZ);
  }
+ EXPORT_SYMBOL_GPL(iscsi_block_session);
  
-+static void
-+lpfc_sli_async_event_handler(struct lpfc_hba * phba,
-+	struct lpfc_sli_ring * pring, struct lpfc_iocbq * iocbq)
++static void __iscsi_unbind_session(struct work_struct *work)
 +{
-+	IOCB_t *icmd;
-+	uint16_t evt_code;
-+	uint16_t temp;
-+	struct temp_event temp_event_data;
-+	struct Scsi_Host *shost;
-+
-+	icmd = &iocbq->iocb;
-+	evt_code = icmd->un.asyncstat.evt_code;
-+	temp = icmd->ulpContext;
++	struct iscsi_cls_session *session =
++			container_of(work, struct iscsi_cls_session,
++				     unbind_work);
++	struct Scsi_Host *shost = iscsi_session_to_shost(session);
++	struct iscsi_host *ihost = shost->shost_data;
 +
-+	if ((evt_code != ASYNC_TEMP_WARN) &&
-+		(evt_code != ASYNC_TEMP_SAFE)) {
-+		lpfc_printf_log(phba,
-+			KERN_ERR,
-+			LOG_SLI,
-+			"0346 Ring %d handler: unexpected ASYNC_STATUS"
-+			" evt_code 0x%x\n",
-+			pring->ringno,
-+			icmd->un.asyncstat.evt_code);
++	/* Prevent new scans and make sure scanning is not in progress */
++	mutex_lock(&ihost->mutex);
++	if (list_empty(&session->host_list)) {
++		mutex_unlock(&ihost->mutex);
 +		return;
 +	}
-+	temp_event_data.data = (uint32_t)temp;
-+	temp_event_data.event_type = FC_REG_TEMPERATURE_EVENT;
-+	if (evt_code == ASYNC_TEMP_WARN) {
-+		temp_event_data.event_code = LPFC_THRESHOLD_TEMP;
-+		lpfc_printf_log(phba,
-+				KERN_ERR,
-+				LOG_TEMP,
-+				"0347 Adapter is very hot, please take "
-+				"corrective action. temperature : %d Celsius\n",
-+				temp);
-+	}
-+	if (evt_code == ASYNC_TEMP_SAFE) {
-+		temp_event_data.event_code = LPFC_NORMAL_TEMP;
-+		lpfc_printf_log(phba,
-+				KERN_ERR,
-+				LOG_TEMP,
-+				"0340 Adapter temperature is OK now. "
-+				"temperature : %d Celsius\n",
-+				temp);
-+	}
-+
-+	/* Send temperature change event to applications */
-+	shost = lpfc_shost_from_vport(phba->pport);
-+	fc_host_post_vendor_event(shost, fc_get_event_number(),
-+		sizeof(temp_event_data), (char *) &temp_event_data,
-+		SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_EMULEX);
++	list_del_init(&session->host_list);
++	mutex_unlock(&ihost->mutex);
 +
++	scsi_remove_target(&session->dev);
++	iscsi_session_event(session, ISCSI_KEVENT_UNBIND_SESSION);
 +}
 +
++static int iscsi_unbind_session(struct iscsi_cls_session *session)
++{
++	struct Scsi_Host *shost = iscsi_session_to_shost(session);
++	struct iscsi_host *ihost = shost->shost_data;
 +
- int
- lpfc_sli_setup(struct lpfc_hba *phba)
++	return queue_work(ihost->unbind_workq, &session->unbind_work);
++}
++
+ struct iscsi_cls_session *
+ iscsi_alloc_session(struct Scsi_Host *shost,
+ 		    struct iscsi_transport *transport)
+@@ -281,6 +330,7 @@ iscsi_alloc_session(struct Scsi_Host *shost,
+ 	INIT_DELAYED_WORK(&session->recovery_work, session_recovery_timedout);
+ 	INIT_LIST_HEAD(&session->host_list);
+ 	INIT_LIST_HEAD(&session->sess_list);
++	INIT_WORK(&session->unbind_work, __iscsi_unbind_session);
+ 
+ 	/* this is released in the dev's release function */
+ 	scsi_host_get(shost);
+@@ -297,6 +347,7 @@ int iscsi_add_session(struct iscsi_cls_session *session, unsigned int target_id)
  {
-@@ -3059,6 +3174,8 @@ lpfc_sli_setup(struct lpfc_hba *phba)
- 			pring->fast_iotag = 0;
- 			pring->iotag_ctr = 0;
- 			pring->iotag_max = 4096;
-+			pring->lpfc_sli_rcv_async_status =
-+				lpfc_sli_async_event_handler;
- 			pring->num_mask = 4;
- 			pring->prt[0].profile = 0;	/* Mask 0 */
- 			pring->prt[0].rctl = FC_ELS_REQ;
-@@ -3123,6 +3240,7 @@ lpfc_sli_queue_setup(struct lpfc_hba *phba)
- 		INIT_LIST_HEAD(&pring->txq);
- 		INIT_LIST_HEAD(&pring->txcmplq);
- 		INIT_LIST_HEAD(&pring->iocb_continueq);
-+		INIT_LIST_HEAD(&pring->iocb_continue_saveq);
- 		INIT_LIST_HEAD(&pring->postbufq);
- 	}
- 	spin_unlock_irq(&phba->hbalock);
-@@ -3193,6 +3311,7 @@ lpfc_sli_hba_down(struct lpfc_hba *phba)
- 	LIST_HEAD(completions);
- 	struct lpfc_sli *psli = &phba->sli;
- 	struct lpfc_sli_ring *pring;
-+	struct lpfc_dmabuf *buf_ptr;
- 	LPFC_MBOXQ_t *pmb;
- 	struct lpfc_iocbq *iocb;
- 	IOCB_t *cmd = NULL;
-@@ -3232,6 +3351,19 @@ lpfc_sli_hba_down(struct lpfc_hba *phba)
- 		}
+ 	struct Scsi_Host *shost = iscsi_session_to_shost(session);
+ 	struct iscsi_host *ihost;
++	unsigned long flags;
+ 	int err;
+ 
+ 	ihost = shost->shost_data;
+@@ -313,9 +364,15 @@ int iscsi_add_session(struct iscsi_cls_session *session, unsigned int target_id)
  	}
+ 	transport_register_device(&session->dev);
  
-+	spin_lock_irqsave(&phba->hbalock, flags);
-+	list_splice_init(&phba->elsbuf, &completions);
-+	phba->elsbuf_cnt = 0;
-+	phba->elsbuf_prev_cnt = 0;
-+	spin_unlock_irqrestore(&phba->hbalock, flags);
++	spin_lock_irqsave(&sesslock, flags);
++	list_add(&session->sess_list, &sesslist);
++	spin_unlock_irqrestore(&sesslock, flags);
 +
-+	while (!list_empty(&completions)) {
-+		list_remove_head(&completions, buf_ptr,
-+			struct lpfc_dmabuf, list);
-+		lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys);
-+		kfree(buf_ptr);
-+	}
+ 	mutex_lock(&ihost->mutex);
+ 	list_add(&session->host_list, &ihost->sessions);
+ 	mutex_unlock(&ihost->mutex);
 +
- 	/* Return any active mbox cmds */
- 	del_timer_sync(&psli->mbox_tmo);
- 	spin_lock_irqsave(&phba->hbalock, flags);
-@@ -3294,6 +3426,47 @@ lpfc_sli_ringpostbuf_put(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
++	iscsi_session_event(session, ISCSI_KEVENT_CREATE_SESSION);
  	return 0;
+ 
+ release_host:
+@@ -328,9 +385,10 @@ EXPORT_SYMBOL_GPL(iscsi_add_session);
+  * iscsi_create_session - create iscsi class session
+  * @shost: scsi host
+  * @transport: iscsi transport
++ * @target_id: which target
+  *
+  * This can be called from a LLD or iscsi_transport.
+- **/
++ */
+ struct iscsi_cls_session *
+ iscsi_create_session(struct Scsi_Host *shost,
+ 		     struct iscsi_transport *transport,
+@@ -350,19 +408,58 @@ iscsi_create_session(struct Scsi_Host *shost,
  }
+ EXPORT_SYMBOL_GPL(iscsi_create_session);
  
-+uint32_t
-+lpfc_sli_get_buffer_tag(struct lpfc_hba *phba)
++static void iscsi_conn_release(struct device *dev)
 +{
-+	spin_lock_irq(&phba->hbalock);
-+	phba->buffer_tag_count++;
-+	/*
-+	 * Always set the QUE_BUFTAG_BIT to distiguish between
-+	 * a tag assigned by HBQ.
-+	 */
-+	phba->buffer_tag_count |= QUE_BUFTAG_BIT;
-+	spin_unlock_irq(&phba->hbalock);
-+	return phba->buffer_tag_count;
++	struct iscsi_cls_conn *conn = iscsi_dev_to_conn(dev);
++	struct device *parent = conn->dev.parent;
++
++	kfree(conn);
++	put_device(parent);
 +}
 +
-+struct lpfc_dmabuf *
-+lpfc_sli_ring_taggedbuf_get(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
-+			uint32_t tag)
++static int iscsi_is_conn_dev(const struct device *dev)
 +{
-+	struct lpfc_dmabuf *mp, *next_mp;
-+	struct list_head *slp = &pring->postbufq;
-+
-+	/* Search postbufq, from the begining, looking for a match on tag */
-+	spin_lock_irq(&phba->hbalock);
-+	list_for_each_entry_safe(mp, next_mp, &pring->postbufq, list) {
-+		if (mp->buffer_tag == tag) {
-+			list_del_init(&mp->list);
-+			pring->postbufq_cnt--;
-+			spin_unlock_irq(&phba->hbalock);
-+			return mp;
-+		}
-+	}
-+
-+	spin_unlock_irq(&phba->hbalock);
-+	lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
-+			"0410 Cannot find virtual addr for buffer tag on "
-+			"ring %d Data x%lx x%p x%p x%x\n",
-+			pring->ringno, (unsigned long) tag,
-+			slp->next, slp->prev, pring->postbufq_cnt);
++	return dev->release == iscsi_conn_release;
++}
 +
-+	return NULL;
++static int iscsi_iter_destroy_conn_fn(struct device *dev, void *data)
++{
++	if (!iscsi_is_conn_dev(dev))
++		return 0;
++	return iscsi_destroy_conn(iscsi_dev_to_conn(dev));
 +}
- 
- struct lpfc_dmabuf *
- lpfc_sli_ringpostbuf_get(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
-@@ -3361,6 +3534,12 @@ lpfc_sli_abort_els_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
- 			pring->txcmplq_cnt--;
- 			spin_unlock_irq(&phba->hbalock);
- 
-+			/* Firmware could still be in progress of DMAing
-+			 * payload, so don't free data buffer till after
-+			 * a hbeat.
-+			 */
-+			abort_iocb->iocb_flag |= LPFC_DELAY_MEM_FREE;
 +
- 			abort_iocb->iocb_flag &= ~LPFC_DRIVER_ABORTED;
- 			abort_iocb->iocb.ulpStatus = IOSTAT_LOCAL_REJECT;
- 			abort_iocb->iocb.un.ulpWord[4] = IOERR_SLI_ABORTED;
-@@ -3699,7 +3878,7 @@ lpfc_sli_issue_mbox_wait(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq,
- 	unsigned long flag;
+ void iscsi_remove_session(struct iscsi_cls_session *session)
+ {
+ 	struct Scsi_Host *shost = iscsi_session_to_shost(session);
+ 	struct iscsi_host *ihost = shost->shost_data;
++	unsigned long flags;
++	int err;
  
- 	/* The caller must leave context1 empty. */
--	if (pmboxq->context1 != 0)
-+	if (pmboxq->context1)
- 		return MBX_NOT_FINISHED;
+-	if (!cancel_delayed_work(&session->recovery_work))
+-		flush_scheduled_work();
++	spin_lock_irqsave(&sesslock, flags);
++	list_del(&session->sess_list);
++	spin_unlock_irqrestore(&sesslock, flags);
  
- 	/* setup wake call as IOCB callback */
-@@ -3771,7 +3950,6 @@ lpfc_intr_handler(int irq, void *dev_id)
- 	uint32_t ha_copy;
- 	uint32_t work_ha_copy;
- 	unsigned long status;
--	int i;
- 	uint32_t control;
+-	mutex_lock(&ihost->mutex);
+-	list_del(&session->host_list);
+-	mutex_unlock(&ihost->mutex);
++	/*
++	 * If we are blocked let commands flow again. The lld or iscsi
++	 * layer should set up the queuecommand to fail commands.
++	 */
++	iscsi_unblock_session(session);
++	iscsi_unbind_session(session);
++	/*
++	 * If the session dropped while removing devices then we need to make
++	 * sure it is not blocked
++	 */
++	if (!cancel_delayed_work(&session->recovery_work))
++		flush_workqueue(iscsi_eh_timer_workq);
++	flush_workqueue(ihost->unbind_workq);
  
- 	MAILBOX_t *mbox, *pmbox;
-@@ -3888,7 +4066,6 @@ lpfc_intr_handler(int irq, void *dev_id)
- 		}
+-	scsi_remove_target(&session->dev);
++	/* hw iscsi may not have removed all connections from session */
++	err = device_for_each_child(&session->dev, NULL,
++				    iscsi_iter_destroy_conn_fn);
++	if (err)
++		dev_printk(KERN_ERR, &session->dev, "iscsi: Could not delete "
++			   "all connections for session. Error %d.\n", err);
  
- 		if (work_ha_copy & HA_ERATT) {
--			phba->link_state = LPFC_HBA_ERROR;
- 			/*
- 			 * There was a link/board error.  Read the
- 			 * status register to retrieve the error event
-@@ -3920,7 +4097,7 @@ lpfc_intr_handler(int irq, void *dev_id)
- 				 * Stray Mailbox Interrupt, mbxCommand <cmd>
- 				 * mbxStatus <status>
- 				 */
--				lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX |
-+				lpfc_printf_log(phba, KERN_ERR, LOG_MBOX |
- 						LOG_SLI,
- 						"(%d):0304 Stray Mailbox "
- 						"Interrupt mbxCommand x%x "
-@@ -3928,51 +4105,60 @@ lpfc_intr_handler(int irq, void *dev_id)
- 						(vport ? vport->vpi : 0),
- 						pmbox->mbxCommand,
- 						pmbox->mbxStatus);
--			}
--			phba->last_completion_time = jiffies;
--			del_timer_sync(&phba->sli.mbox_tmo);
+ 	transport_unregister_device(&session->dev);
+ 	device_del(&session->dev);
+@@ -371,9 +468,9 @@ EXPORT_SYMBOL_GPL(iscsi_remove_session);
+ 
+ void iscsi_free_session(struct iscsi_cls_session *session)
+ {
++	iscsi_session_event(session, ISCSI_KEVENT_DESTROY_SESSION);
+ 	put_device(&session->dev);
+ }
 -
--			phba->sli.mbox_active = NULL;
--			if (pmb->mbox_cmpl) {
--				lpfc_sli_pcimem_bcopy(mbox, pmbox,
--						      MAILBOX_CMD_SIZE);
--			}
--			if (pmb->mbox_flag & LPFC_MBX_IMED_UNREG) {
--				pmb->mbox_flag &= ~LPFC_MBX_IMED_UNREG;
-+				/* clear mailbox attention bit */
-+				work_ha_copy &= ~HA_MBATT;
-+			} else {
-+				phba->last_completion_time = jiffies;
-+				del_timer(&phba->sli.mbox_tmo);
+ EXPORT_SYMBOL_GPL(iscsi_free_session);
  
--				lpfc_debugfs_disc_trc(vport,
--					LPFC_DISC_TRC_MBOX_VPORT,
--					"MBOX dflt rpi: : status:x%x rpi:x%x",
--					(uint32_t)pmbox->mbxStatus,
--					pmbox->un.varWords[0], 0);
+ /**
+@@ -382,7 +479,7 @@ EXPORT_SYMBOL_GPL(iscsi_free_session);
+  *
+  * Can be called by a LLD or iscsi_transport. There must not be
+  * any running connections.
+- **/
++ */
+ int iscsi_destroy_session(struct iscsi_cls_session *session)
+ {
+ 	iscsi_remove_session(session);
+@@ -391,20 +488,6 @@ int iscsi_destroy_session(struct iscsi_cls_session *session)
+ }
+ EXPORT_SYMBOL_GPL(iscsi_destroy_session);
+ 
+-static void iscsi_conn_release(struct device *dev)
+-{
+-	struct iscsi_cls_conn *conn = iscsi_dev_to_conn(dev);
+-	struct device *parent = conn->dev.parent;
 -
--				if ( !pmbox->mbxStatus) {
--					mp = (struct lpfc_dmabuf *)
--						(pmb->context1);
--					ndlp = (struct lpfc_nodelist *)
--						pmb->context2;
+-	kfree(conn);
+-	put_device(parent);
+-}
 -
--					/* Reg_LOGIN of dflt RPI was successful.
--					 * new lets get rid of the RPI using the
--					 * same mbox buffer.
--					 */
--					lpfc_unreg_login(phba, vport->vpi,
--						pmbox->un.varWords[0], pmb);
--					pmb->mbox_cmpl = lpfc_mbx_cmpl_dflt_rpi;
--					pmb->context1 = mp;
--					pmb->context2 = ndlp;
--					pmb->vport = vport;
--					spin_lock(&phba->hbalock);
--					phba->sli.sli_flag &=
--						~LPFC_SLI_MBOX_ACTIVE;
--					spin_unlock(&phba->hbalock);
--					goto send_current_mbox;
-+				phba->sli.mbox_active = NULL;
-+				if (pmb->mbox_cmpl) {
-+					lpfc_sli_pcimem_bcopy(mbox, pmbox,
-+							MAILBOX_CMD_SIZE);
-+				}
-+				if (pmb->mbox_flag & LPFC_MBX_IMED_UNREG) {
-+					pmb->mbox_flag &= ~LPFC_MBX_IMED_UNREG;
-+
-+					lpfc_debugfs_disc_trc(vport,
-+						LPFC_DISC_TRC_MBOX_VPORT,
-+						"MBOX dflt rpi: : "
-+						"status:x%x rpi:x%x",
-+						(uint32_t)pmbox->mbxStatus,
-+						pmbox->un.varWords[0], 0);
-+
-+					if (!pmbox->mbxStatus) {
-+						mp = (struct lpfc_dmabuf *)
-+							(pmb->context1);
-+						ndlp = (struct lpfc_nodelist *)
-+							pmb->context2;
-+
-+						/* Reg_LOGIN of dflt RPI was
-+						 * successful. new lets get
-+						 * rid of the RPI using the
-+						 * same mbox buffer.
-+						 */
-+						lpfc_unreg_login(phba,
-+							vport->vpi,
-+							pmbox->un.varWords[0],
-+							pmb);
-+						pmb->mbox_cmpl =
-+							lpfc_mbx_cmpl_dflt_rpi;
-+						pmb->context1 = mp;
-+						pmb->context2 = ndlp;
-+						pmb->vport = vport;
-+						spin_lock(&phba->hbalock);
-+						phba->sli.sli_flag &=
-+							~LPFC_SLI_MBOX_ACTIVE;
-+						spin_unlock(&phba->hbalock);
-+						goto send_current_mbox;
-+					}
- 				}
-+				spin_lock(&phba->pport->work_port_lock);
-+				phba->pport->work_port_events &=
-+					~WORKER_MBOX_TMO;
-+				spin_unlock(&phba->pport->work_port_lock);
-+				lpfc_mbox_cmpl_put(phba, pmb);
- 			}
--			spin_lock(&phba->pport->work_port_lock);
--			phba->pport->work_port_events &= ~WORKER_MBOX_TMO;
--			spin_unlock(&phba->pport->work_port_lock);
--			lpfc_mbox_cmpl_put(phba, pmb);
- 		}
- 		if ((work_ha_copy & HA_MBATT) &&
- 		    (phba->sli.mbox_active == NULL)) {
-@@ -3990,10 +4176,6 @@ send_current_mbox:
- 					lpfc_mbox_cmpl_put(phba, pmb);
- 					goto send_next_mbox;
- 				}
--			} else {
--				/* Turn on IOCB processing */
--				for (i = 0; i < phba->sli.num_rings; i++)
--					lpfc_sli_turn_on_ring(phba, i);
- 			}
- 
- 		}
-diff --git a/drivers/scsi/lpfc/lpfc_sli.h b/drivers/scsi/lpfc/lpfc_sli.h
-index 51b2b6b..7249fd2 100644
---- a/drivers/scsi/lpfc/lpfc_sli.h
-+++ b/drivers/scsi/lpfc/lpfc_sli.h
-@@ -33,6 +33,7 @@ typedef enum _lpfc_ctx_cmd {
- struct lpfc_iocbq {
- 	/* lpfc_iocbqs are used in double linked lists */
- 	struct list_head list;
-+	struct list_head clist;
- 	uint16_t iotag;         /* pre-assigned IO tag */
- 	uint16_t rsvd1;
+-static int iscsi_is_conn_dev(const struct device *dev)
+-{
+-	return dev->release == iscsi_conn_release;
+-}
+-
+ /**
+  * iscsi_create_conn - create iscsi class connection
+  * @session: iscsi cls session
+@@ -418,12 +501,13 @@ static int iscsi_is_conn_dev(const struct device *dev)
+  * for software iscsi we could be trying to preallocate a connection struct
+  * in which case there could be two connection structs and cid would be
+  * non-zero.
+- **/
++ */
+ struct iscsi_cls_conn *
+ iscsi_create_conn(struct iscsi_cls_session *session, uint32_t cid)
+ {
+ 	struct iscsi_transport *transport = session->transport;
+ 	struct iscsi_cls_conn *conn;
++	unsigned long flags;
+ 	int err;
  
-@@ -44,6 +45,7 @@ struct lpfc_iocbq {
- #define LPFC_IO_FCP		4	/* FCP command -- iocbq in scsi_buf */
- #define LPFC_DRIVER_ABORTED	8	/* driver aborted this request */
- #define LPFC_IO_FABRIC		0x10	/* Iocb send using fabric scheduler */
-+#define LPFC_DELAY_MEM_FREE	0x20    /* Defer free'ing of FC data */
+ 	conn = kzalloc(sizeof(*conn) + transport->conndata_size, GFP_KERNEL);
+@@ -452,6 +536,11 @@ iscsi_create_conn(struct iscsi_cls_session *session, uint32_t cid)
+ 		goto release_parent_ref;
+ 	}
+ 	transport_register_device(&conn->dev);
++
++	spin_lock_irqsave(&connlock, flags);
++	list_add(&conn->conn_list, &connlist);
++	conn->active = 1;
++	spin_unlock_irqrestore(&connlock, flags);
+ 	return conn;
  
- 	uint8_t abort_count;
- 	uint8_t rsvd2;
-@@ -92,8 +94,6 @@ typedef struct lpfcMboxq {
- #define MBX_POLL        1	/* poll mailbox till command done, then
- 				   return */
- #define MBX_NOWAIT      2	/* issue command then return immediately */
--#define MBX_STOP_IOCB   4	/* Stop iocb processing till mbox cmds
--				   complete */
+ release_parent_ref:
+@@ -465,17 +554,23 @@ EXPORT_SYMBOL_GPL(iscsi_create_conn);
  
- #define LPFC_MAX_RING_MASK  4	/* max num of rctl/type masks allowed per
- 				   ring */
-@@ -129,9 +129,7 @@ struct lpfc_sli_ring {
- 	uint16_t flag;		/* ring flags */
- #define LPFC_DEFERRED_RING_EVENT 0x001	/* Deferred processing a ring event */
- #define LPFC_CALL_RING_AVAILABLE 0x002	/* indicates cmd was full */
--#define LPFC_STOP_IOCB_MBX       0x010	/* Stop processing IOCB cmds mbox */
- #define LPFC_STOP_IOCB_EVENT     0x020	/* Stop processing IOCB cmds event */
--#define LPFC_STOP_IOCB_MASK      0x030	/* Stop processing IOCB cmds mask */
- 	uint16_t abtsiotag;	/* tracks next iotag to use for ABTS */
+ /**
+  * iscsi_destroy_conn - destroy iscsi class connection
+- * @session: iscsi cls session
++ * @conn: iscsi cls session
+  *
+  * This can be called from a LLD or iscsi_transport.
+- **/
++ */
+ int iscsi_destroy_conn(struct iscsi_cls_conn *conn)
+ {
++	unsigned long flags;
++
++	spin_lock_irqsave(&connlock, flags);
++	conn->active = 0;
++	list_del(&conn->conn_list);
++	spin_unlock_irqrestore(&connlock, flags);
++
+ 	transport_unregister_device(&conn->dev);
+ 	device_unregister(&conn->dev);
+ 	return 0;
+ }
+-
+ EXPORT_SYMBOL_GPL(iscsi_destroy_conn);
  
- 	uint32_t local_getidx;   /* last available cmd index (from cmdGetInx) */
-@@ -163,9 +161,12 @@ struct lpfc_sli_ring {
- 	struct list_head iocb_continueq;
- 	uint16_t iocb_continueq_cnt;	/* current length of queue */
- 	uint16_t iocb_continueq_max;	/* max length */
-+	struct list_head iocb_continue_saveq;
+ /*
+@@ -685,132 +780,74 @@ iscsi_if_get_stats(struct iscsi_transport *transport, struct nlmsghdr *nlh)
+ }
  
- 	struct lpfc_sli_ring_mask prt[LPFC_MAX_RING_MASK];
- 	uint32_t num_mask;	/* number of mask entries in prt array */
-+	void (*lpfc_sli_rcv_async_status) (struct lpfc_hba *,
-+		struct lpfc_sli_ring *, struct lpfc_iocbq *);
+ /**
+- * iscsi_if_destroy_session_done - send session destr. completion event
+- * @conn: last connection for session
+- *
+- * This is called by HW iscsi LLDs to notify userpsace that its HW has
+- * removed a session.
+- **/
+-int iscsi_if_destroy_session_done(struct iscsi_cls_conn *conn)
++ * iscsi_session_event - send session destr. completion event
++ * @session: iscsi class session
++ * @event: type of event
++ */
++int iscsi_session_event(struct iscsi_cls_session *session,
++			enum iscsi_uevent_e event)
+ {
+ 	struct iscsi_internal *priv;
+-	struct iscsi_cls_session *session;
+ 	struct Scsi_Host *shost;
+ 	struct iscsi_uevent *ev;
+ 	struct sk_buff  *skb;
+ 	struct nlmsghdr *nlh;
+-	unsigned long flags;
+ 	int rc, len = NLMSG_SPACE(sizeof(*ev));
  
- 	struct lpfc_sli_ring_stat stats;	/* SLI statistical info */
+-	priv = iscsi_if_transport_lookup(conn->transport);
++	priv = iscsi_if_transport_lookup(session->transport);
+ 	if (!priv)
+ 		return -EINVAL;
+-
+-	session = iscsi_dev_to_session(conn->dev.parent);
+ 	shost = iscsi_session_to_shost(session);
  
-@@ -199,9 +200,6 @@ struct lpfc_hbq_init {
- 	uint32_t add_count;	/* number to allocate when starved */
- } ;
+ 	skb = alloc_skb(len, GFP_KERNEL);
+ 	if (!skb) {
+-		dev_printk(KERN_ERR, &conn->dev, "Cannot notify userspace of "
+-			  "session creation event\n");
++		dev_printk(KERN_ERR, &session->dev, "Cannot notify userspace "
++			  "of session event %u\n", event);
+ 		return -ENOMEM;
+ 	}
  
--#define LPFC_MAX_HBQ 16
+ 	nlh = __nlmsg_put(skb, priv->daemon_pid, 0, 0, (len - sizeof(*nlh)), 0);
+ 	ev = NLMSG_DATA(nlh);
+-	ev->transport_handle = iscsi_handle(conn->transport);
+-	ev->type = ISCSI_KEVENT_DESTROY_SESSION;
+-	ev->r.d_session.host_no = shost->host_no;
+-	ev->r.d_session.sid = session->sid;
 -
+-	/*
+-	 * this will occur if the daemon is not up, so we just warn
+-	 * the user and when the daemon is restarted it will handle it
+-	 */
+-	rc = iscsi_broadcast_skb(skb, GFP_KERNEL);
+-	if (rc < 0)
+-		dev_printk(KERN_ERR, &conn->dev, "Cannot notify userspace of "
+-			  "session destruction event. Check iscsi daemon\n");
 -
- /* Structure used to hold SLI statistical counters and info */
- struct lpfc_sli_stat {
- 	uint64_t mbox_stat_err;  /* Mbox cmds completed status error */
-diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h
-index 0081f49..4b633d3 100644
---- a/drivers/scsi/lpfc/lpfc_version.h
-+++ b/drivers/scsi/lpfc/lpfc_version.h
-@@ -1,7 +1,7 @@
- /*******************************************************************
-  * This file is part of the Emulex Linux Device Driver for         *
-  * Fibre Channel Host Bus Adapters.                                *
-- * Copyright (C) 2004-2007 Emulex.  All rights reserved.           *
-+ * Copyright (C) 2004-2008 Emulex.  All rights reserved.           *
-  * EMULEX and SLI are trademarks of Emulex.                        *
-  * www.emulex.com                                                  *
-  *                                                                 *
-@@ -18,10 +18,10 @@
-  * included with this package.                                     *
-  *******************************************************************/
- 
--#define LPFC_DRIVER_VERSION "8.2.2"
-+#define LPFC_DRIVER_VERSION "8.2.4"
- 
- #define LPFC_DRIVER_NAME "lpfc"
+-	spin_lock_irqsave(&sesslock, flags);
+-	list_del(&session->sess_list);
+-	spin_unlock_irqrestore(&sesslock, flags);
++	ev->transport_handle = iscsi_handle(session->transport);
  
- #define LPFC_MODULE_DESC "Emulex LightPulse Fibre Channel SCSI driver " \
- 		LPFC_DRIVER_VERSION
--#define LPFC_COPYRIGHT "Copyright(c) 2004-2007 Emulex.  All rights reserved."
-+#define LPFC_COPYRIGHT "Copyright(c) 2004-2008 Emulex.  All rights reserved."
-diff --git a/drivers/scsi/lpfc/lpfc_vport.c b/drivers/scsi/lpfc/lpfc_vport.c
-index dcb415e..9fad766 100644
---- a/drivers/scsi/lpfc/lpfc_vport.c
-+++ b/drivers/scsi/lpfc/lpfc_vport.c
-@@ -125,15 +125,26 @@ lpfc_vport_sparm(struct lpfc_hba *phba, struct lpfc_vport *vport)
- 	pmb->vport = vport;
- 	rc = lpfc_sli_issue_mbox_wait(phba, pmb, phba->fc_ratov * 2);
- 	if (rc != MBX_SUCCESS) {
--		lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT | LOG_VPORT,
--				 "1818 VPort failed init, mbxCmd x%x "
--				 "READ_SPARM mbxStatus x%x, rc = x%x\n",
--				 mb->mbxCommand, mb->mbxStatus, rc);
--		lpfc_mbuf_free(phba, mp->virt, mp->phys);
--		kfree(mp);
--		if (rc != MBX_TIMEOUT)
--			mempool_free(pmb, phba->mbox_mem_pool);
--		return -EIO;
-+		if (signal_pending(current)) {
-+			lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT | LOG_VPORT,
-+					 "1830 Signal aborted mbxCmd x%x\n",
-+					 mb->mbxCommand);
-+			lpfc_mbuf_free(phba, mp->virt, mp->phys);
-+			kfree(mp);
-+			if (rc != MBX_TIMEOUT)
-+				mempool_free(pmb, phba->mbox_mem_pool);
-+			return -EINTR;
-+		} else {
-+			lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT | LOG_VPORT,
-+					 "1818 VPort failed init, mbxCmd x%x "
-+					 "READ_SPARM mbxStatus x%x, rc = x%x\n",
-+					 mb->mbxCommand, mb->mbxStatus, rc);
-+			lpfc_mbuf_free(phba, mp->virt, mp->phys);
-+			kfree(mp);
-+			if (rc != MBX_TIMEOUT)
-+				mempool_free(pmb, phba->mbox_mem_pool);
-+			return -EIO;
-+		}
+-	spin_lock_irqsave(&connlock, flags);
+-	conn->active = 0;
+-	list_del(&conn->conn_list);
+-	spin_unlock_irqrestore(&connlock, flags);
+-
+-	return rc;
+-}
+-EXPORT_SYMBOL_GPL(iscsi_if_destroy_session_done);
+-
+-/**
+- * iscsi_if_create_session_done - send session creation completion event
+- * @conn: leading connection for session
+- *
+- * This is called by HW iscsi LLDs to notify userpsace that its HW has
+- * created a session or a existing session is back in the logged in state.
+- **/
+-int iscsi_if_create_session_done(struct iscsi_cls_conn *conn)
+-{
+-	struct iscsi_internal *priv;
+-	struct iscsi_cls_session *session;
+-	struct Scsi_Host *shost;
+-	struct iscsi_uevent *ev;
+-	struct sk_buff  *skb;
+-	struct nlmsghdr *nlh;
+-	unsigned long flags;
+-	int rc, len = NLMSG_SPACE(sizeof(*ev));
+-
+-	priv = iscsi_if_transport_lookup(conn->transport);
+-	if (!priv)
++	ev->type = event;
++	switch (event) {
++	case ISCSI_KEVENT_DESTROY_SESSION:
++		ev->r.d_session.host_no = shost->host_no;
++		ev->r.d_session.sid = session->sid;
++		break;
++	case ISCSI_KEVENT_CREATE_SESSION:
++		ev->r.c_session_ret.host_no = shost->host_no;
++		ev->r.c_session_ret.sid = session->sid;
++		break;
++	case ISCSI_KEVENT_UNBIND_SESSION:
++		ev->r.unbind_session.host_no = shost->host_no;
++		ev->r.unbind_session.sid = session->sid;
++		break;
++	default:
++		dev_printk(KERN_ERR, &session->dev, "Invalid event %u.\n",
++			   event);
++		kfree_skb(skb);
+ 		return -EINVAL;
+-
+-	session = iscsi_dev_to_session(conn->dev.parent);
+-	shost = iscsi_session_to_shost(session);
+-
+-	skb = alloc_skb(len, GFP_KERNEL);
+-	if (!skb) {
+-		dev_printk(KERN_ERR, &conn->dev, "Cannot notify userspace of "
+-			  "session creation event\n");
+-		return -ENOMEM;
  	}
  
- 	memcpy(&vport->fc_sparam, mp->virt, sizeof (struct serv_parm));
-@@ -204,6 +215,7 @@ lpfc_vport_create(struct fc_vport *fc_vport, bool disable)
- 	int instance;
- 	int vpi;
- 	int rc = VPORT_ERROR;
-+	int status;
+-	nlh = __nlmsg_put(skb, priv->daemon_pid, 0, 0, (len - sizeof(*nlh)), 0);
+-	ev = NLMSG_DATA(nlh);
+-	ev->transport_handle = iscsi_handle(conn->transport);
+-	ev->type = ISCSI_UEVENT_CREATE_SESSION;
+-	ev->r.c_session_ret.host_no = shost->host_no;
+-	ev->r.c_session_ret.sid = session->sid;
+-
+ 	/*
+ 	 * this will occur if the daemon is not up, so we just warn
+ 	 * the user and when the daemon is restarted it will handle it
+ 	 */
+ 	rc = iscsi_broadcast_skb(skb, GFP_KERNEL);
+ 	if (rc < 0)
+-		dev_printk(KERN_ERR, &conn->dev, "Cannot notify userspace of "
+-			  "session creation event. Check iscsi daemon\n");
+-
+-	spin_lock_irqsave(&sesslock, flags);
+-	list_add(&session->sess_list, &sesslist);
+-	spin_unlock_irqrestore(&sesslock, flags);
+-
+-	spin_lock_irqsave(&connlock, flags);
+-	list_add(&conn->conn_list, &connlist);
+-	conn->active = 1;
+-	spin_unlock_irqrestore(&connlock, flags);
++		dev_printk(KERN_ERR, &session->dev, "Cannot notify userspace "
++			  "of session event %u. Check iscsi daemon\n", event);
+ 	return rc;
+ }
+-EXPORT_SYMBOL_GPL(iscsi_if_create_session_done);
++EXPORT_SYMBOL_GPL(iscsi_session_event);
  
- 	if ((phba->sli_rev < 3) ||
- 		!(phba->sli3_options & LPFC_SLI3_NPIV_ENABLED)) {
-@@ -248,13 +260,19 @@ lpfc_vport_create(struct fc_vport *fc_vport, bool disable)
- 	vport->vpi = vpi;
- 	lpfc_debugfs_initialize(vport);
+ static int
+ iscsi_if_create_session(struct iscsi_internal *priv, struct iscsi_uevent *ev)
+ {
+ 	struct iscsi_transport *transport = priv->iscsi_transport;
+ 	struct iscsi_cls_session *session;
+-	unsigned long flags;
+ 	uint32_t hostno;
  
--	if (lpfc_vport_sparm(phba, vport)) {
--		lpfc_printf_vlog(vport, KERN_ERR, LOG_VPORT,
--				 "1813 Create VPORT failed. "
--				 "Cannot get sparam\n");
-+	if ((status = lpfc_vport_sparm(phba, vport))) {
-+		if (status == -EINTR) {
-+			lpfc_printf_vlog(vport, KERN_ERR, LOG_VPORT,
-+					 "1831 Create VPORT Interrupted.\n");
-+			rc = VPORT_ERROR;
-+		} else {
-+			lpfc_printf_vlog(vport, KERN_ERR, LOG_VPORT,
-+					 "1813 Create VPORT failed. "
-+					 "Cannot get sparam\n");
-+			rc = VPORT_NORESOURCES;
-+		}
- 		lpfc_free_vpi(phba, vpi);
- 		destroy_port(vport);
--		rc = VPORT_NORESOURCES;
- 		goto error_out;
- 	}
+ 	session = transport->create_session(transport, &priv->t,
+@@ -821,10 +858,6 @@ iscsi_if_create_session(struct iscsi_internal *priv, struct iscsi_uevent *ev)
+ 	if (!session)
+ 		return -ENOMEM;
  
-@@ -427,7 +445,6 @@ int
- lpfc_vport_delete(struct fc_vport *fc_vport)
+-	spin_lock_irqsave(&sesslock, flags);
+-	list_add(&session->sess_list, &sesslist);
+-	spin_unlock_irqrestore(&sesslock, flags);
+-
+ 	ev->r.c_session_ret.host_no = hostno;
+ 	ev->r.c_session_ret.sid = session->sid;
+ 	return 0;
+@@ -835,7 +868,6 @@ iscsi_if_create_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev)
  {
- 	struct lpfc_nodelist *ndlp = NULL;
--	struct lpfc_nodelist *next_ndlp;
- 	struct Scsi_Host *shost = (struct Scsi_Host *) fc_vport->shost;
- 	struct lpfc_vport *vport = *(struct lpfc_vport **)fc_vport->dd_data;
- 	struct lpfc_hba   *phba = vport->phba;
-@@ -482,8 +499,18 @@ lpfc_vport_delete(struct fc_vport *fc_vport)
+ 	struct iscsi_cls_conn *conn;
+ 	struct iscsi_cls_session *session;
+-	unsigned long flags;
  
- 	ndlp = lpfc_findnode_did(phba->pport, Fabric_DID);
- 	if (ndlp && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE &&
--		phba->link_state >= LPFC_LINK_UP) {
+ 	session = iscsi_session_lookup(ev->u.c_conn.sid);
+ 	if (!session) {
+@@ -854,28 +886,17 @@ iscsi_if_create_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev)
+ 
+ 	ev->r.c_conn_ret.sid = session->sid;
+ 	ev->r.c_conn_ret.cid = conn->cid;
 -
-+	    phba->link_state >= LPFC_LINK_UP) {
-+		if (vport->cfg_enable_da_id) {
-+			timeout = msecs_to_jiffies(phba->fc_ratov * 2000);
-+			if (!lpfc_ns_cmd(vport, SLI_CTNS_DA_ID, 0, 0))
-+				while (vport->ct_flags && timeout)
-+					timeout = schedule_timeout(timeout);
-+			else
-+				lpfc_printf_log(vport->phba, KERN_WARNING,
-+						LOG_VPORT,
-+						"1829 CT command failed to "
-+						"delete objects on fabric. \n");
-+		}
- 		/* First look for the Fabric ndlp */
- 		ndlp = lpfc_findnode_did(vport, Fabric_DID);
- 		if (!ndlp) {
-@@ -503,23 +530,20 @@ lpfc_vport_delete(struct fc_vport *fc_vport)
- 	}
+-	spin_lock_irqsave(&connlock, flags);
+-	list_add(&conn->conn_list, &connlist);
+-	conn->active = 1;
+-	spin_unlock_irqrestore(&connlock, flags);
+-
+ 	return 0;
+ }
  
- skip_logo:
-+	lpfc_cleanup(vport);
- 	lpfc_sli_host_down(vport);
+ static int
+ iscsi_if_destroy_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev)
+ {
+-	unsigned long flags;
+ 	struct iscsi_cls_conn *conn;
  
--	list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) {
--		lpfc_disc_state_machine(vport, ndlp, NULL,
--					     NLP_EVT_DEVICE_RECOVERY);
--		lpfc_disc_state_machine(vport, ndlp, NULL,
--					     NLP_EVT_DEVICE_RM);
--	}
--
- 	lpfc_stop_vport_timers(vport);
- 	lpfc_unreg_all_rpis(vport);
--	lpfc_unreg_default_rpis(vport);
--	/*
--	 * Completion of unreg_vpi (lpfc_mbx_cmpl_unreg_vpi) does the
--	 * scsi_host_put() to release the vport.
--	 */
--	lpfc_mbx_unreg_vpi(vport);
-+
-+	if (!(phba->pport->load_flag & FC_UNLOADING)) {
-+		lpfc_unreg_default_rpis(vport);
-+		/*
-+		 * Completion of unreg_vpi (lpfc_mbx_cmpl_unreg_vpi)
-+		 * does the scsi_host_put() to release the vport.
-+		 */
-+		lpfc_mbx_unreg_vpi(vport);
-+	}
+ 	conn = iscsi_conn_lookup(ev->u.d_conn.sid, ev->u.d_conn.cid);
+ 	if (!conn)
+ 		return -EINVAL;
+-	spin_lock_irqsave(&connlock, flags);
+-	conn->active = 0;
+-	list_del(&conn->conn_list);
+-	spin_unlock_irqrestore(&connlock, flags);
  
- 	lpfc_free_vpi(phba, vport->vpi);
- 	vport->work_port_events = 0;
-@@ -532,16 +556,13 @@ skip_logo:
- 	return VPORT_OK;
- }
+ 	if (transport->destroy_conn)
+ 		transport->destroy_conn(conn);
+@@ -1002,7 +1023,6 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
+ 	struct iscsi_internal *priv;
+ 	struct iscsi_cls_session *session;
+ 	struct iscsi_cls_conn *conn;
+-	unsigned long flags;
  
--EXPORT_SYMBOL(lpfc_vport_create);
--EXPORT_SYMBOL(lpfc_vport_delete);
+ 	priv = iscsi_if_transport_lookup(iscsi_ptr(ev->transport_handle));
+ 	if (!priv)
+@@ -1020,13 +1040,16 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
+ 		break;
+ 	case ISCSI_UEVENT_DESTROY_SESSION:
+ 		session = iscsi_session_lookup(ev->u.d_session.sid);
+-		if (session) {
+-			spin_lock_irqsave(&sesslock, flags);
+-			list_del(&session->sess_list);
+-			spin_unlock_irqrestore(&sesslock, flags);
 -
- struct lpfc_vport **
- lpfc_create_vport_work_array(struct lpfc_hba *phba)
- {
- 	struct lpfc_vport *port_iterator;
- 	struct lpfc_vport **vports;
- 	int index = 0;
--	vports = kzalloc(LPFC_MAX_VPORTS * sizeof(struct lpfc_vport *),
-+	vports = kzalloc((phba->max_vpi + 1) * sizeof(struct lpfc_vport *),
- 			 GFP_KERNEL);
- 	if (vports == NULL)
- 		return NULL;
-@@ -560,12 +581,12 @@ lpfc_create_vport_work_array(struct lpfc_hba *phba)
- }
++		if (session)
+ 			transport->destroy_session(session);
+-		} else
++		else
++			err = -EINVAL;
++		break;
++	case ISCSI_UEVENT_UNBIND_SESSION:
++		session = iscsi_session_lookup(ev->u.d_session.sid);
++		if (session)
++			iscsi_unbind_session(session);
++		else
+ 			err = -EINVAL;
+ 		break;
+ 	case ISCSI_UEVENT_CREATE_CONN:
+@@ -1179,6 +1202,8 @@ iscsi_conn_attr(port, ISCSI_PARAM_CONN_PORT);
+ iscsi_conn_attr(exp_statsn, ISCSI_PARAM_EXP_STATSN);
+ iscsi_conn_attr(persistent_address, ISCSI_PARAM_PERSISTENT_ADDRESS);
+ iscsi_conn_attr(address, ISCSI_PARAM_CONN_ADDRESS);
++iscsi_conn_attr(ping_tmo, ISCSI_PARAM_PING_TMO);
++iscsi_conn_attr(recv_tmo, ISCSI_PARAM_RECV_TMO);
  
- void
--lpfc_destroy_vport_work_array(struct lpfc_vport **vports)
-+lpfc_destroy_vport_work_array(struct lpfc_hba *phba, struct lpfc_vport **vports)
- {
- 	int i;
- 	if (vports == NULL)
- 		return;
--	for (i=0; vports[i] != NULL && i < LPFC_MAX_VPORTS; i++)
-+	for (i=0; vports[i] != NULL && i <= phba->max_vpi; i++)
- 		scsi_host_put(lpfc_shost_from_vport(vports[i]));
- 	kfree(vports);
- }
-diff --git a/drivers/scsi/lpfc/lpfc_vport.h b/drivers/scsi/lpfc/lpfc_vport.h
-index 91da177..96c4453 100644
---- a/drivers/scsi/lpfc/lpfc_vport.h
-+++ b/drivers/scsi/lpfc/lpfc_vport.h
-@@ -89,7 +89,7 @@ int lpfc_vport_delete(struct fc_vport *);
- int lpfc_vport_getinfo(struct Scsi_Host *, struct vport_info *);
- int lpfc_vport_tgt_remove(struct Scsi_Host *, uint, uint);
- struct lpfc_vport **lpfc_create_vport_work_array(struct lpfc_hba *);
--void lpfc_destroy_vport_work_array(struct lpfc_vport **);
-+void lpfc_destroy_vport_work_array(struct lpfc_hba *, struct lpfc_vport **);
+ #define iscsi_cdev_to_session(_cdev) \
+ 	iscsi_dev_to_session(_cdev->dev)
+@@ -1217,6 +1242,9 @@ iscsi_session_attr(username, ISCSI_PARAM_USERNAME, 1);
+ iscsi_session_attr(username_in, ISCSI_PARAM_USERNAME_IN, 1);
+ iscsi_session_attr(password, ISCSI_PARAM_PASSWORD, 1);
+ iscsi_session_attr(password_in, ISCSI_PARAM_PASSWORD_IN, 1);
++iscsi_session_attr(fast_abort, ISCSI_PARAM_FAST_ABORT, 0);
++iscsi_session_attr(abort_tmo, ISCSI_PARAM_ABORT_TMO, 0);
++iscsi_session_attr(lu_reset_tmo, ISCSI_PARAM_LU_RESET_TMO, 0);
  
- /*
-  *  queuecommand  VPORT-specific return codes. Specified in  the host byte code.
-diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c
-index 66c6520..765c24d 100644
---- a/drivers/scsi/megaraid.c
-+++ b/drivers/scsi/megaraid.c
-@@ -4889,7 +4889,7 @@ __megaraid_shutdown(adapter_t *adapter)
- 		mdelay(1000);
- }
+ #define iscsi_priv_session_attr_show(field, format)			\
+ static ssize_t								\
+@@ -1413,6 +1441,8 @@ iscsi_register_transport(struct iscsi_transport *tt)
+ 	SETUP_CONN_RD_ATTR(exp_statsn, ISCSI_EXP_STATSN);
+ 	SETUP_CONN_RD_ATTR(persistent_address, ISCSI_PERSISTENT_ADDRESS);
+ 	SETUP_CONN_RD_ATTR(persistent_port, ISCSI_PERSISTENT_PORT);
++	SETUP_CONN_RD_ATTR(ping_tmo, ISCSI_PING_TMO);
++	SETUP_CONN_RD_ATTR(recv_tmo, ISCSI_RECV_TMO);
  
--static void
-+static void __devexit
- megaraid_remove_one(struct pci_dev *pdev)
- {
- 	struct Scsi_Host *host = pci_get_drvdata(pdev);
-diff --git a/drivers/scsi/megaraid/megaraid_mbox.c b/drivers/scsi/megaraid/megaraid_mbox.c
-index c892310..24e32e4 100644
---- a/drivers/scsi/megaraid/megaraid_mbox.c
-+++ b/drivers/scsi/megaraid/megaraid_mbox.c
-@@ -300,7 +300,7 @@ static struct pci_device_id pci_id_table_g[] =  {
- MODULE_DEVICE_TABLE(pci, pci_id_table_g);
+ 	BUG_ON(count > ISCSI_CONN_ATTRS);
+ 	priv->conn_attrs[count] = NULL;
+@@ -1438,6 +1468,9 @@ iscsi_register_transport(struct iscsi_transport *tt)
+ 	SETUP_SESSION_RD_ATTR(password_in, ISCSI_USERNAME_IN);
+ 	SETUP_SESSION_RD_ATTR(username, ISCSI_PASSWORD);
+ 	SETUP_SESSION_RD_ATTR(username_in, ISCSI_PASSWORD_IN);
++	SETUP_SESSION_RD_ATTR(fast_abort, ISCSI_FAST_ABORT);
++	SETUP_SESSION_RD_ATTR(abort_tmo, ISCSI_ABORT_TMO);
++	SETUP_SESSION_RD_ATTR(lu_reset_tmo,ISCSI_LU_RESET_TMO);
+ 	SETUP_PRIV_SESSION_RD_ATTR(recovery_tmo);
  
+ 	BUG_ON(count > ISCSI_SESSION_ATTRS);
+@@ -1518,8 +1551,14 @@ static __init int iscsi_transport_init(void)
+ 		goto unregister_session_class;
+ 	}
  
--static struct pci_driver megaraid_pci_driver_g = {
-+static struct pci_driver megaraid_pci_driver = {
- 	.name		= "megaraid",
- 	.id_table	= pci_id_table_g,
- 	.probe		= megaraid_probe_one,
-@@ -394,7 +394,7 @@ megaraid_init(void)
++	iscsi_eh_timer_workq = create_singlethread_workqueue("iscsi_eh");
++	if (!iscsi_eh_timer_workq)
++		goto release_nls;
++
+ 	return 0;
  
++release_nls:
++	sock_release(nls->sk_socket);
+ unregister_session_class:
+ 	transport_class_unregister(&iscsi_session_class);
+ unregister_conn_class:
+@@ -1533,6 +1572,7 @@ unregister_transport_class:
  
- 	// register as a PCI hot-plug driver module
--	rval = pci_register_driver(&megaraid_pci_driver_g);
-+	rval = pci_register_driver(&megaraid_pci_driver);
- 	if (rval < 0) {
- 		con_log(CL_ANN, (KERN_WARNING
- 			"megaraid: could not register hotplug support.\n"));
-@@ -415,7 +415,7 @@ megaraid_exit(void)
- 	con_log(CL_DLEVEL1, (KERN_NOTICE "megaraid: unloading framework\n"));
+ static void __exit iscsi_transport_exit(void)
+ {
++	destroy_workqueue(iscsi_eh_timer_workq);
+ 	sock_release(nls->sk_socket);
+ 	transport_class_unregister(&iscsi_connection_class);
+ 	transport_class_unregister(&iscsi_session_class);
+diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.c
+index 3120f4b..f2149d0 100644
+--- a/drivers/scsi/scsi_transport_sas.c
++++ b/drivers/scsi/scsi_transport_sas.c
+@@ -173,6 +173,7 @@ static void sas_smp_request(struct request_queue *q, struct Scsi_Host *shost,
  
- 	// unregister as PCI hotplug driver
--	pci_unregister_driver(&megaraid_pci_driver_g);
-+	pci_unregister_driver(&megaraid_pci_driver);
+ 		handler = to_sas_internal(shost->transportt)->f->smp_handler;
+ 		ret = handler(shost, rphy, req);
++		req->errors = ret;
  
- 	return;
+ 		spin_lock_irq(q->queue_lock);
+ 
+@@ -323,7 +324,7 @@ static int do_sas_phy_delete(struct device *dev, void *data)
  }
-diff --git a/drivers/scsi/megaraid/megaraid_sas.c b/drivers/scsi/megaraid/megaraid_sas.c
-index e3c5c52..d7ec921 100644
---- a/drivers/scsi/megaraid/megaraid_sas.c
-+++ b/drivers/scsi/megaraid/megaraid_sas.c
-@@ -2,7 +2,7 @@
-  *
-  *		Linux MegaRAID driver for SAS based RAID controllers
-  *
-- * Copyright (c) 2003-2005  LSI Logic Corporation.
-+ * Copyright (c) 2003-2005  LSI Corporation.
+ 
+ /**
+- * sas_remove_children  --  tear down a devices SAS data structures
++ * sas_remove_children  -  tear down a devices SAS data structures
+  * @dev:	device belonging to the sas object
   *
-  *	   This program is free software; you can redistribute it and/or
-  *	   modify it under the terms of the GNU General Public License
-@@ -10,7 +10,7 @@
-  *	   2 of the License, or (at your option) any later version.
+  * Removes all SAS PHYs and remote PHYs for a given object
+@@ -336,7 +337,7 @@ void sas_remove_children(struct device *dev)
+ EXPORT_SYMBOL(sas_remove_children);
+ 
+ /**
+- * sas_remove_host  --  tear down a Scsi_Host's SAS data structures
++ * sas_remove_host  -  tear down a Scsi_Host's SAS data structures
+  * @shost:	Scsi Host that is torn down
   *
-  * FILE		: megaraid_sas.c
-- * Version	: v00.00.03.10-rc5
-+ * Version	: v00.00.03.16-rc1
+  * Removes all SAS PHYs and remote PHYs for a given Scsi_Host.
+@@ -577,7 +578,7 @@ static void sas_phy_release(struct device *dev)
+ }
+ 
+ /**
+- * sas_phy_alloc  --  allocates and initialize a SAS PHY structure
++ * sas_phy_alloc  -  allocates and initialize a SAS PHY structure
+  * @parent:	Parent device
+  * @number:	Phy index
   *
-  * Authors:
-  *	(email-id : megaraidlinux at lsi.com)
-@@ -31,6 +31,7 @@
- #include <linux/moduleparam.h>
- #include <linux/module.h>
- #include <linux/spinlock.h>
-+#include <linux/mutex.h>
- #include <linux/interrupt.h>
- #include <linux/delay.h>
- #include <linux/uio.h>
-@@ -46,10 +47,18 @@
- #include <scsi/scsi_host.h>
- #include "megaraid_sas.h"
+@@ -618,7 +619,7 @@ struct sas_phy *sas_phy_alloc(struct device *parent, int number)
+ EXPORT_SYMBOL(sas_phy_alloc);
  
-+/*
-+ * poll_mode_io:1- schedule complete completion from q cmd
-+ */
-+static unsigned int poll_mode_io;
-+module_param_named(poll_mode_io, poll_mode_io, int, 0);
-+MODULE_PARM_DESC(poll_mode_io,
-+	"Complete cmds from IO path, (default=0)");
-+
- MODULE_LICENSE("GPL");
- MODULE_VERSION(MEGASAS_VERSION);
- MODULE_AUTHOR("megaraidlinux at lsi.com");
--MODULE_DESCRIPTION("LSI Logic MegaRAID SAS Driver");
-+MODULE_DESCRIPTION("LSI MegaRAID SAS Driver");
+ /**
+- * sas_phy_add  --  add a SAS PHY to the device hierarchy
++ * sas_phy_add  -  add a SAS PHY to the device hierarchy
+  * @phy:	The PHY to be added
+  *
+  * Publishes a SAS PHY to the rest of the system.
+@@ -638,7 +639,7 @@ int sas_phy_add(struct sas_phy *phy)
+ EXPORT_SYMBOL(sas_phy_add);
  
- /*
-  * PCI ID table for all supported controllers
-@@ -76,6 +85,10 @@ static DEFINE_MUTEX(megasas_async_queue_mutex);
+ /**
+- * sas_phy_free  --  free a SAS PHY
++ * sas_phy_free  -  free a SAS PHY
+  * @phy:	SAS PHY to free
+  *
+  * Frees the specified SAS PHY.
+@@ -655,7 +656,7 @@ void sas_phy_free(struct sas_phy *phy)
+ EXPORT_SYMBOL(sas_phy_free);
  
- static u32 megasas_dbg_lvl;
+ /**
+- * sas_phy_delete  --  remove SAS PHY
++ * sas_phy_delete  -  remove SAS PHY
+  * @phy:	SAS PHY to remove
+  *
+  * Removes the specified SAS PHY.  If the SAS PHY has an
+@@ -677,7 +678,7 @@ sas_phy_delete(struct sas_phy *phy)
+ EXPORT_SYMBOL(sas_phy_delete);
+ 
+ /**
+- * scsi_is_sas_phy  --  check if a struct device represents a SAS PHY
++ * scsi_is_sas_phy  -  check if a struct device represents a SAS PHY
+  * @dev:	device to check
+  *
+  * Returns:
+@@ -843,7 +844,6 @@ EXPORT_SYMBOL(sas_port_alloc_num);
  
-+static void
-+megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd,
-+		     u8 alt_status);
-+
  /**
-  * megasas_get_cmd -	Get a command from the free pool
-  * @instance:		Adapter soft state
-@@ -855,6 +868,12 @@ megasas_queue_command(struct scsi_cmnd *scmd, void (*done) (struct scsi_cmnd *))
- 	atomic_inc(&instance->fw_outstanding);
+  * sas_port_add - add a SAS port to the device hierarchy
+- *
+  * @port:	port to be added
+  *
+  * publishes a port to the rest of the system
+@@ -868,7 +868,7 @@ int sas_port_add(struct sas_port *port)
+ EXPORT_SYMBOL(sas_port_add);
  
- 	instance->instancet->fire_cmd(cmd->frame_phys_addr ,cmd->frame_count-1,instance->reg_set);
-+	/*
-+	 * Check if we have pend cmds to be completed
-+	 */
-+	if (poll_mode_io && atomic_read(&instance->fw_outstanding))
-+		tasklet_schedule(&instance->isr_tasklet);
-+
+ /**
+- * sas_port_free  --  free a SAS PORT
++ * sas_port_free  -  free a SAS PORT
+  * @port:	SAS PORT to free
+  *
+  * Frees the specified SAS PORT.
+@@ -885,7 +885,7 @@ void sas_port_free(struct sas_port *port)
+ EXPORT_SYMBOL(sas_port_free);
  
- 	return 0;
+ /**
+- * sas_port_delete  --  remove SAS PORT
++ * sas_port_delete  -  remove SAS PORT
+  * @port:	SAS PORT to remove
+  *
+  * Removes the specified SAS PORT.  If the SAS PORT has an
+@@ -924,7 +924,7 @@ void sas_port_delete(struct sas_port *port)
+ EXPORT_SYMBOL(sas_port_delete);
  
-@@ -886,6 +905,64 @@ static int megasas_slave_configure(struct scsi_device *sdev)
- }
+ /**
+- * scsi_is_sas_port --  check if a struct device represents a SAS port
++ * scsi_is_sas_port -  check if a struct device represents a SAS port
+  * @dev:	device to check
+  *
+  * Returns:
+@@ -1309,6 +1309,7 @@ static void sas_rphy_initialize(struct sas_rphy *rphy)
  
  /**
-+ * megasas_complete_cmd_dpc	 -	Returns FW's controller structure
-+ * @instance_addr:			Address of adapter soft state
-+ *
-+ * Tasklet to complete cmds
-+ */
-+static void megasas_complete_cmd_dpc(unsigned long instance_addr)
-+{
-+	u32 producer;
-+	u32 consumer;
-+	u32 context;
-+	struct megasas_cmd *cmd;
-+	struct megasas_instance *instance =
-+				(struct megasas_instance *)instance_addr;
-+	unsigned long flags;
-+
-+	/* If we have already declared adapter dead, donot complete cmds */
-+	if (instance->hw_crit_error)
-+		return;
-+
-+	spin_lock_irqsave(&instance->completion_lock, flags);
-+
-+	producer = *instance->producer;
-+	consumer = *instance->consumer;
-+
-+	while (consumer != producer) {
-+		context = instance->reply_queue[consumer];
-+
-+		cmd = instance->cmd_list[context];
-+
-+		megasas_complete_cmd(instance, cmd, DID_OK);
-+
-+		consumer++;
-+		if (consumer == (instance->max_fw_cmds + 1)) {
-+			consumer = 0;
-+		}
-+	}
-+
-+	*instance->consumer = producer;
-+
-+	spin_unlock_irqrestore(&instance->completion_lock, flags);
-+
-+	/*
-+	 * Check if we can restore can_queue
-+	 */
-+	if (instance->flag & MEGASAS_FW_BUSY
-+		&& time_after(jiffies, instance->last_time + 5 * HZ)
-+		&& atomic_read(&instance->fw_outstanding) < 17) {
-+
-+		spin_lock_irqsave(instance->host->host_lock, flags);
-+		instance->flag &= ~MEGASAS_FW_BUSY;
-+		instance->host->can_queue =
-+				instance->max_fw_cmds - MEGASAS_INT_CMDS;
-+
-+		spin_unlock_irqrestore(instance->host->host_lock, flags);
-+	}
-+}
-+
-+/**
-  * megasas_wait_for_outstanding -	Wait for all outstanding cmds
-  * @instance:				Adapter soft state
+  * sas_end_device_alloc - allocate an rphy for an end device
++ * @parent: which port
   *
-@@ -908,6 +985,11 @@ static int megasas_wait_for_outstanding(struct megasas_instance *instance)
- 		if (!(i % MEGASAS_RESET_NOTICE_INTERVAL)) {
- 			printk(KERN_NOTICE "megasas: [%2d]waiting for %d "
- 			       "commands to complete\n",i,outstanding);
-+			/*
-+			 * Call cmd completion routine. Cmd to be
-+			 * be completed directly without depending on isr.
-+			 */
-+			megasas_complete_cmd_dpc((unsigned long)instance);
- 		}
+  * Allocates an SAS remote PHY structure, connected to @parent.
+  *
+@@ -1345,6 +1346,8 @@ EXPORT_SYMBOL(sas_end_device_alloc);
  
- 		msleep(1000);
-@@ -1100,7 +1182,7 @@ megasas_service_aen(struct megasas_instance *instance, struct megasas_cmd *cmd)
- static struct scsi_host_template megasas_template = {
+ /**
+  * sas_expander_alloc - allocate an rphy for an end device
++ * @parent: which port
++ * @type: SAS_EDGE_EXPANDER_DEVICE or SAS_FANOUT_EXPANDER_DEVICE
+  *
+  * Allocates an SAS remote PHY structure, connected to @parent.
+  *
+@@ -1383,7 +1386,7 @@ struct sas_rphy *sas_expander_alloc(struct sas_port *parent,
+ EXPORT_SYMBOL(sas_expander_alloc);
  
- 	.module = THIS_MODULE,
--	.name = "LSI Logic SAS based MegaRAID driver",
-+	.name = "LSI SAS based MegaRAID driver",
- 	.proc_name = "megaraid_sas",
- 	.slave_configure = megasas_slave_configure,
- 	.queuecommand = megasas_queue_command,
-@@ -1749,57 +1831,119 @@ megasas_get_ctrl_info(struct megasas_instance *instance,
- }
+ /**
+- * sas_rphy_add  --  add a SAS remote PHY to the device hierarchy
++ * sas_rphy_add  -  add a SAS remote PHY to the device hierarchy
+  * @rphy:	The remote PHY to be added
+  *
+  * Publishes a SAS remote PHY to the rest of the system.
+@@ -1430,8 +1433,8 @@ int sas_rphy_add(struct sas_rphy *rphy)
+ EXPORT_SYMBOL(sas_rphy_add);
  
  /**
-- * megasas_complete_cmd_dpc	 -	Returns FW's controller structure
-- * @instance_addr:			Address of adapter soft state
-+ * megasas_issue_init_mfi -	Initializes the FW
-+ * @instance:		Adapter soft state
+- * sas_rphy_free  --  free a SAS remote PHY
+- * @rphy	SAS remote PHY to free
++ * sas_rphy_free  -  free a SAS remote PHY
++ * @rphy: SAS remote PHY to free
   *
-- * Tasklet to complete cmds
-+ * Issues the INIT MFI cmd
-  */
--static void megasas_complete_cmd_dpc(unsigned long instance_addr)
-+static int
-+megasas_issue_init_mfi(struct megasas_instance *instance)
- {
--	u32 producer;
--	u32 consumer;
- 	u32 context;
-+
- 	struct megasas_cmd *cmd;
--	struct megasas_instance *instance = (struct megasas_instance *)instance_addr;
--	unsigned long flags;
+  * Frees the specified SAS remote PHY.
+  *
+@@ -1459,7 +1462,7 @@ void sas_rphy_free(struct sas_rphy *rphy)
+ EXPORT_SYMBOL(sas_rphy_free);
  
--	/* If we have already declared adapter dead, donot complete cmds */
--	if (instance->hw_crit_error)
--		return;
-+	struct megasas_init_frame *init_frame;
-+	struct megasas_init_queue_info *initq_info;
-+	dma_addr_t init_frame_h;
-+	dma_addr_t initq_info_h;
+ /**
+- * sas_rphy_delete  --  remove and free SAS remote PHY
++ * sas_rphy_delete  -  remove and free SAS remote PHY
+  * @rphy:	SAS remote PHY to remove and free
+  *
+  * Removes the specified SAS remote PHY and frees it.
+@@ -1473,7 +1476,7 @@ sas_rphy_delete(struct sas_rphy *rphy)
+ EXPORT_SYMBOL(sas_rphy_delete);
  
--	producer = *instance->producer;
--	consumer = *instance->consumer;
-+	/*
-+	 * Prepare a init frame. Note the init frame points to queue info
-+	 * structure. Each frame has SGL allocated after first 64 bytes. For
-+	 * this frame - since we don't need any SGL - we use SGL's space as
-+	 * queue info structure
-+	 *
-+	 * We will not get a NULL command below. We just created the pool.
-+	 */
-+	cmd = megasas_get_cmd(instance);
+ /**
+- * sas_rphy_remove  --  remove SAS remote PHY
++ * sas_rphy_remove  -  remove SAS remote PHY
+  * @rphy:	SAS remote phy to remove
+  *
+  * Removes the specified SAS remote PHY.
+@@ -1504,7 +1507,7 @@ sas_rphy_remove(struct sas_rphy *rphy)
+ EXPORT_SYMBOL(sas_rphy_remove);
  
--	while (consumer != producer) {
--		context = instance->reply_queue[consumer];
-+	init_frame = (struct megasas_init_frame *)cmd->frame;
-+	initq_info = (struct megasas_init_queue_info *)
-+		((unsigned long)init_frame + 64);
+ /**
+- * scsi_is_sas_rphy  --  check if a struct device represents a SAS remote PHY
++ * scsi_is_sas_rphy  -  check if a struct device represents a SAS remote PHY
+  * @dev:	device to check
+  *
+  * Returns:
+@@ -1604,7 +1607,7 @@ static int sas_user_scan(struct Scsi_Host *shost, uint channel,
+ 	SETUP_TEMPLATE(expander_attrs, expander_##field, S_IRUGO, 1)
  
--		cmd = instance->cmd_list[context];
-+	init_frame_h = cmd->frame_phys_addr;
-+	initq_info_h = init_frame_h + 64;
+ /**
+- * sas_attach_transport  --  instantiate SAS transport template
++ * sas_attach_transport  -  instantiate SAS transport template
+  * @ft:		SAS transport class function template
+  */
+ struct scsi_transport_template *
+@@ -1715,7 +1718,7 @@ sas_attach_transport(struct sas_function_template *ft)
+ EXPORT_SYMBOL(sas_attach_transport);
  
--		megasas_complete_cmd(instance, cmd, DID_OK);
-+	context = init_frame->context;
-+	memset(init_frame, 0, MEGAMFI_FRAME_SIZE);
-+	memset(initq_info, 0, sizeof(struct megasas_init_queue_info));
-+	init_frame->context = context;
+ /**
+- * sas_release_transport  --  release SAS transport template instance
++ * sas_release_transport  -  release SAS transport template instance
+  * @t:		transport template instance
+  */
+ void sas_release_transport(struct scsi_transport_template *t)
+diff --git a/drivers/scsi/scsi_transport_spi.c b/drivers/scsi/scsi_transport_spi.c
+index 4df21c9..1fb6031 100644
+--- a/drivers/scsi/scsi_transport_spi.c
++++ b/drivers/scsi/scsi_transport_spi.c
+@@ -52,13 +52,6 @@
+ struct spi_internal {
+ 	struct scsi_transport_template t;
+ 	struct spi_function_template *f;
+-	/* The actual attributes */
+-	struct class_device_attribute private_attrs[SPI_NUM_ATTRS];
+-	/* The array of null terminated pointers to attributes 
+-	 * needed by scsi_sysfs.c */
+-	struct class_device_attribute *attrs[SPI_NUM_ATTRS + SPI_OTHER_ATTRS + 1];
+-	struct class_device_attribute private_host_attrs[SPI_HOST_ATTRS];
+-	struct class_device_attribute *host_attrs[SPI_HOST_ATTRS + 1];
+ };
  
--		consumer++;
--		if (consumer == (instance->max_fw_cmds + 1)) {
--			consumer = 0;
--		}
--	}
-+	initq_info->reply_queue_entries = instance->max_fw_cmds + 1;
-+	initq_info->reply_queue_start_phys_addr_lo = instance->reply_queue_h;
+ #define to_spi_internal(tmpl)	container_of(tmpl, struct spi_internal, t)
+@@ -174,17 +167,20 @@ static int spi_host_setup(struct transport_container *tc, struct device *dev,
+ 	return 0;
+ }
  
--	*instance->consumer = producer;
-+	initq_info->producer_index_phys_addr_lo = instance->producer_h;
-+	initq_info->consumer_index_phys_addr_lo = instance->consumer_h;
-+
-+	init_frame->cmd = MFI_CMD_INIT;
-+	init_frame->cmd_status = 0xFF;
-+	init_frame->queue_info_new_phys_addr_lo = initq_info_h;
++static int spi_host_configure(struct transport_container *tc,
++			      struct device *dev,
++			      struct class_device *cdev);
 +
-+	init_frame->data_xfer_len = sizeof(struct megasas_init_queue_info);
+ static DECLARE_TRANSPORT_CLASS(spi_host_class,
+ 			       "spi_host",
+ 			       spi_host_setup,
+ 			       NULL,
+-			       NULL);
++			       spi_host_configure);
  
- 	/*
--	 * Check if we can restore can_queue
-+	 * disable the intr before firing the init frame to FW
- 	 */
--	if (instance->flag & MEGASAS_FW_BUSY
--		&& time_after(jiffies, instance->last_time + 5 * HZ)
--		&& atomic_read(&instance->fw_outstanding) < 17) {
-+	instance->instancet->disable_intr(instance->reg_set);
+ static int spi_host_match(struct attribute_container *cont,
+ 			  struct device *dev)
+ {
+ 	struct Scsi_Host *shost;
+-	struct spi_internal *i;
  
--		spin_lock_irqsave(instance->host->host_lock, flags);
--		instance->flag &= ~MEGASAS_FW_BUSY;
--		instance->host->can_queue =
--				instance->max_fw_cmds - MEGASAS_INT_CMDS;
-+	/*
-+	 * Issue the init frame in polled mode
-+	 */
+ 	if (!scsi_is_host_device(dev))
+ 		return 0;
+@@ -194,11 +190,13 @@ static int spi_host_match(struct attribute_container *cont,
+ 	    != &spi_host_class.class)
+ 		return 0;
  
--		spin_unlock_irqrestore(instance->host->host_lock, flags);
-+	if (megasas_issue_polled(instance, cmd)) {
-+		printk(KERN_ERR "megasas: Failed to init firmware\n");
-+		megasas_return_cmd(instance, cmd);
-+		goto fail_fw_init;
- 	}
+-	i = to_spi_internal(shost->transportt);
+-	
+-	return &i->t.host_attrs.ac == cont;
++	return &shost->transportt->host_attrs.ac == cont;
+ }
  
-+	megasas_return_cmd(instance, cmd);
-+
-+	return 0;
-+
-+fail_fw_init:
-+	return -EINVAL;
-+}
-+
-+/**
-+ * megasas_start_timer - Initializes a timer object
-+ * @instance:		Adapter soft state
-+ * @timer:		timer object to be initialized
-+ * @fn:			timer function
-+ * @interval:		time interval between timer function call
-+ */
-+static inline void
-+megasas_start_timer(struct megasas_instance *instance,
-+			struct timer_list *timer,
-+			void *fn, unsigned long interval)
-+{
-+	init_timer(timer);
-+	timer->expires = jiffies + interval;
-+	timer->data = (unsigned long)instance;
-+	timer->function = fn;
-+	add_timer(timer);
-+}
-+
-+/**
-+ * megasas_io_completion_timer - Timer fn
-+ * @instance_addr:	Address of adapter soft state
-+ *
-+ * Schedules tasklet for cmd completion
-+ * if poll_mode_io is set
-+ */
-+static void
-+megasas_io_completion_timer(unsigned long instance_addr)
-+{
-+	struct megasas_instance *instance =
-+			(struct megasas_instance *)instance_addr;
-+
-+	if (atomic_read(&instance->fw_outstanding))
-+		tasklet_schedule(&instance->isr_tasklet);
++static int spi_target_configure(struct transport_container *tc,
++				struct device *dev,
++				struct class_device *cdev);
 +
-+	/* Restart timer */
-+	if (poll_mode_io)
-+		mod_timer(&instance->io_completion_timer,
-+			jiffies + MEGASAS_COMPLETION_TIMER_INTERVAL);
+ static int spi_device_configure(struct transport_container *tc,
+ 				struct device *dev,
+ 				struct class_device *cdev)
+@@ -300,8 +298,10 @@ store_spi_transport_##field(struct class_device *cdev, const char *buf, \
+ 	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);	\
+ 	struct spi_internal *i = to_spi_internal(shost->transportt);	\
+ 									\
++	if (!i->f->set_##field)						\
++		return -EINVAL;						\
+ 	val = simple_strtoul(buf, NULL, 0);				\
+-	i->f->set_##field(starget, val);			\
++	i->f->set_##field(starget, val);				\
+ 	return count;							\
  }
  
- /**
-@@ -1814,22 +1958,15 @@ static int megasas_init_mfi(struct megasas_instance *instance)
- 	u32 reply_q_sz;
- 	u32 max_sectors_1;
- 	u32 max_sectors_2;
-+	u32 tmp_sectors;
- 	struct megasas_register_set __iomem *reg_set;
--
--	struct megasas_cmd *cmd;
- 	struct megasas_ctrl_info *ctrl_info;
--
--	struct megasas_init_frame *init_frame;
--	struct megasas_init_queue_info *initq_info;
--	dma_addr_t init_frame_h;
--	dma_addr_t initq_info_h;
--
- 	/*
- 	 * Map the message registers
- 	 */
- 	instance->base_addr = pci_resource_start(instance->pdev, 0);
- 
--	if (pci_request_regions(instance->pdev, "megasas: LSI Logic")) {
-+	if (pci_request_regions(instance->pdev, "megasas: LSI")) {
- 		printk(KERN_DEBUG "megasas: IO memory region busy!\n");
- 		return -EBUSY;
- 	}
-@@ -1900,52 +2037,8 @@ static int megasas_init_mfi(struct megasas_instance *instance)
- 		goto fail_reply_queue;
- 	}
- 
--	/*
--	 * Prepare a init frame. Note the init frame points to queue info
--	 * structure. Each frame has SGL allocated after first 64 bytes. For
--	 * this frame - since we don't need any SGL - we use SGL's space as
--	 * queue info structure
--	 *
--	 * We will not get a NULL command below. We just created the pool.
--	 */
--	cmd = megasas_get_cmd(instance);
--
--	init_frame = (struct megasas_init_frame *)cmd->frame;
--	initq_info = (struct megasas_init_queue_info *)
--	    ((unsigned long)init_frame + 64);
--
--	init_frame_h = cmd->frame_phys_addr;
--	initq_info_h = init_frame_h + 64;
--
--	memset(init_frame, 0, MEGAMFI_FRAME_SIZE);
--	memset(initq_info, 0, sizeof(struct megasas_init_queue_info));
--
--	initq_info->reply_queue_entries = instance->max_fw_cmds + 1;
--	initq_info->reply_queue_start_phys_addr_lo = instance->reply_queue_h;
--
--	initq_info->producer_index_phys_addr_lo = instance->producer_h;
--	initq_info->consumer_index_phys_addr_lo = instance->consumer_h;
--
--	init_frame->cmd = MFI_CMD_INIT;
--	init_frame->cmd_status = 0xFF;
--	init_frame->queue_info_new_phys_addr_lo = initq_info_h;
--
--	init_frame->data_xfer_len = sizeof(struct megasas_init_queue_info);
--
--	/*
--	 * disable the intr before firing the init frame to FW
--	 */
--	instance->instancet->disable_intr(instance->reg_set);
--
--	/*
--	 * Issue the init frame in polled mode
--	 */
--	if (megasas_issue_polled(instance, cmd)) {
--		printk(KERN_DEBUG "megasas: Failed to init firmware\n");
-+	if (megasas_issue_init_mfi(instance))
- 		goto fail_fw_init;
--	}
--
--	megasas_return_cmd(instance, cmd);
+@@ -317,6 +317,8 @@ store_spi_transport_##field(struct class_device *cdev, const char *buf, \
+ 	struct spi_transport_attrs *tp					\
+ 		= (struct spi_transport_attrs *)&starget->starget_data;	\
+ 									\
++	if (i->f->set_##field)						\
++		return -EINVAL;						\
+ 	val = simple_strtoul(buf, NULL, 0);				\
+ 	if (val > tp->max_##field)					\
+ 		val = tp->max_##field;					\
+@@ -327,14 +329,14 @@ store_spi_transport_##field(struct class_device *cdev, const char *buf, \
+ #define spi_transport_rd_attr(field, format_string)			\
+ 	spi_transport_show_function(field, format_string)		\
+ 	spi_transport_store_function(field, format_string)		\
+-static CLASS_DEVICE_ATTR(field, S_IRUGO | S_IWUSR,			\
++static CLASS_DEVICE_ATTR(field, S_IRUGO,				\
+ 			 show_spi_transport_##field,			\
+ 			 store_spi_transport_##field);
  
- 	ctrl_info = kmalloc(sizeof(struct megasas_ctrl_info), GFP_KERNEL);
+ #define spi_transport_simple_attr(field, format_string)			\
+ 	spi_transport_show_simple(field, format_string)			\
+ 	spi_transport_store_simple(field, format_string)		\
+-static CLASS_DEVICE_ATTR(field, S_IRUGO | S_IWUSR,			\
++static CLASS_DEVICE_ATTR(field, S_IRUGO,				\
+ 			 show_spi_transport_##field,			\
+ 			 store_spi_transport_##field);
  
-@@ -1958,17 +2051,20 @@ static int megasas_init_mfi(struct megasas_instance *instance)
- 	 * Note that older firmwares ( < FW ver 30) didn't report information
- 	 * to calculate max_sectors_1. So the number ended up as zero always.
- 	 */
-+	tmp_sectors = 0;
- 	if (ctrl_info && !megasas_get_ctrl_info(instance, ctrl_info)) {
+@@ -342,7 +344,7 @@ static CLASS_DEVICE_ATTR(field, S_IRUGO | S_IWUSR,			\
+ 	spi_transport_show_function(field, format_string)		\
+ 	spi_transport_store_max(field, format_string)			\
+ 	spi_transport_simple_attr(max_##field, format_string)		\
+-static CLASS_DEVICE_ATTR(field, S_IRUGO | S_IWUSR,			\
++static CLASS_DEVICE_ATTR(field, S_IRUGO,				\
+ 			 show_spi_transport_##field,			\
+ 			 store_spi_transport_##field);
  
- 		max_sectors_1 = (1 << ctrl_info->stripe_sz_ops.min) *
- 		    ctrl_info->max_strips_per_io;
- 		max_sectors_2 = ctrl_info->max_request_size;
+@@ -472,6 +474,9 @@ store_spi_transport_period(struct class_device *cdev, const char *buf,
+ 		(struct spi_transport_attrs *)&starget->starget_data;
+ 	int period, retval;
  
--		instance->max_sectors_per_req = (max_sectors_1 < max_sectors_2)
--		    ? max_sectors_1 : max_sectors_2;
--	} else
--		instance->max_sectors_per_req = instance->max_num_sge *
--		    PAGE_SIZE / 512;
-+		tmp_sectors = min_t(u32, max_sectors_1 , max_sectors_2);
-+	}
++	if (!i->f->set_period)
++		return -EINVAL;
 +
-+	instance->max_sectors_per_req = instance->max_num_sge *
-+						PAGE_SIZE / 512;
-+	if (tmp_sectors && (instance->max_sectors_per_req > tmp_sectors))
-+		instance->max_sectors_per_req = tmp_sectors;
+ 	retval = store_spi_transport_period_helper(cdev, buf, count, &period);
  
- 	kfree(ctrl_info);
+ 	if (period < tp->min_period)
+@@ -482,7 +487,7 @@ store_spi_transport_period(struct class_device *cdev, const char *buf,
+ 	return retval;
+ }
  
-@@ -1976,12 +2072,17 @@ static int megasas_init_mfi(struct megasas_instance *instance)
- 	* Setup tasklet for cmd completion
- 	*/
+-static CLASS_DEVICE_ATTR(period, S_IRUGO | S_IWUSR, 
++static CLASS_DEVICE_ATTR(period, S_IRUGO,
+ 			 show_spi_transport_period,
+ 			 store_spi_transport_period);
  
--        tasklet_init(&instance->isr_tasklet, megasas_complete_cmd_dpc,
--                        (unsigned long)instance);
-+	tasklet_init(&instance->isr_tasklet, megasas_complete_cmd_dpc,
-+		(unsigned long)instance);
-+
-+	/* Initialize the cmd completion timer */
-+	if (poll_mode_io)
-+		megasas_start_timer(instance, &instance->io_completion_timer,
-+				megasas_io_completion_timer,
-+				MEGASAS_COMPLETION_TIMER_INTERVAL);
- 	return 0;
+@@ -490,9 +495,14 @@ static ssize_t
+ show_spi_transport_min_period(struct class_device *cdev, char *buf)
+ {
+ 	struct scsi_target *starget = transport_class_to_starget(cdev);
++	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
++	struct spi_internal *i = to_spi_internal(shost->transportt);
+ 	struct spi_transport_attrs *tp =
+ 		(struct spi_transport_attrs *)&starget->starget_data;
  
-       fail_fw_init:
--	megasas_return_cmd(instance, cmd);
++	if (!i->f->set_period)
++		return -EINVAL;
++
+ 	return show_spi_transport_period_helper(buf, tp->min_period);
+ }
  
- 	pci_free_consistent(instance->pdev, reply_q_sz,
- 			    instance->reply_queue, instance->reply_queue_h);
-@@ -2263,6 +2364,28 @@ static int megasas_io_attach(struct megasas_instance *instance)
- 	return 0;
+@@ -509,7 +519,7 @@ store_spi_transport_min_period(struct class_device *cdev, const char *buf,
  }
  
-+static int
-+megasas_set_dma_mask(struct pci_dev *pdev)
-+{
-+	/*
-+	 * All our contollers are capable of performing 64-bit DMA
-+	 */
-+	if (IS_DMA64) {
-+		if (pci_set_dma_mask(pdev, DMA_64BIT_MASK) != 0) {
-+
-+			if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) != 0)
-+				goto fail_set_dma_mask;
-+		}
-+	} else {
-+		if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) != 0)
-+			goto fail_set_dma_mask;
-+	}
-+	return 0;
-+
-+fail_set_dma_mask:
-+	return 1;
-+}
-+
- /**
-  * megasas_probe_one -	PCI hotplug entry point
-  * @pdev:		PCI device structure
-@@ -2296,19 +2419,8 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
  
- 	pci_set_master(pdev);
+-static CLASS_DEVICE_ATTR(min_period, S_IRUGO | S_IWUSR, 
++static CLASS_DEVICE_ATTR(min_period, S_IRUGO,
+ 			 show_spi_transport_min_period,
+ 			 store_spi_transport_min_period);
  
--	/*
--	 * All our contollers are capable of performing 64-bit DMA
--	 */
--	if (IS_DMA64) {
--		if (pci_set_dma_mask(pdev, DMA_64BIT_MASK) != 0) {
--
--			if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) != 0)
--				goto fail_set_dma_mask;
--		}
--	} else {
--		if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) != 0)
--			goto fail_set_dma_mask;
--	}
-+	if (megasas_set_dma_mask(pdev))
-+		goto fail_set_dma_mask;
+@@ -531,12 +541,15 @@ static ssize_t store_spi_host_signalling(struct class_device *cdev,
+ 	struct spi_internal *i = to_spi_internal(shost->transportt);
+ 	enum spi_signal_type type = spi_signal_to_value(buf);
  
- 	host = scsi_host_alloc(&megasas_template,
- 			       sizeof(struct megasas_instance));
-@@ -2357,8 +2469,9 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
- 	init_waitqueue_head(&instance->abort_cmd_wait_q);
++	if (!i->f->set_signalling)
++		return -EINVAL;
++
+ 	if (type != SPI_SIGNAL_UNKNOWN)
+ 		i->f->set_signalling(shost, type);
  
- 	spin_lock_init(&instance->cmd_pool_lock);
-+	spin_lock_init(&instance->completion_lock);
+ 	return count;
+ }
+-static CLASS_DEVICE_ATTR(signalling, S_IRUGO | S_IWUSR,
++static CLASS_DEVICE_ATTR(signalling, S_IRUGO,
+ 			 show_spi_host_signalling,
+ 			 store_spi_host_signalling);
  
--	sema_init(&instance->aen_mutex, 1);
-+	mutex_init(&instance->aen_mutex);
- 	sema_init(&instance->ioctl_sem, MEGASAS_INT_CMDS);
+@@ -1262,35 +1275,6 @@ int spi_print_msg(const unsigned char *msg)
+ EXPORT_SYMBOL(spi_print_msg);
+ #endif /* ! CONFIG_SCSI_CONSTANTS */
  
- 	/*
-@@ -2490,8 +2603,10 @@ static void megasas_flush_cache(struct megasas_instance *instance)
- /**
-  * megasas_shutdown_controller -	Instructs FW to shutdown the controller
-  * @instance:				Adapter soft state
-+ * @opcode:				Shutdown/Hibernate
-  */
--static void megasas_shutdown_controller(struct megasas_instance *instance)
-+static void megasas_shutdown_controller(struct megasas_instance *instance,
-+					u32 opcode)
+-#define SETUP_ATTRIBUTE(field)						\
+-	i->private_attrs[count] = class_device_attr_##field;		\
+-	if (!i->f->set_##field) {					\
+-		i->private_attrs[count].attr.mode = S_IRUGO;		\
+-		i->private_attrs[count].store = NULL;			\
+-	}								\
+-	i->attrs[count] = &i->private_attrs[count];			\
+-	if (i->f->show_##field)						\
+-		count++
+-
+-#define SETUP_RELATED_ATTRIBUTE(field, rel_field)			\
+-	i->private_attrs[count] = class_device_attr_##field;		\
+-	if (!i->f->set_##rel_field) {					\
+-		i->private_attrs[count].attr.mode = S_IRUGO;		\
+-		i->private_attrs[count].store = NULL;			\
+-	}								\
+-	i->attrs[count] = &i->private_attrs[count];			\
+-	if (i->f->show_##rel_field)					\
+-		count++
+-
+-#define SETUP_HOST_ATTRIBUTE(field)					\
+-	i->private_host_attrs[count] = class_device_attr_##field;	\
+-	if (!i->f->set_##field) {					\
+-		i->private_host_attrs[count].attr.mode = S_IRUGO;	\
+-		i->private_host_attrs[count].store = NULL;		\
+-	}								\
+-	i->host_attrs[count] = &i->private_host_attrs[count];		\
+-	count++
+-
+ static int spi_device_match(struct attribute_container *cont,
+ 			    struct device *dev)
  {
- 	struct megasas_cmd *cmd;
- 	struct megasas_dcmd_frame *dcmd;
-@@ -2514,7 +2629,7 @@ static void megasas_shutdown_controller(struct megasas_instance *instance)
- 	dcmd->flags = MFI_FRAME_DIR_NONE;
- 	dcmd->timeout = 0;
- 	dcmd->data_xfer_len = 0;
--	dcmd->opcode = MR_DCMD_CTRL_SHUTDOWN;
-+	dcmd->opcode = opcode;
- 
- 	megasas_issue_blocked_cmd(instance, cmd);
+@@ -1343,16 +1327,156 @@ static DECLARE_TRANSPORT_CLASS(spi_transport_class,
+ 			       "spi_transport",
+ 			       spi_setup_transport_attrs,
+ 			       NULL,
+-			       NULL);
++			       spi_target_configure);
  
-@@ -2524,6 +2639,139 @@ static void megasas_shutdown_controller(struct megasas_instance *instance)
- }
+ static DECLARE_ANON_TRANSPORT_CLASS(spi_device_class,
+ 				    spi_device_match,
+ 				    spi_device_configure);
  
- /**
-+ * megasas_suspend -	driver suspend entry point
-+ * @pdev:		PCI device structure
-+ * @state:		PCI power state to suspend routine
-+ */
-+static int __devinit
-+megasas_suspend(struct pci_dev *pdev, pm_message_t state)
-+{
-+	struct Scsi_Host *host;
-+	struct megasas_instance *instance;
-+
-+	instance = pci_get_drvdata(pdev);
-+	host = instance->host;
-+
-+	if (poll_mode_io)
-+		del_timer_sync(&instance->io_completion_timer);
-+
-+	megasas_flush_cache(instance);
-+	megasas_shutdown_controller(instance, MR_DCMD_HIBERNATE_SHUTDOWN);
-+	tasklet_kill(&instance->isr_tasklet);
-+
-+	pci_set_drvdata(instance->pdev, instance);
-+	instance->instancet->disable_intr(instance->reg_set);
-+	free_irq(instance->pdev->irq, instance);
-+
-+	pci_save_state(pdev);
-+	pci_disable_device(pdev);
-+
-+	pci_set_power_state(pdev, pci_choose_state(pdev, state));
++static struct attribute *host_attributes[] = {
++	&class_device_attr_signalling.attr,
++	NULL
++};
 +
-+	return 0;
-+}
++static struct attribute_group host_attribute_group = {
++	.attrs = host_attributes,
++};
 +
-+/**
-+ * megasas_resume-      driver resume entry point
-+ * @pdev:               PCI device structure
-+ */
-+static int __devinit
-+megasas_resume(struct pci_dev *pdev)
++static int spi_host_configure(struct transport_container *tc,
++			      struct device *dev,
++			      struct class_device *cdev)
 +{
-+	int rval;
-+	struct Scsi_Host *host;
-+	struct megasas_instance *instance;
-+
-+	instance = pci_get_drvdata(pdev);
-+	host = instance->host;
-+	pci_set_power_state(pdev, PCI_D0);
-+	pci_enable_wake(pdev, PCI_D0, 0);
-+	pci_restore_state(pdev);
-+
-+	/*
-+	 * PCI prepping: enable device set bus mastering and dma mask
-+	 */
-+	rval = pci_enable_device(pdev);
-+
-+	if (rval) {
-+		printk(KERN_ERR "megasas: Enable device failed\n");
-+		return rval;
-+	}
-+
-+	pci_set_master(pdev);
-+
-+	if (megasas_set_dma_mask(pdev))
-+		goto fail_set_dma_mask;
-+
-+	/*
-+	 * Initialize MFI Firmware
-+	 */
-+
-+	*instance->producer = 0;
-+	*instance->consumer = 0;
-+
-+	atomic_set(&instance->fw_outstanding, 0);
-+
-+	/*
-+	 * We expect the FW state to be READY
-+	 */
-+	if (megasas_transition_to_ready(instance))
-+		goto fail_ready_state;
++	struct kobject *kobj = &cdev->kobj;
++	struct Scsi_Host *shost = transport_class_to_shost(cdev);
++	struct spi_internal *si = to_spi_internal(shost->transportt);
++	struct attribute *attr = &class_device_attr_signalling.attr;
++	int rc = 0;
 +
-+	if (megasas_issue_init_mfi(instance))
-+		goto fail_init_mfi;
++	if (si->f->set_signalling)
++		rc = sysfs_chmod_file(kobj, attr, attr->mode | S_IWUSR);
 +
-+	tasklet_init(&instance->isr_tasklet, megasas_complete_cmd_dpc,
-+			(unsigned long)instance);
++	return rc;
++}
 +
-+	/*
-+	 * Register IRQ
-+	 */
-+	if (request_irq(pdev->irq, megasas_isr, IRQF_SHARED,
-+		"megasas", instance)) {
-+		printk(KERN_ERR "megasas: Failed to register IRQ\n");
-+		goto fail_irq;
-+	}
++/* returns true if we should be showing the variable.  Also
++ * overloads the return by setting 1<<1 if the attribute should
++ * be writeable */
++#define TARGET_ATTRIBUTE_HELPER(name) \
++	(si->f->show_##name ? 1 : 0) + \
++	(si->f->set_##name ? 2 : 0)
 +
-+	instance->instancet->enable_intr(instance->reg_set);
++static int target_attribute_is_visible(struct kobject *kobj,
++				       struct attribute *attr, int i)
++{
++	struct class_device *cdev =
++		container_of(kobj, struct class_device, kobj);
++	struct scsi_target *starget = transport_class_to_starget(cdev);
++	struct Scsi_Host *shost = transport_class_to_shost(cdev);
++	struct spi_internal *si = to_spi_internal(shost->transportt);
 +
-+	/*
-+	 * Initiate AEN (Asynchronous Event Notification)
-+	 */
-+	if (megasas_start_aen(instance))
-+		printk(KERN_ERR "megasas: Start AEN failed\n");
++	if (attr == &class_device_attr_period.attr &&
++	    spi_support_sync(starget))
++		return TARGET_ATTRIBUTE_HELPER(period);
++	else if (attr == &class_device_attr_min_period.attr &&
++		 spi_support_sync(starget))
++		return TARGET_ATTRIBUTE_HELPER(period);
++	else if (attr == &class_device_attr_offset.attr &&
++		 spi_support_sync(starget))
++		return TARGET_ATTRIBUTE_HELPER(offset);
++	else if (attr == &class_device_attr_max_offset.attr &&
++		 spi_support_sync(starget))
++		return TARGET_ATTRIBUTE_HELPER(offset);
++	else if (attr == &class_device_attr_width.attr &&
++		 spi_support_wide(starget))
++		return TARGET_ATTRIBUTE_HELPER(width);
++	else if (attr == &class_device_attr_max_width.attr &&
++		 spi_support_wide(starget))
++		return TARGET_ATTRIBUTE_HELPER(width);
++	else if (attr == &class_device_attr_iu.attr &&
++		 spi_support_ius(starget))
++		return TARGET_ATTRIBUTE_HELPER(iu);
++	else if (attr == &class_device_attr_dt.attr &&
++		 spi_support_dt(starget))
++		return TARGET_ATTRIBUTE_HELPER(dt);
++	else if (attr == &class_device_attr_qas.attr &&
++		 spi_support_qas(starget))
++		return TARGET_ATTRIBUTE_HELPER(qas);
++	else if (attr == &class_device_attr_wr_flow.attr &&
++		 spi_support_ius(starget))
++		return TARGET_ATTRIBUTE_HELPER(wr_flow);
++	else if (attr == &class_device_attr_rd_strm.attr &&
++		 spi_support_ius(starget))
++		return TARGET_ATTRIBUTE_HELPER(rd_strm);
++	else if (attr == &class_device_attr_rti.attr &&
++		 spi_support_ius(starget))
++		return TARGET_ATTRIBUTE_HELPER(rti);
++	else if (attr == &class_device_attr_pcomp_en.attr &&
++		 spi_support_ius(starget))
++		return TARGET_ATTRIBUTE_HELPER(pcomp_en);
++	else if (attr == &class_device_attr_hold_mcs.attr &&
++		 spi_support_ius(starget))
++		return TARGET_ATTRIBUTE_HELPER(hold_mcs);
++	else if (attr == &class_device_attr_revalidate.attr)
++		return 1;
 +
-+	/* Initialize the cmd completion timer */
-+	if (poll_mode_io)
-+		megasas_start_timer(instance, &instance->io_completion_timer,
-+				megasas_io_completion_timer,
-+				MEGASAS_COMPLETION_TIMER_INTERVAL);
 +	return 0;
-+
-+fail_irq:
-+fail_init_mfi:
-+	if (instance->evt_detail)
-+		pci_free_consistent(pdev, sizeof(struct megasas_evt_detail),
-+				instance->evt_detail,
-+				instance->evt_detail_h);
-+
-+	if (instance->producer)
-+		pci_free_consistent(pdev, sizeof(u32), instance->producer,
-+				instance->producer_h);
-+	if (instance->consumer)
-+		pci_free_consistent(pdev, sizeof(u32), instance->consumer,
-+				instance->consumer_h);
-+	scsi_host_put(host);
-+
-+fail_set_dma_mask:
-+fail_ready_state:
-+
-+	pci_disable_device(pdev);
-+
-+	return -ENODEV;
 +}
 +
-+/**
-  * megasas_detach_one -	PCI hot"un"plug entry point
-  * @pdev:		PCI device structure
-  */
-@@ -2536,9 +2784,12 @@ static void megasas_detach_one(struct pci_dev *pdev)
- 	instance = pci_get_drvdata(pdev);
- 	host = instance->host;
- 
-+	if (poll_mode_io)
-+		del_timer_sync(&instance->io_completion_timer);
-+
- 	scsi_remove_host(instance->host);
- 	megasas_flush_cache(instance);
--	megasas_shutdown_controller(instance);
-+	megasas_shutdown_controller(instance, MR_DCMD_CTRL_SHUTDOWN);
- 	tasklet_kill(&instance->isr_tasklet);
- 
- 	/*
-@@ -2660,6 +2911,7 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance,
- 	void *sense = NULL;
- 	dma_addr_t sense_handle;
- 	u32 *sense_ptr;
-+	unsigned long *sense_buff;
- 
- 	memset(kbuff_arr, 0, sizeof(kbuff_arr));
- 
-@@ -2764,14 +3016,16 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance,
- 	 */
- 	if (ioc->sense_len) {
- 		/*
--		 * sense_ptr points to the location that has the user
-+		 * sense_buff points to the location that has the user
- 		 * sense buffer address
- 		 */
--		sense_ptr = (u32 *) ((unsigned long)ioc->frame.raw +
--				     ioc->sense_off);
-+		sense_buff = (unsigned long *) ((unsigned long)ioc->frame.raw +
-+								ioc->sense_off);
- 
--		if (copy_to_user((void __user *)((unsigned long)(*sense_ptr)),
--				 sense, ioc->sense_len)) {
-+		if (copy_to_user((void __user *)(unsigned long)(*sense_buff),
-+				sense, ioc->sense_len)) {
-+			printk(KERN_ERR "megasas: Failed to copy out to user "
-+					"sense data\n");
- 			error = -EFAULT;
- 			goto out;
- 		}
-@@ -2874,10 +3128,10 @@ static int megasas_mgmt_ioctl_aen(struct file *file, unsigned long arg)
- 	if (!instance)
- 		return -ENODEV;
- 
--	down(&instance->aen_mutex);
-+	mutex_lock(&instance->aen_mutex);
- 	error = megasas_register_aen(instance, aen.seq_num,
- 				     aen.class_locale_word);
--	up(&instance->aen_mutex);
-+	mutex_unlock(&instance->aen_mutex);
- 	return error;
- }
- 
-@@ -2977,6 +3231,8 @@ static struct pci_driver megasas_pci_driver = {
- 	.id_table = megasas_pci_table,
- 	.probe = megasas_probe_one,
- 	.remove = __devexit_p(megasas_detach_one),
-+	.suspend = megasas_suspend,
-+	.resume = megasas_resume,
- 	.shutdown = megasas_shutdown,
- };
- 
-@@ -3004,7 +3260,7 @@ static DRIVER_ATTR(release_date, S_IRUGO, megasas_sysfs_show_release_date,
- static ssize_t
- megasas_sysfs_show_dbg_lvl(struct device_driver *dd, char *buf)
- {
--	return sprintf(buf,"%u",megasas_dbg_lvl);
-+	return sprintf(buf, "%u\n", megasas_dbg_lvl);
- }
- 
- static ssize_t
-@@ -3019,7 +3275,65 @@ megasas_sysfs_set_dbg_lvl(struct device_driver *dd, const char *buf, size_t coun
- }
- 
- static DRIVER_ATTR(dbg_lvl, S_IRUGO|S_IWUGO, megasas_sysfs_show_dbg_lvl,
--		   megasas_sysfs_set_dbg_lvl);
-+		megasas_sysfs_set_dbg_lvl);
++static struct attribute *target_attributes[] = {
++	&class_device_attr_period.attr,
++	&class_device_attr_min_period.attr,
++	&class_device_attr_offset.attr,
++	&class_device_attr_max_offset.attr,
++	&class_device_attr_width.attr,
++	&class_device_attr_max_width.attr,
++	&class_device_attr_iu.attr,
++	&class_device_attr_dt.attr,
++	&class_device_attr_qas.attr,
++	&class_device_attr_wr_flow.attr,
++	&class_device_attr_rd_strm.attr,
++	&class_device_attr_rti.attr,
++	&class_device_attr_pcomp_en.attr,
++	&class_device_attr_hold_mcs.attr,
++	&class_device_attr_revalidate.attr,
++	NULL
++};
 +
-+static ssize_t
-+megasas_sysfs_show_poll_mode_io(struct device_driver *dd, char *buf)
-+{
-+	return sprintf(buf, "%u\n", poll_mode_io);
-+}
++static struct attribute_group target_attribute_group = {
++	.attrs = target_attributes,
++	.is_visible = target_attribute_is_visible,
++};
 +
-+static ssize_t
-+megasas_sysfs_set_poll_mode_io(struct device_driver *dd,
-+				const char *buf, size_t count)
++static int spi_target_configure(struct transport_container *tc,
++				struct device *dev,
++				struct class_device *cdev)
 +{
-+	int retval = count;
-+	int tmp = poll_mode_io;
-+	int i;
-+	struct megasas_instance *instance;
-+
-+	if (sscanf(buf, "%u", &poll_mode_io) < 1) {
-+		printk(KERN_ERR "megasas: could not set poll_mode_io\n");
-+		retval = -EINVAL;
-+	}
++	struct kobject *kobj = &cdev->kobj;
++	int i;
++	struct attribute *attr;
++	int rc;
 +
-+	/*
-+	 * Check if poll_mode_io is already set or is same as previous value
-+	 */
-+	if ((tmp && poll_mode_io) || (tmp == poll_mode_io))
-+		goto out;
++	for (i = 0; (attr = target_attributes[i]) != NULL; i++) {
++		int j = target_attribute_group.is_visible(kobj, attr, i);
 +
-+	if (poll_mode_io) {
-+		/*
-+		 * Start timers for all adapters
-+		 */
-+		for (i = 0; i < megasas_mgmt_info.max_index; i++) {
-+			instance = megasas_mgmt_info.instance[i];
-+			if (instance) {
-+				megasas_start_timer(instance,
-+					&instance->io_completion_timer,
-+					megasas_io_completion_timer,
-+					MEGASAS_COMPLETION_TIMER_INTERVAL);
-+			}
-+		}
-+	} else {
-+		/*
-+		 * Delete timers for all adapters
-+		 */
-+		for (i = 0; i < megasas_mgmt_info.max_index; i++) {
-+			instance = megasas_mgmt_info.instance[i];
-+			if (instance)
-+				del_timer_sync(&instance->io_completion_timer);
-+		}
++		/* FIXME: as well as returning -EEXIST, which we'd like
++		 * to ignore, sysfs also does a WARN_ON and dumps a trace,
++		 * which is bad, so temporarily, skip attributes that are
++		 * already visible (the revalidate one) */
++		if (j && attr != &class_device_attr_revalidate.attr)
++			rc = sysfs_add_file_to_group(kobj, attr,
++						target_attribute_group.name);
++		/* and make the attribute writeable if we have a set
++		 * function */
++		if ((j & 1))
++			rc = sysfs_chmod_file(kobj, attr, attr->mode | S_IWUSR);
 +	}
 +
-+out:
-+	return retval;
++	return 0;
 +}
 +
-+static DRIVER_ATTR(poll_mode_io, S_IRUGO|S_IWUGO,
-+		megasas_sysfs_show_poll_mode_io,
-+		megasas_sysfs_set_poll_mode_io);
- 
- /**
-  * megasas_init - Driver load entry point
-@@ -3070,8 +3384,16 @@ static int __init megasas_init(void)
- 				  &driver_attr_dbg_lvl);
- 	if (rval)
- 		goto err_dcf_dbg_lvl;
-+	rval = driver_create_file(&megasas_pci_driver.driver,
-+				  &driver_attr_poll_mode_io);
-+	if (rval)
-+		goto err_dcf_poll_mode_io;
- 
- 	return rval;
-+
-+err_dcf_poll_mode_io:
-+	driver_remove_file(&megasas_pci_driver.driver,
-+			   &driver_attr_dbg_lvl);
- err_dcf_dbg_lvl:
- 	driver_remove_file(&megasas_pci_driver.driver,
- 			   &driver_attr_release_date);
-@@ -3090,6 +3412,8 @@ err_pcidrv:
- static void __exit megasas_exit(void)
+ struct scsi_transport_template *
+ spi_attach_transport(struct spi_function_template *ft)
  {
- 	driver_remove_file(&megasas_pci_driver.driver,
-+			   &driver_attr_poll_mode_io);
-+	driver_remove_file(&megasas_pci_driver.driver,
- 			   &driver_attr_dbg_lvl);
- 	driver_remove_file(&megasas_pci_driver.driver,
- 			   &driver_attr_release_date);
-diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h
-index 4dffc91..6466bdf 100644
---- a/drivers/scsi/megaraid/megaraid_sas.h
-+++ b/drivers/scsi/megaraid/megaraid_sas.h
-@@ -2,7 +2,7 @@
-  *
-  *		Linux MegaRAID driver for SAS based RAID controllers
-  *
-- * Copyright (c) 2003-2005  LSI Logic Corporation.
-+ * Copyright (c) 2003-2005  LSI Corporation.
-  *
-  *		This program is free software; you can redistribute it and/or
-  *		modify it under the terms of the GNU General Public License
-@@ -18,9 +18,9 @@
- /*
-  * MegaRAID SAS Driver meta data
-  */
--#define MEGASAS_VERSION				"00.00.03.10-rc5"
--#define MEGASAS_RELDATE				"May 17, 2007"
--#define MEGASAS_EXT_VERSION			"Thu May 17 10:09:32 PDT 2007"
-+#define MEGASAS_VERSION				"00.00.03.16-rc1"
-+#define MEGASAS_RELDATE				"Nov. 07, 2007"
-+#define MEGASAS_EXT_VERSION			"Thu. Nov. 07 10:09:32 PDT 2007"
- 
- /*
-  * Device IDs
-@@ -117,6 +117,7 @@
- #define MR_FLUSH_DISK_CACHE			0x02
- 
- #define MR_DCMD_CTRL_SHUTDOWN			0x01050000
-+#define MR_DCMD_HIBERNATE_SHUTDOWN		0x01060000
- #define MR_ENABLE_DRIVE_SPINDOWN		0x01
- 
- #define MR_DCMD_CTRL_EVENT_GET_INFO		0x01040100
-@@ -570,7 +571,8 @@ struct megasas_ctrl_info {
- #define IS_DMA64				(sizeof(dma_addr_t) == 8)
- 
- #define MFI_OB_INTR_STATUS_MASK			0x00000002
--#define MFI_POLL_TIMEOUT_SECS			10
-+#define MFI_POLL_TIMEOUT_SECS			60
-+#define MEGASAS_COMPLETION_TIMER_INTERVAL      (HZ/10)
- 
- #define MFI_REPLY_1078_MESSAGE_INTERRUPT	0x80000000
- 
-@@ -1083,13 +1085,15 @@ struct megasas_instance {
- 	struct megasas_cmd **cmd_list;
- 	struct list_head cmd_pool;
- 	spinlock_t cmd_pool_lock;
-+	/* used to synch producer, consumer ptrs in dpc */
-+	spinlock_t completion_lock;
- 	struct dma_pool *frame_dma_pool;
- 	struct dma_pool *sense_dma_pool;
+-	int count = 0;
+ 	struct spi_internal *i = kzalloc(sizeof(struct spi_internal),
+ 					 GFP_KERNEL);
  
- 	struct megasas_evt_detail *evt_detail;
- 	dma_addr_t evt_detail_h;
- 	struct megasas_cmd *aen_cmd;
--	struct semaphore aen_mutex;
-+	struct mutex aen_mutex;
- 	struct semaphore ioctl_sem;
+@@ -1360,47 +1484,17 @@ spi_attach_transport(struct spi_function_template *ft)
+ 		return NULL;
  
- 	struct Scsi_Host *host;
-@@ -1108,6 +1112,8 @@ struct megasas_instance {
+ 	i->t.target_attrs.ac.class = &spi_transport_class.class;
+-	i->t.target_attrs.ac.attrs = &i->attrs[0];
++	i->t.target_attrs.ac.grp = &target_attribute_group;
+ 	i->t.target_attrs.ac.match = spi_target_match;
+ 	transport_container_register(&i->t.target_attrs);
+ 	i->t.target_size = sizeof(struct spi_transport_attrs);
+ 	i->t.host_attrs.ac.class = &spi_host_class.class;
+-	i->t.host_attrs.ac.attrs = &i->host_attrs[0];
++	i->t.host_attrs.ac.grp = &host_attribute_group;
+ 	i->t.host_attrs.ac.match = spi_host_match;
+ 	transport_container_register(&i->t.host_attrs);
+ 	i->t.host_size = sizeof(struct spi_host_attrs);
+ 	i->f = ft;
  
- 	u8 flag;
- 	unsigned long last_time;
-+
-+	struct timer_list io_completion_timer;
- };
+-	SETUP_ATTRIBUTE(period);
+-	SETUP_RELATED_ATTRIBUTE(min_period, period);
+-	SETUP_ATTRIBUTE(offset);
+-	SETUP_RELATED_ATTRIBUTE(max_offset, offset);
+-	SETUP_ATTRIBUTE(width);
+-	SETUP_RELATED_ATTRIBUTE(max_width, width);
+-	SETUP_ATTRIBUTE(iu);
+-	SETUP_ATTRIBUTE(dt);
+-	SETUP_ATTRIBUTE(qas);
+-	SETUP_ATTRIBUTE(wr_flow);
+-	SETUP_ATTRIBUTE(rd_strm);
+-	SETUP_ATTRIBUTE(rti);
+-	SETUP_ATTRIBUTE(pcomp_en);
+-	SETUP_ATTRIBUTE(hold_mcs);
+-
+-	/* if you add an attribute but forget to increase SPI_NUM_ATTRS
+-	 * this bug will trigger */
+-	BUG_ON(count > SPI_NUM_ATTRS);
+-
+-	i->attrs[count++] = &class_device_attr_revalidate;
+-
+-	i->attrs[count] = NULL;
+-
+-	count = 0;
+-	SETUP_HOST_ATTRIBUTE(signalling);
+-
+-	BUG_ON(count > SPI_HOST_ATTRS);
+-
+-	i->host_attrs[count] = NULL;
+-
+ 	return &i->t;
+ }
+ EXPORT_SYMBOL(spi_attach_transport);
+diff --git a/drivers/scsi/scsi_transport_srp.c b/drivers/scsi/scsi_transport_srp.c
+index 65c584d..2445c98 100644
+--- a/drivers/scsi/scsi_transport_srp.c
++++ b/drivers/scsi/scsi_transport_srp.c
+@@ -185,11 +185,10 @@ static int srp_host_match(struct attribute_container *cont, struct device *dev)
  
- #define MEGASAS_IS_LOGICAL(scp)						\
-diff --git a/drivers/scsi/ncr53c8xx.c b/drivers/scsi/ncr53c8xx.c
-index 016c462..c02771a 100644
---- a/drivers/scsi/ncr53c8xx.c
-+++ b/drivers/scsi/ncr53c8xx.c
-@@ -4963,7 +4963,8 @@ void ncr_complete (struct ncb *np, struct ccb *cp)
- 		**	Copy back sense data to caller's buffer.
- 		*/
- 		memcpy(cmd->sense_buffer, cp->sense_buf,
--		       min(sizeof(cmd->sense_buffer), sizeof(cp->sense_buf)));
-+		       min_t(size_t, SCSI_SENSE_BUFFERSIZE,
-+			     sizeof(cp->sense_buf)));
+ /**
+  * srp_rport_add - add a SRP remote port to the device hierarchy
+- *
+  * @shost:	scsi host the remote port is connected to.
+  * @ids:	The port id for the remote port.
+  *
+- * publishes a port to the rest of the system
++ * Publishes a port to the rest of the system.
+  */
+ struct srp_rport *srp_rport_add(struct Scsi_Host *shost,
+ 				struct srp_rport_identifiers *ids)
+@@ -242,8 +241,8 @@ struct srp_rport *srp_rport_add(struct Scsi_Host *shost,
+ EXPORT_SYMBOL_GPL(srp_rport_add);
  
- 		if (DEBUG_FLAGS & (DEBUG_RESULT|DEBUG_TINY)) {
- 			u_char * p = (u_char*) & cmd->sense_buffer;
-diff --git a/drivers/scsi/pcmcia/Kconfig b/drivers/scsi/pcmcia/Kconfig
-index fa481b5..53857c6 100644
---- a/drivers/scsi/pcmcia/Kconfig
-+++ b/drivers/scsi/pcmcia/Kconfig
-@@ -6,7 +6,8 @@ menuconfig SCSI_LOWLEVEL_PCMCIA
- 	bool "PCMCIA SCSI adapter support"
- 	depends on SCSI!=n && PCMCIA!=n
+ /**
+- * srp_rport_del  --  remove a SRP remote port
+- * @port:	SRP remote port to remove
++ * srp_rport_del  -  remove a SRP remote port
++ * @rport:	SRP remote port to remove
+  *
+  * Removes the specified SRP remote port.
+  */
+@@ -271,7 +270,7 @@ static int do_srp_rport_del(struct device *dev, void *data)
+ }
  
--if SCSI_LOWLEVEL_PCMCIA && SCSI && PCMCIA
-+# drivers have problems when build in, so require modules
-+if SCSI_LOWLEVEL_PCMCIA && SCSI && PCMCIA && m
+ /**
+- * srp_remove_host  --  tear down a Scsi_Host's SRP data structures
++ * srp_remove_host  -  tear down a Scsi_Host's SRP data structures
+  * @shost:	Scsi Host that is torn down
+  *
+  * Removes all SRP remote ports for a given Scsi_Host.
+@@ -297,7 +296,7 @@ static int srp_it_nexus_response(struct Scsi_Host *shost, u64 nexus, int result)
+ }
  
- config PCMCIA_AHA152X
- 	tristate "Adaptec AHA152X PCMCIA support"
-diff --git a/drivers/scsi/pcmcia/nsp_cs.c b/drivers/scsi/pcmcia/nsp_cs.c
-index a45d89b..5082ca3 100644
---- a/drivers/scsi/pcmcia/nsp_cs.c
-+++ b/drivers/scsi/pcmcia/nsp_cs.c
-@@ -135,6 +135,11 @@ static nsp_hw_data nsp_data_base; /* attach <-> detect glue */
+ /**
+- * srp_attach_transport  --  instantiate SRP transport template
++ * srp_attach_transport  -  instantiate SRP transport template
+  * @ft:		SRP transport class function template
+  */
+ struct scsi_transport_template *
+@@ -337,7 +336,7 @@ srp_attach_transport(struct srp_function_template *ft)
+ EXPORT_SYMBOL_GPL(srp_attach_transport);
  
- #define NSP_DEBUG_BUF_LEN		150
+ /**
+- * srp_release_transport  --  release SRP transport template instance
++ * srp_release_transport  -  release SRP transport template instance
+  * @t:		transport template instance
+  */
+ void srp_release_transport(struct scsi_transport_template *t)
+diff --git a/drivers/scsi/scsicam.c b/drivers/scsi/scsicam.c
+index cd68a66..3f21bc6 100644
+--- a/drivers/scsi/scsicam.c
++++ b/drivers/scsi/scsicam.c
+@@ -24,6 +24,14 @@
+ static int setsize(unsigned long capacity, unsigned int *cyls, unsigned int *hds,
+ 		   unsigned int *secs);
  
-+static inline void nsp_inc_resid(struct scsi_cmnd *SCpnt, int residInc)
-+{
-+	scsi_set_resid(SCpnt, scsi_get_resid(SCpnt) + residInc);
-+}
-+
- static void nsp_cs_message(const char *func, int line, char *type, char *fmt, ...)
++/**
++ * scsi_bios_ptable - Read PC partition table out of first sector of device.
++ * @dev: from this device
++ *
++ * Description: Reads the first sector from the device and returns %0x42 bytes
++ *              starting at offset %0x1be.
++ * Returns: partition table in kmalloc(GFP_KERNEL) memory, or NULL on error.
++ */
+ unsigned char *scsi_bios_ptable(struct block_device *dev)
  {
- 	va_list args;
-@@ -192,8 +197,10 @@ static int nsp_queuecommand(struct scsi_cmnd *SCpnt,
- #endif
- 	nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
- 
--	nsp_dbg(NSP_DEBUG_QUEUECOMMAND, "SCpnt=0x%p target=%d lun=%d buff=0x%p bufflen=%d use_sg=%d",
--		   SCpnt, target, SCpnt->device->lun, SCpnt->request_buffer, SCpnt->request_bufflen, SCpnt->use_sg);
-+	nsp_dbg(NSP_DEBUG_QUEUECOMMAND,
-+		"SCpnt=0x%p target=%d lun=%d sglist=0x%p bufflen=%d sg_count=%d",
-+		SCpnt, target, SCpnt->device->lun, scsi_sglist(SCpnt),
-+		scsi_bufflen(SCpnt), scsi_sg_count(SCpnt));
- 	//nsp_dbg(NSP_DEBUG_QUEUECOMMAND, "before CurrentSC=0x%p", data->CurrentSC);
- 
- 	SCpnt->scsi_done	= done;
-@@ -225,7 +232,7 @@ static int nsp_queuecommand(struct scsi_cmnd *SCpnt,
- 	SCpnt->SCp.have_data_in = IO_UNKNOWN;
- 	SCpnt->SCp.sent_command = 0;
- 	SCpnt->SCp.phase	= PH_UNDETERMINED;
--	SCpnt->resid	        = SCpnt->request_bufflen;
-+	scsi_set_resid(SCpnt, scsi_bufflen(SCpnt));
- 
- 	/* setup scratch area
- 	   SCp.ptr		: buffer pointer
-@@ -233,14 +240,14 @@ static int nsp_queuecommand(struct scsi_cmnd *SCpnt,
- 	   SCp.buffer		: next buffer
- 	   SCp.buffers_residual : left buffers in list
- 	   SCp.phase		: current state of the command */
--	if (SCpnt->use_sg) {
--		SCpnt->SCp.buffer	    = (struct scatterlist *) SCpnt->request_buffer;
-+	if (scsi_bufflen(SCpnt)) {
-+		SCpnt->SCp.buffer	    = scsi_sglist(SCpnt);
- 		SCpnt->SCp.ptr		    = BUFFER_ADDR;
- 		SCpnt->SCp.this_residual    = SCpnt->SCp.buffer->length;
--		SCpnt->SCp.buffers_residual = SCpnt->use_sg - 1;
-+		SCpnt->SCp.buffers_residual = scsi_sg_count(SCpnt) - 1;
- 	} else {
--		SCpnt->SCp.ptr		    = (char *) SCpnt->request_buffer;
--		SCpnt->SCp.this_residual    = SCpnt->request_bufflen;
-+		SCpnt->SCp.ptr		    = NULL;
-+		SCpnt->SCp.this_residual    = 0;
- 		SCpnt->SCp.buffer	    = NULL;
- 		SCpnt->SCp.buffers_residual = 0;
- 	}
-@@ -721,7 +728,9 @@ static void nsp_pio_read(struct scsi_cmnd *SCpnt)
- 	ocount = data->FifoCount;
- 
- 	nsp_dbg(NSP_DEBUG_DATA_IO, "in SCpnt=0x%p resid=%d ocount=%d ptr=0x%p this_residual=%d buffers=0x%p nbuf=%d",
--		SCpnt, SCpnt->resid, ocount, SCpnt->SCp.ptr, SCpnt->SCp.this_residual, SCpnt->SCp.buffer, SCpnt->SCp.buffers_residual);
-+		SCpnt, scsi_get_resid(SCpnt), ocount, SCpnt->SCp.ptr,
-+		SCpnt->SCp.this_residual, SCpnt->SCp.buffer,
-+		SCpnt->SCp.buffers_residual);
+ 	unsigned char *res = kmalloc(66, GFP_KERNEL);
+@@ -43,15 +51,17 @@ unsigned char *scsi_bios_ptable(struct block_device *dev)
+ }
+ EXPORT_SYMBOL(scsi_bios_ptable);
  
- 	time_out = 1000;
+-/*
+- * Function : int scsicam_bios_param (struct block_device *bdev, ector_t capacity, int *ip)
++/**
++ * scsicam_bios_param - Determine geometry of a disk in cylinders/heads/sectors.
++ * @bdev: which device
++ * @capacity: size of the disk in sectors
++ * @ip: return value: ip[0]=heads, ip[1]=sectors, ip[2]=cylinders
+  *
+- * Purpose : to determine the BIOS mapping used for a drive in a 
++ * Description : determine the BIOS mapping/geometry used for a drive in a
+  *      SCSI-CAM system, storing the results in ip as required
+  *      by the HDIO_GETGEO ioctl().
+  *
+  * Returns : -1 on failure, 0 on success.
+- *
+  */
  
-@@ -771,7 +780,7 @@ static void nsp_pio_read(struct scsi_cmnd *SCpnt)
- 			return;
- 		}
+ int scsicam_bios_param(struct block_device *bdev, sector_t capacity, int *ip)
+@@ -98,15 +108,18 @@ int scsicam_bios_param(struct block_device *bdev, sector_t capacity, int *ip)
+ }
+ EXPORT_SYMBOL(scsicam_bios_param);
  
--		SCpnt->resid	       	 -= res;
-+		nsp_inc_resid(SCpnt, -res);
- 		SCpnt->SCp.ptr		 += res;
- 		SCpnt->SCp.this_residual -= res;
- 		ocount			 += res;
-@@ -795,10 +804,12 @@ static void nsp_pio_read(struct scsi_cmnd *SCpnt)
+-/*
+- * Function : static int scsi_partsize(unsigned char *buf, unsigned long 
+- *     capacity,unsigned int *cyls, unsigned int *hds, unsigned int *secs);
++/**
++ * scsi_partsize - Parse cylinders/heads/sectors from PC partition table
++ * @buf: partition table, see scsi_bios_ptable()
++ * @capacity: size of the disk in sectors
++ * @cyls: put cylinders here
++ * @hds: put heads here
++ * @secs: put sectors here
+  *
+- * Purpose : to determine the BIOS mapping used to create the partition
++ * Description: determine the BIOS mapping/geometry used to create the partition
+  *      table, storing the results in *cyls, *hds, and *secs 
+  *
+- * Returns : -1 on failure, 0 on success.
+- *
++ * Returns: -1 on failure, 0 on success.
+  */
  
- 	if (time_out == 0) {
- 		nsp_msg(KERN_DEBUG, "pio read timeout resid=%d this_residual=%d buffers_residual=%d",
--			SCpnt->resid, SCpnt->SCp.this_residual, SCpnt->SCp.buffers_residual);
-+			scsi_get_resid(SCpnt), SCpnt->SCp.this_residual,
-+			SCpnt->SCp.buffers_residual);
+ int scsi_partsize(unsigned char *buf, unsigned long capacity,
+@@ -194,7 +207,7 @@ EXPORT_SYMBOL(scsi_partsize);
+  *
+  * WORKING                                                    X3T9.2
+  * DRAFT                                                        792D
+- *
++ * see http://www.t10.org/ftp/t10/drafts/cam/cam-r12b.pdf
+  *
+  *                                                        Revision 6
+  *                                                         10-MAR-94
+diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
+index a69b155..24eba31 100644
+--- a/drivers/scsi/sd.c
++++ b/drivers/scsi/sd.c
+@@ -395,6 +395,15 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq)
+ 		goto out;
  	}
- 	nsp_dbg(NSP_DEBUG_DATA_IO, "read ocount=0x%x", ocount);
--	nsp_dbg(NSP_DEBUG_DATA_IO, "r cmd=%d resid=0x%x\n", data->CmdId, SCpnt->resid);
-+	nsp_dbg(NSP_DEBUG_DATA_IO, "r cmd=%d resid=0x%x\n", data->CmdId,
-+	                                                scsi_get_resid(SCpnt));
- }
  
- /*
-@@ -816,7 +827,9 @@ static void nsp_pio_write(struct scsi_cmnd *SCpnt)
- 	ocount	 = data->FifoCount;
++	/*
++	 * Some devices (some sdcards for one) don't like it if the
++	 * last sector gets read in a larger then 1 sector read.
++	 */
++	if (unlikely(sdp->last_sector_bug &&
++	    rq->nr_sectors > sdp->sector_size / 512 &&
++	    block + this_count == get_capacity(disk)))
++		this_count -= sdp->sector_size / 512;
++
+ 	SCSI_LOG_HLQUEUE(2, scmd_printk(KERN_INFO, SCpnt, "block=%llu\n",
+ 					(unsigned long long)block));
  
- 	nsp_dbg(NSP_DEBUG_DATA_IO, "in fifocount=%d ptr=0x%p this_residual=%d buffers=0x%p nbuf=%d resid=0x%x",
--		data->FifoCount, SCpnt->SCp.ptr, SCpnt->SCp.this_residual, SCpnt->SCp.buffer, SCpnt->SCp.buffers_residual, SCpnt->resid);
-+		data->FifoCount, SCpnt->SCp.ptr, SCpnt->SCp.this_residual,
-+		SCpnt->SCp.buffer, SCpnt->SCp.buffers_residual,
-+		scsi_get_resid(SCpnt));
+@@ -736,6 +745,7 @@ static int sd_media_changed(struct gendisk *disk)
+ {
+ 	struct scsi_disk *sdkp = scsi_disk(disk);
+ 	struct scsi_device *sdp = sdkp->device;
++	struct scsi_sense_hdr *sshdr = NULL;
+ 	int retval;
  
- 	time_out = 1000;
+ 	SCSI_LOG_HLQUEUE(3, sd_printk(KERN_INFO, sdkp, "sd_media_changed\n"));
+@@ -749,8 +759,11 @@ static int sd_media_changed(struct gendisk *disk)
+ 	 * can deal with it then.  It is only because of unrecoverable errors
+ 	 * that we would ever take a device offline in the first place.
+ 	 */
+-	if (!scsi_device_online(sdp))
+-		goto not_present;
++	if (!scsi_device_online(sdp)) {
++		set_media_not_present(sdkp);
++		retval = 1;
++		goto out;
++	}
  
-@@ -830,7 +843,7 @@ static void nsp_pio_write(struct scsi_cmnd *SCpnt)
+ 	/*
+ 	 * Using TEST_UNIT_READY enables differentiation between drive with
+@@ -762,8 +775,12 @@ static int sd_media_changed(struct gendisk *disk)
+ 	 * sd_revalidate() is called.
+ 	 */
+ 	retval = -ENODEV;
+-	if (scsi_block_when_processing_errors(sdp))
+-		retval = scsi_test_unit_ready(sdp, SD_TIMEOUT, SD_MAX_RETRIES);
++
++	if (scsi_block_when_processing_errors(sdp)) {
++		sshdr  = kzalloc(sizeof(*sshdr), GFP_KERNEL);
++		retval = scsi_test_unit_ready(sdp, SD_TIMEOUT, SD_MAX_RETRIES,
++					      sshdr);
++	}
  
- 			nsp_dbg(NSP_DEBUG_DATA_IO, "phase changed stat=0x%x, res=%d\n", stat, res);
- 			/* Put back pointer */
--			SCpnt->resid	       	 += res;
-+			nsp_inc_resid(SCpnt, res);
- 			SCpnt->SCp.ptr		 -= res;
- 			SCpnt->SCp.this_residual += res;
- 			ocount			 -= res;
-@@ -866,7 +879,7 @@ static void nsp_pio_write(struct scsi_cmnd *SCpnt)
- 			break;
- 		}
+ 	/*
+ 	 * Unable to test, unit probably not ready.   This usually
+@@ -771,8 +788,13 @@ static int sd_media_changed(struct gendisk *disk)
+ 	 * and we will figure it out later once the drive is
+ 	 * available again.
+ 	 */
+-	if (retval)
+-		 goto not_present;
++	if (retval || (scsi_sense_valid(sshdr) &&
++		       /* 0x3a is medium not present */
++		       sshdr->asc == 0x3a)) {
++		set_media_not_present(sdkp);
++		retval = 1;
++		goto out;
++	}
  
--		SCpnt->resid	       	 -= res;
-+		nsp_inc_resid(SCpnt, -res);
- 		SCpnt->SCp.ptr		 += res;
- 		SCpnt->SCp.this_residual -= res;
- 		ocount			 += res;
-@@ -886,10 +899,12 @@ static void nsp_pio_write(struct scsi_cmnd *SCpnt)
- 	data->FifoCount = ocount;
+ 	/*
+ 	 * For removable scsi disk we have to recognise the presence
+@@ -783,12 +805,12 @@ static int sd_media_changed(struct gendisk *disk)
  
- 	if (time_out == 0) {
--		nsp_msg(KERN_DEBUG, "pio write timeout resid=0x%x", SCpnt->resid);
-+		nsp_msg(KERN_DEBUG, "pio write timeout resid=0x%x",
-+		                                        scsi_get_resid(SCpnt));
- 	}
- 	nsp_dbg(NSP_DEBUG_DATA_IO, "write ocount=0x%x", ocount);
--	nsp_dbg(NSP_DEBUG_DATA_IO, "w cmd=%d resid=0x%x\n", data->CmdId, SCpnt->resid);
-+	nsp_dbg(NSP_DEBUG_DATA_IO, "w cmd=%d resid=0x%x\n", data->CmdId,
-+	                                                scsi_get_resid(SCpnt));
+ 	retval = sdp->changed;
+ 	sdp->changed = 0;
+-
++out:
++	if (retval != sdkp->previous_state)
++		sdev_evt_send_simple(sdp, SDEV_EVT_MEDIA_CHANGE, GFP_KERNEL);
++	sdkp->previous_state = retval;
++	kfree(sshdr);
+ 	return retval;
+-
+-not_present:
+-	set_media_not_present(sdkp);
+-	return 1;
  }
- #undef RFIFO_CRIT
- #undef WFIFO_CRIT
-@@ -911,9 +926,8 @@ static int nsp_nexus(struct scsi_cmnd *SCpnt)
- 	nsp_index_write(base, SYNCREG,	sync->SyncRegister);
- 	nsp_index_write(base, ACKWIDTH, sync->AckWidth);
- 
--	if (SCpnt->use_sg    == 0        ||
--	    SCpnt->resid % 4 != 0        ||
--	    SCpnt->resid     <= PAGE_SIZE ) {
-+	if (scsi_get_resid(SCpnt) % 4 != 0 ||
-+	    scsi_get_resid(SCpnt) <= PAGE_SIZE ) {
- 		data->TransferMode = MODE_IO8;
- 	} else if (nsp_burst_mode == BURST_MEM32) {
- 		data->TransferMode = MODE_MEM32;
-diff --git a/drivers/scsi/ppa.c b/drivers/scsi/ppa.c
-index 67ee51a..f655ae3 100644
---- a/drivers/scsi/ppa.c
-+++ b/drivers/scsi/ppa.c
-@@ -750,18 +750,16 @@ static int ppa_engine(ppa_struct *dev, struct scsi_cmnd *cmd)
- 		cmd->SCp.phase++;
- 
- 	case 4:		/* Phase 4 - Setup scatter/gather buffers */
--		if (cmd->use_sg) {
--			/* if many buffers are available, start filling the first */
--			cmd->SCp.buffer = (struct scatterlist *) cmd->request_buffer;
-+		if (scsi_bufflen(cmd)) {
-+			cmd->SCp.buffer = scsi_sglist(cmd);
- 			cmd->SCp.this_residual = cmd->SCp.buffer->length;
- 			cmd->SCp.ptr = sg_virt(cmd->SCp.buffer);
- 		} else {
--			/* else fill the only available buffer */
- 			cmd->SCp.buffer = NULL;
--			cmd->SCp.this_residual = cmd->request_bufflen;
--			cmd->SCp.ptr = cmd->request_buffer;
-+			cmd->SCp.this_residual = 0;
-+			cmd->SCp.ptr = NULL;
- 		}
--		cmd->SCp.buffers_residual = cmd->use_sg - 1;
-+		cmd->SCp.buffers_residual = scsi_sg_count(cmd) - 1;
- 		cmd->SCp.phase++;
  
- 	case 5:		/* Phase 5 - Data transfer stage */
-diff --git a/drivers/scsi/psi240i.c b/drivers/scsi/psi240i.c
+ static int sd_sync_cache(struct scsi_disk *sdkp)
+diff --git a/drivers/scsi/seagate.c b/drivers/scsi/seagate.c
 deleted file mode 100644
-index 899e89d..0000000
---- a/drivers/scsi/psi240i.c
+index b113244..0000000
+--- a/drivers/scsi/seagate.c
 +++ /dev/null
-@@ -1,689 +0,0 @@
--/*+M*************************************************************************
-- * Perceptive Solutions, Inc. PSI-240I device driver proc support for Linux.
+@@ -1,1667 +0,0 @@
+-/*
+- *    seagate.c Copyright (C) 1992, 1993 Drew Eckhardt
+- *      low level scsi driver for ST01/ST02, Future Domain TMC-885,
+- *      TMC-950 by Drew Eckhardt <drew at colorado.edu>
 - *
-- * Copyright (c) 1997 Perceptive Solutions, Inc.
+- *      Note : TMC-880 boards don't work because they have two bits in
+- *              the status register flipped, I'll fix this "RSN"
+- *	[why do I have strong feeling that above message is from 1993? :-)
+- *	        pavel at ucw.cz]
 - *
-- * This program is free software; you can redistribute it and/or modify
-- * it under the terms of the GNU General Public License as published by
-- * the Free Software Foundation; either version 2, or (at your option)
-- * any later version.
+- *      This card does all the I/O via memory mapped I/O, so there is no need
+- *      to check or allocate a region of the I/O address space.
+- */
+-
+-/* 1996 - to use new read{b,w,l}, write{b,w,l}, and phys_to_virt
+- * macros, replaced assembler routines with C. There's probably a
+- * performance hit, but I only have a cdrom and can't tell. Define
+- * SEAGATE_USE_ASM if you want the old assembler code -- SJT
 - *
-- * This program is distributed in the hope that it will be useful,
-- * but WITHOUT ANY WARRANTY; without even the implied warranty of
-- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-- * GNU General Public License for more details.
+- * 1998-jul-29 - created DPRINTK macros and made it work under 
+- * linux 2.1.112, simplified some #defines etc. <pavel at ucw.cz>
 - *
-- * 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, 675 Mass Ave, Cambridge, MA 02139, USA.
+- * Aug 2000 - aeb - deleted seagate_st0x_biosparam(). It would try to
+- * read the physical disk geometry, a bad mistake. Of course it doesn't
+- * matter much what geometry one invents, but on large disks it
+- * returned 256 (or more) heads, causing all kind of failures.
+- * Of course this means that people might see a different geometry now,
+- * so boot parameters may be necessary in some cases.
+- */
+-
+-/*
+- * Configuration :
+- * To use without BIOS -DOVERRIDE=base_address -DCONTROLLER=FD or SEAGATE
+- * -DIRQ will override the default of 5.
+- * Note: You can now set these options from the kernel's "command line".
+- * The syntax is:
+- *
+- *     st0x=ADDRESS,IRQ                (for a Seagate controller)
+- * or:
+- *     tmc8xx=ADDRESS,IRQ              (for a TMC-8xx or TMC-950 controller)
+- * eg:
+- *     tmc8xx=0xC8000,15
 - *
+- * will configure the driver for a TMC-8xx style controller using IRQ 15
+- * with a base address of 0xC8000.
 - *
-- *	File Name:		psi240i.c
+- * -DARBITRATE 
+- *      Will cause the host adapter to arbitrate for the
+- *      bus for better SCSI-II compatibility, rather than just
+- *      waiting for BUS FREE and then doing its thing.  Should
+- *      let us do one command per Lun when I integrate my
+- *      reorganization changes into the distribution sources.
 - *
-- *	Description:	SCSI driver for the PSI240I EIDE interface card.
+- * -DDEBUG=65535
+- *      Will activate debug code.
 - *
-- *-M*************************************************************************/
+- * -DFAST or -DFAST32 
+- *      Will use blind transfers where possible
+- *
+- * -DPARITY  
+- *      This will enable parity.
+- *
+- * -DSEAGATE_USE_ASM
+- *      Will use older seagate assembly code. should be (very small amount)
+- *      Faster.
+- *
+- * -DSLOW_RATE=50
+- *      Will allow compatibility with broken devices that don't
+- *      handshake fast enough (ie, some CD ROM's) for the Seagate
+- *      code.
+- *
+- *      50 is some number, It will let you specify a default
+- *      transfer rate if handshaking isn't working correctly.
+- *
+- * -DOLDCNTDATASCEME  There is a new sceme to set the CONTROL
+- *                    and DATA reigsters which complies more closely
+- *                    with the SCSI2 standard. This hopefully eliminates
+- *                    the need to swap the order these registers are
+- *                    'messed' with. It makes the following two options
+- *                    obsolete. To reenable the old sceme define this.
+- *
+- * The following to options are patches from the SCSI.HOWTO
+- *
+- * -DSWAPSTAT  This will swap the definitions for STAT_MSG and STAT_CD.
+- *
+- * -DSWAPCNTDATA  This will swap the order that seagate.c messes with
+- *                the CONTROL an DATA registers.
+- */
 -
 -#include <linux/module.h>
--
--#include <linux/blkdev.h>
--#include <linux/kernel.h>
--#include <linux/types.h>
--#include <linux/string.h>
--#include <linux/ioport.h>
--#include <linux/delay.h>
 -#include <linux/interrupt.h>
--#include <linux/proc_fs.h>
 -#include <linux/spinlock.h>
+-#include <linux/signal.h>
+-#include <linux/string.h>
+-#include <linux/proc_fs.h>
+-#include <linux/init.h>
+-#include <linux/blkdev.h>
 -#include <linux/stat.h>
+-#include <linux/delay.h>
+-#include <linux/io.h>
 -
--#include <asm/dma.h>
 -#include <asm/system.h>
--#include <asm/io.h>
--#include "scsi.h"
--#include <scsi/scsi_host.h>
+-#include <asm/uaccess.h>
 -
--#include "psi240i.h"
--#include "psi_chip.h"
+-#include <scsi/scsi_cmnd.h>
+-#include <scsi/scsi_device.h>
+-#include <scsi/scsi.h>
+-
+-#include <scsi/scsi_dbg.h>
+-#include <scsi/scsi_host.h>
 -
--//#define DEBUG 1
 -
 -#ifdef DEBUG
--#define DEB(x) x
+-#define DPRINTK( when, msg... ) do { if ( (DEBUG & (when)) == (when) ) printk( msg ); } while (0)
 -#else
--#define DEB(x)
+-#define DPRINTK( when, msg... ) do { } while (0)
+-#define DEBUG 0
 -#endif
+-#define DANY( msg... ) DPRINTK( 0xffff, msg );
 -
--#define MAXBOARDS 6	/* Increase this and the sizes of the arrays below, if you need more. */
+-#ifndef IRQ
+-#define IRQ 5
+-#endif
 -
--#define	PORT_DATA				0
--#define	PORT_ERROR				1
--#define	PORT_SECTOR_COUNT		2
--#define	PORT_LBA_0				3
--#define	PORT_LBA_8				4
--#define	PORT_LBA_16				5
--#define	PORT_LBA_24				6
--#define	PORT_STAT_CMD			7
--#define	PORT_SEL_FAIL			8
--#define	PORT_IRQ_STATUS			9
--#define	PORT_ADDRESS			10
--#define	PORT_FAIL				11
--#define	PORT_ALT_STAT		   	12
+-#ifdef FAST32
+-#define FAST
+-#endif
 -
--typedef struct
--	{
--	UCHAR		   	device;				// device code
--	UCHAR			byte6;				// device select register image
--	UCHAR			spigot;				// spigot number
--	UCHAR			expectingIRQ;		// flag for expecting and interrupt
--	USHORT			sectors;			// number of sectors per track
--	USHORT			heads;				// number of heads
--	USHORT			cylinders;			// number of cylinders for this device
--	USHORT			spareword;			// placeholder
--	ULONG			blocks;				// number of blocks on device
--	}	OUR_DEVICE, *POUR_DEVICE;
+-#undef LINKED			/* Linked commands are currently broken! */
 -
--typedef struct
--	{
--	USHORT		 ports[13];
--	OUR_DEVICE	 device[8];
--	struct scsi_cmnd *pSCmnd;
--	IDE_STRUCT	 ide;
--	ULONG		 startSector;
--	USHORT		 sectorCount;
--	struct scsi_cmnd *SCpnt;
--	VOID		*buffer;
--	USHORT		 expectingIRQ;
--	}	ADAPTER240I, *PADAPTER240I;
+-#if defined(OVERRIDE) && !defined(CONTROLLER)
+-#error Please use -DCONTROLLER=SEAGATE or -DCONTROLLER=FD to override controller type
+-#endif
 -
--#define HOSTDATA(host) ((PADAPTER240I)&host->hostdata)
+-#ifndef __i386__
+-#undef SEAGATE_USE_ASM
+-#endif
 -
--static struct	Scsi_Host *PsiHost[6] = {NULL,};  /* One for each IRQ level (10-15) */
--static			IDENTIFY_DATA	identifyData;
--static			SETUP			ChipSetup;
+-/*
+-	Thanks to Brian Antoine for the example code in his Messy-Loss ST-01
+-		driver, and Mitsugu Suzuki for information on the ST-01
+-		SCSI host.
+-*/
 -
--static	USHORT	portAddr[6] = {CHIP_ADRS_0, CHIP_ADRS_1, CHIP_ADRS_2, CHIP_ADRS_3, CHIP_ADRS_4, CHIP_ADRS_5};
+-/*
+-	CONTROL defines
+-*/
 -
--/****************************************************************
-- *	Name:	WriteData	:LOCAL
-- *
-- *	Description:	Write data to device.
-- *
-- *	Parameters:		padapter - Pointer adapter data structure.
-- *
-- *	Returns:		TRUE if drive does not assert DRQ in time.
-- *
-- ****************************************************************/
--static int WriteData (PADAPTER240I padapter)
--	{
--	ULONG	timer;
--	USHORT *pports = padapter->ports;
+-#define CMD_RST 		0x01
+-#define CMD_SEL 		0x02
+-#define CMD_BSY 		0x04
+-#define CMD_ATTN    		0x08
+-#define CMD_START_ARB		0x10
+-#define CMD_EN_PARITY		0x20
+-#define CMD_INTR		0x40
+-#define CMD_DRVR_ENABLE		0x80
 -
--	timer = jiffies + TIMEOUT_DRQ;								// calculate the timeout value
--	do  {
--		if ( inb_p (pports[PORT_STAT_CMD]) & IDE_STATUS_DRQ )
--			{
--			outsw (pports[PORT_DATA], padapter->buffer, (USHORT)padapter->ide.ide.ide[2] * 256);
--			return 0;
--			}
--		}	while ( time_after(timer, jiffies) );									// test for timeout
+-/*
+-	STATUS
+-*/
+-#ifdef SWAPSTAT
+-#define STAT_MSG		0x08
+-#define STAT_CD			0x02
+-#else
+-#define STAT_MSG		0x02
+-#define STAT_CD			0x08
+-#endif
 -
--	padapter->ide.ide.ides.cmd = 0;									// null out the command byte
--	return 1;
--	}
--/****************************************************************
-- *	Name:	IdeCmd	:LOCAL
-- *
-- *	Description:	Process a queued command from the SCSI manager.
-- *
-- *	Parameters:		padapter - Pointer adapter data structure.
-- *
-- *	Returns:		Zero if no error or status register contents on error.
-- *
-- ****************************************************************/
--static UCHAR IdeCmd (PADAPTER240I padapter)
--	{
--	ULONG	timer;
--	USHORT *pports = padapter->ports;
--	UCHAR	status;
+-#define STAT_BSY		0x01
+-#define STAT_IO			0x04
+-#define STAT_REQ		0x10
+-#define STAT_SEL		0x20
+-#define STAT_PARITY		0x40
+-#define STAT_ARB_CMPL		0x80
 -
--	outb_p (padapter->ide.ide.ides.spigot, pports[PORT_SEL_FAIL]);	// select the spigot
--	outb_p (padapter->ide.ide.ide[6], pports[PORT_LBA_24]);			// select the drive
--	timer = jiffies + TIMEOUT_READY;							// calculate the timeout value
--	do  {
--		status = inb_p (padapter->ports[PORT_STAT_CMD]);
--		if ( status & IDE_STATUS_DRDY )
--			{
--			outb_p (padapter->ide.ide.ide[2], pports[PORT_SECTOR_COUNT]);
--			outb_p (padapter->ide.ide.ide[3], pports[PORT_LBA_0]);
--			outb_p (padapter->ide.ide.ide[4], pports[PORT_LBA_8]);
--			outb_p (padapter->ide.ide.ide[5], pports[PORT_LBA_16]);
--			padapter->expectingIRQ = 1;
--			outb_p (padapter->ide.ide.ide[7], pports[PORT_STAT_CMD]);
+-/* 
+-	REQUESTS
+-*/
 -
--			if ( padapter->ide.ide.ides.cmd == IDE_CMD_WRITE_MULTIPLE )
--				return (WriteData (padapter));
+-#define REQ_MASK (STAT_CD |  STAT_IO | STAT_MSG)
+-#define REQ_DATAOUT 0
+-#define REQ_DATAIN STAT_IO
+-#define REQ_CMDOUT STAT_CD
+-#define REQ_STATIN (STAT_CD | STAT_IO)
+-#define REQ_MSGOUT (STAT_MSG | STAT_CD)
+-#define REQ_MSGIN (STAT_MSG | STAT_CD | STAT_IO)
 -
--			return 0;
--			}
--		}	while ( time_after(timer, jiffies) );									// test for timeout
+-extern volatile int seagate_st0x_timeout;
 -
--	padapter->ide.ide.ides.cmd = 0;									// null out the command byte
--	return status;
--	}
--/****************************************************************
-- *	Name:	SetupTransfer	:LOCAL
-- *
-- *	Description:	Setup a data transfer command.
-- *
-- *	Parameters:		padapter - Pointer adapter data structure.
-- *					drive	 - Drive/head register upper nibble only.
-- *
-- *	Returns:		TRUE if no data to transfer.
-- *
-- ****************************************************************/
--static int SetupTransfer (PADAPTER240I padapter, UCHAR drive)
--	{
--	if ( padapter->sectorCount )
--		{
--		*(ULONG *)padapter->ide.ide.ides.lba = padapter->startSector;
--		padapter->ide.ide.ide[6] |= drive;
--		padapter->ide.ide.ides.sectors = ( padapter->sectorCount > SECTORSXFER ) ? SECTORSXFER : padapter->sectorCount;
--		padapter->sectorCount -= padapter->ide.ide.ides.sectors;	// bump the start and count for next xfer
--		padapter->startSector += padapter->ide.ide.ides.sectors;
--		return 0;
--		}
--	else
--		{
--		padapter->ide.ide.ides.cmd = 0;								// null out the command byte
--		padapter->SCpnt = NULL;
--		return 1;
--		}
--	}
--/****************************************************************
-- *	Name:	DecodeError	:LOCAL
-- *
-- *	Description:	Decode and process device errors.
-- *
-- *	Parameters:		pshost - Pointer to host data block.
-- *					status - Status register code.
-- *
-- *	Returns:		The driver status code.
-- *
-- ****************************************************************/
--static ULONG DecodeError (struct Scsi_Host *pshost, UCHAR status)
--	{
--	PADAPTER240I	padapter = HOSTDATA(pshost);
--	UCHAR			error;
+-#ifdef PARITY
+-#define BASE_CMD CMD_EN_PARITY
+-#else
+-#define BASE_CMD  0
+-#endif
 -
--	padapter->expectingIRQ = 0;
--	padapter->SCpnt = NULL;
--	if ( status & IDE_STATUS_WRITE_FAULT )
--		{
--		return DID_PARITY << 16;
--		}
--	if ( status & IDE_STATUS_BUSY )
--		return DID_BUS_BUSY << 16;
+-/*
+-	Debugging code
+-*/
 -
--	error = inb_p (padapter->ports[PORT_ERROR]);
--	DEB(printk ("\npsi240i error register: %x", error));
--	switch ( error )
--		{
--		case IDE_ERROR_AMNF:
--		case IDE_ERROR_TKONF:
--		case IDE_ERROR_ABRT:
--		case IDE_ERROR_IDFN:
--		case IDE_ERROR_UNC:
--		case IDE_ERROR_BBK:
--		default:
--			return DID_ERROR << 16;
--		}
--	return DID_ERROR << 16;
--	}
--/****************************************************************
-- *	Name:	Irq_Handler	:LOCAL
-- *
-- *	Description:	Interrupt handler.
-- *
-- *	Parameters:		irq		- Hardware IRQ number.
-- *					dev_id	-
-- *
-- *	Returns:		TRUE if drive is not ready in time.
-- *
-- ****************************************************************/
--static void Irq_Handler (int irq, void *dev_id)
--	{
--	struct Scsi_Host *shost;	// Pointer to host data block
--	PADAPTER240I padapter;		// Pointer to adapter control structure
--	USHORT *pports;			// I/O port array
--	struct scsi_cmnd *SCpnt;
--	UCHAR status;
--	int z;
+-#define PHASE_BUS_FREE 1
+-#define PHASE_ARBITRATION 2
+-#define PHASE_SELECTION 4
+-#define PHASE_DATAIN 8
+-#define PHASE_DATAOUT 0x10
+-#define PHASE_CMDOUT 0x20
+-#define PHASE_MSGIN 0x40
+-#define PHASE_MSGOUT 0x80
+-#define PHASE_STATUSIN 0x100
+-#define PHASE_ETC (PHASE_DATAIN | PHASE_DATAOUT | PHASE_CMDOUT | PHASE_MSGIN | PHASE_MSGOUT | PHASE_STATUSIN)
+-#define PRINT_COMMAND 0x200
+-#define PHASE_EXIT 0x400
+-#define PHASE_RESELECT 0x800
+-#define DEBUG_FAST 0x1000
+-#define DEBUG_SG   0x2000
+-#define DEBUG_LINKED	0x4000
+-#define DEBUG_BORKEN	0x8000
+-
+-/* 
+- *	Control options - these are timeouts specified in .01 seconds.
+- */
+-
+-/* 30, 20 work */
+-#define ST0X_BUS_FREE_DELAY 25
+-#define ST0X_SELECTION_DELAY 25
+-
+-#define SEAGATE 1		/* these determine the type of the controller */
+-#define FD	2
+-
+-#define ST0X_ID_STR	"Seagate ST-01/ST-02"
+-#define FD_ID_STR	"TMC-8XX/TMC-950"
+-
+-static int internal_command (unsigned char target, unsigned char lun,
+-			     const void *cmnd,
+-			     void *buff, int bufflen, int reselect);
+-
+-static int incommand;		/* set if arbitration has finished
+-				   and we are in some command phase. */
+-
+-static unsigned int base_address = 0;	/* Where the card ROM starts, used to 
+-					   calculate memory mapped register
+-					   location.  */
+-
+-static void __iomem *st0x_cr_sr;	/* control register write, status
+-					   register read.  256 bytes in
+-					   length.
+-					   Read is status of SCSI BUS, as per 
+-					   STAT masks.  */
 -
--	DEB(printk ("\npsi240i received interrupt\n"));
+-static void __iomem *st0x_dr;	/* data register, read write 256
+-				   bytes in length.  */
 -
--	shost = PsiHost[irq - 10];
--	if ( !shost )
--		panic ("Splunge!");
+-static volatile int st0x_aborted = 0;	/* set when we are aborted, ie by a
+-					   time out, etc.  */
 -
--	padapter = HOSTDATA(shost);
--	pports = padapter->ports;
--	SCpnt = padapter->SCpnt;
+-static unsigned char controller_type = 0;	/* set to SEAGATE for ST0x
+-						   boards or FD for TMC-8xx
+-						   boards */
+-static int irq = IRQ;
 -
--	if ( !padapter->expectingIRQ )
--		{
--		DEB(printk ("\npsi240i Unsolicited interrupt\n"));
--		return;
--		}
--	padapter->expectingIRQ = 0;
+-module_param(base_address, uint, 0);
+-module_param(controller_type, byte, 0);
+-module_param(irq, int, 0);
+-MODULE_LICENSE("GPL");
 -
--	status = inb_p (padapter->ports[PORT_STAT_CMD]);			// read the device status
--	if ( status & (IDE_STATUS_ERROR | IDE_STATUS_WRITE_FAULT) )
--		goto irqerror;
 -
--	DEB(printk ("\npsi240i processing interrupt"));
--	switch ( padapter->ide.ide.ides.cmd )							// decide how to handle the interrupt
--		{
--		case IDE_CMD_READ_MULTIPLE:
--			if ( status & IDE_STATUS_DRQ )
--				{
--				insw (pports[PORT_DATA], padapter->buffer, (USHORT)padapter->ide.ide.ides.sectors * 256);
--				padapter->buffer += padapter->ide.ide.ides.sectors * 512;
--				if ( SetupTransfer (padapter, padapter->ide.ide.ide[6] & 0xF0) )
--					{
--					SCpnt->result = DID_OK << 16;
--					padapter->SCpnt = NULL;
--					SCpnt->scsi_done (SCpnt);
--					return;
--					}
--				if ( !(status = IdeCmd (padapter)) )
--					return;
--				}
--			break;
+-#define retcode(result) (((result) << 16) | (message << 8) | status)
+-#define STATUS ((u8) readb(st0x_cr_sr))
+-#define DATA ((u8) readb(st0x_dr))
+-#define WRITE_CONTROL(d) { writeb((d), st0x_cr_sr); }
+-#define WRITE_DATA(d) { writeb((d), st0x_dr); }
 -
--		case IDE_CMD_WRITE_MULTIPLE:
--			padapter->buffer += padapter->ide.ide.ides.sectors * 512;
--			if ( SetupTransfer (padapter, padapter->ide.ide.ide[6] & 0xF0) )
--				{
--				SCpnt->result = DID_OK << 16;
--				padapter->SCpnt = NULL;
--				SCpnt->scsi_done (SCpnt);
--				return;
--				}
--			if ( !(status = IdeCmd (padapter)) )
--				return;
--			break;
+-#ifndef OVERRIDE
+-static unsigned int seagate_bases[] = {
+-	0xc8000, 0xca000, 0xcc000,
+-	0xce000, 0xdc000, 0xde000
+-};
 -
--		case IDE_COMMAND_IDENTIFY:
--			{
--			PINQUIRYDATA	pinquiryData  = SCpnt->request_buffer;
+-typedef struct {
+-	const unsigned char *signature;
+-	unsigned offset;
+-	unsigned length;
+-	unsigned char type;
+-} Signature;
 -
--			if ( status & IDE_STATUS_DRQ )
--				{
--				insw (pports[PORT_DATA], &identifyData, sizeof (identifyData) >> 1);
+-static Signature __initdata signatures[] = {
+-	{"ST01 v1.7  (C) Copyright 1987 Seagate", 15, 37, SEAGATE},
+-	{"SCSI BIOS 2.00  (C) Copyright 1987 Seagate", 15, 40, SEAGATE},
 -
--				memset (pinquiryData, 0, SCpnt->request_bufflen);		// Zero INQUIRY data structure.
--				pinquiryData->DeviceType = 0;
--				pinquiryData->Versions = 2;
--				pinquiryData->AdditionalLength = 35 - 4;
+-/*
+- * The following two lines are NOT mistakes.  One detects ROM revision
+- * 3.0.0, the other 3.2.  Since seagate has only one type of SCSI adapter,
+- * and this is not going to change, the "SEAGATE" and "SCSI" together
+- * are probably "good enough"
+- */
 -
--				// Fill in vendor identification fields.
--				for ( z = 0;  z < 8;  z += 2 )
--					{
--					pinquiryData->VendorId[z]	  = ((UCHAR *)identifyData.ModelNumber)[z + 1];
--					pinquiryData->VendorId[z + 1] = ((UCHAR *)identifyData.ModelNumber)[z];
--					}
+-	{"SEAGATE SCSI BIOS ", 16, 17, SEAGATE},
+-	{"SEAGATE SCSI BIOS ", 17, 17, SEAGATE},
 -
--				// Initialize unused portion of product id.
--				for ( z = 0;  z < 4;  z++ )
--					pinquiryData->ProductId[12 + z] = ' ';
+-/*
+- * However, future domain makes several incompatible SCSI boards, so specific
+- * signatures must be used.
+- */
 -
--				// Move firmware revision from IDENTIFY data to
--				// product revision in INQUIRY data.
--				for ( z = 0;  z < 4;  z += 2 )
--					{
--					pinquiryData->ProductRevisionLevel[z]	 = ((UCHAR *)identifyData.FirmwareRevision)[z + 1];
--					pinquiryData->ProductRevisionLevel[z + 1] = ((UCHAR *)identifyData.FirmwareRevision)[z];
--					}
+-	{"FUTURE DOMAIN CORP. (C) 1986-1989 V5.0C2/14/89", 5, 46, FD},
+-	{"FUTURE DOMAIN CORP. (C) 1986-1989 V6.0A7/28/89", 5, 46, FD},
+-	{"FUTURE DOMAIN CORP. (C) 1986-1990 V6.0105/31/90", 5, 47, FD},
+-	{"FUTURE DOMAIN CORP. (C) 1986-1990 V6.0209/18/90", 5, 47, FD},
+-	{"FUTURE DOMAIN CORP. (C) 1986-1990 V7.009/18/90", 5, 46, FD},
+-	{"FUTURE DOMAIN CORP. (C) 1992 V8.00.004/02/92", 5, 44, FD},
+-	{"IBM F1 BIOS V1.1004/30/92", 5, 25, FD},
+-	{"FUTURE DOMAIN TMC-950", 5, 21, FD},
+-	/* Added for 2.2.16 by Matthias_Heidbrink at b.maus.de */
+-	{"IBM F1 V1.2009/22/93", 5, 25, FD},
+-};
 -
--				SCpnt->result = DID_OK << 16;
--				padapter->SCpnt = NULL;
--				SCpnt->scsi_done (SCpnt);
--				return;
--				}
--			break;
--			}
+-#define NUM_SIGNATURES ARRAY_SIZE(signatures)
+-#endif				/* n OVERRIDE */
 -
--		default:
--			SCpnt->result = DID_OK << 16;
--			padapter->SCpnt = NULL;
--			SCpnt->scsi_done (SCpnt);
--			return;
--		}
+-/*
+- * hostno stores the hostnumber, as told to us by the init routine.
+- */
 -
--irqerror:;
--	DEB(printk ("\npsi240i error  Device Status: %X\n", status));
--	SCpnt->result = DecodeError (shost, status);
--	SCpnt->scsi_done (SCpnt);
--	}
+-static int hostno = -1;
+-static void seagate_reconnect_intr (int, void *);
+-static irqreturn_t do_seagate_reconnect_intr (int, void *);
+-static int seagate_st0x_bus_reset(struct scsi_cmnd *);
 -
--static irqreturn_t do_Irq_Handler (int irq, void *dev_id)
--{
--	unsigned long flags;
--	struct Scsi_Host *dev = dev_id;
--	
--	spin_lock_irqsave(dev->host_lock, flags);
--	Irq_Handler(irq, dev_id);
--	spin_unlock_irqrestore(dev->host_lock, flags);
--	return IRQ_HANDLED;
--}
+-#ifdef FAST
+-static int fast = 1;
+-#else
+-#define fast 0
+-#endif
 -
--/****************************************************************
-- *	Name:	Psi240i_QueueCommand
+-#ifdef SLOW_RATE
+-/*
+- * Support for broken devices :
+- * The Seagate board has a handshaking problem.  Namely, a lack
+- * thereof for slow devices.  You can blast 600K/second through
+- * it if you are polling for each byte, more if you do a blind
+- * transfer.  In the first case, with a fast device, REQ will
+- * transition high-low or high-low-high before your loop restarts
+- * and you'll have no problems.  In the second case, the board
+- * will insert wait states for up to 13.2 usecs for REQ to
+- * transition low->high, and everything will work.
 - *
-- *	Description:	Process a queued command from the SCSI manager.
+- * However, there's nothing in the state machine that says
+- * you *HAVE* to see a high-low-high set of transitions before
+- * sending the next byte, and slow things like the Trantor CD ROMS
+- * will break because of this.
 - *
-- *	Parameters:		SCpnt - Pointer to SCSI command structure.
-- *					done  - Pointer to done function to call.
+- * So, we need to slow things down, which isn't as simple as it
+- * seems.  We can't slow things down period, because then people
+- * who don't recompile their kernels will shoot me for ruining
+- * their performance.  We need to do it on a case per case basis.
 - *
-- *	Returns:		Status code.
+- * The best for performance will be to, only for borken devices
+- * (this is stored on a per-target basis in the scsi_devices array)
 - *
-- ****************************************************************/
--static int Psi240i_QueueCommand(struct scsi_cmnd *SCpnt,
--				void (*done)(struct scsi_cmnd *))
--	{
--	UCHAR *cdb = (UCHAR *)SCpnt->cmnd;
--	// Pointer to SCSI CDB
--	PADAPTER240I padapter = HOSTDATA (SCpnt->device->host);
--	// Pointer to adapter control structure
--	POUR_DEVICE pdev = &padapter->device [SCpnt->device->id];
--	// Pointer to device information
--	UCHAR rc;
--	// command return code
+- * Wait for a low->high transition before continuing with that
+- * transfer.  If we timeout, continue anyways.  We don't need
+- * a long timeout, because REQ should only be asserted until the
+- * corresponding ACK is received and processed.
+- *
+- * Note that we can't use the system timer for this, because of
+- * resolution, and we *really* can't use the timer chip since
+- * gettimeofday() and the beeper routines use that.  So,
+- * the best thing for us to do will be to calibrate a timing
+- * loop in the initialization code using the timer chip before
+- * gettimeofday() can screw with it.
+- *
+- * FIXME: this is broken (not borken :-). Empty loop costs less than
+- * loop with ISA access in it! -- pavel at ucw.cz
+- */
 -
--	SCpnt->scsi_done = done;
--	padapter->ide.ide.ides.spigot = pdev->spigot;
--	padapter->buffer = SCpnt->request_buffer;
--	if (done)
--		{
--		if ( !pdev->device )
--			{
--			SCpnt->result = DID_BAD_TARGET << 16;
--			done (SCpnt);
--			return 0;
--			}
--		}
--	else
--		{
--		printk("psi240i_queuecommand: %02X: done can't be NULL\n", *cdb);
--		return 0;
--		}
+-static int borken_calibration = 0;
 -
--	switch ( *cdb )
--		{
--		case SCSIOP_INQUIRY:   					// inquiry CDB
--			{
--			padapter->ide.ide.ide[6] = pdev->byte6;
--			padapter->ide.ide.ides.cmd = IDE_COMMAND_IDENTIFY;
--			break;
--			}
+-static void __init borken_init (void)
+-{
+-	register int count = 0, start = jiffies + 1, stop = start + 25;
 -
--		case SCSIOP_TEST_UNIT_READY:			// test unit ready CDB
--			SCpnt->result = DID_OK << 16;
--			done (SCpnt);
--			return 0;
+-	/* FIXME: There may be a better approach, this is a straight port for
+-	   now */
+-	preempt_disable();
+-	while (time_before (jiffies, start))
+-		cpu_relax();
+-	for (; time_before (jiffies, stop); ++count)
+-		cpu_relax();
+-	preempt_enable();
 -
--		case SCSIOP_READ_CAPACITY:			  	// read capctiy CDB
--			{
--			PREAD_CAPACITY_DATA	pdata = (PREAD_CAPACITY_DATA)SCpnt->request_buffer;
+-/*
+- * Ok, we now have a count for .25 seconds.  Convert to a
+- * count per second and divide by transfer rate in K.  */
 -
--			pdata->blksiz = 0x20000;
--			XANY2SCSI ((UCHAR *)&pdata->blks, pdev->blocks);
--			SCpnt->result = DID_OK << 16;
--			done (SCpnt);
--			return 0;
--			}
+-	borken_calibration = (count * 4) / (SLOW_RATE * 1024);
 -
--		case SCSIOP_VERIFY:						// verify CDB
--			*(ULONG *)padapter->ide.ide.ides.lba = XSCSI2LONG (&cdb[2]);
--			padapter->ide.ide.ide[6] |= pdev->byte6;
--			padapter->ide.ide.ide[2] = (UCHAR)((USHORT)cdb[8] | ((USHORT)cdb[7] << 8));
--			padapter->ide.ide.ides.cmd = IDE_COMMAND_VERIFY;
--			break;
+-	if (borken_calibration < 1)
+-		borken_calibration = 1;
+-}
 -
--		case SCSIOP_READ:						// read10 CDB
--			padapter->startSector = XSCSI2LONG (&cdb[2]);
--			padapter->sectorCount = (USHORT)cdb[8] | ((USHORT)cdb[7] << 8);
--			SetupTransfer (padapter, pdev->byte6);
--			padapter->ide.ide.ides.cmd = IDE_CMD_READ_MULTIPLE;
--			break;
+-static inline void borken_wait (void)
+-{
+-	register int count;
 -
--		case SCSIOP_READ6:						// read6  CDB
--			padapter->startSector = SCSI2LONG (&cdb[1]);
--			padapter->sectorCount = cdb[4];
--			SetupTransfer (padapter, pdev->byte6);
--			padapter->ide.ide.ides.cmd = IDE_CMD_READ_MULTIPLE;
--			break;
+-	for (count = borken_calibration; count && (STATUS & STAT_REQ); --count)
+-		cpu_relax();
+-	     	
+-#if (DEBUG & DEBUG_BORKEN)
+-	if (count)
+-		printk ("scsi%d : borken timeout\n", hostno);
+-#endif
+-}
 -
--		case SCSIOP_WRITE:						// write10 CDB
--			padapter->startSector = XSCSI2LONG (&cdb[2]);
--			padapter->sectorCount = (USHORT)cdb[8] | ((USHORT)cdb[7] << 8);
--			SetupTransfer (padapter, pdev->byte6);
--			padapter->ide.ide.ides.cmd = IDE_CMD_WRITE_MULTIPLE;
--			break;
--		case SCSIOP_WRITE6:						// write6  CDB
--			padapter->startSector = SCSI2LONG (&cdb[1]);
--			padapter->sectorCount = cdb[4];
--			SetupTransfer (padapter, pdev->byte6);
--			padapter->ide.ide.ides.cmd = IDE_CMD_WRITE_MULTIPLE;
--			break;
+-#endif				/* def SLOW_RATE */
 -
--		default:
--			DEB (printk ("psi240i_queuecommand: Unsupported command %02X\n", *cdb));
--			SCpnt->result = DID_ERROR << 16;
--			done (SCpnt);
--			return 0;
--		}
+-/* These beasts only live on ISA, and ISA means 8MHz. Each ULOOP()
+- * contains at least one ISA access, which takes more than 0.125
+- * usec. So if we loop 8 times time in usec, we are safe.
+- */
 -
--	padapter->SCpnt = SCpnt;  									// Save this command data
+-#define ULOOP( i ) for (clock = i*8;;)
+-#define TIMEOUT (!(clock--))
 -
--	rc = IdeCmd (padapter);
--	if ( rc )
--		{
--		padapter->expectingIRQ = 0;
--		DEB (printk ("psi240i_queuecommand: %02X, %02X: Device failed to respond for command\n", *cdb, padapter->ide.ide.ides.cmd));
--		SCpnt->result = DID_ERROR << 16;
--		done (SCpnt);
+-static int __init seagate_st0x_detect (struct scsi_host_template * tpnt)
+-{
+-	struct Scsi_Host *instance;
+-	int i, j;
+-	unsigned long cr, dr;
+-
+-	tpnt->proc_name = "seagate";
+-/*
+- *	First, we try for the manual override.
+- */
+-	DANY ("Autodetecting ST0x / TMC-8xx\n");
+-
+-	if (hostno != -1) {
+-		printk (KERN_ERR "seagate_st0x_detect() called twice?!\n");
 -		return 0;
--		}
--	DEB (printk("psi240i_queuecommand: %02X, %02X now waiting for interrupt ", *cdb, padapter->ide.ide.ides.cmd));
--	return 0;
 -	}
 -
--/***************************************************************************
-- *	Name:			ReadChipMemory
-- *
-- *	Description:	Read information from controller memory.
-- *
-- *	Parameters:		psetup	- Pointer to memory image of setup information.
-- *					base	- base address of memory.
-- *					length	- lenght of data space in bytes.
-- *					port	- I/O address of data port.
-- *
-- *	Returns:		Nothing.
+-/* If the user specified the controller type from the command line,
+-   controller_type will be non-zero, so don't try to detect one */
+-
+-	if (!controller_type) {
+-#ifdef OVERRIDE
+-		base_address = OVERRIDE;
+-		controller_type = CONTROLLER;
+-
+-		DANY ("Base address overridden to %x, controller type is %s\n",
+-		      base_address,
+-		      controller_type == SEAGATE ? "SEAGATE" : "FD");
+-#else				/* OVERRIDE */
+-/*
+- * 	To detect this card, we simply look for the signature
+- *      from the BIOS version notice in all the possible locations
+- *      of the ROM's.  This has a nice side effect of not trashing
+- *      any register locations that might be used by something else.
 - *
-- **************************************************************************/
--static void ReadChipMemory (void *pdata, USHORT base, USHORT length, USHORT port)
--	{
--	USHORT	z, zz;
--	UCHAR	*pd = (UCHAR *)pdata;
--	outb_p (SEL_NONE, port + REG_SEL_FAIL);				// setup data port
--	zz = 0;
--	while ( zz < length )
--		{
--		outw_p (base, port + REG_ADDRESS);				// setup address
+- * XXX - note that we probably should be probing the address
+- * space for the on-board RAM instead.
+- */
 -
--		for ( z = 0;  z < 8;  z++ )
--			{
--			if ( (zz + z) < length )
--			*pd++ = inb_p (port + z);	// read data byte
--			}
--		zz += 8;
--		base += 8;
+-		for (i = 0; i < ARRAY_SIZE(seagate_bases); ++i) {
+-			void __iomem *p = ioremap(seagate_bases[i], 0x2000);
+-			if (!p)
+-				continue;
+-			for (j = 0; j < NUM_SIGNATURES; ++j)
+-				if (check_signature(p + signatures[j].offset, signatures[j].signature, signatures[j].length)) {
+-					base_address = seagate_bases[i];
+-					controller_type = signatures[j].type;
+-					break;
+-				}
+-			iounmap(p);
 -		}
+-#endif				/* OVERRIDE */
 -	}
--/****************************************************************
-- *	Name:	Psi240i_Detect
-- *
-- *	Description:	Detect and initialize our boards.
-- *
-- *	Parameters:		tpnt - Pointer to SCSI host template structure.
-- *
-- *	Returns:		Number of adapters found.
-- *
-- ****************************************************************/
--static int Psi240i_Detect (struct scsi_host_template *tpnt)
+-	/* (! controller_type) */
+-	tpnt->this_id = (controller_type == SEAGATE) ? 7 : 6;
+-	tpnt->name = (controller_type == SEAGATE) ? ST0X_ID_STR : FD_ID_STR;
+-
+-	if (!base_address) {
+-		printk(KERN_INFO "seagate: ST0x/TMC-8xx not detected.\n");
+-		return 0;
+-	}
+-
+-	cr = base_address + (controller_type == SEAGATE ? 0x1a00 : 0x1c00);
+-	dr = cr + 0x200;
+-	st0x_cr_sr = ioremap(cr, 0x100);
+-	st0x_dr = ioremap(dr, 0x100);
+-
+-	DANY("%s detected. Base address = %x, cr = %x, dr = %x\n",
+-	      tpnt->name, base_address, cr, dr);
+-
+-	/*
+-	 *	At all times, we will use IRQ 5.  Should also check for IRQ3
+-	 *	if we lose our first interrupt.
+-	 */
+-	instance = scsi_register (tpnt, 0);
+-	if (instance == NULL)
+-		return 0;
+-
+-	hostno = instance->host_no;
+-	if (request_irq (irq, do_seagate_reconnect_intr, IRQF_DISABLED, (controller_type == SEAGATE) ? "seagate" : "tmc-8xx", instance)) {
+-		printk(KERN_ERR "scsi%d : unable to allocate IRQ%d\n", hostno, irq);
+-		return 0;
+-	}
+-	instance->irq = irq;
+-	instance->io_port = base_address;
+-#ifdef SLOW_RATE
+-	printk(KERN_INFO "Calibrating borken timer... ");
+-	borken_init();
+-	printk(" %d cycles per transfer\n", borken_calibration);
+-#endif
+-	printk (KERN_INFO "This is one second... ");
 -	{
--	int					board;
--	int					count = 0;
--	int					unit;
--	int					z;
--	USHORT				port, port_range = 16;
--	CHIP_CONFIG_N		chipConfig;
--	CHIP_DEVICE_N		chipDevice[8];
--	struct Scsi_Host   *pshost;
+-		int clock;
+-		ULOOP (1 * 1000 * 1000) {
+-			STATUS;
+-			if (TIMEOUT)
+-				break;
+-		}
+-	}
 -
--	for ( board = 0;  board < MAXBOARDS;  board++ )					// scan for I/O ports
--		{
--		pshost = NULL;
--		port = portAddr[board];								// get base address to test
--		if ( !request_region (port, port_range, "psi240i") )
--			continue;
--		if ( inb_p (port + REG_FAIL) != CHIP_ID )			// do the first test for likley hood that it is us
--			goto host_init_failure;
--		outb_p (SEL_NONE, port + REG_SEL_FAIL);				// setup EEPROM/RAM access
--		outw (0, port + REG_ADDRESS);						// setup EEPROM address zero
--		if ( inb_p (port) != 0x55 )							// test 1st byte
--			goto host_init_failure;									//   nope
--		if ( inb_p (port + 1) != 0xAA )						// test 2nd byte
--			goto host_init_failure;								//   nope
+-	printk ("done, %s options:"
+-#ifdef ARBITRATE
+-		" ARBITRATE"
+-#endif
+-#if DEBUG
+-		" DEBUG"
+-#endif
+-#ifdef FAST
+-		" FAST"
+-#ifdef FAST32
+-		"32"
+-#endif
+-#endif
+-#ifdef LINKED
+-		" LINKED"
+-#endif
+-#ifdef PARITY
+-		" PARITY"
+-#endif
+-#ifdef SEAGATE_USE_ASM
+-		" SEAGATE_USE_ASM"
+-#endif
+-#ifdef SLOW_RATE
+-		" SLOW_RATE"
+-#endif
+-#ifdef SWAPSTAT
+-		" SWAPSTAT"
+-#endif
+-#ifdef SWAPCNTDATA
+-		" SWAPCNTDATA"
+-#endif
+-		"\n", tpnt->name);
+-	return 1;
+-}
 -
--		// at this point our board is found and can be accessed.  Now we need to initialize
--		// our informatation and register with the kernel.
+-static const char *seagate_st0x_info (struct Scsi_Host *shpnt)
+-{
+-	static char buffer[64];
 -
+-	snprintf(buffer, 64, "%s at irq %d, address 0x%05X",
+-		 (controller_type == SEAGATE) ? ST0X_ID_STR : FD_ID_STR,
+-		 irq, base_address);
+-	return buffer;
+-}
 -
--		ReadChipMemory (&chipConfig, CHIP_CONFIG, sizeof (chipConfig), port);
--		ReadChipMemory (&chipDevice, CHIP_DEVICE, sizeof (chipDevice), port);
--		ReadChipMemory (&ChipSetup, CHIP_EEPROM_DATA, sizeof (ChipSetup), port);
+-/*
+- * These are our saved pointers for the outstanding command that is
+- * waiting for a reconnect
+- */
 -
--		if ( !chipConfig.numDrives )						// if no devices on this board
--			goto host_init_failure;
+-static unsigned char current_target, current_lun;
+-static unsigned char *current_cmnd, *current_data;
+-static int current_nobuffs;
+-static struct scatterlist *current_buffer;
+-static int current_bufflen;
 -
--		pshost = scsi_register (tpnt, sizeof(ADAPTER240I));
--		if(pshost == NULL)
--			goto host_init_failure;	
+-#ifdef LINKED
+-/*
+- * linked_connected indicates whether or not we are currently connected to
+- * linked_target, linked_lun and in an INFORMATION TRANSFER phase,
+- * using linked commands.
+- */
 -
--		PsiHost[chipConfig.irq - 10] = pshost;
--		pshost->unique_id = port;
--		pshost->io_port = port;
--		pshost->n_io_port = 16;  /* Number of bytes of I/O space used */
--		pshost->irq = chipConfig.irq;
+-static int linked_connected = 0;
+-static unsigned char linked_target, linked_lun;
+-#endif
 -
--		for ( z = 0;  z < 11;  z++ )						// build regester address array
--			HOSTDATA(pshost)->ports[z] = port + z;
--		HOSTDATA(pshost)->ports[11] = port + REG_FAIL;
--		HOSTDATA(pshost)->ports[12] = port + REG_ALT_STAT;
--		DEB (printk ("\nPorts ="));
--		DEB (for (z=0;z<13;z++) printk(" %#04X",HOSTDATA(pshost)->ports[z]););
+-static void (*done_fn) (struct scsi_cmnd *) = NULL;
+-static struct scsi_cmnd *SCint = NULL;
 -
--		for ( z = 0;  z < chipConfig.numDrives;  ++z )
--			{
--			unit = chipDevice[z].channel & 0x0F;
--			HOSTDATA(pshost)->device[unit].device	 = ChipSetup.setupDevice[unit].device;
--			HOSTDATA(pshost)->device[unit].byte6	 = (UCHAR)(((unit & 1) << 4) | 0xE0);
--			HOSTDATA(pshost)->device[unit].spigot	 = (UCHAR)(1 << (unit >> 1));
--			HOSTDATA(pshost)->device[unit].sectors	 = ChipSetup.setupDevice[unit].sectors;
--			HOSTDATA(pshost)->device[unit].heads	 = ChipSetup.setupDevice[unit].heads;
--			HOSTDATA(pshost)->device[unit].cylinders = ChipSetup.setupDevice[unit].cylinders;
--			HOSTDATA(pshost)->device[unit].blocks	 = ChipSetup.setupDevice[unit].blocks;
--			DEB (printk ("\nHOSTDATA->device    = %X", HOSTDATA(pshost)->device[unit].device));
--			DEB (printk ("\n          byte6     = %X", HOSTDATA(pshost)->device[unit].byte6));
--			DEB (printk ("\n          spigot    = %X", HOSTDATA(pshost)->device[unit].spigot));
--			DEB (printk ("\n          sectors   = %X", HOSTDATA(pshost)->device[unit].sectors));
--			DEB (printk ("\n          heads     = %X", HOSTDATA(pshost)->device[unit].heads));
--			DEB (printk ("\n          cylinders = %X", HOSTDATA(pshost)->device[unit].cylinders));
--			DEB (printk ("\n          blocks    = %lX", HOSTDATA(pshost)->device[unit].blocks));
--			}
+-/*
+- * These control whether or not disconnect / reconnect will be attempted,
+- * or are being attempted.
+- */
 -
--		if ( request_irq (chipConfig.irq, do_Irq_Handler, 0, "psi240i", pshost) == 0 ) 
--			{
--			printk("\nPSI-240I EIDE CONTROLLER: at I/O = %x  IRQ = %d\n", port, chipConfig.irq);
--		        printk("(C) 1997 Perceptive Solutions, Inc. All rights reserved\n\n");
--		        count++;
--		        continue;
--			}
+-#define NO_RECONNECT    0
+-#define RECONNECT_NOW   1
+-#define CAN_RECONNECT   2
 -
--		printk ("Unable to allocate IRQ for PSI-240I controller.\n");
--           
--host_init_failure:
--		
--		release_region (port, port_range);
--		if (pshost)
--			scsi_unregister (pshost);
+-/*
+- * LINKED_RIGHT indicates that we are currently connected to the correct target
+- * for this command, LINKED_WRONG indicates that we are connected to the wrong
+- * target. Note that these imply CAN_RECONNECT and require defined(LINKED).
+- */
+-
+-#define LINKED_RIGHT    3
+-#define LINKED_WRONG    4
+-
+-/*
+- * This determines if we are expecting to reconnect or not.
+- */
+-
+-static int should_reconnect = 0;
+-
+-/*
+- * The seagate_reconnect_intr routine is called when a target reselects the
+- * host adapter.  This occurs on the interrupt triggered by the target
+- * asserting SEL.
+- */
+-
+-static irqreturn_t do_seagate_reconnect_intr(int irq, void *dev_id)
+-{
+-	unsigned long flags;
+-	struct Scsi_Host *dev = dev_id;
+-	
+-	spin_lock_irqsave (dev->host_lock, flags);
+-	seagate_reconnect_intr (irq, dev_id);
+-	spin_unlock_irqrestore (dev->host_lock, flags);
+-	return IRQ_HANDLED;
+-}
+-
+-static void seagate_reconnect_intr (int irq, void *dev_id)
+-{
+-	int temp;
+-	struct scsi_cmnd *SCtmp;
+-
+-	DPRINTK (PHASE_RESELECT, "scsi%d : seagate_reconnect_intr() called\n", hostno);
+-
+-	if (!should_reconnect)
+-		printk(KERN_WARNING "scsi%d: unexpected interrupt.\n", hostno);
+-	else {
+-		should_reconnect = 0;
+-
+-		DPRINTK (PHASE_RESELECT, "scsi%d : internal_command(%d, %08x, %08x, RECONNECT_NOW\n", 
+-			hostno, current_target, current_data, current_bufflen);
+-
+-		temp = internal_command (current_target, current_lun, current_cmnd, current_data, current_bufflen, RECONNECT_NOW);
 -
+-		if (msg_byte(temp) != DISCONNECT) {
+-			if (done_fn) {
+-				DPRINTK(PHASE_RESELECT, "scsi%d : done_fn(%d,%08x)", hostno, hostno, temp);
+-				if (!SCint)
+-					panic ("SCint == NULL in seagate");
+-				SCtmp = SCint;
+-				SCint = NULL;
+-				SCtmp->result = temp;
+-				done_fn(SCtmp);
+-			} else
+-				printk(KERN_ERR "done_fn() not defined.\n");
 -		}
--	return count;
 -	}
+-}
 -
--static int Psi240i_Release(struct Scsi_Host *shost)
+-/*
+- * The seagate_st0x_queue_command() function provides a queued interface
+- * to the seagate SCSI driver.  Basically, it just passes control onto the
+- * seagate_command() function, after fixing it so that the done_fn()
+- * is set to the one passed to the function.  We have to be very careful,
+- * because there are some commands on some devices that do not disconnect,
+- * and if we simply call the done_fn when the command is done then another
+- * command is started and queue_command is called again...  We end up
+- * overflowing the kernel stack, and this tends not to be such a good idea.
+- */
+-
+-static int recursion_depth = 0;
+-
+-static int seagate_st0x_queue_command(struct scsi_cmnd * SCpnt,
+-				      void (*done) (struct scsi_cmnd *))
 -{
--	if (shost->irq)
--		free_irq(shost->irq, NULL);
--	if (shost->io_port && shost->n_io_port)
--		release_region(shost->io_port, shost->n_io_port);
--	scsi_unregister(shost);
--	return 0;
--}
+-	int result, reconnect;
+-	struct scsi_cmnd *SCtmp;
 -
--/****************************************************************
-- *	Name:	Psi240i_BiosParam
-- *
-- *	Description:	Process the biosparam request from the SCSI manager to
-- *					return C/H/S data.
-- *
-- *	Parameters:		disk - Pointer to SCSI disk structure.
-- *					dev	 - Major/minor number from kernel.
-- *					geom - Pointer to integer array to place geometry data.
-- *
-- *	Returns:		zero.
-- *
-- ****************************************************************/
--static int Psi240i_BiosParam (struct scsi_device *sdev, struct block_device *dev,
--		sector_t capacity, int geom[])
--	{
--	POUR_DEVICE	pdev;
+-	DANY ("seagate: que_command");
+-	done_fn = done;
+-	current_target = SCpnt->device->id;
+-	current_lun = SCpnt->device->lun;
+-	current_cmnd = SCpnt->cmnd;
+-	current_data = (unsigned char *) SCpnt->request_buffer;
+-	current_bufflen = SCpnt->request_bufflen;
+-	SCint = SCpnt;
+-	if (recursion_depth)
+-		return 1;
+-	recursion_depth++;
+-	do {
+-#ifdef LINKED
+-		/*
+-		 * Set linked command bit in control field of SCSI command.
+-		 */
 -
--	pdev = &(HOSTDATA(sdev->host)->device[sdev_id(sdev)]);
+-		current_cmnd[SCpnt->cmd_len] |= 0x01;
+-		if (linked_connected) {
+-			DPRINTK (DEBUG_LINKED, "scsi%d : using linked commands, current I_T_L nexus is ", hostno);
+-			if (linked_target == current_target && linked_lun == current_lun) 
+-			{
+-				DPRINTK(DEBUG_LINKED, "correct\n");
+-				reconnect = LINKED_RIGHT;
+-			} else {
+-				DPRINTK(DEBUG_LINKED, "incorrect\n");
+-				reconnect = LINKED_WRONG;
+-			}
+-		} else
+-#endif				/* LINKED */
+-			reconnect = CAN_RECONNECT;
 -
--	geom[0] = pdev->heads;
--	geom[1] = pdev->sectors;
--	geom[2] = pdev->cylinders;
--	return 0;
+-		result = internal_command(SCint->device->id, SCint->device->lun, SCint->cmnd,
+-				      SCint->request_buffer, SCint->request_bufflen, reconnect);
+-		if (msg_byte(result) == DISCONNECT)
+-			break;
+-		SCtmp = SCint;
+-		SCint = NULL;
+-		SCtmp->result = result;
+-		done_fn(SCtmp);
 -	}
+-	while (SCint);
+-	recursion_depth--;
+-	return 0;
+-}
 -
--MODULE_LICENSE("GPL");
+-static int internal_command (unsigned char target, unsigned char lun,
+-		  const void *cmnd, void *buff, int bufflen, int reselect)
+-{
+-	unsigned char *data = NULL;
+-	struct scatterlist *buffer = NULL;
+-	int clock, temp, nobuffs = 0, done = 0, len = 0;
+-#if DEBUG
+-	int transfered = 0, phase = 0, newphase;
+-#endif
+-	register unsigned char status_read;
+-	unsigned char tmp_data, tmp_control, status = 0, message = 0;
+-	unsigned transfersize = 0, underflow = 0;
+-#ifdef SLOW_RATE
+-	int borken = (int) SCint->device->borken;	/* Does the current target require
+-							   Very Slow I/O ?  */
+-#endif
 -
--static struct scsi_host_template driver_template = {
--	.proc_name		= "psi240i", 
--	.name			= "PSI-240I EIDE Disk Controller",
--	.detect			= Psi240i_Detect,
--	.release		= Psi240i_Release,
--	.queuecommand		= Psi240i_QueueCommand,
--	.bios_param	  	= Psi240i_BiosParam,
--	.can_queue	  	= 1,
--	.this_id	  	= -1,
--	.sg_tablesize	  	= SG_NONE,
--	.cmd_per_lun	  	= 1, 
--	.use_clustering		= DISABLE_CLUSTERING,
--};
--#include "scsi_module.c"
-diff --git a/drivers/scsi/psi240i.h b/drivers/scsi/psi240i.h
-deleted file mode 100644
-index 21ebb92..0000000
---- a/drivers/scsi/psi240i.h
-+++ /dev/null
-@@ -1,315 +0,0 @@
--/*+M*************************************************************************
-- * Perceptive Solutions, Inc. PSI-240I device driver proc support for Linux.
-- *
-- * Copyright (c) 1997 Perceptive Solutions, 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, or (at your option)
-- * any later version.
-- *
-- * This program is distributed in the hope that it will be useful,
-- * but WITHOUT ANY WARRANTY; without even the implied warranty of
-- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See 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, 675 Mass Ave, Cambridge, MA 02139, USA.
-- *
-- *
-- *	File Name:		psi240i.h
-- *
-- *	Description:	Header file for the SCSI driver for the PSI240I
-- *					EIDE interface card.
-- *
-- *-M*************************************************************************/
--#ifndef _PSI240I_H
--#define _PSI240I_H
+-	incommand = 0;
+-	st0x_aborted = 0;
 -
--#include <linux/types.h>
+-#if (DEBUG & PRINT_COMMAND)
+-	printk("scsi%d : target = %d, command = ", hostno, target);
+-	__scsi_print_command((unsigned char *) cmnd);
+-#endif
 -
--#ifndef	PSI_EIDE_SCSIOP
--#define	PSI_EIDE_SCSIOP	1
+-#if (DEBUG & PHASE_RESELECT)
+-	switch (reselect) {
+-	case RECONNECT_NOW:
+-		printk("scsi%d : reconnecting\n", hostno);
+-		break;
+-#ifdef LINKED
+-	case LINKED_RIGHT:
+-		printk("scsi%d : connected, can reconnect\n", hostno);
+-		break;
+-	case LINKED_WRONG:
+-		printk("scsi%d : connected to wrong target, can reconnect\n",
+-			hostno);
+-		break;
+-#endif
+-	case CAN_RECONNECT:
+-		printk("scsi%d : allowed to reconnect\n", hostno);
+-		break;
+-	default:
+-		printk("scsi%d : not allowed to reconnect\n", hostno);
+-	}
+-#endif
 -
--/************************************************/
--/*		Some defines that we like 				*/
--/************************************************/
--#define	CHAR		char
--#define	UCHAR		unsigned char
--#define	SHORT		short
--#define	USHORT		unsigned short
--#define	BOOL		unsigned short
--#define	LONG		long
--#define	ULONG		unsigned long
--#define	VOID		void
+-	if (target == (controller_type == SEAGATE ? 7 : 6))
+-		return DID_BAD_TARGET;
 -
--/************************************************/
--/*		Timeout konstants		 				*/
--/************************************************/
--#define	TIMEOUT_READY				10		// 100 mSec
--#define	TIMEOUT_DRQ					40		// 400 mSec
+-	/*
+-	 *	We work it differently depending on if this is is "the first time,"
+-	 *      or a reconnect.  If this is a reselect phase, then SEL will
+-	 *      be asserted, and we must skip selection / arbitration phases.
+-	 */
 -
--/************************************************/
--/*		Misc. macros			 				*/
--/************************************************/
--#define ANY2SCSI(up, p)					\
--((UCHAR *)up)[0] = (((ULONG)(p)) >> 8);	\
--((UCHAR *)up)[1] = ((ULONG)(p));
+-	switch (reselect) {
+-	case RECONNECT_NOW:
+-		DPRINTK (PHASE_RESELECT, "scsi%d : phase RESELECT \n", hostno);
+-		/*
+-		 *	At this point, we should find the logical or of our ID
+-		 *	and the original target's ID on the BUS, with BSY, SEL,
+-		 *	and I/O signals asserted.
+-		 *
+-		 *      After ARBITRATION phase is completed, only SEL, BSY,
+-		 *	and the target ID are asserted.  A valid initiator ID
+-		 *	is not on the bus until IO is asserted, so we must wait
+-		 *	for that.
+-		 */
+-		ULOOP (100 * 1000) {
+-			temp = STATUS;
+-			if ((temp & STAT_IO) && !(temp & STAT_BSY))
+-				break;
+-			if (TIMEOUT) {
+-				DPRINTK (PHASE_RESELECT, "scsi%d : RESELECT timed out while waiting for IO .\n", hostno);
+-				return (DID_BAD_INTR << 16);
+-			}
+-		}
 -
--#define SCSI2LONG(up)					\
--( (((long)*(((UCHAR *)up))) << 16)		\
--+ (((long)(((UCHAR *)up)[1])) << 8)		\
--+ ((long)(((UCHAR *)up)[2])) )
+-		/*
+-		 *	After I/O is asserted by the target, we can read our ID
+-		 *	and its ID off of the BUS.
+-		 */
 -
--#define XANY2SCSI(up, p)				\
--((UCHAR *)up)[0] = ((long)(p)) >> 24;	\
--((UCHAR *)up)[1] = ((long)(p)) >> 16;	\
--((UCHAR *)up)[2] = ((long)(p)) >> 8;	\
--((UCHAR *)up)[3] = ((long)(p));
+-		if (!((temp = DATA) & (controller_type == SEAGATE ? 0x80 : 0x40))) {
+-			DPRINTK (PHASE_RESELECT, "scsi%d : detected reconnect request to different target.\n\tData bus = %d\n", hostno, temp);
+-			return (DID_BAD_INTR << 16);
+-		}
 -
--#define XSCSI2LONG(up)					\
--( (((long)(((UCHAR *)up)[0])) << 24)	\
--+ (((long)(((UCHAR *)up)[1])) << 16)	\
--+ (((long)(((UCHAR *)up)[2])) <<  8)	\
--+ ((long)(((UCHAR *)up)[3])) )
+-		if (!(temp & (1 << current_target))) {
+-			printk(KERN_WARNING "scsi%d : Unexpected reselect interrupt.  Data bus = %d\n", hostno, temp);
+-			return (DID_BAD_INTR << 16);
+-		}
 -
--/************************************************/
--/*		SCSI CDB operation codes 				*/
--/************************************************/
--#define SCSIOP_TEST_UNIT_READY		0x00
--#define SCSIOP_REZERO_UNIT			0x01
--#define SCSIOP_REWIND				0x01
--#define SCSIOP_REQUEST_BLOCK_ADDR	0x02
--#define SCSIOP_REQUEST_SENSE		0x03
--#define SCSIOP_FORMAT_UNIT			0x04
--#define SCSIOP_READ_BLOCK_LIMITS	0x05
--#define SCSIOP_REASSIGN_BLOCKS		0x07
--#define SCSIOP_READ6				0x08
--#define SCSIOP_RECEIVE				0x08
--#define SCSIOP_WRITE6				0x0A
--#define SCSIOP_PRINT				0x0A
--#define SCSIOP_SEND					0x0A
--#define SCSIOP_SEEK6				0x0B
--#define SCSIOP_TRACK_SELECT			0x0B
--#define SCSIOP_SLEW_PRINT			0x0B
--#define SCSIOP_SEEK_BLOCK			0x0C
--#define SCSIOP_PARTITION			0x0D
--#define SCSIOP_READ_REVERSE			0x0F
--#define SCSIOP_WRITE_FILEMARKS		0x10
--#define SCSIOP_FLUSH_BUFFER			0x10
--#define SCSIOP_SPACE				0x11
--#define SCSIOP_INQUIRY				0x12
--#define SCSIOP_VERIFY6				0x13
--#define SCSIOP_RECOVER_BUF_DATA		0x14
--#define SCSIOP_MODE_SELECT			0x15
--#define SCSIOP_RESERVE_UNIT			0x16
--#define SCSIOP_RELEASE_UNIT			0x17
--#define SCSIOP_COPY					0x18
--#define SCSIOP_ERASE				0x19
--#define SCSIOP_MODE_SENSE			0x1A
--#define SCSIOP_START_STOP_UNIT		0x1B
--#define SCSIOP_STOP_PRINT			0x1B
--#define SCSIOP_LOAD_UNLOAD			0x1B
--#define SCSIOP_RECEIVE_DIAGNOSTIC	0x1C
--#define SCSIOP_SEND_DIAGNOSTIC		0x1D
--#define SCSIOP_MEDIUM_REMOVAL		0x1E
--#define SCSIOP_READ_CAPACITY		0x25
--#define SCSIOP_READ					0x28
--#define SCSIOP_WRITE				0x2A
--#define SCSIOP_SEEK					0x2B
--#define SCSIOP_LOCATE				0x2B
--#define SCSIOP_WRITE_VERIFY			0x2E
--#define SCSIOP_VERIFY				0x2F
--#define SCSIOP_SEARCH_DATA_HIGH		0x30
--#define SCSIOP_SEARCH_DATA_EQUAL	0x31
--#define SCSIOP_SEARCH_DATA_LOW		0x32
--#define SCSIOP_SET_LIMITS			0x33
--#define SCSIOP_READ_POSITION		0x34
--#define SCSIOP_SYNCHRONIZE_CACHE	0x35
--#define SCSIOP_COMPARE				0x39
--#define SCSIOP_COPY_COMPARE			0x3A
--#define SCSIOP_WRITE_DATA_BUFF		0x3B
--#define SCSIOP_READ_DATA_BUFF		0x3C
--#define SCSIOP_CHANGE_DEFINITION	0x40
--#define SCSIOP_READ_SUB_CHANNEL		0x42
--#define SCSIOP_READ_TOC				0x43
--#define SCSIOP_READ_HEADER			0x44
--#define SCSIOP_PLAY_AUDIO			0x45
--#define SCSIOP_PLAY_AUDIO_MSF		0x47
--#define SCSIOP_PLAY_TRACK_INDEX		0x48
--#define SCSIOP_PLAY_TRACK_RELATIVE	0x49
--#define SCSIOP_PAUSE_RESUME			0x4B
--#define SCSIOP_LOG_SELECT			0x4C
--#define SCSIOP_LOG_SENSE			0x4D
--#define SCSIOP_MODE_SELECT10		0x55
--#define SCSIOP_MODE_SENSE10			0x5A
--#define SCSIOP_LOAD_UNLOAD_SLOT		0xA6
--#define SCSIOP_MECHANISM_STATUS		0xBD
--#define SCSIOP_READ_CD				0xBE
+-		buffer = current_buffer;
+-		cmnd = current_cmnd;	/* WDE add */
+-		data = current_data;	/* WDE add */
+-		len = current_bufflen;	/* WDE add */
+-		nobuffs = current_nobuffs;
+-
+-		/*
+-		 *	We have determined that we have been selected.  At this
+-		 *	point, we must respond to the reselection by asserting
+-		 *	BSY ourselves
+-		 */
 -
--// IDE command definitions
--#define IDE_COMMAND_ATAPI_RESET		0x08
--#define IDE_COMMAND_READ			0x20
--#define IDE_COMMAND_WRITE			0x30
--#define IDE_COMMAND_RECALIBRATE		0x10
--#define IDE_COMMAND_SEEK			0x70
--#define IDE_COMMAND_SET_PARAMETERS	0x91
--#define IDE_COMMAND_VERIFY			0x40
--#define IDE_COMMAND_ATAPI_PACKET	0xA0
--#define IDE_COMMAND_ATAPI_IDENTIFY	0xA1
--#define	IDE_CMD_READ_MULTIPLE		0xC4
--#define	IDE_CMD_WRITE_MULTIPLE		0xC5
--#define	IDE_CMD_SET_MULTIPLE		0xC6
--#define IDE_COMMAND_WRITE_DMA		0xCA
--#define IDE_COMMAND_READ_DMA		0xC8
--#define IDE_COMMAND_IDENTIFY		0xEC
+-#if 1
+-		WRITE_CONTROL (BASE_CMD | CMD_DRVR_ENABLE | CMD_BSY);
+-#else
+-		WRITE_CONTROL (BASE_CMD | CMD_BSY);
+-#endif
 -
--// IDE status definitions
--#define IDE_STATUS_ERROR			0x01
--#define IDE_STATUS_INDEX			0x02
--#define IDE_STATUS_CORRECTED_ERROR	0x04
--#define IDE_STATUS_DRQ				0x08
--#define IDE_STATUS_DSC				0x10
--#define	IDE_STATUS_WRITE_FAULT		0x20
--#define IDE_STATUS_DRDY				0x40
--#define IDE_STATUS_BUSY				0x80
+-		/*
+-		 *	The target will drop SEL, and raise BSY, at which time
+-		 *	we must drop BSY.
+-		 */
 -
--// IDE error definitions
--#define	IDE_ERROR_AMNF				0x01
--#define	IDE_ERROR_TKONF				0x02
--#define	IDE_ERROR_ABRT				0x04
--#define	IDE_ERROR_MCR				0x08
--#define	IDE_ERROR_IDFN				0x10
--#define	IDE_ERROR_MC				0x20
--#define	IDE_ERROR_UNC				0x40
--#define	IDE_ERROR_BBK				0x80
+-		ULOOP (100 * 1000) {
+-			if (!(STATUS & STAT_SEL))
+-				break;
+-			if (TIMEOUT) {
+-				WRITE_CONTROL (BASE_CMD | CMD_INTR);
+-				DPRINTK (PHASE_RESELECT, "scsi%d : RESELECT timed out while waiting for SEL.\n", hostno);
+-				return (DID_BAD_INTR << 16);
+-			}
+-		}
+-		WRITE_CONTROL (BASE_CMD);
+-		/*
+-		 *	At this point, we have connected with the target
+-		 *	and can get on with our lives.
+-		 */
+-		break;
+-	case CAN_RECONNECT:
+-#ifdef LINKED
+-		/*
+-		 * This is a bletcherous hack, just as bad as the Unix #!
+-		 * interpreter stuff. If it turns out we are using the wrong
+-		 * I_T_L nexus, the easiest way to deal with it is to go into
+-		 *  our INFORMATION TRANSFER PHASE code, send a ABORT
+-		 * message on MESSAGE OUT phase, and then loop back to here.
+-		 */
+-connect_loop:
+-#endif
+-		DPRINTK (PHASE_BUS_FREE, "scsi%d : phase = BUS FREE \n", hostno);
 -
--//	IDE interface structure
--typedef struct _IDE_STRUCT
--	{
--	union
--		{
--		UCHAR	ide[9];
--		struct
--			{
--			USHORT	data;
--			UCHAR	sectors;
--			UCHAR	lba[4];
--			UCHAR	cmd;
--			UCHAR	spigot;
--			}	ides;
--		} ide;
--	}	IDE_STRUCT;
+-		/*
+-		 *    BUS FREE PHASE
+-		 *
+-		 *      On entry, we make sure that the BUS is in a BUS FREE
+-		 *      phase, by insuring that both BSY and SEL are low for
+-		 *      at least one bus settle delay.  Several reads help
+-		 *      eliminate wire glitch.
+-		 */
 -
--// SCSI read capacity structure
--typedef	struct _READ_CAPACITY_DATA
--	{
--	ULONG blks;				/* total blocks (converted to little endian) */
--	ULONG blksiz;			/* size of each (converted to little endian) */
--	}	READ_CAPACITY_DATA, *PREAD_CAPACITY_DATA;
+-#ifndef ARBITRATE
+-#error FIXME: this is broken: we may not use jiffies here - we are under cli(). It will hardlock.
+-		clock = jiffies + ST0X_BUS_FREE_DELAY;
 -
--// SCSI inquiry data
--#ifndef HOSTS_C
+-		while (((STATUS | STATUS | STATUS) & (STAT_BSY | STAT_SEL)) && (!st0x_aborted) && time_before (jiffies, clock))
+-			cpu_relax();
 -
--typedef struct _INQUIRYDATA
--	{
--	UCHAR DeviceType			:5;
--	UCHAR DeviceTypeQualifier	:3;
--	UCHAR DeviceTypeModifier	:7;
--	UCHAR RemovableMedia		:1;
--    UCHAR Versions;
--    UCHAR ResponseDataFormat;
--    UCHAR AdditionalLength;
--    UCHAR Reserved[2];
--	UCHAR SoftReset				:1;
--	UCHAR CommandQueue			:1;
--	UCHAR Reserved2				:1;
--	UCHAR LinkedCommands		:1;
--	UCHAR Synchronous			:1;
--	UCHAR Wide16Bit				:1;
--	UCHAR Wide32Bit				:1;
--	UCHAR RelativeAddressing	:1;
--    UCHAR VendorId[8];
--    UCHAR ProductId[16];
--    UCHAR ProductRevisionLevel[4];
--    UCHAR VendorSpecific[20];
--    UCHAR Reserved3[40];
--	}	INQUIRYDATA, *PINQUIRYDATA;
+-		if (time_after (jiffies, clock))
+-			return retcode (DID_BUS_BUSY);
+-		else if (st0x_aborted)
+-			return retcode (st0x_aborted);
 -#endif
+-		DPRINTK (PHASE_SELECTION, "scsi%d : phase = SELECTION\n", hostno);
 -
--// IDE IDENTIFY data
--typedef struct _IDENTIFY_DATA
--	{
--    USHORT GeneralConfiguration;            // 00
--    USHORT NumberOfCylinders;               // 02
--    USHORT Reserved1;                       // 04
--    USHORT NumberOfHeads;                   // 06
--    USHORT UnformattedBytesPerTrack;        // 08
--    USHORT UnformattedBytesPerSector;       // 0A
--    USHORT SectorsPerTrack;                 // 0C
--    USHORT VendorUnique1[3];                // 0E
--    USHORT SerialNumber[10];                // 14
--    USHORT BufferType;                      // 28
--    USHORT BufferSectorSize;                // 2A
--    USHORT NumberOfEccBytes;                // 2C
--    USHORT FirmwareRevision[4];             // 2E
--    USHORT ModelNumber[20];                 // 36
--    UCHAR  MaximumBlockTransfer;            // 5E
--    UCHAR  VendorUnique2;                   // 5F
--    USHORT DoubleWordIo;                    // 60
--    USHORT Capabilities;                    // 62
--    USHORT Reserved2;                       // 64
--    UCHAR  VendorUnique3;                   // 66
--    UCHAR  PioCycleTimingMode;              // 67
--    UCHAR  VendorUnique4;                   // 68
--    UCHAR  DmaCycleTimingMode;              // 69
--    USHORT TranslationFieldsValid:1;        // 6A
--    USHORT Reserved3:15;
--    USHORT NumberOfCurrentCylinders;        // 6C
--    USHORT NumberOfCurrentHeads;            // 6E
--    USHORT CurrentSectorsPerTrack;          // 70
--    ULONG  CurrentSectorCapacity;           // 72
--    USHORT Reserved4[197];                  // 76
--	}	IDENTIFY_DATA, *PIDENTIFY_DATA;
+-		clock = jiffies + ST0X_SELECTION_DELAY;
 -
--// Identify data without the Reserved4.
--typedef struct _IDENTIFY_DATA2 {
--    USHORT GeneralConfiguration;            // 00
--    USHORT NumberOfCylinders;               // 02
--    USHORT Reserved1;                       // 04
--    USHORT NumberOfHeads;                   // 06
--    USHORT UnformattedBytesPerTrack;        // 08
--    USHORT UnformattedBytesPerSector;       // 0A
--    USHORT SectorsPerTrack;                 // 0C
--    USHORT VendorUnique1[3];                // 0E
--    USHORT SerialNumber[10];                // 14
--    USHORT BufferType;                      // 28
--    USHORT BufferSectorSize;                // 2A
--    USHORT NumberOfEccBytes;                // 2C
--    USHORT FirmwareRevision[4];             // 2E
--    USHORT ModelNumber[20];                 // 36
--    UCHAR  MaximumBlockTransfer;            // 5E
--    UCHAR  VendorUnique2;                   // 5F
--    USHORT DoubleWordIo;                    // 60
--    USHORT Capabilities;                    // 62
--    USHORT Reserved2;                       // 64
--    UCHAR  VendorUnique3;                   // 66
--    UCHAR  PioCycleTimingMode;              // 67
--    UCHAR  VendorUnique4;                   // 68
--    UCHAR  DmaCycleTimingMode;              // 69
--	USHORT TranslationFieldsValid:1;     	// 6A
--    USHORT Reserved3:15;
--    USHORT NumberOfCurrentCylinders;        // 6C
--    USHORT NumberOfCurrentHeads;            // 6E
--    USHORT CurrentSectorsPerTrack;          // 70
--    ULONG  CurrentSectorCapacity;           // 72
--	}	IDENTIFY_DATA2, *PIDENTIFY_DATA2;
+-		/*
+-		 * Arbitration/selection procedure :
+-		 * 1.  Disable drivers
+-		 * 2.  Write HOST adapter address bit
+-		 * 3.  Set start arbitration.
+-		 * 4.  We get either ARBITRATION COMPLETE or SELECT at this
+-		 *     point.
+-		 * 5.  OR our ID and targets on bus.
+-		 * 6.  Enable SCSI drivers and asserted SEL and ATTN
+-		 */
 -
--#endif	// PSI_EIDE_SCSIOP
+-#ifdef ARBITRATE
+-		/* FIXME: verify host lock is always held here */
+-		WRITE_CONTROL(0);
+-		WRITE_DATA((controller_type == SEAGATE) ? 0x80 : 0x40);
+-		WRITE_CONTROL(CMD_START_ARB);
 -
--// function prototypes
--int Psi240i_Command(struct scsi_cmnd *SCpnt);
--int Psi240i_Abort(struct scsi_cmnd *SCpnt);
--int Psi240i_Reset(struct scsi_cmnd *SCpnt, unsigned int flags);
+-		ULOOP (ST0X_SELECTION_DELAY * 10000) {
+-			status_read = STATUS;
+-			if (status_read & STAT_ARB_CMPL)
+-				break;
+-			if (st0x_aborted)	/* FIXME: What? We are going to do something even after abort? */
+-				break;
+-			if (TIMEOUT || (status_read & STAT_SEL)) {
+-				printk(KERN_WARNING "scsi%d : arbitration lost or timeout.\n", hostno);
+-				WRITE_CONTROL (BASE_CMD);
+-				return retcode (DID_NO_CONNECT);
+-			}
+-		}
+-		DPRINTK (PHASE_SELECTION, "scsi%d : arbitration complete\n", hostno);
 -#endif
-diff --git a/drivers/scsi/psi_chip.h b/drivers/scsi/psi_chip.h
-deleted file mode 100644
-index 224cf8f..0000000
---- a/drivers/scsi/psi_chip.h
-+++ /dev/null
-@@ -1,195 +0,0 @@
--/*+M*************************************************************************
-- * Perceptive Solutions, Inc. PSI-240I device driver proc support for Linux.
-- *
-- * Copyright (c) 1997 Perceptive Solutions, 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, or (at your option)
-- * any later version.
-- *
-- * This program is distributed in the hope that it will be useful,
-- * but WITHOUT ANY WARRANTY; without even the implied warranty of
-- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See 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, 675 Mass Ave, Cambridge, MA 02139, USA.
-- *
-- *
-- *	File Name:	psi_chip.h
-- *
-- *	Description:	This file contains the interface defines and
-- *					error codes.
-- *
-- *-M*************************************************************************/
--#ifndef PSI_CHIP
--#define PSI_CHIP
 -
--/************************************************/
--/*		Misc konstants							*/
--/************************************************/
--#define	CHIP_MAXDRIVES			8
+-		/*
+-		 *    When the SCSI device decides that we're gawking at it, 
+-		 *    it will respond by asserting BUSY on the bus.
+-		 *
+-		 *    Note : the Seagate ST-01/02 product manual says that we
+-		 *    should twiddle the DATA register before the control
+-		 *    register. However, this does not work reliably so we do
+-		 *    it the other way around.
+-		 *
+-		 *    Probably could be a problem with arbitration too, we
+-		 *    really should try this with a SCSI protocol or logic 
+-		 *    analyzer to see what is going on.
+-		 */
+-		tmp_data = (unsigned char) ((1 << target) | (controller_type == SEAGATE ? 0x80 : 0x40));
+-		tmp_control = BASE_CMD | CMD_DRVR_ENABLE | CMD_SEL | (reselect ? CMD_ATTN : 0);
 -
--/************************************************/
--/*		Chip I/O addresses						*/
--/************************************************/
--#define	CHIP_ADRS_0				0x0130
--#define	CHIP_ADRS_1				0x0150
--#define	CHIP_ADRS_2				0x0190
--#define	CHIP_ADRS_3				0x0210
--#define	CHIP_ADRS_4				0x0230
--#define	CHIP_ADRS_5				0x0250
+-		/* FIXME: verify host lock is always held here */
+-#ifdef OLDCNTDATASCEME
+-#ifdef SWAPCNTDATA
+-		WRITE_CONTROL (tmp_control);
+-		WRITE_DATA (tmp_data);
+-#else
+-		WRITE_DATA (tmp_data);
+-		WRITE_CONTROL (tmp_control);
+-#endif
+-#else
+-		tmp_control ^= CMD_BSY;	/* This is guesswork. What used to be in driver    */
+-		WRITE_CONTROL (tmp_control);	/* could never work: it sent data into control     */
+-		WRITE_DATA (tmp_data);	/* register and control info into data. Hopefully  */
+-		tmp_control ^= CMD_BSY;	/* fixed, but order of first two may be wrong.     */
+-		WRITE_CONTROL (tmp_control);	/* -- pavel at ucw.cz   */
+-#endif
 -
--/************************************************/
--/*		EEPROM locations		*/
--/************************************************/
--#define	CHIP_EEPROM_BIOS		0x0000		// BIOS base address
--#define	CHIP_EEPROM_DATA		0x2000	   	// SETUP data base address
--#define	CHIP_EEPROM_FACTORY		0x2400	   	// FACTORY data base address
--#define	CHIP_EEPROM_SETUP		0x3000	   	// SETUP PROGRAM base address
+-		ULOOP (250 * 1000) {
+-			if (st0x_aborted) {
+-				/*
+-				 *	If we have been aborted, and we have a
+-				 *	command in progress, IE the target 
+-				 *	still has BSY asserted, then we will
+-				 *	reset the bus, and notify the midlevel
+-				 *	driver to expect sense.
+-				 */
 -
--#define	CHIP_EEPROM_SIZE		32768U	   	// size of the entire EEPROM
--#define	CHIP_EEPROM_BIOS_SIZE	8192	   	// size of the BIOS in bytes
--#define	CHIP_EEPROM_DATA_SIZE	4096	   	// size of factory, setup, log data block in bytes
--#define	CHIP_EEPROM_SETUP_SIZE	20480U	   	// size of the setup program in bytes
+-				WRITE_CONTROL (BASE_CMD);
+-				if (STATUS & STAT_BSY) {
+-					printk(KERN_WARNING "scsi%d : BST asserted after we've been aborted.\n", hostno);
+-					seagate_st0x_bus_reset(NULL);
+-					return retcode (DID_RESET);
+-				}
+-				return retcode (st0x_aborted);
+-			}
+-			if (STATUS & STAT_BSY)
+-				break;
+-			if (TIMEOUT) {
+-				DPRINTK (PHASE_SELECTION, "scsi%d : NO CONNECT with target %d, stat = %x \n", hostno, target, STATUS);
+-				return retcode (DID_NO_CONNECT);
+-			}
+-		}
 -
--/************************************************/
--/*		Chip Interrupts							*/
--/************************************************/
--#define	CHIP_IRQ_10				0x72
--#define	CHIP_IRQ_11				0x73
--#define	CHIP_IRQ_12				0x74
+-		/* Establish current pointers.  Take into account scatter / gather */
 -
--/************************************************/
--/*		Chip Setup addresses		*/
--/************************************************/
--#define	CHIP_SETUP_BASE			0x0000C000L
+-		if ((nobuffs = SCint->use_sg)) {
+-#if (DEBUG & DEBUG_SG)
+-			{
+-				int i;
+-				printk("scsi%d : scatter gather requested, using %d buffers.\n", hostno, nobuffs);
+-				for (i = 0; i < nobuffs; ++i)
+-					printk("scsi%d : buffer %d address = %p length = %d\n",
+-					     hostno, i,
+-					     sg_virt(&buffer[i]),
+-					     buffer[i].length);
+-			}
+-#endif
 -
--/************************************************/
--/*		Chip Register address offsets	*/
--/************************************************/
--#define	REG_DATA				0x00
--#define	REG_ERROR				0x01
--#define	REG_SECTOR_COUNT		0x02
--#define	REG_LBA_0				0x03
--#define	REG_LBA_8				0x04
--#define	REG_LBA_16				0x05
--#define	REG_LBA_24				0x06
--#define	REG_STAT_CMD			0x07
--#define	REG_SEL_FAIL			0x08
--#define	REG_IRQ_STATUS			0x09
--#define	REG_ADDRESS				0x0A
--#define	REG_FAIL				0x0C
--#define	REG_ALT_STAT		   	0x0E
--#define	REG_DRIVE_ADRS			0x0F
+-			buffer = (struct scatterlist *) SCint->request_buffer;
+-			len = buffer->length;
+-			data = sg_virt(buffer);
+-		} else {
+-			DPRINTK (DEBUG_SG, "scsi%d : scatter gather not requested.\n", hostno);
+-			buffer = NULL;
+-			len = SCint->request_bufflen;
+-			data = (unsigned char *) SCint->request_buffer;
+-		}
 -
--/************************************************/
--/*		Chip RAM locations		*/
--/************************************************/
--#define	CHIP_DEVICE				0x8000
--#define	CHIP_DEVICE_0			0x8000
--#define CHIP_DEVICE_1			0x8008
--#define	CHIP_DEVICE_2			0x8010
--#define	CHIP_DEVICE_3			0x8018
--#define	CHIP_DEVICE_4			0x8020
--#define	CHIP_DEVICE_5			0x8028
--#define	CHIP_DEVICE_6			0x8030
--#define	CHIP_DEVICE_7			0x8038
--typedef struct
--	{
--	UCHAR	channel;		// channel of this device (0-8).
--	UCHAR	spt;			// Sectors Per Track.
--	ULONG	spc;			// Sectors Per Cylinder.
--	}	CHIP_DEVICE_N;
+-		DPRINTK (PHASE_DATAIN | PHASE_DATAOUT, "scsi%d : len = %d\n",
+-			 hostno, len);
 -
--#define	CHIP_CONFIG				0x8100		// address of boards configuration.
--typedef struct
--	{
--	UCHAR		irq;			// interrupt request channel number
--	UCHAR		numDrives;		// Number of accessible drives
--	UCHAR		fastFormat;	 	// Boolean for fast format enable
--	}	CHIP_CONFIG_N;
+-		break;
+-#ifdef LINKED
+-	case LINKED_RIGHT:
+-		break;
+-	case LINKED_WRONG:
+-		break;
+-#endif
+-	}			/* end of switch(reselect) */
 -
--#define	CHIP_MAP				0x8108 		// eight byte device type map.
+-	/*
+-	 *    There are several conditions under which we wish to send a message :
+-	 *      1.  When we are allowing disconnect / reconnect, and need to
+-	 *	establish the I_T_L nexus via an IDENTIFY with the DiscPriv bit
+-	 *	set.
+-	 *
+-	 *      2.  When we are doing linked commands, are have the wrong I_T_L
+-	 *	nexus established and want to send an ABORT message.
+-	 */
 -
+-	/* GCC does not like an ifdef inside a macro, so do it the hard way. */
+-#ifdef LINKED
+-	WRITE_CONTROL (BASE_CMD | CMD_DRVR_ENABLE | (((reselect == CAN_RECONNECT)|| (reselect == LINKED_WRONG))? CMD_ATTN : 0));
+-#else
+-	WRITE_CONTROL (BASE_CMD | CMD_DRVR_ENABLE | (((reselect == CAN_RECONNECT))? CMD_ATTN : 0));
+-#endif
 -
--#define	CHIP_RAID				0x8120 		// array of RAID signature structures and LBA
--#define	CHIP_RAID_1				0x8120
--#define CHIP_RAID_2				0x8130
--#define	CHIP_RAID_3				0x8140
--#define	CHIP_RAID_4				0x8150
+-	/*
+-	 *    INFORMATION TRANSFER PHASE
+-	 *
+-	 *      The nasty looking read / write inline assembler loops we use for
+-	 *      DATAIN and DATAOUT phases are approximately 4-5 times as fast as
+-	 *      the 'C' versions - since we're moving 1024 bytes of data, this
+-	 *      really adds up.
+-	 *
+-	 *      SJT: The nasty-looking assembler is gone, so it's slower.
+-	 *
+-	 */
 -
--/************************************************/
--/*		Chip Register Masks		*/
--/************************************************/
--#define	CHIP_ID					0x7B
--#define	SEL_RAM					0x8000
--#define	MASK_FAIL				0x80
+-	DPRINTK (PHASE_ETC, "scsi%d : phase = INFORMATION TRANSFER\n", hostno);
 -
--/************************************************/
--/*		Chip cable select bits		*/
--/************************************************/
--#define	SECTORSXFER				8
+-	incommand = 1;
+-	transfersize = SCint->transfersize;
+-	underflow = SCint->underflow;
 -
--/************************************************/
--/*		Chip cable select bits		*/
--/************************************************/
--#define	SEL_NONE				0x00
--#define	SEL_1					0x01
--#define	SEL_2					0x02
--#define	SEL_3					0x04
--#define	SEL_4					0x08
+-	/*
+-	 *	Now, we poll the device for status information,
+-	 *      and handle any requests it makes.  Note that since we are unsure
+-	 *	of how much data will be flowing across the system, etc and
+-	 *	cannot make reasonable timeouts, that we will instead have the
+-	 *	midlevel driver handle any timeouts that occur in this phase.
+-	 */
 -
--/************************************************/
--/*		Programmable Interrupt Controller*/
--/************************************************/
--#define	PIC1					0x20		// first 8259 base port address
--#define	PIC2					0xA0		// second 8259 base port address
--#define	INT_OCW1				1			// Operation Control Word 1: IRQ mask
--#define	EOI						0x20		// non-specific end-of-interrupt
+-	while (((status_read = STATUS) & STAT_BSY) && !st0x_aborted && !done) {
+-#ifdef PARITY
+-		if (status_read & STAT_PARITY) {
+-			printk(KERN_ERR "scsi%d : got parity error\n", hostno);
+-			st0x_aborted = DID_PARITY;
+-		}
+-#endif
+-		if (status_read & STAT_REQ) {
+-#if ((DEBUG & PHASE_ETC) == PHASE_ETC)
+-			if ((newphase = (status_read & REQ_MASK)) != phase) {
+-				phase = newphase;
+-				switch (phase) {
+-				case REQ_DATAOUT:
+-					printk ("scsi%d : phase = DATA OUT\n", hostno);
+-					break;
+-				case REQ_DATAIN:
+-					printk ("scsi%d : phase = DATA IN\n", hostno);
+-					break;
+-				case REQ_CMDOUT:
+-					printk
+-					    ("scsi%d : phase = COMMAND OUT\n", hostno);
+-					break;
+-				case REQ_STATIN:
+-					printk ("scsi%d : phase = STATUS IN\n",	hostno);
+-					break;
+-				case REQ_MSGOUT:
+-					printk
+-					    ("scsi%d : phase = MESSAGE OUT\n", hostno);
+-					break;
+-				case REQ_MSGIN:
+-					printk ("scsi%d : phase = MESSAGE IN\n", hostno);
+-					break;
+-				default:
+-					printk ("scsi%d : phase = UNKNOWN\n", hostno);
+-					st0x_aborted = DID_ERROR;
+-				}
+-			}
+-#endif
+-			switch (status_read & REQ_MASK) {
+-			case REQ_DATAOUT:
+-				/*
+-				 * If we are in fast mode, then we simply splat
+-				 * the data out in word-sized chunks as fast as
+-				 * we can.
+-				 */
 -
--/************************************************/
--/*		Device/Geometry controls				*/
--/************************************************/
--#define GEOMETRY_NONE		 	0x0			// No device
--#define GEOMETRY_AUTO			0x1			// Geometry set automatically
--#define GEOMETRY_USER		 	0x2			// User supplied geometry
+-				if (!len) {
+-#if 0
+-					printk("scsi%d: underflow to target %d lun %d \n", hostno, target, lun);
+-					st0x_aborted = DID_ERROR;
+-					fast = 0;
+-#endif
+-					break;
+-				}
 -
--#define	DEVICE_NONE				0x0			// No device present
--#define	DEVICE_INACTIVE			0x1			// device present but not registered active
--#define	DEVICE_ATAPI			0x2			// ATAPI device (CD_ROM, Tape, Etc...)
--#define	DEVICE_DASD_NONLBA		0x3			// Non LBA incompatible device
--#define	DEVICE_DASD_LBA			0x4			// LBA compatible device
+-				if (fast && transfersize
+-				    && !(len % transfersize)
+-				    && (len >= transfersize)
+-#ifdef FAST32
+-				    && !(transfersize % 4)
+-#endif
+-				    ) {
+-					DPRINTK (DEBUG_FAST,
+-						 "scsi%d : FAST transfer, underflow = %d, transfersize = %d\n"
+-						 "         len = %d, data = %08x\n",
+-						 hostno, SCint->underflow,
+-						 SCint->transfersize, len,
+-						 data);
 -
--/************************************************/
--/*		Setup Structure Definitions	*/
--/************************************************/
--typedef struct							// device setup parameters
--	{
--	UCHAR			geometryControl;	// geometry control flags
--	UCHAR		   	device;				// device code
--	USHORT			sectors;			// number of sectors per track
--	USHORT			heads;				// number of heads
--	USHORT			cylinders;			// number of cylinders for this device
--	ULONG			blocks;				// number of blocks on device
--	USHORT			spare1;
--	USHORT			spare2;
--	} SETUP_DEVICE, *PSETUP_DEVICE;
+-			/* SJT: Start. Fast Write */
+-#ifdef SEAGATE_USE_ASM
+-					__asm__ ("cld\n\t"
+-#ifdef FAST32
+-						 "shr $2, %%ecx\n\t"
+-						 "1:\t"
+-						 "lodsl\n\t"
+-						 "movl %%eax, (%%edi)\n\t"
+-#else
+-						 "1:\t"
+-						 "lodsb\n\t"
+-						 "movb %%al, (%%edi)\n\t"
+-#endif
+-						 "loop 1b;"
+-				      /* output */ :
+-				      /* input */ :"D" (st0x_dr),
+-						 "S"
+-						 (data),
+-						 "c" (SCint->transfersize)
+-/* clobbered */
+-				      :	 "eax", "ecx",
+-						 "esi");
+-#else				/* SEAGATE_USE_ASM */
+-					memcpy_toio(st0x_dr, data, transfersize);
+-#endif				/* SEAGATE_USE_ASM */
+-/* SJT: End */
+-					len -= transfersize;
+-					data += transfersize;
+-					DPRINTK (DEBUG_FAST, "scsi%d : FAST transfer complete len = %d data = %08x\n", hostno, len, data);
+-				} else {
+-					/*
+-					 *    We loop as long as we are in a 
+-					 *    data out phase, there is data to
+-					 *    send, and BSY is still active.
+-					 */
 -
--typedef struct		// master setup structure
--	{
--	USHORT 			startupDelay;
--	USHORT 			promptBIOS;
--	USHORT 			fastFormat;
--	USHORT			spare2;
--	USHORT			spare3;
--	USHORT			spare4;
--	USHORT			spare5;
--	USHORT			spare6;
--	SETUP_DEVICE	setupDevice[8];
--	}	SETUP, *PSETUP;
+-/* SJT: Start. Slow Write. */
+-#ifdef SEAGATE_USE_ASM
+-
+-					int __dummy_1, __dummy_2;
+-
+-/*
+- *      We loop as long as we are in a data out phase, there is data to send, 
+- *      and BSY is still active.
+- */
+-/* Local variables : len = ecx , data = esi, 
+-                     st0x_cr_sr = ebx, st0x_dr =  edi
+-*/
+-					__asm__ (
+-							/* Test for any data here at all. */
+-							"orl %%ecx, %%ecx\n\t"
+-							"jz 2f\n\t" "cld\n\t"
+-/*                    "movl st0x_cr_sr, %%ebx\n\t"  */
+-/*                    "movl st0x_dr, %%edi\n\t"  */
+-							"1:\t"
+-							"movb (%%ebx), %%al\n\t"
+-							/* Test for BSY */
+-							"test $1, %%al\n\t"
+-							"jz 2f\n\t"
+-							/* Test for data out phase - STATUS & REQ_MASK should be 
+-							   REQ_DATAOUT, which is 0. */
+-							"test $0xe, %%al\n\t"
+-							"jnz 2f\n\t"
+-							/* Test for REQ */
+-							"test $0x10, %%al\n\t"
+-							"jz 1b\n\t"
+-							"lodsb\n\t"
+-							"movb %%al, (%%edi)\n\t"
+-							"loop 1b\n\t" "2:\n"
+-				      /* output */ :"=S" (data), "=c" (len),
+-							"=b"
+-							(__dummy_1),
+-							"=D" (__dummy_2)
+-/* input */
+-				      :		"0" (data), "1" (len),
+-							"2" (st0x_cr_sr),
+-							"3" (st0x_dr)
+-/* clobbered */
+-				      :		"eax");
+-#else				/* SEAGATE_USE_ASM */
+-					while (len) {
+-						unsigned char stat;
+-
+-						stat = STATUS;
+-						if (!(stat & STAT_BSY)
+-						    || ((stat & REQ_MASK) !=
+-							REQ_DATAOUT))
+-							break;
+-						if (stat & STAT_REQ) {
+-							WRITE_DATA (*data++);
+-							--len;
+-						}
+-					}
+-#endif				/* SEAGATE_USE_ASM */
+-/* SJT: End. */
+-				}
+-
+-				if (!len && nobuffs) {
+-					--nobuffs;
+-					++buffer;
+-					len = buffer->length;
+-					data = sg_virt(buffer);
+-					DPRINTK (DEBUG_SG,
+-						 "scsi%d : next scatter-gather buffer len = %d address = %08x\n",
+-						 hostno, len, data);
+-				}
+-				break;
 -
+-			case REQ_DATAIN:
+-#ifdef SLOW_RATE
+-				if (borken) {
+-#if (DEBUG & (PHASE_DATAIN))
+-					transfered += len;
+-#endif
+-					for (; len && (STATUS & (REQ_MASK | STAT_REQ)) == (REQ_DATAIN | STAT_REQ); --len) {
+-						*data++ = DATA;
+-						borken_wait();
+-					}
+-#if (DEBUG & (PHASE_DATAIN))
+-					transfered -= len;
+-#endif
+-				} else
 -#endif
 -
-diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c
-index 2886407..c94906a 100644
---- a/drivers/scsi/qla1280.c
-+++ b/drivers/scsi/qla1280.c
-@@ -528,7 +528,7 @@ __setup("qla1280=", qla1280_setup);
- #define	CMD_CDBLEN(Cmnd)	Cmnd->cmd_len
- #define	CMD_CDBP(Cmnd)		Cmnd->cmnd
- #define	CMD_SNSP(Cmnd)		Cmnd->sense_buffer
--#define	CMD_SNSLEN(Cmnd)	sizeof(Cmnd->sense_buffer)
-+#define	CMD_SNSLEN(Cmnd)	SCSI_SENSE_BUFFERSIZE
- #define	CMD_RESULT(Cmnd)	Cmnd->result
- #define	CMD_HANDLE(Cmnd)	Cmnd->host_scribble
- #define CMD_REQUEST(Cmnd)	Cmnd->request->cmd
-@@ -3715,7 +3715,7 @@ qla1280_status_entry(struct scsi_qla_host *ha, struct response *pkt,
- 			} else
- 				sense_sz = 0;
- 			memset(cmd->sense_buffer + sense_sz, 0,
--			       sizeof(cmd->sense_buffer) - sense_sz);
-+			       SCSI_SENSE_BUFFERSIZE - sense_sz);
- 
- 			dprintk(2, "qla1280_status_entry: Check "
- 				"condition Sense data, b %i, t %i, "
-diff --git a/drivers/scsi/qla2xxx/Makefile b/drivers/scsi/qla2xxx/Makefile
-index 71ddb5d..c51fd1f 100644
---- a/drivers/scsi/qla2xxx/Makefile
-+++ b/drivers/scsi/qla2xxx/Makefile
-@@ -1,4 +1,4 @@
- qla2xxx-y := qla_os.o qla_init.o qla_mbx.o qla_iocb.o qla_isr.o qla_gs.o \
--		qla_dbg.o qla_sup.o qla_attr.o qla_mid.o
-+		qla_dbg.o qla_sup.o qla_attr.o qla_mid.o qla_dfs.o
- 
- obj-$(CONFIG_SCSI_QLA_FC) += qla2xxx.o
-diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c
-index fb388b8..adf9732 100644
---- a/drivers/scsi/qla2xxx/qla_attr.c
-+++ b/drivers/scsi/qla2xxx/qla_attr.c
-@@ -9,7 +9,7 @@
- #include <linux/kthread.h>
- #include <linux/vmalloc.h>
- 
--int qla24xx_vport_disable(struct fc_vport *, bool);
-+static int qla24xx_vport_disable(struct fc_vport *, bool);
- 
- /* SYSFS attributes --------------------------------------------------------- */
- 
-@@ -958,7 +958,7 @@ qla2x00_issue_lip(struct Scsi_Host *shost)
- {
- 	scsi_qla_host_t *ha = shost_priv(shost);
- 
--	set_bit(LOOP_RESET_NEEDED, &ha->dpc_flags);
-+	qla2x00_loop_reset(ha);
- 	return 0;
- }
- 
-@@ -967,35 +967,51 @@ qla2x00_get_fc_host_stats(struct Scsi_Host *shost)
- {
- 	scsi_qla_host_t *ha = shost_priv(shost);
- 	int rval;
--	uint16_t mb_stat[1];
--	link_stat_t stat_buf;
-+	struct link_statistics *stats;
-+	dma_addr_t stats_dma;
- 	struct fc_host_statistics *pfc_host_stat;
- 
--	rval = QLA_FUNCTION_FAILED;
- 	pfc_host_stat = &ha->fc_host_stat;
- 	memset(pfc_host_stat, -1, sizeof(struct fc_host_statistics));
- 
-+	stats = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &stats_dma);
-+	if (stats == NULL) {
-+		DEBUG2_3_11(printk("%s(%ld): Failed to allocate memory.\n",
-+		    __func__, ha->host_no));
-+		goto done;
-+	}
-+	memset(stats, 0, DMA_POOL_SIZE);
-+
-+	rval = QLA_FUNCTION_FAILED;
- 	if (IS_FWI2_CAPABLE(ha)) {
--		rval = qla24xx_get_isp_stats(ha, (uint32_t *)&stat_buf,
--		    sizeof(stat_buf) / 4, mb_stat);
-+		rval = qla24xx_get_isp_stats(ha, stats, stats_dma);
- 	} else if (atomic_read(&ha->loop_state) == LOOP_READY &&
- 		    !test_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags) &&
- 		    !test_bit(ISP_ABORT_NEEDED, &ha->dpc_flags) &&
- 		    !ha->dpc_active) {
- 		/* Must be in a 'READY' state for statistics retrieval. */
--		rval = qla2x00_get_link_status(ha, ha->loop_id, &stat_buf,
--		    mb_stat);
-+		rval = qla2x00_get_link_status(ha, ha->loop_id, stats,
-+		    stats_dma);
- 	}
- 
- 	if (rval != QLA_SUCCESS)
--		goto done;
-+		goto done_free;
-+
-+	pfc_host_stat->link_failure_count = stats->link_fail_cnt;
-+	pfc_host_stat->loss_of_sync_count = stats->loss_sync_cnt;
-+	pfc_host_stat->loss_of_signal_count = stats->loss_sig_cnt;
-+	pfc_host_stat->prim_seq_protocol_err_count = stats->prim_seq_err_cnt;
-+	pfc_host_stat->invalid_tx_word_count = stats->inval_xmit_word_cnt;
-+	pfc_host_stat->invalid_crc_count = stats->inval_crc_cnt;
-+	if (IS_FWI2_CAPABLE(ha)) {
-+		pfc_host_stat->tx_frames = stats->tx_frames;
-+		pfc_host_stat->rx_frames = stats->rx_frames;
-+		pfc_host_stat->dumped_frames = stats->dumped_frames;
-+		pfc_host_stat->nos_count = stats->nos_rcvd;
-+	}
- 
--	pfc_host_stat->link_failure_count = stat_buf.link_fail_cnt;
--	pfc_host_stat->loss_of_sync_count = stat_buf.loss_sync_cnt;
--	pfc_host_stat->loss_of_signal_count = stat_buf.loss_sig_cnt;
--	pfc_host_stat->prim_seq_protocol_err_count = stat_buf.prim_seq_err_cnt;
--	pfc_host_stat->invalid_tx_word_count = stat_buf.inval_xmit_word_cnt;
--	pfc_host_stat->invalid_crc_count = stat_buf.inval_crc_cnt;
-+done_free:
-+        dma_pool_free(ha->s_dma_pool, stats, stats_dma);
- done:
- 	return pfc_host_stat;
- }
-@@ -1113,7 +1129,7 @@ vport_create_failed_2:
- 	return FC_VPORT_FAILED;
- }
- 
--int
-+static int
- qla24xx_vport_delete(struct fc_vport *fc_vport)
- {
- 	scsi_qla_host_t *ha = shost_priv(fc_vport->shost);
-@@ -1124,7 +1140,7 @@ qla24xx_vport_delete(struct fc_vport *fc_vport)
- 
- 	down(&ha->vport_sem);
- 	ha->cur_vport_count--;
--	clear_bit(vha->vp_idx, (unsigned long *)ha->vp_idx_map);
-+	clear_bit(vha->vp_idx, ha->vp_idx_map);
- 	up(&ha->vport_sem);
- 
- 	kfree(vha->node_name);
-@@ -1146,7 +1162,7 @@ qla24xx_vport_delete(struct fc_vport *fc_vport)
- 	return 0;
- }
- 
--int
-+static int
- qla24xx_vport_disable(struct fc_vport *fc_vport, bool disable)
- {
- 	scsi_qla_host_t *vha = fc_vport->dd_data;
-diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c
-index eaa04da..d88e98c 100644
---- a/drivers/scsi/qla2xxx/qla_dbg.c
-+++ b/drivers/scsi/qla2xxx/qla_dbg.c
-@@ -1051,6 +1051,7 @@ qla25xx_fw_dump(scsi_qla_host_t *ha, int hardware_locked)
- 	struct qla25xx_fw_dump *fw;
- 	uint32_t	ext_mem_cnt;
- 	void		*nxt;
-+	struct qla2xxx_fce_chain *fcec;
- 
- 	risc_address = ext_mem_cnt = 0;
- 	flags = 0;
-@@ -1321,10 +1322,31 @@ qla25xx_fw_dump(scsi_qla_host_t *ha, int hardware_locked)
- 	if (rval != QLA_SUCCESS)
- 		goto qla25xx_fw_dump_failed_0;
- 
-+	/* Fibre Channel Trace Buffer. */
- 	nxt = qla2xxx_copy_queues(ha, nxt);
- 	if (ha->eft)
- 		memcpy(nxt, ha->eft, ntohl(ha->fw_dump->eft_size));
- 
-+	/* Fibre Channel Event Buffer. */
-+	if (!ha->fce)
-+		goto qla25xx_fw_dump_failed_0;
-+
-+	ha->fw_dump->version |= __constant_htonl(DUMP_CHAIN_VARIANT);
-+
-+	fcec = nxt + ntohl(ha->fw_dump->eft_size);
-+	fcec->type = __constant_htonl(DUMP_CHAIN_FCE | DUMP_CHAIN_LAST);
-+	fcec->chain_size = htonl(sizeof(struct qla2xxx_fce_chain) +
-+	    fce_calc_size(ha->fce_bufs));
-+	fcec->size = htonl(fce_calc_size(ha->fce_bufs));
-+	fcec->addr_l = htonl(LSD(ha->fce_dma));
-+	fcec->addr_h = htonl(MSD(ha->fce_dma));
-+
-+	iter_reg = fcec->eregs;
-+	for (cnt = 0; cnt < 8; cnt++)
-+		*iter_reg++ = htonl(ha->fce_mb[cnt]);
-+
-+	memcpy(iter_reg, ha->fce, ntohl(fcec->size));
-+
- qla25xx_fw_dump_failed_0:
- 	if (rval != QLA_SUCCESS) {
- 		qla_printk(KERN_WARNING, ha,
-@@ -1428,21 +1450,6 @@ qla2x00_print_scsi_cmd(struct scsi_cmnd * cmd)
- 	printk("  sp flags=0x%x\n", sp->flags);
- }
- 
--void
--qla2x00_dump_pkt(void *pkt)
--{
--	uint32_t i;
--	uint8_t *data = (uint8_t *) pkt;
+-					if (fast && transfersize
+-					    && !(len % transfersize)
+-					    && (len >= transfersize)
+-#ifdef FAST32
+-					    && !(transfersize % 4)
+-#endif
+-				    ) {
+-					DPRINTK (DEBUG_FAST,
+-						 "scsi%d : FAST transfer, underflow = %d, transfersize = %d\n"
+-						 "         len = %d, data = %08x\n",
+-						 hostno, SCint->underflow,
+-						 SCint->transfersize, len,
+-						 data);
+-
+-/* SJT: Start. Fast Read */
+-#ifdef SEAGATE_USE_ASM
+-					__asm__ ("cld\n\t"
+-#ifdef FAST32
+-						 "shr $2, %%ecx\n\t"
+-						 "1:\t"
+-						 "movl (%%esi), %%eax\n\t"
+-						 "stosl\n\t"
+-#else
+-						 "1:\t"
+-						 "movb (%%esi), %%al\n\t"
+-						 "stosb\n\t"
+-#endif
+-						 "loop 1b\n\t"
+-				      /* output */ :
+-				      /* input */ :"S" (st0x_dr),
+-						 "D"
+-						 (data),
+-						 "c" (SCint->transfersize)
+-/* clobbered */
+-				      :	 "eax", "ecx",
+-						 "edi");
+-#else				/* SEAGATE_USE_ASM */
+-					memcpy_fromio(data, st0x_dr, len);
+-#endif				/* SEAGATE_USE_ASM */
+-/* SJT: End */
+-					len -= transfersize;
+-					data += transfersize;
+-#if (DEBUG & PHASE_DATAIN)
+-					printk ("scsi%d: transfered += %d\n", hostno, transfersize);
+-					transfered += transfersize;
+-#endif
+-
+-					DPRINTK (DEBUG_FAST, "scsi%d : FAST transfer complete len = %d data = %08x\n", hostno, len, data);
+-				} else {
+-
+-#if (DEBUG & PHASE_DATAIN)
+-					printk ("scsi%d: transfered += %d\n", hostno, len);
+-					transfered += len;	/* Assume we'll transfer it all, then
+-								   subtract what we *didn't* transfer */
+-#endif
+-
+-/*
+- *	We loop as long as we are in a data in phase, there is room to read,
+- *      and BSY is still active
+- */
+-
+-/* SJT: Start. */
+-#ifdef SEAGATE_USE_ASM
+-
+-					int __dummy_3, __dummy_4;
+-
+-/* Dummy clobbering variables for the new gcc-2.95 */
+-
+-/*
+- *      We loop as long as we are in a data in phase, there is room to read, 
+- *      and BSY is still active
+- */
+-					/* Local variables : ecx = len, edi = data
+-					   esi = st0x_cr_sr, ebx = st0x_dr */
+-					__asm__ (
+-							/* Test for room to read */
+-							"orl %%ecx, %%ecx\n\t"
+-							"jz 2f\n\t" "cld\n\t"
+-/*                "movl st0x_cr_sr, %%esi\n\t"  */
+-/*                "movl st0x_dr, %%ebx\n\t"  */
+-							"1:\t"
+-							"movb (%%esi), %%al\n\t"
+-							/* Test for BSY */
+-							"test $1, %%al\n\t"
+-							"jz 2f\n\t"
+-							/* Test for data in phase - STATUS & REQ_MASK should be REQ_DATAIN, 
+-							   = STAT_IO, which is 4. */
+-							"movb $0xe, %%ah\n\t"
+-							"andb %%al, %%ah\n\t"
+-							"cmpb $0x04, %%ah\n\t"
+-							"jne 2f\n\t"
+-							/* Test for REQ */
+-							"test $0x10, %%al\n\t"
+-							"jz 1b\n\t"
+-							"movb (%%ebx), %%al\n\t"
+-							"stosb\n\t"
+-							"loop 1b\n\t" "2:\n"
+-				      /* output */ :"=D" (data), "=c" (len),
+-							"=S"
+-							(__dummy_3),
+-							"=b" (__dummy_4)
+-/* input */
+-				      :		"0" (data), "1" (len),
+-							"2" (st0x_cr_sr),
+-							"3" (st0x_dr)
+-/* clobbered */
+-				      :		"eax");
+-#else				/* SEAGATE_USE_ASM */
+-					while (len) {
+-						unsigned char stat;
 -
--	for (i = 0; i < 64; i++) {
--		if (!(i % 4))
--			printk("\n%02x: ", i);
+-						stat = STATUS;
+-						if (!(stat & STAT_BSY)
+-						    || ((stat & REQ_MASK) !=
+-							REQ_DATAIN))
+-							break;
+-						if (stat & STAT_REQ) {
+-							*data++ = DATA;
+-							--len;
+-						}
+-					}
+-#endif				/* SEAGATE_USE_ASM */
+-/* SJT: End. */
+-#if (DEBUG & PHASE_DATAIN)
+-					printk ("scsi%d: transfered -= %d\n", hostno, len);
+-					transfered -= len;	/* Since we assumed all of Len got  *
+-								   transfered, correct our mistake */
+-#endif
+-				}
 -
--		printk("%02x ", data[i]);
--	}
--	printk("\n");
--}
+-				if (!len && nobuffs) {
+-					--nobuffs;
+-					++buffer;
+-					len = buffer->length;
+-					data = sg_virt(buffer);
+-					DPRINTK (DEBUG_SG, "scsi%d : next scatter-gather buffer len = %d address = %08x\n", hostno, len, data);
+-				}
+-				break;
 -
- #if defined(QL_DEBUG_ROUTINES)
- /*
-  * qla2x00_formatted_dump_buffer
-diff --git a/drivers/scsi/qla2xxx/qla_dbg.h b/drivers/scsi/qla2xxx/qla_dbg.h
-index a50ecf0..524598a 100644
---- a/drivers/scsi/qla2xxx/qla_dbg.h
-+++ b/drivers/scsi/qla2xxx/qla_dbg.h
-@@ -256,6 +256,25 @@ struct qla25xx_fw_dump {
- #define EFT_BYTES_PER_BUFFER	0x4000
- #define EFT_SIZE		((EFT_BYTES_PER_BUFFER) * (EFT_NUM_BUFFERS))
- 
-+#define FCE_NUM_BUFFERS		64
-+#define FCE_BYTES_PER_BUFFER	0x400
-+#define FCE_SIZE		((FCE_BYTES_PER_BUFFER) * (FCE_NUM_BUFFERS))
-+#define fce_calc_size(b)	((FCE_BYTES_PER_BUFFER) * (b))
-+
-+struct qla2xxx_fce_chain {
-+	uint32_t type;
-+	uint32_t chain_size;
-+
-+	uint32_t size;
-+	uint32_t addr_l;
-+	uint32_t addr_h;
-+	uint32_t eregs[8];
-+};
-+
-+#define DUMP_CHAIN_VARIANT	0x80000000
-+#define DUMP_CHAIN_FCE		0x7FFFFAF0
-+#define DUMP_CHAIN_LAST		0x80000000
-+
- struct qla2xxx_fw_dump {
- 	uint8_t signature[4];
- 	uint32_t version;
-diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
-index 04e8cbc..6f129da 100644
---- a/drivers/scsi/qla2xxx/qla_def.h
-+++ b/drivers/scsi/qla2xxx/qla_def.h
-@@ -623,9 +623,6 @@ typedef struct {
- #define MBC_GET_LINK_PRIV_STATS		0x6d	/* Get link & private data. */
- #define MBC_SET_VENDOR_ID		0x76	/* Set Vendor ID. */
- 
--#define TC_ENABLE			4
--#define TC_DISABLE			5
+-			case REQ_CMDOUT:
+-				while (((status_read = STATUS) & STAT_BSY) &&
+-				       ((status_read & REQ_MASK) == REQ_CMDOUT))
+-					if (status_read & STAT_REQ) {
+-						WRITE_DATA (*(const unsigned char *) cmnd);
+-						cmnd = 1 + (const unsigned char *)cmnd;
+-#ifdef SLOW_RATE
+-						if (borken)
+-							borken_wait ();
+-#endif
+-					}
+-				break;
 -
- /* Firmware return data sizes */
- #define FCAL_MAP_SIZE	128
- 
-@@ -862,14 +859,20 @@ typedef struct {
- #define GLSO_SEND_RPS	BIT_0
- #define GLSO_USE_DID	BIT_3
- 
--typedef struct {
--	uint32_t	link_fail_cnt;
--	uint32_t	loss_sync_cnt;
--	uint32_t	loss_sig_cnt;
--	uint32_t	prim_seq_err_cnt;
--	uint32_t	inval_xmit_word_cnt;
--	uint32_t	inval_crc_cnt;
--} link_stat_t;
-+struct link_statistics {
-+	uint32_t link_fail_cnt;
-+	uint32_t loss_sync_cnt;
-+	uint32_t loss_sig_cnt;
-+	uint32_t prim_seq_err_cnt;
-+	uint32_t inval_xmit_word_cnt;
-+	uint32_t inval_crc_cnt;
-+	uint32_t unused1[0x1b];
-+	uint32_t tx_frames;
-+	uint32_t rx_frames;
-+	uint32_t dumped_frames;
-+	uint32_t unused2[2];
-+	uint32_t nos_rcvd;
-+};
- 
- /*
-  * NVRAM Command values.
-@@ -2116,14 +2119,6 @@ struct qla_msix_entry {
- 
- #define	WATCH_INTERVAL		1       /* number of seconds */
- 
--/* NPIV */
--#define MAX_MULTI_ID_LOOP                     126
--#define MAX_MULTI_ID_FABRIC                    64
--#define MAX_NUM_VPORT_LOOP                      (MAX_MULTI_ID_LOOP - 1)
--#define MAX_NUM_VPORT_FABRIC                    (MAX_MULTI_ID_FABRIC - 1)
--#define MAX_NUM_VHBA_LOOP                       (MAX_MULTI_ID_LOOP - 1)
--#define MAX_NUM_VHBA_FABRIC                     (MAX_MULTI_ID_FABRIC - 1)
+-			case REQ_STATIN:
+-				status = DATA;
+-				break;
 -
- /*
-  * Linux Host Adapter structure
-  */
-@@ -2161,6 +2156,7 @@ typedef struct scsi_qla_host {
- 		uint32_t	gpsc_supported		:1;
- 		uint32_t        vsan_enabled            :1;
- 		uint32_t	npiv_supported		:1;
-+		uint32_t	fce_enabled		:1;
- 	} flags;
- 
- 	atomic_t	loop_state;
-@@ -2273,8 +2269,7 @@ typedef struct scsi_qla_host {
- 
- 	int		bars;
- 	device_reg_t __iomem *iobase;		/* Base I/O address */
--	unsigned long	pio_address;
--	unsigned long	pio_length;
-+	resource_size_t pio_address;
- #define MIN_IOBASE_LEN		0x100
- 
- 	/* ISP ring lock, rings, and indexes */
-@@ -2416,9 +2411,9 @@ typedef struct scsi_qla_host {
- #define MBX_INTR_WAIT	2
- #define MBX_UPDATE_FLASH_ACTIVE	3
- 
--	struct semaphore mbx_cmd_sem;	/* Serialialize mbx access */
- 	struct semaphore vport_sem;	/* Virtual port synchronization */
--	struct semaphore mbx_intr_sem;  /* Used for completion notification */
-+	struct completion mbx_cmd_comp;	/* Serialize mbx access */
-+	struct completion mbx_intr_comp;  /* Used for completion notification */
- 
- 	uint32_t	mbx_flags;
- #define  MBX_IN_PROGRESS	BIT_0
-@@ -2455,6 +2450,15 @@ typedef struct scsi_qla_host {
- 	dma_addr_t	eft_dma;
- 	void		*eft;
- 
-+	struct dentry *dfs_dir;
-+	struct dentry *dfs_fce;
-+	dma_addr_t	fce_dma;
-+	void		*fce;
-+	uint32_t	fce_bufs;
-+	uint16_t	fce_mb[8];
-+	uint64_t	fce_wr, fce_rd;
-+	struct mutex	fce_mutex;
-+
- 	uint8_t		host_str[16];
- 	uint32_t	pci_attr;
- 	uint16_t	chip_revision;
-@@ -2507,7 +2511,7 @@ typedef struct scsi_qla_host {
- 
- 	struct list_head	vp_list;	/* list of VP */
- 	struct fc_vport	*fc_vport;	/* holds fc_vport * for each vport */
--	uint8_t		vp_idx_map[16];
-+	unsigned long	vp_idx_map[(MAX_MULTI_ID_FABRIC / 8) / sizeof(unsigned long)];
- 	uint16_t        num_vhosts;	/* number of vports created */
- 	uint16_t        num_vsans;	/* number of vsan created */
- 	uint16_t        vp_idx;		/* vport ID */
-diff --git a/drivers/scsi/qla2xxx/qla_dfs.c b/drivers/scsi/qla2xxx/qla_dfs.c
-new file mode 100644
-index 0000000..1479c60
---- /dev/null
-+++ b/drivers/scsi/qla2xxx/qla_dfs.c
-@@ -0,0 +1,175 @@
-+/*
-+ * QLogic Fibre Channel HBA Driver
-+ * Copyright (c)  2003-2005 QLogic Corporation
-+ *
-+ * See LICENSE.qla2xxx for copyright and licensing details.
-+ */
-+#include "qla_def.h"
-+
-+#include <linux/debugfs.h>
-+#include <linux/seq_file.h>
-+
-+static struct dentry *qla2x00_dfs_root;
-+static atomic_t qla2x00_dfs_root_count;
-+
-+static int
-+qla2x00_dfs_fce_show(struct seq_file *s, void *unused)
-+{
-+	scsi_qla_host_t *ha = s->private;
-+	uint32_t cnt;
-+	uint32_t *fce;
-+	uint64_t fce_start;
-+
-+	mutex_lock(&ha->fce_mutex);
-+
-+	seq_printf(s, "FCE Trace Buffer\n");
-+	seq_printf(s, "In Pointer = %llx\n\n", ha->fce_wr);
-+	seq_printf(s, "Base = %llx\n\n", (unsigned long long) ha->fce_dma);
-+	seq_printf(s, "FCE Enable Registers\n");
-+	seq_printf(s, "%08x %08x %08x %08x %08x %08x\n",
-+	    ha->fce_mb[0], ha->fce_mb[2], ha->fce_mb[3], ha->fce_mb[4],
-+	    ha->fce_mb[5], ha->fce_mb[6]);
-+
-+	fce = (uint32_t *) ha->fce;
-+	fce_start = (unsigned long long) ha->fce_dma;
-+	for (cnt = 0; cnt < fce_calc_size(ha->fce_bufs) / 4; cnt++) {
-+		if (cnt % 8 == 0)
-+			seq_printf(s, "\n%llx: ",
-+			    (unsigned long long)((cnt * 4) + fce_start));
-+		else
-+			seq_printf(s, " ");
-+		seq_printf(s, "%08x", *fce++);
-+	}
-+
-+	seq_printf(s, "\nEnd\n");
-+
-+	mutex_unlock(&ha->fce_mutex);
-+
-+	return 0;
-+}
-+
-+static int
-+qla2x00_dfs_fce_open(struct inode *inode, struct file *file)
-+{
-+	scsi_qla_host_t *ha = inode->i_private;
-+	int rval;
-+
-+	if (!ha->flags.fce_enabled)
-+		goto out;
-+
-+	mutex_lock(&ha->fce_mutex);
-+
-+	/* Pause tracing to flush FCE buffers. */
-+	rval = qla2x00_disable_fce_trace(ha, &ha->fce_wr, &ha->fce_rd);
-+	if (rval)
-+		qla_printk(KERN_WARNING, ha,
-+		    "DebugFS: Unable to disable FCE (%d).\n", rval);
-+
-+	ha->flags.fce_enabled = 0;
-+
-+	mutex_unlock(&ha->fce_mutex);
-+out:
-+	return single_open(file, qla2x00_dfs_fce_show, ha);
-+}
-+
-+static int
-+qla2x00_dfs_fce_release(struct inode *inode, struct file *file)
-+{
-+	scsi_qla_host_t *ha = inode->i_private;
-+	int rval;
-+
-+	if (ha->flags.fce_enabled)
-+		goto out;
-+
-+	mutex_lock(&ha->fce_mutex);
-+
-+	/* Re-enable FCE tracing. */
-+	ha->flags.fce_enabled = 1;
-+	memset(ha->fce, 0, fce_calc_size(ha->fce_bufs));
-+	rval = qla2x00_enable_fce_trace(ha, ha->fce_dma, ha->fce_bufs,
-+	    ha->fce_mb, &ha->fce_bufs);
-+	if (rval) {
-+		qla_printk(KERN_WARNING, ha,
-+		    "DebugFS: Unable to reinitialize FCE (%d).\n", rval);
-+		ha->flags.fce_enabled = 0;
-+	}
-+
-+	mutex_unlock(&ha->fce_mutex);
-+out:
-+	return single_release(inode, file);
-+}
-+
-+static const struct file_operations dfs_fce_ops = {
-+	.open		= qla2x00_dfs_fce_open,
-+	.read		= seq_read,
-+	.llseek		= seq_lseek,
-+	.release	= qla2x00_dfs_fce_release,
-+};
-+
-+int
-+qla2x00_dfs_setup(scsi_qla_host_t *ha)
-+{
-+	if (!IS_QLA25XX(ha))
-+		goto out;
-+	if (!ha->fce)
-+		goto out;
-+
-+	if (qla2x00_dfs_root)
-+		goto create_dir;
-+
-+	atomic_set(&qla2x00_dfs_root_count, 0);
-+	qla2x00_dfs_root = debugfs_create_dir(QLA2XXX_DRIVER_NAME, NULL);
-+	if (!qla2x00_dfs_root) {
-+		qla_printk(KERN_NOTICE, ha,
-+		    "DebugFS: Unable to create root directory.\n");
-+		goto out;
-+	}
-+
-+create_dir:
-+	if (ha->dfs_dir)
-+		goto create_nodes;
-+
-+	mutex_init(&ha->fce_mutex);
-+	ha->dfs_dir = debugfs_create_dir(ha->host_str, qla2x00_dfs_root);
-+	if (!ha->dfs_dir) {
-+		qla_printk(KERN_NOTICE, ha,
-+		    "DebugFS: Unable to create ha directory.\n");
-+		goto out;
-+	}
-+
-+	atomic_inc(&qla2x00_dfs_root_count);
-+
-+create_nodes:
-+	ha->dfs_fce = debugfs_create_file("fce", S_IRUSR, ha->dfs_dir, ha,
-+	    &dfs_fce_ops);
-+	if (!ha->dfs_fce) {
-+		qla_printk(KERN_NOTICE, ha,
-+		    "DebugFS: Unable to fce node.\n");
-+		goto out;
-+	}
-+out:
-+	return 0;
-+}
-+
-+int
-+qla2x00_dfs_remove(scsi_qla_host_t *ha)
-+{
-+	if (ha->dfs_fce) {
-+		debugfs_remove(ha->dfs_fce);
-+		ha->dfs_fce = NULL;
-+	}
-+
-+	if (ha->dfs_dir) {
-+		debugfs_remove(ha->dfs_dir);
-+		ha->dfs_dir = NULL;
-+		atomic_dec(&qla2x00_dfs_root_count);
-+	}
-+
-+	if (atomic_read(&qla2x00_dfs_root_count) == 0 &&
-+	    qla2x00_dfs_root) {
-+		debugfs_remove(qla2x00_dfs_root);
-+		qla2x00_dfs_root = NULL;
-+	}
-+
-+	return 0;
-+}
-diff --git a/drivers/scsi/qla2xxx/qla_fw.h b/drivers/scsi/qla2xxx/qla_fw.h
-index 25364b1..9337e13 100644
---- a/drivers/scsi/qla2xxx/qla_fw.h
-+++ b/drivers/scsi/qla2xxx/qla_fw.h
-@@ -952,9 +952,31 @@ struct device_reg_24xx {
- 	uint32_t iobase_sdata;
- };
- 
-+/* Trace Control *************************************************************/
-+
-+#define TC_AEN_DISABLE		0
-+
-+#define TC_EFT_ENABLE		4
-+#define TC_EFT_DISABLE		5
-+
-+#define TC_FCE_ENABLE		8
-+#define TC_FCE_OPTIONS		0
-+#define TC_FCE_DEFAULT_RX_SIZE	2112
-+#define TC_FCE_DEFAULT_TX_SIZE	2112
-+#define TC_FCE_DISABLE		9
-+#define TC_FCE_DISABLE_TRACE	BIT_0
-+
- /* MID Support ***************************************************************/
- 
--#define MAX_MID_VPS	125
-+#define MIN_MULTI_ID_FABRIC	64	/* Must be power-of-2. */
-+#define MAX_MULTI_ID_FABRIC	256	/* ... */
-+
-+#define for_each_mapped_vp_idx(_ha, _idx)		\
-+	for (_idx = find_next_bit((_ha)->vp_idx_map,	\
-+		(_ha)->max_npiv_vports + 1, 1);		\
-+	    _idx <= (_ha)->max_npiv_vports;		\
-+	    _idx = find_next_bit((_ha)->vp_idx_map,	\
-+		(_ha)->max_npiv_vports + 1, _idx + 1))	\
- 
- struct mid_conf_entry_24xx {
- 	uint16_t reserved_1;
-@@ -982,7 +1004,7 @@ struct mid_init_cb_24xx {
- 	uint16_t count;
- 	uint16_t options;
- 
--	struct mid_conf_entry_24xx entries[MAX_MID_VPS];
-+	struct mid_conf_entry_24xx entries[MAX_MULTI_ID_FABRIC];
- };
- 
- 
-@@ -1002,10 +1024,6 @@ struct mid_db_entry_24xx {
- 	uint8_t reserved_1;
- };
- 
--struct mid_db_24xx {
--	struct mid_db_entry_24xx entries[MAX_MID_VPS];
--};
+-			case REQ_MSGOUT:
+-				/*
+-				 *	We can only have sent a MSG OUT if we
+-				 *	requested to do this by raising ATTN.
+-				 *	So, we must drop ATTN.
+-				 */
+-				WRITE_CONTROL (BASE_CMD | CMD_DRVR_ENABLE);
+-				/*
+-				 *	If we are reconnecting, then we must 
+-				 *	send an IDENTIFY message in response
+-				 *	to MSGOUT.
+-				 */
+-				switch (reselect) {
+-				case CAN_RECONNECT:
+-					WRITE_DATA (IDENTIFY (1, lun));
+-					DPRINTK (PHASE_RESELECT | PHASE_MSGOUT, "scsi%d : sent IDENTIFY message.\n", hostno);
+-					break;
+-#ifdef LINKED
+-				case LINKED_WRONG:
+-					WRITE_DATA (ABORT);
+-					linked_connected = 0;
+-					reselect = CAN_RECONNECT;
+-					goto connect_loop;
+-					DPRINTK (PHASE_MSGOUT | DEBUG_LINKED, "scsi%d : sent ABORT message to cancel incorrect I_T_L nexus.\n", hostno);
+-#endif					/* LINKED */
+-					DPRINTK (DEBUG_LINKED, "correct\n");
+-				default:
+-					WRITE_DATA (NOP);
+-					printk("scsi%d : target %d requested MSGOUT, sent NOP message.\n", hostno, target);
+-				}
+-				break;
 -
-  /*
-  * Virtual Fabric ID type definition.
-  */
-diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
-index 09cb2a9..ba35fc2 100644
---- a/drivers/scsi/qla2xxx/qla_gbl.h
-+++ b/drivers/scsi/qla2xxx/qla_gbl.h
-@@ -65,33 +65,25 @@ extern int ql2xextended_error_logging;
- extern int ql2xqfullrampup;
- extern int num_hosts;
- 
-+extern int qla2x00_loop_reset(scsi_qla_host_t *);
-+
- /*
-  * Global Functions in qla_mid.c source file.
-  */
--extern struct scsi_host_template qla2x00_driver_template;
- extern struct scsi_host_template qla24xx_driver_template;
- extern struct scsi_transport_template *qla2xxx_transport_vport_template;
--extern uint8_t qla2x00_mem_alloc(scsi_qla_host_t *);
- extern void qla2x00_timer(scsi_qla_host_t *);
- extern void qla2x00_start_timer(scsi_qla_host_t *, void *, unsigned long);
--extern void qla2x00_stop_timer(scsi_qla_host_t *);
--extern uint32_t qla24xx_allocate_vp_id(scsi_qla_host_t *);
- extern void qla24xx_deallocate_vp_id(scsi_qla_host_t *);
- extern int qla24xx_disable_vp (scsi_qla_host_t *);
- extern int qla24xx_enable_vp (scsi_qla_host_t *);
--extern void qla2x00_mem_free(scsi_qla_host_t *);
- extern int qla24xx_control_vp(scsi_qla_host_t *, int );
- extern int qla24xx_modify_vp_config(scsi_qla_host_t *);
- extern int qla2x00_send_change_request(scsi_qla_host_t *, uint16_t, uint16_t);
- extern void qla2x00_vp_stop_timer(scsi_qla_host_t *);
- extern int qla24xx_configure_vhba (scsi_qla_host_t *);
--extern int qla24xx_get_vp_entry(scsi_qla_host_t *, uint16_t, int);
--extern int qla24xx_get_vp_database(scsi_qla_host_t *, uint16_t);
--extern int qla2x00_do_dpc_vp(scsi_qla_host_t *);
- extern void qla24xx_report_id_acquisition(scsi_qla_host_t *,
-     struct vp_rpt_id_entry_24xx *);
--extern scsi_qla_host_t * qla24xx_find_vhost_by_name(scsi_qla_host_t *,
--    uint8_t *);
- extern void qla2x00_do_dpc_all_vps(scsi_qla_host_t *);
- extern int qla24xx_vport_create_req_sanity_check(struct fc_vport *);
- extern scsi_qla_host_t * qla24xx_create_vhost(struct fc_vport *);
-@@ -103,8 +95,6 @@ extern char *qla2x00_get_fw_version_str(struct scsi_qla_host *, char *);
- extern void qla2x00_mark_device_lost(scsi_qla_host_t *, fc_port_t *, int, int);
- extern void qla2x00_mark_all_devices_lost(scsi_qla_host_t *, int);
- 
--extern int qla2x00_down_timeout(struct semaphore *, unsigned long);
+-			case REQ_MSGIN:
+-				switch (message = DATA) {
+-				case DISCONNECT:
+-					DANY("seagate: deciding to disconnect\n");
+-					should_reconnect = 1;
+-					current_data = data;	/* WDE add */
+-					current_buffer = buffer;
+-					current_bufflen = len;	/* WDE add */
+-					current_nobuffs = nobuffs;
+-#ifdef LINKED
+-					linked_connected = 0;
+-#endif
+-					done = 1;
+-					DPRINTK ((PHASE_RESELECT | PHASE_MSGIN), "scsi%d : disconnected.\n", hostno);
+-					break;
 -
- extern struct fw_blob *qla2x00_request_firmware(scsi_qla_host_t *);
- 
- extern int qla2x00_wait_for_hba_online(scsi_qla_host_t *);
-@@ -113,7 +103,6 @@ extern void qla2xxx_wake_dpc(scsi_qla_host_t *);
- extern void qla2x00_alert_all_vps(scsi_qla_host_t *, uint16_t *);
- extern void qla2x00_async_event(scsi_qla_host_t *, uint16_t *);
- extern void qla2x00_vp_abort_isp(scsi_qla_host_t *);
--extern int qla24xx_vport_delete(struct fc_vport *);
- 
- /*
-  * Global Function Prototypes in qla_iocb.c source file.
-@@ -222,21 +211,16 @@ extern int
- qla2x00_get_fcal_position_map(scsi_qla_host_t *ha, char *pos_map);
- 
- extern int
--qla2x00_get_link_status(scsi_qla_host_t *, uint16_t, link_stat_t *,
--    uint16_t *);
-+qla2x00_get_link_status(scsi_qla_host_t *, uint16_t, struct link_statistics *,
-+    dma_addr_t);
- 
- extern int
--qla24xx_get_isp_stats(scsi_qla_host_t *, uint32_t *, uint32_t, uint16_t *);
-+qla24xx_get_isp_stats(scsi_qla_host_t *, struct link_statistics *,
-+    dma_addr_t);
- 
- extern int qla24xx_abort_command(scsi_qla_host_t *, srb_t *);
- extern int qla24xx_abort_target(fc_port_t *);
- 
--extern int qla2x00_system_error(scsi_qla_host_t *);
+-#ifdef LINKED
+-				case LINKED_CMD_COMPLETE:
+-				case LINKED_FLG_CMD_COMPLETE:
+-#endif
+-				case COMMAND_COMPLETE:
+-					/*
+-					 * Note : we should check for underflow here.
+-					 */
+-					DPRINTK(PHASE_MSGIN, "scsi%d : command complete.\n", hostno);
+-					done = 1;
+-					break;
+-				case ABORT:
+-					DPRINTK(PHASE_MSGIN, "scsi%d : abort message.\n", hostno);
+-					done = 1;
+-					break;
+-				case SAVE_POINTERS:
+-					current_buffer = buffer;
+-					current_bufflen = len;	/* WDE add */
+-					current_data = data;	/* WDE mod */
+-					current_nobuffs = nobuffs;
+-					DPRINTK (PHASE_MSGIN, "scsi%d : pointers saved.\n", hostno);
+-					break;
+-				case RESTORE_POINTERS:
+-					buffer = current_buffer;
+-					cmnd = current_cmnd;
+-					data = current_data;	/* WDE mod */
+-					len = current_bufflen;
+-					nobuffs = current_nobuffs;
+-					DPRINTK(PHASE_MSGIN, "scsi%d : pointers restored.\n", hostno);
+-					break;
+-				default:
 -
--extern int
--qla2x00_get_serdes_params(scsi_qla_host_t *, uint16_t *, uint16_t *,
--    uint16_t *);
+-					/*
+-					 *	IDENTIFY distinguishes itself
+-					 *	from the other messages by 
+-					 *	setting the high bit.
+-					 *
+-					 *      Note : we need to handle at 
+-					 *	least one outstanding command
+-					 *	per LUN, and need to hash the 
+-					 *	SCSI command for that I_T_L
+-					 *	nexus based on the known ID 
+-					 *	(at this point) and LUN.
+-					 */
 -
- extern int
- qla2x00_set_serdes_params(scsi_qla_host_t *, uint16_t, uint16_t, uint16_t);
- 
-@@ -244,13 +228,19 @@ extern int
- qla2x00_stop_firmware(scsi_qla_host_t *);
- 
- extern int
--qla2x00_trace_control(scsi_qla_host_t *, uint16_t, dma_addr_t, uint16_t);
-+qla2x00_enable_eft_trace(scsi_qla_host_t *, dma_addr_t, uint16_t);
-+extern int
-+qla2x00_disable_eft_trace(scsi_qla_host_t *);
- 
- extern int
--qla2x00_read_sfp(scsi_qla_host_t *, dma_addr_t, uint16_t, uint16_t, uint16_t);
-+qla2x00_enable_fce_trace(scsi_qla_host_t *, dma_addr_t, uint16_t , uint16_t *,
-+    uint32_t *);
- 
- extern int
--qla2x00_get_idma_speed(scsi_qla_host_t *, uint16_t, uint16_t *, uint16_t *);
-+qla2x00_disable_fce_trace(scsi_qla_host_t *, uint64_t *, uint64_t *);
-+
-+extern int
-+qla2x00_read_sfp(scsi_qla_host_t *, dma_addr_t, uint16_t, uint16_t, uint16_t);
- 
- extern int
- qla2x00_set_idma_speed(scsi_qla_host_t *, uint16_t, uint16_t, uint16_t *);
-@@ -270,11 +260,7 @@ extern void qla2x00_free_irqs(scsi_qla_host_t *);
- /*
-  * Global Function Prototypes in qla_sup.c source file.
-  */
--extern void qla2x00_lock_nvram_access(scsi_qla_host_t *);
--extern void qla2x00_unlock_nvram_access(scsi_qla_host_t *);
- extern void qla2x00_release_nvram_protection(scsi_qla_host_t *);
--extern uint16_t qla2x00_get_nvram_word(scsi_qla_host_t *, uint32_t);
--extern void qla2x00_write_nvram_word(scsi_qla_host_t *, uint32_t, uint16_t);
- extern uint32_t *qla24xx_read_flash_data(scsi_qla_host_t *, uint32_t *,
-     uint32_t, uint32_t);
- extern uint8_t *qla2x00_read_nvram_data(scsi_qla_host_t *, uint8_t *, uint32_t,
-@@ -321,7 +307,6 @@ extern void qla25xx_fw_dump(scsi_qla_host_t *, int);
- extern void qla2x00_dump_regs(scsi_qla_host_t *);
- extern void qla2x00_dump_buffer(uint8_t *, uint32_t);
- extern void qla2x00_print_scsi_cmd(struct scsi_cmnd *);
--extern void qla2x00_dump_pkt(void *);
- 
- /*
-  * Global Function Prototypes in qla_gs.c source file.
-@@ -356,4 +341,10 @@ extern void qla2x00_free_sysfs_attr(scsi_qla_host_t *);
- extern void qla2x00_init_host_attr(scsi_qla_host_t *);
- extern void qla2x00_alloc_sysfs_attr(scsi_qla_host_t *);
- extern void qla2x00_free_sysfs_attr(scsi_qla_host_t *);
-+
-+/*
-+ * Global Function Prototypes in qla_dfs.c source file.
-+ */
-+extern int qla2x00_dfs_setup(scsi_qla_host_t *);
-+extern int qla2x00_dfs_remove(scsi_qla_host_t *);
- #endif /* _QLA_GBL_H */
-diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
-index 191dafd..d0633ca 100644
---- a/drivers/scsi/qla2xxx/qla_init.c
-+++ b/drivers/scsi/qla2xxx/qla_init.c
-@@ -732,9 +732,9 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *ha)
- {
- 	int rval;
- 	uint32_t dump_size, fixed_size, mem_size, req_q_size, rsp_q_size,
--	    eft_size;
--	dma_addr_t eft_dma;
--	void *eft;
-+	    eft_size, fce_size;
-+	dma_addr_t tc_dma;
-+	void *tc;
- 
- 	if (ha->fw_dump) {
- 		qla_printk(KERN_WARNING, ha,
-@@ -743,7 +743,7 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *ha)
- 	}
- 
- 	ha->fw_dumped = 0;
--	fixed_size = mem_size = eft_size = 0;
-+	fixed_size = mem_size = eft_size = fce_size = 0;
- 	if (IS_QLA2100(ha) || IS_QLA2200(ha)) {
- 		fixed_size = sizeof(struct qla2100_fw_dump);
- 	} else if (IS_QLA23XX(ha)) {
-@@ -758,21 +758,21 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *ha)
- 		    sizeof(uint32_t);
- 
- 		/* Allocate memory for Extended Trace Buffer. */
--		eft = dma_alloc_coherent(&ha->pdev->dev, EFT_SIZE, &eft_dma,
-+		tc = dma_alloc_coherent(&ha->pdev->dev, EFT_SIZE, &tc_dma,
- 		    GFP_KERNEL);
--		if (!eft) {
-+		if (!tc) {
- 			qla_printk(KERN_WARNING, ha, "Unable to allocate "
- 			    "(%d KB) for EFT.\n", EFT_SIZE / 1024);
- 			goto cont_alloc;
- 		}
- 
--		rval = qla2x00_trace_control(ha, TC_ENABLE, eft_dma,
--		    EFT_NUM_BUFFERS);
-+		memset(tc, 0, EFT_SIZE);
-+		rval = qla2x00_enable_eft_trace(ha, tc_dma, EFT_NUM_BUFFERS);
- 		if (rval) {
- 			qla_printk(KERN_WARNING, ha, "Unable to initialize "
- 			    "EFT (%d).\n", rval);
--			dma_free_coherent(&ha->pdev->dev, EFT_SIZE, eft,
--			    eft_dma);
-+			dma_free_coherent(&ha->pdev->dev, EFT_SIZE, tc,
-+			    tc_dma);
- 			goto cont_alloc;
- 		}
- 
-@@ -780,9 +780,40 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *ha)
- 		    EFT_SIZE / 1024);
- 
- 		eft_size = EFT_SIZE;
--		memset(eft, 0, eft_size);
--		ha->eft_dma = eft_dma;
--		ha->eft = eft;
-+		ha->eft_dma = tc_dma;
-+		ha->eft = tc;
-+
-+		/* Allocate memory for Fibre Channel Event Buffer. */
-+		if (!IS_QLA25XX(ha))
-+			goto cont_alloc;
-+
-+		tc = dma_alloc_coherent(&ha->pdev->dev, FCE_SIZE, &tc_dma,
-+		    GFP_KERNEL);
-+		if (!tc) {
-+			qla_printk(KERN_WARNING, ha, "Unable to allocate "
-+			    "(%d KB) for FCE.\n", FCE_SIZE / 1024);
-+			goto cont_alloc;
-+		}
-+
-+		memset(tc, 0, FCE_SIZE);
-+		rval = qla2x00_enable_fce_trace(ha, tc_dma, FCE_NUM_BUFFERS,
-+		    ha->fce_mb, &ha->fce_bufs);
-+		if (rval) {
-+			qla_printk(KERN_WARNING, ha, "Unable to initialize "
-+			    "FCE (%d).\n", rval);
-+			dma_free_coherent(&ha->pdev->dev, FCE_SIZE, tc,
-+			    tc_dma);
-+			ha->flags.fce_enabled = 0;
-+			goto cont_alloc;
-+		}
-+
-+		qla_printk(KERN_INFO, ha, "Allocated (%d KB) for FCE...\n",
-+		    FCE_SIZE / 1024);
-+
-+		fce_size = sizeof(struct qla2xxx_fce_chain) + EFT_SIZE;
-+		ha->flags.fce_enabled = 1;
-+		ha->fce_dma = tc_dma;
-+		ha->fce = tc;
- 	}
- cont_alloc:
- 	req_q_size = ha->request_q_length * sizeof(request_t);
-@@ -790,7 +821,7 @@ cont_alloc:
- 
- 	dump_size = offsetof(struct qla2xxx_fw_dump, isp);
- 	dump_size += fixed_size + mem_size + req_q_size + rsp_q_size +
--	    eft_size;
-+	    eft_size + fce_size;
- 
- 	ha->fw_dump = vmalloc(dump_size);
- 	if (!ha->fw_dump) {
-@@ -922,9 +953,9 @@ qla2x00_setup_chip(scsi_qla_host_t *ha)
- 					ha->flags.npiv_supported = 1;
- 					if ((!ha->max_npiv_vports) ||
- 					    ((ha->max_npiv_vports + 1) %
--					    MAX_MULTI_ID_FABRIC))
-+					    MIN_MULTI_ID_FABRIC))
- 						ha->max_npiv_vports =
--						    MAX_NUM_VPORT_FABRIC;
-+						    MIN_MULTI_ID_FABRIC - 1;
- 				}
- 
- 				if (ql2xallocfwdump)
-@@ -1162,7 +1193,10 @@ qla2x00_init_rings(scsi_qla_host_t *ha)
- 
- 	DEBUG(printk("scsi(%ld): Issue init firmware.\n", ha->host_no));
- 
--	mid_init_cb->count = ha->max_npiv_vports;
-+	if (ha->flags.npiv_supported)
-+		mid_init_cb->count = cpu_to_le16(ha->max_npiv_vports);
-+
-+	mid_init_cb->options = __constant_cpu_to_le16(BIT_1);
- 
- 	rval = qla2x00_init_firmware(ha, ha->init_cb_size);
- 	if (rval) {
-@@ -2566,14 +2600,7 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *ha, struct list_head *new_fcports)
- 
- 		/* Bypass virtual ports of the same host. */
- 		if (pha->num_vhosts) {
--			vp_index = find_next_bit(
--			    (unsigned long *)pha->vp_idx_map,
--			    MAX_MULTI_ID_FABRIC + 1, 1);
+-					if (message & 0x80) {
+-						DPRINTK (PHASE_MSGIN, "scsi%d : IDENTIFY message received from id %d, lun %d.\n", hostno, target, message & 7);
+-					} else {
+-						/*
+-						 *      We should go into a
+-						 *	MESSAGE OUT phase, and
+-						 *	send  a MESSAGE_REJECT
+-						 *      if we run into a message 
+-						 *	that we don't like.  The
+-						 *	seagate driver needs 
+-						 *	some serious 
+-						 *	restructuring first
+-						 *	though.
+-						 */
+-						DPRINTK (PHASE_MSGIN, "scsi%d : unknown message %d from target %d.\n", hostno, message, target);
+-					}
+-				}
+-				break;
+-			default:
+-				printk(KERN_ERR "scsi%d : unknown phase.\n", hostno);
+-				st0x_aborted = DID_ERROR;
+-			}	/* end of switch (status_read &  REQ_MASK) */
+-#ifdef SLOW_RATE
+-			/*
+-			 * I really don't care to deal with borken devices in
+-			 * each single byte transfer case (ie, message in,
+-			 * message out, status), so I'll do the wait here if 
+-			 * necessary.
+-			 */
+-			if(borken)
+-				borken_wait();
+-#endif
 -
--			for (;vp_index <= MAX_MULTI_ID_FABRIC;
--			    vp_index = find_next_bit(
--			    (unsigned long *)pha->vp_idx_map,
--			    MAX_MULTI_ID_FABRIC + 1, vp_index + 1)) {
-+			for_each_mapped_vp_idx(pha, vp_index) {
- 				empty_vp_index = 1;
- 				found_vp = 0;
- 				list_for_each_entry(vha, &pha->vp_list,
-@@ -2592,7 +2619,8 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *ha, struct list_head *new_fcports)
- 				    new_fcport->d_id.b24 == vha->d_id.b24)
- 					break;
- 			}
--			if (vp_index <= MAX_MULTI_ID_FABRIC)
-+
-+			if (vp_index <= pha->max_npiv_vports)
- 				continue;
- 		}
- 
-@@ -3245,7 +3273,7 @@ qla2x00_abort_isp(scsi_qla_host_t *ha)
- 			clear_bit(ISP_ABORT_RETRY, &ha->dpc_flags);
- 
- 			if (ha->eft) {
--				rval = qla2x00_trace_control(ha, TC_ENABLE,
-+				rval = qla2x00_enable_eft_trace(ha,
- 				    ha->eft_dma, EFT_NUM_BUFFERS);
- 				if (rval) {
- 					qla_printk(KERN_WARNING, ha,
-@@ -3253,6 +3281,21 @@ qla2x00_abort_isp(scsi_qla_host_t *ha)
- 					    "(%d).\n", rval);
- 				}
- 			}
-+
-+			if (ha->fce) {
-+				ha->flags.fce_enabled = 1;
-+				memset(ha->fce, 0,
-+				    fce_calc_size(ha->fce_bufs));
-+				rval = qla2x00_enable_fce_trace(ha,
-+				    ha->fce_dma, ha->fce_bufs, ha->fce_mb,
-+				    &ha->fce_bufs);
-+				if (rval) {
-+					qla_printk(KERN_WARNING, ha,
-+					    "Unable to reinitialize FCE "
-+					    "(%d).\n", rval);
-+					ha->flags.fce_enabled = 0;
-+				}
-+			}
- 		} else {	/* failed the ISP abort */
- 			ha->flags.online = 1;
- 			if (test_bit(ISP_ABORT_RETRY, &ha->dpc_flags)) {
-diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
-index 1104bd2..642a0c3 100644
---- a/drivers/scsi/qla2xxx/qla_isr.c
-+++ b/drivers/scsi/qla2xxx/qla_isr.c
-@@ -104,7 +104,7 @@ qla2100_intr_handler(int irq, void *dev_id)
- 	if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) &&
- 	    (status & MBX_INTERRUPT) && ha->flags.mbox_int) {
- 		set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
--		up(&ha->mbx_intr_sem);
-+		complete(&ha->mbx_intr_comp);
- 	}
- 
- 	return (IRQ_HANDLED);
-@@ -216,7 +216,7 @@ qla2300_intr_handler(int irq, void *dev_id)
- 	if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) &&
- 	    (status & MBX_INTERRUPT) && ha->flags.mbox_int) {
- 		set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
--		up(&ha->mbx_intr_sem);
-+		complete(&ha->mbx_intr_comp);
- 	}
- 
- 	return (IRQ_HANDLED);
-@@ -347,10 +347,6 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
- 		break;
- 
- 	case MBA_SYSTEM_ERR:		/* System Error */
--		mb[1] = RD_MAILBOX_REG(ha, reg, 1);
--		mb[2] = RD_MAILBOX_REG(ha, reg, 2);
--		mb[3] = RD_MAILBOX_REG(ha, reg, 3);
+-		}		/* if(status_read & STAT_REQ) ends */
+-	}			/* while(((status_read = STATUS)...) ends */
 -
- 		qla_printk(KERN_INFO, ha,
- 		    "ISP System Error - mbx1=%xh mbx2=%xh mbx3=%xh.\n",
- 		    mb[1], mb[2], mb[3]);
-@@ -579,12 +575,15 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
- 		/* Check if the Vport has issued a SCR */
- 		if (ha->parent && test_bit(VP_SCR_NEEDED, &ha->vp_flags))
- 			break;
-+		/* Only handle SCNs for our Vport index. */
-+		if (ha->flags.npiv_supported && ha->vp_idx != mb[3])
-+			break;
- 
- 		DEBUG2(printk("scsi(%ld): Asynchronous RSCR UPDATE.\n",
- 		    ha->host_no));
- 		DEBUG(printk(KERN_INFO
--		    "scsi(%ld): RSCN database changed -- %04x %04x.\n",
--		    ha->host_no, mb[1], mb[2]));
-+		    "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];
- 		host_pid = (ha->d_id.b.domain << 16) | (ha->d_id.b.area << 8) |
-@@ -823,6 +822,35 @@ qla2x00_process_response_queue(struct scsi_qla_host *ha)
- 	WRT_REG_WORD(ISP_RSP_Q_OUT(ha, reg), ha->rsp_ring_index);
- }
- 
-+static inline void
-+qla2x00_handle_sense(srb_t *sp, uint8_t *sense_data, uint32_t sense_len)
-+{
-+	struct scsi_cmnd *cp = sp->cmd;
-+
-+	if (sense_len >= SCSI_SENSE_BUFFERSIZE)
-+		sense_len = SCSI_SENSE_BUFFERSIZE;
-+
-+	CMD_ACTUAL_SNSLEN(cp) = sense_len;
-+	sp->request_sense_length = sense_len;
-+	sp->request_sense_ptr = cp->sense_buffer;
-+	if (sp->request_sense_length > 32)
-+		sense_len = 32;
-+
-+	memcpy(cp->sense_buffer, sense_data, sense_len);
-+
-+	sp->request_sense_ptr += sense_len;
-+	sp->request_sense_length -= sense_len;
-+	if (sp->request_sense_length != 0)
-+		sp->ha->status_srb = sp;
-+
-+	DEBUG5(printk("%s(): Check condition Sense data, scsi(%ld:%d:%d:%d) "
-+	    "cmd=%p pid=%ld\n", __func__, sp->ha->host_no, cp->device->channel,
-+	    cp->device->id, cp->device->lun, cp, cp->serial_number));
-+	if (sense_len)
-+		DEBUG5(qla2x00_dump_buffer(cp->sense_buffer,
-+		    CMD_ACTUAL_SNSLEN(cp)));
-+}
-+
- /**
-  * qla2x00_status_entry() - Process a Status IOCB entry.
-  * @ha: SCSI driver HA context
-@@ -977,36 +1005,11 @@ qla2x00_status_entry(scsi_qla_host_t *ha, void *pkt)
- 		if (lscsi_status != SS_CHECK_CONDITION)
- 			break;
- 
--		/* Copy Sense Data into sense buffer. */
--		memset(cp->sense_buffer, 0, sizeof(cp->sense_buffer));
+-	DPRINTK(PHASE_DATAIN | PHASE_DATAOUT | PHASE_EXIT, "scsi%d : Transfered %d bytes\n", hostno, transfered);
+-
+-#if (DEBUG & PHASE_EXIT)
+-#if 0				/* Doesn't work for scatter/gather */
+-	printk("Buffer : \n");
+-	for(i = 0; i < 20; ++i)
+-		printk("%02x  ", ((unsigned char *) data)[i]);	/* WDE mod */
+-	printk("\n");
+-#endif
+-	printk("scsi%d : status = ", hostno);
+-	scsi_print_status(status);
+-	printk(" message = %02x\n", message);
+-#endif
+-
+-	/* We shouldn't reach this until *after* BSY has been deasserted */
+-
+-#ifdef LINKED
+-	else
+-	{
+-		/*
+-		 * Fix the message byte so that unsuspecting high level drivers
+-		 * don't puke when they see a LINKED COMMAND message in place of
+-		 * the COMMAND COMPLETE they may be expecting.  Shouldn't be
+-		 * necessary, but it's better to be on the safe side.
+-		 *
+-		 * A non LINKED* message byte will indicate that the command
+-		 * completed, and we are now disconnected.
+-		 */
+-
+-		switch (message) {
+-		case LINKED_CMD_COMPLETE:
+-		case LINKED_FLG_CMD_COMPLETE:
+-			message = COMMAND_COMPLETE;
+-			linked_target = current_target;
+-			linked_lun = current_lun;
+-			linked_connected = 1;
+-			DPRINTK (DEBUG_LINKED, "scsi%d : keeping I_T_L nexus established for linked command.\n", hostno);
+-			/* We also will need to adjust status to accommodate intermediate
+-			   conditions. */
+-			if ((status == INTERMEDIATE_GOOD) || (status == INTERMEDIATE_C_GOOD))
+-				status = GOOD;
+-			break;
+-			/*
+-			 * We should also handle what are "normal" termination
+-			 * messages here (ABORT, BUS_DEVICE_RESET?, and
+-			 * COMMAND_COMPLETE individually, and flake if things
+-			 * aren't right.
+-			 */
+-		default:
+-			DPRINTK (DEBUG_LINKED, "scsi%d : closing I_T_L nexus.\n", hostno);
+-			linked_connected = 0;
+-		}
+-	}
+-#endif	/* LINKED */
 -
-+		memset(cp->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
- 		if (!(scsi_status & SS_SENSE_LEN_VALID))
- 			break;
- 
--		if (sense_len >= sizeof(cp->sense_buffer))
--			sense_len = sizeof(cp->sense_buffer);
+-	if (should_reconnect) {
+-		DPRINTK (PHASE_RESELECT, "scsi%d : exiting seagate_st0x_queue_command() with reconnect enabled.\n", hostno);
+-		WRITE_CONTROL (BASE_CMD | CMD_INTR);
+-	} else
+-		WRITE_CONTROL (BASE_CMD);
 -
--		CMD_ACTUAL_SNSLEN(cp) = sense_len;
--		sp->request_sense_length = sense_len;
--		sp->request_sense_ptr = cp->sense_buffer;
+-	return retcode (st0x_aborted);
+-}				/* end of internal_command */
 -
--		if (sp->request_sense_length > 32)
--			sense_len = 32;
+-static int seagate_st0x_abort(struct scsi_cmnd * SCpnt)
+-{
+-	st0x_aborted = DID_ABORT;
+-	return SUCCESS;
+-}
 -
--		memcpy(cp->sense_buffer, sense_data, sense_len);
+-#undef ULOOP
+-#undef TIMEOUT
 -
--		sp->request_sense_ptr += sense_len;
--		sp->request_sense_length -= sense_len;
--		if (sp->request_sense_length != 0)
--			ha->status_srb = sp;
+-/*
+- * the seagate_st0x_reset function resets the SCSI bus 
+- *
+- * May be called with SCpnt = NULL
+- */
 -
--		DEBUG5(printk("%s(): Check condition Sense data, "
--		    "scsi(%ld:%d:%d:%d) cmd=%p pid=%ld\n", __func__,
--		    ha->host_no, cp->device->channel, cp->device->id,
--		    cp->device->lun, cp, cp->serial_number));
--		if (sense_len)
--			DEBUG5(qla2x00_dump_buffer(cp->sense_buffer,
--			    CMD_ACTUAL_SNSLEN(cp)));
-+		qla2x00_handle_sense(sp, sense_data, sense_len);
- 		break;
- 
- 	case CS_DATA_UNDERRUN:
-@@ -1061,34 +1064,11 @@ qla2x00_status_entry(scsi_qla_host_t *ha, void *pkt)
- 			if (lscsi_status != SS_CHECK_CONDITION)
- 				break;
- 
--			/* Copy Sense Data into sense buffer */
--			memset(cp->sense_buffer, 0, sizeof(cp->sense_buffer));
+-static int seagate_st0x_bus_reset(struct scsi_cmnd * SCpnt)
+-{
+-	/* No timeouts - this command is going to fail because it was reset. */
+-	DANY ("scsi%d: Reseting bus... ", hostno);
 -
-+			memset(cp->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
- 			if (!(scsi_status & SS_SENSE_LEN_VALID))
- 				break;
- 
--			if (sense_len >= sizeof(cp->sense_buffer))
--				sense_len = sizeof(cp->sense_buffer);
+-	/* assert  RESET signal on SCSI bus.  */
+-	WRITE_CONTROL (BASE_CMD | CMD_RST);
 -
--			CMD_ACTUAL_SNSLEN(cp) = sense_len;
--			sp->request_sense_length = sense_len;
--			sp->request_sense_ptr = cp->sense_buffer;
+-	mdelay (20);
 -
--			if (sp->request_sense_length > 32)
--				sense_len = 32;
+-	WRITE_CONTROL (BASE_CMD);
+-	st0x_aborted = DID_RESET;
 -
--			memcpy(cp->sense_buffer, sense_data, sense_len);
+-	DANY ("done.\n");
+-	return SUCCESS;
+-}
 -
--			sp->request_sense_ptr += sense_len;
--			sp->request_sense_length -= sense_len;
--			if (sp->request_sense_length != 0)
--				ha->status_srb = sp;
+-static int seagate_st0x_release(struct Scsi_Host *shost)
+-{
+-	if (shost->irq)
+-		free_irq(shost->irq, shost);
+-	release_region(shost->io_port, shost->n_io_port);
+-	return 0;
+-}
 -
--			DEBUG5(printk("%s(): Check condition Sense data, "
--			    "scsi(%ld:%d:%d:%d) cmd=%p pid=%ld\n",
--			    __func__, ha->host_no, cp->device->channel,
--			    cp->device->id, cp->device->lun, cp,
--			    cp->serial_number));
-+			qla2x00_handle_sense(sp, sense_data, sense_len);
- 
- 			/*
- 			 * In case of a Underrun condition, set both the lscsi
-@@ -1108,10 +1088,6 @@ qla2x00_status_entry(scsi_qla_host_t *ha, void *pkt)
+-static struct scsi_host_template driver_template = {
+-	.detect         	= seagate_st0x_detect,
+-	.release        	= seagate_st0x_release,
+-	.info           	= seagate_st0x_info,
+-	.queuecommand   	= seagate_st0x_queue_command,
+-	.eh_abort_handler	= seagate_st0x_abort,
+-	.eh_bus_reset_handler	= seagate_st0x_bus_reset,
+-	.can_queue      	= 1,
+-	.this_id        	= 7,
+-	.sg_tablesize   	= SG_ALL,
+-	.cmd_per_lun    	= 1,
+-	.use_clustering		= DISABLE_CLUSTERING,
+-};
+-#include "scsi_module.c"
+diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
+index f1871ea..aba28f3 100644
+--- a/drivers/scsi/sg.c
++++ b/drivers/scsi/sg.c
+@@ -48,6 +48,7 @@ static int sg_version_num = 30534;	/* 2 digits for each component */
+ #include <linux/blkdev.h>
+ #include <linux/delay.h>
+ #include <linux/scatterlist.h>
++#include <linux/blktrace_api.h>
  
- 				cp->result = DID_ERROR << 16 | lscsi_status;
- 			}
--
--			if (sense_len)
--				DEBUG5(qla2x00_dump_buffer(cp->sense_buffer,
--				    CMD_ACTUAL_SNSLEN(cp)));
- 		} else {
- 			/*
- 			 * If RISC reports underrun and target does not report
-@@ -1621,7 +1597,7 @@ qla24xx_intr_handler(int irq, void *dev_id)
- 	if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) &&
- 	    (status & MBX_INTERRUPT) && ha->flags.mbox_int) {
- 		set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
--		up(&ha->mbx_intr_sem);
-+		complete(&ha->mbx_intr_comp);
+ #include "scsi.h"
+ #include <scsi/scsi_dbg.h>
+@@ -602,8 +603,9 @@ sg_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos)
+ 	 * but is is possible that the app intended SG_DXFER_TO_DEV, because there
+ 	 * is a non-zero input_size, so emit a warning.
+ 	 */
+-	if (hp->dxfer_direction == SG_DXFER_TO_FROM_DEV)
+-		if (printk_ratelimit())
++	if (hp->dxfer_direction == SG_DXFER_TO_FROM_DEV) {
++		static char cmd[TASK_COMM_LEN];
++		if (strcmp(current->comm, cmd) && printk_ratelimit()) {
+ 			printk(KERN_WARNING
+ 			       "sg_write: data in/out %d/%d bytes for SCSI command 0x%x--"
+ 			       "guessing data in;\n" KERN_WARNING "   "
+@@ -611,6 +613,9 @@ sg_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos)
+ 			       old_hdr.reply_len - (int)SZ_SG_HEADER,
+ 			       input_size, (unsigned int) cmnd[0],
+ 			       current->comm);
++			strcpy(cmd, current->comm);
++		}
++	}
+ 	k = sg_common_write(sfp, srp, cmnd, sfp->timeout, blocking);
+ 	return (k < 0) ? k : count;
+ }
+@@ -1063,6 +1068,17 @@ sg_ioctl(struct inode *inode, struct file *filp,
+ 	case BLKSECTGET:
+ 		return put_user(sdp->device->request_queue->max_sectors * 512,
+ 				ip);
++	case BLKTRACESETUP:
++		return blk_trace_setup(sdp->device->request_queue,
++				       sdp->disk->disk_name,
++				       sdp->device->sdev_gendev.devt,
++				       (char *)arg);
++	case BLKTRACESTART:
++		return blk_trace_startstop(sdp->device->request_queue, 1);
++	case BLKTRACESTOP:
++		return blk_trace_startstop(sdp->device->request_queue, 0);
++	case BLKTRACETEARDOWN:
++		return blk_trace_remove(sdp->device->request_queue);
+ 	default:
+ 		if (read_only)
+ 			return -EPERM;	/* don't know so take safe approach */
+@@ -1418,7 +1434,6 @@ sg_add(struct class_device *cl_dev, struct class_interface *cl_intf)
+ 		goto out;
  	}
  
- 	return IRQ_HANDLED;
-@@ -1758,7 +1734,7 @@ qla24xx_msix_default(int irq, void *dev_id)
- 	if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) &&
- 	    (status & MBX_INTERRUPT) && ha->flags.mbox_int) {
- 		set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
--		up(&ha->mbx_intr_sem);
-+		complete(&ha->mbx_intr_comp);
- 	}
+-	class_set_devdata(cl_dev, sdp);
+ 	error = cdev_add(cdev, MKDEV(SCSI_GENERIC_MAJOR, sdp->index), 1);
+ 	if (error)
+ 		goto cdev_add_err;
+@@ -1431,11 +1446,14 @@ sg_add(struct class_device *cl_dev, struct class_interface *cl_intf)
+ 				MKDEV(SCSI_GENERIC_MAJOR, sdp->index),
+ 				cl_dev->dev, "%s",
+ 				disk->disk_name);
+-		if (IS_ERR(sg_class_member))
+-			printk(KERN_WARNING "sg_add: "
+-				"class_device_create failed\n");
++		if (IS_ERR(sg_class_member)) {
++			printk(KERN_ERR "sg_add: "
++			       "class_device_create failed\n");
++			error = PTR_ERR(sg_class_member);
++			goto cdev_add_err;
++		}
+ 		class_set_devdata(sg_class_member, sdp);
+-		error = sysfs_create_link(&scsidp->sdev_gendev.kobj, 
++		error = sysfs_create_link(&scsidp->sdev_gendev.kobj,
+ 					  &sg_class_member->kobj, "generic");
+ 		if (error)
+ 			printk(KERN_ERR "sg_add: unable to make symlink "
+@@ -1447,6 +1465,8 @@ sg_add(struct class_device *cl_dev, struct class_interface *cl_intf)
+ 		    "Attached scsi generic sg%d type %d\n", sdp->index,
+ 		    scsidp->type);
  
- 	return IRQ_HANDLED;
-@@ -1853,6 +1829,18 @@ qla2x00_request_irqs(scsi_qla_host_t *ha)
- 		goto skip_msix;
++	class_set_devdata(cl_dev, sdp);
++
+ 	return 0;
+ 
+ cdev_add_err:
+@@ -2521,7 +2541,7 @@ sg_idr_max_id(int id, void *p, void *data)
+ static int
+ sg_last_dev(void)
+ {
+-	int k = 0;
++	int k = -1;
+ 	unsigned long iflags;
+ 
+ 	read_lock_irqsave(&sg_index_lock, iflags);
+diff --git a/drivers/scsi/sgiwd93.c b/drivers/scsi/sgiwd93.c
+index eef8275..d4ebe8c 100644
+--- a/drivers/scsi/sgiwd93.c
++++ b/drivers/scsi/sgiwd93.c
+@@ -159,6 +159,7 @@ void sgiwd93_reset(unsigned long base)
+ 	udelay(50);
+ 	hregs->ctrl = 0;
+ }
++EXPORT_SYMBOL_GPL(sgiwd93_reset);
+ 
+ static inline void init_hpc_chain(struct hpc_data *hd)
+ {
+diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c
+index c619990..1fcee16 100644
+--- a/drivers/scsi/sr.c
++++ b/drivers/scsi/sr.c
+@@ -67,8 +67,6 @@ MODULE_ALIAS_SCSI_DEVICE(TYPE_WORM);
+ 
+ #define SR_DISKS	256
+ 
+-#define MAX_RETRIES	3
+-#define SR_TIMEOUT	(30 * HZ)
+ #define SR_CAPABILITIES \
+ 	(CDC_CLOSE_TRAY|CDC_OPEN_TRAY|CDC_LOCK|CDC_SELECT_SPEED| \
+ 	 CDC_SELECT_DISC|CDC_MULTI_SESSION|CDC_MCN|CDC_MEDIA_CHANGED| \
+@@ -179,21 +177,28 @@ static int sr_media_change(struct cdrom_device_info *cdi, int slot)
+ {
+ 	struct scsi_cd *cd = cdi->handle;
+ 	int retval;
++	struct scsi_sense_hdr *sshdr;
+ 
+ 	if (CDSL_CURRENT != slot) {
+ 		/* no changer support */
+ 		return -EINVAL;
  	}
  
-+	if (ha->pdev->subsystem_vendor == PCI_VENDOR_ID_HP &&
-+	    (ha->pdev->subsystem_device == 0x7040 ||
-+		ha->pdev->subsystem_device == 0x7041 ||
-+		ha->pdev->subsystem_device == 0x1705)) {
-+		DEBUG2(qla_printk(KERN_WARNING, ha,
-+		    "MSI-X: Unsupported ISP2432 SSVID/SSDID (0x%X, 0x%X).\n",
-+		    ha->pdev->subsystem_vendor,
-+		    ha->pdev->subsystem_device));
+-	retval = scsi_test_unit_ready(cd->device, SR_TIMEOUT, MAX_RETRIES);
+-	if (retval) {
+-		/* Unable to test, unit probably not ready.  This usually
+-		 * means there is no disc in the drive.  Mark as changed,
+-		 * and we will figure it out later once the drive is
+-		 * available again.  */
++	sshdr =  kzalloc(sizeof(*sshdr), GFP_KERNEL);
++	retval = scsi_test_unit_ready(cd->device, SR_TIMEOUT, MAX_RETRIES,
++				      sshdr);
++	if (retval || (scsi_sense_valid(sshdr) &&
++		       /* 0x3a is medium not present */
++		       sshdr->asc == 0x3a)) {
++		/* Media not present or unable to test, unit probably not
++		 * ready. This usually means there is no disc in the drive.
++		 * Mark as changed, and we will figure it out later once
++		 * the drive is available again.
++		 */
+ 		cd->device->changed = 1;
+-		return 1;	/* This will force a flush, if called from
+-				 * check_disk_change */
++		/* This will force a flush, if called from check_disk_change */
++		retval = 1;
++		goto out;
+ 	};
+ 
+ 	retval = cd->device->changed;
+@@ -203,9 +208,17 @@ static int sr_media_change(struct cdrom_device_info *cdi, int slot)
+ 	if (retval) {
+ 		/* check multisession offset etc */
+ 		sr_cd_check(cdi);
+-
+ 		get_sectorsize(cd);
+ 	}
 +
-+		goto skip_msi;
-+	}
++out:
++	/* Notify userspace, that media has changed. */
++	if (retval != cd->previous_state)
++		sdev_evt_send_simple(cd->device, SDEV_EVT_MEDIA_CHANGE,
++				     GFP_KERNEL);
++	cd->previous_state = retval;
++	kfree(sshdr);
 +
- 	ret = qla24xx_enable_msix(ha);
- 	if (!ret) {
- 		DEBUG2(qla_printk(KERN_INFO, ha,
-diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
-index ccd662a..0c10c0b 100644
---- a/drivers/scsi/qla2xxx/qla_mbx.c
-+++ b/drivers/scsi/qla2xxx/qla_mbx.c
-@@ -8,19 +8,6 @@
+ 	return retval;
+ }
+  
+diff --git a/drivers/scsi/sr.h b/drivers/scsi/sr.h
+index d65de96..81fbc0b 100644
+--- a/drivers/scsi/sr.h
++++ b/drivers/scsi/sr.h
+@@ -20,6 +20,9 @@
+ #include <linux/genhd.h>
+ #include <linux/kref.h>
  
- #include <linux/delay.h>
++#define MAX_RETRIES	3
++#define SR_TIMEOUT	(30 * HZ)
++
+ struct scsi_device;
  
--static void
--qla2x00_mbx_sem_timeout(unsigned long data)
+ /* The CDROM is fairly slow, so we need a little extra time */
+@@ -37,6 +40,7 @@ typedef struct scsi_cd {
+ 	unsigned xa_flag:1;	/* CD has XA sectors ? */
+ 	unsigned readcd_known:1;	/* drive supports READ_CD (0xbe) */
+ 	unsigned readcd_cdda:1;	/* reading audio data using READ_CD */
++	unsigned previous_state:1;	/* media has changed */
+ 	struct cdrom_device_info cdi;
+ 	/* We hold gendisk and scsi_device references on probe and use
+ 	 * the refs on this kref to decide when to release them */
+diff --git a/drivers/scsi/sr_ioctl.c b/drivers/scsi/sr_ioctl.c
+index e1589f9..d5cebff 100644
+--- a/drivers/scsi/sr_ioctl.c
++++ b/drivers/scsi/sr_ioctl.c
+@@ -275,18 +275,6 @@ int sr_do_ioctl(Scsi_CD *cd, struct packet_command *cgc)
+ /* ---------------------------------------------------------------------- */
+ /* interface to cdrom.c                                                   */
+ 
+-static int test_unit_ready(Scsi_CD *cd)
 -{
--	struct semaphore	*sem_ptr = (struct semaphore *)data;
--
--	DEBUG11(printk("qla2x00_sem_timeout: entered.\n"));
--
--	if (sem_ptr != NULL) {
--		up(sem_ptr);
--	}
+-	struct packet_command cgc;
 -
--	DEBUG11(printk("qla2x00_mbx_sem_timeout: exiting.\n"));
+-	memset(&cgc, 0, sizeof(struct packet_command));
+-	cgc.cmd[0] = GPCMD_TEST_UNIT_READY;
+-	cgc.quiet = 1;
+-	cgc.data_direction = DMA_NONE;
+-	cgc.timeout = IOCTL_TIMEOUT;
+-	return sr_do_ioctl(cd, &cgc);
 -}
- 
- /*
-  * qla2x00_mailbox_command
-@@ -47,7 +34,6 @@ qla2x00_mailbox_command(scsi_qla_host_t *pvha, mbx_cmd_t *mcp)
- 	int		rval;
- 	unsigned long    flags = 0;
- 	device_reg_t __iomem *reg;
--	struct timer_list	tmp_intr_timer;
- 	uint8_t		abort_active;
- 	uint8_t		io_lock_on;
- 	uint16_t	command;
-@@ -72,7 +58,8 @@ qla2x00_mailbox_command(scsi_qla_host_t *pvha, mbx_cmd_t *mcp)
- 	 * non ISP abort time.
- 	 */
- 	if (!abort_active) {
--		if (qla2x00_down_timeout(&ha->mbx_cmd_sem, mcp->tov * HZ)) {
-+		if (!wait_for_completion_timeout(&ha->mbx_cmd_comp,
-+		    mcp->tov * HZ)) {
- 			/* Timeout occurred. Return error. */
- 			DEBUG2_3_11(printk("%s(%ld): cmd access timeout. "
- 			    "Exiting.\n", __func__, ha->host_no));
-@@ -135,22 +122,6 @@ qla2x00_mailbox_command(scsi_qla_host_t *pvha, mbx_cmd_t *mcp)
- 	/* Wait for mbx cmd completion until timeout */
- 
- 	if (!abort_active && io_lock_on) {
--		/* sleep on completion semaphore */
--		DEBUG11(printk("%s(%ld): INTERRUPT MODE. Initializing timer.\n",
--		    __func__, ha->host_no));
--
--		init_timer(&tmp_intr_timer);
--		tmp_intr_timer.data = (unsigned long)&ha->mbx_intr_sem;
--		tmp_intr_timer.expires = jiffies + mcp->tov * HZ;
--		tmp_intr_timer.function =
--		    (void (*)(unsigned long))qla2x00_mbx_sem_timeout;
--
--		DEBUG11(printk("%s(%ld): Adding timer.\n", __func__,
--		    ha->host_no));
--		add_timer(&tmp_intr_timer);
 -
--		DEBUG11(printk("%s(%ld): going to unlock & sleep. "
--		    "time=0x%lx.\n", __func__, ha->host_no, jiffies));
+ int sr_tray_move(struct cdrom_device_info *cdi, int pos)
+ {
+ 	Scsi_CD *cd = cdi->handle;
+@@ -310,14 +298,46 @@ int sr_lock_door(struct cdrom_device_info *cdi, int lock)
  
- 		set_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags);
+ int sr_drive_status(struct cdrom_device_info *cdi, int slot)
+ {
++	struct scsi_cd *cd = cdi->handle;
++	struct scsi_sense_hdr sshdr;
++	struct media_event_desc med;
++
+ 	if (CDSL_CURRENT != slot) {
+ 		/* we have no changer support */
+ 		return -EINVAL;
+ 	}
+-	if (0 == test_unit_ready(cdi->handle))
++	if (0 == scsi_test_unit_ready(cd->device, SR_TIMEOUT, MAX_RETRIES,
++				      &sshdr))
+ 		return CDS_DISC_OK;
  
-@@ -160,17 +131,10 @@ qla2x00_mailbox_command(scsi_qla_host_t *pvha, mbx_cmd_t *mcp)
- 			WRT_REG_WORD(&reg->isp.hccr, HCCR_SET_HOST_INT);
- 		spin_unlock_irqrestore(&ha->hardware_lock, flags);
+-	return CDS_TRAY_OPEN;
++	if (!cdrom_get_media_event(cdi, &med)) {
++		if (med.media_present)
++			return CDS_DISC_OK;
++		else if (med.door_open)
++			return CDS_TRAY_OPEN;
++		else
++			return CDS_NO_DISC;
++	}
++
++	/*
++	 * 0x04 is format in progress .. but there must be a disc present!
++	 */
++	if (sshdr.sense_key == NOT_READY && sshdr.asc == 0x04)
++		return CDS_DISC_OK;
++
++	/*
++	 * If not using Mt Fuji extended media tray reports,
++	 * just return TRAY_OPEN since ATAPI doesn't provide
++	 * any other way to detect this...
++	 */
++	if (scsi_sense_valid(&sshdr) &&
++	    /* 0x3a is medium not present */
++	    sshdr.asc == 0x3a)
++		return CDS_NO_DISC;
++	else
++		return CDS_TRAY_OPEN;
++
++	return CDS_DRIVE_NOT_READY;
+ }
  
--		/* Wait for either the timer to expire
--		 * or the mbox completion interrupt
--		 */
--		down(&ha->mbx_intr_sem);
-+		wait_for_completion_timeout(&ha->mbx_intr_comp, mcp->tov * HZ);
+ int sr_disk_status(struct cdrom_device_info *cdi)
+diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
+index 328c47c..7195270 100644
+--- a/drivers/scsi/st.c
++++ b/drivers/scsi/st.c
+@@ -9,7 +9,7 @@
+    Steve Hirsch, Andreas Koppenh"ofer, Michael Leodolter, Eyal Lebedinsky,
+    Michael Schaefer, J"org Weule, and Eric Youngdale.
  
--		DEBUG11(printk("%s(%ld): waking up. time=0x%lx\n", __func__,
--		    ha->host_no, jiffies));
- 		clear_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags);
+-   Copyright 1992 - 2007 Kai Makisara
++   Copyright 1992 - 2008 Kai Makisara
+    email Kai.Makisara at kolumbus.fi
  
--		/* delete the timer */
--		del_timer(&tmp_intr_timer);
- 	} else {
- 		DEBUG3_11(printk("%s(%ld): cmd=%x POLLING MODE.\n", __func__,
- 		    ha->host_no, command));
-@@ -299,7 +263,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *pvha, mbx_cmd_t *mcp)
+    Some small formal changes - aeb, 950809
+@@ -17,7 +17,7 @@
+    Last modified: 18-JAN-1998 Richard Gooch <rgooch at atnf.csiro.au> Devfs support
+  */
  
- 	/* Allow next mbx cmd to come in. */
- 	if (!abort_active)
--		up(&ha->mbx_cmd_sem);
-+		complete(&ha->mbx_cmd_comp);
+-static const char *verstr = "20070203";
++static const char *verstr = "20080117";
  
- 	if (rval) {
- 		DEBUG2_3_11(printk("%s(%ld): **** FAILED. mbx0=%x, mbx1=%x, "
-@@ -905,7 +869,7 @@ qla2x00_get_adapter_id(scsi_qla_host_t *ha, uint16_t *id, uint8_t *al_pa,
+ #include <linux/module.h>
  
- 	mcp->mb[0] = MBC_GET_ADAPTER_LOOP_ID;
- 	mcp->mb[9] = ha->vp_idx;
--	mcp->out_mb = MBX_0;
-+	mcp->out_mb = MBX_9|MBX_0;
- 	mcp->in_mb = MBX_9|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0;
- 	mcp->tov = 30;
- 	mcp->flags = 0;
-@@ -1016,7 +980,7 @@ qla2x00_init_firmware(scsi_qla_host_t *ha, uint16_t size)
- 	DEBUG11(printk("qla2x00_init_firmware(%ld): entered.\n",
- 	    ha->host_no));
+@@ -3214,8 +3214,7 @@ static int partition_tape(struct scsi_tape *STp, int size)
  
--	if (ha->flags.npiv_supported)
-+	if (ha->fw_attributes & BIT_2)
- 		mcp->mb[0] = MBC_MID_INITIALIZE_FIRMWARE;
- 	else
- 		mcp->mb[0] = MBC_INITIALIZE_FIRMWARE;
-@@ -2042,29 +2006,20 @@ qla2x00_get_fcal_position_map(scsi_qla_host_t *ha, char *pos_map)
-  */
- int
- qla2x00_get_link_status(scsi_qla_host_t *ha, uint16_t loop_id,
--    link_stat_t *ret_buf, uint16_t *status)
-+    struct link_statistics *stats, dma_addr_t stats_dma)
+ 
+ /* The ioctl command */
+-static int st_ioctl(struct inode *inode, struct file *file,
+-		    unsigned int cmd_in, unsigned long arg)
++static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg)
  {
- 	int rval;
- 	mbx_cmd_t mc;
- 	mbx_cmd_t *mcp = &mc;
--	link_stat_t *stat_buf;
--	dma_addr_t stat_buf_dma;
-+	uint32_t *siter, *diter, dwords;
+ 	int i, cmd_nr, cmd_type, bt;
+ 	int retval = 0;
+@@ -3870,7 +3869,7 @@ static const struct file_operations st_fops =
+ 	.owner =	THIS_MODULE,
+ 	.read =		st_read,
+ 	.write =	st_write,
+-	.ioctl =	st_ioctl,
++	.unlocked_ioctl = st_ioctl,
+ #ifdef CONFIG_COMPAT
+ 	.compat_ioctl = st_compat_ioctl,
+ #endif
+diff --git a/drivers/scsi/sun3_NCR5380.c b/drivers/scsi/sun3_NCR5380.c
+index 2dcde37..bcaba86 100644
+--- a/drivers/scsi/sun3_NCR5380.c
++++ b/drivers/scsi/sun3_NCR5380.c
+@@ -515,9 +515,9 @@ static __inline__ void initialize_SCp(struct scsi_cmnd *cmd)
+      * various queues are valid.
+      */
  
- 	DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
+-    if (cmd->use_sg) {
+-	cmd->SCp.buffer = (struct scatterlist *) cmd->request_buffer;
+-	cmd->SCp.buffers_residual = cmd->use_sg - 1;
++    if (scsi_bufflen(cmd)) {
++	cmd->SCp.buffer = scsi_sglist(cmd);
++	cmd->SCp.buffers_residual = scsi_sg_count(cmd) - 1;
+ 	cmd->SCp.ptr = (char *) SGADDR(cmd->SCp.buffer);
+ 	cmd->SCp.this_residual = cmd->SCp.buffer->length;
  
--	stat_buf = dma_pool_alloc(ha->s_dma_pool, GFP_ATOMIC, &stat_buf_dma);
--	if (stat_buf == NULL) {
--		DEBUG2_3_11(printk("%s(%ld): Failed to allocate memory.\n",
--		    __func__, ha->host_no));
--		return BIT_0;
--	}
--	memset(stat_buf, 0, sizeof(link_stat_t));
--
- 	mcp->mb[0] = MBC_GET_LINK_STATUS;
--	mcp->mb[2] = MSW(stat_buf_dma);
--	mcp->mb[3] = LSW(stat_buf_dma);
--	mcp->mb[6] = MSW(MSD(stat_buf_dma));
--	mcp->mb[7] = LSW(MSD(stat_buf_dma));
-+	mcp->mb[2] = MSW(stats_dma);
-+	mcp->mb[3] = LSW(stats_dma);
-+	mcp->mb[6] = MSW(MSD(stats_dma));
-+	mcp->mb[7] = LSW(MSD(stats_dma));
- 	mcp->out_mb = MBX_7|MBX_6|MBX_3|MBX_2|MBX_0;
- 	mcp->in_mb = MBX_0;
- 	if (IS_FWI2_CAPABLE(ha)) {
-@@ -2089,78 +2044,43 @@ qla2x00_get_link_status(scsi_qla_host_t *ha, uint16_t loop_id,
- 		if (mcp->mb[0] != MBS_COMMAND_COMPLETE) {
- 			DEBUG2_3_11(printk("%s(%ld): cmd failed. mbx0=%x.\n",
- 			    __func__, ha->host_no, mcp->mb[0]));
--			status[0] = mcp->mb[0];
--			rval = BIT_1;
-+			rval = QLA_FUNCTION_FAILED;
- 		} else {
--			/* copy over data -- firmware data is LE. */
--			ret_buf->link_fail_cnt =
--			    le32_to_cpu(stat_buf->link_fail_cnt);
--			ret_buf->loss_sync_cnt =
--			    le32_to_cpu(stat_buf->loss_sync_cnt);
--			ret_buf->loss_sig_cnt =
--			    le32_to_cpu(stat_buf->loss_sig_cnt);
--			ret_buf->prim_seq_err_cnt =
--			    le32_to_cpu(stat_buf->prim_seq_err_cnt);
--			ret_buf->inval_xmit_word_cnt =
--			    le32_to_cpu(stat_buf->inval_xmit_word_cnt);
--			ret_buf->inval_crc_cnt =
--			    le32_to_cpu(stat_buf->inval_crc_cnt);
--
--			DEBUG11(printk("%s(%ld): stat dump: fail_cnt=%d "
--			    "loss_sync=%d loss_sig=%d seq_err=%d "
--			    "inval_xmt_word=%d inval_crc=%d.\n", __func__,
--			    ha->host_no, stat_buf->link_fail_cnt,
--			    stat_buf->loss_sync_cnt, stat_buf->loss_sig_cnt,
--			    stat_buf->prim_seq_err_cnt,
--			    stat_buf->inval_xmit_word_cnt,
--			    stat_buf->inval_crc_cnt));
-+			/* Copy over data -- firmware data is LE. */
-+			dwords = offsetof(struct link_statistics, unused1) / 4;
-+			siter = diter = &stats->link_fail_cnt;
-+			while (dwords--)
-+				*diter++ = le32_to_cpu(*siter++);
- 		}
- 	} else {
- 		/* Failed. */
- 		DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", __func__,
- 		    ha->host_no, rval));
--		rval = BIT_1;
+@@ -528,8 +528,8 @@ static __inline__ void initialize_SCp(struct scsi_cmnd *cmd)
+     } else {
+ 	cmd->SCp.buffer = NULL;
+ 	cmd->SCp.buffers_residual = 0;
+-	cmd->SCp.ptr = (char *) cmd->request_buffer;
+-	cmd->SCp.this_residual = cmd->request_bufflen;
++	cmd->SCp.ptr = NULL;
++	cmd->SCp.this_residual = 0;
+     }
+     
+ }
+@@ -935,7 +935,7 @@ static int NCR5380_queue_command(struct scsi_cmnd *cmd,
+     }
+ # endif
+ # ifdef NCR5380_STAT_LIMIT
+-    if (cmd->request_bufflen > NCR5380_STAT_LIMIT)
++    if (scsi_bufflen(cmd) > NCR5380_STAT_LIMIT)
+ # endif
+ 	switch (cmd->cmnd[0])
+ 	{
+@@ -943,14 +943,14 @@ static int NCR5380_queue_command(struct scsi_cmnd *cmd,
+ 	    case WRITE_6:
+ 	    case WRITE_10:
+ 		hostdata->time_write[cmd->device->id] -= (jiffies - hostdata->timebase);
+-		hostdata->bytes_write[cmd->device->id] += cmd->request_bufflen;
++		hostdata->bytes_write[cmd->device->id] += scsi_bufflen(cmd);
+ 		hostdata->pendingw++;
+ 		break;
+ 	    case READ:
+ 	    case READ_6:
+ 	    case READ_10:
+ 		hostdata->time_read[cmd->device->id] -= (jiffies - hostdata->timebase);
+-		hostdata->bytes_read[cmd->device->id] += cmd->request_bufflen;
++		hostdata->bytes_read[cmd->device->id] += scsi_bufflen(cmd);
+ 		hostdata->pendingr++;
+ 		break;
+ 	}
+@@ -1345,7 +1345,7 @@ static void collect_stats(struct NCR5380_hostdata *hostdata,
+ 			  struct scsi_cmnd *cmd)
+ {
+ # ifdef NCR5380_STAT_LIMIT
+-    if (cmd->request_bufflen > NCR5380_STAT_LIMIT)
++    if (scsi_bufflen(cmd) > NCR5380_STAT_LIMIT)
+ # endif
+ 	switch (cmd->cmnd[0])
+ 	{
+@@ -1353,14 +1353,14 @@ static void collect_stats(struct NCR5380_hostdata *hostdata,
+ 	    case WRITE_6:
+ 	    case WRITE_10:
+ 		hostdata->time_write[cmd->device->id] += (jiffies - hostdata->timebase);
+-		/*hostdata->bytes_write[cmd->device->id] += cmd->request_bufflen;*/
++		/*hostdata->bytes_write[cmd->device->id] += scsi_bufflen(cmd);*/
+ 		hostdata->pendingw--;
+ 		break;
+ 	    case READ:
+ 	    case READ_6:
+ 	    case READ_10:
+ 		hostdata->time_read[cmd->device->id] += (jiffies - hostdata->timebase);
+-		/*hostdata->bytes_read[cmd->device->id] += cmd->request_bufflen;*/
++		/*hostdata->bytes_read[cmd->device->id] += scsi_bufflen(cmd);*/
+ 		hostdata->pendingr--;
+ 		break;
  	}
+@@ -1863,7 +1863,7 @@ static int do_abort (struct Scsi_Host *host)
+      * the target sees, so we just handshake.
+      */
+     
+-    while (!(tmp = NCR5380_read(STATUS_REG)) & SR_REQ);
++    while (!((tmp = NCR5380_read(STATUS_REG)) & SR_REQ));
  
--	dma_pool_free(ha->s_dma_pool, stat_buf, stat_buf_dma);
--
- 	return rval;
- }
+     NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp));
  
- int
--qla24xx_get_isp_stats(scsi_qla_host_t *ha, uint32_t *dwbuf, uint32_t dwords,
--    uint16_t *status)
-+qla24xx_get_isp_stats(scsi_qla_host_t *ha, struct link_statistics *stats,
-+    dma_addr_t stats_dma)
+diff --git a/drivers/scsi/sym53c416.c b/drivers/scsi/sym53c416.c
+index 90cee94..1f6fd16 100644
+--- a/drivers/scsi/sym53c416.c
++++ b/drivers/scsi/sym53c416.c
+@@ -328,27 +328,13 @@ static __inline__ unsigned int sym53c416_write(int base, unsigned char *buffer,
+ static irqreturn_t sym53c416_intr_handle(int irq, void *dev_id)
  {
- 	int rval;
- 	mbx_cmd_t mc;
- 	mbx_cmd_t *mcp = &mc;
--	uint32_t *sbuf, *siter;
--	dma_addr_t sbuf_dma;
-+	uint32_t *siter, *diter, dwords;
- 
- 	DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
+ 	struct Scsi_Host *dev = dev_id;
+-	int base = 0;
++	int base = dev->io_port;
+ 	int i;
+ 	unsigned long flags = 0;
+ 	unsigned char status_reg, pio_int_reg, int_reg;
+ 	struct scatterlist *sg;
+ 	unsigned int tot_trans = 0;
  
--	if (dwords > (DMA_POOL_SIZE / 4)) {
--		DEBUG2_3_11(printk("%s(%ld): Unabled to retrieve %d DWORDs "
--		    "(max %d).\n", __func__, ha->host_no, dwords,
--		    DMA_POOL_SIZE / 4));
--		return BIT_0;
--	}
--	sbuf = dma_pool_alloc(ha->s_dma_pool, GFP_ATOMIC, &sbuf_dma);
--	if (sbuf == NULL) {
--		DEBUG2_3_11(printk("%s(%ld): Failed to allocate memory.\n",
--		    __func__, ha->host_no));
--		return BIT_0;
+-	/* We search the base address of the host adapter which caused the interrupt */
+-	/* FIXME: should pass dev_id sensibly as hosts[i] */
+-	for(i = 0; i < host_index && !base; i++)
+-		if(irq == hosts[i].irq)
+-			base = hosts[i].base;
+-	/* If no adapter found, we cannot handle the interrupt. Leave a message */
+-	/* and continue. This should never happen...                            */
+-	if(!base)
+-	{
+-		printk(KERN_ERR "sym53c416: No host adapter defined for interrupt %d\n", irq);
+-		return IRQ_NONE;
 -	}
--	memset(sbuf, 0, DMA_POOL_SIZE);
+-	/* Now we have the base address and we can start handling the interrupt */
 -
- 	mcp->mb[0] = MBC_GET_LINK_PRIV_STATS;
--	mcp->mb[2] = MSW(sbuf_dma);
--	mcp->mb[3] = LSW(sbuf_dma);
--	mcp->mb[6] = MSW(MSD(sbuf_dma));
--	mcp->mb[7] = LSW(MSD(sbuf_dma));
--	mcp->mb[8] = dwords;
-+	mcp->mb[2] = MSW(stats_dma);
-+	mcp->mb[3] = LSW(stats_dma);
-+	mcp->mb[6] = MSW(MSD(stats_dma));
-+	mcp->mb[7] = LSW(MSD(stats_dma));
-+	mcp->mb[8] = sizeof(struct link_statistics) / 4;
-+	mcp->mb[9] = ha->vp_idx;
- 	mcp->mb[10] = 0;
--	mcp->out_mb = MBX_10|MBX_8|MBX_7|MBX_6|MBX_3|MBX_2|MBX_0;
-+	mcp->out_mb = MBX_10|MBX_9|MBX_8|MBX_7|MBX_6|MBX_3|MBX_2|MBX_0;
- 	mcp->in_mb = MBX_2|MBX_1|MBX_0;
- 	mcp->tov = 30;
- 	mcp->flags = IOCTL_CMD;
-@@ -2170,23 +2090,20 @@ qla24xx_get_isp_stats(scsi_qla_host_t *ha, uint32_t *dwbuf, uint32_t dwords,
- 		if (mcp->mb[0] != MBS_COMMAND_COMPLETE) {
- 			DEBUG2_3_11(printk("%s(%ld): cmd failed. mbx0=%x.\n",
- 			    __func__, ha->host_no, mcp->mb[0]));
--			status[0] = mcp->mb[0];
--			rval = BIT_1;
-+			rval = QLA_FUNCTION_FAILED;
+ 	spin_lock_irqsave(dev->host_lock,flags);
+ 	status_reg = inb(base + STATUS_REG);
+ 	pio_int_reg = inb(base + PIO_INT_REG);
+diff --git a/drivers/scsi/sym53c8xx_2/sym_glue.c b/drivers/scsi/sym53c8xx_2/sym_glue.c
+index 9e0908d..21e926d 100644
+--- a/drivers/scsi/sym53c8xx_2/sym_glue.c
++++ b/drivers/scsi/sym53c8xx_2/sym_glue.c
+@@ -207,10 +207,9 @@ void sym_set_cam_result_error(struct sym_hcb *np, struct sym_ccb *cp, int resid)
+ 			/*
+ 			 *  Bounce back the sense data to user.
+ 			 */
+-			memset(&cmd->sense_buffer, 0, sizeof(cmd->sense_buffer));
++			memset(&cmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
+ 			memcpy(cmd->sense_buffer, cp->sns_bbuf,
+-			      min(sizeof(cmd->sense_buffer),
+-				  (size_t)SYM_SNS_BBUF_LEN));
++			       min(SCSI_SENSE_BUFFERSIZE, SYM_SNS_BBUF_LEN));
+ #if 0
+ 			/*
+ 			 *  If the device reports a UNIT ATTENTION condition 
+@@ -609,22 +608,24 @@ static int sym_eh_handler(int op, char *opname, struct scsi_cmnd *cmd)
+ 	 */
+ #define WAIT_FOR_PCI_RECOVERY	35
+ 	if (pci_channel_offline(pdev)) {
+-		struct completion *io_reset;
+ 		int finished_reset = 0;
+ 		init_completion(&eh_done);
+ 		spin_lock_irq(shost->host_lock);
+ 		/* Make sure we didn't race */
+ 		if (pci_channel_offline(pdev)) {
+-			if (!sym_data->io_reset)
+-				sym_data->io_reset = &eh_done;
+-			io_reset = sym_data->io_reset;
++			BUG_ON(sym_data->io_reset);
++			sym_data->io_reset = &eh_done;
  		} else {
- 			/* Copy over data -- firmware data is LE. */
--			siter = sbuf;
-+			dwords = sizeof(struct link_statistics) / 4;
-+			siter = diter = &stats->link_fail_cnt;
- 			while (dwords--)
--				*dwbuf++ = le32_to_cpu(*siter++);
-+				*diter++ = le32_to_cpu(*siter++);
+ 			finished_reset = 1;
  		}
- 	} else {
- 		/* Failed. */
- 		DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", __func__,
- 		    ha->host_no, rval));
--		rval = BIT_1;
+ 		spin_unlock_irq(shost->host_lock);
+ 		if (!finished_reset)
+-			finished_reset = wait_for_completion_timeout(io_reset,
++			finished_reset = wait_for_completion_timeout
++						(sym_data->io_reset,
+ 						WAIT_FOR_PCI_RECOVERY*HZ);
++		spin_lock_irq(shost->host_lock);
++		sym_data->io_reset = NULL;
++		spin_unlock_irq(shost->host_lock);
+ 		if (!finished_reset)
+ 			return SCSI_FAILED;
  	}
- 
--	dma_pool_free(ha->s_dma_pool, sbuf, sbuf_dma);
--
- 	return rval;
- }
- 
-@@ -2331,6 +2248,8 @@ atarget_done:
- 	return rval;
+@@ -1744,7 +1745,7 @@ static int __devinit sym2_probe(struct pci_dev *pdev,
+ 	return -ENODEV;
  }
  
-+#if 0
-+
- int
- qla2x00_system_error(scsi_qla_host_t *ha)
+-static void __devexit sym2_remove(struct pci_dev *pdev)
++static void sym2_remove(struct pci_dev *pdev)
  {
-@@ -2360,47 +2279,7 @@ qla2x00_system_error(scsi_qla_host_t *ha)
- 	return rval;
- }
- 
--/**
-- * qla2x00_get_serdes_params() -
-- * @ha: HA context
-- *
-- * Returns
-- */
--int
--qla2x00_get_serdes_params(scsi_qla_host_t *ha, uint16_t *sw_em_1g,
--    uint16_t *sw_em_2g, uint16_t *sw_em_4g)
--{
--	int rval;
--	mbx_cmd_t mc;
--	mbx_cmd_t *mcp = &mc;
--
--	DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
--
--	mcp->mb[0] = MBC_SERDES_PARAMS;
--	mcp->mb[1] = 0;
--	mcp->out_mb = MBX_1|MBX_0;
--	mcp->in_mb = MBX_4|MBX_3|MBX_2|MBX_0;
--	mcp->tov = 30;
--	mcp->flags = 0;
--	rval = qla2x00_mailbox_command(ha, mcp);
--
--	if (rval != QLA_SUCCESS) {
--		/*EMPTY*/
--		DEBUG2_3_11(printk("%s(%ld): failed=%x (%x).\n", __func__,
--		    ha->host_no, rval, mcp->mb[0]));
--	} else {
--		DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no));
--
--		if (sw_em_1g)
--			*sw_em_1g = mcp->mb[2];
--		if (sw_em_2g)
--			*sw_em_2g = mcp->mb[3];
--		if (sw_em_4g)
--			*sw_em_4g = mcp->mb[4];
--	}
--
--	return rval;
--}
-+#endif  /*  0  */
+ 	struct Scsi_Host *shost = pci_get_drvdata(pdev);
  
- /**
-  * qla2x00_set_serdes_params() -
-@@ -2471,7 +2350,7 @@ qla2x00_stop_firmware(scsi_qla_host_t *ha)
+@@ -1879,7 +1880,6 @@ static void sym2_io_resume(struct pci_dev *pdev)
+ 	spin_lock_irq(shost->host_lock);
+ 	if (sym_data->io_reset)
+ 		complete_all(sym_data->io_reset);
+-	sym_data->io_reset = NULL;
+ 	spin_unlock_irq(shost->host_lock);
  }
  
- int
--qla2x00_trace_control(scsi_qla_host_t *ha, uint16_t ctrl, dma_addr_t eft_dma,
-+qla2x00_enable_eft_trace(scsi_qla_host_t *ha, dma_addr_t eft_dma,
-     uint16_t buffers)
- {
- 	int rval;
-@@ -2484,22 +2363,18 @@ qla2x00_trace_control(scsi_qla_host_t *ha, uint16_t ctrl, dma_addr_t eft_dma,
- 	DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
+@@ -2056,7 +2056,7 @@ static struct pci_driver sym2_driver = {
+ 	.name		= NAME53C8XX,
+ 	.id_table	= sym2_id_table,
+ 	.probe		= sym2_probe,
+-	.remove		= __devexit_p(sym2_remove),
++	.remove		= sym2_remove,
+ 	.err_handler 	= &sym2_err_handler,
+ };
  
- 	mcp->mb[0] = MBC_TRACE_CONTROL;
--	mcp->mb[1] = ctrl;
--	mcp->out_mb = MBX_1|MBX_0;
-+	mcp->mb[1] = TC_EFT_ENABLE;
-+	mcp->mb[2] = LSW(eft_dma);
-+	mcp->mb[3] = MSW(eft_dma);
-+	mcp->mb[4] = LSW(MSD(eft_dma));
-+	mcp->mb[5] = MSW(MSD(eft_dma));
-+	mcp->mb[6] = buffers;
-+	mcp->mb[7] = TC_AEN_DISABLE;
-+	mcp->out_mb = MBX_7|MBX_6|MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0;
- 	mcp->in_mb = MBX_1|MBX_0;
--	if (ctrl == TC_ENABLE) {
--		mcp->mb[2] = LSW(eft_dma);
--		mcp->mb[3] = MSW(eft_dma);
--		mcp->mb[4] = LSW(MSD(eft_dma));
--		mcp->mb[5] = MSW(MSD(eft_dma));
--		mcp->mb[6] = buffers;
--		mcp->mb[7] = 0;
--		mcp->out_mb |= MBX_7|MBX_6|MBX_5|MBX_4|MBX_3|MBX_2;
--	}
- 	mcp->tov = 30;
- 	mcp->flags = 0;
- 	rval = qla2x00_mailbox_command(ha, mcp);
--
- 	if (rval != QLA_SUCCESS) {
- 		DEBUG2_3_11(printk("%s(%ld): failed=%x mb[0]=%x mb[1]=%x.\n",
- 		    __func__, ha->host_no, rval, mcp->mb[0], mcp->mb[1]));
-@@ -2511,8 +2386,7 @@ qla2x00_trace_control(scsi_qla_host_t *ha, uint16_t ctrl, dma_addr_t eft_dma,
- }
+diff --git a/drivers/scsi/tmscsim.c b/drivers/scsi/tmscsim.c
+index 4419304..5b04ddf 100644
+--- a/drivers/scsi/tmscsim.c
++++ b/drivers/scsi/tmscsim.c
+@@ -444,7 +444,7 @@ static int dc390_pci_map (struct dc390_srb* pSRB)
  
- int
--qla2x00_read_sfp(scsi_qla_host_t *ha, dma_addr_t sfp_dma, uint16_t addr,
--    uint16_t off, uint16_t count)
-+qla2x00_disable_eft_trace(scsi_qla_host_t *ha)
- {
- 	int rval;
- 	mbx_cmd_t mc;
-@@ -2523,24 +2397,16 @@ qla2x00_read_sfp(scsi_qla_host_t *ha, dma_addr_t sfp_dma, uint16_t addr,
+ 	/* Map sense buffer */
+ 	if (pSRB->SRBFlag & AUTO_REQSENSE) {
+-		pSRB->pSegmentList	= dc390_sg_build_single(&pSRB->Segmentx, pcmd->sense_buffer, sizeof(pcmd->sense_buffer));
++		pSRB->pSegmentList	= dc390_sg_build_single(&pSRB->Segmentx, pcmd->sense_buffer, SCSI_SENSE_BUFFERSIZE);
+ 		pSRB->SGcount		= pci_map_sg(pdev, pSRB->pSegmentList, 1,
+ 						     DMA_FROM_DEVICE);
+ 		cmdp->saved_dma_handle	= sg_dma_address(pSRB->pSegmentList);
+@@ -599,7 +599,7 @@ dc390_StartSCSI( struct dc390_acb* pACB, struct dc390_dcb* pDCB, struct dc390_sr
+ 	    DC390_write8 (ScsiFifo, pDCB->TargetLUN << 5);
+ 	    DC390_write8 (ScsiFifo, 0);
+ 	    DC390_write8 (ScsiFifo, 0);
+-	    DC390_write8 (ScsiFifo, sizeof(scmd->sense_buffer));
++	    DC390_write8 (ScsiFifo, SCSI_SENSE_BUFFERSIZE);
+ 	    DC390_write8 (ScsiFifo, 0);
+ 	    DEBUG1(printk (KERN_DEBUG "DC390: AutoReqSense !\n"));
+ 	  }
+@@ -1389,7 +1389,7 @@ dc390_CommandPhase( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus
+ 	DC390_write8 (ScsiFifo, pDCB->TargetLUN << 5);
+ 	DC390_write8 (ScsiFifo, 0);
+ 	DC390_write8 (ScsiFifo, 0);
+-	DC390_write8 (ScsiFifo, sizeof(pSRB->pcmd->sense_buffer));
++	DC390_write8 (ScsiFifo, SCSI_SENSE_BUFFERSIZE);
+ 	DC390_write8 (ScsiFifo, 0);
+ 	DEBUG0(printk(KERN_DEBUG "DC390: AutoReqSense (CmndPhase)!\n"));
+     }
+diff --git a/drivers/scsi/u14-34f.c b/drivers/scsi/u14-34f.c
+index 7edd6ce..4bc5407 100644
+--- a/drivers/scsi/u14-34f.c
++++ b/drivers/scsi/u14-34f.c
+@@ -1121,9 +1121,9 @@ static void map_dma(unsigned int i, unsigned int j) {
  
- 	DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
+    if (SCpnt->sense_buffer)
+       cpp->sense_addr = H2DEV(pci_map_single(HD(j)->pdev, SCpnt->sense_buffer,
+-                           sizeof SCpnt->sense_buffer, PCI_DMA_FROMDEVICE));
++                           SCSI_SENSE_BUFFERSIZE, PCI_DMA_FROMDEVICE));
  
--	mcp->mb[0] = MBC_READ_SFP;
--	mcp->mb[1] = addr;
--	mcp->mb[2] = MSW(sfp_dma);
--	mcp->mb[3] = LSW(sfp_dma);
--	mcp->mb[6] = MSW(MSD(sfp_dma));
--	mcp->mb[7] = LSW(MSD(sfp_dma));
--	mcp->mb[8] = count;
--	mcp->mb[9] = off;
--	mcp->mb[10] = 0;
--	mcp->out_mb = MBX_10|MBX_9|MBX_8|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0;
--	mcp->in_mb = MBX_0;
-+	mcp->mb[0] = MBC_TRACE_CONTROL;
-+	mcp->mb[1] = TC_EFT_DISABLE;
-+	mcp->out_mb = MBX_1|MBX_0;
-+	mcp->in_mb = MBX_1|MBX_0;
- 	mcp->tov = 30;
- 	mcp->flags = 0;
- 	rval = qla2x00_mailbox_command(ha, mcp);
--
- 	if (rval != QLA_SUCCESS) {
--		DEBUG2_3_11(printk("%s(%ld): failed=%x (%x).\n", __func__,
--		    ha->host_no, rval, mcp->mb[0]));
-+		DEBUG2_3_11(printk("%s(%ld): failed=%x mb[0]=%x mb[1]=%x.\n",
-+		    __func__, ha->host_no, rval, mcp->mb[0], mcp->mb[1]));
- 	} else {
- 		DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no));
- 	}
-@@ -2549,176 +2415,168 @@ qla2x00_read_sfp(scsi_qla_host_t *ha, dma_addr_t sfp_dma, uint16_t addr,
- }
+-   cpp->sense_len = sizeof SCpnt->sense_buffer;
++   cpp->sense_len = SCSI_SENSE_BUFFERSIZE;
  
- int
--qla2x00_get_idma_speed(scsi_qla_host_t *ha, uint16_t loop_id,
--    uint16_t *port_speed, uint16_t *mb)
-+qla2x00_enable_fce_trace(scsi_qla_host_t *ha, dma_addr_t fce_dma,
-+    uint16_t buffers, uint16_t *mb, uint32_t *dwords)
- {
- 	int rval;
- 	mbx_cmd_t mc;
- 	mbx_cmd_t *mcp = &mc;
+    if (scsi_bufflen(SCpnt)) {
+ 	   count = scsi_dma_map(SCpnt);
+diff --git a/drivers/scsi/ultrastor.c b/drivers/scsi/ultrastor.c
+index 6d1f0ed..75eca6b 100644
+--- a/drivers/scsi/ultrastor.c
++++ b/drivers/scsi/ultrastor.c
+@@ -298,9 +298,16 @@ static inline int find_and_clear_bit_16(unsigned long *field)
+ {
+   int rv;
  
--	if (!IS_IIDMA_CAPABLE(ha))
-+	if (!IS_QLA25XX(ha))
- 		return QLA_FUNCTION_FAILED;
+-  if (*field == 0) panic("No free mscp");
+-  asm("xorl %0,%0\n0:\tbsfw %1,%w0\n\tbtr %0,%1\n\tjnc 0b"
+-      : "=&r" (rv), "=m" (*field) : "1" (*field));
++  if (*field == 0)
++    panic("No free mscp");
++
++  asm volatile (
++	"xorl %0,%0\n\t"
++	"0: bsfw %1,%w0\n\t"
++	"btr %0,%1\n\t"
++	"jnc 0b"
++	: "=&r" (rv), "=m" (*field) :);
++
+   return rv;
+ }
  
- 	DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
+@@ -741,7 +748,7 @@ static int ultrastor_queuecommand(struct scsi_cmnd *SCpnt,
+     }
+     my_mscp->command_link = 0;		/*???*/
+     my_mscp->scsi_command_link_id = 0;	/*???*/
+-    my_mscp->length_of_sense_byte = sizeof SCpnt->sense_buffer;
++    my_mscp->length_of_sense_byte = SCSI_SENSE_BUFFERSIZE;
+     my_mscp->length_of_scsi_cdbs = SCpnt->cmd_len;
+     memcpy(my_mscp->scsi_cdbs, SCpnt->cmnd, my_mscp->length_of_scsi_cdbs);
+     my_mscp->adapter_status = 0;
+diff --git a/drivers/scsi/wd33c93.c b/drivers/scsi/wd33c93.c
+index fdbb92d..f286c37 100644
+--- a/drivers/scsi/wd33c93.c
++++ b/drivers/scsi/wd33c93.c
+@@ -407,16 +407,16 @@ wd33c93_queuecommand(struct scsi_cmnd *cmd,
+  *  - SCp.phase records this command's SRCID_ER bit setting
+  */
  
--	mcp->mb[0] = MBC_PORT_PARAMS;
--	mcp->mb[1] = loop_id;
--	mcp->mb[2] = mcp->mb[3] = mcp->mb[4] = mcp->mb[5] = 0;
--	mcp->out_mb = MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0;
--	mcp->in_mb = MBX_5|MBX_4|MBX_3|MBX_1|MBX_0;
-+	mcp->mb[0] = MBC_TRACE_CONTROL;
-+	mcp->mb[1] = TC_FCE_ENABLE;
-+	mcp->mb[2] = LSW(fce_dma);
-+	mcp->mb[3] = MSW(fce_dma);
-+	mcp->mb[4] = LSW(MSD(fce_dma));
-+	mcp->mb[5] = MSW(MSD(fce_dma));
-+	mcp->mb[6] = buffers;
-+	mcp->mb[7] = TC_AEN_DISABLE;
-+	mcp->mb[8] = 0;
-+	mcp->mb[9] = TC_FCE_DEFAULT_RX_SIZE;
-+	mcp->mb[10] = TC_FCE_DEFAULT_TX_SIZE;
-+	mcp->out_mb = MBX_10|MBX_9|MBX_8|MBX_7|MBX_6|MBX_5|MBX_4|MBX_3|MBX_2|
-+	    MBX_1|MBX_0;
-+	mcp->in_mb = MBX_6|MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0;
- 	mcp->tov = 30;
- 	mcp->flags = 0;
- 	rval = qla2x00_mailbox_command(ha, mcp);
--
--	/* Return mailbox statuses. */
--	if (mb != NULL) {
--		mb[0] = mcp->mb[0];
--		mb[1] = mcp->mb[1];
--		mb[3] = mcp->mb[3];
--		mb[4] = mcp->mb[4];
--		mb[5] = mcp->mb[5];
--	}
--
- 	if (rval != QLA_SUCCESS) {
--		DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", __func__,
--		    ha->host_no, rval));
-+		DEBUG2_3_11(printk("%s(%ld): failed=%x mb[0]=%x mb[1]=%x.\n",
-+		    __func__, ha->host_no, rval, mcp->mb[0], mcp->mb[1]));
+-	if (cmd->use_sg) {
+-		cmd->SCp.buffer = (struct scatterlist *) cmd->request_buffer;
+-		cmd->SCp.buffers_residual = cmd->use_sg - 1;
++	if (scsi_bufflen(cmd)) {
++		cmd->SCp.buffer = scsi_sglist(cmd);
++		cmd->SCp.buffers_residual = scsi_sg_count(cmd) - 1;
+ 		cmd->SCp.ptr = sg_virt(cmd->SCp.buffer);
+ 		cmd->SCp.this_residual = cmd->SCp.buffer->length;
  	} else {
- 		DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no));
--		if (port_speed)
--			*port_speed = mcp->mb[3];
-+
-+		if (mb)
-+			memcpy(mb, mcp->mb, 8 * sizeof(*mb));
-+		if (dwords)
-+			*dwords = mcp->mb[6];
+ 		cmd->SCp.buffer = NULL;
+ 		cmd->SCp.buffers_residual = 0;
+-		cmd->SCp.ptr = (char *) cmd->request_buffer;
+-		cmd->SCp.this_residual = cmd->request_bufflen;
++		cmd->SCp.ptr = NULL;
++		cmd->SCp.this_residual = 0;
  	}
  
- 	return rval;
- }
- 
- int
--qla2x00_set_idma_speed(scsi_qla_host_t *ha, uint16_t loop_id,
--    uint16_t port_speed, uint16_t *mb)
-+qla2x00_disable_fce_trace(scsi_qla_host_t *ha, uint64_t *wr, uint64_t *rd)
- {
- 	int rval;
- 	mbx_cmd_t mc;
- 	mbx_cmd_t *mcp = &mc;
+ /* WD docs state that at the conclusion of a "LEVEL2" command, the
+diff --git a/drivers/scsi/wd7000.c b/drivers/scsi/wd7000.c
+index 03cd44f..b4304ae 100644
+--- a/drivers/scsi/wd7000.c
++++ b/drivers/scsi/wd7000.c
+@@ -1108,13 +1108,10 @@ static int wd7000_queuecommand(struct scsi_cmnd *SCpnt,
+ 	scb->host = host;
  
--	if (!IS_IIDMA_CAPABLE(ha))
-+	if (!IS_FWI2_CAPABLE(ha))
- 		return QLA_FUNCTION_FAILED;
+ 	nseg = scsi_sg_count(SCpnt);
+-	if (nseg) {
++	if (nseg > 1) {
+ 		struct scatterlist *sg;
+ 		unsigned i;
  
- 	DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
+-		if (SCpnt->device->host->sg_tablesize == SG_NONE) {
+-			panic("wd7000_queuecommand: scatter/gather not supported.\n");
+-		}
+ 		dprintk("Using scatter/gather with %d elements.\n", nseg);
  
--	mcp->mb[0] = MBC_PORT_PARAMS;
--	mcp->mb[1] = loop_id;
--	mcp->mb[2] = BIT_0;
--	mcp->mb[3] = port_speed & (BIT_2|BIT_1|BIT_0);
--	mcp->mb[4] = mcp->mb[5] = 0;
--	mcp->out_mb = MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0;
--	mcp->in_mb = MBX_5|MBX_4|MBX_3|MBX_1|MBX_0;
-+	mcp->mb[0] = MBC_TRACE_CONTROL;
-+	mcp->mb[1] = TC_FCE_DISABLE;
-+	mcp->mb[2] = TC_FCE_DISABLE_TRACE;
-+	mcp->out_mb = MBX_2|MBX_1|MBX_0;
-+	mcp->in_mb = MBX_9|MBX_8|MBX_7|MBX_6|MBX_5|MBX_4|MBX_3|MBX_2|
-+	    MBX_1|MBX_0;
- 	mcp->tov = 30;
- 	mcp->flags = 0;
- 	rval = qla2x00_mailbox_command(ha, mcp);
--
--	/* Return mailbox statuses. */
--	if (mb != NULL) {
--		mb[0] = mcp->mb[0];
--		mb[1] = mcp->mb[1];
--		mb[3] = mcp->mb[3];
--		mb[4] = mcp->mb[4];
--		mb[5] = mcp->mb[5];
--	}
--
- 	if (rval != QLA_SUCCESS) {
--		DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", __func__,
--		    ha->host_no, rval));
-+		DEBUG2_3_11(printk("%s(%ld): failed=%x mb[0]=%x mb[1]=%x.\n",
-+		    __func__, ha->host_no, rval, mcp->mb[0], mcp->mb[1]));
+ 		sgb = scb->sgb;
+@@ -1128,7 +1125,10 @@ static int wd7000_queuecommand(struct scsi_cmnd *SCpnt,
+ 		}
  	} else {
- 		DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no));
-+
-+		if (wr)
-+			*wr = (uint64_t) mcp->mb[5] << 48 |
-+			    (uint64_t) mcp->mb[4] << 32 |
-+			    (uint64_t) mcp->mb[3] << 16 |
-+			    (uint64_t) mcp->mb[2];
-+		if (rd)
-+			*rd = (uint64_t) mcp->mb[9] << 48 |
-+			    (uint64_t) mcp->mb[8] << 32 |
-+			    (uint64_t) mcp->mb[7] << 16 |
-+			    (uint64_t) mcp->mb[6];
+ 		scb->op = 0;
+-		any2scsi(scb->dataptr, isa_virt_to_bus(scsi_sglist(SCpnt)));
++		if (nseg) {
++			struct scatterlist *sg = scsi_sglist(SCpnt);
++			any2scsi(scb->dataptr, isa_page_to_bus(sg_page(sg)) + sg->offset);
++		}
+ 		any2scsi(scb->maxlen, scsi_bufflen(SCpnt));
  	}
  
- 	return rval;
- }
+@@ -1524,7 +1524,7 @@ static __init int wd7000_detect(struct scsi_host_template *tpnt)
+ 				 *  For boards before rev 6.0, scatter/gather isn't supported.
+ 				 */
+ 				if (host->rev1 < 6)
+-					sh->sg_tablesize = SG_NONE;
++					sh->sg_tablesize = 1;
  
--/*
-- * qla24xx_get_vp_database
-- *	Get the VP's database for all configured ports.
-- *
-- * Input:
-- *	ha = adapter block pointer.
-- *	size = size of initialization control block.
-- *
-- * Returns:
-- *	qla2x00 local function return status code.
-- *
-- * Context:
-- *	Kernel context.
-- */
- int
--qla24xx_get_vp_database(scsi_qla_host_t *ha, uint16_t size)
-+qla2x00_read_sfp(scsi_qla_host_t *ha, dma_addr_t sfp_dma, uint16_t addr,
-+    uint16_t off, uint16_t count)
- {
- 	int rval;
- 	mbx_cmd_t mc;
- 	mbx_cmd_t *mcp = &mc;
+ 				present++;	/* count it */
  
--	DEBUG11(printk("scsi(%ld):%s - entered.\n",
--	    ha->host_no, __func__));
-+	if (!IS_FWI2_CAPABLE(ha))
-+		return QLA_FUNCTION_FAILED;
+diff --git a/drivers/serial/21285.c b/drivers/serial/21285.c
+index facb678..6a48dfa 100644
+--- a/drivers/serial/21285.c
++++ b/drivers/serial/21285.c
+@@ -277,6 +277,8 @@ serial21285_set_termios(struct uart_port *port, struct ktermios *termios,
+ 	if (termios->c_iflag & INPCK)
+ 		port->read_status_mask |= RXSTAT_FRAME | RXSTAT_PARITY;
  
--	mcp->mb[0] = MBC_MID_GET_VP_DATABASE;
--	mcp->mb[2] = MSW(ha->init_cb_dma);
--	mcp->mb[3] = LSW(ha->init_cb_dma);
--	mcp->mb[4] = 0;
--	mcp->mb[5] = 0;
--	mcp->mb[6] = MSW(MSD(ha->init_cb_dma));
--	mcp->mb[7] = LSW(MSD(ha->init_cb_dma));
--	mcp->out_mb = MBX_7|MBX_6|MBX_3|MBX_2|MBX_0;
--	mcp->in_mb = MBX_1|MBX_0;
--	mcp->buf_size = size;
--	mcp->flags = MBX_DMA_OUT;
--	mcp->tov = MBX_TOV_SECONDS;
-+	DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
++	tty_encode_baud_rate(tty,  baud, baud);
 +
-+	mcp->mb[0] = MBC_READ_SFP;
-+	mcp->mb[1] = addr;
-+	mcp->mb[2] = MSW(sfp_dma);
-+	mcp->mb[3] = LSW(sfp_dma);
-+	mcp->mb[6] = MSW(MSD(sfp_dma));
-+	mcp->mb[7] = LSW(MSD(sfp_dma));
-+	mcp->mb[8] = count;
-+	mcp->mb[9] = off;
-+	mcp->mb[10] = 0;
-+	mcp->out_mb = MBX_10|MBX_9|MBX_8|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0;
-+	mcp->in_mb = MBX_0;
-+	mcp->tov = 30;
-+	mcp->flags = 0;
- 	rval = qla2x00_mailbox_command(ha, mcp);
+ 	/*
+ 	 * Which character status flags should we ignore?
+ 	 */
+diff --git a/drivers/serial/bfin_5xx.c b/drivers/serial/bfin_5xx.c
+index 6f475b6..ac2a3ef 100644
+--- a/drivers/serial/bfin_5xx.c
++++ b/drivers/serial/bfin_5xx.c
+@@ -442,7 +442,8 @@ static void bfin_serial_dma_tx_chars(struct bfin_serial_port *uart)
+ 		set_bfin_dma_config(DIR_READ, DMA_FLOW_STOP,
+ 			INTR_ON_BUF,
+ 			DIMENSION_LINEAR,
+-			DATA_SIZE_8));
++			DATA_SIZE_8,
++			DMA_SYNC_RESTART));
+ 	set_dma_start_addr(uart->tx_dma_channel, (unsigned long)(xmit->buf+xmit->tail));
+ 	set_dma_x_count(uart->tx_dma_channel, uart->tx_count);
+ 	set_dma_x_modify(uart->tx_dma_channel, 1);
+@@ -689,7 +690,8 @@ static int bfin_serial_startup(struct uart_port *port)
+ 	set_dma_config(uart->rx_dma_channel,
+ 		set_bfin_dma_config(DIR_WRITE, DMA_FLOW_AUTO,
+ 				INTR_ON_ROW, DIMENSION_2D,
+-				DATA_SIZE_8));
++				DATA_SIZE_8,
++				DMA_SYNC_RESTART));
+ 	set_dma_x_count(uart->rx_dma_channel, DMA_RX_XCOUNT);
+ 	set_dma_x_modify(uart->rx_dma_channel, 1);
+ 	set_dma_y_count(uart->rx_dma_channel, DMA_RX_YCOUNT);
+diff --git a/drivers/serial/icom.c b/drivers/serial/icom.c
+index 9d3105b..9c2df5c 100644
+--- a/drivers/serial/icom.c
++++ b/drivers/serial/icom.c
+@@ -48,7 +48,7 @@
+ #include <linux/vmalloc.h>
+ #include <linux/smp.h>
+ #include <linux/spinlock.h>
+-#include <linux/kobject.h>
++#include <linux/kref.h>
+ #include <linux/firmware.h>
+ #include <linux/bitops.h>
  
- 	if (rval != QLA_SUCCESS) {
--		/*EMPTY*/
--		DEBUG2_3_11(printk("%s(%ld): failed=%x "
--		    "mb0=%x.\n",
--		    __func__, ha->host_no, rval, mcp->mb[0]));
-+		DEBUG2_3_11(printk("%s(%ld): failed=%x (%x).\n", __func__,
-+		    ha->host_no, rval, mcp->mb[0]));
- 	} else {
--		/*EMPTY*/
--		DEBUG11(printk("%s(%ld): done.\n",
--		    __func__, ha->host_no));
-+		DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no));
- 	}
+@@ -65,7 +65,7 @@
+ #define ICOM_VERSION_STR "1.3.1"
+ #define NR_PORTS	       128
+ #define ICOM_PORT ((struct icom_port *)port)
+-#define to_icom_adapter(d) container_of(d, struct icom_adapter, kobj)
++#define to_icom_adapter(d) container_of(d, struct icom_adapter, kref)
  
- 	return rval;
- }
+ static const struct pci_device_id icom_pci_table[] = {
+ 	{
+@@ -141,6 +141,7 @@ static inline void trace(struct icom_port *, char *, unsigned long) {};
+ #else
+ static inline void trace(struct icom_port *icom_port, char *trace_pt, unsigned long trace_data) {};
+ #endif
++static void icom_kref_release(struct kref *kref);
  
- int
--qla24xx_get_vp_entry(scsi_qla_host_t *ha, uint16_t size, int vp_id)
-+qla2x00_set_idma_speed(scsi_qla_host_t *ha, uint16_t loop_id,
-+    uint16_t port_speed, uint16_t *mb)
+ static void free_port_memory(struct icom_port *icom_port)
  {
- 	int rval;
- 	mbx_cmd_t mc;
- 	mbx_cmd_t *mcp = &mc;
- 
-+	if (!IS_IIDMA_CAPABLE(ha))
-+		return QLA_FUNCTION_FAILED;
-+
- 	DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
+@@ -1063,11 +1064,11 @@ static int icom_open(struct uart_port *port)
+ {
+ 	int retval;
  
--	mcp->mb[0] = MBC_MID_GET_VP_ENTRY;
--	mcp->mb[2] = MSW(ha->init_cb_dma);
--	mcp->mb[3] = LSW(ha->init_cb_dma);
--	mcp->mb[4] = 0;
--	mcp->mb[5] = 0;
--	mcp->mb[6] = MSW(MSD(ha->init_cb_dma));
--	mcp->mb[7] = LSW(MSD(ha->init_cb_dma));
--	mcp->mb[9] = vp_id;
--	mcp->out_mb = MBX_9|MBX_7|MBX_6|MBX_3|MBX_2|MBX_0;
--	mcp->in_mb = MBX_0;
--	mcp->buf_size = size;
--	mcp->flags = MBX_DMA_OUT;
-+	mcp->mb[0] = MBC_PORT_PARAMS;
-+	mcp->mb[1] = loop_id;
-+	mcp->mb[2] = BIT_0;
-+	mcp->mb[3] = port_speed & (BIT_2|BIT_1|BIT_0);
-+	mcp->mb[4] = mcp->mb[5] = 0;
-+	mcp->out_mb = MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0;
-+	mcp->in_mb = MBX_5|MBX_4|MBX_3|MBX_1|MBX_0;
- 	mcp->tov = 30;
-+	mcp->flags = 0;
- 	rval = qla2x00_mailbox_command(ha, mcp);
+-	kobject_get(&ICOM_PORT->adapter->kobj);
++	kref_get(&ICOM_PORT->adapter->kref);
+ 	retval = startup(ICOM_PORT);
  
-+	/* Return mailbox statuses. */
-+	if (mb != NULL) {
-+		mb[0] = mcp->mb[0];
-+		mb[1] = mcp->mb[1];
-+		mb[3] = mcp->mb[3];
-+		mb[4] = mcp->mb[4];
-+		mb[5] = mcp->mb[5];
-+	}
-+
- 	if (rval != QLA_SUCCESS) {
--		/*EMPTY*/
--		DEBUG2_3_11(printk("qla24xx_get_vp_entry(%ld): failed=%x "
--		    "mb0=%x.\n",
--		    ha->host_no, rval, mcp->mb[0]));
-+		DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", __func__,
-+		    ha->host_no, rval));
- 	} else {
--		/*EMPTY*/
--		DEBUG11(printk("qla24xx_get_vp_entry(%ld): done.\n",
--		    ha->host_no));
-+		DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no));
+ 	if (retval) {
+-		kobject_put(&ICOM_PORT->adapter->kobj);
++		kref_put(&ICOM_PORT->adapter->kref, icom_kref_release);
+ 		trace(ICOM_PORT, "STARTUP_ERROR", 0);
+ 		return retval;
  	}
+@@ -1088,7 +1089,7 @@ static void icom_close(struct uart_port *port)
  
- 	return rval;
-@@ -2873,7 +2731,7 @@ qla24xx_control_vp(scsi_qla_host_t *vha, int cmd)
- 	DEBUG11(printk("%s(%ld): entered. Enabling index %d\n", __func__,
- 	    ha->host_no, vp_index));
+ 	shutdown(ICOM_PORT);
  
--	if (vp_index == 0 || vp_index >= MAX_MULTI_ID_LOOP)
-+	if (vp_index == 0 || vp_index >= ha->max_npiv_vports)
- 		return QLA_PARAMETER_ERROR;
+-	kobject_put(&ICOM_PORT->adapter->kobj);
++	kref_put(&ICOM_PORT->adapter->kref, icom_kref_release);
+ }
  
- 	vce = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &vce_dma);
-diff --git a/drivers/scsi/qla2xxx/qla_mid.c b/drivers/scsi/qla2xxx/qla_mid.c
-index 821ee74..cf784cd 100644
---- a/drivers/scsi/qla2xxx/qla_mid.c
-+++ b/drivers/scsi/qla2xxx/qla_mid.c
-@@ -39,7 +39,7 @@ qla2x00_vp_stop_timer(scsi_qla_host_t *vha)
- 	}
+ static void icom_set_termios(struct uart_port *port,
+@@ -1485,18 +1486,14 @@ static void icom_remove_adapter(struct icom_adapter *icom_adapter)
+ 	pci_release_regions(icom_adapter->pci_dev);
  }
  
--uint32_t
-+static uint32_t
- qla24xx_allocate_vp_id(scsi_qla_host_t *vha)
+-static void icom_kobj_release(struct kobject *kobj)
++static void icom_kref_release(struct kref *kref)
  {
- 	uint32_t vp_id;
-@@ -47,16 +47,15 @@ qla24xx_allocate_vp_id(scsi_qla_host_t *vha)
- 
- 	/* Find an empty slot and assign an vp_id */
- 	down(&ha->vport_sem);
--	vp_id = find_first_zero_bit((unsigned long *)ha->vp_idx_map,
--				MAX_MULTI_ID_FABRIC);
--	if (vp_id > MAX_MULTI_ID_FABRIC) {
--		DEBUG15(printk ("vp_id %d is bigger than MAX_MULTI_ID_FABRID\n",
--		    vp_id));
-+	vp_id = find_first_zero_bit(ha->vp_idx_map, ha->max_npiv_vports + 1);
-+	if (vp_id > ha->max_npiv_vports) {
-+		DEBUG15(printk ("vp_id %d is bigger than max-supported %d.\n",
-+		    vp_id, ha->max_npiv_vports));
- 		up(&ha->vport_sem);
- 		return vp_id;
- 	}
+ 	struct icom_adapter *icom_adapter;
  
--	set_bit(vp_id, (unsigned long *)ha->vp_idx_map);
-+	set_bit(vp_id, ha->vp_idx_map);
- 	ha->num_vhosts++;
- 	vha->vp_idx = vp_id;
- 	list_add_tail(&vha->vp_list, &ha->vp_list);
-@@ -73,12 +72,12 @@ qla24xx_deallocate_vp_id(scsi_qla_host_t *vha)
- 	down(&ha->vport_sem);
- 	vp_id = vha->vp_idx;
- 	ha->num_vhosts--;
--	clear_bit(vp_id, (unsigned long *)ha->vp_idx_map);
-+	clear_bit(vp_id, ha->vp_idx_map);
- 	list_del(&vha->vp_list);
- 	up(&ha->vport_sem);
+-	icom_adapter = to_icom_adapter(kobj);
++	icom_adapter = to_icom_adapter(kref);
+ 	icom_remove_adapter(icom_adapter);
  }
  
--scsi_qla_host_t *
-+static scsi_qla_host_t *
- qla24xx_find_vhost_by_name(scsi_qla_host_t *ha, uint8_t *port_name)
+-static struct kobj_type icom_kobj_type = {
+-	.release = icom_kobj_release,
+-};
+-
+ static int __devinit icom_probe(struct pci_dev *dev,
+ 				const struct pci_device_id *ent)
  {
- 	scsi_qla_host_t *vha;
-@@ -216,11 +215,7 @@ qla2x00_alert_all_vps(scsi_qla_host_t *ha, uint16_t *mb)
- 	if (ha->parent)
- 		return;
+@@ -1592,8 +1589,7 @@ static int __devinit icom_probe(struct pci_dev *dev,
+ 		}
+ 	}
  
--	i = find_next_bit((unsigned long *)ha->vp_idx_map,
--	    MAX_MULTI_ID_FABRIC + 1, 1);
--	for (;i <= MAX_MULTI_ID_FABRIC;
--	    i = find_next_bit((unsigned long *)ha->vp_idx_map,
--	    MAX_MULTI_ID_FABRIC + 1, i + 1)) {
-+	for_each_mapped_vp_idx(ha, i) {
- 		vp_idx_matched = 0;
+-	kobject_init(&icom_adapter->kobj);
+-	icom_adapter->kobj.ktype = &icom_kobj_type;
++	kref_init(&icom_adapter->kref);
+ 	return 0;
  
- 		list_for_each_entry(vha, &ha->vp_list, vp_list) {
-@@ -270,7 +265,7 @@ qla2x00_vp_abort_isp(scsi_qla_host_t *vha)
- 	qla24xx_enable_vp(vha);
- }
+ probe_exit2:
+@@ -1619,7 +1615,7 @@ static void __devexit icom_remove(struct pci_dev *dev)
+ 		icom_adapter = list_entry(tmp, struct icom_adapter,
+ 					  icom_adapter_entry);
+ 		if (icom_adapter->pci_dev == dev) {
+-			kobject_put(&icom_adapter->kobj);
++			kref_put(&icom_adapter->kref, icom_kref_release);
+ 			return;
+ 		}
+ 	}
+diff --git a/drivers/serial/icom.h b/drivers/serial/icom.h
+index e8578d8..0274554 100644
+--- a/drivers/serial/icom.h
++++ b/drivers/serial/icom.h
+@@ -270,7 +270,7 @@ struct icom_adapter {
+ #define V2_ONE_PORT_RVX_ONE_PORT_IMBED_MDM	0x0251
+ 	int numb_ports;
+ 	struct list_head icom_adapter_entry;
+-	struct kobject kobj;
++	struct kref kref;
+ };
  
--int
-+static int
- qla2x00_do_dpc_vp(scsi_qla_host_t *vha)
+ /* prototype */
+diff --git a/drivers/serial/sh-sci.c b/drivers/serial/sh-sci.c
+index 73440e2..ddf6391 100644
+--- a/drivers/serial/sh-sci.c
++++ b/drivers/serial/sh-sci.c
+@@ -302,7 +302,7 @@ static void sci_init_pins_scif(struct uart_port* port, unsigned int cflag)
+ 	}
+ 	sci_out(port, SCFCR, fcr_val);
+ }
+-#elif defined(CONFIG_CPU_SUBTYPE_SH7720)
++#elif defined(CONFIG_CPU_SUBTYPE_SH7720) || defined(CONFIG_CPU_SUBTYPE_SH7721)
+ static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag)
  {
- 	if (test_and_clear_bit(VP_IDX_ACQUIRED, &vha->vp_flags)) {
-@@ -311,11 +306,7 @@ qla2x00_do_dpc_all_vps(scsi_qla_host_t *ha)
+ 	unsigned int fcr_val = 0;
+@@ -395,7 +395,8 @@ static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag)
+ 	} else {
+ #ifdef CONFIG_CPU_SUBTYPE_SH7343
+ 		/* Nothing */
+-#elif defined(CONFIG_CPU_SUBTYPE_SH7780) || \
++#elif defined(CONFIG_CPU_SUBTYPE_SH7763) || \
++      defined(CONFIG_CPU_SUBTYPE_SH7780) || \
+       defined(CONFIG_CPU_SUBTYPE_SH7785) || \
+       defined(CONFIG_CPU_SUBTYPE_SHX3)
+ 		ctrl_outw(0x0080, SCSPTR0); /* Set RTS = 1 */
+@@ -408,6 +409,7 @@ static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag)
+ #endif
  
- 	clear_bit(VP_DPC_NEEDED, &ha->dpc_flags);
+ #if defined(CONFIG_CPU_SUBTYPE_SH7760) || \
++    defined(CONFIG_CPU_SUBTYPE_SH7763) || \
+     defined(CONFIG_CPU_SUBTYPE_SH7780) || \
+     defined(CONFIG_CPU_SUBTYPE_SH7785)
+ static inline int scif_txroom(struct uart_port *port)
+diff --git a/drivers/serial/sh-sci.h b/drivers/serial/sh-sci.h
+index d24621c..f5764eb 100644
+--- a/drivers/serial/sh-sci.h
++++ b/drivers/serial/sh-sci.h
+@@ -46,7 +46,8 @@
+  */
+ # define SCSCR_INIT(port) (port->mapbase == SCIF2) ? 0xF3 : 0xF0
+ # define SCIF_ONLY
+-#elif defined(CONFIG_CPU_SUBTYPE_SH7720)
++#elif defined(CONFIG_CPU_SUBTYPE_SH7720) || \
++      defined(CONFIG_CPU_SUBTYPE_SH7721)
+ # define SCSCR_INIT(port)  0x0030 /* TIE=0,RIE=0,TE=1,RE=1 */
+ # define SCIF_ONLY
+ #define SCIF_ORER    0x0200   /* overrun error bit */
+@@ -119,6 +120,12 @@
+ # define SCSCR_INIT(port)          0x30 /* TIE=0,RIE=0,TE=1,RE=1 */
+ # define SCI_ONLY
+ # define H8300_SCI_DR(ch) *(volatile char *)(P1DR + h8300_sci_pins[ch].port)
++#elif defined(CONFIG_CPU_SUBTYPE_SH7763)
++# define SCSPTR0 0xffe00024 /* 16 bit SCIF */
++# define SCSPTR1 0xffe08024 /* 16 bit SCIF */
++# define SCIF_ORER 0x0001  /* overrun error bit */
++# define SCSCR_INIT(port)	0x3a	/* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
++# define SCIF_ONLY
+ #elif defined(CONFIG_CPU_SUBTYPE_SH7770)
+ # define SCSPTR0 0xff923020 /* 16 bit SCIF */
+ # define SCSPTR1 0xff924020 /* 16 bit SCIF */
+@@ -142,7 +149,9 @@
+ # define SCIF_OPER	0x0001		/* Overrun error bit */
+ # define SCSCR_INIT(port)	0x3a	/* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
+ # define SCIF_ONLY
+-#elif defined(CONFIG_CPU_SUBTYPE_SH7206)
++#elif defined(CONFIG_CPU_SUBTYPE_SH7203) || \
++      defined(CONFIG_CPU_SUBTYPE_SH7206) || \
++      defined(CONFIG_CPU_SUBTYPE_SH7263)
+ # define SCSPTR0 0xfffe8020 /* 16 bit SCIF */
+ # define SCSPTR1 0xfffe8820 /* 16 bit SCIF */
+ # define SCSPTR2 0xfffe9020 /* 16 bit SCIF */
+@@ -214,7 +223,8 @@
+ #define SCIF_DR    0x0001 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */
+ 
+ #if defined(CONFIG_CPU_SUBTYPE_SH7705) || \
+-    defined(CONFIG_CPU_SUBTYPE_SH7720)
++    defined(CONFIG_CPU_SUBTYPE_SH7720) || \
++    defined(CONFIG_CPU_SUBTYPE_SH7721)
+ #define SCIF_ORER    0x0200
+ #define SCIF_ERRORS ( SCIF_PER | SCIF_FER | SCIF_ER | SCIF_BRK | SCIF_ORER)
+ #define SCIF_RFDC_MASK 0x007f
+@@ -252,7 +262,8 @@
+ # define SCxSR_PER(port)		SCIF_PER
+ # define SCxSR_BRK(port)		SCIF_BRK
+ #if defined(CONFIG_CPU_SUBTYPE_SH7705) || \
+-    defined(CONFIG_CPU_SUBTYPE_SH7720)
++    defined(CONFIG_CPU_SUBTYPE_SH7720) || \
++    defined(CONFIG_CPU_SUBTYPE_SH7721)
+ # define SCxSR_RDxF_CLEAR(port)         (sci_in(port,SCxSR)&0xfffc)
+ # define SCxSR_ERROR_CLEAR(port)        (sci_in(port,SCxSR)&0xfd73)
+ # define SCxSR_TDxE_CLEAR(port)         (sci_in(port,SCxSR)&0xffdf)
+@@ -361,7 +372,8 @@
+ #define SCIF_FNS(name, sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size) \
+ 	  CPU_SCIF_FNS(name, sh4_scif_offset, sh4_scif_size)
+ #elif defined(CONFIG_CPU_SUBTYPE_SH7705) || \
+-      defined(CONFIG_CPU_SUBTYPE_SH7720)
++      defined(CONFIG_CPU_SUBTYPE_SH7720) || \
++      defined(CONFIG_CPU_SUBTYPE_SH7721)
+ #define SCIF_FNS(name, scif_offset, scif_size) \
+   CPU_SCIF_FNS(name, scif_offset, scif_size)
+ #else
+@@ -388,7 +400,8 @@
+ #endif
  
--	i = find_next_bit((unsigned long *)ha->vp_idx_map,
--	    MAX_MULTI_ID_FABRIC + 1, 1);
--	for (;i <= MAX_MULTI_ID_FABRIC;
--	    i = find_next_bit((unsigned long *)ha->vp_idx_map,
--	    MAX_MULTI_ID_FABRIC + 1, i + 1)) {
-+	for_each_mapped_vp_idx(ha, i) {
- 		vp_idx_matched = 0;
+ #if defined(CONFIG_CPU_SUBTYPE_SH7705) || \
+-    defined(CONFIG_CPU_SUBTYPE_SH7720)
++    defined(CONFIG_CPU_SUBTYPE_SH7720) || \
++    defined(CONFIG_CPU_SUBTYPE_SH7721)
+ 
+ SCIF_FNS(SCSMR,  0x00, 16)
+ SCIF_FNS(SCBRR,  0x04,  8)
+@@ -412,6 +425,7 @@ SCIx_FNS(SCxSR,  0x08,  8, 0x10,  8, 0x08, 16, 0x10, 16, 0x04,  8)
+ SCIx_FNS(SCxRDR, 0x0a,  8, 0x14,  8, 0x0A,  8, 0x14,  8, 0x05,  8)
+ SCIF_FNS(SCFCR,                      0x0c,  8, 0x18, 16)
+ #if defined(CONFIG_CPU_SUBTYPE_SH7760) || \
++    defined(CONFIG_CPU_SUBTYPE_SH7763) || \
+     defined(CONFIG_CPU_SUBTYPE_SH7780) || \
+     defined(CONFIG_CPU_SUBTYPE_SH7785)
+ SCIF_FNS(SCFDR,			     0x0e, 16, 0x1C, 16)
+@@ -510,7 +524,8 @@ static inline void set_sh771x_scif_pfc(struct uart_port *port)
+ 		return;
+ 	}
+ }
+-#elif defined(CONFIG_CPU_SUBTYPE_SH7720)
++#elif defined(CONFIG_CPU_SUBTYPE_SH7720) || \
++      defined(CONFIG_CPU_SUBTYPE_SH7721)
+ static inline int sci_rxd_in(struct uart_port *port)
+ {
+ 	if (port->mapbase == 0xa4430000)
+@@ -580,6 +595,15 @@ static inline int sci_rxd_in(struct uart_port *port)
+ 	int ch = (port->mapbase - SMR0) >> 3;
+ 	return (H8300_SCI_DR(ch) & h8300_sci_pins[ch].rx) ? 1 : 0;
+ }
++#elif defined(CONFIG_CPU_SUBTYPE_SH7763)
++static inline int sci_rxd_in(struct uart_port *port)
++{
++	if (port->mapbase == 0xffe00000)
++		return ctrl_inw(SCSPTR0) & 0x0001 ? 1 : 0; /* SCIF */
++	if (port->mapbase == 0xffe08000)
++		return ctrl_inw(SCSPTR1) & 0x0001 ? 1 : 0; /* SCIF */
++	return 1;
++}
+ #elif defined(CONFIG_CPU_SUBTYPE_SH7770)
+ static inline int sci_rxd_in(struct uart_port *port)
+ {
+@@ -617,7 +641,9 @@ static inline int sci_rxd_in(struct uart_port *port)
+ 		return ctrl_inw(SCSPTR5) & 0x0001 ? 1 : 0; /* SCIF */
+ 	return 1;
+ }
+-#elif defined(CONFIG_CPU_SUBTYPE_SH7206)
++#elif defined(CONFIG_CPU_SUBTYPE_SH7203) || \
++      defined(CONFIG_CPU_SUBTYPE_SH7206) || \
++      defined(CONFIG_CPU_SUBTYPE_SH7263)
+ static inline int sci_rxd_in(struct uart_port *port)
+ {
+ 	if (port->mapbase == 0xfffe8000)
+@@ -688,11 +714,13 @@ static inline int sci_rxd_in(struct uart_port *port)
+  * -- Mitch Davis - 15 Jul 2000
+  */
+ 
+-#if defined(CONFIG_CPU_SUBTYPE_SH7780) || \
++#if defined(CONFIG_CPU_SUBTYPE_SH7763) || \
++    defined(CONFIG_CPU_SUBTYPE_SH7780) || \
+     defined(CONFIG_CPU_SUBTYPE_SH7785)
+ #define SCBRR_VALUE(bps, clk) ((clk+16*bps)/(16*bps)-1)
+ #elif defined(CONFIG_CPU_SUBTYPE_SH7705) || \
+-      defined(CONFIG_CPU_SUBTYPE_SH7720)
++      defined(CONFIG_CPU_SUBTYPE_SH7720) || \
++      defined(CONFIG_CPU_SUBTYPE_SH7721)
+ #define SCBRR_VALUE(bps, clk) (((clk*2)+16*bps)/(32*bps)-1)
+ #elif defined(__H8300H__) || defined(__H8300S__)
+ #define SCBRR_VALUE(bps) (((CONFIG_CPU_CLOCK*1000/32)/bps)-1)
+diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
+index abf0504..aaaea81 100644
+--- a/drivers/spi/Kconfig
++++ b/drivers/spi/Kconfig
+@@ -153,6 +153,7 @@ config SPI_OMAP24XX
+ config SPI_PXA2XX
+ 	tristate "PXA2xx SSP SPI master"
+ 	depends on SPI_MASTER && ARCH_PXA && EXPERIMENTAL
++	select PXA_SSP
+ 	help
+ 	  This enables using a PXA2xx SSP port as a SPI master controller.
+ 	  The driver can be configured to use any SSP port and additional
+diff --git a/drivers/spi/pxa2xx_spi.c b/drivers/spi/pxa2xx_spi.c
+index 1c2ab54..eb817b8 100644
+--- a/drivers/spi/pxa2xx_spi.c
++++ b/drivers/spi/pxa2xx_spi.c
+@@ -27,6 +27,7 @@
+ #include <linux/spi/spi.h>
+ #include <linux/workqueue.h>
+ #include <linux/delay.h>
++#include <linux/clk.h>
  
- 		list_for_each_entry(vha, &ha->vp_list, vp_list) {
-@@ -350,15 +341,17 @@ qla24xx_vport_create_req_sanity_check(struct fc_vport *fc_vport)
+ #include <asm/io.h>
+ #include <asm/irq.h>
+@@ -36,6 +37,8 @@
  
- 	/* Check up unique WWPN */
- 	u64_to_wwn(fc_vport->port_name, port_name);
-+	if (!memcmp(port_name, ha->port_name, WWN_SIZE))
-+		return VPCERR_BAD_WWN;
- 	vha = qla24xx_find_vhost_by_name(ha, port_name);
- 	if (vha)
- 		return VPCERR_BAD_WWN;
+ #include <asm/arch/hardware.h>
+ #include <asm/arch/pxa-regs.h>
++#include <asm/arch/regs-ssp.h>
++#include <asm/arch/ssp.h>
+ #include <asm/arch/pxa2xx_spi.h>
+ 
+ MODULE_AUTHOR("Stephen Street");
+@@ -80,6 +83,9 @@ struct driver_data {
+ 	/* Driver model hookup */
+ 	struct platform_device *pdev;
  
- 	/* Check up max-npiv-supports */
- 	if (ha->num_vhosts > ha->max_npiv_vports) {
--		DEBUG15(printk("scsi(%ld): num_vhosts %d is bigger than "
--		    "max_npv_vports %d.\n", ha->host_no,
--		    (uint16_t) ha->num_vhosts, (int) ha->max_npiv_vports));
-+		DEBUG15(printk("scsi(%ld): num_vhosts %ud is bigger than "
-+		    "max_npv_vports %ud.\n", ha->host_no,
-+		    ha->num_vhosts, ha->max_npiv_vports));
- 		return VPCERR_UNSUPPORTED;
- 	}
- 	return 0;
-@@ -412,8 +405,9 @@ qla24xx_create_vhost(struct fc_vport *fc_vport)
- 	}
- 	vha->mgmt_svr_loop_id = 10 + vha->vp_idx;
++	/* SSP Info */
++	struct ssp_device *ssp;
++
+ 	/* SPI framework hookup */
+ 	enum pxa_ssp_type ssp_type;
+ 	struct spi_master *master;
+@@ -778,6 +784,16 @@ int set_dma_burst_and_threshold(struct chip_data *chip, struct spi_device *spi,
+ 	return retval;
+ }
  
--	init_MUTEX(&vha->mbx_cmd_sem);
--	init_MUTEX_LOCKED(&vha->mbx_intr_sem);
-+	init_completion(&vha->mbx_cmd_comp);
-+	complete(&vha->mbx_cmd_comp);
-+	init_completion(&vha->mbx_intr_comp);
++static unsigned int ssp_get_clk_div(struct ssp_device *ssp, int rate)
++{
++	unsigned long ssp_clk = clk_get_rate(ssp->clk);
++
++	if (ssp->type == PXA25x_SSP)
++		return ((ssp_clk / (2 * rate) - 1) & 0xff) << 8;
++	else
++		return ((ssp_clk / rate - 1) & 0xfff) << 8;
++}
++
+ static void pump_transfers(unsigned long data)
+ {
+ 	struct driver_data *drv_data = (struct driver_data *)data;
+@@ -785,6 +801,7 @@ static void pump_transfers(unsigned long data)
+ 	struct spi_transfer *transfer = NULL;
+ 	struct spi_transfer *previous = NULL;
+ 	struct chip_data *chip = NULL;
++	struct ssp_device *ssp = drv_data->ssp;
+ 	void *reg = drv_data->ioaddr;
+ 	u32 clk_div = 0;
+ 	u8 bits = 0;
+@@ -866,12 +883,7 @@ static void pump_transfers(unsigned long data)
+ 		if (transfer->bits_per_word)
+ 			bits = transfer->bits_per_word;
+ 
+-		if (reg == SSP1_VIRT)
+-			clk_div = SSP1_SerClkDiv(speed);
+-		else if (reg == SSP2_VIRT)
+-			clk_div = SSP2_SerClkDiv(speed);
+-		else if (reg == SSP3_VIRT)
+-			clk_div = SSP3_SerClkDiv(speed);
++		clk_div = ssp_get_clk_div(ssp, speed);
+ 
+ 		if (bits <= 8) {
+ 			drv_data->n_bytes = 1;
+@@ -1074,6 +1086,7 @@ static int setup(struct spi_device *spi)
+ 	struct pxa2xx_spi_chip *chip_info = NULL;
+ 	struct chip_data *chip;
+ 	struct driver_data *drv_data = spi_master_get_devdata(spi->master);
++	struct ssp_device *ssp = drv_data->ssp;
+ 	unsigned int clk_div;
+ 
+ 	if (!spi->bits_per_word)
+@@ -1157,18 +1170,7 @@ static int setup(struct spi_device *spi)
+ 		}
+ 	}
  
- 	INIT_LIST_HEAD(&vha->list);
- 	INIT_LIST_HEAD(&vha->fcports);
-@@ -450,7 +444,7 @@ qla24xx_create_vhost(struct fc_vport *fc_vport)
- 	num_hosts++;
+-	if (drv_data->ioaddr == SSP1_VIRT)
+-		clk_div = SSP1_SerClkDiv(spi->max_speed_hz);
+-	else if (drv_data->ioaddr == SSP2_VIRT)
+-		clk_div = SSP2_SerClkDiv(spi->max_speed_hz);
+-	else if (drv_data->ioaddr == SSP3_VIRT)
+-		clk_div = SSP3_SerClkDiv(spi->max_speed_hz);
+-	else
+-	{
+-		dev_err(&spi->dev, "failed setup: unknown IO address=0x%p\n",
+-			drv_data->ioaddr);
+-		return -ENODEV;
+-	}
++	clk_div = ssp_get_clk_div(ssp, spi->max_speed_hz);
+ 	chip->speed_hz = spi->max_speed_hz;
  
- 	down(&ha->vport_sem);
--	set_bit(vha->vp_idx, (unsigned long *)ha->vp_idx_map);
-+	set_bit(vha->vp_idx, ha->vp_idx_map);
- 	ha->cur_vport_count++;
- 	up(&ha->vport_sem);
+ 	chip->cr0 = clk_div
+@@ -1183,15 +1185,15 @@ static int setup(struct spi_device *spi)
  
-diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
-index 8ecc047..aba1e6d 100644
---- a/drivers/scsi/qla2xxx/qla_os.c
-+++ b/drivers/scsi/qla2xxx/qla_os.c
-@@ -105,13 +105,12 @@ static int qla2xxx_eh_abort(struct scsi_cmnd *);
- static int qla2xxx_eh_device_reset(struct scsi_cmnd *);
- static int qla2xxx_eh_bus_reset(struct scsi_cmnd *);
- static int qla2xxx_eh_host_reset(struct scsi_cmnd *);
--static int qla2x00_loop_reset(scsi_qla_host_t *ha);
- static int qla2x00_device_reset(scsi_qla_host_t *, fc_port_t *);
+ 	/* NOTE:  PXA25x_SSP _could_ use external clocking ... */
+ 	if (drv_data->ssp_type != PXA25x_SSP)
+-		dev_dbg(&spi->dev, "%d bits/word, %d Hz, mode %d\n",
++		dev_dbg(&spi->dev, "%d bits/word, %ld Hz, mode %d\n",
+ 				spi->bits_per_word,
+-				(CLOCK_SPEED_HZ)
++				clk_get_rate(ssp->clk)
+ 					/ (1 + ((chip->cr0 & SSCR0_SCR) >> 8)),
+ 				spi->mode & 0x3);
+ 	else
+-		dev_dbg(&spi->dev, "%d bits/word, %d Hz, mode %d\n",
++		dev_dbg(&spi->dev, "%d bits/word, %ld Hz, mode %d\n",
+ 				spi->bits_per_word,
+-				(CLOCK_SPEED_HZ/2)
++				clk_get_rate(ssp->clk)
+ 					/ (1 + ((chip->cr0 & SSCR0_SCR) >> 8)),
+ 				spi->mode & 0x3);
+ 
+@@ -1323,14 +1325,14 @@ static int __init pxa2xx_spi_probe(struct platform_device *pdev)
+ 	struct pxa2xx_spi_master *platform_info;
+ 	struct spi_master *master;
+ 	struct driver_data *drv_data = 0;
+-	struct resource *memory_resource;
+-	int irq;
++	struct ssp_device *ssp;
+ 	int status = 0;
  
- static int qla2x00_change_queue_depth(struct scsi_device *, int);
- static int qla2x00_change_queue_type(struct scsi_device *, int);
+ 	platform_info = dev->platform_data;
  
--struct scsi_host_template qla2x00_driver_template = {
-+static struct scsi_host_template qla2x00_driver_template = {
- 	.module			= THIS_MODULE,
- 	.name			= QLA2XXX_DRIVER_NAME,
- 	.queuecommand		= qla2x00_queuecommand,
-@@ -179,13 +178,6 @@ struct scsi_transport_template *qla2xxx_transport_vport_template = NULL;
-  * Timer routines
-  */
+-	if (platform_info->ssp_type == SSP_UNDEFINED) {
+-		dev_err(&pdev->dev, "undefined SSP\n");
++	ssp = ssp_request(pdev->id, pdev->name);
++	if (ssp == NULL) {
++		dev_err(&pdev->dev, "failed to request SSP%d\n", pdev->id);
+ 		return -ENODEV;
+ 	}
  
--void qla2x00_timer(scsi_qla_host_t *);
--
--__inline__ void qla2x00_start_timer(scsi_qla_host_t *,
--    void *, unsigned long);
--static __inline__ void qla2x00_restart_timer(scsi_qla_host_t *, unsigned long);
--__inline__ void qla2x00_stop_timer(scsi_qla_host_t *);
+@@ -1338,12 +1340,14 @@ static int __init pxa2xx_spi_probe(struct platform_device *pdev)
+ 	master = spi_alloc_master(dev, sizeof(struct driver_data) + 16);
+ 	if (!master) {
+ 		dev_err(&pdev->dev, "can not alloc spi_master\n");
++		ssp_free(ssp);
+ 		return -ENOMEM;
+ 	}
+ 	drv_data = spi_master_get_devdata(master);
+ 	drv_data->master = master;
+ 	drv_data->master_info = platform_info;
+ 	drv_data->pdev = pdev;
++	drv_data->ssp = ssp;
+ 
+ 	master->bus_num = pdev->id;
+ 	master->num_chipselect = platform_info->num_chipselect;
+@@ -1351,21 +1355,13 @@ static int __init pxa2xx_spi_probe(struct platform_device *pdev)
+ 	master->setup = setup;
+ 	master->transfer = transfer;
+ 
+-	drv_data->ssp_type = platform_info->ssp_type;
++	drv_data->ssp_type = ssp->type;
+ 	drv_data->null_dma_buf = (u32 *)ALIGN((u32)(drv_data +
+ 						sizeof(struct driver_data)), 8);
+ 
+-	/* Setup register addresses */
+-	memory_resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+-	if (!memory_resource) {
+-		dev_err(&pdev->dev, "memory resources not defined\n");
+-		status = -ENODEV;
+-		goto out_error_master_alloc;
+-	}
+-
+-	drv_data->ioaddr = (void *)io_p2v((unsigned long)(memory_resource->start));
+-	drv_data->ssdr_physical = memory_resource->start + 0x00000010;
+-	if (platform_info->ssp_type == PXA25x_SSP) {
++	drv_data->ioaddr = ssp->mmio_base;
++	drv_data->ssdr_physical = ssp->phys_base + SSDR;
++	if (ssp->type == PXA25x_SSP) {
+ 		drv_data->int_cr1 = SSCR1_TIE | SSCR1_RIE;
+ 		drv_data->dma_cr1 = 0;
+ 		drv_data->clear_sr = SSSR_ROR;
+@@ -1377,15 +1373,7 @@ static int __init pxa2xx_spi_probe(struct platform_device *pdev)
+ 		drv_data->mask_sr = SSSR_TINT | SSSR_RFS | SSSR_TFS | SSSR_ROR;
+ 	}
+ 
+-	/* Attach to IRQ */
+-	irq = platform_get_irq(pdev, 0);
+-	if (irq < 0) {
+-		dev_err(&pdev->dev, "irq resource not defined\n");
+-		status = -ENODEV;
+-		goto out_error_master_alloc;
+-	}
 -
- __inline__ void
- qla2x00_start_timer(scsi_qla_host_t *ha, void *func, unsigned long interval)
- {
-@@ -203,7 +195,7 @@ qla2x00_restart_timer(scsi_qla_host_t *ha, unsigned long interval)
- 	mod_timer(&ha->timer, jiffies + interval * HZ);
+-	status = request_irq(irq, ssp_int, 0, dev->bus_id, drv_data);
++	status = request_irq(ssp->irq, ssp_int, 0, dev->bus_id, drv_data);
+ 	if (status < 0) {
+ 		dev_err(&pdev->dev, "can not get IRQ\n");
+ 		goto out_error_master_alloc;
+@@ -1418,29 +1406,12 @@ static int __init pxa2xx_spi_probe(struct platform_device *pdev)
+ 			goto out_error_dma_alloc;
+ 		}
+ 
+-		if (drv_data->ioaddr == SSP1_VIRT) {
+-				DRCMRRXSSDR = DRCMR_MAPVLD
+-						| drv_data->rx_channel;
+-				DRCMRTXSSDR = DRCMR_MAPVLD
+-						| drv_data->tx_channel;
+-		} else if (drv_data->ioaddr == SSP2_VIRT) {
+-				DRCMRRXSS2DR = DRCMR_MAPVLD
+-						| drv_data->rx_channel;
+-				DRCMRTXSS2DR = DRCMR_MAPVLD
+-						| drv_data->tx_channel;
+-		} else if (drv_data->ioaddr == SSP3_VIRT) {
+-				DRCMRRXSS3DR = DRCMR_MAPVLD
+-						| drv_data->rx_channel;
+-				DRCMRTXSS3DR = DRCMR_MAPVLD
+-						| drv_data->tx_channel;
+-		} else {
+-			dev_err(dev, "bad SSP type\n");
+-			goto out_error_dma_alloc;
+-		}
++		DRCMR(ssp->drcmr_rx) = DRCMR_MAPVLD | drv_data->rx_channel;
++		DRCMR(ssp->drcmr_tx) = DRCMR_MAPVLD | drv_data->tx_channel;
+ 	}
+ 
+ 	/* Enable SOC clock */
+-	pxa_set_cken(platform_info->clock_enable, 1);
++	clk_enable(ssp->clk);
+ 
+ 	/* Load default SSP configuration */
+ 	write_SSCR0(0, drv_data->ioaddr);
+@@ -1479,7 +1450,7 @@ out_error_queue_alloc:
+ 	destroy_queue(drv_data);
+ 
+ out_error_clock_enabled:
+-	pxa_set_cken(platform_info->clock_enable, 0);
++	clk_disable(ssp->clk);
+ 
+ out_error_dma_alloc:
+ 	if (drv_data->tx_channel != -1)
+@@ -1488,17 +1459,18 @@ out_error_dma_alloc:
+ 		pxa_free_dma(drv_data->rx_channel);
+ 
+ out_error_irq_alloc:
+-	free_irq(irq, drv_data);
++	free_irq(ssp->irq, drv_data);
+ 
+ out_error_master_alloc:
+ 	spi_master_put(master);
++	ssp_free(ssp);
+ 	return status;
  }
  
--__inline__ void
-+static __inline__ void
- qla2x00_stop_timer(scsi_qla_host_t *ha)
+ static int pxa2xx_spi_remove(struct platform_device *pdev)
  {
- 	del_timer_sync(&ha->timer);
-@@ -214,12 +206,11 @@ static int qla2x00_do_dpc(void *data);
+ 	struct driver_data *drv_data = platform_get_drvdata(pdev);
+-	int irq;
++	struct ssp_device *ssp = drv_data->ssp;
+ 	int status = 0;
  
- static void qla2x00_rst_aen(scsi_qla_host_t *);
+ 	if (!drv_data)
+@@ -1520,28 +1492,21 @@ static int pxa2xx_spi_remove(struct platform_device *pdev)
  
--uint8_t qla2x00_mem_alloc(scsi_qla_host_t *);
--void qla2x00_mem_free(scsi_qla_host_t *ha);
-+static uint8_t qla2x00_mem_alloc(scsi_qla_host_t *);
-+static void qla2x00_mem_free(scsi_qla_host_t *ha);
- static int qla2x00_allocate_sp_pool( scsi_qla_host_t *ha);
- static void qla2x00_free_sp_pool(scsi_qla_host_t *ha);
- static void qla2x00_sp_free_dma(scsi_qla_host_t *, srb_t *);
--void qla2x00_sp_compl(scsi_qla_host_t *ha, srb_t *);
+ 	/* Disable the SSP at the peripheral and SOC level */
+ 	write_SSCR0(0, drv_data->ioaddr);
+-	pxa_set_cken(drv_data->master_info->clock_enable, 0);
++	clk_disable(ssp->clk);
+ 
+ 	/* Release DMA */
+ 	if (drv_data->master_info->enable_dma) {
+-		if (drv_data->ioaddr == SSP1_VIRT) {
+-			DRCMRRXSSDR = 0;
+-			DRCMRTXSSDR = 0;
+-		} else if (drv_data->ioaddr == SSP2_VIRT) {
+-			DRCMRRXSS2DR = 0;
+-			DRCMRTXSS2DR = 0;
+-		} else if (drv_data->ioaddr == SSP3_VIRT) {
+-			DRCMRRXSS3DR = 0;
+-			DRCMRTXSS3DR = 0;
+-		}
++		DRCMR(ssp->drcmr_rx) = 0;
++		DRCMR(ssp->drcmr_tx) = 0;
+ 		pxa_free_dma(drv_data->tx_channel);
+ 		pxa_free_dma(drv_data->rx_channel);
+ 	}
+ 
+ 	/* Release IRQ */
+-	irq = platform_get_irq(pdev, 0);
+-	if (irq >= 0)
+-		free_irq(irq, drv_data);
++	free_irq(ssp->irq, drv_data);
++
++	/* Release SSP */
++	ssp_free(ssp);
+ 
+ 	/* Disconnect from the SPI framework */
+ 	spi_unregister_master(drv_data->master);
+@@ -1576,6 +1541,7 @@ static int suspend_devices(struct device *dev, void *pm_message)
+ static int pxa2xx_spi_suspend(struct platform_device *pdev, pm_message_t state)
+ {
+ 	struct driver_data *drv_data = platform_get_drvdata(pdev);
++	struct ssp_device *ssp = drv_data->ssp;
+ 	int status = 0;
  
- /* -------------------------------------------------------------------------- */
+ 	/* Check all childern for current power state */
+@@ -1588,7 +1554,7 @@ static int pxa2xx_spi_suspend(struct platform_device *pdev, pm_message_t state)
+ 	if (status != 0)
+ 		return status;
+ 	write_SSCR0(0, drv_data->ioaddr);
+-	pxa_set_cken(drv_data->master_info->clock_enable, 0);
++	clk_disable(ssp->clk);
  
-@@ -1060,7 +1051,7 @@ eh_host_reset_lock:
- * Returns:
- *      0 = success
- */
--static int
-+int
- qla2x00_loop_reset(scsi_qla_host_t *ha)
- {
- 	int ret;
-@@ -1479,8 +1470,7 @@ qla2x00_set_isp_flags(scsi_qla_host_t *ha)
- static int
- qla2x00_iospace_config(scsi_qla_host_t *ha)
+ 	return 0;
+ }
+@@ -1596,10 +1562,11 @@ static int pxa2xx_spi_suspend(struct platform_device *pdev, pm_message_t state)
+ static int pxa2xx_spi_resume(struct platform_device *pdev)
  {
--	unsigned long	pio, pio_len, pio_flags;
--	unsigned long	mmio, mmio_len, mmio_flags;
-+	resource_size_t pio;
+ 	struct driver_data *drv_data = platform_get_drvdata(pdev);
++	struct ssp_device *ssp = drv_data->ssp;
+ 	int status = 0;
  
- 	if (pci_request_selected_regions(ha->pdev, ha->bars,
- 	    QLA2XXX_DRIVER_NAME)) {
-@@ -1495,10 +1485,8 @@ qla2x00_iospace_config(scsi_qla_host_t *ha)
+ 	/* Enable the SSP clock */
+-	pxa_set_cken(drv_data->master_info->clock_enable, 1);
++	clk_disable(ssp->clk);
  
- 	/* We only need PIO for Flash operations on ISP2312 v2 chips. */
- 	pio = pci_resource_start(ha->pdev, 0);
--	pio_len = pci_resource_len(ha->pdev, 0);
--	pio_flags = pci_resource_flags(ha->pdev, 0);
--	if (pio_flags & IORESOURCE_IO) {
--		if (pio_len < MIN_IOBASE_LEN) {
-+	if (pci_resource_flags(ha->pdev, 0) & IORESOURCE_IO) {
-+		if (pci_resource_len(ha->pdev, 0) < MIN_IOBASE_LEN) {
- 			qla_printk(KERN_WARNING, ha,
- 			    "Invalid PCI I/O region size (%s)...\n",
- 				pci_name(ha->pdev));
-@@ -1511,28 +1499,23 @@ qla2x00_iospace_config(scsi_qla_host_t *ha)
- 		pio = 0;
- 	}
- 	ha->pio_address = pio;
--	ha->pio_length = pio_len;
+ 	/* Start the queue running */
+ 	status = start_queue(drv_data);
+diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
+index 93e9de4..682a6a4 100644
+--- a/drivers/spi/spi.c
++++ b/drivers/spi/spi.c
+@@ -485,6 +485,15 @@ void spi_unregister_master(struct spi_master *master)
+ }
+ EXPORT_SYMBOL_GPL(spi_unregister_master);
  
- skip_pio:
- 	/* Use MMIO operations for all accesses. */
--	mmio = pci_resource_start(ha->pdev, 1);
--	mmio_len = pci_resource_len(ha->pdev, 1);
--	mmio_flags = pci_resource_flags(ha->pdev, 1);
++static int __spi_master_match(struct device *dev, void *data)
++{
++	struct spi_master *m;
++	u16 *bus_num = data;
++
++	m = container_of(dev, struct spi_master, dev);
++	return m->bus_num == *bus_num;
++}
++
+ /**
+  * spi_busnum_to_master - look up master associated with bus_num
+  * @bus_num: the master's bus number
+@@ -499,17 +508,12 @@ struct spi_master *spi_busnum_to_master(u16 bus_num)
+ {
+ 	struct device		*dev;
+ 	struct spi_master	*master = NULL;
+-	struct spi_master	*m;
 -
--	if (!(mmio_flags & IORESOURCE_MEM)) {
-+	if (!(pci_resource_flags(ha->pdev, 1) & IORESOURCE_MEM)) {
- 		qla_printk(KERN_ERR, ha,
--		    "region #0 not an MMIO resource (%s), aborting\n",
-+		    "region #1 not an MMIO resource (%s), aborting\n",
- 		    pci_name(ha->pdev));
- 		goto iospace_error_exit;
- 	}
--	if (mmio_len < MIN_IOBASE_LEN) {
-+	if (pci_resource_len(ha->pdev, 1) < MIN_IOBASE_LEN) {
- 		qla_printk(KERN_ERR, ha,
- 		    "Invalid PCI mem region size (%s), aborting\n",
- 			pci_name(ha->pdev));
- 		goto iospace_error_exit;
- 	}
- 
--	ha->iobase = ioremap(mmio, MIN_IOBASE_LEN);
-+	ha->iobase = ioremap(pci_resource_start(ha->pdev, 1), MIN_IOBASE_LEN);
- 	if (!ha->iobase) {
- 		qla_printk(KERN_ERR, ha,
- 		    "cannot remap MMIO (%s), aborting\n", pci_name(ha->pdev));
-@@ -1701,9 +1684,10 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
- 	/* load the F/W, read paramaters, and init the H/W */
- 	ha->instance = num_hosts;
+-	down(&spi_master_class.sem);
+-	list_for_each_entry(dev, &spi_master_class.children, node) {
+-		m = container_of(dev, struct spi_master, dev);
+-		if (m->bus_num == bus_num) {
+-			master = spi_master_get(m);
+-			break;
+-		}
+-	}
+-	up(&spi_master_class.sem);
++
++	dev = class_find_device(&spi_master_class, &bus_num,
++				__spi_master_match);
++	if (dev)
++		master = container_of(dev, struct spi_master, dev);
++	/* reference got in class_find_device */
+ 	return master;
+ }
+ EXPORT_SYMBOL_GPL(spi_busnum_to_master);
+diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c
+index 865f32b..cc246fa 100644
+--- a/drivers/uio/uio.c
++++ b/drivers/uio/uio.c
+@@ -34,12 +34,12 @@ struct uio_device {
+ 	wait_queue_head_t	wait;
+ 	int			vma_count;
+ 	struct uio_info		*info;
+-	struct kset 		map_attr_kset;
++	struct kobject		*map_dir;
+ };
  
--	init_MUTEX(&ha->mbx_cmd_sem);
- 	init_MUTEX(&ha->vport_sem);
--	init_MUTEX_LOCKED(&ha->mbx_intr_sem);
-+	init_completion(&ha->mbx_cmd_comp);
-+	complete(&ha->mbx_cmd_comp);
-+	init_completion(&ha->mbx_intr_comp);
+ static int uio_major;
+ static DEFINE_IDR(uio_idr);
+-static struct file_operations uio_fops;
++static const struct file_operations uio_fops;
  
- 	INIT_LIST_HEAD(&ha->list);
- 	INIT_LIST_HEAD(&ha->fcports);
-@@ -1807,6 +1791,8 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
+ /* UIO class infrastructure */
+ static struct uio_class {
+@@ -51,47 +51,48 @@ static struct uio_class {
+  * attributes
+  */
  
- 	qla2x00_init_host_attr(ha);
+-static struct attribute attr_addr = {
+-	.name  = "addr",
+-	.mode  = S_IRUGO,
++struct uio_map {
++	struct kobject kobj;
++	struct uio_mem *mem;
+ };
++#define to_map(map) container_of(map, struct uio_map, kobj)
  
-+	qla2x00_dfs_setup(ha);
-+
- 	qla_printk(KERN_INFO, ha, "\n"
- 	    " QLogic Fibre Channel HBA Driver: %s\n"
- 	    "  QLogic %s - %s\n"
-@@ -1838,6 +1824,8 @@ qla2x00_remove_one(struct pci_dev *pdev)
+-static struct attribute attr_size = {
+-	.name  = "size",
+-	.mode  = S_IRUGO,
+-};
  
- 	ha = pci_get_drvdata(pdev);
+-static struct attribute* map_attrs[] = {
+-	&attr_addr, &attr_size, NULL
+-};
+-
+-static ssize_t map_attr_show(struct kobject *kobj, struct attribute *attr,
++static ssize_t map_attr_show(struct kobject *kobj, struct kobj_attribute *attr,
+ 			     char *buf)
+ {
+-	struct uio_mem *mem = container_of(kobj, struct uio_mem, kobj);
++	struct uio_map *map = to_map(kobj);
++	struct uio_mem *mem = map->mem;
  
-+	qla2x00_dfs_remove(ha);
-+
- 	qla2x00_free_sysfs_attr(ha);
+-	if (strncmp(attr->name,"addr",4) == 0)
++	if (strncmp(attr->attr.name, "addr", 4) == 0)
+ 		return sprintf(buf, "0x%lx\n", mem->addr);
  
- 	fc_remove_host(ha->host);
-@@ -1871,8 +1859,11 @@ qla2x00_free_device(scsi_qla_host_t *ha)
- 		kthread_stop(t);
- 	}
+-	if (strncmp(attr->name,"size",4) == 0)
++	if (strncmp(attr->attr.name, "size", 4) == 0)
+ 		return sprintf(buf, "0x%lx\n", mem->size);
  
-+	if (ha->flags.fce_enabled)
-+		qla2x00_disable_fce_trace(ha, NULL, NULL);
-+
- 	if (ha->eft)
--		qla2x00_trace_control(ha, TC_DISABLE, 0, 0);
-+		qla2x00_disable_eft_trace(ha);
+ 	return -ENODEV;
+ }
  
- 	ha->flags.online = 0;
+-static void map_attr_release(struct kobject *kobj)
+-{
+-	/* TODO ??? */
+-}
++static struct kobj_attribute attr_attribute =
++	__ATTR(addr, S_IRUGO, map_attr_show, NULL);
++static struct kobj_attribute size_attribute =
++	__ATTR(size, S_IRUGO, map_attr_show, NULL);
  
-@@ -2016,7 +2007,7 @@ qla2x00_mark_all_devices_lost(scsi_qla_host_t *ha, int defer)
- *      0  = success.
- *      1  = failure.
- */
--uint8_t
-+static uint8_t
- qla2x00_mem_alloc(scsi_qla_host_t *ha)
- {
- 	char	name[16];
-@@ -2213,7 +2204,7 @@ qla2x00_mem_alloc(scsi_qla_host_t *ha)
- * Input:
- *      ha = adapter block pointer.
- */
--void
-+static void
- qla2x00_mem_free(scsi_qla_host_t *ha)
- {
- 	struct list_head	*fcpl, *fcptemp;
-@@ -2228,6 +2219,10 @@ qla2x00_mem_free(scsi_qla_host_t *ha)
- 	/* free sp pool */
- 	qla2x00_free_sp_pool(ha);
+-static struct sysfs_ops map_attr_ops = {
+-	.show  = map_attr_show,
++static struct attribute *attrs[] = {
++	&attr_attribute.attr,
++	&size_attribute.attr,
++	NULL,	/* need to NULL terminate the list of attributes */
+ };
  
-+	if (ha->fce)
-+		dma_free_coherent(&ha->pdev->dev, FCE_SIZE, ha->fce,
-+		    ha->fce_dma);
++static void map_release(struct kobject *kobj)
++{
++	struct uio_map *map = to_map(kobj);
++	kfree(map);
++}
 +
- 	if (ha->fw_dump) {
- 		if (ha->eft)
- 			dma_free_coherent(&ha->pdev->dev,
-@@ -2748,23 +2743,6 @@ qla2x00_timer(scsi_qla_host_t *ha)
- 	qla2x00_restart_timer(ha, WATCH_INTERVAL);
- }
+ static struct kobj_type map_attr_type = {
+-	.release	= map_attr_release,
+-	.sysfs_ops	= &map_attr_ops,
+-	.default_attrs	= map_attrs,
++	.release	= map_release,
++	.default_attrs	= attrs,
+ };
  
--/* XXX(hch): crude hack to emulate a down_timeout() */
--int
--qla2x00_down_timeout(struct semaphore *sema, unsigned long timeout)
--{
--	const unsigned int step = 100; /* msecs */
--	unsigned int iterations = jiffies_to_msecs(timeout)/100;
--
--	do {
--		if (!down_trylock(sema))
--			return 0;
--		if (msleep_interruptible(step))
--			break;
--	} while (--iterations > 0);
--
--	return -ETIMEDOUT;
--}
--
- /* Firmware interface routines. */
+ static ssize_t show_name(struct device *dev,
+@@ -148,6 +149,7 @@ static int uio_dev_add_attributes(struct uio_device *idev)
+ 	int mi;
+ 	int map_found = 0;
+ 	struct uio_mem *mem;
++	struct uio_map *map;
  
- #define FW_BLOBS	6
-diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c
-index ad2fa01..b68fb73 100644
---- a/drivers/scsi/qla2xxx/qla_sup.c
-+++ b/drivers/scsi/qla2xxx/qla_sup.c
-@@ -22,7 +22,7 @@ static void qla2x00_nv_write(scsi_qla_host_t *, uint16_t);
-  * qla2x00_lock_nvram_access() -
-  * @ha: HA context
-  */
--void
-+static void
- qla2x00_lock_nvram_access(scsi_qla_host_t *ha)
- {
- 	uint16_t data;
-@@ -55,7 +55,7 @@ qla2x00_lock_nvram_access(scsi_qla_host_t *ha)
-  * qla2x00_unlock_nvram_access() -
-  * @ha: HA context
-  */
--void
-+static void
- qla2x00_unlock_nvram_access(scsi_qla_host_t *ha)
- {
- 	struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
-@@ -74,7 +74,7 @@ qla2x00_unlock_nvram_access(scsi_qla_host_t *ha)
-  *
-  * Returns the word read from nvram @addr.
-  */
--uint16_t
-+static uint16_t
- qla2x00_get_nvram_word(scsi_qla_host_t *ha, uint32_t addr)
- {
- 	uint16_t	data;
-@@ -93,7 +93,7 @@ qla2x00_get_nvram_word(scsi_qla_host_t *ha, uint32_t addr)
-  * @addr: Address in NVRAM to write
-  * @data: word to program
-  */
--void
-+static void
- qla2x00_write_nvram_word(scsi_qla_host_t *ha, uint32_t addr, uint16_t data)
- {
- 	int count;
-@@ -550,7 +550,7 @@ qla24xx_write_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr,
- 	int ret;
- 	uint32_t liter, miter;
- 	uint32_t sec_mask, rest_addr, conf_addr;
--	uint32_t fdata, findex ;
-+	uint32_t fdata, findex, cnt;
- 	uint8_t	man_id, flash_id;
- 	struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
- 	dma_addr_t optrom_dma;
-@@ -690,8 +690,14 @@ qla24xx_write_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr,
- 			    0xff0000) | ((fdata >> 16) & 0xff));
+ 	ret = sysfs_create_group(&idev->dev->kobj, &uio_attr_grp);
+ 	if (ret)
+@@ -159,31 +161,34 @@ static int uio_dev_add_attributes(struct uio_device *idev)
+ 			break;
+ 		if (!map_found) {
+ 			map_found = 1;
+-			kobject_set_name(&idev->map_attr_kset.kobj,"maps");
+-			idev->map_attr_kset.ktype = &map_attr_type;
+-			idev->map_attr_kset.kobj.parent = &idev->dev->kobj;
+-			ret = kset_register(&idev->map_attr_kset);
+-			if (ret)
+-				goto err_remove_group;
++			idev->map_dir = kobject_create_and_add("maps",
++							&idev->dev->kobj);
++			if (!idev->map_dir)
++				goto err;
+ 		}
+-		kobject_init(&mem->kobj);
+-		kobject_set_name(&mem->kobj,"map%d",mi);
+-		mem->kobj.parent = &idev->map_attr_kset.kobj;
+-		mem->kobj.kset = &idev->map_attr_kset;
+-		ret = kobject_add(&mem->kobj);
++		map = kzalloc(sizeof(*map), GFP_KERNEL);
++		if (!map)
++			goto err;
++		kobject_init(&map->kobj, &map_attr_type);
++		map->mem = mem;
++		mem->map = map;
++		ret = kobject_add(&map->kobj, idev->map_dir, "map%d", mi);
++		if (ret)
++			goto err;
++		ret = kobject_uevent(&map->kobj, KOBJ_ADD);
+ 		if (ret)
+-			goto err_remove_maps;
++			goto err;
+ 	}
+ 
+ 	return 0;
+ 
+-err_remove_maps:
++err:
+ 	for (mi--; mi>=0; mi--) {
+ 		mem = &idev->info->mem[mi];
+-		kobject_unregister(&mem->kobj);
++		map = mem->map;
++		kobject_put(&map->kobj);
+ 	}
+-	kset_unregister(&idev->map_attr_kset); /* Needed ? */
+-err_remove_group:
++	kobject_put(idev->map_dir);
+ 	sysfs_remove_group(&idev->dev->kobj, &uio_attr_grp);
+ err_group:
+ 	dev_err(idev->dev, "error creating sysfs files (%d)\n", ret);
+@@ -198,9 +203,9 @@ static void uio_dev_del_attributes(struct uio_device *idev)
+ 		mem = &idev->info->mem[mi];
+ 		if (mem->size == 0)
+ 			break;
+-		kobject_unregister(&mem->kobj);
++		kobject_put(&mem->map->kobj);
+ 	}
+-	kset_unregister(&idev->map_attr_kset);
++	kobject_put(idev->map_dir);
+ 	sysfs_remove_group(&idev->dev->kobj, &uio_attr_grp);
+ }
+ 
+@@ -503,7 +508,7 @@ static int uio_mmap(struct file *filep, struct vm_area_struct *vma)
  	}
+ }
  
--	/* Enable flash write-protection. */
-+	/* Enable flash write-protection and wait for completion. */
- 	qla24xx_write_flash_dword(ha, flash_conf_to_access_addr(0x101), 0x9c);
-+	for (cnt = 300; cnt &&
-+	    qla24xx_read_flash_dword(ha,
-+		    flash_conf_to_access_addr(0x005)) & BIT_0;
-+	    cnt--) {
-+		udelay(10);
-+	}
+-static struct file_operations uio_fops = {
++static const struct file_operations uio_fops = {
+ 	.owner		= THIS_MODULE,
+ 	.open		= uio_open,
+ 	.release	= uio_release,
+diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
+index 7580aa5..7a64990 100644
+--- a/drivers/usb/Kconfig
++++ b/drivers/usb/Kconfig
+@@ -33,6 +33,7 @@ config USB_ARCH_HAS_OHCI
+ 	default y if ARCH_LH7A404
+ 	default y if ARCH_S3C2410
+ 	default y if PXA27x
++	default y if PXA3xx
+ 	default y if ARCH_EP93XX
+ 	default y if ARCH_AT91
+ 	default y if ARCH_PNX4008
+diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
+index c51f8e9..7c3aaa9 100644
+--- a/drivers/usb/core/driver.c
++++ b/drivers/usb/core/driver.c
+@@ -91,8 +91,8 @@ static int usb_create_newid_file(struct usb_driver *usb_drv)
+ 		goto exit;
  
- 	/* Disable flash write. */
- 	WRT_REG_DWORD(&reg->ctrl_status,
-diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h
-index ae6f7a2..2c2f6b4 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.00-k5"
-+#define QLA2XXX_VERSION      "8.02.00-k7"
+ 	if (usb_drv->probe != NULL)
+-		error = sysfs_create_file(&usb_drv->drvwrap.driver.kobj,
+-					  &driver_attr_new_id.attr);
++		error = driver_create_file(&usb_drv->drvwrap.driver,
++					   &driver_attr_new_id);
+ exit:
+ 	return error;
+ }
+@@ -103,8 +103,8 @@ static void usb_remove_newid_file(struct usb_driver *usb_drv)
+ 		return;
  
- #define QLA_DRIVER_MAJOR_VER	8
- #define QLA_DRIVER_MINOR_VER	2
-diff --git a/drivers/scsi/qla4xxx/ql4_init.c b/drivers/scsi/qla4xxx/ql4_init.c
-index d692c71..cbe0a17 100644
---- a/drivers/scsi/qla4xxx/ql4_init.c
-+++ b/drivers/scsi/qla4xxx/ql4_init.c
-@@ -5,6 +5,7 @@
-  * See LICENSE.qla4xxx for copyright and licensing details.
-  */
+ 	if (usb_drv->probe != NULL)
+-		sysfs_remove_file(&usb_drv->drvwrap.driver.kobj,
+-				  &driver_attr_new_id.attr);
++		driver_remove_file(&usb_drv->drvwrap.driver,
++				   &driver_attr_new_id);
+ }
  
-+#include <scsi/iscsi_if.h>
- #include "ql4_def.h"
- #include "ql4_glbl.h"
- #include "ql4_dbg.h"
-@@ -1305,7 +1306,8 @@ int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha,
- 		atomic_set(&ddb_entry->relogin_timer, 0);
- 		clear_bit(DF_RELOGIN, &ddb_entry->flags);
- 		clear_bit(DF_NO_RELOGIN, &ddb_entry->flags);
--		iscsi_if_create_session_done(ddb_entry->conn);
-+		iscsi_session_event(ddb_entry->sess,
-+				    ISCSI_KEVENT_CREATE_SESSION);
- 		/*
- 		 * Change the lun state to READY in case the lun TIMEOUT before
- 		 * the device came back.
-diff --git a/drivers/scsi/qla4xxx/ql4_isr.c b/drivers/scsi/qla4xxx/ql4_isr.c
-index 4a154be..0f029d0 100644
---- a/drivers/scsi/qla4xxx/ql4_isr.c
-+++ b/drivers/scsi/qla4xxx/ql4_isr.c
-@@ -123,15 +123,14 @@ static void qla4xxx_status_entry(struct scsi_qla_host *ha,
- 			break;
+ static void usb_free_dynids(struct usb_driver *usb_drv)
+diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
+index f81d08d..77a3759 100644
+--- a/drivers/usb/gadget/Kconfig
++++ b/drivers/usb/gadget/Kconfig
+@@ -308,7 +308,7 @@ config USB_S3C2410_DEBUG
+ 
+ config USB_GADGET_AT91
+ 	boolean "AT91 USB Device Port"
+-	depends on ARCH_AT91 && !ARCH_AT91SAM9RL
++	depends on ARCH_AT91 && !ARCH_AT91SAM9RL && !ARCH_AT91CAP9
+ 	select USB_GADGET_SELECTED
+ 	help
+ 	   Many Atmel AT91 processors (such as the AT91RM2000) have a
+diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
+index ecfe800..ddd4ee1 100644
+--- a/drivers/usb/host/ohci-hcd.c
++++ b/drivers/usb/host/ohci-hcd.c
+@@ -997,7 +997,7 @@ MODULE_LICENSE ("GPL");
+ #define PLATFORM_DRIVER		ohci_hcd_lh7a404_driver
+ #endif
  
- 		/* Copy Sense Data into sense buffer. */
--		memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer));
-+		memset(cmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
+-#ifdef CONFIG_PXA27x
++#if defined(CONFIG_PXA27x) || defined(CONFIG_PXA3xx)
+ #include "ohci-pxa27x.c"
+ #define PLATFORM_DRIVER		ohci_hcd_pxa27x_driver
+ #endif
+diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c
+index 5cfa3d1..74e1f4b 100644
+--- a/drivers/usb/host/ohci-omap.c
++++ b/drivers/usb/host/ohci-omap.c
+@@ -47,7 +47,7 @@
+ #endif
  
- 		sensebytecnt = le16_to_cpu(sts_entry->senseDataByteCnt);
- 		if (sensebytecnt == 0)
- 			break;
+ #ifdef CONFIG_TPS65010
+-#include <asm/arch/tps65010.h>
++#include <linux/i2c/tps65010.h>
+ #else
  
- 		memcpy(cmd->sense_buffer, sts_entry->senseData,
--		       min(sensebytecnt,
--			   (uint16_t) sizeof(cmd->sense_buffer)));
-+		       min_t(uint16_t, sensebytecnt, SCSI_SENSE_BUFFERSIZE));
+ #define LOW	0
+diff --git a/drivers/usb/host/ohci-pnx4008.c b/drivers/usb/host/ohci-pnx4008.c
+index ca2a6ab..6c52c66 100644
+--- a/drivers/usb/host/ohci-pnx4008.c
++++ b/drivers/usb/host/ohci-pnx4008.c
+@@ -112,9 +112,9 @@ static int isp1301_detach(struct i2c_client *client);
+ static int isp1301_command(struct i2c_client *client, unsigned int cmd,
+ 			   void *arg);
  
- 		DEBUG2(printk("scsi%ld:%d:%d:%d: %s: sense key = %x, "
- 			      "ASC/ASCQ = %02x/%02x\n", ha->host_no,
-@@ -208,8 +207,7 @@ static void qla4xxx_status_entry(struct scsi_qla_host *ha,
- 				break;
+-static unsigned short normal_i2c[] =
++static const unsigned short normal_i2c[] =
+     { ISP1301_I2C_ADDR, ISP1301_I2C_ADDR + 1, I2C_CLIENT_END };
+-static unsigned short dummy_i2c_addrlist[] = { I2C_CLIENT_END };
++static const unsigned short dummy_i2c_addrlist[] = { I2C_CLIENT_END };
  
- 			/* Copy Sense Data into sense buffer. */
--			memset(cmd->sense_buffer, 0,
--			       sizeof(cmd->sense_buffer));
-+			memset(cmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
+ static struct i2c_client_address_data addr_data = {
+ 	.normal_i2c = normal_i2c,
+@@ -123,7 +123,6 @@ static struct i2c_client_address_data addr_data = {
+ };
  
- 			sensebytecnt =
- 				le16_to_cpu(sts_entry->senseDataByteCnt);
-@@ -217,8 +215,7 @@ static void qla4xxx_status_entry(struct scsi_qla_host *ha,
- 				break;
+ struct i2c_driver isp1301_driver = {
+-	.id = I2C_DRIVERID_I2CDEV,	/* Fake Id */
+ 	.class = I2C_CLASS_HWMON,
+ 	.attach_adapter = isp1301_probe,
+ 	.detach_client = isp1301_detach,
+diff --git a/drivers/usb/host/ohci-pxa27x.c b/drivers/usb/host/ohci-pxa27x.c
+index 23d2fe5..ff9a798 100644
+--- a/drivers/usb/host/ohci-pxa27x.c
++++ b/drivers/usb/host/ohci-pxa27x.c
+@@ -22,6 +22,7 @@
+ #include <linux/device.h>
+ #include <linux/signal.h>
+ #include <linux/platform_device.h>
++#include <linux/clk.h>
  
- 			memcpy(cmd->sense_buffer, sts_entry->senseData,
--			       min(sensebytecnt,
--				   (uint16_t) sizeof(cmd->sense_buffer)));
-+			       min_t(uint16_t, sensebytecnt, SCSI_SENSE_BUFFERSIZE));
+ #include <asm/mach-types.h>
+ #include <asm/hardware.h>
+@@ -32,6 +33,8 @@
  
- 			DEBUG2(printk("scsi%ld:%d:%d:%d: %s: sense key = %x, "
- 				      "ASC/ASCQ = %02x/%02x\n", ha->host_no,
-diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c
-index 89460d2..f55b9f7 100644
---- a/drivers/scsi/qla4xxx/ql4_os.c
-+++ b/drivers/scsi/qla4xxx/ql4_os.c
-@@ -298,8 +298,7 @@ void qla4xxx_destroy_sess(struct ddb_entry *ddb_entry)
- 		return;
+ #define UHCRHPS(x)              __REG2( 0x4C000050, (x)<<2 )
  
- 	if (ddb_entry->conn) {
--		iscsi_if_destroy_session_done(ddb_entry->conn);
--		iscsi_destroy_conn(ddb_entry->conn);
-+		atomic_set(&ddb_entry->state, DDB_STATE_DEAD);
- 		iscsi_remove_session(ddb_entry->sess);
- 	}
- 	iscsi_free_session(ddb_entry->sess);
-@@ -309,6 +308,7 @@ int qla4xxx_add_sess(struct ddb_entry *ddb_entry)
- {
- 	int err;
++static struct clk *usb_clk;
++
+ /*
+   PMM_NPS_MODE -- PMM Non-power switching mode
+       Ports are powered continuously.
+@@ -80,7 +83,7 @@ static int pxa27x_start_hc(struct device *dev)
  
-+	ddb_entry->sess->recovery_tmo = ddb_entry->ha->port_down_retry_count;
- 	err = iscsi_add_session(ddb_entry->sess, ddb_entry->fw_ddb_index);
- 	if (err) {
- 		DEBUG2(printk(KERN_ERR "Could not add session.\n"));
-@@ -321,9 +321,6 @@ int qla4xxx_add_sess(struct ddb_entry *ddb_entry)
- 		DEBUG2(printk(KERN_ERR "Could not add connection.\n"));
+ 	inf = dev->platform_data;
+ 
+-	pxa_set_cken(CKEN_USBHOST, 1);
++	clk_enable(usb_clk);
+ 
+ 	UHCHR |= UHCHR_FHR;
+ 	udelay(11);
+@@ -123,7 +126,7 @@ static void pxa27x_stop_hc(struct device *dev)
+ 	UHCCOMS |= 1;
+ 	udelay(10);
+ 
+-	pxa_set_cken(CKEN_USBHOST, 0);
++	clk_disable(usb_clk);
+ }
+ 
+ 
+@@ -158,6 +161,10 @@ int usb_hcd_pxa27x_probe (const struct hc_driver *driver, struct platform_device
  		return -ENOMEM;
  	}
--
--	ddb_entry->sess->recovery_tmo = ddb_entry->ha->port_down_retry_count;
--	iscsi_if_create_session_done(ddb_entry->conn);
- 	return 0;
+ 
++	usb_clk = clk_get(&pdev->dev, "USBCLK");
++	if (IS_ERR(usb_clk))
++		return PTR_ERR(usb_clk);
++
+ 	hcd = usb_create_hcd (driver, &pdev->dev, "pxa27x");
+ 	if (!hcd)
+ 		return -ENOMEM;
+@@ -201,6 +208,7 @@ int usb_hcd_pxa27x_probe (const struct hc_driver *driver, struct platform_device
+ 	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+  err1:
+ 	usb_put_hcd(hcd);
++	clk_put(usb_clk);
+ 	return retval;
  }
  
-diff --git a/drivers/scsi/qlogicpti.c b/drivers/scsi/qlogicpti.c
-index 7a2e798..65455ab 100644
---- a/drivers/scsi/qlogicpti.c
-+++ b/drivers/scsi/qlogicpti.c
-@@ -871,11 +871,12 @@ static inline int load_cmd(struct scsi_cmnd *Cmnd, struct Command_Entry *cmd,
- 	struct scatterlist *sg, *s;
- 	int i, n;
+@@ -225,6 +233,7 @@ void usb_hcd_pxa27x_remove (struct usb_hcd *hcd, struct platform_device *pdev)
+ 	iounmap(hcd->regs);
+ 	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+ 	usb_put_hcd(hcd);
++	clk_put(usb_clk);
+ }
  
--	if (Cmnd->use_sg) {
-+	if (scsi_bufflen(Cmnd)) {
- 		int sg_count;
+ /*-------------------------------------------------------------------------*/
+diff --git a/drivers/usb/storage/freecom.c b/drivers/usb/storage/freecom.c
+index 88aa59a..f5a4e8d 100644
+--- a/drivers/usb/storage/freecom.c
++++ b/drivers/usb/storage/freecom.c
+@@ -132,8 +132,7 @@ freecom_readdata (struct scsi_cmnd *srb, struct us_data *us,
  
--		sg = (struct scatterlist *) Cmnd->request_buffer;
--		sg_count = sbus_map_sg(qpti->sdev, sg, Cmnd->use_sg, Cmnd->sc_data_direction);
-+		sg = scsi_sglist(Cmnd);
-+		sg_count = sbus_map_sg(qpti->sdev, sg, scsi_sg_count(Cmnd),
-+		                                      Cmnd->sc_data_direction);
+ 	/* Now transfer all of our blocks. */
+ 	US_DEBUGP("Start of read\n");
+-	result = usb_stor_bulk_transfer_sg(us, ipipe, srb->request_buffer,
+-			count, srb->use_sg, &srb->resid);
++	result = usb_stor_bulk_srb(us, ipipe, srb);
+ 	US_DEBUGP("freecom_readdata done!\n");
  
- 		ds = cmd->dataseg;
- 		cmd->segment_cnt = sg_count;
-@@ -914,16 +915,6 @@ static inline int load_cmd(struct scsi_cmnd *Cmnd, struct Command_Entry *cmd,
- 			}
- 			sg_count -= n;
- 		}
--	} else if (Cmnd->request_bufflen) {
--		Cmnd->SCp.ptr = (char *)(unsigned long)
--			sbus_map_single(qpti->sdev,
--					Cmnd->request_buffer,
--					Cmnd->request_bufflen,
--					Cmnd->sc_data_direction);
--
--		cmd->dataseg[0].d_base = (u32) ((unsigned long)Cmnd->SCp.ptr);
--		cmd->dataseg[0].d_count = Cmnd->request_bufflen;
--		cmd->segment_cnt = 1;
- 	} else {
- 		cmd->dataseg[0].d_base = 0;
- 		cmd->dataseg[0].d_count = 0;
-@@ -1151,7 +1142,7 @@ static struct scsi_cmnd *qlogicpti_intr_handler(struct qlogicpti *qpti)
+ 	if (result > USB_STOR_XFER_SHORT)
+@@ -166,8 +165,7 @@ freecom_writedata (struct scsi_cmnd *srb, struct us_data *us,
  
- 		if (sts->state_flags & SF_GOT_SENSE)
- 			memcpy(Cmnd->sense_buffer, sts->req_sense_data,
--			       sizeof(Cmnd->sense_buffer));
-+			       SCSI_SENSE_BUFFERSIZE);
+ 	/* Now transfer all of our blocks. */
+ 	US_DEBUGP("Start of write\n");
+-	result = usb_stor_bulk_transfer_sg(us, opipe, srb->request_buffer,
+-			count, srb->use_sg, &srb->resid);
++	result = usb_stor_bulk_srb(us, opipe, srb);
  
- 		if (sts->hdr.entry_type == ENTRY_STATUS)
- 			Cmnd->result =
-@@ -1159,17 +1150,11 @@ static struct scsi_cmnd *qlogicpti_intr_handler(struct qlogicpti *qpti)
- 		else
- 			Cmnd->result = DID_ERROR << 16;
+ 	US_DEBUGP("freecom_writedata done!\n");
+ 	if (result > USB_STOR_XFER_SHORT)
+@@ -281,7 +279,7 @@ int freecom_transport(struct scsi_cmnd *srb, struct us_data *us)
+ 	 * and such will hang. */
+ 	US_DEBUGP("Device indicates that it has %d bytes available\n",
+ 			le16_to_cpu (fst->Count));
+-	US_DEBUGP("SCSI requested %d\n", srb->request_bufflen);
++	US_DEBUGP("SCSI requested %d\n", scsi_bufflen(srb));
  
--		if (Cmnd->use_sg) {
-+		if (scsi_bufflen(Cmnd))
- 			sbus_unmap_sg(qpti->sdev,
--				      (struct scatterlist *)Cmnd->request_buffer,
--				      Cmnd->use_sg,
-+				      scsi_sglist(Cmnd), scsi_sg_count(Cmnd),
- 				      Cmnd->sc_data_direction);
--		} else if (Cmnd->request_bufflen) {
--			sbus_unmap_single(qpti->sdev,
--					  (__u32)((unsigned long)Cmnd->SCp.ptr),
--					  Cmnd->request_bufflen,
--					  Cmnd->sc_data_direction);
--		}
-+
- 		qpti->cmd_count[Cmnd->device->id]--;
- 		sbus_writew(out_ptr, qpti->qregs + MBOX5);
- 		Cmnd->host_scribble = (unsigned char *) done_queue;
-diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
-index 0fb1709..1a9fba6 100644
---- a/drivers/scsi/scsi.c
-+++ b/drivers/scsi/scsi.c
-@@ -122,6 +122,11 @@ static const char *const scsi_device_types[] = {
- 	"Automation/Drive ",
- };
+ 	/* Find the length we desire to read. */
+ 	switch (srb->cmnd[0]) {
+@@ -292,12 +290,12 @@ int freecom_transport(struct scsi_cmnd *srb, struct us_data *us)
+ 			length = le16_to_cpu(fst->Count);
+ 			break;
+ 		default:
+- 			length = srb->request_bufflen;
++			length = scsi_bufflen(srb);
+ 	}
  
-+/**
-+ * scsi_device_type - Return 17 char string indicating device type.
-+ * @type: type number to look up
-+ */
-+
- const char * scsi_device_type(unsigned type)
- {
- 	if (type == 0x1e)
-@@ -136,32 +141,45 @@ const char * scsi_device_type(unsigned type)
- EXPORT_SYMBOL(scsi_device_type);
+ 	/* verify that this amount is legal */
+-	if (length > srb->request_bufflen) {
+-		length = srb->request_bufflen;
++	if (length > scsi_bufflen(srb)) {
++		length = scsi_bufflen(srb);
+ 		US_DEBUGP("Truncating request to match buffer length: %d\n", length);
+ 	}
  
- struct scsi_host_cmd_pool {
--	struct kmem_cache	*slab;
--	unsigned int	users;
--	char		*name;
--	unsigned int	slab_flags;
--	gfp_t		gfp_mask;
-+	struct kmem_cache	*cmd_slab;
-+	struct kmem_cache	*sense_slab;
-+	unsigned int		users;
-+	char			*cmd_name;
-+	char			*sense_name;
-+	unsigned int		slab_flags;
-+	gfp_t			gfp_mask;
- };
+diff --git a/drivers/usb/storage/isd200.c b/drivers/usb/storage/isd200.c
+index 49ba6c0..178e8c2 100644
+--- a/drivers/usb/storage/isd200.c
++++ b/drivers/usb/storage/isd200.c
+@@ -49,6 +49,7 @@
+ #include <linux/slab.h>
+ #include <linux/hdreg.h>
+ #include <linux/ide.h>
++#include <linux/scatterlist.h>
  
- static struct scsi_host_cmd_pool scsi_cmd_pool = {
--	.name		= "scsi_cmd_cache",
-+	.cmd_name	= "scsi_cmd_cache",
-+	.sense_name	= "scsi_sense_cache",
- 	.slab_flags	= SLAB_HWCACHE_ALIGN,
+ #include <scsi/scsi.h>
+ #include <scsi/scsi_cmnd.h>
+@@ -287,6 +288,7 @@ struct isd200_info {
+ 	/* maximum number of LUNs supported */
+ 	unsigned char MaxLUNs;
+ 	struct scsi_cmnd srb;
++	struct scatterlist sg;
  };
  
- static struct scsi_host_cmd_pool scsi_cmd_dma_pool = {
--	.name		= "scsi_cmd_cache(DMA)",
-+	.cmd_name	= "scsi_cmd_cache(DMA)",
-+	.sense_name	= "scsi_sense_cache(DMA)",
- 	.slab_flags	= SLAB_HWCACHE_ALIGN|SLAB_CACHE_DMA,
- 	.gfp_mask	= __GFP_DMA,
- };
  
- static DEFINE_MUTEX(host_cmd_pool_mutex);
+@@ -398,6 +400,31 @@ static void isd200_build_sense(struct us_data *us, struct scsi_cmnd *srb)
+  * Transport routines
+  ***********************************************************************/
  
-+/**
-+ * __scsi_get_command - Allocate a struct scsi_cmnd
-+ * @shost: host to transmit command
-+ * @gfp_mask: allocation mask
++/**************************************************************************
++ *  isd200_set_srb(), isd200_srb_set_bufflen()
 + *
-+ * Description: allocate a struct scsi_cmd from host's slab, recycling from the
-+ *              host's free_list if necessary.
++ * Two helpers to facilitate in initialization of scsi_cmnd structure
++ * Will need to change when struct scsi_cmnd changes
 + */
- struct scsi_cmnd *__scsi_get_command(struct Scsi_Host *shost, gfp_t gfp_mask)
- {
- 	struct scsi_cmnd *cmd;
-+	unsigned char *buf;
- 
--	cmd = kmem_cache_alloc(shost->cmd_pool->slab,
--			gfp_mask | shost->cmd_pool->gfp_mask);
-+	cmd = kmem_cache_alloc(shost->cmd_pool->cmd_slab,
-+			       gfp_mask | shost->cmd_pool->gfp_mask);
- 
- 	if (unlikely(!cmd)) {
- 		unsigned long flags;
-@@ -173,19 +191,32 @@ struct scsi_cmnd *__scsi_get_command(struct Scsi_Host *shost, gfp_t gfp_mask)
- 			list_del_init(&cmd->list);
- 		}
- 		spin_unlock_irqrestore(&shost->free_list_lock, flags);
++static void isd200_set_srb(struct isd200_info *info,
++	enum dma_data_direction dir, void* buff, unsigned bufflen)
++{
++	struct scsi_cmnd *srb = &info->srb;
++
++	if (buff)
++		sg_init_one(&info->sg, buff, bufflen);
++
++	srb->sc_data_direction = dir;
++	srb->request_buffer = buff ? &info->sg : NULL;
++	srb->request_bufflen = bufflen;
++	srb->use_sg = buff ? 1 : 0;
++}
++
++static void isd200_srb_set_bufflen(struct scsi_cmnd *srb, unsigned bufflen)
++{
++	srb->request_bufflen = bufflen;
++}
 +
-+		if (cmd) {
-+			buf = cmd->sense_buffer;
-+			memset(cmd, 0, sizeof(*cmd));
-+			cmd->sense_buffer = buf;
-+		}
-+	} else {
-+		buf = kmem_cache_alloc(shost->cmd_pool->sense_slab,
-+				       gfp_mask | shost->cmd_pool->gfp_mask);
-+		if (likely(buf)) {
-+			memset(cmd, 0, sizeof(*cmd));
-+			cmd->sense_buffer = buf;
-+		} else {
-+			kmem_cache_free(shost->cmd_pool->cmd_slab, cmd);
-+			cmd = NULL;
-+		}
- 	}
- 
- 	return cmd;
- }
- EXPORT_SYMBOL_GPL(__scsi_get_command);
  
--/*
-- * Function:	scsi_get_command()
-- *
-- * Purpose:	Allocate and setup a scsi command block
-- *
-- * Arguments:	dev	- parent scsi device
-- *		gfp_mask- allocator flags
-+/**
-+ * scsi_get_command - Allocate and setup a scsi command block
-+ * @dev: parent scsi device
-+ * @gfp_mask: allocator flags
-  *
-  * Returns:	The allocated scsi command structure.
-  */
-@@ -202,7 +233,6 @@ struct scsi_cmnd *scsi_get_command(struct scsi_device *dev, gfp_t gfp_mask)
- 	if (likely(cmd != NULL)) {
- 		unsigned long flags;
+ /**************************************************************************
+  *  isd200_action
+@@ -432,9 +459,7 @@ static int isd200_action( struct us_data *us, int action,
+ 		ata.generic.RegisterSelect =
+ 		  REG_CYLINDER_LOW | REG_CYLINDER_HIGH |
+ 		  REG_STATUS | REG_ERROR;
+-		srb->sc_data_direction = DMA_FROM_DEVICE;
+-		srb->request_buffer = pointer;
+-		srb->request_bufflen = value;
++		isd200_set_srb(info, DMA_FROM_DEVICE, pointer, value);
+ 		break;
  
--		memset(cmd, 0, sizeof(*cmd));
- 		cmd->device = dev;
- 		init_timer(&cmd->eh_timeout);
- 		INIT_LIST_HEAD(&cmd->list);
-@@ -217,6 +247,12 @@ struct scsi_cmnd *scsi_get_command(struct scsi_device *dev, gfp_t gfp_mask)
- }
- EXPORT_SYMBOL(scsi_get_command);
+ 	case ACTION_ENUM:
+@@ -444,7 +469,7 @@ static int isd200_action( struct us_data *us, int action,
+ 					   ACTION_SELECT_5;
+ 		ata.generic.RegisterSelect = REG_DEVICE_HEAD;
+ 		ata.write.DeviceHeadByte = value;
+-		srb->sc_data_direction = DMA_NONE;
++		isd200_set_srb(info, DMA_NONE, NULL, 0);
+ 		break;
  
-+/**
-+ * __scsi_put_command - Free a struct scsi_cmnd
-+ * @shost: dev->host
-+ * @cmd: Command to free
-+ * @dev: parent scsi device
-+ */
- void __scsi_put_command(struct Scsi_Host *shost, struct scsi_cmnd *cmd,
- 			struct device *dev)
- {
-@@ -230,19 +266,19 @@ void __scsi_put_command(struct Scsi_Host *shost, struct scsi_cmnd *cmd,
- 	}
- 	spin_unlock_irqrestore(&shost->free_list_lock, flags);
+ 	case ACTION_RESET:
+@@ -453,7 +478,7 @@ static int isd200_action( struct us_data *us, int action,
+ 					   ACTION_SELECT_3|ACTION_SELECT_4;
+ 		ata.generic.RegisterSelect = REG_DEVICE_CONTROL;
+ 		ata.write.DeviceControlByte = ATA_DC_RESET_CONTROLLER;
+-		srb->sc_data_direction = DMA_NONE;
++		isd200_set_srb(info, DMA_NONE, NULL, 0);
+ 		break;
  
--	if (likely(cmd != NULL))
--		kmem_cache_free(shost->cmd_pool->slab, cmd);
-+	if (likely(cmd != NULL)) {
-+		kmem_cache_free(shost->cmd_pool->sense_slab,
-+				cmd->sense_buffer);
-+		kmem_cache_free(shost->cmd_pool->cmd_slab, cmd);
-+	}
+ 	case ACTION_REENABLE:
+@@ -462,7 +487,7 @@ static int isd200_action( struct us_data *us, int action,
+ 					   ACTION_SELECT_3|ACTION_SELECT_4;
+ 		ata.generic.RegisterSelect = REG_DEVICE_CONTROL;
+ 		ata.write.DeviceControlByte = ATA_DC_REENABLE_CONTROLLER;
+-		srb->sc_data_direction = DMA_NONE;
++		isd200_set_srb(info, DMA_NONE, NULL, 0);
+ 		break;
  
- 	put_device(dev);
- }
- EXPORT_SYMBOL(__scsi_put_command);
+ 	case ACTION_SOFT_RESET:
+@@ -471,21 +496,20 @@ static int isd200_action( struct us_data *us, int action,
+ 		ata.generic.RegisterSelect = REG_DEVICE_HEAD | REG_COMMAND;
+ 		ata.write.DeviceHeadByte = info->DeviceHead;
+ 		ata.write.CommandByte = WIN_SRST;
+-		srb->sc_data_direction = DMA_NONE;
++		isd200_set_srb(info, DMA_NONE, NULL, 0);
+ 		break;
  
--/*
-- * Function:	scsi_put_command()
-- *
-- * Purpose:	Free a scsi command block
-- *
-- * Arguments:	cmd	- command block to free
-+/**
-+ * scsi_put_command - Free a scsi command block
-+ * @cmd: command block to free
-  *
-  * Returns:	Nothing.
-  *
-@@ -263,12 +299,13 @@ void scsi_put_command(struct scsi_cmnd *cmd)
- }
- EXPORT_SYMBOL(scsi_put_command);
+ 	case ACTION_IDENTIFY:
+ 		US_DEBUGP("   isd200_action(IDENTIFY)\n");
+ 		ata.generic.RegisterSelect = REG_COMMAND;
+ 		ata.write.CommandByte = WIN_IDENTIFY;
+-		srb->sc_data_direction = DMA_FROM_DEVICE;
+-		srb->request_buffer = (void *) info->id;
+-		srb->request_bufflen = sizeof(struct hd_driveid);
++		isd200_set_srb(info, DMA_FROM_DEVICE, info->id,
++		                                sizeof(struct hd_driveid));
+ 		break;
  
--/*
-- * Function:	scsi_setup_command_freelist()
-- *
-- * Purpose:	Setup the command freelist for a scsi host.
-+/**
-+ * scsi_setup_command_freelist - Setup the command freelist for a scsi host.
-+ * @shost: host to allocate the freelist for.
-  *
-- * Arguments:	shost	- host to allocate the freelist for.
-+ * Description: The command freelist protects against system-wide out of memory
-+ * deadlock by preallocating one SCSI command structure for each host, so the
-+ * system can always write to a swap file on a device associated with that host.
-  *
-  * Returns:	Nothing.
-  */
-@@ -282,16 +319,24 @@ int scsi_setup_command_freelist(struct Scsi_Host *shost)
+ 	default:
+ 		US_DEBUGP("Error: Undefined action %d\n",action);
+-		break;
++		return ISD200_ERROR;
+ 	}
  
- 	/*
- 	 * Select a command slab for this host and create it if not
--	 * yet existant.
-+	 * yet existent.
- 	 */
- 	mutex_lock(&host_cmd_pool_mutex);
- 	pool = (shost->unchecked_isa_dma ? &scsi_cmd_dma_pool : &scsi_cmd_pool);
- 	if (!pool->users) {
--		pool->slab = kmem_cache_create(pool->name,
--				sizeof(struct scsi_cmnd), 0,
--				pool->slab_flags, NULL);
--		if (!pool->slab)
-+		pool->cmd_slab = kmem_cache_create(pool->cmd_name,
-+						   sizeof(struct scsi_cmnd), 0,
-+						   pool->slab_flags, NULL);
-+		if (!pool->cmd_slab)
-+			goto fail;
-+
-+		pool->sense_slab = kmem_cache_create(pool->sense_name,
-+						     SCSI_SENSE_BUFFERSIZE, 0,
-+						     pool->slab_flags, NULL);
-+		if (!pool->sense_slab) {
-+			kmem_cache_destroy(pool->cmd_slab);
- 			goto fail;
-+		}
+ 	memcpy(srb->cmnd, &ata, sizeof(ata.generic));
+@@ -590,7 +614,7 @@ static void isd200_invoke_transport( struct us_data *us,
+ 		return;
  	}
  
- 	pool->users++;
-@@ -301,29 +346,36 @@ int scsi_setup_command_freelist(struct Scsi_Host *shost)
- 	/*
- 	 * Get one backup command for this host.
- 	 */
--	cmd = kmem_cache_alloc(shost->cmd_pool->slab,
--			GFP_KERNEL | shost->cmd_pool->gfp_mask);
-+	cmd = kmem_cache_alloc(shost->cmd_pool->cmd_slab,
-+			       GFP_KERNEL | shost->cmd_pool->gfp_mask);
- 	if (!cmd)
- 		goto fail2;
--	list_add(&cmd->list, &shost->free_list);		
-+
-+	cmd->sense_buffer = kmem_cache_alloc(shost->cmd_pool->sense_slab,
-+					     GFP_KERNEL |
-+					     shost->cmd_pool->gfp_mask);
-+	if (!cmd->sense_buffer)
-+		goto fail2;
-+
-+	list_add(&cmd->list, &shost->free_list);
- 	return 0;
+-	if ((srb->resid > 0) &&
++	if ((scsi_get_resid(srb) > 0) &&
+ 	    !((srb->cmnd[0] == REQUEST_SENSE) ||
+ 	      (srb->cmnd[0] == INQUIRY) ||
+ 	      (srb->cmnd[0] == MODE_SENSE) ||
+@@ -1217,7 +1241,6 @@ static int isd200_get_inquiry_data( struct us_data *us )
+ 	return(retStatus);
+ }
  
-  fail2:
--	if (!--pool->users)
--		kmem_cache_destroy(pool->slab);
--	return -ENOMEM;
-+	if (cmd)
-+		kmem_cache_free(shost->cmd_pool->cmd_slab, cmd);
-+	mutex_lock(&host_cmd_pool_mutex);
-+	if (!--pool->users) {
-+		kmem_cache_destroy(pool->cmd_slab);
-+		kmem_cache_destroy(pool->sense_slab);
-+	}
-  fail:
- 	mutex_unlock(&host_cmd_pool_mutex);
- 	return -ENOMEM;
 -
- }
+ /**************************************************************************
+  * isd200_scsi_to_ata
+  *									 
+@@ -1266,7 +1289,7 @@ static int isd200_scsi_to_ata(struct scsi_cmnd *srb, struct us_data *us,
+ 			ataCdb->generic.TransferBlockSize = 1;
+ 			ataCdb->generic.RegisterSelect = REG_COMMAND;
+ 			ataCdb->write.CommandByte = ATA_COMMAND_GET_MEDIA_STATUS;
+-			srb->request_bufflen = 0;
++			isd200_srb_set_bufflen(srb, 0);
+ 		} else {
+ 			US_DEBUGP("   Media Status not supported, just report okay\n");
+ 			srb->result = SAM_STAT_GOOD;
+@@ -1284,7 +1307,7 @@ static int isd200_scsi_to_ata(struct scsi_cmnd *srb, struct us_data *us,
+ 			ataCdb->generic.TransferBlockSize = 1;
+ 			ataCdb->generic.RegisterSelect = REG_COMMAND;
+ 			ataCdb->write.CommandByte = ATA_COMMAND_GET_MEDIA_STATUS;
+-			srb->request_bufflen = 0;
++			isd200_srb_set_bufflen(srb, 0);
+ 		} else {
+ 			US_DEBUGP("   Media Status not supported, just report okay\n");
+ 			srb->result = SAM_STAT_GOOD;
+@@ -1390,7 +1413,7 @@ static int isd200_scsi_to_ata(struct scsi_cmnd *srb, struct us_data *us,
+ 			ataCdb->generic.RegisterSelect = REG_COMMAND;
+ 			ataCdb->write.CommandByte = (srb->cmnd[4] & 0x1) ?
+ 				WIN_DOORLOCK : WIN_DOORUNLOCK;
+-			srb->request_bufflen = 0;
++			isd200_srb_set_bufflen(srb, 0);
+ 		} else {
+ 			US_DEBUGP("   Not removeable media, just report okay\n");
+ 			srb->result = SAM_STAT_GOOD;
+@@ -1416,7 +1439,7 @@ static int isd200_scsi_to_ata(struct scsi_cmnd *srb, struct us_data *us,
+ 			ataCdb->generic.TransferBlockSize = 1;
+ 			ataCdb->generic.RegisterSelect = REG_COMMAND;
+ 			ataCdb->write.CommandByte = ATA_COMMAND_GET_MEDIA_STATUS;
+-			srb->request_bufflen = 0;
++			isd200_srb_set_bufflen(srb, 0);
+ 		} else {
+ 			US_DEBUGP("   Nothing to do, just report okay\n");
+ 			srb->result = SAM_STAT_GOOD;
+@@ -1525,7 +1548,7 @@ int isd200_Initialization(struct us_data *us)
  
--/*
-- * Function:	scsi_destroy_command_freelist()
-- *
-- * Purpose:	Release the command freelist for a scsi host.
-- *
-- * Arguments:	shost	- host that's freelist is going to be destroyed
-+/**
-+ * scsi_destroy_command_freelist - Release the command freelist for a scsi host.
-+ * @shost: host whose freelist is going to be destroyed
-  */
- void scsi_destroy_command_freelist(struct Scsi_Host *shost)
+ void isd200_ata_command(struct scsi_cmnd *srb, struct us_data *us)
  {
-@@ -332,12 +384,16 @@ void scsi_destroy_command_freelist(struct Scsi_Host *shost)
- 
- 		cmd = list_entry(shost->free_list.next, struct scsi_cmnd, list);
- 		list_del_init(&cmd->list);
--		kmem_cache_free(shost->cmd_pool->slab, cmd);
-+		kmem_cache_free(shost->cmd_pool->sense_slab,
-+				cmd->sense_buffer);
-+		kmem_cache_free(shost->cmd_pool->cmd_slab, cmd);
- 	}
+-	int sendToTransport = 1;
++	int sendToTransport = 1, orig_bufflen;
+ 	union ata_cdb ataCdb;
  
- 	mutex_lock(&host_cmd_pool_mutex);
--	if (!--shost->cmd_pool->users)
--		kmem_cache_destroy(shost->cmd_pool->slab);
-+	if (!--shost->cmd_pool->users) {
-+		kmem_cache_destroy(shost->cmd_pool->cmd_slab);
-+		kmem_cache_destroy(shost->cmd_pool->sense_slab);
-+	}
- 	mutex_unlock(&host_cmd_pool_mutex);
- }
+ 	/* Make sure driver was initialized */
+@@ -1533,11 +1556,14 @@ void isd200_ata_command(struct scsi_cmnd *srb, struct us_data *us)
+ 	if (us->extra == NULL)
+ 		US_DEBUGP("ERROR Driver not initialized\n");
  
-@@ -441,8 +497,12 @@ void scsi_log_completion(struct scsi_cmnd *cmd, int disposition)
- }
- #endif
+-	/* Convert command */
+-	srb->resid = 0;
++	scsi_set_resid(srb, 0);
++	/* scsi_bufflen might change in protocol translation to ata */
++	orig_bufflen = scsi_bufflen(srb);
+ 	sendToTransport = isd200_scsi_to_ata(srb, us, &ataCdb);
  
--/* 
-- * Assign a serial number to the request for error recovery
-+/**
-+ * scsi_cmd_get_serial - Assign a serial number to a command
-+ * @host: the scsi host
-+ * @cmd: command to assign serial number to
-+ *
-+ * Description: a serial number identifies a request for error recovery
-  * and debugging purposes.  Protected by the Host_Lock of host.
-  */
- static inline void scsi_cmd_get_serial(struct Scsi_Host *host, struct scsi_cmnd *cmd)
-@@ -452,14 +512,12 @@ static inline void scsi_cmd_get_serial(struct Scsi_Host *host, struct scsi_cmnd
- 		cmd->serial_number = host->cmd_serial_number++;
+ 	/* send the command to the transport layer */
+ 	if (sendToTransport)
+ 		isd200_invoke_transport(us, srb, &ataCdb);
++
++	isd200_srb_set_bufflen(srb, orig_bufflen);
  }
+diff --git a/drivers/usb/storage/protocol.c b/drivers/usb/storage/protocol.c
+index 889622b..a41ce21 100644
+--- a/drivers/usb/storage/protocol.c
++++ b/drivers/usb/storage/protocol.c
+@@ -149,11 +149,7 @@ void usb_stor_transparent_scsi_command(struct scsi_cmnd *srb,
+  ***********************************************************************/
  
--/*
-- * Function:    scsi_dispatch_command
-- *
-- * Purpose:     Dispatch a command to the low-level driver.
-- *
-- * Arguments:   cmd - command block we are dispatching.
-+/**
-+ * scsi_dispatch_command - Dispatch a command to the low-level driver.
-+ * @cmd: command block we are dispatching.
-  *
-- * Notes:
-+ * Return: nonzero return request was rejected and device's queue needs to be
-+ * plugged.
-  */
- int scsi_dispatch_cmd(struct scsi_cmnd *cmd)
- {
-@@ -585,7 +643,7 @@ int scsi_dispatch_cmd(struct scsi_cmnd *cmd)
+ /* Copy a buffer of length buflen to/from the srb's transfer buffer.
+- * (Note: for scatter-gather transfers (srb->use_sg > 0), srb->request_buffer
+- * points to a list of s-g entries and we ignore srb->request_bufflen.
+- * For non-scatter-gather transfers, srb->request_buffer points to the
+- * transfer buffer itself and srb->request_bufflen is the buffer's length.)
+- * Update the *index and *offset variables so that the next copy will
++ * Update the **sgptr and *offset variables so that the next copy will
+  * pick up from where this one left off. */
  
- /**
-  * scsi_req_abort_cmd -- Request command recovery for the specified command
-- * cmd: pointer to the SCSI command of interest
-+ * @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
-@@ -606,9 +664,9 @@ EXPORT_SYMBOL(scsi_req_abort_cmd);
-  * @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.
-  *
-- * This function is the mid-level's (SCSI Core) interrupt routine, which
-- * regains ownership of the SCSI command (de facto) from a LLDD, and enqueues
-- * the command to the done queue for further processing.
-+ * Description: This function is the mid-level's (SCSI Core) interrupt routine,
-+ * which regains ownership of the SCSI command (de facto) from a LLDD, and
-+ * enqueues the command to the done queue for further processing.
-  *
-  * This is the producer of the done queue who enqueues at the tail.
-  *
-@@ -617,7 +675,7 @@ EXPORT_SYMBOL(scsi_req_abort_cmd);
- static void scsi_done(struct scsi_cmnd *cmd)
+ unsigned int usb_stor_access_xfer_buf(unsigned char *buffer,
+@@ -162,80 +158,64 @@ unsigned int usb_stor_access_xfer_buf(unsigned char *buffer,
  {
- 	/*
--	 * We don't have to worry about this one timing out any more.
-+	 * 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
-@@ -660,10 +718,11 @@ static struct scsi_driver *scsi_cmd_to_driver(struct scsi_cmnd *cmd)
- 	return *(struct scsi_driver **)cmd->request->rq_disk->private_data;
- }
- 
--/*
-- * Function:    scsi_finish_command
-+/**
-+ * scsi_finish_command - cleanup and pass command back to upper layer
-+ * @cmd: the command
-  *
-- * Purpose:     Pass command off to upper layer for finishing of I/O
-+ * Description: Pass command off to upper layer for finishing of I/O
-  *              request, waking processes that are waiting on results,
-  *              etc.
-  */
-@@ -708,18 +767,14 @@ void scsi_finish_command(struct scsi_cmnd *cmd)
- }
- EXPORT_SYMBOL(scsi_finish_command);
- 
--/*
-- * Function:	scsi_adjust_queue_depth()
-- *
-- * Purpose:	Allow low level drivers to tell us to change the queue depth
-- * 		on a specific SCSI device
-- *
-- * Arguments:	sdev	- SCSI Device in question
-- * 		tagged	- Do we use tagged queueing (non-0) or do we treat
-- * 			  this device as an untagged device (0)
-- * 		tags	- Number of tags allowed if tagged queueing enabled,
-- * 			  or number of commands the low level driver can
-- * 			  queue up in non-tagged mode (as per cmd_per_lun).
-+/**
-+ * scsi_adjust_queue_depth - Let low level drivers change a device's queue depth
-+ * @sdev: SCSI Device in question
-+ * @tagged: Do we use tagged queueing (non-0) or do we treat
-+ *          this device as an untagged device (0)
-+ * @tags: Number of tags allowed if tagged queueing enabled,
-+ *        or number of commands the low level driver can
-+ *        queue up in non-tagged mode (as per cmd_per_lun).
-  *
-  * Returns:	Nothing
-  *
-@@ -742,8 +797,8 @@ void scsi_adjust_queue_depth(struct scsi_device *sdev, int tagged, int tags)
- 
- 	spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
- 
--	/* Check to see if the queue is managed by the block layer
--	 * if it is, and we fail to adjust the depth, exit */
-+	/* Check to see if the queue is managed by the block layer.
-+	 * If it is, and we fail to adjust the depth, exit. */
- 	if (blk_queue_tagged(sdev->request_queue) &&
- 	    blk_queue_resize_tags(sdev->request_queue, tags) != 0)
- 		goto out;
-@@ -772,20 +827,17 @@ void scsi_adjust_queue_depth(struct scsi_device *sdev, int tagged, int tags)
- }
- EXPORT_SYMBOL(scsi_adjust_queue_depth);
- 
--/*
-- * Function:	scsi_track_queue_full()
-+/**
-+ * scsi_track_queue_full - track QUEUE_FULL events to adjust queue depth
-+ * @sdev: SCSI Device in question
-+ * @depth: Current number of outstanding SCSI commands on this device,
-+ *         not counting the one returned as QUEUE_FULL.
-  *
-- * Purpose:	This function will track successive QUEUE_FULL events on a
-+ * Description:	This function will track successive QUEUE_FULL events on a
-  * 		specific SCSI device to determine if and when there is a
-  * 		need to adjust the queue depth on the device.
-  *
-- * Arguments:	sdev	- SCSI Device in question
-- * 		depth	- Current number of outstanding SCSI commands on
-- * 			  this device, not counting the one returned as
-- * 			  QUEUE_FULL.
-- *
-- * Returns:	0 - No change needed
-- * 		>0 - Adjust queue depth to this new depth
-+ * Returns:	0 - No change needed, >0 - Adjust queue depth to this new depth,
-  * 		-1 - Drop back to untagged operation using host->cmd_per_lun
-  * 			as the untagged command depth
-  *
-@@ -824,10 +876,10 @@ int scsi_track_queue_full(struct scsi_device *sdev, int depth)
- EXPORT_SYMBOL(scsi_track_queue_full);
+ 	unsigned int cnt;
  
- /**
-- * scsi_device_get  -  get an addition reference to a scsi_device
-+ * scsi_device_get  -  get an additional reference to a scsi_device
-  * @sdev:	device to get a reference to
-  *
-- * Gets a reference to the scsi_device and increments the use count
-+ * Description: Gets a reference to the scsi_device and increments the use count
-  * of the underlying LLDD module.  You must hold host_lock of the
-  * parent Scsi_Host or already have a reference when calling this.
-  */
-@@ -849,8 +901,8 @@ EXPORT_SYMBOL(scsi_device_get);
-  * scsi_device_put  -  release a reference to a scsi_device
-  * @sdev:	device to release a reference on.
-  *
-- * Release a reference to the scsi_device and decrements the use count
-- * of the underlying LLDD module.  The device is freed once the last
-+ * Description: Release a reference to the scsi_device and decrements the use
-+ * count of the underlying LLDD module.  The device is freed once the last
-  * user vanishes.
-  */
- void scsi_device_put(struct scsi_device *sdev)
-@@ -867,7 +919,7 @@ void scsi_device_put(struct scsi_device *sdev)
+-	/* If not using scatter-gather, just transfer the data directly.
+-	 * Make certain it will fit in the available buffer space. */
+-	if (srb->use_sg == 0) {
+-		if (*offset >= srb->request_bufflen)
+-			return 0;
+-		cnt = min(buflen, srb->request_bufflen - *offset);
+-		if (dir == TO_XFER_BUF)
+-			memcpy((unsigned char *) srb->request_buffer + *offset,
+-					buffer, cnt);
+-		else
+-			memcpy(buffer, (unsigned char *) srb->request_buffer +
+-					*offset, cnt);
+-		*offset += cnt;
+-
+-	/* Using scatter-gather.  We have to go through the list one entry
++	/* We have to go through the list one entry
+ 	 * at a time.  Each s-g entry contains some number of pages, and
+ 	 * each page has to be kmap()'ed separately.  If the page is already
+ 	 * in kernel-addressable memory then kmap() will return its address.
+ 	 * If the page is not directly accessible -- such as a user buffer
+ 	 * located in high memory -- then kmap() will map it to a temporary
+ 	 * position in the kernel's virtual address space. */
+-	} else {
+-		struct scatterlist *sg = *sgptr;
+-
+-		if (!sg)
+-			sg = (struct scatterlist *) srb->request_buffer;
+-
+-		/* This loop handles a single s-g list entry, which may
+-		 * include multiple pages.  Find the initial page structure
+-		 * and the starting offset within the page, and update
+-		 * the *offset and *index values for the next loop. */
+-		cnt = 0;
+-		while (cnt < buflen) {
+-			struct page *page = sg_page(sg) +
+-					((sg->offset + *offset) >> PAGE_SHIFT);
+-			unsigned int poff =
+-					(sg->offset + *offset) & (PAGE_SIZE-1);
+-			unsigned int sglen = sg->length - *offset;
+-
+-			if (sglen > buflen - cnt) {
+-
+-				/* Transfer ends within this s-g entry */
+-				sglen = buflen - cnt;
+-				*offset += sglen;
+-			} else {
+-
+-				/* Transfer continues to next s-g entry */
+-				*offset = 0;
+-				sg = sg_next(sg);
+-			}
+-
+-			/* Transfer the data for all the pages in this
+-			 * s-g entry.  For each page: call kmap(), do the
+-			 * transfer, and call kunmap() immediately after. */
+-			while (sglen > 0) {
+-				unsigned int plen = min(sglen, (unsigned int)
+-						PAGE_SIZE - poff);
+-				unsigned char *ptr = kmap(page);
+-
+-				if (dir == TO_XFER_BUF)
+-					memcpy(ptr + poff, buffer + cnt, plen);
+-				else
+-					memcpy(buffer + cnt, ptr + poff, plen);
+-				kunmap(page);
+-
+-				/* Start at the beginning of the next page */
+-				poff = 0;
+-				++page;
+-				cnt += plen;
+-				sglen -= plen;
+-			}
++	struct scatterlist *sg = *sgptr;
++
++	if (!sg)
++		sg = scsi_sglist(srb);
++
++	/* This loop handles a single s-g list entry, which may
++		* include multiple pages.  Find the initial page structure
++		* and the starting offset within the page, and update
++		* the *offset and **sgptr values for the next loop. */
++	cnt = 0;
++	while (cnt < buflen) {
++		struct page *page = sg_page(sg) +
++				((sg->offset + *offset) >> PAGE_SHIFT);
++		unsigned int poff =
++				(sg->offset + *offset) & (PAGE_SIZE-1);
++		unsigned int sglen = sg->length - *offset;
++
++		if (sglen > buflen - cnt) {
++
++			/* Transfer ends within this s-g entry */
++			sglen = buflen - cnt;
++			*offset += sglen;
++		} else {
++
++			/* Transfer continues to next s-g entry */
++			*offset = 0;
++			sg = sg_next(sg);
++		}
++
++		/* Transfer the data for all the pages in this
++			* s-g entry.  For each page: call kmap(), do the
++			* transfer, and call kunmap() immediately after. */
++		while (sglen > 0) {
++			unsigned int plen = min(sglen, (unsigned int)
++					PAGE_SIZE - poff);
++			unsigned char *ptr = kmap(page);
++
++			if (dir == TO_XFER_BUF)
++				memcpy(ptr + poff, buffer + cnt, plen);
++			else
++				memcpy(buffer + cnt, ptr + poff, plen);
++			kunmap(page);
++
++			/* Start at the beginning of the next page */
++			poff = 0;
++			++page;
++			cnt += plen;
++			sglen -= plen;
+ 		}
+-		*sgptr = sg;
+ 	}
++	*sgptr = sg;
+ 
+ 	/* Return the amount actually transferred */
+ 	return cnt;
+@@ -251,6 +231,6 @@ void usb_stor_set_xfer_buf(unsigned char *buffer,
+ 
+ 	usb_stor_access_xfer_buf(buffer, buflen, srb, &sg, &offset,
+ 			TO_XFER_BUF);
+-	if (buflen < srb->request_bufflen)
+-		srb->resid = srb->request_bufflen - buflen;
++	if (buflen < scsi_bufflen(srb))
++		scsi_set_resid(srb, scsi_bufflen(srb) - buflen);
  }
- EXPORT_SYMBOL(scsi_device_put);
+diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c
+index 7c9593b..8c1e295 100644
+--- a/drivers/usb/storage/scsiglue.c
++++ b/drivers/usb/storage/scsiglue.c
+@@ -81,6 +81,16 @@ static int slave_alloc (struct scsi_device *sdev)
+ 	 */
+ 	sdev->inquiry_len = 36;
  
--/* helper for shost_for_each_device, thus not documented */
-+/* helper for shost_for_each_device, see that for documentation */
- struct scsi_device *__scsi_iterate_devices(struct Scsi_Host *shost,
- 					   struct scsi_device *prev)
++	/* Scatter-gather buffers (all but the last) must have a length
++	 * divisible by the bulk maxpacket size.  Otherwise a data packet
++	 * would end up being short, causing a premature end to the data
++	 * transfer.  Since high-speed bulk pipes have a maxpacket size
++	 * of 512, we'll use that as the scsi device queue's DMA alignment
++	 * mask.  Guaranteeing proper alignment of the first buffer will
++	 * have the desired effect because, except at the beginning and
++	 * the end, scatter-gather buffers follow page boundaries. */
++	blk_queue_update_dma_alignment(sdev->request_queue, (512 - 1));
++
+ 	/*
+ 	 * The UFI spec treates the Peripheral Qualifier bits in an
+ 	 * INQUIRY result as reserved and requires devices to set them
+@@ -100,16 +110,6 @@ static int slave_configure(struct scsi_device *sdev)
  {
-@@ -895,6 +947,8 @@ EXPORT_SYMBOL(__scsi_iterate_devices);
- /**
-  * starget_for_each_device  -  helper to walk all devices of a target
-  * @starget:	target whose devices we want to iterate over.
-+ * @data:	Opaque passed to each function call.
-+ * @fn:		Function to call on each device
-  *
-  * This traverses over each device of @starget.  The devices have
-  * a reference that must be released by scsi_host_put when breaking
-@@ -946,13 +1000,13 @@ EXPORT_SYMBOL(__starget_for_each_device);
-  * @starget:	SCSI target pointer
-  * @lun:	SCSI Logical Unit Number
-  *
-- * Looks up the scsi_device with the specified @lun for a give
-- * @starget. The returned scsi_device does not have an additional
-+ * Description: Looks up the scsi_device with the specified @lun for a given
-+ * @starget.  The returned scsi_device does not have an additional
-  * reference.  You must hold the host's host_lock over this call and
-  * any access to the returned scsi_device.
-  *
-- * Note:  The only reason why drivers would want to use this is because
-- * they're need to access the device list in irq context.  Otherwise you
-+ * Note:  The only reason why drivers should use this is because
-+ * they need to access the device list in irq context.  Otherwise you
-  * really want to use scsi_device_lookup_by_target instead.
-  **/
- struct scsi_device *__scsi_device_lookup_by_target(struct scsi_target *starget,
-@@ -974,9 +1028,9 @@ EXPORT_SYMBOL(__scsi_device_lookup_by_target);
-  * @starget:	SCSI target pointer
-  * @lun:	SCSI Logical Unit Number
-  *
-- * Looks up the scsi_device with the specified @channel, @id, @lun for a
-- * give host.  The returned scsi_device has an additional reference that
-- * needs to be release with scsi_host_put once you're done with it.
-+ * Description: Looks up the scsi_device with the specified @channel, @id, @lun
-+ * for a given host.  The returned scsi_device has an additional reference that
-+ * needs to be released with scsi_device_put once you're done with it.
-  **/
- struct scsi_device *scsi_device_lookup_by_target(struct scsi_target *starget,
- 						 uint lun)
-@@ -996,19 +1050,19 @@ struct scsi_device *scsi_device_lookup_by_target(struct scsi_target *starget,
- EXPORT_SYMBOL(scsi_device_lookup_by_target);
+ 	struct us_data *us = host_to_us(sdev->host);
  
- /**
-- * scsi_device_lookup - find a device given the host (UNLOCKED)
-+ * __scsi_device_lookup - find a device given the host (UNLOCKED)
-  * @shost:	SCSI host pointer
-  * @channel:	SCSI channel (zero if only one channel)
-- * @pun:	SCSI target number (physical unit number)
-+ * @id:		SCSI target number (physical unit number)
-  * @lun:	SCSI Logical Unit Number
-  *
-- * Looks up the scsi_device with the specified @channel, @id, @lun for a
-- * give host. The returned scsi_device does not have an additional reference.
-- * You must hold the host's host_lock over this call and any access to the
-- * returned scsi_device.
-+ * Description: Looks up the scsi_device with the specified @channel, @id, @lun
-+ * for a given host. The returned scsi_device does not have an additional
-+ * reference.  You must hold the host's host_lock over this call and any access
-+ * to the returned scsi_device.
-  *
-  * Note:  The only reason why drivers would want to use this is because
-- * they're need to access the device list in irq context.  Otherwise you
-+ * they need to access the device list in irq context.  Otherwise you
-  * really want to use scsi_device_lookup instead.
-  **/
- struct scsi_device *__scsi_device_lookup(struct Scsi_Host *shost,
-@@ -1033,9 +1087,9 @@ EXPORT_SYMBOL(__scsi_device_lookup);
-  * @id:		SCSI target number (physical unit number)
-  * @lun:	SCSI Logical Unit Number
-  *
-- * Looks up the scsi_device with the specified @channel, @id, @lun for a
-- * give host.  The returned scsi_device has an additional reference that
-- * needs to be release with scsi_host_put once you're done with it.
-+ * Description: Looks up the scsi_device with the specified @channel, @id, @lun
-+ * for a given host.  The returned scsi_device has an additional reference that
-+ * needs to be released with scsi_device_put once you're done with it.
-  **/
- struct scsi_device *scsi_device_lookup(struct Scsi_Host *shost,
- 		uint channel, uint id, uint lun)
-diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
-index 46cae5a..82c06f0 100644
---- a/drivers/scsi/scsi_debug.c
-+++ b/drivers/scsi/scsi_debug.c
-@@ -329,7 +329,7 @@ int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done)
- 	if (done == NULL)
- 		return 0;	/* assume mid level reprocessing command */
+-	/* Scatter-gather buffers (all but the last) must have a length
+-	 * divisible by the bulk maxpacket size.  Otherwise a data packet
+-	 * would end up being short, causing a premature end to the data
+-	 * transfer.  Since high-speed bulk pipes have a maxpacket size
+-	 * of 512, we'll use that as the scsi device queue's DMA alignment
+-	 * mask.  Guaranteeing proper alignment of the first buffer will
+-	 * have the desired effect because, except at the beginning and
+-	 * the end, scatter-gather buffers follow page boundaries. */
+-	blk_queue_dma_alignment(sdev->request_queue, (512 - 1));
+-
+ 	/* Many devices have trouble transfering more than 32KB at a time,
+ 	 * while others have trouble with more than 64K. At this time we
+ 	 * are limiting both to 32K (64 sectores).
+@@ -187,6 +187,10 @@ static int slave_configure(struct scsi_device *sdev)
+ 		 * automatically, requiring a START-STOP UNIT command. */
+ 		sdev->allow_restart = 1;
  
--	SCpnt->resid = 0;
-+	scsi_set_resid(SCpnt, 0);
- 	if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmd) {
- 		printk(KERN_INFO "scsi_debug: cmd ");
- 		for (k = 0, len = SCpnt->cmd_len; k < len; ++k)
-@@ -603,26 +603,16 @@ static int fill_from_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr,
- 	void * kaddr_off;
- 	struct scatterlist * sg;
++		/* Some USB cardreaders have trouble reading an sdcard's last
++		 * sector in a larger then 1 sector read, since the performance
++		 * impact is negible we set this flag for all USB disks */
++		sdev->last_sector_bug = 1;
+ 	} else {
  
--	if (0 == scp->request_bufflen)
-+	if (0 == scsi_bufflen(scp))
- 		return 0;
--	if (NULL == scp->request_buffer)
-+	if (NULL == scsi_sglist(scp))
- 		return (DID_ERROR << 16);
- 	if (! ((scp->sc_data_direction == DMA_BIDIRECTIONAL) ||
- 	      (scp->sc_data_direction == DMA_FROM_DEVICE)))
- 		return (DID_ERROR << 16);
--	if (0 == scp->use_sg) {
--		req_len = scp->request_bufflen;
--		act_len = (req_len < arr_len) ? req_len : arr_len;
--		memcpy(scp->request_buffer, arr, act_len);
--		if (scp->resid)
--			scp->resid -= act_len;
--		else
--			scp->resid = req_len - act_len;
--		return 0;
--	}
- 	active = 1;
- 	req_len = act_len = 0;
--	scsi_for_each_sg(scp, sg, scp->use_sg, k) {
-+	scsi_for_each_sg(scp, sg, scsi_sg_count(scp), k) {
- 		if (active) {
- 			kaddr = (unsigned char *)
- 				kmap_atomic(sg_page(sg), KM_USER0);
-@@ -640,10 +630,10 @@ static int fill_from_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr,
- 		}
- 		req_len += sg->length;
+ 		/* Non-disk-type devices don't need to blacklist any pages
+diff --git a/drivers/usb/storage/sddr09.c b/drivers/usb/storage/sddr09.c
+index b12202c..8972b17 100644
+--- a/drivers/usb/storage/sddr09.c
++++ b/drivers/usb/storage/sddr09.c
+@@ -1623,7 +1623,7 @@ int sddr09_transport(struct scsi_cmnd *srb, struct us_data *us)
+ 		return USB_STOR_TRANSPORT_ERROR;
  	}
--	if (scp->resid)
--		scp->resid -= act_len;
-+	if (scsi_get_resid(scp))
-+		scsi_set_resid(scp, scsi_get_resid(scp) - act_len);
- 	else
--		scp->resid = req_len - act_len;
-+		scsi_set_resid(scp, req_len - act_len);
- 	return 0;
- }
- 
-@@ -656,22 +646,15 @@ static int fetch_to_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr,
- 	void * kaddr_off;
- 	struct scatterlist * sg;
- 
--	if (0 == scp->request_bufflen)
-+	if (0 == scsi_bufflen(scp))
- 		return 0;
--	if (NULL == scp->request_buffer)
-+	if (NULL == scsi_sglist(scp))
- 		return -1;
- 	if (! ((scp->sc_data_direction == DMA_BIDIRECTIONAL) ||
- 	      (scp->sc_data_direction == DMA_TO_DEVICE)))
- 		return -1;
--	if (0 == scp->use_sg) {
--		req_len = scp->request_bufflen;
--		len = (req_len < max_arr_len) ? req_len : max_arr_len;
--		memcpy(arr, scp->request_buffer, len);
--		return len;
--	}
--	sg = scsi_sglist(scp);
- 	req_len = fin = 0;
--	for (k = 0; k < scp->use_sg; ++k, sg = sg_next(sg)) {
-+	scsi_for_each_sg(scp, sg, scsi_sg_count(scp), k) {
- 		kaddr = (unsigned char *)kmap_atomic(sg_page(sg), KM_USER0);
- 		if (NULL == kaddr)
- 			return -1;
-diff --git a/drivers/scsi/scsi_devinfo.c b/drivers/scsi/scsi_devinfo.c
-index 348cc5a..b8de041 100644
---- a/drivers/scsi/scsi_devinfo.c
-+++ b/drivers/scsi/scsi_devinfo.c
-@@ -276,11 +276,12 @@ static void scsi_strcpy_devinfo(char *name, char *to, size_t to_length,
- }
  
- /**
-- * scsi_dev_info_list_add: add one dev_info list entry.
-+ * scsi_dev_info_list_add - add one dev_info list entry.
-+ * @compatible: if true, null terminate short strings.  Otherwise space pad.
-  * @vendor:	vendor string
-  * @model:	model (product) string
-  * @strflags:	integer string
-- * @flag:	if strflags NULL, use this flag value
-+ * @flags:	if strflags NULL, use this flag value
-  *
-  * Description:
-  * 	Create and add one dev_info entry for @vendor, @model, @strflags or
-@@ -322,8 +323,7 @@ static int scsi_dev_info_list_add(int compatible, char *vendor, char *model,
- }
+-	if (srb->request_bufflen == 0)
++	if (scsi_bufflen(srb) == 0)
+ 		return USB_STOR_TRANSPORT_GOOD;
  
- /**
-- * scsi_dev_info_list_add_str: parse dev_list and add to the
-- * scsi_dev_info_list.
-+ * scsi_dev_info_list_add_str - parse dev_list and add to the scsi_dev_info_list.
-  * @dev_list:	string of device flags to add
-  *
-  * Description:
-@@ -374,15 +374,15 @@ static int scsi_dev_info_list_add_str(char *dev_list)
- }
+ 	if (srb->sc_data_direction == DMA_TO_DEVICE ||
+@@ -1634,12 +1634,9 @@ int sddr09_transport(struct scsi_cmnd *srb, struct us_data *us)
+ 		US_DEBUGP("SDDR09: %s %d bytes\n",
+ 			  (srb->sc_data_direction == DMA_TO_DEVICE) ?
+ 			  "sending" : "receiving",
+-			  srb->request_bufflen);
++			  scsi_bufflen(srb));
  
- /**
-- * get_device_flags - get device specific flags from the dynamic device
-- * list. Called during scan time.
-+ * get_device_flags - get device specific flags from the dynamic device list.
-+ * @sdev:       &scsi_device to get flags for
-  * @vendor:	vendor name
-  * @model:	model name
-  *
-  * Description:
-  *     Search the scsi_dev_info_list for an entry matching @vendor and
-  *     @model, if found, return the matching flags value, else return
-- *     the host or global default settings.
-+ *     the host or global default settings.  Called during scan time.
-  **/
- int scsi_get_device_flags(struct scsi_device *sdev,
- 			  const unsigned char *vendor,
-@@ -483,13 +483,11 @@ stop_output:
- }
+-		result = usb_stor_bulk_transfer_sg(us, pipe,
+-					srb->request_buffer,
+-					srb->request_bufflen,
+-					srb->use_sg, &srb->resid);
++		result = usb_stor_bulk_srb(us, pipe, srb);
  
- /* 
-- * proc_scsi_dev_info_write: allow additions to the scsi_dev_info_list via
-- * /proc.
-+ * proc_scsi_dev_info_write - allow additions to scsi_dev_info_list via /proc.
-  *
-- * Use: echo "vendor:model:flag" > /proc/scsi/device_info
-- *
-- * To add a black/white list entry for vendor and model with an integer
-- * value of flag to the scsi device info list.
-+ * Description: Adds a black/white list entry for vendor and model with an
-+ * integer value of flag to the scsi device info list.
-+ * To use, echo "vendor:model:flag" > /proc/scsi/device_info
+ 		return (result == USB_STOR_XFER_GOOD ?
+ 			USB_STOR_TRANSPORT_GOOD : USB_STOR_TRANSPORT_ERROR);
+diff --git a/drivers/usb/storage/shuttle_usbat.c b/drivers/usb/storage/shuttle_usbat.c
+index cb22a9a..570c125 100644
+--- a/drivers/usb/storage/shuttle_usbat.c
++++ b/drivers/usb/storage/shuttle_usbat.c
+@@ -130,7 +130,7 @@ static int usbat_write(struct us_data *us,
+  * Convenience function to perform a bulk read
   */
- static int proc_scsi_devinfo_write(struct file *file, const char __user *buf,
- 				   unsigned long length, void *data)
-@@ -532,8 +530,7 @@ MODULE_PARM_DESC(default_dev_flags,
- 		 "scsi default device flag integer value");
- 
- /**
-- * scsi_dev_info_list_delete: called from scsi.c:exit_scsi to remove
-- * 	the scsi_dev_info_list.
-+ * scsi_dev_info_list_delete - called from scsi.c:exit_scsi to remove the scsi_dev_info_list.
-  **/
- void scsi_exit_devinfo(void)
+ static int usbat_bulk_read(struct us_data *us,
+-			   unsigned char *data,
++			   void* buf,
+ 			   unsigned int len,
+ 			   int use_sg)
  {
-@@ -552,13 +549,12 @@ void scsi_exit_devinfo(void)
+@@ -138,14 +138,14 @@ static int usbat_bulk_read(struct us_data *us,
+ 		return USB_STOR_XFER_GOOD;
+ 
+ 	US_DEBUGP("usbat_bulk_read: len = %d\n", len);
+-	return usb_stor_bulk_transfer_sg(us, us->recv_bulk_pipe, data, len, use_sg, NULL);
++	return usb_stor_bulk_transfer_sg(us, us->recv_bulk_pipe, buf, len, use_sg, NULL);
  }
  
- /**
-- * scsi_dev_list_init: set up the dynamic device list.
-- * @dev_list:	string of device flags to add
-+ * scsi_init_devinfo - set up the dynamic device list.
-  *
-  * Description:
-- * 	Add command line @dev_list entries, then add
-+ * 	Add command line entries from scsi_dev_flags, then add
-  * 	scsi_static_device_list entries to the scsi device info list.
-- **/
-+ */
- int __init scsi_init_devinfo(void)
- {
- #ifdef CONFIG_SCSI_PROC_FS
-diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
-index ebaca4c..547e85a 100644
---- a/drivers/scsi/scsi_error.c
-+++ b/drivers/scsi/scsi_error.c
-@@ -62,7 +62,7 @@ void scsi_eh_wakeup(struct Scsi_Host *shost)
-  * @shost:	SCSI host to invoke error handling on.
-  *
-  * Schedule SCSI EH without scmd.
-- **/
-+ */
- void scsi_schedule_eh(struct Scsi_Host *shost)
- {
- 	unsigned long flags;
-@@ -86,7 +86,7 @@ EXPORT_SYMBOL_GPL(scsi_schedule_eh);
-  *
-  * Return value:
-  *	0 on failure.
-- **/
-+ */
- int scsi_eh_scmd_add(struct scsi_cmnd *scmd, int eh_flag)
- {
- 	struct Scsi_Host *shost = scmd->device->host;
-@@ -121,7 +121,7 @@ int scsi_eh_scmd_add(struct scsi_cmnd *scmd, int eh_flag)
-  *    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 *))
- {
-@@ -155,7 +155,7 @@ void scsi_add_timer(struct scsi_cmnd *scmd, int timeout,
-  * 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;
-@@ -181,7 +181,7 @@ int scsi_delete_timer(struct scsi_cmnd *scmd)
-  *     only in that the normal completion handling might run, but if the
-  *     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 scsi_eh_timer_return (* eh_timed_out)(struct scsi_cmnd *);
-@@ -224,7 +224,7 @@ void scsi_times_out(struct scsi_cmnd *scmd)
-  *
-  * Return value:
-  *     0 when dev was taken offline by error recovery. 1 OK to proceed.
-- **/
-+ */
- int scsi_block_when_processing_errors(struct scsi_device *sdev)
- {
- 	int online;
-@@ -245,7 +245,7 @@ EXPORT_SYMBOL(scsi_block_when_processing_errors);
-  * scsi_eh_prt_fail_stats - Log info on failures.
-  * @shost:	scsi host being recovered.
-  * @work_q:	Queue of scsi cmds to process.
-- **/
-+ */
- static inline void scsi_eh_prt_fail_stats(struct Scsi_Host *shost,
- 					  struct list_head *work_q)
- {
-@@ -295,7 +295,7 @@ static inline void scsi_eh_prt_fail_stats(struct Scsi_Host *shost,
-  * Notes:
-  *	When a deferred error is detected the current command has
-  *	not been executed and needs retrying.
-- **/
-+ */
- static int scsi_check_sense(struct scsi_cmnd *scmd)
- {
- 	struct scsi_sense_hdr sshdr;
-@@ -398,7 +398,7 @@ static int scsi_check_sense(struct scsi_cmnd *scmd)
-  *    queued during error recovery.  the main difference here is that we
-  *    don't allow for the possibility of retries here, and we are a lot
-  *    more restrictive about what we consider acceptable.
-- **/
-+ */
- static int scsi_eh_completed_normally(struct scsi_cmnd *scmd)
- {
- 	/*
-@@ -452,7 +452,7 @@ static int scsi_eh_completed_normally(struct scsi_cmnd *scmd)
- /**
-  * scsi_eh_done - Completion function for error handling.
-  * @scmd:	Cmd that is done.
-- **/
-+ */
- static void scsi_eh_done(struct scsi_cmnd *scmd)
- {
- 	struct completion     *eh_action;
-@@ -469,7 +469,7 @@ static void scsi_eh_done(struct scsi_cmnd *scmd)
- /**
-  * scsi_try_host_reset - ask host adapter to reset itself
-  * @scmd:	SCSI cmd to send hsot reset.
-- **/
-+ */
- static int scsi_try_host_reset(struct scsi_cmnd *scmd)
- {
- 	unsigned long flags;
-@@ -498,7 +498,7 @@ static int scsi_try_host_reset(struct scsi_cmnd *scmd)
- /**
-  * scsi_try_bus_reset - ask host to perform a bus reset
-  * @scmd:	SCSI cmd to send bus reset.
-- **/
-+ */
- static int scsi_try_bus_reset(struct scsi_cmnd *scmd)
- {
- 	unsigned long flags;
-@@ -533,7 +533,7 @@ static int scsi_try_bus_reset(struct scsi_cmnd *scmd)
-  *    unreliable for a given host, then the host itself needs to put a
-  *    timer on it, and set the host back to a consistent state prior to
-  *    returning.
-- **/
-+ */
- static int scsi_try_bus_device_reset(struct scsi_cmnd *scmd)
- {
- 	int rtn;
-@@ -568,7 +568,7 @@ static int __scsi_try_to_abort_cmd(struct scsi_cmnd *scmd)
-  *    author of the low-level driver wishes this operation to be timed,
-  *    they can provide this facility themselves.  helper functions in
-  *    scsi_error.c can be supplied to make this easier to do.
-- **/
-+ */
- static int scsi_try_to_abort_cmd(struct scsi_cmnd *scmd)
- {
- 	/*
-@@ -601,7 +601,7 @@ static void scsi_abort_eh_cmnd(struct scsi_cmnd *scmd)
-  * sent must be one that does not transfer any data.  If @sense_bytes != 0
-  * @cmnd is ignored and this functions sets up a REQUEST_SENSE command
-  * and cmnd buffers to read @sense_bytes into @scmd->sense_buffer.
-- **/
-+ */
- void scsi_eh_prep_cmnd(struct scsi_cmnd *scmd, struct scsi_eh_save *ses,
- 			unsigned char *cmnd, int cmnd_size, unsigned sense_bytes)
+ /*
+  * Convenience function to perform a bulk write
+  */
+ static int usbat_bulk_write(struct us_data *us,
+-			    unsigned char *data,
++			    void* buf,
+ 			    unsigned int len,
+ 			    int use_sg)
  {
-@@ -625,7 +625,7 @@ void scsi_eh_prep_cmnd(struct scsi_cmnd *scmd, struct scsi_eh_save *ses,
+@@ -153,7 +153,7 @@ static int usbat_bulk_write(struct us_data *us,
+ 		return USB_STOR_XFER_GOOD;
  
- 	if (sense_bytes) {
- 		scmd->request_bufflen = min_t(unsigned,
--		                       sizeof(scmd->sense_buffer), sense_bytes);
-+		                       SCSI_SENSE_BUFFERSIZE, sense_bytes);
- 		sg_init_one(&ses->sense_sgl, scmd->sense_buffer,
- 		                                       scmd->request_bufflen);
- 		scmd->request_buffer = &ses->sense_sgl;
-@@ -657,7 +657,7 @@ void scsi_eh_prep_cmnd(struct scsi_cmnd *scmd, struct scsi_eh_save *ses,
- 	 * Zero the sense buffer.  The scsi spec mandates that any
- 	 * untransferred sense data should be interpreted as being zero.
- 	 */
--	memset(scmd->sense_buffer, 0, sizeof(scmd->sense_buffer));
-+	memset(scmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
+ 	US_DEBUGP("usbat_bulk_write:  len = %d\n", len);
+-	return usb_stor_bulk_transfer_sg(us, us->send_bulk_pipe, data, len, use_sg, NULL);
++	return usb_stor_bulk_transfer_sg(us, us->send_bulk_pipe, buf, len, use_sg, NULL);
  }
- EXPORT_SYMBOL(scsi_eh_prep_cmnd);
  
-@@ -667,7 +667,7 @@ EXPORT_SYMBOL(scsi_eh_prep_cmnd);
-  * @ses:        saved information from a coresponding call to scsi_prep_eh_cmnd
-  *
-  * Undo any damage done by above scsi_prep_eh_cmnd().
-- **/
-+ */
- void scsi_eh_restore_cmnd(struct scsi_cmnd* scmd, struct scsi_eh_save *ses)
- {
- 	/*
-@@ -697,7 +697,7 @@ EXPORT_SYMBOL(scsi_eh_restore_cmnd);
-  *
-  * Return value:
-  *    SUCCESS or FAILED or NEEDS_RETRY
-- **/
-+ */
- static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, unsigned char *cmnd,
- 			     int cmnd_size, int timeout, unsigned sense_bytes)
- {
-@@ -765,7 +765,7 @@ static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, unsigned char *cmnd,
-  *    Some hosts automatically obtain this information, others require
-  *    that we obtain it on our own. This function will *not* return until
-  *    the command either times out, or it completes.
-- **/
-+ */
- static int scsi_request_sense(struct scsi_cmnd *scmd)
- {
- 	return scsi_send_eh_cmnd(scmd, NULL, 0, SENSE_TIMEOUT, ~0);
-@@ -779,10 +779,10 @@ static int scsi_request_sense(struct scsi_cmnd *scmd)
-  * Notes:
-  *    We don't want to use the normal command completion while we are are
-  *    still handling errors - it may cause other commands to be queued,
-- *    and that would disturb what we are doing.  thus we really want to
-+ *    and that would disturb what we are doing.  Thus we really want to
-  *    keep a list of pending commands for final completion, and once we
-  *    are ready to leave error handling we handle completion for real.
-- **/
-+ */
- void scsi_eh_finish_cmd(struct scsi_cmnd *scmd, struct list_head *done_q)
- {
- 	scmd->device->host->host_failed--;
-@@ -794,7 +794,7 @@ EXPORT_SYMBOL(scsi_eh_finish_cmd);
- /**
-  * scsi_eh_get_sense - Get device sense data.
-  * @work_q:	Queue of commands to process.
-- * @done_q:	Queue of proccessed commands..
-+ * @done_q:	Queue of processed commands.
-  *
-  * Description:
-  *    See if we need to request sense information.  if so, then get it
-@@ -802,7 +802,7 @@ EXPORT_SYMBOL(scsi_eh_finish_cmd);
-  *
-  * Notes:
-  *    This has the unfortunate side effect that if a shost adapter does
-- *    not automatically request sense information, that we end up shutting
-+ *    not automatically request sense information, we end up shutting
-  *    it down before we request it.
-  *
-  *    All drivers should request sense information internally these days,
-@@ -810,7 +810,7 @@ EXPORT_SYMBOL(scsi_eh_finish_cmd);
-  *
-  *    XXX: Long term this code should go away, but that needs an audit of
-  *         all LLDDs first.
-- **/
-+ */
- int scsi_eh_get_sense(struct list_head *work_q,
- 		      struct list_head *done_q)
+ /*
+@@ -314,7 +314,7 @@ static int usbat_wait_not_busy(struct us_data *us, int minutes)
+  * Read block data from the data register
+  */
+ static int usbat_read_block(struct us_data *us,
+-			    unsigned char *content,
++			    void* buf,
+ 			    unsigned short len,
+ 			    int use_sg)
  {
-@@ -858,11 +858,11 @@ EXPORT_SYMBOL_GPL(scsi_eh_get_sense);
+@@ -337,7 +337,7 @@ static int usbat_read_block(struct us_data *us,
+ 	if (result != USB_STOR_XFER_GOOD)
+ 		return USB_STOR_TRANSPORT_ERROR;
  
- /**
-  * scsi_eh_tur - Send TUR to device.
-- * @scmd:	Scsi cmd to send TUR
-+ * @scmd:	&scsi_cmnd to send TUR
-  *
-  * Return value:
-  *    0 - Device is ready. 1 - Device NOT ready.
-- **/
-+ */
- static int scsi_eh_tur(struct scsi_cmnd *scmd)
- {
- 	static unsigned char tur_command[6] = {TEST_UNIT_READY, 0, 0, 0, 0, 0};
-@@ -887,17 +887,17 @@ retry_tur:
+-	result = usbat_bulk_read(us, content, len, use_sg);
++	result = usbat_bulk_read(us, buf, len, use_sg);
+ 	return (result == USB_STOR_XFER_GOOD ?
+ 			USB_STOR_TRANSPORT_GOOD : USB_STOR_TRANSPORT_ERROR);
  }
+@@ -347,7 +347,7 @@ static int usbat_read_block(struct us_data *us,
+  */
+ static int usbat_write_block(struct us_data *us,
+ 			     unsigned char access,
+-			     unsigned char *content,
++			     void* buf,
+ 			     unsigned short len,
+ 			     int minutes,
+ 			     int use_sg)
+@@ -372,7 +372,7 @@ static int usbat_write_block(struct us_data *us,
+ 	if (result != USB_STOR_XFER_GOOD)
+ 		return USB_STOR_TRANSPORT_ERROR;
  
- /**
-- * scsi_eh_abort_cmds - abort canceled commands.
-- * @shost:	scsi host being recovered.
-- * @eh_done_q:	list_head for processed commands.
-+ * scsi_eh_abort_cmds - abort pending commands.
-+ * @work_q:	&list_head for pending commands.
-+ * @done_q:	&list_head for processed commands.
-  *
-  * Decription:
-  *    Try and see whether or not it makes sense to try and abort the
-- *    running command.  this only works out to be the case if we have one
-- *    command that has timed out.  if the command simply failed, it makes
-+ *    running command.  This only works out to be the case if we have one
-+ *    command that has timed out.  If the command simply failed, it makes
-  *    no sense to try and abort the command, since as far as the shost
-  *    adapter is concerned, it isn't running.
-- **/
-+ */
- static int scsi_eh_abort_cmds(struct list_head *work_q,
- 			      struct list_head *done_q)
- {
-@@ -931,11 +931,11 @@ static int scsi_eh_abort_cmds(struct list_head *work_q,
+-	result = usbat_bulk_write(us, content, len, use_sg);
++	result = usbat_bulk_write(us, buf, len, use_sg);
+ 	if (result != USB_STOR_XFER_GOOD)
+ 		return USB_STOR_TRANSPORT_ERROR;
  
- /**
-  * scsi_eh_try_stu - Send START_UNIT to device.
-- * @scmd:	Scsi cmd to send START_UNIT
-+ * @scmd:	&scsi_cmnd to send START_UNIT
-  *
-  * Return value:
-  *    0 - Device is ready. 1 - Device NOT ready.
-- **/
-+ */
- static int scsi_eh_try_stu(struct scsi_cmnd *scmd)
- {
- 	static unsigned char stu_command[6] = {START_STOP, 0, 0, 0, 1, 0};
-@@ -956,13 +956,14 @@ static int scsi_eh_try_stu(struct scsi_cmnd *scmd)
+@@ -392,7 +392,7 @@ static int usbat_hp8200e_rw_block_test(struct us_data *us,
+ 				       unsigned char timeout,
+ 				       unsigned char qualifier,
+ 				       int direction,
+-				       unsigned char *content,
++				       void *buf,
+ 				       unsigned short len,
+ 				       int use_sg,
+ 				       int minutes)
+@@ -472,7 +472,7 @@ static int usbat_hp8200e_rw_block_test(struct us_data *us,
+ 		}
  
-  /**
-  * scsi_eh_stu - send START_UNIT if needed
-- * @shost:	scsi host being recovered.
-- * @eh_done_q:	list_head for processed commands.
-+ * @shost:	&scsi host being recovered.
-+ * @work_q:     &list_head for pending commands.
-+ * @done_q:	&list_head for processed commands.
-  *
-  * Notes:
-  *    If commands are failing due to not ready, initializing command required,
-  *	try revalidating the device, which will end up sending a start unit. 
-- **/
-+ */
- static int scsi_eh_stu(struct Scsi_Host *shost,
- 			      struct list_head *work_q,
- 			      struct list_head *done_q)
-@@ -1008,14 +1009,15 @@ static int scsi_eh_stu(struct Scsi_Host *shost,
- /**
-  * scsi_eh_bus_device_reset - send bdr if needed
-  * @shost:	scsi host being recovered.
-- * @eh_done_q:	list_head for processed commands.
-+ * @work_q:     &list_head for pending commands.
-+ * @done_q:	&list_head for processed commands.
-  *
-  * Notes:
-- *    Try a bus device reset.  still, look to see whether we have multiple
-+ *    Try a bus device reset.  Still, look to see whether we have multiple
-  *    devices that are jammed or not - if we have multiple devices, it
-  *    makes no sense to try bus_device_reset - we really would need to try
-  *    a bus_reset instead. 
-- **/
-+ */
- static int scsi_eh_bus_device_reset(struct Scsi_Host *shost,
- 				    struct list_head *work_q,
- 				    struct list_head *done_q)
-@@ -1063,9 +1065,10 @@ static int scsi_eh_bus_device_reset(struct Scsi_Host *shost,
+ 		result = usb_stor_bulk_transfer_sg(us,
+-			pipe, content, len, use_sg, NULL);
++			pipe, buf, len, use_sg, NULL);
  
- /**
-  * scsi_eh_bus_reset - send a bus reset 
-- * @shost:	scsi host being recovered.
-- * @eh_done_q:	list_head for processed commands.
-- **/
-+ * @shost:	&scsi host being recovered.
-+ * @work_q:     &list_head for pending commands.
-+ * @done_q:	&list_head for processed commands.
-+ */
- static int scsi_eh_bus_reset(struct Scsi_Host *shost,
- 			     struct list_head *work_q,
- 			     struct list_head *done_q)
-@@ -1122,7 +1125,7 @@ static int scsi_eh_bus_reset(struct Scsi_Host *shost,
-  * scsi_eh_host_reset - send a host reset 
-  * @work_q:	list_head for processed commands.
-  * @done_q:	list_head for processed commands.
-- **/
-+ */
- static int scsi_eh_host_reset(struct list_head *work_q,
- 			      struct list_head *done_q)
- {
-@@ -1157,8 +1160,7 @@ static int scsi_eh_host_reset(struct list_head *work_q,
-  * scsi_eh_offline_sdevs - offline scsi devices that fail to recover
-  * @work_q:	list_head for processed commands.
-  * @done_q:	list_head for processed commands.
-- *
-- **/
-+ */
- static void scsi_eh_offline_sdevs(struct list_head *work_q,
- 				  struct list_head *done_q)
- {
-@@ -1191,7 +1193,7 @@ static void scsi_eh_offline_sdevs(struct list_head *work_q,
-  *    is woken.  In cases where the error code indicates an error that
-  *    doesn't require the error handler read (i.e. we don't need to
-  *    abort/reset), this function should return SUCCESS.
-- **/
-+ */
- int scsi_decide_disposition(struct scsi_cmnd *scmd)
- {
- 	int rtn;
-@@ -1372,7 +1374,7 @@ int scsi_decide_disposition(struct scsi_cmnd *scmd)
-  *
-  *	If scsi_allocate_request() fails for what ever reason, we
-  *	completely forget to lock the door.
-- **/
-+ */
- static void scsi_eh_lock_door(struct scsi_device *sdev)
- {
- 	unsigned char cmnd[MAX_COMMAND_SIZE];
-@@ -1396,7 +1398,7 @@ static void scsi_eh_lock_door(struct scsi_device *sdev)
-  * Notes:
-  *    When we entered the error handler, we blocked all further i/o to
-  *    this device.  we need to 'reverse' this process.
-- **/
-+ */
- static void scsi_restart_operations(struct Scsi_Host *shost)
- {
- 	struct scsi_device *sdev;
-@@ -1440,9 +1442,9 @@ static void scsi_restart_operations(struct Scsi_Host *shost)
- /**
-  * scsi_eh_ready_devs - check device ready state and recover if not.
-  * @shost: 	host to be recovered.
-- * @eh_done_q:	list_head for processed commands.
-- *
-- **/
-+ * @work_q:     &list_head for pending commands.
-+ * @done_q:	&list_head for processed commands.
-+ */
- void scsi_eh_ready_devs(struct Scsi_Host *shost,
- 			struct list_head *work_q,
- 			struct list_head *done_q)
-@@ -1458,8 +1460,7 @@ EXPORT_SYMBOL_GPL(scsi_eh_ready_devs);
- /**
-  * scsi_eh_flush_done_q - finish processed commands or retry them.
-  * @done_q:	list_head of processed commands.
-- *
-- **/
-+ */
- void scsi_eh_flush_done_q(struct list_head *done_q)
- {
- 	struct scsi_cmnd *scmd, *next;
-@@ -1513,7 +1514,7 @@ EXPORT_SYMBOL(scsi_eh_flush_done_q);
-  *    scsi_finish_cmd() called for it.  we do all of the retry stuff
-  *    here, so when we restart the host after we return it should have an
-  *    empty queue.
-- **/
-+ */
- static void scsi_unjam_host(struct Scsi_Host *shost)
- {
- 	unsigned long flags;
-@@ -1540,7 +1541,7 @@ static void scsi_unjam_host(struct Scsi_Host *shost)
-  * Notes:
-  *    This is the main error handling loop.  This is run as a kernel thread
-  *    for every SCSI host and handles all error handling activity.
-- **/
-+ */
- int scsi_error_handler(void *data)
- {
- 	struct Scsi_Host *shost = data;
-@@ -1769,7 +1770,7 @@ EXPORT_SYMBOL(scsi_reset_provider);
-  *
-  * Return value:
-  *	1 if valid sense data information found, else 0;
-- **/
-+ */
- int scsi_normalize_sense(const u8 *sense_buffer, int sb_len,
-                          struct scsi_sense_hdr *sshdr)
+ 		/*
+ 		 * If we get a stall on the bulk download, we'll retry
+@@ -606,7 +606,7 @@ static int usbat_multiple_write(struct us_data *us,
+  * other related details) are defined beforehand with _set_shuttle_features().
+  */
+ static int usbat_read_blocks(struct us_data *us,
+-			     unsigned char *buffer,
++			     void* buffer,
+ 			     int len,
+ 			     int use_sg)
  {
-@@ -1819,14 +1820,12 @@ int scsi_command_normalize_sense(struct scsi_cmnd *cmd,
- 				 struct scsi_sense_hdr *sshdr)
+@@ -648,7 +648,7 @@ static int usbat_read_blocks(struct us_data *us,
+  * other related details) are defined beforehand with _set_shuttle_features().
+  */
+ static int usbat_write_blocks(struct us_data *us,
+-							  unsigned char *buffer,
++			      void* buffer,
+ 			      int len,
+ 			      int use_sg)
  {
- 	return scsi_normalize_sense(cmd->sense_buffer,
--			sizeof(cmd->sense_buffer), sshdr);
-+			SCSI_SENSE_BUFFERSIZE, sshdr);
- }
- EXPORT_SYMBOL(scsi_command_normalize_sense);
+@@ -1170,15 +1170,15 @@ static int usbat_hp8200e_handle_read10(struct us_data *us,
+ 	US_DEBUGP("handle_read10: transfersize %d\n",
+ 		srb->transfersize);
  
- /**
-- * scsi_sense_desc_find - search for a given descriptor type in
-- *			descriptor sense data format.
-- *
-+ * scsi_sense_desc_find - search for a given descriptor type in	descriptor sense data format.
-  * @sense_buffer:	byte array of descriptor format sense data
-  * @sb_len:		number of valid bytes in sense_buffer
-  * @desc_type:		value of descriptor type to find
-@@ -1837,7 +1836,7 @@ EXPORT_SYMBOL(scsi_command_normalize_sense);
-  *
-  * Return value:
-  *	pointer to start of (first) descriptor if found else NULL
-- **/
-+ */
- const u8 * scsi_sense_desc_find(const u8 * sense_buffer, int sb_len,
- 				int desc_type)
- {
-@@ -1865,9 +1864,7 @@ const u8 * scsi_sense_desc_find(const u8 * sense_buffer, int sb_len,
- EXPORT_SYMBOL(scsi_sense_desc_find);
+-	if (srb->request_bufflen < 0x10000) {
++	if (scsi_bufflen(srb) < 0x10000) {
  
- /**
-- * scsi_get_sense_info_fld - attempts to get information field from
-- *			sense data (either fixed or descriptor format)
-- *
-+ * scsi_get_sense_info_fld - get information field from sense data (either fixed or descriptor format)
-  * @sense_buffer:	byte array of sense data
-  * @sb_len:		number of valid bytes in sense_buffer
-  * @info_out:		pointer to 64 integer where 8 or 4 byte information
-@@ -1875,7 +1872,7 @@ EXPORT_SYMBOL(scsi_sense_desc_find);
-  *
-  * Return value:
-  *	1 if information field found, 0 if not found.
-- **/
-+ */
- int scsi_get_sense_info_fld(const u8 * sense_buffer, int sb_len,
- 			    u64 * info_out)
- {
-diff --git a/drivers/scsi/scsi_ioctl.c b/drivers/scsi/scsi_ioctl.c
-index 32293f4..28b19ef 100644
---- a/drivers/scsi/scsi_ioctl.c
-+++ b/drivers/scsi/scsi_ioctl.c
-@@ -174,10 +174,15 @@ static int scsi_ioctl_get_pci(struct scsi_device *sdev, void __user *arg)
- }
+ 		result = usbat_hp8200e_rw_block_test(us, USBAT_ATA, 
+ 			registers, data, 19,
+ 			USBAT_ATA_DATA, USBAT_ATA_STATUS, 0xFD,
+ 			(USBAT_QUAL_FCQ | USBAT_QUAL_ALQ),
+ 			DMA_FROM_DEVICE,
+-			srb->request_buffer, 
+-			srb->request_bufflen, srb->use_sg, 1);
++			scsi_sglist(srb),
++			scsi_bufflen(srb), scsi_sg_count(srb), 1);
  
+ 		return result;
+ 	}
+@@ -1196,7 +1196,7 @@ static int usbat_hp8200e_handle_read10(struct us_data *us,
+ 		len <<= 16;
+ 		len |= data[7+7];
+ 		US_DEBUGP("handle_read10: GPCMD_READ_CD: len %d\n", len);
+-		srb->transfersize = srb->request_bufflen/len;
++		srb->transfersize = scsi_bufflen(srb)/len;
+ 	}
  
--/*
-- * the scsi_ioctl() function differs from most ioctls in that it does
-- * not take a major/minor number as the dev field.  Rather, it takes
-- * a pointer to a scsi_devices[] element, a structure. 
-+/**
-+ * scsi_ioctl - Dispatch ioctl to scsi device
-+ * @sdev: scsi device receiving ioctl
-+ * @cmd: which ioctl is it
-+ * @arg: data associated with ioctl
-+ *
-+ * Description: The scsi_ioctl() function differs from most ioctls in that it
-+ * does not take a major/minor number as the dev field.  Rather, it takes
-+ * a pointer to a &struct scsi_device.
-  */
- int scsi_ioctl(struct scsi_device *sdev, int cmd, void __user *arg)
- {
-@@ -239,7 +244,7 @@ int scsi_ioctl(struct scsi_device *sdev, int cmd, void __user *arg)
- 		return scsi_set_medium_removal(sdev, SCSI_REMOVAL_ALLOW);
- 	case SCSI_IOCTL_TEST_UNIT_READY:
- 		return scsi_test_unit_ready(sdev, IOCTL_NORMAL_TIMEOUT,
--					    NORMAL_RETRIES);
-+					    NORMAL_RETRIES, NULL);
- 	case SCSI_IOCTL_START_UNIT:
- 		scsi_cmd[0] = START_STOP;
- 		scsi_cmd[1] = 0;
-@@ -264,9 +269,12 @@ int scsi_ioctl(struct scsi_device *sdev, int cmd, void __user *arg)
- }
- EXPORT_SYMBOL(scsi_ioctl);
+ 	if (!srb->transfersize)  {
+@@ -1213,7 +1213,7 @@ static int usbat_hp8200e_handle_read10(struct us_data *us,
  
--/*
-- * the scsi_nonblock_ioctl() function is designed for ioctls which may
-- * be executed even if the device is in recovery.
-+/**
-+ * scsi_nonblock_ioctl() - Handle SG_SCSI_RESET
-+ * @sdev: scsi device receiving ioctl
-+ * @cmd: Must be SC_SCSI_RESET
-+ * @arg: pointer to int containing SG_SCSI_RESET_{DEVICE,BUS,HOST}
-+ * @filp: either NULL or a &struct file which must have the O_NONBLOCK flag.
-  */
- int scsi_nonblockable_ioctl(struct scsi_device *sdev, int cmd,
- 			    void __user *arg, struct file *filp)
-@@ -276,7 +284,7 @@ int scsi_nonblockable_ioctl(struct scsi_device *sdev, int cmd,
- 	/* The first set of iocts may be executed even if we're doing
- 	 * error processing, as long as the device was opened
- 	 * non-blocking */
--	if (filp && filp->f_flags & O_NONBLOCK) {
-+	if (filp && (filp->f_flags & O_NONBLOCK)) {
- 		if (scsi_host_in_recovery(sdev->host))
- 			return -ENODEV;
- 	} else if (!scsi_block_when_processing_errors(sdev))
-diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
-index a9ac5b1..4cf902e 100644
---- a/drivers/scsi/scsi_lib.c
-+++ b/drivers/scsi/scsi_lib.c
-@@ -175,7 +175,7 @@ int scsi_queue_insert(struct scsi_cmnd *cmd, int reason)
-  *
-  * returns the req->errors value which is the scsi_cmnd result
-  * field.
-- **/
-+ */
- int scsi_execute(struct scsi_device *sdev, const unsigned char *cmd,
- 		 int data_direction, void *buffer, unsigned bufflen,
- 		 unsigned char *sense, int timeout, int retries, int flags)
-@@ -274,7 +274,7 @@ static void scsi_bi_endio(struct bio *bio, int error)
- /**
-  * scsi_req_map_sg - map a scatterlist into a request
-  * @rq:		request to fill
-- * @sg:		scatterlist
-+ * @sgl:	scatterlist
-  * @nsegs:	number of elements
-  * @bufflen:	len of buffer
-  * @gfp:	memory allocation flags
-@@ -365,14 +365,16 @@ free_bios:
-  * @sdev:	scsi device
-  * @cmd:	scsi command
-  * @cmd_len:	length of scsi cdb
-- * @data_direction: data direction
-+ * @data_direction: DMA_TO_DEVICE, DMA_FROM_DEVICE, or DMA_NONE
-  * @buffer:	data buffer (this can be a kernel buffer or scatterlist)
-  * @bufflen:	len of buffer
-  * @use_sg:	if buffer is a scatterlist this is the number of elements
-  * @timeout:	request timeout in seconds
-  * @retries:	number of times to retry request
-- * @flags:	or into request flags
-- **/
-+ * @privdata:	data passed to done()
-+ * @done:	callback function when done
-+ * @gfp:	memory allocation flags
-+ */
- int scsi_execute_async(struct scsi_device *sdev, const unsigned char *cmd,
- 		       int cmd_len, int data_direction, void *buffer, unsigned bufflen,
- 		       int use_sg, int timeout, int retries, void *privdata,
-@@ -439,7 +441,7 @@ static void scsi_init_cmd_errh(struct scsi_cmnd *cmd)
- {
- 	cmd->serial_number = 0;
- 	cmd->resid = 0;
--	memset(cmd->sense_buffer, 0, sizeof cmd->sense_buffer);
-+	memset(cmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
- 	if (cmd->cmd_len == 0)
- 		cmd->cmd_len = COMMAND_SIZE(cmd->cmnd[0]);
- }
-@@ -524,7 +526,7 @@ static void scsi_run_queue(struct request_queue *q)
- 	struct Scsi_Host *shost = sdev->host;
- 	unsigned long flags;
+ 	len = (65535/srb->transfersize) * srb->transfersize;
+ 	US_DEBUGP("Max read is %d bytes\n", len);
+-	len = min(len, srb->request_bufflen);
++	len = min(len, scsi_bufflen(srb));
+ 	buffer = kmalloc(len, GFP_NOIO);
+ 	if (buffer == NULL) /* bloody hell! */
+ 		return USB_STOR_TRANSPORT_FAILED;
+@@ -1222,10 +1222,10 @@ static int usbat_hp8200e_handle_read10(struct us_data *us,
+ 	sector |= short_pack(data[7+5], data[7+4]);
+ 	transferred = 0;
+ 
+-	while (transferred != srb->request_bufflen) {
++	while (transferred != scsi_bufflen(srb)) {
+ 
+-		if (len > srb->request_bufflen - transferred)
+-			len = srb->request_bufflen - transferred;
++		if (len > scsi_bufflen(srb) - transferred)
++			len = scsi_bufflen(srb) - transferred;
  
--	if (sdev->single_lun)
-+	if (scsi_target(sdev)->single_lun)
- 		scsi_single_lun_run(sdev);
+ 		data[3] = len&0xFF; 	  /* (cylL) = expected length (L) */
+ 		data[4] = (len>>8)&0xFF;  /* (cylH) = expected length (H) */
+@@ -1261,7 +1261,7 @@ static int usbat_hp8200e_handle_read10(struct us_data *us,
+ 		transferred += len;
+ 		sector += len / srb->transfersize;
  
- 	spin_lock_irqsave(shost->host_lock, flags);
-@@ -1102,7 +1104,6 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
-  *
-  * Returns:     0 on success
-  *		BLKPREP_DEFER if the failure is retryable
-- *		BLKPREP_KILL if the failure is fatal
-  */
- static int scsi_init_io(struct scsi_cmnd *cmd)
- {
-@@ -1136,17 +1137,9 @@ static int scsi_init_io(struct scsi_cmnd *cmd)
- 	 * each segment.
- 	 */
- 	count = blk_rq_map_sg(req->q, req, cmd->request_buffer);
--	if (likely(count <= cmd->use_sg)) {
--		cmd->use_sg = count;
--		return BLKPREP_OK;
--	}
+-	} /* while transferred != srb->request_bufflen */
++	} /* while transferred != scsi_bufflen(srb) */
+ 
+ 	kfree(buffer);
+ 	return result;
+@@ -1429,9 +1429,8 @@ static int usbat_hp8200e_transport(struct scsi_cmnd *srb, struct us_data *us)
+ 	unsigned char data[32];
+ 	unsigned int len;
+ 	int i;
+-	char string[64];
+ 
+-	len = srb->request_bufflen;
++	len = scsi_bufflen(srb);
+ 
+ 	/* Send A0 (ATA PACKET COMMAND).
+ 	   Note: I guess we're never going to get any of the ATA
+@@ -1472,8 +1471,8 @@ static int usbat_hp8200e_transport(struct scsi_cmnd *srb, struct us_data *us)
+ 			USBAT_ATA_DATA, USBAT_ATA_STATUS, 0xFD,
+ 			(USBAT_QUAL_FCQ | USBAT_QUAL_ALQ),
+ 			DMA_TO_DEVICE,
+-			srb->request_buffer, 
+-			len, srb->use_sg, 10);
++			scsi_sglist(srb),
++			len, scsi_sg_count(srb), 10);
+ 
+ 		if (result == USB_STOR_TRANSPORT_GOOD) {
+ 			transferred += len;
+@@ -1540,23 +1539,8 @@ static int usbat_hp8200e_transport(struct scsi_cmnd *srb, struct us_data *us)
+ 			len = *status;
+ 
+ 
+-		result = usbat_read_block(us, srb->request_buffer, len, srb->use_sg);
 -
--	printk(KERN_ERR "Incorrect number of segments after building list\n");
--	printk(KERN_ERR "counted %d, received %d\n", count, cmd->use_sg);
--	printk(KERN_ERR "req nr_sec %lu, cur_nr_sec %u\n", req->nr_sectors,
--			req->current_nr_sectors);
+-		/* Debug-print the first 32 bytes of the transfer */
 -
--	return BLKPREP_KILL;
-+	BUG_ON(count > cmd->use_sg);
-+	cmd->use_sg = count;
-+	return BLKPREP_OK;
- }
- 
- static struct scsi_cmnd *scsi_get_cmd_from_req(struct scsi_device *sdev,
-@@ -1557,7 +1550,7 @@ static void scsi_request_fn(struct request_queue *q)
+-		if (!srb->use_sg) {
+-			string[0] = 0;
+-			for (i=0; i<len && i<32; i++) {
+-				sprintf(string+strlen(string), "%02X ",
+-				  ((unsigned char *)srb->request_buffer)[i]);
+-				if ((i%16)==15) {
+-					US_DEBUGP("%s\n", string);
+-					string[0] = 0;
+-				}
+-			}
+-			if (string[0]!=0)
+-				US_DEBUGP("%s\n", string);
+-		}
++		result = usbat_read_block(us, scsi_sglist(srb), len,
++			                                   scsi_sg_count(srb));
+ 	}
  
- 		if (!scsi_host_queue_ready(q, shost, sdev))
- 			goto not_ready;
--		if (sdev->single_lun) {
-+		if (scsi_target(sdev)->single_lun) {
- 			if (scsi_target(sdev)->starget_sdev_user &&
- 			    scsi_target(sdev)->starget_sdev_user != sdev)
- 				goto not_ready;
-@@ -1675,6 +1668,14 @@ struct request_queue *__scsi_alloc_queue(struct Scsi_Host *shost,
+ 	return result;
+diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c
+index c646750..d9f4912 100644
+--- a/drivers/usb/storage/transport.c
++++ b/drivers/usb/storage/transport.c
+@@ -459,6 +459,22 @@ static int usb_stor_bulk_transfer_sglist(struct us_data *us, unsigned int pipe,
+ }
  
- 	if (!shost->use_clustering)
- 		clear_bit(QUEUE_FLAG_CLUSTER, &q->queue_flags);
+ /*
++ * Common used function. Transfer a complete command
++ * via usb_stor_bulk_transfer_sglist() above. Set cmnd resid
++ */
++int usb_stor_bulk_srb(struct us_data* us, unsigned int pipe,
++		      struct scsi_cmnd* srb)
++{
++	unsigned int partial;
++	int result = usb_stor_bulk_transfer_sglist(us, pipe, scsi_sglist(srb),
++				      scsi_sg_count(srb), scsi_bufflen(srb),
++				      &partial);
 +
-+	/*
-+	 * set a reasonable default alignment on word boundaries: the
-+	 * host and device may alter it using
-+	 * blk_queue_update_dma_alignment() later.
-+	 */
-+	blk_queue_dma_alignment(q, 0x03);
++	scsi_set_resid(srb, scsi_bufflen(srb) - partial);
++	return result;
++}
 +
- 	return q;
- }
- EXPORT_SYMBOL(__scsi_alloc_queue);
-@@ -1804,7 +1805,7 @@ void scsi_exit_queue(void)
-  *	@timeout: command timeout
-  *	@retries: number of retries before failing
-  *	@data: returns a structure abstracting the mode header data
-- *	@sense: place to put sense data (or NULL if no sense to be collected).
-+ *	@sshdr: place to put sense data (or NULL if no sense to be collected).
-  *		must be SCSI_SENSE_BUFFERSIZE big.
++/*
+  * Transfer an entire SCSI command's worth of data payload over the bulk
+  * pipe.
   *
-  *	Returns zero if successful; negative error number or scsi
-@@ -1871,8 +1872,7 @@ scsi_mode_select(struct scsi_device *sdev, int pf, int sp, int modepage,
- EXPORT_SYMBOL_GPL(scsi_mode_select);
+@@ -508,7 +524,7 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
+ 	int result;
  
- /**
-- *	scsi_mode_sense - issue a mode sense, falling back from 10 to 
-- *		six bytes if necessary.
-+ *	scsi_mode_sense - issue a mode sense, falling back from 10 to six bytes if necessary.
-  *	@sdev:	SCSI device to be queried
-  *	@dbd:	set if mode sense will allow block descriptors to be returned
-  *	@modepage: mode page being requested
-@@ -1881,13 +1881,13 @@ EXPORT_SYMBOL_GPL(scsi_mode_select);
-  *	@timeout: command timeout
-  *	@retries: number of retries before failing
-  *	@data: returns a structure abstracting the mode header data
-- *	@sense: place to put sense data (or NULL if no sense to be collected).
-+ *	@sshdr: place to put sense data (or NULL if no sense to be collected).
-  *		must be SCSI_SENSE_BUFFERSIZE big.
-  *
-  *	Returns zero if unsuccessful, or the header offset (either 4
-  *	or 8 depending on whether a six or ten byte command was
-  *	issued) if successful.
-- **/
-+ */
- int
- scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage,
- 		  unsigned char *buffer, int len, int timeout, int retries,
-@@ -1981,40 +1981,69 @@ scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage,
- }
- EXPORT_SYMBOL(scsi_mode_sense);
+ 	/* send the command to the transport layer */
+-	srb->resid = 0;
++	scsi_set_resid(srb, 0);
+ 	result = us->transport(srb, us);
  
-+/**
-+ *	scsi_test_unit_ready - test if unit is ready
-+ *	@sdev:	scsi device to change the state of.
-+ *	@timeout: command timeout
-+ *	@retries: number of retries before failing
-+ *	@sshdr_external: Optional pointer to struct scsi_sense_hdr for
-+ *		returning sense. Make sure that this is cleared before passing
-+ *		in.
-+ *
-+ *	Returns zero if unsuccessful or an error if TUR failed.  For
-+ *	removable media, a return of NOT_READY or UNIT_ATTENTION is
-+ *	translated to success, with the ->changed flag updated.
-+ **/
- int
--scsi_test_unit_ready(struct scsi_device *sdev, int timeout, int retries)
-+scsi_test_unit_ready(struct scsi_device *sdev, int timeout, int retries,
-+		     struct scsi_sense_hdr *sshdr_external)
+ 	/* if the command gets aborted by the higher layers, we need to
+@@ -568,7 +584,7 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
+ 	 * A short transfer on a command where we don't expect it
+ 	 * is unusual, but it doesn't mean we need to auto-sense.
+ 	 */
+-	if ((srb->resid > 0) &&
++	if ((scsi_get_resid(srb) > 0) &&
+ 	    !((srb->cmnd[0] == REQUEST_SENSE) ||
+ 	      (srb->cmnd[0] == INQUIRY) ||
+ 	      (srb->cmnd[0] == MODE_SENSE) ||
+@@ -593,7 +609,7 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
+ 			srb->cmd_len = 12;
+ 
+ 		/* issue the auto-sense command */
+-		srb->resid = 0;
++		scsi_set_resid(srb, 0);
+ 		temp_result = us->transport(us->srb, us);
+ 
+ 		/* let's clean up right away */
+@@ -649,7 +665,7 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
+ 
+ 	/* Did we transfer less than the minimum amount required? */
+ 	if (srb->result == SAM_STAT_GOOD &&
+-			srb->request_bufflen - srb->resid < srb->underflow)
++			scsi_bufflen(srb) - scsi_get_resid(srb) < srb->underflow)
+ 		srb->result = (DID_ERROR << 16) | (SUGGEST_RETRY << 24);
+ 
+ 	return;
+@@ -708,7 +724,7 @@ void usb_stor_stop_transport(struct us_data *us)
+ 
+ int usb_stor_CBI_transport(struct scsi_cmnd *srb, struct us_data *us)
  {
- 	char cmd[] = {
- 		TEST_UNIT_READY, 0, 0, 0, 0, 0,
- 	};
--	struct scsi_sense_hdr sshdr;
-+	struct scsi_sense_hdr *sshdr;
+-	unsigned int transfer_length = srb->request_bufflen;
++	unsigned int transfer_length = scsi_bufflen(srb);
+ 	unsigned int pipe = 0;
  	int result;
--	
--	result = scsi_execute_req(sdev, cmd, DMA_NONE, NULL, 0, &sshdr,
--				  timeout, retries);
-+
-+	if (!sshdr_external)
-+		sshdr = kzalloc(sizeof(*sshdr), GFP_KERNEL);
-+	else
-+		sshdr = sshdr_external;
-+
-+	/* try to eat the UNIT_ATTENTION if there are enough retries */
-+	do {
-+		result = scsi_execute_req(sdev, cmd, DMA_NONE, NULL, 0, sshdr,
-+					  timeout, retries);
-+	} while ((driver_byte(result) & DRIVER_SENSE) &&
-+		 sshdr && sshdr->sense_key == UNIT_ATTENTION &&
-+		 --retries);
-+
-+	if (!sshdr)
-+		/* could not allocate sense buffer, so can't process it */
-+		return result;
  
- 	if ((driver_byte(result) & DRIVER_SENSE) && sdev->removable) {
+@@ -737,9 +753,7 @@ int usb_stor_CBI_transport(struct scsi_cmnd *srb, struct us_data *us)
+ 	if (transfer_length) {
+ 		pipe = srb->sc_data_direction == DMA_FROM_DEVICE ? 
+ 				us->recv_bulk_pipe : us->send_bulk_pipe;
+-		result = usb_stor_bulk_transfer_sg(us, pipe,
+-					srb->request_buffer, transfer_length,
+-					srb->use_sg, &srb->resid);
++		result = usb_stor_bulk_srb(us, pipe, srb);
+ 		US_DEBUGP("CBI data stage result is 0x%x\n", result);
  
--		if ((scsi_sense_valid(&sshdr)) &&
--		    ((sshdr.sense_key == UNIT_ATTENTION) ||
--		     (sshdr.sense_key == NOT_READY))) {
-+		if ((scsi_sense_valid(sshdr)) &&
-+		    ((sshdr->sense_key == UNIT_ATTENTION) ||
-+		     (sshdr->sense_key == NOT_READY))) {
- 			sdev->changed = 1;
- 			result = 0;
+ 		/* if we stalled the data transfer it means command failed */
+@@ -808,7 +822,7 @@ int usb_stor_CBI_transport(struct scsi_cmnd *srb, struct us_data *us)
+  */
+ int usb_stor_CB_transport(struct scsi_cmnd *srb, struct us_data *us)
+ {
+-	unsigned int transfer_length = srb->request_bufflen;
++	unsigned int transfer_length = scsi_bufflen(srb);
+ 	int result;
+ 
+ 	/* COMMAND STAGE */
+@@ -836,9 +850,7 @@ int usb_stor_CB_transport(struct scsi_cmnd *srb, struct us_data *us)
+ 	if (transfer_length) {
+ 		unsigned int pipe = srb->sc_data_direction == DMA_FROM_DEVICE ? 
+ 				us->recv_bulk_pipe : us->send_bulk_pipe;
+-		result = usb_stor_bulk_transfer_sg(us, pipe,
+-					srb->request_buffer, transfer_length,
+-					srb->use_sg, &srb->resid);
++		result = usb_stor_bulk_srb(us, pipe, srb);
+ 		US_DEBUGP("CB data stage result is 0x%x\n", result);
+ 
+ 		/* if we stalled the data transfer it means command failed */
+@@ -904,7 +916,7 @@ int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us)
+ {
+ 	struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
+ 	struct bulk_cs_wrap *bcs = (struct bulk_cs_wrap *) us->iobuf;
+-	unsigned int transfer_length = srb->request_bufflen;
++	unsigned int transfer_length = scsi_bufflen(srb);
+ 	unsigned int residue;
+ 	int result;
+ 	int fake_sense = 0;
+@@ -955,9 +967,7 @@ int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us)
+ 	if (transfer_length) {
+ 		unsigned int pipe = srb->sc_data_direction == DMA_FROM_DEVICE ? 
+ 				us->recv_bulk_pipe : us->send_bulk_pipe;
+-		result = usb_stor_bulk_transfer_sg(us, pipe,
+-					srb->request_buffer, transfer_length,
+-					srb->use_sg, &srb->resid);
++		result = usb_stor_bulk_srb(us, pipe, srb);
+ 		US_DEBUGP("Bulk data transfer result 0x%x\n", result);
+ 		if (result == USB_STOR_XFER_ERROR)
+ 			return USB_STOR_TRANSPORT_ERROR;
+@@ -1036,7 +1046,8 @@ int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us)
+ 	if (residue) {
+ 		if (!(us->flags & US_FL_IGNORE_RESIDUE)) {
+ 			residue = min(residue, transfer_length);
+-			srb->resid = max(srb->resid, (int) residue);
++			scsi_set_resid(srb, max(scsi_get_resid(srb),
++			                                       (int) residue));
  		}
  	}
-+	if (!sshdr_external)
-+		kfree(sshdr);
- 	return result;
- }
- EXPORT_SYMBOL(scsi_test_unit_ready);
  
- /**
-- *	scsi_device_set_state - Take the given device through the device
-- *		state model.
-+ *	scsi_device_set_state - Take the given device through the device state model.
-  *	@sdev:	scsi device to change the state of.
-  *	@state:	state to change to.
-  *
-  *	Returns zero if unsuccessful or an error if the requested 
-  *	transition is illegal.
-- **/
-+ */
- int
- scsi_device_set_state(struct scsi_device *sdev, enum scsi_device_state state)
- {
-@@ -2264,7 +2293,7 @@ EXPORT_SYMBOL_GPL(sdev_evt_send_simple);
-  *	Must be called with user context, may sleep.
-  *
-  *	Returns zero if unsuccessful or an error if not.
-- **/
-+ */
- int
- scsi_device_quiesce(struct scsi_device *sdev)
- {
-@@ -2289,7 +2318,7 @@ EXPORT_SYMBOL(scsi_device_quiesce);
-  *	queues.
-  *
-  *	Must be called with user context, may sleep.
-- **/
-+ */
- void
- scsi_device_resume(struct scsi_device *sdev)
- {
-@@ -2326,8 +2355,7 @@ scsi_target_resume(struct scsi_target *starget)
- EXPORT_SYMBOL(scsi_target_resume);
+diff --git a/drivers/usb/storage/transport.h b/drivers/usb/storage/transport.h
+index 633a715..ada7c2f 100644
+--- a/drivers/usb/storage/transport.h
++++ b/drivers/usb/storage/transport.h
+@@ -139,6 +139,8 @@ extern int usb_stor_bulk_transfer_buf(struct us_data *us, unsigned int pipe,
+ 		void *buf, unsigned int length, unsigned int *act_len);
+ extern int usb_stor_bulk_transfer_sg(struct us_data *us, unsigned int pipe,
+ 		void *buf, unsigned int length, int use_sg, int *residual);
++extern int usb_stor_bulk_srb(struct us_data* us, unsigned int pipe,
++		struct scsi_cmnd* srb);
  
- /**
-- * scsi_internal_device_block - internal function to put a device
-- *				temporarily into the SDEV_BLOCK state
-+ * scsi_internal_device_block - internal function to put a device temporarily into the SDEV_BLOCK state
-  * @sdev:	device to block
-  *
-  * Block request made by scsi lld's to temporarily stop all
-@@ -2342,7 +2370,7 @@ EXPORT_SYMBOL(scsi_target_resume);
-  *	state, all commands are deferred until the scsi lld reenables
-  *	the device with scsi_device_unblock or device_block_tmo fires.
-  *	This routine assumes the host_lock is held on entry.
-- **/
-+ */
- int
- scsi_internal_device_block(struct scsi_device *sdev)
- {
-@@ -2382,7 +2410,7 @@ EXPORT_SYMBOL_GPL(scsi_internal_device_block);
-  *	(which must be a legal transition) allowing the midlayer to
-  *	goose the queue for this device.  This routine assumes the 
-  *	host_lock is held upon entry.
-- **/
-+ */
- int
- scsi_internal_device_unblock(struct scsi_device *sdev)
- {
-@@ -2460,7 +2488,7 @@ EXPORT_SYMBOL_GPL(scsi_target_unblock);
+ extern int usb_stor_port_reset(struct us_data *us);
+ #endif
+diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
+index 5b3dbcf..758435f 100644
+--- a/drivers/video/Kconfig
++++ b/drivers/video/Kconfig
+@@ -889,7 +889,7 @@ config FB_S1D13XXX
+ 
+ config FB_ATMEL
+ 	tristate "AT91/AT32 LCD Controller support"
+-	depends on FB && (ARCH_AT91SAM9261 || ARCH_AT91SAM9263 || AVR32)
++	depends on FB && (ARCH_AT91SAM9261 || ARCH_AT91SAM9263 || ARCH_AT91SAM9RL || ARCH_AT91CAP9 || AVR32)
+ 	select FB_CFB_FILLRECT
+ 	select FB_CFB_COPYAREA
+ 	select FB_CFB_IMAGEBLIT
+diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
+index 7c30cc8..f8e7111 100644
+--- a/drivers/video/atmel_lcdfb.c
++++ b/drivers/video/atmel_lcdfb.c
+@@ -30,7 +30,7 @@
+ #define ATMEL_LCDC_CVAL_DEFAULT		0xc8
+ #define ATMEL_LCDC_DMA_BURST_LEN	8
  
- /**
-  * scsi_kmap_atomic_sg - find and atomically map an sg-elemnt
-- * @sg:		scatter-gather list
-+ * @sgl:	scatter-gather list
-  * @sg_count:	number of segments in sg
-  * @offset:	offset in bytes into sg, on return offset into the mapped area
-  * @len:	bytes to map, on return number of bytes mapped
-@@ -2509,8 +2537,7 @@ void *scsi_kmap_atomic_sg(struct scatterlist *sgl, int sg_count,
- EXPORT_SYMBOL(scsi_kmap_atomic_sg);
+-#if defined(CONFIG_ARCH_AT91SAM9263)
++#if defined(CONFIG_ARCH_AT91SAM9263) || defined(CONFIG_ARCH_AT91CAP9)
+ #define ATMEL_LCDC_FIFO_SIZE		2048
+ #else
+ #define ATMEL_LCDC_FIFO_SIZE		512
+diff --git a/drivers/video/bf54x-lq043fb.c b/drivers/video/bf54x-lq043fb.c
+index 74d11c3..c8e7427 100644
+--- a/drivers/video/bf54x-lq043fb.c
++++ b/drivers/video/bf54x-lq043fb.c
+@@ -224,7 +224,8 @@ static int config_dma(struct bfin_bf54xfb_info *fbi)
+ 	set_dma_config(CH_EPPI0,
+ 		       set_bfin_dma_config(DIR_READ, DMA_FLOW_AUTO,
+ 					   INTR_DISABLE, DIMENSION_2D,
+-					   DATA_SIZE_32));
++					   DATA_SIZE_32,
++					   DMA_NOSYNC_KEEP_DMA_BUF));
+ 	set_dma_x_count(CH_EPPI0, (LCD_X_RES * LCD_BPP) / DMA_BUS_SIZE);
+ 	set_dma_x_modify(CH_EPPI0, DMA_BUS_SIZE / 8);
+ 	set_dma_y_count(CH_EPPI0, LCD_Y_RES);
+@@ -263,8 +264,7 @@ static int request_ports(struct bfin_bf54xfb_info *fbi)
+ 		}
+ 	}
  
- /**
-- * scsi_kunmap_atomic_sg - atomically unmap a virtual address, previously
-- *			   mapped with scsi_kmap_atomic_sg
-+ * scsi_kunmap_atomic_sg - atomically unmap a virtual address, previously mapped with scsi_kmap_atomic_sg
-  * @virt:	virtual address to be unmapped
-  */
- void scsi_kunmap_atomic_sg(void *virt)
-diff --git a/drivers/scsi/scsi_netlink.c b/drivers/scsi/scsi_netlink.c
-index 40579ed..3e15918 100644
---- a/drivers/scsi/scsi_netlink.c
-+++ b/drivers/scsi/scsi_netlink.c
-@@ -32,11 +32,12 @@ EXPORT_SYMBOL_GPL(scsi_nl_sock);
+-	gpio_direction_output(disp);
+-	gpio_set_value(disp, 1);
++	gpio_direction_output(disp, 1);
  
+ 	return 0;
+ }
+diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig
+index b87ed37..2b53d1f 100644
+--- a/drivers/video/console/Kconfig
++++ b/drivers/video/console/Kconfig
+@@ -6,7 +6,7 @@ menu "Console display driver support"
  
- /**
-- * scsi_nl_rcv_msg -
-- *    Receive message handler. Extracts message from a receive buffer.
-+ * scsi_nl_rcv_msg - Receive message handler.
-+ * @skb:		socket receive buffer
-+ *
-+ * Description: Extracts message from a receive buffer.
-  *    Validates message header and calls appropriate transport message handler
-  *
-- * @skb:		socket receive buffer
-  *
-  **/
- static void
-@@ -99,9 +100,7 @@ next_msg:
+ config VGA_CONSOLE
+ 	bool "VGA text console" if EMBEDDED || !X86
+-	depends on !ARCH_ACORN && !ARCH_EBSA110 && !4xx && !8xx && !SPARC && !M68K && !PARISC && !FRV && !ARCH_VERSATILE && !SUPERH && !BLACKFIN
++	depends on !ARCH_ACORN && !ARCH_EBSA110 && !4xx && !8xx && !SPARC && !M68K && !PARISC && !FRV && !ARCH_VERSATILE && !SUPERH && !BLACKFIN && !AVR32
+ 	default y
+ 	help
+ 	  Saying Y here will allow you to use Linux in text mode through a
+diff --git a/drivers/video/matrox/matroxfb_maven.c b/drivers/video/matrox/matroxfb_maven.c
+index 49cd53e..0cd58f8 100644
+--- a/drivers/video/matrox/matroxfb_maven.c
++++ b/drivers/video/matrox/matroxfb_maven.c
+@@ -1232,7 +1232,7 @@ static int maven_shutdown_client(struct i2c_client* clnt) {
+ 	return 0;
+ }
  
+-static unsigned short normal_i2c[] = { MAVEN_I2CID, I2C_CLIENT_END };
++static const unsigned short normal_i2c[] = { MAVEN_I2CID, I2C_CLIENT_END };
+ I2C_CLIENT_INSMOD;
  
- /**
-- * scsi_nl_rcv_event -
-- *    Event handler for a netlink socket.
-- *
-+ * scsi_nl_rcv_event - Event handler for a netlink socket.
-  * @this:		event notifier block
-  * @event:		event type
-  * @ptr:		event payload
-@@ -129,9 +128,7 @@ static struct notifier_block scsi_netlink_notifier = {
+ static struct i2c_driver maven_driver;
+diff --git a/drivers/video/omap/lcd_h3.c b/drivers/video/omap/lcd_h3.c
+index c604d93..31e9783 100644
+--- a/drivers/video/omap/lcd_h3.c
++++ b/drivers/video/omap/lcd_h3.c
+@@ -21,9 +21,9 @@
  
+ #include <linux/module.h>
+ #include <linux/platform_device.h>
++#include <linux/i2c/tps65010.h>
  
- /**
-- * scsi_netlink_init -
-- *    Called by SCSI subsystem to intialize the SCSI transport netlink
-- *    interface
-+ * scsi_netlink_init - Called by SCSI subsystem to intialize the SCSI transport netlink interface
-  *
-  **/
- void
-@@ -160,9 +157,7 @@ scsi_netlink_init(void)
+ #include <asm/arch/gpio.h>
+-#include <asm/arch/tps65010.h>
+ #include <asm/arch/omapfb.h>
  
+ #define MODULE_NAME	"omapfb-lcd_h3"
+diff --git a/drivers/w1/masters/ds2482.c b/drivers/w1/masters/ds2482.c
+index d93eb62..0fd5820 100644
+--- a/drivers/w1/masters/ds2482.c
++++ b/drivers/w1/masters/ds2482.c
+@@ -29,7 +29,7 @@
+  * However, the chip cannot be detected without doing an i2c write,
+  * so use the force module parameter.
+  */
+-static unsigned short normal_i2c[] = {I2C_CLIENT_END};
++static const unsigned short normal_i2c[] = { I2C_CLIENT_END };
  
  /**
-- * scsi_netlink_exit -
-- *    Called by SCSI subsystem to disable the SCSI transport netlink
-- *    interface
-+ * scsi_netlink_exit - Called by SCSI subsystem to disable the SCSI transport netlink interface
-  *
-  **/
- void
-diff --git a/drivers/scsi/scsi_proc.c b/drivers/scsi/scsi_proc.c
-index bb6f051..ed39515 100644
---- a/drivers/scsi/scsi_proc.c
-+++ b/drivers/scsi/scsi_proc.c
-@@ -45,6 +45,16 @@ static struct proc_dir_entry *proc_scsi;
- /* Protect sht->present and sht->proc_dir */
- static DEFINE_MUTEX(global_host_template_mutex);
+  * Insmod parameters
+diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
+index 52dff40..899fc13 100644
+--- a/drivers/watchdog/Kconfig
++++ b/drivers/watchdog/Kconfig
+@@ -223,7 +223,7 @@ config DAVINCI_WATCHDOG
  
-+/**
-+ * proc_scsi_read - handle read from /proc by calling host's proc_info() command
-+ * @buffer: passed to proc_info
-+ * @start: passed to proc_info
-+ * @offset: passed to proc_info
-+ * @length: passed to proc_info
-+ * @eof: returns whether length read was less than requested
-+ * @data: pointer to a &struct Scsi_Host
-+ */
+ config AT32AP700X_WDT
+ 	tristate "AT32AP700x watchdog"
+-	depends on CPU_AT32AP7000
++	depends on CPU_AT32AP700X
+ 	help
+ 	  Watchdog timer embedded into AT32AP700x devices. This will reboot
+ 	  your system when the timeout is reached.
+@@ -639,6 +639,12 @@ config AR7_WDT
+ 	help
+ 	  Hardware driver for the TI AR7 Watchdog Timer.
+ 
++config TXX9_WDT
++	tristate "Toshiba TXx9 Watchdog Timer"
++	depends on CPU_TX39XX || CPU_TX49XX
++	help
++	  Hardware driver for the built-in watchdog timer on TXx9 MIPS SoCs.
 +
- static int proc_scsi_read(char *buffer, char **start, off_t offset,
- 			  int length, int *eof, void *data)
- {
-@@ -57,6 +67,13 @@ static int proc_scsi_read(char *buffer, char **start, off_t offset,
- 	return n;
- }
+ # PARISC Architecture
  
-+/**
-+ * proc_scsi_write_proc - Handle write to /proc by calling host's proc_info()
-+ * @file: not used
-+ * @buf: source of data to write.
-+ * @count: number of bytes (at most PROC_BLOCK_SIZE) to write.
-+ * @data: pointer to &struct Scsi_Host
-+ */
- static int proc_scsi_write_proc(struct file *file, const char __user *buf,
-                            unsigned long count, void *data)
- {
-@@ -80,6 +97,13 @@ out:
- 	return ret;
- }
+ # POWERPC Architecture
+diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
+index 87483cc..ebc2114 100644
+--- a/drivers/watchdog/Makefile
++++ b/drivers/watchdog/Makefile
+@@ -93,6 +93,7 @@ obj-$(CONFIG_INDYDOG) += indydog.o
+ obj-$(CONFIG_WDT_MTX1)	+= mtx-1_wdt.o
+ obj-$(CONFIG_WDT_RM9K_GPI) += rm9k_wdt.o
+ obj-$(CONFIG_AR7_WDT) += ar7_wdt.o
++obj-$(CONFIG_TXX9_WDT) += txx9wdt.o
+ 
+ # PARISC Architecture
+ 
+diff --git a/drivers/watchdog/alim1535_wdt.c b/drivers/watchdog/alim1535_wdt.c
+index b481cc0..2b1fbdb 100644
+--- a/drivers/watchdog/alim1535_wdt.c
++++ b/drivers/watchdog/alim1535_wdt.c
+@@ -413,18 +413,18 @@ static int __init watchdog_init(void)
+ 	/* Calculate the watchdog's timeout */
+ 	ali_settimer(timeout);
  
-+/**
-+ * scsi_proc_hostdir_add - Create directory in /proc for a scsi host
-+ * @sht: owner of this directory
-+ *
-+ * Sets sht->proc_dir to the new directory.
-+ */
-+
- void scsi_proc_hostdir_add(struct scsi_host_template *sht)
- {
- 	if (!sht->proc_info)
-@@ -97,6 +121,10 @@ void scsi_proc_hostdir_add(struct scsi_host_template *sht)
- 	mutex_unlock(&global_host_template_mutex);
- }
+-	ret = misc_register(&ali_miscdev);
++	ret = register_reboot_notifier(&ali_notifier);
+ 	if (ret != 0) {
+-		printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
+-			WATCHDOG_MINOR, ret);
++		printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
++			ret);
+ 		goto out;
+ 	}
  
-+/**
-+ * scsi_proc_hostdir_rm - remove directory in /proc for a scsi host
-+ * @sht: owner of directory
-+ */
- void scsi_proc_hostdir_rm(struct scsi_host_template *sht)
- {
- 	if (!sht->proc_info)
-@@ -110,6 +138,11 @@ void scsi_proc_hostdir_rm(struct scsi_host_template *sht)
- 	mutex_unlock(&global_host_template_mutex);
- }
+-	ret = register_reboot_notifier(&ali_notifier);
++	ret = misc_register(&ali_miscdev);
+ 	if (ret != 0) {
+-		printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
+-			ret);
+-		goto unreg_miscdev;
++		printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
++			WATCHDOG_MINOR, ret);
++		goto unreg_reboot;
+ 	}
  
-+
-+/**
-+ * scsi_proc_host_add - Add entry for this host to appropriate /proc dir
-+ * @shost: host to add
-+ */
- void scsi_proc_host_add(struct Scsi_Host *shost)
- {
- 	struct scsi_host_template *sht = shost->hostt;
-@@ -133,6 +166,10 @@ void scsi_proc_host_add(struct Scsi_Host *shost)
- 	p->owner = sht->module;
- }
+ 	printk(KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d)\n",
+@@ -432,8 +432,8 @@ static int __init watchdog_init(void)
  
-+/**
-+ * scsi_proc_host_rm - remove this host's entry from /proc
-+ * @shost: which host
-+ */
- void scsi_proc_host_rm(struct Scsi_Host *shost)
- {
- 	char name[10];
-@@ -143,7 +180,14 @@ void scsi_proc_host_rm(struct Scsi_Host *shost)
- 	sprintf(name,"%d", shost->host_no);
- 	remove_proc_entry(name, shost->hostt->proc_dir);
- }
--
-+/**
-+ * proc_print_scsidevice - return data about this host
-+ * @dev: A scsi device
-+ * @data: &struct seq_file to output to.
-+ *
-+ * Description: prints Host, Channel, Id, Lun, Vendor, Model, Rev, Type,
-+ * and revision.
-+ */
- static int proc_print_scsidevice(struct device *dev, void *data)
- {
- 	struct scsi_device *sdev = to_scsi_device(dev);
-@@ -189,6 +233,21 @@ static int proc_print_scsidevice(struct device *dev, void *data)
- 	return 0;
+ out:
+ 	return ret;
+-unreg_miscdev:
+-	misc_deregister(&ali_miscdev);
++unreg_reboot:
++	unregister_reboot_notifier(&ali_notifier);
+ 	goto out;
  }
  
-+/**
-+ * scsi_add_single_device - Respond to user request to probe for/add device
-+ * @host: user-supplied decimal integer
-+ * @channel: user-supplied decimal integer
-+ * @id: user-supplied decimal integer
-+ * @lun: user-supplied decimal integer
-+ *
-+ * Description: called by writing "scsi add-single-device" to /proc/scsi/scsi.
-+ *
-+ * does scsi_host_lookup() and either user_scan() if that transport
-+ * type supports it, or else scsi_scan_host_selected()
-+ *
-+ * Note: this seems to be aimed exclusively at SCSI parallel busses.
-+ */
-+
- static int scsi_add_single_device(uint host, uint channel, uint id, uint lun)
- {
- 	struct Scsi_Host *shost;
-@@ -206,6 +265,16 @@ static int scsi_add_single_device(uint host, uint channel, uint id, uint lun)
- 	return error;
- }
+@@ -449,8 +449,8 @@ static void __exit watchdog_exit(void)
+ 	ali_stop();
  
-+/**
-+ * scsi_remove_single_device - Respond to user request to remove a device
-+ * @host: user-supplied decimal integer
-+ * @channel: user-supplied decimal integer
-+ * @id: user-supplied decimal integer
-+ * @lun: user-supplied decimal integer
-+ *
-+ * Description: called by writing "scsi remove-single-device" to
-+ * /proc/scsi/scsi.  Does a scsi_device_lookup() and scsi_remove_device()
-+ */
- static int scsi_remove_single_device(uint host, uint channel, uint id, uint lun)
- {
- 	struct scsi_device *sdev;
-@@ -226,6 +295,25 @@ static int scsi_remove_single_device(uint host, uint channel, uint id, uint lun)
- 	return error;
- }
+ 	/* Deregister */
+-	unregister_reboot_notifier(&ali_notifier);
+ 	misc_deregister(&ali_miscdev);
++	unregister_reboot_notifier(&ali_notifier);
+ 	pci_dev_put(ali_pci);
+ }
+ 
+diff --git a/drivers/watchdog/alim7101_wdt.c b/drivers/watchdog/alim7101_wdt.c
+index 67aed9f..238273c 100644
+--- a/drivers/watchdog/alim7101_wdt.c
++++ b/drivers/watchdog/alim7101_wdt.c
+@@ -377,18 +377,18 @@ static int __init alim7101_wdt_init(void)
+ 			timeout);
+ 	}
  
-+/**
-+ * proc_scsi_write - handle writes to /proc/scsi/scsi
-+ * @file: not used
-+ * @buf: buffer to write
-+ * @length: length of buf, at most PAGE_SIZE
-+ * @ppos: not used
-+ *
-+ * Description: this provides a legacy mechanism to add or remove devices by
-+ * Host, Channel, ID, and Lun.  To use,
-+ * "echo 'scsi add-single-device 0 1 2 3' > /proc/scsi/scsi" or
-+ * "echo 'scsi remove-single-device 0 1 2 3' > /proc/scsi/scsi" with
-+ * "0 1 2 3" replaced by the Host, Channel, Id, and Lun.
-+ *
-+ * Note: this seems to be aimed at parallel SCSI. Most modern busses (USB,
-+ * SATA, Firewire, Fibre Channel, etc) dynamically assign these values to
-+ * provide a unique identifier and nothing more.
-+ */
-+
-+
- static ssize_t proc_scsi_write(struct file *file, const char __user *buf,
- 			       size_t length, loff_t *ppos)
- {
-@@ -291,6 +379,11 @@ static ssize_t proc_scsi_write(struct file *file, const char __user *buf,
- 	return err;
+-	rc = misc_register(&wdt_miscdev);
++	rc = register_reboot_notifier(&wdt_notifier);
+ 	if (rc) {
+-		printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
+-			wdt_miscdev.minor, rc);
++		printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
++			rc);
+ 		goto err_out;
+ 	}
+ 
+-	rc = register_reboot_notifier(&wdt_notifier);
++	rc = misc_register(&wdt_miscdev);
+ 	if (rc) {
+-		printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
+-			rc);
+-		goto err_out_miscdev;
++		printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
++			wdt_miscdev.minor, rc);
++		goto err_out_reboot;
+ 	}
+ 
+ 	if (nowayout) {
+@@ -399,8 +399,8 @@ static int __init alim7101_wdt_init(void)
+ 		timeout, nowayout);
+ 	return 0;
+ 
+-err_out_miscdev:
+-	misc_deregister(&wdt_miscdev);
++err_out_reboot:
++	unregister_reboot_notifier(&wdt_notifier);
+ err_out:
+ 	pci_dev_put(alim7101_pmu);
+ 	return rc;
+diff --git a/drivers/watchdog/ar7_wdt.c b/drivers/watchdog/ar7_wdt.c
+index cdaab8c..2eb48c0 100644
+--- a/drivers/watchdog/ar7_wdt.c
++++ b/drivers/watchdog/ar7_wdt.c
+@@ -279,7 +279,7 @@ static int ar7_wdt_ioctl(struct inode *inode, struct file *file,
+ 	}
  }
  
-+/**
-+ * proc_scsi_show - show contents of /proc/scsi/scsi (attached devices)
-+ * @s: output goes here
-+ * @p: not used
-+ */
- static int proc_scsi_show(struct seq_file *s, void *p)
- {
- 	seq_printf(s, "Attached devices:\n");
-@@ -298,10 +391,17 @@ static int proc_scsi_show(struct seq_file *s, void *p)
+-static struct file_operations ar7_wdt_fops = {
++static const struct file_operations ar7_wdt_fops = {
+ 	.owner		= THIS_MODULE,
+ 	.write		= ar7_wdt_write,
+ 	.ioctl		= ar7_wdt_ioctl,
+diff --git a/drivers/watchdog/bfin_wdt.c b/drivers/watchdog/bfin_wdt.c
+index 31dc7a6..472be10 100644
+--- a/drivers/watchdog/bfin_wdt.c
++++ b/drivers/watchdog/bfin_wdt.c
+@@ -390,7 +390,7 @@ static struct platform_driver bfin_wdt_driver = {
+ 	.resume    = bfin_wdt_resume,
+ };
+ 
+-static struct file_operations bfin_wdt_fops = {
++static const struct file_operations bfin_wdt_fops = {
+ 	.owner    = THIS_MODULE,
+ 	.llseek   = no_llseek,
+ 	.write    = bfin_wdt_write,
+diff --git a/drivers/watchdog/it8712f_wdt.c b/drivers/watchdog/it8712f_wdt.c
+index 6330fc0..1b6d7d1 100644
+--- a/drivers/watchdog/it8712f_wdt.c
++++ b/drivers/watchdog/it8712f_wdt.c
+@@ -296,7 +296,7 @@ it8712f_wdt_release(struct inode *inode, struct file *file)
  	return 0;
  }
  
-+/**
-+ * proc_scsi_open - glue function
-+ * @inode: not used
-+ * @file: passed to single_open()
-+ *
-+ * Associates proc_scsi_show with this file
-+ */
- static int proc_scsi_open(struct inode *inode, struct file *file)
- {
- 	/*
--	 * We don't really needs this for the write case but it doesn't
-+	 * We don't really need this for the write case but it doesn't
- 	 * harm either.
- 	 */
- 	return single_open(file, proc_scsi_show, NULL);
-@@ -315,6 +415,9 @@ static const struct file_operations proc_scsi_operations = {
- 	.release	= single_release,
- };
+-static struct file_operations it8712f_wdt_fops = {
++static const struct file_operations it8712f_wdt_fops = {
+ 	.owner = THIS_MODULE,
+ 	.llseek = no_llseek,
+ 	.write = it8712f_wdt_write,
+diff --git a/drivers/watchdog/mpc5200_wdt.c b/drivers/watchdog/mpc5200_wdt.c
+index 11f6a11..80a91d4 100644
+--- a/drivers/watchdog/mpc5200_wdt.c
++++ b/drivers/watchdog/mpc5200_wdt.c
+@@ -158,7 +158,7 @@ static int mpc5200_wdt_release(struct inode *inode, struct file *file)
+ 	return 0;
+ }
  
-+/**
-+ * scsi_init_procfs - create scsi and scsi/scsi in procfs
-+ */
- int __init scsi_init_procfs(void)
- {
- 	struct proc_dir_entry *pde;
-@@ -336,6 +439,9 @@ err1:
- 	return -ENOMEM;
+-static struct file_operations mpc5200_wdt_fops = {
++static const struct file_operations mpc5200_wdt_fops = {
+ 	.owner	= THIS_MODULE,
+ 	.write	= mpc5200_wdt_write,
+ 	.ioctl	= mpc5200_wdt_ioctl,
+diff --git a/drivers/watchdog/mtx-1_wdt.c b/drivers/watchdog/mtx-1_wdt.c
+index dcfd401..9845174 100644
+--- a/drivers/watchdog/mtx-1_wdt.c
++++ b/drivers/watchdog/mtx-1_wdt.c
+@@ -180,7 +180,7 @@ static ssize_t mtx1_wdt_write(struct file *file, const char *buf, size_t count,
+ 	return count;
  }
  
-+/**
-+ * scsi_exit_procfs - Remove scsi/scsi and scsi from procfs
-+ */
- void scsi_exit_procfs(void)
- {
- 	remove_proc_entry("scsi/scsi", NULL);
-diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
-index 40ea71c..1dc165a 100644
---- a/drivers/scsi/scsi_scan.c
-+++ b/drivers/scsi/scsi_scan.c
-@@ -221,6 +221,9 @@ static void scsi_unlock_floptical(struct scsi_device *sdev,
+-static struct file_operations mtx1_wdt_fops = {
++static const struct file_operations mtx1_wdt_fops = {
+ 	.owner 		= THIS_MODULE,
+ 	.llseek		= no_llseek,
+ 	.ioctl		= mtx1_wdt_ioctl,
+diff --git a/drivers/watchdog/sbc60xxwdt.c b/drivers/watchdog/sbc60xxwdt.c
+index e4f3cb6..ef76f01 100644
+--- a/drivers/watchdog/sbc60xxwdt.c
++++ b/drivers/watchdog/sbc60xxwdt.c
+@@ -359,20 +359,20 @@ static int __init sbc60xxwdt_init(void)
+ 		}
+ 	}
  
- /**
-  * scsi_alloc_sdev - allocate and setup a scsi_Device
-+ * @starget: which target to allocate a &scsi_device for
-+ * @lun: which lun
-+ * @hostdata: usually NULL and set by ->slave_alloc instead
-  *
-  * Description:
-  *     Allocate, initialize for io, and return a pointer to a scsi_Device.
-@@ -472,7 +475,6 @@ static void scsi_target_reap_usercontext(struct work_struct *work)
+-	rc = misc_register(&wdt_miscdev);
++	rc = register_reboot_notifier(&wdt_notifier);
+ 	if (rc)
+ 	{
+-		printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
+-			wdt_miscdev.minor, rc);
++		printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
++			rc);
+ 		goto err_out_region2;
+ 	}
  
- /**
-  * scsi_target_reap - check to see if target is in use and destroy if not
-- *
-  * @starget: target to be checked
-  *
-  * This is used after removing a LUN or doing a last put of the target
-@@ -863,7 +865,7 @@ static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result,
- 		sdev->no_start_on_add = 1;
+-	rc = register_reboot_notifier(&wdt_notifier);
++	rc = misc_register(&wdt_miscdev);
+ 	if (rc)
+ 	{
+-		printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
+-			rc);
+-		goto err_out_miscdev;
++		printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
++			wdt_miscdev.minor, rc);
++		goto err_out_reboot;
+ 	}
+ 
+ 	printk(KERN_INFO PFX "WDT driver for 60XX single board computer initialised. timeout=%d sec (nowayout=%d)\n",
+@@ -380,8 +380,8 @@ static int __init sbc60xxwdt_init(void)
  
- 	if (*bflags & BLIST_SINGLELUN)
--		sdev->single_lun = 1;
-+		scsi_target(sdev)->single_lun = 1;
+ 	return 0;
  
- 	sdev->use_10_for_rw = 1;
+-err_out_miscdev:
+-	misc_deregister(&wdt_miscdev);
++err_out_reboot:
++	unregister_reboot_notifier(&wdt_notifier);
+ err_out_region2:
+ 	if ((wdt_stop != 0x45) && (wdt_stop != wdt_start))
+ 		release_region(wdt_stop,1);
+diff --git a/drivers/watchdog/scx200_wdt.c b/drivers/watchdog/scx200_wdt.c
+index d4fd0fa..d55882b 100644
+--- a/drivers/watchdog/scx200_wdt.c
++++ b/drivers/watchdog/scx200_wdt.c
+@@ -231,17 +231,17 @@ static int __init scx200_wdt_init(void)
+ 
+ 	sema_init(&open_semaphore, 1);
+ 
+-	r = misc_register(&scx200_wdt_miscdev);
++	r = register_reboot_notifier(&scx200_wdt_notifier);
+ 	if (r) {
++		printk(KERN_ERR NAME ": unable to register reboot notifier");
+ 		release_region(scx200_cb_base + SCx200_WDT_OFFSET,
+ 				SCx200_WDT_SIZE);
+ 		return r;
+ 	}
+ 
+-	r = register_reboot_notifier(&scx200_wdt_notifier);
++	r = misc_register(&scx200_wdt_miscdev);
+ 	if (r) {
+-		printk(KERN_ERR NAME ": unable to register reboot notifier");
+-		misc_deregister(&scx200_wdt_miscdev);
++		unregister_reboot_notifier(&scx200_wdt_notifier);
+ 		release_region(scx200_cb_base + SCx200_WDT_OFFSET,
+ 				SCx200_WDT_SIZE);
+ 		return r;
+@@ -252,8 +252,8 @@ static int __init scx200_wdt_init(void)
+ 
+ static void __exit scx200_wdt_cleanup(void)
+ {
+-	unregister_reboot_notifier(&scx200_wdt_notifier);
+ 	misc_deregister(&scx200_wdt_miscdev);
++	unregister_reboot_notifier(&scx200_wdt_notifier);
+ 	release_region(scx200_cb_base + SCx200_WDT_OFFSET,
+ 		       SCx200_WDT_SIZE);
+ }
+diff --git a/drivers/watchdog/txx9wdt.c b/drivers/watchdog/txx9wdt.c
+new file mode 100644
+index 0000000..328b3c7
+--- /dev/null
++++ b/drivers/watchdog/txx9wdt.c
+@@ -0,0 +1,276 @@
++/*
++ * txx9wdt: A Hardware Watchdog Driver for TXx9 SoCs
++ *
++ * Copyright (C) 2007 Atsushi Nemoto <anemo at mba.ocn.ne.jp>
++ *
++ * 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/moduleparam.h>
++#include <linux/types.h>
++#include <linux/miscdevice.h>
++#include <linux/watchdog.h>
++#include <linux/fs.h>
++#include <linux/reboot.h>
++#include <linux/init.h>
++#include <linux/uaccess.h>
++#include <linux/platform_device.h>
++#include <linux/clk.h>
++#include <linux/err.h>
++#include <linux/io.h>
++#include <asm/txx9tmr.h>
++
++#define TIMER_MARGIN	60		/* Default is 60 seconds */
++
++static int timeout = TIMER_MARGIN;	/* in seconds */
++module_param(timeout, int, 0);
++MODULE_PARM_DESC(timeout,
++	"Watchdog timeout in seconds. "
++	"(0<timeout<((2^" __MODULE_STRING(TXX9_TIMER_BITS) ")/(IMCLK/256)), "
++	"default=" __MODULE_STRING(TIMER_MARGIN) ")");
++
++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) ")");
++
++#define WD_TIMER_CCD	7	/* 1/256 */
++#define WD_TIMER_CLK	(clk_get_rate(txx9_imclk) / (2 << WD_TIMER_CCD))
++#define WD_MAX_TIMEOUT	((0xffffffff >> (32 - TXX9_TIMER_BITS)) / WD_TIMER_CLK)
++
++static unsigned long txx9wdt_alive;
++static int expect_close;
++static struct txx9_tmr_reg __iomem *txx9wdt_reg;
++static struct clk *txx9_imclk;
++
++static void txx9wdt_ping(void)
++{
++	__raw_writel(TXx9_TMWTMR_TWIE | TXx9_TMWTMR_TWC, &txx9wdt_reg->wtmr);
++}
++
++static void txx9wdt_start(void)
++{
++	__raw_writel(WD_TIMER_CLK * timeout, &txx9wdt_reg->cpra);
++	__raw_writel(WD_TIMER_CCD, &txx9wdt_reg->ccdr);
++	__raw_writel(0, &txx9wdt_reg->tisr);	/* clear pending interrupt */
++	__raw_writel(TXx9_TMTCR_TCE | TXx9_TMTCR_CCDE | TXx9_TMTCR_TMODE_WDOG,
++		     &txx9wdt_reg->tcr);
++	__raw_writel(TXx9_TMWTMR_TWIE | TXx9_TMWTMR_TWC, &txx9wdt_reg->wtmr);
++}
++
++static void txx9wdt_stop(void)
++{
++	__raw_writel(TXx9_TMWTMR_WDIS, &txx9wdt_reg->wtmr);
++	__raw_writel(__raw_readl(&txx9wdt_reg->tcr) & ~TXx9_TMTCR_TCE,
++		     &txx9wdt_reg->tcr);
++}
++
++static int txx9wdt_open(struct inode *inode, struct file *file)
++{
++	if (test_and_set_bit(0, &txx9wdt_alive))
++		return -EBUSY;
++
++	if (__raw_readl(&txx9wdt_reg->tcr) & TXx9_TMTCR_TCE) {
++		clear_bit(0, &txx9wdt_alive);
++		return -EBUSY;
++	}
++
++	if (nowayout)
++		__module_get(THIS_MODULE);
++
++	txx9wdt_start();
++	return nonseekable_open(inode, file);
++}
++
++static int txx9wdt_release(struct inode *inode, struct file *file)
++{
++	if (expect_close)
++		txx9wdt_stop();
++	else {
++		printk(KERN_CRIT "txx9wdt: "
++		       "Unexpected close, not stopping watchdog!\n");
++		txx9wdt_ping();
++	}
++	clear_bit(0, &txx9wdt_alive);
++	expect_close = 0;
++	return 0;
++}
++
++static ssize_t txx9wdt_write(struct file *file, const char __user *data,
++			     size_t len, loff_t *ppos)
++{
++	if (len) {
++		if (!nowayout) {
++			size_t i;
++
++			expect_close = 0;
++			for (i = 0; i != len; i++) {
++				char c;
++				if (get_user(c, data + i))
++					return -EFAULT;
++				if (c == 'V')
++					expect_close = 1;
++			}
++		}
++		txx9wdt_ping();
++	}
++	return len;
++}
++
++static int txx9wdt_ioctl(struct inode *inode, struct file *file,
++	unsigned int cmd, unsigned long arg)
++{
++	void __user *argp = (void __user *)arg;
++	int __user *p = argp;
++	int new_timeout;
++	static struct watchdog_info ident = {
++		.options =		WDIOF_SETTIMEOUT |
++					WDIOF_KEEPALIVEPING |
++					WDIOF_MAGICCLOSE,
++		.firmware_version =	0,
++		.identity =		"Hardware Watchdog for TXx9",
++	};
++
++	switch (cmd) {
++	default:
++		return -ENOTTY;
++	case WDIOC_GETSUPPORT:
++		return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0;
++	case WDIOC_GETSTATUS:
++	case WDIOC_GETBOOTSTATUS:
++		return put_user(0, p);
++	case WDIOC_KEEPALIVE:
++		txx9wdt_ping();
++		return 0;
++	case WDIOC_SETTIMEOUT:
++		if (get_user(new_timeout, p))
++			return -EFAULT;
++		if (new_timeout < 1 || new_timeout > WD_MAX_TIMEOUT)
++			return -EINVAL;
++		timeout = new_timeout;
++		txx9wdt_stop();
++		txx9wdt_start();
++		/* Fall */
++	case WDIOC_GETTIMEOUT:
++		return put_user(timeout, p);
++	}
++}
++
++static int txx9wdt_notify_sys(struct notifier_block *this, unsigned long code,
++	void *unused)
++{
++	if (code == SYS_DOWN || code == SYS_HALT)
++		txx9wdt_stop();
++	return NOTIFY_DONE;
++}
++
++static const struct file_operations txx9wdt_fops = {
++	.owner =	THIS_MODULE,
++	.llseek =	no_llseek,
++	.write =	txx9wdt_write,
++	.ioctl =	txx9wdt_ioctl,
++	.open =		txx9wdt_open,
++	.release =	txx9wdt_release,
++};
++
++static struct miscdevice txx9wdt_miscdev = {
++	.minor =	WATCHDOG_MINOR,
++	.name =		"watchdog",
++	.fops =		&txx9wdt_fops,
++};
++
++static struct notifier_block txx9wdt_notifier = {
++	.notifier_call = txx9wdt_notify_sys
++};
++
++static int __init txx9wdt_probe(struct platform_device *dev)
++{
++	struct resource *res;
++	int ret;
++
++	txx9_imclk = clk_get(NULL, "imbus_clk");
++	if (IS_ERR(txx9_imclk)) {
++		ret = PTR_ERR(txx9_imclk);
++		txx9_imclk = NULL;
++		goto exit;
++	}
++	ret = clk_enable(txx9_imclk);
++	if (ret) {
++		clk_put(txx9_imclk);
++		txx9_imclk = NULL;
++		goto exit;
++	}
++
++	res = platform_get_resource(dev, IORESOURCE_MEM, 0);
++	if (!res)
++		goto exit_busy;
++	if (!devm_request_mem_region(&dev->dev,
++				     res->start, res->end - res->start + 1,
++				     "txx9wdt"))
++		goto exit_busy;
++	txx9wdt_reg = devm_ioremap(&dev->dev,
++				   res->start, res->end - res->start + 1);
++	if (!txx9wdt_reg)
++		goto exit_busy;
++
++	ret = register_reboot_notifier(&txx9wdt_notifier);
++	if (ret)
++		goto exit;
++
++	ret = misc_register(&txx9wdt_miscdev);
++	if (ret) {
++		unregister_reboot_notifier(&txx9wdt_notifier);
++		goto exit;
++	}
++
++	printk(KERN_INFO "Hardware Watchdog Timer for TXx9: "
++	       "timeout=%d sec (max %ld) (nowayout= %d)\n",
++	       timeout, WD_MAX_TIMEOUT, nowayout);
++
++	return 0;
++exit_busy:
++	ret = -EBUSY;
++exit:
++	if (txx9_imclk) {
++		clk_disable(txx9_imclk);
++		clk_put(txx9_imclk);
++	}
++	return ret;
++}
++
++static int __exit txx9wdt_remove(struct platform_device *dev)
++{
++	misc_deregister(&txx9wdt_miscdev);
++	unregister_reboot_notifier(&txx9wdt_notifier);
++	clk_disable(txx9_imclk);
++	clk_put(txx9_imclk);
++	return 0;
++}
++
++static struct platform_driver txx9wdt_driver = {
++	.remove = __exit_p(txx9wdt_remove),
++	.driver = {
++		.name = "txx9wdt",
++		.owner = THIS_MODULE,
++	},
++};
++
++static int __init watchdog_init(void)
++{
++	return platform_driver_probe(&txx9wdt_driver, txx9wdt_probe);
++}
++
++static void __exit watchdog_exit(void)
++{
++	platform_driver_unregister(&txx9wdt_driver);
++}
++
++module_init(watchdog_init);
++module_exit(watchdog_exit);
++
++MODULE_DESCRIPTION("TXx9 Watchdog Driver");
++MODULE_LICENSE("GPL");
++MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
+diff --git a/drivers/watchdog/w83877f_wdt.c b/drivers/watchdog/w83877f_wdt.c
+index bcc9d48..f510a3a 100644
+--- a/drivers/watchdog/w83877f_wdt.c
++++ b/drivers/watchdog/w83877f_wdt.c
+@@ -373,20 +373,20 @@ static int __init w83877f_wdt_init(void)
+ 		goto err_out_region1;
+ 	}
  
-@@ -928,8 +930,7 @@ static inline void scsi_destroy_sdev(struct scsi_device *sdev)
+-	rc = misc_register(&wdt_miscdev);
++	rc = register_reboot_notifier(&wdt_notifier);
+ 	if (rc)
+ 	{
+-		printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
+-			wdt_miscdev.minor, rc);
++		printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
++			rc);
+ 		goto err_out_region2;
+ 	}
  
- #ifdef CONFIG_SCSI_LOGGING
- /** 
-- * scsi_inq_str - print INQUIRY data from min to max index,
-- * strip trailing whitespace
-+ * scsi_inq_str - print INQUIRY data from min to max index, strip trailing whitespace
-  * @buf:   Output buffer with at least end-first+1 bytes of space
-  * @inq:   Inquiry buffer (input)
-  * @first: Offset of string into inq
-@@ -957,9 +958,10 @@ static unsigned char *scsi_inq_str(unsigned char *buf, unsigned char *inq,
-  * scsi_probe_and_add_lun - probe a LUN, if a LUN is found add it
-  * @starget:	pointer to target device structure
-  * @lun:	LUN of target device
-- * @sdevscan:	probe the LUN corresponding to this scsi_device
-- * @sdevnew:	store the value of any new scsi_device allocated
-  * @bflagsp:	store bflags here if not NULL
-+ * @sdevp:	probe the LUN corresponding to this scsi_device
-+ * @rescan:     if nonzero skip some code only needed on first scan
-+ * @hostdata:	passed to scsi_alloc_sdev()
-  *
-  * Description:
-  *     Call scsi_probe_lun, if a LUN with an attached device is found,
-@@ -1110,6 +1112,8 @@ static int scsi_probe_and_add_lun(struct scsi_target *starget,
-  * scsi_sequential_lun_scan - sequentially scan a SCSI target
-  * @starget:	pointer to target structure to scan
-  * @bflags:	black/white list flag for LUN 0
-+ * @scsi_level: Which version of the standard does this device adhere to
-+ * @rescan:     passed to scsi_probe_add_lun()
-  *
-  * Description:
-  *     Generally, scan from LUN 1 (LUN 0 is assumed to already have been
-@@ -1220,7 +1224,7 @@ EXPORT_SYMBOL(scsilun_to_int);
+-	rc = register_reboot_notifier(&wdt_notifier);
++	rc = misc_register(&wdt_miscdev);
+ 	if (rc)
+ 	{
+-		printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
+-			rc);
+-		goto err_out_miscdev;
++		printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
++			wdt_miscdev.minor, rc);
++		goto err_out_reboot;
+ 	}
+ 
+ 	printk(KERN_INFO PFX "WDT driver for W83877F initialised. timeout=%d sec (nowayout=%d)\n",
+@@ -394,8 +394,8 @@ static int __init w83877f_wdt_init(void)
  
- /**
-  * int_to_scsilun: reverts an int into a scsi_lun
-- * @int:        integer to be reverted
-+ * @lun:        integer to be reverted
-  * @scsilun:	struct scsi_lun to be set.
-  *
-  * Description:
-@@ -1252,18 +1256,22 @@ EXPORT_SYMBOL(int_to_scsilun);
+ 	return 0;
  
- /**
-  * scsi_report_lun_scan - Scan using SCSI REPORT LUN results
-- * @sdevscan:	scan the host, channel, and id of this scsi_device
-+ * @starget: which target
-+ * @bflags: Zero or a mix of BLIST_NOLUN, BLIST_REPORTLUN2, or BLIST_NOREPORTLUN
-+ * @rescan: nonzero if we can skip code only needed on first scan
-  *
-  * Description:
-- *     If @sdevscan is for a SCSI-3 or up device, send a REPORT LUN
-- *     command, and scan the resulting list of LUNs by calling
-- *     scsi_probe_and_add_lun.
-+ *   Fast scanning for modern (SCSI-3) devices by sending a REPORT LUN command.
-+ *   Scan the resulting list of LUNs by calling scsi_probe_and_add_lun.
-  *
-- *     Modifies sdevscan->lun.
-+ *   If BLINK_REPORTLUN2 is set, scan a target that supports more than 8
-+ *   LUNs even if it's older than SCSI-3.
-+ *   If BLIST_NOREPORTLUN is set, return 1 always.
-+ *   If BLIST_NOLUN is set, return 0 always.
-  *
-  * Return:
-  *     0: scan completed (or no memory, so further scanning is futile)
-- *     1: no report lun scan, or not configured
-+ *     1: could not scan with REPORT LUN
-  **/
- static int scsi_report_lun_scan(struct scsi_target *starget, int bflags,
- 				int rescan)
-@@ -1481,6 +1489,7 @@ struct scsi_device *__scsi_add_device(struct Scsi_Host *shost, uint channel,
- 	if (scsi_host_scan_allowed(shost))
- 		scsi_probe_and_add_lun(starget, lun, NULL, &sdev, 1, hostdata);
- 	mutex_unlock(&shost->scan_mutex);
-+	transport_configure_device(&starget->dev);
- 	scsi_target_reap(starget);
- 	put_device(&starget->dev);
+-err_out_miscdev:
+-	misc_deregister(&wdt_miscdev);
++err_out_reboot:
++	unregister_reboot_notifier(&wdt_notifier);
+ err_out_region2:
+ 	release_region(WDT_PING,1);
+ err_out_region1:
+diff --git a/drivers/watchdog/w83977f_wdt.c b/drivers/watchdog/w83977f_wdt.c
+index b475529..b209bcd 100644
+--- a/drivers/watchdog/w83977f_wdt.c
++++ b/drivers/watchdog/w83977f_wdt.c
+@@ -494,20 +494,20 @@ static int __init w83977f_wdt_init(void)
+ 		goto err_out;
+ 	}
  
-@@ -1561,6 +1570,7 @@ static void __scsi_scan_target(struct device *parent, unsigned int channel,
-  out_reap:
- 	/* now determine if the target has any children at all
- 	 * and if not, nuke it */
-+	transport_configure_device(&starget->dev);
- 	scsi_target_reap(starget);
+-	rc = misc_register(&wdt_miscdev);
++	rc = register_reboot_notifier(&wdt_notifier);
+ 	if (rc)
+ 	{
+-		printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
+-			wdt_miscdev.minor, rc);
++		printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
++			rc);
+ 		goto err_out_region;
+ 	}
  
- 	put_device(&starget->dev);
-diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
-index 00b3866..ed83cdb 100644
---- a/drivers/scsi/scsi_sysfs.c
-+++ b/drivers/scsi/scsi_sysfs.c
-@@ -1018,6 +1018,7 @@ int scsi_sysfs_add_host(struct Scsi_Host *shost)
+-	rc = register_reboot_notifier(&wdt_notifier);
++	rc = misc_register(&wdt_miscdev);
+ 	if (rc)
+ 	{
+-		printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
+-			rc);
+-		goto err_out_miscdev;
++		printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
++			wdt_miscdev.minor, rc);
++		goto err_out_reboot;
  	}
  
- 	transport_register_device(&shost->shost_gendev);
-+	transport_configure_device(&shost->shost_gendev);
+ 	printk(KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d testmode=%d)\n",
+@@ -515,8 +515,8 @@ static int __init w83977f_wdt_init(void)
+ 
  	return 0;
- }
  
-diff --git a/drivers/scsi/scsi_tgt_if.c b/drivers/scsi/scsi_tgt_if.c
-index 9815a1a..d2557db 100644
---- a/drivers/scsi/scsi_tgt_if.c
-+++ b/drivers/scsi/scsi_tgt_if.c
-@@ -112,7 +112,7 @@ int scsi_tgt_uspace_send_cmd(struct scsi_cmnd *cmd, u64 itn_id,
- 	memset(&ev, 0, sizeof(ev));
- 	ev.p.cmd_req.host_no = shost->host_no;
- 	ev.p.cmd_req.itn_id = itn_id;
--	ev.p.cmd_req.data_len = cmd->request_bufflen;
-+	ev.p.cmd_req.data_len = scsi_bufflen(cmd);
- 	memcpy(ev.p.cmd_req.scb, cmd->cmnd, sizeof(ev.p.cmd_req.scb));
- 	memcpy(ev.p.cmd_req.lun, lun, sizeof(ev.p.cmd_req.lun));
- 	ev.p.cmd_req.attribute = cmd->tag;
-diff --git a/drivers/scsi/scsi_tgt_lib.c b/drivers/scsi/scsi_tgt_lib.c
-index a91761c..93ece8f 100644
---- a/drivers/scsi/scsi_tgt_lib.c
-+++ b/drivers/scsi/scsi_tgt_lib.c
-@@ -180,7 +180,7 @@ static void scsi_tgt_cmd_destroy(struct work_struct *work)
- 		container_of(work, struct scsi_tgt_cmd, work);
- 	struct scsi_cmnd *cmd = tcmd->rq->special;
+-err_out_miscdev:
+-	misc_deregister(&wdt_miscdev);
++err_out_reboot:
++	unregister_reboot_notifier(&wdt_notifier);
+ err_out_region:
+ 	release_region(IO_INDEX_PORT,2);
+ err_out:
+diff --git a/drivers/watchdog/wdt.c b/drivers/watchdog/wdt.c
+index 53d0bb4..756fb15 100644
+--- a/drivers/watchdog/wdt.c
++++ b/drivers/watchdog/wdt.c
+@@ -70,6 +70,8 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" _
+ static int io=0x240;
+ static int irq=11;
+ 
++static DEFINE_SPINLOCK(wdt_lock);
++
+ module_param(io, int, 0);
+ MODULE_PARM_DESC(io, "WDT io port (default=0x240)");
+ module_param(irq, int, 0);
+@@ -109,6 +111,8 @@ static void wdt_ctr_load(int ctr, int val)
  
--	dprintk("cmd %p %d %lu\n", cmd, cmd->sc_data_direction,
-+	dprintk("cmd %p %d %u\n", cmd, cmd->sc_data_direction,
- 		rq_data_dir(cmd->request));
- 	scsi_unmap_user_pages(tcmd);
- 	scsi_host_put_command(scsi_tgt_cmd_to_host(cmd), cmd);
-@@ -327,11 +327,11 @@ static void scsi_tgt_cmd_done(struct scsi_cmnd *cmd)
+ static int wdt_start(void)
  {
- 	struct scsi_tgt_cmd *tcmd = cmd->request->end_io_data;
++	unsigned long flags;
++	spin_lock_irqsave(&wdt_lock, flags);
+ 	inb_p(WDT_DC);			/* Disable watchdog */
+ 	wdt_ctr_mode(0,3);		/* Program CTR0 for Mode 3: Square Wave Generator */
+ 	wdt_ctr_mode(1,2);		/* Program CTR1 for Mode 2: Rate Generator */
+@@ -117,6 +121,7 @@ static int wdt_start(void)
+ 	wdt_ctr_load(1,wd_heartbeat);	/* Heartbeat */
+ 	wdt_ctr_load(2,65535);		/* Length of reset pulse */
+ 	outb_p(0, WDT_DC);		/* Enable watchdog */
++	spin_unlock_irqrestore(&wdt_lock, flags);
+ 	return 0;
+ }
  
--	dprintk("cmd %p %lu\n", cmd, rq_data_dir(cmd->request));
-+	dprintk("cmd %p %u\n", cmd, rq_data_dir(cmd->request));
+@@ -128,9 +133,12 @@ static int wdt_start(void)
  
- 	scsi_tgt_uspace_send_status(cmd, tcmd->itn_id, tcmd->tag);
+ static int wdt_stop (void)
+ {
++	unsigned long flags;
++	spin_lock_irqsave(&wdt_lock, flags);
+ 	/* Turn the card off */
+ 	inb_p(WDT_DC);			/* Disable watchdog */
+ 	wdt_ctr_load(2,0);		/* 0 length reset pulses now */
++	spin_unlock_irqrestore(&wdt_lock, flags);
+ 	return 0;
+ }
  
--	if (cmd->request_buffer)
-+	if (scsi_sglist(cmd))
- 		scsi_free_sgtable(cmd);
+@@ -143,11 +151,14 @@ static int wdt_stop (void)
  
- 	queue_work(scsi_tgtd, &tcmd->work);
-@@ -342,7 +342,7 @@ static int scsi_tgt_transfer_response(struct scsi_cmnd *cmd)
- 	struct Scsi_Host *shost = scsi_tgt_cmd_to_host(cmd);
- 	int err;
+ static int wdt_ping(void)
+ {
++	unsigned long flags;
++	spin_lock_irqsave(&wdt_lock, flags);
+ 	/* Write a watchdog value */
+ 	inb_p(WDT_DC);			/* Disable watchdog */
+ 	wdt_ctr_mode(1,2);		/* Re-Program CTR1 for Mode 2: Rate Generator */
+ 	wdt_ctr_load(1,wd_heartbeat);	/* Heartbeat */
+ 	outb_p(0, WDT_DC);		/* Enable watchdog */
++	spin_unlock_irqrestore(&wdt_lock, flags);
+ 	return 0;
+ }
  
--	dprintk("cmd %p %lu\n", cmd, rq_data_dir(cmd->request));
-+	dprintk("cmd %p %u\n", cmd, rq_data_dir(cmd->request));
+@@ -182,7 +193,12 @@ static int wdt_set_heartbeat(int t)
  
- 	err = shost->hostt->transfer_response(cmd, scsi_tgt_cmd_done);
- 	switch (err) {
-@@ -365,16 +365,12 @@ static int scsi_tgt_init_cmd(struct scsi_cmnd *cmd, gfp_t gfp_mask)
+ static int wdt_get_status(int *status)
+ {
+-	unsigned char new_status=inb_p(WDT_SR);
++	unsigned char new_status;
++	unsigned long flags;
++
++	spin_lock_irqsave(&wdt_lock, flags);
++	new_status = inb_p(WDT_SR);
++	spin_unlock_irqrestore(&wdt_lock, flags);
+ 
+ 	*status=0;
+ 	if (new_status & WDC_SR_ISOI0)
+@@ -214,8 +230,12 @@ static int wdt_get_status(int *status)
  
- 	cmd->request_bufflen = rq->data_len;
+ static int wdt_get_temperature(int *temperature)
+ {
+-	unsigned short c=inb_p(WDT_RT);
++	unsigned short c;
++	unsigned long flags;
  
--	dprintk("cmd %p cnt %d %lu\n", cmd, cmd->use_sg, rq_data_dir(rq));
--	count = blk_rq_map_sg(rq->q, rq, cmd->request_buffer);
--	if (likely(count <= cmd->use_sg)) {
--		cmd->use_sg = count;
--		return 0;
--	}
--
--	eprintk("cmd %p cnt %d\n", cmd, cmd->use_sg);
--	scsi_free_sgtable(cmd);
--	return -EINVAL;
-+	dprintk("cmd %p cnt %d %lu\n", cmd, scsi_sg_count(cmd),
-+		rq_data_dir(rq));
-+	count = blk_rq_map_sg(rq->q, rq, scsi_sglist(cmd));
-+	BUG_ON(count > cmd->use_sg);
-+	cmd->use_sg = count;
-+	return 0;
++	spin_lock_irqsave(&wdt_lock, flags);
++	c = inb_p(WDT_RT);
++	spin_unlock_irqrestore(&wdt_lock, flags);
+ 	*temperature = (c * 11 / 15) + 7;
+ 	return 0;
  }
+@@ -237,7 +257,10 @@ static irqreturn_t wdt_interrupt(int irq, void *dev_id)
+ 	 *	Read the status register see what is up and
+ 	 *	then printk it.
+ 	 */
+-	unsigned char status=inb_p(WDT_SR);
++	unsigned char status;
++
++	spin_lock(&wdt_lock);
++	status = inb_p(WDT_SR);
  
- /* TODO: test this crap and replace bio_map_user with new interface maybe */
-@@ -496,8 +492,8 @@ int scsi_tgt_kspace_exec(int host_no, u64 itn_id, int result, u64 tag,
- 	}
- 	cmd = rq->special;
+ 	printk(KERN_CRIT "WDT status %d\n", status);
  
--	dprintk("cmd %p scb %x result %d len %d bufflen %u %lu %x\n",
--		cmd, cmd->cmnd[0], result, len, cmd->request_bufflen,
-+	dprintk("cmd %p scb %x result %d len %d bufflen %u %u %x\n",
-+		cmd, cmd->cmnd[0], result, len, scsi_bufflen(cmd),
- 		rq_data_dir(rq), cmd->cmnd[0]);
+@@ -265,6 +288,7 @@ static irqreturn_t wdt_interrupt(int irq, void *dev_id)
+ 		printk(KERN_CRIT "Reset in 5ms.\n");
+ #endif
+ 	}
++	spin_unlock(&wdt_lock);
+ 	return IRQ_HANDLED;
+ }
  
- 	if (result == TASK_ABORTED) {
-@@ -617,7 +613,7 @@ int scsi_tgt_kspace_it_nexus_rsp(int host_no, u64 itn_id, int result)
- 	struct Scsi_Host *shost;
- 	int err = -EINVAL;
+diff --git a/drivers/watchdog/wdt977.c b/drivers/watchdog/wdt977.c
+index 9b7f6b6..fb4b876 100644
+--- a/drivers/watchdog/wdt977.c
++++ b/drivers/watchdog/wdt977.c
+@@ -470,20 +470,20 @@ static int __init wd977_init(void)
+ 		}
+ 	}
  
--	dprintk("%d %d %llx\n", host_no, result, (unsigned long long) mid);
-+	dprintk("%d %d%llx\n", host_no, result, (unsigned long long)itn_id);
+-	rc = misc_register(&wdt977_miscdev);
++	rc = register_reboot_notifier(&wdt977_notifier);
+ 	if (rc)
+ 	{
+-		printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
+-			wdt977_miscdev.minor, rc);
++		printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
++			rc);
+ 		goto err_out_region;
+ 	}
  
- 	shost = scsi_host_lookup(host_no);
- 	if (IS_ERR(shost)) {
-diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c
-index 7a7cfe5..b1119da 100644
---- a/drivers/scsi/scsi_transport_fc.c
-+++ b/drivers/scsi/scsi_transport_fc.c
-@@ -481,9 +481,9 @@ MODULE_PARM_DESC(dev_loss_tmo,
- 		 " exceeded, the scsi target is removed. Value should be"
- 		 " between 1 and SCSI_DEVICE_BLOCK_MAX_TIMEOUT.");
+-	rc = register_reboot_notifier(&wdt977_notifier);
++	rc = misc_register(&wdt977_miscdev);
+ 	if (rc)
+ 	{
+-		printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
+-			rc);
+-		goto err_out_miscdev;
++		printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
++			wdt977_miscdev.minor, rc);
++		goto err_out_reboot;
+ 	}
+ 
+ 	printk(KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d, testmode=%i)\n",
+@@ -491,8 +491,8 @@ static int __init wd977_init(void)
  
--/**
-+/*
-  * Netlink Infrastructure
-- **/
-+ */
+ 	return 0;
  
- static atomic_t fc_event_seq;
+-err_out_miscdev:
+-        misc_deregister(&wdt977_miscdev);
++err_out_reboot:
++	unregister_reboot_notifier(&wdt977_notifier);
+ err_out_region:
+ 	if (!machine_is_netwinder())
+ 	        release_region(IO_INDEX_PORT,2);
+diff --git a/fs/Kconfig b/fs/Kconfig
+index 781b47d..9656139 100644
+--- a/fs/Kconfig
++++ b/fs/Kconfig
+@@ -440,14 +440,8 @@ config OCFS2_FS
+ 	  Tools web page:      http://oss.oracle.com/projects/ocfs2-tools
+ 	  OCFS2 mailing lists: http://oss.oracle.com/projects/ocfs2/mailman/
  
-@@ -491,10 +491,10 @@ static atomic_t fc_event_seq;
-  * fc_get_event_number - Obtain the next sequential FC event number
-  *
-  * Notes:
-- *   We could have inline'd this, but it would have required fc_event_seq to
-+ *   We could have inlined this, but it would have required fc_event_seq to
-  *   be exposed. For now, live with the subroutine call.
-  *   Atomic used to avoid lock/unlock...
-- **/
-+ */
- u32
- fc_get_event_number(void)
- {
-@@ -505,7 +505,6 @@ EXPORT_SYMBOL(fc_get_event_number);
+-	  Note: Features which OCFS2 does not support yet:
+-	          - extended attributes
+-	          - quotas
+-	          - cluster aware flock
+-	          - Directory change notification (F_NOTIFY)
+-	          - Distributed Caching (F_SETLEASE/F_GETLEASE/break_lease)
+-	          - POSIX ACLs
+-	          - readpages / writepages (not user visible)
++	  For more information on OCFS2, see the file
++	  <file:Documentation/filesystems/ocfs2.txt>.
  
- /**
-  * fc_host_post_event - called to post an even on an fc_host.
-- *
-  * @shost:		host the event occurred on
-  * @event_number:	fc event number obtained from get_fc_event_number()
-  * @event_code:		fc_host event being posted
-@@ -513,7 +512,7 @@ EXPORT_SYMBOL(fc_get_event_number);
-  *
-  * Notes:
-  *	This routine assumes no locks are held on entry.
-- **/
-+ */
- void
- fc_host_post_event(struct Scsi_Host *shost, u32 event_number,
- 		enum fc_host_event_code event_code, u32 event_data)
-@@ -579,17 +578,16 @@ EXPORT_SYMBOL(fc_host_post_event);
+ config OCFS2_DEBUG_MASKLOG
+ 	bool "OCFS2 logging support"
+@@ -1028,8 +1022,8 @@ config HUGETLB_PAGE
+ 	def_bool HUGETLBFS
  
+ config CONFIGFS_FS
+-	tristate "Userspace-driven configuration filesystem (EXPERIMENTAL)"
+-	depends on SYSFS && EXPERIMENTAL
++	tristate "Userspace-driven configuration filesystem"
++	depends on SYSFS
+ 	help
+ 	  configfs is a ram-based filesystem that provides the converse
+ 	  of sysfs's functionality. Where sysfs is a filesystem-based
+@@ -1905,13 +1899,15 @@ config CIFS
+ 	  file servers such as Windows 2000 (including Windows 2003, NT 4  
+ 	  and Windows XP) as well by Samba (which provides excellent CIFS
+ 	  server support for Linux and many other operating systems). Limited
+-	  support for OS/2 and Windows ME and similar servers is provided as well.
+-
+-	  The intent of the cifs module is to provide an advanced
+-	  network file system client for mounting to CIFS compliant servers,
+-	  including support for dfs (hierarchical name space), secure per-user
+-	  session establishment, safe distributed caching (oplock), optional
+-	  packet signing, Unicode and other internationalization improvements. 
++	  support for OS/2 and Windows ME and similar servers is provided as
++	  well.
++
++	  The cifs module provides an advanced network file system
++	  client for mounting to CIFS compliant servers.  It includes
++	  support for DFS (hierarchical name space), secure per-user
++	  session establishment via Kerberos or NTLM or NTLMv2,
++	  safe distributed caching (oplock), optional packet
++	  signing, Unicode and other internationalization improvements.
+ 	  If you need to mount to Samba or Windows from this machine, say Y.
  
- /**
-- * fc_host_post_vendor_event - called to post a vendor unique event on
-- *                             a fc_host
-- *
-+ * fc_host_post_vendor_event - called to post a vendor unique event on an fc_host
-  * @shost:		host the event occurred on
-  * @event_number:	fc event number obtained from get_fc_event_number()
-  * @data_len:		amount, in bytes, of vendor unique data
-  * @data_buf:		pointer to vendor unique data
-+ * @vendor_id:          Vendor id
-  *
-  * Notes:
-  *	This routine assumes no locks are held on entry.
-- **/
-+ */
- void
- fc_host_post_vendor_event(struct Scsi_Host *shost, u32 event_number,
- 		u32 data_len, char * data_buf, u64 vendor_id)
-@@ -1900,7 +1898,6 @@ static int fc_vport_match(struct attribute_container *cont,
+ config CIFS_STATS
+@@ -1943,7 +1939,8 @@ config CIFS_WEAK_PW_HASH
+ 	  (since 1997) support stronger NTLM (and even NTLMv2 and Kerberos)
+ 	  security mechanisms. These hash the password more securely
+ 	  than the mechanisms used in the older LANMAN version of the
+-          SMB protocol needed to establish sessions with old SMB servers.
++	  SMB protocol but LANMAN based authentication is needed to
++	  establish sessions with some old SMB servers.
  
- /**
-  * fc_timed_out - FC Transport I/O timeout intercept handler
-- *
-  * @scmd:	The SCSI command which timed out
-  *
-  * This routine protects against error handlers getting invoked while a
-@@ -1920,7 +1917,7 @@ static int fc_vport_match(struct attribute_container *cont,
-  *
-  * Notes:
-  *	This routine assumes no locks are held on entry.
-- **/
-+ */
- static enum scsi_eh_timer_return
- fc_timed_out(struct scsi_cmnd *scmd)
- {
-@@ -2133,7 +2130,7 @@ EXPORT_SYMBOL(fc_release_transport);
-  * 	1 - work queued for execution
-  *	0 - work is already queued
-  *	-EINVAL - work queue doesn't exist
-- **/
-+ */
- static int
- fc_queue_work(struct Scsi_Host *shost, struct work_struct *work)
- {
-@@ -2152,7 +2149,7 @@ fc_queue_work(struct Scsi_Host *shost, struct work_struct *work)
- /**
-  * fc_flush_work - Flush a fc_host's workqueue.
-  * @shost:	Pointer to Scsi_Host bound to fc_host.
-- **/
-+ */
- static void
- fc_flush_work(struct Scsi_Host *shost)
- {
-@@ -2175,7 +2172,7 @@ fc_flush_work(struct Scsi_Host *shost)
-  *
-  * Return value:
-  * 	1 on success / 0 already queued / < 0 for error
-- **/
-+ */
- static int
- fc_queue_devloss_work(struct Scsi_Host *shost, struct delayed_work *work,
- 				unsigned long delay)
-@@ -2195,7 +2192,7 @@ fc_queue_devloss_work(struct Scsi_Host *shost, struct delayed_work *work,
- /**
-  * fc_flush_devloss - Flush a fc_host's devloss workqueue.
-  * @shost:	Pointer to Scsi_Host bound to fc_host.
-- **/
-+ */
- static void
- fc_flush_devloss(struct Scsi_Host *shost)
- {
-@@ -2212,21 +2209,20 @@ fc_flush_devloss(struct Scsi_Host *shost)
+ 	  Enabling this option allows the cifs module to mount to older
+ 	  LANMAN based servers such as OS/2 and Windows 95, but such
+@@ -1951,8 +1948,8 @@ config CIFS_WEAK_PW_HASH
+ 	  security mechanisms if you are on a public network.  Unless you
+ 	  have a need to access old SMB servers (and are on a private 
+ 	  network) you probably want to say N.  Even if this support
+-	  is enabled in the kernel build, they will not be used
+-	  automatically. At runtime LANMAN mounts are disabled but
++	  is enabled in the kernel build, LANMAN authentication will not be
++	  used automatically. At runtime LANMAN mounts are disabled but
+ 	  can be set to required (or optional) either in
+ 	  /proc/fs/cifs (see fs/cifs/README for more detail) or via an
+ 	  option on the mount command. This support is disabled by 
+@@ -2018,12 +2015,22 @@ config CIFS_UPCALL
+ 	  depends on CIFS_EXPERIMENTAL
+ 	  depends on KEYS
+ 	  help
+-	    Enables an upcall mechanism for CIFS which will be used to contact
+-	    userspace helper utilities to provide SPNEGO packaged Kerberos
+-	    tickets which are needed to mount to certain secure servers
++	    Enables an upcall mechanism for CIFS which accesses
++	    userspace helper utilities to provide SPNEGO packaged (RFC 4178)
++	    Kerberos tickets which are needed to mount to certain secure servers
+ 	    (for which more secure Kerberos authentication is required). If
+ 	    unsure, say N.
  
++config CIFS_DFS_UPCALL
++	  bool "DFS feature support (EXPERIMENTAL)"
++	  depends on CIFS_EXPERIMENTAL
++	  depends on KEYS
++	  help
++	    Enables an upcall mechanism for CIFS which contacts userspace
++	    helper utilities to provide server name resolution (host names to
++	    IP addresses) which is needed for implicit mounts of DFS junction
++	    points. If unsure, say N.
++
+ config NCP_FS
+ 	tristate "NCP file system support (to mount NetWare volumes)"
+ 	depends on IPX!=n || INET
+@@ -2130,4 +2137,3 @@ source "fs/nls/Kconfig"
+ source "fs/dlm/Kconfig"
  
- /**
-- * fc_remove_host - called to terminate any fc_transport-related elements
-- *                  for a scsi host.
-- * @rport:	remote port to be unblocked.
-+ * fc_remove_host - called to terminate any fc_transport-related elements for a scsi host.
-+ * @shost:	Which &Scsi_Host
-  *
-  * This routine is expected to be called immediately preceeding the
-  * a driver's call to scsi_remove_host().
-  *
-  * WARNING: A driver utilizing the fc_transport, which fails to call
-- *   this routine prior to scsi_remote_host(), will leave dangling
-+ *   this routine prior to scsi_remove_host(), will leave dangling
-  *   objects in /sys/class/fc_remote_ports. Access to any of these
-  *   objects can result in a system crash !!!
-  *
-  * Notes:
-  *	This routine assumes no locks are held on entry.
-- **/
-+ */
- void
- fc_remove_host(struct Scsi_Host *shost)
+ endmenu
+-
+diff --git a/fs/bio.c b/fs/bio.c
+index d59ddbf..242e409 100644
+--- a/fs/bio.c
++++ b/fs/bio.c
+@@ -248,11 +248,13 @@ inline int bio_hw_segments(struct request_queue *q, struct bio *bio)
+  */
+ void __bio_clone(struct bio *bio, struct bio *bio_src)
  {
-@@ -2281,10 +2277,10 @@ EXPORT_SYMBOL(fc_remove_host);
+-	struct request_queue *q = bdev_get_queue(bio_src->bi_bdev);
+-
+ 	memcpy(bio->bi_io_vec, bio_src->bi_io_vec,
+ 		bio_src->bi_max_vecs * sizeof(struct bio_vec));
  
- /**
-  * fc_starget_delete - called to delete the scsi decendents of an rport
-- *                  (target and all sdevs)
-- *
-  * @work:	remote port to be operated on.
-- **/
-+ *
-+ * Deletes target and all sdevs.
-+ */
- static void
- fc_starget_delete(struct work_struct *work)
- {
-@@ -2303,9 +2299,8 @@ fc_starget_delete(struct work_struct *work)
++	/*
++	 * most users will be overriding ->bi_bdev with a new target,
++	 * so we don't set nor calculate new physical/hw segment counts here
++	 */
+ 	bio->bi_sector = bio_src->bi_sector;
+ 	bio->bi_bdev = bio_src->bi_bdev;
+ 	bio->bi_flags |= 1 << BIO_CLONED;
+@@ -260,8 +262,6 @@ void __bio_clone(struct bio *bio, struct bio *bio_src)
+ 	bio->bi_vcnt = bio_src->bi_vcnt;
+ 	bio->bi_size = bio_src->bi_size;
+ 	bio->bi_idx = bio_src->bi_idx;
+-	bio_phys_segments(q, bio);
+-	bio_hw_segments(q, bio);
+ }
  
  /**
-  * fc_rport_final_delete - finish rport termination and delete it.
-- *
-  * @work:	remote port to be deleted.
-- **/
-+ */
- static void
- fc_rport_final_delete(struct work_struct *work)
+diff --git a/fs/block_dev.c b/fs/block_dev.c
+index 993f78c..e48a630 100644
+--- a/fs/block_dev.c
++++ b/fs/block_dev.c
+@@ -738,9 +738,9 @@ EXPORT_SYMBOL(bd_release);
+ static struct kobject *bdev_get_kobj(struct block_device *bdev)
  {
-@@ -2375,7 +2370,7 @@ fc_rport_final_delete(struct work_struct *work)
-  *
-  * Notes:
-  *	This routine assumes no locks are held on entry.
-- **/
-+ */
- static struct fc_rport *
- fc_rport_create(struct Scsi_Host *shost, int channel,
- 	struct fc_rport_identifiers  *ids)
-@@ -2462,8 +2457,7 @@ delete_rport:
+ 	if (bdev->bd_contains != bdev)
+-		return kobject_get(&bdev->bd_part->kobj);
++		return kobject_get(&bdev->bd_part->dev.kobj);
+ 	else
+-		return kobject_get(&bdev->bd_disk->kobj);
++		return kobject_get(&bdev->bd_disk->dev.kobj);
  }
  
- /**
-- * fc_remote_port_add - notifies the fc transport of the existence
-- *		of a remote FC port.
-+ * fc_remote_port_add - notify fc transport of the existence of a remote FC port.
-  * @shost:	scsi host the remote port is connected to.
-  * @channel:	Channel on shost port connected to.
-  * @ids:	The world wide names, fc address, and FC4 port
-@@ -2499,7 +2493,7 @@ delete_rport:
-  *
-  * Notes:
-  *	This routine assumes no locks are held on entry.
-- **/
-+ */
- struct fc_rport *
- fc_remote_port_add(struct Scsi_Host *shost, int channel,
- 	struct fc_rport_identifiers  *ids)
-@@ -2683,19 +2677,18 @@ EXPORT_SYMBOL(fc_remote_port_add);
- 
- 
- /**
-- * fc_remote_port_delete - notifies the fc transport that a remote
-- *		port is no longer in existence.
-+ * fc_remote_port_delete - notifies the fc transport that a remote port is no longer in existence.
-  * @rport:	The remote port that no longer exists
-  *
-  * The LLDD calls this routine to notify the transport that a remote
-  * port is no longer part of the topology. Note: Although a port
-  * may no longer be part of the topology, it may persist in the remote
-  * ports displayed by the fc_host. We do this under 2 conditions:
-- * - If the port was a scsi target, we delay its deletion by "blocking" it.
-+ * 1) If the port was a scsi target, we delay its deletion by "blocking" it.
-  *   This allows the port to temporarily disappear, then reappear without
-  *   disrupting the SCSI device tree attached to it. During the "blocked"
-  *   period the port will still exist.
-- * - If the port was a scsi target and disappears for longer than we
-+ * 2) If the port was a scsi target and disappears for longer than we
-  *   expect, we'll delete the port and the tear down the SCSI device tree
-  *   attached to it. However, we want to semi-persist the target id assigned
-  *   to that port if it eventually does exist. The port structure will
-@@ -2709,7 +2702,8 @@ EXPORT_SYMBOL(fc_remote_port_add);
-  * temporary blocked state. From the LLDD's perspective, the rport no
-  * longer exists. From the SCSI midlayer's perspective, the SCSI target
-  * exists, but all sdevs on it are blocked from further I/O. The following
-- * is then expected:
-+ * is then expected.
-+ *
-  *   If the remote port does not return (signaled by a LLDD call to
-  *   fc_remote_port_add()) within the dev_loss_tmo timeout, then the
-  *   scsi target is removed - killing all outstanding i/o and removing the
-@@ -2731,7 +2725,7 @@ EXPORT_SYMBOL(fc_remote_port_add);
-  *
-  * Notes:
-  *	This routine assumes no locks are held on entry.
-- **/
-+ */
- void
- fc_remote_port_delete(struct fc_rport  *rport)
- {
-@@ -2792,12 +2786,12 @@ fc_remote_port_delete(struct fc_rport  *rport)
- EXPORT_SYMBOL(fc_remote_port_delete);
+ static struct kobject *bdev_get_holder(struct block_device *bdev)
+@@ -1176,7 +1176,7 @@ static int do_open(struct block_device *bdev, struct file *file, int for_part)
+ 				ret = -ENXIO;
+ 				goto out_first;
+ 			}
+-			kobject_get(&p->kobj);
++			kobject_get(&p->dev.kobj);
+ 			bdev->bd_part = p;
+ 			bd_set_size(bdev, (loff_t) p->nr_sects << 9);
+ 		}
+@@ -1299,7 +1299,7 @@ static int __blkdev_put(struct block_device *bdev, int for_part)
+ 		module_put(owner);
  
- /**
-- * fc_remote_port_rolechg - notifies the fc transport that the roles
-- *		on a remote may have changed.
-+ * fc_remote_port_rolechg - notifies the fc transport that the roles on a remote may have changed.
-  * @rport:	The remote port that changed.
-+ * @roles:      New roles for this port.
-  *
-- * The LLDD calls this routine to notify the transport that the roles
-- * on a remote port may have changed. The largest effect of this is
-+ * Description: The LLDD calls this routine to notify the transport that the
-+ * roles on a remote port may have changed. The largest effect of this is
-  * if a port now becomes a FCP Target, it must be allocated a
-  * scsi target id.  If the port is no longer a FCP target, any
-  * scsi target id value assigned to it will persist in case the
-@@ -2810,7 +2804,7 @@ EXPORT_SYMBOL(fc_remote_port_delete);
-  *
-  * Notes:
-  *	This routine assumes no locks are held on entry.
-- **/
-+ */
- void
- fc_remote_port_rolechg(struct fc_rport  *rport, u32 roles)
+ 		if (bdev->bd_contains != bdev) {
+-			kobject_put(&bdev->bd_part->kobj);
++			kobject_put(&bdev->bd_part->dev.kobj);
+ 			bdev->bd_part = NULL;
+ 		}
+ 		bdev->bd_disk = NULL;
+diff --git a/fs/char_dev.c b/fs/char_dev.c
+index c3bfa76..2c7a8b5 100644
+--- a/fs/char_dev.c
++++ b/fs/char_dev.c
+@@ -510,9 +510,8 @@ struct cdev *cdev_alloc(void)
  {
-@@ -2875,12 +2869,12 @@ fc_remote_port_rolechg(struct fc_rport  *rport, u32 roles)
- EXPORT_SYMBOL(fc_remote_port_rolechg);
- 
- /**
-- * fc_timeout_deleted_rport - Timeout handler for a deleted remote port,
-- * 			which we blocked, and has now failed to return
-- * 			in the allotted time.
-- *
-+ * fc_timeout_deleted_rport - Timeout handler for a deleted remote port.
-  * @work:	rport target that failed to reappear in the allotted time.
-- **/
-+ *
-+ * Description: An attempt to delete a remote port blocks, and if it fails
-+ *              to return in the allotted time this gets called.
-+ */
- static void
- fc_timeout_deleted_rport(struct work_struct *work)
+ 	struct cdev *p = kzalloc(sizeof(struct cdev), GFP_KERNEL);
+ 	if (p) {
+-		p->kobj.ktype = &ktype_cdev_dynamic;
+ 		INIT_LIST_HEAD(&p->list);
+-		kobject_init(&p->kobj);
++		kobject_init(&p->kobj, &ktype_cdev_dynamic);
+ 	}
+ 	return p;
+ }
+@@ -529,8 +528,7 @@ void cdev_init(struct cdev *cdev, const struct file_operations *fops)
  {
-@@ -2984,14 +2978,12 @@ fc_timeout_deleted_rport(struct work_struct *work)
+ 	memset(cdev, 0, sizeof *cdev);
+ 	INIT_LIST_HEAD(&cdev->list);
+-	cdev->kobj.ktype = &ktype_cdev_default;
+-	kobject_init(&cdev->kobj);
++	kobject_init(&cdev->kobj, &ktype_cdev_default);
+ 	cdev->ops = fops;
  }
  
- /**
-- * fc_timeout_fail_rport_io - Timeout handler for a fast io failing on a
-- *                       disconnected SCSI target.
-- *
-+ * fc_timeout_fail_rport_io - Timeout handler for a fast io failing on a disconnected SCSI target.
-  * @work:	rport to terminate io on.
-  *
-  * Notes: Only requests the failure of the io, not that all are flushed
-  *    prior to returning.
-- **/
-+ */
- static void
- fc_timeout_fail_rport_io(struct work_struct *work)
- {
-@@ -3008,9 +3000,8 @@ fc_timeout_fail_rport_io(struct work_struct *work)
+diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES
+index a609599..edd2483 100644
+--- a/fs/cifs/CHANGES
++++ b/fs/cifs/CHANGES
+@@ -3,7 +3,10 @@ Version 1.52
+ Fix oops on second mount to server when null auth is used.
+ Enable experimental Kerberos support.  Return writebehind errors on flush
+ and sync so that events like out of disk space get reported properly on
+-cached files.
++cached files. Fix setxattr failure to certain Samba versions. Fix mount
++of second share to disconnected server session (autoreconnect on this).
++Add ability to modify cifs acls for handling chmod (when mounted with
++cifsacl flag).
  
- /**
-  * fc_scsi_scan_rport - called to perform a scsi scan on a remote port.
-- *
-  * @work:	remote port to be scanned.
-- **/
-+ */
- static void
- fc_scsi_scan_rport(struct work_struct *work)
- {
-@@ -3047,7 +3038,7 @@ fc_scsi_scan_rport(struct work_struct *work)
-  *
-  * Notes:
-  *	This routine assumes no locks are held on entry.
-- **/
-+ */
- static int
- fc_vport_create(struct Scsi_Host *shost, int channel, struct device *pdev,
- 	struct fc_vport_identifiers  *ids, struct fc_vport **ret_vport)
-@@ -3172,7 +3163,7 @@ delete_vport:
-  *
-  * Notes:
-  *	This routine assumes no locks are held on entry.
-- **/
-+ */
- int
- fc_vport_terminate(struct fc_vport *vport)
- {
-@@ -3232,9 +3223,8 @@ EXPORT_SYMBOL(fc_vport_terminate);
+ Version 1.51
+ ------------
+diff --git a/fs/cifs/Makefile b/fs/cifs/Makefile
+index 45e42fb..6ba43fb 100644
+--- a/fs/cifs/Makefile
++++ b/fs/cifs/Makefile
+@@ -9,3 +9,5 @@ cifs-y := cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o inode.o \
+ 	  readdir.o ioctl.o sess.o export.o cifsacl.o
  
- /**
-  * fc_vport_sched_delete - workq-based delete request for a vport
-- *
-  * @work:	vport to be deleted.
-- **/
-+ */
- static void
- fc_vport_sched_delete(struct work_struct *work)
- {
-diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c
-index 5428d15..ef0e742 100644
---- a/drivers/scsi/scsi_transport_iscsi.c
-+++ b/drivers/scsi/scsi_transport_iscsi.c
-@@ -30,10 +30,10 @@
- #include <scsi/scsi_transport_iscsi.h>
- #include <scsi/iscsi_if.h>
+ cifs-$(CONFIG_CIFS_UPCALL) += cifs_spnego.o
++
++cifs-$(CONFIG_CIFS_DFS_UPCALL) += dns_resolve.o cifs_dfs_ref.o
+diff --git a/fs/cifs/README b/fs/cifs/README
+index bf11329..c623e2f 100644
+--- a/fs/cifs/README
++++ b/fs/cifs/README
+@@ -56,7 +56,8 @@ the CIFS VFS web site) copy it to the same directory in which mount.smbfs and
+ similar files reside (usually /sbin).  Although the helper software is not  
+ required, mount.cifs is recommended.  Eventually the Samba 3.0 utility program 
+ "net" may also be helpful since it may someday provide easier mount syntax for
+-users who are used to Windows e.g.  net use <mount point> <UNC name or cifs URL>
++users who are used to Windows e.g.
++	net use <mount point> <UNC name or cifs URL>
+ Note that running the Winbind pam/nss module (logon service) on all of your
+ Linux clients is useful in mapping Uids and Gids consistently across the
+ domain to the proper network user.  The mount.cifs mount helper can be
+@@ -248,7 +249,7 @@ A partial list of the supported mount options follows:
+ 		the CIFS session.
+   password	The user password.  If the mount helper is
+ 		installed, the user will be prompted for password
+-		if it is not supplied.
++		if not supplied.
+   ip		The ip address of the target server
+   unc		The target server Universal Network Name (export) to 
+ 		mount.	
+@@ -283,7 +284,7 @@ A partial list of the supported mount options follows:
+ 		can be enabled by specifying file_mode and dir_mode on 
+ 		the client.  Note that the mount.cifs helper must be
+ 		at version 1.10 or higher to support specifying the uid
+-		(or gid) in non-numberic form.
++		(or gid) in non-numeric form.
+   gid		Set the default gid for inodes (similar to above).
+   file_mode     If CIFS Unix extensions are not supported by the server
+ 		this overrides the default mode for file inodes.
+@@ -417,9 +418,10 @@ A partial list of the supported mount options follows:
+   acl   	Allow setfacl and getfacl to manage posix ACLs if server
+ 		supports them.  (default)
+   noacl 	Do not allow setfacl and getfacl calls on this mount
+-  user_xattr    Allow getting and setting user xattrs as OS/2 EAs (extended
+-		attributes) to the server (default) e.g. via setfattr 
+-		and getfattr utilities. 
++  user_xattr    Allow getting and setting user xattrs (those attributes whose
++		name begins with "user." or "os2.") as OS/2 EAs (extended
++		attributes) to the server.  This allows support of the
++		setfattr and getfattr utilities. (default)
+   nouser_xattr  Do not allow getfattr/setfattr to get/set/list xattrs 
+   mapchars      Translate six of the seven reserved characters (not backslash)
+ 			*?<>|:
+@@ -434,6 +436,7 @@ A partial list of the supported mount options follows:
+  nomapchars     Do not translate any of these seven characters (default).
+  nocase         Request case insensitive path name matching (case
+ 		sensitive is the default if the server suports it).
++		(mount option "ignorecase" is identical to "nocase")
+  posixpaths     If CIFS Unix extensions are supported, attempt to
+ 		negotiate posix path name support which allows certain
+ 		characters forbidden in typical CIFS filenames, without
+@@ -485,6 +488,9 @@ A partial list of the supported mount options follows:
+ 			ntlmv2i Use NTLMv2 password hashing with packet signing
+ 			lanman  (if configured in kernel config) use older
+ 				lanman hash
++hard		Retry file operations if server is not responding
++soft		Limit retries to unresponsive servers (usually only
++		one retry) before returning an error.  (default)
  
--#define ISCSI_SESSION_ATTRS 15
-+#define ISCSI_SESSION_ATTRS 18
- #define ISCSI_CONN_ATTRS 11
- #define ISCSI_HOST_ATTRS 4
--#define ISCSI_TRANSPORT_VERSION "2.0-724"
-+#define ISCSI_TRANSPORT_VERSION "2.0-867"
+ The mount.cifs mount helper also accepts a few mount options before -o
+ including:
+@@ -535,8 +541,8 @@ SecurityFlags		Flags which control security negotiation and
+ 			must use NTLM					0x02002
+ 			may use NTLMv2					0x00004
+ 			must use NTLMv2					0x04004
+-			may use Kerberos security (not implemented yet) 0x00008
+-			must use Kerberos (not implemented yet)         0x08008
++			may use Kerberos security			0x00008
++			must use Kerberos				0x08008
+ 			may use lanman (weak) password hash  		0x00010
+ 			must use lanman password hash			0x10010
+ 			may use plaintext passwords    			0x00020
+@@ -626,6 +632,6 @@ returned success.
+ 	
+ Also note that "cat /proc/fs/cifs/DebugData" will display information about 
+ the active sessions and the shares that are mounted.
+-Enabling Kerberos (extended security) works when CONFIG_CIFS_EXPERIMENTAL is enabled
+-but requires a user space helper (from the Samba project). NTLM and NTLMv2 and
+-LANMAN support do not require this helpr.
++Enabling Kerberos (extended security) works when CONFIG_CIFS_EXPERIMENTAL is
++on but requires a user space helper (from the Samba project). NTLM and NTLMv2 and
++LANMAN support do not require this helper.
+diff --git a/fs/cifs/TODO b/fs/cifs/TODO
+index a8852c2..92c9fea 100644
+--- a/fs/cifs/TODO
++++ b/fs/cifs/TODO
+@@ -1,4 +1,4 @@
+-Version 1.49 April 26, 2007
++Version 1.52 January 3, 2008
  
- struct iscsi_internal {
- 	int daemon_pid;
-@@ -50,6 +50,7 @@ struct iscsi_internal {
- };
+ A Partial List of Missing Features
+ ==================================
+@@ -16,16 +16,14 @@ SecurityDescriptors
+ c) Better pam/winbind integration (e.g. to handle uid mapping
+ better)
  
- static atomic_t iscsi_session_nr; /* sysfs session id for next new session */
-+static struct workqueue_struct *iscsi_eh_timer_workq;
+-d) Verify that Kerberos signing works
+-
+-e) Cleanup now unneeded SessSetup code in
++d) Cleanup now unneeded SessSetup code in
+ fs/cifs/connect.c and add back in NTLMSSP code if any servers
+ need it
  
- /*
-  * list of registered transports and lock that must
-@@ -115,6 +116,8 @@ static struct attribute_group iscsi_transport_group = {
- 	.attrs = iscsi_transport_attrs,
- };
+-f) MD5-HMAC signing SMB PDUs when SPNEGO style SessionSetup 
+-used (Kerberos or NTLMSSP). Signing alreadyimplemented for NTLM
+-and raw NTLMSSP already. This is important when enabling
+-extended security and mounting to Windows 2003 Servers
++e) ms-dfs and ms-dfs host name resolution cleanup
++
++f) fix NTLMv2 signing when two mounts with different users to same
++server.
  
+ g) Directory entry caching relies on a 1 second timer, rather than 
+ using FindNotify or equivalent.  - (started)
+diff --git a/fs/cifs/cifs_dfs_ref.c b/fs/cifs/cifs_dfs_ref.c
+new file mode 100644
+index 0000000..413ee23
+--- /dev/null
++++ b/fs/cifs/cifs_dfs_ref.c
+@@ -0,0 +1,377 @@
++/*
++ *   Contains the CIFS DFS referral mounting routines used for handling
++ *   traversal via DFS junction point
++ *
++ *   Copyright (c) 2007 Igor Mammedov
++ *   Copyright (C) International Business Machines  Corp., 2008
++ *   Author(s): Igor Mammedov (niallain at gmail.com)
++ *		Steve French (sfrench at us.ibm.com)
++ *   This program is free software; you can redistribute it and/or
++ *   modify it under the terms of the GNU General Public License
++ *   as published by the Free Software Foundation; either version
++ *   2 of the License, or (at your option) any later version.
++ */
++
++#include <linux/dcache.h>
++#include <linux/mount.h>
++#include <linux/namei.h>
++#include <linux/vfs.h>
++#include <linux/fs.h>
++#include "cifsglob.h"
++#include "cifsproto.h"
++#include "cifsfs.h"
++#include "dns_resolve.h"
++#include "cifs_debug.h"
++
++LIST_HEAD(cifs_dfs_automount_list);
++
++/*
++ * DFS functions
++*/
++
++void dfs_shrink_umount_helper(struct vfsmount *vfsmnt)
++{
++	mark_mounts_for_expiry(&cifs_dfs_automount_list);
++	mark_mounts_for_expiry(&cifs_dfs_automount_list);
++	shrink_submounts(vfsmnt, &cifs_dfs_automount_list);
++}
++
++/**
++ * cifs_get_share_name	-	extracts share name from UNC
++ * @node_name:	pointer to UNC string
++ *
++ * Extracts sharename form full UNC.
++ * i.e. strips from UNC trailing path that is not part of share
++ * name and fixup missing '\' in the begining of DFS node refferal
++ * if neccessary.
++ * Returns pointer to share name on success or NULL on error.
++ * Caller is responsible for freeing returned string.
++ */
++static char *cifs_get_share_name(const char *node_name)
++{
++	int len;
++	char *UNC;
++	char *pSep;
++
++	len = strlen(node_name);
++	UNC = kmalloc(len+2 /*for term null and additional \ if it's missed */,
++			 GFP_KERNEL);
++	if (!UNC)
++		return NULL;
++
++	/* get share name and server name */
++	if (node_name[1] != '\\') {
++		UNC[0] = '\\';
++		strncpy(UNC+1, node_name, len);
++		len++;
++		UNC[len] = 0;
++	} else {
++		strncpy(UNC, node_name, len);
++		UNC[len] = 0;
++	}
++
++	/* find server name end */
++	pSep = memchr(UNC+2, '\\', len-2);
++	if (!pSep) {
++		cERROR(1, ("%s: no server name end in node name: %s",
++			__FUNCTION__, node_name));
++		kfree(UNC);
++		return NULL;
++	}
++
++	/* find sharename end */
++	pSep++;
++	pSep = memchr(UNC+(pSep-UNC), '\\', len-(pSep-UNC));
++	if (!pSep) {
++		cERROR(1, ("%s:2 cant find share name in node name: %s",
++			__FUNCTION__, node_name));
++		kfree(UNC);
++		return NULL;
++	}
++	/* trim path up to sharename end
++	 *          * now we have share name in UNC */
++	*pSep = 0;
++
++	return UNC;
++}
++
++
++/**
++ * compose_mount_options	-	creates mount options for refferral
++ * @sb_mountdata:	parent/root DFS mount options (template)
++ * @ref_unc:		refferral server UNC
++ * @devname:		pointer for saving device name
++ *
++ * creates mount options for submount based on template options sb_mountdata
++ * and replacing unc,ip,prefixpath options with ones we've got form ref_unc.
++ *
++ * Returns: pointer to new mount options or ERR_PTR.
++ * Caller is responcible for freeing retunrned value if it is not error.
++ */
++static char *compose_mount_options(const char *sb_mountdata,
++				   const char *ref_unc,
++				   char **devname)
++{
++	int rc;
++	char *mountdata;
++	int md_len;
++	char *tkn_e;
++	char *srvIP = NULL;
++	char sep = ',';
++	int off, noff;
++
++	if (sb_mountdata == NULL)
++		return ERR_PTR(-EINVAL);
++
++	*devname = cifs_get_share_name(ref_unc);
++	rc = dns_resolve_server_name_to_ip(*devname, &srvIP);
++	if (rc != 0) {
++		cERROR(1, ("%s: Failed to resolve server part of %s to IP",
++			  __FUNCTION__, *devname));
++		mountdata = ERR_PTR(rc);
++		goto compose_mount_options_out;
++	}
++	md_len = strlen(sb_mountdata) + strlen(srvIP) + strlen(ref_unc) + 3;
++	mountdata = kzalloc(md_len+1, GFP_KERNEL);
++	if (mountdata == NULL) {
++		mountdata = ERR_PTR(-ENOMEM);
++		goto compose_mount_options_out;
++	}
++
++	/* copy all options except of unc,ip,prefixpath */
++	off = 0;
++	if (strncmp(sb_mountdata, "sep=", 4) == 0) {
++			sep = sb_mountdata[4];
++			strncpy(mountdata, sb_mountdata, 5);
++			off += 5;
++	}
++	while ((tkn_e = strchr(sb_mountdata+off, sep))) {
++		noff = (tkn_e - (sb_mountdata+off)) + 1;
++		if (strnicmp(sb_mountdata+off, "unc=", 4) == 0) {
++			off += noff;
++			continue;
++		}
++		if (strnicmp(sb_mountdata+off, "ip=", 3) == 0) {
++			off += noff;
++			continue;
++		}
++		if (strnicmp(sb_mountdata+off, "prefixpath=", 3) == 0) {
++			off += noff;
++			continue;
++		}
++		strncat(mountdata, sb_mountdata+off, noff);
++		off += noff;
++	}
++	strcat(mountdata, sb_mountdata+off);
++	mountdata[md_len] = '\0';
++
++	/* copy new IP and ref share name */
++	strcat(mountdata, ",ip=");
++	strcat(mountdata, srvIP);
++	strcat(mountdata, ",unc=");
++	strcat(mountdata, *devname);
++
++	/* find & copy prefixpath */
++	tkn_e = strchr(ref_unc+2, '\\');
++	if (tkn_e) {
++		tkn_e = strchr(tkn_e+1, '\\');
++		if (tkn_e) {
++			strcat(mountdata, ",prefixpath=");
++			strcat(mountdata, tkn_e);
++		}
++	}
++
++	/*cFYI(1,("%s: parent mountdata: %s", __FUNCTION__,sb_mountdata));*/
++	/*cFYI(1, ("%s: submount mountdata: %s", __FUNCTION__, mountdata ));*/
++
++compose_mount_options_out:
++	kfree(srvIP);
++	return mountdata;
++}
++
++
++static struct vfsmount *cifs_dfs_do_refmount(const struct vfsmount *mnt_parent,
++		struct dentry *dentry, char *ref_unc)
++{
++	struct cifs_sb_info *cifs_sb;
++	struct vfsmount *mnt;
++	char *mountdata;
++	char *devname = NULL;
++
++	cifs_sb = CIFS_SB(dentry->d_inode->i_sb);
++	mountdata = compose_mount_options(cifs_sb->mountdata,
++						ref_unc, &devname);
++
++	if (IS_ERR(mountdata))
++		return (struct vfsmount *)mountdata;
++
++	mnt = vfs_kern_mount(&cifs_fs_type, 0, devname, mountdata);
++	kfree(mountdata);
++	kfree(devname);
++	return mnt;
++
++}
++
++static char *build_full_dfs_path_from_dentry(struct dentry *dentry)
++{
++	char *full_path = NULL;
++	char *search_path;
++	char *tmp_path;
++	size_t l_max_len;
++	struct cifs_sb_info *cifs_sb;
++
++	if (dentry->d_inode == NULL)
++		return NULL;
++
++	cifs_sb = CIFS_SB(dentry->d_inode->i_sb);
++
++	if (cifs_sb->tcon == NULL)
++		return NULL;
++
++	search_path = build_path_from_dentry(dentry);
++	if (search_path == NULL)
++		return NULL;
++
++	if (cifs_sb->tcon->Flags & SMB_SHARE_IS_IN_DFS) {
++		/* we should use full path name to correct working with DFS */
++		l_max_len = strnlen(cifs_sb->tcon->treeName, MAX_TREE_SIZE+1) +
++					strnlen(search_path, MAX_PATHCONF) + 1;
++		tmp_path = kmalloc(l_max_len, GFP_KERNEL);
++		if (tmp_path == NULL) {
++			kfree(search_path);
++			return NULL;
++		}
++		strncpy(tmp_path, cifs_sb->tcon->treeName, l_max_len);
++		strcat(tmp_path, search_path);
++		tmp_path[l_max_len-1] = 0;
++		full_path = tmp_path;
++		kfree(search_path);
++	} else {
++		full_path = search_path;
++	}
++	return full_path;
++}
++
++static int add_mount_helper(struct vfsmount *newmnt, struct nameidata *nd,
++				struct list_head *mntlist)
++{
++	/* stolen from afs code */
++	int err;
++
++	mntget(newmnt);
++	err = do_add_mount(newmnt, nd, nd->mnt->mnt_flags, mntlist);
++	switch (err) {
++	case 0:
++		dput(nd->dentry);
++		mntput(nd->mnt);
++		nd->mnt = newmnt;
++		nd->dentry = dget(newmnt->mnt_root);
++		break;
++	case -EBUSY:
++		/* someone else made a mount here whilst we were busy */
++		while (d_mountpoint(nd->dentry) &&
++		       follow_down(&nd->mnt, &nd->dentry))
++			;
++		err = 0;
++	default:
++		mntput(newmnt);
++		break;
++	}
++	return err;
++}
++
++static void dump_referral(const struct dfs_info3_param *ref)
++{
++	cFYI(1, ("DFS: ref path: %s", ref->path_name));
++	cFYI(1, ("DFS: node path: %s", ref->node_name));
++	cFYI(1, ("DFS: fl: %hd, srv_type: %hd", ref->flags, ref->server_type));
++	cFYI(1, ("DFS: ref_flags: %hd, path_consumed: %hd", ref->ref_flag,
++				ref->PathConsumed));
++}
++
++
++static void*
++cifs_dfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd)
++{
++	struct dfs_info3_param *referrals = NULL;
++	unsigned int num_referrals = 0;
++	struct cifs_sb_info *cifs_sb;
++	struct cifsSesInfo *ses;
++	char *full_path = NULL;
++	int xid, i;
++	int rc = 0;
++	struct vfsmount *mnt = ERR_PTR(-ENOENT);
 +
++	cFYI(1, ("in %s", __FUNCTION__));
++	BUG_ON(IS_ROOT(dentry));
 +
- static int iscsi_setup_host(struct transport_container *tc, struct device *dev,
- 			    struct class_device *cdev)
- {
-@@ -124,13 +127,30 @@ static int iscsi_setup_host(struct transport_container *tc, struct device *dev,
- 	memset(ihost, 0, sizeof(*ihost));
- 	INIT_LIST_HEAD(&ihost->sessions);
- 	mutex_init(&ihost->mutex);
++	xid = GetXid();
 +
-+	snprintf(ihost->unbind_workq_name, KOBJ_NAME_LEN, "iscsi_unbind_%d",
-+		shost->host_no);
-+	ihost->unbind_workq = create_singlethread_workqueue(
-+						ihost->unbind_workq_name);
-+	if (!ihost->unbind_workq)
-+		return -ENOMEM;
-+	return 0;
++	dput(nd->dentry);
++	nd->dentry = dget(dentry);
++
++	cifs_sb = CIFS_SB(dentry->d_inode->i_sb);
++	ses = cifs_sb->tcon->ses;
++
++	if (!ses) {
++		rc = -EINVAL;
++		goto out_err;
++	}
++
++	full_path = build_full_dfs_path_from_dentry(dentry);
++	if (full_path == NULL) {
++		rc = -ENOMEM;
++		goto out_err;
++	}
++
++	rc = get_dfs_path(xid, ses , full_path, cifs_sb->local_nls,
++		&num_referrals, &referrals,
++		cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
++
++	for (i = 0; i < num_referrals; i++) {
++		dump_referral(referrals+i);
++		/* connect to a storage node */
++		if (referrals[i].flags & DFSREF_STORAGE_SERVER) {
++			int len;
++			len = strlen(referrals[i].node_name);
++			if (len < 2) {
++				cERROR(1, ("%s: Net Address path too short: %s",
++					__FUNCTION__, referrals[i].node_name));
++				rc = -EINVAL;
++				goto out_err;
++			}
++			mnt = cifs_dfs_do_refmount(nd->mnt, nd->dentry,
++						referrals[i].node_name);
++			cFYI(1, ("%s: cifs_dfs_do_refmount:%s , mnt:%p",
++					 __FUNCTION__,
++					referrals[i].node_name, mnt));
++
++			/* complete mount procedure if we accured submount */
++			if (!IS_ERR(mnt))
++				break;
++		}
++	}
++
++	/* we need it cause for() above could exit without valid submount */
++	rc = PTR_ERR(mnt);
++	if (IS_ERR(mnt))
++		goto out_err;
++
++	nd->mnt->mnt_flags |= MNT_SHRINKABLE;
++	rc = add_mount_helper(mnt, nd, &cifs_dfs_automount_list);
++
++out:
++	FreeXid(xid);
++	free_dfs_info_array(referrals, num_referrals);
++	kfree(full_path);
++	cFYI(1, ("leaving %s" , __FUNCTION__));
++	return ERR_PTR(rc);
++out_err:
++	path_release(nd);
++	goto out;
 +}
 +
-+static int iscsi_remove_host(struct transport_container *tc, struct device *dev,
-+			     struct class_device *cdev)
-+{
-+	struct Scsi_Host *shost = dev_to_shost(dev);
-+	struct iscsi_host *ihost = shost->shost_data;
++struct inode_operations cifs_dfs_referral_inode_operations = {
++	.follow_link = cifs_dfs_follow_mountpoint,
++};
 +
-+	destroy_workqueue(ihost->unbind_workq);
- 	return 0;
- }
+diff --git a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h
+index 34af556..8ad2330 100644
+--- a/fs/cifs/cifs_fs_sb.h
++++ b/fs/cifs/cifs_fs_sb.h
+@@ -43,6 +43,9 @@ struct cifs_sb_info {
+ 	mode_t	mnt_dir_mode;
+ 	int     mnt_cifs_flags;
+ 	int	prepathlen;
+-	char   *prepath;
++	char   *prepath; /* relative path under the share to mount to */
++#ifdef CONFIG_CIFS_DFS_UPCALL
++	char   *mountdata; /* mount options received at mount time */
++#endif
+ };
+ #endif				/* _CIFS_FS_SB_H */
+diff --git a/fs/cifs/cifs_spnego.c b/fs/cifs/cifs_spnego.c
+index 1529d2b..d543acc 100644
+--- a/fs/cifs/cifs_spnego.c
++++ b/fs/cifs/cifs_spnego.c
+@@ -122,11 +122,13 @@ cifs_get_spnego_key(struct cifsSesInfo *sesInfo)
+ 	cFYI(1, ("key description = %s", description));
+ 	spnego_key = request_key(&cifs_spnego_key_type, description, "");
  
- static DECLARE_TRANSPORT_CLASS(iscsi_host_class,
- 			       "iscsi_host",
- 			       iscsi_setup_host,
--			       NULL,
-+			       iscsi_remove_host,
- 			       NULL);
++#ifdef CONFIG_CIFS_DEBUG2
+ 	if (cifsFYI && !IS_ERR(spnego_key)) {
+ 		struct cifs_spnego_msg *msg = spnego_key->payload.data;
+-		cifs_dump_mem("SPNEGO reply blob:", msg->data,
+-				msg->secblob_len + msg->sesskey_len);
++		cifs_dump_mem("SPNEGO reply blob:", msg->data, min(1024,
++				msg->secblob_len + msg->sesskey_len));
+ 	}
++#endif /* CONFIG_CIFS_DEBUG2 */
  
- static DECLARE_TRANSPORT_CLASS(iscsi_session_class,
-@@ -252,7 +272,7 @@ static void session_recovery_timedout(struct work_struct *work)
- void iscsi_unblock_session(struct iscsi_cls_session *session)
- {
- 	if (!cancel_delayed_work(&session->recovery_work))
--		flush_scheduled_work();
-+		flush_workqueue(iscsi_eh_timer_workq);
- 	scsi_target_unblock(&session->dev);
- }
- EXPORT_SYMBOL_GPL(iscsi_unblock_session);
-@@ -260,11 +280,40 @@ EXPORT_SYMBOL_GPL(iscsi_unblock_session);
- void iscsi_block_session(struct iscsi_cls_session *session)
- {
- 	scsi_target_block(&session->dev);
--	schedule_delayed_work(&session->recovery_work,
--			     session->recovery_tmo * HZ);
-+	queue_delayed_work(iscsi_eh_timer_workq, &session->recovery_work,
-+			   session->recovery_tmo * HZ);
+ out:
+ 	kfree(description);
+diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c
+index c312adc..a7035bd 100644
+--- a/fs/cifs/cifsacl.c
++++ b/fs/cifs/cifsacl.c
+@@ -129,6 +129,54 @@ int compare_sids(const struct cifs_sid *ctsid, const struct cifs_sid *cwsid)
+ 	return (1); /* sids compare/match */
  }
- EXPORT_SYMBOL_GPL(iscsi_block_session);
  
-+static void __iscsi_unbind_session(struct work_struct *work)
++
++/* copy ntsd, owner sid, and group sid from a security descriptor to another */
++static void copy_sec_desc(const struct cifs_ntsd *pntsd,
++				struct cifs_ntsd *pnntsd, __u32 sidsoffset)
 +{
-+	struct iscsi_cls_session *session =
-+			container_of(work, struct iscsi_cls_session,
-+				     unbind_work);
-+	struct Scsi_Host *shost = iscsi_session_to_shost(session);
-+	struct iscsi_host *ihost = shost->shost_data;
++	int i;
 +
-+	/* Prevent new scans and make sure scanning is not in progress */
-+	mutex_lock(&ihost->mutex);
-+	if (list_empty(&session->host_list)) {
-+		mutex_unlock(&ihost->mutex);
-+		return;
-+	}
-+	list_del_init(&session->host_list);
-+	mutex_unlock(&ihost->mutex);
++	struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
++	struct cifs_sid *nowner_sid_ptr, *ngroup_sid_ptr;
 +
-+	scsi_remove_target(&session->dev);
-+	iscsi_session_event(session, ISCSI_KEVENT_UNBIND_SESSION);
-+}
++	/* copy security descriptor control portion */
++	pnntsd->revision = pntsd->revision;
++	pnntsd->type = pntsd->type;
++	pnntsd->dacloffset = cpu_to_le32(sizeof(struct cifs_ntsd));
++	pnntsd->sacloffset = 0;
++	pnntsd->osidoffset = cpu_to_le32(sidsoffset);
++	pnntsd->gsidoffset = cpu_to_le32(sidsoffset + sizeof(struct cifs_sid));
 +
-+static int iscsi_unbind_session(struct iscsi_cls_session *session)
-+{
-+	struct Scsi_Host *shost = iscsi_session_to_shost(session);
-+	struct iscsi_host *ihost = shost->shost_data;
++	/* copy owner sid */
++	owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
++				le32_to_cpu(pntsd->osidoffset));
++	nowner_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset);
 +
-+	return queue_work(ihost->unbind_workq, &session->unbind_work);
-+}
++	nowner_sid_ptr->revision = owner_sid_ptr->revision;
++	nowner_sid_ptr->num_subauth = owner_sid_ptr->num_subauth;
++	for (i = 0; i < 6; i++)
++		nowner_sid_ptr->authority[i] = owner_sid_ptr->authority[i];
++	for (i = 0; i < 5; i++)
++		nowner_sid_ptr->sub_auth[i] = owner_sid_ptr->sub_auth[i];
 +
- struct iscsi_cls_session *
- iscsi_alloc_session(struct Scsi_Host *shost,
- 		    struct iscsi_transport *transport)
-@@ -281,6 +330,7 @@ iscsi_alloc_session(struct Scsi_Host *shost,
- 	INIT_DELAYED_WORK(&session->recovery_work, session_recovery_timedout);
- 	INIT_LIST_HEAD(&session->host_list);
- 	INIT_LIST_HEAD(&session->sess_list);
-+	INIT_WORK(&session->unbind_work, __iscsi_unbind_session);
- 
- 	/* this is released in the dev's release function */
- 	scsi_host_get(shost);
-@@ -297,6 +347,7 @@ int iscsi_add_session(struct iscsi_cls_session *session, unsigned int target_id)
- {
- 	struct Scsi_Host *shost = iscsi_session_to_shost(session);
- 	struct iscsi_host *ihost;
-+	unsigned long flags;
- 	int err;
- 
- 	ihost = shost->shost_data;
-@@ -313,9 +364,15 @@ int iscsi_add_session(struct iscsi_cls_session *session, unsigned int target_id)
- 	}
- 	transport_register_device(&session->dev);
- 
-+	spin_lock_irqsave(&sesslock, flags);
-+	list_add(&session->sess_list, &sesslist);
-+	spin_unlock_irqrestore(&sesslock, flags);
++	/* copy group sid */
++	group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
++				le32_to_cpu(pntsd->gsidoffset));
++	ngroup_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset +
++					sizeof(struct cifs_sid));
 +
- 	mutex_lock(&ihost->mutex);
- 	list_add(&session->host_list, &ihost->sessions);
- 	mutex_unlock(&ihost->mutex);
++	ngroup_sid_ptr->revision = group_sid_ptr->revision;
++	ngroup_sid_ptr->num_subauth = group_sid_ptr->num_subauth;
++	for (i = 0; i < 6; i++)
++		ngroup_sid_ptr->authority[i] = group_sid_ptr->authority[i];
++	for (i = 0; i < 5; i++)
++		ngroup_sid_ptr->sub_auth[i] =
++				cpu_to_le32(group_sid_ptr->sub_auth[i]);
 +
-+	iscsi_session_event(session, ISCSI_KEVENT_CREATE_SESSION);
- 	return 0;
- 
- release_host:
-@@ -328,9 +385,10 @@ EXPORT_SYMBOL_GPL(iscsi_add_session);
-  * iscsi_create_session - create iscsi class session
-  * @shost: scsi host
-  * @transport: iscsi transport
-+ * @target_id: which target
-  *
-  * This can be called from a LLD or iscsi_transport.
-- **/
-+ */
- struct iscsi_cls_session *
- iscsi_create_session(struct Scsi_Host *shost,
- 		     struct iscsi_transport *transport,
-@@ -350,19 +408,58 @@ iscsi_create_session(struct Scsi_Host *shost,
++	return;
++}
++
++
+ /*
+    change posix mode to reflect permissions
+    pmode is the existing mode (we only want to overwrite part of this
+@@ -220,6 +268,33 @@ static void mode_to_access_flags(umode_t mode, umode_t bits_to_use,
+ 	return;
  }
- EXPORT_SYMBOL_GPL(iscsi_create_session);
  
-+static void iscsi_conn_release(struct device *dev)
++static __le16 fill_ace_for_sid(struct cifs_ace *pntace,
++			const struct cifs_sid *psid, __u64 nmode, umode_t bits)
 +{
-+	struct iscsi_cls_conn *conn = iscsi_dev_to_conn(dev);
-+	struct device *parent = conn->dev.parent;
++	int i;
++	__u16 size = 0;
++	__u32 access_req = 0;
 +
-+	kfree(conn);
-+	put_device(parent);
-+}
++	pntace->type = ACCESS_ALLOWED;
++	pntace->flags = 0x0;
++	mode_to_access_flags(nmode, bits, &access_req);
++	if (!access_req)
++		access_req = SET_MINIMUM_RIGHTS;
++	pntace->access_req = cpu_to_le32(access_req);
 +
-+static int iscsi_is_conn_dev(const struct device *dev)
-+{
-+	return dev->release == iscsi_conn_release;
-+}
++	pntace->sid.revision = psid->revision;
++	pntace->sid.num_subauth = psid->num_subauth;
++	for (i = 0; i < 6; i++)
++		pntace->sid.authority[i] = psid->authority[i];
++	for (i = 0; i < psid->num_subauth; i++)
++		pntace->sid.sub_auth[i] = psid->sub_auth[i];
 +
-+static int iscsi_iter_destroy_conn_fn(struct device *dev, void *data)
-+{
-+	if (!iscsi_is_conn_dev(dev))
-+		return 0;
-+	return iscsi_destroy_conn(iscsi_dev_to_conn(dev));
++	size = 1 + 1 + 2 + 4 + 1 + 1 + 6 + (psid->num_subauth * 4);
++	pntace->size = cpu_to_le16(size);
++
++	return (size);
 +}
 +
- void iscsi_remove_session(struct iscsi_cls_session *session)
- {
- 	struct Scsi_Host *shost = iscsi_session_to_shost(session);
- 	struct iscsi_host *ihost = shost->shost_data;
-+	unsigned long flags;
-+	int err;
- 
--	if (!cancel_delayed_work(&session->recovery_work))
--		flush_scheduled_work();
-+	spin_lock_irqsave(&sesslock, flags);
-+	list_del(&session->sess_list);
-+	spin_unlock_irqrestore(&sesslock, flags);
- 
--	mutex_lock(&ihost->mutex);
--	list_del(&session->host_list);
--	mutex_unlock(&ihost->mutex);
-+	/*
-+	 * If we are blocked let commands flow again. The lld or iscsi
-+	 * layer should set up the queuecommand to fail commands.
-+	 */
-+	iscsi_unblock_session(session);
-+	iscsi_unbind_session(session);
-+	/*
-+	 * If the session dropped while removing devices then we need to make
-+	 * sure it is not blocked
-+	 */
-+	if (!cancel_delayed_work(&session->recovery_work))
-+		flush_workqueue(iscsi_eh_timer_workq);
-+	flush_workqueue(ihost->unbind_workq);
- 
--	scsi_remove_target(&session->dev);
-+	/* hw iscsi may not have removed all connections from session */
-+	err = device_for_each_child(&session->dev, NULL,
-+				    iscsi_iter_destroy_conn_fn);
-+	if (err)
-+		dev_printk(KERN_ERR, &session->dev, "iscsi: Could not delete "
-+			   "all connections for session. Error %d.\n", err);
- 
- 	transport_unregister_device(&session->dev);
- 	device_del(&session->dev);
-@@ -371,9 +468,9 @@ EXPORT_SYMBOL_GPL(iscsi_remove_session);
- 
- void iscsi_free_session(struct iscsi_cls_session *session)
- {
-+	iscsi_session_event(session, ISCSI_KEVENT_DESTROY_SESSION);
- 	put_device(&session->dev);
- }
--
- EXPORT_SYMBOL_GPL(iscsi_free_session);
  
- /**
-@@ -382,7 +479,7 @@ EXPORT_SYMBOL_GPL(iscsi_free_session);
-  *
-  * Can be called by a LLD or iscsi_transport. There must not be
-  * any running connections.
-- **/
-+ */
- int iscsi_destroy_session(struct iscsi_cls_session *session)
- {
- 	iscsi_remove_session(session);
-@@ -391,20 +488,6 @@ int iscsi_destroy_session(struct iscsi_cls_session *session)
+ #ifdef CONFIG_CIFS_DEBUG2
+ static void dump_ace(struct cifs_ace *pace, char *end_of_acl)
+@@ -243,7 +318,7 @@ static void dump_ace(struct cifs_ace *pace, char *end_of_acl)
+ 		int i;
+ 		cFYI(1, ("ACE revision %d num_auth %d type %d flags %d size %d",
+ 			pace->sid.revision, pace->sid.num_subauth, pace->type,
+-			pace->flags, pace->size));
++			pace->flags, le16_to_cpu(pace->size)));
+ 		for (i = 0; i < num_subauth; ++i) {
+ 			cFYI(1, ("ACE sub_auth[%d]: 0x%x", i,
+ 				le32_to_cpu(pace->sid.sub_auth[i])));
+@@ -346,6 +421,28 @@ static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
  }
- EXPORT_SYMBOL_GPL(iscsi_destroy_session);
  
--static void iscsi_conn_release(struct device *dev)
--{
--	struct iscsi_cls_conn *conn = iscsi_dev_to_conn(dev);
--	struct device *parent = conn->dev.parent;
--
--	kfree(conn);
--	put_device(parent);
--}
--
--static int iscsi_is_conn_dev(const struct device *dev)
--{
--	return dev->release == iscsi_conn_release;
--}
--
- /**
-  * iscsi_create_conn - create iscsi class connection
-  * @session: iscsi cls session
-@@ -418,12 +501,13 @@ static int iscsi_is_conn_dev(const struct device *dev)
-  * for software iscsi we could be trying to preallocate a connection struct
-  * in which case there could be two connection structs and cid would be
-  * non-zero.
-- **/
-+ */
- struct iscsi_cls_conn *
- iscsi_create_conn(struct iscsi_cls_session *session, uint32_t cid)
- {
- 	struct iscsi_transport *transport = session->transport;
- 	struct iscsi_cls_conn *conn;
-+	unsigned long flags;
- 	int err;
  
- 	conn = kzalloc(sizeof(*conn) + transport->conndata_size, GFP_KERNEL);
-@@ -452,6 +536,11 @@ iscsi_create_conn(struct iscsi_cls_session *session, uint32_t cid)
- 		goto release_parent_ref;
- 	}
- 	transport_register_device(&conn->dev);
++static int set_chmod_dacl(struct cifs_acl *pndacl, struct cifs_sid *pownersid,
++			struct cifs_sid *pgrpsid, __u64 nmode)
++{
++	__le16 size = 0;
++	struct cifs_acl *pnndacl;
 +
-+	spin_lock_irqsave(&connlock, flags);
-+	list_add(&conn->conn_list, &connlist);
-+	conn->active = 1;
-+	spin_unlock_irqrestore(&connlock, flags);
- 	return conn;
- 
- release_parent_ref:
-@@ -465,17 +554,23 @@ EXPORT_SYMBOL_GPL(iscsi_create_conn);
- 
- /**
-  * iscsi_destroy_conn - destroy iscsi class connection
-- * @session: iscsi cls session
-+ * @conn: iscsi cls session
-  *
-  * This can be called from a LLD or iscsi_transport.
-- **/
-+ */
- int iscsi_destroy_conn(struct iscsi_cls_conn *conn)
- {
-+	unsigned long flags;
++	pnndacl = (struct cifs_acl *)((char *)pndacl + sizeof(struct cifs_acl));
 +
-+	spin_lock_irqsave(&connlock, flags);
-+	conn->active = 0;
-+	list_del(&conn->conn_list);
-+	spin_unlock_irqrestore(&connlock, flags);
++	size += fill_ace_for_sid((struct cifs_ace *) ((char *)pnndacl + size),
++					pownersid, nmode, S_IRWXU);
++	size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size),
++					pgrpsid, nmode, S_IRWXG);
++	size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size),
++					 &sid_everyone, nmode, S_IRWXO);
 +
- 	transport_unregister_device(&conn->dev);
- 	device_unregister(&conn->dev);
- 	return 0;
- }
--
- EXPORT_SYMBOL_GPL(iscsi_destroy_conn);
- 
- /*
-@@ -685,132 +780,74 @@ iscsi_if_get_stats(struct iscsi_transport *transport, struct nlmsghdr *nlh)
- }
- 
- /**
-- * iscsi_if_destroy_session_done - send session destr. completion event
-- * @conn: last connection for session
-- *
-- * This is called by HW iscsi LLDs to notify userpsace that its HW has
-- * removed a session.
-- **/
--int iscsi_if_destroy_session_done(struct iscsi_cls_conn *conn)
-+ * iscsi_session_event - send session destr. completion event
-+ * @session: iscsi class session
-+ * @event: type of event
-+ */
-+int iscsi_session_event(struct iscsi_cls_session *session,
-+			enum iscsi_uevent_e event)
- {
- 	struct iscsi_internal *priv;
--	struct iscsi_cls_session *session;
- 	struct Scsi_Host *shost;
- 	struct iscsi_uevent *ev;
- 	struct sk_buff  *skb;
- 	struct nlmsghdr *nlh;
--	unsigned long flags;
- 	int rc, len = NLMSG_SPACE(sizeof(*ev));
- 
--	priv = iscsi_if_transport_lookup(conn->transport);
-+	priv = iscsi_if_transport_lookup(session->transport);
- 	if (!priv)
- 		return -EINVAL;
--
--	session = iscsi_dev_to_session(conn->dev.parent);
- 	shost = iscsi_session_to_shost(session);
- 
- 	skb = alloc_skb(len, GFP_KERNEL);
- 	if (!skb) {
--		dev_printk(KERN_ERR, &conn->dev, "Cannot notify userspace of "
--			  "session creation event\n");
-+		dev_printk(KERN_ERR, &session->dev, "Cannot notify userspace "
-+			  "of session event %u\n", event);
- 		return -ENOMEM;
- 	}
- 
- 	nlh = __nlmsg_put(skb, priv->daemon_pid, 0, 0, (len - sizeof(*nlh)), 0);
- 	ev = NLMSG_DATA(nlh);
--	ev->transport_handle = iscsi_handle(conn->transport);
--	ev->type = ISCSI_KEVENT_DESTROY_SESSION;
--	ev->r.d_session.host_no = shost->host_no;
--	ev->r.d_session.sid = session->sid;
--
--	/*
--	 * this will occur if the daemon is not up, so we just warn
--	 * the user and when the daemon is restarted it will handle it
--	 */
--	rc = iscsi_broadcast_skb(skb, GFP_KERNEL);
--	if (rc < 0)
--		dev_printk(KERN_ERR, &conn->dev, "Cannot notify userspace of "
--			  "session destruction event. Check iscsi daemon\n");
--
--	spin_lock_irqsave(&sesslock, flags);
--	list_del(&session->sess_list);
--	spin_unlock_irqrestore(&sesslock, flags);
-+	ev->transport_handle = iscsi_handle(session->transport);
- 
--	spin_lock_irqsave(&connlock, flags);
--	conn->active = 0;
--	list_del(&conn->conn_list);
--	spin_unlock_irqrestore(&connlock, flags);
--
--	return rc;
--}
--EXPORT_SYMBOL_GPL(iscsi_if_destroy_session_done);
--
--/**
-- * iscsi_if_create_session_done - send session creation completion event
-- * @conn: leading connection for session
-- *
-- * This is called by HW iscsi LLDs to notify userpsace that its HW has
-- * created a session or a existing session is back in the logged in state.
-- **/
--int iscsi_if_create_session_done(struct iscsi_cls_conn *conn)
--{
--	struct iscsi_internal *priv;
--	struct iscsi_cls_session *session;
--	struct Scsi_Host *shost;
--	struct iscsi_uevent *ev;
--	struct sk_buff  *skb;
--	struct nlmsghdr *nlh;
--	unsigned long flags;
--	int rc, len = NLMSG_SPACE(sizeof(*ev));
--
--	priv = iscsi_if_transport_lookup(conn->transport);
--	if (!priv)
-+	ev->type = event;
-+	switch (event) {
-+	case ISCSI_KEVENT_DESTROY_SESSION:
-+		ev->r.d_session.host_no = shost->host_no;
-+		ev->r.d_session.sid = session->sid;
-+		break;
-+	case ISCSI_KEVENT_CREATE_SESSION:
-+		ev->r.c_session_ret.host_no = shost->host_no;
-+		ev->r.c_session_ret.sid = session->sid;
-+		break;
-+	case ISCSI_KEVENT_UNBIND_SESSION:
-+		ev->r.unbind_session.host_no = shost->host_no;
-+		ev->r.unbind_session.sid = session->sid;
-+		break;
-+	default:
-+		dev_printk(KERN_ERR, &session->dev, "Invalid event %u.\n",
-+			   event);
-+		kfree_skb(skb);
- 		return -EINVAL;
--
--	session = iscsi_dev_to_session(conn->dev.parent);
--	shost = iscsi_session_to_shost(session);
--
--	skb = alloc_skb(len, GFP_KERNEL);
--	if (!skb) {
--		dev_printk(KERN_ERR, &conn->dev, "Cannot notify userspace of "
--			  "session creation event\n");
--		return -ENOMEM;
- 	}
- 
--	nlh = __nlmsg_put(skb, priv->daemon_pid, 0, 0, (len - sizeof(*nlh)), 0);
--	ev = NLMSG_DATA(nlh);
--	ev->transport_handle = iscsi_handle(conn->transport);
--	ev->type = ISCSI_UEVENT_CREATE_SESSION;
--	ev->r.c_session_ret.host_no = shost->host_no;
--	ev->r.c_session_ret.sid = session->sid;
--
- 	/*
- 	 * this will occur if the daemon is not up, so we just warn
- 	 * the user and when the daemon is restarted it will handle it
- 	 */
- 	rc = iscsi_broadcast_skb(skb, GFP_KERNEL);
- 	if (rc < 0)
--		dev_printk(KERN_ERR, &conn->dev, "Cannot notify userspace of "
--			  "session creation event. Check iscsi daemon\n");
--
--	spin_lock_irqsave(&sesslock, flags);
--	list_add(&session->sess_list, &sesslist);
--	spin_unlock_irqrestore(&sesslock, flags);
--
--	spin_lock_irqsave(&connlock, flags);
--	list_add(&conn->conn_list, &connlist);
--	conn->active = 1;
--	spin_unlock_irqrestore(&connlock, flags);
-+		dev_printk(KERN_ERR, &session->dev, "Cannot notify userspace "
-+			  "of session event %u. Check iscsi daemon\n", event);
- 	return rc;
- }
--EXPORT_SYMBOL_GPL(iscsi_if_create_session_done);
-+EXPORT_SYMBOL_GPL(iscsi_session_event);
- 
- static int
- iscsi_if_create_session(struct iscsi_internal *priv, struct iscsi_uevent *ev)
- {
- 	struct iscsi_transport *transport = priv->iscsi_transport;
- 	struct iscsi_cls_session *session;
--	unsigned long flags;
- 	uint32_t hostno;
- 
- 	session = transport->create_session(transport, &priv->t,
-@@ -821,10 +858,6 @@ iscsi_if_create_session(struct iscsi_internal *priv, struct iscsi_uevent *ev)
- 	if (!session)
- 		return -ENOMEM;
- 
--	spin_lock_irqsave(&sesslock, flags);
--	list_add(&session->sess_list, &sesslist);
--	spin_unlock_irqrestore(&sesslock, flags);
--
- 	ev->r.c_session_ret.host_no = hostno;
- 	ev->r.c_session_ret.sid = session->sid;
- 	return 0;
-@@ -835,7 +868,6 @@ iscsi_if_create_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev)
- {
- 	struct iscsi_cls_conn *conn;
- 	struct iscsi_cls_session *session;
--	unsigned long flags;
- 
- 	session = iscsi_session_lookup(ev->u.c_conn.sid);
- 	if (!session) {
-@@ -854,28 +886,17 @@ iscsi_if_create_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev)
- 
- 	ev->r.c_conn_ret.sid = session->sid;
- 	ev->r.c_conn_ret.cid = conn->cid;
--
--	spin_lock_irqsave(&connlock, flags);
--	list_add(&conn->conn_list, &connlist);
--	conn->active = 1;
--	spin_unlock_irqrestore(&connlock, flags);
--
- 	return 0;
- }
- 
- static int
- iscsi_if_destroy_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev)
- {
--	unsigned long flags;
- 	struct iscsi_cls_conn *conn;
- 
- 	conn = iscsi_conn_lookup(ev->u.d_conn.sid, ev->u.d_conn.cid);
- 	if (!conn)
- 		return -EINVAL;
--	spin_lock_irqsave(&connlock, flags);
--	conn->active = 0;
--	list_del(&conn->conn_list);
--	spin_unlock_irqrestore(&connlock, flags);
- 
- 	if (transport->destroy_conn)
- 		transport->destroy_conn(conn);
-@@ -1002,7 +1023,6 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
- 	struct iscsi_internal *priv;
- 	struct iscsi_cls_session *session;
- 	struct iscsi_cls_conn *conn;
--	unsigned long flags;
- 
- 	priv = iscsi_if_transport_lookup(iscsi_ptr(ev->transport_handle));
- 	if (!priv)
-@@ -1020,13 +1040,16 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
- 		break;
- 	case ISCSI_UEVENT_DESTROY_SESSION:
- 		session = iscsi_session_lookup(ev->u.d_session.sid);
--		if (session) {
--			spin_lock_irqsave(&sesslock, flags);
--			list_del(&session->sess_list);
--			spin_unlock_irqrestore(&sesslock, flags);
--
-+		if (session)
- 			transport->destroy_session(session);
--		} else
-+		else
-+			err = -EINVAL;
-+		break;
-+	case ISCSI_UEVENT_UNBIND_SESSION:
-+		session = iscsi_session_lookup(ev->u.d_session.sid);
-+		if (session)
-+			iscsi_unbind_session(session);
-+		else
- 			err = -EINVAL;
- 		break;
- 	case ISCSI_UEVENT_CREATE_CONN:
-@@ -1179,6 +1202,8 @@ iscsi_conn_attr(port, ISCSI_PARAM_CONN_PORT);
- iscsi_conn_attr(exp_statsn, ISCSI_PARAM_EXP_STATSN);
- iscsi_conn_attr(persistent_address, ISCSI_PARAM_PERSISTENT_ADDRESS);
- iscsi_conn_attr(address, ISCSI_PARAM_CONN_ADDRESS);
-+iscsi_conn_attr(ping_tmo, ISCSI_PARAM_PING_TMO);
-+iscsi_conn_attr(recv_tmo, ISCSI_PARAM_RECV_TMO);
- 
- #define iscsi_cdev_to_session(_cdev) \
- 	iscsi_dev_to_session(_cdev->dev)
-@@ -1217,6 +1242,9 @@ iscsi_session_attr(username, ISCSI_PARAM_USERNAME, 1);
- iscsi_session_attr(username_in, ISCSI_PARAM_USERNAME_IN, 1);
- iscsi_session_attr(password, ISCSI_PARAM_PASSWORD, 1);
- iscsi_session_attr(password_in, ISCSI_PARAM_PASSWORD_IN, 1);
-+iscsi_session_attr(fast_abort, ISCSI_PARAM_FAST_ABORT, 0);
-+iscsi_session_attr(abort_tmo, ISCSI_PARAM_ABORT_TMO, 0);
-+iscsi_session_attr(lu_reset_tmo, ISCSI_PARAM_LU_RESET_TMO, 0);
- 
- #define iscsi_priv_session_attr_show(field, format)			\
- static ssize_t								\
-@@ -1413,6 +1441,8 @@ iscsi_register_transport(struct iscsi_transport *tt)
- 	SETUP_CONN_RD_ATTR(exp_statsn, ISCSI_EXP_STATSN);
- 	SETUP_CONN_RD_ATTR(persistent_address, ISCSI_PERSISTENT_ADDRESS);
- 	SETUP_CONN_RD_ATTR(persistent_port, ISCSI_PERSISTENT_PORT);
-+	SETUP_CONN_RD_ATTR(ping_tmo, ISCSI_PING_TMO);
-+	SETUP_CONN_RD_ATTR(recv_tmo, ISCSI_RECV_TMO);
- 
- 	BUG_ON(count > ISCSI_CONN_ATTRS);
- 	priv->conn_attrs[count] = NULL;
-@@ -1438,6 +1468,9 @@ iscsi_register_transport(struct iscsi_transport *tt)
- 	SETUP_SESSION_RD_ATTR(password_in, ISCSI_USERNAME_IN);
- 	SETUP_SESSION_RD_ATTR(username, ISCSI_PASSWORD);
- 	SETUP_SESSION_RD_ATTR(username_in, ISCSI_PASSWORD_IN);
-+	SETUP_SESSION_RD_ATTR(fast_abort, ISCSI_FAST_ABORT);
-+	SETUP_SESSION_RD_ATTR(abort_tmo, ISCSI_ABORT_TMO);
-+	SETUP_SESSION_RD_ATTR(lu_reset_tmo,ISCSI_LU_RESET_TMO);
- 	SETUP_PRIV_SESSION_RD_ATTR(recovery_tmo);
- 
- 	BUG_ON(count > ISCSI_SESSION_ATTRS);
-@@ -1518,8 +1551,14 @@ static __init int iscsi_transport_init(void)
- 		goto unregister_session_class;
- 	}
- 
-+	iscsi_eh_timer_workq = create_singlethread_workqueue("iscsi_eh");
-+	if (!iscsi_eh_timer_workq)
-+		goto release_nls;
++	pndacl->size = cpu_to_le16(size + sizeof(struct cifs_acl));
++	pndacl->num_aces = 3;
 +
- 	return 0;
- 
-+release_nls:
-+	sock_release(nls->sk_socket);
- unregister_session_class:
- 	transport_class_unregister(&iscsi_session_class);
- unregister_conn_class:
-@@ -1533,6 +1572,7 @@ unregister_transport_class:
- 
- static void __exit iscsi_transport_exit(void)
++	return (0);
++}
++
++
+ static int parse_sid(struct cifs_sid *psid, char *end_of_acl)
  {
-+	destroy_workqueue(iscsi_eh_timer_workq);
- 	sock_release(nls->sk_socket);
- 	transport_class_unregister(&iscsi_connection_class);
- 	transport_class_unregister(&iscsi_session_class);
-diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.c
-index 3120f4b..f2149d0 100644
---- a/drivers/scsi/scsi_transport_sas.c
-+++ b/drivers/scsi/scsi_transport_sas.c
-@@ -173,6 +173,7 @@ static void sas_smp_request(struct request_queue *q, struct Scsi_Host *shost,
- 
- 		handler = to_sas_internal(shost->transportt)->f->smp_handler;
- 		ret = handler(shost, rphy, req);
-+		req->errors = ret;
- 
- 		spin_lock_irq(q->queue_lock);
- 
-@@ -323,7 +324,7 @@ static int do_sas_phy_delete(struct device *dev, void *data)
- }
- 
- /**
-- * sas_remove_children  --  tear down a devices SAS data structures
-+ * sas_remove_children  -  tear down a devices SAS data structures
-  * @dev:	device belonging to the sas object
-  *
-  * Removes all SAS PHYs and remote PHYs for a given object
-@@ -336,7 +337,7 @@ void sas_remove_children(struct device *dev)
- EXPORT_SYMBOL(sas_remove_children);
- 
- /**
-- * sas_remove_host  --  tear down a Scsi_Host's SAS data structures
-+ * sas_remove_host  -  tear down a Scsi_Host's SAS data structures
-  * @shost:	Scsi Host that is torn down
-  *
-  * Removes all SAS PHYs and remote PHYs for a given Scsi_Host.
-@@ -577,7 +578,7 @@ static void sas_phy_release(struct device *dev)
+ 	/* BB need to add parm so we can store the SID BB */
+@@ -432,6 +529,46 @@ static int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len,
  }
  
- /**
-- * sas_phy_alloc  --  allocates and initialize a SAS PHY structure
-+ * sas_phy_alloc  -  allocates and initialize a SAS PHY structure
-  * @parent:	Parent device
-  * @number:	Phy index
-  *
-@@ -618,7 +619,7 @@ struct sas_phy *sas_phy_alloc(struct device *parent, int number)
- EXPORT_SYMBOL(sas_phy_alloc);
- 
- /**
-- * sas_phy_add  --  add a SAS PHY to the device hierarchy
-+ * sas_phy_add  -  add a SAS PHY to the device hierarchy
-  * @phy:	The PHY to be added
-  *
-  * Publishes a SAS PHY to the rest of the system.
-@@ -638,7 +639,7 @@ int sas_phy_add(struct sas_phy *phy)
- EXPORT_SYMBOL(sas_phy_add);
- 
- /**
-- * sas_phy_free  --  free a SAS PHY
-+ * sas_phy_free  -  free a SAS PHY
-  * @phy:	SAS PHY to free
-  *
-  * Frees the specified SAS PHY.
-@@ -655,7 +656,7 @@ void sas_phy_free(struct sas_phy *phy)
- EXPORT_SYMBOL(sas_phy_free);
- 
- /**
-- * sas_phy_delete  --  remove SAS PHY
-+ * sas_phy_delete  -  remove SAS PHY
-  * @phy:	SAS PHY to remove
-  *
-  * Removes the specified SAS PHY.  If the SAS PHY has an
-@@ -677,7 +678,7 @@ sas_phy_delete(struct sas_phy *phy)
- EXPORT_SYMBOL(sas_phy_delete);
- 
- /**
-- * scsi_is_sas_phy  --  check if a struct device represents a SAS PHY
-+ * scsi_is_sas_phy  -  check if a struct device represents a SAS PHY
-  * @dev:	device to check
-  *
-  * Returns:
-@@ -843,7 +844,6 @@ EXPORT_SYMBOL(sas_port_alloc_num);
- 
- /**
-  * sas_port_add - add a SAS port to the device hierarchy
-- *
-  * @port:	port to be added
-  *
-  * publishes a port to the rest of the system
-@@ -868,7 +868,7 @@ int sas_port_add(struct sas_port *port)
- EXPORT_SYMBOL(sas_port_add);
- 
- /**
-- * sas_port_free  --  free a SAS PORT
-+ * sas_port_free  -  free a SAS PORT
-  * @port:	SAS PORT to free
-  *
-  * Frees the specified SAS PORT.
-@@ -885,7 +885,7 @@ void sas_port_free(struct sas_port *port)
- EXPORT_SYMBOL(sas_port_free);
- 
- /**
-- * sas_port_delete  --  remove SAS PORT
-+ * sas_port_delete  -  remove SAS PORT
-  * @port:	SAS PORT to remove
-  *
-  * Removes the specified SAS PORT.  If the SAS PORT has an
-@@ -924,7 +924,7 @@ void sas_port_delete(struct sas_port *port)
- EXPORT_SYMBOL(sas_port_delete);
- 
- /**
-- * scsi_is_sas_port --  check if a struct device represents a SAS port
-+ * scsi_is_sas_port -  check if a struct device represents a SAS port
-  * @dev:	device to check
-  *
-  * Returns:
-@@ -1309,6 +1309,7 @@ static void sas_rphy_initialize(struct sas_rphy *rphy)
- 
- /**
-  * sas_end_device_alloc - allocate an rphy for an end device
-+ * @parent: which port
-  *
-  * Allocates an SAS remote PHY structure, connected to @parent.
-  *
-@@ -1345,6 +1346,8 @@ EXPORT_SYMBOL(sas_end_device_alloc);
- 
- /**
-  * sas_expander_alloc - allocate an rphy for an end device
-+ * @parent: which port
-+ * @type: SAS_EDGE_EXPANDER_DEVICE or SAS_FANOUT_EXPANDER_DEVICE
-  *
-  * Allocates an SAS remote PHY structure, connected to @parent.
-  *
-@@ -1383,7 +1386,7 @@ struct sas_rphy *sas_expander_alloc(struct sas_port *parent,
- EXPORT_SYMBOL(sas_expander_alloc);
- 
- /**
-- * sas_rphy_add  --  add a SAS remote PHY to the device hierarchy
-+ * sas_rphy_add  -  add a SAS remote PHY to the device hierarchy
-  * @rphy:	The remote PHY to be added
-  *
-  * Publishes a SAS remote PHY to the rest of the system.
-@@ -1430,8 +1433,8 @@ int sas_rphy_add(struct sas_rphy *rphy)
- EXPORT_SYMBOL(sas_rphy_add);
- 
- /**
-- * sas_rphy_free  --  free a SAS remote PHY
-- * @rphy	SAS remote PHY to free
-+ * sas_rphy_free  -  free a SAS remote PHY
-+ * @rphy: SAS remote PHY to free
-  *
-  * Frees the specified SAS remote PHY.
-  *
-@@ -1459,7 +1462,7 @@ void sas_rphy_free(struct sas_rphy *rphy)
- EXPORT_SYMBOL(sas_rphy_free);
- 
- /**
-- * sas_rphy_delete  --  remove and free SAS remote PHY
-+ * sas_rphy_delete  -  remove and free SAS remote PHY
-  * @rphy:	SAS remote PHY to remove and free
-  *
-  * Removes the specified SAS remote PHY and frees it.
-@@ -1473,7 +1476,7 @@ sas_rphy_delete(struct sas_rphy *rphy)
- EXPORT_SYMBOL(sas_rphy_delete);
- 
- /**
-- * sas_rphy_remove  --  remove SAS remote PHY
-+ * sas_rphy_remove  -  remove SAS remote PHY
-  * @rphy:	SAS remote phy to remove
-  *
-  * Removes the specified SAS remote PHY.
-@@ -1504,7 +1507,7 @@ sas_rphy_remove(struct sas_rphy *rphy)
- EXPORT_SYMBOL(sas_rphy_remove);
- 
- /**
-- * scsi_is_sas_rphy  --  check if a struct device represents a SAS remote PHY
-+ * scsi_is_sas_rphy  -  check if a struct device represents a SAS remote PHY
-  * @dev:	device to check
-  *
-  * Returns:
-@@ -1604,7 +1607,7 @@ static int sas_user_scan(struct Scsi_Host *shost, uint channel,
- 	SETUP_TEMPLATE(expander_attrs, expander_##field, S_IRUGO, 1)
- 
- /**
-- * sas_attach_transport  --  instantiate SAS transport template
-+ * sas_attach_transport  -  instantiate SAS transport template
-  * @ft:		SAS transport class function template
-  */
- struct scsi_transport_template *
-@@ -1715,7 +1718,7 @@ sas_attach_transport(struct sas_function_template *ft)
- EXPORT_SYMBOL(sas_attach_transport);
- 
- /**
-- * sas_release_transport  --  release SAS transport template instance
-+ * sas_release_transport  -  release SAS transport template instance
-  * @t:		transport template instance
-  */
- void sas_release_transport(struct scsi_transport_template *t)
-diff --git a/drivers/scsi/scsi_transport_spi.c b/drivers/scsi/scsi_transport_spi.c
-index 4df21c9..1fb6031 100644
---- a/drivers/scsi/scsi_transport_spi.c
-+++ b/drivers/scsi/scsi_transport_spi.c
-@@ -52,13 +52,6 @@
- struct spi_internal {
- 	struct scsi_transport_template t;
- 	struct spi_function_template *f;
--	/* The actual attributes */
--	struct class_device_attribute private_attrs[SPI_NUM_ATTRS];
--	/* The array of null terminated pointers to attributes 
--	 * needed by scsi_sysfs.c */
--	struct class_device_attribute *attrs[SPI_NUM_ATTRS + SPI_OTHER_ATTRS + 1];
--	struct class_device_attribute private_host_attrs[SPI_HOST_ATTRS];
--	struct class_device_attribute *host_attrs[SPI_HOST_ATTRS + 1];
- };
  
- #define to_spi_internal(tmpl)	container_of(tmpl, struct spi_internal, t)
-@@ -174,17 +167,20 @@ static int spi_host_setup(struct transport_container *tc, struct device *dev,
- 	return 0;
++/* Convert permission bits from mode to equivalent CIFS ACL */
++static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
++				int acl_len, struct inode *inode, __u64 nmode)
++{
++	int rc = 0;
++	__u32 dacloffset;
++	__u32 ndacloffset;
++	__u32 sidsoffset;
++	struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
++	struct cifs_acl *dacl_ptr = NULL;  /* no need for SACL ptr */
++	struct cifs_acl *ndacl_ptr = NULL; /* no need for SACL ptr */
++
++	if ((inode == NULL) || (pntsd == NULL) || (pnntsd == NULL))
++		return (-EIO);
++
++	owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
++				le32_to_cpu(pntsd->osidoffset));
++	group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
++				le32_to_cpu(pntsd->gsidoffset));
++
++	dacloffset = le32_to_cpu(pntsd->dacloffset);
++	dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
++
++	ndacloffset = sizeof(struct cifs_ntsd);
++	ndacl_ptr = (struct cifs_acl *)((char *)pnntsd + ndacloffset);
++	ndacl_ptr->revision = dacl_ptr->revision;
++	ndacl_ptr->size = 0;
++	ndacl_ptr->num_aces = 0;
++
++	rc = set_chmod_dacl(ndacl_ptr, owner_sid_ptr, group_sid_ptr, nmode);
++
++	sidsoffset = ndacloffset + le16_to_cpu(ndacl_ptr->size);
++
++	/* copy security descriptor control portion and owner and group sid */
++	copy_sec_desc(pntsd, pnntsd, sidsoffset);
++
++	return (rc);
++}
++
++
+ /* Retrieve an ACL from the server */
+ static struct cifs_ntsd *get_cifs_acl(u32 *pacllen, struct inode *inode,
+ 				       const char *path)
+@@ -487,6 +624,64 @@ static struct cifs_ntsd *get_cifs_acl(u32 *pacllen, struct inode *inode,
+ 	return pntsd;
  }
  
-+static int spi_host_configure(struct transport_container *tc,
-+			      struct device *dev,
-+			      struct class_device *cdev);
++/* Set an ACL on the server */
++static int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
++				struct inode *inode, const char *path)
++{
++	struct cifsFileInfo *open_file;
++	int unlock_file = FALSE;
++	int xid;
++	int rc = -EIO;
++	__u16 fid;
++	struct super_block *sb;
++	struct cifs_sb_info *cifs_sb;
 +
- static DECLARE_TRANSPORT_CLASS(spi_host_class,
- 			       "spi_host",
- 			       spi_host_setup,
- 			       NULL,
--			       NULL);
-+			       spi_host_configure);
++#ifdef CONFIG_CIFS_DEBUG2
++	cFYI(1, ("set ACL for %s from mode 0x%x", path, inode->i_mode));
++#endif
++
++	if (!inode)
++		return (rc);
++
++	sb = inode->i_sb;
++	if (sb == NULL)
++		return (rc);
++
++	cifs_sb = CIFS_SB(sb);
++	xid = GetXid();
++
++	open_file = find_readable_file(CIFS_I(inode));
++	if (open_file) {
++		unlock_file = TRUE;
++		fid = open_file->netfid;
++	} else {
++		int oplock = FALSE;
++		/* open file */
++		rc = CIFSSMBOpen(xid, cifs_sb->tcon, path, FILE_OPEN,
++				WRITE_DAC, 0, &fid, &oplock, NULL,
++				cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
++					CIFS_MOUNT_MAP_SPECIAL_CHR);
++		if (rc != 0) {
++			cERROR(1, ("Unable to open file to set ACL"));
++			FreeXid(xid);
++			return (rc);
++		}
++	}
++
++	rc = CIFSSMBSetCIFSACL(xid, cifs_sb->tcon, fid, pnntsd, acllen);
++#ifdef CONFIG_CIFS_DEBUG2
++	cFYI(1, ("SetCIFSACL rc = %d", rc));
++#endif
++	if (unlock_file == TRUE)
++		atomic_dec(&open_file->wrtPending);
++	else
++		CIFSSMBClose(xid, cifs_sb->tcon, fid);
++
++	FreeXid(xid);
++
++	return (rc);
++}
++
+ /* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */
+ void acl_to_uid_mode(struct inode *inode, const char *path)
+ {
+@@ -510,24 +705,53 @@ void acl_to_uid_mode(struct inode *inode, const char *path)
+ }
  
- static int spi_host_match(struct attribute_container *cont,
- 			  struct device *dev)
+ /* Convert mode bits to an ACL so we can update the ACL on the server */
+-int mode_to_acl(struct inode *inode, const char *path)
++int mode_to_acl(struct inode *inode, const char *path, __u64 nmode)
  {
- 	struct Scsi_Host *shost;
--	struct spi_internal *i;
+ 	int rc = 0;
+ 	__u32 acllen = 0;
+-	struct cifs_ntsd *pntsd = NULL;
++	struct cifs_ntsd *pntsd = NULL; /* acl obtained from server */
++	struct cifs_ntsd *pnntsd = NULL; /* modified acl to be sent to server */
  
- 	if (!scsi_is_host_device(dev))
- 		return 0;
-@@ -194,11 +190,13 @@ static int spi_host_match(struct attribute_container *cont,
- 	    != &spi_host_class.class)
- 		return 0;
++#ifdef CONFIG_CIFS_DEBUG2
+ 	cFYI(1, ("set ACL from mode for %s", path));
++#endif
  
--	i = to_spi_internal(shost->transportt);
--	
--	return &i->t.host_attrs.ac == cont;
-+	return &shost->transportt->host_attrs.ac == cont;
- }
+ 	/* Get the security descriptor */
+ 	pntsd = get_cifs_acl(&acllen, inode, path);
  
-+static int spi_target_configure(struct transport_container *tc,
-+				struct device *dev,
-+				struct class_device *cdev);
-+
- static int spi_device_configure(struct transport_container *tc,
- 				struct device *dev,
- 				struct class_device *cdev)
-@@ -300,8 +298,10 @@ store_spi_transport_##field(struct class_device *cdev, const char *buf, \
- 	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);	\
- 	struct spi_internal *i = to_spi_internal(shost->transportt);	\
- 									\
-+	if (!i->f->set_##field)						\
-+		return -EINVAL;						\
- 	val = simple_strtoul(buf, NULL, 0);				\
--	i->f->set_##field(starget, val);			\
-+	i->f->set_##field(starget, val);				\
- 	return count;							\
- }
+-	/* Add/Modify the three ACEs for owner, group, everyone
+-	   while retaining the other ACEs */
++	/* Add three ACEs for owner, group, everyone getting rid of
++	   other ACEs as chmod disables ACEs and set the security descriptor */
  
-@@ -317,6 +317,8 @@ store_spi_transport_##field(struct class_device *cdev, const char *buf, \
- 	struct spi_transport_attrs *tp					\
- 		= (struct spi_transport_attrs *)&starget->starget_data;	\
- 									\
-+	if (i->f->set_##field)						\
-+		return -EINVAL;						\
- 	val = simple_strtoul(buf, NULL, 0);				\
- 	if (val > tp->max_##field)					\
- 		val = tp->max_##field;					\
-@@ -327,14 +329,14 @@ store_spi_transport_##field(struct class_device *cdev, const char *buf, \
- #define spi_transport_rd_attr(field, format_string)			\
- 	spi_transport_show_function(field, format_string)		\
- 	spi_transport_store_function(field, format_string)		\
--static CLASS_DEVICE_ATTR(field, S_IRUGO | S_IWUSR,			\
-+static CLASS_DEVICE_ATTR(field, S_IRUGO,				\
- 			 show_spi_transport_##field,			\
- 			 store_spi_transport_##field);
+-	/* Set the security descriptor */
++	if (pntsd) {
++		/* allocate memory for the smb header,
++		   set security descriptor request security descriptor
++		   parameters, and secuirty descriptor itself */
  
- #define spi_transport_simple_attr(field, format_string)			\
- 	spi_transport_show_simple(field, format_string)			\
- 	spi_transport_store_simple(field, format_string)		\
--static CLASS_DEVICE_ATTR(field, S_IRUGO | S_IWUSR,			\
-+static CLASS_DEVICE_ATTR(field, S_IRUGO,				\
- 			 show_spi_transport_##field,			\
- 			 store_spi_transport_##field);
++		pnntsd = kmalloc(acllen, GFP_KERNEL);
++		if (!pnntsd) {
++			cERROR(1, ("Unable to allocate security descriptor"));
++			kfree(pntsd);
++			return (-ENOMEM);
++		}
  
-@@ -342,7 +344,7 @@ static CLASS_DEVICE_ATTR(field, S_IRUGO | S_IWUSR,			\
- 	spi_transport_show_function(field, format_string)		\
- 	spi_transport_store_max(field, format_string)			\
- 	spi_transport_simple_attr(max_##field, format_string)		\
--static CLASS_DEVICE_ATTR(field, S_IRUGO | S_IWUSR,			\
-+static CLASS_DEVICE_ATTR(field, S_IRUGO,				\
- 			 show_spi_transport_##field,			\
- 			 store_spi_transport_##field);
+-	kfree(pntsd);
+-	return rc;
++		rc = build_sec_desc(pntsd, pnntsd, acllen, inode, nmode);
++
++#ifdef CONFIG_CIFS_DEBUG2
++		cFYI(1, ("build_sec_desc rc: %d", rc));
++#endif
++
++		if (!rc) {
++			/* Set the security descriptor */
++			rc = set_cifs_acl(pnntsd, acllen, inode, path);
++#ifdef CONFIG_CIFS_DEBUG2
++			cFYI(1, ("set_cifs_acl rc: %d", rc));
++#endif
++		}
++
++		kfree(pnntsd);
++		kfree(pntsd);
++	}
++
++	return (rc);
+ }
+ #endif /* CONFIG_CIFS_EXPERIMENTAL */
+diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
+index 093beaa..e9f4ec7 100644
+--- a/fs/cifs/cifsfs.c
++++ b/fs/cifs/cifsfs.c
+@@ -44,6 +44,7 @@
+ #include "cifs_fs_sb.h"
+ #include <linux/mm.h>
+ #include <linux/key-type.h>
++#include "dns_resolve.h"
+ #include "cifs_spnego.h"
+ #define CIFS_MAGIC_NUMBER 0xFF534D42	/* the first four bytes of SMB PDUs */
  
-@@ -472,6 +474,9 @@ store_spi_transport_period(struct class_device *cdev, const char *buf,
- 		(struct spi_transport_attrs *)&starget->starget_data;
- 	int period, retval;
+@@ -96,6 +97,9 @@ cifs_read_super(struct super_block *sb, void *data,
+ {
+ 	struct inode *inode;
+ 	struct cifs_sb_info *cifs_sb;
++#ifdef CONFIG_CIFS_DFS_UPCALL
++	int len;
++#endif
+ 	int rc = 0;
  
-+	if (!i->f->set_period)
-+		return -EINVAL;
-+
- 	retval = store_spi_transport_period_helper(cdev, buf, count, &period);
+ 	/* BB should we make this contingent on mount parm? */
+@@ -105,6 +109,25 @@ cifs_read_super(struct super_block *sb, void *data,
+ 	if (cifs_sb == NULL)
+ 		return -ENOMEM;
  
- 	if (period < tp->min_period)
-@@ -482,7 +487,7 @@ store_spi_transport_period(struct class_device *cdev, const char *buf,
- 	return retval;
- }
++#ifdef CONFIG_CIFS_DFS_UPCALL
++	/* copy mount params to sb for use in submounts */
++	/* BB: should we move this after the mount so we
++	 * do not have to do the copy on failed mounts?
++	 * BB: May be it is better to do simple copy before
++	 * complex operation (mount), and in case of fail
++	 * just exit instead of doing mount and attempting
++	 * undo it if this copy fails?*/
++	len = strlen(data);
++	cifs_sb->mountdata = kzalloc(len + 1, GFP_KERNEL);
++	if (cifs_sb->mountdata == NULL) {
++		kfree(sb->s_fs_info);
++		sb->s_fs_info = NULL;
++		return -ENOMEM;
++	}
++	strncpy(cifs_sb->mountdata, data, len + 1);
++	cifs_sb->mountdata[len] = '\0';
++#endif
++
+ 	rc = cifs_mount(sb, cifs_sb, data, devname);
  
--static CLASS_DEVICE_ATTR(period, S_IRUGO | S_IWUSR, 
-+static CLASS_DEVICE_ATTR(period, S_IRUGO,
- 			 show_spi_transport_period,
- 			 store_spi_transport_period);
+ 	if (rc) {
+@@ -154,6 +177,12 @@ out_no_root:
  
-@@ -490,9 +495,14 @@ static ssize_t
- show_spi_transport_min_period(struct class_device *cdev, char *buf)
- {
- 	struct scsi_target *starget = transport_class_to_starget(cdev);
-+	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
-+	struct spi_internal *i = to_spi_internal(shost->transportt);
- 	struct spi_transport_attrs *tp =
- 		(struct spi_transport_attrs *)&starget->starget_data;
+ out_mount_failed:
+ 	if (cifs_sb) {
++#ifdef CONFIG_CIFS_DFS_UPCALL
++		if (cifs_sb->mountdata) {
++			kfree(cifs_sb->mountdata);
++			cifs_sb->mountdata = NULL;
++		}
++#endif
+ 		if (cifs_sb->local_nls)
+ 			unload_nls(cifs_sb->local_nls);
+ 		kfree(cifs_sb);
+@@ -177,6 +206,13 @@ cifs_put_super(struct super_block *sb)
+ 	if (rc) {
+ 		cERROR(1, ("cifs_umount failed with return code %d", rc));
+ 	}
++#ifdef CONFIG_CIFS_DFS_UPCALL
++	if (cifs_sb->mountdata) {
++		kfree(cifs_sb->mountdata);
++		cifs_sb->mountdata = NULL;
++	}
++#endif
++
+ 	unload_nls(cifs_sb->local_nls);
+ 	kfree(cifs_sb);
+ 	return;
+@@ -435,6 +471,10 @@ static void cifs_umount_begin(struct vfsmount *vfsmnt, int flags)
+ 	struct cifs_sb_info *cifs_sb;
+ 	struct cifsTconInfo *tcon;
  
-+	if (!i->f->set_period)
-+		return -EINVAL;
++#ifdef CONFIG_CIFS_DFS_UPCALL
++	dfs_shrink_umount_helper(vfsmnt);
++#endif /* CONFIG CIFS_DFS_UPCALL */
 +
- 	return show_spi_transport_period_helper(buf, tp->min_period);
+ 	if (!(flags & MNT_FORCE))
+ 		return;
+ 	cifs_sb = CIFS_SB(vfsmnt->mnt_sb);
+@@ -552,7 +592,7 @@ static loff_t cifs_llseek(struct file *file, loff_t offset, int origin)
+ 	return remote_llseek(file, offset, origin);
  }
  
-@@ -509,7 +519,7 @@ store_spi_transport_min_period(struct class_device *cdev, const char *buf,
- }
+-static struct file_system_type cifs_fs_type = {
++struct file_system_type cifs_fs_type = {
+ 	.owner = THIS_MODULE,
+ 	.name = "cifs",
+ 	.get_sb = cifs_get_sb,
+@@ -1015,11 +1055,16 @@ init_cifs(void)
+ 	if (rc)
+ 		goto out_unregister_filesystem;
+ #endif
++#ifdef CONFIG_CIFS_DFS_UPCALL
++	rc = register_key_type(&key_type_dns_resolver);
++	if (rc)
++		goto out_unregister_key_type;
++#endif
+ 	oplockThread = kthread_run(cifs_oplock_thread, NULL, "cifsoplockd");
+ 	if (IS_ERR(oplockThread)) {
+ 		rc = PTR_ERR(oplockThread);
+ 		cERROR(1, ("error %d create oplock thread", rc));
+-		goto out_unregister_key_type;
++		goto out_unregister_dfs_key_type;
+ 	}
+ 
+ 	dnotifyThread = kthread_run(cifs_dnotify_thread, NULL, "cifsdnotifyd");
+@@ -1033,7 +1078,11 @@ init_cifs(void)
  
+  out_stop_oplock_thread:
+ 	kthread_stop(oplockThread);
++ out_unregister_dfs_key_type:
++#ifdef CONFIG_CIFS_DFS_UPCALL
++	unregister_key_type(&key_type_dns_resolver);
+  out_unregister_key_type:
++#endif
+ #ifdef CONFIG_CIFS_UPCALL
+ 	unregister_key_type(&cifs_spnego_key_type);
+  out_unregister_filesystem:
+@@ -1059,6 +1108,9 @@ exit_cifs(void)
+ #ifdef CONFIG_PROC_FS
+ 	cifs_proc_clean();
+ #endif
++#ifdef CONFIG_CIFS_DFS_UPCALL
++	unregister_key_type(&key_type_dns_resolver);
++#endif
+ #ifdef CONFIG_CIFS_UPCALL
+ 	unregister_key_type(&cifs_spnego_key_type);
+ #endif
+diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h
+index 2a21dc6..195b14d 100644
+--- a/fs/cifs/cifsfs.h
++++ b/fs/cifs/cifsfs.h
+@@ -32,6 +32,7 @@
+ #define TRUE 1
+ #endif
  
--static CLASS_DEVICE_ATTR(min_period, S_IRUGO | S_IWUSR, 
-+static CLASS_DEVICE_ATTR(min_period, S_IRUGO,
- 			 show_spi_transport_min_period,
- 			 store_spi_transport_min_period);
++extern struct file_system_type cifs_fs_type;
+ extern const struct address_space_operations cifs_addr_ops;
+ extern const struct address_space_operations cifs_addr_ops_smallbuf;
  
-@@ -531,12 +541,15 @@ static ssize_t store_spi_host_signalling(struct class_device *cdev,
- 	struct spi_internal *i = to_spi_internal(shost->transportt);
- 	enum spi_signal_type type = spi_signal_to_value(buf);
+@@ -60,6 +61,10 @@ extern int cifs_setattr(struct dentry *, struct iattr *);
  
-+	if (!i->f->set_signalling)
-+		return -EINVAL;
+ extern const struct inode_operations cifs_file_inode_ops;
+ extern const struct inode_operations cifs_symlink_inode_ops;
++extern struct list_head cifs_dfs_automount_list;
++extern struct inode_operations cifs_dfs_referral_inode_operations;
++
 +
- 	if (type != SPI_SIGNAL_UNKNOWN)
- 		i->f->set_signalling(shost, type);
- 
- 	return count;
- }
--static CLASS_DEVICE_ATTR(signalling, S_IRUGO | S_IWUSR,
-+static CLASS_DEVICE_ATTR(signalling, S_IRUGO,
- 			 show_spi_host_signalling,
- 			 store_spi_host_signalling);
  
-@@ -1262,35 +1275,6 @@ int spi_print_msg(const unsigned char *msg)
- EXPORT_SYMBOL(spi_print_msg);
- #endif /* ! CONFIG_SCSI_CONSTANTS */
+ /* Functions related to files and directories */
+ extern const struct file_operations cifs_file_ops;
+diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
+index 1fde219..5d32d8d 100644
+--- a/fs/cifs/cifsglob.h
++++ b/fs/cifs/cifsglob.h
+@@ -1,7 +1,7 @@
+ /*
+  *   fs/cifs/cifsglob.h
+  *
+- *   Copyright (C) International Business Machines  Corp., 2002,2007
++ *   Copyright (C) International Business Machines  Corp., 2002,2008
+  *   Author(s): Steve French (sfrench at us.ibm.com)
+  *              Jeremy Allison (jra at samba.org)
+  *
+@@ -70,14 +70,6 @@
+ #endif
  
--#define SETUP_ATTRIBUTE(field)						\
--	i->private_attrs[count] = class_device_attr_##field;		\
--	if (!i->f->set_##field) {					\
--		i->private_attrs[count].attr.mode = S_IRUGO;		\
--		i->private_attrs[count].store = NULL;			\
--	}								\
--	i->attrs[count] = &i->private_attrs[count];			\
--	if (i->f->show_##field)						\
--		count++
--
--#define SETUP_RELATED_ATTRIBUTE(field, rel_field)			\
--	i->private_attrs[count] = class_device_attr_##field;		\
--	if (!i->f->set_##rel_field) {					\
--		i->private_attrs[count].attr.mode = S_IRUGO;		\
--		i->private_attrs[count].store = NULL;			\
--	}								\
--	i->attrs[count] = &i->private_attrs[count];			\
--	if (i->f->show_##rel_field)					\
--		count++
--
--#define SETUP_HOST_ATTRIBUTE(field)					\
--	i->private_host_attrs[count] = class_device_attr_##field;	\
--	if (!i->f->set_##field) {					\
--		i->private_host_attrs[count].attr.mode = S_IRUGO;	\
--		i->private_host_attrs[count].store = NULL;		\
--	}								\
--	i->host_attrs[count] = &i->private_host_attrs[count];		\
--	count++
+ /*
+- * This information is kept on every Server we know about.
+- *
+- * Some things to note:
+- *
+- */
+-#define SERVER_NAME_LEN_WITH_NULL	(SERVER_NAME_LENGTH + 1)
 -
- static int spi_device_match(struct attribute_container *cont,
- 			    struct device *dev)
- {
-@@ -1343,16 +1327,156 @@ static DECLARE_TRANSPORT_CLASS(spi_transport_class,
- 			       "spi_transport",
- 			       spi_setup_transport_attrs,
- 			       NULL,
--			       NULL);
-+			       spi_target_configure);
+-/*
+  * CIFS vfs client Status information (based on what we know.)
+  */
  
- static DECLARE_ANON_TRANSPORT_CLASS(spi_device_class,
- 				    spi_device_match,
- 				    spi_device_configure);
+@@ -460,6 +452,37 @@ struct dir_notify_req {
+        struct file *pfile;
+ };
  
-+static struct attribute *host_attributes[] = {
-+	&class_device_attr_signalling.attr,
-+	NULL
-+};
-+
-+static struct attribute_group host_attribute_group = {
-+	.attrs = host_attributes,
++struct dfs_info3_param {
++	int flags; /* DFSREF_REFERRAL_SERVER, DFSREF_STORAGE_SERVER*/
++	int PathConsumed;
++	int server_type;
++	int ref_flag;
++	char *path_name;
++	char *node_name;
 +};
 +
-+static int spi_host_configure(struct transport_container *tc,
-+			      struct device *dev,
-+			      struct class_device *cdev)
++static inline void free_dfs_info_param(struct dfs_info3_param *param)
 +{
-+	struct kobject *kobj = &cdev->kobj;
-+	struct Scsi_Host *shost = transport_class_to_shost(cdev);
-+	struct spi_internal *si = to_spi_internal(shost->transportt);
-+	struct attribute *attr = &class_device_attr_signalling.attr;
-+	int rc = 0;
-+
-+	if (si->f->set_signalling)
-+		rc = sysfs_chmod_file(kobj, attr, attr->mode | S_IWUSR);
++	if (param) {
++		kfree(param->path_name);
++		kfree(param->node_name);
++		kfree(param);
++	}
++}
 +
-+	return rc;
++static inline void free_dfs_info_array(struct dfs_info3_param *param,
++				       int number_of_items)
++{
++	int i;
++	if ((number_of_items == 0) || (param == NULL))
++		return;
++	for (i = 0; i < number_of_items; i++) {
++		kfree(param[i].path_name);
++		kfree(param[i].node_name);
++	}
++	kfree(param);
 +}
 +
-+/* returns true if we should be showing the variable.  Also
-+ * overloads the return by setting 1<<1 if the attribute should
-+ * be writeable */
-+#define TARGET_ATTRIBUTE_HELPER(name) \
-+	(si->f->show_##name ? 1 : 0) + \
-+	(si->f->set_##name ? 2 : 0)
+ #define   MID_FREE 0
+ #define   MID_REQUEST_ALLOCATED 1
+ #define   MID_REQUEST_SUBMITTED 2
+diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h
+index dbe6b84..47f7950 100644
+--- a/fs/cifs/cifspdu.h
++++ b/fs/cifs/cifspdu.h
+@@ -237,6 +237,9 @@
+ 				| DELETE | READ_CONTROL | WRITE_DAC \
+ 				| WRITE_OWNER | SYNCHRONIZE)
+ 
++#define SET_MINIMUM_RIGHTS (FILE_READ_EA | FILE_READ_ATTRIBUTES \
++				| READ_CONTROL | SYNCHRONIZE)
 +
-+static int target_attribute_is_visible(struct kobject *kobj,
-+				       struct attribute *attr, int i)
+ 
+ /*
+  * Invalid readdir handle
+diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
+index 8350eec..2f09f56 100644
+--- a/fs/cifs/cifsproto.h
++++ b/fs/cifs/cifsproto.h
+@@ -1,7 +1,7 @@
+ /*
+  *   fs/cifs/cifsproto.h
+  *
+- *   Copyright (c) International Business Machines  Corp., 2002,2007
++ *   Copyright (c) International Business Machines  Corp., 2002,2008
+  *   Author(s): Steve French (sfrench at us.ibm.com)
+  *
+  *   This library is free software; you can redistribute it and/or modify
+@@ -97,11 +97,14 @@ extern int cifs_get_inode_info_unix(struct inode **pinode,
+ 			const unsigned char *search_path,
+ 			struct super_block *sb, int xid);
+ extern void acl_to_uid_mode(struct inode *inode, const char *search_path);
+-extern int mode_to_acl(struct inode *inode, const char *path);
++extern int mode_to_acl(struct inode *inode, const char *path, __u64);
+ 
+ extern int cifs_mount(struct super_block *, struct cifs_sb_info *, char *,
+ 			const char *);
+ extern int cifs_umount(struct super_block *, struct cifs_sb_info *);
++#ifdef CONFIG_CIFS_DFS_UPCALL
++extern void dfs_shrink_umount_helper(struct vfsmount *vfsmnt);
++#endif
+ void cifs_proc_init(void);
+ void cifs_proc_clean(void);
+ 
+@@ -153,7 +156,7 @@ extern int get_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
+ 			const char *old_path,
+ 			const struct nls_table *nls_codepage,
+ 			unsigned int *pnum_referrals,
+-			unsigned char **preferrals,
++			struct dfs_info3_param **preferrals,
+ 			int remap);
+ extern void reset_cifs_unix_caps(int xid, struct cifsTconInfo *tcon,
+ 				 struct super_block *sb, struct smb_vol *vol);
+@@ -342,6 +345,8 @@ extern int CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon,
+ 		const struct nls_table *nls_codepage, int remap_special_chars);
+ extern int CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon,
+ 			__u16 fid, struct cifs_ntsd **acl_inf, __u32 *buflen);
++extern int CIFSSMBSetCIFSACL(const int, struct cifsTconInfo *, __u16,
++			struct cifs_ntsd *, __u32);
+ extern int CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
+ 		const unsigned char *searchName,
+ 		char *acl_inf, const int buflen, const int acl_type,
+diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
+index 9e8a6be..9409524 100644
+--- a/fs/cifs/cifssmb.c
++++ b/fs/cifs/cifssmb.c
+@@ -3156,6 +3156,71 @@ qsec_out:
+ /*	cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
+ 	return rc;
+ }
++
++int
++CIFSSMBSetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
++			struct cifs_ntsd *pntsd, __u32 acllen)
 +{
-+	struct class_device *cdev =
-+		container_of(kobj, struct class_device, kobj);
-+	struct scsi_target *starget = transport_class_to_starget(cdev);
-+	struct Scsi_Host *shost = transport_class_to_shost(cdev);
-+	struct spi_internal *si = to_spi_internal(shost->transportt);
++	__u16 byte_count, param_count, data_count, param_offset, data_offset;
++	int rc = 0;
++	int bytes_returned = 0;
++	SET_SEC_DESC_REQ *pSMB = NULL;
++	NTRANSACT_RSP *pSMBr = NULL;
 +
-+	if (attr == &class_device_attr_period.attr &&
-+	    spi_support_sync(starget))
-+		return TARGET_ATTRIBUTE_HELPER(period);
-+	else if (attr == &class_device_attr_min_period.attr &&
-+		 spi_support_sync(starget))
-+		return TARGET_ATTRIBUTE_HELPER(period);
-+	else if (attr == &class_device_attr_offset.attr &&
-+		 spi_support_sync(starget))
-+		return TARGET_ATTRIBUTE_HELPER(offset);
-+	else if (attr == &class_device_attr_max_offset.attr &&
-+		 spi_support_sync(starget))
-+		return TARGET_ATTRIBUTE_HELPER(offset);
-+	else if (attr == &class_device_attr_width.attr &&
-+		 spi_support_wide(starget))
-+		return TARGET_ATTRIBUTE_HELPER(width);
-+	else if (attr == &class_device_attr_max_width.attr &&
-+		 spi_support_wide(starget))
-+		return TARGET_ATTRIBUTE_HELPER(width);
-+	else if (attr == &class_device_attr_iu.attr &&
-+		 spi_support_ius(starget))
-+		return TARGET_ATTRIBUTE_HELPER(iu);
-+	else if (attr == &class_device_attr_dt.attr &&
-+		 spi_support_dt(starget))
-+		return TARGET_ATTRIBUTE_HELPER(dt);
-+	else if (attr == &class_device_attr_qas.attr &&
-+		 spi_support_qas(starget))
-+		return TARGET_ATTRIBUTE_HELPER(qas);
-+	else if (attr == &class_device_attr_wr_flow.attr &&
-+		 spi_support_ius(starget))
-+		return TARGET_ATTRIBUTE_HELPER(wr_flow);
-+	else if (attr == &class_device_attr_rd_strm.attr &&
-+		 spi_support_ius(starget))
-+		return TARGET_ATTRIBUTE_HELPER(rd_strm);
-+	else if (attr == &class_device_attr_rti.attr &&
-+		 spi_support_ius(starget))
-+		return TARGET_ATTRIBUTE_HELPER(rti);
-+	else if (attr == &class_device_attr_pcomp_en.attr &&
-+		 spi_support_ius(starget))
-+		return TARGET_ATTRIBUTE_HELPER(pcomp_en);
-+	else if (attr == &class_device_attr_hold_mcs.attr &&
-+		 spi_support_ius(starget))
-+		return TARGET_ATTRIBUTE_HELPER(hold_mcs);
-+	else if (attr == &class_device_attr_revalidate.attr)
-+		return 1;
++setCifsAclRetry:
++	rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB,
++			(void **) &pSMBr);
++	if (rc)
++			return (rc);
 +
-+	return 0;
-+}
++	pSMB->MaxSetupCount = 0;
++	pSMB->Reserved = 0;
 +
-+static struct attribute *target_attributes[] = {
-+	&class_device_attr_period.attr,
-+	&class_device_attr_min_period.attr,
-+	&class_device_attr_offset.attr,
-+	&class_device_attr_max_offset.attr,
-+	&class_device_attr_width.attr,
-+	&class_device_attr_max_width.attr,
-+	&class_device_attr_iu.attr,
-+	&class_device_attr_dt.attr,
-+	&class_device_attr_qas.attr,
-+	&class_device_attr_wr_flow.attr,
-+	&class_device_attr_rd_strm.attr,
-+	&class_device_attr_rti.attr,
-+	&class_device_attr_pcomp_en.attr,
-+	&class_device_attr_hold_mcs.attr,
-+	&class_device_attr_revalidate.attr,
-+	NULL
-+};
++	param_count = 8;
++	param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
++	data_count = acllen;
++	data_offset = param_offset + param_count;
++	byte_count = 3 /* pad */  + param_count;
 +
-+static struct attribute_group target_attribute_group = {
-+	.attrs = target_attributes,
-+	.is_visible = target_attribute_is_visible,
-+};
++	pSMB->DataCount = cpu_to_le32(data_count);
++	pSMB->TotalDataCount = pSMB->DataCount;
++	pSMB->MaxParameterCount = cpu_to_le32(4);
++	pSMB->MaxDataCount = cpu_to_le32(16384);
++	pSMB->ParameterCount = cpu_to_le32(param_count);
++	pSMB->ParameterOffset = cpu_to_le32(param_offset);
++	pSMB->TotalParameterCount = pSMB->ParameterCount;
++	pSMB->DataOffset = cpu_to_le32(data_offset);
++	pSMB->SetupCount = 0;
++	pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
++	pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
 +
-+static int spi_target_configure(struct transport_container *tc,
-+				struct device *dev,
-+				struct class_device *cdev)
-+{
-+	struct kobject *kobj = &cdev->kobj;
-+	int i;
-+	struct attribute *attr;
-+	int rc;
++	pSMB->Fid = fid; /* file handle always le */
++	pSMB->Reserved2 = 0;
++	pSMB->AclFlags = cpu_to_le32(CIFS_ACL_DACL);
 +
-+	for (i = 0; (attr = target_attributes[i]) != NULL; i++) {
-+		int j = target_attribute_group.is_visible(kobj, attr, i);
++	if (pntsd && acllen) {
++		memcpy((char *) &pSMBr->hdr.Protocol + data_offset,
++			(char *) pntsd,
++			acllen);
++		pSMB->hdr.smb_buf_length += (byte_count + data_count);
 +
-+		/* FIXME: as well as returning -EEXIST, which we'd like
-+		 * to ignore, sysfs also does a WARN_ON and dumps a trace,
-+		 * which is bad, so temporarily, skip attributes that are
-+		 * already visible (the revalidate one) */
-+		if (j && attr != &class_device_attr_revalidate.attr)
-+			rc = sysfs_add_file_to_group(kobj, attr,
-+						target_attribute_group.name);
-+		/* and make the attribute writeable if we have a set
-+		 * function */
-+		if ((j & 1))
-+			rc = sysfs_chmod_file(kobj, attr, attr->mode | S_IWUSR);
-+	}
++	} else
++		pSMB->hdr.smb_buf_length += byte_count;
 +
-+	return 0;
++	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
++		(struct smb_hdr *) pSMBr, &bytes_returned, 0);
++
++	cFYI(1, ("SetCIFSACL bytes_returned: %d, rc: %d", bytes_returned, rc));
++	if (rc)
++		cFYI(1, ("Set CIFS ACL returned %d", rc));
++	cifs_buf_release(pSMB);
++
++	if (rc == -EAGAIN)
++		goto setCifsAclRetry;
++
++	return (rc);
 +}
 +
- struct scsi_transport_template *
- spi_attach_transport(struct spi_function_template *ft)
- {
--	int count = 0;
- 	struct spi_internal *i = kzalloc(sizeof(struct spi_internal),
- 					 GFP_KERNEL);
+ #endif /* CONFIG_CIFS_EXPERIMENTAL */
  
-@@ -1360,47 +1484,17 @@ spi_attach_transport(struct spi_function_template *ft)
- 		return NULL;
+ /* Legacy Query Path Information call for lookup to old servers such
+@@ -5499,7 +5564,7 @@ SetEARetry:
+ 	else
+ 		name_len = strnlen(ea_name, 255);
  
- 	i->t.target_attrs.ac.class = &spi_transport_class.class;
--	i->t.target_attrs.ac.attrs = &i->attrs[0];
-+	i->t.target_attrs.ac.grp = &target_attribute_group;
- 	i->t.target_attrs.ac.match = spi_target_match;
- 	transport_container_register(&i->t.target_attrs);
- 	i->t.target_size = sizeof(struct spi_transport_attrs);
- 	i->t.host_attrs.ac.class = &spi_host_class.class;
--	i->t.host_attrs.ac.attrs = &i->host_attrs[0];
-+	i->t.host_attrs.ac.grp = &host_attribute_group;
- 	i->t.host_attrs.ac.match = spi_host_match;
- 	transport_container_register(&i->t.host_attrs);
- 	i->t.host_size = sizeof(struct spi_host_attrs);
- 	i->f = ft;
+-	count = sizeof(*parm_data) + ea_value_len + name_len + 1;
++	count = sizeof(*parm_data) + ea_value_len + name_len;
+ 	pSMB->MaxParameterCount = cpu_to_le16(2);
+ 	pSMB->MaxDataCount = cpu_to_le16(1000);	/* BB find max SMB size from sess */
+ 	pSMB->MaxSetupCount = 0;
+diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
+index fd9147c..65d0ba7 100644
+--- a/fs/cifs/connect.c
++++ b/fs/cifs/connect.c
+@@ -1,7 +1,7 @@
+ /*
+  *   fs/cifs/connect.c
+  *
+- *   Copyright (C) International Business Machines  Corp., 2002,2007
++ *   Copyright (C) International Business Machines  Corp., 2002,2008
+  *   Author(s): Steve French (sfrench at us.ibm.com)
+  *
+  *   This library is free software; you can redistribute it and/or modify
+@@ -1410,7 +1410,7 @@ connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
+ 		    const char *old_path, const struct nls_table *nls_codepage,
+ 		    int remap)
+ {
+-	unsigned char *referrals = NULL;
++	struct dfs_info3_param *referrals = NULL;
+ 	unsigned int num_referrals;
+ 	int rc = 0;
  
--	SETUP_ATTRIBUTE(period);
--	SETUP_RELATED_ATTRIBUTE(min_period, period);
--	SETUP_ATTRIBUTE(offset);
--	SETUP_RELATED_ATTRIBUTE(max_offset, offset);
--	SETUP_ATTRIBUTE(width);
--	SETUP_RELATED_ATTRIBUTE(max_width, width);
--	SETUP_ATTRIBUTE(iu);
--	SETUP_ATTRIBUTE(dt);
--	SETUP_ATTRIBUTE(qas);
--	SETUP_ATTRIBUTE(wr_flow);
--	SETUP_ATTRIBUTE(rd_strm);
--	SETUP_ATTRIBUTE(rti);
--	SETUP_ATTRIBUTE(pcomp_en);
--	SETUP_ATTRIBUTE(hold_mcs);
--
--	/* if you add an attribute but forget to increase SPI_NUM_ATTRS
--	 * this bug will trigger */
--	BUG_ON(count > SPI_NUM_ATTRS);
--
--	i->attrs[count++] = &class_device_attr_revalidate;
--
--	i->attrs[count] = NULL;
--
--	count = 0;
--	SETUP_HOST_ATTRIBUTE(signalling);
--
--	BUG_ON(count > SPI_HOST_ATTRS);
--
--	i->host_attrs[count] = NULL;
--
- 	return &i->t;
- }
- EXPORT_SYMBOL(spi_attach_transport);
-diff --git a/drivers/scsi/scsi_transport_srp.c b/drivers/scsi/scsi_transport_srp.c
-index 65c584d..2445c98 100644
---- a/drivers/scsi/scsi_transport_srp.c
-+++ b/drivers/scsi/scsi_transport_srp.c
-@@ -185,11 +185,10 @@ static int srp_host_match(struct attribute_container *cont, struct device *dev)
+@@ -1429,12 +1429,14 @@ connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
+ int
+ get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path,
+ 	     const struct nls_table *nls_codepage, unsigned int *pnum_referrals,
+-	     unsigned char **preferrals, int remap)
++	     struct dfs_info3_param **preferrals, int remap)
+ {
+ 	char *temp_unc;
+ 	int rc = 0;
++	unsigned char *targetUNCs;
  
- /**
-  * srp_rport_add - add a SRP remote port to the device hierarchy
-- *
-  * @shost:	scsi host the remote port is connected to.
-  * @ids:	The port id for the remote port.
-  *
-- * publishes a port to the rest of the system
-+ * Publishes a port to the rest of the system.
-  */
- struct srp_rport *srp_rport_add(struct Scsi_Host *shost,
- 				struct srp_rport_identifiers *ids)
-@@ -242,8 +241,8 @@ struct srp_rport *srp_rport_add(struct Scsi_Host *shost,
- EXPORT_SYMBOL_GPL(srp_rport_add);
+ 	*pnum_referrals = 0;
++	*preferrals = NULL;
  
- /**
-- * srp_rport_del  --  remove a SRP remote port
-- * @port:	SRP remote port to remove
-+ * srp_rport_del  -  remove a SRP remote port
-+ * @rport:	SRP remote port to remove
-  *
-  * Removes the specified SRP remote port.
-  */
-@@ -271,7 +270,7 @@ static int do_srp_rport_del(struct device *dev, void *data)
- }
+ 	if (pSesInfo->ipc_tid == 0) {
+ 		temp_unc = kmalloc(2 /* for slashes */ +
+@@ -1454,8 +1456,10 @@ get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path,
+ 		kfree(temp_unc);
+ 	}
+ 	if (rc == 0)
+-		rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, preferrals,
++		rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, &targetUNCs,
+ 				     pnum_referrals, nls_codepage, remap);
++	/* BB map targetUNCs to dfs_info3 structures, here or
++		in CIFSGetDFSRefer BB */
  
- /**
-- * srp_remove_host  --  tear down a Scsi_Host's SRP data structures
-+ * srp_remove_host  -  tear down a Scsi_Host's SRP data structures
-  * @shost:	Scsi Host that is torn down
-  *
-  * Removes all SRP remote ports for a given Scsi_Host.
-@@ -297,7 +296,7 @@ static int srp_it_nexus_response(struct Scsi_Host *shost, u64 nexus, int result)
+ 	return rc;
  }
+@@ -1964,7 +1968,15 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
  
- /**
-- * srp_attach_transport  --  instantiate SRP transport template
-+ * srp_attach_transport  -  instantiate SRP transport template
-  * @ft:		SRP transport class function template
-  */
- struct scsi_transport_template *
-@@ -337,7 +336,7 @@ srp_attach_transport(struct srp_function_template *ft)
- EXPORT_SYMBOL_GPL(srp_attach_transport);
+ 	if (existingCifsSes) {
+ 		pSesInfo = existingCifsSes;
+-		cFYI(1, ("Existing smb sess found"));
++		cFYI(1, ("Existing smb sess found (status=%d)",
++			pSesInfo->status));
++		down(&pSesInfo->sesSem);
++		if (pSesInfo->status == CifsNeedReconnect) {
++			cFYI(1, ("Session needs reconnect"));
++			rc = cifs_setup_session(xid, pSesInfo,
++						cifs_sb->local_nls);
++		}
++		up(&pSesInfo->sesSem);
+ 	} else if (!rc) {
+ 		cFYI(1, ("Existing smb sess not found"));
+ 		pSesInfo = sesInfoAlloc();
+@@ -3514,7 +3526,7 @@ cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
+ 		sesInfoFree(ses);
  
- /**
-- * srp_release_transport  --  release SRP transport template instance
-+ * srp_release_transport  -  release SRP transport template instance
-  * @t:		transport template instance
-  */
- void srp_release_transport(struct scsi_transport_template *t)
-diff --git a/drivers/scsi/scsicam.c b/drivers/scsi/scsicam.c
-index cd68a66..3f21bc6 100644
---- a/drivers/scsi/scsicam.c
-+++ b/drivers/scsi/scsicam.c
-@@ -24,6 +24,14 @@
- static int setsize(unsigned long capacity, unsigned int *cyls, unsigned int *hds,
- 		   unsigned int *secs);
+ 	FreeXid(xid);
+-	return rc;	/* BB check if we should always return zero here */
++	return rc;
+ }
  
-+/**
-+ * scsi_bios_ptable - Read PC partition table out of first sector of device.
-+ * @dev: from this device
+ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
+diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
+index 37dc97a..699ec11 100644
+--- a/fs/cifs/dir.c
++++ b/fs/cifs/dir.c
+@@ -517,12 +517,10 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
+ 		d_add(direntry, NULL);
+ 	/*	if it was once a directory (but how can we tell?) we could do
+ 		shrink_dcache_parent(direntry); */
+-	} else {
+-		cERROR(1, ("Error 0x%x on cifs_get_inode_info in lookup of %s",
+-			   rc, full_path));
+-		/* BB special case check for Access Denied - watch security
+-		exposure of returning dir info implicitly via different rc
+-		if file exists or not but no access BB */
++	} else if (rc != -EACCES) {
++		cERROR(1, ("Unexpected lookup error %d", rc));
++		/* We special case check for Access Denied - since that
++		is a common return code */
+ 	}
+ 
+ 	kfree(full_path);
+diff --git a/fs/cifs/dns_resolve.c b/fs/cifs/dns_resolve.c
+new file mode 100644
+index 0000000..ef7f438
+--- /dev/null
++++ b/fs/cifs/dns_resolve.c
+@@ -0,0 +1,124 @@
++/*
++ *  fs/cifs/dns_resolve.c
++ *
++ *   Copyright (c) 2007 Igor Mammedov
++ *   Author(s): Igor Mammedov (niallain at gmail.com)
++ *              Steve French (sfrench at us.ibm.com)
++ *
++ *   Contains the CIFS DFS upcall routines used for hostname to
++ *   IP address translation.
++ *
++ *   This library is free software; you can redistribute it and/or modify
++ *   it under the terms of the GNU Lesser General Public License as published
++ *   by the Free Software Foundation; either version 2.1 of the License, or
++ *   (at your option) any later version.
++ *
++ *   This library is distributed in the hope that it will be useful,
++ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
++ *   the GNU Lesser General Public License for more details.
++ *
++ *   You should have received a copy of the GNU Lesser General Public License
++ *   along with this library; if not, write to the Free Software
++ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ */
++
++#include <keys/user-type.h>
++#include "dns_resolve.h"
++#include "cifsglob.h"
++#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;
++}
++
++struct key_type key_type_dns_resolver = {
++	.name        = "dns_resolver",
++	.def_datalen = sizeof(struct in_addr),
++	.describe    = user_describe,
++	.instantiate = dns_resolver_instantiate,
++	.match       = user_match,
++};
++
++
++/* Resolves server name to ip address.
++ * input:
++ * 	unc - server UNC
++ * output:
++ * 	*ip_addr - pointer to server ip, caller responcible for freeing it.
++ * return 0 on success
++ */
++int
++dns_resolve_server_name_to_ip(const char *unc, char **ip_addr)
++{
++	int rc = -EAGAIN;
++	struct key *rkey;
++	char *name;
++	int len;
++
++	if (!ip_addr || !unc)
++		return -EINVAL;
++
++	/* search for server name delimiter */
++	len = strlen(unc);
++	if (len < 3) {
++		cFYI(1, ("%s: unc is too short: %s", __FUNCTION__, unc));
++		return -EINVAL;
++	}
++	len -= 2;
++	name = memchr(unc+2, '\\', len);
++	if (!name) {
++		cFYI(1, ("%s: probably server name is whole unc: %s",
++					__FUNCTION__, unc));
++	} else {
++		len = (name - unc) - 2/* leading // */;
++	}
++
++	name = kmalloc(len+1, GFP_KERNEL);
++	if (!name) {
++		rc = -ENOMEM;
++		return rc;
++	}
++	memcpy(name, unc+2, len);
++	name[len] = 0;
++
++	rkey = request_key(&key_type_dns_resolver, name, "");
++	if (!IS_ERR(rkey)) {
++		len = strlen(rkey->payload.data);
++		*ip_addr = kmalloc(len+1, GFP_KERNEL);
++		if (*ip_addr) {
++			memcpy(*ip_addr, rkey->payload.data, len);
++			(*ip_addr)[len] = '\0';
++			cFYI(1, ("%s: resolved: %s to %s", __FUNCTION__,
++					rkey->description,
++					*ip_addr
++				));
++			rc = 0;
++		} else {
++			rc = -ENOMEM;
++		}
++		key_put(rkey);
++	} else {
++		cERROR(1, ("%s: unable to resolve: %s", __FUNCTION__, name));
++	}
++
++	kfree(name);
++	return rc;
++}
++
++
+diff --git a/fs/cifs/dns_resolve.h b/fs/cifs/dns_resolve.h
+new file mode 100644
+index 0000000..073fdc3
+--- /dev/null
++++ b/fs/cifs/dns_resolve.h
+@@ -0,0 +1,32 @@
++/*
++ *   fs/cifs/dns_resolve.h -- DNS Resolver upcall management for CIFS DFS
++ *                            Handles host name to IP address resolution
++ * 
++ *   Copyright (c) International Business Machines  Corp., 2008
++ *   Author(s): Steve French (sfrench at us.ibm.com)
 + *
-+ * Description: Reads the first sector from the device and returns %0x42 bytes
-+ *              starting at offset %0x1be.
-+ * Returns: partition table in kmalloc(GFP_KERNEL) memory, or NULL on error.
++ *   This library is free software; you can redistribute it and/or modify
++ *   it under the terms of the GNU Lesser General Public License as published
++ *   by the Free Software Foundation; either version 2.1 of the License, or
++ *   (at your option) any later version.
++ *
++ *   This library is distributed in the hope that it will be useful,
++ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
++ *   the GNU Lesser General Public License for more details.
++ *
++ *   You should have received a copy of the GNU Lesser General Public License
++ *   along with this library; if not, write to the Free Software
++ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 + */
- unsigned char *scsi_bios_ptable(struct block_device *dev)
- {
- 	unsigned char *res = kmalloc(66, GFP_KERNEL);
-@@ -43,15 +51,17 @@ unsigned char *scsi_bios_ptable(struct block_device *dev)
- }
- EXPORT_SYMBOL(scsi_bios_ptable);
++
++#ifndef _DNS_RESOLVE_H
++#define _DNS_RESOLVE_H
++
++#ifdef __KERNEL__
++#include <linux/key-type.h>
++extern struct key_type key_type_dns_resolver;
++extern int dns_resolve_server_name_to_ip(const char *unc, char **ip_addr);
++#endif /* KERNEL */
++
++#endif /* _DNS_RESOLVE_H */
+diff --git a/fs/cifs/file.c b/fs/cifs/file.c
+index dd26e27..5f7c374 100644
+--- a/fs/cifs/file.c
++++ b/fs/cifs/file.c
+@@ -1179,12 +1179,10 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to)
+ 		atomic_dec(&open_file->wrtPending);
+ 		/* Does mm or vfs already set times? */
+ 		inode->i_atime = inode->i_mtime = current_fs_time(inode->i_sb);
+-		if ((bytes_written > 0) && (offset)) {
++		if ((bytes_written > 0) && (offset))
+ 			rc = 0;
+-		} else if (bytes_written < 0) {
+-			if (rc != -EBADF)
+-				rc = bytes_written;
+-		}
++		else if (bytes_written < 0)
++			rc = bytes_written;
+ 	} else {
+ 		cFYI(1, ("No writeable filehandles for inode"));
+ 		rc = -EIO;
+diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
+index e915eb1..d9567ba 100644
+--- a/fs/cifs/inode.c
++++ b/fs/cifs/inode.c
+@@ -54,9 +54,9 @@ int cifs_get_inode_info_unix(struct inode **pinode,
+ 					    MAX_TREE_SIZE + 1) +
+ 				    strnlen(search_path, MAX_PATHCONF) + 1,
+ 				    GFP_KERNEL);
+-			if (tmp_path == NULL) {
++			if (tmp_path == NULL)
+ 				return -ENOMEM;
+-			}
++
+ 			/* have to skip first of the double backslash of
+ 			   UNC name */
+ 			strncpy(tmp_path, pTcon->treeName, MAX_TREE_SIZE);
+@@ -511,7 +511,8 @@ int cifs_get_inode_info(struct inode **pinode,
+ 		}
  
--/*
-- * Function : int scsicam_bios_param (struct block_device *bdev, ector_t capacity, int *ip)
-+/**
-+ * scsicam_bios_param - Determine geometry of a disk in cylinders/heads/sectors.
-+ * @bdev: which device
-+ * @capacity: size of the disk in sectors
-+ * @ip: return value: ip[0]=heads, ip[1]=sectors, ip[2]=cylinders
+ 		spin_lock(&inode->i_lock);
+-		if (is_size_safe_to_change(cifsInfo, le64_to_cpu(pfindData->EndOfFile))) {
++		if (is_size_safe_to_change(cifsInfo,
++					   le64_to_cpu(pfindData->EndOfFile))) {
+ 			/* can not safely shrink the file size here if the
+ 			   client is writing to it due to potential races */
+ 			i_size_write(inode, le64_to_cpu(pfindData->EndOfFile));
+@@ -931,7 +932,7 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
+ 		(CIFS_UNIX_POSIX_PATH_OPS_CAP &
+ 			le64_to_cpu(pTcon->fsUnixInfo.Capability))) {
+ 		u32 oplock = 0;
+-		FILE_UNIX_BASIC_INFO * pInfo =
++		FILE_UNIX_BASIC_INFO *pInfo =
+ 			kzalloc(sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL);
+ 		if (pInfo == NULL) {
+ 			rc = -ENOMEM;
+@@ -1607,7 +1608,14 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
+ 						CIFS_MOUNT_MAP_SPECIAL_CHR);
+ 	else if (attrs->ia_valid & ATTR_MODE) {
+ 		rc = 0;
+-		if ((mode & S_IWUGO) == 0) /* not writeable */ {
++#ifdef CONFIG_CIFS_EXPERIMENTAL
++		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL)
++			rc = mode_to_acl(direntry->d_inode, full_path, mode);
++		else if ((mode & S_IWUGO) == 0) {
++#else
++		if ((mode & S_IWUGO) == 0) {
++#endif
++			/* not writeable */
+ 			if ((cifsInode->cifsAttrs & ATTR_READONLY) == 0) {
+ 				set_dosattr = TRUE;
+ 				time_buf.Attributes =
+@@ -1626,10 +1634,10 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
+ 			if (time_buf.Attributes == 0)
+ 				time_buf.Attributes |= cpu_to_le32(ATTR_NORMAL);
+ 		}
+-		/* BB to be implemented -
+-		   via Windows security descriptors or streams */
+-		/* CIFSSMBWinSetPerms(xid, pTcon, full_path, mode, uid, gid,
+-				      cifs_sb->local_nls); */
++#ifdef CONFIG_CIFS_EXPERIMENTAL
++		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL)
++			mode_to_acl(direntry->d_inode, full_path, mode);
++#endif
+ 	}
+ 
+ 	if (attrs->ia_valid & ATTR_ATIME) {
+diff --git a/fs/cifs/link.c b/fs/cifs/link.c
+index 11f2657..1d6fb01 100644
+--- a/fs/cifs/link.c
++++ b/fs/cifs/link.c
+@@ -1,7 +1,7 @@
+ /*
+  *   fs/cifs/link.c
   *
-- * Purpose : to determine the BIOS mapping used for a drive in a 
-+ * Description : determine the BIOS mapping/geometry used for a drive in a
-  *      SCSI-CAM system, storing the results in ip as required
-  *      by the HDIO_GETGEO ioctl().
+- *   Copyright (C) International Business Machines  Corp., 2002,2003
++ *   Copyright (C) International Business Machines  Corp., 2002,2008
+  *   Author(s): Steve French (sfrench at us.ibm.com)
   *
-  * Returns : -1 on failure, 0 on success.
-- *
-  */
+  *   This library is free software; you can redistribute it and/or modify
+@@ -236,8 +236,6 @@ cifs_readlink(struct dentry *direntry, char __user *pBuffer, int buflen)
+ 	char *full_path = NULL;
+ 	char *tmp_path = NULL;
+ 	char *tmpbuffer;
+-	unsigned char *referrals = NULL;
+-	unsigned int num_referrals = 0;
+ 	int len;
+ 	__u16 fid;
  
- int scsicam_bios_param(struct block_device *bdev, sector_t capacity, int *ip)
-@@ -98,15 +108,18 @@ int scsicam_bios_param(struct block_device *bdev, sector_t capacity, int *ip)
+@@ -297,8 +295,11 @@ cifs_readlink(struct dentry *direntry, char __user *pBuffer, int buflen)
+ 				cFYI(1, ("Error closing junction point "
+ 					 "(open for ioctl)"));
+ 			}
++			/* BB unwind this long, nested function, or remove BB */
+ 			if (rc == -EIO) {
+ 				/* Query if DFS Junction */
++				unsigned int num_referrals = 0;
++				struct dfs_info3_param *refs = NULL;
+ 				tmp_path =
+ 					kmalloc(MAX_TREE_SIZE + MAX_PATHCONF + 1,
+ 						GFP_KERNEL);
+@@ -310,7 +311,7 @@ cifs_readlink(struct dentry *direntry, char __user *pBuffer, int buflen)
+ 					rc = get_dfs_path(xid, pTcon->ses,
+ 						tmp_path,
+ 						cifs_sb->local_nls,
+-						&num_referrals, &referrals,
++						&num_referrals, &refs,
+ 						cifs_sb->mnt_cifs_flags &
+ 						    CIFS_MOUNT_MAP_SPECIAL_CHR);
+ 					cFYI(1, ("Get DFS for %s rc = %d ",
+@@ -320,14 +321,13 @@ cifs_readlink(struct dentry *direntry, char __user *pBuffer, int buflen)
+ 					else {
+ 						cFYI(1, ("num referral: %d",
+ 							num_referrals));
+-						if (referrals) {
+-							cFYI(1,("referral string: %s", referrals));
++						if (refs && refs->path_name) {
+ 							strncpy(tmpbuffer,
+-								referrals,
++								refs->path_name,
+ 								len-1);
+ 						}
+ 					}
+-					kfree(referrals);
++					kfree(refs);
+ 					kfree(tmp_path);
  }
- EXPORT_SYMBOL(scsicam_bios_param);
+ 				/* BB add code like else decode referrals
+diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c
+index d0cb469..d2153ab 100644
+--- a/fs/cifs/sess.c
++++ b/fs/cifs/sess.c
+@@ -528,9 +528,11 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
+ 			rc = -EOVERFLOW;
+ 			goto ssetup_exit;
+ 		}
+-		ses->server->mac_signing_key.len = msg->sesskey_len;
+-		memcpy(ses->server->mac_signing_key.data.krb5, msg->data,
+-			msg->sesskey_len);
++		if (first_time) {
++			ses->server->mac_signing_key.len = msg->sesskey_len;
++			memcpy(ses->server->mac_signing_key.data.krb5,
++				msg->data, msg->sesskey_len);
++		}
+ 		pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
+ 		capabilities |= CAP_EXTENDED_SECURITY;
+ 		pSMB->req.Capabilities = cpu_to_le32(capabilities);
+@@ -540,7 +542,7 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
  
--/*
-- * Function : static int scsi_partsize(unsigned char *buf, unsigned long 
-- *     capacity,unsigned int *cyls, unsigned int *hds, unsigned int *secs);
-+/**
-+ * scsi_partsize - Parse cylinders/heads/sectors from PC partition table
-+ * @buf: partition table, see scsi_bios_ptable()
-+ * @capacity: size of the disk in sectors
-+ * @cyls: put cylinders here
-+ * @hds: put heads here
-+ * @secs: put sectors here
-  *
-- * Purpose : to determine the BIOS mapping used to create the partition
-+ * Description: determine the BIOS mapping/geometry used to create the partition
-  *      table, storing the results in *cyls, *hds, and *secs 
-  *
-- * Returns : -1 on failure, 0 on success.
-- *
-+ * Returns: -1 on failure, 0 on success.
-  */
+ 		if (ses->capabilities & CAP_UNICODE) {
+ 			/* unicode strings must be word aligned */
+-			if (iov[0].iov_len % 2) {
++			if ((iov[0].iov_len + iov[1].iov_len) % 2) {
+ 				*bcc_ptr = 0;
+ 				bcc_ptr++;
+ 			}
+diff --git a/fs/coda/psdev.c b/fs/coda/psdev.c
+index dcc6aea..e3eb355 100644
+--- a/fs/coda/psdev.c
++++ b/fs/coda/psdev.c
+@@ -362,8 +362,8 @@ static int init_coda_psdev(void)
+ 		goto out_chrdev;
+ 	}		
+ 	for (i = 0; i < MAX_CODADEVS; i++)
+-		class_device_create(coda_psdev_class, NULL,
+-				MKDEV(CODA_PSDEV_MAJOR,i), NULL, "cfs%d", i);
++		device_create(coda_psdev_class, NULL,
++			      MKDEV(CODA_PSDEV_MAJOR,i), "cfs%d", i);
+ 	coda_sysctl_init();
+ 	goto out;
  
- int scsi_partsize(unsigned char *buf, unsigned long capacity,
-@@ -194,7 +207,7 @@ EXPORT_SYMBOL(scsi_partsize);
-  *
-  * WORKING                                                    X3T9.2
-  * DRAFT                                                        792D
-- *
-+ * see http://www.t10.org/ftp/t10/drafts/cam/cam-r12b.pdf
-  *
-  *                                                        Revision 6
-  *                                                         10-MAR-94
-diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
-index a69b155..24eba31 100644
---- a/drivers/scsi/sd.c
-+++ b/drivers/scsi/sd.c
-@@ -395,6 +395,15 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq)
+@@ -405,7 +405,7 @@ static int __init init_coda(void)
+ 	return 0;
+ out:
+ 	for (i = 0; i < MAX_CODADEVS; i++)
+-		class_device_destroy(coda_psdev_class, MKDEV(CODA_PSDEV_MAJOR, i));
++		device_destroy(coda_psdev_class, MKDEV(CODA_PSDEV_MAJOR, i));
+ 	class_destroy(coda_psdev_class);
+ 	unregister_chrdev(CODA_PSDEV_MAJOR, "coda");
+ 	coda_sysctl_clean();
+@@ -424,7 +424,7 @@ static void __exit exit_coda(void)
+                 printk("coda: failed to unregister filesystem\n");
+         }
+ 	for (i = 0; i < MAX_CODADEVS; i++)
+-		class_device_destroy(coda_psdev_class, MKDEV(CODA_PSDEV_MAJOR, i));
++		device_destroy(coda_psdev_class, MKDEV(CODA_PSDEV_MAJOR, i));
+ 	class_destroy(coda_psdev_class);
+ 	unregister_chrdev(CODA_PSDEV_MAJOR, "coda");
+ 	coda_sysctl_clean();
+diff --git a/fs/compat.c b/fs/compat.c
+index 15078ce..5216c3f 100644
+--- a/fs/compat.c
++++ b/fs/compat.c
+@@ -1104,10 +1104,6 @@ static ssize_t compat_do_readv_writev(int type, struct file *file,
+ 	if (ret < 0)
  		goto out;
- 	}
- 
-+	/*
-+	 * Some devices (some sdcards for one) don't like it if the
-+	 * last sector gets read in a larger then 1 sector read.
-+	 */
-+	if (unlikely(sdp->last_sector_bug &&
-+	    rq->nr_sectors > sdp->sector_size / 512 &&
-+	    block + this_count == get_capacity(disk)))
-+		this_count -= sdp->sector_size / 512;
-+
- 	SCSI_LOG_HLQUEUE(2, scmd_printk(KERN_INFO, SCpnt, "block=%llu\n",
- 					(unsigned long long)block));
- 
-@@ -736,6 +745,7 @@ static int sd_media_changed(struct gendisk *disk)
- {
- 	struct scsi_disk *sdkp = scsi_disk(disk);
- 	struct scsi_device *sdp = sdkp->device;
-+	struct scsi_sense_hdr *sshdr = NULL;
- 	int retval;
  
- 	SCSI_LOG_HLQUEUE(3, sd_printk(KERN_INFO, sdkp, "sd_media_changed\n"));
-@@ -749,8 +759,11 @@ static int sd_media_changed(struct gendisk *disk)
- 	 * can deal with it then.  It is only because of unrecoverable errors
- 	 * that we would ever take a device offline in the first place.
- 	 */
--	if (!scsi_device_online(sdp))
--		goto not_present;
-+	if (!scsi_device_online(sdp)) {
-+		set_media_not_present(sdkp);
-+		retval = 1;
-+		goto out;
-+	}
+-	ret = security_file_permission(file, type == READ ? MAY_READ:MAY_WRITE);
+-	if (ret)
+-		goto out;
+-
+ 	fnv = NULL;
+ 	if (type == READ) {
+ 		fn = file->f_op->read;
+diff --git a/fs/configfs/dir.c b/fs/configfs/dir.c
+index 50ed691..a48dc7d 100644
+--- a/fs/configfs/dir.c
++++ b/fs/configfs/dir.c
+@@ -546,7 +546,7 @@ static int populate_groups(struct config_group *group)
+ 		 * That said, taking our i_mutex is closer to mkdir
+ 		 * emulation, and shouldn't hurt.
+ 		 */
+-		mutex_lock(&dentry->d_inode->i_mutex);
++		mutex_lock_nested(&dentry->d_inode->i_mutex, I_MUTEX_CHILD);
  
- 	/*
- 	 * Using TEST_UNIT_READY enables differentiation between drive with
-@@ -762,8 +775,12 @@ static int sd_media_changed(struct gendisk *disk)
- 	 * sd_revalidate() is called.
- 	 */
- 	retval = -ENODEV;
--	if (scsi_block_when_processing_errors(sdp))
--		retval = scsi_test_unit_ready(sdp, SD_TIMEOUT, SD_MAX_RETRIES);
-+
-+	if (scsi_block_when_processing_errors(sdp)) {
-+		sshdr  = kzalloc(sizeof(*sshdr), GFP_KERNEL);
-+		retval = scsi_test_unit_ready(sdp, SD_TIMEOUT, SD_MAX_RETRIES,
-+					      sshdr);
-+	}
+ 		for (i = 0; group->default_groups[i]; i++) {
+ 			new_group = group->default_groups[i];
+@@ -1405,7 +1405,8 @@ int configfs_register_subsystem(struct configfs_subsystem *subsys)
+ 	sd = configfs_sb->s_root->d_fsdata;
+ 	link_group(to_config_group(sd->s_element), group);
  
- 	/*
- 	 * Unable to test, unit probably not ready.   This usually
-@@ -771,8 +788,13 @@ static int sd_media_changed(struct gendisk *disk)
- 	 * and we will figure it out later once the drive is
- 	 * available again.
- 	 */
--	if (retval)
--		 goto not_present;
-+	if (retval || (scsi_sense_valid(sshdr) &&
-+		       /* 0x3a is medium not present */
-+		       sshdr->asc == 0x3a)) {
-+		set_media_not_present(sdkp);
-+		retval = 1;
-+		goto out;
-+	}
+-	mutex_lock(&configfs_sb->s_root->d_inode->i_mutex);
++	mutex_lock_nested(&configfs_sb->s_root->d_inode->i_mutex,
++			I_MUTEX_PARENT);
  
- 	/*
- 	 * For removable scsi disk we have to recognise the presence
-@@ -783,12 +805,12 @@ static int sd_media_changed(struct gendisk *disk)
+ 	name.name = group->cg_item.ci_name;
+ 	name.len = strlen(name.name);
+diff --git a/fs/configfs/file.c b/fs/configfs/file.c
+index a3658f9..397cb50 100644
+--- a/fs/configfs/file.c
++++ b/fs/configfs/file.c
+@@ -320,7 +320,7 @@ int configfs_add_file(struct dentry * dir, const struct configfs_attribute * att
+ 	umode_t mode = (attr->ca_mode & S_IALLUGO) | S_IFREG;
+ 	int error = 0;
  
- 	retval = sdp->changed;
- 	sdp->changed = 0;
--
-+out:
-+	if (retval != sdkp->previous_state)
-+		sdev_evt_send_simple(sdp, SDEV_EVT_MEDIA_CHANGE, GFP_KERNEL);
-+	sdkp->previous_state = retval;
-+	kfree(sshdr);
- 	return retval;
--
--not_present:
--	set_media_not_present(sdkp);
--	return 1;
- }
+-	mutex_lock(&dir->d_inode->i_mutex);
++	mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_NORMAL);
+ 	error = configfs_make_dirent(parent_sd, NULL, (void *) attr, mode, type);
+ 	mutex_unlock(&dir->d_inode->i_mutex);
  
- static int sd_sync_cache(struct scsi_disk *sdkp)
-diff --git a/drivers/scsi/seagate.c b/drivers/scsi/seagate.c
-deleted file mode 100644
-index b113244..0000000
---- a/drivers/scsi/seagate.c
-+++ /dev/null
-@@ -1,1667 +0,0 @@
--/*
-- *    seagate.c Copyright (C) 1992, 1993 Drew Eckhardt
-- *      low level scsi driver for ST01/ST02, Future Domain TMC-885,
-- *      TMC-950 by Drew Eckhardt <drew at colorado.edu>
-- *
-- *      Note : TMC-880 boards don't work because they have two bits in
-- *              the status register flipped, I'll fix this "RSN"
-- *	[why do I have strong feeling that above message is from 1993? :-)
-- *	        pavel at ucw.cz]
-- *
-- *      This card does all the I/O via memory mapped I/O, so there is no need
-- *      to check or allocate a region of the I/O address space.
-- */
--
--/* 1996 - to use new read{b,w,l}, write{b,w,l}, and phys_to_virt
-- * macros, replaced assembler routines with C. There's probably a
-- * performance hit, but I only have a cdrom and can't tell. Define
-- * SEAGATE_USE_ASM if you want the old assembler code -- SJT
-- *
-- * 1998-jul-29 - created DPRINTK macros and made it work under 
-- * linux 2.1.112, simplified some #defines etc. <pavel at ucw.cz>
-- *
-- * Aug 2000 - aeb - deleted seagate_st0x_biosparam(). It would try to
-- * read the physical disk geometry, a bad mistake. Of course it doesn't
-- * matter much what geometry one invents, but on large disks it
-- * returned 256 (or more) heads, causing all kind of failures.
-- * Of course this means that people might see a different geometry now,
-- * so boot parameters may be necessary in some cases.
-- */
--
--/*
-- * Configuration :
-- * To use without BIOS -DOVERRIDE=base_address -DCONTROLLER=FD or SEAGATE
-- * -DIRQ will override the default of 5.
-- * Note: You can now set these options from the kernel's "command line".
-- * The syntax is:
-- *
-- *     st0x=ADDRESS,IRQ                (for a Seagate controller)
-- * or:
-- *     tmc8xx=ADDRESS,IRQ              (for a TMC-8xx or TMC-950 controller)
-- * eg:
-- *     tmc8xx=0xC8000,15
-- *
-- * will configure the driver for a TMC-8xx style controller using IRQ 15
-- * with a base address of 0xC8000.
-- *
-- * -DARBITRATE 
-- *      Will cause the host adapter to arbitrate for the
-- *      bus for better SCSI-II compatibility, rather than just
-- *      waiting for BUS FREE and then doing its thing.  Should
-- *      let us do one command per Lun when I integrate my
-- *      reorganization changes into the distribution sources.
-- *
-- * -DDEBUG=65535
-- *      Will activate debug code.
-- *
-- * -DFAST or -DFAST32 
-- *      Will use blind transfers where possible
-- *
-- * -DPARITY  
-- *      This will enable parity.
-- *
-- * -DSEAGATE_USE_ASM
-- *      Will use older seagate assembly code. should be (very small amount)
-- *      Faster.
-- *
-- * -DSLOW_RATE=50
-- *      Will allow compatibility with broken devices that don't
-- *      handshake fast enough (ie, some CD ROM's) for the Seagate
-- *      code.
-- *
-- *      50 is some number, It will let you specify a default
-- *      transfer rate if handshaking isn't working correctly.
-- *
-- * -DOLDCNTDATASCEME  There is a new sceme to set the CONTROL
-- *                    and DATA reigsters which complies more closely
-- *                    with the SCSI2 standard. This hopefully eliminates
-- *                    the need to swap the order these registers are
-- *                    'messed' with. It makes the following two options
-- *                    obsolete. To reenable the old sceme define this.
-- *
-- * The following to options are patches from the SCSI.HOWTO
-- *
-- * -DSWAPSTAT  This will swap the definitions for STAT_MSG and STAT_CD.
-- *
-- * -DSWAPCNTDATA  This will swap the order that seagate.c messes with
-- *                the CONTROL an DATA registers.
-- */
--
--#include <linux/module.h>
--#include <linux/interrupt.h>
--#include <linux/spinlock.h>
--#include <linux/signal.h>
--#include <linux/string.h>
--#include <linux/proc_fs.h>
--#include <linux/init.h>
--#include <linux/blkdev.h>
--#include <linux/stat.h>
--#include <linux/delay.h>
--#include <linux/io.h>
--
--#include <asm/system.h>
--#include <asm/uaccess.h>
--
--#include <scsi/scsi_cmnd.h>
--#include <scsi/scsi_device.h>
--#include <scsi/scsi.h>
--
--#include <scsi/scsi_dbg.h>
--#include <scsi/scsi_host.h>
--
--
--#ifdef DEBUG
--#define DPRINTK( when, msg... ) do { if ( (DEBUG & (when)) == (when) ) printk( msg ); } while (0)
--#else
--#define DPRINTK( when, msg... ) do { } while (0)
--#define DEBUG 0
--#endif
--#define DANY( msg... ) DPRINTK( 0xffff, msg );
--
--#ifndef IRQ
--#define IRQ 5
--#endif
--
--#ifdef FAST32
--#define FAST
--#endif
--
--#undef LINKED			/* Linked commands are currently broken! */
--
--#if defined(OVERRIDE) && !defined(CONTROLLER)
--#error Please use -DCONTROLLER=SEAGATE or -DCONTROLLER=FD to override controller type
--#endif
--
--#ifndef __i386__
--#undef SEAGATE_USE_ASM
--#endif
--
--/*
--	Thanks to Brian Antoine for the example code in his Messy-Loss ST-01
--		driver, and Mitsugu Suzuki for information on the ST-01
--		SCSI host.
--*/
--
--/*
--	CONTROL defines
--*/
--
--#define CMD_RST 		0x01
--#define CMD_SEL 		0x02
--#define CMD_BSY 		0x04
--#define CMD_ATTN    		0x08
--#define CMD_START_ARB		0x10
--#define CMD_EN_PARITY		0x20
--#define CMD_INTR		0x40
--#define CMD_DRVR_ENABLE		0x80
--
--/*
--	STATUS
--*/
--#ifdef SWAPSTAT
--#define STAT_MSG		0x08
--#define STAT_CD			0x02
--#else
--#define STAT_MSG		0x02
--#define STAT_CD			0x08
--#endif
--
--#define STAT_BSY		0x01
--#define STAT_IO			0x04
--#define STAT_REQ		0x10
--#define STAT_SEL		0x20
--#define STAT_PARITY		0x40
--#define STAT_ARB_CMPL		0x80
--
--/* 
--	REQUESTS
--*/
--
--#define REQ_MASK (STAT_CD |  STAT_IO | STAT_MSG)
--#define REQ_DATAOUT 0
--#define REQ_DATAIN STAT_IO
--#define REQ_CMDOUT STAT_CD
--#define REQ_STATIN (STAT_CD | STAT_IO)
--#define REQ_MSGOUT (STAT_MSG | STAT_CD)
--#define REQ_MSGIN (STAT_MSG | STAT_CD | STAT_IO)
--
--extern volatile int seagate_st0x_timeout;
--
--#ifdef PARITY
--#define BASE_CMD CMD_EN_PARITY
--#else
--#define BASE_CMD  0
--#endif
--
--/*
--	Debugging code
--*/
--
--#define PHASE_BUS_FREE 1
--#define PHASE_ARBITRATION 2
--#define PHASE_SELECTION 4
--#define PHASE_DATAIN 8
--#define PHASE_DATAOUT 0x10
--#define PHASE_CMDOUT 0x20
--#define PHASE_MSGIN 0x40
--#define PHASE_MSGOUT 0x80
--#define PHASE_STATUSIN 0x100
--#define PHASE_ETC (PHASE_DATAIN | PHASE_DATAOUT | PHASE_CMDOUT | PHASE_MSGIN | PHASE_MSGOUT | PHASE_STATUSIN)
--#define PRINT_COMMAND 0x200
--#define PHASE_EXIT 0x400
--#define PHASE_RESELECT 0x800
--#define DEBUG_FAST 0x1000
--#define DEBUG_SG   0x2000
--#define DEBUG_LINKED	0x4000
--#define DEBUG_BORKEN	0x8000
--
--/* 
-- *	Control options - these are timeouts specified in .01 seconds.
-- */
--
--/* 30, 20 work */
--#define ST0X_BUS_FREE_DELAY 25
--#define ST0X_SELECTION_DELAY 25
--
--#define SEAGATE 1		/* these determine the type of the controller */
--#define FD	2
--
--#define ST0X_ID_STR	"Seagate ST-01/ST-02"
--#define FD_ID_STR	"TMC-8XX/TMC-950"
--
--static int internal_command (unsigned char target, unsigned char lun,
--			     const void *cmnd,
--			     void *buff, int bufflen, int reselect);
--
--static int incommand;		/* set if arbitration has finished
--				   and we are in some command phase. */
--
--static unsigned int base_address = 0;	/* Where the card ROM starts, used to 
--					   calculate memory mapped register
--					   location.  */
--
--static void __iomem *st0x_cr_sr;	/* control register write, status
--					   register read.  256 bytes in
--					   length.
--					   Read is status of SCSI BUS, as per 
--					   STAT masks.  */
--
--static void __iomem *st0x_dr;	/* data register, read write 256
--				   bytes in length.  */
--
--static volatile int st0x_aborted = 0;	/* set when we are aborted, ie by a
--					   time out, etc.  */
--
--static unsigned char controller_type = 0;	/* set to SEAGATE for ST0x
--						   boards or FD for TMC-8xx
--						   boards */
--static int irq = IRQ;
--
--module_param(base_address, uint, 0);
--module_param(controller_type, byte, 0);
--module_param(irq, int, 0);
--MODULE_LICENSE("GPL");
--
--
--#define retcode(result) (((result) << 16) | (message << 8) | status)
--#define STATUS ((u8) readb(st0x_cr_sr))
--#define DATA ((u8) readb(st0x_dr))
--#define WRITE_CONTROL(d) { writeb((d), st0x_cr_sr); }
--#define WRITE_DATA(d) { writeb((d), st0x_dr); }
--
--#ifndef OVERRIDE
--static unsigned int seagate_bases[] = {
--	0xc8000, 0xca000, 0xcc000,
--	0xce000, 0xdc000, 0xde000
--};
--
--typedef struct {
--	const unsigned char *signature;
--	unsigned offset;
--	unsigned length;
--	unsigned char type;
--} Signature;
--
--static Signature __initdata signatures[] = {
--	{"ST01 v1.7  (C) Copyright 1987 Seagate", 15, 37, SEAGATE},
--	{"SCSI BIOS 2.00  (C) Copyright 1987 Seagate", 15, 40, SEAGATE},
--
--/*
-- * The following two lines are NOT mistakes.  One detects ROM revision
-- * 3.0.0, the other 3.2.  Since seagate has only one type of SCSI adapter,
-- * and this is not going to change, the "SEAGATE" and "SCSI" together
-- * are probably "good enough"
-- */
--
--	{"SEAGATE SCSI BIOS ", 16, 17, SEAGATE},
--	{"SEAGATE SCSI BIOS ", 17, 17, SEAGATE},
--
--/*
-- * However, future domain makes several incompatible SCSI boards, so specific
-- * signatures must be used.
-- */
--
--	{"FUTURE DOMAIN CORP. (C) 1986-1989 V5.0C2/14/89", 5, 46, FD},
--	{"FUTURE DOMAIN CORP. (C) 1986-1989 V6.0A7/28/89", 5, 46, FD},
--	{"FUTURE DOMAIN CORP. (C) 1986-1990 V6.0105/31/90", 5, 47, FD},
--	{"FUTURE DOMAIN CORP. (C) 1986-1990 V6.0209/18/90", 5, 47, FD},
--	{"FUTURE DOMAIN CORP. (C) 1986-1990 V7.009/18/90", 5, 46, FD},
--	{"FUTURE DOMAIN CORP. (C) 1992 V8.00.004/02/92", 5, 44, FD},
--	{"IBM F1 BIOS V1.1004/30/92", 5, 25, FD},
--	{"FUTURE DOMAIN TMC-950", 5, 21, FD},
--	/* Added for 2.2.16 by Matthias_Heidbrink at b.maus.de */
--	{"IBM F1 V1.2009/22/93", 5, 25, FD},
--};
--
--#define NUM_SIGNATURES ARRAY_SIZE(signatures)
--#endif				/* n OVERRIDE */
--
--/*
-- * hostno stores the hostnumber, as told to us by the init routine.
-- */
--
--static int hostno = -1;
--static void seagate_reconnect_intr (int, void *);
--static irqreturn_t do_seagate_reconnect_intr (int, void *);
--static int seagate_st0x_bus_reset(struct scsi_cmnd *);
--
--#ifdef FAST
--static int fast = 1;
--#else
--#define fast 0
--#endif
--
--#ifdef SLOW_RATE
--/*
-- * Support for broken devices :
-- * The Seagate board has a handshaking problem.  Namely, a lack
-- * thereof for slow devices.  You can blast 600K/second through
-- * it if you are polling for each byte, more if you do a blind
-- * transfer.  In the first case, with a fast device, REQ will
-- * transition high-low or high-low-high before your loop restarts
-- * and you'll have no problems.  In the second case, the board
-- * will insert wait states for up to 13.2 usecs for REQ to
-- * transition low->high, and everything will work.
-- *
-- * However, there's nothing in the state machine that says
-- * you *HAVE* to see a high-low-high set of transitions before
-- * sending the next byte, and slow things like the Trantor CD ROMS
-- * will break because of this.
-- *
-- * So, we need to slow things down, which isn't as simple as it
-- * seems.  We can't slow things down period, because then people
-- * who don't recompile their kernels will shoot me for ruining
-- * their performance.  We need to do it on a case per case basis.
-- *
-- * The best for performance will be to, only for borken devices
-- * (this is stored on a per-target basis in the scsi_devices array)
-- *
-- * Wait for a low->high transition before continuing with that
-- * transfer.  If we timeout, continue anyways.  We don't need
-- * a long timeout, because REQ should only be asserted until the
-- * corresponding ACK is received and processed.
-- *
-- * Note that we can't use the system timer for this, because of
-- * resolution, and we *really* can't use the timer chip since
-- * gettimeofday() and the beeper routines use that.  So,
-- * the best thing for us to do will be to calibrate a timing
-- * loop in the initialization code using the timer chip before
-- * gettimeofday() can screw with it.
-- *
-- * FIXME: this is broken (not borken :-). Empty loop costs less than
-- * loop with ISA access in it! -- pavel at ucw.cz
-- */
--
--static int borken_calibration = 0;
--
--static void __init borken_init (void)
--{
--	register int count = 0, start = jiffies + 1, stop = start + 25;
--
--	/* FIXME: There may be a better approach, this is a straight port for
--	   now */
--	preempt_disable();
--	while (time_before (jiffies, start))
--		cpu_relax();
--	for (; time_before (jiffies, stop); ++count)
--		cpu_relax();
--	preempt_enable();
--
--/*
-- * Ok, we now have a count for .25 seconds.  Convert to a
-- * count per second and divide by transfer rate in K.  */
--
--	borken_calibration = (count * 4) / (SLOW_RATE * 1024);
--
--	if (borken_calibration < 1)
--		borken_calibration = 1;
--}
--
--static inline void borken_wait (void)
--{
--	register int count;
--
--	for (count = borken_calibration; count && (STATUS & STAT_REQ); --count)
--		cpu_relax();
--	     	
--#if (DEBUG & DEBUG_BORKEN)
--	if (count)
--		printk ("scsi%d : borken timeout\n", hostno);
--#endif
--}
--
--#endif				/* def SLOW_RATE */
--
--/* These beasts only live on ISA, and ISA means 8MHz. Each ULOOP()
-- * contains at least one ISA access, which takes more than 0.125
-- * usec. So if we loop 8 times time in usec, we are safe.
-- */
--
--#define ULOOP( i ) for (clock = i*8;;)
--#define TIMEOUT (!(clock--))
--
--static int __init seagate_st0x_detect (struct scsi_host_template * tpnt)
--{
--	struct Scsi_Host *instance;
--	int i, j;
--	unsigned long cr, dr;
--
--	tpnt->proc_name = "seagate";
--/*
-- *	First, we try for the manual override.
-- */
--	DANY ("Autodetecting ST0x / TMC-8xx\n");
--
--	if (hostno != -1) {
--		printk (KERN_ERR "seagate_st0x_detect() called twice?!\n");
--		return 0;
--	}
--
--/* If the user specified the controller type from the command line,
--   controller_type will be non-zero, so don't try to detect one */
--
--	if (!controller_type) {
--#ifdef OVERRIDE
--		base_address = OVERRIDE;
--		controller_type = CONTROLLER;
--
--		DANY ("Base address overridden to %x, controller type is %s\n",
--		      base_address,
--		      controller_type == SEAGATE ? "SEAGATE" : "FD");
--#else				/* OVERRIDE */
--/*
-- * 	To detect this card, we simply look for the signature
-- *      from the BIOS version notice in all the possible locations
-- *      of the ROM's.  This has a nice side effect of not trashing
-- *      any register locations that might be used by something else.
-- *
-- * XXX - note that we probably should be probing the address
-- * space for the on-board RAM instead.
-- */
--
--		for (i = 0; i < ARRAY_SIZE(seagate_bases); ++i) {
--			void __iomem *p = ioremap(seagate_bases[i], 0x2000);
--			if (!p)
--				continue;
--			for (j = 0; j < NUM_SIGNATURES; ++j)
--				if (check_signature(p + signatures[j].offset, signatures[j].signature, signatures[j].length)) {
--					base_address = seagate_bases[i];
--					controller_type = signatures[j].type;
--					break;
--				}
--			iounmap(p);
--		}
--#endif				/* OVERRIDE */
--	}
--	/* (! controller_type) */
--	tpnt->this_id = (controller_type == SEAGATE) ? 7 : 6;
--	tpnt->name = (controller_type == SEAGATE) ? ST0X_ID_STR : FD_ID_STR;
--
--	if (!base_address) {
--		printk(KERN_INFO "seagate: ST0x/TMC-8xx not detected.\n");
--		return 0;
--	}
--
--	cr = base_address + (controller_type == SEAGATE ? 0x1a00 : 0x1c00);
--	dr = cr + 0x200;
--	st0x_cr_sr = ioremap(cr, 0x100);
--	st0x_dr = ioremap(dr, 0x100);
--
--	DANY("%s detected. Base address = %x, cr = %x, dr = %x\n",
--	      tpnt->name, base_address, cr, dr);
--
--	/*
--	 *	At all times, we will use IRQ 5.  Should also check for IRQ3
--	 *	if we lose our first interrupt.
--	 */
--	instance = scsi_register (tpnt, 0);
--	if (instance == NULL)
--		return 0;
--
--	hostno = instance->host_no;
--	if (request_irq (irq, do_seagate_reconnect_intr, IRQF_DISABLED, (controller_type == SEAGATE) ? "seagate" : "tmc-8xx", instance)) {
--		printk(KERN_ERR "scsi%d : unable to allocate IRQ%d\n", hostno, irq);
--		return 0;
--	}
--	instance->irq = irq;
--	instance->io_port = base_address;
--#ifdef SLOW_RATE
--	printk(KERN_INFO "Calibrating borken timer... ");
--	borken_init();
--	printk(" %d cycles per transfer\n", borken_calibration);
--#endif
--	printk (KERN_INFO "This is one second... ");
--	{
--		int clock;
--		ULOOP (1 * 1000 * 1000) {
--			STATUS;
--			if (TIMEOUT)
--				break;
--		}
--	}
--
--	printk ("done, %s options:"
--#ifdef ARBITRATE
--		" ARBITRATE"
--#endif
--#if DEBUG
--		" DEBUG"
--#endif
--#ifdef FAST
--		" FAST"
--#ifdef FAST32
--		"32"
--#endif
--#endif
--#ifdef LINKED
--		" LINKED"
--#endif
--#ifdef PARITY
--		" PARITY"
--#endif
--#ifdef SEAGATE_USE_ASM
--		" SEAGATE_USE_ASM"
--#endif
--#ifdef SLOW_RATE
--		" SLOW_RATE"
--#endif
--#ifdef SWAPSTAT
--		" SWAPSTAT"
--#endif
--#ifdef SWAPCNTDATA
--		" SWAPCNTDATA"
--#endif
--		"\n", tpnt->name);
--	return 1;
--}
+diff --git a/fs/configfs/mount.c b/fs/configfs/mount.c
+index 3bf0278..de3b31d 100644
+--- a/fs/configfs/mount.c
++++ b/fs/configfs/mount.c
+@@ -128,7 +128,7 @@ void configfs_release_fs(void)
+ }
+ 
+ 
+-static decl_subsys(config, NULL, NULL);
++static struct kobject *config_kobj;
+ 
+ static int __init configfs_init(void)
+ {
+@@ -140,9 +140,8 @@ static int __init configfs_init(void)
+ 	if (!configfs_dir_cachep)
+ 		goto out;
+ 
+-	kobj_set_kset_s(&config_subsys, kernel_subsys);
+-	err = subsystem_register(&config_subsys);
+-	if (err) {
++	config_kobj = kobject_create_and_add("config", kernel_kobj);
++	if (!config_kobj) {
+ 		kmem_cache_destroy(configfs_dir_cachep);
+ 		configfs_dir_cachep = NULL;
+ 		goto out;
+@@ -151,7 +150,7 @@ static int __init configfs_init(void)
+ 	err = register_filesystem(&configfs_fs_type);
+ 	if (err) {
+ 		printk(KERN_ERR "configfs: Unable to register filesystem!\n");
+-		subsystem_unregister(&config_subsys);
++		kobject_put(config_kobj);
+ 		kmem_cache_destroy(configfs_dir_cachep);
+ 		configfs_dir_cachep = NULL;
+ 		goto out;
+@@ -160,7 +159,7 @@ static int __init configfs_init(void)
+ 	err = configfs_inode_init();
+ 	if (err) {
+ 		unregister_filesystem(&configfs_fs_type);
+-		subsystem_unregister(&config_subsys);
++		kobject_put(config_kobj);
+ 		kmem_cache_destroy(configfs_dir_cachep);
+ 		configfs_dir_cachep = NULL;
+ 	}
+@@ -171,7 +170,7 @@ out:
+ static void __exit configfs_exit(void)
+ {
+ 	unregister_filesystem(&configfs_fs_type);
+-	subsystem_unregister(&config_subsys);
++	kobject_put(config_kobj);
+ 	kmem_cache_destroy(configfs_dir_cachep);
+ 	configfs_dir_cachep = NULL;
+ 	configfs_inode_exit();
+diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c
+index 6a713b3..d26e282 100644
+--- a/fs/debugfs/inode.c
++++ b/fs/debugfs/inode.c
+@@ -426,20 +426,19 @@ exit:
+ }
+ EXPORT_SYMBOL_GPL(debugfs_rename);
+ 
+-static decl_subsys(debug, NULL, NULL);
++static struct kobject *debug_kobj;
+ 
+ static int __init debugfs_init(void)
+ {
+ 	int retval;
+ 
+-	kobj_set_kset_s(&debug_subsys, kernel_subsys);
+-	retval = subsystem_register(&debug_subsys);
+-	if (retval)
+-		return retval;
++	debug_kobj = kobject_create_and_add("debug", kernel_kobj);
++	if (!debug_kobj)
++		return -EINVAL;
+ 
+ 	retval = register_filesystem(&debug_fs_type);
+ 	if (retval)
+-		subsystem_unregister(&debug_subsys);
++		kobject_put(debug_kobj);
+ 	return retval;
+ }
+ 
+@@ -447,7 +446,7 @@ static void __exit debugfs_exit(void)
+ {
+ 	simple_release_fs(&debugfs_mount, &debugfs_mount_count);
+ 	unregister_filesystem(&debug_fs_type);
+-	subsystem_unregister(&debug_subsys);
++	kobject_put(debug_kobj);
+ }
+ 
+ core_initcall(debugfs_init);
+diff --git a/fs/dlm/lockspace.c b/fs/dlm/lockspace.c
+index 6353a83..5c108c4 100644
+--- a/fs/dlm/lockspace.c
++++ b/fs/dlm/lockspace.c
+@@ -166,26 +166,7 @@ static struct kobj_type dlm_ktype = {
+ 	.release       = lockspace_kobj_release,
+ };
+ 
+-static struct kset dlm_kset = {
+-	.ktype  = &dlm_ktype,
+-};
 -
--static const char *seagate_st0x_info (struct Scsi_Host *shpnt)
+-static int kobject_setup(struct dlm_ls *ls)
 -{
--	static char buffer[64];
--
--	snprintf(buffer, 64, "%s at irq %d, address 0x%05X",
--		 (controller_type == SEAGATE) ? ST0X_ID_STR : FD_ID_STR,
--		 irq, base_address);
--	return buffer;
--}
--
--/*
-- * These are our saved pointers for the outstanding command that is
-- * waiting for a reconnect
-- */
--
--static unsigned char current_target, current_lun;
--static unsigned char *current_cmnd, *current_data;
--static int current_nobuffs;
--static struct scatterlist *current_buffer;
--static int current_bufflen;
--
--#ifdef LINKED
--/*
-- * linked_connected indicates whether or not we are currently connected to
-- * linked_target, linked_lun and in an INFORMATION TRANSFER phase,
-- * using linked commands.
-- */
--
--static int linked_connected = 0;
--static unsigned char linked_target, linked_lun;
--#endif
--
--static void (*done_fn) (struct scsi_cmnd *) = NULL;
--static struct scsi_cmnd *SCint = NULL;
--
--/*
-- * These control whether or not disconnect / reconnect will be attempted,
-- * or are being attempted.
-- */
+-	char lsname[DLM_LOCKSPACE_LEN];
+-	int error;
 -
--#define NO_RECONNECT    0
--#define RECONNECT_NOW   1
--#define CAN_RECONNECT   2
+-	memset(lsname, 0, DLM_LOCKSPACE_LEN);
+-	snprintf(lsname, DLM_LOCKSPACE_LEN, "%s", ls->ls_name);
 -
--/*
-- * LINKED_RIGHT indicates that we are currently connected to the correct target
-- * for this command, LINKED_WRONG indicates that we are connected to the wrong
-- * target. Note that these imply CAN_RECONNECT and require defined(LINKED).
-- */
+-	error = kobject_set_name(&ls->ls_kobj, "%s", lsname);
+-	if (error)
+-		return error;
 -
--#define LINKED_RIGHT    3
--#define LINKED_WRONG    4
+-	ls->ls_kobj.kset = &dlm_kset;
+-	ls->ls_kobj.ktype = &dlm_ktype;
+-	return 0;
+-}
++static struct kset *dlm_kset;
+ 
+ static int do_uevent(struct dlm_ls *ls, int in)
+ {
+@@ -220,24 +201,22 @@ static int do_uevent(struct dlm_ls *ls, int in)
+ 
+ int dlm_lockspace_init(void)
+ {
+-	int error;
 -
--/*
-- * This determines if we are expecting to reconnect or not.
-- */
+ 	ls_count = 0;
+ 	mutex_init(&ls_lock);
+ 	INIT_LIST_HEAD(&lslist);
+ 	spin_lock_init(&lslist_lock);
+ 
+-	kobject_set_name(&dlm_kset.kobj, "dlm");
+-	kobj_set_kset_s(&dlm_kset, kernel_subsys);
+-	error = kset_register(&dlm_kset);
+-	if (error)
+-		printk("dlm_lockspace_init: cannot register kset %d\n", error);
+-	return error;
++	dlm_kset = kset_create_and_add("dlm", NULL, kernel_kobj);
++	if (!dlm_kset) {
++		printk(KERN_WARNING "%s: can not create kset\n", __FUNCTION__);
++		return -ENOMEM;
++	}
++	return 0;
+ }
+ 
+ void dlm_lockspace_exit(void)
+ {
+-	kset_unregister(&dlm_kset);
++	kset_unregister(dlm_kset);
+ }
+ 
+ static int dlm_scand(void *data)
+@@ -549,13 +528,12 @@ static int new_lockspace(char *name, int namelen, void **lockspace,
+ 		goto out_delist;
+ 	}
+ 
+-	error = kobject_setup(ls);
+-	if (error)
+-		goto out_stop;
 -
--static int should_reconnect = 0;
+-	error = kobject_register(&ls->ls_kobj);
++	ls->ls_kobj.kset = dlm_kset;
++	error = kobject_init_and_add(&ls->ls_kobj, &dlm_ktype, NULL,
++				     "%s", ls->ls_name);
+ 	if (error)
+ 		goto out_stop;
++	kobject_uevent(&ls->ls_kobj, KOBJ_ADD);
+ 
+ 	/* let kobject handle freeing of ls if there's an error */
+ 	do_unreg = 1;
+@@ -601,7 +579,7 @@ static int new_lockspace(char *name, int namelen, void **lockspace,
+ 	kfree(ls->ls_rsbtbl);
+  out_lsfree:
+ 	if (do_unreg)
+-		kobject_unregister(&ls->ls_kobj);
++		kobject_put(&ls->ls_kobj);
+ 	else
+ 		kfree(ls);
+  out:
+@@ -750,7 +728,7 @@ static int release_lockspace(struct dlm_ls *ls, int force)
+ 	dlm_clear_members(ls);
+ 	dlm_clear_members_gone(ls);
+ 	kfree(ls->ls_node_array);
+-	kobject_unregister(&ls->ls_kobj);
++	kobject_put(&ls->ls_kobj);
+ 	/* The ls structure will be freed when the kobject is done with */
+ 
+ 	mutex_lock(&ls_lock);
+diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c
+index e5580bc..0249aa4 100644
+--- a/fs/ecryptfs/main.c
++++ b/fs/ecryptfs/main.c
+@@ -734,127 +734,40 @@ static int ecryptfs_init_kmem_caches(void)
+ 	return 0;
+ }
+ 
+-struct ecryptfs_obj {
+-	char *name;
+-	struct list_head slot_list;
+-	struct kobject kobj;
+-};
 -
--/*
-- * The seagate_reconnect_intr routine is called when a target reselects the
-- * host adapter.  This occurs on the interrupt triggered by the target
-- * asserting SEL.
-- */
+-struct ecryptfs_attribute {
+-	struct attribute attr;
+-	ssize_t(*show) (struct ecryptfs_obj *, char *);
+-	ssize_t(*store) (struct ecryptfs_obj *, const char *, size_t);
+-};
++static struct kobject *ecryptfs_kobj;
+ 
+-static ssize_t
+-ecryptfs_attr_store(struct kobject *kobj,
+-		    struct attribute *attr, const char *buf, size_t len)
++static ssize_t version_show(struct kobject *kobj,
++			    struct kobj_attribute *attr, char *buff)
+ {
+-	struct ecryptfs_obj *obj = container_of(kobj, struct ecryptfs_obj,
+-						kobj);
+-	struct ecryptfs_attribute *attribute =
+-		container_of(attr, struct ecryptfs_attribute, attr);
 -
--static irqreturn_t do_seagate_reconnect_intr(int irq, void *dev_id)
+-	return (attribute->store ? attribute->store(obj, buf, len) : 0);
++	return snprintf(buff, PAGE_SIZE, "%d\n", ECRYPTFS_VERSIONING_MASK);
+ }
+ 
+-static ssize_t
+-ecryptfs_attr_show(struct kobject *kobj, struct attribute *attr, char *buf)
 -{
--	unsigned long flags;
--	struct Scsi_Host *dev = dev_id;
--	
--	spin_lock_irqsave (dev->host_lock, flags);
--	seagate_reconnect_intr (irq, dev_id);
--	spin_unlock_irqrestore (dev->host_lock, flags);
--	return IRQ_HANDLED;
+-	struct ecryptfs_obj *obj = container_of(kobj, struct ecryptfs_obj,
+-						kobj);
+-	struct ecryptfs_attribute *attribute =
+-		container_of(attr, struct ecryptfs_attribute, attr);
+-
+-	return (attribute->show ? attribute->show(obj, buf) : 0);
 -}
++static struct kobj_attribute version_attr = __ATTR_RO(version);
+ 
+-static struct sysfs_ops ecryptfs_sysfs_ops = {
+-	.show = ecryptfs_attr_show,
+-	.store = ecryptfs_attr_store
++static struct attribute *attributes[] = {
++	&version_attr.attr,
++	NULL,
+ };
+ 
+-static struct kobj_type ecryptfs_ktype = {
+-	.sysfs_ops = &ecryptfs_sysfs_ops
++static struct attribute_group attr_group = {
++	.attrs = attributes,
+ };
+ 
+-static decl_subsys(ecryptfs, &ecryptfs_ktype, NULL);
 -
--static void seagate_reconnect_intr (int irq, void *dev_id)
+-static ssize_t version_show(struct ecryptfs_obj *obj, char *buff)
 -{
--	int temp;
--	struct scsi_cmnd *SCtmp;
--
--	DPRINTK (PHASE_RESELECT, "scsi%d : seagate_reconnect_intr() called\n", hostno);
--
--	if (!should_reconnect)
--		printk(KERN_WARNING "scsi%d: unexpected interrupt.\n", hostno);
--	else {
--		should_reconnect = 0;
--
--		DPRINTK (PHASE_RESELECT, "scsi%d : internal_command(%d, %08x, %08x, RECONNECT_NOW\n", 
--			hostno, current_target, current_data, current_bufflen);
--
--		temp = internal_command (current_target, current_lun, current_cmnd, current_data, current_bufflen, RECONNECT_NOW);
--
--		if (msg_byte(temp) != DISCONNECT) {
--			if (done_fn) {
--				DPRINTK(PHASE_RESELECT, "scsi%d : done_fn(%d,%08x)", hostno, hostno, temp);
--				if (!SCint)
--					panic ("SCint == NULL in seagate");
--				SCtmp = SCint;
--				SCint = NULL;
--				SCtmp->result = temp;
--				done_fn(SCtmp);
--			} else
--				printk(KERN_ERR "done_fn() not defined.\n");
--		}
--	}
+-	return snprintf(buff, PAGE_SIZE, "%d\n", ECRYPTFS_VERSIONING_MASK);
 -}
 -
--/*
-- * The seagate_st0x_queue_command() function provides a queued interface
-- * to the seagate SCSI driver.  Basically, it just passes control onto the
-- * seagate_command() function, after fixing it so that the done_fn()
-- * is set to the one passed to the function.  We have to be very careful,
-- * because there are some commands on some devices that do not disconnect,
-- * and if we simply call the done_fn when the command is done then another
-- * command is started and queue_command is called again...  We end up
-- * overflowing the kernel stack, and this tends not to be such a good idea.
-- */
+-static struct ecryptfs_attribute sysfs_attr_version = __ATTR_RO(version);
 -
--static int recursion_depth = 0;
+-static struct ecryptfs_version_str_map_elem {
+-	u32 flag;
+-	char *str;
+-} ecryptfs_version_str_map[] = {
+-	{ECRYPTFS_VERSIONING_PASSPHRASE, "passphrase"},
+-	{ECRYPTFS_VERSIONING_PUBKEY, "pubkey"},
+-	{ECRYPTFS_VERSIONING_PLAINTEXT_PASSTHROUGH, "plaintext passthrough"},
+-	{ECRYPTFS_VERSIONING_POLICY, "policy"},
+-	{ECRYPTFS_VERSIONING_XATTR, "metadata in extended attribute"},
+-	{ECRYPTFS_VERSIONING_MULTKEY, "multiple keys per file"}
+-};
 -
--static int seagate_st0x_queue_command(struct scsi_cmnd * SCpnt,
--				      void (*done) (struct scsi_cmnd *))
+-static ssize_t version_str_show(struct ecryptfs_obj *obj, char *buff)
 -{
--	int result, reconnect;
--	struct scsi_cmnd *SCtmp;
--
--	DANY ("seagate: que_command");
--	done_fn = done;
--	current_target = SCpnt->device->id;
--	current_lun = SCpnt->device->lun;
--	current_cmnd = SCpnt->cmnd;
--	current_data = (unsigned char *) SCpnt->request_buffer;
--	current_bufflen = SCpnt->request_bufflen;
--	SCint = SCpnt;
--	if (recursion_depth)
--		return 1;
--	recursion_depth++;
--	do {
--#ifdef LINKED
--		/*
--		 * Set linked command bit in control field of SCSI command.
--		 */
+-	int i;
+-	int remaining = PAGE_SIZE;
+-	int total_written = 0;
 -
--		current_cmnd[SCpnt->cmd_len] |= 0x01;
--		if (linked_connected) {
--			DPRINTK (DEBUG_LINKED, "scsi%d : using linked commands, current I_T_L nexus is ", hostno);
--			if (linked_target == current_target && linked_lun == current_lun) 
--			{
--				DPRINTK(DEBUG_LINKED, "correct\n");
--				reconnect = LINKED_RIGHT;
--			} else {
--				DPRINTK(DEBUG_LINKED, "incorrect\n");
--				reconnect = LINKED_WRONG;
--			}
--		} else
--#endif				/* LINKED */
--			reconnect = CAN_RECONNECT;
+-	buff[0] = '\0';
+-	for (i = 0; i < ARRAY_SIZE(ecryptfs_version_str_map); i++) {
+-		int entry_size;
 -
--		result = internal_command(SCint->device->id, SCint->device->lun, SCint->cmnd,
--				      SCint->request_buffer, SCint->request_bufflen, reconnect);
--		if (msg_byte(result) == DISCONNECT)
--			break;
--		SCtmp = SCint;
--		SCint = NULL;
--		SCtmp->result = result;
--		done_fn(SCtmp);
+-		if (!(ECRYPTFS_VERSIONING_MASK
+-		      & ecryptfs_version_str_map[i].flag))
+-			continue;
+-		entry_size = strlen(ecryptfs_version_str_map[i].str);
+-		if ((entry_size + 2) > remaining)
+-			goto out;
+-		memcpy(buff, ecryptfs_version_str_map[i].str, entry_size);
+-		buff[entry_size++] = '\n';
+-		buff[entry_size] = '\0';
+-		buff += entry_size;
+-		total_written += entry_size;
+-		remaining -= entry_size;
 -	}
--	while (SCint);
--	recursion_depth--;
--	return 0;
+-out:
+-	return total_written;
 -}
 -
--static int internal_command (unsigned char target, unsigned char lun,
--		  const void *cmnd, void *buff, int bufflen, int reselect)
--{
--	unsigned char *data = NULL;
--	struct scatterlist *buffer = NULL;
--	int clock, temp, nobuffs = 0, done = 0, len = 0;
--#if DEBUG
--	int transfered = 0, phase = 0, newphase;
--#endif
--	register unsigned char status_read;
--	unsigned char tmp_data, tmp_control, status = 0, message = 0;
--	unsigned transfersize = 0, underflow = 0;
--#ifdef SLOW_RATE
--	int borken = (int) SCint->device->borken;	/* Does the current target require
--							   Very Slow I/O ?  */
--#endif
--
--	incommand = 0;
--	st0x_aborted = 0;
--
--#if (DEBUG & PRINT_COMMAND)
--	printk("scsi%d : target = %d, command = ", hostno, target);
--	__scsi_print_command((unsigned char *) cmnd);
--#endif
+-static struct ecryptfs_attribute sysfs_attr_version_str = __ATTR_RO(version_str);
 -
--#if (DEBUG & PHASE_RESELECT)
--	switch (reselect) {
--	case RECONNECT_NOW:
--		printk("scsi%d : reconnecting\n", hostno);
--		break;
--#ifdef LINKED
--	case LINKED_RIGHT:
--		printk("scsi%d : connected, can reconnect\n", hostno);
--		break;
--	case LINKED_WRONG:
--		printk("scsi%d : connected to wrong target, can reconnect\n",
--			hostno);
--		break;
--#endif
--	case CAN_RECONNECT:
--		printk("scsi%d : allowed to reconnect\n", hostno);
--		break;
--	default:
--		printk("scsi%d : not allowed to reconnect\n", hostno);
+ static int do_sysfs_registration(void)
+ {
+ 	int rc;
+ 
+-	rc = subsystem_register(&ecryptfs_subsys);
+-	if (rc) {
+-		printk(KERN_ERR
+-		       "Unable to register ecryptfs sysfs subsystem\n");
+-		goto out;
 -	}
--#endif
--
--	if (target == (controller_type == SEAGATE ? 7 : 6))
--		return DID_BAD_TARGET;
--
--	/*
--	 *	We work it differently depending on if this is is "the first time,"
--	 *      or a reconnect.  If this is a reselect phase, then SEL will
--	 *      be asserted, and we must skip selection / arbitration phases.
--	 */
+-	rc = sysfs_create_file(&ecryptfs_subsys.kobj,
+-			       &sysfs_attr_version.attr);
+-	if (rc) {
+-		printk(KERN_ERR
+-		       "Unable to create ecryptfs version attribute\n");
+-		subsystem_unregister(&ecryptfs_subsys);
++	ecryptfs_kobj = kobject_create_and_add("ecryptfs", fs_kobj);
++	if (!ecryptfs_kobj) {
++		printk(KERN_ERR "Unable to create ecryptfs kset\n");
++		rc = -ENOMEM;
+ 		goto out;
+ 	}
+-	rc = sysfs_create_file(&ecryptfs_subsys.kobj,
+-			       &sysfs_attr_version_str.attr);
++	rc = sysfs_create_group(ecryptfs_kobj, &attr_group);
+ 	if (rc) {
+ 		printk(KERN_ERR
+-		       "Unable to create ecryptfs version_str attribute\n");
+-		sysfs_remove_file(&ecryptfs_subsys.kobj,
+-				  &sysfs_attr_version.attr);
+-		subsystem_unregister(&ecryptfs_subsys);
+-		goto out;
++		       "Unable to create ecryptfs version attributes\n");
++		kobject_put(ecryptfs_kobj);
+ 	}
+ out:
+ 	return rc;
+@@ -862,11 +775,8 @@ out:
+ 
+ static void do_sysfs_unregistration(void)
+ {
+-	sysfs_remove_file(&ecryptfs_subsys.kobj,
+-			  &sysfs_attr_version.attr);
+-	sysfs_remove_file(&ecryptfs_subsys.kobj,
+-			  &sysfs_attr_version_str.attr);
+-	subsystem_unregister(&ecryptfs_subsys);
++	sysfs_remove_group(ecryptfs_kobj, &attr_group);
++	kobject_put(ecryptfs_kobj);
+ }
+ 
+ static int __init ecryptfs_init(void)
+@@ -894,7 +804,6 @@ static int __init ecryptfs_init(void)
+ 		printk(KERN_ERR "Failed to register filesystem\n");
+ 		goto out_free_kmem_caches;
+ 	}
+-	kobj_set_kset_s(&ecryptfs_subsys, fs_subsys);
+ 	rc = do_sysfs_registration();
+ 	if (rc) {
+ 		printk(KERN_ERR "sysfs registration failed\n");
+diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
+index 84f9f7d..e5e80d1 100644
+--- a/fs/fuse/inode.c
++++ b/fs/fuse/inode.c
+@@ -744,9 +744,6 @@ static inline void unregister_fuseblk(void)
+ }
+ #endif
+ 
+-static decl_subsys(fuse, NULL, NULL);
+-static decl_subsys(connections, NULL, NULL);
 -
--	switch (reselect) {
--	case RECONNECT_NOW:
--		DPRINTK (PHASE_RESELECT, "scsi%d : phase RESELECT \n", hostno);
--		/*
--		 *	At this point, we should find the logical or of our ID
--		 *	and the original target's ID on the BUS, with BSY, SEL,
--		 *	and I/O signals asserted.
--		 *
--		 *      After ARBITRATION phase is completed, only SEL, BSY,
--		 *	and the target ID are asserted.  A valid initiator ID
--		 *	is not on the bus until IO is asserted, so we must wait
--		 *	for that.
--		 */
--		ULOOP (100 * 1000) {
--			temp = STATUS;
--			if ((temp & STAT_IO) && !(temp & STAT_BSY))
--				break;
--			if (TIMEOUT) {
--				DPRINTK (PHASE_RESELECT, "scsi%d : RESELECT timed out while waiting for IO .\n", hostno);
--				return (DID_BAD_INTR << 16);
+ static void fuse_inode_init_once(struct kmem_cache *cachep, void *foo)
+ {
+ 	struct inode * inode = foo;
+@@ -791,32 +788,37 @@ static void fuse_fs_cleanup(void)
+ 	kmem_cache_destroy(fuse_inode_cachep);
+ }
+ 
++static struct kobject *fuse_kobj;
++static struct kobject *connections_kobj;
++
+ static int fuse_sysfs_init(void)
+ {
+ 	int err;
+ 
+-	kobj_set_kset_s(&fuse_subsys, fs_subsys);
+-	err = subsystem_register(&fuse_subsys);
+-	if (err)
++	fuse_kobj = kobject_create_and_add("fuse", fs_kobj);
++	if (!fuse_kobj) {
++		err = -ENOMEM;
+ 		goto out_err;
++	}
+ 
+-	kobj_set_kset_s(&connections_subsys, fuse_subsys);
+-	err = subsystem_register(&connections_subsys);
+-	if (err)
++	connections_kobj = kobject_create_and_add("connections", fuse_kobj);
++	if (!connections_kobj) {
++		err = -ENOMEM;
+ 		goto out_fuse_unregister;
++	}
+ 
+ 	return 0;
+ 
+  out_fuse_unregister:
+-	subsystem_unregister(&fuse_subsys);
++	kobject_put(fuse_kobj);
+  out_err:
+ 	return err;
+ }
+ 
+ static void fuse_sysfs_cleanup(void)
+ {
+-	subsystem_unregister(&connections_subsys);
+-	subsystem_unregister(&fuse_subsys);
++	kobject_put(connections_kobj);
++	kobject_put(fuse_kobj);
+ }
+ 
+ static int __init fuse_init(void)
+diff --git a/fs/gfs2/Makefile b/fs/gfs2/Makefile
+index 04ad0ca..8fff110 100644
+--- a/fs/gfs2/Makefile
++++ b/fs/gfs2/Makefile
+@@ -2,7 +2,7 @@ obj-$(CONFIG_GFS2_FS) += gfs2.o
+ gfs2-y := acl.o bmap.o daemon.o dir.o eaops.o eattr.o glock.o \
+ 	glops.o inode.o lm.o log.o lops.o locking.o main.o meta_io.o \
+ 	mount.o ops_address.o ops_dentry.o ops_export.o ops_file.o \
+-	ops_fstype.o ops_inode.o ops_super.o ops_vm.o quota.o \
++	ops_fstype.o ops_inode.o ops_super.o quota.o \
+ 	recovery.o rgrp.o super.o sys.o trans.o util.o
+ 
+ obj-$(CONFIG_GFS2_FS_LOCKING_NOLOCK) += locking/nolock/
+diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c
+index 93fa427..e4effc4 100644
+--- a/fs/gfs2/bmap.c
++++ b/fs/gfs2/bmap.c
+@@ -59,7 +59,6 @@ struct strip_mine {
+ static int gfs2_unstuffer_page(struct gfs2_inode *ip, struct buffer_head *dibh,
+ 			       u64 block, struct page *page)
+ {
+-	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+ 	struct inode *inode = &ip->i_inode;
+ 	struct buffer_head *bh;
+ 	int release = 0;
+@@ -95,7 +94,7 @@ static int gfs2_unstuffer_page(struct gfs2_inode *ip, struct buffer_head *dibh,
+ 	set_buffer_uptodate(bh);
+ 	if (!gfs2_is_jdata(ip))
+ 		mark_buffer_dirty(bh);
+-	if (sdp->sd_args.ar_data == GFS2_DATA_ORDERED || gfs2_is_jdata(ip))
++	if (!gfs2_is_writeback(ip))
+ 		gfs2_trans_add_bh(ip->i_gl, bh, 0);
+ 
+ 	if (release) {
+@@ -453,8 +452,8 @@ static inline void bmap_unlock(struct inode *inode, int create)
+  * Returns: errno
+  */
+ 
+-int gfs2_block_map(struct inode *inode, u64 lblock, int create,
+-		   struct buffer_head *bh_map)
++int gfs2_block_map(struct inode *inode, sector_t lblock,
++		   struct buffer_head *bh_map, int create)
+ {
+ 	struct gfs2_inode *ip = GFS2_I(inode);
+ 	struct gfs2_sbd *sdp = GFS2_SB(inode);
+@@ -470,6 +469,7 @@ int gfs2_block_map(struct inode *inode, u64 lblock, int create,
+ 	unsigned int maxlen = bh_map->b_size >> inode->i_blkbits;
+ 	struct metapath mp;
+ 	u64 size;
++	struct buffer_head *dibh = NULL;
+ 
+ 	BUG_ON(maxlen == 0);
+ 
+@@ -500,6 +500,8 @@ int gfs2_block_map(struct inode *inode, u64 lblock, int create,
+ 	error = gfs2_meta_inode_buffer(ip, &bh);
+ 	if (error)
+ 		goto out_fail;
++	dibh = bh;
++	get_bh(dibh);
+ 
+ 	for (x = 0; x < end_of_metadata; x++) {
+ 		lookup_block(ip, bh, x, &mp, create, &new, &dblock);
+@@ -518,13 +520,8 @@ int gfs2_block_map(struct inode *inode, u64 lblock, int create,
+ 		if (boundary)
+ 			set_buffer_boundary(bh_map);
+ 		if (new) {
+-			struct buffer_head *dibh;
+-			error = gfs2_meta_inode_buffer(ip, &dibh);
+-			if (!error) {
+-				gfs2_trans_add_bh(ip->i_gl, dibh, 1);
+-				gfs2_dinode_out(ip, dibh->b_data);
+-				brelse(dibh);
 -			}
--		}
--
--		/*
--		 *	After I/O is asserted by the target, we can read our ID
--		 *	and its ID off of the BUS.
--		 */
--
--		if (!((temp = DATA) & (controller_type == SEAGATE ? 0x80 : 0x40))) {
--			DPRINTK (PHASE_RESELECT, "scsi%d : detected reconnect request to different target.\n\tData bus = %d\n", hostno, temp);
--			return (DID_BAD_INTR << 16);
--		}
--
--		if (!(temp & (1 << current_target))) {
--			printk(KERN_WARNING "scsi%d : Unexpected reselect interrupt.  Data bus = %d\n", hostno, temp);
--			return (DID_BAD_INTR << 16);
--		}
--
--		buffer = current_buffer;
--		cmnd = current_cmnd;	/* WDE add */
--		data = current_data;	/* WDE add */
--		len = current_bufflen;	/* WDE add */
--		nobuffs = current_nobuffs;
++			gfs2_trans_add_bh(ip->i_gl, dibh, 1);
++			gfs2_dinode_out(ip, dibh->b_data);
+ 			set_buffer_new(bh_map);
+ 			goto out_brelse;
+ 		}
+@@ -545,6 +542,8 @@ out_brelse:
+ out_ok:
+ 	error = 0;
+ out_fail:
++	if (dibh)
++		brelse(dibh);
+ 	bmap_unlock(inode, create);
+ 	return error;
+ }
+@@ -560,7 +559,7 @@ int gfs2_extent_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, unsi
+ 	BUG_ON(!new);
+ 
+ 	bh.b_size = 1 << (inode->i_blkbits + 5);
+-	ret = gfs2_block_map(inode, lblock, create, &bh);
++	ret = gfs2_block_map(inode, lblock, &bh, create);
+ 	*extlen = bh.b_size >> inode->i_blkbits;
+ 	*dblock = bh.b_blocknr;
+ 	if (buffer_new(&bh))
+@@ -684,7 +683,7 @@ static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh,
+ 	if (metadata)
+ 		revokes = (height) ? sdp->sd_inptrs : sdp->sd_diptrs;
+ 
+-	error = gfs2_rindex_hold(sdp, &ip->i_alloc.al_ri_gh);
++	error = gfs2_rindex_hold(sdp, &ip->i_alloc->al_ri_gh);
+ 	if (error)
+ 		return error;
+ 
+@@ -786,7 +785,7 @@ out_rg_gunlock:
+ out_rlist:
+ 	gfs2_rlist_free(&rlist);
+ out:
+-	gfs2_glock_dq_uninit(&ip->i_alloc.al_ri_gh);
++	gfs2_glock_dq_uninit(&ip->i_alloc->al_ri_gh);
+ 	return error;
+ }
+ 
+@@ -879,7 +878,6 @@ static int gfs2_block_truncate_page(struct address_space *mapping)
+ {
+ 	struct inode *inode = mapping->host;
+ 	struct gfs2_inode *ip = GFS2_I(inode);
+-	struct gfs2_sbd *sdp = GFS2_SB(inode);
+ 	loff_t from = inode->i_size;
+ 	unsigned long index = from >> PAGE_CACHE_SHIFT;
+ 	unsigned offset = from & (PAGE_CACHE_SIZE-1);
+@@ -911,7 +909,7 @@ static int gfs2_block_truncate_page(struct address_space *mapping)
+ 	err = 0;
+ 
+ 	if (!buffer_mapped(bh)) {
+-		gfs2_get_block(inode, iblock, bh, 0);
++		gfs2_block_map(inode, iblock, bh, 0);
+ 		/* unmapped? It's a hole - nothing to do */
+ 		if (!buffer_mapped(bh))
+ 			goto unlock;
+@@ -931,7 +929,7 @@ static int gfs2_block_truncate_page(struct address_space *mapping)
+ 		err = 0;
+ 	}
+ 
+-	if (sdp->sd_args.ar_data == GFS2_DATA_ORDERED || gfs2_is_jdata(ip))
++	if (!gfs2_is_writeback(ip))
+ 		gfs2_trans_add_bh(ip->i_gl, bh, 0);
+ 
+ 	zero_user_page(page, offset, length, KM_USER0);
+@@ -1224,8 +1222,13 @@ int gfs2_write_alloc_required(struct gfs2_inode *ip, u64 offset,
+ 		do_div(lblock_stop, bsize);
+ 	} else {
+ 		unsigned int shift = sdp->sd_sb.sb_bsize_shift;
++		u64 end_of_file = (ip->i_di.di_size + sdp->sd_sb.sb_bsize - 1) >> shift;
+ 		lblock = offset >> shift;
+ 		lblock_stop = (offset + len + sdp->sd_sb.sb_bsize - 1) >> shift;
++		if (lblock_stop > end_of_file) {
++			*alloc_required = 1;
++			return 0;
++		}
+ 	}
+ 
+ 	for (; lblock < lblock_stop; lblock += extlen) {
+diff --git a/fs/gfs2/bmap.h b/fs/gfs2/bmap.h
+index ac2fd04..4e6cde2 100644
+--- a/fs/gfs2/bmap.h
++++ b/fs/gfs2/bmap.h
+@@ -15,7 +15,7 @@ struct gfs2_inode;
+ struct page;
+ 
+ int gfs2_unstuff_dinode(struct gfs2_inode *ip, struct page *page);
+-int gfs2_block_map(struct inode *inode, u64 lblock, int create, struct buffer_head *bh);
++int gfs2_block_map(struct inode *inode, sector_t lblock, struct buffer_head *bh, int create);
+ int gfs2_extent_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, unsigned *extlen);
+ 
+ int gfs2_truncatei(struct gfs2_inode *ip, u64 size);
+diff --git a/fs/gfs2/daemon.c b/fs/gfs2/daemon.c
+index 3731ab0..e519919 100644
+--- a/fs/gfs2/daemon.c
++++ b/fs/gfs2/daemon.c
+@@ -83,56 +83,6 @@ int gfs2_recoverd(void *data)
+ }
+ 
+ /**
+- * gfs2_logd - Update log tail as Active Items get flushed to in-place blocks
+- * @sdp: Pointer to GFS2 superblock
+- *
+- * Also, periodically check to make sure that we're using the most recent
+- * journal index.
+- */
 -
--		/*
--		 *	We have determined that we have been selected.  At this
--		 *	point, we must respond to the reselection by asserting
--		 *	BSY ourselves
--		 */
+-int gfs2_logd(void *data)
+-{
+-	struct gfs2_sbd *sdp = data;
+-	struct gfs2_holder ji_gh;
+-	unsigned long t;
+-	int need_flush;
 -
--#if 1
--		WRITE_CONTROL (BASE_CMD | CMD_DRVR_ENABLE | CMD_BSY);
--#else
--		WRITE_CONTROL (BASE_CMD | CMD_BSY);
--#endif
+-	while (!kthread_should_stop()) {
+-		/* Advance the log tail */
 -
--		/*
--		 *	The target will drop SEL, and raise BSY, at which time
--		 *	we must drop BSY.
--		 */
+-		t = sdp->sd_log_flush_time +
+-		    gfs2_tune_get(sdp, gt_log_flush_secs) * HZ;
 -
--		ULOOP (100 * 1000) {
--			if (!(STATUS & STAT_SEL))
--				break;
--			if (TIMEOUT) {
--				WRITE_CONTROL (BASE_CMD | CMD_INTR);
--				DPRINTK (PHASE_RESELECT, "scsi%d : RESELECT timed out while waiting for SEL.\n", hostno);
--				return (DID_BAD_INTR << 16);
--			}
+-		gfs2_ail1_empty(sdp, DIO_ALL);
+-		gfs2_log_lock(sdp);
+-		need_flush = sdp->sd_log_num_buf > gfs2_tune_get(sdp, gt_incore_log_blocks);
+-		gfs2_log_unlock(sdp);
+-		if (need_flush || time_after_eq(jiffies, t)) {
+-			gfs2_log_flush(sdp, NULL);
+-			sdp->sd_log_flush_time = jiffies;
 -		}
--		WRITE_CONTROL (BASE_CMD);
--		/*
--		 *	At this point, we have connected with the target
--		 *	and can get on with our lives.
--		 */
--		break;
--	case CAN_RECONNECT:
--#ifdef LINKED
--		/*
--		 * This is a bletcherous hack, just as bad as the Unix #!
--		 * interpreter stuff. If it turns out we are using the wrong
--		 * I_T_L nexus, the easiest way to deal with it is to go into
--		 *  our INFORMATION TRANSFER PHASE code, send a ABORT
--		 * message on MESSAGE OUT phase, and then loop back to here.
--		 */
--connect_loop:
--#endif
--		DPRINTK (PHASE_BUS_FREE, "scsi%d : phase = BUS FREE \n", hostno);
--
--		/*
--		 *    BUS FREE PHASE
--		 *
--		 *      On entry, we make sure that the BUS is in a BUS FREE
--		 *      phase, by insuring that both BSY and SEL are low for
--		 *      at least one bus settle delay.  Several reads help
--		 *      eliminate wire glitch.
--		 */
--
--#ifndef ARBITRATE
--#error FIXME: this is broken: we may not use jiffies here - we are under cli(). It will hardlock.
--		clock = jiffies + ST0X_BUS_FREE_DELAY;
--
--		while (((STATUS | STATUS | STATUS) & (STAT_BSY | STAT_SEL)) && (!st0x_aborted) && time_before (jiffies, clock))
--			cpu_relax();
--
--		if (time_after (jiffies, clock))
--			return retcode (DID_BUS_BUSY);
--		else if (st0x_aborted)
--			return retcode (st0x_aborted);
--#endif
--		DPRINTK (PHASE_SELECTION, "scsi%d : phase = SELECTION\n", hostno);
 -
--		clock = jiffies + ST0X_SELECTION_DELAY;
--
--		/*
--		 * Arbitration/selection procedure :
--		 * 1.  Disable drivers
--		 * 2.  Write HOST adapter address bit
--		 * 3.  Set start arbitration.
--		 * 4.  We get either ARBITRATION COMPLETE or SELECT at this
--		 *     point.
--		 * 5.  OR our ID and targets on bus.
--		 * 6.  Enable SCSI drivers and asserted SEL and ATTN
--		 */
+-		/* Check for latest journal index */
 -
--#ifdef ARBITRATE
--		/* FIXME: verify host lock is always held here */
--		WRITE_CONTROL(0);
--		WRITE_DATA((controller_type == SEAGATE) ? 0x80 : 0x40);
--		WRITE_CONTROL(CMD_START_ARB);
+-		t = sdp->sd_jindex_refresh_time +
+-		    gfs2_tune_get(sdp, gt_jindex_refresh_secs) * HZ;
 -
--		ULOOP (ST0X_SELECTION_DELAY * 10000) {
--			status_read = STATUS;
--			if (status_read & STAT_ARB_CMPL)
--				break;
--			if (st0x_aborted)	/* FIXME: What? We are going to do something even after abort? */
--				break;
--			if (TIMEOUT || (status_read & STAT_SEL)) {
--				printk(KERN_WARNING "scsi%d : arbitration lost or timeout.\n", hostno);
--				WRITE_CONTROL (BASE_CMD);
--				return retcode (DID_NO_CONNECT);
--			}
+-		if (time_after_eq(jiffies, t)) {
+-			if (!gfs2_jindex_hold(sdp, &ji_gh))
+-				gfs2_glock_dq_uninit(&ji_gh);
+-			sdp->sd_jindex_refresh_time = jiffies;
 -		}
--		DPRINTK (PHASE_SELECTION, "scsi%d : arbitration complete\n", hostno);
--#endif
 -
--		/*
--		 *    When the SCSI device decides that we're gawking at it, 
--		 *    it will respond by asserting BUSY on the bus.
--		 *
--		 *    Note : the Seagate ST-01/02 product manual says that we
--		 *    should twiddle the DATA register before the control
--		 *    register. However, this does not work reliably so we do
--		 *    it the other way around.
--		 *
--		 *    Probably could be a problem with arbitration too, we
--		 *    really should try this with a SCSI protocol or logic 
--		 *    analyzer to see what is going on.
--		 */
--		tmp_data = (unsigned char) ((1 << target) | (controller_type == SEAGATE ? 0x80 : 0x40));
--		tmp_control = BASE_CMD | CMD_DRVR_ENABLE | CMD_SEL | (reselect ? CMD_ATTN : 0);
+-		t = gfs2_tune_get(sdp, gt_logd_secs) * HZ;
+-		if (freezing(current))
+-			refrigerator();
+-		schedule_timeout_interruptible(t);
+-	}
 -
--		/* FIXME: verify host lock is always held here */
--#ifdef OLDCNTDATASCEME
--#ifdef SWAPCNTDATA
--		WRITE_CONTROL (tmp_control);
--		WRITE_DATA (tmp_data);
--#else
--		WRITE_DATA (tmp_data);
--		WRITE_CONTROL (tmp_control);
--#endif
--#else
--		tmp_control ^= CMD_BSY;	/* This is guesswork. What used to be in driver    */
--		WRITE_CONTROL (tmp_control);	/* could never work: it sent data into control     */
--		WRITE_DATA (tmp_data);	/* register and control info into data. Hopefully  */
--		tmp_control ^= CMD_BSY;	/* fixed, but order of first two may be wrong.     */
--		WRITE_CONTROL (tmp_control);	/* -- pavel at ucw.cz   */
--#endif
+-	return 0;
+-}
+-
+-/**
+  * gfs2_quotad - Write cached quota changes into the quota file
+  * @sdp: Pointer to GFS2 superblock
+  *
+diff --git a/fs/gfs2/daemon.h b/fs/gfs2/daemon.h
+index 0de9b35..4be084f 100644
+--- a/fs/gfs2/daemon.h
++++ b/fs/gfs2/daemon.h
+@@ -12,7 +12,6 @@
+ 
+ int gfs2_glockd(void *data);
+ int gfs2_recoverd(void *data);
+-int gfs2_logd(void *data);
+ int gfs2_quotad(void *data);
+ 
+ #endif /* __DAEMON_DOT_H__ */
+diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c
+index 9949bb7..57e2ed9 100644
+--- a/fs/gfs2/dir.c
++++ b/fs/gfs2/dir.c
+@@ -1876,7 +1876,7 @@ static int leaf_dealloc(struct gfs2_inode *dip, u32 index, u32 len,
+ 	if (error)
+ 		goto out;
+ 
+-	error = gfs2_rindex_hold(sdp, &dip->i_alloc.al_ri_gh);
++	error = gfs2_rindex_hold(sdp, &dip->i_alloc->al_ri_gh);
+ 	if (error)
+ 		goto out_qs;
+ 
+@@ -1949,7 +1949,7 @@ out_rg_gunlock:
+ 	gfs2_glock_dq_m(rlist.rl_rgrps, rlist.rl_ghs);
+ out_rlist:
+ 	gfs2_rlist_free(&rlist);
+-	gfs2_glock_dq_uninit(&dip->i_alloc.al_ri_gh);
++	gfs2_glock_dq_uninit(&dip->i_alloc->al_ri_gh);
+ out_qs:
+ 	gfs2_quota_unhold(dip);
+ out:
+diff --git a/fs/gfs2/eaops.c b/fs/gfs2/eaops.c
+index aa8dbf3..f114ba2 100644
+--- a/fs/gfs2/eaops.c
++++ b/fs/gfs2/eaops.c
+@@ -56,46 +56,6 @@ unsigned int gfs2_ea_name2type(const char *name, const char **truncated_name)
+ 	return type;
+ }
+ 
+-static int user_eo_get(struct gfs2_inode *ip, struct gfs2_ea_request *er)
+-{
+-	struct inode *inode = &ip->i_inode;
+-	int error = permission(inode, MAY_READ, NULL);
+-	if (error)
+-		return error;
 -
--		ULOOP (250 * 1000) {
--			if (st0x_aborted) {
--				/*
--				 *	If we have been aborted, and we have a
--				 *	command in progress, IE the target 
--				 *	still has BSY asserted, then we will
--				 *	reset the bus, and notify the midlevel
--				 *	driver to expect sense.
--				 */
+-	return gfs2_ea_get_i(ip, er);
+-}
 -
--				WRITE_CONTROL (BASE_CMD);
--				if (STATUS & STAT_BSY) {
--					printk(KERN_WARNING "scsi%d : BST asserted after we've been aborted.\n", hostno);
--					seagate_st0x_bus_reset(NULL);
--					return retcode (DID_RESET);
--				}
--				return retcode (st0x_aborted);
--			}
--			if (STATUS & STAT_BSY)
--				break;
--			if (TIMEOUT) {
--				DPRINTK (PHASE_SELECTION, "scsi%d : NO CONNECT with target %d, stat = %x \n", hostno, target, STATUS);
--				return retcode (DID_NO_CONNECT);
--			}
--		}
+-static int user_eo_set(struct gfs2_inode *ip, struct gfs2_ea_request *er)
+-{
+-	struct inode *inode = &ip->i_inode;
 -
--		/* Establish current pointers.  Take into account scatter / gather */
+-	if (S_ISREG(inode->i_mode) ||
+-	    (S_ISDIR(inode->i_mode) && !(inode->i_mode & S_ISVTX))) {
+-		int error = permission(inode, MAY_WRITE, NULL);
+-		if (error)
+-			return error;
+-	} else
+-		return -EPERM;
 -
--		if ((nobuffs = SCint->use_sg)) {
--#if (DEBUG & DEBUG_SG)
--			{
--				int i;
--				printk("scsi%d : scatter gather requested, using %d buffers.\n", hostno, nobuffs);
--				for (i = 0; i < nobuffs; ++i)
--					printk("scsi%d : buffer %d address = %p length = %d\n",
--					     hostno, i,
--					     sg_virt(&buffer[i]),
--					     buffer[i].length);
--			}
--#endif
+-	return gfs2_ea_set_i(ip, er);
+-}
 -
--			buffer = (struct scatterlist *) SCint->request_buffer;
--			len = buffer->length;
--			data = sg_virt(buffer);
--		} else {
--			DPRINTK (DEBUG_SG, "scsi%d : scatter gather not requested.\n", hostno);
--			buffer = NULL;
--			len = SCint->request_bufflen;
--			data = (unsigned char *) SCint->request_buffer;
--		}
+-static int user_eo_remove(struct gfs2_inode *ip, struct gfs2_ea_request *er)
+-{
+-	struct inode *inode = &ip->i_inode;
 -
--		DPRINTK (PHASE_DATAIN | PHASE_DATAOUT, "scsi%d : len = %d\n",
--			 hostno, len);
+-	if (S_ISREG(inode->i_mode) ||
+-	    (S_ISDIR(inode->i_mode) && !(inode->i_mode & S_ISVTX))) {
+-		int error = permission(inode, MAY_WRITE, NULL);
+-		if (error)
+-			return error;
+-	} else
+-		return -EPERM;
 -
--		break;
--#ifdef LINKED
--	case LINKED_RIGHT:
--		break;
--	case LINKED_WRONG:
--		break;
--#endif
--	}			/* end of switch(reselect) */
+-	return gfs2_ea_remove_i(ip, er);
+-}
 -
--	/*
--	 *    There are several conditions under which we wish to send a message :
--	 *      1.  When we are allowing disconnect / reconnect, and need to
--	 *	establish the I_T_L nexus via an IDENTIFY with the DiscPriv bit
--	 *	set.
--	 *
--	 *      2.  When we are doing linked commands, are have the wrong I_T_L
--	 *	nexus established and want to send an ABORT message.
--	 */
+ static int system_eo_get(struct gfs2_inode *ip, struct gfs2_ea_request *er)
+ {
+ 	if (!GFS2_ACL_IS_ACCESS(er->er_name, er->er_name_len) &&
+@@ -108,8 +68,6 @@ static int system_eo_get(struct gfs2_inode *ip, struct gfs2_ea_request *er)
+ 	     GFS2_ACL_IS_DEFAULT(er->er_name, er->er_name_len)))
+ 		return -EOPNOTSUPP;
+ 
 -
--	/* GCC does not like an ifdef inside a macro, so do it the hard way. */
--#ifdef LINKED
--	WRITE_CONTROL (BASE_CMD | CMD_DRVR_ENABLE | (((reselect == CAN_RECONNECT)|| (reselect == LINKED_WRONG))? CMD_ATTN : 0));
--#else
--	WRITE_CONTROL (BASE_CMD | CMD_DRVR_ENABLE | (((reselect == CAN_RECONNECT))? CMD_ATTN : 0));
--#endif
 -
--	/*
--	 *    INFORMATION TRANSFER PHASE
--	 *
--	 *      The nasty looking read / write inline assembler loops we use for
--	 *      DATAIN and DATAOUT phases are approximately 4-5 times as fast as
--	 *      the 'C' versions - since we're moving 1024 bytes of data, this
--	 *      really adds up.
--	 *
--	 *      SJT: The nasty-looking assembler is gone, so it's slower.
--	 *
--	 */
+ 	return gfs2_ea_get_i(ip, er);
+ }
+ 
+@@ -170,40 +128,10 @@ static int system_eo_remove(struct gfs2_inode *ip, struct gfs2_ea_request *er)
+ 	return gfs2_ea_remove_i(ip, er);
+ }
+ 
+-static int security_eo_get(struct gfs2_inode *ip, struct gfs2_ea_request *er)
+-{
+-	struct inode *inode = &ip->i_inode;
+-	int error = permission(inode, MAY_READ, NULL);
+-	if (error)
+-		return error;
 -
--	DPRINTK (PHASE_ETC, "scsi%d : phase = INFORMATION TRANSFER\n", hostno);
+-	return gfs2_ea_get_i(ip, er);
+-}
 -
--	incommand = 1;
--	transfersize = SCint->transfersize;
--	underflow = SCint->underflow;
+-static int security_eo_set(struct gfs2_inode *ip, struct gfs2_ea_request *er)
+-{
+-	struct inode *inode = &ip->i_inode;
+-	int error = permission(inode, MAY_WRITE, NULL);
+-	if (error)
+-		return error;
 -
--	/*
--	 *	Now, we poll the device for status information,
--	 *      and handle any requests it makes.  Note that since we are unsure
--	 *	of how much data will be flowing across the system, etc and
--	 *	cannot make reasonable timeouts, that we will instead have the
--	 *	midlevel driver handle any timeouts that occur in this phase.
--	 */
+-	return gfs2_ea_set_i(ip, er);
+-}
 -
--	while (((status_read = STATUS) & STAT_BSY) && !st0x_aborted && !done) {
--#ifdef PARITY
--		if (status_read & STAT_PARITY) {
--			printk(KERN_ERR "scsi%d : got parity error\n", hostno);
--			st0x_aborted = DID_PARITY;
--		}
--#endif
--		if (status_read & STAT_REQ) {
--#if ((DEBUG & PHASE_ETC) == PHASE_ETC)
--			if ((newphase = (status_read & REQ_MASK)) != phase) {
--				phase = newphase;
--				switch (phase) {
--				case REQ_DATAOUT:
--					printk ("scsi%d : phase = DATA OUT\n", hostno);
--					break;
--				case REQ_DATAIN:
--					printk ("scsi%d : phase = DATA IN\n", hostno);
--					break;
--				case REQ_CMDOUT:
--					printk
--					    ("scsi%d : phase = COMMAND OUT\n", hostno);
--					break;
--				case REQ_STATIN:
--					printk ("scsi%d : phase = STATUS IN\n",	hostno);
--					break;
--				case REQ_MSGOUT:
--					printk
--					    ("scsi%d : phase = MESSAGE OUT\n", hostno);
--					break;
--				case REQ_MSGIN:
--					printk ("scsi%d : phase = MESSAGE IN\n", hostno);
--					break;
--				default:
--					printk ("scsi%d : phase = UNKNOWN\n", hostno);
--					st0x_aborted = DID_ERROR;
--				}
--			}
--#endif
--			switch (status_read & REQ_MASK) {
--			case REQ_DATAOUT:
--				/*
--				 * If we are in fast mode, then we simply splat
--				 * the data out in word-sized chunks as fast as
--				 * we can.
--				 */
+-static int security_eo_remove(struct gfs2_inode *ip, struct gfs2_ea_request *er)
+-{
+-	struct inode *inode = &ip->i_inode;
+-	int error = permission(inode, MAY_WRITE, NULL);
+-	if (error)
+-		return error;
 -
--				if (!len) {
--#if 0
--					printk("scsi%d: underflow to target %d lun %d \n", hostno, target, lun);
--					st0x_aborted = DID_ERROR;
--					fast = 0;
--#endif
--					break;
--				}
+-	return gfs2_ea_remove_i(ip, er);
+-}
 -
--				if (fast && transfersize
--				    && !(len % transfersize)
--				    && (len >= transfersize)
--#ifdef FAST32
--				    && !(transfersize % 4)
--#endif
--				    ) {
--					DPRINTK (DEBUG_FAST,
--						 "scsi%d : FAST transfer, underflow = %d, transfersize = %d\n"
--						 "         len = %d, data = %08x\n",
--						 hostno, SCint->underflow,
--						 SCint->transfersize, len,
--						 data);
+ static const struct gfs2_eattr_operations gfs2_user_eaops = {
+-	.eo_get = user_eo_get,
+-	.eo_set = user_eo_set,
+-	.eo_remove = user_eo_remove,
++	.eo_get = gfs2_ea_get_i,
++	.eo_set = gfs2_ea_set_i,
++	.eo_remove = gfs2_ea_remove_i,
+ 	.eo_name = "user",
+ };
+ 
+@@ -215,9 +143,9 @@ const struct gfs2_eattr_operations gfs2_system_eaops = {
+ };
+ 
+ static const struct gfs2_eattr_operations gfs2_security_eaops = {
+-	.eo_get = security_eo_get,
+-	.eo_set = security_eo_set,
+-	.eo_remove = security_eo_remove,
++	.eo_get = gfs2_ea_get_i,
++	.eo_set = gfs2_ea_set_i,
++	.eo_remove = gfs2_ea_remove_i,
+ 	.eo_name = "security",
+ };
+ 
+diff --git a/fs/gfs2/eattr.c b/fs/gfs2/eattr.c
+index 2a7435b..bee9970 100644
+--- a/fs/gfs2/eattr.c
++++ b/fs/gfs2/eattr.c
+@@ -1418,7 +1418,7 @@ out:
+ static int ea_dealloc_block(struct gfs2_inode *ip)
+ {
+ 	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+-	struct gfs2_alloc *al = &ip->i_alloc;
++	struct gfs2_alloc *al = ip->i_alloc;
+ 	struct gfs2_rgrpd *rgd;
+ 	struct buffer_head *dibh;
+ 	int error;
+diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c
+index a37efe4..80e09c5 100644
+--- a/fs/gfs2/glock.c
++++ b/fs/gfs2/glock.c
+@@ -1,6 +1,6 @@
+ /*
+  * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
+- * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
++ * Copyright (C) 2004-2007 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
+@@ -217,7 +217,6 @@ int gfs2_glock_put(struct gfs2_glock *gl)
+ 	if (atomic_dec_and_test(&gl->gl_ref)) {
+ 		hlist_del(&gl->gl_list);
+ 		write_unlock(gl_lock_addr(gl->gl_hash));
+-		BUG_ON(spin_is_locked(&gl->gl_spin));
+ 		gfs2_assert(sdp, gl->gl_state == LM_ST_UNLOCKED);
+ 		gfs2_assert(sdp, list_empty(&gl->gl_reclaim));
+ 		gfs2_assert(sdp, list_empty(&gl->gl_holders));
+@@ -346,7 +345,6 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number,
+ 	gl->gl_object = NULL;
+ 	gl->gl_sbd = sdp;
+ 	gl->gl_aspace = NULL;
+-	lops_init_le(&gl->gl_le, &gfs2_glock_lops);
+ 	INIT_DELAYED_WORK(&gl->gl_work, glock_work_func);
+ 
+ 	/* If this glock protects actual on-disk data or metadata blocks,
+@@ -461,7 +459,6 @@ static void wait_on_holder(struct gfs2_holder *gh)
+ 
+ static void gfs2_demote_wake(struct gfs2_glock *gl)
+ {
+-	BUG_ON(!spin_is_locked(&gl->gl_spin));
+ 	gl->gl_demote_state = LM_ST_EXCLUSIVE;
+         clear_bit(GLF_DEMOTE, &gl->gl_flags);
+         smp_mb__after_clear_bit();
+@@ -507,21 +504,12 @@ static int rq_mutex(struct gfs2_holder *gh)
+ static int rq_promote(struct gfs2_holder *gh)
+ {
+ 	struct gfs2_glock *gl = gh->gh_gl;
+-	struct gfs2_sbd *sdp = gl->gl_sbd;
+ 
+ 	if (!relaxed_state_ok(gl->gl_state, gh->gh_state, gh->gh_flags)) {
+ 		if (list_empty(&gl->gl_holders)) {
+ 			gl->gl_req_gh = gh;
+ 			set_bit(GLF_LOCK, &gl->gl_flags);
+ 			spin_unlock(&gl->gl_spin);
 -
--			/* SJT: Start. Fast Write */
--#ifdef SEAGATE_USE_ASM
--					__asm__ ("cld\n\t"
--#ifdef FAST32
--						 "shr $2, %%ecx\n\t"
--						 "1:\t"
--						 "lodsl\n\t"
--						 "movl %%eax, (%%edi)\n\t"
--#else
--						 "1:\t"
--						 "lodsb\n\t"
--						 "movb %%al, (%%edi)\n\t"
--#endif
--						 "loop 1b;"
--				      /* output */ :
--				      /* input */ :"D" (st0x_dr),
--						 "S"
--						 (data),
--						 "c" (SCint->transfersize)
--/* clobbered */
--				      :	 "eax", "ecx",
--						 "esi");
--#else				/* SEAGATE_USE_ASM */
--					memcpy_toio(st0x_dr, data, transfersize);
--#endif				/* SEAGATE_USE_ASM */
--/* SJT: End */
--					len -= transfersize;
--					data += transfersize;
--					DPRINTK (DEBUG_FAST, "scsi%d : FAST transfer complete len = %d data = %08x\n", hostno, len, data);
--				} else {
--					/*
--					 *    We loop as long as we are in a 
--					 *    data out phase, there is data to
--					 *    send, and BSY is still active.
--					 */
+-			if (atomic_read(&sdp->sd_reclaim_count) >
+-			    gfs2_tune_get(sdp, gt_reclaim_limit) &&
+-			    !(gh->gh_flags & LM_FLAG_PRIORITY)) {
+-				gfs2_reclaim_glock(sdp);
+-				gfs2_reclaim_glock(sdp);
+-			}
 -
--/* SJT: Start. Slow Write. */
--#ifdef SEAGATE_USE_ASM
+ 			gfs2_glock_xmote_th(gh->gh_gl, gh);
+ 			spin_lock(&gl->gl_spin);
+ 		}
+@@ -567,7 +555,10 @@ static int rq_demote(struct gfs2_glock *gl)
+ 		gfs2_demote_wake(gl);
+ 		return 0;
+ 	}
++
+ 	set_bit(GLF_LOCK, &gl->gl_flags);
++	set_bit(GLF_DEMOTE_IN_PROGRESS, &gl->gl_flags);
++
+ 	if (gl->gl_demote_state == LM_ST_UNLOCKED ||
+ 	    gl->gl_state != LM_ST_EXCLUSIVE) {
+ 		spin_unlock(&gl->gl_spin);
+@@ -576,7 +567,9 @@ static int rq_demote(struct gfs2_glock *gl)
+ 		spin_unlock(&gl->gl_spin);
+ 		gfs2_glock_xmote_th(gl, NULL);
+ 	}
++
+ 	spin_lock(&gl->gl_spin);
++	clear_bit(GLF_DEMOTE_IN_PROGRESS, &gl->gl_flags);
+ 
+ 	return 0;
+ }
+@@ -598,23 +591,18 @@ static void run_queue(struct gfs2_glock *gl)
+ 		if (!list_empty(&gl->gl_waiters1)) {
+ 			gh = list_entry(gl->gl_waiters1.next,
+ 					struct gfs2_holder, gh_list);
 -
--					int __dummy_1, __dummy_2;
+-			if (test_bit(HIF_MUTEX, &gh->gh_iflags))
+-				blocked = rq_mutex(gh);
+-			else
+-				gfs2_assert_warn(gl->gl_sbd, 0);
 -
--/*
-- *      We loop as long as we are in a data out phase, there is data to send, 
-- *      and BSY is still active.
-- */
--/* Local variables : len = ecx , data = esi, 
--                     st0x_cr_sr = ebx, st0x_dr =  edi
--*/
--					__asm__ (
--							/* Test for any data here at all. */
--							"orl %%ecx, %%ecx\n\t"
--							"jz 2f\n\t" "cld\n\t"
--/*                    "movl st0x_cr_sr, %%ebx\n\t"  */
--/*                    "movl st0x_dr, %%edi\n\t"  */
--							"1:\t"
--							"movb (%%ebx), %%al\n\t"
--							/* Test for BSY */
--							"test $1, %%al\n\t"
--							"jz 2f\n\t"
--							/* Test for data out phase - STATUS & REQ_MASK should be 
--							   REQ_DATAOUT, which is 0. */
--							"test $0xe, %%al\n\t"
--							"jnz 2f\n\t"
--							/* Test for REQ */
--							"test $0x10, %%al\n\t"
--							"jz 1b\n\t"
--							"lodsb\n\t"
--							"movb %%al, (%%edi)\n\t"
--							"loop 1b\n\t" "2:\n"
--				      /* output */ :"=S" (data), "=c" (len),
--							"=b"
--							(__dummy_1),
--							"=D" (__dummy_2)
--/* input */
--				      :		"0" (data), "1" (len),
--							"2" (st0x_cr_sr),
--							"3" (st0x_dr)
--/* clobbered */
--				      :		"eax");
--#else				/* SEAGATE_USE_ASM */
--					while (len) {
--						unsigned char stat;
++			blocked = rq_mutex(gh);
+ 		} else if (test_bit(GLF_DEMOTE, &gl->gl_flags)) {
+ 			blocked = rq_demote(gl);
++			if (gl->gl_waiters2 && !blocked) {
++				set_bit(GLF_DEMOTE, &gl->gl_flags);
++				gl->gl_demote_state = LM_ST_UNLOCKED;
++			}
++			gl->gl_waiters2 = 0;
+ 		} else if (!list_empty(&gl->gl_waiters3)) {
+ 			gh = list_entry(gl->gl_waiters3.next,
+ 					struct gfs2_holder, gh_list);
 -
--						stat = STATUS;
--						if (!(stat & STAT_BSY)
--						    || ((stat & REQ_MASK) !=
--							REQ_DATAOUT))
--							break;
--						if (stat & STAT_REQ) {
--							WRITE_DATA (*data++);
--							--len;
--						}
--					}
--#endif				/* SEAGATE_USE_ASM */
--/* SJT: End. */
--				}
+-			if (test_bit(HIF_PROMOTE, &gh->gh_iflags))
+-				blocked = rq_promote(gh);
+-			else
+-				gfs2_assert_warn(gl->gl_sbd, 0);
 -
--				if (!len && nobuffs) {
--					--nobuffs;
--					++buffer;
--					len = buffer->length;
--					data = sg_virt(buffer);
--					DPRINTK (DEBUG_SG,
--						 "scsi%d : next scatter-gather buffer len = %d address = %08x\n",
--						 hostno, len, data);
--				}
--				break;
++			blocked = rq_promote(gh);
+ 		} else
+ 			break;
+ 
+@@ -632,27 +620,21 @@ static void run_queue(struct gfs2_glock *gl)
+ 
+ static void gfs2_glmutex_lock(struct gfs2_glock *gl)
+ {
+-	struct gfs2_holder gh;
 -
--			case REQ_DATAIN:
--#ifdef SLOW_RATE
--				if (borken) {
--#if (DEBUG & (PHASE_DATAIN))
--					transfered += len;
--#endif
--					for (; len && (STATUS & (REQ_MASK | STAT_REQ)) == (REQ_DATAIN | STAT_REQ); --len) {
--						*data++ = DATA;
--						borken_wait();
--					}
--#if (DEBUG & (PHASE_DATAIN))
--					transfered -= len;
--#endif
--				} else
--#endif
+-	gfs2_holder_init(gl, 0, 0, &gh);
+-	set_bit(HIF_MUTEX, &gh.gh_iflags);
+-	if (test_and_set_bit(HIF_WAIT, &gh.gh_iflags))
+-		BUG();
 -
--					if (fast && transfersize
--					    && !(len % transfersize)
--					    && (len >= transfersize)
--#ifdef FAST32
--					    && !(transfersize % 4)
--#endif
--				    ) {
--					DPRINTK (DEBUG_FAST,
--						 "scsi%d : FAST transfer, underflow = %d, transfersize = %d\n"
--						 "         len = %d, data = %08x\n",
--						 hostno, SCint->underflow,
--						 SCint->transfersize, len,
--						 data);
+ 	spin_lock(&gl->gl_spin);
+ 	if (test_and_set_bit(GLF_LOCK, &gl->gl_flags)) {
++		struct gfs2_holder gh;
++
++		gfs2_holder_init(gl, 0, 0, &gh);
++		set_bit(HIF_WAIT, &gh.gh_iflags);
+ 		list_add_tail(&gh.gh_list, &gl->gl_waiters1);
++		spin_unlock(&gl->gl_spin);
++		wait_on_holder(&gh);
++		gfs2_holder_uninit(&gh);
+ 	} else {
+ 		gl->gl_owner_pid = current->pid;
+ 		gl->gl_ip = (unsigned long)__builtin_return_address(0);
+-		clear_bit(HIF_WAIT, &gh.gh_iflags);
+-		smp_mb();
+-		wake_up_bit(&gh.gh_iflags, HIF_WAIT);
++		spin_unlock(&gl->gl_spin);
+ 	}
+-	spin_unlock(&gl->gl_spin);
 -
--/* SJT: Start. Fast Read */
--#ifdef SEAGATE_USE_ASM
--					__asm__ ("cld\n\t"
--#ifdef FAST32
--						 "shr $2, %%ecx\n\t"
--						 "1:\t"
--						 "movl (%%esi), %%eax\n\t"
--						 "stosl\n\t"
--#else
--						 "1:\t"
--						 "movb (%%esi), %%al\n\t"
--						 "stosb\n\t"
--#endif
--						 "loop 1b\n\t"
--				      /* output */ :
--				      /* input */ :"S" (st0x_dr),
--						 "D"
--						 (data),
--						 "c" (SCint->transfersize)
--/* clobbered */
--				      :	 "eax", "ecx",
--						 "edi");
--#else				/* SEAGATE_USE_ASM */
--					memcpy_fromio(data, st0x_dr, len);
--#endif				/* SEAGATE_USE_ASM */
--/* SJT: End */
--					len -= transfersize;
--					data += transfersize;
--#if (DEBUG & PHASE_DATAIN)
--					printk ("scsi%d: transfered += %d\n", hostno, transfersize);
--					transfered += transfersize;
--#endif
+-	wait_on_holder(&gh);
+-	gfs2_holder_uninit(&gh);
+ }
+ 
+ /**
+@@ -691,7 +673,6 @@ static void gfs2_glmutex_unlock(struct gfs2_glock *gl)
+ 	gl->gl_owner_pid = 0;
+ 	gl->gl_ip = 0;
+ 	run_queue(gl);
+-	BUG_ON(!spin_is_locked(&gl->gl_spin));
+ 	spin_unlock(&gl->gl_spin);
+ }
+ 
+@@ -722,7 +703,10 @@ static void handle_callback(struct gfs2_glock *gl, unsigned int state,
+ 		}
+ 	} else if (gl->gl_demote_state != LM_ST_UNLOCKED &&
+ 			gl->gl_demote_state != state) {
+-		gl->gl_demote_state = LM_ST_UNLOCKED;
++		if (test_bit(GLF_DEMOTE_IN_PROGRESS,  &gl->gl_flags)) 
++			gl->gl_waiters2 = 1;
++		else 
++			gl->gl_demote_state = LM_ST_UNLOCKED;
+ 	}
+ 	spin_unlock(&gl->gl_spin);
+ }
+@@ -943,8 +927,8 @@ static void gfs2_glock_drop_th(struct gfs2_glock *gl)
+ 	const struct gfs2_glock_operations *glops = gl->gl_ops;
+ 	unsigned int ret;
+ 
+-	if (glops->go_drop_th)
+-		glops->go_drop_th(gl);
++	if (glops->go_xmote_th)
++		glops->go_xmote_th(gl);
+ 
+ 	gfs2_assert_warn(sdp, test_bit(GLF_LOCK, &gl->gl_flags));
+ 	gfs2_assert_warn(sdp, list_empty(&gl->gl_holders));
+@@ -1156,8 +1140,6 @@ restart:
+ 		return -EIO;
+ 	}
+ 
+-	set_bit(HIF_PROMOTE, &gh->gh_iflags);
 -
--					DPRINTK (DEBUG_FAST, "scsi%d : FAST transfer complete len = %d data = %08x\n", hostno, len, data);
--				} else {
+ 	spin_lock(&gl->gl_spin);
+ 	add_to_queue(gh);
+ 	run_queue(gl);
+@@ -1248,12 +1230,11 @@ void gfs2_glock_dq(struct gfs2_holder *gh)
+ 	list_del_init(&gh->gh_list);
+ 
+ 	if (list_empty(&gl->gl_holders)) {
+-		spin_unlock(&gl->gl_spin);
 -
--#if (DEBUG & PHASE_DATAIN)
--					printk ("scsi%d: transfered += %d\n", hostno, len);
--					transfered += len;	/* Assume we'll transfer it all, then
--								   subtract what we *didn't* transfer */
--#endif
+-		if (glops->go_unlock)
++		if (glops->go_unlock) {
++			spin_unlock(&gl->gl_spin);
+ 			glops->go_unlock(gh);
 -
--/*
-- *	We loop as long as we are in a data in phase, there is room to read,
-- *      and BSY is still active
+-		spin_lock(&gl->gl_spin);
++			spin_lock(&gl->gl_spin);
++		}
+ 		gl->gl_stamp = jiffies;
+ 	}
+ 
+@@ -1910,8 +1891,6 @@ static int dump_glock(struct glock_iter *gi, struct gfs2_glock *gl)
+ 	print_dbg(gi, "  req_bh = %s\n", (gl->gl_req_bh) ? "yes" : "no");
+ 	print_dbg(gi, "  lvb_count = %d\n", atomic_read(&gl->gl_lvb_count));
+ 	print_dbg(gi, "  object = %s\n", (gl->gl_object) ? "yes" : "no");
+-	print_dbg(gi, "  le = %s\n",
+-		   (list_empty(&gl->gl_le.le_list)) ? "no" : "yes");
+ 	print_dbg(gi, "  reclaim = %s\n",
+ 		   (list_empty(&gl->gl_reclaim)) ? "no" : "yes");
+ 	if (gl->gl_aspace)
+diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c
+index 4670dcb..c663b7a 100644
+--- a/fs/gfs2/glops.c
++++ b/fs/gfs2/glops.c
+@@ -56,7 +56,7 @@ static void gfs2_ail_empty_gl(struct gfs2_glock *gl)
+ 		bd = list_entry(head->next, struct gfs2_bufdata,
+ 				bd_ail_gl_list);
+ 		bh = bd->bd_bh;
+-		gfs2_remove_from_ail(NULL, bd);
++		gfs2_remove_from_ail(bd);
+ 		bd->bd_bh = NULL;
+ 		bh->b_private = NULL;
+ 		bd->bd_blkno = bh->b_blocknr;
+@@ -86,15 +86,10 @@ static void gfs2_pte_inval(struct gfs2_glock *gl)
+ 	if (!ip || !S_ISREG(inode->i_mode))
+ 		return;
+ 
+-	if (!test_bit(GIF_PAGED, &ip->i_flags))
+-		return;
+-
+ 	unmap_shared_mapping_range(inode->i_mapping, 0, 0);
+-
+ 	if (test_bit(GIF_SW_PAGED, &ip->i_flags))
+ 		set_bit(GLF_DIRTY, &gl->gl_flags);
+ 
+-	clear_bit(GIF_SW_PAGED, &ip->i_flags);
+ }
+ 
+ /**
+@@ -143,44 +138,34 @@ static void meta_go_inval(struct gfs2_glock *gl, int flags)
+ static void inode_go_sync(struct gfs2_glock *gl)
+ {
+ 	struct gfs2_inode *ip = gl->gl_object;
++	struct address_space *metamapping = gl->gl_aspace->i_mapping;
++	int error;
++
++	if (gl->gl_state != LM_ST_UNLOCKED)
++		gfs2_pte_inval(gl);
++	if (gl->gl_state != LM_ST_EXCLUSIVE)
++		return;
+ 
+ 	if (ip && !S_ISREG(ip->i_inode.i_mode))
+ 		ip = NULL;
+ 
+ 	if (test_bit(GLF_DIRTY, &gl->gl_flags)) {
+-		if (ip && !gfs2_is_jdata(ip))
+-			filemap_fdatawrite(ip->i_inode.i_mapping);
+ 		gfs2_log_flush(gl->gl_sbd, gl);
+-		if (ip && gfs2_is_jdata(ip))
+-			filemap_fdatawrite(ip->i_inode.i_mapping);
+-		gfs2_meta_sync(gl);
++		filemap_fdatawrite(metamapping);
+ 		if (ip) {
+ 			struct address_space *mapping = ip->i_inode.i_mapping;
+-			int error = filemap_fdatawait(mapping);
++			filemap_fdatawrite(mapping);
++			error = filemap_fdatawait(mapping);
+ 			mapping_set_error(mapping, error);
+ 		}
++		error = filemap_fdatawait(metamapping);
++		mapping_set_error(metamapping, error);
+ 		clear_bit(GLF_DIRTY, &gl->gl_flags);
+ 		gfs2_ail_empty_gl(gl);
+ 	}
+ }
+ 
+ /**
+- * inode_go_xmote_th - promote/demote a glock
+- * @gl: the glock
+- * @state: the requested state
+- * @flags:
+- *
 - */
 -
--/* SJT: Start. */
--#ifdef SEAGATE_USE_ASM
+-static void inode_go_xmote_th(struct gfs2_glock *gl)
+-{
+-	if (gl->gl_state != LM_ST_UNLOCKED)
+-		gfs2_pte_inval(gl);
+-	if (gl->gl_state == LM_ST_EXCLUSIVE)
+-		inode_go_sync(gl);
+-}
 -
--					int __dummy_3, __dummy_4;
+-/**
+  * inode_go_xmote_bh - After promoting/demoting a glock
+  * @gl: the glock
+  *
+@@ -201,22 +186,6 @@ static void inode_go_xmote_bh(struct gfs2_glock *gl)
+ }
+ 
+ /**
+- * inode_go_drop_th - unlock a glock
+- * @gl: the glock
+- *
+- * Invoked from rq_demote().
+- * Another node needs the lock in EXCLUSIVE mode, or lock (unused for too long)
+- * is being purged from our node's glock cache; we're dropping lock.
+- */
 -
--/* Dummy clobbering variables for the new gcc-2.95 */
+-static void inode_go_drop_th(struct gfs2_glock *gl)
+-{
+-	gfs2_pte_inval(gl);
+-	if (gl->gl_state == LM_ST_EXCLUSIVE)
+-		inode_go_sync(gl);
+-}
 -
--/*
-- *      We loop as long as we are in a data in phase, there is room to read, 
-- *      and BSY is still active
+-/**
+  * inode_go_inval - prepare a inode glock to be released
+  * @gl: the glock
+  * @flags:
+@@ -234,10 +203,8 @@ static void inode_go_inval(struct gfs2_glock *gl, int flags)
+ 			set_bit(GIF_INVALID, &ip->i_flags);
+ 	}
+ 
+-	if (ip && S_ISREG(ip->i_inode.i_mode)) {
++	if (ip && S_ISREG(ip->i_inode.i_mode))
+ 		truncate_inode_pages(ip->i_inode.i_mapping, 0);
+-		clear_bit(GIF_PAGED, &ip->i_flags);
+-	}
+ }
+ 
+ /**
+@@ -294,23 +261,6 @@ static int inode_go_lock(struct gfs2_holder *gh)
+ }
+ 
+ /**
+- * inode_go_unlock - operation done before an inode lock is unlocked by a
+- *		     process
+- * @gl: the glock
+- * @flags:
+- *
 - */
--					/* Local variables : ecx = len, edi = data
--					   esi = st0x_cr_sr, ebx = st0x_dr */
--					__asm__ (
--							/* Test for room to read */
--							"orl %%ecx, %%ecx\n\t"
--							"jz 2f\n\t" "cld\n\t"
--/*                "movl st0x_cr_sr, %%esi\n\t"  */
--/*                "movl st0x_dr, %%ebx\n\t"  */
--							"1:\t"
--							"movb (%%esi), %%al\n\t"
--							/* Test for BSY */
--							"test $1, %%al\n\t"
--							"jz 2f\n\t"
--							/* Test for data in phase - STATUS & REQ_MASK should be REQ_DATAIN, 
--							   = STAT_IO, which is 4. */
--							"movb $0xe, %%ah\n\t"
--							"andb %%al, %%ah\n\t"
--							"cmpb $0x04, %%ah\n\t"
--							"jne 2f\n\t"
--							/* Test for REQ */
--							"test $0x10, %%al\n\t"
--							"jz 1b\n\t"
--							"movb (%%ebx), %%al\n\t"
--							"stosb\n\t"
--							"loop 1b\n\t" "2:\n"
--				      /* output */ :"=D" (data), "=c" (len),
--							"=S"
--							(__dummy_3),
--							"=b" (__dummy_4)
--/* input */
--				      :		"0" (data), "1" (len),
--							"2" (st0x_cr_sr),
--							"3" (st0x_dr)
--/* clobbered */
--				      :		"eax");
--#else				/* SEAGATE_USE_ASM */
--					while (len) {
--						unsigned char stat;
 -
--						stat = STATUS;
--						if (!(stat & STAT_BSY)
--						    || ((stat & REQ_MASK) !=
--							REQ_DATAIN))
--							break;
--						if (stat & STAT_REQ) {
--							*data++ = DATA;
--							--len;
--						}
--					}
--#endif				/* SEAGATE_USE_ASM */
--/* SJT: End. */
--#if (DEBUG & PHASE_DATAIN)
--					printk ("scsi%d: transfered -= %d\n", hostno, len);
--					transfered -= len;	/* Since we assumed all of Len got  *
--								   transfered, correct our mistake */
--#endif
--				}
+-static void inode_go_unlock(struct gfs2_holder *gh)
+-{
+-	struct gfs2_glock *gl = gh->gh_gl;
+-	struct gfs2_inode *ip = gl->gl_object;
 -
--				if (!len && nobuffs) {
--					--nobuffs;
--					++buffer;
--					len = buffer->length;
--					data = sg_virt(buffer);
--					DPRINTK (DEBUG_SG, "scsi%d : next scatter-gather buffer len = %d address = %08x\n", hostno, len, data);
--				}
--				break;
+-	if (ip)
+-		gfs2_meta_cache_flush(ip);
+-}
 -
--			case REQ_CMDOUT:
--				while (((status_read = STATUS) & STAT_BSY) &&
--				       ((status_read & REQ_MASK) == REQ_CMDOUT))
--					if (status_read & STAT_REQ) {
--						WRITE_DATA (*(const unsigned char *) cmnd);
--						cmnd = 1 + (const unsigned char *)cmnd;
--#ifdef SLOW_RATE
--						if (borken)
--							borken_wait ();
--#endif
--					}
--				break;
+-/**
+  * rgrp_go_demote_ok - Check to see if it's ok to unlock a RG's glock
+  * @gl: the glock
+  *
+@@ -350,14 +300,14 @@ static void rgrp_go_unlock(struct gfs2_holder *gh)
+ }
+ 
+ /**
+- * trans_go_xmote_th - promote/demote the transaction glock
++ * trans_go_sync - promote/demote the transaction glock
+  * @gl: the glock
+  * @state: the requested state
+  * @flags:
+  *
+  */
+ 
+-static void trans_go_xmote_th(struct gfs2_glock *gl)
++static void trans_go_sync(struct gfs2_glock *gl)
+ {
+ 	struct gfs2_sbd *sdp = gl->gl_sbd;
+ 
+@@ -384,7 +334,6 @@ static void trans_go_xmote_bh(struct gfs2_glock *gl)
+ 
+ 	if (gl->gl_state != LM_ST_UNLOCKED &&
+ 	    test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags)) {
+-		gfs2_meta_cache_flush(GFS2_I(sdp->sd_jdesc->jd_inode));
+ 		j_gl->gl_ops->go_inval(j_gl, DIO_METADATA);
+ 
+ 		error = gfs2_find_jhead(sdp->sd_jdesc, &head);
+@@ -402,24 +351,6 @@ static void trans_go_xmote_bh(struct gfs2_glock *gl)
+ }
+ 
+ /**
+- * trans_go_drop_th - unlock the transaction glock
+- * @gl: the glock
+- *
+- * We want to sync the device even with localcaching.  Remember
+- * that localcaching journal replay only marks buffers dirty.
+- */
 -
--			case REQ_STATIN:
--				status = DATA;
--				break;
+-static void trans_go_drop_th(struct gfs2_glock *gl)
+-{
+-	struct gfs2_sbd *sdp = gl->gl_sbd;
 -
--			case REQ_MSGOUT:
--				/*
--				 *	We can only have sent a MSG OUT if we
--				 *	requested to do this by raising ATTN.
--				 *	So, we must drop ATTN.
--				 */
--				WRITE_CONTROL (BASE_CMD | CMD_DRVR_ENABLE);
--				/*
--				 *	If we are reconnecting, then we must 
--				 *	send an IDENTIFY message in response
--				 *	to MSGOUT.
--				 */
--				switch (reselect) {
--				case CAN_RECONNECT:
--					WRITE_DATA (IDENTIFY (1, lun));
--					DPRINTK (PHASE_RESELECT | PHASE_MSGOUT, "scsi%d : sent IDENTIFY message.\n", hostno);
--					break;
--#ifdef LINKED
--				case LINKED_WRONG:
--					WRITE_DATA (ABORT);
--					linked_connected = 0;
--					reselect = CAN_RECONNECT;
--					goto connect_loop;
--					DPRINTK (PHASE_MSGOUT | DEBUG_LINKED, "scsi%d : sent ABORT message to cancel incorrect I_T_L nexus.\n", hostno);
--#endif					/* LINKED */
--					DPRINTK (DEBUG_LINKED, "correct\n");
--				default:
--					WRITE_DATA (NOP);
--					printk("scsi%d : target %d requested MSGOUT, sent NOP message.\n", hostno, target);
--				}
--				break;
+-	if (test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags)) {
+-		gfs2_meta_syncfs(sdp);
+-		gfs2_log_shutdown(sdp);
+-	}
+-}
+-
+-/**
+  * quota_go_demote_ok - Check to see if it's ok to unlock a quota glock
+  * @gl: the glock
+  *
+@@ -433,25 +364,21 @@ static int quota_go_demote_ok(struct gfs2_glock *gl)
+ 
+ const struct gfs2_glock_operations gfs2_meta_glops = {
+ 	.go_xmote_th = meta_go_sync,
+-	.go_drop_th = meta_go_sync,
+ 	.go_type = LM_TYPE_META,
+ };
+ 
+ const struct gfs2_glock_operations gfs2_inode_glops = {
+-	.go_xmote_th = inode_go_xmote_th,
++	.go_xmote_th = inode_go_sync,
+ 	.go_xmote_bh = inode_go_xmote_bh,
+-	.go_drop_th = inode_go_drop_th,
+ 	.go_inval = inode_go_inval,
+ 	.go_demote_ok = inode_go_demote_ok,
+ 	.go_lock = inode_go_lock,
+-	.go_unlock = inode_go_unlock,
+ 	.go_type = LM_TYPE_INODE,
+ 	.go_min_hold_time = HZ / 10,
+ };
+ 
+ const struct gfs2_glock_operations gfs2_rgrp_glops = {
+ 	.go_xmote_th = meta_go_sync,
+-	.go_drop_th = meta_go_sync,
+ 	.go_inval = meta_go_inval,
+ 	.go_demote_ok = rgrp_go_demote_ok,
+ 	.go_lock = rgrp_go_lock,
+@@ -461,9 +388,8 @@ const struct gfs2_glock_operations gfs2_rgrp_glops = {
+ };
+ 
+ const struct gfs2_glock_operations gfs2_trans_glops = {
+-	.go_xmote_th = trans_go_xmote_th,
++	.go_xmote_th = trans_go_sync,
+ 	.go_xmote_bh = trans_go_xmote_bh,
+-	.go_drop_th = trans_go_drop_th,
+ 	.go_type = LM_TYPE_NONDISK,
+ };
+ 
+diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h
+index eaddfb5..513aaf0 100644
+--- a/fs/gfs2/incore.h
++++ b/fs/gfs2/incore.h
+@@ -1,6 +1,6 @@
+ /*
+  * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
+- * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
++ * Copyright (C) 2004-2007 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
+@@ -131,7 +131,6 @@ struct gfs2_bufdata {
+ struct gfs2_glock_operations {
+ 	void (*go_xmote_th) (struct gfs2_glock *gl);
+ 	void (*go_xmote_bh) (struct gfs2_glock *gl);
+-	void (*go_drop_th) (struct gfs2_glock *gl);
+ 	void (*go_inval) (struct gfs2_glock *gl, int flags);
+ 	int (*go_demote_ok) (struct gfs2_glock *gl);
+ 	int (*go_lock) (struct gfs2_holder *gh);
+@@ -141,10 +140,6 @@ struct gfs2_glock_operations {
+ };
+ 
+ enum {
+-	/* Actions */
+-	HIF_MUTEX		= 0,
+-	HIF_PROMOTE		= 1,
+-
+ 	/* States */
+ 	HIF_HOLDER		= 6,
+ 	HIF_FIRST		= 7,
+@@ -171,6 +166,8 @@ enum {
+ 	GLF_DEMOTE		= 3,
+ 	GLF_PENDING_DEMOTE	= 4,
+ 	GLF_DIRTY		= 5,
++	GLF_DEMOTE_IN_PROGRESS	= 6,
++	GLF_LFLUSH		= 7,
+ };
+ 
+ struct gfs2_glock {
+@@ -190,6 +187,7 @@ struct gfs2_glock {
+ 	struct list_head gl_holders;
+ 	struct list_head gl_waiters1;	/* HIF_MUTEX */
+ 	struct list_head gl_waiters3;	/* HIF_PROMOTE */
++	int gl_waiters2;		/* GIF_DEMOTE */
+ 
+ 	const struct gfs2_glock_operations *gl_ops;
+ 
+@@ -210,7 +208,6 @@ struct gfs2_glock {
+ 	struct gfs2_sbd *gl_sbd;
+ 
+ 	struct inode *gl_aspace;
+-	struct gfs2_log_element gl_le;
+ 	struct list_head gl_ail_list;
+ 	atomic_t gl_ail_count;
+ 	struct delayed_work gl_work;
+@@ -239,7 +236,6 @@ struct gfs2_alloc {
+ enum {
+ 	GIF_INVALID		= 0,
+ 	GIF_QD_LOCKED		= 1,
+-	GIF_PAGED		= 2,
+ 	GIF_SW_PAGED		= 3,
+ };
+ 
+@@ -268,14 +264,10 @@ struct gfs2_inode {
+ 	struct gfs2_glock *i_gl; /* Move into i_gh? */
+ 	struct gfs2_holder i_iopen_gh;
+ 	struct gfs2_holder i_gh; /* for prepare/commit_write only */
+-	struct gfs2_alloc i_alloc;
++	struct gfs2_alloc *i_alloc;
+ 	u64 i_last_rg_alloc;
+ 
+-	spinlock_t i_spin;
+ 	struct rw_semaphore i_rw_mutex;
+-	unsigned long i_last_pfault;
 -
--			case REQ_MSGIN:
--				switch (message = DATA) {
--				case DISCONNECT:
--					DANY("seagate: deciding to disconnect\n");
--					should_reconnect = 1;
--					current_data = data;	/* WDE add */
--					current_buffer = buffer;
--					current_bufflen = len;	/* WDE add */
--					current_nobuffs = nobuffs;
--#ifdef LINKED
--					linked_connected = 0;
--#endif
--					done = 1;
--					DPRINTK ((PHASE_RESELECT | PHASE_MSGIN), "scsi%d : disconnected.\n", hostno);
--					break;
+-	struct buffer_head *i_cache[GFS2_MAX_META_HEIGHT];
+ };
+ 
+ /*
+@@ -287,19 +279,12 @@ static inline struct gfs2_inode *GFS2_I(struct inode *inode)
+ 	return container_of(inode, struct gfs2_inode, i_inode);
+ }
+ 
+-/* To be removed? */
+-static inline struct gfs2_sbd *GFS2_SB(struct inode *inode)
++static inline struct gfs2_sbd *GFS2_SB(const struct inode *inode)
+ {
+ 	return inode->i_sb->s_fs_info;
+ }
+ 
+-enum {
+-	GFF_DID_DIRECT_ALLOC	= 0,
+-	GFF_EXLOCK = 1,
+-};
 -
--#ifdef LINKED
--				case LINKED_CMD_COMPLETE:
--				case LINKED_FLG_CMD_COMPLETE:
--#endif
--				case COMMAND_COMPLETE:
--					/*
--					 * Note : we should check for underflow here.
--					 */
--					DPRINTK(PHASE_MSGIN, "scsi%d : command complete.\n", hostno);
--					done = 1;
--					break;
--				case ABORT:
--					DPRINTK(PHASE_MSGIN, "scsi%d : abort message.\n", hostno);
--					done = 1;
--					break;
--				case SAVE_POINTERS:
--					current_buffer = buffer;
--					current_bufflen = len;	/* WDE add */
--					current_data = data;	/* WDE mod */
--					current_nobuffs = nobuffs;
--					DPRINTK (PHASE_MSGIN, "scsi%d : pointers saved.\n", hostno);
--					break;
--				case RESTORE_POINTERS:
--					buffer = current_buffer;
--					cmnd = current_cmnd;
--					data = current_data;	/* WDE mod */
--					len = current_bufflen;
--					nobuffs = current_nobuffs;
--					DPRINTK(PHASE_MSGIN, "scsi%d : pointers restored.\n", hostno);
--					break;
--				default:
+ struct gfs2_file {
+-	unsigned long f_flags;		/* GFF_... */
+ 	struct mutex f_fl_mutex;
+ 	struct gfs2_holder f_fl_gh;
+ };
+@@ -373,8 +358,17 @@ struct gfs2_ail {
+ 	u64 ai_sync_gen;
+ };
+ 
++struct gfs2_journal_extent {
++	struct list_head extent_list;
++
++	unsigned int lblock; /* First logical block */
++	u64 dblock; /* First disk block */
++	u64 blocks;
++};
++
+ struct gfs2_jdesc {
+ 	struct list_head jd_list;
++	struct list_head extent_list;
+ 
+ 	struct inode *jd_inode;
+ 	unsigned int jd_jid;
+@@ -421,13 +415,9 @@ struct gfs2_args {
+ struct gfs2_tune {
+ 	spinlock_t gt_spin;
+ 
+-	unsigned int gt_ilimit;
+-	unsigned int gt_ilimit_tries;
+-	unsigned int gt_ilimit_min;
+ 	unsigned int gt_demote_secs; /* Cache retention for unheld glock */
+ 	unsigned int gt_incore_log_blocks;
+ 	unsigned int gt_log_flush_secs;
+-	unsigned int gt_jindex_refresh_secs; /* Check for new journal index */
+ 
+ 	unsigned int gt_recoverd_secs;
+ 	unsigned int gt_logd_secs;
+@@ -443,10 +433,8 @@ struct gfs2_tune {
+ 	unsigned int gt_new_files_jdata;
+ 	unsigned int gt_new_files_directio;
+ 	unsigned int gt_max_readahead; /* Max bytes to read-ahead from disk */
+-	unsigned int gt_lockdump_size;
+ 	unsigned int gt_stall_secs; /* Detects trouble! */
+ 	unsigned int gt_complain_secs;
+-	unsigned int gt_reclaim_limit; /* Max num of glocks in reclaim list */
+ 	unsigned int gt_statfs_quantum;
+ 	unsigned int gt_statfs_slow;
+ };
+@@ -539,7 +527,6 @@ struct gfs2_sbd {
+ 	/* StatFS stuff */
+ 
+ 	spinlock_t sd_statfs_spin;
+-	struct mutex sd_statfs_mutex;
+ 	struct gfs2_statfs_change_host sd_statfs_master;
+ 	struct gfs2_statfs_change_host sd_statfs_local;
+ 	unsigned long sd_statfs_sync_time;
+@@ -602,20 +589,18 @@ struct gfs2_sbd {
+ 	unsigned int sd_log_commited_databuf;
+ 	unsigned int sd_log_commited_revoke;
+ 
+-	unsigned int sd_log_num_gl;
+ 	unsigned int sd_log_num_buf;
+ 	unsigned int sd_log_num_revoke;
+ 	unsigned int sd_log_num_rg;
+ 	unsigned int sd_log_num_databuf;
+ 
+-	struct list_head sd_log_le_gl;
+ 	struct list_head sd_log_le_buf;
+ 	struct list_head sd_log_le_revoke;
+ 	struct list_head sd_log_le_rg;
+ 	struct list_head sd_log_le_databuf;
+ 	struct list_head sd_log_le_ordered;
+ 
+-	unsigned int sd_log_blks_free;
++	atomic_t sd_log_blks_free;
+ 	struct mutex sd_log_reserve_mutex;
+ 
+ 	u64 sd_log_sequence;
+diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c
+index 5f6dc32..728d316 100644
+--- a/fs/gfs2/inode.c
++++ b/fs/gfs2/inode.c
+@@ -31,7 +31,6 @@
+ #include "log.h"
+ #include "meta_io.h"
+ #include "ops_address.h"
+-#include "ops_file.h"
+ #include "ops_inode.h"
+ #include "quota.h"
+ #include "rgrp.h"
+@@ -132,15 +131,21 @@ static struct inode *gfs2_iget_skip(struct super_block *sb,
+ 
+ void gfs2_set_iop(struct inode *inode)
+ {
++	struct gfs2_sbd *sdp = GFS2_SB(inode);
+ 	umode_t mode = inode->i_mode;
+ 
+ 	if (S_ISREG(mode)) {
+ 		inode->i_op = &gfs2_file_iops;
+-		inode->i_fop = &gfs2_file_fops;
+-		inode->i_mapping->a_ops = &gfs2_file_aops;
++		if (sdp->sd_args.ar_localflocks)
++			inode->i_fop = &gfs2_file_fops_nolock;
++		else
++			inode->i_fop = &gfs2_file_fops;
+ 	} else if (S_ISDIR(mode)) {
+ 		inode->i_op = &gfs2_dir_iops;
+-		inode->i_fop = &gfs2_dir_fops;
++		if (sdp->sd_args.ar_localflocks)
++			inode->i_fop = &gfs2_dir_fops_nolock;
++		else
++			inode->i_fop = &gfs2_dir_fops;
+ 	} else if (S_ISLNK(mode)) {
+ 		inode->i_op = &gfs2_symlink_iops;
+ 	} else {
+@@ -291,12 +296,10 @@ static int gfs2_dinode_in(struct gfs2_inode *ip, const void *buf)
+ 	di->di_entries = be32_to_cpu(str->di_entries);
+ 
+ 	di->di_eattr = be64_to_cpu(str->di_eattr);
+-	return 0;
+-}
++	if (S_ISREG(ip->i_inode.i_mode))
++		gfs2_set_aops(&ip->i_inode);
+ 
+-static void gfs2_inode_bh(struct gfs2_inode *ip, struct buffer_head *bh)
+-{
+-	ip->i_cache[0] = bh;
++	return 0;
+ }
+ 
+ /**
+@@ -366,7 +369,8 @@ int gfs2_dinode_dealloc(struct gfs2_inode *ip)
+ 	if (error)
+ 		goto out_rg_gunlock;
+ 
+-	gfs2_trans_add_gl(ip->i_gl);
++	set_bit(GLF_DIRTY, &ip->i_gl->gl_flags);
++	set_bit(GLF_LFLUSH, &ip->i_gl->gl_flags);
+ 
+ 	gfs2_free_di(rgd, ip);
+ 
+@@ -707,9 +711,10 @@ static int alloc_dinode(struct gfs2_inode *dip, u64 *no_addr, u64 *generation)
+ 	struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);
+ 	int error;
+ 
+-	gfs2_alloc_get(dip);
++	if (gfs2_alloc_get(dip) == NULL)
++		return -ENOMEM;
+ 
+-	dip->i_alloc.al_requested = RES_DINODE;
++	dip->i_alloc->al_requested = RES_DINODE;
+ 	error = gfs2_inplace_reserve(dip);
+ 	if (error)
+ 		goto out;
+@@ -855,7 +860,7 @@ static int link_dinode(struct gfs2_inode *dip, const struct qstr *name,
+ 
+ 	error = alloc_required = gfs2_diradd_alloc_required(&dip->i_inode, name);
+ 	if (alloc_required < 0)
+-		goto fail;
++		goto fail_quota_locks;
+ 	if (alloc_required) {
+ 		error = gfs2_quota_check(dip, dip->i_inode.i_uid, dip->i_inode.i_gid);
+ 		if (error)
+@@ -896,7 +901,7 @@ fail_end_trans:
+ 	gfs2_trans_end(sdp);
+ 
+ fail_ipreserv:
+-	if (dip->i_alloc.al_rgd)
++	if (dip->i_alloc->al_rgd)
+ 		gfs2_inplace_release(dip);
+ 
+ fail_quota_locks:
+@@ -966,7 +971,7 @@ struct inode *gfs2_createi(struct gfs2_holder *ghs, const struct qstr *name,
+ 	struct gfs2_inum_host inum = { .no_addr = 0, .no_formal_ino = 0 };
+ 	int error;
+ 	u64 generation;
+-	struct buffer_head *bh=NULL;
++	struct buffer_head *bh = NULL;
+ 
+ 	if (!name->len || name->len > GFS2_FNAMESIZE)
+ 		return ERR_PTR(-ENAMETOOLONG);
+@@ -1003,8 +1008,6 @@ struct inode *gfs2_createi(struct gfs2_holder *ghs, const struct qstr *name,
+ 	if (IS_ERR(inode))
+ 		goto fail_gunlock2;
+ 
+-	gfs2_inode_bh(GFS2_I(inode), bh);
 -
--					/*
--					 *	IDENTIFY distinguishes itself
--					 *	from the other messages by 
--					 *	setting the high bit.
--					 *
--					 *      Note : we need to handle at 
--					 *	least one outstanding command
--					 *	per LUN, and need to hash the 
--					 *	SCSI command for that I_T_L
--					 *	nexus based on the known ID 
--					 *	(at this point) and LUN.
--					 */
+ 	error = gfs2_inode_refresh(GFS2_I(inode));
+ 	if (error)
+ 		goto fail_gunlock2;
+@@ -1021,6 +1024,8 @@ struct inode *gfs2_createi(struct gfs2_holder *ghs, const struct qstr *name,
+ 	if (error)
+ 		goto fail_gunlock2;
+ 
++	if (bh)
++		brelse(bh);
+ 	if (!inode)
+ 		return ERR_PTR(-ENOMEM);
+ 	return inode;
+@@ -1032,6 +1037,8 @@ fail_gunlock2:
+ fail_gunlock:
+ 	gfs2_glock_dq(ghs);
+ fail:
++	if (bh)
++		brelse(bh);
+ 	return ERR_PTR(error);
+ }
+ 
+diff --git a/fs/gfs2/inode.h b/fs/gfs2/inode.h
+index 351ac87..d446506 100644
+--- a/fs/gfs2/inode.h
++++ b/fs/gfs2/inode.h
+@@ -20,6 +20,18 @@ static inline int gfs2_is_jdata(const struct gfs2_inode *ip)
+ 	return ip->i_di.di_flags & GFS2_DIF_JDATA;
+ }
+ 
++static inline int gfs2_is_writeback(const struct gfs2_inode *ip)
++{
++	const struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
++	return (sdp->sd_args.ar_data == GFS2_DATA_WRITEBACK) && !gfs2_is_jdata(ip);
++}
++
++static inline int gfs2_is_ordered(const struct gfs2_inode *ip)
++{
++	const struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
++	return (sdp->sd_args.ar_data == GFS2_DATA_ORDERED) && !gfs2_is_jdata(ip);
++}
++
+ static inline int gfs2_is_dir(const struct gfs2_inode *ip)
+ {
+ 	return S_ISDIR(ip->i_inode.i_mode);
+diff --git a/fs/gfs2/locking/dlm/mount.c b/fs/gfs2/locking/dlm/mount.c
+index 41c5b04..f2efff4 100644
+--- a/fs/gfs2/locking/dlm/mount.c
++++ b/fs/gfs2/locking/dlm/mount.c
+@@ -67,6 +67,11 @@ static int make_args(struct gdlm_ls *ls, char *data_arg, int *nodir)
+ 	memset(data, 0, 256);
+ 	strncpy(data, data_arg, 255);
+ 
++	if (!strlen(data)) {
++		log_error("no mount options, (u)mount helpers not installed");
++		return -EINVAL;
++	}
++
+ 	for (options = data; (x = strsep(&options, ":")); ) {
+ 		if (!*x)
+ 			continue;
+diff --git a/fs/gfs2/locking/dlm/plock.c b/fs/gfs2/locking/dlm/plock.c
+index 1f7b038..2ebd374 100644
+--- a/fs/gfs2/locking/dlm/plock.c
++++ b/fs/gfs2/locking/dlm/plock.c
+@@ -89,15 +89,19 @@ int gdlm_plock(void *lockspace, struct lm_lockname *name,
+ 	op->info.number		= name->ln_number;
+ 	op->info.start		= fl->fl_start;
+ 	op->info.end		= fl->fl_end;
+-	op->info.owner		= (__u64)(long) fl->fl_owner;
+ 	if (fl->fl_lmops && fl->fl_lmops->fl_grant) {
++		/* fl_owner is lockd which doesn't distinguish
++		   processes on the nfs client */
++		op->info.owner	= (__u64) fl->fl_pid;
+ 		xop->callback	= fl->fl_lmops->fl_grant;
+ 		locks_init_lock(&xop->flc);
+ 		locks_copy_lock(&xop->flc, fl);
+ 		xop->fl		= fl;
+ 		xop->file	= file;
+-	} else
++	} else {
++		op->info.owner	= (__u64)(long) fl->fl_owner;
+ 		xop->callback	= NULL;
++	}
+ 
+ 	send_op(op);
+ 
+@@ -203,7 +207,10 @@ int gdlm_punlock(void *lockspace, struct lm_lockname *name,
+ 	op->info.number		= name->ln_number;
+ 	op->info.start		= fl->fl_start;
+ 	op->info.end		= fl->fl_end;
+-	op->info.owner		= (__u64)(long) fl->fl_owner;
++	if (fl->fl_lmops && fl->fl_lmops->fl_grant)
++		op->info.owner	= (__u64) fl->fl_pid;
++	else
++		op->info.owner	= (__u64)(long) fl->fl_owner;
+ 
+ 	send_op(op);
+ 	wait_event(recv_wq, (op->done != 0));
+@@ -242,7 +249,10 @@ int gdlm_plock_get(void *lockspace, struct lm_lockname *name,
+ 	op->info.number		= name->ln_number;
+ 	op->info.start		= fl->fl_start;
+ 	op->info.end		= fl->fl_end;
+-	op->info.owner		= (__u64)(long) fl->fl_owner;
++	if (fl->fl_lmops && fl->fl_lmops->fl_grant)
++		op->info.owner	= (__u64) fl->fl_pid;
++	else
++		op->info.owner	= (__u64)(long) fl->fl_owner;
+ 
+ 	send_op(op);
+ 	wait_event(recv_wq, (op->done != 0));
+diff --git a/fs/gfs2/locking/dlm/sysfs.c b/fs/gfs2/locking/dlm/sysfs.c
+index ae9e6a2..a87b098 100644
+--- a/fs/gfs2/locking/dlm/sysfs.c
++++ b/fs/gfs2/locking/dlm/sysfs.c
+@@ -189,51 +189,39 @@ static struct kobj_type gdlm_ktype = {
+ 	.sysfs_ops     = &gdlm_attr_ops,
+ };
+ 
+-static struct kset gdlm_kset = {
+-	.ktype  = &gdlm_ktype,
+-};
++static struct kset *gdlm_kset;
+ 
+ int gdlm_kobject_setup(struct gdlm_ls *ls, struct kobject *fskobj)
+ {
+ 	int error;
+ 
+-	error = kobject_set_name(&ls->kobj, "%s", "lock_module");
+-	if (error) {
+-		log_error("can't set kobj name %d", error);
+-		return error;
+-	}
 -
--					if (message & 0x80) {
--						DPRINTK (PHASE_MSGIN, "scsi%d : IDENTIFY message received from id %d, lun %d.\n", hostno, target, message & 7);
--					} else {
--						/*
--						 *      We should go into a
--						 *	MESSAGE OUT phase, and
--						 *	send  a MESSAGE_REJECT
--						 *      if we run into a message 
--						 *	that we don't like.  The
--						 *	seagate driver needs 
--						 *	some serious 
--						 *	restructuring first
--						 *	though.
--						 */
--						DPRINTK (PHASE_MSGIN, "scsi%d : unknown message %d from target %d.\n", hostno, message, target);
--					}
--				}
--				break;
--			default:
--				printk(KERN_ERR "scsi%d : unknown phase.\n", hostno);
--				st0x_aborted = DID_ERROR;
--			}	/* end of switch (status_read &  REQ_MASK) */
--#ifdef SLOW_RATE
--			/*
--			 * I really don't care to deal with borken devices in
--			 * each single byte transfer case (ie, message in,
--			 * message out, status), so I'll do the wait here if 
--			 * necessary.
--			 */
--			if(borken)
--				borken_wait();
--#endif
+-	ls->kobj.kset = &gdlm_kset;
+-	ls->kobj.ktype = &gdlm_ktype;
+-	ls->kobj.parent = fskobj;
 -
--		}		/* if(status_read & STAT_REQ) ends */
--	}			/* while(((status_read = STATUS)...) ends */
+-	error = kobject_register(&ls->kobj);
++	ls->kobj.kset = gdlm_kset;
++	error = kobject_init_and_add(&ls->kobj, &gdlm_ktype, fskobj,
++				     "lock_module");
+ 	if (error)
+ 		log_error("can't register kobj %d", error);
++	kobject_uevent(&ls->kobj, KOBJ_ADD);
+ 
+ 	return error;
+ }
+ 
+ void gdlm_kobject_release(struct gdlm_ls *ls)
+ {
+-	kobject_unregister(&ls->kobj);
++	kobject_put(&ls->kobj);
+ }
+ 
+ int gdlm_sysfs_init(void)
+ {
+-	int error;
 -
--	DPRINTK(PHASE_DATAIN | PHASE_DATAOUT | PHASE_EXIT, "scsi%d : Transfered %d bytes\n", hostno, transfered);
+-	kobject_set_name(&gdlm_kset.kobj, "lock_dlm");
+-	kobj_set_kset_s(&gdlm_kset, kernel_subsys);
+-	error = kset_register(&gdlm_kset);
+-	if (error)
+-		printk("lock_dlm: cannot register kset %d\n", error);
 -
--#if (DEBUG & PHASE_EXIT)
--#if 0				/* Doesn't work for scatter/gather */
--	printk("Buffer : \n");
--	for(i = 0; i < 20; ++i)
--		printk("%02x  ", ((unsigned char *) data)[i]);	/* WDE mod */
--	printk("\n");
--#endif
--	printk("scsi%d : status = ", hostno);
--	scsi_print_status(status);
--	printk(" message = %02x\n", message);
--#endif
+-	return error;
++	gdlm_kset = kset_create_and_add("lock_dlm", NULL, kernel_kobj);
++	if (!gdlm_kset) {
++		printk(KERN_WARNING "%s: can not create kset\n", __FUNCTION__);
++		return -ENOMEM;
++	}
++	return 0;
+ }
+ 
+ void gdlm_sysfs_exit(void)
+ {
+-	kset_unregister(&gdlm_kset);
++	kset_unregister(gdlm_kset);
+ }
+ 
+diff --git a/fs/gfs2/locking/dlm/thread.c b/fs/gfs2/locking/dlm/thread.c
+index bd938f0..521694f 100644
+--- a/fs/gfs2/locking/dlm/thread.c
++++ b/fs/gfs2/locking/dlm/thread.c
+@@ -273,18 +273,13 @@ static int gdlm_thread(void *data, int blist)
+ 	struct gdlm_ls *ls = (struct gdlm_ls *) data;
+ 	struct gdlm_lock *lp = NULL;
+ 	uint8_t complete, blocking, submit, drop;
+-	DECLARE_WAITQUEUE(wait, current);
+ 
+ 	/* Only thread1 is allowed to do blocking callbacks since gfs
+ 	   may wait for a completion callback within a blocking cb. */
+ 
+ 	while (!kthread_should_stop()) {
+-		set_current_state(TASK_INTERRUPTIBLE);
+-		add_wait_queue(&ls->thread_wait, &wait);
+-		if (no_work(ls, blist))
+-			schedule();
+-		remove_wait_queue(&ls->thread_wait, &wait);
+-		set_current_state(TASK_RUNNING);
++		wait_event_interruptible(ls->thread_wait,
++				!no_work(ls, blist) || kthread_should_stop());
+ 
+ 		complete = blocking = submit = drop = 0;
+ 
+diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c
+index 7df7024..161ab6f 100644
+--- a/fs/gfs2/log.c
++++ b/fs/gfs2/log.c
+@@ -1,6 +1,6 @@
+ /*
+  * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
+- * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
++ * Copyright (C) 2004-2007 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
+@@ -16,6 +16,8 @@
+ #include <linux/crc32.h>
+ #include <linux/lm_interface.h>
+ #include <linux/delay.h>
++#include <linux/kthread.h>
++#include <linux/freezer.h>
+ 
+ #include "gfs2.h"
+ #include "incore.h"
+@@ -68,14 +70,12 @@ unsigned int gfs2_struct2blk(struct gfs2_sbd *sdp, unsigned int nstruct,
+  *
+  */
+ 
+-void gfs2_remove_from_ail(struct address_space *mapping, struct gfs2_bufdata *bd)
++void gfs2_remove_from_ail(struct gfs2_bufdata *bd)
+ {
+ 	bd->bd_ail = NULL;
+ 	list_del_init(&bd->bd_ail_st_list);
+ 	list_del_init(&bd->bd_ail_gl_list);
+ 	atomic_dec(&bd->bd_gl->gl_ail_count);
+-	if (mapping)
+-		gfs2_meta_cache_flush(GFS2_I(mapping->host));
+ 	brelse(bd->bd_bh);
+ }
+ 
+@@ -92,8 +92,6 @@ static void gfs2_ail1_start_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai)
+ 	struct buffer_head *bh;
+ 	int retry;
+ 
+-	BUG_ON(!spin_is_locked(&sdp->sd_log_lock));
 -
--	/* We shouldn't reach this until *after* BSY has been deasserted */
+ 	do {
+ 		retry = 0;
+ 
+@@ -210,7 +208,7 @@ static void gfs2_ail1_start(struct gfs2_sbd *sdp, int flags)
+ 	gfs2_log_unlock(sdp);
+ }
+ 
+-int gfs2_ail1_empty(struct gfs2_sbd *sdp, int flags)
++static int gfs2_ail1_empty(struct gfs2_sbd *sdp, int flags)
+ {
+ 	struct gfs2_ail *ai, *s;
+ 	int ret;
+@@ -248,7 +246,7 @@ static void gfs2_ail2_empty_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai)
+ 		bd = list_entry(head->prev, struct gfs2_bufdata,
+ 				bd_ail_st_list);
+ 		gfs2_assert(sdp, bd->bd_ail == ai);
+-		gfs2_remove_from_ail(bd->bd_bh->b_page->mapping, bd);
++		gfs2_remove_from_ail(bd);
+ 	}
+ }
+ 
+@@ -303,7 +301,7 @@ int gfs2_log_reserve(struct gfs2_sbd *sdp, unsigned int blks)
+ 
+ 	mutex_lock(&sdp->sd_log_reserve_mutex);
+ 	gfs2_log_lock(sdp);
+-	while(sdp->sd_log_blks_free <= (blks + reserved_blks)) {
++	while(atomic_read(&sdp->sd_log_blks_free) <= (blks + reserved_blks)) {
+ 		gfs2_log_unlock(sdp);
+ 		gfs2_ail1_empty(sdp, 0);
+ 		gfs2_log_flush(sdp, NULL);
+@@ -312,7 +310,7 @@ int gfs2_log_reserve(struct gfs2_sbd *sdp, unsigned int blks)
+ 			gfs2_ail1_start(sdp, 0);
+ 		gfs2_log_lock(sdp);
+ 	}
+-	sdp->sd_log_blks_free -= blks;
++	atomic_sub(blks, &sdp->sd_log_blks_free);
+ 	gfs2_log_unlock(sdp);
+ 	mutex_unlock(&sdp->sd_log_reserve_mutex);
+ 
+@@ -332,27 +330,23 @@ void gfs2_log_release(struct gfs2_sbd *sdp, unsigned int blks)
+ {
+ 
+ 	gfs2_log_lock(sdp);
+-	sdp->sd_log_blks_free += blks;
++	atomic_add(blks, &sdp->sd_log_blks_free);
+ 	gfs2_assert_withdraw(sdp,
+-			     sdp->sd_log_blks_free <= sdp->sd_jdesc->jd_blocks);
++			     atomic_read(&sdp->sd_log_blks_free) <= sdp->sd_jdesc->jd_blocks);
+ 	gfs2_log_unlock(sdp);
+ 	up_read(&sdp->sd_log_flush_lock);
+ }
+ 
+ static u64 log_bmap(struct gfs2_sbd *sdp, unsigned int lbn)
+ {
+-	struct inode *inode = sdp->sd_jdesc->jd_inode;
+-	int error;
+-	struct buffer_head bh_map = { .b_state = 0, .b_blocknr = 0 };
 -
--#ifdef LINKED
--	else
--	{
--		/*
--		 * Fix the message byte so that unsuspecting high level drivers
--		 * don't puke when they see a LINKED COMMAND message in place of
--		 * the COMMAND COMPLETE they may be expecting.  Shouldn't be
--		 * necessary, but it's better to be on the safe side.
--		 *
--		 * A non LINKED* message byte will indicate that the command
--		 * completed, and we are now disconnected.
--		 */
+-	bh_map.b_size = 1 << inode->i_blkbits;
+-	error = gfs2_block_map(inode, lbn, 0, &bh_map);
+-	if (error || !bh_map.b_blocknr)
+-		printk(KERN_INFO "error=%d, dbn=%llu lbn=%u", error,
+-		       (unsigned long long)bh_map.b_blocknr, lbn);
+-	gfs2_assert_withdraw(sdp, !error && bh_map.b_blocknr);
 -
--		switch (message) {
--		case LINKED_CMD_COMPLETE:
--		case LINKED_FLG_CMD_COMPLETE:
--			message = COMMAND_COMPLETE;
--			linked_target = current_target;
--			linked_lun = current_lun;
--			linked_connected = 1;
--			DPRINTK (DEBUG_LINKED, "scsi%d : keeping I_T_L nexus established for linked command.\n", hostno);
--			/* We also will need to adjust status to accommodate intermediate
--			   conditions. */
--			if ((status == INTERMEDIATE_GOOD) || (status == INTERMEDIATE_C_GOOD))
--				status = GOOD;
--			break;
--			/*
--			 * We should also handle what are "normal" termination
--			 * messages here (ABORT, BUS_DEVICE_RESET?, and
--			 * COMMAND_COMPLETE individually, and flake if things
--			 * aren't right.
--			 */
--		default:
--			DPRINTK (DEBUG_LINKED, "scsi%d : closing I_T_L nexus.\n", hostno);
--			linked_connected = 0;
+-	return bh_map.b_blocknr;
++	struct gfs2_journal_extent *je;
++
++	list_for_each_entry(je, &sdp->sd_jdesc->extent_list, extent_list) {
++		if (lbn >= je->lblock && lbn < je->lblock + je->blocks)
++			return je->dblock + lbn - je->lblock;
++	}
++
++	return -1;
+ }
+ 
+ /**
+@@ -561,8 +555,8 @@ static void log_pull_tail(struct gfs2_sbd *sdp, unsigned int new_tail)
+ 	ail2_empty(sdp, new_tail);
+ 
+ 	gfs2_log_lock(sdp);
+-	sdp->sd_log_blks_free += dist;
+-	gfs2_assert_withdraw(sdp, sdp->sd_log_blks_free <= sdp->sd_jdesc->jd_blocks);
++	atomic_add(dist, &sdp->sd_log_blks_free);
++	gfs2_assert_withdraw(sdp, atomic_read(&sdp->sd_log_blks_free) <= sdp->sd_jdesc->jd_blocks);
+ 	gfs2_log_unlock(sdp);
+ 
+ 	sdp->sd_log_tail = new_tail;
+@@ -652,7 +646,7 @@ static void gfs2_ordered_write(struct gfs2_sbd *sdp)
+ 		get_bh(bh);
+ 		gfs2_log_unlock(sdp);
+ 		lock_buffer(bh);
+-		if (test_clear_buffer_dirty(bh)) {
++		if (buffer_mapped(bh) && test_clear_buffer_dirty(bh)) {
+ 			bh->b_end_io = end_buffer_write_sync;
+ 			submit_bh(WRITE, bh);
+ 		} else {
+@@ -694,20 +688,16 @@ static void gfs2_ordered_wait(struct gfs2_sbd *sdp)
+  *
+  */
+ 
+-void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl)
++void __gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl)
+ {
+ 	struct gfs2_ail *ai;
+ 
+ 	down_write(&sdp->sd_log_flush_lock);
+ 
+-	if (gl) {
+-		gfs2_log_lock(sdp);
+-		if (list_empty(&gl->gl_le.le_list)) {
+-			gfs2_log_unlock(sdp);
+-			up_write(&sdp->sd_log_flush_lock);
+-			return;
 -		}
--	}
--#endif	/* LINKED */
+-		gfs2_log_unlock(sdp);
++	/* Log might have been flushed while we waited for the flush lock */
++	if (gl && !test_bit(GLF_LFLUSH, &gl->gl_flags)) {
++		up_write(&sdp->sd_log_flush_lock);
++		return;
+ 	}
+ 
+ 	ai = kzalloc(sizeof(struct gfs2_ail), GFP_NOFS | __GFP_NOFAIL);
+@@ -739,7 +729,7 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl)
+ 		log_flush_commit(sdp);
+ 	else if (sdp->sd_log_tail != current_tail(sdp) && !sdp->sd_log_idle){
+ 		gfs2_log_lock(sdp);
+-		sdp->sd_log_blks_free--; /* Adjust for unreserved buffer */
++		atomic_dec(&sdp->sd_log_blks_free); /* Adjust for unreserved buffer */
+ 		gfs2_log_unlock(sdp);
+ 		log_write_header(sdp, 0, PULL);
+ 	}
+@@ -767,7 +757,7 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl)
+ static void log_refund(struct gfs2_sbd *sdp, struct gfs2_trans *tr)
+ {
+ 	unsigned int reserved;
+-	unsigned int old;
++	unsigned int unused;
+ 
+ 	gfs2_log_lock(sdp);
+ 
+@@ -779,14 +769,11 @@ static void log_refund(struct gfs2_sbd *sdp, struct gfs2_trans *tr)
+ 	sdp->sd_log_commited_revoke += tr->tr_num_revoke - tr->tr_num_revoke_rm;
+ 	gfs2_assert_withdraw(sdp, ((int)sdp->sd_log_commited_revoke) >= 0);
+ 	reserved = calc_reserved(sdp);
+-	old = sdp->sd_log_blks_free;
+-	sdp->sd_log_blks_free += tr->tr_reserved -
+-				 (reserved - sdp->sd_log_blks_reserved);
 -
--	if (should_reconnect) {
--		DPRINTK (PHASE_RESELECT, "scsi%d : exiting seagate_st0x_queue_command() with reconnect enabled.\n", hostno);
--		WRITE_CONTROL (BASE_CMD | CMD_INTR);
--	} else
--		WRITE_CONTROL (BASE_CMD);
+-	gfs2_assert_withdraw(sdp, sdp->sd_log_blks_free >= old);
+-	gfs2_assert_withdraw(sdp, sdp->sd_log_blks_free <=
++	unused = sdp->sd_log_blks_reserved - reserved + tr->tr_reserved;
++	gfs2_assert_withdraw(sdp, unused >= 0);
++	atomic_add(unused, &sdp->sd_log_blks_free);
++	gfs2_assert_withdraw(sdp, atomic_read(&sdp->sd_log_blks_free) <=
+ 			     sdp->sd_jdesc->jd_blocks);
 -
--	return retcode (st0x_aborted);
--}				/* end of internal_command */
+ 	sdp->sd_log_blks_reserved = reserved;
+ 
+ 	gfs2_log_unlock(sdp);
+@@ -825,7 +812,6 @@ void gfs2_log_shutdown(struct gfs2_sbd *sdp)
+ 	down_write(&sdp->sd_log_flush_lock);
+ 
+ 	gfs2_assert_withdraw(sdp, !sdp->sd_log_blks_reserved);
+-	gfs2_assert_withdraw(sdp, !sdp->sd_log_num_gl);
+ 	gfs2_assert_withdraw(sdp, !sdp->sd_log_num_buf);
+ 	gfs2_assert_withdraw(sdp, !sdp->sd_log_num_revoke);
+ 	gfs2_assert_withdraw(sdp, !sdp->sd_log_num_rg);
+@@ -838,7 +824,7 @@ void gfs2_log_shutdown(struct gfs2_sbd *sdp)
+ 	log_write_header(sdp, GFS2_LOG_HEAD_UNMOUNT,
+ 			 (sdp->sd_log_tail == current_tail(sdp)) ? 0 : PULL);
+ 
+-	gfs2_assert_warn(sdp, sdp->sd_log_blks_free == sdp->sd_jdesc->jd_blocks);
++	gfs2_assert_warn(sdp, atomic_read(&sdp->sd_log_blks_free) == sdp->sd_jdesc->jd_blocks);
+ 	gfs2_assert_warn(sdp, sdp->sd_log_head == sdp->sd_log_tail);
+ 	gfs2_assert_warn(sdp, list_empty(&sdp->sd_ail2_list));
+ 
+@@ -866,3 +852,42 @@ void gfs2_meta_syncfs(struct gfs2_sbd *sdp)
+ 	}
+ }
+ 
++
++/**
++ * gfs2_logd - Update log tail as Active Items get flushed to in-place blocks
++ * @sdp: Pointer to GFS2 superblock
++ *
++ * Also, periodically check to make sure that we're using the most recent
++ * journal index.
++ */
++
++int gfs2_logd(void *data)
++{
++	struct gfs2_sbd *sdp = data;
++	unsigned long t;
++	int need_flush;
++
++	while (!kthread_should_stop()) {
++		/* Advance the log tail */
++
++		t = sdp->sd_log_flush_time +
++		    gfs2_tune_get(sdp, gt_log_flush_secs) * HZ;
++
++		gfs2_ail1_empty(sdp, DIO_ALL);
++		gfs2_log_lock(sdp);
++		need_flush = sdp->sd_log_num_buf > gfs2_tune_get(sdp, gt_incore_log_blocks);
++		gfs2_log_unlock(sdp);
++		if (need_flush || time_after_eq(jiffies, t)) {
++			gfs2_log_flush(sdp, NULL);
++			sdp->sd_log_flush_time = jiffies;
++		}
++
++		t = gfs2_tune_get(sdp, gt_logd_secs) * HZ;
++		if (freezing(current))
++			refrigerator();
++		schedule_timeout_interruptible(t);
++	}
++
++	return 0;
++}
++
+diff --git a/fs/gfs2/log.h b/fs/gfs2/log.h
+index dae2824..7711528 100644
+--- a/fs/gfs2/log.h
++++ b/fs/gfs2/log.h
+@@ -48,8 +48,6 @@ static inline void gfs2_log_pointers_init(struct gfs2_sbd *sdp,
+ unsigned int gfs2_struct2blk(struct gfs2_sbd *sdp, unsigned int nstruct,
+ 			    unsigned int ssize);
+ 
+-int gfs2_ail1_empty(struct gfs2_sbd *sdp, int flags);
 -
--static int seagate_st0x_abort(struct scsi_cmnd * SCpnt)
+ int gfs2_log_reserve(struct gfs2_sbd *sdp, unsigned int blks);
+ void gfs2_log_release(struct gfs2_sbd *sdp, unsigned int blks);
+ void gfs2_log_incr_head(struct gfs2_sbd *sdp);
+@@ -57,11 +55,19 @@ void gfs2_log_incr_head(struct gfs2_sbd *sdp);
+ struct buffer_head *gfs2_log_get_buf(struct gfs2_sbd *sdp);
+ struct buffer_head *gfs2_log_fake_buf(struct gfs2_sbd *sdp,
+ 				      struct buffer_head *real);
+-void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl);
++void __gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl);
++
++static inline void gfs2_log_flush(struct gfs2_sbd *sbd, struct gfs2_glock *gl)
++{
++	if (!gl || test_bit(GLF_LFLUSH, &gl->gl_flags))
++		__gfs2_log_flush(sbd, gl);
++}
++
+ void gfs2_log_commit(struct gfs2_sbd *sdp, struct gfs2_trans *trans);
+-void gfs2_remove_from_ail(struct address_space *mapping, struct gfs2_bufdata *bd);
++void gfs2_remove_from_ail(struct gfs2_bufdata *bd);
+ 
+ void gfs2_log_shutdown(struct gfs2_sbd *sdp);
+ void gfs2_meta_syncfs(struct gfs2_sbd *sdp);
++int gfs2_logd(void *data);
+ 
+ #endif /* __LOG_DOT_H__ */
+diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c
+index 6c27cea..fae59d6 100644
+--- a/fs/gfs2/lops.c
++++ b/fs/gfs2/lops.c
+@@ -87,6 +87,7 @@ static void gfs2_unpin(struct gfs2_sbd *sdp, struct buffer_head *bh,
+ 	}
+ 	bd->bd_ail = ai;
+ 	list_add(&bd->bd_ail_st_list, &ai->ai_ail1_list);
++	clear_bit(GLF_LFLUSH, &bd->bd_gl->gl_flags);
+ 	gfs2_log_unlock(sdp);
+ 	unlock_buffer(bh);
+ }
+@@ -124,49 +125,6 @@ static struct buffer_head *gfs2_get_log_desc(struct gfs2_sbd *sdp, u32 ld_type)
+ 	return bh;
+ }
+ 
+-static void __glock_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le)
 -{
--	st0x_aborted = DID_ABORT;
--	return SUCCESS;
--}
--
--#undef ULOOP
--#undef TIMEOUT
--
--/*
-- * the seagate_st0x_reset function resets the SCSI bus 
-- *
-- * May be called with SCpnt = NULL
-- */
+-	struct gfs2_glock *gl;
+-	struct gfs2_trans *tr = current->journal_info;
 -
--static int seagate_st0x_bus_reset(struct scsi_cmnd * SCpnt)
--{
--	/* No timeouts - this command is going to fail because it was reset. */
--	DANY ("scsi%d: Reseting bus... ", hostno);
+-	tr->tr_touched = 1;
 -
--	/* assert  RESET signal on SCSI bus.  */
--	WRITE_CONTROL (BASE_CMD | CMD_RST);
+-	gl = container_of(le, struct gfs2_glock, gl_le);
+-	if (gfs2_assert_withdraw(sdp, gfs2_glock_is_held_excl(gl)))
+-		return;
 -
--	mdelay (20);
+-	if (!list_empty(&le->le_list))
+-		return;
 -
--	WRITE_CONTROL (BASE_CMD);
--	st0x_aborted = DID_RESET;
+-	gfs2_glock_hold(gl);
+-	set_bit(GLF_DIRTY, &gl->gl_flags);
+-	sdp->sd_log_num_gl++;
+-	list_add(&le->le_list, &sdp->sd_log_le_gl);
+-}
 -
--	DANY ("done.\n");
--	return SUCCESS;
+-static void glock_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le)
+-{
+-	gfs2_log_lock(sdp);
+-	__glock_lo_add(sdp, le);
+-	gfs2_log_unlock(sdp);
 -}
 -
--static int seagate_st0x_release(struct Scsi_Host *shost)
+-static void glock_lo_after_commit(struct gfs2_sbd *sdp, struct gfs2_ail *ai)
 -{
--	if (shost->irq)
--		free_irq(shost->irq, shost);
--	release_region(shost->io_port, shost->n_io_port);
--	return 0;
+-	struct list_head *head = &sdp->sd_log_le_gl;
+-	struct gfs2_glock *gl;
+-
+-	while (!list_empty(head)) {
+-		gl = list_entry(head->next, struct gfs2_glock, gl_le.le_list);
+-		list_del_init(&gl->gl_le.le_list);
+-		sdp->sd_log_num_gl--;
+-
+-		gfs2_assert_withdraw(sdp, gfs2_glock_is_held_excl(gl));
+-		gfs2_glock_put(gl);
+-	}
+-	gfs2_assert_warn(sdp, !sdp->sd_log_num_gl);
 -}
 -
--static struct scsi_host_template driver_template = {
--	.detect         	= seagate_st0x_detect,
--	.release        	= seagate_st0x_release,
--	.info           	= seagate_st0x_info,
--	.queuecommand   	= seagate_st0x_queue_command,
--	.eh_abort_handler	= seagate_st0x_abort,
--	.eh_bus_reset_handler	= seagate_st0x_bus_reset,
--	.can_queue      	= 1,
--	.this_id        	= 7,
--	.sg_tablesize   	= SG_ALL,
--	.cmd_per_lun    	= 1,
--	.use_clustering		= DISABLE_CLUSTERING,
--};
--#include "scsi_module.c"
-diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
-index f1871ea..17216b7 100644
---- a/drivers/scsi/sg.c
-+++ b/drivers/scsi/sg.c
-@@ -602,8 +602,9 @@ sg_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos)
- 	 * but is is possible that the app intended SG_DXFER_TO_DEV, because there
- 	 * is a non-zero input_size, so emit a warning.
- 	 */
--	if (hp->dxfer_direction == SG_DXFER_TO_FROM_DEV)
--		if (printk_ratelimit())
-+	if (hp->dxfer_direction == SG_DXFER_TO_FROM_DEV) {
-+		static char cmd[TASK_COMM_LEN];
-+		if (strcmp(current->comm, cmd) && printk_ratelimit()) {
- 			printk(KERN_WARNING
- 			       "sg_write: data in/out %d/%d bytes for SCSI command 0x%x--"
- 			       "guessing data in;\n" KERN_WARNING "   "
-@@ -611,6 +612,9 @@ sg_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos)
- 			       old_hdr.reply_len - (int)SZ_SG_HEADER,
- 			       input_size, (unsigned int) cmnd[0],
- 			       current->comm);
-+			strcpy(cmd, current->comm);
-+		}
-+	}
- 	k = sg_common_write(sfp, srp, cmnd, sfp->timeout, blocking);
- 	return (k < 0) ? k : count;
- }
-@@ -1418,7 +1422,6 @@ sg_add(struct class_device *cl_dev, struct class_interface *cl_intf)
+ static void buf_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le)
+ {
+ 	struct gfs2_bufdata *bd = container_of(le, struct gfs2_bufdata, bd_le);
+@@ -182,7 +140,8 @@ static void buf_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le)
+ 	list_add(&bd->bd_list_tr, &tr->tr_list_buf);
+ 	if (!list_empty(&le->le_list))
  		goto out;
- 	}
+-	__glock_lo_add(sdp, &bd->bd_gl->gl_le);
++	set_bit(GLF_LFLUSH, &bd->bd_gl->gl_flags);
++	set_bit(GLF_DIRTY, &bd->bd_gl->gl_flags);
+ 	gfs2_meta_check(sdp, bd->bd_bh);
+ 	gfs2_pin(sdp, bd->bd_bh);
+ 	sdp->sd_log_num_buf++;
+@@ -556,17 +515,20 @@ static void databuf_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le)
  
--	class_set_devdata(cl_dev, sdp);
- 	error = cdev_add(cdev, MKDEV(SCSI_GENERIC_MAJOR, sdp->index), 1);
- 	if (error)
- 		goto cdev_add_err;
-@@ -1431,11 +1434,14 @@ sg_add(struct class_device *cl_dev, struct class_interface *cl_intf)
- 				MKDEV(SCSI_GENERIC_MAJOR, sdp->index),
- 				cl_dev->dev, "%s",
- 				disk->disk_name);
--		if (IS_ERR(sg_class_member))
--			printk(KERN_WARNING "sg_add: "
--				"class_device_create failed\n");
-+		if (IS_ERR(sg_class_member)) {
-+			printk(KERN_ERR "sg_add: "
-+			       "class_device_create failed\n");
-+			error = PTR_ERR(sg_class_member);
-+			goto cdev_add_err;
+ 	lock_buffer(bd->bd_bh);
+ 	gfs2_log_lock(sdp);
+-	if (!list_empty(&bd->bd_list_tr))
+-		goto out;
+-	tr->tr_touched = 1;
+-	if (gfs2_is_jdata(ip)) {
+-		tr->tr_num_buf++;
+-		list_add(&bd->bd_list_tr, &tr->tr_list_buf);
++	if (tr) {
++		if (!list_empty(&bd->bd_list_tr))
++			goto out;
++		tr->tr_touched = 1;
++		if (gfs2_is_jdata(ip)) {
++			tr->tr_num_buf++;
++			list_add(&bd->bd_list_tr, &tr->tr_list_buf);
 +		}
- 		class_set_devdata(sg_class_member, sdp);
--		error = sysfs_create_link(&scsidp->sdev_gendev.kobj, 
-+		error = sysfs_create_link(&scsidp->sdev_gendev.kobj,
- 					  &sg_class_member->kobj, "generic");
- 		if (error)
- 			printk(KERN_ERR "sg_add: unable to make symlink "
-@@ -1447,6 +1453,8 @@ sg_add(struct class_device *cl_dev, struct class_interface *cl_intf)
- 		    "Attached scsi generic sg%d type %d\n", sdp->index,
- 		    scsidp->type);
+ 	}
+ 	if (!list_empty(&le->le_list))
+ 		goto out;
  
-+	class_set_devdata(cl_dev, sdp);
-+
- 	return 0;
+-	__glock_lo_add(sdp, &bd->bd_gl->gl_le);
++	set_bit(GLF_LFLUSH, &bd->bd_gl->gl_flags);
++	set_bit(GLF_DIRTY, &bd->bd_gl->gl_flags);
+ 	if (gfs2_is_jdata(ip)) {
+ 		gfs2_pin(sdp, bd->bd_bh);
+ 		tr->tr_num_databuf_new++;
+@@ -773,12 +735,6 @@ static void databuf_lo_after_commit(struct gfs2_sbd *sdp, struct gfs2_ail *ai)
+ }
  
- cdev_add_err:
-@@ -2521,7 +2529,7 @@ sg_idr_max_id(int id, void *p, void *data)
- static int
- sg_last_dev(void)
- {
--	int k = 0;
-+	int k = -1;
- 	unsigned long iflags;
  
- 	read_lock_irqsave(&sg_index_lock, iflags);
-diff --git a/drivers/scsi/sgiwd93.c b/drivers/scsi/sgiwd93.c
-index eef8275..d4ebe8c 100644
---- a/drivers/scsi/sgiwd93.c
-+++ b/drivers/scsi/sgiwd93.c
-@@ -159,6 +159,7 @@ void sgiwd93_reset(unsigned long base)
- 	udelay(50);
- 	hregs->ctrl = 0;
- }
-+EXPORT_SYMBOL_GPL(sgiwd93_reset);
+-const struct gfs2_log_operations gfs2_glock_lops = {
+-	.lo_add = glock_lo_add,
+-	.lo_after_commit = glock_lo_after_commit,
+-	.lo_name = "glock",
+-};
+-
+ const struct gfs2_log_operations gfs2_buf_lops = {
+ 	.lo_add = buf_lo_add,
+ 	.lo_incore_commit = buf_lo_incore_commit,
+@@ -816,7 +772,6 @@ const struct gfs2_log_operations gfs2_databuf_lops = {
+ };
  
- static inline void init_hpc_chain(struct hpc_data *hd)
- {
-diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c
-index c619990..1fcee16 100644
---- a/drivers/scsi/sr.c
-+++ b/drivers/scsi/sr.c
-@@ -67,8 +67,6 @@ MODULE_ALIAS_SCSI_DEVICE(TYPE_WORM);
+ const struct gfs2_log_operations *gfs2_log_ops[] = {
+-	&gfs2_glock_lops,
+ 	&gfs2_databuf_lops,
+ 	&gfs2_buf_lops,
+ 	&gfs2_rg_lops,
+diff --git a/fs/gfs2/main.c b/fs/gfs2/main.c
+index 7ecfe0d..9c7765c 100644
+--- a/fs/gfs2/main.c
++++ b/fs/gfs2/main.c
+@@ -29,9 +29,8 @@ static void gfs2_init_inode_once(struct kmem_cache *cachep, void *foo)
+ 	struct gfs2_inode *ip = foo;
  
- #define SR_DISKS	256
+ 	inode_init_once(&ip->i_inode);
+-	spin_lock_init(&ip->i_spin);
+ 	init_rwsem(&ip->i_rw_mutex);
+-	memset(ip->i_cache, 0, sizeof(ip->i_cache));
++	ip->i_alloc = NULL;
+ }
  
--#define MAX_RETRIES	3
--#define SR_TIMEOUT	(30 * HZ)
- #define SR_CAPABILITIES \
- 	(CDC_CLOSE_TRAY|CDC_OPEN_TRAY|CDC_LOCK|CDC_SELECT_SPEED| \
- 	 CDC_SELECT_DISC|CDC_MULTI_SESSION|CDC_MCN|CDC_MEDIA_CHANGED| \
-@@ -179,21 +177,28 @@ static int sr_media_change(struct cdrom_device_info *cdi, int slot)
+ static void gfs2_init_glock_once(struct kmem_cache *cachep, void *foo)
+diff --git a/fs/gfs2/meta_io.c b/fs/gfs2/meta_io.c
+index 4da4239..85aea27 100644
+--- a/fs/gfs2/meta_io.c
++++ b/fs/gfs2/meta_io.c
+@@ -50,6 +50,7 @@ static int gfs2_aspace_writepage(struct page *page,
+ static const struct address_space_operations aspace_aops = {
+ 	.writepage = gfs2_aspace_writepage,
+ 	.releasepage = gfs2_releasepage,
++	.sync_page = block_sync_page,
+ };
+ 
+ /**
+@@ -221,13 +222,14 @@ int gfs2_meta_read(struct gfs2_glock *gl, u64 blkno, int flags,
+ 		   struct buffer_head **bhp)
  {
- 	struct scsi_cd *cd = cdi->handle;
- 	int retval;
-+	struct scsi_sense_hdr *sshdr;
+ 	*bhp = getbuf(gl, blkno, CREATE);
+-	if (!buffer_uptodate(*bhp))
++	if (!buffer_uptodate(*bhp)) {
+ 		ll_rw_block(READ_META, 1, bhp);
+-	if (flags & DIO_WAIT) {
+-		int error = gfs2_meta_wait(gl->gl_sbd, *bhp);
+-		if (error) {
+-			brelse(*bhp);
+-			return error;
++		if (flags & DIO_WAIT) {
++			int error = gfs2_meta_wait(gl->gl_sbd, *bhp);
++			if (error) {
++				brelse(*bhp);
++				return error;
++			}
+ 		}
+ 	}
  
- 	if (CDSL_CURRENT != slot) {
- 		/* no changer support */
- 		return -EINVAL;
+@@ -282,7 +284,7 @@ void gfs2_attach_bufdata(struct gfs2_glock *gl, struct buffer_head *bh,
+ 		return;
  	}
  
--	retval = scsi_test_unit_ready(cd->device, SR_TIMEOUT, MAX_RETRIES);
--	if (retval) {
--		/* Unable to test, unit probably not ready.  This usually
--		 * means there is no disc in the drive.  Mark as changed,
--		 * and we will figure it out later once the drive is
--		 * available again.  */
-+	sshdr =  kzalloc(sizeof(*sshdr), GFP_KERNEL);
-+	retval = scsi_test_unit_ready(cd->device, SR_TIMEOUT, MAX_RETRIES,
-+				      sshdr);
-+	if (retval || (scsi_sense_valid(sshdr) &&
-+		       /* 0x3a is medium not present */
-+		       sshdr->asc == 0x3a)) {
-+		/* Media not present or unable to test, unit probably not
-+		 * ready. This usually means there is no disc in the drive.
-+		 * Mark as changed, and we will figure it out later once
-+		 * the drive is available again.
-+		 */
- 		cd->device->changed = 1;
--		return 1;	/* This will force a flush, if called from
--				 * check_disk_change */
-+		/* This will force a flush, if called from check_disk_change */
-+		retval = 1;
-+		goto out;
- 	};
+-	bd = kmem_cache_zalloc(gfs2_bufdata_cachep, GFP_NOFS | __GFP_NOFAIL),
++	bd = kmem_cache_zalloc(gfs2_bufdata_cachep, GFP_NOFS | __GFP_NOFAIL);
+ 	bd->bd_bh = bh;
+ 	bd->bd_gl = gl;
  
- 	retval = cd->device->changed;
-@@ -203,9 +208,17 @@ static int sr_media_change(struct cdrom_device_info *cdi, int slot)
- 	if (retval) {
- 		/* check multisession offset etc */
- 		sr_cd_check(cdi);
--
- 		get_sectorsize(cd);
+@@ -317,7 +319,7 @@ void gfs2_remove_from_journal(struct buffer_head *bh, struct gfs2_trans *tr, int
  	}
-+
-+out:
-+	/* Notify userspace, that media has changed. */
-+	if (retval != cd->previous_state)
-+		sdev_evt_send_simple(cd->device, SDEV_EVT_MEDIA_CHANGE,
-+				     GFP_KERNEL);
-+	cd->previous_state = retval;
-+	kfree(sshdr);
-+
- 	return retval;
+ 	if (bd) {
+ 		if (bd->bd_ail) {
+-			gfs2_remove_from_ail(NULL, bd);
++			gfs2_remove_from_ail(bd);
+ 			bh->b_private = NULL;
+ 			bd->bd_bh = NULL;
+ 			bd->bd_blkno = bh->b_blocknr;
+@@ -358,32 +360,6 @@ void gfs2_meta_wipe(struct gfs2_inode *ip, u64 bstart, u32 blen)
  }
-  
-diff --git a/drivers/scsi/sr.h b/drivers/scsi/sr.h
-index d65de96..81fbc0b 100644
---- a/drivers/scsi/sr.h
-+++ b/drivers/scsi/sr.h
-@@ -20,6 +20,9 @@
- #include <linux/genhd.h>
- #include <linux/kref.h>
- 
-+#define MAX_RETRIES	3
-+#define SR_TIMEOUT	(30 * HZ)
-+
- struct scsi_device;
- 
- /* The CDROM is fairly slow, so we need a little extra time */
-@@ -37,6 +40,7 @@ typedef struct scsi_cd {
- 	unsigned xa_flag:1;	/* CD has XA sectors ? */
- 	unsigned readcd_known:1;	/* drive supports READ_CD (0xbe) */
- 	unsigned readcd_cdda:1;	/* reading audio data using READ_CD */
-+	unsigned previous_state:1;	/* media has changed */
- 	struct cdrom_device_info cdi;
- 	/* We hold gendisk and scsi_device references on probe and use
- 	 * the refs on this kref to decide when to release them */
-diff --git a/drivers/scsi/sr_ioctl.c b/drivers/scsi/sr_ioctl.c
-index e1589f9..d5cebff 100644
---- a/drivers/scsi/sr_ioctl.c
-+++ b/drivers/scsi/sr_ioctl.c
-@@ -275,18 +275,6 @@ int sr_do_ioctl(Scsi_CD *cd, struct packet_command *cgc)
- /* ---------------------------------------------------------------------- */
- /* interface to cdrom.c                                                   */
  
--static int test_unit_ready(Scsi_CD *cd)
+ /**
+- * gfs2_meta_cache_flush - get rid of any references on buffers for this inode
+- * @ip: The GFS2 inode
+- *
+- * This releases buffers that are in the most-recently-used array of
+- * blocks used for indirect block addressing for this inode.
+- */
+-
+-void gfs2_meta_cache_flush(struct gfs2_inode *ip)
 -{
--	struct packet_command cgc;
+-	struct buffer_head **bh_slot;
+-	unsigned int x;
 -
--	memset(&cgc, 0, sizeof(struct packet_command));
--	cgc.cmd[0] = GPCMD_TEST_UNIT_READY;
--	cgc.quiet = 1;
--	cgc.data_direction = DMA_NONE;
--	cgc.timeout = IOCTL_TIMEOUT;
--	return sr_do_ioctl(cd, &cgc);
+-	spin_lock(&ip->i_spin);
+-
+-	for (x = 0; x < GFS2_MAX_META_HEIGHT; x++) {
+-		bh_slot = &ip->i_cache[x];
+-		if (*bh_slot) {
+-			brelse(*bh_slot);
+-			*bh_slot = NULL;
+-		}
+-	}
+-
+-	spin_unlock(&ip->i_spin);
 -}
 -
- int sr_tray_move(struct cdrom_device_info *cdi, int pos)
- {
- 	Scsi_CD *cd = cdi->handle;
-@@ -310,14 +298,46 @@ int sr_lock_door(struct cdrom_device_info *cdi, int lock)
+-/**
+  * gfs2_meta_indirect_buffer - Get a metadata buffer
+  * @ip: The GFS2 inode
+  * @height: The level of this buf in the metadata (indir addr) tree (if any)
+@@ -391,8 +367,6 @@ void gfs2_meta_cache_flush(struct gfs2_inode *ip)
+  * @new: Non-zero if we may create a new buffer
+  * @bhp: the buffer is returned here
+  *
+- * Try to use the gfs2_inode's MRU metadata tree cache.
+- *
+  * Returns: errno
+  */
  
- int sr_drive_status(struct cdrom_device_info *cdi, int slot)
+@@ -401,58 +375,25 @@ int gfs2_meta_indirect_buffer(struct gfs2_inode *ip, int height, u64 num,
  {
-+	struct scsi_cd *cd = cdi->handle;
-+	struct scsi_sense_hdr sshdr;
-+	struct media_event_desc med;
-+
- 	if (CDSL_CURRENT != slot) {
- 		/* we have no changer support */
- 		return -EINVAL;
- 	}
--	if (0 == test_unit_ready(cdi->handle))
-+	if (0 == scsi_test_unit_ready(cd->device, SR_TIMEOUT, MAX_RETRIES,
-+				      &sshdr))
- 		return CDS_DISC_OK;
+ 	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+ 	struct gfs2_glock *gl = ip->i_gl;
+-	struct buffer_head *bh = NULL, **bh_slot = ip->i_cache + height;
+-	int in_cache = 0;
+-
+-	BUG_ON(!gl);
+-	BUG_ON(!sdp);
+-
+-	spin_lock(&ip->i_spin);
+-	if (*bh_slot && (*bh_slot)->b_blocknr == num) {
+-		bh = *bh_slot;
+-		get_bh(bh);
+-		in_cache = 1;
+-	}
+-	spin_unlock(&ip->i_spin);
+-
+-	if (!bh)
+-		bh = getbuf(gl, num, CREATE);
+-
+-	if (!bh)
+-		return -ENOBUFS;
++	struct buffer_head *bh;
++	int ret = 0;
  
--	return CDS_TRAY_OPEN;
-+	if (!cdrom_get_media_event(cdi, &med)) {
-+		if (med.media_present)
-+			return CDS_DISC_OK;
-+		else if (med.door_open)
-+			return CDS_TRAY_OPEN;
-+		else
-+			return CDS_NO_DISC;
-+	}
-+
-+	/*
-+	 * 0x04 is format in progress .. but there must be a disc present!
-+	 */
-+	if (sshdr.sense_key == NOT_READY && sshdr.asc == 0x04)
-+		return CDS_DISC_OK;
-+
-+	/*
-+	 * If not using Mt Fuji extended media tray reports,
-+	 * just return TRAY_OPEN since ATAPI doesn't provide
-+	 * any other way to detect this...
-+	 */
-+	if (scsi_sense_valid(&sshdr) &&
-+	    /* 0x3a is medium not present */
-+	    sshdr.asc == 0x3a)
-+		return CDS_NO_DISC;
-+	else
-+		return CDS_TRAY_OPEN;
-+
-+	return CDS_DRIVE_NOT_READY;
+ 	if (new) {
+-		if (gfs2_assert_warn(sdp, height))
+-			goto err;
+-		meta_prep_new(bh);
++		BUG_ON(height == 0);
++		bh = gfs2_meta_new(gl, num);
+ 		gfs2_trans_add_bh(ip->i_gl, bh, 1);
+ 		gfs2_metatype_set(bh, GFS2_METATYPE_IN, GFS2_FORMAT_IN);
+ 		gfs2_buffer_clear_tail(bh, sizeof(struct gfs2_meta_header));
+ 	} else {
+ 		u32 mtype = height ? GFS2_METATYPE_IN : GFS2_METATYPE_DI;
+-		if (!buffer_uptodate(bh)) {
+-			ll_rw_block(READ_META, 1, &bh);
+-			if (gfs2_meta_wait(sdp, bh))
+-				goto err;
++		ret = gfs2_meta_read(gl, num, DIO_WAIT, &bh);
++		if (ret == 0 && gfs2_metatype_check(sdp, bh, mtype)) {
++			brelse(bh);
++			ret = -EIO;
+ 		}
+-		if (gfs2_metatype_check(sdp, bh, mtype))
+-			goto err;
+-	}
+-
+-	if (!in_cache) {
+-		spin_lock(&ip->i_spin);
+-		if (*bh_slot)
+-			brelse(*bh_slot);
+-		*bh_slot = bh;
+-		get_bh(bh);
+-		spin_unlock(&ip->i_spin);
+ 	}
+-
+ 	*bhp = bh;
+-	return 0;
+-err:
+-	brelse(bh);
+-	return -EIO;
++	return ret;
  }
  
- int sr_disk_status(struct cdrom_device_info *cdi)
-diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
-index 328c47c..7195270 100644
---- a/drivers/scsi/st.c
-+++ b/drivers/scsi/st.c
-@@ -9,7 +9,7 @@
-    Steve Hirsch, Andreas Koppenh"ofer, Michael Leodolter, Eyal Lebedinsky,
-    Michael Schaefer, J"org Weule, and Eric Youngdale.
- 
--   Copyright 1992 - 2007 Kai Makisara
-+   Copyright 1992 - 2008 Kai Makisara
-    email Kai.Makisara at kolumbus.fi
- 
-    Some small formal changes - aeb, 950809
-@@ -17,7 +17,7 @@
-    Last modified: 18-JAN-1998 Richard Gooch <rgooch at atnf.csiro.au> Devfs support
-  */
+ /**
+diff --git a/fs/gfs2/meta_io.h b/fs/gfs2/meta_io.h
+index b704822..73e3b1c 100644
+--- a/fs/gfs2/meta_io.h
++++ b/fs/gfs2/meta_io.h
+@@ -56,7 +56,6 @@ void gfs2_remove_from_journal(struct buffer_head *bh, struct gfs2_trans *tr,
  
--static const char *verstr = "20070203";
-+static const char *verstr = "20080117";
+ void gfs2_meta_wipe(struct gfs2_inode *ip, u64 bstart, u32 blen);
  
- #include <linux/module.h>
+-void gfs2_meta_cache_flush(struct gfs2_inode *ip);
+ int gfs2_meta_indirect_buffer(struct gfs2_inode *ip, int height, u64 num,
+ 			      int new, struct buffer_head **bhp);
  
-@@ -3214,8 +3214,7 @@ static int partition_tape(struct scsi_tape *STp, int size)
+diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c
+index 9679f8b..38dbe99 100644
+--- a/fs/gfs2/ops_address.c
++++ b/fs/gfs2/ops_address.c
+@@ -20,6 +20,8 @@
+ #include <linux/swap.h>
+ #include <linux/gfs2_ondisk.h>
+ #include <linux/lm_interface.h>
++#include <linux/backing-dev.h>
++#include <linux/pagevec.h>
  
+ #include "gfs2.h"
+ #include "incore.h"
+@@ -32,7 +34,6 @@
+ #include "quota.h"
+ #include "trans.h"
+ #include "rgrp.h"
+-#include "ops_file.h"
+ #include "super.h"
+ #include "util.h"
+ #include "glops.h"
+@@ -58,22 +59,6 @@ static void gfs2_page_add_databufs(struct gfs2_inode *ip, struct page *page,
+ }
  
- /* The ioctl command */
--static int st_ioctl(struct inode *inode, struct file *file,
--		    unsigned int cmd_in, unsigned long arg)
-+static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg)
+ /**
+- * gfs2_get_block - Fills in a buffer head with details about a block
+- * @inode: The inode
+- * @lblock: The block number to look up
+- * @bh_result: The buffer head to return the result in
+- * @create: Non-zero if we may add block to the file
+- *
+- * Returns: errno
+- */
+-
+-int gfs2_get_block(struct inode *inode, sector_t lblock,
+-	           struct buffer_head *bh_result, int create)
+-{
+-	return gfs2_block_map(inode, lblock, create, bh_result);
+-}
+-
+-/**
+  * gfs2_get_block_noalloc - Fills in a buffer head with details about a block
+  * @inode: The inode
+  * @lblock: The block number to look up
+@@ -88,7 +73,7 @@ static int gfs2_get_block_noalloc(struct inode *inode, sector_t lblock,
  {
- 	int i, cmd_nr, cmd_type, bt;
- 	int retval = 0;
-@@ -3870,7 +3869,7 @@ static const struct file_operations st_fops =
- 	.owner =	THIS_MODULE,
- 	.read =		st_read,
- 	.write =	st_write,
--	.ioctl =	st_ioctl,
-+	.unlocked_ioctl = st_ioctl,
- #ifdef CONFIG_COMPAT
- 	.compat_ioctl = st_compat_ioctl,
- #endif
-diff --git a/drivers/scsi/sun3_NCR5380.c b/drivers/scsi/sun3_NCR5380.c
-index 2dcde37..bcaba86 100644
---- a/drivers/scsi/sun3_NCR5380.c
-+++ b/drivers/scsi/sun3_NCR5380.c
-@@ -515,9 +515,9 @@ static __inline__ void initialize_SCp(struct scsi_cmnd *cmd)
-      * various queues are valid.
-      */
- 
--    if (cmd->use_sg) {
--	cmd->SCp.buffer = (struct scatterlist *) cmd->request_buffer;
--	cmd->SCp.buffers_residual = cmd->use_sg - 1;
-+    if (scsi_bufflen(cmd)) {
-+	cmd->SCp.buffer = scsi_sglist(cmd);
-+	cmd->SCp.buffers_residual = scsi_sg_count(cmd) - 1;
- 	cmd->SCp.ptr = (char *) SGADDR(cmd->SCp.buffer);
- 	cmd->SCp.this_residual = cmd->SCp.buffer->length;
+ 	int error;
  
-@@ -528,8 +528,8 @@ static __inline__ void initialize_SCp(struct scsi_cmnd *cmd)
-     } else {
- 	cmd->SCp.buffer = NULL;
- 	cmd->SCp.buffers_residual = 0;
--	cmd->SCp.ptr = (char *) cmd->request_buffer;
--	cmd->SCp.this_residual = cmd->request_bufflen;
-+	cmd->SCp.ptr = NULL;
-+	cmd->SCp.this_residual = 0;
-     }
-     
- }
-@@ -935,7 +935,7 @@ static int NCR5380_queue_command(struct scsi_cmnd *cmd,
-     }
- # endif
- # ifdef NCR5380_STAT_LIMIT
--    if (cmd->request_bufflen > NCR5380_STAT_LIMIT)
-+    if (scsi_bufflen(cmd) > NCR5380_STAT_LIMIT)
- # endif
- 	switch (cmd->cmnd[0])
- 	{
-@@ -943,14 +943,14 @@ static int NCR5380_queue_command(struct scsi_cmnd *cmd,
- 	    case WRITE_6:
- 	    case WRITE_10:
- 		hostdata->time_write[cmd->device->id] -= (jiffies - hostdata->timebase);
--		hostdata->bytes_write[cmd->device->id] += cmd->request_bufflen;
-+		hostdata->bytes_write[cmd->device->id] += scsi_bufflen(cmd);
- 		hostdata->pendingw++;
- 		break;
- 	    case READ:
- 	    case READ_6:
- 	    case READ_10:
- 		hostdata->time_read[cmd->device->id] -= (jiffies - hostdata->timebase);
--		hostdata->bytes_read[cmd->device->id] += cmd->request_bufflen;
-+		hostdata->bytes_read[cmd->device->id] += scsi_bufflen(cmd);
- 		hostdata->pendingr++;
- 		break;
- 	}
-@@ -1345,7 +1345,7 @@ static void collect_stats(struct NCR5380_hostdata *hostdata,
- 			  struct scsi_cmnd *cmd)
+-	error = gfs2_block_map(inode, lblock, 0, bh_result);
++	error = gfs2_block_map(inode, lblock, bh_result, 0);
+ 	if (error)
+ 		return error;
+ 	if (!buffer_mapped(bh_result))
+@@ -99,20 +84,19 @@ static int gfs2_get_block_noalloc(struct inode *inode, sector_t lblock,
+ static int gfs2_get_block_direct(struct inode *inode, sector_t lblock,
+ 				 struct buffer_head *bh_result, int create)
  {
- # ifdef NCR5380_STAT_LIMIT
--    if (cmd->request_bufflen > NCR5380_STAT_LIMIT)
-+    if (scsi_bufflen(cmd) > NCR5380_STAT_LIMIT)
- # endif
- 	switch (cmd->cmnd[0])
- 	{
-@@ -1353,14 +1353,14 @@ static void collect_stats(struct NCR5380_hostdata *hostdata,
- 	    case WRITE_6:
- 	    case WRITE_10:
- 		hostdata->time_write[cmd->device->id] += (jiffies - hostdata->timebase);
--		/*hostdata->bytes_write[cmd->device->id] += cmd->request_bufflen;*/
-+		/*hostdata->bytes_write[cmd->device->id] += scsi_bufflen(cmd);*/
- 		hostdata->pendingw--;
- 		break;
- 	    case READ:
- 	    case READ_6:
- 	    case READ_10:
- 		hostdata->time_read[cmd->device->id] += (jiffies - hostdata->timebase);
--		/*hostdata->bytes_read[cmd->device->id] += cmd->request_bufflen;*/
-+		/*hostdata->bytes_read[cmd->device->id] += scsi_bufflen(cmd);*/
- 		hostdata->pendingr--;
- 		break;
- 	}
-@@ -1863,7 +1863,7 @@ static int do_abort (struct Scsi_Host *host)
-      * the target sees, so we just handshake.
-      */
-     
--    while (!(tmp = NCR5380_read(STATUS_REG)) & SR_REQ);
-+    while (!((tmp = NCR5380_read(STATUS_REG)) & SR_REQ));
+-	return gfs2_block_map(inode, lblock, 0, bh_result);
++	return gfs2_block_map(inode, lblock, bh_result, 0);
+ }
  
-     NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp));
+ /**
+- * gfs2_writepage - Write complete page
+- * @page: Page to write
++ * gfs2_writepage_common - Common bits of writepage
++ * @page: The page to be written
++ * @wbc: The writeback control
+  *
+- * Returns: errno
+- *
+- * Some of this is copied from block_write_full_page() although we still
+- * call it to do most of the work.
++ * Returns: 1 if writepage is ok, otherwise an error code or zero if no error.
+  */
  
-diff --git a/drivers/scsi/sym53c416.c b/drivers/scsi/sym53c416.c
-index 90cee94..1f6fd16 100644
---- a/drivers/scsi/sym53c416.c
-+++ b/drivers/scsi/sym53c416.c
-@@ -328,27 +328,13 @@ static __inline__ unsigned int sym53c416_write(int base, unsigned char *buffer,
- static irqreturn_t sym53c416_intr_handle(int irq, void *dev_id)
+-static int gfs2_writepage(struct page *page, struct writeback_control *wbc)
++static int gfs2_writepage_common(struct page *page,
++				 struct writeback_control *wbc)
  {
- 	struct Scsi_Host *dev = dev_id;
--	int base = 0;
-+	int base = dev->io_port;
- 	int i;
- 	unsigned long flags = 0;
- 	unsigned char status_reg, pio_int_reg, int_reg;
- 	struct scatterlist *sg;
- 	unsigned int tot_trans = 0;
+ 	struct inode *inode = page->mapping->host;
+ 	struct gfs2_inode *ip = GFS2_I(inode);
+@@ -120,41 +104,133 @@ static int gfs2_writepage(struct page *page, struct writeback_control *wbc)
+ 	loff_t i_size = i_size_read(inode);
+ 	pgoff_t end_index = i_size >> PAGE_CACHE_SHIFT;
+ 	unsigned offset;
+-	int error;
+-	int done_trans = 0;
++	int ret = -EIO;
  
--	/* We search the base address of the host adapter which caused the interrupt */
--	/* FIXME: should pass dev_id sensibly as hosts[i] */
--	for(i = 0; i < host_index && !base; i++)
--		if(irq == hosts[i].irq)
--			base = hosts[i].base;
--	/* If no adapter found, we cannot handle the interrupt. Leave a message */
--	/* and continue. This should never happen...                            */
--	if(!base)
--	{
--		printk(KERN_ERR "sym53c416: No host adapter defined for interrupt %d\n", irq);
--		return IRQ_NONE;
+-	if (gfs2_assert_withdraw(sdp, gfs2_glock_is_held_excl(ip->i_gl))) {
+-		unlock_page(page);
+-		return -EIO;
 -	}
--	/* Now we have the base address and we can start handling the interrupt */
++	if (gfs2_assert_withdraw(sdp, gfs2_glock_is_held_excl(ip->i_gl)))
++		goto out;
++	ret = 0;
+ 	if (current->journal_info)
+-		goto out_ignore;
 -
- 	spin_lock_irqsave(dev->host_lock,flags);
- 	status_reg = inb(base + STATUS_REG);
- 	pio_int_reg = inb(base + PIO_INT_REG);
-diff --git a/drivers/scsi/sym53c8xx_2/sym_glue.c b/drivers/scsi/sym53c8xx_2/sym_glue.c
-index 9e0908d..21e926d 100644
---- a/drivers/scsi/sym53c8xx_2/sym_glue.c
-+++ b/drivers/scsi/sym53c8xx_2/sym_glue.c
-@@ -207,10 +207,9 @@ void sym_set_cam_result_error(struct sym_hcb *np, struct sym_ccb *cp, int resid)
- 			/*
- 			 *  Bounce back the sense data to user.
- 			 */
--			memset(&cmd->sense_buffer, 0, sizeof(cmd->sense_buffer));
-+			memset(&cmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
- 			memcpy(cmd->sense_buffer, cp->sns_bbuf,
--			      min(sizeof(cmd->sense_buffer),
--				  (size_t)SYM_SNS_BBUF_LEN));
-+			       min(SCSI_SENSE_BUFFERSIZE, SYM_SNS_BBUF_LEN));
- #if 0
- 			/*
- 			 *  If the device reports a UNIT ATTENTION condition 
-@@ -609,22 +608,24 @@ static int sym_eh_handler(int op, char *opname, struct scsi_cmnd *cmd)
- 	 */
- #define WAIT_FOR_PCI_RECOVERY	35
- 	if (pci_channel_offline(pdev)) {
--		struct completion *io_reset;
- 		int finished_reset = 0;
- 		init_completion(&eh_done);
- 		spin_lock_irq(shost->host_lock);
- 		/* Make sure we didn't race */
- 		if (pci_channel_offline(pdev)) {
--			if (!sym_data->io_reset)
--				sym_data->io_reset = &eh_done;
--			io_reset = sym_data->io_reset;
-+			BUG_ON(sym_data->io_reset);
-+			sym_data->io_reset = &eh_done;
- 		} else {
- 			finished_reset = 1;
- 		}
- 		spin_unlock_irq(shost->host_lock);
- 		if (!finished_reset)
--			finished_reset = wait_for_completion_timeout(io_reset,
-+			finished_reset = wait_for_completion_timeout
-+						(sym_data->io_reset,
- 						WAIT_FOR_PCI_RECOVERY*HZ);
-+		spin_lock_irq(shost->host_lock);
-+		sym_data->io_reset = NULL;
-+		spin_unlock_irq(shost->host_lock);
- 		if (!finished_reset)
- 			return SCSI_FAILED;
++		goto redirty;
+ 	/* Is the page fully outside i_size? (truncate in progress) */
+-        offset = i_size & (PAGE_CACHE_SIZE-1);
++	offset = i_size & (PAGE_CACHE_SIZE-1);
+ 	if (page->index > end_index || (page->index == end_index && !offset)) {
+ 		page->mapping->a_ops->invalidatepage(page, 0);
+-		unlock_page(page);
+-		return 0; /* don't care */
++		goto out;
++	}
++	return 1;
++redirty:
++	redirty_page_for_writepage(wbc, page);
++out:
++	unlock_page(page);
++	return 0;
++}
++
++/**
++ * gfs2_writeback_writepage - Write page for writeback mappings
++ * @page: The page
++ * @wbc: The writeback control
++ *
++ */
++
++static int gfs2_writeback_writepage(struct page *page,
++				    struct writeback_control *wbc)
++{
++	int ret;
++
++	ret = gfs2_writepage_common(page, wbc);
++	if (ret <= 0)
++		return ret;
++
++	ret = mpage_writepage(page, gfs2_get_block_noalloc, wbc);
++	if (ret == -EAGAIN)
++		ret = block_write_full_page(page, gfs2_get_block_noalloc, wbc);
++	return ret;
++}
++
++/**
++ * gfs2_ordered_writepage - Write page for ordered data files
++ * @page: The page to write
++ * @wbc: The writeback control
++ *
++ */
++
++static int gfs2_ordered_writepage(struct page *page,
++				  struct writeback_control *wbc)
++{
++	struct inode *inode = page->mapping->host;
++	struct gfs2_inode *ip = GFS2_I(inode);
++	int ret;
++
++	ret = gfs2_writepage_common(page, wbc);
++	if (ret <= 0)
++		return ret;
++
++	if (!page_has_buffers(page)) {
++		create_empty_buffers(page, inode->i_sb->s_blocksize,
++				     (1 << BH_Dirty)|(1 << BH_Uptodate));
  	}
-@@ -1744,7 +1745,7 @@ static int __devinit sym2_probe(struct pci_dev *pdev,
- 	return -ENODEV;
- }
++	gfs2_page_add_databufs(ip, page, 0, inode->i_sb->s_blocksize-1);
++	return block_write_full_page(page, gfs2_get_block_noalloc, wbc);
++}
  
--static void __devexit sym2_remove(struct pci_dev *pdev)
-+static void sym2_remove(struct pci_dev *pdev)
- {
- 	struct Scsi_Host *shost = pci_get_drvdata(pdev);
+-	if ((sdp->sd_args.ar_data == GFS2_DATA_ORDERED || gfs2_is_jdata(ip)) &&
+-	    PageChecked(page)) {
++/**
++ * __gfs2_jdata_writepage - The core of jdata writepage
++ * @page: The page to write
++ * @wbc: The writeback control
++ *
++ * This is shared between writepage and writepages and implements the
++ * core of the writepage operation. If a transaction is required then
++ * PageChecked will have been set and the transaction will have
++ * already been started before this is called.
++ */
++
++static int __gfs2_jdata_writepage(struct page *page, struct writeback_control *wbc)
++{
++	struct inode *inode = page->mapping->host;
++	struct gfs2_inode *ip = GFS2_I(inode);
++	struct gfs2_sbd *sdp = GFS2_SB(inode);
++
++	if (PageChecked(page)) {
+ 		ClearPageChecked(page);
+-		error = gfs2_trans_begin(sdp, RES_DINODE + 1, 0);
+-		if (error)
+-			goto out_ignore;
+ 		if (!page_has_buffers(page)) {
+ 			create_empty_buffers(page, inode->i_sb->s_blocksize,
+ 					     (1 << BH_Dirty)|(1 << BH_Uptodate));
+ 		}
+ 		gfs2_page_add_databufs(ip, page, 0, sdp->sd_vfs->s_blocksize-1);
++	}
++	return block_write_full_page(page, gfs2_get_block_noalloc, wbc);
++}
++
++/**
++ * gfs2_jdata_writepage - Write complete page
++ * @page: Page to write
++ *
++ * Returns: errno
++ *
++ */
++
++static int gfs2_jdata_writepage(struct page *page, struct writeback_control *wbc)
++{
++	struct inode *inode = page->mapping->host;
++	struct gfs2_sbd *sdp = GFS2_SB(inode);
++	int error;
++	int done_trans = 0;
++
++	error = gfs2_writepage_common(page, wbc);
++	if (error <= 0)
++		return error;
++
++	if (PageChecked(page)) {
++		if (wbc->sync_mode != WB_SYNC_ALL)
++			goto out_ignore;
++		error = gfs2_trans_begin(sdp, RES_DINODE + 1, 0);
++		if (error)
++			goto out_ignore;
+ 		done_trans = 1;
+ 	}
+-	error = block_write_full_page(page, gfs2_get_block_noalloc, wbc);
++	error = __gfs2_jdata_writepage(page, wbc);
+ 	if (done_trans)
+ 		gfs2_trans_end(sdp);
+-	gfs2_meta_cache_flush(ip);
+ 	return error;
  
-@@ -1879,7 +1880,6 @@ static void sym2_io_resume(struct pci_dev *pdev)
- 	spin_lock_irq(shost->host_lock);
- 	if (sym_data->io_reset)
- 		complete_all(sym_data->io_reset);
--	sym_data->io_reset = NULL;
- 	spin_unlock_irq(shost->host_lock);
+ out_ignore:
+@@ -164,29 +240,190 @@ out_ignore:
  }
  
-@@ -2056,7 +2056,7 @@ static struct pci_driver sym2_driver = {
- 	.name		= NAME53C8XX,
- 	.id_table	= sym2_id_table,
- 	.probe		= sym2_probe,
--	.remove		= __devexit_p(sym2_remove),
-+	.remove		= sym2_remove,
- 	.err_handler 	= &sym2_err_handler,
- };
+ /**
+- * gfs2_writepages - Write a bunch of dirty pages back to disk
++ * gfs2_writeback_writepages - Write a bunch of dirty pages back to disk
+  * @mapping: The mapping to write
+  * @wbc: Write-back control
+  *
+- * For journaled files and/or ordered writes this just falls back to the
+- * kernel's default writepages path for now. We will probably want to change
+- * that eventually (i.e. when we look at allocate on flush).
+- *
+- * For the data=writeback case though we can already ignore buffer heads
++ * For the data=writeback case we can already ignore buffer heads
+  * and write whole extents at once. This is a big reduction in the
+  * number of I/O requests we send and the bmap calls we make in this case.
+  */
+-static int gfs2_writepages(struct address_space *mapping,
+-			   struct writeback_control *wbc)
++static int gfs2_writeback_writepages(struct address_space *mapping,
++				     struct writeback_control *wbc)
++{
++	return mpage_writepages(mapping, wbc, gfs2_get_block_noalloc);
++}
++
++/**
++ * gfs2_write_jdata_pagevec - Write back a pagevec's worth of pages
++ * @mapping: The mapping
++ * @wbc: The writeback control
++ * @writepage: The writepage function to call for each page
++ * @pvec: The vector of pages
++ * @nr_pages: The number of pages to write
++ *
++ * Returns: non-zero if loop should terminate, zero otherwise
++ */
++
++static int gfs2_write_jdata_pagevec(struct address_space *mapping,
++				    struct writeback_control *wbc,
++				    struct pagevec *pvec,
++				    int nr_pages, pgoff_t end)
+ {
+ 	struct inode *inode = mapping->host;
+-	struct gfs2_inode *ip = GFS2_I(inode);
+ 	struct gfs2_sbd *sdp = GFS2_SB(inode);
++	loff_t i_size = i_size_read(inode);
++	pgoff_t end_index = i_size >> PAGE_CACHE_SHIFT;
++	unsigned offset = i_size & (PAGE_CACHE_SIZE-1);
++	unsigned nrblocks = nr_pages * (PAGE_CACHE_SIZE/inode->i_sb->s_blocksize);
++	struct backing_dev_info *bdi = mapping->backing_dev_info;
++	int i;
++	int ret;
++
++	ret = gfs2_trans_begin(sdp, nrblocks, 0);
++	if (ret < 0)
++		return ret;
++
++	for(i = 0; i < nr_pages; i++) {
++		struct page *page = pvec->pages[i];
++
++		lock_page(page);
++
++		if (unlikely(page->mapping != mapping)) {
++			unlock_page(page);
++			continue;
++		}
++
++		if (!wbc->range_cyclic && page->index > end) {
++			ret = 1;
++			unlock_page(page);
++			continue;
++		}
++
++		if (wbc->sync_mode != WB_SYNC_NONE)
++			wait_on_page_writeback(page);
++
++		if (PageWriteback(page) ||
++		    !clear_page_dirty_for_io(page)) {
++			unlock_page(page);
++			continue;
++		}
++
++		/* Is the page fully outside i_size? (truncate in progress) */
++		if (page->index > end_index || (page->index == end_index && !offset)) {
++			page->mapping->a_ops->invalidatepage(page, 0);
++			unlock_page(page);
++			continue;
++		}
++
++		ret = __gfs2_jdata_writepage(page, wbc);
++
++		if (ret || (--(wbc->nr_to_write) <= 0))
++			ret = 1;
++		if (wbc->nonblocking && bdi_write_congested(bdi)) {
++			wbc->encountered_congestion = 1;
++			ret = 1;
++		}
++
++	}
++	gfs2_trans_end(sdp);
++	return ret;
++}
++
++/**
++ * gfs2_write_cache_jdata - Like write_cache_pages but different
++ * @mapping: The mapping to write
++ * @wbc: The writeback control
++ * @writepage: The writepage function to call
++ * @data: The data to pass to writepage
++ *
++ * The reason that we use our own function here is that we need to
++ * start transactions before we grab page locks. This allows us
++ * to get the ordering right.
++ */
++
++static int gfs2_write_cache_jdata(struct address_space *mapping,
++				  struct writeback_control *wbc)
++{
++	struct backing_dev_info *bdi = mapping->backing_dev_info;
++	int ret = 0;
++	int done = 0;
++	struct pagevec pvec;
++	int nr_pages;
++	pgoff_t index;
++	pgoff_t end;
++	int scanned = 0;
++	int range_whole = 0;
++
++	if (wbc->nonblocking && bdi_write_congested(bdi)) {
++		wbc->encountered_congestion = 1;
++		return 0;
++	}
++
++	pagevec_init(&pvec, 0);
++	if (wbc->range_cyclic) {
++		index = mapping->writeback_index; /* Start from prev offset */
++		end = -1;
++	} else {
++		index = wbc->range_start >> PAGE_CACHE_SHIFT;
++		end = wbc->range_end >> PAGE_CACHE_SHIFT;
++		if (wbc->range_start == 0 && wbc->range_end == LLONG_MAX)
++			range_whole = 1;
++		scanned = 1;
++	}
  
-diff --git a/drivers/scsi/tmscsim.c b/drivers/scsi/tmscsim.c
-index 4419304..5b04ddf 100644
---- a/drivers/scsi/tmscsim.c
-+++ b/drivers/scsi/tmscsim.c
-@@ -444,7 +444,7 @@ static int dc390_pci_map (struct dc390_srb* pSRB)
+-	if (sdp->sd_args.ar_data == GFS2_DATA_WRITEBACK && !gfs2_is_jdata(ip))
+-		return mpage_writepages(mapping, wbc, gfs2_get_block_noalloc);
++retry:
++	 while (!done && (index <= end) &&
++		(nr_pages = pagevec_lookup_tag(&pvec, mapping, &index,
++					       PAGECACHE_TAG_DIRTY,
++					       min(end - index, (pgoff_t)PAGEVEC_SIZE-1) + 1))) {
++		scanned = 1;
++		ret = gfs2_write_jdata_pagevec(mapping, wbc, &pvec, nr_pages, end);
++		if (ret)
++			done = 1;
++		if (ret > 0)
++			ret = 0;
++
++		pagevec_release(&pvec);
++		cond_resched();
++	}
++
++	if (!scanned && !done) {
++		/*
++		 * We hit the last page and there is more work to be done: wrap
++		 * back to the start of the file
++		 */
++		scanned = 1;
++		index = 0;
++		goto retry;
++	}
++
++	if (wbc->range_cyclic || (range_whole && wbc->nr_to_write > 0))
++		mapping->writeback_index = index;
++	return ret;
++}
++
++
++/**
++ * gfs2_jdata_writepages - Write a bunch of dirty pages back to disk
++ * @mapping: The mapping to write
++ * @wbc: The writeback control
++ * 
++ */
  
- 	/* Map sense buffer */
- 	if (pSRB->SRBFlag & AUTO_REQSENSE) {
--		pSRB->pSegmentList	= dc390_sg_build_single(&pSRB->Segmentx, pcmd->sense_buffer, sizeof(pcmd->sense_buffer));
-+		pSRB->pSegmentList	= dc390_sg_build_single(&pSRB->Segmentx, pcmd->sense_buffer, SCSI_SENSE_BUFFERSIZE);
- 		pSRB->SGcount		= pci_map_sg(pdev, pSRB->pSegmentList, 1,
- 						     DMA_FROM_DEVICE);
- 		cmdp->saved_dma_handle	= sg_dma_address(pSRB->pSegmentList);
-@@ -599,7 +599,7 @@ dc390_StartSCSI( struct dc390_acb* pACB, struct dc390_dcb* pDCB, struct dc390_sr
- 	    DC390_write8 (ScsiFifo, pDCB->TargetLUN << 5);
- 	    DC390_write8 (ScsiFifo, 0);
- 	    DC390_write8 (ScsiFifo, 0);
--	    DC390_write8 (ScsiFifo, sizeof(scmd->sense_buffer));
-+	    DC390_write8 (ScsiFifo, SCSI_SENSE_BUFFERSIZE);
- 	    DC390_write8 (ScsiFifo, 0);
- 	    DEBUG1(printk (KERN_DEBUG "DC390: AutoReqSense !\n"));
- 	  }
-@@ -1389,7 +1389,7 @@ dc390_CommandPhase( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus
- 	DC390_write8 (ScsiFifo, pDCB->TargetLUN << 5);
- 	DC390_write8 (ScsiFifo, 0);
- 	DC390_write8 (ScsiFifo, 0);
--	DC390_write8 (ScsiFifo, sizeof(pSRB->pcmd->sense_buffer));
-+	DC390_write8 (ScsiFifo, SCSI_SENSE_BUFFERSIZE);
- 	DC390_write8 (ScsiFifo, 0);
- 	DEBUG0(printk(KERN_DEBUG "DC390: AutoReqSense (CmndPhase)!\n"));
-     }
-diff --git a/drivers/scsi/u14-34f.c b/drivers/scsi/u14-34f.c
-index 7edd6ce..4bc5407 100644
---- a/drivers/scsi/u14-34f.c
-+++ b/drivers/scsi/u14-34f.c
-@@ -1121,9 +1121,9 @@ static void map_dma(unsigned int i, unsigned int j) {
+-	return generic_writepages(mapping, wbc);
++static int gfs2_jdata_writepages(struct address_space *mapping,
++				 struct writeback_control *wbc)
++{
++	struct gfs2_inode *ip = GFS2_I(mapping->host);
++	struct gfs2_sbd *sdp = GFS2_SB(mapping->host);
++	int ret;
++
++	ret = gfs2_write_cache_jdata(mapping, wbc);
++	if (ret == 0 && wbc->sync_mode == WB_SYNC_ALL) {
++		gfs2_log_flush(sdp, ip->i_gl);
++		ret = gfs2_write_cache_jdata(mapping, wbc);
++	}
++	return ret;
+ }
  
-    if (SCpnt->sense_buffer)
-       cpp->sense_addr = H2DEV(pci_map_single(HD(j)->pdev, SCpnt->sense_buffer,
--                           sizeof SCpnt->sense_buffer, PCI_DMA_FROMDEVICE));
-+                           SCSI_SENSE_BUFFERSIZE, PCI_DMA_FROMDEVICE));
+ /**
+@@ -231,62 +468,107 @@ static int stuffed_readpage(struct gfs2_inode *ip, struct page *page)
  
--   cpp->sense_len = sizeof SCpnt->sense_buffer;
-+   cpp->sense_len = SCSI_SENSE_BUFFERSIZE;
  
-    if (scsi_bufflen(SCpnt)) {
- 	   count = scsi_dma_map(SCpnt);
-diff --git a/drivers/scsi/ultrastor.c b/drivers/scsi/ultrastor.c
-index 6d1f0ed..75eca6b 100644
---- a/drivers/scsi/ultrastor.c
-+++ b/drivers/scsi/ultrastor.c
-@@ -298,9 +298,16 @@ static inline int find_and_clear_bit_16(unsigned long *field)
+ /**
+- * gfs2_readpage - readpage with locking
+- * @file: The file to read a page for. N.B. This may be NULL if we are
+- * reading an internal file.
++ * __gfs2_readpage - readpage
++ * @file: The file to read a page for
+  * @page: The page to read
+  *
+- * Returns: errno
++ * This is the core of gfs2's readpage. Its used by the internal file
++ * reading code as in that case we already hold the glock. Also its
++ * called by gfs2_readpage() once the required lock has been granted.
++ *
+  */
+ 
+-static int gfs2_readpage(struct file *file, struct page *page)
++static int __gfs2_readpage(void *file, struct page *page)
  {
-   int rv;
+ 	struct gfs2_inode *ip = GFS2_I(page->mapping->host);
+ 	struct gfs2_sbd *sdp = GFS2_SB(page->mapping->host);
+-	struct gfs2_file *gf = NULL;
+-	struct gfs2_holder gh;
+ 	int error;
+-	int do_unlock = 0;
+-
+-	if (likely(file != &gfs2_internal_file_sentinel)) {
+-		if (file) {
+-			gf = file->private_data;
+-			if (test_bit(GFF_EXLOCK, &gf->f_flags))
+-				/* gfs2_sharewrite_fault has grabbed the ip->i_gl already */
+-				goto skip_lock;
+-		}
+-		gfs2_holder_init(ip->i_gl, LM_ST_SHARED, GL_ATIME|LM_FLAG_TRY_1CB, &gh);
+-		do_unlock = 1;
+-		error = gfs2_glock_nq_atime(&gh);
+-		if (unlikely(error))
+-			goto out_unlock;
+-	}
  
--  if (*field == 0) panic("No free mscp");
--  asm("xorl %0,%0\n0:\tbsfw %1,%w0\n\tbtr %0,%1\n\tjnc 0b"
--      : "=&r" (rv), "=m" (*field) : "1" (*field));
-+  if (*field == 0)
-+    panic("No free mscp");
+-skip_lock:
+ 	if (gfs2_is_stuffed(ip)) {
+ 		error = stuffed_readpage(ip, page);
+ 		unlock_page(page);
+-	} else
+-		error = mpage_readpage(page, gfs2_get_block);
++	} else {
++		error = mpage_readpage(page, gfs2_block_map);
++	}
+ 
+ 	if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
+-		error = -EIO;
++		return -EIO;
 +
-+  asm volatile (
-+	"xorl %0,%0\n\t"
-+	"0: bsfw %1,%w0\n\t"
-+	"btr %0,%1\n\t"
-+	"jnc 0b"
-+	: "=&r" (rv), "=m" (*field) :);
++	return error;
++}
 +
-   return rv;
++/**
++ * gfs2_readpage - read a page of a file
++ * @file: The file to read
++ * @page: The page of the file
++ *
++ * This deals with the locking required. We use a trylock in order to
++ * avoid the page lock / glock ordering problems returning AOP_TRUNCATED_PAGE
++ * in the event that we are unable to get the lock.
++ */
++
++static int gfs2_readpage(struct file *file, struct page *page)
++{
++	struct gfs2_inode *ip = GFS2_I(page->mapping->host);
++	struct gfs2_holder gh;
++	int error;
+ 
+-	if (do_unlock) {
+-		gfs2_glock_dq_m(1, &gh);
+-		gfs2_holder_uninit(&gh);
++	gfs2_holder_init(ip->i_gl, LM_ST_SHARED, GL_ATIME|LM_FLAG_TRY_1CB, &gh);
++	error = gfs2_glock_nq_atime(&gh);
++	if (unlikely(error)) {
++		unlock_page(page);
++		goto out;
+ 	}
++	error = __gfs2_readpage(file, page);
++	gfs2_glock_dq(&gh);
+ out:
+-	return error;
+-out_unlock:
+-	unlock_page(page);
++	gfs2_holder_uninit(&gh);
+ 	if (error == GLR_TRYFAILED) {
+-		error = AOP_TRUNCATED_PAGE;
+ 		yield();
++		return AOP_TRUNCATED_PAGE;
+ 	}
+-	if (do_unlock)
+-		gfs2_holder_uninit(&gh);
+-	goto out;
++	return error;
++}
++
++/**
++ * gfs2_internal_read - read an internal file
++ * @ip: The gfs2 inode
++ * @ra_state: The readahead state (or NULL for no readahead)
++ * @buf: The buffer to fill
++ * @pos: The file position
++ * @size: The amount to read
++ *
++ */
++
++int gfs2_internal_read(struct gfs2_inode *ip, struct file_ra_state *ra_state,
++                       char *buf, loff_t *pos, unsigned size)
++{
++	struct address_space *mapping = ip->i_inode.i_mapping;
++	unsigned long index = *pos / PAGE_CACHE_SIZE;
++	unsigned offset = *pos & (PAGE_CACHE_SIZE - 1);
++	unsigned copied = 0;
++	unsigned amt;
++	struct page *page;
++	void *p;
++
++	do {
++		amt = size - copied;
++		if (offset + size > PAGE_CACHE_SIZE)
++			amt = PAGE_CACHE_SIZE - offset;
++		page = read_cache_page(mapping, index, __gfs2_readpage, NULL);
++		if (IS_ERR(page))
++			return PTR_ERR(page);
++		p = kmap_atomic(page, KM_USER0);
++		memcpy(buf + copied, p + offset, amt);
++		kunmap_atomic(p, KM_USER0);
++		mark_page_accessed(page);
++		page_cache_release(page);
++		copied += amt;
++		index++;
++		offset = 0;
++	} while(copied < size);
++	(*pos) += size;
++	return size;
  }
  
-@@ -741,7 +748,7 @@ static int ultrastor_queuecommand(struct scsi_cmnd *SCpnt,
-     }
-     my_mscp->command_link = 0;		/*???*/
-     my_mscp->scsi_command_link_id = 0;	/*???*/
--    my_mscp->length_of_sense_byte = sizeof SCpnt->sense_buffer;
-+    my_mscp->length_of_sense_byte = SCSI_SENSE_BUFFERSIZE;
-     my_mscp->length_of_scsi_cdbs = SCpnt->cmd_len;
-     memcpy(my_mscp->scsi_cdbs, SCpnt->cmnd, my_mscp->length_of_scsi_cdbs);
-     my_mscp->adapter_status = 0;
-diff --git a/drivers/scsi/wd33c93.c b/drivers/scsi/wd33c93.c
-index fdbb92d..f286c37 100644
---- a/drivers/scsi/wd33c93.c
-+++ b/drivers/scsi/wd33c93.c
-@@ -407,16 +407,16 @@ wd33c93_queuecommand(struct scsi_cmnd *cmd,
-  *  - SCp.phase records this command's SRCID_ER bit setting
+ /**
+@@ -300,10 +582,9 @@ out_unlock:
+  *    Any I/O we ignore at this time will be done via readpage later.
+  * 2. We don't handle stuffed files here we let readpage do the honours.
+  * 3. mpage_readpages() does most of the heavy lifting in the common case.
+- * 4. gfs2_get_block() is relied upon to set BH_Boundary in the right places.
+- * 5. We use LM_FLAG_TRY_1CB here, effectively we then have lock-ahead as
+- *    well as read-ahead.
++ * 4. gfs2_block_map() is relied upon to set BH_Boundary in the right places.
   */
++
+ static int gfs2_readpages(struct file *file, struct address_space *mapping,
+ 			  struct list_head *pages, unsigned nr_pages)
+ {
+@@ -311,42 +592,20 @@ static int gfs2_readpages(struct file *file, struct address_space *mapping,
+ 	struct gfs2_inode *ip = GFS2_I(inode);
+ 	struct gfs2_sbd *sdp = GFS2_SB(inode);
+ 	struct gfs2_holder gh;
+-	int ret = 0;
+-	int do_unlock = 0;
++	int ret;
  
--	if (cmd->use_sg) {
--		cmd->SCp.buffer = (struct scatterlist *) cmd->request_buffer;
--		cmd->SCp.buffers_residual = cmd->use_sg - 1;
-+	if (scsi_bufflen(cmd)) {
-+		cmd->SCp.buffer = scsi_sglist(cmd);
-+		cmd->SCp.buffers_residual = scsi_sg_count(cmd) - 1;
- 		cmd->SCp.ptr = sg_virt(cmd->SCp.buffer);
- 		cmd->SCp.this_residual = cmd->SCp.buffer->length;
- 	} else {
- 		cmd->SCp.buffer = NULL;
- 		cmd->SCp.buffers_residual = 0;
--		cmd->SCp.ptr = (char *) cmd->request_buffer;
--		cmd->SCp.this_residual = cmd->request_bufflen;
-+		cmd->SCp.ptr = NULL;
-+		cmd->SCp.this_residual = 0;
- 	}
+-	if (likely(file != &gfs2_internal_file_sentinel)) {
+-		if (file) {
+-			struct gfs2_file *gf = file->private_data;
+-			if (test_bit(GFF_EXLOCK, &gf->f_flags))
+-				goto skip_lock;
+-		}
+-		gfs2_holder_init(ip->i_gl, LM_ST_SHARED,
+-				 LM_FLAG_TRY_1CB|GL_ATIME, &gh);
+-		do_unlock = 1;
+-		ret = gfs2_glock_nq_atime(&gh);
+-		if (ret == GLR_TRYFAILED)
+-			goto out_noerror;
+-		if (unlikely(ret))
+-			goto out_unlock;
+-	}
+-skip_lock:
++	gfs2_holder_init(ip->i_gl, LM_ST_SHARED, GL_ATIME, &gh);
++	ret = gfs2_glock_nq_atime(&gh);
++	if (unlikely(ret))
++		goto out_uninit;
+ 	if (!gfs2_is_stuffed(ip))
+-		ret = mpage_readpages(mapping, pages, nr_pages, gfs2_get_block);
+-
+-	if (do_unlock) {
+-		gfs2_glock_dq_m(1, &gh);
+-		gfs2_holder_uninit(&gh);
+-	}
+-out:
++		ret = mpage_readpages(mapping, pages, nr_pages, gfs2_block_map);
++	gfs2_glock_dq(&gh);
++out_uninit:
++	gfs2_holder_uninit(&gh);
+ 	if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
+ 		ret = -EIO;
+ 	return ret;
+-out_noerror:
+-	ret = 0;
+-out_unlock:
+-	if (do_unlock)
+-		gfs2_holder_uninit(&gh);
+-	goto out;
+ }
  
- /* WD docs state that at the conclusion of a "LEVEL2" command, the
-diff --git a/drivers/scsi/wd7000.c b/drivers/scsi/wd7000.c
-index 03cd44f..b4304ae 100644
---- a/drivers/scsi/wd7000.c
-+++ b/drivers/scsi/wd7000.c
-@@ -1108,13 +1108,10 @@ static int wd7000_queuecommand(struct scsi_cmnd *SCpnt,
- 	scb->host = host;
+ /**
+@@ -382,20 +641,11 @@ static int gfs2_write_begin(struct file *file, struct address_space *mapping,
+ 	if (unlikely(error))
+ 		goto out_uninit;
  
- 	nseg = scsi_sg_count(SCpnt);
--	if (nseg) {
-+	if (nseg > 1) {
- 		struct scatterlist *sg;
- 		unsigned i;
+-	error = -ENOMEM;
+-	page = __grab_cache_page(mapping, index);
+-	*pagep = page;
+-	if (!page)
+-		goto out_unlock;
+-
+ 	gfs2_write_calc_reserv(ip, len, &data_blocks, &ind_blocks);
+-
+ 	error = gfs2_write_alloc_required(ip, pos, len, &alloc_required);
+ 	if (error)
+-		goto out_putpage;
+-
++		goto out_unlock;
  
--		if (SCpnt->device->host->sg_tablesize == SG_NONE) {
--			panic("wd7000_queuecommand: scatter/gather not supported.\n");
--		}
- 		dprintk("Using scatter/gather with %d elements.\n", nseg);
+-	ip->i_alloc.al_requested = 0;
+ 	if (alloc_required) {
+ 		al = gfs2_alloc_get(ip);
  
- 		sgb = scb->sgb;
-@@ -1128,7 +1125,10 @@ static int wd7000_queuecommand(struct scsi_cmnd *SCpnt,
- 		}
- 	} else {
- 		scb->op = 0;
--		any2scsi(scb->dataptr, isa_virt_to_bus(scsi_sglist(SCpnt)));
-+		if (nseg) {
-+			struct scatterlist *sg = scsi_sglist(SCpnt);
-+			any2scsi(scb->dataptr, isa_page_to_bus(sg_page(sg)) + sg->offset);
+@@ -424,40 +674,47 @@ static int gfs2_write_begin(struct file *file, struct address_space *mapping,
+ 	if (error)
+ 		goto out_trans_fail;
+ 
++	error = -ENOMEM;
++	page = __grab_cache_page(mapping, index);
++	*pagep = page;
++	if (unlikely(!page))
++		goto out_endtrans;
++
+ 	if (gfs2_is_stuffed(ip)) {
++		error = 0;
+ 		if (pos + len > sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode)) {
+ 			error = gfs2_unstuff_dinode(ip, page);
+ 			if (error == 0)
+ 				goto prepare_write;
+-		} else if (!PageUptodate(page))
++		} else if (!PageUptodate(page)) {
+ 			error = stuffed_readpage(ip, page);
 +		}
- 		any2scsi(scb->maxlen, scsi_bufflen(SCpnt));
+ 		goto out;
  	}
  
-@@ -1524,7 +1524,7 @@ static __init int wd7000_detect(struct scsi_host_template *tpnt)
- 				 *  For boards before rev 6.0, scatter/gather isn't supported.
- 				 */
- 				if (host->rev1 < 6)
--					sh->sg_tablesize = SG_NONE;
-+					sh->sg_tablesize = 1;
- 
- 				present++;	/* count it */
- 
-diff --git a/drivers/serial/bfin_5xx.c b/drivers/serial/bfin_5xx.c
-index 6f475b6..ac2a3ef 100644
---- a/drivers/serial/bfin_5xx.c
-+++ b/drivers/serial/bfin_5xx.c
-@@ -442,7 +442,8 @@ static void bfin_serial_dma_tx_chars(struct bfin_serial_port *uart)
- 		set_bfin_dma_config(DIR_READ, DMA_FLOW_STOP,
- 			INTR_ON_BUF,
- 			DIMENSION_LINEAR,
--			DATA_SIZE_8));
-+			DATA_SIZE_8,
-+			DMA_SYNC_RESTART));
- 	set_dma_start_addr(uart->tx_dma_channel, (unsigned long)(xmit->buf+xmit->tail));
- 	set_dma_x_count(uart->tx_dma_channel, uart->tx_count);
- 	set_dma_x_modify(uart->tx_dma_channel, 1);
-@@ -689,7 +690,8 @@ static int bfin_serial_startup(struct uart_port *port)
- 	set_dma_config(uart->rx_dma_channel,
- 		set_bfin_dma_config(DIR_WRITE, DMA_FLOW_AUTO,
- 				INTR_ON_ROW, DIMENSION_2D,
--				DATA_SIZE_8));
-+				DATA_SIZE_8,
-+				DMA_SYNC_RESTART));
- 	set_dma_x_count(uart->rx_dma_channel, DMA_RX_XCOUNT);
- 	set_dma_x_modify(uart->rx_dma_channel, 1);
- 	set_dma_y_count(uart->rx_dma_channel, DMA_RX_YCOUNT);
-diff --git a/drivers/serial/icom.c b/drivers/serial/icom.c
-index 9d3105b..9c2df5c 100644
---- a/drivers/serial/icom.c
-+++ b/drivers/serial/icom.c
-@@ -48,7 +48,7 @@
- #include <linux/vmalloc.h>
- #include <linux/smp.h>
- #include <linux/spinlock.h>
--#include <linux/kobject.h>
-+#include <linux/kref.h>
- #include <linux/firmware.h>
- #include <linux/bitops.h>
- 
-@@ -65,7 +65,7 @@
- #define ICOM_VERSION_STR "1.3.1"
- #define NR_PORTS	       128
- #define ICOM_PORT ((struct icom_port *)port)
--#define to_icom_adapter(d) container_of(d, struct icom_adapter, kobj)
-+#define to_icom_adapter(d) container_of(d, struct icom_adapter, kref)
+ prepare_write:
+-	error = block_prepare_write(page, from, to, gfs2_get_block);
+-
++	error = block_prepare_write(page, from, to, gfs2_block_map);
+ out:
+-	if (error) {
+-		gfs2_trans_end(sdp);
++	if (error == 0)
++		return 0;
++
++	page_cache_release(page);
++	if (pos + len > ip->i_inode.i_size)
++		vmtruncate(&ip->i_inode, ip->i_inode.i_size);
++out_endtrans:
++	gfs2_trans_end(sdp);
+ out_trans_fail:
+-		if (alloc_required) {
+-			gfs2_inplace_release(ip);
++	if (alloc_required) {
++		gfs2_inplace_release(ip);
+ out_qunlock:
+-			gfs2_quota_unlock(ip);
++		gfs2_quota_unlock(ip);
+ out_alloc_put:
+-			gfs2_alloc_put(ip);
+-		}
+-out_putpage:
+-		page_cache_release(page);
+-		if (pos + len > ip->i_inode.i_size)
+-			vmtruncate(&ip->i_inode, ip->i_inode.i_size);
++		gfs2_alloc_put(ip);
++	}
+ out_unlock:
+-		gfs2_glock_dq_m(1, &ip->i_gh);
++	gfs2_glock_dq(&ip->i_gh);
+ out_uninit:
+-		gfs2_holder_uninit(&ip->i_gh);
+-	}
+-
++	gfs2_holder_uninit(&ip->i_gh);
+ 	return error;
+ }
  
- static const struct pci_device_id icom_pci_table[] = {
- 	{
-@@ -141,6 +141,7 @@ static inline void trace(struct icom_port *, char *, unsigned long) {};
- #else
- static inline void trace(struct icom_port *icom_port, char *trace_pt, unsigned long trace_data) {};
- #endif
-+static void icom_kref_release(struct kref *kref);
+@@ -565,7 +822,7 @@ static int gfs2_write_end(struct file *file, struct address_space *mapping,
+ 	struct gfs2_inode *ip = GFS2_I(inode);
+ 	struct gfs2_sbd *sdp = GFS2_SB(inode);
+ 	struct buffer_head *dibh;
+-	struct gfs2_alloc *al = &ip->i_alloc;
++	struct gfs2_alloc *al = ip->i_alloc;
+ 	struct gfs2_dinode *di;
+ 	unsigned int from = pos & (PAGE_CACHE_SIZE - 1);
+ 	unsigned int to = from + len;
+@@ -585,19 +842,16 @@ static int gfs2_write_end(struct file *file, struct address_space *mapping,
+ 	if (gfs2_is_stuffed(ip))
+ 		return gfs2_stuffed_write_end(inode, dibh, pos, len, copied, page);
  
- static void free_port_memory(struct icom_port *icom_port)
- {
-@@ -1063,11 +1064,11 @@ static int icom_open(struct uart_port *port)
- {
- 	int retval;
+-	if (sdp->sd_args.ar_data == GFS2_DATA_ORDERED || gfs2_is_jdata(ip))
++	if (!gfs2_is_writeback(ip))
+ 		gfs2_page_add_databufs(ip, page, from, to);
  
--	kobject_get(&ICOM_PORT->adapter->kobj);
-+	kref_get(&ICOM_PORT->adapter->kref);
- 	retval = startup(ICOM_PORT);
+ 	ret = generic_write_end(file, mapping, pos, len, copied, page, fsdata);
  
- 	if (retval) {
--		kobject_put(&ICOM_PORT->adapter->kobj);
-+		kref_put(&ICOM_PORT->adapter->kref, icom_kref_release);
- 		trace(ICOM_PORT, "STARTUP_ERROR", 0);
- 		return retval;
+-	if (likely(ret >= 0)) {
+-		copied = ret;
+-		if  ((pos + copied) > inode->i_size) {
+-			di = (struct gfs2_dinode *)dibh->b_data;
+-			ip->i_di.di_size = inode->i_size;
+-			di->di_size = cpu_to_be64(inode->i_size);
+-			mark_inode_dirty(inode);
+-		}
++	if (likely(ret >= 0) && (inode->i_size > ip->i_di.di_size)) {
++		di = (struct gfs2_dinode *)dibh->b_data;
++		ip->i_di.di_size = inode->i_size;
++		di->di_size = cpu_to_be64(inode->i_size);
++		mark_inode_dirty(inode);
  	}
-@@ -1088,7 +1089,7 @@ static void icom_close(struct uart_port *port)
- 
- 	shutdown(ICOM_PORT);
  
--	kobject_put(&ICOM_PORT->adapter->kobj);
-+	kref_put(&ICOM_PORT->adapter->kref, icom_kref_release);
+ 	if (inode == sdp->sd_rindex)
+@@ -606,7 +860,7 @@ static int gfs2_write_end(struct file *file, struct address_space *mapping,
+ 	brelse(dibh);
+ 	gfs2_trans_end(sdp);
+ failed:
+-	if (al->al_requested) {
++	if (al) {
+ 		gfs2_inplace_release(ip);
+ 		gfs2_quota_unlock(ip);
+ 		gfs2_alloc_put(ip);
+@@ -625,11 +879,7 @@ failed:
+  
+ static int gfs2_set_page_dirty(struct page *page)
+ {
+-	struct gfs2_inode *ip = GFS2_I(page->mapping->host);
+-	struct gfs2_sbd *sdp = GFS2_SB(page->mapping->host);
+-
+-	if (sdp->sd_args.ar_data == GFS2_DATA_ORDERED || gfs2_is_jdata(ip))
+-		SetPageChecked(page);
++	SetPageChecked(page);
+ 	return __set_page_dirty_buffers(page);
  }
  
- static void icom_set_termios(struct uart_port *port,
-@@ -1485,18 +1486,14 @@ static void icom_remove_adapter(struct icom_adapter *icom_adapter)
- 	pci_release_regions(icom_adapter->pci_dev);
- }
+@@ -653,7 +903,7 @@ static sector_t gfs2_bmap(struct address_space *mapping, sector_t lblock)
+ 		return 0;
  
--static void icom_kobj_release(struct kobject *kobj)
-+static void icom_kref_release(struct kref *kref)
- {
- 	struct icom_adapter *icom_adapter;
+ 	if (!gfs2_is_stuffed(ip))
+-		dblock = generic_block_bmap(mapping, lblock, gfs2_get_block);
++		dblock = generic_block_bmap(mapping, lblock, gfs2_block_map);
  
--	icom_adapter = to_icom_adapter(kobj);
-+	icom_adapter = to_icom_adapter(kref);
- 	icom_remove_adapter(icom_adapter);
- }
+ 	gfs2_glock_dq_uninit(&i_gh);
  
--static struct kobj_type icom_kobj_type = {
--	.release = icom_kobj_release,
--};
--
- static int __devinit icom_probe(struct pci_dev *dev,
- 				const struct pci_device_id *ent)
+@@ -719,13 +969,9 @@ static int gfs2_ok_for_dio(struct gfs2_inode *ip, int rw, loff_t offset)
  {
-@@ -1592,8 +1589,7 @@ static int __devinit icom_probe(struct pci_dev *dev,
- 		}
- 	}
+ 	/*
+ 	 * Should we return an error here? I can't see that O_DIRECT for
+-	 * a journaled file makes any sense. For now we'll silently fall
+-	 * back to buffered I/O, likewise we do the same for stuffed
+-	 * files since they are (a) small and (b) unaligned.
++	 * a stuffed file makes any sense. For now we'll silently fall
++	 * back to buffered I/O
+ 	 */
+-	if (gfs2_is_jdata(ip))
+-		return 0;
+-
+ 	if (gfs2_is_stuffed(ip))
+ 		return 0;
  
--	kobject_init(&icom_adapter->kobj);
--	icom_adapter->kobj.ktype = &icom_kobj_type;
-+	kref_init(&icom_adapter->kref);
+@@ -836,9 +1082,23 @@ cannot_release:
  	return 0;
+ }
  
- probe_exit2:
-@@ -1619,7 +1615,7 @@ static void __devexit icom_remove(struct pci_dev *dev)
- 		icom_adapter = list_entry(tmp, struct icom_adapter,
- 					  icom_adapter_entry);
- 		if (icom_adapter->pci_dev == dev) {
--			kobject_put(&icom_adapter->kobj);
-+			kref_put(&icom_adapter->kref, icom_kref_release);
- 			return;
- 		}
- 	}
-diff --git a/drivers/serial/icom.h b/drivers/serial/icom.h
-index e8578d8..0274554 100644
---- a/drivers/serial/icom.h
-+++ b/drivers/serial/icom.h
-@@ -270,7 +270,7 @@ struct icom_adapter {
- #define V2_ONE_PORT_RVX_ONE_PORT_IMBED_MDM	0x0251
- 	int numb_ports;
- 	struct list_head icom_adapter_entry;
--	struct kobject kobj;
-+	struct kref kref;
+-const struct address_space_operations gfs2_file_aops = {
+-	.writepage = gfs2_writepage,
+-	.writepages = gfs2_writepages,
++static const struct address_space_operations gfs2_writeback_aops = {
++	.writepage = gfs2_writeback_writepage,
++	.writepages = gfs2_writeback_writepages,
++	.readpage = gfs2_readpage,
++	.readpages = gfs2_readpages,
++	.sync_page = block_sync_page,
++	.write_begin = gfs2_write_begin,
++	.write_end = gfs2_write_end,
++	.bmap = gfs2_bmap,
++	.invalidatepage = gfs2_invalidatepage,
++	.releasepage = gfs2_releasepage,
++	.direct_IO = gfs2_direct_IO,
++	.migratepage = buffer_migrate_page,
++};
++
++static const struct address_space_operations gfs2_ordered_aops = {
++	.writepage = gfs2_ordered_writepage,
+ 	.readpage = gfs2_readpage,
+ 	.readpages = gfs2_readpages,
+ 	.sync_page = block_sync_page,
+@@ -849,5 +1109,34 @@ const struct address_space_operations gfs2_file_aops = {
+ 	.invalidatepage = gfs2_invalidatepage,
+ 	.releasepage = gfs2_releasepage,
+ 	.direct_IO = gfs2_direct_IO,
++	.migratepage = buffer_migrate_page,
  };
  
- /* prototype */
-diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
-index 93e9de4..682a6a4 100644
---- a/drivers/spi/spi.c
-+++ b/drivers/spi/spi.c
-@@ -485,6 +485,15 @@ void spi_unregister_master(struct spi_master *master)
- }
- EXPORT_SYMBOL_GPL(spi_unregister_master);
- 
-+static int __spi_master_match(struct device *dev, void *data)
++static const struct address_space_operations gfs2_jdata_aops = {
++	.writepage = gfs2_jdata_writepage,
++	.writepages = gfs2_jdata_writepages,
++	.readpage = gfs2_readpage,
++	.readpages = gfs2_readpages,
++	.sync_page = block_sync_page,
++	.write_begin = gfs2_write_begin,
++	.write_end = gfs2_write_end,
++	.set_page_dirty = gfs2_set_page_dirty,
++	.bmap = gfs2_bmap,
++	.invalidatepage = gfs2_invalidatepage,
++	.releasepage = gfs2_releasepage,
++};
++
++void gfs2_set_aops(struct inode *inode)
 +{
-+	struct spi_master *m;
-+	u16 *bus_num = data;
++	struct gfs2_inode *ip = GFS2_I(inode);
 +
-+	m = container_of(dev, struct spi_master, dev);
-+	return m->bus_num == *bus_num;
++	if (gfs2_is_writeback(ip))
++		inode->i_mapping->a_ops = &gfs2_writeback_aops;
++	else if (gfs2_is_ordered(ip))
++		inode->i_mapping->a_ops = &gfs2_ordered_aops;
++	else if (gfs2_is_jdata(ip))
++		inode->i_mapping->a_ops = &gfs2_jdata_aops;
++	else
++		BUG();
 +}
 +
- /**
-  * spi_busnum_to_master - look up master associated with bus_num
-  * @bus_num: the master's bus number
-@@ -499,17 +508,12 @@ struct spi_master *spi_busnum_to_master(u16 bus_num)
- {
- 	struct device		*dev;
- 	struct spi_master	*master = NULL;
--	struct spi_master	*m;
--
--	down(&spi_master_class.sem);
--	list_for_each_entry(dev, &spi_master_class.children, node) {
--		m = container_of(dev, struct spi_master, dev);
--		if (m->bus_num == bus_num) {
--			master = spi_master_get(m);
--			break;
--		}
--	}
--	up(&spi_master_class.sem);
-+
-+	dev = class_find_device(&spi_master_class, &bus_num,
-+				__spi_master_match);
-+	if (dev)
-+		master = container_of(dev, struct spi_master, dev);
-+	/* reference got in class_find_device */
- 	return master;
- }
- EXPORT_SYMBOL_GPL(spi_busnum_to_master);
-diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c
-index 865f32b..cc246fa 100644
---- a/drivers/uio/uio.c
-+++ b/drivers/uio/uio.c
-@@ -34,12 +34,12 @@ struct uio_device {
- 	wait_queue_head_t	wait;
- 	int			vma_count;
- 	struct uio_info		*info;
--	struct kset 		map_attr_kset;
-+	struct kobject		*map_dir;
- };
- 
- static int uio_major;
- static DEFINE_IDR(uio_idr);
--static struct file_operations uio_fops;
-+static const struct file_operations uio_fops;
- 
- /* UIO class infrastructure */
- static struct uio_class {
-@@ -51,47 +51,48 @@ static struct uio_class {
-  * attributes
-  */
- 
--static struct attribute attr_addr = {
--	.name  = "addr",
--	.mode  = S_IRUGO,
-+struct uio_map {
-+	struct kobject kobj;
-+	struct uio_mem *mem;
- };
-+#define to_map(map) container_of(map, struct uio_map, kobj)
+diff --git a/fs/gfs2/ops_address.h b/fs/gfs2/ops_address.h
+index fa1b5b3..5da2128 100644
+--- a/fs/gfs2/ops_address.h
++++ b/fs/gfs2/ops_address.h
+@@ -14,9 +14,10 @@
+ #include <linux/buffer_head.h>
+ #include <linux/mm.h>
  
--static struct attribute attr_size = {
--	.name  = "size",
--	.mode  = S_IRUGO,
--};
+-extern const struct address_space_operations gfs2_file_aops;
+-extern int gfs2_get_block(struct inode *inode, sector_t lblock,
+-			  struct buffer_head *bh_result, int create);
+ extern int gfs2_releasepage(struct page *page, gfp_t gfp_mask);
++extern int gfs2_internal_read(struct gfs2_inode *ip,
++			      struct file_ra_state *ra_state,
++			      char *buf, loff_t *pos, unsigned size);
++extern void gfs2_set_aops(struct inode *inode);
  
--static struct attribute* map_attrs[] = {
--	&attr_addr, &attr_size, NULL
+ #endif /* __OPS_ADDRESS_DOT_H__ */
+diff --git a/fs/gfs2/ops_file.c b/fs/gfs2/ops_file.c
+index bb11fd6..f4842f2 100644
+--- a/fs/gfs2/ops_file.c
++++ b/fs/gfs2/ops_file.c
+@@ -33,57 +33,12 @@
+ #include "lm.h"
+ #include "log.h"
+ #include "meta_io.h"
+-#include "ops_file.h"
+-#include "ops_vm.h"
+ #include "quota.h"
+ #include "rgrp.h"
+ #include "trans.h"
+ #include "util.h"
+ #include "eaops.h"
+-
+-/*
+- * Most fields left uninitialised to catch anybody who tries to
+- * use them. f_flags set to prevent file_accessed() from touching
+- * any other part of this. Its use is purely as a flag so that we
+- * know (in readpage()) whether or not do to locking.
+- */
+-struct file gfs2_internal_file_sentinel = {
+-	.f_flags = O_NOATIME|O_RDONLY,
 -};
 -
--static ssize_t map_attr_show(struct kobject *kobj, struct attribute *attr,
-+static ssize_t map_attr_show(struct kobject *kobj, struct kobj_attribute *attr,
- 			     char *buf)
- {
--	struct uio_mem *mem = container_of(kobj, struct uio_mem, kobj);
-+	struct uio_map *map = to_map(kobj);
-+	struct uio_mem *mem = map->mem;
- 
--	if (strncmp(attr->name,"addr",4) == 0)
-+	if (strncmp(attr->attr.name, "addr", 4) == 0)
- 		return sprintf(buf, "0x%lx\n", mem->addr);
- 
--	if (strncmp(attr->name,"size",4) == 0)
-+	if (strncmp(attr->attr.name, "size", 4) == 0)
- 		return sprintf(buf, "0x%lx\n", mem->size);
- 
- 	return -ENODEV;
- }
- 
--static void map_attr_release(struct kobject *kobj)
+-static int gfs2_read_actor(read_descriptor_t *desc, struct page *page,
+-			   unsigned long offset, unsigned long size)
 -{
--	/* TODO ??? */
+-	char *kaddr;
+-	unsigned long count = desc->count;
+-
+-	if (size > count)
+-		size = count;
+-
+-	kaddr = kmap(page);
+-	memcpy(desc->arg.data, kaddr + offset, size);
+-	kunmap(page);
+-
+-	desc->count = count - size;
+-	desc->written += size;
+-	desc->arg.buf += size;
+-	return size;
 -}
-+static struct kobj_attribute attr_attribute =
-+	__ATTR(addr, S_IRUGO, map_attr_show, NULL);
-+static struct kobj_attribute size_attribute =
-+	__ATTR(size, S_IRUGO, map_attr_show, NULL);
+-
+-int gfs2_internal_read(struct gfs2_inode *ip, struct file_ra_state *ra_state,
+-		       char *buf, loff_t *pos, unsigned size)
+-{
+-	struct inode *inode = &ip->i_inode;
+-	read_descriptor_t desc;
+-	desc.written = 0;
+-	desc.arg.data = buf;
+-	desc.count = size;
+-	desc.error = 0;
+-	do_generic_mapping_read(inode->i_mapping, ra_state,
+-				&gfs2_internal_file_sentinel, pos, &desc,
+-				gfs2_read_actor);
+-	return desc.written ? desc.written : desc.error;
+-}
++#include "ops_address.h"
  
--static struct sysfs_ops map_attr_ops = {
--	.show  = map_attr_show,
-+static struct attribute *attrs[] = {
-+	&attr_attribute.attr,
-+	&size_attribute.attr,
-+	NULL,	/* need to NULL terminate the list of attributes */
- };
+ /**
+  * gfs2_llseek - seek to a location in a file
+@@ -214,7 +169,7 @@ static int gfs2_get_flags(struct file *filp, u32 __user *ptr)
+ 	if (put_user(fsflags, ptr))
+ 		error = -EFAULT;
  
-+static void map_release(struct kobject *kobj)
+-	gfs2_glock_dq_m(1, &gh);
++	gfs2_glock_dq(&gh);
+ 	gfs2_holder_uninit(&gh);
+ 	return error;
+ }
+@@ -291,7 +246,16 @@ static int do_gfs2_set_flags(struct file *filp, u32 reqflags, u32 mask)
+ 		if (error)
+ 			goto out;
+ 	}
+-
++	if ((flags ^ new_flags) & GFS2_DIF_JDATA) {
++		if (flags & GFS2_DIF_JDATA)
++			gfs2_log_flush(sdp, ip->i_gl);
++		error = filemap_fdatawrite(inode->i_mapping);
++		if (error)
++			goto out;
++		error = filemap_fdatawait(inode->i_mapping);
++		if (error)
++			goto out;
++	}
+ 	error = gfs2_trans_begin(sdp, RES_DINODE, 0);
+ 	if (error)
+ 		goto out;
+@@ -303,6 +267,7 @@ static int do_gfs2_set_flags(struct file *filp, u32 reqflags, u32 mask)
+ 	gfs2_dinode_out(ip, bh->b_data);
+ 	brelse(bh);
+ 	gfs2_set_inode_flags(inode);
++	gfs2_set_aops(inode);
+ out_trans_end:
+ 	gfs2_trans_end(sdp);
+ out:
+@@ -338,6 +303,128 @@ static long gfs2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+ 	return -ENOTTY;
+ }
+ 
++/**
++ * gfs2_allocate_page_backing - Use bmap to allocate blocks
++ * @page: The (locked) page to allocate backing for
++ *
++ * We try to allocate all the blocks required for the page in
++ * one go. This might fail for various reasons, so we keep
++ * trying until all the blocks to back this page are allocated.
++ * If some of the blocks are already allocated, thats ok too.
++ */
++
++static int gfs2_allocate_page_backing(struct page *page)
 +{
-+	struct uio_map *map = to_map(kobj);
-+	kfree(map);
++	struct inode *inode = page->mapping->host;
++	struct buffer_head bh;
++	unsigned long size = PAGE_CACHE_SIZE;
++	u64 lblock = page->index << (PAGE_CACHE_SHIFT - inode->i_blkbits);
++
++	do {
++		bh.b_state = 0;
++		bh.b_size = size;
++		gfs2_block_map(inode, lblock, &bh, 1);
++		if (!buffer_mapped(&bh))
++			return -EIO;
++		size -= bh.b_size;
++		lblock += (bh.b_size >> inode->i_blkbits);
++	} while(size > 0);
++	return 0;
 +}
 +
- static struct kobj_type map_attr_type = {
--	.release	= map_attr_release,
--	.sysfs_ops	= &map_attr_ops,
--	.default_attrs	= map_attrs,
-+	.release	= map_release,
-+	.default_attrs	= attrs,
- };
- 
- static ssize_t show_name(struct device *dev,
-@@ -148,6 +149,7 @@ static int uio_dev_add_attributes(struct uio_device *idev)
- 	int mi;
- 	int map_found = 0;
- 	struct uio_mem *mem;
-+	struct uio_map *map;
- 
- 	ret = sysfs_create_group(&idev->dev->kobj, &uio_attr_grp);
- 	if (ret)
-@@ -159,31 +161,34 @@ static int uio_dev_add_attributes(struct uio_device *idev)
- 			break;
- 		if (!map_found) {
- 			map_found = 1;
--			kobject_set_name(&idev->map_attr_kset.kobj,"maps");
--			idev->map_attr_kset.ktype = &map_attr_type;
--			idev->map_attr_kset.kobj.parent = &idev->dev->kobj;
--			ret = kset_register(&idev->map_attr_kset);
--			if (ret)
--				goto err_remove_group;
-+			idev->map_dir = kobject_create_and_add("maps",
-+							&idev->dev->kobj);
-+			if (!idev->map_dir)
-+				goto err;
- 		}
--		kobject_init(&mem->kobj);
--		kobject_set_name(&mem->kobj,"map%d",mi);
--		mem->kobj.parent = &idev->map_attr_kset.kobj;
--		mem->kobj.kset = &idev->map_attr_kset;
--		ret = kobject_add(&mem->kobj);
-+		map = kzalloc(sizeof(*map), GFP_KERNEL);
-+		if (!map)
-+			goto err;
-+		kobject_init(&map->kobj, &map_attr_type);
-+		map->mem = mem;
-+		mem->map = map;
-+		ret = kobject_add(&map->kobj, idev->map_dir, "map%d", mi);
++/**
++ * gfs2_page_mkwrite - Make a shared, mmap()ed, page writable
++ * @vma: The virtual memory area
++ * @page: The page which is about to become writable
++ *
++ * When the page becomes writable, we need to ensure that we have
++ * blocks allocated on disk to back that page.
++ */
++
++static int gfs2_page_mkwrite(struct vm_area_struct *vma, struct page *page)
++{
++	struct inode *inode = vma->vm_file->f_path.dentry->d_inode;
++	struct gfs2_inode *ip = GFS2_I(inode);
++	struct gfs2_sbd *sdp = GFS2_SB(inode);
++	unsigned long last_index;
++	u64 pos = page->index << (PAGE_CACHE_SIZE - inode->i_blkbits);
++	unsigned int data_blocks, ind_blocks, rblocks;
++	int alloc_required = 0;
++	struct gfs2_holder gh;
++	struct gfs2_alloc *al;
++	int ret;
++
++	gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, GL_ATIME, &gh);
++	ret = gfs2_glock_nq_atime(&gh);
++	if (ret)
++		goto out;
++
++	set_bit(GIF_SW_PAGED, &ip->i_flags);
++	gfs2_write_calc_reserv(ip, PAGE_CACHE_SIZE, &data_blocks, &ind_blocks);
++	ret = gfs2_write_alloc_required(ip, pos, PAGE_CACHE_SIZE, &alloc_required);
++	if (ret || !alloc_required)
++		goto out_unlock;
++	ret = -ENOMEM;
++	al = gfs2_alloc_get(ip);
++	if (al == NULL)
++		goto out_unlock;
++
++	ret = gfs2_quota_lock(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE);
++	if (ret)
++		goto out_alloc_put;
++	ret = gfs2_quota_check(ip, ip->i_inode.i_uid, ip->i_inode.i_gid);
++	if (ret)
++		goto out_quota_unlock;
++	al->al_requested = data_blocks + ind_blocks;
++	ret = gfs2_inplace_reserve(ip);
++	if (ret)
++		goto out_quota_unlock;
++
++	rblocks = RES_DINODE + ind_blocks;
++	if (gfs2_is_jdata(ip))
++		rblocks += data_blocks ? data_blocks : 1;
++	if (ind_blocks || data_blocks)
++		rblocks += RES_STATFS + RES_QUOTA;
++	ret = gfs2_trans_begin(sdp, rblocks, 0);
++	if (ret)
++		goto out_trans_fail;
++
++	lock_page(page);
++	ret = -EINVAL;
++	last_index = ip->i_inode.i_size >> PAGE_CACHE_SHIFT;
++	if (page->index > last_index)
++		goto out_unlock_page;
++	ret = 0;
++	if (!PageUptodate(page) || page->mapping != ip->i_inode.i_mapping)
++		goto out_unlock_page;
++	if (gfs2_is_stuffed(ip)) {
++		ret = gfs2_unstuff_dinode(ip, page);
 +		if (ret)
-+			goto err;
-+		ret = kobject_uevent(&map->kobj, KOBJ_ADD);
- 		if (ret)
--			goto err_remove_maps;
-+			goto err;
- 	}
- 
- 	return 0;
- 
--err_remove_maps:
-+err:
- 	for (mi--; mi>=0; mi--) {
- 		mem = &idev->info->mem[mi];
--		kobject_unregister(&mem->kobj);
-+		map = mem->map;
-+		kobject_put(&map->kobj);
- 	}
--	kset_unregister(&idev->map_attr_kset); /* Needed ? */
--err_remove_group:
-+	kobject_put(idev->map_dir);
- 	sysfs_remove_group(&idev->dev->kobj, &uio_attr_grp);
- err_group:
- 	dev_err(idev->dev, "error creating sysfs files (%d)\n", ret);
-@@ -198,9 +203,9 @@ static void uio_dev_del_attributes(struct uio_device *idev)
- 		mem = &idev->info->mem[mi];
- 		if (mem->size == 0)
- 			break;
--		kobject_unregister(&mem->kobj);
-+		kobject_put(&mem->map->kobj);
- 	}
--	kset_unregister(&idev->map_attr_kset);
-+	kobject_put(idev->map_dir);
- 	sysfs_remove_group(&idev->dev->kobj, &uio_attr_grp);
- }
++			goto out_unlock_page;
++	}
++	ret = gfs2_allocate_page_backing(page);
++
++out_unlock_page:
++	unlock_page(page);
++	gfs2_trans_end(sdp);
++out_trans_fail:
++	gfs2_inplace_release(ip);
++out_quota_unlock:
++	gfs2_quota_unlock(ip);
++out_alloc_put:
++	gfs2_alloc_put(ip);
++out_unlock:
++	gfs2_glock_dq(&gh);
++out:
++	gfs2_holder_uninit(&gh);
++	return ret;
++}
++
++static struct vm_operations_struct gfs2_vm_ops = {
++	.fault = filemap_fault,
++	.page_mkwrite = gfs2_page_mkwrite,
++};
++
  
-@@ -503,7 +508,7 @@ static int uio_mmap(struct file *filep, struct vm_area_struct *vma)
+ /**
+  * gfs2_mmap -
+@@ -360,14 +447,7 @@ static int gfs2_mmap(struct file *file, struct vm_area_struct *vma)
+ 		return error;
  	}
- }
- 
--static struct file_operations uio_fops = {
-+static const struct file_operations uio_fops = {
- 	.owner		= THIS_MODULE,
- 	.open		= uio_open,
- 	.release	= uio_release,
-diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
-index c51f8e9..7c3aaa9 100644
---- a/drivers/usb/core/driver.c
-+++ b/drivers/usb/core/driver.c
-@@ -91,8 +91,8 @@ static int usb_create_newid_file(struct usb_driver *usb_drv)
- 		goto exit;
- 
- 	if (usb_drv->probe != NULL)
--		error = sysfs_create_file(&usb_drv->drvwrap.driver.kobj,
--					  &driver_attr_new_id.attr);
-+		error = driver_create_file(&usb_drv->drvwrap.driver,
-+					   &driver_attr_new_id);
- exit:
- 	return error;
- }
-@@ -103,8 +103,8 @@ static void usb_remove_newid_file(struct usb_driver *usb_drv)
- 		return;
  
- 	if (usb_drv->probe != NULL)
--		sysfs_remove_file(&usb_drv->drvwrap.driver.kobj,
--				  &driver_attr_new_id.attr);
-+		driver_remove_file(&usb_drv->drvwrap.driver,
-+				   &driver_attr_new_id);
- }
+-	/* This is VM_MAYWRITE instead of VM_WRITE because a call
+-	   to mprotect() can turn on VM_WRITE later. */
+-
+-	if ((vma->vm_flags & (VM_MAYSHARE | VM_MAYWRITE)) ==
+-	    (VM_MAYSHARE | VM_MAYWRITE))
+-		vma->vm_ops = &gfs2_vm_ops_sharewrite;
+-	else
+-		vma->vm_ops = &gfs2_vm_ops_private;
++	vma->vm_ops = &gfs2_vm_ops;
  
- static void usb_free_dynids(struct usb_driver *usb_drv)
-diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c
-index 5cfa3d1..74e1f4b 100644
---- a/drivers/usb/host/ohci-omap.c
-+++ b/drivers/usb/host/ohci-omap.c
-@@ -47,7 +47,7 @@
- #endif
+ 	gfs2_glock_dq_uninit(&i_gh);
  
- #ifdef CONFIG_TPS65010
--#include <asm/arch/tps65010.h>
-+#include <linux/i2c/tps65010.h>
- #else
+@@ -538,15 +618,6 @@ static int gfs2_lock(struct file *file, int cmd, struct file_lock *fl)
+ 	if (__mandatory_lock(&ip->i_inode))
+ 		return -ENOLCK;
  
- #define LOW	0
-diff --git a/drivers/usb/host/ohci-pnx4008.c b/drivers/usb/host/ohci-pnx4008.c
-index ca2a6ab..6c52c66 100644
---- a/drivers/usb/host/ohci-pnx4008.c
-+++ b/drivers/usb/host/ohci-pnx4008.c
-@@ -112,9 +112,9 @@ static int isp1301_detach(struct i2c_client *client);
- static int isp1301_command(struct i2c_client *client, unsigned int cmd,
- 			   void *arg);
+-	if (sdp->sd_args.ar_localflocks) {
+-		if (IS_GETLK(cmd)) {
+-			posix_test_lock(file, fl);
+-			return 0;
+-		} else {
+-			return posix_lock_file_wait(file, fl);
+-		}
+-	}
+-
+ 	if (cmd == F_CANCELLK) {
+ 		/* Hack: */
+ 		cmd = F_SETLK;
+@@ -632,16 +703,12 @@ static void do_unflock(struct file *file, struct file_lock *fl)
+ static int gfs2_flock(struct file *file, int cmd, struct file_lock *fl)
+ {
+ 	struct gfs2_inode *ip = GFS2_I(file->f_mapping->host);
+-	struct gfs2_sbd *sdp = GFS2_SB(file->f_mapping->host);
  
--static unsigned short normal_i2c[] =
-+static const unsigned short normal_i2c[] =
-     { ISP1301_I2C_ADDR, ISP1301_I2C_ADDR + 1, I2C_CLIENT_END };
--static unsigned short dummy_i2c_addrlist[] = { I2C_CLIENT_END };
-+static const unsigned short dummy_i2c_addrlist[] = { I2C_CLIENT_END };
+ 	if (!(fl->fl_flags & FL_FLOCK))
+ 		return -ENOLCK;
+ 	if (__mandatory_lock(&ip->i_inode))
+ 		return -ENOLCK;
  
- static struct i2c_client_address_data addr_data = {
- 	.normal_i2c = normal_i2c,
-@@ -123,7 +123,6 @@ static struct i2c_client_address_data addr_data = {
+-	if (sdp->sd_args.ar_localflocks)
+-		return flock_lock_file_wait(file, fl);
+-
+ 	if (fl->fl_type == F_UNLCK) {
+ 		do_unflock(file, fl);
+ 		return 0;
+@@ -678,3 +745,27 @@ const struct file_operations gfs2_dir_fops = {
+ 	.flock		= gfs2_flock,
  };
  
- struct i2c_driver isp1301_driver = {
--	.id = I2C_DRIVERID_I2CDEV,	/* Fake Id */
- 	.class = I2C_CLASS_HWMON,
- 	.attach_adapter = isp1301_probe,
- 	.detach_client = isp1301_detach,
-diff --git a/drivers/usb/storage/freecom.c b/drivers/usb/storage/freecom.c
-index 88aa59a..f5a4e8d 100644
---- a/drivers/usb/storage/freecom.c
-+++ b/drivers/usb/storage/freecom.c
-@@ -132,8 +132,7 @@ freecom_readdata (struct scsi_cmnd *srb, struct us_data *us,
- 
- 	/* Now transfer all of our blocks. */
- 	US_DEBUGP("Start of read\n");
--	result = usb_stor_bulk_transfer_sg(us, ipipe, srb->request_buffer,
--			count, srb->use_sg, &srb->resid);
-+	result = usb_stor_bulk_srb(us, ipipe, srb);
- 	US_DEBUGP("freecom_readdata done!\n");
- 
- 	if (result > USB_STOR_XFER_SHORT)
-@@ -166,8 +165,7 @@ freecom_writedata (struct scsi_cmnd *srb, struct us_data *us,
- 
- 	/* Now transfer all of our blocks. */
- 	US_DEBUGP("Start of write\n");
--	result = usb_stor_bulk_transfer_sg(us, opipe, srb->request_buffer,
--			count, srb->use_sg, &srb->resid);
-+	result = usb_stor_bulk_srb(us, opipe, srb);
- 
- 	US_DEBUGP("freecom_writedata done!\n");
- 	if (result > USB_STOR_XFER_SHORT)
-@@ -281,7 +279,7 @@ int freecom_transport(struct scsi_cmnd *srb, struct us_data *us)
- 	 * and such will hang. */
- 	US_DEBUGP("Device indicates that it has %d bytes available\n",
- 			le16_to_cpu (fst->Count));
--	US_DEBUGP("SCSI requested %d\n", srb->request_bufflen);
-+	US_DEBUGP("SCSI requested %d\n", scsi_bufflen(srb));
- 
- 	/* Find the length we desire to read. */
- 	switch (srb->cmnd[0]) {
-@@ -292,12 +290,12 @@ int freecom_transport(struct scsi_cmnd *srb, struct us_data *us)
- 			length = le16_to_cpu(fst->Count);
- 			break;
- 		default:
-- 			length = srb->request_bufflen;
-+			length = scsi_bufflen(srb);
- 	}
++const struct file_operations gfs2_file_fops_nolock = {
++	.llseek		= gfs2_llseek,
++	.read		= do_sync_read,
++	.aio_read	= generic_file_aio_read,
++	.write		= do_sync_write,
++	.aio_write	= generic_file_aio_write,
++	.unlocked_ioctl	= gfs2_ioctl,
++	.mmap		= gfs2_mmap,
++	.open		= gfs2_open,
++	.release	= gfs2_close,
++	.fsync		= gfs2_fsync,
++	.splice_read	= generic_file_splice_read,
++	.splice_write	= generic_file_splice_write,
++	.setlease	= gfs2_setlease,
++};
++
++const struct file_operations gfs2_dir_fops_nolock = {
++	.readdir	= gfs2_readdir,
++	.unlocked_ioctl	= gfs2_ioctl,
++	.open		= gfs2_open,
++	.release	= gfs2_close,
++	.fsync		= gfs2_fsync,
++};
++
+diff --git a/fs/gfs2/ops_file.h b/fs/gfs2/ops_file.h
+deleted file mode 100644
+index 7e5d8ec..0000000
+--- a/fs/gfs2/ops_file.h
++++ /dev/null
+@@ -1,24 +0,0 @@
+-/*
+- * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
+- * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
+- *
+- * This copyrighted material is made available to anyone wishing to use,
+- * modify, copy, or redistribute it subject to the terms and conditions
+- * of the GNU General Public License version 2.
+- */
+-
+-#ifndef __OPS_FILE_DOT_H__
+-#define __OPS_FILE_DOT_H__
+-
+-#include <linux/fs.h>
+-struct gfs2_inode;
+-
+-extern struct file gfs2_internal_file_sentinel;
+-extern int gfs2_internal_read(struct gfs2_inode *ip,
+-			      struct file_ra_state *ra_state,
+-			      char *buf, loff_t *pos, unsigned size);
+-extern void gfs2_set_inode_flags(struct inode *inode);
+-extern const struct file_operations gfs2_file_fops;
+-extern const struct file_operations gfs2_dir_fops;
+-
+-#endif /* __OPS_FILE_DOT_H__ */
+diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c
+index 17de58e..43d511b 100644
+--- a/fs/gfs2/ops_fstype.c
++++ b/fs/gfs2/ops_fstype.c
+@@ -1,6 +1,6 @@
+ /*
+  * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
+- * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
++ * Copyright (C) 2004-2007 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
+@@ -21,6 +21,7 @@
  
- 	/* verify that this amount is legal */
--	if (length > srb->request_bufflen) {
--		length = srb->request_bufflen;
-+	if (length > scsi_bufflen(srb)) {
-+		length = scsi_bufflen(srb);
- 		US_DEBUGP("Truncating request to match buffer length: %d\n", length);
- 	}
+ #include "gfs2.h"
+ #include "incore.h"
++#include "bmap.h"
+ #include "daemon.h"
+ #include "glock.h"
+ #include "glops.h"
+@@ -59,7 +60,6 @@ static struct gfs2_sbd *init_sbd(struct super_block *sb)
  
-diff --git a/drivers/usb/storage/isd200.c b/drivers/usb/storage/isd200.c
-index 49ba6c0..178e8c2 100644
---- a/drivers/usb/storage/isd200.c
-+++ b/drivers/usb/storage/isd200.c
-@@ -49,6 +49,7 @@
- #include <linux/slab.h>
- #include <linux/hdreg.h>
- #include <linux/ide.h>
-+#include <linux/scatterlist.h>
+ 	mutex_init(&sdp->sd_inum_mutex);
+ 	spin_lock_init(&sdp->sd_statfs_spin);
+-	mutex_init(&sdp->sd_statfs_mutex);
  
- #include <scsi/scsi.h>
- #include <scsi/scsi_cmnd.h>
-@@ -287,6 +288,7 @@ struct isd200_info {
- 	/* maximum number of LUNs supported */
- 	unsigned char MaxLUNs;
- 	struct scsi_cmnd srb;
-+	struct scatterlist sg;
- };
+ 	spin_lock_init(&sdp->sd_rindex_spin);
+ 	mutex_init(&sdp->sd_rindex_mutex);
+@@ -77,7 +77,6 @@ static struct gfs2_sbd *init_sbd(struct super_block *sb)
  
+ 	spin_lock_init(&sdp->sd_log_lock);
  
-@@ -398,6 +400,31 @@ static void isd200_build_sense(struct us_data *us, struct scsi_cmnd *srb)
-  * Transport routines
-  ***********************************************************************/
+-	INIT_LIST_HEAD(&sdp->sd_log_le_gl);
+ 	INIT_LIST_HEAD(&sdp->sd_log_le_buf);
+ 	INIT_LIST_HEAD(&sdp->sd_log_le_revoke);
+ 	INIT_LIST_HEAD(&sdp->sd_log_le_rg);
+@@ -303,6 +302,67 @@ out:
+ 	return error;
+ }
  
-+/**************************************************************************
-+ *  isd200_set_srb(), isd200_srb_set_bufflen()
++/**
++ * map_journal_extents - create a reusable "extent" mapping from all logical
++ * blocks to all physical blocks for the given journal.  This will save
++ * us time when writing journal blocks.  Most journals will have only one
++ * extent that maps all their logical blocks.  That's because gfs2.mkfs
++ * arranges the journal blocks sequentially to maximize performance.
++ * So the extent would map the first block for the entire file length.
++ * However, gfs2_jadd can happen while file activity is happening, so
++ * those journals may not be sequential.  Less likely is the case where
++ * the users created their own journals by mounting the metafs and
++ * laying it out.  But it's still possible.  These journals might have
++ * several extents.
 + *
-+ * Two helpers to facilitate in initialization of scsi_cmnd structure
-+ * Will need to change when struct scsi_cmnd changes
++ * TODO: This should be done in bigger chunks rather than one block at a time,
++ *       but since it's only done at mount time, I'm not worried about the
++ *       time it takes.
 + */
-+static void isd200_set_srb(struct isd200_info *info,
-+	enum dma_data_direction dir, void* buff, unsigned bufflen)
++static int map_journal_extents(struct gfs2_sbd *sdp)
 +{
-+	struct scsi_cmnd *srb = &info->srb;
++	struct gfs2_jdesc *jd = sdp->sd_jdesc;
++	unsigned int lb;
++	u64 db, prev_db; /* logical block, disk block, prev disk block */
++	struct gfs2_inode *ip = GFS2_I(jd->jd_inode);
++	struct gfs2_journal_extent *jext = NULL;
++	struct buffer_head bh;
++	int rc = 0;
 +
-+	if (buff)
-+		sg_init_one(&info->sg, buff, bufflen);
++	prev_db = 0;
 +
-+	srb->sc_data_direction = dir;
-+	srb->request_buffer = buff ? &info->sg : NULL;
-+	srb->request_bufflen = bufflen;
-+	srb->use_sg = buff ? 1 : 0;
++	for (lb = 0; lb < ip->i_di.di_size >> sdp->sd_sb.sb_bsize_shift; lb++) {
++		bh.b_state = 0;
++		bh.b_blocknr = 0;
++		bh.b_size = 1 << ip->i_inode.i_blkbits;
++		rc = gfs2_block_map(jd->jd_inode, lb, &bh, 0);
++		db = bh.b_blocknr;
++		if (rc || !db) {
++			printk(KERN_INFO "GFS2 journal mapping error %d: lb="
++			       "%u db=%llu\n", rc, lb, (unsigned long long)db);
++			break;
++		}
++		if (!prev_db || db != prev_db + 1) {
++			jext = kzalloc(sizeof(struct gfs2_journal_extent),
++				       GFP_KERNEL);
++			if (!jext) {
++				printk(KERN_INFO "GFS2 error: out of memory "
++				       "mapping journal extents.\n");
++				rc = -ENOMEM;
++				break;
++			}
++			jext->dblock = db;
++			jext->lblock = lb;
++			jext->blocks = 1;
++			list_add_tail(&jext->extent_list, &jd->extent_list);
++		} else {
++			jext->blocks++;
++		}
++		prev_db = db;
++	}
++	return rc;
 +}
 +
-+static void isd200_srb_set_bufflen(struct scsi_cmnd *srb, unsigned bufflen)
-+{
-+	srb->request_bufflen = bufflen;
-+}
+ static int init_journal(struct gfs2_sbd *sdp, int undo)
+ {
+ 	struct gfs2_holder ji_gh;
+@@ -340,7 +400,7 @@ static int init_journal(struct gfs2_sbd *sdp, int undo)
+ 
+ 	if (sdp->sd_args.ar_spectator) {
+ 		sdp->sd_jdesc = gfs2_jdesc_find(sdp, 0);
+-		sdp->sd_log_blks_free = sdp->sd_jdesc->jd_blocks;
++		atomic_set(&sdp->sd_log_blks_free, sdp->sd_jdesc->jd_blocks);
+ 	} else {
+ 		if (sdp->sd_lockstruct.ls_jid >= gfs2_jindex_size(sdp)) {
+ 			fs_err(sdp, "can't mount journal #%u\n",
+@@ -377,7 +437,10 @@ static int init_journal(struct gfs2_sbd *sdp, int undo)
+ 			       sdp->sd_jdesc->jd_jid, error);
+ 			goto fail_jinode_gh;
+ 		}
+-		sdp->sd_log_blks_free = sdp->sd_jdesc->jd_blocks;
++		atomic_set(&sdp->sd_log_blks_free, sdp->sd_jdesc->jd_blocks);
 +
++		/* Map the extents for this journal's blocks */
++		map_journal_extents(sdp);
+ 	}
  
- /**************************************************************************
-  *  isd200_action
-@@ -432,9 +459,7 @@ static int isd200_action( struct us_data *us, int action,
- 		ata.generic.RegisterSelect =
- 		  REG_CYLINDER_LOW | REG_CYLINDER_HIGH |
- 		  REG_STATUS | REG_ERROR;
--		srb->sc_data_direction = DMA_FROM_DEVICE;
--		srb->request_buffer = pointer;
--		srb->request_bufflen = value;
-+		isd200_set_srb(info, DMA_FROM_DEVICE, pointer, value);
- 		break;
+ 	if (sdp->sd_lockstruct.ls_first) {
+diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c
+index 291f0c7..9f71372 100644
+--- a/fs/gfs2/ops_inode.c
++++ b/fs/gfs2/ops_inode.c
+@@ -61,7 +61,7 @@ static int gfs2_create(struct inode *dir, struct dentry *dentry,
+ 		inode = gfs2_createi(ghs, &dentry->d_name, S_IFREG | mode, 0);
+ 		if (!IS_ERR(inode)) {
+ 			gfs2_trans_end(sdp);
+-			if (dip->i_alloc.al_rgd)
++			if (dip->i_alloc->al_rgd)
+ 				gfs2_inplace_release(dip);
+ 			gfs2_quota_unlock(dip);
+ 			gfs2_alloc_put(dip);
+@@ -113,8 +113,18 @@ static struct dentry *gfs2_lookup(struct inode *dir, struct dentry *dentry,
+ 	if (inode && IS_ERR(inode))
+ 		return ERR_PTR(PTR_ERR(inode));
  
- 	case ACTION_ENUM:
-@@ -444,7 +469,7 @@ static int isd200_action( struct us_data *us, int action,
- 					   ACTION_SELECT_5;
- 		ata.generic.RegisterSelect = REG_DEVICE_HEAD;
- 		ata.write.DeviceHeadByte = value;
--		srb->sc_data_direction = DMA_NONE;
-+		isd200_set_srb(info, DMA_NONE, NULL, 0);
- 		break;
+-	if (inode)
++	if (inode) {
++		struct gfs2_glock *gl = GFS2_I(inode)->i_gl;
++		struct gfs2_holder gh;
++		int error;
++		error = gfs2_glock_nq_init(gl, LM_ST_SHARED, LM_FLAG_ANY, &gh);
++		if (error) {
++			iput(inode);
++			return ERR_PTR(error);
++		}
++		gfs2_glock_dq_uninit(&gh);
+ 		return d_splice_alias(inode, dentry);
++	}
+ 	d_add(dentry, inode);
  
- 	case ACTION_RESET:
-@@ -453,7 +478,7 @@ static int isd200_action( struct us_data *us, int action,
- 					   ACTION_SELECT_3|ACTION_SELECT_4;
- 		ata.generic.RegisterSelect = REG_DEVICE_CONTROL;
- 		ata.write.DeviceControlByte = ATA_DC_RESET_CONTROLLER;
--		srb->sc_data_direction = DMA_NONE;
-+		isd200_set_srb(info, DMA_NONE, NULL, 0);
- 		break;
+ 	return NULL;
+@@ -366,7 +376,7 @@ static int gfs2_symlink(struct inode *dir, struct dentry *dentry,
+ 	}
  
- 	case ACTION_REENABLE:
-@@ -462,7 +487,7 @@ static int isd200_action( struct us_data *us, int action,
- 					   ACTION_SELECT_3|ACTION_SELECT_4;
- 		ata.generic.RegisterSelect = REG_DEVICE_CONTROL;
- 		ata.write.DeviceControlByte = ATA_DC_REENABLE_CONTROLLER;
--		srb->sc_data_direction = DMA_NONE;
-+		isd200_set_srb(info, DMA_NONE, NULL, 0);
- 		break;
+ 	gfs2_trans_end(sdp);
+-	if (dip->i_alloc.al_rgd)
++	if (dip->i_alloc->al_rgd)
+ 		gfs2_inplace_release(dip);
+ 	gfs2_quota_unlock(dip);
+ 	gfs2_alloc_put(dip);
+@@ -442,7 +452,7 @@ static int gfs2_mkdir(struct inode *dir, struct dentry *dentry, int mode)
+ 	gfs2_assert_withdraw(sdp, !error); /* dip already pinned */
  
- 	case ACTION_SOFT_RESET:
-@@ -471,21 +496,20 @@ static int isd200_action( struct us_data *us, int action,
- 		ata.generic.RegisterSelect = REG_DEVICE_HEAD | REG_COMMAND;
- 		ata.write.DeviceHeadByte = info->DeviceHead;
- 		ata.write.CommandByte = WIN_SRST;
--		srb->sc_data_direction = DMA_NONE;
-+		isd200_set_srb(info, DMA_NONE, NULL, 0);
- 		break;
+ 	gfs2_trans_end(sdp);
+-	if (dip->i_alloc.al_rgd)
++	if (dip->i_alloc->al_rgd)
+ 		gfs2_inplace_release(dip);
+ 	gfs2_quota_unlock(dip);
+ 	gfs2_alloc_put(dip);
+@@ -548,7 +558,7 @@ static int gfs2_mknod(struct inode *dir, struct dentry *dentry, int mode,
+ 	}
  
- 	case ACTION_IDENTIFY:
- 		US_DEBUGP("   isd200_action(IDENTIFY)\n");
- 		ata.generic.RegisterSelect = REG_COMMAND;
- 		ata.write.CommandByte = WIN_IDENTIFY;
--		srb->sc_data_direction = DMA_FROM_DEVICE;
--		srb->request_buffer = (void *) info->id;
--		srb->request_bufflen = sizeof(struct hd_driveid);
-+		isd200_set_srb(info, DMA_FROM_DEVICE, info->id,
-+		                                sizeof(struct hd_driveid));
- 		break;
+ 	gfs2_trans_end(sdp);
+-	if (dip->i_alloc.al_rgd)
++	if (dip->i_alloc->al_rgd)
+ 		gfs2_inplace_release(dip);
+ 	gfs2_quota_unlock(dip);
+ 	gfs2_alloc_put(dip);
+diff --git a/fs/gfs2/ops_inode.h b/fs/gfs2/ops_inode.h
+index 34f0caa..fd8cee2 100644
+--- a/fs/gfs2/ops_inode.h
++++ b/fs/gfs2/ops_inode.h
+@@ -16,5 +16,11 @@ extern const struct inode_operations gfs2_file_iops;
+ extern const struct inode_operations gfs2_dir_iops;
+ extern const struct inode_operations gfs2_symlink_iops;
+ extern const struct inode_operations gfs2_dev_iops;
++extern const struct file_operations gfs2_file_fops;
++extern const struct file_operations gfs2_dir_fops;
++extern const struct file_operations gfs2_file_fops_nolock;
++extern const struct file_operations gfs2_dir_fops_nolock;
++
++extern void gfs2_set_inode_flags(struct inode *inode);
  
- 	default:
- 		US_DEBUGP("Error: Undefined action %d\n",action);
--		break;
-+		return ISD200_ERROR;
+ #endif /* __OPS_INODE_DOT_H__ */
+diff --git a/fs/gfs2/ops_super.c b/fs/gfs2/ops_super.c
+index 950f314..5e52421 100644
+--- a/fs/gfs2/ops_super.c
++++ b/fs/gfs2/ops_super.c
+@@ -487,7 +487,6 @@ static struct inode *gfs2_alloc_inode(struct super_block *sb)
+ 	if (ip) {
+ 		ip->i_flags = 0;
+ 		ip->i_gl = NULL;
+-		ip->i_last_pfault = jiffies;
+ 	}
+ 	return &ip->i_inode;
+ }
+diff --git a/fs/gfs2/ops_vm.c b/fs/gfs2/ops_vm.c
+deleted file mode 100644
+index 927d739..0000000
+--- a/fs/gfs2/ops_vm.c
++++ /dev/null
+@@ -1,169 +0,0 @@
+-/*
+- * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
+- * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
+- *
+- * This copyrighted material is made available to anyone wishing to use,
+- * modify, copy, or redistribute it subject to the terms and conditions
+- * of the GNU General Public License version 2.
+- */
+-
+-#include <linux/slab.h>
+-#include <linux/spinlock.h>
+-#include <linux/completion.h>
+-#include <linux/buffer_head.h>
+-#include <linux/mm.h>
+-#include <linux/pagemap.h>
+-#include <linux/gfs2_ondisk.h>
+-#include <linux/lm_interface.h>
+-
+-#include "gfs2.h"
+-#include "incore.h"
+-#include "bmap.h"
+-#include "glock.h"
+-#include "inode.h"
+-#include "ops_vm.h"
+-#include "quota.h"
+-#include "rgrp.h"
+-#include "trans.h"
+-#include "util.h"
+-
+-static int gfs2_private_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
+-{
+-	struct gfs2_inode *ip = GFS2_I(vma->vm_file->f_mapping->host);
+-
+-	set_bit(GIF_PAGED, &ip->i_flags);
+-	return filemap_fault(vma, vmf);
+-}
+-
+-static int alloc_page_backing(struct gfs2_inode *ip, struct page *page)
+-{
+-	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+-	unsigned long index = page->index;
+-	u64 lblock = index << (PAGE_CACHE_SHIFT -
+-				    sdp->sd_sb.sb_bsize_shift);
+-	unsigned int blocks = PAGE_CACHE_SIZE >> sdp->sd_sb.sb_bsize_shift;
+-	struct gfs2_alloc *al;
+-	unsigned int data_blocks, ind_blocks;
+-	unsigned int x;
+-	int error;
+-
+-	al = gfs2_alloc_get(ip);
+-
+-	error = gfs2_quota_lock(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE);
+-	if (error)
+-		goto out;
+-
+-	error = gfs2_quota_check(ip, ip->i_inode.i_uid, ip->i_inode.i_gid);
+-	if (error)
+-		goto out_gunlock_q;
+-
+-	gfs2_write_calc_reserv(ip, PAGE_CACHE_SIZE, &data_blocks, &ind_blocks);
+-
+-	al->al_requested = data_blocks + ind_blocks;
+-
+-	error = gfs2_inplace_reserve(ip);
+-	if (error)
+-		goto out_gunlock_q;
+-
+-	error = gfs2_trans_begin(sdp, al->al_rgd->rd_length +
+-				 ind_blocks + RES_DINODE +
+-				 RES_STATFS + RES_QUOTA, 0);
+-	if (error)
+-		goto out_ipres;
+-
+-	if (gfs2_is_stuffed(ip)) {
+-		error = gfs2_unstuff_dinode(ip, NULL);
+-		if (error)
+-			goto out_trans;
+-	}
+-
+-	for (x = 0; x < blocks; ) {
+-		u64 dblock;
+-		unsigned int extlen;
+-		int new = 1;
+-
+-		error = gfs2_extent_map(&ip->i_inode, lblock, &new, &dblock, &extlen);
+-		if (error)
+-			goto out_trans;
+-
+-		lblock += extlen;
+-		x += extlen;
+-	}
+-
+-	gfs2_assert_warn(sdp, al->al_alloced);
+-
+-out_trans:
+-	gfs2_trans_end(sdp);
+-out_ipres:
+-	gfs2_inplace_release(ip);
+-out_gunlock_q:
+-	gfs2_quota_unlock(ip);
+-out:
+-	gfs2_alloc_put(ip);
+-	return error;
+-}
+-
+-static int gfs2_sharewrite_fault(struct vm_area_struct *vma,
+-						struct vm_fault *vmf)
+-{
+-	struct file *file = vma->vm_file;
+-	struct gfs2_file *gf = file->private_data;
+-	struct gfs2_inode *ip = GFS2_I(file->f_mapping->host);
+-	struct gfs2_holder i_gh;
+-	int alloc_required;
+-	int error;
+-	int ret = 0;
+-
+-	error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &i_gh);
+-	if (error)
+-		goto out;
+-
+-	set_bit(GIF_PAGED, &ip->i_flags);
+-	set_bit(GIF_SW_PAGED, &ip->i_flags);
+-
+-	error = gfs2_write_alloc_required(ip,
+-					(u64)vmf->pgoff << PAGE_CACHE_SHIFT,
+-					PAGE_CACHE_SIZE, &alloc_required);
+-	if (error) {
+-		ret = VM_FAULT_OOM; /* XXX: are these right? */
+-		goto out_unlock;
+-	}
+-
+-	set_bit(GFF_EXLOCK, &gf->f_flags);
+-	ret = filemap_fault(vma, vmf);
+-	clear_bit(GFF_EXLOCK, &gf->f_flags);
+-	if (ret & VM_FAULT_ERROR)
+-		goto out_unlock;
+-
+-	if (alloc_required) {
+-		/* XXX: do we need to drop page lock around alloc_page_backing?*/
+-		error = alloc_page_backing(ip, vmf->page);
+-		if (error) {
+-			/*
+-			 * VM_FAULT_LOCKED should always be the case for
+-			 * filemap_fault, but it may not be in a future
+-			 * implementation.
+-			 */
+-			if (ret & VM_FAULT_LOCKED)
+-				unlock_page(vmf->page);
+-			page_cache_release(vmf->page);
+-			ret = VM_FAULT_OOM;
+-			goto out_unlock;
+-		}
+-		set_page_dirty(vmf->page);
+-	}
+-
+-out_unlock:
+-	gfs2_glock_dq_uninit(&i_gh);
+-out:
+-	return ret;
+-}
+-
+-struct vm_operations_struct gfs2_vm_ops_private = {
+-	.fault = gfs2_private_fault,
+-};
+-
+-struct vm_operations_struct gfs2_vm_ops_sharewrite = {
+-	.fault = gfs2_sharewrite_fault,
+-};
+-
+diff --git a/fs/gfs2/ops_vm.h b/fs/gfs2/ops_vm.h
+deleted file mode 100644
+index 4ae8f43..0000000
+--- a/fs/gfs2/ops_vm.h
++++ /dev/null
+@@ -1,18 +0,0 @@
+-/*
+- * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
+- * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
+- *
+- * This copyrighted material is made available to anyone wishing to use,
+- * modify, copy, or redistribute it subject to the terms and conditions
+- * of the GNU General Public License version 2.
+- */
+-
+-#ifndef __OPS_VM_DOT_H__
+-#define __OPS_VM_DOT_H__
+-
+-#include <linux/mm.h>
+-
+-extern struct vm_operations_struct gfs2_vm_ops_private;
+-extern struct vm_operations_struct gfs2_vm_ops_sharewrite;
+-
+-#endif /* __OPS_VM_DOT_H__ */
+diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c
+index addb51e..a08dabd 100644
+--- a/fs/gfs2/quota.c
++++ b/fs/gfs2/quota.c
+@@ -1,6 +1,6 @@
+ /*
+  * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
+- * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
++ * Copyright (C) 2004-2007 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
+@@ -59,7 +59,6 @@
+ #include "super.h"
+ #include "trans.h"
+ #include "inode.h"
+-#include "ops_file.h"
+ #include "ops_address.h"
+ #include "util.h"
+ 
+@@ -274,10 +273,10 @@ static int bh_get(struct gfs2_quota_data *qd)
  	}
  
- 	memcpy(srb->cmnd, &ata, sizeof(ata.generic));
-@@ -590,7 +614,7 @@ static void isd200_invoke_transport( struct us_data *us,
- 		return;
+ 	block = qd->qd_slot / sdp->sd_qc_per_block;
+-	offset = qd->qd_slot % sdp->sd_qc_per_block;;
++	offset = qd->qd_slot % sdp->sd_qc_per_block;
+ 
+ 	bh_map.b_size = 1 << ip->i_inode.i_blkbits;
+-	error = gfs2_block_map(&ip->i_inode, block, 0, &bh_map);
++	error = gfs2_block_map(&ip->i_inode, block, &bh_map, 0);
+ 	if (error)
+ 		goto fail;
+ 	error = gfs2_meta_read(ip->i_gl, bh_map.b_blocknr, DIO_WAIT, &bh);
+@@ -454,7 +453,7 @@ static void qdsb_put(struct gfs2_quota_data *qd)
+ int gfs2_quota_hold(struct gfs2_inode *ip, u32 uid, u32 gid)
+ {
+ 	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+-	struct gfs2_alloc *al = &ip->i_alloc;
++	struct gfs2_alloc *al = ip->i_alloc;
+ 	struct gfs2_quota_data **qd = al->al_qd;
+ 	int error;
+ 
+@@ -502,7 +501,7 @@ out:
+ void gfs2_quota_unhold(struct gfs2_inode *ip)
+ {
+ 	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+-	struct gfs2_alloc *al = &ip->i_alloc;
++	struct gfs2_alloc *al = ip->i_alloc;
+ 	unsigned int x;
+ 
+ 	gfs2_assert_warn(sdp, !test_bit(GIF_QD_LOCKED, &ip->i_flags));
+@@ -646,7 +645,7 @@ static int gfs2_adjust_quota(struct gfs2_inode *ip, loff_t loc,
  	}
  
--	if ((srb->resid > 0) &&
-+	if ((scsi_get_resid(srb) > 0) &&
- 	    !((srb->cmnd[0] == REQUEST_SENSE) ||
- 	      (srb->cmnd[0] == INQUIRY) ||
- 	      (srb->cmnd[0] == MODE_SENSE) ||
-@@ -1217,7 +1241,6 @@ static int isd200_get_inquiry_data( struct us_data *us )
- 	return(retStatus);
- }
+ 	if (!buffer_mapped(bh)) {
+-		gfs2_get_block(inode, iblock, bh, 1);
++		gfs2_block_map(inode, iblock, bh, 1);
+ 		if (!buffer_mapped(bh))
+ 			goto unlock;
+ 	}
+@@ -793,11 +792,9 @@ static int do_glock(struct gfs2_quota_data *qd, int force_refresh,
+ 	struct gfs2_holder i_gh;
+ 	struct gfs2_quota_host q;
+ 	char buf[sizeof(struct gfs2_quota)];
+-	struct file_ra_state ra_state;
+ 	int error;
+ 	struct gfs2_quota_lvb *qlvb;
  
--
- /**************************************************************************
-  * isd200_scsi_to_ata
-  *									 
-@@ -1266,7 +1289,7 @@ static int isd200_scsi_to_ata(struct scsi_cmnd *srb, struct us_data *us,
- 			ataCdb->generic.TransferBlockSize = 1;
- 			ataCdb->generic.RegisterSelect = REG_COMMAND;
- 			ataCdb->write.CommandByte = ATA_COMMAND_GET_MEDIA_STATUS;
--			srb->request_bufflen = 0;
-+			isd200_srb_set_bufflen(srb, 0);
- 		} else {
- 			US_DEBUGP("   Media Status not supported, just report okay\n");
- 			srb->result = SAM_STAT_GOOD;
-@@ -1284,7 +1307,7 @@ static int isd200_scsi_to_ata(struct scsi_cmnd *srb, struct us_data *us,
- 			ataCdb->generic.TransferBlockSize = 1;
- 			ataCdb->generic.RegisterSelect = REG_COMMAND;
- 			ataCdb->write.CommandByte = ATA_COMMAND_GET_MEDIA_STATUS;
--			srb->request_bufflen = 0;
-+			isd200_srb_set_bufflen(srb, 0);
- 		} else {
- 			US_DEBUGP("   Media Status not supported, just report okay\n");
- 			srb->result = SAM_STAT_GOOD;
-@@ -1390,7 +1413,7 @@ static int isd200_scsi_to_ata(struct scsi_cmnd *srb, struct us_data *us,
- 			ataCdb->generic.RegisterSelect = REG_COMMAND;
- 			ataCdb->write.CommandByte = (srb->cmnd[4] & 0x1) ?
- 				WIN_DOORLOCK : WIN_DOORUNLOCK;
--			srb->request_bufflen = 0;
-+			isd200_srb_set_bufflen(srb, 0);
- 		} else {
- 			US_DEBUGP("   Not removeable media, just report okay\n");
- 			srb->result = SAM_STAT_GOOD;
-@@ -1416,7 +1439,7 @@ static int isd200_scsi_to_ata(struct scsi_cmnd *srb, struct us_data *us,
- 			ataCdb->generic.TransferBlockSize = 1;
- 			ataCdb->generic.RegisterSelect = REG_COMMAND;
- 			ataCdb->write.CommandByte = ATA_COMMAND_GET_MEDIA_STATUS;
--			srb->request_bufflen = 0;
-+			isd200_srb_set_bufflen(srb, 0);
- 		} else {
- 			US_DEBUGP("   Nothing to do, just report okay\n");
- 			srb->result = SAM_STAT_GOOD;
-@@ -1525,7 +1548,7 @@ int isd200_Initialization(struct us_data *us)
+-	file_ra_state_init(&ra_state, sdp->sd_quota_inode->i_mapping);
+ restart:
+ 	error = gfs2_glock_nq_init(qd->qd_gl, LM_ST_SHARED, 0, q_gh);
+ 	if (error)
+@@ -820,8 +817,8 @@ restart:
  
- void isd200_ata_command(struct scsi_cmnd *srb, struct us_data *us)
+ 		memset(buf, 0, sizeof(struct gfs2_quota));
+ 		pos = qd2offset(qd);
+-		error = gfs2_internal_read(ip, &ra_state, buf,
+-					   &pos, sizeof(struct gfs2_quota));
++		error = gfs2_internal_read(ip, NULL, buf, &pos,
++					   sizeof(struct gfs2_quota));
+ 		if (error < 0)
+ 			goto fail_gunlock;
+ 
+@@ -856,7 +853,7 @@ fail:
+ int gfs2_quota_lock(struct gfs2_inode *ip, u32 uid, u32 gid)
  {
--	int sendToTransport = 1;
-+	int sendToTransport = 1, orig_bufflen;
- 	union ata_cdb ataCdb;
+ 	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+-	struct gfs2_alloc *al = &ip->i_alloc;
++	struct gfs2_alloc *al = ip->i_alloc;
+ 	unsigned int x;
+ 	int error = 0;
  
- 	/* Make sure driver was initialized */
-@@ -1533,11 +1556,14 @@ void isd200_ata_command(struct scsi_cmnd *srb, struct us_data *us)
- 	if (us->extra == NULL)
- 		US_DEBUGP("ERROR Driver not initialized\n");
+@@ -924,7 +921,7 @@ static int need_sync(struct gfs2_quota_data *qd)
  
--	/* Convert command */
--	srb->resid = 0;
-+	scsi_set_resid(srb, 0);
-+	/* scsi_bufflen might change in protocol translation to ata */
-+	orig_bufflen = scsi_bufflen(srb);
- 	sendToTransport = isd200_scsi_to_ata(srb, us, &ataCdb);
+ void gfs2_quota_unlock(struct gfs2_inode *ip)
+ {
+-	struct gfs2_alloc *al = &ip->i_alloc;
++	struct gfs2_alloc *al = ip->i_alloc;
+ 	struct gfs2_quota_data *qda[4];
+ 	unsigned int count = 0;
+ 	unsigned int x;
+@@ -972,7 +969,7 @@ static int print_message(struct gfs2_quota_data *qd, char *type)
+ int gfs2_quota_check(struct gfs2_inode *ip, u32 uid, u32 gid)
+ {
+ 	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+-	struct gfs2_alloc *al = &ip->i_alloc;
++	struct gfs2_alloc *al = ip->i_alloc;
+ 	struct gfs2_quota_data *qd;
+ 	s64 value;
+ 	unsigned int x;
+@@ -1016,10 +1013,9 @@ int gfs2_quota_check(struct gfs2_inode *ip, u32 uid, u32 gid)
+ void gfs2_quota_change(struct gfs2_inode *ip, s64 change,
+ 		       u32 uid, u32 gid)
+ {
+-	struct gfs2_alloc *al = &ip->i_alloc;
++	struct gfs2_alloc *al = ip->i_alloc;
+ 	struct gfs2_quota_data *qd;
+ 	unsigned int x;
+-	unsigned int found = 0;
  
- 	/* send the command to the transport layer */
- 	if (sendToTransport)
- 		isd200_invoke_transport(us, srb, &ataCdb);
-+
-+	isd200_srb_set_bufflen(srb, orig_bufflen);
+ 	if (gfs2_assert_warn(GFS2_SB(&ip->i_inode), change))
+ 		return;
+@@ -1032,7 +1028,6 @@ void gfs2_quota_change(struct gfs2_inode *ip, s64 change,
+ 		if ((qd->qd_id == uid && test_bit(QDF_USER, &qd->qd_flags)) ||
+ 		    (qd->qd_id == gid && !test_bit(QDF_USER, &qd->qd_flags))) {
+ 			do_qc(qd, change);
+-			found++;
+ 		}
+ 	}
  }
-diff --git a/drivers/usb/storage/protocol.c b/drivers/usb/storage/protocol.c
-index 889622b..a41ce21 100644
---- a/drivers/usb/storage/protocol.c
-+++ b/drivers/usb/storage/protocol.c
-@@ -149,11 +149,7 @@ void usb_stor_transparent_scsi_command(struct scsi_cmnd *srb,
-  ***********************************************************************/
+diff --git a/fs/gfs2/recovery.c b/fs/gfs2/recovery.c
+index beb6c7a..b249e29 100644
+--- a/fs/gfs2/recovery.c
++++ b/fs/gfs2/recovery.c
+@@ -391,7 +391,7 @@ static int clean_journal(struct gfs2_jdesc *jd, struct gfs2_log_header_host *hea
+ 	lblock = head->lh_blkno;
+ 	gfs2_replay_incr_blk(sdp, &lblock);
+ 	bh_map.b_size = 1 << ip->i_inode.i_blkbits;
+-	error = gfs2_block_map(&ip->i_inode, lblock, 0, &bh_map);
++	error = gfs2_block_map(&ip->i_inode, lblock, &bh_map, 0);
+ 	if (error)
+ 		return error;
+ 	if (!bh_map.b_blocknr) {
+@@ -504,13 +504,21 @@ int gfs2_recover_journal(struct gfs2_jdesc *jd)
+ 			if (!test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags))
+ 				ro = 1;
+ 		} else {
+-			if (sdp->sd_vfs->s_flags & MS_RDONLY)
+-				ro = 1;
++			if (sdp->sd_vfs->s_flags & MS_RDONLY) {
++				/* check if device itself is read-only */
++				ro = bdev_read_only(sdp->sd_vfs->s_bdev);
++				if (!ro) {
++					fs_info(sdp, "recovery required on "
++						"read-only filesystem.\n");
++					fs_info(sdp, "write access will be "
++						"enabled during recovery.\n");
++				}
++			}
+ 		}
  
- /* Copy a buffer of length buflen to/from the srb's transfer buffer.
-- * (Note: for scatter-gather transfers (srb->use_sg > 0), srb->request_buffer
-- * points to a list of s-g entries and we ignore srb->request_bufflen.
-- * For non-scatter-gather transfers, srb->request_buffer points to the
-- * transfer buffer itself and srb->request_bufflen is the buffer's length.)
-- * Update the *index and *offset variables so that the next copy will
-+ * Update the **sgptr and *offset variables so that the next copy will
-  * pick up from where this one left off. */
+ 		if (ro) {
+-			fs_warn(sdp, "jid=%u: Can't replay: read-only FS\n",
+-				jd->jd_jid);
++			fs_warn(sdp, "jid=%u: Can't replay: read-only block "
++				"device\n", jd->jd_jid);
+ 			error = -EROFS;
+ 			goto fail_gunlock_tr;
+ 		}
+diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c
+index 708c287..3552110 100644
+--- a/fs/gfs2/rgrp.c
++++ b/fs/gfs2/rgrp.c
+@@ -25,10 +25,10 @@
+ #include "rgrp.h"
+ #include "super.h"
+ #include "trans.h"
+-#include "ops_file.h"
+ #include "util.h"
+ #include "log.h"
+ #include "inode.h"
++#include "ops_address.h"
  
- unsigned int usb_stor_access_xfer_buf(unsigned char *buffer,
-@@ -162,80 +158,64 @@ unsigned int usb_stor_access_xfer_buf(unsigned char *buffer,
- {
- 	unsigned int cnt;
+ #define BFITNOENT ((u32)~0)
+ #define NO_BLOCK ((u64)~0)
+@@ -126,41 +126,43 @@ static unsigned char gfs2_testbit(struct gfs2_rgrpd *rgd, unsigned char *buffer,
+  * Return: the block number (bitmap buffer scope) that was found
+  */
  
--	/* If not using scatter-gather, just transfer the data directly.
--	 * Make certain it will fit in the available buffer space. */
--	if (srb->use_sg == 0) {
--		if (*offset >= srb->request_bufflen)
--			return 0;
--		cnt = min(buflen, srb->request_bufflen - *offset);
--		if (dir == TO_XFER_BUF)
--			memcpy((unsigned char *) srb->request_buffer + *offset,
--					buffer, cnt);
--		else
--			memcpy(buffer, (unsigned char *) srb->request_buffer +
--					*offset, cnt);
--		*offset += cnt;
--
--	/* Using scatter-gather.  We have to go through the list one entry
-+	/* We have to go through the list one entry
- 	 * at a time.  Each s-g entry contains some number of pages, and
- 	 * each page has to be kmap()'ed separately.  If the page is already
- 	 * in kernel-addressable memory then kmap() will return its address.
- 	 * If the page is not directly accessible -- such as a user buffer
- 	 * located in high memory -- then kmap() will map it to a temporary
- 	 * position in the kernel's virtual address space. */
--	} else {
--		struct scatterlist *sg = *sgptr;
--
--		if (!sg)
--			sg = (struct scatterlist *) srb->request_buffer;
--
--		/* This loop handles a single s-g list entry, which may
--		 * include multiple pages.  Find the initial page structure
--		 * and the starting offset within the page, and update
--		 * the *offset and *index values for the next loop. */
--		cnt = 0;
--		while (cnt < buflen) {
--			struct page *page = sg_page(sg) +
--					((sg->offset + *offset) >> PAGE_SHIFT);
--			unsigned int poff =
--					(sg->offset + *offset) & (PAGE_SIZE-1);
--			unsigned int sglen = sg->length - *offset;
--
--			if (sglen > buflen - cnt) {
+-static u32 gfs2_bitfit(struct gfs2_rgrpd *rgd, unsigned char *buffer,
+-			    unsigned int buflen, u32 goal,
+-			    unsigned char old_state)
++static u32 gfs2_bitfit(unsigned char *buffer, unsigned int buflen, u32 goal,
++		       unsigned char old_state)
+ {
+-	unsigned char *byte, *end, alloc;
++	unsigned char *byte;
+ 	u32 blk = goal;
+-	unsigned int bit;
++	unsigned int bit, bitlong;
++	unsigned long *plong, plong55;
+ 
+ 	byte = buffer + (goal / GFS2_NBBY);
++	plong = (unsigned long *)(buffer + (goal / GFS2_NBBY));
+ 	bit = (goal % GFS2_NBBY) * GFS2_BIT_SIZE;
+-	end = buffer + buflen;
+-	alloc = (old_state == GFS2_BLKST_FREE) ? 0x55 : 0;
 -
--				/* Transfer ends within this s-g entry */
--				sglen = buflen - cnt;
--				*offset += sglen;
--			} else {
+-	while (byte < end) {
+-		/* If we're looking for a free block we can eliminate all
+-		   bitmap settings with 0x55, which represents four data
+-		   blocks in a row.  If we're looking for a data block, we can
+-		   eliminate 0x00 which corresponds to four free blocks. */
+-		if ((*byte & 0x55) == alloc) {
+-			blk += (8 - bit) >> 1;
 -
--				/* Transfer continues to next s-g entry */
--				*offset = 0;
--				sg = sg_next(sg);
--			}
+-			bit = 0;
+-			byte++;
 -
--			/* Transfer the data for all the pages in this
--			 * s-g entry.  For each page: call kmap(), do the
--			 * transfer, and call kunmap() immediately after. */
--			while (sglen > 0) {
--				unsigned int plen = min(sglen, (unsigned int)
--						PAGE_SIZE - poff);
--				unsigned char *ptr = kmap(page);
++	bitlong = bit;
++#if BITS_PER_LONG == 32
++	plong55 = 0x55555555;
++#else
++	plong55 = 0x5555555555555555;
++#endif
++	while (byte < buffer + buflen) {
++
++		if (bitlong == 0 && old_state == 0 && *plong == plong55) {
++			plong++;
++			byte += sizeof(unsigned long);
++			blk += sizeof(unsigned long) * GFS2_NBBY;
+ 			continue;
+ 		}
 -
--				if (dir == TO_XFER_BUF)
--					memcpy(ptr + poff, buffer + cnt, plen);
--				else
--					memcpy(buffer + cnt, ptr + poff, plen);
--				kunmap(page);
+ 		if (((*byte >> bit) & GFS2_BIT_MASK) == old_state)
+ 			return blk;
 -
--				/* Start at the beginning of the next page */
--				poff = 0;
--				++page;
--				cnt += plen;
--				sglen -= plen;
--			}
-+	struct scatterlist *sg = *sgptr;
-+
-+	if (!sg)
-+		sg = scsi_sglist(srb);
-+
-+	/* This loop handles a single s-g list entry, which may
-+		* include multiple pages.  Find the initial page structure
-+		* and the starting offset within the page, and update
-+		* the *offset and **sgptr values for the next loop. */
-+	cnt = 0;
-+	while (cnt < buflen) {
-+		struct page *page = sg_page(sg) +
-+				((sg->offset + *offset) >> PAGE_SHIFT);
-+		unsigned int poff =
-+				(sg->offset + *offset) & (PAGE_SIZE-1);
-+		unsigned int sglen = sg->length - *offset;
-+
-+		if (sglen > buflen - cnt) {
-+
-+			/* Transfer ends within this s-g entry */
-+			sglen = buflen - cnt;
-+			*offset += sglen;
-+		} else {
-+
-+			/* Transfer continues to next s-g entry */
-+			*offset = 0;
-+			sg = sg_next(sg);
-+		}
-+
-+		/* Transfer the data for all the pages in this
-+			* s-g entry.  For each page: call kmap(), do the
-+			* transfer, and call kunmap() immediately after. */
-+		while (sglen > 0) {
-+			unsigned int plen = min(sglen, (unsigned int)
-+					PAGE_SIZE - poff);
-+			unsigned char *ptr = kmap(page);
-+
-+			if (dir == TO_XFER_BUF)
-+				memcpy(ptr + poff, buffer + cnt, plen);
-+			else
-+				memcpy(buffer + cnt, ptr + poff, plen);
-+			kunmap(page);
-+
-+			/* Start at the beginning of the next page */
-+			poff = 0;
-+			++page;
-+			cnt += plen;
-+			sglen -= plen;
+ 		bit += GFS2_BIT_SIZE;
+ 		if (bit >= 8) {
+ 			bit = 0;
+ 			byte++;
  		}
--		*sgptr = sg;
- 	}
-+	*sgptr = sg;
- 
- 	/* Return the amount actually transferred */
- 	return cnt;
-@@ -251,6 +231,6 @@ void usb_stor_set_xfer_buf(unsigned char *buffer,
++		bitlong += GFS2_BIT_SIZE;
++		if (bitlong >= sizeof(unsigned long) * 8) {
++			bitlong = 0;
++			plong++;
++		}
  
- 	usb_stor_access_xfer_buf(buffer, buflen, srb, &sg, &offset,
- 			TO_XFER_BUF);
--	if (buflen < srb->request_bufflen)
--		srb->resid = srb->request_bufflen - buflen;
-+	if (buflen < scsi_bufflen(srb))
-+		scsi_set_resid(srb, scsi_bufflen(srb) - buflen);
- }
-diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c
-index 7c9593b..8c1e295 100644
---- a/drivers/usb/storage/scsiglue.c
-+++ b/drivers/usb/storage/scsiglue.c
-@@ -81,6 +81,16 @@ static int slave_alloc (struct scsi_device *sdev)
- 	 */
- 	sdev->inquiry_len = 36;
+ 		blk++;
+ 	}
+@@ -817,11 +819,9 @@ void gfs2_rgrp_repolish_clones(struct gfs2_rgrpd *rgd)
  
-+	/* Scatter-gather buffers (all but the last) must have a length
-+	 * divisible by the bulk maxpacket size.  Otherwise a data packet
-+	 * would end up being short, causing a premature end to the data
-+	 * transfer.  Since high-speed bulk pipes have a maxpacket size
-+	 * of 512, we'll use that as the scsi device queue's DMA alignment
-+	 * mask.  Guaranteeing proper alignment of the first buffer will
-+	 * have the desired effect because, except at the beginning and
-+	 * the end, scatter-gather buffers follow page boundaries. */
-+	blk_queue_update_dma_alignment(sdev->request_queue, (512 - 1));
-+
- 	/*
- 	 * The UFI spec treates the Peripheral Qualifier bits in an
- 	 * INQUIRY result as reserved and requires devices to set them
-@@ -100,16 +110,6 @@ static int slave_configure(struct scsi_device *sdev)
+ struct gfs2_alloc *gfs2_alloc_get(struct gfs2_inode *ip)
  {
- 	struct us_data *us = host_to_us(sdev->host);
- 
--	/* Scatter-gather buffers (all but the last) must have a length
--	 * divisible by the bulk maxpacket size.  Otherwise a data packet
--	 * would end up being short, causing a premature end to the data
--	 * transfer.  Since high-speed bulk pipes have a maxpacket size
--	 * of 512, we'll use that as the scsi device queue's DMA alignment
--	 * mask.  Guaranteeing proper alignment of the first buffer will
--	 * have the desired effect because, except at the beginning and
--	 * the end, scatter-gather buffers follow page boundaries. */
--	blk_queue_dma_alignment(sdev->request_queue, (512 - 1));
+-	struct gfs2_alloc *al = &ip->i_alloc;
 -
- 	/* Many devices have trouble transfering more than 32KB at a time,
- 	 * while others have trouble with more than 64K. At this time we
- 	 * are limiting both to 32K (64 sectores).
-@@ -187,6 +187,10 @@ static int slave_configure(struct scsi_device *sdev)
- 		 * automatically, requiring a START-STOP UNIT command. */
- 		sdev->allow_restart = 1;
- 
-+		/* Some USB cardreaders have trouble reading an sdcard's last
-+		 * sector in a larger then 1 sector read, since the performance
-+		 * impact is negible we set this flag for all USB disks */
-+		sdev->last_sector_bug = 1;
- 	} else {
+-	/* FIXME: Should assert that the correct locks are held here... */
+-	memset(al, 0, sizeof(*al));
+-	return al;
++	BUG_ON(ip->i_alloc != NULL);
++	ip->i_alloc = kzalloc(sizeof(struct gfs2_alloc), GFP_KERNEL);
++	return ip->i_alloc;
+ }
  
- 		/* Non-disk-type devices don't need to blacklist any pages
-diff --git a/drivers/usb/storage/sddr09.c b/drivers/usb/storage/sddr09.c
-index b12202c..8972b17 100644
---- a/drivers/usb/storage/sddr09.c
-+++ b/drivers/usb/storage/sddr09.c
-@@ -1623,7 +1623,7 @@ int sddr09_transport(struct scsi_cmnd *srb, struct us_data *us)
- 		return USB_STOR_TRANSPORT_ERROR;
- 	}
+ /**
+@@ -1059,26 +1059,34 @@ static struct inode *get_local_rgrp(struct gfs2_inode *ip, u64 *last_unlinked)
+ 	struct inode *inode = NULL;
+ 	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+ 	struct gfs2_rgrpd *rgd, *begin = NULL;
+-	struct gfs2_alloc *al = &ip->i_alloc;
++	struct gfs2_alloc *al = ip->i_alloc;
+ 	int flags = LM_FLAG_TRY;
+ 	int skipped = 0;
+ 	int loops = 0;
+-	int error;
++	int error, rg_locked;
  
--	if (srb->request_bufflen == 0)
-+	if (scsi_bufflen(srb) == 0)
- 		return USB_STOR_TRANSPORT_GOOD;
+ 	/* Try recently successful rgrps */
  
- 	if (srb->sc_data_direction == DMA_TO_DEVICE ||
-@@ -1634,12 +1634,9 @@ int sddr09_transport(struct scsi_cmnd *srb, struct us_data *us)
- 		US_DEBUGP("SDDR09: %s %d bytes\n",
- 			  (srb->sc_data_direction == DMA_TO_DEVICE) ?
- 			  "sending" : "receiving",
--			  srb->request_bufflen);
-+			  scsi_bufflen(srb));
+ 	rgd = recent_rgrp_first(sdp, ip->i_last_rg_alloc);
  
--		result = usb_stor_bulk_transfer_sg(us, pipe,
--					srb->request_buffer,
--					srb->request_bufflen,
--					srb->use_sg, &srb->resid);
-+		result = usb_stor_bulk_srb(us, pipe, srb);
+ 	while (rgd) {
+-		error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE,
+-					   LM_FLAG_TRY, &al->al_rgd_gh);
++		rg_locked = 0;
++
++		if (gfs2_glock_is_locked_by_me(rgd->rd_gl)) {
++			rg_locked = 1;
++			error = 0;
++		} else {
++			error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE,
++						   LM_FLAG_TRY, &al->al_rgd_gh);
++		}
+ 		switch (error) {
+ 		case 0:
+ 			if (try_rgrp_fit(rgd, al))
+ 				goto out;
+ 			if (rgd->rd_flags & GFS2_RDF_CHECK)
+ 				inode = try_rgrp_unlink(rgd, last_unlinked);
+-			gfs2_glock_dq_uninit(&al->al_rgd_gh);
++			if (!rg_locked)
++				gfs2_glock_dq_uninit(&al->al_rgd_gh);
+ 			if (inode)
+ 				return inode;
+ 			rgd = recent_rgrp_next(rgd, 1);
+@@ -1098,15 +1106,23 @@ static struct inode *get_local_rgrp(struct gfs2_inode *ip, u64 *last_unlinked)
+ 	begin = rgd = forward_rgrp_get(sdp);
  
- 		return (result == USB_STOR_XFER_GOOD ?
- 			USB_STOR_TRANSPORT_GOOD : USB_STOR_TRANSPORT_ERROR);
-diff --git a/drivers/usb/storage/shuttle_usbat.c b/drivers/usb/storage/shuttle_usbat.c
-index cb22a9a..570c125 100644
---- a/drivers/usb/storage/shuttle_usbat.c
-+++ b/drivers/usb/storage/shuttle_usbat.c
-@@ -130,7 +130,7 @@ static int usbat_write(struct us_data *us,
-  * Convenience function to perform a bulk read
-  */
- static int usbat_bulk_read(struct us_data *us,
--			   unsigned char *data,
-+			   void* buf,
- 			   unsigned int len,
- 			   int use_sg)
+ 	for (;;) {
+-		error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE, flags,
+-					  &al->al_rgd_gh);
++		rg_locked = 0;
++
++		if (gfs2_glock_is_locked_by_me(rgd->rd_gl)) {
++			rg_locked = 1;
++			error = 0;
++		} else {
++			error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE, flags,
++						   &al->al_rgd_gh);
++		}
+ 		switch (error) {
+ 		case 0:
+ 			if (try_rgrp_fit(rgd, al))
+ 				goto out;
+ 			if (rgd->rd_flags & GFS2_RDF_CHECK)
+ 				inode = try_rgrp_unlink(rgd, last_unlinked);
+-			gfs2_glock_dq_uninit(&al->al_rgd_gh);
++			if (!rg_locked)
++				gfs2_glock_dq_uninit(&al->al_rgd_gh);
+ 			if (inode)
+ 				return inode;
+ 			break;
+@@ -1158,7 +1174,7 @@ out:
+ int gfs2_inplace_reserve_i(struct gfs2_inode *ip, char *file, unsigned int line)
  {
-@@ -138,14 +138,14 @@ static int usbat_bulk_read(struct us_data *us,
- 		return USB_STOR_XFER_GOOD;
+ 	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+-	struct gfs2_alloc *al = &ip->i_alloc;
++	struct gfs2_alloc *al = ip->i_alloc;
+ 	struct inode *inode;
+ 	int error = 0;
+ 	u64 last_unlinked = NO_BLOCK;
+@@ -1204,7 +1220,7 @@ try_again:
+ void gfs2_inplace_release(struct gfs2_inode *ip)
+ {
+ 	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+-	struct gfs2_alloc *al = &ip->i_alloc;
++	struct gfs2_alloc *al = ip->i_alloc;
  
- 	US_DEBUGP("usbat_bulk_read: len = %d\n", len);
--	return usb_stor_bulk_transfer_sg(us, us->recv_bulk_pipe, data, len, use_sg, NULL);
-+	return usb_stor_bulk_transfer_sg(us, us->recv_bulk_pipe, buf, len, use_sg, NULL);
+ 	if (gfs2_assert_warn(sdp, al->al_alloced <= al->al_requested) == -1)
+ 		fs_warn(sdp, "al_alloced = %u, al_requested = %u "
+@@ -1213,7 +1229,8 @@ void gfs2_inplace_release(struct gfs2_inode *ip)
+ 			     al->al_line);
+ 
+ 	al->al_rgd = NULL;
+-	gfs2_glock_dq_uninit(&al->al_rgd_gh);
++	if (al->al_rgd_gh.gh_gl)
++		gfs2_glock_dq_uninit(&al->al_rgd_gh);
+ 	if (ip != GFS2_I(sdp->sd_rindex))
+ 		gfs2_glock_dq_uninit(&al->al_ri_gh);
+ }
+@@ -1301,11 +1318,10 @@ static u32 rgblk_search(struct gfs2_rgrpd *rgd, u32 goal,
+ 		/* The GFS2_BLKST_UNLINKED state doesn't apply to the clone
+ 		   bitmaps, so we must search the originals for that. */
+ 		if (old_state != GFS2_BLKST_UNLINKED && bi->bi_clone)
+-			blk = gfs2_bitfit(rgd, bi->bi_clone + bi->bi_offset,
++			blk = gfs2_bitfit(bi->bi_clone + bi->bi_offset,
+ 					  bi->bi_len, goal, old_state);
+ 		else
+-			blk = gfs2_bitfit(rgd,
+-					  bi->bi_bh->b_data + bi->bi_offset,
++			blk = gfs2_bitfit(bi->bi_bh->b_data + bi->bi_offset,
+ 					  bi->bi_len, goal, old_state);
+ 		if (blk != BFITNOENT)
+ 			break;
+@@ -1394,7 +1410,7 @@ static struct gfs2_rgrpd *rgblk_free(struct gfs2_sbd *sdp, u64 bstart,
+ u64 gfs2_alloc_data(struct gfs2_inode *ip)
+ {
+ 	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+-	struct gfs2_alloc *al = &ip->i_alloc;
++	struct gfs2_alloc *al = ip->i_alloc;
+ 	struct gfs2_rgrpd *rgd = al->al_rgd;
+ 	u32 goal, blk;
+ 	u64 block;
+@@ -1439,7 +1455,7 @@ u64 gfs2_alloc_data(struct gfs2_inode *ip)
+ u64 gfs2_alloc_meta(struct gfs2_inode *ip)
+ {
+ 	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+-	struct gfs2_alloc *al = &ip->i_alloc;
++	struct gfs2_alloc *al = ip->i_alloc;
+ 	struct gfs2_rgrpd *rgd = al->al_rgd;
+ 	u32 goal, blk;
+ 	u64 block;
+@@ -1485,7 +1501,7 @@ u64 gfs2_alloc_meta(struct gfs2_inode *ip)
+ u64 gfs2_alloc_di(struct gfs2_inode *dip, u64 *generation)
+ {
+ 	struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);
+-	struct gfs2_alloc *al = &dip->i_alloc;
++	struct gfs2_alloc *al = dip->i_alloc;
+ 	struct gfs2_rgrpd *rgd = al->al_rgd;
+ 	u32 blk;
+ 	u64 block;
+diff --git a/fs/gfs2/rgrp.h b/fs/gfs2/rgrp.h
+index b4c6adf..149bb16 100644
+--- a/fs/gfs2/rgrp.h
++++ b/fs/gfs2/rgrp.h
+@@ -32,7 +32,9 @@ void gfs2_rgrp_repolish_clones(struct gfs2_rgrpd *rgd);
+ struct gfs2_alloc *gfs2_alloc_get(struct gfs2_inode *ip);
+ static inline void gfs2_alloc_put(struct gfs2_inode *ip)
+ {
+-	return; /* So we can see where ip->i_alloc is used */
++	BUG_ON(ip->i_alloc == NULL);
++	kfree(ip->i_alloc);
++	ip->i_alloc = NULL;
  }
  
+ int gfs2_inplace_reserve_i(struct gfs2_inode *ip,
+diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c
+index dd3e737..ef0562c 100644
+--- a/fs/gfs2/super.c
++++ b/fs/gfs2/super.c
+@@ -1,6 +1,6 @@
  /*
-  * Convenience function to perform a bulk write
-  */
- static int usbat_bulk_write(struct us_data *us,
--			    unsigned char *data,
-+			    void* buf,
- 			    unsigned int len,
- 			    int use_sg)
+  * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
+- * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
++ * Copyright (C) 2004-2007 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
+@@ -51,13 +51,9 @@ void gfs2_tune_init(struct gfs2_tune *gt)
  {
-@@ -153,7 +153,7 @@ static int usbat_bulk_write(struct us_data *us,
- 		return USB_STOR_XFER_GOOD;
+ 	spin_lock_init(&gt->gt_spin);
  
- 	US_DEBUGP("usbat_bulk_write:  len = %d\n", len);
--	return usb_stor_bulk_transfer_sg(us, us->send_bulk_pipe, data, len, use_sg, NULL);
-+	return usb_stor_bulk_transfer_sg(us, us->send_bulk_pipe, buf, len, use_sg, NULL);
+-	gt->gt_ilimit = 100;
+-	gt->gt_ilimit_tries = 3;
+-	gt->gt_ilimit_min = 1;
+ 	gt->gt_demote_secs = 300;
+ 	gt->gt_incore_log_blocks = 1024;
+ 	gt->gt_log_flush_secs = 60;
+-	gt->gt_jindex_refresh_secs = 60;
+ 	gt->gt_recoverd_secs = 60;
+ 	gt->gt_logd_secs = 1;
+ 	gt->gt_quotad_secs = 5;
+@@ -71,10 +67,8 @@ void gfs2_tune_init(struct gfs2_tune *gt)
+ 	gt->gt_new_files_jdata = 0;
+ 	gt->gt_new_files_directio = 0;
+ 	gt->gt_max_readahead = 1 << 18;
+-	gt->gt_lockdump_size = 131072;
+ 	gt->gt_stall_secs = 600;
+ 	gt->gt_complain_secs = 10;
+-	gt->gt_reclaim_limit = 5000;
+ 	gt->gt_statfs_quantum = 30;
+ 	gt->gt_statfs_slow = 0;
  }
+@@ -393,6 +387,7 @@ int gfs2_jindex_hold(struct gfs2_sbd *sdp, struct gfs2_holder *ji_gh)
+ 		if (!jd)
+ 			break;
  
- /*
-@@ -314,7 +314,7 @@ static int usbat_wait_not_busy(struct us_data *us, int minutes)
-  * Read block data from the data register
-  */
- static int usbat_read_block(struct us_data *us,
--			    unsigned char *content,
-+			    void* buf,
- 			    unsigned short len,
- 			    int use_sg)
++		INIT_LIST_HEAD(&jd->extent_list);
+ 		jd->jd_inode = gfs2_lookupi(sdp->sd_jindex, &name, 1, NULL);
+ 		if (!jd->jd_inode || IS_ERR(jd->jd_inode)) {
+ 			if (!jd->jd_inode)
+@@ -422,8 +417,9 @@ int gfs2_jindex_hold(struct gfs2_sbd *sdp, struct gfs2_holder *ji_gh)
+ 
+ void gfs2_jindex_free(struct gfs2_sbd *sdp)
  {
-@@ -337,7 +337,7 @@ static int usbat_read_block(struct us_data *us,
- 	if (result != USB_STOR_XFER_GOOD)
- 		return USB_STOR_TRANSPORT_ERROR;
+-	struct list_head list;
++	struct list_head list, *head;
+ 	struct gfs2_jdesc *jd;
++	struct gfs2_journal_extent *jext;
  
--	result = usbat_bulk_read(us, content, len, use_sg);
-+	result = usbat_bulk_read(us, buf, len, use_sg);
- 	return (result == USB_STOR_XFER_GOOD ?
- 			USB_STOR_TRANSPORT_GOOD : USB_STOR_TRANSPORT_ERROR);
- }
-@@ -347,7 +347,7 @@ static int usbat_read_block(struct us_data *us,
-  */
- static int usbat_write_block(struct us_data *us,
- 			     unsigned char access,
--			     unsigned char *content,
-+			     void* buf,
- 			     unsigned short len,
- 			     int minutes,
- 			     int use_sg)
-@@ -372,7 +372,7 @@ static int usbat_write_block(struct us_data *us,
- 	if (result != USB_STOR_XFER_GOOD)
- 		return USB_STOR_TRANSPORT_ERROR;
+ 	spin_lock(&sdp->sd_jindex_spin);
+ 	list_add(&list, &sdp->sd_jindex_list);
+@@ -433,6 +429,14 @@ void gfs2_jindex_free(struct gfs2_sbd *sdp)
  
--	result = usbat_bulk_write(us, content, len, use_sg);
-+	result = usbat_bulk_write(us, buf, len, use_sg);
- 	if (result != USB_STOR_XFER_GOOD)
- 		return USB_STOR_TRANSPORT_ERROR;
+ 	while (!list_empty(&list)) {
+ 		jd = list_entry(list.next, struct gfs2_jdesc, jd_list);
++		head = &jd->extent_list;
++		while (!list_empty(head)) {
++			jext = list_entry(head->next,
++					  struct gfs2_journal_extent,
++					  extent_list);
++			list_del(&jext->extent_list);
++			kfree(jext);
++		}
+ 		list_del(&jd->jd_list);
+ 		iput(jd->jd_inode);
+ 		kfree(jd);
+@@ -543,7 +547,6 @@ int gfs2_make_fs_rw(struct gfs2_sbd *sdp)
+ 	if (error)
+ 		return error;
  
-@@ -392,7 +392,7 @@ static int usbat_hp8200e_rw_block_test(struct us_data *us,
- 				       unsigned char timeout,
- 				       unsigned char qualifier,
- 				       int direction,
--				       unsigned char *content,
-+				       void *buf,
- 				       unsigned short len,
- 				       int use_sg,
- 				       int minutes)
-@@ -472,7 +472,7 @@ static int usbat_hp8200e_rw_block_test(struct us_data *us,
- 		}
+-	gfs2_meta_cache_flush(ip);
+ 	j_gl->gl_ops->go_inval(j_gl, DIO_METADATA);
  
- 		result = usb_stor_bulk_transfer_sg(us,
--			pipe, content, len, use_sg, NULL);
-+			pipe, buf, len, use_sg, NULL);
+ 	error = gfs2_find_jhead(sdp->sd_jdesc, &head);
+@@ -686,9 +689,7 @@ void gfs2_statfs_change(struct gfs2_sbd *sdp, s64 total, s64 free,
+ 	if (error)
+ 		return;
  
- 		/*
- 		 * If we get a stall on the bulk download, we'll retry
-@@ -606,7 +606,7 @@ static int usbat_multiple_write(struct us_data *us,
-  * other related details) are defined beforehand with _set_shuttle_features().
-  */
- static int usbat_read_blocks(struct us_data *us,
--			     unsigned char *buffer,
-+			     void* buffer,
- 			     int len,
- 			     int use_sg)
- {
-@@ -648,7 +648,7 @@ static int usbat_read_blocks(struct us_data *us,
-  * other related details) are defined beforehand with _set_shuttle_features().
-  */
- static int usbat_write_blocks(struct us_data *us,
--							  unsigned char *buffer,
-+			      void* buffer,
- 			      int len,
- 			      int use_sg)
- {
-@@ -1170,15 +1170,15 @@ static int usbat_hp8200e_handle_read10(struct us_data *us,
- 	US_DEBUGP("handle_read10: transfersize %d\n",
- 		srb->transfersize);
+-	mutex_lock(&sdp->sd_statfs_mutex);
+ 	gfs2_trans_add_bh(l_ip->i_gl, l_bh, 1);
+-	mutex_unlock(&sdp->sd_statfs_mutex);
  
--	if (srb->request_bufflen < 0x10000) {
-+	if (scsi_bufflen(srb) < 0x10000) {
+ 	spin_lock(&sdp->sd_statfs_spin);
+ 	l_sc->sc_total += total;
+@@ -736,9 +737,7 @@ int gfs2_statfs_sync(struct gfs2_sbd *sdp)
+ 	if (error)
+ 		goto out_bh2;
  
- 		result = usbat_hp8200e_rw_block_test(us, USBAT_ATA, 
- 			registers, data, 19,
- 			USBAT_ATA_DATA, USBAT_ATA_STATUS, 0xFD,
- 			(USBAT_QUAL_FCQ | USBAT_QUAL_ALQ),
- 			DMA_FROM_DEVICE,
--			srb->request_buffer, 
--			srb->request_bufflen, srb->use_sg, 1);
-+			scsi_sglist(srb),
-+			scsi_bufflen(srb), scsi_sg_count(srb), 1);
+-	mutex_lock(&sdp->sd_statfs_mutex);
+ 	gfs2_trans_add_bh(l_ip->i_gl, l_bh, 1);
+-	mutex_unlock(&sdp->sd_statfs_mutex);
  
- 		return result;
- 	}
-@@ -1196,7 +1196,7 @@ static int usbat_hp8200e_handle_read10(struct us_data *us,
- 		len <<= 16;
- 		len |= data[7+7];
- 		US_DEBUGP("handle_read10: GPCMD_READ_CD: len %d\n", len);
--		srb->transfersize = srb->request_bufflen/len;
-+		srb->transfersize = scsi_bufflen(srb)/len;
- 	}
+ 	spin_lock(&sdp->sd_statfs_spin);
+ 	m_sc->sc_total += l_sc->sc_total;
+diff --git a/fs/gfs2/sys.c b/fs/gfs2/sys.c
+index 06e0b77..eaa3b7b 100644
+--- a/fs/gfs2/sys.c
++++ b/fs/gfs2/sys.c
+@@ -32,7 +32,8 @@ spinlock_t gfs2_sys_margs_lock;
  
- 	if (!srb->transfersize)  {
-@@ -1213,7 +1213,7 @@ static int usbat_hp8200e_handle_read10(struct us_data *us,
+ static ssize_t id_show(struct gfs2_sbd *sdp, char *buf)
+ {
+-	return snprintf(buf, PAGE_SIZE, "%s\n", sdp->sd_vfs->s_id);
++	return snprintf(buf, PAGE_SIZE, "%u:%u\n",
++			MAJOR(sdp->sd_vfs->s_dev), MINOR(sdp->sd_vfs->s_dev));
+ }
  
- 	len = (65535/srb->transfersize) * srb->transfersize;
- 	US_DEBUGP("Max read is %d bytes\n", len);
--	len = min(len, srb->request_bufflen);
-+	len = min(len, scsi_bufflen(srb));
- 	buffer = kmalloc(len, GFP_NOIO);
- 	if (buffer == NULL) /* bloody hell! */
- 		return USB_STOR_TRANSPORT_FAILED;
-@@ -1222,10 +1222,10 @@ static int usbat_hp8200e_handle_read10(struct us_data *us,
- 	sector |= short_pack(data[7+5], data[7+4]);
- 	transferred = 0;
+ static ssize_t fsname_show(struct gfs2_sbd *sdp, char *buf)
+@@ -221,9 +222,7 @@ static struct kobj_type gfs2_ktype = {
+ 	.sysfs_ops     = &gfs2_attr_ops,
+ };
  
--	while (transferred != srb->request_bufflen) {
-+	while (transferred != scsi_bufflen(srb)) {
+-static struct kset gfs2_kset = {
+-	.ktype  = &gfs2_ktype,
+-};
++static struct kset *gfs2_kset;
  
--		if (len > srb->request_bufflen - transferred)
--			len = srb->request_bufflen - transferred;
-+		if (len > scsi_bufflen(srb) - transferred)
-+			len = scsi_bufflen(srb) - transferred;
+ /*
+  * display struct lm_lockstruct fields
+@@ -427,13 +426,11 @@ TUNE_ATTR_2(name, name##_store)
+ TUNE_ATTR(demote_secs, 0);
+ TUNE_ATTR(incore_log_blocks, 0);
+ TUNE_ATTR(log_flush_secs, 0);
+-TUNE_ATTR(jindex_refresh_secs, 0);
+ TUNE_ATTR(quota_warn_period, 0);
+ TUNE_ATTR(quota_quantum, 0);
+ TUNE_ATTR(atime_quantum, 0);
+ TUNE_ATTR(max_readahead, 0);
+ TUNE_ATTR(complain_secs, 0);
+-TUNE_ATTR(reclaim_limit, 0);
+ TUNE_ATTR(statfs_slow, 0);
+ TUNE_ATTR(new_files_jdata, 0);
+ TUNE_ATTR(new_files_directio, 0);
+@@ -450,13 +447,11 @@ static struct attribute *tune_attrs[] = {
+ 	&tune_attr_demote_secs.attr,
+ 	&tune_attr_incore_log_blocks.attr,
+ 	&tune_attr_log_flush_secs.attr,
+-	&tune_attr_jindex_refresh_secs.attr,
+ 	&tune_attr_quota_warn_period.attr,
+ 	&tune_attr_quota_quantum.attr,
+ 	&tune_attr_atime_quantum.attr,
+ 	&tune_attr_max_readahead.attr,
+ 	&tune_attr_complain_secs.attr,
+-	&tune_attr_reclaim_limit.attr,
+ 	&tune_attr_statfs_slow.attr,
+ 	&tune_attr_quota_simul_sync.attr,
+ 	&tune_attr_quota_cache_secs.attr,
+@@ -495,14 +490,9 @@ int gfs2_sys_fs_add(struct gfs2_sbd *sdp)
+ {
+ 	int error;
  
- 		data[3] = len&0xFF; 	  /* (cylL) = expected length (L) */
- 		data[4] = (len>>8)&0xFF;  /* (cylH) = expected length (H) */
-@@ -1261,7 +1261,7 @@ static int usbat_hp8200e_handle_read10(struct us_data *us,
- 		transferred += len;
- 		sector += len / srb->transfersize;
+-	sdp->sd_kobj.kset = &gfs2_kset;
+-	sdp->sd_kobj.ktype = &gfs2_ktype;
+-
+-	error = kobject_set_name(&sdp->sd_kobj, "%s", sdp->sd_table_name);
+-	if (error)
+-		goto fail;
+-
+-	error = kobject_register(&sdp->sd_kobj);
++	sdp->sd_kobj.kset = gfs2_kset;
++	error = kobject_init_and_add(&sdp->sd_kobj, &gfs2_ktype, NULL,
++				     "%s", sdp->sd_table_name);
+ 	if (error)
+ 		goto fail;
  
--	} /* while transferred != srb->request_bufflen */
-+	} /* while transferred != scsi_bufflen(srb) */
+@@ -522,6 +512,7 @@ int gfs2_sys_fs_add(struct gfs2_sbd *sdp)
+ 	if (error)
+ 		goto fail_args;
  
- 	kfree(buffer);
- 	return result;
-@@ -1429,9 +1429,8 @@ static int usbat_hp8200e_transport(struct scsi_cmnd *srb, struct us_data *us)
- 	unsigned char data[32];
- 	unsigned int len;
- 	int i;
--	char string[64];
++	kobject_uevent(&sdp->sd_kobj, KOBJ_ADD);
+ 	return 0;
  
--	len = srb->request_bufflen;
-+	len = scsi_bufflen(srb);
+ fail_args:
+@@ -531,7 +522,7 @@ fail_counters:
+ fail_lockstruct:
+ 	sysfs_remove_group(&sdp->sd_kobj, &lockstruct_group);
+ fail_reg:
+-	kobject_unregister(&sdp->sd_kobj);
++	kobject_put(&sdp->sd_kobj);
+ fail:
+ 	fs_err(sdp, "error %d adding sysfs files", error);
+ 	return error;
+@@ -543,21 +534,22 @@ void gfs2_sys_fs_del(struct gfs2_sbd *sdp)
+ 	sysfs_remove_group(&sdp->sd_kobj, &args_group);
+ 	sysfs_remove_group(&sdp->sd_kobj, &counters_group);
+ 	sysfs_remove_group(&sdp->sd_kobj, &lockstruct_group);
+-	kobject_unregister(&sdp->sd_kobj);
++	kobject_put(&sdp->sd_kobj);
+ }
  
- 	/* Send A0 (ATA PACKET COMMAND).
- 	   Note: I guess we're never going to get any of the ATA
-@@ -1472,8 +1471,8 @@ static int usbat_hp8200e_transport(struct scsi_cmnd *srb, struct us_data *us)
- 			USBAT_ATA_DATA, USBAT_ATA_STATUS, 0xFD,
- 			(USBAT_QUAL_FCQ | USBAT_QUAL_ALQ),
- 			DMA_TO_DEVICE,
--			srb->request_buffer, 
--			len, srb->use_sg, 10);
-+			scsi_sglist(srb),
-+			len, scsi_sg_count(srb), 10);
+ int gfs2_sys_init(void)
+ {
+ 	gfs2_sys_margs = NULL;
+ 	spin_lock_init(&gfs2_sys_margs_lock);
+-	kobject_set_name(&gfs2_kset.kobj, "gfs2");
+-	kobj_set_kset_s(&gfs2_kset, fs_subsys);
+-	return kset_register(&gfs2_kset);
++	gfs2_kset = kset_create_and_add("gfs2", NULL, fs_kobj);
++	if (!gfs2_kset)
++		return -ENOMEM;
++	return 0;
+ }
  
- 		if (result == USB_STOR_TRANSPORT_GOOD) {
- 			transferred += len;
-@@ -1540,23 +1539,8 @@ static int usbat_hp8200e_transport(struct scsi_cmnd *srb, struct us_data *us)
- 			len = *status;
+ void gfs2_sys_uninit(void)
+ {
+ 	kfree(gfs2_sys_margs);
+-	kset_unregister(&gfs2_kset);
++	kset_unregister(gfs2_kset);
+ }
  
+diff --git a/fs/gfs2/trans.c b/fs/gfs2/trans.c
+index 717983e..73e5d92 100644
+--- a/fs/gfs2/trans.c
++++ b/fs/gfs2/trans.c
+@@ -114,11 +114,6 @@ void gfs2_trans_end(struct gfs2_sbd *sdp)
+ 		gfs2_log_flush(sdp, NULL);
+ }
  
--		result = usbat_read_block(us, srb->request_buffer, len, srb->use_sg);
+-void gfs2_trans_add_gl(struct gfs2_glock *gl)
+-{
+-	lops_add(gl->gl_sbd, &gl->gl_le);
+-}
 -
--		/* Debug-print the first 32 bytes of the transfer */
+ /**
+  * gfs2_trans_add_bh - Add a to-be-modified buffer to the current transaction
+  * @gl: the glock the buffer belongs to
+diff --git a/fs/gfs2/trans.h b/fs/gfs2/trans.h
+index 043d5f4..e826f0d 100644
+--- a/fs/gfs2/trans.h
++++ b/fs/gfs2/trans.h
+@@ -30,7 +30,6 @@ int gfs2_trans_begin(struct gfs2_sbd *sdp, unsigned int blocks,
+ 
+ void gfs2_trans_end(struct gfs2_sbd *sdp);
+ 
+-void gfs2_trans_add_gl(struct gfs2_glock *gl);
+ void gfs2_trans_add_bh(struct gfs2_glock *gl, struct buffer_head *bh, int meta);
+ void gfs2_trans_add_revoke(struct gfs2_sbd *sdp, struct gfs2_bufdata *bd);
+ void gfs2_trans_add_unrevoke(struct gfs2_sbd *sdp, u64 blkno);
+diff --git a/fs/ioprio.c b/fs/ioprio.c
+index e4e01bc..c4a1c3c 100644
+--- a/fs/ioprio.c
++++ b/fs/ioprio.c
+@@ -41,18 +41,28 @@ static int set_task_ioprio(struct task_struct *task, int ioprio)
+ 		return err;
+ 
+ 	task_lock(task);
++	do {
++		ioc = task->io_context;
++		/* see wmb() in current_io_context() */
++		smp_read_barrier_depends();
++		if (ioc)
++			break;
+ 
+-	task->ioprio = ioprio;
 -
--		if (!srb->use_sg) {
--			string[0] = 0;
--			for (i=0; i<len && i<32; i++) {
--				sprintf(string+strlen(string), "%02X ",
--				  ((unsigned char *)srb->request_buffer)[i]);
--				if ((i%16)==15) {
--					US_DEBUGP("%s\n", string);
--					string[0] = 0;
--				}
--			}
--			if (string[0]!=0)
--				US_DEBUGP("%s\n", string);
--		}
-+		result = usbat_read_block(us, scsi_sglist(srb), len,
-+			                                   scsi_sg_count(srb));
- 	}
+-	ioc = task->io_context;
+-	/* see wmb() in current_io_context() */
+-	smp_read_barrier_depends();
++		ioc = alloc_io_context(GFP_ATOMIC, -1);
++		if (!ioc) {
++			err = -ENOMEM;
++			break;
++		}
++		task->io_context = ioc;
++	} while (1);
  
- 	return result;
-diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c
-index c646750..d9f4912 100644
---- a/drivers/usb/storage/transport.c
-+++ b/drivers/usb/storage/transport.c
-@@ -459,6 +459,22 @@ static int usb_stor_bulk_transfer_sglist(struct us_data *us, unsigned int pipe,
- }
+-	if (ioc)
++	if (!err) {
++		ioc->ioprio = ioprio;
+ 		ioc->ioprio_changed = 1;
++	}
  
- /*
-+ * Common used function. Transfer a complete command
-+ * via usb_stor_bulk_transfer_sglist() above. Set cmnd resid
-+ */
-+int usb_stor_bulk_srb(struct us_data* us, unsigned int pipe,
-+		      struct scsi_cmnd* srb)
-+{
-+	unsigned int partial;
-+	int result = usb_stor_bulk_transfer_sglist(us, pipe, scsi_sglist(srb),
-+				      scsi_sg_count(srb), scsi_bufflen(srb),
-+				      &partial);
-+
-+	scsi_set_resid(srb, scsi_bufflen(srb) - partial);
-+	return result;
-+}
-+
-+/*
-  * Transfer an entire SCSI command's worth of data payload over the bulk
-  * pipe.
-  *
-@@ -508,7 +524,7 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
- 	int result;
+ 	task_unlock(task);
+-	return 0;
++	return err;
+ }
  
- 	/* send the command to the transport layer */
--	srb->resid = 0;
-+	scsi_set_resid(srb, 0);
- 	result = us->transport(srb, us);
+ asmlinkage long sys_ioprio_set(int which, int who, int ioprio)
+@@ -75,8 +85,6 @@ asmlinkage long sys_ioprio_set(int which, int who, int ioprio)
  
- 	/* if the command gets aborted by the higher layers, we need to
-@@ -568,7 +584,7 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
- 	 * A short transfer on a command where we don't expect it
- 	 * is unusual, but it doesn't mean we need to auto-sense.
- 	 */
--	if ((srb->resid > 0) &&
-+	if ((scsi_get_resid(srb) > 0) &&
- 	    !((srb->cmnd[0] == REQUEST_SENSE) ||
- 	      (srb->cmnd[0] == INQUIRY) ||
- 	      (srb->cmnd[0] == MODE_SENSE) ||
-@@ -593,7 +609,7 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
- 			srb->cmd_len = 12;
+ 			break;
+ 		case IOPRIO_CLASS_IDLE:
+-			if (!capable(CAP_SYS_ADMIN))
+-				return -EPERM;
+ 			break;
+ 		case IOPRIO_CLASS_NONE:
+ 			if (data)
+@@ -148,7 +156,9 @@ static int get_task_ioprio(struct task_struct *p)
+ 	ret = security_task_getioprio(p);
+ 	if (ret)
+ 		goto out;
+-	ret = p->ioprio;
++	ret = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_NONE, IOPRIO_NORM);
++	if (p->io_context)
++		ret = p->io_context->ioprio;
+ out:
+ 	return ret;
+ }
+diff --git a/fs/jfs/jfs_dtree.c b/fs/jfs/jfs_dtree.c
+index df25ecc..4dcc058 100644
+--- a/fs/jfs/jfs_dtree.c
++++ b/fs/jfs/jfs_dtree.c
+@@ -284,11 +284,11 @@ static struct dir_table_slot *find_index(struct inode *ip, u32 index,
+ 			release_metapage(*mp);
+ 			*mp = NULL;
+ 		}
+-		if (*mp == 0) {
++		if (!(*mp)) {
+ 			*lblock = blkno;
+ 			*mp = read_index_page(ip, blkno);
+ 		}
+-		if (*mp == 0) {
++		if (!(*mp)) {
+ 			jfs_err("free_index: error reading directory table");
+ 			return NULL;
+ 		}
+@@ -413,7 +413,8 @@ static u32 add_index(tid_t tid, struct inode *ip, s64 bn, int slot)
+ 		}
+ 		ip->i_size = PSIZE;
  
- 		/* issue the auto-sense command */
--		srb->resid = 0;
-+		scsi_set_resid(srb, 0);
- 		temp_result = us->transport(us->srb, us);
+-		if ((mp = get_index_page(ip, 0)) == 0) {
++		mp = get_index_page(ip, 0);
++		if (!mp) {
+ 			jfs_err("add_index: get_metapage failed!");
+ 			xtTruncate(tid, ip, 0, COMMIT_PWMAP);
+ 			memcpy(&jfs_ip->i_dirtable, temp_table,
+@@ -461,7 +462,7 @@ static u32 add_index(tid_t tid, struct inode *ip, s64 bn, int slot)
+ 	} else
+ 		mp = read_index_page(ip, blkno);
  
- 		/* let's clean up right away */
-@@ -649,7 +665,7 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
+-	if (mp == 0) {
++	if (!mp) {
+ 		jfs_err("add_index: get/read_metapage failed!");
+ 		goto clean_up;
+ 	}
+@@ -499,7 +500,7 @@ static void free_index(tid_t tid, struct inode *ip, u32 index, u32 next)
  
- 	/* Did we transfer less than the minimum amount required? */
- 	if (srb->result == SAM_STAT_GOOD &&
--			srb->request_bufflen - srb->resid < srb->underflow)
-+			scsi_bufflen(srb) - scsi_get_resid(srb) < srb->underflow)
- 		srb->result = (DID_ERROR << 16) | (SUGGEST_RETRY << 24);
+ 	dirtab_slot = find_index(ip, index, &mp, &lblock);
  
- 	return;
-@@ -708,7 +724,7 @@ void usb_stor_stop_transport(struct us_data *us)
+-	if (dirtab_slot == 0)
++	if (!dirtab_slot)
+ 		return;
  
- int usb_stor_CBI_transport(struct scsi_cmnd *srb, struct us_data *us)
- {
--	unsigned int transfer_length = srb->request_bufflen;
-+	unsigned int transfer_length = scsi_bufflen(srb);
- 	unsigned int pipe = 0;
- 	int result;
+ 	dirtab_slot->flag = DIR_INDEX_FREE;
+@@ -526,7 +527,7 @@ static void modify_index(tid_t tid, struct inode *ip, u32 index, s64 bn,
  
-@@ -737,9 +753,7 @@ int usb_stor_CBI_transport(struct scsi_cmnd *srb, struct us_data *us)
- 	if (transfer_length) {
- 		pipe = srb->sc_data_direction == DMA_FROM_DEVICE ? 
- 				us->recv_bulk_pipe : us->send_bulk_pipe;
--		result = usb_stor_bulk_transfer_sg(us, pipe,
--					srb->request_buffer, transfer_length,
--					srb->use_sg, &srb->resid);
-+		result = usb_stor_bulk_srb(us, pipe, srb);
- 		US_DEBUGP("CBI data stage result is 0x%x\n", result);
+ 	dirtab_slot = find_index(ip, index, mp, lblock);
  
- 		/* if we stalled the data transfer it means command failed */
-@@ -808,7 +822,7 @@ int usb_stor_CBI_transport(struct scsi_cmnd *srb, struct us_data *us)
-  */
- int usb_stor_CB_transport(struct scsi_cmnd *srb, struct us_data *us)
- {
--	unsigned int transfer_length = srb->request_bufflen;
-+	unsigned int transfer_length = scsi_bufflen(srb);
- 	int result;
+-	if (dirtab_slot == 0)
++	if (!dirtab_slot)
+ 		return;
  
- 	/* COMMAND STAGE */
-@@ -836,9 +850,7 @@ int usb_stor_CB_transport(struct scsi_cmnd *srb, struct us_data *us)
- 	if (transfer_length) {
- 		unsigned int pipe = srb->sc_data_direction == DMA_FROM_DEVICE ? 
- 				us->recv_bulk_pipe : us->send_bulk_pipe;
--		result = usb_stor_bulk_transfer_sg(us, pipe,
--					srb->request_buffer, transfer_length,
--					srb->use_sg, &srb->resid);
-+		result = usb_stor_bulk_srb(us, pipe, srb);
- 		US_DEBUGP("CB data stage result is 0x%x\n", result);
+ 	DTSaddress(dirtab_slot, bn);
+@@ -552,7 +553,7 @@ static int read_index(struct inode *ip, u32 index,
+ 	struct dir_table_slot *slot;
  
- 		/* if we stalled the data transfer it means command failed */
-@@ -904,7 +916,7 @@ int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us)
- {
- 	struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
- 	struct bulk_cs_wrap *bcs = (struct bulk_cs_wrap *) us->iobuf;
--	unsigned int transfer_length = srb->request_bufflen;
-+	unsigned int transfer_length = scsi_bufflen(srb);
- 	unsigned int residue;
- 	int result;
- 	int fake_sense = 0;
-@@ -955,9 +967,7 @@ int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us)
- 	if (transfer_length) {
- 		unsigned int pipe = srb->sc_data_direction == DMA_FROM_DEVICE ? 
- 				us->recv_bulk_pipe : us->send_bulk_pipe;
--		result = usb_stor_bulk_transfer_sg(us, pipe,
--					srb->request_buffer, transfer_length,
--					srb->use_sg, &srb->resid);
-+		result = usb_stor_bulk_srb(us, pipe, srb);
- 		US_DEBUGP("Bulk data transfer result 0x%x\n", result);
- 		if (result == USB_STOR_XFER_ERROR)
- 			return USB_STOR_TRANSPORT_ERROR;
-@@ -1036,7 +1046,8 @@ int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us)
- 	if (residue) {
- 		if (!(us->flags & US_FL_IGNORE_RESIDUE)) {
- 			residue = min(residue, transfer_length);
--			srb->resid = max(srb->resid, (int) residue);
-+			scsi_set_resid(srb, max(scsi_get_resid(srb),
-+			                                       (int) residue));
- 		}
+ 	slot = find_index(ip, index, &mp, &lblock);
+-	if (slot == 0) {
++	if (!slot) {
+ 		return -EIO;
  	}
  
-diff --git a/drivers/usb/storage/transport.h b/drivers/usb/storage/transport.h
-index 633a715..ada7c2f 100644
---- a/drivers/usb/storage/transport.h
-+++ b/drivers/usb/storage/transport.h
-@@ -139,6 +139,8 @@ extern int usb_stor_bulk_transfer_buf(struct us_data *us, unsigned int pipe,
- 		void *buf, unsigned int length, unsigned int *act_len);
- extern int usb_stor_bulk_transfer_sg(struct us_data *us, unsigned int pipe,
- 		void *buf, unsigned int length, int use_sg, int *residual);
-+extern int usb_stor_bulk_srb(struct us_data* us, unsigned int pipe,
-+		struct scsi_cmnd* srb);
+@@ -592,10 +593,8 @@ int dtSearch(struct inode *ip, struct component_name * key, ino_t * data,
+ 	struct component_name ciKey;
+ 	struct super_block *sb = ip->i_sb;
  
- extern int usb_stor_port_reset(struct us_data *us);
- #endif
-diff --git a/drivers/video/bf54x-lq043fb.c b/drivers/video/bf54x-lq043fb.c
-index 74d11c3..c8e7427 100644
---- a/drivers/video/bf54x-lq043fb.c
-+++ b/drivers/video/bf54x-lq043fb.c
-@@ -224,7 +224,8 @@ static int config_dma(struct bfin_bf54xfb_info *fbi)
- 	set_dma_config(CH_EPPI0,
- 		       set_bfin_dma_config(DIR_READ, DMA_FLOW_AUTO,
- 					   INTR_DISABLE, DIMENSION_2D,
--					   DATA_SIZE_32));
-+					   DATA_SIZE_32,
-+					   DMA_NOSYNC_KEEP_DMA_BUF));
- 	set_dma_x_count(CH_EPPI0, (LCD_X_RES * LCD_BPP) / DMA_BUS_SIZE);
- 	set_dma_x_modify(CH_EPPI0, DMA_BUS_SIZE / 8);
- 	set_dma_y_count(CH_EPPI0, LCD_Y_RES);
-@@ -263,8 +264,7 @@ static int request_ports(struct bfin_bf54xfb_info *fbi)
- 		}
+-	ciKey.name =
+-	    (wchar_t *) kmalloc((JFS_NAME_MAX + 1) * sizeof(wchar_t),
+-				GFP_NOFS);
+-	if (ciKey.name == 0) {
++	ciKey.name = kmalloc((JFS_NAME_MAX + 1) * sizeof(wchar_t), GFP_NOFS);
++	if (!ciKey.name) {
+ 		rc = -ENOMEM;
+ 		goto dtSearch_Exit2;
  	}
+@@ -957,10 +956,8 @@ static int dtSplitUp(tid_t tid,
+ 	smp = split->mp;
+ 	sp = DT_PAGE(ip, smp);
  
--	gpio_direction_output(disp);
--	gpio_set_value(disp, 1);
-+	gpio_direction_output(disp, 1);
+-	key.name =
+-	    (wchar_t *) kmalloc((JFS_NAME_MAX + 2) * sizeof(wchar_t),
+-				GFP_NOFS);
+-	if (key.name == 0) {
++	key.name = kmalloc((JFS_NAME_MAX + 2) * sizeof(wchar_t), GFP_NOFS);
++	if (!key.name) {
+ 		DT_PUTPAGE(smp);
+ 		rc = -ENOMEM;
+ 		goto dtSplitUp_Exit;
+diff --git a/fs/jfs/jfs_dtree.h b/fs/jfs/jfs_dtree.h
+index 8561c6e..cdac2d5 100644
+--- a/fs/jfs/jfs_dtree.h
++++ b/fs/jfs/jfs_dtree.h
+@@ -74,7 +74,7 @@ struct idtentry {
+ #define DTIHDRDATALEN	11
  
- 	return 0;
- }
-diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig
-index b87ed37..2b53d1f 100644
---- a/drivers/video/console/Kconfig
-+++ b/drivers/video/console/Kconfig
-@@ -6,7 +6,7 @@ menu "Console display driver support"
+ /* compute number of slots for entry */
+-#define	NDTINTERNAL(klen) ( ((4 + (klen)) + (15 - 1)) / 15 )
++#define	NDTINTERNAL(klen) (DIV_ROUND_UP((4 + (klen)), 15))
+ 
+ 
+ /*
+@@ -133,7 +133,7 @@ struct dir_table_slot {
+ 	( ((s64)((dts)->addr1)) << 32 | __le32_to_cpu((dts)->addr2) )
  
- config VGA_CONSOLE
- 	bool "VGA text console" if EMBEDDED || !X86
--	depends on !ARCH_ACORN && !ARCH_EBSA110 && !4xx && !8xx && !SPARC && !M68K && !PARISC && !FRV && !ARCH_VERSATILE && !SUPERH && !BLACKFIN
-+	depends on !ARCH_ACORN && !ARCH_EBSA110 && !4xx && !8xx && !SPARC && !M68K && !PARISC && !FRV && !ARCH_VERSATILE && !SUPERH && !BLACKFIN && !AVR32
- 	default y
- 	help
- 	  Saying Y here will allow you to use Linux in text mode through a
-diff --git a/drivers/video/matrox/matroxfb_maven.c b/drivers/video/matrox/matroxfb_maven.c
-index 49cd53e..0cd58f8 100644
---- a/drivers/video/matrox/matroxfb_maven.c
-+++ b/drivers/video/matrox/matroxfb_maven.c
-@@ -1232,7 +1232,7 @@ static int maven_shutdown_client(struct i2c_client* clnt) {
- 	return 0;
- }
+ /* compute number of slots for entry */
+-#define	NDTLEAF_LEGACY(klen)	( ((2 + (klen)) + (15 - 1)) / 15 )
++#define	NDTLEAF_LEGACY(klen)	(DIV_ROUND_UP((2 + (klen)), 15))
+ #define	NDTLEAF	NDTINTERNAL
  
--static unsigned short normal_i2c[] = { MAVEN_I2CID, I2C_CLIENT_END };
-+static const unsigned short normal_i2c[] = { MAVEN_I2CID, I2C_CLIENT_END };
- I2C_CLIENT_INSMOD;
  
- static struct i2c_driver maven_driver;
-diff --git a/drivers/video/omap/lcd_h3.c b/drivers/video/omap/lcd_h3.c
-index c604d93..31e9783 100644
---- a/drivers/video/omap/lcd_h3.c
-+++ b/drivers/video/omap/lcd_h3.c
-@@ -21,9 +21,9 @@
+diff --git a/fs/jfs/jfs_imap.c b/fs/jfs/jfs_imap.c
+index 3870ba8..9bf29f7 100644
+--- a/fs/jfs/jfs_imap.c
++++ b/fs/jfs/jfs_imap.c
+@@ -381,7 +381,7 @@ int diRead(struct inode *ip)
  
- #include <linux/module.h>
- #include <linux/platform_device.h>
-+#include <linux/i2c/tps65010.h>
+ 	/* read the page of disk inode */
+ 	mp = read_metapage(ipimap, pageno << sbi->l2nbperpage, PSIZE, 1);
+-	if (mp == 0) {
++	if (!mp) {
+ 		jfs_err("diRead: read_metapage failed");
+ 		return -EIO;
+ 	}
+@@ -654,7 +654,7 @@ int diWrite(tid_t tid, struct inode *ip)
+ 	/* read the page of disk inode */
+       retry:
+ 	mp = read_metapage(ipimap, pageno << sbi->l2nbperpage, PSIZE, 1);
+-	if (mp == 0)
++	if (!mp)
+ 		return -EIO;
  
- #include <asm/arch/gpio.h>
--#include <asm/arch/tps65010.h>
- #include <asm/arch/omapfb.h>
+ 	/* get the pointer to the disk inode */
+diff --git a/fs/jfs/jfs_logmgr.c b/fs/jfs/jfs_logmgr.c
+index 15a3974..325a967 100644
+--- a/fs/jfs/jfs_logmgr.c
++++ b/fs/jfs/jfs_logmgr.c
+@@ -208,6 +208,17 @@ static struct lmStat {
+ } lmStat;
+ #endif
  
- #define MODULE_NAME	"omapfb-lcd_h3"
-diff --git a/drivers/w1/masters/ds2482.c b/drivers/w1/masters/ds2482.c
-index d93eb62..0fd5820 100644
---- a/drivers/w1/masters/ds2482.c
-+++ b/drivers/w1/masters/ds2482.c
-@@ -29,7 +29,7 @@
-  * However, the chip cannot be detected without doing an i2c write,
-  * so use the force module parameter.
-  */
--static unsigned short normal_i2c[] = {I2C_CLIENT_END};
-+static const unsigned short normal_i2c[] = { I2C_CLIENT_END };
++static void write_special_inodes(struct jfs_log *log,
++				 int (*writer)(struct address_space *))
++{
++	struct jfs_sb_info *sbi;
++
++	list_for_each_entry(sbi, &log->sb_list, log_list) {
++		writer(sbi->ipbmap->i_mapping);
++		writer(sbi->ipimap->i_mapping);
++		writer(sbi->direct_inode->i_mapping);
++	}
++}
  
- /**
-  * Insmod parameters
-diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
-index 52dff40..fbd6112 100644
---- a/drivers/watchdog/Kconfig
-+++ b/drivers/watchdog/Kconfig
-@@ -223,7 +223,7 @@ config DAVINCI_WATCHDOG
+ /*
+  * NAME:	lmLog()
+@@ -935,22 +946,13 @@ static int lmLogSync(struct jfs_log * log, int hard_sync)
+ 	struct lrd lrd;
+ 	int lsn;
+ 	struct logsyncblk *lp;
+-	struct jfs_sb_info *sbi;
+ 	unsigned long flags;
  
- config AT32AP700X_WDT
- 	tristate "AT32AP700x watchdog"
--	depends on CPU_AT32AP7000
-+	depends on CPU_AT32AP700X
- 	help
- 	  Watchdog timer embedded into AT32AP700x devices. This will reboot
- 	  your system when the timeout is reached.
-diff --git a/fs/Kconfig b/fs/Kconfig
-index 781b47d..9656139 100644
---- a/fs/Kconfig
-+++ b/fs/Kconfig
-@@ -440,14 +440,8 @@ config OCFS2_FS
- 	  Tools web page:      http://oss.oracle.com/projects/ocfs2-tools
- 	  OCFS2 mailing lists: http://oss.oracle.com/projects/ocfs2/mailman/
+ 	/* push dirty metapages out to disk */
+ 	if (hard_sync)
+-		list_for_each_entry(sbi, &log->sb_list, log_list) {
+-			filemap_fdatawrite(sbi->ipbmap->i_mapping);
+-			filemap_fdatawrite(sbi->ipimap->i_mapping);
+-			filemap_fdatawrite(sbi->direct_inode->i_mapping);
+-		}
++		write_special_inodes(log, filemap_fdatawrite);
+ 	else
+-		list_for_each_entry(sbi, &log->sb_list, log_list) {
+-			filemap_flush(sbi->ipbmap->i_mapping);
+-			filemap_flush(sbi->ipimap->i_mapping);
+-			filemap_flush(sbi->direct_inode->i_mapping);
+-		}
++		write_special_inodes(log, filemap_flush);
  
--	  Note: Features which OCFS2 does not support yet:
--	          - extended attributes
--	          - quotas
--	          - cluster aware flock
--	          - Directory change notification (F_NOTIFY)
--	          - Distributed Caching (F_SETLEASE/F_GETLEASE/break_lease)
--	          - POSIX ACLs
--	          - readpages / writepages (not user visible)
-+	  For more information on OCFS2, see the file
-+	  <file:Documentation/filesystems/ocfs2.txt>.
+ 	/*
+ 	 *	forward syncpt
+@@ -1536,7 +1538,6 @@ void jfs_flush_journal(struct jfs_log *log, int wait)
+ {
+ 	int i;
+ 	struct tblock *target = NULL;
+-	struct jfs_sb_info *sbi;
  
- config OCFS2_DEBUG_MASKLOG
- 	bool "OCFS2 logging support"
-@@ -1028,8 +1022,8 @@ config HUGETLB_PAGE
- 	def_bool HUGETLBFS
+ 	/* jfs_write_inode may call us during read-only mount */
+ 	if (!log)
+@@ -1598,11 +1599,7 @@ void jfs_flush_journal(struct jfs_log *log, int wait)
+ 	if (wait < 2)
+ 		return;
  
- config CONFIGFS_FS
--	tristate "Userspace-driven configuration filesystem (EXPERIMENTAL)"
--	depends on SYSFS && EXPERIMENTAL
-+	tristate "Userspace-driven configuration filesystem"
-+	depends on SYSFS
- 	help
- 	  configfs is a ram-based filesystem that provides the converse
- 	  of sysfs's functionality. Where sysfs is a filesystem-based
-@@ -1905,13 +1899,15 @@ config CIFS
- 	  file servers such as Windows 2000 (including Windows 2003, NT 4  
- 	  and Windows XP) as well by Samba (which provides excellent CIFS
- 	  server support for Linux and many other operating systems). Limited
--	  support for OS/2 and Windows ME and similar servers is provided as well.
--
--	  The intent of the cifs module is to provide an advanced
--	  network file system client for mounting to CIFS compliant servers,
--	  including support for dfs (hierarchical name space), secure per-user
--	  session establishment, safe distributed caching (oplock), optional
--	  packet signing, Unicode and other internationalization improvements. 
-+	  support for OS/2 and Windows ME and similar servers is provided as
-+	  well.
-+
-+	  The cifs module provides an advanced network file system
-+	  client for mounting to CIFS compliant servers.  It includes
-+	  support for DFS (hierarchical name space), secure per-user
-+	  session establishment via Kerberos or NTLM or NTLMv2,
-+	  safe distributed caching (oplock), optional packet
-+	  signing, Unicode and other internationalization improvements.
- 	  If you need to mount to Samba or Windows from this machine, say Y.
+-	list_for_each_entry(sbi, &log->sb_list, log_list) {
+-		filemap_fdatawrite(sbi->ipbmap->i_mapping);
+-		filemap_fdatawrite(sbi->ipimap->i_mapping);
+-		filemap_fdatawrite(sbi->direct_inode->i_mapping);
+-	}
++	write_special_inodes(log, filemap_fdatawrite);
  
- config CIFS_STATS
-@@ -1943,7 +1939,8 @@ config CIFS_WEAK_PW_HASH
- 	  (since 1997) support stronger NTLM (and even NTLMv2 and Kerberos)
- 	  security mechanisms. These hash the password more securely
- 	  than the mechanisms used in the older LANMAN version of the
--          SMB protocol needed to establish sessions with old SMB servers.
-+	  SMB protocol but LANMAN based authentication is needed to
-+	  establish sessions with some old SMB servers.
+ 	/*
+ 	 * If there was recent activity, we may need to wait
+@@ -1611,6 +1608,7 @@ void jfs_flush_journal(struct jfs_log *log, int wait)
+ 	if ((!list_empty(&log->cqueue)) || !list_empty(&log->synclist)) {
+ 		for (i = 0; i < 200; i++) {	/* Too much? */
+ 			msleep(250);
++			write_special_inodes(log, filemap_fdatawrite);
+ 			if (list_empty(&log->cqueue) &&
+ 			    list_empty(&log->synclist))
+ 				break;
+@@ -2347,7 +2345,7 @@ int jfsIOWait(void *arg)
  
- 	  Enabling this option allows the cifs module to mount to older
- 	  LANMAN based servers such as OS/2 and Windows 95, but such
-@@ -1951,8 +1948,8 @@ config CIFS_WEAK_PW_HASH
- 	  security mechanisms if you are on a public network.  Unless you
- 	  have a need to access old SMB servers (and are on a private 
- 	  network) you probably want to say N.  Even if this support
--	  is enabled in the kernel build, they will not be used
--	  automatically. At runtime LANMAN mounts are disabled but
-+	  is enabled in the kernel build, LANMAN authentication will not be
-+	  used automatically. At runtime LANMAN mounts are disabled but
- 	  can be set to required (or optional) either in
- 	  /proc/fs/cifs (see fs/cifs/README for more detail) or via an
- 	  option on the mount command. This support is disabled by 
-@@ -2018,12 +2015,22 @@ config CIFS_UPCALL
- 	  depends on CIFS_EXPERIMENTAL
- 	  depends on KEYS
- 	  help
--	    Enables an upcall mechanism for CIFS which will be used to contact
--	    userspace helper utilities to provide SPNEGO packaged Kerberos
--	    tickets which are needed to mount to certain secure servers
-+	    Enables an upcall mechanism for CIFS which accesses
-+	    userspace helper utilities to provide SPNEGO packaged (RFC 4178)
-+	    Kerberos tickets which are needed to mount to certain secure servers
- 	    (for which more secure Kerberos authentication is required). If
- 	    unsure, say N.
+ 	do {
+ 		spin_lock_irq(&log_redrive_lock);
+-		while ((bp = log_redrive_list) != 0) {
++		while ((bp = log_redrive_list)) {
+ 			log_redrive_list = bp->l_redrive_next;
+ 			bp->l_redrive_next = NULL;
+ 			spin_unlock_irq(&log_redrive_lock);
+diff --git a/fs/jfs/jfs_metapage.c b/fs/jfs/jfs_metapage.c
+index f5cd8d3..d1e64f2 100644
+--- a/fs/jfs/jfs_metapage.c
++++ b/fs/jfs/jfs_metapage.c
+@@ -39,11 +39,11 @@ static struct {
+ #endif
  
-+config CIFS_DFS_UPCALL
-+	  bool "DFS feature support (EXPERIMENTAL)"
-+	  depends on CIFS_EXPERIMENTAL
-+	  depends on KEYS
-+	  help
-+	    Enables an upcall mechanism for CIFS which contacts userspace
-+	    helper utilities to provide server name resolution (host names to
-+	    IP addresses) which is needed for implicit mounts of DFS junction
-+	    points. If unsure, say N.
-+
- config NCP_FS
- 	tristate "NCP file system support (to mount NetWare volumes)"
- 	depends on IPX!=n || INET
-@@ -2130,4 +2137,3 @@ source "fs/nls/Kconfig"
- source "fs/dlm/Kconfig"
+ #define metapage_locked(mp) test_bit(META_locked, &(mp)->flag)
+-#define trylock_metapage(mp) test_and_set_bit(META_locked, &(mp)->flag)
++#define trylock_metapage(mp) test_and_set_bit_lock(META_locked, &(mp)->flag)
  
- endmenu
--
-diff --git a/fs/block_dev.c b/fs/block_dev.c
-index 993f78c..e48a630 100644
---- a/fs/block_dev.c
-+++ b/fs/block_dev.c
-@@ -738,9 +738,9 @@ EXPORT_SYMBOL(bd_release);
- static struct kobject *bdev_get_kobj(struct block_device *bdev)
+ static inline void unlock_metapage(struct metapage *mp)
  {
- 	if (bdev->bd_contains != bdev)
--		return kobject_get(&bdev->bd_part->kobj);
-+		return kobject_get(&bdev->bd_part->dev.kobj);
- 	else
--		return kobject_get(&bdev->bd_disk->kobj);
-+		return kobject_get(&bdev->bd_disk->dev.kobj);
+-	clear_bit(META_locked, &mp->flag);
++	clear_bit_unlock(META_locked, &mp->flag);
+ 	wake_up(&mp->wait);
  }
  
- static struct kobject *bdev_get_holder(struct block_device *bdev)
-@@ -1176,7 +1176,7 @@ static int do_open(struct block_device *bdev, struct file *file, int for_part)
- 				ret = -ENXIO;
- 				goto out_first;
- 			}
--			kobject_get(&p->kobj);
-+			kobject_get(&p->dev.kobj);
- 			bdev->bd_part = p;
- 			bd_set_size(bdev, (loff_t) p->nr_sects << 9);
- 		}
-@@ -1299,7 +1299,7 @@ static int __blkdev_put(struct block_device *bdev, int for_part)
- 		module_put(owner);
+@@ -88,7 +88,7 @@ struct meta_anchor {
+ };
+ #define mp_anchor(page) ((struct meta_anchor *)page_private(page))
  
- 		if (bdev->bd_contains != bdev) {
--			kobject_put(&bdev->bd_part->kobj);
-+			kobject_put(&bdev->bd_part->dev.kobj);
- 			bdev->bd_part = NULL;
- 		}
- 		bdev->bd_disk = NULL;
-diff --git a/fs/char_dev.c b/fs/char_dev.c
-index c3bfa76..2c7a8b5 100644
---- a/fs/char_dev.c
-+++ b/fs/char_dev.c
-@@ -510,9 +510,8 @@ struct cdev *cdev_alloc(void)
+-static inline struct metapage *page_to_mp(struct page *page, uint offset)
++static inline struct metapage *page_to_mp(struct page *page, int offset)
  {
- 	struct cdev *p = kzalloc(sizeof(struct cdev), GFP_KERNEL);
- 	if (p) {
--		p->kobj.ktype = &ktype_cdev_dynamic;
- 		INIT_LIST_HEAD(&p->list);
--		kobject_init(&p->kobj);
-+		kobject_init(&p->kobj, &ktype_cdev_dynamic);
- 	}
- 	return p;
+ 	if (!PagePrivate(page))
+ 		return NULL;
+@@ -153,7 +153,7 @@ static inline void dec_io(struct page *page, void (*handler) (struct page *))
  }
-@@ -529,8 +528,7 @@ void cdev_init(struct cdev *cdev, const struct file_operations *fops)
+ 
+ #else
+-static inline struct metapage *page_to_mp(struct page *page, uint offset)
++static inline struct metapage *page_to_mp(struct page *page, int offset)
  {
- 	memset(cdev, 0, sizeof *cdev);
- 	INIT_LIST_HEAD(&cdev->list);
--	cdev->kobj.ktype = &ktype_cdev_default;
--	kobject_init(&cdev->kobj);
-+	kobject_init(&cdev->kobj, &ktype_cdev_default);
- 	cdev->ops = fops;
+ 	return PagePrivate(page) ? (struct metapage *)page_private(page) : NULL;
  }
+@@ -249,7 +249,7 @@ static inline void drop_metapage(struct page *page, struct metapage *mp)
+  */
  
-diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES
-index a609599..edd2483 100644
---- a/fs/cifs/CHANGES
-+++ b/fs/cifs/CHANGES
-@@ -3,7 +3,10 @@ Version 1.52
- Fix oops on second mount to server when null auth is used.
- Enable experimental Kerberos support.  Return writebehind errors on flush
- and sync so that events like out of disk space get reported properly on
--cached files.
-+cached files. Fix setxattr failure to certain Samba versions. Fix mount
-+of second share to disconnected server session (autoreconnect on this).
-+Add ability to modify cifs acls for handling chmod (when mounted with
-+cifsacl flag).
+ static sector_t metapage_get_blocks(struct inode *inode, sector_t lblock,
+-				    unsigned int *len)
++				    int *len)
+ {
+ 	int rc = 0;
+ 	int xflag;
+@@ -352,25 +352,27 @@ static void metapage_write_end_io(struct bio *bio, int err)
+ static int metapage_writepage(struct page *page, struct writeback_control *wbc)
+ {
+ 	struct bio *bio = NULL;
+-	unsigned int block_offset;	/* block offset of mp within page */
++	int block_offset;	/* block offset of mp within page */
+ 	struct inode *inode = page->mapping->host;
+-	unsigned int blocks_per_mp = JFS_SBI(inode->i_sb)->nbperpage;
+-	unsigned int len;
+-	unsigned int xlen;
++	int blocks_per_mp = JFS_SBI(inode->i_sb)->nbperpage;
++	int len;
++	int xlen;
+ 	struct metapage *mp;
+ 	int redirty = 0;
+ 	sector_t lblock;
++	int nr_underway = 0;
+ 	sector_t pblock;
+ 	sector_t next_block = 0;
+ 	sector_t page_start;
+ 	unsigned long bio_bytes = 0;
+ 	unsigned long bio_offset = 0;
+-	unsigned int offset;
++	int offset;
  
- Version 1.51
- ------------
-diff --git a/fs/cifs/Makefile b/fs/cifs/Makefile
-index 45e42fb..6ba43fb 100644
---- a/fs/cifs/Makefile
-+++ b/fs/cifs/Makefile
-@@ -9,3 +9,5 @@ cifs-y := cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o inode.o \
- 	  readdir.o ioctl.o sess.o export.o cifsacl.o
+ 	page_start = (sector_t)page->index <<
+ 		     (PAGE_CACHE_SHIFT - inode->i_blkbits);
+ 	BUG_ON(!PageLocked(page));
+ 	BUG_ON(PageWriteback(page));
++	set_page_writeback(page);
  
- cifs-$(CONFIG_CIFS_UPCALL) += cifs_spnego.o
-+
-+cifs-$(CONFIG_CIFS_DFS_UPCALL) += dns_resolve.o cifs_dfs_ref.o
-diff --git a/fs/cifs/README b/fs/cifs/README
-index bf11329..c623e2f 100644
---- a/fs/cifs/README
-+++ b/fs/cifs/README
-@@ -56,7 +56,8 @@ the CIFS VFS web site) copy it to the same directory in which mount.smbfs and
- similar files reside (usually /sbin).  Although the helper software is not  
- required, mount.cifs is recommended.  Eventually the Samba 3.0 utility program 
- "net" may also be helpful since it may someday provide easier mount syntax for
--users who are used to Windows e.g.  net use <mount point> <UNC name or cifs URL>
-+users who are used to Windows e.g.
-+	net use <mount point> <UNC name or cifs URL>
- Note that running the Winbind pam/nss module (logon service) on all of your
- Linux clients is useful in mapping Uids and Gids consistently across the
- domain to the proper network user.  The mount.cifs mount helper can be
-@@ -248,7 +249,7 @@ A partial list of the supported mount options follows:
- 		the CIFS session.
-   password	The user password.  If the mount helper is
- 		installed, the user will be prompted for password
--		if it is not supplied.
-+		if not supplied.
-   ip		The ip address of the target server
-   unc		The target server Universal Network Name (export) to 
- 		mount.	
-@@ -283,7 +284,7 @@ A partial list of the supported mount options follows:
- 		can be enabled by specifying file_mode and dir_mode on 
- 		the client.  Note that the mount.cifs helper must be
- 		at version 1.10 or higher to support specifying the uid
--		(or gid) in non-numberic form.
-+		(or gid) in non-numeric form.
-   gid		Set the default gid for inodes (similar to above).
-   file_mode     If CIFS Unix extensions are not supported by the server
- 		this overrides the default mode for file inodes.
-@@ -417,9 +418,10 @@ A partial list of the supported mount options follows:
-   acl   	Allow setfacl and getfacl to manage posix ACLs if server
- 		supports them.  (default)
-   noacl 	Do not allow setfacl and getfacl calls on this mount
--  user_xattr    Allow getting and setting user xattrs as OS/2 EAs (extended
--		attributes) to the server (default) e.g. via setfattr 
--		and getfattr utilities. 
-+  user_xattr    Allow getting and setting user xattrs (those attributes whose
-+		name begins with "user." or "os2.") as OS/2 EAs (extended
-+		attributes) to the server.  This allows support of the
-+		setfattr and getfattr utilities. (default)
-   nouser_xattr  Do not allow getfattr/setfattr to get/set/list xattrs 
-   mapchars      Translate six of the seven reserved characters (not backslash)
- 			*?<>|:
-@@ -434,6 +436,7 @@ A partial list of the supported mount options follows:
-  nomapchars     Do not translate any of these seven characters (default).
-  nocase         Request case insensitive path name matching (case
- 		sensitive is the default if the server suports it).
-+		(mount option "ignorecase" is identical to "nocase")
-  posixpaths     If CIFS Unix extensions are supported, attempt to
- 		negotiate posix path name support which allows certain
- 		characters forbidden in typical CIFS filenames, without
-@@ -485,6 +488,9 @@ A partial list of the supported mount options follows:
- 			ntlmv2i Use NTLMv2 password hashing with packet signing
- 			lanman  (if configured in kernel config) use older
- 				lanman hash
-+hard		Retry file operations if server is not responding
-+soft		Limit retries to unresponsive servers (usually only
-+		one retry) before returning an error.  (default)
+ 	for (offset = 0; offset < PAGE_CACHE_SIZE; offset += PSIZE) {
+ 		mp = page_to_mp(page, offset);
+@@ -413,11 +415,10 @@ static int metapage_writepage(struct page *page, struct writeback_control *wbc)
+ 			if (!bio->bi_size)
+ 				goto dump_bio;
+ 			submit_bio(WRITE, bio);
++			nr_underway++;
+ 			bio = NULL;
+-		} else {
+-			set_page_writeback(page);
++		} else
+ 			inc_io(page);
+-		}
+ 		xlen = (PAGE_CACHE_SIZE - offset) >> inode->i_blkbits;
+ 		pblock = metapage_get_blocks(inode, lblock, &xlen);
+ 		if (!pblock) {
+@@ -427,7 +428,7 @@ static int metapage_writepage(struct page *page, struct writeback_control *wbc)
+ 			continue;
+ 		}
+ 		set_bit(META_io, &mp->flag);
+-		len = min(xlen, (uint) JFS_SBI(inode->i_sb)->nbperpage);
++		len = min(xlen, (int)JFS_SBI(inode->i_sb)->nbperpage);
  
- The mount.cifs mount helper also accepts a few mount options before -o
- including:
-@@ -535,8 +541,8 @@ SecurityFlags		Flags which control security negotiation and
- 			must use NTLM					0x02002
- 			may use NTLMv2					0x00004
- 			must use NTLMv2					0x04004
--			may use Kerberos security (not implemented yet) 0x00008
--			must use Kerberos (not implemented yet)         0x08008
-+			may use Kerberos security			0x00008
-+			must use Kerberos				0x08008
- 			may use lanman (weak) password hash  		0x00010
- 			must use lanman password hash			0x10010
- 			may use plaintext passwords    			0x00020
-@@ -626,6 +632,6 @@ returned success.
- 	
- Also note that "cat /proc/fs/cifs/DebugData" will display information about 
- the active sessions and the shares that are mounted.
--Enabling Kerberos (extended security) works when CONFIG_CIFS_EXPERIMENTAL is enabled
--but requires a user space helper (from the Samba project). NTLM and NTLMv2 and
--LANMAN support do not require this helpr.
-+Enabling Kerberos (extended security) works when CONFIG_CIFS_EXPERIMENTAL is
-+on but requires a user space helper (from the Samba project). NTLM and NTLMv2 and
-+LANMAN support do not require this helper.
-diff --git a/fs/cifs/TODO b/fs/cifs/TODO
-index a8852c2..92c9fea 100644
---- a/fs/cifs/TODO
-+++ b/fs/cifs/TODO
-@@ -1,4 +1,4 @@
--Version 1.49 April 26, 2007
-+Version 1.52 January 3, 2008
+ 		bio = bio_alloc(GFP_NOFS, 1);
+ 		bio->bi_bdev = inode->i_sb->s_bdev;
+@@ -449,12 +450,16 @@ static int metapage_writepage(struct page *page, struct writeback_control *wbc)
+ 			goto dump_bio;
  
- A Partial List of Missing Features
- ==================================
-@@ -16,16 +16,14 @@ SecurityDescriptors
- c) Better pam/winbind integration (e.g. to handle uid mapping
- better)
+ 		submit_bio(WRITE, bio);
++		nr_underway++;
+ 	}
+ 	if (redirty)
+ 		redirty_page_for_writepage(wbc, page);
  
--d) Verify that Kerberos signing works
--
--e) Cleanup now unneeded SessSetup code in
-+d) Cleanup now unneeded SessSetup code in
- fs/cifs/connect.c and add back in NTLMSSP code if any servers
- need it
+ 	unlock_page(page);
  
--f) MD5-HMAC signing SMB PDUs when SPNEGO style SessionSetup 
--used (Kerberos or NTLMSSP). Signing alreadyimplemented for NTLM
--and raw NTLMSSP already. This is important when enabling
--extended security and mounting to Windows 2003 Servers
-+e) ms-dfs and ms-dfs host name resolution cleanup
++	if (nr_underway == 0)
++		end_page_writeback(page);
 +
-+f) fix NTLMv2 signing when two mounts with different users to same
-+server.
+ 	return 0;
+ add_failed:
+ 	/* We should never reach here, since we're only adding one vec */
+@@ -475,13 +480,13 @@ static int metapage_readpage(struct file *fp, struct page *page)
+ {
+ 	struct inode *inode = page->mapping->host;
+ 	struct bio *bio = NULL;
+-	unsigned int block_offset;
+-	unsigned int blocks_per_page = PAGE_CACHE_SIZE >> inode->i_blkbits;
++	int block_offset;
++	int blocks_per_page = PAGE_CACHE_SIZE >> inode->i_blkbits;
+ 	sector_t page_start;	/* address of page in fs blocks */
+ 	sector_t pblock;
+-	unsigned int xlen;
++	int xlen;
+ 	unsigned int len;
+-	unsigned int offset;
++	int offset;
  
- g) Directory entry caching relies on a 1 second timer, rather than 
- using FindNotify or equivalent.  - (started)
-diff --git a/fs/cifs/cifs_dfs_ref.c b/fs/cifs/cifs_dfs_ref.c
-new file mode 100644
-index 0000000..413ee23
---- /dev/null
-+++ b/fs/cifs/cifs_dfs_ref.c
-@@ -0,0 +1,377 @@
-+/*
-+ *   Contains the CIFS DFS referral mounting routines used for handling
-+ *   traversal via DFS junction point
-+ *
-+ *   Copyright (c) 2007 Igor Mammedov
-+ *   Copyright (C) International Business Machines  Corp., 2008
-+ *   Author(s): Igor Mammedov (niallain at gmail.com)
-+ *		Steve French (sfrench at us.ibm.com)
-+ *   This program is free software; you can redistribute it and/or
-+ *   modify it under the terms of the GNU General Public License
-+ *   as published by the Free Software Foundation; either version
-+ *   2 of the License, or (at your option) any later version.
-+ */
-+
-+#include <linux/dcache.h>
-+#include <linux/mount.h>
-+#include <linux/namei.h>
-+#include <linux/vfs.h>
-+#include <linux/fs.h>
-+#include "cifsglob.h"
-+#include "cifsproto.h"
-+#include "cifsfs.h"
-+#include "dns_resolve.h"
-+#include "cifs_debug.h"
-+
-+LIST_HEAD(cifs_dfs_automount_list);
-+
-+/*
-+ * DFS functions
-+*/
-+
-+void dfs_shrink_umount_helper(struct vfsmount *vfsmnt)
-+{
-+	mark_mounts_for_expiry(&cifs_dfs_automount_list);
-+	mark_mounts_for_expiry(&cifs_dfs_automount_list);
-+	shrink_submounts(vfsmnt, &cifs_dfs_automount_list);
-+}
-+
-+/**
-+ * cifs_get_share_name	-	extracts share name from UNC
-+ * @node_name:	pointer to UNC string
-+ *
-+ * Extracts sharename form full UNC.
-+ * i.e. strips from UNC trailing path that is not part of share
-+ * name and fixup missing '\' in the begining of DFS node refferal
-+ * if neccessary.
-+ * Returns pointer to share name on success or NULL on error.
-+ * Caller is responsible for freeing returned string.
-+ */
-+static char *cifs_get_share_name(const char *node_name)
-+{
-+	int len;
-+	char *UNC;
-+	char *pSep;
-+
-+	len = strlen(node_name);
-+	UNC = kmalloc(len+2 /*for term null and additional \ if it's missed */,
-+			 GFP_KERNEL);
-+	if (!UNC)
-+		return NULL;
-+
-+	/* get share name and server name */
-+	if (node_name[1] != '\\') {
-+		UNC[0] = '\\';
-+		strncpy(UNC+1, node_name, len);
-+		len++;
-+		UNC[len] = 0;
-+	} else {
-+		strncpy(UNC, node_name, len);
-+		UNC[len] = 0;
-+	}
-+
-+	/* find server name end */
-+	pSep = memchr(UNC+2, '\\', len-2);
-+	if (!pSep) {
-+		cERROR(1, ("%s: no server name end in node name: %s",
-+			__FUNCTION__, node_name));
-+		kfree(UNC);
-+		return NULL;
-+	}
-+
-+	/* find sharename end */
-+	pSep++;
-+	pSep = memchr(UNC+(pSep-UNC), '\\', len-(pSep-UNC));
-+	if (!pSep) {
-+		cERROR(1, ("%s:2 cant find share name in node name: %s",
-+			__FUNCTION__, node_name));
-+		kfree(UNC);
-+		return NULL;
-+	}
-+	/* trim path up to sharename end
-+	 *          * now we have share name in UNC */
-+	*pSep = 0;
-+
-+	return UNC;
-+}
-+
-+
-+/**
-+ * compose_mount_options	-	creates mount options for refferral
-+ * @sb_mountdata:	parent/root DFS mount options (template)
-+ * @ref_unc:		refferral server UNC
-+ * @devname:		pointer for saving device name
-+ *
-+ * creates mount options for submount based on template options sb_mountdata
-+ * and replacing unc,ip,prefixpath options with ones we've got form ref_unc.
-+ *
-+ * Returns: pointer to new mount options or ERR_PTR.
-+ * Caller is responcible for freeing retunrned value if it is not error.
-+ */
-+static char *compose_mount_options(const char *sb_mountdata,
-+				   const char *ref_unc,
-+				   char **devname)
-+{
-+	int rc;
-+	char *mountdata;
-+	int md_len;
-+	char *tkn_e;
-+	char *srvIP = NULL;
-+	char sep = ',';
-+	int off, noff;
-+
-+	if (sb_mountdata == NULL)
-+		return ERR_PTR(-EINVAL);
-+
-+	*devname = cifs_get_share_name(ref_unc);
-+	rc = dns_resolve_server_name_to_ip(*devname, &srvIP);
-+	if (rc != 0) {
-+		cERROR(1, ("%s: Failed to resolve server part of %s to IP",
-+			  __FUNCTION__, *devname));
-+		mountdata = ERR_PTR(rc);
-+		goto compose_mount_options_out;
-+	}
-+	md_len = strlen(sb_mountdata) + strlen(srvIP) + strlen(ref_unc) + 3;
-+	mountdata = kzalloc(md_len+1, GFP_KERNEL);
-+	if (mountdata == NULL) {
-+		mountdata = ERR_PTR(-ENOMEM);
-+		goto compose_mount_options_out;
-+	}
-+
-+	/* copy all options except of unc,ip,prefixpath */
-+	off = 0;
-+	if (strncmp(sb_mountdata, "sep=", 4) == 0) {
-+			sep = sb_mountdata[4];
-+			strncpy(mountdata, sb_mountdata, 5);
-+			off += 5;
-+	}
-+	while ((tkn_e = strchr(sb_mountdata+off, sep))) {
-+		noff = (tkn_e - (sb_mountdata+off)) + 1;
-+		if (strnicmp(sb_mountdata+off, "unc=", 4) == 0) {
-+			off += noff;
-+			continue;
-+		}
-+		if (strnicmp(sb_mountdata+off, "ip=", 3) == 0) {
-+			off += noff;
-+			continue;
-+		}
-+		if (strnicmp(sb_mountdata+off, "prefixpath=", 3) == 0) {
-+			off += noff;
-+			continue;
-+		}
-+		strncat(mountdata, sb_mountdata+off, noff);
-+		off += noff;
-+	}
-+	strcat(mountdata, sb_mountdata+off);
-+	mountdata[md_len] = '\0';
-+
-+	/* copy new IP and ref share name */
-+	strcat(mountdata, ",ip=");
-+	strcat(mountdata, srvIP);
-+	strcat(mountdata, ",unc=");
-+	strcat(mountdata, *devname);
-+
-+	/* find & copy prefixpath */
-+	tkn_e = strchr(ref_unc+2, '\\');
-+	if (tkn_e) {
-+		tkn_e = strchr(tkn_e+1, '\\');
-+		if (tkn_e) {
-+			strcat(mountdata, ",prefixpath=");
-+			strcat(mountdata, tkn_e);
-+		}
-+	}
-+
-+	/*cFYI(1,("%s: parent mountdata: %s", __FUNCTION__,sb_mountdata));*/
-+	/*cFYI(1, ("%s: submount mountdata: %s", __FUNCTION__, mountdata ));*/
-+
-+compose_mount_options_out:
-+	kfree(srvIP);
-+	return mountdata;
-+}
-+
-+
-+static struct vfsmount *cifs_dfs_do_refmount(const struct vfsmount *mnt_parent,
-+		struct dentry *dentry, char *ref_unc)
-+{
-+	struct cifs_sb_info *cifs_sb;
-+	struct vfsmount *mnt;
-+	char *mountdata;
-+	char *devname = NULL;
-+
-+	cifs_sb = CIFS_SB(dentry->d_inode->i_sb);
-+	mountdata = compose_mount_options(cifs_sb->mountdata,
-+						ref_unc, &devname);
-+
-+	if (IS_ERR(mountdata))
-+		return (struct vfsmount *)mountdata;
-+
-+	mnt = vfs_kern_mount(&cifs_fs_type, 0, devname, mountdata);
-+	kfree(mountdata);
-+	kfree(devname);
-+	return mnt;
-+
-+}
-+
-+static char *build_full_dfs_path_from_dentry(struct dentry *dentry)
-+{
-+	char *full_path = NULL;
-+	char *search_path;
-+	char *tmp_path;
-+	size_t l_max_len;
-+	struct cifs_sb_info *cifs_sb;
-+
-+	if (dentry->d_inode == NULL)
-+		return NULL;
-+
-+	cifs_sb = CIFS_SB(dentry->d_inode->i_sb);
-+
-+	if (cifs_sb->tcon == NULL)
-+		return NULL;
-+
-+	search_path = build_path_from_dentry(dentry);
-+	if (search_path == NULL)
-+		return NULL;
-+
-+	if (cifs_sb->tcon->Flags & SMB_SHARE_IS_IN_DFS) {
-+		/* we should use full path name to correct working with DFS */
-+		l_max_len = strnlen(cifs_sb->tcon->treeName, MAX_TREE_SIZE+1) +
-+					strnlen(search_path, MAX_PATHCONF) + 1;
-+		tmp_path = kmalloc(l_max_len, GFP_KERNEL);
-+		if (tmp_path == NULL) {
-+			kfree(search_path);
-+			return NULL;
-+		}
-+		strncpy(tmp_path, cifs_sb->tcon->treeName, l_max_len);
-+		strcat(tmp_path, search_path);
-+		tmp_path[l_max_len-1] = 0;
-+		full_path = tmp_path;
-+		kfree(search_path);
-+	} else {
-+		full_path = search_path;
-+	}
-+	return full_path;
-+}
-+
-+static int add_mount_helper(struct vfsmount *newmnt, struct nameidata *nd,
-+				struct list_head *mntlist)
-+{
-+	/* stolen from afs code */
-+	int err;
-+
-+	mntget(newmnt);
-+	err = do_add_mount(newmnt, nd, nd->mnt->mnt_flags, mntlist);
-+	switch (err) {
-+	case 0:
-+		dput(nd->dentry);
-+		mntput(nd->mnt);
-+		nd->mnt = newmnt;
-+		nd->dentry = dget(newmnt->mnt_root);
-+		break;
-+	case -EBUSY:
-+		/* someone else made a mount here whilst we were busy */
-+		while (d_mountpoint(nd->dentry) &&
-+		       follow_down(&nd->mnt, &nd->dentry))
-+			;
-+		err = 0;
-+	default:
-+		mntput(newmnt);
-+		break;
-+	}
-+	return err;
-+}
-+
-+static void dump_referral(const struct dfs_info3_param *ref)
-+{
-+	cFYI(1, ("DFS: ref path: %s", ref->path_name));
-+	cFYI(1, ("DFS: node path: %s", ref->node_name));
-+	cFYI(1, ("DFS: fl: %hd, srv_type: %hd", ref->flags, ref->server_type));
-+	cFYI(1, ("DFS: ref_flags: %hd, path_consumed: %hd", ref->ref_flag,
-+				ref->PathConsumed));
-+}
-+
-+
-+static void*
-+cifs_dfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd)
-+{
-+	struct dfs_info3_param *referrals = NULL;
-+	unsigned int num_referrals = 0;
-+	struct cifs_sb_info *cifs_sb;
-+	struct cifsSesInfo *ses;
-+	char *full_path = NULL;
-+	int xid, i;
-+	int rc = 0;
-+	struct vfsmount *mnt = ERR_PTR(-ENOENT);
-+
-+	cFYI(1, ("in %s", __FUNCTION__));
-+	BUG_ON(IS_ROOT(dentry));
-+
-+	xid = GetXid();
-+
-+	dput(nd->dentry);
-+	nd->dentry = dget(dentry);
-+
-+	cifs_sb = CIFS_SB(dentry->d_inode->i_sb);
-+	ses = cifs_sb->tcon->ses;
-+
-+	if (!ses) {
-+		rc = -EINVAL;
-+		goto out_err;
-+	}
-+
-+	full_path = build_full_dfs_path_from_dentry(dentry);
-+	if (full_path == NULL) {
-+		rc = -ENOMEM;
-+		goto out_err;
-+	}
-+
-+	rc = get_dfs_path(xid, ses , full_path, cifs_sb->local_nls,
-+		&num_referrals, &referrals,
-+		cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
-+
-+	for (i = 0; i < num_referrals; i++) {
-+		dump_referral(referrals+i);
-+		/* connect to a storage node */
-+		if (referrals[i].flags & DFSREF_STORAGE_SERVER) {
-+			int len;
-+			len = strlen(referrals[i].node_name);
-+			if (len < 2) {
-+				cERROR(1, ("%s: Net Address path too short: %s",
-+					__FUNCTION__, referrals[i].node_name));
-+				rc = -EINVAL;
-+				goto out_err;
-+			}
-+			mnt = cifs_dfs_do_refmount(nd->mnt, nd->dentry,
-+						referrals[i].node_name);
-+			cFYI(1, ("%s: cifs_dfs_do_refmount:%s , mnt:%p",
-+					 __FUNCTION__,
-+					referrals[i].node_name, mnt));
-+
-+			/* complete mount procedure if we accured submount */
-+			if (!IS_ERR(mnt))
-+				break;
-+		}
-+	}
-+
-+	/* we need it cause for() above could exit without valid submount */
-+	rc = PTR_ERR(mnt);
-+	if (IS_ERR(mnt))
-+		goto out_err;
-+
-+	nd->mnt->mnt_flags |= MNT_SHRINKABLE;
-+	rc = add_mount_helper(mnt, nd, &cifs_dfs_automount_list);
-+
-+out:
-+	FreeXid(xid);
-+	free_dfs_info_array(referrals, num_referrals);
-+	kfree(full_path);
-+	cFYI(1, ("leaving %s" , __FUNCTION__));
-+	return ERR_PTR(rc);
-+out_err:
-+	path_release(nd);
-+	goto out;
-+}
+ 	BUG_ON(!PageLocked(page));
+ 	page_start = (sector_t)page->index <<
+@@ -530,7 +535,7 @@ static int metapage_releasepage(struct page *page, gfp_t gfp_mask)
+ {
+ 	struct metapage *mp;
+ 	int ret = 1;
+-	unsigned int offset;
++	int offset;
+ 
+ 	for (offset = 0; offset < PAGE_CACHE_SIZE; offset += PSIZE) {
+ 		mp = page_to_mp(page, offset);
+diff --git a/fs/jfs/jfs_mount.c b/fs/jfs/jfs_mount.c
+index 644429a..7b698f2 100644
+--- a/fs/jfs/jfs_mount.c
++++ b/fs/jfs/jfs_mount.c
+@@ -147,7 +147,7 @@ int jfs_mount(struct super_block *sb)
+ 	 */
+ 	if ((sbi->mntflag & JFS_BAD_SAIT) == 0) {
+ 		ipaimap2 = diReadSpecial(sb, AGGREGATE_I, 1);
+-		if (ipaimap2 == 0) {
++		if (!ipaimap2) {
+ 			jfs_err("jfs_mount: Faild to read AGGREGATE_I");
+ 			rc = -EIO;
+ 			goto errout35;
+diff --git a/fs/jfs/jfs_umount.c b/fs/jfs/jfs_umount.c
+index 7971f37..adcf92d 100644
+--- a/fs/jfs/jfs_umount.c
++++ b/fs/jfs/jfs_umount.c
+@@ -68,7 +68,7 @@ int jfs_umount(struct super_block *sb)
+ 		/*
+ 		 * Wait for outstanding transactions to be written to log:
+ 		 */
+-		jfs_flush_journal(log, 2);
++		jfs_flush_journal(log, 1);
+ 
+ 	/*
+ 	 * close fileset inode allocation map (aka fileset inode)
+@@ -146,7 +146,7 @@ int jfs_umount_rw(struct super_block *sb)
+ 	 *
+ 	 * remove file system from log active file system list.
+ 	 */
+-	jfs_flush_journal(log, 2);
++	jfs_flush_journal(log, 1);
+ 
+ 	/*
+ 	 * Make sure all metadata makes it to disk
+diff --git a/fs/jfs/namei.c b/fs/jfs/namei.c
+index 4e0a849..f8718de 100644
+--- a/fs/jfs/namei.c
++++ b/fs/jfs/namei.c
+@@ -1103,8 +1103,8 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry,
+ 	 * Make sure dest inode number (if any) is what we think it is
+ 	 */
+ 	rc = dtSearch(new_dir, &new_dname, &ino, &btstack, JFS_LOOKUP);
+-	if (rc == 0) {
+-		if ((new_ip == 0) || (ino != new_ip->i_ino)) {
++	if (!rc) {
++		if ((!new_ip) || (ino != new_ip->i_ino)) {
+ 			rc = -ESTALE;
+ 			goto out3;
+ 		}
+diff --git a/fs/jfs/resize.c b/fs/jfs/resize.c
+index 71984ee..7f24a0b 100644
+--- a/fs/jfs/resize.c
++++ b/fs/jfs/resize.c
+@@ -172,7 +172,7 @@ int jfs_extendfs(struct super_block *sb, s64 newLVSize, int newLogSize)
+ 	 */
+ 	t64 = ((newLVSize - newLogSize + BPERDMAP - 1) >> L2BPERDMAP)
+ 	    << L2BPERDMAP;
+-	t32 = ((t64 + (BITSPERPAGE - 1)) / BITSPERPAGE) + 1 + 50;
++	t32 = DIV_ROUND_UP(t64, BITSPERPAGE) + 1 + 50;
+ 	newFSCKSize = t32 << sbi->l2nbperpage;
+ 	newFSCKAddress = newLogAddress - newFSCKSize;
+ 
+diff --git a/fs/jfs/super.c b/fs/jfs/super.c
+index 314bb4f..70a1400 100644
+--- a/fs/jfs/super.c
++++ b/fs/jfs/super.c
+@@ -598,6 +598,12 @@ static int jfs_show_options(struct seq_file *seq, struct vfsmount *vfs)
+ 		seq_printf(seq, ",umask=%03o", sbi->umask);
+ 	if (sbi->flag & JFS_NOINTEGRITY)
+ 		seq_puts(seq, ",nointegrity");
++	if (sbi->nls_tab)
++		seq_printf(seq, ",iocharset=%s", sbi->nls_tab->charset);
++	if (sbi->flag & JFS_ERR_CONTINUE)
++		seq_printf(seq, ",errors=continue");
++	if (sbi->flag & JFS_ERR_PANIC)
++		seq_printf(seq, ",errors=panic");
+ 
+ #ifdef CONFIG_QUOTA
+ 	if (sbi->flag & JFS_USRQUOTA)
+diff --git a/fs/namespace.c b/fs/namespace.c
+index 0608388..61bf376 100644
+--- a/fs/namespace.c
++++ b/fs/namespace.c
+@@ -41,8 +41,8 @@ static struct kmem_cache *mnt_cache __read_mostly;
+ static struct rw_semaphore namespace_sem;
+ 
+ /* /sys/fs */
+-decl_subsys(fs, NULL, NULL);
+-EXPORT_SYMBOL_GPL(fs_subsys);
++struct kobject *fs_kobj;
++EXPORT_SYMBOL_GPL(fs_kobj);
+ 
+ static inline unsigned long hash(struct vfsmount *mnt, struct dentry *dentry)
+ {
+@@ -1861,10 +1861,9 @@ void __init mnt_init(void)
+ 	if (err)
+ 		printk(KERN_WARNING "%s: sysfs_init error: %d\n",
+ 			__FUNCTION__, err);
+-	err = subsystem_register(&fs_subsys);
+-	if (err)
+-		printk(KERN_WARNING "%s: subsystem_register error: %d\n",
+-			__FUNCTION__, err);
++	fs_kobj = kobject_create_and_add("fs", NULL);
++	if (!fs_kobj)
++		printk(KERN_WARNING "%s: kobj create error\n", __FUNCTION__);
+ 	init_rootfs();
+ 	init_mount_tree();
+ }
+diff --git a/fs/ocfs2/Makefile b/fs/ocfs2/Makefile
+index 9fb8132..4d4ce48 100644
+--- a/fs/ocfs2/Makefile
++++ b/fs/ocfs2/Makefile
+@@ -19,16 +19,17 @@ ocfs2-objs := \
+ 	ioctl.o 		\
+ 	journal.o 		\
+ 	localalloc.o 		\
++	locks.o			\
+ 	mmap.o 			\
+ 	namei.o 		\
++	resize.o		\
+ 	slot_map.o 		\
+ 	suballoc.o 		\
+ 	super.o 		\
+ 	symlink.o 		\
+ 	sysfile.o 		\
+ 	uptodate.o		\
+-	ver.o 			\
+-	vote.o
++	ver.o
+ 
+ obj-$(CONFIG_OCFS2_FS) += cluster/
+ obj-$(CONFIG_OCFS2_FS) += dlm/
+diff --git a/fs/ocfs2/alloc.c b/fs/ocfs2/alloc.c
+index 23c8cda..e6df06a 100644
+--- a/fs/ocfs2/alloc.c
++++ b/fs/ocfs2/alloc.c
+@@ -4731,7 +4731,7 @@ int __ocfs2_flush_truncate_log(struct ocfs2_super *osb)
+ 
+ 	mutex_lock(&data_alloc_inode->i_mutex);
+ 
+-	status = ocfs2_meta_lock(data_alloc_inode, &data_alloc_bh, 1);
++	status = ocfs2_inode_lock(data_alloc_inode, &data_alloc_bh, 1);
+ 	if (status < 0) {
+ 		mlog_errno(status);
+ 		goto out_mutex;
+@@ -4753,7 +4753,7 @@ int __ocfs2_flush_truncate_log(struct ocfs2_super *osb)
+ 
+ out_unlock:
+ 	brelse(data_alloc_bh);
+-	ocfs2_meta_unlock(data_alloc_inode, 1);
++	ocfs2_inode_unlock(data_alloc_inode, 1);
+ 
+ out_mutex:
+ 	mutex_unlock(&data_alloc_inode->i_mutex);
+@@ -5077,7 +5077,7 @@ static int ocfs2_free_cached_items(struct ocfs2_super *osb,
+ 
+ 	mutex_lock(&inode->i_mutex);
+ 
+-	ret = ocfs2_meta_lock(inode, &di_bh, 1);
++	ret = ocfs2_inode_lock(inode, &di_bh, 1);
+ 	if (ret) {
+ 		mlog_errno(ret);
+ 		goto out_mutex;
+@@ -5118,7 +5118,7 @@ out_journal:
+ 	ocfs2_commit_trans(osb, handle);
+ 
+ out_unlock:
+-	ocfs2_meta_unlock(inode, 1);
++	ocfs2_inode_unlock(inode, 1);
+ 	brelse(di_bh);
+ out_mutex:
+ 	mutex_unlock(&inode->i_mutex);
+diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c
+index 56f7790..bc7b4cb 100644
+--- a/fs/ocfs2/aops.c
++++ b/fs/ocfs2/aops.c
+@@ -26,6 +26,7 @@
+ #include <asm/byteorder.h>
+ #include <linux/swap.h>
+ #include <linux/pipe_fs_i.h>
++#include <linux/mpage.h>
+ 
+ #define MLOG_MASK_PREFIX ML_FILE_IO
+ #include <cluster/masklog.h>
+@@ -139,7 +140,8 @@ static int ocfs2_get_block(struct inode *inode, sector_t iblock,
+ {
+ 	int err = 0;
+ 	unsigned int ext_flags;
+-	u64 p_blkno, past_eof;
++	u64 max_blocks = bh_result->b_size >> inode->i_blkbits;
++	u64 p_blkno, count, past_eof;
+ 	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+ 
+ 	mlog_entry("(0x%p, %llu, 0x%p, %d)\n", inode,
+@@ -155,7 +157,7 @@ static int ocfs2_get_block(struct inode *inode, sector_t iblock,
+ 		goto bail;
+ 	}
+ 
+-	err = ocfs2_extent_map_get_blocks(inode, iblock, &p_blkno, NULL,
++	err = ocfs2_extent_map_get_blocks(inode, iblock, &p_blkno, &count,
+ 					  &ext_flags);
+ 	if (err) {
+ 		mlog(ML_ERROR, "Error %d from get_blocks(0x%p, %llu, 1, "
+@@ -164,6 +166,9 @@ static int ocfs2_get_block(struct inode *inode, sector_t iblock,
+ 		goto bail;
+ 	}
+ 
++	if (max_blocks < count)
++		count = max_blocks;
 +
-+struct inode_operations cifs_dfs_referral_inode_operations = {
-+	.follow_link = cifs_dfs_follow_mountpoint,
-+};
+ 	/*
+ 	 * ocfs2 never allocates in this function - the only time we
+ 	 * need to use BH_New is when we're extending i_size on a file
+@@ -178,6 +183,8 @@ static int ocfs2_get_block(struct inode *inode, sector_t iblock,
+ 	if (p_blkno && !(ext_flags & OCFS2_EXT_UNWRITTEN))
+ 		map_bh(bh_result, inode->i_sb, p_blkno);
+ 
++	bh_result->b_size = count << inode->i_blkbits;
 +
-diff --git a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h
-index 34af556..8ad2330 100644
---- a/fs/cifs/cifs_fs_sb.h
-+++ b/fs/cifs/cifs_fs_sb.h
-@@ -43,6 +43,9 @@ struct cifs_sb_info {
- 	mode_t	mnt_dir_mode;
- 	int     mnt_cifs_flags;
- 	int	prepathlen;
--	char   *prepath;
-+	char   *prepath; /* relative path under the share to mount to */
-+#ifdef CONFIG_CIFS_DFS_UPCALL
-+	char   *mountdata; /* mount options received at mount time */
-+#endif
- };
- #endif				/* _CIFS_FS_SB_H */
-diff --git a/fs/cifs/cifs_spnego.c b/fs/cifs/cifs_spnego.c
-index 1529d2b..d543acc 100644
---- a/fs/cifs/cifs_spnego.c
-+++ b/fs/cifs/cifs_spnego.c
-@@ -122,11 +122,13 @@ cifs_get_spnego_key(struct cifsSesInfo *sesInfo)
- 	cFYI(1, ("key description = %s", description));
- 	spnego_key = request_key(&cifs_spnego_key_type, description, "");
+ 	if (!ocfs2_sparse_alloc(osb)) {
+ 		if (p_blkno == 0) {
+ 			err = -EIO;
+@@ -210,7 +217,7 @@ int ocfs2_read_inline_data(struct inode *inode, struct page *page,
+ 			   struct buffer_head *di_bh)
+ {
+ 	void *kaddr;
+-	unsigned int size;
++	loff_t size;
+ 	struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
  
-+#ifdef CONFIG_CIFS_DEBUG2
- 	if (cifsFYI && !IS_ERR(spnego_key)) {
- 		struct cifs_spnego_msg *msg = spnego_key->payload.data;
--		cifs_dump_mem("SPNEGO reply blob:", msg->data,
--				msg->secblob_len + msg->sesskey_len);
-+		cifs_dump_mem("SPNEGO reply blob:", msg->data, min(1024,
-+				msg->secblob_len + msg->sesskey_len));
+ 	if (!(le16_to_cpu(di->i_dyn_features) & OCFS2_INLINE_DATA_FL)) {
+@@ -224,8 +231,9 @@ int ocfs2_read_inline_data(struct inode *inode, struct page *page,
+ 	if (size > PAGE_CACHE_SIZE ||
+ 	    size > ocfs2_max_inline_data(inode->i_sb)) {
+ 		ocfs2_error(inode->i_sb,
+-			    "Inode %llu has with inline data has bad size: %u",
+-			    (unsigned long long)OCFS2_I(inode)->ip_blkno, size);
++			    "Inode %llu has with inline data has bad size: %Lu",
++			    (unsigned long long)OCFS2_I(inode)->ip_blkno,
++			    (unsigned long long)size);
+ 		return -EROFS;
  	}
-+#endif /* CONFIG_CIFS_DEBUG2 */
  
+@@ -275,7 +283,7 @@ static int ocfs2_readpage(struct file *file, struct page *page)
+ 
+ 	mlog_entry("(0x%p, %lu)\n", file, (page ? page->index : 0));
+ 
+-	ret = ocfs2_meta_lock_with_page(inode, NULL, 0, page);
++	ret = ocfs2_inode_lock_with_page(inode, NULL, 0, page);
+ 	if (ret != 0) {
+ 		if (ret == AOP_TRUNCATED_PAGE)
+ 			unlock = 0;
+@@ -285,7 +293,7 @@ static int ocfs2_readpage(struct file *file, struct page *page)
+ 
+ 	if (down_read_trylock(&oi->ip_alloc_sem) == 0) {
+ 		ret = AOP_TRUNCATED_PAGE;
+-		goto out_meta_unlock;
++		goto out_inode_unlock;
+ 	}
+ 
+ 	/*
+@@ -305,25 +313,16 @@ static int ocfs2_readpage(struct file *file, struct page *page)
+ 		goto out_alloc;
+ 	}
+ 
+-	ret = ocfs2_data_lock_with_page(inode, 0, page);
+-	if (ret != 0) {
+-		if (ret == AOP_TRUNCATED_PAGE)
+-			unlock = 0;
+-		mlog_errno(ret);
+-		goto out_alloc;
+-	}
+-
+ 	if (oi->ip_dyn_features & OCFS2_INLINE_DATA_FL)
+ 		ret = ocfs2_readpage_inline(inode, page);
+ 	else
+ 		ret = block_read_full_page(page, ocfs2_get_block);
+ 	unlock = 0;
+ 
+-	ocfs2_data_unlock(inode, 0);
+ out_alloc:
+ 	up_read(&OCFS2_I(inode)->ip_alloc_sem);
+-out_meta_unlock:
+-	ocfs2_meta_unlock(inode, 0);
++out_inode_unlock:
++	ocfs2_inode_unlock(inode, 0);
  out:
- 	kfree(description);
-diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c
-index c312adc..a7035bd 100644
---- a/fs/cifs/cifsacl.c
-+++ b/fs/cifs/cifsacl.c
-@@ -129,6 +129,54 @@ int compare_sids(const struct cifs_sid *ctsid, const struct cifs_sid *cwsid)
- 	return (1); /* sids compare/match */
+ 	if (unlock)
+ 		unlock_page(page);
+@@ -331,6 +330,62 @@ out:
+ 	return ret;
  }
  
-+
-+/* copy ntsd, owner sid, and group sid from a security descriptor to another */
-+static void copy_sec_desc(const struct cifs_ntsd *pntsd,
-+				struct cifs_ntsd *pnntsd, __u32 sidsoffset)
++/*
++ * This is used only for read-ahead. Failures or difficult to handle
++ * situations are safe to ignore.
++ *
++ * Right now, we don't bother with BH_Boundary - in-inode extent lists
++ * are quite large (243 extents on 4k blocks), so most inodes don't
++ * grow out to a tree. If need be, detecting boundary extents could
++ * trivially be added in a future version of ocfs2_get_block().
++ */
++static int ocfs2_readpages(struct file *filp, struct address_space *mapping,
++			   struct list_head *pages, unsigned nr_pages)
 +{
-+	int i;
++	int ret, err = -EIO;
++	struct inode *inode = mapping->host;
++	struct ocfs2_inode_info *oi = OCFS2_I(inode);
++	loff_t start;
++	struct page *last;
 +
-+	struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
-+	struct cifs_sid *nowner_sid_ptr, *ngroup_sid_ptr;
++	/*
++	 * Use the nonblocking flag for the dlm code to avoid page
++	 * lock inversion, but don't bother with retrying.
++	 */
++	ret = ocfs2_inode_lock_full(inode, NULL, 0, OCFS2_LOCK_NONBLOCK);
++	if (ret)
++		return err;
 +
-+	/* copy security descriptor control portion */
-+	pnntsd->revision = pntsd->revision;
-+	pnntsd->type = pntsd->type;
-+	pnntsd->dacloffset = cpu_to_le32(sizeof(struct cifs_ntsd));
-+	pnntsd->sacloffset = 0;
-+	pnntsd->osidoffset = cpu_to_le32(sidsoffset);
-+	pnntsd->gsidoffset = cpu_to_le32(sidsoffset + sizeof(struct cifs_sid));
++	if (down_read_trylock(&oi->ip_alloc_sem) == 0) {
++		ocfs2_inode_unlock(inode, 0);
++		return err;
++	}
 +
-+	/* copy owner sid */
-+	owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
-+				le32_to_cpu(pntsd->osidoffset));
-+	nowner_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset);
++	/*
++	 * Don't bother with inline-data. There isn't anything
++	 * to read-ahead in that case anyway...
++	 */
++	if (oi->ip_dyn_features & OCFS2_INLINE_DATA_FL)
++		goto out_unlock;
 +
-+	nowner_sid_ptr->revision = owner_sid_ptr->revision;
-+	nowner_sid_ptr->num_subauth = owner_sid_ptr->num_subauth;
-+	for (i = 0; i < 6; i++)
-+		nowner_sid_ptr->authority[i] = owner_sid_ptr->authority[i];
-+	for (i = 0; i < 5; i++)
-+		nowner_sid_ptr->sub_auth[i] = owner_sid_ptr->sub_auth[i];
++	/*
++	 * Check whether a remote node truncated this file - we just
++	 * drop out in that case as it's not worth handling here.
++	 */
++	last = list_entry(pages->prev, struct page, lru);
++	start = (loff_t)last->index << PAGE_CACHE_SHIFT;
++	if (start >= i_size_read(inode))
++		goto out_unlock;
 +
-+	/* copy group sid */
-+	group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
-+				le32_to_cpu(pntsd->gsidoffset));
-+	ngroup_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset +
-+					sizeof(struct cifs_sid));
++	err = mpage_readpages(mapping, pages, nr_pages, ocfs2_get_block);
 +
-+	ngroup_sid_ptr->revision = group_sid_ptr->revision;
-+	ngroup_sid_ptr->num_subauth = group_sid_ptr->num_subauth;
-+	for (i = 0; i < 6; i++)
-+		ngroup_sid_ptr->authority[i] = group_sid_ptr->authority[i];
-+	for (i = 0; i < 5; i++)
-+		ngroup_sid_ptr->sub_auth[i] =
-+				cpu_to_le32(group_sid_ptr->sub_auth[i]);
++out_unlock:
++	up_read(&oi->ip_alloc_sem);
++	ocfs2_inode_unlock(inode, 0);
 +
-+	return;
++	return err;
 +}
 +
+ /* Note: Because we don't support holes, our allocation has
+  * already happened (allocation writes zeros to the file data)
+  * so we don't have to worry about ordered writes in
+@@ -452,7 +507,7 @@ static sector_t ocfs2_bmap(struct address_space *mapping, sector_t block)
+ 	 * accessed concurrently from multiple nodes.
+ 	 */
+ 	if (!INODE_JOURNAL(inode)) {
+-		err = ocfs2_meta_lock(inode, NULL, 0);
++		err = ocfs2_inode_lock(inode, NULL, 0);
+ 		if (err) {
+ 			if (err != -ENOENT)
+ 				mlog_errno(err);
+@@ -467,7 +522,7 @@ static sector_t ocfs2_bmap(struct address_space *mapping, sector_t block)
+ 
+ 	if (!INODE_JOURNAL(inode)) {
+ 		up_read(&OCFS2_I(inode)->ip_alloc_sem);
+-		ocfs2_meta_unlock(inode, 0);
++		ocfs2_inode_unlock(inode, 0);
+ 	}
+ 
+ 	if (err) {
+@@ -638,34 +693,12 @@ static ssize_t ocfs2_direct_IO(int rw,
+ 	if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL)
+ 		return 0;
+ 
+-	if (!ocfs2_sparse_alloc(OCFS2_SB(inode->i_sb))) {
+-		/*
+-		 * We get PR data locks even for O_DIRECT.  This
+-		 * allows concurrent O_DIRECT I/O but doesn't let
+-		 * O_DIRECT with extending and buffered zeroing writes
+-		 * race.  If they did race then the buffered zeroing
+-		 * could be written back after the O_DIRECT I/O.  It's
+-		 * one thing to tell people not to mix buffered and
+-		 * O_DIRECT writes, but expecting them to understand
+-		 * that file extension is also an implicit buffered
+-		 * write is too much.  By getting the PR we force
+-		 * writeback of the buffered zeroing before
+-		 * proceeding.
+-		 */
+-		ret = ocfs2_data_lock(inode, 0);
+-		if (ret < 0) {
+-			mlog_errno(ret);
+-			goto out;
+-		}
+-		ocfs2_data_unlock(inode, 0);
+-	}
+-
+ 	ret = blockdev_direct_IO_no_locking(rw, iocb, inode,
+ 					    inode->i_sb->s_bdev, iov, offset,
+ 					    nr_segs, 
+ 					    ocfs2_direct_IO_get_blocks,
+ 					    ocfs2_dio_end_io);
+-out:
 +
- /*
-    change posix mode to reflect permissions
-    pmode is the existing mode (we only want to overwrite part of this
-@@ -220,6 +268,33 @@ static void mode_to_access_flags(umode_t mode, umode_t bits_to_use,
- 	return;
+ 	mlog_exit(ret);
+ 	return ret;
  }
+@@ -1754,7 +1787,7 @@ static int ocfs2_write_begin(struct file *file, struct address_space *mapping,
+ 	struct buffer_head *di_bh = NULL;
+ 	struct inode *inode = mapping->host;
  
-+static __le16 fill_ace_for_sid(struct cifs_ace *pntace,
-+			const struct cifs_sid *psid, __u64 nmode, umode_t bits)
-+{
-+	int i;
-+	__u16 size = 0;
-+	__u32 access_req = 0;
-+
-+	pntace->type = ACCESS_ALLOWED;
-+	pntace->flags = 0x0;
-+	mode_to_access_flags(nmode, bits, &access_req);
-+	if (!access_req)
-+		access_req = SET_MINIMUM_RIGHTS;
-+	pntace->access_req = cpu_to_le32(access_req);
-+
-+	pntace->sid.revision = psid->revision;
-+	pntace->sid.num_subauth = psid->num_subauth;
-+	for (i = 0; i < 6; i++)
-+		pntace->sid.authority[i] = psid->authority[i];
-+	for (i = 0; i < psid->num_subauth; i++)
-+		pntace->sid.sub_auth[i] = psid->sub_auth[i];
-+
-+	size = 1 + 1 + 2 + 4 + 1 + 1 + 6 + (psid->num_subauth * 4);
-+	pntace->size = cpu_to_le16(size);
-+
-+	return (size);
-+}
-+
+-	ret = ocfs2_meta_lock(inode, &di_bh, 1);
++	ret = ocfs2_inode_lock(inode, &di_bh, 1);
+ 	if (ret) {
+ 		mlog_errno(ret);
+ 		return ret;
+@@ -1769,30 +1802,22 @@ static int ocfs2_write_begin(struct file *file, struct address_space *mapping,
+ 	 */
+ 	down_write(&OCFS2_I(inode)->ip_alloc_sem);
  
- #ifdef CONFIG_CIFS_DEBUG2
- static void dump_ace(struct cifs_ace *pace, char *end_of_acl)
-@@ -243,7 +318,7 @@ static void dump_ace(struct cifs_ace *pace, char *end_of_acl)
- 		int i;
- 		cFYI(1, ("ACE revision %d num_auth %d type %d flags %d size %d",
- 			pace->sid.revision, pace->sid.num_subauth, pace->type,
--			pace->flags, pace->size));
-+			pace->flags, le16_to_cpu(pace->size)));
- 		for (i = 0; i < num_subauth; ++i) {
- 			cFYI(1, ("ACE sub_auth[%d]: 0x%x", i,
- 				le32_to_cpu(pace->sid.sub_auth[i])));
-@@ -346,6 +421,28 @@ static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
+-	ret = ocfs2_data_lock(inode, 1);
+-	if (ret) {
+-		mlog_errno(ret);
+-		goto out_fail;
+-	}
+-
+ 	ret = ocfs2_write_begin_nolock(mapping, pos, len, flags, pagep,
+ 				       fsdata, di_bh, NULL);
+ 	if (ret) {
+ 		mlog_errno(ret);
+-		goto out_fail_data;
++		goto out_fail;
+ 	}
+ 
+ 	brelse(di_bh);
+ 
+ 	return 0;
+ 
+-out_fail_data:
+-	ocfs2_data_unlock(inode, 1);
+ out_fail:
+ 	up_write(&OCFS2_I(inode)->ip_alloc_sem);
+ 
+ 	brelse(di_bh);
+-	ocfs2_meta_unlock(inode, 1);
++	ocfs2_inode_unlock(inode, 1);
+ 
+ 	return ret;
  }
+@@ -1908,15 +1933,15 @@ static int ocfs2_write_end(struct file *file, struct address_space *mapping,
  
+ 	ret = ocfs2_write_end_nolock(mapping, pos, len, copied, page, fsdata);
  
-+static int set_chmod_dacl(struct cifs_acl *pndacl, struct cifs_sid *pownersid,
-+			struct cifs_sid *pgrpsid, __u64 nmode)
-+{
-+	__le16 size = 0;
-+	struct cifs_acl *pnndacl;
-+
-+	pnndacl = (struct cifs_acl *)((char *)pndacl + sizeof(struct cifs_acl));
-+
-+	size += fill_ace_for_sid((struct cifs_ace *) ((char *)pnndacl + size),
-+					pownersid, nmode, S_IRWXU);
-+	size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size),
-+					pgrpsid, nmode, S_IRWXG);
-+	size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size),
-+					 &sid_everyone, nmode, S_IRWXO);
-+
-+	pndacl->size = cpu_to_le16(size + sizeof(struct cifs_acl));
-+	pndacl->num_aces = 3;
-+
-+	return (0);
-+}
-+
-+
- static int parse_sid(struct cifs_sid *psid, char *end_of_acl)
- {
- 	/* BB need to add parm so we can store the SID BB */
-@@ -432,6 +529,46 @@ static int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len,
+-	ocfs2_data_unlock(inode, 1);
+ 	up_write(&OCFS2_I(inode)->ip_alloc_sem);
+-	ocfs2_meta_unlock(inode, 1);
++	ocfs2_inode_unlock(inode, 1);
+ 
+ 	return ret;
  }
  
+ const struct address_space_operations ocfs2_aops = {
+ 	.readpage	= ocfs2_readpage,
++	.readpages	= ocfs2_readpages,
+ 	.writepage	= ocfs2_writepage,
+ 	.write_begin	= ocfs2_write_begin,
+ 	.write_end	= ocfs2_write_end,
+diff --git a/fs/ocfs2/buffer_head_io.c b/fs/ocfs2/buffer_head_io.c
+index c903741..f136639 100644
+--- a/fs/ocfs2/buffer_head_io.c
++++ b/fs/ocfs2/buffer_head_io.c
+@@ -79,7 +79,7 @@ int ocfs2_write_block(struct ocfs2_super *osb, struct buffer_head *bh,
+ 		 * information for this bh as it's not marked locally
+ 		 * uptodate. */
+ 		ret = -EIO;
+-		brelse(bh);
++		put_bh(bh);
+ 	}
  
-+/* Convert permission bits from mode to equivalent CIFS ACL */
-+static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
-+				int acl_len, struct inode *inode, __u64 nmode)
-+{
-+	int rc = 0;
-+	__u32 dacloffset;
-+	__u32 ndacloffset;
-+	__u32 sidsoffset;
-+	struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
-+	struct cifs_acl *dacl_ptr = NULL;  /* no need for SACL ptr */
-+	struct cifs_acl *ndacl_ptr = NULL; /* no need for SACL ptr */
-+
-+	if ((inode == NULL) || (pntsd == NULL) || (pnntsd == NULL))
-+		return (-EIO);
-+
-+	owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
-+				le32_to_cpu(pntsd->osidoffset));
-+	group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
-+				le32_to_cpu(pntsd->gsidoffset));
-+
-+	dacloffset = le32_to_cpu(pntsd->dacloffset);
-+	dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
-+
-+	ndacloffset = sizeof(struct cifs_ntsd);
-+	ndacl_ptr = (struct cifs_acl *)((char *)pnntsd + ndacloffset);
-+	ndacl_ptr->revision = dacl_ptr->revision;
-+	ndacl_ptr->size = 0;
-+	ndacl_ptr->num_aces = 0;
+ 	mutex_unlock(&OCFS2_I(inode)->ip_io_mutex);
+@@ -256,7 +256,7 @@ int ocfs2_read_blocks(struct ocfs2_super *osb, u64 block, int nr,
+ 				 * for this bh as it's not marked locally
+ 				 * uptodate. */
+ 				status = -EIO;
+-				brelse(bh);
++				put_bh(bh);
+ 				bhs[i] = NULL;
+ 				continue;
+ 			}
+@@ -280,3 +280,64 @@ bail:
+ 	mlog_exit(status);
+ 	return status;
+ }
 +
-+	rc = set_chmod_dacl(ndacl_ptr, owner_sid_ptr, group_sid_ptr, nmode);
++/* Check whether the blkno is the super block or one of the backups. */
++static void ocfs2_check_super_or_backup(struct super_block *sb,
++					sector_t blkno)
++{
++	int i;
++	u64 backup_blkno;
 +
-+	sidsoffset = ndacloffset + le16_to_cpu(ndacl_ptr->size);
++	if (blkno == OCFS2_SUPER_BLOCK_BLKNO)
++		return;
 +
-+	/* copy security descriptor control portion and owner and group sid */
-+	copy_sec_desc(pntsd, pnntsd, sidsoffset);
++	for (i = 0; i < OCFS2_MAX_BACKUP_SUPERBLOCKS; i++) {
++		backup_blkno = ocfs2_backup_super_blkno(sb, i);
++		if (backup_blkno == blkno)
++			return;
++	}
 +
-+	return (rc);
++	BUG();
 +}
 +
-+
- /* Retrieve an ACL from the server */
- static struct cifs_ntsd *get_cifs_acl(u32 *pacllen, struct inode *inode,
- 				       const char *path)
-@@ -487,6 +624,64 @@ static struct cifs_ntsd *get_cifs_acl(u32 *pacllen, struct inode *inode,
- 	return pntsd;
- }
- 
-+/* Set an ACL on the server */
-+static int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
-+				struct inode *inode, const char *path)
++/*
++ * Write super block and backups doesn't need to collaborate with journal,
++ * so we don't need to lock ip_io_mutex and inode doesn't need to bea passed
++ * into this function.
++ */
++int ocfs2_write_super_or_backup(struct ocfs2_super *osb,
++				struct buffer_head *bh)
 +{
-+	struct cifsFileInfo *open_file;
-+	int unlock_file = FALSE;
-+	int xid;
-+	int rc = -EIO;
-+	__u16 fid;
-+	struct super_block *sb;
-+	struct cifs_sb_info *cifs_sb;
++	int ret = 0;
 +
-+#ifdef CONFIG_CIFS_DEBUG2
-+	cFYI(1, ("set ACL for %s from mode 0x%x", path, inode->i_mode));
-+#endif
++	mlog_entry_void();
 +
-+	if (!inode)
-+		return (rc);
++	BUG_ON(buffer_jbd(bh));
++	ocfs2_check_super_or_backup(osb->sb, bh->b_blocknr);
 +
-+	sb = inode->i_sb;
-+	if (sb == NULL)
-+		return (rc);
++	if (ocfs2_is_hard_readonly(osb) || ocfs2_is_soft_readonly(osb)) {
++		ret = -EROFS;
++		goto out;
++	}
 +
-+	cifs_sb = CIFS_SB(sb);
-+	xid = GetXid();
++	lock_buffer(bh);
++	set_buffer_uptodate(bh);
 +
-+	open_file = find_readable_file(CIFS_I(inode));
-+	if (open_file) {
-+		unlock_file = TRUE;
-+		fid = open_file->netfid;
-+	} else {
-+		int oplock = FALSE;
-+		/* open file */
-+		rc = CIFSSMBOpen(xid, cifs_sb->tcon, path, FILE_OPEN,
-+				WRITE_DAC, 0, &fid, &oplock, NULL,
-+				cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
-+					CIFS_MOUNT_MAP_SPECIAL_CHR);
-+		if (rc != 0) {
-+			cERROR(1, ("Unable to open file to set ACL"));
-+			FreeXid(xid);
-+			return (rc);
-+		}
-+	}
++	/* remove from dirty list before I/O. */
++	clear_buffer_dirty(bh);
 +
-+	rc = CIFSSMBSetCIFSACL(xid, cifs_sb->tcon, fid, pnntsd, acllen);
-+#ifdef CONFIG_CIFS_DEBUG2
-+	cFYI(1, ("SetCIFSACL rc = %d", rc));
-+#endif
-+	if (unlock_file == TRUE)
-+		atomic_dec(&open_file->wrtPending);
-+	else
-+		CIFSSMBClose(xid, cifs_sb->tcon, fid);
++	get_bh(bh); /* for end_buffer_write_sync() */
++	bh->b_end_io = end_buffer_write_sync;
++	submit_bh(WRITE, bh);
 +
-+	FreeXid(xid);
++	wait_on_buffer(bh);
 +
-+	return (rc);
-+}
++	if (!buffer_uptodate(bh)) {
++		ret = -EIO;
++		put_bh(bh);
++	}
 +
- /* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */
- void acl_to_uid_mode(struct inode *inode, const char *path)
- {
-@@ -510,24 +705,53 @@ void acl_to_uid_mode(struct inode *inode, const char *path)
- }
++out:
++	mlog_exit(ret);
++	return ret;
++}
+diff --git a/fs/ocfs2/buffer_head_io.h b/fs/ocfs2/buffer_head_io.h
+index 6cc2093..c2e7861 100644
+--- a/fs/ocfs2/buffer_head_io.h
++++ b/fs/ocfs2/buffer_head_io.h
+@@ -47,6 +47,8 @@ int ocfs2_read_blocks(struct ocfs2_super          *osb,
+ 		      int                  flags,
+ 		      struct inode        *inode);
  
- /* Convert mode bits to an ACL so we can update the ACL on the server */
--int mode_to_acl(struct inode *inode, const char *path)
-+int mode_to_acl(struct inode *inode, const char *path, __u64 nmode)
++int ocfs2_write_super_or_backup(struct ocfs2_super *osb,
++				struct buffer_head *bh);
+ 
+ #define OCFS2_BH_CACHED            1
+ #define OCFS2_BH_READAHEAD         8
+diff --git a/fs/ocfs2/cluster/heartbeat.h b/fs/ocfs2/cluster/heartbeat.h
+index 35397dd..e511339 100644
+--- a/fs/ocfs2/cluster/heartbeat.h
++++ b/fs/ocfs2/cluster/heartbeat.h
+@@ -35,7 +35,7 @@
+ #define O2HB_LIVE_THRESHOLD	   2
+ /* number of equal samples to be seen as dead */
+ extern unsigned int o2hb_dead_threshold;
+-#define O2HB_DEFAULT_DEAD_THRESHOLD	   7
++#define O2HB_DEFAULT_DEAD_THRESHOLD	   31
+ /* Otherwise MAX_WRITE_TIMEOUT will be zero... */
+ #define O2HB_MIN_DEAD_THRESHOLD	  2
+ #define O2HB_MAX_WRITE_TIMEOUT_MS (O2HB_REGION_TIMEOUT_MS * (o2hb_dead_threshold - 1))
+diff --git a/fs/ocfs2/cluster/masklog.c b/fs/ocfs2/cluster/masklog.c
+index a4882c8..23c732f 100644
+--- a/fs/ocfs2/cluster/masklog.c
++++ b/fs/ocfs2/cluster/masklog.c
+@@ -146,7 +146,7 @@ static struct kset mlog_kset = {
+ 	.kobj   = {.ktype = &mlog_ktype},
+ };
+ 
+-int mlog_sys_init(struct kset *o2cb_subsys)
++int mlog_sys_init(struct kset *o2cb_kset)
  {
- 	int rc = 0;
- 	__u32 acllen = 0;
--	struct cifs_ntsd *pntsd = NULL;
-+	struct cifs_ntsd *pntsd = NULL; /* acl obtained from server */
-+	struct cifs_ntsd *pnntsd = NULL; /* modified acl to be sent to server */
+ 	int i = 0;
  
-+#ifdef CONFIG_CIFS_DEBUG2
- 	cFYI(1, ("set ACL from mode for %s", path));
-+#endif
+@@ -157,7 +157,7 @@ int mlog_sys_init(struct kset *o2cb_subsys)
+ 	mlog_attr_ptrs[i] = NULL;
  
- 	/* Get the security descriptor */
- 	pntsd = get_cifs_acl(&acllen, inode, path);
+ 	kobject_set_name(&mlog_kset.kobj, "logmask");
+-	kobj_set_kset_s(&mlog_kset, *o2cb_subsys);
++	mlog_kset.kobj.kset = o2cb_kset;
+ 	return kset_register(&mlog_kset);
+ }
  
--	/* Add/Modify the three ACEs for owner, group, everyone
--	   while retaining the other ACEs */
-+	/* Add three ACEs for owner, group, everyone getting rid of
-+	   other ACEs as chmod disables ACEs and set the security descriptor */
+diff --git a/fs/ocfs2/cluster/sys.c b/fs/ocfs2/cluster/sys.c
+index 64f6f37..a4b0773 100644
+--- a/fs/ocfs2/cluster/sys.c
++++ b/fs/ocfs2/cluster/sys.c
+@@ -28,96 +28,55 @@
+ #include <linux/module.h>
+ #include <linux/kobject.h>
+ #include <linux/sysfs.h>
++#include <linux/fs.h>
  
--	/* Set the security descriptor */
-+	if (pntsd) {
-+		/* allocate memory for the smb header,
-+		   set security descriptor request security descriptor
-+		   parameters, and secuirty descriptor itself */
+ #include "ocfs2_nodemanager.h"
+ #include "masklog.h"
+ #include "sys.h"
  
-+		pnntsd = kmalloc(acllen, GFP_KERNEL);
-+		if (!pnntsd) {
-+			cERROR(1, ("Unable to allocate security descriptor"));
-+			kfree(pntsd);
-+			return (-ENOMEM);
-+		}
+-struct o2cb_attribute {
+-	struct attribute	attr;
+-	ssize_t (*show)(char *buf);
+-	ssize_t (*store)(const char *buf, size_t count);
+-};
+-
+-#define O2CB_ATTR(_name, _mode, _show, _store)	\
+-struct o2cb_attribute o2cb_attr_##_name = __ATTR(_name, _mode, _show, _store)
+-
+-#define to_o2cb_attr(_attr) container_of(_attr, struct o2cb_attribute, attr)
  
--	kfree(pntsd);
--	return rc;
-+		rc = build_sec_desc(pntsd, pnntsd, acllen, inode, nmode);
-+
-+#ifdef CONFIG_CIFS_DEBUG2
-+		cFYI(1, ("build_sec_desc rc: %d", rc));
-+#endif
-+
-+		if (!rc) {
-+			/* Set the security descriptor */
-+			rc = set_cifs_acl(pnntsd, acllen, inode, path);
-+#ifdef CONFIG_CIFS_DEBUG2
-+			cFYI(1, ("set_cifs_acl rc: %d", rc));
-+#endif
-+		}
-+
-+		kfree(pnntsd);
-+		kfree(pntsd);
-+	}
-+
-+	return (rc);
+-static ssize_t o2cb_interface_revision_show(char *buf)
++static ssize_t version_show(struct kobject *kobj, struct kobj_attribute *attr,
++			    char *buf)
+ {
+ 	return snprintf(buf, PAGE_SIZE, "%u\n", O2NM_API_VERSION);
  }
- #endif /* CONFIG_CIFS_EXPERIMENTAL */
-diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
-index 093beaa..e9f4ec7 100644
---- a/fs/cifs/cifsfs.c
-+++ b/fs/cifs/cifsfs.c
-@@ -44,6 +44,7 @@
- #include "cifs_fs_sb.h"
- #include <linux/mm.h>
- #include <linux/key-type.h>
-+#include "dns_resolve.h"
- #include "cifs_spnego.h"
- #define CIFS_MAGIC_NUMBER 0xFF534D42	/* the first four bytes of SMB PDUs */
+-
+-static O2CB_ATTR(interface_revision, S_IFREG | S_IRUGO, o2cb_interface_revision_show, NULL);
++static struct kobj_attribute attr_version =
++	__ATTR(interface_revision, S_IFREG | S_IRUGO, version_show, NULL);
  
-@@ -96,6 +97,9 @@ cifs_read_super(struct super_block *sb, void *data,
+ static struct attribute *o2cb_attrs[] = {
+-	&o2cb_attr_interface_revision.attr,
++	&attr_version.attr,
+ 	NULL,
+ };
+ 
+-static ssize_t
+-o2cb_show(struct kobject * kobj, struct attribute * attr, char * buffer);
+-static ssize_t
+-o2cb_store(struct kobject * kobj, struct attribute * attr,
+-	   const char * buffer, size_t count);
+-static struct sysfs_ops o2cb_sysfs_ops = {
+-	.show	= o2cb_show,
+-	.store	= o2cb_store,
++static struct attribute_group o2cb_attr_group = {
++	.attrs = o2cb_attrs,
+ };
+ 
+-static struct kobj_type o2cb_subsys_type = {
+-	.default_attrs	= o2cb_attrs,
+-	.sysfs_ops	= &o2cb_sysfs_ops,
+-};
+-
+-/* gives us o2cb_subsys */
+-static decl_subsys(o2cb, NULL, NULL);
+-
+-static ssize_t
+-o2cb_show(struct kobject * kobj, struct attribute * attr, char * buffer)
+-{
+-	struct o2cb_attribute *o2cb_attr = to_o2cb_attr(attr);
+-	struct kset *sbs = to_kset(kobj);
+-
+-	BUG_ON(sbs != &o2cb_subsys);
+-
+-	if (o2cb_attr->show)
+-		return o2cb_attr->show(buffer);
+-	return -EIO;
+-}
+-
+-static ssize_t
+-o2cb_store(struct kobject * kobj, struct attribute * attr,
+-	     const char * buffer, size_t count)
+-{
+-	struct o2cb_attribute *o2cb_attr = to_o2cb_attr(attr);
+-	struct kset *sbs = to_kset(kobj);
+-
+-	BUG_ON(sbs != &o2cb_subsys);
+-
+-	if (o2cb_attr->store)
+-		return o2cb_attr->store(buffer, count);
+-	return -EIO;
+-}
++static struct kset *o2cb_kset;
+ 
+ void o2cb_sys_shutdown(void)
  {
- 	struct inode *inode;
- 	struct cifs_sb_info *cifs_sb;
-+#ifdef CONFIG_CIFS_DFS_UPCALL
-+	int len;
-+#endif
- 	int rc = 0;
+ 	mlog_sys_shutdown();
+-	subsystem_unregister(&o2cb_subsys);
++	kset_unregister(o2cb_kset);
+ }
  
- 	/* BB should we make this contingent on mount parm? */
-@@ -105,6 +109,25 @@ cifs_read_super(struct super_block *sb, void *data,
- 	if (cifs_sb == NULL)
- 		return -ENOMEM;
+ int o2cb_sys_init(void)
+ {
+ 	int ret;
  
-+#ifdef CONFIG_CIFS_DFS_UPCALL
-+	/* copy mount params to sb for use in submounts */
-+	/* BB: should we move this after the mount so we
-+	 * do not have to do the copy on failed mounts?
-+	 * BB: May be it is better to do simple copy before
-+	 * complex operation (mount), and in case of fail
-+	 * just exit instead of doing mount and attempting
-+	 * undo it if this copy fails?*/
-+	len = strlen(data);
-+	cifs_sb->mountdata = kzalloc(len + 1, GFP_KERNEL);
-+	if (cifs_sb->mountdata == NULL) {
-+		kfree(sb->s_fs_info);
-+		sb->s_fs_info = NULL;
+-	o2cb_subsys.kobj.ktype = &o2cb_subsys_type;
+-	ret = subsystem_register(&o2cb_subsys);
++	o2cb_kset = kset_create_and_add("o2cb", NULL, fs_kobj);
++	if (!o2cb_kset)
 +		return -ENOMEM;
-+	}
-+	strncpy(cifs_sb->mountdata, data, len + 1);
-+	cifs_sb->mountdata[len] = '\0';
-+#endif
 +
- 	rc = cifs_mount(sb, cifs_sb, data, devname);
++	ret = sysfs_create_group(&o2cb_kset->kobj, &o2cb_attr_group);
+ 	if (ret)
+-		return ret;
++		goto error;
+ 
+-	ret = mlog_sys_init(&o2cb_subsys);
++	ret = mlog_sys_init(o2cb_kset);
+ 	if (ret)
+-		subsystem_unregister(&o2cb_subsys);
++		goto error;
++	return 0;
++error:
++	kset_unregister(o2cb_kset);
+ 	return ret;
+ }
+diff --git a/fs/ocfs2/cluster/tcp.h b/fs/ocfs2/cluster/tcp.h
+index da880fc..f36f66a 100644
+--- a/fs/ocfs2/cluster/tcp.h
++++ b/fs/ocfs2/cluster/tcp.h
+@@ -60,8 +60,8 @@ typedef void (o2net_post_msg_handler_func)(int status, void *data,
+ /* same as hb delay, we're waiting for another node to recognize our hb */
+ #define O2NET_RECONNECT_DELAY_MS_DEFAULT	2000
+ 
+-#define O2NET_KEEPALIVE_DELAY_MS_DEFAULT	5000
+-#define O2NET_IDLE_TIMEOUT_MS_DEFAULT		10000
++#define O2NET_KEEPALIVE_DELAY_MS_DEFAULT	2000
++#define O2NET_IDLE_TIMEOUT_MS_DEFAULT		30000
+ 
+ 
+ /* TODO: figure this out.... */
+diff --git a/fs/ocfs2/cluster/tcp_internal.h b/fs/ocfs2/cluster/tcp_internal.h
+index 9606111..b2e832a 100644
+--- a/fs/ocfs2/cluster/tcp_internal.h
++++ b/fs/ocfs2/cluster/tcp_internal.h
+@@ -38,6 +38,12 @@
+  * locking semantics of the file system using the protocol.  It should 
+  * be somewhere else, I'm sure, but right now it isn't.
+  *
++ * New in version 10:
++ * 	- Meta/data locks combined
++ *
++ * New in version 9:
++ * 	- All votes removed
++ *
+  * New in version 8:
+  * 	- Replace delete inode votes with a cluster lock
+  *
+@@ -60,7 +66,7 @@
+  * 	- full 64 bit i_size in the metadata lock lvbs
+  * 	- introduction of "rw" lock and pushing meta/data locking down
+  */
+-#define O2NET_PROTOCOL_VERSION 8ULL
++#define O2NET_PROTOCOL_VERSION 10ULL
+ struct o2net_handshake {
+ 	__be64	protocol_version;
+ 	__be64	connector_id;
+diff --git a/fs/ocfs2/cluster/ver.c b/fs/ocfs2/cluster/ver.c
+index 7286c48..a56eee6 100644
+--- a/fs/ocfs2/cluster/ver.c
++++ b/fs/ocfs2/cluster/ver.c
+@@ -28,7 +28,7 @@
+ 
+ #include "ver.h"
+ 
+-#define CLUSTER_BUILD_VERSION "1.3.3"
++#define CLUSTER_BUILD_VERSION "1.5.0"
+ 
+ #define VERSION_STR "OCFS2 Node Manager " CLUSTER_BUILD_VERSION
+ 
+diff --git a/fs/ocfs2/dcache.c b/fs/ocfs2/dcache.c
+index 9923278..b1cc7c3 100644
+--- a/fs/ocfs2/dcache.c
++++ b/fs/ocfs2/dcache.c
+@@ -128,9 +128,9 @@ static int ocfs2_match_dentry(struct dentry *dentry,
+ /*
+  * Walk the inode alias list, and find a dentry which has a given
+  * parent. ocfs2_dentry_attach_lock() wants to find _any_ alias as it
+- * is looking for a dentry_lock reference. The vote thread is looking
+- * to unhash aliases, so we allow it to skip any that already have
+- * that property.
++ * is looking for a dentry_lock reference. The downconvert thread is
++ * looking to unhash aliases, so we allow it to skip any that already
++ * have that property.
+  */
+ struct dentry *ocfs2_find_local_alias(struct inode *inode,
+ 				      u64 parent_blkno,
+@@ -266,7 +266,7 @@ int ocfs2_dentry_attach_lock(struct dentry *dentry,
+ 	dl->dl_count = 0;
+ 	/*
+ 	 * Does this have to happen below, for all attaches, in case
+-	 * the struct inode gets blown away by votes?
++	 * the struct inode gets blown away by the downconvert thread?
+ 	 */
+ 	dl->dl_inode = igrab(inode);
+ 	dl->dl_parent_blkno = parent_blkno;
+diff --git a/fs/ocfs2/dir.c b/fs/ocfs2/dir.c
+index 63b28fd..6b0107f 100644
+--- a/fs/ocfs2/dir.c
++++ b/fs/ocfs2/dir.c
+@@ -846,14 +846,14 @@ int ocfs2_readdir(struct file * filp, void * dirent, filldir_t filldir)
+ 	mlog_entry("dirino=%llu\n",
+ 		   (unsigned long long)OCFS2_I(inode)->ip_blkno);
+ 
+-	error = ocfs2_meta_lock_atime(inode, filp->f_vfsmnt, &lock_level);
++	error = ocfs2_inode_lock_atime(inode, filp->f_vfsmnt, &lock_level);
+ 	if (lock_level && error >= 0) {
+ 		/* We release EX lock which used to update atime
+ 		 * and get PR lock again to reduce contention
+ 		 * on commonly accessed directories. */
+-		ocfs2_meta_unlock(inode, 1);
++		ocfs2_inode_unlock(inode, 1);
+ 		lock_level = 0;
+-		error = ocfs2_meta_lock(inode, NULL, 0);
++		error = ocfs2_inode_lock(inode, NULL, 0);
+ 	}
+ 	if (error < 0) {
+ 		if (error != -ENOENT)
+@@ -865,7 +865,7 @@ int ocfs2_readdir(struct file * filp, void * dirent, filldir_t filldir)
+ 	error = ocfs2_dir_foreach_blk(inode, &filp->f_version, &filp->f_pos,
+ 				      dirent, filldir, NULL);
+ 
+-	ocfs2_meta_unlock(inode, lock_level);
++	ocfs2_inode_unlock(inode, lock_level);
  
- 	if (rc) {
-@@ -154,6 +177,12 @@ out_no_root:
+ bail_nolock:
+ 	mlog_exit(error);
+diff --git a/fs/ocfs2/dlm/dlmfsver.c b/fs/ocfs2/dlm/dlmfsver.c
+index d2be3ad..a733b33 100644
+--- a/fs/ocfs2/dlm/dlmfsver.c
++++ b/fs/ocfs2/dlm/dlmfsver.c
+@@ -28,7 +28,7 @@
  
- out_mount_failed:
- 	if (cifs_sb) {
-+#ifdef CONFIG_CIFS_DFS_UPCALL
-+		if (cifs_sb->mountdata) {
-+			kfree(cifs_sb->mountdata);
-+			cifs_sb->mountdata = NULL;
-+		}
-+#endif
- 		if (cifs_sb->local_nls)
- 			unload_nls(cifs_sb->local_nls);
- 		kfree(cifs_sb);
-@@ -177,6 +206,13 @@ cifs_put_super(struct super_block *sb)
- 	if (rc) {
- 		cERROR(1, ("cifs_umount failed with return code %d", rc));
+ #include "dlmfsver.h"
+ 
+-#define DLM_BUILD_VERSION "1.3.3"
++#define DLM_BUILD_VERSION "1.5.0"
+ 
+ #define VERSION_STR "OCFS2 DLMFS " DLM_BUILD_VERSION
+ 
+diff --git a/fs/ocfs2/dlm/dlmrecovery.c b/fs/ocfs2/dlm/dlmrecovery.c
+index 2fde7bf..91f747b 100644
+--- a/fs/ocfs2/dlm/dlmrecovery.c
++++ b/fs/ocfs2/dlm/dlmrecovery.c
+@@ -2270,6 +2270,12 @@ static void __dlm_hb_node_down(struct dlm_ctxt *dlm, int idx)
+ 		}
  	}
-+#ifdef CONFIG_CIFS_DFS_UPCALL
-+	if (cifs_sb->mountdata) {
-+		kfree(cifs_sb->mountdata);
-+		cifs_sb->mountdata = NULL;
+ 
++	/* Clean up join state on node death. */
++	if (dlm->joining_node == idx) {
++		mlog(0, "Clearing join state for node %u\n", idx);
++		__dlm_set_joining_node(dlm, DLM_LOCK_RES_OWNER_UNKNOWN);
 +	}
-+#endif
 +
- 	unload_nls(cifs_sb->local_nls);
- 	kfree(cifs_sb);
- 	return;
-@@ -435,6 +471,10 @@ static void cifs_umount_begin(struct vfsmount *vfsmnt, int flags)
- 	struct cifs_sb_info *cifs_sb;
- 	struct cifsTconInfo *tcon;
+ 	/* check to see if the node is already considered dead */
+ 	if (!test_bit(idx, dlm->live_nodes_map)) {
+ 		mlog(0, "for domain %s, node %d is already dead. "
+@@ -2288,12 +2294,6 @@ static void __dlm_hb_node_down(struct dlm_ctxt *dlm, int idx)
  
-+#ifdef CONFIG_CIFS_DFS_UPCALL
-+	dfs_shrink_umount_helper(vfsmnt);
-+#endif /* CONFIG CIFS_DFS_UPCALL */
-+
- 	if (!(flags & MNT_FORCE))
+ 	clear_bit(idx, dlm->live_nodes_map);
+ 
+-	/* Clean up join state on node death. */
+-	if (dlm->joining_node == idx) {
+-		mlog(0, "Clearing join state for node %u\n", idx);
+-		__dlm_set_joining_node(dlm, DLM_LOCK_RES_OWNER_UNKNOWN);
+-	}
+-
+ 	/* make sure local cleanup occurs before the heartbeat events */
+ 	if (!test_bit(idx, dlm->recovery_map))
+ 		dlm_do_local_recovery_cleanup(dlm, idx);
+@@ -2321,6 +2321,13 @@ void dlm_hb_node_down_cb(struct o2nm_node *node, int idx, void *data)
+ 	if (!dlm_grab(dlm))
  		return;
- 	cifs_sb = CIFS_SB(vfsmnt->mnt_sb);
-@@ -552,7 +592,7 @@ static loff_t cifs_llseek(struct file *file, loff_t offset, int origin)
- 	return remote_llseek(file, offset, origin);
- }
  
--static struct file_system_type cifs_fs_type = {
-+struct file_system_type cifs_fs_type = {
- 	.owner = THIS_MODULE,
- 	.name = "cifs",
- 	.get_sb = cifs_get_sb,
-@@ -1015,11 +1055,16 @@ init_cifs(void)
- 	if (rc)
- 		goto out_unregister_filesystem;
- #endif
-+#ifdef CONFIG_CIFS_DFS_UPCALL
-+	rc = register_key_type(&key_type_dns_resolver);
-+	if (rc)
-+		goto out_unregister_key_type;
-+#endif
- 	oplockThread = kthread_run(cifs_oplock_thread, NULL, "cifsoplockd");
- 	if (IS_ERR(oplockThread)) {
- 		rc = PTR_ERR(oplockThread);
- 		cERROR(1, ("error %d create oplock thread", rc));
--		goto out_unregister_key_type;
-+		goto out_unregister_dfs_key_type;
- 	}
++	/*
++	 * This will notify any dlm users that a node in our domain
++	 * went away without notifying us first.
++	 */
++	if (test_bit(idx, dlm->domain_map))
++		dlm_fire_domain_eviction_callbacks(dlm, idx);
++
+ 	spin_lock(&dlm->spinlock);
+ 	__dlm_hb_node_down(dlm, idx);
+ 	spin_unlock(&dlm->spinlock);
+diff --git a/fs/ocfs2/dlm/dlmver.c b/fs/ocfs2/dlm/dlmver.c
+index 7ef2653..dfc0da4 100644
+--- a/fs/ocfs2/dlm/dlmver.c
++++ b/fs/ocfs2/dlm/dlmver.c
+@@ -28,7 +28,7 @@
  
- 	dnotifyThread = kthread_run(cifs_dnotify_thread, NULL, "cifsdnotifyd");
-@@ -1033,7 +1078,11 @@ init_cifs(void)
+ #include "dlmver.h"
  
-  out_stop_oplock_thread:
- 	kthread_stop(oplockThread);
-+ out_unregister_dfs_key_type:
-+#ifdef CONFIG_CIFS_DFS_UPCALL
-+	unregister_key_type(&key_type_dns_resolver);
-  out_unregister_key_type:
-+#endif
- #ifdef CONFIG_CIFS_UPCALL
- 	unregister_key_type(&cifs_spnego_key_type);
-  out_unregister_filesystem:
-@@ -1059,6 +1108,9 @@ exit_cifs(void)
- #ifdef CONFIG_PROC_FS
- 	cifs_proc_clean();
- #endif
-+#ifdef CONFIG_CIFS_DFS_UPCALL
-+	unregister_key_type(&key_type_dns_resolver);
-+#endif
- #ifdef CONFIG_CIFS_UPCALL
- 	unregister_key_type(&cifs_spnego_key_type);
- #endif
-diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h
-index 2a21dc6..195b14d 100644
---- a/fs/cifs/cifsfs.h
-+++ b/fs/cifs/cifsfs.h
-@@ -32,6 +32,7 @@
- #define TRUE 1
- #endif
+-#define DLM_BUILD_VERSION "1.3.3"
++#define DLM_BUILD_VERSION "1.5.0"
  
-+extern struct file_system_type cifs_fs_type;
- extern const struct address_space_operations cifs_addr_ops;
- extern const struct address_space_operations cifs_addr_ops_smallbuf;
+ #define VERSION_STR "OCFS2 DLM " DLM_BUILD_VERSION
  
-@@ -60,6 +61,10 @@ extern int cifs_setattr(struct dentry *, struct iattr *);
+diff --git a/fs/ocfs2/dlmglue.c b/fs/ocfs2/dlmglue.c
+index 4e97dcc..3867244 100644
+--- a/fs/ocfs2/dlmglue.c
++++ b/fs/ocfs2/dlmglue.c
+@@ -55,7 +55,6 @@
+ #include "slot_map.h"
+ #include "super.h"
+ #include "uptodate.h"
+-#include "vote.h"
  
- extern const struct inode_operations cifs_file_inode_ops;
- extern const struct inode_operations cifs_symlink_inode_ops;
-+extern struct list_head cifs_dfs_automount_list;
-+extern struct inode_operations cifs_dfs_referral_inode_operations;
-+
-+
+ #include "buffer_head_io.h"
  
- /* Functions related to files and directories */
- extern const struct file_operations cifs_file_ops;
-diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
-index 1fde219..5d32d8d 100644
---- a/fs/cifs/cifsglob.h
-+++ b/fs/cifs/cifsglob.h
-@@ -1,7 +1,7 @@
- /*
-  *   fs/cifs/cifsglob.h
-  *
-- *   Copyright (C) International Business Machines  Corp., 2002,2007
-+ *   Copyright (C) International Business Machines  Corp., 2002,2008
-  *   Author(s): Steve French (sfrench at us.ibm.com)
-  *              Jeremy Allison (jra at samba.org)
-  *
-@@ -70,14 +70,6 @@
- #endif
+@@ -69,6 +68,7 @@ struct ocfs2_mask_waiter {
+ 
+ static struct ocfs2_super *ocfs2_get_dentry_osb(struct ocfs2_lock_res *lockres);
+ static struct ocfs2_super *ocfs2_get_inode_osb(struct ocfs2_lock_res *lockres);
++static struct ocfs2_super *ocfs2_get_file_osb(struct ocfs2_lock_res *lockres);
  
  /*
-- * This information is kept on every Server we know about.
-- *
-- * Some things to note:
-- *
-- */
--#define SERVER_NAME_LEN_WITH_NULL	(SERVER_NAME_LENGTH + 1)
+  * Return value from ->downconvert_worker functions.
+@@ -153,10 +153,10 @@ struct ocfs2_lock_res_ops {
+ 	struct ocfs2_super * (*get_osb)(struct ocfs2_lock_res *);
+ 
+ 	/*
+-	 * Optionally called in the downconvert (or "vote") thread
+-	 * after a successful downconvert. The lockres will not be
+-	 * referenced after this callback is called, so it is safe to
+-	 * free memory, etc.
++	 * Optionally called in the downconvert thread after a
++	 * successful downconvert. The lockres will not be referenced
++	 * after this callback is called, so it is safe to free
++	 * memory, etc.
+ 	 *
+ 	 * The exact semantics of when this is called are controlled
+ 	 * by ->downconvert_worker()
+@@ -225,17 +225,12 @@ static struct ocfs2_lock_res_ops ocfs2_inode_rw_lops = {
+ 	.flags		= 0,
+ };
+ 
+-static struct ocfs2_lock_res_ops ocfs2_inode_meta_lops = {
++static struct ocfs2_lock_res_ops ocfs2_inode_inode_lops = {
+ 	.get_osb	= ocfs2_get_inode_osb,
+ 	.check_downconvert = ocfs2_check_meta_downconvert,
+ 	.set_lvb	= ocfs2_set_meta_lvb,
+-	.flags		= LOCK_TYPE_REQUIRES_REFRESH|LOCK_TYPE_USES_LVB,
+-};
 -
--/*
-  * CIFS vfs client Status information (based on what we know.)
-  */
+-static struct ocfs2_lock_res_ops ocfs2_inode_data_lops = {
+-	.get_osb	= ocfs2_get_inode_osb,
+ 	.downconvert_worker = ocfs2_data_convert_worker,
+-	.flags		= 0,
++	.flags		= LOCK_TYPE_REQUIRES_REFRESH|LOCK_TYPE_USES_LVB,
+ };
  
-@@ -460,6 +452,37 @@ struct dir_notify_req {
-        struct file *pfile;
+ static struct ocfs2_lock_res_ops ocfs2_super_lops = {
+@@ -258,10 +253,14 @@ static struct ocfs2_lock_res_ops ocfs2_inode_open_lops = {
+ 	.flags		= 0,
  };
  
-+struct dfs_info3_param {
-+	int flags; /* DFSREF_REFERRAL_SERVER, DFSREF_STORAGE_SERVER*/
-+	int PathConsumed;
-+	int server_type;
-+	int ref_flag;
-+	char *path_name;
-+	char *node_name;
++static struct ocfs2_lock_res_ops ocfs2_flock_lops = {
++	.get_osb	= ocfs2_get_file_osb,
++	.flags		= 0,
 +};
 +
-+static inline void free_dfs_info_param(struct dfs_info3_param *param)
-+{
-+	if (param) {
-+		kfree(param->path_name);
-+		kfree(param->node_name);
-+		kfree(param);
-+	}
-+}
-+
-+static inline void free_dfs_info_array(struct dfs_info3_param *param,
-+				       int number_of_items)
-+{
-+	int i;
-+	if ((number_of_items == 0) || (param == NULL))
-+		return;
-+	for (i = 0; i < number_of_items; i++) {
-+		kfree(param[i].path_name);
-+		kfree(param[i].node_name);
-+	}
-+	kfree(param);
-+}
-+
- #define   MID_FREE 0
- #define   MID_REQUEST_ALLOCATED 1
- #define   MID_REQUEST_SUBMITTED 2
-diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h
-index dbe6b84..47f7950 100644
---- a/fs/cifs/cifspdu.h
-+++ b/fs/cifs/cifspdu.h
-@@ -237,6 +237,9 @@
- 				| DELETE | READ_CONTROL | WRITE_DAC \
- 				| WRITE_OWNER | SYNCHRONIZE)
- 
-+#define SET_MINIMUM_RIGHTS (FILE_READ_EA | FILE_READ_ATTRIBUTES \
-+				| READ_CONTROL | SYNCHRONIZE)
+ static inline int ocfs2_is_inode_lock(struct ocfs2_lock_res *lockres)
+ {
+ 	return lockres->l_type == OCFS2_LOCK_TYPE_META ||
+-		lockres->l_type == OCFS2_LOCK_TYPE_DATA ||
+ 		lockres->l_type == OCFS2_LOCK_TYPE_RW ||
+ 		lockres->l_type == OCFS2_LOCK_TYPE_OPEN;
+ }
+@@ -310,12 +309,24 @@ static inline void ocfs2_recover_from_dlm_error(struct ocfs2_lock_res *lockres,
+ 		"resource %s: %s\n", dlm_errname(_stat), _func,	\
+ 		_lockres->l_name, dlm_errmsg(_stat));		\
+ } while (0)
+-static void ocfs2_vote_on_unlock(struct ocfs2_super *osb,
+-				 struct ocfs2_lock_res *lockres);
+-static int ocfs2_meta_lock_update(struct inode *inode,
++static int ocfs2_downconvert_thread(void *arg);
++static void ocfs2_downconvert_on_unlock(struct ocfs2_super *osb,
++					struct ocfs2_lock_res *lockres);
++static int ocfs2_inode_lock_update(struct inode *inode,
+ 				  struct buffer_head **bh);
+ static void ocfs2_drop_osb_locks(struct ocfs2_super *osb);
+ static inline int ocfs2_highest_compat_lock_level(int level);
++static void ocfs2_prepare_downconvert(struct ocfs2_lock_res *lockres,
++				      int new_level);
++static int ocfs2_downconvert_lock(struct ocfs2_super *osb,
++				  struct ocfs2_lock_res *lockres,
++				  int new_level,
++				  int lvb);
++static int ocfs2_prepare_cancel_convert(struct ocfs2_super *osb,
++				        struct ocfs2_lock_res *lockres);
++static int ocfs2_cancel_convert(struct ocfs2_super *osb,
++				struct ocfs2_lock_res *lockres);
 +
  
- /*
-  * Invalid readdir handle
-diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
-index 8350eec..2f09f56 100644
---- a/fs/cifs/cifsproto.h
-+++ b/fs/cifs/cifsproto.h
-@@ -1,7 +1,7 @@
- /*
-  *   fs/cifs/cifsproto.h
-  *
-- *   Copyright (c) International Business Machines  Corp., 2002,2007
-+ *   Copyright (c) International Business Machines  Corp., 2002,2008
-  *   Author(s): Steve French (sfrench at us.ibm.com)
-  *
-  *   This library is free software; you can redistribute it and/or modify
-@@ -97,11 +97,14 @@ extern int cifs_get_inode_info_unix(struct inode **pinode,
- 			const unsigned char *search_path,
- 			struct super_block *sb, int xid);
- extern void acl_to_uid_mode(struct inode *inode, const char *search_path);
--extern int mode_to_acl(struct inode *inode, const char *path);
-+extern int mode_to_acl(struct inode *inode, const char *path, __u64);
- 
- extern int cifs_mount(struct super_block *, struct cifs_sb_info *, char *,
- 			const char *);
- extern int cifs_umount(struct super_block *, struct cifs_sb_info *);
-+#ifdef CONFIG_CIFS_DFS_UPCALL
-+extern void dfs_shrink_umount_helper(struct vfsmount *vfsmnt);
-+#endif
- void cifs_proc_init(void);
- void cifs_proc_clean(void);
- 
-@@ -153,7 +156,7 @@ extern int get_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
- 			const char *old_path,
- 			const struct nls_table *nls_codepage,
- 			unsigned int *pnum_referrals,
--			unsigned char **preferrals,
-+			struct dfs_info3_param **preferrals,
- 			int remap);
- extern void reset_cifs_unix_caps(int xid, struct cifsTconInfo *tcon,
- 				 struct super_block *sb, struct smb_vol *vol);
-@@ -342,6 +345,8 @@ extern int CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon,
- 		const struct nls_table *nls_codepage, int remap_special_chars);
- extern int CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon,
- 			__u16 fid, struct cifs_ntsd **acl_inf, __u32 *buflen);
-+extern int CIFSSMBSetCIFSACL(const int, struct cifsTconInfo *, __u16,
-+			struct cifs_ntsd *, __u32);
- extern int CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
- 		const unsigned char *searchName,
- 		char *acl_inf, const int buflen, const int acl_type,
-diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
-index 9e8a6be..9409524 100644
---- a/fs/cifs/cifssmb.c
-+++ b/fs/cifs/cifssmb.c
-@@ -3156,6 +3156,71 @@ qsec_out:
- /*	cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
- 	return rc;
+ static void ocfs2_build_lock_name(enum ocfs2_lock_type type,
+ 				  u64 blkno,
+@@ -402,10 +413,7 @@ void ocfs2_inode_lock_res_init(struct ocfs2_lock_res *res,
+ 			ops = &ocfs2_inode_rw_lops;
+ 			break;
+ 		case OCFS2_LOCK_TYPE_META:
+-			ops = &ocfs2_inode_meta_lops;
+-			break;
+-		case OCFS2_LOCK_TYPE_DATA:
+-			ops = &ocfs2_inode_data_lops;
++			ops = &ocfs2_inode_inode_lops;
+ 			break;
+ 		case OCFS2_LOCK_TYPE_OPEN:
+ 			ops = &ocfs2_inode_open_lops;
+@@ -428,6 +436,13 @@ static struct ocfs2_super *ocfs2_get_inode_osb(struct ocfs2_lock_res *lockres)
+ 	return OCFS2_SB(inode->i_sb);
  }
-+
-+int
-+CIFSSMBSetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
-+			struct cifs_ntsd *pntsd, __u32 acllen)
+ 
++static struct ocfs2_super *ocfs2_get_file_osb(struct ocfs2_lock_res *lockres)
 +{
-+	__u16 byte_count, param_count, data_count, param_offset, data_offset;
-+	int rc = 0;
-+	int bytes_returned = 0;
-+	SET_SEC_DESC_REQ *pSMB = NULL;
-+	NTRANSACT_RSP *pSMBr = NULL;
-+
-+setCifsAclRetry:
-+	rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB,
-+			(void **) &pSMBr);
-+	if (rc)
-+			return (rc);
-+
-+	pSMB->MaxSetupCount = 0;
-+	pSMB->Reserved = 0;
-+
-+	param_count = 8;
-+	param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
-+	data_count = acllen;
-+	data_offset = param_offset + param_count;
-+	byte_count = 3 /* pad */  + param_count;
-+
-+	pSMB->DataCount = cpu_to_le32(data_count);
-+	pSMB->TotalDataCount = pSMB->DataCount;
-+	pSMB->MaxParameterCount = cpu_to_le32(4);
-+	pSMB->MaxDataCount = cpu_to_le32(16384);
-+	pSMB->ParameterCount = cpu_to_le32(param_count);
-+	pSMB->ParameterOffset = cpu_to_le32(param_offset);
-+	pSMB->TotalParameterCount = pSMB->ParameterCount;
-+	pSMB->DataOffset = cpu_to_le32(data_offset);
-+	pSMB->SetupCount = 0;
-+	pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
-+	pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
-+
-+	pSMB->Fid = fid; /* file handle always le */
-+	pSMB->Reserved2 = 0;
-+	pSMB->AclFlags = cpu_to_le32(CIFS_ACL_DACL);
-+
-+	if (pntsd && acllen) {
-+		memcpy((char *) &pSMBr->hdr.Protocol + data_offset,
-+			(char *) pntsd,
-+			acllen);
-+		pSMB->hdr.smb_buf_length += (byte_count + data_count);
-+
-+	} else
-+		pSMB->hdr.smb_buf_length += byte_count;
-+
-+	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
-+		(struct smb_hdr *) pSMBr, &bytes_returned, 0);
-+
-+	cFYI(1, ("SetCIFSACL bytes_returned: %d, rc: %d", bytes_returned, rc));
-+	if (rc)
-+		cFYI(1, ("Set CIFS ACL returned %d", rc));
-+	cifs_buf_release(pSMB);
-+
-+	if (rc == -EAGAIN)
-+		goto setCifsAclRetry;
++	struct ocfs2_file_private *fp = lockres->l_priv;
 +
-+	return (rc);
++	return OCFS2_SB(fp->fp_file->f_mapping->host->i_sb);
 +}
 +
- #endif /* CONFIG_CIFS_EXPERIMENTAL */
- 
- /* Legacy Query Path Information call for lookup to old servers such
-@@ -5499,7 +5564,7 @@ SetEARetry:
- 	else
- 		name_len = strnlen(ea_name, 255);
- 
--	count = sizeof(*parm_data) + ea_value_len + name_len + 1;
-+	count = sizeof(*parm_data) + ea_value_len + name_len;
- 	pSMB->MaxParameterCount = cpu_to_le16(2);
- 	pSMB->MaxDataCount = cpu_to_le16(1000);	/* BB find max SMB size from sess */
- 	pSMB->MaxSetupCount = 0;
-diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
-index fd9147c..65d0ba7 100644
---- a/fs/cifs/connect.c
-+++ b/fs/cifs/connect.c
-@@ -1,7 +1,7 @@
- /*
-  *   fs/cifs/connect.c
-  *
-- *   Copyright (C) International Business Machines  Corp., 2002,2007
-+ *   Copyright (C) International Business Machines  Corp., 2002,2008
-  *   Author(s): Steve French (sfrench at us.ibm.com)
-  *
-  *   This library is free software; you can redistribute it and/or modify
-@@ -1410,7 +1410,7 @@ connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
- 		    const char *old_path, const struct nls_table *nls_codepage,
- 		    int remap)
+ static __u64 ocfs2_get_dentry_lock_ino(struct ocfs2_lock_res *lockres)
  {
--	unsigned char *referrals = NULL;
-+	struct dfs_info3_param *referrals = NULL;
- 	unsigned int num_referrals;
- 	int rc = 0;
+ 	__be64 inode_blkno_be;
+@@ -508,6 +523,21 @@ static void ocfs2_rename_lock_res_init(struct ocfs2_lock_res *res,
+ 				   &ocfs2_rename_lops, osb);
+ }
  
-@@ -1429,12 +1429,14 @@ connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
- int
- get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path,
- 	     const struct nls_table *nls_codepage, unsigned int *pnum_referrals,
--	     unsigned char **preferrals, int remap)
-+	     struct dfs_info3_param **preferrals, int remap)
++void ocfs2_file_lock_res_init(struct ocfs2_lock_res *lockres,
++			      struct ocfs2_file_private *fp)
++{
++	struct inode *inode = fp->fp_file->f_mapping->host;
++	struct ocfs2_inode_info *oi = OCFS2_I(inode);
++
++	ocfs2_lock_res_init_once(lockres);
++	ocfs2_build_lock_name(OCFS2_LOCK_TYPE_FLOCK, oi->ip_blkno,
++			      inode->i_generation, lockres->l_name);
++	ocfs2_lock_res_init_common(OCFS2_SB(inode->i_sb), lockres,
++				   OCFS2_LOCK_TYPE_FLOCK, &ocfs2_flock_lops,
++				   fp);
++	lockres->l_flags |= OCFS2_LOCK_NOCACHE;
++}
++
+ void ocfs2_lock_res_free(struct ocfs2_lock_res *res)
  {
- 	char *temp_unc;
- 	int rc = 0;
-+	unsigned char *targetUNCs;
+ 	mlog_entry_void();
+@@ -724,6 +754,13 @@ static void ocfs2_blocking_ast(void *opaque, int level)
+ 	     lockres->l_name, level, lockres->l_level,
+ 	     ocfs2_lock_type_string(lockres->l_type));
  
- 	*pnum_referrals = 0;
-+	*preferrals = NULL;
++	/*
++	 * We can skip the bast for locks which don't enable caching -
++	 * they'll be dropped at the earliest possible time anyway.
++	 */
++	if (lockres->l_flags & OCFS2_LOCK_NOCACHE)
++		return;
++
+ 	spin_lock_irqsave(&lockres->l_lock, flags);
+ 	needs_downconvert = ocfs2_generic_handle_bast(lockres, level);
+ 	if (needs_downconvert)
+@@ -732,7 +769,7 @@ static void ocfs2_blocking_ast(void *opaque, int level)
  
- 	if (pSesInfo->ipc_tid == 0) {
- 		temp_unc = kmalloc(2 /* for slashes */ +
-@@ -1454,8 +1456,10 @@ get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path,
- 		kfree(temp_unc);
- 	}
- 	if (rc == 0)
--		rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, preferrals,
-+		rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, &targetUNCs,
- 				     pnum_referrals, nls_codepage, remap);
-+	/* BB map targetUNCs to dfs_info3 structures, here or
-+		in CIFSGetDFSRefer BB */
+ 	wake_up(&lockres->l_event);
  
- 	return rc;
+-	ocfs2_kick_vote_thread(osb);
++	ocfs2_wake_downconvert_thread(osb);
  }
-@@ -1964,7 +1968,15 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
  
- 	if (existingCifsSes) {
- 		pSesInfo = existingCifsSes;
--		cFYI(1, ("Existing smb sess found"));
-+		cFYI(1, ("Existing smb sess found (status=%d)",
-+			pSesInfo->status));
-+		down(&pSesInfo->sesSem);
-+		if (pSesInfo->status == CifsNeedReconnect) {
-+			cFYI(1, ("Session needs reconnect"));
-+			rc = cifs_setup_session(xid, pSesInfo,
-+						cifs_sb->local_nls);
-+		}
-+		up(&pSesInfo->sesSem);
- 	} else if (!rc) {
- 		cFYI(1, ("Existing smb sess not found"));
- 		pSesInfo = sesInfoAlloc();
-@@ -3514,7 +3526,7 @@ cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
- 		sesInfoFree(ses);
+ static void ocfs2_locking_ast(void *opaque)
+@@ -935,6 +972,21 @@ static int lockres_remove_mask_waiter(struct ocfs2_lock_res *lockres,
  
- 	FreeXid(xid);
--	return rc;	/* BB check if we should always return zero here */
-+	return rc;
  }
  
- int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
-diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
-index 37dc97a..699ec11 100644
---- a/fs/cifs/dir.c
-+++ b/fs/cifs/dir.c
-@@ -517,12 +517,10 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
- 		d_add(direntry, NULL);
- 	/*	if it was once a directory (but how can we tell?) we could do
- 		shrink_dcache_parent(direntry); */
--	} else {
--		cERROR(1, ("Error 0x%x on cifs_get_inode_info in lookup of %s",
--			   rc, full_path));
--		/* BB special case check for Access Denied - watch security
--		exposure of returning dir info implicitly via different rc
--		if file exists or not but no access BB */
-+	} else if (rc != -EACCES) {
-+		cERROR(1, ("Unexpected lookup error %d", rc));
-+		/* We special case check for Access Denied - since that
-+		is a common return code */
- 	}
- 
- 	kfree(full_path);
-diff --git a/fs/cifs/dns_resolve.c b/fs/cifs/dns_resolve.c
-new file mode 100644
-index 0000000..ef7f438
---- /dev/null
-+++ b/fs/cifs/dns_resolve.c
-@@ -0,0 +1,124 @@
-+/*
-+ *  fs/cifs/dns_resolve.c
-+ *
-+ *   Copyright (c) 2007 Igor Mammedov
-+ *   Author(s): Igor Mammedov (niallain at gmail.com)
-+ *              Steve French (sfrench at us.ibm.com)
-+ *
-+ *   Contains the CIFS DFS upcall routines used for hostname to
-+ *   IP address translation.
-+ *
-+ *   This library is free software; you can redistribute it and/or modify
-+ *   it under the terms of the GNU Lesser General Public License as published
-+ *   by the Free Software Foundation; either version 2.1 of the License, or
-+ *   (at your option) any later version.
-+ *
-+ *   This library is distributed in the hope that it will be useful,
-+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
-+ *   the GNU Lesser General Public License for more details.
-+ *
-+ *   You should have received a copy of the GNU Lesser General Public License
-+ *   along with this library; if not, write to the Free Software
-+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-+ */
-+
-+#include <keys/user-type.h>
-+#include "dns_resolve.h"
-+#include "cifsglob.h"
-+#include "cifsproto.h"
-+#include "cifs_debug.h"
-+
-+static int dns_resolver_instantiate(struct key *key, const void *data,
-+		size_t datalen)
++static int ocfs2_wait_for_mask_interruptible(struct ocfs2_mask_waiter *mw,
++					     struct ocfs2_lock_res *lockres)
 +{
-+	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);
++	int ret;
 +
-+	return rc;
++	ret = wait_for_completion_interruptible(&mw->mw_complete);
++	if (ret)
++		lockres_remove_mask_waiter(lockres, mw);
++	else
++		ret = mw->mw_status;
++	/* Re-arm the completion in case we want to wait on it again */
++	INIT_COMPLETION(mw->mw_complete);
++	return ret;
 +}
 +
-+struct key_type key_type_dns_resolver = {
-+	.name        = "dns_resolver",
-+	.def_datalen = sizeof(struct in_addr),
-+	.describe    = user_describe,
-+	.instantiate = dns_resolver_instantiate,
-+	.match       = user_match,
-+};
-+
-+
-+/* Resolves server name to ip address.
-+ * input:
-+ * 	unc - server UNC
-+ * output:
-+ * 	*ip_addr - pointer to server ip, caller responcible for freeing it.
-+ * return 0 on success
-+ */
-+int
-+dns_resolve_server_name_to_ip(const char *unc, char **ip_addr)
-+{
-+	int rc = -EAGAIN;
-+	struct key *rkey;
-+	char *name;
-+	int len;
-+
-+	if (!ip_addr || !unc)
-+		return -EINVAL;
-+
-+	/* search for server name delimiter */
-+	len = strlen(unc);
-+	if (len < 3) {
-+		cFYI(1, ("%s: unc is too short: %s", __FUNCTION__, unc));
-+		return -EINVAL;
-+	}
-+	len -= 2;
-+	name = memchr(unc+2, '\\', len);
-+	if (!name) {
-+		cFYI(1, ("%s: probably server name is whole unc: %s",
-+					__FUNCTION__, unc));
-+	} else {
-+		len = (name - unc) - 2/* leading // */;
+ static int ocfs2_cluster_lock(struct ocfs2_super *osb,
+ 			      struct ocfs2_lock_res *lockres,
+ 			      int level,
+@@ -1089,7 +1141,7 @@ static void ocfs2_cluster_unlock(struct ocfs2_super *osb,
+ 	mlog_entry_void();
+ 	spin_lock_irqsave(&lockres->l_lock, flags);
+ 	ocfs2_dec_holders(lockres, level);
+-	ocfs2_vote_on_unlock(osb, lockres);
++	ocfs2_downconvert_on_unlock(osb, lockres);
+ 	spin_unlock_irqrestore(&lockres->l_lock, flags);
+ 	mlog_exit_void();
+ }
+@@ -1147,13 +1199,7 @@ int ocfs2_create_new_inode_locks(struct inode *inode)
+ 	 * We don't want to use LKM_LOCAL on a meta data lock as they
+ 	 * don't use a generation in their lock names.
+ 	 */
+-	ret = ocfs2_create_new_lock(osb, &OCFS2_I(inode)->ip_meta_lockres, 1, 0);
+-	if (ret) {
+-		mlog_errno(ret);
+-		goto bail;
+-	}
+-
+-	ret = ocfs2_create_new_lock(osb, &OCFS2_I(inode)->ip_data_lockres, 1, 1);
++	ret = ocfs2_create_new_lock(osb, &OCFS2_I(inode)->ip_inode_lockres, 1, 0);
+ 	if (ret) {
+ 		mlog_errno(ret);
+ 		goto bail;
+@@ -1311,76 +1357,221 @@ out:
+ 	mlog_exit_void();
+ }
+ 
+-int ocfs2_data_lock_full(struct inode *inode,
+-			 int write,
+-			 int arg_flags)
++static int ocfs2_flock_handle_signal(struct ocfs2_lock_res *lockres,
++				     int level)
+ {
+-	int status = 0, level;
+-	struct ocfs2_lock_res *lockres;
+-	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
++	int ret;
++	struct ocfs2_super *osb = ocfs2_get_lockres_osb(lockres);
++	unsigned long flags;
++	struct ocfs2_mask_waiter mw;
+ 
+-	BUG_ON(!inode);
++	ocfs2_init_mask_waiter(&mw);
+ 
+-	mlog_entry_void();
++retry_cancel:
++	spin_lock_irqsave(&lockres->l_lock, flags);
++	if (lockres->l_flags & OCFS2_LOCK_BUSY) {
++		ret = ocfs2_prepare_cancel_convert(osb, lockres);
++		if (ret) {
++			spin_unlock_irqrestore(&lockres->l_lock, flags);
++			ret = ocfs2_cancel_convert(osb, lockres);
++			if (ret < 0) {
++				mlog_errno(ret);
++				goto out;
++			}
++			goto retry_cancel;
++		}
++		lockres_add_mask_waiter(lockres, &mw, OCFS2_LOCK_BUSY, 0);
++		spin_unlock_irqrestore(&lockres->l_lock, flags);
+ 
+-	mlog(0, "inode %llu take %s DATA lock\n",
+-	     (unsigned long long)OCFS2_I(inode)->ip_blkno,
+-	     write ? "EXMODE" : "PRMODE");
++		ocfs2_wait_for_mask(&mw);
++		goto retry_cancel;
 +	}
+ 
+-	/* We'll allow faking a readonly data lock for
+-	 * rodevices. */
+-	if (ocfs2_is_hard_readonly(OCFS2_SB(inode->i_sb))) {
+-		if (write) {
+-			status = -EROFS;
+-			mlog_errno(status);
++	ret = -ERESTARTSYS;
++	/*
++	 * We may still have gotten the lock, in which case there's no
++	 * point to restarting the syscall.
++	 */
++	if (lockres->l_level == level)
++		ret = 0;
 +
-+	name = kmalloc(len+1, GFP_KERNEL);
-+	if (!name) {
-+		rc = -ENOMEM;
-+		return rc;
-+	}
-+	memcpy(name, unc+2, len);
-+	name[len] = 0;
++	mlog(0, "Cancel returning %d. flags: 0x%lx, level: %d, act: %d\n", ret,
++	     lockres->l_flags, lockres->l_level, lockres->l_action);
 +
-+	rkey = request_key(&key_type_dns_resolver, name, "");
-+	if (!IS_ERR(rkey)) {
-+		len = strlen(rkey->payload.data);
-+		*ip_addr = kmalloc(len+1, GFP_KERNEL);
-+		if (*ip_addr) {
-+			memcpy(*ip_addr, rkey->payload.data, len);
-+			(*ip_addr)[len] = '\0';
-+			cFYI(1, ("%s: resolved: %s to %s", __FUNCTION__,
-+					rkey->description,
-+					*ip_addr
-+				));
-+			rc = 0;
-+		} else {
-+			rc = -ENOMEM;
-+		}
-+		key_put(rkey);
-+	} else {
-+		cERROR(1, ("%s: unable to resolve: %s", __FUNCTION__, name));
-+	}
++	spin_unlock_irqrestore(&lockres->l_lock, flags);
 +
-+	kfree(name);
-+	return rc;
++out:
++	return ret;
 +}
 +
-+
-diff --git a/fs/cifs/dns_resolve.h b/fs/cifs/dns_resolve.h
-new file mode 100644
-index 0000000..073fdc3
---- /dev/null
-+++ b/fs/cifs/dns_resolve.h
-@@ -0,0 +1,32 @@
 +/*
-+ *   fs/cifs/dns_resolve.h -- DNS Resolver upcall management for CIFS DFS
-+ *                            Handles host name to IP address resolution
-+ * 
-+ *   Copyright (c) International Business Machines  Corp., 2008
-+ *   Author(s): Steve French (sfrench at us.ibm.com)
++ * ocfs2_file_lock() and ocfs2_file_unlock() map to a single pair of
++ * flock() calls. The locking approach this requires is sufficiently
++ * different from all other cluster lock types that we implement a
++ * seperate path to the "low-level" dlm calls. In particular:
 + *
-+ *   This library is free software; you can redistribute it and/or modify
-+ *   it under the terms of the GNU Lesser General Public License as published
-+ *   by the Free Software Foundation; either version 2.1 of the License, or
-+ *   (at your option) any later version.
++ * - No optimization of lock levels is done - we take at exactly
++ *   what's been requested.
 + *
-+ *   This library is distributed in the hope that it will be useful,
-+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
-+ *   the GNU Lesser General Public License for more details.
++ * - No lock caching is employed. We immediately downconvert to
++ *   no-lock at unlock time. This also means flock locks never go on
++ *   the blocking list).
 + *
-+ *   You should have received a copy of the GNU Lesser General Public License
-+ *   along with this library; if not, write to the Free Software
-+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ * - Since userspace can trivially deadlock itself with flock, we make
++ *   sure to allow cancellation of a misbehaving applications flock()
++ *   request.
++ *
++ * - Access to any flock lockres doesn't require concurrency, so we
++ *   can simplify the code by requiring the caller to guarantee
++ *   serialization of dlmglue flock calls.
 + */
++int ocfs2_file_lock(struct file *file, int ex, int trylock)
++{
++	int ret, level = ex ? LKM_EXMODE : LKM_PRMODE;
++	unsigned int lkm_flags = trylock ? LKM_NOQUEUE : 0;
++	unsigned long flags;
++	struct ocfs2_file_private *fp = file->private_data;
++	struct ocfs2_lock_res *lockres = &fp->fp_flock;
++	struct ocfs2_super *osb = OCFS2_SB(file->f_mapping->host->i_sb);
++	struct ocfs2_mask_waiter mw;
 +
-+#ifndef _DNS_RESOLVE_H
-+#define _DNS_RESOLVE_H
-+
-+#ifdef __KERNEL__
-+#include <linux/key-type.h>
-+extern struct key_type key_type_dns_resolver;
-+extern int dns_resolve_server_name_to_ip(const char *unc, char **ip_addr);
-+#endif /* KERNEL */
-+
-+#endif /* _DNS_RESOLVE_H */
-diff --git a/fs/cifs/file.c b/fs/cifs/file.c
-index dd26e27..5f7c374 100644
---- a/fs/cifs/file.c
-+++ b/fs/cifs/file.c
-@@ -1179,12 +1179,10 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to)
- 		atomic_dec(&open_file->wrtPending);
- 		/* Does mm or vfs already set times? */
- 		inode->i_atime = inode->i_mtime = current_fs_time(inode->i_sb);
--		if ((bytes_written > 0) && (offset)) {
-+		if ((bytes_written > 0) && (offset))
- 			rc = 0;
--		} else if (bytes_written < 0) {
--			if (rc != -EBADF)
--				rc = bytes_written;
--		}
-+		else if (bytes_written < 0)
-+			rc = bytes_written;
- 	} else {
- 		cFYI(1, ("No writeable filehandles for inode"));
- 		rc = -EIO;
-diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
-index e915eb1..d9567ba 100644
---- a/fs/cifs/inode.c
-+++ b/fs/cifs/inode.c
-@@ -54,9 +54,9 @@ int cifs_get_inode_info_unix(struct inode **pinode,
- 					    MAX_TREE_SIZE + 1) +
- 				    strnlen(search_path, MAX_PATHCONF) + 1,
- 				    GFP_KERNEL);
--			if (tmp_path == NULL) {
-+			if (tmp_path == NULL)
- 				return -ENOMEM;
--			}
++	ocfs2_init_mask_waiter(&mw);
 +
- 			/* have to skip first of the double backslash of
- 			   UNC name */
- 			strncpy(tmp_path, pTcon->treeName, MAX_TREE_SIZE);
-@@ -511,7 +511,8 @@ int cifs_get_inode_info(struct inode **pinode,
- 		}
- 
- 		spin_lock(&inode->i_lock);
--		if (is_size_safe_to_change(cifsInfo, le64_to_cpu(pfindData->EndOfFile))) {
-+		if (is_size_safe_to_change(cifsInfo,
-+					   le64_to_cpu(pfindData->EndOfFile))) {
- 			/* can not safely shrink the file size here if the
- 			   client is writing to it due to potential races */
- 			i_size_write(inode, le64_to_cpu(pfindData->EndOfFile));
-@@ -931,7 +932,7 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
- 		(CIFS_UNIX_POSIX_PATH_OPS_CAP &
- 			le64_to_cpu(pTcon->fsUnixInfo.Capability))) {
- 		u32 oplock = 0;
--		FILE_UNIX_BASIC_INFO * pInfo =
-+		FILE_UNIX_BASIC_INFO *pInfo =
- 			kzalloc(sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL);
- 		if (pInfo == NULL) {
- 			rc = -ENOMEM;
-@@ -1607,7 +1608,14 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
- 						CIFS_MOUNT_MAP_SPECIAL_CHR);
- 	else if (attrs->ia_valid & ATTR_MODE) {
- 		rc = 0;
--		if ((mode & S_IWUGO) == 0) /* not writeable */ {
-+#ifdef CONFIG_CIFS_EXPERIMENTAL
-+		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL)
-+			rc = mode_to_acl(direntry->d_inode, full_path, mode);
-+		else if ((mode & S_IWUGO) == 0) {
-+#else
-+		if ((mode & S_IWUGO) == 0) {
-+#endif
-+			/* not writeable */
- 			if ((cifsInode->cifsAttrs & ATTR_READONLY) == 0) {
- 				set_dosattr = TRUE;
- 				time_buf.Attributes =
-@@ -1626,10 +1634,10 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
- 			if (time_buf.Attributes == 0)
- 				time_buf.Attributes |= cpu_to_le32(ATTR_NORMAL);
- 		}
--		/* BB to be implemented -
--		   via Windows security descriptors or streams */
--		/* CIFSSMBWinSetPerms(xid, pTcon, full_path, mode, uid, gid,
--				      cifs_sb->local_nls); */
-+#ifdef CONFIG_CIFS_EXPERIMENTAL
-+		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL)
-+			mode_to_acl(direntry->d_inode, full_path, mode);
-+#endif
- 	}
- 
- 	if (attrs->ia_valid & ATTR_ATIME) {
-diff --git a/fs/cifs/link.c b/fs/cifs/link.c
-index 11f2657..1d6fb01 100644
---- a/fs/cifs/link.c
-+++ b/fs/cifs/link.c
-@@ -1,7 +1,7 @@
- /*
-  *   fs/cifs/link.c
-  *
-- *   Copyright (C) International Business Machines  Corp., 2002,2003
-+ *   Copyright (C) International Business Machines  Corp., 2002,2008
-  *   Author(s): Steve French (sfrench at us.ibm.com)
-  *
-  *   This library is free software; you can redistribute it and/or modify
-@@ -236,8 +236,6 @@ cifs_readlink(struct dentry *direntry, char __user *pBuffer, int buflen)
- 	char *full_path = NULL;
- 	char *tmp_path = NULL;
- 	char *tmpbuffer;
--	unsigned char *referrals = NULL;
--	unsigned int num_referrals = 0;
- 	int len;
- 	__u16 fid;
- 
-@@ -297,8 +295,11 @@ cifs_readlink(struct dentry *direntry, char __user *pBuffer, int buflen)
- 				cFYI(1, ("Error closing junction point "
- 					 "(open for ioctl)"));
- 			}
-+			/* BB unwind this long, nested function, or remove BB */
- 			if (rc == -EIO) {
- 				/* Query if DFS Junction */
-+				unsigned int num_referrals = 0;
-+				struct dfs_info3_param *refs = NULL;
- 				tmp_path =
- 					kmalloc(MAX_TREE_SIZE + MAX_PATHCONF + 1,
- 						GFP_KERNEL);
-@@ -310,7 +311,7 @@ cifs_readlink(struct dentry *direntry, char __user *pBuffer, int buflen)
- 					rc = get_dfs_path(xid, pTcon->ses,
- 						tmp_path,
- 						cifs_sb->local_nls,
--						&num_referrals, &referrals,
-+						&num_referrals, &refs,
- 						cifs_sb->mnt_cifs_flags &
- 						    CIFS_MOUNT_MAP_SPECIAL_CHR);
- 					cFYI(1, ("Get DFS for %s rc = %d ",
-@@ -320,14 +321,13 @@ cifs_readlink(struct dentry *direntry, char __user *pBuffer, int buflen)
- 					else {
- 						cFYI(1, ("num referral: %d",
- 							num_referrals));
--						if (referrals) {
--							cFYI(1,("referral string: %s", referrals));
-+						if (refs && refs->path_name) {
- 							strncpy(tmpbuffer,
--								referrals,
-+								refs->path_name,
- 								len-1);
- 						}
- 					}
--					kfree(referrals);
-+					kfree(refs);
- 					kfree(tmp_path);
- }
- 				/* BB add code like else decode referrals
-diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c
-index d0cb469..d2153ab 100644
---- a/fs/cifs/sess.c
-+++ b/fs/cifs/sess.c
-@@ -528,9 +528,11 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
- 			rc = -EOVERFLOW;
- 			goto ssetup_exit;
++	if ((lockres->l_flags & OCFS2_LOCK_BUSY) ||
++	    (lockres->l_level > LKM_NLMODE)) {
++		mlog(ML_ERROR,
++		     "File lock \"%s\" has busy or locked state: flags: 0x%lx, "
++		     "level: %u\n", lockres->l_name, lockres->l_flags,
++		     lockres->l_level);
++		return -EINVAL;
++	}
++
++	spin_lock_irqsave(&lockres->l_lock, flags);
++	if (!(lockres->l_flags & OCFS2_LOCK_ATTACHED)) {
++		lockres_add_mask_waiter(lockres, &mw, OCFS2_LOCK_BUSY, 0);
++		spin_unlock_irqrestore(&lockres->l_lock, flags);
++
++		/*
++		 * Get the lock at NLMODE to start - that way we
++		 * can cancel the upconvert request if need be.
++		 */
++		ret = ocfs2_lock_create(osb, lockres, LKM_NLMODE, 0);
++		if (ret < 0) {
++			mlog_errno(ret);
++			goto out;
  		}
--		ses->server->mac_signing_key.len = msg->sesskey_len;
--		memcpy(ses->server->mac_signing_key.data.krb5, msg->data,
--			msg->sesskey_len);
-+		if (first_time) {
-+			ses->server->mac_signing_key.len = msg->sesskey_len;
-+			memcpy(ses->server->mac_signing_key.data.krb5,
-+				msg->data, msg->sesskey_len);
+-		goto out;
++
++		ret = ocfs2_wait_for_mask(&mw);
++		if (ret) {
++			mlog_errno(ret);
++			goto out;
 +		}
- 		pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
- 		capabilities |= CAP_EXTENDED_SECURITY;
- 		pSMB->req.Capabilities = cpu_to_le32(capabilities);
-@@ -540,7 +542,7 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
- 
- 		if (ses->capabilities & CAP_UNICODE) {
- 			/* unicode strings must be word aligned */
--			if (iov[0].iov_len % 2) {
-+			if ((iov[0].iov_len + iov[1].iov_len) % 2) {
- 				*bcc_ptr = 0;
- 				bcc_ptr++;
- 			}
-diff --git a/fs/coda/psdev.c b/fs/coda/psdev.c
-index dcc6aea..e3eb355 100644
---- a/fs/coda/psdev.c
-+++ b/fs/coda/psdev.c
-@@ -362,8 +362,8 @@ static int init_coda_psdev(void)
- 		goto out_chrdev;
- 	}		
- 	for (i = 0; i < MAX_CODADEVS; i++)
--		class_device_create(coda_psdev_class, NULL,
--				MKDEV(CODA_PSDEV_MAJOR,i), NULL, "cfs%d", i);
-+		device_create(coda_psdev_class, NULL,
-+			      MKDEV(CODA_PSDEV_MAJOR,i), "cfs%d", i);
- 	coda_sysctl_init();
- 	goto out;
- 
-@@ -405,7 +405,7 @@ static int __init init_coda(void)
- 	return 0;
- out:
- 	for (i = 0; i < MAX_CODADEVS; i++)
--		class_device_destroy(coda_psdev_class, MKDEV(CODA_PSDEV_MAJOR, i));
-+		device_destroy(coda_psdev_class, MKDEV(CODA_PSDEV_MAJOR, i));
- 	class_destroy(coda_psdev_class);
- 	unregister_chrdev(CODA_PSDEV_MAJOR, "coda");
- 	coda_sysctl_clean();
-@@ -424,7 +424,7 @@ static void __exit exit_coda(void)
-                 printk("coda: failed to unregister filesystem\n");
-         }
- 	for (i = 0; i < MAX_CODADEVS; i++)
--		class_device_destroy(coda_psdev_class, MKDEV(CODA_PSDEV_MAJOR, i));
-+		device_destroy(coda_psdev_class, MKDEV(CODA_PSDEV_MAJOR, i));
- 	class_destroy(coda_psdev_class);
- 	unregister_chrdev(CODA_PSDEV_MAJOR, "coda");
- 	coda_sysctl_clean();
-diff --git a/fs/compat.c b/fs/compat.c
-index 15078ce..5216c3f 100644
---- a/fs/compat.c
-+++ b/fs/compat.c
-@@ -1104,10 +1104,6 @@ static ssize_t compat_do_readv_writev(int type, struct file *file,
- 	if (ret < 0)
- 		goto out;
++		spin_lock_irqsave(&lockres->l_lock, flags);
+ 	}
  
--	ret = security_file_permission(file, type == READ ? MAY_READ:MAY_WRITE);
--	if (ret)
+-	if (ocfs2_mount_local(osb))
 -		goto out;
--
- 	fnv = NULL;
- 	if (type == READ) {
- 		fn = file->f_op->read;
-diff --git a/fs/configfs/dir.c b/fs/configfs/dir.c
-index 50ed691..a48dc7d 100644
---- a/fs/configfs/dir.c
-+++ b/fs/configfs/dir.c
-@@ -546,7 +546,7 @@ static int populate_groups(struct config_group *group)
- 		 * That said, taking our i_mutex is closer to mkdir
- 		 * emulation, and shouldn't hurt.
- 		 */
--		mutex_lock(&dentry->d_inode->i_mutex);
-+		mutex_lock_nested(&dentry->d_inode->i_mutex, I_MUTEX_CHILD);
- 
- 		for (i = 0; group->default_groups[i]; i++) {
- 			new_group = group->default_groups[i];
-@@ -1405,7 +1405,8 @@ int configfs_register_subsystem(struct configfs_subsystem *subsys)
- 	sd = configfs_sb->s_root->d_fsdata;
- 	link_group(to_config_group(sd->s_element), group);
++	lockres->l_action = OCFS2_AST_CONVERT;
++	lkm_flags |= LKM_CONVERT;
++	lockres->l_requested = level;
++	lockres_or_flags(lockres, OCFS2_LOCK_BUSY);
  
--	mutex_lock(&configfs_sb->s_root->d_inode->i_mutex);
-+	mutex_lock_nested(&configfs_sb->s_root->d_inode->i_mutex,
-+			I_MUTEX_PARENT);
+-	lockres = &OCFS2_I(inode)->ip_data_lockres;
++	lockres_add_mask_waiter(lockres, &mw, OCFS2_LOCK_BUSY, 0);
++	spin_unlock_irqrestore(&lockres->l_lock, flags);
  
- 	name.name = group->cg_item.ci_name;
- 	name.len = strlen(name.name);
-diff --git a/fs/configfs/file.c b/fs/configfs/file.c
-index a3658f9..397cb50 100644
---- a/fs/configfs/file.c
-+++ b/fs/configfs/file.c
-@@ -320,7 +320,7 @@ int configfs_add_file(struct dentry * dir, const struct configfs_attribute * att
- 	umode_t mode = (attr->ca_mode & S_IALLUGO) | S_IFREG;
- 	int error = 0;
+-	level = write ? LKM_EXMODE : LKM_PRMODE;
++	ret = dlmlock(osb->dlm, level, &lockres->l_lksb, lkm_flags,
++		      lockres->l_name, OCFS2_LOCK_ID_MAX_LEN - 1,
++		      ocfs2_locking_ast, lockres, ocfs2_blocking_ast);
++	if (ret != DLM_NORMAL) {
++		if (trylock && ret == DLM_NOTQUEUED)
++			ret = -EAGAIN;
++		else {
++			ocfs2_log_dlm_error("dlmlock", ret, lockres);
++			ret = -EINVAL;
++		}
  
--	mutex_lock(&dir->d_inode->i_mutex);
-+	mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_NORMAL);
- 	error = configfs_make_dirent(parent_sd, NULL, (void *) attr, mode, type);
- 	mutex_unlock(&dir->d_inode->i_mutex);
+-	status = ocfs2_cluster_lock(OCFS2_SB(inode->i_sb), lockres, level,
+-				    0, arg_flags);
+-	if (status < 0 && status != -EAGAIN)
+-		mlog_errno(status);
++		ocfs2_recover_from_dlm_error(lockres, 1);
++		lockres_remove_mask_waiter(lockres, &mw);
++		goto out;
++	}
++
++	ret = ocfs2_wait_for_mask_interruptible(&mw, lockres);
++	if (ret == -ERESTARTSYS) {
++		/*
++		 * Userspace can cause deadlock itself with
++		 * flock(). Current behavior locally is to allow the
++		 * deadlock, but abort the system call if a signal is
++		 * received. We follow this example, otherwise a
++		 * poorly written program could sit in kernel until
++		 * reboot.
++		 *
++		 * Handling this is a bit more complicated for Ocfs2
++		 * though. We can't exit this function with an
++		 * outstanding lock request, so a cancel convert is
++		 * required. We intentionally overwrite 'ret' - if the
++		 * cancel fails and the lock was granted, it's easier
++		 * to just bubble sucess back up to the user.
++		 */
++		ret = ocfs2_flock_handle_signal(lockres, level);
++	}
  
-diff --git a/fs/configfs/mount.c b/fs/configfs/mount.c
-index 3bf0278..de3b31d 100644
---- a/fs/configfs/mount.c
-+++ b/fs/configfs/mount.c
-@@ -128,7 +128,7 @@ void configfs_release_fs(void)
+ out:
+-	mlog_exit(status);
+-	return status;
++
++	mlog(0, "Lock: \"%s\" ex: %d, trylock: %d, returns: %d\n",
++	     lockres->l_name, ex, trylock, ret);
++	return ret;
  }
  
- 
--static decl_subsys(config, NULL, NULL);
-+static struct kobject *config_kobj;
- 
- static int __init configfs_init(void)
+-/* see ocfs2_meta_lock_with_page() */
+-int ocfs2_data_lock_with_page(struct inode *inode,
+-			      int write,
+-			      struct page *page)
++void ocfs2_file_unlock(struct file *file)
  {
-@@ -140,9 +140,8 @@ static int __init configfs_init(void)
- 	if (!configfs_dir_cachep)
- 		goto out;
+ 	int ret;
++	unsigned long flags;
++	struct ocfs2_file_private *fp = file->private_data;
++	struct ocfs2_lock_res *lockres = &fp->fp_flock;
++	struct ocfs2_super *osb = OCFS2_SB(file->f_mapping->host->i_sb);
++	struct ocfs2_mask_waiter mw;
  
--	kobj_set_kset_s(&config_subsys, kernel_subsys);
--	err = subsystem_register(&config_subsys);
--	if (err) {
-+	config_kobj = kobject_create_and_add("config", kernel_kobj);
-+	if (!config_kobj) {
- 		kmem_cache_destroy(configfs_dir_cachep);
- 		configfs_dir_cachep = NULL;
- 		goto out;
-@@ -151,7 +150,7 @@ static int __init configfs_init(void)
- 	err = register_filesystem(&configfs_fs_type);
- 	if (err) {
- 		printk(KERN_ERR "configfs: Unable to register filesystem!\n");
--		subsystem_unregister(&config_subsys);
-+		kobject_put(config_kobj);
- 		kmem_cache_destroy(configfs_dir_cachep);
- 		configfs_dir_cachep = NULL;
- 		goto out;
-@@ -160,7 +159,7 @@ static int __init configfs_init(void)
- 	err = configfs_inode_init();
- 	if (err) {
- 		unregister_filesystem(&configfs_fs_type);
--		subsystem_unregister(&config_subsys);
-+		kobject_put(config_kobj);
- 		kmem_cache_destroy(configfs_dir_cachep);
- 		configfs_dir_cachep = NULL;
+-	ret = ocfs2_data_lock_full(inode, write, OCFS2_LOCK_NONBLOCK);
+-	if (ret == -EAGAIN) {
+-		unlock_page(page);
+-		if (ocfs2_data_lock(inode, write) == 0)
+-			ocfs2_data_unlock(inode, write);
+-		ret = AOP_TRUNCATED_PAGE;
++	ocfs2_init_mask_waiter(&mw);
++
++	if (!(lockres->l_flags & OCFS2_LOCK_ATTACHED))
++		return;
++
++	if (lockres->l_level == LKM_NLMODE)
++		return;
++
++	mlog(0, "Unlock: \"%s\" flags: 0x%lx, level: %d, act: %d\n",
++	     lockres->l_name, lockres->l_flags, lockres->l_level,
++	     lockres->l_action);
++
++	spin_lock_irqsave(&lockres->l_lock, flags);
++	/*
++	 * Fake a blocking ast for the downconvert code.
++	 */
++	lockres_or_flags(lockres, OCFS2_LOCK_BLOCKED);
++	lockres->l_blocking = LKM_EXMODE;
++
++	ocfs2_prepare_downconvert(lockres, LKM_NLMODE);
++	lockres_add_mask_waiter(lockres, &mw, OCFS2_LOCK_BUSY, 0);
++	spin_unlock_irqrestore(&lockres->l_lock, flags);
++
++	ret = ocfs2_downconvert_lock(osb, lockres, LKM_NLMODE, 0);
++	if (ret) {
++		mlog_errno(ret);
++		return;
  	}
-@@ -171,7 +170,7 @@ out:
- static void __exit configfs_exit(void)
- {
- 	unregister_filesystem(&configfs_fs_type);
--	subsystem_unregister(&config_subsys);
-+	kobject_put(config_kobj);
- 	kmem_cache_destroy(configfs_dir_cachep);
- 	configfs_dir_cachep = NULL;
- 	configfs_inode_exit();
-diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c
-index 6a713b3..d26e282 100644
---- a/fs/debugfs/inode.c
-+++ b/fs/debugfs/inode.c
-@@ -426,20 +426,19 @@ exit:
- }
- EXPORT_SYMBOL_GPL(debugfs_rename);
- 
--static decl_subsys(debug, NULL, NULL);
-+static struct kobject *debug_kobj;
- 
- static int __init debugfs_init(void)
- {
- 	int retval;
- 
--	kobj_set_kset_s(&debug_subsys, kernel_subsys);
--	retval = subsystem_register(&debug_subsys);
--	if (retval)
--		return retval;
-+	debug_kobj = kobject_create_and_add("debug", kernel_kobj);
-+	if (!debug_kobj)
-+		return -EINVAL;
  
- 	retval = register_filesystem(&debug_fs_type);
- 	if (retval)
--		subsystem_unregister(&debug_subsys);
-+		kobject_put(debug_kobj);
- 	return retval;
+-	return ret;
++	ret = ocfs2_wait_for_mask(&mw);
++	if (ret)
++		mlog_errno(ret);
  }
  
-@@ -447,7 +446,7 @@ static void __exit debugfs_exit(void)
+-static void ocfs2_vote_on_unlock(struct ocfs2_super *osb,
+-				 struct ocfs2_lock_res *lockres)
++static void ocfs2_downconvert_on_unlock(struct ocfs2_super *osb,
++					struct ocfs2_lock_res *lockres)
  {
- 	simple_release_fs(&debugfs_mount, &debugfs_mount_count);
- 	unregister_filesystem(&debug_fs_type);
--	subsystem_unregister(&debug_subsys);
-+	kobject_put(debug_kobj);
- }
+ 	int kick = 0;
  
- core_initcall(debugfs_init);
-diff --git a/fs/dlm/lockspace.c b/fs/dlm/lockspace.c
-index 6353a83..5c108c4 100644
---- a/fs/dlm/lockspace.c
-+++ b/fs/dlm/lockspace.c
-@@ -166,26 +166,7 @@ static struct kobj_type dlm_ktype = {
- 	.release       = lockspace_kobj_release,
- };
+ 	mlog_entry_void();
  
--static struct kset dlm_kset = {
--	.ktype  = &dlm_ktype,
--};
+ 	/* If we know that another node is waiting on our lock, kick
+-	 * the vote thread * pre-emptively when we reach a release
++	 * the downconvert thread * pre-emptively when we reach a release
+ 	 * condition. */
+ 	if (lockres->l_flags & OCFS2_LOCK_BLOCKED) {
+ 		switch(lockres->l_blocking) {
+@@ -1398,27 +1589,7 @@ static void ocfs2_vote_on_unlock(struct ocfs2_super *osb,
+ 	}
+ 
+ 	if (kick)
+-		ocfs2_kick_vote_thread(osb);
 -
--static int kobject_setup(struct dlm_ls *ls)
+-	mlog_exit_void();
+-}
+-
+-void ocfs2_data_unlock(struct inode *inode,
+-		       int write)
 -{
--	char lsname[DLM_LOCKSPACE_LEN];
--	int error;
+-	int level = write ? LKM_EXMODE : LKM_PRMODE;
+-	struct ocfs2_lock_res *lockres = &OCFS2_I(inode)->ip_data_lockres;
+-	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
 -
--	memset(lsname, 0, DLM_LOCKSPACE_LEN);
--	snprintf(lsname, DLM_LOCKSPACE_LEN, "%s", ls->ls_name);
+-	mlog_entry_void();
 -
--	error = kobject_set_name(&ls->ls_kobj, "%s", lsname);
--	if (error)
--		return error;
+-	mlog(0, "inode %llu drop %s DATA lock\n",
+-	     (unsigned long long)OCFS2_I(inode)->ip_blkno,
+-	     write ? "EXMODE" : "PRMODE");
 -
--	ls->ls_kobj.kset = &dlm_kset;
--	ls->ls_kobj.ktype = &dlm_ktype;
--	return 0;
--}
-+static struct kset *dlm_kset;
+-	if (!ocfs2_is_hard_readonly(OCFS2_SB(inode->i_sb)) &&
+-	    !ocfs2_mount_local(osb))
+-		ocfs2_cluster_unlock(OCFS2_SB(inode->i_sb), lockres, level);
++		ocfs2_wake_downconvert_thread(osb);
  
- static int do_uevent(struct dlm_ls *ls, int in)
+ 	mlog_exit_void();
+ }
+@@ -1442,11 +1613,11 @@ static u64 ocfs2_pack_timespec(struct timespec *spec)
+ 
+ /* Call this with the lockres locked. I am reasonably sure we don't
+  * need ip_lock in this function as anyone who would be changing those
+- * values is supposed to be blocked in ocfs2_meta_lock right now. */
++ * values is supposed to be blocked in ocfs2_inode_lock right now. */
+ static void __ocfs2_stuff_meta_lvb(struct inode *inode)
  {
-@@ -220,24 +201,22 @@ static int do_uevent(struct dlm_ls *ls, int in)
+ 	struct ocfs2_inode_info *oi = OCFS2_I(inode);
+-	struct ocfs2_lock_res *lockres = &oi->ip_meta_lockres;
++	struct ocfs2_lock_res *lockres = &oi->ip_inode_lockres;
+ 	struct ocfs2_meta_lvb *lvb;
  
- int dlm_lockspace_init(void)
+ 	mlog_entry_void();
+@@ -1496,7 +1667,7 @@ static void ocfs2_unpack_timespec(struct timespec *spec,
+ static void ocfs2_refresh_inode_from_lvb(struct inode *inode)
  {
--	int error;
--
- 	ls_count = 0;
- 	mutex_init(&ls_lock);
- 	INIT_LIST_HEAD(&lslist);
- 	spin_lock_init(&lslist_lock);
+ 	struct ocfs2_inode_info *oi = OCFS2_I(inode);
+-	struct ocfs2_lock_res *lockres = &oi->ip_meta_lockres;
++	struct ocfs2_lock_res *lockres = &oi->ip_inode_lockres;
+ 	struct ocfs2_meta_lvb *lvb;
  
--	kobject_set_name(&dlm_kset.kobj, "dlm");
--	kobj_set_kset_s(&dlm_kset, kernel_subsys);
--	error = kset_register(&dlm_kset);
--	if (error)
--		printk("dlm_lockspace_init: cannot register kset %d\n", error);
--	return error;
-+	dlm_kset = kset_create_and_add("dlm", NULL, kernel_kobj);
-+	if (!dlm_kset) {
-+		printk(KERN_WARNING "%s: can not create kset\n", __FUNCTION__);
-+		return -ENOMEM;
-+	}
-+	return 0;
+ 	mlog_entry_void();
+@@ -1604,12 +1775,12 @@ static inline void ocfs2_complete_lock_res_refresh(struct ocfs2_lock_res *lockre
  }
  
- void dlm_lockspace_exit(void)
+ /* may or may not return a bh if it went to disk. */
+-static int ocfs2_meta_lock_update(struct inode *inode,
++static int ocfs2_inode_lock_update(struct inode *inode,
+ 				  struct buffer_head **bh)
  {
--	kset_unregister(&dlm_kset);
-+	kset_unregister(dlm_kset);
- }
+ 	int status = 0;
+ 	struct ocfs2_inode_info *oi = OCFS2_I(inode);
+-	struct ocfs2_lock_res *lockres = &oi->ip_meta_lockres;
++	struct ocfs2_lock_res *lockres = &oi->ip_inode_lockres;
+ 	struct ocfs2_dinode *fe;
+ 	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
  
- static int dlm_scand(void *data)
-@@ -549,13 +528,12 @@ static int new_lockspace(char *name, int namelen, void **lockspace,
- 		goto out_delist;
- 	}
+@@ -1721,7 +1892,7 @@ static int ocfs2_assign_bh(struct inode *inode,
+  * returns < 0 error if the callback will never be called, otherwise
+  * the result of the lock will be communicated via the callback.
+  */
+-int ocfs2_meta_lock_full(struct inode *inode,
++int ocfs2_inode_lock_full(struct inode *inode,
+ 			 struct buffer_head **ret_bh,
+ 			 int ex,
+ 			 int arg_flags)
+@@ -1756,7 +1927,7 @@ int ocfs2_meta_lock_full(struct inode *inode,
+ 		wait_event(osb->recovery_event,
+ 			   ocfs2_node_map_is_empty(osb, &osb->recovery_map));
  
--	error = kobject_setup(ls);
--	if (error)
--		goto out_stop;
--
--	error = kobject_register(&ls->ls_kobj);
-+	ls->ls_kobj.kset = dlm_kset;
-+	error = kobject_init_and_add(&ls->ls_kobj, &dlm_ktype, NULL,
-+				     "%s", ls->ls_name);
- 	if (error)
- 		goto out_stop;
-+	kobject_uevent(&ls->ls_kobj, KOBJ_ADD);
+-	lockres = &OCFS2_I(inode)->ip_meta_lockres;
++	lockres = &OCFS2_I(inode)->ip_inode_lockres;
+ 	level = ex ? LKM_EXMODE : LKM_PRMODE;
+ 	dlm_flags = 0;
+ 	if (arg_flags & OCFS2_META_LOCK_NOQUEUE)
+@@ -1795,11 +1966,11 @@ local:
+ 	}
  
- 	/* let kobject handle freeing of ls if there's an error */
- 	do_unreg = 1;
-@@ -601,7 +579,7 @@ static int new_lockspace(char *name, int namelen, void **lockspace,
- 	kfree(ls->ls_rsbtbl);
-  out_lsfree:
- 	if (do_unreg)
--		kobject_unregister(&ls->ls_kobj);
-+		kobject_put(&ls->ls_kobj);
- 	else
- 		kfree(ls);
-  out:
-@@ -750,7 +728,7 @@ static int release_lockspace(struct dlm_ls *ls, int force)
- 	dlm_clear_members(ls);
- 	dlm_clear_members_gone(ls);
- 	kfree(ls->ls_node_array);
--	kobject_unregister(&ls->ls_kobj);
-+	kobject_put(&ls->ls_kobj);
- 	/* The ls structure will be freed when the kobject is done with */
+ 	/* This is fun. The caller may want a bh back, or it may
+-	 * not. ocfs2_meta_lock_update definitely wants one in, but
++	 * not. ocfs2_inode_lock_update definitely wants one in, but
+ 	 * may or may not read one, depending on what's in the
+ 	 * LVB. The result of all of this is that we've *only* gone to
+ 	 * disk if we have to, so the complexity is worthwhile. */
+-	status = ocfs2_meta_lock_update(inode, &local_bh);
++	status = ocfs2_inode_lock_update(inode, &local_bh);
+ 	if (status < 0) {
+ 		if (status != -ENOENT)
+ 			mlog_errno(status);
+@@ -1821,7 +1992,7 @@ bail:
+ 			*ret_bh = NULL;
+ 		}
+ 		if (acquired)
+-			ocfs2_meta_unlock(inode, ex);
++			ocfs2_inode_unlock(inode, ex);
+ 	}
  
- 	mutex_lock(&ls_lock);
-diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c
-index e5580bc..0249aa4 100644
---- a/fs/ecryptfs/main.c
-+++ b/fs/ecryptfs/main.c
-@@ -734,127 +734,40 @@ static int ecryptfs_init_kmem_caches(void)
- 	return 0;
+ 	if (local_bh)
+@@ -1832,19 +2003,20 @@ bail:
  }
  
--struct ecryptfs_obj {
--	char *name;
--	struct list_head slot_list;
--	struct kobject kobj;
--};
--
--struct ecryptfs_attribute {
--	struct attribute attr;
--	ssize_t(*show) (struct ecryptfs_obj *, char *);
--	ssize_t(*store) (struct ecryptfs_obj *, const char *, size_t);
--};
-+static struct kobject *ecryptfs_kobj;
- 
--static ssize_t
--ecryptfs_attr_store(struct kobject *kobj,
--		    struct attribute *attr, const char *buf, size_t len)
-+static ssize_t version_show(struct kobject *kobj,
-+			    struct kobj_attribute *attr, char *buff)
+ /*
+- * This is working around a lock inversion between tasks acquiring DLM locks
+- * while holding a page lock and the vote thread which blocks dlm lock acquiry
+- * while acquiring page locks.
++ * This is working around a lock inversion between tasks acquiring DLM
++ * locks while holding a page lock and the downconvert thread which
++ * blocks dlm lock acquiry while acquiring page locks.
+  *
+  * ** These _with_page variantes are only intended to be called from aop
+  * methods that hold page locks and return a very specific *positive* error
+  * code that aop methods pass up to the VFS -- test for errors with != 0. **
+  *
+- * The DLM is called such that it returns -EAGAIN if it would have blocked
+- * waiting for the vote thread.  In that case we unlock our page so the vote
+- * thread can make progress.  Once we've done this we have to return
+- * AOP_TRUNCATED_PAGE so the aop method that called us can bubble that back up
+- * into the VFS who will then immediately retry the aop call.
++ * The DLM is called such that it returns -EAGAIN if it would have
++ * blocked waiting for the downconvert thread.  In that case we unlock
++ * our page so the downconvert thread can make progress.  Once we've
++ * done this we have to return AOP_TRUNCATED_PAGE so the aop method
++ * that called us can bubble that back up into the VFS who will then
++ * immediately retry the aop call.
+  *
+  * We do a blocking lock and immediate unlock before returning, though, so that
+  * the lock has a great chance of being cached on this node by the time the VFS
+@@ -1852,32 +2024,32 @@ bail:
+  * ping locks back and forth, but that's a risk we're willing to take to avoid
+  * the lock inversion simply.
+  */
+-int ocfs2_meta_lock_with_page(struct inode *inode,
++int ocfs2_inode_lock_with_page(struct inode *inode,
+ 			      struct buffer_head **ret_bh,
+ 			      int ex,
+ 			      struct page *page)
  {
--	struct ecryptfs_obj *obj = container_of(kobj, struct ecryptfs_obj,
--						kobj);
--	struct ecryptfs_attribute *attribute =
--		container_of(attr, struct ecryptfs_attribute, attr);
--
--	return (attribute->store ? attribute->store(obj, buf, len) : 0);
-+	return snprintf(buff, PAGE_SIZE, "%d\n", ECRYPTFS_VERSIONING_MASK);
+ 	int ret;
+ 
+-	ret = ocfs2_meta_lock_full(inode, ret_bh, ex, OCFS2_LOCK_NONBLOCK);
++	ret = ocfs2_inode_lock_full(inode, ret_bh, ex, OCFS2_LOCK_NONBLOCK);
+ 	if (ret == -EAGAIN) {
+ 		unlock_page(page);
+-		if (ocfs2_meta_lock(inode, ret_bh, ex) == 0)
+-			ocfs2_meta_unlock(inode, ex);
++		if (ocfs2_inode_lock(inode, ret_bh, ex) == 0)
++			ocfs2_inode_unlock(inode, ex);
+ 		ret = AOP_TRUNCATED_PAGE;
+ 	}
+ 
+ 	return ret;
  }
  
--static ssize_t
--ecryptfs_attr_show(struct kobject *kobj, struct attribute *attr, char *buf)
--{
--	struct ecryptfs_obj *obj = container_of(kobj, struct ecryptfs_obj,
--						kobj);
--	struct ecryptfs_attribute *attribute =
--		container_of(attr, struct ecryptfs_attribute, attr);
--
--	return (attribute->show ? attribute->show(obj, buf) : 0);
--}
-+static struct kobj_attribute version_attr = __ATTR_RO(version);
+-int ocfs2_meta_lock_atime(struct inode *inode,
++int ocfs2_inode_lock_atime(struct inode *inode,
+ 			  struct vfsmount *vfsmnt,
+ 			  int *level)
+ {
+ 	int ret;
  
--static struct sysfs_ops ecryptfs_sysfs_ops = {
--	.show = ecryptfs_attr_show,
--	.store = ecryptfs_attr_store
-+static struct attribute *attributes[] = {
-+	&version_attr.attr,
-+	NULL,
- };
+ 	mlog_entry_void();
+-	ret = ocfs2_meta_lock(inode, NULL, 0);
++	ret = ocfs2_inode_lock(inode, NULL, 0);
+ 	if (ret < 0) {
+ 		mlog_errno(ret);
+ 		return ret;
+@@ -1890,8 +2062,8 @@ int ocfs2_meta_lock_atime(struct inode *inode,
+ 	if (ocfs2_should_update_atime(inode, vfsmnt)) {
+ 		struct buffer_head *bh = NULL;
  
--static struct kobj_type ecryptfs_ktype = {
--	.sysfs_ops = &ecryptfs_sysfs_ops
-+static struct attribute_group attr_group = {
-+	.attrs = attributes,
- };
+-		ocfs2_meta_unlock(inode, 0);
+-		ret = ocfs2_meta_lock(inode, &bh, 1);
++		ocfs2_inode_unlock(inode, 0);
++		ret = ocfs2_inode_lock(inode, &bh, 1);
+ 		if (ret < 0) {
+ 			mlog_errno(ret);
+ 			return ret;
+@@ -1908,11 +2080,11 @@ int ocfs2_meta_lock_atime(struct inode *inode,
+ 	return ret;
+ }
  
--static decl_subsys(ecryptfs, &ecryptfs_ktype, NULL);
--
--static ssize_t version_show(struct ecryptfs_obj *obj, char *buff)
--{
--	return snprintf(buff, PAGE_SIZE, "%d\n", ECRYPTFS_VERSIONING_MASK);
--}
--
--static struct ecryptfs_attribute sysfs_attr_version = __ATTR_RO(version);
--
--static struct ecryptfs_version_str_map_elem {
--	u32 flag;
--	char *str;
--} ecryptfs_version_str_map[] = {
--	{ECRYPTFS_VERSIONING_PASSPHRASE, "passphrase"},
--	{ECRYPTFS_VERSIONING_PUBKEY, "pubkey"},
--	{ECRYPTFS_VERSIONING_PLAINTEXT_PASSTHROUGH, "plaintext passthrough"},
--	{ECRYPTFS_VERSIONING_POLICY, "policy"},
--	{ECRYPTFS_VERSIONING_XATTR, "metadata in extended attribute"},
--	{ECRYPTFS_VERSIONING_MULTKEY, "multiple keys per file"}
--};
--
--static ssize_t version_str_show(struct ecryptfs_obj *obj, char *buff)
--{
--	int i;
--	int remaining = PAGE_SIZE;
--	int total_written = 0;
--
--	buff[0] = '\0';
--	for (i = 0; i < ARRAY_SIZE(ecryptfs_version_str_map); i++) {
--		int entry_size;
--
--		if (!(ECRYPTFS_VERSIONING_MASK
--		      & ecryptfs_version_str_map[i].flag))
--			continue;
--		entry_size = strlen(ecryptfs_version_str_map[i].str);
--		if ((entry_size + 2) > remaining)
--			goto out;
--		memcpy(buff, ecryptfs_version_str_map[i].str, entry_size);
--		buff[entry_size++] = '\n';
--		buff[entry_size] = '\0';
--		buff += entry_size;
--		total_written += entry_size;
--		remaining -= entry_size;
--	}
--out:
--	return total_written;
--}
--
--static struct ecryptfs_attribute sysfs_attr_version_str = __ATTR_RO(version_str);
--
- static int do_sysfs_registration(void)
+-void ocfs2_meta_unlock(struct inode *inode,
++void ocfs2_inode_unlock(struct inode *inode,
+ 		       int ex)
  {
- 	int rc;
+ 	int level = ex ? LKM_EXMODE : LKM_PRMODE;
+-	struct ocfs2_lock_res *lockres = &OCFS2_I(inode)->ip_meta_lockres;
++	struct ocfs2_lock_res *lockres = &OCFS2_I(inode)->ip_inode_lockres;
+ 	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
  
--	rc = subsystem_register(&ecryptfs_subsys);
--	if (rc) {
--		printk(KERN_ERR
--		       "Unable to register ecryptfs sysfs subsystem\n");
--		goto out;
--	}
--	rc = sysfs_create_file(&ecryptfs_subsys.kobj,
--			       &sysfs_attr_version.attr);
--	if (rc) {
--		printk(KERN_ERR
--		       "Unable to create ecryptfs version attribute\n");
--		subsystem_unregister(&ecryptfs_subsys);
-+	ecryptfs_kobj = kobject_create_and_add("ecryptfs", fs_kobj);
-+	if (!ecryptfs_kobj) {
-+		printk(KERN_ERR "Unable to create ecryptfs kset\n");
-+		rc = -ENOMEM;
- 		goto out;
+ 	mlog_entry_void();
+@@ -2320,11 +2492,11 @@ int ocfs2_dlm_init(struct ocfs2_super *osb)
+ 		goto bail;
  	}
--	rc = sysfs_create_file(&ecryptfs_subsys.kobj,
--			       &sysfs_attr_version_str.attr);
-+	rc = sysfs_create_group(ecryptfs_kobj, &attr_group);
- 	if (rc) {
- 		printk(KERN_ERR
--		       "Unable to create ecryptfs version_str attribute\n");
--		sysfs_remove_file(&ecryptfs_subsys.kobj,
--				  &sysfs_attr_version.attr);
--		subsystem_unregister(&ecryptfs_subsys);
--		goto out;
-+		       "Unable to create ecryptfs version attributes\n");
-+		kobject_put(ecryptfs_kobj);
+ 
+-	/* launch vote thread */
+-	osb->vote_task = kthread_run(ocfs2_vote_thread, osb, "ocfs2vote");
+-	if (IS_ERR(osb->vote_task)) {
+-		status = PTR_ERR(osb->vote_task);
+-		osb->vote_task = NULL;
++	/* launch downconvert thread */
++	osb->dc_task = kthread_run(ocfs2_downconvert_thread, osb, "ocfs2dc");
++	if (IS_ERR(osb->dc_task)) {
++		status = PTR_ERR(osb->dc_task);
++		osb->dc_task = NULL;
+ 		mlog_errno(status);
+ 		goto bail;
+ 	}
+@@ -2353,8 +2525,8 @@ local:
+ bail:
+ 	if (status < 0) {
+ 		ocfs2_dlm_shutdown_debug(osb);
+-		if (osb->vote_task)
+-			kthread_stop(osb->vote_task);
++		if (osb->dc_task)
++			kthread_stop(osb->dc_task);
  	}
- out:
- 	return rc;
-@@ -862,11 +775,8 @@ out:
  
- static void do_sysfs_unregistration(void)
- {
--	sysfs_remove_file(&ecryptfs_subsys.kobj,
--			  &sysfs_attr_version.attr);
--	sysfs_remove_file(&ecryptfs_subsys.kobj,
--			  &sysfs_attr_version_str.attr);
--	subsystem_unregister(&ecryptfs_subsys);
-+	sysfs_remove_group(ecryptfs_kobj, &attr_group);
-+	kobject_put(ecryptfs_kobj);
+ 	mlog_exit(status);
+@@ -2369,9 +2541,9 @@ void ocfs2_dlm_shutdown(struct ocfs2_super *osb)
+ 
+ 	ocfs2_drop_osb_locks(osb);
+ 
+-	if (osb->vote_task) {
+-		kthread_stop(osb->vote_task);
+-		osb->vote_task = NULL;
++	if (osb->dc_task) {
++		kthread_stop(osb->dc_task);
++		osb->dc_task = NULL;
+ 	}
+ 
+ 	ocfs2_lock_res_free(&osb->osb_super_lockres);
+@@ -2527,7 +2699,7 @@ out:
+ 
+ /* Mark the lockres as being dropped. It will no longer be
+  * queued if blocking, but we still may have to wait on it
+- * being dequeued from the vote thread before we can consider
++ * being dequeued from the downconvert thread before we can consider
+  * it safe to drop. 
+  *
+  * You can *not* attempt to call cluster_lock on this lockres anymore. */
+@@ -2590,14 +2762,7 @@ int ocfs2_drop_inode_locks(struct inode *inode)
+ 	status = err;
+ 
+ 	err = ocfs2_drop_lock(OCFS2_SB(inode->i_sb),
+-			      &OCFS2_I(inode)->ip_data_lockres);
+-	if (err < 0)
+-		mlog_errno(err);
+-	if (err < 0 && !status)
+-		status = err;
+-
+-	err = ocfs2_drop_lock(OCFS2_SB(inode->i_sb),
+-			      &OCFS2_I(inode)->ip_meta_lockres);
++			      &OCFS2_I(inode)->ip_inode_lockres);
+ 	if (err < 0)
+ 		mlog_errno(err);
+ 	if (err < 0 && !status)
+@@ -2850,6 +3015,9 @@ static int ocfs2_data_convert_worker(struct ocfs2_lock_res *lockres,
+        	inode = ocfs2_lock_res_inode(lockres);
+ 	mapping = inode->i_mapping;
+ 
++	if (S_ISREG(inode->i_mode))
++		goto out;
++
+ 	/*
+ 	 * We need this before the filemap_fdatawrite() so that it can
+ 	 * transfer the dirty bit from the PTE to the
+@@ -2875,6 +3043,7 @@ static int ocfs2_data_convert_worker(struct ocfs2_lock_res *lockres,
+ 		filemap_fdatawait(mapping);
+ 	}
+ 
++out:
+ 	return UNBLOCK_CONTINUE;
  }
  
- static int __init ecryptfs_init(void)
-@@ -894,7 +804,6 @@ static int __init ecryptfs_init(void)
- 		printk(KERN_ERR "Failed to register filesystem\n");
- 		goto out_free_kmem_caches;
+@@ -2903,7 +3072,7 @@ static void ocfs2_set_meta_lvb(struct ocfs2_lock_res *lockres)
+ 
+ /*
+  * Does the final reference drop on our dentry lock. Right now this
+- * happens in the vote thread, but we could choose to simplify the
++ * happens in the downconvert thread, but we could choose to simplify the
+  * dlmglue API and push these off to the ocfs2_wq in the future.
+  */
+ static void ocfs2_dentry_post_unlock(struct ocfs2_super *osb,
+@@ -3042,7 +3211,7 @@ void ocfs2_process_blocked_lock(struct ocfs2_super *osb,
+ 	mlog(0, "lockres %s blocked.\n", lockres->l_name);
+ 
+ 	/* Detect whether a lock has been marked as going away while
+-	 * the vote thread was processing other things. A lock can
++	 * the downconvert thread was processing other things. A lock can
+ 	 * still be marked with OCFS2_LOCK_FREEING after this check,
+ 	 * but short circuiting here will still save us some
+ 	 * performance. */
+@@ -3091,13 +3260,104 @@ static void ocfs2_schedule_blocked_lock(struct ocfs2_super *osb,
+ 
+ 	lockres_or_flags(lockres, OCFS2_LOCK_QUEUED);
+ 
+-	spin_lock(&osb->vote_task_lock);
++	spin_lock(&osb->dc_task_lock);
+ 	if (list_empty(&lockres->l_blocked_list)) {
+ 		list_add_tail(&lockres->l_blocked_list,
+ 			      &osb->blocked_lock_list);
+ 		osb->blocked_lock_count++;
  	}
--	kobj_set_kset_s(&ecryptfs_subsys, fs_subsys);
- 	rc = do_sysfs_registration();
- 	if (rc) {
- 		printk(KERN_ERR "sysfs registration failed\n");
-diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
-index 84f9f7d..e5e80d1 100644
---- a/fs/fuse/inode.c
-+++ b/fs/fuse/inode.c
-@@ -744,9 +744,6 @@ static inline void unregister_fuseblk(void)
+-	spin_unlock(&osb->vote_task_lock);
++	spin_unlock(&osb->dc_task_lock);
++
++	mlog_exit_void();
++}
++
++static void ocfs2_downconvert_thread_do_work(struct ocfs2_super *osb)
++{
++	unsigned long processed;
++	struct ocfs2_lock_res *lockres;
++
++	mlog_entry_void();
++
++	spin_lock(&osb->dc_task_lock);
++	/* grab this early so we know to try again if a state change and
++	 * wake happens part-way through our work  */
++	osb->dc_work_sequence = osb->dc_wake_sequence;
++
++	processed = osb->blocked_lock_count;
++	while (processed) {
++		BUG_ON(list_empty(&osb->blocked_lock_list));
++
++		lockres = list_entry(osb->blocked_lock_list.next,
++				     struct ocfs2_lock_res, l_blocked_list);
++		list_del_init(&lockres->l_blocked_list);
++		osb->blocked_lock_count--;
++		spin_unlock(&osb->dc_task_lock);
++
++		BUG_ON(!processed);
++		processed--;
++
++		ocfs2_process_blocked_lock(osb, lockres);
++
++		spin_lock(&osb->dc_task_lock);
++	}
++	spin_unlock(&osb->dc_task_lock);
+ 
+ 	mlog_exit_void();
+ }
++
++static int ocfs2_downconvert_thread_lists_empty(struct ocfs2_super *osb)
++{
++	int empty = 0;
++
++	spin_lock(&osb->dc_task_lock);
++	if (list_empty(&osb->blocked_lock_list))
++		empty = 1;
++
++	spin_unlock(&osb->dc_task_lock);
++	return empty;
++}
++
++static int ocfs2_downconvert_thread_should_wake(struct ocfs2_super *osb)
++{
++	int should_wake = 0;
++
++	spin_lock(&osb->dc_task_lock);
++	if (osb->dc_work_sequence != osb->dc_wake_sequence)
++		should_wake = 1;
++	spin_unlock(&osb->dc_task_lock);
++
++	return should_wake;
++}
++
++int ocfs2_downconvert_thread(void *arg)
++{
++	int status = 0;
++	struct ocfs2_super *osb = arg;
++
++	/* only quit once we've been asked to stop and there is no more
++	 * work available */
++	while (!(kthread_should_stop() &&
++		ocfs2_downconvert_thread_lists_empty(osb))) {
++
++		wait_event_interruptible(osb->dc_event,
++					 ocfs2_downconvert_thread_should_wake(osb) ||
++					 kthread_should_stop());
++
++		mlog(0, "downconvert_thread: awoken\n");
++
++		ocfs2_downconvert_thread_do_work(osb);
++	}
++
++	osb->dc_task = NULL;
++	return status;
++}
++
++void ocfs2_wake_downconvert_thread(struct ocfs2_super *osb)
++{
++	spin_lock(&osb->dc_task_lock);
++	/* make sure the voting thread gets a swipe at whatever changes
++	 * the caller may have made to the voting state */
++	osb->dc_wake_sequence++;
++	spin_unlock(&osb->dc_task_lock);
++	wake_up(&osb->dc_event);
++}
+diff --git a/fs/ocfs2/dlmglue.h b/fs/ocfs2/dlmglue.h
+index 87a785e..5f17243 100644
+--- a/fs/ocfs2/dlmglue.h
++++ b/fs/ocfs2/dlmglue.h
+@@ -49,12 +49,12 @@ struct ocfs2_meta_lvb {
+ 	__be32       lvb_reserved2;
+ };
+ 
+-/* ocfs2_meta_lock_full() and ocfs2_data_lock_full() 'arg_flags' flags */
++/* ocfs2_inode_lock_full() 'arg_flags' flags */
+ /* don't wait on recovery. */
+ #define OCFS2_META_LOCK_RECOVERY	(0x01)
+ /* Instruct the dlm not to queue ourselves on the other node. */
+ #define OCFS2_META_LOCK_NOQUEUE		(0x02)
+-/* don't block waiting for the vote thread, instead return -EAGAIN */
++/* don't block waiting for the downconvert thread, instead return -EAGAIN */
+ #define OCFS2_LOCK_NONBLOCK		(0x04)
+ 
+ int ocfs2_dlm_init(struct ocfs2_super *osb);
+@@ -66,38 +66,32 @@ void ocfs2_inode_lock_res_init(struct ocfs2_lock_res *res,
+ 			       struct inode *inode);
+ void ocfs2_dentry_lock_res_init(struct ocfs2_dentry_lock *dl,
+ 				u64 parent, struct inode *inode);
++struct ocfs2_file_private;
++void ocfs2_file_lock_res_init(struct ocfs2_lock_res *lockres,
++			      struct ocfs2_file_private *fp);
+ void ocfs2_lock_res_free(struct ocfs2_lock_res *res);
+ int ocfs2_create_new_inode_locks(struct inode *inode);
+ int ocfs2_drop_inode_locks(struct inode *inode);
+-int ocfs2_data_lock_full(struct inode *inode,
+-			 int write,
+-			 int arg_flags);
+-#define ocfs2_data_lock(inode, write) ocfs2_data_lock_full(inode, write, 0)
+-int ocfs2_data_lock_with_page(struct inode *inode,
+-			      int write,
+-			      struct page *page);
+-void ocfs2_data_unlock(struct inode *inode,
+-		       int write);
+ int ocfs2_rw_lock(struct inode *inode, int write);
+ void ocfs2_rw_unlock(struct inode *inode, int write);
+ int ocfs2_open_lock(struct inode *inode);
+ int ocfs2_try_open_lock(struct inode *inode, int write);
+ void ocfs2_open_unlock(struct inode *inode);
+-int ocfs2_meta_lock_atime(struct inode *inode,
++int ocfs2_inode_lock_atime(struct inode *inode,
+ 			  struct vfsmount *vfsmnt,
+ 			  int *level);
+-int ocfs2_meta_lock_full(struct inode *inode,
++int ocfs2_inode_lock_full(struct inode *inode,
+ 			 struct buffer_head **ret_bh,
+ 			 int ex,
+ 			 int arg_flags);
+-int ocfs2_meta_lock_with_page(struct inode *inode,
++int ocfs2_inode_lock_with_page(struct inode *inode,
+ 			      struct buffer_head **ret_bh,
+ 			      int ex,
+ 			      struct page *page);
+ /* 99% of the time we don't want to supply any additional flags --
+  * those are for very specific cases only. */
+-#define ocfs2_meta_lock(i, b, e) ocfs2_meta_lock_full(i, b, e, 0)
+-void ocfs2_meta_unlock(struct inode *inode,
++#define ocfs2_inode_lock(i, b, e) ocfs2_inode_lock_full(i, b, e, 0)
++void ocfs2_inode_unlock(struct inode *inode,
+ 		       int ex);
+ int ocfs2_super_lock(struct ocfs2_super *osb,
+ 		     int ex);
+@@ -107,14 +101,17 @@ int ocfs2_rename_lock(struct ocfs2_super *osb);
+ void ocfs2_rename_unlock(struct ocfs2_super *osb);
+ int ocfs2_dentry_lock(struct dentry *dentry, int ex);
+ void ocfs2_dentry_unlock(struct dentry *dentry, int ex);
++int ocfs2_file_lock(struct file *file, int ex, int trylock);
++void ocfs2_file_unlock(struct file *file);
+ 
+ void ocfs2_mark_lockres_freeing(struct ocfs2_lock_res *lockres);
+ void ocfs2_simple_drop_lockres(struct ocfs2_super *osb,
+ 			       struct ocfs2_lock_res *lockres);
+ 
+-/* for the vote thread */
++/* for the downconvert thread */
+ void ocfs2_process_blocked_lock(struct ocfs2_super *osb,
+ 				struct ocfs2_lock_res *lockres);
++void ocfs2_wake_downconvert_thread(struct ocfs2_super *osb);
+ 
+ struct ocfs2_dlm_debug *ocfs2_new_dlm_debug(void);
+ void ocfs2_put_dlm_debug(struct ocfs2_dlm_debug *dlm_debug);
+diff --git a/fs/ocfs2/endian.h b/fs/ocfs2/endian.h
+index ff25762..1942e09 100644
+--- a/fs/ocfs2/endian.h
++++ b/fs/ocfs2/endian.h
+@@ -37,11 +37,6 @@ static inline void le64_add_cpu(__le64 *var, u64 val)
+ 	*var = cpu_to_le64(le64_to_cpu(*var) + val);
  }
- #endif
  
--static decl_subsys(fuse, NULL, NULL);
--static decl_subsys(connections, NULL, NULL);
+-static inline void le32_and_cpu(__le32 *var, u32 val)
+-{
+-	*var = cpu_to_le32(le32_to_cpu(*var) & val);
+-}
 -
- static void fuse_inode_init_once(struct kmem_cache *cachep, void *foo)
+ static inline void be32_add_cpu(__be32 *var, u32 val)
  {
- 	struct inode * inode = foo;
-@@ -791,32 +788,37 @@ static void fuse_fs_cleanup(void)
- 	kmem_cache_destroy(fuse_inode_cachep);
- }
+ 	*var = cpu_to_be32(be32_to_cpu(*var) + val);
+diff --git a/fs/ocfs2/export.c b/fs/ocfs2/export.c
+index 535bfa9..67527ce 100644
+--- a/fs/ocfs2/export.c
++++ b/fs/ocfs2/export.c
+@@ -58,7 +58,7 @@ static struct dentry *ocfs2_get_dentry(struct super_block *sb,
+ 		return ERR_PTR(-ESTALE);
+ 	}
  
-+static struct kobject *fuse_kobj;
-+static struct kobject *connections_kobj;
-+
- static int fuse_sysfs_init(void)
- {
- 	int err;
+-	inode = ocfs2_iget(OCFS2_SB(sb), handle->ih_blkno, 0);
++	inode = ocfs2_iget(OCFS2_SB(sb), handle->ih_blkno, 0, 0);
  
--	kobj_set_kset_s(&fuse_subsys, fs_subsys);
--	err = subsystem_register(&fuse_subsys);
--	if (err)
-+	fuse_kobj = kobject_create_and_add("fuse", fs_kobj);
-+	if (!fuse_kobj) {
-+		err = -ENOMEM;
- 		goto out_err;
-+	}
+ 	if (IS_ERR(inode))
+ 		return (void *)inode;
+@@ -95,7 +95,7 @@ static struct dentry *ocfs2_get_parent(struct dentry *child)
+ 	mlog(0, "find parent of directory %llu\n",
+ 	     (unsigned long long)OCFS2_I(dir)->ip_blkno);
  
--	kobj_set_kset_s(&connections_subsys, fuse_subsys);
--	err = subsystem_register(&connections_subsys);
--	if (err)
-+	connections_kobj = kobject_create_and_add("connections", fuse_kobj);
-+	if (!connections_kobj) {
-+		err = -ENOMEM;
- 		goto out_fuse_unregister;
-+	}
+-	status = ocfs2_meta_lock(dir, NULL, 0);
++	status = ocfs2_inode_lock(dir, NULL, 0);
+ 	if (status < 0) {
+ 		if (status != -ENOENT)
+ 			mlog_errno(status);
+@@ -109,7 +109,7 @@ static struct dentry *ocfs2_get_parent(struct dentry *child)
+ 		goto bail_unlock;
+ 	}
  
- 	return 0;
+-	inode = ocfs2_iget(OCFS2_SB(dir->i_sb), blkno, 0);
++	inode = ocfs2_iget(OCFS2_SB(dir->i_sb), blkno, 0, 0);
+ 	if (IS_ERR(inode)) {
+ 		mlog(ML_ERROR, "Unable to create inode %llu\n",
+ 		     (unsigned long long)blkno);
+@@ -126,7 +126,7 @@ static struct dentry *ocfs2_get_parent(struct dentry *child)
+ 	parent->d_op = &ocfs2_dentry_ops;
  
-  out_fuse_unregister:
--	subsystem_unregister(&fuse_subsys);
-+	kobject_put(fuse_kobj);
-  out_err:
- 	return err;
- }
+ bail_unlock:
+-	ocfs2_meta_unlock(dir, 0);
++	ocfs2_inode_unlock(dir, 0);
  
- static void fuse_sysfs_cleanup(void)
- {
--	subsystem_unregister(&connections_subsys);
--	subsystem_unregister(&fuse_subsys);
-+	kobject_put(connections_kobj);
-+	kobject_put(fuse_kobj);
+ bail:
+ 	mlog_exit_ptr(parent);
+diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c
+index b75b2e1..ed5d523 100644
+--- a/fs/ocfs2/file.c
++++ b/fs/ocfs2/file.c
+@@ -51,6 +51,7 @@
+ #include "inode.h"
+ #include "ioctl.h"
+ #include "journal.h"
++#include "locks.h"
+ #include "mmap.h"
+ #include "suballoc.h"
+ #include "super.h"
+@@ -63,6 +64,35 @@ static int ocfs2_sync_inode(struct inode *inode)
+ 	return sync_mapping_buffers(inode->i_mapping);
  }
  
- static int __init fuse_init(void)
-diff --git a/fs/gfs2/Makefile b/fs/gfs2/Makefile
-index 04ad0ca..8fff110 100644
---- a/fs/gfs2/Makefile
-+++ b/fs/gfs2/Makefile
-@@ -2,7 +2,7 @@ obj-$(CONFIG_GFS2_FS) += gfs2.o
- gfs2-y := acl.o bmap.o daemon.o dir.o eaops.o eattr.o glock.o \
- 	glops.o inode.o lm.o log.o lops.o locking.o main.o meta_io.o \
- 	mount.o ops_address.o ops_dentry.o ops_export.o ops_file.o \
--	ops_fstype.o ops_inode.o ops_super.o ops_vm.o quota.o \
-+	ops_fstype.o ops_inode.o ops_super.o quota.o \
- 	recovery.o rgrp.o super.o sys.o trans.o util.o
- 
- obj-$(CONFIG_GFS2_FS_LOCKING_NOLOCK) += locking/nolock/
-diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c
-index 93fa427..e4effc4 100644
---- a/fs/gfs2/bmap.c
-+++ b/fs/gfs2/bmap.c
-@@ -59,7 +59,6 @@ struct strip_mine {
- static int gfs2_unstuffer_page(struct gfs2_inode *ip, struct buffer_head *dibh,
- 			       u64 block, struct page *page)
- {
--	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
- 	struct inode *inode = &ip->i_inode;
- 	struct buffer_head *bh;
- 	int release = 0;
-@@ -95,7 +94,7 @@ static int gfs2_unstuffer_page(struct gfs2_inode *ip, struct buffer_head *dibh,
- 	set_buffer_uptodate(bh);
- 	if (!gfs2_is_jdata(ip))
- 		mark_buffer_dirty(bh);
--	if (sdp->sd_args.ar_data == GFS2_DATA_ORDERED || gfs2_is_jdata(ip))
-+	if (!gfs2_is_writeback(ip))
- 		gfs2_trans_add_bh(ip->i_gl, bh, 0);
- 
- 	if (release) {
-@@ -453,8 +452,8 @@ static inline void bmap_unlock(struct inode *inode, int create)
-  * Returns: errno
-  */
- 
--int gfs2_block_map(struct inode *inode, u64 lblock, int create,
--		   struct buffer_head *bh_map)
-+int gfs2_block_map(struct inode *inode, sector_t lblock,
-+		   struct buffer_head *bh_map, int create)
++static int ocfs2_init_file_private(struct inode *inode, struct file *file)
++{
++	struct ocfs2_file_private *fp;
++
++	fp = kzalloc(sizeof(struct ocfs2_file_private), GFP_KERNEL);
++	if (!fp)
++		return -ENOMEM;
++
++	fp->fp_file = file;
++	mutex_init(&fp->fp_mutex);
++	ocfs2_file_lock_res_init(&fp->fp_flock, fp);
++	file->private_data = fp;
++
++	return 0;
++}
++
++static void ocfs2_free_file_private(struct inode *inode, struct file *file)
++{
++	struct ocfs2_file_private *fp = file->private_data;
++	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
++
++	if (fp) {
++		ocfs2_simple_drop_lockres(osb, &fp->fp_flock);
++		ocfs2_lock_res_free(&fp->fp_flock);
++		kfree(fp);
++		file->private_data = NULL;
++	}
++}
++
+ static int ocfs2_file_open(struct inode *inode, struct file *file)
  {
- 	struct gfs2_inode *ip = GFS2_I(inode);
- 	struct gfs2_sbd *sdp = GFS2_SB(inode);
-@@ -470,6 +469,7 @@ int gfs2_block_map(struct inode *inode, u64 lblock, int create,
- 	unsigned int maxlen = bh_map->b_size >> inode->i_blkbits;
- 	struct metapath mp;
- 	u64 size;
-+	struct buffer_head *dibh = NULL;
+ 	int status;
+@@ -89,7 +119,18 @@ static int ocfs2_file_open(struct inode *inode, struct file *file)
  
- 	BUG_ON(maxlen == 0);
+ 	oi->ip_open_count++;
+ 	spin_unlock(&oi->ip_lock);
+-	status = 0;
++
++	status = ocfs2_init_file_private(inode, file);
++	if (status) {
++		/*
++		 * We want to set open count back if we're failing the
++		 * open.
++		 */
++		spin_lock(&oi->ip_lock);
++		oi->ip_open_count--;
++		spin_unlock(&oi->ip_lock);
++	}
++
+ leave:
+ 	mlog_exit(status);
+ 	return status;
+@@ -108,11 +149,24 @@ static int ocfs2_file_release(struct inode *inode, struct file *file)
+ 		oi->ip_flags &= ~OCFS2_INODE_OPEN_DIRECT;
+ 	spin_unlock(&oi->ip_lock);
  
-@@ -500,6 +500,8 @@ int gfs2_block_map(struct inode *inode, u64 lblock, int create,
- 	error = gfs2_meta_inode_buffer(ip, &bh);
- 	if (error)
- 		goto out_fail;
-+	dibh = bh;
-+	get_bh(dibh);
++	ocfs2_free_file_private(inode, file);
++
+ 	mlog_exit(0);
  
- 	for (x = 0; x < end_of_metadata; x++) {
- 		lookup_block(ip, bh, x, &mp, create, &new, &dblock);
-@@ -518,13 +520,8 @@ int gfs2_block_map(struct inode *inode, u64 lblock, int create,
- 		if (boundary)
- 			set_buffer_boundary(bh_map);
- 		if (new) {
--			struct buffer_head *dibh;
--			error = gfs2_meta_inode_buffer(ip, &dibh);
--			if (!error) {
--				gfs2_trans_add_bh(ip->i_gl, dibh, 1);
--				gfs2_dinode_out(ip, dibh->b_data);
--				brelse(dibh);
--			}
-+			gfs2_trans_add_bh(ip->i_gl, dibh, 1);
-+			gfs2_dinode_out(ip, dibh->b_data);
- 			set_buffer_new(bh_map);
- 			goto out_brelse;
- 		}
-@@ -545,6 +542,8 @@ out_brelse:
- out_ok:
- 	error = 0;
- out_fail:
-+	if (dibh)
-+		brelse(dibh);
- 	bmap_unlock(inode, create);
- 	return error;
+ 	return 0;
  }
-@@ -560,7 +559,7 @@ int gfs2_extent_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, unsi
- 	BUG_ON(!new);
  
- 	bh.b_size = 1 << (inode->i_blkbits + 5);
--	ret = gfs2_block_map(inode, lblock, create, &bh);
-+	ret = gfs2_block_map(inode, lblock, &bh, create);
- 	*extlen = bh.b_size >> inode->i_blkbits;
- 	*dblock = bh.b_blocknr;
- 	if (buffer_new(&bh))
-@@ -684,7 +683,7 @@ static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh,
- 	if (metadata)
- 		revokes = (height) ? sdp->sd_inptrs : sdp->sd_diptrs;
++static int ocfs2_dir_open(struct inode *inode, struct file *file)
++{
++	return ocfs2_init_file_private(inode, file);
++}
++
++static int ocfs2_dir_release(struct inode *inode, struct file *file)
++{
++	ocfs2_free_file_private(inode, file);
++	return 0;
++}
++
+ static int ocfs2_sync_file(struct file *file,
+ 			   struct dentry *dentry,
+ 			   int datasync)
+@@ -382,18 +436,13 @@ static int ocfs2_truncate_file(struct inode *inode,
  
--	error = gfs2_rindex_hold(sdp, &ip->i_alloc.al_ri_gh);
-+	error = gfs2_rindex_hold(sdp, &ip->i_alloc->al_ri_gh);
- 	if (error)
- 		return error;
+ 	down_write(&OCFS2_I(inode)->ip_alloc_sem);
  
-@@ -786,7 +785,7 @@ out_rg_gunlock:
- out_rlist:
- 	gfs2_rlist_free(&rlist);
- out:
--	gfs2_glock_dq_uninit(&ip->i_alloc.al_ri_gh);
-+	gfs2_glock_dq_uninit(&ip->i_alloc->al_ri_gh);
- 	return error;
- }
+-	/* This forces other nodes to sync and drop their pages. Do
+-	 * this even if we have a truncate without allocation change -
+-	 * ocfs2 cluster sizes can be much greater than page size, so
+-	 * we have to truncate them anyway.  */
+-	status = ocfs2_data_lock(inode, 1);
+-	if (status < 0) {
+-		up_write(&OCFS2_I(inode)->ip_alloc_sem);
+-
+-		mlog_errno(status);
+-		goto bail;
+-	}
+-
++	/*
++	 * The inode lock forced other nodes to sync and drop their
++	 * pages, which (correctly) happens even if we have a truncate
++	 * without allocation change - ocfs2 cluster sizes can be much
++	 * greater than page size, so we have to truncate them
++	 * anyway.
++	 */
+ 	unmap_mapping_range(inode->i_mapping, new_i_size + PAGE_SIZE - 1, 0, 1);
+ 	truncate_inode_pages(inode->i_mapping, new_i_size);
  
-@@ -879,7 +878,6 @@ static int gfs2_block_truncate_page(struct address_space *mapping)
- {
- 	struct inode *inode = mapping->host;
- 	struct gfs2_inode *ip = GFS2_I(inode);
--	struct gfs2_sbd *sdp = GFS2_SB(inode);
- 	loff_t from = inode->i_size;
- 	unsigned long index = from >> PAGE_CACHE_SHIFT;
- 	unsigned offset = from & (PAGE_CACHE_SIZE-1);
-@@ -911,7 +909,7 @@ static int gfs2_block_truncate_page(struct address_space *mapping)
- 	err = 0;
+@@ -403,7 +452,7 @@ static int ocfs2_truncate_file(struct inode *inode,
+ 		if (status)
+ 			mlog_errno(status);
  
- 	if (!buffer_mapped(bh)) {
--		gfs2_get_block(inode, iblock, bh, 0);
-+		gfs2_block_map(inode, iblock, bh, 0);
- 		/* unmapped? It's a hole - nothing to do */
- 		if (!buffer_mapped(bh))
- 			goto unlock;
-@@ -931,7 +929,7 @@ static int gfs2_block_truncate_page(struct address_space *mapping)
- 		err = 0;
+-		goto bail_unlock_data;
++		goto bail_unlock_sem;
  	}
  
--	if (sdp->sd_args.ar_data == GFS2_DATA_ORDERED || gfs2_is_jdata(ip))
-+	if (!gfs2_is_writeback(ip))
- 		gfs2_trans_add_bh(ip->i_gl, bh, 0);
+ 	/* alright, we're going to need to do a full blown alloc size
+@@ -413,25 +462,23 @@ static int ocfs2_truncate_file(struct inode *inode,
+ 	status = ocfs2_orphan_for_truncate(osb, inode, di_bh, new_i_size);
+ 	if (status < 0) {
+ 		mlog_errno(status);
+-		goto bail_unlock_data;
++		goto bail_unlock_sem;
+ 	}
  
- 	zero_user_page(page, offset, length, KM_USER0);
-@@ -1224,8 +1222,13 @@ int gfs2_write_alloc_required(struct gfs2_inode *ip, u64 offset,
- 		do_div(lblock_stop, bsize);
- 	} else {
- 		unsigned int shift = sdp->sd_sb.sb_bsize_shift;
-+		u64 end_of_file = (ip->i_di.di_size + sdp->sd_sb.sb_bsize - 1) >> shift;
- 		lblock = offset >> shift;
- 		lblock_stop = (offset + len + sdp->sd_sb.sb_bsize - 1) >> shift;
-+		if (lblock_stop > end_of_file) {
-+			*alloc_required = 1;
-+			return 0;
-+		}
+ 	status = ocfs2_prepare_truncate(osb, inode, di_bh, &tc);
+ 	if (status < 0) {
+ 		mlog_errno(status);
+-		goto bail_unlock_data;
++		goto bail_unlock_sem;
  	}
  
- 	for (; lblock < lblock_stop; lblock += extlen) {
-diff --git a/fs/gfs2/bmap.h b/fs/gfs2/bmap.h
-index ac2fd04..4e6cde2 100644
---- a/fs/gfs2/bmap.h
-+++ b/fs/gfs2/bmap.h
-@@ -15,7 +15,7 @@ struct gfs2_inode;
- struct page;
+ 	status = ocfs2_commit_truncate(osb, inode, di_bh, tc);
+ 	if (status < 0) {
+ 		mlog_errno(status);
+-		goto bail_unlock_data;
++		goto bail_unlock_sem;
+ 	}
  
- int gfs2_unstuff_dinode(struct gfs2_inode *ip, struct page *page);
--int gfs2_block_map(struct inode *inode, u64 lblock, int create, struct buffer_head *bh);
-+int gfs2_block_map(struct inode *inode, sector_t lblock, struct buffer_head *bh, int create);
- int gfs2_extent_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, unsigned *extlen);
+ 	/* TODO: orphan dir cleanup here. */
+-bail_unlock_data:
+-	ocfs2_data_unlock(inode, 1);
+-
++bail_unlock_sem:
+ 	up_write(&OCFS2_I(inode)->ip_alloc_sem);
  
- int gfs2_truncatei(struct gfs2_inode *ip, u64 size);
-diff --git a/fs/gfs2/daemon.c b/fs/gfs2/daemon.c
-index 3731ab0..e519919 100644
---- a/fs/gfs2/daemon.c
-+++ b/fs/gfs2/daemon.c
-@@ -83,56 +83,6 @@ int gfs2_recoverd(void *data)
- }
+ bail:
+@@ -579,7 +626,7 @@ int ocfs2_lock_allocators(struct inode *inode, struct ocfs2_dinode *di,
  
- /**
-- * gfs2_logd - Update log tail as Active Items get flushed to in-place blocks
-- * @sdp: Pointer to GFS2 superblock
-- *
-- * Also, periodically check to make sure that we're using the most recent
-- * journal index.
-- */
--
--int gfs2_logd(void *data)
--{
--	struct gfs2_sbd *sdp = data;
--	struct gfs2_holder ji_gh;
--	unsigned long t;
--	int need_flush;
--
--	while (!kthread_should_stop()) {
--		/* Advance the log tail */
--
--		t = sdp->sd_log_flush_time +
--		    gfs2_tune_get(sdp, gt_log_flush_secs) * HZ;
--
--		gfs2_ail1_empty(sdp, DIO_ALL);
--		gfs2_log_lock(sdp);
--		need_flush = sdp->sd_log_num_buf > gfs2_tune_get(sdp, gt_incore_log_blocks);
--		gfs2_log_unlock(sdp);
--		if (need_flush || time_after_eq(jiffies, t)) {
--			gfs2_log_flush(sdp, NULL);
--			sdp->sd_log_flush_time = jiffies;
--		}
--
--		/* Check for latest journal index */
--
--		t = sdp->sd_jindex_refresh_time +
--		    gfs2_tune_get(sdp, gt_jindex_refresh_secs) * HZ;
--
--		if (time_after_eq(jiffies, t)) {
--			if (!gfs2_jindex_hold(sdp, &ji_gh))
--				gfs2_glock_dq_uninit(&ji_gh);
--			sdp->sd_jindex_refresh_time = jiffies;
--		}
--
--		t = gfs2_tune_get(sdp, gt_logd_secs) * HZ;
--		if (freezing(current))
--			refrigerator();
--		schedule_timeout_interruptible(t);
+ 	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, i_size_read(inode),
++	     (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);
+@@ -760,7 +807,7 @@ restarted_transaction:
+ 	     le32_to_cpu(fe->i_clusters),
+ 	     (unsigned long long)le64_to_cpu(fe->i_size));
+ 	mlog(0, "inode: ip_clusters=%u, i_size=%lld\n",
+-	     OCFS2_I(inode)->ip_clusters, i_size_read(inode));
++	     OCFS2_I(inode)->ip_clusters, (long long)i_size_read(inode));
+ 
+ leave:
+ 	if (handle) {
+@@ -917,7 +964,7 @@ static int ocfs2_extend_file(struct inode *inode,
+ 			     struct buffer_head *di_bh,
+ 			     u64 new_i_size)
+ {
+-	int ret = 0, data_locked = 0;
++	int ret = 0;
+ 	struct ocfs2_inode_info *oi = OCFS2_I(inode);
+ 
+ 	BUG_ON(!di_bh);
+@@ -943,20 +990,6 @@ static int ocfs2_extend_file(struct inode *inode,
+ 	    && ocfs2_sparse_alloc(OCFS2_SB(inode->i_sb)))
+ 		goto out_update_size;
+ 
+-	/* 
+-	 * protect the pages that ocfs2_zero_extend is going to be
+-	 * pulling into the page cache.. we do this before the
+-	 * metadata extend so that we don't get into the situation
+-	 * where we've extended the metadata but can't get the data
+-	 * lock to zero.
+-	 */
+-	ret = ocfs2_data_lock(inode, 1);
+-	if (ret < 0) {
+-		mlog_errno(ret);
+-		goto out;
 -	}
+-	data_locked = 1;
 -
--	return 0;
--}
--
--/**
-  * gfs2_quotad - Write cached quota changes into the quota file
-  * @sdp: Pointer to GFS2 superblock
-  *
-diff --git a/fs/gfs2/daemon.h b/fs/gfs2/daemon.h
-index 0de9b35..4be084f 100644
---- a/fs/gfs2/daemon.h
-+++ b/fs/gfs2/daemon.h
-@@ -12,7 +12,6 @@
+ 	/*
+ 	 * The alloc sem blocks people in read/write from reading our
+ 	 * allocation until we're done changing it. We depend on
+@@ -980,7 +1013,7 @@ static int ocfs2_extend_file(struct inode *inode,
+ 			up_write(&oi->ip_alloc_sem);
  
- int gfs2_glockd(void *data);
- int gfs2_recoverd(void *data);
--int gfs2_logd(void *data);
- int gfs2_quotad(void *data);
+ 			mlog_errno(ret);
+-			goto out_unlock;
++			goto out;
+ 		}
+ 	}
  
- #endif /* __DAEMON_DOT_H__ */
-diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c
-index 9949bb7..57e2ed9 100644
---- a/fs/gfs2/dir.c
-+++ b/fs/gfs2/dir.c
-@@ -1876,7 +1876,7 @@ static int leaf_dealloc(struct gfs2_inode *dip, u32 index, u32 len,
- 	if (error)
- 		goto out;
+@@ -991,7 +1024,7 @@ static int ocfs2_extend_file(struct inode *inode,
  
--	error = gfs2_rindex_hold(sdp, &dip->i_alloc.al_ri_gh);
-+	error = gfs2_rindex_hold(sdp, &dip->i_alloc->al_ri_gh);
- 	if (error)
- 		goto out_qs;
+ 	if (ret < 0) {
+ 		mlog_errno(ret);
+-		goto out_unlock;
++		goto out;
+ 	}
  
-@@ -1949,7 +1949,7 @@ out_rg_gunlock:
- 	gfs2_glock_dq_m(rlist.rl_rgrps, rlist.rl_ghs);
- out_rlist:
- 	gfs2_rlist_free(&rlist);
--	gfs2_glock_dq_uninit(&dip->i_alloc.al_ri_gh);
-+	gfs2_glock_dq_uninit(&dip->i_alloc->al_ri_gh);
- out_qs:
- 	gfs2_quota_unhold(dip);
+ out_update_size:
+@@ -999,10 +1032,6 @@ out_update_size:
+ 	if (ret < 0)
+ 		mlog_errno(ret);
+ 
+-out_unlock:
+-	if (data_locked)
+-		ocfs2_data_unlock(inode, 1);
+-
  out:
-diff --git a/fs/gfs2/eaops.c b/fs/gfs2/eaops.c
-index aa8dbf3..f114ba2 100644
---- a/fs/gfs2/eaops.c
-+++ b/fs/gfs2/eaops.c
-@@ -56,46 +56,6 @@ unsigned int gfs2_ea_name2type(const char *name, const char **truncated_name)
- 	return type;
+ 	return ret;
  }
+@@ -1050,7 +1079,7 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr)
+ 		}
+ 	}
  
--static int user_eo_get(struct gfs2_inode *ip, struct gfs2_ea_request *er)
--{
--	struct inode *inode = &ip->i_inode;
--	int error = permission(inode, MAY_READ, NULL);
--	if (error)
--		return error;
--
--	return gfs2_ea_get_i(ip, er);
--}
--
--static int user_eo_set(struct gfs2_inode *ip, struct gfs2_ea_request *er)
--{
--	struct inode *inode = &ip->i_inode;
--
--	if (S_ISREG(inode->i_mode) ||
--	    (S_ISDIR(inode->i_mode) && !(inode->i_mode & S_ISVTX))) {
--		int error = permission(inode, MAY_WRITE, NULL);
--		if (error)
--			return error;
--	} else
--		return -EPERM;
--
--	return gfs2_ea_set_i(ip, er);
--}
--
--static int user_eo_remove(struct gfs2_inode *ip, struct gfs2_ea_request *er)
--{
--	struct inode *inode = &ip->i_inode;
--
--	if (S_ISREG(inode->i_mode) ||
--	    (S_ISDIR(inode->i_mode) && !(inode->i_mode & S_ISVTX))) {
--		int error = permission(inode, MAY_WRITE, NULL);
--		if (error)
--			return error;
--	} else
--		return -EPERM;
--
--	return gfs2_ea_remove_i(ip, er);
--}
--
- static int system_eo_get(struct gfs2_inode *ip, struct gfs2_ea_request *er)
- {
- 	if (!GFS2_ACL_IS_ACCESS(er->er_name, er->er_name_len) &&
-@@ -108,8 +68,6 @@ static int system_eo_get(struct gfs2_inode *ip, struct gfs2_ea_request *er)
- 	     GFS2_ACL_IS_DEFAULT(er->er_name, er->er_name_len)))
- 		return -EOPNOTSUPP;
+-	status = ocfs2_meta_lock(inode, &bh, 1);
++	status = ocfs2_inode_lock(inode, &bh, 1);
+ 	if (status < 0) {
+ 		if (status != -ENOENT)
+ 			mlog_errno(status);
+@@ -1102,7 +1131,7 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr)
+ bail_commit:
+ 	ocfs2_commit_trans(osb, handle);
+ bail_unlock:
+-	ocfs2_meta_unlock(inode, 1);
++	ocfs2_inode_unlock(inode, 1);
+ bail_unlock_rw:
+ 	if (size_change)
+ 		ocfs2_rw_unlock(inode, 1);
+@@ -1149,7 +1178,7 @@ int ocfs2_permission(struct inode *inode, int mask, struct nameidata *nd)
  
--
--
- 	return gfs2_ea_get_i(ip, er);
- }
+ 	mlog_entry_void();
  
-@@ -170,40 +128,10 @@ static int system_eo_remove(struct gfs2_inode *ip, struct gfs2_ea_request *er)
- 	return gfs2_ea_remove_i(ip, er);
- }
+-	ret = ocfs2_meta_lock(inode, NULL, 0);
++	ret = ocfs2_inode_lock(inode, NULL, 0);
+ 	if (ret) {
+ 		if (ret != -ENOENT)
+ 			mlog_errno(ret);
+@@ -1158,7 +1187,7 @@ int ocfs2_permission(struct inode *inode, int mask, struct nameidata *nd)
  
--static int security_eo_get(struct gfs2_inode *ip, struct gfs2_ea_request *er)
--{
--	struct inode *inode = &ip->i_inode;
--	int error = permission(inode, MAY_READ, NULL);
--	if (error)
--		return error;
--
--	return gfs2_ea_get_i(ip, er);
--}
--
--static int security_eo_set(struct gfs2_inode *ip, struct gfs2_ea_request *er)
--{
--	struct inode *inode = &ip->i_inode;
--	int error = permission(inode, MAY_WRITE, NULL);
--	if (error)
--		return error;
--
--	return gfs2_ea_set_i(ip, er);
--}
--
--static int security_eo_remove(struct gfs2_inode *ip, struct gfs2_ea_request *er)
--{
--	struct inode *inode = &ip->i_inode;
--	int error = permission(inode, MAY_WRITE, NULL);
--	if (error)
--		return error;
--
--	return gfs2_ea_remove_i(ip, er);
--}
--
- static const struct gfs2_eattr_operations gfs2_user_eaops = {
--	.eo_get = user_eo_get,
--	.eo_set = user_eo_set,
--	.eo_remove = user_eo_remove,
-+	.eo_get = gfs2_ea_get_i,
-+	.eo_set = gfs2_ea_set_i,
-+	.eo_remove = gfs2_ea_remove_i,
- 	.eo_name = "user",
- };
+ 	ret = generic_permission(inode, mask, NULL);
  
-@@ -215,9 +143,9 @@ const struct gfs2_eattr_operations gfs2_system_eaops = {
- };
+-	ocfs2_meta_unlock(inode, 0);
++	ocfs2_inode_unlock(inode, 0);
+ out:
+ 	mlog_exit(ret);
+ 	return ret;
+@@ -1630,7 +1659,7 @@ static int __ocfs2_change_file_space(struct file *file, struct inode *inode,
+ 		goto out;
+ 	}
  
- static const struct gfs2_eattr_operations gfs2_security_eaops = {
--	.eo_get = security_eo_get,
--	.eo_set = security_eo_set,
--	.eo_remove = security_eo_remove,
-+	.eo_get = gfs2_ea_get_i,
-+	.eo_set = gfs2_ea_set_i,
-+	.eo_remove = gfs2_ea_remove_i,
- 	.eo_name = "security",
- };
+-	ret = ocfs2_meta_lock(inode, &di_bh, 1);
++	ret = ocfs2_inode_lock(inode, &di_bh, 1);
+ 	if (ret) {
+ 		mlog_errno(ret);
+ 		goto out_rw_unlock;
+@@ -1638,7 +1667,7 @@ static int __ocfs2_change_file_space(struct file *file, struct inode *inode,
  
-diff --git a/fs/gfs2/eattr.c b/fs/gfs2/eattr.c
-index 2a7435b..bee9970 100644
---- a/fs/gfs2/eattr.c
-+++ b/fs/gfs2/eattr.c
-@@ -1418,7 +1418,7 @@ out:
- static int ea_dealloc_block(struct gfs2_inode *ip)
- {
- 	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
--	struct gfs2_alloc *al = &ip->i_alloc;
-+	struct gfs2_alloc *al = ip->i_alloc;
- 	struct gfs2_rgrpd *rgd;
- 	struct buffer_head *dibh;
- 	int error;
-diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c
-index a37efe4..80e09c5 100644
---- a/fs/gfs2/glock.c
-+++ b/fs/gfs2/glock.c
-@@ -1,6 +1,6 @@
- /*
-  * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
-- * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
-+ * Copyright (C) 2004-2007 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
-@@ -217,7 +217,6 @@ int gfs2_glock_put(struct gfs2_glock *gl)
- 	if (atomic_dec_and_test(&gl->gl_ref)) {
- 		hlist_del(&gl->gl_list);
- 		write_unlock(gl_lock_addr(gl->gl_hash));
--		BUG_ON(spin_is_locked(&gl->gl_spin));
- 		gfs2_assert(sdp, gl->gl_state == LM_ST_UNLOCKED);
- 		gfs2_assert(sdp, list_empty(&gl->gl_reclaim));
- 		gfs2_assert(sdp, list_empty(&gl->gl_holders));
-@@ -346,7 +345,6 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number,
- 	gl->gl_object = NULL;
- 	gl->gl_sbd = sdp;
- 	gl->gl_aspace = NULL;
--	lops_init_le(&gl->gl_le, &gfs2_glock_lops);
- 	INIT_DELAYED_WORK(&gl->gl_work, glock_work_func);
+ 	if (inode->i_flags & (S_IMMUTABLE|S_APPEND)) {
+ 		ret = -EPERM;
+-		goto out_meta_unlock;
++		goto out_inode_unlock;
+ 	}
  
- 	/* If this glock protects actual on-disk data or metadata blocks,
-@@ -461,7 +459,6 @@ static void wait_on_holder(struct gfs2_holder *gh)
+ 	switch (sr->l_whence) {
+@@ -1652,7 +1681,7 @@ static int __ocfs2_change_file_space(struct file *file, struct inode *inode,
+ 		break;
+ 	default:
+ 		ret = -EINVAL;
+-		goto out_meta_unlock;
++		goto out_inode_unlock;
+ 	}
+ 	sr->l_whence = 0;
  
- static void gfs2_demote_wake(struct gfs2_glock *gl)
- {
--	BUG_ON(!spin_is_locked(&gl->gl_spin));
- 	gl->gl_demote_state = LM_ST_EXCLUSIVE;
-         clear_bit(GLF_DEMOTE, &gl->gl_flags);
-         smp_mb__after_clear_bit();
-@@ -507,21 +504,12 @@ static int rq_mutex(struct gfs2_holder *gh)
- static int rq_promote(struct gfs2_holder *gh)
- {
- 	struct gfs2_glock *gl = gh->gh_gl;
--	struct gfs2_sbd *sdp = gl->gl_sbd;
+@@ -1663,14 +1692,14 @@ static int __ocfs2_change_file_space(struct file *file, struct inode *inode,
+ 	    || (sr->l_start + llen) < 0
+ 	    || (sr->l_start + llen) > max_off) {
+ 		ret = -EINVAL;
+-		goto out_meta_unlock;
++		goto out_inode_unlock;
+ 	}
+ 	size = sr->l_start + sr->l_len;
  
- 	if (!relaxed_state_ok(gl->gl_state, gh->gh_state, gh->gh_flags)) {
- 		if (list_empty(&gl->gl_holders)) {
- 			gl->gl_req_gh = gh;
- 			set_bit(GLF_LOCK, &gl->gl_flags);
- 			spin_unlock(&gl->gl_spin);
--
--			if (atomic_read(&sdp->sd_reclaim_count) >
--			    gfs2_tune_get(sdp, gt_reclaim_limit) &&
--			    !(gh->gh_flags & LM_FLAG_PRIORITY)) {
--				gfs2_reclaim_glock(sdp);
--				gfs2_reclaim_glock(sdp);
--			}
--
- 			gfs2_glock_xmote_th(gh->gh_gl, gh);
- 			spin_lock(&gl->gl_spin);
+ 	if (cmd == OCFS2_IOC_RESVSP || cmd == OCFS2_IOC_RESVSP64) {
+ 		if (sr->l_len <= 0) {
+ 			ret = -EINVAL;
+-			goto out_meta_unlock;
++			goto out_inode_unlock;
  		}
-@@ -567,7 +555,10 @@ static int rq_demote(struct gfs2_glock *gl)
- 		gfs2_demote_wake(gl);
- 		return 0;
- 	}
-+
- 	set_bit(GLF_LOCK, &gl->gl_flags);
-+	set_bit(GLF_DEMOTE_IN_PROGRESS, &gl->gl_flags);
-+
- 	if (gl->gl_demote_state == LM_ST_UNLOCKED ||
- 	    gl->gl_state != LM_ST_EXCLUSIVE) {
- 		spin_unlock(&gl->gl_spin);
-@@ -576,7 +567,9 @@ static int rq_demote(struct gfs2_glock *gl)
- 		spin_unlock(&gl->gl_spin);
- 		gfs2_glock_xmote_th(gl, NULL);
  	}
-+
- 	spin_lock(&gl->gl_spin);
-+	clear_bit(GLF_DEMOTE_IN_PROGRESS, &gl->gl_flags);
  
- 	return 0;
- }
-@@ -598,23 +591,18 @@ static void run_queue(struct gfs2_glock *gl)
- 		if (!list_empty(&gl->gl_waiters1)) {
- 			gh = list_entry(gl->gl_waiters1.next,
- 					struct gfs2_holder, gh_list);
--
--			if (test_bit(HIF_MUTEX, &gh->gh_iflags))
--				blocked = rq_mutex(gh);
--			else
--				gfs2_assert_warn(gl->gl_sbd, 0);
--
-+			blocked = rq_mutex(gh);
- 		} else if (test_bit(GLF_DEMOTE, &gl->gl_flags)) {
- 			blocked = rq_demote(gl);
-+			if (gl->gl_waiters2 && !blocked) {
-+				set_bit(GLF_DEMOTE, &gl->gl_flags);
-+				gl->gl_demote_state = LM_ST_UNLOCKED;
-+			}
-+			gl->gl_waiters2 = 0;
- 		} else if (!list_empty(&gl->gl_waiters3)) {
- 			gh = list_entry(gl->gl_waiters3.next,
- 					struct gfs2_holder, gh_list);
--
--			if (test_bit(HIF_PROMOTE, &gh->gh_iflags))
--				blocked = rq_promote(gh);
--			else
--				gfs2_assert_warn(gl->gl_sbd, 0);
--
-+			blocked = rq_promote(gh);
- 		} else
- 			break;
+@@ -1678,7 +1707,7 @@ static int __ocfs2_change_file_space(struct file *file, struct inode *inode,
+ 		ret = __ocfs2_write_remove_suid(inode, di_bh);
+ 		if (ret) {
+ 			mlog_errno(ret);
+-			goto out_meta_unlock;
++			goto out_inode_unlock;
+ 		}
+ 	}
  
-@@ -632,27 +620,21 @@ static void run_queue(struct gfs2_glock *gl)
+@@ -1704,7 +1733,7 @@ static int __ocfs2_change_file_space(struct file *file, struct inode *inode,
+ 	up_write(&OCFS2_I(inode)->ip_alloc_sem);
+ 	if (ret) {
+ 		mlog_errno(ret);
+-		goto out_meta_unlock;
++		goto out_inode_unlock;
+ 	}
  
- static void gfs2_glmutex_lock(struct gfs2_glock *gl)
- {
--	struct gfs2_holder gh;
--
--	gfs2_holder_init(gl, 0, 0, &gh);
--	set_bit(HIF_MUTEX, &gh.gh_iflags);
--	if (test_and_set_bit(HIF_WAIT, &gh.gh_iflags))
--		BUG();
--
- 	spin_lock(&gl->gl_spin);
- 	if (test_and_set_bit(GLF_LOCK, &gl->gl_flags)) {
-+		struct gfs2_holder gh;
-+
-+		gfs2_holder_init(gl, 0, 0, &gh);
-+		set_bit(HIF_WAIT, &gh.gh_iflags);
- 		list_add_tail(&gh.gh_list, &gl->gl_waiters1);
-+		spin_unlock(&gl->gl_spin);
-+		wait_on_holder(&gh);
-+		gfs2_holder_uninit(&gh);
- 	} else {
- 		gl->gl_owner_pid = current->pid;
- 		gl->gl_ip = (unsigned long)__builtin_return_address(0);
--		clear_bit(HIF_WAIT, &gh.gh_iflags);
--		smp_mb();
--		wake_up_bit(&gh.gh_iflags, HIF_WAIT);
-+		spin_unlock(&gl->gl_spin);
+ 	/*
+@@ -1714,7 +1743,7 @@ static int __ocfs2_change_file_space(struct file *file, struct inode *inode,
+ 	if (IS_ERR(handle)) {
+ 		ret = PTR_ERR(handle);
+ 		mlog_errno(ret);
+-		goto out_meta_unlock;
++		goto out_inode_unlock;
  	}
--	spin_unlock(&gl->gl_spin);
--
--	wait_on_holder(&gh);
--	gfs2_holder_uninit(&gh);
- }
  
- /**
-@@ -691,7 +673,6 @@ static void gfs2_glmutex_unlock(struct gfs2_glock *gl)
- 	gl->gl_owner_pid = 0;
- 	gl->gl_ip = 0;
- 	run_queue(gl);
--	BUG_ON(!spin_is_locked(&gl->gl_spin));
- 	spin_unlock(&gl->gl_spin);
- }
+ 	if (change_size && i_size_read(inode) < size)
+@@ -1727,9 +1756,9 @@ static int __ocfs2_change_file_space(struct file *file, struct inode *inode,
  
-@@ -722,7 +703,10 @@ static void handle_callback(struct gfs2_glock *gl, unsigned int state,
- 		}
- 	} else if (gl->gl_demote_state != LM_ST_UNLOCKED &&
- 			gl->gl_demote_state != state) {
--		gl->gl_demote_state = LM_ST_UNLOCKED;
-+		if (test_bit(GLF_DEMOTE_IN_PROGRESS,  &gl->gl_flags)) 
-+			gl->gl_waiters2 = 1;
-+		else 
-+			gl->gl_demote_state = LM_ST_UNLOCKED;
+ 	ocfs2_commit_trans(osb, handle);
+ 
+-out_meta_unlock:
++out_inode_unlock:
+ 	brelse(di_bh);
+-	ocfs2_meta_unlock(inode, 1);
++	ocfs2_inode_unlock(inode, 1);
+ out_rw_unlock:
+ 	ocfs2_rw_unlock(inode, 1);
+ 
+@@ -1799,7 +1828,7 @@ static int ocfs2_prepare_inode_for_write(struct dentry *dentry,
+ 	 * if we need to make modifications here.
+ 	 */
+ 	for(;;) {
+-		ret = ocfs2_meta_lock(inode, NULL, meta_level);
++		ret = ocfs2_inode_lock(inode, NULL, meta_level);
+ 		if (ret < 0) {
+ 			meta_level = -1;
+ 			mlog_errno(ret);
+@@ -1817,7 +1846,7 @@ static int ocfs2_prepare_inode_for_write(struct dentry *dentry,
+ 		 * set inode->i_size at the end of a write. */
+ 		if (should_remove_suid(dentry)) {
+ 			if (meta_level == 0) {
+-				ocfs2_meta_unlock(inode, meta_level);
++				ocfs2_inode_unlock(inode, meta_level);
+ 				meta_level = 1;
+ 				continue;
+ 			}
+@@ -1886,7 +1915,7 @@ static int ocfs2_prepare_inode_for_write(struct dentry *dentry,
+ 		*ppos = saved_pos;
+ 
+ out_unlock:
+-	ocfs2_meta_unlock(inode, meta_level);
++	ocfs2_inode_unlock(inode, meta_level);
+ 
+ out:
+ 	return ret;
+@@ -2099,12 +2128,12 @@ static ssize_t ocfs2_file_splice_read(struct file *in,
+ 	/*
+ 	 * See the comment in ocfs2_file_aio_read()
+ 	 */
+-	ret = ocfs2_meta_lock(inode, NULL, 0);
++	ret = ocfs2_inode_lock(inode, NULL, 0);
+ 	if (ret < 0) {
+ 		mlog_errno(ret);
+ 		goto bail;
  	}
- 	spin_unlock(&gl->gl_spin);
- }
-@@ -943,8 +927,8 @@ static void gfs2_glock_drop_th(struct gfs2_glock *gl)
- 	const struct gfs2_glock_operations *glops = gl->gl_ops;
- 	unsigned int ret;
+-	ocfs2_meta_unlock(inode, 0);
++	ocfs2_inode_unlock(inode, 0);
  
--	if (glops->go_drop_th)
--		glops->go_drop_th(gl);
-+	if (glops->go_xmote_th)
-+		glops->go_xmote_th(gl);
+ 	ret = generic_file_splice_read(in, ppos, pipe, len, flags);
  
- 	gfs2_assert_warn(sdp, test_bit(GLF_LOCK, &gl->gl_flags));
- 	gfs2_assert_warn(sdp, list_empty(&gl->gl_holders));
-@@ -1156,8 +1140,6 @@ restart:
- 		return -EIO;
+@@ -2160,12 +2189,12 @@ static ssize_t ocfs2_file_aio_read(struct kiocb *iocb,
+ 	 * like i_size. This allows the checks down below
+ 	 * generic_file_aio_read() a chance of actually working. 
+ 	 */
+-	ret = ocfs2_meta_lock_atime(inode, filp->f_vfsmnt, &lock_level);
++	ret = ocfs2_inode_lock_atime(inode, filp->f_vfsmnt, &lock_level);
+ 	if (ret < 0) {
+ 		mlog_errno(ret);
+ 		goto bail;
  	}
+-	ocfs2_meta_unlock(inode, lock_level);
++	ocfs2_inode_unlock(inode, lock_level);
+ 
+ 	ret = generic_file_aio_read(iocb, iov, nr_segs, iocb->ki_pos);
+ 	if (ret == -EINVAL)
+@@ -2204,6 +2233,7 @@ const struct inode_operations ocfs2_special_file_iops = {
+ };
+ 
+ const struct file_operations ocfs2_fops = {
++	.llseek		= generic_file_llseek,
+ 	.read		= do_sync_read,
+ 	.write		= do_sync_write,
+ 	.mmap		= ocfs2_mmap,
+@@ -2216,16 +2246,21 @@ const struct file_operations ocfs2_fops = {
+ #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 = {
++	.llseek		= generic_file_llseek,
+ 	.read		= generic_read_dir,
+ 	.readdir	= ocfs2_readdir,
+ 	.fsync		= ocfs2_sync_file,
++	.release	= ocfs2_dir_release,
++	.open		= ocfs2_dir_open,
+ 	.ioctl		= ocfs2_ioctl,
+ #ifdef CONFIG_COMPAT
+ 	.compat_ioctl   = ocfs2_compat_ioctl,
+ #endif
++	.flock		= ocfs2_flock,
+ };
+diff --git a/fs/ocfs2/file.h b/fs/ocfs2/file.h
+index 066f14a..048ddca 100644
+--- a/fs/ocfs2/file.h
++++ b/fs/ocfs2/file.h
+@@ -32,6 +32,12 @@ extern const struct inode_operations ocfs2_file_iops;
+ extern const struct inode_operations ocfs2_special_file_iops;
+ struct ocfs2_alloc_context;
+ 
++struct ocfs2_file_private {
++	struct file		*fp_file;
++	struct mutex		fp_mutex;
++	struct ocfs2_lock_res	fp_flock;
++};
++
+ enum ocfs2_alloc_restarted {
+ 	RESTART_NONE = 0,
+ 	RESTART_TRANS,
+diff --git a/fs/ocfs2/heartbeat.c b/fs/ocfs2/heartbeat.c
+index c4c3617..c0efd94 100644
+--- a/fs/ocfs2/heartbeat.c
++++ b/fs/ocfs2/heartbeat.c
+@@ -30,9 +30,6 @@
+ #include <linux/highmem.h>
+ #include <linux/kmod.h>
  
--	set_bit(HIF_PROMOTE, &gh->gh_iflags);
+-#include <cluster/heartbeat.h>
+-#include <cluster/nodemanager.h>
 -
- 	spin_lock(&gl->gl_spin);
- 	add_to_queue(gh);
- 	run_queue(gl);
-@@ -1248,12 +1230,11 @@ void gfs2_glock_dq(struct gfs2_holder *gh)
- 	list_del_init(&gh->gh_list);
+ #include <dlm/dlmapi.h>
  
- 	if (list_empty(&gl->gl_holders)) {
--		spin_unlock(&gl->gl_spin);
--
--		if (glops->go_unlock)
-+		if (glops->go_unlock) {
-+			spin_unlock(&gl->gl_spin);
- 			glops->go_unlock(gh);
+ #define MLOG_MASK_PREFIX ML_SUPER
+@@ -44,13 +41,9 @@
+ #include "heartbeat.h"
+ #include "inode.h"
+ #include "journal.h"
+-#include "vote.h"
+ 
+ #include "buffer_head_io.h"
+ 
+-#define OCFS2_HB_NODE_DOWN_PRI     (0x0000002)
+-#define OCFS2_HB_NODE_UP_PRI	   OCFS2_HB_NODE_DOWN_PRI
 -
--		spin_lock(&gl->gl_spin);
-+			spin_lock(&gl->gl_spin);
-+		}
- 		gl->gl_stamp = jiffies;
- 	}
+ static inline void __ocfs2_node_map_set_bit(struct ocfs2_node_map *map,
+ 					    int bit);
+ static inline void __ocfs2_node_map_clear_bit(struct ocfs2_node_map *map,
+@@ -64,9 +57,7 @@ static void __ocfs2_node_map_set(struct ocfs2_node_map *target,
+ void ocfs2_init_node_maps(struct ocfs2_super *osb)
+ {
+ 	spin_lock_init(&osb->node_map_lock);
+-	ocfs2_node_map_init(&osb->mounted_map);
+ 	ocfs2_node_map_init(&osb->recovery_map);
+-	ocfs2_node_map_init(&osb->umount_map);
+ 	ocfs2_node_map_init(&osb->osb_recovering_orphan_dirs);
+ }
  
-@@ -1910,8 +1891,6 @@ static int dump_glock(struct glock_iter *gi, struct gfs2_glock *gl)
- 	print_dbg(gi, "  req_bh = %s\n", (gl->gl_req_bh) ? "yes" : "no");
- 	print_dbg(gi, "  lvb_count = %d\n", atomic_read(&gl->gl_lvb_count));
- 	print_dbg(gi, "  object = %s\n", (gl->gl_object) ? "yes" : "no");
--	print_dbg(gi, "  le = %s\n",
--		   (list_empty(&gl->gl_le.le_list)) ? "no" : "yes");
- 	print_dbg(gi, "  reclaim = %s\n",
- 		   (list_empty(&gl->gl_reclaim)) ? "no" : "yes");
- 	if (gl->gl_aspace)
-diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c
-index 4670dcb..c663b7a 100644
---- a/fs/gfs2/glops.c
-+++ b/fs/gfs2/glops.c
-@@ -56,7 +56,7 @@ static void gfs2_ail_empty_gl(struct gfs2_glock *gl)
- 		bd = list_entry(head->next, struct gfs2_bufdata,
- 				bd_ail_gl_list);
- 		bh = bd->bd_bh;
--		gfs2_remove_from_ail(NULL, bd);
-+		gfs2_remove_from_ail(bd);
- 		bd->bd_bh = NULL;
- 		bh->b_private = NULL;
- 		bd->bd_blkno = bh->b_blocknr;
-@@ -86,15 +86,10 @@ static void gfs2_pte_inval(struct gfs2_glock *gl)
- 	if (!ip || !S_ISREG(inode->i_mode))
+@@ -87,24 +78,7 @@ static void ocfs2_do_node_down(int node_num,
  		return;
+ 	}
  
--	if (!test_bit(GIF_PAGED, &ip->i_flags))
+-	if (ocfs2_node_map_test_bit(osb, &osb->umount_map, node_num)) {
+-		/* If a node is in the umount map, then we've been
+-		 * expecting him to go down and we know ahead of time
+-		 * that recovery is not necessary. */
+-		ocfs2_node_map_clear_bit(osb, &osb->umount_map, node_num);
 -		return;
+-	}
 -
- 	unmap_shared_mapping_range(inode->i_mapping, 0, 0);
+ 	ocfs2_recovery_thread(osb, node_num);
 -
- 	if (test_bit(GIF_SW_PAGED, &ip->i_flags))
- 		set_bit(GLF_DIRTY, &gl->gl_flags);
- 
--	clear_bit(GIF_SW_PAGED, &ip->i_flags);
+-	ocfs2_remove_node_from_vote_queues(osb, node_num);
+-}
+-
+-static void ocfs2_hb_node_down_cb(struct o2nm_node *node,
+-				  int node_num,
+-				  void *data)
+-{
+-	ocfs2_do_node_down(node_num, (struct ocfs2_super *) data);
  }
  
- /**
-@@ -143,44 +138,34 @@ static void meta_go_inval(struct gfs2_glock *gl, int flags)
- static void inode_go_sync(struct gfs2_glock *gl)
- {
- 	struct gfs2_inode *ip = gl->gl_object;
-+	struct address_space *metamapping = gl->gl_aspace->i_mapping;
-+	int error;
-+
-+	if (gl->gl_state != LM_ST_UNLOCKED)
-+		gfs2_pte_inval(gl);
-+	if (gl->gl_state != LM_ST_EXCLUSIVE)
-+		return;
- 
- 	if (ip && !S_ISREG(ip->i_inode.i_mode))
- 		ip = NULL;
- 
- 	if (test_bit(GLF_DIRTY, &gl->gl_flags)) {
--		if (ip && !gfs2_is_jdata(ip))
--			filemap_fdatawrite(ip->i_inode.i_mapping);
- 		gfs2_log_flush(gl->gl_sbd, gl);
--		if (ip && gfs2_is_jdata(ip))
--			filemap_fdatawrite(ip->i_inode.i_mapping);
--		gfs2_meta_sync(gl);
-+		filemap_fdatawrite(metamapping);
- 		if (ip) {
- 			struct address_space *mapping = ip->i_inode.i_mapping;
--			int error = filemap_fdatawait(mapping);
-+			filemap_fdatawrite(mapping);
-+			error = filemap_fdatawait(mapping);
- 			mapping_set_error(mapping, error);
- 		}
-+		error = filemap_fdatawait(metamapping);
-+		mapping_set_error(metamapping, error);
- 		clear_bit(GLF_DIRTY, &gl->gl_flags);
- 		gfs2_ail_empty_gl(gl);
- 	}
+ /* Called from the dlm when it's about to evict a node. We may also
+@@ -121,27 +95,8 @@ static void ocfs2_dlm_eviction_cb(int node_num,
+ 	ocfs2_do_node_down(node_num, osb);
  }
  
- /**
-- * inode_go_xmote_th - promote/demote a glock
-- * @gl: the glock
-- * @state: the requested state
-- * @flags:
-- *
-- */
--
--static void inode_go_xmote_th(struct gfs2_glock *gl)
+-static void ocfs2_hb_node_up_cb(struct o2nm_node *node,
+-				int node_num,
+-				void *data)
 -{
--	if (gl->gl_state != LM_ST_UNLOCKED)
--		gfs2_pte_inval(gl);
--	if (gl->gl_state == LM_ST_EXCLUSIVE)
--		inode_go_sync(gl);
+-	struct ocfs2_super *osb = data;
+-
+-	BUG_ON(osb->node_num == node_num);
+-
+-	mlog(0, "node up event for %d\n", node_num);
+-	ocfs2_node_map_clear_bit(osb, &osb->umount_map, node_num);
 -}
 -
--/**
-  * inode_go_xmote_bh - After promoting/demoting a glock
-  * @gl: the glock
-  *
-@@ -201,22 +186,6 @@ static void inode_go_xmote_bh(struct gfs2_glock *gl)
+ void ocfs2_setup_hb_callbacks(struct ocfs2_super *osb)
+ {
+-	o2hb_setup_callback(&osb->osb_hb_down, O2HB_NODE_DOWN_CB,
+-			    ocfs2_hb_node_down_cb, osb,
+-			    OCFS2_HB_NODE_DOWN_PRI);
+-
+-	o2hb_setup_callback(&osb->osb_hb_up, O2HB_NODE_UP_CB,
+-			    ocfs2_hb_node_up_cb, osb, OCFS2_HB_NODE_UP_PRI);
+-
+ 	/* Not exactly a heartbeat callback, but leads to essentially
+ 	 * the same path so we set it up here. */
+ 	dlm_setup_eviction_cb(&osb->osb_eviction_cb,
+@@ -149,39 +104,6 @@ void ocfs2_setup_hb_callbacks(struct ocfs2_super *osb)
+ 			      osb);
  }
  
- /**
-- * inode_go_drop_th - unlock a glock
-- * @gl: the glock
-- *
-- * Invoked from rq_demote().
-- * Another node needs the lock in EXCLUSIVE mode, or lock (unused for too long)
-- * is being purged from our node's glock cache; we're dropping lock.
-- */
--
--static void inode_go_drop_th(struct gfs2_glock *gl)
+-/* Most functions here are just stubs for now... */
+-int ocfs2_register_hb_callbacks(struct ocfs2_super *osb)
 -{
--	gfs2_pte_inval(gl);
--	if (gl->gl_state == LM_ST_EXCLUSIVE)
--		inode_go_sync(gl);
--}
+-	int status;
 -
--/**
-  * inode_go_inval - prepare a inode glock to be released
-  * @gl: the glock
-  * @flags:
-@@ -234,10 +203,8 @@ static void inode_go_inval(struct gfs2_glock *gl, int flags)
- 			set_bit(GIF_INVALID, &ip->i_flags);
- 	}
- 
--	if (ip && S_ISREG(ip->i_inode.i_mode)) {
-+	if (ip && S_ISREG(ip->i_inode.i_mode))
- 		truncate_inode_pages(ip->i_inode.i_mapping, 0);
--		clear_bit(GIF_PAGED, &ip->i_flags);
+-	if (ocfs2_mount_local(osb))
+-		return 0;
+-
+-	status = o2hb_register_callback(osb->uuid_str, &osb->osb_hb_down);
+-	if (status < 0) {
+-		mlog_errno(status);
+-		goto bail;
 -	}
- }
- 
- /**
-@@ -294,23 +261,6 @@ static int inode_go_lock(struct gfs2_holder *gh)
- }
- 
- /**
-- * inode_go_unlock - operation done before an inode lock is unlocked by a
-- *		     process
-- * @gl: the glock
-- * @flags:
-- *
-- */
 -
--static void inode_go_unlock(struct gfs2_holder *gh)
+-	status = o2hb_register_callback(osb->uuid_str, &osb->osb_hb_up);
+-	if (status < 0) {
+-		mlog_errno(status);
+-		o2hb_unregister_callback(osb->uuid_str, &osb->osb_hb_down);
+-	}
+-
+-bail:
+-	return status;
+-}
+-
+-void ocfs2_clear_hb_callbacks(struct ocfs2_super *osb)
 -{
--	struct gfs2_glock *gl = gh->gh_gl;
--	struct gfs2_inode *ip = gl->gl_object;
+-	if (ocfs2_mount_local(osb))
+-		return;
 -
--	if (ip)
--		gfs2_meta_cache_flush(ip);
+-	o2hb_unregister_callback(osb->uuid_str, &osb->osb_hb_down);
+-	o2hb_unregister_callback(osb->uuid_str, &osb->osb_hb_up);
 -}
 -
--/**
-  * rgrp_go_demote_ok - Check to see if it's ok to unlock a RG's glock
-  * @gl: the glock
-  *
-@@ -350,14 +300,14 @@ static void rgrp_go_unlock(struct gfs2_holder *gh)
- }
+ void ocfs2_stop_heartbeat(struct ocfs2_super *osb)
+ {
+ 	int ret;
+@@ -341,8 +263,6 @@ int ocfs2_recovery_map_set(struct ocfs2_super *osb,
  
- /**
-- * trans_go_xmote_th - promote/demote the transaction glock
-+ * trans_go_sync - promote/demote the transaction glock
-  * @gl: the glock
-  * @state: the requested state
-  * @flags:
-  *
-  */
+ 	spin_lock(&osb->node_map_lock);
  
--static void trans_go_xmote_th(struct gfs2_glock *gl)
-+static void trans_go_sync(struct gfs2_glock *gl)
- {
- 	struct gfs2_sbd *sdp = gl->gl_sbd;
+-	__ocfs2_node_map_clear_bit(&osb->mounted_map, num);
+-
+ 	if (!test_bit(num, osb->recovery_map.map)) {
+ 	    __ocfs2_node_map_set_bit(&osb->recovery_map, num);
+ 	    set = 1;
+diff --git a/fs/ocfs2/heartbeat.h b/fs/ocfs2/heartbeat.h
+index e8fb079..5685921 100644
+--- a/fs/ocfs2/heartbeat.h
++++ b/fs/ocfs2/heartbeat.h
+@@ -29,8 +29,6 @@
+ void ocfs2_init_node_maps(struct ocfs2_super *osb);
  
-@@ -384,7 +334,6 @@ static void trans_go_xmote_bh(struct gfs2_glock *gl)
+ void ocfs2_setup_hb_callbacks(struct ocfs2_super *osb);
+-int ocfs2_register_hb_callbacks(struct ocfs2_super *osb);
+-void ocfs2_clear_hb_callbacks(struct ocfs2_super *osb);
+ void ocfs2_stop_heartbeat(struct ocfs2_super *osb);
  
- 	if (gl->gl_state != LM_ST_UNLOCKED &&
- 	    test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags)) {
--		gfs2_meta_cache_flush(GFS2_I(sdp->sd_jdesc->jd_inode));
- 		j_gl->gl_ops->go_inval(j_gl, DIO_METADATA);
+ /* node map functions - used to keep track of mounted and in-recovery
+diff --git a/fs/ocfs2/inode.c b/fs/ocfs2/inode.c
+index ebb2bbe..7e9e4c7 100644
+--- a/fs/ocfs2/inode.c
++++ b/fs/ocfs2/inode.c
+@@ -49,7 +49,6 @@
+ #include "symlink.h"
+ #include "sysfile.h"
+ #include "uptodate.h"
+-#include "vote.h"
  
- 		error = gfs2_find_jhead(sdp->sd_jdesc, &head);
-@@ -402,24 +351,6 @@ static void trans_go_xmote_bh(struct gfs2_glock *gl)
+ #include "buffer_head_io.h"
+ 
+@@ -58,8 +57,11 @@ struct ocfs2_find_inode_args
+ 	u64		fi_blkno;
+ 	unsigned long	fi_ino;
+ 	unsigned int	fi_flags;
++	unsigned int	fi_sysfile_type;
+ };
+ 
++static struct lock_class_key ocfs2_sysfile_lock_key[NUM_SYSTEM_INODES];
++
+ static int ocfs2_read_locked_inode(struct inode *inode,
+ 				   struct ocfs2_find_inode_args *args);
+ static int ocfs2_init_locked_inode(struct inode *inode, void *opaque);
+@@ -107,7 +109,8 @@ void ocfs2_get_inode_flags(struct ocfs2_inode_info *oi)
+ 		oi->ip_attr |= OCFS2_DIRSYNC_FL;
  }
  
- /**
-- * trans_go_drop_th - unlock the transaction glock
-- * @gl: the glock
-- *
-- * We want to sync the device even with localcaching.  Remember
-- * that localcaching journal replay only marks buffers dirty.
-- */
--
--static void trans_go_drop_th(struct gfs2_glock *gl)
--{
--	struct gfs2_sbd *sdp = gl->gl_sbd;
--
--	if (test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags)) {
--		gfs2_meta_syncfs(sdp);
--		gfs2_log_shutdown(sdp);
--	}
--}
--
--/**
-  * quota_go_demote_ok - Check to see if it's ok to unlock a quota glock
-  * @gl: the glock
-  *
-@@ -433,25 +364,21 @@ static int quota_go_demote_ok(struct gfs2_glock *gl)
+-struct inode *ocfs2_iget(struct ocfs2_super *osb, u64 blkno, int flags)
++struct inode *ocfs2_iget(struct ocfs2_super *osb, u64 blkno, unsigned flags,
++			 int sysfile_type)
+ {
+ 	struct inode *inode = NULL;
+ 	struct super_block *sb = osb->sb;
+@@ -127,6 +130,7 @@ struct inode *ocfs2_iget(struct ocfs2_super *osb, u64 blkno, int flags)
+ 	args.fi_blkno = blkno;
+ 	args.fi_flags = flags;
+ 	args.fi_ino = ino_from_blkno(sb, blkno);
++	args.fi_sysfile_type = sysfile_type;
  
- const struct gfs2_glock_operations gfs2_meta_glops = {
- 	.go_xmote_th = meta_go_sync,
--	.go_drop_th = meta_go_sync,
- 	.go_type = LM_TYPE_META,
- };
+ 	inode = iget5_locked(sb, args.fi_ino, ocfs2_find_actor,
+ 			     ocfs2_init_locked_inode, &args);
+@@ -201,6 +205,9 @@ static int ocfs2_init_locked_inode(struct inode *inode, void *opaque)
  
- const struct gfs2_glock_operations gfs2_inode_glops = {
--	.go_xmote_th = inode_go_xmote_th,
-+	.go_xmote_th = inode_go_sync,
- 	.go_xmote_bh = inode_go_xmote_bh,
--	.go_drop_th = inode_go_drop_th,
- 	.go_inval = inode_go_inval,
- 	.go_demote_ok = inode_go_demote_ok,
- 	.go_lock = inode_go_lock,
--	.go_unlock = inode_go_unlock,
- 	.go_type = LM_TYPE_INODE,
- 	.go_min_hold_time = HZ / 10,
- };
+ 	inode->i_ino = args->fi_ino;
+ 	OCFS2_I(inode)->ip_blkno = args->fi_blkno;
++	if (args->fi_sysfile_type != 0)
++		lockdep_set_class(&inode->i_mutex,
++			&ocfs2_sysfile_lock_key[args->fi_sysfile_type]);
  
- const struct gfs2_glock_operations gfs2_rgrp_glops = {
- 	.go_xmote_th = meta_go_sync,
--	.go_drop_th = meta_go_sync,
- 	.go_inval = meta_go_inval,
- 	.go_demote_ok = rgrp_go_demote_ok,
- 	.go_lock = rgrp_go_lock,
-@@ -461,9 +388,8 @@ const struct gfs2_glock_operations gfs2_rgrp_glops = {
- };
+ 	mlog_exit(0);
+ 	return 0;
+@@ -322,7 +329,7 @@ int ocfs2_populate_inode(struct inode *inode, struct ocfs2_dinode *fe,
+ 		 */
+ 		BUG_ON(le32_to_cpu(fe->i_flags) & OCFS2_SYSTEM_FL);
  
- const struct gfs2_glock_operations gfs2_trans_glops = {
--	.go_xmote_th = trans_go_xmote_th,
-+	.go_xmote_th = trans_go_sync,
- 	.go_xmote_bh = trans_go_xmote_bh,
--	.go_drop_th = trans_go_drop_th,
- 	.go_type = LM_TYPE_NONDISK,
- };
+-		ocfs2_inode_lock_res_init(&OCFS2_I(inode)->ip_meta_lockres,
++		ocfs2_inode_lock_res_init(&OCFS2_I(inode)->ip_inode_lockres,
+ 					  OCFS2_LOCK_TYPE_META, 0, inode);
  
-diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h
-index eaddfb5..513aaf0 100644
---- a/fs/gfs2/incore.h
-+++ b/fs/gfs2/incore.h
-@@ -1,6 +1,6 @@
- /*
-  * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
-- * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
-+ * Copyright (C) 2004-2007 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
-@@ -131,7 +131,6 @@ struct gfs2_bufdata {
- struct gfs2_glock_operations {
- 	void (*go_xmote_th) (struct gfs2_glock *gl);
- 	void (*go_xmote_bh) (struct gfs2_glock *gl);
--	void (*go_drop_th) (struct gfs2_glock *gl);
- 	void (*go_inval) (struct gfs2_glock *gl, int flags);
- 	int (*go_demote_ok) (struct gfs2_glock *gl);
- 	int (*go_lock) (struct gfs2_holder *gh);
-@@ -141,10 +140,6 @@ struct gfs2_glock_operations {
- };
+ 		ocfs2_inode_lock_res_init(&OCFS2_I(inode)->ip_open_lockres,
+@@ -333,10 +340,6 @@ int ocfs2_populate_inode(struct inode *inode, struct ocfs2_dinode *fe,
+ 				  OCFS2_LOCK_TYPE_RW, inode->i_generation,
+ 				  inode);
  
- enum {
--	/* Actions */
--	HIF_MUTEX		= 0,
--	HIF_PROMOTE		= 1,
+-	ocfs2_inode_lock_res_init(&OCFS2_I(inode)->ip_data_lockres,
+-				  OCFS2_LOCK_TYPE_DATA, inode->i_generation,
+-				  inode);
 -
- 	/* States */
- 	HIF_HOLDER		= 6,
- 	HIF_FIRST		= 7,
-@@ -171,6 +166,8 @@ enum {
- 	GLF_DEMOTE		= 3,
- 	GLF_PENDING_DEMOTE	= 4,
- 	GLF_DIRTY		= 5,
-+	GLF_DEMOTE_IN_PROGRESS	= 6,
-+	GLF_LFLUSH		= 7,
- };
+ 	ocfs2_set_inode_flags(inode);
  
- struct gfs2_glock {
-@@ -190,6 +187,7 @@ struct gfs2_glock {
- 	struct list_head gl_holders;
- 	struct list_head gl_waiters1;	/* HIF_MUTEX */
- 	struct list_head gl_waiters3;	/* HIF_PROMOTE */
-+	int gl_waiters2;		/* GIF_DEMOTE */
+ 	status = 0;
+@@ -414,7 +417,7 @@ static int ocfs2_read_locked_inode(struct inode *inode,
+ 	if (args->fi_flags & OCFS2_FI_FLAG_SYSFILE)
+ 		generation = osb->fs_generation;
  
- 	const struct gfs2_glock_operations *gl_ops;
+-	ocfs2_inode_lock_res_init(&OCFS2_I(inode)->ip_meta_lockres,
++	ocfs2_inode_lock_res_init(&OCFS2_I(inode)->ip_inode_lockres,
+ 				  OCFS2_LOCK_TYPE_META,
+ 				  generation, inode);
  
-@@ -210,7 +208,6 @@ struct gfs2_glock {
- 	struct gfs2_sbd *gl_sbd;
+@@ -429,7 +432,7 @@ static int ocfs2_read_locked_inode(struct inode *inode,
+ 			mlog_errno(status);
+ 			return status;
+ 		}
+-		status = ocfs2_meta_lock(inode, NULL, 0);
++		status = ocfs2_inode_lock(inode, NULL, 0);
+ 		if (status) {
+ 			make_bad_inode(inode);
+ 			mlog_errno(status);
+@@ -484,7 +487,7 @@ static int ocfs2_read_locked_inode(struct inode *inode,
  
- 	struct inode *gl_aspace;
--	struct gfs2_log_element gl_le;
- 	struct list_head gl_ail_list;
- 	atomic_t gl_ail_count;
- 	struct delayed_work gl_work;
-@@ -239,7 +236,6 @@ struct gfs2_alloc {
- enum {
- 	GIF_INVALID		= 0,
- 	GIF_QD_LOCKED		= 1,
--	GIF_PAGED		= 2,
- 	GIF_SW_PAGED		= 3,
- };
+ bail:
+ 	if (can_lock)
+-		ocfs2_meta_unlock(inode, 0);
++		ocfs2_inode_unlock(inode, 0);
  
-@@ -268,14 +264,10 @@ struct gfs2_inode {
- 	struct gfs2_glock *i_gl; /* Move into i_gh? */
- 	struct gfs2_holder i_iopen_gh;
- 	struct gfs2_holder i_gh; /* for prepare/commit_write only */
--	struct gfs2_alloc i_alloc;
-+	struct gfs2_alloc *i_alloc;
- 	u64 i_last_rg_alloc;
+ 	if (status < 0)
+ 		make_bad_inode(inode);
+@@ -586,7 +589,7 @@ static int ocfs2_remove_inode(struct inode *inode,
+ 	}
  
--	spinlock_t i_spin;
- 	struct rw_semaphore i_rw_mutex;
--	unsigned long i_last_pfault;
--
--	struct buffer_head *i_cache[GFS2_MAX_META_HEIGHT];
- };
+ 	mutex_lock(&inode_alloc_inode->i_mutex);
+-	status = ocfs2_meta_lock(inode_alloc_inode, &inode_alloc_bh, 1);
++	status = ocfs2_inode_lock(inode_alloc_inode, &inode_alloc_bh, 1);
+ 	if (status < 0) {
+ 		mutex_unlock(&inode_alloc_inode->i_mutex);
  
- /*
-@@ -287,19 +279,12 @@ static inline struct gfs2_inode *GFS2_I(struct inode *inode)
- 	return container_of(inode, struct gfs2_inode, i_inode);
- }
+@@ -617,7 +620,7 @@ static int ocfs2_remove_inode(struct inode *inode,
+ 	}
  
--/* To be removed? */
--static inline struct gfs2_sbd *GFS2_SB(struct inode *inode)
-+static inline struct gfs2_sbd *GFS2_SB(const struct inode *inode)
- {
- 	return inode->i_sb->s_fs_info;
+ 	di->i_dtime = cpu_to_le64(CURRENT_TIME.tv_sec);
+-	le32_and_cpu(&di->i_flags, ~(OCFS2_VALID_FL | OCFS2_ORPHANED_FL));
++	di->i_flags &= cpu_to_le32(~(OCFS2_VALID_FL | OCFS2_ORPHANED_FL));
+ 
+ 	status = ocfs2_journal_dirty(handle, di_bh);
+ 	if (status < 0) {
+@@ -635,7 +638,7 @@ static int ocfs2_remove_inode(struct inode *inode,
+ bail_commit:
+ 	ocfs2_commit_trans(osb, handle);
+ bail_unlock:
+-	ocfs2_meta_unlock(inode_alloc_inode, 1);
++	ocfs2_inode_unlock(inode_alloc_inode, 1);
+ 	mutex_unlock(&inode_alloc_inode->i_mutex);
+ 	brelse(inode_alloc_bh);
+ bail:
+@@ -709,7 +712,7 @@ static int ocfs2_wipe_inode(struct inode *inode,
+ 	 * delete_inode operation. We do this now to avoid races with
+ 	 * recovery completion on other nodes. */
+ 	mutex_lock(&orphan_dir_inode->i_mutex);
+-	status = ocfs2_meta_lock(orphan_dir_inode, &orphan_dir_bh, 1);
++	status = ocfs2_inode_lock(orphan_dir_inode, &orphan_dir_bh, 1);
+ 	if (status < 0) {
+ 		mutex_unlock(&orphan_dir_inode->i_mutex);
+ 
+@@ -718,8 +721,8 @@ static int ocfs2_wipe_inode(struct inode *inode,
+ 	}
+ 
+ 	/* we do this while holding the orphan dir lock because we
+-	 * don't want recovery being run from another node to vote for
+-	 * an inode delete on us -- this will result in two nodes
++	 * don't want recovery being run from another node to try an
++	 * inode delete underneath us -- this will result in two nodes
+ 	 * truncating the same file! */
+ 	status = ocfs2_truncate_for_delete(osb, inode, di_bh);
+ 	if (status < 0) {
+@@ -733,7 +736,7 @@ static int ocfs2_wipe_inode(struct inode *inode,
+ 		mlog_errno(status);
+ 
+ bail_unlock_dir:
+-	ocfs2_meta_unlock(orphan_dir_inode, 1);
++	ocfs2_inode_unlock(orphan_dir_inode, 1);
+ 	mutex_unlock(&orphan_dir_inode->i_mutex);
+ 	brelse(orphan_dir_bh);
+ bail:
+@@ -744,7 +747,7 @@ bail:
  }
  
--enum {
--	GFF_DID_DIRECT_ALLOC	= 0,
--	GFF_EXLOCK = 1,
--};
--
- struct gfs2_file {
--	unsigned long f_flags;		/* GFF_... */
- 	struct mutex f_fl_mutex;
- 	struct gfs2_holder f_fl_gh;
- };
-@@ -373,8 +358,17 @@ struct gfs2_ail {
- 	u64 ai_sync_gen;
- };
+ /* There is a series of simple checks that should be done before a
+- * vote is even considered. Encapsulate those in this function. */
++ * trylock is even considered. Encapsulate those in this function. */
+ static int ocfs2_inode_is_valid_to_delete(struct inode *inode)
+ {
+ 	int ret = 0;
+@@ -758,14 +761,14 @@ static int ocfs2_inode_is_valid_to_delete(struct inode *inode)
+ 		goto bail;
+ 	}
  
-+struct gfs2_journal_extent {
-+	struct list_head extent_list;
-+
-+	unsigned int lblock; /* First logical block */
-+	u64 dblock; /* First disk block */
-+	u64 blocks;
-+};
-+
- struct gfs2_jdesc {
- 	struct list_head jd_list;
-+	struct list_head extent_list;
+-	/* If we're coming from process_vote we can't go into our own
++	/* If we're coming from downconvert_thread we can't go into our own
+ 	 * voting [hello, deadlock city!], so unforuntately we just
+ 	 * have to skip deleting this guy. That's OK though because
+ 	 * the node who's doing the actual deleting should handle it
+ 	 * anyway. */
+-	if (current == osb->vote_task) {
++	if (current == osb->dc_task) {
+ 		mlog(0, "Skipping delete of %lu because we're currently "
+-		     "in process_vote\n", inode->i_ino);
++		     "in downconvert\n", inode->i_ino);
+ 		goto bail;
+ 	}
  
- 	struct inode *jd_inode;
- 	unsigned int jd_jid;
-@@ -421,13 +415,9 @@ struct gfs2_args {
- struct gfs2_tune {
- 	spinlock_t gt_spin;
+@@ -779,10 +782,9 @@ static int ocfs2_inode_is_valid_to_delete(struct inode *inode)
+ 		goto bail_unlock;
+ 	}
  
--	unsigned int gt_ilimit;
--	unsigned int gt_ilimit_tries;
--	unsigned int gt_ilimit_min;
- 	unsigned int gt_demote_secs; /* Cache retention for unheld glock */
- 	unsigned int gt_incore_log_blocks;
- 	unsigned int gt_log_flush_secs;
--	unsigned int gt_jindex_refresh_secs; /* Check for new journal index */
+-	/* If we have voted "yes" on the wipe of this inode for
+-	 * another node, it will be marked here so we can safely skip
+-	 * it. Recovery will cleanup any inodes we might inadvertantly
+-	 * skip here. */
++	/* If we have allowd wipe of this inode for another node, it
++	 * will be marked here so we can safely skip it. Recovery will
++	 * cleanup any inodes we might inadvertantly skip here. */
+ 	if (oi->ip_flags & OCFS2_INODE_SKIP_DELETE) {
+ 		mlog(0, "Skipping delete of %lu because another node "
+ 		     "has done this for us.\n", inode->i_ino);
+@@ -929,13 +931,13 @@ void ocfs2_delete_inode(struct inode *inode)
  
- 	unsigned int gt_recoverd_secs;
- 	unsigned int gt_logd_secs;
-@@ -443,10 +433,8 @@ struct gfs2_tune {
- 	unsigned int gt_new_files_jdata;
- 	unsigned int gt_new_files_directio;
- 	unsigned int gt_max_readahead; /* Max bytes to read-ahead from disk */
--	unsigned int gt_lockdump_size;
- 	unsigned int gt_stall_secs; /* Detects trouble! */
- 	unsigned int gt_complain_secs;
--	unsigned int gt_reclaim_limit; /* Max num of glocks in reclaim list */
- 	unsigned int gt_statfs_quantum;
- 	unsigned int gt_statfs_slow;
- };
-@@ -539,7 +527,6 @@ struct gfs2_sbd {
- 	/* StatFS stuff */
+ 	/* Lock down the inode. This gives us an up to date view of
+ 	 * it's metadata (for verification), and allows us to
+-	 * serialize delete_inode votes. 
++	 * serialize delete_inode on multiple nodes.
+ 	 *
+ 	 * Even though we might be doing a truncate, we don't take the
+ 	 * allocation lock here as it won't be needed - nobody will
+ 	 * have the file open.
+ 	 */
+-	status = ocfs2_meta_lock(inode, &di_bh, 1);
++	status = ocfs2_inode_lock(inode, &di_bh, 1);
+ 	if (status < 0) {
+ 		if (status != -ENOENT)
+ 			mlog_errno(status);
+@@ -947,15 +949,15 @@ void ocfs2_delete_inode(struct inode *inode)
+ 	 * before we go ahead and wipe the inode. */
+ 	status = ocfs2_query_inode_wipe(inode, di_bh, &wipe);
+ 	if (!wipe || status < 0) {
+-		/* Error and inode busy vote both mean we won't be
++		/* Error and remote inode busy both mean we won't be
+ 		 * removing the inode, so they take almost the same
+ 		 * path. */
+ 		if (status < 0)
+ 			mlog_errno(status);
  
- 	spinlock_t sd_statfs_spin;
--	struct mutex sd_statfs_mutex;
- 	struct gfs2_statfs_change_host sd_statfs_master;
- 	struct gfs2_statfs_change_host sd_statfs_local;
- 	unsigned long sd_statfs_sync_time;
-@@ -602,20 +589,18 @@ struct gfs2_sbd {
- 	unsigned int sd_log_commited_databuf;
- 	unsigned int sd_log_commited_revoke;
+-		/* Someone in the cluster has voted to not wipe this
+-		 * inode, or it was never completely orphaned. Write
+-		 * out the pages and exit now. */
++		/* Someone in the cluster has disallowed a wipe of
++		 * this inode, or it was never completely
++		 * orphaned. Write out the pages and exit now. */
+ 		ocfs2_cleanup_delete_inode(inode, 1);
+ 		goto bail_unlock_inode;
+ 	}
+@@ -981,7 +983,7 @@ void ocfs2_delete_inode(struct inode *inode)
+ 	OCFS2_I(inode)->ip_flags |= OCFS2_INODE_DELETED;
  
--	unsigned int sd_log_num_gl;
- 	unsigned int sd_log_num_buf;
- 	unsigned int sd_log_num_revoke;
- 	unsigned int sd_log_num_rg;
- 	unsigned int sd_log_num_databuf;
+ bail_unlock_inode:
+-	ocfs2_meta_unlock(inode, 1);
++	ocfs2_inode_unlock(inode, 1);
+ 	brelse(di_bh);
+ bail_unblock:
+ 	status = sigprocmask(SIG_SETMASK, &oldset, NULL);
+@@ -1008,15 +1010,14 @@ void ocfs2_clear_inode(struct inode *inode)
+ 	mlog_bug_on_msg(OCFS2_SB(inode->i_sb) == NULL,
+ 			"Inode=%lu\n", inode->i_ino);
  
--	struct list_head sd_log_le_gl;
- 	struct list_head sd_log_le_buf;
- 	struct list_head sd_log_le_revoke;
- 	struct list_head sd_log_le_rg;
- 	struct list_head sd_log_le_databuf;
- 	struct list_head sd_log_le_ordered;
+-	/* For remove delete_inode vote, we hold open lock before,
+-	 * now it is time to unlock PR and EX open locks. */
++	/* To preven remote deletes we hold open lock before, now it
++	 * is time to unlock PR and EX open locks. */
+ 	ocfs2_open_unlock(inode);
  
--	unsigned int sd_log_blks_free;
-+	atomic_t sd_log_blks_free;
- 	struct mutex sd_log_reserve_mutex;
+ 	/* Do these before all the other work so that we don't bounce
+-	 * the vote thread while waiting to destroy the locks. */
++	 * the downconvert thread while waiting to destroy the locks. */
+ 	ocfs2_mark_lockres_freeing(&oi->ip_rw_lockres);
+-	ocfs2_mark_lockres_freeing(&oi->ip_meta_lockres);
+-	ocfs2_mark_lockres_freeing(&oi->ip_data_lockres);
++	ocfs2_mark_lockres_freeing(&oi->ip_inode_lockres);
+ 	ocfs2_mark_lockres_freeing(&oi->ip_open_lockres);
  
- 	u64 sd_log_sequence;
-diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c
-index 5f6dc32..728d316 100644
---- a/fs/gfs2/inode.c
-+++ b/fs/gfs2/inode.c
-@@ -31,7 +31,6 @@
- #include "log.h"
- #include "meta_io.h"
- #include "ops_address.h"
--#include "ops_file.h"
- #include "ops_inode.h"
- #include "quota.h"
- #include "rgrp.h"
-@@ -132,15 +131,21 @@ static struct inode *gfs2_iget_skip(struct super_block *sb,
+ 	/* We very well may get a clear_inode before all an inodes
+@@ -1039,8 +1040,7 @@ void ocfs2_clear_inode(struct inode *inode)
+ 		mlog_errno(status);
  
- void gfs2_set_iop(struct inode *inode)
- {
-+	struct gfs2_sbd *sdp = GFS2_SB(inode);
- 	umode_t mode = inode->i_mode;
+ 	ocfs2_lock_res_free(&oi->ip_rw_lockres);
+-	ocfs2_lock_res_free(&oi->ip_meta_lockres);
+-	ocfs2_lock_res_free(&oi->ip_data_lockres);
++	ocfs2_lock_res_free(&oi->ip_inode_lockres);
+ 	ocfs2_lock_res_free(&oi->ip_open_lockres);
  
- 	if (S_ISREG(mode)) {
- 		inode->i_op = &gfs2_file_iops;
--		inode->i_fop = &gfs2_file_fops;
--		inode->i_mapping->a_ops = &gfs2_file_aops;
-+		if (sdp->sd_args.ar_localflocks)
-+			inode->i_fop = &gfs2_file_fops_nolock;
-+		else
-+			inode->i_fop = &gfs2_file_fops;
- 	} else if (S_ISDIR(mode)) {
- 		inode->i_op = &gfs2_dir_iops;
--		inode->i_fop = &gfs2_dir_fops;
-+		if (sdp->sd_args.ar_localflocks)
-+			inode->i_fop = &gfs2_dir_fops_nolock;
-+		else
-+			inode->i_fop = &gfs2_dir_fops;
- 	} else if (S_ISLNK(mode)) {
- 		inode->i_op = &gfs2_symlink_iops;
- 	} else {
-@@ -291,12 +296,10 @@ static int gfs2_dinode_in(struct gfs2_inode *ip, const void *buf)
- 	di->di_entries = be32_to_cpu(str->di_entries);
+ 	ocfs2_metadata_cache_purge(inode);
+@@ -1184,15 +1184,15 @@ int ocfs2_inode_revalidate(struct dentry *dentry)
+ 	}
+ 	spin_unlock(&OCFS2_I(inode)->ip_lock);
  
- 	di->di_eattr = be64_to_cpu(str->di_eattr);
--	return 0;
--}
-+	if (S_ISREG(ip->i_inode.i_mode))
-+		gfs2_set_aops(&ip->i_inode);
+-	/* Let ocfs2_meta_lock do the work of updating our struct
++	/* Let ocfs2_inode_lock do the work of updating our struct
+ 	 * inode for us. */
+-	status = ocfs2_meta_lock(inode, NULL, 0);
++	status = ocfs2_inode_lock(inode, NULL, 0);
+ 	if (status < 0) {
+ 		if (status != -ENOENT)
+ 			mlog_errno(status);
+ 		goto bail;
+ 	}
+-	ocfs2_meta_unlock(inode, 0);
++	ocfs2_inode_unlock(inode, 0);
+ bail:
+ 	mlog_exit(status);
  
--static void gfs2_inode_bh(struct gfs2_inode *ip, struct buffer_head *bh)
--{
--	ip->i_cache[0] = bh;
-+	return 0;
- }
+diff --git a/fs/ocfs2/inode.h b/fs/ocfs2/inode.h
+index 70e881c..390a855 100644
+--- a/fs/ocfs2/inode.h
++++ b/fs/ocfs2/inode.h
+@@ -34,8 +34,7 @@ struct ocfs2_inode_info
+ 	u64			ip_blkno;
  
- /**
-@@ -366,7 +369,8 @@ int gfs2_dinode_dealloc(struct gfs2_inode *ip)
- 	if (error)
- 		goto out_rg_gunlock;
+ 	struct ocfs2_lock_res		ip_rw_lockres;
+-	struct ocfs2_lock_res		ip_meta_lockres;
+-	struct ocfs2_lock_res		ip_data_lockres;
++	struct ocfs2_lock_res		ip_inode_lockres;
+ 	struct ocfs2_lock_res		ip_open_lockres;
  
--	gfs2_trans_add_gl(ip->i_gl);
-+	set_bit(GLF_DIRTY, &ip->i_gl->gl_flags);
-+	set_bit(GLF_LFLUSH, &ip->i_gl->gl_flags);
+ 	/* protects allocation changes on this inode. */
+@@ -121,9 +120,10 @@ void ocfs2_delete_inode(struct inode *inode);
+ void ocfs2_drop_inode(struct inode *inode);
  
- 	gfs2_free_di(rgd, ip);
+ /* Flags for ocfs2_iget() */
+-#define OCFS2_FI_FLAG_SYSFILE		0x4
+-#define OCFS2_FI_FLAG_ORPHAN_RECOVERY	0x8
+-struct inode *ocfs2_iget(struct ocfs2_super *osb, u64 feoff, int flags);
++#define OCFS2_FI_FLAG_SYSFILE		0x1
++#define OCFS2_FI_FLAG_ORPHAN_RECOVERY	0x2
++struct inode *ocfs2_iget(struct ocfs2_super *osb, u64 feoff, unsigned flags,
++			 int sysfile_type);
+ int ocfs2_inode_init_private(struct inode *inode);
+ int ocfs2_inode_revalidate(struct dentry *dentry);
+ int ocfs2_populate_inode(struct inode *inode, struct ocfs2_dinode *fe,
+diff --git a/fs/ocfs2/ioctl.c b/fs/ocfs2/ioctl.c
+index 87dcece..5177fba 100644
+--- a/fs/ocfs2/ioctl.c
++++ b/fs/ocfs2/ioctl.c
+@@ -20,6 +20,7 @@
  
-@@ -707,9 +711,10 @@ static int alloc_dinode(struct gfs2_inode *dip, u64 *no_addr, u64 *generation)
- 	struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);
- 	int error;
+ #include "ocfs2_fs.h"
+ #include "ioctl.h"
++#include "resize.h"
  
--	gfs2_alloc_get(dip);
-+	if (gfs2_alloc_get(dip) == NULL)
-+		return -ENOMEM;
+ #include <linux/ext2_fs.h>
  
--	dip->i_alloc.al_requested = RES_DINODE;
-+	dip->i_alloc->al_requested = RES_DINODE;
- 	error = gfs2_inplace_reserve(dip);
- 	if (error)
- 		goto out;
-@@ -855,7 +860,7 @@ static int link_dinode(struct gfs2_inode *dip, const struct qstr *name,
+@@ -27,14 +28,14 @@ static int ocfs2_get_inode_attr(struct inode *inode, unsigned *flags)
+ {
+ 	int status;
  
- 	error = alloc_required = gfs2_diradd_alloc_required(&dip->i_inode, name);
- 	if (alloc_required < 0)
--		goto fail;
-+		goto fail_quota_locks;
- 	if (alloc_required) {
- 		error = gfs2_quota_check(dip, dip->i_inode.i_uid, dip->i_inode.i_gid);
- 		if (error)
-@@ -896,7 +901,7 @@ fail_end_trans:
- 	gfs2_trans_end(sdp);
+-	status = ocfs2_meta_lock(inode, NULL, 0);
++	status = ocfs2_inode_lock(inode, NULL, 0);
+ 	if (status < 0) {
+ 		mlog_errno(status);
+ 		return status;
+ 	}
+ 	ocfs2_get_inode_flags(OCFS2_I(inode));
+ 	*flags = OCFS2_I(inode)->ip_attr;
+-	ocfs2_meta_unlock(inode, 0);
++	ocfs2_inode_unlock(inode, 0);
  
- fail_ipreserv:
--	if (dip->i_alloc.al_rgd)
-+	if (dip->i_alloc->al_rgd)
- 		gfs2_inplace_release(dip);
+ 	mlog_exit(status);
+ 	return status;
+@@ -52,7 +53,7 @@ static int ocfs2_set_inode_attr(struct inode *inode, unsigned flags,
  
- fail_quota_locks:
-@@ -966,7 +971,7 @@ struct inode *gfs2_createi(struct gfs2_holder *ghs, const struct qstr *name,
- 	struct gfs2_inum_host inum = { .no_addr = 0, .no_formal_ino = 0 };
- 	int error;
- 	u64 generation;
--	struct buffer_head *bh=NULL;
-+	struct buffer_head *bh = NULL;
+ 	mutex_lock(&inode->i_mutex);
  
- 	if (!name->len || name->len > GFS2_FNAMESIZE)
- 		return ERR_PTR(-ENAMETOOLONG);
-@@ -1003,8 +1008,6 @@ struct inode *gfs2_createi(struct gfs2_holder *ghs, const struct qstr *name,
- 	if (IS_ERR(inode))
- 		goto fail_gunlock2;
+-	status = ocfs2_meta_lock(inode, &bh, 1);
++	status = ocfs2_inode_lock(inode, &bh, 1);
+ 	if (status < 0) {
+ 		mlog_errno(status);
+ 		goto bail;
+@@ -100,7 +101,7 @@ static int ocfs2_set_inode_attr(struct inode *inode, unsigned flags,
  
--	gfs2_inode_bh(GFS2_I(inode), bh);
--
- 	error = gfs2_inode_refresh(GFS2_I(inode));
- 	if (error)
- 		goto fail_gunlock2;
-@@ -1021,6 +1024,8 @@ struct inode *gfs2_createi(struct gfs2_holder *ghs, const struct qstr *name,
- 	if (error)
- 		goto fail_gunlock2;
+ 	ocfs2_commit_trans(osb, handle);
+ bail_unlock:
+-	ocfs2_meta_unlock(inode, 1);
++	ocfs2_inode_unlock(inode, 1);
+ bail:
+ 	mutex_unlock(&inode->i_mutex);
  
-+	if (bh)
-+		brelse(bh);
- 	if (!inode)
- 		return ERR_PTR(-ENOMEM);
- 	return inode;
-@@ -1032,6 +1037,8 @@ fail_gunlock2:
- fail_gunlock:
- 	gfs2_glock_dq(ghs);
- fail:
-+	if (bh)
-+		brelse(bh);
- 	return ERR_PTR(error);
- }
+@@ -115,8 +116,10 @@ int ocfs2_ioctl(struct inode * inode, struct file * filp,
+ 	unsigned int cmd, unsigned long arg)
+ {
+ 	unsigned int flags;
++	int new_clusters;
+ 	int status;
+ 	struct ocfs2_space_resv sr;
++	struct ocfs2_new_group_input input;
  
-diff --git a/fs/gfs2/inode.h b/fs/gfs2/inode.h
-index 351ac87..d446506 100644
---- a/fs/gfs2/inode.h
-+++ b/fs/gfs2/inode.h
-@@ -20,6 +20,18 @@ static inline int gfs2_is_jdata(const struct gfs2_inode *ip)
- 	return ip->i_di.di_flags & GFS2_DIF_JDATA;
- }
+ 	switch (cmd) {
+ 	case OCFS2_IOC_GETFLAGS:
+@@ -140,6 +143,23 @@ int ocfs2_ioctl(struct inode * inode, struct file * filp,
+ 			return -EFAULT;
  
-+static inline int gfs2_is_writeback(const struct gfs2_inode *ip)
-+{
-+	const struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
-+	return (sdp->sd_args.ar_data == GFS2_DATA_WRITEBACK) && !gfs2_is_jdata(ip);
-+}
+ 		return ocfs2_change_file_space(filp, cmd, &sr);
++	case OCFS2_IOC_GROUP_EXTEND:
++		if (!capable(CAP_SYS_RESOURCE))
++			return -EPERM;
 +
-+static inline int gfs2_is_ordered(const struct gfs2_inode *ip)
-+{
-+	const struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
-+	return (sdp->sd_args.ar_data == GFS2_DATA_ORDERED) && !gfs2_is_jdata(ip);
-+}
++		if (get_user(new_clusters, (int __user *)arg))
++			return -EFAULT;
 +
- static inline int gfs2_is_dir(const struct gfs2_inode *ip)
- {
- 	return S_ISDIR(ip->i_inode.i_mode);
-diff --git a/fs/gfs2/locking/dlm/mount.c b/fs/gfs2/locking/dlm/mount.c
-index 41c5b04..f2efff4 100644
---- a/fs/gfs2/locking/dlm/mount.c
-+++ b/fs/gfs2/locking/dlm/mount.c
-@@ -67,6 +67,11 @@ static int make_args(struct gdlm_ls *ls, char *data_arg, int *nodir)
- 	memset(data, 0, 256);
- 	strncpy(data, data_arg, 255);
- 
-+	if (!strlen(data)) {
-+		log_error("no mount options, (u)mount helpers not installed");
-+		return -EINVAL;
-+	}
++		return ocfs2_group_extend(inode, new_clusters);
++	case OCFS2_IOC_GROUP_ADD:
++	case OCFS2_IOC_GROUP_ADD64:
++		if (!capable(CAP_SYS_RESOURCE))
++			return -EPERM;
 +
- 	for (options = data; (x = strsep(&options, ":")); ) {
- 		if (!*x)
- 			continue;
-diff --git a/fs/gfs2/locking/dlm/plock.c b/fs/gfs2/locking/dlm/plock.c
-index 1f7b038..2ebd374 100644
---- a/fs/gfs2/locking/dlm/plock.c
-+++ b/fs/gfs2/locking/dlm/plock.c
-@@ -89,15 +89,19 @@ int gdlm_plock(void *lockspace, struct lm_lockname *name,
- 	op->info.number		= name->ln_number;
- 	op->info.start		= fl->fl_start;
- 	op->info.end		= fl->fl_end;
--	op->info.owner		= (__u64)(long) fl->fl_owner;
- 	if (fl->fl_lmops && fl->fl_lmops->fl_grant) {
-+		/* fl_owner is lockd which doesn't distinguish
-+		   processes on the nfs client */
-+		op->info.owner	= (__u64) fl->fl_pid;
- 		xop->callback	= fl->fl_lmops->fl_grant;
- 		locks_init_lock(&xop->flc);
- 		locks_copy_lock(&xop->flc, fl);
- 		xop->fl		= fl;
- 		xop->file	= file;
--	} else
-+	} else {
-+		op->info.owner	= (__u64)(long) fl->fl_owner;
- 		xop->callback	= NULL;
-+	}
++		if (copy_from_user(&input, (int __user *) arg, sizeof(input)))
++			return -EFAULT;
++
++		return ocfs2_group_add(inode, &input);
+ 	default:
+ 		return -ENOTTY;
+ 	}
+@@ -162,6 +182,9 @@ long ocfs2_compat_ioctl(struct file *file, unsigned cmd, unsigned long arg)
+ 	case OCFS2_IOC_RESVSP64:
+ 	case OCFS2_IOC_UNRESVSP:
+ 	case OCFS2_IOC_UNRESVSP64:
++	case OCFS2_IOC_GROUP_EXTEND:
++	case OCFS2_IOC_GROUP_ADD:
++	case OCFS2_IOC_GROUP_ADD64:
+ 		break;
+ 	default:
+ 		return -ENOIOCTLCMD;
+diff --git a/fs/ocfs2/journal.c b/fs/ocfs2/journal.c
+index 8d81f6c..f31c7e8 100644
+--- a/fs/ocfs2/journal.c
++++ b/fs/ocfs2/journal.c
+@@ -44,7 +44,6 @@
+ #include "localalloc.h"
+ #include "slot_map.h"
+ #include "super.h"
+-#include "vote.h"
+ #include "sysfile.h"
  
- 	send_op(op);
+ #include "buffer_head_io.h"
+@@ -103,7 +102,7 @@ static int ocfs2_commit_cache(struct ocfs2_super *osb)
+ 	mlog(0, "commit_thread: flushed transaction %lu (%u handles)\n",
+ 	     journal->j_trans_id, flushed);
  
-@@ -203,7 +207,10 @@ int gdlm_punlock(void *lockspace, struct lm_lockname *name,
- 	op->info.number		= name->ln_number;
- 	op->info.start		= fl->fl_start;
- 	op->info.end		= fl->fl_end;
--	op->info.owner		= (__u64)(long) fl->fl_owner;
-+	if (fl->fl_lmops && fl->fl_lmops->fl_grant)
-+		op->info.owner	= (__u64) fl->fl_pid;
-+	else
-+		op->info.owner	= (__u64)(long) fl->fl_owner;
+-	ocfs2_kick_vote_thread(osb);
++	ocfs2_wake_downconvert_thread(osb);
+ 	wake_up(&journal->j_checkpointed);
+ finally:
+ 	mlog_exit(status);
+@@ -314,14 +313,18 @@ int ocfs2_journal_dirty_data(handle_t *handle,
+ 	return err;
+ }
  
- 	send_op(op);
- 	wait_event(recv_wq, (op->done != 0));
-@@ -242,7 +249,10 @@ int gdlm_plock_get(void *lockspace, struct lm_lockname *name,
- 	op->info.number		= name->ln_number;
- 	op->info.start		= fl->fl_start;
- 	op->info.end		= fl->fl_end;
--	op->info.owner		= (__u64)(long) fl->fl_owner;
-+	if (fl->fl_lmops && fl->fl_lmops->fl_grant)
-+		op->info.owner	= (__u64) fl->fl_pid;
-+	else
-+		op->info.owner	= (__u64)(long) fl->fl_owner;
+-#define OCFS2_DEFAULT_COMMIT_INTERVAL 	(HZ * 5)
++#define OCFS2_DEFAULT_COMMIT_INTERVAL 	(HZ * JBD_DEFAULT_MAX_COMMIT_AGE)
  
- 	send_op(op);
- 	wait_event(recv_wq, (op->done != 0));
-diff --git a/fs/gfs2/locking/dlm/sysfs.c b/fs/gfs2/locking/dlm/sysfs.c
-index ae9e6a2..a87b098 100644
---- a/fs/gfs2/locking/dlm/sysfs.c
-+++ b/fs/gfs2/locking/dlm/sysfs.c
-@@ -189,51 +189,39 @@ static struct kobj_type gdlm_ktype = {
- 	.sysfs_ops     = &gdlm_attr_ops,
- };
+ void ocfs2_set_journal_params(struct ocfs2_super *osb)
+ {
+ 	journal_t *journal = osb->journal->j_journal;
++	unsigned long commit_interval = OCFS2_DEFAULT_COMMIT_INTERVAL;
++
++	if (osb->osb_commit_interval)
++		commit_interval = osb->osb_commit_interval;
  
--static struct kset gdlm_kset = {
--	.ktype  = &gdlm_ktype,
--};
-+static struct kset *gdlm_kset;
+ 	spin_lock(&journal->j_state_lock);
+-	journal->j_commit_interval = OCFS2_DEFAULT_COMMIT_INTERVAL;
++	journal->j_commit_interval = commit_interval;
+ 	if (osb->s_mount_opt & OCFS2_MOUNT_BARRIER)
+ 		journal->j_flags |= JFS_BARRIER;
+ 	else
+@@ -337,7 +340,7 @@ int ocfs2_journal_init(struct ocfs2_journal *journal, int *dirty)
+ 	struct ocfs2_dinode *di = NULL;
+ 	struct buffer_head *bh = NULL;
+ 	struct ocfs2_super *osb;
+-	int meta_lock = 0;
++	int inode_lock = 0;
  
- int gdlm_kobject_setup(struct gdlm_ls *ls, struct kobject *fskobj)
- {
- 	int error;
+ 	mlog_entry_void();
  
--	error = kobject_set_name(&ls->kobj, "%s", "lock_module");
--	if (error) {
--		log_error("can't set kobj name %d", error);
--		return error;
--	}
--
--	ls->kobj.kset = &gdlm_kset;
--	ls->kobj.ktype = &gdlm_ktype;
--	ls->kobj.parent = fskobj;
--
--	error = kobject_register(&ls->kobj);
-+	ls->kobj.kset = gdlm_kset;
-+	error = kobject_init_and_add(&ls->kobj, &gdlm_ktype, fskobj,
-+				     "lock_module");
- 	if (error)
- 		log_error("can't register kobj %d", error);
-+	kobject_uevent(&ls->kobj, KOBJ_ADD);
+@@ -367,14 +370,14 @@ int ocfs2_journal_init(struct ocfs2_journal *journal, int *dirty)
+ 	/* Skip recovery waits here - journal inode metadata never
+ 	 * changes in a live cluster so it can be considered an
+ 	 * exception to the rule. */
+-	status = ocfs2_meta_lock_full(inode, &bh, 1, OCFS2_META_LOCK_RECOVERY);
++	status = ocfs2_inode_lock_full(inode, &bh, 1, OCFS2_META_LOCK_RECOVERY);
+ 	if (status < 0) {
+ 		if (status != -ERESTARTSYS)
+ 			mlog(ML_ERROR, "Could not get lock on journal!\n");
+ 		goto done;
+ 	}
  
- 	return error;
- }
+-	meta_lock = 1;
++	inode_lock = 1;
+ 	di = (struct ocfs2_dinode *)bh->b_data;
  
- void gdlm_kobject_release(struct gdlm_ls *ls)
- {
--	kobject_unregister(&ls->kobj);
-+	kobject_put(&ls->kobj);
- }
+ 	if (inode->i_size <  OCFS2_MIN_JOURNAL_SIZE) {
+@@ -414,8 +417,8 @@ int ocfs2_journal_init(struct ocfs2_journal *journal, int *dirty)
+ 	status = 0;
+ done:
+ 	if (status < 0) {
+-		if (meta_lock)
+-			ocfs2_meta_unlock(inode, 1);
++		if (inode_lock)
++			ocfs2_inode_unlock(inode, 1);
+ 		if (bh != NULL)
+ 			brelse(bh);
+ 		if (inode) {
+@@ -544,7 +547,7 @@ void ocfs2_journal_shutdown(struct ocfs2_super *osb)
+ 	OCFS2_I(inode)->ip_open_count--;
  
- int gdlm_sysfs_init(void)
- {
--	int error;
--
--	kobject_set_name(&gdlm_kset.kobj, "lock_dlm");
--	kobj_set_kset_s(&gdlm_kset, kernel_subsys);
--	error = kset_register(&gdlm_kset);
--	if (error)
--		printk("lock_dlm: cannot register kset %d\n", error);
--
--	return error;
-+	gdlm_kset = kset_create_and_add("lock_dlm", NULL, kernel_kobj);
-+	if (!gdlm_kset) {
-+		printk(KERN_WARNING "%s: can not create kset\n", __FUNCTION__);
-+		return -ENOMEM;
-+	}
-+	return 0;
- }
+ 	/* unlock our journal */
+-	ocfs2_meta_unlock(inode, 1);
++	ocfs2_inode_unlock(inode, 1);
  
- void gdlm_sysfs_exit(void)
- {
--	kset_unregister(&gdlm_kset);
-+	kset_unregister(gdlm_kset);
- }
+ 	brelse(journal->j_bh);
+ 	journal->j_bh = NULL;
+@@ -883,8 +886,8 @@ restart:
+ 	ocfs2_super_unlock(osb, 1);
  
-diff --git a/fs/gfs2/locking/dlm/thread.c b/fs/gfs2/locking/dlm/thread.c
-index bd938f0..521694f 100644
---- a/fs/gfs2/locking/dlm/thread.c
-+++ b/fs/gfs2/locking/dlm/thread.c
-@@ -273,18 +273,13 @@ static int gdlm_thread(void *data, int blist)
- 	struct gdlm_ls *ls = (struct gdlm_ls *) data;
- 	struct gdlm_lock *lp = NULL;
- 	uint8_t complete, blocking, submit, drop;
--	DECLARE_WAITQUEUE(wait, current);
+ 	/* We always run recovery on our own orphan dir - the dead
+-	 * node(s) may have voted "no" on an inode delete earlier. A
+-	 * revote is therefore required. */
++	 * node(s) may have disallowd a previos inode delete. Re-processing
++	 * is therefore required. */
+ 	ocfs2_queue_recovery_completion(osb->journal, osb->slot_num, NULL,
+ 					NULL);
  
- 	/* Only thread1 is allowed to do blocking callbacks since gfs
- 	   may wait for a completion callback within a blocking cb. */
+@@ -973,9 +976,9 @@ static int ocfs2_replay_journal(struct ocfs2_super *osb,
+ 	}
+ 	SET_INODE_JOURNAL(inode);
  
- 	while (!kthread_should_stop()) {
--		set_current_state(TASK_INTERRUPTIBLE);
--		add_wait_queue(&ls->thread_wait, &wait);
--		if (no_work(ls, blist))
--			schedule();
--		remove_wait_queue(&ls->thread_wait, &wait);
--		set_current_state(TASK_RUNNING);
-+		wait_event_interruptible(ls->thread_wait,
-+				!no_work(ls, blist) || kthread_should_stop());
+-	status = ocfs2_meta_lock_full(inode, &bh, 1, OCFS2_META_LOCK_RECOVERY);
++	status = ocfs2_inode_lock_full(inode, &bh, 1, OCFS2_META_LOCK_RECOVERY);
+ 	if (status < 0) {
+-		mlog(0, "status returned from ocfs2_meta_lock=%d\n", status);
++		mlog(0, "status returned from ocfs2_inode_lock=%d\n", status);
+ 		if (status != -ERESTARTSYS)
+ 			mlog(ML_ERROR, "Could not lock journal!\n");
+ 		goto done;
+@@ -1047,7 +1050,7 @@ static int ocfs2_replay_journal(struct ocfs2_super *osb,
+ done:
+ 	/* drop the lock on this nodes journal */
+ 	if (got_lock)
+-		ocfs2_meta_unlock(inode, 1);
++		ocfs2_inode_unlock(inode, 1);
  
- 		complete = blocking = submit = drop = 0;
+ 	if (inode)
+ 		iput(inode);
+@@ -1162,14 +1165,14 @@ static int ocfs2_trylock_journal(struct ocfs2_super *osb,
+ 	SET_INODE_JOURNAL(inode);
  
-diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c
-index 7df7024..161ab6f 100644
---- a/fs/gfs2/log.c
-+++ b/fs/gfs2/log.c
-@@ -1,6 +1,6 @@
- /*
-  * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
-- * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
-+ * Copyright (C) 2004-2007 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
-@@ -16,6 +16,8 @@
- #include <linux/crc32.h>
- #include <linux/lm_interface.h>
- #include <linux/delay.h>
-+#include <linux/kthread.h>
-+#include <linux/freezer.h>
+ 	flags = OCFS2_META_LOCK_RECOVERY | OCFS2_META_LOCK_NOQUEUE;
+-	status = ocfs2_meta_lock_full(inode, NULL, 1, flags);
++	status = ocfs2_inode_lock_full(inode, NULL, 1, flags);
+ 	if (status < 0) {
+ 		if (status != -EAGAIN)
+ 			mlog_errno(status);
+ 		goto bail;
+ 	}
  
- #include "gfs2.h"
- #include "incore.h"
-@@ -68,14 +70,12 @@ unsigned int gfs2_struct2blk(struct gfs2_sbd *sdp, unsigned int nstruct,
-  *
-  */
+-	ocfs2_meta_unlock(inode, 1);
++	ocfs2_inode_unlock(inode, 1);
+ bail:
+ 	if (inode)
+ 		iput(inode);
+@@ -1241,7 +1244,7 @@ static int ocfs2_orphan_filldir(void *priv, const char *name, int name_len,
  
--void gfs2_remove_from_ail(struct address_space *mapping, struct gfs2_bufdata *bd)
-+void gfs2_remove_from_ail(struct gfs2_bufdata *bd)
- {
- 	bd->bd_ail = NULL;
- 	list_del_init(&bd->bd_ail_st_list);
- 	list_del_init(&bd->bd_ail_gl_list);
- 	atomic_dec(&bd->bd_gl->gl_ail_count);
--	if (mapping)
--		gfs2_meta_cache_flush(GFS2_I(mapping->host));
- 	brelse(bd->bd_bh);
- }
+ 	/* Skip bad inodes so that recovery can continue */
+ 	iter = ocfs2_iget(p->osb, ino,
+-			  OCFS2_FI_FLAG_ORPHAN_RECOVERY);
++			  OCFS2_FI_FLAG_ORPHAN_RECOVERY, 0);
+ 	if (IS_ERR(iter))
+ 		return 0;
  
-@@ -92,8 +92,6 @@ static void gfs2_ail1_start_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai)
- 	struct buffer_head *bh;
- 	int retry;
+@@ -1277,7 +1280,7 @@ static int ocfs2_queue_orphans(struct ocfs2_super *osb,
+ 	}	
  
--	BUG_ON(!spin_is_locked(&sdp->sd_log_lock));
--
- 	do {
- 		retry = 0;
+ 	mutex_lock(&orphan_dir_inode->i_mutex);
+-	status = ocfs2_meta_lock(orphan_dir_inode, NULL, 0);
++	status = ocfs2_inode_lock(orphan_dir_inode, NULL, 0);
+ 	if (status < 0) {
+ 		mlog_errno(status);
+ 		goto out;
+@@ -1293,7 +1296,7 @@ static int ocfs2_queue_orphans(struct ocfs2_super *osb,
+ 	*head = priv.head;
  
-@@ -210,7 +208,7 @@ static void gfs2_ail1_start(struct gfs2_sbd *sdp, int flags)
- 	gfs2_log_unlock(sdp);
- }
+ out_cluster:
+-	ocfs2_meta_unlock(orphan_dir_inode, 0);
++	ocfs2_inode_unlock(orphan_dir_inode, 0);
+ out:
+ 	mutex_unlock(&orphan_dir_inode->i_mutex);
+ 	iput(orphan_dir_inode);
+@@ -1380,10 +1383,10 @@ static int ocfs2_recover_orphans(struct ocfs2_super *osb,
+ 		iter = oi->ip_next_orphan;
  
--int gfs2_ail1_empty(struct gfs2_sbd *sdp, int flags)
-+static int gfs2_ail1_empty(struct gfs2_sbd *sdp, int flags)
- {
- 	struct gfs2_ail *ai, *s;
- 	int ret;
-@@ -248,7 +246,7 @@ static void gfs2_ail2_empty_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai)
- 		bd = list_entry(head->prev, struct gfs2_bufdata,
- 				bd_ail_st_list);
- 		gfs2_assert(sdp, bd->bd_ail == ai);
--		gfs2_remove_from_ail(bd->bd_bh->b_page->mapping, bd);
-+		gfs2_remove_from_ail(bd);
- 	}
- }
+ 		spin_lock(&oi->ip_lock);
+-		/* Delete voting may have set these on the assumption
+-		 * that the other node would wipe them successfully.
+-		 * If they are still in the node's orphan dir, we need
+-		 * to reset that state. */
++		/* The remote delete code may have set these on the
++		 * assumption that the other node would wipe them
++		 * successfully.  If they are still in the node's
++		 * orphan dir, we need to reset that state. */
+ 		oi->ip_flags &= ~(OCFS2_INODE_DELETED|OCFS2_INODE_SKIP_DELETE);
  
-@@ -303,7 +301,7 @@ int gfs2_log_reserve(struct gfs2_sbd *sdp, unsigned int blks)
+ 		/* Set the proper information to get us going into
+diff --git a/fs/ocfs2/journal.h b/fs/ocfs2/journal.h
+index 4b32e09..220f3e8 100644
+--- a/fs/ocfs2/journal.h
++++ b/fs/ocfs2/journal.h
+@@ -278,6 +278,12 @@ int                  ocfs2_journal_dirty_data(handle_t *handle,
+ /* simple file updates like chmod, etc. */
+ #define OCFS2_INODE_UPDATE_CREDITS 1
  
- 	mutex_lock(&sdp->sd_log_reserve_mutex);
- 	gfs2_log_lock(sdp);
--	while(sdp->sd_log_blks_free <= (blks + reserved_blks)) {
-+	while(atomic_read(&sdp->sd_log_blks_free) <= (blks + reserved_blks)) {
- 		gfs2_log_unlock(sdp);
- 		gfs2_ail1_empty(sdp, 0);
- 		gfs2_log_flush(sdp, NULL);
-@@ -312,7 +310,7 @@ int gfs2_log_reserve(struct gfs2_sbd *sdp, unsigned int blks)
- 			gfs2_ail1_start(sdp, 0);
- 		gfs2_log_lock(sdp);
- 	}
--	sdp->sd_log_blks_free -= blks;
-+	atomic_sub(blks, &sdp->sd_log_blks_free);
- 	gfs2_log_unlock(sdp);
- 	mutex_unlock(&sdp->sd_log_reserve_mutex);
++/* group extend. inode update and last group update. */
++#define OCFS2_GROUP_EXTEND_CREDITS	(OCFS2_INODE_UPDATE_CREDITS + 1)
++
++/* group add. inode update and the new group update. */
++#define OCFS2_GROUP_ADD_CREDITS	(OCFS2_INODE_UPDATE_CREDITS + 1)
++
+ /* get one bit out of a suballocator: dinode + group descriptor +
+  * prev. group desc. if we relink. */
+ #define OCFS2_SUBALLOC_ALLOC (3)
+diff --git a/fs/ocfs2/localalloc.c b/fs/ocfs2/localalloc.c
+index 58ea88b..add1ffd 100644
+--- a/fs/ocfs2/localalloc.c
++++ b/fs/ocfs2/localalloc.c
+@@ -75,18 +75,12 @@ static int ocfs2_local_alloc_new_window(struct ocfs2_super *osb,
+ static int ocfs2_local_alloc_slide_window(struct ocfs2_super *osb,
+ 					  struct inode *local_alloc_inode);
  
-@@ -332,27 +330,23 @@ void gfs2_log_release(struct gfs2_sbd *sdp, unsigned int blks)
+-/*
+- * Determine how large our local alloc window should be, in bits.
+- *
+- * These values (and the behavior in ocfs2_alloc_should_use_local) have
+- * been chosen so that most allocations, including new block groups go
+- * through local alloc.
+- */
+ static inline int ocfs2_local_alloc_window_bits(struct ocfs2_super *osb)
  {
+-	BUG_ON(osb->s_clustersize_bits < 12);
++	BUG_ON(osb->s_clustersize_bits > 20);
  
- 	gfs2_log_lock(sdp);
--	sdp->sd_log_blks_free += blks;
-+	atomic_add(blks, &sdp->sd_log_blks_free);
- 	gfs2_assert_withdraw(sdp,
--			     sdp->sd_log_blks_free <= sdp->sd_jdesc->jd_blocks);
-+			     atomic_read(&sdp->sd_log_blks_free) <= sdp->sd_jdesc->jd_blocks);
- 	gfs2_log_unlock(sdp);
- 	up_read(&sdp->sd_log_flush_lock);
+-	return 2048 >> (osb->s_clustersize_bits - 12);
++	/* Size local alloc windows by the megabyte */
++	return osb->local_alloc_size << (20 - osb->s_clustersize_bits);
  }
  
- static u64 log_bmap(struct gfs2_sbd *sdp, unsigned int lbn)
+ /*
+@@ -96,18 +90,23 @@ static inline int ocfs2_local_alloc_window_bits(struct ocfs2_super *osb)
+ int ocfs2_alloc_should_use_local(struct ocfs2_super *osb, u64 bits)
  {
--	struct inode *inode = sdp->sd_jdesc->jd_inode;
--	int error;
--	struct buffer_head bh_map = { .b_state = 0, .b_blocknr = 0 };
--
--	bh_map.b_size = 1 << inode->i_blkbits;
--	error = gfs2_block_map(inode, lbn, 0, &bh_map);
--	if (error || !bh_map.b_blocknr)
--		printk(KERN_INFO "error=%d, dbn=%llu lbn=%u", error,
--		       (unsigned long long)bh_map.b_blocknr, lbn);
--	gfs2_assert_withdraw(sdp, !error && bh_map.b_blocknr);
--
--	return bh_map.b_blocknr;
-+	struct gfs2_journal_extent *je;
-+
-+	list_for_each_entry(je, &sdp->sd_jdesc->extent_list, extent_list) {
-+		if (lbn >= je->lblock && lbn < je->lblock + je->blocks)
-+			return je->dblock + lbn - je->lblock;
-+	}
-+
-+	return -1;
- }
+ 	int la_bits = ocfs2_local_alloc_window_bits(osb);
++	int ret = 0;
  
- /**
-@@ -561,8 +555,8 @@ static void log_pull_tail(struct gfs2_sbd *sdp, unsigned int new_tail)
- 	ail2_empty(sdp, new_tail);
+ 	if (osb->local_alloc_state != OCFS2_LA_ENABLED)
+-		return 0;
++		goto bail;
  
- 	gfs2_log_lock(sdp);
--	sdp->sd_log_blks_free += dist;
--	gfs2_assert_withdraw(sdp, sdp->sd_log_blks_free <= sdp->sd_jdesc->jd_blocks);
-+	atomic_add(dist, &sdp->sd_log_blks_free);
-+	gfs2_assert_withdraw(sdp, atomic_read(&sdp->sd_log_blks_free) <= sdp->sd_jdesc->jd_blocks);
- 	gfs2_log_unlock(sdp);
+ 	/* la_bits should be at least twice the size (in clusters) of
+ 	 * a new block group. We want to be sure block group
+ 	 * allocations go through the local alloc, so allow an
+ 	 * allocation to take up to half the bitmap. */
+ 	if (bits > (la_bits / 2))
+-		return 0;
++		goto bail;
  
- 	sdp->sd_log_tail = new_tail;
-@@ -652,7 +646,7 @@ static void gfs2_ordered_write(struct gfs2_sbd *sdp)
- 		get_bh(bh);
- 		gfs2_log_unlock(sdp);
- 		lock_buffer(bh);
--		if (test_clear_buffer_dirty(bh)) {
-+		if (buffer_mapped(bh) && test_clear_buffer_dirty(bh)) {
- 			bh->b_end_io = end_buffer_write_sync;
- 			submit_bh(WRITE, bh);
- 		} else {
-@@ -694,20 +688,16 @@ static void gfs2_ordered_wait(struct gfs2_sbd *sdp)
-  *
-  */
+-	return 1;
++	ret = 1;
++bail:
++	mlog(0, "state=%d, bits=%llu, la_bits=%d, ret=%d\n",
++	     osb->local_alloc_state, (unsigned long long)bits, la_bits, ret);
++	return ret;
+ }
  
--void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl)
-+void __gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl)
- {
- 	struct gfs2_ail *ai;
+ int ocfs2_load_local_alloc(struct ocfs2_super *osb)
+@@ -121,6 +120,19 @@ int ocfs2_load_local_alloc(struct ocfs2_super *osb)
  
- 	down_write(&sdp->sd_log_flush_lock);
+ 	mlog_entry_void();
  
--	if (gl) {
--		gfs2_log_lock(sdp);
--		if (list_empty(&gl->gl_le.le_list)) {
--			gfs2_log_unlock(sdp);
--			up_write(&sdp->sd_log_flush_lock);
--			return;
--		}
--		gfs2_log_unlock(sdp);
-+	/* Log might have been flushed while we waited for the flush lock */
-+	if (gl && !test_bit(GLF_LFLUSH, &gl->gl_flags)) {
-+		up_write(&sdp->sd_log_flush_lock);
-+		return;
- 	}
++	if (ocfs2_mount_local(osb))
++		goto bail;
++
++	if (osb->local_alloc_size == 0)
++		goto bail;
++
++	if (ocfs2_local_alloc_window_bits(osb) >= 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;
++	}
++
+ 	/* read the alloc off disk */
+ 	inode = ocfs2_get_system_file_inode(osb, LOCAL_ALLOC_SYSTEM_INODE,
+ 					    osb->slot_num);
+@@ -181,6 +193,9 @@ bail:
+ 	if (inode)
+ 		iput(inode);
  
- 	ai = kzalloc(sizeof(struct gfs2_ail), GFP_NOFS | __GFP_NOFAIL);
-@@ -739,7 +729,7 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl)
- 		log_flush_commit(sdp);
- 	else if (sdp->sd_log_tail != current_tail(sdp) && !sdp->sd_log_idle){
- 		gfs2_log_lock(sdp);
--		sdp->sd_log_blks_free--; /* Adjust for unreserved buffer */
-+		atomic_dec(&sdp->sd_log_blks_free); /* Adjust for unreserved buffer */
- 		gfs2_log_unlock(sdp);
- 		log_write_header(sdp, 0, PULL);
- 	}
-@@ -767,7 +757,7 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl)
- static void log_refund(struct gfs2_sbd *sdp, struct gfs2_trans *tr)
- {
- 	unsigned int reserved;
--	unsigned int old;
-+	unsigned int unused;
++	mlog(0, "Local alloc window bits = %d\n",
++	     ocfs2_local_alloc_window_bits(osb));
++
+ 	mlog_exit(status);
+ 	return status;
+ }
+@@ -231,7 +246,7 @@ void ocfs2_shutdown_local_alloc(struct ocfs2_super *osb)
  
- 	gfs2_log_lock(sdp);
+ 	mutex_lock(&main_bm_inode->i_mutex);
  
-@@ -779,14 +769,11 @@ static void log_refund(struct gfs2_sbd *sdp, struct gfs2_trans *tr)
- 	sdp->sd_log_commited_revoke += tr->tr_num_revoke - tr->tr_num_revoke_rm;
- 	gfs2_assert_withdraw(sdp, ((int)sdp->sd_log_commited_revoke) >= 0);
- 	reserved = calc_reserved(sdp);
--	old = sdp->sd_log_blks_free;
--	sdp->sd_log_blks_free += tr->tr_reserved -
--				 (reserved - sdp->sd_log_blks_reserved);
--
--	gfs2_assert_withdraw(sdp, sdp->sd_log_blks_free >= old);
--	gfs2_assert_withdraw(sdp, sdp->sd_log_blks_free <=
-+	unused = sdp->sd_log_blks_reserved - reserved + tr->tr_reserved;
-+	gfs2_assert_withdraw(sdp, unused >= 0);
-+	atomic_add(unused, &sdp->sd_log_blks_free);
-+	gfs2_assert_withdraw(sdp, atomic_read(&sdp->sd_log_blks_free) <=
- 			     sdp->sd_jdesc->jd_blocks);
--
- 	sdp->sd_log_blks_reserved = reserved;
+-	status = ocfs2_meta_lock(main_bm_inode, &main_bm_bh, 1);
++	status = ocfs2_inode_lock(main_bm_inode, &main_bm_bh, 1);
+ 	if (status < 0) {
+ 		mlog_errno(status);
+ 		goto out_mutex;
+@@ -286,7 +301,7 @@ out_unlock:
+ 	if (main_bm_bh)
+ 		brelse(main_bm_bh);
  
- 	gfs2_log_unlock(sdp);
-@@ -825,7 +812,6 @@ void gfs2_log_shutdown(struct gfs2_sbd *sdp)
- 	down_write(&sdp->sd_log_flush_lock);
+-	ocfs2_meta_unlock(main_bm_inode, 1);
++	ocfs2_inode_unlock(main_bm_inode, 1);
  
- 	gfs2_assert_withdraw(sdp, !sdp->sd_log_blks_reserved);
--	gfs2_assert_withdraw(sdp, !sdp->sd_log_num_gl);
- 	gfs2_assert_withdraw(sdp, !sdp->sd_log_num_buf);
- 	gfs2_assert_withdraw(sdp, !sdp->sd_log_num_revoke);
- 	gfs2_assert_withdraw(sdp, !sdp->sd_log_num_rg);
-@@ -838,7 +824,7 @@ void gfs2_log_shutdown(struct gfs2_sbd *sdp)
- 	log_write_header(sdp, GFS2_LOG_HEAD_UNMOUNT,
- 			 (sdp->sd_log_tail == current_tail(sdp)) ? 0 : PULL);
+ out_mutex:
+ 	mutex_unlock(&main_bm_inode->i_mutex);
+@@ -399,7 +414,7 @@ int ocfs2_complete_local_alloc_recovery(struct ocfs2_super *osb,
  
--	gfs2_assert_warn(sdp, sdp->sd_log_blks_free == sdp->sd_jdesc->jd_blocks);
-+	gfs2_assert_warn(sdp, atomic_read(&sdp->sd_log_blks_free) == sdp->sd_jdesc->jd_blocks);
- 	gfs2_assert_warn(sdp, sdp->sd_log_head == sdp->sd_log_tail);
- 	gfs2_assert_warn(sdp, list_empty(&sdp->sd_ail2_list));
+ 	mutex_lock(&main_bm_inode->i_mutex);
  
-@@ -866,3 +852,42 @@ void gfs2_meta_syncfs(struct gfs2_sbd *sdp)
+-	status = ocfs2_meta_lock(main_bm_inode, &main_bm_bh, 1);
++	status = ocfs2_inode_lock(main_bm_inode, &main_bm_bh, 1);
+ 	if (status < 0) {
+ 		mlog_errno(status);
+ 		goto out_mutex;
+@@ -424,7 +439,7 @@ int ocfs2_complete_local_alloc_recovery(struct ocfs2_super *osb,
+ 	ocfs2_commit_trans(osb, handle);
+ 
+ out_unlock:
+-	ocfs2_meta_unlock(main_bm_inode, 1);
++	ocfs2_inode_unlock(main_bm_inode, 1);
+ 
+ out_mutex:
+ 	mutex_unlock(&main_bm_inode->i_mutex);
+@@ -521,6 +536,9 @@ bail:
+ 		iput(local_alloc_inode);
  	}
- }
  
++	mlog(0, "bits=%d, slot=%d, ret=%d\n", bits_wanted, osb->slot_num,
++	     status);
 +
-+/**
-+ * gfs2_logd - Update log tail as Active Items get flushed to in-place blocks
-+ * @sdp: Pointer to GFS2 superblock
+ 	mlog_exit(status);
+ 	return status;
+ }
+diff --git a/fs/ocfs2/locks.c b/fs/ocfs2/locks.c
+new file mode 100644
+index 0000000..203f871
+--- /dev/null
++++ b/fs/ocfs2/locks.c
+@@ -0,0 +1,125 @@
++/* -*- mode: c; c-basic-offset: 8; -*-
++ * vim: noexpandtab sw=8 ts=8 sts=0:
 + *
-+ * Also, periodically check to make sure that we're using the most recent
-+ * journal index.
++ * locks.c
++ *
++ * Userspace file locking support
++ *
++ * Copyright (C) 2007 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.
 + */
 +
-+int gfs2_logd(void *data)
++#include <linux/fs.h>
++
++#define MLOG_MASK_PREFIX ML_INODE
++#include <cluster/masklog.h>
++
++#include "ocfs2.h"
++
++#include "dlmglue.h"
++#include "file.h"
++#include "locks.h"
++
++static int ocfs2_do_flock(struct file *file, struct inode *inode,
++			  int cmd, struct file_lock *fl)
 +{
-+	struct gfs2_sbd *sdp = data;
-+	unsigned long t;
-+	int need_flush;
++	int ret = 0, level = 0, trylock = 0;
++	struct ocfs2_file_private *fp = file->private_data;
++	struct ocfs2_lock_res *lockres = &fp->fp_flock;
 +
-+	while (!kthread_should_stop()) {
-+		/* Advance the log tail */
++	if (fl->fl_type == F_WRLCK)
++		level = 1;
++	if (!IS_SETLKW(cmd))
++		trylock = 1;
 +
-+		t = sdp->sd_log_flush_time +
-+		    gfs2_tune_get(sdp, gt_log_flush_secs) * HZ;
++	mutex_lock(&fp->fp_mutex);
 +
-+		gfs2_ail1_empty(sdp, DIO_ALL);
-+		gfs2_log_lock(sdp);
-+		need_flush = sdp->sd_log_num_buf > gfs2_tune_get(sdp, gt_incore_log_blocks);
-+		gfs2_log_unlock(sdp);
-+		if (need_flush || time_after_eq(jiffies, t)) {
-+			gfs2_log_flush(sdp, NULL);
-+			sdp->sd_log_flush_time = jiffies;
-+		}
++	if (lockres->l_flags & OCFS2_LOCK_ATTACHED &&
++	    lockres->l_level > LKM_NLMODE) {
++		int old_level = 0;
 +
-+		t = gfs2_tune_get(sdp, gt_logd_secs) * HZ;
-+		if (freezing(current))
-+			refrigerator();
-+		schedule_timeout_interruptible(t);
++		if (lockres->l_level == LKM_EXMODE)
++			old_level = 1;
++
++		if (level == old_level)
++			goto out;
++
++		/*
++		 * Converting an existing lock is not guaranteed to be
++		 * atomic, so we can get away with simply unlocking
++		 * here and allowing the lock code to try at the new
++		 * level.
++		 */
++
++		flock_lock_file_wait(file,
++				     &(struct file_lock){.fl_type = F_UNLCK});
++
++		ocfs2_file_unlock(file);
 +	}
 +
-+	return 0;
++	ret = ocfs2_file_lock(file, level, trylock);
++	if (ret) {
++		if (ret == -EAGAIN && trylock)
++			ret = -EWOULDBLOCK;
++		else
++			mlog_errno(ret);
++		goto out;
++	}
++
++	ret = flock_lock_file_wait(file, fl);
++
++out:
++	mutex_unlock(&fp->fp_mutex);
++
++	return ret;
 +}
 +
-diff --git a/fs/gfs2/log.h b/fs/gfs2/log.h
-index dae2824..7711528 100644
---- a/fs/gfs2/log.h
-+++ b/fs/gfs2/log.h
-@@ -48,8 +48,6 @@ static inline void gfs2_log_pointers_init(struct gfs2_sbd *sdp,
- unsigned int gfs2_struct2blk(struct gfs2_sbd *sdp, unsigned int nstruct,
- 			    unsigned int ssize);
- 
--int gfs2_ail1_empty(struct gfs2_sbd *sdp, int flags);
--
- int gfs2_log_reserve(struct gfs2_sbd *sdp, unsigned int blks);
- void gfs2_log_release(struct gfs2_sbd *sdp, unsigned int blks);
- void gfs2_log_incr_head(struct gfs2_sbd *sdp);
-@@ -57,11 +55,19 @@ void gfs2_log_incr_head(struct gfs2_sbd *sdp);
- struct buffer_head *gfs2_log_get_buf(struct gfs2_sbd *sdp);
- struct buffer_head *gfs2_log_fake_buf(struct gfs2_sbd *sdp,
- 				      struct buffer_head *real);
--void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl);
-+void __gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl);
++static int ocfs2_do_funlock(struct file *file, int cmd, struct file_lock *fl)
++{
++	int ret;
++	struct ocfs2_file_private *fp = file->private_data;
 +
-+static inline void gfs2_log_flush(struct gfs2_sbd *sbd, struct gfs2_glock *gl)
++	mutex_lock(&fp->fp_mutex);
++	ocfs2_file_unlock(file);
++	ret = flock_lock_file_wait(file, fl);
++	mutex_unlock(&fp->fp_mutex);
++
++	return ret;
++}
++
++/*
++ * Overall flow of ocfs2_flock() was influenced by gfs2_flock().
++ */
++int ocfs2_flock(struct file *file, int cmd, struct file_lock *fl)
 +{
-+	if (!gl || test_bit(GLF_LFLUSH, &gl->gl_flags))
-+		__gfs2_log_flush(sbd, gl);
++	struct inode *inode = file->f_mapping->host;
++	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
++
++	if (!(fl->fl_flags & FL_FLOCK))
++		return -ENOLCK;
++	if (__mandatory_lock(inode))
++		return -ENOLCK;
++
++	if ((osb->s_mount_opt & OCFS2_MOUNT_LOCALFLOCKS) ||
++	    ocfs2_mount_local(osb))
++		return flock_lock_file_wait(file, fl);
++
++	if (fl->fl_type == F_UNLCK)
++		return ocfs2_do_funlock(file, cmd, fl);
++	else
++		return ocfs2_do_flock(file, inode, cmd, fl);
 +}
+diff --git a/fs/ocfs2/locks.h b/fs/ocfs2/locks.h
+new file mode 100644
+index 0000000..9743ef2
+--- /dev/null
++++ b/fs/ocfs2/locks.h
+@@ -0,0 +1,31 @@
++/* -*- mode: c; c-basic-offset: 8; -*-
++ * vim: noexpandtab sw=8 ts=8 sts=0:
++ *
++ * locks.h
++ *
++ * Function prototypes for Userspace file locking support
++ *
++ * Copyright (C) 2002, 2004 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.
++ */
 +
- void gfs2_log_commit(struct gfs2_sbd *sdp, struct gfs2_trans *trans);
--void gfs2_remove_from_ail(struct address_space *mapping, struct gfs2_bufdata *bd);
-+void gfs2_remove_from_ail(struct gfs2_bufdata *bd);
- 
- void gfs2_log_shutdown(struct gfs2_sbd *sdp);
- void gfs2_meta_syncfs(struct gfs2_sbd *sdp);
-+int gfs2_logd(void *data);
- 
- #endif /* __LOG_DOT_H__ */
-diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c
-index 6c27cea..fae59d6 100644
---- a/fs/gfs2/lops.c
-+++ b/fs/gfs2/lops.c
-@@ -87,6 +87,7 @@ static void gfs2_unpin(struct gfs2_sbd *sdp, struct buffer_head *bh,
- 	}
- 	bd->bd_ail = ai;
- 	list_add(&bd->bd_ail_st_list, &ai->ai_ail1_list);
-+	clear_bit(GLF_LFLUSH, &bd->bd_gl->gl_flags);
- 	gfs2_log_unlock(sdp);
- 	unlock_buffer(bh);
- }
-@@ -124,49 +125,6 @@ static struct buffer_head *gfs2_get_log_desc(struct gfs2_sbd *sdp, u32 ld_type)
- 	return bh;
- }
++#ifndef OCFS2_LOCKS_H
++#define OCFS2_LOCKS_H
++
++int ocfs2_flock(struct file *file, int cmd, struct file_lock *fl);
++
++#endif /* OCFS2_LOCKS_H */
+diff --git a/fs/ocfs2/mmap.c b/fs/ocfs2/mmap.c
+index 9875615..3dc18d6 100644
+--- a/fs/ocfs2/mmap.c
++++ b/fs/ocfs2/mmap.c
+@@ -168,7 +168,7 @@ static int ocfs2_page_mkwrite(struct vm_area_struct *vma, struct page *page)
+ 	 * node. Taking the data lock will also ensure that we don't
+ 	 * attempt page truncation as part of a downconvert.
+ 	 */
+-	ret = ocfs2_meta_lock(inode, &di_bh, 1);
++	ret = ocfs2_inode_lock(inode, &di_bh, 1);
+ 	if (ret < 0) {
+ 		mlog_errno(ret);
+ 		goto out;
+@@ -181,21 +181,12 @@ static int ocfs2_page_mkwrite(struct vm_area_struct *vma, struct page *page)
+ 	 */
+ 	down_write(&OCFS2_I(inode)->ip_alloc_sem);
  
--static void __glock_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le)
--{
--	struct gfs2_glock *gl;
--	struct gfs2_trans *tr = current->journal_info;
--
--	tr->tr_touched = 1;
--
--	gl = container_of(le, struct gfs2_glock, gl_le);
--	if (gfs2_assert_withdraw(sdp, gfs2_glock_is_held_excl(gl)))
--		return;
--
--	if (!list_empty(&le->le_list))
--		return;
--
--	gfs2_glock_hold(gl);
--	set_bit(GLF_DIRTY, &gl->gl_flags);
--	sdp->sd_log_num_gl++;
--	list_add(&le->le_list, &sdp->sd_log_le_gl);
--}
--
--static void glock_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le)
--{
--	gfs2_log_lock(sdp);
--	__glock_lo_add(sdp, le);
--	gfs2_log_unlock(sdp);
--}
--
--static void glock_lo_after_commit(struct gfs2_sbd *sdp, struct gfs2_ail *ai)
--{
--	struct list_head *head = &sdp->sd_log_le_gl;
--	struct gfs2_glock *gl;
--
--	while (!list_empty(head)) {
--		gl = list_entry(head->next, struct gfs2_glock, gl_le.le_list);
--		list_del_init(&gl->gl_le.le_list);
--		sdp->sd_log_num_gl--;
--
--		gfs2_assert_withdraw(sdp, gfs2_glock_is_held_excl(gl));
--		gfs2_glock_put(gl);
+-	ret = ocfs2_data_lock(inode, 1);
+-	if (ret < 0) {
+-		mlog_errno(ret);
+-		goto out_meta_unlock;
 -	}
--	gfs2_assert_warn(sdp, !sdp->sd_log_num_gl);
--}
 -
- static void buf_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le)
+ 	ret = __ocfs2_page_mkwrite(inode, di_bh, page);
+ 
+-	ocfs2_data_unlock(inode, 1);
+-
+-out_meta_unlock:
+ 	up_write(&OCFS2_I(inode)->ip_alloc_sem);
+ 
+ 	brelse(di_bh);
+-	ocfs2_meta_unlock(inode, 1);
++	ocfs2_inode_unlock(inode, 1);
+ 
+ out:
+ 	ret2 = ocfs2_vm_op_unblock_sigs(&oldset);
+@@ -214,13 +205,13 @@ int ocfs2_mmap(struct file *file, struct vm_area_struct *vma)
  {
- 	struct gfs2_bufdata *bd = container_of(le, struct gfs2_bufdata, bd_le);
-@@ -182,7 +140,8 @@ static void buf_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le)
- 	list_add(&bd->bd_list_tr, &tr->tr_list_buf);
- 	if (!list_empty(&le->le_list))
+ 	int ret = 0, lock_level = 0;
+ 
+-	ret = ocfs2_meta_lock_atime(file->f_dentry->d_inode,
++	ret = ocfs2_inode_lock_atime(file->f_dentry->d_inode,
+ 				    file->f_vfsmnt, &lock_level);
+ 	if (ret < 0) {
+ 		mlog_errno(ret);
  		goto out;
--	__glock_lo_add(sdp, &bd->bd_gl->gl_le);
-+	set_bit(GLF_LFLUSH, &bd->bd_gl->gl_flags);
-+	set_bit(GLF_DIRTY, &bd->bd_gl->gl_flags);
- 	gfs2_meta_check(sdp, bd->bd_bh);
- 	gfs2_pin(sdp, bd->bd_bh);
- 	sdp->sd_log_num_buf++;
-@@ -556,17 +515,20 @@ static void databuf_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le)
+ 	}
+-	ocfs2_meta_unlock(file->f_dentry->d_inode, lock_level);
++	ocfs2_inode_unlock(file->f_dentry->d_inode, lock_level);
+ out:
+ 	vma->vm_ops = &ocfs2_file_vm_ops;
+ 	vma->vm_flags |= VM_CAN_NONLINEAR;
+diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c
+index 989ac27..ae9ad95 100644
+--- a/fs/ocfs2/namei.c
++++ b/fs/ocfs2/namei.c
+@@ -60,7 +60,6 @@
+ #include "symlink.h"
+ #include "sysfile.h"
+ #include "uptodate.h"
+-#include "vote.h"
  
- 	lock_buffer(bd->bd_bh);
- 	gfs2_log_lock(sdp);
--	if (!list_empty(&bd->bd_list_tr))
--		goto out;
--	tr->tr_touched = 1;
--	if (gfs2_is_jdata(ip)) {
--		tr->tr_num_buf++;
--		list_add(&bd->bd_list_tr, &tr->tr_list_buf);
-+	if (tr) {
-+		if (!list_empty(&bd->bd_list_tr))
-+			goto out;
-+		tr->tr_touched = 1;
-+		if (gfs2_is_jdata(ip)) {
-+			tr->tr_num_buf++;
-+			list_add(&bd->bd_list_tr, &tr->tr_list_buf);
-+		}
+ #include "buffer_head_io.h"
+ 
+@@ -116,7 +115,7 @@ static struct dentry *ocfs2_lookup(struct inode *dir, struct dentry *dentry,
+ 	mlog(0, "find name %.*s in directory %llu\n", dentry->d_name.len,
+ 	     dentry->d_name.name, (unsigned long long)OCFS2_I(dir)->ip_blkno);
+ 
+-	status = ocfs2_meta_lock(dir, NULL, 0);
++	status = ocfs2_inode_lock(dir, NULL, 0);
+ 	if (status < 0) {
+ 		if (status != -ENOENT)
+ 			mlog_errno(status);
+@@ -129,7 +128,7 @@ static struct dentry *ocfs2_lookup(struct inode *dir, struct dentry *dentry,
+ 	if (status < 0)
+ 		goto bail_add;
+ 
+-	inode = ocfs2_iget(OCFS2_SB(dir->i_sb), blkno, 0);
++	inode = ocfs2_iget(OCFS2_SB(dir->i_sb), blkno, 0, 0);
+ 	if (IS_ERR(inode)) {
+ 		ret = ERR_PTR(-EACCES);
+ 		goto bail_unlock;
+@@ -176,8 +175,8 @@ bail_unlock:
+ 	/* Don't drop the cluster lock until *after* the d_add --
+ 	 * unlink on another node will message us to remove that
+ 	 * dentry under this lock so otherwise we can race this with
+-	 * the vote thread and have a stale dentry. */
+-	ocfs2_meta_unlock(dir, 0);
++	 * the downconvert thread and have a stale dentry. */
++	ocfs2_inode_unlock(dir, 0);
+ 
+ bail:
+ 
+@@ -209,7 +208,7 @@ static int ocfs2_mknod(struct inode *dir,
+ 	/* get our super block */
+ 	osb = OCFS2_SB(dir->i_sb);
+ 
+-	status = ocfs2_meta_lock(dir, &parent_fe_bh, 1);
++	status = ocfs2_inode_lock(dir, &parent_fe_bh, 1);
+ 	if (status < 0) {
+ 		if (status != -ENOENT)
+ 			mlog_errno(status);
+@@ -323,7 +322,7 @@ leave:
+ 	if (handle)
+ 		ocfs2_commit_trans(osb, handle);
+ 
+-	ocfs2_meta_unlock(dir, 1);
++	ocfs2_inode_unlock(dir, 1);
+ 
+ 	if (status == -ENOSPC)
+ 		mlog(0, "Disk is full\n");
+@@ -553,7 +552,7 @@ static int ocfs2_link(struct dentry *old_dentry,
+ 	if (S_ISDIR(inode->i_mode))
+ 		return -EPERM;
+ 
+-	err = ocfs2_meta_lock(dir, &parent_fe_bh, 1);
++	err = ocfs2_inode_lock(dir, &parent_fe_bh, 1);
+ 	if (err < 0) {
+ 		if (err != -ENOENT)
+ 			mlog_errno(err);
+@@ -578,7 +577,7 @@ static int ocfs2_link(struct dentry *old_dentry,
+ 		goto out;
+ 	}
+ 
+-	err = ocfs2_meta_lock(inode, &fe_bh, 1);
++	err = ocfs2_inode_lock(inode, &fe_bh, 1);
+ 	if (err < 0) {
+ 		if (err != -ENOENT)
+ 			mlog_errno(err);
+@@ -643,10 +642,10 @@ static int ocfs2_link(struct dentry *old_dentry,
+ out_commit:
+ 	ocfs2_commit_trans(osb, handle);
+ out_unlock_inode:
+-	ocfs2_meta_unlock(inode, 1);
++	ocfs2_inode_unlock(inode, 1);
+ 
+ out:
+-	ocfs2_meta_unlock(dir, 1);
++	ocfs2_inode_unlock(dir, 1);
+ 
+ 	if (de_bh)
+ 		brelse(de_bh);
+@@ -720,7 +719,7 @@ static int ocfs2_unlink(struct inode *dir,
+ 		return -EPERM;
+ 	}
+ 
+-	status = ocfs2_meta_lock(dir, &parent_node_bh, 1);
++	status = ocfs2_inode_lock(dir, &parent_node_bh, 1);
+ 	if (status < 0) {
+ 		if (status != -ENOENT)
+ 			mlog_errno(status);
+@@ -745,7 +744,7 @@ static int ocfs2_unlink(struct inode *dir,
+ 		goto leave;
  	}
- 	if (!list_empty(&le->le_list))
- 		goto out;
  
--	__glock_lo_add(sdp, &bd->bd_gl->gl_le);
-+	set_bit(GLF_LFLUSH, &bd->bd_gl->gl_flags);
-+	set_bit(GLF_DIRTY, &bd->bd_gl->gl_flags);
- 	if (gfs2_is_jdata(ip)) {
- 		gfs2_pin(sdp, bd->bd_bh);
- 		tr->tr_num_databuf_new++;
-@@ -773,12 +735,6 @@ static void databuf_lo_after_commit(struct gfs2_sbd *sdp, struct gfs2_ail *ai)
- }
+-	status = ocfs2_meta_lock(inode, &fe_bh, 1);
++	status = ocfs2_inode_lock(inode, &fe_bh, 1);
+ 	if (status < 0) {
+ 		if (status != -ENOENT)
+ 			mlog_errno(status);
+@@ -765,7 +764,7 @@ static int ocfs2_unlink(struct inode *dir,
  
+ 	status = ocfs2_remote_dentry_delete(dentry);
+ 	if (status < 0) {
+-		/* This vote should succeed under all normal
++		/* This remote delete should succeed under all normal
+ 		 * circumstances. */
+ 		mlog_errno(status);
+ 		goto leave;
+@@ -841,13 +840,13 @@ leave:
+ 		ocfs2_commit_trans(osb, handle);
  
--const struct gfs2_log_operations gfs2_glock_lops = {
--	.lo_add = glock_lo_add,
--	.lo_after_commit = glock_lo_after_commit,
--	.lo_name = "glock",
--};
--
- const struct gfs2_log_operations gfs2_buf_lops = {
- 	.lo_add = buf_lo_add,
- 	.lo_incore_commit = buf_lo_incore_commit,
-@@ -816,7 +772,6 @@ const struct gfs2_log_operations gfs2_databuf_lops = {
- };
+ 	if (child_locked)
+-		ocfs2_meta_unlock(inode, 1);
++		ocfs2_inode_unlock(inode, 1);
  
- const struct gfs2_log_operations *gfs2_log_ops[] = {
--	&gfs2_glock_lops,
- 	&gfs2_databuf_lops,
- 	&gfs2_buf_lops,
- 	&gfs2_rg_lops,
-diff --git a/fs/gfs2/main.c b/fs/gfs2/main.c
-index 7ecfe0d..9c7765c 100644
---- a/fs/gfs2/main.c
-+++ b/fs/gfs2/main.c
-@@ -29,9 +29,8 @@ static void gfs2_init_inode_once(struct kmem_cache *cachep, void *foo)
- 	struct gfs2_inode *ip = foo;
+-	ocfs2_meta_unlock(dir, 1);
++	ocfs2_inode_unlock(dir, 1);
  
- 	inode_init_once(&ip->i_inode);
--	spin_lock_init(&ip->i_spin);
- 	init_rwsem(&ip->i_rw_mutex);
--	memset(ip->i_cache, 0, sizeof(ip->i_cache));
-+	ip->i_alloc = NULL;
- }
+ 	if (orphan_dir) {
+ 		/* This was locked for us in ocfs2_prepare_orphan_dir() */
+-		ocfs2_meta_unlock(orphan_dir, 1);
++		ocfs2_inode_unlock(orphan_dir, 1);
+ 		mutex_unlock(&orphan_dir->i_mutex);
+ 		iput(orphan_dir);
+ 	}
+@@ -908,7 +907,7 @@ static int ocfs2_double_lock(struct ocfs2_super *osb,
+ 			inode1 = tmpinode;
+ 		}
+ 		/* lock id2 */
+-		status = ocfs2_meta_lock(inode2, bh2, 1);
++		status = ocfs2_inode_lock(inode2, bh2, 1);
+ 		if (status < 0) {
+ 			if (status != -ENOENT)
+ 				mlog_errno(status);
+@@ -917,14 +916,14 @@ static int ocfs2_double_lock(struct ocfs2_super *osb,
+ 	}
  
- static void gfs2_init_glock_once(struct kmem_cache *cachep, void *foo)
-diff --git a/fs/gfs2/meta_io.c b/fs/gfs2/meta_io.c
-index 4da4239..85aea27 100644
---- a/fs/gfs2/meta_io.c
-+++ b/fs/gfs2/meta_io.c
-@@ -50,6 +50,7 @@ static int gfs2_aspace_writepage(struct page *page,
- static const struct address_space_operations aspace_aops = {
- 	.writepage = gfs2_aspace_writepage,
- 	.releasepage = gfs2_releasepage,
-+	.sync_page = block_sync_page,
- };
+ 	/* lock id1 */
+-	status = ocfs2_meta_lock(inode1, bh1, 1);
++	status = ocfs2_inode_lock(inode1, bh1, 1);
+ 	if (status < 0) {
+ 		/*
+ 		 * An error return must mean that no cluster locks
+ 		 * were held on function exit.
+ 		 */
+ 		if (oi1->ip_blkno != oi2->ip_blkno)
+-			ocfs2_meta_unlock(inode2, 1);
++			ocfs2_inode_unlock(inode2, 1);
  
- /**
-@@ -221,13 +222,14 @@ int gfs2_meta_read(struct gfs2_glock *gl, u64 blkno, int flags,
- 		   struct buffer_head **bhp)
+ 		if (status != -ENOENT)
+ 			mlog_errno(status);
+@@ -937,10 +936,10 @@ bail:
+ 
+ static void ocfs2_double_unlock(struct inode *inode1, struct inode *inode2)
  {
- 	*bhp = getbuf(gl, blkno, CREATE);
--	if (!buffer_uptodate(*bhp))
-+	if (!buffer_uptodate(*bhp)) {
- 		ll_rw_block(READ_META, 1, bhp);
--	if (flags & DIO_WAIT) {
--		int error = gfs2_meta_wait(gl->gl_sbd, *bhp);
--		if (error) {
--			brelse(*bhp);
--			return error;
-+		if (flags & DIO_WAIT) {
-+			int error = gfs2_meta_wait(gl->gl_sbd, *bhp);
-+			if (error) {
-+				brelse(*bhp);
-+				return error;
-+			}
+-	ocfs2_meta_unlock(inode1, 1);
++	ocfs2_inode_unlock(inode1, 1);
+ 
+ 	if (inode1 != inode2)
+-		ocfs2_meta_unlock(inode2, 1);
++		ocfs2_inode_unlock(inode2, 1);
+ }
+ 
+ static int ocfs2_rename(struct inode *old_dir,
+@@ -1031,10 +1030,11 @@ static int ocfs2_rename(struct inode *old_dir,
+ 
+ 	/*
+ 	 * Aside from allowing a meta data update, the locking here
+-	 * also ensures that the vote thread on other nodes won't have
+-	 * to concurrently downconvert the inode and the dentry locks.
++	 * also ensures that the downconvert thread on other nodes
++	 * won't have to concurrently downconvert the inode and the
++	 * dentry locks.
+ 	 */
+-	status = ocfs2_meta_lock(old_inode, &old_inode_bh, 1);
++	status = ocfs2_inode_lock(old_inode, &old_inode_bh, 1);
+ 	if (status < 0) {
+ 		if (status != -ENOENT)
+ 			mlog_errno(status);
+@@ -1143,7 +1143,7 @@ static int ocfs2_rename(struct inode *old_dir,
+ 			goto bail;
  		}
- 	}
  
-@@ -282,7 +284,7 @@ void gfs2_attach_bufdata(struct gfs2_glock *gl, struct buffer_head *bh,
- 		return;
- 	}
+-		status = ocfs2_meta_lock(new_inode, &newfe_bh, 1);
++		status = ocfs2_inode_lock(new_inode, &newfe_bh, 1);
+ 		if (status < 0) {
+ 			if (status != -ENOENT)
+ 				mlog_errno(status);
+@@ -1355,14 +1355,14 @@ bail:
+ 		ocfs2_double_unlock(old_dir, new_dir);
  
--	bd = kmem_cache_zalloc(gfs2_bufdata_cachep, GFP_NOFS | __GFP_NOFAIL),
-+	bd = kmem_cache_zalloc(gfs2_bufdata_cachep, GFP_NOFS | __GFP_NOFAIL);
- 	bd->bd_bh = bh;
- 	bd->bd_gl = gl;
+ 	if (old_child_locked)
+-		ocfs2_meta_unlock(old_inode, 1);
++		ocfs2_inode_unlock(old_inode, 1);
  
-@@ -317,7 +319,7 @@ void gfs2_remove_from_journal(struct buffer_head *bh, struct gfs2_trans *tr, int
+ 	if (new_child_locked)
+-		ocfs2_meta_unlock(new_inode, 1);
++		ocfs2_inode_unlock(new_inode, 1);
+ 
+ 	if (orphan_dir) {
+ 		/* This was locked for us in ocfs2_prepare_orphan_dir() */
+-		ocfs2_meta_unlock(orphan_dir, 1);
++		ocfs2_inode_unlock(orphan_dir, 1);
+ 		mutex_unlock(&orphan_dir->i_mutex);
+ 		iput(orphan_dir);
  	}
- 	if (bd) {
- 		if (bd->bd_ail) {
--			gfs2_remove_from_ail(NULL, bd);
-+			gfs2_remove_from_ail(bd);
- 			bh->b_private = NULL;
- 			bd->bd_bh = NULL;
- 			bd->bd_blkno = bh->b_blocknr;
-@@ -358,32 +360,6 @@ void gfs2_meta_wipe(struct gfs2_inode *ip, u64 bstart, u32 blen)
- }
+@@ -1530,7 +1530,7 @@ static int ocfs2_symlink(struct inode *dir,
+ 	credits = ocfs2_calc_symlink_credits(sb);
  
- /**
-- * gfs2_meta_cache_flush - get rid of any references on buffers for this inode
-- * @ip: The GFS2 inode
-- *
-- * This releases buffers that are in the most-recently-used array of
-- * blocks used for indirect block addressing for this inode.
-- */
--
--void gfs2_meta_cache_flush(struct gfs2_inode *ip)
--{
--	struct buffer_head **bh_slot;
--	unsigned int x;
--
--	spin_lock(&ip->i_spin);
--
--	for (x = 0; x < GFS2_MAX_META_HEIGHT; x++) {
--		bh_slot = &ip->i_cache[x];
--		if (*bh_slot) {
--			brelse(*bh_slot);
--			*bh_slot = NULL;
--		}
--	}
--
--	spin_unlock(&ip->i_spin);
--}
--
--/**
-  * gfs2_meta_indirect_buffer - Get a metadata buffer
-  * @ip: The GFS2 inode
-  * @height: The level of this buf in the metadata (indir addr) tree (if any)
-@@ -391,8 +367,6 @@ void gfs2_meta_cache_flush(struct gfs2_inode *ip)
-  * @new: Non-zero if we may create a new buffer
-  * @bhp: the buffer is returned here
-  *
-- * Try to use the gfs2_inode's MRU metadata tree cache.
-- *
-  * Returns: errno
-  */
+ 	/* lock the parent directory */
+-	status = ocfs2_meta_lock(dir, &parent_fe_bh, 1);
++	status = ocfs2_inode_lock(dir, &parent_fe_bh, 1);
+ 	if (status < 0) {
+ 		if (status != -ENOENT)
+ 			mlog_errno(status);
+@@ -1657,7 +1657,7 @@ bail:
+ 	if (handle)
+ 		ocfs2_commit_trans(osb, handle);
  
-@@ -401,58 +375,25 @@ int gfs2_meta_indirect_buffer(struct gfs2_inode *ip, int height, u64 num,
- {
- 	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
- 	struct gfs2_glock *gl = ip->i_gl;
--	struct buffer_head *bh = NULL, **bh_slot = ip->i_cache + height;
--	int in_cache = 0;
--
--	BUG_ON(!gl);
--	BUG_ON(!sdp);
--
--	spin_lock(&ip->i_spin);
--	if (*bh_slot && (*bh_slot)->b_blocknr == num) {
--		bh = *bh_slot;
--		get_bh(bh);
--		in_cache = 1;
--	}
--	spin_unlock(&ip->i_spin);
--
--	if (!bh)
--		bh = getbuf(gl, num, CREATE);
--
--	if (!bh)
--		return -ENOBUFS;
-+	struct buffer_head *bh;
-+	int ret = 0;
+-	ocfs2_meta_unlock(dir, 1);
++	ocfs2_inode_unlock(dir, 1);
  
- 	if (new) {
--		if (gfs2_assert_warn(sdp, height))
--			goto err;
--		meta_prep_new(bh);
-+		BUG_ON(height == 0);
-+		bh = gfs2_meta_new(gl, num);
- 		gfs2_trans_add_bh(ip->i_gl, bh, 1);
- 		gfs2_metatype_set(bh, GFS2_METATYPE_IN, GFS2_FORMAT_IN);
- 		gfs2_buffer_clear_tail(bh, sizeof(struct gfs2_meta_header));
- 	} else {
- 		u32 mtype = height ? GFS2_METATYPE_IN : GFS2_METATYPE_DI;
--		if (!buffer_uptodate(bh)) {
--			ll_rw_block(READ_META, 1, &bh);
--			if (gfs2_meta_wait(sdp, bh))
--				goto err;
-+		ret = gfs2_meta_read(gl, num, DIO_WAIT, &bh);
-+		if (ret == 0 && gfs2_metatype_check(sdp, bh, mtype)) {
-+			brelse(bh);
-+			ret = -EIO;
- 		}
--		if (gfs2_metatype_check(sdp, bh, mtype))
--			goto err;
--	}
--
--	if (!in_cache) {
--		spin_lock(&ip->i_spin);
--		if (*bh_slot)
--			brelse(*bh_slot);
--		*bh_slot = bh;
--		get_bh(bh);
--		spin_unlock(&ip->i_spin);
- 	}
--
- 	*bhp = bh;
--	return 0;
--err:
--	brelse(bh);
--	return -EIO;
-+	return ret;
- }
+ 	if (new_fe_bh)
+ 		brelse(new_fe_bh);
+@@ -1735,7 +1735,7 @@ static int ocfs2_prepare_orphan_dir(struct ocfs2_super *osb,
  
- /**
-diff --git a/fs/gfs2/meta_io.h b/fs/gfs2/meta_io.h
-index b704822..73e3b1c 100644
---- a/fs/gfs2/meta_io.h
-+++ b/fs/gfs2/meta_io.h
-@@ -56,7 +56,6 @@ void gfs2_remove_from_journal(struct buffer_head *bh, struct gfs2_trans *tr,
+ 	mutex_lock(&orphan_dir_inode->i_mutex);
  
- void gfs2_meta_wipe(struct gfs2_inode *ip, u64 bstart, u32 blen);
+-	status = ocfs2_meta_lock(orphan_dir_inode, &orphan_dir_bh, 1);
++	status = ocfs2_inode_lock(orphan_dir_inode, &orphan_dir_bh, 1);
+ 	if (status < 0) {
+ 		mlog_errno(status);
+ 		goto leave;
+@@ -1745,7 +1745,7 @@ static int ocfs2_prepare_orphan_dir(struct ocfs2_super *osb,
+ 					      orphan_dir_bh, name,
+ 					      OCFS2_ORPHAN_NAMELEN, de_bh);
+ 	if (status < 0) {
+-		ocfs2_meta_unlock(orphan_dir_inode, 1);
++		ocfs2_inode_unlock(orphan_dir_inode, 1);
  
--void gfs2_meta_cache_flush(struct gfs2_inode *ip);
- int gfs2_meta_indirect_buffer(struct gfs2_inode *ip, int height, u64 num,
- 			      int new, struct buffer_head **bhp);
+ 		mlog_errno(status);
+ 		goto leave;
+diff --git a/fs/ocfs2/ocfs2.h b/fs/ocfs2/ocfs2.h
+index 60a23e1..d084805 100644
+--- a/fs/ocfs2/ocfs2.h
++++ b/fs/ocfs2/ocfs2.h
+@@ -101,6 +101,7 @@ enum ocfs2_unlock_action {
+ 					       * about to be
+ 					       * dropped. */
+ #define OCFS2_LOCK_QUEUED        (0x00000100) /* queued for downconvert */
++#define OCFS2_LOCK_NOCACHE       (0x00000200) /* don't use a holder count */
  
-diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c
-index 9679f8b..38dbe99 100644
---- a/fs/gfs2/ops_address.c
-+++ b/fs/gfs2/ops_address.c
-@@ -20,6 +20,8 @@
- #include <linux/swap.h>
- #include <linux/gfs2_ondisk.h>
- #include <linux/lm_interface.h>
-+#include <linux/backing-dev.h>
-+#include <linux/pagevec.h>
+ struct ocfs2_lock_res_ops;
  
- #include "gfs2.h"
- #include "incore.h"
-@@ -32,7 +34,6 @@
- #include "quota.h"
- #include "trans.h"
- #include "rgrp.h"
--#include "ops_file.h"
- #include "super.h"
- #include "util.h"
- #include "glops.h"
-@@ -58,22 +59,6 @@ static void gfs2_page_add_databufs(struct gfs2_inode *ip, struct page *page,
- }
+@@ -170,6 +171,7 @@ enum ocfs2_mount_options
+ 	OCFS2_MOUNT_NOINTR  = 1 << 2,   /* Don't catch signals */
+ 	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 */
+ };
  
- /**
-- * gfs2_get_block - Fills in a buffer head with details about a block
-- * @inode: The inode
-- * @lblock: The block number to look up
-- * @bh_result: The buffer head to return the result in
-- * @create: Non-zero if we may add block to the file
-- *
-- * Returns: errno
-- */
+ #define OCFS2_OSB_SOFT_RO	0x0001
+@@ -189,9 +191,7 @@ struct ocfs2_super
+ 	struct ocfs2_slot_info *slot_info;
+ 
+ 	spinlock_t node_map_lock;
+-	struct ocfs2_node_map mounted_map;
+ 	struct ocfs2_node_map recovery_map;
+-	struct ocfs2_node_map umount_map;
+ 
+ 	u64 root_blkno;
+ 	u64 system_dir_blkno;
+@@ -231,7 +231,9 @@ struct ocfs2_super
+ 	wait_queue_head_t checkpoint_event;
+ 	atomic_t needs_checkpoint;
+ 	struct ocfs2_journal *journal;
++	unsigned long osb_commit_interval;
+ 
++	int local_alloc_size;
+ 	enum ocfs2_local_alloc_state local_alloc_state;
+ 	struct buffer_head *local_alloc_bh;
+ 	u64 la_last_gd;
+@@ -254,28 +256,21 @@ struct ocfs2_super
+ 
+ 	wait_queue_head_t recovery_event;
+ 
+-	spinlock_t vote_task_lock;
+-	struct task_struct *vote_task;
+-	wait_queue_head_t vote_event;
+-	unsigned long vote_wake_sequence;
+-	unsigned long vote_work_sequence;
++	spinlock_t dc_task_lock;
++	struct task_struct *dc_task;
++	wait_queue_head_t dc_event;
++	unsigned long dc_wake_sequence;
++	unsigned long dc_work_sequence;
+ 
++	/*
++	 * Any thread can add locks to the list, but the downconvert
++	 * thread is the only one allowed to remove locks. Any change
++	 * to this rule requires updating
++	 * ocfs2_downconvert_thread_do_work().
++	 */
+ 	struct list_head blocked_lock_list;
+ 	unsigned long blocked_lock_count;
+ 
+-	struct list_head vote_list;
+-	int vote_count;
 -
--int gfs2_get_block(struct inode *inode, sector_t lblock,
--	           struct buffer_head *bh_result, int create)
--{
--	return gfs2_block_map(inode, lblock, create, bh_result);
--}
+-	u32 net_key;
+-	spinlock_t net_response_lock;
+-	unsigned int net_response_ids;
+-	struct list_head net_response_list;
 -
--/**
-  * gfs2_get_block_noalloc - Fills in a buffer head with details about a block
-  * @inode: The inode
-  * @lblock: The block number to look up
-@@ -88,7 +73,7 @@ static int gfs2_get_block_noalloc(struct inode *inode, sector_t lblock,
- {
- 	int error;
+-	struct o2hb_callback_func osb_hb_up;
+-	struct o2hb_callback_func osb_hb_down;
+-
+-	struct list_head	osb_net_handlers;
+-
+ 	wait_queue_head_t		osb_mount_event;
  
--	error = gfs2_block_map(inode, lblock, 0, bh_result);
-+	error = gfs2_block_map(inode, lblock, bh_result, 0);
- 	if (error)
- 		return error;
- 	if (!buffer_mapped(bh_result))
-@@ -99,20 +84,19 @@ static int gfs2_get_block_noalloc(struct inode *inode, sector_t lblock,
- static int gfs2_get_block_direct(struct inode *inode, sector_t lblock,
- 				 struct buffer_head *bh_result, int create)
- {
--	return gfs2_block_map(inode, lblock, 0, bh_result);
-+	return gfs2_block_map(inode, lblock, bh_result, 0);
- }
+ 	/* Truncate log info */
+diff --git a/fs/ocfs2/ocfs2_fs.h b/fs/ocfs2/ocfs2_fs.h
+index 6ef8767..3633edd 100644
+--- a/fs/ocfs2/ocfs2_fs.h
++++ b/fs/ocfs2/ocfs2_fs.h
+@@ -231,6 +231,20 @@ struct ocfs2_space_resv {
+ #define OCFS2_IOC_RESVSP64	_IOW ('X', 42, struct ocfs2_space_resv)
+ #define OCFS2_IOC_UNRESVSP64	_IOW ('X', 43, struct ocfs2_space_resv)
  
- /**
-- * gfs2_writepage - Write complete page
-- * @page: Page to write
-+ * gfs2_writepage_common - Common bits of writepage
-+ * @page: The page to be written
-+ * @wbc: The writeback control
-  *
-- * Returns: errno
-- *
-- * Some of this is copied from block_write_full_page() although we still
-- * call it to do most of the work.
-+ * Returns: 1 if writepage is ok, otherwise an error code or zero if no error.
++/* Used to pass group descriptor data when online resize is done */
++struct ocfs2_new_group_input {
++	__u64 group;		/* Group descriptor's blkno. */
++	__u32 clusters;		/* Total number of clusters in this group */
++	__u32 frees;		/* Total free clusters in this group */
++	__u16 chain;		/* Chain for this group */
++	__u16 reserved1;
++	__u32 reserved2;
++};
++
++#define OCFS2_IOC_GROUP_EXTEND	_IOW('o', 1, int)
++#define OCFS2_IOC_GROUP_ADD	_IOW('o', 2,struct ocfs2_new_group_input)
++#define OCFS2_IOC_GROUP_ADD64	_IOW('o', 3,struct ocfs2_new_group_input)
++
+ /*
+  * Journal Flags (ocfs2_dinode.id1.journal1.i_flags)
   */
+@@ -256,6 +270,14 @@ struct ocfs2_space_resv {
+ /* Journal limits (in bytes) */
+ #define OCFS2_MIN_JOURNAL_SIZE		(4 * 1024 * 1024)
  
--static int gfs2_writepage(struct page *page, struct writeback_control *wbc)
-+static int gfs2_writepage_common(struct page *page,
-+				 struct writeback_control *wbc)
- {
- 	struct inode *inode = page->mapping->host;
- 	struct gfs2_inode *ip = GFS2_I(inode);
-@@ -120,41 +104,133 @@ static int gfs2_writepage(struct page *page, struct writeback_control *wbc)
- 	loff_t i_size = i_size_read(inode);
- 	pgoff_t end_index = i_size >> PAGE_CACHE_SHIFT;
- 	unsigned offset;
--	int error;
--	int done_trans = 0;
-+	int ret = -EIO;
++/*
++ * Default local alloc size (in megabytes)
++ *
++ * The value chosen should be such that most allocations, including new
++ * block groups, use local alloc.
++ */
++#define OCFS2_DEFAULT_LOCAL_ALLOC_SIZE	8
++
+ struct ocfs2_system_inode_info {
+ 	char	*si_name;
+ 	int	si_iflags;
+diff --git a/fs/ocfs2/ocfs2_lockid.h b/fs/ocfs2/ocfs2_lockid.h
+index 4ca02b1..86f3e37 100644
+--- a/fs/ocfs2/ocfs2_lockid.h
++++ b/fs/ocfs2/ocfs2_lockid.h
+@@ -45,6 +45,7 @@ enum ocfs2_lock_type {
+ 	OCFS2_LOCK_TYPE_RW,
+ 	OCFS2_LOCK_TYPE_DENTRY,
+ 	OCFS2_LOCK_TYPE_OPEN,
++	OCFS2_LOCK_TYPE_FLOCK,
+ 	OCFS2_NUM_LOCK_TYPES
+ };
  
--	if (gfs2_assert_withdraw(sdp, gfs2_glock_is_held_excl(ip->i_gl))) {
--		unlock_page(page);
--		return -EIO;
--	}
-+	if (gfs2_assert_withdraw(sdp, gfs2_glock_is_held_excl(ip->i_gl)))
+@@ -73,6 +74,9 @@ static inline char ocfs2_lock_type_char(enum ocfs2_lock_type type)
+ 		case OCFS2_LOCK_TYPE_OPEN:
+ 			c = 'O';
+ 			break;
++		case OCFS2_LOCK_TYPE_FLOCK:
++			c = 'F';
++			break;
+ 		default:
+ 			c = '\0';
+ 	}
+@@ -90,6 +94,7 @@ static char *ocfs2_lock_type_strings[] = {
+ 	[OCFS2_LOCK_TYPE_RW] = "Write/Read",
+ 	[OCFS2_LOCK_TYPE_DENTRY] = "Dentry",
+ 	[OCFS2_LOCK_TYPE_OPEN] = "Open",
++	[OCFS2_LOCK_TYPE_FLOCK] = "Flock",
+ };
+ 
+ static inline const char *ocfs2_lock_type_string(enum ocfs2_lock_type type)
+diff --git a/fs/ocfs2/resize.c b/fs/ocfs2/resize.c
+new file mode 100644
+index 0000000..37835ff
+--- /dev/null
++++ b/fs/ocfs2/resize.c
+@@ -0,0 +1,634 @@
++/* -*- mode: c; c-basic-offset: 8; -*-
++ * vim: noexpandtab sw=8 ts=8 sts=0:
++ *
++ * resize.c
++ *
++ * volume resize.
++ * Inspired by ext3/resize.c.
++ *
++ * Copyright (C) 2007 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.
++ */
++
++#include <linux/fs.h>
++#include <linux/types.h>
++
++#define MLOG_MASK_PREFIX ML_DISK_ALLOC
++#include <cluster/masklog.h>
++
++#include "ocfs2.h"
++
++#include "alloc.h"
++#include "dlmglue.h"
++#include "inode.h"
++#include "journal.h"
++#include "super.h"
++#include "sysfile.h"
++#include "uptodate.h"
++
++#include "buffer_head_io.h"
++#include "suballoc.h"
++#include "resize.h"
++
++/*
++ * Check whether there are new backup superblocks exist
++ * in the last group. If there are some, mark them or clear
++ * them in the bitmap.
++ *
++ * Return how many backups we find in the last group.
++ */
++static u16 ocfs2_calc_new_backup_super(struct inode *inode,
++				       struct ocfs2_group_desc *gd,
++				       int new_clusters,
++				       u32 first_new_cluster,
++				       u16 cl_cpg,
++				       int set)
++{
++	int i;
++	u16 backups = 0;
++	u32 cluster;
++	u64 blkno, gd_blkno, lgd_blkno = le64_to_cpu(gd->bg_blkno);
++
++	for (i = 0; i < OCFS2_MAX_BACKUP_SUPERBLOCKS; i++) {
++		blkno = ocfs2_backup_super_blkno(inode->i_sb, i);
++		cluster = ocfs2_blocks_to_clusters(inode->i_sb, blkno);
++
++		gd_blkno = ocfs2_which_cluster_group(inode, cluster);
++		if (gd_blkno < lgd_blkno)
++			continue;
++		else if (gd_blkno > lgd_blkno)
++			break;
++
++		if (set)
++			ocfs2_set_bit(cluster % cl_cpg,
++				      (unsigned long *)gd->bg_bitmap);
++		else
++			ocfs2_clear_bit(cluster % cl_cpg,
++					(unsigned long *)gd->bg_bitmap);
++		backups++;
++	}
++
++	mlog_exit_void();
++	return backups;
++}
++
++static int ocfs2_update_last_group_and_inode(handle_t *handle,
++					     struct inode *bm_inode,
++					     struct buffer_head *bm_bh,
++					     struct buffer_head *group_bh,
++					     u32 first_new_cluster,
++					     int new_clusters)
++{
++	int ret = 0;
++	struct ocfs2_super *osb = OCFS2_SB(bm_inode->i_sb);
++	struct ocfs2_dinode *fe = (struct ocfs2_dinode *) bm_bh->b_data;
++	struct ocfs2_chain_list *cl = &fe->id2.i_chain;
++	struct ocfs2_chain_rec *cr;
++	struct ocfs2_group_desc *group;
++	u16 chain, num_bits, backups = 0;
++	u16 cl_bpc = le16_to_cpu(cl->cl_bpc);
++	u16 cl_cpg = le16_to_cpu(cl->cl_cpg);
++
++	mlog_entry("(new_clusters=%d, first_new_cluster = %u)\n",
++		   new_clusters, first_new_cluster);
++
++	ret = ocfs2_journal_access(handle, bm_inode, group_bh,
++				   OCFS2_JOURNAL_ACCESS_WRITE);
++	if (ret < 0) {
++		mlog_errno(ret);
 +		goto out;
-+	ret = 0;
- 	if (current->journal_info)
--		goto out_ignore;
--
-+		goto redirty;
- 	/* Is the page fully outside i_size? (truncate in progress) */
--        offset = i_size & (PAGE_CACHE_SIZE-1);
-+	offset = i_size & (PAGE_CACHE_SIZE-1);
- 	if (page->index > end_index || (page->index == end_index && !offset)) {
- 		page->mapping->a_ops->invalidatepage(page, 0);
--		unlock_page(page);
--		return 0; /* don't care */
++	}
++
++	group = (struct ocfs2_group_desc *)group_bh->b_data;
++
++	/* update the group first. */
++	num_bits = new_clusters * cl_bpc;
++	le16_add_cpu(&group->bg_bits, num_bits);
++	le16_add_cpu(&group->bg_free_bits_count, num_bits);
++
++	/*
++	 * check whether there are some new backup superblocks exist in
++	 * this group and update the group bitmap accordingly.
++	 */
++	if (OCFS2_HAS_COMPAT_FEATURE(osb->sb,
++				     OCFS2_FEATURE_COMPAT_BACKUP_SB)) {
++		backups = ocfs2_calc_new_backup_super(bm_inode,
++						     group,
++						     new_clusters,
++						     first_new_cluster,
++						     cl_cpg, 1);
++		le16_add_cpu(&group->bg_free_bits_count, -1 * backups);
++	}
++
++	ret = ocfs2_journal_dirty(handle, group_bh);
++	if (ret < 0) {
++		mlog_errno(ret);
++		goto out_rollback;
++	}
++
++	/* update the inode accordingly. */
++	ret = ocfs2_journal_access(handle, bm_inode, bm_bh,
++				   OCFS2_JOURNAL_ACCESS_WRITE);
++	if (ret < 0) {
++		mlog_errno(ret);
++		goto out_rollback;
++	}
++
++	chain = le16_to_cpu(group->bg_chain);
++	cr = (&cl->cl_recs[chain]);
++	le32_add_cpu(&cr->c_total, num_bits);
++	le32_add_cpu(&cr->c_free, num_bits);
++	le32_add_cpu(&fe->id1.bitmap1.i_total, num_bits);
++	le32_add_cpu(&fe->i_clusters, new_clusters);
++
++	if (backups) {
++		le32_add_cpu(&cr->c_free, -1 * backups);
++		le32_add_cpu(&fe->id1.bitmap1.i_used, backups);
++	}
++
++	spin_lock(&OCFS2_I(bm_inode)->ip_lock);
++	OCFS2_I(bm_inode)->ip_clusters = le32_to_cpu(fe->i_clusters);
++	le64_add_cpu(&fe->i_size, new_clusters << osb->s_clustersize_bits);
++	spin_unlock(&OCFS2_I(bm_inode)->ip_lock);
++	i_size_write(bm_inode, le64_to_cpu(fe->i_size));
++
++	ocfs2_journal_dirty(handle, bm_bh);
++
++out_rollback:
++	if (ret < 0) {
++		ocfs2_calc_new_backup_super(bm_inode,
++					    group,
++					    new_clusters,
++					    first_new_cluster,
++					    cl_cpg, 0);
++		le16_add_cpu(&group->bg_free_bits_count, backups);
++		le16_add_cpu(&group->bg_bits, -1 * num_bits);
++		le16_add_cpu(&group->bg_free_bits_count, -1 * num_bits);
++	}
++out:
++	mlog_exit(ret);
++	return ret;
++}
++
++static int update_backups(struct inode * inode, u32 clusters, char *data)
++{
++	int i, ret = 0;
++	u32 cluster;
++	u64 blkno;
++	struct buffer_head *backup = NULL;
++	struct ocfs2_dinode *backup_di = NULL;
++	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
++
++	/* calculate the real backups we need to update. */
++	for (i = 0; i < OCFS2_MAX_BACKUP_SUPERBLOCKS; i++) {
++		blkno = ocfs2_backup_super_blkno(inode->i_sb, i);
++		cluster = ocfs2_blocks_to_clusters(inode->i_sb, blkno);
++		if (cluster > clusters)
++			break;
++
++		ret = ocfs2_read_block(osb, blkno, &backup, 0, NULL);
++		if (ret < 0) {
++			mlog_errno(ret);
++			break;
++		}
++
++		memcpy(backup->b_data, data, inode->i_sb->s_blocksize);
++
++		backup_di = (struct ocfs2_dinode *)backup->b_data;
++		backup_di->i_blkno = cpu_to_le64(blkno);
++
++		ret = ocfs2_write_super_or_backup(osb, backup);
++		brelse(backup);
++		backup = NULL;
++		if (ret < 0) {
++			mlog_errno(ret);
++			break;
++		}
++	}
++
++	return ret;
++}
++
++static void ocfs2_update_super_and_backups(struct inode *inode,
++					   int new_clusters)
++{
++	int ret;
++	u32 clusters = 0;
++	struct buffer_head *super_bh = NULL;
++	struct ocfs2_dinode *super_di = NULL;
++	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
++
++	/*
++	 * 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);
++	if (ret < 0) {
++		mlog_errno(ret);
 +		goto out;
 +	}
-+	return 1;
-+redirty:
-+	redirty_page_for_writepage(wbc, page);
++
++	super_di = (struct ocfs2_dinode *)super_bh->b_data;
++	le32_add_cpu(&super_di->i_clusters, new_clusters);
++	clusters = le32_to_cpu(super_di->i_clusters);
++
++	ret = ocfs2_write_super_or_backup(osb, super_bh);
++	if (ret < 0) {
++		mlog_errno(ret);
++		goto out;
++	}
++
++	if (OCFS2_HAS_COMPAT_FEATURE(osb->sb, OCFS2_FEATURE_COMPAT_BACKUP_SB))
++		ret = update_backups(inode, clusters, super_bh->b_data);
++
 +out:
-+	unlock_page(page);
-+	return 0;
++	brelse(super_bh);
++	if (ret)
++		printk(KERN_WARNING "ocfs2: Failed to update super blocks on %s"
++			" during fs resize. This condition is not fatal,"
++			" but fsck.ocfs2 should be run to fix it\n",
++			osb->dev_str);
++	return;
 +}
 +
-+/**
-+ * gfs2_writeback_writepage - Write page for writeback mappings
-+ * @page: The page
-+ * @wbc: The writeback control
-+ *
++/*
++ * Extend the filesystem to the new number of clusters specified.  This entry
++ * point is only used to extend the current filesystem to the end of the last
++ * existing group.
 + */
++int ocfs2_group_extend(struct inode * inode, int new_clusters)
++{
++	int ret;
++	handle_t *handle;
++	struct buffer_head *main_bm_bh = NULL;
++	struct buffer_head *group_bh = NULL;
++	struct inode *main_bm_inode = NULL;
++	struct ocfs2_dinode *fe = NULL;
++	struct ocfs2_group_desc *group = NULL;
++	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
++	u16 cl_bpc;
++	u32 first_new_cluster;
++	u64 lgd_blkno;
 +
-+static int gfs2_writeback_writepage(struct page *page,
-+				    struct writeback_control *wbc)
++	mlog_entry_void();
++
++	if (ocfs2_is_hard_readonly(osb) || ocfs2_is_soft_readonly(osb))
++		return -EROFS;
++
++	if (new_clusters < 0)
++		return -EINVAL;
++	else if (new_clusters == 0)
++		return 0;
++
++	main_bm_inode = ocfs2_get_system_file_inode(osb,
++						    GLOBAL_BITMAP_SYSTEM_INODE,
++						    OCFS2_INVALID_SLOT);
++	if (!main_bm_inode) {
++		ret = -EINVAL;
++		mlog_errno(ret);
++		goto out;
++	}
++
++	mutex_lock(&main_bm_inode->i_mutex);
++
++	ret = ocfs2_inode_lock(main_bm_inode, &main_bm_bh, 1);
++	if (ret < 0) {
++		mlog_errno(ret);
++		goto out_mutex;
++	}
++
++	fe = (struct ocfs2_dinode *)main_bm_bh->b_data;
++
++	if (le16_to_cpu(fe->id2.i_chain.cl_cpg) !=
++				 ocfs2_group_bitmap_size(osb->sb) * 8) {
++		mlog(ML_ERROR, "The disk is too old and small. "
++		     "Force to do offline resize.");
++		ret = -EINVAL;
++		goto out_unlock;
++	}
++
++	if (!OCFS2_IS_VALID_DINODE(fe)) {
++		OCFS2_RO_ON_INVALID_DINODE(main_bm_inode->i_sb, fe);
++		ret = -EIO;
++		goto out_unlock;
++	}
++
++	first_new_cluster = le32_to_cpu(fe->i_clusters);
++	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);
++	if (ret < 0) {
++		mlog_errno(ret);
++		goto out_unlock;
++	}
++
++	group = (struct ocfs2_group_desc *)group_bh->b_data;
++
++	ret = ocfs2_check_group_descriptor(inode->i_sb, fe, group);
++	if (ret) {
++		mlog_errno(ret);
++		goto out_unlock;
++	}
++
++	cl_bpc = le16_to_cpu(fe->id2.i_chain.cl_bpc);
++	if (le16_to_cpu(group->bg_bits) / cl_bpc + new_clusters >
++		le16_to_cpu(fe->id2.i_chain.cl_cpg)) {
++		ret = -EINVAL;
++		goto out_unlock;
++	}
++
++	mlog(0, "extend the last group at %llu, new clusters = %d\n",
++	     (unsigned long long)le64_to_cpu(group->bg_blkno), new_clusters);
++
++	handle = ocfs2_start_trans(osb, OCFS2_GROUP_EXTEND_CREDITS);
++	if (IS_ERR(handle)) {
++		mlog_errno(PTR_ERR(handle));
++		ret = -EINVAL;
++		goto out_unlock;
++	}
++
++	/* update the last group descriptor and inode. */
++	ret = ocfs2_update_last_group_and_inode(handle, main_bm_inode,
++						main_bm_bh, group_bh,
++						first_new_cluster,
++						new_clusters);
++	if (ret) {
++		mlog_errno(ret);
++		goto out_commit;
++	}
++
++	ocfs2_update_super_and_backups(main_bm_inode, new_clusters);
++
++out_commit:
++	ocfs2_commit_trans(osb, handle);
++out_unlock:
++	brelse(group_bh);
++	brelse(main_bm_bh);
++
++	ocfs2_inode_unlock(main_bm_inode, 1);
++
++out_mutex:
++	mutex_unlock(&main_bm_inode->i_mutex);
++	iput(main_bm_inode);
++
++out:
++	mlog_exit_void();
++	return ret;
++}
++
++static int ocfs2_check_new_group(struct inode *inode,
++				 struct ocfs2_dinode *di,
++				 struct ocfs2_new_group_input *input,
++				 struct buffer_head *group_bh)
 +{
 +	int ret;
++	struct ocfs2_group_desc *gd;
++	u16 cl_bpc = le16_to_cpu(di->id2.i_chain.cl_bpc);
++	unsigned int max_bits = le16_to_cpu(di->id2.i_chain.cl_cpg) *
++				le16_to_cpu(di->id2.i_chain.cl_bpc);
 +
-+	ret = gfs2_writepage_common(page, wbc);
-+	if (ret <= 0)
-+		return ret;
 +
-+	ret = mpage_writepage(page, gfs2_get_block_noalloc, wbc);
-+	if (ret == -EAGAIN)
-+		ret = block_write_full_page(page, gfs2_get_block_noalloc, wbc);
++	gd = (struct ocfs2_group_desc *)group_bh->b_data;
++
++	ret = -EIO;
++	if (!OCFS2_IS_VALID_GROUP_DESC(gd))
++		mlog(ML_ERROR, "Group descriptor # %llu isn't valid.\n",
++		     (unsigned long long)le64_to_cpu(gd->bg_blkno));
++	else if (di->i_blkno != gd->bg_parent_dinode)
++		mlog(ML_ERROR, "Group descriptor # %llu has bad parent "
++		     "pointer (%llu, expected %llu)\n",
++		     (unsigned long long)le64_to_cpu(gd->bg_blkno),
++		     (unsigned long long)le64_to_cpu(gd->bg_parent_dinode),
++		     (unsigned long long)le64_to_cpu(di->i_blkno));
++	else if (le16_to_cpu(gd->bg_bits) > max_bits)
++		mlog(ML_ERROR, "Group descriptor # %llu has bit count of %u\n",
++		     (unsigned long long)le64_to_cpu(gd->bg_blkno),
++		     le16_to_cpu(gd->bg_bits));
++	else if (le16_to_cpu(gd->bg_free_bits_count) > le16_to_cpu(gd->bg_bits))
++		mlog(ML_ERROR, "Group descriptor # %llu has bit count %u but "
++		     "claims that %u are free\n",
++		     (unsigned long long)le64_to_cpu(gd->bg_blkno),
++		     le16_to_cpu(gd->bg_bits),
++		     le16_to_cpu(gd->bg_free_bits_count));
++	else if (le16_to_cpu(gd->bg_bits) > (8 * le16_to_cpu(gd->bg_size)))
++		mlog(ML_ERROR, "Group descriptor # %llu has bit count %u but "
++		     "max bitmap bits of %u\n",
++		     (unsigned long long)le64_to_cpu(gd->bg_blkno),
++		     le16_to_cpu(gd->bg_bits),
++		     8 * le16_to_cpu(gd->bg_size));
++	else if (le16_to_cpu(gd->bg_chain) != input->chain)
++		mlog(ML_ERROR, "Group descriptor # %llu has bad chain %u "
++		     "while input has %u set.\n",
++		     (unsigned long long)le64_to_cpu(gd->bg_blkno),
++		     le16_to_cpu(gd->bg_chain), input->chain);
++	else if (le16_to_cpu(gd->bg_bits) != input->clusters * cl_bpc)
++		mlog(ML_ERROR, "Group descriptor # %llu has bit count %u but "
++		     "input has %u clusters set\n",
++		     (unsigned long long)le64_to_cpu(gd->bg_blkno),
++		     le16_to_cpu(gd->bg_bits), input->clusters);
++	else if (le16_to_cpu(gd->bg_free_bits_count) != input->frees * cl_bpc)
++		mlog(ML_ERROR, "Group descriptor # %llu has free bit count %u "
++		     "but it should have %u set\n",
++		     (unsigned long long)le64_to_cpu(gd->bg_blkno),
++		     le16_to_cpu(gd->bg_bits),
++		     input->frees * cl_bpc);
++	else
++		ret = 0;
++
 +	return ret;
 +}
 +
-+/**
-+ * gfs2_ordered_writepage - Write page for ordered data files
-+ * @page: The page to write
-+ * @wbc: The writeback control
-+ *
-+ */
-+
-+static int gfs2_ordered_writepage(struct page *page,
-+				  struct writeback_control *wbc)
++static int ocfs2_verify_group_and_input(struct inode *inode,
++					struct ocfs2_dinode *di,
++					struct ocfs2_new_group_input *input,
++					struct buffer_head *group_bh)
 +{
-+	struct inode *inode = page->mapping->host;
-+	struct gfs2_inode *ip = GFS2_I(inode);
-+	int ret;
-+
-+	ret = gfs2_writepage_common(page, wbc);
-+	if (ret <= 0)
-+		return ret;
-+
-+	if (!page_has_buffers(page)) {
-+		create_empty_buffers(page, inode->i_sb->s_blocksize,
-+				     (1 << BH_Dirty)|(1 << BH_Uptodate));
- 	}
-+	gfs2_page_add_databufs(ip, page, 0, inode->i_sb->s_blocksize-1);
-+	return block_write_full_page(page, gfs2_get_block_noalloc, wbc);
-+}
- 
--	if ((sdp->sd_args.ar_data == GFS2_DATA_ORDERED || gfs2_is_jdata(ip)) &&
--	    PageChecked(page)) {
-+/**
-+ * __gfs2_jdata_writepage - The core of jdata writepage
-+ * @page: The page to write
-+ * @wbc: The writeback control
-+ *
-+ * This is shared between writepage and writepages and implements the
-+ * core of the writepage operation. If a transaction is required then
-+ * PageChecked will have been set and the transaction will have
-+ * already been started before this is called.
-+ */
++	u16 cl_count = le16_to_cpu(di->id2.i_chain.cl_count);
++	u16 cl_cpg = le16_to_cpu(di->id2.i_chain.cl_cpg);
++	u16 next_free = le16_to_cpu(di->id2.i_chain.cl_next_free_rec);
++	u32 cluster = ocfs2_blocks_to_clusters(inode->i_sb, input->group);
++	u32 total_clusters = le32_to_cpu(di->i_clusters);
++	int ret = -EINVAL;
 +
-+static int __gfs2_jdata_writepage(struct page *page, struct writeback_control *wbc)
-+{
-+	struct inode *inode = page->mapping->host;
-+	struct gfs2_inode *ip = GFS2_I(inode);
-+	struct gfs2_sbd *sdp = GFS2_SB(inode);
++	if (cluster < total_clusters)
++		mlog(ML_ERROR, "add a group which is in the current volume.\n");
++	else if (input->chain >= cl_count)
++		mlog(ML_ERROR, "input chain exceeds the limit.\n");
++	else if (next_free != cl_count && next_free != input->chain)
++		mlog(ML_ERROR,
++		     "the add group should be in chain %u\n", next_free);
++	else if (total_clusters + input->clusters < total_clusters)
++		mlog(ML_ERROR, "add group's clusters overflow.\n");
++	else if (input->clusters > cl_cpg)
++		mlog(ML_ERROR, "the cluster exceeds the maximum of a group\n");
++	else if (input->frees > input->clusters)
++		mlog(ML_ERROR, "the free cluster exceeds the total clusters\n");
++	else if (total_clusters % cl_cpg != 0)
++		mlog(ML_ERROR,
++		     "the last group isn't full. Use group extend first.\n");
++	else if (input->group != ocfs2_which_cluster_group(inode, cluster))
++		mlog(ML_ERROR, "group blkno is invalid\n");
++	else if ((ret = ocfs2_check_new_group(inode, di, input, group_bh)))
++		mlog(ML_ERROR, "group descriptor check failed.\n");
++	else
++		ret = 0;
 +
-+	if (PageChecked(page)) {
- 		ClearPageChecked(page);
--		error = gfs2_trans_begin(sdp, RES_DINODE + 1, 0);
--		if (error)
--			goto out_ignore;
- 		if (!page_has_buffers(page)) {
- 			create_empty_buffers(page, inode->i_sb->s_blocksize,
- 					     (1 << BH_Dirty)|(1 << BH_Uptodate));
- 		}
- 		gfs2_page_add_databufs(ip, page, 0, sdp->sd_vfs->s_blocksize-1);
-+	}
-+	return block_write_full_page(page, gfs2_get_block_noalloc, wbc);
++	return ret;
 +}
 +
-+/**
-+ * gfs2_jdata_writepage - Write complete page
-+ * @page: Page to write
-+ *
-+ * Returns: errno
-+ *
-+ */
-+
-+static int gfs2_jdata_writepage(struct page *page, struct writeback_control *wbc)
++/* Add a new group descriptor to global_bitmap. */
++int ocfs2_group_add(struct inode *inode, struct ocfs2_new_group_input *input)
 +{
-+	struct inode *inode = page->mapping->host;
-+	struct gfs2_sbd *sdp = GFS2_SB(inode);
-+	int error;
-+	int done_trans = 0;
-+
-+	error = gfs2_writepage_common(page, wbc);
-+	if (error <= 0)
-+		return error;
++	int ret;
++	handle_t *handle;
++	struct buffer_head *main_bm_bh = NULL;
++	struct inode *main_bm_inode = NULL;
++	struct ocfs2_dinode *fe = NULL;
++	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
++	struct buffer_head *group_bh = NULL;
++	struct ocfs2_group_desc *group = NULL;
++	struct ocfs2_chain_list *cl;
++	struct ocfs2_chain_rec *cr;
++	u16 cl_bpc;
 +
-+	if (PageChecked(page)) {
-+		if (wbc->sync_mode != WB_SYNC_ALL)
-+			goto out_ignore;
-+		error = gfs2_trans_begin(sdp, RES_DINODE + 1, 0);
-+		if (error)
-+			goto out_ignore;
- 		done_trans = 1;
- 	}
--	error = block_write_full_page(page, gfs2_get_block_noalloc, wbc);
-+	error = __gfs2_jdata_writepage(page, wbc);
- 	if (done_trans)
- 		gfs2_trans_end(sdp);
--	gfs2_meta_cache_flush(ip);
- 	return error;
- 
- out_ignore:
-@@ -164,29 +240,190 @@ out_ignore:
- }
- 
- /**
-- * gfs2_writepages - Write a bunch of dirty pages back to disk
-+ * gfs2_writeback_writepages - Write a bunch of dirty pages back to disk
-  * @mapping: The mapping to write
-  * @wbc: Write-back control
-  *
-- * For journaled files and/or ordered writes this just falls back to the
-- * kernel's default writepages path for now. We will probably want to change
-- * that eventually (i.e. when we look at allocate on flush).
-- *
-- * For the data=writeback case though we can already ignore buffer heads
-+ * For the data=writeback case we can already ignore buffer heads
-  * and write whole extents at once. This is a big reduction in the
-  * number of I/O requests we send and the bmap calls we make in this case.
-  */
--static int gfs2_writepages(struct address_space *mapping,
--			   struct writeback_control *wbc)
-+static int gfs2_writeback_writepages(struct address_space *mapping,
-+				     struct writeback_control *wbc)
-+{
-+	return mpage_writepages(mapping, wbc, gfs2_get_block_noalloc);
-+}
++	mlog_entry_void();
 +
-+/**
-+ * gfs2_write_jdata_pagevec - Write back a pagevec's worth of pages
-+ * @mapping: The mapping
-+ * @wbc: The writeback control
-+ * @writepage: The writepage function to call for each page
-+ * @pvec: The vector of pages
-+ * @nr_pages: The number of pages to write
-+ *
-+ * Returns: non-zero if loop should terminate, zero otherwise
-+ */
++	if (ocfs2_is_hard_readonly(osb) || ocfs2_is_soft_readonly(osb))
++		return -EROFS;
 +
-+static int gfs2_write_jdata_pagevec(struct address_space *mapping,
-+				    struct writeback_control *wbc,
-+				    struct pagevec *pvec,
-+				    int nr_pages, pgoff_t end)
- {
- 	struct inode *inode = mapping->host;
--	struct gfs2_inode *ip = GFS2_I(inode);
- 	struct gfs2_sbd *sdp = GFS2_SB(inode);
-+	loff_t i_size = i_size_read(inode);
-+	pgoff_t end_index = i_size >> PAGE_CACHE_SHIFT;
-+	unsigned offset = i_size & (PAGE_CACHE_SIZE-1);
-+	unsigned nrblocks = nr_pages * (PAGE_CACHE_SIZE/inode->i_sb->s_blocksize);
-+	struct backing_dev_info *bdi = mapping->backing_dev_info;
-+	int i;
-+	int ret;
++	main_bm_inode = ocfs2_get_system_file_inode(osb,
++						    GLOBAL_BITMAP_SYSTEM_INODE,
++						    OCFS2_INVALID_SLOT);
++	if (!main_bm_inode) {
++		ret = -EINVAL;
++		mlog_errno(ret);
++		goto out;
++	}
 +
-+	ret = gfs2_trans_begin(sdp, nrblocks, 0);
-+	if (ret < 0)
-+		return ret;
++	mutex_lock(&main_bm_inode->i_mutex);
 +
-+	for(i = 0; i < nr_pages; i++) {
-+		struct page *page = pvec->pages[i];
++	ret = ocfs2_inode_lock(main_bm_inode, &main_bm_bh, 1);
++	if (ret < 0) {
++		mlog_errno(ret);
++		goto out_mutex;
++	}
 +
-+		lock_page(page);
++	fe = (struct ocfs2_dinode *)main_bm_bh->b_data;
 +
-+		if (unlikely(page->mapping != mapping)) {
-+			unlock_page(page);
-+			continue;
-+		}
++	if (le16_to_cpu(fe->id2.i_chain.cl_cpg) !=
++				 ocfs2_group_bitmap_size(osb->sb) * 8) {
++		mlog(ML_ERROR, "The disk is too old and small."
++		     " Force to do offline resize.");
++		ret = -EINVAL;
++		goto out_unlock;
++	}
 +
-+		if (!wbc->range_cyclic && page->index > end) {
-+			ret = 1;
-+			unlock_page(page);
-+			continue;
-+		}
++	ret = ocfs2_read_block(osb, input->group, &group_bh, 0, NULL);
++	if (ret < 0) {
++		mlog(ML_ERROR, "Can't read the group descriptor # %llu "
++		     "from the device.", (unsigned long long)input->group);
++		goto out_unlock;
++	}
 +
-+		if (wbc->sync_mode != WB_SYNC_NONE)
-+			wait_on_page_writeback(page);
++	ocfs2_set_new_buffer_uptodate(inode, group_bh);
 +
-+		if (PageWriteback(page) ||
-+		    !clear_page_dirty_for_io(page)) {
-+			unlock_page(page);
-+			continue;
-+		}
++	ret = ocfs2_verify_group_and_input(main_bm_inode, fe, input, group_bh);
++	if (ret) {
++		mlog_errno(ret);
++		goto out_unlock;
++	}
 +
-+		/* Is the page fully outside i_size? (truncate in progress) */
-+		if (page->index > end_index || (page->index == end_index && !offset)) {
-+			page->mapping->a_ops->invalidatepage(page, 0);
-+			unlock_page(page);
-+			continue;
-+		}
++	mlog(0, "Add a new group  %llu in chain = %u, length = %u\n",
++	     (unsigned long long)input->group, input->chain, input->clusters);
 +
-+		ret = __gfs2_jdata_writepage(page, wbc);
++	handle = ocfs2_start_trans(osb, OCFS2_GROUP_ADD_CREDITS);
++	if (IS_ERR(handle)) {
++		mlog_errno(PTR_ERR(handle));
++		ret = -EINVAL;
++		goto out_unlock;
++	}
 +
-+		if (ret || (--(wbc->nr_to_write) <= 0))
-+			ret = 1;
-+		if (wbc->nonblocking && bdi_write_congested(bdi)) {
-+			wbc->encountered_congestion = 1;
-+			ret = 1;
-+		}
++	cl_bpc = le16_to_cpu(fe->id2.i_chain.cl_bpc);
++	cl = &fe->id2.i_chain;
++	cr = &cl->cl_recs[input->chain];
 +
++	ret = ocfs2_journal_access(handle, main_bm_inode, group_bh,
++				   OCFS2_JOURNAL_ACCESS_WRITE);
++	if (ret < 0) {
++		mlog_errno(ret);
++		goto out_commit;
 +	}
-+	gfs2_trans_end(sdp);
-+	return ret;
-+}
-+
-+/**
-+ * gfs2_write_cache_jdata - Like write_cache_pages but different
-+ * @mapping: The mapping to write
-+ * @wbc: The writeback control
-+ * @writepage: The writepage function to call
-+ * @data: The data to pass to writepage
-+ *
-+ * The reason that we use our own function here is that we need to
-+ * start transactions before we grab page locks. This allows us
-+ * to get the ordering right.
-+ */
 +
-+static int gfs2_write_cache_jdata(struct address_space *mapping,
-+				  struct writeback_control *wbc)
-+{
-+	struct backing_dev_info *bdi = mapping->backing_dev_info;
-+	int ret = 0;
-+	int done = 0;
-+	struct pagevec pvec;
-+	int nr_pages;
-+	pgoff_t index;
-+	pgoff_t end;
-+	int scanned = 0;
-+	int range_whole = 0;
++	group = (struct ocfs2_group_desc *)group_bh->b_data;
++	group->bg_next_group = cr->c_blkno;
 +
-+	if (wbc->nonblocking && bdi_write_congested(bdi)) {
-+		wbc->encountered_congestion = 1;
-+		return 0;
++	ret = ocfs2_journal_dirty(handle, group_bh);
++	if (ret < 0) {
++		mlog_errno(ret);
++		goto out_commit;
 +	}
 +
-+	pagevec_init(&pvec, 0);
-+	if (wbc->range_cyclic) {
-+		index = mapping->writeback_index; /* Start from prev offset */
-+		end = -1;
-+	} else {
-+		index = wbc->range_start >> PAGE_CACHE_SHIFT;
-+		end = wbc->range_end >> PAGE_CACHE_SHIFT;
-+		if (wbc->range_start == 0 && wbc->range_end == LLONG_MAX)
-+			range_whole = 1;
-+		scanned = 1;
++	ret = ocfs2_journal_access(handle, main_bm_inode, main_bm_bh,
++				   OCFS2_JOURNAL_ACCESS_WRITE);
++	if (ret < 0) {
++		mlog_errno(ret);
++		goto out_commit;
 +	}
- 
--	if (sdp->sd_args.ar_data == GFS2_DATA_WRITEBACK && !gfs2_is_jdata(ip))
--		return mpage_writepages(mapping, wbc, gfs2_get_block_noalloc);
-+retry:
-+	 while (!done && (index <= end) &&
-+		(nr_pages = pagevec_lookup_tag(&pvec, mapping, &index,
-+					       PAGECACHE_TAG_DIRTY,
-+					       min(end - index, (pgoff_t)PAGEVEC_SIZE-1) + 1))) {
-+		scanned = 1;
-+		ret = gfs2_write_jdata_pagevec(mapping, wbc, &pvec, nr_pages, end);
-+		if (ret)
-+			done = 1;
-+		if (ret > 0)
-+			ret = 0;
 +
-+		pagevec_release(&pvec);
-+		cond_resched();
++	if (input->chain == le16_to_cpu(cl->cl_next_free_rec)) {
++		le16_add_cpu(&cl->cl_next_free_rec, 1);
++		memset(cr, 0, sizeof(struct ocfs2_chain_rec));
 +	}
 +
-+	if (!scanned && !done) {
-+		/*
-+		 * We hit the last page and there is more work to be done: wrap
-+		 * back to the start of the file
-+		 */
-+		scanned = 1;
-+		index = 0;
-+		goto retry;
-+	}
++	cr->c_blkno = le64_to_cpu(input->group);
++	le32_add_cpu(&cr->c_total, input->clusters * cl_bpc);
++	le32_add_cpu(&cr->c_free, input->frees * cl_bpc);
 +
-+	if (wbc->range_cyclic || (range_whole && wbc->nr_to_write > 0))
-+		mapping->writeback_index = index;
-+	return ret;
-+}
++	le32_add_cpu(&fe->id1.bitmap1.i_total, input->clusters *cl_bpc);
++	le32_add_cpu(&fe->id1.bitmap1.i_used,
++		     (input->clusters - input->frees) * cl_bpc);
++	le32_add_cpu(&fe->i_clusters, input->clusters);
 +
++	ocfs2_journal_dirty(handle, main_bm_bh);
 +
-+/**
-+ * gfs2_jdata_writepages - Write a bunch of dirty pages back to disk
-+ * @mapping: The mapping to write
-+ * @wbc: The writeback control
-+ * 
-+ */
- 
--	return generic_writepages(mapping, wbc);
-+static int gfs2_jdata_writepages(struct address_space *mapping,
-+				 struct writeback_control *wbc)
-+{
-+	struct gfs2_inode *ip = GFS2_I(mapping->host);
-+	struct gfs2_sbd *sdp = GFS2_SB(mapping->host);
-+	int ret;
++	spin_lock(&OCFS2_I(main_bm_inode)->ip_lock);
++	OCFS2_I(main_bm_inode)->ip_clusters = le32_to_cpu(fe->i_clusters);
++	le64_add_cpu(&fe->i_size, input->clusters << osb->s_clustersize_bits);
++	spin_unlock(&OCFS2_I(main_bm_inode)->ip_lock);
++	i_size_write(main_bm_inode, le64_to_cpu(fe->i_size));
 +
-+	ret = gfs2_write_cache_jdata(mapping, wbc);
-+	if (ret == 0 && wbc->sync_mode == WB_SYNC_ALL) {
-+		gfs2_log_flush(sdp, ip->i_gl);
-+		ret = gfs2_write_cache_jdata(mapping, wbc);
-+	}
-+	return ret;
- }
- 
- /**
-@@ -231,62 +468,107 @@ static int stuffed_readpage(struct gfs2_inode *ip, struct page *page)
- 
- 
- /**
-- * gfs2_readpage - readpage with locking
-- * @file: The file to read a page for. N.B. This may be NULL if we are
-- * reading an internal file.
-+ * __gfs2_readpage - readpage
-+ * @file: The file to read a page for
-  * @page: The page to read
-  *
-- * Returns: errno
-+ * This is the core of gfs2's readpage. Its used by the internal file
-+ * reading code as in that case we already hold the glock. Also its
-+ * called by gfs2_readpage() once the required lock has been granted.
-+ *
-  */
- 
--static int gfs2_readpage(struct file *file, struct page *page)
-+static int __gfs2_readpage(void *file, struct page *page)
- {
- 	struct gfs2_inode *ip = GFS2_I(page->mapping->host);
- 	struct gfs2_sbd *sdp = GFS2_SB(page->mapping->host);
--	struct gfs2_file *gf = NULL;
--	struct gfs2_holder gh;
- 	int error;
--	int do_unlock = 0;
--
--	if (likely(file != &gfs2_internal_file_sentinel)) {
--		if (file) {
--			gf = file->private_data;
--			if (test_bit(GFF_EXLOCK, &gf->f_flags))
--				/* gfs2_sharewrite_fault has grabbed the ip->i_gl already */
--				goto skip_lock;
--		}
--		gfs2_holder_init(ip->i_gl, LM_ST_SHARED, GL_ATIME|LM_FLAG_TRY_1CB, &gh);
--		do_unlock = 1;
--		error = gfs2_glock_nq_atime(&gh);
--		if (unlikely(error))
--			goto out_unlock;
--	}
- 
--skip_lock:
- 	if (gfs2_is_stuffed(ip)) {
- 		error = stuffed_readpage(ip, page);
- 		unlock_page(page);
--	} else
--		error = mpage_readpage(page, gfs2_get_block);
-+	} else {
-+		error = mpage_readpage(page, gfs2_block_map);
-+	}
- 
- 	if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
--		error = -EIO;
-+		return -EIO;
++	ocfs2_update_super_and_backups(main_bm_inode, input->clusters);
 +
-+	return error;
-+}
++out_commit:
++	ocfs2_commit_trans(osb, handle);
++out_unlock:
++	brelse(group_bh);
++	brelse(main_bm_bh);
 +
-+/**
-+ * gfs2_readpage - read a page of a file
-+ * @file: The file to read
-+ * @page: The page of the file
-+ *
-+ * This deals with the locking required. We use a trylock in order to
-+ * avoid the page lock / glock ordering problems returning AOP_TRUNCATED_PAGE
-+ * in the event that we are unable to get the lock.
-+ */
++	ocfs2_inode_unlock(main_bm_inode, 1);
 +
-+static int gfs2_readpage(struct file *file, struct page *page)
-+{
-+	struct gfs2_inode *ip = GFS2_I(page->mapping->host);
-+	struct gfs2_holder gh;
-+	int error;
- 
--	if (do_unlock) {
--		gfs2_glock_dq_m(1, &gh);
--		gfs2_holder_uninit(&gh);
-+	gfs2_holder_init(ip->i_gl, LM_ST_SHARED, GL_ATIME|LM_FLAG_TRY_1CB, &gh);
-+	error = gfs2_glock_nq_atime(&gh);
-+	if (unlikely(error)) {
-+		unlock_page(page);
-+		goto out;
- 	}
-+	error = __gfs2_readpage(file, page);
-+	gfs2_glock_dq(&gh);
- out:
--	return error;
--out_unlock:
--	unlock_page(page);
-+	gfs2_holder_uninit(&gh);
- 	if (error == GLR_TRYFAILED) {
--		error = AOP_TRUNCATED_PAGE;
- 		yield();
-+		return AOP_TRUNCATED_PAGE;
- 	}
--	if (do_unlock)
--		gfs2_holder_uninit(&gh);
--	goto out;
-+	return error;
-+}
++out_mutex:
++	mutex_unlock(&main_bm_inode->i_mutex);
++	iput(main_bm_inode);
 +
-+/**
-+ * gfs2_internal_read - read an internal file
-+ * @ip: The gfs2 inode
-+ * @ra_state: The readahead state (or NULL for no readahead)
-+ * @buf: The buffer to fill
-+ * @pos: The file position
-+ * @size: The amount to read
++out:
++	mlog_exit_void();
++	return ret;
++}
+diff --git a/fs/ocfs2/resize.h b/fs/ocfs2/resize.h
+new file mode 100644
+index 0000000..f38841a
+--- /dev/null
++++ b/fs/ocfs2/resize.h
+@@ -0,0 +1,32 @@
++/* -*- mode: c; c-basic-offset: 8; -*-
++ * vim: noexpandtab sw=8 ts=8 sts=0:
++ *
++ * resize.h
++ *
++ * Function prototypes
 + *
++ * Copyright (C) 2007 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.
 + */
 +
-+int gfs2_internal_read(struct gfs2_inode *ip, struct file_ra_state *ra_state,
-+                       char *buf, loff_t *pos, unsigned size)
-+{
-+	struct address_space *mapping = ip->i_inode.i_mapping;
-+	unsigned long index = *pos / PAGE_CACHE_SIZE;
-+	unsigned offset = *pos & (PAGE_CACHE_SIZE - 1);
-+	unsigned copied = 0;
-+	unsigned amt;
-+	struct page *page;
-+	void *p;
++#ifndef OCFS2_RESIZE_H
++#define OCFS2_RESIZE_H
 +
-+	do {
-+		amt = size - copied;
-+		if (offset + size > PAGE_CACHE_SIZE)
-+			amt = PAGE_CACHE_SIZE - offset;
-+		page = read_cache_page(mapping, index, __gfs2_readpage, NULL);
-+		if (IS_ERR(page))
-+			return PTR_ERR(page);
-+		p = kmap_atomic(page, KM_USER0);
-+		memcpy(buf + copied, p + offset, amt);
-+		kunmap_atomic(p, KM_USER0);
-+		mark_page_accessed(page);
-+		page_cache_release(page);
-+		copied += amt;
-+		index++;
-+		offset = 0;
-+	} while(copied < size);
-+	(*pos) += size;
-+	return size;
- }
- 
- /**
-@@ -300,10 +582,9 @@ out_unlock:
-  *    Any I/O we ignore at this time will be done via readpage later.
-  * 2. We don't handle stuffed files here we let readpage do the honours.
-  * 3. mpage_readpages() does most of the heavy lifting in the common case.
-- * 4. gfs2_get_block() is relied upon to set BH_Boundary in the right places.
-- * 5. We use LM_FLAG_TRY_1CB here, effectively we then have lock-ahead as
-- *    well as read-ahead.
-+ * 4. gfs2_block_map() is relied upon to set BH_Boundary in the right places.
-  */
++int ocfs2_group_extend(struct inode * inode, int new_clusters);
++int ocfs2_group_add(struct inode *inode, struct ocfs2_new_group_input *input);
 +
- static int gfs2_readpages(struct file *file, struct address_space *mapping,
- 			  struct list_head *pages, unsigned nr_pages)
- {
-@@ -311,42 +592,20 @@ static int gfs2_readpages(struct file *file, struct address_space *mapping,
- 	struct gfs2_inode *ip = GFS2_I(inode);
- 	struct gfs2_sbd *sdp = GFS2_SB(inode);
- 	struct gfs2_holder gh;
--	int ret = 0;
--	int do_unlock = 0;
-+	int ret;
++#endif /* OCFS2_RESIZE_H */
+diff --git a/fs/ocfs2/slot_map.c b/fs/ocfs2/slot_map.c
+index af4882b..3a50ce5 100644
+--- a/fs/ocfs2/slot_map.c
++++ b/fs/ocfs2/slot_map.c
+@@ -48,25 +48,6 @@ static void __ocfs2_fill_slot(struct ocfs2_slot_info *si,
+ 			      s16 slot_num,
+ 			      s16 node_num);
  
--	if (likely(file != &gfs2_internal_file_sentinel)) {
--		if (file) {
--			struct gfs2_file *gf = file->private_data;
--			if (test_bit(GFF_EXLOCK, &gf->f_flags))
--				goto skip_lock;
--		}
--		gfs2_holder_init(ip->i_gl, LM_ST_SHARED,
--				 LM_FLAG_TRY_1CB|GL_ATIME, &gh);
--		do_unlock = 1;
--		ret = gfs2_glock_nq_atime(&gh);
--		if (ret == GLR_TRYFAILED)
--			goto out_noerror;
--		if (unlikely(ret))
--			goto out_unlock;
--	}
--skip_lock:
-+	gfs2_holder_init(ip->i_gl, LM_ST_SHARED, GL_ATIME, &gh);
-+	ret = gfs2_glock_nq_atime(&gh);
-+	if (unlikely(ret))
-+		goto out_uninit;
- 	if (!gfs2_is_stuffed(ip))
--		ret = mpage_readpages(mapping, pages, nr_pages, gfs2_get_block);
+-/* Use the slot information we've collected to create a map of mounted
+- * nodes. Should be holding an EX on super block. assumes slot info is
+- * up to date. Note that we call this *after* we find a slot, so our
+- * own node should be set in the map too... */
+-void ocfs2_populate_mounted_map(struct ocfs2_super *osb)
+-{
+-	int i;
+-	struct ocfs2_slot_info *si = osb->slot_info;
 -
--	if (do_unlock) {
--		gfs2_glock_dq_m(1, &gh);
--		gfs2_holder_uninit(&gh);
--	}
--out:
-+		ret = mpage_readpages(mapping, pages, nr_pages, gfs2_block_map);
-+	gfs2_glock_dq(&gh);
-+out_uninit:
-+	gfs2_holder_uninit(&gh);
- 	if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
- 		ret = -EIO;
- 	return ret;
--out_noerror:
--	ret = 0;
--out_unlock:
--	if (do_unlock)
--		gfs2_holder_uninit(&gh);
--	goto out;
- }
- 
- /**
-@@ -382,20 +641,11 @@ static int gfs2_write_begin(struct file *file, struct address_space *mapping,
- 	if (unlikely(error))
- 		goto out_uninit;
- 
--	error = -ENOMEM;
--	page = __grab_cache_page(mapping, index);
--	*pagep = page;
--	if (!page)
--		goto out_unlock;
+-	spin_lock(&si->si_lock);
 -
- 	gfs2_write_calc_reserv(ip, len, &data_blocks, &ind_blocks);
+-	for (i = 0; i < si->si_size; i++)
+-		if (si->si_global_node_nums[i] != OCFS2_INVALID_SLOT)
+-			ocfs2_node_map_set_bit(osb, &osb->mounted_map,
+-					      si->si_global_node_nums[i]);
 -
- 	error = gfs2_write_alloc_required(ip, pos, len, &alloc_required);
- 	if (error)
--		goto out_putpage;
+-	spin_unlock(&si->si_lock);
+-}
 -
-+		goto out_unlock;
+ /* post the slot information on disk into our slot_info struct. */
+ void ocfs2_update_slot_info(struct ocfs2_slot_info *si)
+ {
+diff --git a/fs/ocfs2/slot_map.h b/fs/ocfs2/slot_map.h
+index d8c8cee..1025872 100644
+--- a/fs/ocfs2/slot_map.h
++++ b/fs/ocfs2/slot_map.h
+@@ -52,8 +52,6 @@ s16 ocfs2_node_num_to_slot(struct ocfs2_slot_info *si,
+ void ocfs2_clear_slot(struct ocfs2_slot_info *si,
+ 		      s16 slot_num);
  
--	ip->i_alloc.al_requested = 0;
- 	if (alloc_required) {
- 		al = gfs2_alloc_get(ip);
+-void ocfs2_populate_mounted_map(struct ocfs2_super *osb);
+-
+ static inline int ocfs2_is_empty_slot(struct ocfs2_slot_info *si,
+ 				      int slot_num)
+ {
+diff --git a/fs/ocfs2/suballoc.c b/fs/ocfs2/suballoc.c
+index 8f09f52..7e397e2 100644
+--- a/fs/ocfs2/suballoc.c
++++ b/fs/ocfs2/suballoc.c
+@@ -101,8 +101,6 @@ static inline int ocfs2_block_group_reasonably_empty(struct ocfs2_group_desc *bg
+ static inline u32 ocfs2_desc_bitmap_to_cluster_off(struct inode *inode,
+ 						   u64 bg_blkno,
+ 						   u16 bg_bit_off);
+-static inline u64 ocfs2_which_cluster_group(struct inode *inode,
+-					    u32 cluster);
+ static inline void ocfs2_block_to_cluster_group(struct inode *inode,
+ 						u64 data_blkno,
+ 						u64 *bg_blkno,
+@@ -114,7 +112,7 @@ void ocfs2_free_alloc_context(struct ocfs2_alloc_context *ac)
  
-@@ -424,40 +674,47 @@ static int gfs2_write_begin(struct file *file, struct address_space *mapping,
- 	if (error)
- 		goto out_trans_fail;
+ 	if (inode) {
+ 		if (ac->ac_which != OCFS2_AC_USE_LOCAL)
+-			ocfs2_meta_unlock(inode, 1);
++			ocfs2_inode_unlock(inode, 1);
  
-+	error = -ENOMEM;
-+	page = __grab_cache_page(mapping, index);
-+	*pagep = page;
-+	if (unlikely(!page))
-+		goto out_endtrans;
-+
- 	if (gfs2_is_stuffed(ip)) {
-+		error = 0;
- 		if (pos + len > sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode)) {
- 			error = gfs2_unstuff_dinode(ip, page);
- 			if (error == 0)
- 				goto prepare_write;
--		} else if (!PageUptodate(page))
-+		} else if (!PageUptodate(page)) {
- 			error = stuffed_readpage(ip, page);
-+		}
- 		goto out;
- 	}
+ 		mutex_unlock(&inode->i_mutex);
  
- prepare_write:
--	error = block_prepare_write(page, from, to, gfs2_get_block);
--
-+	error = block_prepare_write(page, from, to, gfs2_block_map);
- out:
--	if (error) {
--		gfs2_trans_end(sdp);
-+	if (error == 0)
-+		return 0;
-+
-+	page_cache_release(page);
-+	if (pos + len > ip->i_inode.i_size)
-+		vmtruncate(&ip->i_inode, ip->i_inode.i_size);
-+out_endtrans:
-+	gfs2_trans_end(sdp);
- out_trans_fail:
--		if (alloc_required) {
--			gfs2_inplace_release(ip);
-+	if (alloc_required) {
-+		gfs2_inplace_release(ip);
- out_qunlock:
--			gfs2_quota_unlock(ip);
-+		gfs2_quota_unlock(ip);
- out_alloc_put:
--			gfs2_alloc_put(ip);
--		}
--out_putpage:
--		page_cache_release(page);
--		if (pos + len > ip->i_inode.i_size)
--			vmtruncate(&ip->i_inode, ip->i_inode.i_size);
-+		gfs2_alloc_put(ip);
-+	}
- out_unlock:
--		gfs2_glock_dq_m(1, &ip->i_gh);
-+	gfs2_glock_dq(&ip->i_gh);
- out_uninit:
--		gfs2_holder_uninit(&ip->i_gh);
--	}
--
-+	gfs2_holder_uninit(&ip->i_gh);
- 	return error;
+@@ -131,9 +129,9 @@ static u32 ocfs2_bits_per_group(struct ocfs2_chain_list *cl)
  }
  
-@@ -565,7 +822,7 @@ static int gfs2_write_end(struct file *file, struct address_space *mapping,
- 	struct gfs2_inode *ip = GFS2_I(inode);
- 	struct gfs2_sbd *sdp = GFS2_SB(inode);
- 	struct buffer_head *dibh;
--	struct gfs2_alloc *al = &ip->i_alloc;
-+	struct gfs2_alloc *al = ip->i_alloc;
- 	struct gfs2_dinode *di;
- 	unsigned int from = pos & (PAGE_CACHE_SIZE - 1);
- 	unsigned int to = from + len;
-@@ -585,19 +842,16 @@ static int gfs2_write_end(struct file *file, struct address_space *mapping,
- 	if (gfs2_is_stuffed(ip))
- 		return gfs2_stuffed_write_end(inode, dibh, pos, len, copied, page);
+ /* somewhat more expensive than our other checks, so use sparingly. */
+-static int ocfs2_check_group_descriptor(struct super_block *sb,
+-					struct ocfs2_dinode *di,
+-					struct ocfs2_group_desc *gd)
++int ocfs2_check_group_descriptor(struct super_block *sb,
++				 struct ocfs2_dinode *di,
++				 struct ocfs2_group_desc *gd)
+ {
+ 	unsigned int max_bits;
  
--	if (sdp->sd_args.ar_data == GFS2_DATA_ORDERED || gfs2_is_jdata(ip))
-+	if (!gfs2_is_writeback(ip))
- 		gfs2_page_add_databufs(ip, page, from, to);
+@@ -412,7 +410,7 @@ static int ocfs2_reserve_suballoc_bits(struct ocfs2_super *osb,
  
- 	ret = generic_write_end(file, mapping, pos, len, copied, page, fsdata);
+ 	mutex_lock(&alloc_inode->i_mutex);
  
--	if (likely(ret >= 0)) {
--		copied = ret;
--		if  ((pos + copied) > inode->i_size) {
--			di = (struct gfs2_dinode *)dibh->b_data;
--			ip->i_di.di_size = inode->i_size;
--			di->di_size = cpu_to_be64(inode->i_size);
--			mark_inode_dirty(inode);
--		}
-+	if (likely(ret >= 0) && (inode->i_size > ip->i_di.di_size)) {
-+		di = (struct gfs2_dinode *)dibh->b_data;
-+		ip->i_di.di_size = inode->i_size;
-+		di->di_size = cpu_to_be64(inode->i_size);
-+		mark_inode_dirty(inode);
- 	}
+-	status = ocfs2_meta_lock(alloc_inode, &bh, 1);
++	status = ocfs2_inode_lock(alloc_inode, &bh, 1);
+ 	if (status < 0) {
+ 		mutex_unlock(&alloc_inode->i_mutex);
+ 		iput(alloc_inode);
+@@ -1443,8 +1441,7 @@ static inline u32 ocfs2_desc_bitmap_to_cluster_off(struct inode *inode,
  
- 	if (inode == sdp->sd_rindex)
-@@ -606,7 +860,7 @@ static int gfs2_write_end(struct file *file, struct address_space *mapping,
- 	brelse(dibh);
- 	gfs2_trans_end(sdp);
- failed:
--	if (al->al_requested) {
-+	if (al) {
- 		gfs2_inplace_release(ip);
- 		gfs2_quota_unlock(ip);
- 		gfs2_alloc_put(ip);
-@@ -625,11 +879,7 @@ failed:
-  
- static int gfs2_set_page_dirty(struct page *page)
+ /* given a cluster offset, calculate which block group it belongs to
+  * and return that block offset. */
+-static inline u64 ocfs2_which_cluster_group(struct inode *inode,
+-					    u32 cluster)
++u64 ocfs2_which_cluster_group(struct inode *inode, u32 cluster)
  {
--	struct gfs2_inode *ip = GFS2_I(page->mapping->host);
--	struct gfs2_sbd *sdp = GFS2_SB(page->mapping->host);
--
--	if (sdp->sd_args.ar_data == GFS2_DATA_ORDERED || gfs2_is_jdata(ip))
--		SetPageChecked(page);
-+	SetPageChecked(page);
- 	return __set_page_dirty_buffers(page);
- }
+ 	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+ 	u32 group_no;
+@@ -1519,8 +1516,9 @@ int __ocfs2_claim_clusters(struct ocfs2_super *osb,
+ 		if (min_clusters > (osb->bitmap_cpg - 1)) {
+ 			/* The only paths asking for contiguousness
+ 			 * should know about this already. */
+-			mlog(ML_ERROR, "minimum allocation requested exceeds "
+-				       "group bitmap size!");
++			mlog(ML_ERROR, "minimum allocation requested %u exceeds "
++			     "group bitmap size %u!\n", min_clusters,
++			     osb->bitmap_cpg);
+ 			status = -ENOSPC;
+ 			goto bail;
+ 		}
+diff --git a/fs/ocfs2/suballoc.h b/fs/ocfs2/suballoc.h
+index cafe937..8799033 100644
+--- a/fs/ocfs2/suballoc.h
++++ b/fs/ocfs2/suballoc.h
+@@ -147,4 +147,12 @@ static inline int ocfs2_is_cluster_bitmap(struct inode *inode)
+ int ocfs2_reserve_cluster_bitmap_bits(struct ocfs2_super *osb,
+ 				      struct ocfs2_alloc_context *ac);
  
-@@ -653,7 +903,7 @@ static sector_t gfs2_bmap(struct address_space *mapping, sector_t lblock)
- 		return 0;
++/* given a cluster offset, calculate which block group it belongs to
++ * and return that block offset. */
++u64 ocfs2_which_cluster_group(struct inode *inode, u32 cluster);
++
++/* somewhat more expensive than our other checks, so use sparingly. */
++int ocfs2_check_group_descriptor(struct super_block *sb,
++				 struct ocfs2_dinode *di,
++				 struct ocfs2_group_desc *gd);
+ #endif /* _CHAINALLOC_H_ */
+diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c
+index 5ee7754..01fe40e 100644
+--- a/fs/ocfs2/super.c
++++ b/fs/ocfs2/super.c
+@@ -65,7 +65,6 @@
+ #include "sysfile.h"
+ #include "uptodate.h"
+ #include "ver.h"
+-#include "vote.h"
  
- 	if (!gfs2_is_stuffed(ip))
--		dblock = generic_block_bmap(mapping, lblock, gfs2_get_block);
-+		dblock = generic_block_bmap(mapping, lblock, gfs2_block_map);
+ #include "buffer_head_io.h"
  
- 	gfs2_glock_dq_uninit(&i_gh);
+@@ -84,9 +83,11 @@ MODULE_LICENSE("GPL");
  
-@@ -719,13 +969,9 @@ static int gfs2_ok_for_dio(struct gfs2_inode *ip, int rw, loff_t offset)
+ struct mount_options
  {
- 	/*
- 	 * Should we return an error here? I can't see that O_DIRECT for
--	 * a journaled file makes any sense. For now we'll silently fall
--	 * back to buffered I/O, likewise we do the same for stuffed
--	 * files since they are (a) small and (b) unaligned.
-+	 * a stuffed file makes any sense. For now we'll silently fall
-+	 * back to buffered I/O
- 	 */
--	if (gfs2_is_jdata(ip))
--		return 0;
--
- 	if (gfs2_is_stuffed(ip))
- 		return 0;
++	unsigned long	commit_interval;
+ 	unsigned long	mount_opt;
+ 	unsigned int	atime_quantum;
+ 	signed short	slot;
++	unsigned int	localalloc_opt;
+ };
  
-@@ -836,9 +1082,23 @@ cannot_release:
- 	return 0;
- }
+ static int ocfs2_parse_options(struct super_block *sb, char *options,
+@@ -150,6 +151,9 @@ enum {
+ 	Opt_data_writeback,
+ 	Opt_atime_quantum,
+ 	Opt_slot,
++	Opt_commit,
++	Opt_localalloc,
++	Opt_localflocks,
+ 	Opt_err,
+ };
  
--const struct address_space_operations gfs2_file_aops = {
--	.writepage = gfs2_writepage,
--	.writepages = gfs2_writepages,
-+static const struct address_space_operations gfs2_writeback_aops = {
-+	.writepage = gfs2_writeback_writepage,
-+	.writepages = gfs2_writeback_writepages,
-+	.readpage = gfs2_readpage,
-+	.readpages = gfs2_readpages,
-+	.sync_page = block_sync_page,
-+	.write_begin = gfs2_write_begin,
-+	.write_end = gfs2_write_end,
-+	.bmap = gfs2_bmap,
-+	.invalidatepage = gfs2_invalidatepage,
-+	.releasepage = gfs2_releasepage,
-+	.direct_IO = gfs2_direct_IO,
-+	.migratepage = buffer_migrate_page,
-+};
-+
-+static const struct address_space_operations gfs2_ordered_aops = {
-+	.writepage = gfs2_ordered_writepage,
- 	.readpage = gfs2_readpage,
- 	.readpages = gfs2_readpages,
- 	.sync_page = block_sync_page,
-@@ -849,5 +1109,34 @@ const struct address_space_operations gfs2_file_aops = {
- 	.invalidatepage = gfs2_invalidatepage,
- 	.releasepage = gfs2_releasepage,
- 	.direct_IO = gfs2_direct_IO,
-+	.migratepage = buffer_migrate_page,
+@@ -165,6 +169,9 @@ static match_table_t tokens = {
+ 	{Opt_data_writeback, "data=writeback"},
+ 	{Opt_atime_quantum, "atime_quantum=%u"},
+ 	{Opt_slot, "preferred_slot=%u"},
++	{Opt_commit, "commit=%u"},
++	{Opt_localalloc, "localalloc=%d"},
++	{Opt_localflocks, "localflocks"},
+ 	{Opt_err, NULL}
  };
  
-+static const struct address_space_operations gfs2_jdata_aops = {
-+	.writepage = gfs2_jdata_writepage,
-+	.writepages = gfs2_jdata_writepages,
-+	.readpage = gfs2_readpage,
-+	.readpages = gfs2_readpages,
-+	.sync_page = block_sync_page,
-+	.write_begin = gfs2_write_begin,
-+	.write_end = gfs2_write_end,
-+	.set_page_dirty = gfs2_set_page_dirty,
-+	.bmap = gfs2_bmap,
-+	.invalidatepage = gfs2_invalidatepage,
-+	.releasepage = gfs2_releasepage,
-+};
-+
-+void gfs2_set_aops(struct inode *inode)
-+{
-+	struct gfs2_inode *ip = GFS2_I(inode);
-+
-+	if (gfs2_is_writeback(ip))
-+		inode->i_mapping->a_ops = &gfs2_writeback_aops;
-+	else if (gfs2_is_ordered(ip))
-+		inode->i_mapping->a_ops = &gfs2_ordered_aops;
-+	else if (gfs2_is_jdata(ip))
-+		inode->i_mapping->a_ops = &gfs2_jdata_aops;
-+	else
-+		BUG();
-+}
-+
-diff --git a/fs/gfs2/ops_address.h b/fs/gfs2/ops_address.h
-index fa1b5b3..5da2128 100644
---- a/fs/gfs2/ops_address.h
-+++ b/fs/gfs2/ops_address.h
-@@ -14,9 +14,10 @@
- #include <linux/buffer_head.h>
- #include <linux/mm.h>
+@@ -213,7 +220,7 @@ static int ocfs2_init_global_system_inodes(struct ocfs2_super *osb)
+ 
+ 	mlog_entry_void();
+ 
+-	new = ocfs2_iget(osb, osb->root_blkno, OCFS2_FI_FLAG_SYSFILE);
++	new = ocfs2_iget(osb, osb->root_blkno, OCFS2_FI_FLAG_SYSFILE, 0);
+ 	if (IS_ERR(new)) {
+ 		status = PTR_ERR(new);
+ 		mlog_errno(status);
+@@ -221,7 +228,7 @@ static int ocfs2_init_global_system_inodes(struct ocfs2_super *osb)
+ 	}
+ 	osb->root_inode = new;
+ 
+-	new = ocfs2_iget(osb, osb->system_dir_blkno, OCFS2_FI_FLAG_SYSFILE);
++	new = ocfs2_iget(osb, osb->system_dir_blkno, OCFS2_FI_FLAG_SYSFILE, 0);
+ 	if (IS_ERR(new)) {
+ 		status = PTR_ERR(new);
+ 		mlog_errno(status);
+@@ -443,6 +450,8 @@ unlock_osb:
+ 		osb->s_mount_opt = parsed_options.mount_opt;
+ 		osb->s_atime_quantum = parsed_options.atime_quantum;
+ 		osb->preferred_slot = parsed_options.slot;
++		if (parsed_options.commit_interval)
++			osb->osb_commit_interval = parsed_options.commit_interval;
  
--extern const struct address_space_operations gfs2_file_aops;
--extern int gfs2_get_block(struct inode *inode, sector_t lblock,
--			  struct buffer_head *bh_result, int create);
- extern int gfs2_releasepage(struct page *page, gfp_t gfp_mask);
-+extern int gfs2_internal_read(struct gfs2_inode *ip,
-+			      struct file_ra_state *ra_state,
-+			      char *buf, loff_t *pos, unsigned size);
-+extern void gfs2_set_aops(struct inode *inode);
+ 		if (!ocfs2_is_hard_readonly(osb))
+ 			ocfs2_set_journal_params(osb);
+@@ -597,6 +606,8 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent)
+ 	osb->s_mount_opt = parsed_options.mount_opt;
+ 	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;
  
- #endif /* __OPS_ADDRESS_DOT_H__ */
-diff --git a/fs/gfs2/ops_file.c b/fs/gfs2/ops_file.c
-index bb11fd6..f4842f2 100644
---- a/fs/gfs2/ops_file.c
-+++ b/fs/gfs2/ops_file.c
-@@ -33,57 +33,12 @@
- #include "lm.h"
- #include "log.h"
- #include "meta_io.h"
--#include "ops_file.h"
--#include "ops_vm.h"
- #include "quota.h"
- #include "rgrp.h"
- #include "trans.h"
- #include "util.h"
- #include "eaops.h"
--
--/*
-- * Most fields left uninitialised to catch anybody who tries to
-- * use them. f_flags set to prevent file_accessed() from touching
-- * any other part of this. Its use is purely as a flag so that we
-- * know (in readpage()) whether or not do to locking.
-- */
--struct file gfs2_internal_file_sentinel = {
--	.f_flags = O_NOATIME|O_RDONLY,
--};
--
--static int gfs2_read_actor(read_descriptor_t *desc, struct page *page,
--			   unsigned long offset, unsigned long size)
--{
--	char *kaddr;
--	unsigned long count = desc->count;
--
--	if (size > count)
--		size = count;
--
--	kaddr = kmap(page);
--	memcpy(desc->arg.data, kaddr + offset, size);
--	kunmap(page);
--
--	desc->count = count - size;
--	desc->written += size;
--	desc->arg.buf += size;
--	return size;
--}
--
--int gfs2_internal_read(struct gfs2_inode *ip, struct file_ra_state *ra_state,
--		       char *buf, loff_t *pos, unsigned size)
--{
--	struct inode *inode = &ip->i_inode;
--	read_descriptor_t desc;
--	desc.written = 0;
--	desc.arg.data = buf;
--	desc.count = size;
--	desc.error = 0;
--	do_generic_mapping_read(inode->i_mapping, ra_state,
--				&gfs2_internal_file_sentinel, pos, &desc,
--				gfs2_read_actor);
--	return desc.written ? desc.written : desc.error;
--}
-+#include "ops_address.h"
+ 	sb->s_magic = OCFS2_SUPER_MAGIC;
  
- /**
-  * gfs2_llseek - seek to a location in a file
-@@ -214,7 +169,7 @@ static int gfs2_get_flags(struct file *filp, u32 __user *ptr)
- 	if (put_user(fsflags, ptr))
- 		error = -EFAULT;
+@@ -747,9 +758,11 @@ static int ocfs2_parse_options(struct super_block *sb,
+ 	mlog_entry("remount: %d, options: \"%s\"\n", is_remount,
+ 		   options ? options : "(none)");
  
--	gfs2_glock_dq_m(1, &gh);
-+	gfs2_glock_dq(&gh);
- 	gfs2_holder_uninit(&gh);
- 	return error;
- }
-@@ -291,7 +246,16 @@ static int do_gfs2_set_flags(struct file *filp, u32 reqflags, u32 mask)
- 		if (error)
- 			goto out;
- 	}
--
-+	if ((flags ^ new_flags) & GFS2_DIF_JDATA) {
-+		if (flags & GFS2_DIF_JDATA)
-+			gfs2_log_flush(sdp, ip->i_gl);
-+		error = filemap_fdatawrite(inode->i_mapping);
-+		if (error)
-+			goto out;
-+		error = filemap_fdatawait(inode->i_mapping);
-+		if (error)
-+			goto out;
-+	}
- 	error = gfs2_trans_begin(sdp, RES_DINODE, 0);
- 	if (error)
- 		goto out;
-@@ -303,6 +267,7 @@ static int do_gfs2_set_flags(struct file *filp, u32 reqflags, u32 mask)
- 	gfs2_dinode_out(ip, bh->b_data);
- 	brelse(bh);
- 	gfs2_set_inode_flags(inode);
-+	gfs2_set_aops(inode);
- out_trans_end:
- 	gfs2_trans_end(sdp);
- out:
-@@ -338,6 +303,128 @@ static long gfs2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
- 	return -ENOTTY;
- }
++	mopt->commit_interval = 0;
+ 	mopt->mount_opt = 0;
+ 	mopt->atime_quantum = OCFS2_DEFAULT_ATIME_QUANTUM;
+ 	mopt->slot = OCFS2_INVALID_SLOT;
++	mopt->localalloc_opt = OCFS2_DEFAULT_LOCAL_ALLOC_SIZE;
  
-+/**
-+ * gfs2_allocate_page_backing - Use bmap to allocate blocks
-+ * @page: The (locked) page to allocate backing for
-+ *
-+ * We try to allocate all the blocks required for the page in
-+ * one go. This might fail for various reasons, so we keep
-+ * trying until all the blocks to back this page are allocated.
-+ * If some of the blocks are already allocated, thats ok too.
-+ */
-+
-+static int gfs2_allocate_page_backing(struct page *page)
-+{
-+	struct inode *inode = page->mapping->host;
-+	struct buffer_head bh;
-+	unsigned long size = PAGE_CACHE_SIZE;
-+	u64 lblock = page->index << (PAGE_CACHE_SHIFT - inode->i_blkbits);
-+
-+	do {
-+		bh.b_state = 0;
-+		bh.b_size = size;
-+		gfs2_block_map(inode, lblock, &bh, 1);
-+		if (!buffer_mapped(&bh))
-+			return -EIO;
-+		size -= bh.b_size;
-+		lblock += (bh.b_size >> inode->i_blkbits);
-+	} while(size > 0);
-+	return 0;
-+}
-+
-+/**
-+ * gfs2_page_mkwrite - Make a shared, mmap()ed, page writable
-+ * @vma: The virtual memory area
-+ * @page: The page which is about to become writable
-+ *
-+ * When the page becomes writable, we need to ensure that we have
-+ * blocks allocated on disk to back that page.
-+ */
-+
-+static int gfs2_page_mkwrite(struct vm_area_struct *vma, struct page *page)
-+{
-+	struct inode *inode = vma->vm_file->f_path.dentry->d_inode;
-+	struct gfs2_inode *ip = GFS2_I(inode);
-+	struct gfs2_sbd *sdp = GFS2_SB(inode);
-+	unsigned long last_index;
-+	u64 pos = page->index << (PAGE_CACHE_SIZE - inode->i_blkbits);
-+	unsigned int data_blocks, ind_blocks, rblocks;
-+	int alloc_required = 0;
-+	struct gfs2_holder gh;
-+	struct gfs2_alloc *al;
-+	int ret;
-+
-+	gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, GL_ATIME, &gh);
-+	ret = gfs2_glock_nq_atime(&gh);
-+	if (ret)
-+		goto out;
-+
-+	set_bit(GIF_SW_PAGED, &ip->i_flags);
-+	gfs2_write_calc_reserv(ip, PAGE_CACHE_SIZE, &data_blocks, &ind_blocks);
-+	ret = gfs2_write_alloc_required(ip, pos, PAGE_CACHE_SIZE, &alloc_required);
-+	if (ret || !alloc_required)
-+		goto out_unlock;
-+	ret = -ENOMEM;
-+	al = gfs2_alloc_get(ip);
-+	if (al == NULL)
-+		goto out_unlock;
-+
-+	ret = gfs2_quota_lock(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE);
-+	if (ret)
-+		goto out_alloc_put;
-+	ret = gfs2_quota_check(ip, ip->i_inode.i_uid, ip->i_inode.i_gid);
-+	if (ret)
-+		goto out_quota_unlock;
-+	al->al_requested = data_blocks + ind_blocks;
-+	ret = gfs2_inplace_reserve(ip);
-+	if (ret)
-+		goto out_quota_unlock;
-+
-+	rblocks = RES_DINODE + ind_blocks;
-+	if (gfs2_is_jdata(ip))
-+		rblocks += data_blocks ? data_blocks : 1;
-+	if (ind_blocks || data_blocks)
-+		rblocks += RES_STATFS + RES_QUOTA;
-+	ret = gfs2_trans_begin(sdp, rblocks, 0);
-+	if (ret)
-+		goto out_trans_fail;
-+
-+	lock_page(page);
-+	ret = -EINVAL;
-+	last_index = ip->i_inode.i_size >> PAGE_CACHE_SHIFT;
-+	if (page->index > last_index)
-+		goto out_unlock_page;
-+	ret = 0;
-+	if (!PageUptodate(page) || page->mapping != ip->i_inode.i_mapping)
-+		goto out_unlock_page;
-+	if (gfs2_is_stuffed(ip)) {
-+		ret = gfs2_unstuff_dinode(ip, page);
-+		if (ret)
-+			goto out_unlock_page;
-+	}
-+	ret = gfs2_allocate_page_backing(page);
+ 	if (!options) {
+ 		status = 1;
+@@ -816,6 +829,41 @@ static int ocfs2_parse_options(struct super_block *sb,
+ 			if (option)
+ 				mopt->slot = (s16)option;
+ 			break;
++		case Opt_commit:
++			option = 0;
++			if (match_int(&args[0], &option)) {
++				status = 0;
++				goto bail;
++			}
++			if (option < 0)
++				return 0;
++			if (option == 0)
++				option = JBD_DEFAULT_MAX_COMMIT_AGE;
++			mopt->commit_interval = HZ * option;
++			break;
++		case Opt_localalloc:
++			option = 0;
++			if (match_int(&args[0], &option)) {
++				status = 0;
++				goto bail;
++			}
++			if (option >= 0 && (option <= ocfs2_local_alloc_size(sb) * 8))
++				mopt->localalloc_opt = option;
++			break;
++		case Opt_localflocks:
++			/*
++			 * Changing this during remount could race
++			 * flock() requests, or "unbalance" existing
++			 * ones (e.g., a lock is taken in one mode but
++			 * dropped in the other). If users care enough
++			 * to flip locking modes during remount, we
++			 * could add a "local" flag to individual
++			 * flock structures for proper tracking of
++			 * state.
++			 */
++			if (!is_remount)
++				mopt->mount_opt |= OCFS2_MOUNT_LOCALFLOCKS;
++			break;
+ 		default:
+ 			mlog(ML_ERROR,
+ 			     "Unrecognized mount option \"%s\" "
+@@ -864,6 +912,16 @@ static int ocfs2_show_options(struct seq_file *s, struct vfsmount *mnt)
+ 	if (osb->s_atime_quantum != OCFS2_DEFAULT_ATIME_QUANTUM)
+ 		seq_printf(s, ",atime_quantum=%u", osb->s_atime_quantum);
+ 
++	if (osb->osb_commit_interval)
++		seq_printf(s, ",commit=%u",
++			   (unsigned) (osb->osb_commit_interval / HZ));
 +
-+out_unlock_page:
-+	unlock_page(page);
-+	gfs2_trans_end(sdp);
-+out_trans_fail:
-+	gfs2_inplace_release(ip);
-+out_quota_unlock:
-+	gfs2_quota_unlock(ip);
-+out_alloc_put:
-+	gfs2_alloc_put(ip);
-+out_unlock:
-+	gfs2_glock_dq(&gh);
-+out:
-+	gfs2_holder_uninit(&gh);
-+	return ret;
-+}
++	if (osb->local_alloc_size != OCFS2_DEFAULT_LOCAL_ALLOC_SIZE)
++		seq_printf(s, ",localalloc=%d", osb->local_alloc_size);
 +
-+static struct vm_operations_struct gfs2_vm_ops = {
-+	.fault = filemap_fault,
-+	.page_mkwrite = gfs2_page_mkwrite,
-+};
++	if (opts & OCFS2_MOUNT_LOCALFLOCKS)
++		seq_printf(s, ",localflocks,");
 +
+ 	return 0;
+ }
  
- /**
-  * gfs2_mmap -
-@@ -360,14 +447,7 @@ static int gfs2_mmap(struct file *file, struct vm_area_struct *vma)
- 		return error;
+@@ -965,7 +1023,7 @@ static int ocfs2_statfs(struct dentry *dentry, struct kstatfs *buf)
+ 		goto bail;
  	}
  
--	/* This is VM_MAYWRITE instead of VM_WRITE because a call
--	   to mprotect() can turn on VM_WRITE later. */
--
--	if ((vma->vm_flags & (VM_MAYSHARE | VM_MAYWRITE)) ==
--	    (VM_MAYSHARE | VM_MAYWRITE))
--		vma->vm_ops = &gfs2_vm_ops_sharewrite;
--	else
--		vma->vm_ops = &gfs2_vm_ops_private;
-+	vma->vm_ops = &gfs2_vm_ops;
+-	status = ocfs2_meta_lock(inode, &bh, 0);
++	status = ocfs2_inode_lock(inode, &bh, 0);
+ 	if (status < 0) {
+ 		mlog_errno(status);
+ 		goto bail;
+@@ -989,7 +1047,7 @@ static int ocfs2_statfs(struct dentry *dentry, struct kstatfs *buf)
  
- 	gfs2_glock_dq_uninit(&i_gh);
+ 	brelse(bh);
  
-@@ -538,15 +618,6 @@ static int gfs2_lock(struct file *file, int cmd, struct file_lock *fl)
- 	if (__mandatory_lock(&ip->i_inode))
- 		return -ENOLCK;
+-	ocfs2_meta_unlock(inode, 0);
++	ocfs2_inode_unlock(inode, 0);
+ 	status = 0;
+ bail:
+ 	if (inode)
+@@ -1020,8 +1078,7 @@ static void ocfs2_inode_init_once(struct kmem_cache *cachep, void *data)
+ 	oi->ip_clusters = 0;
  
--	if (sdp->sd_args.ar_localflocks) {
--		if (IS_GETLK(cmd)) {
--			posix_test_lock(file, fl);
--			return 0;
--		} else {
--			return posix_lock_file_wait(file, fl);
--		}
+ 	ocfs2_lock_res_init_once(&oi->ip_rw_lockres);
+-	ocfs2_lock_res_init_once(&oi->ip_meta_lockres);
+-	ocfs2_lock_res_init_once(&oi->ip_data_lockres);
++	ocfs2_lock_res_init_once(&oi->ip_inode_lockres);
+ 	ocfs2_lock_res_init_once(&oi->ip_open_lockres);
+ 
+ 	ocfs2_metadata_cache_init(&oi->vfs_inode);
+@@ -1117,25 +1174,12 @@ static int ocfs2_mount_volume(struct super_block *sb)
+ 		goto leave;
+ 	}
+ 
+-	status = ocfs2_register_hb_callbacks(osb);
+-	if (status < 0) {
+-		mlog_errno(status);
+-		goto leave;
 -	}
 -
- 	if (cmd == F_CANCELLK) {
- 		/* Hack: */
- 		cmd = F_SETLK;
-@@ -632,16 +703,12 @@ static void do_unflock(struct file *file, struct file_lock *fl)
- static int gfs2_flock(struct file *file, int cmd, struct file_lock *fl)
- {
- 	struct gfs2_inode *ip = GFS2_I(file->f_mapping->host);
--	struct gfs2_sbd *sdp = GFS2_SB(file->f_mapping->host);
+ 	status = ocfs2_dlm_init(osb);
+ 	if (status < 0) {
+ 		mlog_errno(status);
+ 		goto leave;
+ 	}
  
- 	if (!(fl->fl_flags & FL_FLOCK))
- 		return -ENOLCK;
- 	if (__mandatory_lock(&ip->i_inode))
- 		return -ENOLCK;
+-	/* requires vote_thread to be running. */
+-	status = ocfs2_register_net_handlers(osb);
+-	if (status < 0) {
+-		mlog_errno(status);
+-		goto leave;
+-	}
+-
+ 	status = ocfs2_super_lock(osb, 1);
+ 	if (status < 0) {
+ 		mlog_errno(status);
+@@ -1150,8 +1194,6 @@ static int ocfs2_mount_volume(struct super_block *sb)
+ 		goto leave;
+ 	}
  
--	if (sdp->sd_args.ar_localflocks)
--		return flock_lock_file_wait(file, fl);
+-	ocfs2_populate_mounted_map(osb);
 -
- 	if (fl->fl_type == F_UNLCK) {
- 		do_unflock(file, fl);
- 		return 0;
-@@ -678,3 +745,27 @@ const struct file_operations gfs2_dir_fops = {
- 	.flock		= gfs2_flock,
- };
+ 	/* load all node-local system inodes */
+ 	status = ocfs2_init_local_system_inodes(osb);
+ 	if (status < 0) {
+@@ -1174,15 +1216,6 @@ static int ocfs2_mount_volume(struct super_block *sb)
+ 	if (ocfs2_mount_local(osb))
+ 		goto leave;
  
-+const struct file_operations gfs2_file_fops_nolock = {
-+	.llseek		= gfs2_llseek,
-+	.read		= do_sync_read,
-+	.aio_read	= generic_file_aio_read,
-+	.write		= do_sync_write,
-+	.aio_write	= generic_file_aio_write,
-+	.unlocked_ioctl	= gfs2_ioctl,
-+	.mmap		= gfs2_mmap,
-+	.open		= gfs2_open,
-+	.release	= gfs2_close,
-+	.fsync		= gfs2_fsync,
-+	.splice_read	= generic_file_splice_read,
-+	.splice_write	= generic_file_splice_write,
-+	.setlease	= gfs2_setlease,
-+};
-+
-+const struct file_operations gfs2_dir_fops_nolock = {
-+	.readdir	= gfs2_readdir,
-+	.unlocked_ioctl	= gfs2_ioctl,
-+	.open		= gfs2_open,
-+	.release	= gfs2_close,
-+	.fsync		= gfs2_fsync,
-+};
-+
-diff --git a/fs/gfs2/ops_file.h b/fs/gfs2/ops_file.h
-deleted file mode 100644
-index 7e5d8ec..0000000
---- a/fs/gfs2/ops_file.h
-+++ /dev/null
-@@ -1,24 +0,0 @@
--/*
-- * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
-- * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
-- *
-- * This copyrighted material is made available to anyone wishing to use,
-- * modify, copy, or redistribute it subject to the terms and conditions
-- * of the GNU General Public License version 2.
-- */
+-	/* This should be sent *after* we recovered our journal as it
+-	 * will cause other nodes to unmark us as needing
+-	 * recovery. However, we need to send it *before* dropping the
+-	 * super block lock as otherwise their recovery threads might
+-	 * try to clean us up while we're live! */
+-	status = ocfs2_request_mount_vote(osb);
+-	if (status < 0)
+-		mlog_errno(status);
 -
--#ifndef __OPS_FILE_DOT_H__
--#define __OPS_FILE_DOT_H__
+ leave:
+ 	if (unlock_super)
+ 		ocfs2_super_unlock(osb, 1);
+@@ -1240,10 +1273,6 @@ static void ocfs2_dismount_volume(struct super_block *sb, int mnt_err)
+ 			mlog_errno(tmp);
+ 			return;
+ 		}
 -
--#include <linux/fs.h>
--struct gfs2_inode;
+-		tmp = ocfs2_request_umount_vote(osb);
+-		if (tmp < 0)
+-			mlog_errno(tmp);
+ 	}
+ 
+ 	if (osb->slot_num != OCFS2_INVALID_SLOT)
+@@ -1254,13 +1283,8 @@ static void ocfs2_dismount_volume(struct super_block *sb, int mnt_err)
+ 
+ 	ocfs2_release_system_inodes(osb);
+ 
+-	if (osb->dlm) {
+-		ocfs2_unregister_net_handlers(osb);
 -
--extern struct file gfs2_internal_file_sentinel;
--extern int gfs2_internal_read(struct gfs2_inode *ip,
--			      struct file_ra_state *ra_state,
--			      char *buf, loff_t *pos, unsigned size);
--extern void gfs2_set_inode_flags(struct inode *inode);
--extern const struct file_operations gfs2_file_fops;
--extern const struct file_operations gfs2_dir_fops;
++	if (osb->dlm)
+ 		ocfs2_dlm_shutdown(osb);
+-	}
 -
--#endif /* __OPS_FILE_DOT_H__ */
-diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c
-index 17de58e..43d511b 100644
---- a/fs/gfs2/ops_fstype.c
-+++ b/fs/gfs2/ops_fstype.c
-@@ -1,6 +1,6 @@
- /*
-  * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
-- * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
-+ * Copyright (C) 2004-2007 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
-@@ -21,6 +21,7 @@
- 
- #include "gfs2.h"
- #include "incore.h"
-+#include "bmap.h"
- #include "daemon.h"
- #include "glock.h"
- #include "glops.h"
-@@ -59,7 +60,6 @@ static struct gfs2_sbd *init_sbd(struct super_block *sb)
+-	ocfs2_clear_hb_callbacks(osb);
  
- 	mutex_init(&sdp->sd_inum_mutex);
- 	spin_lock_init(&sdp->sd_statfs_spin);
--	mutex_init(&sdp->sd_statfs_mutex);
+ 	debugfs_remove(osb->osb_debug_root);
  
- 	spin_lock_init(&sdp->sd_rindex_spin);
- 	mutex_init(&sdp->sd_rindex_mutex);
-@@ -77,7 +77,6 @@ static struct gfs2_sbd *init_sbd(struct super_block *sb)
+@@ -1315,7 +1339,6 @@ static int ocfs2_initialize_super(struct super_block *sb,
+ 	int i, cbits, bbits;
+ 	struct ocfs2_dinode *di = (struct ocfs2_dinode *)bh->b_data;
+ 	struct inode *inode = NULL;
+-	struct buffer_head *bitmap_bh = NULL;
+ 	struct ocfs2_journal *journal;
+ 	__le32 uuid_net_key;
+ 	struct ocfs2_super *osb;
+@@ -1344,19 +1367,13 @@ static int ocfs2_initialize_super(struct super_block *sb,
+ 	osb->s_sectsize_bits = blksize_bits(sector_size);
+ 	BUG_ON(!osb->s_sectsize_bits);
  
- 	spin_lock_init(&sdp->sd_log_lock);
+-	osb->net_response_ids = 0;
+-	spin_lock_init(&osb->net_response_lock);
+-	INIT_LIST_HEAD(&osb->net_response_list);
+-
+-	INIT_LIST_HEAD(&osb->osb_net_handlers);
+ 	init_waitqueue_head(&osb->recovery_event);
+-	spin_lock_init(&osb->vote_task_lock);
+-	init_waitqueue_head(&osb->vote_event);
+-	osb->vote_work_sequence = 0;
+-	osb->vote_wake_sequence = 0;
++	spin_lock_init(&osb->dc_task_lock);
++	init_waitqueue_head(&osb->dc_event);
++	osb->dc_work_sequence = 0;
++	osb->dc_wake_sequence = 0;
+ 	INIT_LIST_HEAD(&osb->blocked_lock_list);
+ 	osb->blocked_lock_count = 0;
+-	INIT_LIST_HEAD(&osb->vote_list);
+ 	spin_lock_init(&osb->osb_lock);
  
--	INIT_LIST_HEAD(&sdp->sd_log_le_gl);
- 	INIT_LIST_HEAD(&sdp->sd_log_le_buf);
- 	INIT_LIST_HEAD(&sdp->sd_log_le_revoke);
- 	INIT_LIST_HEAD(&sdp->sd_log_le_rg);
-@@ -303,6 +302,67 @@ out:
- 	return error;
- }
+ 	atomic_set(&osb->alloc_stats.moves, 0);
+@@ -1496,7 +1513,6 @@ static int ocfs2_initialize_super(struct super_block *sb,
+ 	}
  
-+/**
-+ * map_journal_extents - create a reusable "extent" mapping from all logical
-+ * blocks to all physical blocks for the given journal.  This will save
-+ * us time when writing journal blocks.  Most journals will have only one
-+ * extent that maps all their logical blocks.  That's because gfs2.mkfs
-+ * arranges the journal blocks sequentially to maximize performance.
-+ * So the extent would map the first block for the entire file length.
-+ * However, gfs2_jadd can happen while file activity is happening, so
-+ * those journals may not be sequential.  Less likely is the case where
-+ * the users created their own journals by mounting the metafs and
-+ * laying it out.  But it's still possible.  These journals might have
-+ * several extents.
-+ *
-+ * TODO: This should be done in bigger chunks rather than one block at a time,
-+ *       but since it's only done at mount time, I'm not worried about the
-+ *       time it takes.
-+ */
-+static int map_journal_extents(struct gfs2_sbd *sdp)
-+{
-+	struct gfs2_jdesc *jd = sdp->sd_jdesc;
-+	unsigned int lb;
-+	u64 db, prev_db; /* logical block, disk block, prev disk block */
-+	struct gfs2_inode *ip = GFS2_I(jd->jd_inode);
-+	struct gfs2_journal_extent *jext = NULL;
-+	struct buffer_head bh;
-+	int rc = 0;
-+
-+	prev_db = 0;
-+
-+	for (lb = 0; lb < ip->i_di.di_size >> sdp->sd_sb.sb_bsize_shift; lb++) {
-+		bh.b_state = 0;
-+		bh.b_blocknr = 0;
-+		bh.b_size = 1 << ip->i_inode.i_blkbits;
-+		rc = gfs2_block_map(jd->jd_inode, lb, &bh, 0);
-+		db = bh.b_blocknr;
-+		if (rc || !db) {
-+			printk(KERN_INFO "GFS2 journal mapping error %d: lb="
-+			       "%u db=%llu\n", rc, lb, (unsigned long long)db);
-+			break;
-+		}
-+		if (!prev_db || db != prev_db + 1) {
-+			jext = kzalloc(sizeof(struct gfs2_journal_extent),
-+				       GFP_KERNEL);
-+			if (!jext) {
-+				printk(KERN_INFO "GFS2 error: out of memory "
-+				       "mapping journal extents.\n");
-+				rc = -ENOMEM;
-+				break;
-+			}
-+			jext->dblock = db;
-+			jext->lblock = lb;
-+			jext->blocks = 1;
-+			list_add_tail(&jext->extent_list, &jd->extent_list);
-+		} else {
-+			jext->blocks++;
-+		}
-+		prev_db = db;
-+	}
-+	return rc;
-+}
-+
- static int init_journal(struct gfs2_sbd *sdp, int undo)
- {
- 	struct gfs2_holder ji_gh;
-@@ -340,7 +400,7 @@ static int init_journal(struct gfs2_sbd *sdp, int undo)
+ 	memcpy(&uuid_net_key, di->id2.i_super.s_uuid, sizeof(uuid_net_key));
+-	osb->net_key = le32_to_cpu(uuid_net_key);
  
- 	if (sdp->sd_args.ar_spectator) {
- 		sdp->sd_jdesc = gfs2_jdesc_find(sdp, 0);
--		sdp->sd_log_blks_free = sdp->sd_jdesc->jd_blocks;
-+		atomic_set(&sdp->sd_log_blks_free, sdp->sd_jdesc->jd_blocks);
- 	} else {
- 		if (sdp->sd_lockstruct.ls_jid >= gfs2_jindex_size(sdp)) {
- 			fs_err(sdp, "can't mount journal #%u\n",
-@@ -377,7 +437,10 @@ static int init_journal(struct gfs2_sbd *sdp, int undo)
- 			       sdp->sd_jdesc->jd_jid, error);
- 			goto fail_jinode_gh;
- 		}
--		sdp->sd_log_blks_free = sdp->sd_jdesc->jd_blocks;
-+		atomic_set(&sdp->sd_log_blks_free, sdp->sd_jdesc->jd_blocks);
-+
-+		/* Map the extents for this journal's blocks */
-+		map_journal_extents(sdp);
+ 	strncpy(osb->vol_label, di->id2.i_super.s_label, 63);
+ 	osb->vol_label[63] = '\0';
+@@ -1539,25 +1555,9 @@ static int ocfs2_initialize_super(struct super_block *sb,
  	}
  
- 	if (sdp->sd_lockstruct.ls_first) {
-diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c
-index 291f0c7..9f71372 100644
---- a/fs/gfs2/ops_inode.c
-+++ b/fs/gfs2/ops_inode.c
-@@ -61,7 +61,7 @@ static int gfs2_create(struct inode *dir, struct dentry *dentry,
- 		inode = gfs2_createi(ghs, &dentry->d_name, S_IFREG | mode, 0);
- 		if (!IS_ERR(inode)) {
- 			gfs2_trans_end(sdp);
--			if (dip->i_alloc.al_rgd)
-+			if (dip->i_alloc->al_rgd)
- 				gfs2_inplace_release(dip);
- 			gfs2_quota_unlock(dip);
- 			gfs2_alloc_put(dip);
-@@ -113,8 +113,18 @@ static struct dentry *gfs2_lookup(struct inode *dir, struct dentry *dentry,
- 	if (inode && IS_ERR(inode))
- 		return ERR_PTR(PTR_ERR(inode));
+ 	osb->bitmap_blkno = OCFS2_I(inode)->ip_blkno;
+-
+-	/* We don't have a cluster lock on the bitmap here because
+-	 * we're only interested in static information and the extra
+-	 * complexity at mount time isn't worht it. Don't pass the
+-	 * inode in to the read function though as we don't want it to
+-	 * be put in the cache. */
+-	status = ocfs2_read_block(osb, osb->bitmap_blkno, &bitmap_bh, 0,
+-				  NULL);
+ 	iput(inode);
+-	if (status < 0) {
+-		mlog_errno(status);
+-		goto bail;
+-	}
  
--	if (inode)
-+	if (inode) {
-+		struct gfs2_glock *gl = GFS2_I(inode)->i_gl;
-+		struct gfs2_holder gh;
-+		int error;
-+		error = gfs2_glock_nq_init(gl, LM_ST_SHARED, LM_FLAG_ANY, &gh);
-+		if (error) {
-+			iput(inode);
-+			return ERR_PTR(error);
-+		}
-+		gfs2_glock_dq_uninit(&gh);
- 		return d_splice_alias(inode, dentry);
-+	}
- 	d_add(dentry, inode);
+-	di = (struct ocfs2_dinode *) bitmap_bh->b_data;
+-	osb->bitmap_cpg = le16_to_cpu(di->id2.i_chain.cl_cpg);
+-	brelse(bitmap_bh);
+-	mlog(0, "cluster bitmap inode: %llu, clusters per group: %u\n",
+-	     (unsigned long long)osb->bitmap_blkno, osb->bitmap_cpg);
++	osb->bitmap_cpg = ocfs2_group_bitmap_size(sb) * 8;
  
- 	return NULL;
-@@ -366,7 +376,7 @@ static int gfs2_symlink(struct inode *dir, struct dentry *dentry,
+ 	status = ocfs2_init_slot_info(osb);
+ 	if (status < 0) {
+diff --git a/fs/ocfs2/sysfile.c b/fs/ocfs2/sysfile.c
+index fd2e846..ab713eb 100644
+--- a/fs/ocfs2/sysfile.c
++++ b/fs/ocfs2/sysfile.c
+@@ -112,7 +112,7 @@ static struct inode * _ocfs2_get_system_file_inode(struct ocfs2_super *osb,
+ 		goto bail;
  	}
  
- 	gfs2_trans_end(sdp);
--	if (dip->i_alloc.al_rgd)
-+	if (dip->i_alloc->al_rgd)
- 		gfs2_inplace_release(dip);
- 	gfs2_quota_unlock(dip);
- 	gfs2_alloc_put(dip);
-@@ -442,7 +452,7 @@ static int gfs2_mkdir(struct inode *dir, struct dentry *dentry, int mode)
- 	gfs2_assert_withdraw(sdp, !error); /* dip already pinned */
+-	inode = ocfs2_iget(osb, blkno, OCFS2_FI_FLAG_SYSFILE);
++	inode = ocfs2_iget(osb, blkno, OCFS2_FI_FLAG_SYSFILE, type);
+ 	if (IS_ERR(inode)) {
+ 		mlog_errno(PTR_ERR(inode));
+ 		inode = NULL;
+diff --git a/fs/ocfs2/ver.c b/fs/ocfs2/ver.c
+index 5405ce1..e2488f4 100644
+--- a/fs/ocfs2/ver.c
++++ b/fs/ocfs2/ver.c
+@@ -29,7 +29,7 @@
  
- 	gfs2_trans_end(sdp);
--	if (dip->i_alloc.al_rgd)
-+	if (dip->i_alloc->al_rgd)
- 		gfs2_inplace_release(dip);
- 	gfs2_quota_unlock(dip);
- 	gfs2_alloc_put(dip);
-@@ -548,7 +558,7 @@ static int gfs2_mknod(struct inode *dir, struct dentry *dentry, int mode,
- 	}
+ #include "ver.h"
  
- 	gfs2_trans_end(sdp);
--	if (dip->i_alloc.al_rgd)
-+	if (dip->i_alloc->al_rgd)
- 		gfs2_inplace_release(dip);
- 	gfs2_quota_unlock(dip);
- 	gfs2_alloc_put(dip);
-diff --git a/fs/gfs2/ops_inode.h b/fs/gfs2/ops_inode.h
-index 34f0caa..fd8cee2 100644
---- a/fs/gfs2/ops_inode.h
-+++ b/fs/gfs2/ops_inode.h
-@@ -16,5 +16,11 @@ extern const struct inode_operations gfs2_file_iops;
- extern const struct inode_operations gfs2_dir_iops;
- extern const struct inode_operations gfs2_symlink_iops;
- extern const struct inode_operations gfs2_dev_iops;
-+extern const struct file_operations gfs2_file_fops;
-+extern const struct file_operations gfs2_dir_fops;
-+extern const struct file_operations gfs2_file_fops_nolock;
-+extern const struct file_operations gfs2_dir_fops_nolock;
-+
-+extern void gfs2_set_inode_flags(struct inode *inode);
+-#define OCFS2_BUILD_VERSION "1.3.3"
++#define OCFS2_BUILD_VERSION "1.5.0"
  
- #endif /* __OPS_INODE_DOT_H__ */
-diff --git a/fs/gfs2/ops_super.c b/fs/gfs2/ops_super.c
-index 950f314..5e52421 100644
---- a/fs/gfs2/ops_super.c
-+++ b/fs/gfs2/ops_super.c
-@@ -487,7 +487,6 @@ static struct inode *gfs2_alloc_inode(struct super_block *sb)
- 	if (ip) {
- 		ip->i_flags = 0;
- 		ip->i_gl = NULL;
--		ip->i_last_pfault = jiffies;
- 	}
- 	return &ip->i_inode;
- }
-diff --git a/fs/gfs2/ops_vm.c b/fs/gfs2/ops_vm.c
+ #define VERSION_STR "OCFS2 " OCFS2_BUILD_VERSION
+ 
+diff --git a/fs/ocfs2/vote.c b/fs/ocfs2/vote.c
 deleted file mode 100644
-index 927d739..0000000
---- a/fs/gfs2/ops_vm.c
+index c053585..0000000
+--- a/fs/ocfs2/vote.c
 +++ /dev/null
-@@ -1,169 +0,0 @@
--/*
-- * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
-- * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
+@@ -1,756 +0,0 @@
+-/* -*- mode: c; c-basic-offset: 8; -*-
+- * vim: noexpandtab sw=8 ts=8 sts=0:
 - *
-- * This copyrighted material is made available to anyone wishing to use,
-- * modify, copy, or redistribute it subject to the terms and conditions
-- * of the GNU General Public License version 2.
+- * vote.c
+- *
+- * description here
+- *
+- * Copyright (C) 2003, 2004 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.
 - */
 -
--#include <linux/slab.h>
--#include <linux/spinlock.h>
--#include <linux/completion.h>
--#include <linux/buffer_head.h>
--#include <linux/mm.h>
--#include <linux/pagemap.h>
--#include <linux/gfs2_ondisk.h>
--#include <linux/lm_interface.h>
+-#include <linux/types.h>
+-#include <linux/slab.h>
+-#include <linux/highmem.h>
+-#include <linux/kthread.h>
+-
+-#include <cluster/heartbeat.h>
+-#include <cluster/nodemanager.h>
+-#include <cluster/tcp.h>
+-
+-#include <dlm/dlmapi.h>
+-
+-#define MLOG_MASK_PREFIX ML_VOTE
+-#include <cluster/masklog.h>
+-
+-#include "ocfs2.h"
+-
+-#include "alloc.h"
+-#include "dlmglue.h"
+-#include "extent_map.h"
+-#include "heartbeat.h"
+-#include "inode.h"
+-#include "journal.h"
+-#include "slot_map.h"
+-#include "vote.h"
+-
+-#include "buffer_head_io.h"
+-
+-#define OCFS2_MESSAGE_TYPE_VOTE     (0x1)
+-#define OCFS2_MESSAGE_TYPE_RESPONSE (0x2)
+-struct ocfs2_msg_hdr
+-{
+-	__be32 h_response_id; /* used to lookup message handle on sending
+-			    * node. */
+-	__be32 h_request;
+-	__be64 h_blkno;
+-	__be32 h_generation;
+-	__be32 h_node_num;    /* node sending this particular message. */
+-};
+-
+-struct ocfs2_vote_msg
+-{
+-	struct ocfs2_msg_hdr v_hdr;
+-	__be32 v_reserved1;
+-} __attribute__ ((packed));
+-
+-/* Responses are given these values to maintain backwards
+- * compatibility with older ocfs2 versions */
+-#define OCFS2_RESPONSE_OK		(0)
+-#define OCFS2_RESPONSE_BUSY		(-16)
+-#define OCFS2_RESPONSE_BAD_MSG		(-22)
+-
+-struct ocfs2_response_msg
+-{
+-	struct ocfs2_msg_hdr r_hdr;
+-	__be32 r_response;
+-} __attribute__ ((packed));
+-
+-struct ocfs2_vote_work {
+-	struct list_head   w_list;
+-	struct ocfs2_vote_msg w_msg;
+-};
+-
+-enum ocfs2_vote_request {
+-	OCFS2_VOTE_REQ_INVALID = 0,
+-	OCFS2_VOTE_REQ_MOUNT,
+-	OCFS2_VOTE_REQ_UMOUNT,
+-	OCFS2_VOTE_REQ_LAST
+-};
+-
+-static inline int ocfs2_is_valid_vote_request(int request)
+-{
+-	return OCFS2_VOTE_REQ_INVALID < request &&
+-		request < OCFS2_VOTE_REQ_LAST;
+-}
+-
+-typedef void (*ocfs2_net_response_callback)(void *priv,
+-					    struct ocfs2_response_msg *resp);
+-struct ocfs2_net_response_cb {
+-	ocfs2_net_response_callback	rc_cb;
+-	void				*rc_priv;
+-};
+-
+-struct ocfs2_net_wait_ctxt {
+-	struct list_head        n_list;
+-	u32                     n_response_id;
+-	wait_queue_head_t       n_event;
+-	struct ocfs2_node_map   n_node_map;
+-	int                     n_response; /* an agreggate response. 0 if
+-					     * all nodes are go, < 0 on any
+-					     * negative response from any
+-					     * node or network error. */
+-	struct ocfs2_net_response_cb *n_callback;
+-};
+-
+-static void ocfs2_process_mount_request(struct ocfs2_super *osb,
+-					unsigned int node_num)
+-{
+-	mlog(0, "MOUNT vote from node %u\n", node_num);
+-	/* The other node only sends us this message when he has an EX
+-	 * on the superblock, so our recovery threads (if having been
+-	 * launched) are waiting on it.*/
+-	ocfs2_recovery_map_clear(osb, node_num);
+-	ocfs2_node_map_set_bit(osb, &osb->mounted_map, node_num);
+-
+-	/* We clear the umount map here because a node may have been
+-	 * previously mounted, safely unmounted but never stopped
+-	 * heartbeating - in which case we'd have a stale entry. */
+-	ocfs2_node_map_clear_bit(osb, &osb->umount_map, node_num);
+-}
+-
+-static void ocfs2_process_umount_request(struct ocfs2_super *osb,
+-					 unsigned int node_num)
+-{
+-	mlog(0, "UMOUNT vote from node %u\n", node_num);
+-	ocfs2_node_map_clear_bit(osb, &osb->mounted_map, node_num);
+-	ocfs2_node_map_set_bit(osb, &osb->umount_map, node_num);
+-}
+-
+-static void ocfs2_process_vote(struct ocfs2_super *osb,
+-			       struct ocfs2_vote_msg *msg)
+-{
+-	int net_status, vote_response;
+-	unsigned int node_num;
+-	u64 blkno;
+-	enum ocfs2_vote_request request;
+-	struct ocfs2_msg_hdr *hdr = &msg->v_hdr;
+-	struct ocfs2_response_msg response;
+-
+-	/* decode the network mumbo jumbo into local variables. */
+-	request = be32_to_cpu(hdr->h_request);
+-	blkno = be64_to_cpu(hdr->h_blkno);
+-	node_num = be32_to_cpu(hdr->h_node_num);
+-
+-	mlog(0, "processing vote: request = %u, blkno = %llu, node_num = %u\n",
+-	     request, (unsigned long long)blkno, node_num);
+-
+-	if (!ocfs2_is_valid_vote_request(request)) {
+-		mlog(ML_ERROR, "Invalid vote request %d from node %u\n",
+-		     request, node_num);
+-		vote_response = OCFS2_RESPONSE_BAD_MSG;
+-		goto respond;
+-	}
+-
+-	vote_response = OCFS2_RESPONSE_OK;
+-
+-	switch (request) {
+-	case OCFS2_VOTE_REQ_UMOUNT:
+-		ocfs2_process_umount_request(osb, node_num);
+-		goto respond;
+-	case OCFS2_VOTE_REQ_MOUNT:
+-		ocfs2_process_mount_request(osb, node_num);
+-		goto respond;
+-	default:
+-		/* avoids a gcc warning */
+-		break;
+-	}
+-
+-respond:
+-	/* Response struture is small so we just put it on the stack
+-	 * and stuff it inline. */
+-	memset(&response, 0, sizeof(struct ocfs2_response_msg));
+-	response.r_hdr.h_response_id = hdr->h_response_id;
+-	response.r_hdr.h_blkno = hdr->h_blkno;
+-	response.r_hdr.h_generation = hdr->h_generation;
+-	response.r_hdr.h_node_num = cpu_to_be32(osb->node_num);
+-	response.r_response = cpu_to_be32(vote_response);
+-
+-	net_status = o2net_send_message(OCFS2_MESSAGE_TYPE_RESPONSE,
+-					osb->net_key,
+-					&response,
+-					sizeof(struct ocfs2_response_msg),
+-					node_num,
+-					NULL);
+-	/* We still want to error print for ENOPROTOOPT here. The
+-	 * sending node shouldn't have unregistered his net handler
+-	 * without sending an unmount vote 1st */
+-	if (net_status < 0
+-	    && net_status != -ETIMEDOUT
+-	    && net_status != -ENOTCONN)
+-		mlog(ML_ERROR, "message to node %u fails with error %d!\n",
+-		     node_num, net_status);
+-}
+-
+-static void ocfs2_vote_thread_do_work(struct ocfs2_super *osb)
+-{
+-	unsigned long processed;
+-	struct ocfs2_lock_res *lockres;
+-	struct ocfs2_vote_work *work;
+-
+-	mlog_entry_void();
+-
+-	spin_lock(&osb->vote_task_lock);
+-	/* grab this early so we know to try again if a state change and
+-	 * wake happens part-way through our work  */
+-	osb->vote_work_sequence = osb->vote_wake_sequence;
+-
+-	processed = osb->blocked_lock_count;
+-	while (processed) {
+-		BUG_ON(list_empty(&osb->blocked_lock_list));
+-
+-		lockres = list_entry(osb->blocked_lock_list.next,
+-				     struct ocfs2_lock_res, l_blocked_list);
+-		list_del_init(&lockres->l_blocked_list);
+-		osb->blocked_lock_count--;
+-		spin_unlock(&osb->vote_task_lock);
+-
+-		BUG_ON(!processed);
+-		processed--;
+-
+-		ocfs2_process_blocked_lock(osb, lockres);
+-
+-		spin_lock(&osb->vote_task_lock);
+-	}
+-
+-	while (osb->vote_count) {
+-		BUG_ON(list_empty(&osb->vote_list));
+-		work = list_entry(osb->vote_list.next,
+-				  struct ocfs2_vote_work, w_list);
+-		list_del(&work->w_list);
+-		osb->vote_count--;
+-		spin_unlock(&osb->vote_task_lock);
+-
+-		ocfs2_process_vote(osb, &work->w_msg);
+-		kfree(work);
+-
+-		spin_lock(&osb->vote_task_lock);
+-	}
+-	spin_unlock(&osb->vote_task_lock);
 -
--#include "gfs2.h"
--#include "incore.h"
--#include "bmap.h"
--#include "glock.h"
--#include "inode.h"
--#include "ops_vm.h"
--#include "quota.h"
--#include "rgrp.h"
--#include "trans.h"
--#include "util.h"
+-	mlog_exit_void();
+-}
 -
--static int gfs2_private_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
+-static int ocfs2_vote_thread_lists_empty(struct ocfs2_super *osb)
 -{
--	struct gfs2_inode *ip = GFS2_I(vma->vm_file->f_mapping->host);
+-	int empty = 0;
 -
--	set_bit(GIF_PAGED, &ip->i_flags);
--	return filemap_fault(vma, vmf);
+-	spin_lock(&osb->vote_task_lock);
+-	if (list_empty(&osb->blocked_lock_list) &&
+-	    list_empty(&osb->vote_list))
+-		empty = 1;
+-
+-	spin_unlock(&osb->vote_task_lock);
+-	return empty;
 -}
 -
--static int alloc_page_backing(struct gfs2_inode *ip, struct page *page)
+-static int ocfs2_vote_thread_should_wake(struct ocfs2_super *osb)
 -{
--	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
--	unsigned long index = page->index;
--	u64 lblock = index << (PAGE_CACHE_SHIFT -
--				    sdp->sd_sb.sb_bsize_shift);
--	unsigned int blocks = PAGE_CACHE_SIZE >> sdp->sd_sb.sb_bsize_shift;
--	struct gfs2_alloc *al;
--	unsigned int data_blocks, ind_blocks;
--	unsigned int x;
--	int error;
+-	int should_wake = 0;
 -
--	al = gfs2_alloc_get(ip);
+-	spin_lock(&osb->vote_task_lock);
+-	if (osb->vote_work_sequence != osb->vote_wake_sequence)
+-		should_wake = 1;
+-	spin_unlock(&osb->vote_task_lock);
 -
--	error = gfs2_quota_lock(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE);
--	if (error)
--		goto out;
+-	return should_wake;
+-}
 -
--	error = gfs2_quota_check(ip, ip->i_inode.i_uid, ip->i_inode.i_gid);
--	if (error)
--		goto out_gunlock_q;
+-int ocfs2_vote_thread(void *arg)
+-{
+-	int status = 0;
+-	struct ocfs2_super *osb = arg;
 -
--	gfs2_write_calc_reserv(ip, PAGE_CACHE_SIZE, &data_blocks, &ind_blocks);
+-	/* only quit once we've been asked to stop and there is no more
+-	 * work available */
+-	while (!(kthread_should_stop() &&
+-		 ocfs2_vote_thread_lists_empty(osb))) {
 -
--	al->al_requested = data_blocks + ind_blocks;
+-		wait_event_interruptible(osb->vote_event,
+-					 ocfs2_vote_thread_should_wake(osb) ||
+-					 kthread_should_stop());
 -
--	error = gfs2_inplace_reserve(ip);
--	if (error)
--		goto out_gunlock_q;
+-		mlog(0, "vote_thread: awoken\n");
 -
--	error = gfs2_trans_begin(sdp, al->al_rgd->rd_length +
--				 ind_blocks + RES_DINODE +
--				 RES_STATFS + RES_QUOTA, 0);
--	if (error)
--		goto out_ipres;
+-		ocfs2_vote_thread_do_work(osb);
+-	}
 -
--	if (gfs2_is_stuffed(ip)) {
--		error = gfs2_unstuff_dinode(ip, NULL);
--		if (error)
--			goto out_trans;
+-	osb->vote_task = NULL;
+-	return status;
+-}
+-
+-static struct ocfs2_net_wait_ctxt *ocfs2_new_net_wait_ctxt(unsigned int response_id)
+-{
+-	struct ocfs2_net_wait_ctxt *w;
+-
+-	w = kzalloc(sizeof(*w), GFP_NOFS);
+-	if (!w) {
+-		mlog_errno(-ENOMEM);
+-		goto bail;
 -	}
 -
--	for (x = 0; x < blocks; ) {
--		u64 dblock;
--		unsigned int extlen;
--		int new = 1;
+-	INIT_LIST_HEAD(&w->n_list);
+-	init_waitqueue_head(&w->n_event);
+-	ocfs2_node_map_init(&w->n_node_map);
+-	w->n_response_id = response_id;
+-	w->n_callback = NULL;
+-bail:
+-	return w;
+-}
 -
--		error = gfs2_extent_map(&ip->i_inode, lblock, &new, &dblock, &extlen);
--		if (error)
--			goto out_trans;
+-static unsigned int ocfs2_new_response_id(struct ocfs2_super *osb)
+-{
+-	unsigned int ret;
 -
--		lblock += extlen;
--		x += extlen;
+-	spin_lock(&osb->net_response_lock);
+-	ret = ++osb->net_response_ids;
+-	spin_unlock(&osb->net_response_lock);
+-
+-	return ret;
+-}
+-
+-static void ocfs2_dequeue_net_wait_ctxt(struct ocfs2_super *osb,
+-					struct ocfs2_net_wait_ctxt *w)
+-{
+-	spin_lock(&osb->net_response_lock);
+-	list_del(&w->n_list);
+-	spin_unlock(&osb->net_response_lock);
+-}
+-
+-static void ocfs2_queue_net_wait_ctxt(struct ocfs2_super *osb,
+-				      struct ocfs2_net_wait_ctxt *w)
+-{
+-	spin_lock(&osb->net_response_lock);
+-	list_add_tail(&w->n_list,
+-		      &osb->net_response_list);
+-	spin_unlock(&osb->net_response_lock);
+-}
+-
+-static void __ocfs2_mark_node_responded(struct ocfs2_super *osb,
+-					struct ocfs2_net_wait_ctxt *w,
+-					int node_num)
+-{
+-	assert_spin_locked(&osb->net_response_lock);
+-
+-	ocfs2_node_map_clear_bit(osb, &w->n_node_map, node_num);
+-	if (ocfs2_node_map_is_empty(osb, &w->n_node_map))
+-		wake_up(&w->n_event);
+-}
+-
+-/* Intended to be called from the node down callback, we fake remove
+- * the node from all our response contexts */
+-void ocfs2_remove_node_from_vote_queues(struct ocfs2_super *osb,
+-					int node_num)
+-{
+-	struct list_head *p;
+-	struct ocfs2_net_wait_ctxt *w = NULL;
+-
+-	spin_lock(&osb->net_response_lock);
+-
+-	list_for_each(p, &osb->net_response_list) {
+-		w = list_entry(p, struct ocfs2_net_wait_ctxt, n_list);
+-
+-		__ocfs2_mark_node_responded(osb, w, node_num);
 -	}
 -
--	gfs2_assert_warn(sdp, al->al_alloced);
+-	spin_unlock(&osb->net_response_lock);
+-}
 -
--out_trans:
--	gfs2_trans_end(sdp);
--out_ipres:
--	gfs2_inplace_release(ip);
--out_gunlock_q:
--	gfs2_quota_unlock(ip);
--out:
--	gfs2_alloc_put(ip);
--	return error;
+-static int ocfs2_broadcast_vote(struct ocfs2_super *osb,
+-				struct ocfs2_vote_msg *request,
+-				unsigned int response_id,
+-				int *response,
+-				struct ocfs2_net_response_cb *callback)
+-{
+-	int status, i, remote_err;
+-	struct ocfs2_net_wait_ctxt *w = NULL;
+-	int dequeued = 0;
+-
+-	mlog_entry_void();
+-
+-	w = ocfs2_new_net_wait_ctxt(response_id);
+-	if (!w) {
+-		status = -ENOMEM;
+-		mlog_errno(status);
+-		goto bail;
+-	}
+-	w->n_callback = callback;
+-
+-	/* we're pretty much ready to go at this point, and this fills
+-	 * in n_response which we need anyway... */
+-	ocfs2_queue_net_wait_ctxt(osb, w);
+-
+-	i = ocfs2_node_map_iterate(osb, &osb->mounted_map, 0);
+-
+-	while (i != O2NM_INVALID_NODE_NUM) {
+-		if (i != osb->node_num) {
+-			mlog(0, "trying to send request to node %i\n", i);
+-			ocfs2_node_map_set_bit(osb, &w->n_node_map, i);
+-
+-			remote_err = 0;
+-			status = o2net_send_message(OCFS2_MESSAGE_TYPE_VOTE,
+-						    osb->net_key,
+-						    request,
+-						    sizeof(*request),
+-						    i,
+-						    &remote_err);
+-			if (status == -ETIMEDOUT) {
+-				mlog(0, "remote node %d timed out!\n", i);
+-				status = -EAGAIN;
+-				goto bail;
+-			}
+-			if (remote_err < 0) {
+-				status = remote_err;
+-				mlog(0, "remote error %d on node %d!\n",
+-				     remote_err, i);
+-				mlog_errno(status);
+-				goto bail;
+-			}
+-			if (status < 0) {
+-				mlog_errno(status);
+-				goto bail;
+-			}
+-		}
+-		i++;
+-		i = ocfs2_node_map_iterate(osb, &osb->mounted_map, i);
+-		mlog(0, "next is %d, i am %d\n", i, osb->node_num);
+-	}
+-	mlog(0, "done sending, now waiting on responses...\n");
+-
+-	wait_event(w->n_event, ocfs2_node_map_is_empty(osb, &w->n_node_map));
+-
+-	ocfs2_dequeue_net_wait_ctxt(osb, w);
+-	dequeued = 1;
+-
+-	*response = w->n_response;
+-	status = 0;
+-bail:
+-	if (w) {
+-		if (!dequeued)
+-			ocfs2_dequeue_net_wait_ctxt(osb, w);
+-		kfree(w);
+-	}
+-
+-	mlog_exit(status);
+-	return status;
 -}
 -
--static int gfs2_sharewrite_fault(struct vm_area_struct *vma,
--						struct vm_fault *vmf)
+-static struct ocfs2_vote_msg * ocfs2_new_vote_request(struct ocfs2_super *osb,
+-						      u64 blkno,
+-						      unsigned int generation,
+-						      enum ocfs2_vote_request type)
 -{
--	struct file *file = vma->vm_file;
--	struct gfs2_file *gf = file->private_data;
--	struct gfs2_inode *ip = GFS2_I(file->f_mapping->host);
--	struct gfs2_holder i_gh;
--	int alloc_required;
--	int error;
--	int ret = 0;
+-	struct ocfs2_vote_msg *request;
+-	struct ocfs2_msg_hdr *hdr;
 -
--	error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &i_gh);
--	if (error)
--		goto out;
+-	BUG_ON(!ocfs2_is_valid_vote_request(type));
 -
--	set_bit(GIF_PAGED, &ip->i_flags);
--	set_bit(GIF_SW_PAGED, &ip->i_flags);
+-	request = kzalloc(sizeof(*request), GFP_NOFS);
+-	if (!request) {
+-		mlog_errno(-ENOMEM);
+-	} else {
+-		hdr = &request->v_hdr;
+-		hdr->h_node_num = cpu_to_be32(osb->node_num);
+-		hdr->h_request = cpu_to_be32(type);
+-		hdr->h_blkno = cpu_to_be64(blkno);
+-		hdr->h_generation = cpu_to_be32(generation);
+-	}
 -
--	error = gfs2_write_alloc_required(ip,
--					(u64)vmf->pgoff << PAGE_CACHE_SHIFT,
--					PAGE_CACHE_SIZE, &alloc_required);
--	if (error) {
--		ret = VM_FAULT_OOM; /* XXX: are these right? */
--		goto out_unlock;
+-	return request;
+-}
+-
+-/* Complete the buildup of a new vote request and process the
+- * broadcast return value. */
+-static int ocfs2_do_request_vote(struct ocfs2_super *osb,
+-				 struct ocfs2_vote_msg *request,
+-				 struct ocfs2_net_response_cb *callback)
+-{
+-	int status, response = -EBUSY;
+-	unsigned int response_id;
+-	struct ocfs2_msg_hdr *hdr;
+-
+-	response_id = ocfs2_new_response_id(osb);
+-
+-	hdr = &request->v_hdr;
+-	hdr->h_response_id = cpu_to_be32(response_id);
+-
+-	status = ocfs2_broadcast_vote(osb, request, response_id, &response,
+-				      callback);
+-	if (status < 0) {
+-		mlog_errno(status);
+-		goto bail;
 -	}
 -
--	set_bit(GFF_EXLOCK, &gf->f_flags);
--	ret = filemap_fault(vma, vmf);
--	clear_bit(GFF_EXLOCK, &gf->f_flags);
--	if (ret & VM_FAULT_ERROR)
--		goto out_unlock;
+-	status = response;
+-bail:
 -
--	if (alloc_required) {
--		/* XXX: do we need to drop page lock around alloc_page_backing?*/
--		error = alloc_page_backing(ip, vmf->page);
--		if (error) {
--			/*
--			 * VM_FAULT_LOCKED should always be the case for
--			 * filemap_fault, but it may not be in a future
--			 * implementation.
--			 */
--			if (ret & VM_FAULT_LOCKED)
--				unlock_page(vmf->page);
--			page_cache_release(vmf->page);
--			ret = VM_FAULT_OOM;
--			goto out_unlock;
+-	return status;
+-}
+-
+-int ocfs2_request_mount_vote(struct ocfs2_super *osb)
+-{
+-	int status;
+-	struct ocfs2_vote_msg *request = NULL;
+-
+-	request = ocfs2_new_vote_request(osb, 0ULL, 0, OCFS2_VOTE_REQ_MOUNT);
+-	if (!request) {
+-		status = -ENOMEM;
+-		goto bail;
+-	}
+-
+-	status = -EAGAIN;
+-	while (status == -EAGAIN) {
+-		if (!(osb->s_mount_opt & OCFS2_MOUNT_NOINTR) &&
+-		    signal_pending(current)) {
+-			status = -ERESTARTSYS;
+-			goto bail;
 -		}
--		set_page_dirty(vmf->page);
+-
+-		if (ocfs2_node_map_is_only(osb, &osb->mounted_map,
+-					   osb->node_num)) {
+-			status = 0;
+-			goto bail;
+-		}
+-
+-		status = ocfs2_do_request_vote(osb, request, NULL);
+-	}
+-
+-bail:
+-	kfree(request);
+-	return status;
+-}
+-
+-int ocfs2_request_umount_vote(struct ocfs2_super *osb)
+-{
+-	int status;
+-	struct ocfs2_vote_msg *request = NULL;
+-
+-	request = ocfs2_new_vote_request(osb, 0ULL, 0, OCFS2_VOTE_REQ_UMOUNT);
+-	if (!request) {
+-		status = -ENOMEM;
+-		goto bail;
+-	}
+-
+-	status = -EAGAIN;
+-	while (status == -EAGAIN) {
+-		/* Do not check signals on this vote... We really want
+-		 * this one to go all the way through. */
+-
+-		if (ocfs2_node_map_is_only(osb, &osb->mounted_map,
+-					   osb->node_num)) {
+-			status = 0;
+-			goto bail;
+-		}
+-
+-		status = ocfs2_do_request_vote(osb, request, NULL);
+-	}
+-
+-bail:
+-	kfree(request);
+-	return status;
+-}
+-
+-/* TODO: This should eventually be a hash table! */
+-static struct ocfs2_net_wait_ctxt * __ocfs2_find_net_wait_ctxt(struct ocfs2_super *osb,
+-							       u32 response_id)
+-{
+-	struct list_head *p;
+-	struct ocfs2_net_wait_ctxt *w = NULL;
+-
+-	list_for_each(p, &osb->net_response_list) {
+-		w = list_entry(p, struct ocfs2_net_wait_ctxt, n_list);
+-		if (response_id == w->n_response_id)
+-			break;
+-		w = NULL;
+-	}
+-
+-	return w;
+-}
+-
+-/* Translate response codes into local node errno values */
+-static inline int ocfs2_translate_response(int response)
+-{
+-	int ret;
+-
+-	switch (response) {
+-	case OCFS2_RESPONSE_OK:
+-		ret = 0;
+-		break;
+-
+-	case OCFS2_RESPONSE_BUSY:
+-		ret = -EBUSY;
+-		break;
+-
+-	default:
+-		ret = -EINVAL;
 -	}
 -
--out_unlock:
--	gfs2_glock_dq_uninit(&i_gh);
--out:
 -	return ret;
 -}
 -
--struct vm_operations_struct gfs2_vm_ops_private = {
--	.fault = gfs2_private_fault,
--};
+-static int ocfs2_handle_response_message(struct o2net_msg *msg,
+-					 u32 len,
+-					 void *data, void **ret_data)
+-{
+-	unsigned int response_id, node_num;
+-	int response_status;
+-	struct ocfs2_super *osb = data;
+-	struct ocfs2_response_msg *resp;
+-	struct ocfs2_net_wait_ctxt * w;
+-	struct ocfs2_net_response_cb *resp_cb;
 -
--struct vm_operations_struct gfs2_vm_ops_sharewrite = {
--	.fault = gfs2_sharewrite_fault,
--};
+-	resp = (struct ocfs2_response_msg *) msg->buf;
 -
-diff --git a/fs/gfs2/ops_vm.h b/fs/gfs2/ops_vm.h
-deleted file mode 100644
-index 4ae8f43..0000000
---- a/fs/gfs2/ops_vm.h
-+++ /dev/null
-@@ -1,18 +0,0 @@
--/*
-- * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
-- * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
-- *
-- * This copyrighted material is made available to anyone wishing to use,
-- * modify, copy, or redistribute it subject to the terms and conditions
-- * of the GNU General Public License version 2.
-- */
+-	response_id = be32_to_cpu(resp->r_hdr.h_response_id);
+-	node_num = be32_to_cpu(resp->r_hdr.h_node_num);
+-	response_status = 
+-		ocfs2_translate_response(be32_to_cpu(resp->r_response));
 -
--#ifndef __OPS_VM_DOT_H__
--#define __OPS_VM_DOT_H__
+-	mlog(0, "received response message:\n");
+-	mlog(0, "h_response_id = %u\n", response_id);
+-	mlog(0, "h_request = %u\n", be32_to_cpu(resp->r_hdr.h_request));
+-	mlog(0, "h_blkno = %llu\n",
+-	     (unsigned long long)be64_to_cpu(resp->r_hdr.h_blkno));
+-	mlog(0, "h_generation = %u\n", be32_to_cpu(resp->r_hdr.h_generation));
+-	mlog(0, "h_node_num = %u\n", node_num);
+-	mlog(0, "r_response = %d\n", response_status);
 -
--#include <linux/mm.h>
+-	spin_lock(&osb->net_response_lock);
+-	w = __ocfs2_find_net_wait_ctxt(osb, response_id);
+-	if (!w) {
+-		mlog(0, "request not found!\n");
+-		goto bail;
+-	}
+-	resp_cb = w->n_callback;
 -
--extern struct vm_operations_struct gfs2_vm_ops_private;
--extern struct vm_operations_struct gfs2_vm_ops_sharewrite;
+-	if (response_status && (!w->n_response)) {
+-		/* we only really need one negative response so don't
+-		 * set it twice. */
+-		w->n_response = response_status;
+-	}
 -
--#endif /* __OPS_VM_DOT_H__ */
-diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c
-index addb51e..a08dabd 100644
---- a/fs/gfs2/quota.c
-+++ b/fs/gfs2/quota.c
-@@ -1,6 +1,6 @@
- /*
-  * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
-- * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
-+ * Copyright (C) 2004-2007 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
-@@ -59,7 +59,6 @@
- #include "super.h"
- #include "trans.h"
- #include "inode.h"
--#include "ops_file.h"
- #include "ops_address.h"
- #include "util.h"
- 
-@@ -274,10 +273,10 @@ static int bh_get(struct gfs2_quota_data *qd)
- 	}
- 
- 	block = qd->qd_slot / sdp->sd_qc_per_block;
--	offset = qd->qd_slot % sdp->sd_qc_per_block;;
-+	offset = qd->qd_slot % sdp->sd_qc_per_block;
- 
- 	bh_map.b_size = 1 << ip->i_inode.i_blkbits;
--	error = gfs2_block_map(&ip->i_inode, block, 0, &bh_map);
-+	error = gfs2_block_map(&ip->i_inode, block, &bh_map, 0);
- 	if (error)
- 		goto fail;
- 	error = gfs2_meta_read(ip->i_gl, bh_map.b_blocknr, DIO_WAIT, &bh);
-@@ -454,7 +453,7 @@ static void qdsb_put(struct gfs2_quota_data *qd)
- int gfs2_quota_hold(struct gfs2_inode *ip, u32 uid, u32 gid)
- {
- 	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
--	struct gfs2_alloc *al = &ip->i_alloc;
-+	struct gfs2_alloc *al = ip->i_alloc;
- 	struct gfs2_quota_data **qd = al->al_qd;
- 	int error;
- 
-@@ -502,7 +501,7 @@ out:
- void gfs2_quota_unhold(struct gfs2_inode *ip)
- {
- 	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
--	struct gfs2_alloc *al = &ip->i_alloc;
-+	struct gfs2_alloc *al = ip->i_alloc;
- 	unsigned int x;
- 
- 	gfs2_assert_warn(sdp, !test_bit(GIF_QD_LOCKED, &ip->i_flags));
-@@ -646,7 +645,7 @@ static int gfs2_adjust_quota(struct gfs2_inode *ip, loff_t loc,
- 	}
- 
- 	if (!buffer_mapped(bh)) {
--		gfs2_get_block(inode, iblock, bh, 1);
-+		gfs2_block_map(inode, iblock, bh, 1);
- 		if (!buffer_mapped(bh))
- 			goto unlock;
- 	}
-@@ -793,11 +792,9 @@ static int do_glock(struct gfs2_quota_data *qd, int force_refresh,
- 	struct gfs2_holder i_gh;
- 	struct gfs2_quota_host q;
- 	char buf[sizeof(struct gfs2_quota)];
--	struct file_ra_state ra_state;
- 	int error;
- 	struct gfs2_quota_lvb *qlvb;
- 
--	file_ra_state_init(&ra_state, sdp->sd_quota_inode->i_mapping);
- restart:
- 	error = gfs2_glock_nq_init(qd->qd_gl, LM_ST_SHARED, 0, q_gh);
- 	if (error)
-@@ -820,8 +817,8 @@ restart:
- 
- 		memset(buf, 0, sizeof(struct gfs2_quota));
- 		pos = qd2offset(qd);
--		error = gfs2_internal_read(ip, &ra_state, buf,
--					   &pos, sizeof(struct gfs2_quota));
-+		error = gfs2_internal_read(ip, NULL, buf, &pos,
-+					   sizeof(struct gfs2_quota));
- 		if (error < 0)
- 			goto fail_gunlock;
- 
-@@ -856,7 +853,7 @@ fail:
- int gfs2_quota_lock(struct gfs2_inode *ip, u32 uid, u32 gid)
- {
- 	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
--	struct gfs2_alloc *al = &ip->i_alloc;
-+	struct gfs2_alloc *al = ip->i_alloc;
- 	unsigned int x;
- 	int error = 0;
- 
-@@ -924,7 +921,7 @@ static int need_sync(struct gfs2_quota_data *qd)
- 
- void gfs2_quota_unlock(struct gfs2_inode *ip)
- {
--	struct gfs2_alloc *al = &ip->i_alloc;
-+	struct gfs2_alloc *al = ip->i_alloc;
- 	struct gfs2_quota_data *qda[4];
- 	unsigned int count = 0;
- 	unsigned int x;
-@@ -972,7 +969,7 @@ static int print_message(struct gfs2_quota_data *qd, char *type)
- int gfs2_quota_check(struct gfs2_inode *ip, u32 uid, u32 gid)
- {
- 	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
--	struct gfs2_alloc *al = &ip->i_alloc;
-+	struct gfs2_alloc *al = ip->i_alloc;
- 	struct gfs2_quota_data *qd;
- 	s64 value;
- 	unsigned int x;
-@@ -1016,10 +1013,9 @@ int gfs2_quota_check(struct gfs2_inode *ip, u32 uid, u32 gid)
- void gfs2_quota_change(struct gfs2_inode *ip, s64 change,
- 		       u32 uid, u32 gid)
- {
--	struct gfs2_alloc *al = &ip->i_alloc;
-+	struct gfs2_alloc *al = ip->i_alloc;
- 	struct gfs2_quota_data *qd;
- 	unsigned int x;
--	unsigned int found = 0;
- 
- 	if (gfs2_assert_warn(GFS2_SB(&ip->i_inode), change))
- 		return;
-@@ -1032,7 +1028,6 @@ void gfs2_quota_change(struct gfs2_inode *ip, s64 change,
- 		if ((qd->qd_id == uid && test_bit(QDF_USER, &qd->qd_flags)) ||
- 		    (qd->qd_id == gid && !test_bit(QDF_USER, &qd->qd_flags))) {
- 			do_qc(qd, change);
--			found++;
- 		}
- 	}
- }
-diff --git a/fs/gfs2/recovery.c b/fs/gfs2/recovery.c
-index beb6c7a..b249e29 100644
---- a/fs/gfs2/recovery.c
-+++ b/fs/gfs2/recovery.c
-@@ -391,7 +391,7 @@ static int clean_journal(struct gfs2_jdesc *jd, struct gfs2_log_header_host *hea
- 	lblock = head->lh_blkno;
- 	gfs2_replay_incr_blk(sdp, &lblock);
- 	bh_map.b_size = 1 << ip->i_inode.i_blkbits;
--	error = gfs2_block_map(&ip->i_inode, lblock, 0, &bh_map);
-+	error = gfs2_block_map(&ip->i_inode, lblock, &bh_map, 0);
- 	if (error)
- 		return error;
- 	if (!bh_map.b_blocknr) {
-@@ -504,13 +504,21 @@ int gfs2_recover_journal(struct gfs2_jdesc *jd)
- 			if (!test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags))
- 				ro = 1;
- 		} else {
--			if (sdp->sd_vfs->s_flags & MS_RDONLY)
--				ro = 1;
-+			if (sdp->sd_vfs->s_flags & MS_RDONLY) {
-+				/* check if device itself is read-only */
-+				ro = bdev_read_only(sdp->sd_vfs->s_bdev);
-+				if (!ro) {
-+					fs_info(sdp, "recovery required on "
-+						"read-only filesystem.\n");
-+					fs_info(sdp, "write access will be "
-+						"enabled during recovery.\n");
-+				}
-+			}
- 		}
- 
- 		if (ro) {
--			fs_warn(sdp, "jid=%u: Can't replay: read-only FS\n",
--				jd->jd_jid);
-+			fs_warn(sdp, "jid=%u: Can't replay: read-only block "
-+				"device\n", jd->jd_jid);
- 			error = -EROFS;
- 			goto fail_gunlock_tr;
- 		}
-diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c
-index 708c287..3552110 100644
---- a/fs/gfs2/rgrp.c
-+++ b/fs/gfs2/rgrp.c
-@@ -25,10 +25,10 @@
- #include "rgrp.h"
- #include "super.h"
- #include "trans.h"
--#include "ops_file.h"
- #include "util.h"
- #include "log.h"
- #include "inode.h"
-+#include "ops_address.h"
- 
- #define BFITNOENT ((u32)~0)
- #define NO_BLOCK ((u64)~0)
-@@ -126,41 +126,43 @@ static unsigned char gfs2_testbit(struct gfs2_rgrpd *rgd, unsigned char *buffer,
-  * Return: the block number (bitmap buffer scope) that was found
-  */
- 
--static u32 gfs2_bitfit(struct gfs2_rgrpd *rgd, unsigned char *buffer,
--			    unsigned int buflen, u32 goal,
--			    unsigned char old_state)
-+static u32 gfs2_bitfit(unsigned char *buffer, unsigned int buflen, u32 goal,
-+		       unsigned char old_state)
- {
--	unsigned char *byte, *end, alloc;
-+	unsigned char *byte;
- 	u32 blk = goal;
--	unsigned int bit;
-+	unsigned int bit, bitlong;
-+	unsigned long *plong, plong55;
- 
- 	byte = buffer + (goal / GFS2_NBBY);
-+	plong = (unsigned long *)(buffer + (goal / GFS2_NBBY));
- 	bit = (goal % GFS2_NBBY) * GFS2_BIT_SIZE;
--	end = buffer + buflen;
--	alloc = (old_state == GFS2_BLKST_FREE) ? 0x55 : 0;
+-	if (resp_cb) {
+-		spin_unlock(&osb->net_response_lock);
 -
--	while (byte < end) {
--		/* If we're looking for a free block we can eliminate all
--		   bitmap settings with 0x55, which represents four data
--		   blocks in a row.  If we're looking for a data block, we can
--		   eliminate 0x00 which corresponds to four free blocks. */
--		if ((*byte & 0x55) == alloc) {
--			blk += (8 - bit) >> 1;
+-		resp_cb->rc_cb(resp_cb->rc_priv, resp);
 -
--			bit = 0;
--			byte++;
+-		spin_lock(&osb->net_response_lock);
+-	}
 -
-+	bitlong = bit;
-+#if BITS_PER_LONG == 32
-+	plong55 = 0x55555555;
-+#else
-+	plong55 = 0x5555555555555555;
-+#endif
-+	while (byte < buffer + buflen) {
-+
-+		if (bitlong == 0 && old_state == 0 && *plong == plong55) {
-+			plong++;
-+			byte += sizeof(unsigned long);
-+			blk += sizeof(unsigned long) * GFS2_NBBY;
- 			continue;
- 		}
+-	__ocfs2_mark_node_responded(osb, w, node_num);
+-bail:
+-	spin_unlock(&osb->net_response_lock);
 -
- 		if (((*byte >> bit) & GFS2_BIT_MASK) == old_state)
- 			return blk;
+-	return 0;
+-}
 -
- 		bit += GFS2_BIT_SIZE;
- 		if (bit >= 8) {
- 			bit = 0;
- 			byte++;
- 		}
-+		bitlong += GFS2_BIT_SIZE;
-+		if (bitlong >= sizeof(unsigned long) * 8) {
-+			bitlong = 0;
-+			plong++;
-+		}
- 
- 		blk++;
- 	}
-@@ -817,11 +819,9 @@ void gfs2_rgrp_repolish_clones(struct gfs2_rgrpd *rgd)
- 
- struct gfs2_alloc *gfs2_alloc_get(struct gfs2_inode *ip)
- {
--	struct gfs2_alloc *al = &ip->i_alloc;
+-static int ocfs2_handle_vote_message(struct o2net_msg *msg,
+-				     u32 len,
+-				     void *data, void **ret_data)
+-{
+-	int status;
+-	struct ocfs2_super *osb = data;
+-	struct ocfs2_vote_work *work;
 -
--	/* FIXME: Should assert that the correct locks are held here... */
--	memset(al, 0, sizeof(*al));
--	return al;
-+	BUG_ON(ip->i_alloc != NULL);
-+	ip->i_alloc = kzalloc(sizeof(struct gfs2_alloc), GFP_KERNEL);
-+	return ip->i_alloc;
- }
- 
- /**
-@@ -1059,26 +1059,34 @@ static struct inode *get_local_rgrp(struct gfs2_inode *ip, u64 *last_unlinked)
- 	struct inode *inode = NULL;
- 	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
- 	struct gfs2_rgrpd *rgd, *begin = NULL;
--	struct gfs2_alloc *al = &ip->i_alloc;
-+	struct gfs2_alloc *al = ip->i_alloc;
- 	int flags = LM_FLAG_TRY;
- 	int skipped = 0;
- 	int loops = 0;
--	int error;
-+	int error, rg_locked;
- 
- 	/* Try recently successful rgrps */
- 
- 	rgd = recent_rgrp_first(sdp, ip->i_last_rg_alloc);
- 
- 	while (rgd) {
--		error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE,
--					   LM_FLAG_TRY, &al->al_rgd_gh);
-+		rg_locked = 0;
-+
-+		if (gfs2_glock_is_locked_by_me(rgd->rd_gl)) {
-+			rg_locked = 1;
-+			error = 0;
-+		} else {
-+			error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE,
-+						   LM_FLAG_TRY, &al->al_rgd_gh);
-+		}
- 		switch (error) {
- 		case 0:
- 			if (try_rgrp_fit(rgd, al))
- 				goto out;
- 			if (rgd->rd_flags & GFS2_RDF_CHECK)
- 				inode = try_rgrp_unlink(rgd, last_unlinked);
--			gfs2_glock_dq_uninit(&al->al_rgd_gh);
-+			if (!rg_locked)
-+				gfs2_glock_dq_uninit(&al->al_rgd_gh);
- 			if (inode)
- 				return inode;
- 			rgd = recent_rgrp_next(rgd, 1);
-@@ -1098,15 +1106,23 @@ static struct inode *get_local_rgrp(struct gfs2_inode *ip, u64 *last_unlinked)
- 	begin = rgd = forward_rgrp_get(sdp);
- 
- 	for (;;) {
--		error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE, flags,
--					  &al->al_rgd_gh);
-+		rg_locked = 0;
-+
-+		if (gfs2_glock_is_locked_by_me(rgd->rd_gl)) {
-+			rg_locked = 1;
-+			error = 0;
-+		} else {
-+			error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE, flags,
-+						   &al->al_rgd_gh);
-+		}
- 		switch (error) {
- 		case 0:
- 			if (try_rgrp_fit(rgd, al))
- 				goto out;
- 			if (rgd->rd_flags & GFS2_RDF_CHECK)
- 				inode = try_rgrp_unlink(rgd, last_unlinked);
--			gfs2_glock_dq_uninit(&al->al_rgd_gh);
-+			if (!rg_locked)
-+				gfs2_glock_dq_uninit(&al->al_rgd_gh);
- 			if (inode)
- 				return inode;
- 			break;
-@@ -1158,7 +1174,7 @@ out:
- int gfs2_inplace_reserve_i(struct gfs2_inode *ip, char *file, unsigned int line)
- {
- 	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
--	struct gfs2_alloc *al = &ip->i_alloc;
-+	struct gfs2_alloc *al = ip->i_alloc;
- 	struct inode *inode;
- 	int error = 0;
- 	u64 last_unlinked = NO_BLOCK;
-@@ -1204,7 +1220,7 @@ try_again:
- void gfs2_inplace_release(struct gfs2_inode *ip)
- {
- 	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
--	struct gfs2_alloc *al = &ip->i_alloc;
-+	struct gfs2_alloc *al = ip->i_alloc;
- 
- 	if (gfs2_assert_warn(sdp, al->al_alloced <= al->al_requested) == -1)
- 		fs_warn(sdp, "al_alloced = %u, al_requested = %u "
-@@ -1213,7 +1229,8 @@ void gfs2_inplace_release(struct gfs2_inode *ip)
- 			     al->al_line);
- 
- 	al->al_rgd = NULL;
--	gfs2_glock_dq_uninit(&al->al_rgd_gh);
-+	if (al->al_rgd_gh.gh_gl)
-+		gfs2_glock_dq_uninit(&al->al_rgd_gh);
- 	if (ip != GFS2_I(sdp->sd_rindex))
- 		gfs2_glock_dq_uninit(&al->al_ri_gh);
- }
-@@ -1301,11 +1318,10 @@ static u32 rgblk_search(struct gfs2_rgrpd *rgd, u32 goal,
- 		/* The GFS2_BLKST_UNLINKED state doesn't apply to the clone
- 		   bitmaps, so we must search the originals for that. */
- 		if (old_state != GFS2_BLKST_UNLINKED && bi->bi_clone)
--			blk = gfs2_bitfit(rgd, bi->bi_clone + bi->bi_offset,
-+			blk = gfs2_bitfit(bi->bi_clone + bi->bi_offset,
- 					  bi->bi_len, goal, old_state);
- 		else
--			blk = gfs2_bitfit(rgd,
--					  bi->bi_bh->b_data + bi->bi_offset,
-+			blk = gfs2_bitfit(bi->bi_bh->b_data + bi->bi_offset,
- 					  bi->bi_len, goal, old_state);
- 		if (blk != BFITNOENT)
- 			break;
-@@ -1394,7 +1410,7 @@ static struct gfs2_rgrpd *rgblk_free(struct gfs2_sbd *sdp, u64 bstart,
- u64 gfs2_alloc_data(struct gfs2_inode *ip)
- {
- 	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
--	struct gfs2_alloc *al = &ip->i_alloc;
-+	struct gfs2_alloc *al = ip->i_alloc;
- 	struct gfs2_rgrpd *rgd = al->al_rgd;
- 	u32 goal, blk;
- 	u64 block;
-@@ -1439,7 +1455,7 @@ u64 gfs2_alloc_data(struct gfs2_inode *ip)
- u64 gfs2_alloc_meta(struct gfs2_inode *ip)
- {
- 	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
--	struct gfs2_alloc *al = &ip->i_alloc;
-+	struct gfs2_alloc *al = ip->i_alloc;
- 	struct gfs2_rgrpd *rgd = al->al_rgd;
- 	u32 goal, blk;
- 	u64 block;
-@@ -1485,7 +1501,7 @@ u64 gfs2_alloc_meta(struct gfs2_inode *ip)
- u64 gfs2_alloc_di(struct gfs2_inode *dip, u64 *generation)
- {
- 	struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);
--	struct gfs2_alloc *al = &dip->i_alloc;
-+	struct gfs2_alloc *al = dip->i_alloc;
- 	struct gfs2_rgrpd *rgd = al->al_rgd;
- 	u32 blk;
- 	u64 block;
-diff --git a/fs/gfs2/rgrp.h b/fs/gfs2/rgrp.h
-index b4c6adf..149bb16 100644
---- a/fs/gfs2/rgrp.h
-+++ b/fs/gfs2/rgrp.h
-@@ -32,7 +32,9 @@ void gfs2_rgrp_repolish_clones(struct gfs2_rgrpd *rgd);
- struct gfs2_alloc *gfs2_alloc_get(struct gfs2_inode *ip);
- static inline void gfs2_alloc_put(struct gfs2_inode *ip)
- {
--	return; /* So we can see where ip->i_alloc is used */
-+	BUG_ON(ip->i_alloc == NULL);
-+	kfree(ip->i_alloc);
-+	ip->i_alloc = NULL;
+-	work = kmalloc(sizeof(struct ocfs2_vote_work), GFP_NOFS);
+-	if (!work) {
+-		status = -ENOMEM;
+-		mlog_errno(status);
+-		goto bail;
+-	}
+-
+-	INIT_LIST_HEAD(&work->w_list);
+-	memcpy(&work->w_msg, msg->buf, sizeof(struct ocfs2_vote_msg));
+-
+-	mlog(0, "scheduling vote request:\n");
+-	mlog(0, "h_response_id = %u\n",
+-	     be32_to_cpu(work->w_msg.v_hdr.h_response_id));
+-	mlog(0, "h_request = %u\n", be32_to_cpu(work->w_msg.v_hdr.h_request));
+-	mlog(0, "h_blkno = %llu\n",
+-	     (unsigned long long)be64_to_cpu(work->w_msg.v_hdr.h_blkno));
+-	mlog(0, "h_generation = %u\n",
+-	     be32_to_cpu(work->w_msg.v_hdr.h_generation));
+-	mlog(0, "h_node_num = %u\n",
+-	     be32_to_cpu(work->w_msg.v_hdr.h_node_num));
+-
+-	spin_lock(&osb->vote_task_lock);
+-	list_add_tail(&work->w_list, &osb->vote_list);
+-	osb->vote_count++;
+-	spin_unlock(&osb->vote_task_lock);
+-
+-	ocfs2_kick_vote_thread(osb);
+-
+-	status = 0;
+-bail:
+-	return status;
+-}
+-
+-void ocfs2_unregister_net_handlers(struct ocfs2_super *osb)
+-{
+-	if (!osb->net_key)
+-		return;
+-
+-	o2net_unregister_handler_list(&osb->osb_net_handlers);
+-
+-	if (!list_empty(&osb->net_response_list))
+-		mlog(ML_ERROR, "net response list not empty!\n");
+-
+-	osb->net_key = 0;
+-}
+-
+-int ocfs2_register_net_handlers(struct ocfs2_super *osb)
+-{
+-	int status = 0;
+-
+-	if (ocfs2_mount_local(osb))
+-		return 0;
+-
+-	status = o2net_register_handler(OCFS2_MESSAGE_TYPE_RESPONSE,
+-					osb->net_key,
+-					sizeof(struct ocfs2_response_msg),
+-					ocfs2_handle_response_message,
+-					osb, NULL, &osb->osb_net_handlers);
+-	if (status) {
+-		mlog_errno(status);
+-		goto bail;
+-	}
+-
+-	status = o2net_register_handler(OCFS2_MESSAGE_TYPE_VOTE,
+-					osb->net_key,
+-					sizeof(struct ocfs2_vote_msg),
+-					ocfs2_handle_vote_message,
+-					osb, NULL, &osb->osb_net_handlers);
+-	if (status) {
+-		mlog_errno(status);
+-		goto bail;
+-	}
+-bail:
+-	if (status < 0)
+-		ocfs2_unregister_net_handlers(osb);
+-
+-	return status;
+-}
+diff --git a/fs/ocfs2/vote.h b/fs/ocfs2/vote.h
+deleted file mode 100644
+index 9ea46f6..0000000
+--- a/fs/ocfs2/vote.h
++++ /dev/null
+@@ -1,48 +0,0 @@
+-/* -*- mode: c; c-basic-offset: 8; -*-
+- * vim: noexpandtab sw=8 ts=8 sts=0:
+- *
+- * vote.h
+- *
+- * description here
+- *
+- * Copyright (C) 2002, 2004 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 VOTE_H
+-#define VOTE_H
+-
+-int ocfs2_vote_thread(void *arg);
+-static inline void ocfs2_kick_vote_thread(struct ocfs2_super *osb)
+-{
+-	spin_lock(&osb->vote_task_lock);
+-	/* make sure the voting thread gets a swipe at whatever changes
+-	 * the caller may have made to the voting state */
+-	osb->vote_wake_sequence++;
+-	spin_unlock(&osb->vote_task_lock);
+-	wake_up(&osb->vote_event);
+-}
+-
+-int ocfs2_request_mount_vote(struct ocfs2_super *osb);
+-int ocfs2_request_umount_vote(struct ocfs2_super *osb);
+-int ocfs2_register_net_handlers(struct ocfs2_super *osb);
+-void ocfs2_unregister_net_handlers(struct ocfs2_super *osb);
+-
+-void ocfs2_remove_node_from_vote_queues(struct ocfs2_super *osb,
+-					int node_num);
+-#endif
+diff --git a/fs/partitions/check.c b/fs/partitions/check.c
+index 722e12e..739da70 100644
+--- a/fs/partitions/check.c
++++ b/fs/partitions/check.c
+@@ -195,96 +195,45 @@ check_partition(struct gendisk *hd, struct block_device *bdev)
+ 	return ERR_PTR(res);
  }
  
- int gfs2_inplace_reserve_i(struct gfs2_inode *ip,
-diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c
-index dd3e737..ef0562c 100644
---- a/fs/gfs2/super.c
-+++ b/fs/gfs2/super.c
-@@ -1,6 +1,6 @@
- /*
-  * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
-- * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
-+ * Copyright (C) 2004-2007 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
-@@ -51,13 +51,9 @@ void gfs2_tune_init(struct gfs2_tune *gt)
+-/*
+- * sysfs bindings for partitions
+- */
+-
+-struct part_attribute {
+-	struct attribute attr;
+-	ssize_t (*show)(struct hd_struct *,char *);
+-	ssize_t (*store)(struct hd_struct *,const char *, size_t);
+-};
+-
+-static ssize_t 
+-part_attr_show(struct kobject * kobj, struct attribute * attr, char * page)
++static ssize_t part_start_show(struct device *dev,
++			       struct device_attribute *attr, char *buf)
  {
- 	spin_lock_init(&gt->gt_spin);
+-	struct hd_struct * p = container_of(kobj,struct hd_struct,kobj);
+-	struct part_attribute * part_attr = container_of(attr,struct part_attribute,attr);
+-	ssize_t ret = 0;
+-	if (part_attr->show)
+-		ret = part_attr->show(p, page);
+-	return ret;
+-}
+-static ssize_t
+-part_attr_store(struct kobject * kobj, struct attribute * attr,
+-		const char *page, size_t count)
+-{
+-	struct hd_struct * p = container_of(kobj,struct hd_struct,kobj);
+-	struct part_attribute * part_attr = container_of(attr,struct part_attribute,attr);
+-	ssize_t ret = 0;
++	struct hd_struct *p = dev_to_part(dev);
  
--	gt->gt_ilimit = 100;
--	gt->gt_ilimit_tries = 3;
--	gt->gt_ilimit_min = 1;
- 	gt->gt_demote_secs = 300;
- 	gt->gt_incore_log_blocks = 1024;
- 	gt->gt_log_flush_secs = 60;
--	gt->gt_jindex_refresh_secs = 60;
- 	gt->gt_recoverd_secs = 60;
- 	gt->gt_logd_secs = 1;
- 	gt->gt_quotad_secs = 5;
-@@ -71,10 +67,8 @@ void gfs2_tune_init(struct gfs2_tune *gt)
- 	gt->gt_new_files_jdata = 0;
- 	gt->gt_new_files_directio = 0;
- 	gt->gt_max_readahead = 1 << 18;
--	gt->gt_lockdump_size = 131072;
- 	gt->gt_stall_secs = 600;
- 	gt->gt_complain_secs = 10;
--	gt->gt_reclaim_limit = 5000;
- 	gt->gt_statfs_quantum = 30;
- 	gt->gt_statfs_slow = 0;
+-	if (part_attr->store)
+-		ret = part_attr->store(p, page, count);
+-	return ret;
++	return sprintf(buf, "%llu\n",(unsigned long long)p->start_sect);
  }
-@@ -393,6 +387,7 @@ int gfs2_jindex_hold(struct gfs2_sbd *sdp, struct gfs2_holder *ji_gh)
- 		if (!jd)
- 			break;
- 
-+		INIT_LIST_HEAD(&jd->extent_list);
- 		jd->jd_inode = gfs2_lookupi(sdp->sd_jindex, &name, 1, NULL);
- 		if (!jd->jd_inode || IS_ERR(jd->jd_inode)) {
- 			if (!jd->jd_inode)
-@@ -422,8 +417,9 @@ int gfs2_jindex_hold(struct gfs2_sbd *sdp, struct gfs2_holder *ji_gh)
  
- void gfs2_jindex_free(struct gfs2_sbd *sdp)
+-static struct sysfs_ops part_sysfs_ops = {
+-	.show	=	part_attr_show,
+-	.store	=	part_attr_store,
+-};
+-
+-static ssize_t part_uevent_store(struct hd_struct * p,
+-				 const char *page, size_t count)
++static ssize_t part_size_show(struct device *dev,
++			      struct device_attribute *attr, char *buf)
  {
--	struct list_head list;
-+	struct list_head list, *head;
- 	struct gfs2_jdesc *jd;
-+	struct gfs2_journal_extent *jext;
- 
- 	spin_lock(&sdp->sd_jindex_spin);
- 	list_add(&list, &sdp->sd_jindex_list);
-@@ -433,6 +429,14 @@ void gfs2_jindex_free(struct gfs2_sbd *sdp)
+-	kobject_uevent(&p->kobj, KOBJ_ADD);
+-	return count;
++	struct hd_struct *p = dev_to_part(dev);
++	return sprintf(buf, "%llu\n",(unsigned long long)p->nr_sects);
+ }
+-static ssize_t part_dev_read(struct hd_struct * p, char *page)
+-{
+-	struct gendisk *disk = container_of(p->kobj.parent,struct gendisk,kobj);
+-	dev_t dev = MKDEV(disk->major, disk->first_minor + p->partno); 
+-	return print_dev_t(page, dev);
+-}
+-static ssize_t part_start_read(struct hd_struct * p, char *page)
+-{
+-	return sprintf(page, "%llu\n",(unsigned long long)p->start_sect);
+-}
+-static ssize_t part_size_read(struct hd_struct * p, char *page)
+-{
+-	return sprintf(page, "%llu\n",(unsigned long long)p->nr_sects);
+-}
+-static ssize_t part_stat_read(struct hd_struct * p, char *page)
++
++static ssize_t part_stat_show(struct device *dev,
++			      struct device_attribute *attr, char *buf)
+ {
+-	return sprintf(page, "%8u %8llu %8u %8llu\n",
++	struct hd_struct *p = dev_to_part(dev);
++
++	return sprintf(buf, "%8u %8llu %8u %8llu\n",
+ 		       p->ios[0], (unsigned long long)p->sectors[0],
+ 		       p->ios[1], (unsigned long long)p->sectors[1]);
+ }
+-static struct part_attribute part_attr_uevent = {
+-	.attr = {.name = "uevent", .mode = S_IWUSR },
+-	.store	= part_uevent_store
+-};
+-static struct part_attribute part_attr_dev = {
+-	.attr = {.name = "dev", .mode = S_IRUGO },
+-	.show	= part_dev_read
+-};
+-static struct part_attribute part_attr_start = {
+-	.attr = {.name = "start", .mode = S_IRUGO },
+-	.show	= part_start_read
+-};
+-static struct part_attribute part_attr_size = {
+-	.attr = {.name = "size", .mode = S_IRUGO },
+-	.show	= part_size_read
+-};
+-static struct part_attribute part_attr_stat = {
+-	.attr = {.name = "stat", .mode = S_IRUGO },
+-	.show	= part_stat_read
+-};
  
- 	while (!list_empty(&list)) {
- 		jd = list_entry(list.next, struct gfs2_jdesc, jd_list);
-+		head = &jd->extent_list;
-+		while (!list_empty(head)) {
-+			jext = list_entry(head->next,
-+					  struct gfs2_journal_extent,
-+					  extent_list);
-+			list_del(&jext->extent_list);
-+			kfree(jext);
-+		}
- 		list_del(&jd->jd_list);
- 		iput(jd->jd_inode);
- 		kfree(jd);
-@@ -543,7 +547,6 @@ int gfs2_make_fs_rw(struct gfs2_sbd *sdp)
- 	if (error)
- 		return error;
+ #ifdef CONFIG_FAIL_MAKE_REQUEST
++static ssize_t part_fail_show(struct device *dev,
++			      struct device_attribute *attr, char *buf)
++{
++	struct hd_struct *p = dev_to_part(dev);
  
--	gfs2_meta_cache_flush(ip);
- 	j_gl->gl_ops->go_inval(j_gl, DIO_METADATA);
+-static ssize_t part_fail_store(struct hd_struct * p,
++	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)
+ {
++	struct hd_struct *p = dev_to_part(dev);
+ 	int i;
  
- 	error = gfs2_find_jhead(sdp->sd_jdesc, &head);
-@@ -686,9 +689,7 @@ void gfs2_statfs_change(struct gfs2_sbd *sdp, s64 total, s64 free,
- 	if (error)
- 		return;
+ 	if (count > 0 && sscanf(buf, "%d", &i) > 0)
+@@ -292,50 +241,53 @@ static ssize_t part_fail_store(struct hd_struct * p,
  
--	mutex_lock(&sdp->sd_statfs_mutex);
- 	gfs2_trans_add_bh(l_ip->i_gl, l_bh, 1);
--	mutex_unlock(&sdp->sd_statfs_mutex);
+ 	return count;
+ }
+-static ssize_t part_fail_read(struct hd_struct * p, char *page)
+-{
+-	return sprintf(page, "%d\n", p->make_it_fail);
+-}
+-static struct part_attribute part_attr_fail = {
+-	.attr = {.name = "make-it-fail", .mode = S_IRUGO | S_IWUSR },
+-	.store	= part_fail_store,
+-	.show	= part_fail_read
+-};
++#endif
  
- 	spin_lock(&sdp->sd_statfs_spin);
- 	l_sc->sc_total += total;
-@@ -736,9 +737,7 @@ int gfs2_statfs_sync(struct gfs2_sbd *sdp)
- 	if (error)
- 		goto out_bh2;
++static DEVICE_ATTR(start, S_IRUGO, part_start_show, NULL);
++static DEVICE_ATTR(size, S_IRUGO, part_size_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, part_fail_show, part_fail_store);
+ #endif
  
--	mutex_lock(&sdp->sd_statfs_mutex);
- 	gfs2_trans_add_bh(l_ip->i_gl, l_bh, 1);
--	mutex_unlock(&sdp->sd_statfs_mutex);
+-static struct attribute * default_attrs[] = {
+-	&part_attr_uevent.attr,
+-	&part_attr_dev.attr,
+-	&part_attr_start.attr,
+-	&part_attr_size.attr,
+-	&part_attr_stat.attr,
++static struct attribute *part_attrs[] = {
++	&dev_attr_start.attr,
++	&dev_attr_size.attr,
++	&dev_attr_stat.attr,
+ #ifdef CONFIG_FAIL_MAKE_REQUEST
+-	&part_attr_fail.attr,
++	&dev_attr_fail.attr,
+ #endif
+-	NULL,
++	NULL
+ };
  
- 	spin_lock(&sdp->sd_statfs_spin);
- 	m_sc->sc_total += l_sc->sc_total;
-diff --git a/fs/gfs2/sys.c b/fs/gfs2/sys.c
-index 06e0b77..eaa3b7b 100644
---- a/fs/gfs2/sys.c
-+++ b/fs/gfs2/sys.c
-@@ -32,7 +32,8 @@ spinlock_t gfs2_sys_margs_lock;
+-extern struct kset block_subsys;
++static struct attribute_group part_attr_group = {
++	.attrs = part_attrs,
++};
  
- static ssize_t id_show(struct gfs2_sbd *sdp, char *buf)
+-static void part_release(struct kobject *kobj)
++static struct attribute_group *part_attr_groups[] = {
++	&part_attr_group,
++	NULL
++};
++
++static void part_release(struct device *dev)
  {
--	return snprintf(buf, PAGE_SIZE, "%s\n", sdp->sd_vfs->s_id);
-+	return snprintf(buf, PAGE_SIZE, "%u:%u\n",
-+			MAJOR(sdp->sd_vfs->s_dev), MINOR(sdp->sd_vfs->s_dev));
+-	struct hd_struct * p = container_of(kobj,struct hd_struct,kobj);
++	struct hd_struct *p = dev_to_part(dev);
+ 	kfree(p);
  }
  
- static ssize_t fsname_show(struct gfs2_sbd *sdp, char *buf)
-@@ -221,9 +222,7 @@ static struct kobj_type gfs2_ktype = {
- 	.sysfs_ops     = &gfs2_attr_ops,
+-struct kobj_type ktype_part = {
++struct device_type part_type = {
++	.name		= "partition",
++	.groups		= part_attr_groups,
+ 	.release	= part_release,
+-	.default_attrs	= default_attrs,
+-	.sysfs_ops	= &part_sysfs_ops,
  };
  
--static struct kset gfs2_kset = {
--	.ktype  = &gfs2_ktype,
--};
-+static struct kset *gfs2_kset;
- 
- /*
-  * display struct lm_lockstruct fields
-@@ -427,13 +426,11 @@ TUNE_ATTR_2(name, name##_store)
- TUNE_ATTR(demote_secs, 0);
- TUNE_ATTR(incore_log_blocks, 0);
- TUNE_ATTR(log_flush_secs, 0);
--TUNE_ATTR(jindex_refresh_secs, 0);
- TUNE_ATTR(quota_warn_period, 0);
- TUNE_ATTR(quota_quantum, 0);
- TUNE_ATTR(atime_quantum, 0);
- TUNE_ATTR(max_readahead, 0);
- TUNE_ATTR(complain_secs, 0);
--TUNE_ATTR(reclaim_limit, 0);
- TUNE_ATTR(statfs_slow, 0);
- TUNE_ATTR(new_files_jdata, 0);
- TUNE_ATTR(new_files_directio, 0);
-@@ -450,13 +447,11 @@ static struct attribute *tune_attrs[] = {
- 	&tune_attr_demote_secs.attr,
- 	&tune_attr_incore_log_blocks.attr,
- 	&tune_attr_log_flush_secs.attr,
--	&tune_attr_jindex_refresh_secs.attr,
- 	&tune_attr_quota_warn_period.attr,
- 	&tune_attr_quota_quantum.attr,
- 	&tune_attr_atime_quantum.attr,
- 	&tune_attr_max_readahead.attr,
- 	&tune_attr_complain_secs.attr,
--	&tune_attr_reclaim_limit.attr,
- 	&tune_attr_statfs_slow.attr,
- 	&tune_attr_quota_simul_sync.attr,
- 	&tune_attr_quota_cache_secs.attr,
-@@ -495,14 +490,9 @@ int gfs2_sys_fs_add(struct gfs2_sbd *sdp)
+ static inline void partition_sysfs_add_subdir(struct hd_struct *p)
  {
- 	int error;
- 
--	sdp->sd_kobj.kset = &gfs2_kset;
--	sdp->sd_kobj.ktype = &gfs2_ktype;
--
--	error = kobject_set_name(&sdp->sd_kobj, "%s", sdp->sd_table_name);
--	if (error)
--		goto fail;
--
--	error = kobject_register(&sdp->sd_kobj);
-+	sdp->sd_kobj.kset = gfs2_kset;
-+	error = kobject_init_and_add(&sdp->sd_kobj, &gfs2_ktype, NULL,
-+				     "%s", sdp->sd_table_name);
- 	if (error)
- 		goto fail;
+ 	struct kobject *k;
  
-@@ -522,6 +512,7 @@ int gfs2_sys_fs_add(struct gfs2_sbd *sdp)
- 	if (error)
- 		goto fail_args;
+-	k = kobject_get(&p->kobj);
+-	p->holder_dir = kobject_add_dir(k, "holders");
++	k = kobject_get(&p->dev.kobj);
++	p->holder_dir = kobject_create_and_add("holders", k);
+ 	kobject_put(k);
+ }
  
-+	kobject_uevent(&sdp->sd_kobj, KOBJ_ADD);
- 	return 0;
+@@ -343,15 +295,16 @@ static inline void disk_sysfs_add_subdirs(struct gendisk *disk)
+ {
+ 	struct kobject *k;
  
- fail_args:
-@@ -531,7 +522,7 @@ fail_counters:
- fail_lockstruct:
- 	sysfs_remove_group(&sdp->sd_kobj, &lockstruct_group);
- fail_reg:
--	kobject_unregister(&sdp->sd_kobj);
-+	kobject_put(&sdp->sd_kobj);
- fail:
- 	fs_err(sdp, "error %d adding sysfs files", error);
- 	return error;
-@@ -543,21 +534,22 @@ void gfs2_sys_fs_del(struct gfs2_sbd *sdp)
- 	sysfs_remove_group(&sdp->sd_kobj, &args_group);
- 	sysfs_remove_group(&sdp->sd_kobj, &counters_group);
- 	sysfs_remove_group(&sdp->sd_kobj, &lockstruct_group);
--	kobject_unregister(&sdp->sd_kobj);
-+	kobject_put(&sdp->sd_kobj);
+-	k = kobject_get(&disk->kobj);
+-	disk->holder_dir = kobject_add_dir(k, "holders");
+-	disk->slave_dir = kobject_add_dir(k, "slaves");
++	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);
  }
  
- int gfs2_sys_init(void)
+ void delete_partition(struct gendisk *disk, int part)
  {
- 	gfs2_sys_margs = NULL;
- 	spin_lock_init(&gfs2_sys_margs_lock);
--	kobject_set_name(&gfs2_kset.kobj, "gfs2");
--	kobj_set_kset_s(&gfs2_kset, fs_subsys);
--	return kset_register(&gfs2_kset);
-+	gfs2_kset = kset_create_and_add("gfs2", NULL, fs_kobj);
-+	if (!gfs2_kset)
-+		return -ENOMEM;
-+	return 0;
+ 	struct hd_struct *p = disk->part[part-1];
++
+ 	if (!p)
+ 		return;
+ 	if (!p->nr_sects)
+@@ -361,113 +314,55 @@ void delete_partition(struct gendisk *disk, int part)
+ 	p->nr_sects = 0;
+ 	p->ios[0] = p->ios[1] = 0;
+ 	p->sectors[0] = p->sectors[1] = 0;
+-	sysfs_remove_link(&p->kobj, "subsystem");
+-	kobject_unregister(p->holder_dir);
+-	kobject_uevent(&p->kobj, KOBJ_REMOVE);
+-	kobject_del(&p->kobj);
+-	kobject_put(&p->kobj);
++	kobject_put(p->holder_dir);
++	device_del(&p->dev);
++	put_device(&p->dev);
  }
  
- void gfs2_sys_uninit(void)
+ void add_partition(struct gendisk *disk, int part, sector_t start, sector_t len, int flags)
  {
- 	kfree(gfs2_sys_margs);
--	kset_unregister(&gfs2_kset);
-+	kset_unregister(gfs2_kset);
- }
+ 	struct hd_struct *p;
++	int err;
  
-diff --git a/fs/gfs2/trans.c b/fs/gfs2/trans.c
-index 717983e..73e5d92 100644
---- a/fs/gfs2/trans.c
-+++ b/fs/gfs2/trans.c
-@@ -114,11 +114,6 @@ void gfs2_trans_end(struct gfs2_sbd *sdp)
- 		gfs2_log_flush(sdp, NULL);
- }
+ 	p = kzalloc(sizeof(*p), GFP_KERNEL);
+ 	if (!p)
+ 		return;
+-	
++
+ 	p->start_sect = start;
+ 	p->nr_sects = len;
+ 	p->partno = part;
+ 	p->policy = disk->policy;
  
--void gfs2_trans_add_gl(struct gfs2_glock *gl)
+-	if (isdigit(disk->kobj.k_name[strlen(disk->kobj.k_name)-1]))
+-		kobject_set_name(&p->kobj, "%sp%d",
+-				 kobject_name(&disk->kobj), part);
++	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);
+ 	else
+-		kobject_set_name(&p->kobj, "%s%d",
+-				 kobject_name(&disk->kobj),part);
+-	p->kobj.parent = &disk->kobj;
+-	p->kobj.ktype = &ktype_part;
+-	kobject_init(&p->kobj);
+-	kobject_add(&p->kobj);
+-	if (!disk->part_uevent_suppress)
+-		kobject_uevent(&p->kobj, KOBJ_ADD);
+-	sysfs_create_link(&p->kobj, &block_subsys.kobj, "subsystem");
++		snprintf(p->dev.bus_id, BUS_ID_SIZE,
++			 "%s%d", disk->dev.bus_id, part);
++
++	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;
++
++	/* delay uevent until 'holders' subdir is created */
++	p->dev.uevent_suppress = 1;
++	device_add(&p->dev);
++	partition_sysfs_add_subdir(p);
++	p->dev.uevent_suppress = 0;
+ 	if (flags & ADDPART_FLAG_WHOLEDISK) {
+ 		static struct attribute addpartattr = {
+ 			.name = "whole_disk",
+ 			.mode = S_IRUSR | S_IRGRP | S_IROTH,
+ 		};
+-
+-		sysfs_create_file(&p->kobj, &addpartattr);
++		err = sysfs_create_file(&p->dev.kobj, &addpartattr);
+ 	}
+-	partition_sysfs_add_subdir(p);
+-	disk->part[part-1] = p;
+-}
+ 
+-static char *make_block_name(struct gendisk *disk)
 -{
--	lops_add(gl->gl_sbd, &gl->gl_le);
+-	char *name;
+-	static char *block_str = "block:";
+-	int size;
+-	char *s;
+-
+-	size = strlen(block_str) + strlen(disk->disk_name) + 1;
+-	name = kmalloc(size, GFP_KERNEL);
+-	if (!name)
+-		return NULL;
+-	strcpy(name, block_str);
+-	strcat(name, disk->disk_name);
+-	/* ewww... some of these buggers have / in name... */
+-	s = strchr(name, '/');
+-	if (s)
+-		*s = '!';
+-	return name;
 -}
 -
- /**
-  * gfs2_trans_add_bh - Add a to-be-modified buffer to the current transaction
-  * @gl: the glock the buffer belongs to
-diff --git a/fs/gfs2/trans.h b/fs/gfs2/trans.h
-index 043d5f4..e826f0d 100644
---- a/fs/gfs2/trans.h
-+++ b/fs/gfs2/trans.h
-@@ -30,7 +30,6 @@ int gfs2_trans_begin(struct gfs2_sbd *sdp, unsigned int blocks,
+-static int disk_sysfs_symlinks(struct gendisk *disk)
+-{
+-	struct device *target = get_device(disk->driverfs_dev);
+-	int err;
+-	char *disk_name = NULL;
+-
+-	if (target) {
+-		disk_name = make_block_name(disk);
+-		if (!disk_name) {
+-			err = -ENOMEM;
+-			goto err_out;
+-		}
+-
+-		err = sysfs_create_link(&disk->kobj, &target->kobj, "device");
+-		if (err)
+-			goto err_out_disk_name;
+-
+-		err = sysfs_create_link(&target->kobj, &disk->kobj, disk_name);
+-		if (err)
+-			goto err_out_dev_link;
+-	}
+-
+-	err = sysfs_create_link(&disk->kobj, &block_subsys.kobj,
+-				"subsystem");
+-	if (err)
+-		goto err_out_disk_name_lnk;
+-
+-	kfree(disk_name);
+-
+-	return 0;
+-
+-err_out_disk_name_lnk:
+-	if (target) {
+-		sysfs_remove_link(&target->kobj, disk_name);
+-err_out_dev_link:
+-		sysfs_remove_link(&disk->kobj, "device");
+-err_out_disk_name:
+-		kfree(disk_name);
+-err_out:
+-		put_device(target);
+-	}
+-	return err;
++	/* suppress uevent if the disk supresses it */
++	if (!disk->dev.uevent_suppress)
++		kobject_uevent(&p->dev.kobj, KOBJ_ADD);
+ }
  
- void gfs2_trans_end(struct gfs2_sbd *sdp);
+ /* Not exported, helper to add_disk(). */
+@@ -479,19 +374,29 @@ void register_disk(struct gendisk *disk)
+ 	struct hd_struct *p;
+ 	int err;
  
--void gfs2_trans_add_gl(struct gfs2_glock *gl);
- void gfs2_trans_add_bh(struct gfs2_glock *gl, struct buffer_head *bh, int meta);
- void gfs2_trans_add_revoke(struct gfs2_sbd *sdp, struct gfs2_bufdata *bd);
- void gfs2_trans_add_unrevoke(struct gfs2_sbd *sdp, u64 blkno);
-diff --git a/fs/jfs/jfs_dtree.c b/fs/jfs/jfs_dtree.c
-index df25ecc..4dcc058 100644
---- a/fs/jfs/jfs_dtree.c
-+++ b/fs/jfs/jfs_dtree.c
-@@ -284,11 +284,11 @@ static struct dir_table_slot *find_index(struct inode *ip, u32 index,
- 			release_metapage(*mp);
- 			*mp = NULL;
- 		}
--		if (*mp == 0) {
-+		if (!(*mp)) {
- 			*lblock = blkno;
- 			*mp = read_index_page(ip, blkno);
- 		}
--		if (*mp == 0) {
-+		if (!(*mp)) {
- 			jfs_err("free_index: error reading directory table");
- 			return NULL;
- 		}
-@@ -413,7 +413,8 @@ static u32 add_index(tid_t tid, struct inode *ip, s64 bn, int slot)
- 		}
- 		ip->i_size = PSIZE;
+-	kobject_set_name(&disk->kobj, "%s", disk->disk_name);
+-	/* ewww... some of these buggers have / in name... */
+-	s = strchr(disk->kobj.k_name, '/');
++	disk->dev.parent = disk->driverfs_dev;
++	disk->dev.devt = MKDEV(disk->major, disk->first_minor);
++
++	strlcpy(disk->dev.bus_id, disk->disk_name, KOBJ_NAME_LEN);
++	/* ewww... some of these buggers have / in the name... */
++	s = strchr(disk->dev.bus_id, '/');
+ 	if (s)
+ 		*s = '!';
+-	if ((err = kobject_add(&disk->kobj)))
++
++	/* delay uevents, until we scanned partition table */
++	disk->dev.uevent_suppress = 1;
++
++	if (device_add(&disk->dev))
+ 		return;
+-	err = disk_sysfs_symlinks(disk);
++#ifndef CONFIG_SYSFS_DEPRECATED
++	err = sysfs_create_link(block_depr, &disk->dev.kobj,
++				kobject_name(&disk->dev.kobj));
+ 	if (err) {
+-		kobject_del(&disk->kobj);
++		device_del(&disk->dev);
+ 		return;
+ 	}
+- 	disk_sysfs_add_subdirs(disk);
++#endif
++	disk_sysfs_add_subdirs(disk);
  
--		if ((mp = get_index_page(ip, 0)) == 0) {
-+		mp = get_index_page(ip, 0);
-+		if (!mp) {
- 			jfs_err("add_index: get_metapage failed!");
- 			xtTruncate(tid, ip, 0, COMMIT_PWMAP);
- 			memcpy(&jfs_ip->i_dirtable, temp_table,
-@@ -461,7 +462,7 @@ static u32 add_index(tid_t tid, struct inode *ip, s64 bn, int slot)
- 	} else
- 		mp = read_index_page(ip, blkno);
+ 	/* No minors to use for partitions */
+ 	if (disk->minors == 1)
+@@ -505,25 +410,23 @@ void register_disk(struct gendisk *disk)
+ 	if (!bdev)
+ 		goto exit;
  
--	if (mp == 0) {
-+	if (!mp) {
- 		jfs_err("add_index: get/read_metapage failed!");
- 		goto clean_up;
- 	}
-@@ -499,7 +500,7 @@ static void free_index(tid_t tid, struct inode *ip, u32 index, u32 next)
+-	/* scan partition table, but suppress uevents */
+ 	bdev->bd_invalidated = 1;
+-	disk->part_uevent_suppress = 1;
+ 	err = blkdev_get(bdev, FMODE_READ, 0);
+-	disk->part_uevent_suppress = 0;
+ 	if (err < 0)
+ 		goto exit;
+ 	blkdev_put(bdev);
  
- 	dirtab_slot = find_index(ip, index, &mp, &lblock);
+ exit:
+-	/* announce disk after possible partitions are already created */
+-	kobject_uevent(&disk->kobj, KOBJ_ADD);
++	/* announce disk after possible partitions are created */
++	disk->dev.uevent_suppress = 0;
++	kobject_uevent(&disk->dev.kobj, KOBJ_ADD);
  
--	if (dirtab_slot == 0)
-+	if (!dirtab_slot)
- 		return;
+ 	/* announce possible partitions */
+ 	for (i = 1; i < disk->minors; i++) {
+ 		p = disk->part[i-1];
+ 		if (!p || !p->nr_sects)
+ 			continue;
+-		kobject_uevent(&p->kobj, KOBJ_ADD);
++		kobject_uevent(&p->dev.kobj, KOBJ_ADD);
+ 	}
+ }
  
- 	dirtab_slot->flag = DIR_INDEX_FREE;
-@@ -526,7 +527,7 @@ static void modify_index(tid_t tid, struct inode *ip, u32 index, s64 bn,
+@@ -602,19 +505,11 @@ void del_gendisk(struct gendisk *disk)
+ 	disk_stat_set_all(disk, 0);
+ 	disk->stamp = 0;
  
- 	dirtab_slot = find_index(ip, index, mp, lblock);
+-	kobject_uevent(&disk->kobj, KOBJ_REMOVE);
+-	kobject_unregister(disk->holder_dir);
+-	kobject_unregister(disk->slave_dir);
+-	if (disk->driverfs_dev) {
+-		char *disk_name = make_block_name(disk);
+-		sysfs_remove_link(&disk->kobj, "device");
+-		if (disk_name) {
+-			sysfs_remove_link(&disk->driverfs_dev->kobj, disk_name);
+-			kfree(disk_name);
+-		}
+-		put_device(disk->driverfs_dev);
+-		disk->driverfs_dev = NULL;
+-	}
+-	sysfs_remove_link(&disk->kobj, "subsystem");
+-	kobject_del(&disk->kobj);
++	kobject_put(disk->holder_dir);
++	kobject_put(disk->slave_dir);
++	disk->driverfs_dev = NULL;
++#ifndef CONFIG_SYSFS_DEPRECATED
++	sysfs_remove_link(block_depr, disk->dev.bus_id);
++#endif
++	device_del(&disk->dev);
+ }
+diff --git a/fs/proc/base.c b/fs/proc/base.c
+index 7411bfb..91fa8e6 100644
+--- a/fs/proc/base.c
++++ b/fs/proc/base.c
+@@ -310,6 +310,77 @@ static int proc_pid_schedstat(struct task_struct *task, char *buffer)
+ }
+ #endif
  
--	if (dirtab_slot == 0)
-+	if (!dirtab_slot)
- 		return;
++#ifdef CONFIG_LATENCYTOP
++static int lstats_show_proc(struct seq_file *m, void *v)
++{
++	int i;
++	struct task_struct *task = m->private;
++	seq_puts(m, "Latency Top version : v0.1\n");
++
++	for (i = 0; i < 32; i++) {
++		if (task->latency_record[i].backtrace[0]) {
++			int q;
++			seq_printf(m, "%i %li %li ",
++				task->latency_record[i].count,
++				task->latency_record[i].time,
++				task->latency_record[i].max);
++			for (q = 0; q < LT_BACKTRACEDEPTH; q++) {
++				char sym[KSYM_NAME_LEN];
++				char *c;
++				if (!task->latency_record[i].backtrace[q])
++					break;
++				if (task->latency_record[i].backtrace[q] == ULONG_MAX)
++					break;
++				sprint_symbol(sym, task->latency_record[i].backtrace[q]);
++				c = strchr(sym, '+');
++				if (c)
++					*c = 0;
++				seq_printf(m, "%s ", sym);
++			}
++			seq_printf(m, "\n");
++		}
++
++	}
++	return 0;
++}
++
++static int lstats_open(struct inode *inode, struct file *file)
++{
++	int ret;
++	struct seq_file *m;
++	struct task_struct *task = get_proc_task(inode);
++
++	ret = single_open(file, lstats_show_proc, NULL);
++	if (!ret) {
++		m = file->private_data;
++		m->private = task;
++	}
++	return ret;
++}
++
++static ssize_t lstats_write(struct file *file, const char __user *buf,
++			    size_t count, loff_t *offs)
++{
++	struct seq_file *m;
++	struct task_struct *task;
++
++	m = file->private_data;
++	task = m->private;
++	clear_all_latency_tracing(task);
++
++	return count;
++}
++
++static const struct file_operations proc_lstats_operations = {
++	.open		= lstats_open,
++	.read		= seq_read,
++	.write		= lstats_write,
++	.llseek		= seq_lseek,
++	.release	= single_release,
++};
++
++#endif
++
+ /* The badness from the OOM killer */
+ unsigned long badness(struct task_struct *p, unsigned long uptime);
+ static int proc_oom_score(struct task_struct *task, char *buffer)
+@@ -1020,6 +1091,7 @@ static const struct file_operations proc_fault_inject_operations = {
+ };
+ #endif
  
- 	DTSaddress(dirtab_slot, bn);
-@@ -552,7 +553,7 @@ static int read_index(struct inode *ip, u32 index,
- 	struct dir_table_slot *slot;
++
+ #ifdef CONFIG_SCHED_DEBUG
+ /*
+  * Print out various scheduling related per-task fields:
+@@ -2230,6 +2302,9 @@ static const struct pid_entry tgid_base_stuff[] = {
+ #ifdef CONFIG_SCHEDSTATS
+ 	INF("schedstat",  S_IRUGO, pid_schedstat),
+ #endif
++#ifdef CONFIG_LATENCYTOP
++	REG("latency",  S_IRUGO, lstats),
++#endif
+ #ifdef CONFIG_PROC_PID_CPUSET
+ 	REG("cpuset",     S_IRUGO, cpuset),
+ #endif
+@@ -2555,6 +2630,9 @@ static const struct pid_entry tid_base_stuff[] = {
+ #ifdef CONFIG_SCHEDSTATS
+ 	INF("schedstat", S_IRUGO, pid_schedstat),
+ #endif
++#ifdef CONFIG_LATENCYTOP
++	REG("latency",  S_IRUGO, lstats),
++#endif
+ #ifdef CONFIG_PROC_PID_CPUSET
+ 	REG("cpuset",    S_IRUGO, cpuset),
+ #endif
+diff --git a/fs/read_write.c b/fs/read_write.c
+index ea1f94c..c4d3d17 100644
+--- a/fs/read_write.c
++++ b/fs/read_write.c
+@@ -197,25 +197,27 @@ int rw_verify_area(int read_write, struct file *file, loff_t *ppos, size_t count
+ {
+ 	struct inode *inode;
+ 	loff_t pos;
++	int retval = -EINVAL;
  
- 	slot = find_index(ip, index, &mp, &lblock);
--	if (slot == 0) {
-+	if (!slot) {
- 		return -EIO;
- 	}
+ 	inode = file->f_path.dentry->d_inode;
+ 	if (unlikely((ssize_t) count < 0))
+-		goto Einval;
++		return retval;
+ 	pos = *ppos;
+ 	if (unlikely((pos < 0) || (loff_t) (pos + count) < 0))
+-		goto Einval;
++		return retval;
  
-@@ -592,10 +593,8 @@ int dtSearch(struct inode *ip, struct component_name * key, ino_t * data,
- 	struct component_name ciKey;
- 	struct super_block *sb = ip->i_sb;
+ 	if (unlikely(inode->i_flock && mandatory_lock(inode))) {
+-		int retval = locks_mandatory_area(
++		retval = locks_mandatory_area(
+ 			read_write == READ ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE,
+ 			inode, file, pos, count);
+ 		if (retval < 0)
+ 			return retval;
+ 	}
++	retval = security_file_permission(file,
++				read_write == READ ? MAY_READ : MAY_WRITE);
++	if (retval)
++		return retval;
+ 	return count > MAX_RW_COUNT ? MAX_RW_COUNT : count;
+-
+-Einval:
+-	return -EINVAL;
+ }
  
--	ciKey.name =
--	    (wchar_t *) kmalloc((JFS_NAME_MAX + 1) * sizeof(wchar_t),
--				GFP_NOFS);
--	if (ciKey.name == 0) {
-+	ciKey.name = kmalloc((JFS_NAME_MAX + 1) * sizeof(wchar_t), GFP_NOFS);
-+	if (!ciKey.name) {
- 		rc = -ENOMEM;
- 		goto dtSearch_Exit2;
+ static void wait_on_retry_sync_kiocb(struct kiocb *iocb)
+@@ -267,18 +269,15 @@ ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos)
+ 	ret = rw_verify_area(READ, file, pos, count);
+ 	if (ret >= 0) {
+ 		count = ret;
+-		ret = security_file_permission (file, MAY_READ);
+-		if (!ret) {
+-			if (file->f_op->read)
+-				ret = file->f_op->read(file, buf, count, pos);
+-			else
+-				ret = do_sync_read(file, buf, count, pos);
+-			if (ret > 0) {
+-				fsnotify_access(file->f_path.dentry);
+-				add_rchar(current, ret);
+-			}
+-			inc_syscr(current);
++		if (file->f_op->read)
++			ret = file->f_op->read(file, buf, count, pos);
++		else
++			ret = do_sync_read(file, buf, count, pos);
++		if (ret > 0) {
++			fsnotify_access(file->f_path.dentry);
++			add_rchar(current, ret);
+ 		}
++		inc_syscr(current);
  	}
-@@ -957,10 +956,8 @@ static int dtSplitUp(tid_t tid,
- 	smp = split->mp;
- 	sp = DT_PAGE(ip, smp);
  
--	key.name =
--	    (wchar_t *) kmalloc((JFS_NAME_MAX + 2) * sizeof(wchar_t),
--				GFP_NOFS);
--	if (key.name == 0) {
-+	key.name = kmalloc((JFS_NAME_MAX + 2) * sizeof(wchar_t), GFP_NOFS);
-+	if (!key.name) {
- 		DT_PUTPAGE(smp);
- 		rc = -ENOMEM;
- 		goto dtSplitUp_Exit;
-diff --git a/fs/jfs/jfs_dtree.h b/fs/jfs/jfs_dtree.h
-index 8561c6e..cdac2d5 100644
---- a/fs/jfs/jfs_dtree.h
-+++ b/fs/jfs/jfs_dtree.h
-@@ -74,7 +74,7 @@ struct idtentry {
- #define DTIHDRDATALEN	11
+ 	return ret;
+@@ -325,18 +324,15 @@ ssize_t vfs_write(struct file *file, const char __user *buf, size_t count, loff_
+ 	ret = rw_verify_area(WRITE, file, pos, count);
+ 	if (ret >= 0) {
+ 		count = ret;
+-		ret = security_file_permission (file, MAY_WRITE);
+-		if (!ret) {
+-			if (file->f_op->write)
+-				ret = file->f_op->write(file, buf, count, pos);
+-			else
+-				ret = do_sync_write(file, buf, count, pos);
+-			if (ret > 0) {
+-				fsnotify_modify(file->f_path.dentry);
+-				add_wchar(current, ret);
+-			}
+-			inc_syscw(current);
++		if (file->f_op->write)
++			ret = file->f_op->write(file, buf, count, pos);
++		else
++			ret = do_sync_write(file, buf, count, pos);
++		if (ret > 0) {
++			fsnotify_modify(file->f_path.dentry);
++			add_wchar(current, ret);
+ 		}
++		inc_syscw(current);
+ 	}
  
- /* compute number of slots for entry */
--#define	NDTINTERNAL(klen) ( ((4 + (klen)) + (15 - 1)) / 15 )
-+#define	NDTINTERNAL(klen) (DIV_ROUND_UP((4 + (klen)), 15))
+ 	return ret;
+@@ -603,9 +599,6 @@ static ssize_t do_readv_writev(int type, struct file *file,
+ 	ret = rw_verify_area(type, file, pos, tot_len);
+ 	if (ret < 0)
+ 		goto out;
+-	ret = security_file_permission(file, type == READ ? MAY_READ : MAY_WRITE);
+-	if (ret)
+-		goto out;
  
+ 	fnv = NULL;
+ 	if (type == READ) {
+@@ -737,10 +730,6 @@ static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos,
+ 		goto fput_in;
+ 	count = retval;
  
- /*
-@@ -133,7 +133,7 @@ struct dir_table_slot {
- 	( ((s64)((dts)->addr1)) << 32 | __le32_to_cpu((dts)->addr2) )
+-	retval = security_file_permission (in_file, MAY_READ);
+-	if (retval)
+-		goto fput_in;
+-
+ 	/*
+ 	 * Get output file, and verify that it is ok..
+ 	 */
+@@ -759,10 +748,6 @@ static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos,
+ 		goto fput_out;
+ 	count = retval;
  
- /* compute number of slots for entry */
--#define	NDTLEAF_LEGACY(klen)	( ((2 + (klen)) + (15 - 1)) / 15 )
-+#define	NDTLEAF_LEGACY(klen)	(DIV_ROUND_UP((2 + (klen)), 15))
- #define	NDTLEAF	NDTINTERNAL
+-	retval = security_file_permission (out_file, MAY_WRITE);
+-	if (retval)
+-		goto fput_out;
+-
+ 	if (!max)
+ 		max = min(in_inode->i_sb->s_maxbytes, out_inode->i_sb->s_maxbytes);
  
+diff --git a/fs/splice.c b/fs/splice.c
+index 6bdcb61..56b802b 100644
+--- a/fs/splice.c
++++ b/fs/splice.c
+@@ -908,10 +908,6 @@ static long do_splice_from(struct pipe_inode_info *pipe, struct file *out,
+ 	if (unlikely(ret < 0))
+ 		return ret;
  
-diff --git a/fs/jfs/jfs_imap.c b/fs/jfs/jfs_imap.c
-index 3870ba8..9bf29f7 100644
---- a/fs/jfs/jfs_imap.c
-+++ b/fs/jfs/jfs_imap.c
-@@ -381,7 +381,7 @@ int diRead(struct inode *ip)
+-	ret = security_file_permission(out, MAY_WRITE);
+-	if (unlikely(ret < 0))
+-		return ret;
+-
+ 	return out->f_op->splice_write(pipe, out, ppos, len, flags);
+ }
  
- 	/* read the page of disk inode */
- 	mp = read_metapage(ipimap, pageno << sbi->l2nbperpage, PSIZE, 1);
--	if (mp == 0) {
-+	if (!mp) {
- 		jfs_err("diRead: read_metapage failed");
- 		return -EIO;
- 	}
-@@ -654,7 +654,7 @@ int diWrite(tid_t tid, struct inode *ip)
- 	/* read the page of disk inode */
-       retry:
- 	mp = read_metapage(ipimap, pageno << sbi->l2nbperpage, PSIZE, 1);
--	if (mp == 0)
-+	if (!mp)
- 		return -EIO;
+@@ -934,10 +930,6 @@ static long do_splice_to(struct file *in, loff_t *ppos,
+ 	if (unlikely(ret < 0))
+ 		return ret;
  
- 	/* get the pointer to the disk inode */
-diff --git a/fs/jfs/jfs_logmgr.c b/fs/jfs/jfs_logmgr.c
-index 15a3974..325a967 100644
---- a/fs/jfs/jfs_logmgr.c
-+++ b/fs/jfs/jfs_logmgr.c
-@@ -208,6 +208,17 @@ static struct lmStat {
- } lmStat;
- #endif
+-	ret = security_file_permission(in, MAY_READ);
+-	if (unlikely(ret < 0))
+-		return ret;
+-
+ 	return in->f_op->splice_read(in, ppos, pipe, len, flags);
+ }
  
-+static void write_special_inodes(struct jfs_log *log,
-+				 int (*writer)(struct address_space *))
-+{
-+	struct jfs_sb_info *sbi;
-+
-+	list_for_each_entry(sbi, &log->sb_list, log_list) {
-+		writer(sbi->ipbmap->i_mapping);
-+		writer(sbi->ipimap->i_mapping);
-+		writer(sbi->direct_inode->i_mapping);
-+	}
-+}
+diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c
+index f281cc6..4948d9b 100644
+--- a/fs/sysfs/dir.c
++++ b/fs/sysfs/dir.c
+@@ -440,7 +440,7 @@ int sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd)
+ /**
+  *	sysfs_remove_one - remove sysfs_dirent from parent
+  *	@acxt: addrm context to use
+- *	@sd: sysfs_dirent to be added
++ *	@sd: sysfs_dirent to be removed
+  *
+  *	Mark @sd removed and drop nlink of parent inode if @sd is a
+  *	directory.  @sd is unlinked from the children list.
+diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c
+index 4045bdc..a271c87 100644
+--- a/fs/sysfs/file.c
++++ b/fs/sysfs/file.c
+@@ -20,43 +20,6 @@
  
- /*
-  * NAME:	lmLog()
-@@ -935,22 +946,13 @@ static int lmLogSync(struct jfs_log * log, int hard_sync)
- 	struct lrd lrd;
- 	int lsn;
- 	struct logsyncblk *lp;
--	struct jfs_sb_info *sbi;
- 	unsigned long flags;
+ #include "sysfs.h"
  
- 	/* push dirty metapages out to disk */
- 	if (hard_sync)
--		list_for_each_entry(sbi, &log->sb_list, log_list) {
--			filemap_fdatawrite(sbi->ipbmap->i_mapping);
--			filemap_fdatawrite(sbi->ipimap->i_mapping);
--			filemap_fdatawrite(sbi->direct_inode->i_mapping);
--		}
-+		write_special_inodes(log, filemap_fdatawrite);
- 	else
--		list_for_each_entry(sbi, &log->sb_list, log_list) {
--			filemap_flush(sbi->ipbmap->i_mapping);
--			filemap_flush(sbi->ipimap->i_mapping);
--			filemap_flush(sbi->direct_inode->i_mapping);
--		}
-+		write_special_inodes(log, filemap_flush);
+-#define to_sattr(a) container_of(a,struct subsys_attribute, attr)
+-
+-/*
+- * Subsystem file operations.
+- * These operations allow subsystems to have files that can be 
+- * read/written. 
+- */
+-static ssize_t 
+-subsys_attr_show(struct kobject * kobj, struct attribute * attr, char * page)
+-{
+-	struct kset *kset = to_kset(kobj);
+-	struct subsys_attribute * sattr = to_sattr(attr);
+-	ssize_t ret = -EIO;
+-
+-	if (sattr->show)
+-		ret = sattr->show(kset, page);
+-	return ret;
+-}
+-
+-static ssize_t 
+-subsys_attr_store(struct kobject * kobj, struct attribute * attr, 
+-		  const char * page, size_t count)
+-{
+-	struct kset *kset = to_kset(kobj);
+-	struct subsys_attribute * sattr = to_sattr(attr);
+-	ssize_t ret = -EIO;
+-
+-	if (sattr->store)
+-		ret = sattr->store(kset, page, count);
+-	return ret;
+-}
+-
+-static struct sysfs_ops subsys_sysfs_ops = {
+-	.show	= subsys_attr_show,
+-	.store	= subsys_attr_store,
+-};
+-
+ /*
+  * There's one sysfs_buffer for each open file and one
+  * sysfs_open_dirent for each sysfs_dirent with one or more open
+@@ -66,7 +29,7 @@ static struct sysfs_ops subsys_sysfs_ops = {
+  * sysfs_dirent->s_attr.open points to sysfs_open_dirent.  s_attr.open
+  * is protected by sysfs_open_dirent_lock.
+  */
+-static spinlock_t sysfs_open_dirent_lock = SPIN_LOCK_UNLOCKED;
++static DEFINE_SPINLOCK(sysfs_open_dirent_lock);
  
- 	/*
- 	 *	forward syncpt
-@@ -1536,7 +1538,6 @@ void jfs_flush_journal(struct jfs_log *log, int wait)
+ struct sysfs_open_dirent {
+ 	atomic_t		refcnt;
+@@ -354,31 +317,23 @@ static int sysfs_open_file(struct inode *inode, struct file *file)
  {
- 	int i;
- 	struct tblock *target = NULL;
--	struct jfs_sb_info *sbi;
- 
- 	/* jfs_write_inode may call us during read-only mount */
- 	if (!log)
-@@ -1598,11 +1599,7 @@ void jfs_flush_journal(struct jfs_log *log, int wait)
- 	if (wait < 2)
- 		return;
+ 	struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;
+ 	struct kobject *kobj = attr_sd->s_parent->s_dir.kobj;
+-	struct sysfs_buffer * buffer;
+-	struct sysfs_ops * ops = NULL;
+-	int error;
++	struct sysfs_buffer *buffer;
++	struct sysfs_ops *ops;
++	int error = -EACCES;
  
--	list_for_each_entry(sbi, &log->sb_list, log_list) {
--		filemap_fdatawrite(sbi->ipbmap->i_mapping);
--		filemap_fdatawrite(sbi->ipimap->i_mapping);
--		filemap_fdatawrite(sbi->direct_inode->i_mapping);
--	}
-+	write_special_inodes(log, filemap_fdatawrite);
+ 	/* need attr_sd for attr and ops, its parent for kobj */
+ 	if (!sysfs_get_active_two(attr_sd))
+ 		return -ENODEV;
  
- 	/*
- 	 * If there was recent activity, we may need to wait
-@@ -1611,6 +1608,7 @@ void jfs_flush_journal(struct jfs_log *log, int wait)
- 	if ((!list_empty(&log->cqueue)) || !list_empty(&log->synclist)) {
- 		for (i = 0; i < 200; i++) {	/* Too much? */
- 			msleep(250);
-+			write_special_inodes(log, filemap_fdatawrite);
- 			if (list_empty(&log->cqueue) &&
- 			    list_empty(&log->synclist))
- 				break;
-@@ -2347,7 +2345,7 @@ int jfsIOWait(void *arg)
+-	/* if the kobject has no ktype, then we assume that it is a subsystem
+-	 * itself, and use ops for it.
+-	 */
+-	if (kobj->kset && kobj->kset->ktype)
+-		ops = kobj->kset->ktype->sysfs_ops;
+-	else if (kobj->ktype)
++	/* every kobject with an attribute needs a ktype assigned */
++	if (kobj->ktype && kobj->ktype->sysfs_ops)
+ 		ops = kobj->ktype->sysfs_ops;
+-	else
+-		ops = &subsys_sysfs_ops;
+-
+-	error = -EACCES;
+-
+-	/* No sysfs operations, either from having no subsystem,
+-	 * or the subsystem have no operations.
+-	 */
+-	if (!ops)
++	else {
++		printk(KERN_ERR "missing sysfs attribute operations for "
++		       "kobject: %s\n", kobject_name(kobj));
++		WARN_ON(1);
+ 		goto err_out;
++	}
  
- 	do {
- 		spin_lock_irq(&log_redrive_lock);
--		while ((bp = log_redrive_list) != 0) {
-+		while ((bp = log_redrive_list)) {
- 			log_redrive_list = bp->l_redrive_next;
- 			bp->l_redrive_next = NULL;
- 			spin_unlock_irq(&log_redrive_lock);
-diff --git a/fs/jfs/jfs_metapage.c b/fs/jfs/jfs_metapage.c
-index f5cd8d3..d1e64f2 100644
---- a/fs/jfs/jfs_metapage.c
-+++ b/fs/jfs/jfs_metapage.c
-@@ -39,11 +39,11 @@ static struct {
- #endif
+ 	/* File needs write support.
+ 	 * The inode's perms must say it's ok, 
+@@ -568,7 +523,11 @@ int sysfs_add_file_to_group(struct kobject *kobj,
+ 	struct sysfs_dirent *dir_sd;
+ 	int error;
  
- #define metapage_locked(mp) test_bit(META_locked, &(mp)->flag)
--#define trylock_metapage(mp) test_and_set_bit(META_locked, &(mp)->flag)
-+#define trylock_metapage(mp) test_and_set_bit_lock(META_locked, &(mp)->flag)
+-	dir_sd = sysfs_get_dirent(kobj->sd, group);
++	if (group)
++		dir_sd = sysfs_get_dirent(kobj->sd, group);
++	else
++		dir_sd = sysfs_get(kobj->sd);
++
+ 	if (!dir_sd)
+ 		return -ENOENT;
  
- static inline void unlock_metapage(struct metapage *mp)
+@@ -656,7 +615,10 @@ void sysfs_remove_file_from_group(struct kobject *kobj,
  {
--	clear_bit(META_locked, &mp->flag);
-+	clear_bit_unlock(META_locked, &mp->flag);
- 	wake_up(&mp->wait);
- }
+ 	struct sysfs_dirent *dir_sd;
  
-@@ -88,7 +88,7 @@ struct meta_anchor {
- };
- #define mp_anchor(page) ((struct meta_anchor *)page_private(page))
+-	dir_sd = sysfs_get_dirent(kobj->sd, group);
++	if (group)
++		dir_sd = sysfs_get_dirent(kobj->sd, group);
++	else
++		dir_sd = sysfs_get(kobj->sd);
+ 	if (dir_sd) {
+ 		sysfs_hash_and_remove(dir_sd, attr->name);
+ 		sysfs_put(dir_sd);
+diff --git a/fs/sysfs/group.c b/fs/sysfs/group.c
+index d197237..0871c3d 100644
+--- a/fs/sysfs/group.c
++++ b/fs/sysfs/group.c
+@@ -16,25 +16,31 @@
+ #include "sysfs.h"
  
--static inline struct metapage *page_to_mp(struct page *page, uint offset)
-+static inline struct metapage *page_to_mp(struct page *page, int offset)
+ 
+-static void remove_files(struct sysfs_dirent *dir_sd,
++static void remove_files(struct sysfs_dirent *dir_sd, struct kobject *kobj,
+ 			 const struct attribute_group *grp)
  {
- 	if (!PagePrivate(page))
- 		return NULL;
-@@ -153,7 +153,7 @@ static inline void dec_io(struct page *page, void (*handler) (struct page *))
+ 	struct attribute *const* attr;
++	int i;
+ 
+-	for (attr = grp->attrs; *attr; attr++)
+-		sysfs_hash_and_remove(dir_sd, (*attr)->name);
++	for (i = 0, attr = grp->attrs; *attr; i++, attr++)
++		if (!grp->is_visible ||
++		    grp->is_visible(kobj, *attr, i))
++			sysfs_hash_and_remove(dir_sd, (*attr)->name);
  }
  
- #else
--static inline struct metapage *page_to_mp(struct page *page, uint offset)
-+static inline struct metapage *page_to_mp(struct page *page, int offset)
+-static int create_files(struct sysfs_dirent *dir_sd,
++static int create_files(struct sysfs_dirent *dir_sd, struct kobject *kobj,
+ 			const struct attribute_group *grp)
  {
- 	return PagePrivate(page) ? (struct metapage *)page_private(page) : NULL;
+ 	struct attribute *const* attr;
+-	int error = 0;
++	int error = 0, i;
+ 
+-	for (attr = grp->attrs; *attr && !error; attr++)
+-		error = sysfs_add_file(dir_sd, *attr, SYSFS_KOBJ_ATTR);
++	for (i = 0, attr = grp->attrs; *attr && !error; i++, attr++)
++		if (!grp->is_visible ||
++		    grp->is_visible(kobj, *attr, i))
++			error |=
++				sysfs_add_file(dir_sd, *attr, SYSFS_KOBJ_ATTR);
+ 	if (error)
+-		remove_files(dir_sd, grp);
++		remove_files(dir_sd, kobj, grp);
+ 	return error;
  }
-@@ -249,7 +249,7 @@ static inline void drop_metapage(struct page *page, struct metapage *mp)
-  */
  
- static sector_t metapage_get_blocks(struct inode *inode, sector_t lblock,
--				    unsigned int *len)
-+				    int *len)
- {
- 	int rc = 0;
- 	int xflag;
-@@ -352,25 +352,27 @@ static void metapage_write_end_io(struct bio *bio, int err)
- static int metapage_writepage(struct page *page, struct writeback_control *wbc)
- {
- 	struct bio *bio = NULL;
--	unsigned int block_offset;	/* block offset of mp within page */
-+	int block_offset;	/* block offset of mp within page */
- 	struct inode *inode = page->mapping->host;
--	unsigned int blocks_per_mp = JFS_SBI(inode->i_sb)->nbperpage;
--	unsigned int len;
--	unsigned int xlen;
-+	int blocks_per_mp = JFS_SBI(inode->i_sb)->nbperpage;
-+	int len;
-+	int xlen;
- 	struct metapage *mp;
- 	int redirty = 0;
- 	sector_t lblock;
-+	int nr_underway = 0;
- 	sector_t pblock;
- 	sector_t next_block = 0;
- 	sector_t page_start;
- 	unsigned long bio_bytes = 0;
- 	unsigned long bio_offset = 0;
--	unsigned int offset;
-+	int offset;
+@@ -54,7 +60,7 @@ int sysfs_create_group(struct kobject * kobj,
+ 	} else
+ 		sd = kobj->sd;
+ 	sysfs_get(sd);
+-	error = create_files(sd, grp);
++	error = create_files(sd, kobj, grp);
+ 	if (error) {
+ 		if (grp->name)
+ 			sysfs_remove_subdir(sd);
+@@ -75,7 +81,7 @@ void sysfs_remove_group(struct kobject * kobj,
+ 	} else
+ 		sd = sysfs_get(dir_sd);
  
- 	page_start = (sector_t)page->index <<
- 		     (PAGE_CACHE_SHIFT - inode->i_blkbits);
- 	BUG_ON(!PageLocked(page));
- 	BUG_ON(PageWriteback(page));
-+	set_page_writeback(page);
+-	remove_files(sd, grp);
++	remove_files(sd, kobj, grp);
+ 	if (grp->name)
+ 		sysfs_remove_subdir(sd);
  
- 	for (offset = 0; offset < PAGE_CACHE_SIZE; offset += PSIZE) {
- 		mp = page_to_mp(page, offset);
-@@ -413,11 +415,10 @@ static int metapage_writepage(struct page *page, struct writeback_control *wbc)
- 			if (!bio->bi_size)
- 				goto dump_bio;
- 			submit_bio(WRITE, bio);
-+			nr_underway++;
- 			bio = NULL;
--		} else {
--			set_page_writeback(page);
-+		} else
- 			inc_io(page);
--		}
- 		xlen = (PAGE_CACHE_SIZE - offset) >> inode->i_blkbits;
- 		pblock = metapage_get_blocks(inode, lblock, &xlen);
- 		if (!pblock) {
-@@ -427,7 +428,7 @@ static int metapage_writepage(struct page *page, struct writeback_control *wbc)
- 			continue;
- 		}
- 		set_bit(META_io, &mp->flag);
--		len = min(xlen, (uint) JFS_SBI(inode->i_sb)->nbperpage);
-+		len = min(xlen, (int)JFS_SBI(inode->i_sb)->nbperpage);
+diff --git a/fs/sysfs/symlink.c b/fs/sysfs/symlink.c
+index 3eac20c..5f66c44 100644
+--- a/fs/sysfs/symlink.c
++++ b/fs/sysfs/symlink.c
+@@ -19,39 +19,6 @@
  
- 		bio = bio_alloc(GFP_NOFS, 1);
- 		bio->bi_bdev = inode->i_sb->s_bdev;
-@@ -449,12 +450,16 @@ static int metapage_writepage(struct page *page, struct writeback_control *wbc)
- 			goto dump_bio;
+ #include "sysfs.h"
  
- 		submit_bio(WRITE, bio);
-+		nr_underway++;
- 	}
- 	if (redirty)
- 		redirty_page_for_writepage(wbc, page);
+-static int object_depth(struct sysfs_dirent *sd)
+-{
+-	int depth = 0;
+-
+-	for (; sd->s_parent; sd = sd->s_parent)
+-		depth++;
+-
+-	return depth;
+-}
+-
+-static int object_path_length(struct sysfs_dirent * sd)
+-{
+-	int length = 1;
+-
+-	for (; sd->s_parent; sd = sd->s_parent)
+-		length += strlen(sd->s_name) + 1;
+-
+-	return length;
+-}
+-
+-static void fill_object_path(struct sysfs_dirent *sd, char *buffer, int length)
+-{
+-	--length;
+-	for (; sd->s_parent; sd = sd->s_parent) {
+-		int cur = strlen(sd->s_name);
+-
+-		/* back up enough to print this bus id with '/' */
+-		length -= cur;
+-		strncpy(buffer + length, sd->s_name, cur);
+-		*(buffer + --length) = '/';
+-	}
+-}
+-
+ /**
+  *	sysfs_create_link - create symlink between two objects.
+  *	@kobj:	object whose directory we're creating the link in.
+@@ -112,7 +79,6 @@ int sysfs_create_link(struct kobject * kobj, struct kobject * target, const char
+ 	return error;
+ }
  
- 	unlock_page(page);
+-
+ /**
+  *	sysfs_remove_link - remove symlink in object's directory.
+  *	@kobj:	object we're acting for.
+@@ -124,24 +90,54 @@ void sysfs_remove_link(struct kobject * kobj, const char * name)
+ 	sysfs_hash_and_remove(kobj->sd, name);
+ }
  
-+	if (nr_underway == 0)
-+		end_page_writeback(page);
-+
- 	return 0;
- add_failed:
- 	/* We should never reach here, since we're only adding one vec */
-@@ -475,13 +480,13 @@ static int metapage_readpage(struct file *fp, struct page *page)
+-static int sysfs_get_target_path(struct sysfs_dirent * parent_sd,
+-				 struct sysfs_dirent * target_sd, char *path)
++static int sysfs_get_target_path(struct sysfs_dirent *parent_sd,
++				 struct sysfs_dirent *target_sd, char *path)
  {
- 	struct inode *inode = page->mapping->host;
- 	struct bio *bio = NULL;
--	unsigned int block_offset;
--	unsigned int blocks_per_page = PAGE_CACHE_SIZE >> inode->i_blkbits;
-+	int block_offset;
-+	int blocks_per_page = PAGE_CACHE_SIZE >> inode->i_blkbits;
- 	sector_t page_start;	/* address of page in fs blocks */
- 	sector_t pblock;
--	unsigned int xlen;
-+	int xlen;
- 	unsigned int len;
--	unsigned int offset;
-+	int offset;
+-	char * s;
+-	int depth, size;
++	struct sysfs_dirent *base, *sd;
++	char *s = path;
++	int len = 0;
++
++	/* go up to the root, stop at the base */
++	base = parent_sd;
++	while (base->s_parent) {
++		sd = target_sd->s_parent;
++		while (sd->s_parent && base != sd)
++			sd = sd->s_parent;
++
++		if (base == sd)
++			break;
++
++		strcpy(s, "../");
++		s += 3;
++		base = base->s_parent;
++	}
++
++	/* determine end of target string for reverse fillup */
++	sd = target_sd;
++	while (sd->s_parent && sd != base) {
++		len += strlen(sd->s_name) + 1;
++		sd = sd->s_parent;
++	}
  
- 	BUG_ON(!PageLocked(page));
- 	page_start = (sector_t)page->index <<
-@@ -530,7 +535,7 @@ static int metapage_releasepage(struct page *page, gfp_t gfp_mask)
- {
- 	struct metapage *mp;
- 	int ret = 1;
--	unsigned int offset;
-+	int offset;
+-	depth = object_depth(parent_sd);
+-	size = object_path_length(target_sd) + depth * 3 - 1;
+-	if (size > PATH_MAX)
++	/* check limits */
++	if (len < 2)
++		return -EINVAL;
++	len--;
++	if ((s - path) + len > PATH_MAX)
+ 		return -ENAMETOOLONG;
  
- 	for (offset = 0; offset < PAGE_CACHE_SIZE; offset += PSIZE) {
- 		mp = page_to_mp(page, offset);
-diff --git a/fs/jfs/jfs_mount.c b/fs/jfs/jfs_mount.c
-index 644429a..7b698f2 100644
---- a/fs/jfs/jfs_mount.c
-+++ b/fs/jfs/jfs_mount.c
-@@ -147,7 +147,7 @@ int jfs_mount(struct super_block *sb)
- 	 */
- 	if ((sbi->mntflag & JFS_BAD_SAIT) == 0) {
- 		ipaimap2 = diReadSpecial(sb, AGGREGATE_I, 1);
--		if (ipaimap2 == 0) {
-+		if (!ipaimap2) {
- 			jfs_err("jfs_mount: Faild to read AGGREGATE_I");
- 			rc = -EIO;
- 			goto errout35;
-diff --git a/fs/jfs/jfs_umount.c b/fs/jfs/jfs_umount.c
-index 7971f37..adcf92d 100644
---- a/fs/jfs/jfs_umount.c
-+++ b/fs/jfs/jfs_umount.c
-@@ -68,7 +68,7 @@ int jfs_umount(struct super_block *sb)
- 		/*
- 		 * Wait for outstanding transactions to be written to log:
- 		 */
--		jfs_flush_journal(log, 2);
-+		jfs_flush_journal(log, 1);
+-	pr_debug("%s: depth = %d, size = %d\n", __FUNCTION__, depth, size);
++	/* reverse fillup of target string from target to base */
++	sd = target_sd;
++	while (sd->s_parent && sd != base) {
++		int slen = strlen(sd->s_name);
  
- 	/*
- 	 * close fileset inode allocation map (aka fileset inode)
-@@ -146,7 +146,7 @@ int jfs_umount_rw(struct super_block *sb)
- 	 *
- 	 * remove file system from log active file system list.
- 	 */
--	jfs_flush_journal(log, 2);
-+	jfs_flush_journal(log, 1);
+-	for (s = path; depth--; s += 3)
+-		strcpy(s,"../");
++		len -= slen;
++		strncpy(s + len, sd->s_name, slen);
++		if (len)
++			s[--len] = '/';
  
- 	/*
- 	 * Make sure all metadata makes it to disk
-diff --git a/fs/jfs/namei.c b/fs/jfs/namei.c
-index 4e0a849..f8718de 100644
---- a/fs/jfs/namei.c
-+++ b/fs/jfs/namei.c
-@@ -1103,8 +1103,8 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry,
- 	 * Make sure dest inode number (if any) is what we think it is
- 	 */
- 	rc = dtSearch(new_dir, &new_dname, &ino, &btstack, JFS_LOOKUP);
--	if (rc == 0) {
--		if ((new_ip == 0) || (ino != new_ip->i_ino)) {
-+	if (!rc) {
-+		if ((!new_ip) || (ino != new_ip->i_ino)) {
- 			rc = -ESTALE;
- 			goto out3;
- 		}
-diff --git a/fs/jfs/resize.c b/fs/jfs/resize.c
-index 71984ee..7f24a0b 100644
---- a/fs/jfs/resize.c
-+++ b/fs/jfs/resize.c
-@@ -172,7 +172,7 @@ int jfs_extendfs(struct super_block *sb, s64 newLVSize, int newLogSize)
- 	 */
- 	t64 = ((newLVSize - newLogSize + BPERDMAP - 1) >> L2BPERDMAP)
- 	    << L2BPERDMAP;
--	t32 = ((t64 + (BITSPERPAGE - 1)) / BITSPERPAGE) + 1 + 50;
-+	t32 = DIV_ROUND_UP(t64, BITSPERPAGE) + 1 + 50;
- 	newFSCKSize = t32 << sbi->l2nbperpage;
- 	newFSCKAddress = newLogAddress - newFSCKSize;
+-	fill_object_path(target_sd, path, size);
+-	pr_debug("%s: path = '%s'\n", __FUNCTION__, path);
++		sd = sd->s_parent;
++	}
  
-diff --git a/fs/jfs/super.c b/fs/jfs/super.c
-index 314bb4f..70a1400 100644
---- a/fs/jfs/super.c
-+++ b/fs/jfs/super.c
-@@ -598,6 +598,12 @@ static int jfs_show_options(struct seq_file *seq, struct vfsmount *vfs)
- 		seq_printf(seq, ",umask=%03o", sbi->umask);
- 	if (sbi->flag & JFS_NOINTEGRITY)
- 		seq_puts(seq, ",nointegrity");
-+	if (sbi->nls_tab)
-+		seq_printf(seq, ",iocharset=%s", sbi->nls_tab->charset);
-+	if (sbi->flag & JFS_ERR_CONTINUE)
-+		seq_printf(seq, ",errors=continue");
-+	if (sbi->flag & JFS_ERR_PANIC)
-+		seq_printf(seq, ",errors=panic");
+ 	return 0;
+ }
+diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h
+index 7b74b60..fb7171b 100644
+--- a/include/acpi/acpi_bus.h
++++ b/include/acpi/acpi_bus.h
+@@ -319,7 +319,7 @@ struct acpi_bus_event {
+ 	u32 data;
+ };
  
- #ifdef CONFIG_QUOTA
- 	if (sbi->flag & JFS_USRQUOTA)
-diff --git a/fs/namespace.c b/fs/namespace.c
-index 0608388..61bf376 100644
---- a/fs/namespace.c
-+++ b/fs/namespace.c
-@@ -41,8 +41,8 @@ static struct kmem_cache *mnt_cache __read_mostly;
- static struct rw_semaphore namespace_sem;
+-extern struct kset acpi_subsys;
++extern struct kobject *acpi_kobj;
+ extern int acpi_bus_generate_netlink_event(const char*, const char*, u8, int);
+ /*
+  * External Functions
+diff --git a/include/asm-arm/arch-at91/at91_lcdc.h b/include/asm-arm/arch-at91/at91_lcdc.h
+deleted file mode 100644
+index ab040a4..0000000
+--- a/include/asm-arm/arch-at91/at91_lcdc.h
++++ /dev/null
+@@ -1,148 +0,0 @@
+-/*
+- * include/asm-arm/arch-at91/at91_lcdc.h
+- *
+- * LCD Controller (LCDC).
+- * Based on AT91SAM9261 datasheet revision E.
+- *
+- * This program is free software; you can redistribute it and/or modify
+- * it under the terms of the GNU General Public License as published by
+- * the Free Software Foundation; either version 2 of the License, or
+- * (at your option) any later version.
+- */
+-
+-#ifndef AT91_LCDC_H
+-#define AT91_LCDC_H
+-
+-#define AT91_LCDC_DMABADDR1	0x00		/* DMA Base Address Register 1 */
+-#define AT91_LCDC_DMABADDR2	0x04		/* DMA Base Address Register 2 */
+-#define AT91_LCDC_DMAFRMPT1	0x08		/* DMA Frame Pointer Register 1 */
+-#define AT91_LCDC_DMAFRMPT2	0x0c		/* DMA Frame Pointer Register 2 */
+-#define AT91_LCDC_DMAFRMADD1	0x10		/* DMA Frame Address Register 1 */
+-#define AT91_LCDC_DMAFRMADD2	0x14		/* DMA Frame Address Register 2 */
+-
+-#define AT91_LCDC_DMAFRMCFG	0x18		/* DMA Frame Configuration Register */
+-#define		AT91_LCDC_FRSIZE	(0x7fffff <<  0)	/* Frame Size */
+-#define		AT91_LCDC_BLENGTH	(0x7f     << 24)	/* Burst Length */
+-
+-#define AT91_LCDC_DMACON	0x1c		/* DMA Control Register */
+-#define		AT91_LCDC_DMAEN		(0x1 << 0)	/* DMA Enable */
+-#define		AT91_LCDC_DMARST	(0x1 << 1)	/* DMA Reset */
+-#define		AT91_LCDC_DMABUSY	(0x1 << 2)	/* DMA Busy */
+-
+-#define AT91_LCDC_LCDCON1	0x0800		/* LCD Control Register 1 */
+-#define		AT91_LCDC_BYPASS	(1     <<  0)	/* Bypass lcd_dotck divider */
+-#define		AT91_LCDC_CLKVAL	(0x1ff << 12)	/* Clock Divider */
+-#define		AT91_LCDC_LINCNT	(0x7ff << 21)	/* Line Counter */
+-
+-#define AT91_LCDC_LCDCON2	0x0804		/* LCD Control Register 2 */
+-#define		AT91_LCDC_DISTYPE	(3 << 0)	/* Display Type */
+-#define			AT91_LCDC_DISTYPE_STNMONO	(0 << 0)
+-#define			AT91_LCDC_DISTYPE_STNCOLOR	(1 << 0)
+-#define			AT91_LCDC_DISTYPE_TFT		(2 << 0)
+-#define		AT91_LCDC_SCANMOD	(1 << 2)	/* Scan Mode */
+-#define			AT91_LCDC_SCANMOD_SINGLE	(0 << 2)
+-#define			AT91_LCDC_SCANMOD_DUAL		(1 << 2)
+-#define		AT91_LCDC_IFWIDTH	(3 << 3)	/*Interface Width */
+-#define			AT91_LCDC_IFWIDTH_4		(0 << 3)
+-#define			AT91_LCDC_IFWIDTH_8		(1 << 3)
+-#define			AT91_LCDC_IFWIDTH_16		(2 << 3)
+-#define		AT91_LCDC_PIXELSIZE	(7 << 5)	/* Bits per pixel */
+-#define			AT91_LCDC_PIXELSIZE_1		(0 << 5)
+-#define			AT91_LCDC_PIXELSIZE_2		(1 << 5)
+-#define			AT91_LCDC_PIXELSIZE_4		(2 << 5)
+-#define			AT91_LCDC_PIXELSIZE_8		(3 << 5)
+-#define			AT91_LCDC_PIXELSIZE_16		(4 << 5)
+-#define			AT91_LCDC_PIXELSIZE_24		(5 << 5)
+-#define		AT91_LCDC_INVVD		(1 << 8)	/* LCD Data polarity */
+-#define			AT91_LCDC_INVVD_NORMAL		(0 << 8)
+-#define			AT91_LCDC_INVVD_INVERTED	(1 << 8)
+-#define		AT91_LCDC_INVFRAME	(1 << 9 )	/* LCD VSync polarity */
+-#define			AT91_LCDC_INVFRAME_NORMAL	(0 << 9)
+-#define			AT91_LCDC_INVFRAME_INVERTED	(1 << 9)
+-#define		AT91_LCDC_INVLINE	(1 << 10)	/* LCD HSync polarity */
+-#define			AT91_LCDC_INVLINE_NORMAL	(0 << 10)
+-#define			AT91_LCDC_INVLINE_INVERTED	(1 << 10)
+-#define		AT91_LCDC_INVCLK	(1 << 11)	/* LCD dotclk polarity */
+-#define			AT91_LCDC_INVCLK_NORMAL		(0 << 11)
+-#define			AT91_LCDC_INVCLK_INVERTED	(1 << 11)
+-#define		AT91_LCDC_INVDVAL	(1 << 12)	/* LCD dval polarity */
+-#define			AT91_LCDC_INVDVAL_NORMAL	(0 << 12)
+-#define			AT91_LCDC_INVDVAL_INVERTED	(1 << 12)
+-#define		AT91_LCDC_CLKMOD	(1 << 15)	/* LCD dotclk mode */
+-#define			AT91_LCDC_CLKMOD_ACTIVEDISPLAY	(0 << 15)
+-#define			AT91_LCDC_CLKMOD_ALWAYSACTIVE	(1 << 15)
+-#define		AT91_LCDC_MEMOR		(1 << 31)	/* Memory Ordering Format */
+-#define			AT91_LCDC_MEMOR_BIG		(0 << 31)
+-#define			AT91_LCDC_MEMOR_LITTLE		(1 << 31)
+-
+-#define AT91_LCDC_TIM1		0x0808		/* LCD Timing Register 1 */
+-#define		AT91_LCDC_VFP		(0xff <<  0)	/* Vertical Front Porch */
+-#define		AT91_LCDC_VBP		(0xff <<  8)	/* Vertical Back Porch */
+-#define		AT91_LCDC_VPW		(0x3f << 16)	/* Vertical Synchronization Pulse Width */
+-#define		AT91_LCDC_VHDLY		(0xf  << 24)	/* Vertical to Horizontal Delay */
+-
+-#define AT91_LCDC_TIM2		0x080c		/* LCD Timing Register 2 */
+-#define		AT91_LCDC_HBP		(0xff  <<  0)	/* Horizontal Back Porch */
+-#define		AT91_LCDC_HPW		(0x3f  <<  8)	/* Horizontal Synchronization Pulse Width */
+-#define		AT91_LCDC_HFP		(0x7ff << 21)	/* Horizontal Front Porch */
+-
+-#define AT91_LCDC_LCDFRMCFG	0x0810		/* LCD Frame Configuration Register */
+-#define		AT91_LCDC_LINEVAL	(0x7ff <<  0)	/* Vertical Size of LCD Module */
+-#define		AT91_LCDC_HOZVAL	(0x7ff << 21)	/* Horizontal Size of LCD Module */
+-
+-#define AT91_LCDC_FIFO		0x0814		/* LCD FIFO Register */
+-#define		AT91_LCDC_FIFOTH	(0xffff)	/* FIFO Threshold */
+-
+-#define AT91_LCDC_DP1_2		0x081c		/* Dithering Pattern DP1_2 Register */
+-#define AT91_LCDC_DP4_7		0x0820		/* Dithering Pattern DP4_7 Register */
+-#define AT91_LCDC_DP3_5		0x0824		/* Dithering Pattern DP3_5 Register */
+-#define AT91_LCDC_DP2_3		0x0828		/* Dithering Pattern DP2_3 Register */
+-#define AT91_LCDC_DP5_7		0x082c		/* Dithering Pattern DP5_7 Register */
+-#define AT91_LCDC_DP3_4		0x0830		/* Dithering Pattern DP3_4 Register */
+-#define AT91_LCDC_DP4_5		0x0834		/* Dithering Pattern DP4_5 Register */
+-#define AT91_LCDC_DP6_7		0x0838		/* Dithering Pattern DP6_7 Register */
+-#define		AT91_LCDC_DP1_2_VAL	(0xff)
+-#define		AT91_LCDC_DP4_7_VAL	(0xfffffff)
+-#define		AT91_LCDC_DP3_5_VAL	(0xfffff)
+-#define		AT91_LCDC_DP2_3_VAL	(0xfff)
+-#define		AT91_LCDC_DP5_7_VAL	(0xfffffff)
+-#define		AT91_LCDC_DP3_4_VAL	(0xffff)
+-#define		AT91_LCDC_DP4_5_VAL	(0xfffff)
+-#define		AT91_LCDC_DP6_7_VAL	(0xfffffff)
+-
+-#define AT91_LCDC_PWRCON	0x083c		/* Power Control Register */
+-#define		AT91_LCDC_PWR		(1    <<  0)	/* LCD Module Power Control */
+-#define		AT91_LCDC_GUARDT	(0x7f <<  1)	/* Delay in Frame Period */
+-#define		AT91_LCDC_BUSY		(1    << 31)	/* LCD Busy */
+-
+-#define AT91_LCDC_CONTRAST_CTR	0x0840		/* Contrast Control Register */
+-#define		AT91_LCDC_PS		(3 << 0)	/* Contrast Counter Prescaler */
+-#define			AT91_LCDC_PS_DIV1		(0 << 0)
+-#define			AT91_LCDC_PS_DIV2		(1 << 0)
+-#define			AT91_LCDC_PS_DIV4		(2 << 0)
+-#define			AT91_LCDC_PS_DIV8		(3 << 0)
+-#define		AT91_LCDC_POL		(1 << 2)	/* Polarity of output Pulse */
+-#define			AT91_LCDC_POL_NEGATIVE		(0 << 2)
+-#define			AT91_LCDC_POL_POSITIVE		(1 << 2)
+-#define		AT91_LCDC_ENA		(1 << 3)	/* PWM generator Control */
+-#define			AT91_LCDC_ENA_PWMDISABLE	(0 << 3)
+-#define			AT91_LCDC_ENA_PWMENABLE		(1 << 3)
+-
+-#define AT91_LCDC_CONTRAST_VAL	0x0844		/* Contrast Value Register */
+-#define		AT91_LCDC_CVAL		(0xff)		/* PWM compare value */
+-
+-#define AT91_LCDC_IER		0x0848		/* Interrupt Enable Register */
+-#define AT91_LCDC_IDR		0x084c		/* Interrupt Disable Register */
+-#define AT91_LCDC_IMR		0x0850		/* Interrupt Mask Register */
+-#define AT91_LCDC_ISR		0x0854		/* Interrupt Enable Register */
+-#define AT91_LCDC_ICR		0x0858		/* Interrupt Clear Register */
+-#define		AT91_LCDC_LNI		(1 << 0)	/* Line Interrupt */
+-#define		AT91_LCDC_LSTLNI	(1 << 1)	/* Last Line Interrupt */
+-#define		AT91_LCDC_EOFI		(1 << 2)	/* DMA End Of Frame Interrupt */
+-#define		AT91_LCDC_UFLWI		(1 << 4)	/* FIFO Underflow Interrupt */
+-#define		AT91_LCDC_OWRI		(1 << 5)	/* FIFO Overwrite Interrupt */
+-#define		AT91_LCDC_MERI		(1 << 6)	/* DMA Memory Error Interrupt */
+-
+-#define AT91_LCDC_LUT_(n)	(0x0c00 + ((n)*4))	/* Palette Entry 0..255 */
+-
+-#endif
+diff --git a/include/asm-arm/arch-at91/at91_pmc.h b/include/asm-arm/arch-at91/at91_pmc.h
+index 33ff5b6..52cd8e5 100644
+--- a/include/asm-arm/arch-at91/at91_pmc.h
++++ b/include/asm-arm/arch-at91/at91_pmc.h
+@@ -25,6 +25,7 @@
+ #define		AT91RM9200_PMC_MCKUDP	(1 <<  2)		/* USB Device Port Master Clock Automatic Disable on Suspend [AT91RM9200 only] */
+ #define		AT91RM9200_PMC_UHP	(1 <<  4)		/* USB Host Port Clock [AT91RM9200 only] */
+ #define		AT91SAM926x_PMC_UHP	(1 <<  6)		/* USB Host Port Clock [AT91SAM926x only] */
++#define		AT91CAP9_PMC_UHP	(1 <<  6)		/* USB Host Port Clock [AT91CAP9 only] */
+ #define		AT91SAM926x_PMC_UDP	(1 <<  7)		/* USB Devcice Port Clock [AT91SAM926x only] */
+ #define		AT91_PMC_PCK0		(1 <<  8)		/* Programmable Clock 0 */
+ #define		AT91_PMC_PCK1		(1 <<  9)		/* Programmable Clock 1 */
+@@ -37,7 +38,9 @@
+ #define	AT91_PMC_PCDR		(AT91_PMC + 0x14)	/* Peripheral Clock Disable Register */
+ #define	AT91_PMC_PCSR		(AT91_PMC + 0x18)	/* Peripheral Clock Status Register */
+ 
+-#define	AT91_CKGR_MOR		(AT91_PMC + 0x20)	/* Main Oscillator Register */
++#define	AT91_CKGR_UCKR		(AT91_PMC + 0x1C)	/* UTMI Clock Register [SAM9RL, CAP9] */
++
++#define	AT91_CKGR_MOR		(AT91_PMC + 0x20)	/* Main Oscillator Register [not on SAM9RL] */
+ #define		AT91_PMC_MOSCEN		(1    << 0)		/* Main Oscillator Enable */
+ #define		AT91_PMC_OSCBYPASS	(1    << 1)		/* Oscillator Bypass [AT91SAM926x only] */
+ #define		AT91_PMC_OSCOUNT	(0xff << 8)		/* Main Oscillator Start-up Time */
+@@ -52,6 +55,10 @@
+ #define		AT91_PMC_PLLCOUNT	(0x3f  <<  8)		/* PLL Counter */
+ #define		AT91_PMC_OUT		(3     << 14)		/* PLL Clock Frequency Range */
+ #define		AT91_PMC_MUL		(0x7ff << 16)		/* PLL Multiplier */
++#define		AT91_PMC_USBDIV		(3     << 28)		/* USB Divisor (PLLB only) */
++#define			AT91_PMC_USBDIV_1		(0 << 28)
++#define			AT91_PMC_USBDIV_2		(1 << 28)
++#define			AT91_PMC_USBDIV_4		(2 << 28)
+ #define		AT91_PMC_USB96M		(1     << 28)		/* Divider by 2 Enable (PLLB only) */
+ 
+ #define	AT91_PMC_MCKR		(AT91_PMC + 0x30)	/* Master Clock Register */
+diff --git a/include/asm-arm/arch-at91/at91_rtt.h b/include/asm-arm/arch-at91/at91_rtt.h
+index bae1103..39a3263 100644
+--- a/include/asm-arm/arch-at91/at91_rtt.h
++++ b/include/asm-arm/arch-at91/at91_rtt.h
+@@ -13,19 +13,19 @@
+ #ifndef AT91_RTT_H
+ #define AT91_RTT_H
+ 
+-#define AT91_RTT_MR		(AT91_RTT + 0x00)	/* Real-time Mode Register */
++#define AT91_RTT_MR		0x00			/* Real-time Mode Register */
+ #define		AT91_RTT_RTPRES		(0xffff << 0)		/* Real-time Timer Prescaler Value */
+ #define		AT91_RTT_ALMIEN		(1 << 16)		/* Alarm Interrupt Enable */
+ #define		AT91_RTT_RTTINCIEN	(1 << 17)		/* Real Time Timer Increment Interrupt Enable */
+ #define		AT91_RTT_RTTRST		(1 << 18)		/* Real Time Timer Restart */
+ 
+-#define AT91_RTT_AR		(AT91_RTT + 0x04)	/* Real-time Alarm Register */
++#define AT91_RTT_AR		0x04			/* Real-time Alarm Register */
+ #define		AT91_RTT_ALMV		(0xffffffff)		/* Alarm Value */
+ 
+-#define AT91_RTT_VR		(AT91_RTT + 0x08)	/* Real-time Value Register */
++#define AT91_RTT_VR		0x08			/* Real-time Value Register */
+ #define		AT91_RTT_CRTV		(0xffffffff)		/* Current Real-time Value */
+ 
+-#define AT91_RTT_SR		(AT91_RTT + 0x0c)	/* Real-time Status Register */
++#define AT91_RTT_SR		0x0c			/* Real-time Status Register */
+ #define		AT91_RTT_ALMS		(1 << 0)		/* Real-time Alarm Status */
+ #define		AT91_RTT_RTTINC		(1 << 1)		/* Real-time Timer Increment */
+ 
+diff --git a/include/asm-arm/arch-at91/at91_twi.h b/include/asm-arm/arch-at91/at91_twi.h
+index ca9a907..f9f2e3c 100644
+--- a/include/asm-arm/arch-at91/at91_twi.h
++++ b/include/asm-arm/arch-at91/at91_twi.h
+@@ -21,6 +21,8 @@
+ #define		AT91_TWI_STOP		(1 <<  1)	/* Send a Stop Condition */
+ #define		AT91_TWI_MSEN		(1 <<  2)	/* Master Transfer Enable */
+ #define		AT91_TWI_MSDIS		(1 <<  3)	/* Master Transfer Disable */
++#define		AT91_TWI_SVEN		(1 <<  4)	/* Slave Transfer Enable [SAM9260 only] */
++#define		AT91_TWI_SVDIS		(1 <<  5)	/* Slave Transfer Disable [SAM9260 only] */
+ #define		AT91_TWI_SWRST		(1 <<  7)	/* Software Reset */
+ 
+ #define	AT91_TWI_MMR		0x04		/* Master Mode Register */
+@@ -32,6 +34,9 @@
+ #define		AT91_TWI_MREAD		(1    << 12)	/* Master Read Direction */
+ #define		AT91_TWI_DADR		(0x7f << 16)	/* Device Address */
+ 
++#define	AT91_TWI_SMR		0x08		/* Slave Mode Register [SAM9260 only] */
++#define		AT91_TWI_SADR		(0x7f << 16)	/* Slave Address */
++
+ #define	AT91_TWI_IADR		0x0c		/* Internal Address Register */
+ 
+ #define	AT91_TWI_CWGR		0x10		/* Clock Waveform Generator Register */
+@@ -43,9 +48,15 @@
+ #define		AT91_TWI_TXCOMP		(1 <<  0)	/* Transmission Complete */
+ #define		AT91_TWI_RXRDY		(1 <<  1)	/* Receive Holding Register Ready */
+ #define		AT91_TWI_TXRDY		(1 <<  2)	/* Transmit Holding Register Ready */
++#define		AT91_TWI_SVREAD		(1 <<  3)	/* Slave Read [SAM9260 only] */
++#define		AT91_TWI_SVACC		(1 <<  4)	/* Slave Access [SAM9260 only] */
++#define		AT91_TWI_GACC		(1 <<  5)	/* General Call Access [SAM9260 only] */
+ #define		AT91_TWI_OVRE		(1 <<  6)	/* Overrun Error [AT91RM9200 only] */
+ #define		AT91_TWI_UNRE		(1 <<  7)	/* Underrun Error [AT91RM9200 only] */
+ #define		AT91_TWI_NACK		(1 <<  8)	/* Not Acknowledged */
++#define		AT91_TWI_ARBLST		(1 <<  9)	/* Arbitration Lost [SAM9260 only] */
++#define		AT91_TWI_SCLWS		(1 << 10)	/* Clock Wait State [SAM9260 only] */
++#define		AT91_TWI_EOSACC		(1 << 11)	/* End of Slave Address [SAM9260 only] */
+ 
+ #define	AT91_TWI_IER		0x24		/* Interrupt Enable Register */
+ #define	AT91_TWI_IDR		0x28		/* Interrupt Disable Register */
+diff --git a/include/asm-arm/arch-at91/at91cap9.h b/include/asm-arm/arch-at91/at91cap9.h
+new file mode 100644
+index 0000000..73e1fcf
+--- /dev/null
++++ b/include/asm-arm/arch-at91/at91cap9.h
+@@ -0,0 +1,121 @@
++/*
++ * include/asm-arm/arch-at91/at91cap9.h
++ *
++ *  Copyright (C) 2007 Stelian Pop <stelian.pop at leadtechdesign.com>
++ *  Copyright (C) 2007 Lead Tech Design <www.leadtechdesign.com>
++ *  Copyright (C) 2007 Atmel Corporation.
++ *
++ * Common definitions.
++ * Based on AT91CAP9 datasheet revision B (Preliminary).
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the 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 AT91CAP9_H
++#define AT91CAP9_H
++
++/*
++ * Peripheral identifiers/interrupts.
++ */
++#define AT91_ID_FIQ		0	/* Advanced Interrupt Controller (FIQ) */
++#define AT91_ID_SYS		1	/* System Peripherals */
++#define AT91CAP9_ID_PIOABCD	2	/* Parallel IO Controller A, B, C and D */
++#define AT91CAP9_ID_MPB0	3	/* MP Block Peripheral 0 */
++#define AT91CAP9_ID_MPB1	4	/* MP Block Peripheral 1 */
++#define AT91CAP9_ID_MPB2	5	/* MP Block Peripheral 2 */
++#define AT91CAP9_ID_MPB3	6	/* MP Block Peripheral 3 */
++#define AT91CAP9_ID_MPB4	7	/* MP Block Peripheral 4 */
++#define AT91CAP9_ID_US0		8	/* USART 0 */
++#define AT91CAP9_ID_US1		9	/* USART 1 */
++#define AT91CAP9_ID_US2		10	/* USART 2 */
++#define AT91CAP9_ID_MCI0	11	/* Multimedia Card Interface 0 */
++#define AT91CAP9_ID_MCI1	12	/* Multimedia Card Interface 1 */
++#define AT91CAP9_ID_CAN		13	/* CAN */
++#define AT91CAP9_ID_TWI		14	/* Two-Wire Interface */
++#define AT91CAP9_ID_SPI0	15	/* Serial Peripheral Interface 0 */
++#define AT91CAP9_ID_SPI1	16	/* Serial Peripheral Interface 0 */
++#define AT91CAP9_ID_SSC0	17	/* Serial Synchronous Controller 0 */
++#define AT91CAP9_ID_SSC1	18	/* Serial Synchronous Controller 1 */
++#define AT91CAP9_ID_AC97C	19	/* AC97 Controller */
++#define AT91CAP9_ID_TCB		20	/* Timer Counter 0, 1 and 2 */
++#define AT91CAP9_ID_PWMC	21	/* Pulse Width Modulation Controller */
++#define AT91CAP9_ID_EMAC	22	/* Ethernet */
++#define AT91CAP9_ID_AESTDES	23	/* Advanced Encryption Standard, Triple DES */
++#define AT91CAP9_ID_ADC		24	/* Analog-to-Digital Converter */
++#define AT91CAP9_ID_ISI		25	/* Image Sensor Interface */
++#define AT91CAP9_ID_LCDC	26	/* LCD Controller */
++#define AT91CAP9_ID_DMA		27	/* DMA Controller */
++#define AT91CAP9_ID_UDPHS	28	/* USB High Speed Device Port */
++#define AT91CAP9_ID_UHP		29	/* USB Host Port */
++#define AT91CAP9_ID_IRQ0	30	/* Advanced Interrupt Controller (IRQ0) */
++#define AT91CAP9_ID_IRQ1	31	/* Advanced Interrupt Controller (IRQ1) */
++
++/*
++ * User Peripheral physical base addresses.
++ */
++#define AT91CAP9_BASE_UDPHS		0xfff78000
++#define AT91CAP9_BASE_TCB0		0xfff7c000
++#define AT91CAP9_BASE_TC0		0xfff7c000
++#define AT91CAP9_BASE_TC1		0xfff7c040
++#define AT91CAP9_BASE_TC2		0xfff7c080
++#define AT91CAP9_BASE_MCI0		0xfff80000
++#define AT91CAP9_BASE_MCI1		0xfff84000
++#define AT91CAP9_BASE_TWI		0xfff88000
++#define AT91CAP9_BASE_US0		0xfff8c000
++#define AT91CAP9_BASE_US1		0xfff90000
++#define AT91CAP9_BASE_US2		0xfff94000
++#define AT91CAP9_BASE_SSC0		0xfff98000
++#define AT91CAP9_BASE_SSC1		0xfff9c000
++#define AT91CAP9_BASE_AC97C		0xfffa0000
++#define AT91CAP9_BASE_SPI0		0xfffa4000
++#define AT91CAP9_BASE_SPI1		0xfffa8000
++#define AT91CAP9_BASE_CAN		0xfffac000
++#define AT91CAP9_BASE_PWMC		0xfffb8000
++#define AT91CAP9_BASE_EMAC		0xfffbc000
++#define AT91CAP9_BASE_ADC		0xfffc0000
++#define AT91CAP9_BASE_ISI		0xfffc4000
++#define AT91_BASE_SYS			0xffffe200
++
++/*
++ * System Peripherals (offset from AT91_BASE_SYS)
++ */
++#define AT91_ECC	(0xffffe200 - AT91_BASE_SYS)
++#define AT91_BCRAMC	(0xffffe400 - AT91_BASE_SYS)
++#define AT91_DDRSDRC	(0xffffe600 - AT91_BASE_SYS)
++#define AT91_SMC	(0xffffe800 - AT91_BASE_SYS)
++#define AT91_MATRIX	(0xffffea00 - AT91_BASE_SYS)
++#define AT91_CCFG	(0xffffeb10 - AT91_BASE_SYS)
++#define AT91_DMA	(0xffffec00 - AT91_BASE_SYS)
++#define AT91_DBGU	(0xffffee00 - AT91_BASE_SYS)
++#define AT91_AIC	(0xfffff000 - AT91_BASE_SYS)
++#define AT91_PIOA	(0xfffff200 - AT91_BASE_SYS)
++#define AT91_PIOB	(0xfffff400 - AT91_BASE_SYS)
++#define AT91_PIOC	(0xfffff600 - AT91_BASE_SYS)
++#define AT91_PIOD	(0xfffff800 - AT91_BASE_SYS)
++#define AT91_PMC	(0xfffffc00 - AT91_BASE_SYS)
++#define AT91_RSTC	(0xfffffd00 - AT91_BASE_SYS)
++#define AT91_SHDC	(0xfffffd10 - AT91_BASE_SYS)
++#define AT91_RTT	(0xfffffd20 - AT91_BASE_SYS)
++#define AT91_PIT	(0xfffffd30 - AT91_BASE_SYS)
++#define AT91_WDT	(0xfffffd40 - AT91_BASE_SYS)
++#define AT91_GPBR	(0xfffffd50 - AT91_BASE_SYS)
++
++/*
++ * Internal Memory.
++ */
++#define AT91CAP9_SRAM_BASE	0x00100000	/* Internal SRAM base address */
++#define AT91CAP9_SRAM_SIZE	(32 * SZ_1K)	/* Internal SRAM size (32Kb) */
++
++#define AT91CAP9_ROM_BASE	0x00400000	/* Internal ROM base address */
++#define AT91CAP9_ROM_SIZE	(32 * SZ_1K)	/* Internal ROM size (32Kb) */
++
++#define AT91CAP9_LCDC_BASE	0x00500000	/* LCD Controller */
++#define AT91CAP9_UDPHS_BASE	0x00600000	/* USB High Speed Device Port */
++#define AT91CAP9_UHP_BASE	0x00700000	/* USB Host controller */
++
++#define CONFIG_DRAM_BASE	AT91_CHIPSELECT_6
++
++#endif
+diff --git a/include/asm-arm/arch-at91/at91cap9_matrix.h b/include/asm-arm/arch-at91/at91cap9_matrix.h
+new file mode 100644
+index 0000000..a641686
+--- /dev/null
++++ b/include/asm-arm/arch-at91/at91cap9_matrix.h
+@@ -0,0 +1,132 @@
++/*
++ * include/asm-arm/arch-at91/at91cap9_matrix.h
++ *
++ *  Copyright (C) 2007 Stelian Pop <stelian.pop at leadtechdesign.com>
++ *  Copyright (C) 2007 Lead Tech Design <www.leadtechdesign.com>
++ *  Copyright (C) 2006 Atmel Corporation.
++ *
++ * Memory Controllers (MATRIX, EBI) - System peripherals registers.
++ * Based on AT91CAP9 datasheet revision B (Preliminary).
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the 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 AT91CAP9_MATRIX_H
++#define AT91CAP9_MATRIX_H
++
++#define AT91_MATRIX_MCFG0	(AT91_MATRIX + 0x00)	/* Master Configuration Register 0 */
++#define AT91_MATRIX_MCFG1	(AT91_MATRIX + 0x04)	/* Master Configuration Register 1 */
++#define AT91_MATRIX_MCFG2	(AT91_MATRIX + 0x08)	/* Master Configuration Register 2 */
++#define AT91_MATRIX_MCFG3	(AT91_MATRIX + 0x0C)	/* Master Configuration Register 3 */
++#define AT91_MATRIX_MCFG4	(AT91_MATRIX + 0x10)	/* Master Configuration Register 4 */
++#define AT91_MATRIX_MCFG5	(AT91_MATRIX + 0x14)	/* Master Configuration Register 5 */
++#define AT91_MATRIX_MCFG6	(AT91_MATRIX + 0x18)	/* Master Configuration Register 6 */
++#define AT91_MATRIX_MCFG7	(AT91_MATRIX + 0x1C)	/* Master Configuration Register 7 */
++#define AT91_MATRIX_MCFG8	(AT91_MATRIX + 0x20)	/* Master Configuration Register 8 */
++#define AT91_MATRIX_MCFG9	(AT91_MATRIX + 0x24)	/* Master Configuration Register 9 */
++#define AT91_MATRIX_MCFG10	(AT91_MATRIX + 0x28)	/* Master Configuration Register 10 */
++#define AT91_MATRIX_MCFG11	(AT91_MATRIX + 0x2C)	/* Master Configuration Register 11 */
++#define		AT91_MATRIX_ULBT	(7 << 0)	/* Undefined Length Burst Type */
++#define			AT91_MATRIX_ULBT_INFINITE	(0 << 0)
++#define			AT91_MATRIX_ULBT_SINGLE		(1 << 0)
++#define			AT91_MATRIX_ULBT_FOUR		(2 << 0)
++#define			AT91_MATRIX_ULBT_EIGHT		(3 << 0)
++#define			AT91_MATRIX_ULBT_SIXTEEN	(4 << 0)
++
++#define AT91_MATRIX_SCFG0	(AT91_MATRIX + 0x40)	/* Slave Configuration Register 0 */
++#define AT91_MATRIX_SCFG1	(AT91_MATRIX + 0x44)	/* Slave Configuration Register 1 */
++#define AT91_MATRIX_SCFG2	(AT91_MATRIX + 0x48)	/* Slave Configuration Register 2 */
++#define AT91_MATRIX_SCFG3	(AT91_MATRIX + 0x4C)	/* Slave Configuration Register 3 */
++#define AT91_MATRIX_SCFG4	(AT91_MATRIX + 0x50)	/* Slave Configuration Register 4 */
++#define AT91_MATRIX_SCFG5	(AT91_MATRIX + 0x54)	/* Slave Configuration Register 5 */
++#define AT91_MATRIX_SCFG6	(AT91_MATRIX + 0x58)	/* Slave Configuration Register 6 */
++#define AT91_MATRIX_SCFG7	(AT91_MATRIX + 0x5C)	/* Slave Configuration Register 7 */
++#define AT91_MATRIX_SCFG8	(AT91_MATRIX + 0x60)	/* Slave Configuration Register 8 */
++#define AT91_MATRIX_SCFG9	(AT91_MATRIX + 0x64)	/* Slave Configuration Register 9 */
++#define		AT91_MATRIX_SLOT_CYCLE		(0xff << 0)	/* Maximum Number of Allowed Cycles for a Burst */
++#define		AT91_MATRIX_DEFMSTR_TYPE	(3    << 16)	/* Default Master Type */
++#define			AT91_MATRIX_DEFMSTR_TYPE_NONE	(0 << 16)
++#define			AT91_MATRIX_DEFMSTR_TYPE_LAST	(1 << 16)
++#define			AT91_MATRIX_DEFMSTR_TYPE_FIXED	(2 << 16)
++#define		AT91_MATRIX_FIXED_DEFMSTR	(0xf  << 18)	/* Fixed Index of Default Master */
++#define		AT91_MATRIX_ARBT		(3    << 24)	/* Arbitration Type */
++#define			AT91_MATRIX_ARBT_ROUND_ROBIN	(0 << 24)
++#define			AT91_MATRIX_ARBT_FIXED_PRIORITY	(1 << 24)
++
++#define AT91_MATRIX_PRAS0	(AT91_MATRIX + 0x80)	/* Priority Register A for Slave 0 */
++#define AT91_MATRIX_PRBS0	(AT91_MATRIX + 0x84)	/* Priority Register B for Slave 0 */
++#define AT91_MATRIX_PRAS1	(AT91_MATRIX + 0x88)	/* Priority Register A for Slave 1 */
++#define AT91_MATRIX_PRBS1	(AT91_MATRIX + 0x8C)	/* Priority Register B for Slave 1 */
++#define AT91_MATRIX_PRAS2	(AT91_MATRIX + 0x90)	/* Priority Register A for Slave 2 */
++#define AT91_MATRIX_PRBS2	(AT91_MATRIX + 0x94)	/* Priority Register B for Slave 2 */
++#define AT91_MATRIX_PRAS3	(AT91_MATRIX + 0x98)	/* Priority Register A for Slave 3 */
++#define AT91_MATRIX_PRBS3	(AT91_MATRIX + 0x9C)	/* Priority Register B for Slave 3 */
++#define AT91_MATRIX_PRAS4	(AT91_MATRIX + 0xA0)	/* Priority Register A for Slave 4 */
++#define AT91_MATRIX_PRBS4	(AT91_MATRIX + 0xA4)	/* Priority Register B for Slave 4 */
++#define AT91_MATRIX_PRAS5	(AT91_MATRIX + 0xA8)	/* Priority Register A for Slave 5 */
++#define AT91_MATRIX_PRBS5	(AT91_MATRIX + 0xAC)	/* Priority Register B for Slave 5 */
++#define AT91_MATRIX_PRAS6	(AT91_MATRIX + 0xB0)	/* Priority Register A for Slave 6 */
++#define AT91_MATRIX_PRBS6	(AT91_MATRIX + 0xB4)	/* Priority Register B for Slave 6 */
++#define AT91_MATRIX_PRAS7	(AT91_MATRIX + 0xB8)	/* Priority Register A for Slave 7 */
++#define AT91_MATRIX_PRBS7	(AT91_MATRIX + 0xBC)	/* Priority Register B for Slave 7 */
++#define AT91_MATRIX_PRAS8	(AT91_MATRIX + 0xC0)	/* Priority Register A for Slave 8 */
++#define AT91_MATRIX_PRBS8	(AT91_MATRIX + 0xC4)	/* Priority Register B for Slave 8 */
++#define AT91_MATRIX_PRAS9	(AT91_MATRIX + 0xC8)	/* Priority Register A for Slave 9 */
++#define AT91_MATRIX_PRBS9	(AT91_MATRIX + 0xCC)	/* Priority Register B for Slave 9 */
++#define		AT91_MATRIX_M0PR		(3 << 0)	/* Master 0 Priority */
++#define		AT91_MATRIX_M1PR		(3 << 4)	/* Master 1 Priority */
++#define		AT91_MATRIX_M2PR		(3 << 8)	/* Master 2 Priority */
++#define		AT91_MATRIX_M3PR		(3 << 12)	/* Master 3 Priority */
++#define		AT91_MATRIX_M4PR		(3 << 16)	/* Master 4 Priority */
++#define		AT91_MATRIX_M5PR		(3 << 20)	/* Master 5 Priority */
++#define		AT91_MATRIX_M6PR		(3 << 24)	/* Master 6 Priority */
++#define		AT91_MATRIX_M7PR		(3 << 28)	/* Master 7 Priority */
++#define		AT91_MATRIX_M8PR		(3 << 0)	/* Master 8 Priority (in Register B) */
++#define		AT91_MATRIX_M9PR		(3 << 4)	/* Master 9 Priority (in Register B) */
++#define		AT91_MATRIX_M10PR		(3 << 8)	/* Master 10 Priority (in Register B) */
++#define		AT91_MATRIX_M11PR		(3 << 12)	/* Master 11 Priority (in Register B) */
++
++#define AT91_MATRIX_MRCR	(AT91_MATRIX + 0x100)	/* Master Remap Control Register */
++#define		AT91_MATRIX_RCB0		(1 << 0)	/* Remap Command for AHB Master 0 (ARM926EJ-S Instruction Master) */
++#define		AT91_MATRIX_RCB1		(1 << 1)	/* Remap Command for AHB Master 1 (ARM926EJ-S Data Master) */
++#define		AT91_MATRIX_RCB2		(1 << 2)
++#define		AT91_MATRIX_RCB3		(1 << 3)
++#define		AT91_MATRIX_RCB4		(1 << 4)
++#define		AT91_MATRIX_RCB5		(1 << 5)
++#define		AT91_MATRIX_RCB6		(1 << 6)
++#define		AT91_MATRIX_RCB7		(1 << 7)
++#define		AT91_MATRIX_RCB8		(1 << 8)
++#define		AT91_MATRIX_RCB9		(1 << 9)
++#define		AT91_MATRIX_RCB10		(1 << 10)
++#define		AT91_MATRIX_RCB11		(1 << 11)
++
++#define AT91_MPBS0_SFR		(AT91_MATRIX + 0x114)	/* MPBlock Slave 0 Special Function Register */
++#define AT91_MPBS1_SFR		(AT91_MATRIX + 0x11C)	/* MPBlock Slave 1 Special Function Register */
++
++#define AT91_MATRIX_EBICSA	(AT91_MATRIX + 0x120)	/* EBI Chip Select Assignment Register */
++#define		AT91_MATRIX_EBI_CS1A		(1 << 1)	/* Chip Select 1 Assignment */
++#define			AT91_MATRIX_EBI_CS1A_SMC		(0 << 1)
++#define			AT91_MATRIX_EBI_CS1A_BCRAMC		(1 << 1)
++#define		AT91_MATRIX_EBI_CS3A		(1 << 3)	/* Chip Select 3 Assignment */
++#define			AT91_MATRIX_EBI_CS3A_SMC		(0 << 3)
++#define			AT91_MATRIX_EBI_CS3A_SMC_SMARTMEDIA	(1 << 3)
++#define		AT91_MATRIX_EBI_CS4A		(1 << 4)	/* Chip Select 4 Assignment */
++#define			AT91_MATRIX_EBI_CS4A_SMC		(0 << 4)
++#define			AT91_MATRIX_EBI_CS4A_SMC_CF1		(1 << 4)
++#define		AT91_MATRIX_EBI_CS5A		(1 << 5)	/* Chip Select 5 Assignment */
++#define			AT91_MATRIX_EBI_CS5A_SMC		(0 << 5)
++#define			AT91_MATRIX_EBI_CS5A_SMC_CF2		(1 << 5)
++#define		AT91_MATRIX_EBI_DBPUC		(1 << 8)	/* Data Bus Pull-up Configuration */
++#define		AT91_MATRIX_EBI_DQSPDC		(1 << 9)	/* Data Qualifier Strobe Pull-Down Configuration */
++#define		AT91_MATRIX_EBI_VDDIOMSEL	(1 << 16)	/* Memory voltage selection */
++#define			AT91_MATRIX_EBI_VDDIOMSEL_1_8V		(0 << 16)
++#define			AT91_MATRIX_EBI_VDDIOMSEL_3_3V		(1 << 16)
++
++#define AT91_MPBS2_SFR		(AT91_MATRIX + 0x12C)	/* MPBlock Slave 2 Special Function Register */
++#define AT91_MPBS3_SFR		(AT91_MATRIX + 0x130)	/* MPBlock Slave 3 Special Function Register */
++#define AT91_APB_SFR		(AT91_MATRIX + 0x134)	/* APB Bridge Special Function Register */
++
++#endif
+diff --git a/include/asm-arm/arch-at91/at91sam9260_matrix.h b/include/asm-arm/arch-at91/at91sam9260_matrix.h
+index aacb1e9..a8e9fec 100644
+--- a/include/asm-arm/arch-at91/at91sam9260_matrix.h
++++ b/include/asm-arm/arch-at91/at91sam9260_matrix.h
+@@ -67,7 +67,7 @@
+ #define		AT91_MATRIX_CS4A		(1 << 4)	/* Chip Select 4 Assignment */
+ #define			AT91_MATRIX_CS4A_SMC		(0 << 4)
+ #define			AT91_MATRIX_CS4A_SMC_CF1	(1 << 4)
+-#define		AT91_MATRIX_CS5A		(1 << 5 )	/* Chip Select 5 Assignment */
++#define		AT91_MATRIX_CS5A		(1 << 5)	/* Chip Select 5 Assignment */
+ #define			AT91_MATRIX_CS5A_SMC		(0 << 5)
+ #define			AT91_MATRIX_CS5A_SMC_CF2	(1 << 5)
+ #define		AT91_MATRIX_DBPUC		(1 << 8)	/* Data Bus Pull-up Configuration */
+diff --git a/include/asm-arm/arch-at91/at91sam9263_matrix.h b/include/asm-arm/arch-at91/at91sam9263_matrix.h
+index 6fc6e4b..72f6e66 100644
+--- a/include/asm-arm/arch-at91/at91sam9263_matrix.h
++++ b/include/asm-arm/arch-at91/at91sam9263_matrix.h
+@@ -44,7 +44,7 @@
+ #define			AT91_MATRIX_DEFMSTR_TYPE_NONE	(0 << 16)
+ #define			AT91_MATRIX_DEFMSTR_TYPE_LAST	(1 << 16)
+ #define			AT91_MATRIX_DEFMSTR_TYPE_FIXED	(2 << 16)
+-#define		AT91_MATRIX_FIXED_DEFMSTR	(7    << 18)	/* Fixed Index of Default Master */
++#define		AT91_MATRIX_FIXED_DEFMSTR	(0xf  << 18)	/* Fixed Index of Default Master */
+ #define		AT91_MATRIX_ARBT		(3    << 24)	/* Arbitration Type */
+ #define			AT91_MATRIX_ARBT_ROUND_ROBIN	(0 << 24)
+ #define			AT91_MATRIX_ARBT_FIXED_PRIORITY	(1 << 24)
+diff --git a/include/asm-arm/arch-at91/at91sam9rl_matrix.h b/include/asm-arm/arch-at91/at91sam9rl_matrix.h
+index b15f11b..8422417 100644
+--- a/include/asm-arm/arch-at91/at91sam9rl_matrix.h
++++ b/include/asm-arm/arch-at91/at91sam9rl_matrix.h
+@@ -38,7 +38,7 @@
+ #define			AT91_MATRIX_DEFMSTR_TYPE_NONE	(0 << 16)
+ #define			AT91_MATRIX_DEFMSTR_TYPE_LAST	(1 << 16)
+ #define			AT91_MATRIX_DEFMSTR_TYPE_FIXED	(2 << 16)
+-#define		AT91_MATRIX_FIXED_DEFMSTR	(7    << 18)	/* Fixed Index of Default Master */
++#define		AT91_MATRIX_FIXED_DEFMSTR	(0xf  << 18)	/* Fixed Index of Default Master */
+ #define		AT91_MATRIX_ARBT		(3    << 24)	/* Arbitration Type */
+ #define			AT91_MATRIX_ARBT_ROUND_ROBIN	(0 << 24)
+ #define			AT91_MATRIX_ARBT_FIXED_PRIORITY	(1 << 24)
+diff --git a/include/asm-arm/arch-at91/board.h b/include/asm-arm/arch-at91/board.h
+index 7905496..55b07bd 100644
+--- a/include/asm-arm/arch-at91/board.h
++++ b/include/asm-arm/arch-at91/board.h
+@@ -34,6 +34,7 @@
+ #include <linux/mtd/partitions.h>
+ #include <linux/device.h>
+ #include <linux/i2c.h>
++#include <linux/leds.h>
+ #include <linux/spi/spi.h>
  
- /* /sys/fs */
--decl_subsys(fs, NULL, NULL);
--EXPORT_SYMBOL_GPL(fs_subsys);
-+struct kobject *fs_kobj;
-+EXPORT_SYMBOL_GPL(fs_kobj);
+  /* USB Device */
+@@ -71,7 +72,7 @@ struct at91_eth_data {
+ };
+ extern void __init at91_add_device_eth(struct at91_eth_data *data);
  
- static inline unsigned long hash(struct vfsmount *mnt, struct dentry *dentry)
- {
-@@ -1861,10 +1861,9 @@ void __init mnt_init(void)
- 	if (err)
- 		printk(KERN_WARNING "%s: sysfs_init error: %d\n",
- 			__FUNCTION__, err);
--	err = subsystem_register(&fs_subsys);
--	if (err)
--		printk(KERN_WARNING "%s: subsystem_register error: %d\n",
--			__FUNCTION__, err);
-+	fs_kobj = kobject_create_and_add("fs", NULL);
-+	if (!fs_kobj)
-+		printk(KERN_WARNING "%s: kobj create error\n", __FUNCTION__);
- 	init_rootfs();
- 	init_mount_tree();
- }
-diff --git a/fs/ocfs2/Makefile b/fs/ocfs2/Makefile
-index 9fb8132..4d4ce48 100644
---- a/fs/ocfs2/Makefile
-+++ b/fs/ocfs2/Makefile
-@@ -19,16 +19,17 @@ ocfs2-objs := \
- 	ioctl.o 		\
- 	journal.o 		\
- 	localalloc.o 		\
-+	locks.o			\
- 	mmap.o 			\
- 	namei.o 		\
-+	resize.o		\
- 	slot_map.o 		\
- 	suballoc.o 		\
- 	super.o 		\
- 	symlink.o 		\
- 	sysfile.o 		\
- 	uptodate.o		\
--	ver.o 			\
--	vote.o
-+	ver.o
+-#if defined(CONFIG_ARCH_AT91SAM9260) || defined(CONFIG_ARCH_AT91SAM9263)
++#if defined(CONFIG_ARCH_AT91SAM9260) || defined(CONFIG_ARCH_AT91SAM9263) || defined(CONFIG_ARCH_AT91CAP9)
+ #define eth_platform_data	at91_eth_data
+ #endif
  
- obj-$(CONFIG_OCFS2_FS) += cluster/
- obj-$(CONFIG_OCFS2_FS) += dlm/
-diff --git a/fs/ocfs2/alloc.c b/fs/ocfs2/alloc.c
-index 23c8cda..e6df06a 100644
---- a/fs/ocfs2/alloc.c
-+++ b/fs/ocfs2/alloc.c
-@@ -4731,7 +4731,7 @@ int __ocfs2_flush_truncate_log(struct ocfs2_super *osb)
+@@ -101,13 +102,23 @@ extern void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_de
+ extern void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices);
  
- 	mutex_lock(&data_alloc_inode->i_mutex);
+  /* Serial */
++#define ATMEL_UART_CTS	0x01
++#define ATMEL_UART_RTS	0x02
++#define ATMEL_UART_DSR	0x04
++#define ATMEL_UART_DTR	0x08
++#define ATMEL_UART_DCD	0x10
++#define ATMEL_UART_RI	0x20
++
++extern void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins);
++extern void __init at91_set_serial_console(unsigned portnr);
++
+ struct at91_uart_config {
+ 	unsigned short	console_tty;	/* tty number of serial console */
+ 	unsigned short	nr_tty;		/* number of serial tty's */
+ 	short		tty_map[];	/* map UART to tty number */
+ };
+ extern struct platform_device *atmel_default_console_device;
+-extern void __init at91_init_serial(struct at91_uart_config *config);
++extern void __init __deprecated at91_init_serial(struct at91_uart_config *config);
+ 
+ struct atmel_uart_data {
+ 	short		use_dma_tx;	/* use transmit DMA? */
+@@ -116,6 +127,23 @@ struct atmel_uart_data {
+ };
+ extern void __init at91_add_device_serial(void);
+ 
++/*
++ * 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.
++ */
++#define ATMEL_SSC_TK	0x01
++#define ATMEL_SSC_TF	0x02
++#define ATMEL_SSC_TD	0x04
++#define ATMEL_SSC_TX	(ATMEL_SSC_TK | ATMEL_SSC_TF | ATMEL_SSC_TD)
++
++#define ATMEL_SSC_RK	0x10
++#define ATMEL_SSC_RF	0x20
++#define ATMEL_SSC_RD	0x40
++#define ATMEL_SSC_RX	(ATMEL_SSC_RK | ATMEL_SSC_RF | ATMEL_SSC_RD)
++
++extern void __init at91_add_device_ssc(unsigned id, unsigned pins);
++
+  /* LCD Controller */
+ struct atmel_lcdfb_info;
+ extern void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data);
+@@ -126,10 +154,12 @@ struct atmel_ac97_data {
+ };
+ extern void __init at91_add_device_ac97(struct atmel_ac97_data *data);
+ 
++ /* ISI */
++extern void __init at91_add_device_isi(void);
++
+  /* LEDs */
+-extern u8 at91_leds_cpu;
+-extern u8 at91_leds_timer;
+ extern void __init at91_init_leds(u8 cpu_led, u8 timer_led);
++extern void __init at91_gpio_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/include/asm-arm/arch-at91/cpu.h b/include/asm-arm/arch-at91/cpu.h
+index 080cbb4..7145166 100644
+--- a/include/asm-arm/arch-at91/cpu.h
++++ b/include/asm-arm/arch-at91/cpu.h
+@@ -21,13 +21,13 @@
+ #define ARCH_ID_AT91SAM9260	0x019803a0
+ #define ARCH_ID_AT91SAM9261	0x019703a0
+ #define ARCH_ID_AT91SAM9263	0x019607a0
++#define ARCH_ID_AT91SAM9RL64	0x019b03a0
++#define ARCH_ID_AT91CAP9	0x039A03A0
+ 
+ #define ARCH_ID_AT91SAM9XE128	0x329973a0
+ #define ARCH_ID_AT91SAM9XE256	0x329a93a0
+ #define ARCH_ID_AT91SAM9XE512	0x329aa3a0
+ 
+-#define ARCH_ID_AT91SAM9RL64	0x019b03a0
+-
+ #define ARCH_ID_AT91M40800	0x14080044
+ #define ARCH_ID_AT91R40807	0x44080746
+ #define ARCH_ID_AT91M40807	0x14080745
+@@ -81,6 +81,11 @@ static inline unsigned long at91_arch_identify(void)
+ #define cpu_is_at91sam9rl()	(0)
+ #endif
  
--	status = ocfs2_meta_lock(data_alloc_inode, &data_alloc_bh, 1);
-+	status = ocfs2_inode_lock(data_alloc_inode, &data_alloc_bh, 1);
- 	if (status < 0) {
- 		mlog_errno(status);
- 		goto out_mutex;
-@@ -4753,7 +4753,7 @@ int __ocfs2_flush_truncate_log(struct ocfs2_super *osb)
++#ifdef CONFIG_ARCH_AT91CAP9
++#define cpu_is_at91cap9()	(at91_cpu_identify() == ARCH_ID_AT91CAP9)
++#else
++#define cpu_is_at91cap9()	(0)
++#endif
  
- out_unlock:
- 	brelse(data_alloc_bh);
--	ocfs2_meta_unlock(data_alloc_inode, 1);
-+	ocfs2_inode_unlock(data_alloc_inode, 1);
+ /*
+  * Since this is ARM, we will never run on any AVR32 CPU. But these
+diff --git a/include/asm-arm/arch-at91/entry-macro.S b/include/asm-arm/arch-at91/entry-macro.S
+index cc1d850..1005eee 100644
+--- a/include/asm-arm/arch-at91/entry-macro.S
++++ b/include/asm-arm/arch-at91/entry-macro.S
+@@ -17,13 +17,13 @@
+ 	.endm
+ 
+ 	.macro  get_irqnr_preamble, base, tmp
++	ldr	\base, =(AT91_VA_BASE_SYS + AT91_AIC)		@ base virtual address of AIC peripheral
+ 	.endm
+ 
+ 	.macro  arch_ret_to_user, tmp1, tmp2
+ 	.endm
+ 
+ 	.macro	get_irqnr_and_base, irqnr, irqstat, base, tmp
+-	ldr	\base, =(AT91_VA_BASE_SYS + AT91_AIC)		@ base virtual address of AIC peripheral
+ 	ldr	\irqnr, [\base, #(AT91_AIC_IVR - AT91_AIC)]	@ read IRQ vector register: de-asserts nIRQ to processor (and clears interrupt)
+ 	ldr	\irqstat, [\base, #(AT91_AIC_ISR - AT91_AIC)]	@ read interrupt source number
+ 	teq	\irqstat, #0					@ ISR is 0 when no current interrupt, or spurious interrupt
+diff --git a/include/asm-arm/arch-at91/hardware.h b/include/asm-arm/arch-at91/hardware.h
+index 8f1cdd3..2c826d8 100644
+--- a/include/asm-arm/arch-at91/hardware.h
++++ b/include/asm-arm/arch-at91/hardware.h
+@@ -26,6 +26,8 @@
+ #include <asm/arch/at91sam9263.h>
+ #elif defined(CONFIG_ARCH_AT91SAM9RL)
+ #include <asm/arch/at91sam9rl.h>
++#elif defined(CONFIG_ARCH_AT91CAP9)
++#include <asm/arch/at91cap9.h>
+ #elif defined(CONFIG_ARCH_AT91X40)
+ #include <asm/arch/at91x40.h>
+ #else
+diff --git a/include/asm-arm/arch-at91/timex.h b/include/asm-arm/arch-at91/timex.h
+index a310698..f1933b0 100644
+--- a/include/asm-arm/arch-at91/timex.h
++++ b/include/asm-arm/arch-at91/timex.h
+@@ -42,6 +42,11 @@
+ #define AT91SAM9_MASTER_CLOCK	100000000
+ #define CLOCK_TICK_RATE		(AT91SAM9_MASTER_CLOCK/16)
+ 
++#elif defined(CONFIG_ARCH_AT91CAP9)
++
++#define AT91CAP9_MASTER_CLOCK	100000000
++#define CLOCK_TICK_RATE		(AT91CAP9_MASTER_CLOCK/16)
++
+ #elif defined(CONFIG_ARCH_AT91X40)
+ 
+ #define AT91X40_MASTER_CLOCK	40000000
+diff --git a/include/asm-arm/arch-ep93xx/gpio.h b/include/asm-arm/arch-ep93xx/gpio.h
+index 1ee14a1..9b1864b 100644
+--- a/include/asm-arm/arch-ep93xx/gpio.h
++++ b/include/asm-arm/arch-ep93xx/gpio.h
+@@ -5,16 +5,6 @@
+ #ifndef __ASM_ARCH_GPIO_H
+ #define __ASM_ARCH_GPIO_H
+ 
+-#define GPIO_IN				0
+-#define GPIO_OUT			1
+-
+-#define EP93XX_GPIO_LOW			0
+-#define EP93XX_GPIO_HIGH		1
+-
+-extern void gpio_line_config(int line, int direction);
+-extern int  gpio_line_get(int line);
+-extern void gpio_line_set(int line, int value);
+-
+ /* GPIO port A.  */
+ #define EP93XX_GPIO_LINE_A(x)		((x) + 0)
+ #define EP93XX_GPIO_LINE_EGPIO0		EP93XX_GPIO_LINE_A(0)
+@@ -38,7 +28,7 @@ extern void gpio_line_set(int line, int value);
+ #define EP93XX_GPIO_LINE_EGPIO15	EP93XX_GPIO_LINE_B(7)
+ 
+ /* GPIO port C.  */
+-#define EP93XX_GPIO_LINE_C(x)		((x) + 16)
++#define EP93XX_GPIO_LINE_C(x)		((x) + 40)
+ #define EP93XX_GPIO_LINE_ROW0		EP93XX_GPIO_LINE_C(0)
+ #define EP93XX_GPIO_LINE_ROW1		EP93XX_GPIO_LINE_C(1)
+ #define EP93XX_GPIO_LINE_ROW2		EP93XX_GPIO_LINE_C(2)
+@@ -71,7 +61,7 @@ extern void gpio_line_set(int line, int value);
+ #define EP93XX_GPIO_LINE_IDEDA2		EP93XX_GPIO_LINE_E(7)
+ 
+ /* GPIO port F.  */
+-#define EP93XX_GPIO_LINE_F(x)		((x) + 40)
++#define EP93XX_GPIO_LINE_F(x)		((x) + 16)
+ #define EP93XX_GPIO_LINE_WP		EP93XX_GPIO_LINE_F(0)
+ #define EP93XX_GPIO_LINE_MCCD1		EP93XX_GPIO_LINE_F(1)
+ #define EP93XX_GPIO_LINE_MCCD2		EP93XX_GPIO_LINE_F(2)
+@@ -103,5 +93,49 @@ extern void gpio_line_set(int line, int value);
+ #define EP93XX_GPIO_LINE_DD6		EP93XX_GPIO_LINE_H(6)
+ #define EP93XX_GPIO_LINE_DD7		EP93XX_GPIO_LINE_H(7)
+ 
++/* maximum value for gpio line identifiers */
++#define EP93XX_GPIO_LINE_MAX		EP93XX_GPIO_LINE_H(7)
++
++/* maximum value for irq capable line identifiers */
++#define EP93XX_GPIO_LINE_MAX_IRQ	EP93XX_GPIO_LINE_F(7)
++
++/* new generic GPIO API - see Documentation/gpio.txt */
++
++static inline int gpio_request(unsigned gpio, const char *label)
++{
++	if (gpio > EP93XX_GPIO_LINE_MAX)
++		return -EINVAL;
++	return 0;
++}
++
++static inline void gpio_free(unsigned gpio)
++{
++}
++
++int gpio_direction_input(unsigned gpio);
++int gpio_direction_output(unsigned gpio, int value);
++int gpio_get_value(unsigned gpio);
++void gpio_set_value(unsigned gpio, int value);
++
++#include <asm-generic/gpio.h> /* cansleep wrappers */
++
++/*
++ * Map GPIO A0..A7  (0..7)  to irq 64..71,
++ *          B0..B7  (7..15) to irq 72..79, and
++ *          F0..F7 (16..24) to irq 80..87.
++ */
++
++static inline int gpio_to_irq(unsigned gpio)
++{
++	if (gpio <= EP93XX_GPIO_LINE_MAX_IRQ)
++		return 64 + gpio;
++
++	return -EINVAL;
++}
++
++static inline int irq_to_gpio(unsigned irq)
++{
++	return irq - gpio_to_irq(0);
++}
  
- out_mutex:
- 	mutex_unlock(&data_alloc_inode->i_mutex);
-@@ -5077,7 +5077,7 @@ static int ocfs2_free_cached_items(struct ocfs2_super *osb,
+ #endif
+diff --git a/include/asm-arm/arch-ep93xx/irqs.h b/include/asm-arm/arch-ep93xx/irqs.h
+index 2a8c636..53d4a68 100644
+--- a/include/asm-arm/arch-ep93xx/irqs.h
++++ b/include/asm-arm/arch-ep93xx/irqs.h
+@@ -67,12 +67,6 @@
+ #define IRQ_EP93XX_SAI			60
+ #define EP93XX_VIC2_VALID_IRQ_MASK	0x1fffffff
  
- 	mutex_lock(&inode->i_mutex);
+-/*
+- * Map GPIO A0..A7 to irq 64..71, B0..B7 to 72..79, and
+- * F0..F7 to 80..87.
+- */
+-#define IRQ_EP93XX_GPIO(x)		(64 + (((x) + (((x) >> 2) & 8)) & 0x1f))
+-
+ #define NR_EP93XX_IRQS			(64 + 24)
  
--	ret = ocfs2_meta_lock(inode, &di_bh, 1);
-+	ret = ocfs2_inode_lock(inode, &di_bh, 1);
- 	if (ret) {
- 		mlog_errno(ret);
- 		goto out_mutex;
-@@ -5118,7 +5118,7 @@ out_journal:
- 	ocfs2_commit_trans(osb, handle);
+ #define EP93XX_BOARD_IRQ(x)		(NR_EP93XX_IRQS + (x))
+diff --git a/include/asm-arm/arch-ixp4xx/io.h b/include/asm-arm/arch-ixp4xx/io.h
+index eeeea90..9c5d235 100644
+--- a/include/asm-arm/arch-ixp4xx/io.h
++++ b/include/asm-arm/arch-ixp4xx/io.h
+@@ -61,13 +61,13 @@ __ixp4xx_ioremap(unsigned long addr, size_t size, unsigned int mtype)
+ 	if((addr < PCIBIOS_MIN_MEM) || (addr > 0x4fffffff))
+ 		return __arm_ioremap(addr, size, mtype);
  
- out_unlock:
--	ocfs2_meta_unlock(inode, 1);
-+	ocfs2_inode_unlock(inode, 1);
- 	brelse(di_bh);
- out_mutex:
- 	mutex_unlock(&inode->i_mutex);
-diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c
-index 56f7790..bc7b4cb 100644
---- a/fs/ocfs2/aops.c
-+++ b/fs/ocfs2/aops.c
-@@ -26,6 +26,7 @@
- #include <asm/byteorder.h>
- #include <linux/swap.h>
- #include <linux/pipe_fs_i.h>
-+#include <linux/mpage.h>
+-	return (void *)addr;
++	return (void __iomem *)addr;
+ }
  
- #define MLOG_MASK_PREFIX ML_FILE_IO
- #include <cluster/masklog.h>
-@@ -139,7 +140,8 @@ static int ocfs2_get_block(struct inode *inode, sector_t iblock,
+ static inline void
+ __ixp4xx_iounmap(void __iomem *addr)
  {
- 	int err = 0;
- 	unsigned int ext_flags;
--	u64 p_blkno, past_eof;
-+	u64 max_blocks = bh_result->b_size >> inode->i_blkbits;
-+	u64 p_blkno, count, past_eof;
- 	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
- 
- 	mlog_entry("(0x%p, %llu, 0x%p, %d)\n", inode,
-@@ -155,7 +157,7 @@ static int ocfs2_get_block(struct inode *inode, sector_t iblock,
- 		goto bail;
+-	if ((u32)addr >= VMALLOC_START)
++	if ((__force u32)addr >= VMALLOC_START)
+ 		__iounmap(addr);
+ }
+ 
+@@ -141,9 +141,9 @@ __ixp4xx_writesw(volatile void __iomem *bus_addr, const u16 *vaddr, int count)
+ static inline void 
+ __ixp4xx_writel(u32 value, volatile void __iomem *p)
+ {
+-	u32 addr = (u32)p;
++	u32 addr = (__force u32)p;
+ 	if (addr >= VMALLOC_START) {
+-		__raw_writel(value, addr);
++		__raw_writel(value, p);
+ 		return;
  	}
  
--	err = ocfs2_extent_map_get_blocks(inode, iblock, &p_blkno, NULL,
-+	err = ocfs2_extent_map_get_blocks(inode, iblock, &p_blkno, &count,
- 					  &ext_flags);
- 	if (err) {
- 		mlog(ML_ERROR, "Error %d from get_blocks(0x%p, %llu, 1, "
-@@ -164,6 +166,9 @@ static int ocfs2_get_block(struct inode *inode, sector_t iblock,
- 		goto bail;
- 	}
+@@ -208,11 +208,11 @@ __ixp4xx_readsw(const volatile void __iomem *bus_addr, u16 *vaddr, u32 count)
+ static inline unsigned long 
+ __ixp4xx_readl(const volatile void __iomem *p)
+ {
+-	u32 addr = (u32)p;
++	u32 addr = (__force u32)p;
+ 	u32 data;
  
-+	if (max_blocks < count)
-+		count = max_blocks;
+ 	if (addr >= VMALLOC_START)
+-		return __raw_readl(addr);
++		return __raw_readl(p);
+ 
+ 	if (ixp4xx_pci_read(addr, NP_CMD_MEMREAD, &data))
+ 		return 0xffffffff;
+@@ -438,7 +438,7 @@ __ixp4xx_ioread32(const void __iomem *addr)
+ 		return	(unsigned int)__ixp4xx_inl(port & PIO_MASK);
+ 	else {
+ #ifndef CONFIG_IXP4XX_INDIRECT_PCI
+-		return le32_to_cpu(__raw_readl((u32)port));
++		return le32_to_cpu((__force __le32)__raw_readl(addr));
+ #else
+ 		return (unsigned int)__ixp4xx_readl(addr);
+ #endif
+@@ -523,7 +523,7 @@ __ixp4xx_iowrite32(u32 value, void __iomem *addr)
+ 		__ixp4xx_outl(value, port & PIO_MASK);
+ 	else
+ #ifndef CONFIG_IXP4XX_INDIRECT_PCI
+-		__raw_writel(cpu_to_le32(value), port);
++		__raw_writel((u32 __force)cpu_to_le32(value), addr);
+ #else
+ 		__ixp4xx_writel(value, addr);
+ #endif
+diff --git a/include/asm-arm/arch-ixp4xx/platform.h b/include/asm-arm/arch-ixp4xx/platform.h
+index 2a44d3d..2ce28e3 100644
+--- a/include/asm-arm/arch-ixp4xx/platform.h
++++ b/include/asm-arm/arch-ixp4xx/platform.h
+@@ -76,17 +76,6 @@ extern unsigned long ixp4xx_exp_bus_size;
+ #define IXP4XX_UART_XTAL        	14745600
+ 
+ /*
+- * The IXP4xx chips do not have an I2C unit, so GPIO lines are just
+- * used to 
+- * Used as platform_data to provide GPIO pin information to the ixp42x
+- * I2C driver.
+- */
+-struct ixp4xx_i2c_pins {
+-	unsigned long sda_pin;
+-	unsigned long scl_pin;
+-};
+-
+-/*
+  * This structure provide a means for the board setup code
+  * to give information to th pata_ixp4xx driver. It is
+  * passed as platform_data.
+diff --git a/include/asm-arm/arch-ks8695/regs-gpio.h b/include/asm-arm/arch-ks8695/regs-gpio.h
+index 57fcf9f..6b95d77 100644
+--- a/include/asm-arm/arch-ks8695/regs-gpio.h
++++ b/include/asm-arm/arch-ks8695/regs-gpio.h
+@@ -49,5 +49,7 @@
+ #define IOPC_TM_FALLING		(4)		/* Falling Edge Detection */
+ #define IOPC_TM_EDGE		(6)		/* Both Edge Detection */
+ 
++/* Port Data Register */
++#define IOPD_(x)		(1 << (x))	/* Signal Level of GPIO Pin x */
+ 
+ #endif
+diff --git a/include/asm-arm/arch-msm/board.h b/include/asm-arm/arch-msm/board.h
+new file mode 100644
+index 0000000..763051f
+--- /dev/null
++++ b/include/asm-arm/arch-msm/board.h
+@@ -0,0 +1,37 @@
++/* linux/include/asm-arm/arch-msm/board.h
++ *
++ * Copyright (C) 2007 Google, Inc.
++ * Author: Brian Swetland <swetland at google.com>
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ */
++
++#ifndef __ASM_ARCH_MSM_BOARD_H
++#define __ASM_ARCH_MSM_BOARD_H
++
++#include <linux/types.h>
++
++/* platform device data structures */
++
++struct msm_mddi_platform_data
++{
++	void (*panel_power)(int on);
++	unsigned has_vsync_irq:1;
++};
++
++/* common init routines for use by arch/arm/mach-msm/board-*.c */
++
++void __init msm_add_devices(void);
++void __init msm_map_common_io(void);
++void __init msm_init_irq(void);
++void __init msm_init_gpio(void);
++
++#endif
+diff --git a/include/asm-arm/arch-msm/debug-macro.S b/include/asm-arm/arch-msm/debug-macro.S
+new file mode 100644
+index 0000000..393d527
+--- /dev/null
++++ b/include/asm-arm/arch-msm/debug-macro.S
+@@ -0,0 +1,40 @@
++/* include/asm-arm/arch-msm7200/debug-macro.S
++ *
++ * Copyright (C) 2007 Google, Inc.
++ * Author: Brian Swetland <swetland at google.com>
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ */
++
++#include <asm/hardware.h>
++#include <asm/arch/msm_iomap.h>
++
++	.macro	addruart,rx
++	@ see if the MMU is enabled and select appropriate base address
++	mrc	p15, 0, \rx, c1, c0
++	tst	\rx, #1
++	ldreq	\rx, =MSM_UART1_PHYS
++	ldrne	\rx, =MSM_UART1_BASE
++	.endm
++
++	.macro	senduart,rd,rx
++	str	\rd, [\rx, #0x0C]
++	.endm
++
++	.macro	waituart,rd,rx
++	@ wait for TX_READY
++1:	ldr	\rd, [\rx, #0x08]
++	tst	\rd, #0x04
++	beq	1b
++	.endm
++
++	.macro	busyuart,rd,rx
++	.endm
+diff --git a/include/asm-arm/arch-msm/dma.h b/include/asm-arm/arch-msm/dma.h
+new file mode 100644
+index 0000000..e4b565b
+--- /dev/null
++++ b/include/asm-arm/arch-msm/dma.h
+@@ -0,0 +1,151 @@
++/* linux/include/asm-arm/arch-msm/dma.h
++ *
++ * Copyright (C) 2007 Google, Inc.
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ */
++
++#ifndef __ASM_ARCH_MSM_DMA_H
++
++#include <linux/list.h>
++#include <asm/arch/msm_iomap.h>
++
++struct msm_dmov_cmd {
++	struct list_head list;
++	unsigned int cmdptr;
++	void (*complete_func)(struct msm_dmov_cmd *cmd, unsigned int result);
++/*	void (*user_result_func)(struct msm_dmov_cmd *cmd); */
++};
++
++void msm_dmov_enqueue_cmd(unsigned id, struct msm_dmov_cmd *cmd);
++void msm_dmov_stop_cmd(unsigned id, struct msm_dmov_cmd *cmd);
++int msm_dmov_exec_cmd(unsigned id, unsigned int cmdptr);
++/* int msm_dmov_exec_cmd_etc(unsigned id, unsigned int cmdptr, int timeout, int interruptible); */
++
++
++
++#define DMOV_SD0(off, ch) (MSM_DMOV_BASE + 0x0000 + (off) + ((ch) << 2))
++#define DMOV_SD1(off, ch) (MSM_DMOV_BASE + 0x0400 + (off) + ((ch) << 2))
++#define DMOV_SD2(off, ch) (MSM_DMOV_BASE + 0x0800 + (off) + ((ch) << 2))
++#define DMOV_SD3(off, ch) (MSM_DMOV_BASE + 0x0C00 + (off) + ((ch) << 2))
++
++/* only security domain 3 is available to the ARM11
++ * SD0 -> mARM trusted, SD1 -> mARM nontrusted, SD2 -> aDSP, SD3 -> aARM
++ */
++
++#define DMOV_CMD_PTR(ch)      DMOV_SD3(0x000, ch)
++#define DMOV_CMD_LIST         (0 << 29) /* does not work */
++#define DMOV_CMD_PTR_LIST     (1 << 29) /* works */
++#define DMOV_CMD_INPUT_CFG    (2 << 29) /* untested */
++#define DMOV_CMD_OUTPUT_CFG   (3 << 29) /* untested */
++#define DMOV_CMD_ADDR(addr)   ((addr) >> 3)
++
++#define DMOV_RSLT(ch)         DMOV_SD3(0x040, ch)
++#define DMOV_RSLT_VALID       (1 << 31) /* 0 == host has empties result fifo */
++#define DMOV_RSLT_ERROR       (1 << 3)
++#define DMOV_RSLT_FLUSH       (1 << 2)
++#define DMOV_RSLT_DONE        (1 << 1)  /* top pointer done */
++#define DMOV_RSLT_USER        (1 << 0)  /* command with FR force result */
++
++#define DMOV_FLUSH0(ch)       DMOV_SD3(0x080, ch)
++#define DMOV_FLUSH1(ch)       DMOV_SD3(0x0C0, ch)
++#define DMOV_FLUSH2(ch)       DMOV_SD3(0x100, ch)
++#define DMOV_FLUSH3(ch)       DMOV_SD3(0x140, ch)
++#define DMOV_FLUSH4(ch)       DMOV_SD3(0x180, ch)
++#define DMOV_FLUSH5(ch)       DMOV_SD3(0x1C0, ch)
++
++#define DMOV_STATUS(ch)       DMOV_SD3(0x200, ch)
++#define DMOV_STATUS_RSLT_COUNT(n)    (((n) >> 29))
++#define DMOV_STATUS_CMD_COUNT(n)     (((n) >> 27) & 3)
++#define DMOV_STATUS_RSLT_VALID       (1 << 1)
++#define DMOV_STATUS_CMD_PTR_RDY      (1 << 0)
++
++#define DMOV_ISR              DMOV_SD3(0x380, 0)
++
++#define DMOV_CONFIG(ch)       DMOV_SD3(0x300, ch)
++#define DMOV_CONFIG_FORCE_TOP_PTR_RSLT (1 << 2)
++#define DMOV_CONFIG_FORCE_FLUSH_RSLT   (1 << 1)
++#define DMOV_CONFIG_IRQ_EN             (1 << 0)
++
++/* channel assignments */
++
++#define DMOV_NAND_CHAN        7
++#define DMOV_NAND_CRCI_CMD    5
++#define DMOV_NAND_CRCI_DATA   4
++
++#define DMOV_SDC1_CHAN        8
++#define DMOV_SDC1_CRCI        6
++
++#define DMOV_SDC2_CHAN        8
++#define DMOV_SDC2_CRCI        7
++
++#define DMOV_TSIF_CHAN        10
++#define DMOV_TSIF_CRCI        10
++
++#define DMOV_USB_CHAN         11
++
++/* no client rate control ifc (eg, ram) */
++#define DMOV_NONE_CRCI        0
++
++
++/* If the CMD_PTR register has CMD_PTR_LIST selected, the data mover
++ * is going to walk a list of 32bit pointers as described below.  Each
++ * pointer points to a *array* of dmov_s, etc structs.  The last pointer
++ * in the list is marked with CMD_PTR_LP.  The last struct in each array
++ * is marked with CMD_LC (see below).
++ */
++#define CMD_PTR_ADDR(addr)  ((addr) >> 3)
++#define CMD_PTR_LP          (1 << 31) /* last pointer */
++#define CMD_PTR_PT          (3 << 29) /* ? */
++
++/* Single Item Mode */
++typedef struct {
++	unsigned cmd;
++	unsigned src;
++	unsigned dst;
++	unsigned len;
++} dmov_s;
++
++/* Scatter/Gather Mode */
++typedef struct {
++	unsigned cmd;
++	unsigned src_dscr;
++	unsigned dst_dscr;
++	unsigned _reserved;
++} dmov_sg;
++
++/* bits for the cmd field of the above structures */
++
++#define CMD_LC      (1 << 31)  /* last command */
++#define CMD_FR      (1 << 22)  /* force result -- does not work? */
++#define CMD_OCU     (1 << 21)  /* other channel unblock */
++#define CMD_OCB     (1 << 20)  /* other channel block */
++#define CMD_TCB     (1 << 19)  /* ? */
++#define CMD_DAH     (1 << 18)  /* destination address hold -- does not work?*/
++#define CMD_SAH     (1 << 17)  /* source address hold -- does not work? */
++
++#define CMD_MODE_SINGLE     (0 << 0) /* dmov_s structure used */
++#define CMD_MODE_SG         (1 << 0) /* untested */
++#define CMD_MODE_IND_SG     (2 << 0) /* untested */
++#define CMD_MODE_BOX        (3 << 0) /* untested */
++
++#define CMD_DST_SWAP_BYTES  (1 << 14) /* exchange each byte n with byte n+1 */
++#define CMD_DST_SWAP_SHORTS (1 << 15) /* exchange each short n with short n+1 */
++#define CMD_DST_SWAP_WORDS  (1 << 16) /* exchange each word n with word n+1 */
++
++#define CMD_SRC_SWAP_BYTES  (1 << 11) /* exchange each byte n with byte n+1 */
++#define CMD_SRC_SWAP_SHORTS (1 << 12) /* exchange each short n with short n+1 */
++#define CMD_SRC_SWAP_WORDS  (1 << 13) /* exchange each word n with word n+1 */
++
++#define CMD_DST_CRCI(n)     (((n) & 15) << 7)
++#define CMD_SRC_CRCI(n)     (((n) & 15) << 3)
++
++#endif
+diff --git a/include/asm-arm/arch-msm/entry-macro.S b/include/asm-arm/arch-msm/entry-macro.S
+new file mode 100644
+index 0000000..ee24aec
+--- /dev/null
++++ b/include/asm-arm/arch-msm/entry-macro.S
+@@ -0,0 +1,38 @@
++/* include/asm-arm/arch-msm7200/entry-macro.S
++ *
++ * Copyright (C) 2007 Google, Inc.
++ * Author: Brian Swetland <swetland at google.com>
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ */
++
++#include <asm/arch/msm_iomap.h>
++
++ 	.macro	disable_fiq
++	.endm
++
++	.macro	get_irqnr_preamble, base, tmp
++	@ enable imprecise aborts
++	cpsie	a
++	mov	\base, #MSM_VIC_BASE
++	.endm
++
++	.macro	arch_ret_to_user, tmp1, tmp2
++	.endm
++
++	.macro	get_irqnr_and_base, irqnr, irqstat, base, tmp
++	@ 0xD0 has irq# or old irq# if the irq has been handled
++	@ 0xD4 has irq# or -1 if none pending *but* if you just
++	@ read 0xD4 you never get the first irq for some reason
++	ldr	\irqnr, [\base, #0xD0]
++	ldr	\irqnr, [\base, #0xD4]
++	cmp	\irqnr, #0xffffffff
++	.endm
+diff --git a/include/asm-arm/arch-msm/hardware.h b/include/asm-arm/arch-msm/hardware.h
+new file mode 100644
+index 0000000..89af2b7
+--- /dev/null
++++ b/include/asm-arm/arch-msm/hardware.h
+@@ -0,0 +1,18 @@
++/* linux/include/asm-arm/arch-msm/hardware.h
++ *
++ * Copyright (C) 2007 Google, Inc.
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ */
++
++#ifndef __ASM_ARCH_MSM_HARDWARE_H
++
++#endif
+diff --git a/include/asm-arm/arch-msm/io.h b/include/asm-arm/arch-msm/io.h
+new file mode 100644
+index 0000000..4645ae2
+--- /dev/null
++++ b/include/asm-arm/arch-msm/io.h
+@@ -0,0 +1,33 @@
++/* include/asm-arm/arch-msm/io.h
++ *
++ * Copyright (C) 2007 Google, Inc.
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ */
++
++#ifndef __ASM_ARM_ARCH_IO_H
++#define __ASM_ARM_ARCH_IO_H
++
++#define IO_SPACE_LIMIT 0xffffffff
++
++#define __arch_ioremap __msm_ioremap
++#define __arch_iounmap __iounmap
++
++void __iomem *__msm_ioremap(unsigned long phys_addr, size_t size, unsigned int mtype);
++
++static inline void __iomem *__io(unsigned long addr)
++{
++	return (void __iomem *)addr;
++}
++#define __io(a)         __io(a)
++#define __mem_pci(a)    (a)
++
++#endif
+diff --git a/include/asm-arm/arch-msm/irqs.h b/include/asm-arm/arch-msm/irqs.h
+new file mode 100644
+index 0000000..565430c
+--- /dev/null
++++ b/include/asm-arm/arch-msm/irqs.h
+@@ -0,0 +1,89 @@
++/* linux/include/asm-arm/arch-msm/irqs.h
++ *
++ * Copyright (C) 2007 Google, Inc.
++ * Author: Brian Swetland <swetland at google.com>
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ */
++
++#ifndef __ASM_ARCH_MSM_IRQS_H
++
++/* MSM ARM11 Interrupt Numbers */
++/* See 80-VE113-1 A, pp219-221     */
++
++#define INT_A9_M2A_0         0
++#define INT_A9_M2A_1         1
++#define INT_A9_M2A_2         2
++#define INT_A9_M2A_3         3
++#define INT_A9_M2A_4         4
++#define INT_A9_M2A_5         5
++#define INT_A9_M2A_6         6
++#define INT_GP_TIMER_EXP     7
++#define INT_DEBUG_TIMER_EXP  8
++#define INT_UART1            9
++#define INT_UART2            10
++#define INT_UART3            11
++#define INT_UART1_RX         12
++#define INT_UART2_RX         13
++#define INT_UART3_RX         14
++#define INT_USB_OTG          15
++#define INT_MDDI_PRI         16
++#define INT_MDDI_EXT         17
++#define INT_MDDI_CLIENT      18
++#define INT_MDP              19
++#define INT_GRAPHICS         20
++#define INT_ADM_AARM         21
++#define INT_ADSP_A11         22
++#define INT_ADSP_A9_A11      23
++#define INT_SDC1_0           24
++#define INT_SDC1_1           25
++#define INT_SDC2_0           26
++#define INT_SDC2_1           27
++#define INT_KEYSENSE         28
++#define INT_TCHSCRN_SSBI     29
++#define INT_TCHSCRN1         30
++#define INT_TCHSCRN2         31
++
++#define INT_GPIO_GROUP1      (32 + 0)
++#define INT_GPIO_GROUP2      (32 + 1)
++#define INT_PWB_I2C          (32 + 2)
++#define INT_SOFTRESET        (32 + 3)
++#define INT_NAND_WR_ER_DONE  (32 + 4)
++#define INT_NAND_OP_DONE     (32 + 5)
++#define INT_PBUS_ARM11       (32 + 6)
++#define INT_AXI_MPU_SMI      (32 + 7)
++#define INT_AXI_MPU_EBI1     (32 + 8)
++#define INT_AD_HSSD          (32 + 9)
++#define INT_ARM11_PMU        (32 + 10)
++#define INT_ARM11_DMA        (32 + 11)
++#define INT_TSIF_IRQ         (32 + 12)
++#define INT_UART1DM_IRQ      (32 + 13)
++#define INT_UART1DM_RX       (32 + 14)
++#define INT_USB_HS           (32 + 15)
++#define INT_SDC3_0           (32 + 16)
++#define INT_SDC3_1           (32 + 17)
++#define INT_SDC4_0           (32 + 18)
++#define INT_SDC4_1           (32 + 19)
++#define INT_UART2DM_RX       (32 + 20)
++#define INT_UART2DM_IRQ      (32 + 21)
++
++/* 22-31 are reserved */
++
++#define MSM_IRQ_BIT(irq)     (1 << ((irq) & 31))
++
++#define NR_MSM_IRQS 64
++#define NR_GPIO_IRQS 122
++#define NR_BOARD_IRQS 64
++#define NR_IRQS (NR_MSM_IRQS + NR_GPIO_IRQS + NR_BOARD_IRQS)
++
++#define MSM_GPIO_TO_INT(n) (NR_MSM_IRQS + (n))
++
++#endif
+diff --git a/include/asm-arm/arch-msm/memory.h b/include/asm-arm/arch-msm/memory.h
+new file mode 100644
+index 0000000..b5ce0e9
+--- /dev/null
++++ b/include/asm-arm/arch-msm/memory.h
+@@ -0,0 +1,27 @@
++/* linux/include/asm-arm/arch-msm/memory.h
++ *
++ * Copyright (C) 2007 Google, Inc.
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ */
++
++#ifndef __ASM_ARCH_MEMORY_H
++#define __ASM_ARCH_MEMORY_H
++
++/* physical offset of RAM */
++#define PHYS_OFFSET		UL(0x10000000)
++
++/* bus address and physical addresses are identical */
++#define __virt_to_bus(x)	__virt_to_phys(x)
++#define __bus_to_virt(x)	__phys_to_virt(x)
++
++#endif
++
+diff --git a/include/asm-arm/arch-msm/msm_iomap.h b/include/asm-arm/arch-msm/msm_iomap.h
+new file mode 100644
+index 0000000..b8955cc
+--- /dev/null
++++ b/include/asm-arm/arch-msm/msm_iomap.h
+@@ -0,0 +1,104 @@
++/* linux/include/asm-arm/arch-msm/msm_iomap.h
++ *
++ * Copyright (C) 2007 Google, Inc.
++ * Author: Brian Swetland <swetland at google.com>
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ *
++ * The MSM peripherals are spread all over across 768MB of physical
++ * space, which makes just having a simple IO_ADDRESS macro to slide
++ * them into the right virtual location rough.  Instead, we will
++ * provide a master phys->virt mapping for peripherals here.
++ *
++ */
++
++#ifndef __ASM_ARCH_MSM_IOMAP_H
++#define __ASM_ARCH_MSM_IOMAP_H
++
++#include <asm/sizes.h>
++
++/* Physical base address and size of peripherals.
++ * Ordered by the virtual base addresses they will be mapped at.
++ *
++ * MSM_VIC_BASE must be an value that can be loaded via a "mov"
++ * instruction, otherwise entry-macro.S will not compile.
++ *
++ * If you add or remove entries here, you'll want to edit the
++ * msm_io_desc array in arch/arm/mach-msm/io.c to reflect your
++ * changes.
++ *
++ */
++
++#define MSM_VIC_BASE          0xE0000000
++#define MSM_VIC_PHYS          0xC0000000
++#define MSM_VIC_SIZE          SZ_4K
++
++#define MSM_CSR_BASE          0xE0001000
++#define MSM_CSR_PHYS          0xC0100000
++#define MSM_CSR_SIZE          SZ_4K
++
++#define MSM_GPT_PHYS          MSM_CSR_PHYS
++#define MSM_GPT_BASE          MSM_CSR_BASE
++#define MSM_GPT_SIZE          SZ_4K
++
++#define MSM_DMOV_BASE         0xE0002000
++#define MSM_DMOV_PHYS         0xA9700000
++#define MSM_DMOV_SIZE         SZ_4K
++
++#define MSM_UART1_BASE        0xE0003000
++#define MSM_UART1_PHYS        0xA9A00000
++#define MSM_UART1_SIZE        SZ_4K
++
++#define MSM_UART2_BASE        0xE0004000
++#define MSM_UART2_PHYS        0xA9B00000
++#define MSM_UART2_SIZE        SZ_4K
++
++#define MSM_UART3_BASE        0xE0005000
++#define MSM_UART3_PHYS        0xA9C00000
++#define MSM_UART3_SIZE        SZ_4K
++
++#define MSM_I2C_BASE          0xE0006000
++#define MSM_I2C_PHYS          0xA9900000
++#define MSM_I2C_SIZE          SZ_4K
++
++#define MSM_GPIO1_BASE        0xE0007000
++#define MSM_GPIO1_PHYS        0xA9200000
++#define MSM_GPIO1_SIZE        SZ_4K
++
++#define MSM_GPIO2_BASE        0xE0008000
++#define MSM_GPIO2_PHYS        0xA9300000
++#define MSM_GPIO2_SIZE        SZ_4K
++
++#define MSM_HSUSB_BASE        0xE0009000
++#define MSM_HSUSB_PHYS        0xA0800000
++#define MSM_HSUSB_SIZE        SZ_4K
++
++#define MSM_CLK_CTL_BASE      0xE000A000
++#define MSM_CLK_CTL_PHYS      0xA8600000
++#define MSM_CLK_CTL_SIZE      SZ_4K
++
++#define MSM_PMDH_BASE         0xE000B000
++#define MSM_PMDH_PHYS         0xAA600000
++#define MSM_PMDH_SIZE         SZ_4K
++
++#define MSM_EMDH_BASE         0xE000C000
++#define MSM_EMDH_PHYS         0xAA700000
++#define MSM_EMDH_SIZE         SZ_4K
++
++#define MSM_MDP_BASE          0xE0010000
++#define MSM_MDP_PHYS          0xAA200000
++#define MSM_MDP_SIZE          0x000F0000
++
++#define MSM_SHARED_RAM_BASE   0xE0100000
++#define MSM_SHARED_RAM_PHYS   0x01F00000
++#define MSM_SHARED_RAM_SIZE   SZ_1M
++
++#endif
+diff --git a/include/asm-arm/arch-msm/system.h b/include/asm-arm/arch-msm/system.h
+new file mode 100644
+index 0000000..7c5544b
+--- /dev/null
++++ b/include/asm-arm/arch-msm/system.h
+@@ -0,0 +1,23 @@
++/* linux/include/asm-arm/arch-msm/system.h
++ *
++ * Copyright (C) 2007 Google, Inc.
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ */
++
++#include <asm/hardware.h>
++
++void arch_idle(void);
++
++static inline void arch_reset(char mode)
++{
++	for (;;) ;  /* depends on IPC w/ other core */
++}
+diff --git a/include/asm-arm/arch-msm/timex.h b/include/asm-arm/arch-msm/timex.h
+new file mode 100644
+index 0000000..154b23f
+--- /dev/null
++++ b/include/asm-arm/arch-msm/timex.h
+@@ -0,0 +1,20 @@
++/* linux/include/asm-arm/arch-msm/timex.h
++ *
++ * Copyright (C) 2007 Google, Inc.
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ */
 +
- 	/*
- 	 * ocfs2 never allocates in this function - the only time we
- 	 * need to use BH_New is when we're extending i_size on a file
-@@ -178,6 +183,8 @@ static int ocfs2_get_block(struct inode *inode, sector_t iblock,
- 	if (p_blkno && !(ext_flags & OCFS2_EXT_UNWRITTEN))
- 		map_bh(bh_result, inode->i_sb, p_blkno);
- 
-+	bh_result->b_size = count << inode->i_blkbits;
++#ifndef __ASM_ARCH_MSM_TIMEX_H
 +
- 	if (!ocfs2_sparse_alloc(osb)) {
- 		if (p_blkno == 0) {
- 			err = -EIO;
-@@ -210,7 +217,7 @@ int ocfs2_read_inline_data(struct inode *inode, struct page *page,
- 			   struct buffer_head *di_bh)
- {
- 	void *kaddr;
--	unsigned int size;
-+	loff_t size;
- 	struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
- 
- 	if (!(le16_to_cpu(di->i_dyn_features) & OCFS2_INLINE_DATA_FL)) {
-@@ -224,8 +231,9 @@ int ocfs2_read_inline_data(struct inode *inode, struct page *page,
- 	if (size > PAGE_CACHE_SIZE ||
- 	    size > ocfs2_max_inline_data(inode->i_sb)) {
- 		ocfs2_error(inode->i_sb,
--			    "Inode %llu has with inline data has bad size: %u",
--			    (unsigned long long)OCFS2_I(inode)->ip_blkno, size);
-+			    "Inode %llu has with inline data has bad size: %Lu",
-+			    (unsigned long long)OCFS2_I(inode)->ip_blkno,
-+			    (unsigned long long)size);
- 		return -EROFS;
- 	}
- 
-@@ -275,7 +283,7 @@ static int ocfs2_readpage(struct file *file, struct page *page)
- 
- 	mlog_entry("(0x%p, %lu)\n", file, (page ? page->index : 0));
- 
--	ret = ocfs2_meta_lock_with_page(inode, NULL, 0, page);
-+	ret = ocfs2_inode_lock_with_page(inode, NULL, 0, page);
- 	if (ret != 0) {
- 		if (ret == AOP_TRUNCATED_PAGE)
- 			unlock = 0;
-@@ -285,7 +293,7 @@ static int ocfs2_readpage(struct file *file, struct page *page)
- 
- 	if (down_read_trylock(&oi->ip_alloc_sem) == 0) {
- 		ret = AOP_TRUNCATED_PAGE;
--		goto out_meta_unlock;
-+		goto out_inode_unlock;
- 	}
- 
- 	/*
-@@ -305,25 +313,16 @@ static int ocfs2_readpage(struct file *file, struct page *page)
- 		goto out_alloc;
- 	}
- 
--	ret = ocfs2_data_lock_with_page(inode, 0, page);
--	if (ret != 0) {
--		if (ret == AOP_TRUNCATED_PAGE)
--			unlock = 0;
--		mlog_errno(ret);
--		goto out_alloc;
--	}
--
- 	if (oi->ip_dyn_features & OCFS2_INLINE_DATA_FL)
- 		ret = ocfs2_readpage_inline(inode, page);
- 	else
- 		ret = block_read_full_page(page, ocfs2_get_block);
- 	unlock = 0;
- 
--	ocfs2_data_unlock(inode, 0);
- out_alloc:
- 	up_read(&OCFS2_I(inode)->ip_alloc_sem);
--out_meta_unlock:
--	ocfs2_meta_unlock(inode, 0);
-+out_inode_unlock:
-+	ocfs2_inode_unlock(inode, 0);
- out:
- 	if (unlock)
- 		unlock_page(page);
-@@ -331,6 +330,62 @@ out:
- 	return ret;
- }
- 
-+/*
-+ * This is used only for read-ahead. Failures or difficult to handle
-+ * situations are safe to ignore.
++#define CLOCK_TICK_RATE		1000000
++
++#endif
+diff --git a/include/asm-arm/arch-msm/uncompress.h b/include/asm-arm/arch-msm/uncompress.h
+new file mode 100644
+index 0000000..e91ed78
+--- /dev/null
++++ b/include/asm-arm/arch-msm/uncompress.h
+@@ -0,0 +1,36 @@
++/* linux/include/asm-arm/arch-msm/uncompress.h
++ *
++ * Copyright (C) 2007 Google, Inc.
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
 + *
-+ * Right now, we don't bother with BH_Boundary - in-inode extent lists
-+ * are quite large (243 extents on 4k blocks), so most inodes don't
-+ * grow out to a tree. If need be, detecting boundary extents could
-+ * trivially be added in a future version of ocfs2_get_block().
 + */
-+static int ocfs2_readpages(struct file *filp, struct address_space *mapping,
-+			   struct list_head *pages, unsigned nr_pages)
++
++#ifndef __ASM_ARCH_MSM_UNCOMPRESS_H
++
++#include "hardware.h"
++
++static void putc(int c)
 +{
-+	int ret, err = -EIO;
-+	struct inode *inode = mapping->host;
-+	struct ocfs2_inode_info *oi = OCFS2_I(inode);
-+	loff_t start;
-+	struct page *last;
++}
 +
-+	/*
-+	 * Use the nonblocking flag for the dlm code to avoid page
-+	 * lock inversion, but don't bother with retrying.
-+	 */
-+	ret = ocfs2_inode_lock_full(inode, NULL, 0, OCFS2_LOCK_NONBLOCK);
-+	if (ret)
-+		return err;
++static inline void flush(void)
++{
++}
 +
-+	if (down_read_trylock(&oi->ip_alloc_sem) == 0) {
-+		ocfs2_inode_unlock(inode, 0);
-+		return err;
-+	}
++static inline void arch_decomp_setup(void)
++{
++}
 +
-+	/*
-+	 * Don't bother with inline-data. There isn't anything
-+	 * to read-ahead in that case anyway...
-+	 */
-+	if (oi->ip_dyn_features & OCFS2_INLINE_DATA_FL)
-+		goto out_unlock;
++static inline void arch_decomp_wdog(void)
++{
++}
 +
-+	/*
-+	 * Check whether a remote node truncated this file - we just
-+	 * drop out in that case as it's not worth handling here.
-+	 */
-+	last = list_entry(pages->prev, struct page, lru);
-+	start = (loff_t)last->index << PAGE_CACHE_SHIFT;
-+	if (start >= i_size_read(inode))
-+		goto out_unlock;
++#endif
+diff --git a/include/asm-arm/arch-msm/vmalloc.h b/include/asm-arm/arch-msm/vmalloc.h
+new file mode 100644
+index 0000000..60f8d91
+--- /dev/null
++++ b/include/asm-arm/arch-msm/vmalloc.h
+@@ -0,0 +1,22 @@
++/* linux/include/asm-arm/arch-msm/vmalloc.h
++ *
++ * Copyright (C) 2007 Google, Inc.
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ */
 +
-+	err = mpage_readpages(mapping, pages, nr_pages, ocfs2_get_block);
++#ifndef __ASM_ARCH_MSM_VMALLOC_H
++#define __ASM_ARCH_MSM_VMALLOC_H
 +
-+out_unlock:
-+	up_read(&oi->ip_alloc_sem);
-+	ocfs2_inode_unlock(inode, 0);
++#define VMALLOC_END	  (PAGE_OFFSET + 0x10000000)
 +
-+	return err;
-+}
++#endif
 +
- /* Note: Because we don't support holes, our allocation has
-  * already happened (allocation writes zeros to the file data)
-  * so we don't have to worry about ordered writes in
-@@ -452,7 +507,7 @@ static sector_t ocfs2_bmap(struct address_space *mapping, sector_t block)
- 	 * accessed concurrently from multiple nodes.
- 	 */
- 	if (!INODE_JOURNAL(inode)) {
--		err = ocfs2_meta_lock(inode, NULL, 0);
-+		err = ocfs2_inode_lock(inode, NULL, 0);
- 		if (err) {
- 			if (err != -ENOENT)
- 				mlog_errno(err);
-@@ -467,7 +522,7 @@ static sector_t ocfs2_bmap(struct address_space *mapping, sector_t block)
- 
- 	if (!INODE_JOURNAL(inode)) {
- 		up_read(&OCFS2_I(inode)->ip_alloc_sem);
--		ocfs2_meta_unlock(inode, 0);
-+		ocfs2_inode_unlock(inode, 0);
- 	}
- 
- 	if (err) {
-@@ -638,34 +693,12 @@ static ssize_t ocfs2_direct_IO(int rw,
- 	if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL)
- 		return 0;
- 
--	if (!ocfs2_sparse_alloc(OCFS2_SB(inode->i_sb))) {
--		/*
--		 * We get PR data locks even for O_DIRECT.  This
--		 * allows concurrent O_DIRECT I/O but doesn't let
--		 * O_DIRECT with extending and buffered zeroing writes
--		 * race.  If they did race then the buffered zeroing
--		 * could be written back after the O_DIRECT I/O.  It's
--		 * one thing to tell people not to mix buffered and
--		 * O_DIRECT writes, but expecting them to understand
--		 * that file extension is also an implicit buffered
--		 * write is too much.  By getting the PR we force
--		 * writeback of the buffered zeroing before
--		 * proceeding.
--		 */
--		ret = ocfs2_data_lock(inode, 0);
--		if (ret < 0) {
--			mlog_errno(ret);
--			goto out;
--		}
--		ocfs2_data_unlock(inode, 0);
--	}
+diff --git a/include/asm-arm/arch-omap/tps65010.h b/include/asm-arm/arch-omap/tps65010.h
+deleted file mode 100644
+index b9aa2b3..0000000
+--- a/include/asm-arm/arch-omap/tps65010.h
++++ /dev/null
+@@ -1,156 +0,0 @@
+-/* linux/include/asm-arm/arch-omap/tps65010.h
+- *
+- * Functions to access TPS65010 power management device.
+- *
+- * Copyright (C) 2004 Dirk Behme <dirk.behme at de.bosch.com>
+- *
+- * This program is free software; you can redistribute it and/or modify it
+- * under the terms of the GNU General Public License as published by the
+- * Free Software Foundation; either version 2 of the License, or (at your
+- * option) any later version.
+- *
+- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+- * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+- *
+- * You should have received a copy of the  GNU General Public License along
+- * with this program; if not, write  to the Free Software Foundation, Inc.,
+- * 675 Mass Ave, Cambridge, MA 02139, USA.
+- */
 -
- 	ret = blockdev_direct_IO_no_locking(rw, iocb, inode,
- 					    inode->i_sb->s_bdev, iov, offset,
- 					    nr_segs, 
- 					    ocfs2_direct_IO_get_blocks,
- 					    ocfs2_dio_end_io);
--out:
-+
- 	mlog_exit(ret);
- 	return ret;
- }
-@@ -1754,7 +1787,7 @@ static int ocfs2_write_begin(struct file *file, struct address_space *mapping,
- 	struct buffer_head *di_bh = NULL;
- 	struct inode *inode = mapping->host;
- 
--	ret = ocfs2_meta_lock(inode, &di_bh, 1);
-+	ret = ocfs2_inode_lock(inode, &di_bh, 1);
- 	if (ret) {
- 		mlog_errno(ret);
- 		return ret;
-@@ -1769,30 +1802,22 @@ static int ocfs2_write_begin(struct file *file, struct address_space *mapping,
- 	 */
- 	down_write(&OCFS2_I(inode)->ip_alloc_sem);
- 
--	ret = ocfs2_data_lock(inode, 1);
--	if (ret) {
--		mlog_errno(ret);
--		goto out_fail;
--	}
+-#ifndef __ASM_ARCH_TPS65010_H
+-#define __ASM_ARCH_TPS65010_H
 -
- 	ret = ocfs2_write_begin_nolock(mapping, pos, len, flags, pagep,
- 				       fsdata, di_bh, NULL);
- 	if (ret) {
- 		mlog_errno(ret);
--		goto out_fail_data;
-+		goto out_fail;
- 	}
- 
- 	brelse(di_bh);
- 
- 	return 0;
- 
--out_fail_data:
--	ocfs2_data_unlock(inode, 1);
- out_fail:
- 	up_write(&OCFS2_I(inode)->ip_alloc_sem);
- 
- 	brelse(di_bh);
--	ocfs2_meta_unlock(inode, 1);
-+	ocfs2_inode_unlock(inode, 1);
- 
- 	return ret;
- }
-@@ -1908,15 +1933,15 @@ static int ocfs2_write_end(struct file *file, struct address_space *mapping,
- 
- 	ret = ocfs2_write_end_nolock(mapping, pos, len, copied, page, fsdata);
- 
--	ocfs2_data_unlock(inode, 1);
- 	up_write(&OCFS2_I(inode)->ip_alloc_sem);
--	ocfs2_meta_unlock(inode, 1);
-+	ocfs2_inode_unlock(inode, 1);
- 
- 	return ret;
- }
- 
- const struct address_space_operations ocfs2_aops = {
- 	.readpage	= ocfs2_readpage,
-+	.readpages	= ocfs2_readpages,
- 	.writepage	= ocfs2_writepage,
- 	.write_begin	= ocfs2_write_begin,
- 	.write_end	= ocfs2_write_end,
-diff --git a/fs/ocfs2/buffer_head_io.c b/fs/ocfs2/buffer_head_io.c
-index c903741..f136639 100644
---- a/fs/ocfs2/buffer_head_io.c
-+++ b/fs/ocfs2/buffer_head_io.c
-@@ -79,7 +79,7 @@ int ocfs2_write_block(struct ocfs2_super *osb, struct buffer_head *bh,
- 		 * information for this bh as it's not marked locally
- 		 * uptodate. */
- 		ret = -EIO;
--		brelse(bh);
-+		put_bh(bh);
- 	}
- 
- 	mutex_unlock(&OCFS2_I(inode)->ip_io_mutex);
-@@ -256,7 +256,7 @@ int ocfs2_read_blocks(struct ocfs2_super *osb, u64 block, int nr,
- 				 * for this bh as it's not marked locally
- 				 * uptodate. */
- 				status = -EIO;
--				brelse(bh);
-+				put_bh(bh);
- 				bhs[i] = NULL;
- 				continue;
- 			}
-@@ -280,3 +280,64 @@ bail:
- 	mlog_exit(status);
- 	return status;
- }
+-/*
+- * ----------------------------------------------------------------------------
+- * Registers, all 8 bits
+- * ----------------------------------------------------------------------------
+- */
+-
+-#define	TPS_CHGSTATUS		0x01
+-#	define	TPS_CHG_USB		(1 << 7)
+-#	define	TPS_CHG_AC		(1 << 6)
+-#	define	TPS_CHG_THERM		(1 << 5)
+-#	define	TPS_CHG_TERM		(1 << 4)
+-#	define	TPS_CHG_TAPER_TMO	(1 << 3)
+-#	define	TPS_CHG_CHG_TMO		(1 << 2)
+-#	define	TPS_CHG_PRECHG_TMO	(1 << 1)
+-#	define	TPS_CHG_TEMP_ERR	(1 << 0)
+-#define	TPS_REGSTATUS		0x02
+-#	define	TPS_REG_ONOFF		(1 << 7)
+-#	define	TPS_REG_COVER		(1 << 6)
+-#	define	TPS_REG_UVLO		(1 << 5)
+-#	define	TPS_REG_NO_CHG		(1 << 4)	/* tps65013 */
+-#	define	TPS_REG_PG_LD02		(1 << 3)
+-#	define	TPS_REG_PG_LD01		(1 << 2)
+-#	define	TPS_REG_PG_MAIN		(1 << 1)
+-#	define	TPS_REG_PG_CORE		(1 << 0)
+-#define	TPS_MASK1		0x03
+-#define	TPS_MASK2		0x04
+-#define	TPS_ACKINT1		0x05
+-#define	TPS_ACKINT2		0x06
+-#define	TPS_CHGCONFIG		0x07
+-#	define	TPS_CHARGE_POR		(1 << 7)	/* 65010/65012 */
+-#	define	TPS65013_AUA		(1 << 7)	/* 65011/65013 */
+-#	define	TPS_CHARGE_RESET	(1 << 6)
+-#	define	TPS_CHARGE_FAST		(1 << 5)
+-#	define	TPS_CHARGE_CURRENT	(3 << 3)
+-#	define	TPS_VBUS_500MA		(1 << 2)
+-#	define	TPS_VBUS_CHARGING	(1 << 1)
+-#	define	TPS_CHARGE_ENABLE	(1 << 0)
+-#define	TPS_LED1_ON		0x08
+-#define	TPS_LED1_PER		0x09
+-#define	TPS_LED2_ON		0x0a
+-#define	TPS_LED2_PER		0x0b
+-#define	TPS_VDCDC1		0x0c
+-#	define	TPS_ENABLE_LP		(1 << 3)
+-#define	TPS_VDCDC2		0x0d
+-#define	TPS_VREGS1		0x0e
+-#	define	TPS_LDO2_ENABLE	(1 << 7)
+-#	define	TPS_LDO2_OFF	(1 << 6)
+-#	define	TPS_VLDO2_3_0V	(3 << 4)
+-#	define	TPS_VLDO2_2_75V	(2 << 4)
+-#	define	TPS_VLDO2_2_5V	(1 << 4)
+-#	define	TPS_VLDO2_1_8V	(0 << 4)
+-#	define	TPS_LDO1_ENABLE	(1 << 3)
+-#	define	TPS_LDO1_OFF	(1 << 2)
+-#	define	TPS_VLDO1_3_0V	(3 << 0)
+-#	define	TPS_VLDO1_2_75V	(2 << 0)
+-#	define	TPS_VLDO1_2_5V	(1 << 0)
+-#	define	TPS_VLDO1_ADJ	(0 << 0)
+-#define	TPS_MASK3		0x0f
+-#define	TPS_DEFGPIO		0x10
+-
+-/*
+- * ----------------------------------------------------------------------------
+- * Macros used by exported functions
+- * ----------------------------------------------------------------------------
+- */
+-
+-#define LED1  1
+-#define LED2  2
+-#define OFF   0
+-#define ON    1
+-#define BLINK 2
+-#define GPIO1 1
+-#define GPIO2 2
+-#define GPIO3 3
+-#define GPIO4 4
+-#define LOW   0
+-#define HIGH  1
+-
+-/*
+- * ----------------------------------------------------------------------------
+- * Exported functions
+- * ----------------------------------------------------------------------------
+- */
+-
+-/* Draw from VBUS:
+- *   0 mA -- DON'T DRAW (might supply power instead)
+- * 100 mA -- usb unit load (slowest charge rate)
+- * 500 mA -- usb high power (fast battery charge)
+- */
+-extern int tps65010_set_vbus_draw(unsigned mA);
+-
+-/* tps65010_set_gpio_out_value parameter:
+- * gpio:  GPIO1, GPIO2, GPIO3 or GPIO4
+- * value: LOW or HIGH
+- */
+-extern int tps65010_set_gpio_out_value(unsigned gpio, unsigned value);
+-
+-/* tps65010_set_led parameter:
+- * led:  LED1 or LED2
+- * mode: ON, OFF or BLINK
+- */
+-extern int tps65010_set_led(unsigned led, unsigned mode);
+-
+-/* tps65010_set_vib parameter:
+- * value: ON or OFF
+- */
+-extern int tps65010_set_vib(unsigned value);
+-
+-/* tps65010_set_low_pwr parameter:
+- * mode: ON or OFF
+- */
+-extern int tps65010_set_low_pwr(unsigned mode);
+-
+-/* tps65010_config_vregs1 parameter:
+- * value to be written to VREGS1 register
+- * Note: The complete register is written, set all bits you need
+- */
+-extern int tps65010_config_vregs1(unsigned value);
+-
+-/* tps65013_set_low_pwr parameter:
+- * mode: ON or OFF
+- */
+-extern int tps65013_set_low_pwr(unsigned mode);
+-
+-#endif /*  __ASM_ARCH_TPS65010_H */
+-
+diff --git a/include/asm-arm/arch-orion/debug-macro.S b/include/asm-arm/arch-orion/debug-macro.S
+new file mode 100644
+index 0000000..e2a8064
+--- /dev/null
++++ b/include/asm-arm/arch-orion/debug-macro.S
+@@ -0,0 +1,17 @@
++/*
++ * linux/include/asm-arm/arch-orion/debug-macro.S
++ *
++ * Debugging macro include header
++ *
++ * 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.
++*/
 +
-+/* Check whether the blkno is the super block or one of the backups. */
-+static void ocfs2_check_super_or_backup(struct super_block *sb,
-+					sector_t blkno)
++	.macro  addruart,rx
++	mov   \rx, #0xf1000000
++	orr   \rx, \rx, #0x00012000
++	.endm
++
++#define UART_SHIFT	2
++#include <asm/hardware/debug-8250.S>
+diff --git a/include/asm-arm/arch-orion/dma.h b/include/asm-arm/arch-orion/dma.h
+new file mode 100644
+index 0000000..40a8c17
+--- /dev/null
++++ b/include/asm-arm/arch-orion/dma.h
+@@ -0,0 +1 @@
++/* empty */
+diff --git a/include/asm-arm/arch-orion/entry-macro.S b/include/asm-arm/arch-orion/entry-macro.S
+new file mode 100644
+index 0000000..b76075a
+--- /dev/null
++++ b/include/asm-arm/arch-orion/entry-macro.S
+@@ -0,0 +1,31 @@
++/*
++ * include/asm-arm/arch-orion/entry-macro.S
++ *
++ * Low-level IRQ helper macros for Orion platforms
++ *
++ * This file is licensed under  the terms of the GNU General Public
++ * License version 2. This program is licensed "as is" without any
++ * warranty of any kind, whether express or implied.
++ */
++
++#include <asm/arch/orion.h>
++
++	.macro  disable_fiq
++	.endm
++
++	.macro  arch_ret_to_user, tmp1, tmp2
++	.endm
++
++	.macro  get_irqnr_preamble, base, tmp
++	ldr	\base, =MAIN_IRQ_CAUSE
++	.endm
++
++	.macro  get_irqnr_and_base, irqnr, irqstat, base, tmp
++	ldr	\irqstat, [\base, #0]		@ main cause
++	ldr	\tmp, [\base, #(MAIN_IRQ_MASK - MAIN_IRQ_CAUSE)] @ main mask
++	mov	\irqnr, #0			@ default irqnr
++	@ find cause bits that are unmasked
++	ands	\irqstat, \irqstat, \tmp	@ clear Z flag if any
++	clzne	\irqnr,	\irqstat		@ calc irqnr
++	rsbne	\irqnr, \irqnr, #31
++	.endm
+diff --git a/include/asm-arm/arch-orion/gpio.h b/include/asm-arm/arch-orion/gpio.h
+new file mode 100644
+index 0000000..d66284f
+--- /dev/null
++++ b/include/asm-arm/arch-orion/gpio.h
+@@ -0,0 +1,28 @@
++/*
++ * include/asm-arm/arch-orion/gpio.h
++ *
++ * 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.
++ */
++
++extern int gpio_request(unsigned pin, const char *label);
++extern void gpio_free(unsigned pin);
++extern int gpio_direction_input(unsigned pin);
++extern int gpio_direction_output(unsigned pin, int value);
++extern int gpio_get_value(unsigned pin);
++extern void gpio_set_value(unsigned pin, int value);
++extern void orion_gpio_set_blink(unsigned pin, int blink);
++extern void gpio_display(void);		/* debug */
++
++static inline int gpio_to_irq(int pin)
 +{
-+	int i;
-+	u64 backup_blkno;
++	return pin + IRQ_ORION_GPIO_START;
++}
 +
-+	if (blkno == OCFS2_SUPER_BLOCK_BLKNO)
-+		return;
++static inline int irq_to_gpio(int irq)
++{
++	return irq - IRQ_ORION_GPIO_START;
++}
 +
-+	for (i = 0; i < OCFS2_MAX_BACKUP_SUPERBLOCKS; i++) {
-+		backup_blkno = ocfs2_backup_super_blkno(sb, i);
-+		if (backup_blkno == blkno)
-+			return;
-+	}
++#include <asm-generic/gpio.h>		/* cansleep wrappers */
+diff --git a/include/asm-arm/arch-orion/hardware.h b/include/asm-arm/arch-orion/hardware.h
+new file mode 100644
+index 0000000..8a12d21
+--- /dev/null
++++ b/include/asm-arm/arch-orion/hardware.h
+@@ -0,0 +1,24 @@
++/*
++ * include/asm-arm/arch-orion/hardware.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.
++ *
++ */
 +
-+	BUG();
++#ifndef __ASM_ARCH_HARDWARE_H__
++#define __ASM_ARCH_HARDWARE_H__
++
++#include "orion.h"
++
++#define PCI_MEMORY_VADDR        ORION_PCI_SYS_MEM_BASE
++#define PCI_IO_VADDR            ORION_PCI_SYS_IO_BASE
++
++#define pcibios_assign_all_busses()  1
++
++#define PCIBIOS_MIN_IO  0x1000
++#define PCIBIOS_MIN_MEM 0x01000000
++#define PCIMEM_BASE     PCI_MEMORY_VADDR /* mem base for VGA */
++
++#endif  /* _ASM_ARCH_HARDWARE_H */
+diff --git a/include/asm-arm/arch-orion/io.h b/include/asm-arm/arch-orion/io.h
+new file mode 100644
+index 0000000..e0b8c39
+--- /dev/null
++++ b/include/asm-arm/arch-orion/io.h
+@@ -0,0 +1,27 @@
++/*
++ * include/asm-arm/arch-orion/io.h
++ *
++ * Tzachi Perelstein <tzachi at marvell.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.
++ */
++
++#ifndef __ASM_ARM_ARCH_IO_H
++#define __ASM_ARM_ARCH_IO_H
++
++#include "orion.h"
++
++#define IO_SPACE_LIMIT		0xffffffff
++#define IO_SPACE_REMAP		ORION_PCI_SYS_IO_BASE
++
++static inline void __iomem *__io(unsigned long addr)
++{
++	return (void __iomem *)addr;
 +}
 +
++#define __io(a)			__io(a)
++#define __mem_pci(a)		(a)
++
++#endif
+diff --git a/include/asm-arm/arch-orion/irqs.h b/include/asm-arm/arch-orion/irqs.h
+new file mode 100644
+index 0000000..eea65ca
+--- /dev/null
++++ b/include/asm-arm/arch-orion/irqs.h
+@@ -0,0 +1,61 @@
 +/*
-+ * Write super block and backups doesn't need to collaborate with journal,
-+ * so we don't need to lock ip_io_mutex and inode doesn't need to bea passed
-+ * into this function.
++ * include/asm-arm/arch-orion/irqs.h
++ *
++ * IRQ definitions for Orion SoC
++ *
++ *  Maintainer: Tzachi Perelstein <tzachi at marvell.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.
++ */
++
++#ifndef __ASM_ARCH_IRQS_H__
++#define __ASM_ARCH_IRQS_H__
++
++#include "orion.h"	/* need GPIO_MAX */
++
++/*
++ * Orion Main Interrupt Controller
++ */
++#define IRQ_ORION_BRIDGE	0
++#define IRQ_ORION_DOORBELL_H2C	1
++#define IRQ_ORION_DOORBELL_C2H	2
++#define IRQ_ORION_UART0		3
++#define IRQ_ORION_UART1		4
++#define IRQ_ORION_I2C		5
++#define IRQ_ORION_GPIO_0_7	6
++#define IRQ_ORION_GPIO_8_15	7
++#define IRQ_ORION_GPIO_16_23	8
++#define IRQ_ORION_GPIO_24_31	9
++#define IRQ_ORION_PCIE0_ERR	10
++#define IRQ_ORION_PCIE0_INT	11
++#define IRQ_ORION_USB1_CTRL	12
++#define IRQ_ORION_DEV_BUS_ERR	14
++#define IRQ_ORION_PCI_ERR	15
++#define IRQ_ORION_USB_BR_ERR	16
++#define IRQ_ORION_USB0_CTRL	17
++#define IRQ_ORION_ETH_RX	18
++#define IRQ_ORION_ETH_TX	19
++#define IRQ_ORION_ETH_MISC	20
++#define IRQ_ORION_ETH_SUM	21
++#define IRQ_ORION_ETH_ERR	22
++#define IRQ_ORION_IDMA_ERR	23
++#define IRQ_ORION_IDMA_0	24
++#define IRQ_ORION_IDMA_1	25
++#define IRQ_ORION_IDMA_2	26
++#define IRQ_ORION_IDMA_3	27
++#define IRQ_ORION_CESA		28
++#define IRQ_ORION_SATA		29
++#define IRQ_ORION_XOR0		30
++#define IRQ_ORION_XOR1		31
++
++/*
++ * Orion General Purpose Pins
 + */
-+int ocfs2_write_super_or_backup(struct ocfs2_super *osb,
-+				struct buffer_head *bh)
++#define IRQ_ORION_GPIO_START	32
++#define NR_GPIO_IRQS		GPIO_MAX
++
++#define NR_IRQS			(IRQ_ORION_GPIO_START + NR_GPIO_IRQS)
++
++#endif /* __ASM_ARCH_IRQS_H__ */
+diff --git a/include/asm-arm/arch-orion/memory.h b/include/asm-arm/arch-orion/memory.h
+new file mode 100644
+index 0000000..d954dba
+--- /dev/null
++++ b/include/asm-arm/arch-orion/memory.h
+@@ -0,0 +1,15 @@
++/*
++ * include/asm-arm/arch-orion/memory.h
++ *
++ * Marvell Orion memory definitions
++ */
++
++#ifndef __ASM_ARCH_MMU_H
++#define __ASM_ARCH_MMU_H
++
++#define PHYS_OFFSET	UL(0x00000000)
++
++#define __virt_to_bus(x)	__virt_to_phys(x)
++#define __bus_to_virt(x)	__phys_to_virt(x)
++
++#endif
+diff --git a/include/asm-arm/arch-orion/orion.h b/include/asm-arm/arch-orion/orion.h
+new file mode 100644
+index 0000000..f787f75
+--- /dev/null
++++ b/include/asm-arm/arch-orion/orion.h
+@@ -0,0 +1,143 @@
++/*
++ * include/asm-arm/arch-orion/orion.h
++ *
++ * Generic definitions of Orion SoC flavors:
++ *  Orion-1, Orion-NAS, Orion-VoIP, and Orion-2.
++ *
++ * Maintainer: Tzachi Perelstein <tzachi at marvell.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.
++ */
++
++#ifndef __ASM_ARCH_ORION_H__
++#define __ASM_ARCH_ORION_H__
++
++/*******************************************************************************
++ * Orion Address Map
++ * Use the same mapping (1:1 virtual:physical) of internal registers and
++ * PCI system (PCI+PCIE) for all machines.
++ * Each machine defines the rest of its mapping (e.g. device bus flashes)
++ ******************************************************************************/
++#define ORION_REGS_BASE		0xf1000000
++#define ORION_REGS_SIZE		SZ_1M
++
++#define ORION_PCI_SYS_MEM_BASE	0xe0000000
++#define ORION_PCIE_MEM_BASE	ORION_PCI_SYS_MEM_BASE
++#define ORION_PCIE_MEM_SIZE	SZ_128M
++#define ORION_PCI_MEM_BASE	(ORION_PCIE_MEM_BASE + ORION_PCIE_MEM_SIZE)
++#define ORION_PCI_MEM_SIZE	SZ_128M
++
++#define ORION_PCI_SYS_IO_BASE	0xf2000000
++#define ORION_PCIE_IO_BASE	ORION_PCI_SYS_IO_BASE
++#define ORION_PCIE_IO_SIZE	SZ_1M
++#define ORION_PCIE_IO_REMAP	(ORION_PCIE_IO_BASE - ORION_PCI_SYS_IO_BASE)
++#define ORION_PCI_IO_BASE	(ORION_PCIE_IO_BASE + ORION_PCIE_IO_SIZE)
++#define ORION_PCI_IO_SIZE	SZ_1M
++#define ORION_PCI_IO_REMAP	(ORION_PCI_IO_BASE - ORION_PCI_SYS_IO_BASE)
++/* Relevant only for Orion-NAS */
++#define ORION_PCIE_WA_BASE	0xf0000000
++#define ORION_PCIE_WA_SIZE	SZ_16M
++
++/*******************************************************************************
++ * Supported Devices & Revisions
++ ******************************************************************************/
++/* Orion-1 (88F5181) */
++#define MV88F5181_DEV_ID	0x5181
++#define MV88F5181_REV_B1	3
++/* Orion-NAS (88F5182) */
++#define MV88F5182_DEV_ID	0x5182
++#define MV88F5182_REV_A2	2
++/* Orion-2 (88F5281) */
++#define MV88F5281_DEV_ID	0x5281
++#define MV88F5281_REV_D1	5
++#define MV88F5281_REV_D2	6
++
++/*******************************************************************************
++ * Orion Registers Map
++ ******************************************************************************/
++#define ORION_DDR_REG_BASE	(ORION_REGS_BASE | 0x00000)
++#define ORION_DEV_BUS_REG_BASE	(ORION_REGS_BASE | 0x10000)
++#define ORION_BRIDGE_REG_BASE	(ORION_REGS_BASE | 0x20000)
++#define ORION_PCI_REG_BASE	(ORION_REGS_BASE | 0x30000)
++#define ORION_PCIE_REG_BASE	(ORION_REGS_BASE | 0x40000)
++#define ORION_USB0_REG_BASE	(ORION_REGS_BASE | 0x50000)
++#define ORION_ETH_REG_BASE	(ORION_REGS_BASE | 0x70000)
++#define ORION_SATA_REG_BASE	(ORION_REGS_BASE | 0x80000)
++#define ORION_USB1_REG_BASE	(ORION_REGS_BASE | 0xa0000)
++
++#define ORION_DDR_REG(x)	(ORION_DDR_REG_BASE | (x))
++#define ORION_DEV_BUS_REG(x)	(ORION_DEV_BUS_REG_BASE | (x))
++#define ORION_BRIDGE_REG(x)	(ORION_BRIDGE_REG_BASE | (x))
++#define ORION_PCI_REG(x)	(ORION_PCI_REG_BASE | (x))
++#define ORION_PCIE_REG(x)	(ORION_PCIE_REG_BASE | (x))
++#define ORION_USB0_REG(x)	(ORION_USB0_REG_BASE | (x))
++#define ORION_USB1_REG(x)	(ORION_USB1_REG_BASE | (x))
++#define ORION_ETH_REG(x)	(ORION_ETH_REG_BASE | (x))
++#define ORION_SATA_REG(x)	(ORION_SATA_REG_BASE | (x))
++
++/*******************************************************************************
++ * Device Bus Registers
++ ******************************************************************************/
++#define MPP_0_7_CTRL		ORION_DEV_BUS_REG(0x000)
++#define MPP_8_15_CTRL		ORION_DEV_BUS_REG(0x004)
++#define MPP_16_19_CTRL		ORION_DEV_BUS_REG(0x050)
++#define MPP_DEV_CTRL		ORION_DEV_BUS_REG(0x008)
++#define MPP_RESET_SAMPLE	ORION_DEV_BUS_REG(0x010)
++#define GPIO_OUT		ORION_DEV_BUS_REG(0x100)
++#define GPIO_IO_CONF		ORION_DEV_BUS_REG(0x104)
++#define GPIO_BLINK_EN		ORION_DEV_BUS_REG(0x108)
++#define GPIO_IN_POL		ORION_DEV_BUS_REG(0x10c)
++#define GPIO_DATA_IN		ORION_DEV_BUS_REG(0x110)
++#define GPIO_EDGE_CAUSE		ORION_DEV_BUS_REG(0x114)
++#define GPIO_EDGE_MASK		ORION_DEV_BUS_REG(0x118)
++#define GPIO_LEVEL_MASK		ORION_DEV_BUS_REG(0x11c)
++#define DEV_BANK_0_PARAM	ORION_DEV_BUS_REG(0x45c)
++#define DEV_BANK_1_PARAM	ORION_DEV_BUS_REG(0x460)
++#define DEV_BANK_2_PARAM	ORION_DEV_BUS_REG(0x464)
++#define DEV_BANK_BOOT_PARAM	ORION_DEV_BUS_REG(0x46c)
++#define DEV_BUS_CTRL		ORION_DEV_BUS_REG(0x4c0)
++#define DEV_BUS_INT_CAUSE	ORION_DEV_BUS_REG(0x4d0)
++#define DEV_BUS_INT_MASK	ORION_DEV_BUS_REG(0x4d4)
++#define I2C_BASE		ORION_DEV_BUS_REG(0x1000)
++#define UART0_BASE		ORION_DEV_BUS_REG(0x2000)
++#define UART1_BASE		ORION_DEV_BUS_REG(0x2100)
++#define GPIO_MAX		32
++
++/***************************************************************************
++ * Orion CPU Bridge Registers
++ **************************************************************************/
++#define CPU_CONF		ORION_BRIDGE_REG(0x100)
++#define CPU_CTRL		ORION_BRIDGE_REG(0x104)
++#define CPU_RESET_MASK		ORION_BRIDGE_REG(0x108)
++#define CPU_SOFT_RESET		ORION_BRIDGE_REG(0x10c)
++#define POWER_MNG_CTRL_REG	ORION_BRIDGE_REG(0x11C)
++#define BRIDGE_CAUSE		ORION_BRIDGE_REG(0x110)
++#define BRIDGE_MASK		ORION_BRIDGE_REG(0x114)
++#define MAIN_IRQ_CAUSE		ORION_BRIDGE_REG(0x200)
++#define MAIN_IRQ_MASK		ORION_BRIDGE_REG(0x204)
++#define TIMER_CTRL		ORION_BRIDGE_REG(0x300)
++#define TIMER_VAL(x)		ORION_BRIDGE_REG(0x314 + ((x) * 8))
++#define TIMER_VAL_RELOAD(x)	ORION_BRIDGE_REG(0x310 + ((x) * 8))
++
++#ifndef __ASSEMBLY__
++
++/*******************************************************************************
++ * Helpers to access Orion registers
++ ******************************************************************************/
++#include <asm/types.h>
++#include <asm/io.h>
++
++#define orion_read(r)		__raw_readl(r)
++#define orion_write(r, val)	__raw_writel(val, r)
++
++/*
++ * These are not preempt safe. Locks, if needed, must be taken care by caller.
++ */
++#define orion_setbits(r, mask)	orion_write((r), orion_read(r) | (mask))
++#define orion_clrbits(r, mask)	orion_write((r), orion_read(r) & ~(mask))
++
++#endif /* __ASSEMBLY__ */
++
++#endif /* __ASM_ARCH_ORION_H__ */
+diff --git a/include/asm-arm/arch-orion/platform.h b/include/asm-arm/arch-orion/platform.h
+new file mode 100644
+index 0000000..143c38e
+--- /dev/null
++++ b/include/asm-arm/arch-orion/platform.h
+@@ -0,0 +1,25 @@
++/*
++ * asm-arm/arch-orion/platform.h
++ *
++ * Tzachi Perelstein <tzachi at marvell.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.
++ */
++
++#ifndef __ASM_ARCH_PLATFORM_H__
++#define __ASM_ARCH_PLATFORM_H__
++
++/*
++ * Device bus NAND private data
++ */
++struct orion_nand_data {
++	struct mtd_partition *parts;
++	u32 nr_parts;
++	u8 ale;		/* address line number connected to ALE */
++	u8 cle;		/* address line number connected to CLE */
++	u8 width;	/* buswidth */
++};
++
++#endif
+diff --git a/include/asm-arm/arch-orion/system.h b/include/asm-arm/arch-orion/system.h
+new file mode 100644
+index 0000000..17704c6
+--- /dev/null
++++ b/include/asm-arm/arch-orion/system.h
+@@ -0,0 +1,31 @@
++/*
++ * include/asm-arm/arch-orion/system.h
++ *
++ * Tzachi Perelstein <tzachi at marvell.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.
++ */
++
++#ifndef __ASM_ARCH_SYSTEM_H
++#define __ASM_ARCH_SYSTEM_H
++
++#include <asm/arch/hardware.h>
++#include <asm/arch/orion.h>
++
++static inline void arch_idle(void)
 +{
-+	int ret = 0;
++	cpu_do_idle();
++}
 +
-+	mlog_entry_void();
++static inline void arch_reset(char mode)
++{
++	/*
++	 * Enable and issue soft reset
++	 */
++	orion_setbits(CPU_RESET_MASK, (1 << 2));
++	orion_setbits(CPU_SOFT_RESET, 1);
++}
 +
-+	BUG_ON(buffer_jbd(bh));
-+	ocfs2_check_super_or_backup(osb->sb, bh->b_blocknr);
++#endif
+diff --git a/include/asm-arm/arch-orion/timex.h b/include/asm-arm/arch-orion/timex.h
+new file mode 100644
+index 0000000..26c2c91
+--- /dev/null
++++ b/include/asm-arm/arch-orion/timex.h
+@@ -0,0 +1,12 @@
++/*
++ * include/asm-arm/arch-orion/timex.h
++ *
++ * Tzachi Perelstein <tzachi at marvell.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.
++ */
 +
-+	if (ocfs2_is_hard_readonly(osb) || ocfs2_is_soft_readonly(osb)) {
-+		ret = -EROFS;
-+		goto out;
-+	}
++#define ORION_TCLK		166666667
++#define CLOCK_TICK_RATE		ORION_TCLK
+diff --git a/include/asm-arm/arch-orion/uncompress.h b/include/asm-arm/arch-orion/uncompress.h
+new file mode 100644
+index 0000000..a1a222f
+--- /dev/null
++++ b/include/asm-arm/arch-orion/uncompress.h
+@@ -0,0 +1,44 @@
++/*
++ * include/asm-arm/arch-orion/uncompress.h
++ *
++ * Tzachi Perelstein <tzachi at marvell.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.
++ */
 +
-+	lock_buffer(bh);
-+	set_buffer_uptodate(bh);
++#include <asm/arch/orion.h>
 +
-+	/* remove from dirty list before I/O. */
-+	clear_buffer_dirty(bh);
++#define MV_UART_LSR 	((volatile unsigned char *)(UART0_BASE + 0x14))
++#define MV_UART_THR	((volatile unsigned char *)(UART0_BASE + 0x0))
 +
-+	get_bh(bh); /* for end_buffer_write_sync() */
-+	bh->b_end_io = end_buffer_write_sync;
-+	submit_bh(WRITE, bh);
++#define LSR_THRE	0x20
 +
-+	wait_on_buffer(bh);
++static void putc(const char c)
++{
++	int j = 0x1000;
++	while (--j && !(*MV_UART_LSR & LSR_THRE))
++		barrier();
++	*MV_UART_THR = c;
++}
 +
-+	if (!buffer_uptodate(bh)) {
-+		ret = -EIO;
-+		put_bh(bh);
-+	}
++static void flush(void)
++{
++}
 +
-+out:
-+	mlog_exit(ret);
-+	return ret;
++static void orion_early_putstr(const char *ptr)
++{
++	char c;
++	while ((c = *ptr++) != '\0') {
++		if (c == '\n')
++			putc('\r');
++		putc(c);
++	}
 +}
-diff --git a/fs/ocfs2/buffer_head_io.h b/fs/ocfs2/buffer_head_io.h
-index 6cc2093..c2e7861 100644
---- a/fs/ocfs2/buffer_head_io.h
-+++ b/fs/ocfs2/buffer_head_io.h
-@@ -47,6 +47,8 @@ int ocfs2_read_blocks(struct ocfs2_super          *osb,
- 		      int                  flags,
- 		      struct inode        *inode);
++
++/*
++ * nothing to do
++ */
++#define arch_decomp_setup()
++#define arch_decomp_wdog()
+diff --git a/include/asm-arm/arch-orion/vmalloc.h b/include/asm-arm/arch-orion/vmalloc.h
+new file mode 100644
+index 0000000..23e2a10
+--- /dev/null
++++ b/include/asm-arm/arch-orion/vmalloc.h
+@@ -0,0 +1,5 @@
++/*
++ * include/asm-arm/arch-orion/vmalloc.h
++ */
++
++#define VMALLOC_END       0xf0000000
+diff --git a/include/asm-arm/arch-pxa/colibri.h b/include/asm-arm/arch-pxa/colibri.h
+new file mode 100644
+index 0000000..2ae373f
+--- /dev/null
++++ b/include/asm-arm/arch-pxa/colibri.h
+@@ -0,0 +1,19 @@
++#ifndef _COLIBRI_H_
++#define _COLIBRI_H_
++
++/* physical memory regions */
++#define COLIBRI_FLASH_PHYS	(PXA_CS0_PHYS)  /* Flash region */
++#define COLIBRI_ETH_PHYS	(PXA_CS2_PHYS)  /* Ethernet DM9000 region */
++#define COLIBRI_SDRAM_BASE	0xa0000000      /* SDRAM region */
++
++/* virtual memory regions */
++#define COLIBRI_DISK_VIRT	0xF0000000	/* Disk On Chip region */
++
++/* size of flash */
++#define COLIBRI_FLASH_SIZE	0x02000000	/* Flash size 32 MB */
++
++/* Ethernet Controller Davicom DM9000 */
++#define GPIO_DM9000		114
++#define COLIBRI_ETH_IRQ	IRQ_GPIO(GPIO_DM9000)
++
++#endif /* _COLIBRI_H_ */
+diff --git a/include/asm-arm/arch-pxa/corgi.h b/include/asm-arm/arch-pxa/corgi.h
+index e554caa..bf85650 100644
+--- a/include/asm-arm/arch-pxa/corgi.h
++++ b/include/asm-arm/arch-pxa/corgi.h
+@@ -104,7 +104,6 @@
+  */
+ extern struct platform_device corgiscoop_device;
+ extern struct platform_device corgissp_device;
+-extern struct platform_device corgifb_device;
  
-+int ocfs2_write_super_or_backup(struct ocfs2_super *osb,
-+				struct buffer_head *bh);
+ #endif /* __ASM_ARCH_CORGI_H  */
  
- #define OCFS2_BH_CACHED            1
- #define OCFS2_BH_READAHEAD         8
-diff --git a/fs/ocfs2/cluster/heartbeat.h b/fs/ocfs2/cluster/heartbeat.h
-index 35397dd..e511339 100644
---- a/fs/ocfs2/cluster/heartbeat.h
-+++ b/fs/ocfs2/cluster/heartbeat.h
-@@ -35,7 +35,7 @@
- #define O2HB_LIVE_THRESHOLD	   2
- /* number of equal samples to be seen as dead */
- extern unsigned int o2hb_dead_threshold;
--#define O2HB_DEFAULT_DEAD_THRESHOLD	   7
-+#define O2HB_DEFAULT_DEAD_THRESHOLD	   31
- /* Otherwise MAX_WRITE_TIMEOUT will be zero... */
- #define O2HB_MIN_DEAD_THRESHOLD	  2
- #define O2HB_MAX_WRITE_TIMEOUT_MS (O2HB_REGION_TIMEOUT_MS * (o2hb_dead_threshold - 1))
-diff --git a/fs/ocfs2/cluster/masklog.c b/fs/ocfs2/cluster/masklog.c
-index a4882c8..23c732f 100644
---- a/fs/ocfs2/cluster/masklog.c
-+++ b/fs/ocfs2/cluster/masklog.c
-@@ -146,7 +146,7 @@ static struct kset mlog_kset = {
- 	.kobj   = {.ktype = &mlog_ktype},
+diff --git a/include/asm-arm/arch-pxa/i2c.h b/include/asm-arm/arch-pxa/i2c.h
+index e404b23..80596b0 100644
+--- a/include/asm-arm/arch-pxa/i2c.h
++++ b/include/asm-arm/arch-pxa/i2c.h
+@@ -65,7 +65,13 @@ struct i2c_pxa_platform_data {
+ 	unsigned int		slave_addr;
+ 	struct i2c_slave_client	*slave;
+ 	unsigned int		class;
++	int			use_pio;
  };
  
--int mlog_sys_init(struct kset *o2cb_subsys)
-+int mlog_sys_init(struct kset *o2cb_kset)
- {
- 	int i = 0;
+ 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);
++#endif
++
+ #endif
+diff --git a/include/asm-arm/arch-pxa/irqs.h b/include/asm-arm/arch-pxa/irqs.h
+index b76ee6d..c562b97 100644
+--- a/include/asm-arm/arch-pxa/irqs.h
++++ b/include/asm-arm/arch-pxa/irqs.h
+@@ -180,7 +180,8 @@
+ #define NR_IRQS			(IRQ_LOCOMO_SPI_TEND + 1)
+ #elif defined(CONFIG_ARCH_LUBBOCK) || \
+       defined(CONFIG_MACH_LOGICPD_PXA270) || \
+-      defined(CONFIG_MACH_MAINSTONE)
++      defined(CONFIG_MACH_MAINSTONE) || \
++      defined(CONFIG_MACH_PCM027)
+ #define NR_IRQS			(IRQ_BOARD_END)
+ #else
+ #define NR_IRQS			(IRQ_BOARD_START)
+@@ -227,6 +228,13 @@
+ #define IRQ_LOCOMO_LT_BASE	(IRQ_BOARD_START + 2)
+ #define IRQ_LOCOMO_SPI_BASE	(IRQ_BOARD_START + 3)
+ 
++/* phyCORE-PXA270 (PCM027) Interrupts */
++#define PCM027_IRQ(x)          (IRQ_BOARD_START + (x))
++#define PCM027_BTDET_IRQ       PCM027_IRQ(0)
++#define PCM027_FF_RI_IRQ       PCM027_IRQ(1)
++#define PCM027_MMCDET_IRQ      PCM027_IRQ(2)
++#define PCM027_PM_5V_IRQ       PCM027_IRQ(3)
++
+ /* ITE8152 irqs */
+ /* add IT8152 IRQs beyond BOARD_END */
+ #ifdef CONFIG_PCI_HOST_ITE8152
+diff --git a/include/asm-arm/arch-pxa/littleton.h b/include/asm-arm/arch-pxa/littleton.h
+new file mode 100644
+index 0000000..79d209b
+--- /dev/null
++++ b/include/asm-arm/arch-pxa/littleton.h
+@@ -0,0 +1,6 @@
++#ifndef __ASM_ARCH_ZYLONITE_H
++#define __ASM_ARCH_ZYLONITE_H
++
++#define LITTLETON_ETH_PHYS	0x30000000
++
++#endif /* __ASM_ARCH_ZYLONITE_H */
+diff --git a/include/asm-arm/arch-pxa/magician.h b/include/asm-arm/arch-pxa/magician.h
+new file mode 100644
+index 0000000..337f51f
+--- /dev/null
++++ b/include/asm-arm/arch-pxa/magician.h
+@@ -0,0 +1,111 @@
++/*
++ * GPIO and IRQ definitions for HTC Magician PDA phones
++ *
++ * Copyright (c) 2007 Philipp Zabel
++ *
++ * 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 _MAGICIAN_H_
++#define _MAGICIAN_H_
++
++#include <asm/arch/pxa-regs.h>
++
++/*
++ * PXA GPIOs
++ */
++
++#define GPIO0_MAGICIAN_KEY_POWER		0
++#define GPIO9_MAGICIAN_UNKNOWN			9
++#define GPIO10_MAGICIAN_GSM_IRQ			10
++#define GPIO11_MAGICIAN_GSM_OUT1		11
++#define GPIO13_MAGICIAN_CPLD_IRQ		13
++#define GPIO18_MAGICIAN_UNKNOWN			18
++#define GPIO22_MAGICIAN_VIBRA_EN		22
++#define GPIO26_MAGICIAN_GSM_POWER		26
++#define GPIO27_MAGICIAN_USBC_PUEN		27
++#define GPIO30_MAGICIAN_nCHARGE_EN		30
++#define GPIO37_MAGICIAN_KEY_HANGUP		37
++#define GPIO38_MAGICIAN_KEY_CONTACTS		38
++#define GPIO40_MAGICIAN_GSM_OUT2		40
++#define GPIO48_MAGICIAN_UNKNOWN			48
++#define GPIO56_MAGICIAN_UNKNOWN			56
++#define GPIO57_MAGICIAN_CAM_RESET		57
++#define GPIO83_MAGICIAN_nIR_EN			83
++#define GPIO86_MAGICIAN_GSM_RESET		86
++#define GPIO87_MAGICIAN_GSM_SELECT		87
++#define GPIO90_MAGICIAN_KEY_CALENDAR		90
++#define GPIO91_MAGICIAN_KEY_CAMERA		91
++#define GPIO93_MAGICIAN_KEY_UP			93
++#define GPIO94_MAGICIAN_KEY_DOWN		94
++#define GPIO95_MAGICIAN_KEY_LEFT		95
++#define GPIO96_MAGICIAN_KEY_RIGHT		96
++#define GPIO97_MAGICIAN_KEY_ENTER		97
++#define GPIO98_MAGICIAN_KEY_RECORD		98
++#define GPIO99_MAGICIAN_HEADPHONE_IN		99
++#define GPIO100_MAGICIAN_KEY_VOL_UP		100
++#define GPIO101_MAGICIAN_KEY_VOL_DOWN 		101
++#define GPIO102_MAGICIAN_KEY_PHONE		102
++#define GPIO103_MAGICIAN_LED_KP			103
++#define GPIO104_MAGICIAN_LCD_POWER_1 		104
++#define GPIO105_MAGICIAN_LCD_POWER_2		105
++#define GPIO106_MAGICIAN_LCD_POWER_3		106
++#define GPIO107_MAGICIAN_DS1WM_IRQ		107
++#define GPIO108_MAGICIAN_GSM_READY		108
++#define GPIO114_MAGICIAN_UNKNOWN		114
++#define GPIO115_MAGICIAN_nPEN_IRQ		115
++#define GPIO116_MAGICIAN_nCAM_EN		116
++#define GPIO119_MAGICIAN_UNKNOWN		119
++#define GPIO120_MAGICIAN_UNKNOWN		120
++
++/*
++ * PXA GPIO alternate function mode & direction
++ */
++
++#define GPIO0_MAGICIAN_KEY_POWER_MD		(0 | GPIO_IN)
++#define GPIO9_MAGICIAN_UNKNOWN_MD		(9 | GPIO_IN)
++#define GPIO10_MAGICIAN_GSM_IRQ_MD		(10 | GPIO_IN)
++#define GPIO11_MAGICIAN_GSM_OUT1_MD		(11 | GPIO_OUT)
++#define GPIO13_MAGICIAN_CPLD_IRQ_MD		(13 | GPIO_IN)
++#define GPIO18_MAGICIAN_UNKNOWN_MD		(18 | GPIO_OUT)
++#define GPIO22_MAGICIAN_VIBRA_EN_MD		(22 | GPIO_OUT)
++#define GPIO26_MAGICIAN_GSM_POWER_MD		(26 | GPIO_OUT)
++#define GPIO27_MAGICIAN_USBC_PUEN_MD		(27 | GPIO_OUT)
++#define GPIO30_MAGICIAN_nCHARGE_EN_MD		(30 | GPIO_OUT)
++#define GPIO37_MAGICIAN_KEY_HANGUP_MD		(37 | GPIO_OUT)
++#define GPIO38_MAGICIAN_KEY_CONTACTS_MD		(38 | GPIO_OUT)
++#define GPIO40_MAGICIAN_GSM_OUT2_MD		(40 | GPIO_OUT)
++#define GPIO48_MAGICIAN_UNKNOWN_MD		(48 | GPIO_OUT)
++#define GPIO56_MAGICIAN_UNKNOWN_MD		(56 | GPIO_OUT)
++#define GPIO57_MAGICIAN_CAM_RESET_MD		(57 | GPIO_OUT)
++#define GPIO83_MAGICIAN_nIR_EN_MD		(83 | GPIO_OUT)
++#define GPIO86_MAGICIAN_GSM_RESET_MD		(86 | GPIO_OUT)
++#define GPIO87_MAGICIAN_GSM_SELECT_MD		(87 | GPIO_OUT)
++#define GPIO90_MAGICIAN_KEY_CALENDAR_MD		(90 | GPIO_OUT)
++#define GPIO91_MAGICIAN_KEY_CAMERA_MD		(91 | GPIO_OUT)
++#define GPIO93_MAGICIAN_KEY_UP_MD		(93 | GPIO_IN)
++#define GPIO94_MAGICIAN_KEY_DOWN_MD		(94 | GPIO_IN)
++#define GPIO95_MAGICIAN_KEY_LEFT_MD		(95 | GPIO_IN)
++#define GPIO96_MAGICIAN_KEY_RIGHT_MD		(96 | GPIO_IN)
++#define GPIO97_MAGICIAN_KEY_ENTER_MD		(97 | GPIO_IN)
++#define GPIO98_MAGICIAN_KEY_RECORD_MD		(98 | GPIO_IN)
++#define GPIO99_MAGICIAN_HEADPHONE_IN_MD		(99 | GPIO_IN)
++#define GPIO100_MAGICIAN_KEY_VOL_UP_MD		(100 | GPIO_IN)
++#define GPIO101_MAGICIAN_KEY_VOL_DOWN_MD 	(101 | GPIO_IN)
++#define GPIO102_MAGICIAN_KEY_PHONE_MD		(102 | GPIO_IN)
++#define GPIO103_MAGICIAN_LED_KP_MD		(103 | GPIO_OUT)
++#define GPIO104_MAGICIAN_LCD_POWER_1_MD 	(104 | GPIO_OUT)
++#define GPIO105_MAGICIAN_LCD_POWER_2_MD		(105 | GPIO_OUT)
++#define GPIO106_MAGICIAN_LCD_POWER_3_MD		(106 | GPIO_OUT)
++#define GPIO107_MAGICIAN_DS1WM_IRQ_MD		(107 | GPIO_IN)
++#define GPIO108_MAGICIAN_GSM_READY_MD		(108 | GPIO_IN)
++#define GPIO114_MAGICIAN_UNKNOWN_MD		(114 | GPIO_OUT)
++#define GPIO115_MAGICIAN_nPEN_IRQ_MD		(115 | GPIO_IN)
++#define GPIO116_MAGICIAN_nCAM_EN_MD		(116 | GPIO_OUT)
++#define GPIO119_MAGICIAN_UNKNOWN_MD		(119 | GPIO_OUT)
++#define GPIO120_MAGICIAN_UNKNOWN_MD		(120 | GPIO_OUT)
++
++#endif /* _MAGICIAN_H_ */
+diff --git a/include/asm-arm/arch-pxa/mfp-pxa300.h b/include/asm-arm/arch-pxa/mfp-pxa300.h
+index a209966..bb41031 100644
+--- a/include/asm-arm/arch-pxa/mfp-pxa300.h
++++ b/include/asm-arm/arch-pxa/mfp-pxa300.h
+@@ -16,6 +16,7 @@
+ #define __ASM_ARCH_MFP_PXA300_H
  
-@@ -157,7 +157,7 @@ int mlog_sys_init(struct kset *o2cb_subsys)
- 	mlog_attr_ptrs[i] = NULL;
+ #include <asm/arch/mfp.h>
++#include <asm/arch/mfp-pxa3xx.h>
  
- 	kobject_set_name(&mlog_kset.kobj, "logmask");
--	kobj_set_kset_s(&mlog_kset, *o2cb_subsys);
-+	mlog_kset.kobj.kset = o2cb_kset;
- 	return kset_register(&mlog_kset);
- }
+ /* GPIO */
+ #define GPIO46_GPIO		MFP_CFG(GPIO46, AF1)
+diff --git a/include/asm-arm/arch-pxa/mfp-pxa320.h b/include/asm-arm/arch-pxa/mfp-pxa320.h
+index 52deedc..576aa46 100644
+--- a/include/asm-arm/arch-pxa/mfp-pxa320.h
++++ b/include/asm-arm/arch-pxa/mfp-pxa320.h
+@@ -16,6 +16,7 @@
+ #define __ASM_ARCH_MFP_PXA320_H
  
-diff --git a/fs/ocfs2/cluster/sys.c b/fs/ocfs2/cluster/sys.c
-index 64f6f37..a4b0773 100644
---- a/fs/ocfs2/cluster/sys.c
-+++ b/fs/ocfs2/cluster/sys.c
-@@ -28,96 +28,55 @@
- #include <linux/module.h>
- #include <linux/kobject.h>
- #include <linux/sysfs.h>
-+#include <linux/fs.h>
+ #include <asm/arch/mfp.h>
++#include <asm/arch/mfp-pxa3xx.h>
  
- #include "ocfs2_nodemanager.h"
- #include "masklog.h"
- #include "sys.h"
+ /* GPIO */
+ #define GPIO46_GPIO		MFP_CFG(GPIO46, AF0)
+diff --git a/include/asm-arm/arch-pxa/mfp-pxa3xx.h b/include/asm-arm/arch-pxa/mfp-pxa3xx.h
+new file mode 100644
+index 0000000..1f6b35c
+--- /dev/null
++++ b/include/asm-arm/arch-pxa/mfp-pxa3xx.h
+@@ -0,0 +1,252 @@
++#ifndef __ASM_ARCH_MFP_PXA3XX_H
++#define __ASM_ARCH_MFP_PXA3XX_H
++
++#define MFPR_BASE	(0x40e10000)
++#define MFPR_SIZE	(PAGE_SIZE)
++
++/* MFPR register bit definitions */
++#define MFPR_PULL_SEL		(0x1 << 15)
++#define MFPR_PULLUP_EN		(0x1 << 14)
++#define MFPR_PULLDOWN_EN	(0x1 << 13)
++#define MFPR_SLEEP_SEL		(0x1 << 9)
++#define MFPR_SLEEP_OE_N		(0x1 << 7)
++#define MFPR_EDGE_CLEAR		(0x1 << 6)
++#define MFPR_EDGE_FALL_EN	(0x1 << 5)
++#define MFPR_EDGE_RISE_EN	(0x1 << 4)
++
++#define MFPR_SLEEP_DATA(x)	((x) << 8)
++#define MFPR_DRIVE(x)		(((x) & 0x7) << 10)
++#define MFPR_AF_SEL(x)		(((x) & 0x7) << 0)
++
++#define MFPR_EDGE_NONE		(0)
++#define MFPR_EDGE_RISE		(MFPR_EDGE_RISE_EN)
++#define MFPR_EDGE_FALL		(MFPR_EDGE_FALL_EN)
++#define MFPR_EDGE_BOTH		(MFPR_EDGE_RISE | MFPR_EDGE_FALL)
++
++/*
++ * Table that determines the low power modes outputs, with actual settings
++ * used in parentheses for don't-care values. Except for the float output,
++ * the configured driven and pulled levels match, so if there is a need for
++ * non-LPM pulled output, the same configuration could probably be used.
++ *
++ * Output value  sleep_oe_n  sleep_data  pullup_en  pulldown_en  pull_sel
++ *                 (bit 7)    (bit 8)    (bit 14)     (bit 13)   (bit 15)
++ *
++ * Input            0          X(0)        X(0)        X(0)       0
++ * Drive 0          0          0           0           X(1)       0
++ * Drive 1          0          1           X(1)        0	  0
++ * Pull hi (1)      1          X(1)        1           0	  0
++ * Pull lo (0)      1          X(0)        0           1	  0
++ * Z (float)        1          X(0)        0           0	  0
++ */
++#define MFPR_LPM_INPUT		(0)
++#define MFPR_LPM_DRIVE_LOW	(MFPR_SLEEP_DATA(0) | MFPR_PULLDOWN_EN)
++#define MFPR_LPM_DRIVE_HIGH    	(MFPR_SLEEP_DATA(1) | MFPR_PULLUP_EN)
++#define MFPR_LPM_PULL_LOW      	(MFPR_LPM_DRIVE_LOW  | MFPR_SLEEP_OE_N)
++#define MFPR_LPM_PULL_HIGH     	(MFPR_LPM_DRIVE_HIGH | MFPR_SLEEP_OE_N)
++#define MFPR_LPM_FLOAT         	(MFPR_SLEEP_OE_N)
++#define MFPR_LPM_MASK		(0xe080)
++
++/*
++ * The pullup and pulldown state of the MFP pin at run mode is by default
++ * determined by the selected alternate function. In case that some buggy
++ * devices need to override this default behavior,  the definitions below
++ * indicates the setting of corresponding MFPR bits
++ *
++ * Definition       pull_sel  pullup_en  pulldown_en
++ * MFPR_PULL_NONE       0         0        0
++ * MFPR_PULL_LOW        1         0        1
++ * MFPR_PULL_HIGH       1         1        0
++ * MFPR_PULL_BOTH       1         1        1
++ */
++#define MFPR_PULL_NONE		(0)
++#define MFPR_PULL_LOW		(MFPR_PULL_SEL | MFPR_PULLDOWN_EN)
++#define MFPR_PULL_BOTH		(MFPR_PULL_LOW | MFPR_PULLUP_EN)
++#define MFPR_PULL_HIGH		(MFPR_PULL_SEL | MFPR_PULLUP_EN)
++
++/* PXA3xx common MFP configurations - processor specific ones defined
++ * in mfp-pxa300.h and mfp-pxa320.h
++ */
++#define GPIO0_GPIO		MFP_CFG(GPIO0, AF0)
++#define GPIO1_GPIO		MFP_CFG(GPIO1, AF0)
++#define GPIO2_GPIO		MFP_CFG(GPIO2, AF0)
++#define GPIO3_GPIO		MFP_CFG(GPIO3, AF0)
++#define GPIO4_GPIO		MFP_CFG(GPIO4, AF0)
++#define GPIO5_GPIO		MFP_CFG(GPIO5, AF0)
++#define GPIO6_GPIO		MFP_CFG(GPIO6, AF0)
++#define GPIO7_GPIO		MFP_CFG(GPIO7, AF0)
++#define GPIO8_GPIO		MFP_CFG(GPIO8, AF0)
++#define GPIO9_GPIO		MFP_CFG(GPIO9, AF0)
++#define GPIO10_GPIO		MFP_CFG(GPIO10, AF0)
++#define GPIO11_GPIO		MFP_CFG(GPIO11, AF0)
++#define GPIO12_GPIO		MFP_CFG(GPIO12, AF0)
++#define GPIO13_GPIO		MFP_CFG(GPIO13, AF0)
++#define GPIO14_GPIO		MFP_CFG(GPIO14, AF0)
++#define GPIO15_GPIO		MFP_CFG(GPIO15, AF0)
++#define GPIO16_GPIO		MFP_CFG(GPIO16, AF0)
++#define GPIO17_GPIO		MFP_CFG(GPIO17, AF0)
++#define GPIO18_GPIO		MFP_CFG(GPIO18, AF0)
++#define GPIO19_GPIO		MFP_CFG(GPIO19, AF0)
++#define GPIO20_GPIO		MFP_CFG(GPIO20, AF0)
++#define GPIO21_GPIO		MFP_CFG(GPIO21, AF0)
++#define GPIO22_GPIO		MFP_CFG(GPIO22, AF0)
++#define GPIO23_GPIO		MFP_CFG(GPIO23, AF0)
++#define GPIO24_GPIO		MFP_CFG(GPIO24, AF0)
++#define GPIO25_GPIO		MFP_CFG(GPIO25, AF0)
++#define GPIO26_GPIO		MFP_CFG(GPIO26, AF0)
++#define GPIO27_GPIO		MFP_CFG(GPIO27, AF0)
++#define GPIO28_GPIO		MFP_CFG(GPIO28, AF0)
++#define GPIO29_GPIO		MFP_CFG(GPIO29, AF0)
++#define GPIO30_GPIO		MFP_CFG(GPIO30, AF0)
++#define GPIO31_GPIO		MFP_CFG(GPIO31, AF0)
++#define GPIO32_GPIO		MFP_CFG(GPIO32, AF0)
++#define GPIO33_GPIO		MFP_CFG(GPIO33, AF0)
++#define GPIO34_GPIO		MFP_CFG(GPIO34, AF0)
++#define GPIO35_GPIO		MFP_CFG(GPIO35, AF0)
++#define GPIO36_GPIO		MFP_CFG(GPIO36, AF0)
++#define GPIO37_GPIO		MFP_CFG(GPIO37, AF0)
++#define GPIO38_GPIO		MFP_CFG(GPIO38, AF0)
++#define GPIO39_GPIO		MFP_CFG(GPIO39, AF0)
++#define GPIO40_GPIO		MFP_CFG(GPIO40, AF0)
++#define GPIO41_GPIO		MFP_CFG(GPIO41, AF0)
++#define GPIO42_GPIO		MFP_CFG(GPIO42, AF0)
++#define GPIO43_GPIO		MFP_CFG(GPIO43, AF0)
++#define GPIO44_GPIO		MFP_CFG(GPIO44, AF0)
++#define GPIO45_GPIO		MFP_CFG(GPIO45, AF0)
++
++#define GPIO47_GPIO		MFP_CFG(GPIO47, AF0)
++#define GPIO48_GPIO		MFP_CFG(GPIO48, AF0)
++
++#define GPIO53_GPIO		MFP_CFG(GPIO53, AF0)
++#define GPIO54_GPIO		MFP_CFG(GPIO54, AF0)
++#define GPIO55_GPIO		MFP_CFG(GPIO55, AF0)
++
++#define GPIO57_GPIO		MFP_CFG(GPIO57, AF0)
++
++#define GPIO63_GPIO		MFP_CFG(GPIO63, AF0)
++#define GPIO64_GPIO		MFP_CFG(GPIO64, AF0)
++#define GPIO65_GPIO		MFP_CFG(GPIO65, AF0)
++#define GPIO66_GPIO		MFP_CFG(GPIO66, AF0)
++#define GPIO67_GPIO		MFP_CFG(GPIO67, AF0)
++#define GPIO68_GPIO		MFP_CFG(GPIO68, AF0)
++#define GPIO69_GPIO		MFP_CFG(GPIO69, AF0)
++#define GPIO70_GPIO		MFP_CFG(GPIO70, AF0)
++#define GPIO71_GPIO		MFP_CFG(GPIO71, AF0)
++#define GPIO72_GPIO		MFP_CFG(GPIO72, AF0)
++#define GPIO73_GPIO		MFP_CFG(GPIO73, AF0)
++#define GPIO74_GPIO		MFP_CFG(GPIO74, AF0)
++#define GPIO75_GPIO		MFP_CFG(GPIO75, AF0)
++#define GPIO76_GPIO		MFP_CFG(GPIO76, AF0)
++#define GPIO77_GPIO		MFP_CFG(GPIO77, AF0)
++#define GPIO78_GPIO		MFP_CFG(GPIO78, AF0)
++#define GPIO79_GPIO		MFP_CFG(GPIO79, AF0)
++#define GPIO80_GPIO		MFP_CFG(GPIO80, AF0)
++#define GPIO81_GPIO		MFP_CFG(GPIO81, AF0)
++#define GPIO82_GPIO		MFP_CFG(GPIO82, AF0)
++#define GPIO83_GPIO		MFP_CFG(GPIO83, AF0)
++#define GPIO84_GPIO		MFP_CFG(GPIO84, AF0)
++#define GPIO85_GPIO		MFP_CFG(GPIO85, AF0)
++#define GPIO86_GPIO		MFP_CFG(GPIO86, AF0)
++#define GPIO87_GPIO		MFP_CFG(GPIO87, AF0)
++#define GPIO88_GPIO		MFP_CFG(GPIO88, AF0)
++#define GPIO89_GPIO		MFP_CFG(GPIO89, AF0)
++#define GPIO90_GPIO		MFP_CFG(GPIO90, AF0)
++#define GPIO91_GPIO		MFP_CFG(GPIO91, AF0)
++#define GPIO92_GPIO		MFP_CFG(GPIO92, AF0)
++#define GPIO93_GPIO		MFP_CFG(GPIO93, AF0)
++#define GPIO94_GPIO		MFP_CFG(GPIO94, AF0)
++#define GPIO95_GPIO		MFP_CFG(GPIO95, AF0)
++#define GPIO96_GPIO		MFP_CFG(GPIO96, AF0)
++#define GPIO97_GPIO		MFP_CFG(GPIO97, AF0)
++#define GPIO98_GPIO		MFP_CFG(GPIO98, AF0)
++#define GPIO99_GPIO		MFP_CFG(GPIO99, AF0)
++#define GPIO100_GPIO		MFP_CFG(GPIO100, AF0)
++#define GPIO101_GPIO		MFP_CFG(GPIO101, AF0)
++#define GPIO102_GPIO		MFP_CFG(GPIO102, AF0)
++#define GPIO103_GPIO		MFP_CFG(GPIO103, AF0)
++#define GPIO104_GPIO		MFP_CFG(GPIO104, AF0)
++#define GPIO105_GPIO		MFP_CFG(GPIO105, AF0)
++#define GPIO106_GPIO		MFP_CFG(GPIO106, AF0)
++#define GPIO107_GPIO		MFP_CFG(GPIO107, AF0)
++#define GPIO108_GPIO		MFP_CFG(GPIO108, AF0)
++#define GPIO109_GPIO		MFP_CFG(GPIO109, AF0)
++#define GPIO110_GPIO		MFP_CFG(GPIO110, AF0)
++#define GPIO111_GPIO		MFP_CFG(GPIO111, AF0)
++#define GPIO112_GPIO		MFP_CFG(GPIO112, AF0)
++#define GPIO113_GPIO		MFP_CFG(GPIO113, AF0)
++#define GPIO114_GPIO		MFP_CFG(GPIO114, AF0)
++#define GPIO115_GPIO		MFP_CFG(GPIO115, AF0)
++#define GPIO116_GPIO		MFP_CFG(GPIO116, AF0)
++#define GPIO117_GPIO		MFP_CFG(GPIO117, AF0)
++#define GPIO118_GPIO		MFP_CFG(GPIO118, AF0)
++#define GPIO119_GPIO		MFP_CFG(GPIO119, AF0)
++#define GPIO120_GPIO		MFP_CFG(GPIO120, AF0)
++#define GPIO121_GPIO		MFP_CFG(GPIO121, AF0)
++#define GPIO122_GPIO		MFP_CFG(GPIO122, AF0)
++#define GPIO123_GPIO		MFP_CFG(GPIO123, AF0)
++#define GPIO124_GPIO		MFP_CFG(GPIO124, AF0)
++#define GPIO125_GPIO		MFP_CFG(GPIO125, AF0)
++#define GPIO126_GPIO		MFP_CFG(GPIO126, AF0)
++#define GPIO127_GPIO		MFP_CFG(GPIO127, AF0)
++
++#define GPIO0_2_GPIO		MFP_CFG(GPIO0_2, AF0)
++#define GPIO1_2_GPIO		MFP_CFG(GPIO1_2, AF0)
++#define GPIO2_2_GPIO		MFP_CFG(GPIO2_2, AF0)
++#define GPIO3_2_GPIO		MFP_CFG(GPIO3_2, AF0)
++#define GPIO4_2_GPIO		MFP_CFG(GPIO4_2, AF0)
++#define GPIO5_2_GPIO		MFP_CFG(GPIO5_2, AF0)
++#define GPIO6_2_GPIO		MFP_CFG(GPIO6_2, AF0)
++
++/*
++ * each MFP pin will have a MFPR register, since the offset of the
++ * register varies between processors, the processor specific code
++ * should initialize the pin offsets by pxa3xx_mfp_init_addr()
++ *
++ * pxa3xx_mfp_init_addr - accepts a table of "pxa3xx_mfp_addr_map"
++ * structure, which represents a range of MFP pins from "start" to
++ * "end", with the offset begining at "offset", to define a single
++ * pin, let "end" = -1
++ *
++ * use
++ *
++ * MFP_ADDR_X() to define a range of pins
++ * MFP_ADDR()   to define a single pin
++ * MFP_ADDR_END to signal the end of pin offset definitions
++ */
++struct pxa3xx_mfp_addr_map {
++	unsigned int	start;
++	unsigned int	end;
++	unsigned long	offset;
++};
++
++#define MFP_ADDR_X(start, end, offset) \
++	{ MFP_PIN_##start, MFP_PIN_##end, offset }
++
++#define MFP_ADDR(pin, offset) \
++	{ MFP_PIN_##pin, -1, offset }
++
++#define MFP_ADDR_END	{ MFP_PIN_INVALID, 0 }
++
++/*
++ * pxa3xx_mfp_read()/pxa3xx_mfp_write() - for direct read/write access
++ * to the MFPR register
++ */
++unsigned long pxa3xx_mfp_read(int mfp);
++void pxa3xx_mfp_write(int mfp, unsigned long mfpr_val);
++
++/*
++ * pxa3xx_mfp_config - configure the MFPR registers
++ *
++ * used by board specific initialization code
++ */
++void pxa3xx_mfp_config(unsigned long *mfp_cfgs, int num);
++
++/*
++ * pxa3xx_mfp_init_addr() - initialize the mapping between mfp pin
++ * index and MFPR register offset
++ *
++ * used by processor specific code
++ */
++void __init pxa3xx_mfp_init_addr(struct pxa3xx_mfp_addr_map *);
++void __init pxa3xx_init_mfp(void);
++#endif /* __ASM_ARCH_MFP_PXA3XX_H */
+diff --git a/include/asm-arm/arch-pxa/mfp.h b/include/asm-arm/arch-pxa/mfp.h
+index 03c508d..02f6157 100644
+--- a/include/asm-arm/arch-pxa/mfp.h
++++ b/include/asm-arm/arch-pxa/mfp.h
+@@ -16,9 +16,6 @@
+ #ifndef __ASM_ARCH_MFP_H
+ #define __ASM_ARCH_MFP_H
+ 
+-#define MFPR_BASE	(0x40e10000)
+-#define MFPR_SIZE	(PAGE_SIZE)
+-
+ #define mfp_to_gpio(m)	((m) % 128)
+ 
+ /* list of all the configurable MFP pins */
+@@ -217,114 +214,21 @@ enum {
+ };
+ 
+ /*
+- * Table that determines the low power modes outputs, with actual settings
+- * used in parentheses for don't-care values. Except for the float output,
+- * the configured driven and pulled levels match, so if there is a need for
+- * non-LPM pulled output, the same configuration could probably be used.
+- *
+- * Output value  sleep_oe_n  sleep_data  pullup_en  pulldown_en  pull_sel
+- *                 (bit 7)    (bit 8)    (bit 14d)   (bit 13d)
+- *
+- * Drive 0          0          0           0           X (1)      0
+- * Drive 1          0          1           X (1)       0	  0
+- * Pull hi (1)      1          X(1)        1           0	  0
+- * Pull lo (0)      1          X(0)        0           1	  0
+- * Z (float)        1          X(0)        0           0	  0
+- */
+-#define MFP_LPM_DRIVE_LOW	0x8
+-#define MFP_LPM_DRIVE_HIGH    	0x6
+-#define MFP_LPM_PULL_HIGH     	0x7
+-#define MFP_LPM_PULL_LOW      	0x9
+-#define MFP_LPM_FLOAT         	0x1
+-#define MFP_LPM_PULL_NEITHER	0x0
+-
+-/*
+- * The pullup and pulldown state of the MFP pin is by default determined by
+- * selected alternate function. In case some buggy devices need to override
+- * this default behavior,  pxa3xx_mfp_set_pull() can be invoked with one of
+- * the following definition as the parameter.
+- *
+- * Definition       pull_sel  pullup_en  pulldown_en
+- * MFP_PULL_HIGH        1         1        0
+- * MFP_PULL_LOW         1         0        1
+- * MFP_PULL_BOTH        1         1        1
+- * MFP_PULL_NONE        1         0        0
+- * MFP_PULL_DEFAULT     0         X        X
+- *
+- * NOTE: pxa3xx_mfp_set_pull() will modify the PULLUP_EN and PULLDOWN_EN
+- * bits,  which will cause potential conflicts with the low power mode
+- * setting, device drivers should take care of this
+- */
+-#define MFP_PULL_BOTH		(0x7u)
+-#define MFP_PULL_HIGH		(0x6u)
+-#define MFP_PULL_LOW		(0x5u)
+-#define MFP_PULL_NONE		(0x4u)
+-#define MFP_PULL_DEFAULT	(0x0u)
+-
+-#define MFP_AF0			(0)
+-#define MFP_AF1			(1)
+-#define MFP_AF2			(2)
+-#define MFP_AF3			(3)
+-#define MFP_AF4			(4)
+-#define MFP_AF5			(5)
+-#define MFP_AF6			(6)
+-#define MFP_AF7			(7)
+-
+-#define MFP_DS01X		(0)
+-#define MFP_DS02X		(1)
+-#define MFP_DS03X		(2)
+-#define MFP_DS04X		(3)
+-#define MFP_DS06X		(4)
+-#define MFP_DS08X		(5)
+-#define MFP_DS10X		(6)
+-#define MFP_DS12X		(7)
+-
+-#define MFP_EDGE_BOTH		0x3
+-#define MFP_EDGE_RISE		0x2
+-#define MFP_EDGE_FALL		0x1
+-#define MFP_EDGE_NONE		0x0
+-
+-#define MFPR_AF_MASK		0x0007
+-#define MFPR_DRV_MASK		0x1c00
+-#define MFPR_RDH_MASK		0x0200
+-#define MFPR_LPM_MASK		0xe180
+-#define MFPR_PULL_MASK		0xe000
+-#define MFPR_EDGE_MASK		0x0070
+-
+-#define MFPR_ALT_OFFSET		0
+-#define MFPR_ERE_OFFSET		4
+-#define MFPR_EFE_OFFSET		5
+-#define MFPR_EC_OFFSET		6
+-#define MFPR_SON_OFFSET		7
+-#define MFPR_SD_OFFSET		8
+-#define MFPR_SS_OFFSET		9
+-#define MFPR_DRV_OFFSET		10
+-#define MFPR_PD_OFFSET		13
+-#define MFPR_PU_OFFSET		14
+-#define MFPR_PS_OFFSET		15
+-
+-#define MFPR(af, drv, rdh, lpm, edge) \
+-	(((af) & 0x7) | (((drv) & 0x7) << 10) |\
+-	 (((rdh) & 0x1) << 9) |\
+-	 (((lpm) & 0x3) << 7) |\
+-	 (((lpm) & 0x4) << 12)|\
+-	 (((lpm) & 0x8) << 10)|\
+-	 ((!(edge)) << 6) |\
+-	 (((edge) & 0x1) << 5) |\
+-	 (((edge) & 0x2) << 3))
+-
+-/*
+  * a possible MFP configuration is represented by a 32-bit integer
+- * bit  0..15 - MFPR value (16-bit)
+- * bit 16..31 - mfp pin index (used to obtain the MFPR offset)
++ *
++ * bit  0.. 9 - MFP Pin Number (1024 Pins Maximum)
++ * bit 10..12 - Alternate Function Selection
++ * bit 13..15 - Drive Strength
++ * bit 16..18 - Low Power Mode State
++ * bit 19..20 - Low Power Mode Edge Detection
++ * bit 21..22 - Run Mode Pull State
+  *
+  * to facilitate the definition, the following macros are provided
+  *
+- * MFPR_DEFAULT - default MFPR value, with
++ * MFP_CFG_DEFAULT - default MFP configuration value, with
+  * 		  alternate function = 0,
+- * 		  drive strength = fast 1mA (MFP_DS01X)
++ * 		  drive strength = fast 3mA (MFP_DS03X)
+  * 		  low power mode = default
+- * 		  release dalay hold = false (RDH bit)
+  * 		  edge detection = none
+  *
+  * MFP_CFG	- default MFPR value with alternate function
+@@ -334,251 +238,74 @@ enum {
+  * 		  low power mode
+  * MFP_CFG_X	- default MFPR value with alternate function,
+  * 		  pin drive strength and low power mode
+- *
+- * use
+- *
+- * MFP_CFG_PIN	- to get the MFP pin index
+- * MFP_CFG_VAL	- to get the corresponding MFPR value
+  */
  
--struct o2cb_attribute {
--	struct attribute	attr;
--	ssize_t (*show)(char *buf);
--	ssize_t (*store)(const char *buf, size_t count);
+-typedef uint32_t mfp_cfg_t;
+-
+-#define MFP_CFG_PIN(mfp_cfg)	(((mfp_cfg) >> 16) & 0xffff)
+-#define MFP_CFG_VAL(mfp_cfg)	((mfp_cfg) & 0xffff)
+-
+-/*
+- * MFP register defaults to
+- *   drive strength fast 3mA (010'b)
+- *   edge detection logic disabled
+- *   alternate function 0
+- */
+-#define MFPR_DEFAULT	(0x0840)
++typedef unsigned long mfp_cfg_t;
++
++#define MFP_PIN(x)		((x) & 0x3ff)
++
++#define MFP_AF0			(0x0 << 10)
++#define MFP_AF1			(0x1 << 10)
++#define MFP_AF2			(0x2 << 10)
++#define MFP_AF3			(0x3 << 10)
++#define MFP_AF4			(0x4 << 10)
++#define MFP_AF5			(0x5 << 10)
++#define MFP_AF6			(0x6 << 10)
++#define MFP_AF7			(0x7 << 10)
++#define MFP_AF_MASK		(0x7 << 10)
++#define MFP_AF(x)		(((x) >> 10) & 0x7)
++
++#define MFP_DS01X		(0x0 << 13)
++#define MFP_DS02X		(0x1 << 13)
++#define MFP_DS03X		(0x2 << 13)
++#define MFP_DS04X		(0x3 << 13)
++#define MFP_DS06X		(0x4 << 13)
++#define MFP_DS08X		(0x5 << 13)
++#define MFP_DS10X		(0x6 << 13)
++#define MFP_DS13X		(0x7 << 13)
++#define MFP_DS_MASK		(0x7 << 13)
++#define MFP_DS(x)		(((x) >> 13) & 0x7)
++
++#define MFP_LPM_INPUT		(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_STATE_MASK	(0x7 << 16)
++#define MFP_LPM_STATE(x)	(((x) >> 16) & 0x7)
++
++#define MFP_LPM_EDGE_NONE	(0x0 << 19)
++#define MFP_LPM_EDGE_RISE	(0x1 << 19)
++#define MFP_LPM_EDGE_FALL	(0x2 << 19)
++#define MFP_LPM_EDGE_BOTH	(0x3 << 19)
++#define MFP_LPM_EDGE_MASK	(0x3 << 19)
++#define MFP_LPM_EDGE(x)		(((x) >> 19) & 0x3)
++
++#define MFP_PULL_NONE		(0x0 << 21)
++#define MFP_PULL_LOW		(0x1 << 21)
++#define MFP_PULL_HIGH		(0x2 << 21)
++#define MFP_PULL_BOTH		(0x3 << 21)
++#define MFP_PULL_MASK		(0x3 << 21)
++#define MFP_PULL(x)		(((x) >> 21) & 0x3)
++
++#define MFP_CFG_DEFAULT		(MFP_AF0 | MFP_DS03X | MFP_LPM_INPUT |\
++				 MFP_LPM_EDGE_NONE | MFP_PULL_NONE)
+ 
+ #define MFP_CFG(pin, af)		\
+-	((MFP_PIN_##pin << 16) | MFPR_DEFAULT | (MFP_##af))
++	((MFP_CFG_DEFAULT & ~MFP_AF_MASK) |\
++	 (MFP_PIN(MFP_PIN_##pin) | MFP_##af))
+ 
+ #define MFP_CFG_DRV(pin, af, drv)	\
+-	((MFP_PIN_##pin << 16) | (MFPR_DEFAULT & ~MFPR_DRV_MASK) |\
+-	 ((MFP_##drv) << 10) | (MFP_##af))
++	((MFP_CFG_DEFAULT & ~(MFP_AF_MASK | MFP_DS_MASK)) |\
++	 (MFP_PIN(MFP_PIN_##pin) | MFP_##af | MFP_##drv))
+ 
+ #define MFP_CFG_LPM(pin, af, lpm)	\
+-	((MFP_PIN_##pin << 16) | (MFPR_DEFAULT & ~MFPR_LPM_MASK) |\
+-	 (((MFP_LPM_##lpm) & 0x3) << 7)  |\
+-	 (((MFP_LPM_##lpm) & 0x4) << 12) |\
+-	 (((MFP_LPM_##lpm) & 0x8) << 10) |\
+-	 (MFP_##af))
++	((MFP_CFG_DEFAULT & ~(MFP_AF_MASK | MFP_LPM_STATE_MASK)) |\
++	 (MFP_PIN(MFP_PIN_##pin) | MFP_##af | MFP_LPM_##lpm))
+ 
+ #define MFP_CFG_X(pin, af, drv, lpm)	\
+-	((MFP_PIN_##pin << 16) |\
+-	 (MFPR_DEFAULT & ~(MFPR_DRV_MASK | MFPR_LPM_MASK)) |\
+-	 ((MFP_##drv) << 10) | (MFP_##af) |\
+-	 (((MFP_LPM_##lpm) & 0x3) << 7)  |\
+-	 (((MFP_LPM_##lpm) & 0x4) << 12) |\
+-	 (((MFP_LPM_##lpm) & 0x8) << 10))
+-
+-/* common MFP configurations - processor specific ones defined
+- * in mfp-pxa3xx.h
+- */
+-#define GPIO0_GPIO		MFP_CFG(GPIO0, AF0)
+-#define GPIO1_GPIO		MFP_CFG(GPIO1, AF0)
+-#define GPIO2_GPIO		MFP_CFG(GPIO2, AF0)
+-#define GPIO3_GPIO		MFP_CFG(GPIO3, AF0)
+-#define GPIO4_GPIO		MFP_CFG(GPIO4, AF0)
+-#define GPIO5_GPIO		MFP_CFG(GPIO5, AF0)
+-#define GPIO6_GPIO		MFP_CFG(GPIO6, AF0)
+-#define GPIO7_GPIO		MFP_CFG(GPIO7, AF0)
+-#define GPIO8_GPIO		MFP_CFG(GPIO8, AF0)
+-#define GPIO9_GPIO		MFP_CFG(GPIO9, AF0)
+-#define GPIO10_GPIO		MFP_CFG(GPIO10, AF0)
+-#define GPIO11_GPIO		MFP_CFG(GPIO11, AF0)
+-#define GPIO12_GPIO		MFP_CFG(GPIO12, AF0)
+-#define GPIO13_GPIO		MFP_CFG(GPIO13, AF0)
+-#define GPIO14_GPIO		MFP_CFG(GPIO14, AF0)
+-#define GPIO15_GPIO		MFP_CFG(GPIO15, AF0)
+-#define GPIO16_GPIO		MFP_CFG(GPIO16, AF0)
+-#define GPIO17_GPIO		MFP_CFG(GPIO17, AF0)
+-#define GPIO18_GPIO		MFP_CFG(GPIO18, AF0)
+-#define GPIO19_GPIO		MFP_CFG(GPIO19, AF0)
+-#define GPIO20_GPIO		MFP_CFG(GPIO20, AF0)
+-#define GPIO21_GPIO		MFP_CFG(GPIO21, AF0)
+-#define GPIO22_GPIO		MFP_CFG(GPIO22, AF0)
+-#define GPIO23_GPIO		MFP_CFG(GPIO23, AF0)
+-#define GPIO24_GPIO		MFP_CFG(GPIO24, AF0)
+-#define GPIO25_GPIO		MFP_CFG(GPIO25, AF0)
+-#define GPIO26_GPIO		MFP_CFG(GPIO26, AF0)
+-#define GPIO27_GPIO		MFP_CFG(GPIO27, AF0)
+-#define GPIO28_GPIO		MFP_CFG(GPIO28, AF0)
+-#define GPIO29_GPIO		MFP_CFG(GPIO29, AF0)
+-#define GPIO30_GPIO		MFP_CFG(GPIO30, AF0)
+-#define GPIO31_GPIO		MFP_CFG(GPIO31, AF0)
+-#define GPIO32_GPIO		MFP_CFG(GPIO32, AF0)
+-#define GPIO33_GPIO		MFP_CFG(GPIO33, AF0)
+-#define GPIO34_GPIO		MFP_CFG(GPIO34, AF0)
+-#define GPIO35_GPIO		MFP_CFG(GPIO35, AF0)
+-#define GPIO36_GPIO		MFP_CFG(GPIO36, AF0)
+-#define GPIO37_GPIO		MFP_CFG(GPIO37, AF0)
+-#define GPIO38_GPIO		MFP_CFG(GPIO38, AF0)
+-#define GPIO39_GPIO		MFP_CFG(GPIO39, AF0)
+-#define GPIO40_GPIO		MFP_CFG(GPIO40, AF0)
+-#define GPIO41_GPIO		MFP_CFG(GPIO41, AF0)
+-#define GPIO42_GPIO		MFP_CFG(GPIO42, AF0)
+-#define GPIO43_GPIO		MFP_CFG(GPIO43, AF0)
+-#define GPIO44_GPIO		MFP_CFG(GPIO44, AF0)
+-#define GPIO45_GPIO		MFP_CFG(GPIO45, AF0)
+-
+-#define GPIO47_GPIO		MFP_CFG(GPIO47, AF0)
+-#define GPIO48_GPIO		MFP_CFG(GPIO48, AF0)
+-
+-#define GPIO53_GPIO		MFP_CFG(GPIO53, AF0)
+-#define GPIO54_GPIO		MFP_CFG(GPIO54, AF0)
+-#define GPIO55_GPIO		MFP_CFG(GPIO55, AF0)
+-
+-#define GPIO57_GPIO		MFP_CFG(GPIO57, AF0)
+-
+-#define GPIO63_GPIO		MFP_CFG(GPIO63, AF0)
+-#define GPIO64_GPIO		MFP_CFG(GPIO64, AF0)
+-#define GPIO65_GPIO		MFP_CFG(GPIO65, AF0)
+-#define GPIO66_GPIO		MFP_CFG(GPIO66, AF0)
+-#define GPIO67_GPIO		MFP_CFG(GPIO67, AF0)
+-#define GPIO68_GPIO		MFP_CFG(GPIO68, AF0)
+-#define GPIO69_GPIO		MFP_CFG(GPIO69, AF0)
+-#define GPIO70_GPIO		MFP_CFG(GPIO70, AF0)
+-#define GPIO71_GPIO		MFP_CFG(GPIO71, AF0)
+-#define GPIO72_GPIO		MFP_CFG(GPIO72, AF0)
+-#define GPIO73_GPIO		MFP_CFG(GPIO73, AF0)
+-#define GPIO74_GPIO		MFP_CFG(GPIO74, AF0)
+-#define GPIO75_GPIO		MFP_CFG(GPIO75, AF0)
+-#define GPIO76_GPIO		MFP_CFG(GPIO76, AF0)
+-#define GPIO77_GPIO		MFP_CFG(GPIO77, AF0)
+-#define GPIO78_GPIO		MFP_CFG(GPIO78, AF0)
+-#define GPIO79_GPIO		MFP_CFG(GPIO79, AF0)
+-#define GPIO80_GPIO		MFP_CFG(GPIO80, AF0)
+-#define GPIO81_GPIO		MFP_CFG(GPIO81, AF0)
+-#define GPIO82_GPIO		MFP_CFG(GPIO82, AF0)
+-#define GPIO83_GPIO		MFP_CFG(GPIO83, AF0)
+-#define GPIO84_GPIO		MFP_CFG(GPIO84, AF0)
+-#define GPIO85_GPIO		MFP_CFG(GPIO85, AF0)
+-#define GPIO86_GPIO		MFP_CFG(GPIO86, AF0)
+-#define GPIO87_GPIO		MFP_CFG(GPIO87, AF0)
+-#define GPIO88_GPIO		MFP_CFG(GPIO88, AF0)
+-#define GPIO89_GPIO		MFP_CFG(GPIO89, AF0)
+-#define GPIO90_GPIO		MFP_CFG(GPIO90, AF0)
+-#define GPIO91_GPIO		MFP_CFG(GPIO91, AF0)
+-#define GPIO92_GPIO		MFP_CFG(GPIO92, AF0)
+-#define GPIO93_GPIO		MFP_CFG(GPIO93, AF0)
+-#define GPIO94_GPIO		MFP_CFG(GPIO94, AF0)
+-#define GPIO95_GPIO		MFP_CFG(GPIO95, AF0)
+-#define GPIO96_GPIO		MFP_CFG(GPIO96, AF0)
+-#define GPIO97_GPIO		MFP_CFG(GPIO97, AF0)
+-#define GPIO98_GPIO		MFP_CFG(GPIO98, AF0)
+-#define GPIO99_GPIO		MFP_CFG(GPIO99, AF0)
+-#define GPIO100_GPIO		MFP_CFG(GPIO100, AF0)
+-#define GPIO101_GPIO		MFP_CFG(GPIO101, AF0)
+-#define GPIO102_GPIO		MFP_CFG(GPIO102, AF0)
+-#define GPIO103_GPIO		MFP_CFG(GPIO103, AF0)
+-#define GPIO104_GPIO		MFP_CFG(GPIO104, AF0)
+-#define GPIO105_GPIO		MFP_CFG(GPIO105, AF0)
+-#define GPIO106_GPIO		MFP_CFG(GPIO106, AF0)
+-#define GPIO107_GPIO		MFP_CFG(GPIO107, AF0)
+-#define GPIO108_GPIO		MFP_CFG(GPIO108, AF0)
+-#define GPIO109_GPIO		MFP_CFG(GPIO109, AF0)
+-#define GPIO110_GPIO		MFP_CFG(GPIO110, AF0)
+-#define GPIO111_GPIO		MFP_CFG(GPIO111, AF0)
+-#define GPIO112_GPIO		MFP_CFG(GPIO112, AF0)
+-#define GPIO113_GPIO		MFP_CFG(GPIO113, AF0)
+-#define GPIO114_GPIO		MFP_CFG(GPIO114, AF0)
+-#define GPIO115_GPIO		MFP_CFG(GPIO115, AF0)
+-#define GPIO116_GPIO		MFP_CFG(GPIO116, AF0)
+-#define GPIO117_GPIO		MFP_CFG(GPIO117, AF0)
+-#define GPIO118_GPIO		MFP_CFG(GPIO118, AF0)
+-#define GPIO119_GPIO		MFP_CFG(GPIO119, AF0)
+-#define GPIO120_GPIO		MFP_CFG(GPIO120, AF0)
+-#define GPIO121_GPIO		MFP_CFG(GPIO121, AF0)
+-#define GPIO122_GPIO		MFP_CFG(GPIO122, AF0)
+-#define GPIO123_GPIO		MFP_CFG(GPIO123, AF0)
+-#define GPIO124_GPIO		MFP_CFG(GPIO124, AF0)
+-#define GPIO125_GPIO		MFP_CFG(GPIO125, AF0)
+-#define GPIO126_GPIO		MFP_CFG(GPIO126, AF0)
+-#define GPIO127_GPIO		MFP_CFG(GPIO127, AF0)
+-
+-#define GPIO0_2_GPIO		MFP_CFG(GPIO0_2, AF0)
+-#define GPIO1_2_GPIO		MFP_CFG(GPIO1_2, AF0)
+-#define GPIO2_2_GPIO		MFP_CFG(GPIO2_2, AF0)
+-#define GPIO3_2_GPIO		MFP_CFG(GPIO3_2, AF0)
+-#define GPIO4_2_GPIO		MFP_CFG(GPIO4_2, AF0)
+-#define GPIO5_2_GPIO		MFP_CFG(GPIO5_2, AF0)
+-#define GPIO6_2_GPIO		MFP_CFG(GPIO6_2, AF0)
+-
+-/*
+- * each MFP pin will have a MFPR register, since the offset of the
+- * register varies between processors, the processor specific code
+- * should initialize the pin offsets by pxa3xx_mfp_init_addr()
+- *
+- * pxa3xx_mfp_init_addr - accepts a table of "pxa3xx_mfp_addr_map"
+- * structure, which represents a range of MFP pins from "start" to
+- * "end", with the offset begining at "offset", to define a single
+- * pin, let "end" = -1
+- *
+- * use
+- *
+- * MFP_ADDR_X() to define a range of pins
+- * MFP_ADDR()   to define a single pin
+- * MFP_ADDR_END to signal the end of pin offset definitions
+- */
+-struct pxa3xx_mfp_addr_map {
+-	unsigned int	start;
+-	unsigned int	end;
+-	unsigned long	offset;
 -};
 -
--#define O2CB_ATTR(_name, _mode, _show, _store)	\
--struct o2cb_attribute o2cb_attr_##_name = __ATTR(_name, _mode, _show, _store)
+-#define MFP_ADDR_X(start, end, offset) \
+-	{ MFP_PIN_##start, MFP_PIN_##end, offset }
 -
--#define to_o2cb_attr(_attr) container_of(_attr, struct o2cb_attribute, attr)
- 
--static ssize_t o2cb_interface_revision_show(char *buf)
-+static ssize_t version_show(struct kobject *kobj, struct kobj_attribute *attr,
-+			    char *buf)
- {
- 	return snprintf(buf, PAGE_SIZE, "%u\n", O2NM_API_VERSION);
- }
+-#define MFP_ADDR(pin, offset) \
+-	{ MFP_PIN_##pin, -1, offset }
 -
--static O2CB_ATTR(interface_revision, S_IFREG | S_IRUGO, o2cb_interface_revision_show, NULL);
-+static struct kobj_attribute attr_version =
-+	__ATTR(interface_revision, S_IFREG | S_IRUGO, version_show, NULL);
- 
- static struct attribute *o2cb_attrs[] = {
--	&o2cb_attr_interface_revision.attr,
-+	&attr_version.attr,
- 	NULL,
- };
- 
--static ssize_t
--o2cb_show(struct kobject * kobj, struct attribute * attr, char * buffer);
--static ssize_t
--o2cb_store(struct kobject * kobj, struct attribute * attr,
--	   const char * buffer, size_t count);
--static struct sysfs_ops o2cb_sysfs_ops = {
--	.show	= o2cb_show,
--	.store	= o2cb_store,
-+static struct attribute_group o2cb_attr_group = {
-+	.attrs = o2cb_attrs,
- };
- 
--static struct kobj_type o2cb_subsys_type = {
--	.default_attrs	= o2cb_attrs,
--	.sysfs_ops	= &o2cb_sysfs_ops,
+-#define MFP_ADDR_END	{ MFP_PIN_INVALID, 0 }
+-
+-struct pxa3xx_mfp_pin {
+-	unsigned long	mfpr_off;	/* MFPRxx register offset */
+-	unsigned long	mfpr_val;	/* MFPRxx register value */
 -};
 -
--/* gives us o2cb_subsys */
--static decl_subsys(o2cb, NULL, NULL);
+-/*
+- * pxa3xx_mfp_read()/pxa3xx_mfp_write() - for direct read/write access
+- * to the MFPR register
+- */
+-unsigned long pxa3xx_mfp_read(int mfp);
+-void pxa3xx_mfp_write(int mfp, unsigned long mfpr_val);
 -
--static ssize_t
--o2cb_show(struct kobject * kobj, struct attribute * attr, char * buffer)
--{
--	struct o2cb_attribute *o2cb_attr = to_o2cb_attr(attr);
--	struct kset *sbs = to_kset(kobj);
+-/*
+- * pxa3xx_mfp_set_afds - set MFP alternate function and drive strength
+- * pxa3xx_mfp_set_rdh  - set MFP release delay hold on/off
+- * pxa3xx_mfp_set_lpm  - set MFP low power mode state
+- * pxa3xx_mfp_set_edge - set MFP edge detection in low power mode
+- *
+- * use these functions to override/change the default configuration
+- * done by pxa3xx_mfp_set_config(s)
+- */
+-void pxa3xx_mfp_set_afds(int mfp, int af, int ds);
+-void pxa3xx_mfp_set_rdh(int mfp, int rdh);
+-void pxa3xx_mfp_set_lpm(int mfp, int lpm);
+-void pxa3xx_mfp_set_edge(int mfp, int edge);
 -
--	BUG_ON(sbs != &o2cb_subsys);
+-/*
+- * pxa3xx_mfp_config - configure the MFPR registers
+- *
+- * used by board specific initialization code
+- */
+-void pxa3xx_mfp_config(mfp_cfg_t *mfp_cfgs, int num);
 -
--	if (o2cb_attr->show)
--		return o2cb_attr->show(buffer);
--	return -EIO;
--}
+-/*
+- * pxa3xx_mfp_init_addr() - initialize the mapping between mfp pin
+- * index and MFPR register offset
+- *
+- * used by processor specific code
+- */
+-void __init pxa3xx_mfp_init_addr(struct pxa3xx_mfp_addr_map *);
+-void __init pxa3xx_init_mfp(void);
++	((MFP_CFG_DEFAULT & ~(MFP_AF_MASK | MFP_DS_MASK | MFP_LPM_STATE_MASK)) |\
++	 (MFP_PIN(MFP_PIN_##pin) | MFP_##af | MFP_##drv | MFP_LPM_##lpm))
+ 
+ #endif /* __ASM_ARCH_MFP_H */
+diff --git a/include/asm-arm/arch-pxa/mmc.h b/include/asm-arm/arch-pxa/mmc.h
+index ef4f570..6d1304c 100644
+--- a/include/asm-arm/arch-pxa/mmc.h
++++ b/include/asm-arm/arch-pxa/mmc.h
+@@ -17,5 +17,7 @@ struct pxamci_platform_data {
+ };
+ 
+ extern void pxa_set_mci_info(struct pxamci_platform_data *info);
++extern void pxa3xx_set_mci2_info(struct pxamci_platform_data *info);
++extern void pxa3xx_set_mci3_info(struct pxamci_platform_data *info);
+ 
+ #endif
+diff --git a/include/asm-arm/arch-pxa/pcm027.h b/include/asm-arm/arch-pxa/pcm027.h
+new file mode 100644
+index 0000000..7beae14
+--- /dev/null
++++ b/include/asm-arm/arch-pxa/pcm027.h
+@@ -0,0 +1,75 @@
++/*
++ * linux/include/asm-arm/arch-pxa/pcm027.h
++ *
++ * (c) 2003 Phytec Messtechnik GmbH <armlinux at phytec.de>
++ * (c) 2007 Juergen Beisert <j.beisert at 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++
++/*
++ * Definitions of CPU card resources only
++ */
++
++/* I2C RTC */
++#define PCM027_RTC_IRQ_GPIO	0
++#define PCM027_RTC_IRQ		IRQ_GPIO(PCM027_RTC_IRQ_GPIO)
++#define PCM027_RTC_IRQ_EDGE	IRQ_TYPE_EDGE_FALLING
++#define ADR_PCM027_RTC		0x51	/* I2C address */
++
++/* I2C EEPROM */
++#define ADR_PCM027_EEPROM	0x54	/* I2C address */
++
++/* Ethernet chip (SMSC91C111) */
++#define PCM027_ETH_IRQ_GPIO	52
++#define PCM027_ETH_IRQ		IRQ_GPIO(PCM027_ETH_IRQ_GPIO)
++#define PCM027_ETH_IRQ_EDGE	IRQ_TYPE_EDGE_RISING
++#define PCM027_ETH_PHYS		PXA_CS5_PHYS
++#define PCM027_ETH_SIZE		(1*1024*1024)
++
++/* CAN controller SJA1000 (unsupported yet) */
++#define PCM027_CAN_IRQ_GPIO	114
++#define PCM027_CAN_IRQ		IRQ_GPIO(PCM027_CAN_IRQ_GPIO)
++#define PCM027_CAN_IRQ_EDGE	IRQ_TYPE_EDGE_FALLING
++#define PCM027_CAN_PHYS		0x22000000
++#define PCM027_CAN_SIZE		0x100
++
++/* SPI GPIO expander (unsupported yet) */
++#define PCM027_EGPIO_IRQ_GPIO	27
++#define PCM027_EGPIO_IRQ	IRQ_GPIO(PCM027_EGPIO_IRQ_GPIO)
++#define PCM027_EGPIO_IRQ_EDGE	IRQ_TYPE_EDGE_FALLING
++#define PCM027_EGPIO_CS		24
++/*
++ * TODO: Switch this pin from dedicated usage to GPIO if
++ * more than the MAX7301 device is connected to this SPI bus
++ */
++#define PCM027_EGPIO_CS_MODE	GPIO24_SFRM_MD
++
++/* Flash memory */
++#define PCM027_FLASH_PHYS	0x00000000
++#define PCM027_FLASH_SIZE	0x02000000
++
++/* onboard LEDs connected to GPIO */
++#define PCM027_LED_CPU		90
++#define PCM027_LED_HEARD_BEAT	91
++
++/*
++ * This CPU module needs a baseboard to work. After basic initializing
++ * its own devices, it calls baseboard's init function.
++ * TODO: Add your own basebaord init function and call it from
++ * inside pcm027_init(). This example here is for the developmen board.
++ * Refer pcm990-baseboard.c
++ */
++extern void pcm990_baseboard_init(void);
+diff --git a/include/asm-arm/arch-pxa/pcm990_baseboard.h b/include/asm-arm/arch-pxa/pcm990_baseboard.h
+new file mode 100644
+index 0000000..b699d0d
+--- /dev/null
++++ b/include/asm-arm/arch-pxa/pcm990_baseboard.h
+@@ -0,0 +1,275 @@
++/*
++ * include/asm-arm/arch-pxa/pcm990_baseboard.h
++ *
++ * (c) 2003 Phytec Messtechnik GmbH <armlinux at phytec.de>
++ * (c) 2007 Juergen Beisert <j.beisert at 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++
++#include <asm/arch/pcm027.h>
++
++/*
++ * definitions relevant only when the PCM-990
++ * development base board is in use
++ */
++
++/* CPLD's interrupt controller is connected to PCM-027 GPIO 9 */
++#define PCM990_CTRL_INT_IRQ_GPIO	9
++#define PCM990_CTRL_INT_IRQ		IRQ_GPIO(PCM990_CTRL_INT_IRQ_GPIO)
++#define PCM990_CTRL_INT_IRQ_EDGE	IRQT_RISING
++#define PCM990_CTRL_PHYS		PXA_CS1_PHYS	/* 16-Bit */
++#define PCM990_CTRL_BASE		0xea000000
++#define PCM990_CTRL_SIZE		(1*1024*1024)
++
++#define PCM990_CTRL_PWR_IRQ_GPIO	14
++#define PCM990_CTRL_PWR_IRQ		IRQ_GPIO(PCM990_CTRL_PWR_IRQ_GPIO)
++#define PCM990_CTRL_PWR_IRQ_EDGE	IRQT_RISING
++
++/* visible CPLD (U7) registers */
++#define PCM990_CTRL_REG0	0x0000	/* RESET REGISTER */
++#define PCM990_CTRL_SYSRES	0x0001	/* System RESET REGISTER */
++#define PCM990_CTRL_RESOUT	0x0002	/* RESETOUT Enable REGISTER */
++#define PCM990_CTRL_RESGPIO	0x0004	/* RESETGPIO Enable REGISTER */
++
++#define PCM990_CTRL_REG1	0x0002	/* Power REGISTER */
++#define PCM990_CTRL_5VOFF	0x0001	/* Disable  5V Regulators */
++#define PCM990_CTRL_CANPWR	0x0004	/* Enable CANPWR ADUM */
++#define PCM990_CTRL_PM_5V	0x0008	/* Read 5V OK */
++
++#define PCM990_CTRL_REG2	0x0004	/* LED REGISTER */
++#define PCM990_CTRL_LEDPWR	0x0001	/* POWER LED enable */
++#define PCM990_CTRL_LEDBAS	0x0002	/* BASIS LED enable */
++#define PCM990_CTRL_LEDUSR	0x0004	/* USER LED enable */
++
++#define PCM990_CTRL_REG3	0x0006	/* LCD CTRL REGISTER 3 */
++#define PCM990_CTRL_LCDPWR	0x0001	/* RW LCD Power on */
++#define PCM990_CTRL_LCDON	0x0002	/* RW LCD Latch on */
++#define PCM990_CTRL_LCDPOS1	0x0004	/* RW POS 1 */
++#define PCM990_CTRL_LCDPOS2	0x0008	/* RW POS 2 */
++
++#define PCM990_CTRL_REG4	0x0008	/* MMC1 CTRL REGISTER 4 */
++#define PCM990_CTRL_MMC1PWR	0x0001 /* RW MMC1 Power on */
++
++#define PCM990_CTRL_REG5	0x000A	/* MMC2 CTRL REGISTER 5 */
++#define PCM990_CTRL_MMC2PWR	0x0001	/* RW MMC2 Power on */
++#define PCM990_CTRL_MMC2LED	0x0002	/* RW MMC2 LED */
++#define PCM990_CTRL_MMC2DE	0x0004	/* R MMC2 Card detect */
++#define PCM990_CTRL_MMC2WP	0x0008	/* R MMC2 Card write protect */
++
++#define PCM990_CTRL_REG6	0x000C	/* Interrupt Clear REGISTER */
++#define PCM990_CTRL_INTC0	0x0001	/* Clear Reg BT Detect */
++#define PCM990_CTRL_INTC1	0x0002	/* Clear Reg FR RI */
++#define PCM990_CTRL_INTC2	0x0004	/* Clear Reg MMC1 Detect */
++#define PCM990_CTRL_INTC3	0x0008	/* Clear Reg PM_5V off */
++
++#define PCM990_CTRL_REG7	0x000E	/* Interrupt Enable REGISTER */
++#define PCM990_CTRL_ENAINT0	0x0001	/* Enable Int BT Detect */
++#define PCM990_CTRL_ENAINT1	0x0002	/* Enable Int FR RI */
++#define PCM990_CTRL_ENAINT2	0x0004	/* Enable Int MMC1 Detect */
++#define PCM990_CTRL_ENAINT3	0x0008	/* Enable Int PM_5V off */
++
++#define PCM990_CTRL_REG8	0x0014	/* Uart REGISTER */
++#define PCM990_CTRL_FFSD	0x0001	/* BT Uart Enable */
++#define PCM990_CTRL_BTSD	0x0002	/* FF Uart Enable */
++#define PCM990_CTRL_FFRI	0x0004	/* FF Uart RI detect */
++#define PCM990_CTRL_BTRX	0x0008	/* BT Uart Rx detect */
++
++#define PCM990_CTRL_REG9	0x0010	/* AC97 Flash REGISTER */
++#define PCM990_CTRL_FLWP	0x0001	/* pC Flash Write Protect */
++#define PCM990_CTRL_FLDIS	0x0002	/* pC Flash Disable */
++#define PCM990_CTRL_AC97ENA	0x0004	/* Enable AC97 Expansion */
++
++#define PCM990_CTRL_REG10	0x0012	/* GPS-REGISTER */
++#define PCM990_CTRL_GPSPWR	0x0004	/* GPS-Modul Power on */
++#define PCM990_CTRL_GPSENA	0x0008	/* GPS-Modul Enable */
++
++#define PCM990_CTRL_REG11	0x0014	/* Accu REGISTER */
++#define PCM990_CTRL_ACENA	0x0001	/* Charge Enable */
++#define PCM990_CTRL_ACSEL	0x0002	/* Charge Akku -> DC Enable */
++#define PCM990_CTRL_ACPRES	0x0004	/* DC Present */
++#define PCM990_CTRL_ACALARM	0x0008	/* Error Akku */
++
++#define PCM990_CTRL_P2V(x)	((x) - PCM990_CTRL_PHYS + PCM990_CTRL_BASE)
++#define PCM990_CTRL_V2P(x)	((x) - PCM990_CTRL_BASE + PCM990_CTRL_PHYS)
++
++#ifndef __ASSEMBLY__
++#  define __PCM990_CTRL_REG(x) \
++		(*((volatile unsigned char *)PCM990_CTRL_P2V(x)))
++#else
++#  define __PCM990_CTRL_REG(x)	PCM990_CTRL_P2V(x)
++#endif
++
++#define PCM990_INTMSKENA __PCM990_CTRL_REG(PCM990_CTRL_PHYS + PCM990_CTRL_REG7)
++#define PCM990_INTSETCLR __PCM990_CTRL_REG(PCM990_CTRL_PHYS + PCM990_CTRL_REG6)
++#define PCM990_CTRL0	__PCM990_CTRL_REG(PCM990_CTRL_PHYS + PCM990_CTRL_REG0)
++#define PCM990_CTRL1	__PCM990_CTRL_REG(PCM990_CTRL_PHYS + PCM990_CTRL_REG1)
++#define PCM990_CTRL2	__PCM990_CTRL_REG(PCM990_CTRL_PHYS + PCM990_CTRL_REG2)
++#define PCM990_CTRL3	__PCM990_CTRL_REG(PCM990_CTRL_PHYS + PCM990_CTRL_REG3)
++#define PCM990_CTRL4	__PCM990_CTRL_REG(PCM990_CTRL_PHYS + PCM990_CTRL_REG4)
++#define PCM990_CTRL5	__PCM990_CTRL_REG(PCM990_CTRL_PHYS + PCM990_CTRL_REG5)
++#define PCM990_CTRL6	__PCM990_CTRL_REG(PCM990_CTRL_PHYS + PCM990_CTRL_REG6)
++#define PCM990_CTRL7	__PCM990_CTRL_REG(PCM990_CTRL_PHYS + PCM990_CTRL_REG7)
++#define PCM990_CTRL8	__PCM990_CTRL_REG(PCM990_CTRL_PHYS + PCM990_CTRL_REG8)
++#define PCM990_CTRL9	__PCM990_CTRL_REG(PCM990_CTRL_PHYS + PCM990_CTRL_REG9)
++#define PCM990_CTRL10	__PCM990_CTRL_REG(PCM990_CTRL_PHYS + PCM990_CTRL_REG10)
++#define PCM990_CTRL11	__PCM990_CTRL_REG(PCM990_CTRL_PHYS + PCM990_CTRL_REG11)
++
++
++/*
++ * IDE
++ */
++#define PCM990_IDE_IRQ_GPIO	13
++#define PCM990_IDE_IRQ		IRQ_GPIO(PCM990_IDE_IRQ_GPIO)
++#define PCM990_IDE_IRQ_EDGE	IRQT_RISING
++#define PCM990_IDE_PLD_PHYS	0x20000000	/* 16 bit wide */
++#define PCM990_IDE_PLD_BASE	0xee000000
++#define PCM990_IDE_PLD_SIZE	(1*1024*1024)
++
++/* visible CPLD (U6) registers */
++#define PCM990_IDE_PLD_REG0	0x1000	/* OFFSET IDE REGISTER 0 */
++#define PCM990_IDE_PM5V		0x0004	/* R System VCC_5V */
++#define PCM990_IDE_STBY		0x0008	/* R System StandBy */
++
++#define PCM990_IDE_PLD_REG1	0x1002	/* OFFSET IDE REGISTER 1 */
++#define PCM990_IDE_IDEMODE	0x0001	/* R TrueIDE Mode */
++#define PCM990_IDE_DMAENA	0x0004	/* RW DMA Enable */
++#define PCM990_IDE_DMA1_0	0x0008	/* RW 1=DREQ1 0=DREQ0 */
++
++#define PCM990_IDE_PLD_REG2	0x1004	/* OFFSET IDE REGISTER 2 */
++#define PCM990_IDE_RESENA	0x0001	/* RW IDE Reset Bit enable */
++#define PCM990_IDE_RES		0x0002	/* RW IDE Reset Bit */
++#define PCM990_IDE_RDY		0x0008	/* RDY */
++
++#define PCM990_IDE_PLD_REG3	0x1006	/* OFFSET IDE REGISTER 3 */
++#define PCM990_IDE_IDEOE	0x0001	/* RW Latch on Databus */
++#define PCM990_IDE_IDEON	0x0002	/* RW Latch on Control Address */
++#define PCM990_IDE_IDEIN	0x0004	/* RW Latch on Interrupt usw. */
++
++#define PCM990_IDE_PLD_REG4	0x1008	/* OFFSET IDE REGISTER 4 */
++#define PCM990_IDE_PWRENA	0x0001	/* RW IDE Power enable */
++#define PCM990_IDE_5V		0x0002	/* R IDE Power 5V */
++#define PCM990_IDE_PWG		0x0008	/* R IDE Power is on */
++
++#define PCM990_IDE_PLD_P2V(x) ((x) - PCM990_IDE_PLD_PHYS + PCM990_IDE_PLD_BASE)
++#define PCM990_IDE_PLD_V2P(x) ((x) - PCM990_IDE_PLD_BASE + PCM990_IDE_PLD_PHYS)
++
++#ifndef __ASSEMBLY__
++# define  __PCM990_IDE_PLD_REG(x) \
++	(*((volatile unsigned char *)PCM990_IDE_PLD_P2V(x)))
++#else
++# define  __PCM990_IDE_PLD_REG(x)	PCM990_IDE_PLD_P2V(x)
++#endif
++
++#define PCM990_IDE0 \
++	__PCM990_IDE_PLD_REG(PCM990_IDE_PLD_PHYS + PCM990_IDE_PLD_REG0)
++#define PCM990_IDE1 \
++	__PCM990_IDE_PLD_REG(PCM990_IDE_PLD_PHYS + PCM990_IDE_PLD_REG1)
++#define PCM990_IDE2 \
++	__PCM990_IDE_PLD_REG(PCM990_IDE_PLD_PHYS + PCM990_IDE_PLD_REG2)
++#define PCM990_IDE3 \
++	__PCM990_IDE_PLD_REG(PCM990_IDE_PLD_PHYS + PCM990_IDE_PLD_REG3)
++#define PCM990_IDE4 \
++	__PCM990_IDE_PLD_REG(PCM990_IDE_PLD_PHYS + PCM990_IDE_PLD_REG4)
++
++/*
++ * Compact Flash
++ */
++#define PCM990_CF_IRQ_GPIO	11
++#define PCM990_CF_IRQ		IRQ_GPIO(PCM990_CF_IRQ_GPIO)
++#define PCM990_CF_IRQ_EDGE	IRQT_RISING
++
++#define PCM990_CF_CD_GPIO	12
++#define PCM990_CF_CD		IRQ_GPIO(PCM990_CF_CD_GPIO)
++#define PCM990_CF_CD_EDGE	IRQT_RISING
++
++#define PCM990_CF_PLD_PHYS	0x30000000	/* 16 bit wide */
++#define PCM990_CF_PLD_BASE	0xef000000
++#define PCM990_CF_PLD_SIZE	(1*1024*1024)
++#define PCM990_CF_PLD_P2V(x)	((x) - PCM990_CF_PLD_PHYS + PCM990_CF_PLD_BASE)
++#define PCM990_CF_PLD_V2P(x)	((x) - PCM990_CF_PLD_BASE + PCM990_CF_PLD_PHYS)
++
++/* visible CPLD (U6) registers */
++#define PCM990_CF_PLD_REG0	0x1000	/* OFFSET CF REGISTER 0 */
++#define PCM990_CF_REG0_LED	0x0001	/* RW LED on */
++#define PCM990_CF_REG0_BLK	0x0002	/* RW LED flash when access */
++#define PCM990_CF_REG0_PM5V	0x0004	/* R System VCC_5V enable */
++#define PCM990_CF_REG0_STBY	0x0008	/* R System StandBy */
++
++#define PCM990_CF_PLD_REG1	0x1002	/* OFFSET CF REGISTER 1 */
++#define PCM990_CF_REG1_IDEMODE	0x0001	/* RW CF card run as TrueIDE */
++#define PCM990_CF_REG1_CF0	0x0002	/* RW CF card at ADDR 0x28000000 */
++
++#define PCM990_CF_PLD_REG2	0x1004	/* OFFSET CF REGISTER 2 */
++#define PCM990_CF_REG2_RES	0x0002	/* RW CF RESET BIT */
++#define PCM990_CF_REG2_RDYENA	0x0004	/* RW Enable CF_RDY */
++#define PCM990_CF_REG2_RDY	0x0008	/* R CF_RDY auf PWAIT */
++
++#define PCM990_CF_PLD_REG3	0x1006	/* OFFSET CF REGISTER 3 */
++#define PCM990_CF_REG3_CFOE	0x0001	/* RW Latch on Databus */
++#define PCM990_CF_REG3_CFON	0x0002	/* RW Latch on Control Address */
++#define PCM990_CF_REG3_CFIN	0x0004	/* RW Latch on Interrupt usw. */
++#define PCM990_CF_REG3_CFCD	0x0008	/* RW Latch on CD1/2 VS1/2 usw */
++
++#define PCM990_CF_PLD_REG4	0x1008	/* OFFSET CF REGISTER 4 */
++#define PCM990_CF_REG4_PWRENA	0x0001	/* RW CF Power on (CD1/2 = "00") */
++#define PCM990_CF_REG4_5_3V	0x0002	/* RW 1 = 5V CF_VCC 0 = 3 V CF_VCC */
++#define PCM990_CF_REG4_3B	0x0004	/* RW 3.0V Backup from VCC (5_3V=0) */
++#define PCM990_CF_REG4_PWG	0x0008	/* R CF-Power is on */
++
++#define PCM990_CF_PLD_REG5	0x100A	/* OFFSET CF REGISTER 5 */
++#define PCM990_CF_REG5_BVD1	0x0001	/* R CF /BVD1 */
++#define PCM990_CF_REG5_BVD2	0x0002	/* R CF /BVD2 */
++#define PCM990_CF_REG5_VS1	0x0004	/* R CF /VS1 */
++#define PCM990_CF_REG5_VS2	0x0008	/* R CF /VS2 */
++
++#define PCM990_CF_PLD_REG6	0x100C	/* OFFSET CF REGISTER 6 */
++#define PCM990_CF_REG6_CD1	0x0001	/* R CF Card_Detect1 */
++#define PCM990_CF_REG6_CD2	0x0002	/* R CF Card_Detect2 */
++
++#ifndef __ASSEMBLY__
++#  define  __PCM990_CF_PLD_REG(x) \
++	(*((volatile unsigned char *)PCM990_CF_PLD_P2V(x)))
++#else
++#  define  __PCM990_CF_PLD_REG(x)	PCM990_CF_PLD_P2V(x)
++#endif
++
++#define PCM990_CF0 __PCM990_CF_PLD_REG(PCM990_CF_PLD_PHYS + PCM990_CF_PLD_REG0)
++#define PCM990_CF1 __PCM990_CF_PLD_REG(PCM990_CF_PLD_PHYS + PCM990_CF_PLD_REG1)
++#define PCM990_CF2 __PCM990_CF_PLD_REG(PCM990_CF_PLD_PHYS + PCM990_CF_PLD_REG2)
++#define PCM990_CF3 __PCM990_CF_PLD_REG(PCM990_CF_PLD_PHYS + PCM990_CF_PLD_REG3)
++#define PCM990_CF4 __PCM990_CF_PLD_REG(PCM990_CF_PLD_PHYS + PCM990_CF_PLD_REG4)
++#define PCM990_CF5 __PCM990_CF_PLD_REG(PCM990_CF_PLD_PHYS + PCM990_CF_PLD_REG5)
++#define PCM990_CF6 __PCM990_CF_PLD_REG(PCM990_CF_PLD_PHYS + PCM990_CF_PLD_REG6)
++
++/*
++ * Wolfson AC97 Touch
++ */
++#define PCM990_AC97_IRQ_GPIO	10
++#define PCM990_AC97_IRQ		IRQ_GPIO(PCM990_AC97_IRQ_GPIO)
++#define PCM990_AC97_IRQ_EDGE	IRQT_RISING
++
++/*
++ * MMC phyCORE
++ */
++#define PCM990_MMC0_IRQ_GPIO	9
++#define PCM990_MMC0_IRQ		IRQ_GPIO(PCM990_MMC0_IRQ_GPIO)
++#define PCM990_MMC0_IRQ_EDGE	IRQT_FALLING
++
++/*
++ * USB phyCore
++ */
++#define PCM990_USB_OVERCURRENT (88 | GPIO_ALT_FN_1_IN)
++#define PCM990_USB_PWR_EN (89 | GPIO_ALT_FN_2_OUT)
+diff --git a/include/asm-arm/arch-pxa/pxa-regs.h b/include/asm-arm/arch-pxa/pxa-regs.h
+index 1bd398d..442494d 100644
+--- a/include/asm-arm/arch-pxa/pxa-regs.h
++++ b/include/asm-arm/arch-pxa/pxa-regs.h
+@@ -1597,176 +1597,10 @@
+ #define PWER_GPIO15	PWER_GPIO (15)	/* GPIO [15] wake-up enable        */
+ #define PWER_RTC	0x80000000	/* RTC alarm wake-up enable        */
+ 
+-
+ /*
+- * SSP Serial Port Registers
+- * PXA250, PXA255, PXA26x and PXA27x SSP controllers are all slightly different.
+- * PXA255, PXA26x and PXA27x have extra ports, registers and bits.
++ * SSP Serial Port Registers - see include/asm-arm/arch-pxa/regs-ssp.h
+  */
+ 
+- /* Common PXA2xx bits first */
+-#define SSCR0_DSS	(0x0000000f)	/* Data Size Select (mask) */
+-#define SSCR0_DataSize(x)  ((x) - 1)	/* Data Size Select [4..16] */
+-#define SSCR0_FRF	(0x00000030)	/* FRame Format (mask) */
+-#define SSCR0_Motorola	(0x0 << 4)	/* Motorola's Serial Peripheral Interface (SPI) */
+-#define SSCR0_TI	(0x1 << 4)	/* Texas Instruments' Synchronous Serial Protocol (SSP) */
+-#define SSCR0_National	(0x2 << 4)	/* National Microwire */
+-#define SSCR0_ECS	(1 << 6)	/* External clock select */
+-#define SSCR0_SSE	(1 << 7)	/* Synchronous Serial Port Enable */
+-#if defined(CONFIG_PXA25x)
+-#define SSCR0_SCR	(0x0000ff00)	/* Serial Clock Rate (mask) */
+-#define SSCR0_SerClkDiv(x) ((((x) - 2)/2) << 8) /* Divisor [2..512] */
+-#elif defined(CONFIG_PXA27x)
+-#define SSCR0_SCR	(0x000fff00)	/* Serial Clock Rate (mask) */
+-#define SSCR0_SerClkDiv(x) (((x) - 1) << 8) /* Divisor [1..4096] */
+-#define SSCR0_EDSS	(1 << 20)	/* Extended data size select */
+-#define SSCR0_NCS	(1 << 21)	/* Network clock select */
+-#define SSCR0_RIM	(1 << 22)	/* Receive FIFO overrrun interrupt mask */
+-#define SSCR0_TUM	(1 << 23)	/* Transmit FIFO underrun interrupt mask */
+-#define SSCR0_FRDC	(0x07000000)	/* Frame rate divider control (mask) */
+-#define SSCR0_SlotsPerFrm(x) (((x) - 1) << 24)	/* Time slots per frame [1..8] */
+-#define SSCR0_ADC	(1 << 30)	/* Audio clock select */
+-#define SSCR0_MOD	(1 << 31)	/* Mode (normal or network) */
+-#endif
 -
--static ssize_t
--o2cb_store(struct kobject * kobj, struct attribute * attr,
--	     const char * buffer, size_t count)
--{
--	struct o2cb_attribute *o2cb_attr = to_o2cb_attr(attr);
--	struct kset *sbs = to_kset(kobj);
+-#define SSCR1_RIE	(1 << 0)	/* Receive FIFO Interrupt Enable */
+-#define SSCR1_TIE	(1 << 1)	/* Transmit FIFO Interrupt Enable */
+-#define SSCR1_LBM	(1 << 2)	/* Loop-Back Mode */
+-#define SSCR1_SPO	(1 << 3)	/* Motorola SPI SSPSCLK polarity setting */
+-#define SSCR1_SPH	(1 << 4)	/* Motorola SPI SSPSCLK phase setting */
+-#define SSCR1_MWDS	(1 << 5)	/* Microwire Transmit Data Size */
+-#define SSCR1_TFT	(0x000003c0)	/* Transmit FIFO Threshold (mask) */
+-#define SSCR1_TxTresh(x) (((x) - 1) << 6) /* level [1..16] */
+-#define SSCR1_RFT	(0x00003c00)	/* Receive FIFO Threshold (mask) */
+-#define SSCR1_RxTresh(x) (((x) - 1) << 10) /* level [1..16] */
+-
+-#define SSSR_TNF	(1 << 2)	/* Transmit FIFO Not Full */
+-#define SSSR_RNE	(1 << 3)	/* Receive FIFO Not Empty */
+-#define SSSR_BSY	(1 << 4)	/* SSP Busy */
+-#define SSSR_TFS	(1 << 5)	/* Transmit FIFO Service Request */
+-#define SSSR_RFS	(1 << 6)	/* Receive FIFO Service Request */
+-#define SSSR_ROR	(1 << 7)	/* Receive FIFO Overrun */
+-
+-#define SSCR0_TIM		(1 << 23)	/* Transmit FIFO Under Run Interrupt Mask */
+-#define SSCR0_RIM		(1 << 22)	/* Receive FIFO Over Run interrupt Mask */
+-#define SSCR0_NCS		(1 << 21)	/* Network Clock Select */
+-#define SSCR0_EDSS		(1 << 20)	/* Extended Data Size Select */
+-
+-/* extra bits in PXA255, PXA26x and PXA27x SSP ports */
+-#define SSCR0_TISSP		(1 << 4)	/* TI Sync Serial Protocol */
+-#define SSCR0_PSP		(3 << 4)	/* PSP - Programmable Serial Protocol */
+-#define SSCR1_TTELP		(1 << 31)	/* TXD Tristate Enable Last Phase */
+-#define SSCR1_TTE		(1 << 30)	/* TXD Tristate Enable */
+-#define SSCR1_EBCEI		(1 << 29)	/* Enable Bit Count Error interrupt */
+-#define SSCR1_SCFR		(1 << 28)	/* Slave Clock free Running */
+-#define SSCR1_ECRA		(1 << 27)	/* Enable Clock Request A */
+-#define SSCR1_ECRB		(1 << 26)	/* Enable Clock request B */
+-#define SSCR1_SCLKDIR	(1 << 25)	/* Serial Bit Rate Clock Direction */
+-#define SSCR1_SFRMDIR	(1 << 24)	/* Frame Direction */
+-#define SSCR1_RWOT		(1 << 23)	/* Receive Without Transmit */
+-#define SSCR1_TRAIL		(1 << 22)	/* Trailing Byte */
+-#define SSCR1_TSRE		(1 << 21)	/* Transmit Service Request Enable */
+-#define SSCR1_RSRE		(1 << 20)	/* Receive Service Request Enable */
+-#define SSCR1_TINTE		(1 << 19)	/* Receiver Time-out Interrupt enable */
+-#define SSCR1_PINTE		(1 << 18)	/* Peripheral Trailing Byte Interupt Enable */
+-#define SSCR1_STRF		(1 << 15)	/* Select FIFO or EFWR */
+-#define SSCR1_EFWR		(1 << 14)	/* Enable FIFO Write/Read */
+-
+-#define SSSR_BCE		(1 << 23)	/* Bit Count Error */
+-#define SSSR_CSS		(1 << 22)	/* Clock Synchronisation Status */
+-#define SSSR_TUR		(1 << 21)	/* Transmit FIFO Under Run */
+-#define SSSR_EOC		(1 << 20)	/* End Of Chain */
+-#define SSSR_TINT		(1 << 19)	/* Receiver Time-out Interrupt */
+-#define SSSR_PINT		(1 << 18)	/* Peripheral Trailing Byte Interrupt */
+-
+-#define SSPSP_FSRT		(1 << 25)	/* Frame Sync Relative Timing */
+-#define SSPSP_DMYSTOP(x)	((x) << 23)	/* Dummy Stop */
+-#define SSPSP_SFRMWDTH(x)	((x) << 16)	/* Serial Frame Width */
+-#define SSPSP_SFRMDLY(x)	((x) << 9)	/* Serial Frame Delay */
+-#define SSPSP_DMYSTRT(x)	((x) << 7)	/* Dummy Start */
+-#define SSPSP_STRTDLY(x)	((x) << 4)	/* Start Delay */
+-#define SSPSP_ETDS			(1 << 3)	/* End of Transfer data State */
+-#define SSPSP_SFRMP			(1 << 2)	/* Serial Frame Polarity */
+-#define SSPSP_SCMODE(x)		((x) << 0)	/* Serial Bit Rate Clock Mode */
+-
+-#define SSACD_SCDB		(1 << 3)	/* SSPSYSCLK Divider Bypass */
+-#define SSACD_ACPS(x)		((x) << 4)	/* Audio clock PLL select */
+-#define SSACD_ACDS(x)		((x) << 0)	/* Audio clock divider select */
+-
+-#define SSCR0_P1	__REG(0x41000000)  /* SSP Port 1 Control Register 0 */
+-#define SSCR1_P1	__REG(0x41000004)  /* SSP Port 1 Control Register 1 */
+-#define SSSR_P1		__REG(0x41000008)  /* SSP Port 1 Status Register */
+-#define SSITR_P1	__REG(0x4100000C)  /* SSP Port 1 Interrupt Test Register */
+-#define SSDR_P1		__REG(0x41000010)  /* (Write / Read) SSP Port 1 Data Write Register/SSP Data Read Register */
+-
+-/* Support existing PXA25x drivers */
+-#define SSCR0		SSCR0_P1  /* SSP Control Register 0 */
+-#define SSCR1		SSCR1_P1  /* SSP Control Register 1 */
+-#define SSSR		SSSR_P1	  /* SSP Status Register */
+-#define SSITR		SSITR_P1  /* SSP Interrupt Test Register */
+-#define SSDR		SSDR_P1	  /* (Write / Read) SSP Data Write Register/SSP Data Read Register */
+-
+-/* PXA27x ports */
+-#if defined (CONFIG_PXA27x)
+-#define SSTO_P1		__REG(0x41000028)  /* SSP Port 1 Time Out Register */
+-#define SSPSP_P1	__REG(0x4100002C)  /* SSP Port 1 Programmable Serial Protocol */
+-#define SSTSA_P1	__REG(0x41000030)  /* SSP Port 1 Tx Timeslot Active */
+-#define SSRSA_P1	__REG(0x41000034)  /* SSP Port 1 Rx Timeslot Active */
+-#define SSTSS_P1	__REG(0x41000038)  /* SSP Port 1 Timeslot Status */
+-#define SSACD_P1	__REG(0x4100003C)  /* SSP Port 1 Audio Clock Divider */
+-#define SSCR0_P2	__REG(0x41700000)  /* SSP Port 2 Control Register 0 */
+-#define SSCR1_P2	__REG(0x41700004)  /* SSP Port 2 Control Register 1 */
+-#define SSSR_P2		__REG(0x41700008)  /* SSP Port 2 Status Register */
+-#define SSITR_P2	__REG(0x4170000C)  /* SSP Port 2 Interrupt Test Register */
+-#define SSDR_P2		__REG(0x41700010)  /* (Write / Read) SSP Port 2 Data Write Register/SSP Data Read Register */
+-#define SSTO_P2		__REG(0x41700028)  /* SSP Port 2 Time Out Register */
+-#define SSPSP_P2	__REG(0x4170002C)  /* SSP Port 2 Programmable Serial Protocol */
+-#define SSTSA_P2	__REG(0x41700030)  /* SSP Port 2 Tx Timeslot Active */
+-#define SSRSA_P2	__REG(0x41700034)  /* SSP Port 2 Rx Timeslot Active */
+-#define SSTSS_P2	__REG(0x41700038)  /* SSP Port 2 Timeslot Status */
+-#define SSACD_P2	__REG(0x4170003C)  /* SSP Port 2 Audio Clock Divider */
+-#define SSCR0_P3	__REG(0x41900000)  /* SSP Port 3 Control Register 0 */
+-#define SSCR1_P3	__REG(0x41900004)  /* SSP Port 3 Control Register 1 */
+-#define SSSR_P3		__REG(0x41900008)  /* SSP Port 3 Status Register */
+-#define SSITR_P3	__REG(0x4190000C)  /* SSP Port 3 Interrupt Test Register */
+-#define SSDR_P3		__REG(0x41900010)  /* (Write / Read) SSP Port 3 Data Write Register/SSP Data Read Register */
+-#define SSTO_P3		__REG(0x41900028)  /* SSP Port 3 Time Out Register */
+-#define SSPSP_P3	__REG(0x4190002C)  /* SSP Port 3 Programmable Serial Protocol */
+-#define SSTSA_P3	__REG(0x41900030)  /* SSP Port 3 Tx Timeslot Active */
+-#define SSRSA_P3	__REG(0x41900034)  /* SSP Port 3 Rx Timeslot Active */
+-#define SSTSS_P3	__REG(0x41900038)  /* SSP Port 3 Timeslot Status */
+-#define SSACD_P3	__REG(0x4190003C)  /* SSP Port 3 Audio Clock Divider */
+-#else /* PXA255 (only port 2) and PXA26x ports*/
+-#define SSTO_P1		__REG(0x41000028)  /* SSP Port 1 Time Out Register */
+-#define SSPSP_P1	__REG(0x4100002C)  /* SSP Port 1 Programmable Serial Protocol */
+-#define SSCR0_P2	__REG(0x41400000)  /* SSP Port 2 Control Register 0 */
+-#define SSCR1_P2	__REG(0x41400004)  /* SSP Port 2 Control Register 1 */
+-#define SSSR_P2		__REG(0x41400008)  /* SSP Port 2 Status Register */
+-#define SSITR_P2	__REG(0x4140000C)  /* SSP Port 2 Interrupt Test Register */
+-#define SSDR_P2		__REG(0x41400010)  /* (Write / Read) SSP Port 2 Data Write Register/SSP Data Read Register */
+-#define SSTO_P2		__REG(0x41400028)  /* SSP Port 2 Time Out Register */
+-#define SSPSP_P2	__REG(0x4140002C)  /* SSP Port 2 Programmable Serial Protocol */
+-#define SSCR0_P3	__REG(0x41500000)  /* SSP Port 3 Control Register 0 */
+-#define SSCR1_P3	__REG(0x41500004)  /* SSP Port 3 Control Register 1 */
+-#define SSSR_P3		__REG(0x41500008)  /* SSP Port 3 Status Register */
+-#define SSITR_P3	__REG(0x4150000C)  /* SSP Port 3 Interrupt Test Register */
+-#define SSDR_P3		__REG(0x41500010)  /* (Write / Read) SSP Port 3 Data Write Register/SSP Data Read Register */
+-#define SSTO_P3		__REG(0x41500028)  /* SSP Port 3 Time Out Register */
+-#define SSPSP_P3	__REG(0x4150002C)  /* SSP Port 3 Programmable Serial Protocol */
+-#endif
 -
--	BUG_ON(sbs != &o2cb_subsys);
+-#define SSCR0_P(x) (*(((x) == 1) ? &SSCR0_P1 : ((x) == 2) ? &SSCR0_P2 : ((x) == 3) ? &SSCR0_P3 : NULL))
+-#define SSCR1_P(x) (*(((x) == 1) ? &SSCR1_P1 : ((x) == 2) ? &SSCR1_P2 : ((x) == 3) ? &SSCR1_P3 : NULL))
+-#define SSSR_P(x) (*(((x) == 1) ? &SSSR_P1 : ((x) == 2) ? &SSSR_P2 : ((x) == 3) ? &SSSR_P3 : NULL))
+-#define SSITR_P(x) (*(((x) == 1) ? &SSITR_P1 : ((x) == 2) ? &SSITR_P2 : ((x) == 3) ? &SSITR_P3 : NULL))
+-#define SSDR_P(x) (*(((x) == 1) ? &SSDR_P1 : ((x) == 2) ? &SSDR_P2 : ((x) == 3) ? &SSDR_P3 : NULL))
+-#define SSTO_P(x) (*(((x) == 1) ? &SSTO_P1 : ((x) == 2) ? &SSTO_P2 : ((x) == 3) ? &SSTO_P3 : NULL))
+-#define SSPSP_P(x) (*(((x) == 1) ? &SSPSP_P1 : ((x) == 2) ? &SSPSP_P2 : ((x) == 3) ? &SSPSP_P3 : NULL))
+-#define SSTSA_P(x) (*(((x) == 1) ? &SSTSA_P1 : ((x) == 2) ? &SSTSA_P2 : ((x) == 3) ? &SSTSA_P3 : NULL))
+-#define SSRSA_P(x) (*(((x) == 1) ? &SSRSA_P1 : ((x) == 2) ? &SSRSA_P2 : ((x) == 3) ? &SSRSA_P3 : NULL))
+-#define SSTSS_P(x) (*(((x) == 1) ? &SSTSS_P1 : ((x) == 2) ? &SSTSS_P2 : ((x) == 3) ? &SSTSS_P3 : NULL))
+-#define SSACD_P(x) (*(((x) == 1) ? &SSACD_P1 : ((x) == 2) ? &SSACD_P2 : ((x) == 3) ? &SSACD_P3 : NULL))
 -
--	if (o2cb_attr->store)
--		return o2cb_attr->store(buffer, count);
--	return -EIO;
--}
-+static struct kset *o2cb_kset;
+ /*
+  * MultiMediaCard (MMC) controller - see drivers/mmc/host/pxamci.h
+  */
+@@ -2014,71 +1848,8 @@
  
- void o2cb_sys_shutdown(void)
- {
- 	mlog_sys_shutdown();
--	subsystem_unregister(&o2cb_subsys);
-+	kset_unregister(o2cb_kset);
- }
+ #define LDCMD_PAL	(1 << 26)	/* instructs DMA to load palette buffer */
  
- int o2cb_sys_init(void)
- {
- 	int ret;
+-/*
+- * Memory controller
+- */
+-
+-#define MDCNFG		__REG(0x48000000)  /* SDRAM Configuration Register 0 */
+-#define MDREFR		__REG(0x48000004)  /* SDRAM Refresh Control Register */
+-#define MSC0		__REG(0x48000008)  /* Static Memory Control Register 0 */
+-#define MSC1		__REG(0x4800000C)  /* Static Memory Control Register 1 */
+-#define MSC2		__REG(0x48000010)  /* Static Memory Control Register 2 */
+-#define MECR		__REG(0x48000014)  /* Expansion Memory (PCMCIA/Compact Flash) Bus Configuration */
+-#define SXLCR		__REG(0x48000018)  /* LCR value to be written to SDRAM-Timing Synchronous Flash */
+-#define SXCNFG		__REG(0x4800001C)  /* Synchronous Static Memory Control Register */
+-#define SXMRS		__REG(0x48000024)  /* MRS value to be written to Synchronous Flash or SMROM */
+-#define MCMEM0		__REG(0x48000028)  /* Card interface Common Memory Space Socket 0 Timing */
+-#define MCMEM1		__REG(0x4800002C)  /* Card interface Common Memory Space Socket 1 Timing */
+-#define MCATT0		__REG(0x48000030)  /* Card interface Attribute Space Socket 0 Timing Configuration */
+-#define MCATT1		__REG(0x48000034)  /* Card interface Attribute Space Socket 1 Timing Configuration */
+-#define MCIO0		__REG(0x48000038)  /* Card interface I/O Space Socket 0 Timing Configuration */
+-#define MCIO1		__REG(0x4800003C)  /* Card interface I/O Space Socket 1 Timing Configuration */
+-#define MDMRS		__REG(0x48000040)  /* MRS value to be written to SDRAM */
+-#define BOOT_DEF	__REG(0x48000044)  /* Read-Only Boot-Time Register. Contains BOOT_SEL and PKG_SEL */
+-
+-/*
+- * More handy macros for PCMCIA
+- *
+- * Arg is socket number
+- */
+-#define MCMEM(s)	__REG2(0x48000028, (s)<<2 )  /* Card interface Common Memory Space Socket s Timing */
+-#define MCATT(s)	__REG2(0x48000030, (s)<<2 )  /* Card interface Attribute Space Socket s Timing Configuration */
+-#define MCIO(s)		__REG2(0x48000038, (s)<<2 )  /* Card interface I/O Space Socket s Timing Configuration */
+-
+-/* MECR register defines */
+-#define MECR_NOS	(1 << 0)	/* Number Of Sockets: 0 -> 1 sock, 1 -> 2 sock */
+-#define MECR_CIT	(1 << 1)	/* Card Is There: 0 -> no card, 1 -> card inserted */
+-
+-#define MDREFR_K0DB4	(1 << 29)	/* SDCLK0 Divide by 4 Control/Status */
+-#define MDREFR_K2FREE	(1 << 25)	/* SDRAM Free-Running Control */
+-#define MDREFR_K1FREE	(1 << 24)	/* SDRAM Free-Running Control */
+-#define MDREFR_K0FREE	(1 << 23)	/* SDRAM Free-Running Control */
+-#define MDREFR_SLFRSH	(1 << 22)	/* SDRAM Self-Refresh Control/Status */
+-#define MDREFR_APD	(1 << 20)	/* SDRAM/SSRAM Auto-Power-Down Enable */
+-#define MDREFR_K2DB2	(1 << 19)	/* SDCLK2 Divide by 2 Control/Status */
+-#define MDREFR_K2RUN	(1 << 18)	/* SDCLK2 Run Control/Status */
+-#define MDREFR_K1DB2	(1 << 17)	/* SDCLK1 Divide by 2 Control/Status */
+-#define MDREFR_K1RUN	(1 << 16)	/* SDCLK1 Run Control/Status */
+-#define MDREFR_E1PIN	(1 << 15)	/* SDCKE1 Level Control/Status */
+-#define MDREFR_K0DB2	(1 << 14)	/* SDCLK0 Divide by 2 Control/Status */
+-#define MDREFR_K0RUN	(1 << 13)	/* SDCLK0 Run Control/Status */
+-#define MDREFR_E0PIN	(1 << 12)	/* SDCKE0 Level Control/Status */
+-
+-
+ #ifdef CONFIG_PXA27x
+ 
+-#define ARB_CNTRL	__REG(0x48000048)  /* Arbiter Control Register */
+-
+-#define ARB_DMA_SLV_PARK	(1<<31)	   /* Be parked with DMA slave when idle */
+-#define ARB_CI_PARK		(1<<30)	   /* Be parked with Camera Interface when idle */
+-#define ARB_EX_MEM_PARK 	(1<<29)	   /* Be parked with external MEMC when idle */
+-#define ARB_INT_MEM_PARK	(1<<28)	   /* Be parked with internal MEMC when idle */
+-#define ARB_USB_PARK		(1<<27)	   /* Be parked with USB when idle */
+-#define ARB_LCD_PARK		(1<<26)	   /* Be parked with LCD when idle */
+-#define ARB_DMA_PARK		(1<<25)	   /* Be parked with DMA when idle */
+-#define ARB_CORE_PARK		(1<<24)	   /* Be parked with core when idle */
+-#define ARB_LOCK_FLAG		(1<<23)	   /* Only Locking masters gain access to the bus */
+-
+ /*
+  * Keypad
+  */
+@@ -2135,74 +1906,6 @@
+ #define KPAS_SO         (0x1 << 31)
+ #define KPASMKPx_SO     (0x1 << 31)
  
--	o2cb_subsys.kobj.ktype = &o2cb_subsys_type;
--	ret = subsystem_register(&o2cb_subsys);
-+	o2cb_kset = kset_create_and_add("o2cb", NULL, fs_kobj);
-+	if (!o2cb_kset)
-+		return -ENOMEM;
-+
-+	ret = sysfs_create_group(&o2cb_kset->kobj, &o2cb_attr_group);
- 	if (ret)
--		return ret;
-+		goto error;
+-/*
+- * 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 */
+-
+ /* Camera Interface */
+ #define CICR0		__REG(0x50000000)
+ #define CICR1		__REG(0x50000004)
+@@ -2350,6 +2053,77 @@
  
--	ret = mlog_sys_init(&o2cb_subsys);
-+	ret = mlog_sys_init(o2cb_kset);
- 	if (ret)
--		subsystem_unregister(&o2cb_subsys);
-+		goto error;
-+	return 0;
-+error:
-+	kset_unregister(o2cb_kset);
- 	return ret;
- }
-diff --git a/fs/ocfs2/cluster/tcp.h b/fs/ocfs2/cluster/tcp.h
-index da880fc..f36f66a 100644
---- a/fs/ocfs2/cluster/tcp.h
-+++ b/fs/ocfs2/cluster/tcp.h
-@@ -60,8 +60,8 @@ typedef void (o2net_post_msg_handler_func)(int status, void *data,
- /* same as hb delay, we're waiting for another node to recognize our hb */
- #define O2NET_RECONNECT_DELAY_MS_DEFAULT	2000
+ #endif
  
--#define O2NET_KEEPALIVE_DELAY_MS_DEFAULT	5000
--#define O2NET_IDLE_TIMEOUT_MS_DEFAULT		10000
-+#define O2NET_KEEPALIVE_DELAY_MS_DEFAULT	2000
-+#define O2NET_IDLE_TIMEOUT_MS_DEFAULT		30000
++#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/include/asm-arm/arch-pxa/pxa2xx-regs.h b/include/asm-arm/arch-pxa/pxa2xx-regs.h
+new file mode 100644
+index 0000000..9553b54
+--- /dev/null
++++ b/include/asm-arm/arch-pxa/pxa2xx-regs.h
+@@ -0,0 +1,84 @@
++/*
++ *  linux/include/asm-arm/arch-pxa/pxa2xx-regs.h
++ *
++ *  Taken from pxa-regs.h by Russell King
++ *
++ *  Author:	Nicolas Pitre
++ *  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 __PXA2XX_REGS_H
++#define __PXA2XX_REGS_H
++
++/*
++ * Memory controller
++ */
++
++#define MDCNFG		__REG(0x48000000)  /* SDRAM Configuration Register 0 */
++#define MDREFR		__REG(0x48000004)  /* SDRAM Refresh Control Register */
++#define MSC0		__REG(0x48000008)  /* Static Memory Control Register 0 */
++#define MSC1		__REG(0x4800000C)  /* Static Memory Control Register 1 */
++#define MSC2		__REG(0x48000010)  /* Static Memory Control Register 2 */
++#define MECR		__REG(0x48000014)  /* Expansion Memory (PCMCIA/Compact Flash) Bus Configuration */
++#define SXLCR		__REG(0x48000018)  /* LCR value to be written to SDRAM-Timing Synchronous Flash */
++#define SXCNFG		__REG(0x4800001C)  /* Synchronous Static Memory Control Register */
++#define SXMRS		__REG(0x48000024)  /* MRS value to be written to Synchronous Flash or SMROM */
++#define MCMEM0		__REG(0x48000028)  /* Card interface Common Memory Space Socket 0 Timing */
++#define MCMEM1		__REG(0x4800002C)  /* Card interface Common Memory Space Socket 1 Timing */
++#define MCATT0		__REG(0x48000030)  /* Card interface Attribute Space Socket 0 Timing Configuration */
++#define MCATT1		__REG(0x48000034)  /* Card interface Attribute Space Socket 1 Timing Configuration */
++#define MCIO0		__REG(0x48000038)  /* Card interface I/O Space Socket 0 Timing Configuration */
++#define MCIO1		__REG(0x4800003C)  /* Card interface I/O Space Socket 1 Timing Configuration */
++#define MDMRS		__REG(0x48000040)  /* MRS value to be written to SDRAM */
++#define BOOT_DEF	__REG(0x48000044)  /* Read-Only Boot-Time Register. Contains BOOT_SEL and PKG_SEL */
++
++/*
++ * More handy macros for PCMCIA
++ *
++ * Arg is socket number
++ */
++#define MCMEM(s)	__REG2(0x48000028, (s)<<2 )  /* Card interface Common Memory Space Socket s Timing */
++#define MCATT(s)	__REG2(0x48000030, (s)<<2 )  /* Card interface Attribute Space Socket s Timing Configuration */
++#define MCIO(s)		__REG2(0x48000038, (s)<<2 )  /* Card interface I/O Space Socket s Timing Configuration */
++
++/* MECR register defines */
++#define MECR_NOS	(1 << 0)	/* Number Of Sockets: 0 -> 1 sock, 1 -> 2 sock */
++#define MECR_CIT	(1 << 1)	/* Card Is There: 0 -> no card, 1 -> card inserted */
++
++#define MDREFR_K0DB4	(1 << 29)	/* SDCLK0 Divide by 4 Control/Status */
++#define MDREFR_K2FREE	(1 << 25)	/* SDRAM Free-Running Control */
++#define MDREFR_K1FREE	(1 << 24)	/* SDRAM Free-Running Control */
++#define MDREFR_K0FREE	(1 << 23)	/* SDRAM Free-Running Control */
++#define MDREFR_SLFRSH	(1 << 22)	/* SDRAM Self-Refresh Control/Status */
++#define MDREFR_APD	(1 << 20)	/* SDRAM/SSRAM Auto-Power-Down Enable */
++#define MDREFR_K2DB2	(1 << 19)	/* SDCLK2 Divide by 2 Control/Status */
++#define MDREFR_K2RUN	(1 << 18)	/* SDCLK2 Run Control/Status */
++#define MDREFR_K1DB2	(1 << 17)	/* SDCLK1 Divide by 2 Control/Status */
++#define MDREFR_K1RUN	(1 << 16)	/* SDCLK1 Run Control/Status */
++#define MDREFR_E1PIN	(1 << 15)	/* SDCKE1 Level Control/Status */
++#define MDREFR_K0DB2	(1 << 14)	/* SDCLK0 Divide by 2 Control/Status */
++#define MDREFR_K0RUN	(1 << 13)	/* SDCLK0 Run Control/Status */
++#define MDREFR_E0PIN	(1 << 12)	/* SDCKE0 Level Control/Status */
++
++
++#ifdef CONFIG_PXA27x
++
++#define ARB_CNTRL	__REG(0x48000048)  /* Arbiter Control Register */
++
++#define ARB_DMA_SLV_PARK	(1<<31)	   /* Be parked with DMA slave when idle */
++#define ARB_CI_PARK		(1<<30)	   /* Be parked with Camera Interface when idle */
++#define ARB_EX_MEM_PARK 	(1<<29)	   /* Be parked with external MEMC when idle */
++#define ARB_INT_MEM_PARK	(1<<28)	   /* Be parked with internal MEMC when idle */
++#define ARB_USB_PARK		(1<<27)	   /* Be parked with USB when idle */
++#define ARB_LCD_PARK		(1<<26)	   /* Be parked with LCD when idle */
++#define ARB_DMA_PARK		(1<<25)	   /* Be parked with DMA when idle */
++#define ARB_CORE_PARK		(1<<24)	   /* Be parked with core when idle */
++#define ARB_LOCK_FLAG		(1<<23)	   /* Only Locking masters gain access to the bus */
++
++#endif
++
++#endif
+diff --git a/include/asm-arm/arch-pxa/pxa2xx_spi.h b/include/asm-arm/arch-pxa/pxa2xx_spi.h
+index acc7ec7..3459fb2 100644
+--- a/include/asm-arm/arch-pxa/pxa2xx_spi.h
++++ b/include/asm-arm/arch-pxa/pxa2xx_spi.h
+@@ -22,32 +22,8 @@
+ #define PXA2XX_CS_ASSERT (0x01)
+ #define PXA2XX_CS_DEASSERT (0x02)
+ 
+-#if defined(CONFIG_PXA25x)
+-#define CLOCK_SPEED_HZ 3686400
+-#define SSP1_SerClkDiv(x) (((CLOCK_SPEED_HZ/2/(x+1))<<8)&0x0000ff00)
+-#define SSP2_SerClkDiv(x) (((CLOCK_SPEED_HZ/(x+1))<<8)&0x000fff00)
+-#define SSP3_SerClkDiv(x) (((CLOCK_SPEED_HZ/(x+1))<<8)&0x000fff00)
+-#elif defined(CONFIG_PXA27x)
+-#define CLOCK_SPEED_HZ 13000000
+-#define SSP1_SerClkDiv(x) (((CLOCK_SPEED_HZ/(x+1))<<8)&0x000fff00)
+-#define SSP2_SerClkDiv(x) (((CLOCK_SPEED_HZ/(x+1))<<8)&0x000fff00)
+-#define SSP3_SerClkDiv(x) (((CLOCK_SPEED_HZ/(x+1))<<8)&0x000fff00)
+-#endif
+-
+-#define SSP1_VIRT ((void *)(io_p2v(__PREG(SSCR0_P(1)))))
+-#define SSP2_VIRT ((void *)(io_p2v(__PREG(SSCR0_P(2)))))
+-#define SSP3_VIRT ((void *)(io_p2v(__PREG(SSCR0_P(3)))))
+-
+-enum pxa_ssp_type {
+-	SSP_UNDEFINED = 0,
+-	PXA25x_SSP,  /* pxa 210, 250, 255, 26x */
+-	PXA25x_NSSP, /* pxa 255, 26x (including ASSP) */
+-	PXA27x_SSP,
+-};
+-
+ /* device.platform_data for SSP controller devices */
+ struct pxa2xx_spi_master {
+-	enum pxa_ssp_type ssp_type;
+ 	u32 clock_enable;
+ 	u16 num_chipselect;
+ 	u8 enable_dma;
+diff --git a/include/asm-arm/arch-pxa/pxa3xx-regs.h b/include/asm-arm/arch-pxa/pxa3xx-regs.h
+index 3900a0c..66d5411 100644
+--- a/include/asm-arm/arch-pxa/pxa3xx-regs.h
++++ b/include/asm-arm/arch-pxa/pxa3xx-regs.h
+@@ -14,6 +14,92 @@
+ #define __ASM_ARCH_PXA3XX_REGS_H
+ 
+ /*
++ * Slave Power Managment Unit
++ */
++#define ASCR		__REG(0x40f40000)	/* Application Subsystem Power Status/Configuration */
++#define ARSR		__REG(0x40f40004)	/* Application Subsystem Reset Status */
++#define AD3ER		__REG(0x40f40008)	/* Application Subsystem Wake-Up from D3 Enable */
++#define AD3SR		__REG(0x40f4000c)	/* Application Subsystem Wake-Up from D3 Status */
++#define AD2D0ER		__REG(0x40f40010)	/* Application Subsystem Wake-Up from D2 to D0 Enable */
++#define AD2D0SR		__REG(0x40f40014)	/* Application Subsystem Wake-Up from D2 to D0 Status */
++#define AD2D1ER		__REG(0x40f40018)	/* Application Subsystem Wake-Up from D2 to D1 Enable */
++#define AD2D1SR		__REG(0x40f4001c)	/* Application Subsystem Wake-Up from D2 to D1 Status */
++#define AD1D0ER		__REG(0x40f40020)	/* Application Subsystem Wake-Up from D1 to D0 Enable */
++#define AD1D0SR		__REG(0x40f40024)	/* Application Subsystem Wake-Up from D1 to D0 Status */
++#define AGENP		__REG(0x40f4002c)	/* Application Subsystem General Purpose */
++#define AD3R		__REG(0x40f40030)	/* Application Subsystem D3 Configuration */
++#define AD2R		__REG(0x40f40034)	/* Application Subsystem D2 Configuration */
++#define AD1R		__REG(0x40f40038)	/* Application Subsystem D1 Configuration */
++
++/*
++ * Application Subsystem Configuration bits.
++ */
++#define ASCR_RDH		(1 << 31)
++#define ASCR_D1S		(1 << 2)
++#define ASCR_D2S		(1 << 1)
++#define ASCR_D3S		(1 << 0)
++
++/*
++ * Application Reset Status bits.
++ */
++#define ARSR_GPR		(1 << 3)
++#define ARSR_LPMR		(1 << 2)
++#define ARSR_WDT		(1 << 1)
++#define ARSR_HWR		(1 << 0)
++
++/*
++ * Application Subsystem Wake-Up bits.
++ */
++#define ADXER_WRTC		(1 << 31)	/* RTC */
++#define ADXER_WOST		(1 << 30)	/* OS Timer */
++#define ADXER_WTSI		(1 << 29)	/* Touchscreen */
++#define ADXER_WUSBH		(1 << 28)	/* USB host */
++#define ADXER_WUSB2		(1 << 26)	/* USB client 2.0 */
++#define ADXER_WMSL0		(1 << 24)	/* MSL port 0*/
++#define ADXER_WDMUX3		(1 << 23)	/* USB EDMUX3 */
++#define ADXER_WDMUX2		(1 << 22)	/* USB EDMUX2 */
++#define ADXER_WKP		(1 << 21)	/* Keypad */
++#define ADXER_WUSIM1		(1 << 20)	/* USIM Port 1 */
++#define ADXER_WUSIM0		(1 << 19)	/* USIM Port 0 */
++#define ADXER_WOTG		(1 << 16)	/* USBOTG input */
++#define ADXER_MFP_WFLASH	(1 << 15)	/* MFP: Data flash busy */
++#define ADXER_MFP_GEN12		(1 << 14)	/* MFP: MMC3/GPIO/OST inputs */
++#define ADXER_MFP_WMMC2		(1 << 13)	/* MFP: MMC2 */
++#define ADXER_MFP_WMMC1		(1 << 12)	/* MFP: MMC1 */
++#define ADXER_MFP_WI2C		(1 << 11)	/* MFP: I2C */
++#define ADXER_MFP_WSSP4		(1 << 10)	/* MFP: SSP4 */
++#define ADXER_MFP_WSSP3		(1 << 9)	/* MFP: SSP3 */
++#define ADXER_MFP_WMAXTRIX	(1 << 8)	/* MFP: matrix keypad */
++#define ADXER_MFP_WUART3	(1 << 7)	/* MFP: UART3 */
++#define ADXER_MFP_WUART2	(1 << 6)	/* MFP: UART2 */
++#define ADXER_MFP_WUART1	(1 << 5)	/* MFP: UART1 */
++#define ADXER_MFP_WSSP2		(1 << 4)	/* MFP: SSP2 */
++#define ADXER_MFP_WSSP1		(1 << 3)	/* MFP: SSP1 */
++#define ADXER_MFP_WAC97		(1 << 2)	/* MFP: AC97 */
++#define ADXER_WEXTWAKE1		(1 << 1)	/* External Wake 1 */
++#define ADXER_WEXTWAKE0		(1 << 0)	/* External Wake 0 */
++
++/*
++ * AD3R/AD2R/AD1R bits.  R2-R5 are only defined for PXA320.
++ */
++#define ADXR_L2			(1 << 8)
++#define ADXR_R5			(1 << 5)
++#define ADXR_R4			(1 << 4)
++#define ADXR_R3			(1 << 3)
++#define ADXR_R2			(1 << 2)
++#define ADXR_R1			(1 << 1)
++#define ADXR_R0			(1 << 0)
++
++/*
++ * Values for PWRMODE CP15 register
++ */
++#define PXA3xx_PM_S3D4C4	0x07	/* aka deep sleep */
++#define PXA3xx_PM_S2D3C4	0x06	/* aka sleep */
++#define PXA3xx_PM_S0D2C2	0x03	/* aka standby */
++#define PXA3xx_PM_S0D1C2	0x02	/* aka LCD refresh */
++#define PXA3xx_PM_S0D0C1	0x01
++
++/*
+  * Application Subsystem Clock
+  */
+ #define ACCR		__REG(0x41340000)	/* Application Subsystem Clock Configuration Register */
+diff --git a/include/asm-arm/arch-pxa/regs-ssp.h b/include/asm-arm/arch-pxa/regs-ssp.h
+new file mode 100644
+index 0000000..991cb68
+--- /dev/null
++++ b/include/asm-arm/arch-pxa/regs-ssp.h
+@@ -0,0 +1,112 @@
++#ifndef __ASM_ARCH_REGS_SSP_H
++#define __ASM_ARCH_REGS_SSP_H
++
++/*
++ * SSP Serial Port Registers
++ * PXA250, PXA255, PXA26x and PXA27x SSP controllers are all slightly different.
++ * PXA255, PXA26x and PXA27x have extra ports, registers and bits.
++ */
++
++#define SSCR0		(0x00)  /* SSP Control Register 0 */
++#define SSCR1		(0x04)  /* SSP Control Register 1 */
++#define SSSR		(0x08)  /* SSP Status Register */
++#define SSITR		(0x0C)  /* SSP Interrupt Test Register */
++#define SSDR		(0x10)  /* SSP Data Write/Data Read Register */
++
++#define SSTO		(0x28)  /* SSP Time Out Register */
++#define SSPSP		(0x2C)  /* SSP Programmable Serial Protocol */
++#define SSTSA		(0x30)  /* SSP Tx Timeslot Active */
++#define SSRSA		(0x34)  /* SSP Rx Timeslot Active */
++#define SSTSS		(0x38)  /* SSP Timeslot Status */
++#define SSACD		(0x3C)  /* SSP Audio Clock Divider */
++
++/* Common PXA2xx bits first */
++#define SSCR0_DSS	(0x0000000f)	/* Data Size Select (mask) */
++#define SSCR0_DataSize(x)  ((x) - 1)	/* Data Size Select [4..16] */
++#define SSCR0_FRF	(0x00000030)	/* FRame Format (mask) */
++#define SSCR0_Motorola	(0x0 << 4)	/* Motorola's Serial Peripheral Interface (SPI) */
++#define SSCR0_TI	(0x1 << 4)	/* Texas Instruments' Synchronous Serial Protocol (SSP) */
++#define SSCR0_National	(0x2 << 4)	/* National Microwire */
++#define SSCR0_ECS	(1 << 6)	/* External clock select */
++#define SSCR0_SSE	(1 << 7)	/* Synchronous Serial Port Enable */
++#if defined(CONFIG_PXA25x)
++#define SSCR0_SCR	(0x0000ff00)	/* Serial Clock Rate (mask) */
++#define SSCR0_SerClkDiv(x) ((((x) - 2)/2) << 8) /* Divisor [2..512] */
++#elif defined(CONFIG_PXA27x)
++#define SSCR0_SCR	(0x000fff00)	/* Serial Clock Rate (mask) */
++#define SSCR0_SerClkDiv(x) (((x) - 1) << 8) /* Divisor [1..4096] */
++#define SSCR0_EDSS	(1 << 20)	/* Extended data size select */
++#define SSCR0_NCS	(1 << 21)	/* Network clock select */
++#define SSCR0_RIM	(1 << 22)	/* Receive FIFO overrrun interrupt mask */
++#define SSCR0_TUM	(1 << 23)	/* Transmit FIFO underrun interrupt mask */
++#define SSCR0_FRDC	(0x07000000)	/* Frame rate divider control (mask) */
++#define SSCR0_SlotsPerFrm(x) (((x) - 1) << 24)	/* Time slots per frame [1..8] */
++#define SSCR0_ADC	(1 << 30)	/* Audio clock select */
++#define SSCR0_MOD	(1 << 31)	/* Mode (normal or network) */
++#endif
++
++#define SSCR1_RIE	(1 << 0)	/* Receive FIFO Interrupt Enable */
++#define SSCR1_TIE	(1 << 1)	/* Transmit FIFO Interrupt Enable */
++#define SSCR1_LBM	(1 << 2)	/* Loop-Back Mode */
++#define SSCR1_SPO	(1 << 3)	/* Motorola SPI SSPSCLK polarity setting */
++#define SSCR1_SPH	(1 << 4)	/* Motorola SPI SSPSCLK phase setting */
++#define SSCR1_MWDS	(1 << 5)	/* Microwire Transmit Data Size */
++#define SSCR1_TFT	(0x000003c0)	/* Transmit FIFO Threshold (mask) */
++#define SSCR1_TxTresh(x) (((x) - 1) << 6) /* level [1..16] */
++#define SSCR1_RFT	(0x00003c00)	/* Receive FIFO Threshold (mask) */
++#define SSCR1_RxTresh(x) (((x) - 1) << 10) /* level [1..16] */
++
++#define SSSR_TNF	(1 << 2)	/* Transmit FIFO Not Full */
++#define SSSR_RNE	(1 << 3)	/* Receive FIFO Not Empty */
++#define SSSR_BSY	(1 << 4)	/* SSP Busy */
++#define SSSR_TFS	(1 << 5)	/* Transmit FIFO Service Request */
++#define SSSR_RFS	(1 << 6)	/* Receive FIFO Service Request */
++#define SSSR_ROR	(1 << 7)	/* Receive FIFO Overrun */
++
++#define SSCR0_TIM		(1 << 23)	/* Transmit FIFO Under Run Interrupt Mask */
++#define SSCR0_RIM		(1 << 22)	/* Receive FIFO Over Run interrupt Mask */
++#define SSCR0_NCS		(1 << 21)	/* Network Clock Select */
++#define SSCR0_EDSS		(1 << 20)	/* Extended Data Size Select */
++
++/* extra bits in PXA255, PXA26x and PXA27x SSP ports */
++#define SSCR0_TISSP		(1 << 4)	/* TI Sync Serial Protocol */
++#define SSCR0_PSP		(3 << 4)	/* PSP - Programmable Serial Protocol */
++#define SSCR1_TTELP		(1 << 31)	/* TXD Tristate Enable Last Phase */
++#define SSCR1_TTE		(1 << 30)	/* TXD Tristate Enable */
++#define SSCR1_EBCEI		(1 << 29)	/* Enable Bit Count Error interrupt */
++#define SSCR1_SCFR		(1 << 28)	/* Slave Clock free Running */
++#define SSCR1_ECRA		(1 << 27)	/* Enable Clock Request A */
++#define SSCR1_ECRB		(1 << 26)	/* Enable Clock request B */
++#define SSCR1_SCLKDIR		(1 << 25)	/* Serial Bit Rate Clock Direction */
++#define SSCR1_SFRMDIR		(1 << 24)	/* Frame Direction */
++#define SSCR1_RWOT		(1 << 23)	/* Receive Without Transmit */
++#define SSCR1_TRAIL		(1 << 22)	/* Trailing Byte */
++#define SSCR1_TSRE		(1 << 21)	/* Transmit Service Request Enable */
++#define SSCR1_RSRE		(1 << 20)	/* Receive Service Request Enable */
++#define SSCR1_TINTE		(1 << 19)	/* Receiver Time-out Interrupt enable */
++#define SSCR1_PINTE		(1 << 18)	/* Peripheral Trailing Byte Interupt Enable */
++#define SSCR1_STRF		(1 << 15)	/* Select FIFO or EFWR */
++#define SSCR1_EFWR		(1 << 14)	/* Enable FIFO Write/Read */
++
++#define SSSR_BCE		(1 << 23)	/* Bit Count Error */
++#define SSSR_CSS		(1 << 22)	/* Clock Synchronisation Status */
++#define SSSR_TUR		(1 << 21)	/* Transmit FIFO Under Run */
++#define SSSR_EOC		(1 << 20)	/* End Of Chain */
++#define SSSR_TINT		(1 << 19)	/* Receiver Time-out Interrupt */
++#define SSSR_PINT		(1 << 18)	/* Peripheral Trailing Byte Interrupt */
++
++#define SSPSP_FSRT		(1 << 25)	/* Frame Sync Relative Timing */
++#define SSPSP_DMYSTOP(x)	((x) << 23)	/* Dummy Stop */
++#define SSPSP_SFRMWDTH(x)	((x) << 16)	/* Serial Frame Width */
++#define SSPSP_SFRMDLY(x)	((x) << 9)	/* Serial Frame Delay */
++#define SSPSP_DMYSTRT(x)	((x) << 7)	/* Dummy Start */
++#define SSPSP_STRTDLY(x)	((x) << 4)	/* Start Delay */
++#define SSPSP_ETDS		(1 << 3)	/* End of Transfer data State */
++#define SSPSP_SFRMP		(1 << 2)	/* Serial Frame Polarity */
++#define SSPSP_SCMODE(x)		((x) << 0)	/* Serial Bit Rate Clock Mode */
++
++#define SSACD_SCDB		(1 << 3)	/* SSPSYSCLK Divider Bypass */
++#define SSACD_ACPS(x)		((x) << 4)	/* Audio clock PLL select */
++#define SSACD_ACDS(x)		((x) << 0)	/* Audio clock divider select */
++
++#endif /* __ASM_ARCH_REGS_SSP_H */
+diff --git a/include/asm-arm/arch-pxa/sharpsl.h b/include/asm-arm/arch-pxa/sharpsl.h
+index 2b0fe77..3b1d4a7 100644
+--- a/include/asm-arm/arch-pxa/sharpsl.h
++++ b/include/asm-arm/arch-pxa/sharpsl.h
+@@ -16,7 +16,7 @@ int corgi_ssp_max1111_get(unsigned long data);
+  */
+ 
+ struct corgits_machinfo {
+-	unsigned long (*get_hsync_len)(void);
++	unsigned long (*get_hsync_invperiod)(void);
+ 	void (*put_hsync)(void);
+ 	void (*wait_hsync)(void);
+ };
+diff --git a/include/asm-arm/arch-pxa/spitz.h b/include/asm-arm/arch-pxa/spitz.h
+index 4953dd3..bd14365 100644
+--- a/include/asm-arm/arch-pxa/spitz.h
++++ b/include/asm-arm/arch-pxa/spitz.h
+@@ -156,5 +156,3 @@ 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;
+-
+-extern void spitz_lcd_power(int on, struct fb_var_screeninfo *var);
+diff --git a/include/asm-arm/arch-pxa/ssp.h b/include/asm-arm/arch-pxa/ssp.h
+index ea20055..a012882 100644
+--- a/include/asm-arm/arch-pxa/ssp.h
++++ b/include/asm-arm/arch-pxa/ssp.h
+@@ -13,10 +13,37 @@
+  *       PXA255     SSP, NSSP
+  *       PXA26x     SSP, NSSP, ASSP
+  *       PXA27x     SSP1, SSP2, SSP3
++ *       PXA3xx     SSP1, SSP2, SSP3, SSP4
+  */
+ 
+-#ifndef SSP_H
+-#define SSP_H
++#ifndef __ASM_ARCH_SSP_H
++#define __ASM_ARCH_SSP_H
++
++#include <linux/list.h>
++
++enum pxa_ssp_type {
++	SSP_UNDEFINED = 0,
++	PXA25x_SSP,  /* pxa 210, 250, 255, 26x */
++	PXA25x_NSSP, /* pxa 255, 26x (including ASSP) */
++	PXA27x_SSP,
++};
++
++struct ssp_device {
++	struct platform_device *pdev;
++	struct list_head	node;
++
++	struct clk	*clk;
++	void __iomem	*mmio_base;
++	unsigned long	phys_base;
++
++	const char	*label;
++	int		port_id;
++	int		type;
++	int		use_count;
++	int		irq;
++	int		drcmr_rx;
++	int		drcmr_tx;
++};
  
+ /*
+  * SSP initialisation flags
+@@ -31,6 +58,7 @@ struct ssp_state {
+ };
+ 
+ struct ssp_dev {
++	struct ssp_device *ssp;
+ 	u32 port;
+ 	u32 mode;
+ 	u32 flags;
+@@ -50,4 +78,6 @@ int ssp_init(struct ssp_dev *dev, u32 port, u32 init_flags);
+ int ssp_config(struct ssp_dev *dev, u32 mode, u32 flags, u32 psp_flags, u32 speed);
+ void ssp_exit(struct ssp_dev *dev);
  
- /* TODO: figure this out.... */
-diff --git a/fs/ocfs2/cluster/tcp_internal.h b/fs/ocfs2/cluster/tcp_internal.h
-index 9606111..b2e832a 100644
---- a/fs/ocfs2/cluster/tcp_internal.h
-+++ b/fs/ocfs2/cluster/tcp_internal.h
-@@ -38,6 +38,12 @@
-  * locking semantics of the file system using the protocol.  It should 
-  * be somewhere else, I'm sure, but right now it isn't.
-  *
-+ * New in version 10:
-+ * 	- Meta/data locks combined
-+ *
-+ * New in version 9:
-+ * 	- All votes removed
-+ *
-  * New in version 8:
-  * 	- Replace delete inode votes with a cluster lock
-  *
-@@ -60,7 +66,7 @@
-  * 	- full 64 bit i_size in the metadata lock lvbs
-  * 	- introduction of "rw" lock and pushing meta/data locking down
+-#endif
++struct ssp_device *ssp_request(int port, const char *label);
++void ssp_free(struct ssp_device *);
++#endif /* __ASM_ARCH_SSP_H */
+diff --git a/include/asm-arm/arch-pxa/uncompress.h b/include/asm-arm/arch-pxa/uncompress.h
+index 178aa2e..dadf4c2 100644
+--- a/include/asm-arm/arch-pxa/uncompress.h
++++ b/include/asm-arm/arch-pxa/uncompress.h
+@@ -9,19 +9,21 @@
+  * published by the Free Software Foundation.
   */
--#define O2NET_PROTOCOL_VERSION 8ULL
-+#define O2NET_PROTOCOL_VERSION 10ULL
- struct o2net_handshake {
- 	__be64	protocol_version;
- 	__be64	connector_id;
-diff --git a/fs/ocfs2/cluster/ver.c b/fs/ocfs2/cluster/ver.c
-index 7286c48..a56eee6 100644
---- a/fs/ocfs2/cluster/ver.c
-+++ b/fs/ocfs2/cluster/ver.c
-@@ -28,7 +28,7 @@
  
- #include "ver.h"
+-#define FFUART		((volatile unsigned long *)0x40100000)
+-#define BTUART		((volatile unsigned long *)0x40200000)
+-#define STUART		((volatile unsigned long *)0x40700000)
+-#define HWUART		((volatile unsigned long *)0x41600000)
++#include <linux/serial_reg.h>
++#include <asm/arch/pxa-regs.h>
++
++#define __REG(x)	((volatile unsigned long *)x)
  
--#define CLUSTER_BUILD_VERSION "1.3.3"
-+#define CLUSTER_BUILD_VERSION "1.5.0"
+ #define UART		FFUART
  
- #define VERSION_STR "OCFS2 Node Manager " CLUSTER_BUILD_VERSION
  
-diff --git a/fs/ocfs2/dcache.c b/fs/ocfs2/dcache.c
-index 9923278..b1cc7c3 100644
---- a/fs/ocfs2/dcache.c
-+++ b/fs/ocfs2/dcache.c
-@@ -128,9 +128,9 @@ static int ocfs2_match_dentry(struct dentry *dentry,
+ static inline void putc(char c)
+ {
+-	while (!(UART[5] & 0x20))
++	if (!(UART[UART_IER] & IER_UUE))
++		return;
++	while (!(UART[UART_LSR] & LSR_TDRQ))
+ 		barrier();
+-	UART[0] = c;
++	UART[UART_TX] = c;
+ }
+ 
  /*
-  * Walk the inode alias list, and find a dentry which has a given
-  * parent. ocfs2_dentry_attach_lock() wants to find _any_ alias as it
-- * is looking for a dentry_lock reference. The vote thread is looking
-- * to unhash aliases, so we allow it to skip any that already have
-- * that property.
-+ * is looking for a dentry_lock reference. The downconvert thread is
-+ * looking to unhash aliases, so we allow it to skip any that already
-+ * have that property.
+diff --git a/include/asm-arm/arch-pxa/zylonite.h b/include/asm-arm/arch-pxa/zylonite.h
+index f58b591..5f717d6 100644
+--- a/include/asm-arm/arch-pxa/zylonite.h
++++ b/include/asm-arm/arch-pxa/zylonite.h
+@@ -3,9 +3,18 @@
+ 
+ #define ZYLONITE_ETH_PHYS	0x14000000
+ 
++#define EXT_GPIO(x)		(128 + (x))
++
+ /* the following variables are processor specific and initialized
+  * by the corresponding zylonite_pxa3xx_init()
   */
- struct dentry *ocfs2_find_local_alias(struct inode *inode,
- 				      u64 parent_blkno,
-@@ -266,7 +266,7 @@ int ocfs2_dentry_attach_lock(struct dentry *dentry,
- 	dl->dl_count = 0;
- 	/*
- 	 * Does this have to happen below, for all attaches, in case
--	 * the struct inode gets blown away by votes?
-+	 * the struct inode gets blown away by the downconvert thread?
- 	 */
- 	dl->dl_inode = igrab(inode);
- 	dl->dl_parent_blkno = parent_blkno;
-diff --git a/fs/ocfs2/dir.c b/fs/ocfs2/dir.c
-index 63b28fd..6b0107f 100644
---- a/fs/ocfs2/dir.c
-+++ b/fs/ocfs2/dir.c
-@@ -846,14 +846,14 @@ int ocfs2_readdir(struct file * filp, void * dirent, filldir_t filldir)
- 	mlog_entry("dirino=%llu\n",
- 		   (unsigned long long)OCFS2_I(inode)->ip_blkno);
++struct platform_mmc_slot {
++	int gpio_cd;
++	int gpio_wp;
++};
++
++extern struct platform_mmc_slot zylonite_mmc_slot[];
++
+ extern int gpio_backlight;
+ extern int gpio_eth_irq;
  
--	error = ocfs2_meta_lock_atime(inode, filp->f_vfsmnt, &lock_level);
-+	error = ocfs2_inode_lock_atime(inode, filp->f_vfsmnt, &lock_level);
- 	if (lock_level && error >= 0) {
- 		/* We release EX lock which used to update atime
- 		 * and get PR lock again to reduce contention
- 		 * on commonly accessed directories. */
--		ocfs2_meta_unlock(inode, 1);
-+		ocfs2_inode_unlock(inode, 1);
- 		lock_level = 0;
--		error = ocfs2_meta_lock(inode, NULL, 0);
-+		error = ocfs2_inode_lock(inode, NULL, 0);
- 	}
- 	if (error < 0) {
- 		if (error != -ENOENT)
-@@ -865,7 +865,7 @@ int ocfs2_readdir(struct file * filp, void * dirent, filldir_t filldir)
- 	error = ocfs2_dir_foreach_blk(inode, &filp->f_version, &filp->f_pos,
- 				      dirent, filldir, NULL);
+diff --git a/include/asm-arm/arch-s3c2410/debug-macro.S b/include/asm-arm/arch-s3c2410/debug-macro.S
+index 9c8cd9a..89076c3 100644
+--- a/include/asm-arm/arch-s3c2410/debug-macro.S
++++ b/include/asm-arm/arch-s3c2410/debug-macro.S
+@@ -92,11 +92,9 @@
+ #if defined(CONFIG_CPU_LLSERIAL_S3C2410_ONLY)
+ #define fifo_full  fifo_full_s3c2410
+ #define fifo_level fifo_level_s3c2410
+-#warning 2410only
+ #elif !defined(CONFIG_CPU_LLSERIAL_S3C2440_ONLY)
+ #define fifo_full  fifo_full_s3c24xx
+ #define fifo_level fifo_level_s3c24xx
+-#warning generic
+ #endif
  
--	ocfs2_meta_unlock(inode, lock_level);
-+	ocfs2_inode_unlock(inode, lock_level);
+ /* include the reset of the code which will do the work */
+diff --git a/include/asm-arm/arch-s3c2410/dma.h b/include/asm-arm/arch-s3c2410/dma.h
+index c6e8d8f..4f291d9 100644
+--- a/include/asm-arm/arch-s3c2410/dma.h
++++ b/include/asm-arm/arch-s3c2410/dma.h
+@@ -214,6 +214,7 @@ struct s3c2410_dma_chan {
+ 	unsigned long		 dev_addr;
+ 	unsigned long		 load_timeout;
+ 	unsigned int		 flags;		/* channel flags */
++	unsigned int		 hw_cfg;	/* last hw config */
+ 
+ 	struct s3c24xx_dma_map	*map;		/* channel hw maps */
+ 
+diff --git a/include/asm-arm/arch-s3c2410/hardware.h b/include/asm-arm/arch-s3c2410/hardware.h
+index 6dadf58..29592c3 100644
+--- a/include/asm-arm/arch-s3c2410/hardware.h
++++ b/include/asm-arm/arch-s3c2410/hardware.h
+@@ -50,6 +50,17 @@ extern unsigned int s3c2410_gpio_getcfg(unsigned int pin);
+ 
+ extern int s3c2410_gpio_getirq(unsigned int pin);
+ 
++/* s3c2410_gpio_irq2pin
++ *
++ * turn the given irq number into the corresponding GPIO number
++ *
++ * returns:
++ *	< 0 = no pin
++ *	>=0 = gpio pin number
++*/
++
++extern int s3c2410_gpio_irq2pin(unsigned int irq);
++
+ #ifdef CONFIG_CPU_S3C2400
  
- bail_nolock:
- 	mlog_exit(error);
-diff --git a/fs/ocfs2/dlm/dlmfsver.c b/fs/ocfs2/dlm/dlmfsver.c
-index d2be3ad..a733b33 100644
---- a/fs/ocfs2/dlm/dlmfsver.c
-+++ b/fs/ocfs2/dlm/dlmfsver.c
-@@ -28,7 +28,7 @@
+ extern int s3c2400_gpio_getirq(unsigned int pin);
+@@ -87,6 +98,18 @@ extern int s3c2410_gpio_irqfilter(unsigned int pin, unsigned int on,
  
- #include "dlmfsver.h"
+ extern void s3c2410_gpio_pullup(unsigned int pin, unsigned int to);
  
--#define DLM_BUILD_VERSION "1.3.3"
-+#define DLM_BUILD_VERSION "1.5.0"
++/* s3c2410_gpio_getpull
++ *
++ * Read the state of the pull-up on a given pin
++ *
++ * return:
++ *	< 0 => error code
++ *	  0 => enabled
++ *	  1 => disabled
++*/
++
++extern int s3c2410_gpio_getpull(unsigned int pin);
++
+ extern void s3c2410_gpio_setpin(unsigned int pin, unsigned int to);
  
- #define VERSION_STR "OCFS2 DLMFS " DLM_BUILD_VERSION
+ extern unsigned int s3c2410_gpio_getpin(unsigned int pin);
+@@ -99,6 +122,11 @@ extern int s3c2440_set_dsc(unsigned int pin, unsigned int value);
  
-diff --git a/fs/ocfs2/dlm/dlmrecovery.c b/fs/ocfs2/dlm/dlmrecovery.c
-index 2fde7bf..91f747b 100644
---- a/fs/ocfs2/dlm/dlmrecovery.c
-+++ b/fs/ocfs2/dlm/dlmrecovery.c
-@@ -2270,6 +2270,12 @@ static void __dlm_hb_node_down(struct dlm_ctxt *dlm, int idx)
- 		}
- 	}
+ #endif /* CONFIG_CPU_S3C2440 */
  
-+	/* Clean up join state on node death. */
-+	if (dlm->joining_node == idx) {
-+		mlog(0, "Clearing join state for node %u\n", idx);
-+		__dlm_set_joining_node(dlm, DLM_LOCK_RES_OWNER_UNKNOWN);
-+	}
++#ifdef CONFIG_CPU_S3C2412
 +
- 	/* check to see if the node is already considered dead */
- 	if (!test_bit(idx, dlm->live_nodes_map)) {
- 		mlog(0, "for domain %s, node %d is already dead. "
-@@ -2288,12 +2294,6 @@ static void __dlm_hb_node_down(struct dlm_ctxt *dlm, int idx)
++extern int s3c2412_gpio_set_sleepcfg(unsigned int pin, unsigned int state);
++
++#endif /* CONFIG_CPU_S3C2412 */
  
- 	clear_bit(idx, dlm->live_nodes_map);
+ #endif /* __ASSEMBLY__ */
  
--	/* Clean up join state on node death. */
--	if (dlm->joining_node == idx) {
--		mlog(0, "Clearing join state for node %u\n", idx);
--		__dlm_set_joining_node(dlm, DLM_LOCK_RES_OWNER_UNKNOWN);
--	}
--
- 	/* make sure local cleanup occurs before the heartbeat events */
- 	if (!test_bit(idx, dlm->recovery_map))
- 		dlm_do_local_recovery_cleanup(dlm, idx);
-@@ -2321,6 +2321,13 @@ void dlm_hb_node_down_cb(struct o2nm_node *node, int idx, void *data)
- 	if (!dlm_grab(dlm))
- 		return;
+diff --git a/include/asm-arm/arch-s3c2410/irqs.h b/include/asm-arm/arch-s3c2410/irqs.h
+index 996f654..d858b3e 100644
+--- a/include/asm-arm/arch-s3c2410/irqs.h
++++ b/include/asm-arm/arch-s3c2410/irqs.h
+@@ -160,4 +160,7 @@
+ #define NR_IRQS (IRQ_S3C2440_AC97+1)
+ #endif
  
-+	/*
-+	 * This will notify any dlm users that a node in our domain
-+	 * went away without notifying us first.
-+	 */
-+	if (test_bit(idx, dlm->domain_map))
-+		dlm_fire_domain_eviction_callbacks(dlm, idx);
++/* Our FIQs are routable from IRQ_EINT0 to IRQ_ADCPARENT */
++#define FIQ_START		IRQ_EINT0
 +
- 	spin_lock(&dlm->spinlock);
- 	__dlm_hb_node_down(dlm, idx);
- 	spin_unlock(&dlm->spinlock);
-diff --git a/fs/ocfs2/dlm/dlmver.c b/fs/ocfs2/dlm/dlmver.c
-index 7ef2653..dfc0da4 100644
---- a/fs/ocfs2/dlm/dlmver.c
-+++ b/fs/ocfs2/dlm/dlmver.c
-@@ -28,7 +28,7 @@
+ #endif /* __ASM_ARCH_IRQ_H */
+diff --git a/include/asm-arm/arch-s3c2410/regs-clock.h b/include/asm-arm/arch-s3c2410/regs-clock.h
+index e39656b..dba9df9 100644
+--- a/include/asm-arm/arch-s3c2410/regs-clock.h
++++ b/include/asm-arm/arch-s3c2410/regs-clock.h
+@@ -138,6 +138,8 @@ s3c2410_get_pll(unsigned int pllval, unsigned int baseclk)
+ #define S3C2412_CLKDIVN_PDIVN		(1<<2)
+ #define S3C2412_CLKDIVN_HDIVN_MASK	(3<<0)
+ #define S3C2421_CLKDIVN_ARMDIVN		(1<<3)
++#define S3C2412_CLKDIVN_DVSEN		(1<<4)
++#define S3C2412_CLKDIVN_HALFHCLK	(1<<5)
+ #define S3C2412_CLKDIVN_USB48DIV	(1<<6)
+ #define S3C2412_CLKDIVN_UARTDIV_MASK	(15<<8)
+ #define S3C2412_CLKDIVN_UARTDIV_SHIFT	(8)
+diff --git a/include/asm-arm/arch-s3c2410/regs-dsc.h b/include/asm-arm/arch-s3c2410/regs-dsc.h
+index c074851..1235df7 100644
+--- a/include/asm-arm/arch-s3c2410/regs-dsc.h
++++ b/include/asm-arm/arch-s3c2410/regs-dsc.h
+@@ -19,7 +19,7 @@
+ #define S3C2412_DSC1	   S3C2410_GPIOREG(0xe0)
+ #endif
  
- #include "dlmver.h"
+-#if defined(CONFIG_CPU_S3C2440)
++#if defined(CONFIG_CPU_S3C244X)
  
--#define DLM_BUILD_VERSION "1.3.3"
-+#define DLM_BUILD_VERSION "1.5.0"
+ #define S3C2440_DSC0	   S3C2410_GPIOREG(0xc4)
+ #define S3C2440_DSC1	   S3C2410_GPIOREG(0xc8)
+diff --git a/include/asm-arm/arch-s3c2410/regs-gpio.h b/include/asm-arm/arch-s3c2410/regs-gpio.h
+index b693158..0ad75d7 100644
+--- a/include/asm-arm/arch-s3c2410/regs-gpio.h
++++ b/include/asm-arm/arch-s3c2410/regs-gpio.h
+@@ -1133,12 +1133,16 @@
+ #define S3C2412_GPBSLPCON	S3C2410_GPIOREG(0x1C)
+ #define S3C2412_GPCSLPCON	S3C2410_GPIOREG(0x2C)
+ #define S3C2412_GPDSLPCON	S3C2410_GPIOREG(0x3C)
+-#define S3C2412_GPESLPCON	S3C2410_GPIOREG(0x4C)
+ #define S3C2412_GPFSLPCON	S3C2410_GPIOREG(0x5C)
+ #define S3C2412_GPGSLPCON	S3C2410_GPIOREG(0x6C)
+ #define S3C2412_GPHSLPCON	S3C2410_GPIOREG(0x7C)
+ 
+ /* definitions for each pin bit */
++#define S3C2412_GPIO_SLPCON_LOW	 ( 0x00 )
++#define S3C2412_GPIO_SLPCON_HIGH ( 0x01 )
++#define S3C2412_GPIO_SLPCON_IN   ( 0x02 )
++#define S3C2412_GPIO_SLPCON_PULL ( 0x03 )
++
+ #define S3C2412_SLPCON_LOW(x)	( 0x00 << ((x) * 2))
+ #define S3C2412_SLPCON_HIGH(x)	( 0x01 << ((x) * 2))
+ #define S3C2412_SLPCON_IN(x)	( 0x02 << ((x) * 2))
+diff --git a/include/asm-arm/arch-s3c2410/regs-mem.h b/include/asm-arm/arch-s3c2410/regs-mem.h
+index e4d8234..312ff93 100644
+--- a/include/asm-arm/arch-s3c2410/regs-mem.h
++++ b/include/asm-arm/arch-s3c2410/regs-mem.h
+@@ -98,16 +98,19 @@
+ #define S3C2410_BANKCON_Tacp3		(0x1 << 2)
+ #define S3C2410_BANKCON_Tacp4		(0x2 << 2)
+ #define S3C2410_BANKCON_Tacp6		(0x3 << 2)
++#define S3C2410_BANKCON_Tacp_SHIFT	(2)
+ 
+ #define S3C2410_BANKCON_Tcah0		(0x0 << 4)
+ #define S3C2410_BANKCON_Tcah1		(0x1 << 4)
+ #define S3C2410_BANKCON_Tcah2		(0x2 << 4)
+ #define S3C2410_BANKCON_Tcah4		(0x3 << 4)
++#define S3C2410_BANKCON_Tcah_SHIFT	(4)
+ 
+ #define S3C2410_BANKCON_Tcoh0		(0x0 << 6)
+ #define S3C2410_BANKCON_Tcoh1		(0x1 << 6)
+ #define S3C2410_BANKCON_Tcoh2		(0x2 << 6)
+ #define S3C2410_BANKCON_Tcoh4		(0x3 << 6)
++#define S3C2410_BANKCON_Tcoh_SHIFT	(6)
+ 
+ #define S3C2410_BANKCON_Tacc1		(0x0 << 8)
+ #define S3C2410_BANKCON_Tacc2		(0x1 << 8)
+@@ -117,16 +120,19 @@
+ #define S3C2410_BANKCON_Tacc8		(0x5 << 8)
+ #define S3C2410_BANKCON_Tacc10		(0x6 << 8)
+ #define S3C2410_BANKCON_Tacc14		(0x7 << 8)
++#define S3C2410_BANKCON_Tacc_SHIFT	(8)
+ 
+ #define S3C2410_BANKCON_Tcos0		(0x0 << 11)
+ #define S3C2410_BANKCON_Tcos1		(0x1 << 11)
+ #define S3C2410_BANKCON_Tcos2		(0x2 << 11)
+ #define S3C2410_BANKCON_Tcos4		(0x3 << 11)
++#define S3C2410_BANKCON_Tcos_SHIFT	(11)
+ 
+ #define S3C2410_BANKCON_Tacs0		(0x0 << 13)
+ #define S3C2410_BANKCON_Tacs1		(0x1 << 13)
+ #define S3C2410_BANKCON_Tacs2		(0x2 << 13)
+ #define S3C2410_BANKCON_Tacs4		(0x3 << 13)
++#define S3C2410_BANKCON_Tacs_SHIFT	(13)
+ 
+ #define S3C2410_BANKCON_SRAM		(0x0 << 15)
+ #define S3C2400_BANKCON_EDODRAM		(0x2 << 15)
+diff --git a/include/asm-arm/arch-s3c2410/regs-power.h b/include/asm-arm/arch-s3c2410/regs-power.h
+index f79987b..13d13b7 100644
+--- a/include/asm-arm/arch-s3c2410/regs-power.h
++++ b/include/asm-arm/arch-s3c2410/regs-power.h
+@@ -23,7 +23,8 @@
+ #define S3C2412_INFORM2		S3C24XX_PWRREG(0x78)
+ #define S3C2412_INFORM3		S3C24XX_PWRREG(0x7C)
+ 
+-#define S3C2412_PWRCFG_BATF_IGNORE		(0<<0)
++#define S3C2412_PWRCFG_BATF_IRQ			(1<<0)
++#define S3C2412_PWRCFG_BATF_IGNORE		(2<<0)
+ #define S3C2412_PWRCFG_BATF_SLEEP		(3<<0)
+ #define S3C2412_PWRCFG_BATF_MASK		(3<<0)
+ 
+diff --git a/include/asm-arm/arch-s3c2410/system.h b/include/asm-arm/arch-s3c2410/system.h
+index 6389178..14de4e5 100644
+--- a/include/asm-arm/arch-s3c2410/system.h
++++ b/include/asm-arm/arch-s3c2410/system.h
+@@ -20,6 +20,9 @@
+ #include <asm/plat-s3c/regs-watchdog.h>
+ #include <asm/arch/regs-clock.h>
  
- #define VERSION_STR "OCFS2 DLM " DLM_BUILD_VERSION
++#include <linux/clk.h>
++#include <linux/err.h>
++
+ void (*s3c24xx_idle)(void);
+ void (*s3c24xx_reset_hook)(void);
  
-diff --git a/fs/ocfs2/dlmglue.c b/fs/ocfs2/dlmglue.c
-index 4e97dcc..3867244 100644
---- a/fs/ocfs2/dlmglue.c
-+++ b/fs/ocfs2/dlmglue.c
-@@ -55,7 +55,6 @@
- #include "slot_map.h"
- #include "super.h"
- #include "uptodate.h"
--#include "vote.h"
+@@ -59,6 +62,8 @@ static void arch_idle(void)
+ static void
+ arch_reset(char mode)
+ {
++	struct clk *wdtclk;
++
+ 	if (mode == 's') {
+ 		cpu_reset(0);
+ 	}
+@@ -70,19 +75,28 @@ arch_reset(char mode)
  
- #include "buffer_head_io.h"
+ 	__raw_writel(0, S3C2410_WTCON);	  /* disable watchdog, to be safe  */
  
-@@ -69,6 +68,7 @@ struct ocfs2_mask_waiter {
++	wdtclk = clk_get(NULL, "watchdog");
++	if (!IS_ERR(wdtclk)) {
++		clk_enable(wdtclk);
++	} else
++		printk(KERN_WARNING "%s: warning: cannot get watchdog clock\n", __func__);
++
+ 	/* put initial values into count and data */
+-	__raw_writel(0x100, S3C2410_WTCNT);
+-	__raw_writel(0x100, S3C2410_WTDAT);
++	__raw_writel(0x80, S3C2410_WTCNT);
++	__raw_writel(0x80, S3C2410_WTDAT);
+ 
+ 	/* set the watchdog to go and reset... */
+ 	__raw_writel(S3C2410_WTCON_ENABLE|S3C2410_WTCON_DIV16|S3C2410_WTCON_RSTEN |
+ 		     S3C2410_WTCON_PRESCALE(0x20), S3C2410_WTCON);
+ 
+ 	/* wait for reset to assert... */
+-	mdelay(5000);
++	mdelay(500);
+ 
+ 	printk(KERN_ERR "Watchdog reset failed to assert reset\n");
+ 
++	/* delay to allow the serial port to show the message */
++	mdelay(50);
++
+ 	/* we'll take a jump through zero as a poor second */
+ 	cpu_reset(0);
+ }
+diff --git a/include/asm-arm/cacheflush.h b/include/asm-arm/cacheflush.h
+index 6c1c968..759a97b 100644
+--- a/include/asm-arm/cacheflush.h
++++ b/include/asm-arm/cacheflush.h
+@@ -94,6 +94,14 @@
+ # endif
+ #endif
  
- static struct ocfs2_super *ocfs2_get_dentry_osb(struct ocfs2_lock_res *lockres);
- static struct ocfs2_super *ocfs2_get_inode_osb(struct ocfs2_lock_res *lockres);
-+static struct ocfs2_super *ocfs2_get_file_osb(struct ocfs2_lock_res *lockres);
++#if defined(CONFIG_CPU_FEROCEON)
++# ifdef _CACHE
++#  define MULTI_CACHE 1
++# else
++#  define _CACHE feroceon
++# endif
++#endif
++
+ #if defined(CONFIG_CPU_V6)
+ //# ifdef _CACHE
+ #  define MULTI_CACHE 1
+diff --git a/include/asm-arm/fpstate.h b/include/asm-arm/fpstate.h
+index f31cda5..392eb53 100644
+--- a/include/asm-arm/fpstate.h
++++ b/include/asm-arm/fpstate.h
+@@ -17,14 +17,18 @@
+ /*
+  * VFP storage area has:
+  *  - FPEXC, FPSCR, FPINST and FPINST2.
+- *  - 16 double precision data registers
+- *  - an implementation-dependant word of state for FLDMX/FSTMX
++ *  - 16 or 32 double precision data registers
++ *  - an implementation-dependant word of state for FLDMX/FSTMX (pre-ARMv6)
+  * 
+  *  FPEXC will always be non-zero once the VFP has been used in this process.
+  */
  
- /*
-  * Return value from ->downconvert_worker functions.
-@@ -153,10 +153,10 @@ struct ocfs2_lock_res_ops {
- 	struct ocfs2_super * (*get_osb)(struct ocfs2_lock_res *);
+ struct vfp_hard_struct {
++#ifdef CONFIG_VFPv3
++	__u64 fpregs[32];
++#else
+ 	__u64 fpregs[16];
++#endif
+ #if __LINUX_ARM_ARCH__ < 6
+ 	__u32 fpmx_state;
+ #endif
+@@ -35,6 +39,7 @@ struct vfp_hard_struct {
+ 	 */
+ 	__u32 fpinst;
+ 	__u32 fpinst2;
++
+ #ifdef CONFIG_SMP
+ 	__u32 cpu;
+ #endif
+diff --git a/include/asm-arm/kprobes.h b/include/asm-arm/kprobes.h
+new file mode 100644
+index 0000000..4e7bd32
+--- /dev/null
++++ b/include/asm-arm/kprobes.h
+@@ -0,0 +1,79 @@
++/*
++ * include/asm-arm/kprobes.h
++ *
++ * Copyright (C) 2006, 2007 Motorola 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.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT 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 _ARM_KPROBES_H
++#define _ARM_KPROBES_H
++
++#include <linux/types.h>
++#include <linux/ptrace.h>
++#include <linux/percpu.h>
++
++#define ARCH_SUPPORTS_KRETPROBES
++#define __ARCH_WANT_KPROBES_INSN_SLOT
++#define MAX_INSN_SIZE			2
++#define MAX_STACK_SIZE			64	/* 32 would probably be OK */
++
++/*
++ * This undefined instruction must be unique and
++ * reserved solely for kprobes' use.
++ */
++#define KPROBE_BREAKPOINT_INSTRUCTION	0xe7f001f8
++
++#define regs_return_value(regs)		((regs)->ARM_r0)
++#define flush_insn_slot(p)		do { } while (0)
++#define kretprobe_blacklist_size	0
++
++typedef u32 kprobe_opcode_t;
++
++struct kprobe;
++typedef void (kprobe_insn_handler_t)(struct kprobe *, struct pt_regs *);
++
++/* Architecture specific copy of original instruction. */
++struct arch_specific_insn {
++	kprobe_opcode_t		*insn;
++	kprobe_insn_handler_t	*insn_handler;
++};
++
++struct prev_kprobe {
++	struct kprobe *kp;
++	unsigned int status;
++};
++
++/* per-cpu kprobe control block */
++struct kprobe_ctlblk {
++	unsigned int kprobe_status;
++	struct prev_kprobe prev_kprobe;
++	struct pt_regs jprobe_saved_regs;
++	char jprobes_stack[MAX_STACK_SIZE];
++};
++
++void arch_remove_kprobe(struct kprobe *);
++
++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);
++
++enum kprobe_insn {
++	INSN_REJECTED,
++	INSN_GOOD,
++	INSN_GOOD_NO_SLOT
++};
++
++enum kprobe_insn arm_kprobe_decode_insn(kprobe_opcode_t,
++					struct arch_specific_insn *);
++void __init arm_kprobe_decode_init(void);
++
++#endif /* _ARM_KPROBES_H */
+diff --git a/include/asm-arm/plat-s3c24xx/dma.h b/include/asm-arm/plat-s3c24xx/dma.h
+index 2c59406..c78efe3 100644
+--- a/include/asm-arm/plat-s3c24xx/dma.h
++++ b/include/asm-arm/plat-s3c24xx/dma.h
+@@ -32,6 +32,7 @@ struct s3c24xx_dma_map {
+ 	struct s3c24xx_dma_addr  hw_addr;
  
- 	/*
--	 * Optionally called in the downconvert (or "vote") thread
--	 * after a successful downconvert. The lockres will not be
--	 * referenced after this callback is called, so it is safe to
--	 * free memory, etc.
-+	 * Optionally called in the downconvert thread after a
-+	 * successful downconvert. The lockres will not be referenced
-+	 * after this callback is called, so it is safe to free
-+	 * memory, etc.
- 	 *
- 	 * The exact semantics of when this is called are controlled
- 	 * by ->downconvert_worker()
-@@ -225,17 +225,12 @@ static struct ocfs2_lock_res_ops ocfs2_inode_rw_lops = {
- 	.flags		= 0,
+ 	unsigned long		 channels[S3C2410_DMA_CHANNELS];
++	unsigned long		 channels_rx[S3C2410_DMA_CHANNELS];
  };
  
--static struct ocfs2_lock_res_ops ocfs2_inode_meta_lops = {
-+static struct ocfs2_lock_res_ops ocfs2_inode_inode_lops = {
- 	.get_osb	= ocfs2_get_inode_osb,
- 	.check_downconvert = ocfs2_check_meta_downconvert,
- 	.set_lvb	= ocfs2_set_meta_lvb,
--	.flags		= LOCK_TYPE_REQUIRES_REFRESH|LOCK_TYPE_USES_LVB,
--};
--
--static struct ocfs2_lock_res_ops ocfs2_inode_data_lops = {
--	.get_osb	= ocfs2_get_inode_osb,
- 	.downconvert_worker = ocfs2_data_convert_worker,
--	.flags		= 0,
-+	.flags		= LOCK_TYPE_REQUIRES_REFRESH|LOCK_TYPE_USES_LVB,
- };
+ struct s3c24xx_dma_selection {
+@@ -41,6 +42,10 @@ struct s3c24xx_dma_selection {
  
- static struct ocfs2_lock_res_ops ocfs2_super_lops = {
-@@ -258,10 +253,14 @@ static struct ocfs2_lock_res_ops ocfs2_inode_open_lops = {
- 	.flags		= 0,
+ 	void	(*select)(struct s3c2410_dma_chan *chan,
+ 			  struct s3c24xx_dma_map *map);
++
++	void	(*direction)(struct s3c2410_dma_chan *chan,
++			     struct s3c24xx_dma_map *map,
++			     enum s3c2410_dmasrc dir);
  };
  
-+static struct ocfs2_lock_res_ops ocfs2_flock_lops = {
-+	.get_osb	= ocfs2_get_file_osb,
-+	.flags		= 0,
-+};
-+
- static inline int ocfs2_is_inode_lock(struct ocfs2_lock_res *lockres)
- {
- 	return lockres->l_type == OCFS2_LOCK_TYPE_META ||
--		lockres->l_type == OCFS2_LOCK_TYPE_DATA ||
- 		lockres->l_type == OCFS2_LOCK_TYPE_RW ||
- 		lockres->l_type == OCFS2_LOCK_TYPE_OPEN;
- }
-@@ -310,12 +309,24 @@ static inline void ocfs2_recover_from_dlm_error(struct ocfs2_lock_res *lockres,
- 		"resource %s: %s\n", dlm_errname(_stat), _func,	\
- 		_lockres->l_name, dlm_errmsg(_stat));		\
- } while (0)
--static void ocfs2_vote_on_unlock(struct ocfs2_super *osb,
--				 struct ocfs2_lock_res *lockres);
--static int ocfs2_meta_lock_update(struct inode *inode,
-+static int ocfs2_downconvert_thread(void *arg);
-+static void ocfs2_downconvert_on_unlock(struct ocfs2_super *osb,
-+					struct ocfs2_lock_res *lockres);
-+static int ocfs2_inode_lock_update(struct inode *inode,
- 				  struct buffer_head **bh);
- static void ocfs2_drop_osb_locks(struct ocfs2_super *osb);
- static inline int ocfs2_highest_compat_lock_level(int level);
-+static void ocfs2_prepare_downconvert(struct ocfs2_lock_res *lockres,
-+				      int new_level);
-+static int ocfs2_downconvert_lock(struct ocfs2_super *osb,
-+				  struct ocfs2_lock_res *lockres,
-+				  int new_level,
-+				  int lvb);
-+static int ocfs2_prepare_cancel_convert(struct ocfs2_super *osb,
-+				        struct ocfs2_lock_res *lockres);
-+static int ocfs2_cancel_convert(struct ocfs2_super *osb,
-+				struct ocfs2_lock_res *lockres);
-+
+ extern int s3c24xx_dma_init_map(struct s3c24xx_dma_selection *sel);
+diff --git a/include/asm-arm/plat-s3c24xx/irq.h b/include/asm-arm/plat-s3c24xx/irq.h
+index 8af6d95..45746a9 100644
+--- a/include/asm-arm/plat-s3c24xx/irq.h
++++ b/include/asm-arm/plat-s3c24xx/irq.h
+@@ -15,7 +15,9 @@
  
- static void ocfs2_build_lock_name(enum ocfs2_lock_type type,
- 				  u64 blkno,
-@@ -402,10 +413,7 @@ void ocfs2_inode_lock_res_init(struct ocfs2_lock_res *res,
- 			ops = &ocfs2_inode_rw_lops;
- 			break;
- 		case OCFS2_LOCK_TYPE_META:
--			ops = &ocfs2_inode_meta_lops;
--			break;
--		case OCFS2_LOCK_TYPE_DATA:
--			ops = &ocfs2_inode_data_lops;
-+			ops = &ocfs2_inode_inode_lops;
- 			break;
- 		case OCFS2_LOCK_TYPE_OPEN:
- 			ops = &ocfs2_inode_open_lops;
-@@ -428,6 +436,13 @@ static struct ocfs2_super *ocfs2_get_inode_osb(struct ocfs2_lock_res *lockres)
- 	return OCFS2_SB(inode->i_sb);
- }
+ #define EXTINT_OFF (IRQ_EINT4 - 4)
  
-+static struct ocfs2_super *ocfs2_get_file_osb(struct ocfs2_lock_res *lockres)
-+{
-+	struct ocfs2_file_private *fp = lockres->l_priv;
++/* these are exported for arch/arm/mach-* usage */
+ extern struct irq_chip s3c_irq_level_chip;
++extern struct irq_chip s3c_irq_chip;
+ 
+ static inline void
+ s3c_irqsub_mask(unsigned int irqno, unsigned int parentbit,
+diff --git a/include/asm-arm/plat-s3c24xx/regs-s3c2412-iis.h b/include/asm-arm/plat-s3c24xx/regs-s3c2412-iis.h
+new file mode 100644
+index 0000000..25d4058
+--- /dev/null
++++ b/include/asm-arm/plat-s3c24xx/regs-s3c2412-iis.h
+@@ -0,0 +1,72 @@
++/* linux/include/asm-arm/plat-s3c24xx/regs-s3c2412-iis.h
++ *
++ * Copyright 2007 Simtec Electronics <linux at simtec.co.uk>
++ *	http://armlinux.simtec.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
++ * published by the Free Software Foundation.
++ *
++ * S3C2412 IIS register definition
++*/
 +
-+	return OCFS2_SB(fp->fp_file->f_mapping->host->i_sb);
-+}
++#ifndef __ASM_ARCH_REGS_S3C2412_IIS_H
++#define __ASM_ARCH_REGS_S3C2412_IIS_H
 +
- static __u64 ocfs2_get_dentry_lock_ino(struct ocfs2_lock_res *lockres)
- {
- 	__be64 inode_blkno_be;
-@@ -508,6 +523,21 @@ static void ocfs2_rename_lock_res_init(struct ocfs2_lock_res *res,
- 				   &ocfs2_rename_lops, osb);
- }
++#define S3C2412_IISCON			(0x00)
++#define S3C2412_IISMOD			(0x04)
++#define S3C2412_IISFIC			(0x08)
++#define S3C2412_IISPSR			(0x0C)
++#define S3C2412_IISTXD			(0x10)
++#define S3C2412_IISRXD			(0x14)
++
++#define S3C2412_IISCON_LRINDEX		(1 << 11)
++#define S3C2412_IISCON_TXFIFO_EMPTY	(1 << 10)
++#define S3C2412_IISCON_RXFIFO_EMPTY	(1 << 9)
++#define S3C2412_IISCON_TXFIFO_FULL	(1 << 8)
++#define S3C2412_IISCON_RXFIFO_FULL	(1 << 7)
++#define S3C2412_IISCON_TXDMA_PAUSE	(1 << 6)
++#define S3C2412_IISCON_RXDMA_PAUSE	(1 << 5)
++#define S3C2412_IISCON_TXCH_PAUSE	(1 << 4)
++#define S3C2412_IISCON_RXCH_PAUSE	(1 << 3)
++#define S3C2412_IISCON_TXDMA_ACTIVE	(1 << 2)
++#define S3C2412_IISCON_RXDMA_ACTIVE	(1 << 1)
++#define S3C2412_IISCON_IIS_ACTIVE	(1 << 0)
++
++#define S3C2412_IISMOD_MASTER_INTERNAL	(0 << 10)
++#define S3C2412_IISMOD_MASTER_EXTERNAL	(1 << 10)
++#define S3C2412_IISMOD_SLAVE		(2 << 10)
++#define S3C2412_IISMOD_MASTER_MASK	(3 << 10)
++#define S3C2412_IISMOD_MODE_TXONLY	(0 << 8)
++#define S3C2412_IISMOD_MODE_RXONLY	(1 << 8)
++#define S3C2412_IISMOD_MODE_TXRX	(2 << 8)
++#define S3C2412_IISMOD_MODE_MASK	(3 << 8)
++#define S3C2412_IISMOD_LR_LLOW		(0 << 7)
++#define S3C2412_IISMOD_LR_RLOW		(1 << 7)
++#define S3C2412_IISMOD_SDF_IIS		(0 << 5)
++#define S3C2412_IISMOD_SDF_MSB		(0 << 5)
++#define S3C2412_IISMOD_SDF_LSB		(0 << 5)
++#define S3C2412_IISMOD_SDF_MASK		(3 << 5)
++#define S3C2412_IISMOD_RCLK_256FS	(0 << 3)
++#define S3C2412_IISMOD_RCLK_512FS	(1 << 3)
++#define S3C2412_IISMOD_RCLK_384FS	(2 << 3)
++#define S3C2412_IISMOD_RCLK_768FS	(3 << 3)
++#define S3C2412_IISMOD_RCLK_MASK 	(3 << 3)
++#define S3C2412_IISMOD_BCLK_32FS	(0 << 1)
++#define S3C2412_IISMOD_BCLK_48FS	(1 << 1)
++#define S3C2412_IISMOD_BCLK_16FS	(2 << 1)
++#define S3C2412_IISMOD_BCLK_24FS	(3 << 1)
++#define S3C2412_IISMOD_BCLK_MASK	(3 << 1)
++#define S3C2412_IISMOD_8BIT		(1 << 0)
++
++#define S3C2412_IISPSR_PSREN		(1 << 15)
++
++#define S3C2412_IISFIC_TXFLUSH		(1 << 15)
++#define S3C2412_IISFIC_RXFLUSH		(1 << 7)
++#define S3C2412_IISFIC_TXCOUNT(x)	(((x) >>  8) & 0xf)
++#define S3C2412_IISFIC_RXCOUNT(x)	(((x) >>  0) & 0xf)
++
++
++
++#endif /* __ASM_ARCH_REGS_S3C2412_IIS_H */
++
+diff --git a/include/asm-arm/plat-s3c24xx/regs-spi.h b/include/asm-arm/plat-s3c24xx/regs-spi.h
+index 4a499a1..ea565b0 100644
+--- a/include/asm-arm/plat-s3c24xx/regs-spi.h
++++ b/include/asm-arm/plat-s3c24xx/regs-spi.h
+@@ -17,6 +17,21 @@
+ 
+ #define S3C2410_SPCON	(0x00)
+ 
++#define S3C2412_SPCON_RXFIFO_RB2	(0<<14)
++#define S3C2412_SPCON_RXFIFO_RB4	(1<<14)
++#define S3C2412_SPCON_RXFIFO_RB12	(2<<14)
++#define S3C2412_SPCON_RXFIFO_RB14	(3<<14)
++#define S3C2412_SPCON_TXFIFO_RB2	(0<<12)
++#define S3C2412_SPCON_TXFIFO_RB4	(1<<12)
++#define S3C2412_SPCON_TXFIFO_RB12	(2<<12)
++#define S3C2412_SPCON_TXFIFO_RB14	(3<<12)
++#define S3C2412_SPCON_RXFIFO_RESET	(1<<11) /* RxFIFO reset */
++#define S3C2412_SPCON_TXFIFO_RESET	(1<<10) /* TxFIFO reset */
++#define S3C2412_SPCON_RXFIFO_EN		(1<<9)  /* RxFIFO Enable */
++#define S3C2412_SPCON_TXFIFO_EN		(1<<8)  /* TxFIFO Enable */
++
++#define S3C2412_SPCON_DIRC_RX	  (1<<7)
++
+ #define S3C2410_SPCON_SMOD_DMA	  (2<<5)	/* DMA mode */
+ #define S3C2410_SPCON_SMOD_INT	  (1<<5)	/* interrupt mode */
+ #define S3C2410_SPCON_SMOD_POLL   (0<<5)	/* polling mode */
+@@ -34,10 +49,19 @@
+ 
+ #define S3C2410_SPSTA	 (0x04)
+ 
++#define S3C2412_SPSTA_RXFIFO_AE		(1<<11)
++#define S3C2412_SPSTA_TXFIFO_AE		(1<<10)
++#define S3C2412_SPSTA_RXFIFO_ERROR	(1<<9)
++#define S3C2412_SPSTA_TXFIFO_ERROR	(1<<8)
++#define S3C2412_SPSTA_RXFIFO_FIFO	(1<<7)
++#define S3C2412_SPSTA_RXFIFO_EMPTY	(1<<6)
++#define S3C2412_SPSTA_TXFIFO_NFULL	(1<<5)
++#define S3C2412_SPSTA_TXFIFO_EMPTY	(1<<4)
++
+ #define S3C2410_SPSTA_DCOL	  (1<<2)	/* Data Collision Error */
+ #define S3C2410_SPSTA_MULD	  (1<<1)	/* Multi Master Error */
+ #define S3C2410_SPSTA_READY	  (1<<0)	/* Data Tx/Rx ready */
+-
++#define S3C2412_SPSTA_READY_ORG	  (1<<3)
+ 
+ #define S3C2410_SPPIN	 (0x08)
+ 
+@@ -46,9 +70,13 @@
+ #define S3C2400_SPPIN_nCS     	  (1<<1)	/* SPI Card Select */
+ #define S3C2410_SPPIN_KEEP	  (1<<0)	/* Master Out keep */
+ 
+-
+ #define S3C2410_SPPRE	 (0x0C)
+ #define S3C2410_SPTDAT	 (0x10)
+ #define S3C2410_SPRDAT	 (0x14)
+ 
++#define S3C2412_TXFIFO	 (0x18)
++#define S3C2412_RXFIFO	 (0x18)
++#define S3C2412_SPFIC	 (0x24)
++
++
+ #endif /* __ASM_ARCH_REGS_SPI_H */
+diff --git a/include/asm-arm/proc-fns.h b/include/asm-arm/proc-fns.h
+index 5599d4e..a4ce457 100644
+--- a/include/asm-arm/proc-fns.h
++++ b/include/asm-arm/proc-fns.h
+@@ -185,6 +185,14 @@
+ #   define CPU_NAME cpu_xsc3
+ #  endif
+ # endif
++# ifdef CONFIG_CPU_FEROCEON
++#  ifdef CPU_NAME
++#   undef  MULTI_CPU
++#   define MULTI_CPU
++#  else
++#   define CPU_NAME cpu_feroceon
++#  endif
++# endif
+ # ifdef CONFIG_CPU_V6
+ #  ifdef CPU_NAME
+ #   undef  MULTI_CPU
+diff --git a/include/asm-arm/traps.h b/include/asm-arm/traps.h
+index d4f34dc..f1541af 100644
+--- a/include/asm-arm/traps.h
++++ b/include/asm-arm/traps.h
+@@ -15,4 +15,13 @@ struct undef_hook {
+ void register_undef_hook(struct undef_hook *hook);
+ void unregister_undef_hook(struct undef_hook *hook);
  
-+void ocfs2_file_lock_res_init(struct ocfs2_lock_res *lockres,
-+			      struct ocfs2_file_private *fp)
++static inline int in_exception_text(unsigned long ptr)
 +{
-+	struct inode *inode = fp->fp_file->f_mapping->host;
-+	struct ocfs2_inode_info *oi = OCFS2_I(inode);
++	extern char __exception_text_start[];
++	extern char __exception_text_end[];
 +
-+	ocfs2_lock_res_init_once(lockres);
-+	ocfs2_build_lock_name(OCFS2_LOCK_TYPE_FLOCK, oi->ip_blkno,
-+			      inode->i_generation, lockres->l_name);
-+	ocfs2_lock_res_init_common(OCFS2_SB(inode->i_sb), lockres,
-+				   OCFS2_LOCK_TYPE_FLOCK, &ocfs2_flock_lops,
-+				   fp);
-+	lockres->l_flags |= OCFS2_LOCK_NOCACHE;
++	return ptr >= (unsigned long)&__exception_text_start &&
++	       ptr < (unsigned long)&__exception_text_end;
 +}
 +
- void ocfs2_lock_res_free(struct ocfs2_lock_res *res)
- {
- 	mlog_entry_void();
-@@ -724,6 +754,13 @@ static void ocfs2_blocking_ast(void *opaque, int level)
- 	     lockres->l_name, level, lockres->l_level,
- 	     ocfs2_lock_type_string(lockres->l_type));
+ #endif
+diff --git a/include/asm-arm/vfp.h b/include/asm-arm/vfp.h
+index bd6be9d..5f9a2cb 100644
+--- a/include/asm-arm/vfp.h
++++ b/include/asm-arm/vfp.h
+@@ -7,7 +7,11 @@
+ 
+ #define FPSID			cr0
+ #define FPSCR			cr1
++#define MVFR1			cr6
++#define MVFR0			cr7
+ #define FPEXC			cr8
++#define FPINST			cr9
++#define FPINST2			cr10
+ 
+ /* FPSID bits */
+ #define FPSID_IMPLEMENTER_BIT	(24)
+@@ -28,6 +32,19 @@
+ /* FPEXC bits */
+ #define FPEXC_EX		(1 << 31)
+ #define FPEXC_EN		(1 << 30)
++#define FPEXC_DEX		(1 << 29)
++#define FPEXC_FP2V		(1 << 28)
++#define FPEXC_VV		(1 << 27)
++#define FPEXC_TFV		(1 << 26)
++#define FPEXC_LENGTH_BIT	(8)
++#define FPEXC_LENGTH_MASK	(7 << FPEXC_LENGTH_BIT)
++#define FPEXC_IDF		(1 << 7)
++#define FPEXC_IXF		(1 << 4)
++#define FPEXC_UFF		(1 << 3)
++#define FPEXC_OFF		(1 << 2)
++#define FPEXC_DZF		(1 << 1)
++#define FPEXC_IOF		(1 << 0)
++#define FPEXC_TRAP_MASK		(FPEXC_IDF|FPEXC_IXF|FPEXC_UFF|FPEXC_OFF|FPEXC_DZF|FPEXC_IOF)
+ 
+ /* FPSCR bits */
+ #define FPSCR_DEFAULT_NAN	(1<<25)
+@@ -55,20 +72,9 @@
+ #define FPSCR_IXC		(1<<4)
+ #define FPSCR_IDC		(1<<7)
  
-+	/*
-+	 * We can skip the bast for locks which don't enable caching -
-+	 * they'll be dropped at the earliest possible time anyway.
-+	 */
-+	if (lockres->l_flags & OCFS2_LOCK_NOCACHE)
-+		return;
+-/*
+- * VFP9-S specific.
+- */
+-#define FPINST			cr9
+-#define FPINST2			cr10
+-
+-/* FPEXC bits */
+-#define FPEXC_FPV2		(1<<28)
+-#define FPEXC_LENGTH_BIT	(8)
+-#define FPEXC_LENGTH_MASK	(7 << FPEXC_LENGTH_BIT)
+-#define FPEXC_INV		(1 << 7)
+-#define FPEXC_UFC		(1 << 3)
+-#define FPEXC_OFC		(1 << 2)
+-#define FPEXC_IOC		(1 << 0)
++/* MVFR0 bits */
++#define MVFR0_A_SIMD_BIT	(0)
++#define MVFR0_A_SIMD_MASK	(0xf << MVFR0_A_SIMD_BIT)
+ 
+ /* Bit patterns for decoding the packaged operation descriptors */
+ #define VFPOPDESC_LENGTH_BIT	(9)
+diff --git a/include/asm-arm/vfpmacros.h b/include/asm-arm/vfpmacros.h
+index 27fe028..cccb389 100644
+--- a/include/asm-arm/vfpmacros.h
++++ b/include/asm-arm/vfpmacros.h
+@@ -15,19 +15,33 @@
+ 	.endm
+ 
+ 	@ read all the working registers back into the VFP
+-	.macro	VFPFLDMIA, base
++	.macro	VFPFLDMIA, base, tmp
+ #if __LINUX_ARM_ARCH__ < 6
+ 	LDC	p11, cr0, [\base],#33*4		    @ FLDMIAX \base!, {d0-d15}
+ #else
+ 	LDC	p11, cr0, [\base],#32*4		    @ FLDMIAD \base!, {d0-d15}
+ #endif
++#ifdef CONFIG_VFPv3
++	VFPFMRX	\tmp, MVFR0			    @ Media and VFP Feature Register 0
++	and	\tmp, \tmp, #MVFR0_A_SIMD_MASK	    @ A_SIMD field
++	cmp	\tmp, #2			    @ 32 x 64bit registers?
++	ldceql	p11, cr0, [\base],#32*4		    @ FLDMIAD \base!, {d16-d31}
++	addne	\base, \base, #32*4		    @ step over unused register space
++#endif
+ 	.endm
+ 
+ 	@ write all the working registers out of the VFP
+-	.macro	VFPFSTMIA, base
++	.macro	VFPFSTMIA, base, tmp
+ #if __LINUX_ARM_ARCH__ < 6
+ 	STC	p11, cr0, [\base],#33*4		    @ FSTMIAX \base!, {d0-d15}
+ #else
+ 	STC	p11, cr0, [\base],#32*4		    @ FSTMIAD \base!, {d0-d15}
+ #endif
++#ifdef CONFIG_VFPv3
++	VFPFMRX	\tmp, MVFR0			    @ Media and VFP Feature Register 0
++	and	\tmp, \tmp, #MVFR0_A_SIMD_MASK	    @ A_SIMD field
++	cmp	\tmp, #2			    @ 32 x 64bit registers?
++	stceql	p11, cr0, [\base],#32*4		    @ FSTMIAD \base!, {d16-d31}
++	addne	\base, \base, #32*4		    @ step over unused register space
++#endif
+ 	.endm
+diff --git a/include/asm-avr32/arch-at32ap/at32ap7000.h b/include/asm-avr32/arch-at32ap/at32ap7000.h
+deleted file mode 100644
+index 3914d7b..0000000
+--- a/include/asm-avr32/arch-at32ap/at32ap7000.h
++++ /dev/null
+@@ -1,35 +0,0 @@
+-/*
+- * Pin definitions for AT32AP7000.
+- *
+- * Copyright (C) 2006 Atmel 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.
+- */
+-#ifndef __ASM_ARCH_AT32AP7000_H__
+-#define __ASM_ARCH_AT32AP7000_H__
+-
+-#define GPIO_PERIPH_A	0
+-#define GPIO_PERIPH_B	1
+-
+-#define NR_GPIO_CONTROLLERS	4
+-
+-/*
+- * Pin numbers identifying specific GPIO pins on the chip. They can
+- * also be converted to IRQ numbers by passing them through
+- * gpio_to_irq().
+- */
+-#define GPIO_PIOA_BASE	(0)
+-#define GPIO_PIOB_BASE	(GPIO_PIOA_BASE + 32)
+-#define GPIO_PIOC_BASE	(GPIO_PIOB_BASE + 32)
+-#define GPIO_PIOD_BASE	(GPIO_PIOC_BASE + 32)
+-#define GPIO_PIOE_BASE	(GPIO_PIOD_BASE + 32)
+-
+-#define GPIO_PIN_PA(N)	(GPIO_PIOA_BASE + (N))
+-#define GPIO_PIN_PB(N)	(GPIO_PIOB_BASE + (N))
+-#define GPIO_PIN_PC(N)	(GPIO_PIOC_BASE + (N))
+-#define GPIO_PIN_PD(N)	(GPIO_PIOD_BASE + (N))
+-#define GPIO_PIN_PE(N)	(GPIO_PIOE_BASE + (N))
+-
+-#endif /* __ASM_ARCH_AT32AP7000_H__ */
+diff --git a/include/asm-avr32/arch-at32ap/at32ap700x.h b/include/asm-avr32/arch-at32ap/at32ap700x.h
+new file mode 100644
+index 0000000..99684d6
+--- /dev/null
++++ b/include/asm-avr32/arch-at32ap/at32ap700x.h
+@@ -0,0 +1,35 @@
++/*
++ * Pin definitions for AT32AP7000.
++ *
++ * Copyright (C) 2006 Atmel 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.
++ */
++#ifndef __ASM_ARCH_AT32AP700X_H__
++#define __ASM_ARCH_AT32AP700X_H__
 +
- 	spin_lock_irqsave(&lockres->l_lock, flags);
- 	needs_downconvert = ocfs2_generic_handle_bast(lockres, level);
- 	if (needs_downconvert)
-@@ -732,7 +769,7 @@ static void ocfs2_blocking_ast(void *opaque, int level)
++#define GPIO_PERIPH_A	0
++#define GPIO_PERIPH_B	1
++
++#define NR_GPIO_CONTROLLERS	4
++
++/*
++ * Pin numbers identifying specific GPIO pins on the chip. They can
++ * also be converted to IRQ numbers by passing them through
++ * gpio_to_irq().
++ */
++#define GPIO_PIOA_BASE	(0)
++#define GPIO_PIOB_BASE	(GPIO_PIOA_BASE + 32)
++#define GPIO_PIOC_BASE	(GPIO_PIOB_BASE + 32)
++#define GPIO_PIOD_BASE	(GPIO_PIOC_BASE + 32)
++#define GPIO_PIOE_BASE	(GPIO_PIOD_BASE + 32)
++
++#define GPIO_PIN_PA(N)	(GPIO_PIOA_BASE + (N))
++#define GPIO_PIN_PB(N)	(GPIO_PIOB_BASE + (N))
++#define GPIO_PIN_PC(N)	(GPIO_PIOC_BASE + (N))
++#define GPIO_PIN_PD(N)	(GPIO_PIOD_BASE + (N))
++#define GPIO_PIN_PE(N)	(GPIO_PIOE_BASE + (N))
++
++#endif /* __ASM_ARCH_AT32AP700X_H__ */
+diff --git a/include/asm-avr32/arch-at32ap/cpu.h b/include/asm-avr32/arch-at32ap/cpu.h
+index a762f42..44d0bfa 100644
+--- a/include/asm-avr32/arch-at32ap/cpu.h
++++ b/include/asm-avr32/arch-at32ap/cpu.h
+@@ -14,7 +14,7 @@
+  * Only AT32AP7000 is defined for now. We can identify the specific
+  * chip at runtime, but I'm not sure if it's really worth it.
+  */
+-#ifdef CONFIG_CPU_AT32AP7000
++#ifdef CONFIG_CPU_AT32AP700X
+ # define cpu_is_at32ap7000()	(1)
+ #else
+ # define cpu_is_at32ap7000()	(0)
+@@ -30,5 +30,6 @@
+ #define cpu_is_at91sam9261()	(0)
+ #define cpu_is_at91sam9263()	(0)
+ #define cpu_is_at91sam9rl()	(0)
++#define cpu_is_at91cap9()	(0)
  
- 	wake_up(&lockres->l_event);
+ #endif /* __ASM_ARCH_CPU_H */
+diff --git a/include/asm-avr32/arch-at32ap/io.h b/include/asm-avr32/arch-at32ap/io.h
+index ee59e40..4ec6abc 100644
+--- a/include/asm-avr32/arch-at32ap/io.h
++++ b/include/asm-avr32/arch-at32ap/io.h
+@@ -4,7 +4,7 @@
+ /* For "bizarre" halfword swapping */
+ #include <linux/byteorder/swabb.h>
  
--	ocfs2_kick_vote_thread(osb);
-+	ocfs2_wake_downconvert_thread(osb);
- }
+-#if defined(CONFIG_AP7000_32_BIT_SMC)
++#if defined(CONFIG_AP700X_32_BIT_SMC)
+ # define __swizzle_addr_b(addr)	(addr ^ 3UL)
+ # define __swizzle_addr_w(addr)	(addr ^ 2UL)
+ # define __swizzle_addr_l(addr)	(addr)
+@@ -14,7 +14,7 @@
+ # define __mem_ioswabb(a, x)	(x)
+ # define __mem_ioswabw(a, x)	swab16(x)
+ # define __mem_ioswabl(a, x)	swab32(x)
+-#elif defined(CONFIG_AP7000_16_BIT_SMC)
++#elif defined(CONFIG_AP700X_16_BIT_SMC)
+ # define __swizzle_addr_b(addr)	(addr ^ 1UL)
+ # define __swizzle_addr_w(addr)	(addr)
+ # define __swizzle_addr_l(addr)	(addr)
+diff --git a/include/asm-avr32/irq.h b/include/asm-avr32/irq.h
+index 83e6549..9315724 100644
+--- a/include/asm-avr32/irq.h
++++ b/include/asm-avr32/irq.h
+@@ -11,4 +11,9 @@
  
- static void ocfs2_locking_ast(void *opaque)
-@@ -935,6 +972,21 @@ static int lockres_remove_mask_waiter(struct ocfs2_lock_res *lockres,
+ #define irq_canonicalize(i)	(i)
  
- }
++#ifndef __ASSEMBLER__
++int nmi_enable(void);
++void nmi_disable(void);
++#endif
++
+ #endif /* __ASM_AVR32_IOCTLS_H */
+diff --git a/include/asm-avr32/kdebug.h b/include/asm-avr32/kdebug.h
+index fd7e990..ca4f954 100644
+--- a/include/asm-avr32/kdebug.h
++++ b/include/asm-avr32/kdebug.h
+@@ -5,6 +5,7 @@
+ enum die_val {
+ 	DIE_BREAKPOINT,
+ 	DIE_SSTEP,
++	DIE_NMI,
+ };
  
-+static int ocfs2_wait_for_mask_interruptible(struct ocfs2_mask_waiter *mw,
-+					     struct ocfs2_lock_res *lockres)
-+{
-+	int ret;
+ #endif /* __ASM_AVR32_KDEBUG_H */
+diff --git a/include/asm-avr32/ocd.h b/include/asm-avr32/ocd.h
+index 996405e..6bef094 100644
+--- a/include/asm-avr32/ocd.h
++++ b/include/asm-avr32/ocd.h
+@@ -533,6 +533,11 @@ static inline void __ocd_write(unsigned int reg, unsigned long value)
+ #define ocd_read(reg)			__ocd_read(OCD_##reg)
+ #define ocd_write(reg, value)		__ocd_write(OCD_##reg, value)
+ 
++struct task_struct;
 +
-+	ret = wait_for_completion_interruptible(&mw->mw_complete);
-+	if (ret)
-+		lockres_remove_mask_waiter(lockres, mw);
-+	else
-+		ret = mw->mw_status;
-+	/* Re-arm the completion in case we want to wait on it again */
-+	INIT_COMPLETION(mw->mw_complete);
-+	return ret;
-+}
++void ocd_enable(struct task_struct *child);
++void ocd_disable(struct task_struct *child);
 +
- static int ocfs2_cluster_lock(struct ocfs2_super *osb,
- 			      struct ocfs2_lock_res *lockres,
- 			      int level,
-@@ -1089,7 +1141,7 @@ static void ocfs2_cluster_unlock(struct ocfs2_super *osb,
- 	mlog_entry_void();
- 	spin_lock_irqsave(&lockres->l_lock, flags);
- 	ocfs2_dec_holders(lockres, level);
--	ocfs2_vote_on_unlock(osb, lockres);
-+	ocfs2_downconvert_on_unlock(osb, lockres);
- 	spin_unlock_irqrestore(&lockres->l_lock, flags);
- 	mlog_exit_void();
- }
-@@ -1147,13 +1199,7 @@ int ocfs2_create_new_inode_locks(struct inode *inode)
- 	 * We don't want to use LKM_LOCAL on a meta data lock as they
- 	 * don't use a generation in their lock names.
- 	 */
--	ret = ocfs2_create_new_lock(osb, &OCFS2_I(inode)->ip_meta_lockres, 1, 0);
--	if (ret) {
--		mlog_errno(ret);
--		goto bail;
--	}
--
--	ret = ocfs2_create_new_lock(osb, &OCFS2_I(inode)->ip_data_lockres, 1, 1);
-+	ret = ocfs2_create_new_lock(osb, &OCFS2_I(inode)->ip_inode_lockres, 1, 0);
- 	if (ret) {
- 		mlog_errno(ret);
- 		goto bail;
-@@ -1311,76 +1357,221 @@ out:
- 	mlog_exit_void();
- }
+ #endif /* !__ASSEMBLER__ */
  
--int ocfs2_data_lock_full(struct inode *inode,
--			 int write,
--			 int arg_flags)
-+static int ocfs2_flock_handle_signal(struct ocfs2_lock_res *lockres,
-+				     int level)
- {
--	int status = 0, level;
--	struct ocfs2_lock_res *lockres;
--	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
-+	int ret;
-+	struct ocfs2_super *osb = ocfs2_get_lockres_osb(lockres);
-+	unsigned long flags;
-+	struct ocfs2_mask_waiter mw;
+ #endif /* __ASM_AVR32_OCD_H */
+diff --git a/include/asm-avr32/processor.h b/include/asm-avr32/processor.h
+index a52576b..4212551 100644
+--- a/include/asm-avr32/processor.h
++++ b/include/asm-avr32/processor.h
+@@ -57,11 +57,25 @@ struct avr32_cpuinfo {
+ 	unsigned short cpu_revision;
+ 	enum tlb_config tlb_config;
+ 	unsigned long features;
++	u32 device_id;
  
--	BUG_ON(!inode);
-+	ocfs2_init_mask_waiter(&mw);
+ 	struct cache_info icache;
+ 	struct cache_info dcache;
+ };
  
--	mlog_entry_void();
-+retry_cancel:
-+	spin_lock_irqsave(&lockres->l_lock, flags);
-+	if (lockres->l_flags & OCFS2_LOCK_BUSY) {
-+		ret = ocfs2_prepare_cancel_convert(osb, lockres);
-+		if (ret) {
-+			spin_unlock_irqrestore(&lockres->l_lock, flags);
-+			ret = ocfs2_cancel_convert(osb, lockres);
-+			if (ret < 0) {
-+				mlog_errno(ret);
-+				goto out;
-+			}
-+			goto retry_cancel;
-+		}
-+		lockres_add_mask_waiter(lockres, &mw, OCFS2_LOCK_BUSY, 0);
-+		spin_unlock_irqrestore(&lockres->l_lock, flags);
++static inline unsigned int avr32_get_manufacturer_id(struct avr32_cpuinfo *cpu)
++{
++	return (cpu->device_id >> 1) & 0x7f;
++}
++static inline unsigned int avr32_get_product_number(struct avr32_cpuinfo *cpu)
++{
++	return (cpu->device_id >> 12) & 0xffff;
++}
++static inline unsigned int avr32_get_chip_revision(struct avr32_cpuinfo *cpu)
++{
++	return (cpu->device_id >> 28) & 0x0f;
++}
++
+ extern struct avr32_cpuinfo boot_cpu_data;
  
--	mlog(0, "inode %llu take %s DATA lock\n",
--	     (unsigned long long)OCFS2_I(inode)->ip_blkno,
--	     write ? "EXMODE" : "PRMODE");
-+		ocfs2_wait_for_mask(&mw);
-+		goto retry_cancel;
-+	}
+ #ifdef CONFIG_SMP
+diff --git a/include/asm-avr32/ptrace.h b/include/asm-avr32/ptrace.h
+index 8c5dba5..9e2d44f 100644
+--- a/include/asm-avr32/ptrace.h
++++ b/include/asm-avr32/ptrace.h
+@@ -121,7 +121,15 @@ struct pt_regs {
+ };
  
--	/* We'll allow faking a readonly data lock for
--	 * rodevices. */
--	if (ocfs2_is_hard_readonly(OCFS2_SB(inode->i_sb))) {
--		if (write) {
--			status = -EROFS;
--			mlog_errno(status);
-+	ret = -ERESTARTSYS;
-+	/*
-+	 * We may still have gotten the lock, in which case there's no
-+	 * point to restarting the syscall.
-+	 */
-+	if (lockres->l_level == level)
-+		ret = 0;
+ #ifdef __KERNEL__
+-# define user_mode(regs) (((regs)->sr & MODE_MASK) == MODE_USER)
 +
-+	mlog(0, "Cancel returning %d. flags: 0x%lx, level: %d, act: %d\n", ret,
-+	     lockres->l_flags, lockres->l_level, lockres->l_action);
++#include <asm/ocd.h>
 +
-+	spin_unlock_irqrestore(&lockres->l_lock, flags);
++#define arch_ptrace_attach(child)       ocd_enable(child)
 +
-+out:
-+	return ret;
-+}
++#define user_mode(regs)                 (((regs)->sr & MODE_MASK) == MODE_USER)
++#define instruction_pointer(regs)       ((regs)->pc)
++#define profile_pc(regs)                instruction_pointer(regs)
 +
+ extern void show_regs (struct pt_regs *);
+ 
+ static __inline__ int valid_user_regs(struct pt_regs *regs)
+@@ -141,9 +149,6 @@ static __inline__ int valid_user_regs(struct pt_regs *regs)
+ 	return 0;
+ }
+ 
+-#define instruction_pointer(regs) ((regs)->pc)
+-
+-#define profile_pc(regs) instruction_pointer(regs)
+ 
+ #endif /* __KERNEL__ */
+ 
+diff --git a/include/asm-avr32/thread_info.h b/include/asm-avr32/thread_info.h
+index 184b574..07049f6 100644
+--- a/include/asm-avr32/thread_info.h
++++ b/include/asm-avr32/thread_info.h
+@@ -88,6 +88,7 @@ static inline struct thread_info *current_thread_info(void)
+ #define TIF_MEMDIE		6
+ #define TIF_RESTORE_SIGMASK	7	/* restore signal mask in do_signal */
+ #define TIF_CPU_GOING_TO_SLEEP	8	/* CPU is entering sleep 0 mode */
++#define TIF_DEBUG		30	/* debugging enabled */
+ #define TIF_USERSPACE		31      /* true if FS sets userspace */
+ 
+ #define _TIF_SYSCALL_TRACE	(1 << TIF_SYSCALL_TRACE)
+diff --git a/include/asm-blackfin/bfin-global.h b/include/asm-blackfin/bfin-global.h
+index 39bdd86..6ae0619 100644
+--- a/include/asm-blackfin/bfin-global.h
++++ b/include/asm-blackfin/bfin-global.h
+@@ -51,7 +51,7 @@ extern unsigned long sclk_to_usecs(unsigned long sclk);
+ extern unsigned long usecs_to_sclk(unsigned long usecs);
+ 
+ extern void dump_bfin_process(struct pt_regs *regs);
+-extern void dump_bfin_mem(void *retaddr);
++extern void dump_bfin_mem(struct pt_regs *regs);
+ extern void dump_bfin_trace_buffer(void);
+ 
+ extern int init_arch_irq(void);
+diff --git a/include/asm-blackfin/cplb-mpu.h b/include/asm-blackfin/cplb-mpu.h
+new file mode 100644
+index 0000000..75c67b9
+--- /dev/null
++++ b/include/asm-blackfin/cplb-mpu.h
+@@ -0,0 +1,61 @@
 +/*
-+ * ocfs2_file_lock() and ocfs2_file_unlock() map to a single pair of
-+ * flock() calls. The locking approach this requires is sufficiently
-+ * different from all other cluster lock types that we implement a
-+ * seperate path to the "low-level" dlm calls. In particular:
++ * File:         include/asm-blackfin/cplbinit.h
++ * Based on:
++ * Author:
 + *
-+ * - No optimization of lock levels is done - we take at exactly
-+ *   what's been requested.
++ * Created:
++ * Description:
 + *
-+ * - No lock caching is employed. We immediately downconvert to
-+ *   no-lock at unlock time. This also means flock locks never go on
-+ *   the blocking list).
++ * Modified:
++ *               Copyright 2004-2006 Analog Devices Inc.
 + *
-+ * - Since userspace can trivially deadlock itself with flock, we make
-+ *   sure to allow cancellation of a misbehaving applications flock()
-+ *   request.
++ * Bugs:         Enter bugs at http://blackfin.uclinux.org/
 + *
-+ * - Access to any flock lockres doesn't require concurrency, so we
-+ *   can simplify the code by requiring the caller to guarantee
-+ *   serialization of dlmglue flock calls.
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU 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
 + */
-+int ocfs2_file_lock(struct file *file, int ex, int trylock)
-+{
-+	int ret, level = ex ? LKM_EXMODE : LKM_PRMODE;
-+	unsigned int lkm_flags = trylock ? LKM_NOQUEUE : 0;
-+	unsigned long flags;
-+	struct ocfs2_file_private *fp = file->private_data;
-+	struct ocfs2_lock_res *lockres = &fp->fp_flock;
-+	struct ocfs2_super *osb = OCFS2_SB(file->f_mapping->host->i_sb);
-+	struct ocfs2_mask_waiter mw;
++#ifndef __ASM_BFIN_CPLB_MPU_H
++#define __ASM_BFIN_CPLB_MPU_H
 +
-+	ocfs2_init_mask_waiter(&mw);
++struct cplb_entry {
++	unsigned long data, addr;
++};
 +
-+	if ((lockres->l_flags & OCFS2_LOCK_BUSY) ||
-+	    (lockres->l_level > LKM_NLMODE)) {
-+		mlog(ML_ERROR,
-+		     "File lock \"%s\" has busy or locked state: flags: 0x%lx, "
-+		     "level: %u\n", lockres->l_name, lockres->l_flags,
-+		     lockres->l_level);
-+		return -EINVAL;
-+	}
++struct mem_region {
++	unsigned long start, end;
++	unsigned long dcplb_data;
++	unsigned long icplb_data;
++};
 +
-+	spin_lock_irqsave(&lockres->l_lock, flags);
-+	if (!(lockres->l_flags & OCFS2_LOCK_ATTACHED)) {
-+		lockres_add_mask_waiter(lockres, &mw, OCFS2_LOCK_BUSY, 0);
-+		spin_unlock_irqrestore(&lockres->l_lock, flags);
++extern struct cplb_entry dcplb_tbl[MAX_CPLBS];
++extern struct cplb_entry icplb_tbl[MAX_CPLBS];
++extern int first_switched_icplb;
++extern int first_mask_dcplb;
++extern int first_switched_dcplb;
 +
-+		/*
-+		 * Get the lock at NLMODE to start - that way we
-+		 * can cancel the upconvert request if need be.
-+		 */
-+		ret = ocfs2_lock_create(osb, lockres, LKM_NLMODE, 0);
-+		if (ret < 0) {
-+			mlog_errno(ret);
-+			goto out;
- 		}
--		goto out;
++extern int nr_dcplb_miss, nr_icplb_miss, nr_icplb_supv_miss, nr_dcplb_prot;
++extern int nr_cplb_flush;
 +
-+		ret = ocfs2_wait_for_mask(&mw);
-+		if (ret) {
-+			mlog_errno(ret);
-+			goto out;
-+		}
-+		spin_lock_irqsave(&lockres->l_lock, flags);
- 	}
++extern int page_mask_order;
++extern int page_mask_nelts;
++
++extern unsigned long *current_rwx_mask;
++
++extern void flush_switched_cplbs(void);
++extern void set_mask_dcplbs(unsigned long *);
++
++extern void __noreturn panic_cplb_error(int seqstat, struct pt_regs *);
++
++#endif /* __ASM_BFIN_CPLB_MPU_H */
+diff --git a/include/asm-blackfin/cplb.h b/include/asm-blackfin/cplb.h
+index 06828d7..654375c 100644
+--- a/include/asm-blackfin/cplb.h
++++ b/include/asm-blackfin/cplb.h
+@@ -65,7 +65,11 @@
+ #define SIZE_1M 0x00100000      /* 1M */
+ #define SIZE_4M 0x00400000      /* 4M */
  
--	if (ocfs2_mount_local(osb))
--		goto out;
-+	lockres->l_action = OCFS2_AST_CONVERT;
-+	lkm_flags |= LKM_CONVERT;
-+	lockres->l_requested = level;
-+	lockres_or_flags(lockres, OCFS2_LOCK_BUSY);
++#ifdef CONFIG_MPU
++#define MAX_CPLBS 16
++#else
+ #define MAX_CPLBS (16 * 2)
++#endif
  
--	lockres = &OCFS2_I(inode)->ip_data_lockres;
-+	lockres_add_mask_waiter(lockres, &mw, OCFS2_LOCK_BUSY, 0);
-+	spin_unlock_irqrestore(&lockres->l_lock, flags);
+ #define ASYNC_MEMORY_CPLB_COVERAGE	((ASYNC_BANK0_SIZE + ASYNC_BANK1_SIZE + \
+ 				 ASYNC_BANK2_SIZE + ASYNC_BANK3_SIZE) / SIZE_4M)
+diff --git a/include/asm-blackfin/cplbinit.h b/include/asm-blackfin/cplbinit.h
+index c4d0596..0eb1c1b 100644
+--- a/include/asm-blackfin/cplbinit.h
++++ b/include/asm-blackfin/cplbinit.h
+@@ -33,6 +33,12 @@
+ #include <asm/blackfin.h>
+ #include <asm/cplb.h>
  
--	level = write ? LKM_EXMODE : LKM_PRMODE;
-+	ret = dlmlock(osb->dlm, level, &lockres->l_lksb, lkm_flags,
-+		      lockres->l_name, OCFS2_LOCK_ID_MAX_LEN - 1,
-+		      ocfs2_locking_ast, lockres, ocfs2_blocking_ast);
-+	if (ret != DLM_NORMAL) {
-+		if (trylock && ret == DLM_NOTQUEUED)
-+			ret = -EAGAIN;
-+		else {
-+			ocfs2_log_dlm_error("dlmlock", ret, lockres);
-+			ret = -EINVAL;
-+		}
++#ifdef CONFIG_MPU
++
++#include <asm/cplb-mpu.h>
++
++#else
++
+ #define INITIAL_T 0x1
+ #define SWITCH_T  0x2
+ #define I_CPLB    0x4
+@@ -79,6 +85,8 @@ extern u_long ipdt_swapcount_table[];
+ extern u_long dpdt_swapcount_table[];
+ #endif
  
--	status = ocfs2_cluster_lock(OCFS2_SB(inode->i_sb), lockres, level,
--				    0, arg_flags);
--	if (status < 0 && status != -EAGAIN)
--		mlog_errno(status);
-+		ocfs2_recover_from_dlm_error(lockres, 1);
-+		lockres_remove_mask_waiter(lockres, &mw);
-+		goto out;
-+	}
++#endif /* CONFIG_MPU */
 +
-+	ret = ocfs2_wait_for_mask_interruptible(&mw, lockres);
-+	if (ret == -ERESTARTSYS) {
-+		/*
-+		 * Userspace can cause deadlock itself with
-+		 * flock(). Current behavior locally is to allow the
-+		 * deadlock, but abort the system call if a signal is
-+		 * received. We follow this example, otherwise a
-+		 * poorly written program could sit in kernel until
-+		 * reboot.
-+		 *
-+		 * Handling this is a bit more complicated for Ocfs2
-+		 * though. We can't exit this function with an
-+		 * outstanding lock request, so a cancel convert is
-+		 * required. We intentionally overwrite 'ret' - if the
-+		 * cancel fails and the lock was granted, it's easier
-+		 * to just bubble sucess back up to the user.
-+		 */
-+		ret = ocfs2_flock_handle_signal(lockres, level);
-+	}
+ extern unsigned long reserved_mem_dcache_on;
+ extern unsigned long reserved_mem_icache_on;
+ 
+diff --git a/include/asm-blackfin/dma.h b/include/asm-blackfin/dma.h
+index b469505..5abaa2c 100644
+--- a/include/asm-blackfin/dma.h
++++ b/include/asm-blackfin/dma.h
+@@ -76,6 +76,9 @@ enum dma_chan_status {
+ #define INTR_ON_BUF    2
+ #define INTR_ON_ROW    3
+ 
++#define DMA_NOSYNC_KEEP_DMA_BUF	0
++#define DMA_SYNC_RESTART	1
++
+ struct dmasg {
+ 	unsigned long next_desc_addr;
+ 	unsigned long start_addr;
+@@ -157,7 +160,8 @@ void set_dma_y_count(unsigned int channel, unsigned short y_count);
+ void set_dma_y_modify(unsigned int channel, short y_modify);
+ void set_dma_config(unsigned int channel, unsigned short config);
+ unsigned short set_bfin_dma_config(char direction, char flow_mode,
+-				   char intr_mode, char dma_mode, char width);
++				   char intr_mode, char dma_mode, char width,
++				   char syncmode);
+ void set_dma_curr_addr(unsigned int channel, unsigned long addr);
+ 
+ /* get curr status for polling */
+diff --git a/include/asm-blackfin/gpio.h b/include/asm-blackfin/gpio.h
+index 33ce98e..d0426c1 100644
+--- a/include/asm-blackfin/gpio.h
++++ b/include/asm-blackfin/gpio.h
+@@ -7,7 +7,7 @@
+  * Description:
+  *
+  * Modified:
+- *               Copyright 2004-2006 Analog Devices Inc.
++ *               Copyright 2004-2008 Analog Devices Inc.
+  *
+  * Bugs:         Enter bugs at http://blackfin.uclinux.org/
+  *
+@@ -304,39 +304,39 @@
+ **************************************************************/
+ 
+ #ifndef BF548_FAMILY
+-void set_gpio_dir(unsigned short, unsigned short);
+-void set_gpio_inen(unsigned short, unsigned short);
+-void set_gpio_polar(unsigned short, unsigned short);
+-void set_gpio_edge(unsigned short, unsigned short);
+-void set_gpio_both(unsigned short, unsigned short);
+-void set_gpio_data(unsigned short, unsigned short);
+-void set_gpio_maska(unsigned short, unsigned short);
+-void set_gpio_maskb(unsigned short, unsigned short);
+-void set_gpio_toggle(unsigned short);
+-void set_gpiop_dir(unsigned short, unsigned short);
+-void set_gpiop_inen(unsigned short, unsigned short);
+-void set_gpiop_polar(unsigned short, unsigned short);
+-void set_gpiop_edge(unsigned short, unsigned short);
+-void set_gpiop_both(unsigned short, unsigned short);
+-void set_gpiop_data(unsigned short, unsigned short);
+-void set_gpiop_maska(unsigned short, unsigned short);
+-void set_gpiop_maskb(unsigned short, unsigned short);
+-unsigned short get_gpio_dir(unsigned short);
+-unsigned short get_gpio_inen(unsigned short);
+-unsigned short get_gpio_polar(unsigned short);
+-unsigned short get_gpio_edge(unsigned short);
+-unsigned short get_gpio_both(unsigned short);
+-unsigned short get_gpio_maska(unsigned short);
+-unsigned short get_gpio_maskb(unsigned short);
+-unsigned short get_gpio_data(unsigned short);
+-unsigned short get_gpiop_dir(unsigned short);
+-unsigned short get_gpiop_inen(unsigned short);
+-unsigned short get_gpiop_polar(unsigned short);
+-unsigned short get_gpiop_edge(unsigned short);
+-unsigned short get_gpiop_both(unsigned short);
+-unsigned short get_gpiop_maska(unsigned short);
+-unsigned short get_gpiop_maskb(unsigned short);
+-unsigned short get_gpiop_data(unsigned short);
++void set_gpio_dir(unsigned, unsigned short);
++void set_gpio_inen(unsigned, unsigned short);
++void set_gpio_polar(unsigned, unsigned short);
++void set_gpio_edge(unsigned, unsigned short);
++void set_gpio_both(unsigned, unsigned short);
++void set_gpio_data(unsigned, unsigned short);
++void set_gpio_maska(unsigned, unsigned short);
++void set_gpio_maskb(unsigned, unsigned short);
++void set_gpio_toggle(unsigned);
++void set_gpiop_dir(unsigned, unsigned short);
++void set_gpiop_inen(unsigned, unsigned short);
++void set_gpiop_polar(unsigned, unsigned short);
++void set_gpiop_edge(unsigned, unsigned short);
++void set_gpiop_both(unsigned, unsigned short);
++void set_gpiop_data(unsigned, unsigned short);
++void set_gpiop_maska(unsigned, unsigned short);
++void set_gpiop_maskb(unsigned, unsigned short);
++unsigned short get_gpio_dir(unsigned);
++unsigned short get_gpio_inen(unsigned);
++unsigned short get_gpio_polar(unsigned);
++unsigned short get_gpio_edge(unsigned);
++unsigned short get_gpio_both(unsigned);
++unsigned short get_gpio_maska(unsigned);
++unsigned short get_gpio_maskb(unsigned);
++unsigned short get_gpio_data(unsigned);
++unsigned short get_gpiop_dir(unsigned);
++unsigned short get_gpiop_inen(unsigned);
++unsigned short get_gpiop_polar(unsigned);
++unsigned short get_gpiop_edge(unsigned);
++unsigned short get_gpiop_both(unsigned);
++unsigned short get_gpiop_maska(unsigned);
++unsigned short get_gpiop_maskb(unsigned);
++unsigned short get_gpiop_data(unsigned);
  
- out:
--	mlog_exit(status);
--	return status;
-+
-+	mlog(0, "Lock: \"%s\" ex: %d, trylock: %d, returns: %d\n",
-+	     lockres->l_name, ex, trylock, ret);
-+	return ret;
- }
+ struct gpio_port_t {
+ 	unsigned short data;
+@@ -382,8 +382,8 @@ struct gpio_port_t {
+ #define PM_WAKE_LOW	0x8
+ #define PM_WAKE_BOTH_EDGES	(PM_WAKE_RISING | PM_WAKE_FALLING)
  
--/* see ocfs2_meta_lock_with_page() */
--int ocfs2_data_lock_with_page(struct inode *inode,
--			      int write,
--			      struct page *page)
-+void ocfs2_file_unlock(struct file *file)
- {
- 	int ret;
-+	unsigned long flags;
-+	struct ocfs2_file_private *fp = file->private_data;
-+	struct ocfs2_lock_res *lockres = &fp->fp_flock;
-+	struct ocfs2_super *osb = OCFS2_SB(file->f_mapping->host->i_sb);
-+	struct ocfs2_mask_waiter mw;
+-int gpio_pm_wakeup_request(unsigned short gpio, unsigned char type);
+-void gpio_pm_wakeup_free(unsigned short gpio);
++int gpio_pm_wakeup_request(unsigned gpio, unsigned char type);
++void gpio_pm_wakeup_free(unsigned gpio);
+ unsigned int gpio_pm_setup(void);
+ void gpio_pm_restore(void);
  
--	ret = ocfs2_data_lock_full(inode, write, OCFS2_LOCK_NONBLOCK);
--	if (ret == -EAGAIN) {
--		unlock_page(page);
--		if (ocfs2_data_lock(inode, write) == 0)
--			ocfs2_data_unlock(inode, write);
--		ret = AOP_TRUNCATED_PAGE;
-+	ocfs2_init_mask_waiter(&mw);
-+
-+	if (!(lockres->l_flags & OCFS2_LOCK_ATTACHED))
-+		return;
-+
-+	if (lockres->l_level == LKM_NLMODE)
-+		return;
-+
-+	mlog(0, "Unlock: \"%s\" flags: 0x%lx, level: %d, act: %d\n",
-+	     lockres->l_name, lockres->l_flags, lockres->l_level,
-+	     lockres->l_action);
-+
-+	spin_lock_irqsave(&lockres->l_lock, flags);
-+	/*
-+	 * Fake a blocking ast for the downconvert code.
-+	 */
-+	lockres_or_flags(lockres, OCFS2_LOCK_BLOCKED);
-+	lockres->l_blocking = LKM_EXMODE;
-+
-+	ocfs2_prepare_downconvert(lockres, LKM_NLMODE);
-+	lockres_add_mask_waiter(lockres, &mw, OCFS2_LOCK_BUSY, 0);
-+	spin_unlock_irqrestore(&lockres->l_lock, flags);
-+
-+	ret = ocfs2_downconvert_lock(osb, lockres, LKM_NLMODE, 0);
-+	if (ret) {
-+		mlog_errno(ret);
-+		return;
- 	}
+@@ -426,19 +426,19 @@ struct gpio_port_s {
+ * MODIFICATION HISTORY :
+ **************************************************************/
  
--	return ret;
-+	ret = ocfs2_wait_for_mask(&mw);
-+	if (ret)
-+		mlog_errno(ret);
- }
+-int gpio_request(unsigned short, const char *);
+-void gpio_free(unsigned short);
++int gpio_request(unsigned, const char *);
++void gpio_free(unsigned);
  
--static void ocfs2_vote_on_unlock(struct ocfs2_super *osb,
--				 struct ocfs2_lock_res *lockres)
-+static void ocfs2_downconvert_on_unlock(struct ocfs2_super *osb,
-+					struct ocfs2_lock_res *lockres)
- {
- 	int kick = 0;
+-void gpio_set_value(unsigned short gpio, unsigned short arg);
+-unsigned short gpio_get_value(unsigned short gpio);
++void gpio_set_value(unsigned gpio, int arg);
++int gpio_get_value(unsigned gpio);
  
- 	mlog_entry_void();
+ #ifndef BF548_FAMILY
+ #define gpio_get_value(gpio) 		get_gpio_data(gpio)
+ #define gpio_set_value(gpio, value)	set_gpio_data(gpio, value)
+ #endif
  
- 	/* If we know that another node is waiting on our lock, kick
--	 * the vote thread * pre-emptively when we reach a release
-+	 * the downconvert thread * pre-emptively when we reach a release
- 	 * condition. */
- 	if (lockres->l_flags & OCFS2_LOCK_BLOCKED) {
- 		switch(lockres->l_blocking) {
-@@ -1398,27 +1589,7 @@ static void ocfs2_vote_on_unlock(struct ocfs2_super *osb,
- 	}
+-void gpio_direction_input(unsigned short gpio);
+-void gpio_direction_output(unsigned short gpio);
++int gpio_direction_input(unsigned gpio);
++int gpio_direction_output(unsigned gpio, int value);
  
- 	if (kick)
--		ocfs2_kick_vote_thread(osb);
--
--	mlog_exit_void();
--}
--
--void ocfs2_data_unlock(struct inode *inode,
--		       int write)
--{
--	int level = write ? LKM_EXMODE : LKM_PRMODE;
--	struct ocfs2_lock_res *lockres = &OCFS2_I(inode)->ip_data_lockres;
--	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
--
--	mlog_entry_void();
--
--	mlog(0, "inode %llu drop %s DATA lock\n",
--	     (unsigned long long)OCFS2_I(inode)->ip_blkno,
--	     write ? "EXMODE" : "PRMODE");
--
--	if (!ocfs2_is_hard_readonly(OCFS2_SB(inode->i_sb)) &&
--	    !ocfs2_mount_local(osb))
--		ocfs2_cluster_unlock(OCFS2_SB(inode->i_sb), lockres, level);
-+		ocfs2_wake_downconvert_thread(osb);
+ #include <asm-generic/gpio.h>		/* cansleep wrappers */
+ #include <asm/irq.h>
+diff --git a/include/asm-blackfin/mach-bf527/bfin_serial_5xx.h b/include/asm-blackfin/mach-bf527/bfin_serial_5xx.h
+index 0b867e6..15dbc21 100644
+--- a/include/asm-blackfin/mach-bf527/bfin_serial_5xx.h
++++ b/include/asm-blackfin/mach-bf527/bfin_serial_5xx.h
+@@ -146,7 +146,7 @@ static void bfin_serial_hw_init(struct bfin_serial_port *uart)
  
- 	mlog_exit_void();
+ 	if (uart->rts_pin >= 0) {
+ 		gpio_request(uart->rts_pin, DRIVER_NAME);
+-		gpio_direction_output(uart->rts_pin);
++		gpio_direction_output(uart->rts_pin, 0);
+ 	}
+ #endif
  }
-@@ -1442,11 +1613,11 @@ static u64 ocfs2_pack_timespec(struct timespec *spec)
+diff --git a/include/asm-blackfin/mach-bf527/portmux.h b/include/asm-blackfin/mach-bf527/portmux.h
+index dcf001a..ae4d205 100644
+--- a/include/asm-blackfin/mach-bf527/portmux.h
++++ b/include/asm-blackfin/mach-bf527/portmux.h
+@@ -1,6 +1,8 @@
+ #ifndef _MACH_PORTMUX_H_
+ #define _MACH_PORTMUX_H_
  
- /* Call this with the lockres locked. I am reasonably sure we don't
-  * need ip_lock in this function as anyone who would be changing those
-- * values is supposed to be blocked in ocfs2_meta_lock right now. */
-+ * values is supposed to be blocked in ocfs2_inode_lock right now. */
- static void __ocfs2_stuff_meta_lvb(struct inode *inode)
- {
- 	struct ocfs2_inode_info *oi = OCFS2_I(inode);
--	struct ocfs2_lock_res *lockres = &oi->ip_meta_lockres;
-+	struct ocfs2_lock_res *lockres = &oi->ip_inode_lockres;
- 	struct ocfs2_meta_lvb *lvb;
++#define MAX_RESOURCES 	MAX_BLACKFIN_GPIOS
++
+ #define P_PPI0_D0	(P_DEFINED | P_IDENT(GPIO_PF0) | P_FUNCT(0))
+ #define P_PPI0_D1	(P_DEFINED | P_IDENT(GPIO_PF1) | P_FUNCT(0))
+ #define P_PPI0_D2	(P_DEFINED | P_IDENT(GPIO_PF2) | P_FUNCT(0))
+diff --git a/include/asm-blackfin/mach-bf533/anomaly.h b/include/asm-blackfin/mach-bf533/anomaly.h
+index f36ff5a..98209d4 100644
+--- a/include/asm-blackfin/mach-bf533/anomaly.h
++++ b/include/asm-blackfin/mach-bf533/anomaly.h
+@@ -7,9 +7,7 @@
+  */
  
- 	mlog_entry_void();
-@@ -1496,7 +1667,7 @@ static void ocfs2_unpack_timespec(struct timespec *spec,
- static void ocfs2_refresh_inode_from_lvb(struct inode *inode)
- {
- 	struct ocfs2_inode_info *oi = OCFS2_I(inode);
--	struct ocfs2_lock_res *lockres = &oi->ip_meta_lockres;
-+	struct ocfs2_lock_res *lockres = &oi->ip_inode_lockres;
- 	struct ocfs2_meta_lvb *lvb;
+ /* This file shoule be up to date with:
+- *  - Revision X,  March 23, 2007; ADSP-BF533 Blackfin Processor Anomaly List
+- *  - Revision AB, March 23, 2007; ADSP-BF532 Blackfin Processor Anomaly List
+- *  - Revision W,  March 23, 2007; ADSP-BF531 Blackfin Processor Anomaly List
++ *  - Revision B, 12/10/2007; ADSP-BF531/BF532/BF533 Blackfin Processor Anomaly List
+  */
  
- 	mlog_entry_void();
-@@ -1604,12 +1775,12 @@ static inline void ocfs2_complete_lock_res_refresh(struct ocfs2_lock_res *lockre
- }
+ #ifndef _MACH_ANOMALY_H_
+@@ -17,7 +15,7 @@
  
- /* may or may not return a bh if it went to disk. */
--static int ocfs2_meta_lock_update(struct inode *inode,
-+static int ocfs2_inode_lock_update(struct inode *inode,
- 				  struct buffer_head **bh)
- {
- 	int status = 0;
- 	struct ocfs2_inode_info *oi = OCFS2_I(inode);
--	struct ocfs2_lock_res *lockres = &oi->ip_meta_lockres;
-+	struct ocfs2_lock_res *lockres = &oi->ip_inode_lockres;
- 	struct ocfs2_dinode *fe;
- 	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+ /* We do not support 0.1 or 0.2 silicon - sorry */
+ #if __SILICON_REVISION__ < 3
+-# error Kernel will not work on BF533 silicon version 0.0, 0.1, or 0.2
++# error will not work on BF533 silicon version 0.0, 0.1, or 0.2
+ #endif
  
-@@ -1721,7 +1892,7 @@ static int ocfs2_assign_bh(struct inode *inode,
-  * returns < 0 error if the callback will never be called, otherwise
-  * the result of the lock will be communicated via the callback.
-  */
--int ocfs2_meta_lock_full(struct inode *inode,
-+int ocfs2_inode_lock_full(struct inode *inode,
- 			 struct buffer_head **ret_bh,
- 			 int ex,
- 			 int arg_flags)
-@@ -1756,7 +1927,7 @@ int ocfs2_meta_lock_full(struct inode *inode,
- 		wait_event(osb->recovery_event,
- 			   ocfs2_node_map_is_empty(osb, &osb->recovery_map));
+ #if defined(__ADSPBF531__)
+@@ -251,6 +249,12 @@
+ #define ANOMALY_05000192 (__SILICON_REVISION__ < 3)
+ /* Internal Voltage Regulator may not start up */
+ #define ANOMALY_05000206 (__SILICON_REVISION__ < 3)
++/* Serial Port (SPORT) Multichannel Transmit Failure when Channel 0 Is Disabled */
++#define ANOMALY_05000357 (1)
++/* 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)
  
--	lockres = &OCFS2_I(inode)->ip_meta_lockres;
-+	lockres = &OCFS2_I(inode)->ip_inode_lockres;
- 	level = ex ? LKM_EXMODE : LKM_PRMODE;
- 	dlm_flags = 0;
- 	if (arg_flags & OCFS2_META_LOCK_NOQUEUE)
-@@ -1795,11 +1966,11 @@ local:
+ /* Anomalies that don't exist on this proc */
+ #define ANOMALY_05000266 (0)
+diff --git a/include/asm-blackfin/mach-bf533/bfin_serial_5xx.h b/include/asm-blackfin/mach-bf533/bfin_serial_5xx.h
+index 69b9f8e..7871d43 100644
+--- a/include/asm-blackfin/mach-bf533/bfin_serial_5xx.h
++++ b/include/asm-blackfin/mach-bf533/bfin_serial_5xx.h
+@@ -111,7 +111,7 @@ static void bfin_serial_hw_init(struct bfin_serial_port *uart)
  	}
- 
- 	/* This is fun. The caller may want a bh back, or it may
--	 * not. ocfs2_meta_lock_update definitely wants one in, but
-+	 * not. ocfs2_inode_lock_update definitely wants one in, but
- 	 * may or may not read one, depending on what's in the
- 	 * LVB. The result of all of this is that we've *only* gone to
- 	 * disk if we have to, so the complexity is worthwhile. */
--	status = ocfs2_meta_lock_update(inode, &local_bh);
-+	status = ocfs2_inode_lock_update(inode, &local_bh);
- 	if (status < 0) {
- 		if (status != -ENOENT)
- 			mlog_errno(status);
-@@ -1821,7 +1992,7 @@ bail:
- 			*ret_bh = NULL;
- 		}
- 		if (acquired)
--			ocfs2_meta_unlock(inode, ex);
-+			ocfs2_inode_unlock(inode, ex);
+ 	if (uart->rts_pin >= 0) {
+ 		gpio_request(uart->rts_pin, DRIVER_NAME);
+-		gpio_direction_input(uart->rts_pin);
++		gpio_direction_input(uart->rts_pin, 0);
  	}
- 
- 	if (local_bh)
-@@ -1832,19 +2003,20 @@ bail:
+ #endif
  }
+diff --git a/include/asm-blackfin/mach-bf533/portmux.h b/include/asm-blackfin/mach-bf533/portmux.h
+index 137f488..685a265 100644
+--- a/include/asm-blackfin/mach-bf533/portmux.h
++++ b/include/asm-blackfin/mach-bf533/portmux.h
+@@ -1,6 +1,8 @@
+ #ifndef _MACH_PORTMUX_H_
+ #define _MACH_PORTMUX_H_
  
- /*
-- * This is working around a lock inversion between tasks acquiring DLM locks
-- * while holding a page lock and the vote thread which blocks dlm lock acquiry
-- * while acquiring page locks.
-+ * This is working around a lock inversion between tasks acquiring DLM
-+ * locks while holding a page lock and the downconvert thread which
-+ * blocks dlm lock acquiry while acquiring page locks.
-  *
-  * ** These _with_page variantes are only intended to be called from aop
-  * methods that hold page locks and return a very specific *positive* error
-  * code that aop methods pass up to the VFS -- test for errors with != 0. **
-  *
-- * The DLM is called such that it returns -EAGAIN if it would have blocked
-- * waiting for the vote thread.  In that case we unlock our page so the vote
-- * thread can make progress.  Once we've done this we have to return
-- * AOP_TRUNCATED_PAGE so the aop method that called us can bubble that back up
-- * into the VFS who will then immediately retry the aop call.
-+ * The DLM is called such that it returns -EAGAIN if it would have
-+ * blocked waiting for the downconvert thread.  In that case we unlock
-+ * our page so the downconvert thread can make progress.  Once we've
-+ * done this we have to return AOP_TRUNCATED_PAGE so the aop method
-+ * that called us can bubble that back up into the VFS who will then
-+ * immediately retry the aop call.
-  *
-  * We do a blocking lock and immediate unlock before returning, though, so that
-  * the lock has a great chance of being cached on this node by the time the VFS
-@@ -1852,32 +2024,32 @@ bail:
-  * ping locks back and forth, but that's a risk we're willing to take to avoid
-  * the lock inversion simply.
++#define MAX_RESOURCES 	MAX_BLACKFIN_GPIOS
++
+ #define P_PPI0_CLK	(P_DONTCARE)
+ #define P_PPI0_FS1	(P_DONTCARE)
+ #define P_PPI0_FS2	(P_DONTCARE)
+diff --git a/include/asm-blackfin/mach-bf537/anomaly.h b/include/asm-blackfin/mach-bf537/anomaly.h
+index 2b66ecf..746a794 100644
+--- a/include/asm-blackfin/mach-bf537/anomaly.h
++++ b/include/asm-blackfin/mach-bf537/anomaly.h
+@@ -7,9 +7,7 @@
   */
--int ocfs2_meta_lock_with_page(struct inode *inode,
-+int ocfs2_inode_lock_with_page(struct inode *inode,
- 			      struct buffer_head **ret_bh,
- 			      int ex,
- 			      struct page *page)
- {
- 	int ret;
  
--	ret = ocfs2_meta_lock_full(inode, ret_bh, ex, OCFS2_LOCK_NONBLOCK);
-+	ret = ocfs2_inode_lock_full(inode, ret_bh, ex, OCFS2_LOCK_NONBLOCK);
- 	if (ret == -EAGAIN) {
- 		unlock_page(page);
--		if (ocfs2_meta_lock(inode, ret_bh, ex) == 0)
--			ocfs2_meta_unlock(inode, ex);
-+		if (ocfs2_inode_lock(inode, ret_bh, ex) == 0)
-+			ocfs2_inode_unlock(inode, ex);
- 		ret = AOP_TRUNCATED_PAGE;
- 	}
+ /* This file shoule be up to date with:
+- *  - Revision M, March 13, 2007; ADSP-BF537 Blackfin Processor Anomaly List
+- *  - Revision L, March 13, 2007; ADSP-BF536 Blackfin Processor Anomaly List
+- *  - Revision M, March 13, 2007; ADSP-BF534 Blackfin Processor Anomaly List
++ *  - Revision A, 09/04/2007; ADSP-BF534/ADSP-BF536/ADSP-BF537 Blackfin Processor Anomaly List
+  */
  
- 	return ret;
- }
+ #ifndef _MACH_ANOMALY_H_
+@@ -17,7 +15,7 @@
  
--int ocfs2_meta_lock_atime(struct inode *inode,
-+int ocfs2_inode_lock_atime(struct inode *inode,
- 			  struct vfsmount *vfsmnt,
- 			  int *level)
- {
- 	int ret;
+ /* We do not support 0.1 silicon - sorry */
+ #if __SILICON_REVISION__ < 2
+-# error Kernel will not work on BF537 silicon version 0.0 or 0.1
++# error will not work on BF537 silicon version 0.0 or 0.1
+ #endif
  
- 	mlog_entry_void();
--	ret = ocfs2_meta_lock(inode, NULL, 0);
-+	ret = ocfs2_inode_lock(inode, NULL, 0);
- 	if (ret < 0) {
- 		mlog_errno(ret);
- 		return ret;
-@@ -1890,8 +2062,8 @@ int ocfs2_meta_lock_atime(struct inode *inode,
- 	if (ocfs2_should_update_atime(inode, vfsmnt)) {
- 		struct buffer_head *bh = NULL;
+ #if defined(__ADSPBF534__)
+@@ -44,6 +42,8 @@
+ #define ANOMALY_05000122 (1)
+ /* Killed 32-bit MMR write leads to next system MMR access thinking it should be 32-bit */
+ #define ANOMALY_05000157 (__SILICON_REVISION__ < 2)
++/* Turning SPORTs on while External Frame Sync Is Active May Corrupt Data */
++#define ANOMALY_05000167 (1)
+ /* PPI_DELAY not functional in PPI modes with 0 frame syncs */
+ #define ANOMALY_05000180 (1)
+ /* Instruction Cache Is Not Functional */
+@@ -130,6 +130,12 @@
+ #define ANOMALY_05000321 (__SILICON_REVISION__ < 3)
+ /* EMAC RMII mode at 10-Base-T speed: RX frames not received properly */
+ #define ANOMALY_05000322 (1)
++/* Ethernet MAC MDIO Reads Do Not Meet IEEE Specification */
++#define ANOMALY_05000341 (__SILICON_REVISION__ >= 3)
++/* Serial Port (SPORT) Multichannel Transmit Failure when Channel 0 Is Disabled */
++#define ANOMALY_05000357 (1)
++/* DMAs that Go Urgent during Tight Core Writes to External Memory Are Blocked */
++#define ANOMALY_05000359 (1)
  
--		ocfs2_meta_unlock(inode, 0);
--		ret = ocfs2_meta_lock(inode, &bh, 1);
-+		ocfs2_inode_unlock(inode, 0);
-+		ret = ocfs2_inode_lock(inode, &bh, 1);
- 		if (ret < 0) {
- 			mlog_errno(ret);
- 			return ret;
-@@ -1908,11 +2080,11 @@ int ocfs2_meta_lock_atime(struct inode *inode,
- 	return ret;
+ /* Anomalies that don't exist on this proc */
+ #define ANOMALY_05000125 (0)
+diff --git a/include/asm-blackfin/mach-bf537/bfin_serial_5xx.h b/include/asm-blackfin/mach-bf537/bfin_serial_5xx.h
+index 6fb328f..86e45c3 100644
+--- a/include/asm-blackfin/mach-bf537/bfin_serial_5xx.h
++++ b/include/asm-blackfin/mach-bf537/bfin_serial_5xx.h
+@@ -146,7 +146,7 @@ static void bfin_serial_hw_init(struct bfin_serial_port *uart)
+ 
+ 	if (uart->rts_pin >= 0) {
+ 		gpio_request(uart->rts_pin, DRIVER_NAME);
+-		gpio_direction_output(uart->rts_pin);
++		gpio_direction_output(uart->rts_pin, 0);
+ 	}
+ #endif
  }
+diff --git a/include/asm-blackfin/mach-bf537/portmux.h b/include/asm-blackfin/mach-bf537/portmux.h
+index 5a3f7d3..78fee6e 100644
+--- a/include/asm-blackfin/mach-bf537/portmux.h
++++ b/include/asm-blackfin/mach-bf537/portmux.h
+@@ -1,6 +1,8 @@
+ #ifndef _MACH_PORTMUX_H_
+ #define _MACH_PORTMUX_H_
  
--void ocfs2_meta_unlock(struct inode *inode,
-+void ocfs2_inode_unlock(struct inode *inode,
- 		       int ex)
- {
- 	int level = ex ? LKM_EXMODE : LKM_PRMODE;
--	struct ocfs2_lock_res *lockres = &OCFS2_I(inode)->ip_meta_lockres;
-+	struct ocfs2_lock_res *lockres = &OCFS2_I(inode)->ip_inode_lockres;
- 	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
++#define MAX_RESOURCES 	(MAX_BLACKFIN_GPIOS + GPIO_BANKSIZE)	/* We additionally handle PORTJ */
++
+ #define P_UART0_TX	(P_DEFINED | P_IDENT(GPIO_PF0) | P_FUNCT(0))
+ #define P_UART0_RX	(P_DEFINED | P_IDENT(GPIO_PF1) | P_FUNCT(0))
+ #define P_UART1_TX	(P_DEFINED | P_IDENT(GPIO_PF2) | P_FUNCT(0))
+diff --git a/include/asm-blackfin/mach-bf548/anomaly.h b/include/asm-blackfin/mach-bf548/anomaly.h
+index c5b6375..850dc12 100644
+--- a/include/asm-blackfin/mach-bf548/anomaly.h
++++ b/include/asm-blackfin/mach-bf548/anomaly.h
+@@ -7,7 +7,7 @@
+  */
  
- 	mlog_entry_void();
-@@ -2320,11 +2492,11 @@ int ocfs2_dlm_init(struct ocfs2_super *osb)
- 		goto bail;
- 	}
+ /* This file shoule be up to date with:
+- *  - Revision C, July 16, 2007; ADSP-BF549 Silicon Anomaly List
++ *  - Revision E, 11/28/2007; ADSP-BF542/BF544/BF547/BF548/BF549 Blackfin Processor Anomaly List
+  */
  
--	/* launch vote thread */
--	osb->vote_task = kthread_run(ocfs2_vote_thread, osb, "ocfs2vote");
--	if (IS_ERR(osb->vote_task)) {
--		status = PTR_ERR(osb->vote_task);
--		osb->vote_task = NULL;
-+	/* launch downconvert thread */
-+	osb->dc_task = kthread_run(ocfs2_downconvert_thread, osb, "ocfs2dc");
-+	if (IS_ERR(osb->dc_task)) {
-+		status = PTR_ERR(osb->dc_task);
-+		osb->dc_task = NULL;
- 		mlog_errno(status);
- 		goto bail;
- 	}
-@@ -2353,8 +2525,8 @@ local:
- bail:
- 	if (status < 0) {
- 		ocfs2_dlm_shutdown_debug(osb);
--		if (osb->vote_task)
--			kthread_stop(osb->vote_task);
-+		if (osb->dc_task)
-+			kthread_stop(osb->dc_task);
+ #ifndef _MACH_ANOMALY_H_
+@@ -26,47 +26,59 @@
+ /* Certain Data Cache Writethrough Modes Fail for Vddint <= 0.9V */
+ #define ANOMALY_05000272 (1)
+ /* False Hardware Error Exception when ISR context is not restored */
+-#define ANOMALY_05000281 (1)
++#define ANOMALY_05000281 (__SILICON_REVISION__ < 1)
+ /* SSYNCs After Writes To CAN/DMA MMR Registers Are Not Always Handled Correctly */
+-#define ANOMALY_05000304 (1)
++#define ANOMALY_05000304 (__SILICON_REVISION__ < 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 (__SILICON_REVISION__ < 1)
+ /* TWI Slave Boot Mode Is Not Functional */
+-#define ANOMALY_05000324 (1)
++#define ANOMALY_05000324 (__SILICON_REVISION__ < 1)
+ /* External FIFO Boot Mode Is Not Functional */
+-#define ANOMALY_05000325 (1)
++#define ANOMALY_05000325 (__SILICON_REVISION__ < 1)
+ /* Data Lost When Core and DMA Accesses Are Made to the USB FIFO Simultaneously */
+-#define ANOMALY_05000327 (1)
++#define ANOMALY_05000327 (__SILICON_REVISION__ < 1)
+ /* Incorrect Access of OTP_STATUS During otp_write() Function */
+-#define ANOMALY_05000328 (1)
++#define ANOMALY_05000328 (__SILICON_REVISION__ < 1)
+ /* Synchronous Burst Flash Boot Mode Is Not Functional */
+-#define ANOMALY_05000329 (1)
++#define ANOMALY_05000329 (__SILICON_REVISION__ < 1)
+ /* Host DMA Boot Mode Is Not Functional */
+-#define ANOMALY_05000330 (1)
++#define ANOMALY_05000330 (__SILICON_REVISION__ < 1)
+ /* Inadequate Timing Margins on DDR DQS to DQ and DQM Skew */
+-#define ANOMALY_05000334 (1)
++#define ANOMALY_05000334 (__SILICON_REVISION__ < 1)
+ /* Inadequate Rotary Debounce Logic Duration */
+-#define ANOMALY_05000335 (1)
++#define ANOMALY_05000335 (__SILICON_REVISION__ < 1)
+ /* Phantom Interrupt Occurs After First Configuration of Host DMA Port */
+-#define ANOMALY_05000336 (1)
++#define ANOMALY_05000336 (__SILICON_REVISION__ < 1)
+ /* Disallowed Configuration Prevents Subsequent Allowed Configuration on Host DMA Port */
+-#define ANOMALY_05000337 (1)
++#define ANOMALY_05000337 (__SILICON_REVISION__ < 1)
+ /* Slave-Mode SPI0 MISO Failure With CPHA = 0 */
+-#define ANOMALY_05000338 (1)
++#define ANOMALY_05000338 (__SILICON_REVISION__ < 1)
+ /* If Memory Reads Are Enabled on SDH or HOSTDP, Other DMAC1 Peripherals Cannot Read */
+-#define ANOMALY_05000340 (1)
++#define ANOMALY_05000340 (__SILICON_REVISION__ < 1)
+ /* Boot Host Wait (HWAIT) and Boot Host Wait Alternate (HWAITA) Signals Are Swapped */
+-#define ANOMALY_05000344 (1)
++#define ANOMALY_05000344 (__SILICON_REVISION__ < 1)
+ /* USB Calibration Value Is Not Intialized */
+-#define ANOMALY_05000346 (1)
++#define ANOMALY_05000346 (__SILICON_REVISION__ < 1)
+ /* Boot ROM Kernel Incorrectly Alters Reset Value of USB Register */
+-#define ANOMALY_05000347 (1)
++#define ANOMALY_05000347 (__SILICON_REVISION__ < 1)
+ /* Data Lost when Core Reads SDH Data FIFO */
+-#define ANOMALY_05000349 (1)
++#define ANOMALY_05000349 (__SILICON_REVISION__ < 1)
+ /* PLL Status Register Is Inaccurate */
+-#define ANOMALY_05000351 (1)
++#define ANOMALY_05000351 (__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)
++/* Addressing Conflict between Boot ROM and Asynchronous Memory */
++#define ANOMALY_05000369 (1)
++/* Mobile DDR Operation Not Functional */
++#define ANOMALY_05000377 (1)
++/* Security/Authentication Speedpath Causes Authentication To Fail To Initiate */
++#define ANOMALY_05000378 (1)
+ 
+ /* Anomalies that don't exist on this proc */
+ #define ANOMALY_05000125 (0)
+diff --git a/include/asm-blackfin/mach-bf548/bfin_serial_5xx.h b/include/asm-blackfin/mach-bf548/bfin_serial_5xx.h
+index f21a162..3770aa3 100644
+--- a/include/asm-blackfin/mach-bf548/bfin_serial_5xx.h
++++ b/include/asm-blackfin/mach-bf548/bfin_serial_5xx.h
+@@ -186,7 +186,7 @@ static void bfin_serial_hw_init(struct bfin_serial_port *uart)
+ 
+ 	if (uart->rts_pin >= 0) {
+ 		gpio_request(uart->rts_pin, DRIVER_NAME);
+-		gpio_direction_output(uart->rts_pin);
++		gpio_direction_output(uart->rts_pin, 0);
  	}
+ #endif
+ }
+diff --git a/include/asm-blackfin/mach-bf548/cdefBF54x_base.h b/include/asm-blackfin/mach-bf548/cdefBF54x_base.h
+index aefab3f..19ddcd8 100644
+--- a/include/asm-blackfin/mach-bf548/cdefBF54x_base.h
++++ b/include/asm-blackfin/mach-bf548/cdefBF54x_base.h
+@@ -244,39 +244,6 @@ static __inline__ void bfin_write_VR_CTL(unsigned int val)
+ #define bfin_read_TWI0_RCV_DATA16()		bfin_read16(TWI0_RCV_DATA16)
+ #define bfin_write_TWI0_RCV_DATA16(val)		bfin_write16(TWI0_RCV_DATA16, val)
  
- 	mlog_exit(status);
-@@ -2369,9 +2541,9 @@ void ocfs2_dlm_shutdown(struct ocfs2_super *osb)
+-#define bfin_read_TWI_CLKDIV()			bfin_read16(TWI0_CLKDIV)
+-#define bfin_write_TWI_CLKDIV(val)		bfin_write16(TWI0_CLKDIV, val)
+-#define bfin_read_TWI_CONTROL()			bfin_read16(TWI0_CONTROL)
+-#define bfin_write_TWI_CONTROL(val)		bfin_write16(TWI0_CONTROL, val)
+-#define bfin_read_TWI_SLAVE_CTRL()		bfin_read16(TWI0_SLAVE_CTRL)
+-#define bfin_write_TWI_SLAVE_CTRL(val)		bfin_write16(TWI0_SLAVE_CTRL, val)
+-#define bfin_read_TWI_SLAVE_STAT()		bfin_read16(TWI0_SLAVE_STAT)
+-#define bfin_write_TWI_SLAVE_STAT(val)		bfin_write16(TWI0_SLAVE_STAT, val)
+-#define bfin_read_TWI_SLAVE_ADDR()		bfin_read16(TWI0_SLAVE_ADDR)
+-#define bfin_write_TWI_SLAVE_ADDR(val)		bfin_write16(TWI0_SLAVE_ADDR, val)
+-#define bfin_read_TWI_MASTER_CTL()		bfin_read16(TWI0_MASTER_CTRL)
+-#define bfin_write_TWI_MASTER_CTL(val)		bfin_write16(TWI0_MASTER_CTRL, val)
+-#define bfin_read_TWI_MASTER_STAT()		bfin_read16(TWI0_MASTER_STAT)
+-#define bfin_write_TWI_MASTER_STAT(val)		bfin_write16(TWI0_MASTER_STAT, val)
+-#define bfin_read_TWI_MASTER_ADDR()		bfin_read16(TWI0_MASTER_ADDR)
+-#define bfin_write_TWI_MASTER_ADDR(val)		bfin_write16(TWI0_MASTER_ADDR, val)
+-#define bfin_read_TWI_INT_STAT()		bfin_read16(TWI0_INT_STAT)
+-#define bfin_write_TWI_INT_STAT(val)		bfin_write16(TWI0_INT_STAT, val)
+-#define bfin_read_TWI_INT_MASK()		bfin_read16(TWI0_INT_MASK)
+-#define bfin_write_TWI_INT_MASK(val)		bfin_write16(TWI0_INT_MASK, val)
+-#define bfin_read_TWI_FIFO_CTL()		bfin_read16(TWI0_FIFO_CTRL)
+-#define bfin_write_TWI_FIFO_CTL(val)		bfin_write16(TWI0_FIFO_CTRL, val)
+-#define bfin_read_TWI_FIFO_STAT()		bfin_read16(TWI0_FIFO_STAT)
+-#define bfin_write_TWI_FIFO_STAT(val)		bfin_write16(TWI0_FIFO_STAT, val)
+-#define bfin_read_TWI_XMT_DATA8()		bfin_read16(TWI0_XMT_DATA8)
+-#define bfin_write_TWI_XMT_DATA8(val)		bfin_write16(TWI0_XMT_DATA8, val)
+-#define bfin_read_TWI_XMT_DATA16()		bfin_read16(TWI0_XMT_DATA16)
+-#define bfin_write_TWI_XMT_DATA16(val)		bfin_write16(TWI0_XMT_DATA16, val)
+-#define bfin_read_TWI_RCV_DATA8()		bfin_read16(TWI0_RCV_DATA8)
+-#define bfin_write_TWI_RCV_DATA8(val)		bfin_write16(TWI0_RCV_DATA8, val)
+-#define bfin_read_TWI_RCV_DATA16()		bfin_read16(TWI0_RCV_DATA16)
+-#define bfin_write_TWI_RCV_DATA16(val)		bfin_write16(TWI0_RCV_DATA16, val)
+-
+ /* SPORT0 is not defined in the shared file because it is not available on the ADSP-BF542 and ADSP-BF544 bfin_read_()rocessors */
  
- 	ocfs2_drop_osb_locks(osb);
+ /* SPORT1 Registers */
+diff --git a/include/asm-blackfin/mach-bf548/defBF542.h b/include/asm-blackfin/mach-bf548/defBF542.h
+index 32d0713..a7c809f 100644
+--- a/include/asm-blackfin/mach-bf548/defBF542.h
++++ b/include/asm-blackfin/mach-bf548/defBF542.h
+@@ -432,8 +432,8 @@
  
--	if (osb->vote_task) {
--		kthread_stop(osb->vote_task);
--		osb->vote_task = NULL;
-+	if (osb->dc_task) {
-+		kthread_stop(osb->dc_task);
-+		osb->dc_task = NULL;
- 	}
+ #define              CMD_CRC_FAIL  0x1        /* CMD CRC Fail */
+ #define              DAT_CRC_FAIL  0x2        /* Data CRC Fail */
+-#define               CMD_TIMEOUT  0x4        /* CMD Time Out */
+-#define               DAT_TIMEOUT  0x8        /* Data Time Out */
++#define               CMD_TIME_OUT  0x4        /* CMD Time Out */
++#define               DAT_TIME_OUT  0x8        /* Data Time Out */
+ #define               TX_UNDERRUN  0x10       /* Transmit Underrun */
+ #define                RX_OVERRUN  0x20       /* Receive Overrun */
+ #define              CMD_RESP_END  0x40       /* CMD Response End */
+diff --git a/include/asm-blackfin/mach-bf548/defBF548.h b/include/asm-blackfin/mach-bf548/defBF548.h
+index ecbca95..e46f568 100644
+--- a/include/asm-blackfin/mach-bf548/defBF548.h
++++ b/include/asm-blackfin/mach-bf548/defBF548.h
+@@ -1095,8 +1095,8 @@
  
- 	ocfs2_lock_res_free(&osb->osb_super_lockres);
-@@ -2527,7 +2699,7 @@ out:
+ #define              CMD_CRC_FAIL  0x1        /* CMD CRC Fail */
+ #define              DAT_CRC_FAIL  0x2        /* Data CRC Fail */
+-#define               CMD_TIMEOUT  0x4        /* CMD Time Out */
+-#define               DAT_TIMEOUT  0x8        /* Data Time Out */
++#define               CMD_TIME_OUT  0x4        /* CMD Time Out */
++#define               DAT_TIME_OUT  0x8        /* Data Time Out */
+ #define               TX_UNDERRUN  0x10       /* Transmit Underrun */
+ #define                RX_OVERRUN  0x20       /* Receive Overrun */
+ #define              CMD_RESP_END  0x40       /* CMD Response End */
+diff --git a/include/asm-blackfin/mach-bf548/defBF54x_base.h b/include/asm-blackfin/mach-bf548/defBF54x_base.h
+index 319a485..08f90c2 100644
+--- a/include/asm-blackfin/mach-bf548/defBF54x_base.h
++++ b/include/asm-blackfin/mach-bf548/defBF54x_base.h
+@@ -1772,17 +1772,36 @@
+ #define                       TRP  0x3c0000   /* Pre charge-to-active command period */
+ #define                      TRAS  0x3c00000  /* Min Active-to-pre charge time */
+ #define                       TRC  0x3c000000 /* Active-to-active time */
++#define DDR_TRAS(x)		((x<<22)&TRAS)	/* DDR tRAS = (1~15) cycles */
++#define DDR_TRP(x)		((x<<18)&TRP)	/* DDR tRP = (1~15) cycles */
++#define DDR_TRC(x)		((x<<26)&TRC)	/* DDR tRC = (1~15) cycles */
++#define DDR_TRFC(x)		((x<<14)&TRFC)	/* DDR tRFC = (1~15) cycles */
++#define DDR_TREFI(x)		(x&TREFI)	/* DDR tRFC = (1~15) cycles */
  
- /* Mark the lockres as being dropped. It will no longer be
-  * queued if blocking, but we still may have to wait on it
-- * being dequeued from the vote thread before we can consider
-+ * being dequeued from the downconvert thread before we can consider
-  * it safe to drop. 
-  *
-  * You can *not* attempt to call cluster_lock on this lockres anymore. */
-@@ -2590,14 +2762,7 @@ int ocfs2_drop_inode_locks(struct inode *inode)
- 	status = err;
+ /* Bit masks for EBIU_DDRCTL1 */
  
- 	err = ocfs2_drop_lock(OCFS2_SB(inode->i_sb),
--			      &OCFS2_I(inode)->ip_data_lockres);
--	if (err < 0)
--		mlog_errno(err);
--	if (err < 0 && !status)
--		status = err;
--
--	err = ocfs2_drop_lock(OCFS2_SB(inode->i_sb),
--			      &OCFS2_I(inode)->ip_meta_lockres);
-+			      &OCFS2_I(inode)->ip_inode_lockres);
- 	if (err < 0)
- 		mlog_errno(err);
- 	if (err < 0 && !status)
-@@ -2850,6 +3015,9 @@ static int ocfs2_data_convert_worker(struct ocfs2_lock_res *lockres,
-        	inode = ocfs2_lock_res_inode(lockres);
- 	mapping = inode->i_mapping;
+ #define                      TRCD  0xf        /* Active-to-Read/write delay */
+-#define                       MRD  0xf0       /* Mode register set to active */
++#define                      TMRD  0xf0       /* Mode register set to active */
+ #define                       TWR  0x300      /* Write Recovery time */
+ #define               DDRDATWIDTH  0x3000     /* DDR data width */
+ #define                  EXTBANKS  0xc000     /* External banks */
+ #define               DDRDEVWIDTH  0x30000    /* DDR device width */
+ #define                DDRDEVSIZE  0xc0000    /* DDR device size */
+-#define                     TWWTR  0xf0000000 /* Write-to-read delay */
++#define                      TWTR  0xf0000000 /* Write-to-read delay */
++#define DDR_TWTR(x)		((x<<28)&TWTR)	/* DDR tWTR = (1~15) cycles */
++#define DDR_TMRD(x)		((x<<4)&TMRD)	/* DDR tMRD = (1~15) cycles */
++#define DDR_TWR(x)		((x<<8)&TWR)	/* DDR tWR = (1~15) cycles */
++#define DDR_TRCD(x)		(x&TRCD)	/* DDR tRCD = (1~15) cycles */
++#define DDR_DATWIDTH		0x2000		/* DDR data width */
++#define EXTBANK_1		0		/* 1 external bank */
++#define EXTBANK_2		0x4000		/* 2 external banks */
++#define DEVSZ_64		0x40000		/* DDR External Bank Size = 64MB */
++#define DEVSZ_128		0x80000		/* DDR External Bank Size = 128MB */
++#define DEVSZ_256		0xc0000		/* DDR External Bank Size = 256MB */
++#define DEVSZ_512		0		/* DDR External Bank Size = 512MB */
++#define DEVWD_4			0		/* DDR Device Width = 4 Bits    */
++#define DEVWD_8			0x10000		/* DDR Device Width = 8 Bits    */
++#define DEVWD_16		0x20000		/* DDR Device Width = 16 Bits    */
  
-+	if (S_ISREG(inode->i_mode))
-+		goto out;
-+
- 	/*
- 	 * We need this before the filemap_fdatawrite() so that it can
- 	 * transfer the dirty bit from the PTE to the
-@@ -2875,6 +3043,7 @@ static int ocfs2_data_convert_worker(struct ocfs2_lock_res *lockres,
- 		filemap_fdatawait(mapping);
- 	}
+ /* Bit masks for EBIU_DDRCTL2 */
  
-+out:
- 	return UNBLOCK_CONTINUE;
- }
+@@ -1790,6 +1809,10 @@
+ #define                CASLATENCY  0x70       /* CAS latency */
+ #define                  DLLRESET  0x100      /* DLL Reset */
+ #define                      REGE  0x1000     /* Register mode enable */
++#define CL_1_5			0x50		/* DDR CAS Latency = 1.5 cycles */
++#define CL_2			0x20		/* DDR CAS Latency = 2 cycles */
++#define CL_2_5			0x60		/* DDR CAS Latency = 2.5 cycles */
++#define CL_3			0x30		/* DDR CAS Latency = 3 cycles */
  
-@@ -2903,7 +3072,7 @@ static void ocfs2_set_meta_lvb(struct ocfs2_lock_res *lockres)
+ /* Bit masks for EBIU_DDRCTL3 */
  
- /*
-  * Does the final reference drop on our dentry lock. Right now this
-- * happens in the vote thread, but we could choose to simplify the
-+ * happens in the downconvert thread, but we could choose to simplify the
-  * dlmglue API and push these off to the ocfs2_wq in the future.
-  */
- static void ocfs2_dentry_post_unlock(struct ocfs2_super *osb,
-@@ -3042,7 +3211,7 @@ void ocfs2_process_blocked_lock(struct ocfs2_super *osb,
- 	mlog(0, "lockres %s blocked.\n", lockres->l_name);
+@@ -2257,6 +2280,10 @@
  
- 	/* Detect whether a lock has been marked as going away while
--	 * the vote thread was processing other things. A lock can
-+	 * the downconvert thread was processing other things. A lock can
- 	 * still be marked with OCFS2_LOCK_FREEING after this check,
- 	 * but short circuiting here will still save us some
- 	 * performance. */
-@@ -3091,13 +3260,104 @@ static void ocfs2_schedule_blocked_lock(struct ocfs2_super *osb,
+ #define                      CSEL  0x30       /* Core Select */
+ #define                      SSEL  0xf        /* System Select */
++#define			CSEL_DIV1	0x0000	/* CCLK = VCO / 1 */
++#define			CSEL_DIV2	0x0010	/* CCLK = VCO / 2 */
++#define			CSEL_DIV4	0x0020	/* CCLK = VCO / 4 */
++#define			CSEL_DIV8	0x0030	/* CCLK = VCO / 8 */
  
- 	lockres_or_flags(lockres, OCFS2_LOCK_QUEUED);
+ /* Bit masks for PLL_CTL */
  
--	spin_lock(&osb->vote_task_lock);
-+	spin_lock(&osb->dc_task_lock);
- 	if (list_empty(&lockres->l_blocked_list)) {
- 		list_add_tail(&lockres->l_blocked_list,
- 			      &osb->blocked_lock_list);
- 		osb->blocked_lock_count++;
- 	}
--	spin_unlock(&osb->vote_task_lock);
-+	spin_unlock(&osb->dc_task_lock);
-+
-+	mlog_exit_void();
-+}
-+
-+static void ocfs2_downconvert_thread_do_work(struct ocfs2_super *osb)
-+{
-+	unsigned long processed;
-+	struct ocfs2_lock_res *lockres;
-+
-+	mlog_entry_void();
-+
-+	spin_lock(&osb->dc_task_lock);
-+	/* grab this early so we know to try again if a state change and
-+	 * wake happens part-way through our work  */
-+	osb->dc_work_sequence = osb->dc_wake_sequence;
-+
-+	processed = osb->blocked_lock_count;
-+	while (processed) {
-+		BUG_ON(list_empty(&osb->blocked_lock_list));
-+
-+		lockres = list_entry(osb->blocked_lock_list.next,
-+				     struct ocfs2_lock_res, l_blocked_list);
-+		list_del_init(&lockres->l_blocked_list);
-+		osb->blocked_lock_count--;
-+		spin_unlock(&osb->dc_task_lock);
-+
-+		BUG_ON(!processed);
-+		processed--;
-+
-+		ocfs2_process_blocked_lock(osb, lockres);
-+
-+		spin_lock(&osb->dc_task_lock);
-+	}
-+	spin_unlock(&osb->dc_task_lock);
+diff --git a/include/asm-blackfin/mach-bf548/irq.h b/include/asm-blackfin/mach-bf548/irq.h
+index 9fb7bc5..c34507a 100644
+--- a/include/asm-blackfin/mach-bf548/irq.h
++++ b/include/asm-blackfin/mach-bf548/irq.h
+@@ -88,7 +88,7 @@ Events         (highest priority)  EMU         0
+ #define IRQ_PINT1		BFIN_IRQ(20)	/* PINT1 Interrupt */
+ #define IRQ_MDMAS0		BFIN_IRQ(21)	/* MDMA Stream 0 Interrupt */
+ #define IRQ_MDMAS1		BFIN_IRQ(22)	/* MDMA Stream 1 Interrupt */
+-#define IRQ_WATCHDOG		BFIN_IRQ(23)	/* Watchdog Interrupt */
++#define IRQ_WATCH		BFIN_IRQ(23)	/* Watchdog Interrupt */
+ #define IRQ_DMAC1_ERROR		BFIN_IRQ(24)	/* DMAC1 Status (Error) Interrupt */
+ #define IRQ_SPORT2_ERROR	BFIN_IRQ(25)	/* SPORT2 Error Interrupt */
+ #define IRQ_SPORT3_ERROR	BFIN_IRQ(26)	/* SPORT3 Error Interrupt */
+@@ -406,7 +406,7 @@ Events         (highest priority)  EMU         0
+ #define IRQ_PINT1_POS		16
+ #define IRQ_MDMAS0_POS		20
+ #define IRQ_MDMAS1_POS		24
+-#define IRQ_WATCHDOG_POS	28
++#define IRQ_WATCH_POS		28
  
- 	mlog_exit_void();
- }
-+
-+static int ocfs2_downconvert_thread_lists_empty(struct ocfs2_super *osb)
-+{
-+	int empty = 0;
-+
-+	spin_lock(&osb->dc_task_lock);
-+	if (list_empty(&osb->blocked_lock_list))
-+		empty = 1;
-+
-+	spin_unlock(&osb->dc_task_lock);
-+	return empty;
-+}
+ /* IAR3 BIT FIELDS */
+ #define IRQ_DMAC1_ERR_POS	0
+diff --git a/include/asm-blackfin/mach-bf548/mem_init.h b/include/asm-blackfin/mach-bf548/mem_init.h
+index 0cb279e..befc290 100644
+--- a/include/asm-blackfin/mach-bf548/mem_init.h
++++ b/include/asm-blackfin/mach-bf548/mem_init.h
+@@ -28,8 +28,68 @@
+  * If not, write to the Free Software Foundation,
+  * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+  */
++#define MIN_DDR_SCLK(x)	(x*(CONFIG_SCLK_HZ/1000/1000)/1000 + 1)
 +
-+static int ocfs2_downconvert_thread_should_wake(struct ocfs2_super *osb)
-+{
-+	int should_wake = 0;
++#if (CONFIG_MEM_MT46V32M16_6T)
++#define DDR_SIZE	DEVSZ_512
++#define DDR_WIDTH	DEVWD_16
 +
-+	spin_lock(&osb->dc_task_lock);
-+	if (osb->dc_work_sequence != osb->dc_wake_sequence)
-+		should_wake = 1;
-+	spin_unlock(&osb->dc_task_lock);
++#define DDR_tRC		DDR_TRC(MIN_DDR_SCLK(60))
++#define DDR_tRAS	DDR_TRAS(MIN_DDR_SCLK(42))
++#define DDR_tRP		DDR_TRP(MIN_DDR_SCLK(15))
++#define DDR_tRFC	DDR_TRFC(MIN_DDR_SCLK(72))
++#define DDR_tREFI	DDR_TREFI(MIN_DDR_SCLK(7800))
 +
-+	return should_wake;
-+}
++#define DDR_tRCD	DDR_TRCD(MIN_DDR_SCLK(15))
++#define DDR_tWTR	DDR_TWTR(1)
++#define DDR_tMRD	DDR_TMRD(MIN_DDR_SCLK(12))
++#define DDR_tWR		DDR_TWR(MIN_DDR_SCLK(15))
++#endif
 +
-+int ocfs2_downconvert_thread(void *arg)
-+{
-+	int status = 0;
-+	struct ocfs2_super *osb = arg;
++#if (CONFIG_MEM_MT46V32M16_5B)
++#define DDR_SIZE	DEVSZ_512
++#define DDR_WIDTH	DEVWD_16
 +
-+	/* only quit once we've been asked to stop and there is no more
-+	 * work available */
-+	while (!(kthread_should_stop() &&
-+		ocfs2_downconvert_thread_lists_empty(osb))) {
++#define DDR_tRC		DDR_TRC(MIN_DDR_SCLK(55))
++#define DDR_tRAS	DDR_TRAS(MIN_DDR_SCLK(40))
++#define DDR_tRP		DDR_TRP(MIN_DDR_SCLK(15))
++#define DDR_tRFC	DDR_TRFC(MIN_DDR_SCLK(70))
++#define DDR_tREFI	DDR_TREFI(MIN_DDR_SCLK(7800))
 +
-+		wait_event_interruptible(osb->dc_event,
-+					 ocfs2_downconvert_thread_should_wake(osb) ||
-+					 kthread_should_stop());
++#define DDR_tRCD	DDR_TRCD(MIN_DDR_SCLK(15))
++#define DDR_tWTR	DDR_TWTR(2)
++#define DDR_tMRD	DDR_TMRD(MIN_DDR_SCLK(10))
++#define DDR_tWR		DDR_TWR(MIN_DDR_SCLK(15))
++#endif
 +
-+		mlog(0, "downconvert_thread: awoken\n");
++#if (CONFIG_MEM_GENERIC_BOARD)
++#define DDR_SIZE	DEVSZ_512
++#define DDR_WIDTH	DEVWD_16
 +
-+		ocfs2_downconvert_thread_do_work(osb);
-+	}
++#define DDR_tRCD	DDR_TRCD(3)
++#define DDR_tWTR	DDR_TWTR(2)
++#define DDR_tWR		DDR_TWR(2)
++#define DDR_tMRD	DDR_TMRD(2)
++#define DDR_tRP		DDR_TRP(3)
++#define DDR_tRAS	DDR_TRAS(7)
++#define DDR_tRC		DDR_TRC(10)
++#define DDR_tRFC	DDR_TRFC(12)
++#define DDR_tREFI	DDR_TREFI(1288)
++#endif
 +
-+	osb->dc_task = NULL;
-+	return status;
-+}
++#if (CONFIG_SCLK_HZ <= 133333333)
++#define	DDR_CL		CL_2
++#elif (CONFIG_SCLK_HZ <= 166666666)
++#define	DDR_CL		CL_2_5
++#else
++#define	DDR_CL		CL_3
++#endif
 +
-+void ocfs2_wake_downconvert_thread(struct ocfs2_super *osb)
-+{
-+	spin_lock(&osb->dc_task_lock);
-+	/* make sure the voting thread gets a swipe at whatever changes
-+	 * the caller may have made to the voting state */
-+	osb->dc_wake_sequence++;
-+	spin_unlock(&osb->dc_task_lock);
-+	wake_up(&osb->dc_event);
-+}
-diff --git a/fs/ocfs2/dlmglue.h b/fs/ocfs2/dlmglue.h
-index 87a785e..5f17243 100644
---- a/fs/ocfs2/dlmglue.h
-+++ b/fs/ocfs2/dlmglue.h
-@@ -49,12 +49,12 @@ struct ocfs2_meta_lvb {
- 	__be32       lvb_reserved2;
- };
++#define mem_DDRCTL0	(DDR_tRP | DDR_tRAS | DDR_tRC | DDR_tRFC | DDR_tREFI)
++#define mem_DDRCTL1	(DDR_DATWIDTH | EXTBANK_1 | DDR_SIZE | DDR_WIDTH | DDR_tWTR \
++			| DDR_tMRD | DDR_tWR | DDR_tRCD)
++#define mem_DDRCTL2	DDR_CL
  
--/* ocfs2_meta_lock_full() and ocfs2_data_lock_full() 'arg_flags' flags */
-+/* ocfs2_inode_lock_full() 'arg_flags' flags */
- /* don't wait on recovery. */
- #define OCFS2_META_LOCK_RECOVERY	(0x01)
- /* Instruct the dlm not to queue ourselves on the other node. */
- #define OCFS2_META_LOCK_NOQUEUE		(0x02)
--/* don't block waiting for the vote thread, instead return -EAGAIN */
-+/* don't block waiting for the downconvert thread, instead return -EAGAIN */
- #define OCFS2_LOCK_NONBLOCK		(0x04)
+-#if (CONFIG_MEM_MT46V32M16)
  
- int ocfs2_dlm_init(struct ocfs2_super *osb);
-@@ -66,38 +66,32 @@ void ocfs2_inode_lock_res_init(struct ocfs2_lock_res *res,
- 			       struct inode *inode);
- void ocfs2_dentry_lock_res_init(struct ocfs2_dentry_lock *dl,
- 				u64 parent, struct inode *inode);
-+struct ocfs2_file_private;
-+void ocfs2_file_lock_res_init(struct ocfs2_lock_res *lockres,
-+			      struct ocfs2_file_private *fp);
- void ocfs2_lock_res_free(struct ocfs2_lock_res *res);
- int ocfs2_create_new_inode_locks(struct inode *inode);
- int ocfs2_drop_inode_locks(struct inode *inode);
--int ocfs2_data_lock_full(struct inode *inode,
--			 int write,
--			 int arg_flags);
--#define ocfs2_data_lock(inode, write) ocfs2_data_lock_full(inode, write, 0)
--int ocfs2_data_lock_with_page(struct inode *inode,
--			      int write,
--			      struct page *page);
--void ocfs2_data_unlock(struct inode *inode,
--		       int write);
- int ocfs2_rw_lock(struct inode *inode, int write);
- void ocfs2_rw_unlock(struct inode *inode, int write);
- int ocfs2_open_lock(struct inode *inode);
- int ocfs2_try_open_lock(struct inode *inode, int write);
- void ocfs2_open_unlock(struct inode *inode);
--int ocfs2_meta_lock_atime(struct inode *inode,
-+int ocfs2_inode_lock_atime(struct inode *inode,
- 			  struct vfsmount *vfsmnt,
- 			  int *level);
--int ocfs2_meta_lock_full(struct inode *inode,
-+int ocfs2_inode_lock_full(struct inode *inode,
- 			 struct buffer_head **ret_bh,
- 			 int ex,
- 			 int arg_flags);
--int ocfs2_meta_lock_with_page(struct inode *inode,
-+int ocfs2_inode_lock_with_page(struct inode *inode,
- 			      struct buffer_head **ret_bh,
- 			      int ex,
- 			      struct page *page);
- /* 99% of the time we don't want to supply any additional flags --
-  * those are for very specific cases only. */
--#define ocfs2_meta_lock(i, b, e) ocfs2_meta_lock_full(i, b, e, 0)
--void ocfs2_meta_unlock(struct inode *inode,
-+#define ocfs2_inode_lock(i, b, e) ocfs2_inode_lock_full(i, b, e, 0)
-+void ocfs2_inode_unlock(struct inode *inode,
- 		       int ex);
- int ocfs2_super_lock(struct ocfs2_super *osb,
- 		     int ex);
-@@ -107,14 +101,17 @@ int ocfs2_rename_lock(struct ocfs2_super *osb);
- void ocfs2_rename_unlock(struct ocfs2_super *osb);
- int ocfs2_dentry_lock(struct dentry *dentry, int ex);
- void ocfs2_dentry_unlock(struct dentry *dentry, int ex);
-+int ocfs2_file_lock(struct file *file, int ex, int trylock);
-+void ocfs2_file_unlock(struct file *file);
+ #if defined CONFIG_CLKIN_HALF
+ #define CLKIN_HALF       1
+diff --git a/include/asm-blackfin/mach-bf548/portmux.h b/include/asm-blackfin/mach-bf548/portmux.h
+index 6b48512..8177a56 100644
+--- a/include/asm-blackfin/mach-bf548/portmux.h
++++ b/include/asm-blackfin/mach-bf548/portmux.h
+@@ -1,6 +1,8 @@
+ #ifndef _MACH_PORTMUX_H_
+ #define _MACH_PORTMUX_H_
+ 
++#define MAX_RESOURCES 	MAX_BLACKFIN_GPIOS
++
+ #define P_SPORT2_TFS	(P_DEFINED | P_IDENT(GPIO_PA0) | P_FUNCT(0))
+ #define P_SPORT2_DTSEC	(P_DEFINED | P_IDENT(GPIO_PA1) | P_FUNCT(0))
+ #define P_SPORT2_DTPRI	(P_DEFINED | P_IDENT(GPIO_PA2) | P_FUNCT(0))
+diff --git a/include/asm-blackfin/mach-bf561/anomaly.h b/include/asm-blackfin/mach-bf561/anomaly.h
+index bed9564..0c1d461 100644
+--- a/include/asm-blackfin/mach-bf561/anomaly.h
++++ b/include/asm-blackfin/mach-bf561/anomaly.h
+@@ -7,7 +7,7 @@
+  */
  
- void ocfs2_mark_lockres_freeing(struct ocfs2_lock_res *lockres);
- void ocfs2_simple_drop_lockres(struct ocfs2_super *osb,
- 			       struct ocfs2_lock_res *lockres);
+ /* This file shoule be up to date with:
+- *  - Revision N, March 28, 2007; ADSP-BF561 Silicon Anomaly List
++ *  - Revision O, 11/15/2007; ADSP-BF561 Blackfin Processor Anomaly List
+  */
  
--/* for the vote thread */
-+/* for the downconvert thread */
- void ocfs2_process_blocked_lock(struct ocfs2_super *osb,
- 				struct ocfs2_lock_res *lockres);
-+void ocfs2_wake_downconvert_thread(struct ocfs2_super *osb);
+ #ifndef _MACH_ANOMALY_H_
+@@ -15,7 +15,7 @@
  
- struct ocfs2_dlm_debug *ocfs2_new_dlm_debug(void);
- void ocfs2_put_dlm_debug(struct ocfs2_dlm_debug *dlm_debug);
-diff --git a/fs/ocfs2/endian.h b/fs/ocfs2/endian.h
-index ff25762..1942e09 100644
---- a/fs/ocfs2/endian.h
-+++ b/fs/ocfs2/endian.h
-@@ -37,11 +37,6 @@ static inline void le64_add_cpu(__le64 *var, u64 val)
- 	*var = cpu_to_le64(le64_to_cpu(*var) + val);
+ /* We do not support 0.1, 0.2, or 0.4 silicon - sorry */
+ #if __SILICON_REVISION__ < 3 || __SILICON_REVISION__ == 4
+-# error Kernel will not work on BF561 silicon version 0.0, 0.1, 0.2, or 0.4
++# error will not work on BF561 silicon version 0.0, 0.1, 0.2, or 0.4
+ #endif
+ 
+ /* Multi-Issue Instruction with dsp32shiftimm in slot1 and P-reg Store in slot 2 Not Supported */
+@@ -208,6 +208,8 @@
+ #define ANOMALY_05000275 (__SILICON_REVISION__ > 2)
+ /* Timing Requirements Change for External Frame Sync PPI Modes with Non-Zero PPI_DELAY */
+ #define ANOMALY_05000276 (__SILICON_REVISION__ < 5)
++/* Writes to an I/O data register one SCLK cycle after an edge is detected may clear interrupt */
++#define ANOMALY_05000277 (__SILICON_REVISION__ < 3)
+ /* Disabling Peripherals with DMA Running May Cause DMA System Instability */
+ #define ANOMALY_05000278 (__SILICON_REVISION__ < 5)
+ /* False Hardware Error Exception When ISR Context Is Not Restored */
+@@ -246,6 +248,18 @@
+ #define ANOMALY_05000332 (__SILICON_REVISION__ < 5)
+ /* Flag Data Register Writes One SCLK Cycle After Edge Is Detected May Clear Interrupt Status */
+ #define ANOMALY_05000333 (__SILICON_REVISION__ < 5)
++/* New Feature: Additional PPI Frame Sync Sampling Options (Not Available on Older Silicon) */
++#define ANOMALY_05000339 (__SILICON_REVISION__ < 5)
++/* Memory DMA FIFO Causes Throughput Degradation on Writes to External Memory */
++#define ANOMALY_05000343 (__SILICON_REVISION__ < 5)
++/* Serial Port (SPORT) Multichannel Transmit Failure when Channel 0 Is Disabled */
++#define ANOMALY_05000357 (1)
++/* Conflicting Column Address Widths Causes SDRAM Errors */
++#define ANOMALY_05000362 (1)
++/* 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)
+ 
+ /* Anomalies that don't exist on this proc */
+ #define ANOMALY_05000158 (0)
+diff --git a/include/asm-blackfin/mach-bf561/bfin_serial_5xx.h b/include/asm-blackfin/mach-bf561/bfin_serial_5xx.h
+index 69b9f8e..7871d43 100644
+--- a/include/asm-blackfin/mach-bf561/bfin_serial_5xx.h
++++ b/include/asm-blackfin/mach-bf561/bfin_serial_5xx.h
+@@ -111,7 +111,7 @@ static void bfin_serial_hw_init(struct bfin_serial_port *uart)
+ 	}
+ 	if (uart->rts_pin >= 0) {
+ 		gpio_request(uart->rts_pin, DRIVER_NAME);
+-		gpio_direction_input(uart->rts_pin);
++		gpio_direction_input(uart->rts_pin, 0);
+ 	}
+ #endif
  }
+diff --git a/include/asm-blackfin/mach-bf561/portmux.h b/include/asm-blackfin/mach-bf561/portmux.h
+index 132ad31..a6ee820 100644
+--- a/include/asm-blackfin/mach-bf561/portmux.h
++++ b/include/asm-blackfin/mach-bf561/portmux.h
+@@ -1,6 +1,8 @@
+ #ifndef _MACH_PORTMUX_H_
+ #define _MACH_PORTMUX_H_
  
--static inline void le32_and_cpu(__le32 *var, u32 val)
--{
--	*var = cpu_to_le32(le32_to_cpu(*var) & val);
--}
++#define MAX_RESOURCES 	MAX_BLACKFIN_GPIOS
++
+ #define P_PPI0_CLK	(P_DONTCARE)
+ #define P_PPI0_FS1	(P_DONTCARE)
+ #define P_PPI0_FS2	(P_DONTCARE)
+diff --git a/include/asm-blackfin/mmu.h b/include/asm-blackfin/mmu.h
+index 11d52f1..757e439 100644
+--- a/include/asm-blackfin/mmu.h
++++ b/include/asm-blackfin/mmu.h
+@@ -24,7 +24,9 @@ typedef struct {
+ 	unsigned long	exec_fdpic_loadmap;
+ 	unsigned long	interp_fdpic_loadmap;
+ #endif
 -
- static inline void be32_add_cpu(__be32 *var, u32 val)
- {
- 	*var = cpu_to_be32(be32_to_cpu(*var) + val);
-diff --git a/fs/ocfs2/export.c b/fs/ocfs2/export.c
-index 535bfa9..67527ce 100644
---- a/fs/ocfs2/export.c
-+++ b/fs/ocfs2/export.c
-@@ -58,7 +58,7 @@ static struct dentry *ocfs2_get_dentry(struct super_block *sb,
- 		return ERR_PTR(-ESTALE);
- 	}
++#ifdef CONFIG_MPU
++	unsigned long *page_rwx_mask;
++#endif
+ } mm_context_t;
  
--	inode = ocfs2_iget(OCFS2_SB(sb), handle->ih_blkno, 0);
-+	inode = ocfs2_iget(OCFS2_SB(sb), handle->ih_blkno, 0, 0);
+ #endif
+diff --git a/include/asm-blackfin/mmu_context.h b/include/asm-blackfin/mmu_context.h
+index c5c71a6..b5eb675 100644
+--- a/include/asm-blackfin/mmu_context.h
++++ b/include/asm-blackfin/mmu_context.h
+@@ -30,9 +30,12 @@
+ #ifndef __BLACKFIN_MMU_CONTEXT_H__
+ #define __BLACKFIN_MMU_CONTEXT_H__
  
- 	if (IS_ERR(inode))
- 		return (void *)inode;
-@@ -95,7 +95,7 @@ static struct dentry *ocfs2_get_parent(struct dentry *child)
- 	mlog(0, "find parent of directory %llu\n",
- 	     (unsigned long long)OCFS2_I(dir)->ip_blkno);
++#include <linux/gfp.h>
++#include <linux/sched.h>
+ #include <asm/setup.h>
+ #include <asm/page.h>
+ #include <asm/pgalloc.h>
++#include <asm/cplbinit.h>
  
--	status = ocfs2_meta_lock(dir, NULL, 0);
-+	status = ocfs2_inode_lock(dir, NULL, 0);
- 	if (status < 0) {
- 		if (status != -ENOENT)
- 			mlog_errno(status);
-@@ -109,7 +109,7 @@ static struct dentry *ocfs2_get_parent(struct dentry *child)
- 		goto bail_unlock;
- 	}
+ extern void *current_l1_stack_save;
+ extern int nr_l1stack_tasks;
+@@ -50,6 +53,12 @@ static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
+ 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;
+ }
  
--	inode = ocfs2_iget(OCFS2_SB(dir->i_sb), blkno, 0);
-+	inode = ocfs2_iget(OCFS2_SB(dir->i_sb), blkno, 0, 0);
- 	if (IS_ERR(inode)) {
- 		mlog(ML_ERROR, "Unable to create inode %llu\n",
- 		     (unsigned long long)blkno);
-@@ -126,7 +126,7 @@ static struct dentry *ocfs2_get_parent(struct dentry *child)
- 	parent->d_op = &ocfs2_dentry_ops;
+@@ -73,6 +82,11 @@ static inline void destroy_context(struct mm_struct *mm)
+ 		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
+ }
  
- bail_unlock:
--	ocfs2_meta_unlock(dir, 0);
-+	ocfs2_inode_unlock(dir, 0);
+ static inline unsigned long
+@@ -106,9 +120,21 @@ activate_l1stack(struct mm_struct *mm, unsigned long sp_base)
  
- bail:
- 	mlog_exit_ptr(parent);
-diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c
-index b75b2e1..ed5d523 100644
---- a/fs/ocfs2/file.c
-+++ b/fs/ocfs2/file.c
-@@ -51,6 +51,7 @@
- #include "inode.h"
- #include "ioctl.h"
- #include "journal.h"
-+#include "locks.h"
- #include "mmap.h"
- #include "suballoc.h"
- #include "super.h"
-@@ -63,6 +64,35 @@ static int ocfs2_sync_inode(struct inode *inode)
- 	return sync_mapping_buffers(inode->i_mapping);
- }
+ #define deactivate_mm(tsk,mm)	do { } while (0)
  
-+static int ocfs2_init_file_private(struct inode *inode, struct file *file)
-+{
-+	struct ocfs2_file_private *fp;
-+
-+	fp = kzalloc(sizeof(struct ocfs2_file_private), GFP_KERNEL);
-+	if (!fp)
-+		return -ENOMEM;
-+
-+	fp->fp_file = file;
-+	mutex_init(&fp->fp_mutex);
-+	ocfs2_file_lock_res_init(&fp->fp_flock, fp);
-+	file->private_data = fp;
+-static inline void activate_mm(struct mm_struct *prev_mm,
+-			       struct mm_struct *next_mm)
++#define activate_mm(prev, next) switch_mm(prev, next, NULL)
 +
-+	return 0;
-+}
++static inline void switch_mm(struct mm_struct *prev_mm, struct mm_struct *next_mm,
++			     struct task_struct *tsk)
+ {
++	if (prev_mm == next_mm)
++		return;
++#ifdef CONFIG_MPU
++	if (prev_mm->context.page_rwx_mask == current_rwx_mask) {
++		flush_switched_cplbs();
++		set_mask_dcplbs(next_mm->context.page_rwx_mask);
++	}
++#endif
 +
-+static void ocfs2_free_file_private(struct inode *inode, struct file *file)
++	/* L1 stack switching.  */
+ 	if (!next_mm->context.l1_stack_save)
+ 		return;
+ 	if (next_mm->context.l1_stack_save == current_l1_stack_save)
+@@ -120,10 +146,36 @@ static inline void activate_mm(struct mm_struct *prev_mm,
+ 	memcpy(l1_stack_base, current_l1_stack_save, l1_stack_len);
+ }
+ 
+-static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
+-			     struct task_struct *tsk)
++#ifdef CONFIG_MPU
++static inline void protect_page(struct mm_struct *mm, unsigned long addr,
++				unsigned long flags)
 +{
-+	struct ocfs2_file_private *fp = file->private_data;
-+	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
++	unsigned long *mask = mm->context.page_rwx_mask;
++	unsigned long page = addr >> 12;
++	unsigned long idx = page >> 5;
++	unsigned long bit = 1 << (page & 31);
 +
-+	if (fp) {
-+		ocfs2_simple_drop_lockres(osb, &fp->fp_flock);
-+		ocfs2_lock_res_free(&fp->fp_flock);
-+		kfree(fp);
-+		file->private_data = NULL;
-+	}
++	if (flags & VM_MAYREAD)
++		mask[idx] |= bit;
++	else
++		mask[idx] &= ~bit;
++	mask += page_mask_nelts;
++	if (flags & VM_MAYWRITE)
++		mask[idx] |= bit;
++	else
++		mask[idx] &= ~bit;
++	mask += page_mask_nelts;
++	if (flags & VM_MAYEXEC)
++		mask[idx] |= bit;
++	else
++		mask[idx] &= ~bit;
 +}
 +
- static int ocfs2_file_open(struct inode *inode, struct file *file)
++static inline void update_protections(struct mm_struct *mm)
  {
- 	int status;
-@@ -89,7 +119,18 @@ static int ocfs2_file_open(struct inode *inode, struct file *file)
+-	activate_mm(prev, next);
++	flush_switched_cplbs();
++	set_mask_dcplbs(mm->context.page_rwx_mask);
+ }
++#endif
  
- 	oi->ip_open_count++;
- 	spin_unlock(&oi->ip_lock);
--	status = 0;
-+
-+	status = ocfs2_init_file_private(inode, file);
-+	if (status) {
-+		/*
-+		 * We want to set open count back if we're failing the
-+		 * open.
-+		 */
-+		spin_lock(&oi->ip_lock);
-+		oi->ip_open_count--;
-+		spin_unlock(&oi->ip_lock);
-+	}
-+
- leave:
- 	mlog_exit(status);
- 	return status;
-@@ -108,11 +149,24 @@ static int ocfs2_file_release(struct inode *inode, struct file *file)
- 		oi->ip_flags &= ~OCFS2_INODE_OPEN_DIRECT;
- 	spin_unlock(&oi->ip_lock);
+ #endif
+diff --git a/include/asm-blackfin/traps.h b/include/asm-blackfin/traps.h
+index ee1cbf7..f0e5f94 100644
+--- a/include/asm-blackfin/traps.h
++++ b/include/asm-blackfin/traps.h
+@@ -45,6 +45,10 @@
+ #define VEC_CPLB_I_M	(44)
+ #define VEC_CPLB_I_MHIT	(45)
+ #define VEC_ILL_RES	(46)	/* including unvalid supervisor mode insn */
++/* The hardware reserves (63) for future use - we use it to tell our
++ * normal exception handling code we have a hardware error
++ */
++#define VEC_HWERR	(63)
  
-+	ocfs2_free_file_private(inode, file);
-+
- 	mlog_exit(0);
+ #ifndef __ASSEMBLY__
  
- 	return 0;
+diff --git a/include/asm-blackfin/uaccess.h b/include/asm-blackfin/uaccess.h
+index 2233f8f..22a410b 100644
+--- a/include/asm-blackfin/uaccess.h
++++ b/include/asm-blackfin/uaccess.h
+@@ -31,7 +31,7 @@ static inline void set_fs(mm_segment_t fs)
+ #define VERIFY_READ	0
+ #define VERIFY_WRITE	1
+ 
+-#define access_ok(type,addr,size) _access_ok((unsigned long)(addr),(size))
++#define access_ok(type, addr, size) _access_ok((unsigned long)(addr), (size))
+ 
+ static inline int is_in_rom(unsigned long addr)
+ {
+diff --git a/include/asm-blackfin/unistd.h b/include/asm-blackfin/unistd.h
+index 07ffe8b..e981673 100644
+--- a/include/asm-blackfin/unistd.h
++++ b/include/asm-blackfin/unistd.h
+@@ -369,8 +369,9 @@
+ #define __NR_set_robust_list	354
+ #define __NR_get_robust_list	355
+ #define __NR_fallocate		356
++#define __NR_semtimedop		357
+ 
+-#define __NR_syscall		357
++#define __NR_syscall		358
+ #define NR_syscalls		__NR_syscall
+ 
+ /* Old optional stuff no one actually uses */
+diff --git a/include/asm-cris/arch-v10/ide.h b/include/asm-cris/arch-v10/ide.h
+index 78b301e..ea34e0d 100644
+--- a/include/asm-cris/arch-v10/ide.h
++++ b/include/asm-cris/arch-v10/ide.h
+@@ -89,11 +89,6 @@ static inline void ide_init_default_hwifs(void)
+ 	}
  }
  
-+static int ocfs2_dir_open(struct inode *inode, struct file *file)
-+{
-+	return ocfs2_init_file_private(inode, file);
-+}
-+
-+static int ocfs2_dir_release(struct inode *inode, struct file *file)
-+{
-+	ocfs2_free_file_private(inode, file);
-+	return 0;
-+}
-+
- static int ocfs2_sync_file(struct file *file,
- 			   struct dentry *dentry,
- 			   int datasync)
-@@ -382,18 +436,13 @@ static int ocfs2_truncate_file(struct inode *inode,
+-/* some configuration options we don't need */
+-
+-#undef SUPPORT_VLB_SYNC
+-#define SUPPORT_VLB_SYNC 0
+-
+ #endif /* __KERNEL__ */
  
- 	down_write(&OCFS2_I(inode)->ip_alloc_sem);
+ #endif /* __ASMCRIS_IDE_H */
+diff --git a/include/asm-cris/arch-v32/ide.h b/include/asm-cris/arch-v32/ide.h
+index 1129617..fb9c362 100644
+--- a/include/asm-cris/arch-v32/ide.h
++++ b/include/asm-cris/arch-v32/ide.h
+@@ -48,11 +48,6 @@ static inline unsigned long ide_default_io_base(int index)
+ 	return REG_TYPE_CONV(unsigned long, reg_ata_rw_ctrl2, ctrl2);
+ }
  
--	/* This forces other nodes to sync and drop their pages. Do
--	 * this even if we have a truncate without allocation change -
--	 * ocfs2 cluster sizes can be much greater than page size, so
--	 * we have to truncate them anyway.  */
--	status = ocfs2_data_lock(inode, 1);
--	if (status < 0) {
--		up_write(&OCFS2_I(inode)->ip_alloc_sem);
+-/* some configuration options we don't need */
 -
--		mlog_errno(status);
--		goto bail;
--	}
+-#undef SUPPORT_VLB_SYNC
+-#define SUPPORT_VLB_SYNC 0
 -
-+	/*
-+	 * The inode lock forced other nodes to sync and drop their
-+	 * pages, which (correctly) happens even if we have a truncate
-+	 * without allocation change - ocfs2 cluster sizes can be much
-+	 * greater than page size, so we have to truncate them
-+	 * anyway.
-+	 */
- 	unmap_mapping_range(inode->i_mapping, new_i_size + PAGE_SIZE - 1, 0, 1);
- 	truncate_inode_pages(inode->i_mapping, new_i_size);
+ #define IDE_ARCH_ACK_INTR
+ #define ide_ack_intr(hwif)	((hwif)->ack_intr(hwif))
  
-@@ -403,7 +452,7 @@ static int ocfs2_truncate_file(struct inode *inode,
- 		if (status)
- 			mlog_errno(status);
+diff --git a/include/asm-frv/ide.h b/include/asm-frv/ide.h
+index f0bd2cb..8c9a540 100644
+--- a/include/asm-frv/ide.h
++++ b/include/asm-frv/ide.h
+@@ -18,12 +18,6 @@
+ #include <asm/io.h>
+ #include <asm/irq.h>
  
--		goto bail_unlock_data;
-+		goto bail_unlock_sem;
- 	}
+-#undef SUPPORT_SLOW_DATA_PORTS
+-#define SUPPORT_SLOW_DATA_PORTS 0
+-
+-#undef SUPPORT_VLB_SYNC
+-#define SUPPORT_VLB_SYNC 0
+-
+ #ifndef MAX_HWIFS
+ #define MAX_HWIFS 8
+ #endif
+diff --git a/include/asm-generic/resource.h b/include/asm-generic/resource.h
+index a4a22cc..587566f 100644
+--- a/include/asm-generic/resource.h
++++ b/include/asm-generic/resource.h
+@@ -44,8 +44,8 @@
+ #define RLIMIT_NICE		13	/* max nice prio allowed to raise to
+ 					   0-39 for nice level 19 .. -20 */
+ #define RLIMIT_RTPRIO		14	/* maximum realtime priority */
+-
+-#define RLIM_NLIMITS		15
++#define RLIMIT_RTTIME		15	/* timeout for RT tasks in us */
++#define RLIM_NLIMITS		16
  
- 	/* alright, we're going to need to do a full blown alloc size
-@@ -413,25 +462,23 @@ static int ocfs2_truncate_file(struct inode *inode,
- 	status = ocfs2_orphan_for_truncate(osb, inode, di_bh, new_i_size);
- 	if (status < 0) {
- 		mlog_errno(status);
--		goto bail_unlock_data;
-+		goto bail_unlock_sem;
- 	}
+ /*
+  * SuS says limits have to be unsigned.
+@@ -86,6 +86,7 @@
+ 	[RLIMIT_MSGQUEUE]	= {   MQ_BYTES_MAX,   MQ_BYTES_MAX },	\
+ 	[RLIMIT_NICE]		= { 0, 0 },				\
+ 	[RLIMIT_RTPRIO]		= { 0, 0 },				\
++	[RLIMIT_RTTIME]		= {  RLIM_INFINITY,  RLIM_INFINITY },	\
+ }
  
- 	status = ocfs2_prepare_truncate(osb, inode, di_bh, &tc);
- 	if (status < 0) {
- 		mlog_errno(status);
--		goto bail_unlock_data;
-+		goto bail_unlock_sem;
- 	}
+ #endif	/* __KERNEL__ */
+diff --git a/include/asm-powerpc/ide.h b/include/asm-powerpc/ide.h
+index fd7f5a4..6d50310 100644
+--- a/include/asm-powerpc/ide.h
++++ b/include/asm-powerpc/ide.h
+@@ -42,9 +42,6 @@ struct ide_machdep_calls {
  
- 	status = ocfs2_commit_truncate(osb, inode, di_bh, tc);
- 	if (status < 0) {
- 		mlog_errno(status);
--		goto bail_unlock_data;
-+		goto bail_unlock_sem;
- 	}
+ extern struct ide_machdep_calls ppc_ide_md;
  
- 	/* TODO: orphan dir cleanup here. */
--bail_unlock_data:
--	ocfs2_data_unlock(inode, 1);
+-#undef	SUPPORT_SLOW_DATA_PORTS
+-#define	SUPPORT_SLOW_DATA_PORTS	0
 -
-+bail_unlock_sem:
- 	up_write(&OCFS2_I(inode)->ip_alloc_sem);
+ #define IDE_ARCH_OBSOLETE_DEFAULTS
  
- bail:
-@@ -579,7 +626,7 @@ int ocfs2_lock_allocators(struct inode *inode, struct ocfs2_dinode *di,
+ static __inline__ int ide_default_irq(unsigned long base)
+diff --git a/include/asm-s390/airq.h b/include/asm-s390/airq.h
+new file mode 100644
+index 0000000..41d028c
+--- /dev/null
++++ b/include/asm-s390/airq.h
+@@ -0,0 +1,19 @@
++/*
++ *  include/asm-s390/airq.h
++ *
++ *    Copyright IBM Corp. 2002,2007
++ *    Author(s): Ingo Adlung <adlung at de.ibm.com>
++ *		 Cornelia Huck <cornelia.huck at de.ibm.com>
++ *		 Arnd Bergmann <arndb at de.ibm.com>
++ *		 Peter Oberparleiter <peter.oberparleiter at de.ibm.com>
++ */
++
++#ifndef _ASM_S390_AIRQ_H
++#define _ASM_S390_AIRQ_H
++
++typedef void (*adapter_int_handler_t)(void *, void *);
++
++void *s390_register_adapter_interrupt(adapter_int_handler_t, void *);
++void s390_unregister_adapter_interrupt(void *);
++
++#endif /* _ASM_S390_AIRQ_H */
+diff --git a/include/asm-s390/cio.h b/include/asm-s390/cio.h
+index 2f08c16..123b557 100644
+--- a/include/asm-s390/cio.h
++++ b/include/asm-s390/cio.h
+@@ -24,8 +24,8 @@
+  * @fmt: format
+  * @pfch: prefetch
+  * @isic: initial-status interruption control
+- * @alcc: adress-limit checking control
+- * @ssi: supress-suspended interruption
++ * @alcc: address-limit checking control
++ * @ssi: suppress-suspended interruption
+  * @zcc: zero condition code
+  * @ectl: extended control
+  * @pno: path not operational
+diff --git a/include/asm-s390/dasd.h b/include/asm-s390/dasd.h
+index 604f68f..3f002e1 100644
+--- a/include/asm-s390/dasd.h
++++ b/include/asm-s390/dasd.h
+@@ -105,7 +105,7 @@ typedef struct dasd_information_t {
+ } dasd_information_t;
  
- 	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, i_size_read(inode),
-+	     (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);
+ /*
+- * Read Subsystem Data - Perfomance Statistics
++ * Read Subsystem Data - Performance Statistics
+  */ 
+ typedef struct dasd_rssd_perf_stats_t {
+ 	unsigned char  invalid:1;
+diff --git a/include/asm-s390/ipl.h b/include/asm-s390/ipl.h
+index 2c40fd3..c1b2e50 100644
+--- a/include/asm-s390/ipl.h
++++ b/include/asm-s390/ipl.h
+@@ -83,6 +83,8 @@ extern u32 dump_prefix_page;
+ extern unsigned int zfcpdump_prefix_array[];
  
- 	num_free_extents = ocfs2_num_free_extents(osb, inode, di);
-@@ -760,7 +807,7 @@ restarted_transaction:
- 	     le32_to_cpu(fe->i_clusters),
- 	     (unsigned long long)le64_to_cpu(fe->i_size));
- 	mlog(0, "inode: ip_clusters=%u, i_size=%lld\n",
--	     OCFS2_I(inode)->ip_clusters, i_size_read(inode));
-+	     OCFS2_I(inode)->ip_clusters, (long long)i_size_read(inode));
+ extern void do_reipl(void);
++extern void do_halt(void);
++extern void do_poff(void);
+ extern void ipl_save_parameters(void);
  
- leave:
- 	if (handle) {
-@@ -917,7 +964,7 @@ static int ocfs2_extend_file(struct inode *inode,
- 			     struct buffer_head *di_bh,
- 			     u64 new_i_size)
+ enum {
+@@ -118,7 +120,7 @@ struct ipl_info
+ };
+ 
+ extern struct ipl_info ipl_info;
+-extern void setup_ipl_info(void);
++extern void setup_ipl(void);
+ 
+ /*
+  * DIAG 308 support
+@@ -141,6 +143,10 @@ enum diag308_opt {
+ 	DIAG308_IPL_OPT_DUMP	= 0x20,
+ };
+ 
++enum diag308_flags {
++	DIAG308_FLAGS_LP_VALID	= 0x80,
++};
++
+ enum diag308_rc {
+ 	DIAG308_RC_OK	= 1,
+ };
+diff --git a/include/asm-s390/mmu_context.h b/include/asm-s390/mmu_context.h
+index 05b8421..a77d4ba 100644
+--- a/include/asm-s390/mmu_context.h
++++ b/include/asm-s390/mmu_context.h
+@@ -12,10 +12,15 @@
+ #include <asm/pgalloc.h>
+ #include <asm-generic/mm_hooks.h>
+ 
+-/*
+- * get a new mmu context.. S390 don't know about contexts.
+- */
+-#define init_new_context(tsk,mm)        0
++static inline int init_new_context(struct task_struct *tsk,
++				   struct mm_struct *mm)
++{
++	mm->context = _ASCE_TABLE_LENGTH | _ASCE_USER_BITS;
++#ifdef CONFIG_64BIT
++	mm->context |= _ASCE_TYPE_REGION3;
++#endif
++	return 0;
++}
+ 
+ #define destroy_context(mm)             do { } while (0)
+ 
+@@ -27,19 +32,11 @@
+ 
+ static inline void update_mm(struct mm_struct *mm, struct task_struct *tsk)
  {
--	int ret = 0, data_locked = 0;
-+	int ret = 0;
- 	struct ocfs2_inode_info *oi = OCFS2_I(inode);
+-	pgd_t *pgd = mm->pgd;
+-	unsigned long asce_bits;
+-
+-	/* Calculate asce bits from the first pgd table entry. */
+-	asce_bits = _ASCE_TABLE_LENGTH | _ASCE_USER_BITS;
+-#ifdef CONFIG_64BIT
+-	asce_bits |= _ASCE_TYPE_REGION3;
+-#endif
+-	S390_lowcore.user_asce = asce_bits | __pa(pgd);
++	S390_lowcore.user_asce = mm->context | __pa(mm->pgd);
+ 	if (switch_amode) {
+ 		/* Load primary space page table origin. */
+-		pgd_t *shadow_pgd = get_shadow_table(pgd) ? : pgd;
+-		S390_lowcore.user_exec_asce = asce_bits | __pa(shadow_pgd);
++		pgd_t *shadow_pgd = get_shadow_table(mm->pgd) ? : mm->pgd;
++		S390_lowcore.user_exec_asce = mm->context | __pa(shadow_pgd);
+ 		asm volatile(LCTL_OPCODE" 1,1,%0\n"
+ 			     : : "m" (S390_lowcore.user_exec_asce) );
+ 	} else
+diff --git a/include/asm-s390/pgtable.h b/include/asm-s390/pgtable.h
+index 1f530f8..79b9eab 100644
+--- a/include/asm-s390/pgtable.h
++++ b/include/asm-s390/pgtable.h
+@@ -104,41 +104,27 @@ extern char empty_zero_page[PAGE_SIZE];
  
- 	BUG_ON(!di_bh);
-@@ -943,20 +990,6 @@ static int ocfs2_extend_file(struct inode *inode,
- 	    && ocfs2_sparse_alloc(OCFS2_SB(inode->i_sb)))
- 		goto out_update_size;
+ #ifndef __ASSEMBLY__
+ /*
+- * Just any arbitrary offset to the start of the vmalloc VM area: the
+- * current 8MB value just means that there will be a 8MB "hole" after the
+- * physical memory until the kernel virtual memory starts.  That means that
+- * any out-of-bounds memory accesses will hopefully be caught.
+- * The vmalloc() routines leaves a hole of 4kB between each vmalloced
+- * area for the same reason. ;)
+- * vmalloc area starts at 4GB to prevent syscall table entry exchanging
+- * from modules.
+- */
+-extern unsigned long vmalloc_end;
+-
+-#ifdef CONFIG_64BIT
+-#define VMALLOC_ADDR	(max(0x100000000UL, (unsigned long) high_memory))
+-#else
+-#define VMALLOC_ADDR	((unsigned long) high_memory)
+-#endif
+-#define VMALLOC_OFFSET	(8*1024*1024)
+-#define VMALLOC_START	((VMALLOC_ADDR + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
+-#define VMALLOC_END	vmalloc_end
+-
+-/*
+- * We need some free virtual space to be able to do vmalloc.
+- * VMALLOC_MIN_SIZE defines the minimum size of the vmalloc
+- * area. On a machine with 2GB memory we make sure that we
+- * have at least 128MB free space for vmalloc. On a machine
+- * with 4TB we make sure we have at least 128GB.
++ * The vmalloc area will always be on the topmost area of the kernel
++ * mapping. We reserve 96MB (31bit) / 1GB (64bit) for vmalloc,
++ * which should be enough for any sane case.
++ * By putting vmalloc at the top, we maximise the gap between physical
++ * memory and vmalloc to catch misplaced memory accesses. As a side
++ * effect, this also makes sure that 64 bit module code cannot be used
++ * as system call address.
+  */
+ #ifndef __s390x__
+-#define VMALLOC_MIN_SIZE	0x8000000UL
+-#define VMALLOC_END_INIT	0x80000000UL
++#define VMALLOC_START	0x78000000UL
++#define VMALLOC_END	0x7e000000UL
++#define VMEM_MAP_MAX	0x80000000UL
+ #else /* __s390x__ */
+-#define VMALLOC_MIN_SIZE	0x2000000000UL
+-#define VMALLOC_END_INIT	0x40000000000UL
++#define VMALLOC_START	0x3e000000000UL
++#define VMALLOC_END	0x3e040000000UL
++#define VMEM_MAP_MAX	0x40000000000UL
+ #endif /* __s390x__ */
  
--	/* 
--	 * protect the pages that ocfs2_zero_extend is going to be
--	 * pulling into the page cache.. we do this before the
--	 * metadata extend so that we don't get into the situation
--	 * where we've extended the metadata but can't get the data
--	 * lock to zero.
--	 */
--	ret = ocfs2_data_lock(inode, 1);
--	if (ret < 0) {
--		mlog_errno(ret);
--		goto out;
--	}
--	data_locked = 1;
++#define VMEM_MAP	((struct page *) VMALLOC_END)
++#define VMEM_MAP_SIZE	((VMALLOC_START / PAGE_SIZE) * sizeof(struct page))
++
+ /*
+  * A 31 bit pagetable entry of S390 has following format:
+  *  |   PFRA          |    |  OS  |
+diff --git a/include/asm-s390/processor.h b/include/asm-s390/processor.h
+index 21d40a1..c86b982 100644
+--- a/include/asm-s390/processor.h
++++ b/include/asm-s390/processor.h
+@@ -59,9 +59,6 @@ extern void s390_adjust_jiffies(void);
+ extern void print_cpu_info(struct cpuinfo_S390 *);
+ extern int get_cpu_capability(unsigned int *);
+ 
+-/* Lazy FPU handling on uni-processor */
+-extern struct task_struct *last_task_used_math;
 -
- 	/*
- 	 * The alloc sem blocks people in read/write from reading our
- 	 * allocation until we're done changing it. We depend on
-@@ -980,7 +1013,7 @@ static int ocfs2_extend_file(struct inode *inode,
- 			up_write(&oi->ip_alloc_sem);
+ /*
+  * User space process size: 2GB for 31 bit, 4TB for 64 bit.
+  */
+@@ -95,7 +92,6 @@ struct thread_struct {
+         unsigned long ksp;              /* kernel stack pointer             */
+ 	mm_segment_t mm_segment;
+         unsigned long prot_addr;        /* address of protection-excep.     */
+-        unsigned int error_code;        /* error-code of last prog-excep.   */
+         unsigned int trap_no;
+         per_struct per_info;
+ 	/* Used to give failing instruction back to user for ieee exceptions */
+diff --git a/include/asm-s390/ptrace.h b/include/asm-s390/ptrace.h
+index 332ee73..61f6952 100644
+--- a/include/asm-s390/ptrace.h
++++ b/include/asm-s390/ptrace.h
+@@ -465,6 +465,14 @@ struct user_regs_struct
+ #ifdef __KERNEL__
+ #define __ARCH_SYS_PTRACE	1
  
- 			mlog_errno(ret);
--			goto out_unlock;
-+			goto out;
- 		}
- 	}
++/*
++ * These are defined as per linux/ptrace.h, which see.
++ */
++#define arch_has_single_step()	(1)
++struct task_struct;
++extern void user_enable_single_step(struct task_struct *);
++extern void user_disable_single_step(struct task_struct *);
++
+ #define user_mode(regs) (((regs)->psw.mask & PSW_MASK_PSTATE) != 0)
+ #define instruction_pointer(regs) ((regs)->psw.addr & PSW_ADDR_INSN)
+ #define regs_return_value(regs)((regs)->gprs[2])
+diff --git a/include/asm-s390/qdio.h b/include/asm-s390/qdio.h
+index 74db1dc..4b8ff55 100644
+--- a/include/asm-s390/qdio.h
++++ b/include/asm-s390/qdio.h
+@@ -184,7 +184,7 @@ struct qdr {
+ #endif /* QDIO_32_BIT */
+ 	unsigned long qiba;             /* queue-information-block address */
+ 	unsigned int  res8;             /* reserved */
+-	unsigned int  qkey    :  4;     /* queue-informatio-block key */
++	unsigned int  qkey    :  4;	/* queue-information-block key */
+ 	unsigned int  res9    : 28;     /* reserved */
+ /*	union _qd {*/ /* why this? */
+ 		struct qdesfmt0 qdf0[126];
+diff --git a/include/asm-s390/rwsem.h b/include/asm-s390/rwsem.h
+index 90f4ecc..9d2a179 100644
+--- a/include/asm-s390/rwsem.h
++++ b/include/asm-s390/rwsem.h
+@@ -91,8 +91,8 @@ struct rw_semaphore {
+ #endif
  
-@@ -991,7 +1024,7 @@ static int ocfs2_extend_file(struct inode *inode,
+ #define __RWSEM_INITIALIZER(name) \
+-{ RWSEM_UNLOCKED_VALUE, SPIN_LOCK_UNLOCKED, LIST_HEAD_INIT((name).wait_list) \
+-  __RWSEM_DEP_MAP_INIT(name) }
++ { RWSEM_UNLOCKED_VALUE, __SPIN_LOCK_UNLOCKED((name).wait.lock), \
++   LIST_HEAD_INIT((name).wait_list) __RWSEM_DEP_MAP_INIT(name) }
  
- 	if (ret < 0) {
- 		mlog_errno(ret);
--		goto out_unlock;
-+		goto out;
- 	}
+ #define DECLARE_RWSEM(name) \
+ 	struct rw_semaphore name = __RWSEM_INITIALIZER(name)
+diff --git a/include/asm-s390/sclp.h b/include/asm-s390/sclp.h
+index cb9faf1..b5f2843 100644
+--- a/include/asm-s390/sclp.h
++++ b/include/asm-s390/sclp.h
+@@ -27,7 +27,25 @@ struct sclp_ipl_info {
+ 	char loadparm[LOADPARM_LEN];
+ };
  
- out_update_size:
-@@ -999,10 +1032,6 @@ out_update_size:
- 	if (ret < 0)
- 		mlog_errno(ret);
+-void sclp_readinfo_early(void);
++struct sclp_cpu_entry {
++	u8 address;
++	u8 reserved0[13];
++	u8 type;
++	u8 reserved1;
++} __attribute__((packed));
++
++struct sclp_cpu_info {
++	unsigned int configured;
++	unsigned int standby;
++	unsigned int combined;
++	int has_cpu_type;
++	struct sclp_cpu_entry cpu[255];
++};
++
++int sclp_get_cpu_info(struct sclp_cpu_info *info);
++int sclp_cpu_configure(u8 cpu);
++int sclp_cpu_deconfigure(u8 cpu);
++void sclp_read_info_early(void);
+ void sclp_facilities_detect(void);
+ unsigned long long sclp_memory_detect(void);
+ int sclp_sdias_blk_count(void);
+diff --git a/include/asm-s390/smp.h b/include/asm-s390/smp.h
+index 07708c0..c7b7432 100644
+--- a/include/asm-s390/smp.h
++++ b/include/asm-s390/smp.h
+@@ -35,8 +35,6 @@ extern void machine_restart_smp(char *);
+ extern void machine_halt_smp(void);
+ extern void machine_power_off_smp(void);
  
--out_unlock:
--	if (data_locked)
--		ocfs2_data_unlock(inode, 1);
+-extern void smp_setup_cpu_possible_map(void);
 -
- out:
- 	return ret;
- }
-@@ -1050,7 +1079,7 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr)
- 		}
- 	}
+ #define NO_PROC_ID		0xFF		/* No processor magic marker */
  
--	status = ocfs2_meta_lock(inode, &bh, 1);
-+	status = ocfs2_inode_lock(inode, &bh, 1);
- 	if (status < 0) {
- 		if (status != -ENOENT)
- 			mlog_errno(status);
-@@ -1102,7 +1131,7 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr)
- bail_commit:
- 	ocfs2_commit_trans(osb, handle);
- bail_unlock:
--	ocfs2_meta_unlock(inode, 1);
-+	ocfs2_inode_unlock(inode, 1);
- bail_unlock_rw:
- 	if (size_change)
- 		ocfs2_rw_unlock(inode, 1);
-@@ -1149,7 +1178,7 @@ int ocfs2_permission(struct inode *inode, int mask, struct nameidata *nd)
+ /*
+@@ -92,6 +90,8 @@ extern void __cpu_die (unsigned int cpu);
+ extern void cpu_die (void) __attribute__ ((noreturn));
+ extern int __cpu_up (unsigned int cpu);
  
- 	mlog_entry_void();
++extern int smp_call_function_mask(cpumask_t mask, void (*func)(void *),
++	void *info, int wait);
+ #endif
  
--	ret = ocfs2_meta_lock(inode, NULL, 0);
-+	ret = ocfs2_inode_lock(inode, NULL, 0);
- 	if (ret) {
- 		if (ret != -ENOENT)
- 			mlog_errno(ret);
-@@ -1158,7 +1187,7 @@ int ocfs2_permission(struct inode *inode, int mask, struct nameidata *nd)
+ #ifndef CONFIG_SMP
+@@ -103,7 +103,6 @@ static inline void smp_send_stop(void)
  
- 	ret = generic_permission(inode, mask, NULL);
+ #define hard_smp_processor_id()		0
+ #define smp_cpu_not_running(cpu)	1
+-#define smp_setup_cpu_possible_map()	do { } while (0)
+ #endif
  
--	ocfs2_meta_unlock(inode, 0);
-+	ocfs2_inode_unlock(inode, 0);
- out:
- 	mlog_exit(ret);
- 	return ret;
-@@ -1630,7 +1659,7 @@ static int __ocfs2_change_file_space(struct file *file, struct inode *inode,
- 		goto out;
- 	}
+ extern union save_area *zfcpdump_save_areas[NR_CPUS + 1];
+diff --git a/include/asm-s390/spinlock.h b/include/asm-s390/spinlock.h
+index 3fd4382..df84ae9 100644
+--- a/include/asm-s390/spinlock.h
++++ b/include/asm-s390/spinlock.h
+@@ -53,44 +53,48 @@ _raw_compare_and_swap(volatile unsigned int *lock,
+  */
  
--	ret = ocfs2_meta_lock(inode, &di_bh, 1);
-+	ret = ocfs2_inode_lock(inode, &di_bh, 1);
- 	if (ret) {
- 		mlog_errno(ret);
- 		goto out_rw_unlock;
-@@ -1638,7 +1667,7 @@ static int __ocfs2_change_file_space(struct file *file, struct inode *inode,
+ #define __raw_spin_is_locked(x) ((x)->owner_cpu != 0)
+-#define __raw_spin_lock_flags(lock, flags) __raw_spin_lock(lock)
+ #define __raw_spin_unlock_wait(lock) \
+ 	do { while (__raw_spin_is_locked(lock)) \
+ 		 _raw_spin_relax(lock); } while (0)
  
- 	if (inode->i_flags & (S_IMMUTABLE|S_APPEND)) {
- 		ret = -EPERM;
--		goto out_meta_unlock;
-+		goto out_inode_unlock;
- 	}
+-extern void _raw_spin_lock_wait(raw_spinlock_t *, unsigned int pc);
+-extern int _raw_spin_trylock_retry(raw_spinlock_t *, unsigned int pc);
++extern void _raw_spin_lock_wait(raw_spinlock_t *);
++extern void _raw_spin_lock_wait_flags(raw_spinlock_t *, unsigned long flags);
++extern int _raw_spin_trylock_retry(raw_spinlock_t *);
+ extern void _raw_spin_relax(raw_spinlock_t *lock);
  
- 	switch (sr->l_whence) {
-@@ -1652,7 +1681,7 @@ static int __ocfs2_change_file_space(struct file *file, struct inode *inode,
- 		break;
- 	default:
- 		ret = -EINVAL;
--		goto out_meta_unlock;
-+		goto out_inode_unlock;
- 	}
- 	sr->l_whence = 0;
+ static inline void __raw_spin_lock(raw_spinlock_t *lp)
+ {
+-	unsigned long pc = 1 | (unsigned long) __builtin_return_address(0);
+ 	int old;
  
-@@ -1663,14 +1692,14 @@ static int __ocfs2_change_file_space(struct file *file, struct inode *inode,
- 	    || (sr->l_start + llen) < 0
- 	    || (sr->l_start + llen) > max_off) {
- 		ret = -EINVAL;
--		goto out_meta_unlock;
-+		goto out_inode_unlock;
- 	}
- 	size = sr->l_start + sr->l_len;
+ 	old = _raw_compare_and_swap(&lp->owner_cpu, 0, ~smp_processor_id());
+-	if (likely(old == 0)) {
+-		lp->owner_pc = pc;
++	if (likely(old == 0))
+ 		return;
+-	}
+-	_raw_spin_lock_wait(lp, pc);
++	_raw_spin_lock_wait(lp);
++}
++
++static inline void __raw_spin_lock_flags(raw_spinlock_t *lp,
++					 unsigned long flags)
++{
++	int old;
++
++	old = _raw_compare_and_swap(&lp->owner_cpu, 0, ~smp_processor_id());
++	if (likely(old == 0))
++		return;
++	_raw_spin_lock_wait_flags(lp, flags);
+ }
  
- 	if (cmd == OCFS2_IOC_RESVSP || cmd == OCFS2_IOC_RESVSP64) {
- 		if (sr->l_len <= 0) {
- 			ret = -EINVAL;
--			goto out_meta_unlock;
-+			goto out_inode_unlock;
- 		}
- 	}
+ static inline int __raw_spin_trylock(raw_spinlock_t *lp)
+ {
+-	unsigned long pc = 1 | (unsigned long) __builtin_return_address(0);
+ 	int old;
  
-@@ -1678,7 +1707,7 @@ static int __ocfs2_change_file_space(struct file *file, struct inode *inode,
- 		ret = __ocfs2_write_remove_suid(inode, di_bh);
- 		if (ret) {
- 			mlog_errno(ret);
--			goto out_meta_unlock;
-+			goto out_inode_unlock;
- 		}
- 	}
+ 	old = _raw_compare_and_swap(&lp->owner_cpu, 0, ~smp_processor_id());
+-	if (likely(old == 0)) {
+-		lp->owner_pc = pc;
++	if (likely(old == 0))
+ 		return 1;
+-	}
+-	return _raw_spin_trylock_retry(lp, pc);
++	return _raw_spin_trylock_retry(lp);
+ }
  
-@@ -1704,7 +1733,7 @@ static int __ocfs2_change_file_space(struct file *file, struct inode *inode,
- 	up_write(&OCFS2_I(inode)->ip_alloc_sem);
- 	if (ret) {
- 		mlog_errno(ret);
--		goto out_meta_unlock;
-+		goto out_inode_unlock;
- 	}
+ static inline void __raw_spin_unlock(raw_spinlock_t *lp)
+ {
+-	lp->owner_pc = 0;
+ 	_raw_compare_and_swap(&lp->owner_cpu, lp->owner_cpu, 0);
+ }
+ 		
+diff --git a/include/asm-s390/spinlock_types.h b/include/asm-s390/spinlock_types.h
+index b7ac13f..654abc4 100644
+--- a/include/asm-s390/spinlock_types.h
++++ b/include/asm-s390/spinlock_types.h
+@@ -7,7 +7,6 @@
+ 
+ typedef struct {
+ 	volatile unsigned int owner_cpu;
+-	volatile unsigned int owner_pc;
+ } __attribute__ ((aligned (4))) raw_spinlock_t;
+ 
+ #define __RAW_SPIN_LOCK_UNLOCKED	{ 0 }
+diff --git a/include/asm-s390/tlbflush.h b/include/asm-s390/tlbflush.h
+index a69bd24..70fa5ae 100644
+--- a/include/asm-s390/tlbflush.h
++++ b/include/asm-s390/tlbflush.h
+@@ -42,11 +42,11 @@ static inline void __tlb_flush_global(void)
+ /*
+  * Flush all tlb entries of a page table on all cpus.
+  */
+-static inline void __tlb_flush_idte(pgd_t *pgd)
++static inline void __tlb_flush_idte(unsigned long asce)
+ {
+ 	asm volatile(
+ 		"	.insn	rrf,0xb98e0000,0,%0,%1,0"
+-		: : "a" (2048), "a" (__pa(pgd) & PAGE_MASK) : "cc" );
++		: : "a" (2048), "a" (asce) : "cc" );
+ }
  
- 	/*
-@@ -1714,7 +1743,7 @@ static int __ocfs2_change_file_space(struct file *file, struct inode *inode,
- 	if (IS_ERR(handle)) {
- 		ret = PTR_ERR(handle);
- 		mlog_errno(ret);
--		goto out_meta_unlock;
-+		goto out_inode_unlock;
+ static inline void __tlb_flush_mm(struct mm_struct * mm)
+@@ -61,11 +61,11 @@ static inline void __tlb_flush_mm(struct mm_struct * mm)
+ 	 * only ran on the local cpu.
+ 	 */
+ 	if (MACHINE_HAS_IDTE) {
+-		pgd_t *shadow_pgd = get_shadow_table(mm->pgd);
++		pgd_t *shadow = get_shadow_table(mm->pgd);
+ 
+-		if (shadow_pgd)
+-			__tlb_flush_idte(shadow_pgd);
+-		__tlb_flush_idte(mm->pgd);
++		if (shadow)
++			__tlb_flush_idte((unsigned long) shadow | mm->context);
++		__tlb_flush_idte((unsigned long) mm->pgd | mm->context);
+ 		return;
  	}
+ 	preempt_disable();
+@@ -106,9 +106,23 @@ static inline void __tlb_flush_mm_cond(struct mm_struct * mm)
+  */
+ #define flush_tlb()				do { } while (0)
+ #define flush_tlb_all()				do { } while (0)
+-#define flush_tlb_mm(mm)			__tlb_flush_mm_cond(mm)
+ #define flush_tlb_page(vma, addr)		do { } while (0)
+-#define flush_tlb_range(vma, start, end)	__tlb_flush_mm_cond(mm)
+-#define flush_tlb_kernel_range(start, end)	__tlb_flush_mm(&init_mm)
++
++static inline void flush_tlb_mm(struct mm_struct *mm)
++{
++	__tlb_flush_mm_cond(mm);
++}
++
++static inline void flush_tlb_range(struct vm_area_struct *vma,
++				   unsigned long start, unsigned long end)
++{
++	__tlb_flush_mm_cond(vma->vm_mm);
++}
++
++static inline void flush_tlb_kernel_range(unsigned long start,
++					  unsigned long end)
++{
++	__tlb_flush_mm(&init_mm);
++}
  
- 	if (change_size && i_size_read(inode) < size)
-@@ -1727,9 +1756,9 @@ static int __ocfs2_change_file_space(struct file *file, struct inode *inode,
+ #endif /* _S390_TLBFLUSH_H */
+diff --git a/include/asm-s390/zcrypt.h b/include/asm-s390/zcrypt.h
+index a5dada6..f228f1b 100644
+--- a/include/asm-s390/zcrypt.h
++++ b/include/asm-s390/zcrypt.h
+@@ -117,7 +117,7 @@ struct CPRBX {
+ 	unsigned char	padx004[16 - sizeof (char *)];
+ 	unsigned char *	req_extb;	/* request extension block 'addr'*/
+ 	unsigned char	padx005[16 - sizeof (char *)];
+-	unsigned char *	rpl_extb;	/* reply extension block 'addres'*/
++	unsigned char *	rpl_extb;	/* reply extension block 'address'*/
+ 	unsigned short	ccp_rtcode;	/* server return code		 */
+ 	unsigned short	ccp_rscode;	/* server reason code		 */
+ 	unsigned int	mac_data_len;	/* Mac Data Length		 */
+diff --git a/include/asm-sh/Kbuild b/include/asm-sh/Kbuild
+index 76a8ccf..43910cd 100644
+--- a/include/asm-sh/Kbuild
++++ b/include/asm-sh/Kbuild
+@@ -1,3 +1,8 @@
+ include include/asm-generic/Kbuild.asm
+ 
+ header-y += cpu-features.h
++
++unifdef-y += unistd_32.h
++unifdef-y += unistd_64.h
++unifdef-y += posix_types_32.h
++unifdef-y += posix_types_64.h
+diff --git a/include/asm-sh/addrspace.h b/include/asm-sh/addrspace.h
+index b860218..fa544fc 100644
+--- a/include/asm-sh/addrspace.h
++++ b/include/asm-sh/addrspace.h
+@@ -9,24 +9,21 @@
+  */
+ #ifndef __ASM_SH_ADDRSPACE_H
+ #define __ASM_SH_ADDRSPACE_H
++
+ #ifdef __KERNEL__
  
- 	ocfs2_commit_trans(osb, handle);
+ #include <asm/cpu/addrspace.h>
  
--out_meta_unlock:
-+out_inode_unlock:
- 	brelse(di_bh);
--	ocfs2_meta_unlock(inode, 1);
-+	ocfs2_inode_unlock(inode, 1);
- out_rw_unlock:
- 	ocfs2_rw_unlock(inode, 1);
+-/* Memory segments (32bit Privileged mode addresses)  */
+-#ifndef CONFIG_CPU_SH2A
+-#define P0SEG		0x00000000
+-#define P1SEG		0x80000000
+-#define P2SEG		0xa0000000
+-#define P3SEG		0xc0000000
+-#define P4SEG		0xe0000000
+-#else
+-#define P0SEG		0x00000000
+-#define P1SEG		0x00000000
+-#define P2SEG		0x20000000
+-#define P3SEG		0x00000000
+-#define P4SEG 		0x80000000
+-#endif
++/* If this CPU supports segmentation, hook up the helpers */
++#ifdef P1SEG
++
++/*
++   [ P0/U0 (virtual) ]		0x00000000     <------ User space
++   [ P1 (fixed)   cached ]	0x80000000     <------ Kernel space
++   [ P2 (fixed)  non-cachable]	0xA0000000     <------ Physical access
++   [ P3 (virtual) cached]	0xC0000000     <------ vmalloced area
++   [ P4 control   ]		0xE0000000
++ */
+ 
+ /* Returns the privileged segment base of a given address  */
+ #define PXSEG(a)	(((unsigned long)(a)) & 0xe0000000)
+@@ -34,13 +31,23 @@
+ /* Returns the physical address of a PnSEG (n=1,2) address   */
+ #define PHYSADDR(a)	(((unsigned long)(a)) & 0x1fffffff)
+ 
++#ifdef CONFIG_29BIT
+ /*
+  * Map an address to a certain privileged segment
+  */
+-#define P1SEGADDR(a)	((__typeof__(a))(((unsigned long)(a) & 0x1fffffff) | P1SEG))
+-#define P2SEGADDR(a)	((__typeof__(a))(((unsigned long)(a) & 0x1fffffff) | P2SEG))
+-#define P3SEGADDR(a)	((__typeof__(a))(((unsigned long)(a) & 0x1fffffff) | P3SEG))
+-#define P4SEGADDR(a)	((__typeof__(a))(((unsigned long)(a) & 0x1fffffff) | P4SEG))
++#define P1SEGADDR(a)	\
++	((__typeof__(a))(((unsigned long)(a) & 0x1fffffff) | P1SEG))
++#define P2SEGADDR(a)	\
++	((__typeof__(a))(((unsigned long)(a) & 0x1fffffff) | P2SEG))
++#define P3SEGADDR(a)	\
++	((__typeof__(a))(((unsigned long)(a) & 0x1fffffff) | P3SEG))
++#define P4SEGADDR(a)	\
++	((__typeof__(a))(((unsigned long)(a) & 0x1fffffff) | P4SEG))
++#endif /* 29BIT */
++#endif /* P1SEG */
++
++/* Check if an address can be reached in 29 bits */
++#define IS_29BIT(a)	(((unsigned long)(a)) < 0x20000000)
  
-@@ -1799,7 +1828,7 @@ static int ocfs2_prepare_inode_for_write(struct dentry *dentry,
- 	 * if we need to make modifications here.
- 	 */
- 	for(;;) {
--		ret = ocfs2_meta_lock(inode, NULL, meta_level);
-+		ret = ocfs2_inode_lock(inode, NULL, meta_level);
- 		if (ret < 0) {
- 			meta_level = -1;
- 			mlog_errno(ret);
-@@ -1817,7 +1846,7 @@ static int ocfs2_prepare_inode_for_write(struct dentry *dentry,
- 		 * set inode->i_size at the end of a write. */
- 		if (should_remove_suid(dentry)) {
- 			if (meta_level == 0) {
--				ocfs2_meta_unlock(inode, meta_level);
-+				ocfs2_inode_unlock(inode, meta_level);
- 				meta_level = 1;
- 				continue;
- 			}
-@@ -1886,7 +1915,7 @@ static int ocfs2_prepare_inode_for_write(struct dentry *dentry,
- 		*ppos = saved_pos;
+ #endif /* __KERNEL__ */
+ #endif /* __ASM_SH_ADDRSPACE_H */
+diff --git a/include/asm-sh/atomic-grb.h b/include/asm-sh/atomic-grb.h
+new file mode 100644
+index 0000000..4c5b7db
+--- /dev/null
++++ b/include/asm-sh/atomic-grb.h
+@@ -0,0 +1,169 @@
++#ifndef __ASM_SH_ATOMIC_GRB_H
++#define __ASM_SH_ATOMIC_GRB_H
++
++static inline void atomic_add(int i, atomic_t *v)
++{
++	int tmp;
++
++	__asm__ __volatile__ (
++		"   .align 2              \n\t"
++		"   mova    1f,   r0      \n\t" /* r0 = end point */
++		"   mov    r15,   r1      \n\t" /* r1 = saved sp */
++		"   mov    #-6,   r15     \n\t" /* LOGIN: r15 = size */
++		"   mov.l  @%1,   %0      \n\t" /* load  old value */
++		"   add     %2,   %0      \n\t" /* add */
++		"   mov.l   %0,   @%1     \n\t" /* store new value */
++		"1: mov     r1,   r15     \n\t" /* LOGOUT */
++		: "=&r" (tmp),
++		  "+r"  (v)
++		: "r"   (i)
++		: "memory" , "r0", "r1");
++}
++
++static inline void atomic_sub(int i, atomic_t *v)
++{
++	int tmp;
++
++	__asm__ __volatile__ (
++		"   .align 2              \n\t"
++		"   mova    1f,   r0      \n\t" /* r0 = end point */
++		"   mov     r15,  r1      \n\t" /* r1 = saved sp */
++		"   mov    #-6,   r15     \n\t" /* LOGIN: r15 = size */
++		"   mov.l  @%1,   %0      \n\t" /* load  old value */
++		"   sub     %2,   %0      \n\t" /* sub */
++		"   mov.l   %0,   @%1     \n\t" /* store new value */
++		"1: mov     r1,   r15     \n\t" /* LOGOUT */
++		: "=&r" (tmp),
++		  "+r"  (v)
++		: "r"   (i)
++		: "memory" , "r0", "r1");
++}
++
++static inline int atomic_add_return(int i, atomic_t *v)
++{
++	int tmp;
++
++	__asm__ __volatile__ (
++		"   .align 2              \n\t"
++		"   mova    1f,   r0      \n\t" /* r0 = end point */
++		"   mov    r15,   r1      \n\t" /* r1 = saved sp */
++		"   mov    #-6,   r15     \n\t" /* LOGIN: r15 = size */
++		"   mov.l  @%1,   %0      \n\t" /* load  old value */
++		"   add     %2,   %0      \n\t" /* add */
++		"   mov.l   %0,   @%1     \n\t" /* store new value */
++		"1: mov     r1,   r15     \n\t" /* LOGOUT */
++		: "=&r" (tmp),
++		  "+r"  (v)
++		: "r"   (i)
++		: "memory" , "r0", "r1");
++
++	return tmp;
++}
++
++static inline int atomic_sub_return(int i, atomic_t *v)
++{
++	int tmp;
++
++	__asm__ __volatile__ (
++		"   .align 2              \n\t"
++		"   mova    1f,   r0      \n\t" /* r0 = end point */
++		"   mov    r15,   r1      \n\t" /* r1 = saved sp */
++		"   mov    #-6,   r15     \n\t" /* LOGIN: r15 = size */
++		"   mov.l  @%1,   %0      \n\t" /* load  old value */
++		"   sub     %2,   %0      \n\t" /* sub */
++		"   mov.l   %0,   @%1     \n\t" /* store new value */
++		"1: mov     r1,   r15     \n\t" /* LOGOUT */
++		: "=&r" (tmp),
++		  "+r"  (v)
++		: "r"   (i)
++		: "memory", "r0", "r1");
++
++	return tmp;
++}
++
++static inline void atomic_clear_mask(unsigned int mask, atomic_t *v)
++{
++	int tmp;
++	unsigned int _mask = ~mask;
++
++	__asm__ __volatile__ (
++		"   .align 2              \n\t"
++		"   mova    1f,   r0      \n\t" /* r0 = end point */
++		"   mov    r15,   r1      \n\t" /* r1 = saved sp */
++		"   mov    #-6,   r15     \n\t" /* LOGIN: r15 = size */
++		"   mov.l  @%1,   %0      \n\t" /* load  old value */
++		"   and     %2,   %0      \n\t" /* add */
++		"   mov.l   %0,   @%1     \n\t" /* store new value */
++		"1: mov     r1,   r15     \n\t" /* LOGOUT */
++		: "=&r" (tmp),
++		  "+r"  (v)
++		: "r"   (_mask)
++		: "memory" , "r0", "r1");
++}
++
++static inline void atomic_set_mask(unsigned int mask, atomic_t *v)
++{
++	int tmp;
++
++	__asm__ __volatile__ (
++		"   .align 2              \n\t"
++		"   mova    1f,   r0      \n\t" /* r0 = end point */
++		"   mov    r15,   r1      \n\t" /* r1 = saved sp */
++		"   mov    #-6,   r15     \n\t" /* LOGIN: r15 = size */
++		"   mov.l  @%1,   %0      \n\t" /* load  old value */
++		"   or      %2,   %0      \n\t" /* or */
++		"   mov.l   %0,   @%1     \n\t" /* store new value */
++		"1: mov     r1,   r15     \n\t" /* LOGOUT */
++		: "=&r" (tmp),
++		  "+r"  (v)
++		: "r"   (mask)
++		: "memory" , "r0", "r1");
++}
++
++static inline int atomic_cmpxchg(atomic_t *v, int old, int new)
++{
++	int ret;
++
++	__asm__ __volatile__ (
++		"   .align 2		\n\t"
++		"   mova     1f,  r0	\n\t"
++		"   nop			\n\t"
++		"   mov     r15,  r1	\n\t"
++		"   mov    #-8,  r15	\n\t"
++		"   mov.l   @%1,  %0	\n\t"
++		"   cmp/eq   %2,  %0	\n\t"
++		"   bf	     1f		\n\t"
++		"   mov.l    %3, @%1	\n\t"
++		"1: mov      r1,  r15	\n\t"
++		: "=&r" (ret)
++		: "r" (v), "r" (old), "r" (new)
++		: "memory" , "r0", "r1" , "t");
++
++	return ret;
++}
++
++static inline int atomic_add_unless(atomic_t *v, int a, int u)
++{
++	int ret;
++	unsigned long tmp;
++
++	__asm__ __volatile__ (
++		"   .align 2		\n\t"
++		"   mova    1f,   r0	\n\t"
++		"   nop			\n\t"
++		"   mov    r15,   r1	\n\t"
++		"   mov    #-12,  r15	\n\t"
++		"   mov.l  @%2,   %1	\n\t"
++		"   mov	    %1,   %0    \n\t"
++		"   cmp/eq  %4,   %0	\n\t"
++		"   bt/s    1f		\n\t"
++		"    add    %3,   %1	\n\t"
++		"   mov.l   %1,  @%2	\n\t"
++		"1: mov     r1,   r15	\n\t"
++		: "=&r" (ret), "=&r" (tmp)
++		: "r" (v), "r" (a), "r" (u)
++		: "memory" , "r0", "r1" , "t");
++
++	return ret != u;
++}
++#endif /* __ASM_SH_ATOMIC_GRB_H */
+diff --git a/include/asm-sh/atomic.h b/include/asm-sh/atomic.h
+index e12570b..c043ef0 100644
+--- a/include/asm-sh/atomic.h
++++ b/include/asm-sh/atomic.h
+@@ -17,7 +17,9 @@ typedef struct { volatile int counter; } atomic_t;
+ #include <linux/compiler.h>
+ #include <asm/system.h>
  
- out_unlock:
--	ocfs2_meta_unlock(inode, meta_level);
-+	ocfs2_inode_unlock(inode, meta_level);
+-#ifdef CONFIG_CPU_SH4A
++#if defined(CONFIG_GUSA_RB)
++#include <asm/atomic-grb.h>
++#elif defined(CONFIG_CPU_SH4A)
+ #include <asm/atomic-llsc.h>
+ #else
+ #include <asm/atomic-irq.h>
+@@ -44,6 +46,7 @@ typedef struct { volatile int counter; } atomic_t;
+ #define atomic_inc(v) atomic_add(1,(v))
+ #define atomic_dec(v) atomic_sub(1,(v))
  
- out:
++#ifndef CONFIG_GUSA_RB
+ static inline int atomic_cmpxchg(atomic_t *v, int old, int new)
+ {
+ 	int ret;
+@@ -58,8 +61,6 @@ static inline int atomic_cmpxchg(atomic_t *v, int old, int new)
  	return ret;
-@@ -2099,12 +2128,12 @@ static ssize_t ocfs2_file_splice_read(struct file *in,
- 	/*
- 	 * See the comment in ocfs2_file_aio_read()
- 	 */
--	ret = ocfs2_meta_lock(inode, NULL, 0);
-+	ret = ocfs2_inode_lock(inode, NULL, 0);
- 	if (ret < 0) {
- 		mlog_errno(ret);
- 		goto bail;
- 	}
--	ocfs2_meta_unlock(inode, 0);
-+	ocfs2_inode_unlock(inode, 0);
- 
- 	ret = generic_file_splice_read(in, ppos, pipe, len, flags);
+ }
  
-@@ -2160,12 +2189,12 @@ static ssize_t ocfs2_file_aio_read(struct kiocb *iocb,
- 	 * like i_size. This allows the checks down below
- 	 * generic_file_aio_read() a chance of actually working. 
- 	 */
--	ret = ocfs2_meta_lock_atime(inode, filp->f_vfsmnt, &lock_level);
-+	ret = ocfs2_inode_lock_atime(inode, filp->f_vfsmnt, &lock_level);
- 	if (ret < 0) {
- 		mlog_errno(ret);
- 		goto bail;
- 	}
--	ocfs2_meta_unlock(inode, lock_level);
-+	ocfs2_inode_unlock(inode, lock_level);
+-#define atomic_xchg(v, new) (xchg(&((v)->counter), new))
+-
+ static inline int atomic_add_unless(atomic_t *v, int a, int u)
+ {
+ 	int ret;
+@@ -73,6 +74,9 @@ static inline int atomic_add_unless(atomic_t *v, int a, int u)
  
- 	ret = generic_file_aio_read(iocb, iov, nr_segs, iocb->ki_pos);
- 	if (ret == -EINVAL)
-@@ -2204,6 +2233,7 @@ const struct inode_operations ocfs2_special_file_iops = {
- };
+ 	return ret != u;
+ }
++#endif
++
++#define atomic_xchg(v, new) (xchg(&((v)->counter), new))
+ #define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
  
- const struct file_operations ocfs2_fops = {
-+	.llseek		= generic_file_llseek,
- 	.read		= do_sync_read,
- 	.write		= do_sync_write,
- 	.mmap		= ocfs2_mmap,
-@@ -2216,16 +2246,21 @@ const struct file_operations ocfs2_fops = {
- #ifdef CONFIG_COMPAT
- 	.compat_ioctl   = ocfs2_compat_ioctl,
- #endif
-+	.flock		= ocfs2_flock,
- 	.splice_read	= ocfs2_file_splice_read,
- 	.splice_write	= ocfs2_file_splice_write,
- };
+ /* Atomic operations are already serializing on SH */
+diff --git a/include/asm-sh/auxvec.h b/include/asm-sh/auxvec.h
+index 1b6916e..a6b9d4f 100644
+--- a/include/asm-sh/auxvec.h
++++ b/include/asm-sh/auxvec.h
+@@ -6,6 +6,12 @@
+  * for more of them.
+  */
  
- 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,
- 	.ioctl		= ocfs2_ioctl,
- #ifdef CONFIG_COMPAT
- 	.compat_ioctl   = ocfs2_compat_ioctl,
++/*
++ * This entry gives some information about the FPU initialization
++ * performed by the kernel.
++ */
++#define AT_FPUCW		18	/* Used FPU control word.  */
++
+ #ifdef CONFIG_VSYSCALL
+ /*
+  * Only define this in the vsyscall case, the entry point to
+@@ -15,4 +21,16 @@
+ #define AT_SYSINFO_EHDR		33
  #endif
-+	.flock		= ocfs2_flock,
- };
-diff --git a/fs/ocfs2/file.h b/fs/ocfs2/file.h
-index 066f14a..048ddca 100644
---- a/fs/ocfs2/file.h
-+++ b/fs/ocfs2/file.h
-@@ -32,6 +32,12 @@ extern const struct inode_operations ocfs2_file_iops;
- extern const struct inode_operations ocfs2_special_file_iops;
- struct ocfs2_alloc_context;
  
-+struct ocfs2_file_private {
-+	struct file		*fp_file;
-+	struct mutex		fp_mutex;
-+	struct ocfs2_lock_res	fp_flock;
-+};
++/*
++ * More complete cache descriptions than AT_[DIU]CACHEBSIZE.  If the
++ * value is -1, then the cache doesn't exist.  Otherwise:
++ *
++ *    bit 0-3:	  Cache set-associativity; 0 means fully associative.
++ *    bit 4-7:	  Log2 of cacheline size.
++ *    bit 8-31:	  Size of the entire cache >> 8.
++ */
++#define AT_L1I_CACHESHAPE	34
++#define AT_L1D_CACHESHAPE	35
++#define AT_L2_CACHESHAPE	36
 +
- enum ocfs2_alloc_restarted {
- 	RESTART_NONE = 0,
- 	RESTART_TRANS,
-diff --git a/fs/ocfs2/heartbeat.c b/fs/ocfs2/heartbeat.c
-index c4c3617..c0efd94 100644
---- a/fs/ocfs2/heartbeat.c
-+++ b/fs/ocfs2/heartbeat.c
-@@ -30,9 +30,6 @@
- #include <linux/highmem.h>
- #include <linux/kmod.h>
+ #endif /* __ASM_SH_AUXVEC_H */
+diff --git a/include/asm-sh/bitops-grb.h b/include/asm-sh/bitops-grb.h
+new file mode 100644
+index 0000000..a5907b9
+--- /dev/null
++++ b/include/asm-sh/bitops-grb.h
+@@ -0,0 +1,169 @@
++#ifndef __ASM_SH_BITOPS_GRB_H
++#define __ASM_SH_BITOPS_GRB_H
++
++static inline void set_bit(int nr, volatile void * addr)
++{
++	int	mask;
++	volatile unsigned int *a = addr;
++	unsigned long tmp;
++
++	a += nr >> 5;
++	mask = 1 << (nr & 0x1f);
++
++        __asm__ __volatile__ (
++                "   .align 2              \n\t"
++                "   mova    1f,   r0      \n\t" /* r0 = end point */
++                "   mov    r15,   r1      \n\t" /* r1 = saved sp */
++                "   mov    #-6,   r15     \n\t" /* LOGIN: r15 = size */
++                "   mov.l  @%1,   %0      \n\t" /* load  old value */
++                "   or      %2,   %0      \n\t" /* or */
++                "   mov.l   %0,   @%1     \n\t" /* store new value */
++                "1: mov     r1,   r15     \n\t" /* LOGOUT */
++                : "=&r" (tmp),
++                  "+r"  (a)
++                : "r"   (mask)
++                : "memory" , "r0", "r1");
++}
++
++static inline void clear_bit(int nr, volatile void * addr)
++{
++	int	mask;
++	volatile unsigned int *a = addr;
++        unsigned long tmp;
++
++	a += nr >> 5;
++        mask = ~(1 << (nr & 0x1f));
++        __asm__ __volatile__ (
++                "   .align 2              \n\t"
++                "   mova    1f,   r0      \n\t" /* r0 = end point */
++                "   mov    r15,   r1      \n\t" /* r1 = saved sp */
++                "   mov    #-6,   r15     \n\t" /* LOGIN: r15 = size */
++                "   mov.l  @%1,   %0      \n\t" /* load  old value */
++                "   and     %2,   %0      \n\t" /* and */
++                "   mov.l   %0,   @%1     \n\t" /* store new value */
++                "1: mov     r1,   r15     \n\t" /* LOGOUT */
++                : "=&r" (tmp),
++                  "+r"  (a)
++                : "r"   (mask)
++                : "memory" , "r0", "r1");
++}
++
++static inline void change_bit(int nr, volatile void * addr)
++{
++        int     mask;
++        volatile unsigned int *a = addr;
++        unsigned long tmp;
++
++        a += nr >> 5;
++        mask = 1 << (nr & 0x1f);
++        __asm__ __volatile__ (
++                "   .align 2              \n\t"
++                "   mova    1f,   r0      \n\t" /* r0 = end point */
++                "   mov    r15,   r1      \n\t" /* r1 = saved sp */
++                "   mov    #-6,   r15     \n\t" /* LOGIN: r15 = size */
++                "   mov.l  @%1,   %0      \n\t" /* load  old value */
++                "   xor     %2,   %0      \n\t" /* xor */
++                "   mov.l   %0,   @%1     \n\t" /* store new value */
++                "1: mov     r1,   r15     \n\t" /* LOGOUT */
++                : "=&r" (tmp),
++                  "+r"  (a)
++                : "r"   (mask)
++                : "memory" , "r0", "r1");
++}
++
++static inline int test_and_set_bit(int nr, volatile void * addr)
++{
++        int     mask, retval;
++	volatile unsigned int *a = addr;
++        unsigned long tmp;
++
++	a += nr >> 5;
++	mask = 1 << (nr & 0x1f);
++
++        __asm__ __volatile__ (
++                "   .align 2              \n\t"
++                "   mova    1f,   r0      \n\t" /* r0 = end point */
++                "   mov    r15,   r1      \n\t" /* r1 = saved sp */
++                "   mov   #-14,   r15     \n\t" /* LOGIN: r15 = size */
++                "   mov.l  @%2,   %0      \n\t" /* load old value */
++                "   mov     %0,   %1      \n\t"
++                "   tst     %1,   %3      \n\t" /* T = ((*a & mask) == 0) */
++                "   mov    #-1,   %1      \n\t" /* retvat = -1 */
++                "   negc    %1,   %1      \n\t" /* retval = (mask & *a) != 0 */
++                "   or      %3,   %0      \n\t"
++                "   mov.l   %0,  @%2      \n\t" /* store new value */
++                "1: mov     r1,  r15      \n\t" /* LOGOUT */
++                : "=&r" (tmp),
++                  "=&r" (retval),
++                  "+r"  (a)
++                : "r"   (mask)
++                : "memory" , "r0", "r1" ,"t");
++
++        return retval;
++}
++
++static inline int test_and_clear_bit(int nr, volatile void * addr)
++{
++        int     mask, retval,not_mask;
++        volatile unsigned int *a = addr;
++        unsigned long tmp;
++
++        a += nr >> 5;
++        mask = 1 << (nr & 0x1f);
++
++	not_mask = ~mask;
++
++        __asm__ __volatile__ (
++                "   .align 2              \n\t"
++		"   mova    1f,   r0      \n\t" /* r0 = end point */
++                "   mov    r15,   r1      \n\t" /* r1 = saved sp */
++		"   mov   #-14,   r15     \n\t" /* LOGIN */
++		"   mov.l  @%2,   %0      \n\t" /* load old value */
++                "   mov     %0,   %1      \n\t" /* %1 = *a */
++                "   tst     %1,   %3      \n\t" /* T = ((*a & mask) == 0) */
++		"   mov    #-1,   %1      \n\t" /* retvat = -1 */
++                "   negc    %1,   %1      \n\t" /* retval = (mask & *a) != 0 */
++                "   and     %4,   %0      \n\t"
++                "   mov.l   %0,  @%2      \n\t" /* store new value */
++		"1: mov     r1,   r15     \n\t" /* LOGOUT */
++		: "=&r" (tmp),
++		  "=&r" (retval),
++		  "+r"  (a)
++		: "r"   (mask),
++		  "r"   (not_mask)
++		: "memory" , "r0", "r1", "t");
++
++        return retval;
++}
++
++static inline int test_and_change_bit(int nr, volatile void * addr)
++{
++        int     mask, retval;
++        volatile unsigned int *a = addr;
++        unsigned long tmp;
++
++        a += nr >> 5;
++        mask = 1 << (nr & 0x1f);
++
++        __asm__ __volatile__ (
++                "   .align 2              \n\t"
++                "   mova    1f,   r0      \n\t" /* r0 = end point */
++                "   mov    r15,   r1      \n\t" /* r1 = saved sp */
++                "   mov   #-14,   r15     \n\t" /* LOGIN */
++                "   mov.l  @%2,   %0      \n\t" /* load old value */
++                "   mov     %0,   %1      \n\t" /* %1 = *a */
++                "   tst     %1,   %3      \n\t" /* T = ((*a & mask) == 0) */
++                "   mov    #-1,   %1      \n\t" /* retvat = -1 */
++                "   negc    %1,   %1      \n\t" /* retval = (mask & *a) != 0 */
++                "   xor     %3,   %0      \n\t"
++                "   mov.l   %0,  @%2      \n\t" /* store new value */
++                "1: mov     r1,   r15     \n\t" /* LOGOUT */
++                : "=&r" (tmp),
++                  "=&r" (retval),
++                  "+r"  (a)
++                : "r"   (mask)
++                : "memory" , "r0", "r1", "t");
++
++        return retval;
++}
++#endif /* __ASM_SH_BITOPS_GRB_H */
+diff --git a/include/asm-sh/bitops-irq.h b/include/asm-sh/bitops-irq.h
+new file mode 100644
+index 0000000..653a127
+--- /dev/null
++++ b/include/asm-sh/bitops-irq.h
+@@ -0,0 +1,91 @@
++#ifndef __ASM_SH_BITOPS_IRQ_H
++#define __ASM_SH_BITOPS_IRQ_H
++
++static inline void set_bit(int nr, volatile void *addr)
++{
++	int	mask;
++	volatile unsigned int *a = addr;
++	unsigned long flags;
++
++	a += nr >> 5;
++	mask = 1 << (nr & 0x1f);
++	local_irq_save(flags);
++	*a |= mask;
++	local_irq_restore(flags);
++}
++
++static inline void clear_bit(int nr, volatile void *addr)
++{
++	int	mask;
++	volatile unsigned int *a = addr;
++	unsigned long flags;
++
++	a += nr >> 5;
++	mask = 1 << (nr & 0x1f);
++	local_irq_save(flags);
++	*a &= ~mask;
++	local_irq_restore(flags);
++}
++
++static inline void change_bit(int nr, volatile void *addr)
++{
++	int	mask;
++	volatile unsigned int *a = addr;
++	unsigned long flags;
++
++	a += nr >> 5;
++	mask = 1 << (nr & 0x1f);
++	local_irq_save(flags);
++	*a ^= mask;
++	local_irq_restore(flags);
++}
++
++static inline int test_and_set_bit(int nr, volatile void *addr)
++{
++	int	mask, retval;
++	volatile unsigned int *a = addr;
++	unsigned long flags;
++
++	a += nr >> 5;
++	mask = 1 << (nr & 0x1f);
++	local_irq_save(flags);
++	retval = (mask & *a) != 0;
++	*a |= mask;
++	local_irq_restore(flags);
++
++	return retval;
++}
++
++static inline int test_and_clear_bit(int nr, volatile void *addr)
++{
++	int	mask, retval;
++	volatile unsigned int *a = addr;
++	unsigned long flags;
++
++	a += nr >> 5;
++	mask = 1 << (nr & 0x1f);
++	local_irq_save(flags);
++	retval = (mask & *a) != 0;
++	*a &= ~mask;
++	local_irq_restore(flags);
++
++	return retval;
++}
++
++static inline int test_and_change_bit(int nr, volatile void *addr)
++{
++	int	mask, retval;
++	volatile unsigned int *a = addr;
++	unsigned long flags;
++
++	a += nr >> 5;
++	mask = 1 << (nr & 0x1f);
++	local_irq_save(flags);
++	retval = (mask & *a) != 0;
++	*a ^= mask;
++	local_irq_restore(flags);
++
++	return retval;
++}
++
++#endif /* __ASM_SH_BITOPS_IRQ_H */
+diff --git a/include/asm-sh/bitops.h b/include/asm-sh/bitops.h
+index df805f2..b6ba5a6 100644
+--- a/include/asm-sh/bitops.h
++++ b/include/asm-sh/bitops.h
+@@ -11,100 +11,22 @@
+ /* For __swab32 */
+ #include <asm/byteorder.h>
  
--#include <cluster/heartbeat.h>
--#include <cluster/nodemanager.h>
+-static inline void set_bit(int nr, volatile void * addr)
+-{
+-	int	mask;
+-	volatile unsigned int *a = addr;
+-	unsigned long flags;
 -
- #include <dlm/dlmapi.h>
+-	a += nr >> 5;
+-	mask = 1 << (nr & 0x1f);
+-	local_irq_save(flags);
+-	*a |= mask;
+-	local_irq_restore(flags);
+-}
++#ifdef CONFIG_GUSA_RB
++#include <asm/bitops-grb.h>
++#else
++#include <asm/bitops-irq.h>
++#endif
++
  
- #define MLOG_MASK_PREFIX ML_SUPER
-@@ -44,13 +41,9 @@
- #include "heartbeat.h"
- #include "inode.h"
- #include "journal.h"
--#include "vote.h"
+ /*
+  * clear_bit() doesn't provide any barrier for the compiler.
+  */
+ #define smp_mb__before_clear_bit()	barrier()
+ #define smp_mb__after_clear_bit()	barrier()
+-static inline void clear_bit(int nr, volatile void * addr)
+-{
+-	int	mask;
+-	volatile unsigned int *a = addr;
+-	unsigned long flags;
+-
+-	a += nr >> 5;
+-	mask = 1 << (nr & 0x1f);
+-	local_irq_save(flags);
+-	*a &= ~mask;
+-	local_irq_restore(flags);
+-}
+-
+-static inline void change_bit(int nr, volatile void * addr)
+-{
+-	int	mask;
+-	volatile unsigned int *a = addr;
+-	unsigned long flags;
+-
+-	a += nr >> 5;
+-	mask = 1 << (nr & 0x1f);
+-	local_irq_save(flags);
+-	*a ^= mask;
+-	local_irq_restore(flags);
+-}
+-
+-static inline int test_and_set_bit(int nr, volatile void * addr)
+-{
+-	int	mask, retval;
+-	volatile unsigned int *a = addr;
+-	unsigned long flags;
+-
+-	a += nr >> 5;
+-	mask = 1 << (nr & 0x1f);
+-	local_irq_save(flags);
+-	retval = (mask & *a) != 0;
+-	*a |= mask;
+-	local_irq_restore(flags);
+-
+-	return retval;
+-}
+-
+-static inline int test_and_clear_bit(int nr, volatile void * addr)
+-{
+-	int	mask, retval;
+-	volatile unsigned int *a = addr;
+-	unsigned long flags;
+-
+-	a += nr >> 5;
+-	mask = 1 << (nr & 0x1f);
+-	local_irq_save(flags);
+-	retval = (mask & *a) != 0;
+-	*a &= ~mask;
+-	local_irq_restore(flags);
+-
+-	return retval;
+-}
+-
+-static inline int test_and_change_bit(int nr, volatile void * addr)
+-{
+-	int	mask, retval;
+-	volatile unsigned int *a = addr;
+-	unsigned long flags;
+-
+-	a += nr >> 5;
+-	mask = 1 << (nr & 0x1f);
+-	local_irq_save(flags);
+-	retval = (mask & *a) != 0;
+-	*a ^= mask;
+-	local_irq_restore(flags);
+-
+-	return retval;
+-}
  
- #include "buffer_head_io.h"
+ #include <asm-generic/bitops/non-atomic.h>
  
--#define OCFS2_HB_NODE_DOWN_PRI     (0x0000002)
--#define OCFS2_HB_NODE_UP_PRI	   OCFS2_HB_NODE_DOWN_PRI
--
- static inline void __ocfs2_node_map_set_bit(struct ocfs2_node_map *map,
- 					    int bit);
- static inline void __ocfs2_node_map_clear_bit(struct ocfs2_node_map *map,
-@@ -64,9 +57,7 @@ static void __ocfs2_node_map_set(struct ocfs2_node_map *target,
- void ocfs2_init_node_maps(struct ocfs2_super *osb)
++#ifdef CONFIG_SUPERH32
+ static inline unsigned long ffz(unsigned long word)
  {
- 	spin_lock_init(&osb->node_map_lock);
--	ocfs2_node_map_init(&osb->mounted_map);
- 	ocfs2_node_map_init(&osb->recovery_map);
--	ocfs2_node_map_init(&osb->umount_map);
- 	ocfs2_node_map_init(&osb->osb_recovering_orphan_dirs);
+ 	unsigned long result;
+@@ -138,6 +60,31 @@ static inline unsigned long __ffs(unsigned long word)
+ 		: "t");
+ 	return result;
  }
++#else
++static inline unsigned long ffz(unsigned long word)
++{
++	unsigned long result, __d2, __d3;
++
++        __asm__("gettr  tr0, %2\n\t"
++                "pta    $+32, tr0\n\t"
++                "andi   %1, 1, %3\n\t"
++                "beq    %3, r63, tr0\n\t"
++                "pta    $+4, tr0\n"
++                "0:\n\t"
++                "shlri.l        %1, 1, %1\n\t"
++                "addi   %0, 1, %0\n\t"
++                "andi   %1, 1, %3\n\t"
++                "beqi   %3, 1, tr0\n"
++                "1:\n\t"
++                "ptabs  %2, tr0\n\t"
++                : "=r" (result), "=r" (word), "=r" (__d2), "=r" (__d3)
++                : "0" (0L), "1" (word));
++
++	return result;
++}
++
++#include <asm-generic/bitops/__ffs.h>
++#endif
  
-@@ -87,24 +78,7 @@ static void ocfs2_do_node_down(int node_num,
- 		return;
+ #include <asm-generic/bitops/find.h>
+ #include <asm-generic/bitops/ffs.h>
+diff --git a/include/asm-sh/bug.h b/include/asm-sh/bug.h
+index a78d482..c017180 100644
+--- a/include/asm-sh/bug.h
++++ b/include/asm-sh/bug.h
+@@ -3,7 +3,7 @@
+ 
+ #define TRAPA_BUG_OPCODE	0xc33e	/* trapa #0x3e */
+ 
+-#ifdef CONFIG_BUG
++#ifdef CONFIG_GENERIC_BUG
+ #define HAVE_ARCH_BUG
+ #define HAVE_ARCH_WARN_ON
+ 
+@@ -72,12 +72,7 @@ do {							\
+ 	unlikely(__ret_warn_on);				\
+ })
+ 
+-struct pt_regs;
+-
+-/* arch/sh/kernel/traps.c */
+-void handle_BUG(struct pt_regs *);
+-
+-#endif /* CONFIG_BUG */
++#endif /* CONFIG_GENERIC_BUG */
+ 
+ #include <asm-generic/bug.h>
+ 
+diff --git a/include/asm-sh/bugs.h b/include/asm-sh/bugs.h
+index b66139f..def8128 100644
+--- a/include/asm-sh/bugs.h
++++ b/include/asm-sh/bugs.h
+@@ -25,7 +25,7 @@ static void __init check_bugs(void)
+ 	case CPU_SH7619:
+ 		*p++ = '2';
+ 		break;
+-	case CPU_SH7206:
++	case CPU_SH7203 ... CPU_SH7263:
+ 		*p++ = '2';
+ 		*p++ = 'a';
+ 		break;
+@@ -35,7 +35,7 @@ static void __init check_bugs(void)
+ 	case CPU_SH7750 ... CPU_SH4_501:
+ 		*p++ = '4';
+ 		break;
+-	case CPU_SH7770 ... CPU_SHX3:
++	case CPU_SH7763 ... CPU_SHX3:
+ 		*p++ = '4';
+ 		*p++ = 'a';
+ 		break;
+@@ -48,9 +48,16 @@ static void __init check_bugs(void)
+ 		*p++ = 's';
+ 		*p++ = 'p';
+ 		break;
+-	default:
+-		*p++ = '?';
+-		*p++ = '!';
++	case CPU_SH5_101 ... CPU_SH5_103:
++		*p++ = '6';
++		*p++ = '4';
++		break;
++	case CPU_SH_NONE:
++		/*
++		 * Specifically use CPU_SH_NONE rather than default:,
++		 * so we're able to have the compiler whine about
++		 * unhandled enumerations.
++		 */
+ 		break;
  	}
  
--	if (ocfs2_node_map_test_bit(osb, &osb->umount_map, node_num)) {
--		/* If a node is in the umount map, then we've been
--		 * expecting him to go down and we know ahead of time
--		 * that recovery is not necessary. */
--		ocfs2_node_map_clear_bit(osb, &osb->umount_map, node_num);
--		return;
--	}
--
- 	ocfs2_recovery_thread(osb, node_num);
--
--	ocfs2_remove_node_from_vote_queues(osb, node_num);
--}
+diff --git a/include/asm-sh/byteorder.h b/include/asm-sh/byteorder.h
+index bff2b13..0eb9904 100644
+--- a/include/asm-sh/byteorder.h
++++ b/include/asm-sh/byteorder.h
+@@ -3,40 +3,55 @@
+ 
+ /*
+  * Copyright (C) 1999  Niibe Yutaka
++ * Copyright (C) 2000, 2001  Paolo Alberelli
+  */
 -
--static void ocfs2_hb_node_down_cb(struct o2nm_node *node,
--				  int node_num,
--				  void *data)
--{
--	ocfs2_do_node_down(node_num, (struct ocfs2_super *) data);
+-#include <asm/types.h>
+ #include <linux/compiler.h>
++#include <linux/types.h>
+ 
+-static __inline__ __attribute_const__ __u32 ___arch__swab32(__u32 x)
++static inline __attribute_const__ __u32 ___arch__swab32(__u32 x)
+ {
+-	__asm__("swap.b	%0, %0\n\t"
+-		"swap.w %0, %0\n\t"
+-		"swap.b %0, %0"
++	__asm__(
++#ifdef CONFIG_SUPERH32
++		"swap.b		%0, %0\n\t"
++		"swap.w		%0, %0\n\t"
++		"swap.b		%0, %0"
++#else
++		"byterev	%0, %0\n\t"
++		"shari		%0, 32, %0"
++#endif
+ 		: "=r" (x)
+ 		: "0" (x));
++
+ 	return x;
  }
  
- /* Called from the dlm when it's about to evict a node. We may also
-@@ -121,27 +95,8 @@ static void ocfs2_dlm_eviction_cb(int node_num,
- 	ocfs2_do_node_down(node_num, osb);
+-static __inline__ __attribute_const__ __u16 ___arch__swab16(__u16 x)
++static inline __attribute_const__ __u16 ___arch__swab16(__u16 x)
+ {
+-	__asm__("swap.b %0, %0"
++	__asm__(
++#ifdef CONFIG_SUPERH32
++		"swap.b		%0, %0"
++#else
++		"byterev	%0, %0\n\t"
++		"shari		%0, 32, %0"
++
++#endif
+ 		: "=r" (x)
+ 		:  "0" (x));
++
+ 	return x;
  }
  
--static void ocfs2_hb_node_up_cb(struct o2nm_node *node,
--				int node_num,
--				void *data)
--{
--	struct ocfs2_super *osb = data;
+-static inline __u64 ___arch__swab64(__u64 val) 
+-{ 
+-	union { 
++static inline __u64 ___arch__swab64(__u64 val)
++{
++	union {
+ 		struct { __u32 a,b; } s;
+ 		__u64 u;
+ 	} v, w;
+ 	v.u = val;
+-	w.s.b = ___arch__swab32(v.s.a); 
+-	w.s.a = ___arch__swab32(v.s.b); 
+-	return w.u;	
+-} 
++	w.s.b = ___arch__swab32(v.s.a);
++	w.s.a = ___arch__swab32(v.s.b);
++	return w.u;
++}
+ 
+ #define __arch__swab64(x) ___arch__swab64(x)
+ #define __arch__swab32(x) ___arch__swab32(x)
+diff --git a/include/asm-sh/cache.h b/include/asm-sh/cache.h
+index 01e5cf5..083419f 100644
+--- a/include/asm-sh/cache.h
++++ b/include/asm-sh/cache.h
+@@ -12,11 +12,6 @@
+ #include <linux/init.h>
+ #include <asm/cpu/cache.h>
+ 
+-#define SH_CACHE_VALID		1
+-#define SH_CACHE_UPDATED	2
+-#define SH_CACHE_COMBINED	4
+-#define SH_CACHE_ASSOC		8
+-
+ #define L1_CACHE_BYTES		(1 << L1_CACHE_SHIFT)
+ 
+ #define __read_mostly __attribute__((__section__(".data.read_mostly")))
+diff --git a/include/asm-sh/checksum.h b/include/asm-sh/checksum.h
+index 4bc8357..67496ab 100644
+--- a/include/asm-sh/checksum.h
++++ b/include/asm-sh/checksum.h
+@@ -1,215 +1,5 @@
+-#ifndef __ASM_SH_CHECKSUM_H
+-#define __ASM_SH_CHECKSUM_H
 -
--	BUG_ON(osb->node_num == node_num);
+-/*
+- * 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 by Kaz Kojima & Niibe Yutaka
+- */
 -
--	mlog(0, "node up event for %d\n", node_num);
--	ocfs2_node_map_clear_bit(osb, &osb->umount_map, node_num);
+-#include <linux/in6.h>
+-
+-/*
+- * computes the checksum of a memory block at buff, length len,
+- * and adds in "sum" (32-bit)
+- *
+- * returns a 32-bit number suitable for feeding into itself
+- * or csum_tcpudp_magic
+- *
+- * this function must be called with even lengths, except
+- * for the last fragment, which may be odd
+- *
+- * it's best to have buff aligned on a 32-bit boundary
+- */
+-asmlinkage __wsum csum_partial(const void *buff, int len, __wsum sum);
+-
+-/*
+- * the same as csum_partial, but copies from src while it
+- * checksums, and handles user-space pointer exceptions correctly, when needed.
+- *
+- * here even more important to align src and dst on a 32-bit (or even
+- * better 64-bit) boundary
+- */
+-
+-asmlinkage __wsum csum_partial_copy_generic(const void *src, void *dst,
+-					    int len, __wsum sum,
+-					    int *src_err_ptr, int *dst_err_ptr);
+-
+-/*
+- *	Note: when you get a NULL pointer exception here this means someone
+- *	passed in an incorrect kernel address to one of these functions.
+- *
+- *	If you use these functions directly please don't forget the
+- *	access_ok().
+- */
+-static inline
+-__wsum csum_partial_copy_nocheck(const void *src, void *dst,
+-				 int len, __wsum sum)
+-{
+-	return csum_partial_copy_generic(src, dst, len, sum, NULL, NULL);
 -}
 -
- void ocfs2_setup_hb_callbacks(struct ocfs2_super *osb)
- {
--	o2hb_setup_callback(&osb->osb_hb_down, O2HB_NODE_DOWN_CB,
--			    ocfs2_hb_node_down_cb, osb,
--			    OCFS2_HB_NODE_DOWN_PRI);
+-static inline
+-__wsum csum_partial_copy_from_user(const void __user *src, void *dst,
+-				   int len, __wsum sum, int *err_ptr)
+-{
+-	return csum_partial_copy_generic((__force const void *)src, dst,
+-					len, sum, err_ptr, NULL);
+-}
 -
--	o2hb_setup_callback(&osb->osb_hb_up, O2HB_NODE_UP_CB,
--			    ocfs2_hb_node_up_cb, osb, OCFS2_HB_NODE_UP_PRI);
+-/*
+- *	Fold a partial checksum
+- */
 -
- 	/* Not exactly a heartbeat callback, but leads to essentially
- 	 * the same path so we set it up here. */
- 	dlm_setup_eviction_cb(&osb->osb_eviction_cb,
-@@ -149,39 +104,6 @@ void ocfs2_setup_hb_callbacks(struct ocfs2_super *osb)
- 			      osb);
- }
- 
--/* Most functions here are just stubs for now... */
--int ocfs2_register_hb_callbacks(struct ocfs2_super *osb)
+-static inline __sum16 csum_fold(__wsum sum)
 -{
--	int status;
+-	unsigned int __dummy;
+-	__asm__("swap.w %0, %1\n\t"
+-		"extu.w	%0, %0\n\t"
+-		"extu.w	%1, %1\n\t"
+-		"add	%1, %0\n\t"
+-		"swap.w	%0, %1\n\t"
+-		"add	%1, %0\n\t"
+-		"not	%0, %0\n\t"
+-		: "=r" (sum), "=&r" (__dummy)
+-		: "0" (sum)
+-		: "t");
+-	return (__force __sum16)sum;
+-}
 -
--	if (ocfs2_mount_local(osb))
--		return 0;
+-/*
+- *	This is a version of ip_compute_csum() optimized for IP headers,
+- *	which always checksum on 4 octet boundaries.
+- *
+- *      i386 version by Jorge Cwik <jorge at laser.satlink.net>, adapted
+- *      for linux by * Arnt Gulbrandsen.
+- */
+-static inline __sum16 ip_fast_csum(const void *iph, unsigned int ihl)
+-{
+-	unsigned int sum, __dummy0, __dummy1;
 -
--	status = o2hb_register_callback(osb->uuid_str, &osb->osb_hb_down);
--	if (status < 0) {
--		mlog_errno(status);
--		goto bail;
--	}
+-	__asm__ __volatile__(
+-		"mov.l	@%1+, %0\n\t"
+-		"mov.l	@%1+, %3\n\t"
+-		"add	#-2, %2\n\t"
+-		"clrt\n\t"
+-		"1:\t"
+-		"addc	%3, %0\n\t"
+-		"movt	%4\n\t"
+-		"mov.l	@%1+, %3\n\t"
+-		"dt	%2\n\t"
+-		"bf/s	1b\n\t"
+-		" cmp/eq #1, %4\n\t"
+-		"addc	%3, %0\n\t"
+-		"addc	%2, %0"	    /* Here %2 is 0, add carry-bit */
+-	/* Since the input registers which are loaded with iph and ihl
+-	   are modified, we must also specify them as outputs, or gcc
+-	   will assume they contain their original values. */
+-	: "=r" (sum), "=r" (iph), "=r" (ihl), "=&r" (__dummy0), "=&z" (__dummy1)
+-	: "1" (iph), "2" (ihl)
+-	: "t");
+-
+-	return	csum_fold(sum);
+-}
+-
+-static inline __wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr,
+-					unsigned short len,
+-					unsigned short proto,
+-					__wsum sum)
+-{
+-#ifdef __LITTLE_ENDIAN__
+-	unsigned long len_proto = (proto + len) << 8;
++#ifdef CONFIG_SUPERH32
++# include "checksum_32.h"
+ #else
+-	unsigned long len_proto = proto + len;
++# include "checksum_64.h"
+ #endif
+-	__asm__("clrt\n\t"
+-		"addc	%0, %1\n\t"
+-		"addc	%2, %1\n\t"
+-		"addc	%3, %1\n\t"
+-		"movt	%0\n\t"
+-		"add	%1, %0"
+-		: "=r" (sum), "=r" (len_proto)
+-		: "r" (daddr), "r" (saddr), "1" (len_proto), "0" (sum)
+-		: "t");
 -
--	status = o2hb_register_callback(osb->uuid_str, &osb->osb_hb_up);
--	if (status < 0) {
--		mlog_errno(status);
--		o2hb_unregister_callback(osb->uuid_str, &osb->osb_hb_down);
--	}
+-	return sum;
+-}
 -
--bail:
--	return status;
+-/*
+- * computes the checksum of the TCP/UDP pseudo-header
+- * returns a 16-bit checksum, already complemented
+- */
+-static inline __sum16 csum_tcpudp_magic(__be32 saddr, __be32 daddr,
+-					unsigned short len,
+-					unsigned short proto,
+-					__wsum sum)
+-{
+-	return csum_fold(csum_tcpudp_nofold(saddr, daddr, len, proto, sum));
 -}
 -
--void ocfs2_clear_hb_callbacks(struct ocfs2_super *osb)
+-/*
+- * this routine is used for miscellaneous IP-like checksums, mainly
+- * in icmp.c
+- */
+-static inline __sum16 ip_compute_csum(const void *buff, int len)
 -{
--	if (ocfs2_mount_local(osb))
--		return;
+-    return csum_fold(csum_partial(buff, len, 0));
+-}
 -
--	o2hb_unregister_callback(osb->uuid_str, &osb->osb_hb_down);
--	o2hb_unregister_callback(osb->uuid_str, &osb->osb_hb_up);
+-#define _HAVE_ARCH_IPV6_CSUM
+-static inline __sum16 csum_ipv6_magic(const struct in6_addr *saddr,
+-				      const struct in6_addr *daddr,
+-				      __u32 len, unsigned short proto,
+-				      __wsum sum)
+-{
+-	unsigned int __dummy;
+-	__asm__("clrt\n\t"
+-		"mov.l	@(0,%2), %1\n\t"
+-		"addc	%1, %0\n\t"
+-		"mov.l	@(4,%2), %1\n\t"
+-		"addc	%1, %0\n\t"
+-		"mov.l	@(8,%2), %1\n\t"
+-		"addc	%1, %0\n\t"
+-		"mov.l	@(12,%2), %1\n\t"
+-		"addc	%1, %0\n\t"
+-		"mov.l	@(0,%3), %1\n\t"
+-		"addc	%1, %0\n\t"
+-		"mov.l	@(4,%3), %1\n\t"
+-		"addc	%1, %0\n\t"
+-		"mov.l	@(8,%3), %1\n\t"
+-		"addc	%1, %0\n\t"
+-		"mov.l	@(12,%3), %1\n\t"
+-		"addc	%1, %0\n\t"
+-		"addc	%4, %0\n\t"
+-		"addc	%5, %0\n\t"
+-		"movt	%1\n\t"
+-		"add	%1, %0\n"
+-		: "=r" (sum), "=&r" (__dummy)
+-		: "r" (saddr), "r" (daddr),
+-		  "r" (htonl(len)), "r" (htonl(proto)), "0" (sum)
+-		: "t");
+-
+-	return csum_fold(sum);
 -}
 -
- void ocfs2_stop_heartbeat(struct ocfs2_super *osb)
- {
- 	int ret;
-@@ -341,8 +263,6 @@ int ocfs2_recovery_map_set(struct ocfs2_super *osb,
- 
- 	spin_lock(&osb->node_map_lock);
- 
--	__ocfs2_node_map_clear_bit(&osb->mounted_map, num);
+-/*
+- *	Copy and checksum to user
+- */
+-#define HAVE_CSUM_COPY_USER
+-static inline __wsum csum_and_copy_to_user(const void *src,
+-					   void __user *dst,
+-					   int len, __wsum sum,
+-					   int *err_ptr)
+-{
+-	if (access_ok(VERIFY_WRITE, dst, len))
+-		return csum_partial_copy_generic((__force const void *)src,
+-						dst, len, sum, NULL, err_ptr);
 -
- 	if (!test_bit(num, osb->recovery_map.map)) {
- 	    __ocfs2_node_map_set_bit(&osb->recovery_map, num);
- 	    set = 1;
-diff --git a/fs/ocfs2/heartbeat.h b/fs/ocfs2/heartbeat.h
-index e8fb079..5685921 100644
---- a/fs/ocfs2/heartbeat.h
-+++ b/fs/ocfs2/heartbeat.h
-@@ -29,8 +29,6 @@
- void ocfs2_init_node_maps(struct ocfs2_super *osb);
- 
- void ocfs2_setup_hb_callbacks(struct ocfs2_super *osb);
--int ocfs2_register_hb_callbacks(struct ocfs2_super *osb);
--void ocfs2_clear_hb_callbacks(struct ocfs2_super *osb);
- void ocfs2_stop_heartbeat(struct ocfs2_super *osb);
- 
- /* node map functions - used to keep track of mounted and in-recovery
-diff --git a/fs/ocfs2/inode.c b/fs/ocfs2/inode.c
-index ebb2bbe..7e9e4c7 100644
---- a/fs/ocfs2/inode.c
-+++ b/fs/ocfs2/inode.c
-@@ -49,7 +49,6 @@
- #include "symlink.h"
- #include "sysfile.h"
- #include "uptodate.h"
--#include "vote.h"
+-	if (len)
+-		*err_ptr = -EFAULT;
+-
+-	return (__force __wsum)-1; /* invalid checksum */
+-}
+-#endif /* __ASM_SH_CHECKSUM_H */
+diff --git a/include/asm-sh/checksum_32.h b/include/asm-sh/checksum_32.h
+new file mode 100644
+index 0000000..4bc8357
+--- /dev/null
++++ b/include/asm-sh/checksum_32.h
+@@ -0,0 +1,215 @@
++#ifndef __ASM_SH_CHECKSUM_H
++#define __ASM_SH_CHECKSUM_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.
++ *
++ * Copyright (C) 1999 by Kaz Kojima & Niibe Yutaka
++ */
++
++#include <linux/in6.h>
++
++/*
++ * computes the checksum of a memory block at buff, length len,
++ * and adds in "sum" (32-bit)
++ *
++ * returns a 32-bit number suitable for feeding into itself
++ * or csum_tcpudp_magic
++ *
++ * this function must be called with even lengths, except
++ * for the last fragment, which may be odd
++ *
++ * it's best to have buff aligned on a 32-bit boundary
++ */
++asmlinkage __wsum csum_partial(const void *buff, int len, __wsum sum);
++
++/*
++ * the same as csum_partial, but copies from src while it
++ * checksums, and handles user-space pointer exceptions correctly, when needed.
++ *
++ * here even more important to align src and dst on a 32-bit (or even
++ * better 64-bit) boundary
++ */
++
++asmlinkage __wsum csum_partial_copy_generic(const void *src, void *dst,
++					    int len, __wsum sum,
++					    int *src_err_ptr, int *dst_err_ptr);
++
++/*
++ *	Note: when you get a NULL pointer exception here this means someone
++ *	passed in an incorrect kernel address to one of these functions.
++ *
++ *	If you use these functions directly please don't forget the
++ *	access_ok().
++ */
++static inline
++__wsum csum_partial_copy_nocheck(const void *src, void *dst,
++				 int len, __wsum sum)
++{
++	return csum_partial_copy_generic(src, dst, len, sum, NULL, NULL);
++}
++
++static inline
++__wsum csum_partial_copy_from_user(const void __user *src, void *dst,
++				   int len, __wsum sum, int *err_ptr)
++{
++	return csum_partial_copy_generic((__force const void *)src, dst,
++					len, sum, err_ptr, NULL);
++}
++
++/*
++ *	Fold a partial checksum
++ */
++
++static inline __sum16 csum_fold(__wsum sum)
++{
++	unsigned int __dummy;
++	__asm__("swap.w %0, %1\n\t"
++		"extu.w	%0, %0\n\t"
++		"extu.w	%1, %1\n\t"
++		"add	%1, %0\n\t"
++		"swap.w	%0, %1\n\t"
++		"add	%1, %0\n\t"
++		"not	%0, %0\n\t"
++		: "=r" (sum), "=&r" (__dummy)
++		: "0" (sum)
++		: "t");
++	return (__force __sum16)sum;
++}
++
++/*
++ *	This is a version of ip_compute_csum() optimized for IP headers,
++ *	which always checksum on 4 octet boundaries.
++ *
++ *      i386 version by Jorge Cwik <jorge at laser.satlink.net>, adapted
++ *      for linux by * Arnt Gulbrandsen.
++ */
++static inline __sum16 ip_fast_csum(const void *iph, unsigned int ihl)
++{
++	unsigned int sum, __dummy0, __dummy1;
++
++	__asm__ __volatile__(
++		"mov.l	@%1+, %0\n\t"
++		"mov.l	@%1+, %3\n\t"
++		"add	#-2, %2\n\t"
++		"clrt\n\t"
++		"1:\t"
++		"addc	%3, %0\n\t"
++		"movt	%4\n\t"
++		"mov.l	@%1+, %3\n\t"
++		"dt	%2\n\t"
++		"bf/s	1b\n\t"
++		" cmp/eq #1, %4\n\t"
++		"addc	%3, %0\n\t"
++		"addc	%2, %0"	    /* Here %2 is 0, add carry-bit */
++	/* Since the input registers which are loaded with iph and ihl
++	   are modified, we must also specify them as outputs, or gcc
++	   will assume they contain their original values. */
++	: "=r" (sum), "=r" (iph), "=r" (ihl), "=&r" (__dummy0), "=&z" (__dummy1)
++	: "1" (iph), "2" (ihl)
++	: "t");
++
++	return	csum_fold(sum);
++}
++
++static inline __wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr,
++					unsigned short len,
++					unsigned short proto,
++					__wsum sum)
++{
++#ifdef __LITTLE_ENDIAN__
++	unsigned long len_proto = (proto + len) << 8;
++#else
++	unsigned long len_proto = proto + len;
++#endif
++	__asm__("clrt\n\t"
++		"addc	%0, %1\n\t"
++		"addc	%2, %1\n\t"
++		"addc	%3, %1\n\t"
++		"movt	%0\n\t"
++		"add	%1, %0"
++		: "=r" (sum), "=r" (len_proto)
++		: "r" (daddr), "r" (saddr), "1" (len_proto), "0" (sum)
++		: "t");
++
++	return sum;
++}
++
++/*
++ * computes the checksum of the TCP/UDP pseudo-header
++ * returns a 16-bit checksum, already complemented
++ */
++static inline __sum16 csum_tcpudp_magic(__be32 saddr, __be32 daddr,
++					unsigned short len,
++					unsigned short proto,
++					__wsum sum)
++{
++	return csum_fold(csum_tcpudp_nofold(saddr, daddr, len, proto, sum));
++}
++
++/*
++ * this routine is used for miscellaneous IP-like checksums, mainly
++ * in icmp.c
++ */
++static inline __sum16 ip_compute_csum(const void *buff, int len)
++{
++    return csum_fold(csum_partial(buff, len, 0));
++}
++
++#define _HAVE_ARCH_IPV6_CSUM
++static inline __sum16 csum_ipv6_magic(const struct in6_addr *saddr,
++				      const struct in6_addr *daddr,
++				      __u32 len, unsigned short proto,
++				      __wsum sum)
++{
++	unsigned int __dummy;
++	__asm__("clrt\n\t"
++		"mov.l	@(0,%2), %1\n\t"
++		"addc	%1, %0\n\t"
++		"mov.l	@(4,%2), %1\n\t"
++		"addc	%1, %0\n\t"
++		"mov.l	@(8,%2), %1\n\t"
++		"addc	%1, %0\n\t"
++		"mov.l	@(12,%2), %1\n\t"
++		"addc	%1, %0\n\t"
++		"mov.l	@(0,%3), %1\n\t"
++		"addc	%1, %0\n\t"
++		"mov.l	@(4,%3), %1\n\t"
++		"addc	%1, %0\n\t"
++		"mov.l	@(8,%3), %1\n\t"
++		"addc	%1, %0\n\t"
++		"mov.l	@(12,%3), %1\n\t"
++		"addc	%1, %0\n\t"
++		"addc	%4, %0\n\t"
++		"addc	%5, %0\n\t"
++		"movt	%1\n\t"
++		"add	%1, %0\n"
++		: "=r" (sum), "=&r" (__dummy)
++		: "r" (saddr), "r" (daddr),
++		  "r" (htonl(len)), "r" (htonl(proto)), "0" (sum)
++		: "t");
++
++	return csum_fold(sum);
++}
++
++/*
++ *	Copy and checksum to user
++ */
++#define HAVE_CSUM_COPY_USER
++static inline __wsum csum_and_copy_to_user(const void *src,
++					   void __user *dst,
++					   int len, __wsum sum,
++					   int *err_ptr)
++{
++	if (access_ok(VERIFY_WRITE, dst, len))
++		return csum_partial_copy_generic((__force const void *)src,
++						dst, len, sum, NULL, err_ptr);
++
++	if (len)
++		*err_ptr = -EFAULT;
++
++	return (__force __wsum)-1; /* invalid checksum */
++}
++#endif /* __ASM_SH_CHECKSUM_H */
+diff --git a/include/asm-sh/checksum_64.h b/include/asm-sh/checksum_64.h
+new file mode 100644
+index 0000000..9c62a03
+--- /dev/null
++++ b/include/asm-sh/checksum_64.h
+@@ -0,0 +1,78 @@
++#ifndef __ASM_SH_CHECKSUM_64_H
++#define __ASM_SH_CHECKSUM_64_H
++
++/*
++ * include/asm-sh/checksum_64.h
++ *
++ * Copyright (C) 2000, 2001  Paolo Alberelli
++ *
++ * 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.
++ */
++
++/*
++ * computes the checksum of a memory block at buff, length len,
++ * and adds in "sum" (32-bit)
++ *
++ * returns a 32-bit number suitable for feeding into itself
++ * or csum_tcpudp_magic
++ *
++ * this function must be called with even lengths, except
++ * for the last fragment, which may be odd
++ *
++ * it's best to have buff aligned on a 32-bit boundary
++ */
++asmlinkage __wsum csum_partial(const void *buff, int len, __wsum sum);
++
++/*
++ *	Note: when you get a NULL pointer exception here this means someone
++ *	passed in an incorrect kernel address to one of these functions.
++ *
++ *	If you use these functions directly please don't forget the
++ *	access_ok().
++ */
++
++
++__wsum csum_partial_copy_nocheck(const void *src, void *dst, int len,
++				       __wsum sum);
++
++__wsum csum_partial_copy_from_user(const void __user *src, void *dst,
++					 int len, __wsum sum, int *err_ptr);
++
++static inline __sum16 csum_fold(__wsum csum)
++{
++	u32 sum = (__force u32)csum;
++        sum = (sum & 0xffff) + (sum >> 16);
++        sum = (sum & 0xffff) + (sum >> 16);
++        return (__force __sum16)~sum;
++}
++
++__sum16 ip_fast_csum(const void *iph, unsigned int ihl);
++
++__wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr,
++				 unsigned short len, unsigned short proto,
++				 __wsum sum);
++
++/*
++ * computes the checksum of the TCP/UDP pseudo-header
++ * returns a 16-bit checksum, already complemented
++ */
++static inline __sum16 csum_tcpudp_magic(__be32 saddr, __be32 daddr,
++						   unsigned short len,
++						   unsigned short proto,
++						   __wsum sum)
++{
++	return csum_fold(csum_tcpudp_nofold(saddr,daddr,len,proto,sum));
++}
++
++/*
++ * this routine is used for miscellaneous IP-like checksums, mainly
++ * in icmp.c
++ */
++static inline __sum16 ip_compute_csum(const void *buff, int len)
++{
++	return csum_fold(csum_partial(buff, len, 0));
++}
++
++#endif /* __ASM_SH_CHECKSUM_64_H */
+diff --git a/include/asm-sh/cmpxchg-grb.h b/include/asm-sh/cmpxchg-grb.h
+new file mode 100644
+index 0000000..e2681ab
+--- /dev/null
++++ b/include/asm-sh/cmpxchg-grb.h
+@@ -0,0 +1,70 @@
++#ifndef __ASM_SH_CMPXCHG_GRB_H
++#define __ASM_SH_CMPXCHG_GRB_H
++
++static inline unsigned long xchg_u32(volatile u32 *m, unsigned long val)
++{
++	unsigned long retval;
++
++	__asm__ __volatile__ (
++		"   .align 2              \n\t"
++		"   mova    1f,   r0      \n\t" /* r0 = end point */
++		"   nop                   \n\t"
++		"   mov    r15,   r1      \n\t" /* r1 = saved sp */
++		"   mov    #-4,   r15     \n\t" /* LOGIN */
++		"   mov.l  @%1,   %0      \n\t" /* load  old value */
++		"   mov.l   %2,   @%1     \n\t" /* store new value */
++		"1: mov     r1,   r15     \n\t" /* LOGOUT */
++		: "=&r" (retval),
++		  "+r"  (m)
++		: "r"   (val)
++		: "memory", "r0", "r1");
++
++	return retval;
++}
++
++static inline unsigned long xchg_u8(volatile u8 *m, unsigned long val)
++{
++	unsigned long retval;
++
++	__asm__ __volatile__ (
++		"   .align  2             \n\t"
++		"   mova    1f,   r0      \n\t" /* r0 = end point */
++		"   mov    r15,   r1      \n\t" /* r1 = saved sp */
++		"   mov    #-6,   r15     \n\t" /* LOGIN */
++		"   mov.b  @%1,   %0      \n\t" /* load  old value */
++		"   extu.b  %0,   %0      \n\t" /* extend as unsigned */
++		"   mov.b   %2,   @%1     \n\t" /* store new value */
++		"1: mov     r1,   r15     \n\t" /* LOGOUT */
++		: "=&r" (retval),
++		  "+r"  (m)
++		: "r"   (val)
++		: "memory" , "r0", "r1");
++
++	return retval;
++}
++
++static inline unsigned long __cmpxchg_u32(volatile int *m, unsigned long old,
++					  unsigned long new)
++{
++	unsigned long retval;
++
++	__asm__ __volatile__ (
++		"   .align  2             \n\t"
++		"   mova    1f,   r0      \n\t" /* r0 = end point */
++		"   nop                   \n\t"
++		"   mov    r15,   r1      \n\t" /* r1 = saved sp */
++		"   mov    #-8,   r15     \n\t" /* LOGIN */
++		"   mov.l  @%1,   %0      \n\t" /* load  old value */
++		"   cmp/eq  %0,   %2      \n\t"
++		"   bf            1f      \n\t" /* if not equal */
++		"   mov.l   %2,   @%1     \n\t" /* store new value */
++		"1: mov     r1,   r15     \n\t" /* LOGOUT */
++		: "=&r" (retval),
++		  "+r"  (m)
++		: "r"   (new)
++		: "memory" , "r0", "r1", "t");
++
++	return retval;
++}
++
++#endif /* __ASM_SH_CMPXCHG_GRB_H */
+diff --git a/include/asm-sh/cmpxchg-irq.h b/include/asm-sh/cmpxchg-irq.h
+new file mode 100644
+index 0000000..43049ec
+--- /dev/null
++++ b/include/asm-sh/cmpxchg-irq.h
+@@ -0,0 +1,40 @@
++#ifndef __ASM_SH_CMPXCHG_IRQ_H
++#define __ASM_SH_CMPXCHG_IRQ_H
++
++static inline unsigned long xchg_u32(volatile u32 *m, unsigned long val)
++{
++	unsigned long flags, retval;
++
++	local_irq_save(flags);
++	retval = *m;
++	*m = val;
++	local_irq_restore(flags);
++	return retval;
++}
++
++static inline unsigned long xchg_u8(volatile u8 *m, unsigned long val)
++{
++	unsigned long flags, retval;
++
++	local_irq_save(flags);
++	retval = *m;
++	*m = val & 0xff;
++	local_irq_restore(flags);
++	return retval;
++}
++
++static inline unsigned long __cmpxchg_u32(volatile int *m, unsigned long old,
++	unsigned long new)
++{
++	__u32 retval;
++	unsigned long flags;
++
++	local_irq_save(flags);
++	retval = *m;
++	if (retval == old)
++		*m = new;
++	local_irq_restore(flags);       /* implies memory barrier  */
++	return retval;
++}
++
++#endif /* __ASM_SH_CMPXCHG_IRQ_H */
+diff --git a/include/asm-sh/cpu-sh2/addrspace.h b/include/asm-sh/cpu-sh2/addrspace.h
+index 8706c90..2b9ab93 100644
+--- a/include/asm-sh/cpu-sh2/addrspace.h
++++ b/include/asm-sh/cpu-sh2/addrspace.h
+@@ -10,7 +10,10 @@
+ #ifndef __ASM_CPU_SH2_ADDRSPACE_H
+ #define __ASM_CPU_SH2_ADDRSPACE_H
+ 
+-/* Should fill here */
++#define P0SEG		0x00000000
++#define P1SEG		0x80000000
++#define P2SEG		0xa0000000
++#define P3SEG		0xc0000000
++#define P4SEG		0xe0000000
+ 
+ #endif /* __ASM_CPU_SH2_ADDRSPACE_H */
+-
+diff --git a/include/asm-sh/cpu-sh2/cache.h b/include/asm-sh/cpu-sh2/cache.h
+index f02ba7a..4e0b165 100644
+--- a/include/asm-sh/cpu-sh2/cache.h
++++ b/include/asm-sh/cpu-sh2/cache.h
+@@ -12,9 +12,13 @@
+ 
+ #define L1_CACHE_SHIFT	4
+ 
++#define SH_CACHE_VALID		1
++#define SH_CACHE_UPDATED	2
++#define SH_CACHE_COMBINED	4
++#define SH_CACHE_ASSOC		8
++
+ #if defined(CONFIG_CPU_SUBTYPE_SH7619)
+-#define CCR1		0xffffffec
+-#define CCR		CCR1
++#define CCR		0xffffffec
+ 
+ #define CCR_CACHE_CE	0x01	/* Cache enable */
+ #define CCR_CACHE_WT	0x06    /* CCR[bit1=1,bit2=1] */
+diff --git a/include/asm-sh/cpu-sh2/rtc.h b/include/asm-sh/cpu-sh2/rtc.h
+new file mode 100644
+index 0000000..39e2d6e
+--- /dev/null
++++ b/include/asm-sh/cpu-sh2/rtc.h
+@@ -0,0 +1,8 @@
++#ifndef __ASM_SH_CPU_SH2_RTC_H
++#define __ASM_SH_CPU_SH2_RTC_H
++
++#define rtc_reg_size		sizeof(u16)
++#define RTC_BIT_INVERTED	0
++#define RTC_DEF_CAPABILITIES	0UL
++
++#endif /* __ASM_SH_CPU_SH2_RTC_H */
+diff --git a/include/asm-sh/cpu-sh2a/addrspace.h b/include/asm-sh/cpu-sh2a/addrspace.h
+index 3d2e9aa..795ddd6 100644
+--- a/include/asm-sh/cpu-sh2a/addrspace.h
++++ b/include/asm-sh/cpu-sh2a/addrspace.h
+@@ -1 +1,10 @@
+-#include <asm/cpu-sh2/addrspace.h>
++#ifndef __ASM_SH_CPU_SH2A_ADDRSPACE_H
++#define __ASM_SH_CPU_SH2A_ADDRSPACE_H
++
++#define P0SEG		0x00000000
++#define P1SEG		0x00000000
++#define P2SEG		0x20000000
++#define P3SEG		0x00000000
++#define P4SEG		0x80000000
++
++#endif /* __ASM_SH_CPU_SH2A_ADDRSPACE_H */
+diff --git a/include/asm-sh/cpu-sh2a/cache.h b/include/asm-sh/cpu-sh2a/cache.h
+index 3e4b9e4..afe228b 100644
+--- a/include/asm-sh/cpu-sh2a/cache.h
++++ b/include/asm-sh/cpu-sh2a/cache.h
+@@ -12,11 +12,13 @@
+ 
+ #define L1_CACHE_SHIFT	4
+ 
+-#define CCR1		0xfffc1000
+-#define CCR2		0xfffc1004
++#define SH_CACHE_VALID		1
++#define SH_CACHE_UPDATED	2
++#define SH_CACHE_COMBINED	4
++#define SH_CACHE_ASSOC		8
+ 
+-/* CCR1 behaves more like the traditional CCR */
+-#define CCR		CCR1
++#define CCR		0xfffc1000 /* CCR1 */
++#define CCR2		0xfffc1004
+ 
+ /*
+  * Most of the SH-2A CCR1 definitions resemble the SH-4 ones. All others not
+@@ -36,4 +38,3 @@
+ #define CCR_CACHE_INVALIDATE	(CCR_CACHE_OCI | CCR_CACHE_ICI)
+ 
+ #endif /* __ASM_CPU_SH2A_CACHE_H */
+-
+diff --git a/include/asm-sh/cpu-sh2a/freq.h b/include/asm-sh/cpu-sh2a/freq.h
+index e518fff..830fd43 100644
+--- a/include/asm-sh/cpu-sh2a/freq.h
++++ b/include/asm-sh/cpu-sh2a/freq.h
+@@ -10,9 +10,7 @@
+ #ifndef __ASM_CPU_SH2A_FREQ_H
+ #define __ASM_CPU_SH2A_FREQ_H
  
- #include "buffer_head_io.h"
+-#if defined(CONFIG_CPU_SUBTYPE_SH7206)
+ #define FREQCR	0xfffe0010
+-#endif
  
-@@ -58,8 +57,11 @@ struct ocfs2_find_inode_args
- 	u64		fi_blkno;
- 	unsigned long	fi_ino;
- 	unsigned int	fi_flags;
-+	unsigned int	fi_sysfile_type;
- };
+ #endif /* __ASM_CPU_SH2A_FREQ_H */
  
-+static struct lock_class_key ocfs2_sysfile_lock_key[NUM_SYSTEM_INODES];
+diff --git a/include/asm-sh/cpu-sh2a/rtc.h b/include/asm-sh/cpu-sh2a/rtc.h
+new file mode 100644
+index 0000000..afb511e
+--- /dev/null
++++ b/include/asm-sh/cpu-sh2a/rtc.h
+@@ -0,0 +1,8 @@
++#ifndef __ASM_SH_CPU_SH2A_RTC_H
++#define __ASM_SH_CPU_SH2A_RTC_H
 +
- static int ocfs2_read_locked_inode(struct inode *inode,
- 				   struct ocfs2_find_inode_args *args);
- static int ocfs2_init_locked_inode(struct inode *inode, void *opaque);
-@@ -107,7 +109,8 @@ void ocfs2_get_inode_flags(struct ocfs2_inode_info *oi)
- 		oi->ip_attr |= OCFS2_DIRSYNC_FL;
- }
++#define rtc_reg_size		sizeof(u16)
++#define RTC_BIT_INVERTED	0
++#define RTC_DEF_CAPABILITIES	RTC_CAP_4_DIGIT_YEAR
++
++#endif /* __ASM_SH_CPU_SH2A_RTC_H */
+diff --git a/include/asm-sh/cpu-sh3/addrspace.h b/include/asm-sh/cpu-sh3/addrspace.h
+index 872e9e1..0f94726 100644
+--- a/include/asm-sh/cpu-sh3/addrspace.h
++++ b/include/asm-sh/cpu-sh3/addrspace.h
+@@ -10,7 +10,10 @@
+ #ifndef __ASM_CPU_SH3_ADDRSPACE_H
+ #define __ASM_CPU_SH3_ADDRSPACE_H
+ 
+-/* Should fill here */
++#define P0SEG		0x00000000
++#define P1SEG		0x80000000
++#define P2SEG		0xa0000000
++#define P3SEG		0xc0000000
++#define P4SEG		0xe0000000
+ 
+ #endif /* __ASM_CPU_SH3_ADDRSPACE_H */
+-
+diff --git a/include/asm-sh/cpu-sh3/cache.h b/include/asm-sh/cpu-sh3/cache.h
+index 255016f..56bd838 100644
+--- a/include/asm-sh/cpu-sh3/cache.h
++++ b/include/asm-sh/cpu-sh3/cache.h
+@@ -12,6 +12,11 @@
+ 
+ #define L1_CACHE_SHIFT	4
+ 
++#define SH_CACHE_VALID		1
++#define SH_CACHE_UPDATED	2
++#define SH_CACHE_COMBINED	4
++#define SH_CACHE_ASSOC		8
++
+ #define CCR		0xffffffec	/* Address of Cache Control Register */
+ 
+ #define CCR_CACHE_CE	0x01	/* Cache Enable */
+@@ -28,7 +33,8 @@
+ 
+ #if defined(CONFIG_CPU_SUBTYPE_SH7705) || \
+     defined(CONFIG_CPU_SUBTYPE_SH7710) || \
+-    defined(CONFIG_CPU_SUBTYPE_SH7720)
++    defined(CONFIG_CPU_SUBTYPE_SH7720) || \
++    defined(CONFIG_CPU_SUBTYPE_SH7721)
+ #define CCR3	0xa40000b4
+ #define CCR_CACHE_16KB  0x00010000
+ #define CCR_CACHE_32KB	0x00020000
+diff --git a/include/asm-sh/cpu-sh3/dma.h b/include/asm-sh/cpu-sh3/dma.h
+index 54bfece..092ff9d 100644
+--- a/include/asm-sh/cpu-sh3/dma.h
++++ b/include/asm-sh/cpu-sh3/dma.h
+@@ -2,7 +2,9 @@
+ #define __ASM_CPU_SH3_DMA_H
+ 
+ 
+-#if defined(CONFIG_CPU_SUBTYPE_SH7720) || defined(CONFIG_CPU_SUBTYPE_SH7709)
++#if defined(CONFIG_CPU_SUBTYPE_SH7720) || \
++    defined(CONFIG_CPU_SUBTYPE_SH7721) || \
++    defined(CONFIG_CPU_SUBTYPE_SH7709)
+ #define SH_DMAC_BASE	0xa4010020
+ 
+ #define DMTE0_IRQ	48
+diff --git a/include/asm-sh/cpu-sh3/freq.h b/include/asm-sh/cpu-sh3/freq.h
+index 0a054b5..53c6230 100644
+--- a/include/asm-sh/cpu-sh3/freq.h
++++ b/include/asm-sh/cpu-sh3/freq.h
+@@ -10,7 +10,12 @@
+ #ifndef __ASM_CPU_SH3_FREQ_H
+ #define __ASM_CPU_SH3_FREQ_H
  
--struct inode *ocfs2_iget(struct ocfs2_super *osb, u64 blkno, int flags)
-+struct inode *ocfs2_iget(struct ocfs2_super *osb, u64 blkno, unsigned flags,
-+			 int sysfile_type)
- {
- 	struct inode *inode = NULL;
- 	struct super_block *sb = osb->sb;
-@@ -127,6 +130,7 @@ struct inode *ocfs2_iget(struct ocfs2_super *osb, u64 blkno, int flags)
- 	args.fi_blkno = blkno;
- 	args.fi_flags = flags;
- 	args.fi_ino = ino_from_blkno(sb, blkno);
-+	args.fi_sysfile_type = sysfile_type;
++#ifdef CONFIG_CPU_SUBTYPE_SH7712
++#define FRQCR			0xA415FF80
++#else
+ #define FRQCR			0xffffff80
++#endif
++
+ #define MIN_DIVISOR_NR		0
+ #define MAX_DIVISOR_NR		4
  
- 	inode = iget5_locked(sb, args.fi_ino, ocfs2_find_actor,
- 			     ocfs2_init_locked_inode, &args);
-@@ -201,6 +205,9 @@ static int ocfs2_init_locked_inode(struct inode *inode, void *opaque)
+diff --git a/include/asm-sh/cpu-sh3/gpio.h b/include/asm-sh/cpu-sh3/gpio.h
+index 48770c1..4e53eb3 100644
+--- a/include/asm-sh/cpu-sh3/gpio.h
++++ b/include/asm-sh/cpu-sh3/gpio.h
+@@ -12,7 +12,8 @@
+ #ifndef _CPU_SH3_GPIO_H
+ #define _CPU_SH3_GPIO_H
+ 
+-#if defined(CONFIG_CPU_SUBTYPE_SH7720)
++#if defined(CONFIG_CPU_SUBTYPE_SH7720) || \
++    defined(CONFIG_CPU_SUBTYPE_SH7721)
+ 
+ /* Control registers */
+ #define PORT_PACR	0xA4050100UL
+diff --git a/include/asm-sh/cpu-sh3/mmu_context.h b/include/asm-sh/cpu-sh3/mmu_context.h
+index 16c2d63..ab09da7 100644
+--- a/include/asm-sh/cpu-sh3/mmu_context.h
++++ b/include/asm-sh/cpu-sh3/mmu_context.h
+@@ -33,7 +33,8 @@
+     defined(CONFIG_CPU_SUBTYPE_SH7709) || \
+     defined(CONFIG_CPU_SUBTYPE_SH7710) || \
+     defined(CONFIG_CPU_SUBTYPE_SH7712) || \
+-    defined(CONFIG_CPU_SUBTYPE_SH7720)
++    defined(CONFIG_CPU_SUBTYPE_SH7720) || \
++    defined(CONFIG_CPU_SUBTYPE_SH7721)
+ #define INTEVT	0xa4000000	/* INTEVTE2(0xa4000000) */
+ #else
+ #define INTEVT	0xffffffd8
+diff --git a/include/asm-sh/cpu-sh3/rtc.h b/include/asm-sh/cpu-sh3/rtc.h
+new file mode 100644
+index 0000000..319404a
+--- /dev/null
++++ b/include/asm-sh/cpu-sh3/rtc.h
+@@ -0,0 +1,8 @@
++#ifndef __ASM_SH_CPU_SH3_RTC_H
++#define __ASM_SH_CPU_SH3_RTC_H
++
++#define rtc_reg_size		sizeof(u16)
++#define RTC_BIT_INVERTED	0	/* No bug on SH7708, SH7709A */
++#define RTC_DEF_CAPABILITIES	0UL
++
++#endif /* __ASM_SH_CPU_SH3_RTC_H */
+diff --git a/include/asm-sh/cpu-sh3/timer.h b/include/asm-sh/cpu-sh3/timer.h
+index 7b795ac..793acf1 100644
+--- a/include/asm-sh/cpu-sh3/timer.h
++++ b/include/asm-sh/cpu-sh3/timer.h
+@@ -23,12 +23,13 @@
+  * ---------------------------------------------------------------------------
+  */
  
- 	inode->i_ino = args->fi_ino;
- 	OCFS2_I(inode)->ip_blkno = args->fi_blkno;
-+	if (args->fi_sysfile_type != 0)
-+		lockdep_set_class(&inode->i_mutex,
-+			&ocfs2_sysfile_lock_key[args->fi_sysfile_type]);
+-#if  !defined(CONFIG_CPU_SUBTYPE_SH7720)
++#if  !defined(CONFIG_CPU_SUBTYPE_SH7720) && !defined(CONFIG_CPU_SUBTYPE_SH7721)
+ #define TMU_TOCR	0xfffffe90	/* Byte access */
+ #endif
  
- 	mlog_exit(0);
- 	return 0;
-@@ -322,7 +329,7 @@ int ocfs2_populate_inode(struct inode *inode, struct ocfs2_dinode *fe,
- 		 */
- 		BUG_ON(le32_to_cpu(fe->i_flags) & OCFS2_SYSTEM_FL);
+ #if defined(CONFIG_CPU_SUBTYPE_SH7710) || \
+-    defined(CONFIG_CPU_SUBTYPE_SH7720)
++    defined(CONFIG_CPU_SUBTYPE_SH7720) || \
++    defined(CONFIG_CPU_SUBTYPE_SH7721)
+ #define TMU_012_TSTR	0xa412fe92	/* Byte access */
+ 
+ #define TMU0_TCOR	0xa412fe94	/* Long access */
+@@ -57,7 +58,7 @@
+ #define TMU2_TCOR	0xfffffeac	/* Long access */
+ #define TMU2_TCNT	0xfffffeb0	/* Long access */
+ #define TMU2_TCR	0xfffffeb4	/* Word access */
+-#if !defined(CONFIG_CPU_SUBTYPE_SH7720)
++#if !defined(CONFIG_CPU_SUBTYPE_SH7720) && !defined(CONFIG_CPU_SUBTYPE_SH7721)
+ #define TMU2_TCPR2	0xfffffeb8	/* Long access */
+ #endif
+ #endif
+diff --git a/include/asm-sh/cpu-sh3/ubc.h b/include/asm-sh/cpu-sh3/ubc.h
+index 18467c5..4e6381d 100644
+--- a/include/asm-sh/cpu-sh3/ubc.h
++++ b/include/asm-sh/cpu-sh3/ubc.h
+@@ -12,7 +12,8 @@
+ #define __ASM_CPU_SH3_UBC_H
+ 
+ #if defined(CONFIG_CPU_SUBTYPE_SH7710) || \
+-    defined(CONFIG_CPU_SUBTYPE_SH7720)
++    defined(CONFIG_CPU_SUBTYPE_SH7720) || \
++    defined(CONFIG_CPU_SUBTYPE_SH7721)
+ #define UBC_BARA		0xa4ffffb0
+ #define UBC_BAMRA		0xa4ffffb4
+ #define UBC_BBRA		0xa4ffffb8
+diff --git a/include/asm-sh/cpu-sh4/addrspace.h b/include/asm-sh/cpu-sh4/addrspace.h
+index bb2e1b0..a3fa733 100644
+--- a/include/asm-sh/cpu-sh4/addrspace.h
++++ b/include/asm-sh/cpu-sh4/addrspace.h
+@@ -10,6 +10,12 @@
+ #ifndef __ASM_CPU_SH4_ADDRSPACE_H
+ #define __ASM_CPU_SH4_ADDRSPACE_H
+ 
++#define P0SEG		0x00000000
++#define P1SEG		0x80000000
++#define P2SEG		0xa0000000
++#define P3SEG		0xc0000000
++#define P4SEG		0xe0000000
++
+ /* Detailed P4SEG  */
+ #define P4SEG_STORE_QUE	(P4SEG)
+ #define P4SEG_IC_ADDR	0xf0000000
+diff --git a/include/asm-sh/cpu-sh4/cache.h b/include/asm-sh/cpu-sh4/cache.h
+index f92b20a..1c61ebf 100644
+--- a/include/asm-sh/cpu-sh4/cache.h
++++ b/include/asm-sh/cpu-sh4/cache.h
+@@ -12,6 +12,11 @@
+ 
+ #define L1_CACHE_SHIFT	5
+ 
++#define SH_CACHE_VALID		1
++#define SH_CACHE_UPDATED	2
++#define SH_CACHE_COMBINED	4
++#define SH_CACHE_ASSOC		8
++
+ #define CCR		0xff00001c	/* Address of Cache Control Register */
+ #define CCR_CACHE_OCE	0x0001	/* Operand Cache Enable */
+ #define CCR_CACHE_WT	0x0002	/* Write-Through (for P0,U0,P3) (else writeback)*/
+diff --git a/include/asm-sh/cpu-sh4/fpu.h b/include/asm-sh/cpu-sh4/fpu.h
+new file mode 100644
+index 0000000..febef73
+--- /dev/null
++++ b/include/asm-sh/cpu-sh4/fpu.h
+@@ -0,0 +1,32 @@
++/*
++ * linux/arch/sh/kernel/cpu/sh4/sh4_fpu.h
++ *
++ * Copyright (C) 2006 STMicroelectronics Limited
++ * Author: Carl Shaw <carl.shaw at st.com>
++ *
++ * May be copied or modified under the terms of the GNU General Public
++ * License Version 2.  See linux/COPYING for more information.
++ *
++ * Definitions for SH4 FPU operations
++ */
++
++#ifndef __CPU_SH4_FPU_H
++#define __CPU_SH4_FPU_H
++
++#define FPSCR_ENABLE_MASK	0x00000f80UL
++
++#define FPSCR_FMOV_DOUBLE	(1<<1)
++
++#define FPSCR_CAUSE_INEXACT	(1<<12)
++#define FPSCR_CAUSE_UNDERFLOW	(1<<13)
++#define FPSCR_CAUSE_OVERFLOW	(1<<14)
++#define FPSCR_CAUSE_DIVZERO	(1<<15)
++#define FPSCR_CAUSE_INVALID	(1<<16)
++#define FPSCR_CAUSE_ERROR 	(1<<17)
++
++#define FPSCR_DBL_PRECISION	(1<<19)
++#define FPSCR_ROUNDING_MODE(x)	((x >> 20) & 3)
++#define FPSCR_RM_NEAREST	(0)
++#define FPSCR_RM_ZERO		(1)
++
++#endif
+diff --git a/include/asm-sh/cpu-sh4/freq.h b/include/asm-sh/cpu-sh4/freq.h
+index dc1d32a..1ac10b9 100644
+--- a/include/asm-sh/cpu-sh4/freq.h
++++ b/include/asm-sh/cpu-sh4/freq.h
+@@ -16,7 +16,8 @@
+ #define SCLKACR			0xa4150008
+ #define SCLKBCR			0xa415000c
+ #define IrDACLKCR		0xa4150010
+-#elif defined(CONFIG_CPU_SUBTYPE_SH7780)
++#elif defined(CONFIG_CPU_SUBTYPE_SH7763) || \
++      defined(CONFIG_CPU_SUBTYPE_SH7780)
+ #define	FRQCR			0xffc80000
+ #elif defined(CONFIG_CPU_SUBTYPE_SH7785)
+ #define FRQCR0			0xffc80000
+diff --git a/include/asm-sh/cpu-sh4/mmu_context.h b/include/asm-sh/cpu-sh4/mmu_context.h
+index 979acdd..9ea8eb2 100644
+--- a/include/asm-sh/cpu-sh4/mmu_context.h
++++ b/include/asm-sh/cpu-sh4/mmu_context.h
+@@ -22,12 +22,20 @@
+ #define MMU_UTLB_ADDRESS_ARRAY	0xF6000000
+ #define MMU_PAGE_ASSOC_BIT	0x80
  
--		ocfs2_inode_lock_res_init(&OCFS2_I(inode)->ip_meta_lockres,
-+		ocfs2_inode_lock_res_init(&OCFS2_I(inode)->ip_inode_lockres,
- 					  OCFS2_LOCK_TYPE_META, 0, inode);
++#define MMUCR_TI		(1<<2)
++
+ #ifdef CONFIG_X2TLB
+ #define MMUCR_ME		(1 << 7)
+ #else
+ #define MMUCR_ME		(0)
+ #endif
  
- 		ocfs2_inode_lock_res_init(&OCFS2_I(inode)->ip_open_lockres,
-@@ -333,10 +340,6 @@ int ocfs2_populate_inode(struct inode *inode, struct ocfs2_dinode *fe,
- 				  OCFS2_LOCK_TYPE_RW, inode->i_generation,
- 				  inode);
++#if defined(CONFIG_32BIT) && defined(CONFIG_CPU_SUBTYPE_ST40)
++#define MMUCR_SE		(1 << 4)
++#else
++#define MMUCR_SE		(0)
++#endif
++
+ #ifdef CONFIG_SH_STORE_QUEUES
+ #define MMUCR_SQMD		(1 << 9)
+ #else
+@@ -35,7 +43,7 @@
+ #endif
  
--	ocfs2_inode_lock_res_init(&OCFS2_I(inode)->ip_data_lockres,
--				  OCFS2_LOCK_TYPE_DATA, inode->i_generation,
--				  inode);
--
- 	ocfs2_set_inode_flags(inode);
+ #define MMU_NTLB_ENTRIES	64
+-#define MMU_CONTROL_INIT	(0x05|MMUCR_SQMD|MMUCR_ME)
++#define MMU_CONTROL_INIT	(0x05|MMUCR_SQMD|MMUCR_ME|MMUCR_SE)
+ 
+ #define MMU_ITLB_DATA_ARRAY	0xF3000000
+ #define MMU_UTLB_DATA_ARRAY	0xF7000000
+diff --git a/include/asm-sh/cpu-sh4/rtc.h b/include/asm-sh/cpu-sh4/rtc.h
+new file mode 100644
+index 0000000..f3d0f53
+--- /dev/null
++++ b/include/asm-sh/cpu-sh4/rtc.h
+@@ -0,0 +1,8 @@
++#ifndef __ASM_SH_CPU_SH4_RTC_H
++#define __ASM_SH_CPU_SH4_RTC_H
++
++#define rtc_reg_size		sizeof(u32)
++#define RTC_BIT_INVERTED	0x40	/* bug on SH7750, SH7750S */
++#define RTC_DEF_CAPABILITIES	RTC_CAP_4_DIGIT_YEAR
++
++#endif /* __ASM_SH_CPU_SH4_RTC_H */
+diff --git a/include/asm-sh/cpu-sh5/addrspace.h b/include/asm-sh/cpu-sh5/addrspace.h
+new file mode 100644
+index 0000000..dc36b9a
+--- /dev/null
++++ b/include/asm-sh/cpu-sh5/addrspace.h
+@@ -0,0 +1,11 @@
++#ifndef __ASM_SH_CPU_SH5_ADDRSPACE_H
++#define __ASM_SH_CPU_SH5_ADDRSPACE_H
++
++#define	PHYS_PERIPHERAL_BLOCK	0x09000000
++#define PHYS_DMAC_BLOCK		0x0e000000
++#define PHYS_PCI_BLOCK		0x60000000
++#define PHYS_EMI_BLOCK		0xff000000
++
++/* No segmentation.. */
++
++#endif /* __ASM_SH_CPU_SH5_ADDRSPACE_H */
+diff --git a/include/asm-sh/cpu-sh5/cache.h b/include/asm-sh/cpu-sh5/cache.h
+new file mode 100644
+index 0000000..ed050ab
+--- /dev/null
++++ b/include/asm-sh/cpu-sh5/cache.h
+@@ -0,0 +1,97 @@
++#ifndef __ASM_SH_CPU_SH5_CACHE_H
++#define __ASM_SH_CPU_SH5_CACHE_H
++
++/*
++ * include/asm-sh/cpu-sh5/cache.h
++ *
++ * Copyright (C) 2000, 2001  Paolo Alberelli
++ * Copyright (C) 2003, 2004  Paul Mundt
++ *
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License.  See the file "COPYING" in the main directory of this archive
++ * for more details.
++ */
++
++#define L1_CACHE_SHIFT		5
++
++/* Valid and Dirty bits */
++#define SH_CACHE_VALID		(1LL<<0)
++#define SH_CACHE_UPDATED	(1LL<<57)
++
++/* Unimplemented compat bits.. */
++#define SH_CACHE_COMBINED	0
++#define SH_CACHE_ASSOC		0
++
++/* Cache flags */
++#define SH_CACHE_MODE_WT	(1LL<<0)
++#define SH_CACHE_MODE_WB	(1LL<<1)
++
++/*
++ * Control Registers.
++ */
++#define ICCR_BASE	0x01600000	/* Instruction Cache Control Register */
++#define ICCR_REG0	0		/* Register 0 offset */
++#define ICCR_REG1	1		/* Register 1 offset */
++#define ICCR0		ICCR_BASE+ICCR_REG0
++#define ICCR1		ICCR_BASE+ICCR_REG1
++
++#define ICCR0_OFF	0x0		/* Set ICACHE off */
++#define ICCR0_ON	0x1		/* Set ICACHE on */
++#define ICCR0_ICI	0x2		/* Invalidate all in IC */
++
++#define ICCR1_NOLOCK	0x0		/* Set No Locking */
++
++#define OCCR_BASE	0x01E00000	/* Operand Cache Control Register */
++#define OCCR_REG0	0		/* Register 0 offset */
++#define OCCR_REG1	1		/* Register 1 offset */
++#define OCCR0		OCCR_BASE+OCCR_REG0
++#define OCCR1		OCCR_BASE+OCCR_REG1
++
++#define OCCR0_OFF	0x0		/* Set OCACHE off */
++#define OCCR0_ON	0x1		/* Set OCACHE on */
++#define OCCR0_OCI	0x2		/* Invalidate all in OC */
++#define OCCR0_WT	0x4		/* Set OCACHE in WT Mode */
++#define OCCR0_WB	0x0		/* Set OCACHE in WB Mode */
++
++#define OCCR1_NOLOCK	0x0		/* Set No Locking */
++
++/*
++ * SH-5
++ * A bit of description here, for neff=32.
++ *
++ *                               |<--- tag  (19 bits) --->|
++ * +-----------------------------+-----------------+------+----------+------+
++ * |                             |                 | ways |set index |offset|
++ * +-----------------------------+-----------------+------+----------+------+
++ *                                ^                 2 bits   8 bits   5 bits
++ *                                +- Bit 31
++ *
++ * Cacheline size is based on offset: 5 bits = 32 bytes per line
++ * A cache line is identified by a tag + set but OCACHETAG/ICACHETAG
++ * have a broader space for registers. These are outlined by
++ * CACHE_?C_*_STEP below.
++ *
++ */
++
++/* Instruction cache */
++#define CACHE_IC_ADDRESS_ARRAY 0x01000000
++
++/* Operand Cache */
++#define CACHE_OC_ADDRESS_ARRAY 0x01800000
++
++/* These declarations relate to cache 'synonyms' in the operand cache.  A
++   'synonym' occurs where effective address bits overlap between those used for
++   indexing the cache sets and those passed to the MMU for translation.  In the
++   case of SH5-101 & SH5-103, only bit 12 is affected for 4k pages. */
++
++#define CACHE_OC_N_SYNBITS  1               /* Number of synonym bits */
++#define CACHE_OC_SYN_SHIFT  12
++/* Mask to select synonym bit(s) */
++#define CACHE_OC_SYN_MASK   (((1UL<<CACHE_OC_N_SYNBITS)-1)<<CACHE_OC_SYN_SHIFT)
++
++/*
++ * Instruction cache can't be invalidated based on physical addresses.
++ * No Instruction Cache defines required, then.
++ */
++
++#endif /* __ASM_SH_CPU_SH5_CACHE_H */
+diff --git a/include/asm-sh/cpu-sh5/cacheflush.h b/include/asm-sh/cpu-sh5/cacheflush.h
+new file mode 100644
+index 0000000..98edb5b
+--- /dev/null
++++ b/include/asm-sh/cpu-sh5/cacheflush.h
+@@ -0,0 +1,35 @@
++#ifndef __ASM_SH_CPU_SH5_CACHEFLUSH_H
++#define __ASM_SH_CPU_SH5_CACHEFLUSH_H
++
++#ifndef __ASSEMBLY__
++
++#include <asm/page.h>
++
++struct vm_area_struct;
++struct page;
++struct mm_struct;
++
++extern void flush_cache_all(void);
++extern void flush_cache_mm(struct mm_struct *mm);
++extern void flush_cache_sigtramp(unsigned long start, unsigned long end);
++extern void flush_cache_range(struct vm_area_struct *vma, unsigned long start,
++			      unsigned long end);
++extern void flush_cache_page(struct vm_area_struct *vma, unsigned long addr, unsigned long pfn);
++extern void flush_dcache_page(struct page *pg);
++extern void flush_icache_range(unsigned long start, unsigned long end);
++extern void flush_icache_user_range(struct vm_area_struct *vma,
++				    struct page *page, unsigned long addr,
++				    int len);
++
++#define flush_cache_dup_mm(mm)	flush_cache_mm(mm)
++
++#define flush_dcache_mmap_lock(mapping)		do { } while (0)
++#define flush_dcache_mmap_unlock(mapping)	do { } while (0)
++
++#define flush_icache_page(vma, page)	do { } while (0)
++#define p3_cache_init()			do { } while (0)
++
++#endif /* __ASSEMBLY__ */
++
++#endif /* __ASM_SH_CPU_SH5_CACHEFLUSH_H */
++
+diff --git a/include/asm-sh/cpu-sh5/dma.h b/include/asm-sh/cpu-sh5/dma.h
+new file mode 100644
+index 0000000..7bf6bb3
+--- /dev/null
++++ b/include/asm-sh/cpu-sh5/dma.h
+@@ -0,0 +1,6 @@
++#ifndef __ASM_SH_CPU_SH5_DMA_H
++#define __ASM_SH_CPU_SH5_DMA_H
++
++/* Nothing yet */
++
++#endif /* __ASM_SH_CPU_SH5_DMA_H */
+diff --git a/include/asm-sh/cpu-sh5/irq.h b/include/asm-sh/cpu-sh5/irq.h
+new file mode 100644
+index 0000000..f0f0756
+--- /dev/null
++++ b/include/asm-sh/cpu-sh5/irq.h
+@@ -0,0 +1,117 @@
++#ifndef __ASM_SH_CPU_SH5_IRQ_H
++#define __ASM_SH_CPU_SH5_IRQ_H
++
++/*
++ * include/asm-sh/cpu-sh5/irq.h
++ *
++ * Copyright (C) 2000, 2001  Paolo Alberelli
++ *
++ * 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.
++ */
++
++
++/*
++ * Encoded IRQs are not considered worth to be supported.
++ * Main reason is that there's no per-encoded-interrupt
++ * enable/disable mechanism (as there was in SH3/4).
++ * An all enabled/all disabled is worth only if there's
++ * a cascaded IC to disable/enable/ack on. Until such
++ * IC is available there's no such support.
++ *
++ * Presumably Encoded IRQs may use extra IRQs beyond 64,
++ * below. Some logic must be added to cope with IRQ_IRL?
++ * in an exclusive way.
++ *
++ * Priorities are set at Platform level, when IRQ_IRL0-3
++ * are set to 0 Encoding is allowed. Otherwise it's not
++ * allowed.
++ */
++
++/* Independent IRQs */
++#define IRQ_IRL0	0
++#define IRQ_IRL1	1
++#define IRQ_IRL2	2
++#define IRQ_IRL3	3
++
++#define IRQ_INTA	4
++#define IRQ_INTB	5
++#define IRQ_INTC	6
++#define IRQ_INTD	7
++
++#define IRQ_SERR	12
++#define IRQ_ERR		13
++#define IRQ_PWR3	14
++#define IRQ_PWR2	15
++#define IRQ_PWR1	16
++#define IRQ_PWR0	17
++
++#define IRQ_DMTE0	18
++#define IRQ_DMTE1	19
++#define IRQ_DMTE2	20
++#define IRQ_DMTE3	21
++#define IRQ_DAERR	22
++
++#define IRQ_TUNI0	32
++#define IRQ_TUNI1	33
++#define IRQ_TUNI2	34
++#define IRQ_TICPI2	35
++
++#define IRQ_ATI		36
++#define IRQ_PRI		37
++#define IRQ_CUI		38
++
++#define IRQ_ERI		39
++#define IRQ_RXI		40
++#define IRQ_BRI		41
++#define IRQ_TXI		42
++
++#define IRQ_ITI		63
++
++#define NR_INTC_IRQS	64
++
++#ifdef CONFIG_SH_CAYMAN
++#define NR_EXT_IRQS     32
++#define START_EXT_IRQS  64
++
++/* PCI bus 2 uses encoded external interrupts on the Cayman board */
++#define IRQ_P2INTA      (START_EXT_IRQS + (3*8) + 0)
++#define IRQ_P2INTB      (START_EXT_IRQS + (3*8) + 1)
++#define IRQ_P2INTC      (START_EXT_IRQS + (3*8) + 2)
++#define IRQ_P2INTD      (START_EXT_IRQS + (3*8) + 3)
++
++#define I8042_KBD_IRQ	(START_EXT_IRQS + 2)
++#define I8042_AUX_IRQ	(START_EXT_IRQS + 6)
++
++#define IRQ_CFCARD	(START_EXT_IRQS + 7)
++#define IRQ_PCMCIA	(0)
++
++#else
++#define NR_EXT_IRQS	0
++#endif
++
++/* Default IRQs, fixed */
++#define TIMER_IRQ	IRQ_TUNI0
++#define RTC_IRQ		IRQ_CUI
++
++/* Default Priorities, Platform may choose differently */
++#define	NO_PRIORITY	0	/* Disabled */
++#define TIMER_PRIORITY	2
++#define RTC_PRIORITY	TIMER_PRIORITY
++#define SCIF_PRIORITY	3
++#define INTD_PRIORITY	3
++#define	IRL3_PRIORITY	4
++#define INTC_PRIORITY	6
++#define	IRL2_PRIORITY	7
++#define INTB_PRIORITY	9
++#define	IRL1_PRIORITY	10
++#define INTA_PRIORITY	12
++#define	IRL0_PRIORITY	13
++#define TOP_PRIORITY	15
++
++extern int intc_evt_to_irq[(0xE20/0x20)+1];
++int intc_irq_describe(char* p, int irq);
++extern int platform_int_priority[NR_INTC_IRQS];
++
++#endif /* __ASM_SH_CPU_SH5_IRQ_H */
+diff --git a/include/asm-sh/cpu-sh5/mmu_context.h b/include/asm-sh/cpu-sh5/mmu_context.h
+new file mode 100644
+index 0000000..df857fc
+--- /dev/null
++++ b/include/asm-sh/cpu-sh5/mmu_context.h
+@@ -0,0 +1,27 @@
++#ifndef __ASM_SH_CPU_SH5_MMU_CONTEXT_H
++#define __ASM_SH_CPU_SH5_MMU_CONTEXT_H
++
++/* Common defines */
++#define TLB_STEP	0x00000010
++#define TLB_PTEH	0x00000000
++#define TLB_PTEL	0x00000008
++
++/* PTEH defines */
++#define PTEH_ASID_SHIFT	2
++#define PTEH_VALID	0x0000000000000001
++#define PTEH_SHARED	0x0000000000000002
++#define PTEH_MATCH_ASID	0x00000000000003ff
++
++#ifndef __ASSEMBLY__
++/* This has to be a common function because the next location to fill
++ * information is shared. */
++extern void __do_tlb_refill(unsigned long address, unsigned long long is_text_not_data, pte_t *pte);
++
++/* Profiling counter. */
++#ifdef CONFIG_SH64_PROC_TLB
++extern unsigned long long calls_to_do_fast_page_fault;
++#endif
++
++#endif /* __ASSEMBLY__ */
++
++#endif /* __ASM_SH_CPU_SH5_MMU_CONTEXT_H */
+diff --git a/include/asm-sh/cpu-sh5/registers.h b/include/asm-sh/cpu-sh5/registers.h
+new file mode 100644
+index 0000000..6664ea6
+--- /dev/null
++++ b/include/asm-sh/cpu-sh5/registers.h
+@@ -0,0 +1,106 @@
++#ifndef __ASM_SH_CPU_SH5_REGISTERS_H
++#define __ASM_SH_CPU_SH5_REGISTERS_H
++
++/*
++ * include/asm-sh/cpu-sh5/registers.h
++ *
++ * Copyright (C) 2000, 2001  Paolo Alberelli
++ * Copyright (C) 2004  Richard Curnow
++ *
++ * 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.
++ */
++
++#ifdef __ASSEMBLY__
++/* =====================================================================
++**
++** Section 1: acts on assembly sources pre-processed by GPP ( <source.S>).
++**	      Assigns symbolic names to control & target registers.
++*/
++
++/*
++ * Define some useful aliases for control registers.
++ */
++#define SR	cr0
++#define SSR	cr1
++#define PSSR	cr2
++			/* cr3 UNDEFINED */
++#define INTEVT	cr4
++#define EXPEVT	cr5
++#define PEXPEVT	cr6
++#define TRA	cr7
++#define SPC	cr8
++#define PSPC	cr9
++#define RESVEC	cr10
++#define VBR	cr11
++			/* cr12 UNDEFINED */
++#define TEA	cr13
++			/* cr14-cr15 UNDEFINED */
++#define DCR	cr16
++#define KCR0	cr17
++#define KCR1	cr18
++			/* cr19-cr31 UNDEFINED */
++			/* cr32-cr61 RESERVED */
++#define CTC	cr62
++#define USR	cr63
++
++/*
++ * ABI dependent registers (general purpose set)
++ */
++#define RET	r2
++#define ARG1	r2
++#define ARG2	r3
++#define ARG3	r4
++#define ARG4	r5
++#define ARG5	r6
++#define ARG6	r7
++#define SP	r15
++#define LINK	r18
++#define ZERO	r63
++
++/*
++ * Status register defines: used only by assembly sources (and
++ * 			    syntax independednt)
++ */
++#define SR_RESET_VAL	0x0000000050008000
++#define SR_HARMLESS	0x00000000500080f0	/* Write ignores for most */
++#define SR_ENABLE_FPU	0xffffffffffff7fff	/* AND with this */
++
++#if defined (CONFIG_SH64_SR_WATCH)
++#define SR_ENABLE_MMU	0x0000000084000000	/* OR with this */
++#else
++#define SR_ENABLE_MMU	0x0000000080000000	/* OR with this */
++#endif
++
++#define SR_UNBLOCK_EXC	0xffffffffefffffff	/* AND with this */
++#define SR_BLOCK_EXC	0x0000000010000000	/* OR with this */
++
++#else	/* Not __ASSEMBLY__ syntax */
++
++/*
++** Stringify reg. name
++*/
++#define __str(x)  #x
++
++/* Stringify control register names for use in inline assembly */
++#define __SR __str(SR)
++#define __SSR __str(SSR)
++#define __PSSR __str(PSSR)
++#define __INTEVT __str(INTEVT)
++#define __EXPEVT __str(EXPEVT)
++#define __PEXPEVT __str(PEXPEVT)
++#define __TRA __str(TRA)
++#define __SPC __str(SPC)
++#define __PSPC __str(PSPC)
++#define __RESVEC __str(RESVEC)
++#define __VBR __str(VBR)
++#define __TEA __str(TEA)
++#define __DCR __str(DCR)
++#define __KCR0 __str(KCR0)
++#define __KCR1 __str(KCR1)
++#define __CTC __str(CTC)
++#define __USR __str(USR)
++
++#endif /* __ASSEMBLY__ */
++#endif /* __ASM_SH_CPU_SH5_REGISTERS_H */
+diff --git a/include/asm-sh/cpu-sh5/rtc.h b/include/asm-sh/cpu-sh5/rtc.h
+new file mode 100644
+index 0000000..12ea0ed
+--- /dev/null
++++ b/include/asm-sh/cpu-sh5/rtc.h
+@@ -0,0 +1,8 @@
++#ifndef __ASM_SH_CPU_SH5_RTC_H
++#define __ASM_SH_CPU_SH5_RTC_H
++
++#define rtc_reg_size		sizeof(u32)
++#define RTC_BIT_INVERTED	0	/* The SH-5 RTC is surprisingly sane! */
++#define RTC_DEF_CAPABILITIES	RTC_CAP_4_DIGIT_YEAR
++
++#endif /* __ASM_SH_CPU_SH5_RTC_H */
+diff --git a/include/asm-sh/cpu-sh5/timer.h b/include/asm-sh/cpu-sh5/timer.h
+new file mode 100644
+index 0000000..88da9b3
+--- /dev/null
++++ b/include/asm-sh/cpu-sh5/timer.h
+@@ -0,0 +1,4 @@
++#ifndef __ASM_SH_CPU_SH5_TIMER_H
++#define __ASM_SH_CPU_SH5_TIMER_H
++
++#endif /* __ASM_SH_CPU_SH5_TIMER_H */
+diff --git a/include/asm-sh/delay.h b/include/asm-sh/delay.h
+index db599b2..031db84 100644
+--- a/include/asm-sh/delay.h
++++ b/include/asm-sh/delay.h
+@@ -6,7 +6,7 @@
+  *
+  * Delay routines calling functions in arch/sh/lib/delay.c
+  */
+- 
++
+ extern void __bad_udelay(void);
+ extern void __bad_ndelay(void);
  
- 	status = 0;
-@@ -414,7 +417,7 @@ static int ocfs2_read_locked_inode(struct inode *inode,
- 	if (args->fi_flags & OCFS2_FI_FLAG_SYSFILE)
- 		generation = osb->fs_generation;
+@@ -15,13 +15,17 @@ extern void __ndelay(unsigned long nsecs);
+ extern void __const_udelay(unsigned long usecs);
+ extern void __delay(unsigned long loops);
+ 
++#ifdef CONFIG_SUPERH32
+ #define udelay(n) (__builtin_constant_p(n) ? \
+ 	((n) > 20000 ? __bad_udelay() : __const_udelay((n) * 0x10c6ul)) : \
+ 	__udelay(n))
+ 
+-
+ #define ndelay(n) (__builtin_constant_p(n) ? \
+ 	((n) > 20000 ? __bad_ndelay() : __const_udelay((n) * 5ul)) : \
+ 	__ndelay(n))
++#else
++extern void udelay(unsigned long usecs);
++extern void ndelay(unsigned long nsecs);
++#endif
  
--	ocfs2_inode_lock_res_init(&OCFS2_I(inode)->ip_meta_lockres,
-+	ocfs2_inode_lock_res_init(&OCFS2_I(inode)->ip_inode_lockres,
- 				  OCFS2_LOCK_TYPE_META,
- 				  generation, inode);
+ #endif /* __ASM_SH_DELAY_H */
+diff --git a/include/asm-sh/dma-mapping.h b/include/asm-sh/dma-mapping.h
+index fcea067..22cc419 100644
+--- a/include/asm-sh/dma-mapping.h
++++ b/include/asm-sh/dma-mapping.h
+@@ -8,11 +8,6 @@
  
-@@ -429,7 +432,7 @@ static int ocfs2_read_locked_inode(struct inode *inode,
- 			mlog_errno(status);
- 			return status;
- 		}
--		status = ocfs2_meta_lock(inode, NULL, 0);
-+		status = ocfs2_inode_lock(inode, NULL, 0);
- 		if (status) {
- 			make_bad_inode(inode);
- 			mlog_errno(status);
-@@ -484,7 +487,7 @@ static int ocfs2_read_locked_inode(struct inode *inode,
+ extern struct bus_type pci_bus_type;
  
- bail:
- 	if (can_lock)
--		ocfs2_meta_unlock(inode, 0);
-+		ocfs2_inode_unlock(inode, 0);
+-/* arch/sh/mm/consistent.c */
+-extern void *consistent_alloc(gfp_t gfp, size_t size, dma_addr_t *handle);
+-extern void consistent_free(void *vaddr, size_t size);
+-extern void consistent_sync(void *vaddr, size_t size, int direction);
+-
+ #define dma_supported(dev, mask)	(1)
  
- 	if (status < 0)
- 		make_bad_inode(inode);
-@@ -586,7 +589,7 @@ static int ocfs2_remove_inode(struct inode *inode,
- 	}
+ static inline int dma_set_mask(struct device *dev, u64 mask)
+@@ -25,44 +20,19 @@ static inline int dma_set_mask(struct device *dev, u64 mask)
+ 	return 0;
+ }
  
- 	mutex_lock(&inode_alloc_inode->i_mutex);
--	status = ocfs2_meta_lock(inode_alloc_inode, &inode_alloc_bh, 1);
-+	status = ocfs2_inode_lock(inode_alloc_inode, &inode_alloc_bh, 1);
- 	if (status < 0) {
- 		mutex_unlock(&inode_alloc_inode->i_mutex);
+-static inline void *dma_alloc_coherent(struct device *dev, size_t size,
+-			 dma_addr_t *dma_handle, gfp_t flag)
+-{
+-	if (sh_mv.mv_consistent_alloc) {
+-		void *ret;
++void *dma_alloc_coherent(struct device *dev, size_t size,
++			 dma_addr_t *dma_handle, gfp_t flag);
  
-@@ -617,7 +620,7 @@ static int ocfs2_remove_inode(struct inode *inode,
- 	}
+-		ret = sh_mv.mv_consistent_alloc(dev, size, dma_handle, flag);
+-		if (ret != NULL)
+-			return ret;
+-	}
+-
+-	return consistent_alloc(flag, size, dma_handle);
+-}
+-
+-static inline void dma_free_coherent(struct device *dev, size_t size,
+-		       void *vaddr, dma_addr_t dma_handle)
+-{
+-	if (sh_mv.mv_consistent_free) {
+-		int ret;
+-
+-		ret = sh_mv.mv_consistent_free(dev, size, vaddr, dma_handle);
+-		if (ret == 0)
+-			return;
+-	}
++void dma_free_coherent(struct device *dev, size_t size,
++		       void *vaddr, dma_addr_t dma_handle);
  
- 	di->i_dtime = cpu_to_le64(CURRENT_TIME.tv_sec);
--	le32_and_cpu(&di->i_flags, ~(OCFS2_VALID_FL | OCFS2_ORPHANED_FL));
-+	di->i_flags &= cpu_to_le32(~(OCFS2_VALID_FL | OCFS2_ORPHANED_FL));
+-	consistent_free(vaddr, size);
+-}
++void dma_cache_sync(struct device *dev, void *vaddr, size_t size,
++		    enum dma_data_direction dir);
  
- 	status = ocfs2_journal_dirty(handle, di_bh);
- 	if (status < 0) {
-@@ -635,7 +638,7 @@ static int ocfs2_remove_inode(struct inode *inode,
- bail_commit:
- 	ocfs2_commit_trans(osb, handle);
- bail_unlock:
--	ocfs2_meta_unlock(inode_alloc_inode, 1);
-+	ocfs2_inode_unlock(inode_alloc_inode, 1);
- 	mutex_unlock(&inode_alloc_inode->i_mutex);
- 	brelse(inode_alloc_bh);
- bail:
-@@ -709,7 +712,7 @@ static int ocfs2_wipe_inode(struct inode *inode,
- 	 * delete_inode operation. We do this now to avoid races with
- 	 * recovery completion on other nodes. */
- 	mutex_lock(&orphan_dir_inode->i_mutex);
--	status = ocfs2_meta_lock(orphan_dir_inode, &orphan_dir_bh, 1);
-+	status = ocfs2_inode_lock(orphan_dir_inode, &orphan_dir_bh, 1);
- 	if (status < 0) {
- 		mutex_unlock(&orphan_dir_inode->i_mutex);
+ #define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f)
+ #define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h)
+ #define dma_is_consistent(d, h) (1)
  
-@@ -718,8 +721,8 @@ static int ocfs2_wipe_inode(struct inode *inode,
- 	}
+-static inline void dma_cache_sync(struct device *dev, void *vaddr, size_t size,
+-				  enum dma_data_direction dir)
+-{
+-	consistent_sync(vaddr, size, (int)dir);
+-}
+-
+ static inline dma_addr_t dma_map_single(struct device *dev,
+ 					void *ptr, size_t size,
+ 					enum dma_data_direction dir)
+@@ -205,4 +175,18 @@ static inline int dma_mapping_error(dma_addr_t dma_addr)
+ {
+ 	return dma_addr == 0;
+ }
++
++#define ARCH_HAS_DMA_DECLARE_COHERENT_MEMORY
++
++extern int
++dma_declare_coherent_memory(struct device *dev, dma_addr_t bus_addr,
++			    dma_addr_t device_addr, size_t size, int flags);
++
++extern void
++dma_release_declared_memory(struct device *dev);
++
++extern void *
++dma_mark_declared_memory_occupied(struct device *dev,
++				  dma_addr_t device_addr, size_t size);
++
+ #endif /* __ASM_SH_DMA_MAPPING_H */
+diff --git a/include/asm-sh/elf.h b/include/asm-sh/elf.h
+index 12cc4b3..05092da 100644
+--- a/include/asm-sh/elf.h
++++ b/include/asm-sh/elf.h
+@@ -5,7 +5,7 @@
+ #include <asm/ptrace.h>
+ #include <asm/user.h>
  
- 	/* we do this while holding the orphan dir lock because we
--	 * don't want recovery being run from another node to vote for
--	 * an inode delete on us -- this will result in two nodes
-+	 * don't want recovery being run from another node to try an
-+	 * inode delete underneath us -- this will result in two nodes
- 	 * truncating the same file! */
- 	status = ocfs2_truncate_for_delete(osb, inode, di_bh);
- 	if (status < 0) {
-@@ -733,7 +736,7 @@ static int ocfs2_wipe_inode(struct inode *inode,
- 		mlog_errno(status);
+-/* SH relocation types  */
++/* SH (particularly SHcompact) relocation types  */
+ #define	R_SH_NONE		0
+ #define	R_SH_DIR32		1
+ #define	R_SH_REL32		2
+@@ -43,6 +43,11 @@
+ #define	R_SH_RELATIVE		165
+ #define	R_SH_GOTOFF		166
+ #define	R_SH_GOTPC		167
++/* SHmedia relocs */
++#define R_SH_IMM_LOW16		246
++#define R_SH_IMM_LOW16_PCREL	247
++#define R_SH_IMM_MEDLOW16	248
++#define R_SH_IMM_MEDLOW16_PCREL	249
+ /* Keep this the last entry.  */
+ #define	R_SH_NUM		256
  
- bail_unlock_dir:
--	ocfs2_meta_unlock(orphan_dir_inode, 1);
-+	ocfs2_inode_unlock(orphan_dir_inode, 1);
- 	mutex_unlock(&orphan_dir_inode->i_mutex);
- 	brelse(orphan_dir_bh);
- bail:
-@@ -744,7 +747,7 @@ bail:
- }
+@@ -58,11 +63,6 @@ typedef elf_greg_t elf_gregset_t[ELF_NGREG];
+ typedef struct user_fpu_struct elf_fpregset_t;
  
- /* There is a series of simple checks that should be done before a
-- * vote is even considered. Encapsulate those in this function. */
-+ * trylock is even considered. Encapsulate those in this function. */
- static int ocfs2_inode_is_valid_to_delete(struct inode *inode)
- {
- 	int ret = 0;
-@@ -758,14 +761,14 @@ static int ocfs2_inode_is_valid_to_delete(struct inode *inode)
- 		goto bail;
- 	}
+ /*
+- * This is used to ensure we don't load something for the wrong architecture.
+- */
+-#define elf_check_arch(x) ( (x)->e_machine == EM_SH )
+-
+-/*
+  * These are used to set parameters in the core dumps.
+  */
+ #define ELF_CLASS	ELFCLASS32
+@@ -73,6 +73,12 @@ typedef struct user_fpu_struct elf_fpregset_t;
+ #endif
+ #define ELF_ARCH	EM_SH
  
--	/* If we're coming from process_vote we can't go into our own
-+	/* If we're coming from downconvert_thread we can't go into our own
- 	 * voting [hello, deadlock city!], so unforuntately we just
- 	 * have to skip deleting this guy. That's OK though because
- 	 * the node who's doing the actual deleting should handle it
- 	 * anyway. */
--	if (current == osb->vote_task) {
-+	if (current == osb->dc_task) {
- 		mlog(0, "Skipping delete of %lu because we're currently "
--		     "in process_vote\n", inode->i_ino);
-+		     "in downconvert\n", inode->i_ino);
- 		goto bail;
- 	}
++#ifdef __KERNEL__
++/*
++ * This is used to ensure we don't load something for the wrong architecture.
++ */
++#define elf_check_arch(x) ( (x)->e_machine == EM_SH )
++
+ #define USE_ELF_CORE_DUMP
+ #define ELF_EXEC_PAGESIZE	PAGE_SIZE
  
-@@ -779,10 +782,9 @@ static int ocfs2_inode_is_valid_to_delete(struct inode *inode)
- 		goto bail_unlock;
- 	}
+@@ -83,7 +89,6 @@ typedef struct user_fpu_struct elf_fpregset_t;
  
--	/* If we have voted "yes" on the wipe of this inode for
--	 * another node, it will be marked here so we can safely skip
--	 * it. Recovery will cleanup any inodes we might inadvertantly
--	 * skip here. */
-+	/* If we have allowd wipe of this inode for another node, it
-+	 * will be marked here so we can safely skip it. Recovery will
-+	 * cleanup any inodes we might inadvertantly skip here. */
- 	if (oi->ip_flags & OCFS2_INODE_SKIP_DELETE) {
- 		mlog(0, "Skipping delete of %lu because another node "
- 		     "has done this for us.\n", inode->i_ino);
-@@ -929,13 +931,13 @@ void ocfs2_delete_inode(struct inode *inode)
+ #define ELF_ET_DYN_BASE         (2 * TASK_SIZE / 3)
+ 
+-
+ #define ELF_CORE_COPY_REGS(_dest,_regs)				\
+ 	memcpy((char *) &_dest, (char *) _regs,			\
+ 	       sizeof(struct pt_regs));
+@@ -101,16 +106,38 @@ typedef struct user_fpu_struct elf_fpregset_t;
+    For the moment, we have only optimizations for the Intel generations,
+    but that could change... */
+ 
+-#define ELF_PLATFORM  (NULL)
++#define ELF_PLATFORM	(utsname()->machine)
+ 
++#ifdef __SH5__
++#define ELF_PLAT_INIT(_r, load_addr) \
++  do { _r->regs[0]=0; _r->regs[1]=0; _r->regs[2]=0; _r->regs[3]=0; \
++       _r->regs[4]=0; _r->regs[5]=0; _r->regs[6]=0; _r->regs[7]=0; \
++       _r->regs[8]=0; _r->regs[9]=0; _r->regs[10]=0; _r->regs[11]=0; \
++       _r->regs[12]=0; _r->regs[13]=0; _r->regs[14]=0; _r->regs[15]=0; \
++       _r->regs[16]=0; _r->regs[17]=0; _r->regs[18]=0; _r->regs[19]=0; \
++       _r->regs[20]=0; _r->regs[21]=0; _r->regs[22]=0; _r->regs[23]=0; \
++       _r->regs[24]=0; _r->regs[25]=0; _r->regs[26]=0; _r->regs[27]=0; \
++       _r->regs[28]=0; _r->regs[29]=0; _r->regs[30]=0; _r->regs[31]=0; \
++       _r->regs[32]=0; _r->regs[33]=0; _r->regs[34]=0; _r->regs[35]=0; \
++       _r->regs[36]=0; _r->regs[37]=0; _r->regs[38]=0; _r->regs[39]=0; \
++       _r->regs[40]=0; _r->regs[41]=0; _r->regs[42]=0; _r->regs[43]=0; \
++       _r->regs[44]=0; _r->regs[45]=0; _r->regs[46]=0; _r->regs[47]=0; \
++       _r->regs[48]=0; _r->regs[49]=0; _r->regs[50]=0; _r->regs[51]=0; \
++       _r->regs[52]=0; _r->regs[53]=0; _r->regs[54]=0; _r->regs[55]=0; \
++       _r->regs[56]=0; _r->regs[57]=0; _r->regs[58]=0; _r->regs[59]=0; \
++       _r->regs[60]=0; _r->regs[61]=0; _r->regs[62]=0; \
++       _r->tregs[0]=0; _r->tregs[1]=0; _r->tregs[2]=0; _r->tregs[3]=0; \
++       _r->tregs[4]=0; _r->tregs[5]=0; _r->tregs[6]=0; _r->tregs[7]=0; \
++       _r->sr = SR_FD | SR_MMU; } while (0)
++#else
+ #define ELF_PLAT_INIT(_r, load_addr) \
+   do { _r->regs[0]=0; _r->regs[1]=0; _r->regs[2]=0; _r->regs[3]=0; \
+        _r->regs[4]=0; _r->regs[5]=0; _r->regs[6]=0; _r->regs[7]=0; \
+        _r->regs[8]=0; _r->regs[9]=0; _r->regs[10]=0; _r->regs[11]=0; \
+        _r->regs[12]=0; _r->regs[13]=0; _r->regs[14]=0; \
+        _r->sr = SR_FD; } while (0)
++#endif
  
- 	/* Lock down the inode. This gives us an up to date view of
- 	 * it's metadata (for verification), and allows us to
--	 * serialize delete_inode votes. 
-+	 * serialize delete_inode on multiple nodes.
- 	 *
- 	 * Even though we might be doing a truncate, we don't take the
- 	 * allocation lock here as it won't be needed - nobody will
- 	 * have the file open.
- 	 */
--	status = ocfs2_meta_lock(inode, &di_bh, 1);
-+	status = ocfs2_inode_lock(inode, &di_bh, 1);
- 	if (status < 0) {
- 		if (status != -ENOENT)
- 			mlog_errno(status);
-@@ -947,15 +949,15 @@ void ocfs2_delete_inode(struct inode *inode)
- 	 * before we go ahead and wipe the inode. */
- 	status = ocfs2_query_inode_wipe(inode, di_bh, &wipe);
- 	if (!wipe || status < 0) {
--		/* Error and inode busy vote both mean we won't be
-+		/* Error and remote inode busy both mean we won't be
- 		 * removing the inode, so they take almost the same
- 		 * path. */
- 		if (status < 0)
- 			mlog_errno(status);
+-#ifdef __KERNEL__
+ #define SET_PERSONALITY(ex, ibcs2) set_personality(PER_LINUX_32BIT)
+ struct task_struct;
+ extern int dump_task_regs (struct task_struct *, elf_gregset_t *);
+@@ -118,7 +145,6 @@ extern int dump_task_fpu (struct task_struct *, elf_fpregset_t *);
  
--		/* Someone in the cluster has voted to not wipe this
--		 * inode, or it was never completely orphaned. Write
--		 * out the pages and exit now. */
-+		/* Someone in the cluster has disallowed a wipe of
-+		 * this inode, or it was never completely
-+		 * orphaned. Write out the pages and exit now. */
- 		ocfs2_cleanup_delete_inode(inode, 1);
- 		goto bail_unlock_inode;
- 	}
-@@ -981,7 +983,7 @@ void ocfs2_delete_inode(struct inode *inode)
- 	OCFS2_I(inode)->ip_flags |= OCFS2_INODE_DELETED;
+ #define ELF_CORE_COPY_TASK_REGS(tsk, elf_regs) dump_task_regs(tsk, elf_regs)
+ #define ELF_CORE_COPY_FPREGS(tsk, elf_fpregs) dump_task_fpu(tsk, elf_fpregs)
+-#endif
  
- bail_unlock_inode:
--	ocfs2_meta_unlock(inode, 1);
-+	ocfs2_inode_unlock(inode, 1);
- 	brelse(di_bh);
- bail_unblock:
- 	status = sigprocmask(SIG_SETMASK, &oldset, NULL);
-@@ -1008,15 +1010,14 @@ void ocfs2_clear_inode(struct inode *inode)
- 	mlog_bug_on_msg(OCFS2_SB(inode->i_sb) == NULL,
- 			"Inode=%lu\n", inode->i_ino);
+ #ifdef CONFIG_VSYSCALL
+ /* vDSO has arch_setup_additional_pages */
+@@ -133,12 +159,35 @@ extern void __kernel_vsyscall;
+ #define VDSO_BASE		((unsigned long)current->mm->context.vdso)
+ #define VDSO_SYM(x)		(VDSO_BASE + (unsigned long)(x))
+ 
++#define VSYSCALL_AUX_ENT					\
++	if (vdso_enabled)					\
++		NEW_AUX_ENT(AT_SYSINFO_EHDR, VDSO_BASE);
++#else
++#define VSYSCALL_AUX_ENT
++#endif /* CONFIG_VSYSCALL */
++
++#ifdef CONFIG_SH_FPU
++#define FPU_AUX_ENT	NEW_AUX_ENT(AT_FPUCW, FPSCR_INIT)
++#else
++#define FPU_AUX_ENT
++#endif
++
++extern int l1i_cache_shape, l1d_cache_shape, l2_cache_shape;
++
+ /* update AT_VECTOR_SIZE_ARCH if the number of NEW_AUX_ENT entries changes */
+ #define ARCH_DLINFO						\
+ do {								\
+-	if (vdso_enabled)					\
+-		NEW_AUX_ENT(AT_SYSINFO_EHDR, VDSO_BASE);	\
++	/* Optional FPU initialization */			\
++	FPU_AUX_ENT;						\
++								\
++	/* Optional vsyscall entry */				\
++	VSYSCALL_AUX_ENT;					\
++								\
++	/* Cache desc */					\
++	NEW_AUX_ENT(AT_L1I_CACHESHAPE, l1i_cache_shape);	\
++	NEW_AUX_ENT(AT_L1D_CACHESHAPE, l1d_cache_shape);	\
++	NEW_AUX_ENT(AT_L2_CACHESHAPE, l2_cache_shape);		\
+ } while (0)
+-#endif /* CONFIG_VSYSCALL */
  
--	/* For remove delete_inode vote, we hold open lock before,
--	 * now it is time to unlock PR and EX open locks. */
-+	/* To preven remote deletes we hold open lock before, now it
-+	 * is time to unlock PR and EX open locks. */
- 	ocfs2_open_unlock(inode);
++#endif /* __KERNEL__ */
+ #endif /* __ASM_SH_ELF_H */
+diff --git a/include/asm-sh/fixmap.h b/include/asm-sh/fixmap.h
+index 8a56617..721fcc4 100644
+--- a/include/asm-sh/fixmap.h
++++ b/include/asm-sh/fixmap.h
+@@ -49,6 +49,7 @@ enum fixed_addresses {
+ #define FIX_N_COLOURS 16
+ 	FIX_CMAP_BEGIN,
+ 	FIX_CMAP_END = FIX_CMAP_BEGIN + FIX_N_COLOURS,
++	FIX_UNCACHED,
+ #ifdef CONFIG_HIGHMEM
+ 	FIX_KMAP_BEGIN,	/* reserved pte's for temporary kernel mappings */
+ 	FIX_KMAP_END = FIX_KMAP_BEGIN+(KM_TYPE_NR*NR_CPUS)-1,
+@@ -73,7 +74,11 @@ extern void __set_fixmap(enum fixed_addresses idx,
+  * the start of the fixmap, and leave one page empty
+  * at the top of mem..
+  */
++#ifdef CONFIG_SUPERH32
+ #define FIXADDR_TOP	(P4SEG - PAGE_SIZE)
++#else
++#define FIXADDR_TOP	(0xff000000 - PAGE_SIZE)
++#endif
+ #define FIXADDR_SIZE	(__end_of_fixed_addresses << PAGE_SHIFT)
+ #define FIXADDR_START	(FIXADDR_TOP - FIXADDR_SIZE)
  
- 	/* Do these before all the other work so that we don't bounce
--	 * the vote thread while waiting to destroy the locks. */
-+	 * the downconvert thread while waiting to destroy the locks. */
- 	ocfs2_mark_lockres_freeing(&oi->ip_rw_lockres);
--	ocfs2_mark_lockres_freeing(&oi->ip_meta_lockres);
--	ocfs2_mark_lockres_freeing(&oi->ip_data_lockres);
-+	ocfs2_mark_lockres_freeing(&oi->ip_inode_lockres);
- 	ocfs2_mark_lockres_freeing(&oi->ip_open_lockres);
+diff --git a/include/asm-sh/flat.h b/include/asm-sh/flat.h
+index dc4f595..0cc8002 100644
+--- a/include/asm-sh/flat.h
++++ b/include/asm-sh/flat.h
+@@ -19,6 +19,6 @@
+ #define	flat_get_addr_from_rp(rp, relval, flags, p)	get_unaligned(rp)
+ #define	flat_put_addr_at_rp(rp, val, relval)	put_unaligned(val,rp)
+ #define	flat_get_relocate_addr(rel)		(rel)
+-#define	flat_set_persistent(relval, p)		0
++#define	flat_set_persistent(relval, p)		({ (void)p; 0; })
  
- 	/* We very well may get a clear_inode before all an inodes
-@@ -1039,8 +1040,7 @@ void ocfs2_clear_inode(struct inode *inode)
- 		mlog_errno(status);
+ #endif /* __ASM_SH_FLAT_H */
+diff --git a/include/asm-sh/fpu.h b/include/asm-sh/fpu.h
+new file mode 100644
+index 0000000..f842988
+--- /dev/null
++++ b/include/asm-sh/fpu.h
+@@ -0,0 +1,46 @@
++#ifndef __ASM_SH_FPU_H
++#define __ASM_SH_FPU_H
++
++#define SR_FD    0x00008000
++
++#ifndef __ASSEMBLY__
++#include <asm/ptrace.h>
++
++#ifdef CONFIG_SH_FPU
++static inline void release_fpu(struct pt_regs *regs)
++{
++	regs->sr |= SR_FD;
++}
++
++static inline void grab_fpu(struct pt_regs *regs)
++{
++	regs->sr &= ~SR_FD;
++}
++
++struct task_struct;
++
++extern void save_fpu(struct task_struct *__tsk, struct pt_regs *regs);
++#else
++#define release_fpu(regs)	do { } while (0)
++#define grab_fpu(regs)		do { } while (0)
++#define save_fpu(tsk, regs)	do { } while (0)
++#endif
++
++extern int do_fpu_inst(unsigned short, struct pt_regs *);
++
++#define unlazy_fpu(tsk, regs) do {			\
++	if (test_tsk_thread_flag(tsk, TIF_USEDFPU)) {	\
++		save_fpu(tsk, regs);			\
++	}						\
++} while (0)
++
++#define clear_fpu(tsk, regs) do {				\
++	if (test_tsk_thread_flag(tsk, TIF_USEDFPU)) {		\
++		clear_tsk_thread_flag(tsk, TIF_USEDFPU);	\
++		release_fpu(regs);				\
++	}							\
++} while (0)
++
++#endif /* __ASSEMBLY__ */
++
++#endif /* __ASM_SH_FPU_H */
+diff --git a/include/asm-sh/hd64461.h b/include/asm-sh/hd64461.h
+index 342ca55..8c1353b 100644
+--- a/include/asm-sh/hd64461.h
++++ b/include/asm-sh/hd64461.h
+@@ -46,10 +46,10 @@
+ /* CPU Data Bus Control Register */
+ #define	HD64461_SCPUCR		(CONFIG_HD64461_IOBASE + 0x04)
+ 
+-/* Base Adress Register */
++/* Base Address Register */
+ #define	HD64461_LCDCBAR		(CONFIG_HD64461_IOBASE + 0x1000)
+ 
+-/* Line increment adress */
++/* Line increment address */
+ #define	HD64461_LCDCLOR		(CONFIG_HD64461_IOBASE + 0x1002)
+ 
+ /* Controls LCD controller */
+@@ -80,9 +80,9 @@
+ #define	HD64461_LDR3		(CONFIG_HD64461_IOBASE + 0x101e)
+ 
+ /* Palette Registers */
+-#define	HD64461_CPTWAR		(CONFIG_HD64461_IOBASE + 0x1030)	/* Color Palette Write Adress Register */
++#define	HD64461_CPTWAR		(CONFIG_HD64461_IOBASE + 0x1030)	/* Color Palette Write Address Register */
+ #define	HD64461_CPTWDR		(CONFIG_HD64461_IOBASE + 0x1032)	/* Color Palette Write Data Register */
+-#define	HD64461_CPTRAR		(CONFIG_HD64461_IOBASE + 0x1034)	/* Color Palette Read Adress Register */
++#define	HD64461_CPTRAR		(CONFIG_HD64461_IOBASE + 0x1034)	/* Color Palette Read Address Register */
+ #define	HD64461_CPTRDR		(CONFIG_HD64461_IOBASE + 0x1036)	/* Color Palette Read Data Register */
+ 
+ #define	HD64461_GRDOR		(CONFIG_HD64461_IOBASE + 0x1040)	/* Display Resolution Offset Register */
+@@ -97,8 +97,8 @@
+ #define	HD64461_GRCFGR_COLORDEPTH8	0x01	/* Sets Colordepth 8 for Accelerator */
+ 
+ /* Line Drawing Registers */
+-#define	HD64461_LNSARH		(CONFIG_HD64461_IOBASE + 0x1046)	/* Line Start Adress Register (H) */
+-#define	HD64461_LNSARL		(CONFIG_HD64461_IOBASE + 0x1048)	/* Line Start Adress Register (L) */
++#define	HD64461_LNSARH		(CONFIG_HD64461_IOBASE + 0x1046)	/* Line Start Address Register (H) */
++#define	HD64461_LNSARL		(CONFIG_HD64461_IOBASE + 0x1048)	/* Line Start Address Register (L) */
+ #define	HD64461_LNAXLR		(CONFIG_HD64461_IOBASE + 0x104a)	/* Axis Pixel Length Register */
+ #define	HD64461_LNDGR		(CONFIG_HD64461_IOBASE + 0x104c)	/* Diagonal Register */
+ #define	HD64461_LNAXR		(CONFIG_HD64461_IOBASE + 0x104e)	/* Axial Register */
+@@ -106,16 +106,16 @@
+ #define	HD64461_LNMDR		(CONFIG_HD64461_IOBASE + 0x1052)	/* Line Mode Register */
+ 
+ /* BitBLT Registers */
+-#define	HD64461_BBTSSARH	(CONFIG_HD64461_IOBASE + 0x1054)	/* Source Start Adress Register (H) */
+-#define	HD64461_BBTSSARL	(CONFIG_HD64461_IOBASE + 0x1056)	/* Source Start Adress Register (L) */
+-#define	HD64461_BBTDSARH	(CONFIG_HD64461_IOBASE + 0x1058)	/* Destination Start Adress Register (H) */
+-#define	HD64461_BBTDSARL	(CONFIG_HD64461_IOBASE + 0x105a)	/* Destination Start Adress Register (L) */
++#define	HD64461_BBTSSARH	(CONFIG_HD64461_IOBASE + 0x1054)	/* Source Start Address Register (H) */
++#define	HD64461_BBTSSARL	(CONFIG_HD64461_IOBASE + 0x1056)	/* Source Start Address Register (L) */
++#define	HD64461_BBTDSARH	(CONFIG_HD64461_IOBASE + 0x1058)	/* Destination Start Address Register (H) */
++#define	HD64461_BBTDSARL	(CONFIG_HD64461_IOBASE + 0x105a)	/* Destination Start Address Register (L) */
+ #define	HD64461_BBTDWR		(CONFIG_HD64461_IOBASE + 0x105c)	/* Destination Block Width Register */
+ #define	HD64461_BBTDHR		(CONFIG_HD64461_IOBASE + 0x105e)	/* Destination Block Height Register */
+-#define	HD64461_BBTPARH		(CONFIG_HD64461_IOBASE + 0x1060)	/* Pattern Start Adress Register (H) */
+-#define	HD64461_BBTPARL		(CONFIG_HD64461_IOBASE + 0x1062)	/* Pattern Start Adress Register (L) */
+-#define	HD64461_BBTMARH		(CONFIG_HD64461_IOBASE + 0x1064)	/* Mask Start Adress Register (H) */
+-#define	HD64461_BBTMARL		(CONFIG_HD64461_IOBASE + 0x1066)	/* Mask Start Adress Register (L) */
++#define	HD64461_BBTPARH		(CONFIG_HD64461_IOBASE + 0x1060)	/* Pattern Start Address Register (H) */
++#define	HD64461_BBTPARL		(CONFIG_HD64461_IOBASE + 0x1062)	/* Pattern Start Address Register (L) */
++#define	HD64461_BBTMARH		(CONFIG_HD64461_IOBASE + 0x1064)	/* Mask Start Address Register (H) */
++#define	HD64461_BBTMARL		(CONFIG_HD64461_IOBASE + 0x1066)	/* Mask Start Address Register (L) */
+ #define	HD64461_BBTROPR		(CONFIG_HD64461_IOBASE + 0x1068)	/* ROP Register */
+ #define	HD64461_BBTMDR		(CONFIG_HD64461_IOBASE + 0x106a)	/* BitBLT Mode Register */
  
- 	ocfs2_lock_res_free(&oi->ip_rw_lockres);
--	ocfs2_lock_res_free(&oi->ip_meta_lockres);
--	ocfs2_lock_res_free(&oi->ip_data_lockres);
-+	ocfs2_lock_res_free(&oi->ip_inode_lockres);
- 	ocfs2_lock_res_free(&oi->ip_open_lockres);
+diff --git a/include/asm-sh/hs7751rvoip.h b/include/asm-sh/hs7751rvoip.h
+deleted file mode 100644
+index c4cff9d..0000000
+--- a/include/asm-sh/hs7751rvoip.h
++++ /dev/null
+@@ -1,54 +0,0 @@
+-#ifndef __ASM_SH_RENESAS_HS7751RVOIP_H
+-#define __ASM_SH_RENESAS_HS7751RVOIP_H
+-
+-/*
+- * linux/include/asm-sh/hs7751rvoip/hs7751rvoip.h
+- *
+- * Copyright (C) 2000  Atom Create Engineering Co., Ltd.
+- *
+- * Renesas Technology Sales HS7751RVoIP support
+- */
+-
+-/* Box specific addresses.  */
+-
+-#define PA_BCR		0xa4000000	/* FPGA */
+-#define PA_SLICCNTR1	0xa4000006	/* SLIC PIO Control 1 */
+-#define PA_SLICCNTR2	0xa4000008	/* SLIC PIO Control 2 */
+-#define PA_DMACNTR	0xa400000a	/* USB DMA Control */
+-#define PA_INPORTR	0xa400000c	/* Input Port Register */
+-#define PA_OUTPORTR	0xa400000e	/* Output Port Reguster */
+-#define PA_VERREG	0xa4000014	/* FPGA Version Register */
+-
+-#define PA_IDE_OFFSET	0x1f0		/* CF IDE Offset */
+-
+-#define IRLCNTR1	(PA_BCR + 0)	/* Interrupt Control Register1 */
+-#define IRLCNTR2	(PA_BCR + 2)	/* Interrupt Control Register2 */
+-#define IRLCNTR3	(PA_BCR + 4)	/* Interrupt Control Register3 */
+-#define IRLCNTR4	(PA_BCR + 16)	/* Interrupt Control Register4 */
+-#define IRLCNTR5	(PA_BCR + 18)	/* Interrupt Control Register5 */
+-
+-#define IRQ_PCIETH	6		/* PCI Ethernet IRQ */
+-#define IRQ_PCIHUB	7		/* PCI Ethernet Hub IRQ */
+-#define IRQ_USBCOM	8		/* USB Comunication IRQ */
+-#define IRQ_USBCON	9		/* USB Connect IRQ */
+-#define IRQ_USBDMA	10		/* USB DMA IRQ */
+-#define IRQ_CFCARD	11		/* CF Card IRQ */
+-#define IRQ_PCMCIA	12		/* PCMCIA IRQ */
+-#define IRQ_PCISLOT	13		/* PCI Slot #1 IRQ */
+-#define IRQ_ONHOOK1	0		/* ON HOOK1 IRQ */
+-#define IRQ_OFFHOOK1	1		/* OFF HOOK1 IRQ */
+-#define IRQ_ONHOOK2	2		/* ON HOOK2 IRQ */
+-#define IRQ_OFFHOOK2	3		/* OFF HOOK2 IRQ */
+-#define	IRQ_RINGING	4		/* Ringing IRQ */
+-#define	IRQ_CODEC	5		/* CODEC IRQ */
+-
+-#define __IO_PREFIX	hs7751rvoip
+-#include <asm/io_generic.h>
+-
+-/* arch/sh/boards/renesas/hs7751rvoip/irq.c */
+-void init_hs7751rvoip_IRQ(void);
+-
+-/* arch/sh/boards/renesas/hs7751rvoip/io.c */
+-void *hs7751rvoip_ioremap(unsigned long, unsigned long);
+-
+-#endif  /* __ASM_SH_RENESAS_HS7751RVOIP */
+diff --git a/include/asm-sh/hw_irq.h b/include/asm-sh/hw_irq.h
+index cb0b6c9..c958fda 100644
+--- a/include/asm-sh/hw_irq.h
++++ b/include/asm-sh/hw_irq.h
+@@ -33,13 +33,6 @@ struct intc_vect {
+ #define INTC_VECT(enum_id, vect) { enum_id, vect }
+ #define INTC_IRQ(enum_id, irq) INTC_VECT(enum_id, irq2evt(irq))
+ 
+-struct intc_prio {
+-	intc_enum enum_id;
+-	unsigned char priority;
+-};
+-
+-#define INTC_PRIO(enum_id, prio) { enum_id, prio }
+-
+ struct intc_group {
+ 	intc_enum enum_id;
+ 	intc_enum enum_ids[32];
+@@ -79,8 +72,6 @@ struct intc_desc {
+ 	unsigned int nr_vectors;
+ 	struct intc_group *groups;
+ 	unsigned int nr_groups;
+-	struct intc_prio *priorities;
+-	unsigned int nr_priorities;
+ 	struct intc_mask_reg *mask_regs;
+ 	unsigned int nr_mask_regs;
+ 	struct intc_prio_reg *prio_regs;
+@@ -92,10 +83,9 @@ struct intc_desc {
  
- 	ocfs2_metadata_cache_purge(inode);
-@@ -1184,15 +1184,15 @@ int ocfs2_inode_revalidate(struct dentry *dentry)
- 	}
- 	spin_unlock(&OCFS2_I(inode)->ip_lock);
+ #define _INTC_ARRAY(a) a, sizeof(a)/sizeof(*a)
+ #define DECLARE_INTC_DESC(symbol, chipname, vectors, groups,		\
+-	priorities, mask_regs, prio_regs, sense_regs)			\
++	mask_regs, prio_regs, sense_regs)				\
+ struct intc_desc symbol __initdata = {					\
+ 	_INTC_ARRAY(vectors), _INTC_ARRAY(groups),			\
+-	_INTC_ARRAY(priorities),					\
+ 	_INTC_ARRAY(mask_regs), _INTC_ARRAY(prio_regs),			\
+ 	_INTC_ARRAY(sense_regs),					\
+ 	chipname,							\
+diff --git a/include/asm-sh/io.h b/include/asm-sh/io.h
+index 6ed34d8..94900c0 100644
+--- a/include/asm-sh/io.h
++++ b/include/asm-sh/io.h
+@@ -191,6 +191,8 @@ __BUILD_MEMORY_STRING(w, u16)
  
--	/* Let ocfs2_meta_lock do the work of updating our struct
-+	/* Let ocfs2_inode_lock do the work of updating our struct
- 	 * inode for us. */
--	status = ocfs2_meta_lock(inode, NULL, 0);
-+	status = ocfs2_inode_lock(inode, NULL, 0);
- 	if (status < 0) {
- 		if (status != -ENOENT)
- 			mlog_errno(status);
- 		goto bail;
- 	}
--	ocfs2_meta_unlock(inode, 0);
-+	ocfs2_inode_unlock(inode, 0);
- bail:
- 	mlog_exit(status);
+ #define mmiowb()	wmb()	/* synco on SH-4A, otherwise a nop */
  
-diff --git a/fs/ocfs2/inode.h b/fs/ocfs2/inode.h
-index 70e881c..390a855 100644
---- a/fs/ocfs2/inode.h
-+++ b/fs/ocfs2/inode.h
-@@ -34,8 +34,7 @@ struct ocfs2_inode_info
- 	u64			ip_blkno;
++#define IO_SPACE_LIMIT 0xffffffff
++
+ /*
+  * This function provides a method for the generic case where a board-specific
+  * ioport_map simply needs to return the port + some arbitrary port base.
+@@ -226,6 +228,11 @@ static inline unsigned int ctrl_inl(unsigned long addr)
+ 	return *(volatile unsigned long*)addr;
+ }
  
- 	struct ocfs2_lock_res		ip_rw_lockres;
--	struct ocfs2_lock_res		ip_meta_lockres;
--	struct ocfs2_lock_res		ip_data_lockres;
-+	struct ocfs2_lock_res		ip_inode_lockres;
- 	struct ocfs2_lock_res		ip_open_lockres;
++static inline unsigned long long ctrl_inq(unsigned long addr)
++{
++	return *(volatile unsigned long long*)addr;
++}
++
+ static inline void ctrl_outb(unsigned char b, unsigned long addr)
+ {
+ 	*(volatile unsigned char*)addr = b;
+@@ -241,49 +248,52 @@ static inline void ctrl_outl(unsigned int b, unsigned long addr)
+         *(volatile unsigned long*)addr = b;
+ }
  
- 	/* protects allocation changes on this inode. */
-@@ -121,9 +120,10 @@ void ocfs2_delete_inode(struct inode *inode);
- void ocfs2_drop_inode(struct inode *inode);
++static inline void ctrl_outq(unsigned long long b, unsigned long addr)
++{
++	*(volatile unsigned long long*)addr = b;
++}
++
+ static inline void ctrl_delay(void)
+ {
++#ifdef P2SEG
+ 	ctrl_inw(P2SEG);
++#endif
+ }
  
- /* Flags for ocfs2_iget() */
--#define OCFS2_FI_FLAG_SYSFILE		0x4
--#define OCFS2_FI_FLAG_ORPHAN_RECOVERY	0x8
--struct inode *ocfs2_iget(struct ocfs2_super *osb, u64 feoff, int flags);
-+#define OCFS2_FI_FLAG_SYSFILE		0x1
-+#define OCFS2_FI_FLAG_ORPHAN_RECOVERY	0x2
-+struct inode *ocfs2_iget(struct ocfs2_super *osb, u64 feoff, unsigned flags,
-+			 int sysfile_type);
- int ocfs2_inode_init_private(struct inode *inode);
- int ocfs2_inode_revalidate(struct dentry *dentry);
- int ocfs2_populate_inode(struct inode *inode, struct ocfs2_dinode *fe,
-diff --git a/fs/ocfs2/ioctl.c b/fs/ocfs2/ioctl.c
-index 87dcece..5177fba 100644
---- a/fs/ocfs2/ioctl.c
-+++ b/fs/ocfs2/ioctl.c
-@@ -20,6 +20,7 @@
+-#define IO_SPACE_LIMIT 0xffffffff
++/* Quad-word real-mode I/O, don't ask.. */
++unsigned long long peek_real_address_q(unsigned long long addr);
++unsigned long long poke_real_address_q(unsigned long long addr,
++				       unsigned long long val);
  
- #include "ocfs2_fs.h"
- #include "ioctl.h"
-+#include "resize.h"
+-#ifdef CONFIG_MMU
+-/*
+- * Change virtual addresses to physical addresses and vv.
+- * These are trivial on the 1:1 Linux/SuperH mapping
+- */
+-static inline unsigned long virt_to_phys(volatile void *address)
+-{
+-	return PHYSADDR(address);
+-}
++/* arch/sh/mm/ioremap_64.c */
++unsigned long onchip_remap(unsigned long addr, unsigned long size,
++			   const char *name);
++extern void onchip_unmap(unsigned long vaddr);
  
- #include <linux/ext2_fs.h>
+-static inline void *phys_to_virt(unsigned long address)
+-{
+-	return (void *)P1SEGADDR(address);
+-}
+-#else
+-#define phys_to_virt(address)	((void *)(address))
++#if !defined(CONFIG_MMU)
+ #define virt_to_phys(address)	((unsigned long)(address))
++#define phys_to_virt(address)	((void *)(address))
++#else
++#define virt_to_phys(address)	(__pa(address))
++#define phys_to_virt(address)	(__va(address))
+ #endif
  
-@@ -27,14 +28,14 @@ static int ocfs2_get_inode_attr(struct inode *inode, unsigned *flags)
+ /*
+- * readX/writeX() are used to access memory mapped devices. On some
+- * architectures the memory mapped IO stuff needs to be accessed
+- * differently. On the x86 architecture, we just read/write the
+- * memory location directly.
++ * On 32-bit SH, we traditionally have the whole physical address space
++ * mapped at all times (as MIPS does), so "ioremap()" and "iounmap()" do
++ * not need to do anything but place the address in the proper segment.
++ * This is true for P1 and P2 addresses, as well as some P3 ones.
++ * However, most of the P3 addresses and newer cores using extended
++ * addressing need to map through page tables, so the ioremap()
++ * implementation becomes a bit more complicated.
+  *
+- * On SH, we traditionally have the whole physical address space mapped
+- * at all times (as MIPS does), so "ioremap()" and "iounmap()" do not
+- * need to do anything but place the address in the proper segment. This
+- * is true for P1 and P2 addresses, as well as some P3 ones. However,
+- * most of the P3 addresses and newer cores using extended addressing
+- * need to map through page tables, so the ioremap() implementation
+- * becomes a bit more complicated. See arch/sh/mm/ioremap.c for
+- * additional notes on this.
++ * See arch/sh/mm/ioremap.c for additional notes on this.
+  *
+  * We cheat a bit and always return uncachable areas until we've fixed
+  * the drivers to handle caching properly.
++ *
++ * On the SH-5 the concept of segmentation in the 1:1 PXSEG sense simply
++ * doesn't exist, so everything must go through page tables.
+  */
+ #ifdef CONFIG_MMU
+ void __iomem *__ioremap(unsigned long offset, unsigned long size,
+@@ -297,6 +307,7 @@ void __iounmap(void __iomem *addr);
+ static inline void __iomem *
+ __ioremap_mode(unsigned long offset, unsigned long size, unsigned long flags)
  {
- 	int status;
++#ifdef CONFIG_SUPERH32
+ 	unsigned long last_addr = offset + size - 1;
  
--	status = ocfs2_meta_lock(inode, NULL, 0);
-+	status = ocfs2_inode_lock(inode, NULL, 0);
- 	if (status < 0) {
- 		mlog_errno(status);
- 		return status;
+ 	/*
+@@ -311,6 +322,7 @@ __ioremap_mode(unsigned long offset, unsigned long size, unsigned long flags)
+ 
+ 		return (void __iomem *)P2SEGADDR(offset);
  	}
- 	ocfs2_get_inode_flags(OCFS2_I(inode));
- 	*flags = OCFS2_I(inode)->ip_attr;
--	ocfs2_meta_unlock(inode, 0);
-+	ocfs2_inode_unlock(inode, 0);
++#endif
  
- 	mlog_exit(status);
- 	return status;
-@@ -52,7 +53,7 @@ static int ocfs2_set_inode_attr(struct inode *inode, unsigned flags,
+ 	return __ioremap(offset, size, flags);
+ }
+diff --git a/include/asm-sh/irqflags.h b/include/asm-sh/irqflags.h
+index 9dedc1b..46e71da 100644
+--- a/include/asm-sh/irqflags.h
++++ b/include/asm-sh/irqflags.h
+@@ -1,81 +1,11 @@
+ #ifndef __ASM_SH_IRQFLAGS_H
+ #define __ASM_SH_IRQFLAGS_H
+ 
+-static inline void raw_local_irq_enable(void)
+-{
+-	unsigned long __dummy0, __dummy1;
+-
+-	__asm__ __volatile__ (
+-		"stc	sr, %0\n\t"
+-		"and	%1, %0\n\t"
+-#ifdef CONFIG_CPU_HAS_SR_RB
+-		"stc	r6_bank, %1\n\t"
+-		"or	%1, %0\n\t"
++#ifdef CONFIG_SUPERH32
++#include "irqflags_32.h"
++#else
++#include "irqflags_64.h"
+ #endif
+-		"ldc	%0, sr\n\t"
+-		: "=&r" (__dummy0), "=r" (__dummy1)
+-		: "1" (~0x000000f0)
+-		: "memory"
+-	);
+-}
+-
+-static inline void raw_local_irq_disable(void)
+-{
+-	unsigned long flags;
+-
+-	__asm__ __volatile__ (
+-		"stc	sr, %0\n\t"
+-		"or	#0xf0, %0\n\t"
+-		"ldc	%0, sr\n\t"
+-		: "=&z" (flags)
+-		: /* no inputs */
+-		: "memory"
+-	);
+-}
+-
+-static inline void set_bl_bit(void)
+-{
+-	unsigned long __dummy0, __dummy1;
+-
+-	__asm__ __volatile__ (
+-		"stc	sr, %0\n\t"
+-		"or	%2, %0\n\t"
+-		"and	%3, %0\n\t"
+-		"ldc	%0, sr\n\t"
+-		: "=&r" (__dummy0), "=r" (__dummy1)
+-		: "r" (0x10000000), "r" (0xffffff0f)
+-		: "memory"
+-	);
+-}
+-
+-static inline void clear_bl_bit(void)
+-{
+-	unsigned long __dummy0, __dummy1;
+-
+-	__asm__ __volatile__ (
+-		"stc	sr, %0\n\t"
+-		"and	%2, %0\n\t"
+-		"ldc	%0, sr\n\t"
+-		: "=&r" (__dummy0), "=r" (__dummy1)
+-		: "1" (~0x10000000)
+-		: "memory"
+-	);
+-}
+-
+-static inline unsigned long __raw_local_save_flags(void)
+-{
+-	unsigned long flags;
+-
+-	__asm__ __volatile__ (
+-		"stc	sr, %0\n\t"
+-		"and	#0xf0, %0\n\t"
+-		: "=&z" (flags)
+-		: /* no inputs */
+-		: "memory"
+-	);
+-
+-	return flags;
+-}
  
- 	mutex_lock(&inode->i_mutex);
+ #define raw_local_save_flags(flags) \
+ 		do { (flags) = __raw_local_save_flags(); } while (0)
+@@ -92,25 +22,6 @@ static inline int raw_irqs_disabled(void)
+ 	return raw_irqs_disabled_flags(flags);
+ }
  
--	status = ocfs2_meta_lock(inode, &bh, 1);
-+	status = ocfs2_inode_lock(inode, &bh, 1);
- 	if (status < 0) {
- 		mlog_errno(status);
- 		goto bail;
-@@ -100,7 +101,7 @@ static int ocfs2_set_inode_attr(struct inode *inode, unsigned flags,
+-static inline unsigned long __raw_local_irq_save(void)
+-{
+-	unsigned long flags, __dummy;
+-
+-	__asm__ __volatile__ (
+-		"stc	sr, %1\n\t"
+-		"mov	%1, %0\n\t"
+-		"or	#0xf0, %0\n\t"
+-		"ldc	%0, sr\n\t"
+-		"mov	%1, %0\n\t"
+-		"and	#0xf0, %0\n\t"
+-		: "=&z" (flags), "=&r" (__dummy)
+-		: /* no inputs */
+-		: "memory"
+-	);
+-
+-	return flags;
+-}
+-
+ #define raw_local_irq_save(flags) \
+ 		do { (flags) = __raw_local_irq_save(); } while (0)
  
- 	ocfs2_commit_trans(osb, handle);
- bail_unlock:
--	ocfs2_meta_unlock(inode, 1);
-+	ocfs2_inode_unlock(inode, 1);
- bail:
- 	mutex_unlock(&inode->i_mutex);
+diff --git a/include/asm-sh/irqflags_32.h b/include/asm-sh/irqflags_32.h
+new file mode 100644
+index 0000000..60218f5
+--- /dev/null
++++ b/include/asm-sh/irqflags_32.h
+@@ -0,0 +1,99 @@
++#ifndef __ASM_SH_IRQFLAGS_32_H
++#define __ASM_SH_IRQFLAGS_32_H
++
++static inline void raw_local_irq_enable(void)
++{
++	unsigned long __dummy0, __dummy1;
++
++	__asm__ __volatile__ (
++		"stc	sr, %0\n\t"
++		"and	%1, %0\n\t"
++#ifdef CONFIG_CPU_HAS_SR_RB
++		"stc	r6_bank, %1\n\t"
++		"or	%1, %0\n\t"
++#endif
++		"ldc	%0, sr\n\t"
++		: "=&r" (__dummy0), "=r" (__dummy1)
++		: "1" (~0x000000f0)
++		: "memory"
++	);
++}
++
++static inline void raw_local_irq_disable(void)
++{
++	unsigned long flags;
++
++	__asm__ __volatile__ (
++		"stc	sr, %0\n\t"
++		"or	#0xf0, %0\n\t"
++		"ldc	%0, sr\n\t"
++		: "=&z" (flags)
++		: /* no inputs */
++		: "memory"
++	);
++}
++
++static inline void set_bl_bit(void)
++{
++	unsigned long __dummy0, __dummy1;
++
++	__asm__ __volatile__ (
++		"stc	sr, %0\n\t"
++		"or	%2, %0\n\t"
++		"and	%3, %0\n\t"
++		"ldc	%0, sr\n\t"
++		: "=&r" (__dummy0), "=r" (__dummy1)
++		: "r" (0x10000000), "r" (0xffffff0f)
++		: "memory"
++	);
++}
++
++static inline void clear_bl_bit(void)
++{
++	unsigned long __dummy0, __dummy1;
++
++	__asm__ __volatile__ (
++		"stc	sr, %0\n\t"
++		"and	%2, %0\n\t"
++		"ldc	%0, sr\n\t"
++		: "=&r" (__dummy0), "=r" (__dummy1)
++		: "1" (~0x10000000)
++		: "memory"
++	);
++}
++
++static inline unsigned long __raw_local_save_flags(void)
++{
++	unsigned long flags;
++
++	__asm__ __volatile__ (
++		"stc	sr, %0\n\t"
++		"and	#0xf0, %0\n\t"
++		: "=&z" (flags)
++		: /* no inputs */
++		: "memory"
++	);
++
++	return flags;
++}
++
++static inline unsigned long __raw_local_irq_save(void)
++{
++	unsigned long flags, __dummy;
++
++	__asm__ __volatile__ (
++		"stc	sr, %1\n\t"
++		"mov	%1, %0\n\t"
++		"or	#0xf0, %0\n\t"
++		"ldc	%0, sr\n\t"
++		"mov	%1, %0\n\t"
++		"and	#0xf0, %0\n\t"
++		: "=&z" (flags), "=&r" (__dummy)
++		: /* no inputs */
++		: "memory"
++	);
++
++	return flags;
++}
++
++#endif /* __ASM_SH_IRQFLAGS_32_H */
+diff --git a/include/asm-sh/irqflags_64.h b/include/asm-sh/irqflags_64.h
+new file mode 100644
+index 0000000..4f6b8a5
+--- /dev/null
++++ b/include/asm-sh/irqflags_64.h
+@@ -0,0 +1,85 @@
++#ifndef __ASM_SH_IRQFLAGS_64_H
++#define __ASM_SH_IRQFLAGS_64_H
++
++#include <asm/cpu/registers.h>
++
++#define SR_MASK_LL	0x00000000000000f0LL
++#define SR_BL_LL	0x0000000010000000LL
++
++static inline void raw_local_irq_enable(void)
++{
++	unsigned long long __dummy0, __dummy1 = ~SR_MASK_LL;
++
++	__asm__ __volatile__("getcon	" __SR ", %0\n\t"
++			     "and	%0, %1, %0\n\t"
++			     "putcon	%0, " __SR "\n\t"
++			     : "=&r" (__dummy0)
++			     : "r" (__dummy1));
++}
++
++static inline void raw_local_irq_disable(void)
++{
++	unsigned long long __dummy0, __dummy1 = SR_MASK_LL;
++
++	__asm__ __volatile__("getcon	" __SR ", %0\n\t"
++			     "or	%0, %1, %0\n\t"
++			     "putcon	%0, " __SR "\n\t"
++			     : "=&r" (__dummy0)
++			     : "r" (__dummy1));
++}
++
++static inline void set_bl_bit(void)
++{
++	unsigned long long __dummy0, __dummy1 = SR_BL_LL;
++
++	__asm__ __volatile__("getcon	" __SR ", %0\n\t"
++			     "or	%0, %1, %0\n\t"
++			     "putcon	%0, " __SR "\n\t"
++			     : "=&r" (__dummy0)
++			     : "r" (__dummy1));
++
++}
++
++static inline void clear_bl_bit(void)
++{
++	unsigned long long __dummy0, __dummy1 = ~SR_BL_LL;
++
++	__asm__ __volatile__("getcon	" __SR ", %0\n\t"
++			     "and	%0, %1, %0\n\t"
++			     "putcon	%0, " __SR "\n\t"
++			     : "=&r" (__dummy0)
++			     : "r" (__dummy1));
++}
++
++static inline unsigned long __raw_local_save_flags(void)
++{
++	unsigned long long __dummy = SR_MASK_LL;
++	unsigned long flags;
++
++	__asm__ __volatile__ (
++		"getcon	" __SR ", %0\n\t"
++		"and	%0, %1, %0"
++		: "=&r" (flags)
++		: "r" (__dummy));
++
++	return flags;
++}
++
++static inline unsigned long __raw_local_irq_save(void)
++{
++	unsigned long long __dummy0, __dummy1 = SR_MASK_LL;
++	unsigned long flags;
++
++	__asm__ __volatile__ (
++		"getcon	" __SR ", %1\n\t"
++		"or	%1, r63, %0\n\t"
++		"or	%1, %2, %1\n\t"
++		"putcon	%1, " __SR "\n\t"
++		"and	%0, %2, %0"
++		: "=&r" (flags), "=&r" (__dummy0)
++		: "r" (__dummy1));
++
++	return flags;
++}
++
++#endif /* __ASM_SH_IRQFLAGS_64_H */
+diff --git a/include/asm-sh/machvec.h b/include/asm-sh/machvec.h
+index 088698b..ddb18ad 100644
+--- a/include/asm-sh/machvec.h
++++ b/include/asm-sh/machvec.h
+@@ -56,9 +56,6 @@ struct sh_machine_vector {
+ 
+ 	void (*mv_heartbeat)(void);
+ 
+-	void *(*mv_consistent_alloc)(struct device *, size_t, dma_addr_t *, gfp_t);
+-	int (*mv_consistent_free)(struct device *, size_t, void *, dma_addr_t);
+-
+ 	void __iomem *(*mv_ioport_map)(unsigned long port, unsigned int size);
+ 	void (*mv_ioport_unmap)(void __iomem *);
+ };
+diff --git a/include/asm-sh/microdev.h b/include/asm-sh/microdev.h
+index 018332a..1aed158 100644
+--- a/include/asm-sh/microdev.h
++++ b/include/asm-sh/microdev.h
+@@ -17,7 +17,7 @@ extern void microdev_print_fpga_intc_status(void);
+ /*
+  * The following are useful macros for manipulating the interrupt
+  * controller (INTC) on the CPU-board FPGA.  should be noted that there
+- * is an INTC on the FPGA, and a seperate INTC on the SH4-202 core -
++ * is an INTC on the FPGA, and a separate INTC on the SH4-202 core -
+  * these are two different things, both of which need to be prorammed to
+  * correctly route - unfortunately, they have the same name and
+  * abbreviations!
+@@ -25,7 +25,7 @@ extern void microdev_print_fpga_intc_status(void);
+ #define	MICRODEV_FPGA_INTC_BASE		0xa6110000ul				/* INTC base address on CPU-board FPGA */
+ #define	MICRODEV_FPGA_INTENB_REG	(MICRODEV_FPGA_INTC_BASE+0ul)		/* Interrupt Enable Register on INTC on CPU-board FPGA */
+ #define	MICRODEV_FPGA_INTDSB_REG	(MICRODEV_FPGA_INTC_BASE+8ul)		/* Interrupt Disable Register on INTC on CPU-board FPGA */
+-#define	MICRODEV_FPGA_INTC_MASK(n)	(1ul<<(n))				/* Interupt mask to enable/disable INTC in CPU-board FPGA */
++#define	MICRODEV_FPGA_INTC_MASK(n)	(1ul<<(n))				/* Interrupt mask to enable/disable INTC in CPU-board FPGA */
+ #define	MICRODEV_FPGA_INTPRI_REG(n)	(MICRODEV_FPGA_INTC_BASE+0x10+((n)/8)*8)/* Interrupt Priority Register on INTC on CPU-board FPGA */
+ #define	MICRODEV_FPGA_INTPRI_LEVEL(n,x)	((x)<<(((n)%8)*4))			/* MICRODEV_FPGA_INTPRI_LEVEL(int_number, int_level) */
+ #define	MICRODEV_FPGA_INTPRI_MASK(n)	(MICRODEV_FPGA_INTPRI_LEVEL((n),0xful))	/* Interrupt Priority Mask on INTC on CPU-board FPGA */
+diff --git a/include/asm-sh/mmu_context.h b/include/asm-sh/mmu_context.h
+index 199662b..fe58d00 100644
+--- a/include/asm-sh/mmu_context.h
++++ b/include/asm-sh/mmu_context.h
+@@ -1,13 +1,13 @@
+ /*
+  * Copyright (C) 1999 Niibe Yutaka
+- * Copyright (C) 2003 - 2006 Paul Mundt
++ * Copyright (C) 2003 - 2007 Paul Mundt
+  *
+  * ASID handling idea taken from MIPS implementation.
+  */
+ #ifndef __ASM_SH_MMU_CONTEXT_H
+ #define __ASM_SH_MMU_CONTEXT_H
+-#ifdef __KERNEL__
  
-@@ -115,8 +116,10 @@ int ocfs2_ioctl(struct inode * inode, struct file * filp,
- 	unsigned int cmd, unsigned long arg)
- {
- 	unsigned int flags;
-+	int new_clusters;
- 	int status;
- 	struct ocfs2_space_resv sr;
-+	struct ocfs2_new_group_input input;
++#ifdef __KERNEL__
+ #include <asm/cpu/mmu_context.h>
+ #include <asm/tlbflush.h>
+ #include <asm/uaccess.h>
+@@ -19,7 +19,6 @@
+  *    (a) TLB cache version (or round, cycle whatever expression you like)
+  *    (b) ASID (Address Space IDentifier)
+  */
+-
+ #define MMU_CONTEXT_ASID_MASK		0x000000ff
+ #define MMU_CONTEXT_VERSION_MASK	0xffffff00
+ #define MMU_CONTEXT_FIRST_VERSION	0x00000100
+@@ -28,10 +27,11 @@
+ /* ASID is 8-bit value, so it can't be 0x100 */
+ #define MMU_NO_ASID			0x100
+ 
+-#define cpu_context(cpu, mm)	((mm)->context.id[cpu])
+-#define cpu_asid(cpu, mm)	(cpu_context((cpu), (mm)) & \
+-				 MMU_CONTEXT_ASID_MASK)
+ #define asid_cache(cpu)		(cpu_data[cpu].asid_cache)
++#define cpu_context(cpu, mm)	((mm)->context.id[cpu])
++
++#define cpu_asid(cpu, mm)	\
++	(cpu_context((cpu), (mm)) & MMU_CONTEXT_ASID_MASK)
+ 
+ /*
+  * Virtual Page Number mask
+@@ -39,6 +39,12 @@
+ #define MMU_VPN_MASK	0xfffff000
+ 
+ #ifdef CONFIG_MMU
++#if defined(CONFIG_SUPERH32)
++#include "mmu_context_32.h"
++#else
++#include "mmu_context_64.h"
++#endif
++
+ /*
+  * Get MMU context if needed.
+  */
+@@ -59,6 +65,14 @@ static inline void get_mmu_context(struct mm_struct *mm, unsigned int cpu)
+ 		 */
+ 		flush_tlb_all();
  
- 	switch (cmd) {
- 	case OCFS2_IOC_GETFLAGS:
-@@ -140,6 +143,23 @@ int ocfs2_ioctl(struct inode * inode, struct file * filp,
- 			return -EFAULT;
++#ifdef CONFIG_SUPERH64
++		/*
++		 * The SH-5 cache uses the ASIDs, requiring both the I and D
++		 * cache to be flushed when the ASID is exhausted. Weak.
++		 */
++		flush_cache_all();
++#endif
++
+ 		/*
+ 		 * Fix version; Note that we avoid version #0
+ 		 * to distingush NO_CONTEXT.
+@@ -86,39 +100,6 @@ static inline int init_new_context(struct task_struct *tsk,
+ }
  
- 		return ocfs2_change_file_space(filp, cmd, &sr);
-+	case OCFS2_IOC_GROUP_EXTEND:
-+		if (!capable(CAP_SYS_RESOURCE))
-+			return -EPERM;
+ /*
+- * 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)
+-{
+-	/* Do nothing */
+-}
+-
+-static inline void set_asid(unsigned long asid)
+-{
+-	unsigned long __dummy;
+-
+-	__asm__ __volatile__ ("mov.l	%2, %0\n\t"
+-			      "and	%3, %0\n\t"
+-			      "or	%1, %0\n\t"
+-			      "mov.l	%0, %2"
+-			      : "=&r" (__dummy)
+-			      : "r" (asid), "m" (__m(MMU_PTEH)),
+-			        "r" (0xffffff00));
+-}
+-
+-static inline unsigned long get_asid(void)
+-{
+-	unsigned long asid;
+-
+-	__asm__ __volatile__ ("mov.l	%1, %0"
+-			      : "=r" (asid)
+-			      : "m" (__m(MMU_PTEH)));
+-	asid &= MMU_CONTEXT_ASID_MASK;
+-	return asid;
+-}
+-
+-/*
+  * After we have set current->mm to a new value, this activates
+  * the context for the new mm so we see the new mappings.
+  */
+@@ -128,17 +109,6 @@ static inline void activate_context(struct mm_struct *mm, unsigned int cpu)
+ 	set_asid(cpu_asid(cpu, mm));
+ }
+ 
+-/* MMU_TTB is used for optimizing the fault handling. */
+-static inline void set_TTB(pgd_t *pgd)
+-{
+-	ctrl_outl((unsigned long)pgd, MMU_TTB);
+-}
+-
+-static inline pgd_t *get_TTB(void)
+-{
+-	return (pgd_t *)ctrl_inl(MMU_TTB);
+-}
+-
+ static inline void switch_mm(struct mm_struct *prev,
+ 			     struct mm_struct *next,
+ 			     struct task_struct *tsk)
+@@ -153,17 +123,7 @@ static inline void switch_mm(struct mm_struct *prev,
+ 		if (!cpu_test_and_set(cpu, next->cpu_vm_mask))
+ 			activate_context(next, cpu);
+ }
+-
+-#define deactivate_mm(tsk,mm)	do { } while (0)
+-
+-#define activate_mm(prev, next) \
+-	switch_mm((prev),(next),NULL)
+-
+-static inline void
+-enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
+-{
+-}
+-#else /* !CONFIG_MMU */
++#else
+ #define get_mmu_context(mm)		do { } while (0)
+ #define init_new_context(tsk,mm)	(0)
+ #define destroy_context(mm)		do { } while (0)
+@@ -173,10 +133,11 @@ enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
+ #define get_TTB()			(0)
+ #define activate_context(mm,cpu)	do { } while (0)
+ #define switch_mm(prev,next,tsk)	do { } while (0)
++#endif /* CONFIG_MMU */
++
++#define activate_mm(prev, next)		switch_mm((prev),(next),NULL)
+ #define deactivate_mm(tsk,mm)		do { } while (0)
+-#define activate_mm(prev,next)		do { } while (0)
+ #define enter_lazy_tlb(mm,tsk)		do { } while (0)
+-#endif /* CONFIG_MMU */
+ 
+ #if defined(CONFIG_CPU_SH3) || defined(CONFIG_CPU_SH4)
+ /*
+diff --git a/include/asm-sh/mmu_context_32.h b/include/asm-sh/mmu_context_32.h
+new file mode 100644
+index 0000000..f4f9aeb
+--- /dev/null
++++ b/include/asm-sh/mmu_context_32.h
+@@ -0,0 +1,47 @@
++#ifndef __ASM_SH_MMU_CONTEXT_32_H
++#define __ASM_SH_MMU_CONTEXT_32_H
 +
-+		if (get_user(new_clusters, (int __user *)arg))
-+			return -EFAULT;
++/*
++ * 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)
++{
++	/* Do nothing */
++}
 +
-+		return ocfs2_group_extend(inode, new_clusters);
-+	case OCFS2_IOC_GROUP_ADD:
-+	case OCFS2_IOC_GROUP_ADD64:
-+		if (!capable(CAP_SYS_RESOURCE))
-+			return -EPERM;
++static inline void set_asid(unsigned long asid)
++{
++	unsigned long __dummy;
 +
-+		if (copy_from_user(&input, (int __user *) arg, sizeof(input)))
-+			return -EFAULT;
++	__asm__ __volatile__ ("mov.l	%2, %0\n\t"
++			      "and	%3, %0\n\t"
++			      "or	%1, %0\n\t"
++			      "mov.l	%0, %2"
++			      : "=&r" (__dummy)
++			      : "r" (asid), "m" (__m(MMU_PTEH)),
++			        "r" (0xffffff00));
++}
 +
-+		return ocfs2_group_add(inode, &input);
- 	default:
- 		return -ENOTTY;
- 	}
-@@ -162,6 +182,9 @@ long ocfs2_compat_ioctl(struct file *file, unsigned cmd, unsigned long arg)
- 	case OCFS2_IOC_RESVSP64:
- 	case OCFS2_IOC_UNRESVSP:
- 	case OCFS2_IOC_UNRESVSP64:
-+	case OCFS2_IOC_GROUP_EXTEND:
-+	case OCFS2_IOC_GROUP_ADD:
-+	case OCFS2_IOC_GROUP_ADD64:
- 		break;
- 	default:
- 		return -ENOIOCTLCMD;
-diff --git a/fs/ocfs2/journal.c b/fs/ocfs2/journal.c
-index 8d81f6c..f31c7e8 100644
---- a/fs/ocfs2/journal.c
-+++ b/fs/ocfs2/journal.c
-@@ -44,7 +44,6 @@
- #include "localalloc.h"
- #include "slot_map.h"
- #include "super.h"
--#include "vote.h"
- #include "sysfile.h"
++static inline unsigned long get_asid(void)
++{
++	unsigned long asid;
++
++	__asm__ __volatile__ ("mov.l	%1, %0"
++			      : "=r" (asid)
++			      : "m" (__m(MMU_PTEH)));
++	asid &= MMU_CONTEXT_ASID_MASK;
++	return asid;
++}
++
++/* MMU_TTB is used for optimizing the fault handling. */
++static inline void set_TTB(pgd_t *pgd)
++{
++	ctrl_outl((unsigned long)pgd, MMU_TTB);
++}
++
++static inline pgd_t *get_TTB(void)
++{
++	return (pgd_t *)ctrl_inl(MMU_TTB);
++}
++#endif /* __ASM_SH_MMU_CONTEXT_32_H */
+diff --git a/include/asm-sh/mmu_context_64.h b/include/asm-sh/mmu_context_64.h
+new file mode 100644
+index 0000000..020be74
+--- /dev/null
++++ b/include/asm-sh/mmu_context_64.h
+@@ -0,0 +1,75 @@
++#ifndef __ASM_SH_MMU_CONTEXT_64_H
++#define __ASM_SH_MMU_CONTEXT_64_H
++
++/*
++ * sh64-specific mmu_context interface.
++ *
++ * Copyright (C) 2000, 2001  Paolo Alberelli
++ * Copyright (C) 2003 - 2007  Paul Mundt
++ *
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License.  See the file "COPYING" in the main directory of this archive
++ * for more details.
++ */
++#include <asm/cpu/registers.h>
++#include <asm/cacheflush.h>
++
++#define SR_ASID_MASK		0xffffffffff00ffffULL
++#define SR_ASID_SHIFT		16
++
++/*
++ * 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)
++{
++	/* Well, at least free TLB entries */
++	flush_tlb_mm(mm);
++}
++
++static inline unsigned long get_asid(void)
++{
++	unsigned long long sr;
++
++	asm volatile ("getcon   " __SR ", %0\n\t"
++		      : "=r" (sr));
++
++	sr = (sr >> SR_ASID_SHIFT) & MMU_CONTEXT_ASID_MASK;
++	return (unsigned long) sr;
++}
++
++/* Set ASID into SR */
++static inline void set_asid(unsigned long asid)
++{
++	unsigned long long sr, pc;
++
++	asm volatile ("getcon	" __SR ", %0" : "=r" (sr));
++
++	sr = (sr & SR_ASID_MASK) | (asid << SR_ASID_SHIFT);
++
++	/*
++	 * It is possible that this function may be inlined and so to avoid
++	 * the assembler reporting duplicate symbols we make use of the
++	 * gas trick of generating symbols using numerics and forward
++	 * reference.
++	 */
++	asm volatile ("movi	1, %1\n\t"
++		      "shlli	%1, 28, %1\n\t"
++		      "or	%0, %1, %1\n\t"
++		      "putcon	%1, " __SR "\n\t"
++		      "putcon	%0, " __SSR "\n\t"
++		      "movi	1f, %1\n\t"
++		      "ori	%1, 1 , %1\n\t"
++		      "putcon	%1, " __SPC "\n\t"
++		      "rte\n"
++		      "1:\n\t"
++		      : "=r" (sr), "=r" (pc) : "0" (sr));
++}
++
++/* No spare register to twiddle, so use a software cache */
++extern pgd_t *mmu_pdtp_cache;
++
++#define set_TTB(pgd)	(mmu_pdtp_cache = (pgd))
++#define get_TTB()	(mmu_pdtp_cache)
++
++#endif /* __ASM_SH_MMU_CONTEXT_64_H */
+diff --git a/include/asm-sh/module.h b/include/asm-sh/module.h
+index 118d5a2..46eccd3 100644
+--- a/include/asm-sh/module.h
++++ b/include/asm-sh/module.h
+@@ -20,6 +20,8 @@ struct mod_arch_specific {
+ #  define MODULE_PROC_FAMILY "SH3LE "
+ # elif defined  CONFIG_CPU_SH4
+ #  define MODULE_PROC_FAMILY "SH4LE "
++# elif defined  CONFIG_CPU_SH5
++#  define MODULE_PROC_FAMILY "SH5LE "
+ # else
+ #  error unknown processor family
+ # endif
+@@ -30,6 +32,8 @@ struct mod_arch_specific {
+ #  define MODULE_PROC_FAMILY "SH3BE "
+ # elif defined  CONFIG_CPU_SH4
+ #  define MODULE_PROC_FAMILY "SH4BE "
++# elif defined  CONFIG_CPU_SH5
++#  define MODULE_PROC_FAMILY "SH5BE "
+ # else
+ #  error unknown processor family
+ # endif
+diff --git a/include/asm-sh/page.h b/include/asm-sh/page.h
+index d00a8fd..002e64a 100644
+--- a/include/asm-sh/page.h
++++ b/include/asm-sh/page.h
+@@ -5,13 +5,7 @@
+  * Copyright (C) 1999  Niibe Yutaka
+  */
  
- #include "buffer_head_io.h"
-@@ -103,7 +102,7 @@ static int ocfs2_commit_cache(struct ocfs2_super *osb)
- 	mlog(0, "commit_thread: flushed transaction %lu (%u handles)\n",
- 	     journal->j_trans_id, flushed);
+-/*
+-   [ P0/U0 (virtual) ]		0x00000000     <------ User space
+-   [ P1 (fixed)   cached ]	0x80000000     <------ Kernel space
+-   [ P2 (fixed)  non-cachable]	0xA0000000     <------ Physical access
+-   [ P3 (virtual) cached]	0xC0000000     <------ vmalloced area
+-   [ P4 control   ]		0xE0000000
+- */
++#include <linux/const.h>
  
--	ocfs2_kick_vote_thread(osb);
-+	ocfs2_wake_downconvert_thread(osb);
- 	wake_up(&journal->j_checkpointed);
- finally:
- 	mlog_exit(status);
-@@ -314,14 +313,18 @@ int ocfs2_journal_dirty_data(handle_t *handle,
- 	return err;
- }
+ #ifdef __KERNEL__
  
--#define OCFS2_DEFAULT_COMMIT_INTERVAL 	(HZ * 5)
-+#define OCFS2_DEFAULT_COMMIT_INTERVAL 	(HZ * JBD_DEFAULT_MAX_COMMIT_AGE)
+@@ -26,15 +20,13 @@
+ # error "Bogus kernel page size?"
+ #endif
  
- void ocfs2_set_journal_params(struct ocfs2_super *osb)
- {
- 	journal_t *journal = osb->journal->j_journal;
-+	unsigned long commit_interval = OCFS2_DEFAULT_COMMIT_INTERVAL;
-+
-+	if (osb->osb_commit_interval)
-+		commit_interval = osb->osb_commit_interval;
+-#ifdef __ASSEMBLY__
+-#define PAGE_SIZE	(1 << PAGE_SHIFT)
+-#else
+-#define PAGE_SIZE	(1UL << PAGE_SHIFT)
+-#endif
+-
++#define PAGE_SIZE	(_AC(1, UL) << PAGE_SHIFT)
+ #define PAGE_MASK	(~(PAGE_SIZE-1))
+ #define PTE_MASK	PAGE_MASK
+ 
++/* to align the pointer to the (next) page boundary */
++#define PAGE_ALIGN(addr)	(((addr)+PAGE_SIZE-1)&PAGE_MASK)
++
+ #if defined(CONFIG_HUGETLB_PAGE_SIZE_64K)
+ #define HPAGE_SHIFT	16
+ #elif defined(CONFIG_HUGETLB_PAGE_SIZE_256K)
+@@ -45,6 +37,8 @@
+ #define HPAGE_SHIFT	22
+ #elif defined(CONFIG_HUGETLB_PAGE_SIZE_64MB)
+ #define HPAGE_SHIFT	26
++#elif defined(CONFIG_HUGETLB_PAGE_SIZE_512MB)
++#define HPAGE_SHIFT	29
+ #endif
  
- 	spin_lock(&journal->j_state_lock);
--	journal->j_commit_interval = OCFS2_DEFAULT_COMMIT_INTERVAL;
-+	journal->j_commit_interval = commit_interval;
- 	if (osb->s_mount_opt & OCFS2_MOUNT_BARRIER)
- 		journal->j_flags |= JFS_BARRIER;
- 	else
-@@ -337,7 +340,7 @@ int ocfs2_journal_init(struct ocfs2_journal *journal, int *dirty)
- 	struct ocfs2_dinode *di = NULL;
- 	struct buffer_head *bh = NULL;
- 	struct ocfs2_super *osb;
--	int meta_lock = 0;
-+	int inode_lock = 0;
+ #ifdef CONFIG_HUGETLB_PAGE
+@@ -55,20 +49,12 @@
  
- 	mlog_entry_void();
+ #ifndef __ASSEMBLY__
  
-@@ -367,14 +370,14 @@ int ocfs2_journal_init(struct ocfs2_journal *journal, int *dirty)
- 	/* Skip recovery waits here - journal inode metadata never
- 	 * changes in a live cluster so it can be considered an
- 	 * exception to the rule. */
--	status = ocfs2_meta_lock_full(inode, &bh, 1, OCFS2_META_LOCK_RECOVERY);
-+	status = ocfs2_inode_lock_full(inode, &bh, 1, OCFS2_META_LOCK_RECOVERY);
- 	if (status < 0) {
- 		if (status != -ERESTARTSYS)
- 			mlog(ML_ERROR, "Could not get lock on journal!\n");
- 		goto done;
- 	}
+-extern void (*clear_page)(void *to);
+-extern void (*copy_page)(void *to, void *from);
+-
+ extern unsigned long shm_align_mask;
+ extern unsigned long max_low_pfn, min_low_pfn;
+ extern unsigned long memory_start, memory_end;
+ 
+-#ifdef CONFIG_MMU
+-extern void clear_page_slow(void *to);
+-extern void copy_page_slow(void *to, void *from);
+-#else
+-extern void clear_page_nommu(void *to);
+-extern void copy_page_nommu(void *to, void *from);
+-#endif
++extern void clear_page(void *to);
++extern void copy_page(void *to, void *from);
  
--	meta_lock = 1;
-+	inode_lock = 1;
- 	di = (struct ocfs2_dinode *)bh->b_data;
+ #if !defined(CONFIG_CACHE_OFF) && defined(CONFIG_MMU) && \
+ 	(defined(CONFIG_CPU_SH4) || defined(CONFIG_SH7705_CACHE_32KB))
+@@ -96,12 +82,18 @@ typedef struct { unsigned long long pgd; } pgd_t;
+ 	((x).pte_low | ((unsigned long long)(x).pte_high << 32))
+ #define __pte(x) \
+ 	({ pte_t __pte = {(x), ((unsigned long long)(x)) >> 32}; __pte; })
+-#else
++#elif defined(CONFIG_SUPERH32)
+ typedef struct { unsigned long pte_low; } pte_t;
+ typedef struct { unsigned long pgprot; } pgprot_t;
+ typedef struct { unsigned long pgd; } pgd_t;
+ #define pte_val(x)	((x).pte_low)
+-#define __pte(x) ((pte_t) { (x) } )
++#define __pte(x)	((pte_t) { (x) } )
++#else
++typedef struct { unsigned long long pte_low; } pte_t;
++typedef struct { unsigned long pgprot; } pgprot_t;
++typedef struct { unsigned long pgd; } pgd_t;
++#define pte_val(x)	((x).pte_low)
++#define __pte(x)	((pte_t) { (x) } )
+ #endif
  
- 	if (inode->i_size <  OCFS2_MIN_JOURNAL_SIZE) {
-@@ -414,8 +417,8 @@ int ocfs2_journal_init(struct ocfs2_journal *journal, int *dirty)
- 	status = 0;
- done:
- 	if (status < 0) {
--		if (meta_lock)
--			ocfs2_meta_unlock(inode, 1);
-+		if (inode_lock)
-+			ocfs2_inode_unlock(inode, 1);
- 		if (bh != NULL)
- 			brelse(bh);
- 		if (inode) {
-@@ -544,7 +547,7 @@ void ocfs2_journal_shutdown(struct ocfs2_super *osb)
- 	OCFS2_I(inode)->ip_open_count--;
+ #define pgd_val(x)	((x).pgd)
+@@ -112,28 +104,44 @@ typedef struct { unsigned long pgd; } pgd_t;
  
- 	/* unlock our journal */
--	ocfs2_meta_unlock(inode, 1);
-+	ocfs2_inode_unlock(inode, 1);
+ #endif /* !__ASSEMBLY__ */
  
- 	brelse(journal->j_bh);
- 	journal->j_bh = NULL;
-@@ -883,8 +886,8 @@ restart:
- 	ocfs2_super_unlock(osb, 1);
+-/* to align the pointer to the (next) page boundary */
+-#define PAGE_ALIGN(addr)	(((addr)+PAGE_SIZE-1)&PAGE_MASK)
+-
+ /*
+- * IF YOU CHANGE THIS, PLEASE ALSO CHANGE
+- *
+- *	arch/sh/kernel/vmlinux.lds.S
+- *
+- * which has the same constant encoded..
++ * __MEMORY_START and SIZE are the physical addresses and size of RAM.
+  */
+-
+ #define __MEMORY_START		CONFIG_MEMORY_START
+ #define __MEMORY_SIZE		CONFIG_MEMORY_SIZE
  
- 	/* We always run recovery on our own orphan dir - the dead
--	 * node(s) may have voted "no" on an inode delete earlier. A
--	 * revote is therefore required. */
-+	 * node(s) may have disallowd a previos inode delete. Re-processing
-+	 * is therefore required. */
- 	ocfs2_queue_recovery_completion(osb->journal, osb->slot_num, NULL,
- 					NULL);
++/*
++ * PAGE_OFFSET is the virtual address of the start of kernel address
++ * space.
++ */
+ #define PAGE_OFFSET		CONFIG_PAGE_OFFSET
+-#define __pa(x)			((unsigned long)(x)-PAGE_OFFSET)
+-#define __va(x)			((void *)((unsigned long)(x)+PAGE_OFFSET))
+-#define pfn_to_kaddr(pfn)	__va((pfn) << PAGE_SHIFT)
  
-@@ -973,9 +976,9 @@ static int ocfs2_replay_journal(struct ocfs2_super *osb,
- 	}
- 	SET_INODE_JOURNAL(inode);
++/*
++ * Virtual to physical RAM address translation.
++ *
++ * In 29 bit mode, the physical offset of RAM from address 0 is visible in
++ * the kernel virtual address space, and thus we don't have to take
++ * this into account when translating. However in 32 bit mode this offset
++ * is not visible (it is part of the PMB mapping) and so needs to be
++ * added or subtracted as required.
++ */
++#ifdef CONFIG_32BIT
++#define __pa(x)	((unsigned long)(x)-PAGE_OFFSET+__MEMORY_START)
++#define __va(x)	((void *)((unsigned long)(x)+PAGE_OFFSET-__MEMORY_START))
++#else
++#define __pa(x)	((unsigned long)(x)-PAGE_OFFSET)
++#define __va(x)	((void *)((unsigned long)(x)+PAGE_OFFSET))
++#endif
++
++#define pfn_to_kaddr(pfn)	__va((pfn) << PAGE_SHIFT)
+ #define page_to_phys(page)	(page_to_pfn(page) << PAGE_SHIFT)
  
--	status = ocfs2_meta_lock_full(inode, &bh, 1, OCFS2_META_LOCK_RECOVERY);
-+	status = ocfs2_inode_lock_full(inode, &bh, 1, OCFS2_META_LOCK_RECOVERY);
- 	if (status < 0) {
--		mlog(0, "status returned from ocfs2_meta_lock=%d\n", status);
-+		mlog(0, "status returned from ocfs2_inode_lock=%d\n", status);
- 		if (status != -ERESTARTSYS)
- 			mlog(ML_ERROR, "Could not lock journal!\n");
- 		goto done;
-@@ -1047,7 +1050,7 @@ static int ocfs2_replay_journal(struct ocfs2_super *osb,
- done:
- 	/* drop the lock on this nodes journal */
- 	if (got_lock)
--		ocfs2_meta_unlock(inode, 1);
-+		ocfs2_inode_unlock(inode, 1);
+-/* PFN start number, because of __MEMORY_START */
++/*
++ * PFN = physical frame number (ie PFN 0 == physical address 0)
++ * PFN_START is the PFN of the first page of RAM. By defining this we
++ * don't have struct page entries for the portion of address space
++ * between physical address 0 and the start of RAM.
++ */
+ #define PFN_START		(__MEMORY_START >> PAGE_SHIFT)
+ #define ARCH_PFN_OFFSET		(PFN_START)
+ #define virt_to_page(kaddr)	pfn_to_page(__pa(kaddr) >> PAGE_SHIFT)
+@@ -154,11 +162,21 @@ typedef struct { unsigned long pgd; } pgd_t;
+ #endif
  
- 	if (inode)
- 		iput(inode);
-@@ -1162,14 +1165,14 @@ static int ocfs2_trylock_journal(struct ocfs2_super *osb,
- 	SET_INODE_JOURNAL(inode);
+ /*
+- * Slub defaults to 8-byte alignment, we're only interested in 4.
+- * Slab defaults to BYTES_PER_WORD, which ends up being the same anyways.
++ * Some drivers need to perform DMA into kmalloc'ed buffers
++ * and so we have to increase the kmalloc minalign for this.
+  */
+-#define ARCH_KMALLOC_MINALIGN	4
+-#define ARCH_SLAB_MINALIGN	4
++#define ARCH_KMALLOC_MINALIGN	L1_CACHE_BYTES
++
++#ifdef CONFIG_SUPERH64
++/*
++ * While BYTES_PER_WORD == 4 on the current sh64 ABI, GCC will still
++ * happily generate {ld/st}.q pairs, requiring us to have 8-byte
++ * alignment to avoid traps. The kmalloc alignment is gauranteed by
++ * virtue of L1_CACHE_BYTES, requiring this to only be special cased
++ * for slab caches.
++ */
++#define ARCH_SLAB_MINALIGN	8
++#endif
  
- 	flags = OCFS2_META_LOCK_RECOVERY | OCFS2_META_LOCK_NOQUEUE;
--	status = ocfs2_meta_lock_full(inode, NULL, 1, flags);
-+	status = ocfs2_inode_lock_full(inode, NULL, 1, flags);
- 	if (status < 0) {
- 		if (status != -EAGAIN)
- 			mlog_errno(status);
- 		goto bail;
- 	}
+ #endif /* __KERNEL__ */
+ #endif /* __ASM_SH_PAGE_H */
+diff --git a/include/asm-sh/param.h b/include/asm-sh/param.h
+index 1012296..ae245af 100644
+--- a/include/asm-sh/param.h
++++ b/include/asm-sh/param.h
+@@ -2,11 +2,7 @@
+ #define __ASM_SH_PARAM_H
  
--	ocfs2_meta_unlock(inode, 1);
-+	ocfs2_inode_unlock(inode, 1);
- bail:
- 	if (inode)
- 		iput(inode);
-@@ -1241,7 +1244,7 @@ static int ocfs2_orphan_filldir(void *priv, const char *name, int name_len,
+ #ifdef __KERNEL__
+-# ifdef CONFIG_SH_WDT
+-#  define HZ		1000		/* Needed for high-res WOVF */
+-# else
+-#  define HZ		CONFIG_HZ
+-# endif
++# define HZ		CONFIG_HZ
+ # define USER_HZ	100		/* User interfaces are in "ticks" */
+ # define CLOCKS_PER_SEC	(USER_HZ)	/* frequency at which times() counts */
+ #endif
+diff --git a/include/asm-sh/pci.h b/include/asm-sh/pci.h
+index 2757ce0..df1d383 100644
+--- a/include/asm-sh/pci.h
++++ b/include/asm-sh/pci.h
+@@ -38,9 +38,12 @@ extern struct pci_channel board_pci_channels[];
+ #if defined(CONFIG_CPU_SUBTYPE_SH7780) || defined(CONFIG_CPU_SUBTYPE_SH7785)
+ #define PCI_IO_AREA		0xFE400000
+ #define PCI_IO_SIZE		0x00400000
++#elif defined(CONFIG_CPU_SH5)
++extern unsigned long PCI_IO_AREA;
++#define PCI_IO_SIZE		0x00010000
+ #else
+ #define PCI_IO_AREA		0xFE240000
+-#define PCI_IO_SIZE		0X00040000
++#define PCI_IO_SIZE		0x00040000
+ #endif
  
- 	/* Skip bad inodes so that recovery can continue */
- 	iter = ocfs2_iget(p->osb, ino,
--			  OCFS2_FI_FLAG_ORPHAN_RECOVERY);
-+			  OCFS2_FI_FLAG_ORPHAN_RECOVERY, 0);
- 	if (IS_ERR(iter))
- 		return 0;
+ #define PCI_MEM_SIZE		0x01000000
+diff --git a/include/asm-sh/pgtable.h b/include/asm-sh/pgtable.h
+index 8f1e8be..a4a8f8b 100644
+--- a/include/asm-sh/pgtable.h
++++ b/include/asm-sh/pgtable.h
+@@ -3,7 +3,7 @@
+  * use the SuperH page table tree.
+  *
+  * Copyright (C) 1999 Niibe Yutaka
+- * Copyright (C) 2002 - 2005 Paul Mundt
++ * Copyright (C) 2002 - 2007 Paul Mundt
+  *
+  * This file is subject to the terms and conditions of the GNU General
+  * Public License.  See the file "COPYING" in the main directory of this
+@@ -29,10 +29,27 @@ extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)];
+ #endif /* !__ASSEMBLY__ */
  
-@@ -1277,7 +1280,7 @@ static int ocfs2_queue_orphans(struct ocfs2_super *osb,
- 	}	
+ /*
++ * Effective and physical address definitions, to aid with sign
++ * extension.
++ */
++#define NEFF		32
++#define	NEFF_SIGN	(1LL << (NEFF - 1))
++#define	NEFF_MASK	(-1LL << NEFF)
++
++#ifdef CONFIG_29BIT
++#define NPHYS		29
++#else
++#define NPHYS		32
++#endif
++
++#define	NPHYS_SIGN	(1LL << (NPHYS - 1))
++#define	NPHYS_MASK	(-1LL << NPHYS)
++
++/*
+  * traditional two-level paging structure
+  */
+ /* PTE bits */
+-#ifdef CONFIG_X2TLB
++#if defined(CONFIG_X2TLB) || defined(CONFIG_SUPERH64)
+ # define PTE_MAGNITUDE	3	/* 64-bit PTEs on extended mode SH-X2 TLB */
+ #else
+ # define PTE_MAGNITUDE	2	/* 32-bit PTEs */
+@@ -52,283 +69,27 @@ extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)];
+ #define USER_PTRS_PER_PGD	(TASK_SIZE/PGDIR_SIZE)
+ #define FIRST_USER_ADDRESS	0
  
- 	mutex_lock(&orphan_dir_inode->i_mutex);
--	status = ocfs2_meta_lock(orphan_dir_inode, NULL, 0);
-+	status = ocfs2_inode_lock(orphan_dir_inode, NULL, 0);
- 	if (status < 0) {
- 		mlog_errno(status);
- 		goto out;
-@@ -1293,7 +1296,7 @@ static int ocfs2_queue_orphans(struct ocfs2_super *osb,
- 	*head = priv.head;
+-#define PTE_PHYS_MASK		(0x20000000 - PAGE_SIZE)
+-
+-#define VMALLOC_START	(P3SEG)
+-#define VMALLOC_END	(FIXADDR_START-2*PAGE_SIZE)
+-
+-/*
+- * Linux PTEL encoding.
+- *
+- * Hardware and software bit definitions for the PTEL value (see below for
+- * notes on SH-X2 MMUs and 64-bit PTEs):
+- *
+- * - Bits 0 and 7 are reserved on SH-3 (_PAGE_WT and _PAGE_SZ1 on SH-4).
+- *
+- * - Bit 1 is the SH-bit, but is unused on SH-3 due to an MMU bug (the
+- *   hardware PTEL value can't have the SH-bit set when MMUCR.IX is set,
+- *   which is the default in cpu-sh3/mmu_context.h:MMU_CONTROL_INIT).
+- *
+- *   In order to keep this relatively clean, do not use these for defining
+- *   SH-3 specific flags until all of the other unused bits have been
+- *   exhausted.
+- *
+- * - Bit 9 is reserved by everyone and used by _PAGE_PROTNONE.
+- *
+- * - Bits 10 and 11 are low bits of the PPN that are reserved on >= 4K pages.
+- *   Bit 10 is used for _PAGE_ACCESSED, bit 11 remains unused.
+- *
+- * - Bits 31, 30, and 29 remain unused by everyone and can be used for future
+- *   software flags, although care must be taken to update _PAGE_CLEAR_FLAGS.
+- *
+- * XXX: Leave the _PAGE_FILE and _PAGE_WT overhaul for a rainy day.
+- *
+- * SH-X2 MMUs and extended PTEs
+- *
+- * SH-X2 supports an extended mode TLB with split data arrays due to the
+- * number of bits needed for PR and SZ (now EPR and ESZ) encodings. The PR and
+- * SZ bit placeholders still exist in data array 1, but are implemented as
+- * reserved bits, with the real logic existing in data array 2.
+- *
+- * The downside to this is that we can no longer fit everything in to a 32-bit
+- * PTE encoding, so a 64-bit pte_t is necessary for these parts. On the plus
+- * side, this gives us quite a few spare bits to play with for future usage.
+- */
+-/* Legacy and compat mode bits */
+-#define	_PAGE_WT	0x001		/* WT-bit on SH-4, 0 on SH-3 */
+-#define _PAGE_HW_SHARED	0x002		/* SH-bit  : shared among processes */
+-#define _PAGE_DIRTY	0x004		/* D-bit   : page changed */
+-#define _PAGE_CACHABLE	0x008		/* C-bit   : cachable */
+-#define _PAGE_SZ0	0x010		/* SZ0-bit : Size of page */
+-#define _PAGE_RW	0x020		/* PR0-bit : write access allowed */
+-#define _PAGE_USER	0x040		/* PR1-bit : user space access allowed*/
+-#define _PAGE_SZ1	0x080		/* SZ1-bit : Size of page (on SH-4) */
+-#define _PAGE_PRESENT	0x100		/* V-bit   : page is valid */
+-#define _PAGE_PROTNONE	0x200		/* software: if not present  */
+-#define _PAGE_ACCESSED	0x400		/* software: page referenced */
+-#define _PAGE_FILE	_PAGE_WT	/* software: pagecache or swap? */
+-
+-#define _PAGE_SZ_MASK	(_PAGE_SZ0 | _PAGE_SZ1)
+-#define _PAGE_PR_MASK	(_PAGE_RW | _PAGE_USER)
+-
+-/* Extended mode bits */
+-#define _PAGE_EXT_ESZ0		0x0010	/* ESZ0-bit: Size of page */
+-#define _PAGE_EXT_ESZ1		0x0020	/* ESZ1-bit: Size of page */
+-#define _PAGE_EXT_ESZ2		0x0040	/* ESZ2-bit: Size of page */
+-#define _PAGE_EXT_ESZ3		0x0080	/* ESZ3-bit: Size of page */
+-
+-#define _PAGE_EXT_USER_EXEC	0x0100	/* EPR0-bit: User space executable */
+-#define _PAGE_EXT_USER_WRITE	0x0200	/* EPR1-bit: User space writable */
+-#define _PAGE_EXT_USER_READ	0x0400	/* EPR2-bit: User space readable */
+-
+-#define _PAGE_EXT_KERN_EXEC	0x0800	/* EPR3-bit: Kernel space executable */
+-#define _PAGE_EXT_KERN_WRITE	0x1000	/* EPR4-bit: Kernel space writable */
+-#define _PAGE_EXT_KERN_READ	0x2000	/* EPR5-bit: Kernel space readable */
+-
+-/* Wrapper for extended mode pgprot twiddling */
+-#define _PAGE_EXT(x)		((unsigned long long)(x) << 32)
+-
+-/* software: moves to PTEA.TC (Timing Control) */
+-#define _PAGE_PCC_AREA5	0x00000000	/* use BSC registers for area5 */
+-#define _PAGE_PCC_AREA6	0x80000000	/* use BSC registers for area6 */
+-
+-/* software: moves to PTEA.SA[2:0] (Space Attributes) */
+-#define _PAGE_PCC_IODYN 0x00000001	/* IO space, dynamically sized bus */
+-#define _PAGE_PCC_IO8	0x20000000	/* IO space, 8 bit bus */
+-#define _PAGE_PCC_IO16	0x20000001	/* IO space, 16 bit bus */
+-#define _PAGE_PCC_COM8	0x40000000	/* Common Memory space, 8 bit bus */
+-#define _PAGE_PCC_COM16	0x40000001	/* Common Memory space, 16 bit bus */
+-#define _PAGE_PCC_ATR8	0x60000000	/* Attribute Memory space, 8 bit bus */
+-#define _PAGE_PCC_ATR16	0x60000001	/* Attribute Memory space, 6 bit bus */
+-
+-/* Mask which drops unused bits from the PTEL value */
+-#if defined(CONFIG_CPU_SH3)
+-#define _PAGE_CLEAR_FLAGS	(_PAGE_PROTNONE | _PAGE_ACCESSED| \
+-				 _PAGE_FILE	| _PAGE_SZ1	| \
+-				 _PAGE_HW_SHARED)
+-#elif defined(CONFIG_X2TLB)
+-/* Get rid of the legacy PR/SZ bits when using extended mode */
+-#define _PAGE_CLEAR_FLAGS	(_PAGE_PROTNONE | _PAGE_ACCESSED | \
+-				 _PAGE_FILE | _PAGE_PR_MASK | _PAGE_SZ_MASK)
++#ifdef CONFIG_32BIT
++#define PHYS_ADDR_MASK		0xffffffff
+ #else
+-#define _PAGE_CLEAR_FLAGS	(_PAGE_PROTNONE | _PAGE_ACCESSED | _PAGE_FILE)
++#define PHYS_ADDR_MASK		0x1fffffff
+ #endif
  
- out_cluster:
--	ocfs2_meta_unlock(orphan_dir_inode, 0);
-+	ocfs2_inode_unlock(orphan_dir_inode, 0);
- out:
- 	mutex_unlock(&orphan_dir_inode->i_mutex);
- 	iput(orphan_dir_inode);
-@@ -1380,10 +1383,10 @@ static int ocfs2_recover_orphans(struct ocfs2_super *osb,
- 		iter = oi->ip_next_orphan;
+-#define _PAGE_FLAGS_HARDWARE_MASK	(0x1fffffff & ~(_PAGE_CLEAR_FLAGS))
++#define PTE_PHYS_MASK		(PHYS_ADDR_MASK & PAGE_MASK)
  
- 		spin_lock(&oi->ip_lock);
--		/* Delete voting may have set these on the assumption
--		 * that the other node would wipe them successfully.
--		 * If they are still in the node's orphan dir, we need
--		 * to reset that state. */
-+		/* The remote delete code may have set these on the
-+		 * assumption that the other node would wipe them
-+		 * successfully.  If they are still in the node's
-+		 * orphan dir, we need to reset that state. */
- 		oi->ip_flags &= ~(OCFS2_INODE_DELETED|OCFS2_INODE_SKIP_DELETE);
+-/* Hardware flags, page size encoding */
+-#if defined(CONFIG_X2TLB)
+-# if defined(CONFIG_PAGE_SIZE_4KB)
+-#  define _PAGE_FLAGS_HARD	_PAGE_EXT(_PAGE_EXT_ESZ0)
+-# elif defined(CONFIG_PAGE_SIZE_8KB)
+-#  define _PAGE_FLAGS_HARD	_PAGE_EXT(_PAGE_EXT_ESZ1)
+-# elif defined(CONFIG_PAGE_SIZE_64KB)
+-#  define _PAGE_FLAGS_HARD	_PAGE_EXT(_PAGE_EXT_ESZ2)
+-# endif
++#ifdef CONFIG_SUPERH32
++#define VMALLOC_START	(P3SEG)
+ #else
+-# if defined(CONFIG_PAGE_SIZE_4KB)
+-#  define _PAGE_FLAGS_HARD	_PAGE_SZ0
+-# elif defined(CONFIG_PAGE_SIZE_64KB)
+-#  define _PAGE_FLAGS_HARD	_PAGE_SZ1
+-# endif
++#define VMALLOC_START	(0xf0000000)
+ #endif
++#define VMALLOC_END	(FIXADDR_START-2*PAGE_SIZE)
  
- 		/* Set the proper information to get us going into
-diff --git a/fs/ocfs2/journal.h b/fs/ocfs2/journal.h
-index 4b32e09..220f3e8 100644
---- a/fs/ocfs2/journal.h
-+++ b/fs/ocfs2/journal.h
-@@ -278,6 +278,12 @@ int                  ocfs2_journal_dirty_data(handle_t *handle,
- /* simple file updates like chmod, etc. */
- #define OCFS2_INODE_UPDATE_CREDITS 1
+-#if defined(CONFIG_X2TLB)
+-# if defined(CONFIG_HUGETLB_PAGE_SIZE_64K)
+-#  define _PAGE_SZHUGE	(_PAGE_EXT_ESZ2)
+-# elif defined(CONFIG_HUGETLB_PAGE_SIZE_256K)
+-#  define _PAGE_SZHUGE	(_PAGE_EXT_ESZ0 | _PAGE_EXT_ESZ2)
+-# elif defined(CONFIG_HUGETLB_PAGE_SIZE_1MB)
+-#  define _PAGE_SZHUGE	(_PAGE_EXT_ESZ0 | _PAGE_EXT_ESZ1 | _PAGE_EXT_ESZ2)
+-# elif defined(CONFIG_HUGETLB_PAGE_SIZE_4MB)
+-#  define _PAGE_SZHUGE	(_PAGE_EXT_ESZ3)
+-# elif defined(CONFIG_HUGETLB_PAGE_SIZE_64MB)
+-#  define _PAGE_SZHUGE	(_PAGE_EXT_ESZ2 | _PAGE_EXT_ESZ3)
+-# endif
++#if defined(CONFIG_SUPERH32)
++#include <asm/pgtable_32.h>
+ #else
+-# if defined(CONFIG_HUGETLB_PAGE_SIZE_64K)
+-#  define _PAGE_SZHUGE	(_PAGE_SZ1)
+-# elif defined(CONFIG_HUGETLB_PAGE_SIZE_1MB)
+-#  define _PAGE_SZHUGE	(_PAGE_SZ0 | _PAGE_SZ1)
+-# endif
+-#endif
+-
+-/*
+- * Stub out _PAGE_SZHUGE if we don't have a good definition for it,
+- * to make pte_mkhuge() happy.
+- */
+-#ifndef _PAGE_SZHUGE
+-# define _PAGE_SZHUGE	(_PAGE_FLAGS_HARD)
+-#endif
+-
+-#define _PAGE_CHG_MASK \
+-	(PTE_MASK | _PAGE_ACCESSED | _PAGE_CACHABLE | _PAGE_DIRTY)
+-
+-#ifndef __ASSEMBLY__
+-
+-#if defined(CONFIG_X2TLB) /* SH-X2 TLB */
+-#define PAGE_NONE	__pgprot(_PAGE_PROTNONE | _PAGE_CACHABLE | \
+-				 _PAGE_ACCESSED | _PAGE_FLAGS_HARD)
+-
+-#define PAGE_SHARED	__pgprot(_PAGE_PRESENT | _PAGE_ACCESSED | \
+-				 _PAGE_CACHABLE | _PAGE_FLAGS_HARD | \
+-				 _PAGE_EXT(_PAGE_EXT_KERN_READ  | \
+-					   _PAGE_EXT_KERN_WRITE | \
+-					   _PAGE_EXT_USER_READ  | \
+-					   _PAGE_EXT_USER_WRITE))
+-
+-#define PAGE_EXECREAD	__pgprot(_PAGE_PRESENT | _PAGE_ACCESSED | \
+-				 _PAGE_CACHABLE | _PAGE_FLAGS_HARD | \
+-				 _PAGE_EXT(_PAGE_EXT_KERN_EXEC | \
+-					   _PAGE_EXT_KERN_READ | \
+-					   _PAGE_EXT_USER_EXEC | \
+-					   _PAGE_EXT_USER_READ))
+-
+-#define PAGE_COPY	PAGE_EXECREAD
+-
+-#define PAGE_READONLY	__pgprot(_PAGE_PRESENT | _PAGE_ACCESSED | \
+-				 _PAGE_CACHABLE | _PAGE_FLAGS_HARD | \
+-				 _PAGE_EXT(_PAGE_EXT_KERN_READ | \
+-					   _PAGE_EXT_USER_READ))
+-
+-#define PAGE_WRITEONLY	__pgprot(_PAGE_PRESENT | _PAGE_ACCESSED | \
+-				 _PAGE_CACHABLE | _PAGE_FLAGS_HARD | \
+-				 _PAGE_EXT(_PAGE_EXT_KERN_WRITE | \
+-					   _PAGE_EXT_USER_WRITE))
+-
+-#define PAGE_RWX	__pgprot(_PAGE_PRESENT | _PAGE_ACCESSED | \
+-				 _PAGE_CACHABLE | _PAGE_FLAGS_HARD | \
+-				 _PAGE_EXT(_PAGE_EXT_KERN_WRITE | \
+-					   _PAGE_EXT_KERN_READ  | \
+-					   _PAGE_EXT_KERN_EXEC  | \
+-					   _PAGE_EXT_USER_WRITE | \
+-					   _PAGE_EXT_USER_READ  | \
+-					   _PAGE_EXT_USER_EXEC))
+-
+-#define PAGE_KERNEL	__pgprot(_PAGE_PRESENT | _PAGE_CACHABLE | \
+-				 _PAGE_DIRTY | _PAGE_ACCESSED | \
+-				 _PAGE_HW_SHARED | _PAGE_FLAGS_HARD | \
+-				 _PAGE_EXT(_PAGE_EXT_KERN_READ | \
+-					   _PAGE_EXT_KERN_WRITE | \
+-					   _PAGE_EXT_KERN_EXEC))
+-
+-#define PAGE_KERNEL_NOCACHE \
+-			__pgprot(_PAGE_PRESENT | _PAGE_DIRTY | \
+-				 _PAGE_ACCESSED | _PAGE_HW_SHARED | \
+-				 _PAGE_FLAGS_HARD | \
+-				 _PAGE_EXT(_PAGE_EXT_KERN_READ | \
+-					   _PAGE_EXT_KERN_WRITE | \
+-					   _PAGE_EXT_KERN_EXEC))
+-
+-#define PAGE_KERNEL_RO	__pgprot(_PAGE_PRESENT | _PAGE_CACHABLE | \
+-				 _PAGE_DIRTY | _PAGE_ACCESSED | \
+-				 _PAGE_HW_SHARED | _PAGE_FLAGS_HARD | \
+-				 _PAGE_EXT(_PAGE_EXT_KERN_READ | \
+-					   _PAGE_EXT_KERN_EXEC))
+-
+-#define PAGE_KERNEL_PCC(slot, type) \
+-			__pgprot(_PAGE_PRESENT | _PAGE_DIRTY | \
+-				 _PAGE_ACCESSED | _PAGE_FLAGS_HARD | \
+-				 _PAGE_EXT(_PAGE_EXT_KERN_READ | \
+-					   _PAGE_EXT_KERN_WRITE | \
+-					   _PAGE_EXT_KERN_EXEC) \
+-				 (slot ? _PAGE_PCC_AREA5 : _PAGE_PCC_AREA6) | \
+-				 (type))
+-
+-#elif defined(CONFIG_MMU) /* SH-X TLB */
+-#define PAGE_NONE	__pgprot(_PAGE_PROTNONE | _PAGE_CACHABLE | \
+-				 _PAGE_ACCESSED | _PAGE_FLAGS_HARD)
+-
+-#define PAGE_SHARED	__pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | \
+-				 _PAGE_CACHABLE | _PAGE_ACCESSED | \
+-				 _PAGE_FLAGS_HARD)
+-
+-#define PAGE_COPY	__pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_CACHABLE | \
+-				 _PAGE_ACCESSED | _PAGE_FLAGS_HARD)
+-
+-#define PAGE_READONLY	__pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_CACHABLE | \
+-				 _PAGE_ACCESSED | _PAGE_FLAGS_HARD)
+-
+-#define PAGE_EXECREAD	PAGE_READONLY
+-#define PAGE_RWX	PAGE_SHARED
+-#define PAGE_WRITEONLY	PAGE_SHARED
+-
+-#define PAGE_KERNEL	__pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_CACHABLE | \
+-				 _PAGE_DIRTY | _PAGE_ACCESSED | \
+-				 _PAGE_HW_SHARED | _PAGE_FLAGS_HARD)
+-
+-#define PAGE_KERNEL_NOCACHE \
+-			__pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | \
+-				 _PAGE_ACCESSED | _PAGE_HW_SHARED | \
+-				 _PAGE_FLAGS_HARD)
+-
+-#define PAGE_KERNEL_RO	__pgprot(_PAGE_PRESENT | _PAGE_CACHABLE | \
+-				 _PAGE_DIRTY | _PAGE_ACCESSED | \
+-				 _PAGE_HW_SHARED | _PAGE_FLAGS_HARD)
+-
+-#define PAGE_KERNEL_PCC(slot, type) \
+-			__pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | \
+-				 _PAGE_ACCESSED | _PAGE_FLAGS_HARD | \
+-				 (slot ? _PAGE_PCC_AREA5 : _PAGE_PCC_AREA6) | \
+-				 (type))
+-#else /* no mmu */
+-#define PAGE_NONE		__pgprot(0)
+-#define PAGE_SHARED		__pgprot(0)
+-#define PAGE_COPY		__pgprot(0)
+-#define PAGE_EXECREAD		__pgprot(0)
+-#define PAGE_RWX		__pgprot(0)
+-#define PAGE_READONLY		__pgprot(0)
+-#define PAGE_WRITEONLY		__pgprot(0)
+-#define PAGE_KERNEL		__pgprot(0)
+-#define PAGE_KERNEL_NOCACHE	__pgprot(0)
+-#define PAGE_KERNEL_RO		__pgprot(0)
+-
+-#define PAGE_KERNEL_PCC(slot, type) \
+-				__pgprot(0)
++#include <asm/pgtable_64.h>
+ #endif
  
-+/* group extend. inode update and last group update. */
-+#define OCFS2_GROUP_EXTEND_CREDITS	(OCFS2_INODE_UPDATE_CREDITS + 1)
+-#endif /* __ASSEMBLY__ */
+-
+ /*
+  * SH-X and lower (legacy) SuperH parts (SH-3, SH-4, some SH-4A) can't do page
+  * protection for execute, and considers it the same as a read. Also, write
+@@ -357,208 +118,6 @@ extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)];
+ #define __S110	PAGE_RWX
+ #define __S111	PAGE_RWX
+ 
+-#ifndef __ASSEMBLY__
+-
+-/*
+- * Certain architectures need to do special things when PTEs
+- * within a page table are directly modified.  Thus, the following
+- * hook is made available.
+- */
+-#ifdef CONFIG_X2TLB
+-static inline void set_pte(pte_t *ptep, pte_t pte)
+-{
+-	ptep->pte_high = pte.pte_high;
+-	smp_wmb();
+-	ptep->pte_low = pte.pte_low;
+-}
+-#else
+-#define set_pte(pteptr, pteval) (*(pteptr) = pteval)
+-#endif
+-
+-#define set_pte_at(mm,addr,ptep,pteval) set_pte(ptep,pteval)
+-
+-/*
+- * (pmds are folded into pgds so this doesn't get actually called,
+- * but the define is needed for a generic inline function.)
+- */
+-#define set_pmd(pmdptr, pmdval) (*(pmdptr) = pmdval)
+-
+-#define pte_pfn(x)		((unsigned long)(((x).pte_low >> PAGE_SHIFT)))
+-
+-#define pfn_pte(pfn, prot) \
+-	__pte(((unsigned long long)(pfn) << PAGE_SHIFT) | pgprot_val(prot))
+-#define pfn_pmd(pfn, prot) \
+-	__pmd(((unsigned long long)(pfn) << PAGE_SHIFT) | pgprot_val(prot))
+-
+-#define pte_none(x)		(!pte_val(x))
+-#define pte_present(x)		((x).pte_low & (_PAGE_PRESENT | _PAGE_PROTNONE))
+-
+-#define pte_clear(mm,addr,xp) do { set_pte_at(mm, addr, xp, __pte(0)); } while (0)
+-
+-#define pmd_none(x)	(!pmd_val(x))
+-#define pmd_present(x)	(pmd_val(x))
+-#define pmd_clear(xp)	do { set_pmd(xp, __pmd(0)); } while (0)
+-#define	pmd_bad(x)	(pmd_val(x) & ~PAGE_MASK)
+-
+-#define pages_to_mb(x)	((x) >> (20-PAGE_SHIFT))
+-#define pte_page(x)	pfn_to_page(pte_pfn(x))
+-
+-/*
+- * The following only work if pte_present() is true.
+- * Undefined behaviour if not..
+- */
+-#define pte_not_present(pte)	(!((pte).pte_low & _PAGE_PRESENT))
+-#define pte_dirty(pte)		((pte).pte_low & _PAGE_DIRTY)
+-#define pte_young(pte)		((pte).pte_low & _PAGE_ACCESSED)
+-#define pte_file(pte)		((pte).pte_low & _PAGE_FILE)
+-
+-#ifdef CONFIG_X2TLB
+-#define pte_write(pte)		((pte).pte_high & _PAGE_EXT_USER_WRITE)
+-#else
+-#define pte_write(pte)		((pte).pte_low & _PAGE_RW)
+-#endif
+-
+-#define PTE_BIT_FUNC(h,fn,op) \
+-static inline pte_t pte_##fn(pte_t pte) { pte.pte_##h op; return pte; }
+-
+-#ifdef CONFIG_X2TLB
+-/*
+- * We cheat a bit in the SH-X2 TLB case. As the permission bits are
+- * individually toggled (and user permissions are entirely decoupled from
+- * kernel permissions), we attempt to couple them a bit more sanely here.
+- */
+-PTE_BIT_FUNC(high, wrprotect, &= ~_PAGE_EXT_USER_WRITE);
+-PTE_BIT_FUNC(high, mkwrite, |= _PAGE_EXT_USER_WRITE | _PAGE_EXT_KERN_WRITE);
+-PTE_BIT_FUNC(high, mkhuge, |= _PAGE_SZHUGE);
+-#else
+-PTE_BIT_FUNC(low, wrprotect, &= ~_PAGE_RW);
+-PTE_BIT_FUNC(low, mkwrite, |= _PAGE_RW);
+-PTE_BIT_FUNC(low, mkhuge, |= _PAGE_SZHUGE);
+-#endif
+-
+-PTE_BIT_FUNC(low, mkclean, &= ~_PAGE_DIRTY);
+-PTE_BIT_FUNC(low, mkdirty, |= _PAGE_DIRTY);
+-PTE_BIT_FUNC(low, mkold, &= ~_PAGE_ACCESSED);
+-PTE_BIT_FUNC(low, mkyoung, |= _PAGE_ACCESSED);
+-
+-/*
+- * Macro and implementation to make a page protection as uncachable.
+- */
+-#define pgprot_writecombine(prot) \
+-	__pgprot(pgprot_val(prot) & ~_PAGE_CACHABLE)
+-
+-#define pgprot_noncached	 pgprot_writecombine
+-
+-/*
+- * Conversion functions: convert a page and protection to a page entry,
+- * and a page entry and page directory to the page they refer to.
+- *
+- * extern pte_t mk_pte(struct page *page, pgprot_t pgprot)
+- */
+-#define mk_pte(page, pgprot)	pfn_pte(page_to_pfn(page), (pgprot))
+-
+-static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
+-{
+-	pte.pte_low &= _PAGE_CHG_MASK;
+-	pte.pte_low |= pgprot_val(newprot);
+-
+-#ifdef CONFIG_X2TLB
+-	pte.pte_high |= pgprot_val(newprot) >> 32;
+-#endif
+-
+-	return pte;
+-}
+-
+-#define pmd_page_vaddr(pmd)	((unsigned long)pmd_val(pmd))
+-#define pmd_page(pmd)		(virt_to_page(pmd_val(pmd)))
+-
+-/* to find an entry in a page-table-directory. */
+-#define pgd_index(address)	(((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD-1))
+-#define pgd_offset(mm, address)	((mm)->pgd+pgd_index(address))
+-
+-/* to find an entry in a kernel page-table-directory */
+-#define pgd_offset_k(address)	pgd_offset(&init_mm, address)
+-
+-/* Find an entry in the third-level page table.. */
+-#define pte_index(address)	((address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
+-#define pte_offset_kernel(dir, address) \
+-	((pte_t *) pmd_page_vaddr(*(dir)) + pte_index(address))
+-#define pte_offset_map(dir, address)		pte_offset_kernel(dir, address)
+-#define pte_offset_map_nested(dir, address)	pte_offset_kernel(dir, address)
+-
+-#define pte_unmap(pte)		do { } while (0)
+-#define pte_unmap_nested(pte)	do { } while (0)
+-
+-#ifdef CONFIG_X2TLB
+-#define pte_ERROR(e) \
+-	printk("%s:%d: bad pte %p(%08lx%08lx).\n", __FILE__, __LINE__, \
+-	       &(e), (e).pte_high, (e).pte_low)
+-#define pgd_ERROR(e) \
+-	printk("%s:%d: bad pgd %016llx.\n", __FILE__, __LINE__, pgd_val(e))
+-#else
+-#define pte_ERROR(e) \
+-	printk("%s:%d: bad pte %08lx.\n", __FILE__, __LINE__, pte_val(e))
+-#define pgd_ERROR(e) \
+-	printk("%s:%d: bad pgd %08lx.\n", __FILE__, __LINE__, pgd_val(e))
+-#endif
+-
+-struct vm_area_struct;
+-extern void update_mmu_cache(struct vm_area_struct * vma,
+-			     unsigned long address, pte_t pte);
+-
+-/*
+- * Encode and de-code a swap entry
+- *
+- * Constraints:
+- *	_PAGE_FILE at bit 0
+- *	_PAGE_PRESENT at bit 8
+- *	_PAGE_PROTNONE at bit 9
+- *
+- * For the normal case, we encode the swap type into bits 0:7 and the
+- * swap offset into bits 10:30. For the 64-bit PTE case, we keep the
+- * preserved bits in the low 32-bits and use the upper 32 as the swap
+- * offset (along with a 5-bit type), following the same approach as x86
+- * PAE. This keeps the logic quite simple, and allows for a full 32
+- * PTE_FILE_MAX_BITS, as opposed to the 29-bits we're constrained with
+- * in the pte_low case.
+- *
+- * As is evident by the Alpha code, if we ever get a 64-bit unsigned
+- * long (swp_entry_t) to match up with the 64-bit PTEs, this all becomes
+- * much cleaner..
+- *
+- * NOTE: We should set ZEROs at the position of _PAGE_PRESENT
+- *       and _PAGE_PROTNONE bits
+- */
+-#ifdef CONFIG_X2TLB
+-#define __swp_type(x)			((x).val & 0x1f)
+-#define __swp_offset(x)			((x).val >> 5)
+-#define __swp_entry(type, offset)	((swp_entry_t){ (type) | (offset) << 5})
+-#define __pte_to_swp_entry(pte)		((swp_entry_t){ (pte).pte_high })
+-#define __swp_entry_to_pte(x)		((pte_t){ 0, (x).val })
+-
+-/*
+- * Encode and decode a nonlinear file mapping entry
+- */
+-#define pte_to_pgoff(pte)		((pte).pte_high)
+-#define pgoff_to_pte(off)		((pte_t) { _PAGE_FILE, (off) })
+-
+-#define PTE_FILE_MAX_BITS		32
+-#else
+-#define __swp_type(x)			((x).val & 0xff)
+-#define __swp_offset(x)			((x).val >> 10)
+-#define __swp_entry(type, offset)	((swp_entry_t){(type) | (offset) <<10})
+-
+-#define __pte_to_swp_entry(pte)		((swp_entry_t) { pte_val(pte) >> 1 })
+-#define __swp_entry_to_pte(x)		((pte_t) { (x).val << 1 })
+-
+-/*
+- * Encode and decode a nonlinear file mapping entry
+- */
+-#define PTE_FILE_MAX_BITS	29
+-#define pte_to_pgoff(pte)	(pte_val(pte) >> 1)
+-#define pgoff_to_pte(off)	((pte_t) { ((off) << 1) | _PAGE_FILE })
+-#endif
+-
+ typedef pte_t *pte_addr_t;
+ 
+ #define kern_addr_valid(addr)	(1)
+@@ -566,27 +125,28 @@ typedef pte_t *pte_addr_t;
+ #define io_remap_pfn_range(vma, vaddr, pfn, size, prot)		\
+ 		remap_pfn_range(vma, vaddr, pfn, size, prot)
+ 
+-struct mm_struct;
++#define pte_pfn(x)		((unsigned long)(((x).pte_low >> PAGE_SHIFT)))
+ 
+ /*
+  * No page table caches to initialise
+  */
+ #define pgtable_cache_init()	do { } while (0)
+ 
+-#ifndef CONFIG_MMU
+-extern unsigned int kobjsize(const void *objp);
+-#endif /* !CONFIG_MMU */
+-
+ #if !defined(CONFIG_CACHE_OFF) && (defined(CONFIG_CPU_SH4) || \
+ 	defined(CONFIG_SH7705_CACHE_32KB))
++struct mm_struct;
+ #define __HAVE_ARCH_PTEP_GET_AND_CLEAR
+-extern pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep);
++pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep);
+ #endif
+ 
++struct vm_area_struct;
++extern void update_mmu_cache(struct vm_area_struct * vma,
++			     unsigned long address, pte_t pte);
+ extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
+ extern void paging_init(void);
++extern void page_table_range_init(unsigned long start, unsigned long end,
++				  pgd_t *pgd);
+ 
+ #include <asm-generic/pgtable.h>
+ 
+-#endif /* !__ASSEMBLY__ */
+-#endif /* __ASM_SH_PAGE_H */
++#endif /* __ASM_SH_PGTABLE_H */
+diff --git a/include/asm-sh/pgtable_32.h b/include/asm-sh/pgtable_32.h
+new file mode 100644
+index 0000000..3e3557c
+--- /dev/null
++++ b/include/asm-sh/pgtable_32.h
+@@ -0,0 +1,474 @@
++#ifndef __ASM_SH_PGTABLE_32_H
++#define __ASM_SH_PGTABLE_32_H
++
++/*
++ * Linux PTEL encoding.
++ *
++ * Hardware and software bit definitions for the PTEL value (see below for
++ * notes on SH-X2 MMUs and 64-bit PTEs):
++ *
++ * - Bits 0 and 7 are reserved on SH-3 (_PAGE_WT and _PAGE_SZ1 on SH-4).
++ *
++ * - Bit 1 is the SH-bit, but is unused on SH-3 due to an MMU bug (the
++ *   hardware PTEL value can't have the SH-bit set when MMUCR.IX is set,
++ *   which is the default in cpu-sh3/mmu_context.h:MMU_CONTROL_INIT).
++ *
++ *   In order to keep this relatively clean, do not use these for defining
++ *   SH-3 specific flags until all of the other unused bits have been
++ *   exhausted.
++ *
++ * - Bit 9 is reserved by everyone and used by _PAGE_PROTNONE.
++ *
++ * - Bits 10 and 11 are low bits of the PPN that are reserved on >= 4K pages.
++ *   Bit 10 is used for _PAGE_ACCESSED, bit 11 remains unused.
++ *
++ * - On 29 bit platforms, bits 31 to 29 are used for the space attributes
++ *   and timing control which (together with bit 0) are moved into the
++ *   old-style PTEA on the parts that support it.
++ *
++ * XXX: Leave the _PAGE_FILE and _PAGE_WT overhaul for a rainy day.
++ *
++ * SH-X2 MMUs and extended PTEs
++ *
++ * SH-X2 supports an extended mode TLB with split data arrays due to the
++ * number of bits needed for PR and SZ (now EPR and ESZ) encodings. The PR and
++ * SZ bit placeholders still exist in data array 1, but are implemented as
++ * reserved bits, with the real logic existing in data array 2.
++ *
++ * The downside to this is that we can no longer fit everything in to a 32-bit
++ * PTE encoding, so a 64-bit pte_t is necessary for these parts. On the plus
++ * side, this gives us quite a few spare bits to play with for future usage.
++ */
++/* Legacy and compat mode bits */
++#define	_PAGE_WT	0x001		/* WT-bit on SH-4, 0 on SH-3 */
++#define _PAGE_HW_SHARED	0x002		/* SH-bit  : shared among processes */
++#define _PAGE_DIRTY	0x004		/* D-bit   : page changed */
++#define _PAGE_CACHABLE	0x008		/* C-bit   : cachable */
++#define _PAGE_SZ0	0x010		/* SZ0-bit : Size of page */
++#define _PAGE_RW	0x020		/* PR0-bit : write access allowed */
++#define _PAGE_USER	0x040		/* PR1-bit : user space access allowed*/
++#define _PAGE_SZ1	0x080		/* SZ1-bit : Size of page (on SH-4) */
++#define _PAGE_PRESENT	0x100		/* V-bit   : page is valid */
++#define _PAGE_PROTNONE	0x200		/* software: if not present  */
++#define _PAGE_ACCESSED	0x400		/* software: page referenced */
++#define _PAGE_FILE	_PAGE_WT	/* software: pagecache or swap? */
++
++#define _PAGE_SZ_MASK	(_PAGE_SZ0 | _PAGE_SZ1)
++#define _PAGE_PR_MASK	(_PAGE_RW | _PAGE_USER)
++
++/* Extended mode bits */
++#define _PAGE_EXT_ESZ0		0x0010	/* ESZ0-bit: Size of page */
++#define _PAGE_EXT_ESZ1		0x0020	/* ESZ1-bit: Size of page */
++#define _PAGE_EXT_ESZ2		0x0040	/* ESZ2-bit: Size of page */
++#define _PAGE_EXT_ESZ3		0x0080	/* ESZ3-bit: Size of page */
++
++#define _PAGE_EXT_USER_EXEC	0x0100	/* EPR0-bit: User space executable */
++#define _PAGE_EXT_USER_WRITE	0x0200	/* EPR1-bit: User space writable */
++#define _PAGE_EXT_USER_READ	0x0400	/* EPR2-bit: User space readable */
++
++#define _PAGE_EXT_KERN_EXEC	0x0800	/* EPR3-bit: Kernel space executable */
++#define _PAGE_EXT_KERN_WRITE	0x1000	/* EPR4-bit: Kernel space writable */
++#define _PAGE_EXT_KERN_READ	0x2000	/* EPR5-bit: Kernel space readable */
++
++/* Wrapper for extended mode pgprot twiddling */
++#define _PAGE_EXT(x)		((unsigned long long)(x) << 32)
++
++/* software: moves to PTEA.TC (Timing Control) */
++#define _PAGE_PCC_AREA5	0x00000000	/* use BSC registers for area5 */
++#define _PAGE_PCC_AREA6	0x80000000	/* use BSC registers for area6 */
++
++/* software: moves to PTEA.SA[2:0] (Space Attributes) */
++#define _PAGE_PCC_IODYN 0x00000001	/* IO space, dynamically sized bus */
++#define _PAGE_PCC_IO8	0x20000000	/* IO space, 8 bit bus */
++#define _PAGE_PCC_IO16	0x20000001	/* IO space, 16 bit bus */
++#define _PAGE_PCC_COM8	0x40000000	/* Common Memory space, 8 bit bus */
++#define _PAGE_PCC_COM16	0x40000001	/* Common Memory space, 16 bit bus */
++#define _PAGE_PCC_ATR8	0x60000000	/* Attribute Memory space, 8 bit bus */
++#define _PAGE_PCC_ATR16	0x60000001	/* Attribute Memory space, 6 bit bus */
++
++/* Mask which drops unused bits from the PTEL value */
++#if defined(CONFIG_CPU_SH3)
++#define _PAGE_CLEAR_FLAGS	(_PAGE_PROTNONE | _PAGE_ACCESSED| \
++				 _PAGE_FILE	| _PAGE_SZ1	| \
++				 _PAGE_HW_SHARED)
++#elif defined(CONFIG_X2TLB)
++/* Get rid of the legacy PR/SZ bits when using extended mode */
++#define _PAGE_CLEAR_FLAGS	(_PAGE_PROTNONE | _PAGE_ACCESSED | \
++				 _PAGE_FILE | _PAGE_PR_MASK | _PAGE_SZ_MASK)
++#else
++#define _PAGE_CLEAR_FLAGS	(_PAGE_PROTNONE | _PAGE_ACCESSED | _PAGE_FILE)
++#endif
++
++#define _PAGE_FLAGS_HARDWARE_MASK	(PHYS_ADDR_MASK & ~(_PAGE_CLEAR_FLAGS))
++
++/* Hardware flags, page size encoding */
++#if defined(CONFIG_X2TLB)
++# if defined(CONFIG_PAGE_SIZE_4KB)
++#  define _PAGE_FLAGS_HARD	_PAGE_EXT(_PAGE_EXT_ESZ0)
++# elif defined(CONFIG_PAGE_SIZE_8KB)
++#  define _PAGE_FLAGS_HARD	_PAGE_EXT(_PAGE_EXT_ESZ1)
++# elif defined(CONFIG_PAGE_SIZE_64KB)
++#  define _PAGE_FLAGS_HARD	_PAGE_EXT(_PAGE_EXT_ESZ2)
++# endif
++#else
++# if defined(CONFIG_PAGE_SIZE_4KB)
++#  define _PAGE_FLAGS_HARD	_PAGE_SZ0
++# elif defined(CONFIG_PAGE_SIZE_64KB)
++#  define _PAGE_FLAGS_HARD	_PAGE_SZ1
++# endif
++#endif
++
++#if defined(CONFIG_X2TLB)
++# if defined(CONFIG_HUGETLB_PAGE_SIZE_64K)
++#  define _PAGE_SZHUGE	(_PAGE_EXT_ESZ2)
++# elif defined(CONFIG_HUGETLB_PAGE_SIZE_256K)
++#  define _PAGE_SZHUGE	(_PAGE_EXT_ESZ0 | _PAGE_EXT_ESZ2)
++# elif defined(CONFIG_HUGETLB_PAGE_SIZE_1MB)
++#  define _PAGE_SZHUGE	(_PAGE_EXT_ESZ0 | _PAGE_EXT_ESZ1 | _PAGE_EXT_ESZ2)
++# elif defined(CONFIG_HUGETLB_PAGE_SIZE_4MB)
++#  define _PAGE_SZHUGE	(_PAGE_EXT_ESZ3)
++# elif defined(CONFIG_HUGETLB_PAGE_SIZE_64MB)
++#  define _PAGE_SZHUGE	(_PAGE_EXT_ESZ2 | _PAGE_EXT_ESZ3)
++# endif
++#else
++# if defined(CONFIG_HUGETLB_PAGE_SIZE_64K)
++#  define _PAGE_SZHUGE	(_PAGE_SZ1)
++# elif defined(CONFIG_HUGETLB_PAGE_SIZE_1MB)
++#  define _PAGE_SZHUGE	(_PAGE_SZ0 | _PAGE_SZ1)
++# endif
++#endif
++
++/*
++ * Stub out _PAGE_SZHUGE if we don't have a good definition for it,
++ * to make pte_mkhuge() happy.
++ */
++#ifndef _PAGE_SZHUGE
++# define _PAGE_SZHUGE	(_PAGE_FLAGS_HARD)
++#endif
++
++#define _PAGE_CHG_MASK \
++	(PTE_MASK | _PAGE_ACCESSED | _PAGE_CACHABLE | _PAGE_DIRTY)
++
++#ifndef __ASSEMBLY__
++
++#if defined(CONFIG_X2TLB) /* SH-X2 TLB */
++#define PAGE_NONE	__pgprot(_PAGE_PROTNONE | _PAGE_CACHABLE | \
++				 _PAGE_ACCESSED | _PAGE_FLAGS_HARD)
++
++#define PAGE_SHARED	__pgprot(_PAGE_PRESENT | _PAGE_ACCESSED | \
++				 _PAGE_CACHABLE | _PAGE_FLAGS_HARD | \
++				 _PAGE_EXT(_PAGE_EXT_KERN_READ  | \
++					   _PAGE_EXT_KERN_WRITE | \
++					   _PAGE_EXT_USER_READ  | \
++					   _PAGE_EXT_USER_WRITE))
++
++#define PAGE_EXECREAD	__pgprot(_PAGE_PRESENT | _PAGE_ACCESSED | \
++				 _PAGE_CACHABLE | _PAGE_FLAGS_HARD | \
++				 _PAGE_EXT(_PAGE_EXT_KERN_EXEC | \
++					   _PAGE_EXT_KERN_READ | \
++					   _PAGE_EXT_USER_EXEC | \
++					   _PAGE_EXT_USER_READ))
++
++#define PAGE_COPY	PAGE_EXECREAD
++
++#define PAGE_READONLY	__pgprot(_PAGE_PRESENT | _PAGE_ACCESSED | \
++				 _PAGE_CACHABLE | _PAGE_FLAGS_HARD | \
++				 _PAGE_EXT(_PAGE_EXT_KERN_READ | \
++					   _PAGE_EXT_USER_READ))
++
++#define PAGE_WRITEONLY	__pgprot(_PAGE_PRESENT | _PAGE_ACCESSED | \
++				 _PAGE_CACHABLE | _PAGE_FLAGS_HARD | \
++				 _PAGE_EXT(_PAGE_EXT_KERN_WRITE | \
++					   _PAGE_EXT_USER_WRITE))
++
++#define PAGE_RWX	__pgprot(_PAGE_PRESENT | _PAGE_ACCESSED | \
++				 _PAGE_CACHABLE | _PAGE_FLAGS_HARD | \
++				 _PAGE_EXT(_PAGE_EXT_KERN_WRITE | \
++					   _PAGE_EXT_KERN_READ  | \
++					   _PAGE_EXT_KERN_EXEC  | \
++					   _PAGE_EXT_USER_WRITE | \
++					   _PAGE_EXT_USER_READ  | \
++					   _PAGE_EXT_USER_EXEC))
++
++#define PAGE_KERNEL	__pgprot(_PAGE_PRESENT | _PAGE_CACHABLE | \
++				 _PAGE_DIRTY | _PAGE_ACCESSED | \
++				 _PAGE_HW_SHARED | _PAGE_FLAGS_HARD | \
++				 _PAGE_EXT(_PAGE_EXT_KERN_READ | \
++					   _PAGE_EXT_KERN_WRITE | \
++					   _PAGE_EXT_KERN_EXEC))
++
++#define PAGE_KERNEL_NOCACHE \
++			__pgprot(_PAGE_PRESENT | _PAGE_DIRTY | \
++				 _PAGE_ACCESSED | _PAGE_HW_SHARED | \
++				 _PAGE_FLAGS_HARD | \
++				 _PAGE_EXT(_PAGE_EXT_KERN_READ | \
++					   _PAGE_EXT_KERN_WRITE | \
++					   _PAGE_EXT_KERN_EXEC))
++
++#define PAGE_KERNEL_RO	__pgprot(_PAGE_PRESENT | _PAGE_CACHABLE | \
++				 _PAGE_DIRTY | _PAGE_ACCESSED | \
++				 _PAGE_HW_SHARED | _PAGE_FLAGS_HARD | \
++				 _PAGE_EXT(_PAGE_EXT_KERN_READ | \
++					   _PAGE_EXT_KERN_EXEC))
++
++#define PAGE_KERNEL_PCC(slot, type) \
++			__pgprot(_PAGE_PRESENT | _PAGE_DIRTY | \
++				 _PAGE_ACCESSED | _PAGE_FLAGS_HARD | \
++				 _PAGE_EXT(_PAGE_EXT_KERN_READ | \
++					   _PAGE_EXT_KERN_WRITE | \
++					   _PAGE_EXT_KERN_EXEC) \
++				 (slot ? _PAGE_PCC_AREA5 : _PAGE_PCC_AREA6) | \
++				 (type))
++
++#elif defined(CONFIG_MMU) /* SH-X TLB */
++#define PAGE_NONE	__pgprot(_PAGE_PROTNONE | _PAGE_CACHABLE | \
++				 _PAGE_ACCESSED | _PAGE_FLAGS_HARD)
++
++#define PAGE_SHARED	__pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | \
++				 _PAGE_CACHABLE | _PAGE_ACCESSED | \
++				 _PAGE_FLAGS_HARD)
++
++#define PAGE_COPY	__pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_CACHABLE | \
++				 _PAGE_ACCESSED | _PAGE_FLAGS_HARD)
++
++#define PAGE_READONLY	__pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_CACHABLE | \
++				 _PAGE_ACCESSED | _PAGE_FLAGS_HARD)
++
++#define PAGE_EXECREAD	PAGE_READONLY
++#define PAGE_RWX	PAGE_SHARED
++#define PAGE_WRITEONLY	PAGE_SHARED
++
++#define PAGE_KERNEL	__pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_CACHABLE | \
++				 _PAGE_DIRTY | _PAGE_ACCESSED | \
++				 _PAGE_HW_SHARED | _PAGE_FLAGS_HARD)
++
++#define PAGE_KERNEL_NOCACHE \
++			__pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | \
++				 _PAGE_ACCESSED | _PAGE_HW_SHARED | \
++				 _PAGE_FLAGS_HARD)
++
++#define PAGE_KERNEL_RO	__pgprot(_PAGE_PRESENT | _PAGE_CACHABLE | \
++				 _PAGE_DIRTY | _PAGE_ACCESSED | \
++				 _PAGE_HW_SHARED | _PAGE_FLAGS_HARD)
++
++#define PAGE_KERNEL_PCC(slot, type) \
++			__pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | \
++				 _PAGE_ACCESSED | _PAGE_FLAGS_HARD | \
++				 (slot ? _PAGE_PCC_AREA5 : _PAGE_PCC_AREA6) | \
++				 (type))
++#else /* no mmu */
++#define PAGE_NONE		__pgprot(0)
++#define PAGE_SHARED		__pgprot(0)
++#define PAGE_COPY		__pgprot(0)
++#define PAGE_EXECREAD		__pgprot(0)
++#define PAGE_RWX		__pgprot(0)
++#define PAGE_READONLY		__pgprot(0)
++#define PAGE_WRITEONLY		__pgprot(0)
++#define PAGE_KERNEL		__pgprot(0)
++#define PAGE_KERNEL_NOCACHE	__pgprot(0)
++#define PAGE_KERNEL_RO		__pgprot(0)
++
++#define PAGE_KERNEL_PCC(slot, type) \
++				__pgprot(0)
++#endif
++
++#endif /* __ASSEMBLY__ */
++
++#ifndef __ASSEMBLY__
++
++/*
++ * Certain architectures need to do special things when PTEs
++ * within a page table are directly modified.  Thus, the following
++ * hook is made available.
++ */
++#ifdef CONFIG_X2TLB
++static inline void set_pte(pte_t *ptep, pte_t pte)
++{
++	ptep->pte_high = pte.pte_high;
++	smp_wmb();
++	ptep->pte_low = pte.pte_low;
++}
++#else
++#define set_pte(pteptr, pteval) (*(pteptr) = pteval)
++#endif
++
++#define set_pte_at(mm,addr,ptep,pteval) set_pte(ptep,pteval)
++
++/*
++ * (pmds are folded into pgds so this doesn't get actually called,
++ * but the define is needed for a generic inline function.)
++ */
++#define set_pmd(pmdptr, pmdval) (*(pmdptr) = pmdval)
++
++#define pfn_pte(pfn, prot) \
++	__pte(((unsigned long long)(pfn) << PAGE_SHIFT) | pgprot_val(prot))
++#define pfn_pmd(pfn, prot) \
++	__pmd(((unsigned long long)(pfn) << PAGE_SHIFT) | pgprot_val(prot))
++
++#define pte_none(x)		(!pte_val(x))
++#define pte_present(x)		((x).pte_low & (_PAGE_PRESENT | _PAGE_PROTNONE))
++
++#define pte_clear(mm,addr,xp) do { set_pte_at(mm, addr, xp, __pte(0)); } while (0)
++
++#define pmd_none(x)	(!pmd_val(x))
++#define pmd_present(x)	(pmd_val(x))
++#define pmd_clear(xp)	do { set_pmd(xp, __pmd(0)); } while (0)
++#define	pmd_bad(x)	(pmd_val(x) & ~PAGE_MASK)
++
++#define pages_to_mb(x)	((x) >> (20-PAGE_SHIFT))
++#define pte_page(x)	pfn_to_page(pte_pfn(x))
++
++/*
++ * The following only work if pte_present() is true.
++ * Undefined behaviour if not..
++ */
++#define pte_not_present(pte)	(!((pte).pte_low & _PAGE_PRESENT))
++#define pte_dirty(pte)		((pte).pte_low & _PAGE_DIRTY)
++#define pte_young(pte)		((pte).pte_low & _PAGE_ACCESSED)
++#define pte_file(pte)		((pte).pte_low & _PAGE_FILE)
++
++#ifdef CONFIG_X2TLB
++#define pte_write(pte)		((pte).pte_high & _PAGE_EXT_USER_WRITE)
++#else
++#define pte_write(pte)		((pte).pte_low & _PAGE_RW)
++#endif
++
++#define PTE_BIT_FUNC(h,fn,op) \
++static inline pte_t pte_##fn(pte_t pte) { pte.pte_##h op; return pte; }
++
++#ifdef CONFIG_X2TLB
++/*
++ * We cheat a bit in the SH-X2 TLB case. As the permission bits are
++ * individually toggled (and user permissions are entirely decoupled from
++ * kernel permissions), we attempt to couple them a bit more sanely here.
++ */
++PTE_BIT_FUNC(high, wrprotect, &= ~_PAGE_EXT_USER_WRITE);
++PTE_BIT_FUNC(high, mkwrite, |= _PAGE_EXT_USER_WRITE | _PAGE_EXT_KERN_WRITE);
++PTE_BIT_FUNC(high, mkhuge, |= _PAGE_SZHUGE);
++#else
++PTE_BIT_FUNC(low, wrprotect, &= ~_PAGE_RW);
++PTE_BIT_FUNC(low, mkwrite, |= _PAGE_RW);
++PTE_BIT_FUNC(low, mkhuge, |= _PAGE_SZHUGE);
++#endif
++
++PTE_BIT_FUNC(low, mkclean, &= ~_PAGE_DIRTY);
++PTE_BIT_FUNC(low, mkdirty, |= _PAGE_DIRTY);
++PTE_BIT_FUNC(low, mkold, &= ~_PAGE_ACCESSED);
++PTE_BIT_FUNC(low, mkyoung, |= _PAGE_ACCESSED);
++
++/*
++ * Macro and implementation to make a page protection as uncachable.
++ */
++#define pgprot_writecombine(prot) \
++	__pgprot(pgprot_val(prot) & ~_PAGE_CACHABLE)
++
++#define pgprot_noncached	 pgprot_writecombine
++
++/*
++ * Conversion functions: convert a page and protection to a page entry,
++ * and a page entry and page directory to the page they refer to.
++ *
++ * extern pte_t mk_pte(struct page *page, pgprot_t pgprot)
++ */
++#define mk_pte(page, pgprot)	pfn_pte(page_to_pfn(page), (pgprot))
++
++static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
++{
++	pte.pte_low &= _PAGE_CHG_MASK;
++	pte.pte_low |= pgprot_val(newprot);
++
++#ifdef CONFIG_X2TLB
++	pte.pte_high |= pgprot_val(newprot) >> 32;
++#endif
++
++	return pte;
++}
++
++#define pmd_page_vaddr(pmd)	((unsigned long)pmd_val(pmd))
++#define pmd_page(pmd)		(virt_to_page(pmd_val(pmd)))
++
++/* to find an entry in a page-table-directory. */
++#define pgd_index(address)	(((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD-1))
++#define pgd_offset(mm, address)	((mm)->pgd+pgd_index(address))
++
++/* to find an entry in a kernel page-table-directory */
++#define pgd_offset_k(address)	pgd_offset(&init_mm, address)
++
++/* Find an entry in the third-level page table.. */
++#define pte_index(address)	((address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
++#define pte_offset_kernel(dir, address) \
++	((pte_t *) pmd_page_vaddr(*(dir)) + pte_index(address))
++#define pte_offset_map(dir, address)		pte_offset_kernel(dir, address)
++#define pte_offset_map_nested(dir, address)	pte_offset_kernel(dir, address)
++
++#define pte_unmap(pte)		do { } while (0)
++#define pte_unmap_nested(pte)	do { } while (0)
++
++#ifdef CONFIG_X2TLB
++#define pte_ERROR(e) \
++	printk("%s:%d: bad pte %p(%08lx%08lx).\n", __FILE__, __LINE__, \
++	       &(e), (e).pte_high, (e).pte_low)
++#define pgd_ERROR(e) \
++	printk("%s:%d: bad pgd %016llx.\n", __FILE__, __LINE__, pgd_val(e))
++#else
++#define pte_ERROR(e) \
++	printk("%s:%d: bad pte %08lx.\n", __FILE__, __LINE__, pte_val(e))
++#define pgd_ERROR(e) \
++	printk("%s:%d: bad pgd %08lx.\n", __FILE__, __LINE__, pgd_val(e))
++#endif
++
++/*
++ * Encode and de-code a swap entry
++ *
++ * Constraints:
++ *	_PAGE_FILE at bit 0
++ *	_PAGE_PRESENT at bit 8
++ *	_PAGE_PROTNONE at bit 9
++ *
++ * For the normal case, we encode the swap type into bits 0:7 and the
++ * swap offset into bits 10:30. For the 64-bit PTE case, we keep the
++ * preserved bits in the low 32-bits and use the upper 32 as the swap
++ * offset (along with a 5-bit type), following the same approach as x86
++ * PAE. This keeps the logic quite simple, and allows for a full 32
++ * PTE_FILE_MAX_BITS, as opposed to the 29-bits we're constrained with
++ * in the pte_low case.
++ *
++ * As is evident by the Alpha code, if we ever get a 64-bit unsigned
++ * long (swp_entry_t) to match up with the 64-bit PTEs, this all becomes
++ * much cleaner..
++ *
++ * NOTE: We should set ZEROs at the position of _PAGE_PRESENT
++ *       and _PAGE_PROTNONE bits
++ */
++#ifdef CONFIG_X2TLB
++#define __swp_type(x)			((x).val & 0x1f)
++#define __swp_offset(x)			((x).val >> 5)
++#define __swp_entry(type, offset)	((swp_entry_t){ (type) | (offset) << 5})
++#define __pte_to_swp_entry(pte)		((swp_entry_t){ (pte).pte_high })
++#define __swp_entry_to_pte(x)		((pte_t){ 0, (x).val })
++
++/*
++ * Encode and decode a nonlinear file mapping entry
++ */
++#define pte_to_pgoff(pte)		((pte).pte_high)
++#define pgoff_to_pte(off)		((pte_t) { _PAGE_FILE, (off) })
++
++#define PTE_FILE_MAX_BITS		32
++#else
++#define __swp_type(x)			((x).val & 0xff)
++#define __swp_offset(x)			((x).val >> 10)
++#define __swp_entry(type, offset)	((swp_entry_t){(type) | (offset) <<10})
++
++#define __pte_to_swp_entry(pte)		((swp_entry_t) { pte_val(pte) >> 1 })
++#define __swp_entry_to_pte(x)		((pte_t) { (x).val << 1 })
++
++/*
++ * Encode and decode a nonlinear file mapping entry
++ */
++#define PTE_FILE_MAX_BITS	29
++#define pte_to_pgoff(pte)	(pte_val(pte) >> 1)
++#define pgoff_to_pte(off)	((pte_t) { ((off) << 1) | _PAGE_FILE })
++#endif
++
++#endif /* __ASSEMBLY__ */
++#endif /* __ASM_SH_PGTABLE_32_H */
+diff --git a/include/asm-sh/pgtable_64.h b/include/asm-sh/pgtable_64.h
+new file mode 100644
+index 0000000..9722116
+--- /dev/null
++++ b/include/asm-sh/pgtable_64.h
+@@ -0,0 +1,299 @@
++#ifndef __ASM_SH_PGTABLE_64_H
++#define __ASM_SH_PGTABLE_64_H
++
++/*
++ * include/asm-sh/pgtable_64.h
++ *
++ * This file contains the functions and defines necessary to modify and use
++ * the SuperH page table tree.
++ *
++ * Copyright (C) 2000, 2001  Paolo Alberelli
++ * Copyright (C) 2003, 2004  Paul Mundt
++ * Copyright (C) 2003, 2004  Richard Curnow
++ *
++ * 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/threads.h>
++#include <asm/processor.h>
++#include <asm/page.h>
++
++/*
++ * Error outputs.
++ */
++#define pte_ERROR(e) \
++	printk("%s:%d: bad pte %016Lx.\n", __FILE__, __LINE__, pte_val(e))
++#define pgd_ERROR(e) \
++	printk("%s:%d: bad pgd %08lx.\n", __FILE__, __LINE__, pgd_val(e))
++
++/*
++ * Table setting routines. Used within arch/mm only.
++ */
++#define set_pmd(pmdptr, pmdval) (*(pmdptr) = pmdval)
++
++static __inline__ void set_pte(pte_t *pteptr, pte_t pteval)
++{
++	unsigned long long x = ((unsigned long long) pteval.pte_low);
++	unsigned long long *xp = (unsigned long long *) pteptr;
++	/*
++	 * Sign-extend based on NPHYS.
++	 */
++	*(xp) = (x & NPHYS_SIGN) ? (x | NPHYS_MASK) : x;
++}
++#define set_pte_at(mm,addr,ptep,pteval) set_pte(ptep,pteval)
++
++static __inline__ void pmd_set(pmd_t *pmdp,pte_t *ptep)
++{
++	pmd_val(*pmdp) = (unsigned long) ptep;
++}
++
++/*
++ * PGD defines. Top level.
++ */
++
++/* To find an entry in a generic PGD. */
++#define pgd_index(address) (((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD-1))
++#define __pgd_offset(address) pgd_index(address)
++#define pgd_offset(mm, address) ((mm)->pgd+pgd_index(address))
++
++/* To find an entry in a kernel PGD. */
++#define pgd_offset_k(address) pgd_offset(&init_mm, address)
++
++/*
++ * PMD level access routines. Same notes as above.
++ */
++#define _PMD_EMPTY		0x0
++/* Either the PMD is empty or present, it's not paged out */
++#define pmd_present(pmd_entry)	(pmd_val(pmd_entry) & _PAGE_PRESENT)
++#define pmd_clear(pmd_entry_p)	(set_pmd((pmd_entry_p), __pmd(_PMD_EMPTY)))
++#define pmd_none(pmd_entry)	(pmd_val((pmd_entry)) == _PMD_EMPTY)
++#define pmd_bad(pmd_entry)	((pmd_val(pmd_entry) & (~PAGE_MASK & ~_PAGE_USER)) != _KERNPG_TABLE)
++
++#define pmd_page_vaddr(pmd_entry) \
++	((unsigned long) __va(pmd_val(pmd_entry) & PAGE_MASK))
++
++#define pmd_page(pmd) \
++	(virt_to_page(pmd_val(pmd)))
++
++/* PMD to PTE dereferencing */
++#define pte_index(address) \
++		((address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
++
++#define pte_offset_kernel(dir, addr) \
++		((pte_t *) ((pmd_val(*(dir))) & PAGE_MASK) + pte_index((addr)))
++
++#define pte_offset_map(dir,addr)	pte_offset_kernel(dir, addr)
++#define pte_offset_map_nested(dir,addr)	pte_offset_kernel(dir, addr)
++#define pte_unmap(pte)		do { } while (0)
++#define pte_unmap_nested(pte)	do { } while (0)
++
++#ifndef __ASSEMBLY__
++#define IOBASE_VADDR	0xff000000
++#define IOBASE_END	0xffffffff
++
++/*
++ * PTEL coherent flags.
++ * See Chapter 17 ST50 CPU Core Volume 1, Architecture.
++ */
++/* The bits that are required in the SH-5 TLB are placed in the h/w-defined
++   positions, to avoid expensive bit shuffling on every refill.  The remaining
++   bits are used for s/w purposes and masked out on each refill.
++
++   Note, the PTE slots are used to hold data of type swp_entry_t when a page is
++   swapped out.  Only the _PAGE_PRESENT flag is significant when the page is
++   swapped out, and it must be placed so that it doesn't overlap either the
++   type or offset fields of swp_entry_t.  For x86, offset is at [31:8] and type
++   at [6:1], with _PAGE_PRESENT at bit 0 for both pte_t and swp_entry_t.  This
++   scheme doesn't map to SH-5 because bit [0] controls cacheability.  So bit
++   [2] is used for _PAGE_PRESENT and the type field of swp_entry_t is split
++   into 2 pieces.  That is handled by SWP_ENTRY and SWP_TYPE below. */
++#define _PAGE_WT	0x001  /* CB0: if cacheable, 1->write-thru, 0->write-back */
++#define _PAGE_DEVICE	0x001  /* CB0: if uncacheable, 1->device (i.e. no write-combining or reordering at bus level) */
++#define _PAGE_CACHABLE	0x002  /* CB1: uncachable/cachable */
++#define _PAGE_PRESENT	0x004  /* software: page referenced */
++#define _PAGE_FILE	0x004  /* software: only when !present */
++#define _PAGE_SIZE0	0x008  /* SZ0-bit : size of page */
++#define _PAGE_SIZE1	0x010  /* SZ1-bit : size of page */
++#define _PAGE_SHARED	0x020  /* software: reflects PTEH's SH */
++#define _PAGE_READ	0x040  /* PR0-bit : read access allowed */
++#define _PAGE_EXECUTE	0x080  /* PR1-bit : execute access allowed */
++#define _PAGE_WRITE	0x100  /* PR2-bit : write access allowed */
++#define _PAGE_USER	0x200  /* PR3-bit : user space access allowed */
++#define _PAGE_DIRTY	0x400  /* software: page accessed in write */
++#define _PAGE_ACCESSED	0x800  /* software: page referenced */
++
++/* Mask which drops software flags */
++#define _PAGE_FLAGS_HARDWARE_MASK	0xfffffffffffff3dbLL
++
++/*
++ * HugeTLB support
++ */
++#if defined(CONFIG_HUGETLB_PAGE_SIZE_64K)
++#define _PAGE_SZHUGE	(_PAGE_SIZE0)
++#elif defined(CONFIG_HUGETLB_PAGE_SIZE_1MB)
++#define _PAGE_SZHUGE	(_PAGE_SIZE1)
++#elif defined(CONFIG_HUGETLB_PAGE_SIZE_512MB)
++#define _PAGE_SZHUGE	(_PAGE_SIZE0 | _PAGE_SIZE1)
++#endif
++
++/*
++ * Default flags for a Kernel page.
++ * This is fundametally also SHARED because the main use of this define
++ * (other than for PGD/PMD entries) is for the VMALLOC pool which is
++ * contextless.
++ *
++ * _PAGE_EXECUTE is required for modules
++ *
++ */
++#define _KERNPG_TABLE	(_PAGE_PRESENT | _PAGE_READ | _PAGE_WRITE | \
++			 _PAGE_EXECUTE | \
++			 _PAGE_CACHABLE | _PAGE_ACCESSED | _PAGE_DIRTY | \
++			 _PAGE_SHARED)
++
++/* Default flags for a User page */
++#define _PAGE_TABLE	(_KERNPG_TABLE | _PAGE_USER)
++
++#define _PAGE_CHG_MASK	(PTE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY)
++
++/*
++ * We have full permissions (Read/Write/Execute/Shared).
++ */
++#define _PAGE_COMMON	(_PAGE_PRESENT | _PAGE_USER | \
++			 _PAGE_CACHABLE | _PAGE_ACCESSED)
++
++#define PAGE_NONE	__pgprot(_PAGE_CACHABLE | _PAGE_ACCESSED)
++#define PAGE_SHARED	__pgprot(_PAGE_COMMON | _PAGE_READ | _PAGE_WRITE | \
++				 _PAGE_SHARED)
++#define PAGE_EXECREAD	__pgprot(_PAGE_COMMON | _PAGE_READ | _PAGE_EXECUTE)
++
++/*
++ * We need to include PAGE_EXECUTE in PAGE_COPY because it is the default
++ * protection mode for the stack.
++ */
++#define PAGE_COPY	PAGE_EXECREAD
++
++#define PAGE_READONLY	__pgprot(_PAGE_COMMON | _PAGE_READ)
++#define PAGE_WRITEONLY	__pgprot(_PAGE_COMMON | _PAGE_WRITE)
++#define PAGE_RWX	__pgprot(_PAGE_COMMON | _PAGE_READ | \
++				 _PAGE_WRITE | _PAGE_EXECUTE)
++#define PAGE_KERNEL	__pgprot(_KERNPG_TABLE)
++
++/* Make it a device mapping for maximum safety (e.g. for mapping device
++   registers into user-space via /dev/map).  */
++#define pgprot_noncached(x) __pgprot(((x).pgprot & ~(_PAGE_CACHABLE)) | _PAGE_DEVICE)
++#define pgprot_writecombine(prot) __pgprot(pgprot_val(prot) & ~_PAGE_CACHABLE)
++
++/*
++ * Handling allocation failures during page table setup.
++ */
++extern void __handle_bad_pmd_kernel(pmd_t * pmd);
++#define __handle_bad_pmd(x)	__handle_bad_pmd_kernel(x)
++
++/*
++ * PTE level access routines.
++ *
++ * Note1:
++ * It's the tree walk leaf. This is physical address to be stored.
++ *
++ * Note 2:
++ * Regarding the choice of _PTE_EMPTY:
++
++   We must choose a bit pattern that cannot be valid, whether or not the page
++   is present.  bit[2]==1 => present, bit[2]==0 => swapped out.  If swapped
++   out, bits [31:8], [6:3], [1:0] are under swapper control, so only bit[7] is
++   left for us to select.  If we force bit[7]==0 when swapped out, we could use
++   the combination bit[7,2]=2'b10 to indicate an empty PTE.  Alternatively, if
++   we force bit[7]==1 when swapped out, we can use all zeroes to indicate
++   empty.  This is convenient, because the page tables get cleared to zero
++   when they are allocated.
++
++ */
++#define _PTE_EMPTY	0x0
++#define pte_present(x)	(pte_val(x) & _PAGE_PRESENT)
++#define pte_clear(mm,addr,xp)	(set_pte_at(mm, addr, xp, __pte(_PTE_EMPTY)))
++#define pte_none(x)	(pte_val(x) == _PTE_EMPTY)
++
++/*
++ * Some definitions to translate between mem_map, PTEs, and page
++ * addresses:
++ */
++
++/*
++ * Given a PTE, return the index of the mem_map[] entry corresponding
++ * to the page frame the PTE. Get the absolute physical address, make
++ * a relative physical address and translate it to an index.
++ */
++#define pte_pagenr(x)		(((unsigned long) (pte_val(x)) - \
++				 __MEMORY_START) >> PAGE_SHIFT)
++
++/*
++ * Given a PTE, return the "struct page *".
++ */
++#define pte_page(x)		(mem_map + pte_pagenr(x))
++
++/*
++ * Return number of (down rounded) MB corresponding to x pages.
++ */
++#define pages_to_mb(x) ((x) >> (20-PAGE_SHIFT))
++
++
++/*
++ * The following have defined behavior only work if pte_present() is true.
++ */
++static inline int pte_dirty(pte_t pte){ return pte_val(pte) & _PAGE_DIRTY; }
++static inline int pte_young(pte_t pte){ return pte_val(pte) & _PAGE_ACCESSED; }
++static inline int pte_file(pte_t pte) { return pte_val(pte) & _PAGE_FILE; }
++static inline int pte_write(pte_t pte){ return pte_val(pte) & _PAGE_WRITE; }
++
++static inline pte_t pte_wrprotect(pte_t pte)	{ set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_WRITE)); return pte; }
++static inline pte_t pte_mkclean(pte_t pte)	{ set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_DIRTY)); return pte; }
++static inline pte_t pte_mkold(pte_t pte)	{ set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_ACCESSED)); return pte; }
++static inline pte_t pte_mkwrite(pte_t pte)	{ set_pte(&pte, __pte(pte_val(pte) | _PAGE_WRITE)); return pte; }
++static inline pte_t pte_mkdirty(pte_t pte)	{ set_pte(&pte, __pte(pte_val(pte) | _PAGE_DIRTY)); return pte; }
++static inline pte_t pte_mkyoung(pte_t pte)	{ set_pte(&pte, __pte(pte_val(pte) | _PAGE_ACCESSED)); return pte; }
++static inline pte_t pte_mkhuge(pte_t pte)	{ set_pte(&pte, __pte(pte_val(pte) | _PAGE_SZHUGE)); return pte; }
++
++
++/*
++ * Conversion functions: convert a page and protection to a page entry.
++ *
++ * extern pte_t mk_pte(struct page *page, pgprot_t pgprot)
++ */
++#define mk_pte(page,pgprot)							\
++({										\
++	pte_t __pte;								\
++										\
++	set_pte(&__pte, __pte((((page)-mem_map) << PAGE_SHIFT) | 		\
++		__MEMORY_START | pgprot_val((pgprot))));			\
++	__pte;									\
++})
++
++/*
++ * This takes a (absolute) physical page address that is used
++ * by the remapping functions
++ */
++#define mk_pte_phys(physpage, pgprot) \
++({ pte_t __pte; set_pte(&__pte, __pte(physpage | pgprot_val(pgprot))); __pte; })
++
++static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
++{ set_pte(&pte, __pte((pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot))); return pte; }
++
++/* Encode and decode a swap entry */
++#define __swp_type(x)			(((x).val & 3) + (((x).val >> 1) & 0x3c))
++#define __swp_offset(x)			((x).val >> 8)
++#define __swp_entry(type, offset)	((swp_entry_t) { ((offset << 8) + ((type & 0x3c) << 1) + (type & 3)) })
++#define __pte_to_swp_entry(pte)		((swp_entry_t) { pte_val(pte) })
++#define __swp_entry_to_pte(x)		((pte_t) { (x).val })
++
++/* Encode and decode a nonlinear file mapping entry */
++#define PTE_FILE_MAX_BITS		29
++#define pte_to_pgoff(pte)		(pte_val(pte))
++#define pgoff_to_pte(off)		((pte_t) { (off) | _PAGE_FILE })
++
++#endif /* !__ASSEMBLY__ */
++
++#define pfn_pte(pfn, prot)	__pte(((pfn) << PAGE_SHIFT) | pgprot_val(prot))
++#define pfn_pmd(pfn, prot)	__pmd(((pfn) << PAGE_SHIFT) | pgprot_val(prot))
++
++#endif /* __ASM_SH_PGTABLE_64_H */
+diff --git a/include/asm-sh/posix_types.h b/include/asm-sh/posix_types.h
+index 0a3d2f5..4b9d11c 100644
+--- a/include/asm-sh/posix_types.h
++++ b/include/asm-sh/posix_types.h
+@@ -1,122 +1,7 @@
+-#ifndef __ASM_SH_POSIX_TYPES_H
+-#define __ASM_SH_POSIX_TYPES_H
+-
+-/*
+- * This file is generally used by user-level software, so you need to
+- * be a little careful about namespace pollution etc.  Also, we cannot
+- * assume GCC is being used.
+- */
+-
+-typedef unsigned long	__kernel_ino_t;
+-typedef unsigned short	__kernel_mode_t;
+-typedef unsigned short	__kernel_nlink_t;
+-typedef long		__kernel_off_t;
+-typedef int		__kernel_pid_t;
+-typedef unsigned short	__kernel_ipc_pid_t;
+-typedef unsigned short	__kernel_uid_t;
+-typedef unsigned short	__kernel_gid_t;
+-typedef unsigned int	__kernel_size_t;
+-typedef int		__kernel_ssize_t;
+-typedef int		__kernel_ptrdiff_t;
+-typedef long		__kernel_time_t;
+-typedef long		__kernel_suseconds_t;
+-typedef long		__kernel_clock_t;
+-typedef int		__kernel_timer_t;
+-typedef int		__kernel_clockid_t;
+-typedef int		__kernel_daddr_t;
+-typedef char *		__kernel_caddr_t;
+-typedef unsigned short	__kernel_uid16_t;
+-typedef unsigned short	__kernel_gid16_t;
+-typedef unsigned int	__kernel_uid32_t;
+-typedef unsigned int	__kernel_gid32_t;
+-
+-typedef unsigned short	__kernel_old_uid_t;
+-typedef unsigned short	__kernel_old_gid_t;
+-typedef unsigned short	__kernel_old_dev_t;
+-
+-#ifdef __GNUC__
+-typedef long long	__kernel_loff_t;
+-#endif
+-
+-typedef struct {
+-#if defined(__KERNEL__) || defined(__USE_ALL)
+-	int	val[2];
+-#else /* !defined(__KERNEL__) && !defined(__USE_ALL) */
+-	int	__val[2];
+-#endif /* !defined(__KERNEL__) && !defined(__USE_ALL) */
+-} __kernel_fsid_t;
+-
+-#if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2)
+-
+-#undef	__FD_SET
+-static __inline__ void __FD_SET(unsigned long __fd, __kernel_fd_set *__fdsetp)
+-{
+-	unsigned long __tmp = __fd / __NFDBITS;
+-	unsigned long __rem = __fd % __NFDBITS;
+-	__fdsetp->fds_bits[__tmp] |= (1UL<<__rem);
+-}
+-
+-#undef	__FD_CLR
+-static __inline__ void __FD_CLR(unsigned long __fd, __kernel_fd_set *__fdsetp)
+-{
+-	unsigned long __tmp = __fd / __NFDBITS;
+-	unsigned long __rem = __fd % __NFDBITS;
+-	__fdsetp->fds_bits[__tmp] &= ~(1UL<<__rem);
+-}
+-
+-
+-#undef	__FD_ISSET
+-static __inline__ int __FD_ISSET(unsigned long __fd, const __kernel_fd_set *__p)
+-{ 
+-	unsigned long __tmp = __fd / __NFDBITS;
+-	unsigned long __rem = __fd % __NFDBITS;
+-	return (__p->fds_bits[__tmp] & (1UL<<__rem)) != 0;
+-}
+-
+-/*
+- * This will unroll the loop for the normal constant case (8 ints,
+- * for a 256-bit fd_set)
+- */
+-#undef	__FD_ZERO
+-static __inline__ void __FD_ZERO(__kernel_fd_set *__p)
+-{
+-	unsigned long *__tmp = __p->fds_bits;
+-	int __i;
+-
+-	if (__builtin_constant_p(__FDSET_LONGS)) {
+-		switch (__FDSET_LONGS) {
+-		case 16:
+-			__tmp[ 0] = 0; __tmp[ 1] = 0;
+-			__tmp[ 2] = 0; __tmp[ 3] = 0;
+-			__tmp[ 4] = 0; __tmp[ 5] = 0;
+-			__tmp[ 6] = 0; __tmp[ 7] = 0;
+-			__tmp[ 8] = 0; __tmp[ 9] = 0;
+-			__tmp[10] = 0; __tmp[11] = 0;
+-			__tmp[12] = 0; __tmp[13] = 0;
+-			__tmp[14] = 0; __tmp[15] = 0;
+-			return;
+-
+-		case 8:
+-			__tmp[ 0] = 0; __tmp[ 1] = 0;
+-			__tmp[ 2] = 0; __tmp[ 3] = 0;
+-			__tmp[ 4] = 0; __tmp[ 5] = 0;
+-			__tmp[ 6] = 0; __tmp[ 7] = 0;
+-			return;
+-
+-		case 4:
+-			__tmp[ 0] = 0; __tmp[ 1] = 0;
+-			__tmp[ 2] = 0; __tmp[ 3] = 0;
+-			return;
+-		}
+-	}
+-	__i = __FDSET_LONGS;
+-	while (__i) {
+-		__i--;
+-		*__tmp = 0;
+-		__tmp++;
+-	}
+-}
+-
+-#endif /* defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2) */
+-
+-#endif /* __ASM_SH_POSIX_TYPES_H */
++#ifdef __KERNEL__
++# ifdef CONFIG_SUPERH32
++#  include "posix_types_32.h"
++# else
++#  include "posix_types_64.h"
++# endif
++#endif /* __KERNEL__ */
+diff --git a/include/asm-sh/posix_types_32.h b/include/asm-sh/posix_types_32.h
+new file mode 100644
+index 0000000..0a3d2f5
+--- /dev/null
++++ b/include/asm-sh/posix_types_32.h
+@@ -0,0 +1,122 @@
++#ifndef __ASM_SH_POSIX_TYPES_H
++#define __ASM_SH_POSIX_TYPES_H
++
++/*
++ * This file is generally used by user-level software, so you need to
++ * be a little careful about namespace pollution etc.  Also, we cannot
++ * assume GCC is being used.
++ */
++
++typedef unsigned long	__kernel_ino_t;
++typedef unsigned short	__kernel_mode_t;
++typedef unsigned short	__kernel_nlink_t;
++typedef long		__kernel_off_t;
++typedef int		__kernel_pid_t;
++typedef unsigned short	__kernel_ipc_pid_t;
++typedef unsigned short	__kernel_uid_t;
++typedef unsigned short	__kernel_gid_t;
++typedef unsigned int	__kernel_size_t;
++typedef int		__kernel_ssize_t;
++typedef int		__kernel_ptrdiff_t;
++typedef long		__kernel_time_t;
++typedef long		__kernel_suseconds_t;
++typedef long		__kernel_clock_t;
++typedef int		__kernel_timer_t;
++typedef int		__kernel_clockid_t;
++typedef int		__kernel_daddr_t;
++typedef char *		__kernel_caddr_t;
++typedef unsigned short	__kernel_uid16_t;
++typedef unsigned short	__kernel_gid16_t;
++typedef unsigned int	__kernel_uid32_t;
++typedef unsigned int	__kernel_gid32_t;
++
++typedef unsigned short	__kernel_old_uid_t;
++typedef unsigned short	__kernel_old_gid_t;
++typedef unsigned short	__kernel_old_dev_t;
++
++#ifdef __GNUC__
++typedef long long	__kernel_loff_t;
++#endif
++
++typedef struct {
++#if defined(__KERNEL__) || defined(__USE_ALL)
++	int	val[2];
++#else /* !defined(__KERNEL__) && !defined(__USE_ALL) */
++	int	__val[2];
++#endif /* !defined(__KERNEL__) && !defined(__USE_ALL) */
++} __kernel_fsid_t;
++
++#if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2)
++
++#undef	__FD_SET
++static __inline__ void __FD_SET(unsigned long __fd, __kernel_fd_set *__fdsetp)
++{
++	unsigned long __tmp = __fd / __NFDBITS;
++	unsigned long __rem = __fd % __NFDBITS;
++	__fdsetp->fds_bits[__tmp] |= (1UL<<__rem);
++}
++
++#undef	__FD_CLR
++static __inline__ void __FD_CLR(unsigned long __fd, __kernel_fd_set *__fdsetp)
++{
++	unsigned long __tmp = __fd / __NFDBITS;
++	unsigned long __rem = __fd % __NFDBITS;
++	__fdsetp->fds_bits[__tmp] &= ~(1UL<<__rem);
++}
 +
-+/* group add. inode update and the new group update. */
-+#define OCFS2_GROUP_ADD_CREDITS	(OCFS2_INODE_UPDATE_CREDITS + 1)
 +
- /* get one bit out of a suballocator: dinode + group descriptor +
-  * prev. group desc. if we relink. */
- #define OCFS2_SUBALLOC_ALLOC (3)
-diff --git a/fs/ocfs2/localalloc.c b/fs/ocfs2/localalloc.c
-index 58ea88b..add1ffd 100644
---- a/fs/ocfs2/localalloc.c
-+++ b/fs/ocfs2/localalloc.c
-@@ -75,18 +75,12 @@ static int ocfs2_local_alloc_new_window(struct ocfs2_super *osb,
- static int ocfs2_local_alloc_slide_window(struct ocfs2_super *osb,
- 					  struct inode *local_alloc_inode);
- 
++#undef	__FD_ISSET
++static __inline__ int __FD_ISSET(unsigned long __fd, const __kernel_fd_set *__p)
++{ 
++	unsigned long __tmp = __fd / __NFDBITS;
++	unsigned long __rem = __fd % __NFDBITS;
++	return (__p->fds_bits[__tmp] & (1UL<<__rem)) != 0;
++}
++
++/*
++ * This will unroll the loop for the normal constant case (8 ints,
++ * for a 256-bit fd_set)
++ */
++#undef	__FD_ZERO
++static __inline__ void __FD_ZERO(__kernel_fd_set *__p)
++{
++	unsigned long *__tmp = __p->fds_bits;
++	int __i;
++
++	if (__builtin_constant_p(__FDSET_LONGS)) {
++		switch (__FDSET_LONGS) {
++		case 16:
++			__tmp[ 0] = 0; __tmp[ 1] = 0;
++			__tmp[ 2] = 0; __tmp[ 3] = 0;
++			__tmp[ 4] = 0; __tmp[ 5] = 0;
++			__tmp[ 6] = 0; __tmp[ 7] = 0;
++			__tmp[ 8] = 0; __tmp[ 9] = 0;
++			__tmp[10] = 0; __tmp[11] = 0;
++			__tmp[12] = 0; __tmp[13] = 0;
++			__tmp[14] = 0; __tmp[15] = 0;
++			return;
++
++		case 8:
++			__tmp[ 0] = 0; __tmp[ 1] = 0;
++			__tmp[ 2] = 0; __tmp[ 3] = 0;
++			__tmp[ 4] = 0; __tmp[ 5] = 0;
++			__tmp[ 6] = 0; __tmp[ 7] = 0;
++			return;
++
++		case 4:
++			__tmp[ 0] = 0; __tmp[ 1] = 0;
++			__tmp[ 2] = 0; __tmp[ 3] = 0;
++			return;
++		}
++	}
++	__i = __FDSET_LONGS;
++	while (__i) {
++		__i--;
++		*__tmp = 0;
++		__tmp++;
++	}
++}
++
++#endif /* defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2) */
++
++#endif /* __ASM_SH_POSIX_TYPES_H */
+diff --git a/include/asm-sh/posix_types_64.h b/include/asm-sh/posix_types_64.h
+new file mode 100644
+index 0000000..0620317
+--- /dev/null
++++ b/include/asm-sh/posix_types_64.h
+@@ -0,0 +1,131 @@
++#ifndef __ASM_SH64_POSIX_TYPES_H
++#define __ASM_SH64_POSIX_TYPES_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.
++ *
++ * include/asm-sh64/posix_types.h
++ *
++ * Copyright (C) 2000, 2001  Paolo Alberelli
++ * Copyright (C) 2003  Paul Mundt
++ *
++ * This file is generally used by user-level software, so you need to
++ * be a little careful about namespace pollution etc.  Also, we cannot
++ * assume GCC is being used.
++ */
++
++typedef unsigned long	__kernel_ino_t;
++typedef unsigned short	__kernel_mode_t;
++typedef unsigned short	__kernel_nlink_t;
++typedef long		__kernel_off_t;
++typedef int		__kernel_pid_t;
++typedef unsigned short	__kernel_ipc_pid_t;
++typedef unsigned short	__kernel_uid_t;
++typedef unsigned short	__kernel_gid_t;
++typedef long unsigned int	__kernel_size_t;
++typedef int		__kernel_ssize_t;
++typedef int		__kernel_ptrdiff_t;
++typedef long		__kernel_time_t;
++typedef long		__kernel_suseconds_t;
++typedef long		__kernel_clock_t;
++typedef int		__kernel_timer_t;
++typedef int		__kernel_clockid_t;
++typedef int		__kernel_daddr_t;
++typedef char *		__kernel_caddr_t;
++typedef unsigned short	__kernel_uid16_t;
++typedef unsigned short	__kernel_gid16_t;
++typedef unsigned int	__kernel_uid32_t;
++typedef unsigned int	__kernel_gid32_t;
++
++typedef unsigned short	__kernel_old_uid_t;
++typedef unsigned short	__kernel_old_gid_t;
++typedef unsigned short	__kernel_old_dev_t;
++
++#ifdef __GNUC__
++typedef long long	__kernel_loff_t;
++#endif
++
++typedef struct {
++#if defined(__KERNEL__) || defined(__USE_ALL)
++	int	val[2];
++#else /* !defined(__KERNEL__) && !defined(__USE_ALL) */
++	int	__val[2];
++#endif /* !defined(__KERNEL__) && !defined(__USE_ALL) */
++} __kernel_fsid_t;
++
++#if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2)
++
++#undef	__FD_SET
++static __inline__ void __FD_SET(unsigned long __fd, __kernel_fd_set *__fdsetp)
++{
++	unsigned long __tmp = __fd / __NFDBITS;
++	unsigned long __rem = __fd % __NFDBITS;
++	__fdsetp->fds_bits[__tmp] |= (1UL<<__rem);
++}
++
++#undef	__FD_CLR
++static __inline__ void __FD_CLR(unsigned long __fd, __kernel_fd_set *__fdsetp)
++{
++	unsigned long __tmp = __fd / __NFDBITS;
++	unsigned long __rem = __fd % __NFDBITS;
++	__fdsetp->fds_bits[__tmp] &= ~(1UL<<__rem);
++}
++
++
++#undef	__FD_ISSET
++static __inline__ int __FD_ISSET(unsigned long __fd, const __kernel_fd_set *__p)
++{
++	unsigned long __tmp = __fd / __NFDBITS;
++	unsigned long __rem = __fd % __NFDBITS;
++	return (__p->fds_bits[__tmp] & (1UL<<__rem)) != 0;
++}
++
++/*
++ * This will unroll the loop for the normal constant case (8 ints,
++ * for a 256-bit fd_set)
++ */
++#undef	__FD_ZERO
++static __inline__ void __FD_ZERO(__kernel_fd_set *__p)
++{
++	unsigned long *__tmp = __p->fds_bits;
++	int __i;
++
++	if (__builtin_constant_p(__FDSET_LONGS)) {
++		switch (__FDSET_LONGS) {
++		case 16:
++			__tmp[ 0] = 0; __tmp[ 1] = 0;
++			__tmp[ 2] = 0; __tmp[ 3] = 0;
++			__tmp[ 4] = 0; __tmp[ 5] = 0;
++			__tmp[ 6] = 0; __tmp[ 7] = 0;
++			__tmp[ 8] = 0; __tmp[ 9] = 0;
++			__tmp[10] = 0; __tmp[11] = 0;
++			__tmp[12] = 0; __tmp[13] = 0;
++			__tmp[14] = 0; __tmp[15] = 0;
++			return;
++
++		case 8:
++			__tmp[ 0] = 0; __tmp[ 1] = 0;
++			__tmp[ 2] = 0; __tmp[ 3] = 0;
++			__tmp[ 4] = 0; __tmp[ 5] = 0;
++			__tmp[ 6] = 0; __tmp[ 7] = 0;
++			return;
++
++		case 4:
++			__tmp[ 0] = 0; __tmp[ 1] = 0;
++			__tmp[ 2] = 0; __tmp[ 3] = 0;
++			return;
++		}
++	}
++	__i = __FDSET_LONGS;
++	while (__i) {
++		__i--;
++		*__tmp = 0;
++		__tmp++;
++	}
++}
++
++#endif /* defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2) */
++
++#endif /* __ASM_SH64_POSIX_TYPES_H */
+diff --git a/include/asm-sh/processor.h b/include/asm-sh/processor.h
+index fda6848..c9b1416 100644
+--- a/include/asm-sh/processor.h
++++ b/include/asm-sh/processor.h
+@@ -1,32 +1,10 @@
 -/*
-- * Determine how large our local alloc window should be, in bits.
+- * include/asm-sh/processor.h
 - *
-- * These values (and the behavior in ocfs2_alloc_should_use_local) have
-- * been chosen so that most allocations, including new block groups go
-- * through local alloc.
+- * Copyright (C) 1999, 2000  Niibe Yutaka
+- * Copyright (C) 2002, 2003  Paul Mundt
 - */
- static inline int ocfs2_local_alloc_window_bits(struct ocfs2_super *osb)
- {
--	BUG_ON(osb->s_clustersize_bits < 12);
-+	BUG_ON(osb->s_clustersize_bits > 20);
- 
--	return 2048 >> (osb->s_clustersize_bits - 12);
-+	/* Size local alloc windows by the megabyte */
-+	return osb->local_alloc_size << (20 - osb->s_clustersize_bits);
- }
+-
+ #ifndef __ASM_SH_PROCESSOR_H
+ #define __ASM_SH_PROCESSOR_H
+-#ifdef __KERNEL__
+ 
+-#include <linux/compiler.h>
+-#include <asm/page.h>
+-#include <asm/types.h>
+-#include <asm/cache.h>
+-#include <asm/ptrace.h>
+ #include <asm/cpu-features.h>
++#include <asm/fpu.h>
  
+-/*
+- * Default implementation of macro that returns current
+- * instruction pointer ("program counter").
+- */
+-#define current_text_addr() ({ void *pc; __asm__("mova	1f, %0\n1:":"=z" (pc)); pc; })
+-
+-/* Core Processor Version Register */
+-#define CCN_PVR		0xff000030
+-#define CCN_CVR		0xff000040
+-#define CCN_PRR		0xff000044
+-
++#ifndef __ASSEMBLY__
  /*
-@@ -96,18 +90,23 @@ static inline int ocfs2_local_alloc_window_bits(struct ocfs2_super *osb)
- int ocfs2_alloc_should_use_local(struct ocfs2_super *osb, u64 bits)
- {
- 	int la_bits = ocfs2_local_alloc_window_bits(osb);
-+	int ret = 0;
- 
- 	if (osb->local_alloc_state != OCFS2_LA_ENABLED)
--		return 0;
-+		goto bail;
+  *  CPU type and hardware bug flags. Kept separately for each CPU.
+  *
+@@ -39,247 +17,49 @@ enum cpu_type {
+ 	CPU_SH7619,
  
- 	/* la_bits should be at least twice the size (in clusters) of
- 	 * a new block group. We want to be sure block group
- 	 * allocations go through the local alloc, so allow an
- 	 * allocation to take up to half the bitmap. */
- 	if (bits > (la_bits / 2))
--		return 0;
-+		goto bail;
+ 	/* SH-2A types */
+-	CPU_SH7206,
++	CPU_SH7203, CPU_SH7206, CPU_SH7263,
  
--	return 1;
-+	ret = 1;
-+bail:
-+	mlog(0, "state=%d, bits=%llu, la_bits=%d, ret=%d\n",
-+	     osb->local_alloc_state, (unsigned long long)bits, la_bits, ret);
-+	return ret;
- }
+ 	/* SH-3 types */
+ 	CPU_SH7705, CPU_SH7706, CPU_SH7707,
+ 	CPU_SH7708, CPU_SH7708S, CPU_SH7708R,
+ 	CPU_SH7709, CPU_SH7709A, CPU_SH7710, CPU_SH7712,
+-	CPU_SH7720, CPU_SH7729,
++	CPU_SH7720, CPU_SH7721, CPU_SH7729,
  
- int ocfs2_load_local_alloc(struct ocfs2_super *osb)
-@@ -121,6 +120,19 @@ int ocfs2_load_local_alloc(struct ocfs2_super *osb)
+ 	/* SH-4 types */
+ 	CPU_SH7750, CPU_SH7750S, CPU_SH7750R, CPU_SH7751, CPU_SH7751R,
+ 	CPU_SH7760, CPU_SH4_202, CPU_SH4_501,
  
- 	mlog_entry_void();
+ 	/* SH-4A types */
+-	CPU_SH7770, CPU_SH7780, CPU_SH7781, CPU_SH7785, CPU_SHX3,
++	CPU_SH7763, CPU_SH7770, CPU_SH7780, CPU_SH7781, CPU_SH7785, CPU_SHX3,
  
-+	if (ocfs2_mount_local(osb))
-+		goto bail;
-+
-+	if (osb->local_alloc_size == 0)
-+		goto bail;
-+
-+	if (ocfs2_local_alloc_window_bits(osb) >= 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;
-+	}
-+
- 	/* read the alloc off disk */
- 	inode = ocfs2_get_system_file_inode(osb, LOCAL_ALLOC_SYSTEM_INODE,
- 					    osb->slot_num);
-@@ -181,6 +193,9 @@ bail:
- 	if (inode)
- 		iput(inode);
+ 	/* SH4AL-DSP types */
+ 	CPU_SH7343, CPU_SH7722,
  
-+	mlog(0, "Local alloc window bits = %d\n",
-+	     ocfs2_local_alloc_window_bits(osb));
++	/* SH-5 types */
++        CPU_SH5_101, CPU_SH5_103,
 +
- 	mlog_exit(status);
- 	return status;
- }
-@@ -231,7 +246,7 @@ void ocfs2_shutdown_local_alloc(struct ocfs2_super *osb)
- 
- 	mutex_lock(&main_bm_inode->i_mutex);
- 
--	status = ocfs2_meta_lock(main_bm_inode, &main_bm_bh, 1);
-+	status = ocfs2_inode_lock(main_bm_inode, &main_bm_bh, 1);
- 	if (status < 0) {
- 		mlog_errno(status);
- 		goto out_mutex;
-@@ -286,7 +301,7 @@ out_unlock:
- 	if (main_bm_bh)
- 		brelse(main_bm_bh);
- 
--	ocfs2_meta_unlock(main_bm_inode, 1);
-+	ocfs2_inode_unlock(main_bm_inode, 1);
- 
- out_mutex:
- 	mutex_unlock(&main_bm_inode->i_mutex);
-@@ -399,7 +414,7 @@ int ocfs2_complete_local_alloc_recovery(struct ocfs2_super *osb,
- 
- 	mutex_lock(&main_bm_inode->i_mutex);
+ 	/* Unknown subtype */
+ 	CPU_SH_NONE
+ };
  
--	status = ocfs2_meta_lock(main_bm_inode, &main_bm_bh, 1);
-+	status = ocfs2_inode_lock(main_bm_inode, &main_bm_bh, 1);
- 	if (status < 0) {
- 		mlog_errno(status);
- 		goto out_mutex;
-@@ -424,7 +439,7 @@ int ocfs2_complete_local_alloc_recovery(struct ocfs2_super *osb,
- 	ocfs2_commit_trans(osb, handle);
+-struct sh_cpuinfo {
+-	unsigned int type;
+-	unsigned long loops_per_jiffy;
+-	unsigned long asid_cache;
+-
+-	struct cache_info icache;	/* Primary I-cache */
+-	struct cache_info dcache;	/* Primary D-cache */
+-	struct cache_info scache;	/* Secondary cache */
+-
+-	unsigned long flags;
+-} __attribute__ ((aligned(L1_CACHE_BYTES)));
+-
+-extern struct sh_cpuinfo cpu_data[];
+-#define boot_cpu_data cpu_data[0]
+-#define current_cpu_data cpu_data[smp_processor_id()]
+-#define raw_current_cpu_data cpu_data[raw_smp_processor_id()]
+-
+-/*
+- * User space process size: 2GB.
+- *
+- * Since SH7709 and SH7750 have "area 7", we can't use 0x7c000000--0x7fffffff
+- */
+-#define TASK_SIZE	0x7c000000UL
+-
+-/* This decides where the kernel will search for a free chunk of vm
+- * space during mmap's.
+- */
+-#define TASK_UNMAPPED_BASE	(TASK_SIZE / 3)
+-
+-/*
+- * Bit of SR register
+- *
+- * FD-bit:
+- *     When it's set, it means the processor doesn't have right to use FPU,
+- *     and it results exception when the floating operation is executed.
+- *
+- * IMASK-bit:
+- *     Interrupt level mask
+- */
+-#define SR_FD		0x00008000
+-#define SR_DSP		0x00001000
+-#define SR_IMASK	0x000000f0
+-
+-/*
+- * FPU structure and data
+- */
+-
+-struct sh_fpu_hard_struct {
+-	unsigned long fp_regs[16];
+-	unsigned long xfp_regs[16];
+-	unsigned long fpscr;
+-	unsigned long fpul;
+-
+-	long status; /* software status information */
+-};
+-
+-/* Dummy fpu emulator  */
+-struct sh_fpu_soft_struct {
+-	unsigned long fp_regs[16];
+-	unsigned long xfp_regs[16];
+-	unsigned long fpscr;
+-	unsigned long fpul;
+-
+-	unsigned char lookahead;
+-	unsigned long entry_pc;
+-};
+-
+-union sh_fpu_union {
+-	struct sh_fpu_hard_struct hard;
+-	struct sh_fpu_soft_struct soft;
+-};
+-
+-struct thread_struct {
+-	/* Saved registers when thread is descheduled */
+-	unsigned long sp;
+-	unsigned long pc;
+-
+-	/* Hardware debugging registers */
+-	unsigned long ubc_pc;
+-
+-	/* floating point info */
+-	union sh_fpu_union fpu;
+-};
+-
+-typedef struct {
+-	unsigned long seg;
+-} mm_segment_t;
+-
+-/* Count of active tasks with UBC settings */
+-extern int ubc_usercnt;
++/* Forward decl */
++struct sh_cpuinfo;
  
- out_unlock:
--	ocfs2_meta_unlock(main_bm_inode, 1);
-+	ocfs2_inode_unlock(main_bm_inode, 1);
+-#define INIT_THREAD  {						\
+-	.sp = sizeof(init_stack) + (long) &init_stack,		\
+-}
+-
+-/*
+- * Do necessary setup to start up a newly executed thread.
+- */
+-#define start_thread(regs, new_pc, new_sp)	 \
+-	set_fs(USER_DS);			 \
+-	regs->pr = 0;				 \
+-	regs->sr = SR_FD;	/* User mode. */ \
+-	regs->pc = new_pc;			 \
+-	regs->regs[15] = new_sp
+-
+-/* Forward declaration, a strange C thing */
+-struct task_struct;
+-struct mm_struct;
+-
+-/* Free all resources held by a thread. */
+-extern void release_thread(struct task_struct *);
+-
+-/* Prepare to copy thread state - unlazy all lazy status */
+-#define prepare_to_copy(tsk)	do { } while (0)
+-
+-/*
+- * create a kernel thread without removing it from tasklists
+- */
+-extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
+-
+-/* Copy and release all segment info associated with a VM */
+-#define copy_segments(p, mm)	do { } while(0)
+-#define release_segments(mm)	do { } while(0)
+-
+-/*
+- * FPU lazy state save handling.
+- */
+-
+-static __inline__ void disable_fpu(void)
+-{
+-	unsigned long __dummy;
+-
+-	/* Set FD flag in SR */
+-	__asm__ __volatile__("stc	sr, %0\n\t"
+-			     "or	%1, %0\n\t"
+-			     "ldc	%0, sr"
+-			     : "=&r" (__dummy)
+-			     : "r" (SR_FD));
+-}
+-
+-static __inline__ void enable_fpu(void)
+-{
+-	unsigned long __dummy;
+-
+-	/* Clear out FD flag in SR */
+-	__asm__ __volatile__("stc	sr, %0\n\t"
+-			     "and	%1, %0\n\t"
+-			     "ldc	%0, sr"
+-			     : "=&r" (__dummy)
+-			     : "r" (~SR_FD));
+-}
+-
+-static __inline__ void release_fpu(struct pt_regs *regs)
+-{
+-	regs->sr |= SR_FD;
+-}
+-
+-static __inline__ void grab_fpu(struct pt_regs *regs)
+-{
+-	regs->sr &= ~SR_FD;
+-}
+-
+-extern void save_fpu(struct task_struct *__tsk, struct pt_regs *regs);
+-
+-#define unlazy_fpu(tsk, regs) do {			\
+-	if (test_tsk_thread_flag(tsk, TIF_USEDFPU)) {	\
+-		save_fpu(tsk, regs);			\
+-	}						\
+-} while (0)
+-
+-#define clear_fpu(tsk, regs) do {				\
+-	if (test_tsk_thread_flag(tsk, TIF_USEDFPU)) {		\
+-		clear_tsk_thread_flag(tsk, TIF_USEDFPU);	\
+-		release_fpu(regs);				\
+-	}							\
+-} while (0)
+-
+-/* Double presision, NANS as NANS, rounding to nearest, no exceptions */
+-#define FPSCR_INIT  0x00080000
+-
+-#define	FPSCR_CAUSE_MASK	0x0001f000	/* Cause bits */
+-#define	FPSCR_FLAG_MASK		0x0000007c	/* Flag bits */
+-
+-/*
+- * Return saved PC of a blocked thread.
+- */
+-#define thread_saved_pc(tsk)	(tsk->thread.pc)
+-
+-void show_trace(struct task_struct *tsk, unsigned long *sp,
+-		struct pt_regs *regs);
+-extern unsigned long get_wchan(struct task_struct *p);
+-
+-#define KSTK_EIP(tsk)  (task_pt_regs(tsk)->pc)
+-#define KSTK_ESP(tsk)  (task_pt_regs(tsk)->regs[15])
+-
+-#define cpu_sleep()	__asm__ __volatile__ ("sleep" : : : "memory")
+-#define cpu_relax()	barrier()
+-
+-#if defined(CONFIG_CPU_SH2A) || defined(CONFIG_CPU_SH3) || \
+-    defined(CONFIG_CPU_SH4)
+-#define PREFETCH_STRIDE		L1_CACHE_BYTES
+-#define ARCH_HAS_PREFETCH
+-#define ARCH_HAS_PREFETCHW
+-static inline void prefetch(void *x)
+-{
+-	__asm__ __volatile__ ("pref @%0\n\t" : : "r" (x) : "memory");
+-}
+-
+-#define prefetchw(x)	prefetch(x)
+-#endif
++/* arch/sh/kernel/setup.c */
++const char *get_cpu_subtype(struct sh_cpuinfo *c);
  
- out_mutex:
- 	mutex_unlock(&main_bm_inode->i_mutex);
-@@ -521,6 +536,9 @@ bail:
- 		iput(local_alloc_inode);
- 	}
+ #ifdef CONFIG_VSYSCALL
+-extern int vsyscall_init(void);
++int vsyscall_init(void);
+ #else
+ #define vsyscall_init() do { } while (0)
+ #endif
  
-+	mlog(0, "bits=%d, slot=%d, ret=%d\n", bits_wanted, osb->slot_num,
-+	     status);
+-/* arch/sh/kernel/setup.c */
+-const char *get_cpu_subtype(struct sh_cpuinfo *c);
++#endif /* __ASSEMBLY__ */
 +
- 	mlog_exit(status);
- 	return status;
- }
-diff --git a/fs/ocfs2/locks.c b/fs/ocfs2/locks.c
++#ifdef CONFIG_SUPERH32
++# include "processor_32.h"
++#else
++# include "processor_64.h"
++#endif
+ 
+-#endif /* __KERNEL__ */
+ #endif /* __ASM_SH_PROCESSOR_H */
+diff --git a/include/asm-sh/processor_32.h b/include/asm-sh/processor_32.h
 new file mode 100644
-index 0000000..203f871
+index 0000000..a7edaa1
 --- /dev/null
-+++ b/fs/ocfs2/locks.c
-@@ -0,0 +1,125 @@
-+/* -*- mode: c; c-basic-offset: 8; -*-
-+ * vim: noexpandtab sw=8 ts=8 sts=0:
-+ *
-+ * locks.c
-+ *
-+ * Userspace file locking support
++++ b/include/asm-sh/processor_32.h
+@@ -0,0 +1,215 @@
++/*
++ * include/asm-sh/processor.h
 + *
-+ * Copyright (C) 2007 Oracle.  All rights reserved.
++ * Copyright (C) 1999, 2000  Niibe Yutaka
++ * Copyright (C) 2002, 2003  Paul Mundt
++ */
++
++#ifndef __ASM_SH_PROCESSOR_32_H
++#define __ASM_SH_PROCESSOR_32_H
++#ifdef __KERNEL__
++
++#include <linux/compiler.h>
++#include <asm/page.h>
++#include <asm/types.h>
++#include <asm/cache.h>
++#include <asm/ptrace.h>
++
++/*
++ * Default implementation of macro that returns current
++ * instruction pointer ("program counter").
++ */
++#define current_text_addr() ({ void *pc; __asm__("mova	1f, %0\n1:":"=z" (pc)); pc; })
++
++/* Core Processor Version Register */
++#define CCN_PVR		0xff000030
++#define CCN_CVR		0xff000040
++#define CCN_PRR		0xff000044
++
++struct sh_cpuinfo {
++	unsigned int type;
++	unsigned long loops_per_jiffy;
++	unsigned long asid_cache;
++
++	struct cache_info icache;	/* Primary I-cache */
++	struct cache_info dcache;	/* Primary D-cache */
++	struct cache_info scache;	/* Secondary cache */
++
++	unsigned long flags;
++} __attribute__ ((aligned(L1_CACHE_BYTES)));
++
++extern struct sh_cpuinfo cpu_data[];
++#define boot_cpu_data cpu_data[0]
++#define current_cpu_data cpu_data[smp_processor_id()]
++#define raw_current_cpu_data cpu_data[raw_smp_processor_id()]
++
++/*
++ * User space process size: 2GB.
 + *
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public
-+ * License as published by the Free Software Foundation; either
-+ * version 2 of the License, or (at your option) any later version.
++ * Since SH7709 and SH7750 have "area 7", we can't use 0x7c000000--0x7fffffff
++ */
++#define TASK_SIZE	0x7c000000UL
++
++/* This decides where the kernel will search for a free chunk of vm
++ * space during mmap's.
++ */
++#define TASK_UNMAPPED_BASE	(TASK_SIZE / 3)
++
++/*
++ * Bit of SR register
 + *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-+ * General Public License for more details.
++ * FD-bit:
++ *     When it's set, it means the processor doesn't have right to use FPU,
++ *     and it results exception when the floating operation is executed.
 + *
-+ * You 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.
++ * IMASK-bit:
++ *     Interrupt level mask
 + */
++#define SR_DSP		0x00001000
++#define SR_IMASK	0x000000f0
 +
-+#include <linux/fs.h>
++/*
++ * FPU structure and data
++ */
 +
-+#define MLOG_MASK_PREFIX ML_INODE
-+#include <cluster/masklog.h>
++struct sh_fpu_hard_struct {
++	unsigned long fp_regs[16];
++	unsigned long xfp_regs[16];
++	unsigned long fpscr;
++	unsigned long fpul;
 +
-+#include "ocfs2.h"
++	long status; /* software status information */
++};
 +
-+#include "dlmglue.h"
-+#include "file.h"
-+#include "locks.h"
++/* Dummy fpu emulator  */
++struct sh_fpu_soft_struct {
++	unsigned long fp_regs[16];
++	unsigned long xfp_regs[16];
++	unsigned long fpscr;
++	unsigned long fpul;
 +
-+static int ocfs2_do_flock(struct file *file, struct inode *inode,
-+			  int cmd, struct file_lock *fl)
-+{
-+	int ret = 0, level = 0, trylock = 0;
-+	struct ocfs2_file_private *fp = file->private_data;
-+	struct ocfs2_lock_res *lockres = &fp->fp_flock;
++	unsigned char lookahead;
++	unsigned long entry_pc;
++};
 +
-+	if (fl->fl_type == F_WRLCK)
-+		level = 1;
-+	if (!IS_SETLKW(cmd))
-+		trylock = 1;
++union sh_fpu_union {
++	struct sh_fpu_hard_struct hard;
++	struct sh_fpu_soft_struct soft;
++};
 +
-+	mutex_lock(&fp->fp_mutex);
++struct thread_struct {
++	/* Saved registers when thread is descheduled */
++	unsigned long sp;
++	unsigned long pc;
 +
-+	if (lockres->l_flags & OCFS2_LOCK_ATTACHED &&
-+	    lockres->l_level > LKM_NLMODE) {
-+		int old_level = 0;
++	/* Hardware debugging registers */
++	unsigned long ubc_pc;
 +
-+		if (lockres->l_level == LKM_EXMODE)
-+			old_level = 1;
++	/* floating point info */
++	union sh_fpu_union fpu;
++};
 +
-+		if (level == old_level)
-+			goto out;
++typedef struct {
++	unsigned long seg;
++} mm_segment_t;
 +
-+		/*
-+		 * Converting an existing lock is not guaranteed to be
-+		 * atomic, so we can get away with simply unlocking
-+		 * here and allowing the lock code to try at the new
-+		 * level.
-+		 */
++/* Count of active tasks with UBC settings */
++extern int ubc_usercnt;
 +
-+		flock_lock_file_wait(file,
-+				     &(struct file_lock){.fl_type = F_UNLCK});
++#define INIT_THREAD  {						\
++	.sp = sizeof(init_stack) + (long) &init_stack,		\
++}
 +
-+		ocfs2_file_unlock(file);
-+	}
++/*
++ * Do necessary setup to start up a newly executed thread.
++ */
++#define start_thread(regs, new_pc, new_sp)	 \
++	set_fs(USER_DS);			 \
++	regs->pr = 0;				 \
++	regs->sr = SR_FD;	/* User mode. */ \
++	regs->pc = new_pc;			 \
++	regs->regs[15] = new_sp
 +
-+	ret = ocfs2_file_lock(file, level, trylock);
-+	if (ret) {
-+		if (ret == -EAGAIN && trylock)
-+			ret = -EWOULDBLOCK;
-+		else
-+			mlog_errno(ret);
-+		goto out;
-+	}
++/* Forward declaration, a strange C thing */
++struct task_struct;
++struct mm_struct;
 +
-+	ret = flock_lock_file_wait(file, fl);
++/* Free all resources held by a thread. */
++extern void release_thread(struct task_struct *);
 +
-+out:
-+	mutex_unlock(&fp->fp_mutex);
++/* Prepare to copy thread state - unlazy all lazy status */
++#define prepare_to_copy(tsk)	do { } while (0)
 +
-+	return ret;
-+}
++/*
++ * create a kernel thread without removing it from tasklists
++ */
++extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
 +
-+static int ocfs2_do_funlock(struct file *file, int cmd, struct file_lock *fl)
++/* Copy and release all segment info associated with a VM */
++#define copy_segments(p, mm)	do { } while(0)
++#define release_segments(mm)	do { } while(0)
++
++/*
++ * FPU lazy state save handling.
++ */
++
++static __inline__ void disable_fpu(void)
 +{
-+	int ret;
-+	struct ocfs2_file_private *fp = file->private_data;
++	unsigned long __dummy;
 +
-+	mutex_lock(&fp->fp_mutex);
-+	ocfs2_file_unlock(file);
-+	ret = flock_lock_file_wait(file, fl);
-+	mutex_unlock(&fp->fp_mutex);
++	/* Set FD flag in SR */
++	__asm__ __volatile__("stc	sr, %0\n\t"
++			     "or	%1, %0\n\t"
++			     "ldc	%0, sr"
++			     : "=&r" (__dummy)
++			     : "r" (SR_FD));
++}
 +
-+	return ret;
++static __inline__ void enable_fpu(void)
++{
++	unsigned long __dummy;
++
++	/* Clear out FD flag in SR */
++	__asm__ __volatile__("stc	sr, %0\n\t"
++			     "and	%1, %0\n\t"
++			     "ldc	%0, sr"
++			     : "=&r" (__dummy)
++			     : "r" (~SR_FD));
 +}
 +
++/* Double presision, NANS as NANS, rounding to nearest, no exceptions */
++#define FPSCR_INIT  0x00080000
++
++#define	FPSCR_CAUSE_MASK	0x0001f000	/* Cause bits */
++#define	FPSCR_FLAG_MASK		0x0000007c	/* Flag bits */
++
 +/*
-+ * Overall flow of ocfs2_flock() was influenced by gfs2_flock().
++ * Return saved PC of a blocked thread.
 + */
-+int ocfs2_flock(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);
++#define thread_saved_pc(tsk)	(tsk->thread.pc)
 +
-+	if (!(fl->fl_flags & FL_FLOCK))
-+		return -ENOLCK;
-+	if (__mandatory_lock(inode))
-+		return -ENOLCK;
++void show_trace(struct task_struct *tsk, unsigned long *sp,
++		struct pt_regs *regs);
++extern unsigned long get_wchan(struct task_struct *p);
 +
-+	if ((osb->s_mount_opt & OCFS2_MOUNT_LOCALFLOCKS) ||
-+	    ocfs2_mount_local(osb))
-+		return flock_lock_file_wait(file, fl);
++#define KSTK_EIP(tsk)  (task_pt_regs(tsk)->pc)
++#define KSTK_ESP(tsk)  (task_pt_regs(tsk)->regs[15])
 +
-+	if (fl->fl_type == F_UNLCK)
-+		return ocfs2_do_funlock(file, cmd, fl);
-+	else
-+		return ocfs2_do_flock(file, inode, cmd, fl);
++#define cpu_sleep()	__asm__ __volatile__ ("sleep" : : : "memory")
++#define cpu_relax()	barrier()
++
++#if defined(CONFIG_CPU_SH2A) || defined(CONFIG_CPU_SH3) || \
++    defined(CONFIG_CPU_SH4)
++#define PREFETCH_STRIDE		L1_CACHE_BYTES
++#define ARCH_HAS_PREFETCH
++#define ARCH_HAS_PREFETCHW
++static inline void prefetch(void *x)
++{
++	__asm__ __volatile__ ("pref @%0\n\t" : : "r" (x) : "memory");
 +}
-diff --git a/fs/ocfs2/locks.h b/fs/ocfs2/locks.h
++
++#define prefetchw(x)	prefetch(x)
++#endif
++
++#endif /* __KERNEL__ */
++#endif /* __ASM_SH_PROCESSOR_32_H */
+diff --git a/include/asm-sh/processor_64.h b/include/asm-sh/processor_64.h
 new file mode 100644
-index 0000000..9743ef2
+index 0000000..99c22b1
 --- /dev/null
-+++ b/fs/ocfs2/locks.h
-@@ -0,0 +1,31 @@
-+/* -*- mode: c; c-basic-offset: 8; -*-
-+ * vim: noexpandtab sw=8 ts=8 sts=0:
++++ b/include/asm-sh/processor_64.h
+@@ -0,0 +1,275 @@
++#ifndef __ASM_SH_PROCESSOR_64_H
++#define __ASM_SH_PROCESSOR_64_H
++
++/*
++ * include/asm-sh/processor_64.h
 + *
-+ * locks.h
++ * Copyright (C) 2000, 2001  Paolo Alberelli
++ * Copyright (C) 2003  Paul Mundt
++ * Copyright (C) 2004  Richard Curnow
 + *
-+ * Function prototypes for Userspace file locking support
++ * 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 __ASSEMBLY__
++
++#include <linux/compiler.h>
++#include <asm/page.h>
++#include <asm/types.h>
++#include <asm/cache.h>
++#include <asm/ptrace.h>
++#include <asm/cpu/registers.h>
++
++/*
++ * Default implementation of macro that returns current
++ * instruction pointer ("program counter").
++ */
++#define current_text_addr() ({ \
++void *pc; \
++unsigned long long __dummy = 0; \
++__asm__("gettr	tr0, %1\n\t" \
++	"pta	4, tr0\n\t" \
++	"gettr	tr0, %0\n\t" \
++	"ptabs	%1, tr0\n\t"	\
++	:"=r" (pc), "=r" (__dummy) \
++	: "1" (__dummy)); \
++pc; })
++
++/*
++ * TLB information structure
++ *
++ * Defined for both I and D tlb, per-processor.
++ */
++struct tlb_info {
++	unsigned long long next;
++	unsigned long long first;
++	unsigned long long last;
++
++	unsigned int entries;
++	unsigned int step;
++
++	unsigned long flags;
++};
++
++struct sh_cpuinfo {
++	enum cpu_type type;
++	unsigned long loops_per_jiffy;
++	unsigned long asid_cache;
++
++	unsigned int cpu_clock, master_clock, bus_clock, module_clock;
++
++	/* Cache info */
++	struct cache_info icache;
++	struct cache_info dcache;
++	struct cache_info scache;
++
++	/* TLB info */
++	struct tlb_info itlb;
++	struct tlb_info dtlb;
++
++	unsigned long flags;
++};
++
++extern struct sh_cpuinfo cpu_data[];
++#define boot_cpu_data cpu_data[0]
++#define current_cpu_data cpu_data[smp_processor_id()]
++#define raw_current_cpu_data cpu_data[raw_smp_processor_id()]
++
++#endif
++
++/*
++ * User space process size: 2GB - 4k.
++ */
++#define TASK_SIZE	0x7ffff000UL
++
++/* This decides where the kernel will search for a free chunk of vm
++ * space during mmap's.
++ */
++#define TASK_UNMAPPED_BASE	(TASK_SIZE / 3)
++
++/*
++ * Bit of SR register
 + *
-+ * Copyright (C) 2002, 2004 Oracle.  All rights reserved.
++ * FD-bit:
++ *     When it's set, it means the processor doesn't have right to use FPU,
++ *     and it results exception when the floating operation is executed.
 + *
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public
-+ * License as published by the Free Software Foundation; either
-+ * version 2 of the License, or (at your option) any later version.
++ * IMASK-bit:
++ *     Interrupt level mask
 + *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-+ * General Public License for more details.
++ * STEP-bit:
++ *     Single step bit
 + *
-+ * You 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.
 + */
++#if defined(CONFIG_SH64_SR_WATCH)
++#define SR_MMU   0x84000000
++#else
++#define SR_MMU   0x80000000
++#endif
 +
-+#ifndef OCFS2_LOCKS_H
-+#define OCFS2_LOCKS_H
++#define SR_IMASK 0x000000f0
++#define SR_SSTEP 0x08000000
 +
-+int ocfs2_flock(struct file *file, int cmd, struct file_lock *fl);
++#ifndef __ASSEMBLY__
 +
-+#endif /* OCFS2_LOCKS_H */
-diff --git a/fs/ocfs2/mmap.c b/fs/ocfs2/mmap.c
-index 9875615..3dc18d6 100644
---- a/fs/ocfs2/mmap.c
-+++ b/fs/ocfs2/mmap.c
-@@ -168,7 +168,7 @@ static int ocfs2_page_mkwrite(struct vm_area_struct *vma, struct page *page)
- 	 * node. Taking the data lock will also ensure that we don't
- 	 * attempt page truncation as part of a downconvert.
- 	 */
--	ret = ocfs2_meta_lock(inode, &di_bh, 1);
-+	ret = ocfs2_inode_lock(inode, &di_bh, 1);
- 	if (ret < 0) {
- 		mlog_errno(ret);
- 		goto out;
-@@ -181,21 +181,12 @@ static int ocfs2_page_mkwrite(struct vm_area_struct *vma, struct page *page)
- 	 */
- 	down_write(&OCFS2_I(inode)->ip_alloc_sem);
- 
--	ret = ocfs2_data_lock(inode, 1);
--	if (ret < 0) {
--		mlog_errno(ret);
--		goto out_meta_unlock;
--	}
--
- 	ret = __ocfs2_page_mkwrite(inode, di_bh, page);
- 
--	ocfs2_data_unlock(inode, 1);
++/*
++ * FPU structure and data : require 8-byte alignment as we need to access it
++   with fld.p, fst.p
++ */
++
++struct sh_fpu_hard_struct {
++	unsigned long fp_regs[64];
++	unsigned int fpscr;
++	/* long status; * software status information */
++};
++
++#if 0
++/* Dummy fpu emulator  */
++struct sh_fpu_soft_struct {
++	unsigned long long fp_regs[32];
++	unsigned int fpscr;
++	unsigned char lookahead;
++	unsigned long entry_pc;
++};
++#endif
++
++union sh_fpu_union {
++	struct sh_fpu_hard_struct hard;
++	/* 'hard' itself only produces 32 bit alignment, yet we need
++	   to access it using 64 bit load/store as well. */
++	unsigned long long alignment_dummy;
++};
++
++struct thread_struct {
++	unsigned long sp;
++	unsigned long pc;
++	/* This stores the address of the pt_regs built during a context
++	   switch, or of the register save area built for a kernel mode
++	   exception.  It is used for backtracing the stack of a sleeping task
++	   or one that traps in kernel mode. */
++        struct pt_regs *kregs;
++	/* This stores the address of the pt_regs constructed on entry from
++	   user mode.  It is a fixed value over the lifetime of a process, or
++	   NULL for a kernel thread. */
++	struct pt_regs *uregs;
++
++	unsigned long trap_no, error_code;
++	unsigned long address;
++	/* Hardware debugging registers may come here */
++
++	/* floating point info */
++	union sh_fpu_union fpu;
++};
++
++typedef struct {
++	unsigned long seg;
++} mm_segment_t;
++
++#define INIT_MMAP \
++{ &init_mm, 0, 0, NULL, PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC, 1, NULL, NULL }
++
++extern  struct pt_regs fake_swapper_regs;
++
++#define INIT_THREAD  {				\
++	.sp		= sizeof(init_stack) +	\
++			  (long) &init_stack,	\
++	.pc		= 0,			\
++        .kregs		= &fake_swapper_regs,	\
++	.uregs	        = NULL,			\
++	.trap_no	= 0,			\
++	.error_code	= 0,			\
++	.address	= 0,			\
++	.fpu		= { { { 0, } }, }	\
++}
++
++/*
++ * Do necessary setup to start up a newly executed thread.
++ */
++#define SR_USER (SR_MMU | SR_FD)
++
++#define start_thread(regs, new_pc, new_sp)			\
++	set_fs(USER_DS);					\
++	regs->sr = SR_USER;	/* User mode. */		\
++	regs->pc = new_pc - 4;	/* Compensate syscall exit */	\
++	regs->pc |= 1;		/* Set SHmedia ! */		\
++	regs->regs[18] = 0;					\
++	regs->regs[15] = new_sp
++
++/* Forward declaration, a strange C thing */
++struct task_struct;
++struct mm_struct;
++
++/* Free all resources held by a thread. */
++extern void release_thread(struct task_struct *);
++/*
++ * create a kernel thread without removing it from tasklists
++ */
++extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
++
++
++/* Copy and release all segment info associated with a VM */
++#define copy_segments(p, mm)	do { } while (0)
++#define release_segments(mm)	do { } while (0)
++#define forget_segments()	do { } while (0)
++#define prepare_to_copy(tsk)	do { } while (0)
++/*
++ * FPU lazy state save handling.
++ */
++
++static inline void disable_fpu(void)
++{
++	unsigned long long __dummy;
++
++	/* Set FD flag in SR */
++	__asm__ __volatile__("getcon	" __SR ", %0\n\t"
++			     "or	%0, %1, %0\n\t"
++			     "putcon	%0, " __SR "\n\t"
++			     : "=&r" (__dummy)
++			     : "r" (SR_FD));
++}
++
++static inline void enable_fpu(void)
++{
++	unsigned long long __dummy;
++
++	/* Clear out FD flag in SR */
++	__asm__ __volatile__("getcon	" __SR ", %0\n\t"
++			     "and	%0, %1, %0\n\t"
++			     "putcon	%0, " __SR "\n\t"
++			     : "=&r" (__dummy)
++			     : "r" (~SR_FD));
++}
++
++/* Round to nearest, no exceptions on inexact, overflow, underflow,
++   zero-divide, invalid.  Configure option for whether to flush denorms to
++   zero, or except if a denorm is encountered.  */
++#if defined(CONFIG_SH64_FPU_DENORM_FLUSH)
++#define FPSCR_INIT  0x00040000
++#else
++#define FPSCR_INIT  0x00000000
++#endif
++
++#ifdef CONFIG_SH_FPU
++/* Initialise the FP state of a task */
++void fpinit(struct sh_fpu_hard_struct *fpregs);
++#else
++#define fpinit(fpregs)	do { } while (0)
++#endif
++
++extern struct task_struct *last_task_used_math;
++
++/*
++ * Return saved PC of a blocked thread.
++ */
++#define thread_saved_pc(tsk)	(tsk->thread.pc)
++
++extern unsigned long get_wchan(struct task_struct *p);
++
++#define KSTK_EIP(tsk)  ((tsk)->thread.pc)
++#define KSTK_ESP(tsk)  ((tsk)->thread.sp)
++
++#define cpu_relax()	barrier()
++
++#endif	/* __ASSEMBLY__ */
++#endif /* __ASM_SH_PROCESSOR_64_H */
+diff --git a/include/asm-sh/ptrace.h b/include/asm-sh/ptrace.h
+index b9789c8..8d6c92b 100644
+--- a/include/asm-sh/ptrace.h
++++ b/include/asm-sh/ptrace.h
+@@ -5,7 +5,16 @@
+  * Copyright (C) 1999, 2000  Niibe Yutaka
+  *
+  */
 -
--out_meta_unlock:
- 	up_write(&OCFS2_I(inode)->ip_alloc_sem);
- 
- 	brelse(di_bh);
--	ocfs2_meta_unlock(inode, 1);
-+	ocfs2_inode_unlock(inode, 1);
- 
- out:
- 	ret2 = ocfs2_vm_op_unblock_sigs(&oldset);
-@@ -214,13 +205,13 @@ int ocfs2_mmap(struct file *file, struct vm_area_struct *vma)
- {
- 	int ret = 0, lock_level = 0;
- 
--	ret = ocfs2_meta_lock_atime(file->f_dentry->d_inode,
-+	ret = ocfs2_inode_lock_atime(file->f_dentry->d_inode,
- 				    file->f_vfsmnt, &lock_level);
- 	if (ret < 0) {
- 		mlog_errno(ret);
- 		goto out;
- 	}
--	ocfs2_meta_unlock(file->f_dentry->d_inode, lock_level);
-+	ocfs2_inode_unlock(file->f_dentry->d_inode, lock_level);
- out:
- 	vma->vm_ops = &ocfs2_file_vm_ops;
- 	vma->vm_flags |= VM_CAN_NONLINEAR;
-diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c
-index 989ac27..ae9ad95 100644
---- a/fs/ocfs2/namei.c
-+++ b/fs/ocfs2/namei.c
-@@ -60,7 +60,6 @@
- #include "symlink.h"
- #include "sysfile.h"
- #include "uptodate.h"
--#include "vote.h"
- 
- #include "buffer_head_io.h"
- 
-@@ -116,7 +115,7 @@ static struct dentry *ocfs2_lookup(struct inode *dir, struct dentry *dentry,
- 	mlog(0, "find name %.*s in directory %llu\n", dentry->d_name.len,
- 	     dentry->d_name.name, (unsigned long long)OCFS2_I(dir)->ip_blkno);
- 
--	status = ocfs2_meta_lock(dir, NULL, 0);
-+	status = ocfs2_inode_lock(dir, NULL, 0);
- 	if (status < 0) {
- 		if (status != -ENOENT)
- 			mlog_errno(status);
-@@ -129,7 +128,7 @@ static struct dentry *ocfs2_lookup(struct inode *dir, struct dentry *dentry,
- 	if (status < 0)
- 		goto bail_add;
- 
--	inode = ocfs2_iget(OCFS2_SB(dir->i_sb), blkno, 0);
-+	inode = ocfs2_iget(OCFS2_SB(dir->i_sb), blkno, 0, 0);
- 	if (IS_ERR(inode)) {
- 		ret = ERR_PTR(-EACCES);
- 		goto bail_unlock;
-@@ -176,8 +175,8 @@ bail_unlock:
- 	/* Don't drop the cluster lock until *after* the d_add --
- 	 * unlink on another node will message us to remove that
- 	 * dentry under this lock so otherwise we can race this with
--	 * the vote thread and have a stale dentry. */
--	ocfs2_meta_unlock(dir, 0);
-+	 * the downconvert thread and have a stale dentry. */
-+	ocfs2_inode_unlock(dir, 0);
- 
- bail:
- 
-@@ -209,7 +208,7 @@ static int ocfs2_mknod(struct inode *dir,
- 	/* get our super block */
- 	osb = OCFS2_SB(dir->i_sb);
- 
--	status = ocfs2_meta_lock(dir, &parent_fe_bh, 1);
-+	status = ocfs2_inode_lock(dir, &parent_fe_bh, 1);
- 	if (status < 0) {
- 		if (status != -ENOENT)
- 			mlog_errno(status);
-@@ -323,7 +322,7 @@ leave:
- 	if (handle)
- 		ocfs2_commit_trans(osb, handle);
- 
--	ocfs2_meta_unlock(dir, 1);
-+	ocfs2_inode_unlock(dir, 1);
- 
- 	if (status == -ENOSPC)
- 		mlog(0, "Disk is full\n");
-@@ -553,7 +552,7 @@ static int ocfs2_link(struct dentry *old_dentry,
- 	if (S_ISDIR(inode->i_mode))
- 		return -EPERM;
- 
--	err = ocfs2_meta_lock(dir, &parent_fe_bh, 1);
-+	err = ocfs2_inode_lock(dir, &parent_fe_bh, 1);
- 	if (err < 0) {
- 		if (err != -ENOENT)
- 			mlog_errno(err);
-@@ -578,7 +577,7 @@ static int ocfs2_link(struct dentry *old_dentry,
- 		goto out;
- 	}
- 
--	err = ocfs2_meta_lock(inode, &fe_bh, 1);
-+	err = ocfs2_inode_lock(inode, &fe_bh, 1);
- 	if (err < 0) {
- 		if (err != -ENOENT)
- 			mlog_errno(err);
-@@ -643,10 +642,10 @@ static int ocfs2_link(struct dentry *old_dentry,
- out_commit:
- 	ocfs2_commit_trans(osb, handle);
- out_unlock_inode:
--	ocfs2_meta_unlock(inode, 1);
-+	ocfs2_inode_unlock(inode, 1);
- 
- out:
--	ocfs2_meta_unlock(dir, 1);
-+	ocfs2_inode_unlock(dir, 1);
- 
- 	if (de_bh)
- 		brelse(de_bh);
-@@ -720,7 +719,7 @@ static int ocfs2_unlink(struct inode *dir,
- 		return -EPERM;
- 	}
- 
--	status = ocfs2_meta_lock(dir, &parent_node_bh, 1);
-+	status = ocfs2_inode_lock(dir, &parent_node_bh, 1);
- 	if (status < 0) {
- 		if (status != -ENOENT)
- 			mlog_errno(status);
-@@ -745,7 +744,7 @@ static int ocfs2_unlink(struct inode *dir,
- 		goto leave;
- 	}
- 
--	status = ocfs2_meta_lock(inode, &fe_bh, 1);
-+	status = ocfs2_inode_lock(inode, &fe_bh, 1);
- 	if (status < 0) {
- 		if (status != -ENOENT)
- 			mlog_errno(status);
-@@ -765,7 +764,7 @@ static int ocfs2_unlink(struct inode *dir,
- 
- 	status = ocfs2_remote_dentry_delete(dentry);
- 	if (status < 0) {
--		/* This vote should succeed under all normal
-+		/* This remote delete should succeed under all normal
- 		 * circumstances. */
- 		mlog_errno(status);
- 		goto leave;
-@@ -841,13 +840,13 @@ leave:
- 		ocfs2_commit_trans(osb, handle);
- 
- 	if (child_locked)
--		ocfs2_meta_unlock(inode, 1);
-+		ocfs2_inode_unlock(inode, 1);
- 
--	ocfs2_meta_unlock(dir, 1);
-+	ocfs2_inode_unlock(dir, 1);
++#if defined(__SH5__) || defined(CONFIG_SUPERH64)
++struct pt_regs {
++	unsigned long long pc;
++	unsigned long long sr;
++	unsigned long long syscall_nr;
++	unsigned long long regs[63];
++	unsigned long long tregs[8];
++	unsigned long long pad[2];
++};
++#else
+ /*
+  * GCC defines register number like this:
+  * -----------------------------
+@@ -28,7 +37,7 @@
+ 
+ #define REG_PR		17
+ #define REG_SR		18
+-#define REG_GBR      	19
++#define REG_GBR		19
+ #define REG_MACH	20
+ #define REG_MACL	21
  
- 	if (orphan_dir) {
- 		/* This was locked for us in ocfs2_prepare_orphan_dir() */
--		ocfs2_meta_unlock(orphan_dir, 1);
-+		ocfs2_inode_unlock(orphan_dir, 1);
- 		mutex_unlock(&orphan_dir->i_mutex);
- 		iput(orphan_dir);
- 	}
-@@ -908,7 +907,7 @@ static int ocfs2_double_lock(struct ocfs2_super *osb,
- 			inode1 = tmpinode;
- 		}
- 		/* lock id2 */
--		status = ocfs2_meta_lock(inode2, bh2, 1);
-+		status = ocfs2_inode_lock(inode2, bh2, 1);
- 		if (status < 0) {
- 			if (status != -ENOENT)
- 				mlog_errno(status);
-@@ -917,14 +916,14 @@ static int ocfs2_double_lock(struct ocfs2_super *osb,
- 	}
+@@ -80,10 +89,14 @@ struct pt_dspregs {
  
- 	/* lock id1 */
--	status = ocfs2_meta_lock(inode1, bh1, 1);
-+	status = ocfs2_inode_lock(inode1, bh1, 1);
- 	if (status < 0) {
- 		/*
- 		 * An error return must mean that no cluster locks
- 		 * were held on function exit.
- 		 */
- 		if (oi1->ip_blkno != oi2->ip_blkno)
--			ocfs2_meta_unlock(inode2, 1);
-+			ocfs2_inode_unlock(inode2, 1);
+ #define	PTRACE_GETDSPREGS	55
+ #define	PTRACE_SETDSPREGS	56
++#endif
  
- 		if (status != -ENOENT)
- 			mlog_errno(status);
-@@ -937,10 +936,10 @@ bail:
+ #ifdef __KERNEL__
+-#define user_mode(regs) (((regs)->sr & 0x40000000)==0)
+-#define instruction_pointer(regs) ((regs)->pc)
++#include <asm/addrspace.h>
++
++#define user_mode(regs)			(((regs)->sr & 0x40000000)==0)
++#define instruction_pointer(regs)	((unsigned long)(regs)->pc)
++
+ extern void show_regs(struct pt_regs *);
  
- static void ocfs2_double_unlock(struct inode *inode1, struct inode *inode2)
+ #ifdef CONFIG_SH_DSP
+@@ -100,10 +113,13 @@ static inline unsigned long profile_pc(struct pt_regs *regs)
  {
--	ocfs2_meta_unlock(inode1, 1);
-+	ocfs2_inode_unlock(inode1, 1);
+ 	unsigned long pc = instruction_pointer(regs);
  
- 	if (inode1 != inode2)
--		ocfs2_meta_unlock(inode2, 1);
-+		ocfs2_inode_unlock(inode2, 1);
+-	if (pc >= 0xa0000000UL && pc < 0xc0000000UL)
++#ifdef P2SEG
++	if (pc >= P2SEG && pc < P3SEG)
+ 		pc -= 0x20000000;
++#endif
++
+ 	return pc;
  }
+-#endif
++#endif /* __KERNEL__ */
  
- static int ocfs2_rename(struct inode *old_dir,
-@@ -1031,10 +1030,11 @@ static int ocfs2_rename(struct inode *old_dir,
- 
- 	/*
- 	 * Aside from allowing a meta data update, the locking here
--	 * also ensures that the vote thread on other nodes won't have
--	 * to concurrently downconvert the inode and the dentry locks.
-+	 * also ensures that the downconvert thread on other nodes
-+	 * won't have to concurrently downconvert the inode and the
-+	 * dentry locks.
- 	 */
--	status = ocfs2_meta_lock(old_inode, &old_inode_bh, 1);
-+	status = ocfs2_inode_lock(old_inode, &old_inode_bh, 1);
- 	if (status < 0) {
- 		if (status != -ENOENT)
- 			mlog_errno(status);
-@@ -1143,7 +1143,7 @@ static int ocfs2_rename(struct inode *old_dir,
- 			goto bail;
- 		}
- 
--		status = ocfs2_meta_lock(new_inode, &newfe_bh, 1);
-+		status = ocfs2_inode_lock(new_inode, &newfe_bh, 1);
- 		if (status < 0) {
- 			if (status != -ENOENT)
- 				mlog_errno(status);
-@@ -1355,14 +1355,14 @@ bail:
- 		ocfs2_double_unlock(old_dir, new_dir);
- 
- 	if (old_child_locked)
--		ocfs2_meta_unlock(old_inode, 1);
-+		ocfs2_inode_unlock(old_inode, 1);
- 
- 	if (new_child_locked)
--		ocfs2_meta_unlock(new_inode, 1);
-+		ocfs2_inode_unlock(new_inode, 1);
- 
- 	if (orphan_dir) {
- 		/* This was locked for us in ocfs2_prepare_orphan_dir() */
--		ocfs2_meta_unlock(orphan_dir, 1);
-+		ocfs2_inode_unlock(orphan_dir, 1);
- 		mutex_unlock(&orphan_dir->i_mutex);
- 		iput(orphan_dir);
- 	}
-@@ -1530,7 +1530,7 @@ static int ocfs2_symlink(struct inode *dir,
- 	credits = ocfs2_calc_symlink_credits(sb);
- 
- 	/* lock the parent directory */
--	status = ocfs2_meta_lock(dir, &parent_fe_bh, 1);
-+	status = ocfs2_inode_lock(dir, &parent_fe_bh, 1);
- 	if (status < 0) {
- 		if (status != -ENOENT)
- 			mlog_errno(status);
-@@ -1657,7 +1657,7 @@ bail:
- 	if (handle)
- 		ocfs2_commit_trans(osb, handle);
- 
--	ocfs2_meta_unlock(dir, 1);
-+	ocfs2_inode_unlock(dir, 1);
- 
- 	if (new_fe_bh)
- 		brelse(new_fe_bh);
-@@ -1735,7 +1735,7 @@ static int ocfs2_prepare_orphan_dir(struct ocfs2_super *osb,
- 
- 	mutex_lock(&orphan_dir_inode->i_mutex);
+ #endif /* __ASM_SH_PTRACE_H */
+diff --git a/include/asm-sh/r7780rp.h b/include/asm-sh/r7780rp.h
+index de37f93..bdecea0 100644
+--- a/include/asm-sh/r7780rp.h
++++ b/include/asm-sh/r7780rp.h
+@@ -121,21 +121,6 @@
+ 
+ #define IRLCNTR1	(PA_BCR + 0)	/* Interrupt Control Register1 */
+ 
+-#define IRQ_PCISLOT1	0		/* PCI Slot #1 IRQ */
+-#define IRQ_PCISLOT2	1		/* PCI Slot #2 IRQ */
+-#define IRQ_PCISLOT3	2		/* PCI Slot #3 IRQ */
+-#define IRQ_PCISLOT4	3		/* PCI Slot #4 IRQ */
+-#define IRQ_CFINST	5		/* CF Card Insert IRQ */
+-#define IRQ_M66596	6		/* M66596 IRQ */
+-#define IRQ_SDCARD	7		/* SD Card IRQ */
+-#define IRQ_TUCHPANEL	8		/* Touch Panel IRQ */
+-#define IRQ_SCI		9		/* SCI IRQ */
+-#define IRQ_2SERIAL	10		/* Serial IRQ */
+-#define	IRQ_EXTENTION	11		/* EXTn IRQ */
+-#define IRQ_ONETH	12		/* On board Ethernet IRQ */
+-#define IRQ_PSW		13		/* Push Switch IRQ */
+-#define IRQ_ZIGBEE	14		/* Ziggbee IO IRQ */
+-
+ #define IVDR_CK_ON	8		/* iVDR Clock ON */
+ 
+ #elif defined(CONFIG_SH_R7785RP)
+@@ -192,13 +177,19 @@
+ 
+ #define IRQ_AX88796		(HL_FPGA_IRQ_BASE + 0)
+ #define IRQ_CF			(HL_FPGA_IRQ_BASE + 1)
+-#ifndef IRQ_PSW
+ #define IRQ_PSW			(HL_FPGA_IRQ_BASE + 2)
+-#endif
+-#define IRQ_EXT1		(HL_FPGA_IRQ_BASE + 3)
+-#define IRQ_EXT4		(HL_FPGA_IRQ_BASE + 4)
+-
+-void make_r7780rp_irq(unsigned int irq);
++#define IRQ_EXT0		(HL_FPGA_IRQ_BASE + 3)
++#define IRQ_EXT1		(HL_FPGA_IRQ_BASE + 4)
++#define IRQ_EXT2		(HL_FPGA_IRQ_BASE + 5)
++#define IRQ_EXT3		(HL_FPGA_IRQ_BASE + 6)
++#define IRQ_EXT4		(HL_FPGA_IRQ_BASE + 7)
++#define IRQ_EXT5		(HL_FPGA_IRQ_BASE + 8)
++#define IRQ_EXT6		(HL_FPGA_IRQ_BASE + 9)
++#define IRQ_EXT7		(HL_FPGA_IRQ_BASE + 10)
++#define IRQ_SMBUS		(HL_FPGA_IRQ_BASE + 11)
++#define IRQ_TP			(HL_FPGA_IRQ_BASE + 12)
++#define IRQ_RTC			(HL_FPGA_IRQ_BASE + 13)
++#define IRQ_TH_ALERT		(HL_FPGA_IRQ_BASE + 14)
+ 
+ unsigned char *highlander_init_irq_r7780mp(void);
+ unsigned char *highlander_init_irq_r7780rp(void);
+diff --git a/include/asm-sh/rtc.h b/include/asm-sh/rtc.h
+index 858da99..ec45ba8 100644
+--- a/include/asm-sh/rtc.h
++++ b/include/asm-sh/rtc.h
+@@ -11,4 +11,6 @@ struct sh_rtc_platform_info {
+ 	unsigned long capabilities;
+ };
+ 
++#include <asm/cpu/rtc.h>
++
+ #endif /* _ASM_RTC_H */
+diff --git a/include/asm-sh/scatterlist.h b/include/asm-sh/scatterlist.h
+index a7d0d18..2084d03 100644
+--- a/include/asm-sh/scatterlist.h
++++ b/include/asm-sh/scatterlist.h
+@@ -13,7 +13,7 @@ struct scatterlist {
+     unsigned int length;
+ };
+ 
+-#define ISA_DMA_THRESHOLD (0x1fffffff)
++#define ISA_DMA_THRESHOLD	PHYS_ADDR_MASK
+ 
+ /* These macros should be used after a pci_map_sg call has been done
+  * to get bus addresses of each of the SG entries and their lengths.
+diff --git a/include/asm-sh/sdk7780.h b/include/asm-sh/sdk7780.h
+new file mode 100644
+index 0000000..697dc86
+--- /dev/null
++++ b/include/asm-sh/sdk7780.h
+@@ -0,0 +1,81 @@
++#ifndef __ASM_SH_RENESAS_SDK7780_H
++#define __ASM_SH_RENESAS_SDK7780_H
++
++/*
++ * linux/include/asm-sh/sdk7780.h
++ *
++ * Renesas Solutions SH7780 SDK Support
++ * Copyright (C) 2008 Nicholas Beck <nbeck at mpc-data.co.uk>
++ *
++ * 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 <asm/addrspace.h>
++
++/* Box specific addresses.  */
++#define SE_AREA0_WIDTH	4		/* Area0: 32bit */
++#define PA_ROM			0xa0000000	/* EPROM */
++#define PA_ROM_SIZE		0x00400000	/* EPROM size 4M byte */
++#define PA_FROM			0xa0800000	/* Flash-ROM */
++#define PA_FROM_SIZE	0x00400000	/* Flash-ROM size 4M byte */
++#define PA_EXT1			0xa4000000
++#define PA_EXT1_SIZE	0x04000000
++#define PA_SDRAM		0xa8000000	/* DDR-SDRAM(Area2/3) 128MB */
++#define PA_SDRAM_SIZE	0x08000000
++
++#define PA_EXT4			0xb0000000
++#define PA_EXT4_SIZE	0x04000000
++#define PA_EXT_USER		PA_EXT4		/* User Expansion Space */
++
++#define PA_PERIPHERAL	PA_AREA5_IO
++
++/* SRAM/Reserved */
++#define PA_RESERVED	(PA_PERIPHERAL + 0)
++/* FPGA base address */
++#define PA_FPGA		(PA_PERIPHERAL + 0x01000000)
++/* SMC LAN91C111 */
++#define PA_LAN		(PA_PERIPHERAL + 0x01800000)
++
++
++#define FPGA_SRSTR      (PA_FPGA + 0x000)	/* System reset */
++#define FPGA_IRQ0SR     (PA_FPGA + 0x010)	/* IRQ0 status */
++#define FPGA_IRQ0MR     (PA_FPGA + 0x020)	/* IRQ0 mask */
++#define FPGA_BDMR       (PA_FPGA + 0x030)	/* Board operating mode */
++#define FPGA_INTT0PRTR  (PA_FPGA + 0x040)	/* Interrupt test mode0 port */
++#define FPGA_INTT0SELR  (PA_FPGA + 0x050)	/* Int. test mode0 select */
++#define FPGA_INTT1POLR  (PA_FPGA + 0x060)	/* Int. test mode0 polarity */
++#define FPGA_NMIR       (PA_FPGA + 0x070)	/* NMI source */
++#define FPGA_NMIMR      (PA_FPGA + 0x080)	/* NMI mask */
++#define FPGA_IRQR       (PA_FPGA + 0x090)	/* IRQX source */
++#define FPGA_IRQMR      (PA_FPGA + 0x0A0)	/* IRQX mask */
++#define FPGA_SLEDR      (PA_FPGA + 0x0B0)	/* LED control */
++#define PA_LED			FPGA_SLEDR
++#define FPGA_MAPSWR     (PA_FPGA + 0x0C0)	/* Map switch */
++#define FPGA_FPVERR     (PA_FPGA + 0x0D0)	/* FPGA version */
++#define FPGA_FPDATER    (PA_FPGA + 0x0E0)	/* FPGA date */
++#define FPGA_RSE        (PA_FPGA + 0x100)	/* Reset source */
++#define FPGA_EASR       (PA_FPGA + 0x110)	/* External area select */
++#define FPGA_SPER       (PA_FPGA + 0x120)	/* Serial port enable */
++#define FPGA_IMSR       (PA_FPGA + 0x130)	/* Interrupt mode select */
++#define FPGA_PCIMR      (PA_FPGA + 0x140)	/* PCI Mode */
++#define FPGA_DIPSWMR    (PA_FPGA + 0x150)	/* DIPSW monitor */
++#define FPGA_FPODR      (PA_FPGA + 0x160)	/* Output port data */
++#define FPGA_ATAESR     (PA_FPGA + 0x170)	/* ATA extended bus status */
++#define FPGA_IRQPOLR    (PA_FPGA + 0x180)	/* IRQx polarity */
++
++
++#define SDK7780_NR_IRL			15
++/* IDE/ATA interrupt */
++#define IRQ_CFCARD				14
++/* SMC interrupt */
++#define IRQ_ETHERNET			6
++
++
++/* arch/sh/boards/renesas/sdk7780/irq.c */
++void init_sdk7780_IRQ(void);
++
++#define __IO_PREFIX		sdk7780
++#include <asm/io_generic.h>
++
++#endif  /* __ASM_SH_RENESAS_SDK7780_H */
+diff --git a/include/asm-sh/sections.h b/include/asm-sh/sections.h
+index bd9cbc9..8f8f4ad 100644
+--- a/include/asm-sh/sections.h
++++ b/include/asm-sh/sections.h
+@@ -4,6 +4,7 @@
+ #include <asm-generic/sections.h>
  
--	status = ocfs2_meta_lock(orphan_dir_inode, &orphan_dir_bh, 1);
-+	status = ocfs2_inode_lock(orphan_dir_inode, &orphan_dir_bh, 1);
- 	if (status < 0) {
- 		mlog_errno(status);
- 		goto leave;
-@@ -1745,7 +1745,7 @@ static int ocfs2_prepare_orphan_dir(struct ocfs2_super *osb,
- 					      orphan_dir_bh, name,
- 					      OCFS2_ORPHAN_NAMELEN, de_bh);
- 	if (status < 0) {
--		ocfs2_meta_unlock(orphan_dir_inode, 1);
-+		ocfs2_inode_unlock(orphan_dir_inode, 1);
+ extern long __machvec_start, __machvec_end;
++extern char __uncached_start, __uncached_end;
+ extern char _ebss[];
+ 
+ #endif /* __ASM_SH_SECTIONS_H */
+diff --git a/include/asm-sh/sigcontext.h b/include/asm-sh/sigcontext.h
+index eb8effb..8ce1435 100644
+--- a/include/asm-sh/sigcontext.h
++++ b/include/asm-sh/sigcontext.h
+@@ -4,6 +4,18 @@
+ struct sigcontext {
+ 	unsigned long	oldmask;
+ 
++#if defined(__SH5__) || defined(CONFIG_CPU_SH5)
++	/* CPU registers */
++	unsigned long long sc_regs[63];
++	unsigned long long sc_tregs[8];
++	unsigned long long sc_pc;
++	unsigned long long sc_sr;
++
++	/* FPU registers */
++	unsigned long long sc_fpregs[32];
++	unsigned int sc_fpscr;
++	unsigned int sc_fpvalid;
++#else
+ 	/* CPU registers */
+ 	unsigned long sc_regs[16];
+ 	unsigned long sc_pc;
+@@ -13,7 +25,8 @@ struct sigcontext {
+ 	unsigned long sc_mach;
+ 	unsigned long sc_macl;
+ 
+-#if defined(__SH4__) || defined(CONFIG_CPU_SH4)
++#if defined(__SH4__) || defined(CONFIG_CPU_SH4) || \
++    defined(__SH2A__) || defined(CONFIG_CPU_SH2A)
+ 	/* FPU registers */
+ 	unsigned long sc_fpregs[16];
+ 	unsigned long sc_xfpregs[16];
+@@ -21,6 +34,7 @@ struct sigcontext {
+ 	unsigned int sc_fpul;
+ 	unsigned int sc_ownedfp;
+ #endif
++#endif
+ };
  
- 		mlog_errno(status);
- 		goto leave;
-diff --git a/fs/ocfs2/ocfs2.h b/fs/ocfs2/ocfs2.h
-index 60a23e1..d084805 100644
---- a/fs/ocfs2/ocfs2.h
-+++ b/fs/ocfs2/ocfs2.h
-@@ -101,6 +101,7 @@ enum ocfs2_unlock_action {
- 					       * about to be
- 					       * dropped. */
- #define OCFS2_LOCK_QUEUED        (0x00000100) /* queued for downconvert */
-+#define OCFS2_LOCK_NOCACHE       (0x00000200) /* don't use a holder count */
+ #endif /* __ASM_SH_SIGCONTEXT_H */
+diff --git a/include/asm-sh/spi.h b/include/asm-sh/spi.h
+new file mode 100644
+index 0000000..e96f5b0
+--- /dev/null
++++ b/include/asm-sh/spi.h
+@@ -0,0 +1,13 @@
++#ifndef __ASM_SPI_H__
++#define __ASM_SPI_H__
++
++struct sh_spi_info;
++
++struct sh_spi_info {
++	int			 bus_num;
++	int			 num_chipselect;
++
++	void (*chip_select)(struct sh_spi_info *spi, int cs, int state);
++};
++
++#endif /* __ASM_SPI_H__ */
+diff --git a/include/asm-sh/stat.h b/include/asm-sh/stat.h
+index 6d6ad26..e1810cc 100644
+--- a/include/asm-sh/stat.h
++++ b/include/asm-sh/stat.h
+@@ -15,6 +15,66 @@ struct __old_kernel_stat {
+ 	unsigned long  st_ctime;
+ };
+ 
++#if defined(__SH5__) || defined(CONFIG_CPU_SH5)
++struct stat {
++	unsigned short st_dev;
++	unsigned short __pad1;
++	unsigned long st_ino;
++	unsigned short st_mode;
++	unsigned short st_nlink;
++	unsigned short st_uid;
++	unsigned short st_gid;
++	unsigned short st_rdev;
++	unsigned short __pad2;
++	unsigned long  st_size;
++	unsigned long  st_blksize;
++	unsigned long  st_blocks;
++	unsigned long  st_atime;
++	unsigned long  st_atime_nsec;
++	unsigned long  st_mtime;
++	unsigned long  st_mtime_nsec;
++	unsigned long  st_ctime;
++	unsigned long  st_ctime_nsec;
++	unsigned long  __unused4;
++	unsigned long  __unused5;
++};
++
++/* This matches struct stat64 in glibc2.1, hence the absolutely
++ * insane amounts of padding around dev_t's.
++ */
++struct stat64 {
++	unsigned short	st_dev;
++	unsigned char	__pad0[10];
++
++	unsigned long	st_ino;
++	unsigned int	st_mode;
++	unsigned int	st_nlink;
++
++	unsigned long	st_uid;
++	unsigned long	st_gid;
++
++	unsigned short	st_rdev;
++	unsigned char	__pad3[10];
++
++	long long	st_size;
++	unsigned long	st_blksize;
++
++	unsigned long	st_blocks;	/* Number 512-byte blocks allocated. */
++	unsigned long	__pad4;		/* future possible st_blocks high bits */
++
++	unsigned long	st_atime;
++	unsigned long	st_atime_nsec;
++
++	unsigned long	st_mtime;
++	unsigned long	st_mtime_nsec;
++
++	unsigned long	st_ctime;
++	unsigned long	st_ctime_nsec;	/* will be high 32 bits of ctime someday */
++
++	unsigned long	__unused1;
++	unsigned long	__unused2;
++};
++#else
+ struct stat {
+ 	unsigned long  st_dev;
+ 	unsigned long  st_ino;
+@@ -67,11 +127,12 @@ struct stat64 {
+ 	unsigned long	st_mtime_nsec;
  
- struct ocfs2_lock_res_ops;
+ 	unsigned long	st_ctime;
+-	unsigned long	st_ctime_nsec; 
++	unsigned long	st_ctime_nsec;
  
-@@ -170,6 +171,7 @@ enum ocfs2_mount_options
- 	OCFS2_MOUNT_NOINTR  = 1 << 2,   /* Don't catch signals */
- 	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 */
+ 	unsigned long long	st_ino;
  };
  
- #define OCFS2_OSB_SOFT_RO	0x0001
-@@ -189,9 +191,7 @@ struct ocfs2_super
- 	struct ocfs2_slot_info *slot_info;
- 
- 	spinlock_t node_map_lock;
--	struct ocfs2_node_map mounted_map;
- 	struct ocfs2_node_map recovery_map;
--	struct ocfs2_node_map umount_map;
- 
- 	u64 root_blkno;
- 	u64 system_dir_blkno;
-@@ -231,7 +231,9 @@ struct ocfs2_super
- 	wait_queue_head_t checkpoint_event;
- 	atomic_t needs_checkpoint;
- 	struct ocfs2_journal *journal;
-+	unsigned long osb_commit_interval;
+ #define STAT_HAVE_NSEC 1
++#endif
  
-+	int local_alloc_size;
- 	enum ocfs2_local_alloc_state local_alloc_state;
- 	struct buffer_head *local_alloc_bh;
- 	u64 la_last_gd;
-@@ -254,28 +256,21 @@ struct ocfs2_super
+ #endif /* __ASM_SH_STAT_H */
+diff --git a/include/asm-sh/string.h b/include/asm-sh/string.h
+index 55f8db6..8c1ea21 100644
+--- a/include/asm-sh/string.h
++++ b/include/asm-sh/string.h
+@@ -1,131 +1,5 @@
+-#ifndef __ASM_SH_STRING_H
+-#define __ASM_SH_STRING_H
+-
+-#ifdef __KERNEL__
+-
+-/*
+- * Copyright (C) 1999 Niibe Yutaka
+- * But consider these trivial functions to be public domain.
+- */
+-
+-#define __HAVE_ARCH_STRCPY
+-static inline char *strcpy(char *__dest, const char *__src)
+-{
+-	register char *__xdest = __dest;
+-	unsigned long __dummy;
+-
+-	__asm__ __volatile__("1:\n\t"
+-			     "mov.b	@%1+, %2\n\t"
+-			     "mov.b	%2, @%0\n\t"
+-			     "cmp/eq	#0, %2\n\t"
+-			     "bf/s	1b\n\t"
+-			     " add	#1, %0\n\t"
+-			     : "=r" (__dest), "=r" (__src), "=&z" (__dummy)
+-			     : "0" (__dest), "1" (__src)
+-			     : "memory", "t");
+-
+-	return __xdest;
+-}
+-
+-#define __HAVE_ARCH_STRNCPY
+-static inline char *strncpy(char *__dest, const char *__src, size_t __n)
+-{
+-	register char *__xdest = __dest;
+-	unsigned long __dummy;
+-
+-	if (__n == 0)
+-		return __xdest;
+-
+-	__asm__ __volatile__(
+-		"1:\n"
+-		"mov.b	@%1+, %2\n\t"
+-		"mov.b	%2, @%0\n\t"
+-		"cmp/eq	#0, %2\n\t"
+-		"bt/s	2f\n\t"
+-		" cmp/eq	%5,%1\n\t"
+-		"bf/s	1b\n\t"
+-		" add	#1, %0\n"
+-		"2:"
+-		: "=r" (__dest), "=r" (__src), "=&z" (__dummy)
+-		: "0" (__dest), "1" (__src), "r" (__src+__n)
+-		: "memory", "t");
+-
+-	return __xdest;
+-}
+-
+-#define __HAVE_ARCH_STRCMP
+-static inline int strcmp(const char *__cs, const char *__ct)
+-{
+-	register int __res;
+-	unsigned long __dummy;
+-
+-	__asm__ __volatile__(
+-		"mov.b	@%1+, %3\n"
+-		"1:\n\t"
+-		"mov.b	@%0+, %2\n\t"
+-		"cmp/eq #0, %3\n\t"
+-		"bt	2f\n\t"
+-		"cmp/eq %2, %3\n\t"
+-		"bt/s	1b\n\t"
+-		" mov.b	@%1+, %3\n\t"
+-		"add	#-2, %1\n\t"
+-		"mov.b	@%1, %3\n\t"
+-		"sub	%3, %2\n"
+-		"2:"
+-		: "=r" (__cs), "=r" (__ct), "=&r" (__res), "=&z" (__dummy)
+-		: "0" (__cs), "1" (__ct)
+-		: "t");
+-
+-	return __res;
+-}
+-
+-#define __HAVE_ARCH_STRNCMP
+-static inline int strncmp(const char *__cs, const char *__ct, size_t __n)
+-{
+-	register int __res;
+-	unsigned long __dummy;
+-
+-	if (__n == 0)
+-		return 0;
+-
+-	__asm__ __volatile__(
+-		"mov.b	@%1+, %3\n"
+-		"1:\n\t"
+-		"mov.b	@%0+, %2\n\t"
+-		"cmp/eq %6, %0\n\t"
+-		"bt/s	2f\n\t"
+-		" cmp/eq #0, %3\n\t"
+-		"bt/s	3f\n\t"
+-		" cmp/eq %3, %2\n\t"
+-		"bt/s	1b\n\t"
+-		" mov.b	@%1+, %3\n\t"
+-		"add	#-2, %1\n\t"
+-		"mov.b	@%1, %3\n"
+-		"2:\n\t"
+-		"sub	%3, %2\n"
+-		"3:"
+-		:"=r" (__cs), "=r" (__ct), "=&r" (__res), "=&z" (__dummy)
+-		: "0" (__cs), "1" (__ct), "r" (__cs+__n)
+-		: "t");
+-
+-	return __res;
+-}
+-
+-#define __HAVE_ARCH_MEMSET
+-extern void *memset(void *__s, int __c, size_t __count);
+-
+-#define __HAVE_ARCH_MEMCPY
+-extern void *memcpy(void *__to, __const__ void *__from, size_t __n);
+-
+-#define __HAVE_ARCH_MEMMOVE
+-extern void *memmove(void *__dest, __const__ void *__src, size_t __n);
+-
+-#define __HAVE_ARCH_MEMCHR
+-extern void *memchr(const void *__s, int __c, size_t __n);
+-
+-#define __HAVE_ARCH_STRLEN
+-extern size_t strlen(const char *);
+-
+-#endif /* __KERNEL__ */
+-
+-#endif /* __ASM_SH_STRING_H */
++#ifdef CONFIG_SUPERH32
++# include "string_32.h"
++#else
++# include "string_64.h"
++#endif
+diff --git a/include/asm-sh/string_32.h b/include/asm-sh/string_32.h
+new file mode 100644
+index 0000000..55f8db6
+--- /dev/null
++++ b/include/asm-sh/string_32.h
+@@ -0,0 +1,131 @@
++#ifndef __ASM_SH_STRING_H
++#define __ASM_SH_STRING_H
++
++#ifdef __KERNEL__
++
++/*
++ * Copyright (C) 1999 Niibe Yutaka
++ * But consider these trivial functions to be public domain.
++ */
++
++#define __HAVE_ARCH_STRCPY
++static inline char *strcpy(char *__dest, const char *__src)
++{
++	register char *__xdest = __dest;
++	unsigned long __dummy;
++
++	__asm__ __volatile__("1:\n\t"
++			     "mov.b	@%1+, %2\n\t"
++			     "mov.b	%2, @%0\n\t"
++			     "cmp/eq	#0, %2\n\t"
++			     "bf/s	1b\n\t"
++			     " add	#1, %0\n\t"
++			     : "=r" (__dest), "=r" (__src), "=&z" (__dummy)
++			     : "0" (__dest), "1" (__src)
++			     : "memory", "t");
++
++	return __xdest;
++}
++
++#define __HAVE_ARCH_STRNCPY
++static inline char *strncpy(char *__dest, const char *__src, size_t __n)
++{
++	register char *__xdest = __dest;
++	unsigned long __dummy;
++
++	if (__n == 0)
++		return __xdest;
++
++	__asm__ __volatile__(
++		"1:\n"
++		"mov.b	@%1+, %2\n\t"
++		"mov.b	%2, @%0\n\t"
++		"cmp/eq	#0, %2\n\t"
++		"bt/s	2f\n\t"
++		" cmp/eq	%5,%1\n\t"
++		"bf/s	1b\n\t"
++		" add	#1, %0\n"
++		"2:"
++		: "=r" (__dest), "=r" (__src), "=&z" (__dummy)
++		: "0" (__dest), "1" (__src), "r" (__src+__n)
++		: "memory", "t");
++
++	return __xdest;
++}
++
++#define __HAVE_ARCH_STRCMP
++static inline int strcmp(const char *__cs, const char *__ct)
++{
++	register int __res;
++	unsigned long __dummy;
++
++	__asm__ __volatile__(
++		"mov.b	@%1+, %3\n"
++		"1:\n\t"
++		"mov.b	@%0+, %2\n\t"
++		"cmp/eq #0, %3\n\t"
++		"bt	2f\n\t"
++		"cmp/eq %2, %3\n\t"
++		"bt/s	1b\n\t"
++		" mov.b	@%1+, %3\n\t"
++		"add	#-2, %1\n\t"
++		"mov.b	@%1, %3\n\t"
++		"sub	%3, %2\n"
++		"2:"
++		: "=r" (__cs), "=r" (__ct), "=&r" (__res), "=&z" (__dummy)
++		: "0" (__cs), "1" (__ct)
++		: "t");
++
++	return __res;
++}
++
++#define __HAVE_ARCH_STRNCMP
++static inline int strncmp(const char *__cs, const char *__ct, size_t __n)
++{
++	register int __res;
++	unsigned long __dummy;
++
++	if (__n == 0)
++		return 0;
++
++	__asm__ __volatile__(
++		"mov.b	@%1+, %3\n"
++		"1:\n\t"
++		"mov.b	@%0+, %2\n\t"
++		"cmp/eq %6, %0\n\t"
++		"bt/s	2f\n\t"
++		" cmp/eq #0, %3\n\t"
++		"bt/s	3f\n\t"
++		" cmp/eq %3, %2\n\t"
++		"bt/s	1b\n\t"
++		" mov.b	@%1+, %3\n\t"
++		"add	#-2, %1\n\t"
++		"mov.b	@%1, %3\n"
++		"2:\n\t"
++		"sub	%3, %2\n"
++		"3:"
++		:"=r" (__cs), "=r" (__ct), "=&r" (__res), "=&z" (__dummy)
++		: "0" (__cs), "1" (__ct), "r" (__cs+__n)
++		: "t");
++
++	return __res;
++}
++
++#define __HAVE_ARCH_MEMSET
++extern void *memset(void *__s, int __c, size_t __count);
++
++#define __HAVE_ARCH_MEMCPY
++extern void *memcpy(void *__to, __const__ void *__from, size_t __n);
++
++#define __HAVE_ARCH_MEMMOVE
++extern void *memmove(void *__dest, __const__ void *__src, size_t __n);
++
++#define __HAVE_ARCH_MEMCHR
++extern void *memchr(const void *__s, int __c, size_t __n);
++
++#define __HAVE_ARCH_STRLEN
++extern size_t strlen(const char *);
++
++#endif /* __KERNEL__ */
++
++#endif /* __ASM_SH_STRING_H */
+diff --git a/include/asm-sh/string_64.h b/include/asm-sh/string_64.h
+new file mode 100644
+index 0000000..aa1fef2
+--- /dev/null
++++ b/include/asm-sh/string_64.h
+@@ -0,0 +1,17 @@
++#ifndef __ASM_SH_STRING_64_H
++#define __ASM_SH_STRING_64_H
++
++/*
++ * include/asm-sh/string_64.h
++ *
++ * Copyright (C) 2000, 2001  Paolo Alberelli
++ *
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License.  See the file "COPYING" in the main directory of this archive
++ * for more details.
++ */
++
++#define __HAVE_ARCH_MEMCPY
++extern void *memcpy(void *dest, const void *src, size_t count);
++
++#endif /* __ASM_SH_STRING_64_H */
+diff --git a/include/asm-sh/system.h b/include/asm-sh/system.h
+index 4faa2fb..772cd1a 100644
+--- a/include/asm-sh/system.h
++++ b/include/asm-sh/system.h
+@@ -12,60 +12,9 @@
+ #include <asm/types.h>
+ #include <asm/ptrace.h>
  
- 	wait_queue_head_t recovery_event;
+-struct task_struct *__switch_to(struct task_struct *prev,
+-				struct task_struct *next);
++#define AT_VECTOR_SIZE_ARCH 5 /* entries in ARCH_DLINFO */
  
--	spinlock_t vote_task_lock;
--	struct task_struct *vote_task;
--	wait_queue_head_t vote_event;
--	unsigned long vote_wake_sequence;
--	unsigned long vote_work_sequence;
-+	spinlock_t dc_task_lock;
-+	struct task_struct *dc_task;
-+	wait_queue_head_t dc_event;
-+	unsigned long dc_wake_sequence;
-+	unsigned long dc_work_sequence;
+-#define AT_VECTOR_SIZE_ARCH 1 /* entries in ARCH_DLINFO */
+-/*
+- *	switch_to() should switch tasks to task nr n, first
+- */
+-
+-#define switch_to(prev, next, last) do {				\
+- struct task_struct *__last;						\
+- register unsigned long *__ts1 __asm__ ("r1") = &prev->thread.sp;	\
+- register unsigned long *__ts2 __asm__ ("r2") = &prev->thread.pc;	\
+- register unsigned long *__ts4 __asm__ ("r4") = (unsigned long *)prev;	\
+- register unsigned long *__ts5 __asm__ ("r5") = (unsigned long *)next;	\
+- register unsigned long *__ts6 __asm__ ("r6") = &next->thread.sp;	\
+- register unsigned long __ts7 __asm__ ("r7") = next->thread.pc;		\
+- __asm__ __volatile__ (".balign 4\n\t" 					\
+-		       "stc.l	gbr, @-r15\n\t" 			\
+-		       "sts.l	pr, @-r15\n\t" 				\
+-		       "mov.l	r8, @-r15\n\t" 				\
+-		       "mov.l	r9, @-r15\n\t" 				\
+-		       "mov.l	r10, @-r15\n\t" 			\
+-		       "mov.l	r11, @-r15\n\t" 			\
+-		       "mov.l	r12, @-r15\n\t" 			\
+-		       "mov.l	r13, @-r15\n\t" 			\
+-		       "mov.l	r14, @-r15\n\t" 			\
+-		       "mov.l	r15, @r1	! save SP\n\t"		\
+-		       "mov.l	@r6, r15	! change to new stack\n\t" \
+-		       "mova	1f, %0\n\t" 				\
+-		       "mov.l	%0, @r2		! save PC\n\t" 		\
+-		       "mov.l	2f, %0\n\t" 				\
+-		       "jmp	@%0		! call __switch_to\n\t" \
+-		       " lds	r7, pr		!  with return to new PC\n\t" \
+-		       ".balign	4\n"					\
+-		       "2:\n\t"						\
+-		       ".long	__switch_to\n"				\
+-		       "1:\n\t"						\
+-		       "mov.l	@r15+, r14\n\t"				\
+-		       "mov.l	@r15+, r13\n\t"				\
+-		       "mov.l	@r15+, r12\n\t"				\
+-		       "mov.l	@r15+, r11\n\t"				\
+-		       "mov.l	@r15+, r10\n\t"				\
+-		       "mov.l	@r15+, r9\n\t"				\
+-		       "mov.l	@r15+, r8\n\t"				\
+-		       "lds.l	@r15+, pr\n\t"				\
+-		       "ldc.l	@r15+, gbr\n\t"				\
+-		       : "=z" (__last)					\
+-		       : "r" (__ts1), "r" (__ts2), "r" (__ts4), 	\
+-			 "r" (__ts5), "r" (__ts6), "r" (__ts7) 		\
+-		       : "r3", "t");					\
+-	last = __last;							\
+-} while (0)
+-
+-#ifdef CONFIG_CPU_SH4A
++#if defined(CONFIG_CPU_SH4A) || defined(CONFIG_CPU_SH5)
+ #define __icbi()			\
+ {					\
+ 	unsigned long __addr;		\
+@@ -91,7 +40,7 @@ struct task_struct *__switch_to(struct task_struct *prev,
+  * Historically we have only done this type of barrier for the MMUCR, but
+  * it's also necessary for the CCR, so we make it generic here instead.
+  */
+-#ifdef CONFIG_CPU_SH4A
++#if defined(CONFIG_CPU_SH4A) || defined(CONFIG_CPU_SH5)
+ #define mb()		__asm__ __volatile__ ("synco": : :"memory")
+ #define rmb()		mb()
+ #define wmb()		__asm__ __volatile__ ("synco": : :"memory")
+@@ -119,63 +68,11 @@ struct task_struct *__switch_to(struct task_struct *prev,
  
-+	/*
-+	 * Any thread can add locks to the list, but the downconvert
-+	 * thread is the only one allowed to remove locks. Any change
-+	 * to this rule requires updating
-+	 * ocfs2_downconvert_thread_do_work().
-+	 */
- 	struct list_head blocked_lock_list;
- 	unsigned long blocked_lock_count;
+ #define set_mb(var, value) do { (void)xchg(&var, value); } while (0)
  
--	struct list_head vote_list;
--	int vote_count;
+-/*
+- * Jump to P2 area.
+- * When handling TLB or caches, we need to do it from P2 area.
+- */
+-#define jump_to_P2()			\
+-do {					\
+-	unsigned long __dummy;		\
+-	__asm__ __volatile__(		\
+-		"mov.l	1f, %0\n\t"	\
+-		"or	%1, %0\n\t"	\
+-		"jmp	@%0\n\t"	\
+-		" nop\n\t" 		\
+-		".balign 4\n"		\
+-		"1:	.long 2f\n"	\
+-		"2:"			\
+-		: "=&r" (__dummy)	\
+-		: "r" (0x20000000));	\
+-} while (0)
 -
--	u32 net_key;
--	spinlock_t net_response_lock;
--	unsigned int net_response_ids;
--	struct list_head net_response_list;
+-/*
+- * Back to P1 area.
+- */
+-#define back_to_P1()					\
+-do {							\
+-	unsigned long __dummy;				\
+-	ctrl_barrier();					\
+-	__asm__ __volatile__(				\
+-		"mov.l	1f, %0\n\t"			\
+-		"jmp	@%0\n\t"			\
+-		" nop\n\t"				\
+-		".balign 4\n"				\
+-		"1:	.long 2f\n"			\
+-		"2:"					\
+-		: "=&r" (__dummy));			\
+-} while (0)
 -
--	struct o2hb_callback_func osb_hb_up;
--	struct o2hb_callback_func osb_hb_down;
+-static inline unsigned long xchg_u32(volatile u32 *m, unsigned long val)
+-{
+-	unsigned long flags, retval;
 -
--	struct list_head	osb_net_handlers;
+-	local_irq_save(flags);
+-	retval = *m;
+-	*m = val;
+-	local_irq_restore(flags);
+-	return retval;
+-}
 -
- 	wait_queue_head_t		osb_mount_event;
+-static inline unsigned long xchg_u8(volatile u8 *m, unsigned long val)
+-{
+-	unsigned long flags, retval;
+-
+-	local_irq_save(flags);
+-	retval = *m;
+-	*m = val & 0xff;
+-	local_irq_restore(flags);
+-	return retval;
+-}
++#ifdef CONFIG_GUSA_RB
++#include <asm/cmpxchg-grb.h>
++#else
++#include <asm/cmpxchg-irq.h>
++#endif
  
- 	/* Truncate log info */
-diff --git a/fs/ocfs2/ocfs2_fs.h b/fs/ocfs2/ocfs2_fs.h
-index 6ef8767..3633edd 100644
---- a/fs/ocfs2/ocfs2_fs.h
-+++ b/fs/ocfs2/ocfs2_fs.h
-@@ -231,6 +231,20 @@ struct ocfs2_space_resv {
- #define OCFS2_IOC_RESVSP64	_IOW ('X', 42, struct ocfs2_space_resv)
- #define OCFS2_IOC_UNRESVSP64	_IOW ('X', 43, struct ocfs2_space_resv)
+ extern void __xchg_called_with_bad_pointer(void);
  
-+/* Used to pass group descriptor data when online resize is done */
-+struct ocfs2_new_group_input {
-+	__u64 group;		/* Group descriptor's blkno. */
-+	__u32 clusters;		/* Total number of clusters in this group */
-+	__u32 frees;		/* Total free clusters in this group */
-+	__u16 chain;		/* Chain for this group */
-+	__u16 reserved1;
-+	__u32 reserved2;
-+};
+@@ -202,20 +99,6 @@ extern void __xchg_called_with_bad_pointer(void);
+ #define xchg(ptr,x)	\
+ 	((__typeof__(*(ptr)))__xchg((ptr),(unsigned long)(x), sizeof(*(ptr))))
+ 
+-static inline unsigned long __cmpxchg_u32(volatile int * m, unsigned long old,
+-	unsigned long new)
+-{
+-	__u32 retval;
+-	unsigned long flags;
+-
+-	local_irq_save(flags);
+-	retval = *m;
+-	if (retval == old)
+-		*m = new;
+-	local_irq_restore(flags);       /* implies memory barrier  */
+-	return retval;
+-}
+-
+ /* This function doesn't exist, so you'll get a linker error
+  * if something tries to do an invalid cmpxchg(). */
+ extern void __cmpxchg_called_with_bad_pointer(void);
+@@ -255,10 +138,14 @@ static inline void *set_exception_table_evt(unsigned int evt, void *handler)
+  */
+ #ifdef CONFIG_CPU_SH2A
+ extern unsigned int instruction_size(unsigned int insn);
+-#else
++#elif defined(CONFIG_SUPERH32)
+ #define instruction_size(insn)	(2)
++#else
++#define instruction_size(insn)	(4)
+ #endif
+ 
++extern unsigned long cached_to_uncached;
 +
-+#define OCFS2_IOC_GROUP_EXTEND	_IOW('o', 1, int)
-+#define OCFS2_IOC_GROUP_ADD	_IOW('o', 2,struct ocfs2_new_group_input)
-+#define OCFS2_IOC_GROUP_ADD64	_IOW('o', 3,struct ocfs2_new_group_input)
+ /* XXX
+  * disable hlt during certain critical i/o operations
+  */
+@@ -270,13 +157,35 @@ void default_idle(void);
+ void per_cpu_trap_init(void);
+ 
+ asmlinkage void break_point_trap(void);
+-asmlinkage void debug_trap_handler(unsigned long r4, unsigned long r5,
+-				   unsigned long r6, unsigned long r7,
+-				   struct pt_regs __regs);
+-asmlinkage void bug_trap_handler(unsigned long r4, unsigned long r5,
+-				 unsigned long r6, unsigned long r7,
+-				 struct pt_regs __regs);
++
++#ifdef CONFIG_SUPERH32
++#define BUILD_TRAP_HANDLER(name)					\
++asmlinkage void name##_trap_handler(unsigned long r4, unsigned long r5,	\
++				    unsigned long r6, unsigned long r7,	\
++				    struct pt_regs __regs)
++
++#define TRAP_HANDLER_DECL				\
++	struct pt_regs *regs = RELOC_HIDE(&__regs, 0);	\
++	unsigned int vec = regs->tra;			\
++	(void)vec;
++#else
++#define BUILD_TRAP_HANDLER(name)	\
++asmlinkage void name##_trap_handler(unsigned int vec, struct pt_regs *regs)
++#define TRAP_HANDLER_DECL
++#endif
++
++BUILD_TRAP_HANDLER(address_error);
++BUILD_TRAP_HANDLER(debug);
++BUILD_TRAP_HANDLER(bug);
++BUILD_TRAP_HANDLER(fpu_error);
++BUILD_TRAP_HANDLER(fpu_state_restore);
+ 
+ #define arch_align_stack(x) (x)
+ 
++#ifdef CONFIG_SUPERH32
++# include "system_32.h"
++#else
++# include "system_64.h"
++#endif
++
+ #endif
+diff --git a/include/asm-sh/system_32.h b/include/asm-sh/system_32.h
+new file mode 100644
+index 0000000..7ff08d9
+--- /dev/null
++++ b/include/asm-sh/system_32.h
+@@ -0,0 +1,99 @@
++#ifndef __ASM_SH_SYSTEM_32_H
++#define __ASM_SH_SYSTEM_32_H
++
++#include <linux/types.h>
++
++struct task_struct *__switch_to(struct task_struct *prev,
++				struct task_struct *next);
++
++/*
++ *	switch_to() should switch tasks to task nr n, first
++ */
++#define switch_to(prev, next, last)					\
++do {									\
++	register u32 *__ts1 __asm__ ("r1") = (u32 *)&prev->thread.sp;	\
++	register u32 *__ts2 __asm__ ("r2") = (u32 *)&prev->thread.pc;	\
++	register u32 *__ts4 __asm__ ("r4") = (u32 *)prev;		\
++	register u32 *__ts5 __asm__ ("r5") = (u32 *)next;		\
++	register u32 *__ts6 __asm__ ("r6") = (u32 *)&next->thread.sp;	\
++	register u32 __ts7 __asm__ ("r7") = next->thread.pc;		\
++	struct task_struct *__last;					\
++									\
++	__asm__ __volatile__ (						\
++		".balign 4\n\t"						\
++		"stc.l	gbr, @-r15\n\t"					\
++		"sts.l	pr, @-r15\n\t"					\
++		"mov.l	r8, @-r15\n\t"					\
++		"mov.l	r9, @-r15\n\t"					\
++		"mov.l	r10, @-r15\n\t"					\
++		"mov.l	r11, @-r15\n\t"					\
++		"mov.l	r12, @-r15\n\t"					\
++		"mov.l	r13, @-r15\n\t"					\
++		"mov.l	r14, @-r15\n\t"					\
++		"mov.l	r15, @r1\t! save SP\n\t"			\
++		"mov.l	@r6, r15\t! change to new stack\n\t"		\
++		"mova	1f, %0\n\t"					\
++		"mov.l	%0, @r2\t! save PC\n\t"				\
++		"mov.l	2f, %0\n\t"					\
++		"jmp	@%0\t! call __switch_to\n\t"			\
++		" lds	r7, pr\t!  with return to new PC\n\t"		\
++		".balign	4\n"					\
++		"2:\n\t"						\
++		".long	__switch_to\n"					\
++		"1:\n\t"						\
++		"mov.l	@r15+, r14\n\t"					\
++		"mov.l	@r15+, r13\n\t"					\
++		"mov.l	@r15+, r12\n\t"					\
++		"mov.l	@r15+, r11\n\t"					\
++		"mov.l	@r15+, r10\n\t"					\
++		"mov.l	@r15+, r9\n\t"					\
++		"mov.l	@r15+, r8\n\t"					\
++		"lds.l	@r15+, pr\n\t"					\
++		"ldc.l	@r15+, gbr\n\t"					\
++		: "=z" (__last)						\
++		: "r" (__ts1), "r" (__ts2), "r" (__ts4),		\
++		  "r" (__ts5), "r" (__ts6), "r" (__ts7)			\
++		: "r3", "t");						\
++									\
++	last = __last;							\
++} while (0)
++
++#define __uses_jump_to_uncached __attribute__ ((__section__ (".uncached.text")))
++
++/*
++ * Jump to uncached area.
++ * When handling TLB or caches, we need to do it from an uncached area.
++ */
++#define jump_to_uncached()			\
++do {						\
++	unsigned long __dummy;			\
++						\
++	__asm__ __volatile__(			\
++		"mova	1f, %0\n\t"		\
++		"add	%1, %0\n\t"		\
++		"jmp	@%0\n\t"		\
++		" nop\n\t"			\
++		".balign 4\n"			\
++		"1:"				\
++		: "=&z" (__dummy)		\
++		: "r" (cached_to_uncached));	\
++} while (0)
++
++/*
++ * Back to cached area.
++ */
++#define back_to_cached()				\
++do {							\
++	unsigned long __dummy;				\
++	ctrl_barrier();					\
++	__asm__ __volatile__(				\
++		"mov.l	1f, %0\n\t"			\
++		"jmp	@%0\n\t"			\
++		" nop\n\t"				\
++		".balign 4\n"				\
++		"1:	.long 2f\n"			\
++		"2:"					\
++		: "=&r" (__dummy));			\
++} while (0)
++
++#endif /* __ASM_SH_SYSTEM_32_H */
+diff --git a/include/asm-sh/system_64.h b/include/asm-sh/system_64.h
+new file mode 100644
+index 0000000..943acf5
+--- /dev/null
++++ b/include/asm-sh/system_64.h
+@@ -0,0 +1,40 @@
++#ifndef __ASM_SH_SYSTEM_64_H
++#define __ASM_SH_SYSTEM_64_H
 +
- /*
-  * Journal Flags (ocfs2_dinode.id1.journal1.i_flags)
-  */
-@@ -256,6 +270,14 @@ struct ocfs2_space_resv {
- /* Journal limits (in bytes) */
- #define OCFS2_MIN_JOURNAL_SIZE		(4 * 1024 * 1024)
- 
 +/*
-+ * Default local alloc size (in megabytes)
++ * include/asm-sh/system_64.h
 + *
-+ * The value chosen should be such that most allocations, including new
-+ * block groups, use local alloc.
++ * Copyright (C) 2000, 2001  Paolo Alberelli
++ * Copyright (C) 2003  Paul Mundt
++ * Copyright (C) 2004  Richard Curnow
++ *
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License.  See the file "COPYING" in the main directory of this archive
++ * for more details.
 + */
-+#define OCFS2_DEFAULT_LOCAL_ALLOC_SIZE	8
++#include <asm/processor.h>
 +
- struct ocfs2_system_inode_info {
- 	char	*si_name;
- 	int	si_iflags;
-diff --git a/fs/ocfs2/ocfs2_lockid.h b/fs/ocfs2/ocfs2_lockid.h
-index 4ca02b1..86f3e37 100644
---- a/fs/ocfs2/ocfs2_lockid.h
-+++ b/fs/ocfs2/ocfs2_lockid.h
-@@ -45,6 +45,7 @@ enum ocfs2_lock_type {
- 	OCFS2_LOCK_TYPE_RW,
- 	OCFS2_LOCK_TYPE_DENTRY,
- 	OCFS2_LOCK_TYPE_OPEN,
-+	OCFS2_LOCK_TYPE_FLOCK,
- 	OCFS2_NUM_LOCK_TYPES
- };
++/*
++ *	switch_to() should switch tasks to task nr n, first
++ */
++struct task_struct *sh64_switch_to(struct task_struct *prev,
++				   struct thread_struct *prev_thread,
++				   struct task_struct *next,
++				   struct thread_struct *next_thread);
++
++#define switch_to(prev,next,last)				\
++do {								\
++	if (last_task_used_math != next) {			\
++		struct pt_regs *regs = next->thread.uregs;	\
++		if (regs) regs->sr |= SR_FD;			\
++	}							\
++	last = sh64_switch_to(prev, &prev->thread, next,	\
++			      &next->thread);			\
++} while (0)
++
++#define __uses_jump_to_uncached
++
++#define jump_to_uncached()	do { } while (0)
++#define back_to_cached()	do { } while (0)
++
++#endif /* __ASM_SH_SYSTEM_64_H */
+diff --git a/include/asm-sh/thread_info.h b/include/asm-sh/thread_info.h
+index 1f7e1de..c6577d3 100644
+--- a/include/asm-sh/thread_info.h
++++ b/include/asm-sh/thread_info.h
+@@ -74,8 +74,10 @@ register unsigned long current_stack_pointer asm("r15") __attribute_used__;
+ static inline struct thread_info *current_thread_info(void)
+ {
+ 	struct thread_info *ti;
+-#ifdef CONFIG_CPU_HAS_SR_RB
+-	__asm__("stc	r7_bank, %0" : "=r" (ti));
++#if defined(CONFIG_SUPERH64)
++	__asm__ __volatile__ ("getcon	cr17, %0" : "=r" (ti));
++#elif defined(CONFIG_CPU_HAS_SR_RB)
++	__asm__ __volatile__ ("stc	r7_bank, %0" : "=r" (ti));
+ #else
+ 	unsigned long __dummy;
  
-@@ -73,6 +74,9 @@ static inline char ocfs2_lock_type_char(enum ocfs2_lock_type type)
- 		case OCFS2_LOCK_TYPE_OPEN:
- 			c = 'O';
- 			break;
-+		case OCFS2_LOCK_TYPE_FLOCK:
-+			c = 'F';
-+			break;
- 		default:
- 			c = '\0';
- 	}
-@@ -90,6 +94,7 @@ static char *ocfs2_lock_type_strings[] = {
- 	[OCFS2_LOCK_TYPE_RW] = "Write/Read",
- 	[OCFS2_LOCK_TYPE_DENTRY] = "Dentry",
- 	[OCFS2_LOCK_TYPE_OPEN] = "Open",
-+	[OCFS2_LOCK_TYPE_FLOCK] = "Flock",
- };
+@@ -111,6 +113,7 @@ static inline struct thread_info *current_thread_info(void)
+ #define TIF_NEED_RESCHED	2	/* rescheduling necessary */
+ #define TIF_RESTORE_SIGMASK	3	/* restore signal mask in do_signal() */
+ #define TIF_SINGLESTEP		4	/* singlestepping active */
++#define TIF_SYSCALL_AUDIT	5
+ #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
+@@ -121,6 +124,7 @@ static inline struct thread_info *current_thread_info(void)
+ #define _TIF_NEED_RESCHED	(1<<TIF_NEED_RESCHED)
+ #define _TIF_RESTORE_SIGMASK	(1<<TIF_RESTORE_SIGMASK)
+ #define _TIF_SINGLESTEP		(1<<TIF_SINGLESTEP)
++#define _TIF_SYSCALL_AUDIT		(1<<TIF_SYSCALL_AUDIT)
+ #define _TIF_USEDFPU		(1<<TIF_USEDFPU)
+ #define _TIF_POLLING_NRFLAG	(1<<TIF_POLLING_NRFLAG)
+ #define _TIF_FREEZE		(1<<TIF_FREEZE)
+diff --git a/include/asm-sh/tlb.h b/include/asm-sh/tlb.h
+index 53d185b..56ad1fb 100644
+--- a/include/asm-sh/tlb.h
++++ b/include/asm-sh/tlb.h
+@@ -1,6 +1,12 @@
+ #ifndef __ASM_SH_TLB_H
+ #define __ASM_SH_TLB_H
  
- static inline const char *ocfs2_lock_type_string(enum ocfs2_lock_type type)
-diff --git a/fs/ocfs2/resize.c b/fs/ocfs2/resize.c
++#ifdef CONFIG_SUPERH64
++# include "tlb_64.h"
++#endif
++
++#ifndef __ASSEMBLY__
++
+ #define tlb_start_vma(tlb, vma) \
+ 	flush_cache_range(vma, vma->vm_start, vma->vm_end)
+ 
+@@ -15,4 +21,6 @@
+ #define tlb_flush(tlb)				flush_tlb_mm((tlb)->mm)
+ 
+ #include <asm-generic/tlb.h>
+-#endif
++
++#endif /* __ASSEMBLY__ */
++#endif /* __ASM_SH_TLB_H */
+diff --git a/include/asm-sh/tlb_64.h b/include/asm-sh/tlb_64.h
 new file mode 100644
-index 0000000..37835ff
+index 0000000..0308e05
 --- /dev/null
-+++ b/fs/ocfs2/resize.c
-@@ -0,0 +1,634 @@
-+/* -*- mode: c; c-basic-offset: 8; -*-
-+ * vim: noexpandtab sw=8 ts=8 sts=0:
-+ *
-+ * resize.c
-+ *
-+ * volume resize.
-+ * Inspired by ext3/resize.c.
-+ *
-+ * Copyright (C) 2007 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.
++++ b/include/asm-sh/tlb_64.h
+@@ -0,0 +1,69 @@
++/*
++ * include/asm-sh/tlb_64.h
 + *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT 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) 2003  Paul Mundt
 + *
-+ * You 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.
++ * 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_SH_TLB_64_H
++#define __ASM_SH_TLB_64_H
 +
-+#include <linux/fs.h>
-+#include <linux/types.h>
++/* ITLB defines */
++#define ITLB_FIXED	0x00000000	/* First fixed ITLB, see head.S */
++#define ITLB_LAST_VAR_UNRESTRICTED	0x000003F0	/* Last ITLB */
 +
-+#define MLOG_MASK_PREFIX ML_DISK_ALLOC
-+#include <cluster/masklog.h>
++/* DTLB defines */
++#define DTLB_FIXED	0x00800000	/* First fixed DTLB, see head.S */
++#define DTLB_LAST_VAR_UNRESTRICTED	0x008003F0	/* Last DTLB */
 +
-+#include "ocfs2.h"
++#ifndef __ASSEMBLY__
 +
-+#include "alloc.h"
-+#include "dlmglue.h"
-+#include "inode.h"
-+#include "journal.h"
-+#include "super.h"
-+#include "sysfile.h"
-+#include "uptodate.h"
++/**
++ * for_each_dtlb_entry
++ *
++ * @tlb:	TLB entry
++ *
++ * Iterate over free (non-wired) DTLB entries
++ */
++#define for_each_dtlb_entry(tlb)		\
++	for (tlb  = cpu_data->dtlb.first;	\
++	     tlb <= cpu_data->dtlb.last;	\
++	     tlb += cpu_data->dtlb.step)
 +
-+#include "buffer_head_io.h"
-+#include "suballoc.h"
-+#include "resize.h"
++/**
++ * for_each_itlb_entry
++ *
++ * @tlb:	TLB entry
++ *
++ * Iterate over free (non-wired) ITLB entries
++ */
++#define for_each_itlb_entry(tlb)		\
++	for (tlb  = cpu_data->itlb.first;	\
++	     tlb <= cpu_data->itlb.last;	\
++	     tlb += cpu_data->itlb.step)
 +
-+/*
-+ * Check whether there are new backup superblocks exist
-+ * in the last group. If there are some, mark them or clear
-+ * them in the bitmap.
++/**
++ * __flush_tlb_slot
 + *
-+ * Return how many backups we find in the last group.
++ * @slot:	Address of TLB slot.
++ *
++ * Flushes TLB slot @slot.
 + */
-+static u16 ocfs2_calc_new_backup_super(struct inode *inode,
-+				       struct ocfs2_group_desc *gd,
-+				       int new_clusters,
-+				       u32 first_new_cluster,
-+				       u16 cl_cpg,
-+				       int set)
++static inline void __flush_tlb_slot(unsigned long long slot)
 +{
-+	int i;
-+	u16 backups = 0;
-+	u32 cluster;
-+	u64 blkno, gd_blkno, lgd_blkno = le64_to_cpu(gd->bg_blkno);
++	__asm__ __volatile__ ("putcfg %0, 0, r63\n" : : "r" (slot));
++}
 +
-+	for (i = 0; i < OCFS2_MAX_BACKUP_SUPERBLOCKS; i++) {
-+		blkno = ocfs2_backup_super_blkno(inode->i_sb, i);
-+		cluster = ocfs2_blocks_to_clusters(inode->i_sb, blkno);
++/* arch/sh64/mm/tlb.c */
++int sh64_tlb_init(void);
++unsigned long long sh64_next_free_dtlb_entry(void);
++unsigned long long sh64_get_wired_dtlb_entry(void);
++int sh64_put_wired_dtlb_entry(unsigned long long entry);
++void sh64_setup_tlb_slot(unsigned long long config_addr, unsigned long eaddr,
++			 unsigned long asid, unsigned long paddr);
++void sh64_teardown_tlb_slot(unsigned long long config_addr);
 +
-+		gd_blkno = ocfs2_which_cluster_group(inode, cluster);
-+		if (gd_blkno < lgd_blkno)
-+			continue;
-+		else if (gd_blkno > lgd_blkno)
-+			break;
++#endif /* __ASSEMBLY__ */
++#endif /* __ASM_SH_TLB_64_H */
+diff --git a/include/asm-sh/types.h b/include/asm-sh/types.h
+index 7ba69d9..a6e1d41 100644
+--- a/include/asm-sh/types.h
++++ b/include/asm-sh/types.h
+@@ -52,6 +52,12 @@ typedef unsigned long long u64;
+ 
+ typedef u32 dma_addr_t;
+ 
++#ifdef CONFIG_SUPERH32
++typedef u16 opcode_t;
++#else
++typedef u32 opcode_t;
++#endif
 +
-+		if (set)
-+			ocfs2_set_bit(cluster % cl_cpg,
-+				      (unsigned long *)gd->bg_bitmap);
-+		else
-+			ocfs2_clear_bit(cluster % cl_cpg,
-+					(unsigned long *)gd->bg_bitmap);
-+		backups++;
-+	}
+ #endif /* __ASSEMBLY__ */
+ 
+ #endif /* __KERNEL__ */
+diff --git a/include/asm-sh/uaccess.h b/include/asm-sh/uaccess.h
+index 77c391f..ff24ce9 100644
+--- a/include/asm-sh/uaccess.h
++++ b/include/asm-sh/uaccess.h
+@@ -1,563 +1,5 @@
+-/* $Id: uaccess.h,v 1.11 2003/10/13 07:21:20 lethal Exp $
+- *
+- * User space memory access functions
+- *
+- * Copyright (C) 1999, 2002  Niibe Yutaka
+- * Copyright (C) 2003  Paul Mundt
+- *
+- *  Based on:
+- *     MIPS implementation version 1.15 by
+- *              Copyright (C) 1996, 1997, 1998 by Ralf Baechle
+- *     and i386 version.
+- */
+-#ifndef __ASM_SH_UACCESS_H
+-#define __ASM_SH_UACCESS_H
+-
+-#include <linux/errno.h>
+-#include <linux/sched.h>
+-
+-#define VERIFY_READ    0
+-#define VERIFY_WRITE   1
+-
+-/*
+- * 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 (Data Segment Register?), these macros are misnamed.
+- */
+-
+-#define MAKE_MM_SEG(s)	((mm_segment_t) { (s) })
+-
+-#define KERNEL_DS	MAKE_MM_SEG(0xFFFFFFFFUL)
+-#define USER_DS		MAKE_MM_SEG(PAGE_OFFSET)
+-
+-#define segment_eq(a,b)	((a).seg == (b).seg)
+-
+-#define get_ds()	(KERNEL_DS)
+-
+-#if !defined(CONFIG_MMU)
+-/* NOMMU is always true */
+-#define __addr_ok(addr) (1)
+-
+-static inline mm_segment_t get_fs(void)
+-{
+-	return USER_DS;
+-}
+-
+-static inline void set_fs(mm_segment_t s)
+-{
+-}
+-
+-/*
+- * __access_ok: Check if address with size is OK or not.
+- *
+- * If we don't have an MMU (or if its disabled) the only thing we really have
+- * to look out for is if the address resides somewhere outside of what
+- * available RAM we have.
+- *
+- * TODO: This check could probably also stand to be restricted somewhat more..
+- * though it still does the Right Thing(tm) for the time being.
+- */
+-static inline int __access_ok(unsigned long addr, unsigned long size)
+-{
+-	return ((addr >= memory_start) && ((addr + size) < memory_end));
+-}
+-#else /* CONFIG_MMU */
+-#define __addr_ok(addr) \
+-	((unsigned long)(addr) < (current_thread_info()->addr_limit.seg))
+-
+-#define get_fs()	(current_thread_info()->addr_limit)
+-#define set_fs(x)	(current_thread_info()->addr_limit = (x))
+-
+-/*
+- * __access_ok: Check if address with size is OK or not.
+- *
+- * Uhhuh, this needs 33-bit arithmetic. We have a carry..
+- *
+- * sum := addr + size;  carry? --> flag = true;
+- * if (sum >= addr_limit) flag = true;
+- */
+-static inline int __access_ok(unsigned long addr, unsigned long size)
+-{
+-	unsigned long flag, sum;
+-
+-	__asm__("clrt\n\t"
+-		"addc	%3, %1\n\t"
+-		"movt	%0\n\t"
+-		"cmp/hi	%4, %1\n\t"
+-		"rotcl	%0"
+-		:"=&r" (flag), "=r" (sum)
+-		:"1" (addr), "r" (size),
+-		 "r" (current_thread_info()->addr_limit.seg)
+-		:"t");
+-	return flag == 0;
+-
+-}
+-#endif /* CONFIG_MMU */
+-
+-static inline int access_ok(int type, const void __user *p, unsigned long size)
+-{
+-	unsigned long addr = (unsigned long)p;
+-	return __access_ok(addr, size);
+-}
+-
+-/*
+- * Uh, these should become the main single-value transfer routines ...
+- * They automatically use the right size if we just have the right
+- * pointer type ...
+- *
+- * As SuperH uses the same address space for kernel and user data, we
+- * can just do these as direct assignments.
+- *
+- * Careful to not
+- * (a) re-use the arguments for side effects (sizeof is ok)
+- * (b) require any knowledge of processes at this stage
+- */
+-#define put_user(x,ptr)	__put_user_check((x),(ptr),sizeof(*(ptr)))
+-#define get_user(x,ptr) __get_user_check((x),(ptr),sizeof(*(ptr)))
+-
+-/*
+- * The "__xxx" versions do not do address space checking, useful when
+- * doing multiple accesses to the same area (the user has to do the
+- * checks by hand with "access_ok()")
+- */
+-#define __put_user(x,ptr) \
+-  __put_user_nocheck((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr)))
+-#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))
+-
+-#define __get_user_size(x,ptr,size,retval)			\
+-do {								\
+-	retval = 0;						\
+-	__chk_user_ptr(ptr);					\
+-	switch (size) {						\
+-	case 1:							\
+-		__get_user_asm(x, ptr, retval, "b");		\
+-		break;						\
+-	case 2:							\
+-		__get_user_asm(x, ptr, retval, "w");		\
+-		break;						\
+-	case 4:							\
+-		__get_user_asm(x, ptr, retval, "l");		\
+-		break;						\
+-	default:						\
+-		__get_user_unknown();				\
+-		break;						\
+-	}							\
+-} while (0)
+-
+-#define __get_user_nocheck(x,ptr,size)				\
+-({								\
+-	long __gu_err, __gu_val;				\
+-	__get_user_size(__gu_val, (ptr), (size), __gu_err);	\
+-	(x) = (__typeof__(*(ptr)))__gu_val;			\
+-	__gu_err;						\
+-})
+-
+-#ifdef CONFIG_MMU
+-#define __get_user_check(x,ptr,size)				\
+-({								\
+-	long __gu_err, __gu_val;				\
+-	__chk_user_ptr(ptr);					\
+-	switch (size) {						\
+-	case 1:							\
+-		__get_user_1(__gu_val, (ptr), __gu_err);	\
+-		break;						\
+-	case 2:							\
+-		__get_user_2(__gu_val, (ptr), __gu_err);	\
+-		break;						\
+-	case 4:							\
+-		__get_user_4(__gu_val, (ptr), __gu_err);	\
+-		break;						\
+-	default:						\
+-		__get_user_unknown();				\
+-		break;						\
+-	}							\
+-								\
+-	(x) = (__typeof__(*(ptr)))__gu_val;			\
+-	__gu_err;						\
+-})
+-
+-#define __get_user_1(x,addr,err) ({		\
+-__asm__("stc	r7_bank, %1\n\t"		\
+-	"mov.l	@(8,%1), %1\n\t"		\
+-	"and	%2, %1\n\t"			\
+-	"cmp/pz	%1\n\t"				\
+-	"bt/s	1f\n\t"				\
+-	" mov	#0, %0\n\t"			\
+-	"0:\n"					\
+-	"mov	#-14, %0\n\t"			\
+-	"bra	2f\n\t"				\
+-	" mov	#0, %1\n"			\
+-	"1:\n\t"				\
+-	"mov.b	@%2, %1\n\t"			\
+-	"extu.b	%1, %1\n"			\
+-	"2:\n"					\
+-	".section	__ex_table,\"a\"\n\t"	\
+-	".long	1b, 0b\n\t"			\
+-	".previous"				\
+-	: "=&r" (err), "=&r" (x)		\
+-	: "r" (addr)				\
+-	: "t");					\
+-})
+-
+-#define __get_user_2(x,addr,err) ({		\
+-__asm__("stc	r7_bank, %1\n\t"		\
+-	"mov.l	@(8,%1), %1\n\t"		\
+-	"and	%2, %1\n\t"			\
+-	"cmp/pz	%1\n\t"				\
+-	"bt/s	1f\n\t"				\
+-	" mov	#0, %0\n\t"			\
+-	"0:\n"					\
+-	"mov	#-14, %0\n\t"			\
+-	"bra	2f\n\t"				\
+-	" mov	#0, %1\n"			\
+-	"1:\n\t"				\
+-	"mov.w	@%2, %1\n\t"			\
+-	"extu.w	%1, %1\n"			\
+-	"2:\n"					\
+-	".section	__ex_table,\"a\"\n\t"	\
+-	".long	1b, 0b\n\t"			\
+-	".previous"				\
+-	: "=&r" (err), "=&r" (x)		\
+-	: "r" (addr)				\
+-	: "t");					\
+-})
+-
+-#define __get_user_4(x,addr,err) ({		\
+-__asm__("stc	r7_bank, %1\n\t"		\
+-	"mov.l	@(8,%1), %1\n\t"		\
+-	"and	%2, %1\n\t"			\
+-	"cmp/pz	%1\n\t"				\
+-	"bt/s	1f\n\t"				\
+-	" mov	#0, %0\n\t"			\
+-	"0:\n"					\
+-	"mov	#-14, %0\n\t"			\
+-	"bra	2f\n\t"				\
+-	" mov	#0, %1\n"			\
+-	"1:\n\t"				\
+-	"mov.l	@%2, %1\n\t"			\
+-	"2:\n"					\
+-	".section	__ex_table,\"a\"\n\t"	\
+-	".long	1b, 0b\n\t"			\
+-	".previous"				\
+-	: "=&r" (err), "=&r" (x)		\
+-	: "r" (addr)				\
+-	: "t");					\
+-})
+-#else /* CONFIG_MMU */
+-#define __get_user_check(x,ptr,size)					\
+-({									\
+-	long __gu_err, __gu_val;					\
+-	if (__access_ok((unsigned long)(ptr), (size))) {		\
+-		__get_user_size(__gu_val, (ptr), (size), __gu_err);	\
+-		(x) = (__typeof__(*(ptr)))__gu_val;			\
+-	} else								\
+-		__gu_err = -EFAULT;					\
+-	__gu_err;							\
+-})
+-#endif
+-
+-#define __get_user_asm(x, addr, err, insn) \
+-({ \
+-__asm__ __volatile__( \
+-	"1:\n\t" \
+-	"mov." insn "	%2, %1\n\t" \
+-	"mov	#0, %0\n" \
+-	"2:\n" \
+-	".section	.fixup,\"ax\"\n" \
+-	"3:\n\t" \
+-	"mov	#0, %1\n\t" \
+-	"mov.l	4f, %0\n\t" \
+-	"jmp	@%0\n\t" \
+-	" mov	%3, %0\n" \
+-	"4:	.long	2b\n\t" \
+-	".previous\n" \
+-	".section	__ex_table,\"a\"\n\t" \
+-	".long	1b, 3b\n\t" \
+-	".previous" \
+-	:"=&r" (err), "=&r" (x) \
+-	:"m" (__m(addr)), "i" (-EFAULT)); })
+-
+-extern void __get_user_unknown(void);
+-
+-#define __put_user_size(x,ptr,size,retval)		\
+-do {							\
+-	retval = 0;					\
+-	__chk_user_ptr(ptr);				\
+-	switch (size) {					\
+-	case 1:						\
+-		__put_user_asm(x, ptr, retval, "b");	\
+-		break;					\
+-	case 2:						\
+-		__put_user_asm(x, ptr, retval, "w");	\
+-		break;					\
+-	case 4:						\
+-		__put_user_asm(x, ptr, retval, "l");	\
+-		break;					\
+-	case 8:						\
+-		__put_user_u64(x, ptr, retval);		\
+-		break;					\
+-	default:					\
+-		__put_user_unknown();			\
+-	}						\
+-} while (0)
+-
+-#define __put_user_nocheck(x,ptr,size)			\
+-({							\
+-	long __pu_err;					\
+-	__put_user_size((x),(ptr),(size),__pu_err);	\
+-	__pu_err;					\
+-})
+-
+-#define __put_user_check(x,ptr,size)				\
+-({								\
+-	long __pu_err = -EFAULT;				\
+-	__typeof__(*(ptr)) __user *__pu_addr = (ptr);		\
+-								\
+-	if (__access_ok((unsigned long)__pu_addr,size))		\
+-		__put_user_size((x),__pu_addr,(size),__pu_err);	\
+-	__pu_err;						\
+-})
+-
+-#define __put_user_asm(x, addr, err, insn) \
+-({ \
+-__asm__ __volatile__( \
+-	"1:\n\t" \
+-	"mov." insn "	%1, %2\n\t" \
+-	"mov	#0, %0\n" \
+-	"2:\n" \
+-	".section	.fixup,\"ax\"\n" \
+-	"3:\n\t" \
+-	"nop\n\t" \
+-	"mov.l	4f, %0\n\t" \
+-	"jmp	@%0\n\t" \
+-	"mov	%3, %0\n" \
+-	"4:	.long	2b\n\t" \
+-	".previous\n" \
+-	".section	__ex_table,\"a\"\n\t" \
+-	".long	1b, 3b\n\t" \
+-	".previous" \
+-	:"=&r" (err) \
+-	:"r" (x), "m" (__m(addr)), "i" (-EFAULT) \
+-        :"memory"); })
+-
+-#if defined(__LITTLE_ENDIAN__)
+-#define __put_user_u64(val,addr,retval) \
+-({ \
+-__asm__ __volatile__( \
+-	"1:\n\t" \
+-	"mov.l	%R1,%2\n\t" \
+-	"mov.l	%S1,%T2\n\t" \
+-	"mov	#0,%0\n" \
+-	"2:\n" \
+-	".section	.fixup,\"ax\"\n" \
+-	"3:\n\t" \
+-	"nop\n\t" \
+-	"mov.l	4f,%0\n\t" \
+-	"jmp	@%0\n\t" \
+-	" mov	%3,%0\n" \
+-	"4:	.long	2b\n\t" \
+-	".previous\n" \
+-	".section	__ex_table,\"a\"\n\t" \
+-	".long	1b, 3b\n\t" \
+-	".previous" \
+-	: "=r" (retval) \
+-	: "r" (val), "m" (__m(addr)), "i" (-EFAULT) \
+-        : "memory"); })
++#ifdef CONFIG_SUPERH32
++# include "uaccess_32.h"
+ #else
+-#define __put_user_u64(val,addr,retval) \
+-({ \
+-__asm__ __volatile__( \
+-	"1:\n\t" \
+-	"mov.l	%S1,%2\n\t" \
+-	"mov.l	%R1,%T2\n\t" \
+-	"mov	#0,%0\n" \
+-	"2:\n" \
+-	".section	.fixup,\"ax\"\n" \
+-	"3:\n\t" \
+-	"nop\n\t" \
+-	"mov.l	4f,%0\n\t" \
+-	"jmp	@%0\n\t" \
+-	" mov	%3,%0\n" \
+-	"4:	.long	2b\n\t" \
+-	".previous\n" \
+-	".section	__ex_table,\"a\"\n\t" \
+-	".long	1b, 3b\n\t" \
+-	".previous" \
+-	: "=r" (retval) \
+-	: "r" (val), "m" (__m(addr)), "i" (-EFAULT) \
+-        : "memory"); })
++# include "uaccess_64.h"
+ #endif
+-
+-extern void __put_user_unknown(void);
+-
+-/* Generic arbitrary sized copy.  */
+-/* Return the number of bytes NOT copied */
+-__kernel_size_t __copy_user(void *to, const void *from, __kernel_size_t n);
+-
+-#define copy_to_user(to,from,n) ({ \
+-void *__copy_to = (void *) (to); \
+-__kernel_size_t __copy_size = (__kernel_size_t) (n); \
+-__kernel_size_t __copy_res; \
+-if(__copy_size && __access_ok((unsigned long)__copy_to, __copy_size)) { \
+-__copy_res = __copy_user(__copy_to, (void *) (from), __copy_size); \
+-} else __copy_res = __copy_size; \
+-__copy_res; })
+-
+-#define copy_from_user(to,from,n) ({ \
+-void *__copy_to = (void *) (to); \
+-void *__copy_from = (void *) (from); \
+-__kernel_size_t __copy_size = (__kernel_size_t) (n); \
+-__kernel_size_t __copy_res; \
+-if(__copy_size && __access_ok((unsigned long)__copy_from, __copy_size)) { \
+-__copy_res = __copy_user(__copy_to, __copy_from, __copy_size); \
+-} else __copy_res = __copy_size; \
+-__copy_res; })
+-
+-static __always_inline unsigned long
+-__copy_from_user(void *to, const void __user *from, unsigned long n)
+-{
+-	return __copy_user(to, (__force void *)from, n);
+-}
+-
+-static __always_inline unsigned long __must_check
+-__copy_to_user(void __user *to, const void *from, unsigned long n)
+-{
+-	return __copy_user((__force void *)to, from, n);
+-}
+-
+-#define __copy_to_user_inatomic __copy_to_user
+-#define __copy_from_user_inatomic __copy_from_user
+-
+-/*
+- * Clear the area and return remaining number of bytes
+- * (on failure.  Usually it's 0.)
+- */
+-extern __kernel_size_t __clear_user(void *addr, __kernel_size_t size);
+-
+-#define clear_user(addr,n) ({ \
+-void * __cl_addr = (addr); \
+-unsigned long __cl_size = (n); \
+-if (__cl_size && __access_ok(((unsigned long)(__cl_addr)), __cl_size)) \
+-__cl_size = __clear_user(__cl_addr, __cl_size); \
+-__cl_size; })
+-
+-static __inline__ int
+-__strncpy_from_user(unsigned long __dest, unsigned long __user __src, int __count)
+-{
+-	__kernel_size_t res;
+-	unsigned long __dummy, _d, _s;
+-
+-	__asm__ __volatile__(
+-		"9:\n"
+-		"mov.b	@%2+, %1\n\t"
+-		"cmp/eq	#0, %1\n\t"
+-		"bt/s	2f\n"
+-		"1:\n"
+-		"mov.b	%1, @%3\n\t"
+-		"dt	%7\n\t"
+-		"bf/s	9b\n\t"
+-		" add	#1, %3\n\t"
+-		"2:\n\t"
+-		"sub	%7, %0\n"
+-		"3:\n"
+-		".section .fixup,\"ax\"\n"
+-		"4:\n\t"
+-		"mov.l	5f, %1\n\t"
+-		"jmp	@%1\n\t"
+-		" mov	%8, %0\n\t"
+-		".balign 4\n"
+-		"5:	.long 3b\n"
+-		".previous\n"
+-		".section __ex_table,\"a\"\n"
+-		"	.balign 4\n"
+-		"	.long 9b,4b\n"
+-		".previous"
+-		: "=r" (res), "=&z" (__dummy), "=r" (_s), "=r" (_d)
+-		: "0" (__count), "2" (__src), "3" (__dest), "r" (__count),
+-		  "i" (-EFAULT)
+-		: "memory", "t");
+-
+-	return res;
+-}
+-
+-#define strncpy_from_user(dest,src,count) ({ \
+-unsigned long __sfu_src = (unsigned long) (src); \
+-int __sfu_count = (int) (count); \
+-long __sfu_res = -EFAULT; \
+-if(__access_ok(__sfu_src, __sfu_count)) { \
+-__sfu_res = __strncpy_from_user((unsigned long) (dest), __sfu_src, __sfu_count); \
+-} __sfu_res; })
+-
+-/*
+- * Return the size of a string (including the ending 0!)
+- */
+-static __inline__ long __strnlen_user(const char __user *__s, long __n)
+-{
+-	unsigned long res;
+-	unsigned long __dummy;
+-
+-	__asm__ __volatile__(
+-		"9:\n"
+-		"cmp/eq	%4, %0\n\t"
+-		"bt	2f\n"
+-		"1:\t"
+-		"mov.b	@(%0,%3), %1\n\t"
+-		"tst	%1, %1\n\t"
+-		"bf/s	9b\n\t"
+-		" add	#1, %0\n"
+-		"2:\n"
+-		".section .fixup,\"ax\"\n"
+-		"3:\n\t"
+-		"mov.l	4f, %1\n\t"
+-		"jmp	@%1\n\t"
+-		" mov	#0, %0\n"
+-		".balign 4\n"
+-		"4:	.long 2b\n"
+-		".previous\n"
+-		".section __ex_table,\"a\"\n"
+-		"	.balign 4\n"
+-		"	.long 1b,3b\n"
+-		".previous"
+-		: "=z" (res), "=&r" (__dummy)
+-		: "0" (0), "r" (__s), "r" (__n)
+-		: "t");
+-	return res;
+-}
+-
+-static __inline__ long strnlen_user(const char __user *s, long n)
+-{
+-	if (!__addr_ok(s))
+-		return 0;
+-	else
+-		return __strnlen_user(s, n);
+-}
+-
+-#define strlen_user(str)	strnlen_user(str, ~0UL >> 1)
+-
+-/*
+- * The exception table consists of pairs of addresses: the first is the
+- * address of an instruction that is allowed to fault, and the second is
+- * the address at which the program should continue.  No registers are
+- * modified, so it is entirely up to the continuation code to figure out
+- * what to do.
+- *
+- * All the routines below use bits of fixup code that are out of line
+- * with the main instruction path.  This means when everything is well,
+- * we don't even have to jump over them.  Further, they do not intrude
+- * on our cache or tlb entries.
+- */
+-
+-struct exception_table_entry
+-{
+-	unsigned long insn, fixup;
+-};
+-
+-extern int fixup_exception(struct pt_regs *regs);
+-
+-#endif /* __ASM_SH_UACCESS_H */
+diff --git a/include/asm-sh/uaccess_32.h b/include/asm-sh/uaccess_32.h
+new file mode 100644
+index 0000000..b6082f3
+--- /dev/null
++++ b/include/asm-sh/uaccess_32.h
+@@ -0,0 +1,510 @@
++/* $Id: uaccess.h,v 1.11 2003/10/13 07:21:20 lethal Exp $
++ *
++ * User space memory access functions
++ *
++ * Copyright (C) 1999, 2002  Niibe Yutaka
++ * Copyright (C) 2003  Paul Mundt
++ *
++ *  Based on:
++ *     MIPS implementation version 1.15 by
++ *              Copyright (C) 1996, 1997, 1998 by Ralf Baechle
++ *     and i386 version.
++ */
++#ifndef __ASM_SH_UACCESS_H
++#define __ASM_SH_UACCESS_H
 +
-+	mlog_exit_void();
-+	return backups;
-+}
++#include <linux/errno.h>
++#include <linux/sched.h>
 +
-+static int ocfs2_update_last_group_and_inode(handle_t *handle,
-+					     struct inode *bm_inode,
-+					     struct buffer_head *bm_bh,
-+					     struct buffer_head *group_bh,
-+					     u32 first_new_cluster,
-+					     int new_clusters)
-+{
-+	int ret = 0;
-+	struct ocfs2_super *osb = OCFS2_SB(bm_inode->i_sb);
-+	struct ocfs2_dinode *fe = (struct ocfs2_dinode *) bm_bh->b_data;
-+	struct ocfs2_chain_list *cl = &fe->id2.i_chain;
-+	struct ocfs2_chain_rec *cr;
-+	struct ocfs2_group_desc *group;
-+	u16 chain, num_bits, backups = 0;
-+	u16 cl_bpc = le16_to_cpu(cl->cl_bpc);
-+	u16 cl_cpg = le16_to_cpu(cl->cl_cpg);
++#define VERIFY_READ    0
++#define VERIFY_WRITE   1
 +
-+	mlog_entry("(new_clusters=%d, first_new_cluster = %u)\n",
-+		   new_clusters, first_new_cluster);
++/*
++ * 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 (Data Segment Register?), these macros are misnamed.
++ */
 +
-+	ret = ocfs2_journal_access(handle, bm_inode, group_bh,
-+				   OCFS2_JOURNAL_ACCESS_WRITE);
-+	if (ret < 0) {
-+		mlog_errno(ret);
-+		goto out;
-+	}
++#define MAKE_MM_SEG(s)	((mm_segment_t) { (s) })
 +
-+	group = (struct ocfs2_group_desc *)group_bh->b_data;
++#define KERNEL_DS	MAKE_MM_SEG(0xFFFFFFFFUL)
++#define USER_DS		MAKE_MM_SEG(PAGE_OFFSET)
 +
-+	/* update the group first. */
-+	num_bits = new_clusters * cl_bpc;
-+	le16_add_cpu(&group->bg_bits, num_bits);
-+	le16_add_cpu(&group->bg_free_bits_count, num_bits);
++#define segment_eq(a,b)	((a).seg == (b).seg)
 +
-+	/*
-+	 * check whether there are some new backup superblocks exist in
-+	 * this group and update the group bitmap accordingly.
-+	 */
-+	if (OCFS2_HAS_COMPAT_FEATURE(osb->sb,
-+				     OCFS2_FEATURE_COMPAT_BACKUP_SB)) {
-+		backups = ocfs2_calc_new_backup_super(bm_inode,
-+						     group,
-+						     new_clusters,
-+						     first_new_cluster,
-+						     cl_cpg, 1);
-+		le16_add_cpu(&group->bg_free_bits_count, -1 * backups);
-+	}
++#define get_ds()	(KERNEL_DS)
 +
-+	ret = ocfs2_journal_dirty(handle, group_bh);
-+	if (ret < 0) {
-+		mlog_errno(ret);
-+		goto out_rollback;
-+	}
++#if !defined(CONFIG_MMU)
++/* NOMMU is always true */
++#define __addr_ok(addr) (1)
 +
-+	/* update the inode accordingly. */
-+	ret = ocfs2_journal_access(handle, bm_inode, bm_bh,
-+				   OCFS2_JOURNAL_ACCESS_WRITE);
-+	if (ret < 0) {
-+		mlog_errno(ret);
-+		goto out_rollback;
-+	}
++static inline mm_segment_t get_fs(void)
++{
++	return USER_DS;
++}
 +
-+	chain = le16_to_cpu(group->bg_chain);
-+	cr = (&cl->cl_recs[chain]);
-+	le32_add_cpu(&cr->c_total, num_bits);
-+	le32_add_cpu(&cr->c_free, num_bits);
-+	le32_add_cpu(&fe->id1.bitmap1.i_total, num_bits);
-+	le32_add_cpu(&fe->i_clusters, new_clusters);
++static inline void set_fs(mm_segment_t s)
++{
++}
 +
-+	if (backups) {
-+		le32_add_cpu(&cr->c_free, -1 * backups);
-+		le32_add_cpu(&fe->id1.bitmap1.i_used, backups);
-+	}
++/*
++ * __access_ok: Check if address with size is OK or not.
++ *
++ * If we don't have an MMU (or if its disabled) the only thing we really have
++ * to look out for is if the address resides somewhere outside of what
++ * available RAM we have.
++ *
++ * TODO: This check could probably also stand to be restricted somewhat more..
++ * though it still does the Right Thing(tm) for the time being.
++ */
++static inline int __access_ok(unsigned long addr, unsigned long size)
++{
++	return ((addr >= memory_start) && ((addr + size) < memory_end));
++}
++#else /* CONFIG_MMU */
++#define __addr_ok(addr) \
++	((unsigned long)(addr) < (current_thread_info()->addr_limit.seg))
 +
-+	spin_lock(&OCFS2_I(bm_inode)->ip_lock);
-+	OCFS2_I(bm_inode)->ip_clusters = le32_to_cpu(fe->i_clusters);
-+	le64_add_cpu(&fe->i_size, new_clusters << osb->s_clustersize_bits);
-+	spin_unlock(&OCFS2_I(bm_inode)->ip_lock);
-+	i_size_write(bm_inode, le64_to_cpu(fe->i_size));
++#define get_fs()	(current_thread_info()->addr_limit)
++#define set_fs(x)	(current_thread_info()->addr_limit = (x))
 +
-+	ocfs2_journal_dirty(handle, bm_bh);
++/*
++ * __access_ok: Check if address with size is OK or not.
++ *
++ * Uhhuh, this needs 33-bit arithmetic. We have a carry..
++ *
++ * sum := addr + size;  carry? --> flag = true;
++ * if (sum >= addr_limit) flag = true;
++ */
++static inline int __access_ok(unsigned long addr, unsigned long size)
++{
++	unsigned long flag, sum;
 +
-+out_rollback:
-+	if (ret < 0) {
-+		ocfs2_calc_new_backup_super(bm_inode,
-+					    group,
-+					    new_clusters,
-+					    first_new_cluster,
-+					    cl_cpg, 0);
-+		le16_add_cpu(&group->bg_free_bits_count, backups);
-+		le16_add_cpu(&group->bg_bits, -1 * num_bits);
-+		le16_add_cpu(&group->bg_free_bits_count, -1 * num_bits);
-+	}
-+out:
-+	mlog_exit(ret);
-+	return ret;
++	__asm__("clrt\n\t"
++		"addc	%3, %1\n\t"
++		"movt	%0\n\t"
++		"cmp/hi	%4, %1\n\t"
++		"rotcl	%0"
++		:"=&r" (flag), "=r" (sum)
++		:"1" (addr), "r" (size),
++		 "r" (current_thread_info()->addr_limit.seg)
++		:"t");
++	return flag == 0;
 +}
++#endif /* CONFIG_MMU */
 +
-+static int update_backups(struct inode * inode, u32 clusters, char *data)
-+{
-+	int i, ret = 0;
-+	u32 cluster;
-+	u64 blkno;
-+	struct buffer_head *backup = NULL;
-+	struct ocfs2_dinode *backup_di = NULL;
-+	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
++#define access_ok(type, addr, size)	\
++	(__chk_user_ptr(addr),		\
++	 __access_ok((unsigned long __force)(addr), (size)))
 +
-+	/* calculate the real backups we need to update. */
-+	for (i = 0; i < OCFS2_MAX_BACKUP_SUPERBLOCKS; i++) {
-+		blkno = ocfs2_backup_super_blkno(inode->i_sb, i);
-+		cluster = ocfs2_blocks_to_clusters(inode->i_sb, blkno);
-+		if (cluster > clusters)
-+			break;
++/*
++ * Uh, these should become the main single-value transfer routines ...
++ * They automatically use the right size if we just have the right
++ * pointer type ...
++ *
++ * As SuperH uses the same address space for kernel and user data, we
++ * can just do these as direct assignments.
++ *
++ * Careful to not
++ * (a) re-use the arguments for side effects (sizeof is ok)
++ * (b) require any knowledge of processes at this stage
++ */
++#define put_user(x,ptr)		__put_user_check((x), (ptr), sizeof(*(ptr)))
++#define get_user(x,ptr)		__get_user_check((x), (ptr), sizeof(*(ptr)))
 +
-+		ret = ocfs2_read_block(osb, blkno, &backup, 0, NULL);
-+		if (ret < 0) {
-+			mlog_errno(ret);
-+			break;
-+		}
++/*
++ * The "__xxx" versions do not do address space checking, useful when
++ * doing multiple accesses to the same area (the user has to do the
++ * checks by hand with "access_ok()")
++ */
++#define __put_user(x,ptr)	__put_user_nocheck((x), (ptr), sizeof(*(ptr)))
++#define __get_user(x,ptr)	__get_user_nocheck((x), (ptr), sizeof(*(ptr)))
 +
-+		memcpy(backup->b_data, data, inode->i_sb->s_blocksize);
++struct __large_struct { unsigned long buf[100]; };
++#define __m(x) (*(struct __large_struct __user *)(x))
 +
-+		backup_di = (struct ocfs2_dinode *)backup->b_data;
-+		backup_di->i_blkno = cpu_to_le64(blkno);
++#define __get_user_size(x,ptr,size,retval)			\
++do {								\
++	retval = 0;						\
++	switch (size) {						\
++	case 1:							\
++		__get_user_asm(x, ptr, retval, "b");		\
++		break;						\
++	case 2:							\
++		__get_user_asm(x, ptr, retval, "w");		\
++		break;						\
++	case 4:							\
++		__get_user_asm(x, ptr, retval, "l");		\
++		break;						\
++	default:						\
++		__get_user_unknown();				\
++		break;						\
++	}							\
++} while (0)
 +
-+		ret = ocfs2_write_super_or_backup(osb, backup);
-+		brelse(backup);
-+		backup = NULL;
-+		if (ret < 0) {
-+			mlog_errno(ret);
-+			break;
-+		}
-+	}
++#define __get_user_nocheck(x,ptr,size)				\
++({								\
++	long __gu_err;						\
++	unsigned long __gu_val;					\
++	const __typeof__(*(ptr)) __user *__gu_addr = (ptr);	\
++	__chk_user_ptr(ptr);					\
++	__get_user_size(__gu_val, __gu_addr, (size), __gu_err);	\
++	(x) = (__typeof__(*(ptr)))__gu_val;			\
++	__gu_err;						\
++})
 +
-+	return ret;
-+}
++#define __get_user_check(x,ptr,size)					\
++({									\
++	long __gu_err = -EFAULT;					\
++	unsigned long __gu_val = 0;					\
++	const __typeof__(*(ptr)) *__gu_addr = (ptr);			\
++	if (likely(access_ok(VERIFY_READ, __gu_addr, (size))))		\
++		__get_user_size(__gu_val, __gu_addr, (size), __gu_err);	\
++	(x) = (__typeof__(*(ptr)))__gu_val;				\
++	__gu_err;							\
++})
 +
-+static void ocfs2_update_super_and_backups(struct inode *inode,
-+					   int new_clusters)
-+{
-+	int ret;
-+	u32 clusters = 0;
-+	struct buffer_head *super_bh = NULL;
-+	struct ocfs2_dinode *super_di = NULL;
-+	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
++#define __get_user_asm(x, addr, err, insn) \
++({ \
++__asm__ __volatile__( \
++	"1:\n\t" \
++	"mov." insn "	%2, %1\n\t" \
++	"2:\n" \
++	".section	.fixup,\"ax\"\n" \
++	"3:\n\t" \
++	"mov	#0, %1\n\t" \
++	"mov.l	4f, %0\n\t" \
++	"jmp	@%0\n\t" \
++	" mov	%3, %0\n\t" \
++	".balign	4\n" \
++	"4:	.long	2b\n\t" \
++	".previous\n" \
++	".section	__ex_table,\"a\"\n\t" \
++	".long	1b, 3b\n\t" \
++	".previous" \
++	:"=&r" (err), "=&r" (x) \
++	:"m" (__m(addr)), "i" (-EFAULT), "0" (err)); })
++
++extern void __get_user_unknown(void);
++
++#define __put_user_size(x,ptr,size,retval)		\
++do {							\
++	retval = 0;					\
++	switch (size) {					\
++	case 1:						\
++		__put_user_asm(x, ptr, retval, "b");	\
++		break;					\
++	case 2:						\
++		__put_user_asm(x, ptr, retval, "w");	\
++		break;					\
++	case 4:						\
++		__put_user_asm(x, ptr, retval, "l");	\
++		break;					\
++	case 8:						\
++		__put_user_u64(x, ptr, retval);		\
++		break;					\
++	default:					\
++		__put_user_unknown();			\
++	}						\
++} while (0)
 +
-+	/*
-+	 * 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);
-+	if (ret < 0) {
-+		mlog_errno(ret);
-+		goto out;
-+	}
++#define __put_user_nocheck(x,ptr,size)				\
++({								\
++	long __pu_err;						\
++	__typeof__(*(ptr)) __user *__pu_addr = (ptr);		\
++	__chk_user_ptr(ptr);					\
++	__put_user_size((x), __pu_addr, (size), __pu_err);	\
++	__pu_err;						\
++})
 +
-+	super_di = (struct ocfs2_dinode *)super_bh->b_data;
-+	le32_add_cpu(&super_di->i_clusters, new_clusters);
-+	clusters = le32_to_cpu(super_di->i_clusters);
++#define __put_user_check(x,ptr,size)				\
++({								\
++	long __pu_err = -EFAULT;				\
++	__typeof__(*(ptr)) __user *__pu_addr = (ptr);		\
++	if (likely(access_ok(VERIFY_WRITE, __pu_addr, size)))	\
++		__put_user_size((x), __pu_addr, (size),		\
++				__pu_err);			\
++	__pu_err;						\
++})
 +
-+	ret = ocfs2_write_super_or_backup(osb, super_bh);
-+	if (ret < 0) {
-+		mlog_errno(ret);
-+		goto out;
-+	}
++#define __put_user_asm(x, addr, err, insn) \
++({ \
++__asm__ __volatile__( \
++	"1:\n\t" \
++	"mov." insn "	%1, %2\n\t" \
++	"2:\n" \
++	".section	.fixup,\"ax\"\n" \
++	"3:\n\t" \
++	"mov.l	4f, %0\n\t" \
++	"jmp	@%0\n\t" \
++	" mov	%3, %0\n\t" \
++	".balign	4\n" \
++	"4:	.long	2b\n\t" \
++	".previous\n" \
++	".section	__ex_table,\"a\"\n\t" \
++	".long	1b, 3b\n\t" \
++	".previous" \
++	:"=&r" (err) \
++	:"r" (x), "m" (__m(addr)), "i" (-EFAULT), "0" (err)	\
++        :"memory"); })
++
++#if defined(CONFIG_CPU_LITTLE_ENDIAN)
++#define __put_user_u64(val,addr,retval) \
++({ \
++__asm__ __volatile__( \
++	"1:\n\t" \
++	"mov.l	%R1,%2\n\t" \
++	"mov.l	%S1,%T2\n\t" \
++	"2:\n" \
++	".section	.fixup,\"ax\"\n" \
++	"3:\n\t" \
++	"mov.l	4f,%0\n\t" \
++	"jmp	@%0\n\t" \
++	" mov	%3,%0\n\t" \
++	".balign	4\n" \
++	"4:	.long	2b\n\t" \
++	".previous\n" \
++	".section	__ex_table,\"a\"\n\t" \
++	".long	1b, 3b\n\t" \
++	".previous" \
++	: "=r" (retval) \
++	: "r" (val), "m" (__m(addr)), "i" (-EFAULT), "0" (retval) \
++        : "memory"); })
++#else
++#define __put_user_u64(val,addr,retval) \
++({ \
++__asm__ __volatile__( \
++	"1:\n\t" \
++	"mov.l	%S1,%2\n\t" \
++	"mov.l	%R1,%T2\n\t" \
++	"2:\n" \
++	".section	.fixup,\"ax\"\n" \
++	"3:\n\t" \
++	"mov.l	4f,%0\n\t" \
++	"jmp	@%0\n\t" \
++	" mov	%3,%0\n\t" \
++	".balign	4\n" \
++	"4:	.long	2b\n\t" \
++	".previous\n" \
++	".section	__ex_table,\"a\"\n\t" \
++	".long	1b, 3b\n\t" \
++	".previous" \
++	: "=r" (retval) \
++	: "r" (val), "m" (__m(addr)), "i" (-EFAULT), "0" (retval) \
++        : "memory"); })
++#endif
 +
-+	if (OCFS2_HAS_COMPAT_FEATURE(osb->sb, OCFS2_FEATURE_COMPAT_BACKUP_SB))
-+		ret = update_backups(inode, clusters, super_bh->b_data);
++extern void __put_user_unknown(void);
 +
-+out:
-+	brelse(super_bh);
-+	if (ret)
-+		printk(KERN_WARNING "ocfs2: Failed to update super blocks on %s"
-+			" during fs resize. This condition is not fatal,"
-+			" but fsck.ocfs2 should be run to fix it\n",
-+			osb->dev_str);
-+	return;
++/* Generic arbitrary sized copy.  */
++/* Return the number of bytes NOT copied */
++__kernel_size_t __copy_user(void *to, const void *from, __kernel_size_t n);
++
++#define copy_to_user(to,from,n) ({ \
++void *__copy_to = (void *) (to); \
++__kernel_size_t __copy_size = (__kernel_size_t) (n); \
++__kernel_size_t __copy_res; \
++if(__copy_size && __access_ok((unsigned long)__copy_to, __copy_size)) { \
++__copy_res = __copy_user(__copy_to, (void *) (from), __copy_size); \
++} else __copy_res = __copy_size; \
++__copy_res; })
++
++#define copy_from_user(to,from,n) ({ \
++void *__copy_to = (void *) (to); \
++void *__copy_from = (void *) (from); \
++__kernel_size_t __copy_size = (__kernel_size_t) (n); \
++__kernel_size_t __copy_res; \
++if(__copy_size && __access_ok((unsigned long)__copy_from, __copy_size)) { \
++__copy_res = __copy_user(__copy_to, __copy_from, __copy_size); \
++} else __copy_res = __copy_size; \
++__copy_res; })
++
++static __always_inline unsigned long
++__copy_from_user(void *to, const void __user *from, unsigned long n)
++{
++	return __copy_user(to, (__force void *)from, n);
++}
++
++static __always_inline unsigned long __must_check
++__copy_to_user(void __user *to, const void *from, unsigned long n)
++{
++	return __copy_user((__force void *)to, from, n);
++}
++
++#define __copy_to_user_inatomic __copy_to_user
++#define __copy_from_user_inatomic __copy_from_user
++
++/*
++ * Clear the area and return remaining number of bytes
++ * (on failure.  Usually it's 0.)
++ */
++extern __kernel_size_t __clear_user(void *addr, __kernel_size_t size);
++
++#define clear_user(addr,n) ({ \
++void * __cl_addr = (addr); \
++unsigned long __cl_size = (n); \
++if (__cl_size && __access_ok(((unsigned long)(__cl_addr)), __cl_size)) \
++__cl_size = __clear_user(__cl_addr, __cl_size); \
++__cl_size; })
++
++static __inline__ int
++__strncpy_from_user(unsigned long __dest, unsigned long __user __src, int __count)
++{
++	__kernel_size_t res;
++	unsigned long __dummy, _d, _s, _c;
++
++	__asm__ __volatile__(
++		"9:\n"
++		"mov.b	@%2+, %1\n\t"
++		"cmp/eq	#0, %1\n\t"
++		"bt/s	2f\n"
++		"1:\n"
++		"mov.b	%1, @%3\n\t"
++		"dt	%4\n\t"
++		"bf/s	9b\n\t"
++		" add	#1, %3\n\t"
++		"2:\n\t"
++		"sub	%4, %0\n"
++		"3:\n"
++		".section .fixup,\"ax\"\n"
++		"4:\n\t"
++		"mov.l	5f, %1\n\t"
++		"jmp	@%1\n\t"
++		" mov	%9, %0\n\t"
++		".balign 4\n"
++		"5:	.long 3b\n"
++		".previous\n"
++		".section __ex_table,\"a\"\n"
++		"	.balign 4\n"
++		"	.long 9b,4b\n"
++		".previous"
++		: "=r" (res), "=&z" (__dummy), "=r" (_s), "=r" (_d), "=r"(_c)
++		: "0" (__count), "2" (__src), "3" (__dest), "4" (__count),
++		  "i" (-EFAULT)
++		: "memory", "t");
++
++	return res;
 +}
 +
-+/*
-+ * Extend the filesystem to the new number of clusters specified.  This entry
-+ * point is only used to extend the current filesystem to the end of the last
-+ * existing group.
++/**
++ * 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.
++ */
++#define strncpy_from_user(dest,src,count) ({ \
++unsigned long __sfu_src = (unsigned long) (src); \
++int __sfu_count = (int) (count); \
++long __sfu_res = -EFAULT; \
++if(__access_ok(__sfu_src, __sfu_count)) { \
++__sfu_res = __strncpy_from_user((unsigned long) (dest), __sfu_src, __sfu_count); \
++} __sfu_res; })
++
++/*
++ * Return the size of a string (including the ending 0 even when we have
++ * exceeded the maximum string length).
++ */
++static __inline__ long __strnlen_user(const char __user *__s, long __n)
++{
++	unsigned long res;
++	unsigned long __dummy;
++
++	__asm__ __volatile__(
++		"1:\t"
++		"mov.b	@(%0,%3), %1\n\t"
++		"cmp/eq	%4, %0\n\t"
++		"bt/s	2f\n\t"
++		" add	#1, %0\n\t"
++		"tst	%1, %1\n\t"
++		"bf	1b\n\t"
++		"2:\n"
++		".section .fixup,\"ax\"\n"
++		"3:\n\t"
++		"mov.l	4f, %1\n\t"
++		"jmp	@%1\n\t"
++		" mov	#0, %0\n"
++		".balign 4\n"
++		"4:	.long 2b\n"
++		".previous\n"
++		".section __ex_table,\"a\"\n"
++		"	.balign 4\n"
++		"	.long 1b,3b\n"
++		".previous"
++		: "=z" (res), "=&r" (__dummy)
++		: "0" (0), "r" (__s), "r" (__n)
++		: "t");
++	return res;
++}
++
++/**
++ * strnlen_user: - Get the size of a string in user space.
++ * @s: The string to measure.
++ * @n: The maximum valid length
++ *
++ * 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 the string is too long, returns a value greater than @n.
 + */
-+int ocfs2_group_extend(struct inode * inode, int new_clusters)
++static __inline__ long strnlen_user(const char __user *s, long n)
 +{
-+	int ret;
-+	handle_t *handle;
-+	struct buffer_head *main_bm_bh = NULL;
-+	struct buffer_head *group_bh = NULL;
-+	struct inode *main_bm_inode = NULL;
-+	struct ocfs2_dinode *fe = NULL;
-+	struct ocfs2_group_desc *group = NULL;
-+	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
-+	u16 cl_bpc;
-+	u32 first_new_cluster;
-+	u64 lgd_blkno;
-+
-+	mlog_entry_void();
-+
-+	if (ocfs2_is_hard_readonly(osb) || ocfs2_is_soft_readonly(osb))
-+		return -EROFS;
-+
-+	if (new_clusters < 0)
-+		return -EINVAL;
-+	else if (new_clusters == 0)
++	if (!__addr_ok(s))
 +		return 0;
++	else
++		return __strnlen_user(s, n);
++}
 +
-+	main_bm_inode = ocfs2_get_system_file_inode(osb,
-+						    GLOBAL_BITMAP_SYSTEM_INODE,
-+						    OCFS2_INVALID_SLOT);
-+	if (!main_bm_inode) {
-+		ret = -EINVAL;
-+		mlog_errno(ret);
-+		goto out;
-+	}
++/**
++ * strlen_user: - Get the size of a string in user space.
++ * @str: The string to measure.
++ *
++ * Context: User context only.  This function may sleep.
++ *
++ * Get the size of a NUL-terminated string in user space.
++ *
++ * Returns the size of the string INCLUDING the terminating NUL.
++ * On exception, returns 0.
++ *
++ * If there is a limit on the length of a valid string, you may wish to
++ * consider using strnlen_user() instead.
++ */
++#define strlen_user(str)	strnlen_user(str, ~0UL >> 1)
 +
-+	mutex_lock(&main_bm_inode->i_mutex);
++/*
++ * The exception table consists of pairs of addresses: the first is the
++ * address of an instruction that is allowed to fault, and the second is
++ * the address at which the program should continue.  No registers are
++ * modified, so it is entirely up to the continuation code to figure out
++ * what to do.
++ *
++ * All the routines below use bits of fixup code that are out of line
++ * with the main instruction path.  This means when everything is well,
++ * we don't even have to jump over them.  Further, they do not intrude
++ * on our cache or tlb entries.
++ */
 +
-+	ret = ocfs2_inode_lock(main_bm_inode, &main_bm_bh, 1);
-+	if (ret < 0) {
-+		mlog_errno(ret);
-+		goto out_mutex;
-+	}
++struct exception_table_entry
++{
++	unsigned long insn, fixup;
++};
 +
-+	fe = (struct ocfs2_dinode *)main_bm_bh->b_data;
++extern int fixup_exception(struct pt_regs *regs);
 +
-+	if (le16_to_cpu(fe->id2.i_chain.cl_cpg) !=
-+				 ocfs2_group_bitmap_size(osb->sb) * 8) {
-+		mlog(ML_ERROR, "The disk is too old and small. "
-+		     "Force to do offline resize.");
-+		ret = -EINVAL;
-+		goto out_unlock;
-+	}
++#endif /* __ASM_SH_UACCESS_H */
+diff --git a/include/asm-sh/uaccess_64.h b/include/asm-sh/uaccess_64.h
+new file mode 100644
+index 0000000..d54ec08
+--- /dev/null
++++ b/include/asm-sh/uaccess_64.h
+@@ -0,0 +1,302 @@
++#ifndef __ASM_SH_UACCESS_64_H
++#define __ASM_SH_UACCESS_64_H
 +
-+	if (!OCFS2_IS_VALID_DINODE(fe)) {
-+		OCFS2_RO_ON_INVALID_DINODE(main_bm_inode->i_sb, fe);
-+		ret = -EIO;
-+		goto out_unlock;
-+	}
++/*
++ * include/asm-sh/uaccess_64.h
++ *
++ * Copyright (C) 2000, 2001  Paolo Alberelli
++ * Copyright (C) 2003, 2004  Paul Mundt
++ *
++ * User space memory access functions
++ *
++ * Copyright (C) 1999  Niibe Yutaka
++ *
++ *  Based on:
++ *     MIPS implementation version 1.15 by
++ *              Copyright (C) 1996, 1997, 1998 by Ralf Baechle
++ *     and i386 version.
++ *
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License.  See the file "COPYING" in the main directory of this archive
++ * for more details.
++ */
++#include <linux/errno.h>
++#include <linux/sched.h>
 +
-+	first_new_cluster = le32_to_cpu(fe->i_clusters);
-+	lgd_blkno = ocfs2_which_cluster_group(main_bm_inode,
-+					      first_new_cluster - 1);
++#define VERIFY_READ    0
++#define VERIFY_WRITE   1
 +
-+	ret = ocfs2_read_block(osb, lgd_blkno, &group_bh, OCFS2_BH_CACHED,
-+			       main_bm_inode);
-+	if (ret < 0) {
-+		mlog_errno(ret);
-+		goto out_unlock;
-+	}
++/*
++ * 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 (Data Segment Register?), these macros are misnamed.
++ */
 +
-+	group = (struct ocfs2_group_desc *)group_bh->b_data;
++#define MAKE_MM_SEG(s)	((mm_segment_t) { (s) })
 +
-+	ret = ocfs2_check_group_descriptor(inode->i_sb, fe, group);
-+	if (ret) {
-+		mlog_errno(ret);
-+		goto out_unlock;
-+	}
++#define KERNEL_DS	MAKE_MM_SEG(0xFFFFFFFF)
++#define USER_DS		MAKE_MM_SEG(0x80000000)
 +
-+	cl_bpc = le16_to_cpu(fe->id2.i_chain.cl_bpc);
-+	if (le16_to_cpu(group->bg_bits) / cl_bpc + new_clusters >
-+		le16_to_cpu(fe->id2.i_chain.cl_cpg)) {
-+		ret = -EINVAL;
-+		goto out_unlock;
-+	}
++#define get_ds()	(KERNEL_DS)
++#define get_fs()        (current_thread_info()->addr_limit)
++#define set_fs(x)       (current_thread_info()->addr_limit=(x))
 +
-+	mlog(0, "extend the last group at %llu, new clusters = %d\n",
-+	     (unsigned long long)le64_to_cpu(group->bg_blkno), new_clusters);
++#define segment_eq(a,b)	((a).seg == (b).seg)
 +
-+	handle = ocfs2_start_trans(osb, OCFS2_GROUP_EXTEND_CREDITS);
-+	if (IS_ERR(handle)) {
-+		mlog_errno(PTR_ERR(handle));
-+		ret = -EINVAL;
-+		goto out_unlock;
-+	}
++#define __addr_ok(addr) ((unsigned long)(addr) < (current_thread_info()->addr_limit.seg))
 +
-+	/* update the last group descriptor and inode. */
-+	ret = ocfs2_update_last_group_and_inode(handle, main_bm_inode,
-+						main_bm_bh, group_bh,
-+						first_new_cluster,
-+						new_clusters);
-+	if (ret) {
-+		mlog_errno(ret);
-+		goto out_commit;
-+	}
++/*
++ * Uhhuh, this needs 33-bit arithmetic. We have a carry..
++ *
++ * sum := addr + size;  carry? --> flag = true;
++ * if (sum >= addr_limit) flag = true;
++ */
++#define __range_ok(addr,size) (((unsigned long) (addr) + (size) < (current_thread_info()->addr_limit.seg)) ? 0 : 1)
 +
-+	ocfs2_update_super_and_backups(main_bm_inode, new_clusters);
++#define access_ok(type,addr,size) (__range_ok(addr,size) == 0)
++#define __access_ok(addr,size) (__range_ok(addr,size) == 0)
 +
-+out_commit:
-+	ocfs2_commit_trans(osb, handle);
-+out_unlock:
-+	brelse(group_bh);
-+	brelse(main_bm_bh);
++/*
++ * Uh, these should become the main single-value transfer routines ...
++ * They automatically use the right size if we just have the right
++ * pointer type ...
++ *
++ * As MIPS uses the same address space for kernel and user data, we
++ * can just do these as direct assignments.
++ *
++ * Careful to not
++ * (a) re-use the arguments for side effects (sizeof is ok)
++ * (b) require any knowledge of processes at this stage
++ */
++#define put_user(x,ptr)	__put_user_check((x),(ptr),sizeof(*(ptr)))
++#define get_user(x,ptr) __get_user_check((x),(ptr),sizeof(*(ptr)))
 +
-+	ocfs2_inode_unlock(main_bm_inode, 1);
++/*
++ * The "__xxx" versions do not do address space checking, useful when
++ * doing multiple accesses to the same area (the user has to do the
++ * checks by hand with "access_ok()")
++ */
++#define __put_user(x,ptr) __put_user_nocheck((x),(ptr),sizeof(*(ptr)))
++#define __get_user(x,ptr) __get_user_nocheck((x),(ptr),sizeof(*(ptr)))
 +
-+out_mutex:
-+	mutex_unlock(&main_bm_inode->i_mutex);
-+	iput(main_bm_inode);
++/*
++ * The "xxx_ret" versions return constant specified in third argument, if
++ * something bad happens. These macros can be optimized for the
++ * case of just returning from the function xxx_ret is used.
++ */
 +
-+out:
-+	mlog_exit_void();
-+	return ret;
-+}
++#define put_user_ret(x,ptr,ret) ({ \
++if (put_user(x,ptr)) return ret; })
 +
-+static int ocfs2_check_new_group(struct inode *inode,
-+				 struct ocfs2_dinode *di,
-+				 struct ocfs2_new_group_input *input,
-+				 struct buffer_head *group_bh)
-+{
-+	int ret;
-+	struct ocfs2_group_desc *gd;
-+	u16 cl_bpc = le16_to_cpu(di->id2.i_chain.cl_bpc);
-+	unsigned int max_bits = le16_to_cpu(di->id2.i_chain.cl_cpg) *
-+				le16_to_cpu(di->id2.i_chain.cl_bpc);
++#define get_user_ret(x,ptr,ret) ({ \
++if (get_user(x,ptr)) return ret; })
 +
++#define __put_user_ret(x,ptr,ret) ({ \
++if (__put_user(x,ptr)) return ret; })
 +
-+	gd = (struct ocfs2_group_desc *)group_bh->b_data;
++#define __get_user_ret(x,ptr,ret) ({ \
++if (__get_user(x,ptr)) return ret; })
 +
-+	ret = -EIO;
-+	if (!OCFS2_IS_VALID_GROUP_DESC(gd))
-+		mlog(ML_ERROR, "Group descriptor # %llu isn't valid.\n",
-+		     (unsigned long long)le64_to_cpu(gd->bg_blkno));
-+	else if (di->i_blkno != gd->bg_parent_dinode)
-+		mlog(ML_ERROR, "Group descriptor # %llu has bad parent "
-+		     "pointer (%llu, expected %llu)\n",
-+		     (unsigned long long)le64_to_cpu(gd->bg_blkno),
-+		     (unsigned long long)le64_to_cpu(gd->bg_parent_dinode),
-+		     (unsigned long long)le64_to_cpu(di->i_blkno));
-+	else if (le16_to_cpu(gd->bg_bits) > max_bits)
-+		mlog(ML_ERROR, "Group descriptor # %llu has bit count of %u\n",
-+		     (unsigned long long)le64_to_cpu(gd->bg_blkno),
-+		     le16_to_cpu(gd->bg_bits));
-+	else if (le16_to_cpu(gd->bg_free_bits_count) > le16_to_cpu(gd->bg_bits))
-+		mlog(ML_ERROR, "Group descriptor # %llu has bit count %u but "
-+		     "claims that %u are free\n",
-+		     (unsigned long long)le64_to_cpu(gd->bg_blkno),
-+		     le16_to_cpu(gd->bg_bits),
-+		     le16_to_cpu(gd->bg_free_bits_count));
-+	else if (le16_to_cpu(gd->bg_bits) > (8 * le16_to_cpu(gd->bg_size)))
-+		mlog(ML_ERROR, "Group descriptor # %llu has bit count %u but "
-+		     "max bitmap bits of %u\n",
-+		     (unsigned long long)le64_to_cpu(gd->bg_blkno),
-+		     le16_to_cpu(gd->bg_bits),
-+		     8 * le16_to_cpu(gd->bg_size));
-+	else if (le16_to_cpu(gd->bg_chain) != input->chain)
-+		mlog(ML_ERROR, "Group descriptor # %llu has bad chain %u "
-+		     "while input has %u set.\n",
-+		     (unsigned long long)le64_to_cpu(gd->bg_blkno),
-+		     le16_to_cpu(gd->bg_chain), input->chain);
-+	else if (le16_to_cpu(gd->bg_bits) != input->clusters * cl_bpc)
-+		mlog(ML_ERROR, "Group descriptor # %llu has bit count %u but "
-+		     "input has %u clusters set\n",
-+		     (unsigned long long)le64_to_cpu(gd->bg_blkno),
-+		     le16_to_cpu(gd->bg_bits), input->clusters);
-+	else if (le16_to_cpu(gd->bg_free_bits_count) != input->frees * cl_bpc)
-+		mlog(ML_ERROR, "Group descriptor # %llu has free bit count %u "
-+		     "but it should have %u set\n",
-+		     (unsigned long long)le64_to_cpu(gd->bg_blkno),
-+		     le16_to_cpu(gd->bg_bits),
-+		     input->frees * cl_bpc);
-+	else
-+		ret = 0;
++struct __large_struct { unsigned long buf[100]; };
++#define __m(x) (*(struct __large_struct *)(x))
 +
-+	return ret;
-+}
++#define __get_user_size(x,ptr,size,retval)			\
++do {								\
++	retval = 0;						\
++	switch (size) {						\
++	case 1:							\
++		retval = __get_user_asm_b(x, ptr);		\
++		break;						\
++	case 2:							\
++		retval = __get_user_asm_w(x, ptr);		\
++		break;						\
++	case 4:							\
++		retval = __get_user_asm_l(x, ptr);		\
++		break;						\
++	case 8:							\
++		retval = __get_user_asm_q(x, ptr);		\
++		break;						\
++	default:						\
++		__get_user_unknown();				\
++		break;						\
++	}							\
++} while (0)
 +
-+static int ocfs2_verify_group_and_input(struct inode *inode,
-+					struct ocfs2_dinode *di,
-+					struct ocfs2_new_group_input *input,
-+					struct buffer_head *group_bh)
-+{
-+	u16 cl_count = le16_to_cpu(di->id2.i_chain.cl_count);
-+	u16 cl_cpg = le16_to_cpu(di->id2.i_chain.cl_cpg);
-+	u16 next_free = le16_to_cpu(di->id2.i_chain.cl_next_free_rec);
-+	u32 cluster = ocfs2_blocks_to_clusters(inode->i_sb, input->group);
-+	u32 total_clusters = le32_to_cpu(di->i_clusters);
-+	int ret = -EINVAL;
++#define __get_user_nocheck(x,ptr,size)				\
++({								\
++	long __gu_err, __gu_val;				\
++	__get_user_size((void *)&__gu_val, (long)(ptr),		\
++			(size), __gu_err);			\
++	(x) = (__typeof__(*(ptr)))__gu_val;			\
++	__gu_err;						\
++})
 +
-+	if (cluster < total_clusters)
-+		mlog(ML_ERROR, "add a group which is in the current volume.\n");
-+	else if (input->chain >= cl_count)
-+		mlog(ML_ERROR, "input chain exceeds the limit.\n");
-+	else if (next_free != cl_count && next_free != input->chain)
-+		mlog(ML_ERROR,
-+		     "the add group should be in chain %u\n", next_free);
-+	else if (total_clusters + input->clusters < total_clusters)
-+		mlog(ML_ERROR, "add group's clusters overflow.\n");
-+	else if (input->clusters > cl_cpg)
-+		mlog(ML_ERROR, "the cluster exceeds the maximum of a group\n");
-+	else if (input->frees > input->clusters)
-+		mlog(ML_ERROR, "the free cluster exceeds the total clusters\n");
-+	else if (total_clusters % cl_cpg != 0)
-+		mlog(ML_ERROR,
-+		     "the last group isn't full. Use group extend first.\n");
-+	else if (input->group != ocfs2_which_cluster_group(inode, cluster))
-+		mlog(ML_ERROR, "group blkno is invalid\n");
-+	else if ((ret = ocfs2_check_new_group(inode, di, input, group_bh)))
-+		mlog(ML_ERROR, "group descriptor check failed.\n");
-+	else
-+		ret = 0;
++#define __get_user_check(x,ptr,size)				\
++({								\
++	long __gu_addr = (long)(ptr);				\
++	long __gu_err = -EFAULT, __gu_val;			\
++	if (__access_ok(__gu_addr, (size)))			\
++		__get_user_size((void *)&__gu_val, __gu_addr,	\
++				(size), __gu_err);		\
++	(x) = (__typeof__(*(ptr))) __gu_val;			\
++	__gu_err;						\
++})
 +
-+	return ret;
-+}
++extern long __get_user_asm_b(void *, long);
++extern long __get_user_asm_w(void *, long);
++extern long __get_user_asm_l(void *, long);
++extern long __get_user_asm_q(void *, long);
++extern void __get_user_unknown(void);
 +
-+/* Add a new group descriptor to global_bitmap. */
-+int ocfs2_group_add(struct inode *inode, struct ocfs2_new_group_input *input)
-+{
-+	int ret;
-+	handle_t *handle;
-+	struct buffer_head *main_bm_bh = NULL;
-+	struct inode *main_bm_inode = NULL;
-+	struct ocfs2_dinode *fe = NULL;
-+	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
-+	struct buffer_head *group_bh = NULL;
-+	struct ocfs2_group_desc *group = NULL;
-+	struct ocfs2_chain_list *cl;
-+	struct ocfs2_chain_rec *cr;
-+	u16 cl_bpc;
++#define __put_user_size(x,ptr,size,retval)			\
++do {								\
++	retval = 0;						\
++	switch (size) {						\
++	case 1:							\
++		retval = __put_user_asm_b(x, ptr);		\
++		break;						\
++	case 2:							\
++		retval = __put_user_asm_w(x, ptr);		\
++		break;						\
++	case 4:							\
++		retval = __put_user_asm_l(x, ptr);		\
++		break;						\
++	case 8:							\
++		retval = __put_user_asm_q(x, ptr);		\
++		break;						\
++	default:						\
++		__put_user_unknown();				\
++	}							\
++} while (0)
 +
-+	mlog_entry_void();
++#define __put_user_nocheck(x,ptr,size)				\
++({								\
++	long __pu_err;						\
++	__typeof__(*(ptr)) __pu_val = (x);			\
++	__put_user_size((void *)&__pu_val, (long)(ptr), (size), __pu_err); \
++	__pu_err;						\
++})
 +
-+	if (ocfs2_is_hard_readonly(osb) || ocfs2_is_soft_readonly(osb))
-+		return -EROFS;
++#define __put_user_check(x,ptr,size)				\
++({								\
++	long __pu_err = -EFAULT;				\
++	long __pu_addr = (long)(ptr);				\
++	__typeof__(*(ptr)) __pu_val = (x);			\
++								\
++	if (__access_ok(__pu_addr, (size)))			\
++		__put_user_size((void *)&__pu_val, __pu_addr, (size), __pu_err);\
++	__pu_err;						\
++})
 +
-+	main_bm_inode = ocfs2_get_system_file_inode(osb,
-+						    GLOBAL_BITMAP_SYSTEM_INODE,
-+						    OCFS2_INVALID_SLOT);
-+	if (!main_bm_inode) {
-+		ret = -EINVAL;
-+		mlog_errno(ret);
-+		goto out;
-+	}
++extern long __put_user_asm_b(void *, long);
++extern long __put_user_asm_w(void *, long);
++extern long __put_user_asm_l(void *, long);
++extern long __put_user_asm_q(void *, long);
++extern void __put_user_unknown(void);
++
++
++/* Generic arbitrary sized copy.  */
++/* Return the number of bytes NOT copied */
++/* XXX: should be such that: 4byte and the rest. */
++extern __kernel_size_t __copy_user(void *__to, const void *__from, __kernel_size_t __n);
++
++#define copy_to_user(to,from,n) ({ \
++void *__copy_to = (void *) (to); \
++__kernel_size_t __copy_size = (__kernel_size_t) (n); \
++__kernel_size_t __copy_res; \
++if(__copy_size && __access_ok((unsigned long)__copy_to, __copy_size)) { \
++__copy_res = __copy_user(__copy_to, (void *) (from), __copy_size); \
++} else __copy_res = __copy_size; \
++__copy_res; })
++
++#define copy_to_user_ret(to,from,n,retval) ({ \
++if (copy_to_user(to,from,n)) \
++	return retval; \
++})
 +
-+	mutex_lock(&main_bm_inode->i_mutex);
++#define __copy_to_user(to,from,n)		\
++	__copy_user((void *)(to),		\
++		    (void *)(from), n)
++
++#define __copy_to_user_ret(to,from,n,retval) ({ \
++if (__copy_to_user(to,from,n)) \
++	return retval; \
++})
 +
-+	ret = ocfs2_inode_lock(main_bm_inode, &main_bm_bh, 1);
-+	if (ret < 0) {
-+		mlog_errno(ret);
-+		goto out_mutex;
-+	}
++#define copy_from_user(to,from,n) ({ \
++void *__copy_to = (void *) (to); \
++void *__copy_from = (void *) (from); \
++__kernel_size_t __copy_size = (__kernel_size_t) (n); \
++__kernel_size_t __copy_res; \
++if(__copy_size && __access_ok((unsigned long)__copy_from, __copy_size)) { \
++__copy_res = __copy_user(__copy_to, __copy_from, __copy_size); \
++} else __copy_res = __copy_size; \
++__copy_res; })
++
++#define copy_from_user_ret(to,from,n,retval) ({ \
++if (copy_from_user(to,from,n)) \
++	return retval; \
++})
 +
-+	fe = (struct ocfs2_dinode *)main_bm_bh->b_data;
++#define __copy_from_user(to,from,n)		\
++	__copy_user((void *)(to),		\
++		    (void *)(from), n)
++
++#define __copy_from_user_ret(to,from,n,retval) ({ \
++if (__copy_from_user(to,from,n)) \
++	return retval; \
++})
 +
-+	if (le16_to_cpu(fe->id2.i_chain.cl_cpg) !=
-+				 ocfs2_group_bitmap_size(osb->sb) * 8) {
-+		mlog(ML_ERROR, "The disk is too old and small."
-+		     " Force to do offline resize.");
-+		ret = -EINVAL;
-+		goto out_unlock;
-+	}
++#define __copy_to_user_inatomic __copy_to_user
++#define __copy_from_user_inatomic __copy_from_user
 +
-+	ret = ocfs2_read_block(osb, input->group, &group_bh, 0, NULL);
-+	if (ret < 0) {
-+		mlog(ML_ERROR, "Can't read the group descriptor # %llu "
-+		     "from the device.", (unsigned long long)input->group);
-+		goto out_unlock;
-+	}
++/* XXX: Not sure it works well..
++   should be such that: 4byte clear and the rest. */
++extern __kernel_size_t __clear_user(void *addr, __kernel_size_t size);
 +
-+	ocfs2_set_new_buffer_uptodate(inode, group_bh);
++#define clear_user(addr,n) ({ \
++void * __cl_addr = (addr); \
++unsigned long __cl_size = (n); \
++if (__cl_size && __access_ok(((unsigned long)(__cl_addr)), __cl_size)) \
++__cl_size = __clear_user(__cl_addr, __cl_size); \
++__cl_size; })
 +
-+	ret = ocfs2_verify_group_and_input(main_bm_inode, fe, input, group_bh);
-+	if (ret) {
-+		mlog_errno(ret);
-+		goto out_unlock;
-+	}
++extern int __strncpy_from_user(unsigned long __dest, unsigned long __src, int __count);
 +
-+	mlog(0, "Add a new group  %llu in chain = %u, length = %u\n",
-+	     (unsigned long long)input->group, input->chain, input->clusters);
++#define strncpy_from_user(dest,src,count) ({ \
++unsigned long __sfu_src = (unsigned long) (src); \
++int __sfu_count = (int) (count); \
++long __sfu_res = -EFAULT; \
++if(__access_ok(__sfu_src, __sfu_count)) { \
++__sfu_res = __strncpy_from_user((unsigned long) (dest), __sfu_src, __sfu_count); \
++} __sfu_res; })
 +
-+	handle = ocfs2_start_trans(osb, OCFS2_GROUP_ADD_CREDITS);
-+	if (IS_ERR(handle)) {
-+		mlog_errno(PTR_ERR(handle));
-+		ret = -EINVAL;
-+		goto out_unlock;
-+	}
++#define strlen_user(str) strnlen_user(str, ~0UL >> 1)
 +
-+	cl_bpc = le16_to_cpu(fe->id2.i_chain.cl_bpc);
-+	cl = &fe->id2.i_chain;
-+	cr = &cl->cl_recs[input->chain];
++/*
++ * Return the size of a string (including the ending 0!)
++ */
++extern long __strnlen_user(const char *__s, long __n);
 +
-+	ret = ocfs2_journal_access(handle, main_bm_inode, group_bh,
-+				   OCFS2_JOURNAL_ACCESS_WRITE);
-+	if (ret < 0) {
-+		mlog_errno(ret);
-+		goto out_commit;
-+	}
++static inline long strnlen_user(const char *s, long n)
++{
++	if (!__addr_ok(s))
++		return 0;
++	else
++		return __strnlen_user(s, n);
++}
 +
-+	group = (struct ocfs2_group_desc *)group_bh->b_data;
-+	group->bg_next_group = cr->c_blkno;
++struct exception_table_entry
++{
++	unsigned long insn, fixup;
++};
 +
-+	ret = ocfs2_journal_dirty(handle, group_bh);
-+	if (ret < 0) {
-+		mlog_errno(ret);
-+		goto out_commit;
-+	}
++#define ARCH_HAS_SEARCH_EXTABLE
 +
-+	ret = ocfs2_journal_access(handle, main_bm_inode, main_bm_bh,
-+				   OCFS2_JOURNAL_ACCESS_WRITE);
-+	if (ret < 0) {
-+		mlog_errno(ret);
-+		goto out_commit;
-+	}
++/* Returns 0 if exception not found and fixup.unit otherwise.  */
++extern unsigned long search_exception_table(unsigned long addr);
++extern const struct exception_table_entry *search_exception_tables (unsigned long addr);
 +
-+	if (input->chain == le16_to_cpu(cl->cl_next_free_rec)) {
-+		le16_add_cpu(&cl->cl_next_free_rec, 1);
-+		memset(cr, 0, sizeof(struct ocfs2_chain_rec));
-+	}
++#endif /* __ASM_SH_UACCESS_64_H */
+diff --git a/include/asm-sh/unistd.h b/include/asm-sh/unistd.h
+index b182b1c..4b21f36 100644
+--- a/include/asm-sh/unistd.h
++++ b/include/asm-sh/unistd.h
+@@ -1,376 +1,5 @@
+-#ifndef __ASM_SH_UNISTD_H
+-#define __ASM_SH_UNISTD_H
+-
+-/*
+- * Copyright (C) 1999  Niibe Yutaka
+- */
+-
+-/*
+- * This file contains the system call numbers.
+- */
+-
+-#define __NR_restart_syscall	  0
+-#define __NR_exit		  1
+-#define __NR_fork		  2
+-#define __NR_read		  3
+-#define __NR_write		  4
+-#define __NR_open		  5
+-#define __NR_close		  6
+-#define __NR_waitpid		  7
+-#define __NR_creat		  8
+-#define __NR_link		  9
+-#define __NR_unlink		 10
+-#define __NR_execve		 11
+-#define __NR_chdir		 12
+-#define __NR_time		 13
+-#define __NR_mknod		 14
+-#define __NR_chmod		 15
+-#define __NR_lchown		 16
+-#define __NR_break		 17
+-#define __NR_oldstat		 18
+-#define __NR_lseek		 19
+-#define __NR_getpid		 20
+-#define __NR_mount		 21
+-#define __NR_umount		 22
+-#define __NR_setuid		 23
+-#define __NR_getuid		 24
+-#define __NR_stime		 25
+-#define __NR_ptrace		 26
+-#define __NR_alarm		 27
+-#define __NR_oldfstat		 28
+-#define __NR_pause		 29
+-#define __NR_utime		 30
+-#define __NR_stty		 31
+-#define __NR_gtty		 32
+-#define __NR_access		 33
+-#define __NR_nice		 34
+-#define __NR_ftime		 35
+-#define __NR_sync		 36
+-#define __NR_kill		 37
+-#define __NR_rename		 38
+-#define __NR_mkdir		 39
+-#define __NR_rmdir		 40
+-#define __NR_dup		 41
+-#define __NR_pipe		 42
+-#define __NR_times		 43
+-#define __NR_prof		 44
+-#define __NR_brk		 45
+-#define __NR_setgid		 46
+-#define __NR_getgid		 47
+-#define __NR_signal		 48
+-#define __NR_geteuid		 49
+-#define __NR_getegid		 50
+-#define __NR_acct		 51
+-#define __NR_umount2		 52
+-#define __NR_lock		 53
+-#define __NR_ioctl		 54
+-#define __NR_fcntl		 55
+-#define __NR_mpx		 56
+-#define __NR_setpgid		 57
+-#define __NR_ulimit		 58
+-#define __NR_oldolduname	 59
+-#define __NR_umask		 60
+-#define __NR_chroot		 61
+-#define __NR_ustat		 62
+-#define __NR_dup2		 63
+-#define __NR_getppid		 64
+-#define __NR_getpgrp		 65
+-#define __NR_setsid		 66
+-#define __NR_sigaction		 67
+-#define __NR_sgetmask		 68
+-#define __NR_ssetmask		 69
+-#define __NR_setreuid		 70
+-#define __NR_setregid		 71
+-#define __NR_sigsuspend		 72
+-#define __NR_sigpending		 73
+-#define __NR_sethostname	 74
+-#define __NR_setrlimit		 75
+-#define __NR_getrlimit		 76	/* Back compatible 2Gig limited rlimit */
+-#define __NR_getrusage		 77
+-#define __NR_gettimeofday	 78
+-#define __NR_settimeofday	 79
+-#define __NR_getgroups		 80
+-#define __NR_setgroups		 81
+-#define __NR_select		 82
+-#define __NR_symlink		 83
+-#define __NR_oldlstat		 84
+-#define __NR_readlink		 85
+-#define __NR_uselib		 86
+-#define __NR_swapon		 87
+-#define __NR_reboot		 88
+-#define __NR_readdir		 89
+-#define __NR_mmap		 90
+-#define __NR_munmap		 91
+-#define __NR_truncate		 92
+-#define __NR_ftruncate		 93
+-#define __NR_fchmod		 94
+-#define __NR_fchown		 95
+-#define __NR_getpriority	 96
+-#define __NR_setpriority	 97
+-#define __NR_profil		 98
+-#define __NR_statfs		 99
+-#define __NR_fstatfs		100
+-#define __NR_ioperm		101
+-#define __NR_socketcall		102
+-#define __NR_syslog		103
+-#define __NR_setitimer		104
+-#define __NR_getitimer		105
+-#define __NR_stat		106
+-#define __NR_lstat		107
+-#define __NR_fstat		108
+-#define __NR_olduname		109
+-#define __NR_iopl		110
+-#define __NR_vhangup		111
+-#define __NR_idle		112
+-#define __NR_vm86old		113
+-#define __NR_wait4		114
+-#define __NR_swapoff		115
+-#define __NR_sysinfo		116
+-#define __NR_ipc		117
+-#define __NR_fsync		118
+-#define __NR_sigreturn		119
+-#define __NR_clone		120
+-#define __NR_setdomainname	121
+-#define __NR_uname		122
+-#define __NR_modify_ldt		123
+-#define __NR_adjtimex		124
+-#define __NR_mprotect		125
+-#define __NR_sigprocmask	126
+-#define __NR_create_module	127
+-#define __NR_init_module	128
+-#define __NR_delete_module	129
+-#define __NR_get_kernel_syms	130
+-#define __NR_quotactl		131
+-#define __NR_getpgid		132
+-#define __NR_fchdir		133
+-#define __NR_bdflush		134
+-#define __NR_sysfs		135
+-#define __NR_personality	136
+-#define __NR_afs_syscall	137 /* Syscall for Andrew File System */
+-#define __NR_setfsuid		138
+-#define __NR_setfsgid		139
+-#define __NR__llseek		140
+-#define __NR_getdents		141
+-#define __NR__newselect		142
+-#define __NR_flock		143
+-#define __NR_msync		144
+-#define __NR_readv		145
+-#define __NR_writev		146
+-#define __NR_getsid		147
+-#define __NR_fdatasync		148
+-#define __NR__sysctl		149
+-#define __NR_mlock		150
+-#define __NR_munlock		151
+-#define __NR_mlockall		152
+-#define __NR_munlockall		153
+-#define __NR_sched_setparam		154
+-#define __NR_sched_getparam		155
+-#define __NR_sched_setscheduler		156
+-#define __NR_sched_getscheduler		157
+-#define __NR_sched_yield		158
+-#define __NR_sched_get_priority_max	159
+-#define __NR_sched_get_priority_min	160
+-#define __NR_sched_rr_get_interval	161
+-#define __NR_nanosleep		162
+-#define __NR_mremap		163
+-#define __NR_setresuid		164
+-#define __NR_getresuid		165
+-#define __NR_vm86		166
+-#define __NR_query_module	167
+-#define __NR_poll		168
+-#define __NR_nfsservctl		169
+-#define __NR_setresgid		170
+-#define __NR_getresgid		171
+-#define __NR_prctl              172
+-#define __NR_rt_sigreturn	173
+-#define __NR_rt_sigaction	174
+-#define __NR_rt_sigprocmask	175
+-#define __NR_rt_sigpending	176
+-#define __NR_rt_sigtimedwait	177
+-#define __NR_rt_sigqueueinfo	178
+-#define __NR_rt_sigsuspend	179
+-#define __NR_pread64		180
+-#define __NR_pwrite64		181
+-#define __NR_chown		182
+-#define __NR_getcwd		183
+-#define __NR_capget		184
+-#define __NR_capset		185
+-#define __NR_sigaltstack	186
+-#define __NR_sendfile		187
+-#define __NR_streams1		188	/* some people actually want it */
+-#define __NR_streams2		189	/* some people actually want it */
+-#define __NR_vfork		190
+-#define __NR_ugetrlimit		191	/* SuS compliant getrlimit */
+-#define __NR_mmap2		192
+-#define __NR_truncate64		193
+-#define __NR_ftruncate64	194
+-#define __NR_stat64		195
+-#define __NR_lstat64		196
+-#define __NR_fstat64		197
+-#define __NR_lchown32		198
+-#define __NR_getuid32		199
+-#define __NR_getgid32		200
+-#define __NR_geteuid32		201
+-#define __NR_getegid32		202
+-#define __NR_setreuid32		203
+-#define __NR_setregid32		204
+-#define __NR_getgroups32	205
+-#define __NR_setgroups32	206
+-#define __NR_fchown32		207
+-#define __NR_setresuid32	208
+-#define __NR_getresuid32	209
+-#define __NR_setresgid32	210
+-#define __NR_getresgid32	211
+-#define __NR_chown32		212
+-#define __NR_setuid32		213
+-#define __NR_setgid32		214
+-#define __NR_setfsuid32		215
+-#define __NR_setfsgid32		216
+-#define __NR_pivot_root		217
+-#define __NR_mincore		218
+-#define __NR_madvise		219
+-#define __NR_getdents64		220
+-#define __NR_fcntl64		221
+-/* 223 is unused */
+-#define __NR_gettid		224
+-#define __NR_readahead		225
+-#define __NR_setxattr		226
+-#define __NR_lsetxattr		227
+-#define __NR_fsetxattr		228
+-#define __NR_getxattr		229
+-#define __NR_lgetxattr		230
+-#define __NR_fgetxattr		231
+-#define __NR_listxattr		232
+-#define __NR_llistxattr		233
+-#define __NR_flistxattr		234
+-#define __NR_removexattr	235
+-#define __NR_lremovexattr	236
+-#define __NR_fremovexattr	237
+-#define __NR_tkill		238
+-#define __NR_sendfile64		239
+-#define __NR_futex		240
+-#define __NR_sched_setaffinity	241
+-#define __NR_sched_getaffinity	242
+-#define __NR_set_thread_area	243
+-#define __NR_get_thread_area	244
+-#define __NR_io_setup		245
+-#define __NR_io_destroy		246
+-#define __NR_io_getevents	247
+-#define __NR_io_submit		248
+-#define __NR_io_cancel		249
+-#define __NR_fadvise64		250
+-
+-#define __NR_exit_group		252
+-#define __NR_lookup_dcookie	253
+-#define __NR_epoll_create	254
+-#define __NR_epoll_ctl		255
+-#define __NR_epoll_wait		256
+-#define __NR_remap_file_pages	257
+-#define __NR_set_tid_address	258
+-#define __NR_timer_create	259
+-#define __NR_timer_settime	(__NR_timer_create+1)
+-#define __NR_timer_gettime	(__NR_timer_create+2)
+-#define __NR_timer_getoverrun	(__NR_timer_create+3)
+-#define __NR_timer_delete	(__NR_timer_create+4)
+-#define __NR_clock_settime	(__NR_timer_create+5)
+-#define __NR_clock_gettime	(__NR_timer_create+6)
+-#define __NR_clock_getres	(__NR_timer_create+7)
+-#define __NR_clock_nanosleep	(__NR_timer_create+8)
+-#define __NR_statfs64		268
+-#define __NR_fstatfs64		269
+-#define __NR_tgkill		270
+-#define __NR_utimes		271
+-#define __NR_fadvise64_64	272
+-#define __NR_vserver		273
+-#define __NR_mbind              274
+-#define __NR_get_mempolicy      275
+-#define __NR_set_mempolicy      276
+-#define __NR_mq_open            277
+-#define __NR_mq_unlink          (__NR_mq_open+1)
+-#define __NR_mq_timedsend       (__NR_mq_open+2)
+-#define __NR_mq_timedreceive    (__NR_mq_open+3)
+-#define __NR_mq_notify          (__NR_mq_open+4)
+-#define __NR_mq_getsetattr      (__NR_mq_open+5)
+-#define __NR_kexec_load		283
+-#define __NR_waitid		284
+-#define __NR_add_key		285
+-#define __NR_request_key	286
+-#define __NR_keyctl		287
+-#define __NR_ioprio_set		288
+-#define __NR_ioprio_get		289
+-#define __NR_inotify_init	290
+-#define __NR_inotify_add_watch	291
+-#define __NR_inotify_rm_watch	292
+-/* 293 is unused */
+-#define __NR_migrate_pages	294
+-#define __NR_openat		295
+-#define __NR_mkdirat		296
+-#define __NR_mknodat		297
+-#define __NR_fchownat		298
+-#define __NR_futimesat		299
+-#define __NR_fstatat64		300
+-#define __NR_unlinkat		301
+-#define __NR_renameat		302
+-#define __NR_linkat		303
+-#define __NR_symlinkat		304
+-#define __NR_readlinkat		305
+-#define __NR_fchmodat		306
+-#define __NR_faccessat		307
+-#define __NR_pselect6		308
+-#define __NR_ppoll		309
+-#define __NR_unshare		310
+-#define __NR_set_robust_list	311
+-#define __NR_get_robust_list	312
+-#define __NR_splice		313
+-#define __NR_sync_file_range	314
+-#define __NR_tee		315
+-#define __NR_vmsplice		316
+-#define __NR_move_pages		317
+-#define __NR_getcpu		318
+-#define __NR_epoll_pwait	319
+-#define __NR_utimensat		320
+-#define __NR_signalfd		321
+-#define __NR_timerfd		322
+-#define __NR_eventfd		323
+-#define __NR_fallocate		324
+-
+-#define NR_syscalls 325
+-
+-#ifdef __KERNEL__
+-
+-#define __ARCH_WANT_IPC_PARSE_VERSION
+-#define __ARCH_WANT_OLD_READDIR
+-#define __ARCH_WANT_OLD_STAT
+-#define __ARCH_WANT_STAT64
+-#define __ARCH_WANT_SYS_ALARM
+-#define __ARCH_WANT_SYS_GETHOSTNAME
+-#define __ARCH_WANT_SYS_PAUSE
+-#define __ARCH_WANT_SYS_SGETMASK
+-#define __ARCH_WANT_SYS_SIGNAL
+-#define __ARCH_WANT_SYS_TIME
+-#define __ARCH_WANT_SYS_UTIME
+-#define __ARCH_WANT_SYS_WAITPID
+-#define __ARCH_WANT_SYS_SOCKETCALL
+-#define __ARCH_WANT_SYS_FADVISE64
+-#define __ARCH_WANT_SYS_GETPGRP
+-#define __ARCH_WANT_SYS_LLSEEK
+-#define __ARCH_WANT_SYS_NICE
+-#define __ARCH_WANT_SYS_OLD_GETRLIMIT
+-#define __ARCH_WANT_SYS_OLDUMOUNT
+-#define __ARCH_WANT_SYS_SIGPENDING
+-#define __ARCH_WANT_SYS_SIGPROCMASK
+-#define __ARCH_WANT_SYS_RT_SIGACTION
+-#define __ARCH_WANT_SYS_RT_SIGSUSPEND
+-
+-/*
+- * "Conditional" syscalls
+- *
+- * What we want is __attribute__((weak,alias("sys_ni_syscall"))),
+- * but it doesn't work on all toolchains, so we just do it by hand
+- */
+-#ifndef cond_syscall
+-#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall")
++#ifdef CONFIG_SUPERH32
++# include "unistd_32.h"
++#else
++# include "unistd_64.h"
+ #endif
+-
+-#endif /* __KERNEL__ */
+-#endif /* __ASM_SH_UNISTD_H */
+diff --git a/include/asm-sh/unistd_32.h b/include/asm-sh/unistd_32.h
+new file mode 100644
+index 0000000..b182b1c
+--- /dev/null
++++ b/include/asm-sh/unistd_32.h
+@@ -0,0 +1,376 @@
++#ifndef __ASM_SH_UNISTD_H
++#define __ASM_SH_UNISTD_H
++
++/*
++ * Copyright (C) 1999  Niibe Yutaka
++ */
++
++/*
++ * This file contains the system call numbers.
++ */
++
++#define __NR_restart_syscall	  0
++#define __NR_exit		  1
++#define __NR_fork		  2
++#define __NR_read		  3
++#define __NR_write		  4
++#define __NR_open		  5
++#define __NR_close		  6
++#define __NR_waitpid		  7
++#define __NR_creat		  8
++#define __NR_link		  9
++#define __NR_unlink		 10
++#define __NR_execve		 11
++#define __NR_chdir		 12
++#define __NR_time		 13
++#define __NR_mknod		 14
++#define __NR_chmod		 15
++#define __NR_lchown		 16
++#define __NR_break		 17
++#define __NR_oldstat		 18
++#define __NR_lseek		 19
++#define __NR_getpid		 20
++#define __NR_mount		 21
++#define __NR_umount		 22
++#define __NR_setuid		 23
++#define __NR_getuid		 24
++#define __NR_stime		 25
++#define __NR_ptrace		 26
++#define __NR_alarm		 27
++#define __NR_oldfstat		 28
++#define __NR_pause		 29
++#define __NR_utime		 30
++#define __NR_stty		 31
++#define __NR_gtty		 32
++#define __NR_access		 33
++#define __NR_nice		 34
++#define __NR_ftime		 35
++#define __NR_sync		 36
++#define __NR_kill		 37
++#define __NR_rename		 38
++#define __NR_mkdir		 39
++#define __NR_rmdir		 40
++#define __NR_dup		 41
++#define __NR_pipe		 42
++#define __NR_times		 43
++#define __NR_prof		 44
++#define __NR_brk		 45
++#define __NR_setgid		 46
++#define __NR_getgid		 47
++#define __NR_signal		 48
++#define __NR_geteuid		 49
++#define __NR_getegid		 50
++#define __NR_acct		 51
++#define __NR_umount2		 52
++#define __NR_lock		 53
++#define __NR_ioctl		 54
++#define __NR_fcntl		 55
++#define __NR_mpx		 56
++#define __NR_setpgid		 57
++#define __NR_ulimit		 58
++#define __NR_oldolduname	 59
++#define __NR_umask		 60
++#define __NR_chroot		 61
++#define __NR_ustat		 62
++#define __NR_dup2		 63
++#define __NR_getppid		 64
++#define __NR_getpgrp		 65
++#define __NR_setsid		 66
++#define __NR_sigaction		 67
++#define __NR_sgetmask		 68
++#define __NR_ssetmask		 69
++#define __NR_setreuid		 70
++#define __NR_setregid		 71
++#define __NR_sigsuspend		 72
++#define __NR_sigpending		 73
++#define __NR_sethostname	 74
++#define __NR_setrlimit		 75
++#define __NR_getrlimit		 76	/* Back compatible 2Gig limited rlimit */
++#define __NR_getrusage		 77
++#define __NR_gettimeofday	 78
++#define __NR_settimeofday	 79
++#define __NR_getgroups		 80
++#define __NR_setgroups		 81
++#define __NR_select		 82
++#define __NR_symlink		 83
++#define __NR_oldlstat		 84
++#define __NR_readlink		 85
++#define __NR_uselib		 86
++#define __NR_swapon		 87
++#define __NR_reboot		 88
++#define __NR_readdir		 89
++#define __NR_mmap		 90
++#define __NR_munmap		 91
++#define __NR_truncate		 92
++#define __NR_ftruncate		 93
++#define __NR_fchmod		 94
++#define __NR_fchown		 95
++#define __NR_getpriority	 96
++#define __NR_setpriority	 97
++#define __NR_profil		 98
++#define __NR_statfs		 99
++#define __NR_fstatfs		100
++#define __NR_ioperm		101
++#define __NR_socketcall		102
++#define __NR_syslog		103
++#define __NR_setitimer		104
++#define __NR_getitimer		105
++#define __NR_stat		106
++#define __NR_lstat		107
++#define __NR_fstat		108
++#define __NR_olduname		109
++#define __NR_iopl		110
++#define __NR_vhangup		111
++#define __NR_idle		112
++#define __NR_vm86old		113
++#define __NR_wait4		114
++#define __NR_swapoff		115
++#define __NR_sysinfo		116
++#define __NR_ipc		117
++#define __NR_fsync		118
++#define __NR_sigreturn		119
++#define __NR_clone		120
++#define __NR_setdomainname	121
++#define __NR_uname		122
++#define __NR_modify_ldt		123
++#define __NR_adjtimex		124
++#define __NR_mprotect		125
++#define __NR_sigprocmask	126
++#define __NR_create_module	127
++#define __NR_init_module	128
++#define __NR_delete_module	129
++#define __NR_get_kernel_syms	130
++#define __NR_quotactl		131
++#define __NR_getpgid		132
++#define __NR_fchdir		133
++#define __NR_bdflush		134
++#define __NR_sysfs		135
++#define __NR_personality	136
++#define __NR_afs_syscall	137 /* Syscall for Andrew File System */
++#define __NR_setfsuid		138
++#define __NR_setfsgid		139
++#define __NR__llseek		140
++#define __NR_getdents		141
++#define __NR__newselect		142
++#define __NR_flock		143
++#define __NR_msync		144
++#define __NR_readv		145
++#define __NR_writev		146
++#define __NR_getsid		147
++#define __NR_fdatasync		148
++#define __NR__sysctl		149
++#define __NR_mlock		150
++#define __NR_munlock		151
++#define __NR_mlockall		152
++#define __NR_munlockall		153
++#define __NR_sched_setparam		154
++#define __NR_sched_getparam		155
++#define __NR_sched_setscheduler		156
++#define __NR_sched_getscheduler		157
++#define __NR_sched_yield		158
++#define __NR_sched_get_priority_max	159
++#define __NR_sched_get_priority_min	160
++#define __NR_sched_rr_get_interval	161
++#define __NR_nanosleep		162
++#define __NR_mremap		163
++#define __NR_setresuid		164
++#define __NR_getresuid		165
++#define __NR_vm86		166
++#define __NR_query_module	167
++#define __NR_poll		168
++#define __NR_nfsservctl		169
++#define __NR_setresgid		170
++#define __NR_getresgid		171
++#define __NR_prctl              172
++#define __NR_rt_sigreturn	173
++#define __NR_rt_sigaction	174
++#define __NR_rt_sigprocmask	175
++#define __NR_rt_sigpending	176
++#define __NR_rt_sigtimedwait	177
++#define __NR_rt_sigqueueinfo	178
++#define __NR_rt_sigsuspend	179
++#define __NR_pread64		180
++#define __NR_pwrite64		181
++#define __NR_chown		182
++#define __NR_getcwd		183
++#define __NR_capget		184
++#define __NR_capset		185
++#define __NR_sigaltstack	186
++#define __NR_sendfile		187
++#define __NR_streams1		188	/* some people actually want it */
++#define __NR_streams2		189	/* some people actually want it */
++#define __NR_vfork		190
++#define __NR_ugetrlimit		191	/* SuS compliant getrlimit */
++#define __NR_mmap2		192
++#define __NR_truncate64		193
++#define __NR_ftruncate64	194
++#define __NR_stat64		195
++#define __NR_lstat64		196
++#define __NR_fstat64		197
++#define __NR_lchown32		198
++#define __NR_getuid32		199
++#define __NR_getgid32		200
++#define __NR_geteuid32		201
++#define __NR_getegid32		202
++#define __NR_setreuid32		203
++#define __NR_setregid32		204
++#define __NR_getgroups32	205
++#define __NR_setgroups32	206
++#define __NR_fchown32		207
++#define __NR_setresuid32	208
++#define __NR_getresuid32	209
++#define __NR_setresgid32	210
++#define __NR_getresgid32	211
++#define __NR_chown32		212
++#define __NR_setuid32		213
++#define __NR_setgid32		214
++#define __NR_setfsuid32		215
++#define __NR_setfsgid32		216
++#define __NR_pivot_root		217
++#define __NR_mincore		218
++#define __NR_madvise		219
++#define __NR_getdents64		220
++#define __NR_fcntl64		221
++/* 223 is unused */
++#define __NR_gettid		224
++#define __NR_readahead		225
++#define __NR_setxattr		226
++#define __NR_lsetxattr		227
++#define __NR_fsetxattr		228
++#define __NR_getxattr		229
++#define __NR_lgetxattr		230
++#define __NR_fgetxattr		231
++#define __NR_listxattr		232
++#define __NR_llistxattr		233
++#define __NR_flistxattr		234
++#define __NR_removexattr	235
++#define __NR_lremovexattr	236
++#define __NR_fremovexattr	237
++#define __NR_tkill		238
++#define __NR_sendfile64		239
++#define __NR_futex		240
++#define __NR_sched_setaffinity	241
++#define __NR_sched_getaffinity	242
++#define __NR_set_thread_area	243
++#define __NR_get_thread_area	244
++#define __NR_io_setup		245
++#define __NR_io_destroy		246
++#define __NR_io_getevents	247
++#define __NR_io_submit		248
++#define __NR_io_cancel		249
++#define __NR_fadvise64		250
++
++#define __NR_exit_group		252
++#define __NR_lookup_dcookie	253
++#define __NR_epoll_create	254
++#define __NR_epoll_ctl		255
++#define __NR_epoll_wait		256
++#define __NR_remap_file_pages	257
++#define __NR_set_tid_address	258
++#define __NR_timer_create	259
++#define __NR_timer_settime	(__NR_timer_create+1)
++#define __NR_timer_gettime	(__NR_timer_create+2)
++#define __NR_timer_getoverrun	(__NR_timer_create+3)
++#define __NR_timer_delete	(__NR_timer_create+4)
++#define __NR_clock_settime	(__NR_timer_create+5)
++#define __NR_clock_gettime	(__NR_timer_create+6)
++#define __NR_clock_getres	(__NR_timer_create+7)
++#define __NR_clock_nanosleep	(__NR_timer_create+8)
++#define __NR_statfs64		268
++#define __NR_fstatfs64		269
++#define __NR_tgkill		270
++#define __NR_utimes		271
++#define __NR_fadvise64_64	272
++#define __NR_vserver		273
++#define __NR_mbind              274
++#define __NR_get_mempolicy      275
++#define __NR_set_mempolicy      276
++#define __NR_mq_open            277
++#define __NR_mq_unlink          (__NR_mq_open+1)
++#define __NR_mq_timedsend       (__NR_mq_open+2)
++#define __NR_mq_timedreceive    (__NR_mq_open+3)
++#define __NR_mq_notify          (__NR_mq_open+4)
++#define __NR_mq_getsetattr      (__NR_mq_open+5)
++#define __NR_kexec_load		283
++#define __NR_waitid		284
++#define __NR_add_key		285
++#define __NR_request_key	286
++#define __NR_keyctl		287
++#define __NR_ioprio_set		288
++#define __NR_ioprio_get		289
++#define __NR_inotify_init	290
++#define __NR_inotify_add_watch	291
++#define __NR_inotify_rm_watch	292
++/* 293 is unused */
++#define __NR_migrate_pages	294
++#define __NR_openat		295
++#define __NR_mkdirat		296
++#define __NR_mknodat		297
++#define __NR_fchownat		298
++#define __NR_futimesat		299
++#define __NR_fstatat64		300
++#define __NR_unlinkat		301
++#define __NR_renameat		302
++#define __NR_linkat		303
++#define __NR_symlinkat		304
++#define __NR_readlinkat		305
++#define __NR_fchmodat		306
++#define __NR_faccessat		307
++#define __NR_pselect6		308
++#define __NR_ppoll		309
++#define __NR_unshare		310
++#define __NR_set_robust_list	311
++#define __NR_get_robust_list	312
++#define __NR_splice		313
++#define __NR_sync_file_range	314
++#define __NR_tee		315
++#define __NR_vmsplice		316
++#define __NR_move_pages		317
++#define __NR_getcpu		318
++#define __NR_epoll_pwait	319
++#define __NR_utimensat		320
++#define __NR_signalfd		321
++#define __NR_timerfd		322
++#define __NR_eventfd		323
++#define __NR_fallocate		324
 +
-+	cr->c_blkno = le64_to_cpu(input->group);
-+	le32_add_cpu(&cr->c_total, input->clusters * cl_bpc);
-+	le32_add_cpu(&cr->c_free, input->frees * cl_bpc);
++#define NR_syscalls 325
 +
-+	le32_add_cpu(&fe->id1.bitmap1.i_total, input->clusters *cl_bpc);
-+	le32_add_cpu(&fe->id1.bitmap1.i_used,
-+		     (input->clusters - input->frees) * cl_bpc);
-+	le32_add_cpu(&fe->i_clusters, input->clusters);
++#ifdef __KERNEL__
 +
-+	ocfs2_journal_dirty(handle, main_bm_bh);
++#define __ARCH_WANT_IPC_PARSE_VERSION
++#define __ARCH_WANT_OLD_READDIR
++#define __ARCH_WANT_OLD_STAT
++#define __ARCH_WANT_STAT64
++#define __ARCH_WANT_SYS_ALARM
++#define __ARCH_WANT_SYS_GETHOSTNAME
++#define __ARCH_WANT_SYS_PAUSE
++#define __ARCH_WANT_SYS_SGETMASK
++#define __ARCH_WANT_SYS_SIGNAL
++#define __ARCH_WANT_SYS_TIME
++#define __ARCH_WANT_SYS_UTIME
++#define __ARCH_WANT_SYS_WAITPID
++#define __ARCH_WANT_SYS_SOCKETCALL
++#define __ARCH_WANT_SYS_FADVISE64
++#define __ARCH_WANT_SYS_GETPGRP
++#define __ARCH_WANT_SYS_LLSEEK
++#define __ARCH_WANT_SYS_NICE
++#define __ARCH_WANT_SYS_OLD_GETRLIMIT
++#define __ARCH_WANT_SYS_OLDUMOUNT
++#define __ARCH_WANT_SYS_SIGPENDING
++#define __ARCH_WANT_SYS_SIGPROCMASK
++#define __ARCH_WANT_SYS_RT_SIGACTION
++#define __ARCH_WANT_SYS_RT_SIGSUSPEND
 +
-+	spin_lock(&OCFS2_I(main_bm_inode)->ip_lock);
-+	OCFS2_I(main_bm_inode)->ip_clusters = le32_to_cpu(fe->i_clusters);
-+	le64_add_cpu(&fe->i_size, input->clusters << osb->s_clustersize_bits);
-+	spin_unlock(&OCFS2_I(main_bm_inode)->ip_lock);
-+	i_size_write(main_bm_inode, le64_to_cpu(fe->i_size));
++/*
++ * "Conditional" syscalls
++ *
++ * What we want is __attribute__((weak,alias("sys_ni_syscall"))),
++ * but it doesn't work on all toolchains, so we just do it by hand
++ */
++#ifndef cond_syscall
++#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall")
++#endif
 +
-+	ocfs2_update_super_and_backups(main_bm_inode, input->clusters);
++#endif /* __KERNEL__ */
++#endif /* __ASM_SH_UNISTD_H */
+diff --git a/include/asm-sh/unistd_64.h b/include/asm-sh/unistd_64.h
+new file mode 100644
+index 0000000..9445118
+--- /dev/null
++++ b/include/asm-sh/unistd_64.h
+@@ -0,0 +1,415 @@
++#ifndef __ASM_SH_UNISTD_64_H
++#define __ASM_SH_UNISTD_64_H
++
++/*
++ * include/asm-sh/unistd_64.h
++ *
++ * This file contains the system call numbers.
++ *
++ * Copyright (C) 2000, 2001  Paolo Alberelli
++ * Copyright (C) 2003 - 2007 Paul Mundt
++ * Copyright (C) 2004  Sean McGoogan
++ *
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License.  See the file "COPYING" in the main directory of this archive
++ * for more details.
++ */
++#define __NR_restart_syscall	  0
++#define __NR_exit		  1
++#define __NR_fork		  2
++#define __NR_read		  3
++#define __NR_write		  4
++#define __NR_open		  5
++#define __NR_close		  6
++#define __NR_waitpid		  7
++#define __NR_creat		  8
++#define __NR_link		  9
++#define __NR_unlink		 10
++#define __NR_execve		 11
++#define __NR_chdir		 12
++#define __NR_time		 13
++#define __NR_mknod		 14
++#define __NR_chmod		 15
++#define __NR_lchown		 16
++#define __NR_break		 17
++#define __NR_oldstat		 18
++#define __NR_lseek		 19
++#define __NR_getpid		 20
++#define __NR_mount		 21
++#define __NR_umount		 22
++#define __NR_setuid		 23
++#define __NR_getuid		 24
++#define __NR_stime		 25
++#define __NR_ptrace		 26
++#define __NR_alarm		 27
++#define __NR_oldfstat		 28
++#define __NR_pause		 29
++#define __NR_utime		 30
++#define __NR_stty		 31
++#define __NR_gtty		 32
++#define __NR_access		 33
++#define __NR_nice		 34
++#define __NR_ftime		 35
++#define __NR_sync		 36
++#define __NR_kill		 37
++#define __NR_rename		 38
++#define __NR_mkdir		 39
++#define __NR_rmdir		 40
++#define __NR_dup		 41
++#define __NR_pipe		 42
++#define __NR_times		 43
++#define __NR_prof		 44
++#define __NR_brk		 45
++#define __NR_setgid		 46
++#define __NR_getgid		 47
++#define __NR_signal		 48
++#define __NR_geteuid		 49
++#define __NR_getegid		 50
++#define __NR_acct		 51
++#define __NR_umount2		 52
++#define __NR_lock		 53
++#define __NR_ioctl		 54
++#define __NR_fcntl		 55
++#define __NR_mpx		 56
++#define __NR_setpgid		 57
++#define __NR_ulimit		 58
++#define __NR_oldolduname	 59
++#define __NR_umask		 60
++#define __NR_chroot		 61
++#define __NR_ustat		 62
++#define __NR_dup2		 63
++#define __NR_getppid		 64
++#define __NR_getpgrp		 65
++#define __NR_setsid		 66
++#define __NR_sigaction		 67
++#define __NR_sgetmask		 68
++#define __NR_ssetmask		 69
++#define __NR_setreuid		 70
++#define __NR_setregid		 71
++#define __NR_sigsuspend		 72
++#define __NR_sigpending		 73
++#define __NR_sethostname	 74
++#define __NR_setrlimit		 75
++#define __NR_getrlimit	 	 76	/* Back compatible 2Gig limited rlimit */
++#define __NR_getrusage		 77
++#define __NR_gettimeofday	 78
++#define __NR_settimeofday	 79
++#define __NR_getgroups		 80
++#define __NR_setgroups		 81
++#define __NR_select		 82
++#define __NR_symlink		 83
++#define __NR_oldlstat		 84
++#define __NR_readlink		 85
++#define __NR_uselib		 86
++#define __NR_swapon		 87
++#define __NR_reboot		 88
++#define __NR_readdir		 89
++#define __NR_mmap		 90
++#define __NR_munmap		 91
++#define __NR_truncate		 92
++#define __NR_ftruncate		 93
++#define __NR_fchmod		 94
++#define __NR_fchown		 95
++#define __NR_getpriority	 96
++#define __NR_setpriority	 97
++#define __NR_profil		 98
++#define __NR_statfs		 99
++#define __NR_fstatfs		100
++#define __NR_ioperm		101
++#define __NR_socketcall		102	/* old implementation of socket systemcall */
++#define __NR_syslog		103
++#define __NR_setitimer		104
++#define __NR_getitimer		105
++#define __NR_stat		106
++#define __NR_lstat		107
++#define __NR_fstat		108
++#define __NR_olduname		109
++#define __NR_iopl		110
++#define __NR_vhangup		111
++#define __NR_idle		112
++#define __NR_vm86old		113
++#define __NR_wait4		114
++#define __NR_swapoff		115
++#define __NR_sysinfo		116
++#define __NR_ipc		117
++#define __NR_fsync		118
++#define __NR_sigreturn		119
++#define __NR_clone		120
++#define __NR_setdomainname	121
++#define __NR_uname		122
++#define __NR_modify_ldt		123
++#define __NR_adjtimex		124
++#define __NR_mprotect		125
++#define __NR_sigprocmask	126
++#define __NR_create_module	127
++#define __NR_init_module	128
++#define __NR_delete_module	129
++#define __NR_get_kernel_syms	130
++#define __NR_quotactl		131
++#define __NR_getpgid		132
++#define __NR_fchdir		133
++#define __NR_bdflush		134
++#define __NR_sysfs		135
++#define __NR_personality	136
++#define __NR_afs_syscall	137 /* Syscall for Andrew File System */
++#define __NR_setfsuid		138
++#define __NR_setfsgid		139
++#define __NR__llseek		140
++#define __NR_getdents		141
++#define __NR__newselect		142
++#define __NR_flock		143
++#define __NR_msync		144
++#define __NR_readv		145
++#define __NR_writev		146
++#define __NR_getsid		147
++#define __NR_fdatasync		148
++#define __NR__sysctl		149
++#define __NR_mlock		150
++#define __NR_munlock		151
++#define __NR_mlockall		152
++#define __NR_munlockall		153
++#define __NR_sched_setparam		154
++#define __NR_sched_getparam		155
++#define __NR_sched_setscheduler		156
++#define __NR_sched_getscheduler		157
++#define __NR_sched_yield		158
++#define __NR_sched_get_priority_max	159
++#define __NR_sched_get_priority_min	160
++#define __NR_sched_rr_get_interval	161
++#define __NR_nanosleep		162
++#define __NR_mremap		163
++#define __NR_setresuid		164
++#define __NR_getresuid		165
++#define __NR_vm86		166
++#define __NR_query_module	167
++#define __NR_poll		168
++#define __NR_nfsservctl		169
++#define __NR_setresgid		170
++#define __NR_getresgid		171
++#define __NR_prctl              172
++#define __NR_rt_sigreturn	173
++#define __NR_rt_sigaction	174
++#define __NR_rt_sigprocmask	175
++#define __NR_rt_sigpending	176
++#define __NR_rt_sigtimedwait	177
++#define __NR_rt_sigqueueinfo	178
++#define __NR_rt_sigsuspend	179
++#define __NR_pread64		180
++#define __NR_pwrite64		181
++#define __NR_chown		182
++#define __NR_getcwd		183
++#define __NR_capget		184
++#define __NR_capset		185
++#define __NR_sigaltstack	186
++#define __NR_sendfile		187
++#define __NR_streams1		188	/* some people actually want it */
++#define __NR_streams2		189	/* some people actually want it */
++#define __NR_vfork		190
++#define __NR_ugetrlimit		191	/* SuS compliant getrlimit */
++#define __NR_mmap2		192
++#define __NR_truncate64		193
++#define __NR_ftruncate64	194
++#define __NR_stat64		195
++#define __NR_lstat64		196
++#define __NR_fstat64		197
++#define __NR_lchown32		198
++#define __NR_getuid32		199
++#define __NR_getgid32		200
++#define __NR_geteuid32		201
++#define __NR_getegid32		202
++#define __NR_setreuid32		203
++#define __NR_setregid32		204
++#define __NR_getgroups32	205
++#define __NR_setgroups32	206
++#define __NR_fchown32		207
++#define __NR_setresuid32	208
++#define __NR_getresuid32	209
++#define __NR_setresgid32	210
++#define __NR_getresgid32	211
++#define __NR_chown32		212
++#define __NR_setuid32		213
++#define __NR_setgid32		214
++#define __NR_setfsuid32		215
++#define __NR_setfsgid32		216
++#define __NR_pivot_root		217
++#define __NR_mincore		218
++#define __NR_madvise		219
++
++/* Non-multiplexed socket family */
++#define __NR_socket		220
++#define __NR_bind		221
++#define __NR_connect		222
++#define __NR_listen		223
++#define __NR_accept		224
++#define __NR_getsockname	225
++#define __NR_getpeername	226
++#define __NR_socketpair		227
++#define __NR_send		228
++#define __NR_sendto		229
++#define __NR_recv		230
++#define __NR_recvfrom		231
++#define __NR_shutdown		232
++#define __NR_setsockopt		233
++#define __NR_getsockopt		234
++#define __NR_sendmsg		235
++#define __NR_recvmsg		236
++
++/* Non-multiplexed IPC family */
++#define __NR_semop		237
++#define __NR_semget		238
++#define __NR_semctl		239
++#define __NR_msgsnd		240
++#define __NR_msgrcv		241
++#define __NR_msgget		242
++#define __NR_msgctl		243
++#if 0
++#define __NR_shmatcall		244
++#endif
++#define __NR_shmdt		245
++#define __NR_shmget		246
++#define __NR_shmctl		247
++
++#define __NR_getdents64		248
++#define __NR_fcntl64		249
++/* 223 is unused */
++#define __NR_gettid		252
++#define __NR_readahead		253
++#define __NR_setxattr		254
++#define __NR_lsetxattr		255
++#define __NR_fsetxattr		256
++#define __NR_getxattr		257
++#define __NR_lgetxattr		258
++#define __NR_fgetxattr		269
++#define __NR_listxattr		260
++#define __NR_llistxattr		261
++#define __NR_flistxattr		262
++#define __NR_removexattr	263
++#define __NR_lremovexattr	264
++#define __NR_fremovexattr	265
++#define __NR_tkill		266
++#define __NR_sendfile64		267
++#define __NR_futex		268
++#define __NR_sched_setaffinity	269
++#define __NR_sched_getaffinity	270
++#define __NR_set_thread_area	271
++#define __NR_get_thread_area	272
++#define __NR_io_setup		273
++#define __NR_io_destroy		274
++#define __NR_io_getevents	275
++#define __NR_io_submit		276
++#define __NR_io_cancel		277
++#define __NR_fadvise64		278
++#define __NR_exit_group		280
++
++#define __NR_lookup_dcookie	281
++#define __NR_epoll_create	282
++#define __NR_epoll_ctl		283
++#define __NR_epoll_wait		284
++#define __NR_remap_file_pages	285
++#define __NR_set_tid_address	286
++#define __NR_timer_create	287
++#define __NR_timer_settime	(__NR_timer_create+1)
++#define __NR_timer_gettime	(__NR_timer_create+2)
++#define __NR_timer_getoverrun	(__NR_timer_create+3)
++#define __NR_timer_delete	(__NR_timer_create+4)
++#define __NR_clock_settime	(__NR_timer_create+5)
++#define __NR_clock_gettime	(__NR_timer_create+6)
++#define __NR_clock_getres	(__NR_timer_create+7)
++#define __NR_clock_nanosleep	(__NR_timer_create+8)
++#define __NR_statfs64		296
++#define __NR_fstatfs64		297
++#define __NR_tgkill		298
++#define __NR_utimes		299
++#define __NR_fadvise64_64	300
++#define __NR_vserver		301
++#define __NR_mbind              302
++#define __NR_get_mempolicy      303
++#define __NR_set_mempolicy      304
++#define __NR_mq_open            305
++#define __NR_mq_unlink          (__NR_mq_open+1)
++#define __NR_mq_timedsend       (__NR_mq_open+2)
++#define __NR_mq_timedreceive    (__NR_mq_open+3)
++#define __NR_mq_notify          (__NR_mq_open+4)
++#define __NR_mq_getsetattr      (__NR_mq_open+5)
++#define __NR_kexec_load		311
++#define __NR_waitid		312
++#define __NR_add_key		313
++#define __NR_request_key	314
++#define __NR_keyctl		315
++#define __NR_ioprio_set		316
++#define __NR_ioprio_get		317
++#define __NR_inotify_init	318
++#define __NR_inotify_add_watch	319
++#define __NR_inotify_rm_watch	320
++/* 321 is unused */
++#define __NR_migrate_pages	322
++#define __NR_openat		323
++#define __NR_mkdirat		324
++#define __NR_mknodat		325
++#define __NR_fchownat		326
++#define __NR_futimesat		327
++#define __NR_fstatat64		328
++#define __NR_unlinkat		329
++#define __NR_renameat		330
++#define __NR_linkat		331
++#define __NR_symlinkat		332
++#define __NR_readlinkat		333
++#define __NR_fchmodat		334
++#define __NR_faccessat		335
++#define __NR_pselect6		336
++#define __NR_ppoll		337
++#define __NR_unshare		338
++#define __NR_set_robust_list	339
++#define __NR_get_robust_list	340
++#define __NR_splice		341
++#define __NR_sync_file_range	342
++#define __NR_tee		343
++#define __NR_vmsplice		344
++#define __NR_move_pages		345
++#define __NR_getcpu		346
++#define __NR_epoll_pwait	347
++#define __NR_utimensat		348
++#define __NR_signalfd		349
++#define __NR_timerfd		350
++#define __NR_eventfd		351
++#define __NR_fallocate		352
 +
-+out_commit:
-+	ocfs2_commit_trans(osb, handle);
-+out_unlock:
-+	brelse(group_bh);
-+	brelse(main_bm_bh);
++#ifdef __KERNEL__
 +
-+	ocfs2_inode_unlock(main_bm_inode, 1);
++#define NR_syscalls 353
 +
-+out_mutex:
-+	mutex_unlock(&main_bm_inode->i_mutex);
-+	iput(main_bm_inode);
++#define __ARCH_WANT_IPC_PARSE_VERSION
++#define __ARCH_WANT_OLD_READDIR
++#define __ARCH_WANT_OLD_STAT
++#define __ARCH_WANT_STAT64
++#define __ARCH_WANT_SYS_ALARM
++#define __ARCH_WANT_SYS_GETHOSTNAME
++#define __ARCH_WANT_SYS_PAUSE
++#define __ARCH_WANT_SYS_SGETMASK
++#define __ARCH_WANT_SYS_SIGNAL
++#define __ARCH_WANT_SYS_TIME
++#define __ARCH_WANT_SYS_UTIME
++#define __ARCH_WANT_SYS_WAITPID
++#define __ARCH_WANT_SYS_SOCKETCALL
++#define __ARCH_WANT_SYS_FADVISE64
++#define __ARCH_WANT_SYS_GETPGRP
++#define __ARCH_WANT_SYS_LLSEEK
++#define __ARCH_WANT_SYS_NICE
++#define __ARCH_WANT_SYS_OLD_GETRLIMIT
++#define __ARCH_WANT_SYS_OLDUMOUNT
++#define __ARCH_WANT_SYS_SIGPENDING
++#define __ARCH_WANT_SYS_SIGPROCMASK
++#define __ARCH_WANT_SYS_RT_SIGACTION
 +
-+out:
-+	mlog_exit_void();
-+	return ret;
-+}
-diff --git a/fs/ocfs2/resize.h b/fs/ocfs2/resize.h
-new file mode 100644
-index 0000000..f38841a
---- /dev/null
-+++ b/fs/ocfs2/resize.h
-@@ -0,0 +1,32 @@
-+/* -*- mode: c; c-basic-offset: 8; -*-
-+ * vim: noexpandtab sw=8 ts=8 sts=0:
-+ *
-+ * resize.h
-+ *
-+ * Function prototypes
-+ *
-+ * Copyright (C) 2007 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.
++/*
++ * "Conditional" syscalls
 + *
-+ * You 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.
++ * What we want is __attribute__((weak,alias("sys_ni_syscall"))),
++ * but it doesn't work on all toolchains, so we just do it by hand
 + */
++#ifndef cond_syscall
++#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall")
++#endif
 +
-+#ifndef OCFS2_RESIZE_H
-+#define OCFS2_RESIZE_H
-+
-+int ocfs2_group_extend(struct inode * inode, int new_clusters);
-+int ocfs2_group_add(struct inode *inode, struct ocfs2_new_group_input *input);
-+
-+#endif /* OCFS2_RESIZE_H */
-diff --git a/fs/ocfs2/slot_map.c b/fs/ocfs2/slot_map.c
-index af4882b..3a50ce5 100644
---- a/fs/ocfs2/slot_map.c
-+++ b/fs/ocfs2/slot_map.c
-@@ -48,25 +48,6 @@ static void __ocfs2_fill_slot(struct ocfs2_slot_info *si,
- 			      s16 slot_num,
- 			      s16 node_num);
++#endif /* __KERNEL__ */
++#endif /* __ASM_SH_UNISTD_64_H */
+diff --git a/include/asm-sh/user.h b/include/asm-sh/user.h
+index d1b8511..1a4f43c 100644
+--- a/include/asm-sh/user.h
++++ b/include/asm-sh/user.h
+@@ -27,12 +27,19 @@
+  *	to write an integer number of pages.
+  */
  
--/* Use the slot information we've collected to create a map of mounted
-- * nodes. Should be holding an EX on super block. assumes slot info is
-- * up to date. Note that we call this *after* we find a slot, so our
-- * own node should be set in the map too... */
--void ocfs2_populate_mounted_map(struct ocfs2_super *osb)
++#if defined(__SH5__) || defined(CONFIG_CPU_SH5)
++struct user_fpu_struct {
++	unsigned long fp_regs[32];
++	unsigned int fpscr;
++};
++#else
+ struct user_fpu_struct {
+ 	unsigned long fp_regs[16];
+ 	unsigned long xfp_regs[16];
+ 	unsigned long fpscr;
+ 	unsigned long fpul;
+ };
++#endif
+ 
+ struct user {
+ 	struct pt_regs	regs;			/* entire machine state */
+diff --git a/include/asm-sh/voyagergx.h b/include/asm-sh/voyagergx.h
+deleted file mode 100644
+index d825596..0000000
+--- a/include/asm-sh/voyagergx.h
++++ /dev/null
+@@ -1,341 +0,0 @@
+-/* -------------------------------------------------------------------- */
+-/* voyagergx.h	                                                      */
+-/* -------------------------------------------------------------------- */
+-/*  This program is free software; you can redistribute it and/or modify
+-    it under the terms of the GNU General Public License as published by
+-    the Free Software Foundation; either version 2 of the License, or
+-    (at your option) any later version.
+-
+-    This program is distributed in the hope that it will be useful,
+-    but WITHOUT ANY WARRANTY; without even the implied warranty of
+-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+-    GNU General Public License for more details.
+-
+-    You 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.
+-
+-    Copyright 2003 (c) Lineo uSolutions,Inc.
+-*/
+-/* -------------------------------------------------------------------- */
+-
+-#ifndef _VOYAGER_GX_REG_H
+-#define _VOYAGER_GX_REG_H
+-
+-#define VOYAGER_BASE			0xb3e00000
+-#define VOYAGER_USBH_BASE		(0x40000 + VOYAGER_BASE)
+-#define VOYAGER_UART_BASE		(0x30000 + VOYAGER_BASE)
+-#define	VOYAGER_AC97_BASE		(0xa0000 + VOYAGER_BASE)
+-
+-#define VOYAGER_IRQ_NUM			26
+-#define VOYAGER_IRQ_BASE		200
+-
+-#define IRQ_SM501_UP			(VOYAGER_IRQ_BASE + 0)
+-#define IRQ_SM501_G54			(VOYAGER_IRQ_BASE + 1)
+-#define IRQ_SM501_G53			(VOYAGER_IRQ_BASE + 2)
+-#define IRQ_SM501_G52			(VOYAGER_IRQ_BASE + 3)
+-#define IRQ_SM501_G51			(VOYAGER_IRQ_BASE + 4)
+-#define IRQ_SM501_G50			(VOYAGER_IRQ_BASE + 5)
+-#define IRQ_SM501_G49			(VOYAGER_IRQ_BASE + 6)
+-#define IRQ_SM501_G48			(VOYAGER_IRQ_BASE + 7)
+-#define IRQ_SM501_I2C			(VOYAGER_IRQ_BASE + 8)
+-#define IRQ_SM501_PW			(VOYAGER_IRQ_BASE + 9)
+-#define IRQ_SM501_DMA			(VOYAGER_IRQ_BASE + 10)
+-#define IRQ_SM501_PCI			(VOYAGER_IRQ_BASE + 11)
+-#define IRQ_SM501_I2S			(VOYAGER_IRQ_BASE + 12)
+-#define IRQ_SM501_AC			(VOYAGER_IRQ_BASE + 13)
+-#define IRQ_SM501_US			(VOYAGER_IRQ_BASE + 14)
+-#define IRQ_SM501_U1			(VOYAGER_IRQ_BASE + 15)
+-#define IRQ_SM501_U0			(VOYAGER_IRQ_BASE + 16)
+-#define IRQ_SM501_CV			(VOYAGER_IRQ_BASE + 17)
+-#define IRQ_SM501_MC			(VOYAGER_IRQ_BASE + 18)
+-#define IRQ_SM501_S1			(VOYAGER_IRQ_BASE + 19)
+-#define IRQ_SM501_S0			(VOYAGER_IRQ_BASE + 20)
+-#define IRQ_SM501_UH			(VOYAGER_IRQ_BASE + 21)
+-#define IRQ_SM501_2D			(VOYAGER_IRQ_BASE + 22)
+-#define IRQ_SM501_ZD			(VOYAGER_IRQ_BASE + 23)
+-#define IRQ_SM501_PV			(VOYAGER_IRQ_BASE + 24)
+-#define IRQ_SM501_CI			(VOYAGER_IRQ_BASE + 25)
+-
+-/* ----- MISC controle  register ------------------------------ */
+-#define MISC_CTRL			(0x000004 + VOYAGER_BASE)
+-#define MISC_CTRL_USBCLK_48		(3 << 28)
+-#define MISC_CTRL_USBCLK_96		(2 << 28)
+-#define MISC_CTRL_USBCLK_CRYSTAL	(1 << 28)
+-
+-/* ----- GPIO[31:0] register --------------------------------- */
+-#define GPIO_MUX_LOW			(0x000008 + VOYAGER_BASE)
+-#define GPIO_MUX_LOW_AC97		0x1F000000
+-#define GPIO_MUX_LOW_8051		0x0000ffff
+-#define GPIO_MUX_LOW_PWM		(1 << 29)
+-
+-/* ----- GPIO[63:32] register --------------------------------- */
+-#define GPIO_MUX_HIGH			(0x00000C + VOYAGER_BASE)
+-
+-/* ----- DRAM controle  register ------------------------------- */
+-#define DRAM_CTRL			(0x000010 + VOYAGER_BASE)
+-#define DRAM_CTRL_EMBEDDED		(1 << 31)
+-#define DRAM_CTRL_CPU_BURST_1		(0 << 28)
+-#define DRAM_CTRL_CPU_BURST_2		(1 << 28)
+-#define DRAM_CTRL_CPU_BURST_4		(2 << 28)
+-#define DRAM_CTRL_CPU_BURST_8		(3 << 28)
+-#define DRAM_CTRL_CPU_CAS_LATENCY	(1 << 27)
+-#define DRAM_CTRL_CPU_SIZE_2		(0 << 24)
+-#define DRAM_CTRL_CPU_SIZE_4		(1 << 24)
+-#define DRAM_CTRL_CPU_SIZE_64		(4 << 24)
+-#define DRAM_CTRL_CPU_SIZE_32		(5 << 24)
+-#define DRAM_CTRL_CPU_SIZE_16		(6 << 24)
+-#define DRAM_CTRL_CPU_SIZE_8		(7 << 24)
+-#define DRAM_CTRL_CPU_COLUMN_SIZE_1024	(0 << 22)
+-#define DRAM_CTRL_CPU_COLUMN_SIZE_512	(2 << 22)
+-#define DRAM_CTRL_CPU_COLUMN_SIZE_256	(3 << 22)
+-#define DRAM_CTRL_CPU_ACTIVE_PRECHARGE	(1 << 21)
+-#define DRAM_CTRL_CPU_RESET		(1 << 20)
+-#define DRAM_CTRL_CPU_BANKS		(1 << 19)
+-#define DRAM_CTRL_CPU_WRITE_PRECHARGE	(1 << 18)
+-#define DRAM_CTRL_BLOCK_WRITE		(1 << 17)
+-#define DRAM_CTRL_REFRESH_COMMAND	(1 << 16)
+-#define DRAM_CTRL_SIZE_4		(0 << 13)
+-#define DRAM_CTRL_SIZE_8		(1 << 13)
+-#define DRAM_CTRL_SIZE_16		(2 << 13)
+-#define DRAM_CTRL_SIZE_32		(3 << 13)
+-#define DRAM_CTRL_SIZE_64		(4 << 13)
+-#define DRAM_CTRL_SIZE_2		(5 << 13)
+-#define DRAM_CTRL_COLUMN_SIZE_256	(0 << 11)
+-#define DRAM_CTRL_COLUMN_SIZE_512	(2 << 11)
+-#define DRAM_CTRL_COLUMN_SIZE_1024	(3 << 11)
+-#define DRAM_CTRL_BLOCK_WRITE_TIME	(1 << 10)
+-#define DRAM_CTRL_BLOCK_WRITE_PRECHARGE	(1 << 9)
+-#define DRAM_CTRL_ACTIVE_PRECHARGE	(1 << 8)
+-#define DRAM_CTRL_RESET			(1 << 7)
+-#define DRAM_CTRL_REMAIN_ACTIVE		(1 << 6)
+-#define DRAM_CTRL_BANKS			(1 << 1)
+-#define DRAM_CTRL_WRITE_PRECHARGE	(1 << 0)
+-
+-/* ----- Arvitration control register -------------------------- */
+-#define ARBITRATION_CTRL		(0x000014 + VOYAGER_BASE)
+-#define ARBITRATION_CTRL_CPUMEM		(1 << 29)
+-#define ARBITRATION_CTRL_INTMEM		(1 << 28)
+-#define ARBITRATION_CTRL_USB_OFF	(0 << 24)
+-#define ARBITRATION_CTRL_USB_PRIORITY_1	(1 << 24)
+-#define ARBITRATION_CTRL_USB_PRIORITY_2	(2 << 24)
+-#define ARBITRATION_CTRL_USB_PRIORITY_3	(3 << 24)
+-#define ARBITRATION_CTRL_USB_PRIORITY_4	(4 << 24)
+-#define ARBITRATION_CTRL_USB_PRIORITY_5	(5 << 24)
+-#define ARBITRATION_CTRL_USB_PRIORITY_6	(6 << 24)
+-#define ARBITRATION_CTRL_USB_PRIORITY_7	(7 << 24)
+-#define ARBITRATION_CTRL_PANEL_OFF	(0 << 20)
+-#define ARBITRATION_CTRL_PANEL_PRIORITY_1	(1 << 20)
+-#define ARBITRATION_CTRL_PANEL_PRIORITY_2	(2 << 20)
+-#define ARBITRATION_CTRL_PANEL_PRIORITY_3	(3 << 20)
+-#define ARBITRATION_CTRL_PANEL_PRIORITY_4	(4 << 20)
+-#define ARBITRATION_CTRL_PANEL_PRIORITY_5	(5 << 20)
+-#define ARBITRATION_CTRL_PANEL_PRIORITY_6	(6 << 20)
+-#define ARBITRATION_CTRL_PANEL_PRIORITY_7	(7 << 20)
+-#define ARBITRATION_CTRL_ZVPORT_OFF	(0 << 16)
+-#define ARBITRATION_CTRL_ZVPORTL_PRIORITY_1	(1 << 16)
+-#define ARBITRATION_CTRL_ZVPORTL_PRIORITY_2	(2 << 16)
+-#define ARBITRATION_CTRL_ZVPORTL_PRIORITY_3	(3 << 16)
+-#define ARBITRATION_CTRL_ZVPORTL_PRIORITY_4	(4 << 16)
+-#define ARBITRATION_CTRL_ZVPORTL_PRIORITY_5	(5 << 16)
+-#define ARBITRATION_CTRL_ZVPORTL_PRIORITY_6	(6 << 16)
+-#define ARBITRATION_CTRL_ZVPORTL_PRIORITY_7	(7 << 16)
+-#define ARBITRATION_CTRL_CMD_INTPR_OFF	(0 << 12)
+-#define ARBITRATION_CTRL_CMD_INTPR_PRIORITY_1	(1 << 12)
+-#define ARBITRATION_CTRL_CMD_INTPR_PRIORITY_2	(2 << 12)
+-#define ARBITRATION_CTRL_CMD_INTPR_PRIORITY_3	(3 << 12)
+-#define ARBITRATION_CTRL_CMD_INTPR_PRIORITY_4	(4 << 12)
+-#define ARBITRATION_CTRL_CMD_INTPR_PRIORITY_5	(5 << 12)
+-#define ARBITRATION_CTRL_CMD_INTPR_PRIORITY_6	(6 << 12)
+-#define ARBITRATION_CTRL_CMD_INTPR_PRIORITY_7	(7 << 12)
+-#define ARBITRATION_CTRL_DMA_OFF	(0 << 8)
+-#define ARBITRATION_CTRL_DMA_PRIORITY_1	(1 << 8)
+-#define ARBITRATION_CTRL_DMA_PRIORITY_2	(2 << 8)
+-#define ARBITRATION_CTRL_DMA_PRIORITY_3	(3 << 8)
+-#define ARBITRATION_CTRL_DMA_PRIORITY_4	(4 << 8)
+-#define ARBITRATION_CTRL_DMA_PRIORITY_5	(5 << 8)
+-#define ARBITRATION_CTRL_DMA_PRIORITY_6	(6 << 8)
+-#define ARBITRATION_CTRL_DMA_PRIORITY_7	(7 << 8)
+-#define ARBITRATION_CTRL_VIDEO_OFF	(0 << 4)
+-#define ARBITRATION_CTRL_VIDEO_PRIORITY_1	(1 << 4)
+-#define ARBITRATION_CTRL_VIDEO_PRIORITY_2	(2 << 4)
+-#define ARBITRATION_CTRL_VIDEO_PRIORITY_3	(3 << 4)
+-#define ARBITRATION_CTRL_VIDEO_PRIORITY_4	(4 << 4)
+-#define ARBITRATION_CTRL_VIDEO_PRIORITY_5	(5 << 4)
+-#define ARBITRATION_CTRL_VIDEO_PRIORITY_6	(6 << 4)
+-#define ARBITRATION_CTRL_VIDEO_PRIORITY_7	(7 << 4)
+-#define ARBITRATION_CTRL_CRT_OFF	(0 << 0)
+-#define ARBITRATION_CTRL_CRT_PRIORITY_1	(1 << 0)
+-#define ARBITRATION_CTRL_CRT_PRIORITY_2	(2 << 0)
+-#define ARBITRATION_CTRL_CRT_PRIORITY_3	(3 << 0)
+-#define ARBITRATION_CTRL_CRT_PRIORITY_4	(4 << 0)
+-#define ARBITRATION_CTRL_CRT_PRIORITY_5	(5 << 0)
+-#define ARBITRATION_CTRL_CRT_PRIORITY_6	(6 << 0)
+-#define ARBITRATION_CTRL_CRT_PRIORITY_7	(7 << 0)
+-
+-/* ----- Command list status register -------------------------- */
+-#define CMD_INTPR_STATUS		(0x000024 + VOYAGER_BASE)
+-
+-/* ----- Interrupt status register ----------------------------- */
+-#define INT_STATUS			(0x00002c + VOYAGER_BASE)
+-#define INT_STATUS_UH			(1 << 6)
+-#define INT_STATUS_MC			(1 << 10)
+-#define INT_STATUS_U0			(1 << 12)
+-#define INT_STATUS_U1			(1 << 13)
+-#define	INT_STATUS_AC			(1 << 17)
+-
+-/* ----- Interrupt mask register ------------------------------ */
+-#define VOYAGER_INT_MASK		(0x000030 + VOYAGER_BASE)
+-#define VOYAGER_INT_MASK_AC		(1 << 17)
+-
+-/* ----- Current Gate register ---------------------------------*/
+-#define CURRENT_GATE			(0x000038 + VOYAGER_BASE)
+-
+-/* ----- Power mode 0 gate register --------------------------- */
+-#define POWER_MODE0_GATE		(0x000040 + VOYAGER_BASE)
+-#define POWER_MODE0_GATE_G		(1 << 6)
+-#define POWER_MODE0_GATE_U0		(1 << 7)
+-#define POWER_MODE0_GATE_U1		(1 << 8)
+-#define POWER_MODE0_GATE_UH		(1 << 11)
+-#define	POWER_MODE0_GATE_AC		(1 << 18)
+-
+-/* ----- Power mode 1 gate register --------------------------- */
+-#define POWER_MODE1_GATE		(0x000048 + VOYAGER_BASE)
+-#define POWER_MODE1_GATE_G		(1 << 6)
+-#define POWER_MODE1_GATE_U0		(1 << 7)
+-#define POWER_MODE1_GATE_U1		(1 << 8)
+-#define POWER_MODE1_GATE_UH		(1 << 11)
+-#define	POWER_MODE1_GATE_AC		(1 << 18)
+-
+-/* ----- Power mode 0 clock register -------------------------- */
+-#define POWER_MODE0_CLOCK		(0x000044 + VOYAGER_BASE)
+-
+-/* ----- Power mode 1 clock register -------------------------- */
+-#define POWER_MODE1_CLOCK		(0x00004C + VOYAGER_BASE)
+-
+-/* ----- Power mode controll register ------------------------- */
+-#define POWER_MODE_CTRL			(0x000054 + VOYAGER_BASE)
+-
+-/* ----- Miscellaneous Timing register ------------------------ */
+-#define SYSTEM_DRAM_CTRL		(0x000068 + VOYAGER_BASE)
+-
+-/* ----- PWM register ------------------------------------------*/
+-#define PWM_0				(0x010020 + VOYAGER_BASE)
+-#define PWM_0_HC(x)			(((x)&0x0fff)<<20)
+-#define PWM_0_LC(x)			(((x)&0x0fff)<<8 )
+-#define PWM_0_CLK_DEV(x)		(((x)&0x000f)<<4 )
+-#define PWM_0_EN			(1<<0)
+-
+-/* ----- I2C register ----------------------------------------- */
+-#define I2C_BYTECOUNT			(0x010040 + VOYAGER_BASE)
+-#define I2C_CONTROL			(0x010041 + VOYAGER_BASE)
+-#define I2C_STATUS			(0x010042 + VOYAGER_BASE)
+-#define I2C_RESET			(0x010042 + VOYAGER_BASE)
+-#define I2C_SADDRESS			(0x010043 + VOYAGER_BASE)
+-#define I2C_DATA			(0x010044 + VOYAGER_BASE)
+-
+-/* ----- Controle register bits ----------------------------------------- */
+-#define I2C_CONTROL_E			(1 << 0)
+-#define I2C_CONTROL_MODE		(1 << 1)
+-#define I2C_CONTROL_STATUS		(1 << 2)
+-#define I2C_CONTROL_INT			(1 << 4)
+-#define I2C_CONTROL_INTACK		(1 << 5)
+-#define I2C_CONTROL_REPEAT		(1 << 6)
+-
+-/* ----- Status register bits ----------------------------------------- */
+-#define I2C_STATUS_BUSY			(1 << 0)
+-#define I2C_STATUS_ACK			(1 << 1)
+-#define I2C_STATUS_ERROR		(1 << 2)
+-#define I2C_STATUS_COMPLETE		(1 << 3)
+-
+-/* ----- Reset register  ---------------------------------------------- */
+-#define I2C_RESET_ERROR			(1 << 2)
+-
+-/* ----- transmission frequencies ------------------------------------- */
+-#define I2C_SADDRESS_SELECT		(1 << 0)
+-
+-/* ----- Display Controll register ----------------------------------------- */
+-#define PANEL_DISPLAY_CTRL		(0x080000 + VOYAGER_BASE)
+-#define PANEL_DISPLAY_CTRL_BIAS         (1<<26)
+-#define PANEL_PAN_CTRL			(0x080004 + VOYAGER_BASE)
+-#define PANEL_COLOR_KEY			(0x080008 + VOYAGER_BASE)
+-#define PANEL_FB_ADDRESS		(0x08000C + VOYAGER_BASE)
+-#define PANEL_FB_WIDTH			(0x080010 + VOYAGER_BASE)
+-#define PANEL_WINDOW_WIDTH		(0x080014 + VOYAGER_BASE)
+-#define PANEL_WINDOW_HEIGHT		(0x080018 + VOYAGER_BASE)
+-#define PANEL_PLANE_TL			(0x08001C + VOYAGER_BASE)
+-#define PANEL_PLANE_BR			(0x080020 + VOYAGER_BASE)
+-#define PANEL_HORIZONTAL_TOTAL		(0x080024 + VOYAGER_BASE)
+-#define PANEL_HORIZONTAL_SYNC		(0x080028 + VOYAGER_BASE)
+-#define PANEL_VERTICAL_TOTAL		(0x08002C + VOYAGER_BASE)
+-#define PANEL_VERTICAL_SYNC		(0x080030 + VOYAGER_BASE)
+-#define PANEL_CURRENT_LINE		(0x080034 + VOYAGER_BASE)
+-#define VIDEO_DISPLAY_CTRL		(0x080040 + VOYAGER_BASE)
+-#define VIDEO_FB_0_ADDRESS		(0x080044 + VOYAGER_BASE)
+-#define VIDEO_FB_WIDTH			(0x080048 + VOYAGER_BASE)
+-#define VIDEO_FB_0_LAST_ADDRESS		(0x08004C + VOYAGER_BASE)
+-#define VIDEO_PLANE_TL			(0x080050 + VOYAGER_BASE)
+-#define VIDEO_PLANE_BR			(0x080054 + VOYAGER_BASE)
+-#define VIDEO_SCALE			(0x080058 + VOYAGER_BASE)
+-#define VIDEO_INITIAL_SCALE		(0x08005C + VOYAGER_BASE)
+-#define VIDEO_YUV_CONSTANTS		(0x080060 + VOYAGER_BASE)
+-#define VIDEO_FB_1_ADDRESS		(0x080064 + VOYAGER_BASE)
+-#define VIDEO_FB_1_LAST_ADDRESS		(0x080068 + VOYAGER_BASE)
+-#define VIDEO_ALPHA_DISPLAY_CTRL	(0x080080 + VOYAGER_BASE)
+-#define VIDEO_ALPHA_FB_ADDRESS		(0x080084 + VOYAGER_BASE)
+-#define VIDEO_ALPHA_FB_WIDTH		(0x080088 + VOYAGER_BASE)
+-#define VIDEO_ALPHA_FB_LAST_ADDRESS	(0x08008C + VOYAGER_BASE)
+-#define VIDEO_ALPHA_PLANE_TL		(0x080090 + VOYAGER_BASE)
+-#define VIDEO_ALPHA_PLANE_BR		(0x080094 + VOYAGER_BASE)
+-#define VIDEO_ALPHA_SCALE		(0x080098 + VOYAGER_BASE)
+-#define VIDEO_ALPHA_INITIAL_SCALE	(0x08009C + VOYAGER_BASE)
+-#define VIDEO_ALPHA_CHROMA_KEY		(0x0800A0 + VOYAGER_BASE)
+-#define PANEL_HWC_ADDRESS		(0x0800F0 + VOYAGER_BASE)
+-#define PANEL_HWC_LOCATION		(0x0800F4 + VOYAGER_BASE)
+-#define PANEL_HWC_COLOR_12		(0x0800F8 + VOYAGER_BASE)
+-#define PANEL_HWC_COLOR_3		(0x0800FC + VOYAGER_BASE)
+-#define ALPHA_DISPLAY_CTRL		(0x080100 + VOYAGER_BASE)
+-#define ALPHA_FB_ADDRESS		(0x080104 + VOYAGER_BASE)
+-#define ALPHA_FB_WIDTH			(0x080108 + VOYAGER_BASE)
+-#define ALPHA_PLANE_TL			(0x08010C + VOYAGER_BASE)
+-#define ALPHA_PLANE_BR			(0x080110 + VOYAGER_BASE)
+-#define ALPHA_CHROMA_KEY		(0x080114 + VOYAGER_BASE)
+-#define CRT_DISPLAY_CTRL		(0x080200 + VOYAGER_BASE)
+-#define CRT_FB_ADDRESS			(0x080204 + VOYAGER_BASE)
+-#define CRT_FB_WIDTH			(0x080208 + VOYAGER_BASE)
+-#define CRT_HORIZONTAL_TOTAL		(0x08020C + VOYAGER_BASE)
+-#define CRT_HORIZONTAL_SYNC		(0x080210 + VOYAGER_BASE)
+-#define CRT_VERTICAL_TOTAL		(0x080214 + VOYAGER_BASE)
+-#define CRT_VERTICAL_SYNC		(0x080218 + VOYAGER_BASE)
+-#define CRT_SIGNATURE_ANALYZER		(0x08021C + VOYAGER_BASE)
+-#define CRT_CURRENT_LINE		(0x080220 + VOYAGER_BASE)
+-#define CRT_MONITOR_DETECT		(0x080224 + VOYAGER_BASE)
+-#define CRT_HWC_ADDRESS			(0x080230 + VOYAGER_BASE)
+-#define CRT_HWC_LOCATION		(0x080234 + VOYAGER_BASE)
+-#define CRT_HWC_COLOR_12		(0x080238 + VOYAGER_BASE)
+-#define CRT_HWC_COLOR_3			(0x08023C + VOYAGER_BASE)
+-#define CRT_PALETTE_RAM			(0x080400 + VOYAGER_BASE)
+-#define PANEL_PALETTE_RAM		(0x080800 + VOYAGER_BASE)
+-#define VIDEO_PALETTE_RAM		(0x080C00 + VOYAGER_BASE)
+-
+-/* ----- 8051 Controle register ----------------------------------------- */
+-#define VOYAGER_8051_BASE		(0x000c0000 + VOYAGER_BASE)
+-#define VOYAGER_8051_RESET		(0x000b0000 + VOYAGER_BASE)
+-#define VOYAGER_8051_SELECT		(0x000b0004 + VOYAGER_BASE)
+-#define VOYAGER_8051_CPU_INT		(0x000b000c + VOYAGER_BASE)
+-
+-/* ----- AC97 Controle register ----------------------------------------- */
+-#define AC97_TX_SLOT0			(0x00000000 + VOYAGER_AC97_BASE)
+-#define AC97_CONTROL_STATUS		(0x00000080 + VOYAGER_AC97_BASE)
+-#define AC97C_READ			(1 << 19)
+-#define AC97C_WD_BIT			(1 << 2)
+-#define AC97C_INDEX_MASK		0x7f
+-
+-/* arch/sh/cchips/voyagergx/consistent.c */
+-void *voyagergx_consistent_alloc(struct device *, size_t, dma_addr_t *, gfp_t);
+-int voyagergx_consistent_free(struct device *, size_t, void *, dma_addr_t);
+-
+-/* arch/sh/cchips/voyagergx/irq.c */
+-void setup_voyagergx_irq(void);
+-
+-#endif /* _VOYAGER_GX_REG_H */
+diff --git a/include/asm-sh64/Kbuild b/include/asm-sh64/Kbuild
+deleted file mode 100644
+index c68e168..0000000
+--- a/include/asm-sh64/Kbuild
++++ /dev/null
+@@ -1 +0,0 @@
+-include include/asm-generic/Kbuild.asm
+diff --git a/include/asm-sh64/a.out.h b/include/asm-sh64/a.out.h
+deleted file mode 100644
+index 237ee4e..0000000
+--- a/include/asm-sh64/a.out.h
++++ /dev/null
+@@ -1,38 +0,0 @@
+-#ifndef __ASM_SH64_A_OUT_H
+-#define __ASM_SH64_A_OUT_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.
+- *
+- * include/asm-sh64/a.out.h
+- *
+- * Copyright (C) 2000, 2001  Paolo Alberelli
+- *
+- */
+-
+-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)
+-
+-#ifdef __KERNEL__
+-
+-#define STACK_TOP	TASK_SIZE
+-#define STACK_TOP_MAX	STACK_TOP
+-
+-#endif
+-
+-#endif /* __ASM_SH64_A_OUT_H */
+diff --git a/include/asm-sh64/atomic.h b/include/asm-sh64/atomic.h
+deleted file mode 100644
+index 28f2ea9..0000000
+--- a/include/asm-sh64/atomic.h
++++ /dev/null
+@@ -1,158 +0,0 @@
+-#ifndef __ASM_SH64_ATOMIC_H
+-#define __ASM_SH64_ATOMIC_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.
+- *
+- * include/asm-sh64/atomic.h
+- *
+- * Copyright (C) 2000, 2001  Paolo Alberelli
+- * Copyright (C) 2003  Paul Mundt
+- *
+- */
+-
+-/*
+- * Atomic operations that C can't guarantee us.  Useful for
+- * resource counting etc..
+- *
+- */
+-
+-typedef struct { volatile int counter; } atomic_t;
+-
+-#define ATOMIC_INIT(i)	( (atomic_t) { (i) } )
+-
+-#define atomic_read(v)		((v)->counter)
+-#define atomic_set(v,i)		((v)->counter = (i))
+-
+-#include <asm/system.h>
+-
+-/*
+- * To get proper branch prediction for the main line, we must branch
+- * forward to code at the end of this object's .text section, then
+- * branch back to restart the operation.
+- */
+-
+-static __inline__ void atomic_add(int i, atomic_t * v)
+-{
+-	unsigned long flags;
+-
+-	local_irq_save(flags);
+-	*(long *)v += i;
+-	local_irq_restore(flags);
+-}
+-
+-static __inline__ void atomic_sub(int i, atomic_t *v)
+-{
+-	unsigned long flags;
+-
+-	local_irq_save(flags);
+-	*(long *)v -= i;
+-	local_irq_restore(flags);
+-}
+-
+-static __inline__ int atomic_add_return(int i, atomic_t * v)
+-{
+-	unsigned long temp, flags;
+-
+-	local_irq_save(flags);
+-	temp = *(long *)v;
+-	temp += i;
+-	*(long *)v = temp;
+-	local_irq_restore(flags);
+-
+-	return temp;
+-}
+-
+-#define atomic_add_negative(a, v)	(atomic_add_return((a), (v)) < 0)
+-
+-static __inline__ int atomic_sub_return(int i, atomic_t * v)
+-{
+-	unsigned long temp, flags;
+-
+-	local_irq_save(flags);
+-	temp = *(long *)v;
+-	temp -= i;
+-	*(long *)v = temp;
+-	local_irq_restore(flags);
+-
+-	return temp;
+-}
+-
+-#define atomic_dec_return(v) atomic_sub_return(1,(v))
+-#define atomic_inc_return(v) atomic_add_return(1,(v))
+-
+-/*
+- * atomic_inc_and_test - increment and test
+- * @v: pointer of type atomic_t
+- *
+- * Atomically increments @v by 1
+- * and returns true if the result is zero, or false for all
+- * other cases.
+- */
+-#define atomic_inc_and_test(v) (atomic_inc_return(v) == 0)
+-
+-#define atomic_sub_and_test(i,v) (atomic_sub_return((i), (v)) == 0)
+-#define atomic_dec_and_test(v) (atomic_sub_return(1, (v)) == 0)
+-
+-#define atomic_inc(v) atomic_add(1,(v))
+-#define atomic_dec(v) atomic_sub(1,(v))
+-
+-static inline int atomic_cmpxchg(atomic_t *v, int old, int new)
+-{
+-	int ret;
+-	unsigned long flags;
+-
+-	local_irq_save(flags);
+-	ret = v->counter;
+-	if (likely(ret == old))
+-		v->counter = new;
+-	local_irq_restore(flags);
+-
+-	return ret;
+-}
+-
+-#define atomic_xchg(v, new) (xchg(&((v)->counter), new))
+-
+-static inline int atomic_add_unless(atomic_t *v, int a, int u)
+-{
+-	int ret;
+-	unsigned long flags;
+-
+-	local_irq_save(flags);
+-	ret = v->counter;
+-	if (ret != u)
+-		v->counter += a;
+-	local_irq_restore(flags);
+-
+-	return ret != u;
+-}
+-#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
+-
+-static __inline__ void atomic_clear_mask(unsigned int mask, atomic_t *v)
 -{
--	int i;
--	struct ocfs2_slot_info *si = osb->slot_info;
+-	unsigned long flags;
 -
--	spin_lock(&si->si_lock);
+-	local_irq_save(flags);
+-	*(long *)v &= ~mask;
+-	local_irq_restore(flags);
+-}
 -
--	for (i = 0; i < si->si_size; i++)
--		if (si->si_global_node_nums[i] != OCFS2_INVALID_SLOT)
--			ocfs2_node_map_set_bit(osb, &osb->mounted_map,
--					      si->si_global_node_nums[i]);
+-static __inline__ void atomic_set_mask(unsigned int mask, atomic_t *v)
+-{
+-	unsigned long flags;
 -
--	spin_unlock(&si->si_lock);
+-	local_irq_save(flags);
+-	*(long *)v |= mask;
+-	local_irq_restore(flags);
 -}
 -
- /* post the slot information on disk into our slot_info struct. */
- void ocfs2_update_slot_info(struct ocfs2_slot_info *si)
- {
-diff --git a/fs/ocfs2/slot_map.h b/fs/ocfs2/slot_map.h
-index d8c8cee..1025872 100644
---- a/fs/ocfs2/slot_map.h
-+++ b/fs/ocfs2/slot_map.h
-@@ -52,8 +52,6 @@ s16 ocfs2_node_num_to_slot(struct ocfs2_slot_info *si,
- void ocfs2_clear_slot(struct ocfs2_slot_info *si,
- 		      s16 slot_num);
- 
--void ocfs2_populate_mounted_map(struct ocfs2_super *osb);
+-/* Atomic operations are already serializing on SH */
+-#define smp_mb__before_atomic_dec()	barrier()
+-#define smp_mb__after_atomic_dec()	barrier()
+-#define smp_mb__before_atomic_inc()	barrier()
+-#define smp_mb__after_atomic_inc()	barrier()
+-
+-#include <asm-generic/atomic.h>
+-#endif /* __ASM_SH64_ATOMIC_H */
+diff --git a/include/asm-sh64/auxvec.h b/include/asm-sh64/auxvec.h
+deleted file mode 100644
+index 1ad5a44..0000000
+--- a/include/asm-sh64/auxvec.h
++++ /dev/null
+@@ -1,4 +0,0 @@
+-#ifndef __ASM_SH64_AUXVEC_H
+-#define __ASM_SH64_AUXVEC_H
 -
- static inline int ocfs2_is_empty_slot(struct ocfs2_slot_info *si,
- 				      int slot_num)
- {
-diff --git a/fs/ocfs2/suballoc.c b/fs/ocfs2/suballoc.c
-index 8f09f52..7e397e2 100644
---- a/fs/ocfs2/suballoc.c
-+++ b/fs/ocfs2/suballoc.c
-@@ -101,8 +101,6 @@ static inline int ocfs2_block_group_reasonably_empty(struct ocfs2_group_desc *bg
- static inline u32 ocfs2_desc_bitmap_to_cluster_off(struct inode *inode,
- 						   u64 bg_blkno,
- 						   u16 bg_bit_off);
--static inline u64 ocfs2_which_cluster_group(struct inode *inode,
--					    u32 cluster);
- static inline void ocfs2_block_to_cluster_group(struct inode *inode,
- 						u64 data_blkno,
- 						u64 *bg_blkno,
-@@ -114,7 +112,7 @@ void ocfs2_free_alloc_context(struct ocfs2_alloc_context *ac)
- 
- 	if (inode) {
- 		if (ac->ac_which != OCFS2_AC_USE_LOCAL)
--			ocfs2_meta_unlock(inode, 1);
-+			ocfs2_inode_unlock(inode, 1);
- 
- 		mutex_unlock(&inode->i_mutex);
- 
-@@ -131,9 +129,9 @@ static u32 ocfs2_bits_per_group(struct ocfs2_chain_list *cl)
- }
- 
- /* somewhat more expensive than our other checks, so use sparingly. */
--static int ocfs2_check_group_descriptor(struct super_block *sb,
--					struct ocfs2_dinode *di,
--					struct ocfs2_group_desc *gd)
-+int ocfs2_check_group_descriptor(struct super_block *sb,
-+				 struct ocfs2_dinode *di,
-+				 struct ocfs2_group_desc *gd)
- {
- 	unsigned int max_bits;
- 
-@@ -412,7 +410,7 @@ static int ocfs2_reserve_suballoc_bits(struct ocfs2_super *osb,
- 
- 	mutex_lock(&alloc_inode->i_mutex);
- 
--	status = ocfs2_meta_lock(alloc_inode, &bh, 1);
-+	status = ocfs2_inode_lock(alloc_inode, &bh, 1);
- 	if (status < 0) {
- 		mutex_unlock(&alloc_inode->i_mutex);
- 		iput(alloc_inode);
-@@ -1443,8 +1441,7 @@ static inline u32 ocfs2_desc_bitmap_to_cluster_off(struct inode *inode,
- 
- /* given a cluster offset, calculate which block group it belongs to
-  * and return that block offset. */
--static inline u64 ocfs2_which_cluster_group(struct inode *inode,
--					    u32 cluster)
-+u64 ocfs2_which_cluster_group(struct inode *inode, u32 cluster)
- {
- 	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
- 	u32 group_no;
-@@ -1519,8 +1516,9 @@ int __ocfs2_claim_clusters(struct ocfs2_super *osb,
- 		if (min_clusters > (osb->bitmap_cpg - 1)) {
- 			/* The only paths asking for contiguousness
- 			 * should know about this already. */
--			mlog(ML_ERROR, "minimum allocation requested exceeds "
--				       "group bitmap size!");
-+			mlog(ML_ERROR, "minimum allocation requested %u exceeds "
-+			     "group bitmap size %u!\n", min_clusters,
-+			     osb->bitmap_cpg);
- 			status = -ENOSPC;
- 			goto bail;
- 		}
-diff --git a/fs/ocfs2/suballoc.h b/fs/ocfs2/suballoc.h
-index cafe937..8799033 100644
---- a/fs/ocfs2/suballoc.h
-+++ b/fs/ocfs2/suballoc.h
-@@ -147,4 +147,12 @@ static inline int ocfs2_is_cluster_bitmap(struct inode *inode)
- int ocfs2_reserve_cluster_bitmap_bits(struct ocfs2_super *osb,
- 				      struct ocfs2_alloc_context *ac);
- 
-+/* given a cluster offset, calculate which block group it belongs to
-+ * and return that block offset. */
-+u64 ocfs2_which_cluster_group(struct inode *inode, u32 cluster);
-+
-+/* somewhat more expensive than our other checks, so use sparingly. */
-+int ocfs2_check_group_descriptor(struct super_block *sb,
-+				 struct ocfs2_dinode *di,
-+				 struct ocfs2_group_desc *gd);
- #endif /* _CHAINALLOC_H_ */
-diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c
-index 5ee7754..01fe40e 100644
---- a/fs/ocfs2/super.c
-+++ b/fs/ocfs2/super.c
-@@ -65,7 +65,6 @@
- #include "sysfile.h"
- #include "uptodate.h"
- #include "ver.h"
--#include "vote.h"
- 
- #include "buffer_head_io.h"
- 
-@@ -84,9 +83,11 @@ MODULE_LICENSE("GPL");
- 
- struct mount_options
- {
-+	unsigned long	commit_interval;
- 	unsigned long	mount_opt;
- 	unsigned int	atime_quantum;
- 	signed short	slot;
-+	unsigned int	localalloc_opt;
- };
- 
- static int ocfs2_parse_options(struct super_block *sb, char *options,
-@@ -150,6 +151,9 @@ enum {
- 	Opt_data_writeback,
- 	Opt_atime_quantum,
- 	Opt_slot,
-+	Opt_commit,
-+	Opt_localalloc,
-+	Opt_localflocks,
- 	Opt_err,
- };
- 
-@@ -165,6 +169,9 @@ static match_table_t tokens = {
- 	{Opt_data_writeback, "data=writeback"},
- 	{Opt_atime_quantum, "atime_quantum=%u"},
- 	{Opt_slot, "preferred_slot=%u"},
-+	{Opt_commit, "commit=%u"},
-+	{Opt_localalloc, "localalloc=%d"},
-+	{Opt_localflocks, "localflocks"},
- 	{Opt_err, NULL}
- };
- 
-@@ -213,7 +220,7 @@ static int ocfs2_init_global_system_inodes(struct ocfs2_super *osb)
- 
- 	mlog_entry_void();
- 
--	new = ocfs2_iget(osb, osb->root_blkno, OCFS2_FI_FLAG_SYSFILE);
-+	new = ocfs2_iget(osb, osb->root_blkno, OCFS2_FI_FLAG_SYSFILE, 0);
- 	if (IS_ERR(new)) {
- 		status = PTR_ERR(new);
- 		mlog_errno(status);
-@@ -221,7 +228,7 @@ static int ocfs2_init_global_system_inodes(struct ocfs2_super *osb)
- 	}
- 	osb->root_inode = new;
- 
--	new = ocfs2_iget(osb, osb->system_dir_blkno, OCFS2_FI_FLAG_SYSFILE);
-+	new = ocfs2_iget(osb, osb->system_dir_blkno, OCFS2_FI_FLAG_SYSFILE, 0);
- 	if (IS_ERR(new)) {
- 		status = PTR_ERR(new);
- 		mlog_errno(status);
-@@ -443,6 +450,8 @@ unlock_osb:
- 		osb->s_mount_opt = parsed_options.mount_opt;
- 		osb->s_atime_quantum = parsed_options.atime_quantum;
- 		osb->preferred_slot = parsed_options.slot;
-+		if (parsed_options.commit_interval)
-+			osb->osb_commit_interval = parsed_options.commit_interval;
- 
- 		if (!ocfs2_is_hard_readonly(osb))
- 			ocfs2_set_journal_params(osb);
-@@ -597,6 +606,8 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent)
- 	osb->s_mount_opt = parsed_options.mount_opt;
- 	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;
- 
- 	sb->s_magic = OCFS2_SUPER_MAGIC;
- 
-@@ -747,9 +758,11 @@ static int ocfs2_parse_options(struct super_block *sb,
- 	mlog_entry("remount: %d, options: \"%s\"\n", is_remount,
- 		   options ? options : "(none)");
- 
-+	mopt->commit_interval = 0;
- 	mopt->mount_opt = 0;
- 	mopt->atime_quantum = OCFS2_DEFAULT_ATIME_QUANTUM;
- 	mopt->slot = OCFS2_INVALID_SLOT;
-+	mopt->localalloc_opt = OCFS2_DEFAULT_LOCAL_ALLOC_SIZE;
- 
- 	if (!options) {
- 		status = 1;
-@@ -816,6 +829,41 @@ static int ocfs2_parse_options(struct super_block *sb,
- 			if (option)
- 				mopt->slot = (s16)option;
- 			break;
-+		case Opt_commit:
-+			option = 0;
-+			if (match_int(&args[0], &option)) {
-+				status = 0;
-+				goto bail;
-+			}
-+			if (option < 0)
-+				return 0;
-+			if (option == 0)
-+				option = JBD_DEFAULT_MAX_COMMIT_AGE;
-+			mopt->commit_interval = HZ * option;
-+			break;
-+		case Opt_localalloc:
-+			option = 0;
-+			if (match_int(&args[0], &option)) {
-+				status = 0;
-+				goto bail;
-+			}
-+			if (option >= 0 && (option <= ocfs2_local_alloc_size(sb) * 8))
-+				mopt->localalloc_opt = option;
-+			break;
-+		case Opt_localflocks:
-+			/*
-+			 * Changing this during remount could race
-+			 * flock() requests, or "unbalance" existing
-+			 * ones (e.g., a lock is taken in one mode but
-+			 * dropped in the other). If users care enough
-+			 * to flip locking modes during remount, we
-+			 * could add a "local" flag to individual
-+			 * flock structures for proper tracking of
-+			 * state.
-+			 */
-+			if (!is_remount)
-+				mopt->mount_opt |= OCFS2_MOUNT_LOCALFLOCKS;
-+			break;
- 		default:
- 			mlog(ML_ERROR,
- 			     "Unrecognized mount option \"%s\" "
-@@ -864,6 +912,16 @@ static int ocfs2_show_options(struct seq_file *s, struct vfsmount *mnt)
- 	if (osb->s_atime_quantum != OCFS2_DEFAULT_ATIME_QUANTUM)
- 		seq_printf(s, ",atime_quantum=%u", osb->s_atime_quantum);
- 
-+	if (osb->osb_commit_interval)
-+		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);
-+
-+	if (opts & OCFS2_MOUNT_LOCALFLOCKS)
-+		seq_printf(s, ",localflocks,");
-+
- 	return 0;
- }
- 
-@@ -965,7 +1023,7 @@ static int ocfs2_statfs(struct dentry *dentry, struct kstatfs *buf)
- 		goto bail;
- 	}
- 
--	status = ocfs2_meta_lock(inode, &bh, 0);
-+	status = ocfs2_inode_lock(inode, &bh, 0);
- 	if (status < 0) {
- 		mlog_errno(status);
- 		goto bail;
-@@ -989,7 +1047,7 @@ static int ocfs2_statfs(struct dentry *dentry, struct kstatfs *buf)
- 
- 	brelse(bh);
- 
--	ocfs2_meta_unlock(inode, 0);
-+	ocfs2_inode_unlock(inode, 0);
- 	status = 0;
- bail:
- 	if (inode)
-@@ -1020,8 +1078,7 @@ static void ocfs2_inode_init_once(struct kmem_cache *cachep, void *data)
- 	oi->ip_clusters = 0;
- 
- 	ocfs2_lock_res_init_once(&oi->ip_rw_lockres);
--	ocfs2_lock_res_init_once(&oi->ip_meta_lockres);
--	ocfs2_lock_res_init_once(&oi->ip_data_lockres);
-+	ocfs2_lock_res_init_once(&oi->ip_inode_lockres);
- 	ocfs2_lock_res_init_once(&oi->ip_open_lockres);
- 
- 	ocfs2_metadata_cache_init(&oi->vfs_inode);
-@@ -1117,25 +1174,12 @@ static int ocfs2_mount_volume(struct super_block *sb)
- 		goto leave;
- 	}
- 
--	status = ocfs2_register_hb_callbacks(osb);
--	if (status < 0) {
--		mlog_errno(status);
--		goto leave;
--	}
+-#endif /* __ASM_SH64_AUXVEC_H */
+diff --git a/include/asm-sh64/bitops.h b/include/asm-sh64/bitops.h
+deleted file mode 100644
+index 600c59e..0000000
+--- a/include/asm-sh64/bitops.h
++++ /dev/null
+@@ -1,155 +0,0 @@
+-#ifndef __ASM_SH64_BITOPS_H
+-#define __ASM_SH64_BITOPS_H
 -
- 	status = ocfs2_dlm_init(osb);
- 	if (status < 0) {
- 		mlog_errno(status);
- 		goto leave;
- 	}
- 
--	/* requires vote_thread to be running. */
--	status = ocfs2_register_net_handlers(osb);
--	if (status < 0) {
--		mlog_errno(status);
--		goto leave;
--	}
+-/*
+- * 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/asm-sh64/bitops.h
+- *
+- * Copyright (C) 2000, 2001  Paolo Alberelli
+- * Copyright (C) 2003  Paul Mundt
+- */
 -
- 	status = ocfs2_super_lock(osb, 1);
- 	if (status < 0) {
- 		mlog_errno(status);
-@@ -1150,8 +1194,6 @@ static int ocfs2_mount_volume(struct super_block *sb)
- 		goto leave;
- 	}
- 
--	ocfs2_populate_mounted_map(osb);
+-#ifdef __KERNEL__
 -
- 	/* load all node-local system inodes */
- 	status = ocfs2_init_local_system_inodes(osb);
- 	if (status < 0) {
-@@ -1174,15 +1216,6 @@ static int ocfs2_mount_volume(struct super_block *sb)
- 	if (ocfs2_mount_local(osb))
- 		goto leave;
- 
--	/* This should be sent *after* we recovered our journal as it
--	 * will cause other nodes to unmark us as needing
--	 * recovery. However, we need to send it *before* dropping the
--	 * super block lock as otherwise their recovery threads might
--	 * try to clean us up while we're live! */
--	status = ocfs2_request_mount_vote(osb);
--	if (status < 0)
--		mlog_errno(status);
+-#ifndef _LINUX_BITOPS_H
+-#error only <linux/bitops.h> can be included directly
+-#endif
 -
- leave:
- 	if (unlock_super)
- 		ocfs2_super_unlock(osb, 1);
-@@ -1240,10 +1273,6 @@ static void ocfs2_dismount_volume(struct super_block *sb, int mnt_err)
- 			mlog_errno(tmp);
- 			return;
- 		}
+-#include <linux/compiler.h>
+-#include <asm/system.h>
+-/* For __swab32 */
+-#include <asm/byteorder.h>
 -
--		tmp = ocfs2_request_umount_vote(osb);
--		if (tmp < 0)
--			mlog_errno(tmp);
- 	}
- 
- 	if (osb->slot_num != OCFS2_INVALID_SLOT)
-@@ -1254,13 +1283,8 @@ static void ocfs2_dismount_volume(struct super_block *sb, int mnt_err)
- 
- 	ocfs2_release_system_inodes(osb);
- 
--	if (osb->dlm) {
--		ocfs2_unregister_net_handlers(osb);
+-static __inline__ void set_bit(int nr, volatile void * addr)
+-{
+-	int	mask;
+-	volatile unsigned int *a = addr;
+-	unsigned long flags;
 -
-+	if (osb->dlm)
- 		ocfs2_dlm_shutdown(osb);
--	}
+-	a += nr >> 5;
+-	mask = 1 << (nr & 0x1f);
+-	local_irq_save(flags);
+-	*a |= mask;
+-	local_irq_restore(flags);
+-}
 -
--	ocfs2_clear_hb_callbacks(osb);
- 
- 	debugfs_remove(osb->osb_debug_root);
- 
-@@ -1315,7 +1339,6 @@ static int ocfs2_initialize_super(struct super_block *sb,
- 	int i, cbits, bbits;
- 	struct ocfs2_dinode *di = (struct ocfs2_dinode *)bh->b_data;
- 	struct inode *inode = NULL;
--	struct buffer_head *bitmap_bh = NULL;
- 	struct ocfs2_journal *journal;
- 	__le32 uuid_net_key;
- 	struct ocfs2_super *osb;
-@@ -1344,19 +1367,13 @@ static int ocfs2_initialize_super(struct super_block *sb,
- 	osb->s_sectsize_bits = blksize_bits(sector_size);
- 	BUG_ON(!osb->s_sectsize_bits);
- 
--	osb->net_response_ids = 0;
--	spin_lock_init(&osb->net_response_lock);
--	INIT_LIST_HEAD(&osb->net_response_list);
+-/*
+- * clear_bit() doesn't provide any barrier for the compiler.
+- */
+-#define smp_mb__before_clear_bit()	barrier()
+-#define smp_mb__after_clear_bit()	barrier()
+-static inline void clear_bit(int nr, volatile unsigned long *a)
+-{
+-	int	mask;
+-	unsigned long flags;
 -
--	INIT_LIST_HEAD(&osb->osb_net_handlers);
- 	init_waitqueue_head(&osb->recovery_event);
--	spin_lock_init(&osb->vote_task_lock);
--	init_waitqueue_head(&osb->vote_event);
--	osb->vote_work_sequence = 0;
--	osb->vote_wake_sequence = 0;
-+	spin_lock_init(&osb->dc_task_lock);
-+	init_waitqueue_head(&osb->dc_event);
-+	osb->dc_work_sequence = 0;
-+	osb->dc_wake_sequence = 0;
- 	INIT_LIST_HEAD(&osb->blocked_lock_list);
- 	osb->blocked_lock_count = 0;
--	INIT_LIST_HEAD(&osb->vote_list);
- 	spin_lock_init(&osb->osb_lock);
- 
- 	atomic_set(&osb->alloc_stats.moves, 0);
-@@ -1496,7 +1513,6 @@ static int ocfs2_initialize_super(struct super_block *sb,
- 	}
- 
- 	memcpy(&uuid_net_key, di->id2.i_super.s_uuid, sizeof(uuid_net_key));
--	osb->net_key = le32_to_cpu(uuid_net_key);
- 
- 	strncpy(osb->vol_label, di->id2.i_super.s_label, 63);
- 	osb->vol_label[63] = '\0';
-@@ -1539,25 +1555,9 @@ static int ocfs2_initialize_super(struct super_block *sb,
- 	}
- 
- 	osb->bitmap_blkno = OCFS2_I(inode)->ip_blkno;
+-	a += nr >> 5;
+-	mask = 1 << (nr & 0x1f);
+-	local_irq_save(flags);
+-	*a &= ~mask;
+-	local_irq_restore(flags);
+-}
 -
--	/* We don't have a cluster lock on the bitmap here because
--	 * we're only interested in static information and the extra
--	 * complexity at mount time isn't worht it. Don't pass the
--	 * inode in to the read function though as we don't want it to
--	 * be put in the cache. */
--	status = ocfs2_read_block(osb, osb->bitmap_blkno, &bitmap_bh, 0,
--				  NULL);
- 	iput(inode);
--	if (status < 0) {
--		mlog_errno(status);
--		goto bail;
--	}
- 
--	di = (struct ocfs2_dinode *) bitmap_bh->b_data;
--	osb->bitmap_cpg = le16_to_cpu(di->id2.i_chain.cl_cpg);
--	brelse(bitmap_bh);
--	mlog(0, "cluster bitmap inode: %llu, clusters per group: %u\n",
--	     (unsigned long long)osb->bitmap_blkno, osb->bitmap_cpg);
-+	osb->bitmap_cpg = ocfs2_group_bitmap_size(sb) * 8;
- 
- 	status = ocfs2_init_slot_info(osb);
- 	if (status < 0) {
-diff --git a/fs/ocfs2/sysfile.c b/fs/ocfs2/sysfile.c
-index fd2e846..ab713eb 100644
---- a/fs/ocfs2/sysfile.c
-+++ b/fs/ocfs2/sysfile.c
-@@ -112,7 +112,7 @@ static struct inode * _ocfs2_get_system_file_inode(struct ocfs2_super *osb,
- 		goto bail;
- 	}
- 
--	inode = ocfs2_iget(osb, blkno, OCFS2_FI_FLAG_SYSFILE);
-+	inode = ocfs2_iget(osb, blkno, OCFS2_FI_FLAG_SYSFILE, type);
- 	if (IS_ERR(inode)) {
- 		mlog_errno(PTR_ERR(inode));
- 		inode = NULL;
-diff --git a/fs/ocfs2/ver.c b/fs/ocfs2/ver.c
-index 5405ce1..e2488f4 100644
---- a/fs/ocfs2/ver.c
-+++ b/fs/ocfs2/ver.c
-@@ -29,7 +29,7 @@
- 
- #include "ver.h"
- 
--#define OCFS2_BUILD_VERSION "1.3.3"
-+#define OCFS2_BUILD_VERSION "1.5.0"
- 
- #define VERSION_STR "OCFS2 " OCFS2_BUILD_VERSION
- 
-diff --git a/fs/ocfs2/vote.c b/fs/ocfs2/vote.c
+-static __inline__ void change_bit(int nr, volatile void * addr)
+-{
+-	int	mask;
+-	volatile unsigned int *a = addr;
+-	unsigned long flags;
+-
+-	a += nr >> 5;
+-	mask = 1 << (nr & 0x1f);
+-	local_irq_save(flags);
+-	*a ^= mask;
+-	local_irq_restore(flags);
+-}
+-
+-static __inline__ int test_and_set_bit(int nr, volatile void * addr)
+-{
+-	int	mask, retval;
+-	volatile unsigned int *a = addr;
+-	unsigned long flags;
+-
+-	a += nr >> 5;
+-	mask = 1 << (nr & 0x1f);
+-	local_irq_save(flags);
+-	retval = (mask & *a) != 0;
+-	*a |= mask;
+-	local_irq_restore(flags);
+-
+-	return retval;
+-}
+-
+-static __inline__ int test_and_clear_bit(int nr, volatile void * addr)
+-{
+-	int	mask, retval;
+-	volatile unsigned int *a = addr;
+-	unsigned long flags;
+-
+-	a += nr >> 5;
+-	mask = 1 << (nr & 0x1f);
+-	local_irq_save(flags);
+-	retval = (mask & *a) != 0;
+-	*a &= ~mask;
+-	local_irq_restore(flags);
+-
+-	return retval;
+-}
+-
+-static __inline__ int test_and_change_bit(int nr, volatile void * addr)
+-{
+-	int	mask, retval;
+-	volatile unsigned int *a = addr;
+-	unsigned long flags;
+-
+-	a += nr >> 5;
+-	mask = 1 << (nr & 0x1f);
+-	local_irq_save(flags);
+-	retval = (mask & *a) != 0;
+-	*a ^= mask;
+-	local_irq_restore(flags);
+-
+-	return retval;
+-}
+-
+-#include <asm-generic/bitops/non-atomic.h>
+-
+-static __inline__ unsigned long ffz(unsigned long word)
+-{
+-	unsigned long result, __d2, __d3;
+-
+-        __asm__("gettr  tr0, %2\n\t"
+-                "pta    $+32, tr0\n\t"
+-                "andi   %1, 1, %3\n\t"
+-                "beq    %3, r63, tr0\n\t"
+-                "pta    $+4, tr0\n"
+-                "0:\n\t"
+-                "shlri.l        %1, 1, %1\n\t"
+-                "addi   %0, 1, %0\n\t"
+-                "andi   %1, 1, %3\n\t"
+-                "beqi   %3, 1, tr0\n"
+-                "1:\n\t"
+-                "ptabs  %2, tr0\n\t"
+-                : "=r" (result), "=r" (word), "=r" (__d2), "=r" (__d3)
+-                : "0" (0L), "1" (word));
+-
+-	return result;
+-}
+-
+-#include <asm-generic/bitops/__ffs.h>
+-#include <asm-generic/bitops/find.h>
+-#include <asm-generic/bitops/hweight.h>
+-#include <asm-generic/bitops/lock.h>
+-#include <asm-generic/bitops/sched.h>
+-#include <asm-generic/bitops/ffs.h>
+-#include <asm-generic/bitops/ext2-non-atomic.h>
+-#include <asm-generic/bitops/ext2-atomic.h>
+-#include <asm-generic/bitops/minix.h>
+-#include <asm-generic/bitops/fls.h>
+-#include <asm-generic/bitops/fls64.h>
+-
+-#endif /* __KERNEL__ */
+-
+-#endif /* __ASM_SH64_BITOPS_H */
+diff --git a/include/asm-sh64/bug.h b/include/asm-sh64/bug.h
 deleted file mode 100644
-index c053585..0000000
---- a/fs/ocfs2/vote.c
+index f3a9c92..0000000
+--- a/include/asm-sh64/bug.h
 +++ /dev/null
-@@ -1,756 +0,0 @@
--/* -*- mode: c; c-basic-offset: 8; -*-
-- * vim: noexpandtab sw=8 ts=8 sts=0:
+@@ -1,19 +0,0 @@
+-#ifndef __ASM_SH64_BUG_H
+-#define __ASM_SH64_BUG_H
+-
+-#ifdef CONFIG_BUG
+-/*
+- * Tell the user there is some problem, then force a segfault (in process
+- * context) or a panic (interrupt context).
+- */
+-#define BUG() do { \
+-	printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \
+-	*(volatile int *)0 = 0; \
+-} while (0)
+-
+-#define HAVE_ARCH_BUG
+-#endif
+-
+-#include <asm-generic/bug.h>
+-
+-#endif /* __ASM_SH64_BUG_H */
+diff --git a/include/asm-sh64/bugs.h b/include/asm-sh64/bugs.h
+deleted file mode 100644
+index 05554aa..0000000
+--- a/include/asm-sh64/bugs.h
++++ /dev/null
+@@ -1,38 +0,0 @@
+-#ifndef __ASM_SH64_BUGS_H
+-#define __ASM_SH64_BUGS_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.
 - *
-- * vote.c
+- * include/asm-sh64/bugs.h
 - *
-- * description here
+- * Copyright (C) 2000, 2001  Paolo Alberelli
+- * Copyright (C) 2003  Paul Mundt
 - *
-- * Copyright (C) 2003, 2004 Oracle.  All rights reserved.
+- */
+-
+-/*
+- * This is included by init/main.c to check for architecture-dependent bugs.
 - *
-- * This program is free software; you can redistribute it and/or
-- * modify it under the terms of the GNU General Public
-- * License as published by the Free Software Foundation; either
-- * version 2 of the License, or (at your option) any later version.
+- * Needs:
+- *	void check_bugs(void);
+- */
+-
+-/*
+- * I don't know of any Super-H bugs yet.
+- */
+-
+-#include <asm/processor.h>
+-
+-static void __init check_bugs(void)
+-{
+-	extern char *get_cpu_subtype(void);
+-	extern unsigned long loops_per_jiffy;
+-
+-	cpu_data->loops_per_jiffy = loops_per_jiffy;
+-
+-	printk("CPU: %s\n", get_cpu_subtype());
+-}
+-#endif /* __ASM_SH64_BUGS_H */
+diff --git a/include/asm-sh64/byteorder.h b/include/asm-sh64/byteorder.h
+deleted file mode 100644
+index 7419d78..0000000
+--- a/include/asm-sh64/byteorder.h
++++ /dev/null
+@@ -1,49 +0,0 @@
+-#ifndef __ASM_SH64_BYTEORDER_H
+-#define __ASM_SH64_BYTEORDER_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.
 - *
-- * This program is distributed in the hope that it will be useful,
-- * but WITHOUT ANY WARRANTY; without even the implied warranty of
-- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-- * General Public License for more details.
+- * include/asm-sh64/byteorder.h
+- *
+- * Copyright (C) 2000, 2001  Paolo Alberelli
 - *
-- * You 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/types.h>
--#include <linux/slab.h>
--#include <linux/highmem.h>
--#include <linux/kthread.h>
+-#include <asm/types.h>
 -
--#include <cluster/heartbeat.h>
--#include <cluster/nodemanager.h>
--#include <cluster/tcp.h>
+-static inline __attribute_const__ __u32 ___arch__swab32(__u32 x)
+-{
+-	__asm__("byterev	%0, %0\n\t"
+-		"shari		%0, 32, %0"
+-		: "=r" (x)
+-		: "0" (x));
+-	return x;
+-}
 -
--#include <dlm/dlmapi.h>
+-static inline __attribute_const__ __u16 ___arch__swab16(__u16 x)
+-{
+-	__asm__("byterev	%0, %0\n\t"
+-		"shari		%0, 48, %0"
+-		: "=r" (x)
+-		: "0" (x));
+-	return x;
+-}
 -
--#define MLOG_MASK_PREFIX ML_VOTE
--#include <cluster/masklog.h>
+-#define __arch__swab32(x) ___arch__swab32(x)
+-#define __arch__swab16(x) ___arch__swab16(x)
 -
--#include "ocfs2.h"
+-#if !defined(__STRICT_ANSI__) || defined(__KERNEL__)
+-#  define __BYTEORDER_HAS_U64__
+-#  define __SWAB_64_THRU_32__
+-#endif
 -
--#include "alloc.h"
--#include "dlmglue.h"
--#include "extent_map.h"
--#include "heartbeat.h"
--#include "inode.h"
--#include "journal.h"
--#include "slot_map.h"
--#include "vote.h"
+-#ifdef __LITTLE_ENDIAN__
+-#include <linux/byteorder/little_endian.h>
+-#else
+-#include <linux/byteorder/big_endian.h>
+-#endif
 -
--#include "buffer_head_io.h"
+-#endif /* __ASM_SH64_BYTEORDER_H */
+diff --git a/include/asm-sh64/cache.h b/include/asm-sh64/cache.h
+deleted file mode 100644
+index a4f36f0..0000000
+--- a/include/asm-sh64/cache.h
++++ /dev/null
+@@ -1,139 +0,0 @@
+-#ifndef __ASM_SH64_CACHE_H
+-#define __ASM_SH64_CACHE_H
 -
--#define OCFS2_MESSAGE_TYPE_VOTE     (0x1)
--#define OCFS2_MESSAGE_TYPE_RESPONSE (0x2)
--struct ocfs2_msg_hdr
--{
--	__be32 h_response_id; /* used to lookup message handle on sending
--			    * node. */
--	__be32 h_request;
--	__be64 h_blkno;
--	__be32 h_generation;
--	__be32 h_node_num;    /* node sending this particular message. */
+-/*
+- * 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/asm-sh64/cache.h
+- *
+- * Copyright (C) 2000, 2001  Paolo Alberelli
+- * Copyright (C) 2003, 2004  Paul Mundt
+- *
+- */
+-#include <asm/cacheflush.h>
+-
+-#define L1_CACHE_SHIFT		5
+-/* bytes per L1 cache line */
+-#define L1_CACHE_BYTES		(1 << L1_CACHE_SHIFT)
+-#define L1_CACHE_ALIGN_MASK	(~(L1_CACHE_BYTES - 1))
+-#define L1_CACHE_ALIGN(x)	(((x)+(L1_CACHE_BYTES - 1)) & L1_CACHE_ALIGN_MASK)
+-#define L1_CACHE_SIZE_BYTES	(L1_CACHE_BYTES << 10)
+-
+-#ifdef MODULE
+-#define __cacheline_aligned __attribute__((__aligned__(L1_CACHE_BYTES)))
+-#else
+-#define __cacheline_aligned					\
+-  __attribute__((__aligned__(L1_CACHE_BYTES),			\
+-		 __section__(".data.cacheline_aligned")))
+-#endif
+-
+-/*
+- * Control Registers.
+- */
+-#define ICCR_BASE	0x01600000	/* Instruction Cache Control Register */
+-#define ICCR_REG0	0		/* Register 0 offset */
+-#define ICCR_REG1	1		/* Register 1 offset */
+-#define ICCR0		ICCR_BASE+ICCR_REG0
+-#define ICCR1		ICCR_BASE+ICCR_REG1
+-
+-#define ICCR0_OFF	0x0		/* Set ICACHE off */
+-#define ICCR0_ON	0x1		/* Set ICACHE on */
+-#define ICCR0_ICI	0x2		/* Invalidate all in IC */
+-
+-#define ICCR1_NOLOCK	0x0		/* Set No Locking */
+-
+-#define OCCR_BASE	0x01E00000	/* Operand Cache Control Register */
+-#define OCCR_REG0	0		/* Register 0 offset */
+-#define OCCR_REG1	1		/* Register 1 offset */
+-#define OCCR0		OCCR_BASE+OCCR_REG0
+-#define OCCR1		OCCR_BASE+OCCR_REG1
+-
+-#define OCCR0_OFF	0x0		/* Set OCACHE off */
+-#define OCCR0_ON	0x1		/* Set OCACHE on */
+-#define OCCR0_OCI	0x2		/* Invalidate all in OC */
+-#define OCCR0_WT	0x4		/* Set OCACHE in WT Mode */
+-#define OCCR0_WB	0x0		/* Set OCACHE in WB Mode */
+-
+-#define OCCR1_NOLOCK	0x0		/* Set No Locking */
+-
+-
+-/*
+- * SH-5
+- * A bit of description here, for neff=32.
+- *
+- *                               |<--- tag  (19 bits) --->|
+- * +-----------------------------+-----------------+------+----------+------+
+- * |                             |                 | ways |set index |offset|
+- * +-----------------------------+-----------------+------+----------+------+
+- *                                ^                 2 bits   8 bits   5 bits
+- *                                +- Bit 31
+- *
+- * Cacheline size is based on offset: 5 bits = 32 bytes per line
+- * A cache line is identified by a tag + set but OCACHETAG/ICACHETAG
+- * have a broader space for registers. These are outlined by
+- * CACHE_?C_*_STEP below.
+- *
+- */
+-
+-/* Valid and Dirty bits */
+-#define SH_CACHE_VALID		(1LL<<0)
+-#define SH_CACHE_UPDATED	(1LL<<57)
+-
+-/* Cache flags */
+-#define SH_CACHE_MODE_WT	(1LL<<0)
+-#define SH_CACHE_MODE_WB	(1LL<<1)
+-
+-#ifndef __ASSEMBLY__
+-
+-/*
+- * Cache information structure.
+- *
+- * Defined for both I and D cache, per-processor.
+- */
+-struct cache_info {
+-	unsigned int ways;
+-	unsigned int sets;
+-	unsigned int linesz;
+-
+-	unsigned int way_shift;
+-	unsigned int entry_shift;
+-	unsigned int set_shift;
+-	unsigned int way_step_shift;
+-	unsigned int asid_shift;
+-
+-	unsigned int way_ofs;
+-
+-	unsigned int asid_mask;
+-	unsigned int idx_mask;
+-	unsigned int epn_mask;
+-
+-	unsigned long flags;
 -};
 -
--struct ocfs2_vote_msg
+-#endif /* __ASSEMBLY__ */
+-
+-/* Instruction cache */
+-#define CACHE_IC_ADDRESS_ARRAY 0x01000000
+-
+-/* Operand Cache */
+-#define CACHE_OC_ADDRESS_ARRAY 0x01800000
+-
+-/* These declarations relate to cache 'synonyms' in the operand cache.  A
+-   'synonym' occurs where effective address bits overlap between those used for
+-   indexing the cache sets and those passed to the MMU for translation.  In the
+-   case of SH5-101 & SH5-103, only bit 12 is affected for 4k pages. */
+-
+-#define CACHE_OC_N_SYNBITS  1               /* Number of synonym bits */
+-#define CACHE_OC_SYN_SHIFT  12
+-/* Mask to select synonym bit(s) */
+-#define CACHE_OC_SYN_MASK   (((1UL<<CACHE_OC_N_SYNBITS)-1)<<CACHE_OC_SYN_SHIFT)
+-
+-
+-/*
+- * Instruction cache can't be invalidated based on physical addresses.
+- * No Instruction Cache defines required, then.
+- */
+-
+-#endif /* __ASM_SH64_CACHE_H */
+diff --git a/include/asm-sh64/cacheflush.h b/include/asm-sh64/cacheflush.h
+deleted file mode 100644
+index 1e53a47..0000000
+--- a/include/asm-sh64/cacheflush.h
++++ /dev/null
+@@ -1,50 +0,0 @@
+-#ifndef __ASM_SH64_CACHEFLUSH_H
+-#define __ASM_SH64_CACHEFLUSH_H
+-
+-#ifndef __ASSEMBLY__
+-
+-#include <asm/page.h>
+-
+-struct vm_area_struct;
+-struct page;
+-struct mm_struct;
+-
+-extern void flush_cache_all(void);
+-extern void flush_cache_mm(struct mm_struct *mm);
+-extern void flush_cache_sigtramp(unsigned long start, unsigned long end);
+-extern void flush_cache_range(struct vm_area_struct *vma, unsigned long start,
+-			      unsigned long end);
+-extern void flush_cache_page(struct vm_area_struct *vma, unsigned long addr, unsigned long pfn);
+-extern void flush_dcache_page(struct page *pg);
+-extern void flush_icache_range(unsigned long start, unsigned long end);
+-extern void flush_icache_user_range(struct vm_area_struct *vma,
+-				    struct page *page, unsigned long addr,
+-				    int len);
+-
+-#define flush_cache_dup_mm(mm)	flush_cache_mm(mm)
+-
+-#define flush_dcache_mmap_lock(mapping)		do { } while (0)
+-#define flush_dcache_mmap_unlock(mapping)	do { } while (0)
+-
+-#define flush_cache_vmap(start, end)		flush_cache_all()
+-#define flush_cache_vunmap(start, end)		flush_cache_all()
+-
+-#define flush_icache_page(vma, page)	do { } while (0)
+-
+-#define copy_to_user_page(vma, page, vaddr, dst, src, len) \
+-	do {							\
+-		flush_cache_page(vma, vaddr, page_to_pfn(page));\
+-		memcpy(dst, src, len);				\
+-		flush_icache_user_range(vma, page, vaddr, len);	\
+-	} while (0)
+-
+-#define copy_from_user_page(vma, page, vaddr, dst, src, len) \
+-	do {							\
+-		flush_cache_page(vma, vaddr, page_to_pfn(page));\
+-		memcpy(dst, src, len);				\
+-	} while (0)
+-
+-#endif /* __ASSEMBLY__ */
+-
+-#endif /* __ASM_SH64_CACHEFLUSH_H */
+-
+diff --git a/include/asm-sh64/cayman.h b/include/asm-sh64/cayman.h
+deleted file mode 100644
+index 7b6b968..0000000
+--- a/include/asm-sh64/cayman.h
++++ /dev/null
+@@ -1,20 +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.
+- *
+- * include/asm-sh64/cayman.h
+- *
+- * Cayman definitions
+- *
+- * Global defintions for the SH5 Cayman board
+- *
+- * Copyright (C) 2002 Stuart Menefy
+- */
+-
+-
+-/* Setup for the SMSC FDC37C935 / LAN91C100FD */
+-#define SMSC_IRQ         IRQ_IRL1
+-
+-/* Setup for PCI Bus 2, which transmits interrupts via the EPLD */
+-#define PCI2_IRQ         IRQ_IRL3
+diff --git a/include/asm-sh64/checksum.h b/include/asm-sh64/checksum.h
+deleted file mode 100644
+index ba594cc..0000000
+--- a/include/asm-sh64/checksum.h
++++ /dev/null
+@@ -1,82 +0,0 @@
+-#ifndef __ASM_SH64_CHECKSUM_H
+-#define __ASM_SH64_CHECKSUM_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.
+- *
+- * include/asm-sh64/checksum.h
+- *
+- * Copyright (C) 2000, 2001  Paolo Alberelli
+- *
+- */
+-
+-#include <asm/registers.h>
+-
+-/*
+- * computes the checksum of a memory block at buff, length len,
+- * and adds in "sum" (32-bit)
+- *
+- * returns a 32-bit number suitable for feeding into itself
+- * or csum_tcpudp_magic
+- *
+- * this function must be called with even lengths, except
+- * for the last fragment, which may be odd
+- *
+- * it's best to have buff aligned on a 32-bit boundary
+- */
+-asmlinkage __wsum csum_partial(const void *buff, int len, __wsum sum);
+-
+-/*
+- *	Note: when you get a NULL pointer exception here this means someone
+- *	passed in an incorrect kernel address to one of these functions.
+- *
+- *	If you use these functions directly please don't forget the
+- *	access_ok().
+- */
+-
+-
+-__wsum csum_partial_copy_nocheck(const void *src, void *dst, int len,
+-				       __wsum sum);
+-
+-__wsum csum_partial_copy_from_user(const void __user *src, void *dst,
+-					 int len, __wsum sum, int *err_ptr);
+-
+-static inline __sum16 csum_fold(__wsum csum)
 -{
--	struct ocfs2_msg_hdr v_hdr;
--	__be32 v_reserved1;
--} __attribute__ ((packed));
+-	u32 sum = (__force u32)csum;
+-        sum = (sum & 0xffff) + (sum >> 16);
+-        sum = (sum & 0xffff) + (sum >> 16);
+-        return (__force __sum16)~sum;
+-}
 -
--/* Responses are given these values to maintain backwards
-- * compatibility with older ocfs2 versions */
--#define OCFS2_RESPONSE_OK		(0)
--#define OCFS2_RESPONSE_BUSY		(-16)
--#define OCFS2_RESPONSE_BAD_MSG		(-22)
+-__sum16 ip_fast_csum(const void *iph, unsigned int ihl);
 -
--struct ocfs2_response_msg
+-__wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr,
+-				 unsigned short len, unsigned short proto,
+-				 __wsum sum);
+-
+-/*
+- * computes the checksum of the TCP/UDP pseudo-header
+- * returns a 16-bit checksum, already complemented
+- */
+-static inline __sum16 csum_tcpudp_magic(__be32 saddr, __be32 daddr,
+-						   unsigned short len,
+-						   unsigned short proto,
+-						   __wsum sum)
 -{
--	struct ocfs2_msg_hdr r_hdr;
--	__be32 r_response;
--} __attribute__ ((packed));
+-	return csum_fold(csum_tcpudp_nofold(saddr,daddr,len,proto,sum));
+-}
 -
--struct ocfs2_vote_work {
--	struct list_head   w_list;
--	struct ocfs2_vote_msg w_msg;
--};
+-/*
+- * this routine is used for miscellaneous IP-like checksums, mainly
+- * in icmp.c
+- */
+-static inline __sum16 ip_compute_csum(const void *buff, int len)
+-{
+-	return csum_fold(csum_partial(buff, len, 0));
+-}
 -
--enum ocfs2_vote_request {
--	OCFS2_VOTE_REQ_INVALID = 0,
--	OCFS2_VOTE_REQ_MOUNT,
--	OCFS2_VOTE_REQ_UMOUNT,
--	OCFS2_VOTE_REQ_LAST
--};
+-#endif /* __ASM_SH64_CHECKSUM_H */
 -
--static inline int ocfs2_is_valid_vote_request(int request)
+diff --git a/include/asm-sh64/cpumask.h b/include/asm-sh64/cpumask.h
+deleted file mode 100644
+index b7b105d..0000000
+--- a/include/asm-sh64/cpumask.h
++++ /dev/null
+@@ -1,6 +0,0 @@
+-#ifndef __ASM_SH64_CPUMASK_H
+-#define __ASM_SH64_CPUMASK_H
+-
+-#include <asm-generic/cpumask.h>
+-
+-#endif /* __ASM_SH64_CPUMASK_H */
+diff --git a/include/asm-sh64/cputime.h b/include/asm-sh64/cputime.h
+deleted file mode 100644
+index 0fd89da..0000000
+--- a/include/asm-sh64/cputime.h
++++ /dev/null
+@@ -1,6 +0,0 @@
+-#ifndef __SH64_CPUTIME_H
+-#define __SH64_CPUTIME_H
+-
+-#include <asm-generic/cputime.h>
+-
+-#endif /* __SH64_CPUTIME_H */
+diff --git a/include/asm-sh64/current.h b/include/asm-sh64/current.h
+deleted file mode 100644
+index 2612243..0000000
+--- a/include/asm-sh64/current.h
++++ /dev/null
+@@ -1,28 +0,0 @@
+-#ifndef __ASM_SH64_CURRENT_H
+-#define __ASM_SH64_CURRENT_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.
+- *
+- * include/asm-sh64/current.h
+- *
+- * Copyright (C) 2000, 2001  Paolo Alberelli
+- * Copyright (C) 2003  Paul Mundt
+- *
+- */
+-
+-#include <linux/thread_info.h>
+-
+-struct task_struct;
+-
+-static __inline__ struct task_struct * get_current(void)
 -{
--	return OCFS2_VOTE_REQ_INVALID < request &&
--		request < OCFS2_VOTE_REQ_LAST;
+-	return current_thread_info()->task;
 -}
 -
--typedef void (*ocfs2_net_response_callback)(void *priv,
--					    struct ocfs2_response_msg *resp);
--struct ocfs2_net_response_cb {
--	ocfs2_net_response_callback	rc_cb;
--	void				*rc_priv;
--};
+-#define current get_current()
 -
--struct ocfs2_net_wait_ctxt {
--	struct list_head        n_list;
--	u32                     n_response_id;
--	wait_queue_head_t       n_event;
--	struct ocfs2_node_map   n_node_map;
--	int                     n_response; /* an agreggate response. 0 if
--					     * all nodes are go, < 0 on any
--					     * negative response from any
--					     * node or network error. */
--	struct ocfs2_net_response_cb *n_callback;
--};
+-#endif /* __ASM_SH64_CURRENT_H */
 -
--static void ocfs2_process_mount_request(struct ocfs2_super *osb,
--					unsigned int node_num)
+diff --git a/include/asm-sh64/delay.h b/include/asm-sh64/delay.h
+deleted file mode 100644
+index 6ae3130..0000000
+--- a/include/asm-sh64/delay.h
++++ /dev/null
+@@ -1,11 +0,0 @@
+-#ifndef __ASM_SH64_DELAY_H
+-#define __ASM_SH64_DELAY_H
+-
+-extern void __delay(int loops);
+-extern void __udelay(unsigned long long usecs, unsigned long lpj);
+-extern void __ndelay(unsigned long long nsecs, unsigned long lpj);
+-extern void udelay(unsigned long usecs);
+-extern void ndelay(unsigned long nsecs);
+-
+-#endif /* __ASM_SH64_DELAY_H */
+-
+diff --git a/include/asm-sh64/device.h b/include/asm-sh64/device.h
+deleted file mode 100644
+index d8f9872..0000000
+--- a/include/asm-sh64/device.h
++++ /dev/null
+@@ -1,7 +0,0 @@
+-/*
+- * Arch specific extensions to struct device
+- *
+- * This file is released under the GPLv2
+- */
+-#include <asm-generic/device.h>
+-
+diff --git a/include/asm-sh64/div64.h b/include/asm-sh64/div64.h
+deleted file mode 100644
+index f758695..0000000
+--- a/include/asm-sh64/div64.h
++++ /dev/null
+@@ -1,6 +0,0 @@
+-#ifndef __ASM_SH64_DIV64_H
+-#define __ASM_SH64_DIV64_H
+-
+-#include <asm-generic/div64.h>
+-
+-#endif /* __ASM_SH64_DIV64_H */
+diff --git a/include/asm-sh64/dma-mapping.h b/include/asm-sh64/dma-mapping.h
+deleted file mode 100644
+index 18f8dd6..0000000
+--- a/include/asm-sh64/dma-mapping.h
++++ /dev/null
+@@ -1,194 +0,0 @@
+-#ifndef __ASM_SH_DMA_MAPPING_H
+-#define __ASM_SH_DMA_MAPPING_H
+-
+-#include <linux/mm.h>
+-#include <linux/scatterlist.h>
+-#include <asm/io.h>
+-
+-struct pci_dev;
+-extern void *consistent_alloc(struct pci_dev *hwdev, size_t size,
+-				    dma_addr_t *dma_handle);
+-extern void consistent_free(struct pci_dev *hwdev, size_t size,
+-				  void *vaddr, dma_addr_t dma_handle);
+-
+-#define dma_supported(dev, mask)	(1)
+-
+-static inline int dma_set_mask(struct device *dev, u64 mask)
 -{
--	mlog(0, "MOUNT vote from node %u\n", node_num);
--	/* The other node only sends us this message when he has an EX
--	 * on the superblock, so our recovery threads (if having been
--	 * launched) are waiting on it.*/
--	ocfs2_recovery_map_clear(osb, node_num);
--	ocfs2_node_map_set_bit(osb, &osb->mounted_map, node_num);
+-	if (!dev->dma_mask || !dma_supported(dev, mask))
+-		return -EIO;
 -
--	/* We clear the umount map here because a node may have been
--	 * previously mounted, safely unmounted but never stopped
--	 * heartbeating - in which case we'd have a stale entry. */
--	ocfs2_node_map_clear_bit(osb, &osb->umount_map, node_num);
+-	*dev->dma_mask = mask;
+-
+-	return 0;
+-}
+-
+-static inline void *dma_alloc_coherent(struct device *dev, size_t size,
+-			 dma_addr_t *dma_handle, gfp_t flag)
+-{
+-	return consistent_alloc(NULL, size, dma_handle);
+-}
+-
+-static inline void dma_free_coherent(struct device *dev, size_t size,
+-		       void *vaddr, dma_addr_t dma_handle)
+-{
+-	consistent_free(NULL, size, vaddr, dma_handle);
+-}
+-
+-#define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f)
+-#define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h)
+-#define dma_is_consistent(d, h) (1)
+-
+-static inline void dma_cache_sync(struct device *dev, void *vaddr, size_t size,
+-				  enum dma_data_direction dir)
+-{
+-	unsigned long start = (unsigned long) vaddr;
+-	unsigned long s = start & L1_CACHE_ALIGN_MASK;
+-	unsigned long e = (start + size) & L1_CACHE_ALIGN_MASK;
+-
+-	for (; s <= e; s += L1_CACHE_BYTES)
+-		asm volatile ("ocbp	%0, 0" : : "r" (s));
+-}
+-
+-static inline dma_addr_t dma_map_single(struct device *dev,
+-					void *ptr, size_t size,
+-					enum dma_data_direction dir)
+-{
+-#if defined(CONFIG_PCI) && !defined(CONFIG_SH_PCIDMA_NONCOHERENT)
+-	if (dev->bus == &pci_bus_type)
+-		return virt_to_phys(ptr);
+-#endif
+-	dma_cache_sync(dev, ptr, size, dir);
+-
+-	return virt_to_phys(ptr);
+-}
+-
+-#define dma_unmap_single(dev, addr, size, dir)	do { } while (0)
+-
+-static inline int dma_map_sg(struct device *dev, struct scatterlist *sg,
+-			     int nents, enum dma_data_direction dir)
+-{
+-	int i;
+-
+-	for (i = 0; i < nents; i++) {
+-#if !defined(CONFIG_PCI) || defined(CONFIG_SH_PCIDMA_NONCOHERENT)
+-		dma_cache_sync(dev, sg_virt(&sg[i]), sg[i].length, dir);
+-#endif
+-		sg[i].dma_address = sg_phys(&sg[i]);
+-	}
+-
+-	return nents;
+-}
+-
+-#define dma_unmap_sg(dev, sg, nents, dir)	do { } while (0)
+-
+-static inline dma_addr_t dma_map_page(struct device *dev, struct page *page,
+-				      unsigned long offset, size_t size,
+-				      enum dma_data_direction dir)
+-{
+-	return dma_map_single(dev, page_address(page) + offset, size, dir);
+-}
+-
+-static inline void dma_unmap_page(struct device *dev, dma_addr_t dma_address,
+-				  size_t size, enum dma_data_direction dir)
+-{
+-	dma_unmap_single(dev, dma_address, size, dir);
+-}
+-
+-static inline void dma_sync_single(struct device *dev, dma_addr_t dma_handle,
+-				   size_t size, enum dma_data_direction dir)
+-{
+-#if defined(CONFIG_PCI) && !defined(CONFIG_SH_PCIDMA_NONCOHERENT)
+-	if (dev->bus == &pci_bus_type)
+-		return;
+-#endif
+-	dma_cache_sync(dev, phys_to_virt(dma_handle), size, dir);
+-}
+-
+-static inline void dma_sync_single_range(struct device *dev,
+-					 dma_addr_t dma_handle,
+-					 unsigned long offset, size_t size,
+-					 enum dma_data_direction dir)
+-{
+-#if defined(CONFIG_PCI) && !defined(CONFIG_SH_PCIDMA_NONCOHERENT)
+-	if (dev->bus == &pci_bus_type)
+-		return;
+-#endif
+-	dma_cache_sync(dev, phys_to_virt(dma_handle) + offset, size, dir);
+-}
+-
+-static inline void dma_sync_sg(struct device *dev, struct scatterlist *sg,
+-			       int nelems, enum dma_data_direction dir)
+-{
+-	int i;
+-
+-	for (i = 0; i < nelems; i++) {
+-#if !defined(CONFIG_PCI) || defined(CONFIG_SH_PCIDMA_NONCOHERENT)
+-		dma_cache_sync(dev, sg_virt(&sg[i]), sg[i].length, dir);
+-#endif
+-		sg[i].dma_address = sg_phys(&sg[i]);
+-	}
+-}
+-
+-static inline void dma_sync_single_for_cpu(struct device *dev,
+-					   dma_addr_t dma_handle, size_t size,
+-					   enum dma_data_direction dir)
+-{
+-	dma_sync_single(dev, dma_handle, size, dir);
+-}
+-
+-static inline void dma_sync_single_for_device(struct device *dev,
+-					   dma_addr_t dma_handle, size_t size,
+-					   enum dma_data_direction dir)
+-{
+-	dma_sync_single(dev, dma_handle, size, dir);
+-}
+-
+-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)
+-{
+-	dma_sync_single_for_cpu(dev, dma_handle+offset, size, direction);
+-}
+-
+-static inline void dma_sync_single_range_for_device(struct device *dev,
+-						    dma_addr_t dma_handle,
+-						    unsigned long offset,
+-						    size_t size,
+-						    enum dma_data_direction direction)
+-{
+-	dma_sync_single_for_device(dev, dma_handle+offset, size, direction);
+-}
+-
+-static inline void dma_sync_sg_for_cpu(struct device *dev,
+-				       struct scatterlist *sg, int nelems,
+-				       enum dma_data_direction dir)
+-{
+-	dma_sync_sg(dev, sg, nelems, dir);
+-}
+-
+-static inline void dma_sync_sg_for_device(struct device *dev,
+-				       struct scatterlist *sg, int nelems,
+-				       enum dma_data_direction dir)
+-{
+-	dma_sync_sg(dev, sg, nelems, dir);
+-}
+-
+-static inline int dma_get_cache_alignment(void)
+-{
+-	/*
+-	 * Each processor family will define its own L1_CACHE_SHIFT,
+-	 * L1_CACHE_BYTES wraps to this, so this is always safe.
+-	 */
+-	return L1_CACHE_BYTES;
+-}
+-
+-static inline int dma_mapping_error(dma_addr_t dma_addr)
+-{
+-	return dma_addr == 0;
+-}
+-
+-#endif /* __ASM_SH_DMA_MAPPING_H */
+-
+diff --git a/include/asm-sh64/dma.h b/include/asm-sh64/dma.h
+deleted file mode 100644
+index e701f39..0000000
+--- a/include/asm-sh64/dma.h
++++ /dev/null
+@@ -1,41 +0,0 @@
+-#ifndef __ASM_SH64_DMA_H
+-#define __ASM_SH64_DMA_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.
+- *
+- * include/asm-sh64/dma.h
+- *
+- * Copyright (C) 2000, 2001  Paolo Alberelli
+- * Copyright (C) 2003  Paul Mundt
+- *
+- */
+-
+-#include <linux/mm.h>
+-#include <asm/io.h>
+-#include <asm/pgtable.h>
+-
+-#define MAX_DMA_CHANNELS	4
+-
+-/*
+- * SH5 can DMA in any memory area.
+- *
+- * The static definition is dodgy because it should limit
+- * the highest DMA-able address based on the actual
+- * Physical memory available. This is actually performed
+- * at run time in defining the memory allowed to DMA_ZONE.
+- */
+-#define MAX_DMA_ADDRESS		~(NPHYS_MASK)
+-
+-#define DMA_MODE_READ		0
+-#define DMA_MODE_WRITE		1
+-
+-#ifdef CONFIG_PCI
+-extern int isa_dma_bridge_buggy;
+-#else
+-#define isa_dma_bridge_buggy 	(0)
+-#endif
+-
+-#endif /* __ASM_SH64_DMA_H */
+diff --git a/include/asm-sh64/elf.h b/include/asm-sh64/elf.h
+deleted file mode 100644
+index f994286..0000000
+--- a/include/asm-sh64/elf.h
++++ /dev/null
+@@ -1,107 +0,0 @@
+-#ifndef __ASM_SH64_ELF_H
+-#define __ASM_SH64_ELF_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.
+- *
+- * include/asm-sh64/elf.h
+- *
+- * Copyright (C) 2000, 2001  Paolo Alberelli
+- *
+- */
+-
+-/*
+- * ELF register definitions..
+- */
+-
+-#include <asm/ptrace.h>
+-#include <asm/user.h>
+-#include <asm/byteorder.h>
+-
+-typedef unsigned long elf_greg_t;
+-
+-#define ELF_NGREG (sizeof (struct pt_regs) / sizeof(elf_greg_t))
+-typedef elf_greg_t elf_gregset_t[ELF_NGREG];
+-
+-typedef struct user_fpu_struct elf_fpregset_t;
+-
+-/*
+- * This is used to ensure we don't load something for the wrong architecture.
+- */
+-#define elf_check_arch(x) ( (x)->e_machine == EM_SH )
+-
+-/*
+- * These are used to set parameters in the core dumps.
+- */
+-#define ELF_CLASS	ELFCLASS32
+-#ifdef __LITTLE_ENDIAN__
+-#define ELF_DATA	ELFDATA2LSB
+-#else
+-#define ELF_DATA	ELFDATA2MSB
+-#endif
+-#define ELF_ARCH	EM_SH
+-
+-#define USE_ELF_CORE_DUMP
+-#define ELF_EXEC_PAGESIZE	4096
+-
+-/* This is the location that an ET_DYN program is loaded if exec'ed.  Typical
+-   use of this is to invoke "./ld.so someprog" to test out a new version of
+-   the loader.  We need to make sure that it is out of the way of the program
+-   that it will "exec", and that there is sufficient room for the brk.  */
+-
+-#define ELF_ET_DYN_BASE         (2 * TASK_SIZE / 3)
+-
+-#define	R_SH_DIR32		1
+-#define	R_SH_REL32		2
+-#define	R_SH_IMM_LOW16		246
+-#define	R_SH_IMM_LOW16_PCREL	247
+-#define	R_SH_IMM_MEDLOW16	248
+-#define	R_SH_IMM_MEDLOW16_PCREL	249
+-
+-#define ELF_CORE_COPY_REGS(_dest,_regs)				\
+-	memcpy((char *) &_dest, (char *) _regs,			\
+-	       sizeof(struct pt_regs));
+-
+-/* This yields a mask that user programs can use to figure out what
+-   instruction set this CPU supports.  This could be done in user space,
+-   but it's not easy, and we've already done it here.  */
+-
+-#define ELF_HWCAP	(0)
+-
+-/* This yields a string that ld.so will use to load implementation
+-   specific libraries for optimization.  This is more specific in
+-   intent than poking at uname or /proc/cpuinfo.
+-
+-   For the moment, we have only optimizations for the Intel generations,
+-   but that could change... */
+-
+-#define ELF_PLATFORM  (NULL)
+-
+-#define ELF_PLAT_INIT(_r, load_addr) \
+-  do { _r->regs[0]=0; _r->regs[1]=0; _r->regs[2]=0; _r->regs[3]=0; \
+-       _r->regs[4]=0; _r->regs[5]=0; _r->regs[6]=0; _r->regs[7]=0; \
+-       _r->regs[8]=0; _r->regs[9]=0; _r->regs[10]=0; _r->regs[11]=0; \
+-       _r->regs[12]=0; _r->regs[13]=0; _r->regs[14]=0; _r->regs[15]=0; \
+-       _r->regs[16]=0; _r->regs[17]=0; _r->regs[18]=0; _r->regs[19]=0; \
+-       _r->regs[20]=0; _r->regs[21]=0; _r->regs[22]=0; _r->regs[23]=0; \
+-       _r->regs[24]=0; _r->regs[25]=0; _r->regs[26]=0; _r->regs[27]=0; \
+-       _r->regs[28]=0; _r->regs[29]=0; _r->regs[30]=0; _r->regs[31]=0; \
+-       _r->regs[32]=0; _r->regs[33]=0; _r->regs[34]=0; _r->regs[35]=0; \
+-       _r->regs[36]=0; _r->regs[37]=0; _r->regs[38]=0; _r->regs[39]=0; \
+-       _r->regs[40]=0; _r->regs[41]=0; _r->regs[42]=0; _r->regs[43]=0; \
+-       _r->regs[44]=0; _r->regs[45]=0; _r->regs[46]=0; _r->regs[47]=0; \
+-       _r->regs[48]=0; _r->regs[49]=0; _r->regs[50]=0; _r->regs[51]=0; \
+-       _r->regs[52]=0; _r->regs[53]=0; _r->regs[54]=0; _r->regs[55]=0; \
+-       _r->regs[56]=0; _r->regs[57]=0; _r->regs[58]=0; _r->regs[59]=0; \
+-       _r->regs[60]=0; _r->regs[61]=0; _r->regs[62]=0; \
+-       _r->tregs[0]=0; _r->tregs[1]=0; _r->tregs[2]=0; _r->tregs[3]=0; \
+-       _r->tregs[4]=0; _r->tregs[5]=0; _r->tregs[6]=0; _r->tregs[7]=0; \
+-       _r->sr = SR_FD | SR_MMU; } while (0)
+-
+-#ifdef __KERNEL__
+-#define SET_PERSONALITY(ex, ibcs2) set_personality(PER_LINUX_32BIT)
+-#endif
+-
+-#endif /* __ASM_SH64_ELF_H */
+diff --git a/include/asm-sh64/emergency-restart.h b/include/asm-sh64/emergency-restart.h
+deleted file mode 100644
+index 108d8c4..0000000
+--- a/include/asm-sh64/emergency-restart.h
++++ /dev/null
+@@ -1,6 +0,0 @@
+-#ifndef _ASM_EMERGENCY_RESTART_H
+-#define _ASM_EMERGENCY_RESTART_H
+-
+-#include <asm-generic/emergency-restart.h>
+-
+-#endif /* _ASM_EMERGENCY_RESTART_H */
+diff --git a/include/asm-sh64/errno.h b/include/asm-sh64/errno.h
+deleted file mode 100644
+index 57b46d4..0000000
+--- a/include/asm-sh64/errno.h
++++ /dev/null
+@@ -1,6 +0,0 @@
+-#ifndef __ASM_SH64_ERRNO_H
+-#define __ASM_SH64_ERRNO_H
+-
+-#include <asm-generic/errno.h>
+-
+-#endif /* __ASM_SH64_ERRNO_H */
+diff --git a/include/asm-sh64/fb.h b/include/asm-sh64/fb.h
+deleted file mode 100644
+index d92e99c..0000000
+--- a/include/asm-sh64/fb.h
++++ /dev/null
+@@ -1,19 +0,0 @@
+-#ifndef _ASM_FB_H_
+-#define _ASM_FB_H_
+-
+-#include <linux/fb.h>
+-#include <linux/fs.h>
+-#include <asm/page.h>
+-
+-static inline void fb_pgprotect(struct file *file, struct vm_area_struct *vma,
+-				unsigned long off)
+-{
+-	vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+-}
+-
+-static inline int fb_is_primary_device(struct fb_info *info)
+-{
+-	return 0;
 -}
 -
--static void ocfs2_process_umount_request(struct ocfs2_super *osb,
--					 unsigned int node_num)
+-#endif /* _ASM_FB_H_ */
+diff --git a/include/asm-sh64/fcntl.h b/include/asm-sh64/fcntl.h
+deleted file mode 100644
+index 744dd79..0000000
+--- a/include/asm-sh64/fcntl.h
++++ /dev/null
+@@ -1 +0,0 @@
+-#include <asm-sh/fcntl.h>
+diff --git a/include/asm-sh64/futex.h b/include/asm-sh64/futex.h
+deleted file mode 100644
+index 6a332a9..0000000
+--- a/include/asm-sh64/futex.h
++++ /dev/null
+@@ -1,6 +0,0 @@
+-#ifndef _ASM_FUTEX_H
+-#define _ASM_FUTEX_H
+-
+-#include <asm-generic/futex.h>
+-
+-#endif
+diff --git a/include/asm-sh64/gpio.h b/include/asm-sh64/gpio.h
+deleted file mode 100644
+index 6bc5a13..0000000
+--- a/include/asm-sh64/gpio.h
++++ /dev/null
+@@ -1,8 +0,0 @@
+-#ifndef __ASM_SH64_GPIO_H
+-#define __ASM_SH64_GPIO_H
+-
+-/*
+- * This is just a stub, so that every arch using sh-sci has a gpio.h
+- */
+-
+-#endif /* __ASM_SH64_GPIO_H */
+diff --git a/include/asm-sh64/hardirq.h b/include/asm-sh64/hardirq.h
+deleted file mode 100644
+index 555fd7a..0000000
+--- a/include/asm-sh64/hardirq.h
++++ /dev/null
+@@ -1,18 +0,0 @@
+-#ifndef __ASM_SH64_HARDIRQ_H
+-#define __ASM_SH64_HARDIRQ_H
+-
+-#include <linux/threads.h>
+-#include <linux/irq.h>
+-
+-/* entry.S is sensitive to the offsets of these fields */
+-typedef struct {
+-	unsigned int __softirq_pending;
+-} ____cacheline_aligned irq_cpustat_t;
+-
+-#include <linux/irq_cpustat.h>	/* Standard mappings for irq_cpustat_t above */
+-
+-/* arch/sh64/kernel/irq.c */
+-extern void ack_bad_irq(unsigned int irq);
+-
+-#endif /* __ASM_SH64_HARDIRQ_H */
+-
+diff --git a/include/asm-sh64/hardware.h b/include/asm-sh64/hardware.h
+deleted file mode 100644
+index 931c1ad..0000000
+--- a/include/asm-sh64/hardware.h
++++ /dev/null
+@@ -1,22 +0,0 @@
+-#ifndef __ASM_SH64_HARDWARE_H
+-#define __ASM_SH64_HARDWARE_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.
+- *
+- * include/asm-sh64/hardware.h
+- *
+- * Copyright (C) 2002 Stuart Menefy
+- * Copyright (C) 2003 Paul Mundt
+- *
+- * Defitions of the locations of registers in the physical address space.
+- */
+-
+-#define	PHYS_PERIPHERAL_BLOCK	0x09000000
+-#define PHYS_DMAC_BLOCK		0x0e000000
+-#define PHYS_PCI_BLOCK		0x60000000
+-#define PHYS_EMI_BLOCK		0xff000000
+-
+-#endif /* __ASM_SH64_HARDWARE_H */
+diff --git a/include/asm-sh64/hw_irq.h b/include/asm-sh64/hw_irq.h
+deleted file mode 100644
+index ebb3908..0000000
+--- a/include/asm-sh64/hw_irq.h
++++ /dev/null
+@@ -1,15 +0,0 @@
+-#ifndef __ASM_SH64_HW_IRQ_H
+-#define __ASM_SH64_HW_IRQ_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.
+- *
+- * include/asm-sh64/hw_irq.h
+- *
+- * Copyright (C) 2000, 2001  Paolo Alberelli
+- *
+- */
+-
+-#endif /* __ASM_SH64_HW_IRQ_H */
+diff --git a/include/asm-sh64/ide.h b/include/asm-sh64/ide.h
+deleted file mode 100644
+index b6e31e8..0000000
+--- a/include/asm-sh64/ide.h
++++ /dev/null
+@@ -1,29 +0,0 @@
+-/*
+- *  linux/include/asm-sh64/ide.h
+- *
+- *  Copyright (C) 1994-1996  Linus Torvalds & authors
+- *
+- *  sh64 version by Richard Curnow & Paul Mundt
+- */
+-
+-/*
+- *  This file contains the sh64 architecture specific IDE code.
+- */
+-
+-#ifndef __ASM_SH64_IDE_H
+-#define __ASM_SH64_IDE_H
+-
+-#ifdef __KERNEL__
+-
+-
+-/* Without this, the initialisation of PCI IDE cards end up calling
+- * ide_init_hwif_ports, which won't work. */
+-#ifdef CONFIG_BLK_DEV_IDEPCI
+-#define ide_default_io_ctl(base)	(0)
+-#endif
+-
+-#include <asm-generic/ide_iops.h>
+-
+-#endif /* __KERNEL__ */
+-
+-#endif /* __ASM_SH64_IDE_H */
+diff --git a/include/asm-sh64/io.h b/include/asm-sh64/io.h
+deleted file mode 100644
+index 7bd7314..0000000
+--- a/include/asm-sh64/io.h
++++ /dev/null
+@@ -1,196 +0,0 @@
+-#ifndef __ASM_SH64_IO_H
+-#define __ASM_SH64_IO_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.
+- *
+- * include/asm-sh64/io.h
+- *
+- * Copyright (C) 2000, 2001  Paolo Alberelli
+- * Copyright (C) 2003  Paul Mundt
+- *
+- */
+-
+-/*
+- * Convention:
+- *    read{b,w,l}/write{b,w,l} are for PCI,
+- *    while in{b,w,l}/out{b,w,l} are for ISA
+- * These may (will) be platform specific function.
+- *
+- * In addition, we have
+- *   ctrl_in{b,w,l}/ctrl_out{b,w,l} for SuperH specific I/O.
+- * which are processor specific. Address should be the result of
+- * onchip_remap();
+- */
+-
+-#include <linux/compiler.h>
+-#include <asm/cache.h>
+-#include <asm/system.h>
+-#include <asm/page.h>
+-#include <asm-generic/iomap.h>
+-
+-/*
+- * Nothing overly special here.. instead of doing the same thing
+- * over and over again, we just define a set of sh64_in/out functions
+- * with an implicit size. The traditional read{b,w,l}/write{b,w,l}
+- * mess is wrapped to this, as are the SH-specific ctrl_in/out routines.
+- */
+-static inline unsigned char sh64_in8(const volatile void __iomem *addr)
 -{
--	mlog(0, "UMOUNT vote from node %u\n", node_num);
--	ocfs2_node_map_clear_bit(osb, &osb->mounted_map, node_num);
--	ocfs2_node_map_set_bit(osb, &osb->umount_map, node_num);
+-	return *(volatile unsigned char __force *)addr;
 -}
 -
--static void ocfs2_process_vote(struct ocfs2_super *osb,
--			       struct ocfs2_vote_msg *msg)
+-static inline unsigned short sh64_in16(const volatile void __iomem *addr)
 -{
--	int net_status, vote_response;
--	unsigned int node_num;
--	u64 blkno;
--	enum ocfs2_vote_request request;
--	struct ocfs2_msg_hdr *hdr = &msg->v_hdr;
--	struct ocfs2_response_msg response;
--
--	/* decode the network mumbo jumbo into local variables. */
--	request = be32_to_cpu(hdr->h_request);
--	blkno = be64_to_cpu(hdr->h_blkno);
--	node_num = be32_to_cpu(hdr->h_node_num);
--
--	mlog(0, "processing vote: request = %u, blkno = %llu, node_num = %u\n",
--	     request, (unsigned long long)blkno, node_num);
+-	return *(volatile unsigned short __force *)addr;
+-}
 -
--	if (!ocfs2_is_valid_vote_request(request)) {
--		mlog(ML_ERROR, "Invalid vote request %d from node %u\n",
--		     request, node_num);
--		vote_response = OCFS2_RESPONSE_BAD_MSG;
--		goto respond;
--	}
+-static inline unsigned int sh64_in32(const volatile void __iomem *addr)
+-{
+-	return *(volatile unsigned int __force *)addr;
+-}
 -
--	vote_response = OCFS2_RESPONSE_OK;
+-static inline unsigned long long sh64_in64(const volatile void __iomem *addr)
+-{
+-	return *(volatile unsigned long long __force *)addr;
+-}
 -
--	switch (request) {
--	case OCFS2_VOTE_REQ_UMOUNT:
--		ocfs2_process_umount_request(osb, node_num);
--		goto respond;
--	case OCFS2_VOTE_REQ_MOUNT:
--		ocfs2_process_mount_request(osb, node_num);
--		goto respond;
--	default:
--		/* avoids a gcc warning */
--		break;
--	}
+-static inline void sh64_out8(unsigned char b, volatile void __iomem *addr)
+-{
+-	*(volatile unsigned char __force *)addr = b;
+-	wmb();
+-}
 -
--respond:
--	/* Response struture is small so we just put it on the stack
--	 * and stuff it inline. */
--	memset(&response, 0, sizeof(struct ocfs2_response_msg));
--	response.r_hdr.h_response_id = hdr->h_response_id;
--	response.r_hdr.h_blkno = hdr->h_blkno;
--	response.r_hdr.h_generation = hdr->h_generation;
--	response.r_hdr.h_node_num = cpu_to_be32(osb->node_num);
--	response.r_response = cpu_to_be32(vote_response);
+-static inline void sh64_out16(unsigned short b, volatile void __iomem *addr)
+-{
+-	*(volatile unsigned short __force *)addr = b;
+-	wmb();
+-}
 -
--	net_status = o2net_send_message(OCFS2_MESSAGE_TYPE_RESPONSE,
--					osb->net_key,
--					&response,
--					sizeof(struct ocfs2_response_msg),
--					node_num,
--					NULL);
--	/* We still want to error print for ENOPROTOOPT here. The
--	 * sending node shouldn't have unregistered his net handler
--	 * without sending an unmount vote 1st */
--	if (net_status < 0
--	    && net_status != -ETIMEDOUT
--	    && net_status != -ENOTCONN)
--		mlog(ML_ERROR, "message to node %u fails with error %d!\n",
--		     node_num, net_status);
+-static inline void sh64_out32(unsigned int b, volatile void __iomem *addr)
+-{
+-	*(volatile unsigned int __force *)addr = b;
+-	wmb();
 -}
 -
--static void ocfs2_vote_thread_do_work(struct ocfs2_super *osb)
+-static inline void sh64_out64(unsigned long long b, volatile void __iomem *addr)
 -{
--	unsigned long processed;
--	struct ocfs2_lock_res *lockres;
--	struct ocfs2_vote_work *work;
+-	*(volatile unsigned long long __force *)addr = b;
+-	wmb();
+-}
 -
--	mlog_entry_void();
+-#define readb(addr)		sh64_in8(addr)
+-#define readw(addr)		sh64_in16(addr)
+-#define readl(addr)		sh64_in32(addr)
+-#define readb_relaxed(addr)	sh64_in8(addr)
+-#define readw_relaxed(addr)	sh64_in16(addr)
+-#define readl_relaxed(addr)	sh64_in32(addr)
 -
--	spin_lock(&osb->vote_task_lock);
--	/* grab this early so we know to try again if a state change and
--	 * wake happens part-way through our work  */
--	osb->vote_work_sequence = osb->vote_wake_sequence;
+-#define writeb(b, addr)		sh64_out8(b, addr)
+-#define writew(b, addr)		sh64_out16(b, addr)
+-#define writel(b, addr)		sh64_out32(b, addr)
 -
--	processed = osb->blocked_lock_count;
--	while (processed) {
--		BUG_ON(list_empty(&osb->blocked_lock_list));
+-#define ctrl_inb(addr)		sh64_in8(ioport_map(addr, 1))
+-#define ctrl_inw(addr)		sh64_in16(ioport_map(addr, 2))
+-#define ctrl_inl(addr)		sh64_in32(ioport_map(addr, 4))
 -
--		lockres = list_entry(osb->blocked_lock_list.next,
--				     struct ocfs2_lock_res, l_blocked_list);
--		list_del_init(&lockres->l_blocked_list);
--		osb->blocked_lock_count--;
--		spin_unlock(&osb->vote_task_lock);
+-#define ctrl_outb(b, addr)	sh64_out8(b, ioport_map(addr, 1))
+-#define ctrl_outw(b, addr)	sh64_out16(b, ioport_map(addr, 2))
+-#define ctrl_outl(b, addr)	sh64_out32(b, ioport_map(addr, 4))
 -
--		BUG_ON(!processed);
--		processed--;
+-#define ioread8(addr)		sh64_in8(addr)
+-#define ioread16(addr)		sh64_in16(addr)
+-#define ioread32(addr)		sh64_in32(addr)
+-#define iowrite8(b, addr)	sh64_out8(b, addr)
+-#define iowrite16(b, addr)	sh64_out16(b, addr)
+-#define iowrite32(b, addr)	sh64_out32(b, addr)
 -
--		ocfs2_process_blocked_lock(osb, lockres);
+-#define inb(addr)		ctrl_inb(addr)
+-#define inw(addr)		ctrl_inw(addr)
+-#define inl(addr)		ctrl_inl(addr)
+-#define outb(b, addr)		ctrl_outb(b, addr)
+-#define outw(b, addr)		ctrl_outw(b, addr)
+-#define outl(b, addr)		ctrl_outl(b, addr)
 -
--		spin_lock(&osb->vote_task_lock);
--	}
+-void outsw(unsigned long port, const void *addr, unsigned long count);
+-void insw(unsigned long port, void *addr, unsigned long count);
+-void outsl(unsigned long port, const void *addr, unsigned long count);
+-void insl(unsigned long port, void *addr, unsigned long count);
 -
--	while (osb->vote_count) {
--		BUG_ON(list_empty(&osb->vote_list));
--		work = list_entry(osb->vote_list.next,
--				  struct ocfs2_vote_work, w_list);
--		list_del(&work->w_list);
--		osb->vote_count--;
--		spin_unlock(&osb->vote_task_lock);
+-#define inb_p(addr)    inb(addr)
+-#define inw_p(addr)    inw(addr)
+-#define inl_p(addr)    inl(addr)
+-#define outb_p(x,addr) outb(x,addr)
+-#define outw_p(x,addr) outw(x,addr)
+-#define outl_p(x,addr) outl(x,addr)
 -
--		ocfs2_process_vote(osb, &work->w_msg);
--		kfree(work);
+-#define __raw_readb		readb
+-#define __raw_readw		readw
+-#define __raw_readl		readl
+-#define __raw_writeb		writeb
+-#define __raw_writew		writew
+-#define __raw_writel		writel
 -
--		spin_lock(&osb->vote_task_lock);
--	}
--	spin_unlock(&osb->vote_task_lock);
+-void memcpy_toio(void __iomem *to, const void *from, long count);
+-void memcpy_fromio(void *to, void __iomem *from, long count);
 -
--	mlog_exit_void();
--}
+-#define mmiowb()
 -
--static int ocfs2_vote_thread_lists_empty(struct ocfs2_super *osb)
--{
--	int empty = 0;
+-#ifdef __KERNEL__
 -
--	spin_lock(&osb->vote_task_lock);
--	if (list_empty(&osb->blocked_lock_list) &&
--	    list_empty(&osb->vote_list))
--		empty = 1;
+-#ifdef CONFIG_SH_CAYMAN
+-extern unsigned long smsc_superio_virt;
+-#endif
+-#ifdef CONFIG_PCI
+-extern unsigned long pciio_virt;
+-#endif
 -
--	spin_unlock(&osb->vote_task_lock);
--	return empty;
+-#define IO_SPACE_LIMIT 0xffffffff
+-
+-/*
+- * Change virtual addresses to physical addresses and vv.
+- * These are trivial on the 1:1 Linux/SuperH mapping
+- */
+-static inline unsigned long virt_to_phys(volatile void * address)
+-{
+-	return __pa(address);
 -}
 -
--static int ocfs2_vote_thread_should_wake(struct ocfs2_super *osb)
+-static inline void * phys_to_virt(unsigned long address)
 -{
--	int should_wake = 0;
+-	return __va(address);
+-}
 -
--	spin_lock(&osb->vote_task_lock);
--	if (osb->vote_work_sequence != osb->vote_wake_sequence)
--		should_wake = 1;
--	spin_unlock(&osb->vote_task_lock);
+-extern void * __ioremap(unsigned long phys_addr, unsigned long size,
+-			unsigned long flags);
 -
--	return should_wake;
+-static inline void * ioremap(unsigned long phys_addr, unsigned long size)
+-{
+-	return __ioremap(phys_addr, size, 1);
 -}
 -
--int ocfs2_vote_thread(void *arg)
+-static inline void * ioremap_nocache (unsigned long phys_addr, unsigned long size)
 -{
--	int status = 0;
--	struct ocfs2_super *osb = arg;
+-	return __ioremap(phys_addr, size, 0);
+-}
 -
--	/* only quit once we've been asked to stop and there is no more
--	 * work available */
--	while (!(kthread_should_stop() &&
--		 ocfs2_vote_thread_lists_empty(osb))) {
+-extern void iounmap(void *addr);
 -
--		wait_event_interruptible(osb->vote_event,
--					 ocfs2_vote_thread_should_wake(osb) ||
--					 kthread_should_stop());
+-unsigned long onchip_remap(unsigned long addr, unsigned long size, const char* name);
+-extern void onchip_unmap(unsigned long vaddr);
 -
--		mlog(0, "vote_thread: awoken\n");
+-/*
+- * Convert a physical pointer to a virtual kernel pointer for /dev/mem
+- * access
+- */
+-#define xlate_dev_mem_ptr(p)	__va(p)
 -
--		ocfs2_vote_thread_do_work(osb);
--	}
+-/*
+- * Convert a virtual cached pointer to an uncached pointer
+- */
+-#define xlate_dev_kmem_ptr(p)	p
 -
--	osb->vote_task = NULL;
--	return status;
--}
+-#endif /* __KERNEL__ */
+-#endif /* __ASM_SH64_IO_H */
+diff --git a/include/asm-sh64/ioctl.h b/include/asm-sh64/ioctl.h
+deleted file mode 100644
+index b279fe0..0000000
+--- a/include/asm-sh64/ioctl.h
++++ /dev/null
+@@ -1 +0,0 @@
+-#include <asm-generic/ioctl.h>
+diff --git a/include/asm-sh64/ioctls.h b/include/asm-sh64/ioctls.h
+deleted file mode 100644
+index 6b0c04f..0000000
+--- a/include/asm-sh64/ioctls.h
++++ /dev/null
+@@ -1,116 +0,0 @@
+-#ifndef __ASM_SH64_IOCTLS_H
+-#define __ASM_SH64_IOCTLS_H
 -
--static struct ocfs2_net_wait_ctxt *ocfs2_new_net_wait_ctxt(unsigned int response_id)
--{
--	struct ocfs2_net_wait_ctxt *w;
+-/*
+- * 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/asm-sh64/ioctls.h
+- *
+- * Copyright (C) 2000, 2001  Paolo Alberelli
+- * Copyright (C) 2004  Richard Curnow
+- *
+- */
 -
--	w = kzalloc(sizeof(*w), GFP_NOFS);
--	if (!w) {
--		mlog_errno(-ENOMEM);
--		goto bail;
--	}
+-#include <asm/ioctl.h>
 -
--	INIT_LIST_HEAD(&w->n_list);
--	init_waitqueue_head(&w->n_event);
--	ocfs2_node_map_init(&w->n_node_map);
--	w->n_response_id = response_id;
--	w->n_callback = NULL;
--bail:
--	return w;
--}
+-#define FIOCLEX		0x6601		/* _IO('f', 1) */
+-#define FIONCLEX	0x6602		/* _IO('f', 2) */
+-#define FIOASYNC	0x4004667d	/* _IOW('f', 125, int) */
+-#define FIONBIO		0x4004667e	/* _IOW('f', 126, int) */
+-#define FIONREAD	0x8004667f	/* _IOW('f', 127, int) */
+-#define TIOCINQ		FIONREAD
+-#define FIOQSIZE	0x80086680	/* _IOR('f', 128, loff_t) */
+-
+-#define TCGETS		0x5401
+-#define TCSETS		0x5402
+-#define TCSETSW		0x5403
+-#define TCSETSF		0x5404
+-
+-#define TCGETA		0x80127417	/* _IOR('t', 23, struct termio) */
+-#define TCSETA		0x40127418	/* _IOW('t', 24, struct termio) */
+-#define TCSETAW		0x40127419	/* _IOW('t', 25, struct termio) */
+-#define TCSETAF		0x4012741c	/* _IOW('t', 28, struct termio) */
+-
+-#define TCSBRK		0x741d		/* _IO('t', 29) */
+-#define TCXONC		0x741e		/* _IO('t', 30) */
+-#define TCFLSH		0x741f		/* _IO('t', 31) */
+-
+-#define TIOCSWINSZ	0x40087467	/* _IOW('t', 103, struct winsize) */
+-#define TIOCGWINSZ	0x80087468	/* _IOR('t', 104, struct winsize) */
+-#define	TIOCSTART	0x746e		/* _IO('t', 110)  start output, like ^Q */
+-#define	TIOCSTOP	0x746f		/* _IO('t', 111)  stop output, like ^S */
+-#define TIOCOUTQ        0x80047473	/* _IOR('t', 115, int) output queue size */
+-
+-#define TIOCSPGRP	0x40047476	/* _IOW('t', 118, int) */
+-#define TIOCGPGRP	0x80047477	/* _IOR('t', 119, int) */
+-
+-#define TIOCEXCL	0x540c		/* _IO('T', 12) */
+-#define TIOCNXCL	0x540d		/* _IO('T', 13) */
+-#define TIOCSCTTY	0x540e		/* _IO('T', 14) */
+-
+-#define TIOCSTI		0x40015412	/* _IOW('T', 18, char) 0x5412 */
+-#define TIOCMGET	0x80045415	/* _IOR('T', 21, unsigned int) 0x5415 */
+-#define TIOCMBIS	0x40045416	/* _IOW('T', 22, unsigned int) 0x5416 */
+-#define TIOCMBIC	0x40045417	/* _IOW('T', 23, unsigned int) 0x5417 */
+-#define TIOCMSET	0x40045418	/* _IOW('T', 24, unsigned int) 0x5418 */
+-
+-#define TIOCM_LE	0x001
+-#define TIOCM_DTR	0x002
+-#define TIOCM_RTS	0x004
+-#define TIOCM_ST	0x008
+-#define TIOCM_SR	0x010
+-#define TIOCM_CTS	0x020
+-#define TIOCM_CAR	0x040
+-#define TIOCM_RNG	0x080
+-#define TIOCM_DSR	0x100
+-#define TIOCM_CD	TIOCM_CAR
+-#define TIOCM_RI	TIOCM_RNG
+-
+-#define TIOCGSOFTCAR	0x80045419	/* _IOR('T', 25, unsigned int) 0x5419 */
+-#define TIOCSSOFTCAR	0x4004541a	/* _IOW('T', 26, unsigned int) 0x541A */
+-#define TIOCLINUX	0x4004541c	/* _IOW('T', 28, char) 0x541C */
+-#define TIOCCONS	0x541d		/* _IO('T', 29) */
+-#define TIOCGSERIAL	0x803c541e	/* _IOR('T', 30, struct serial_struct) 0x541E */
+-#define TIOCSSERIAL	0x403c541f	/* _IOW('T', 31, struct serial_struct) 0x541F */
+-#define TIOCPKT		0x40045420	/* _IOW('T', 32, int) 0x5420 */
+-
+-#define TIOCPKT_DATA		 0
+-#define TIOCPKT_FLUSHREAD	 1
+-#define TIOCPKT_FLUSHWRITE	 2
+-#define TIOCPKT_STOP		 4
+-#define TIOCPKT_START		 8
+-#define TIOCPKT_NOSTOP		16
+-#define TIOCPKT_DOSTOP		32
+-
+-
+-#define TIOCNOTTY	0x5422		/* _IO('T', 34) */
+-#define TIOCSETD	0x40045423	/* _IOW('T', 35, int) 0x5423 */
+-#define TIOCGETD	0x80045424	/* _IOR('T', 36, int) 0x5424 */
+-#define TCSBRKP		0x40045424	/* _IOW('T', 37, int) 0x5425 */	/* Needed for POSIX tcsendbreak() */
+-#define TIOCTTYGSTRUCT	0x8c105426	/* _IOR('T', 38, struct tty_struct) 0x5426 */ /* For debugging only */
+-#define TIOCSBRK	0x5427		/* _IO('T', 39) */ /* BSD compatibility */
+-#define TIOCCBRK	0x5428		/* _IO('T', 40) */ /* BSD compatibility */
+-#define TIOCGSID	0x80045429	/* _IOR('T', 41, pid_t) 0x5429 */ /* Return the session ID of FD */
+-#define TIOCGPTN	0x80045430	/* _IOR('T',0x30, unsigned int) 0x5430 Get Pty Number (of pty-mux device) */
+-#define TIOCSPTLCK	0x40045431	/* _IOW('T',0x31, int) Lock/unlock Pty */
+-
+-#define TIOCSERCONFIG	0x5453		/* _IO('T', 83) */
+-#define TIOCSERGWILD	0x80045454	/* _IOR('T', 84,  int) 0x5454 */
+-#define TIOCSERSWILD	0x40045455	/* _IOW('T', 85,  int) 0x5455 */
+-#define TIOCGLCKTRMIOS	0x5456
+-#define TIOCSLCKTRMIOS	0x5457
+-#define TIOCSERGSTRUCT	0x80d85458	/* _IOR('T', 88, struct async_struct) 0x5458 */ /* For debugging only */
+-#define TIOCSERGETLSR   0x80045459	/* _IOR('T', 89, unsigned int) 0x5459 */ /* Get line status register */
+-
+-/* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */
+-#define TIOCSER_TEMT    0x01	/* Transmitter physically empty */
 -
--static unsigned int ocfs2_new_response_id(struct ocfs2_super *osb)
--{
--	unsigned int ret;
+-#define TIOCSERGETMULTI 0x80a8545a	/* _IOR('T', 90, struct serial_multiport_struct) 0x545A */ /* Get multiport config  */
+-#define TIOCSERSETMULTI 0x40a8545b	/* _IOW('T', 91, struct serial_multiport_struct) 0x545B */ /* Set multiport config */
 -
--	spin_lock(&osb->net_response_lock);
--	ret = ++osb->net_response_ids;
--	spin_unlock(&osb->net_response_lock);
+-#define TIOCMIWAIT	0x545c		/* _IO('T', 92) wait for a change on serial input line(s) */
+-#define TIOCGICOUNT	0x545d		/* read serial port inline interrupt counts */
 -
--	return ret;
--}
+-#endif /* __ASM_SH64_IOCTLS_H */
+diff --git a/include/asm-sh64/ipcbuf.h b/include/asm-sh64/ipcbuf.h
+deleted file mode 100644
+index c441e35..0000000
+--- a/include/asm-sh64/ipcbuf.h
++++ /dev/null
+@@ -1,40 +0,0 @@
+-#ifndef __ASM_SH64_IPCBUF_H__
+-#define __ASM_SH64_IPCBUF_H__
 -
--static void ocfs2_dequeue_net_wait_ctxt(struct ocfs2_super *osb,
--					struct ocfs2_net_wait_ctxt *w)
--{
--	spin_lock(&osb->net_response_lock);
--	list_del(&w->n_list);
--	spin_unlock(&osb->net_response_lock);
--}
+-/*
+- * 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/asm-sh64/ipcbuf.h
+- *
+- * Copyright (C) 2000, 2001  Paolo Alberelli
+- *
+- */
 -
--static void ocfs2_queue_net_wait_ctxt(struct ocfs2_super *osb,
--				      struct ocfs2_net_wait_ctxt *w)
--{
--	spin_lock(&osb->net_response_lock);
--	list_add_tail(&w->n_list,
--		      &osb->net_response_list);
--	spin_unlock(&osb->net_response_lock);
--}
+-/*
+- * The ipc64_perm structure for i386 architecture.
+- * Note extra padding because this structure is passed back and forth
+- * between kernel and user space.
+- *
+- * Pad space is left for:
+- * - 32-bit mode_t and seq
+- * - 2 miscellaneous 32-bit values
+- */
 -
--static void __ocfs2_mark_node_responded(struct ocfs2_super *osb,
--					struct ocfs2_net_wait_ctxt *w,
--					int node_num)
+-struct ipc64_perm
 -{
--	assert_spin_locked(&osb->net_response_lock);
+-	__kernel_key_t		key;
+-	__kernel_uid32_t	uid;
+-	__kernel_gid32_t	gid;
+-	__kernel_uid32_t	cuid;
+-	__kernel_gid32_t	cgid;
+-	__kernel_mode_t		mode;
+-	unsigned short		__pad1;
+-	unsigned short		seq;
+-	unsigned short		__pad2;
+-	unsigned long		__unused1;
+-	unsigned long		__unused2;
+-};
 -
--	ocfs2_node_map_clear_bit(osb, &w->n_node_map, node_num);
--	if (ocfs2_node_map_is_empty(osb, &w->n_node_map))
--		wake_up(&w->n_event);
--}
+-#endif /* __ASM_SH64_IPCBUF_H__ */
+diff --git a/include/asm-sh64/irq.h b/include/asm-sh64/irq.h
+deleted file mode 100644
+index 5c9e6a8..0000000
+--- a/include/asm-sh64/irq.h
++++ /dev/null
+@@ -1,144 +0,0 @@
+-#ifndef __ASM_SH64_IRQ_H
+-#define __ASM_SH64_IRQ_H
 -
--/* Intended to be called from the node down callback, we fake remove
-- * the node from all our response contexts */
--void ocfs2_remove_node_from_vote_queues(struct ocfs2_super *osb,
--					int node_num)
--{
--	struct list_head *p;
--	struct ocfs2_net_wait_ctxt *w = NULL;
+-/*
+- * 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/asm-sh64/irq.h
+- *
+- * Copyright (C) 2000, 2001  Paolo Alberelli
+- *
+- */
 -
--	spin_lock(&osb->net_response_lock);
 -
--	list_for_each(p, &osb->net_response_list) {
--		w = list_entry(p, struct ocfs2_net_wait_ctxt, n_list);
+-/*
+- * Encoded IRQs are not considered worth to be supported.
+- * Main reason is that there's no per-encoded-interrupt
+- * enable/disable mechanism (as there was in SH3/4).
+- * An all enabled/all disabled is worth only if there's
+- * a cascaded IC to disable/enable/ack on. Until such
+- * IC is available there's no such support.
+- *
+- * Presumably Encoded IRQs may use extra IRQs beyond 64,
+- * below. Some logic must be added to cope with IRQ_IRL?
+- * in an exclusive way.
+- *
+- * Priorities are set at Platform level, when IRQ_IRL0-3
+- * are set to 0 Encoding is allowed. Otherwise it's not
+- * allowed.
+- */
 -
--		__ocfs2_mark_node_responded(osb, w, node_num);
--	}
+-/* Independent IRQs */
+-#define IRQ_IRL0	0
+-#define IRQ_IRL1	1
+-#define IRQ_IRL2	2
+-#define IRQ_IRL3	3
+-
+-#define IRQ_INTA	4
+-#define IRQ_INTB	5
+-#define IRQ_INTC	6
+-#define IRQ_INTD	7
+-
+-#define IRQ_SERR	12
+-#define IRQ_ERR		13
+-#define IRQ_PWR3	14
+-#define IRQ_PWR2	15
+-#define IRQ_PWR1	16
+-#define IRQ_PWR0	17
+-
+-#define IRQ_DMTE0	18
+-#define IRQ_DMTE1	19
+-#define IRQ_DMTE2	20
+-#define IRQ_DMTE3	21
+-#define IRQ_DAERR	22
+-
+-#define IRQ_TUNI0	32
+-#define IRQ_TUNI1	33
+-#define IRQ_TUNI2	34
+-#define IRQ_TICPI2	35
+-
+-#define IRQ_ATI		36
+-#define IRQ_PRI		37
+-#define IRQ_CUI		38
+-
+-#define IRQ_ERI		39
+-#define IRQ_RXI		40
+-#define IRQ_BRI		41
+-#define IRQ_TXI		42
+-
+-#define IRQ_ITI		63
+-
+-#define NR_INTC_IRQS	64
+-
+-#ifdef CONFIG_SH_CAYMAN
+-#define NR_EXT_IRQS     32
+-#define START_EXT_IRQS  64
+-
+-/* PCI bus 2 uses encoded external interrupts on the Cayman board */
+-#define IRQ_P2INTA      (START_EXT_IRQS + (3*8) + 0)
+-#define IRQ_P2INTB      (START_EXT_IRQS + (3*8) + 1)
+-#define IRQ_P2INTC      (START_EXT_IRQS + (3*8) + 2)
+-#define IRQ_P2INTD      (START_EXT_IRQS + (3*8) + 3)
 -
--	spin_unlock(&osb->net_response_lock);
--}
+-#define I8042_KBD_IRQ	(START_EXT_IRQS + 2)
+-#define I8042_AUX_IRQ	(START_EXT_IRQS + 6)
 -
--static int ocfs2_broadcast_vote(struct ocfs2_super *osb,
--				struct ocfs2_vote_msg *request,
--				unsigned int response_id,
--				int *response,
--				struct ocfs2_net_response_cb *callback)
--{
--	int status, i, remote_err;
--	struct ocfs2_net_wait_ctxt *w = NULL;
--	int dequeued = 0;
+-#define IRQ_CFCARD	(START_EXT_IRQS + 7)
+-#define IRQ_PCMCIA	(0)
 -
--	mlog_entry_void();
+-#else
+-#define NR_EXT_IRQS	0
+-#endif
 -
--	w = ocfs2_new_net_wait_ctxt(response_id);
--	if (!w) {
--		status = -ENOMEM;
--		mlog_errno(status);
--		goto bail;
--	}
--	w->n_callback = callback;
+-#define NR_IRQS		(NR_INTC_IRQS+NR_EXT_IRQS)
 -
--	/* we're pretty much ready to go at this point, and this fills
--	 * in n_response which we need anyway... */
--	ocfs2_queue_net_wait_ctxt(osb, w);
 -
--	i = ocfs2_node_map_iterate(osb, &osb->mounted_map, 0);
+-/* Default IRQs, fixed */
+-#define TIMER_IRQ	IRQ_TUNI0
+-#define RTC_IRQ		IRQ_CUI
+-
+-/* Default Priorities, Platform may choose differently */
+-#define	NO_PRIORITY	0	/* Disabled */
+-#define TIMER_PRIORITY	2
+-#define RTC_PRIORITY	TIMER_PRIORITY
+-#define SCIF_PRIORITY	3
+-#define INTD_PRIORITY	3
+-#define	IRL3_PRIORITY	4
+-#define INTC_PRIORITY	6
+-#define	IRL2_PRIORITY	7
+-#define INTB_PRIORITY	9
+-#define	IRL1_PRIORITY	10
+-#define INTA_PRIORITY	12
+-#define	IRL0_PRIORITY	13
+-#define TOP_PRIORITY	15
+-
+-extern int intc_evt_to_irq[(0xE20/0x20)+1];
+-int intc_irq_describe(char* p, int irq);
+-
+-#define irq_canonicalize(irq)	(irq)
+-
+-#ifdef CONFIG_SH_CAYMAN
+-int cayman_irq_demux(int evt);
+-int cayman_irq_describe(char* p, int irq);
+-#define irq_demux(x) cayman_irq_demux(x)
+-#define irq_describe(p, x) cayman_irq_describe(p, x)
+-#else
+-#define irq_demux(x) (intc_evt_to_irq[x])
+-#define irq_describe(p, x) intc_irq_describe(p, x)
+-#endif
 -
--	while (i != O2NM_INVALID_NODE_NUM) {
--		if (i != osb->node_num) {
--			mlog(0, "trying to send request to node %i\n", i);
--			ocfs2_node_map_set_bit(osb, &w->n_node_map, i);
+-/*
+- * Function for "on chip support modules".
+- */
 -
--			remote_err = 0;
--			status = o2net_send_message(OCFS2_MESSAGE_TYPE_VOTE,
--						    osb->net_key,
--						    request,
--						    sizeof(*request),
--						    i,
--						    &remote_err);
--			if (status == -ETIMEDOUT) {
--				mlog(0, "remote node %d timed out!\n", i);
--				status = -EAGAIN;
--				goto bail;
--			}
--			if (remote_err < 0) {
--				status = remote_err;
--				mlog(0, "remote error %d on node %d!\n",
--				     remote_err, i);
--				mlog_errno(status);
--				goto bail;
--			}
--			if (status < 0) {
--				mlog_errno(status);
--				goto bail;
--			}
--		}
--		i++;
--		i = ocfs2_node_map_iterate(osb, &osb->mounted_map, i);
--		mlog(0, "next is %d, i am %d\n", i, osb->node_num);
--	}
--	mlog(0, "done sending, now waiting on responses...\n");
+-/*
+- * SH-5 supports Priority based interrupts only.
+- * Interrupt priorities are defined at platform level.
+- */
+-#define set_ipr_data(a, b, c, d)
+-#define make_ipr_irq(a)
+-#define make_imask_irq(a)
 -
--	wait_event(w->n_event, ocfs2_node_map_is_empty(osb, &w->n_node_map));
+-#endif /* __ASM_SH64_IRQ_H */
+diff --git a/include/asm-sh64/irq_regs.h b/include/asm-sh64/irq_regs.h
+deleted file mode 100644
+index 3dd9c0b..0000000
+--- a/include/asm-sh64/irq_regs.h
++++ /dev/null
+@@ -1 +0,0 @@
+-#include <asm-generic/irq_regs.h>
+diff --git a/include/asm-sh64/kdebug.h b/include/asm-sh64/kdebug.h
+deleted file mode 100644
+index 6ece1b0..0000000
+--- a/include/asm-sh64/kdebug.h
++++ /dev/null
+@@ -1 +0,0 @@
+-#include <asm-generic/kdebug.h>
+diff --git a/include/asm-sh64/keyboard.h b/include/asm-sh64/keyboard.h
+deleted file mode 100644
+index 0b01c3b..0000000
+--- a/include/asm-sh64/keyboard.h
++++ /dev/null
+@@ -1,70 +0,0 @@
+-/*
+- *  linux/include/asm-shmedia/keyboard.h
+- *
+- * Copied from i386 version:
+- *    Created 3 Nov 1996 by Geert Uytterhoeven
+- */
 -
--	ocfs2_dequeue_net_wait_ctxt(osb, w);
--	dequeued = 1;
+-/*
+- *  This file contains the i386 architecture specific keyboard definitions
+- */
 -
--	*response = w->n_response;
--	status = 0;
--bail:
--	if (w) {
--		if (!dequeued)
--			ocfs2_dequeue_net_wait_ctxt(osb, w);
--		kfree(w);
--	}
+-#ifndef __ASM_SH64_KEYBOARD_H
+-#define __ASM_SH64_KEYBOARD_H
 -
--	mlog_exit(status);
--	return status;
--}
+-#ifdef __KERNEL__
 -
--static struct ocfs2_vote_msg * ocfs2_new_vote_request(struct ocfs2_super *osb,
--						      u64 blkno,
--						      unsigned int generation,
--						      enum ocfs2_vote_request type)
--{
--	struct ocfs2_vote_msg *request;
--	struct ocfs2_msg_hdr *hdr;
+-#include <linux/kernel.h>
+-#include <linux/ioport.h>
+-#include <asm/io.h>
 -
--	BUG_ON(!ocfs2_is_valid_vote_request(type));
+-#ifdef CONFIG_SH_CAYMAN
+-#define KEYBOARD_IRQ			(START_EXT_IRQS + 2) /* SMSC SuperIO IRQ 1 */
+-#endif
+-#define DISABLE_KBD_DURING_INTERRUPTS	0
 -
--	request = kzalloc(sizeof(*request), GFP_NOFS);
--	if (!request) {
--		mlog_errno(-ENOMEM);
--	} else {
--		hdr = &request->v_hdr;
--		hdr->h_node_num = cpu_to_be32(osb->node_num);
--		hdr->h_request = cpu_to_be32(type);
--		hdr->h_blkno = cpu_to_be64(blkno);
--		hdr->h_generation = cpu_to_be32(generation);
--	}
+-extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
+-extern int pckbd_getkeycode(unsigned int scancode);
+-extern int pckbd_translate(unsigned char scancode, unsigned char *keycode,
+-			   char raw_mode);
+-extern char pckbd_unexpected_up(unsigned char keycode);
+-extern void pckbd_leds(unsigned char leds);
+-extern void pckbd_init_hw(void);
+-
+-#define kbd_setkeycode		pckbd_setkeycode
+-#define kbd_getkeycode		pckbd_getkeycode
+-#define kbd_translate		pckbd_translate
+-#define kbd_unexpected_up	pckbd_unexpected_up
+-#define kbd_leds		pckbd_leds
+-#define kbd_init_hw		pckbd_init_hw
+-
+-/* resource allocation */
+-#define kbd_request_region()
+-#define kbd_request_irq(handler) request_irq(KEYBOARD_IRQ, handler, 0, \
+-                                             "keyboard", NULL)
+-
+-/* How to access the keyboard macros on this platform.  */
+-#define kbd_read_input() inb(KBD_DATA_REG)
+-#define kbd_read_status() inb(KBD_STATUS_REG)
+-#define kbd_write_output(val) outb(val, KBD_DATA_REG)
+-#define kbd_write_command(val) outb(val, KBD_CNTL_REG)
 -
--	return request;
--}
+-/* Some stoneage hardware needs delays after some operations.  */
+-#define kbd_pause() do { } while(0)
 -
--/* Complete the buildup of a new vote request and process the
-- * broadcast return value. */
--static int ocfs2_do_request_vote(struct ocfs2_super *osb,
--				 struct ocfs2_vote_msg *request,
--				 struct ocfs2_net_response_cb *callback)
--{
--	int status, response = -EBUSY;
--	unsigned int response_id;
--	struct ocfs2_msg_hdr *hdr;
+-/*
+- * Machine specific bits for the PS/2 driver
+- */
 -
--	response_id = ocfs2_new_response_id(osb);
+-#ifdef CONFIG_SH_CAYMAN
+-#define AUX_IRQ (START_EXT_IRQS + 6) /* SMSC SuperIO IRQ12 */
+-#endif
 -
--	hdr = &request->v_hdr;
--	hdr->h_response_id = cpu_to_be32(response_id);
+-#define aux_request_irq(hand, dev_id)					\
+-	request_irq(AUX_IRQ, hand, IRQF_SHARED, "PS2 Mouse", dev_id)
 -
--	status = ocfs2_broadcast_vote(osb, request, response_id, &response,
--				      callback);
--	if (status < 0) {
--		mlog_errno(status);
--		goto bail;
--	}
+-#define aux_free_irq(dev_id) free_irq(AUX_IRQ, dev_id)
 -
--	status = response;
--bail:
+-#endif /* __KERNEL__ */
+-#endif /* __ASM_SH64_KEYBOARD_H */
 -
--	return status;
--}
+diff --git a/include/asm-sh64/kmap_types.h b/include/asm-sh64/kmap_types.h
+deleted file mode 100644
+index 2ae7c75..0000000
+--- a/include/asm-sh64/kmap_types.h
++++ /dev/null
+@@ -1,7 +0,0 @@
+-#ifndef __ASM_SH64_KMAP_TYPES_H
+-#define __ASM_SH64_KMAP_TYPES_H
 -
--int ocfs2_request_mount_vote(struct ocfs2_super *osb)
--{
--	int status;
--	struct ocfs2_vote_msg *request = NULL;
+-#include <asm-sh/kmap_types.h>
 -
--	request = ocfs2_new_vote_request(osb, 0ULL, 0, OCFS2_VOTE_REQ_MOUNT);
--	if (!request) {
--		status = -ENOMEM;
--		goto bail;
--	}
+-#endif /* __ASM_SH64_KMAP_TYPES_H */
 -
--	status = -EAGAIN;
--	while (status == -EAGAIN) {
--		if (!(osb->s_mount_opt & OCFS2_MOUNT_NOINTR) &&
--		    signal_pending(current)) {
--			status = -ERESTARTSYS;
--			goto bail;
--		}
+diff --git a/include/asm-sh64/linkage.h b/include/asm-sh64/linkage.h
+deleted file mode 100644
+index 1dd0e84..0000000
+--- a/include/asm-sh64/linkage.h
++++ /dev/null
+@@ -1,7 +0,0 @@
+-#ifndef __ASM_SH64_LINKAGE_H
+-#define __ASM_SH64_LINKAGE_H
 -
--		if (ocfs2_node_map_is_only(osb, &osb->mounted_map,
--					   osb->node_num)) {
--			status = 0;
--			goto bail;
--		}
+-#include <asm-sh/linkage.h>
 -
--		status = ocfs2_do_request_vote(osb, request, NULL);
--	}
+-#endif /* __ASM_SH64_LINKAGE_H */
 -
--bail:
--	kfree(request);
--	return status;
--}
+diff --git a/include/asm-sh64/local.h b/include/asm-sh64/local.h
+deleted file mode 100644
+index d9bd95d..0000000
+--- a/include/asm-sh64/local.h
++++ /dev/null
+@@ -1,7 +0,0 @@
+-#ifndef __ASM_SH64_LOCAL_H
+-#define __ASM_SH64_LOCAL_H
 -
--int ocfs2_request_umount_vote(struct ocfs2_super *osb)
--{
--	int status;
--	struct ocfs2_vote_msg *request = NULL;
+-#include <asm-generic/local.h>
 -
--	request = ocfs2_new_vote_request(osb, 0ULL, 0, OCFS2_VOTE_REQ_UMOUNT);
--	if (!request) {
--		status = -ENOMEM;
--		goto bail;
--	}
+-#endif /* __ASM_SH64_LOCAL_H */
 -
--	status = -EAGAIN;
--	while (status == -EAGAIN) {
--		/* Do not check signals on this vote... We really want
--		 * this one to go all the way through. */
+diff --git a/include/asm-sh64/mc146818rtc.h b/include/asm-sh64/mc146818rtc.h
+deleted file mode 100644
+index 6cd3aec..0000000
+--- a/include/asm-sh64/mc146818rtc.h
++++ /dev/null
+@@ -1,7 +0,0 @@
+-/*
+- * linux/include/asm-sh64/mc146818rtc.h
+- *
+-*/
 -
--		if (ocfs2_node_map_is_only(osb, &osb->mounted_map,
--					   osb->node_num)) {
--			status = 0;
--			goto bail;
--		}
+-/* For now, an empty place-holder to get IDE to compile. */
 -
--		status = ocfs2_do_request_vote(osb, request, NULL);
--	}
+diff --git a/include/asm-sh64/mman.h b/include/asm-sh64/mman.h
+deleted file mode 100644
+index a9be6d8..0000000
+--- a/include/asm-sh64/mman.h
++++ /dev/null
+@@ -1,6 +0,0 @@
+-#ifndef __ASM_SH64_MMAN_H
+-#define __ASM_SH64_MMAN_H
 -
--bail:
--	kfree(request);
--	return status;
--}
+-#include <asm-sh/mman.h>
 -
--/* TODO: This should eventually be a hash table! */
--static struct ocfs2_net_wait_ctxt * __ocfs2_find_net_wait_ctxt(struct ocfs2_super *osb,
--							       u32 response_id)
--{
--	struct list_head *p;
--	struct ocfs2_net_wait_ctxt *w = NULL;
+-#endif /* __ASM_SH64_MMAN_H */
+diff --git a/include/asm-sh64/mmu.h b/include/asm-sh64/mmu.h
+deleted file mode 100644
+index ccd36d2..0000000
+--- a/include/asm-sh64/mmu.h
++++ /dev/null
+@@ -1,7 +0,0 @@
+-#ifndef __MMU_H
+-#define __MMU_H
 -
--	list_for_each(p, &osb->net_response_list) {
--		w = list_entry(p, struct ocfs2_net_wait_ctxt, n_list);
--		if (response_id == w->n_response_id)
--			break;
--		w = NULL;
--	}
+-/* Default "unsigned long" context */
+-typedef unsigned long mm_context_t;
 -
--	return w;
--}
+-#endif
+diff --git a/include/asm-sh64/mmu_context.h b/include/asm-sh64/mmu_context.h
+deleted file mode 100644
+index 507bf72..0000000
+--- a/include/asm-sh64/mmu_context.h
++++ /dev/null
+@@ -1,208 +0,0 @@
+-#ifndef __ASM_SH64_MMU_CONTEXT_H
+-#define __ASM_SH64_MMU_CONTEXT_H
 -
--/* Translate response codes into local node errno values */
--static inline int ocfs2_translate_response(int response)
--{
--	int ret;
+-/*
+- * 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/asm-sh64/mmu_context.h
+- *
+- * Copyright (C) 2000, 2001  Paolo Alberelli
+- * Copyright (C) 2003  Paul Mundt
+- *
+- * ASID handling idea taken from MIPS implementation.
+- *
+- */
 -
--	switch (response) {
--	case OCFS2_RESPONSE_OK:
--		ret = 0;
--		break;
+-#ifndef __ASSEMBLY__
 -
--	case OCFS2_RESPONSE_BUSY:
--		ret = -EBUSY;
--		break;
+-/*
+- * Cache of MMU context last used.
+- *
+- * The MMU "context" consists of two things:
+- *   (a) TLB cache version (or cycle, top 24 bits of mmu_context_cache)
+- *   (b) ASID (Address Space IDentifier, bottom 8 bits of mmu_context_cache)
+- */
+-extern unsigned long mmu_context_cache;
 -
--	default:
--		ret = -EINVAL;
--	}
+-#include <asm/page.h>
+-#include <asm-generic/mm_hooks.h>
 -
--	return ret;
--}
+-/* Current mm's pgd */
+-extern pgd_t *mmu_pdtp_cache;
 -
--static int ocfs2_handle_response_message(struct o2net_msg *msg,
--					 u32 len,
--					 void *data, void **ret_data)
--{
--	unsigned int response_id, node_num;
--	int response_status;
--	struct ocfs2_super *osb = data;
--	struct ocfs2_response_msg *resp;
--	struct ocfs2_net_wait_ctxt * w;
--	struct ocfs2_net_response_cb *resp_cb;
+-#define SR_ASID_MASK		0xffffffffff00ffffULL
+-#define SR_ASID_SHIFT		16
 -
--	resp = (struct ocfs2_response_msg *) msg->buf;
+-#define MMU_CONTEXT_ASID_MASK		0x000000ff
+-#define MMU_CONTEXT_VERSION_MASK	0xffffff00
+-#define MMU_CONTEXT_FIRST_VERSION	0x00000100
+-#define NO_CONTEXT			0
 -
--	response_id = be32_to_cpu(resp->r_hdr.h_response_id);
--	node_num = be32_to_cpu(resp->r_hdr.h_node_num);
--	response_status = 
--		ocfs2_translate_response(be32_to_cpu(resp->r_response));
+-/* ASID is 8-bit value, so it can't be 0x100 */
+-#define MMU_NO_ASID			0x100
 -
--	mlog(0, "received response message:\n");
--	mlog(0, "h_response_id = %u\n", response_id);
--	mlog(0, "h_request = %u\n", be32_to_cpu(resp->r_hdr.h_request));
--	mlog(0, "h_blkno = %llu\n",
--	     (unsigned long long)be64_to_cpu(resp->r_hdr.h_blkno));
--	mlog(0, "h_generation = %u\n", be32_to_cpu(resp->r_hdr.h_generation));
--	mlog(0, "h_node_num = %u\n", node_num);
--	mlog(0, "r_response = %d\n", response_status);
 -
--	spin_lock(&osb->net_response_lock);
--	w = __ocfs2_find_net_wait_ctxt(osb, response_id);
--	if (!w) {
--		mlog(0, "request not found!\n");
--		goto bail;
--	}
--	resp_cb = w->n_callback;
+-/*
+- * Virtual Page Number mask
+- */
+-#define MMU_VPN_MASK	0xfffff000
 -
--	if (response_status && (!w->n_response)) {
--		/* we only really need one negative response so don't
--		 * set it twice. */
--		w->n_response = response_status;
--	}
+-static inline void
+-get_new_mmu_context(struct mm_struct *mm)
+-{
+-	extern void flush_tlb_all(void);
+-	extern void flush_cache_all(void);
 -
--	if (resp_cb) {
--		spin_unlock(&osb->net_response_lock);
+-	unsigned long mc = ++mmu_context_cache;
 -
--		resp_cb->rc_cb(resp_cb->rc_priv, resp);
+-	if (!(mc & MMU_CONTEXT_ASID_MASK)) {
+-		/* We exhaust ASID of this version.
+-		   Flush all TLB and start new cycle. */
+-		flush_tlb_all();
+-		/* We have to flush all caches as ASIDs are
+-                   used in cache */
+-		flush_cache_all();
+-		/* Fix version if needed.
+-		   Note that we avoid version #0/asid #0 to distingush NO_CONTEXT. */
+-		if (!mc)
+-			mmu_context_cache = mc = MMU_CONTEXT_FIRST_VERSION;
+-	}
+-	mm->context = mc;
+-}
 -
--		spin_lock(&osb->net_response_lock);
+-/*
+- * Get MMU context if needed.
+- */
+-static __inline__ void
+-get_mmu_context(struct mm_struct *mm)
+-{
+-	if (mm) {
+-		unsigned long mc = mmu_context_cache;
+-		/* Check if we have old version of context.
+-		   If it's old, we need to get new context with new version. */
+-		if ((mm->context ^ mc) & MMU_CONTEXT_VERSION_MASK)
+-			get_new_mmu_context(mm);
 -	}
+-}
 -
--	__ocfs2_mark_node_responded(osb, w, node_num);
--bail:
--	spin_unlock(&osb->net_response_lock);
+-/*
+- * 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)
+-{
+-	mm->context = NO_CONTEXT;
 -
 -	return 0;
 -}
 -
--static int ocfs2_handle_vote_message(struct o2net_msg *msg,
--				     u32 len,
--				     void *data, void **ret_data)
+-/*
+- * 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)
 -{
--	int status;
--	struct ocfs2_super *osb = data;
--	struct ocfs2_vote_work *work;
+-	extern void flush_tlb_mm(struct mm_struct *mm);
 -
--	work = kmalloc(sizeof(struct ocfs2_vote_work), GFP_NOFS);
--	if (!work) {
--		status = -ENOMEM;
--		mlog_errno(status);
--		goto bail;
--	}
+-	/* Well, at least free TLB entries */
+-	flush_tlb_mm(mm);
+-}
 -
--	INIT_LIST_HEAD(&work->w_list);
--	memcpy(&work->w_msg, msg->buf, sizeof(struct ocfs2_vote_msg));
+-#endif	/* __ASSEMBLY__ */
 -
--	mlog(0, "scheduling vote request:\n");
--	mlog(0, "h_response_id = %u\n",
--	     be32_to_cpu(work->w_msg.v_hdr.h_response_id));
--	mlog(0, "h_request = %u\n", be32_to_cpu(work->w_msg.v_hdr.h_request));
--	mlog(0, "h_blkno = %llu\n",
--	     (unsigned long long)be64_to_cpu(work->w_msg.v_hdr.h_blkno));
--	mlog(0, "h_generation = %u\n",
--	     be32_to_cpu(work->w_msg.v_hdr.h_generation));
--	mlog(0, "h_node_num = %u\n",
--	     be32_to_cpu(work->w_msg.v_hdr.h_node_num));
+-/* Common defines */
+-#define TLB_STEP	0x00000010
+-#define TLB_PTEH	0x00000000
+-#define TLB_PTEL	0x00000008
 -
--	spin_lock(&osb->vote_task_lock);
--	list_add_tail(&work->w_list, &osb->vote_list);
--	osb->vote_count++;
--	spin_unlock(&osb->vote_task_lock);
+-/* PTEH defines */
+-#define PTEH_ASID_SHIFT	2
+-#define PTEH_VALID	0x0000000000000001
+-#define PTEH_SHARED	0x0000000000000002
+-#define PTEH_MATCH_ASID	0x00000000000003ff
 -
--	ocfs2_kick_vote_thread(osb);
+-#ifndef __ASSEMBLY__
+-/* This has to be a common function because the next location to fill
+- * information is shared. */
+-extern void __do_tlb_refill(unsigned long address, unsigned long long is_text_not_data, pte_t *pte);
 -
--	status = 0;
--bail:
--	return status;
+-/* Profiling counter. */
+-#ifdef CONFIG_SH64_PROC_TLB
+-extern unsigned long long calls_to_do_fast_page_fault;
+-#endif
+-
+-static inline unsigned long get_asid(void)
+-{
+-	unsigned long long sr;
+-
+-	asm volatile ("getcon   " __SR ", %0\n\t"
+-		      : "=r" (sr));
+-
+-	sr = (sr >> SR_ASID_SHIFT) & MMU_CONTEXT_ASID_MASK;
+-	return (unsigned long) sr;
 -}
 -
--void ocfs2_unregister_net_handlers(struct ocfs2_super *osb)
+-/* Set ASID into SR */
+-static inline void set_asid(unsigned long asid)
 -{
--	if (!osb->net_key)
--		return;
+-	unsigned long long sr, pc;
 -
--	o2net_unregister_handler_list(&osb->osb_net_handlers);
+-	asm volatile ("getcon	" __SR ", %0" : "=r" (sr));
 -
--	if (!list_empty(&osb->net_response_list))
--		mlog(ML_ERROR, "net response list not empty!\n");
+-	sr = (sr & SR_ASID_MASK) | (asid << SR_ASID_SHIFT);
 -
--	osb->net_key = 0;
+-	/*
+-	 * It is possible that this function may be inlined and so to avoid
+-	 * the assembler reporting duplicate symbols we make use of the gas trick
+-	 * of generating symbols using numerics and forward reference.
+-	 */
+-	asm volatile ("movi	1, %1\n\t"
+-		      "shlli	%1, 28, %1\n\t"
+-		      "or	%0, %1, %1\n\t"
+-		      "putcon	%1, " __SR "\n\t"
+-		      "putcon	%0, " __SSR "\n\t"
+-		      "movi	1f, %1\n\t"
+-		      "ori	%1, 1 , %1\n\t"
+-		      "putcon	%1, " __SPC "\n\t"
+-		      "rte\n"
+-		      "1:\n\t"
+-		      : "=r" (sr), "=r" (pc) : "0" (sr));
 -}
 -
--int ocfs2_register_net_handlers(struct ocfs2_super *osb)
+-/*
+- * 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_context(struct mm_struct *mm)
 -{
--	int status = 0;
+-	get_mmu_context(mm);
+-	set_asid(mm->context & MMU_CONTEXT_ASID_MASK);
+-}
 -
--	if (ocfs2_mount_local(osb))
--		return 0;
 -
--	status = o2net_register_handler(OCFS2_MESSAGE_TYPE_RESPONSE,
--					osb->net_key,
--					sizeof(struct ocfs2_response_msg),
--					ocfs2_handle_response_message,
--					osb, NULL, &osb->osb_net_handlers);
--	if (status) {
--		mlog_errno(status);
--		goto bail;
+-static __inline__ void switch_mm(struct mm_struct *prev,
+-				 struct mm_struct *next,
+-				 struct task_struct *tsk)
+-{
+-	if (prev != next) {
+-		mmu_pdtp_cache = next->pgd;
+-		activate_context(next);
 -	}
+-}
 -
--	status = o2net_register_handler(OCFS2_MESSAGE_TYPE_VOTE,
--					osb->net_key,
--					sizeof(struct ocfs2_vote_msg),
--					ocfs2_handle_vote_message,
--					osb, NULL, &osb->osb_net_handlers);
--	if (status) {
--		mlog_errno(status);
--		goto bail;
--	}
--bail:
--	if (status < 0)
--		ocfs2_unregister_net_handlers(osb);
+-#define deactivate_mm(tsk,mm)	do { } while (0)
 -
--	return status;
+-#define activate_mm(prev, next) \
+-	switch_mm((prev),(next),NULL)
+-
+-static inline void
+-enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
+-{
 -}
-diff --git a/fs/ocfs2/vote.h b/fs/ocfs2/vote.h
+-
+-#endif	/* __ASSEMBLY__ */
+-
+-#endif /* __ASM_SH64_MMU_CONTEXT_H */
+diff --git a/include/asm-sh64/module.h b/include/asm-sh64/module.h
 deleted file mode 100644
-index 9ea46f6..0000000
---- a/fs/ocfs2/vote.h
+index c313650..0000000
+--- a/include/asm-sh64/module.h
 +++ /dev/null
-@@ -1,48 +0,0 @@
--/* -*- mode: c; c-basic-offset: 8; -*-
-- * vim: noexpandtab sw=8 ts=8 sts=0:
+@@ -1,20 +0,0 @@
+-#ifndef __ASM_SH64_MODULE_H
+-#define __ASM_SH64_MODULE_H
+-/*
+- * This file contains the SH architecture specific module code.
+- */
+-
+-struct mod_arch_specific {
+-	/* empty */
+-};
+-
+-#define Elf_Shdr		Elf32_Shdr
+-#define Elf_Sym			Elf32_Sym
+-#define Elf_Ehdr		Elf32_Ehdr
+-
+-#define module_map(x)		vmalloc(x)
+-#define module_unmap(x)		vfree(x)
+-#define module_arch_init(x)	(0)
+-#define arch_init_modules(x)	do { } while (0)
+-
+-#endif /* __ASM_SH64_MODULE_H */
+diff --git a/include/asm-sh64/msgbuf.h b/include/asm-sh64/msgbuf.h
+deleted file mode 100644
+index cf0494c..0000000
+--- a/include/asm-sh64/msgbuf.h
++++ /dev/null
+@@ -1,42 +0,0 @@
+-#ifndef __ASM_SH64_MSGBUF_H
+-#define __ASM_SH64_MSGBUF_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.
 - *
-- * vote.h
+- * include/asm-sh64/msgbuf.h
 - *
-- * description here
+- * Copyright (C) 2000, 2001  Paolo Alberelli
 - *
-- * Copyright (C) 2002, 2004 Oracle.  All rights reserved.
+- */
+-
+-/*
+- * The msqid64_ds structure for i386 architecture.
+- * Note extra padding because this structure is passed back and forth
+- * between kernel and user space.
+- *
+- * Pad space is left for:
+- * - 64-bit time_t to solve y2038 problem
+- * - 2 miscellaneous 32-bit values
+- */
+-
+-struct msqid64_ds {
+-	struct ipc64_perm msg_perm;
+-	__kernel_time_t msg_stime;	/* last msgsnd time */
+-	unsigned long	__unused1;
+-	__kernel_time_t msg_rtime;	/* last msgrcv time */
+-	unsigned long	__unused2;
+-	__kernel_time_t msg_ctime;	/* last change time */
+-	unsigned long	__unused3;
+-	unsigned long  msg_cbytes;	/* current number of bytes on queue */
+-	unsigned long  msg_qnum;	/* number of messages in queue */
+-	unsigned long  msg_qbytes;	/* max number of bytes on queue */
+-	__kernel_pid_t msg_lspid;	/* pid of last msgsnd */
+-	__kernel_pid_t msg_lrpid;	/* last receive pid */
+-	unsigned long  __unused4;
+-	unsigned long  __unused5;
+-};
+-
+-#endif /* __ASM_SH64_MSGBUF_H */
+diff --git a/include/asm-sh64/mutex.h b/include/asm-sh64/mutex.h
+deleted file mode 100644
+index 458c1f7..0000000
+--- a/include/asm-sh64/mutex.h
++++ /dev/null
+@@ -1,9 +0,0 @@
+-/*
+- * Pull in the generic implementation for the mutex fastpath.
 - *
-- * This program is free software; you can redistribute it and/or
-- * modify it under the terms of the GNU General Public
-- * License as published by the Free Software Foundation; either
-- * version 2 of the License, or (at your option) any later version.
+- * TODO: implement optimized primitives instead, or leave the generic
+- * implementation in place, or pick the atomic_xchg() based generic
+- * implementation. (see asm-generic/mutex-xchg.h for details)
+- */
+-
+-#include <asm-generic/mutex-dec.h>
+diff --git a/include/asm-sh64/namei.h b/include/asm-sh64/namei.h
+deleted file mode 100644
+index 99d759a..0000000
+--- a/include/asm-sh64/namei.h
++++ /dev/null
+@@ -1,24 +0,0 @@
+-#ifndef __ASM_SH64_NAMEI_H
+-#define __ASM_SH64_NAMEI_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.
 - *
-- * This program is distributed in the hope that it will be useful,
-- * but WITHOUT ANY WARRANTY; without even the implied warranty of
-- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-- * General Public License for more details.
+- * include/asm-sh64/namei.h
+- *
+- * Copyright (C) 2000, 2001  Paolo Alberelli
+- *
+- * Included from linux/fs/namei.c
 - *
-- * You 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.
 - */
 -
+-/* This dummy routine maybe changed to something useful
+- * for /usr/gnemul/ emulation stuff.
+- * Look at asm-sparc/namei.h for details.
+- */
 -
--#ifndef VOTE_H
--#define VOTE_H
+-#define __emul_prefix() NULL
 -
--int ocfs2_vote_thread(void *arg);
--static inline void ocfs2_kick_vote_thread(struct ocfs2_super *osb)
--{
--	spin_lock(&osb->vote_task_lock);
--	/* make sure the voting thread gets a swipe at whatever changes
--	 * the caller may have made to the voting state */
--	osb->vote_wake_sequence++;
--	spin_unlock(&osb->vote_task_lock);
--	wake_up(&osb->vote_event);
--}
+-#endif /* __ASM_SH64_NAMEI_H */
+diff --git a/include/asm-sh64/page.h b/include/asm-sh64/page.h
+deleted file mode 100644
+index 472089a..0000000
+--- a/include/asm-sh64/page.h
++++ /dev/null
+@@ -1,119 +0,0 @@
+-#ifndef __ASM_SH64_PAGE_H
+-#define __ASM_SH64_PAGE_H
 -
--int ocfs2_request_mount_vote(struct ocfs2_super *osb);
--int ocfs2_request_umount_vote(struct ocfs2_super *osb);
--int ocfs2_register_net_handlers(struct ocfs2_super *osb);
--void ocfs2_unregister_net_handlers(struct ocfs2_super *osb);
+-/*
+- * 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/asm-sh64/page.h
+- *
+- * Copyright (C) 2000, 2001  Paolo Alberelli
+- * Copyright (C) 2003, 2004  Paul Mundt
+- *
+- * benedict.gaster at superh.com 19th, 24th July 2002.
+- *
+- * Modified to take account of enabling for D-CACHE support.
+- *
+- */
 -
--void ocfs2_remove_node_from_vote_queues(struct ocfs2_super *osb,
--					int node_num);
+-
+-/* PAGE_SHIFT determines the page size */
+-#define PAGE_SHIFT	12
+-#ifdef __ASSEMBLY__
+-#define PAGE_SIZE	4096
+-#else
+-#define PAGE_SIZE	(1UL << PAGE_SHIFT)
 -#endif
-diff --git a/fs/partitions/check.c b/fs/partitions/check.c
-index 722e12e..739da70 100644
---- a/fs/partitions/check.c
-+++ b/fs/partitions/check.c
-@@ -195,96 +195,45 @@ check_partition(struct gendisk *hd, struct block_device *bdev)
- 	return ERR_PTR(res);
- }
- 
+-#define PAGE_MASK	(~(PAGE_SIZE-1))
+-#define PTE_MASK	PAGE_MASK
+-
+-#if defined(CONFIG_HUGETLB_PAGE_SIZE_64K)
+-#define HPAGE_SHIFT	16
+-#elif defined(CONFIG_HUGETLB_PAGE_SIZE_1MB)
+-#define HPAGE_SHIFT	20
+-#elif defined(CONFIG_HUGETLB_PAGE_SIZE_512MB)
+-#define HPAGE_SHIFT	29
+-#endif
+-
+-#ifdef CONFIG_HUGETLB_PAGE
+-#define HPAGE_SIZE		(1UL << HPAGE_SHIFT)
+-#define HPAGE_MASK		(~(HPAGE_SIZE-1))
+-#define HUGETLB_PAGE_ORDER	(HPAGE_SHIFT-PAGE_SHIFT)
+-#define ARCH_HAS_SETCLEAR_HUGE_PTE
+-#endif
+-
+-#ifdef __KERNEL__
+-#ifndef __ASSEMBLY__
+-
+-extern struct page *mem_map;
+-extern void sh64_page_clear(void *page);
+-extern void sh64_page_copy(void *from, void *to);
+-
+-#define clear_page(page)               sh64_page_clear(page)
+-#define copy_page(to,from)             sh64_page_copy(from, to)
+-
+-#if defined(CONFIG_DCACHE_DISABLED)
+-
+-#define clear_user_page(page, vaddr, pg)	clear_page(page)
+-#define copy_user_page(to, from, vaddr, pg)	copy_page(to, from)
+-
+-#else
+-
+-extern void clear_user_page(void *to, unsigned long address, struct page *pg);
+-extern void copy_user_page(void *to, void *from, unsigned long address, struct page *pg);
+-
+-#endif /* defined(CONFIG_DCACHE_DISABLED) */
+-
 -/*
-- * sysfs bindings for partitions
+- * These are used to make use of C type-checking..
 - */
+-typedef struct { unsigned long long pte; } pte_t;
+-typedef struct { unsigned long pmd; } pmd_t;
+-typedef struct { unsigned long pgd; } pgd_t;
+-typedef struct { unsigned long pgprot; } pgprot_t;
+-
+-#define pte_val(x)	((x).pte)
+-#define pmd_val(x)	((x).pmd)
+-#define pgd_val(x)	((x).pgd)
+-#define pgprot_val(x)	((x).pgprot)
+-
+-#define __pte(x) ((pte_t) { (x) } )
+-#define __pmd(x) ((pmd_t) { (x) } )
+-#define __pgd(x) ((pgd_t) { (x) } )
+-#define __pgprot(x)	((pgprot_t) { (x) } )
 -
--struct part_attribute {
--	struct attribute attr;
--	ssize_t (*show)(struct hd_struct *,char *);
--	ssize_t (*store)(struct hd_struct *,const char *, size_t);
--};
+-#endif /* !__ASSEMBLY__ */
 -
--static ssize_t 
--part_attr_show(struct kobject * kobj, struct attribute * attr, char * page)
-+static ssize_t part_start_show(struct device *dev,
-+			       struct device_attribute *attr, char *buf)
- {
--	struct hd_struct * p = container_of(kobj,struct hd_struct,kobj);
--	struct part_attribute * part_attr = container_of(attr,struct part_attribute,attr);
--	ssize_t ret = 0;
--	if (part_attr->show)
--		ret = part_attr->show(p, page);
--	return ret;
--}
--static ssize_t
--part_attr_store(struct kobject * kobj, struct attribute * attr,
--		const char *page, size_t count)
--{
--	struct hd_struct * p = container_of(kobj,struct hd_struct,kobj);
--	struct part_attribute * part_attr = container_of(attr,struct part_attribute,attr);
--	ssize_t ret = 0;
-+	struct hd_struct *p = dev_to_part(dev);
- 
--	if (part_attr->store)
--		ret = part_attr->store(p, page, count);
--	return ret;
-+	return sprintf(buf, "%llu\n",(unsigned long long)p->start_sect);
- }
- 
--static struct sysfs_ops part_sysfs_ops = {
--	.show	=	part_attr_show,
--	.store	=	part_attr_store,
--};
+-/* to align the pointer to the (next) page boundary */
+-#define PAGE_ALIGN(addr)	(((addr)+PAGE_SIZE-1)&PAGE_MASK)
 -
--static ssize_t part_uevent_store(struct hd_struct * p,
--				 const char *page, size_t count)
-+static ssize_t part_size_show(struct device *dev,
-+			      struct device_attribute *attr, char *buf)
- {
--	kobject_uevent(&p->kobj, KOBJ_ADD);
--	return count;
-+	struct hd_struct *p = dev_to_part(dev);
-+	return sprintf(buf, "%llu\n",(unsigned long long)p->nr_sects);
- }
--static ssize_t part_dev_read(struct hd_struct * p, char *page)
--{
--	struct gendisk *disk = container_of(p->kobj.parent,struct gendisk,kobj);
--	dev_t dev = MKDEV(disk->major, disk->first_minor + p->partno); 
--	return print_dev_t(page, dev);
--}
--static ssize_t part_start_read(struct hd_struct * p, char *page)
--{
--	return sprintf(page, "%llu\n",(unsigned long long)p->start_sect);
--}
--static ssize_t part_size_read(struct hd_struct * p, char *page)
--{
--	return sprintf(page, "%llu\n",(unsigned long long)p->nr_sects);
--}
--static ssize_t part_stat_read(struct hd_struct * p, char *page)
-+
-+static ssize_t part_stat_show(struct device *dev,
-+			      struct device_attribute *attr, char *buf)
- {
--	return sprintf(page, "%8u %8llu %8u %8llu\n",
-+	struct hd_struct *p = dev_to_part(dev);
-+
-+	return sprintf(buf, "%8u %8llu %8u %8llu\n",
- 		       p->ios[0], (unsigned long long)p->sectors[0],
- 		       p->ios[1], (unsigned long long)p->sectors[1]);
- }
--static struct part_attribute part_attr_uevent = {
--	.attr = {.name = "uevent", .mode = S_IWUSR },
--	.store	= part_uevent_store
--};
--static struct part_attribute part_attr_dev = {
--	.attr = {.name = "dev", .mode = S_IRUGO },
--	.show	= part_dev_read
--};
--static struct part_attribute part_attr_start = {
--	.attr = {.name = "start", .mode = S_IRUGO },
--	.show	= part_start_read
--};
--static struct part_attribute part_attr_size = {
--	.attr = {.name = "size", .mode = S_IRUGO },
--	.show	= part_size_read
--};
--static struct part_attribute part_attr_stat = {
--	.attr = {.name = "stat", .mode = S_IRUGO },
--	.show	= part_stat_read
--};
- 
- #ifdef CONFIG_FAIL_MAKE_REQUEST
-+static ssize_t part_fail_show(struct device *dev,
-+			      struct device_attribute *attr, char *buf)
-+{
-+	struct hd_struct *p = dev_to_part(dev);
- 
--static ssize_t part_fail_store(struct hd_struct * p,
-+	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)
- {
-+	struct hd_struct *p = dev_to_part(dev);
- 	int i;
- 
- 	if (count > 0 && sscanf(buf, "%d", &i) > 0)
-@@ -292,50 +241,53 @@ static ssize_t part_fail_store(struct hd_struct * p,
- 
- 	return count;
- }
--static ssize_t part_fail_read(struct hd_struct * p, char *page)
--{
--	return sprintf(page, "%d\n", p->make_it_fail);
--}
--static struct part_attribute part_attr_fail = {
--	.attr = {.name = "make-it-fail", .mode = S_IRUGO | S_IWUSR },
--	.store	= part_fail_store,
--	.show	= part_fail_read
--};
-+#endif
- 
-+static DEVICE_ATTR(start, S_IRUGO, part_start_show, NULL);
-+static DEVICE_ATTR(size, S_IRUGO, part_size_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, part_fail_show, part_fail_store);
- #endif
- 
--static struct attribute * default_attrs[] = {
--	&part_attr_uevent.attr,
--	&part_attr_dev.attr,
--	&part_attr_start.attr,
--	&part_attr_size.attr,
--	&part_attr_stat.attr,
-+static struct attribute *part_attrs[] = {
-+	&dev_attr_start.attr,
-+	&dev_attr_size.attr,
-+	&dev_attr_stat.attr,
- #ifdef CONFIG_FAIL_MAKE_REQUEST
--	&part_attr_fail.attr,
-+	&dev_attr_fail.attr,
- #endif
--	NULL,
-+	NULL
- };
- 
--extern struct kset block_subsys;
-+static struct attribute_group part_attr_group = {
-+	.attrs = part_attrs,
-+};
- 
--static void part_release(struct kobject *kobj)
-+static struct attribute_group *part_attr_groups[] = {
-+	&part_attr_group,
-+	NULL
-+};
-+
-+static void part_release(struct device *dev)
- {
--	struct hd_struct * p = container_of(kobj,struct hd_struct,kobj);
-+	struct hd_struct *p = dev_to_part(dev);
- 	kfree(p);
- }
- 
--struct kobj_type ktype_part = {
-+struct device_type part_type = {
-+	.name		= "partition",
-+	.groups		= part_attr_groups,
- 	.release	= part_release,
--	.default_attrs	= default_attrs,
--	.sysfs_ops	= &part_sysfs_ops,
- };
- 
- static inline void partition_sysfs_add_subdir(struct hd_struct *p)
- {
- 	struct kobject *k;
- 
--	k = kobject_get(&p->kobj);
--	p->holder_dir = kobject_add_dir(k, "holders");
-+	k = kobject_get(&p->dev.kobj);
-+	p->holder_dir = kobject_create_and_add("holders", k);
- 	kobject_put(k);
- }
- 
-@@ -343,15 +295,16 @@ static inline void disk_sysfs_add_subdirs(struct gendisk *disk)
- {
- 	struct kobject *k;
- 
--	k = kobject_get(&disk->kobj);
--	disk->holder_dir = kobject_add_dir(k, "holders");
--	disk->slave_dir = kobject_add_dir(k, "slaves");
-+	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)
- 		return;
- 	if (!p->nr_sects)
-@@ -361,113 +314,55 @@ void delete_partition(struct gendisk *disk, int part)
- 	p->nr_sects = 0;
- 	p->ios[0] = p->ios[1] = 0;
- 	p->sectors[0] = p->sectors[1] = 0;
--	sysfs_remove_link(&p->kobj, "subsystem");
--	kobject_unregister(p->holder_dir);
--	kobject_uevent(&p->kobj, KOBJ_REMOVE);
--	kobject_del(&p->kobj);
--	kobject_put(&p->kobj);
-+	kobject_put(p->holder_dir);
-+	device_del(&p->dev);
-+	put_device(&p->dev);
- }
- 
- void add_partition(struct gendisk *disk, int part, sector_t start, sector_t len, int flags)
- {
- 	struct hd_struct *p;
-+	int err;
- 
- 	p = kzalloc(sizeof(*p), GFP_KERNEL);
- 	if (!p)
- 		return;
--	
-+
- 	p->start_sect = start;
- 	p->nr_sects = len;
- 	p->partno = part;
- 	p->policy = disk->policy;
- 
--	if (isdigit(disk->kobj.k_name[strlen(disk->kobj.k_name)-1]))
--		kobject_set_name(&p->kobj, "%sp%d",
--				 kobject_name(&disk->kobj), part);
-+	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);
- 	else
--		kobject_set_name(&p->kobj, "%s%d",
--				 kobject_name(&disk->kobj),part);
--	p->kobj.parent = &disk->kobj;
--	p->kobj.ktype = &ktype_part;
--	kobject_init(&p->kobj);
--	kobject_add(&p->kobj);
--	if (!disk->part_uevent_suppress)
--		kobject_uevent(&p->kobj, KOBJ_ADD);
--	sysfs_create_link(&p->kobj, &block_subsys.kobj, "subsystem");
-+		snprintf(p->dev.bus_id, BUS_ID_SIZE,
-+			 "%s%d", disk->dev.bus_id, part);
-+
-+	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;
-+
-+	/* delay uevent until 'holders' subdir is created */
-+	p->dev.uevent_suppress = 1;
-+	device_add(&p->dev);
-+	partition_sysfs_add_subdir(p);
-+	p->dev.uevent_suppress = 0;
- 	if (flags & ADDPART_FLAG_WHOLEDISK) {
- 		static struct attribute addpartattr = {
- 			.name = "whole_disk",
- 			.mode = S_IRUSR | S_IRGRP | S_IROTH,
- 		};
+-/*
+- * Kconfig defined.
+- */
+-#define __MEMORY_START		(CONFIG_MEMORY_START)
+-#define PAGE_OFFSET		(CONFIG_CACHED_MEMORY_OFFSET)
+-
+-#define __pa(x)			((unsigned long)(x)-PAGE_OFFSET)
+-#define __va(x)			((void *)((unsigned long)(x)+PAGE_OFFSET))
+-#define MAP_NR(addr)		((__pa(addr)-__MEMORY_START) >> PAGE_SHIFT)
+-#define VALID_PAGE(page)	((page - mem_map) < max_mapnr)
+-
+-#define phys_to_page(phys)	(mem_map + (((phys) - __MEMORY_START) >> PAGE_SHIFT))
+-#define page_to_phys(page)	(((page - mem_map) << PAGE_SHIFT) + __MEMORY_START)
+-
+-/* PFN start number, because of __MEMORY_START */
+-#define PFN_START		(__MEMORY_START >> PAGE_SHIFT)
+-#define ARCH_PFN_OFFSET		(PFN_START)
+-#define virt_to_page(kaddr)	pfn_to_page(__pa(kaddr) >> PAGE_SHIFT)
+-#define pfn_valid(pfn)		(((pfn) - PFN_START) < max_mapnr)
+-#define virt_addr_valid(kaddr)	pfn_valid(__pa(kaddr) >> PAGE_SHIFT)
+-
+-#define VM_DATA_DEFAULT_FLAGS	(VM_READ | VM_WRITE | VM_EXEC | \
+-				 VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
+-
+-#include <asm-generic/memory_model.h>
+-#include <asm-generic/page.h>
+-
+-#endif /* __KERNEL__ */
+-#endif /* __ASM_SH64_PAGE_H */
+diff --git a/include/asm-sh64/param.h b/include/asm-sh64/param.h
+deleted file mode 100644
+index f409adb..0000000
+--- a/include/asm-sh64/param.h
++++ /dev/null
+@@ -1,42 +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.
+- *
+- * include/asm-sh64/param.h
+- *
+- * Copyright (C) 2000, 2001  Paolo Alberelli
+- * Copyright (C) 2003  Paul Mundt
+- *
+- */
+-#ifndef __ASM_SH64_PARAM_H
+-#define __ASM_SH64_PARAM_H
+-
+-
+-#ifdef __KERNEL__
+-# ifdef CONFIG_SH_WDT
+-#  define HZ		1000		/* Needed for high-res WOVF */
+-# else
+-#  define HZ		100
+-# endif
+-# define USER_HZ	100		/* User interfaces are in "ticks" */
+-# define CLOCKS_PER_SEC	(USER_HZ)	/* frequency at which times() counts */
+-#endif
 -
--		sysfs_create_file(&p->kobj, &addpartattr);
-+		err = sysfs_create_file(&p->dev.kobj, &addpartattr);
- 	}
--	partition_sysfs_add_subdir(p);
--	disk->part[part-1] = p;
--}
- 
--static char *make_block_name(struct gendisk *disk)
--{
--	char *name;
--	static char *block_str = "block:";
--	int size;
--	char *s;
+-#ifndef HZ
+-#define HZ 100
+-#endif
 -
--	size = strlen(block_str) + strlen(disk->disk_name) + 1;
--	name = kmalloc(size, GFP_KERNEL);
--	if (!name)
--		return NULL;
--	strcpy(name, block_str);
--	strcat(name, disk->disk_name);
--	/* ewww... some of these buggers have / in name... */
--	s = strchr(name, '/');
--	if (s)
--		*s = '!';
--	return name;
--}
+-#define EXEC_PAGESIZE	4096
 -
--static int disk_sysfs_symlinks(struct gendisk *disk)
+-#ifndef NGROUPS
+-#define NGROUPS		32
+-#endif
+-
+-#ifndef NOGROUP
+-#define NOGROUP		(-1)
+-#endif
+-
+-#define MAXHOSTNAMELEN	64	/* max length of hostname */
+-
+-#endif /* __ASM_SH64_PARAM_H */
+diff --git a/include/asm-sh64/pci.h b/include/asm-sh64/pci.h
+deleted file mode 100644
+index 18055db..0000000
+--- a/include/asm-sh64/pci.h
++++ /dev/null
+@@ -1,102 +0,0 @@
+-#ifndef __ASM_SH64_PCI_H
+-#define __ASM_SH64_PCI_H
+-
+-#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 */
+-
+-#define pcibios_assign_all_busses()     1
+-
+-/*
+- * These are currently the correct values for the STM overdrive board
+- * We need some way of setting this on a board specific way, it will
+- * not be the same on other boards I think
+- */
+-#if defined(CONFIG_CPU_SUBTYPE_SH5_101) || defined(CONFIG_CPU_SUBTYPE_SH5_103)
+-#define PCIBIOS_MIN_IO          0x2000
+-#define PCIBIOS_MIN_MEM         0x40000000
+-#endif
+-
+-extern void pcibios_set_master(struct pci_dev *dev);
+-
+-/*
+- * Set penalize isa irq function
+- */
+-static inline void pcibios_penalize_isa_irq(int irq, int active)
 -{
--	struct device *target = get_device(disk->driverfs_dev);
--	int err;
--	char *disk_name = NULL;
+-	/* We don't do dynamic PCI IRQ allocation */
+-}
 -
--	if (target) {
--		disk_name = make_block_name(disk);
--		if (!disk_name) {
--			err = -ENOMEM;
--			goto err_out;
--		}
+-/* Dynamic DMA mapping stuff.
+- * SuperH has everything mapped statically like x86.
+- */
 -
--		err = sysfs_create_link(&disk->kobj, &target->kobj, "device");
--		if (err)
--			goto err_out_disk_name;
+-/* The PCI address space does equal the physical memory
+- * address space.  The networking and block device layers use
+- * this boolean for bounce buffer decisions.
+- */
+-#define PCI_DMA_BUS_IS_PHYS	(1)
 -
--		err = sysfs_create_link(&target->kobj, &disk->kobj, disk_name);
--		if (err)
--			goto err_out_dev_link;
--	}
+-#include <linux/types.h>
+-#include <linux/slab.h>
+-#include <asm/scatterlist.h>
+-#include <linux/string.h>
+-#include <asm/io.h>
 -
--	err = sysfs_create_link(&disk->kobj, &block_subsys.kobj,
--				"subsystem");
--	if (err)
--		goto err_out_disk_name_lnk;
+-/* pci_unmap_{single,page} being a nop depends upon the
+- * configuration.
+- */
+-#ifdef CONFIG_SH_PCIDMA_NONCOHERENT
+-#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)	\
+-	dma_addr_t ADDR_NAME;
+-#define DECLARE_PCI_UNMAP_LEN(LEN_NAME)		\
+-	__u32 LEN_NAME;
+-#define pci_unmap_addr(PTR, ADDR_NAME)			\
+-	((PTR)->ADDR_NAME)
+-#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL)		\
+-	(((PTR)->ADDR_NAME) = (VAL))
+-#define pci_unmap_len(PTR, LEN_NAME)			\
+-	((PTR)->LEN_NAME)
+-#define pci_unmap_len_set(PTR, LEN_NAME, VAL)		\
+-	(((PTR)->LEN_NAME) = (VAL))
+-#else
+-#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)
+-#define DECLARE_PCI_UNMAP_LEN(LEN_NAME)
+-#define pci_unmap_addr(PTR, ADDR_NAME)		(0)
+-#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL)	do { } while (0)
+-#define pci_unmap_len(PTR, LEN_NAME)		(0)
+-#define pci_unmap_len_set(PTR, LEN_NAME, VAL)	do { } while (0)
+-#endif
 -
--	kfree(disk_name);
+-#ifdef CONFIG_PCI
+-static inline void pci_dma_burst_advice(struct pci_dev *pdev,
+-					enum pci_dma_burst_strategy *strat,
+-					unsigned long *strategy_parameter)
+-{
+-	*strat = PCI_DMA_BURST_INFINITY;
+-	*strategy_parameter = ~0UL;
+-}
+-#endif
 -
--	return 0;
+-/* Board-specific fixup routines. */
+-extern void pcibios_fixup(void);
+-extern void pcibios_fixup_irqs(void);
 -
--err_out_disk_name_lnk:
--	if (target) {
--		sysfs_remove_link(&target->kobj, disk_name);
--err_out_dev_link:
--		sysfs_remove_link(&disk->kobj, "device");
--err_out_disk_name:
--		kfree(disk_name);
--err_out:
--		put_device(target);
--	}
--	return err;
-+	/* suppress uevent if the disk supresses it */
-+	if (!disk->dev.uevent_suppress)
-+		kobject_uevent(&p->dev.kobj, KOBJ_ADD);
- }
- 
- /* Not exported, helper to add_disk(). */
-@@ -479,19 +374,29 @@ void register_disk(struct gendisk *disk)
- 	struct hd_struct *p;
- 	int err;
- 
--	kobject_set_name(&disk->kobj, "%s", disk->disk_name);
--	/* ewww... some of these buggers have / in name... */
--	s = strchr(disk->kobj.k_name, '/');
-+	disk->dev.parent = disk->driverfs_dev;
-+	disk->dev.devt = MKDEV(disk->major, disk->first_minor);
-+
-+	strlcpy(disk->dev.bus_id, disk->disk_name, KOBJ_NAME_LEN);
-+	/* ewww... some of these buggers have / in the name... */
-+	s = strchr(disk->dev.bus_id, '/');
- 	if (s)
- 		*s = '!';
--	if ((err = kobject_add(&disk->kobj)))
-+
-+	/* delay uevents, until we scanned partition table */
-+	disk->dev.uevent_suppress = 1;
-+
-+	if (device_add(&disk->dev))
- 		return;
--	err = disk_sysfs_symlinks(disk);
-+#ifndef CONFIG_SYSFS_DEPRECATED
-+	err = sysfs_create_link(block_depr, &disk->dev.kobj,
-+				kobject_name(&disk->dev.kobj));
- 	if (err) {
--		kobject_del(&disk->kobj);
-+		device_del(&disk->dev);
- 		return;
- 	}
-- 	disk_sysfs_add_subdirs(disk);
-+#endif
-+	disk_sysfs_add_subdirs(disk);
- 
- 	/* No minors to use for partitions */
- 	if (disk->minors == 1)
-@@ -505,25 +410,23 @@ void register_disk(struct gendisk *disk)
- 	if (!bdev)
- 		goto exit;
- 
--	/* scan partition table, but suppress uevents */
- 	bdev->bd_invalidated = 1;
--	disk->part_uevent_suppress = 1;
- 	err = blkdev_get(bdev, FMODE_READ, 0);
--	disk->part_uevent_suppress = 0;
- 	if (err < 0)
- 		goto exit;
- 	blkdev_put(bdev);
- 
- exit:
--	/* announce disk after possible partitions are already created */
--	kobject_uevent(&disk->kobj, KOBJ_ADD);
-+	/* announce disk after possible partitions are created */
-+	disk->dev.uevent_suppress = 0;
-+	kobject_uevent(&disk->dev.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->kobj, KOBJ_ADD);
-+		kobject_uevent(&p->dev.kobj, KOBJ_ADD);
- 	}
- }
- 
-@@ -602,19 +505,11 @@ void del_gendisk(struct gendisk *disk)
- 	disk_stat_set_all(disk, 0);
- 	disk->stamp = 0;
- 
--	kobject_uevent(&disk->kobj, KOBJ_REMOVE);
--	kobject_unregister(disk->holder_dir);
--	kobject_unregister(disk->slave_dir);
--	if (disk->driverfs_dev) {
--		char *disk_name = make_block_name(disk);
--		sysfs_remove_link(&disk->kobj, "device");
--		if (disk_name) {
--			sysfs_remove_link(&disk->driverfs_dev->kobj, disk_name);
--			kfree(disk_name);
--		}
--		put_device(disk->driverfs_dev);
--		disk->driverfs_dev = NULL;
--	}
--	sysfs_remove_link(&disk->kobj, "subsystem");
--	kobject_del(&disk->kobj);
-+	kobject_put(disk->holder_dir);
-+	kobject_put(disk->slave_dir);
-+	disk->driverfs_dev = NULL;
-+#ifndef CONFIG_SYSFS_DEPRECATED
-+	sysfs_remove_link(block_depr, disk->dev.bus_id);
-+#endif
-+	device_del(&disk->dev);
- }
-diff --git a/fs/proc/base.c b/fs/proc/base.c
-index 7411bfb..91fa8e6 100644
---- a/fs/proc/base.c
-+++ b/fs/proc/base.c
-@@ -310,6 +310,77 @@ static int proc_pid_schedstat(struct task_struct *task, char *buffer)
- }
- #endif
- 
-+#ifdef CONFIG_LATENCYTOP
-+static int lstats_show_proc(struct seq_file *m, void *v)
-+{
-+	int i;
-+	struct task_struct *task = m->private;
-+	seq_puts(m, "Latency Top version : v0.1\n");
-+
-+	for (i = 0; i < 32; i++) {
-+		if (task->latency_record[i].backtrace[0]) {
-+			int q;
-+			seq_printf(m, "%i %li %li ",
-+				task->latency_record[i].count,
-+				task->latency_record[i].time,
-+				task->latency_record[i].max);
-+			for (q = 0; q < LT_BACKTRACEDEPTH; q++) {
-+				char sym[KSYM_NAME_LEN];
-+				char *c;
-+				if (!task->latency_record[i].backtrace[q])
-+					break;
-+				if (task->latency_record[i].backtrace[q] == ULONG_MAX)
-+					break;
-+				sprint_symbol(sym, task->latency_record[i].backtrace[q]);
-+				c = strchr(sym, '+');
-+				if (c)
-+					*c = 0;
-+				seq_printf(m, "%s ", sym);
-+			}
-+			seq_printf(m, "\n");
-+		}
-+
-+	}
-+	return 0;
-+}
-+
-+static int lstats_open(struct inode *inode, struct file *file)
-+{
-+	int ret;
-+	struct seq_file *m;
-+	struct task_struct *task = get_proc_task(inode);
-+
-+	ret = single_open(file, lstats_show_proc, NULL);
-+	if (!ret) {
-+		m = file->private_data;
-+		m->private = task;
-+	}
-+	return ret;
-+}
-+
-+static ssize_t lstats_write(struct file *file, const char __user *buf,
-+			    size_t count, loff_t *offs)
-+{
-+	struct seq_file *m;
-+	struct task_struct *task;
-+
-+	m = file->private_data;
-+	task = m->private;
-+	clear_all_latency_tracing(task);
-+
-+	return count;
-+}
-+
-+static const struct file_operations proc_lstats_operations = {
-+	.open		= lstats_open,
-+	.read		= seq_read,
-+	.write		= lstats_write,
-+	.llseek		= seq_lseek,
-+	.release	= single_release,
-+};
-+
-+#endif
-+
- /* The badness from the OOM killer */
- unsigned long badness(struct task_struct *p, unsigned long uptime);
- static int proc_oom_score(struct task_struct *task, char *buffer)
-@@ -1020,6 +1091,7 @@ static const struct file_operations proc_fault_inject_operations = {
- };
- #endif
- 
-+
- #ifdef CONFIG_SCHED_DEBUG
- /*
-  * Print out various scheduling related per-task fields:
-@@ -2230,6 +2302,9 @@ static const struct pid_entry tgid_base_stuff[] = {
- #ifdef CONFIG_SCHEDSTATS
- 	INF("schedstat",  S_IRUGO, pid_schedstat),
- #endif
-+#ifdef CONFIG_LATENCYTOP
-+	REG("latency",  S_IRUGO, lstats),
-+#endif
- #ifdef CONFIG_PROC_PID_CPUSET
- 	REG("cpuset",     S_IRUGO, cpuset),
- #endif
-@@ -2555,6 +2630,9 @@ static const struct pid_entry tid_base_stuff[] = {
- #ifdef CONFIG_SCHEDSTATS
- 	INF("schedstat", S_IRUGO, pid_schedstat),
- #endif
-+#ifdef CONFIG_LATENCYTOP
-+	REG("latency",  S_IRUGO, lstats),
-+#endif
- #ifdef CONFIG_PROC_PID_CPUSET
- 	REG("cpuset",    S_IRUGO, cpuset),
- #endif
-diff --git a/fs/read_write.c b/fs/read_write.c
-index ea1f94c..c4d3d17 100644
---- a/fs/read_write.c
-+++ b/fs/read_write.c
-@@ -197,25 +197,27 @@ int rw_verify_area(int read_write, struct file *file, loff_t *ppos, size_t count
- {
- 	struct inode *inode;
- 	loff_t pos;
-+	int retval = -EINVAL;
- 
- 	inode = file->f_path.dentry->d_inode;
- 	if (unlikely((ssize_t) count < 0))
--		goto Einval;
-+		return retval;
- 	pos = *ppos;
- 	if (unlikely((pos < 0) || (loff_t) (pos + count) < 0))
--		goto Einval;
-+		return retval;
- 
- 	if (unlikely(inode->i_flock && mandatory_lock(inode))) {
--		int retval = locks_mandatory_area(
-+		retval = locks_mandatory_area(
- 			read_write == READ ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE,
- 			inode, file, pos, count);
- 		if (retval < 0)
- 			return retval;
- 	}
-+	retval = security_file_permission(file,
-+				read_write == READ ? MAY_READ : MAY_WRITE);
-+	if (retval)
-+		return retval;
- 	return count > MAX_RW_COUNT ? MAX_RW_COUNT : count;
+-#ifdef CONFIG_PCI_AUTO
+-extern int pciauto_assign_resources(int busno, struct pci_channel *hose);
+-#endif
 -
--Einval:
--	return -EINVAL;
- }
- 
- static void wait_on_retry_sync_kiocb(struct kiocb *iocb)
-@@ -267,18 +269,15 @@ ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos)
- 	ret = rw_verify_area(READ, file, pos, count);
- 	if (ret >= 0) {
- 		count = ret;
--		ret = security_file_permission (file, MAY_READ);
--		if (!ret) {
--			if (file->f_op->read)
--				ret = file->f_op->read(file, buf, count, pos);
--			else
--				ret = do_sync_read(file, buf, count, pos);
--			if (ret > 0) {
--				fsnotify_access(file->f_path.dentry);
--				add_rchar(current, ret);
--			}
--			inc_syscr(current);
-+		if (file->f_op->read)
-+			ret = file->f_op->read(file, buf, count, pos);
-+		else
-+			ret = do_sync_read(file, buf, count, pos);
-+		if (ret > 0) {
-+			fsnotify_access(file->f_path.dentry);
-+			add_rchar(current, ret);
- 		}
-+		inc_syscr(current);
- 	}
- 
- 	return ret;
-@@ -325,18 +324,15 @@ ssize_t vfs_write(struct file *file, const char __user *buf, size_t count, loff_
- 	ret = rw_verify_area(WRITE, file, pos, count);
- 	if (ret >= 0) {
- 		count = ret;
--		ret = security_file_permission (file, MAY_WRITE);
--		if (!ret) {
--			if (file->f_op->write)
--				ret = file->f_op->write(file, buf, count, pos);
--			else
--				ret = do_sync_write(file, buf, count, pos);
--			if (ret > 0) {
--				fsnotify_modify(file->f_path.dentry);
--				add_wchar(current, ret);
--			}
--			inc_syscw(current);
-+		if (file->f_op->write)
-+			ret = file->f_op->write(file, buf, count, pos);
-+		else
-+			ret = do_sync_write(file, buf, count, pos);
-+		if (ret > 0) {
-+			fsnotify_modify(file->f_path.dentry);
-+			add_wchar(current, ret);
- 		}
-+		inc_syscw(current);
- 	}
- 
- 	return ret;
-@@ -603,9 +599,6 @@ static ssize_t do_readv_writev(int type, struct file *file,
- 	ret = rw_verify_area(type, file, pos, tot_len);
- 	if (ret < 0)
- 		goto out;
--	ret = security_file_permission(file, type == READ ? MAY_READ : MAY_WRITE);
--	if (ret)
--		goto out;
- 
- 	fnv = NULL;
- 	if (type == READ) {
-@@ -737,10 +730,6 @@ static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos,
- 		goto fput_in;
- 	count = retval;
- 
--	retval = security_file_permission (in_file, MAY_READ);
--	if (retval)
--		goto fput_in;
+-#endif /* __KERNEL__ */
 -
- 	/*
- 	 * Get output file, and verify that it is ok..
- 	 */
-@@ -759,10 +748,6 @@ static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos,
- 		goto fput_out;
- 	count = retval;
- 
--	retval = security_file_permission (out_file, MAY_WRITE);
--	if (retval)
--		goto fput_out;
+-/* generic pci stuff */
+-#include <asm-generic/pci.h>
 -
- 	if (!max)
- 		max = min(in_inode->i_sb->s_maxbytes, out_inode->i_sb->s_maxbytes);
- 
-diff --git a/fs/splice.c b/fs/splice.c
-index 6bdcb61..56b802b 100644
---- a/fs/splice.c
-+++ b/fs/splice.c
-@@ -908,10 +908,6 @@ static long do_splice_from(struct pipe_inode_info *pipe, struct file *out,
- 	if (unlikely(ret < 0))
- 		return ret;
- 
--	ret = security_file_permission(out, MAY_WRITE);
--	if (unlikely(ret < 0))
--		return ret;
+-/* generic DMA-mapping stuff */
+-#include <asm-generic/pci-dma-compat.h>
 -
- 	return out->f_op->splice_write(pipe, out, ppos, len, flags);
- }
- 
-@@ -934,10 +930,6 @@ static long do_splice_to(struct file *in, loff_t *ppos,
- 	if (unlikely(ret < 0))
- 		return ret;
- 
--	ret = security_file_permission(in, MAY_READ);
--	if (unlikely(ret < 0))
--		return ret;
+-#endif /* __ASM_SH64_PCI_H */
 -
- 	return in->f_op->splice_read(in, ppos, pipe, len, flags);
- }
- 
-diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c
-index f281cc6..4948d9b 100644
---- a/fs/sysfs/dir.c
-+++ b/fs/sysfs/dir.c
-@@ -440,7 +440,7 @@ int sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd)
- /**
-  *	sysfs_remove_one - remove sysfs_dirent from parent
-  *	@acxt: addrm context to use
-- *	@sd: sysfs_dirent to be added
-+ *	@sd: sysfs_dirent to be removed
-  *
-  *	Mark @sd removed and drop nlink of parent inode if @sd is a
-  *	directory.  @sd is unlinked from the children list.
-diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c
-index 4045bdc..a271c87 100644
---- a/fs/sysfs/file.c
-+++ b/fs/sysfs/file.c
-@@ -20,43 +20,6 @@
- 
- #include "sysfs.h"
- 
--#define to_sattr(a) container_of(a,struct subsys_attribute, attr)
+diff --git a/include/asm-sh64/percpu.h b/include/asm-sh64/percpu.h
+deleted file mode 100644
+index a01d16c..0000000
+--- a/include/asm-sh64/percpu.h
++++ /dev/null
+@@ -1,6 +0,0 @@
+-#ifndef __ASM_SH64_PERCPU
+-#define __ASM_SH64_PERCPU
+-
+-#include <asm-generic/percpu.h>
+-
+-#endif /* __ASM_SH64_PERCPU */
+diff --git a/include/asm-sh64/pgalloc.h b/include/asm-sh64/pgalloc.h
+deleted file mode 100644
+index 6eccab7..0000000
+--- a/include/asm-sh64/pgalloc.h
++++ /dev/null
+@@ -1,125 +0,0 @@
+-#ifndef __ASM_SH64_PGALLOC_H
+-#define __ASM_SH64_PGALLOC_H
 -
 -/*
-- * Subsystem file operations.
-- * These operations allow subsystems to have files that can be 
-- * read/written. 
+- * 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/asm-sh64/pgalloc.h
+- *
+- * Copyright (C) 2000, 2001  Paolo Alberelli
+- * Copyright (C) 2003, 2004  Paul Mundt
+- * Copyright (C) 2003, 2004  Richard Curnow
+- *
 - */
--static ssize_t 
--subsys_attr_show(struct kobject * kobj, struct attribute * attr, char * page)
+-
+-#include <linux/mm.h>
+-#include <linux/quicklist.h>
+-#include <asm/page.h>
+-
+-static inline void pgd_init(unsigned long page)
 -{
--	struct kset *kset = to_kset(kobj);
--	struct subsys_attribute * sattr = to_sattr(attr);
--	ssize_t ret = -EIO;
+-	unsigned long *pgd = (unsigned long *)page;
+-	extern pte_t empty_bad_pte_table[PTRS_PER_PTE];
+-	int i;
 -
--	if (sattr->show)
--		ret = sattr->show(kset, page);
+-	for (i = 0; i < USER_PTRS_PER_PGD; i++)
+-		pgd[i] = (unsigned long)empty_bad_pte_table;
+-}
+-
+-/*
+- * Allocate and free page tables. The xxx_kernel() versions are
+- * used to allocate a kernel page table - this turns on ASN bits
+- * if any.
+- */
+-
+-static inline pgd_t *get_pgd_slow(void)
+-{
+-	unsigned int pgd_size = (USER_PTRS_PER_PGD * sizeof(pgd_t));
+-	pgd_t *ret = kmalloc(pgd_size, GFP_KERNEL);
 -	return ret;
 -}
 -
--static ssize_t 
--subsys_attr_store(struct kobject * kobj, struct attribute * attr, 
--		  const char * page, size_t count)
+-static inline pgd_t *pgd_alloc(struct mm_struct *mm)
 -{
--	struct kset *kset = to_kset(kobj);
--	struct subsys_attribute * sattr = to_sattr(attr);
--	ssize_t ret = -EIO;
+-	return quicklist_alloc(0, GFP_KERNEL, NULL);
+-}
 -
--	if (sattr->store)
--		ret = sattr->store(kset, page, count);
--	return ret;
+-static inline void pgd_free(pgd_t *pgd)
+-{
+-	quicklist_free(0, NULL, pgd);
 -}
 -
--static struct sysfs_ops subsys_sysfs_ops = {
--	.show	= subsys_attr_show,
--	.store	= subsys_attr_store,
--};
+-static inline struct page *pte_alloc_one(struct mm_struct *mm,
+-					 unsigned long address)
+-{
+-	void *pg = quicklist_alloc(0, GFP_KERNEL, NULL);
+-	return pg ? virt_to_page(pg) : NULL;
+-}
 -
- /*
-  * There's one sysfs_buffer for each open file and one
-  * sysfs_open_dirent for each sysfs_dirent with one or more open
-@@ -66,7 +29,7 @@ static struct sysfs_ops subsys_sysfs_ops = {
-  * sysfs_dirent->s_attr.open points to sysfs_open_dirent.  s_attr.open
-  * is protected by sysfs_open_dirent_lock.
-  */
--static spinlock_t sysfs_open_dirent_lock = SPIN_LOCK_UNLOCKED;
-+static DEFINE_SPINLOCK(sysfs_open_dirent_lock);
- 
- struct sysfs_open_dirent {
- 	atomic_t		refcnt;
-@@ -354,31 +317,23 @@ static int sysfs_open_file(struct inode *inode, struct file *file)
- {
- 	struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;
- 	struct kobject *kobj = attr_sd->s_parent->s_dir.kobj;
--	struct sysfs_buffer * buffer;
--	struct sysfs_ops * ops = NULL;
--	int error;
-+	struct sysfs_buffer *buffer;
-+	struct sysfs_ops *ops;
-+	int error = -EACCES;
- 
- 	/* need attr_sd for attr and ops, its parent for kobj */
- 	if (!sysfs_get_active_two(attr_sd))
- 		return -ENODEV;
- 
--	/* if the kobject has no ktype, then we assume that it is a subsystem
--	 * itself, and use ops for it.
--	 */
--	if (kobj->kset && kobj->kset->ktype)
--		ops = kobj->kset->ktype->sysfs_ops;
--	else if (kobj->ktype)
-+	/* every kobject with an attribute needs a ktype assigned */
-+	if (kobj->ktype && kobj->ktype->sysfs_ops)
- 		ops = kobj->ktype->sysfs_ops;
--	else
--		ops = &subsys_sysfs_ops;
+-static inline void pte_free_kernel(pte_t *pte)
+-{
+-	quicklist_free(0, NULL, pte);
+-}
 -
--	error = -EACCES;
+-static inline void pte_free(struct page *pte)
+-{
+-	quicklist_free_page(0, NULL, pte);
+-}
 -
--	/* No sysfs operations, either from having no subsystem,
--	 * or the subsystem have no operations.
+-static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm,
+-					   unsigned long address)
+-{
+-	return quicklist_alloc(0, GFP_KERNEL, NULL);
+-}
+-
+-#define __pte_free_tlb(tlb,pte) tlb_remove_page((tlb),(pte))
+-
+-/*
+- * allocating and freeing a pmd is trivial: the 1-entry pmd is
+- * inside the pgd, so has no extra memory associated with it.
+- */
+-
+-#if defined(CONFIG_SH64_PGTABLE_2_LEVEL)
+-
+-#define pmd_alloc_one(mm, addr)		({ BUG(); ((pmd_t *)2); })
+-#define pmd_free(x)			do { } while (0)
+-#define pgd_populate(mm, pmd, pte)	BUG()
+-#define __pte_free_tlb(tlb,pte)		tlb_remove_page((tlb),(pte))
+-#define __pmd_free_tlb(tlb,pmd)		do { } while (0)
+-
+-#elif defined(CONFIG_SH64_PGTABLE_3_LEVEL)
+-
+-static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long address)
+-{
+-	return quicklist_alloc(0, GFP_KERNEL, NULL);
+-}
+-
+-static inline void pmd_free(pmd_t *pmd)
+-{
+-	quicklist_free(0, NULL, pmd);
+-}
+-
+-#define pgd_populate(mm, pgd, pmd)	pgd_set(pgd, pmd)
+-#define __pmd_free_tlb(tlb,pmd)		pmd_free(pmd)
+-
+-#else
+-#error "No defined page table size"
+-#endif
+-
+-#define pmd_populate_kernel(mm, pmd, pte) \
+-	set_pmd(pmd, __pmd(_PAGE_TABLE + (unsigned long) (pte)))
+-
+-static inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd,
+-				struct page *pte)
+-{
+-	set_pmd(pmd, __pmd(_PAGE_TABLE + (unsigned long) page_address (pte)));
+-}
+-
+-static inline void check_pgt_cache(void)
+-{
+-	quicklist_trim(0, NULL, 25, 16);
+-}
+-
+-#endif /* __ASM_SH64_PGALLOC_H */
+diff --git a/include/asm-sh64/pgtable.h b/include/asm-sh64/pgtable.h
+deleted file mode 100644
+index 3488fe3..0000000
+--- a/include/asm-sh64/pgtable.h
++++ /dev/null
+@@ -1,496 +0,0 @@
+-#ifndef __ASM_SH64_PGTABLE_H
+-#define __ASM_SH64_PGTABLE_H
+-
+-#include <asm-generic/4level-fixup.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.
+- *
+- * include/asm-sh64/pgtable.h
+- *
+- * Copyright (C) 2000, 2001  Paolo Alberelli
+- * Copyright (C) 2003, 2004  Paul Mundt
+- * Copyright (C) 2003, 2004  Richard Curnow
+- *
+- * This file contains the functions and defines necessary to modify and use
+- * the SuperH page table tree.
+- */
+-
+-#ifndef __ASSEMBLY__
+-#include <asm/processor.h>
+-#include <asm/page.h>
+-#include <linux/threads.h>
+-
+-struct vm_area_struct;
+-
+-extern void paging_init(void);
+-
+-/* We provide our own get_unmapped_area to avoid cache synonym issue */
+-#define HAVE_ARCH_UNMAPPED_AREA
+-
+-/*
+- * Basically we have the same two-level (which is the logical three level
+- * Linux page table layout folded) page tables as the i386.
+- */
+-
+-/*
+- * ZERO_PAGE is a global shared page that is always zero: used
+- * for zero-mapped memory areas etc..
+- */
+-extern unsigned char empty_zero_page[PAGE_SIZE];
+-#define ZERO_PAGE(vaddr) (mem_map + MAP_NR(empty_zero_page))
+-
+-#endif /* !__ASSEMBLY__ */
+-
+-/*
+- * NEFF and NPHYS related defines.
+- * FIXME : These need to be model-dependent.  For now this is OK, SH5-101 and SH5-103
+- * implement 32 bits effective and 32 bits physical.  But future implementations may
+- * extend beyond this.
+- */
+-#define NEFF		32
+-#define	NEFF_SIGN	(1LL << (NEFF - 1))
+-#define	NEFF_MASK	(-1LL << NEFF)
+-
+-#define NPHYS		32
+-#define	NPHYS_SIGN	(1LL << (NPHYS - 1))
+-#define	NPHYS_MASK	(-1LL << NPHYS)
+-
+-/* Typically 2-level is sufficient up to 32 bits of virtual address space, beyond
+-   that 3-level would be appropriate. */
+-#if defined(CONFIG_SH64_PGTABLE_2_LEVEL)
+-/* For 4k pages, this contains 512 entries, i.e. 9 bits worth of address. */
+-#define PTRS_PER_PTE	((1<<PAGE_SHIFT)/sizeof(unsigned long long))
+-#define PTE_MAGNITUDE	3	      /* sizeof(unsigned long long) magnit. */
+-#define PTE_SHIFT	PAGE_SHIFT
+-#define PTE_BITS	(PAGE_SHIFT - PTE_MAGNITUDE)
+-
+-/* top level: PMD. */
+-#define PGDIR_SHIFT	(PTE_SHIFT + PTE_BITS)
+-#define PGD_BITS	(NEFF - PGDIR_SHIFT)
+-#define PTRS_PER_PGD	(1<<PGD_BITS)
+-
+-/* middle level: PMD. This doesn't do anything for the 2-level case. */
+-#define PTRS_PER_PMD	(1)
+-
+-#define PGDIR_SIZE	(1UL << PGDIR_SHIFT)
+-#define PGDIR_MASK	(~(PGDIR_SIZE-1))
+-#define PMD_SHIFT	PGDIR_SHIFT
+-#define PMD_SIZE	PGDIR_SIZE
+-#define PMD_MASK	PGDIR_MASK
+-
+-#elif defined(CONFIG_SH64_PGTABLE_3_LEVEL)
+-/*
+- * three-level asymmetric paging structure: PGD is top level.
+- * The asymmetry comes from 32-bit pointers and 64-bit PTEs.
+- */
+-/* bottom level: PTE. It's 9 bits = 512 pointers */
+-#define PTRS_PER_PTE	((1<<PAGE_SHIFT)/sizeof(unsigned long long))
+-#define PTE_MAGNITUDE	3	      /* sizeof(unsigned long long) magnit. */
+-#define PTE_SHIFT	PAGE_SHIFT
+-#define PTE_BITS	(PAGE_SHIFT - PTE_MAGNITUDE)
+-
+-/* middle level: PMD. It's 10 bits = 1024 pointers */
+-#define PTRS_PER_PMD	((1<<PAGE_SHIFT)/sizeof(unsigned long long *))
+-#define PMD_MAGNITUDE	2	      /* sizeof(unsigned long long *) magnit. */
+-#define PMD_SHIFT	(PTE_SHIFT + PTE_BITS)
+-#define PMD_BITS	(PAGE_SHIFT - PMD_MAGNITUDE)
+-
+-/* top level: PMD. It's 1 bit = 2 pointers */
+-#define PGDIR_SHIFT	(PMD_SHIFT + PMD_BITS)
+-#define PGD_BITS	(NEFF - PGDIR_SHIFT)
+-#define PTRS_PER_PGD	(1<<PGD_BITS)
+-
+-#define PMD_SIZE	(1UL << PMD_SHIFT)
+-#define PMD_MASK	(~(PMD_SIZE-1))
+-#define PGDIR_SIZE	(1UL << PGDIR_SHIFT)
+-#define PGDIR_MASK	(~(PGDIR_SIZE-1))
+-
+-#else
+-#error "No defined number of page table levels"
+-#endif
+-
+-/*
+- * Error outputs.
+- */
+-#define pte_ERROR(e) \
+-	printk("%s:%d: bad pte %016Lx.\n", __FILE__, __LINE__, pte_val(e))
+-#define pmd_ERROR(e) \
+-	printk("%s:%d: bad pmd %08lx.\n", __FILE__, __LINE__, pmd_val(e))
+-#define pgd_ERROR(e) \
+-	printk("%s:%d: bad pgd %08lx.\n", __FILE__, __LINE__, pgd_val(e))
+-
+-/*
+- * Table setting routines. Used within arch/mm only.
+- */
+-#define set_pgd(pgdptr, pgdval) (*(pgdptr) = pgdval)
+-#define set_pmd(pmdptr, pmdval) (*(pmdptr) = pmdval)
+-
+-static __inline__ void set_pte(pte_t *pteptr, pte_t pteval)
+-{
+-	unsigned long long x = ((unsigned long long) pteval.pte);
+-	unsigned long long *xp = (unsigned long long *) pteptr;
+-	/*
+-	 * Sign-extend based on NPHYS.
 -	 */
--	if (!ops)
-+	else {
-+		printk(KERN_ERR "missing sysfs attribute operations for "
-+		       "kobject: %s\n", kobject_name(kobj));
-+		WARN_ON(1);
- 		goto err_out;
-+	}
- 
- 	/* File needs write support.
- 	 * The inode's perms must say it's ok, 
-@@ -568,7 +523,11 @@ int sysfs_add_file_to_group(struct kobject *kobj,
- 	struct sysfs_dirent *dir_sd;
- 	int error;
- 
--	dir_sd = sysfs_get_dirent(kobj->sd, group);
-+	if (group)
-+		dir_sd = sysfs_get_dirent(kobj->sd, group);
-+	else
-+		dir_sd = sysfs_get(kobj->sd);
-+
- 	if (!dir_sd)
- 		return -ENOENT;
- 
-@@ -656,7 +615,10 @@ void sysfs_remove_file_from_group(struct kobject *kobj,
- {
- 	struct sysfs_dirent *dir_sd;
- 
--	dir_sd = sysfs_get_dirent(kobj->sd, group);
-+	if (group)
-+		dir_sd = sysfs_get_dirent(kobj->sd, group);
-+	else
-+		dir_sd = sysfs_get(kobj->sd);
- 	if (dir_sd) {
- 		sysfs_hash_and_remove(dir_sd, attr->name);
- 		sysfs_put(dir_sd);
-diff --git a/fs/sysfs/group.c b/fs/sysfs/group.c
-index d197237..0871c3d 100644
---- a/fs/sysfs/group.c
-+++ b/fs/sysfs/group.c
-@@ -16,25 +16,31 @@
- #include "sysfs.h"
- 
- 
--static void remove_files(struct sysfs_dirent *dir_sd,
-+static void remove_files(struct sysfs_dirent *dir_sd, struct kobject *kobj,
- 			 const struct attribute_group *grp)
- {
- 	struct attribute *const* attr;
-+	int i;
- 
--	for (attr = grp->attrs; *attr; attr++)
--		sysfs_hash_and_remove(dir_sd, (*attr)->name);
-+	for (i = 0, attr = grp->attrs; *attr; i++, attr++)
-+		if (!grp->is_visible ||
-+		    grp->is_visible(kobj, *attr, i))
-+			sysfs_hash_and_remove(dir_sd, (*attr)->name);
- }
- 
--static int create_files(struct sysfs_dirent *dir_sd,
-+static int create_files(struct sysfs_dirent *dir_sd, struct kobject *kobj,
- 			const struct attribute_group *grp)
- {
- 	struct attribute *const* attr;
--	int error = 0;
-+	int error = 0, i;
- 
--	for (attr = grp->attrs; *attr && !error; attr++)
--		error = sysfs_add_file(dir_sd, *attr, SYSFS_KOBJ_ATTR);
-+	for (i = 0, attr = grp->attrs; *attr && !error; i++, attr++)
-+		if (!grp->is_visible ||
-+		    grp->is_visible(kobj, *attr, i))
-+			error |=
-+				sysfs_add_file(dir_sd, *attr, SYSFS_KOBJ_ATTR);
- 	if (error)
--		remove_files(dir_sd, grp);
-+		remove_files(dir_sd, kobj, grp);
- 	return error;
- }
- 
-@@ -54,7 +60,7 @@ int sysfs_create_group(struct kobject * kobj,
- 	} else
- 		sd = kobj->sd;
- 	sysfs_get(sd);
--	error = create_files(sd, grp);
-+	error = create_files(sd, kobj, grp);
- 	if (error) {
- 		if (grp->name)
- 			sysfs_remove_subdir(sd);
-@@ -75,7 +81,7 @@ void sysfs_remove_group(struct kobject * kobj,
- 	} else
- 		sd = sysfs_get(dir_sd);
- 
--	remove_files(sd, grp);
-+	remove_files(sd, kobj, grp);
- 	if (grp->name)
- 		sysfs_remove_subdir(sd);
- 
-diff --git a/fs/sysfs/symlink.c b/fs/sysfs/symlink.c
-index 3eac20c..5f66c44 100644
---- a/fs/sysfs/symlink.c
-+++ b/fs/sysfs/symlink.c
-@@ -19,39 +19,6 @@
- 
- #include "sysfs.h"
- 
--static int object_depth(struct sysfs_dirent *sd)
+-	*(xp) = (x & NPHYS_SIGN) ? (x | NPHYS_MASK) : x;
+-}
+-#define set_pte_at(mm,addr,ptep,pteval) set_pte(ptep,pteval)
+-
+-static __inline__ void pmd_set(pmd_t *pmdp,pte_t *ptep)
 -{
--	int depth = 0;
+-	pmd_val(*pmdp) = (unsigned long) ptep;
+-}
 -
--	for (; sd->s_parent; sd = sd->s_parent)
--		depth++;
+-/*
+- * PGD defines. Top level.
+- */
 -
--	return depth;
+-/* To find an entry in a generic PGD. */
+-#define pgd_index(address) (((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD-1))
+-#define __pgd_offset(address) pgd_index(address)
+-#define pgd_offset(mm, address) ((mm)->pgd+pgd_index(address))
+-
+-/* To find an entry in a kernel PGD. */
+-#define pgd_offset_k(address) pgd_offset(&init_mm, address)
+-
+-/*
+- * PGD level access routines.
+- *
+- * Note1:
+- * There's no need to use physical addresses since the tree walk is all
+- * in performed in software, until the PTE translation.
+- *
+- * Note 2:
+- * A PGD entry can be uninitialized (_PGD_UNUSED), generically bad,
+- * clear (_PGD_EMPTY), present. When present, lower 3 nibbles contain
+- * _KERNPG_TABLE. Being a kernel virtual pointer also bit 31 must
+- * be 1. Assuming an arbitrary clear value of bit 31 set to 0 and
+- * lower 3 nibbles set to 0xFFF (_PGD_EMPTY) any other value is a
+- * bad pgd that must be notified via printk().
+- *
+- */
+-#define _PGD_EMPTY		0x0
+-
+-#if defined(CONFIG_SH64_PGTABLE_2_LEVEL)
+-static inline int pgd_none(pgd_t pgd)		{ return 0; }
+-static inline int pgd_bad(pgd_t pgd)		{ return 0; }
+-#define pgd_present(pgd) ((pgd_val(pgd) & _PAGE_PRESENT) ? 1 : 0)
+-#define pgd_clear(xx)				do { } while(0)
+-
+-#elif defined(CONFIG_SH64_PGTABLE_3_LEVEL)
+-#define pgd_present(pgd_entry)	(1)
+-#define pgd_none(pgd_entry)	(pgd_val((pgd_entry)) == _PGD_EMPTY)
+-/* TODO: Think later about what a useful definition of 'bad' would be now. */
+-#define pgd_bad(pgd_entry)	(0)
+-#define pgd_clear(pgd_entry_p)	(set_pgd((pgd_entry_p), __pgd(_PGD_EMPTY)))
+-
+-#endif
+-
+-
+-#define pgd_page_vaddr(pgd_entry)	((unsigned long) (pgd_val(pgd_entry) & PAGE_MASK))
+-#define pgd_page(pgd)	(virt_to_page(pgd_val(pgd)))
+-
+-
+-/*
+- * PMD defines. Middle level.
+- */
+-
+-/* PGD to PMD dereferencing */
+-#if defined(CONFIG_SH64_PGTABLE_2_LEVEL)
+-static inline pmd_t * pmd_offset(pgd_t * dir, unsigned long address)
+-{
+-	return (pmd_t *) dir;
+-}
+-#elif defined(CONFIG_SH64_PGTABLE_3_LEVEL)
+-#define __pmd_offset(address) \
+-		(((address) >> PMD_SHIFT) & (PTRS_PER_PMD-1))
+-#define pmd_offset(dir, addr) \
+-		((pmd_t *) ((pgd_val(*(dir))) & PAGE_MASK) + __pmd_offset((addr)))
+-#endif
+-
+-/*
+- * PMD level access routines. Same notes as above.
+- */
+-#define _PMD_EMPTY		0x0
+-/* Either the PMD is empty or present, it's not paged out */
+-#define pmd_present(pmd_entry)	(pmd_val(pmd_entry) & _PAGE_PRESENT)
+-#define pmd_clear(pmd_entry_p)	(set_pmd((pmd_entry_p), __pmd(_PMD_EMPTY)))
+-#define pmd_none(pmd_entry)	(pmd_val((pmd_entry)) == _PMD_EMPTY)
+-#define pmd_bad(pmd_entry)	((pmd_val(pmd_entry) & (~PAGE_MASK & ~_PAGE_USER)) != _KERNPG_TABLE)
+-
+-#define pmd_page_vaddr(pmd_entry) \
+-	((unsigned long) __va(pmd_val(pmd_entry) & PAGE_MASK))
+-
+-#define pmd_page(pmd) \
+-	(virt_to_page(pmd_val(pmd)))
+-
+-/* PMD to PTE dereferencing */
+-#define pte_index(address) \
+-		((address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
+-
+-#define pte_offset_kernel(dir, addr) \
+-		((pte_t *) ((pmd_val(*(dir))) & PAGE_MASK) + pte_index((addr)))
+-
+-#define pte_offset_map(dir,addr)	pte_offset_kernel(dir, addr)
+-#define pte_offset_map_nested(dir,addr)	pte_offset_kernel(dir, addr)
+-#define pte_unmap(pte)		do { } while (0)
+-#define pte_unmap_nested(pte)	do { } while (0)
+-
+-/* Round it up ! */
+-#define USER_PTRS_PER_PGD	((TASK_SIZE+PGDIR_SIZE-1)/PGDIR_SIZE)
+-#define FIRST_USER_ADDRESS	0
+-
+-#ifndef __ASSEMBLY__
+-#define VMALLOC_END	0xff000000
+-#define VMALLOC_START	0xf0000000
+-#define VMALLOC_VMADDR(x) ((unsigned long)(x))
+-
+-#define IOBASE_VADDR	0xff000000
+-#define IOBASE_END	0xffffffff
+-
+-/*
+- * PTEL coherent flags.
+- * See Chapter 17 ST50 CPU Core Volume 1, Architecture.
+- */
+-/* The bits that are required in the SH-5 TLB are placed in the h/w-defined
+-   positions, to avoid expensive bit shuffling on every refill.  The remaining
+-   bits are used for s/w purposes and masked out on each refill.
+-
+-   Note, the PTE slots are used to hold data of type swp_entry_t when a page is
+-   swapped out.  Only the _PAGE_PRESENT flag is significant when the page is
+-   swapped out, and it must be placed so that it doesn't overlap either the
+-   type or offset fields of swp_entry_t.  For x86, offset is at [31:8] and type
+-   at [6:1], with _PAGE_PRESENT at bit 0 for both pte_t and swp_entry_t.  This
+-   scheme doesn't map to SH-5 because bit [0] controls cacheability.  So bit
+-   [2] is used for _PAGE_PRESENT and the type field of swp_entry_t is split
+-   into 2 pieces.  That is handled by SWP_ENTRY and SWP_TYPE below. */
+-#define _PAGE_WT	0x001  /* CB0: if cacheable, 1->write-thru, 0->write-back */
+-#define _PAGE_DEVICE	0x001  /* CB0: if uncacheable, 1->device (i.e. no write-combining or reordering at bus level) */
+-#define _PAGE_CACHABLE	0x002  /* CB1: uncachable/cachable */
+-#define _PAGE_PRESENT	0x004  /* software: page referenced */
+-#define _PAGE_FILE	0x004  /* software: only when !present */
+-#define _PAGE_SIZE0	0x008  /* SZ0-bit : size of page */
+-#define _PAGE_SIZE1	0x010  /* SZ1-bit : size of page */
+-#define _PAGE_SHARED	0x020  /* software: reflects PTEH's SH */
+-#define _PAGE_READ	0x040  /* PR0-bit : read access allowed */
+-#define _PAGE_EXECUTE	0x080  /* PR1-bit : execute access allowed */
+-#define _PAGE_WRITE	0x100  /* PR2-bit : write access allowed */
+-#define _PAGE_USER	0x200  /* PR3-bit : user space access allowed */
+-#define _PAGE_DIRTY	0x400  /* software: page accessed in write */
+-#define _PAGE_ACCESSED	0x800  /* software: page referenced */
+-
+-/* Mask which drops software flags */
+-#define _PAGE_FLAGS_HARDWARE_MASK	0xfffffffffffff3dbLL
+-
+-/*
+- * HugeTLB support
+- */
+-#if defined(CONFIG_HUGETLB_PAGE_SIZE_64K)
+-#define _PAGE_SZHUGE	(_PAGE_SIZE0)
+-#elif defined(CONFIG_HUGETLB_PAGE_SIZE_1MB)
+-#define _PAGE_SZHUGE	(_PAGE_SIZE1)
+-#elif defined(CONFIG_HUGETLB_PAGE_SIZE_512MB)
+-#define _PAGE_SZHUGE	(_PAGE_SIZE0 | _PAGE_SIZE1)
+-#endif
+-
+-/*
+- * Default flags for a Kernel page.
+- * This is fundametally also SHARED because the main use of this define
+- * (other than for PGD/PMD entries) is for the VMALLOC pool which is
+- * contextless.
+- *
+- * _PAGE_EXECUTE is required for modules
+- *
+- */
+-#define _KERNPG_TABLE	(_PAGE_PRESENT | _PAGE_READ | _PAGE_WRITE | \
+-			 _PAGE_EXECUTE | \
+-			 _PAGE_CACHABLE | _PAGE_ACCESSED | _PAGE_DIRTY | \
+-			 _PAGE_SHARED)
+-
+-/* Default flags for a User page */
+-#define _PAGE_TABLE	(_KERNPG_TABLE | _PAGE_USER)
+-
+-#define _PAGE_CHG_MASK	(PTE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY)
+-
+-#define PAGE_NONE	__pgprot(_PAGE_CACHABLE | _PAGE_ACCESSED)
+-#define PAGE_SHARED	__pgprot(_PAGE_PRESENT | _PAGE_READ | _PAGE_WRITE | \
+-				 _PAGE_CACHABLE | _PAGE_ACCESSED | _PAGE_USER | \
+-				 _PAGE_SHARED)
+-/* We need to include PAGE_EXECUTE in PAGE_COPY because it is the default
+- * protection mode for the stack. */
+-#define PAGE_COPY	__pgprot(_PAGE_PRESENT | _PAGE_READ | _PAGE_CACHABLE | \
+-				 _PAGE_ACCESSED | _PAGE_USER | _PAGE_EXECUTE)
+-#define PAGE_READONLY	__pgprot(_PAGE_PRESENT | _PAGE_READ | _PAGE_CACHABLE | \
+-				 _PAGE_ACCESSED | _PAGE_USER)
+-#define PAGE_KERNEL	__pgprot(_KERNPG_TABLE)
+-
+-
+-/*
+- * In ST50 we have full permissions (Read/Write/Execute/Shared).
+- * Just match'em all. These are for mmap(), therefore all at least
+- * User/Cachable/Present/Accessed. No point in making Fault on Write.
+- */
+-#define __MMAP_COMMON	(_PAGE_PRESENT | _PAGE_USER | _PAGE_CACHABLE | _PAGE_ACCESSED)
+-       /* sxwr */
+-#define __P000	__pgprot(__MMAP_COMMON)
+-#define __P001	__pgprot(__MMAP_COMMON | _PAGE_READ)
+-#define __P010	__pgprot(__MMAP_COMMON)
+-#define __P011	__pgprot(__MMAP_COMMON | _PAGE_READ)
+-#define __P100	__pgprot(__MMAP_COMMON | _PAGE_EXECUTE)
+-#define __P101	__pgprot(__MMAP_COMMON | _PAGE_EXECUTE | _PAGE_READ)
+-#define __P110	__pgprot(__MMAP_COMMON | _PAGE_EXECUTE)
+-#define __P111	__pgprot(__MMAP_COMMON | _PAGE_EXECUTE | _PAGE_READ)
+-
+-#define __S000	__pgprot(__MMAP_COMMON | _PAGE_SHARED)
+-#define __S001	__pgprot(__MMAP_COMMON | _PAGE_SHARED | _PAGE_READ)
+-#define __S010	__pgprot(__MMAP_COMMON | _PAGE_SHARED | _PAGE_WRITE)
+-#define __S011	__pgprot(__MMAP_COMMON | _PAGE_SHARED | _PAGE_READ | _PAGE_WRITE)
+-#define __S100	__pgprot(__MMAP_COMMON | _PAGE_SHARED | _PAGE_EXECUTE)
+-#define __S101	__pgprot(__MMAP_COMMON | _PAGE_SHARED | _PAGE_EXECUTE | _PAGE_READ)
+-#define __S110	__pgprot(__MMAP_COMMON | _PAGE_SHARED | _PAGE_EXECUTE | _PAGE_WRITE)
+-#define __S111	__pgprot(__MMAP_COMMON | _PAGE_SHARED | _PAGE_EXECUTE | _PAGE_READ | _PAGE_WRITE)
+-
+-/* Make it a device mapping for maximum safety (e.g. for mapping device
+-   registers into user-space via /dev/map).  */
+-#define pgprot_noncached(x) __pgprot(((x).pgprot & ~(_PAGE_CACHABLE)) | _PAGE_DEVICE)
+-#define pgprot_writecombine(prot) __pgprot(pgprot_val(prot) & ~_PAGE_CACHABLE)
+-
+-/*
+- * Handling allocation failures during page table setup.
+- */
+-extern void __handle_bad_pmd_kernel(pmd_t * pmd);
+-#define __handle_bad_pmd(x)	__handle_bad_pmd_kernel(x)
+-
+-/*
+- * PTE level access routines.
+- *
+- * Note1:
+- * It's the tree walk leaf. This is physical address to be stored.
+- *
+- * Note 2:
+- * Regarding the choice of _PTE_EMPTY:
+-
+-   We must choose a bit pattern that cannot be valid, whether or not the page
+-   is present.  bit[2]==1 => present, bit[2]==0 => swapped out.  If swapped
+-   out, bits [31:8], [6:3], [1:0] are under swapper control, so only bit[7] is
+-   left for us to select.  If we force bit[7]==0 when swapped out, we could use
+-   the combination bit[7,2]=2'b10 to indicate an empty PTE.  Alternatively, if
+-   we force bit[7]==1 when swapped out, we can use all zeroes to indicate
+-   empty.  This is convenient, because the page tables get cleared to zero
+-   when they are allocated.
+-
+- */
+-#define _PTE_EMPTY	0x0
+-#define pte_present(x)	(pte_val(x) & _PAGE_PRESENT)
+-#define pte_clear(mm,addr,xp)	(set_pte_at(mm, addr, xp, __pte(_PTE_EMPTY)))
+-#define pte_none(x)	(pte_val(x) == _PTE_EMPTY)
+-
+-/*
+- * Some definitions to translate between mem_map, PTEs, and page
+- * addresses:
+- */
+-
+-/*
+- * Given a PTE, return the index of the mem_map[] entry corresponding
+- * to the page frame the PTE. Get the absolute physical address, make
+- * a relative physical address and translate it to an index.
+- */
+-#define pte_pagenr(x)		(((unsigned long) (pte_val(x)) - \
+-				 __MEMORY_START) >> PAGE_SHIFT)
+-
+-/*
+- * Given a PTE, return the "struct page *".
+- */
+-#define pte_page(x)		(mem_map + pte_pagenr(x))
+-
+-/*
+- * Return number of (down rounded) MB corresponding to x pages.
+- */
+-#define pages_to_mb(x) ((x) >> (20-PAGE_SHIFT))
+-
+-
+-/*
+- * The following have defined behavior only work if pte_present() is true.
+- */
+-static inline int pte_dirty(pte_t pte){ return pte_val(pte) & _PAGE_DIRTY; }
+-static inline int pte_young(pte_t pte){ return pte_val(pte) & _PAGE_ACCESSED; }
+-static inline int pte_file(pte_t pte) { return pte_val(pte) & _PAGE_FILE; }
+-static inline int pte_write(pte_t pte){ return pte_val(pte) & _PAGE_WRITE; }
+-
+-static inline pte_t pte_wrprotect(pte_t pte)	{ set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_WRITE)); return pte; }
+-static inline pte_t pte_mkclean(pte_t pte)	{ set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_DIRTY)); return pte; }
+-static inline pte_t pte_mkold(pte_t pte)	{ set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_ACCESSED)); return pte; }
+-static inline pte_t pte_mkwrite(pte_t pte)	{ set_pte(&pte, __pte(pte_val(pte) | _PAGE_WRITE)); return pte; }
+-static inline pte_t pte_mkdirty(pte_t pte)	{ set_pte(&pte, __pte(pte_val(pte) | _PAGE_DIRTY)); return pte; }
+-static inline pte_t pte_mkyoung(pte_t pte)	{ set_pte(&pte, __pte(pte_val(pte) | _PAGE_ACCESSED)); return pte; }
+-static inline pte_t pte_mkhuge(pte_t pte)	{ set_pte(&pte, __pte(pte_val(pte) | _PAGE_SZHUGE)); return pte; }
+-
+-
+-/*
+- * Conversion functions: convert a page and protection to a page entry.
+- *
+- * extern pte_t mk_pte(struct page *page, pgprot_t pgprot)
+- */
+-#define mk_pte(page,pgprot)							\
+-({										\
+-	pte_t __pte;								\
+-										\
+-	set_pte(&__pte, __pte((((page)-mem_map) << PAGE_SHIFT) | 		\
+-		__MEMORY_START | pgprot_val((pgprot))));			\
+-	__pte;									\
+-})
+-
+-/*
+- * This takes a (absolute) physical page address that is used
+- * by the remapping functions
+- */
+-#define mk_pte_phys(physpage, pgprot) \
+-({ pte_t __pte; set_pte(&__pte, __pte(physpage | pgprot_val(pgprot))); __pte; })
+-
+-static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
+-{ set_pte(&pte, __pte((pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot))); return pte; }
+-
+-typedef pte_t *pte_addr_t;
+-#define pgtable_cache_init()	do { } while (0)
+-
+-extern void update_mmu_cache(struct vm_area_struct * vma,
+-			     unsigned long address, pte_t pte);
+-
+-/* Encode and decode a swap entry */
+-#define __swp_type(x)			(((x).val & 3) + (((x).val >> 1) & 0x3c))
+-#define __swp_offset(x)			((x).val >> 8)
+-#define __swp_entry(type, offset)	((swp_entry_t) { ((offset << 8) + ((type & 0x3c) << 1) + (type & 3)) })
+-#define __pte_to_swp_entry(pte)		((swp_entry_t) { pte_val(pte) })
+-#define __swp_entry_to_pte(x)		((pte_t) { (x).val })
+-
+-/* Encode and decode a nonlinear file mapping entry */
+-#define PTE_FILE_MAX_BITS		29
+-#define pte_to_pgoff(pte)		(pte_val(pte))
+-#define pgoff_to_pte(off)		((pte_t) { (off) | _PAGE_FILE })
+-
+-/* Needs to be defined here and not in linux/mm.h, as it is arch dependent */
+-#define PageSkip(page)		(0)
+-#define kern_addr_valid(addr)	(1)
+-
+-#define io_remap_pfn_range(vma, vaddr, pfn, size, prot)		\
+-		remap_pfn_range(vma, vaddr, pfn, size, prot)
+-
+-#endif /* !__ASSEMBLY__ */
+-
+-/*
+- * No page table caches to initialise
+- */
+-#define pgtable_cache_init()    do { } while (0)
+-
+-#define pte_pfn(x)		(((unsigned long)((x).pte)) >> PAGE_SHIFT)
+-#define pfn_pte(pfn, prot)	__pte(((pfn) << PAGE_SHIFT) | pgprot_val(prot))
+-#define pfn_pmd(pfn, prot)	__pmd(((pfn) << PAGE_SHIFT) | pgprot_val(prot))
+-
+-extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
+-
+-#include <asm-generic/pgtable.h>
+-
+-#endif /* __ASM_SH64_PGTABLE_H */
+diff --git a/include/asm-sh64/platform.h b/include/asm-sh64/platform.h
+deleted file mode 100644
+index bd0d9c4..0000000
+--- a/include/asm-sh64/platform.h
++++ /dev/null
+@@ -1,64 +0,0 @@
+-#ifndef __ASM_SH64_PLATFORM_H
+-#define __ASM_SH64_PLATFORM_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.
+- *
+- * include/asm-sh64/platform.h
+- *
+- * Copyright (C) 2000, 2001  Paolo Alberelli
+- *
+- * benedict.gaster at superh.com:	 3rd May 2002
+- *    Added support for ramdisk, removing statically linked romfs at the same time.
+- */
+-
+-#include <linux/ioport.h>
+-#include <asm/irq.h>
+-
+-
+-/*
+- * Platform definition structure.
+- */
+-struct sh64_platform {
+-	unsigned int readonly_rootfs;
+-	unsigned int ramdisk_flags;
+-	unsigned int initial_root_dev;
+-	unsigned int loader_type;
+-	unsigned int initrd_start;
+-	unsigned int initrd_size;
+-	unsigned int fpu_flags;
+-	unsigned int io_res_count;
+-	unsigned int kram_res_count;
+-	unsigned int xram_res_count;
+-	unsigned int rom_res_count;
+-	struct resource *io_res_p;
+-	struct resource *kram_res_p;
+-	struct resource *xram_res_p;
+-	struct resource *rom_res_p;
+-};
+-
+-extern struct sh64_platform platform_parms;
+-
+-extern unsigned long long memory_start, memory_end;
+-
+-extern unsigned long long fpu_in_use;
+-
+-extern int platform_int_priority[NR_INTC_IRQS];
+-
+-#define FPU_FLAGS		(platform_parms.fpu_flags)
+-#define STANDARD_IO_RESOURCES	(platform_parms.io_res_count)
+-#define STANDARD_KRAM_RESOURCES	(platform_parms.kram_res_count)
+-#define STANDARD_XRAM_RESOURCES	(platform_parms.xram_res_count)
+-#define STANDARD_ROM_RESOURCES	(platform_parms.rom_res_count)
+-
+-/*
+- * Kernel Memory description, Respectively:
+- * code = last but one memory descriptor
+- * data = last memory descriptor
+- */
+-#define code_resource (platform_parms.kram_res_p[STANDARD_KRAM_RESOURCES - 2])
+-#define data_resource (platform_parms.kram_res_p[STANDARD_KRAM_RESOURCES - 1])
+-
+-#endif	/* __ASM_SH64_PLATFORM_H */
+diff --git a/include/asm-sh64/poll.h b/include/asm-sh64/poll.h
+deleted file mode 100644
+index ca29502..0000000
+--- a/include/asm-sh64/poll.h
++++ /dev/null
+@@ -1,8 +0,0 @@
+-#ifndef __ASM_SH64_POLL_H
+-#define __ASM_SH64_POLL_H
+-
+-#include <asm-generic/poll.h>
+-
+-#undef POLLREMOVE
+-
+-#endif /* __ASM_SH64_POLL_H */
+diff --git a/include/asm-sh64/posix_types.h b/include/asm-sh64/posix_types.h
+deleted file mode 100644
+index 0620317..0000000
+--- a/include/asm-sh64/posix_types.h
++++ /dev/null
+@@ -1,131 +0,0 @@
+-#ifndef __ASM_SH64_POSIX_TYPES_H
+-#define __ASM_SH64_POSIX_TYPES_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.
+- *
+- * include/asm-sh64/posix_types.h
+- *
+- * Copyright (C) 2000, 2001  Paolo Alberelli
+- * Copyright (C) 2003  Paul Mundt
+- *
+- * This file is generally used by user-level software, so you need to
+- * be a little careful about namespace pollution etc.  Also, we cannot
+- * assume GCC is being used.
+- */
+-
+-typedef unsigned long	__kernel_ino_t;
+-typedef unsigned short	__kernel_mode_t;
+-typedef unsigned short	__kernel_nlink_t;
+-typedef long		__kernel_off_t;
+-typedef int		__kernel_pid_t;
+-typedef unsigned short	__kernel_ipc_pid_t;
+-typedef unsigned short	__kernel_uid_t;
+-typedef unsigned short	__kernel_gid_t;
+-typedef long unsigned int	__kernel_size_t;
+-typedef int		__kernel_ssize_t;
+-typedef int		__kernel_ptrdiff_t;
+-typedef long		__kernel_time_t;
+-typedef long		__kernel_suseconds_t;
+-typedef long		__kernel_clock_t;
+-typedef int		__kernel_timer_t;
+-typedef int		__kernel_clockid_t;
+-typedef int		__kernel_daddr_t;
+-typedef char *		__kernel_caddr_t;
+-typedef unsigned short	__kernel_uid16_t;
+-typedef unsigned short	__kernel_gid16_t;
+-typedef unsigned int	__kernel_uid32_t;
+-typedef unsigned int	__kernel_gid32_t;
+-
+-typedef unsigned short	__kernel_old_uid_t;
+-typedef unsigned short	__kernel_old_gid_t;
+-typedef unsigned short	__kernel_old_dev_t;
+-
+-#ifdef __GNUC__
+-typedef long long	__kernel_loff_t;
+-#endif
+-
+-typedef struct {
+-#if defined(__KERNEL__) || defined(__USE_ALL)
+-	int	val[2];
+-#else /* !defined(__KERNEL__) && !defined(__USE_ALL) */
+-	int	__val[2];
+-#endif /* !defined(__KERNEL__) && !defined(__USE_ALL) */
+-} __kernel_fsid_t;
+-
+-#if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2)
+-
+-#undef	__FD_SET
+-static __inline__ void __FD_SET(unsigned long __fd, __kernel_fd_set *__fdsetp)
+-{
+-	unsigned long __tmp = __fd / __NFDBITS;
+-	unsigned long __rem = __fd % __NFDBITS;
+-	__fdsetp->fds_bits[__tmp] |= (1UL<<__rem);
 -}
 -
--static int object_path_length(struct sysfs_dirent * sd)
+-#undef	__FD_CLR
+-static __inline__ void __FD_CLR(unsigned long __fd, __kernel_fd_set *__fdsetp)
 -{
--	int length = 1;
+-	unsigned long __tmp = __fd / __NFDBITS;
+-	unsigned long __rem = __fd % __NFDBITS;
+-	__fdsetp->fds_bits[__tmp] &= ~(1UL<<__rem);
+-}
 -
--	for (; sd->s_parent; sd = sd->s_parent)
--		length += strlen(sd->s_name) + 1;
 -
--	return length;
+-#undef	__FD_ISSET
+-static __inline__ int __FD_ISSET(unsigned long __fd, const __kernel_fd_set *__p)
+-{
+-	unsigned long __tmp = __fd / __NFDBITS;
+-	unsigned long __rem = __fd % __NFDBITS;
+-	return (__p->fds_bits[__tmp] & (1UL<<__rem)) != 0;
 -}
 -
--static void fill_object_path(struct sysfs_dirent *sd, char *buffer, int length)
+-/*
+- * This will unroll the loop for the normal constant case (8 ints,
+- * for a 256-bit fd_set)
+- */
+-#undef	__FD_ZERO
+-static __inline__ void __FD_ZERO(__kernel_fd_set *__p)
 -{
--	--length;
--	for (; sd->s_parent; sd = sd->s_parent) {
--		int cur = strlen(sd->s_name);
+-	unsigned long *__tmp = __p->fds_bits;
+-	int __i;
 -
--		/* back up enough to print this bus id with '/' */
--		length -= cur;
--		strncpy(buffer + length, sd->s_name, cur);
--		*(buffer + --length) = '/';
+-	if (__builtin_constant_p(__FDSET_LONGS)) {
+-		switch (__FDSET_LONGS) {
+-		case 16:
+-			__tmp[ 0] = 0; __tmp[ 1] = 0;
+-			__tmp[ 2] = 0; __tmp[ 3] = 0;
+-			__tmp[ 4] = 0; __tmp[ 5] = 0;
+-			__tmp[ 6] = 0; __tmp[ 7] = 0;
+-			__tmp[ 8] = 0; __tmp[ 9] = 0;
+-			__tmp[10] = 0; __tmp[11] = 0;
+-			__tmp[12] = 0; __tmp[13] = 0;
+-			__tmp[14] = 0; __tmp[15] = 0;
+-			return;
+-
+-		case 8:
+-			__tmp[ 0] = 0; __tmp[ 1] = 0;
+-			__tmp[ 2] = 0; __tmp[ 3] = 0;
+-			__tmp[ 4] = 0; __tmp[ 5] = 0;
+-			__tmp[ 6] = 0; __tmp[ 7] = 0;
+-			return;
+-
+-		case 4:
+-			__tmp[ 0] = 0; __tmp[ 1] = 0;
+-			__tmp[ 2] = 0; __tmp[ 3] = 0;
+-			return;
+-		}
+-	}
+-	__i = __FDSET_LONGS;
+-	while (__i) {
+-		__i--;
+-		*__tmp = 0;
+-		__tmp++;
 -	}
 -}
 -
- /**
-  *	sysfs_create_link - create symlink between two objects.
-  *	@kobj:	object whose directory we're creating the link in.
-@@ -112,7 +79,6 @@ int sysfs_create_link(struct kobject * kobj, struct kobject * target, const char
- 	return error;
- }
- 
+-#endif /* defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2) */
 -
- /**
-  *	sysfs_remove_link - remove symlink in object's directory.
-  *	@kobj:	object we're acting for.
-@@ -124,24 +90,54 @@ void sysfs_remove_link(struct kobject * kobj, const char * name)
- 	sysfs_hash_and_remove(kobj->sd, name);
- }
- 
--static int sysfs_get_target_path(struct sysfs_dirent * parent_sd,
--				 struct sysfs_dirent * target_sd, char *path)
-+static int sysfs_get_target_path(struct sysfs_dirent *parent_sd,
-+				 struct sysfs_dirent *target_sd, char *path)
- {
--	char * s;
--	int depth, size;
-+	struct sysfs_dirent *base, *sd;
-+	char *s = path;
-+	int len = 0;
-+
-+	/* go up to the root, stop at the base */
-+	base = parent_sd;
-+	while (base->s_parent) {
-+		sd = target_sd->s_parent;
-+		while (sd->s_parent && base != sd)
-+			sd = sd->s_parent;
-+
-+		if (base == sd)
-+			break;
-+
-+		strcpy(s, "../");
-+		s += 3;
-+		base = base->s_parent;
-+	}
-+
-+	/* determine end of target string for reverse fillup */
-+	sd = target_sd;
-+	while (sd->s_parent && sd != base) {
-+		len += strlen(sd->s_name) + 1;
-+		sd = sd->s_parent;
-+	}
- 
--	depth = object_depth(parent_sd);
--	size = object_path_length(target_sd) + depth * 3 - 1;
--	if (size > PATH_MAX)
-+	/* check limits */
-+	if (len < 2)
-+		return -EINVAL;
-+	len--;
-+	if ((s - path) + len > PATH_MAX)
- 		return -ENAMETOOLONG;
- 
--	pr_debug("%s: depth = %d, size = %d\n", __FUNCTION__, depth, size);
-+	/* reverse fillup of target string from target to base */
-+	sd = target_sd;
-+	while (sd->s_parent && sd != base) {
-+		int slen = strlen(sd->s_name);
- 
--	for (s = path; depth--; s += 3)
--		strcpy(s,"../");
-+		len -= slen;
-+		strncpy(s + len, sd->s_name, slen);
-+		if (len)
-+			s[--len] = '/';
- 
--	fill_object_path(target_sd, path, size);
--	pr_debug("%s: path = '%s'\n", __FUNCTION__, path);
-+		sd = sd->s_parent;
-+	}
- 
- 	return 0;
- }
-diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h
-index 7b74b60..fb7171b 100644
---- a/include/acpi/acpi_bus.h
-+++ b/include/acpi/acpi_bus.h
-@@ -319,7 +319,7 @@ struct acpi_bus_event {
- 	u32 data;
- };
- 
--extern struct kset acpi_subsys;
-+extern struct kobject *acpi_kobj;
- extern int acpi_bus_generate_netlink_event(const char*, const char*, u8, int);
- /*
-  * External Functions
-diff --git a/include/asm-arm/arch-ixp4xx/platform.h b/include/asm-arm/arch-ixp4xx/platform.h
-index 2a44d3d..2ce28e3 100644
---- a/include/asm-arm/arch-ixp4xx/platform.h
-+++ b/include/asm-arm/arch-ixp4xx/platform.h
-@@ -76,17 +76,6 @@ extern unsigned long ixp4xx_exp_bus_size;
- #define IXP4XX_UART_XTAL        	14745600
- 
- /*
-- * The IXP4xx chips do not have an I2C unit, so GPIO lines are just
-- * used to 
-- * Used as platform_data to provide GPIO pin information to the ixp42x
-- * I2C driver.
+-#endif /* __ASM_SH64_POSIX_TYPES_H */
+diff --git a/include/asm-sh64/processor.h b/include/asm-sh64/processor.h
+deleted file mode 100644
+index eb2bee4..0000000
+--- a/include/asm-sh64/processor.h
++++ /dev/null
+@@ -1,287 +0,0 @@
+-#ifndef __ASM_SH64_PROCESSOR_H
+-#define __ASM_SH64_PROCESSOR_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.
+- *
+- * include/asm-sh64/processor.h
+- *
+- * Copyright (C) 2000, 2001  Paolo Alberelli
+- * Copyright (C) 2003  Paul Mundt
+- * Copyright (C) 2004  Richard Curnow
+- *
+- */
+-
+-#include <asm/page.h>
+-
+-#ifndef __ASSEMBLY__
+-
+-#include <asm/types.h>
+-#include <asm/cache.h>
+-#include <asm/registers.h>
+-#include <linux/threads.h>
+-#include <linux/compiler.h>
+-
+-/*
+- * Default implementation of macro that returns current
+- * instruction pointer ("program counter").
+- */
+-#define current_text_addr() ({ \
+-void *pc; \
+-unsigned long long __dummy = 0; \
+-__asm__("gettr	tr0, %1\n\t" \
+-	"pta	4, tr0\n\t" \
+-	"gettr	tr0, %0\n\t" \
+-	"ptabs	%1, tr0\n\t"	\
+-	:"=r" (pc), "=r" (__dummy) \
+-	: "1" (__dummy)); \
+-pc; })
+-
+-/*
+- *  CPU type and hardware bug flags. Kept separately for each CPU.
+- */
+-enum cpu_type {
+-	CPU_SH5_101,
+-	CPU_SH5_103,
+-	CPU_SH_NONE
+-};
+-
+-/*
+- * TLB information structure
+- *
+- * Defined for both I and D tlb, per-processor.
+- */
+-struct tlb_info {
+-	unsigned long long next;
+-	unsigned long long first;
+-	unsigned long long last;
+-
+-	unsigned int entries;
+-	unsigned int step;
+-
+-	unsigned long flags;
+-};
+-
+-struct sh_cpuinfo {
+-	enum cpu_type type;
+-	unsigned long loops_per_jiffy;
+-
+-	char	hard_math;
+-
+-	unsigned long *pgd_quick;
+-	unsigned long *pmd_quick;
+-	unsigned long *pte_quick;
+-	unsigned long pgtable_cache_sz;
+-	unsigned int cpu_clock, master_clock, bus_clock, module_clock;
+-
+-	/* Cache info */
+-	struct cache_info icache;
+-	struct cache_info dcache;
+-
+-	/* TLB info */
+-	struct tlb_info itlb;
+-	struct tlb_info dtlb;
+-};
+-
+-extern struct sh_cpuinfo boot_cpu_data;
+-
+-#define cpu_data (&boot_cpu_data)
+-#define current_cpu_data boot_cpu_data
+-
+-#endif
+-
+-/*
+- * User space process size: 2GB - 4k.
 - */
--struct ixp4xx_i2c_pins {
--	unsigned long sda_pin;
--	unsigned long scl_pin;
--};
+-#define TASK_SIZE	0x7ffff000UL
+-
+-/* This decides where the kernel will search for a free chunk of vm
+- * space during mmap's.
+- */
+-#define TASK_UNMAPPED_BASE	(TASK_SIZE / 3)
 -
 -/*
-  * This structure provide a means for the board setup code
-  * to give information to th pata_ixp4xx driver. It is
-  * passed as platform_data.
-diff --git a/include/asm-arm/arch-omap/tps65010.h b/include/asm-arm/arch-omap/tps65010.h
-deleted file mode 100644
-index b9aa2b3..0000000
---- a/include/asm-arm/arch-omap/tps65010.h
-+++ /dev/null
-@@ -1,156 +0,0 @@
--/* linux/include/asm-arm/arch-omap/tps65010.h
-- *
-- * Functions to access TPS65010 power management device.
+- * Bit of SR register
 - *
-- * Copyright (C) 2004 Dirk Behme <dirk.behme at de.bosch.com>
+- * FD-bit:
+- *     When it's set, it means the processor doesn't have right to use FPU,
+- *     and it results exception when the floating operation is executed.
 - *
-- * This program is free software; you can redistribute it and/or modify it
-- * under the terms of the GNU General Public License as published by the
-- * Free Software Foundation; either version 2 of the License, or (at your
-- * option) any later version.
+- * IMASK-bit:
+- *     Interrupt level mask
 - *
-- * 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.
+- * STEP-bit:
+- *     Single step bit
 - *
-- * You 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 SR_FD    0x00008000
 -
--#ifndef __ASM_ARCH_TPS65010_H
--#define __ASM_ARCH_TPS65010_H
+-#if defined(CONFIG_SH64_SR_WATCH)
+-#define SR_MMU   0x84000000
+-#else
+-#define SR_MMU   0x80000000
+-#endif
+-
+-#define SR_IMASK 0x000000f0
+-#define SR_SSTEP 0x08000000
+-
+-#ifndef __ASSEMBLY__
 -
 -/*
-- * ----------------------------------------------------------------------------
-- * Registers, all 8 bits
-- * ----------------------------------------------------------------------------
+- * FPU structure and data : require 8-byte alignment as we need to access it
+-   with fld.p, fst.p
 - */
 -
--#define	TPS_CHGSTATUS		0x01
--#	define	TPS_CHG_USB		(1 << 7)
--#	define	TPS_CHG_AC		(1 << 6)
--#	define	TPS_CHG_THERM		(1 << 5)
--#	define	TPS_CHG_TERM		(1 << 4)
--#	define	TPS_CHG_TAPER_TMO	(1 << 3)
--#	define	TPS_CHG_CHG_TMO		(1 << 2)
--#	define	TPS_CHG_PRECHG_TMO	(1 << 1)
--#	define	TPS_CHG_TEMP_ERR	(1 << 0)
--#define	TPS_REGSTATUS		0x02
--#	define	TPS_REG_ONOFF		(1 << 7)
--#	define	TPS_REG_COVER		(1 << 6)
--#	define	TPS_REG_UVLO		(1 << 5)
--#	define	TPS_REG_NO_CHG		(1 << 4)	/* tps65013 */
--#	define	TPS_REG_PG_LD02		(1 << 3)
--#	define	TPS_REG_PG_LD01		(1 << 2)
--#	define	TPS_REG_PG_MAIN		(1 << 1)
--#	define	TPS_REG_PG_CORE		(1 << 0)
--#define	TPS_MASK1		0x03
--#define	TPS_MASK2		0x04
--#define	TPS_ACKINT1		0x05
--#define	TPS_ACKINT2		0x06
--#define	TPS_CHGCONFIG		0x07
--#	define	TPS_CHARGE_POR		(1 << 7)	/* 65010/65012 */
--#	define	TPS65013_AUA		(1 << 7)	/* 65011/65013 */
--#	define	TPS_CHARGE_RESET	(1 << 6)
--#	define	TPS_CHARGE_FAST		(1 << 5)
--#	define	TPS_CHARGE_CURRENT	(3 << 3)
--#	define	TPS_VBUS_500MA		(1 << 2)
--#	define	TPS_VBUS_CHARGING	(1 << 1)
--#	define	TPS_CHARGE_ENABLE	(1 << 0)
--#define	TPS_LED1_ON		0x08
--#define	TPS_LED1_PER		0x09
--#define	TPS_LED2_ON		0x0a
--#define	TPS_LED2_PER		0x0b
--#define	TPS_VDCDC1		0x0c
--#	define	TPS_ENABLE_LP		(1 << 3)
--#define	TPS_VDCDC2		0x0d
--#define	TPS_VREGS1		0x0e
--#	define	TPS_LDO2_ENABLE	(1 << 7)
--#	define	TPS_LDO2_OFF	(1 << 6)
--#	define	TPS_VLDO2_3_0V	(3 << 4)
--#	define	TPS_VLDO2_2_75V	(2 << 4)
--#	define	TPS_VLDO2_2_5V	(1 << 4)
--#	define	TPS_VLDO2_1_8V	(0 << 4)
--#	define	TPS_LDO1_ENABLE	(1 << 3)
--#	define	TPS_LDO1_OFF	(1 << 2)
--#	define	TPS_VLDO1_3_0V	(3 << 0)
--#	define	TPS_VLDO1_2_75V	(2 << 0)
--#	define	TPS_VLDO1_2_5V	(1 << 0)
--#	define	TPS_VLDO1_ADJ	(0 << 0)
--#define	TPS_MASK3		0x0f
--#define	TPS_DEFGPIO		0x10
+-struct sh_fpu_hard_struct {
+-	unsigned long fp_regs[64];
+-	unsigned int fpscr;
+-	/* long status; * software status information */
+-};
+-
+-#if 0
+-/* Dummy fpu emulator  */
+-struct sh_fpu_soft_struct {
+-	unsigned long long fp_regs[32];
+-	unsigned int fpscr;
+-	unsigned char lookahead;
+-	unsigned long entry_pc;
+-};
+-#endif
+-
+-union sh_fpu_union {
+-	struct sh_fpu_hard_struct hard;
+-	/* 'hard' itself only produces 32 bit alignment, yet we need
+-	   to access it using 64 bit load/store as well. */
+-	unsigned long long alignment_dummy;
+-};
+-
+-struct thread_struct {
+-	unsigned long sp;
+-	unsigned long pc;
+-	/* This stores the address of the pt_regs built during a context
+-	   switch, or of the register save area built for a kernel mode
+-	   exception.  It is used for backtracing the stack of a sleeping task
+-	   or one that traps in kernel mode. */
+-        struct pt_regs *kregs;
+-	/* This stores the address of the pt_regs constructed on entry from
+-	   user mode.  It is a fixed value over the lifetime of a process, or
+-	   NULL for a kernel thread. */
+-	struct pt_regs *uregs;
+-
+-	unsigned long trap_no, error_code;
+-	unsigned long address;
+-	/* Hardware debugging registers may come here */
+-
+-	/* floating point info */
+-	union sh_fpu_union fpu;
+-};
+-
+-#define INIT_MMAP \
+-{ &init_mm, 0, 0, NULL, PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC, 1, NULL, NULL }
+-
+-extern  struct pt_regs fake_swapper_regs;
+-
+-#define INIT_THREAD  {				\
+-	.sp		= sizeof(init_stack) +	\
+-			  (long) &init_stack,	\
+-	.pc		= 0,			\
+-        .kregs		= &fake_swapper_regs,	\
+-	.uregs	        = NULL,			\
+-	.trap_no	= 0,			\
+-	.error_code	= 0,			\
+-	.address	= 0,			\
+-	.fpu		= { { { 0, } }, }	\
+-}
 -
 -/*
-- * ----------------------------------------------------------------------------
-- * Macros used by exported functions
-- * ----------------------------------------------------------------------------
+- * Do necessary setup to start up a newly executed thread.
 - */
+-#define SR_USER (SR_MMU | SR_FD)
 -
--#define LED1  1
--#define LED2  2
--#define OFF   0
--#define ON    1
--#define BLINK 2
--#define GPIO1 1
--#define GPIO2 2
--#define GPIO3 3
--#define GPIO4 4
--#define LOW   0
--#define HIGH  1
+-#define start_thread(regs, new_pc, new_sp) 	 		\
+-	set_fs(USER_DS);			 		\
+-	regs->sr = SR_USER;	/* User mode. */ 		\
+-	regs->pc = new_pc - 4;	/* Compensate syscall exit */	\
+-	regs->pc |= 1;		/* Set SHmedia ! */		\
+-	regs->regs[18] = 0;   		 	 		\
+-	regs->regs[15] = new_sp
+-
+-/* Forward declaration, a strange C thing */
+-struct task_struct;
+-struct mm_struct;
 -
+-/* Free all resources held by a thread. */
+-extern void release_thread(struct task_struct *);
 -/*
-- * ----------------------------------------------------------------------------
-- * Exported functions
-- * ----------------------------------------------------------------------------
+- * create a kernel thread without removing it from tasklists
 - */
+-extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
 -
--/* Draw from VBUS:
-- *   0 mA -- DON'T DRAW (might supply power instead)
-- * 100 mA -- usb unit load (slowest charge rate)
-- * 500 mA -- usb high power (fast battery charge)
-- */
--extern int tps65010_set_vbus_draw(unsigned mA);
 -
--/* tps65010_set_gpio_out_value parameter:
-- * gpio:  GPIO1, GPIO2, GPIO3 or GPIO4
-- * value: LOW or HIGH
+-/* Copy and release all segment info associated with a VM */
+-#define copy_segments(p, mm)	do { } while (0)
+-#define release_segments(mm)	do { } while (0)
+-#define forget_segments()	do { } while (0)
+-#define prepare_to_copy(tsk)	do { } while (0)
+-/*
+- * FPU lazy state save handling.
 - */
--extern int tps65010_set_gpio_out_value(unsigned gpio, unsigned value);
 -
--/* tps65010_set_led parameter:
-- * led:  LED1 or LED2
-- * mode: ON, OFF or BLINK
-- */
--extern int tps65010_set_led(unsigned led, unsigned mode);
+-static inline void release_fpu(void)
+-{
+-	unsigned long long __dummy;
 -
--/* tps65010_set_vib parameter:
-- * value: ON or OFF
-- */
--extern int tps65010_set_vib(unsigned value);
+-	/* Set FD flag in SR */
+-	__asm__ __volatile__("getcon	" __SR ", %0\n\t"
+-			     "or	%0, %1, %0\n\t"
+-			     "putcon	%0, " __SR "\n\t"
+-			     : "=&r" (__dummy)
+-			     : "r" (SR_FD));
+-}
 -
--/* tps65010_set_low_pwr parameter:
-- * mode: ON or OFF
+-static inline void grab_fpu(void)
+-{
+-	unsigned long long __dummy;
+-
+-	/* Clear out FD flag in SR */
+-	__asm__ __volatile__("getcon	" __SR ", %0\n\t"
+-			     "and	%0, %1, %0\n\t"
+-			     "putcon	%0, " __SR "\n\t"
+-			     : "=&r" (__dummy)
+-			     : "r" (~SR_FD));
+-}
+-
+-/* Round to nearest, no exceptions on inexact, overflow, underflow,
+-   zero-divide, invalid.  Configure option for whether to flush denorms to
+-   zero, or except if a denorm is encountered.  */
+-#if defined(CONFIG_SH64_FPU_DENORM_FLUSH)
+-#define FPSCR_INIT  0x00040000
+-#else
+-#define FPSCR_INIT  0x00000000
+-#endif
+-
+-/* Save the current FP regs */
+-void fpsave(struct sh_fpu_hard_struct *fpregs);
+-
+-/* Initialise the FP state of a task */
+-void fpinit(struct sh_fpu_hard_struct *fpregs);
+-
+-extern struct task_struct *last_task_used_math;
+-
+-/*
+- * Return saved PC of a blocked thread.
 - */
--extern int tps65010_set_low_pwr(unsigned mode);
+-#define thread_saved_pc(tsk)	(tsk->thread.pc)
 -
--/* tps65010_config_vregs1 parameter:
-- * value to be written to VREGS1 register
-- * Note: The complete register is written, set all bits you need
+-extern unsigned long get_wchan(struct task_struct *p);
+-
+-#define KSTK_EIP(tsk)  ((tsk)->thread.pc)
+-#define KSTK_ESP(tsk)  ((tsk)->thread.sp)
+-
+-#define cpu_relax()	barrier()
+-
+-#endif	/* __ASSEMBLY__ */
+-#endif /* __ASM_SH64_PROCESSOR_H */
+-
+diff --git a/include/asm-sh64/ptrace.h b/include/asm-sh64/ptrace.h
+deleted file mode 100644
+index c424f80..0000000
+--- a/include/asm-sh64/ptrace.h
++++ /dev/null
+@@ -1,35 +0,0 @@
+-#ifndef __ASM_SH64_PTRACE_H
+-#define __ASM_SH64_PTRACE_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.
+- *
+- * include/asm-sh64/ptrace.h
+- *
+- * Copyright (C) 2000, 2001  Paolo Alberelli
+- *
 - */
--extern int tps65010_config_vregs1(unsigned value);
 -
--/* tps65013_set_low_pwr parameter:
-- * mode: ON or OFF
+-/*
+- * This struct defines the way the registers are stored on the
+- * kernel stack during a system call or other kernel entry.
 - */
--extern int tps65013_set_low_pwr(unsigned mode);
+-struct pt_regs {
+-	unsigned long long pc;
+-	unsigned long long sr;
+-	unsigned long long syscall_nr;
+-	unsigned long long regs[63];
+-	unsigned long long tregs[8];
+-	unsigned long long pad[2];
+-};
 -
--#endif /*  __ASM_ARCH_TPS65010_H */
+-#ifdef __KERNEL__
+-#define user_mode(regs) (((regs)->sr & 0x40000000)==0)
+-#define instruction_pointer(regs) ((regs)->pc)
+-#define profile_pc(regs) ((unsigned long)instruction_pointer(regs))
+-extern void show_regs(struct pt_regs *);
+-#endif
 -
-diff --git a/include/asm-arm/arch-pxa/i2c.h b/include/asm-arm/arch-pxa/i2c.h
-index e404b23..80596b0 100644
---- a/include/asm-arm/arch-pxa/i2c.h
-+++ b/include/asm-arm/arch-pxa/i2c.h
-@@ -65,7 +65,13 @@ struct i2c_pxa_platform_data {
- 	unsigned int		slave_addr;
- 	struct i2c_slave_client	*slave;
- 	unsigned int		class;
-+	int			use_pio;
- };
- 
- 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);
-+#endif
-+
- #endif
-diff --git a/include/asm-avr32/arch-at32ap/at32ap7000.h b/include/asm-avr32/arch-at32ap/at32ap7000.h
+-#endif /* __ASM_SH64_PTRACE_H */
+diff --git a/include/asm-sh64/registers.h b/include/asm-sh64/registers.h
 deleted file mode 100644
-index 3914d7b..0000000
---- a/include/asm-avr32/arch-at32ap/at32ap7000.h
+index 7eec666..0000000
+--- a/include/asm-sh64/registers.h
 +++ /dev/null
-@@ -1,35 +0,0 @@
+@@ -1,106 +0,0 @@
+-#ifndef __ASM_SH64_REGISTERS_H
+-#define __ASM_SH64_REGISTERS_H
+-
 -/*
-- * Pin definitions for AT32AP7000.
+- * 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) 2006 Atmel Corporation
+- * include/asm-sh64/registers.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.
+- * Copyright (C) 2000, 2001  Paolo Alberelli
+- * Copyright (C) 2004  Richard Curnow
 - */
--#ifndef __ASM_ARCH_AT32AP7000_H__
--#define __ASM_ARCH_AT32AP7000_H__
 -
--#define GPIO_PERIPH_A	0
--#define GPIO_PERIPH_B	1
+-#ifdef __ASSEMBLY__
+-/* =====================================================================
+-**
+-** Section 1: acts on assembly sources pre-processed by GPP ( <source.S>).
+-**	      Assigns symbolic names to control & target registers.
+-*/
 -
--#define NR_GPIO_CONTROLLERS	4
+-/*
+- * Define some useful aliases for control registers.
+- */
+-#define SR	cr0
+-#define SSR	cr1
+-#define PSSR	cr2
+-			/* cr3 UNDEFINED */
+-#define INTEVT	cr4
+-#define EXPEVT	cr5
+-#define PEXPEVT	cr6
+-#define TRA	cr7
+-#define SPC	cr8
+-#define PSPC	cr9
+-#define RESVEC	cr10
+-#define VBR	cr11
+-			/* cr12 UNDEFINED */
+-#define TEA	cr13
+-			/* cr14-cr15 UNDEFINED */
+-#define DCR	cr16
+-#define KCR0	cr17
+-#define KCR1	cr18
+-			/* cr19-cr31 UNDEFINED */
+-			/* cr32-cr61 RESERVED */
+-#define CTC	cr62
+-#define USR	cr63
 -
 -/*
-- * Pin numbers identifying specific GPIO pins on the chip. They can
-- * also be converted to IRQ numbers by passing them through
-- * gpio_to_irq().
+- * ABI dependent registers (general purpose set)
 - */
--#define GPIO_PIOA_BASE	(0)
--#define GPIO_PIOB_BASE	(GPIO_PIOA_BASE + 32)
--#define GPIO_PIOC_BASE	(GPIO_PIOB_BASE + 32)
--#define GPIO_PIOD_BASE	(GPIO_PIOC_BASE + 32)
--#define GPIO_PIOE_BASE	(GPIO_PIOD_BASE + 32)
+-#define RET	r2
+-#define ARG1	r2
+-#define ARG2	r3
+-#define ARG3	r4
+-#define ARG4	r5
+-#define ARG5	r6
+-#define ARG6	r7
+-#define SP	r15
+-#define LINK	r18
+-#define ZERO	r63
 -
--#define GPIO_PIN_PA(N)	(GPIO_PIOA_BASE + (N))
--#define GPIO_PIN_PB(N)	(GPIO_PIOB_BASE + (N))
--#define GPIO_PIN_PC(N)	(GPIO_PIOC_BASE + (N))
--#define GPIO_PIN_PD(N)	(GPIO_PIOD_BASE + (N))
--#define GPIO_PIN_PE(N)	(GPIO_PIOE_BASE + (N))
+-/*
+- * Status register defines: used only by assembly sources (and
+- * 			    syntax independednt)
+- */
+-#define SR_RESET_VAL	0x0000000050008000
+-#define SR_HARMLESS	0x00000000500080f0	/* Write ignores for most */
+-#define SR_ENABLE_FPU	0xffffffffffff7fff	/* AND with this */
 -
--#endif /* __ASM_ARCH_AT32AP7000_H__ */
-diff --git a/include/asm-avr32/arch-at32ap/at32ap700x.h b/include/asm-avr32/arch-at32ap/at32ap700x.h
-new file mode 100644
-index 0000000..99684d6
---- /dev/null
-+++ b/include/asm-avr32/arch-at32ap/at32ap700x.h
-@@ -0,0 +1,35 @@
-+/*
-+ * Pin definitions for AT32AP7000.
-+ *
-+ * Copyright (C) 2006 Atmel 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.
-+ */
-+#ifndef __ASM_ARCH_AT32AP700X_H__
-+#define __ASM_ARCH_AT32AP700X_H__
-+
-+#define GPIO_PERIPH_A	0
-+#define GPIO_PERIPH_B	1
-+
-+#define NR_GPIO_CONTROLLERS	4
-+
-+/*
-+ * Pin numbers identifying specific GPIO pins on the chip. They can
-+ * also be converted to IRQ numbers by passing them through
-+ * gpio_to_irq().
-+ */
-+#define GPIO_PIOA_BASE	(0)
-+#define GPIO_PIOB_BASE	(GPIO_PIOA_BASE + 32)
-+#define GPIO_PIOC_BASE	(GPIO_PIOB_BASE + 32)
-+#define GPIO_PIOD_BASE	(GPIO_PIOC_BASE + 32)
-+#define GPIO_PIOE_BASE	(GPIO_PIOD_BASE + 32)
-+
-+#define GPIO_PIN_PA(N)	(GPIO_PIOA_BASE + (N))
-+#define GPIO_PIN_PB(N)	(GPIO_PIOB_BASE + (N))
-+#define GPIO_PIN_PC(N)	(GPIO_PIOC_BASE + (N))
-+#define GPIO_PIN_PD(N)	(GPIO_PIOD_BASE + (N))
-+#define GPIO_PIN_PE(N)	(GPIO_PIOE_BASE + (N))
-+
-+#endif /* __ASM_ARCH_AT32AP700X_H__ */
-diff --git a/include/asm-avr32/arch-at32ap/cpu.h b/include/asm-avr32/arch-at32ap/cpu.h
-index a762f42..0dc2026 100644
---- a/include/asm-avr32/arch-at32ap/cpu.h
-+++ b/include/asm-avr32/arch-at32ap/cpu.h
-@@ -14,7 +14,7 @@
-  * Only AT32AP7000 is defined for now. We can identify the specific
-  * chip at runtime, but I'm not sure if it's really worth it.
-  */
--#ifdef CONFIG_CPU_AT32AP7000
-+#ifdef CONFIG_CPU_AT32AP700X
- # define cpu_is_at32ap7000()	(1)
- #else
- # define cpu_is_at32ap7000()	(0)
-diff --git a/include/asm-avr32/arch-at32ap/io.h b/include/asm-avr32/arch-at32ap/io.h
-index ee59e40..4ec6abc 100644
---- a/include/asm-avr32/arch-at32ap/io.h
-+++ b/include/asm-avr32/arch-at32ap/io.h
-@@ -4,7 +4,7 @@
- /* For "bizarre" halfword swapping */
- #include <linux/byteorder/swabb.h>
- 
--#if defined(CONFIG_AP7000_32_BIT_SMC)
-+#if defined(CONFIG_AP700X_32_BIT_SMC)
- # define __swizzle_addr_b(addr)	(addr ^ 3UL)
- # define __swizzle_addr_w(addr)	(addr ^ 2UL)
- # define __swizzle_addr_l(addr)	(addr)
-@@ -14,7 +14,7 @@
- # define __mem_ioswabb(a, x)	(x)
- # define __mem_ioswabw(a, x)	swab16(x)
- # define __mem_ioswabl(a, x)	swab32(x)
--#elif defined(CONFIG_AP7000_16_BIT_SMC)
-+#elif defined(CONFIG_AP700X_16_BIT_SMC)
- # define __swizzle_addr_b(addr)	(addr ^ 1UL)
- # define __swizzle_addr_w(addr)	(addr)
- # define __swizzle_addr_l(addr)	(addr)
-diff --git a/include/asm-avr32/irq.h b/include/asm-avr32/irq.h
-index 83e6549..9315724 100644
---- a/include/asm-avr32/irq.h
-+++ b/include/asm-avr32/irq.h
-@@ -11,4 +11,9 @@
- 
- #define irq_canonicalize(i)	(i)
- 
-+#ifndef __ASSEMBLER__
-+int nmi_enable(void);
-+void nmi_disable(void);
-+#endif
-+
- #endif /* __ASM_AVR32_IOCTLS_H */
-diff --git a/include/asm-avr32/kdebug.h b/include/asm-avr32/kdebug.h
-index fd7e990..ca4f954 100644
---- a/include/asm-avr32/kdebug.h
-+++ b/include/asm-avr32/kdebug.h
-@@ -5,6 +5,7 @@
- enum die_val {
- 	DIE_BREAKPOINT,
- 	DIE_SSTEP,
-+	DIE_NMI,
- };
- 
- #endif /* __ASM_AVR32_KDEBUG_H */
-diff --git a/include/asm-avr32/ocd.h b/include/asm-avr32/ocd.h
-index 996405e..6bef094 100644
---- a/include/asm-avr32/ocd.h
-+++ b/include/asm-avr32/ocd.h
-@@ -533,6 +533,11 @@ static inline void __ocd_write(unsigned int reg, unsigned long value)
- #define ocd_read(reg)			__ocd_read(OCD_##reg)
- #define ocd_write(reg, value)		__ocd_write(OCD_##reg, value)
- 
-+struct task_struct;
-+
-+void ocd_enable(struct task_struct *child);
-+void ocd_disable(struct task_struct *child);
-+
- #endif /* !__ASSEMBLER__ */
- 
- #endif /* __ASM_AVR32_OCD_H */
-diff --git a/include/asm-avr32/processor.h b/include/asm-avr32/processor.h
-index a52576b..4212551 100644
---- a/include/asm-avr32/processor.h
-+++ b/include/asm-avr32/processor.h
-@@ -57,11 +57,25 @@ struct avr32_cpuinfo {
- 	unsigned short cpu_revision;
- 	enum tlb_config tlb_config;
- 	unsigned long features;
-+	u32 device_id;
- 
- 	struct cache_info icache;
- 	struct cache_info dcache;
- };
- 
-+static inline unsigned int avr32_get_manufacturer_id(struct avr32_cpuinfo *cpu)
-+{
-+	return (cpu->device_id >> 1) & 0x7f;
-+}
-+static inline unsigned int avr32_get_product_number(struct avr32_cpuinfo *cpu)
-+{
-+	return (cpu->device_id >> 12) & 0xffff;
-+}
-+static inline unsigned int avr32_get_chip_revision(struct avr32_cpuinfo *cpu)
-+{
-+	return (cpu->device_id >> 28) & 0x0f;
-+}
-+
- extern struct avr32_cpuinfo boot_cpu_data;
- 
- #ifdef CONFIG_SMP
-diff --git a/include/asm-avr32/ptrace.h b/include/asm-avr32/ptrace.h
-index 8c5dba5..9e2d44f 100644
---- a/include/asm-avr32/ptrace.h
-+++ b/include/asm-avr32/ptrace.h
-@@ -121,7 +121,15 @@ struct pt_regs {
- };
- 
- #ifdef __KERNEL__
--# define user_mode(regs) (((regs)->sr & MODE_MASK) == MODE_USER)
-+
-+#include <asm/ocd.h>
-+
-+#define arch_ptrace_attach(child)       ocd_enable(child)
-+
-+#define user_mode(regs)                 (((regs)->sr & MODE_MASK) == MODE_USER)
-+#define instruction_pointer(regs)       ((regs)->pc)
-+#define profile_pc(regs)                instruction_pointer(regs)
-+
- extern void show_regs (struct pt_regs *);
- 
- static __inline__ int valid_user_regs(struct pt_regs *regs)
-@@ -141,9 +149,6 @@ static __inline__ int valid_user_regs(struct pt_regs *regs)
- 	return 0;
- }
- 
--#define instruction_pointer(regs) ((regs)->pc)
+-#if defined (CONFIG_SH64_SR_WATCH)
+-#define SR_ENABLE_MMU	0x0000000084000000	/* OR with this */
+-#else
+-#define SR_ENABLE_MMU	0x0000000080000000	/* OR with this */
+-#endif
 -
--#define profile_pc(regs) instruction_pointer(regs)
- 
- #endif /* __KERNEL__ */
- 
-diff --git a/include/asm-avr32/thread_info.h b/include/asm-avr32/thread_info.h
-index 184b574..07049f6 100644
---- a/include/asm-avr32/thread_info.h
-+++ b/include/asm-avr32/thread_info.h
-@@ -88,6 +88,7 @@ static inline struct thread_info *current_thread_info(void)
- #define TIF_MEMDIE		6
- #define TIF_RESTORE_SIGMASK	7	/* restore signal mask in do_signal */
- #define TIF_CPU_GOING_TO_SLEEP	8	/* CPU is entering sleep 0 mode */
-+#define TIF_DEBUG		30	/* debugging enabled */
- #define TIF_USERSPACE		31      /* true if FS sets userspace */
- 
- #define _TIF_SYSCALL_TRACE	(1 << TIF_SYSCALL_TRACE)
-diff --git a/include/asm-blackfin/bfin-global.h b/include/asm-blackfin/bfin-global.h
-index 39bdd86..6ae0619 100644
---- a/include/asm-blackfin/bfin-global.h
-+++ b/include/asm-blackfin/bfin-global.h
-@@ -51,7 +51,7 @@ extern unsigned long sclk_to_usecs(unsigned long sclk);
- extern unsigned long usecs_to_sclk(unsigned long usecs);
- 
- extern void dump_bfin_process(struct pt_regs *regs);
--extern void dump_bfin_mem(void *retaddr);
-+extern void dump_bfin_mem(struct pt_regs *regs);
- extern void dump_bfin_trace_buffer(void);
- 
- extern int init_arch_irq(void);
-diff --git a/include/asm-blackfin/cplb-mpu.h b/include/asm-blackfin/cplb-mpu.h
-new file mode 100644
-index 0000000..75c67b9
---- /dev/null
-+++ b/include/asm-blackfin/cplb-mpu.h
-@@ -0,0 +1,61 @@
-+/*
-+ * File:         include/asm-blackfin/cplbinit.h
-+ * Based on:
-+ * Author:
-+ *
-+ * Created:
-+ * Description:
-+ *
-+ * Modified:
-+ *               Copyright 2004-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 __ASM_BFIN_CPLB_MPU_H
-+#define __ASM_BFIN_CPLB_MPU_H
-+
-+struct cplb_entry {
-+	unsigned long data, addr;
-+};
-+
-+struct mem_region {
-+	unsigned long start, end;
-+	unsigned long dcplb_data;
-+	unsigned long icplb_data;
-+};
-+
-+extern struct cplb_entry dcplb_tbl[MAX_CPLBS];
-+extern struct cplb_entry icplb_tbl[MAX_CPLBS];
-+extern int first_switched_icplb;
-+extern int first_mask_dcplb;
-+extern int first_switched_dcplb;
-+
-+extern int nr_dcplb_miss, nr_icplb_miss, nr_icplb_supv_miss, nr_dcplb_prot;
-+extern int nr_cplb_flush;
-+
-+extern int page_mask_order;
-+extern int page_mask_nelts;
-+
-+extern unsigned long *current_rwx_mask;
-+
-+extern void flush_switched_cplbs(void);
-+extern void set_mask_dcplbs(unsigned long *);
-+
-+extern void __noreturn panic_cplb_error(int seqstat, struct pt_regs *);
-+
-+#endif /* __ASM_BFIN_CPLB_MPU_H */
-diff --git a/include/asm-blackfin/cplb.h b/include/asm-blackfin/cplb.h
-index 06828d7..654375c 100644
---- a/include/asm-blackfin/cplb.h
-+++ b/include/asm-blackfin/cplb.h
-@@ -65,7 +65,11 @@
- #define SIZE_1M 0x00100000      /* 1M */
- #define SIZE_4M 0x00400000      /* 4M */
- 
-+#ifdef CONFIG_MPU
-+#define MAX_CPLBS 16
-+#else
- #define MAX_CPLBS (16 * 2)
-+#endif
- 
- #define ASYNC_MEMORY_CPLB_COVERAGE	((ASYNC_BANK0_SIZE + ASYNC_BANK1_SIZE + \
- 				 ASYNC_BANK2_SIZE + ASYNC_BANK3_SIZE) / SIZE_4M)
-diff --git a/include/asm-blackfin/cplbinit.h b/include/asm-blackfin/cplbinit.h
-index c4d0596..0eb1c1b 100644
---- a/include/asm-blackfin/cplbinit.h
-+++ b/include/asm-blackfin/cplbinit.h
-@@ -33,6 +33,12 @@
- #include <asm/blackfin.h>
- #include <asm/cplb.h>
- 
-+#ifdef CONFIG_MPU
-+
-+#include <asm/cplb-mpu.h>
-+
-+#else
-+
- #define INITIAL_T 0x1
- #define SWITCH_T  0x2
- #define I_CPLB    0x4
-@@ -79,6 +85,8 @@ extern u_long ipdt_swapcount_table[];
- extern u_long dpdt_swapcount_table[];
- #endif
- 
-+#endif /* CONFIG_MPU */
-+
- extern unsigned long reserved_mem_dcache_on;
- extern unsigned long reserved_mem_icache_on;
- 
-diff --git a/include/asm-blackfin/dma.h b/include/asm-blackfin/dma.h
-index b469505..5abaa2c 100644
---- a/include/asm-blackfin/dma.h
-+++ b/include/asm-blackfin/dma.h
-@@ -76,6 +76,9 @@ enum dma_chan_status {
- #define INTR_ON_BUF    2
- #define INTR_ON_ROW    3
- 
-+#define DMA_NOSYNC_KEEP_DMA_BUF	0
-+#define DMA_SYNC_RESTART	1
-+
- struct dmasg {
- 	unsigned long next_desc_addr;
- 	unsigned long start_addr;
-@@ -157,7 +160,8 @@ void set_dma_y_count(unsigned int channel, unsigned short y_count);
- void set_dma_y_modify(unsigned int channel, short y_modify);
- void set_dma_config(unsigned int channel, unsigned short config);
- unsigned short set_bfin_dma_config(char direction, char flow_mode,
--				   char intr_mode, char dma_mode, char width);
-+				   char intr_mode, char dma_mode, char width,
-+				   char syncmode);
- void set_dma_curr_addr(unsigned int channel, unsigned long addr);
- 
- /* get curr status for polling */
-diff --git a/include/asm-blackfin/gpio.h b/include/asm-blackfin/gpio.h
-index 33ce98e..d0426c1 100644
---- a/include/asm-blackfin/gpio.h
-+++ b/include/asm-blackfin/gpio.h
-@@ -7,7 +7,7 @@
-  * Description:
-  *
-  * Modified:
-- *               Copyright 2004-2006 Analog Devices Inc.
-+ *               Copyright 2004-2008 Analog Devices Inc.
-  *
-  * Bugs:         Enter bugs at http://blackfin.uclinux.org/
-  *
-@@ -304,39 +304,39 @@
- **************************************************************/
- 
- #ifndef BF548_FAMILY
--void set_gpio_dir(unsigned short, unsigned short);
--void set_gpio_inen(unsigned short, unsigned short);
--void set_gpio_polar(unsigned short, unsigned short);
--void set_gpio_edge(unsigned short, unsigned short);
--void set_gpio_both(unsigned short, unsigned short);
--void set_gpio_data(unsigned short, unsigned short);
--void set_gpio_maska(unsigned short, unsigned short);
--void set_gpio_maskb(unsigned short, unsigned short);
--void set_gpio_toggle(unsigned short);
--void set_gpiop_dir(unsigned short, unsigned short);
--void set_gpiop_inen(unsigned short, unsigned short);
--void set_gpiop_polar(unsigned short, unsigned short);
--void set_gpiop_edge(unsigned short, unsigned short);
--void set_gpiop_both(unsigned short, unsigned short);
--void set_gpiop_data(unsigned short, unsigned short);
--void set_gpiop_maska(unsigned short, unsigned short);
--void set_gpiop_maskb(unsigned short, unsigned short);
--unsigned short get_gpio_dir(unsigned short);
--unsigned short get_gpio_inen(unsigned short);
--unsigned short get_gpio_polar(unsigned short);
--unsigned short get_gpio_edge(unsigned short);
--unsigned short get_gpio_both(unsigned short);
--unsigned short get_gpio_maska(unsigned short);
--unsigned short get_gpio_maskb(unsigned short);
--unsigned short get_gpio_data(unsigned short);
--unsigned short get_gpiop_dir(unsigned short);
--unsigned short get_gpiop_inen(unsigned short);
--unsigned short get_gpiop_polar(unsigned short);
--unsigned short get_gpiop_edge(unsigned short);
--unsigned short get_gpiop_both(unsigned short);
--unsigned short get_gpiop_maska(unsigned short);
--unsigned short get_gpiop_maskb(unsigned short);
--unsigned short get_gpiop_data(unsigned short);
-+void set_gpio_dir(unsigned, unsigned short);
-+void set_gpio_inen(unsigned, unsigned short);
-+void set_gpio_polar(unsigned, unsigned short);
-+void set_gpio_edge(unsigned, unsigned short);
-+void set_gpio_both(unsigned, unsigned short);
-+void set_gpio_data(unsigned, unsigned short);
-+void set_gpio_maska(unsigned, unsigned short);
-+void set_gpio_maskb(unsigned, unsigned short);
-+void set_gpio_toggle(unsigned);
-+void set_gpiop_dir(unsigned, unsigned short);
-+void set_gpiop_inen(unsigned, unsigned short);
-+void set_gpiop_polar(unsigned, unsigned short);
-+void set_gpiop_edge(unsigned, unsigned short);
-+void set_gpiop_both(unsigned, unsigned short);
-+void set_gpiop_data(unsigned, unsigned short);
-+void set_gpiop_maska(unsigned, unsigned short);
-+void set_gpiop_maskb(unsigned, unsigned short);
-+unsigned short get_gpio_dir(unsigned);
-+unsigned short get_gpio_inen(unsigned);
-+unsigned short get_gpio_polar(unsigned);
-+unsigned short get_gpio_edge(unsigned);
-+unsigned short get_gpio_both(unsigned);
-+unsigned short get_gpio_maska(unsigned);
-+unsigned short get_gpio_maskb(unsigned);
-+unsigned short get_gpio_data(unsigned);
-+unsigned short get_gpiop_dir(unsigned);
-+unsigned short get_gpiop_inen(unsigned);
-+unsigned short get_gpiop_polar(unsigned);
-+unsigned short get_gpiop_edge(unsigned);
-+unsigned short get_gpiop_both(unsigned);
-+unsigned short get_gpiop_maska(unsigned);
-+unsigned short get_gpiop_maskb(unsigned);
-+unsigned short get_gpiop_data(unsigned);
- 
- struct gpio_port_t {
- 	unsigned short data;
-@@ -382,8 +382,8 @@ struct gpio_port_t {
- #define PM_WAKE_LOW	0x8
- #define PM_WAKE_BOTH_EDGES	(PM_WAKE_RISING | PM_WAKE_FALLING)
- 
--int gpio_pm_wakeup_request(unsigned short gpio, unsigned char type);
--void gpio_pm_wakeup_free(unsigned short gpio);
-+int gpio_pm_wakeup_request(unsigned gpio, unsigned char type);
-+void gpio_pm_wakeup_free(unsigned gpio);
- unsigned int gpio_pm_setup(void);
- void gpio_pm_restore(void);
- 
-@@ -426,19 +426,19 @@ struct gpio_port_s {
- * MODIFICATION HISTORY :
- **************************************************************/
- 
--int gpio_request(unsigned short, const char *);
--void gpio_free(unsigned short);
-+int gpio_request(unsigned, const char *);
-+void gpio_free(unsigned);
- 
--void gpio_set_value(unsigned short gpio, unsigned short arg);
--unsigned short gpio_get_value(unsigned short gpio);
-+void gpio_set_value(unsigned gpio, int arg);
-+int gpio_get_value(unsigned gpio);
- 
- #ifndef BF548_FAMILY
- #define gpio_get_value(gpio) 		get_gpio_data(gpio)
- #define gpio_set_value(gpio, value)	set_gpio_data(gpio, value)
- #endif
- 
--void gpio_direction_input(unsigned short gpio);
--void gpio_direction_output(unsigned short gpio);
-+int gpio_direction_input(unsigned gpio);
-+int gpio_direction_output(unsigned gpio, int value);
- 
- #include <asm-generic/gpio.h>		/* cansleep wrappers */
- #include <asm/irq.h>
-diff --git a/include/asm-blackfin/mach-bf527/bfin_serial_5xx.h b/include/asm-blackfin/mach-bf527/bfin_serial_5xx.h
-index 0b867e6..15dbc21 100644
---- a/include/asm-blackfin/mach-bf527/bfin_serial_5xx.h
-+++ b/include/asm-blackfin/mach-bf527/bfin_serial_5xx.h
-@@ -146,7 +146,7 @@ static void bfin_serial_hw_init(struct bfin_serial_port *uart)
- 
- 	if (uart->rts_pin >= 0) {
- 		gpio_request(uart->rts_pin, DRIVER_NAME);
--		gpio_direction_output(uart->rts_pin);
-+		gpio_direction_output(uart->rts_pin, 0);
- 	}
- #endif
- }
-diff --git a/include/asm-blackfin/mach-bf527/portmux.h b/include/asm-blackfin/mach-bf527/portmux.h
-index dcf001a..ae4d205 100644
---- a/include/asm-blackfin/mach-bf527/portmux.h
-+++ b/include/asm-blackfin/mach-bf527/portmux.h
-@@ -1,6 +1,8 @@
- #ifndef _MACH_PORTMUX_H_
- #define _MACH_PORTMUX_H_
- 
-+#define MAX_RESOURCES 	MAX_BLACKFIN_GPIOS
-+
- #define P_PPI0_D0	(P_DEFINED | P_IDENT(GPIO_PF0) | P_FUNCT(0))
- #define P_PPI0_D1	(P_DEFINED | P_IDENT(GPIO_PF1) | P_FUNCT(0))
- #define P_PPI0_D2	(P_DEFINED | P_IDENT(GPIO_PF2) | P_FUNCT(0))
-diff --git a/include/asm-blackfin/mach-bf533/anomaly.h b/include/asm-blackfin/mach-bf533/anomaly.h
-index f36ff5a..98209d4 100644
---- a/include/asm-blackfin/mach-bf533/anomaly.h
-+++ b/include/asm-blackfin/mach-bf533/anomaly.h
-@@ -7,9 +7,7 @@
-  */
- 
- /* This file shoule be up to date with:
-- *  - Revision X,  March 23, 2007; ADSP-BF533 Blackfin Processor Anomaly List
-- *  - Revision AB, March 23, 2007; ADSP-BF532 Blackfin Processor Anomaly List
-- *  - Revision W,  March 23, 2007; ADSP-BF531 Blackfin Processor Anomaly List
-+ *  - Revision B, 12/10/2007; ADSP-BF531/BF532/BF533 Blackfin Processor Anomaly List
-  */
- 
- #ifndef _MACH_ANOMALY_H_
-@@ -17,7 +15,7 @@
- 
- /* We do not support 0.1 or 0.2 silicon - sorry */
- #if __SILICON_REVISION__ < 3
--# error Kernel will not work on BF533 silicon version 0.0, 0.1, or 0.2
-+# error will not work on BF533 silicon version 0.0, 0.1, or 0.2
- #endif
- 
- #if defined(__ADSPBF531__)
-@@ -251,6 +249,12 @@
- #define ANOMALY_05000192 (__SILICON_REVISION__ < 3)
- /* Internal Voltage Regulator may not start up */
- #define ANOMALY_05000206 (__SILICON_REVISION__ < 3)
-+/* Serial Port (SPORT) Multichannel Transmit Failure when Channel 0 Is Disabled */
-+#define ANOMALY_05000357 (1)
-+/* 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)
- 
- /* Anomalies that don't exist on this proc */
- #define ANOMALY_05000266 (0)
-diff --git a/include/asm-blackfin/mach-bf533/bfin_serial_5xx.h b/include/asm-blackfin/mach-bf533/bfin_serial_5xx.h
-index 69b9f8e..7871d43 100644
---- a/include/asm-blackfin/mach-bf533/bfin_serial_5xx.h
-+++ b/include/asm-blackfin/mach-bf533/bfin_serial_5xx.h
-@@ -111,7 +111,7 @@ static void bfin_serial_hw_init(struct bfin_serial_port *uart)
- 	}
- 	if (uart->rts_pin >= 0) {
- 		gpio_request(uart->rts_pin, DRIVER_NAME);
--		gpio_direction_input(uart->rts_pin);
-+		gpio_direction_input(uart->rts_pin, 0);
- 	}
- #endif
- }
-diff --git a/include/asm-blackfin/mach-bf533/portmux.h b/include/asm-blackfin/mach-bf533/portmux.h
-index 137f488..685a265 100644
---- a/include/asm-blackfin/mach-bf533/portmux.h
-+++ b/include/asm-blackfin/mach-bf533/portmux.h
-@@ -1,6 +1,8 @@
- #ifndef _MACH_PORTMUX_H_
- #define _MACH_PORTMUX_H_
- 
-+#define MAX_RESOURCES 	MAX_BLACKFIN_GPIOS
-+
- #define P_PPI0_CLK	(P_DONTCARE)
- #define P_PPI0_FS1	(P_DONTCARE)
- #define P_PPI0_FS2	(P_DONTCARE)
-diff --git a/include/asm-blackfin/mach-bf537/anomaly.h b/include/asm-blackfin/mach-bf537/anomaly.h
-index 2b66ecf..746a794 100644
---- a/include/asm-blackfin/mach-bf537/anomaly.h
-+++ b/include/asm-blackfin/mach-bf537/anomaly.h
-@@ -7,9 +7,7 @@
-  */
- 
- /* This file shoule be up to date with:
-- *  - Revision M, March 13, 2007; ADSP-BF537 Blackfin Processor Anomaly List
-- *  - Revision L, March 13, 2007; ADSP-BF536 Blackfin Processor Anomaly List
-- *  - Revision M, March 13, 2007; ADSP-BF534 Blackfin Processor Anomaly List
-+ *  - Revision A, 09/04/2007; ADSP-BF534/ADSP-BF536/ADSP-BF537 Blackfin Processor Anomaly List
-  */
- 
- #ifndef _MACH_ANOMALY_H_
-@@ -17,7 +15,7 @@
- 
- /* We do not support 0.1 silicon - sorry */
- #if __SILICON_REVISION__ < 2
--# error Kernel will not work on BF537 silicon version 0.0 or 0.1
-+# error will not work on BF537 silicon version 0.0 or 0.1
- #endif
- 
- #if defined(__ADSPBF534__)
-@@ -44,6 +42,8 @@
- #define ANOMALY_05000122 (1)
- /* Killed 32-bit MMR write leads to next system MMR access thinking it should be 32-bit */
- #define ANOMALY_05000157 (__SILICON_REVISION__ < 2)
-+/* Turning SPORTs on while External Frame Sync Is Active May Corrupt Data */
-+#define ANOMALY_05000167 (1)
- /* PPI_DELAY not functional in PPI modes with 0 frame syncs */
- #define ANOMALY_05000180 (1)
- /* Instruction Cache Is Not Functional */
-@@ -130,6 +130,12 @@
- #define ANOMALY_05000321 (__SILICON_REVISION__ < 3)
- /* EMAC RMII mode at 10-Base-T speed: RX frames not received properly */
- #define ANOMALY_05000322 (1)
-+/* Ethernet MAC MDIO Reads Do Not Meet IEEE Specification */
-+#define ANOMALY_05000341 (__SILICON_REVISION__ >= 3)
-+/* Serial Port (SPORT) Multichannel Transmit Failure when Channel 0 Is Disabled */
-+#define ANOMALY_05000357 (1)
-+/* DMAs that Go Urgent during Tight Core Writes to External Memory Are Blocked */
-+#define ANOMALY_05000359 (1)
- 
- /* Anomalies that don't exist on this proc */
- #define ANOMALY_05000125 (0)
-diff --git a/include/asm-blackfin/mach-bf537/bfin_serial_5xx.h b/include/asm-blackfin/mach-bf537/bfin_serial_5xx.h
-index 6fb328f..86e45c3 100644
---- a/include/asm-blackfin/mach-bf537/bfin_serial_5xx.h
-+++ b/include/asm-blackfin/mach-bf537/bfin_serial_5xx.h
-@@ -146,7 +146,7 @@ static void bfin_serial_hw_init(struct bfin_serial_port *uart)
- 
- 	if (uart->rts_pin >= 0) {
- 		gpio_request(uart->rts_pin, DRIVER_NAME);
--		gpio_direction_output(uart->rts_pin);
-+		gpio_direction_output(uart->rts_pin, 0);
- 	}
- #endif
- }
-diff --git a/include/asm-blackfin/mach-bf537/portmux.h b/include/asm-blackfin/mach-bf537/portmux.h
-index 5a3f7d3..78fee6e 100644
---- a/include/asm-blackfin/mach-bf537/portmux.h
-+++ b/include/asm-blackfin/mach-bf537/portmux.h
-@@ -1,6 +1,8 @@
- #ifndef _MACH_PORTMUX_H_
- #define _MACH_PORTMUX_H_
- 
-+#define MAX_RESOURCES 	(MAX_BLACKFIN_GPIOS + GPIO_BANKSIZE)	/* We additionally handle PORTJ */
-+
- #define P_UART0_TX	(P_DEFINED | P_IDENT(GPIO_PF0) | P_FUNCT(0))
- #define P_UART0_RX	(P_DEFINED | P_IDENT(GPIO_PF1) | P_FUNCT(0))
- #define P_UART1_TX	(P_DEFINED | P_IDENT(GPIO_PF2) | P_FUNCT(0))
-diff --git a/include/asm-blackfin/mach-bf548/anomaly.h b/include/asm-blackfin/mach-bf548/anomaly.h
-index c5b6375..850dc12 100644
---- a/include/asm-blackfin/mach-bf548/anomaly.h
-+++ b/include/asm-blackfin/mach-bf548/anomaly.h
-@@ -7,7 +7,7 @@
-  */
- 
- /* This file shoule be up to date with:
-- *  - Revision C, July 16, 2007; ADSP-BF549 Silicon Anomaly List
-+ *  - Revision E, 11/28/2007; ADSP-BF542/BF544/BF547/BF548/BF549 Blackfin Processor Anomaly List
-  */
- 
- #ifndef _MACH_ANOMALY_H_
-@@ -26,47 +26,59 @@
- /* Certain Data Cache Writethrough Modes Fail for Vddint <= 0.9V */
- #define ANOMALY_05000272 (1)
- /* False Hardware Error Exception when ISR context is not restored */
--#define ANOMALY_05000281 (1)
-+#define ANOMALY_05000281 (__SILICON_REVISION__ < 1)
- /* SSYNCs After Writes To CAN/DMA MMR Registers Are Not Always Handled Correctly */
--#define ANOMALY_05000304 (1)
-+#define ANOMALY_05000304 (__SILICON_REVISION__ < 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 (__SILICON_REVISION__ < 1)
- /* TWI Slave Boot Mode Is Not Functional */
--#define ANOMALY_05000324 (1)
-+#define ANOMALY_05000324 (__SILICON_REVISION__ < 1)
- /* External FIFO Boot Mode Is Not Functional */
--#define ANOMALY_05000325 (1)
-+#define ANOMALY_05000325 (__SILICON_REVISION__ < 1)
- /* Data Lost When Core and DMA Accesses Are Made to the USB FIFO Simultaneously */
--#define ANOMALY_05000327 (1)
-+#define ANOMALY_05000327 (__SILICON_REVISION__ < 1)
- /* Incorrect Access of OTP_STATUS During otp_write() Function */
--#define ANOMALY_05000328 (1)
-+#define ANOMALY_05000328 (__SILICON_REVISION__ < 1)
- /* Synchronous Burst Flash Boot Mode Is Not Functional */
--#define ANOMALY_05000329 (1)
-+#define ANOMALY_05000329 (__SILICON_REVISION__ < 1)
- /* Host DMA Boot Mode Is Not Functional */
--#define ANOMALY_05000330 (1)
-+#define ANOMALY_05000330 (__SILICON_REVISION__ < 1)
- /* Inadequate Timing Margins on DDR DQS to DQ and DQM Skew */
--#define ANOMALY_05000334 (1)
-+#define ANOMALY_05000334 (__SILICON_REVISION__ < 1)
- /* Inadequate Rotary Debounce Logic Duration */
--#define ANOMALY_05000335 (1)
-+#define ANOMALY_05000335 (__SILICON_REVISION__ < 1)
- /* Phantom Interrupt Occurs After First Configuration of Host DMA Port */
--#define ANOMALY_05000336 (1)
-+#define ANOMALY_05000336 (__SILICON_REVISION__ < 1)
- /* Disallowed Configuration Prevents Subsequent Allowed Configuration on Host DMA Port */
--#define ANOMALY_05000337 (1)
-+#define ANOMALY_05000337 (__SILICON_REVISION__ < 1)
- /* Slave-Mode SPI0 MISO Failure With CPHA = 0 */
--#define ANOMALY_05000338 (1)
-+#define ANOMALY_05000338 (__SILICON_REVISION__ < 1)
- /* If Memory Reads Are Enabled on SDH or HOSTDP, Other DMAC1 Peripherals Cannot Read */
--#define ANOMALY_05000340 (1)
-+#define ANOMALY_05000340 (__SILICON_REVISION__ < 1)
- /* Boot Host Wait (HWAIT) and Boot Host Wait Alternate (HWAITA) Signals Are Swapped */
--#define ANOMALY_05000344 (1)
-+#define ANOMALY_05000344 (__SILICON_REVISION__ < 1)
- /* USB Calibration Value Is Not Intialized */
--#define ANOMALY_05000346 (1)
-+#define ANOMALY_05000346 (__SILICON_REVISION__ < 1)
- /* Boot ROM Kernel Incorrectly Alters Reset Value of USB Register */
--#define ANOMALY_05000347 (1)
-+#define ANOMALY_05000347 (__SILICON_REVISION__ < 1)
- /* Data Lost when Core Reads SDH Data FIFO */
--#define ANOMALY_05000349 (1)
-+#define ANOMALY_05000349 (__SILICON_REVISION__ < 1)
- /* PLL Status Register Is Inaccurate */
--#define ANOMALY_05000351 (1)
-+#define ANOMALY_05000351 (__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)
-+/* Addressing Conflict between Boot ROM and Asynchronous Memory */
-+#define ANOMALY_05000369 (1)
-+/* Mobile DDR Operation Not Functional */
-+#define ANOMALY_05000377 (1)
-+/* Security/Authentication Speedpath Causes Authentication To Fail To Initiate */
-+#define ANOMALY_05000378 (1)
- 
- /* Anomalies that don't exist on this proc */
- #define ANOMALY_05000125 (0)
-diff --git a/include/asm-blackfin/mach-bf548/bfin_serial_5xx.h b/include/asm-blackfin/mach-bf548/bfin_serial_5xx.h
-index f21a162..3770aa3 100644
---- a/include/asm-blackfin/mach-bf548/bfin_serial_5xx.h
-+++ b/include/asm-blackfin/mach-bf548/bfin_serial_5xx.h
-@@ -186,7 +186,7 @@ static void bfin_serial_hw_init(struct bfin_serial_port *uart)
- 
- 	if (uart->rts_pin >= 0) {
- 		gpio_request(uart->rts_pin, DRIVER_NAME);
--		gpio_direction_output(uart->rts_pin);
-+		gpio_direction_output(uart->rts_pin, 0);
- 	}
- #endif
- }
-diff --git a/include/asm-blackfin/mach-bf548/cdefBF54x_base.h b/include/asm-blackfin/mach-bf548/cdefBF54x_base.h
-index aefab3f..19ddcd8 100644
---- a/include/asm-blackfin/mach-bf548/cdefBF54x_base.h
-+++ b/include/asm-blackfin/mach-bf548/cdefBF54x_base.h
-@@ -244,39 +244,6 @@ static __inline__ void bfin_write_VR_CTL(unsigned int val)
- #define bfin_read_TWI0_RCV_DATA16()		bfin_read16(TWI0_RCV_DATA16)
- #define bfin_write_TWI0_RCV_DATA16(val)		bfin_write16(TWI0_RCV_DATA16, val)
- 
--#define bfin_read_TWI_CLKDIV()			bfin_read16(TWI0_CLKDIV)
--#define bfin_write_TWI_CLKDIV(val)		bfin_write16(TWI0_CLKDIV, val)
--#define bfin_read_TWI_CONTROL()			bfin_read16(TWI0_CONTROL)
--#define bfin_write_TWI_CONTROL(val)		bfin_write16(TWI0_CONTROL, val)
--#define bfin_read_TWI_SLAVE_CTRL()		bfin_read16(TWI0_SLAVE_CTRL)
--#define bfin_write_TWI_SLAVE_CTRL(val)		bfin_write16(TWI0_SLAVE_CTRL, val)
--#define bfin_read_TWI_SLAVE_STAT()		bfin_read16(TWI0_SLAVE_STAT)
--#define bfin_write_TWI_SLAVE_STAT(val)		bfin_write16(TWI0_SLAVE_STAT, val)
--#define bfin_read_TWI_SLAVE_ADDR()		bfin_read16(TWI0_SLAVE_ADDR)
--#define bfin_write_TWI_SLAVE_ADDR(val)		bfin_write16(TWI0_SLAVE_ADDR, val)
--#define bfin_read_TWI_MASTER_CTL()		bfin_read16(TWI0_MASTER_CTRL)
--#define bfin_write_TWI_MASTER_CTL(val)		bfin_write16(TWI0_MASTER_CTRL, val)
--#define bfin_read_TWI_MASTER_STAT()		bfin_read16(TWI0_MASTER_STAT)
--#define bfin_write_TWI_MASTER_STAT(val)		bfin_write16(TWI0_MASTER_STAT, val)
--#define bfin_read_TWI_MASTER_ADDR()		bfin_read16(TWI0_MASTER_ADDR)
--#define bfin_write_TWI_MASTER_ADDR(val)		bfin_write16(TWI0_MASTER_ADDR, val)
--#define bfin_read_TWI_INT_STAT()		bfin_read16(TWI0_INT_STAT)
--#define bfin_write_TWI_INT_STAT(val)		bfin_write16(TWI0_INT_STAT, val)
--#define bfin_read_TWI_INT_MASK()		bfin_read16(TWI0_INT_MASK)
--#define bfin_write_TWI_INT_MASK(val)		bfin_write16(TWI0_INT_MASK, val)
--#define bfin_read_TWI_FIFO_CTL()		bfin_read16(TWI0_FIFO_CTRL)
--#define bfin_write_TWI_FIFO_CTL(val)		bfin_write16(TWI0_FIFO_CTRL, val)
--#define bfin_read_TWI_FIFO_STAT()		bfin_read16(TWI0_FIFO_STAT)
--#define bfin_write_TWI_FIFO_STAT(val)		bfin_write16(TWI0_FIFO_STAT, val)
--#define bfin_read_TWI_XMT_DATA8()		bfin_read16(TWI0_XMT_DATA8)
--#define bfin_write_TWI_XMT_DATA8(val)		bfin_write16(TWI0_XMT_DATA8, val)
--#define bfin_read_TWI_XMT_DATA16()		bfin_read16(TWI0_XMT_DATA16)
--#define bfin_write_TWI_XMT_DATA16(val)		bfin_write16(TWI0_XMT_DATA16, val)
--#define bfin_read_TWI_RCV_DATA8()		bfin_read16(TWI0_RCV_DATA8)
--#define bfin_write_TWI_RCV_DATA8(val)		bfin_write16(TWI0_RCV_DATA8, val)
--#define bfin_read_TWI_RCV_DATA16()		bfin_read16(TWI0_RCV_DATA16)
--#define bfin_write_TWI_RCV_DATA16(val)		bfin_write16(TWI0_RCV_DATA16, val)
+-#define SR_UNBLOCK_EXC	0xffffffffefffffff	/* AND with this */
+-#define SR_BLOCK_EXC	0x0000000010000000	/* OR with this */
+-
+-#else	/* Not __ASSEMBLY__ syntax */
+-
+-/*
+-** Stringify reg. name
+-*/
+-#define __str(x)  #x
+-
+-/* Stringify control register names for use in inline assembly */
+-#define __SR __str(SR)
+-#define __SSR __str(SSR)
+-#define __PSSR __str(PSSR)
+-#define __INTEVT __str(INTEVT)
+-#define __EXPEVT __str(EXPEVT)
+-#define __PEXPEVT __str(PEXPEVT)
+-#define __TRA __str(TRA)
+-#define __SPC __str(SPC)
+-#define __PSPC __str(PSPC)
+-#define __RESVEC __str(RESVEC)
+-#define __VBR __str(VBR)
+-#define __TEA __str(TEA)
+-#define __DCR __str(DCR)
+-#define __KCR0 __str(KCR0)
+-#define __KCR1 __str(KCR1)
+-#define __CTC __str(CTC)
+-#define __USR __str(USR)
+-
+-#endif /* __ASSEMBLY__ */
+-#endif /* __ASM_SH64_REGISTERS_H */
+diff --git a/include/asm-sh64/resource.h b/include/asm-sh64/resource.h
+deleted file mode 100644
+index 8ff9394..0000000
+--- a/include/asm-sh64/resource.h
++++ /dev/null
+@@ -1,6 +0,0 @@
+-#ifndef __ASM_SH64_RESOURCE_H
+-#define __ASM_SH64_RESOURCE_H
+-
+-#include <asm-sh/resource.h>
+-
+-#endif /* __ASM_SH64_RESOURCE_H */
+diff --git a/include/asm-sh64/scatterlist.h b/include/asm-sh64/scatterlist.h
+deleted file mode 100644
+index 7f729bb..0000000
+--- a/include/asm-sh64/scatterlist.h
++++ /dev/null
+@@ -1,37 +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.
+- *
+- * include/asm-sh64/scatterlist.h
+- *
+- * Copyright (C) 2003  Paul Mundt
+- *
+- */
+-#ifndef __ASM_SH64_SCATTERLIST_H
+-#define __ASM_SH64_SCATTERLIST_H
 -
- /* SPORT0 is not defined in the shared file because it is not available on the ADSP-BF542 and ADSP-BF544 bfin_read_()rocessors */
- 
- /* SPORT1 Registers */
-diff --git a/include/asm-blackfin/mach-bf548/defBF542.h b/include/asm-blackfin/mach-bf548/defBF542.h
-index 32d0713..a7c809f 100644
---- a/include/asm-blackfin/mach-bf548/defBF542.h
-+++ b/include/asm-blackfin/mach-bf548/defBF542.h
-@@ -432,8 +432,8 @@
- 
- #define              CMD_CRC_FAIL  0x1        /* CMD CRC Fail */
- #define              DAT_CRC_FAIL  0x2        /* Data CRC Fail */
--#define               CMD_TIMEOUT  0x4        /* CMD Time Out */
--#define               DAT_TIMEOUT  0x8        /* Data Time Out */
-+#define               CMD_TIME_OUT  0x4        /* CMD Time Out */
-+#define               DAT_TIME_OUT  0x8        /* Data Time Out */
- #define               TX_UNDERRUN  0x10       /* Transmit Underrun */
- #define                RX_OVERRUN  0x20       /* Receive Overrun */
- #define              CMD_RESP_END  0x40       /* CMD Response End */
-diff --git a/include/asm-blackfin/mach-bf548/defBF548.h b/include/asm-blackfin/mach-bf548/defBF548.h
-index ecbca95..e46f568 100644
---- a/include/asm-blackfin/mach-bf548/defBF548.h
-+++ b/include/asm-blackfin/mach-bf548/defBF548.h
-@@ -1095,8 +1095,8 @@
- 
- #define              CMD_CRC_FAIL  0x1        /* CMD CRC Fail */
- #define              DAT_CRC_FAIL  0x2        /* Data CRC Fail */
--#define               CMD_TIMEOUT  0x4        /* CMD Time Out */
--#define               DAT_TIMEOUT  0x8        /* Data Time Out */
-+#define               CMD_TIME_OUT  0x4        /* CMD Time Out */
-+#define               DAT_TIME_OUT  0x8        /* Data Time Out */
- #define               TX_UNDERRUN  0x10       /* Transmit Underrun */
- #define                RX_OVERRUN  0x20       /* Receive Overrun */
- #define              CMD_RESP_END  0x40       /* CMD Response End */
-diff --git a/include/asm-blackfin/mach-bf548/defBF54x_base.h b/include/asm-blackfin/mach-bf548/defBF54x_base.h
-index 319a485..08f90c2 100644
---- a/include/asm-blackfin/mach-bf548/defBF54x_base.h
-+++ b/include/asm-blackfin/mach-bf548/defBF54x_base.h
-@@ -1772,17 +1772,36 @@
- #define                       TRP  0x3c0000   /* Pre charge-to-active command period */
- #define                      TRAS  0x3c00000  /* Min Active-to-pre charge time */
- #define                       TRC  0x3c000000 /* Active-to-active time */
-+#define DDR_TRAS(x)		((x<<22)&TRAS)	/* DDR tRAS = (1~15) cycles */
-+#define DDR_TRP(x)		((x<<18)&TRP)	/* DDR tRP = (1~15) cycles */
-+#define DDR_TRC(x)		((x<<26)&TRC)	/* DDR tRC = (1~15) cycles */
-+#define DDR_TRFC(x)		((x<<14)&TRFC)	/* DDR tRFC = (1~15) cycles */
-+#define DDR_TREFI(x)		(x&TREFI)	/* DDR tRFC = (1~15) cycles */
- 
- /* Bit masks for EBIU_DDRCTL1 */
- 
- #define                      TRCD  0xf        /* Active-to-Read/write delay */
--#define                       MRD  0xf0       /* Mode register set to active */
-+#define                      TMRD  0xf0       /* Mode register set to active */
- #define                       TWR  0x300      /* Write Recovery time */
- #define               DDRDATWIDTH  0x3000     /* DDR data width */
- #define                  EXTBANKS  0xc000     /* External banks */
- #define               DDRDEVWIDTH  0x30000    /* DDR device width */
- #define                DDRDEVSIZE  0xc0000    /* DDR device size */
--#define                     TWWTR  0xf0000000 /* Write-to-read delay */
-+#define                      TWTR  0xf0000000 /* Write-to-read delay */
-+#define DDR_TWTR(x)		((x<<28)&TWTR)	/* DDR tWTR = (1~15) cycles */
-+#define DDR_TMRD(x)		((x<<4)&TMRD)	/* DDR tMRD = (1~15) cycles */
-+#define DDR_TWR(x)		((x<<8)&TWR)	/* DDR tWR = (1~15) cycles */
-+#define DDR_TRCD(x)		(x&TRCD)	/* DDR tRCD = (1~15) cycles */
-+#define DDR_DATWIDTH		0x2000		/* DDR data width */
-+#define EXTBANK_1		0		/* 1 external bank */
-+#define EXTBANK_2		0x4000		/* 2 external banks */
-+#define DEVSZ_64		0x40000		/* DDR External Bank Size = 64MB */
-+#define DEVSZ_128		0x80000		/* DDR External Bank Size = 128MB */
-+#define DEVSZ_256		0xc0000		/* DDR External Bank Size = 256MB */
-+#define DEVSZ_512		0		/* DDR External Bank Size = 512MB */
-+#define DEVWD_4			0		/* DDR Device Width = 4 Bits    */
-+#define DEVWD_8			0x10000		/* DDR Device Width = 8 Bits    */
-+#define DEVWD_16		0x20000		/* DDR Device Width = 16 Bits    */
- 
- /* Bit masks for EBIU_DDRCTL2 */
- 
-@@ -1790,6 +1809,10 @@
- #define                CASLATENCY  0x70       /* CAS latency */
- #define                  DLLRESET  0x100      /* DLL Reset */
- #define                      REGE  0x1000     /* Register mode enable */
-+#define CL_1_5			0x50		/* DDR CAS Latency = 1.5 cycles */
-+#define CL_2			0x20		/* DDR CAS Latency = 2 cycles */
-+#define CL_2_5			0x60		/* DDR CAS Latency = 2.5 cycles */
-+#define CL_3			0x30		/* DDR CAS Latency = 3 cycles */
- 
- /* Bit masks for EBIU_DDRCTL3 */
- 
-@@ -2257,6 +2280,10 @@
- 
- #define                      CSEL  0x30       /* Core Select */
- #define                      SSEL  0xf        /* System Select */
-+#define			CSEL_DIV1	0x0000	/* CCLK = VCO / 1 */
-+#define			CSEL_DIV2	0x0010	/* CCLK = VCO / 2 */
-+#define			CSEL_DIV4	0x0020	/* CCLK = VCO / 4 */
-+#define			CSEL_DIV8	0x0030	/* CCLK = VCO / 8 */
- 
- /* Bit masks for PLL_CTL */
- 
-diff --git a/include/asm-blackfin/mach-bf548/irq.h b/include/asm-blackfin/mach-bf548/irq.h
-index 9fb7bc5..c34507a 100644
---- a/include/asm-blackfin/mach-bf548/irq.h
-+++ b/include/asm-blackfin/mach-bf548/irq.h
-@@ -88,7 +88,7 @@ Events         (highest priority)  EMU         0
- #define IRQ_PINT1		BFIN_IRQ(20)	/* PINT1 Interrupt */
- #define IRQ_MDMAS0		BFIN_IRQ(21)	/* MDMA Stream 0 Interrupt */
- #define IRQ_MDMAS1		BFIN_IRQ(22)	/* MDMA Stream 1 Interrupt */
--#define IRQ_WATCHDOG		BFIN_IRQ(23)	/* Watchdog Interrupt */
-+#define IRQ_WATCH		BFIN_IRQ(23)	/* Watchdog Interrupt */
- #define IRQ_DMAC1_ERROR		BFIN_IRQ(24)	/* DMAC1 Status (Error) Interrupt */
- #define IRQ_SPORT2_ERROR	BFIN_IRQ(25)	/* SPORT2 Error Interrupt */
- #define IRQ_SPORT3_ERROR	BFIN_IRQ(26)	/* SPORT3 Error Interrupt */
-@@ -406,7 +406,7 @@ Events         (highest priority)  EMU         0
- #define IRQ_PINT1_POS		16
- #define IRQ_MDMAS0_POS		20
- #define IRQ_MDMAS1_POS		24
--#define IRQ_WATCHDOG_POS	28
-+#define IRQ_WATCH_POS		28
- 
- /* IAR3 BIT FIELDS */
- #define IRQ_DMAC1_ERR_POS	0
-diff --git a/include/asm-blackfin/mach-bf548/mem_init.h b/include/asm-blackfin/mach-bf548/mem_init.h
-index 0cb279e..befc290 100644
---- a/include/asm-blackfin/mach-bf548/mem_init.h
-+++ b/include/asm-blackfin/mach-bf548/mem_init.h
-@@ -28,8 +28,68 @@
-  * If not, write to the Free Software Foundation,
-  * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-  */
-+#define MIN_DDR_SCLK(x)	(x*(CONFIG_SCLK_HZ/1000/1000)/1000 + 1)
-+
-+#if (CONFIG_MEM_MT46V32M16_6T)
-+#define DDR_SIZE	DEVSZ_512
-+#define DDR_WIDTH	DEVWD_16
-+
-+#define DDR_tRC		DDR_TRC(MIN_DDR_SCLK(60))
-+#define DDR_tRAS	DDR_TRAS(MIN_DDR_SCLK(42))
-+#define DDR_tRP		DDR_TRP(MIN_DDR_SCLK(15))
-+#define DDR_tRFC	DDR_TRFC(MIN_DDR_SCLK(72))
-+#define DDR_tREFI	DDR_TREFI(MIN_DDR_SCLK(7800))
-+
-+#define DDR_tRCD	DDR_TRCD(MIN_DDR_SCLK(15))
-+#define DDR_tWTR	DDR_TWTR(1)
-+#define DDR_tMRD	DDR_TMRD(MIN_DDR_SCLK(12))
-+#define DDR_tWR		DDR_TWR(MIN_DDR_SCLK(15))
-+#endif
-+
-+#if (CONFIG_MEM_MT46V32M16_5B)
-+#define DDR_SIZE	DEVSZ_512
-+#define DDR_WIDTH	DEVWD_16
-+
-+#define DDR_tRC		DDR_TRC(MIN_DDR_SCLK(55))
-+#define DDR_tRAS	DDR_TRAS(MIN_DDR_SCLK(40))
-+#define DDR_tRP		DDR_TRP(MIN_DDR_SCLK(15))
-+#define DDR_tRFC	DDR_TRFC(MIN_DDR_SCLK(70))
-+#define DDR_tREFI	DDR_TREFI(MIN_DDR_SCLK(7800))
-+
-+#define DDR_tRCD	DDR_TRCD(MIN_DDR_SCLK(15))
-+#define DDR_tWTR	DDR_TWTR(2)
-+#define DDR_tMRD	DDR_TMRD(MIN_DDR_SCLK(10))
-+#define DDR_tWR		DDR_TWR(MIN_DDR_SCLK(15))
-+#endif
-+
-+#if (CONFIG_MEM_GENERIC_BOARD)
-+#define DDR_SIZE	DEVSZ_512
-+#define DDR_WIDTH	DEVWD_16
-+
-+#define DDR_tRCD	DDR_TRCD(3)
-+#define DDR_tWTR	DDR_TWTR(2)
-+#define DDR_tWR		DDR_TWR(2)
-+#define DDR_tMRD	DDR_TMRD(2)
-+#define DDR_tRP		DDR_TRP(3)
-+#define DDR_tRAS	DDR_TRAS(7)
-+#define DDR_tRC		DDR_TRC(10)
-+#define DDR_tRFC	DDR_TRFC(12)
-+#define DDR_tREFI	DDR_TREFI(1288)
-+#endif
-+
-+#if (CONFIG_SCLK_HZ <= 133333333)
-+#define	DDR_CL		CL_2
-+#elif (CONFIG_SCLK_HZ <= 166666666)
-+#define	DDR_CL		CL_2_5
-+#else
-+#define	DDR_CL		CL_3
-+#endif
-+
-+#define mem_DDRCTL0	(DDR_tRP | DDR_tRAS | DDR_tRC | DDR_tRFC | DDR_tREFI)
-+#define mem_DDRCTL1	(DDR_DATWIDTH | EXTBANK_1 | DDR_SIZE | DDR_WIDTH | DDR_tWTR \
-+			| DDR_tMRD | DDR_tWR | DDR_tRCD)
-+#define mem_DDRCTL2	DDR_CL
- 
--#if (CONFIG_MEM_MT46V32M16)
- 
- #if defined CONFIG_CLKIN_HALF
- #define CLKIN_HALF       1
-diff --git a/include/asm-blackfin/mach-bf548/portmux.h b/include/asm-blackfin/mach-bf548/portmux.h
-index 6b48512..8177a56 100644
---- a/include/asm-blackfin/mach-bf548/portmux.h
-+++ b/include/asm-blackfin/mach-bf548/portmux.h
-@@ -1,6 +1,8 @@
- #ifndef _MACH_PORTMUX_H_
- #define _MACH_PORTMUX_H_
- 
-+#define MAX_RESOURCES 	MAX_BLACKFIN_GPIOS
-+
- #define P_SPORT2_TFS	(P_DEFINED | P_IDENT(GPIO_PA0) | P_FUNCT(0))
- #define P_SPORT2_DTSEC	(P_DEFINED | P_IDENT(GPIO_PA1) | P_FUNCT(0))
- #define P_SPORT2_DTPRI	(P_DEFINED | P_IDENT(GPIO_PA2) | P_FUNCT(0))
-diff --git a/include/asm-blackfin/mach-bf561/anomaly.h b/include/asm-blackfin/mach-bf561/anomaly.h
-index bed9564..0c1d461 100644
---- a/include/asm-blackfin/mach-bf561/anomaly.h
-+++ b/include/asm-blackfin/mach-bf561/anomaly.h
-@@ -7,7 +7,7 @@
-  */
- 
- /* This file shoule be up to date with:
-- *  - Revision N, March 28, 2007; ADSP-BF561 Silicon Anomaly List
-+ *  - Revision O, 11/15/2007; ADSP-BF561 Blackfin Processor Anomaly List
-  */
- 
- #ifndef _MACH_ANOMALY_H_
-@@ -15,7 +15,7 @@
- 
- /* We do not support 0.1, 0.2, or 0.4 silicon - sorry */
- #if __SILICON_REVISION__ < 3 || __SILICON_REVISION__ == 4
--# error Kernel will not work on BF561 silicon version 0.0, 0.1, 0.2, or 0.4
-+# error will not work on BF561 silicon version 0.0, 0.1, 0.2, or 0.4
- #endif
- 
- /* Multi-Issue Instruction with dsp32shiftimm in slot1 and P-reg Store in slot 2 Not Supported */
-@@ -208,6 +208,8 @@
- #define ANOMALY_05000275 (__SILICON_REVISION__ > 2)
- /* Timing Requirements Change for External Frame Sync PPI Modes with Non-Zero PPI_DELAY */
- #define ANOMALY_05000276 (__SILICON_REVISION__ < 5)
-+/* Writes to an I/O data register one SCLK cycle after an edge is detected may clear interrupt */
-+#define ANOMALY_05000277 (__SILICON_REVISION__ < 3)
- /* Disabling Peripherals with DMA Running May Cause DMA System Instability */
- #define ANOMALY_05000278 (__SILICON_REVISION__ < 5)
- /* False Hardware Error Exception When ISR Context Is Not Restored */
-@@ -246,6 +248,18 @@
- #define ANOMALY_05000332 (__SILICON_REVISION__ < 5)
- /* Flag Data Register Writes One SCLK Cycle After Edge Is Detected May Clear Interrupt Status */
- #define ANOMALY_05000333 (__SILICON_REVISION__ < 5)
-+/* New Feature: Additional PPI Frame Sync Sampling Options (Not Available on Older Silicon) */
-+#define ANOMALY_05000339 (__SILICON_REVISION__ < 5)
-+/* Memory DMA FIFO Causes Throughput Degradation on Writes to External Memory */
-+#define ANOMALY_05000343 (__SILICON_REVISION__ < 5)
-+/* Serial Port (SPORT) Multichannel Transmit Failure when Channel 0 Is Disabled */
-+#define ANOMALY_05000357 (1)
-+/* Conflicting Column Address Widths Causes SDRAM Errors */
-+#define ANOMALY_05000362 (1)
-+/* 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)
- 
- /* Anomalies that don't exist on this proc */
- #define ANOMALY_05000158 (0)
-diff --git a/include/asm-blackfin/mach-bf561/bfin_serial_5xx.h b/include/asm-blackfin/mach-bf561/bfin_serial_5xx.h
-index 69b9f8e..7871d43 100644
---- a/include/asm-blackfin/mach-bf561/bfin_serial_5xx.h
-+++ b/include/asm-blackfin/mach-bf561/bfin_serial_5xx.h
-@@ -111,7 +111,7 @@ static void bfin_serial_hw_init(struct bfin_serial_port *uart)
- 	}
- 	if (uart->rts_pin >= 0) {
- 		gpio_request(uart->rts_pin, DRIVER_NAME);
--		gpio_direction_input(uart->rts_pin);
-+		gpio_direction_input(uart->rts_pin, 0);
- 	}
- #endif
- }
-diff --git a/include/asm-blackfin/mach-bf561/portmux.h b/include/asm-blackfin/mach-bf561/portmux.h
-index 132ad31..a6ee820 100644
---- a/include/asm-blackfin/mach-bf561/portmux.h
-+++ b/include/asm-blackfin/mach-bf561/portmux.h
-@@ -1,6 +1,8 @@
- #ifndef _MACH_PORTMUX_H_
- #define _MACH_PORTMUX_H_
- 
-+#define MAX_RESOURCES 	MAX_BLACKFIN_GPIOS
-+
- #define P_PPI0_CLK	(P_DONTCARE)
- #define P_PPI0_FS1	(P_DONTCARE)
- #define P_PPI0_FS2	(P_DONTCARE)
-diff --git a/include/asm-blackfin/mmu.h b/include/asm-blackfin/mmu.h
-index 11d52f1..757e439 100644
---- a/include/asm-blackfin/mmu.h
-+++ b/include/asm-blackfin/mmu.h
-@@ -24,7 +24,9 @@ typedef struct {
- 	unsigned long	exec_fdpic_loadmap;
- 	unsigned long	interp_fdpic_loadmap;
- #endif
+-#include <asm/types.h>
 -
-+#ifdef CONFIG_MPU
-+	unsigned long *page_rwx_mask;
-+#endif
- } mm_context_t;
- 
- #endif
-diff --git a/include/asm-blackfin/mmu_context.h b/include/asm-blackfin/mmu_context.h
-index c5c71a6..b5eb675 100644
---- a/include/asm-blackfin/mmu_context.h
-+++ b/include/asm-blackfin/mmu_context.h
-@@ -30,9 +30,12 @@
- #ifndef __BLACKFIN_MMU_CONTEXT_H__
- #define __BLACKFIN_MMU_CONTEXT_H__
- 
-+#include <linux/gfp.h>
-+#include <linux/sched.h>
- #include <asm/setup.h>
- #include <asm/page.h>
- #include <asm/pgalloc.h>
-+#include <asm/cplbinit.h>
- 
- extern void *current_l1_stack_save;
- extern int nr_l1stack_tasks;
-@@ -50,6 +53,12 @@ static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
- 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;
- }
- 
-@@ -73,6 +82,11 @@ static inline void destroy_context(struct mm_struct *mm)
- 		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
-@@ -106,9 +120,21 @@ activate_l1stack(struct mm_struct *mm, unsigned long sp_base)
- 
- #define deactivate_mm(tsk,mm)	do { } while (0)
- 
--static inline void activate_mm(struct mm_struct *prev_mm,
--			       struct mm_struct *next_mm)
-+#define activate_mm(prev, next) switch_mm(prev, next, NULL)
-+
-+static inline void switch_mm(struct mm_struct *prev_mm, struct mm_struct *next_mm,
-+			     struct task_struct *tsk)
- {
-+	if (prev_mm == next_mm)
-+		return;
-+#ifdef CONFIG_MPU
-+	if (prev_mm->context.page_rwx_mask == current_rwx_mask) {
-+		flush_switched_cplbs();
-+		set_mask_dcplbs(next_mm->context.page_rwx_mask);
-+	}
-+#endif
-+
-+	/* L1 stack switching.  */
- 	if (!next_mm->context.l1_stack_save)
- 		return;
- 	if (next_mm->context.l1_stack_save == current_l1_stack_save)
-@@ -120,10 +146,36 @@ static inline void activate_mm(struct mm_struct *prev_mm,
- 	memcpy(l1_stack_base, current_l1_stack_save, l1_stack_len);
- }
- 
--static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
--			     struct task_struct *tsk)
-+#ifdef CONFIG_MPU
-+static inline void protect_page(struct mm_struct *mm, unsigned long addr,
-+				unsigned long flags)
-+{
-+	unsigned long *mask = mm->context.page_rwx_mask;
-+	unsigned long page = addr >> 12;
-+	unsigned long idx = page >> 5;
-+	unsigned long bit = 1 << (page & 31);
-+
-+	if (flags & VM_MAYREAD)
-+		mask[idx] |= bit;
-+	else
-+		mask[idx] &= ~bit;
-+	mask += page_mask_nelts;
-+	if (flags & VM_MAYWRITE)
-+		mask[idx] |= bit;
-+	else
-+		mask[idx] &= ~bit;
-+	mask += page_mask_nelts;
-+	if (flags & VM_MAYEXEC)
-+		mask[idx] |= bit;
-+	else
-+		mask[idx] &= ~bit;
-+}
-+
-+static inline void update_protections(struct mm_struct *mm)
- {
--	activate_mm(prev, next);
-+	flush_switched_cplbs();
-+	set_mask_dcplbs(mm->context.page_rwx_mask);
- }
-+#endif
- 
- #endif
-diff --git a/include/asm-blackfin/traps.h b/include/asm-blackfin/traps.h
-index ee1cbf7..f0e5f94 100644
---- a/include/asm-blackfin/traps.h
-+++ b/include/asm-blackfin/traps.h
-@@ -45,6 +45,10 @@
- #define VEC_CPLB_I_M	(44)
- #define VEC_CPLB_I_MHIT	(45)
- #define VEC_ILL_RES	(46)	/* including unvalid supervisor mode insn */
-+/* The hardware reserves (63) for future use - we use it to tell our
-+ * normal exception handling code we have a hardware error
-+ */
-+#define VEC_HWERR	(63)
- 
- #ifndef __ASSEMBLY__
- 
-diff --git a/include/asm-blackfin/uaccess.h b/include/asm-blackfin/uaccess.h
-index 2233f8f..22a410b 100644
---- a/include/asm-blackfin/uaccess.h
-+++ b/include/asm-blackfin/uaccess.h
-@@ -31,7 +31,7 @@ static inline void set_fs(mm_segment_t fs)
- #define VERIFY_READ	0
- #define VERIFY_WRITE	1
- 
--#define access_ok(type,addr,size) _access_ok((unsigned long)(addr),(size))
-+#define access_ok(type, addr, size) _access_ok((unsigned long)(addr), (size))
- 
- static inline int is_in_rom(unsigned long addr)
- {
-diff --git a/include/asm-blackfin/unistd.h b/include/asm-blackfin/unistd.h
-index 07ffe8b..e981673 100644
---- a/include/asm-blackfin/unistd.h
-+++ b/include/asm-blackfin/unistd.h
-@@ -369,8 +369,9 @@
- #define __NR_set_robust_list	354
- #define __NR_get_robust_list	355
- #define __NR_fallocate		356
-+#define __NR_semtimedop		357
- 
--#define __NR_syscall		357
-+#define __NR_syscall		358
- #define NR_syscalls		__NR_syscall
- 
- /* Old optional stuff no one actually uses */
-diff --git a/include/asm-cris/arch-v10/ide.h b/include/asm-cris/arch-v10/ide.h
-index 78b301e..ea34e0d 100644
---- a/include/asm-cris/arch-v10/ide.h
-+++ b/include/asm-cris/arch-v10/ide.h
-@@ -89,11 +89,6 @@ static inline void ide_init_default_hwifs(void)
- 	}
- }
- 
--/* some configuration options we don't need */
+-struct scatterlist {
+-#ifdef CONFIG_DEBUG_SG
+-    unsigned long sg_magic;
+-#endif
+-    unsigned long page_link;
+-    unsigned int offset;/* for highmem, page offset */
+-    dma_addr_t dma_address;
+-    unsigned int length;
+-};
+-
+-/* These macros should be used after a pci_map_sg call has been done
+- * to get bus addresses of each of the SG entries and their lengths.
+- * You should only work with the number of sg entries pci_map_sg
+- * returns, or alternatively stop on the first sg_dma_len(sg) which
+- * is 0.
+- */
+-#define sg_dma_address(sg)	((sg)->dma_address)
+-#define sg_dma_len(sg)		((sg)->length)
+-
+-#define ISA_DMA_THRESHOLD (0xffffffff)
+-
+-#endif /* !__ASM_SH64_SCATTERLIST_H */
+diff --git a/include/asm-sh64/sci.h b/include/asm-sh64/sci.h
+deleted file mode 100644
+index 793c568..0000000
+--- a/include/asm-sh64/sci.h
++++ /dev/null
+@@ -1 +0,0 @@
+-#include <asm-sh/sci.h>
+diff --git a/include/asm-sh64/sections.h b/include/asm-sh64/sections.h
+deleted file mode 100644
+index 897f36b..0000000
+--- a/include/asm-sh64/sections.h
++++ /dev/null
+@@ -1,7 +0,0 @@
+-#ifndef __ASM_SH64_SECTIONS_H
+-#define __ASM_SH64_SECTIONS_H
+-
+-#include <asm-sh/sections.h>
+-
+-#endif /* __ASM_SH64_SECTIONS_H */
+-
+diff --git a/include/asm-sh64/segment.h b/include/asm-sh64/segment.h
+deleted file mode 100644
+index 92ac001..0000000
+--- a/include/asm-sh64/segment.h
++++ /dev/null
+@@ -1,6 +0,0 @@
+-#ifndef _ASM_SEGMENT_H
+-#define _ASM_SEGMENT_H
+-
+-/* Only here because we have some old header files that expect it.. */
+-
+-#endif /* _ASM_SEGMENT_H */
+diff --git a/include/asm-sh64/semaphore-helper.h b/include/asm-sh64/semaphore-helper.h
+deleted file mode 100644
+index fcfafe2..0000000
+--- a/include/asm-sh64/semaphore-helper.h
++++ /dev/null
+@@ -1,101 +0,0 @@
+-#ifndef __ASM_SH64_SEMAPHORE_HELPER_H
+-#define __ASM_SH64_SEMAPHORE_HELPER_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.
+- *
+- * include/asm-sh64/semaphore-helper.h
+- *
+- * Copyright (C) 2000, 2001  Paolo Alberelli
+- *
+- */
+-#include <asm/errno.h>
+-
+-/*
+- * SMP- and interrupt-safe semaphores helper functions.
+- *
+- * (C) Copyright 1996 Linus Torvalds
+- * (C) Copyright 1999 Andrea Arcangeli
+- */
+-
+-/*
+- * These two _must_ execute atomically wrt each other.
+- *
+- * This is trivially done with load_locked/store_cond,
+- * which we have.  Let the rest of the losers suck eggs.
+- */
+-static __inline__ void wake_one_more(struct semaphore * sem)
+-{
+-	atomic_inc((atomic_t *)&sem->sleepers);
+-}
+-
+-static __inline__ int waking_non_zero(struct semaphore *sem)
+-{
+-	unsigned long flags;
+-	int ret = 0;
+-
+-	spin_lock_irqsave(&semaphore_wake_lock, flags);
+-	if (sem->sleepers > 0) {
+-		sem->sleepers--;
+-		ret = 1;
+-	}
+-	spin_unlock_irqrestore(&semaphore_wake_lock, flags);
+-	return ret;
+-}
+-
+-/*
+- * waking_non_zero_interruptible:
+- *	1	got the lock
+- *	0	go to sleep
+- *	-EINTR	interrupted
+- *
+- * We must undo the sem->count down_interruptible() increment while we are
+- * protected by the spinlock in order to make atomic this atomic_inc() with the
+- * atomic_read() in wake_one_more(), otherwise we can race. -arca
+- */
+-static __inline__ int waking_non_zero_interruptible(struct semaphore *sem,
+-						struct task_struct *tsk)
+-{
+-	unsigned long flags;
+-	int ret = 0;
+-
+-	spin_lock_irqsave(&semaphore_wake_lock, flags);
+-	if (sem->sleepers > 0) {
+-		sem->sleepers--;
+-		ret = 1;
+-	} else if (signal_pending(tsk)) {
+-		atomic_inc(&sem->count);
+-		ret = -EINTR;
+-	}
+-	spin_unlock_irqrestore(&semaphore_wake_lock, flags);
+-	return ret;
+-}
+-
+-/*
+- * waking_non_zero_trylock:
+- *	1	failed to lock
+- *	0	got the lock
+- *
+- * We must undo the sem->count down_trylock() increment while we are
+- * protected by the spinlock in order to make atomic this atomic_inc() with the
+- * atomic_read() in wake_one_more(), otherwise we can race. -arca
+- */
+-static __inline__ int waking_non_zero_trylock(struct semaphore *sem)
+-{
+-	unsigned long flags;
+-	int ret = 1;
+-
+-	spin_lock_irqsave(&semaphore_wake_lock, flags);
+-	if (sem->sleepers <= 0)
+-		atomic_inc(&sem->count);
+-	else {
+-		sem->sleepers--;
+-		ret = 0;
+-	}
+-	spin_unlock_irqrestore(&semaphore_wake_lock, flags);
+-	return ret;
+-}
+-
+-#endif /* __ASM_SH64_SEMAPHORE_HELPER_H */
+diff --git a/include/asm-sh64/semaphore.h b/include/asm-sh64/semaphore.h
+deleted file mode 100644
+index f027cc1..0000000
+--- a/include/asm-sh64/semaphore.h
++++ /dev/null
+@@ -1,119 +0,0 @@
+-#ifndef __ASM_SH64_SEMAPHORE_H
+-#define __ASM_SH64_SEMAPHORE_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.
+- *
+- * include/asm-sh64/semaphore.h
+- *
+- * Copyright (C) 2000, 2001  Paolo Alberelli
+- *
+- * SMP- and interrupt-safe semaphores.
+- *
+- * (C) Copyright 1996 Linus Torvalds
+- *
+- * SuperH verison by Niibe Yutaka
+- *  (Currently no asm implementation but generic C code...)
+- *
+- */
+-
+-#include <linux/linkage.h>
+-#include <linux/spinlock.h>
+-#include <linux/wait.h>
+-#include <linux/rwsem.h>
+-
+-#include <asm/system.h>
+-#include <asm/atomic.h>
+-
+-struct semaphore {
+-	atomic_t count;
+-	int sleepers;
+-	wait_queue_head_t wait;
+-};
+-
+-#define __SEMAPHORE_INITIALIZER(name, n)				\
+-{									\
+-	.count		= ATOMIC_INIT(n),				\
+-	.sleepers	= 0,						\
+-	.wait		= __WAIT_QUEUE_HEAD_INITIALIZER((name).wait)	\
+-}
+-
+-#define __DECLARE_SEMAPHORE_GENERIC(name,count) \
+-	struct semaphore name = __SEMAPHORE_INITIALIZER(name,count)
+-
+-#define DECLARE_MUTEX(name) __DECLARE_SEMAPHORE_GENERIC(name,1)
+-
+-static inline void sema_init (struct semaphore *sem, int val)
+-{
+-/*
+- *	*sem = (struct semaphore)__SEMAPHORE_INITIALIZER((*sem),val);
+- *
+- * i'd rather use the more flexible initialization above, but sadly
+- * GCC 2.7.2.3 emits a bogus warning. EGCS doesnt. Oh well.
+- */
+-	atomic_set(&sem->count, val);
+-	sem->sleepers = 0;
+-	init_waitqueue_head(&sem->wait);
+-}
+-
+-static inline void init_MUTEX (struct semaphore *sem)
+-{
+-	sema_init(sem, 1);
+-}
+-
+-static inline void init_MUTEX_LOCKED (struct semaphore *sem)
+-{
+-	sema_init(sem, 0);
+-}
+-
+-#if 0
+-asmlinkage void __down_failed(void /* special register calling convention */);
+-asmlinkage int  __down_failed_interruptible(void  /* params in registers */);
+-asmlinkage int  __down_failed_trylock(void  /* params in registers */);
+-asmlinkage void __up_wakeup(void /* special register calling convention */);
+-#endif
+-
+-asmlinkage void __down(struct semaphore * sem);
+-asmlinkage int  __down_interruptible(struct semaphore * sem);
+-asmlinkage int  __down_trylock(struct semaphore * sem);
+-asmlinkage void __up(struct semaphore * sem);
+-
+-extern spinlock_t semaphore_wake_lock;
+-
+-static inline void down(struct semaphore * sem)
+-{
+-	if (atomic_dec_return(&sem->count) < 0)
+-		__down(sem);
+-}
+-
+-static inline int down_interruptible(struct semaphore * sem)
+-{
+-	int ret = 0;
+-
+-	if (atomic_dec_return(&sem->count) < 0)
+-		ret = __down_interruptible(sem);
+-	return ret;
+-}
+-
+-static inline int down_trylock(struct semaphore * sem)
+-{
+-	int ret = 0;
+-
+-	if (atomic_dec_return(&sem->count) < 0)
+-		ret = __down_trylock(sem);
+-	return ret;
+-}
+-
+-/*
+- * Note! This is subtle. We jump to wake people up only if
+- * the semaphore was negative (== somebody was waiting on it).
+- */
+-static inline void up(struct semaphore * sem)
+-{
+-	if (atomic_inc_return(&sem->count) <= 0)
+-		__up(sem);
+-}
+-
+-#endif /* __ASM_SH64_SEMAPHORE_H */
+diff --git a/include/asm-sh64/sembuf.h b/include/asm-sh64/sembuf.h
+deleted file mode 100644
+index ec4d9f1..0000000
+--- a/include/asm-sh64/sembuf.h
++++ /dev/null
+@@ -1,36 +0,0 @@
+-#ifndef __ASM_SH64_SEMBUF_H
+-#define __ASM_SH64_SEMBUF_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.
+- *
+- * include/asm-sh64/sembuf.h
+- *
+- * Copyright (C) 2000, 2001  Paolo Alberelli
+- *
+- */
+-
+-/*
+- * The semid64_ds structure for i386 architecture.
+- * Note extra padding because this structure is passed back and forth
+- * between kernel and user space.
+- *
+- * Pad space is left for:
+- * - 64-bit time_t to solve y2038 problem
+- * - 2 miscellaneous 32-bit values
+- */
+-
+-struct semid64_ds {
+-	struct ipc64_perm sem_perm;		/* permissions .. see ipc.h */
+-	__kernel_time_t	sem_otime;		/* last semop time */
+-	unsigned long	__unused1;
+-	__kernel_time_t	sem_ctime;		/* last change time */
+-	unsigned long	__unused2;
+-	unsigned long	sem_nsems;		/* no. of semaphores in array */
+-	unsigned long	__unused3;
+-	unsigned long	__unused4;
+-};
+-
+-#endif /* __ASM_SH64_SEMBUF_H */
+diff --git a/include/asm-sh64/serial.h b/include/asm-sh64/serial.h
+deleted file mode 100644
+index e8d7b3f..0000000
+--- a/include/asm-sh64/serial.h
++++ /dev/null
+@@ -1,31 +0,0 @@
+-/*
+- * include/asm-sh64/serial.h
+- *
+- * Configuration details for 8250, 16450, 16550, etc. serial ports
+- */
+-
+-#ifndef _ASM_SERIAL_H
+-#define _ASM_SERIAL_H
+-
+-/*
+- * This assumes you have a 1.8432 MHz clock for your UART.
+- *
+- * It'd be nice if someone built a serial card with a 24.576 MHz
+- * clock, since the 16550A is capable of handling a top speed of 1.5
+- * megabits/second; but this requires the faster clock.
+- */
+-#define BASE_BAUD ( 1843200 / 16 )
+-
+-#define RS_TABLE_SIZE  2
+-
+-#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
+-
+-#define SERIAL_PORT_DFNS			\
+-	/* UART CLK   PORT IRQ     FLAGS        */			\
+-	{ 0, BASE_BAUD, 0x3F8, 4, STD_COM_FLAGS },	/* ttyS0 */	\
+-	{ 0, BASE_BAUD, 0x2F8, 3, STD_COM_FLAGS }	/* ttyS1 */
+-
+-/* XXX: This should be moved ino irq.h */
+-#define irq_cannonicalize(x) (x)
+-
+-#endif /* _ASM_SERIAL_H */
+diff --git a/include/asm-sh64/setup.h b/include/asm-sh64/setup.h
+deleted file mode 100644
+index 5b07b14..0000000
+--- a/include/asm-sh64/setup.h
++++ /dev/null
+@@ -1,22 +0,0 @@
+-#ifndef __ASM_SH64_SETUP_H
+-#define __ASM_SH64_SETUP_H
+-
+-#define COMMAND_LINE_SIZE 256
+-
+-#ifdef __KERNEL__
+-
+-#define PARAM ((unsigned char *)empty_zero_page)
+-#define MOUNT_ROOT_RDONLY (*(unsigned long *) (PARAM+0x000))
+-#define RAMDISK_FLAGS (*(unsigned long *) (PARAM+0x004))
+-#define ORIG_ROOT_DEV (*(unsigned long *) (PARAM+0x008))
+-#define LOADER_TYPE (*(unsigned long *) (PARAM+0x00c))
+-#define INITRD_START (*(unsigned long *) (PARAM+0x010))
+-#define INITRD_SIZE (*(unsigned long *) (PARAM+0x014))
+-
+-#define COMMAND_LINE ((char *) (PARAM+256))
+-#define COMMAND_LINE_SIZE 256
+-
+-#endif  /*  __KERNEL__  */
+-
+-#endif /* __ASM_SH64_SETUP_H */
+-
+diff --git a/include/asm-sh64/shmbuf.h b/include/asm-sh64/shmbuf.h
+deleted file mode 100644
+index 022f349..0000000
+--- a/include/asm-sh64/shmbuf.h
++++ /dev/null
+@@ -1,53 +0,0 @@
+-#ifndef __ASM_SH64_SHMBUF_H
+-#define __ASM_SH64_SHMBUF_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.
+- *
+- * include/asm-sh64/shmbuf.h
+- *
+- * Copyright (C) 2000, 2001  Paolo Alberelli
+- *
+- */
+-
+-/*
+- * The shmid64_ds structure for i386 architecture.
+- * Note extra padding because this structure is passed back and forth
+- * between kernel and user space.
+- *
+- * Pad space is left for:
+- * - 64-bit time_t to solve y2038 problem
+- * - 2 miscellaneous 32-bit values
+- */
+-
+-struct shmid64_ds {
+-	struct ipc64_perm	shm_perm;	/* operation perms */
+-	size_t			shm_segsz;	/* size of segment (bytes) */
+-	__kernel_time_t		shm_atime;	/* last attach time */
+-	unsigned long		__unused1;
+-	__kernel_time_t		shm_dtime;	/* last detach time */
+-	unsigned long		__unused2;
+-	__kernel_time_t		shm_ctime;	/* last change time */
+-	unsigned long		__unused3;
+-	__kernel_pid_t		shm_cpid;	/* pid of creator */
+-	__kernel_pid_t		shm_lpid;	/* pid of last operator */
+-	unsigned long		shm_nattch;	/* no. of current attaches */
+-	unsigned long		__unused4;
+-	unsigned long		__unused5;
+-};
+-
+-struct shminfo64 {
+-	unsigned long	shmmax;
+-	unsigned long	shmmin;
+-	unsigned long	shmmni;
+-	unsigned long	shmseg;
+-	unsigned long	shmall;
+-	unsigned long	__unused1;
+-	unsigned long	__unused2;
+-	unsigned long	__unused3;
+-	unsigned long	__unused4;
+-};
+-
+-#endif /* __ASM_SH64_SHMBUF_H */
+diff --git a/include/asm-sh64/shmparam.h b/include/asm-sh64/shmparam.h
+deleted file mode 100644
+index 1bb820c..0000000
+--- a/include/asm-sh64/shmparam.h
++++ /dev/null
+@@ -1,12 +0,0 @@
+-#ifndef __ASM_SH64_SHMPARAM_H
+-#define __ASM_SH64_SHMPARAM_H
+-
+-/*
+- * Set this to a sensible safe default, we'll work out the specifics for the
+- * align mask from the cache descriptor at run-time.
+- */
+-#define	SHMLBA	0x4000
+-
+-#define __ARCH_FORCE_SHMLBA
+-
+-#endif /* __ASM_SH64_SHMPARAM_H */
+diff --git a/include/asm-sh64/sigcontext.h b/include/asm-sh64/sigcontext.h
+deleted file mode 100644
+index 6293509..0000000
+--- a/include/asm-sh64/sigcontext.h
++++ /dev/null
+@@ -1,30 +0,0 @@
+-#ifndef __ASM_SH64_SIGCONTEXT_H
+-#define __ASM_SH64_SIGCONTEXT_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.
+- *
+- * include/asm-sh64/sigcontext.h
+- *
+- * Copyright (C) 2000, 2001  Paolo Alberelli
+- *
+- */
+-
+-struct sigcontext {
+-	unsigned long	oldmask;
+-
+-	/* CPU registers */
+-	unsigned long long sc_regs[63];
+-	unsigned long long sc_tregs[8];
+-	unsigned long long sc_pc;
+-	unsigned long long sc_sr;
+-
+-	/* FPU registers */
+-	unsigned long long sc_fpregs[32];
+-	unsigned int sc_fpscr;
+-	unsigned int sc_fpvalid;
+-};
+-
+-#endif /* __ASM_SH64_SIGCONTEXT_H */
+diff --git a/include/asm-sh64/siginfo.h b/include/asm-sh64/siginfo.h
+deleted file mode 100644
+index 56ef1da..0000000
+--- a/include/asm-sh64/siginfo.h
++++ /dev/null
+@@ -1,6 +0,0 @@
+-#ifndef __ASM_SH64_SIGINFO_H
+-#define __ASM_SH64_SIGINFO_H
+-
+-#include <asm-generic/siginfo.h>
+-
+-#endif /* __ASM_SH64_SIGINFO_H */
+diff --git a/include/asm-sh64/signal.h b/include/asm-sh64/signal.h
+deleted file mode 100644
+index 244e134..0000000
+--- a/include/asm-sh64/signal.h
++++ /dev/null
+@@ -1,159 +0,0 @@
+-#ifndef __ASM_SH64_SIGNAL_H
+-#define __ASM_SH64_SIGNAL_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.
+- *
+- * include/asm-sh64/signal.h
+- *
+- * Copyright (C) 2000, 2001  Paolo Alberelli
+- *
+- */
+-
+-#include <linux/types.h>
+-
+-/* Avoid too many header ordering problems.  */
+-struct siginfo;
+-
+-#define _NSIG		64
+-#define _NSIG_BPW	32
+-#define _NSIG_WORDS	(_NSIG / _NSIG_BPW)
+-
+-typedef unsigned long old_sigset_t;		/* at least 32 bits */
+-
+-typedef struct {
+-	unsigned long sig[_NSIG_WORDS];
+-} sigset_t;
+-
+-#define SIGHUP		 1
+-#define SIGINT		 2
+-#define SIGQUIT		 3
+-#define SIGILL		 4
+-#define SIGTRAP		 5
+-#define SIGABRT		 6
+-#define SIGIOT		 6
+-#define SIGBUS		 7
+-#define SIGFPE		 8
+-#define SIGKILL		 9
+-#define SIGUSR1		10
+-#define SIGSEGV		11
+-#define SIGUSR2		12
+-#define SIGPIPE		13
+-#define SIGALRM		14
+-#define SIGTERM		15
+-#define SIGSTKFLT	16
+-#define SIGCHLD		17
+-#define SIGCONT		18
+-#define SIGSTOP		19
+-#define SIGTSTP		20
+-#define SIGTTIN		21
+-#define SIGTTOU		22
+-#define SIGURG		23
+-#define SIGXCPU		24
+-#define SIGXFSZ		25
+-#define SIGVTALRM	26
+-#define SIGPROF		27
+-#define SIGWINCH	28
+-#define SIGIO		29
+-#define SIGPOLL		SIGIO
+-/*
+-#define SIGLOST		29
+-*/
+-#define SIGPWR		30
+-#define SIGSYS		31
+-#define	SIGUNUSED	31
+-
+-/* These should not be considered constants from userland.  */
+-#define SIGRTMIN	32
+-#define SIGRTMAX	(_NSIG-1)
+-
+-/*
+- * SA_FLAGS values:
+- *
+- * SA_ONSTACK indicates that a registered stack_t will be used.
+- * SA_RESTART flag to get restarting signals (which were the default long ago)
+- * SA_NOCLDSTOP flag to turn off SIGCHLD when children stop.
+- * SA_RESETHAND clears the handler when the signal is delivered.
+- * SA_NOCLDWAIT flag on SIGCHLD to inhibit zombies.
+- * SA_NODEFER prevents the current signal from being masked in the handler.
+- *
+- * SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single
+- * Unix names RESETHAND and NODEFER respectively.
+- */
+-#define SA_NOCLDSTOP	0x00000001
+-#define SA_NOCLDWAIT	0x00000002 /* not supported yet */
+-#define SA_SIGINFO	0x00000004
+-#define SA_ONSTACK	0x08000000
+-#define SA_RESTART	0x10000000
+-#define SA_NODEFER	0x40000000
+-#define SA_RESETHAND	0x80000000
+-
+-#define SA_NOMASK	SA_NODEFER
+-#define SA_ONESHOT	SA_RESETHAND
+-
+-#define SA_RESTORER	0x04000000
+-
+-/*
+- * sigaltstack controls
+- */
+-#define SS_ONSTACK	1
+-#define SS_DISABLE	2
+-
+-#define MINSIGSTKSZ	2048
+-#define SIGSTKSZ	THREAD_SIZE
+-
+-#include <asm-generic/signal.h>
+-
+-#ifdef __KERNEL__
+-struct old_sigaction {
+-	__sighandler_t sa_handler;
+-	old_sigset_t sa_mask;
+-	unsigned long sa_flags;
+-	void (*sa_restorer)(void);
+-};
+-
+-struct sigaction {
+-	__sighandler_t sa_handler;
+-	unsigned long sa_flags;
+-	void (*sa_restorer)(void);
+-	sigset_t sa_mask;		/* mask last for extensibility */
+-};
+-
+-struct k_sigaction {
+-	struct sigaction sa;
+-};
+-#else
+-/* Here we must cater to libcs that poke about in kernel headers.  */
+-
+-struct sigaction {
+-	union {
+-	  __sighandler_t _sa_handler;
+-	  void (*_sa_sigaction)(int, struct siginfo *, void *);
+-	} _u;
+-	sigset_t sa_mask;
+-	unsigned long sa_flags;
+-	void (*sa_restorer)(void);
+-};
+-
+-#define sa_handler	_u._sa_handler
+-#define sa_sigaction	_u._sa_sigaction
+-
+-#endif /* __KERNEL__ */
+-
+-typedef struct sigaltstack {
+-	void *ss_sp;
+-	int ss_flags;
+-	size_t ss_size;
+-} stack_t;
+-
+-#ifdef __KERNEL__
+-#include <asm/sigcontext.h>
+-
+-#define sigmask(sig)	(1UL << ((sig) - 1))
+-#define ptrace_signal_deliver(regs, cookie) do { } while (0)
+-
+-#endif /* __KERNEL__ */
+-
+-#endif /* __ASM_SH64_SIGNAL_H */
+diff --git a/include/asm-sh64/smp.h b/include/asm-sh64/smp.h
+deleted file mode 100644
+index 4a4d0da..0000000
+--- a/include/asm-sh64/smp.h
++++ /dev/null
+@@ -1,15 +0,0 @@
+-#ifndef __ASM_SH64_SMP_H
+-#define __ASM_SH64_SMP_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.
+- *
+- * include/asm-sh64/smp.h
+- *
+- * Copyright (C) 2000, 2001  Paolo Alberelli
+- *
+- */
+-
+-#endif /* __ASM_SH64_SMP_H */
+diff --git a/include/asm-sh64/socket.h b/include/asm-sh64/socket.h
+deleted file mode 100644
+index 1853f72..0000000
+--- a/include/asm-sh64/socket.h
++++ /dev/null
+@@ -1,6 +0,0 @@
+-#ifndef __ASM_SH64_SOCKET_H
+-#define __ASM_SH64_SOCKET_H
+-
+-#include <asm-sh/socket.h>
+-
+-#endif /* __ASM_SH64_SOCKET_H */
+diff --git a/include/asm-sh64/sockios.h b/include/asm-sh64/sockios.h
+deleted file mode 100644
+index 419e76f..0000000
+--- a/include/asm-sh64/sockios.h
++++ /dev/null
+@@ -1,25 +0,0 @@
+-#ifndef __ASM_SH64_SOCKIOS_H
+-#define __ASM_SH64_SOCKIOS_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.
+- *
+- * include/asm-sh64/sockios.h
+- *
+- * Copyright (C) 2000, 2001  Paolo Alberelli
+- *
+- */
+-
+-/* Socket-level I/O control calls. */
+-#define FIOGETOWN	_IOR('f', 123, int)
+-#define FIOSETOWN 	_IOW('f', 124, int)
+-
+-#define SIOCATMARK	_IOR('s', 7, int)
+-#define SIOCSPGRP	_IOW('s', 8, pid_t)
+-#define SIOCGPGRP	_IOR('s', 9, pid_t)
+-
+-#define SIOCGSTAMP	_IOR('s', 100, struct timeval) /* Get stamp (timeval) */
+-#define SIOCGSTAMPNS	_IOR('s', 101, struct timespec) /* Get stamp (timespec) */
+-#endif /* __ASM_SH64_SOCKIOS_H */
+diff --git a/include/asm-sh64/spinlock.h b/include/asm-sh64/spinlock.h
+deleted file mode 100644
+index 296b0c9..0000000
+--- a/include/asm-sh64/spinlock.h
++++ /dev/null
+@@ -1,17 +0,0 @@
+-#ifndef __ASM_SH64_SPINLOCK_H
+-#define __ASM_SH64_SPINLOCK_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.
+- *
+- * include/asm-sh64/spinlock.h
+- *
+- * Copyright (C) 2000, 2001  Paolo Alberelli
+- *
+- */
+-
+-#error "No SMP on SH64"
+-
+-#endif /* __ASM_SH64_SPINLOCK_H */
+diff --git a/include/asm-sh64/stat.h b/include/asm-sh64/stat.h
+deleted file mode 100644
+index 86f551b..0000000
+--- a/include/asm-sh64/stat.h
++++ /dev/null
+@@ -1,88 +0,0 @@
+-#ifndef __ASM_SH64_STAT_H
+-#define __ASM_SH64_STAT_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.
+- *
+- * include/asm-sh64/stat.h
+- *
+- * Copyright (C) 2000, 2001  Paolo Alberelli
+- *
+- */
+-
+-struct __old_kernel_stat {
+-	unsigned short st_dev;
+-	unsigned short st_ino;
+-	unsigned short st_mode;
+-	unsigned short st_nlink;
+-	unsigned short st_uid;
+-	unsigned short st_gid;
+-	unsigned short st_rdev;
+-	unsigned long  st_size;
+-	unsigned long  st_atime;
+-	unsigned long  st_mtime;
+-	unsigned long  st_ctime;
+-};
+-
+-struct stat {
+-	unsigned short st_dev;
+-	unsigned short __pad1;
+-	unsigned long st_ino;
+-	unsigned short st_mode;
+-	unsigned short st_nlink;
+-	unsigned short st_uid;
+-	unsigned short st_gid;
+-	unsigned short st_rdev;
+-	unsigned short __pad2;
+-	unsigned long  st_size;
+-	unsigned long  st_blksize;
+-	unsigned long  st_blocks;
+-	unsigned long  st_atime;
+-	unsigned long  st_atime_nsec;
+-	unsigned long  st_mtime;
+-	unsigned long  st_mtime_nsec;
+-	unsigned long  st_ctime;
+-	unsigned long  st_ctime_nsec;
+-	unsigned long  __unused4;
+-	unsigned long  __unused5;
+-};
+-
+-/* This matches struct stat64 in glibc2.1, hence the absolutely
+- * insane amounts of padding around dev_t's.
+- */
+-struct stat64 {
+-	unsigned short	st_dev;
+-	unsigned char	__pad0[10];
+-
+-	unsigned long	st_ino;
+-	unsigned int	st_mode;
+-	unsigned int	st_nlink;
+-
+-	unsigned long	st_uid;
+-	unsigned long	st_gid;
+-
+-	unsigned short	st_rdev;
+-	unsigned char	__pad3[10];
+-
+-	long long	st_size;
+-	unsigned long	st_blksize;
+-
+-	unsigned long	st_blocks;	/* Number 512-byte blocks allocated. */
+-	unsigned long	__pad4;		/* future possible st_blocks high bits */
+-
+-	unsigned long	st_atime;
+-	unsigned long	st_atime_nsec;
+-
+-	unsigned long	st_mtime;
+-	unsigned long	st_mtime_nsec;
+-
+-	unsigned long	st_ctime;
+-	unsigned long	st_ctime_nsec;	/* will be high 32 bits of ctime someday */
+-
+-	unsigned long	__unused1;
+-	unsigned long	__unused2;
+-};
+-
+-#endif /* __ASM_SH64_STAT_H */
+diff --git a/include/asm-sh64/statfs.h b/include/asm-sh64/statfs.h
+deleted file mode 100644
+index 083fd79..0000000
+--- a/include/asm-sh64/statfs.h
++++ /dev/null
+@@ -1,6 +0,0 @@
+-#ifndef __ASM_SH64_STATFS_H
+-#define __ASM_SH64_STATFS_H
+-
+-#include <asm-generic/statfs.h>
+-
+-#endif /* __ASM_SH64_STATFS_H */
+diff --git a/include/asm-sh64/string.h b/include/asm-sh64/string.h
+deleted file mode 100644
+index 8a73573..0000000
+--- a/include/asm-sh64/string.h
++++ /dev/null
+@@ -1,21 +0,0 @@
+-#ifndef __ASM_SH64_STRING_H
+-#define __ASM_SH64_STRING_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.
+- *
+- * include/asm-sh64/string.h
+- *
+- * Copyright (C) 2000, 2001  Paolo Alberelli
+- *
+- * Empty on purpose. ARCH SH64 ASM libs are out of the current project scope.
+- *
+- */
+-
+-#define __HAVE_ARCH_MEMCPY
+-
+-extern void *memcpy(void *dest, const void *src, size_t count);
+-
+-#endif
+diff --git a/include/asm-sh64/system.h b/include/asm-sh64/system.h
+deleted file mode 100644
+index be2a15f..0000000
+--- a/include/asm-sh64/system.h
++++ /dev/null
+@@ -1,190 +0,0 @@
+-#ifndef __ASM_SH64_SYSTEM_H
+-#define __ASM_SH64_SYSTEM_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.
+- *
+- * include/asm-sh64/system.h
+- *
+- * Copyright (C) 2000, 2001  Paolo Alberelli
+- * Copyright (C) 2003  Paul Mundt
+- * Copyright (C) 2004  Richard Curnow
+- *
+- */
+-
+-#include <asm/registers.h>
+-#include <asm/processor.h>
+-
+-/*
+- *	switch_to() should switch tasks to task nr n, first
+- */
+-
+-typedef struct {
+-	unsigned long seg;
+-} mm_segment_t;
+-
+-extern struct task_struct *sh64_switch_to(struct task_struct *prev,
+-					  struct thread_struct *prev_thread,
+-					  struct task_struct *next,
+-					  struct thread_struct *next_thread);
+-
+-#define switch_to(prev,next,last) \
+-	do {\
+-		if (last_task_used_math != next) {\
+-			struct pt_regs *regs = next->thread.uregs;\
+-			if (regs) regs->sr |= SR_FD;\
+-		}\
+-		last = sh64_switch_to(prev, &prev->thread, next, &next->thread);\
+-	} while(0)
+-
+-#define nop() __asm__ __volatile__ ("nop")
+-
+-#define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
+-
+-extern void __xchg_called_with_bad_pointer(void);
+-
+-#define mb()	__asm__ __volatile__ ("synco": : :"memory")
+-#define rmb()	mb()
+-#define wmb()	__asm__ __volatile__ ("synco": : :"memory")
+-#define read_barrier_depends()	do { } while (0)
+-
+-#ifdef CONFIG_SMP
+-#define smp_mb()	mb()
+-#define smp_rmb()	rmb()
+-#define smp_wmb()	wmb()
+-#define smp_read_barrier_depends()	read_barrier_depends()
+-#else
+-#define smp_mb()	barrier()
+-#define smp_rmb()	barrier()
+-#define smp_wmb()	barrier()
+-#define smp_read_barrier_depends()	do { } while (0)
+-#endif /* CONFIG_SMP */
+-
+-#define set_mb(var, value) do { (void)xchg(&var, value); } while (0)
+-
+-/* Interrupt Control */
+-#ifndef HARD_CLI
+-#define SR_MASK_L 0x000000f0L
+-#define SR_MASK_LL 0x00000000000000f0LL
+-#else
+-#define SR_MASK_L 0x10000000L
+-#define SR_MASK_LL 0x0000000010000000LL
+-#endif
+-
+-static __inline__ void local_irq_enable(void)
+-{
+-	/* cli/sti based on SR.BL */
+-	unsigned long long __dummy0, __dummy1=~SR_MASK_LL;
+-
+-	__asm__ __volatile__("getcon	" __SR ", %0\n\t"
+-			     "and	%0, %1, %0\n\t"
+-			     "putcon	%0, " __SR "\n\t"
+-			     : "=&r" (__dummy0)
+-			     : "r" (__dummy1));
+-}
+-
+-static __inline__ void local_irq_disable(void)
+-{
+-	/* cli/sti based on SR.BL */
+-	unsigned long long __dummy0, __dummy1=SR_MASK_LL;
+-	__asm__ __volatile__("getcon	" __SR ", %0\n\t"
+-			     "or	%0, %1, %0\n\t"
+-			     "putcon	%0, " __SR "\n\t"
+-			     : "=&r" (__dummy0)
+-			     : "r" (__dummy1));
+-}
+-
+-#define local_save_flags(x) 						\
+-(__extension__ ({	unsigned long long __dummy=SR_MASK_LL;		\
+-	__asm__ __volatile__(						\
+-		"getcon	" __SR ", %0\n\t"				\
+-		"and	%0, %1, %0"					\
+-		: "=&r" (x)						\
+-		: "r" (__dummy));}))
+-
+-#define local_irq_save(x)						\
+-(__extension__ ({	unsigned long long __d2=SR_MASK_LL, __d1;	\
+-	__asm__ __volatile__(          	         			\
+-		"getcon	" __SR ", %1\n\t" 				\
+-		"or	%1, r63, %0\n\t"				\
+-		"or	%1, %2, %1\n\t"					\
+-		"putcon	%1, " __SR "\n\t"    				\
+-		"and	%0, %2, %0"    					\
+-		: "=&r" (x), "=&r" (__d1)				\
+-		: "r" (__d2));}));
+-
+-#define local_irq_restore(x) do { 					\
+-	if ( ((x) & SR_MASK_L) == 0 )		/* dropping to 0 ? */	\
+-		local_irq_enable();		/* yes...re-enable */	\
+-} while (0)
+-
+-#define irqs_disabled()			\
+-({					\
+-	unsigned long flags;		\
+-	local_save_flags(flags);	\
+-	(flags != 0);			\
+-})
+-
+-static inline unsigned long xchg_u32(volatile int * m, unsigned long val)
+-{
+-	unsigned long flags, retval;
+-
+-	local_irq_save(flags);
+-	retval = *m;
+-	*m = val;
+-	local_irq_restore(flags);
+-	return retval;
+-}
+-
+-static inline unsigned long xchg_u8(volatile unsigned char * m, unsigned long val)
+-{
+-	unsigned long flags, retval;
+-
+-	local_irq_save(flags);
+-	retval = *m;
+-	*m = val & 0xff;
+-	local_irq_restore(flags);
+-	return retval;
+-}
+-
+-static __inline__ unsigned long __xchg(unsigned long x, volatile void * ptr, int size)
+-{
+-	switch (size) {
+-	case 4:
+-		return xchg_u32(ptr, x);
+-		break;
+-	case 1:
+-		return xchg_u8(ptr, x);
+-		break;
+-	}
+-	__xchg_called_with_bad_pointer();
+-	return x;
+-}
+-
+-/* XXX
+- * disable hlt during certain critical i/o operations
+- */
+-#define HAVE_DISABLE_HLT
+-void disable_hlt(void);
+-void enable_hlt(void);
+-
+-
+-#define smp_mb()        barrier()
+-#define smp_rmb()       barrier()
+-#define smp_wmb()       barrier()
+-
+-#ifdef CONFIG_SH_ALPHANUMERIC
+-/* This is only used for debugging. */
+-extern void print_seg(char *file,int line);
+-#define PLS() print_seg(__FILE__,__LINE__)
+-#else	/* CONFIG_SH_ALPHANUMERIC */
+-#define PLS()
+-#endif	/* CONFIG_SH_ALPHANUMERIC */
+-
+-#define PL() printk("@ <%s,%s:%d>\n",__FILE__,__FUNCTION__,__LINE__)
+-
+-#define arch_align_stack(x) (x)
+-
+-#endif /* __ASM_SH64_SYSTEM_H */
+diff --git a/include/asm-sh64/termbits.h b/include/asm-sh64/termbits.h
+deleted file mode 100644
+index 86bde5e..0000000
+--- a/include/asm-sh64/termbits.h
++++ /dev/null
+@@ -1,6 +0,0 @@
+-#ifndef __ASM_SH64_TERMBITS_H
+-#define __ASM_SH64_TERMBITS_H
+-
+-#include <asm-sh/termbits.h>
+-
+-#endif /* __ASM_SH64_TERMBITS_H */
+diff --git a/include/asm-sh64/termios.h b/include/asm-sh64/termios.h
+deleted file mode 100644
+index dc44e6e..0000000
+--- a/include/asm-sh64/termios.h
++++ /dev/null
+@@ -1,99 +0,0 @@
+-#ifndef __ASM_SH64_TERMIOS_H
+-#define __ASM_SH64_TERMIOS_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.
+- *
+- * include/asm-sh64/termios.h
+- *
+- * Copyright (C) 2000, 2001  Paolo Alberelli
+- *
+- */
+-
+-#include <asm/termbits.h>
+-#include <asm/ioctls.h>
+-
+-struct winsize {
+-	unsigned short ws_row;
+-	unsigned short ws_col;
+-	unsigned short ws_xpixel;
+-	unsigned short ws_ypixel;
+-};
+-
+-#define NCC 8
+-struct termio {
+-	unsigned short c_iflag;		/* input mode flags */
+-	unsigned short c_oflag;		/* output mode flags */
+-	unsigned short c_cflag;		/* control mode flags */
+-	unsigned short c_lflag;		/* local mode flags */
+-	unsigned char c_line;		/* line discipline */
+-	unsigned char c_cc[NCC];	/* control characters */
+-};
+-
+-/* modem lines */
+-#define TIOCM_LE	0x001
+-#define TIOCM_DTR	0x002
+-#define TIOCM_RTS	0x004
+-#define TIOCM_ST	0x008
+-#define TIOCM_SR	0x010
+-#define TIOCM_CTS	0x020
+-#define TIOCM_CAR	0x040
+-#define TIOCM_RNG	0x080
+-#define TIOCM_DSR	0x100
+-#define TIOCM_CD	TIOCM_CAR
+-#define TIOCM_RI	TIOCM_RNG
+-#define TIOCM_OUT1	0x2000
+-#define TIOCM_OUT2	0x4000
+-#define TIOCM_LOOP	0x8000
+-
+-/* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */
+-
+-#ifdef __KERNEL__
+-
+-/*	intr=^C		quit=^\		erase=del	kill=^U
+-	eof=^D		vtime=\0	vmin=\1		sxtc=\0
+-	start=^Q	stop=^S		susp=^Z		eol=\0
+-	reprint=^R	discard=^U	werase=^W	lnext=^V
+-	eol2=\0
+-*/
+-#define INIT_C_CC "\003\034\177\025\004\0\1\0\021\023\032\0\022\017\027\026\0"
+-
+-/*
+- * Translate a "termio" structure into a "termios". Ugh.
+- */
+-#define SET_LOW_TERMIOS_BITS(termios, termio, x) { \
+-	unsigned short __tmp; \
+-	get_user(__tmp,&(termio)->x); \
+-	*(unsigned short *) &(termios)->x = __tmp; \
+-}
+-
+-#define user_termio_to_kernel_termios(termios, termio) \
+-({ \
+-	SET_LOW_TERMIOS_BITS(termios, termio, c_iflag); \
+-	SET_LOW_TERMIOS_BITS(termios, termio, c_oflag); \
+-	SET_LOW_TERMIOS_BITS(termios, termio, c_cflag); \
+-	SET_LOW_TERMIOS_BITS(termios, termio, c_lflag); \
+-	copy_from_user((termios)->c_cc, (termio)->c_cc, NCC); \
+-})
+-
+-/*
+- * Translate a "termios" structure into a "termio". Ugh.
+- */
+-#define kernel_termios_to_user_termio(termio, termios) \
+-({ \
+-	put_user((termios)->c_iflag, &(termio)->c_iflag); \
+-	put_user((termios)->c_oflag, &(termio)->c_oflag); \
+-	put_user((termios)->c_cflag, &(termio)->c_cflag); \
+-	put_user((termios)->c_lflag, &(termio)->c_lflag); \
+-	put_user((termios)->c_line,  &(termio)->c_line); \
+-	copy_to_user((termio)->c_cc, (termios)->c_cc, NCC); \
+-})
+-
+-#define user_termios_to_kernel_termios(k, u) copy_from_user(k, u, sizeof(struct termios))
+-#define kernel_termios_to_user_termios(u, k) copy_to_user(u, k, sizeof(struct termios))
+-
+-#endif	/* __KERNEL__ */
+-
+-#endif	/* __ASM_SH64_TERMIOS_H */
+diff --git a/include/asm-sh64/thread_info.h b/include/asm-sh64/thread_info.h
+deleted file mode 100644
+index f6d5117..0000000
+--- a/include/asm-sh64/thread_info.h
++++ /dev/null
+@@ -1,91 +0,0 @@
+-#ifndef __ASM_SH64_THREAD_INFO_H
+-#define __ASM_SH64_THREAD_INFO_H
+-
+-/*
+- * SuperH 5 version
+- * Copyright (C) 2003  Paul Mundt
+- */
+-
+-#ifdef __KERNEL__
+-
+-#ifndef __ASSEMBLY__
+-#include <asm/registers.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 */
+-	/* Put the 4 32-bit fields together to make asm offsetting easier. */
+-	int			preempt_count;	/* 0 => preemptable, <0 => BUG */
+-	__u16			cpu;
+-
+-	mm_segment_t		addr_limit;
+-	struct restart_block	restart_block;
+-
+-	__u8			supervisor_stack[0];
+-};
+-
+-/*
+- * macros/functions for gaining access to the thread information structure
+- */
+-#define INIT_THREAD_INFO(tsk)			\
+-{						\
+-	.task		= &tsk,			\
+-	.exec_domain	= &default_exec_domain,	\
+-	.flags		= 0,			\
+-	.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 */
+-static inline struct thread_info *current_thread_info(void)
+-{
+-	struct thread_info *ti;
+-
+-	__asm__ __volatile__ ("getcon " __KCR0 ", %0\n\t" : "=r" (ti));
+-
+-	return ti;
+-}
+-
+-/* thread information allocation */
+-
+-
+-
+-#define alloc_thread_info(ti) ((struct thread_info *) __get_free_pages(GFP_KERNEL,1))
+-#define free_thread_info(ti) free_pages((unsigned long) (ti), 1)
+-
+-#endif /* __ASSEMBLY__ */
+-
+-#define THREAD_SIZE  8192
+-
+-#define PREEMPT_ACTIVE		0x10000000
+-
+-/* thread information flags */
+-#define TIF_SYSCALL_TRACE	0	/* syscall trace active */
+-#define TIF_SIGPENDING		2	/* signal pending */
+-#define TIF_NEED_RESCHED	3	/* rescheduling necessary */
+-#define TIF_MEMDIE		4
+-#define TIF_RESTORE_SIGMASK	5	/* Restore signal mask in do_signal */
+-
+-#define _TIF_SYSCALL_TRACE	(1 << TIF_SYSCALL_TRACE)
+-#define _TIF_SIGPENDING		(1 << TIF_SIGPENDING)
+-#define _TIF_NEED_RESCHED	(1 << TIF_NEED_RESCHED)
+-#define _TIF_MEMDIE		(1 << TIF_MEMDIE)
+-#define _TIF_RESTORE_SIGMASK	(1 << TIF_RESTORE_SIGMASK)
+-
+-#endif /* __KERNEL__ */
+-
+-#endif /* __ASM_SH64_THREAD_INFO_H */
+diff --git a/include/asm-sh64/timex.h b/include/asm-sh64/timex.h
+deleted file mode 100644
+index 163e2b6..0000000
+--- a/include/asm-sh64/timex.h
++++ /dev/null
+@@ -1,31 +0,0 @@
+-#ifndef __ASM_SH64_TIMEX_H
+-#define __ASM_SH64_TIMEX_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.
+- *
+- * include/asm-sh64/timex.h
+- *
+- * Copyright (C) 2000, 2001  Paolo Alberelli
+- * Copyright (C) 2003  Paul Mundt
+- *
+- * sh-5 architecture timex specifications
+- *
+- */
+-
+-#define CLOCK_TICK_RATE	1193180 /* Underlying HZ */
+-#define CLOCK_TICK_FACTOR	20	/* Factor of both 1000000 and CLOCK_TICK_RATE */
+-
+-typedef unsigned long cycles_t;
+-
+-static __inline__ cycles_t get_cycles (void)
+-{
+-	return 0;
+-}
+-
+-#define vxtime_lock()		do {} while (0)
+-#define vxtime_unlock()		do {} while (0)
+-
+-#endif /* __ASM_SH64_TIMEX_H */
+diff --git a/include/asm-sh64/tlb.h b/include/asm-sh64/tlb.h
+deleted file mode 100644
+index 4979408..0000000
+--- a/include/asm-sh64/tlb.h
++++ /dev/null
+@@ -1,92 +0,0 @@
+-/*
+- * include/asm-sh64/tlb.h
+- *
+- * Copyright (C) 2003  Paul Mundt
+- *
+- * This file is subject to the terms and conditions of the GNU General Public
+- * License.  See the file "COPYING" in the main directory of this archive
+- * for more details.
+- *
+- */
+-#ifndef __ASM_SH64_TLB_H
+-#define __ASM_SH64_TLB_H
+-
+-/*
+- * Note! These are mostly unused, we just need the xTLB_LAST_VAR_UNRESTRICTED
+- * for head.S! Once this limitation is gone, we can clean the rest of this up.
+- */
+-
+-/* ITLB defines */
+-#define ITLB_FIXED	0x00000000	/* First fixed ITLB, see head.S */
+-#define ITLB_LAST_VAR_UNRESTRICTED	0x000003F0	/* Last ITLB */
+-
+-/* DTLB defines */
+-#define DTLB_FIXED	0x00800000	/* First fixed DTLB, see head.S */
+-#define DTLB_LAST_VAR_UNRESTRICTED	0x008003F0	/* Last DTLB */
+-
+-#ifndef __ASSEMBLY__
+-
+-/**
+- * for_each_dtlb_entry
+- *
+- * @tlb:	TLB entry
+- *
+- * Iterate over free (non-wired) DTLB entries
+- */
+-#define for_each_dtlb_entry(tlb)		\
+-	for (tlb  = cpu_data->dtlb.first;	\
+-	     tlb <= cpu_data->dtlb.last;	\
+-	     tlb += cpu_data->dtlb.step)
+-
+-/**
+- * for_each_itlb_entry
+- *
+- * @tlb:	TLB entry
+- *
+- * Iterate over free (non-wired) ITLB entries
+- */
+-#define for_each_itlb_entry(tlb)		\
+-	for (tlb  = cpu_data->itlb.first;	\
+-	     tlb <= cpu_data->itlb.last;	\
+-	     tlb += cpu_data->itlb.step)
+-
+-/**
+- * __flush_tlb_slot
+- *
+- * @slot:	Address of TLB slot.
+- *
+- * Flushes TLB slot @slot.
+- */
+-static inline void __flush_tlb_slot(unsigned long long slot)
+-{
+-	__asm__ __volatile__ ("putcfg %0, 0, r63\n" : : "r" (slot));
+-}
+-
+-/* arch/sh64/mm/tlb.c */
+-extern int sh64_tlb_init(void);
+-extern unsigned long long sh64_next_free_dtlb_entry(void);
+-extern unsigned long long sh64_get_wired_dtlb_entry(void);
+-extern int sh64_put_wired_dtlb_entry(unsigned long long entry);
+-
+-extern void sh64_setup_tlb_slot(unsigned long long config_addr, unsigned long eaddr, unsigned long asid, unsigned long paddr);
+-extern void sh64_teardown_tlb_slot(unsigned long long config_addr);
+-
+-#define tlb_start_vma(tlb, vma) \
+-	flush_cache_range(vma, vma->vm_start, vma->vm_end)
+-
+-#define tlb_end_vma(tlb, vma)	\
+-	flush_tlb_range(vma, vma->vm_start, vma->vm_end)
+-
+-#define __tlb_remove_tlb_entry(tlb, pte, address)	do { } while (0)
+-
+-/*
+- * Flush whole TLBs for MM
+- */
+-#define tlb_flush(tlb)		flush_tlb_mm((tlb)->mm)
+-
+-#include <asm-generic/tlb.h>
+-
+-#endif /* __ASSEMBLY__ */
+-
+-#endif /* __ASM_SH64_TLB_H */
+-
+diff --git a/include/asm-sh64/tlbflush.h b/include/asm-sh64/tlbflush.h
+deleted file mode 100644
+index 16a164a..0000000
+--- a/include/asm-sh64/tlbflush.h
++++ /dev/null
+@@ -1,27 +0,0 @@
+-#ifndef __ASM_SH64_TLBFLUSH_H
+-#define __ASM_SH64_TLBFLUSH_H
+-
+-#include <asm/pgalloc.h>
+-
+-/*
+- * TLB flushing:
+- *
+- *  - flush_tlb() flushes the current mm struct TLBs
+- *  - flush_tlb_all() flushes all processes TLBs
+- *  - flush_tlb_mm(mm) flushes the specified mm context TLB's
+- *  - flush_tlb_page(vma, vmaddr) flushes one page
+- *  - flush_tlb_range(mm, start, end) flushes a range of pages
+- *
+- */
+-
+-extern void flush_tlb(void);
+-extern void flush_tlb_all(void);
+-extern void flush_tlb_mm(struct mm_struct *mm);
+-extern void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
+-			    unsigned long end);
+-extern void flush_tlb_page(struct vm_area_struct *vma, unsigned long page);
+-
+-extern void flush_tlb_kernel_range(unsigned long start, unsigned long end);
+-
+-#endif /* __ASM_SH64_TLBFLUSH_H */
+-
+diff --git a/include/asm-sh64/topology.h b/include/asm-sh64/topology.h
+deleted file mode 100644
+index 3421178..0000000
+--- a/include/asm-sh64/topology.h
++++ /dev/null
+@@ -1,6 +0,0 @@
+-#ifndef __ASM_SH64_TOPOLOGY_H
+-#define __ASM_SH64_TOPOLOGY_H
+-
+-#include <asm-generic/topology.h>
+-
+-#endif /* __ASM_SH64_TOPOLOGY_H */
+diff --git a/include/asm-sh64/types.h b/include/asm-sh64/types.h
+deleted file mode 100644
+index 2c7ad73..0000000
+--- a/include/asm-sh64/types.h
++++ /dev/null
+@@ -1,74 +0,0 @@
+-#ifndef __ASM_SH64_TYPES_H
+-#define __ASM_SH64_TYPES_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.
+- *
+- * include/asm-sh64/types.h
+- *
+- * Copyright (C) 2000, 2001  Paolo Alberelli
+- *
+- */
+-
+-#ifndef __ASSEMBLY__
+-
+-typedef unsigned short umode_t;
+-
+-/*
+- * __xx is ok: it doesn't pollute the POSIX namespace. Use these in the
+- * header files exported to user space
+- */
+-
+-typedef __signed__ char __s8;
+-typedef unsigned char __u8;
+-
+-typedef __signed__ short __s16;
+-typedef unsigned short __u16;
+-
+-typedef __signed__ int __s32;
+-typedef unsigned int __u32;
+-
+-#if defined(__GNUC__)
+-__extension__ typedef __signed__ long long __s64;
+-__extension__ typedef unsigned long long __u64;
+-#endif
+-
+-#endif /* __ASSEMBLY__ */
+-
+-/*
+- * These aren't exported outside the kernel to avoid name space clashes
+- */
+-#ifdef __KERNEL__
+-
+-#ifndef __ASSEMBLY__
+-
+-typedef __signed__ char s8;
+-typedef unsigned char u8;
+-
+-typedef __signed__ short s16;
+-typedef unsigned short u16;
+-
+-typedef __signed__ int s32;
+-typedef unsigned int u32;
+-
+-typedef __signed__ long long s64;
+-typedef unsigned long long u64;
+-
+-/* DMA addresses come in generic and 64-bit flavours.  */
+-
+-#ifdef CONFIG_HIGHMEM64G
+-typedef u64 dma_addr_t;
+-#else
+-typedef u32 dma_addr_t;
+-#endif
+-typedef u64 dma64_addr_t;
+-
+-#endif /* __ASSEMBLY__ */
+-
+-#define BITS_PER_LONG 32
+-
+-#endif /* __KERNEL__ */
+-
+-#endif /* __ASM_SH64_TYPES_H */
+diff --git a/include/asm-sh64/uaccess.h b/include/asm-sh64/uaccess.h
+deleted file mode 100644
+index 644c67b..0000000
+--- a/include/asm-sh64/uaccess.h
++++ /dev/null
+@@ -1,316 +0,0 @@
+-#ifndef __ASM_SH64_UACCESS_H
+-#define __ASM_SH64_UACCESS_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.
+- *
+- * include/asm-sh64/uaccess.h
+- *
+- * Copyright (C) 2000, 2001  Paolo Alberelli
+- * Copyright (C) 2003, 2004  Paul Mundt
+- *
+- * User space memory access functions
+- *
+- * Copyright (C) 1999  Niibe Yutaka
+- *
+- *  Based on:
+- *     MIPS implementation version 1.15 by
+- *              Copyright (C) 1996, 1997, 1998 by Ralf Baechle
+- *     and i386 version.
+- *
+- */
 -
--#undef SUPPORT_VLB_SYNC
--#define SUPPORT_VLB_SYNC 0
+-#include <linux/errno.h>
+-#include <linux/sched.h>
 -
- #endif /* __KERNEL__ */
- 
- #endif /* __ASMCRIS_IDE_H */
-diff --git a/include/asm-cris/arch-v32/ide.h b/include/asm-cris/arch-v32/ide.h
-index 1129617..fb9c362 100644
---- a/include/asm-cris/arch-v32/ide.h
-+++ b/include/asm-cris/arch-v32/ide.h
-@@ -48,11 +48,6 @@ static inline unsigned long ide_default_io_base(int index)
- 	return REG_TYPE_CONV(unsigned long, reg_ata_rw_ctrl2, ctrl2);
- }
- 
--/* some configuration options we don't need */
+-#define VERIFY_READ    0
+-#define VERIFY_WRITE   1
 -
--#undef SUPPORT_VLB_SYNC
--#define SUPPORT_VLB_SYNC 0
+-/*
+- * 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 (Data Segment Register?), these macros are misnamed.
+- */
 -
- #define IDE_ARCH_ACK_INTR
- #define ide_ack_intr(hwif)	((hwif)->ack_intr(hwif))
- 
-diff --git a/include/asm-frv/ide.h b/include/asm-frv/ide.h
-index f0bd2cb..8c9a540 100644
---- a/include/asm-frv/ide.h
-+++ b/include/asm-frv/ide.h
-@@ -18,12 +18,6 @@
- #include <asm/io.h>
- #include <asm/irq.h>
- 
--#undef SUPPORT_SLOW_DATA_PORTS
--#define SUPPORT_SLOW_DATA_PORTS 0
+-#define MAKE_MM_SEG(s)	((mm_segment_t) { (s) })
 -
--#undef SUPPORT_VLB_SYNC
--#define SUPPORT_VLB_SYNC 0
+-#define KERNEL_DS	MAKE_MM_SEG(0xFFFFFFFF)
+-#define USER_DS		MAKE_MM_SEG(0x80000000)
 -
- #ifndef MAX_HWIFS
- #define MAX_HWIFS 8
- #endif
-diff --git a/include/asm-generic/resource.h b/include/asm-generic/resource.h
-index a4a22cc..587566f 100644
---- a/include/asm-generic/resource.h
-+++ b/include/asm-generic/resource.h
-@@ -44,8 +44,8 @@
- #define RLIMIT_NICE		13	/* max nice prio allowed to raise to
- 					   0-39 for nice level 19 .. -20 */
- #define RLIMIT_RTPRIO		14	/* maximum realtime priority */
+-#define get_ds()	(KERNEL_DS)
+-#define get_fs()        (current_thread_info()->addr_limit)
+-#define set_fs(x)       (current_thread_info()->addr_limit=(x))
 -
--#define RLIM_NLIMITS		15
-+#define RLIMIT_RTTIME		15	/* timeout for RT tasks in us */
-+#define RLIM_NLIMITS		16
- 
- /*
-  * SuS says limits have to be unsigned.
-@@ -86,6 +86,7 @@
- 	[RLIMIT_MSGQUEUE]	= {   MQ_BYTES_MAX,   MQ_BYTES_MAX },	\
- 	[RLIMIT_NICE]		= { 0, 0 },				\
- 	[RLIMIT_RTPRIO]		= { 0, 0 },				\
-+	[RLIMIT_RTTIME]		= {  RLIM_INFINITY,  RLIM_INFINITY },	\
- }
- 
- #endif	/* __KERNEL__ */
-diff --git a/include/asm-powerpc/ide.h b/include/asm-powerpc/ide.h
-index fd7f5a4..6d50310 100644
---- a/include/asm-powerpc/ide.h
-+++ b/include/asm-powerpc/ide.h
-@@ -42,9 +42,6 @@ struct ide_machdep_calls {
- 
- extern struct ide_machdep_calls ppc_ide_md;
- 
--#undef	SUPPORT_SLOW_DATA_PORTS
--#define	SUPPORT_SLOW_DATA_PORTS	0
+-#define segment_eq(a,b)	((a).seg == (b).seg)
+-
+-#define __addr_ok(addr) ((unsigned long)(addr) < (current_thread_info()->addr_limit.seg))
 -
- #define IDE_ARCH_OBSOLETE_DEFAULTS
- 
- static __inline__ int ide_default_irq(unsigned long base)
-diff --git a/include/asm-s390/airq.h b/include/asm-s390/airq.h
-new file mode 100644
-index 0000000..41d028c
---- /dev/null
-+++ b/include/asm-s390/airq.h
-@@ -0,0 +1,19 @@
-+/*
-+ *  include/asm-s390/airq.h
-+ *
-+ *    Copyright IBM Corp. 2002,2007
-+ *    Author(s): Ingo Adlung <adlung at de.ibm.com>
-+ *		 Cornelia Huck <cornelia.huck at de.ibm.com>
-+ *		 Arnd Bergmann <arndb at de.ibm.com>
-+ *		 Peter Oberparleiter <peter.oberparleiter at de.ibm.com>
-+ */
-+
-+#ifndef _ASM_S390_AIRQ_H
-+#define _ASM_S390_AIRQ_H
-+
-+typedef void (*adapter_int_handler_t)(void *, void *);
-+
-+void *s390_register_adapter_interrupt(adapter_int_handler_t, void *);
-+void s390_unregister_adapter_interrupt(void *);
-+
-+#endif /* _ASM_S390_AIRQ_H */
-diff --git a/include/asm-s390/cio.h b/include/asm-s390/cio.h
-index 2f08c16..123b557 100644
---- a/include/asm-s390/cio.h
-+++ b/include/asm-s390/cio.h
-@@ -24,8 +24,8 @@
-  * @fmt: format
-  * @pfch: prefetch
-  * @isic: initial-status interruption control
-- * @alcc: adress-limit checking control
-- * @ssi: supress-suspended interruption
-+ * @alcc: address-limit checking control
-+ * @ssi: suppress-suspended interruption
-  * @zcc: zero condition code
-  * @ectl: extended control
-  * @pno: path not operational
-diff --git a/include/asm-s390/dasd.h b/include/asm-s390/dasd.h
-index 604f68f..3f002e1 100644
---- a/include/asm-s390/dasd.h
-+++ b/include/asm-s390/dasd.h
-@@ -105,7 +105,7 @@ typedef struct dasd_information_t {
- } dasd_information_t;
- 
- /*
-- * Read Subsystem Data - Perfomance Statistics
-+ * Read Subsystem Data - Performance Statistics
-  */ 
- typedef struct dasd_rssd_perf_stats_t {
- 	unsigned char  invalid:1;
-diff --git a/include/asm-s390/ipl.h b/include/asm-s390/ipl.h
-index 2c40fd3..c1b2e50 100644
---- a/include/asm-s390/ipl.h
-+++ b/include/asm-s390/ipl.h
-@@ -83,6 +83,8 @@ extern u32 dump_prefix_page;
- extern unsigned int zfcpdump_prefix_array[];
- 
- extern void do_reipl(void);
-+extern void do_halt(void);
-+extern void do_poff(void);
- extern void ipl_save_parameters(void);
- 
- enum {
-@@ -118,7 +120,7 @@ struct ipl_info
- };
- 
- extern struct ipl_info ipl_info;
--extern void setup_ipl_info(void);
-+extern void setup_ipl(void);
- 
- /*
-  * DIAG 308 support
-@@ -141,6 +143,10 @@ enum diag308_opt {
- 	DIAG308_IPL_OPT_DUMP	= 0x20,
- };
- 
-+enum diag308_flags {
-+	DIAG308_FLAGS_LP_VALID	= 0x80,
-+};
-+
- enum diag308_rc {
- 	DIAG308_RC_OK	= 1,
- };
-diff --git a/include/asm-s390/mmu_context.h b/include/asm-s390/mmu_context.h
-index 05b8421..a77d4ba 100644
---- a/include/asm-s390/mmu_context.h
-+++ b/include/asm-s390/mmu_context.h
-@@ -12,10 +12,15 @@
- #include <asm/pgalloc.h>
- #include <asm-generic/mm_hooks.h>
- 
 -/*
-- * get a new mmu context.. S390 don't know about contexts.
+- * Uhhuh, this needs 33-bit arithmetic. We have a carry..
+- *
+- * sum := addr + size;  carry? --> flag = true;
+- * if (sum >= addr_limit) flag = true;
 - */
--#define init_new_context(tsk,mm)        0
-+static inline int init_new_context(struct task_struct *tsk,
-+				   struct mm_struct *mm)
-+{
-+	mm->context = _ASCE_TABLE_LENGTH | _ASCE_USER_BITS;
-+#ifdef CONFIG_64BIT
-+	mm->context |= _ASCE_TYPE_REGION3;
-+#endif
-+	return 0;
-+}
- 
- #define destroy_context(mm)             do { } while (0)
- 
-@@ -27,19 +32,11 @@
- 
- static inline void update_mm(struct mm_struct *mm, struct task_struct *tsk)
- {
--	pgd_t *pgd = mm->pgd;
--	unsigned long asce_bits;
+-#define __range_ok(addr,size) (((unsigned long) (addr) + (size) < (current_thread_info()->addr_limit.seg)) ? 0 : 1)
 -
--	/* Calculate asce bits from the first pgd table entry. */
--	asce_bits = _ASCE_TABLE_LENGTH | _ASCE_USER_BITS;
--#ifdef CONFIG_64BIT
--	asce_bits |= _ASCE_TYPE_REGION3;
--#endif
--	S390_lowcore.user_asce = asce_bits | __pa(pgd);
-+	S390_lowcore.user_asce = mm->context | __pa(mm->pgd);
- 	if (switch_amode) {
- 		/* Load primary space page table origin. */
--		pgd_t *shadow_pgd = get_shadow_table(pgd) ? : pgd;
--		S390_lowcore.user_exec_asce = asce_bits | __pa(shadow_pgd);
-+		pgd_t *shadow_pgd = get_shadow_table(mm->pgd) ? : mm->pgd;
-+		S390_lowcore.user_exec_asce = mm->context | __pa(shadow_pgd);
- 		asm volatile(LCTL_OPCODE" 1,1,%0\n"
- 			     : : "m" (S390_lowcore.user_exec_asce) );
- 	} else
-diff --git a/include/asm-s390/pgtable.h b/include/asm-s390/pgtable.h
-index 1f530f8..79b9eab 100644
---- a/include/asm-s390/pgtable.h
-+++ b/include/asm-s390/pgtable.h
-@@ -104,41 +104,27 @@ extern char empty_zero_page[PAGE_SIZE];
- 
- #ifndef __ASSEMBLY__
- /*
-- * Just any arbitrary offset to the start of the vmalloc VM area: the
-- * current 8MB value just means that there will be a 8MB "hole" after the
-- * physical memory until the kernel virtual memory starts.  That means that
-- * any out-of-bounds memory accesses will hopefully be caught.
-- * The vmalloc() routines leaves a hole of 4kB between each vmalloced
-- * area for the same reason. ;)
-- * vmalloc area starts at 4GB to prevent syscall table entry exchanging
-- * from modules.
+-#define access_ok(type,addr,size) (__range_ok(addr,size) == 0)
+-#define __access_ok(addr,size) (__range_ok(addr,size) == 0)
+-
+-/*
+- * Uh, these should become the main single-value transfer routines ...
+- * They automatically use the right size if we just have the right
+- * pointer type ...
+- *
+- * As MIPS uses the same address space for kernel and user data, we
+- * can just do these as direct assignments.
+- *
+- * Careful to not
+- * (a) re-use the arguments for side effects (sizeof is ok)
+- * (b) require any knowledge of processes at this stage
 - */
--extern unsigned long vmalloc_end;
+-#define put_user(x,ptr)	__put_user_check((x),(ptr),sizeof(*(ptr)))
+-#define get_user(x,ptr) __get_user_check((x),(ptr),sizeof(*(ptr)))
 -
--#ifdef CONFIG_64BIT
--#define VMALLOC_ADDR	(max(0x100000000UL, (unsigned long) high_memory))
--#else
--#define VMALLOC_ADDR	((unsigned long) high_memory)
+-/*
+- * The "__xxx" versions do not do address space checking, useful when
+- * doing multiple accesses to the same area (the user has to do the
+- * checks by hand with "access_ok()")
+- */
+-#define __put_user(x,ptr) __put_user_nocheck((x),(ptr),sizeof(*(ptr)))
+-#define __get_user(x,ptr) __get_user_nocheck((x),(ptr),sizeof(*(ptr)))
+-
+-/*
+- * The "xxx_ret" versions return constant specified in third argument, if
+- * something bad happens. These macros can be optimized for the
+- * case of just returning from the function xxx_ret is used.
+- */
+-
+-#define put_user_ret(x,ptr,ret) ({ \
+-if (put_user(x,ptr)) return ret; })
+-
+-#define get_user_ret(x,ptr,ret) ({ \
+-if (get_user(x,ptr)) return ret; })
+-
+-#define __put_user_ret(x,ptr,ret) ({ \
+-if (__put_user(x,ptr)) return ret; })
+-
+-#define __get_user_ret(x,ptr,ret) ({ \
+-if (__get_user(x,ptr)) return ret; })
+-
+-struct __large_struct { unsigned long buf[100]; };
+-#define __m(x) (*(struct __large_struct *)(x))
+-
+-#define __get_user_size(x,ptr,size,retval)			\
+-do {								\
+-	retval = 0;						\
+-	switch (size) {						\
+-	case 1:							\
+-		retval = __get_user_asm_b(x, ptr);		\
+-		break;						\
+-	case 2:							\
+-		retval = __get_user_asm_w(x, ptr);		\
+-		break;						\
+-	case 4:							\
+-		retval = __get_user_asm_l(x, ptr);		\
+-		break;						\
+-	case 8:							\
+-		retval = __get_user_asm_q(x, ptr);		\
+-		break;						\
+-	default:						\
+-		__get_user_unknown();				\
+-		break;						\
+-	}							\
+-} while (0)
+-
+-#define __get_user_nocheck(x,ptr,size)				\
+-({								\
+-	long __gu_err, __gu_val;				\
+-	__get_user_size((void *)&__gu_val, (long)(ptr),		\
+-			(size), __gu_err);			\
+-	(x) = (__typeof__(*(ptr)))__gu_val;			\
+-	__gu_err;						\
+-})
+-
+-#define __get_user_check(x,ptr,size)				\
+-({								\
+-	long __gu_addr = (long)(ptr);				\
+-	long __gu_err = -EFAULT, __gu_val;			\
+-	if (__access_ok(__gu_addr, (size)))			\
+-		__get_user_size((void *)&__gu_val, __gu_addr,	\
+-				(size), __gu_err);		\
+-	(x) = (__typeof__(*(ptr))) __gu_val;			\
+-	__gu_err;						\
+-})
+-
+-extern long __get_user_asm_b(void *, long);
+-extern long __get_user_asm_w(void *, long);
+-extern long __get_user_asm_l(void *, long);
+-extern long __get_user_asm_q(void *, long);
+-extern void __get_user_unknown(void);
+-
+-#define __put_user_size(x,ptr,size,retval)			\
+-do {								\
+-	retval = 0;						\
+-	switch (size) {						\
+-	case 1:							\
+-		retval = __put_user_asm_b(x, ptr);		\
+-		break;						\
+-	case 2:							\
+-		retval = __put_user_asm_w(x, ptr);		\
+-		break;						\
+-	case 4:							\
+-		retval = __put_user_asm_l(x, ptr);		\
+-		break;						\
+-	case 8:							\
+-		retval = __put_user_asm_q(x, ptr);		\
+-		break;						\
+-	default:						\
+-		__put_user_unknown();				\
+-	}							\
+-} while (0)
+-
+-#define __put_user_nocheck(x,ptr,size)				\
+-({								\
+-	long __pu_err;						\
+-	__typeof__(*(ptr)) __pu_val = (x);			\
+-	__put_user_size((void *)&__pu_val, (long)(ptr), (size), __pu_err); \
+-	__pu_err;						\
+-})
+-
+-#define __put_user_check(x,ptr,size)				\
+-({								\
+-	long __pu_err = -EFAULT;				\
+-	long __pu_addr = (long)(ptr);				\
+-	__typeof__(*(ptr)) __pu_val = (x);			\
+-								\
+-	if (__access_ok(__pu_addr, (size)))			\
+-		__put_user_size((void *)&__pu_val, __pu_addr, (size), __pu_err);\
+-	__pu_err;						\
+-})
+-
+-extern long __put_user_asm_b(void *, long);
+-extern long __put_user_asm_w(void *, long);
+-extern long __put_user_asm_l(void *, long);
+-extern long __put_user_asm_q(void *, long);
+-extern void __put_user_unknown(void);
+-
+-
+-/* Generic arbitrary sized copy.  */
+-/* Return the number of bytes NOT copied */
+-/* XXX: should be such that: 4byte and the rest. */
+-extern __kernel_size_t __copy_user(void *__to, const void *__from, __kernel_size_t __n);
+-
+-#define copy_to_user(to,from,n) ({ \
+-void *__copy_to = (void *) (to); \
+-__kernel_size_t __copy_size = (__kernel_size_t) (n); \
+-__kernel_size_t __copy_res; \
+-if(__copy_size && __access_ok((unsigned long)__copy_to, __copy_size)) { \
+-__copy_res = __copy_user(__copy_to, (void *) (from), __copy_size); \
+-} else __copy_res = __copy_size; \
+-__copy_res; })
+-
+-#define copy_to_user_ret(to,from,n,retval) ({ \
+-if (copy_to_user(to,from,n)) \
+-	return retval; \
+-})
+-
+-#define __copy_to_user(to,from,n)		\
+-	__copy_user((void *)(to),		\
+-		    (void *)(from), n)
+-
+-#define __copy_to_user_ret(to,from,n,retval) ({ \
+-if (__copy_to_user(to,from,n)) \
+-	return retval; \
+-})
+-
+-#define copy_from_user(to,from,n) ({ \
+-void *__copy_to = (void *) (to); \
+-void *__copy_from = (void *) (from); \
+-__kernel_size_t __copy_size = (__kernel_size_t) (n); \
+-__kernel_size_t __copy_res; \
+-if(__copy_size && __access_ok((unsigned long)__copy_from, __copy_size)) { \
+-__copy_res = __copy_user(__copy_to, __copy_from, __copy_size); \
+-} else __copy_res = __copy_size; \
+-__copy_res; })
+-
+-#define copy_from_user_ret(to,from,n,retval) ({ \
+-if (copy_from_user(to,from,n)) \
+-	return retval; \
+-})
+-
+-#define __copy_from_user(to,from,n)		\
+-	__copy_user((void *)(to),		\
+-		    (void *)(from), n)
+-
+-#define __copy_from_user_ret(to,from,n,retval) ({ \
+-if (__copy_from_user(to,from,n)) \
+-	return retval; \
+-})
+-
+-#define __copy_to_user_inatomic __copy_to_user
+-#define __copy_from_user_inatomic __copy_from_user
+-
+-/* XXX: Not sure it works well..
+-   should be such that: 4byte clear and the rest. */
+-extern __kernel_size_t __clear_user(void *addr, __kernel_size_t size);
+-
+-#define clear_user(addr,n) ({ \
+-void * __cl_addr = (addr); \
+-unsigned long __cl_size = (n); \
+-if (__cl_size && __access_ok(((unsigned long)(__cl_addr)), __cl_size)) \
+-__cl_size = __clear_user(__cl_addr, __cl_size); \
+-__cl_size; })
+-
+-extern int __strncpy_from_user(unsigned long __dest, unsigned long __src, int __count);
+-
+-#define strncpy_from_user(dest,src,count) ({ \
+-unsigned long __sfu_src = (unsigned long) (src); \
+-int __sfu_count = (int) (count); \
+-long __sfu_res = -EFAULT; \
+-if(__access_ok(__sfu_src, __sfu_count)) { \
+-__sfu_res = __strncpy_from_user((unsigned long) (dest), __sfu_src, __sfu_count); \
+-} __sfu_res; })
+-
+-#define strlen_user(str) strnlen_user(str, ~0UL >> 1)
+-
+-/*
+- * Return the size of a string (including the ending 0!)
+- */
+-extern long __strnlen_user(const char *__s, long __n);
+-
+-static inline long strnlen_user(const char *s, long n)
+-{
+-	if (!__addr_ok(s))
+-		return 0;
+-	else
+-		return __strnlen_user(s, n);
+-}
+-
+-struct exception_table_entry
+-{
+-	unsigned long insn, fixup;
+-};
+-
+-#define ARCH_HAS_SEARCH_EXTABLE
+-
+-/* If gcc inlines memset, it will use st.q instructions.  Therefore, we need
+-   kmalloc allocations to be 8-byte aligned.  Without this, the alignment
+-   becomes BYTE_PER_WORD i.e. only 4 (since sizeof(long)==sizeof(void*)==4 on
+-   sh64 at the moment). */
+-#define ARCH_KMALLOC_MINALIGN 8
+-
+-/*
+- * We want 8-byte alignment for the slab caches as well, otherwise we have
+- * the same BYTES_PER_WORD (sizeof(void *)) min align in kmem_cache_create().
+- */
+-#define ARCH_SLAB_MINALIGN 8
+-
+-/* Returns 0 if exception not found and fixup.unit otherwise.  */
+-extern unsigned long search_exception_table(unsigned long addr);
+-extern const struct exception_table_entry *search_exception_tables (unsigned long addr);
+-
+-#endif /* __ASM_SH64_UACCESS_H */
+diff --git a/include/asm-sh64/ucontext.h b/include/asm-sh64/ucontext.h
+deleted file mode 100644
+index cf77a08..0000000
+--- a/include/asm-sh64/ucontext.h
++++ /dev/null
+@@ -1,23 +0,0 @@
+-#ifndef __ASM_SH64_UCONTEXT_H
+-#define __ASM_SH64_UCONTEXT_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.
+- *
+- * include/asm-sh64/ucontext.h
+- *
+- * Copyright (C) 2000, 2001  Paolo Alberelli
+- *
+- */
+-
+-struct ucontext {
+-	unsigned long	  uc_flags;
+-	struct ucontext  *uc_link;
+-	stack_t		  uc_stack;
+-	struct sigcontext uc_mcontext;
+-	sigset_t	  uc_sigmask;	/* mask last for extensibility */
+-};
+-
+-#endif /* __ASM_SH64_UCONTEXT_H */
+diff --git a/include/asm-sh64/unaligned.h b/include/asm-sh64/unaligned.h
+deleted file mode 100644
+index 74481b1..0000000
+--- a/include/asm-sh64/unaligned.h
++++ /dev/null
+@@ -1,17 +0,0 @@
+-#ifndef __ASM_SH64_UNALIGNED_H
+-#define __ASM_SH64_UNALIGNED_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.
+- *
+- * include/asm-sh64/unaligned.h
+- *
+- * Copyright (C) 2000, 2001  Paolo Alberelli
+- *
+- */
+-
+-#include <asm-generic/unaligned.h>
+-
+-#endif /* __ASM_SH64_UNALIGNED_H */
+diff --git a/include/asm-sh64/unistd.h b/include/asm-sh64/unistd.h
+deleted file mode 100644
+index 1a5197f..0000000
+--- a/include/asm-sh64/unistd.h
++++ /dev/null
+@@ -1,417 +0,0 @@
+-#ifndef __ASM_SH64_UNISTD_H
+-#define __ASM_SH64_UNISTD_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.
+- *
+- * include/asm-sh64/unistd.h
+- *
+- * Copyright (C) 2000, 2001  Paolo Alberelli
+- * Copyright (C) 2003 - 2007 Paul Mundt
+- * Copyright (C) 2004  Sean McGoogan
+- *
+- * This file contains the system call numbers.
+- *
+- */
+-
+-#define __NR_restart_syscall	  0
+-#define __NR_exit		  1
+-#define __NR_fork		  2
+-#define __NR_read		  3
+-#define __NR_write		  4
+-#define __NR_open		  5
+-#define __NR_close		  6
+-#define __NR_waitpid		  7
+-#define __NR_creat		  8
+-#define __NR_link		  9
+-#define __NR_unlink		 10
+-#define __NR_execve		 11
+-#define __NR_chdir		 12
+-#define __NR_time		 13
+-#define __NR_mknod		 14
+-#define __NR_chmod		 15
+-#define __NR_lchown		 16
+-#define __NR_break		 17
+-#define __NR_oldstat		 18
+-#define __NR_lseek		 19
+-#define __NR_getpid		 20
+-#define __NR_mount		 21
+-#define __NR_umount		 22
+-#define __NR_setuid		 23
+-#define __NR_getuid		 24
+-#define __NR_stime		 25
+-#define __NR_ptrace		 26
+-#define __NR_alarm		 27
+-#define __NR_oldfstat		 28
+-#define __NR_pause		 29
+-#define __NR_utime		 30
+-#define __NR_stty		 31
+-#define __NR_gtty		 32
+-#define __NR_access		 33
+-#define __NR_nice		 34
+-#define __NR_ftime		 35
+-#define __NR_sync		 36
+-#define __NR_kill		 37
+-#define __NR_rename		 38
+-#define __NR_mkdir		 39
+-#define __NR_rmdir		 40
+-#define __NR_dup		 41
+-#define __NR_pipe		 42
+-#define __NR_times		 43
+-#define __NR_prof		 44
+-#define __NR_brk		 45
+-#define __NR_setgid		 46
+-#define __NR_getgid		 47
+-#define __NR_signal		 48
+-#define __NR_geteuid		 49
+-#define __NR_getegid		 50
+-#define __NR_acct		 51
+-#define __NR_umount2		 52
+-#define __NR_lock		 53
+-#define __NR_ioctl		 54
+-#define __NR_fcntl		 55
+-#define __NR_mpx		 56
+-#define __NR_setpgid		 57
+-#define __NR_ulimit		 58
+-#define __NR_oldolduname	 59
+-#define __NR_umask		 60
+-#define __NR_chroot		 61
+-#define __NR_ustat		 62
+-#define __NR_dup2		 63
+-#define __NR_getppid		 64
+-#define __NR_getpgrp		 65
+-#define __NR_setsid		 66
+-#define __NR_sigaction		 67
+-#define __NR_sgetmask		 68
+-#define __NR_ssetmask		 69
+-#define __NR_setreuid		 70
+-#define __NR_setregid		 71
+-#define __NR_sigsuspend		 72
+-#define __NR_sigpending		 73
+-#define __NR_sethostname	 74
+-#define __NR_setrlimit		 75
+-#define __NR_getrlimit	 	 76	/* Back compatible 2Gig limited rlimit */
+-#define __NR_getrusage		 77
+-#define __NR_gettimeofday	 78
+-#define __NR_settimeofday	 79
+-#define __NR_getgroups		 80
+-#define __NR_setgroups		 81
+-#define __NR_select		 82
+-#define __NR_symlink		 83
+-#define __NR_oldlstat		 84
+-#define __NR_readlink		 85
+-#define __NR_uselib		 86
+-#define __NR_swapon		 87
+-#define __NR_reboot		 88
+-#define __NR_readdir		 89
+-#define __NR_mmap		 90
+-#define __NR_munmap		 91
+-#define __NR_truncate		 92
+-#define __NR_ftruncate		 93
+-#define __NR_fchmod		 94
+-#define __NR_fchown		 95
+-#define __NR_getpriority	 96
+-#define __NR_setpriority	 97
+-#define __NR_profil		 98
+-#define __NR_statfs		 99
+-#define __NR_fstatfs		100
+-#define __NR_ioperm		101
+-#define __NR_socketcall		102	/* old implementation of socket systemcall */
+-#define __NR_syslog		103
+-#define __NR_setitimer		104
+-#define __NR_getitimer		105
+-#define __NR_stat		106
+-#define __NR_lstat		107
+-#define __NR_fstat		108
+-#define __NR_olduname		109
+-#define __NR_iopl		110
+-#define __NR_vhangup		111
+-#define __NR_idle		112
+-#define __NR_vm86old		113
+-#define __NR_wait4		114
+-#define __NR_swapoff		115
+-#define __NR_sysinfo		116
+-#define __NR_ipc		117
+-#define __NR_fsync		118
+-#define __NR_sigreturn		119
+-#define __NR_clone		120
+-#define __NR_setdomainname	121
+-#define __NR_uname		122
+-#define __NR_modify_ldt		123
+-#define __NR_adjtimex		124
+-#define __NR_mprotect		125
+-#define __NR_sigprocmask	126
+-#define __NR_create_module	127
+-#define __NR_init_module	128
+-#define __NR_delete_module	129
+-#define __NR_get_kernel_syms	130
+-#define __NR_quotactl		131
+-#define __NR_getpgid		132
+-#define __NR_fchdir		133
+-#define __NR_bdflush		134
+-#define __NR_sysfs		135
+-#define __NR_personality	136
+-#define __NR_afs_syscall	137 /* Syscall for Andrew File System */
+-#define __NR_setfsuid		138
+-#define __NR_setfsgid		139
+-#define __NR__llseek		140
+-#define __NR_getdents		141
+-#define __NR__newselect		142
+-#define __NR_flock		143
+-#define __NR_msync		144
+-#define __NR_readv		145
+-#define __NR_writev		146
+-#define __NR_getsid		147
+-#define __NR_fdatasync		148
+-#define __NR__sysctl		149
+-#define __NR_mlock		150
+-#define __NR_munlock		151
+-#define __NR_mlockall		152
+-#define __NR_munlockall		153
+-#define __NR_sched_setparam		154
+-#define __NR_sched_getparam		155
+-#define __NR_sched_setscheduler		156
+-#define __NR_sched_getscheduler		157
+-#define __NR_sched_yield		158
+-#define __NR_sched_get_priority_max	159
+-#define __NR_sched_get_priority_min	160
+-#define __NR_sched_rr_get_interval	161
+-#define __NR_nanosleep		162
+-#define __NR_mremap		163
+-#define __NR_setresuid		164
+-#define __NR_getresuid		165
+-#define __NR_vm86		166
+-#define __NR_query_module	167
+-#define __NR_poll		168
+-#define __NR_nfsservctl		169
+-#define __NR_setresgid		170
+-#define __NR_getresgid		171
+-#define __NR_prctl              172
+-#define __NR_rt_sigreturn	173
+-#define __NR_rt_sigaction	174
+-#define __NR_rt_sigprocmask	175
+-#define __NR_rt_sigpending	176
+-#define __NR_rt_sigtimedwait	177
+-#define __NR_rt_sigqueueinfo	178
+-#define __NR_rt_sigsuspend	179
+-#define __NR_pread64		180
+-#define __NR_pwrite64		181
+-#define __NR_chown		182
+-#define __NR_getcwd		183
+-#define __NR_capget		184
+-#define __NR_capset		185
+-#define __NR_sigaltstack	186
+-#define __NR_sendfile		187
+-#define __NR_streams1		188	/* some people actually want it */
+-#define __NR_streams2		189	/* some people actually want it */
+-#define __NR_vfork		190
+-#define __NR_ugetrlimit		191	/* SuS compliant getrlimit */
+-#define __NR_mmap2		192
+-#define __NR_truncate64		193
+-#define __NR_ftruncate64	194
+-#define __NR_stat64		195
+-#define __NR_lstat64		196
+-#define __NR_fstat64		197
+-#define __NR_lchown32		198
+-#define __NR_getuid32		199
+-#define __NR_getgid32		200
+-#define __NR_geteuid32		201
+-#define __NR_getegid32		202
+-#define __NR_setreuid32		203
+-#define __NR_setregid32		204
+-#define __NR_getgroups32	205
+-#define __NR_setgroups32	206
+-#define __NR_fchown32		207
+-#define __NR_setresuid32	208
+-#define __NR_getresuid32	209
+-#define __NR_setresgid32	210
+-#define __NR_getresgid32	211
+-#define __NR_chown32		212
+-#define __NR_setuid32		213
+-#define __NR_setgid32		214
+-#define __NR_setfsuid32		215
+-#define __NR_setfsgid32		216
+-#define __NR_pivot_root		217
+-#define __NR_mincore		218
+-#define __NR_madvise		219
+-
+-/* Non-multiplexed socket family */
+-#define __NR_socket		220
+-#define __NR_bind		221
+-#define __NR_connect		222
+-#define __NR_listen		223
+-#define __NR_accept		224
+-#define __NR_getsockname	225
+-#define __NR_getpeername	226
+-#define __NR_socketpair		227
+-#define __NR_send		228
+-#define __NR_sendto		229
+-#define __NR_recv		230
+-#define __NR_recvfrom		231
+-#define __NR_shutdown		232
+-#define __NR_setsockopt		233
+-#define __NR_getsockopt		234
+-#define __NR_sendmsg		235
+-#define __NR_recvmsg		236
+-
+-/* Non-multiplexed IPC family */
+-#define __NR_semop		237
+-#define __NR_semget		238
+-#define __NR_semctl		239
+-#define __NR_msgsnd		240
+-#define __NR_msgrcv		241
+-#define __NR_msgget		242
+-#define __NR_msgctl		243
+-#if 0
+-#define __NR_shmatcall		244
 -#endif
--#define VMALLOC_OFFSET	(8*1024*1024)
--#define VMALLOC_START	((VMALLOC_ADDR + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
--#define VMALLOC_END	vmalloc_end
+-#define __NR_shmdt		245
+-#define __NR_shmget		246
+-#define __NR_shmctl		247
+-
+-#define __NR_getdents64		248
+-#define __NR_fcntl64		249
+-/* 223 is unused */
+-#define __NR_gettid		252
+-#define __NR_readahead		253
+-#define __NR_setxattr		254
+-#define __NR_lsetxattr		255
+-#define __NR_fsetxattr		256
+-#define __NR_getxattr		257
+-#define __NR_lgetxattr		258
+-#define __NR_fgetxattr		269
+-#define __NR_listxattr		260
+-#define __NR_llistxattr		261
+-#define __NR_flistxattr		262
+-#define __NR_removexattr	263
+-#define __NR_lremovexattr	264
+-#define __NR_fremovexattr	265
+-#define __NR_tkill		266
+-#define __NR_sendfile64		267
+-#define __NR_futex		268
+-#define __NR_sched_setaffinity	269
+-#define __NR_sched_getaffinity	270
+-#define __NR_set_thread_area	271
+-#define __NR_get_thread_area	272
+-#define __NR_io_setup		273
+-#define __NR_io_destroy		274
+-#define __NR_io_getevents	275
+-#define __NR_io_submit		276
+-#define __NR_io_cancel		277
+-#define __NR_fadvise64		278
+-#define __NR_exit_group		280
+-
+-#define __NR_lookup_dcookie	281
+-#define __NR_epoll_create	282
+-#define __NR_epoll_ctl		283
+-#define __NR_epoll_wait		284
+-#define __NR_remap_file_pages	285
+-#define __NR_set_tid_address	286
+-#define __NR_timer_create	287
+-#define __NR_timer_settime	(__NR_timer_create+1)
+-#define __NR_timer_gettime	(__NR_timer_create+2)
+-#define __NR_timer_getoverrun	(__NR_timer_create+3)
+-#define __NR_timer_delete	(__NR_timer_create+4)
+-#define __NR_clock_settime	(__NR_timer_create+5)
+-#define __NR_clock_gettime	(__NR_timer_create+6)
+-#define __NR_clock_getres	(__NR_timer_create+7)
+-#define __NR_clock_nanosleep	(__NR_timer_create+8)
+-#define __NR_statfs64		296
+-#define __NR_fstatfs64		297
+-#define __NR_tgkill		298
+-#define __NR_utimes		299
+-#define __NR_fadvise64_64	300
+-#define __NR_vserver		301
+-#define __NR_mbind              302
+-#define __NR_get_mempolicy      303
+-#define __NR_set_mempolicy      304
+-#define __NR_mq_open            305
+-#define __NR_mq_unlink          (__NR_mq_open+1)
+-#define __NR_mq_timedsend       (__NR_mq_open+2)
+-#define __NR_mq_timedreceive    (__NR_mq_open+3)
+-#define __NR_mq_notify          (__NR_mq_open+4)
+-#define __NR_mq_getsetattr      (__NR_mq_open+5)
+-#define __NR_kexec_load		311
+-#define __NR_waitid		312
+-#define __NR_add_key		313
+-#define __NR_request_key	314
+-#define __NR_keyctl		315
+-#define __NR_ioprio_set		316
+-#define __NR_ioprio_get		317
+-#define __NR_inotify_init	318
+-#define __NR_inotify_add_watch	319
+-#define __NR_inotify_rm_watch	320
+-/* 321 is unused */
+-#define __NR_migrate_pages	322
+-#define __NR_openat		323
+-#define __NR_mkdirat		324
+-#define __NR_mknodat		325
+-#define __NR_fchownat		326
+-#define __NR_futimesat		327
+-#define __NR_fstatat64		328
+-#define __NR_unlinkat		329
+-#define __NR_renameat		330
+-#define __NR_linkat		331
+-#define __NR_symlinkat		332
+-#define __NR_readlinkat		333
+-#define __NR_fchmodat		334
+-#define __NR_faccessat		335
+-#define __NR_pselect6		336
+-#define __NR_ppoll		337
+-#define __NR_unshare		338
+-#define __NR_set_robust_list	339
+-#define __NR_get_robust_list	340
+-#define __NR_splice		341
+-#define __NR_sync_file_range	342
+-#define __NR_tee		343
+-#define __NR_vmsplice		344
+-#define __NR_move_pages		345
+-#define __NR_getcpu		346
+-#define __NR_epoll_pwait	347
+-#define __NR_utimensat		348
+-#define __NR_signalfd		349
+-#define __NR_timerfd		350
+-#define __NR_eventfd		351
+-#define __NR_fallocate		352
+-
+-#ifdef __KERNEL__
+-
+-#define NR_syscalls 353
+-
+-#define __ARCH_WANT_IPC_PARSE_VERSION
+-#define __ARCH_WANT_OLD_READDIR
+-#define __ARCH_WANT_OLD_STAT
+-#define __ARCH_WANT_STAT64
+-#define __ARCH_WANT_SYS_ALARM
+-#define __ARCH_WANT_SYS_GETHOSTNAME
+-#define __ARCH_WANT_SYS_PAUSE
+-#define __ARCH_WANT_SYS_SGETMASK
+-#define __ARCH_WANT_SYS_SIGNAL
+-#define __ARCH_WANT_SYS_TIME
+-#define __ARCH_WANT_SYS_UTIME
+-#define __ARCH_WANT_SYS_WAITPID
+-#define __ARCH_WANT_SYS_SOCKETCALL
+-#define __ARCH_WANT_SYS_FADVISE64
+-#define __ARCH_WANT_SYS_GETPGRP
+-#define __ARCH_WANT_SYS_LLSEEK
+-#define __ARCH_WANT_SYS_NICE
+-#define __ARCH_WANT_SYS_OLD_GETRLIMIT
+-#define __ARCH_WANT_SYS_OLDUMOUNT
+-#define __ARCH_WANT_SYS_SIGPENDING
+-#define __ARCH_WANT_SYS_SIGPROCMASK
+-#define __ARCH_WANT_SYS_RT_SIGACTION
 -
 -/*
-- * We need some free virtual space to be able to do vmalloc.
-- * VMALLOC_MIN_SIZE defines the minimum size of the vmalloc
-- * area. On a machine with 2GB memory we make sure that we
-- * have at least 128MB free space for vmalloc. On a machine
-- * with 4TB we make sure we have at least 128GB.
-+ * The vmalloc area will always be on the topmost area of the kernel
-+ * mapping. We reserve 96MB (31bit) / 1GB (64bit) for vmalloc,
-+ * which should be enough for any sane case.
-+ * By putting vmalloc at the top, we maximise the gap between physical
-+ * memory and vmalloc to catch misplaced memory accesses. As a side
-+ * effect, this also makes sure that 64 bit module code cannot be used
-+ * as system call address.
-  */
- #ifndef __s390x__
--#define VMALLOC_MIN_SIZE	0x8000000UL
--#define VMALLOC_END_INIT	0x80000000UL
-+#define VMALLOC_START	0x78000000UL
-+#define VMALLOC_END	0x7e000000UL
-+#define VMEM_MAP_MAX	0x80000000UL
- #else /* __s390x__ */
--#define VMALLOC_MIN_SIZE	0x2000000000UL
--#define VMALLOC_END_INIT	0x40000000000UL
-+#define VMALLOC_START	0x3e000000000UL
-+#define VMALLOC_END	0x3e040000000UL
-+#define VMEM_MAP_MAX	0x40000000000UL
- #endif /* __s390x__ */
- 
-+#define VMEM_MAP	((struct page *) VMALLOC_END)
-+#define VMEM_MAP_SIZE	((VMALLOC_START / PAGE_SIZE) * sizeof(struct page))
-+
- /*
-  * A 31 bit pagetable entry of S390 has following format:
-  *  |   PFRA          |    |  OS  |
-diff --git a/include/asm-s390/processor.h b/include/asm-s390/processor.h
-index 21d40a1..c86b982 100644
---- a/include/asm-s390/processor.h
-+++ b/include/asm-s390/processor.h
-@@ -59,9 +59,6 @@ extern void s390_adjust_jiffies(void);
- extern void print_cpu_info(struct cpuinfo_S390 *);
- extern int get_cpu_capability(unsigned int *);
- 
--/* Lazy FPU handling on uni-processor */
--extern struct task_struct *last_task_used_math;
+- * "Conditional" syscalls
+- *
+- * What we want is __attribute__((weak,alias("sys_ni_syscall"))),
+- * but it doesn't work on all toolchains, so we just do it by hand
+- */
+-#ifndef cond_syscall
+-#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall")
+-#endif
 -
- /*
-  * User space process size: 2GB for 31 bit, 4TB for 64 bit.
-  */
-@@ -95,7 +92,6 @@ struct thread_struct {
-         unsigned long ksp;              /* kernel stack pointer             */
- 	mm_segment_t mm_segment;
-         unsigned long prot_addr;        /* address of protection-excep.     */
--        unsigned int error_code;        /* error-code of last prog-excep.   */
-         unsigned int trap_no;
-         per_struct per_info;
- 	/* Used to give failing instruction back to user for ieee exceptions */
-diff --git a/include/asm-s390/ptrace.h b/include/asm-s390/ptrace.h
-index 332ee73..61f6952 100644
---- a/include/asm-s390/ptrace.h
-+++ b/include/asm-s390/ptrace.h
-@@ -465,6 +465,14 @@ struct user_regs_struct
- #ifdef __KERNEL__
- #define __ARCH_SYS_PTRACE	1
- 
-+/*
-+ * These are defined as per linux/ptrace.h, which see.
-+ */
-+#define arch_has_single_step()	(1)
-+struct task_struct;
-+extern void user_enable_single_step(struct task_struct *);
-+extern void user_disable_single_step(struct task_struct *);
-+
- #define user_mode(regs) (((regs)->psw.mask & PSW_MASK_PSTATE) != 0)
- #define instruction_pointer(regs) ((regs)->psw.addr & PSW_ADDR_INSN)
- #define regs_return_value(regs)((regs)->gprs[2])
-diff --git a/include/asm-s390/qdio.h b/include/asm-s390/qdio.h
-index 74db1dc..4b8ff55 100644
---- a/include/asm-s390/qdio.h
-+++ b/include/asm-s390/qdio.h
-@@ -184,7 +184,7 @@ struct qdr {
- #endif /* QDIO_32_BIT */
- 	unsigned long qiba;             /* queue-information-block address */
- 	unsigned int  res8;             /* reserved */
--	unsigned int  qkey    :  4;     /* queue-informatio-block key */
-+	unsigned int  qkey    :  4;	/* queue-information-block key */
- 	unsigned int  res9    : 28;     /* reserved */
- /*	union _qd {*/ /* why this? */
- 		struct qdesfmt0 qdf0[126];
-diff --git a/include/asm-s390/rwsem.h b/include/asm-s390/rwsem.h
-index 90f4ecc..9d2a179 100644
---- a/include/asm-s390/rwsem.h
-+++ b/include/asm-s390/rwsem.h
-@@ -91,8 +91,8 @@ struct rw_semaphore {
- #endif
- 
- #define __RWSEM_INITIALIZER(name) \
--{ RWSEM_UNLOCKED_VALUE, SPIN_LOCK_UNLOCKED, LIST_HEAD_INIT((name).wait_list) \
--  __RWSEM_DEP_MAP_INIT(name) }
-+ { RWSEM_UNLOCKED_VALUE, __SPIN_LOCK_UNLOCKED((name).wait.lock), \
-+   LIST_HEAD_INIT((name).wait_list) __RWSEM_DEP_MAP_INIT(name) }
- 
- #define DECLARE_RWSEM(name) \
- 	struct rw_semaphore name = __RWSEM_INITIALIZER(name)
-diff --git a/include/asm-s390/sclp.h b/include/asm-s390/sclp.h
-index cb9faf1..b5f2843 100644
---- a/include/asm-s390/sclp.h
-+++ b/include/asm-s390/sclp.h
-@@ -27,7 +27,25 @@ struct sclp_ipl_info {
- 	char loadparm[LOADPARM_LEN];
- };
- 
--void sclp_readinfo_early(void);
-+struct sclp_cpu_entry {
-+	u8 address;
-+	u8 reserved0[13];
-+	u8 type;
-+	u8 reserved1;
-+} __attribute__((packed));
-+
-+struct sclp_cpu_info {
-+	unsigned int configured;
-+	unsigned int standby;
-+	unsigned int combined;
-+	int has_cpu_type;
-+	struct sclp_cpu_entry cpu[255];
-+};
-+
-+int sclp_get_cpu_info(struct sclp_cpu_info *info);
-+int sclp_cpu_configure(u8 cpu);
-+int sclp_cpu_deconfigure(u8 cpu);
-+void sclp_read_info_early(void);
- void sclp_facilities_detect(void);
- unsigned long long sclp_memory_detect(void);
- int sclp_sdias_blk_count(void);
-diff --git a/include/asm-s390/smp.h b/include/asm-s390/smp.h
-index 07708c0..c7b7432 100644
---- a/include/asm-s390/smp.h
-+++ b/include/asm-s390/smp.h
-@@ -35,8 +35,6 @@ extern void machine_restart_smp(char *);
- extern void machine_halt_smp(void);
- extern void machine_power_off_smp(void);
- 
--extern void smp_setup_cpu_possible_map(void);
+-#endif /* __KERNEL__ */
+-#endif /* __ASM_SH64_UNISTD_H */
+diff --git a/include/asm-sh64/user.h b/include/asm-sh64/user.h
+deleted file mode 100644
+index eb3b33e..0000000
+--- a/include/asm-sh64/user.h
++++ /dev/null
+@@ -1,70 +0,0 @@
+-#ifndef __ASM_SH64_USER_H
+-#define __ASM_SH64_USER_H
 -
- #define NO_PROC_ID		0xFF		/* No processor magic marker */
- 
- /*
-@@ -92,6 +90,8 @@ extern void __cpu_die (unsigned int cpu);
- extern void cpu_die (void) __attribute__ ((noreturn));
- extern int __cpu_up (unsigned int cpu);
- 
-+extern int smp_call_function_mask(cpumask_t mask, void (*func)(void *),
-+	void *info, int wait);
- #endif
- 
- #ifndef CONFIG_SMP
-@@ -103,7 +103,6 @@ static inline void smp_send_stop(void)
- 
- #define hard_smp_processor_id()		0
- #define smp_cpu_not_running(cpu)	1
--#define smp_setup_cpu_possible_map()	do { } while (0)
- #endif
- 
- extern union save_area *zfcpdump_save_areas[NR_CPUS + 1];
-diff --git a/include/asm-s390/spinlock.h b/include/asm-s390/spinlock.h
-index 3fd4382..df84ae9 100644
---- a/include/asm-s390/spinlock.h
-+++ b/include/asm-s390/spinlock.h
-@@ -53,44 +53,48 @@ _raw_compare_and_swap(volatile unsigned int *lock,
-  */
- 
- #define __raw_spin_is_locked(x) ((x)->owner_cpu != 0)
--#define __raw_spin_lock_flags(lock, flags) __raw_spin_lock(lock)
- #define __raw_spin_unlock_wait(lock) \
- 	do { while (__raw_spin_is_locked(lock)) \
- 		 _raw_spin_relax(lock); } while (0)
- 
--extern void _raw_spin_lock_wait(raw_spinlock_t *, unsigned int pc);
--extern int _raw_spin_trylock_retry(raw_spinlock_t *, unsigned int pc);
-+extern void _raw_spin_lock_wait(raw_spinlock_t *);
-+extern void _raw_spin_lock_wait_flags(raw_spinlock_t *, unsigned long flags);
-+extern int _raw_spin_trylock_retry(raw_spinlock_t *);
- extern void _raw_spin_relax(raw_spinlock_t *lock);
- 
- static inline void __raw_spin_lock(raw_spinlock_t *lp)
- {
--	unsigned long pc = 1 | (unsigned long) __builtin_return_address(0);
- 	int old;
- 
- 	old = _raw_compare_and_swap(&lp->owner_cpu, 0, ~smp_processor_id());
--	if (likely(old == 0)) {
--		lp->owner_pc = pc;
-+	if (likely(old == 0))
- 		return;
--	}
--	_raw_spin_lock_wait(lp, pc);
-+	_raw_spin_lock_wait(lp);
-+}
-+
-+static inline void __raw_spin_lock_flags(raw_spinlock_t *lp,
-+					 unsigned long flags)
-+{
-+	int old;
-+
-+	old = _raw_compare_and_swap(&lp->owner_cpu, 0, ~smp_processor_id());
-+	if (likely(old == 0))
-+		return;
-+	_raw_spin_lock_wait_flags(lp, flags);
- }
- 
- static inline int __raw_spin_trylock(raw_spinlock_t *lp)
- {
--	unsigned long pc = 1 | (unsigned long) __builtin_return_address(0);
- 	int old;
- 
- 	old = _raw_compare_and_swap(&lp->owner_cpu, 0, ~smp_processor_id());
--	if (likely(old == 0)) {
--		lp->owner_pc = pc;
-+	if (likely(old == 0))
- 		return 1;
--	}
--	return _raw_spin_trylock_retry(lp, pc);
-+	return _raw_spin_trylock_retry(lp);
- }
- 
- static inline void __raw_spin_unlock(raw_spinlock_t *lp)
- {
--	lp->owner_pc = 0;
- 	_raw_compare_and_swap(&lp->owner_cpu, lp->owner_cpu, 0);
- }
- 		
-diff --git a/include/asm-s390/spinlock_types.h b/include/asm-s390/spinlock_types.h
-index b7ac13f..654abc4 100644
---- a/include/asm-s390/spinlock_types.h
-+++ b/include/asm-s390/spinlock_types.h
-@@ -7,7 +7,6 @@
- 
- typedef struct {
- 	volatile unsigned int owner_cpu;
--	volatile unsigned int owner_pc;
- } __attribute__ ((aligned (4))) raw_spinlock_t;
- 
- #define __RAW_SPIN_LOCK_UNLOCKED	{ 0 }
-diff --git a/include/asm-s390/tlbflush.h b/include/asm-s390/tlbflush.h
-index a69bd24..70fa5ae 100644
---- a/include/asm-s390/tlbflush.h
-+++ b/include/asm-s390/tlbflush.h
-@@ -42,11 +42,11 @@ static inline void __tlb_flush_global(void)
- /*
-  * Flush all tlb entries of a page table on all cpus.
-  */
--static inline void __tlb_flush_idte(pgd_t *pgd)
-+static inline void __tlb_flush_idte(unsigned long asce)
- {
- 	asm volatile(
- 		"	.insn	rrf,0xb98e0000,0,%0,%1,0"
--		: : "a" (2048), "a" (__pa(pgd) & PAGE_MASK) : "cc" );
-+		: : "a" (2048), "a" (asce) : "cc" );
- }
- 
- static inline void __tlb_flush_mm(struct mm_struct * mm)
-@@ -61,11 +61,11 @@ static inline void __tlb_flush_mm(struct mm_struct * mm)
- 	 * only ran on the local cpu.
- 	 */
- 	if (MACHINE_HAS_IDTE) {
--		pgd_t *shadow_pgd = get_shadow_table(mm->pgd);
-+		pgd_t *shadow = get_shadow_table(mm->pgd);
- 
--		if (shadow_pgd)
--			__tlb_flush_idte(shadow_pgd);
--		__tlb_flush_idte(mm->pgd);
-+		if (shadow)
-+			__tlb_flush_idte((unsigned long) shadow | mm->context);
-+		__tlb_flush_idte((unsigned long) mm->pgd | mm->context);
- 		return;
- 	}
- 	preempt_disable();
-@@ -106,9 +106,23 @@ static inline void __tlb_flush_mm_cond(struct mm_struct * mm)
-  */
- #define flush_tlb()				do { } while (0)
- #define flush_tlb_all()				do { } while (0)
--#define flush_tlb_mm(mm)			__tlb_flush_mm_cond(mm)
- #define flush_tlb_page(vma, addr)		do { } while (0)
--#define flush_tlb_range(vma, start, end)	__tlb_flush_mm_cond(mm)
--#define flush_tlb_kernel_range(start, end)	__tlb_flush_mm(&init_mm)
-+
-+static inline void flush_tlb_mm(struct mm_struct *mm)
-+{
-+	__tlb_flush_mm_cond(mm);
-+}
-+
-+static inline void flush_tlb_range(struct vm_area_struct *vma,
-+				   unsigned long start, unsigned long end)
-+{
-+	__tlb_flush_mm_cond(vma->vm_mm);
-+}
-+
-+static inline void flush_tlb_kernel_range(unsigned long start,
-+					  unsigned long end)
-+{
-+	__tlb_flush_mm(&init_mm);
-+}
- 
- #endif /* _S390_TLBFLUSH_H */
-diff --git a/include/asm-s390/zcrypt.h b/include/asm-s390/zcrypt.h
-index a5dada6..f228f1b 100644
---- a/include/asm-s390/zcrypt.h
-+++ b/include/asm-s390/zcrypt.h
-@@ -117,7 +117,7 @@ struct CPRBX {
- 	unsigned char	padx004[16 - sizeof (char *)];
- 	unsigned char *	req_extb;	/* request extension block 'addr'*/
- 	unsigned char	padx005[16 - sizeof (char *)];
--	unsigned char *	rpl_extb;	/* reply extension block 'addres'*/
-+	unsigned char *	rpl_extb;	/* reply extension block 'address'*/
- 	unsigned short	ccp_rtcode;	/* server return code		 */
- 	unsigned short	ccp_rscode;	/* server reason code		 */
- 	unsigned int	mac_data_len;	/* Mac Data Length		 */
+-/*
+- * 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/asm-sh64/user.h
+- *
+- * Copyright (C) 2000, 2001  Paolo Alberelli
+- *
+- */
+-
+-#include <linux/types.h>
+-#include <asm/ptrace.h>
+-#include <asm/page.h>
+-
+-/*
+- * Core file format: The core file is written in such a way that gdb
+- * can understand it and provide useful information to the user (under
+- * linux we use the `trad-core' bfd).  The file contents are as follows:
+- *
+- *  upage: 1 page consisting of a user struct that tells gdb
+- *	what is present in the file.  Directly after this is a
+- *	copy of the task_struct, which is currently not used by gdb,
+- *	but it may come in handy at some point.  All of the registers
+- *	are stored as part of the upage.  The upage should always be
+- *	only one page long.
+- *  data: The data segment follows next.  We use current->end_text to
+- *	current->brk to pick up all of the user variables, plus any memory
+- *	that may have been sbrk'ed.  No attempt is made to determine if a
+- *	page is demand-zero or if a page is totally unused, we just cover
+- *	the entire range.  All of the addresses are rounded in such a way
+- *	that an integral number of pages is written.
+- *  stack: We need the stack information in order to get a meaningful
+- *	backtrace.  We need to write the data from usp to
+- *	current->start_stack, so we round each of these in order to be able
+- *	to write an integer number of pages.
+- */
+-
+-struct user_fpu_struct {
+-        unsigned long long fp_regs[32];
+-	unsigned int fpscr;
+-};
+-
+-struct user {
+-	struct pt_regs	regs;			/* entire machine state */
+-	struct user_fpu_struct fpu;	/* Math Co-processor registers  */
+-	int u_fpvalid;		/* True if math co-processor being used */
+-	size_t		u_tsize;		/* text size (pages) */
+-	size_t		u_dsize;		/* data size (pages) */
+-	size_t		u_ssize;		/* stack size (pages) */
+-	unsigned long	start_code;		/* text starting address */
+-	unsigned long	start_data;		/* data starting address */
+-	unsigned long	start_stack;		/* stack starting address */
+-	long int	signal;			/* signal causing core dump */
+-	struct regs *	u_ar0;			/* help gdb find registers */
+-	struct user_fpu_struct* u_fpstate;	/* Math Co-processor pointer */
+-	unsigned long	magic;			/* identifies a core file */
+-	char		u_comm[32];		/* user command name */
+-};
+-
+-#define NBPG			PAGE_SIZE
+-#define UPAGES			1
+-#define HOST_TEXT_START_ADDR	(u.start_code)
+-#define HOST_DATA_START_ADDR	(u.start_data)
+-#define HOST_STACK_END_ADDR	(u.start_stack + u.u_ssize * NBPG)
+-
+-#endif /* __ASM_SH64_USER_H */
 diff --git a/include/asm-x86/thread_info_32.h b/include/asm-x86/thread_info_32.h
 index 22a8cbc..ef58fd2 100644
 --- a/include/asm-x86/thread_info_32.h
@@ -208250,10 +327910,96 @@
  	int (*match)(struct attribute_container *, struct device *);
  #define	ATTRIBUTE_CONTAINER_NO_CLASSDEVS	0x01
 diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
-index d18ee67..49b7a4c 100644
+index d18ee67..71e7a84 100644
 --- a/include/linux/blkdev.h
 +++ b/include/linux/blkdev.h
-@@ -143,8 +143,6 @@ enum rq_cmd_type_bits {
+@@ -34,83 +34,10 @@ struct sg_io_hdr;
+ #define BLKDEV_MIN_RQ	4
+ #define BLKDEV_MAX_RQ	128	/* Default maximum */
+ 
+-/*
+- * This is the per-process anticipatory I/O scheduler state.
+- */
+-struct as_io_context {
+-	spinlock_t lock;
+-
+-	void (*dtor)(struct as_io_context *aic); /* destructor */
+-	void (*exit)(struct as_io_context *aic); /* called on task exit */
+-
+-	unsigned long state;
+-	atomic_t nr_queued; /* queued reads & sync writes */
+-	atomic_t nr_dispatched; /* number of requests gone to the drivers */
+-
+-	/* IO History tracking */
+-	/* Thinktime */
+-	unsigned long last_end_request;
+-	unsigned long ttime_total;
+-	unsigned long ttime_samples;
+-	unsigned long ttime_mean;
+-	/* Layout pattern */
+-	unsigned int seek_samples;
+-	sector_t last_request_pos;
+-	u64 seek_total;
+-	sector_t seek_mean;
+-};
+-
+-struct cfq_queue;
+-struct cfq_io_context {
+-	struct rb_node rb_node;
+-	void *key;
+-
+-	struct cfq_queue *cfqq[2];
+-
+-	struct io_context *ioc;
+-
+-	unsigned long last_end_request;
+-	sector_t last_request_pos;
+-
+-	unsigned long ttime_total;
+-	unsigned long ttime_samples;
+-	unsigned long ttime_mean;
+-
+-	unsigned int seek_samples;
+-	u64 seek_total;
+-	sector_t seek_mean;
+-
+-	struct list_head queue_list;
+-
+-	void (*dtor)(struct io_context *); /* destructor */
+-	void (*exit)(struct io_context *); /* called on task exit */
+-};
+-
+-/*
+- * This is the per-process I/O subsystem state.  It is refcounted and
+- * kmalloc'ed. Currently all fields are modified in process io context
+- * (apart from the atomic refcount), so require no locking.
+- */
+-struct io_context {
+-	atomic_t refcount;
+-	struct task_struct *task;
+-
+-	unsigned int ioprio_changed;
+-
+-	/*
+-	 * For request batching
+-	 */
+-	unsigned long last_waited; /* Time last woken after wait for request */
+-	int nr_batch_requests;     /* Number of requests left in the batch */
+-
+-	struct as_io_context *aic;
+-	struct rb_root cic_root;
+-	void *ioc_data;
+-};
+-
+-void put_io_context(struct io_context *ioc);
++int put_io_context(struct io_context *ioc);
+ void exit_io_context(void);
+ struct io_context *get_io_context(gfp_t gfp_flags, int node);
++struct io_context *alloc_io_context(gfp_t gfp_flags, int node);
+ void copy_io_context(struct io_context **pdst, struct io_context **psrc);
+ void swap_io_context(struct io_context **ioc1, struct io_context **ioc2);
+ 
+@@ -143,8 +70,6 @@ enum rq_cmd_type_bits {
  	 * use REQ_TYPE_SPECIAL and use rq->cmd[0] with the range of driver
  	 * private REQ_LB opcodes to differentiate what type of request this is
  	 */
@@ -208262,7 +328008,77 @@
  	REQ_TYPE_ATA_TASKFILE,
  	REQ_TYPE_ATA_PC,
  };
-@@ -766,6 +764,7 @@ extern void blk_queue_segment_boundary(struct request_queue *, unsigned long);
+@@ -431,6 +356,8 @@ struct request_queue
+ 	unsigned int		max_segment_size;
+ 
+ 	unsigned long		seg_boundary_mask;
++	void			*dma_drain_buffer;
++	unsigned int		dma_drain_size;
+ 	unsigned int		dma_alignment;
+ 
+ 	struct blk_queue_tag	*queue_tags;
+@@ -539,6 +466,8 @@ enum {
+ #define blk_fua_rq(rq)		((rq)->cmd_flags & REQ_FUA)
+ #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() */
++#define blk_queued_rq(rq)	(!list_empty(&(rq)->queuelist))
+ 
+ #define list_entry_rq(ptr)	list_entry((ptr), struct request, queuelist)
+ 
+@@ -718,29 +647,32 @@ static inline void blk_run_address_space(struct address_space *mapping)
+ }
+ 
+ /*
+- * end_request() and friends. Must be called with the request queue spinlock
+- * acquired. All functions called within end_request() _must_be_ atomic.
++ * blk_end_request() and friends.
++ * __blk_end_request() and end_request() must be called with
++ * the request queue spinlock acquired.
+  *
+  * Several drivers define their own end_request and call
+- * end_that_request_first() and end_that_request_last()
+- * for parts of the original function. This prevents
+- * code duplication in drivers.
++ * blk_end_request() for parts of the original function.
++ * This prevents code duplication in drivers.
+  */
+-extern int end_that_request_first(struct request *, int, int);
+-extern int end_that_request_chunk(struct request *, int, int);
+-extern void end_that_request_last(struct request *, int);
++extern int blk_end_request(struct request *rq, int error, int nr_bytes);
++extern int __blk_end_request(struct request *rq, int error, int nr_bytes);
++extern int blk_end_bidi_request(struct request *rq, int error, int nr_bytes,
++				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, int nr_bytes,
++				    int (drv_callback)(struct request *));
+ extern void blk_complete_request(struct request *);
+ 
+ /*
+- * end_that_request_first/chunk() takes an uptodate argument. we account
+- * any value <= as an io error. 0 means -EIO for compatability reasons,
+- * any other < 0 value is the direct error type. An uptodate value of
+- * 1 indicates successful io completion
++ * blk_end_request() takes bytes instead of sectors as a complete size.
++ * blk_rq_bytes() returns bytes left to complete in the entire request.
++ * blk_rq_cur_bytes() returns bytes left to complete in the current segment.
+  */
+-#define end_io_error(uptodate)	(unlikely((uptodate) <= 0))
++extern unsigned int blk_rq_bytes(struct request *rq);
++extern unsigned int blk_rq_cur_bytes(struct request *rq);
+ 
+ static inline void blkdev_dequeue_request(struct request *req)
+ {
+@@ -762,10 +694,13 @@ extern void blk_queue_max_hw_segments(struct request_queue *, unsigned short);
+ extern void blk_queue_max_segment_size(struct request_queue *, unsigned int);
+ extern void blk_queue_hardsect_size(struct request_queue *, unsigned short);
+ extern void blk_queue_stack_limits(struct request_queue *t, struct request_queue *b);
++extern int blk_queue_dma_drain(struct request_queue *q, void *buf,
++			       unsigned int size);
+ 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);
@@ -208270,6 +328086,70 @@
  extern void blk_queue_softirq_done(struct request_queue *, softirq_done_fn *);
  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 *);
+@@ -837,12 +772,7 @@ static inline int bdev_hardsect_size(struct block_device *bdev)
+ 
+ static inline int queue_dma_alignment(struct request_queue *q)
+ {
+-	int retval = 511;
+-
+-	if (q && q->dma_alignment)
+-		retval = q->dma_alignment;
+-
+-	return retval;
++	return q ? q->dma_alignment : 511;
+ }
+ 
+ /* assumes size > 256 */
+@@ -895,6 +825,12 @@ static inline void exit_io_context(void)
+ {
+ }
+ 
++static inline int put_io_context(struct io_context *ioc)
++{
++	return 1;
++}
++
++
+ #endif /* CONFIG_BLOCK */
+ 
+ #endif
+diff --git a/include/linux/blktrace_api.h b/include/linux/blktrace_api.h
+index 7e11d23..06dadba 100644
+--- a/include/linux/blktrace_api.h
++++ b/include/linux/blktrace_api.h
+@@ -148,7 +148,7 @@ 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 *);
+ extern int do_blk_trace_setup(struct request_queue *q,
+-	struct block_device *bdev, struct blk_user_trace_setup *buts);
++	char *name, dev_t dev, struct blk_user_trace_setup *buts);
+ 
+ 
+ /**
+@@ -282,6 +282,11 @@ static inline void blk_add_trace_remap(struct request_queue *q, struct bio *bio,
+ 	__blk_add_trace(bt, from, bio->bi_size, bio->bi_rw, BLK_TA_REMAP, !bio_flagged(bio, BIO_UPTODATE), sizeof(r), &r);
+ }
+ 
++extern int blk_trace_setup(request_queue_t *q, char *name, dev_t dev,
++			   char __user *arg);
++extern int blk_trace_startstop(request_queue_t *q, int start);
++extern int blk_trace_remove(request_queue_t *q);
++
+ #else /* !CONFIG_BLK_DEV_IO_TRACE */
+ #define blk_trace_ioctl(bdev, cmd, arg)		(-ENOTTY)
+ #define blk_trace_shutdown(q)			do { } while (0)
+@@ -290,7 +295,10 @@ static inline void blk_add_trace_remap(struct request_queue *q, struct bio *bio,
+ #define blk_add_trace_generic(q, rq, rw, what)	do { } while (0)
+ #define blk_add_trace_pdu_int(q, what, bio, pdu)	do { } while (0)
+ #define blk_add_trace_remap(q, bio, dev, f, t)	do {} while (0)
+-#define do_blk_trace_setup(q, bdev, buts)	(-ENOTTY)
++#define do_blk_trace_setup(q, name, dev, buts)	(-ENOTTY)
++#define blk_trace_setup(q, name, dev, arg)	(-ENOTTY)
++#define blk_trace_startstop(q, start)		(-ENOTTY)
++#define blk_trace_remove(q)			(-ENOTTY)
+ #endif /* CONFIG_BLK_DEV_IO_TRACE */
+ #endif /* __KERNEL__ */
+ #endif
 diff --git a/include/linux/cdrom.h b/include/linux/cdrom.h
 index c6d3e22..fcdc11b 100644
 --- a/include/linux/cdrom.h
@@ -209880,6 +329760,71 @@
  
  /* ATA/ATAPI Commands pre T13 Spec */
  #define WIN_NOP				0x00
+diff --git a/include/linux/hid.h b/include/linux/hid.h
+index 6e35b92..3902690 100644
+--- a/include/linux/hid.h
++++ b/include/linux/hid.h
+@@ -267,10 +267,10 @@ struct hid_item {
+ #define HID_QUIRK_2WHEEL_MOUSE_HACK_5		0x00000100
+ #define HID_QUIRK_2WHEEL_MOUSE_HACK_ON		0x00000200
+ #define HID_QUIRK_MIGHTYMOUSE			0x00000400
+-#define HID_QUIRK_POWERBOOK_HAS_FN		0x00000800
+-#define HID_QUIRK_POWERBOOK_FN_ON		0x00001000
++#define HID_QUIRK_APPLE_HAS_FN			0x00000800
++#define HID_QUIRK_APPLE_FN_ON			0x00001000
+ #define HID_QUIRK_INVERT_HWHEEL			0x00002000
+-#define HID_QUIRK_POWERBOOK_ISO_KEYBOARD        0x00004000
++#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
+@@ -281,6 +281,9 @@ struct hid_item {
+ #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
+ 
+ /*
+  * Separate quirks for runtime report descriptor fixup
+@@ -291,6 +294,8 @@ struct hid_item {
+ #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
+ 
+ /*
+  * This is the global environment of the parser. This information is
+@@ -456,6 +461,8 @@ struct hid_device {							/* device report descriptor */
+ 
+ 	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 *);
+@@ -469,7 +476,7 @@ struct hid_device {							/* device report descriptor */
+ 	/* 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 pb_pressed_fn[BITS_TO_LONGS(KEY_CNT)];
++	unsigned long apple_pressed_fn[BITS_TO_LONGS(KEY_CNT)];
+ 	unsigned long pb_pressed_numlock[BITS_TO_LONGS(KEY_CNT)];
+ #endif
+ };
+@@ -520,6 +527,9 @@ 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 *);
++void 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_input_field(struct hid_device *hid, struct hid_field *field, __u8 *data, int interrupt);
+ void hid_output_report(struct hid_report *report, __u8 *data);
+ void hid_free_device(struct hid_device *device);
 diff --git a/include/linux/hrtimer.h b/include/linux/hrtimer.h
 index 7a9398e..49067f1 100644
 --- a/include/linux/hrtimer.h
@@ -211150,21 +331095,21 @@
 +
  #endif /* _IDE_H */
 diff --git a/include/linux/init_task.h b/include/linux/init_task.h
-index cae35b6..796019b 100644
+index cae35b6..e6b3f70 100644
 --- a/include/linux/init_task.h
 +++ b/include/linux/init_task.h
-@@ -132,9 +132,12 @@ extern struct group_info init_groups;
+@@ -132,9 +132,11 @@ extern struct group_info init_groups;
  	.cpus_allowed	= CPU_MASK_ALL,					\
  	.mm		= NULL,						\
  	.active_mm	= &init_mm,					\
 -	.run_list	= LIST_HEAD_INIT(tsk.run_list),			\
+-	.ioprio		= 0,						\
+-	.time_slice	= HZ,						\
 +	.rt		= {						\
 +		.run_list	= LIST_HEAD_INIT(tsk.rt.run_list),	\
 +		.time_slice	= HZ, 					\
 +		.nr_cpus_allowed = NR_CPUS,				\
 +	},								\
- 	.ioprio		= 0,						\
--	.time_slice	= HZ,						\
  	.tasks		= LIST_HEAD_INIT(tsk.tasks),			\
  	.ptrace_children= LIST_HEAD_INIT(tsk.ptrace_children),		\
  	.ptrace_list	= LIST_HEAD_INIT(tsk.ptrace_list),		\
@@ -211180,6 +331125,144 @@
  };
  
  /* softirq mask and active fields moved to irq_cpustat_t in
+diff --git a/include/linux/iocontext.h b/include/linux/iocontext.h
+new file mode 100644
+index 0000000..593b222
+--- /dev/null
++++ b/include/linux/iocontext.h
+@@ -0,0 +1,95 @@
++#ifndef IOCONTEXT_H
++#define IOCONTEXT_H
++
++#include <linux/radix-tree.h>
++
++/*
++ * This is the per-process anticipatory I/O scheduler state.
++ */
++struct as_io_context {
++	spinlock_t lock;
++
++	void (*dtor)(struct as_io_context *aic); /* destructor */
++	void (*exit)(struct as_io_context *aic); /* called on task exit */
++
++	unsigned long state;
++	atomic_t nr_queued; /* queued reads & sync writes */
++	atomic_t nr_dispatched; /* number of requests gone to the drivers */
++
++	/* IO History tracking */
++	/* Thinktime */
++	unsigned long last_end_request;
++	unsigned long ttime_total;
++	unsigned long ttime_samples;
++	unsigned long ttime_mean;
++	/* Layout pattern */
++	unsigned int seek_samples;
++	sector_t last_request_pos;
++	u64 seek_total;
++	sector_t seek_mean;
++};
++
++struct cfq_queue;
++struct cfq_io_context {
++	void *key;
++	unsigned long dead_key;
++
++	struct cfq_queue *cfqq[2];
++
++	struct io_context *ioc;
++
++	unsigned long last_end_request;
++	sector_t last_request_pos;
++
++	unsigned long ttime_total;
++	unsigned long ttime_samples;
++	unsigned long ttime_mean;
++
++	unsigned int seek_samples;
++	u64 seek_total;
++	sector_t seek_mean;
++
++	struct list_head queue_list;
++
++	void (*dtor)(struct io_context *); /* destructor */
++	void (*exit)(struct io_context *); /* called on task exit */
++};
++
++/*
++ * I/O subsystem state of the associated processes.  It is refcounted
++ * and kmalloc'ed. These could be shared between processes.
++ */
++struct io_context {
++	atomic_t refcount;
++	atomic_t nr_tasks;
++
++	/* all the fields below are protected by this lock */
++	spinlock_t lock;
++
++	unsigned short ioprio;
++	unsigned short ioprio_changed;
++
++	/*
++	 * For request batching
++	 */
++	unsigned long last_waited; /* Time last woken after wait for request */
++	int nr_batch_requests;     /* Number of requests left in the batch */
++
++	struct as_io_context *aic;
++	struct radix_tree_root radix_root;
++	void *ioc_data;
++};
++
++static inline struct io_context *ioc_task_link(struct io_context *ioc)
++{
++	/*
++	 * if ref count is zero, don't allow sharing (ioc is going away, it's
++	 * a race).
++	 */
++	if (ioc && atomic_inc_not_zero(&ioc->refcount))
++		return ioc;
++
++	return NULL;
++}
++
++#endif
+diff --git a/include/linux/ioprio.h b/include/linux/ioprio.h
+index baf2938..2a3bb1b 100644
+--- a/include/linux/ioprio.h
++++ b/include/linux/ioprio.h
+@@ -2,6 +2,7 @@
+ #define IOPRIO_H
+ 
+ #include <linux/sched.h>
++#include <linux/iocontext.h>
+ 
+ /*
+  * Gives us 8 prio classes with 13-bits of data for each class
+@@ -45,18 +46,18 @@ enum {
+  * the cpu scheduler nice value to an io priority
+  */
+ #define IOPRIO_NORM	(4)
+-static inline int task_ioprio(struct task_struct *task)
++static inline int task_ioprio(struct io_context *ioc)
+ {
+-	if (ioprio_valid(task->ioprio))
+-		return IOPRIO_PRIO_DATA(task->ioprio);
++	if (ioprio_valid(ioc->ioprio))
++		return IOPRIO_PRIO_DATA(ioc->ioprio);
+ 
+ 	return IOPRIO_NORM;
+ }
+ 
+-static inline int task_ioprio_class(struct task_struct *task)
++static inline int task_ioprio_class(struct io_context *ioc)
+ {
+-	if (ioprio_valid(task->ioprio))
+-		return IOPRIO_PRIO_CLASS(task->ioprio);
++	if (ioprio_valid(ioc->ioprio))
++		return IOPRIO_PRIO_CLASS(ioc->ioprio);
+ 
+ 	return IOPRIO_CLASS_BE;
+ }
 diff --git a/include/linux/jiffies.h b/include/linux/jiffies.h
 index 8b08002..7ba9e47 100644
 --- a/include/linux/jiffies.h
@@ -212044,6 +332127,69 @@
  #define symbol_request(x) try_then_request_module(symbol_get(x), "symbol:" #x)
  
  /* BELOW HERE ALL THESE ARE OBSOLETE AND WILL VANISH */
+diff --git a/include/linux/mv643xx.h b/include/linux/mv643xx.h
+index d2ae618..69327b7 100644
+--- a/include/linux/mv643xx.h
++++ b/include/linux/mv643xx.h
+@@ -15,6 +15,7 @@
+ 
+ #include <asm/types.h>
+ #include <linux/mv643xx_eth.h>
++#include <linux/mv643xx_i2c.h>
+ 
+ /****************************************/
+ /* Processor Address Space              */
+@@ -863,7 +864,6 @@
+ /* I2C Registers                        */
+ /****************************************/
+ 
+-#define MV64XXX_I2C_CTLR_NAME					"mv64xxx_i2c"
+ #define MV64XXX_I2C_OFFSET                                          0xc000
+ #define MV64XXX_I2C_REG_BLOCK_SIZE                                  0x0020
+ 
+@@ -968,14 +968,6 @@ struct mpsc_pdata {
+ 	u32	brg_clk_freq;
+ };
+ 
+-/* i2c Platform Device, Driver Data */
+-struct mv64xxx_i2c_pdata {
+-	u32	freq_m;
+-	u32	freq_n;
+-	u32	timeout;	/* In milliseconds */
+-	u32	retries;
+-};
+-
+ /* Watchdog Platform Device, Driver Data */
+ #define	MV64x60_WDT_NAME			"mv64x60_wdt"
+ 
+diff --git a/include/linux/mv643xx_i2c.h b/include/linux/mv643xx_i2c.h
+new file mode 100644
+index 0000000..5db5152
+--- /dev/null
++++ b/include/linux/mv643xx_i2c.h
+@@ -0,0 +1,22 @@
++/*
++ * This program is free software; you can redistribute  it and/or modify it
++ * under  the terms of  the 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 _MV64XXX_I2C_H_
++#define _MV64XXX_I2C_H_
++
++#include <linux/types.h>
++
++#define MV64XXX_I2C_CTLR_NAME	"mv64xxx_i2c"
++
++/* i2c Platform Device, Driver Data */
++struct mv64xxx_i2c_pdata {
++	u32	freq_m;
++	u32	freq_n;
++	u32	timeout;	/* In milliseconds */
++};
++
++#endif /*_MV64XXX_I2C_H_*/
 diff --git a/include/linux/notifier.h b/include/linux/notifier.h
 index 0c40cc0..5dfbc68 100644
 --- a/include/linux/notifier.h
@@ -212720,11 +332866,182 @@
 +
 +#endif /* __KERNEL__ */
 +#endif /* __LINUX_RCUPREEMPT_TRACE_H */
+diff --git a/include/linux/scatterlist.h b/include/linux/scatterlist.h
+index e3ff21d..a3d567a 100644
+--- a/include/linux/scatterlist.h
++++ b/include/linux/scatterlist.h
+@@ -7,6 +7,12 @@
+ #include <linux/string.h>
+ #include <asm/io.h>
+ 
++struct sg_table {
++	struct scatterlist *sgl;	/* the list */
++	unsigned int nents;		/* number of mapped entries */
++	unsigned int orig_nents;	/* original size of list */
++};
++
+ /*
+  * Notes on SG table design.
+  *
+@@ -106,31 +112,6 @@ static inline void sg_set_buf(struct scatterlist *sg, const void *buf,
+ 	sg_set_page(sg, virt_to_page(buf), buflen, offset_in_page(buf));
+ }
+ 
+-/**
+- * sg_next - return the next scatterlist entry in a list
+- * @sg:		The current sg entry
+- *
+- * Description:
+- *   Usually the next entry will be @sg@ + 1, but if this sg element is part
+- *   of a chained scatterlist, it could jump to the start of a new
+- *   scatterlist array.
+- *
+- **/
+-static inline struct scatterlist *sg_next(struct scatterlist *sg)
+-{
+-#ifdef CONFIG_DEBUG_SG
+-	BUG_ON(sg->sg_magic != SG_MAGIC);
+-#endif
+-	if (sg_is_last(sg))
+-		return NULL;
+-
+-	sg++;
+-	if (unlikely(sg_is_chain(sg)))
+-		sg = sg_chain_ptr(sg);
+-
+-	return sg;
+-}
+-
+ /*
+  * Loop over each sg element, following the pointer to a new list if necessary
+  */
+@@ -138,40 +119,6 @@ static inline struct scatterlist *sg_next(struct scatterlist *sg)
+ 	for (__i = 0, sg = (sglist); __i < (nr); __i++, sg = sg_next(sg))
+ 
+ /**
+- * sg_last - return the last scatterlist entry in a list
+- * @sgl:	First entry in the scatterlist
+- * @nents:	Number of entries in the scatterlist
+- *
+- * Description:
+- *   Should only be used casually, it (currently) scan the entire list
+- *   to get the last entry.
+- *
+- *   Note that the @sgl@ pointer passed in need not be the first one,
+- *   the important bit is that @nents@ denotes the number of entries that
+- *   exist from @sgl at .
+- *
+- **/
+-static inline struct scatterlist *sg_last(struct scatterlist *sgl,
+-					  unsigned int nents)
+-{
+-#ifndef ARCH_HAS_SG_CHAIN
+-	struct scatterlist *ret = &sgl[nents - 1];
+-#else
+-	struct scatterlist *sg, *ret = NULL;
+-	unsigned int i;
+-
+-	for_each_sg(sgl, sg, nents, i)
+-		ret = sg;
+-
+-#endif
+-#ifdef CONFIG_DEBUG_SG
+-	BUG_ON(sgl[0].sg_magic != SG_MAGIC);
+-	BUG_ON(!sg_is_last(ret));
+-#endif
+-	return ret;
+-}
+-
+-/**
+  * sg_chain - Chain two sglists together
+  * @prv:	First scatterlist
+  * @prv_nents:	Number of entries in prv
+@@ -223,47 +170,6 @@ static inline void sg_mark_end(struct scatterlist *sg)
+ }
+ 
+ /**
+- * sg_init_table - Initialize SG table
+- * @sgl:	   The SG table
+- * @nents:	   Number of entries in table
+- *
+- * Notes:
+- *   If this is part of a chained sg table, sg_mark_end() should be
+- *   used only on the last table part.
+- *
+- **/
+-static inline void sg_init_table(struct scatterlist *sgl, unsigned int nents)
+-{
+-	memset(sgl, 0, sizeof(*sgl) * nents);
+-#ifdef CONFIG_DEBUG_SG
+-	{
+-		unsigned int i;
+-		for (i = 0; i < nents; i++)
+-			sgl[i].sg_magic = SG_MAGIC;
+-	}
+-#endif
+-	sg_mark_end(&sgl[nents - 1]);
+-}
+-
+-/**
+- * sg_init_one - Initialize a single entry sg list
+- * @sg:		 SG entry
+- * @buf:	 Virtual address for IO
+- * @buflen:	 IO length
+- *
+- * Notes:
+- *   This should not be used on a single entry that is part of a larger
+- *   table. Use sg_init_table() for that.
+- *
+- **/
+-static inline void sg_init_one(struct scatterlist *sg, const void *buf,
+-			       unsigned int buflen)
+-{
+-	sg_init_table(sg, 1);
+-	sg_set_buf(sg, buf, buflen);
+-}
+-
+-/**
+  * sg_phys - Return physical address of an sg entry
+  * @sg:	     SG entry
+  *
+@@ -293,4 +199,24 @@ static inline void *sg_virt(struct scatterlist *sg)
+ 	return page_address(sg_page(sg)) + sg->offset;
+ }
+ 
++struct scatterlist *sg_next(struct scatterlist *);
++struct scatterlist *sg_last(struct scatterlist *s, unsigned int);
++void sg_init_table(struct scatterlist *, unsigned int);
++void sg_init_one(struct scatterlist *, const void *, unsigned int);
++
++typedef struct scatterlist *(sg_alloc_fn)(unsigned int, gfp_t);
++typedef void (sg_free_fn)(struct scatterlist *, unsigned int);
++
++void __sg_free_table(struct sg_table *, unsigned int, sg_free_fn *);
++void sg_free_table(struct sg_table *);
++int __sg_alloc_table(struct sg_table *, unsigned int, unsigned int, gfp_t,
++		     sg_alloc_fn *);
++int sg_alloc_table(struct sg_table *, unsigned int, gfp_t);
++
++/*
++ * Maximum number of entries that will be allocated in one piece, if
++ * a list larger than this is required then chaining will be utilized.
++ */
++#define SG_MAX_SINGLE_ALLOC		(PAGE_SIZE / sizeof(struct scatterlist))
++
+ #endif /* _LINUX_SCATTERLIST_H */
 diff --git a/include/linux/sched.h b/include/linux/sched.h
-index cc14656..df5b24e 100644
+index cc14656..2d0546e 100644
 --- a/include/linux/sched.h
 +++ b/include/linux/sched.h
-@@ -78,7 +78,6 @@ struct sched_param {
+@@ -27,6 +27,7 @@
+ #define CLONE_NEWUSER		0x10000000	/* New user namespace */
+ #define CLONE_NEWPID		0x20000000	/* New pid namespace */
+ #define CLONE_NEWNET		0x40000000	/* New network namespace */
++#define CLONE_IO		0x80000000	/* Clone io context */
+ 
+ /*
+  * Scheduling policies
+@@ -78,7 +79,6 @@ struct sched_param {
  #include <linux/proportions.h>
  #include <linux/seccomp.h>
  #include <linux/rcupdate.h>
@@ -212732,7 +333049,7 @@
  #include <linux/rtmutex.h>
  
  #include <linux/time.h>
-@@ -88,11 +87,13 @@ struct sched_param {
+@@ -88,11 +88,13 @@ struct sched_param {
  #include <linux/hrtimer.h>
  #include <linux/task_io_accounting.h>
  #include <linux/kobject.h>
@@ -212746,7 +333063,7 @@
  struct bio;
  
  /*
-@@ -230,6 +231,8 @@ static inline int select_nohz_load_balancer(int cpu)
+@@ -230,6 +232,8 @@ static inline int select_nohz_load_balancer(int cpu)
  }
  #endif
  
@@ -212755,7 +333072,7 @@
  /*
   * Only dump TASK_* tasks. (0 for all tasks)
   */
-@@ -257,13 +260,19 @@ extern void trap_init(void);
+@@ -257,13 +261,19 @@ extern void trap_init(void);
  extern void account_process_tick(struct task_struct *task, int user);
  extern void update_process_times(int user);
  extern void scheduler_tick(void);
@@ -212776,7 +333093,7 @@
  #else
  static inline void softlockup_tick(void)
  {
-@@ -552,18 +561,13 @@ struct user_struct {
+@@ -552,18 +562,13 @@ struct user_struct {
  #ifdef CONFIG_FAIR_USER_SCHED
  	struct task_group *tg;
  #ifdef CONFIG_SYSFS
@@ -212797,7 +333114,7 @@
  
  extern struct user_struct *find_user(uid_t);
  
-@@ -827,6 +831,7 @@ struct sched_class {
+@@ -827,6 +832,7 @@ struct sched_class {
  	void (*enqueue_task) (struct rq *rq, struct task_struct *p, int wakeup);
  	void (*dequeue_task) (struct rq *rq, struct task_struct *p, int sleep);
  	void (*yield_task) (struct rq *rq);
@@ -212805,7 +333122,7 @@
  
  	void (*check_preempt_curr) (struct rq *rq, struct task_struct *p);
  
-@@ -842,11 +847,25 @@ struct sched_class {
+@@ -842,11 +848,25 @@ struct sched_class {
  	int (*move_one_task) (struct rq *this_rq, int this_cpu,
  			      struct rq *busiest, struct sched_domain *sd,
  			      enum cpu_idle_type idle);
@@ -212832,7 +333149,7 @@
  };
  
  struct load_weight {
-@@ -876,6 +895,8 @@ struct sched_entity {
+@@ -876,6 +896,8 @@ struct sched_entity {
  #ifdef CONFIG_SCHEDSTATS
  	u64			wait_start;
  	u64			wait_max;
@@ -212841,7 +333158,7 @@
  
  	u64			sleep_start;
  	u64			sleep_max;
-@@ -914,6 +935,21 @@ struct sched_entity {
+@@ -914,6 +936,21 @@ struct sched_entity {
  #endif
  };
  
@@ -212863,7 +333180,7 @@
  struct task_struct {
  	volatile long state;	/* -1 unrunnable, 0 runnable, >0 stopped */
  	void *stack;
-@@ -930,9 +966,9 @@ struct task_struct {
+@@ -930,16 +967,15 @@ struct task_struct {
  #endif
  
  	int prio, static_prio, normal_prio;
@@ -212874,6 +333191,13 @@
  
  #ifdef CONFIG_PREEMPT_NOTIFIERS
  	/* list of struct preempt_notifier: */
+ 	struct hlist_head preempt_notifiers;
+ #endif
+ 
+-	unsigned short ioprio;
+ 	/*
+ 	 * fpu_counter contains the number of consecutive context switches
+ 	 * that the FPU is used. If this is over a threshold, the lazy fpu
 @@ -956,7 +992,11 @@ struct task_struct {
  
  	unsigned int policy;
@@ -214379,10 +334703,28 @@
  
  /* From the spec; local phys only */
 diff --git a/include/scsi/scsi_cmnd.h b/include/scsi/scsi_cmnd.h
-index 3f47e52..abd7479 100644
+index 3f47e52..a457fca 100644
 --- a/include/scsi/scsi_cmnd.h
 +++ b/include/scsi/scsi_cmnd.h
-@@ -88,7 +88,7 @@ struct scsi_cmnd {
+@@ -8,7 +8,6 @@
+ #include <linux/scatterlist.h>
+ 
+ struct request;
+-struct scatterlist;
+ struct Scsi_Host;
+ struct scsi_device;
+ 
+@@ -68,8 +67,8 @@ struct scsi_cmnd {
+ 	void *request_buffer;		/* Actual requested buffer */
+ 
+ 	/* These elements define the operation we ultimately want to perform */
++	struct sg_table sg_table;
+ 	unsigned short use_sg;	/* Number of pieces of scatter-gather */
+-	unsigned short __use_sg;
+ 
+ 	unsigned underflow;	/* Return error if less than
+ 				   this amount is transferred */
+@@ -88,7 +87,7 @@ struct scsi_cmnd {
  				   	   working on */
  
  #define SCSI_SENSE_BUFFERSIZE 	96
@@ -214391,6 +334733,23 @@
  				/* obtained by REQUEST SENSE when
  				 * CHECK CONDITION is received on original
  				 * command (auto-sense) */
+@@ -128,14 +127,14 @@ extern void *scsi_kmap_atomic_sg(struct scatterlist *sg, int sg_count,
+ 				 size_t *offset, size_t *len);
+ extern void scsi_kunmap_atomic_sg(void *virt);
+ 
+-extern struct scatterlist *scsi_alloc_sgtable(struct scsi_cmnd *, gfp_t);
++extern int scsi_alloc_sgtable(struct scsi_cmnd *, gfp_t);
+ extern void scsi_free_sgtable(struct scsi_cmnd *);
+ 
+ extern int scsi_dma_map(struct scsi_cmnd *cmd);
+ extern void scsi_dma_unmap(struct scsi_cmnd *cmd);
+ 
+ #define scsi_sg_count(cmd) ((cmd)->use_sg)
+-#define scsi_sglist(cmd) ((struct scatterlist *)(cmd)->request_buffer)
++#define scsi_sglist(cmd) ((cmd)->sg_table.sgl)
+ #define scsi_bufflen(cmd) ((cmd)->request_bufflen)
+ 
+ static inline void scsi_set_resid(struct scsi_cmnd *cmd, int resid)
 diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h
 index 6c2d80b..ab7acbe 100644
 --- a/include/scsi/scsi_device.h
@@ -214538,9 +334897,18 @@
  	unsigned	RCD : 1;	/* state of disk RCD bit, unused */
  	unsigned	DPOFUA : 1;	/* state of disk DPOFUA bit */
 diff --git a/init/Kconfig b/init/Kconfig
-index b9d11a8..0eda68f 100644
+index b9d11a8..288444b 100644
 --- a/init/Kconfig
 +++ b/init/Kconfig
+@@ -238,7 +238,7 @@ config AUDIT
+ 
+ config AUDITSYSCALL
+ 	bool "Enable system-call auditing support"
+-	depends on AUDIT && (X86 || PPC || PPC64 || S390 || IA64 || UML || SPARC64)
++	depends on AUDIT && (X86 || PPC || PPC64 || S390 || IA64 || UML || SPARC64|| SUPERH)
+ 	default y if SECURITY_SELINUX
+ 	help
+ 	  Enable low-overhead system-call auditing infrastructure that
 @@ -363,6 +363,7 @@ config CGROUP_CPUACCT
  
  config SYSFS_DEPRECATED
@@ -215156,10 +335524,50 @@
   */
  
 diff --git a/kernel/fork.c b/kernel/fork.c
-index 8dd8ff2..39d22b3 100644
+index 8dd8ff2..314f510 100644
 --- a/kernel/fork.c
 +++ b/kernel/fork.c
-@@ -1045,6 +1045,10 @@ static struct task_struct *copy_process(unsigned long clone_flags,
+@@ -51,6 +51,7 @@
+ #include <linux/random.h>
+ #include <linux/tty.h>
+ #include <linux/proc_fs.h>
++#include <linux/blkdev.h>
+ 
+ #include <asm/pgtable.h>
+ #include <asm/pgalloc.h>
+@@ -791,6 +792,31 @@ out:
+ 	return error;
+ }
+ 
++static int copy_io(unsigned long clone_flags, struct task_struct *tsk)
++{
++#ifdef CONFIG_BLOCK
++	struct io_context *ioc = current->io_context;
++
++	if (!ioc)
++		return 0;
++	/*
++	 * Share io context with parent, if CLONE_IO is set
++	 */
++	if (clone_flags & CLONE_IO) {
++		tsk->io_context = ioc_task_link(ioc);
++		if (unlikely(!tsk->io_context))
++			return -ENOMEM;
++	} else if (ioprio_valid(ioc->ioprio)) {
++		tsk->io_context = alloc_io_context(GFP_KERNEL, -1);
++		if (unlikely(!tsk->io_context))
++			return -ENOMEM;
++
++		tsk->io_context->ioprio = ioc->ioprio;
++	}
++#endif
++	return 0;
++}
++
+ /*
+  *	Helper to unshare the files of the current task.
+  *	We don't want to expose copy_files internals to
+@@ -1045,6 +1071,10 @@ static struct task_struct *copy_process(unsigned long clone_flags,
  	copy_flags(clone_flags, p);
  	INIT_LIST_HEAD(&p->children);
  	INIT_LIST_HEAD(&p->sibling);
@@ -215170,7 +335578,7 @@
  	p->vfork_done = NULL;
  	spin_lock_init(&p->alloc_lock);
  
-@@ -1059,6 +1063,11 @@ static struct task_struct *copy_process(unsigned long clone_flags,
+@@ -1059,6 +1089,11 @@ static struct task_struct *copy_process(unsigned long clone_flags,
  	p->prev_utime = cputime_zero;
  	p->prev_stime = cputime_zero;
  
@@ -215182,7 +335590,27 @@
  #ifdef CONFIG_TASK_XACCT
  	p->rchar = 0;		/* I/O counter: bytes read */
  	p->wchar = 0;		/* I/O counter: bytes written */
-@@ -1196,6 +1205,7 @@ static struct task_struct *copy_process(unsigned long clone_flags,
+@@ -1147,15 +1182,17 @@ static struct task_struct *copy_process(unsigned long clone_flags,
+ 		goto bad_fork_cleanup_mm;
+ 	if ((retval = copy_namespaces(clone_flags, p)))
+ 		goto bad_fork_cleanup_keys;
++	if ((retval = copy_io(clone_flags, p)))
++		goto bad_fork_cleanup_namespaces;
+ 	retval = copy_thread(0, clone_flags, stack_start, stack_size, p, regs);
+ 	if (retval)
+-		goto bad_fork_cleanup_namespaces;
++		goto bad_fork_cleanup_io;
+ 
+ 	if (pid != &init_struct_pid) {
+ 		retval = -ENOMEM;
+ 		pid = alloc_pid(task_active_pid_ns(p));
+ 		if (!pid)
+-			goto bad_fork_cleanup_namespaces;
++			goto bad_fork_cleanup_io;
+ 
+ 		if (clone_flags & CLONE_NEWPID) {
+ 			retval = pid_ns_prepare_proc(task_active_pid_ns(p));
+@@ -1196,6 +1233,7 @@ static struct task_struct *copy_process(unsigned long clone_flags,
  #ifdef TIF_SYSCALL_EMU
  	clear_tsk_thread_flag(p, TIF_SYSCALL_EMU);
  #endif
@@ -215190,7 +335618,17 @@
  
  	/* Our parent execution domain becomes current domain
  	   These must match for thread signalling to apply */
-@@ -1237,6 +1247,7 @@ static struct task_struct *copy_process(unsigned long clone_flags,
+@@ -1224,9 +1262,6 @@ static struct task_struct *copy_process(unsigned long clone_flags,
+ 	/* Need tasklist lock for parent etc handling! */
+ 	write_lock_irq(&tasklist_lock);
+ 
+-	/* for sys_ioprio_set(IOPRIO_WHO_PGRP) */
+-	p->ioprio = current->ioprio;
+-
+ 	/*
+ 	 * The task hasn't been attached yet, so its cpus_allowed mask will
+ 	 * not be changed, nor will its assigned CPU.
+@@ -1237,6 +1272,7 @@ static struct task_struct *copy_process(unsigned long clone_flags,
  	 * parent's CPU). This avoids alot of nasty races.
  	 */
  	p->cpus_allowed = current->cpus_allowed;
@@ -215198,6 +335636,15 @@
  	if (unlikely(!cpu_isset(task_cpu(p), p->cpus_allowed) ||
  			!cpu_online(task_cpu(p))))
  		set_task_cpu(p, smp_processor_id());
+@@ -1317,6 +1353,8 @@ static struct task_struct *copy_process(unsigned long clone_flags,
+ bad_fork_free_pid:
+ 	if (pid != &init_struct_pid)
+ 		free_pid(pid);
++bad_fork_cleanup_io:
++	put_io_context(p->io_context);
+ bad_fork_cleanup_namespaces:
+ 	exit_task_namespaces(p);
+ bad_fork_cleanup_keys:
 diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c
 index f994bb8..bd5d6b5 100644
 --- a/kernel/hrtimer.c
@@ -224515,6 +344962,19 @@
 +
 +
  source "samples/Kconfig"
+diff --git a/lib/Makefile b/lib/Makefile
+index b6793ed..89841dc 100644
+--- a/lib/Makefile
++++ b/lib/Makefile
+@@ -6,7 +6,7 @@ lib-y := ctype.o string.o vsprintf.o cmdline.o \
+ 	 rbtree.o radix-tree.o dump_stack.o \
+ 	 idr.o int_sqrt.o extable.o prio_tree.o \
+ 	 sha1.o irq_regs.o reciprocal_div.o argv_split.o \
+-	 proportions.o prio_heap.o
++	 proportions.o prio_heap.o scatterlist.o
+ 
+ lib-$(CONFIG_MMU) += ioremap.o
+ lib-$(CONFIG_SMP) += cpumask.o
 diff --git a/lib/kernel_lock.c b/lib/kernel_lock.c
 index f73e2f8..812dbf0 100644
 --- a/lib/kernel_lock.c
@@ -225809,6 +346269,319 @@
  EXPORT_SYMBOL(kref_init);
  EXPORT_SYMBOL(kref_get);
  EXPORT_SYMBOL(kref_put);
+diff --git a/lib/scatterlist.c b/lib/scatterlist.c
+new file mode 100644
+index 0000000..acca490
+--- /dev/null
++++ b/lib/scatterlist.c
+@@ -0,0 +1,294 @@
++/*
++ * Copyright (C) 2007 Jens Axboe <jens.axboe at oracle.com>
++ *
++ * Scatterlist handling helpers.
++ *
++ * This source code is licensed under the GNU General Public License,
++ * Version 2. See the file COPYING for more details.
++ */
++#include <linux/module.h>
++#include <linux/scatterlist.h>
++
++/**
++ * sg_next - return the next scatterlist entry in a list
++ * @sg:		The current sg entry
++ *
++ * Description:
++ *   Usually the next entry will be @sg@ + 1, but if this sg element is part
++ *   of a chained scatterlist, it could jump to the start of a new
++ *   scatterlist array.
++ *
++ **/
++struct scatterlist *sg_next(struct scatterlist *sg)
++{
++#ifdef CONFIG_DEBUG_SG
++	BUG_ON(sg->sg_magic != SG_MAGIC);
++#endif
++	if (sg_is_last(sg))
++		return NULL;
++
++	sg++;
++	if (unlikely(sg_is_chain(sg)))
++		sg = sg_chain_ptr(sg);
++
++	return sg;
++}
++EXPORT_SYMBOL(sg_next);
++
++/**
++ * sg_last - return the last scatterlist entry in a list
++ * @sgl:	First entry in the scatterlist
++ * @nents:	Number of entries in the scatterlist
++ *
++ * Description:
++ *   Should only be used casually, it (currently) scans the entire list
++ *   to get the last entry.
++ *
++ *   Note that the @sgl@ pointer passed in need not be the first one,
++ *   the important bit is that @nents@ denotes the number of entries that
++ *   exist from @sgl at .
++ *
++ **/
++struct scatterlist *sg_last(struct scatterlist *sgl, unsigned int nents)
++{
++#ifndef ARCH_HAS_SG_CHAIN
++	struct scatterlist *ret = &sgl[nents - 1];
++#else
++	struct scatterlist *sg, *ret = NULL;
++	unsigned int i;
++
++	for_each_sg(sgl, sg, nents, i)
++		ret = sg;
++
++#endif
++#ifdef CONFIG_DEBUG_SG
++	BUG_ON(sgl[0].sg_magic != SG_MAGIC);
++	BUG_ON(!sg_is_last(ret));
++#endif
++	return ret;
++}
++EXPORT_SYMBOL(sg_last);
++
++/**
++ * sg_init_table - Initialize SG table
++ * @sgl:	   The SG table
++ * @nents:	   Number of entries in table
++ *
++ * Notes:
++ *   If this is part of a chained sg table, sg_mark_end() should be
++ *   used only on the last table part.
++ *
++ **/
++void sg_init_table(struct scatterlist *sgl, unsigned int nents)
++{
++	memset(sgl, 0, sizeof(*sgl) * nents);
++#ifdef CONFIG_DEBUG_SG
++	{
++		unsigned int i;
++		for (i = 0; i < nents; i++)
++			sgl[i].sg_magic = SG_MAGIC;
++	}
++#endif
++	sg_mark_end(&sgl[nents - 1]);
++}
++EXPORT_SYMBOL(sg_init_table);
++
++/**
++ * sg_init_one - Initialize a single entry sg list
++ * @sg:		 SG entry
++ * @buf:	 Virtual address for IO
++ * @buflen:	 IO length
++ *
++ **/
++void sg_init_one(struct scatterlist *sg, const void *buf, unsigned int buflen)
++{
++	sg_init_table(sg, 1);
++	sg_set_buf(sg, buf, buflen);
++}
++EXPORT_SYMBOL(sg_init_one);
++
++/*
++ * The default behaviour of sg_alloc_table() is to use these kmalloc/kfree
++ * helpers.
++ */
++static struct scatterlist *sg_kmalloc(unsigned int nents, gfp_t gfp_mask)
++{
++	if (nents == SG_MAX_SINGLE_ALLOC)
++		return (struct scatterlist *) __get_free_page(gfp_mask);
++	else
++		return kmalloc(nents * sizeof(struct scatterlist), gfp_mask);
++}
++
++static void sg_kfree(struct scatterlist *sg, unsigned int nents)
++{
++	if (nents == SG_MAX_SINGLE_ALLOC)
++		free_page((unsigned long) sg);
++	else
++		kfree(sg);
++}
++
++/**
++ * __sg_free_table - Free a previously mapped sg table
++ * @table:	The sg table header to use
++ * @max_ents:	The maximum number of entries per single scatterlist
++ * @free_fn:	Free function
++ *
++ *  Description:
++ *    Free an sg table previously allocated and setup with
++ *    __sg_alloc_table().  The @max_ents value must be identical to
++ *    that previously used with __sg_alloc_table().
++ *
++ **/
++void __sg_free_table(struct sg_table *table, unsigned int max_ents,
++		     sg_free_fn *free_fn)
++{
++	struct scatterlist *sgl, *next;
++
++	if (unlikely(!table->sgl))
++		return;
++
++	sgl = table->sgl;
++	while (table->orig_nents) {
++		unsigned int alloc_size = table->orig_nents;
++		unsigned int sg_size;
++
++		/*
++		 * If we have more than max_ents segments left,
++		 * then assign 'next' to the sg table after the current one.
++		 * sg_size is then one less than alloc size, since the last
++		 * element is the chain pointer.
++		 */
++		if (alloc_size > max_ents) {
++			next = sg_chain_ptr(&sgl[max_ents - 1]);
++			alloc_size = max_ents;
++			sg_size = alloc_size - 1;
++		} else {
++			sg_size = alloc_size;
++			next = NULL;
++		}
++
++		table->orig_nents -= sg_size;
++		free_fn(sgl, alloc_size);
++		sgl = next;
++	}
++
++	table->sgl = NULL;
++}
++EXPORT_SYMBOL(__sg_free_table);
++
++/**
++ * sg_free_table - Free a previously allocated sg table
++ * @table:	The mapped sg table header
++ *
++ **/
++void sg_free_table(struct sg_table *table)
++{
++	__sg_free_table(table, SG_MAX_SINGLE_ALLOC, sg_kfree);
++}
++EXPORT_SYMBOL(sg_free_table);
++
++/**
++ * __sg_alloc_table - Allocate and initialize an sg table with given allocator
++ * @table:	The sg table header to use
++ * @nents:	Number of entries in sg list
++ * @max_ents:	The maximum number of entries the allocator returns per call
++ * @gfp_mask:	GFP allocation mask
++ * @alloc_fn:	Allocator to use
++ *
++ * Description:
++ *   This function returns a @table @nents long. The allocator is
++ *   defined to return scatterlist chunks of maximum size @max_ents.
++ *   Thus if @nents is bigger than @max_ents, the scatterlists will be
++ *   chained in units of @max_ents.
++ *
++ * Notes:
++ *   If this function returns non-0 (eg failure), the caller must call
++ *   __sg_free_table() to cleanup any leftover allocations.
++ *
++ **/
++int __sg_alloc_table(struct sg_table *table, unsigned int nents,
++		     unsigned int max_ents, gfp_t gfp_mask,
++		     sg_alloc_fn *alloc_fn)
++{
++	struct scatterlist *sg, *prv;
++	unsigned int left;
++
++#ifndef ARCH_HAS_SG_CHAIN
++	BUG_ON(nents > max_ents);
++#endif
++
++	memset(table, 0, sizeof(*table));
++
++	left = nents;
++	prv = NULL;
++	do {
++		unsigned int sg_size, alloc_size = left;
++
++		if (alloc_size > max_ents) {
++			alloc_size = max_ents;
++			sg_size = alloc_size - 1;
++		} else
++			sg_size = alloc_size;
++
++		left -= sg_size;
++
++		sg = alloc_fn(alloc_size, gfp_mask);
++		if (unlikely(!sg))
++			return -ENOMEM;
++
++		sg_init_table(sg, alloc_size);
++		table->nents = table->orig_nents += sg_size;
++
++		/*
++		 * If this is the first mapping, assign the sg table header.
++		 * If this is not the first mapping, chain previous part.
++		 */
++		if (prv)
++			sg_chain(prv, max_ents, sg);
++		else
++			table->sgl = sg;
++
++		/*
++		 * If no more entries after this one, mark the end
++		 */
++		if (!left)
++			sg_mark_end(&sg[sg_size - 1]);
++
++		/*
++		 * only really needed for mempool backed sg allocations (like
++		 * SCSI), a possible improvement here would be to pass the
++		 * table pointer into the allocator and let that clear these
++		 * flags
++		 */
++		gfp_mask &= ~__GFP_WAIT;
++		gfp_mask |= __GFP_HIGH;
++		prv = sg;
++	} while (left);
++
++	return 0;
++}
++EXPORT_SYMBOL(__sg_alloc_table);
++
++/**
++ * sg_alloc_table - Allocate and initialize an sg table
++ * @table:	The sg table header to use
++ * @nents:	Number of entries in sg list
++ * @gfp_mask:	GFP allocation mask
++ *
++ *  Description:
++ *    Allocate and initialize an sg table. If @nents@ is larger than
++ *    SG_MAX_SINGLE_ALLOC a chained sg table will be setup.
++ *
++ **/
++int sg_alloc_table(struct sg_table *table, unsigned int nents, gfp_t gfp_mask)
++{
++	int ret;
++
++	ret = __sg_alloc_table(table, nents, SG_MAX_SINGLE_ALLOC,
++			       gfp_mask, sg_kmalloc);
++	if (unlikely(ret))
++		__sg_free_table(table, SG_MAX_SINGLE_ALLOC, sg_kfree);
++
++	return ret;
++}
++EXPORT_SYMBOL(sg_alloc_table);
+diff --git a/mm/Kconfig b/mm/Kconfig
+index 9ef9741..0016ebd 100644
+--- a/mm/Kconfig
++++ b/mm/Kconfig
+@@ -187,7 +187,7 @@ config BOUNCE
+ config NR_QUICK
+ 	int
+ 	depends on QUICKLIST
+-	default "2" if (SUPERH && !SUPERH64)
++	default "2" if SUPERH
+ 	default "1"
+ 
+ config VIRT_TO_BUS
 diff --git a/mm/mmap.c b/mm/mmap.c
 index 15678aa..bfa389f 100644
 --- a/mm/mmap.c
@@ -227843,6 +348616,19 @@
  	POLICY_RDLOCK;
  
  	for (genfs = policydb.genfs; genfs; genfs = genfs->next) {
+diff --git a/sound/oss/waveartist.c b/sound/oss/waveartist.c
+index b48c729..8849041 100644
+--- a/sound/oss/waveartist.c
++++ b/sound/oss/waveartist.c
+@@ -835,7 +835,7 @@ static struct audio_driver waveartist_audio_driver = {
+ static irqreturn_t
+ waveartist_intr(int irq, void *dev_id)
+ {
+-	wavnc_info *devc = (wavnc_info *)dev_id;
++	wavnc_info *devc = dev_id;
+ 	int	   irqstatus, status;
+ 
+ 	spin_lock(&waveartist_lock);
 diff --git a/sound/ppc/keywest.c b/sound/ppc/keywest.c
 index 272ae38..bb7d744 100644
 --- a/sound/ppc/keywest.c

Modified: dists/trunk/linux-2.6/debian/patches/series/1~experimental.1
==============================================================================
--- dists/trunk/linux-2.6/debian/patches/series/1~experimental.1	(original)
+++ dists/trunk/linux-2.6/debian/patches/series/1~experimental.1	Tue Jan 29 09:43:52 2008
@@ -41,4 +41,4 @@
 + bugfix/all/fw-sbp2-incr-login-orb-reply-timeout.patch
 + bugfix/all/fw-sbp2-skip-unnecessary-logout.patch
 + bugfix/all/fw-sbp2-try-increase-reconnect_hold.patch
-+ bugfix/all/patch-2.6.24-git4
++ bugfix/all/patch-2.6.24-git5



More information about the Kernel-svn-changes mailing list